From f64e8bbcc5e255d64ffe2a0001617d30b5ef8074 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Fri, 31 Jan 2025 18:26:12 -0800 Subject: [PATCH 01/20] customizable toolbars --- src/mpc-hc/AppSettings.cpp | 2 + src/mpc-hc/AppSettings.h | 1 + src/mpc-hc/ImageGrayer.cpp | 16 ++ src/mpc-hc/ImageGrayer.h | 1 + src/mpc-hc/PlayerToolBar.cpp | 420 +++++++++++++++++++++++------------ src/mpc-hc/PlayerToolBar.h | 15 +- src/mpc-hc/mplayerc.cpp | 27 +++ src/mpc-hc/mplayerc.h | 2 + src/mpc-hc/res/buttons.svg | 149 +++++++++++++ src/mpc-hc/res/mpc-hc.rc2 | Bin 19828 -> 19982 bytes src/mpc-hc/resource.h | 1 + 11 files changed, 495 insertions(+), 139 deletions(-) create mode 100644 src/mpc-hc/res/buttons.svg diff --git a/src/mpc-hc/AppSettings.cpp b/src/mpc-hc/AppSettings.cpp index 187f9b7b4e1..608f1b982cb 100644 --- a/src/mpc-hc/AppSettings.cpp +++ b/src/mpc-hc/AppSettings.cpp @@ -39,6 +39,7 @@ #include "date/date.h" #include "PPageExternalFilters.h" #include "../VideoRenderers/MPCVRAllocatorPresenter.h" +std::map CAppSettings::CommandIDToWMCMD; #pragma warning(push) #pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized @@ -754,6 +755,7 @@ void CAppSettings::CreateCommands() for (const auto& wc : default_wmcmds) { wmcmd w = wmcmd(wc); w.fVirt |= FVIRTKEY | FNOINVERT; + CommandIDToWMCMD[wc.cmd] = &wc; wmcmds.AddTail(w); } ASSERT(wmcmds.GetCount() <= ACCEL_LIST_SIZE); diff --git a/src/mpc-hc/AppSettings.h b/src/mpc-hc/AppSettings.h index 3af3312afbe..1ab8e4dc6d7 100644 --- a/src/mpc-hc/AppSettings.h +++ b/src/mpc-hc/AppSettings.h @@ -555,6 +555,7 @@ class CAppSettings // cmdline params UINT64 nCLSwitches; CAtlList slFiles, slDubs, slSubs, slFilters; + static std::map CommandIDToWMCMD; // Initial position (used by command line flags) REFERENCE_TIME rtShift; diff --git a/src/mpc-hc/ImageGrayer.cpp b/src/mpc-hc/ImageGrayer.cpp index 66f4f6b0840..d1a12bbee1b 100644 --- a/src/mpc-hc/ImageGrayer.cpp +++ b/src/mpc-hc/ImageGrayer.cpp @@ -286,3 +286,19 @@ bool ImageGrayer::Colorize(const CImage& imgSrc, CImage& imgDest, COLORREF fg, C return true; } + +void ImageGrayer::PreMultiplyAlpha(CImage& imgSource) { + BYTE* bits = static_cast(imgSource.GetBits()); + for (int y = 0; y < imgSource.GetHeight(); y++, bits += imgSource.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgSource.GetWidth(); x++) { + HLS hls(p[x]); + + RGBQUAD rgb = hls.toRGBQUAD(); + + p[x].rgbRed = static_cast(round((float)p[x].rgbRed * p[x].rgbReserved / 255.0f)); + p[x].rgbBlue = static_cast(round((float)p[x].rgbBlue * p[x].rgbReserved / 255.0f)); + p[x].rgbGreen = static_cast(round((float)p[x].rgbGreen * p[x].rgbReserved / 255.0f)); + } + } +} \ No newline at end of file diff --git a/src/mpc-hc/ImageGrayer.h b/src/mpc-hc/ImageGrayer.h index 9c0c5317a60..1cfb310af6c 100644 --- a/src/mpc-hc/ImageGrayer.h +++ b/src/mpc-hc/ImageGrayer.h @@ -31,4 +31,5 @@ namespace ImageGrayer bool Gray(const CImage& imgSource, CImage& imgDest, float brightness = 1.0f); bool UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle); bool Colorize(const CImage& imgSource, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90); + void PreMultiplyAlpha(CImage& imgSource); } diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index 8e6d30a55c8..ae3d6fab23d 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -34,6 +34,33 @@ // CPlayerToolBar +struct svgButtonInfo { + UINT style; + int svgIndex; +}; + +//svg has 30 positions +//0-7 are standard mpc buttons +//8-24 reserved for additional toolbar buttons +//25-27 are volume mute variants +//28-29 reserved for volume svg + +#define VOLUMEBUTTON_SVG_INDEX 25 +#define VOLUME_SVG_INDEX 28 + +static std::map supportedSvgButtons = { + {ID_PLAY_PLAY, {TBBS_CHECKGROUP,0}}, + {ID_PLAY_PAUSE, {TBBS_CHECKGROUP,1}}, + {ID_PLAY_STOP, {TBBS_CHECKGROUP,2}}, + {ID_NAVIGATE_SKIPBACK, {TBBS_BUTTON,3}}, + {ID_PLAY_DECRATE, {TBBS_BUTTON,4}}, + {ID_PLAY_INCRATE, {TBBS_BUTTON,5}}, + {ID_NAVIGATE_SKIPFORWARD, {TBBS_BUTTON,6}}, + {ID_PLAY_FRAMESTEP, {TBBS_BUTTON,7}}, + {ID_DUMMYSEPARATOR, {TBBS_SEPARATOR,-1}}, + {ID_VOLUME_MUTE, {TBBS_CHECKBOX,VOLUMEBUTTON_SVG_INDEX}}, +}; + IMPLEMENT_DYNAMIC(CPlayerToolBar, CToolBar) CPlayerToolBar::CPlayerToolBar(CMainFrame* pMainFrame) : m_pMainFrame(pMainFrame) @@ -41,6 +68,10 @@ CPlayerToolBar::CPlayerToolBar(CMainFrame* pMainFrame) , m_volumeCtrlSize(60) , mouseDownL(false) , mouseDownR(false) + , volumeButtonIndex(12) + , dummySeparatorIndex(11) + , flexibleSpaceIndex(10) + , currentlyDraggingButton(-1) { GetEventd().Connect(m_eventc, { MpcEvent::DPI_CHANGED, @@ -52,7 +83,7 @@ CPlayerToolBar::~CPlayerToolBar() { } -bool CPlayerToolBar::LoadExternalToolBar(CImage& image, bool useColor) +bool CPlayerToolBar::LoadExternalToolBar(CImage& image, float svgscale) { // Paths and extensions to try (by order of preference) std::vector paths({ PathUtils::GetProgramPath() }); @@ -60,37 +91,14 @@ bool CPlayerToolBar::LoadExternalToolBar(CImage& image, bool useColor) if (AfxGetMyApp()->GetAppDataPath(appDataPath)) { paths.emplace_back(appDataPath); } - const std::vector extensions({ _T("png"), _T("bmp") }); CString basetbname; - if (AppIsThemeLoaded()) { - const auto& s = AfxGetAppSettings(); - if (s.eModernThemeMode == CMPCTheme::ModernThemeMode::DARK || s.eModernThemeMode == CMPCTheme::ModernThemeMode::WINDOWSDEFAULT && s.bWindows10DarkThemeActive) { - basetbname = _T("toolbar_dark."); - } else { - basetbname = _T("toolbar_light."); - } - } else { - basetbname = _T("toolbar."); - } - - if (useColor) { - basetbname = _T("color_") + basetbname; - } - - // TODO: Find a better solution? - float dpiScaling = (float)std::min(m_pMainFrame->m_dpi.ScaleFactorX(), m_pMainFrame->m_dpi.ScaleFactorY()); + basetbname = _T("buttons-."); // Try loading the external toolbar for (const auto& path : paths) { - if (SUCCEEDED(SVGImage::Load(PathUtils::CombinePaths(path, basetbname + _T("svg")), image, dpiScaling))) { + if (SUCCEEDED(SVGImage::Load(PathUtils::CombinePaths(path, basetbname + _T("svg")), image, svgscale))) { return true; } - - for (const auto& ext : extensions) { - if (SUCCEEDED(image.Load(PathUtils::CombinePaths(path, basetbname + ext)))) { - return true; - } - } } return false; @@ -103,104 +111,169 @@ void CPlayerToolBar::LoadToolbarImage() int targetsize = int(dpiScaling * AfxGetAppSettings().nDefaultToolbarSize); float svgscale = targetsize / 16.0f; - CImage image, themedImage, origImage; + CImage image; + m_pButtonsImages.reset(); m_pDisabledButtonsImages.reset(); - bool colorToolbar = false, toolbarImageLoaded = false; - if (LoadExternalToolBar(origImage, true)) { - colorToolbar = true; - toolbarImageLoaded = true; - } else if (LoadExternalToolBar(origImage, false)) { - toolbarImageLoaded = true; + bool buttonsImageLoaded = false; + if (LoadExternalToolBar(image, svgscale) && image.GetHeight() % 4 == 0 && image.GetWidth() % (image.GetHeight()/4) == 0) { + buttonsImageLoaded = true; } - if (toolbarImageLoaded || (!AfxGetAppSettings().bUseLegacyToolbar && SUCCEEDED(SVGImage::Load(IDF_SVG_TOOLBAR, origImage, svgscale)))) { - if (AppIsThemeLoaded() && colorToolbar == false) { - ImageGrayer::UpdateColor(origImage, themedImage, false, ImageGrayer::mpcMono); - image = themedImage; - } else { - image = origImage; - } + if (buttonsImageLoaded || SUCCEEDED(SVGImage::Load(IDF_SVG_BUTTONS, image, svgscale))) { + CImage imageDisabled; CBitmap* bmp = CBitmap::FromHandle(image); + + int width = image.GetWidth(); - int height = image.GetHeight(); + int height = image.GetHeight() / 4; int bpp = image.GetBPP(); - if (width == height * 15) { + if (width % height == 0) { //todo: dynamically determine which buttons are supported by this toolbar, otherwise show generic buttons? // the manual specifies that sizeButton should be sizeImage inflated by (7, 6) SetSizes(CSize(height + 7, height + 6), CSize(height, height)); + int volumeIndex = VOLUME_SVG_INDEX; + volumeOn.Destroy(); + volumeOff.Destroy(); + volumeOn.Create(height * 2, height, bpp, CImage::createAlphaChannel); + volumeOff.Create(height * 2, height, bpp, CImage::createAlphaChannel); + m_pButtonsImages.reset(DEBUG_NEW CImageList()); - if (bpp == 32) { - m_pButtonsImages->Create(height, height, ILC_COLOR32 | ILC_MASK, 1, 0); - m_pButtonsImages->Add(bmp, nullptr); // alpha is the mask - - if (colorToolbar == false) {//if color toolbar, we assume the imagelist can grey itself nicely, rather than using imagegrayer - CImage imageDisabled; - if (ImageGrayer::UpdateColor(origImage, imageDisabled, true, AppIsThemeLoaded() ? ImageGrayer::mpcMono : ImageGrayer::classicGrayscale)) { - m_pDisabledButtonsImages.reset(DEBUG_NEW CImageList()); - m_pDisabledButtonsImages->Create(height, height, ILC_COLOR32 | ILC_MASK, 1, 0); - m_pDisabledButtonsImages->Add(CBitmap::FromHandle(imageDisabled), nullptr); // alpha is the mask - imageDisabled.Destroy(); - } else { - m_pDisabledButtonsImages = nullptr; - } - } else { - m_pDisabledButtonsImages = nullptr; - } - } else { - m_pButtonsImages->Create(height, height, ILC_COLOR24 | ILC_MASK, 1, 0); - m_pButtonsImages->Add(bmp, RGB(255, 0, 255)); + m_pButtonsImages->Create(height, height, ILC_COLOR32 | ILC_MASK, 1, 64); + m_pDisabledButtonsImages.reset(DEBUG_NEW CImageList()); + m_pDisabledButtonsImages->Create(height, height, ILC_COLOR32 | ILC_MASK, 1, 64); + + CImage dynamicToolbar, dynamicToolbarDisabled; + + dynamicToolbar.Create(width, height, bpp, CImage::createAlphaChannel); + dynamicToolbarDisabled.Create(width, height, bpp, CImage::createAlphaChannel); + + CBitmap* pOldTargetBmp = nullptr; + CBitmap* pOldSourceBmp = nullptr; + + + CDC targetDC; + CDC sourceDC; + CDC* pDC = this->GetDC(); + targetDC.CreateCompatibleDC(pDC); + sourceDC.CreateCompatibleDC(pDC); + + pOldTargetBmp = targetDC.SelectObject(CBitmap::FromHandle(dynamicToolbar)); + pOldSourceBmp = sourceDC.GetCurrentBitmap(); + + int imageOffset = 0, imageDisabledOffset=height; + if (AppIsThemeLoaded()) { + imageOffset = height * 2; + imageDisabledOffset = height * 3; } + + sourceDC.SelectObject(bmp); + targetDC.BitBlt(0, 0, image.GetWidth(), height, &sourceDC, 0, imageOffset, SRCCOPY); + + targetDC.SelectObject(CBitmap::FromHandle(dynamicToolbarDisabled)); + targetDC.BitBlt(0, 0, image.GetWidth(), height, &sourceDC, 0, imageDisabledOffset, SRCCOPY); + + targetDC.SelectObject(CBitmap::FromHandle(volumeOn)); + targetDC.BitBlt(0, 0, height * 2, height, &sourceDC, volumeIndex * height, imageOffset, SRCCOPY); + targetDC.SelectObject(CBitmap::FromHandle(volumeOff)); + targetDC.BitBlt(0, 0, height * 2, height, &sourceDC, volumeIndex * height, imageDisabledOffset, SRCCOPY); + + //volumeOn.Save(L"c:\\temp\\vON.png", Gdiplus::ImageFormatPNG); + //volumeOff.Save(L"c:\\temp\\vOFF.png", Gdiplus::ImageFormatPNG); + + ImageGrayer::PreMultiplyAlpha(volumeOn); + ImageGrayer::PreMultiplyAlpha(volumeOff); + + sourceDC.SelectObject(pOldSourceBmp); + targetDC.SelectObject(pOldTargetBmp); + + sourceDC.DeleteDC(); + targetDC.DeleteDC(); + + ReleaseDC(pDC); + + m_pButtonsImages->Add(CBitmap::FromHandle(dynamicToolbar), nullptr); + dynamicToolbar.Destroy(); + + m_pDisabledButtonsImages->Add(CBitmap::FromHandle(dynamicToolbarDisabled), nullptr); + dynamicToolbarDisabled.Destroy(); + m_nButtonHeight = height; + GetToolBarCtrl().SetImageList(m_pButtonsImages.get()); GetToolBarCtrl().SetDisabledImageList(m_pDisabledButtonsImages.get()); } - if (themedImage) { - themedImage.Destroy(); - } } - origImage.Destroy(); + image.Destroy(); + } BOOL CPlayerToolBar::Create(CWnd* pParentWnd) { VERIFY(__super::CreateEx(pParentWnd, - TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_AUTOSIZE | TBSTYLE_CUSTOMERASE, + TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_AUTOSIZE | TBSTYLE_CUSTOMERASE | CCS_ADJUSTABLE, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM /*| CBRS_TOOLTIPS*/, CRect(2, 2, 0, 1))); - VERIFY(LoadToolBar(IDB_PLAYERTOOLBAR)); - - // Should never be RTLed - ModifyStyleEx(WS_EX_LAYOUTRTL, WS_EX_NOINHERITLAYOUT); + auto& s = AfxGetAppSettings(); CToolBarCtrl& tb = GetToolBarCtrl(); - tb.DeleteButton(tb.GetButtonCount() - 1); - tb.DeleteButton(tb.GetButtonCount() - 1); - SetMute(AfxGetAppSettings().fMute); + dummySeparatorIndex = -1; + volumeButtonIndex = -1; + flexibleSpaceIndex = -1; + buttonCount = 0; + sepCount = 0; + + auto addButton = [&](int cmdid) { + auto& svgInfo = supportedSvgButtons[cmdid]; + TBBUTTON button = { 0 }; + button.iBitmap = svgInfo.svgIndex; + button.idCommand = cmdid; + button.iString = -1; + tb.AddButtons(1, &button); + SetButtonStyle(tb.GetButtonCount() - 1, svgInfo.style | TBBS_DISABLED); + buttonCount++; + }; - UINT styles[] = { - TBBS_CHECKGROUP, TBBS_CHECKGROUP, TBBS_CHECKGROUP, - TBBS_SEPARATOR, - TBBS_BUTTON, TBBS_BUTTON, TBBS_BUTTON, TBBS_BUTTON, - TBBS_SEPARATOR, - TBBS_BUTTON, - TBBS_SEPARATOR, - TBBS_SEPARATOR, // variable spacing between the regular controls and mute button - TBBS_CHECKBOX, + auto addSeparator = [&]() { + TBBUTTON button = { 0 }; + button.iBitmap = -1; + button.iString = -1; + button.fsStyle = BTNS_SEP; + tb.AddButtons(1, &button); + sepCount++; }; - for (int i = 0; i < _countof(styles); ++i) { - // This fixes missing separator in Win 7 - if (styles[i] & TBBS_SEPARATOR) { - SetButtonInfo(i, GetItemID(i), styles[i], -1); - } else { - SetButtonStyle(i, styles[i] | TBBS_DISABLED); + int sequence = 0; + std::vector buttons = AfxGetMyApp()->GetProfileVectorInt(L"Toolbars\\PlayerToolBar", L"ButtonSequence"); + + addButton(ID_PLAY_PLAY); + addButton(ID_PLAY_PAUSE); + addButton(ID_PLAY_STOP); + + if (buttons.size() >= 5) { //it is required that the toolbar have the 5 standard items, otherwise this is invalid + for (int i = 3; i < buttons.size() - 2; i++) { + addButton(buttons[i]); //todo: validate these are allowed buttons } + } else { //add standard dynamic items + addButton(ID_NAVIGATE_SKIPBACK); + addButton(ID_PLAY_DECRATE); + addButton(ID_PLAY_INCRATE); + addButton(ID_NAVIGATE_SKIPFORWARD); + addButton(ID_PLAY_FRAMESTEP); } + addButton(ID_DUMMYSEPARATOR); + addButton(ID_VOLUME_MUTE); + + + // Should never be RTLed + ModifyStyleEx(WS_EX_LAYOUTRTL, WS_EX_NOINHERITLAYOUT); + + SetMute(AfxGetAppSettings().fMute); + m_volctrl.Create(this); m_volctrl.SetRange(0, 100); @@ -230,55 +303,42 @@ void CPlayerToolBar::ArrangeControls() { CRect br = GetBorders(); CRect vr; - if (AppIsThemeLoaded()) { - float dpiScaling = (float)std::min(m_pMainFrame->m_dpi.ScaleFactorX(), m_pMainFrame->m_dpi.ScaleFactorY()); - int targetsize = int(dpiScaling * AfxGetAppSettings().nDefaultToolbarSize); + float dpiScaling = (float)std::min(m_pMainFrame->m_dpi.ScaleFactorX(), m_pMainFrame->m_dpi.ScaleFactorY()); + int targetsize = int(dpiScaling * AfxGetAppSettings().nDefaultToolbarSize); + + m_volumeCtrlSize = targetsize * 2.5f; + vr = CRect(r.right + br.right - m_volumeCtrlSize, r.top + targetsize / 4, r.right + br.right, r.bottom - targetsize / 4); - m_volumeCtrlSize = targetsize * 2.5f; - vr = CRect(r.right + br.right - m_volumeCtrlSize, r.top+targetsize/4, r.right + br.right, r.bottom-targetsize/4); - } else { - vr = CRect(r.right + br.right - 58, r.top - 2, r.right + br.right + 6, r.bottom); - m_volctrl.MoveWindow(vr); - - CRect thumbRect; - m_volctrl.GetThumbRect(thumbRect); - m_volctrl.MapWindowPoints(this, thumbRect); - vr.top += std::max((r.bottom - thumbRect.bottom - 4) / 2, 0l); - vr.left -= MulDiv(thumbRect.Height(), 50, 19) - 50; - m_volumeCtrlSize = vr.Width(); - } m_volctrl.MoveWindow(vr); - CRect r10; // last normal separator - GetItemRect(10, &r10); - CRect r12; // mute button - GetItemRect(12, &r12); + volumeButtonIndex = GetToolBarCtrl().GetButtonCount() - 1; + dummySeparatorIndex = volumeButtonIndex - 1; + flexibleSpaceIndex = dummySeparatorIndex - 1; - // adjust spacing between controls and mute - int spacing = vr.left - r10.right - r12.Width(); - SetButtonInfo(11, GetItemID(11), TBBS_SEPARATOR, spacing); + CRect rFlexible, rVolumeButton; + GetItemRect(flexibleSpaceIndex, &rFlexible); + GetItemRect(volumeButtonIndex, &rVolumeButton); + int spacing = vr.left - rFlexible.right - rVolumeButton.Width(); + SetButtonInfo(dummySeparatorIndex, GetItemID(dummySeparatorIndex), TBBS_SEPARATOR, spacing); } -void CPlayerToolBar::SetMute(bool fMute) -{ +void CPlayerToolBar::SetMute(bool fMute) { CToolBarCtrl& tb = GetToolBarCtrl(); - TBBUTTONINFO bi; - bi.cbSize = sizeof(bi); + TBBUTTONINFO bi = { sizeof(bi) }; bi.dwMask = TBIF_IMAGE; - bi.iImage = fMute ? 13 : 12; + bi.iImage = VOLUMEBUTTON_SVG_INDEX + (fMute ? 1:0); tb.SetButtonInfo(ID_VOLUME_MUTE, &bi); - AfxGetAppSettings().fMute = fMute; } bool CPlayerToolBar::IsMuted() const { CToolBarCtrl& tb = GetToolBarCtrl(); - TBBUTTONINFO bi; - bi.cbSize = sizeof(bi); + TBBUTTONINFO bi = { sizeof(bi) }; bi.dwMask = TBIF_IMAGE; tb.GetButtonInfo(ID_VOLUME_MUTE, &bi); - return (bi.iImage == 13); + return (bi.iImage == VOLUMEBUTTON_SVG_INDEX + 1); + return AfxGetAppSettings().fMute; } int CPlayerToolBar::GetVolume() const @@ -297,7 +357,7 @@ int CPlayerToolBar::GetMinWidth() const { // button widths are inflated by 7px // 9 buttons + 3 separators + spacing + volume - return 9 * (m_nButtonHeight + 7) + 3 * 8 + 4 + m_volumeCtrlSize; + return buttonCount * (m_nButtonHeight + 1 + 7) + sepCount * (1 + 7) + 4 + m_volumeCtrlSize; } void CPlayerToolBar::SetVolume(int volume) @@ -332,6 +392,10 @@ BEGIN_MESSAGE_MAP(CPlayerToolBar, CToolBar) ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) ON_WM_LBUTTONUP() ON_WM_RBUTTONUP() + ON_NOTIFY_REFLECT(TBN_QUERYDELETE, &CPlayerToolBar::OnTbnQueryDelete) + ON_NOTIFY_REFLECT(TBN_QUERYINSERT, &CPlayerToolBar::OnTbnQueryInsert) + ON_NOTIFY_REFLECT(TBN_TOOLBARCHANGE, &CPlayerToolBar::OnTbnToolbarChange) + ON_WM_MOUSEMOVE() END_MESSAGE_MAP() // CPlayerToolBar message handlers @@ -379,10 +443,10 @@ void CPlayerToolBar::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) lr |= CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT; break; case CDDS_ITEMPREPAINT: - lr |= CDRF_NOTIFYPOSTPAINT; + lr |= CDRF_NOTIFYPOSTPAINT | TBCDRF_NOOFFSET; { if (AppIsThemeLoaded()) { - lr |= TBCDRF_NOBACKGROUND | TBCDRF_NOOFFSET; + lr |= TBCDRF_NOBACKGROUND; if (pTBCD->nmcd.uItemState & CDIS_CHECKED) { drawButtonBG(pTBCD->nmcd, CMPCTheme::PlayerButtonCheckedColor); } else if (pTBCD->nmcd.uItemState & CDIS_HOT) { @@ -396,7 +460,7 @@ void CPlayerToolBar::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) CDC dc; dc.Attach(pTBCD->nmcd.hdc); RECT r; - GetItemRect(11, &r); + GetItemRect(dummySeparatorIndex, &r); if (AppIsThemeLoaded()) { dc.FillSolidRect(&r, CMPCTheme::PlayerBGColor); } else { @@ -492,13 +556,20 @@ void CPlayerToolBar::OnLButtonDown(UINT nFlags, CPoint point) int i = getHitButtonIdx(point); mouseDownL = true; - if (!m_pMainFrame->m_fFullScreen && (i < 0 || (GetButtonStyle(i) & (TBBS_SEPARATOR | TBBS_DISABLED)))) { + bool isShift = (MK_SHIFT & nFlags); + + if (isShift) { + currentlyDraggingButton = i; + } + + DWORD ignoreButtons = TBBS_SEPARATOR | (isShift ? 0 : TBBS_DISABLED); //if shift is pressed, allow dragging + + if (!m_pMainFrame->m_fFullScreen && (i < 0 || (GetButtonStyle(i) & ignoreButtons))) { ClientToScreen(&point); m_pMainFrame->PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y)); } else { __super::OnLButtonDown(nFlags, point); } - m_pMainFrame->RestoreFocus(); } void CPlayerToolBar::OnRButtonDown(UINT nFlags, CPoint point) { @@ -516,7 +587,7 @@ void CPlayerToolBar::OnRButtonDown(UINT nFlags, CPoint point) { int CPlayerToolBar::getHitButtonIdx(CPoint point) { - int hit = -1; // -1 means not on any buttons, mute button is 12/13, others < 10, 11 is empty space between + int hit = -1; // -1 means not on any buttons, mute button is 12/13, others < 10, 11 is empty space between (adipose: dynamic toolbar positions may differ) CRect r; for (int i = 0, j = GetToolBarCtrl().GetButtonCount(); i < j; i++) { @@ -535,12 +606,14 @@ BOOL CPlayerToolBar::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) { TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR; - UINT_PTR nID = pNMHDR->idFrom; + int nID; if (pTTT->uFlags & TTF_IDISHWND) { - nID = ::GetDlgCtrlID((HWND)nID); + nID = ::GetDlgCtrlID((HWND)pNMHDR->idFrom); + } else { + nID = (int)pNMHDR->idFrom; } - - if (nID != ID_VOLUME_MUTE) { + const auto& s = AfxGetAppSettings(); + if (nID != ID_VOLUME_MUTE && s.CommandIDToWMCMD.count(nID) == 0) { return FALSE; } CToolBarCtrl& tb = GetToolBarCtrl(); @@ -548,14 +621,22 @@ BOOL CPlayerToolBar::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) TBBUTTONINFO bi; bi.cbSize = sizeof(bi); bi.dwMask = TBIF_IMAGE; - tb.GetButtonInfo(ID_VOLUME_MUTE, &bi); + if (-1 == tb.GetButtonInfo(nID, &bi)) { //should only fail if they choose not to show volume button + return FALSE; + } static CString strTipText; - if (bi.iImage == 12) { + if (nID != ID_VOLUME_MUTE) { + if (s.CommandIDToWMCMD.count(nID) > 0) { + strTipText.LoadString(s.CommandIDToWMCMD[nID]->dwname); + } else { + return FALSE; + } + } else if (bi.iImage == VOLUMEBUTTON_SVG_INDEX) { strTipText.LoadString(ID_VOLUME_MUTE); - } else if (bi.iImage == 13) { + } else if (bi.iImage == VOLUMEBUTTON_SVG_INDEX +1 ) { strTipText.LoadString(ID_VOLUME_MUTE_OFF); - } else if (bi.iImage == 14) { + } else if (bi.iImage == VOLUMEBUTTON_SVG_INDEX + 2) { strTipText.LoadString(ID_VOLUME_MUTE_DISABLED); } else { return FALSE; @@ -572,6 +653,7 @@ void CPlayerToolBar::OnLButtonUp(UINT nFlags, CPoint point) { mouseDownL = false; CToolBar::OnLButtonUp(nFlags, point); + m_pMainFrame->RestoreFocus(); } void CPlayerToolBar::OnRButtonUp(UINT nFlags, CPoint point) { @@ -610,3 +692,69 @@ void CPlayerToolBar::OnRButtonUp(UINT nFlags, CPoint point) { } } } + + +void CPlayerToolBar::OnTbnQueryDelete(NMHDR* pNMHDR, LRESULT* pResult) { + LPNMTOOLBAR pNMTB = reinterpret_cast(pNMHDR); + auto a = GetToolBarCtrl().GetButtonCount(); + if (pNMTB->iItem < 3 || pNMTB->iItem >= dummySeparatorIndex) { + *pResult = FALSE; + return; + } + *pResult = TRUE; +} + + +void CPlayerToolBar::OnTbnQueryInsert(NMHDR* pNMHDR, LRESULT* pResult) { + LPNMTOOLBAR pNMTB = reinterpret_cast(pNMHDR); + + int width = LOWORD(GetToolBarCtrl().GetButtonSize()); + + CPoint p = mousePosition; + p.x += width / 2; + + int testButton = GetToolBarCtrl().HitTest(&p); + + //according to https://learn.microsoft.com/en-us/windows/win32/Controls/tb-hittest + //"The absolute value of the return value is the index of a separator item" + //but emperical testing shows it is offset by 1 + if (testButton < 0) { + testButton = -1 - testButton; + } + + //this code prevents inserting at the given point + //first test is to prevent inserting the dragged button outside of the "dynamic" area + //second test is to prevent the insertion of a separator directly to the left of the dragged button + if (pNMTB->iItem < 3 || pNMTB->iItem >= volumeButtonIndex //do not allow moving between beginning and ending standard toolbar items + || currentlyDraggingButton+1 == testButton) //undocumented toolbar behavior--if the "testpoint" is on the button to the right, a separator is created to the left + { + *pResult = FALSE; + return; + } + + *pResult = TRUE; +} + + +void CPlayerToolBar::OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult) { + // TODO: Add your control notification handler code here + auto& ctrl = GetToolBarCtrl(); + std::vector buttons; + for (int i = 0; i < ctrl.GetButtonCount(); i++) { + TBBUTTON button; + ctrl.GetButton(i, &button); + int debug = 1; + buttons.push_back(button.idCommand); + } + ArrangeControls(); + + Invalidate(); + *pResult = 0; + AfxGetMyApp()->WriteProfileVectorInt(L"Toolbars\\PlayerToolBar", L"ButtonSequence", buttons); +} + + +void CPlayerToolBar::OnMouseMove(UINT nFlags, CPoint point) { + mousePosition = point; + CToolBar::OnMouseMove(nFlags, point); +} diff --git a/src/mpc-hc/PlayerToolBar.h b/src/mpc-hc/PlayerToolBar.h index f8ac651ee5d..33ca72609cd 100644 --- a/src/mpc-hc/PlayerToolBar.h +++ b/src/mpc-hc/PlayerToolBar.h @@ -35,6 +35,7 @@ class CPlayerToolBar : public CToolBar private: CMainFrame* m_pMainFrame; + CImage volumeOn, volumeOff; bool IsMuted() const; void SetMute(bool fMute = true); int getHitButtonIdx(CPoint point); @@ -47,16 +48,19 @@ class CPlayerToolBar : public CToolBar int m_nButtonHeight; std::unique_ptr m_pButtonsImages; std::unique_ptr m_pDisabledButtonsImages; + int buttonCount, sepCount; int m_volumeCtrlSize; EventClient m_eventc; void EventCallback(MpcEvent ev); - + int volumeButtonIndex, dummySeparatorIndex, flexibleSpaceIndex; + int currentlyDraggingButton, mouseOverButton; + CPoint mousePosition; public: CPlayerToolBar(CMainFrame* pMainFrame); virtual ~CPlayerToolBar(); - bool LoadExternalToolBar(CImage& image, bool useColor); + bool LoadExternalToolBar(CImage& image, float svgscale); int GetVolume() const; int GetMinWidth() const; @@ -64,6 +68,8 @@ class CPlayerToolBar : public CToolBar __declspec(property(get = GetVolume, put = SetVolume)) int Volume; void ArrangeControls(); + CImage& GetVolumeImageOn() { return volumeOn; }; + CImage& GetVolumeImageOff() { return volumeOff; }; CVolumeCtrl m_volctrl; @@ -86,7 +92,6 @@ class CPlayerToolBar : public CToolBar afx_msg void OnNcPaint(); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnRButtonDown(UINT nFlags, CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); //}}AFX_MSG @@ -94,4 +99,8 @@ class CPlayerToolBar : public CToolBar public: afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnRButtonUp(UINT nFlags, CPoint point); + afx_msg void OnTbnQueryDelete(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnTbnQueryInsert(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); }; diff --git a/src/mpc-hc/mplayerc.cpp b/src/mpc-hc/mplayerc.cpp index 10a85204851..88de0955d8d 100644 --- a/src/mpc-hc/mplayerc.cpp +++ b/src/mpc-hc/mplayerc.cpp @@ -1367,6 +1367,33 @@ bool CMPlayerCApp::HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry) return ret; } +std::vector CMPlayerCApp::GetProfileVectorInt(CString strSection, CString strKey) { + std::vector vData; + UINT uSize = theApp.GetProfileInt(strSection, strKey + _T("Size"), 0); + UINT uSizeRead = 0; + BYTE* temp = nullptr; + theApp.GetProfileBinary(strSection, strKey, &temp, &uSizeRead); + if (uSizeRead == uSize) { + vData.resize(uSizeRead / sizeof(int), 0); + memcpy(vData.data(), temp, uSizeRead); + } + delete[] temp; + temp = nullptr; + return vData; +} + + +void CMPlayerCApp::WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData) { + UINT uSize = static_cast(sizeof(int) * vData.size()); + theApp.WriteProfileBinary( + strSection, + strKey, + (LPBYTE)vData.data(), + uSize + ); + theApp.WriteProfileInt(strSection, strKey + _T("Size"), uSize); +} + void CMPlayerCApp::PreProcessCommandLine() { m_cmdln.RemoveAll(); diff --git a/src/mpc-hc/mplayerc.h b/src/mpc-hc/mplayerc.h index 6757562ba51..8ec7937dc75 100644 --- a/src/mpc-hc/mplayerc.h +++ b/src/mpc-hc/mplayerc.h @@ -179,6 +179,8 @@ class CMPlayerCApp : public CWinAppEx virtual BOOL WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) override; virtual BOOL WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) override; bool HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry); + std::vector GetProfileVectorInt(CString strSection, CString strKey); + void WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData); bool GetAppSavePath(CString& path); bool GetAppDataPath(CString& path); diff --git a/src/mpc-hc/res/buttons.svg b/src/mpc-hc/res/buttons.svg new file mode 100644 index 00000000000..d11b784ad74 --- /dev/null +++ b/src/mpc-hc/res/buttons.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mpc-hc/res/mpc-hc.rc2 b/src/mpc-hc/res/mpc-hc.rc2 index 3a090587020432d2a0a8826da2415e044349abb2..0f211a1f0e6bcd8d7851a7ab7e47841a62b4cdb8 100644 GIT binary patch delta 70 zcmew|i?MGGH;1{%aRLCH-4aIt delta 14 WcmeC1!}w(u Date: Sun, 2 Feb 2025 17:07:08 -0800 Subject: [PATCH 02/20] support customize dialog --- src/mpc-hc/PlayerToolBar.cpp | 122 +++++++++++++++++++++++++++-------- src/mpc-hc/PlayerToolBar.h | 11 +++- 2 files changed, 103 insertions(+), 30 deletions(-) diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index ae3d6fab23d..adc17656dcf 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -37,6 +37,7 @@ struct svgButtonInfo { UINT style; int svgIndex; + CString text; }; //svg has 30 positions @@ -61,6 +62,8 @@ static std::map supportedSvgButtons = { {ID_VOLUME_MUTE, {TBBS_CHECKBOX,VOLUMEBUTTON_SVG_INDEX}}, }; +static std::vector supportedSvgButtonsSeq; + IMPLEMENT_DYNAMIC(CPlayerToolBar, CToolBar) CPlayerToolBar::CPlayerToolBar(CMainFrame* pMainFrame) : m_pMainFrame(pMainFrame) @@ -72,6 +75,7 @@ CPlayerToolBar::CPlayerToolBar(CMainFrame* pMainFrame) , dummySeparatorIndex(11) , flexibleSpaceIndex(10) , currentlyDraggingButton(-1) + , toolbarAdjustActive(false) { GetEventd().Connect(m_eventc, { MpcEvent::DPI_CHANGED, @@ -92,7 +96,7 @@ bool CPlayerToolBar::LoadExternalToolBar(CImage& image, float svgscale) paths.emplace_back(appDataPath); } CString basetbname; - basetbname = _T("buttons-."); + basetbname = _T("buttons."); // Try loading the external toolbar for (const auto& path : paths) { @@ -209,6 +213,15 @@ void CPlayerToolBar::LoadToolbarImage() } +TBBUTTON CPlayerToolBar::GetStandardButton(int cmdid) { + auto& svgInfo = supportedSvgButtons[cmdid]; + TBBUTTON button = { 0 }; + button.iBitmap = svgInfo.svgIndex; + button.idCommand = cmdid; + button.iString = -1; + return button; +} + BOOL CPlayerToolBar::Create(CWnd* pParentWnd) { VERIFY(__super::CreateEx(pParentWnd, @@ -228,10 +241,7 @@ BOOL CPlayerToolBar::Create(CWnd* pParentWnd) auto addButton = [&](int cmdid) { auto& svgInfo = supportedSvgButtons[cmdid]; - TBBUTTON button = { 0 }; - button.iBitmap = svgInfo.svgIndex; - button.idCommand = cmdid; - button.iString = -1; + TBBUTTON button = GetStandardButton(cmdid); tb.AddButtons(1, &button); SetButtonStyle(tb.GetButtonCount() - 1, svgInfo.style | TBBS_DISABLED); buttonCount++; @@ -246,6 +256,13 @@ BOOL CPlayerToolBar::Create(CWnd* pParentWnd) sepCount++; }; + for (auto& it : supportedSvgButtons) { + if (it.second.svgIndex != -1) { + it.second.text.LoadString(s.CommandIDToWMCMD[it.first]->dwname); + supportedSvgButtonsSeq.push_back(it.first); + } + } + int sequence = 0; std::vector buttons = AfxGetMyApp()->GetProfileVectorInt(L"Toolbars\\PlayerToolBar", L"ButtonSequence"); @@ -396,6 +413,10 @@ BEGIN_MESSAGE_MAP(CPlayerToolBar, CToolBar) ON_NOTIFY_REFLECT(TBN_QUERYINSERT, &CPlayerToolBar::OnTbnQueryInsert) ON_NOTIFY_REFLECT(TBN_TOOLBARCHANGE, &CPlayerToolBar::OnTbnToolbarChange) ON_WM_MOUSEMOVE() + ON_NOTIFY_REFLECT(TBN_GETBUTTONINFO, &CPlayerToolBar::OnTbnGetButtonInfo) + ON_NOTIFY_REFLECT(TBN_INITCUSTOMIZE, &CPlayerToolBar::OnTbnInitCustomize) + ON_NOTIFY_REFLECT(TBN_BEGINADJUST, &CPlayerToolBar::OnTbnBeginAdjust) + ON_NOTIFY_REFLECT(TBN_ENDADJUST, &CPlayerToolBar::OnTbnEndAdjust) END_MESSAGE_MAP() // CPlayerToolBar message handlers @@ -708,25 +729,32 @@ void CPlayerToolBar::OnTbnQueryDelete(NMHDR* pNMHDR, LRESULT* pResult) { void CPlayerToolBar::OnTbnQueryInsert(NMHDR* pNMHDR, LRESULT* pResult) { LPNMTOOLBAR pNMTB = reinterpret_cast(pNMHDR); - int width = LOWORD(GetToolBarCtrl().GetButtonSize()); + bool preventSeparatorInsert = false; + + if (!toolbarAdjustActive) { + int width = LOWORD(GetToolBarCtrl().GetButtonSize()); - CPoint p = mousePosition; - p.x += width / 2; + CPoint p = mousePosition; + p.x += width / 2; - int testButton = GetToolBarCtrl().HitTest(&p); + int testButton = GetToolBarCtrl().HitTest(&p); - //according to https://learn.microsoft.com/en-us/windows/win32/Controls/tb-hittest - //"The absolute value of the return value is the index of a separator item" - //but emperical testing shows it is offset by 1 - if (testButton < 0) { - testButton = -1 - testButton; + //according to https://learn.microsoft.com/en-us/windows/win32/Controls/tb-hittest + //"The absolute value of the return value is the index of a separator item" + //but emperical testing shows it is offset by 1 + if (testButton < 0) { + testButton = -1 - testButton; + } + + //undocumented toolbar behavior--if the "testpoint" is on the button to the right, a separator is created to the left + preventSeparatorInsert = (currentlyDraggingButton + 1 == testButton); } //this code prevents inserting at the given point - //first test is to prevent inserting the dragged button outside of the "dynamic" area + //first test is to prevent inserting buttons outside of the "dynamic" area //second test is to prevent the insertion of a separator directly to the left of the dragged button if (pNMTB->iItem < 3 || pNMTB->iItem >= volumeButtonIndex //do not allow moving between beginning and ending standard toolbar items - || currentlyDraggingButton+1 == testButton) //undocumented toolbar behavior--if the "testpoint" is on the button to the right, a separator is created to the left + || preventSeparatorInsert) { *pResult = FALSE; return; @@ -736,21 +764,27 @@ void CPlayerToolBar::OnTbnQueryInsert(NMHDR* pNMHDR, LRESULT* pResult) { } -void CPlayerToolBar::OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult) { - // TODO: Add your control notification handler code here - auto& ctrl = GetToolBarCtrl(); - std::vector buttons; - for (int i = 0; i < ctrl.GetButtonCount(); i++) { - TBBUTTON button; - ctrl.GetButton(i, &button); - int debug = 1; - buttons.push_back(button.idCommand); +void CPlayerToolBar::SaveToolbarState() { + return; + if (!toolbarAdjustActive) { + auto& ctrl = GetToolBarCtrl(); + std::vector buttons; + for (int i = 0; i < ctrl.GetButtonCount(); i++) { + TBBUTTON button; + ctrl.GetButton(i, &button); + int debug = 1; + buttons.push_back(button.idCommand); + } + ArrangeControls(); + + Invalidate(); + AfxGetMyApp()->WriteProfileVectorInt(L"Toolbars\\PlayerToolBar", L"ButtonSequence", buttons); } - ArrangeControls(); +} - Invalidate(); +void CPlayerToolBar::OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult) { + SaveToolbarState(); *pResult = 0; - AfxGetMyApp()->WriteProfileVectorInt(L"Toolbars\\PlayerToolBar", L"ButtonSequence", buttons); } @@ -758,3 +792,35 @@ void CPlayerToolBar::OnMouseMove(UINT nFlags, CPoint point) { mousePosition = point; CToolBar::OnMouseMove(nFlags, point); } + + +void CPlayerToolBar::OnTbnGetButtonInfo(NMHDR* pNMHDR, LRESULT* pResult) { + LPNMTOOLBAR pNMTB = reinterpret_cast(pNMHDR); + if (pNMTB->iItem < supportedSvgButtonsSeq.size()) { + int cmdid = supportedSvgButtonsSeq[pNMTB->iItem]; + TBBUTTON t = GetStandardButton(cmdid); + t.iString = (INT_PTR)supportedSvgButtons[t.idCommand].text.GetString(); + pNMTB->tbButton = t; + *pResult = TRUE; + return; + } + *pResult = 0; +} + + +void CPlayerToolBar::OnTbnInitCustomize(NMHDR* pNMHDR, LRESULT* pResult) { + *pResult = TBNRF_HIDEHELP; +} + + +void CPlayerToolBar::OnTbnBeginAdjust(NMHDR* pNMHDR, LRESULT* pResult) { + toolbarAdjustActive = true; + *pResult = 0; +} + + +void CPlayerToolBar::OnTbnEndAdjust(NMHDR* pNMHDR, LRESULT* pResult) { + toolbarAdjustActive = false; + SaveToolbarState(); + *pResult = 0; +} diff --git a/src/mpc-hc/PlayerToolBar.h b/src/mpc-hc/PlayerToolBar.h index 33ca72609cd..f1d4fe13159 100644 --- a/src/mpc-hc/PlayerToolBar.h +++ b/src/mpc-hc/PlayerToolBar.h @@ -41,6 +41,7 @@ class CPlayerToolBar : public CToolBar int getHitButtonIdx(CPoint point); bool LoadExternalToolBar(CImage& image); void LoadToolbarImage(); + TBBUTTON GetStandardButton(int cmdid); bool mouseDownL, mouseDownR; int rightButtonIndex=-1; CMPCThemeToolTipCtrl themedToolTip; @@ -54,8 +55,9 @@ class CPlayerToolBar : public CToolBar EventClient m_eventc; void EventCallback(MpcEvent ev); int volumeButtonIndex, dummySeparatorIndex, flexibleSpaceIndex; - int currentlyDraggingButton, mouseOverButton; + int currentlyDraggingButton; CPoint mousePosition; + bool toolbarAdjustActive; public: CPlayerToolBar(CMainFrame* pMainFrame); virtual ~CPlayerToolBar(); @@ -101,6 +103,11 @@ class CPlayerToolBar : public CToolBar afx_msg void OnRButtonUp(UINT nFlags, CPoint point); afx_msg void OnTbnQueryDelete(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnTbnQueryInsert(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void SaveToolbarState(); + void OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnTbnGetButtonInfo(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnTbnInitCustomize(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnTbnBeginAdjust(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnTbnEndAdjust(NMHDR* pNMHDR, LRESULT* pResult); }; From ef94cc7dea6b9d94ade4cdbb068bcadf466dd60d Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 2 Feb 2025 17:34:01 -0800 Subject: [PATCH 03/20] arrangecontrols outside savestate --- src/mpc-hc/PlayerToolBar.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index adc17656dcf..274b9e9028c 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -717,7 +717,6 @@ void CPlayerToolBar::OnRButtonUp(UINT nFlags, CPoint point) { void CPlayerToolBar::OnTbnQueryDelete(NMHDR* pNMHDR, LRESULT* pResult) { LPNMTOOLBAR pNMTB = reinterpret_cast(pNMHDR); - auto a = GetToolBarCtrl().GetButtonCount(); if (pNMTB->iItem < 3 || pNMTB->iItem >= dummySeparatorIndex) { *pResult = FALSE; return; @@ -765,25 +764,22 @@ void CPlayerToolBar::OnTbnQueryInsert(NMHDR* pNMHDR, LRESULT* pResult) { void CPlayerToolBar::SaveToolbarState() { - return; if (!toolbarAdjustActive) { auto& ctrl = GetToolBarCtrl(); std::vector buttons; for (int i = 0; i < ctrl.GetButtonCount(); i++) { TBBUTTON button; ctrl.GetButton(i, &button); - int debug = 1; buttons.push_back(button.idCommand); } - ArrangeControls(); - - Invalidate(); AfxGetMyApp()->WriteProfileVectorInt(L"Toolbars\\PlayerToolBar", L"ButtonSequence", buttons); } } void CPlayerToolBar::OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult) { SaveToolbarState(); + ArrangeControls(); + Invalidate(); *pResult = 0; } From 0cffe30bece155fc3a818cd79460cad59d2a36ec Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Thu, 13 Feb 2025 10:39:42 -0800 Subject: [PATCH 04/20] support theming of customize toolbar dialog --- src/mpc-hc/CMPCThemeDialog.cpp | 9 +++++++++ src/mpc-hc/CMPCThemeDialog.h | 1 + src/mpc-hc/CMPCThemeListBox.cpp | 26 ++++++++++++++++++++++---- src/mpc-hc/CMPCThemeListBox.h | 2 ++ src/mpc-hc/CMPCThemeUtil.cpp | 31 +++++++++++++++++++++++++++---- src/mpc-hc/CMPCThemeUtil.h | 6 ++++-- src/mpc-hc/MainFrm.cpp | 33 ++++++++++++++++++++++----------- src/mpc-hc/MainFrm.h | 13 ++++++++++--- src/mpc-hc/PlayerToolBar.cpp | 7 +++++++ src/mpc-hc/PlayerToolBar.h | 5 +++-- 10 files changed, 107 insertions(+), 26 deletions(-) diff --git a/src/mpc-hc/CMPCThemeDialog.cpp b/src/mpc-hc/CMPCThemeDialog.cpp index 69071251064..460cd01b730 100755 --- a/src/mpc-hc/CMPCThemeDialog.cpp +++ b/src/mpc-hc/CMPCThemeDialog.cpp @@ -22,6 +22,7 @@ CMPCThemeDialog::~CMPCThemeDialog() IMPLEMENT_DYNAMIC(CMPCThemeDialog, CDialog) BEGIN_MESSAGE_MAP(CMPCThemeDialog, CDialog) + ON_COMMAND_EX(IDOK, OnOK_EX) ON_WM_CTLCOLOR() ON_WM_HSCROLL() END_MESSAGE_MAP() @@ -56,3 +57,11 @@ void CMPCThemeDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) UpdateAnalogCaptureDeviceSlider(pScrollBar); } } + +BOOL CMPCThemeDialog::OnOK_EX(UINT nId) { + if (ToolbarCustomizeDialog == specialCase) { //the toolbar customize dialog has assigned 1==IDOK to the "add" button, which CDialog interprets as `EndDialog(IDOK)` + return FALSE; + } + __super::OnOK(); + return TRUE; +} diff --git a/src/mpc-hc/CMPCThemeDialog.h b/src/mpc-hc/CMPCThemeDialog.h index 6d5282a60fa..bfaae9bfce1 100755 --- a/src/mpc-hc/CMPCThemeDialog.h +++ b/src/mpc-hc/CMPCThemeDialog.h @@ -19,6 +19,7 @@ class CMPCThemeDialog : DECLARE_MESSAGE_MAP() afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL OnOK_EX(UINT nId); private: bool isDummy = false; CMPCThemeUtil::SpecialThemeCases specialCase = NoSpecialCase; diff --git a/src/mpc-hc/CMPCThemeListBox.cpp b/src/mpc-hc/CMPCThemeListBox.cpp index dcd8480b5ab..a636d54c9d9 100755 --- a/src/mpc-hc/CMPCThemeListBox.cpp +++ b/src/mpc-hc/CMPCThemeListBox.cpp @@ -7,6 +7,7 @@ IMPLEMENT_DYNAMIC(CMPCThemeListBox, CListBox) CMPCThemeListBox::CMPCThemeListBox() + :customizeToolBar(nullptr) { themedToolTipCid = (UINT_PTR) - 1; themedSBHelper = nullptr; @@ -42,27 +43,44 @@ void CMPCThemeListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) } dc.Attach(lpDrawItemStruct->hDC); + int buttonID = (int16_t)LOWORD(lpDrawItemStruct->itemData); + + CRect rc(lpDrawItemStruct->rcItem); + COLORREF crOldTextColor = dc.GetTextColor(); COLORREF crOldBkColor = dc.GetBkColor(); if ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED)) { dc.SetTextColor(CMPCTheme::TextFGColor); dc.SetBkColor(CMPCTheme::ContentSelectedColor); - dc.FillSolidRect(&lpDrawItemStruct->rcItem, CMPCTheme::ContentSelectedColor); + dc.FillSolidRect(&rc, CMPCTheme::ContentSelectedColor); } else { dc.SetTextColor(CMPCTheme::TextFGColor); dc.SetBkColor(CMPCTheme::ContentBGColor); - dc.FillSolidRect(&lpDrawItemStruct->rcItem, CMPCTheme::ContentBGColor); + dc.FillSolidRect(&rc, CMPCTheme::ContentBGColor); + } + + if (customizeToolBar) { + if (buttonID != -1) { + auto list = customizeToolBar->GetToolBarCtrl().GetImageList(); + IMAGEINFO ii; + list->GetImageInfo(buttonID, &ii); + CRect rci(ii.rcImage); + int border = (rc.Height() - rci.Height()) / 2; + border = border < 0 ? 0 : border; + list->Draw(&dc, buttonID, rc.TopLeft() + CPoint(border, border), ILD_NORMAL); + } + rc.left += rc.Height(); } - lpDrawItemStruct->rcItem.left += 3; + rc.left += 3; CString strText; GetText(lpDrawItemStruct->itemID, strText); CFont* font = GetFont(); CFont* pOldFont = dc.SelectObject(font); - dc.DrawTextW(strText, strText.GetLength(), &lpDrawItemStruct->rcItem, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); + dc.DrawTextW(strText, strText.GetLength(), &rc, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); dc.SetTextColor(crOldTextColor); dc.SetBkColor(crOldBkColor); diff --git a/src/mpc-hc/CMPCThemeListBox.h b/src/mpc-hc/CMPCThemeListBox.h index 790d43af48e..ad38d24013d 100755 --- a/src/mpc-hc/CMPCThemeListBox.h +++ b/src/mpc-hc/CMPCThemeListBox.h @@ -13,6 +13,7 @@ class CMPCThemeListBox : CMPCThemeToolTipCtrl themedToolTip; UINT_PTR themedToolTipCid; CMPCThemeScrollBarHelper* themedSBHelper; + CToolBar* customizeToolBar; protected: virtual void PreSubclassWindow(); public: @@ -31,5 +32,6 @@ class CMPCThemeListBox : void setIntegralHeight(); afx_msg void OnSize(UINT nType, int cx, int cy); void EnsureVisible(int index); + void SetCustomizeToolbar(CToolBar* tb) { customizeToolBar = tb; }; }; diff --git a/src/mpc-hc/CMPCThemeUtil.cpp b/src/mpc-hc/CMPCThemeUtil.cpp index eb755a30e94..53259dabff7 100755 --- a/src/mpc-hc/CMPCThemeUtil.cpp +++ b/src/mpc-hc/CMPCThemeUtil.cpp @@ -35,8 +35,25 @@ CMPCThemeUtil::~CMPCThemeUtil() } } +void CMPCThemeUtil::subClassTBCustomizeDialog(CWnd* wnd, CToolBar* customizeToolBar) +{ + CWnd* c = CWnd::FromHandle(themableDialogHandle); + CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(); + pObject->SetSpecialCase(ToolbarCustomizeDialog); + makeThemed(pObject, c); + fulfillThemeReqs(c, ToolbarCustomizeDialog, customizeToolBar); + + ::RedrawWindow(themableDialogHandle, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_ERASE); + + if (AfxGetAppSettings().bWindows10DarkThemeActive) { + enableWindows10DarkFrame(pObject); + //force titlebar redraw + c->SendMessage(WM_NCACTIVATE, FALSE); + c->SendMessage(WM_NCACTIVATE, TRUE); + } +} -void CMPCThemeUtil::fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase /* = 0 */) +void CMPCThemeUtil::fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase /* = 0 */, CWnd* otherWindow /* = nullptr */) { if (AppIsThemeLoaded()) { @@ -129,6 +146,12 @@ void CMPCThemeUtil::fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase /* } else if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { CMPCThemeComboBox* pObject = DEBUG_NEW CMPCThemeComboBox(); makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, WC_LISTBOX)) { + CMPCThemeListBox* pObject = DEBUG_NEW CMPCThemeListBox(); + makeThemed(pObject, tChild); + if (specialCase == ToolbarCustomizeDialog) { + pObject->SetCustomizeToolbar ((CToolBar*)otherWindow); + } } else if (0 == _tcsicmp(windowClass, TRACKBAR_CLASS)) { CMPCThemeSliderCtrl* pObject = DEBUG_NEW CMPCThemeSliderCtrl(); makeThemed(pObject, tChild); @@ -274,16 +297,16 @@ void CMPCThemeUtil::subClassFileDialog(CWnd* wnd) { if (AfxGetAppSettings().bWindows10DarkThemeActive) { initHelperObjects(); - HWND duiview = ::FindWindowExW(fileDialogHandle, NULL, L"DUIViewWndClassName", NULL); + HWND duiview = ::FindWindowExW(themableDialogHandle, NULL, L"DUIViewWndClassName", NULL); HWND duihwnd = ::FindWindowExW(duiview, NULL, L"DirectUIHWND", NULL); if (duihwnd) { //we found the FileDialog if (dialogProminentControlStringID) { //if this is set, we assume there is a single prominent control (note, it's in the filedialog main window) - subClassFileDialogRecurse(wnd, fileDialogHandle, ProminentControlIDWidget); + subClassFileDialogRecurse(wnd, themableDialogHandle, ProminentControlIDWidget); } else { subClassFileDialogRecurse(wnd, duihwnd, RecurseSinkWidgets); } - fileDialogHandle = nullptr; + themableDialogHandle = nullptr; ::RedrawWindow(duiview, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); } } diff --git a/src/mpc-hc/CMPCThemeUtil.h b/src/mpc-hc/CMPCThemeUtil.h index 678af411809..cfd45d5fe1a 100644 --- a/src/mpc-hc/CMPCThemeUtil.h +++ b/src/mpc-hc/CMPCThemeUtil.h @@ -18,6 +18,7 @@ class CMPCThemeUtil NoSpecialCase = 0, ExternalPropertyPageWithDefaultButton, ExternalPropertyPageWithAnalogCaptureSliders, + ToolbarCustomizeDialog }; enum WidgetPairType { @@ -44,12 +45,13 @@ class CMPCThemeUtil ,ProminentControlIDWidget }; - HWND fileDialogHandle = nullptr; + HWND themableDialogHandle = nullptr; void enableFileDialogHook(); void subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType); void subClassFileDialog(CWnd* wnd); void subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass); void redrawAllThemedWidgets(); + void subClassTBCustomizeDialog(CWnd* wnd, CToolBar* tb); protected: int dialogProminentControlStringID = 0; @@ -57,7 +59,7 @@ class CMPCThemeUtil static NONCLIENTMETRICS nonClientMetrics; std::vector allocatedWindows; - void fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase); + void fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase, CWnd* otherWindow = nullptr); static void initHelperObjects(); void makeThemed(CWnd* pObject, CWnd* tChild); diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 06ad7dbaca3..7f96c4c48bb 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -897,8 +897,8 @@ CMainFrame::CMainFrame() , m_bExtOnTop(false) , m_bIsBDPlay(false) , m_bHasBDMeta(false) - , watchingFileDialog(false) - , fileDialogHookHelper(nullptr) + , watchingDialog(themableDialogTypes::None) + , dialogHookHelper(nullptr) , delayingFullScreen(false) , restoringWindowRect(false) , mediaTypesErrorDlg(nullptr) @@ -20767,11 +20767,17 @@ BOOL CMainFrame::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwS return FALSE; } -void CMainFrame::enableFileDialogHook(CMPCThemeUtil* helper) -{ +void CMainFrame::enableFileDialogHook(CMPCThemeUtil* helper) { if (AfxGetAppSettings().bWindows10DarkThemeActive) { //hard coded behavior for windows 10 dark theme file dialogs, irrespsective of theme loaded by user (fixing windows bugs) - watchingFileDialog = true; - fileDialogHookHelper = helper; + watchingDialog = themableDialogTypes::windowsFileDialog; + dialogHookHelper = helper; + } +} + +void CMainFrame::enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type) { + if (AppIsThemeLoaded()) { + watchingDialog = type; + dialogHookHelper = helper; } } @@ -20830,12 +20836,17 @@ LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) break; } return 0; - } else if (watchingFileDialog && nullptr != fileDialogHookHelper && message == WM_ACTIVATE && LOWORD(wParam) == WA_INACTIVE) { - fileDialogHookHelper->fileDialogHandle = (HWND)lParam; - watchingFileDialog = false; + } else if (watchingDialog != themableDialogTypes::None && nullptr != dialogHookHelper && message == WM_ACTIVATE && LOWORD(wParam) == WA_INACTIVE) { + dialogHookHelper->themableDialogHandle = (HWND)lParam; + foundDialog = watchingDialog; + watchingDialog = themableDialogTypes::None; //capture but process message normally - } else if (message == WM_GETICON && nullptr != fileDialogHookHelper && nullptr != fileDialogHookHelper->fileDialogHandle) { - fileDialogHookHelper->subClassFileDialog(this); + } else if (message == WM_GETICON && foundDialog == themableDialogTypes::windowsFileDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { + dialogHookHelper->subClassFileDialog(this); + foundDialog = themableDialogTypes::None; + } else if (message == WM_ENTERIDLE && foundDialog == themableDialogTypes::toolbarCustomizeDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { + dialogHookHelper->subClassTBCustomizeDialog(this, &m_wndToolBar); + foundDialog = themableDialogTypes::None; } if (message == WM_NCLBUTTONDOWN && wParam == HTCAPTION && !m_pMVRSR) { diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 65c78632308..35e434dffa8 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1269,7 +1269,6 @@ class CMainFrame : public CFrameWnd, public CDropClient DWORD dwExStyle = 0, CCreateContext* pContext = NULL); CMPCThemeMenu* defaultMPCThemeMenu = nullptr; - void enableFileDialogHook(CMPCThemeUtil* helper); bool isSafeZone(CPoint pt); @@ -1390,9 +1389,17 @@ class CMainFrame : public CFrameWnd, public CDropClient void MediaTransportControlSetMedia(); void MediaTransportControlUpdateState(OAFilterState state); + enum themableDialogTypes { + None, + windowsFileDialog, + toolbarCustomizeDialog + }; + void enableFileDialogHook(CMPCThemeUtil* helper); + void enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type); private: - bool watchingFileDialog; - CMPCThemeUtil* fileDialogHookHelper; + themableDialogTypes watchingDialog, foundDialog; + CMPCThemeUtil* dialogHookHelper; + public: afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); afx_msg void OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt); diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index 274b9e9028c..473441595ac 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -417,6 +417,7 @@ BEGIN_MESSAGE_MAP(CPlayerToolBar, CToolBar) ON_NOTIFY_REFLECT(TBN_INITCUSTOMIZE, &CPlayerToolBar::OnTbnInitCustomize) ON_NOTIFY_REFLECT(TBN_BEGINADJUST, &CPlayerToolBar::OnTbnBeginAdjust) ON_NOTIFY_REFLECT(TBN_ENDADJUST, &CPlayerToolBar::OnTbnEndAdjust) + ON_WM_LBUTTONDBLCLK() END_MESSAGE_MAP() // CPlayerToolBar message handlers @@ -820,3 +821,9 @@ void CPlayerToolBar::OnTbnEndAdjust(NMHDR* pNMHDR, LRESULT* pResult) { SaveToolbarState(); *pResult = 0; } + + +void CPlayerToolBar::OnLButtonDblClk(UINT nFlags, CPoint point) { + m_pMainFrame->enableDialogHook(this, CMainFrame::themableDialogTypes::toolbarCustomizeDialog); + CToolBar::OnLButtonDblClk(nFlags, point); +} diff --git a/src/mpc-hc/PlayerToolBar.h b/src/mpc-hc/PlayerToolBar.h index f1d4fe13159..1bd2160e7b0 100644 --- a/src/mpc-hc/PlayerToolBar.h +++ b/src/mpc-hc/PlayerToolBar.h @@ -23,12 +23,12 @@ #include "VolumeCtrl.h" #include "CMPCThemeToolTipCtrl.h" - +#include "CMPCThemeUtil.h" #include class CMainFrame; -class CPlayerToolBar : public CToolBar +class CPlayerToolBar : public CToolBar, public CMPCThemeUtil { DECLARE_DYNAMIC(CPlayerToolBar) @@ -110,4 +110,5 @@ class CPlayerToolBar : public CToolBar afx_msg void OnTbnInitCustomize(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnTbnBeginAdjust(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnTbnEndAdjust(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); }; From b5e7e54f56732fd2e7dcfcd9069b4626af5bd347 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Thu, 13 Feb 2025 13:19:24 -0800 Subject: [PATCH 05/20] use light buttons for light modern theme --- src/mpc-hc/PlayerToolBar.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index 473441595ac..f4bd65f3815 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -110,6 +110,8 @@ bool CPlayerToolBar::LoadExternalToolBar(CImage& image, float svgscale) void CPlayerToolBar::LoadToolbarImage() { + auto& s = AfxGetAppSettings(); + // We are currently not aware of any cases where the scale factors are different float dpiScaling = (float)std::min(m_pMainFrame->m_dpi.ScaleFactorX(), m_pMainFrame->m_dpi.ScaleFactorY()); int targetsize = int(dpiScaling * AfxGetAppSettings().nDefaultToolbarSize); @@ -167,7 +169,7 @@ void CPlayerToolBar::LoadToolbarImage() pOldSourceBmp = sourceDC.GetCurrentBitmap(); int imageOffset = 0, imageDisabledOffset=height; - if (AppIsThemeLoaded()) { + if (AppIsThemeLoaded() && s.eModernThemeMode == CMPCTheme::ModernThemeMode::DARK) { imageOffset = height * 2; imageDisabledOffset = height * 3; } From 21f96d76c65b9d64efff4ef60ba0b6365d97fd74 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Thu, 13 Feb 2025 14:19:52 -0800 Subject: [PATCH 06/20] support tb reset --- src/mpc-hc/PlayerToolBar.cpp | 95 +++++++++++++++++++++--------------- src/mpc-hc/PlayerToolBar.h | 2 + 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index f4bd65f3815..064f2044c78 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -238,6 +238,42 @@ BOOL CPlayerToolBar::Create(CWnd* pParentWnd) dummySeparatorIndex = -1; volumeButtonIndex = -1; flexibleSpaceIndex = -1; + + for (auto& it : supportedSvgButtons) { + if (it.second.svgIndex != -1) { + it.second.text.LoadString(s.CommandIDToWMCMD[it.first]->dwname); + supportedSvgButtonsSeq.push_back(it.first); + } + } + + PlaceButtons(true); + + // Should never be RTLed + ModifyStyleEx(WS_EX_LAYOUTRTL, WS_EX_NOINHERITLAYOUT); + + SetMute(AfxGetAppSettings().fMute); + + m_volctrl.Create(this); + m_volctrl.SetRange(0, 100); + + m_nButtonHeight = 16; // reset m_nButtonHeight + + LoadToolbarImage(); + + if (AppIsThemeLoaded()) { + themedToolTip.enableFlickerHelper(); //avoid flicker on button hover + themedToolTip.Create(this, TTS_ALWAYSTIP); + tb.SetToolTips(&themedToolTip); + } else { + tb.EnableToolTips(); + } + + return TRUE; +} + +void CPlayerToolBar::PlaceButtons(bool loadSavedLayout) { + CToolBarCtrl& tb = GetToolBarCtrl(); + buttonCount = 0; sepCount = 0; @@ -249,25 +285,11 @@ BOOL CPlayerToolBar::Create(CWnd* pParentWnd) buttonCount++; }; - auto addSeparator = [&]() { - TBBUTTON button = { 0 }; - button.iBitmap = -1; - button.iString = -1; - button.fsStyle = BTNS_SEP; - tb.AddButtons(1, &button); - sepCount++; - }; - - for (auto& it : supportedSvgButtons) { - if (it.second.svgIndex != -1) { - it.second.text.LoadString(s.CommandIDToWMCMD[it.first]->dwname); - supportedSvgButtonsSeq.push_back(it.first); - } + std::vector buttons(0); + if (loadSavedLayout) { + buttons = AfxGetMyApp()->GetProfileVectorInt(L"Toolbars\\PlayerToolBar", L"ButtonSequence"); } - int sequence = 0; - std::vector buttons = AfxGetMyApp()->GetProfileVectorInt(L"Toolbars\\PlayerToolBar", L"ButtonSequence"); - addButton(ID_PLAY_PLAY); addButton(ID_PLAY_PAUSE); addButton(ID_PLAY_STOP); @@ -286,29 +308,6 @@ BOOL CPlayerToolBar::Create(CWnd* pParentWnd) addButton(ID_DUMMYSEPARATOR); addButton(ID_VOLUME_MUTE); - - - // Should never be RTLed - ModifyStyleEx(WS_EX_LAYOUTRTL, WS_EX_NOINHERITLAYOUT); - - SetMute(AfxGetAppSettings().fMute); - - m_volctrl.Create(this); - m_volctrl.SetRange(0, 100); - - m_nButtonHeight = 16; // reset m_nButtonHeight - - LoadToolbarImage(); - - if (AppIsThemeLoaded()) { - themedToolTip.enableFlickerHelper(); //avoid flicker on button hover - themedToolTip.Create(this, TTS_ALWAYSTIP); - tb.SetToolTips(&themedToolTip); - } else { - tb.EnableToolTips(); - } - - return TRUE; } void CPlayerToolBar::ArrangeControls() { @@ -420,6 +419,7 @@ BEGIN_MESSAGE_MAP(CPlayerToolBar, CToolBar) ON_NOTIFY_REFLECT(TBN_BEGINADJUST, &CPlayerToolBar::OnTbnBeginAdjust) ON_NOTIFY_REFLECT(TBN_ENDADJUST, &CPlayerToolBar::OnTbnEndAdjust) ON_WM_LBUTTONDBLCLK() + ON_NOTIFY_REFLECT(TBN_RESET, &CPlayerToolBar::OnTbnReset) END_MESSAGE_MAP() // CPlayerToolBar message handlers @@ -829,3 +829,18 @@ void CPlayerToolBar::OnLButtonDblClk(UINT nFlags, CPoint point) { m_pMainFrame->enableDialogHook(this, CMainFrame::themableDialogTypes::toolbarCustomizeDialog); CToolBar::OnLButtonDblClk(nFlags, point); } + + +void CPlayerToolBar::OnTbnReset(NMHDR* pNMHDR, LRESULT* pResult) { + // TODO: Add your control notification handler code here + CToolBarCtrl& tb = GetToolBarCtrl(); + + for (int i = tb.GetButtonCount()-1; i >= 0; i--) { + tb.DeleteButton(i); + } + PlaceButtons(false); + ArrangeControls(); + Invalidate(); + + *pResult = 0; +} diff --git a/src/mpc-hc/PlayerToolBar.h b/src/mpc-hc/PlayerToolBar.h index 1bd2160e7b0..b63a4bb1bc0 100644 --- a/src/mpc-hc/PlayerToolBar.h +++ b/src/mpc-hc/PlayerToolBar.h @@ -42,6 +42,7 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil bool LoadExternalToolBar(CImage& image); void LoadToolbarImage(); TBBUTTON GetStandardButton(int cmdid); + void PlaceButtons(bool loadSavedLayout); bool mouseDownL, mouseDownR; int rightButtonIndex=-1; CMPCThemeToolTipCtrl themedToolTip; @@ -111,4 +112,5 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil afx_msg void OnTbnBeginAdjust(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnTbnEndAdjust(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); + afx_msg void OnTbnReset(NMHDR* pNMHDR, LRESULT* pResult); }; From 26601f1eab2428b6ea6eda7fe1793c79521f53f8 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Thu, 13 Feb 2025 14:20:42 -0800 Subject: [PATCH 07/20] . --- src/mpc-hc/PlayerToolBar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index 064f2044c78..d497beae788 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -832,7 +832,6 @@ void CPlayerToolBar::OnLButtonDblClk(UINT nFlags, CPoint point) { void CPlayerToolBar::OnTbnReset(NMHDR* pNMHDR, LRESULT* pResult) { - // TODO: Add your control notification handler code here CToolBarCtrl& tb = GetToolBarCtrl(); for (int i = tb.GetButtonCount()-1; i >= 0; i--) { From 180a25ac3e60d4b4489dda8bcf58c86e427499c9 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sat, 8 Mar 2025 22:27:58 -0800 Subject: [PATCH 08/20] options page for toolbar customization --- src/mpc-hc/CMPCThemePPageBase.cpp | 17 +++-- src/mpc-hc/CMPCThemePPageBase.h | 2 +- src/mpc-hc/CMPCThemePlayerListCtrl.cpp | 15 ++-- src/mpc-hc/CMPCThemePlayerListCtrl.h | 1 + src/mpc-hc/ImageGrayer.cpp | 4 +- src/mpc-hc/ImageGrayer.h | 2 +- src/mpc-hc/MainFrm.h | 1 + src/mpc-hc/PPageBase.cpp | 14 ++-- src/mpc-hc/PPageBase.h | 7 +- src/mpc-hc/PPageFormats.cpp | 8 +-- src/mpc-hc/PPageShaders.cpp | 12 ++-- src/mpc-hc/PPageSheet.cpp | 1 + src/mpc-hc/PPageSheet.h | 2 + src/mpc-hc/PlayerToolBar.cpp | 44 ++++++------ src/mpc-hc/PlayerToolBar.h | 22 +++++- src/mpc-hc/PnSPresetsDlg.cpp | 4 +- src/mpc-hc/PnSPresetsDlg.h | 2 +- src/mpc-hc/SVGImage.cpp | 41 +++++++++++ src/mpc-hc/SVGImage.h | 21 ++++++ src/mpc-hc/mpc-hc.rc | 95 +++++++++++++++++-------- src/mpc-hc/mpc-hc.vcxproj | 2 + src/mpc-hc/mpc-hc.vcxproj.filters | 6 ++ src/mpc-hc/res/arrow.svg | 8 +++ src/mpc-hc/res/mpc-hc.rc2 | Bin 19982 -> 20132 bytes src/mpc-hc/resource.h | 4 +- 25 files changed, 245 insertions(+), 90 deletions(-) create mode 100644 src/mpc-hc/res/arrow.svg diff --git a/src/mpc-hc/CMPCThemePPageBase.cpp b/src/mpc-hc/CMPCThemePPageBase.cpp index c46d97557ff..4f2f95430af 100755 --- a/src/mpc-hc/CMPCThemePPageBase.cpp +++ b/src/mpc-hc/CMPCThemePPageBase.cpp @@ -23,30 +23,33 @@ BOOL CMPCThemePPageBase::OnInitDialog() return 0; } -void CMPCThemePPageBase::SetMPCThemeButtonIcon(UINT nIDButton, UINT nIDIcon, ImageGrayer::mpcColorStyle colorStyle) +void CMPCThemePPageBase::SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle) { if (AppIsThemeLoaded()) { - if (!m_buttonIcons.count(nIDIcon)) { + if (!m_buttonIcons.count(iconDef)) { CImage img, imgEnabled, imgDisabled; - img.LoadFromResource(AfxGetInstanceHandle(), nIDIcon); + if (iconDef.svgTargetWidth) { + SVGImage::LoadIconDef(iconDef, img); + } else { + img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); + } ImageGrayer::UpdateColor(img, imgEnabled, false, colorStyle); ImageGrayer::UpdateColor(img, imgDisabled, true, colorStyle); - CImageList& imageList = m_buttonIcons[nIDIcon]; + CImageList& imageList = m_buttonIcons[iconDef]; imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 2, 0); imageList.Add(CBitmap::FromHandle(imgEnabled), nullptr); imageList.Add(CBitmap::FromHandle(imgDisabled), nullptr); } BUTTON_IMAGELIST buttonImageList; - buttonImageList.himl = m_buttonIcons[nIDIcon]; + buttonImageList.himl = m_buttonIcons[iconDef]; buttonImageList.margin = { 0, 0, 0, 0 }; buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); } else { - CPPageBase::SetButtonIcon(nIDButton, nIDIcon); - + CPPageBase::SetButtonIcon(nIDButton, iconDef); } } diff --git a/src/mpc-hc/CMPCThemePPageBase.h b/src/mpc-hc/CMPCThemePPageBase.h index 725729761ad..28d0cd2c917 100755 --- a/src/mpc-hc/CMPCThemePPageBase.h +++ b/src/mpc-hc/CMPCThemePPageBase.h @@ -17,7 +17,7 @@ class CMPCThemePPageBase : protected: virtual BOOL OnInitDialog(); virtual void AdjustDynamicWidgets() {}; - void SetMPCThemeButtonIcon(UINT nIDButton, UINT nIDIcon, ImageGrayer::mpcColorStyle colorStyle = ImageGrayer::mpcMono); + void SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle = ImageGrayer::mpcMono); BOOL PreTranslateMessage(MSG* pMsg); CPPageBase* FindSiblingPage(CRuntimeClass* pClass); }; diff --git a/src/mpc-hc/CMPCThemePlayerListCtrl.cpp b/src/mpc-hc/CMPCThemePlayerListCtrl.cpp index a8ee555953d..4d18569a186 100755 --- a/src/mpc-hc/CMPCThemePlayerListCtrl.cpp +++ b/src/mpc-hc/CMPCThemePlayerListCtrl.cpp @@ -406,6 +406,7 @@ void CMPCThemePlayerListCtrl::drawItem(CDC* pDC, int nItem, int nSubItem) } if (IsWindowEnabled()) { + bool selected = false; if (GetItemState(nItem, LVIS_SELECTED) == LVIS_SELECTED && (nSubItem == 0 || fullRowSelect) && (GetStyle() & LVS_SHOWSELALWAYS || GetFocus() == this)) { bgColor = selectedBGColor; if (LVS_REPORT != dwStyle) { //in list mode we don't fill the "whole" column @@ -413,6 +414,7 @@ void CMPCThemePlayerListCtrl::drawItem(CDC* pDC, int nItem, int nSubItem) dcMem.DrawTextW(text, tmp, textFormat | DT_CALCRECT); //end of string rTextBG.right = tmp.right + (rText.left - rTextBG.left); //end of string plus same indent from the left side } + selected = true; } else if (hasCheckedColors) { if (isChecked && checkedBGClr != -1) { bgColor = checkedBGClr; @@ -426,11 +428,11 @@ void CMPCThemePlayerListCtrl::drawItem(CDC* pDC, int nItem, int nSubItem) } dcMem.FillSolidRect(rTextBG, bgColor); - if (themeGridLines || nullptr != customThemeInterface) { + if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { CRect rGrid = rect; rGrid.bottom -= 1; CPen gridPenV, gridPenH, *oldPen; - if (nullptr != customThemeInterface) { + if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { COLORREF horzGridColor, vertGridColor; customThemeInterface->GetCustomGridColors(nItem, horzGridColor, vertGridColor); gridPenV.CreatePen(PS_SOLID, 1, vertGridColor); @@ -457,6 +459,11 @@ void CMPCThemePlayerListCtrl::drawItem(CDC* pDC, int nItem, int nSubItem) dcMem.SelectObject(oldPen); gridPenV.DeleteObject(); gridPenH.DeleteObject(); + } else if (selected) { + CBrush borderBG; + borderBG.CreateSolidBrush(CMPCTheme::ListCtrlDisabledBGColor); + dcMem.FrameRect(rTextBG, &borderBG); + borderBG.DeleteObject(); } } @@ -533,7 +540,7 @@ BOOL CMPCThemePlayerListCtrl::OnEraseBkgnd(CDC* pDC) } pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); - if (themeGridLines || nullptr != customThemeInterface) { + if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { CPen gridPen, *oldPen; gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); @@ -556,7 +563,7 @@ BOOL CMPCThemePlayerListCtrl::OnEraseBkgnd(CDC* pDC) { CPen horzPen; pDC->MoveTo(r.left, gr.bottom - 1); - if (nullptr != customThemeInterface) { + if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { COLORREF horzGridColor, tmp; customThemeInterface->GetCustomGridColors(y, horzGridColor, tmp); horzPen.CreatePen(PS_SOLID, 1, horzGridColor); diff --git a/src/mpc-hc/CMPCThemePlayerListCtrl.h b/src/mpc-hc/CMPCThemePlayerListCtrl.h index 9b4d478af93..0624e60a36d 100755 --- a/src/mpc-hc/CMPCThemePlayerListCtrl.h +++ b/src/mpc-hc/CMPCThemePlayerListCtrl.h @@ -14,6 +14,7 @@ class CMPCThemeListCtrlCustomInterface virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) = 0; virtual void DoCustomPrePaint() = 0; virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) = 0; + virtual bool UseCustomGrid() { return true; }; }; class CMPCThemePlayerListCtrl : public CListCtrl, CMPCThemeUtil, CMPCThemeScrollable diff --git a/src/mpc-hc/ImageGrayer.cpp b/src/mpc-hc/ImageGrayer.cpp index d1a12bbee1b..a858ac58448 100644 --- a/src/mpc-hc/ImageGrayer.cpp +++ b/src/mpc-hc/ImageGrayer.cpp @@ -194,7 +194,7 @@ bool ImageGrayer::UpdateColor(const CImage& imgSource, CImage& imgDest, bool dis if (disabled) { themeColor = CMPCTheme::ImageDisabledColor; } else { - themeColor = CMPCTheme::TextFGColor; + themeColor = CMPCTheme::TextFGColorFade; } newColor.rgbRed = GetRValue(themeColor); newColor.rgbGreen = GetGValue(themeColor); @@ -301,4 +301,4 @@ void ImageGrayer::PreMultiplyAlpha(CImage& imgSource) { p[x].rgbGreen = static_cast(round((float)p[x].rgbGreen * p[x].rgbReserved / 255.0f)); } } -} \ No newline at end of file +} diff --git a/src/mpc-hc/ImageGrayer.h b/src/mpc-hc/ImageGrayer.h index 1cfb310af6c..0ef54dbe4d3 100644 --- a/src/mpc-hc/ImageGrayer.h +++ b/src/mpc-hc/ImageGrayer.h @@ -25,7 +25,7 @@ namespace ImageGrayer enum mpcColorStyle { classicGrayscale, mpcMono, - mpcGrayDisabled + mpcGrayDisabled, }; bool Gray(const CImage& imgSource, CImage& imgDest, float brightness = 1.0f); diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 35e434dffa8..7cfa0d91ac6 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -817,6 +817,7 @@ class CMainFrame : public CFrameWnd, public CDropClient protected: // control bar embedded members friend class CMainFrameControls; + friend class CPPageToolBar; CMainFrameControls m_controls; friend class CPlayerBar; // it notifies m_controls of panel re-dock diff --git a/src/mpc-hc/PPageBase.cpp b/src/mpc-hc/PPageBase.cpp index a36703f5f2a..b7e316e15f0 100644 --- a/src/mpc-hc/PPageBase.cpp +++ b/src/mpc-hc/PPageBase.cpp @@ -94,18 +94,22 @@ void CPPageBase::CreateToolTip() } } -void CPPageBase::SetButtonIcon(UINT nIDButton, UINT nIDIcon) +void CPPageBase::SetButtonIcon(UINT nIDButton, IconDef iconDef) { - if (!m_buttonIcons.count(nIDIcon)) { + if (!m_buttonIcons.count(iconDef)) { CImage img; - img.LoadFromResource(AfxGetInstanceHandle(), nIDIcon); - CImageList& imageList = m_buttonIcons[nIDIcon]; + if (iconDef.svgTargetWidth) { + SVGImage::LoadIconDef(iconDef, img); + } else { + img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); + } + CImageList& imageList = m_buttonIcons[iconDef]; imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 1, 0); imageList.Add(CBitmap::FromHandle(img), nullptr); } BUTTON_IMAGELIST buttonImageList; - buttonImageList.himl = m_buttonIcons[nIDIcon]; + buttonImageList.himl = m_buttonIcons[iconDef]; buttonImageList.margin = { 0, 0, 0, 0 }; buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); diff --git a/src/mpc-hc/PPageBase.h b/src/mpc-hc/PPageBase.h index a9c0b383362..89f0450efa2 100644 --- a/src/mpc-hc/PPageBase.h +++ b/src/mpc-hc/PPageBase.h @@ -23,22 +23,23 @@ #include "ResizableLib/ResizableDialog.h" #include "CMPCThemeToolTipCtrl.h" +#include "SVGImage.h" // CPPageBase dialog - +using namespace SVGImage; class CPPageBase : public CCmdUIPropertyPage { DECLARE_DYNAMIC(CPPageBase) protected: CMPCThemeToolTipCtrl m_wndToolTip; - std::map m_buttonIcons; + std::map m_buttonIcons; static bool FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT); void CreateToolTip(); - void SetButtonIcon(UINT nIDButton, UINT nIDIcon); + void SetButtonIcon(UINT nIDButton, IconDef iconDef); public: CPPageBase(UINT nIDTemplate, UINT nIDCaption = 0); diff --git a/src/mpc-hc/PPageFormats.cpp b/src/mpc-hc/PPageFormats.cpp index 186147ca623..85a70b0a995 100644 --- a/src/mpc-hc/PPageFormats.cpp +++ b/src/mpc-hc/PPageFormats.cpp @@ -199,10 +199,10 @@ BOOL CPPageFormats::OnInitDialog() LoadSettings(); CreateToolTip(); - SetMPCThemeButtonIcon(IDC_ASSOCIATE_ALL_FORMATS, IDB_CHECK_ALL, ImageGrayer::mpcGrayDisabled); - SetMPCThemeButtonIcon(IDC_ASSOCIATE_AUDIO_FORMATS, IDB_CHECK_AUDIO, ImageGrayer::mpcGrayDisabled); - SetMPCThemeButtonIcon(IDC_ASSOCIATE_VIDEO_FORMATS, IDB_CHECK_VIDEO, ImageGrayer::mpcGrayDisabled); - SetMPCThemeButtonIcon(IDC_CLEAR_ALL_ASSOCIATIONS, IDB_UNCHECK_ALL, ImageGrayer::mpcGrayDisabled); + SetMPCThemeButtonIcon(IDC_ASSOCIATE_ALL_FORMATS, { IDB_CHECK_ALL }, ImageGrayer::mpcGrayDisabled); + SetMPCThemeButtonIcon(IDC_ASSOCIATE_AUDIO_FORMATS, { IDB_CHECK_AUDIO }, ImageGrayer::mpcGrayDisabled); + SetMPCThemeButtonIcon(IDC_ASSOCIATE_VIDEO_FORMATS, { IDB_CHECK_VIDEO }, ImageGrayer::mpcGrayDisabled); + SetMPCThemeButtonIcon(IDC_CLEAR_ALL_ASSOCIATIONS, { IDB_UNCHECK_ALL }, ImageGrayer::mpcGrayDisabled); if (!IsUserAnAdmin()) { GetDlgItem(IDC_EDIT1)->EnableWindow(FALSE); diff --git a/src/mpc-hc/PPageShaders.cpp b/src/mpc-hc/PPageShaders.cpp index 68aaba6175f..d652eae677a 100644 --- a/src/mpc-hc/PPageShaders.cpp +++ b/src/mpc-hc/PPageShaders.cpp @@ -278,12 +278,12 @@ BOOL CPPageShaders::OnInitDialog() VERIFY(m_PresetsBox.SelectString(-1, preset) != CB_ERR); } - SetMPCThemeButtonIcon(IDC_BUTTON6, IDB_SHADER_UP); - SetMPCThemeButtonIcon(IDC_BUTTON7, IDB_SHADER_DOWN); - SetMPCThemeButtonIcon(IDC_BUTTON8, IDB_SHADER_DEL); - SetMPCThemeButtonIcon(IDC_BUTTON9, IDB_SHADER_UP); - SetMPCThemeButtonIcon(IDC_BUTTON10, IDB_SHADER_DOWN); - SetMPCThemeButtonIcon(IDC_BUTTON11, IDB_SHADER_DEL); + SetMPCThemeButtonIcon(IDC_BUTTON6, { IDB_SHADER_UP }); + SetMPCThemeButtonIcon(IDC_BUTTON7, { IDB_SHADER_DOWN }); + SetMPCThemeButtonIcon(IDC_BUTTON8, { IDB_SHADER_DEL }); + SetMPCThemeButtonIcon(IDC_BUTTON9, { IDB_SHADER_UP }); + SetMPCThemeButtonIcon(IDC_BUTTON10, { IDB_SHADER_DOWN }); + SetMPCThemeButtonIcon(IDC_BUTTON11, { IDB_SHADER_DEL }); m_bCurrentPresetChanged = false; diff --git a/src/mpc-hc/PPageSheet.cpp b/src/mpc-hc/PPageSheet.cpp index b4e493616c6..93c898894a0 100644 --- a/src/mpc-hc/PPageSheet.cpp +++ b/src/mpc-hc/PPageSheet.cpp @@ -47,6 +47,7 @@ CPPageSheet::CPPageSheet(LPCTSTR pszCaption, IFilterGraph* pFG, CWnd* pParentWnd SetTreeWidth(216); AddPage(&m_player); + AddPage(&m_toolBar); AddPage(&m_theme); AddPage(&m_formats); AddPage(&m_acceltbl); diff --git a/src/mpc-hc/PPageSheet.h b/src/mpc-hc/PPageSheet.h index 50ecb510b07..70057f8ec4a 100644 --- a/src/mpc-hc/PPageSheet.h +++ b/src/mpc-hc/PPageSheet.h @@ -23,6 +23,7 @@ #include "mplayerc.h" #include "PPagePlayer.h" +#include "PPageToolBar.h" #include "PPageTheme.h" #include "PPageFormats.h" #include "PPageAccelTbl.h" @@ -92,6 +93,7 @@ class CPPageSheet : public TreePropSheet::CTreePropSheet, public CMPCThemeUtil CFont dpiButtonFont, dpiTabFont; CPPagePlayer m_player; + CPPageToolBar m_toolBar; CPPageTheme m_theme; CPPageFormats m_formats; CPPageAccelTbl m_acceltbl; diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index d497beae788..b2059d723a8 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -34,12 +34,6 @@ // CPlayerToolBar -struct svgButtonInfo { - UINT style; - int svgIndex; - CString text; -}; - //svg has 30 positions //0-7 are standard mpc buttons //8-24 reserved for additional toolbar buttons @@ -49,17 +43,17 @@ struct svgButtonInfo { #define VOLUMEBUTTON_SVG_INDEX 25 #define VOLUME_SVG_INDEX 28 -static std::map supportedSvgButtons = { - {ID_PLAY_PLAY, {TBBS_CHECKGROUP,0}}, - {ID_PLAY_PAUSE, {TBBS_CHECKGROUP,1}}, - {ID_PLAY_STOP, {TBBS_CHECKGROUP,2}}, +std::map CPlayerToolBar::supportedSvgButtons = { + {ID_PLAY_PLAY, {TBBS_CHECKGROUP,0,true}}, + {ID_PLAY_PAUSE, {TBBS_CHECKGROUP,1,true}}, + {ID_PLAY_STOP, {TBBS_CHECKGROUP,2,true}}, {ID_NAVIGATE_SKIPBACK, {TBBS_BUTTON,3}}, {ID_PLAY_DECRATE, {TBBS_BUTTON,4}}, {ID_PLAY_INCRATE, {TBBS_BUTTON,5}}, {ID_NAVIGATE_SKIPFORWARD, {TBBS_BUTTON,6}}, {ID_PLAY_FRAMESTEP, {TBBS_BUTTON,7}}, - {ID_DUMMYSEPARATOR, {TBBS_SEPARATOR,-1}}, - {ID_VOLUME_MUTE, {TBBS_CHECKBOX,VOLUMEBUTTON_SVG_INDEX}}, + {ID_DUMMYSEPARATOR, {TBBS_SEPARATOR,-1,true}}, + {ID_VOLUME_MUTE, {TBBS_CHECKBOX,VOLUMEBUTTON_SVG_INDEX,true}}, }; static std::vector supportedSvgButtonsSeq; @@ -765,7 +759,6 @@ void CPlayerToolBar::OnTbnQueryInsert(NMHDR* pNMHDR, LRESULT* pResult) { *pResult = TRUE; } - void CPlayerToolBar::SaveToolbarState() { if (!toolbarAdjustActive) { auto& ctrl = GetToolBarCtrl(); @@ -779,26 +772,32 @@ void CPlayerToolBar::SaveToolbarState() { } } -void CPlayerToolBar::OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult) { +void CPlayerToolBar::ToolbarChange() { SaveToolbarState(); ArrangeControls(); Invalidate(); - *pResult = 0; } +void CPlayerToolBar::OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult) { + ToolbarChange(); + *pResult = 0; +} void CPlayerToolBar::OnMouseMove(UINT nFlags, CPoint point) { mousePosition = point; CToolBar::OnMouseMove(nFlags, point); } +LPCWSTR CPlayerToolBar::GetStringFromID(int idCommand) { + return supportedSvgButtons[idCommand].text.GetString(); +} void CPlayerToolBar::OnTbnGetButtonInfo(NMHDR* pNMHDR, LRESULT* pResult) { LPNMTOOLBAR pNMTB = reinterpret_cast(pNMHDR); if (pNMTB->iItem < supportedSvgButtonsSeq.size()) { int cmdid = supportedSvgButtonsSeq[pNMTB->iItem]; TBBUTTON t = GetStandardButton(cmdid); - t.iString = (INT_PTR)supportedSvgButtons[t.idCommand].text.GetString(); + t.iString = (INT_PTR)GetStringFromID(t.idCommand); pNMTB->tbButton = t; *pResult = TRUE; return; @@ -817,29 +816,32 @@ void CPlayerToolBar::OnTbnBeginAdjust(NMHDR* pNMHDR, LRESULT* pResult) { *pResult = 0; } - void CPlayerToolBar::OnTbnEndAdjust(NMHDR* pNMHDR, LRESULT* pResult) { toolbarAdjustActive = false; SaveToolbarState(); *pResult = 0; } - void CPlayerToolBar::OnLButtonDblClk(UINT nFlags, CPoint point) { +//disabled to avoid the built-in customization dialog +#if 0 m_pMainFrame->enableDialogHook(this, CMainFrame::themableDialogTypes::toolbarCustomizeDialog); CToolBar::OnLButtonDblClk(nFlags, point); +#endif } - -void CPlayerToolBar::OnTbnReset(NMHDR* pNMHDR, LRESULT* pResult) { +void CPlayerToolBar::ToolBarReset() { CToolBarCtrl& tb = GetToolBarCtrl(); - for (int i = tb.GetButtonCount()-1; i >= 0; i--) { + for (int i = tb.GetButtonCount() - 1; i >= 0; i--) { tb.DeleteButton(i); } PlaceButtons(false); ArrangeControls(); Invalidate(); +} +void CPlayerToolBar::OnTbnReset(NMHDR* pNMHDR, LRESULT* pResult) { + ToolBarReset(); *pResult = 0; } diff --git a/src/mpc-hc/PlayerToolBar.h b/src/mpc-hc/PlayerToolBar.h index b63a4bb1bc0..ff179d59c20 100644 --- a/src/mpc-hc/PlayerToolBar.h +++ b/src/mpc-hc/PlayerToolBar.h @@ -41,7 +41,6 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil int getHitButtonIdx(CPoint point); bool LoadExternalToolBar(CImage& image); void LoadToolbarImage(); - TBBUTTON GetStandardButton(int cmdid); void PlaceButtons(bool loadSavedLayout); bool mouseDownL, mouseDownR; int rightButtonIndex=-1; @@ -59,18 +58,35 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil int currentlyDraggingButton; CPoint mousePosition; bool toolbarAdjustActive; + + struct svgButtonInfo { + UINT style; + int svgIndex; + bool positionLocked = false; + CString text; + }; + + static std::map supportedSvgButtons; public: CPlayerToolBar(CMainFrame* pMainFrame); virtual ~CPlayerToolBar(); bool LoadExternalToolBar(CImage& image, float svgscale); + LPCWSTR GetStringFromID(int idCommand); + const std::map GetSupportedSvgButtons() { + return supportedSvgButtons; + } int GetVolume() const; int GetMinWidth() const; void SetVolume(int volume); __declspec(property(get = GetVolume, put = SetVolume)) int Volume; + TBBUTTON GetStandardButton(int cmdid); void ArrangeControls(); + void ToolbarChange(); + void ToolBarReset(); + CImage& GetVolumeImageOn() { return volumeOn; }; CImage& GetVolumeImageOff() { return volumeOff; }; @@ -105,7 +121,7 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil afx_msg void OnTbnQueryDelete(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnTbnQueryInsert(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void SaveToolbarState(); - void OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnTbnToolbarChange(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnTbnGetButtonInfo(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnTbnInitCustomize(NMHDR* pNMHDR, LRESULT* pResult); @@ -114,3 +130,5 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); afx_msg void OnTbnReset(NMHDR* pNMHDR, LRESULT* pResult); }; + + diff --git a/src/mpc-hc/PnSPresetsDlg.cpp b/src/mpc-hc/PnSPresetsDlg.cpp index 1ee4c4bd5b5..6ef8e43db69 100644 --- a/src/mpc-hc/PnSPresetsDlg.cpp +++ b/src/mpc-hc/PnSPresetsDlg.cpp @@ -133,7 +133,7 @@ BEGIN_MESSAGE_MAP(CPnSPresetsDlg, CMPCThemeResizableDialog) ON_LBN_SELCHANGE(IDC_LIST1, OnLbnSelchangeList1) ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2) ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateButton2) - ON_BN_CLICKED(IDC_BUTTON3, OnBnClickedButton6) + ON_BN_CLICKED(IDC_BUTTON3, MoveDown) ON_UPDATE_COMMAND_UI(IDC_BUTTON3, OnUpdateButton6) ON_BN_CLICKED(IDC_BUTTON4, OnBnClickedButton9) ON_UPDATE_COMMAND_UI(IDC_BUTTON4, OnUpdateButton9) @@ -183,7 +183,7 @@ void CPnSPresetsDlg::OnUpdateButton2(CCmdUI* pCmdUI) pCmdUI->Enable(str != _T("New")); } -void CPnSPresetsDlg::OnBnClickedButton6() // del +void CPnSPresetsDlg::MoveDown() // del { int i = m_list.GetCurSel(); m_list.DeleteString(i); diff --git a/src/mpc-hc/PnSPresetsDlg.h b/src/mpc-hc/PnSPresetsDlg.h index fb571b0d8d5..2ad976575a2 100644 --- a/src/mpc-hc/PnSPresetsDlg.h +++ b/src/mpc-hc/PnSPresetsDlg.h @@ -62,7 +62,7 @@ class CPnSPresetsDlg : public CMPCThemeResizableDialog afx_msg void OnLbnSelchangeList1(); afx_msg void OnBnClickedButton2(); afx_msg void OnUpdateButton2(CCmdUI* pCmdUI); - afx_msg void OnBnClickedButton6(); + afx_msg void MoveDown(); afx_msg void OnUpdateButton6(CCmdUI* pCmdUI); afx_msg void OnBnClickedButton9(); afx_msg void OnUpdateButton9(CCmdUI* pCmdUI); diff --git a/src/mpc-hc/SVGImage.cpp b/src/mpc-hc/SVGImage.cpp index b54f0f522e5..6457c2c7ae3 100644 --- a/src/mpc-hc/SVGImage.cpp +++ b/src/mpc-hc/SVGImage.cpp @@ -83,3 +83,44 @@ HRESULT SVGImage::Load(UINT uResId, CImage& image, float scale /*= 1.0f*/) return NSVGimageToCImage(nsvgParse(svg.GetBuffer(), "px", 96.0f), image, scale); } + +void GdiTransform(CImage& image, Gdiplus::RotateFlipType transform) { + int bpp = image.GetBPP(); + + HBITMAP hbmp = image.Detach(); + Gdiplus::Bitmap* bmpTemp = Gdiplus::Bitmap::FromHBITMAP(hbmp, 0); + Gdiplus::PixelFormat pixel_format = bmpTemp->GetPixelFormat(); + if (bpp == 32) { + pixel_format = PixelFormat32bppARGB; + } + image.Attach(hbmp); + + Gdiplus::Bitmap bmp(image.GetWidth(), image.GetHeight(), image.GetPitch(), pixel_format, static_cast(image.GetBits())); + bmp.RotateFlip(transform); + + image.Destroy(); + if (image.Create(bmp.GetWidth(), bmp.GetHeight(), 32, CImage::createAlphaChannel)) { + Gdiplus::Bitmap dst(image.GetWidth(), image.GetHeight(), image.GetPitch(), PixelFormat32bppARGB, static_cast(image.GetBits())); + Gdiplus::Graphics graphics(&dst); + graphics.DrawImage(&bmp, 0, 0); + } +} + +HRESULT SVGImage::LoadIconDef(IconDef iconDef, CImage& image) { + CStringA svg; + if (!LoadResource(iconDef.nIDIcon, svg, _T("SVG"))) { + return E_FAIL; + } + + NSVGimage* svgImage = nsvgParse(svg.GetBuffer(), "px", 96.0f); + HRESULT ret = NSVGimageToCImage(svgImage, image, (float)iconDef.svgTargetWidth / svgImage->width); + if (iconDef.svgTransform == TRANSFORM_FLIP_HORZ) { + GdiTransform(image, Gdiplus::RotateNoneFlipX); + } else if (iconDef.svgTransform == TRANSFORM_ROT90CCW) { + GdiTransform(image, Gdiplus::Rotate270FlipNone); + } else if (iconDef.svgTransform == TRANSFORM_ROT90CW) { + GdiTransform(image, Gdiplus::Rotate90FlipNone); + } + + return ret; +} diff --git a/src/mpc-hc/SVGImage.h b/src/mpc-hc/SVGImage.h index 8582d21183f..90340b6039a 100644 --- a/src/mpc-hc/SVGImage.h +++ b/src/mpc-hc/SVGImage.h @@ -27,6 +27,27 @@ namespace ATL namespace SVGImage { + enum IconTransform { + TRANSFORM_NONE = 0, + TRANSFORM_ROT90CW, + TRANSFORM_ROT90CCW, + TRANSFORM_FLIP_HORZ + }; + struct IconDef { + UINT nIDIcon; + int svgTargetWidth = 0; + IconTransform svgTransform = TRANSFORM_NONE; + }; + + struct icomp { + bool operator() (const IconDef& c1, const IconDef& c2) const { + return c1.nIDIcon < c2.nIDIcon || + (c1.nIDIcon == c2.nIDIcon && c1.svgTargetWidth < c2.svgTargetWidth) || + (c1.nIDIcon == c2.nIDIcon && c1.svgTargetWidth == c2.svgTargetWidth && c1.svgTransform < c2.svgTransform); + } + }; + HRESULT Load(LPCTSTR filename, ATL::CImage& image, float scale = 1.0f); HRESULT Load(UINT uResId, ATL::CImage& image, float scale = 1.0f); + HRESULT LoadIconDef(IconDef iconDef, CImage& image); } diff --git a/src/mpc-hc/mpc-hc.rc b/src/mpc-hc/mpc-hc.rc index 86d45934933..880e98198a8 100644 --- a/src/mpc-hc/mpc-hc.rc +++ b/src/mpc-hc/mpc-hc.rc @@ -125,7 +125,7 @@ BEGIN LTEXT "%",IDC_STATIC5,194,37,14,8 CONTROL "Regain volume",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,212,37,130,8 LTEXT "Boost:",IDC_STATIC6,6,59,66,8 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | TBS_DOWNISLEFT,72,55,132,15 + CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,72,55,132,15 CONTROL "Down-sample to 44100 Hz",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,78,343,8 CONTROL "Audio time shift (ms):",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,95,138,8 EDITTEXT IDC_EDIT2,149,92,55,13,ES_AUTOHSCROLL,WS_EX_RIGHT @@ -233,7 +233,7 @@ BEGIN CONTROL "Display full path",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON | WS_GROUP,12,169,126,8 CONTROL "File name only",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,12,184,126,8 CONTROL "Don't prefix anything",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,12,198,126,8 - CONTROL "Replace file name with title",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP | WS_GROUP,12,212,126,18 + CONTROL "Replace file name with title",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_GROUP | WS_TABSTOP,12,212,126,18 GROUPBOX "Other",IDC_STATIC,149,6,200,90,WS_GROUP CONTROL "Tray icon",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,155,20,192,8 CONTROL "Store settings in .ini file",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,155,35,192,8 @@ -277,11 +277,11 @@ BEGIN GROUPBOX "Audio",IDC_STATIC,6,6,343,56 CTEXT "Volume",IDC_STATIC,54,18,66,8 RTEXT "Min",IDC_STATIC,12,37,24,8 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_TOOLTIPS | WS_TABSTOP | TBS_DOWNISLEFT,36,28,102,24 + CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_TOOLTIPS | WS_TABSTOP | 0x400,36,28,102,24 LTEXT "Max",IDC_STATIC,139,37,28,8 CTEXT "Balance",IDC_STATIC_BALANCE,228,18,66,8,SS_NOTIFY RTEXT "L",IDC_STATIC,174,37,36,8 - CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_TOOLTIPS | WS_TABSTOP | TBS_DOWNISLEFT,210,28,102,24 + CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_TOOLTIPS | WS_TABSTOP | 0x400,210,28,102,24 LTEXT "R",IDC_STATIC,313,37,32,8 GROUPBOX "Control",IDC_STATIC,6,66,151,55 LTEXT "Volume step:",IDC_STATIC5,13,80,82,8 @@ -579,8 +579,8 @@ CAPTION "Saving..." FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN CONTROL "",IDC_ANIMATE1,"SysAnimate32",ACS_CENTER | ACS_TRANSPARENT | WS_TABSTOP,5,5,187,30 - CONTROL "",IDC_STATIC1,"Static",SS_LEFTNOWORDWRAP | WS_GROUP | SS_PATHELLIPSIS,5,37,240,8 - CONTROL "",IDC_STATIC2,"Static",SS_LEFTNOWORDWRAP | WS_GROUP | SS_PATHELLIPSIS,5,45,240,8 + CONTROL "",IDC_STATIC1,"Static",SS_LEFTNOWORDWRAP | SS_PATHELLIPSIS | WS_GROUP,5,37,240,8 + CONTROL "",IDC_STATIC2,"Static",SS_LEFTNOWORDWRAP | SS_PATHELLIPSIS | WS_GROUP,5,45,240,8 CONTROL "",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,5,58,189,8 LTEXT "",IDC_REPORT,5,70,189,8 PUSHBUTTON "Cancel",IDCANCEL,198,65,47,14 @@ -658,16 +658,16 @@ BEGIN LTEXT "100%",IDC_STATIC,322,97,24,8 LTEXT "Primary",IDC_STATIC,143,114,56,8 CONTROL "",IDC_COLORPRI,"Button",BS_OWNERDRAW | WS_TABSTOP,204,110,24,14 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | TBS_DOWNISLEFT | TBS_TOOLTIPS,233,112,113,14 + CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,233,112,113,14 LTEXT "Secondary",IDC_STATIC,143,133,56,8 CONTROL "",IDC_COLORSEC,"Button",BS_OWNERDRAW | WS_TABSTOP,204,130,24,14 - CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | TBS_DOWNISLEFT | TBS_TOOLTIPS,233,131,113,14 + CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,233,131,113,14 LTEXT "Outline",IDC_STATIC,143,152,56,8 CONTROL "",IDC_COLOROUTL,"Button",BS_OWNERDRAW | WS_TABSTOP,204,149,24,14 - CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | TBS_DOWNISLEFT | TBS_TOOLTIPS,233,150,113,14 + CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,233,150,113,14 LTEXT "Shadow",IDC_STATIC,143,172,56,8 CONTROL "",IDC_COLORSHAD,"Button",BS_OWNERDRAW | WS_TABSTOP,204,168,24,14 - CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | TBS_DOWNISLEFT | TBS_TOOLTIPS,233,169,113,14 + CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,233,169,113,14 CONTROL "Link alpha channels",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,216,196,132,10 LTEXT "8-bit Character Set",IDC_STATIC21,12,46,112,8 LTEXT "OpenType Language",IDC_STATIC22,12,86,112,8 @@ -716,7 +716,7 @@ BEGIN CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS | UDS_HORZ,76,246,43,13 EDITTEXT IDC_AUTHOR,124,246,224,13,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY EDITTEXT IDC_LOGOFILENAME,77,266,208,13,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Browse...",IDC_BUTTON2,289,266,60,14,WS_TABSTOP + PUSHBUTTON "Browse...",IDC_BUTTON2,289,266,60,14 END IDD_PPAGEOUTPUT DIALOGEX 0, 0, 355, 289 @@ -822,10 +822,10 @@ BEGIN RTEXT "",IDC_STATIC2,84,42,24,10,SS_SUNKEN RTEXT "",IDC_STATIC3,84,61,24,10,SS_SUNKEN RTEXT "",IDC_STATIC4,84,80,24,10,SS_SUNKEN - CONTROL "",IDC_SLI_BRIGHTNESS,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | TBS_DOWNISLEFT,119,20,224,14 - CONTROL "",IDC_SLI_CONTRAST,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | TBS_DOWNISLEFT,119,40,224,14 - CONTROL "",IDC_SLI_HUE,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | TBS_DOWNISLEFT,119,59,224,14 - CONTROL "",IDC_SLI_SATURATION,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | TBS_DOWNISLEFT,119,78,224,14 + CONTROL "",IDC_SLI_BRIGHTNESS,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | 0x400,119,20,224,14 + CONTROL "",IDC_SLI_CONTRAST,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | 0x400,119,40,224,14 + CONTROL "",IDC_SLI_HUE,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | 0x400,119,59,224,14 + CONTROL "",IDC_SLI_SATURATION,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | 0x400,119,78,224,14 PUSHBUTTON "Reset",IDC_RESET,277,96,60,14 GROUPBOX "Update check",IDC_STATIC,6,127,343,48 CONTROL "Enable automatic update check",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,142,300,8 @@ -1197,6 +1197,19 @@ BEGIN LISTBOX IDC_LIST1,7,7,302,84,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END +IDD_PPAGETOOLBAR DIALOGEX 0, 0, 355, 289 +STYLE DS_SETFONT | WS_CHILD +FONT 9, "Segoe UI", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_LIST2,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,190,22,153,230 + PUSHBUTTON "Default",IDC_BUTTON1,278,262,65,14 + CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,24,22,138,230 + PUSHBUTTON "<<",IDC_BUTTON3,168,94,16,16 + PUSHBUTTON ">>",IDC_BUTTON4,168,113,16,16 + PUSHBUTTON "^",IDC_BUTTON5,71,254,16,16 + PUSHBUTTON "v",IDC_BUTTON6,91,254,16,16 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -1466,6 +1479,14 @@ BEGIN VERTGUIDE, 8 VERTGUIDE, 78 END + + IDD_PPAGETOOLBAR, DIALOG + BEGIN + VERTGUIDE, 10 + HORZGUIDE, 4 + HORZGUIDE, 20 + HORZGUIDE, 22 + END END #endif // APSTUDIO_INVOKED @@ -2502,6 +2523,11 @@ BEGIN 0 END +IDD_PPAGETOOLBAR AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -2523,7 +2549,6 @@ BEGIN IDS_PROPSHEET_PROPERTIES "Properties" IDS_PLAY_LOOPMODE_FILE "File" IDS_SUB_OVERRIDE_DEFAULT_STYLE "Override Default Style" - IDS_SUB_OVERRIDE_ALL_STYLES "Override All Styles" IDS_PLAY_LOOPMODE_PLAYLIST "Playlist" IDS_FAVFILES "Files" IDS_FAVDVDS "DVDs" @@ -2539,6 +2564,7 @@ BEGIN IDS_THEMEMODE_DARK "Dark" IDS_THEMEMODE_LIGHT "Light" IDS_THEMEMODE_WINDOWS "Windows Default" + IDS_SUB_OVERRIDE_ALL_STYLES "Override All Styles" END STRINGTABLE @@ -2707,6 +2733,11 @@ BEGIN IDD_PPAGESHADERS "Playback::Shaders" END +STRINGTABLE +BEGIN + IDD_PPAGETOOLBAR "Player::ToolBar" +END + STRINGTABLE BEGIN IDD_FILEPROPRES "Resources" @@ -2716,6 +2747,7 @@ BEGIN IDD_PPAGESYNC "Playback::Sync Renderer Settings" IDD_PPAGEFULLSCREEN "Playback::Fullscreen" IDD_PPAGEAUDIORENDERER "Internal Filters::Audio Renderer" + IDD_PPAGEMOUSE "Player::Mouse" END STRINGTABLE @@ -2754,7 +2786,6 @@ END STRINGTABLE BEGIN IDD_PPAGEACCELTBL "Player::Keys" - IDD_PPAGEMOUSE "Player::Mouse" IDD_PPAGESUBSTYLE "Subtitles::Default Style" IDD_PPAGEINTERNALFILTERS "Internal Filters" IDD_PPAGELOGO "Player::Logo" @@ -2937,6 +2968,8 @@ BEGIN "Insert deinterlace filter (blend) in capture mode" IDS_PLAYLIST_TOGGLE_SHUFFLE "Toggle Playlist Shuffle" IDS_AUDIOSHIFT_ONOFF "Toggle Audio Delay" + IDS_PPAGEADVANCED_PAUSE_WHILE_DRAGGING_SEEKBAR + "Pause playback while dragging the seekbar." END STRINGTABLE @@ -4011,14 +4044,23 @@ BEGIN IDS_CMD_UNREGALL "/unregall\t\tRemove all file associations" IDS_CMD_START "/start ms\t\tStart playing at ""ms"" (= milliseconds)" IDS_CMD_STARTPOS "/startpos hh:mm:ss\tStart playing at position hh:mm:ss" - IDS_CMD_AB_START "/ab_start hh:mm:ss\tA-B repeat start position" - IDS_CMD_AB_END "/ab_end hh:mm:ss\tA-B repeat end position" IDS_CMD_FIXEDSIZE "/fixedsize w,h[,x,y]\tSet a fixed window size; optionally specificy upper-left window position" IDS_CMD_MONITOR "/monitor N\tStart player on monitor N, where N starts from 1" IDS_CMD_AUDIORENDERER "/audiorenderer N\tStart using audiorenderer N, where N starts from 1 (see ""Output"" settings)" IDS_CMD_SHADERPRESET "/shaderpreset ""Pr""\tStart using ""Pr"" shader preset" END +STRINGTABLE +BEGIN + IDS_CMD_THUMBNAILS "/thumbnails\tCreate thumbnails" + IDS_PPAGEADVANCED_CONFIRM_FILE_DELETE + "Show confirmation prompt before deleting file" + IDS_PPAGEADVANCED_LIBASS_FOR_SRT + "Use libass (instead of standard renderer) for SRT subtitles. NOT recommended." + IDS_CMD_AB_START "/ab_start hh:mm:ss\tA-B repeat start position" + IDS_CMD_AB_END "/ab_end hh:mm:ss\tA-B repeat end position" +END + STRINGTABLE BEGIN IDS_MESSAGEBOX_CANCEL "Cancel" @@ -4039,6 +4081,10 @@ BEGIN IDS_MOUSE_WHEEL_RIGHT "Wheel Right" IDS_MOUSE_ACTION "Action" IDS_MOUSE_COMMAND "Command" +END + +STRINGTABLE +BEGIN IDS_MOUSE_RIGHT_BUTTON "Right button" END @@ -4085,12 +4131,6 @@ BEGIN "Display current A-B repeat marks in status bar." IDS_PPAGEADVANCED_SHOW_VIDEOINFO_STATUSBAR "Display video info (codec name, resolution) in status bar." - IDS_PPAGEADVANCED_PAUSE_WHILE_DRAGGING_SEEKBAR - "Pause playback while dragging the seekbar." - IDS_PPAGEADVANCED_CONFIRM_FILE_DELETE - "Show confirmation prompt before deleting file" - IDS_PPAGEADVANCED_LIBASS_FOR_SRT - "Use libass (instead of standard renderer) for SRT subtitles. NOT recommended." END STRINGTABLE @@ -4152,11 +4192,6 @@ BEGIN IDS_AG_DEFAULT "Default" END -STRINGTABLE -BEGIN - IDS_CMD_THUMBNAILS "/thumbnails\tCreate thumbnails" -END - #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/src/mpc-hc/mpc-hc.vcxproj b/src/mpc-hc/mpc-hc.vcxproj index 0d332487d10..b1b0de618f7 100644 --- a/src/mpc-hc/mpc-hc.vcxproj +++ b/src/mpc-hc/mpc-hc.vcxproj @@ -275,6 +275,7 @@ + @@ -473,6 +474,7 @@ + diff --git a/src/mpc-hc/mpc-hc.vcxproj.filters b/src/mpc-hc/mpc-hc.vcxproj.filters index 56654761ee1..0eed9ce49c5 100644 --- a/src/mpc-hc/mpc-hc.vcxproj.filters +++ b/src/mpc-hc/mpc-hc.vcxproj.filters @@ -624,6 +624,9 @@ Modal Dialogs + + Property Dialogs\Player Options\Pages + @@ -1185,6 +1188,9 @@ Modal Dialogs + + Property Dialogs\Player Options\Pages + diff --git a/src/mpc-hc/res/arrow.svg b/src/mpc-hc/res/arrow.svg new file mode 100644 index 00000000000..38bf5886646 --- /dev/null +++ b/src/mpc-hc/res/arrow.svg @@ -0,0 +1,8 @@ + + + + + + + diff --git a/src/mpc-hc/res/mpc-hc.rc2 b/src/mpc-hc/res/mpc-hc.rc2 index 0f211a1f0e6bcd8d7851a7ab7e47841a62b4cdb8..27600f5444141cf7c98396862386acba69840f31 100644 GIT binary patch delta 52 zcmeC1!?Ea{9z344Dk$(3_(EX&k#QOA&=%{FJ~LhM1~?D%x5Uytn2cS F699ow4r~Ab delta 18 acmZ27m$7dS;|3d-$z}FiHn+LTaRLBI@drNu diff --git a/src/mpc-hc/resource.h b/src/mpc-hc/resource.h index f1c00209e85..0cd406fd264 100644 --- a/src/mpc-hc/resource.h +++ b/src/mpc-hc/resource.h @@ -74,6 +74,7 @@ #define IDF_SHADER_FINAL 702 #define IDF_SVG_TOOLBAR 703 #define IDF_SVG_BUTTONS 704 +#define IDF_SVG_ARROW 705 #define ID_FILE_OPENMEDIA 800 #define ID_FILE_OPENDVDBD 801 #define ID_FILE_OPENDEVICE 802 @@ -621,6 +622,7 @@ #define IDD_PPAGEDPICALC 20018 #define IDD_RAR_ENTRY_SELECTOR 20019 #define IDD_ADDCOMMAND_DLG 20020 +#define IDD_PPAGETOOLBAR 20021 #define IDB_DT_CB_96 20050 #define IDB_DT_CB_120 20051 #define IDB_DT_CB_144 20052 @@ -1760,7 +1762,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 20076 +#define _APS_NEXT_RESOURCE_VALUE 20077 #define _APS_NEXT_COMMAND_VALUE 33462 #define _APS_NEXT_CONTROL_VALUE 22094 #define _APS_NEXT_SYMED_VALUE 24052 From 8e5681a6742a262d34467afd18bc92d1fa49e80e Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sat, 8 Mar 2025 22:43:55 -0800 Subject: [PATCH 09/20] fix bug when no insert position found --- build.bat | 1044 +- contrib/sign.bat | 160 +- distrib/Languages/Basque.isl | 678 +- distrib/Languages/Belarusian.isl | 638 +- distrib/Languages/ChineseSimplified.isl | 674 +- distrib/Languages/ChineseTraditional.isl | 662 +- distrib/Languages/Korean.isl | 644 +- distrib/Languages/Slovak.isl | 526 +- distrib/custom_messages.iss | 110 +- distrib/mpc-hc_setup.iss | 1134 +- docs/Compilation.md | 324 +- include/IBitRateInfo.h | 60 +- include/IBufferInfo.h | 62 +- include/IChapterInfo.h | 132 +- include/IFilterVersion.h | 58 +- include/IKeyFrameInfo.h | 60 +- include/ITrackInfo.h | 168 +- include/avisynth/avisynth1.h | 828 +- include/avisynth/avisynth25.h | 1590 +- include/dsm/dsm.h | 74 +- include/lglcd/lglcd.h | 912 +- include/moreuuids.h | 3350 +- include/unrar.h | 370 +- include/vd2/Copying | 678 +- include/vd2/OldFilterSDK/Filter.h | 114 +- include/vd2/OldFilterSDK/ScriptError.h | 16 +- include/vd2/OldFilterSDK/ScriptInterpreter.h | 22 +- include/vd2/OldFilterSDK/ScriptValue.h | 34 +- include/vd2/OldFilterSDK/VBitmap.h | 32 +- include/vd2/OldFilterSDK/VirtualDub.h | 14 +- include/vd2/VDXFrame/Unknown.h | 220 +- include/vd2/VDXFrame/VideoFilter.h | 442 +- include/vd2/VDXFrame/VideoFilterDialog.h | 92 +- include/vd2/VDXFrame/VideoFilterEntry.h | 168 +- include/vd2/extras/FilterSDK/Filter.h | 488 +- include/vd2/extras/FilterSDK/ScriptError.h | 186 +- .../vd2/extras/FilterSDK/ScriptInterpreter.h | 140 +- include/vd2/extras/FilterSDK/ScriptValue.h | 252 +- include/vd2/extras/FilterSDK/VBitmap.h | 344 +- include/vd2/extras/FilterSDK/VirtualDub.h | 14 +- include/vd2/plugin/vdaudiofilt.h | 296 +- include/vd2/plugin/vdinputdriver.h | 568 +- include/vd2/plugin/vdplugin.h | 412 +- include/vd2/plugin/vdvideofilt.h | 1034 +- include/vd2/plugin/vdvideoutil.h | 242 +- include/version.h | 234 +- include/winddk/devioctl.h | 328 +- include/winddk/ntddcdrm.h | 1884 +- include/winddk/ntddcdvd.h | 1592 +- include/winddk/ntdddisk.h | 3518 +- include/winddk/ntddstor.h | 2776 +- src/CmdUI/CmdUI.cpp | 392 +- src/CmdUI/CmdUI.h | 130 +- src/CmdUI/CmdUI.vcxproj | 118 +- src/CmdUI/CmdUI.vcxproj.filters | 58 +- src/CmdUI/stdafx.cpp | 44 +- src/CmdUI/stdafx.h | 56 +- src/DSUtil/DSMPropertyBag.cpp | 1084 +- src/DSUtil/DSMPropertyBag.h | 468 +- src/DSUtil/DSUtil.cpp | 4496 +- src/DSUtil/DSUtil.h | 712 +- src/DSUtil/DSUtil.vcxproj | 240 +- src/DSUtil/DSUtil.vcxproj.filters | 374 +- src/DSUtil/FileVersionInfo.cpp | 182 +- src/DSUtil/FileVersionInfo.h | 64 +- src/DSUtil/FontInstaller.cpp | 278 +- src/DSUtil/FontInstaller.h | 96 +- src/DSUtil/GolombBuffer.cpp | 410 +- src/DSUtil/GolombBuffer.h | 136 +- src/DSUtil/H264Nalu.cpp | 220 +- src/DSUtil/H264Nalu.h | 164 +- src/DSUtil/HdmvClipInfo.cpp | 1642 +- src/DSUtil/HdmvClipInfo.h | 378 +- src/DSUtil/MediaTypeEx.cpp | 1502 +- src/DSUtil/MediaTypeEx.h | 84 +- src/DSUtil/MediaTypes.cpp | 926 +- src/DSUtil/MediaTypes.h | 96 +- src/DSUtil/Mpeg2Def.h | 400 +- src/DSUtil/NullRenderers.cpp | 906 +- src/DSUtil/NullRenderers.h | 190 +- src/DSUtil/SharedInclude.h | 82 +- src/DSUtil/VersionHelpersInternal.h | 166 +- src/DSUtil/WinAPIUtils.cpp | 696 +- src/DSUtil/WinAPIUtils.h | 128 +- src/DSUtil/deinterlace.cpp | 3936 +- src/DSUtil/stdafx.cpp | 44 +- src/DSUtil/stdafx.h | 86 +- src/DSUtil/text.cpp | 838 +- src/DSUtil/text.h | 510 +- src/DSUtil/vd.cpp | 784 +- src/DSUtil/vd.h | 94 +- src/DSUtil/vd_asm.cpp | 864 +- src/DSUtil/vd_asm.h | 68 +- src/DeCSS/CSSauth.cpp | 678 +- src/DeCSS/CSSauth.h | 10 +- src/DeCSS/CSSscramble.cpp | 472 +- src/DeCSS/CSSscramble.h | 16 +- src/DeCSS/DeCSS.vcxproj | 140 +- src/DeCSS/DeCSS.vcxproj.filters | 122 +- src/DeCSS/DeCSSInputPin.cpp | 722 +- src/DeCSS/DeCSSInputPin.h | 100 +- src/DeCSS/VobDec.cpp | 324 +- src/DeCSS/VobDec.h | 42 +- src/DeCSS/VobFile.cpp | 1756 +- src/DeCSS/VobFile.h | 214 +- src/DeCSS/stdafx.cpp | 44 +- src/DeCSS/stdafx.h | 64 +- src/DeCSS/udf.cpp | 704 +- src/DeCSS/udf.h | 512 +- src/MPCTestAPI/HScrollListBox.cpp | 338 +- src/MPCTestAPI/HScrollListBox.h | 124 +- src/MPCTestAPI/MPCTestAPI.cpp | 162 +- src/MPCTestAPI/MPCTestAPI.h | 104 +- src/MPCTestAPI/MPCTestAPI.rc | 520 +- src/MPCTestAPI/MPCTestAPI.vcxproj | 162 +- src/MPCTestAPI/MPCTestAPI.vcxproj.filters | 120 +- src/MPCTestAPI/MPCTestAPIDlg.cpp | 718 +- src/MPCTestAPI/MPCTestAPIDlg.h | 148 +- src/MPCTestAPI/res/MPCTestAPI.exe.manifest | 84 +- src/MPCTestAPI/resource.h | 60 +- src/MPCTestAPI/stdafx.cpp | 42 +- src/MPCTestAPI/stdafx.h | 62 +- src/SubPic/CoordGeom.cpp | 1136 +- src/SubPic/CoordGeom.h | 274 +- src/SubPic/DX9SubPic.cpp | 964 +- src/SubPic/DX9SubPic.h | 156 +- src/SubPic/ISubPic.h | 524 +- src/SubPic/ISubRender.h | 146 +- src/SubPic/MemSubPic.cpp | 1562 +- src/SubPic/MemSubPic.h | 172 +- src/SubPic/SubPic.vcxproj | 168 +- src/SubPic/SubPic.vcxproj.filters | 200 +- src/SubPic/SubPicAllocatorPresenterImpl.cpp | 1292 +- src/SubPic/SubPicAllocatorPresenterImpl.h | 350 +- src/SubPic/SubPicImpl.cpp | 868 +- src/SubPic/SubPicImpl.h | 290 +- src/SubPic/SubPicProviderImpl.cpp | 130 +- src/SubPic/SubPicProviderImpl.h | 104 +- src/SubPic/SubPicQueueImpl.cpp | 1788 +- src/SubPic/SubPicQueueImpl.h | 386 +- src/SubPic/stdafx.cpp | 44 +- src/SubPic/stdafx.h | 78 +- src/Subtitles/CCDecoder.cpp | 780 +- src/Subtitles/CCDecoder.h | 92 +- src/Subtitles/CompositionObject.cpp | 740 +- src/Subtitles/CompositionObject.h | 184 +- src/Subtitles/DVBSub.cpp | 1416 +- src/Subtitles/DVBSub.h | 350 +- src/Subtitles/PGSSub.cpp | 1234 +- src/Subtitles/PGSSub.h | 322 +- src/Subtitles/RTS.cpp | 7450 +-- src/Subtitles/RTS.h | 1092 +- src/Subtitles/Rasterizer.cpp | 4000 +- src/Subtitles/Rasterizer.h | 412 +- src/Subtitles/RealTextParser.cpp | 1198 +- src/Subtitles/RealTextParser.h | 212 +- src/Subtitles/STS.cpp | 7804 +-- src/Subtitles/STS.h | 394 +- src/Subtitles/SeparableFilter.h | 748 +- src/Subtitles/SubtitleInputPin.cpp | 1038 +- src/Subtitles/SubtitleInputPin.h | 172 +- src/Subtitles/Subtitles.vcxproj | 234 +- src/Subtitles/Subtitles.vcxproj.filters | 352 +- src/Subtitles/TextFile.cpp | 1774 +- src/Subtitles/TextFile.h | 194 +- src/Subtitles/USFSubtitles.cpp | 1566 +- src/Subtitles/USFSubtitles.h | 206 +- src/Subtitles/VobSubFile.cpp | 5300 +- src/Subtitles/VobSubFile.h | 438 +- src/Subtitles/VobSubFileRipper.cpp | 2368 +- src/Subtitles/VobSubFileRipper.h | 382 +- src/Subtitles/VobSubImage.cpp | 2722 +- src/Subtitles/VobSubImage.h | 192 +- src/Subtitles/stdafx.cpp | 44 +- src/Subtitles/stdafx.h | 86 +- src/YASM.props | 68 +- src/YASM.targets | 168 +- src/YASM.xml | 292 +- src/common.props | 192 +- src/filters/FilterApp.cpp | 104 +- src/filters/FilterApp.h | 66 +- src/filters/Filters.h | 76 +- src/filters/Filters.vcxproj | 148 +- src/filters/Filters.vcxproj.filters | 86 +- src/filters/InternalPropertyPage.cpp | 714 +- src/filters/InternalPropertyPage.h | 248 +- src/filters/PinInfoWnd.cpp | 572 +- src/filters/PinInfoWnd.h | 140 +- src/filters/muxer/BaseMuxer/BaseMuxer.cpp | 1042 +- src/filters/muxer/BaseMuxer/BaseMuxer.h | 220 +- src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj | 146 +- .../muxer/BaseMuxer/BaseMuxer.vcxproj.filters | 104 +- .../muxer/BaseMuxer/BaseMuxerInputPin.cpp | 572 +- .../muxer/BaseMuxer/BaseMuxerInputPin.h | 194 +- .../muxer/BaseMuxer/BaseMuxerOutputPin.cpp | 974 +- .../muxer/BaseMuxer/BaseMuxerOutputPin.h | 136 +- .../muxer/BaseMuxer/BaseMuxerRelatedPin.cpp | 98 +- .../muxer/BaseMuxer/BaseMuxerRelatedPin.h | 88 +- src/filters/muxer/BaseMuxer/BitStream.cpp | 324 +- src/filters/muxer/BaseMuxer/BitStream.h | 116 +- src/filters/muxer/BaseMuxer/stdafx.cpp | 44 +- src/filters/muxer/BaseMuxer/stdafx.h | 74 +- src/filters/muxer/DSMMuxer/DSMMuxer.cpp | 900 +- src/filters/muxer/DSMMuxer/DSMMuxer.def | 10 +- src/filters/muxer/DSMMuxer/DSMMuxer.h | 132 +- src/filters/muxer/DSMMuxer/DSMMuxer.rc | 204 +- src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj | 252 +- .../muxer/DSMMuxer/DSMMuxer.vcxproj.filters | 90 +- src/filters/muxer/DSMMuxer/resource.h | 30 +- src/filters/muxer/DSMMuxer/stdafx.cpp | 44 +- src/filters/muxer/DSMMuxer/stdafx.h | 78 +- .../muxer/MatroskaMuxer/MatroskaFile.cpp | 1874 +- .../muxer/MatroskaMuxer/MatroskaFile.h | 854 +- .../muxer/MatroskaMuxer/MatroskaMuxer.cpp | 2838 +- .../muxer/MatroskaMuxer/MatroskaMuxer.def | 10 +- .../muxer/MatroskaMuxer/MatroskaMuxer.h | 324 +- .../muxer/MatroskaMuxer/MatroskaMuxer.rc | 204 +- .../muxer/MatroskaMuxer/MatroskaMuxer.vcxproj | 250 +- .../MatroskaMuxer.vcxproj.filters | 102 +- src/filters/muxer/MatroskaMuxer/resource.h | 28 +- src/filters/muxer/MatroskaMuxer/stdafx.cpp | 44 +- src/filters/muxer/MatroskaMuxer/stdafx.h | 70 +- src/filters/muxer/WavDest/WavDest.cpp | 668 +- src/filters/muxer/WavDest/WavDest.def | 10 +- src/filters/muxer/WavDest/WavDest.h | 132 +- src/filters/muxer/WavDest/WavDest.rc | 204 +- src/filters/muxer/WavDest/WavDest.vcxproj | 226 +- .../muxer/WavDest/WavDest.vcxproj.filters | 88 +- src/filters/muxer/WavDest/resource.h | 28 +- src/filters/muxer/WavDest/stdafx.cpp | 44 +- src/filters/muxer/WavDest/stdafx.h | 62 +- .../parser/BaseSplitter/AsyncReader.cpp | 480 +- src/filters/parser/BaseSplitter/AsyncReader.h | 208 +- .../parser/BaseSplitter/BaseSplitter.cpp | 3272 +- .../parser/BaseSplitter/BaseSplitter.h | 832 +- .../parser/BaseSplitter/BaseSplitter.vcxproj | 142 +- .../BaseSplitter/BaseSplitter.vcxproj.filters | 92 +- .../parser/BaseSplitter/BaseSplitterFile.cpp | 518 +- .../parser/BaseSplitter/BaseSplitterFile.h | 142 +- .../parser/BaseSplitter/MultiFiles.cpp | 396 +- src/filters/parser/BaseSplitter/MultiFiles.h | 202 +- src/filters/parser/BaseSplitter/stdafx.cpp | 44 +- src/filters/parser/BaseSplitter/stdafx.h | 70 +- .../parser/DSMSplitter/DSMSplitter.cpp | 582 +- .../parser/DSMSplitter/DSMSplitter.def | 10 +- src/filters/parser/DSMSplitter/DSMSplitter.h | 122 +- src/filters/parser/DSMSplitter/DSMSplitter.rc | 204 +- .../parser/DSMSplitter/DSMSplitter.vcxproj | 256 +- .../DSMSplitter/DSMSplitter.vcxproj.filters | 102 +- .../parser/DSMSplitter/DSMSplitterFile.cpp | 850 +- .../parser/DSMSplitter/DSMSplitterFile.h | 124 +- src/filters/parser/DSMSplitter/resource.h | 28 +- src/filters/parser/DSMSplitter/stdafx.cpp | 44 +- src/filters/parser/DSMSplitter/stdafx.h | 72 +- .../StreamDriveThru/StreamDriveThru.cpp | 1248 +- .../StreamDriveThru/StreamDriveThru.def | 10 +- .../parser/StreamDriveThru/StreamDriveThru.h | 258 +- .../parser/StreamDriveThru/StreamDriveThru.rc | 204 +- .../StreamDriveThru/StreamDriveThru.vcxproj | 246 +- .../StreamDriveThru.vcxproj.filters | 90 +- src/filters/parser/StreamDriveThru/resource.h | 28 +- src/filters/parser/StreamDriveThru/stdafx.cpp | 44 +- src/filters/parser/StreamDriveThru/stdafx.h | 68 +- src/filters/reader/CDDAReader/CDDAReader.cpp | 1120 +- src/filters/reader/CDDAReader/CDDAReader.def | 10 +- src/filters/reader/CDDAReader/CDDAReader.h | 286 +- src/filters/reader/CDDAReader/CDDAReader.rc | 204 +- .../reader/CDDAReader/CDDAReader.vcxproj | 252 +- .../CDDAReader/CDDAReader.vcxproj.filters | 90 +- src/filters/reader/CDDAReader/resource.h | 28 +- src/filters/reader/CDDAReader/stdafx.cpp | 44 +- src/filters/reader/CDDAReader/stdafx.h | 68 +- src/filters/reader/CDXAReader/CDXAReader.cpp | 1122 +- src/filters/reader/CDXAReader/CDXAReader.def | 10 +- src/filters/reader/CDXAReader/CDXAReader.h | 186 +- src/filters/reader/CDXAReader/CDXAReader.rc | 204 +- .../reader/CDXAReader/CDXAReader.vcxproj | 252 +- .../CDXAReader/CDXAReader.vcxproj.filters | 90 +- src/filters/reader/CDXAReader/resource.h | 28 +- src/filters/reader/CDXAReader/stdafx.cpp | 44 +- src/filters/reader/CDXAReader/stdafx.h | 68 +- src/filters/reader/VTSReader/VTSReader.cpp | 594 +- src/filters/reader/VTSReader/VTSReader.def | 10 +- src/filters/reader/VTSReader/VTSReader.h | 192 +- src/filters/reader/VTSReader/VTSReader.rc | 204 +- .../reader/VTSReader/VTSReader.vcxproj | 258 +- .../VTSReader/VTSReader.vcxproj.filters | 90 +- src/filters/reader/VTSReader/resource.h | 28 +- src/filters/reader/VTSReader/stdafx.cpp | 44 +- src/filters/reader/VTSReader/stdafx.h | 66 +- src/filters/renderer/SyncClock/Interfaces.h | 66 +- src/filters/renderer/SyncClock/SyncClock.cpp | 240 +- src/filters/renderer/SyncClock/SyncClock.h | 142 +- .../renderer/SyncClock/SyncClock.vcxproj | 122 +- .../SyncClock/SyncClock.vcxproj.filters | 62 +- src/filters/renderer/SyncClock/stdafx.cpp | 42 +- src/filters/renderer/SyncClock/stdafx.h | 64 +- .../VideoRenderers/AllocatorCommon.cpp | 642 +- .../renderer/VideoRenderers/AllocatorCommon.h | 122 +- .../renderer/VideoRenderers/D3DFont.cpp | 1754 +- src/filters/renderer/VideoRenderers/D3DFont.h | 156 +- .../VideoRenderers/DX9AllocatorPresenter.cpp | 4618 +- .../VideoRenderers/DX9AllocatorPresenter.h | 626 +- .../VideoRenderers/DX9RenderingEngine.cpp | 3510 +- .../VideoRenderers/DX9RenderingEngine.h | 370 +- .../VideoRenderers/DXRAllocatorPresenter.cpp | 456 +- .../VideoRenderers/DXRAllocatorPresenter.h | 206 +- .../renderer/VideoRenderers/Dither.cpp | 180 +- src/filters/renderer/VideoRenderers/Dither.h | 48 +- .../VideoRenderers/EVRAllocatorPresenter.cpp | 5992 +-- .../VideoRenderers/EVRAllocatorPresenter.h | 560 +- .../renderer/VideoRenderers/IPinHook.cpp | 588 +- .../renderer/VideoRenderers/IPinHook.h | 164 +- .../renderer/VideoRenderers/IQTVideoSurface.h | 68 +- .../VideoRenderers/MacrovisionKicker.cpp | 196 +- .../VideoRenderers/MacrovisionKicker.h | 86 +- .../renderer/VideoRenderers/OuterEVR.cpp | 308 +- .../renderer/VideoRenderers/OuterEVR.h | 182 +- .../renderer/VideoRenderers/OuterVMR.cpp | 340 +- .../renderer/VideoRenderers/OuterVMR.h | 402 +- .../VideoRenderers/PixelShaderCompiler.cpp | 460 +- .../VideoRenderers/PixelShaderCompiler.h | 140 +- .../VideoRenderers/RenderersSettings.cpp | 258 +- .../VideoRenderers/RenderersSettings.h | 310 +- .../VideoRenderers/SyncAllocatorPresenter.h | 66 +- .../renderer/VideoRenderers/SyncRenderer.cpp | 9440 ++-- .../renderer/VideoRenderers/SyncRenderer.h | 1372 +- .../VideoRenderers/VMR9AllocatorPresenter.cpp | 1164 +- .../VideoRenderers/VMR9AllocatorPresenter.h | 160 +- .../VideoRenderers/VideoRenderers.vcxproj | 210 +- .../VideoRenderers.vcxproj.filters | 308 +- .../madVRAllocatorPresenter.cpp | 598 +- .../VideoRenderers/madVRAllocatorPresenter.h | 178 +- .../renderer/VideoRenderers/stdafx.cpp | 44 +- src/filters/renderer/VideoRenderers/stdafx.h | 72 +- src/filters/source/BaseSource/BaseSource.cpp | 384 +- src/filters/source/BaseSource/BaseSource.h | 260 +- .../source/BaseSource/BaseSource.vcxproj | 130 +- .../BaseSource/BaseSource.vcxproj.filters | 56 +- src/filters/source/BaseSource/stdafx.cpp | 44 +- src/filters/source/BaseSource/stdafx.h | 70 +- .../source/SubtitleSource/SubtitleSource.cpp | 1602 +- .../source/SubtitleSource/SubtitleSource.def | 10 +- .../source/SubtitleSource/SubtitleSource.h | 310 +- .../source/SubtitleSource/SubtitleSource.rc | 204 +- .../SubtitleSource/SubtitleSource.vcxproj | 264 +- .../SubtitleSource.vcxproj.filters | 90 +- src/filters/source/SubtitleSource/resource.h | 28 +- src/filters/source/SubtitleSource/stdafx.cpp | 44 +- src/filters/source/SubtitleSource/stdafx.h | 68 +- src/filters/stdafx.cpp | 44 +- src/filters/stdafx.h | 86 +- src/filters/switcher/AudioSwitcher/Audio.cpp | 644 +- src/filters/switcher/AudioSwitcher/Audio.h | 100 +- .../switcher/AudioSwitcher/AudioSwitcher.cpp | 1510 +- .../switcher/AudioSwitcher/AudioSwitcher.def | 10 +- .../switcher/AudioSwitcher/AudioSwitcher.h | 208 +- .../switcher/AudioSwitcher/AudioSwitcher.rc | 204 +- .../AudioSwitcher/AudioSwitcher.vcxproj | 254 +- .../AudioSwitcher.vcxproj.filters | 112 +- .../switcher/AudioSwitcher/StreamSwitcher.cpp | 3280 +- .../switcher/AudioSwitcher/StreamSwitcher.h | 538 +- src/filters/switcher/AudioSwitcher/resource.h | 28 +- src/filters/switcher/AudioSwitcher/stdafx.cpp | 44 +- src/filters/switcher/AudioSwitcher/stdafx.h | 72 +- .../transform/AVI2AC3Filter/AVI2AC3Filter.cpp | 1024 +- .../transform/AVI2AC3Filter/AVI2AC3Filter.def | 10 +- .../transform/AVI2AC3Filter/AVI2AC3Filter.h | 134 +- .../transform/AVI2AC3Filter/AVI2AC3Filter.rc | 204 +- .../AVI2AC3Filter/AVI2AC3Filter.vcxproj | 226 +- .../AVI2AC3Filter.vcxproj.filters | 90 +- .../transform/AVI2AC3Filter/resource.h | 28 +- .../transform/AVI2AC3Filter/stdafx.cpp | 44 +- src/filters/transform/AVI2AC3Filter/stdafx.h | 68 +- .../transform/BufferFilter/BufferFilter.cpp | 744 +- .../transform/BufferFilter/BufferFilter.def | 10 +- .../transform/BufferFilter/BufferFilter.h | 198 +- .../transform/BufferFilter/BufferFilter.rc | 204 +- .../BufferFilter/BufferFilter.vcxproj | 226 +- .../BufferFilter/BufferFilter.vcxproj.filters | 88 +- src/filters/transform/BufferFilter/resource.h | 28 +- src/filters/transform/BufferFilter/stdafx.cpp | 44 +- src/filters/transform/BufferFilter/stdafx.h | 68 +- .../transform/DeCSSFilter/DeCSSFilter.cpp | 518 +- .../transform/DeCSSFilter/DeCSSFilter.def | 10 +- .../transform/DeCSSFilter/DeCSSFilter.h | 80 +- .../transform/DeCSSFilter/DeCSSFilter.rc | 204 +- .../transform/DeCSSFilter/DeCSSFilter.vcxproj | 232 +- .../DeCSSFilter/DeCSSFilter.vcxproj.filters | 88 +- src/filters/transform/DeCSSFilter/resource.h | 28 +- src/filters/transform/DeCSSFilter/stdafx.cpp | 44 +- src/filters/transform/DeCSSFilter/stdafx.h | 68 +- .../transform/VSFilter/IDirectVobSub.h | 388 +- src/mpc-hc/AboutDlg.cpp | 680 +- src/mpc-hc/AboutDlg.h | 134 +- src/mpc-hc/AppSettings.cpp | 7738 +-- src/mpc-hc/AppSettings.h | 2152 +- src/mpc-hc/AuthDlg.cpp | 184 +- src/mpc-hc/AuthDlg.h | 52 +- src/mpc-hc/BaseGraph.cpp | 1818 +- src/mpc-hc/BaseGraph.h | 522 +- src/mpc-hc/CMPCTheme.cpp | 1394 +- src/mpc-hc/CMPCTheme.h | 390 +- src/mpc-hc/CMPCThemeButton.cpp | 382 +- src/mpc-hc/CMPCThemeButton.h | 44 +- src/mpc-hc/CMPCThemeCmdUIDialog.cpp | 90 +- src/mpc-hc/CMPCThemeCmdUIDialog.h | 42 +- src/mpc-hc/CMPCThemeComPropertyPage.cpp | 92 +- src/mpc-hc/CMPCThemeComPropertyPage.h | 42 +- src/mpc-hc/CMPCThemeComboBox.cpp | 600 +- src/mpc-hc/CMPCThemeComboBox.h | 66 +- src/mpc-hc/CMPCThemeDialog.cpp | 134 +- src/mpc-hc/CMPCThemeDialog.h | 58 +- src/mpc-hc/CMPCThemeDockBar.cpp | 124 +- src/mpc-hc/CMPCThemeDockBar.h | 30 +- src/mpc-hc/CMPCThemeEdit.cpp | 874 +- src/mpc-hc/CMPCThemeEdit.h | 78 +- src/mpc-hc/CMPCThemeFrameUtil.cpp | 14 +- src/mpc-hc/CMPCThemeFrameUtil.h | 28 +- src/mpc-hc/CMPCThemeFrameWnd.cpp | 900 +- src/mpc-hc/CMPCThemeFrameWnd.h | 98 +- src/mpc-hc/CMPCThemeGroupBox.cpp | 212 +- src/mpc-hc/CMPCThemeGroupBox.h | 36 +- src/mpc-hc/CMPCThemeHeaderCtrl.cpp | 544 +- src/mpc-hc/CMPCThemeHeaderCtrl.h | 42 +- src/mpc-hc/CMPCThemeInlineEdit.cpp | 138 +- src/mpc-hc/CMPCThemeInlineEdit.h | 42 +- src/mpc-hc/CMPCThemeLinkCtrl.cpp | 70 +- src/mpc-hc/CMPCThemeLinkCtrl.h | 26 +- src/mpc-hc/CMPCThemeListBox.cpp | 448 +- src/mpc-hc/CMPCThemeListBox.h | 74 +- src/mpc-hc/CMPCThemeMaskedEdit.cpp | 102 +- src/mpc-hc/CMPCThemeMaskedEdit.h | 36 +- src/mpc-hc/CMPCThemeMenu.cpp | 1180 +- src/mpc-hc/CMPCThemeMenu.h | 126 +- src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp | 42 +- src/mpc-hc/CMPCThemeMiniDockFrameWnd.h | 24 +- src/mpc-hc/CMPCThemeMsgBox.cpp | 164 +- src/mpc-hc/CMPCThemeMsgBox.h | 40 +- src/mpc-hc/CMPCThemePPageBase.cpp | 178 +- src/mpc-hc/CMPCThemePPageBase.h | 48 +- src/mpc-hc/CMPCThemePlayerBar.cpp | 282 +- src/mpc-hc/CMPCThemePlayerBar.h | 44 +- src/mpc-hc/CMPCThemePlayerListCtrl.cpp | 1266 +- src/mpc-hc/CMPCThemePlayerListCtrl.h | 148 +- src/mpc-hc/CMPCThemePropPageFrame.cpp | 196 +- src/mpc-hc/CMPCThemePropPageFrame.h | 38 +- src/mpc-hc/CMPCThemePropertyPage.cpp | 72 +- src/mpc-hc/CMPCThemePropertyPage.h | 38 +- src/mpc-hc/CMPCThemePropertySheet.cpp | 132 +- src/mpc-hc/CMPCThemePropertySheet.h | 50 +- src/mpc-hc/CMPCThemeRadioOrCheck.cpp | 548 +- src/mpc-hc/CMPCThemeRadioOrCheck.h | 76 +- src/mpc-hc/CMPCThemeResizableDialog.cpp | 102 +- src/mpc-hc/CMPCThemeResizableDialog.h | 38 +- src/mpc-hc/CMPCThemeScrollBar.cpp | 560 +- src/mpc-hc/CMPCThemeScrollBar.h | 62 +- src/mpc-hc/CMPCThemeScrollBarHelper.cpp | 696 +- src/mpc-hc/CMPCThemeScrollBarHelper.h | 102 +- src/mpc-hc/CMPCThemeSliderCtrl.cpp | 402 +- src/mpc-hc/CMPCThemeSliderCtrl.h | 56 +- src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp | 472 +- src/mpc-hc/CMPCThemeSpinButtonCtrl.h | 54 +- src/mpc-hc/CMPCThemeStatic.cpp | 358 +- src/mpc-hc/CMPCThemeStatic.h | 42 +- src/mpc-hc/CMPCThemeStaticLink.cpp | 198 +- src/mpc-hc/CMPCThemeStaticLink.h | 36 +- src/mpc-hc/CMPCThemeStatusBar.cpp | 246 +- src/mpc-hc/CMPCThemeStatusBar.h | 46 +- src/mpc-hc/CMPCThemeTabCtrl.cpp | 400 +- src/mpc-hc/CMPCThemeTabCtrl.h | 42 +- src/mpc-hc/CMPCThemeTitleBarControlButton.cpp | 266 +- src/mpc-hc/CMPCThemeTitleBarControlButton.h | 42 +- src/mpc-hc/CMPCThemeToolTipCtrl.cpp | 526 +- src/mpc-hc/CMPCThemeToolTipCtrl.h | 90 +- src/mpc-hc/CMPCThemeTreeCtrl.cpp | 488 +- src/mpc-hc/CMPCThemeTreeCtrl.h | 72 +- src/mpc-hc/CMPCThemeUtil.cpp | 2602 +- src/mpc-hc/CMPCThemeUtil.h | 270 +- src/mpc-hc/CMPCThemeWin10Api.h | 120 +- src/mpc-hc/CShockwaveFlash.cpp | 58 +- src/mpc-hc/CShockwaveFlash.h | 766 +- src/mpc-hc/ChildView.cpp | 414 +- src/mpc-hc/ChildView.h | 106 +- src/mpc-hc/ColorButton.cpp | 192 +- src/mpc-hc/ComPropertyPage.cpp | 208 +- src/mpc-hc/ComPropertyPage.h | 104 +- src/mpc-hc/ComPropertySheet.cpp | 574 +- src/mpc-hc/ComPropertySheet.h | 140 +- src/mpc-hc/DVBChannel.cpp | 620 +- src/mpc-hc/DVBChannel.h | 442 +- src/mpc-hc/DeinterlacerFilter.cpp | 340 +- src/mpc-hc/DeinterlacerFilter.h | 74 +- src/mpc-hc/EditListEditor.cpp | 1324 +- src/mpc-hc/EditListEditor.h | 242 +- src/mpc-hc/EditWithButton.cpp | 726 +- src/mpc-hc/EditWithButton.h | 226 +- src/mpc-hc/ExceptionHandler.cpp | 426 +- src/mpc-hc/ExceptionHandler.h | 54 +- src/mpc-hc/FGFilter.cpp | 1556 +- src/mpc-hc/FGFilter.h | 386 +- src/mpc-hc/FGFilterLAV.cpp | 2548 +- src/mpc-hc/FGManager.cpp | 6088 +-- src/mpc-hc/FGManager.h | 424 +- src/mpc-hc/FGManagerBDA.cpp | 2912 +- src/mpc-hc/FGManagerBDA.h | 356 +- src/mpc-hc/FakeFilterMapper2.cpp | 1436 +- src/mpc-hc/FakeFilterMapper2.h | 198 +- src/mpc-hc/FavoriteAddDlg.cpp | 250 +- src/mpc-hc/FavoriteAddDlg.h | 108 +- src/mpc-hc/FavoriteOrganizeDlg.cpp | 1064 +- src/mpc-hc/FavoriteOrganizeDlg.h | 168 +- src/mpc-hc/FileAssoc.cpp | 1488 +- src/mpc-hc/FileAssoc.h | 272 +- src/mpc-hc/FilterEnum.h | 548 +- src/mpc-hc/FloatEdit.cpp | 362 +- src/mpc-hc/FloatEdit.h | 140 +- src/mpc-hc/FullscreenWnd.cpp | 206 +- src/mpc-hc/FullscreenWnd.h | 102 +- src/mpc-hc/GoToDlg.cpp | 390 +- src/mpc-hc/GoToDlg.h | 134 +- src/mpc-hc/GraphThread.cpp | 214 +- src/mpc-hc/GraphThread.h | 112 +- src/mpc-hc/IGraphBuilder2.h | 122 +- src/mpc-hc/Ifo.cpp | 564 +- src/mpc-hc/Ifo.h | 372 +- src/mpc-hc/ImageGrayer.cpp | 608 +- src/mpc-hc/ImageGrayer.h | 70 +- src/mpc-hc/InternalFiltersConfig.h | 248 +- src/mpc-hc/KeyProvider.cpp | 114 +- src/mpc-hc/KeyProvider.h | 84 +- src/mpc-hc/LcdSupport.cpp | 1522 +- src/mpc-hc/LcdSupport.h | 272 +- src/mpc-hc/MPCPngImage.cpp | 228 +- src/mpc-hc/MPCPngImage.h | 58 +- src/mpc-hc/MainFrm.cpp | 44364 ++++++++-------- src/mpc-hc/MainFrm.h | 2822 +- src/mpc-hc/MediaFormats.cpp | 686 +- src/mpc-hc/MediaFormats.h | 182 +- src/mpc-hc/MediaTypesDlg.cpp | 316 +- src/mpc-hc/MediaTypesDlg.h | 128 +- src/mpc-hc/Monitors.cpp | 492 +- src/mpc-hc/Monitors.h | 180 +- src/mpc-hc/MpcApi.h | 572 +- src/mpc-hc/Mpeg2SectionData.cpp | 1758 +- src/mpc-hc/Mpeg2SectionData.h | 188 +- src/mpc-hc/MultiMonitor.cpp | 526 +- src/mpc-hc/MultiMonitor.h | 178 +- src/mpc-hc/OpenDirHelper.cpp | 226 +- src/mpc-hc/OpenDirHelper.h | 72 +- src/mpc-hc/OpenDlg.cpp | 474 +- src/mpc-hc/OpenDlg.h | 136 +- src/mpc-hc/OpenFileDlg.cpp | 474 +- src/mpc-hc/OpenFileDlg.h | 124 +- src/mpc-hc/PPageAccelTbl.cpp | 2904 +- src/mpc-hc/PPageAccelTbl.h | 250 +- src/mpc-hc/PPageAudioSwitcher.cpp | 880 +- src/mpc-hc/PPageAudioSwitcher.h | 188 +- src/mpc-hc/PPageBase.cpp | 382 +- src/mpc-hc/PPageBase.h | 122 +- src/mpc-hc/PPageCapture.cpp | 1460 +- src/mpc-hc/PPageCapture.h | 146 +- src/mpc-hc/PPageDVD.cpp | 660 +- src/mpc-hc/PPageDVD.h | 140 +- src/mpc-hc/PPageExternalFilters.cpp | 1740 +- src/mpc-hc/PPageExternalFilters.h | 234 +- src/mpc-hc/PPageFileInfoClip.cpp | 450 +- src/mpc-hc/PPageFileInfoClip.h | 130 +- src/mpc-hc/PPageFileInfoDetails.cpp | 786 +- src/mpc-hc/PPageFileInfoDetails.h | 126 +- src/mpc-hc/PPageFileInfoSheet.cpp | 196 +- src/mpc-hc/PPageFileInfoSheet.h | 116 +- src/mpc-hc/PPageFileMediaInfo.cpp | 596 +- src/mpc-hc/PPageFileMediaInfo.h | 140 +- src/mpc-hc/PPageFormats.cpp | 1050 +- src/mpc-hc/PPageFormats.h | 198 +- src/mpc-hc/PPageFullscreen.cpp | 1514 +- src/mpc-hc/PPageFullscreen.h | 222 +- src/mpc-hc/PPageInternalFilters.cpp | 1546 +- src/mpc-hc/PPageInternalFilters.h | 214 +- src/mpc-hc/PPageLogo.cpp | 474 +- src/mpc-hc/PPageLogo.h | 130 +- src/mpc-hc/PPageMisc.cpp | 586 +- src/mpc-hc/PPageMisc.h | 172 +- src/mpc-hc/PPageOutput.cpp | 1524 +- src/mpc-hc/PPageOutput.h | 206 +- src/mpc-hc/PPagePlayback.cpp | 740 +- src/mpc-hc/PPagePlayback.h | 192 +- src/mpc-hc/PPagePlayer.cpp | 412 +- src/mpc-hc/PPagePlayer.h | 152 +- src/mpc-hc/PPageShaders.cpp | 1218 +- src/mpc-hc/PPageShaders.h | 244 +- src/mpc-hc/PPageSheet.cpp | 786 +- src/mpc-hc/PPageSheet.h | 304 +- src/mpc-hc/PPageSubMisc.cpp | 770 +- src/mpc-hc/PPageSubMisc.h | 172 +- src/mpc-hc/PPageSubStyle.cpp | 834 +- src/mpc-hc/PPageSubStyle.h | 200 +- src/mpc-hc/PPageSubtitles.cpp | 676 +- src/mpc-hc/PPageSubtitles.h | 146 +- src/mpc-hc/PPageSync.cpp | 362 +- src/mpc-hc/PPageSync.h | 132 +- src/mpc-hc/PPageToolBar.cpp | 365 + src/mpc-hc/PPageToolBar.h | 76 + src/mpc-hc/PPageTweaks.cpp | 340 +- src/mpc-hc/PPageTweaks.h | 128 +- src/mpc-hc/PPageWebServer.cpp | 522 +- src/mpc-hc/PPageWebServer.h | 144 +- src/mpc-hc/PlayerBar.cpp | 398 +- src/mpc-hc/PlayerBar.h | 134 +- src/mpc-hc/PlayerCaptureBar.cpp | 220 +- src/mpc-hc/PlayerCaptureBar.h | 102 +- src/mpc-hc/PlayerCaptureDialog.cpp | 3506 +- src/mpc-hc/PlayerCaptureDialog.h | 1020 +- src/mpc-hc/PlayerInfoBar.cpp | 600 +- src/mpc-hc/PlayerInfoBar.h | 144 +- src/mpc-hc/PlayerListCtrl.cpp | 2296 +- src/mpc-hc/PlayerListCtrl.h | 408 +- src/mpc-hc/PlayerNavigationBar.cpp | 296 +- src/mpc-hc/PlayerNavigationBar.h | 114 +- src/mpc-hc/PlayerNavigationDialog.cpp | 702 +- src/mpc-hc/PlayerNavigationDialog.h | 164 +- src/mpc-hc/PlayerPlaylistBar.cpp | 5194 +- src/mpc-hc/PlayerPlaylistBar.h | 412 +- src/mpc-hc/PlayerSeekBar.cpp | 1912 +- src/mpc-hc/PlayerSeekBar.h | 268 +- src/mpc-hc/PlayerStatusBar.cpp | 1266 +- src/mpc-hc/PlayerStatusBar.h | 202 +- src/mpc-hc/PlayerSubresyncBar.cpp | 3130 +- src/mpc-hc/PlayerSubresyncBar.h | 356 +- src/mpc-hc/PlayerToolBar.cpp | 1694 +- src/mpc-hc/PlayerToolBar.h | 268 +- src/mpc-hc/Playlist.cpp | 954 +- src/mpc-hc/Playlist.h | 246 +- src/mpc-hc/PnSPresetsDlg.cpp | 544 +- src/mpc-hc/PnSPresetsDlg.h | 146 +- src/mpc-hc/RegFilterChooserDlg.cpp | 368 +- src/mpc-hc/RegFilterChooserDlg.h | 122 +- src/mpc-hc/SaveDlg.cpp | 562 +- src/mpc-hc/SaveDlg.h | 126 +- src/mpc-hc/SaveImageDialog.cpp | 232 +- src/mpc-hc/SaveImageDialog.h | 96 +- src/mpc-hc/SaveTextFileDialog.cpp | 180 +- src/mpc-hc/SaveTextFileDialog.h | 108 +- src/mpc-hc/SaveThumbnailsDialog.cpp | 204 +- src/mpc-hc/SaveThumbnailsDialog.h | 100 +- src/mpc-hc/SelectMediaType.cpp | 204 +- src/mpc-hc/SelectMediaType.h | 114 +- src/mpc-hc/SettingsDefines.h | 816 +- src/mpc-hc/ShockwaveGraph.cpp | 652 +- src/mpc-hc/ShockwaveGraph.h | 164 +- src/mpc-hc/StaticLink.cpp | 302 +- src/mpc-hc/StaticLink.h | 148 +- src/mpc-hc/StatusLabel.cpp | 198 +- src/mpc-hc/StatusLabel.h | 102 +- src/mpc-hc/Struct.h | 164 +- src/mpc-hc/SubtitleDlDlg.cpp | 1694 +- src/mpc-hc/SubtitleDlDlg.h | 272 +- src/mpc-hc/SubtitlesProvider.cpp | 2016 +- src/mpc-hc/SubtitlesProvider.h | 246 +- src/mpc-hc/SubtitlesProviders.h | 886 +- src/mpc-hc/TextPassThruFilter.cpp | 510 +- src/mpc-hc/TextPassThruFilter.h | 92 +- src/mpc-hc/TunerScanDlg.cpp | 634 +- src/mpc-hc/TunerScanDlg.h | 160 +- src/mpc-hc/UpdateChecker.cpp | 576 +- src/mpc-hc/UpdateChecker.h | 174 +- src/mpc-hc/UpdateCheckerDlg.cpp | 264 +- src/mpc-hc/UpdateCheckerDlg.h | 108 +- src/mpc-hc/VMROSD.cpp | 1324 +- src/mpc-hc/VMROSD.h | 288 +- src/mpc-hc/VolumeCtrl.cpp | 996 +- src/mpc-hc/VolumeCtrl.h | 132 +- src/mpc-hc/WebClientSocket.cpp | 2036 +- src/mpc-hc/WebClientSocket.h | 170 +- src/mpc-hc/WebServer.cpp | 1430 +- src/mpc-hc/WebServer.h | 146 +- src/mpc-hc/WebServerSocket.cpp | 90 +- src/mpc-hc/WebServerSocket.h | 72 +- src/mpc-hc/WinHotkeyCtrl.cpp | 634 +- src/mpc-hc/WinHotkeyCtrl.h | 144 +- src/mpc-hc/mpc-hc.vcxproj | 1684 +- src/mpc-hc/mpc-hc.vcxproj.filters | 2952 +- src/mpc-hc/mpciconlib/mpciconlib.cpp | 546 +- src/mpc-hc/mpciconlib/mpciconlib.h | 172 +- src/mpc-hc/mpciconlib/mpciconlib.rc | 308 +- src/mpc-hc/mpciconlib/mpciconlib.vcxproj | 226 +- .../mpciconlib/mpciconlib.vcxproj.filters | 342 +- src/mpc-hc/mpcresources/mpcresources.vcxproj | 1192 +- .../mpcresources/mpcresources.vcxproj.filters | 320 +- src/mpc-hc/mplayerc.cpp | 5650 +- src/mpc-hc/mplayerc.h | 468 +- src/mpc-hc/res/mpc-hc.exe.manifest.conf | 88 +- src/mpc-hc/res/shaders/empty.psh | 34 +- src/mpc-hc/res/shaders/final.psh | 58 +- src/mpc-hc/res/shaders/resizer.psh | 230 +- src/mpc-hc/res/web/404.html | 28 +- src/mpc-hc/res/web/browser.html | 66 +- src/mpc-hc/res/web/controls.html | 2408 +- src/mpc-hc/res/web/default.css | 700 +- src/mpc-hc/res/web/index.html | 50 +- src/mpc-hc/res/web/info.html | 28 +- src/mpc-hc/res/web/javascript.js | 1148 +- src/mpc-hc/res/web/player.html | 218 +- src/mpc-hc/res/web/variables.html | 62 +- src/mpc-hc/resource.h | 3540 +- src/mpc-hc/stdafx.cpp | 44 +- src/mpc-hc/stdafx.h | 178 +- src/mpc-hc/vkCodes.cpp | 674 +- src/mpc-hc/vkCodes.h | 52 +- .../AsyncReader/AsyncReader.vcxproj | 134 +- .../AsyncReader/AsyncReader.vcxproj.filters | 68 +- src/thirdparty/AsyncReader/asyncio.cpp | 1418 +- src/thirdparty/AsyncReader/asyncio.h | 560 +- src/thirdparty/AsyncReader/asyncrdr.cpp | 908 +- src/thirdparty/AsyncReader/asyncrdr.h | 472 +- src/thirdparty/AsyncReader/stdafx.cpp | 44 +- src/thirdparty/AsyncReader/stdafx.h | 56 +- .../BaseClasses/BaseClasses.vcxproj | 258 +- .../BaseClasses/BaseClasses.vcxproj.filters | 446 +- src/thirdparty/BaseClasses/amextra.cpp | 222 +- src/thirdparty/BaseClasses/amextra.h | 112 +- src/thirdparty/BaseClasses/amfilter.cpp | 10746 ++-- src/thirdparty/BaseClasses/amfilter.h | 3174 +- src/thirdparty/BaseClasses/amvideo.cpp | 550 +- src/thirdparty/BaseClasses/arithutil.cpp | 720 +- src/thirdparty/BaseClasses/cache.h | 148 +- src/thirdparty/BaseClasses/checkbmi.h | 240 +- src/thirdparty/BaseClasses/combase.cpp | 532 +- src/thirdparty/BaseClasses/combase.h | 630 +- src/thirdparty/BaseClasses/cprop.cpp | 768 +- src/thirdparty/BaseClasses/cprop.h | 190 +- src/thirdparty/BaseClasses/ctlutil.cpp | 5078 +- src/thirdparty/BaseClasses/ctlutil.h | 1846 +- src/thirdparty/BaseClasses/ddmm.cpp | 258 +- src/thirdparty/BaseClasses/ddmm.h | 56 +- src/thirdparty/BaseClasses/dllentry.cpp | 730 +- src/thirdparty/BaseClasses/dllsetup.cpp | 1392 +- src/thirdparty/BaseClasses/dllsetup.h | 92 +- src/thirdparty/BaseClasses/dxmperf.h | 500 +- src/thirdparty/BaseClasses/fourcc.h | 202 +- src/thirdparty/BaseClasses/measure.h | 444 +- src/thirdparty/BaseClasses/msgthrd.h | 240 +- src/thirdparty/BaseClasses/mtype.cpp | 956 +- src/thirdparty/BaseClasses/mtype.h | 178 +- src/thirdparty/BaseClasses/outputq.cpp | 1602 +- src/thirdparty/BaseClasses/outputq.h | 274 +- src/thirdparty/BaseClasses/perflog.cpp | 694 +- src/thirdparty/BaseClasses/perflog.h | 112 +- src/thirdparty/BaseClasses/perfstruct.h | 388 +- src/thirdparty/BaseClasses/pstream.cpp | 394 +- src/thirdparty/BaseClasses/pstream.h | 228 +- src/thirdparty/BaseClasses/pullpin.cpp | 1186 +- src/thirdparty/BaseClasses/pullpin.h | 304 +- src/thirdparty/BaseClasses/refclock.cpp | 806 +- src/thirdparty/BaseClasses/refclock.h | 368 +- src/thirdparty/BaseClasses/reftime.h | 232 +- src/thirdparty/BaseClasses/renbase.cpp | 5716 +- src/thirdparty/BaseClasses/renbase.h | 956 +- src/thirdparty/BaseClasses/schedule.cpp | 576 +- src/thirdparty/BaseClasses/schedule.h | 280 +- src/thirdparty/BaseClasses/seekpt.cpp | 166 +- src/thirdparty/BaseClasses/seekpt.h | 60 +- src/thirdparty/BaseClasses/source.cpp | 1044 +- src/thirdparty/BaseClasses/source.h | 344 +- src/thirdparty/BaseClasses/stdafx.cpp | 46 +- src/thirdparty/BaseClasses/streams.h | 380 +- src/thirdparty/BaseClasses/strmctl.cpp | 810 +- src/thirdparty/BaseClasses/strmctl.h | 314 +- src/thirdparty/BaseClasses/sysclock.cpp | 148 +- src/thirdparty/BaseClasses/sysclock.h | 78 +- src/thirdparty/BaseClasses/transfrm.cpp | 2032 +- src/thirdparty/BaseClasses/transfrm.h | 608 +- src/thirdparty/BaseClasses/transip.cpp | 1954 +- src/thirdparty/BaseClasses/transip.h | 500 +- src/thirdparty/BaseClasses/videoctl.cpp | 1490 +- src/thirdparty/BaseClasses/videoctl.h | 336 +- src/thirdparty/BaseClasses/vtrans.cpp | 938 +- src/thirdparty/BaseClasses/vtrans.h | 286 +- src/thirdparty/BaseClasses/winctrl.cpp | 4162 +- src/thirdparty/BaseClasses/winctrl.h | 448 +- src/thirdparty/BaseClasses/winutil.cpp | 5518 +- src/thirdparty/BaseClasses/winutil.h | 842 +- src/thirdparty/BaseClasses/wxdebug.cpp | 2950 +- src/thirdparty/BaseClasses/wxdebug.h | 718 +- src/thirdparty/BaseClasses/wxlist.cpp | 1782 +- src/thirdparty/BaseClasses/wxlist.h | 1106 +- src/thirdparty/BaseClasses/wxutil.cpp | 1544 +- src/thirdparty/BaseClasses/wxutil.h | 1064 +- src/thirdparty/LAVFilters/LAVFilters.vcxproj | 98 +- .../LAVFilters/build_lavfilters.bat | 446 +- src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp | 292 +- src/thirdparty/LCDUI/LCDAnimatedBitmap.h | 114 +- src/thirdparty/LCDUI/LCDBase.cpp | 770 +- src/thirdparty/LCDUI/LCDBase.h | 194 +- src/thirdparty/LCDUI/LCDBitmap.cpp | 358 +- src/thirdparty/LCDUI/LCDBitmap.h | 108 +- src/thirdparty/LCDUI/LCDCollection.cpp | 466 +- src/thirdparty/LCDUI/LCDCollection.h | 102 +- src/thirdparty/LCDUI/LCDColorProgressBar.cpp | 406 +- src/thirdparty/LCDUI/LCDColorProgressBar.h | 104 +- src/thirdparty/LCDUI/LCDColorText.cpp | 602 +- src/thirdparty/LCDUI/LCDColorText.h | 126 +- src/thirdparty/LCDUI/LCDConnection.cpp | 1446 +- src/thirdparty/LCDUI/LCDConnection.h | 322 +- src/thirdparty/LCDUI/LCDGfxBase.cpp | 600 +- src/thirdparty/LCDUI/LCDGfxBase.h | 190 +- src/thirdparty/LCDUI/LCDGfxColor.cpp | 188 +- src/thirdparty/LCDUI/LCDGfxColor.h | 96 +- src/thirdparty/LCDUI/LCDGfxMono.cpp | 216 +- src/thirdparty/LCDUI/LCDGfxMono.h | 98 +- src/thirdparty/LCDUI/LCDIcon.cpp | 172 +- src/thirdparty/LCDUI/LCDIcon.h | 100 +- src/thirdparty/LCDUI/LCDOutput.cpp | 1308 +- src/thirdparty/LCDUI/LCDOutput.h | 214 +- src/thirdparty/LCDUI/LCDPage.cpp | 448 +- src/thirdparty/LCDUI/LCDPage.h | 116 +- src/thirdparty/LCDUI/LCDPaginateText.cpp | 548 +- src/thirdparty/LCDUI/LCDPaginateText.h | 126 +- src/thirdparty/LCDUI/LCDPopup.cpp | 1112 +- src/thirdparty/LCDUI/LCDPopup.h | 200 +- src/thirdparty/LCDUI/LCDProgressBar.cpp | 526 +- src/thirdparty/LCDUI/LCDProgressBar.h | 144 +- src/thirdparty/LCDUI/LCDScrollingText.cpp | 612 +- src/thirdparty/LCDUI/LCDScrollingText.h | 150 +- .../LCDUI/LCDSkinnedProgressBar.cpp | 646 +- src/thirdparty/LCDUI/LCDSkinnedProgressBar.h | 166 +- src/thirdparty/LCDUI/LCDStreamingText.cpp | 1510 +- src/thirdparty/LCDUI/LCDStreamingText.h | 240 +- src/thirdparty/LCDUI/LCDText.cpp | 934 +- src/thirdparty/LCDUI/LCDText.h | 164 +- src/thirdparty/LCDUI/LCDUI.h | 184 +- src/thirdparty/LCDUI/LCDUI.vcxproj | 212 +- src/thirdparty/LCDUI/LCDUI.vcxproj.filters | 284 +- src/thirdparty/LCDUI/stdafx.cpp | 42 +- .../MessageBoxDialog/MessageBoxDialog.cpp | 2146 +- .../MessageBoxDialog/MessageBoxDialog.h | 376 +- src/thirdparty/MessageBoxDialog/lgpl-2.1.txt | 962 +- src/thirdparty/MessageBoxDialog/mpl-1.1.txt | 940 +- src/thirdparty/RARFileSource/File.h | 24 +- src/thirdparty/RARFileSource/OutputPin.h | 2 +- .../RARFileSource/RARFileSource.vcxproj | 186 +- .../RARFileSource.vcxproj.filters | 134 +- .../ResizableLib/ResizableDialog.cpp | 332 +- src/thirdparty/ResizableLib/ResizableDialog.h | 206 +- src/thirdparty/ResizableLib/ResizableGrip.cpp | 636 +- src/thirdparty/ResizableLib/ResizableGrip.h | 188 +- .../ResizableLib/ResizableLayout.cpp | 1840 +- src/thirdparty/ResizableLib/ResizableLayout.h | 632 +- .../ResizableLib/ResizableLib.vcxproj | 160 +- .../ResizableLib/ResizableLib.vcxproj.filters | 176 +- .../ResizableLib/ResizableMinMax.cpp | 422 +- src/thirdparty/ResizableLib/ResizableMinMax.h | 164 +- .../ResizableLib/ResizableMsgSupport.h | 208 +- src/thirdparty/ResizableLib/ResizablePage.cpp | 238 +- src/thirdparty/ResizableLib/ResizablePage.h | 164 +- .../ResizableLib/ResizableSheet.cpp | 952 +- src/thirdparty/ResizableLib/ResizableSheet.h | 242 +- .../ResizableLib/ResizableState.cpp | 264 +- src/thirdparty/ResizableLib/ResizableState.h | 154 +- src/thirdparty/ResizableLib/stdafx.cpp | 12 +- src/thirdparty/ResizableLib/stdafx.h | 136 +- .../TreePropSheet/PropPageFrame.cpp | 374 +- src/thirdparty/TreePropSheet/PropPageFrame.h | 612 +- .../TreePropSheet/PropPageFrameDefault.cpp | 820 +- .../TreePropSheet/PropPageFrameDefault.h | 234 +- .../TreePropSheet/TreePropSheet.cpp | 2000 +- src/thirdparty/TreePropSheet/TreePropSheet.h | 974 +- .../TreePropSheet/TreePropSheet.vcxproj | 128 +- .../TreePropSheet.vcxproj.filters | 80 +- src/thirdparty/TreePropSheet/stdafx.cpp | 44 +- src/thirdparty/TreePropSheet/stdafx.h | 68 +- .../VirtualDub/Kasumi/Kasumi.vcxproj | 398 +- .../VirtualDub/Kasumi/Kasumi.vcxproj.filters | 646 +- src/thirdparty/VirtualDub/Kasumi/h/bitutils.h | 52 +- .../VirtualDub/Kasumi/h/blt_setup.h | 124 +- .../VirtualDub/Kasumi/h/blt_spanutils.h | 46 +- .../VirtualDub/Kasumi/h/blt_spanutils_x86.h | 70 +- .../VirtualDub/Kasumi/h/resample_stages.h | 160 +- .../Kasumi/h/resample_stages_reference.h | 312 +- .../VirtualDub/Kasumi/h/resample_stages_x64.h | 52 +- .../VirtualDub/Kasumi/h/resample_stages_x86.h | 386 +- src/thirdparty/VirtualDub/Kasumi/h/stdafx.h | 42 +- src/thirdparty/VirtualDub/Kasumi/h/uberblit.h | 190 +- .../VirtualDub/Kasumi/h/uberblit_16f.h | 78 +- .../VirtualDub/Kasumi/h/uberblit_base.h | 258 +- .../VirtualDub/Kasumi/h/uberblit_fill.h | 110 +- .../VirtualDub/Kasumi/h/uberblit_gen.h | 354 +- .../VirtualDub/Kasumi/h/uberblit_input.h | 138 +- .../VirtualDub/Kasumi/h/uberblit_interlace.h | 246 +- .../VirtualDub/Kasumi/h/uberblit_pal.h | 296 +- .../VirtualDub/Kasumi/h/uberblit_resample.h | 166 +- .../Kasumi/h/uberblit_resample_special.h | 162 +- .../Kasumi/h/uberblit_resample_special_x86.h | 52 +- .../VirtualDub/Kasumi/h/uberblit_rgb.h | 1104 +- .../VirtualDub/Kasumi/h/uberblit_rgb_x86.h | 228 +- .../VirtualDub/Kasumi/h/uberblit_swizzle.h | 686 +- .../Kasumi/h/uberblit_swizzle_x86.h | 142 +- .../VirtualDub/Kasumi/h/uberblit_v210.h | 144 +- .../VirtualDub/Kasumi/h/uberblit_ycbcr.h | 1200 +- .../Kasumi/h/uberblit_ycbcr_generic.h | 308 +- .../VirtualDub/Kasumi/h/uberblit_ycbcr_x86.h | 54 +- .../Kasumi/source/a64_resample.asm64 | 1240 +- .../VirtualDub/Kasumi/source/a_bltrgb.asm | 1624 +- .../Kasumi/source/a_bltrgb2yuv_mmx.asm | 1302 +- .../VirtualDub/Kasumi/source/a_bltrgb_mmx.asm | 1612 +- .../Kasumi/source/a_bltyuv2rgb_sse2.asm | 322 +- .../Kasumi/source/a_resample_mmx.asm | 3118 +- .../Kasumi/source/a_resample_sse41.asm | 716 +- .../Kasumi/source/a_spanutils_isse.asm | 386 +- .../Kasumi/source/a_stretchrgb_mmx.asm | 652 +- .../Kasumi/source/a_stretchrgb_point.asm | 192 +- .../VirtualDub/Kasumi/source/a_triblt.inc | 48 +- .../VirtualDub/Kasumi/source/a_triblt_mmx.asm | 850 +- .../Kasumi/source/a_triblt_scalar.asm | 70 +- .../Kasumi/source/a_triblt_sse2.asm | 394 +- .../VirtualDub/Kasumi/source/alphablt.cpp | 190 +- .../VirtualDub/Kasumi/source/blitter.cpp | 104 +- .../VirtualDub/Kasumi/source/blt.cpp | 584 +- .../Kasumi/source/blt_reference.cpp | 688 +- .../Kasumi/source/blt_reference_pal.cpp | 1128 +- .../Kasumi/source/blt_reference_rgb.cpp | 658 +- .../Kasumi/source/blt_reference_yuv.cpp | 3220 +- .../Kasumi/source/blt_reference_yuv2yuv.cpp | 558 +- .../Kasumi/source/blt_reference_yuvrev.cpp | 1098 +- .../VirtualDub/Kasumi/source/blt_setup.cpp | 72 +- .../Kasumi/source/blt_spanutils.cpp | 768 +- .../Kasumi/source/blt_spanutils_x86.cpp | 342 +- .../VirtualDub/Kasumi/source/blt_uberblit.cpp | 76 +- .../VirtualDub/Kasumi/source/blt_x86.cpp | 326 +- .../VirtualDub/Kasumi/source/pixel.cpp | 1884 +- .../VirtualDub/Kasumi/source/pixmaputils.cpp | 1266 +- .../VirtualDub/Kasumi/source/region.cpp | 2750 +- .../VirtualDub/Kasumi/source/resample.cpp | 832 +- .../Kasumi/source/resample_kernels.cpp | 584 +- .../Kasumi/source/resample_stages.cpp | 336 +- .../source/resample_stages_reference.cpp | 888 +- .../Kasumi/source/resample_stages_x64.cpp | 54 +- .../Kasumi/source/resample_stages_x86.cpp | 2592 +- .../VirtualDub/Kasumi/source/stdafx.cpp | 36 +- .../Kasumi/source/stretchblt_reference.cpp | 1670 +- .../VirtualDub/Kasumi/source/tables.cpp | 410 +- .../VirtualDub/Kasumi/source/triblt.cpp | 3520 +- .../VirtualDub/Kasumi/source/uberblit.cpp | 2832 +- .../VirtualDub/Kasumi/source/uberblit_16f.cpp | 118 +- .../VirtualDub/Kasumi/source/uberblit_gen.cpp | 3458 +- .../Kasumi/source/uberblit_resample.cpp | 1284 +- .../source/uberblit_resample_special.cpp | 410 +- .../source/uberblit_resample_special_x86.cpp | 108 +- .../Kasumi/source/uberblit_swizzle.cpp | 216 +- .../Kasumi/source/uberblit_swizzle_x86.cpp | 838 +- .../Kasumi/source/uberblit_v210.cpp | 436 +- .../Kasumi/source/uberblit_ycbcr_generic.cpp | 1090 +- .../Kasumi/source/uberblit_ycbcr_x86.cpp | 108 +- .../VirtualDub/h/vd2/Kasumi/blitter.h | 78 +- .../VirtualDub/h/vd2/Kasumi/pixel.h | 80 +- .../VirtualDub/h/vd2/Kasumi/pixmap.h | 218 +- .../VirtualDub/h/vd2/Kasumi/pixmapops.h | 40 +- .../VirtualDub/h/vd2/Kasumi/pixmaputils.h | 342 +- .../VirtualDub/h/vd2/Kasumi/region.h | 186 +- .../VirtualDub/h/vd2/Kasumi/resample.h | 62 +- .../h/vd2/Kasumi/resample_kernels.h | 182 +- .../VirtualDub/h/vd2/Kasumi/tables.h | 82 +- src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h | 152 +- .../VirtualDub/h/vd2/Kasumi/triblt.h | 144 +- .../VirtualDub/h/vd2/system/Error.h | 250 +- .../VirtualDub/h/vd2/system/Fraction.h | 190 +- .../VirtualDub/h/vd2/system/VDNamespace.h | 314 +- .../VirtualDub/h/vd2/system/VDQueue.h | 180 +- .../VirtualDub/h/vd2/system/VDRingBuffer.h | 602 +- .../VirtualDub/h/vd2/system/VDScheduler.h | 294 +- .../VirtualDub/h/vd2/system/VDString.h | 2528 +- .../VirtualDub/h/vd2/system/atomic.h | 752 +- .../VirtualDub/h/vd2/system/binary.h | 362 +- .../VirtualDub/h/vd2/system/bitmath.h | 190 +- .../VirtualDub/h/vd2/system/cache.h | 650 +- .../VirtualDub/h/vd2/system/cmdline.h | 168 +- .../VirtualDub/h/vd2/system/cpuaccel.h | 102 +- .../VirtualDub/h/vd2/system/debug.h | 192 +- .../VirtualDub/h/vd2/system/debugx86.h | 74 +- .../VirtualDub/h/vd2/system/event.h | 398 +- src/thirdparty/VirtualDub/h/vd2/system/file.h | 654 +- .../VirtualDub/h/vd2/system/fileasync.h | 134 +- .../VirtualDub/h/vd2/system/halffloat.h | 18 +- src/thirdparty/VirtualDub/h/vd2/system/hash.h | 102 +- .../VirtualDub/h/vd2/system/int128.h | 750 +- .../VirtualDub/h/vd2/system/linearalloc.h | 176 +- src/thirdparty/VirtualDub/h/vd2/system/list.h | 550 +- src/thirdparty/VirtualDub/h/vd2/system/math.h | 538 +- .../VirtualDub/h/vd2/system/memory.h | 168 +- .../VirtualDub/h/vd2/system/progress.h | 192 +- .../VirtualDub/h/vd2/system/protscope.h | 490 +- .../VirtualDub/h/vd2/system/refcount.h | 694 +- .../VirtualDub/h/vd2/system/registry.h | 310 +- .../VirtualDub/h/vd2/system/registrymemory.h | 162 +- .../h/vd2/system/source/registrymemory.cpp | 1338 +- .../VirtualDub/h/vd2/system/strutil.h | 120 +- src/thirdparty/VirtualDub/h/vd2/system/text.h | 120 +- .../VirtualDub/h/vd2/system/thread.h | 570 +- .../VirtualDub/h/vd2/system/thunk.h | 152 +- src/thirdparty/VirtualDub/h/vd2/system/tls.h | 76 +- .../VirtualDub/h/vd2/system/unknown.h | 154 +- .../VirtualDub/h/vd2/system/vdalloc.h | 380 +- .../VirtualDub/h/vd2/system/vdstl.h | 3528 +- .../VirtualDub/h/vd2/system/vdstl_hash.h | 280 +- .../VirtualDub/h/vd2/system/vdstl_hashmap.h | 1208 +- .../VirtualDub/h/vd2/system/vdstl_hashset.h | 1052 +- .../VirtualDub/h/vd2/system/vdstl_hashtable.h | 730 +- .../VirtualDub/h/vd2/system/vdstl_vector.h | 1212 +- .../VirtualDub/h/vd2/system/vdtypes.h | 898 +- .../VirtualDub/h/vd2/system/vectors.h | 1232 +- .../VirtualDub/h/vd2/system/vectors_float.h | 414 +- .../VirtualDub/h/vd2/system/vectors_int.h | 366 +- .../VirtualDub/h/vd2/system/w32assist.h | 214 +- .../VirtualDub/h/vd2/system/win32/intrin.h | 112 +- .../h/vd2/system/win32/miniwindows.h | 122 +- src/thirdparty/VirtualDub/system/h/stdafx.h | 72 +- .../VirtualDub/system/source/Error.cpp | 298 +- .../VirtualDub/system/source/Fraction.cpp | 654 +- .../VirtualDub/system/source/VDNamespace.cpp | 506 +- .../VirtualDub/system/source/VDScheduler.cpp | 644 +- .../VirtualDub/system/source/VDString.cpp | 592 +- .../VirtualDub/system/source/a64_cpuaccel.asm | 84 +- .../VirtualDub/system/source/a64_fraction.asm | 116 +- .../VirtualDub/system/source/a64_int128.asm | 146 +- .../VirtualDub/system/source/a64_thunk.asm | 116 +- .../VirtualDub/system/source/a_memory.asm | 394 +- .../VirtualDub/system/source/a_thunk.asm | 126 +- .../VirtualDub/system/source/cache.cpp | 844 +- .../VirtualDub/system/source/cmdline.cpp | 548 +- .../VirtualDub/system/source/cpuaccel.cpp | 376 +- .../VirtualDub/system/source/debug.cpp | 580 +- .../VirtualDub/system/source/debugx86.cpp | 312 +- .../VirtualDub/system/source/event.cpp | 176 +- .../VirtualDub/system/source/file.cpp | 860 +- .../VirtualDub/system/source/fileasync.cpp | 1850 +- .../VirtualDub/system/source/filewatcher.cpp | 314 +- .../VirtualDub/system/source/halffloat.cpp | 158 +- .../VirtualDub/system/source/hash.cpp | 246 +- .../VirtualDub/system/source/int128.cpp | 1330 +- .../VirtualDub/system/source/list.cpp | 194 +- .../VirtualDub/system/source/math.cpp | 370 +- .../VirtualDub/system/source/memory.cpp | 944 +- .../VirtualDub/system/source/progress.cpp | 70 +- .../VirtualDub/system/source/protscope.cpp | 74 +- .../VirtualDub/system/source/refcount.cpp | 58 +- .../VirtualDub/system/source/registry.cpp | 960 +- .../VirtualDub/system/source/stdaccel.cpp | 84 +- .../VirtualDub/system/source/stdafx.cpp | 92 +- .../VirtualDub/system/source/strutil.cpp | 198 +- .../VirtualDub/system/source/text.cpp | 1306 +- .../VirtualDub/system/source/thread.cpp | 624 +- .../VirtualDub/system/source/thunk.cpp | 616 +- .../VirtualDub/system/source/tls.cpp | 86 +- .../VirtualDub/system/source/vdstl.cpp | 74 +- .../VirtualDub/system/source/vdstl_hash.cpp | 218 +- .../system/source/vdstl_hashtable.cpp | 164 +- .../VirtualDub/system/source/vectors.cpp | 166 +- .../VirtualDub/system/source/w32assist.cpp | 1420 +- .../VirtualDub/system/system.vcxproj | 354 +- .../VirtualDub/system/system.vcxproj.filters | 662 +- .../XeScrollBar/XeScrollBarBase.cpp | 2858 +- src/thirdparty/XeScrollBar/xescrollbarbase.h | 798 +- src/thirdparty/lcms2/lcms2.vcxproj | 174 +- src/thirdparty/lcms2/lcms2.vcxproj.filters | 212 +- src/thirdparty/sizecbar/scbarcf.cpp | 468 +- src/thirdparty/sizecbar/scbarcf.h | 156 +- src/thirdparty/sizecbar/scbarg.cpp | 510 +- src/thirdparty/sizecbar/scbarg.h | 236 +- src/thirdparty/sizecbar/sizecbar.cpp | 2926 +- src/thirdparty/sizecbar/sizecbar.h | 514 +- src/thirdparty/sizecbar/sizecbar.vcxproj | 132 +- .../sizecbar/sizecbar.vcxproj.filters | 80 +- src/thirdparty/sizecbar/stdafx.cpp | 44 +- src/thirdparty/sizecbar/stdafx.h | 66 +- src/thirdparty/unrar/acknow.txt | 118 +- src/thirdparty/unrar/dll.def | 26 +- src/thirdparty/unrar/dll.rc | 46 +- src/thirdparty/unrar/unrar.vcxproj | 344 +- src/thirdparty/unrar/unrar.vcxproj.filters | 728 +- src/thirdparty/zlib/zlib.vcxproj | 166 +- src/thirdparty/zlib/zlib.vcxproj.filters | 200 +- update_version.bat | 102 +- 1083 files changed, 328491 insertions(+), 328050 deletions(-) create mode 100644 src/mpc-hc/PPageToolBar.cpp create mode 100644 src/mpc-hc/PPageToolBar.h diff --git a/build.bat b/build.bat index fa2d8feb75f..455b1368b2d 100755 --- a/build.bat +++ b/build.bat @@ -1,522 +1,522 @@ -@ECHO OFF -REM (C) 2009-2019 see Authors.txt -REM -REM This file is part of MPC-HC. -REM -REM MPC-HC is free software; you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation; either version 3 of the License, or -REM (at your option) any later version. -REM -REM MPC-HC is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with this program. If not, see . - - -SETLOCAL EnableDelayedExpansion - -SET ARG=/%* -SET ARG=%ARG:/=% -SET ARG=%ARG:-=% -SET ARGB=0 -SET ARGBC=0 -SET ARGC=0 -SET ARGPL=0 -SET INPUT=0 -SET VALID=0 - -IF /I "%ARG%" == "?" GOTO ShowHelp - -FOR %%G IN (%ARG%) DO ( - IF /I "%%G" == "help" GOTO ShowHelp - IF /I "%%G" == "GetVersion" ENDLOCAL & SET "FORCE_VER_UPDATE=True" & CALL "%~dp0common.bat" :SubGetVersion & EXIT /B - IF /I "%%G" == "Build" SET "BUILDTYPE=Build" & SET /A ARGB+=1 - IF /I "%%G" == "Clean" SET "BUILDTYPE=Clean" & SET /A ARGB+=1 & SET "NO_INST=True" & SET /A "NO_ZIP=True" & SET "NO_LAV=True" - IF /I "%%G" == "Rebuild" SET "BUILDTYPE=Rebuild" & SET /A ARGB+=1 & SET "NO_LAV=True" - IF /I "%%G" == "Both" SET "PPLATFORM=Both" & SET /A ARGPL+=1 - IF /I "%%G" == "Win32" SET "PPLATFORM=Win32" & SET /A ARGPL+=1 - IF /I "%%G" == "x86" SET "PPLATFORM=Win32" & SET /A ARGPL+=1 - IF /I "%%G" == "x64" SET "PPLATFORM=x64" & SET /A ARGPL+=1 - IF /I "%%G" == "All" SET "CONFIG=All" & SET /A ARGC+=1 & SET "NO_LITE=True" - IF /I "%%G" == "Main" SET "CONFIG=Main" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" - IF /I "%%G" == "Filters" SET "CONFIG=Filters" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_LITE=True" - IF /I "%%G" == "Filter" SET "CONFIG=Filters" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_LITE=True" - IF /I "%%G" == "API" SET "CONFIG=API" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "MPCHC" SET "CONFIG=MPCHC" & SET /A ARGC+=1 - IF /I "%%G" == "MPC-HC" SET "CONFIG=MPCHC" & SET /A ARGC+=1 - IF /I "%%G" == "Resources" SET "CONFIG=Resources" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "MPCIconLib" SET "CONFIG=IconLib" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "IconLib" SET "CONFIG=IconLib" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "Translations" SET "CONFIG=Translation" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "Debug" SET "BUILDCFG=Debug" & SET /A ARGBC+=1 & SET "NO_INST=True" - IF /I "%%G" == "Release" SET "BUILDCFG=Release" & SET /A ARGBC+=1 - IF /I "%%G" == "Packages" SET "PACKAGES=True" & SET /A VALID+=1 - IF /I "%%G" == "Installer" SET "INSTALLER=True" & SET /A VALID+=1 - IF /I "%%G" == "7z" SET "ZIP=True" & SET /A VALID+=1 - IF /I "%%G" == "Lite" SET "MPCHC_LITE=True" & SET /A VALID+=1 - IF /I "%%G" == "LAVFilters" SET "CLEAN=LAVFilters" & SET /A VALID+=1 - IF /I "%%G" == "Silent" SET "SILENT=True" & SET /A VALID+=1 - IF /I "%%G" == "Nocolors" SET "NOCOLORS=True" & SET /A VALID+=1 - IF /I "%%G" == "Analyze" SET "ANALYZE=True" & SET /A VALID+=1 - IF /I "%%G" == "MINGWLIB" ENDLOCAL & SET "FORCE_MINGW_UPDATE=True" & CALL "%~dp0common.bat" :SubMINGWLIB & EXIT /B -) - -SET "FILE_DIR=%~dp0" -PUSHD "%FILE_DIR%" - -SET "COMMON=%FILE_DIR%\common.bat" - -CALL "%COMMON%" :SubPreBuild -IF %ERRORLEVEL% NEQ 0 GOTO MissingVar - -FOR %%G IN (%*) DO SET /A INPUT+=1 -SET /A VALID+=%ARGB%+%ARGPL%+%ARGC%+%ARGBC% -IF %VALID% NEQ %INPUT% GOTO UnsupportedSwitch - -IF %ARGB% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGB% == 0 (SET "BUILDTYPE=Build") -IF %ARGPL% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGPL% == 0 (SET "PPLATFORM=Both") -IF %ARGC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGC% == 0 (SET "CONFIG=MPCHC") -IF %ARGBC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGBC% == 0 (SET "BUILDCFG=Release") - -IF /I "%PACKAGES%" == "True" SET "INSTALLER=True" & SET "ZIP=True" - -IF /I "%INSTALLER%" == "True" IF "%NO_INST%" == "True" GOTO UnsupportedSwitch -IF /I "%ZIP%" == "True" IF "%NO_ZIP%" == "True" GOTO UnsupportedSwitch -IF /I "%MPCHC_LITE%" == "True" IF "%NO_LITE%" == "True" GOTO UnsupportedSwitch -IF /I "%CLEAN%" == "LAVFilters" IF "%NO_LAV%" == "True" GOTO UnsupportedSwitch - -IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath -IF NOT EXIST "!MPCHC_VS_PATH!" GOTO MissingVar -SET "TOOLSET=!MPCHC_VS_PATH!\Common7\Tools\vsdevcmd" -SET "BIN_DIR=bin" -IF NOT EXIST "%TOOLSET%" GOTO MissingVar - -IF EXIST "%FILE_DIR%signinfo.txt" ( - IF /I "%INSTALLER%" == "True" SET "SIGN=True" - IF /I "%ZIP%" == "True" SET "SIGN=True" -) - -REM Set version for DX libraries -CALL "%COMMON%" :SubParseConfig - -:Start -REM Check if the %LOG_DIR% folder exists otherwise MSBuild will fail -SET "LOG_DIR=%BIN_DIR%\logs" -IF NOT EXIST "%LOG_DIR%" MD "%LOG_DIR%" - -IF DEFINED MPCHC_LITE SET "BUILDCFG=%BUILDCFG% Lite" - -SET "MSBUILD_SWITCHES=/nologo /consoleloggerparameters:Verbosity=minimal /maxcpucount /nodeReuse:true" - -SET START_TIME=%TIME% -SET START_DATE=%DATE% - -IF /I "%PPLATFORM%" == "Both" ( - SET "PPLATFORM=Win32" & CALL :Main - SET "PPLATFORM=x64" & CALL :Main -) ELSE ( - CALL :Main -) -GOTO End - - -:Main -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%PPLATFORM%" == "x64" ( - SET "LAVFILTERSDIR=LAVFilters64" -) ELSE ( - SET "LAVFILTERSDIR=LAVFilters" -) - -IF /I "%CLEAN%" == "LAVFilters" CALL "src\thirdparty\LAVFilters\build_lavfilters.bat" Clean %PPLATFORM% %BUILDCFG% %COMPILER% -IF %ERRORLEVEL% NEQ 0 ENDLOCAL & EXIT /B - -IF /I "%PPLATFORM%" == "Win32" (SET ARCH=x86) ELSE (SET ARCH=amd64) -CALL "%TOOLSET%" -no_logo -arch=%ARCH% -winsdk=%MPCHC_WINSDK_VER% -IF %ERRORLEVEL% NEQ 0 GOTO MissingVar - -IF /I "%CONFIG%" == "Filters" ( - CALL :SubFilters %PPLATFORM% - IF /I "%ZIP%" == "True" CALL :SubCreatePackages Filters %PPLATFORM% - EXIT /B -) - -IF /I "%CONFIG%" == "IconLib" ( - CALL :SubMPCIconLib %PPLATFORM% - EXIT /B -) - -IF /I "%CONFIG%" == "Translation" ( - CALL :SubMPCRresources %PPLATFORM% - EXIT /B -) - -IF /I "%CONFIG%" == "API" ( - CALL :SubMPCTestAPI %PPLATFORM% - EXIT /B -) - -IF /I "%CONFIG%" NEQ "Resources" CALL :SubMPCHC %PPLATFORM% -IF /I "%CONFIG%" NEQ "Main" CALL :SubResources %PPLATFORM% - -IF /I "%INSTALLER%" == "True" CALL :SubCreateInstaller %PPLATFORM% -IF /I "%ZIP%" == "True" CALL :SubCreatePackages MPC-HC %PPLATFORM% - -IF /I "%CONFIG%" == "All" ( - CALL :SubFilters %PPLATFORM% - IF /I "%ZIP%" == "True" CALL :SubCreatePackages Filters %PPLATFORM% -) -EXIT /B - - -:End -IF %ERRORLEVEL% NEQ 0 EXIT /B -TITLE Compiling MPC-HC %COMPILER% [FINISHED] -SET END_TIME=%TIME% -CALL "%COMMON%" :SubGetDuration -CALL "%COMMON%" :SubMsg "INFO" "Compilation started on %START_DATE%-%START_TIME% and completed on %DATE%-%END_TIME% [%DURATION%]" -ENDLOCAL -EXIT /B - - -:SubFilters -IF %ERRORLEVEL% NEQ 0 EXIT /B - -TITLE Compiling MPC-HC Filters %COMPILER% - %BUILDCFG% Filter^|%1... -CALL "update_version.bat" - -MSBuild.exe mpc-hc.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration="%BUILDCFG% Filter";Platform=%1^ - /flp1:LogFile=%LOG_DIR%\filters_errors_%BUILDCFG%_%1.log;errorsonly;Verbosity=diagnostic^ - /flp2:LogFile=%LOG_DIR%\filters_warnings_%BUILDCFG%_%1.log;warningsonly;Verbosity=diagnostic -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "mpc-hc.sln %BUILDCFG% Filter %1 - Compilation failed!" - EXIT /B -) ELSE ( - CALL "%COMMON%" :SubMsg "INFO" "mpc-hc.sln %BUILDCFG% Filter %1 compiled successfully" -) -IF /I "%SIGN%" == "True" CALL :SubSign Filters *.ax -IF /I "%SIGN%" == "True" CALL :SubSign Filters VSFilter.dll -EXIT /B - - -:SubMPCHC -IF %ERRORLEVEL% NEQ 0 EXIT /B - -TITLE Compiling MPC-HC %COMPILER% - %BUILDCFG%^|%1... -CALL "update_version.bat" - -MSBuild.exe mpc-hc.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration="%BUILDCFG%";Platform=%1^ - /flp1:LogFile="%LOG_DIR%\mpc-hc_errors_%BUILDCFG%_%1.log";errorsonly;Verbosity=diagnostic^ - /flp2:LogFile="%LOG_DIR%\mpc-hc_warnings_%BUILDCFG%_%1.log";warningsonly;Verbosity=diagnostic -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "mpc-hc.sln %BUILDCFG% %1 - Compilation failed!" - EXIT /B -) ELSE ( - CALL "%COMMON%" :SubMsg "INFO" "mpc-hc.sln %BUILDCFG% %1 compiled successfully" -) -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpc-hc*.exe -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC *.dll %LAVFILTERSDIR% -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC *.ax %LAVFILTERSDIR% -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC CrashReporterDialog.dll CrashReporter - -EXIT /B - - -:SubResources -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%BUILDCFG%" == "Debug" ( - CALL "%COMMON%" :SubMsg "WARNING" "/debug was used, resources will not be built" - EXIT /B -) - -CALL :SubMPCIconLib %1 - -IF DEFINED MPCHC_LITE ( - CALL "%COMMON%" :SubMsg "WARNING" "/lite was used, translations will not be built" - EXIT /B -) - -CALL :SubMPCRresources %1 -EXIT /B - - -:SubMPCIconLib -IF %ERRORLEVEL% NEQ 0 EXIT /B - -TITLE Compiling mpciconlib %COMPILER% - Release^|%1... -MSBuild.exe mpciconlib.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration=Release;Platform=%1 -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "mpciconlib.sln %1 - Compilation failed!" - EXIT /B -) ELSE ( - CALL "%COMMON%" :SubMsg "INFO" "mpciconlib.sln %1 compiled successfully" -) -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpciconlib.dll - -IF /I "%1" == "Win32" (SET "VS_OUT_DIR=mpc-hc_x86") ELSE (SET "VS_OUT_DIR=mpc-hc_x64") -IF DEFINED MPCHC_LITE ( - PUSHD "%BIN_DIR%" - COPY /Y /V "%VS_OUT_DIR%\mpciconlib.dll" "%VS_OUT_DIR% Lite" >NUL - POPD -) - -EXIT /B - - -:SubMPCRresources -IF %ERRORLEVEL% NEQ 0 EXIT /B - -TITLE Compiling mpcresources %COMPILER%... -MSBuild.exe mpcresources.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration="Release";Platform=%1 -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpcresources.??.dll Lang -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpcresources.??_??.dll Lang -EXIT /B - - -:SubMPCTestAPI -IF %ERRORLEVEL% NEQ 0 EXIT /B - -PUSHD "src\MPCTestAPI" -TITLE Compiling MPCTestAPI %COMPILER% - %BUILDCFG%^|%1... -MSBuild.exe MPCTestAPI.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration=%BUILDCFG%;Platform=%1 -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "MPCTestAPI.sln %1 - Compilation failed!" - EXIT /B -) ELSE ( - CALL "%COMMON%" :SubMsg "INFO" "MPCTestAPI.sln %1 compiled successfully" -) -POPD -EXIT /B - - -:SubSign -IF %ERRORLEVEL% NEQ 0 EXIT /B -REM %1 is Filters or MPC-HC -REM %2 is name of the file to sign -REM %3 is the subfolder - -IF /I "%PPLATFORM%" == "Win32" PUSHD "%BIN_DIR%\%~1_x86\%3" -IF /I "%PPLATFORM%" == "x64" PUSHD "%BIN_DIR%\%~1_x64\%3" - -FOR /F "delims=" %%A IN ('DIR "%2" /b') DO ( - CALL "%FILE_DIR%contrib\sign.bat" "%%A" || (CALL "%COMMON%" :SubMsg "ERROR" "Problem signing %%A" & GOTO Break) -) -CALL "%COMMON%" :SubMsg "INFO" "%2 signed successfully." - -:Break -POPD -EXIT /B - - -:SubCopyDXDll -REM SubCopyDXDll skipped -EXIT /B -IF /I "%BUILDCFG%" == "Debug" EXIT /B -PUSHD "%BIN_DIR%" -COPY /Y /V "%WindowsSdkDir%\Redist\D3D\%~1\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" "mpc-hc_%~1%~2" >NUL -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Problem when copying %WindowsSdkDir%\Redist\D3D\%~1\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" & EXIT /B -EXPAND "%DXSDK_DIR%\Redist\Jun2010_d3dx9_%MPC_DX_SDK_NUMBER%_%~1.cab" -F:d3dx9_%MPC_DX_SDK_NUMBER%.dll "mpc-hc_%~1%~2" -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Problem when extracting Jun2010_d3dx9_%MPC_DX_SDK_NUMBER%_%~1.cab" & EXIT /B -POPD -EXIT /B - - -:SubCreateInstaller -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%~1" == "x64" ( - SET MPCHC_INNO_DEF=%MPCHC_INNO_DEF% /Dx64Build - SET MPCHC_COPY_DX_DLL_ARGS=x64 -) ELSE SET MPCHC_COPY_DX_DLL_ARGS=x86 - - -IF DEFINED MPCHC_LITE ( - SET MPCHC_INNO_DEF=%MPCHC_INNO_DEF% /DMPCHC_LITE - SET MPCHC_COPY_DX_DLL_ARGS=%MPCHC_COPY_DX_DLL_ARGS% " Lite" -) - -CALL :SubCopyDXDll %MPCHC_COPY_DX_DLL_ARGS% - -CALL "%COMMON%" :SubDetectInnoSetup - -IF NOT DEFINED InnoSetupPath ( - CALL "%COMMON%" :SubMsg "WARNING" "Inno Setup wasn't found, the %1 installer wasn't built" - EXIT /B -) - -TITLE Compiling %1 %COMPILER% installer... -"%InnoSetupPath%" /SMySignTool="cmd /c "%FILE_DIR%contrib\sign.bat" $f" /Q /O"%BIN_DIR%"^ - "distrib\mpc-hc_setup.iss" %MPCHC_INNO_DEF% -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B -CALL "%COMMON%" :SubMsg "INFO" "%1 installer successfully built" - -EXIT /B - - -:SubCreatePackages -IF %ERRORLEVEL% NEQ 0 EXIT /B - -CALL "%COMMON%" :SubDetectSevenzipPath -CALL "%COMMON%" :SubGetVersion -CALL "%COMMON%" :SubMINGWLIB - -IF NOT DEFINED SEVENZIP ( - CALL "%COMMON%" :SubMsg "WARNING" "7-Zip wasn't found, the %1 %2 package wasn't built" - EXIT /B -) - -IF /I "%~1" == "Filters" (SET "NAME=MPC-HC_standalone_filters") ELSE (SET "NAME=MPC-HC") -IF /I "%~2" == "Win32" ( - SET ARCH=x86 -) ELSE ( - SET ARCH=x64 -) - -IF DEFINED MPCHC_LITE ( - CALL :SubCopyDXDll %ARCH% " Lite" -) ELSE IF /I "%NAME%" == "MPC-HC" ( - CALL :SubCopyDXDll %ARCH% -) - -PUSHD "%BIN_DIR%" - -SET "VS_OUT_DIR=%~1_%ARCH%" -SET "PCKG_NAME=%NAME%.%MPCHC_VER%.%ARCH%" -IF DEFINED MPCHC_LITE ( - SET "VS_OUT_DIR=%VS_OUT_DIR% Lite" - SET "PCKG_NAME=%PCKG_NAME%.Lite" -) -IF /I "%BUILDCFG%" == "Debug" ( - SET "PCKG_NAME=%PCKG_NAME%.dbg" - SET "VS_OUT_DIR=%VS_OUT_DIR%_Debug" -) - -IF EXIST "%PCKG_NAME%.7z" DEL "%PCKG_NAME%.7z" -IF EXIST "%PCKG_NAME%.pdb.7z" DEL "%PCKG_NAME%.pdb.7z" -IF EXIST "%PCKG_NAME%" RD /Q /S "%PCKG_NAME%" - -SET "PDB_FILES=*.pdb" -IF NOT DEFINED MPCHC_LITE (SET "PDB_FILES=%PDB_FILES% %LAVFILTERSDIR%\*.pdb") - -REM Compress the pdb file for mpc-hc only -IF /I "%NAME%" == "MPC-HC" ( - PUSHD "%VS_OUT_DIR%" - TITLE Creating archive %PCKG_NAME%.pdb.7z... - START "7z" /B /WAIT "%SEVENZIP%" a -t7z "%PCKG_NAME%.pdb.7z" %PDB_FILES% -m0=LZMA2^ - -mmt=%NUMBER_OF_PROCESSORS% -mx9 -ms=on - IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Unable to create %PCKG_NAME%.pdb.7z!" & EXIT /B - CALL "%COMMON%" :SubMsg "INFO" "%PCKG_NAME%.pdb.7z successfully created" - IF EXIST "%PCKG_NAME%.pdb.7z" MOVE /Y "%PCKG_NAME%.pdb.7z" ".." >NUL - POPD -) - -TITLE Copying %PCKG_NAME%... -IF NOT EXIST "%PCKG_NAME%" MD "%PCKG_NAME%" - -IF /I "%NAME%" == "MPC-HC" ( - IF NOT DEFINED MPCHC_LITE ( - IF /I "%BUILDCFG%" NEQ "Debug" ( - IF NOT EXIST "%PCKG_NAME%\Lang" MD "%PCKG_NAME%\Lang" - ) - IF NOT EXIST "%PCKG_NAME%\%LAVFILTERSDIR%" MD "%PCKG_NAME%\%LAVFILTERSDIR%" - ) - IF /I "%ARCH%" == "x64" ( - COPY /Y /V "%VS_OUT_DIR%\mpc-hc64.exe" "%PCKG_NAME%\mpc-hc64.exe" >NUL - ) ELSE ( - COPY /Y /V "%VS_OUT_DIR%\mpc-hc.exe" "%PCKG_NAME%\mpc-hc.exe" >NUL - ) - COPY /Y /V "%VS_OUT_DIR%\mpciconlib.dll" "%PCKG_NAME%\*.dll" >NUL - IF NOT DEFINED MPCHC_LITE ( - COPY /Y /V "%VS_OUT_DIR%\Lang\mpcresources.??.dll" "%PCKG_NAME%\Lang\" >NUL - COPY /Y /V "%VS_OUT_DIR%\Lang\mpcresources.??_??.dll" "%PCKG_NAME%\Lang\" >NUL - COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.ax" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL - COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.dll" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL - COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.manifest" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL - ) - COPY /Y /V "%VS_OUT_DIR%\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" "%PCKG_NAME%\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" >NUL - COPY /Y /V "%VS_OUT_DIR%\d3dx9_%MPC_DX_SDK_NUMBER%.dll" "%PCKG_NAME%\d3dx9_%MPC_DX_SDK_NUMBER%.dll" >NUL - IF NOT EXIST "%PCKG_NAME%\Shaders" MD "%PCKG_NAME%\Shaders" - COPY /Y /V "..\src\mpc-hc\res\shaders\dx9\*.hlsl" "%PCKG_NAME%\Shaders" >NUL - IF NOT EXIST "%PCKG_NAME%\Shaders11" MD "%PCKG_NAME%\Shaders11" - COPY /Y /V "..\src\mpc-hc\res\shaders\dx11\*.hlsl" "%PCKG_NAME%\Shaders11" >NUL - IF /I "%BUILDCFG%" NEQ "Debug" IF /I "%BUILDCFG%" NEQ "Debug Lite" IF EXIST "%VS_OUT_DIR%\CrashReporter\crashrpt.dll" ( - IF NOT EXIST "%PCKG_NAME%\CrashReporter" MD "%PCKG_NAME%\CrashReporter" - COPY /Y /V "%VS_OUT_DIR%\CrashReporter\crashrpt.dll" "%PCKG_NAME%\CrashReporter" - COPY /Y /V "%VS_OUT_DIR%\CrashReporter\dbghelp.dll" "%PCKG_NAME%\CrashReporter" - COPY /Y /V "%VS_OUT_DIR%\CrashReporter\sendrpt.exe" "%PCKG_NAME%\CrashReporter" - COPY /Y /V "%VS_OUT_DIR%\CrashReporter\CrashReporterDialog.dll" "%PCKG_NAME%\CrashReporter" - ) -) ELSE ( - COPY /Y /V "%VS_OUT_DIR%\*.ax" "%PCKG_NAME%\*.ax" >NUL - COPY /Y /V "%VS_OUT_DIR%\VSFilter.dll" "%PCKG_NAME%\VSFilter.dll" >NUL -) - -COPY /Y /V "..\COPYING.txt" "%PCKG_NAME%" >NUL - -TITLE Creating archive %PCKG_NAME%.7z... -START "7z" /B /WAIT "%SEVENZIP%" a -t7z "%PCKG_NAME%.7z" "%PCKG_NAME%" -m0=LZMA2^ - -mmt=%NUMBER_OF_PROCESSORS% -mx9 -ms=on -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Unable to create %PCKG_NAME%.7z!" & EXIT /B -CALL "%COMMON%" :SubMsg "INFO" "%PCKG_NAME%.7z successfully created" - -IF EXIST "%PCKG_NAME%" RD /Q /S "%PCKG_NAME%" - -POPD -EXIT /B - - -:ShowHelp -TITLE %~nx0 Help -ECHO. -ECHO Usage: -ECHO %~nx0 [Clean^|Build^|Rebuild] [x86^|x64^|Both] [Main^|Resources^|MPCHC^|IconLib^|Translations^|Filters^|API^|All] [Debug^|Release] [Lite] [Packages^|Installer^|7z] [LAVFilters] [Analyze] -ECHO. -ECHO Notes: You can also prefix the commands with "-", "--" or "/". -ECHO Debug only applies to mpc-hc.sln. -ECHO The arguments are not case sensitive and can be ommitted. -ECHO. & ECHO. -ECHO Executing %~nx0 without any arguments will use the default ones: -ECHO "%~nx0 Build Both MPCHC Release" -ECHO. & ECHO. -ECHO Examples: -ECHO %~nx0 x86 Resources -Builds the x86 resources -ECHO %~nx0 Resources -Builds both x86 and x64 resources -ECHO %~nx0 x86 -Builds x86 Main exe and the x86 resources -ECHO %~nx0 x86 Debug -Builds x86 Main Debug exe and x86 resources -ECHO %~nx0 x86 Filters -Builds x86 Filters -ECHO %~nx0 x86 All -Builds x86 Main exe, x86 Filters and the x86 resources -ECHO %~nx0 x86 Packages -Builds x86 Main exe, x86 resources and creates the installer and the .7z package -ECHO %~nx0 x64 LAVFilters 7z -Rebuilds LAVFilters, builds x64 Main exe, x64 resources and creates the .7z package -ECHO. -ENDLOCAL -EXIT /B - - -:MissingVar -TITLE Compiling MPC-HC %COMPILER% [ERROR] -ECHO Not all build dependencies were found. -ECHO. -ECHO See "docs\Compilation.md" for more information. -CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B - - -:UnsupportedSwitch -ECHO. -ECHO Unsupported commandline switch! -ECHO. -ECHO "%~nx0 %*" -ECHO. -ECHO Run "%~nx0 help" for details about the commandline switches. -CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B +@ECHO OFF +REM (C) 2009-2019 see Authors.txt +REM +REM This file is part of MPC-HC. +REM +REM MPC-HC is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation; either version 3 of the License, or +REM (at your option) any later version. +REM +REM MPC-HC is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with this program. If not, see . + + +SETLOCAL EnableDelayedExpansion + +SET ARG=/%* +SET ARG=%ARG:/=% +SET ARG=%ARG:-=% +SET ARGB=0 +SET ARGBC=0 +SET ARGC=0 +SET ARGPL=0 +SET INPUT=0 +SET VALID=0 + +IF /I "%ARG%" == "?" GOTO ShowHelp + +FOR %%G IN (%ARG%) DO ( + IF /I "%%G" == "help" GOTO ShowHelp + IF /I "%%G" == "GetVersion" ENDLOCAL & SET "FORCE_VER_UPDATE=True" & CALL "%~dp0common.bat" :SubGetVersion & EXIT /B + IF /I "%%G" == "Build" SET "BUILDTYPE=Build" & SET /A ARGB+=1 + IF /I "%%G" == "Clean" SET "BUILDTYPE=Clean" & SET /A ARGB+=1 & SET "NO_INST=True" & SET /A "NO_ZIP=True" & SET "NO_LAV=True" + IF /I "%%G" == "Rebuild" SET "BUILDTYPE=Rebuild" & SET /A ARGB+=1 & SET "NO_LAV=True" + IF /I "%%G" == "Both" SET "PPLATFORM=Both" & SET /A ARGPL+=1 + IF /I "%%G" == "Win32" SET "PPLATFORM=Win32" & SET /A ARGPL+=1 + IF /I "%%G" == "x86" SET "PPLATFORM=Win32" & SET /A ARGPL+=1 + IF /I "%%G" == "x64" SET "PPLATFORM=x64" & SET /A ARGPL+=1 + IF /I "%%G" == "All" SET "CONFIG=All" & SET /A ARGC+=1 & SET "NO_LITE=True" + IF /I "%%G" == "Main" SET "CONFIG=Main" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" + IF /I "%%G" == "Filters" SET "CONFIG=Filters" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_LITE=True" + IF /I "%%G" == "Filter" SET "CONFIG=Filters" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_LITE=True" + IF /I "%%G" == "API" SET "CONFIG=API" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "MPCHC" SET "CONFIG=MPCHC" & SET /A ARGC+=1 + IF /I "%%G" == "MPC-HC" SET "CONFIG=MPCHC" & SET /A ARGC+=1 + IF /I "%%G" == "Resources" SET "CONFIG=Resources" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "MPCIconLib" SET "CONFIG=IconLib" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "IconLib" SET "CONFIG=IconLib" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "Translations" SET "CONFIG=Translation" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "Debug" SET "BUILDCFG=Debug" & SET /A ARGBC+=1 & SET "NO_INST=True" + IF /I "%%G" == "Release" SET "BUILDCFG=Release" & SET /A ARGBC+=1 + IF /I "%%G" == "Packages" SET "PACKAGES=True" & SET /A VALID+=1 + IF /I "%%G" == "Installer" SET "INSTALLER=True" & SET /A VALID+=1 + IF /I "%%G" == "7z" SET "ZIP=True" & SET /A VALID+=1 + IF /I "%%G" == "Lite" SET "MPCHC_LITE=True" & SET /A VALID+=1 + IF /I "%%G" == "LAVFilters" SET "CLEAN=LAVFilters" & SET /A VALID+=1 + IF /I "%%G" == "Silent" SET "SILENT=True" & SET /A VALID+=1 + IF /I "%%G" == "Nocolors" SET "NOCOLORS=True" & SET /A VALID+=1 + IF /I "%%G" == "Analyze" SET "ANALYZE=True" & SET /A VALID+=1 + IF /I "%%G" == "MINGWLIB" ENDLOCAL & SET "FORCE_MINGW_UPDATE=True" & CALL "%~dp0common.bat" :SubMINGWLIB & EXIT /B +) + +SET "FILE_DIR=%~dp0" +PUSHD "%FILE_DIR%" + +SET "COMMON=%FILE_DIR%\common.bat" + +CALL "%COMMON%" :SubPreBuild +IF %ERRORLEVEL% NEQ 0 GOTO MissingVar + +FOR %%G IN (%*) DO SET /A INPUT+=1 +SET /A VALID+=%ARGB%+%ARGPL%+%ARGC%+%ARGBC% +IF %VALID% NEQ %INPUT% GOTO UnsupportedSwitch + +IF %ARGB% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGB% == 0 (SET "BUILDTYPE=Build") +IF %ARGPL% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGPL% == 0 (SET "PPLATFORM=Both") +IF %ARGC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGC% == 0 (SET "CONFIG=MPCHC") +IF %ARGBC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGBC% == 0 (SET "BUILDCFG=Release") + +IF /I "%PACKAGES%" == "True" SET "INSTALLER=True" & SET "ZIP=True" + +IF /I "%INSTALLER%" == "True" IF "%NO_INST%" == "True" GOTO UnsupportedSwitch +IF /I "%ZIP%" == "True" IF "%NO_ZIP%" == "True" GOTO UnsupportedSwitch +IF /I "%MPCHC_LITE%" == "True" IF "%NO_LITE%" == "True" GOTO UnsupportedSwitch +IF /I "%CLEAN%" == "LAVFilters" IF "%NO_LAV%" == "True" GOTO UnsupportedSwitch + +IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath +IF NOT EXIST "!MPCHC_VS_PATH!" GOTO MissingVar +SET "TOOLSET=!MPCHC_VS_PATH!\Common7\Tools\vsdevcmd" +SET "BIN_DIR=bin" +IF NOT EXIST "%TOOLSET%" GOTO MissingVar + +IF EXIST "%FILE_DIR%signinfo.txt" ( + IF /I "%INSTALLER%" == "True" SET "SIGN=True" + IF /I "%ZIP%" == "True" SET "SIGN=True" +) + +REM Set version for DX libraries +CALL "%COMMON%" :SubParseConfig + +:Start +REM Check if the %LOG_DIR% folder exists otherwise MSBuild will fail +SET "LOG_DIR=%BIN_DIR%\logs" +IF NOT EXIST "%LOG_DIR%" MD "%LOG_DIR%" + +IF DEFINED MPCHC_LITE SET "BUILDCFG=%BUILDCFG% Lite" + +SET "MSBUILD_SWITCHES=/nologo /consoleloggerparameters:Verbosity=minimal /maxcpucount /nodeReuse:true" + +SET START_TIME=%TIME% +SET START_DATE=%DATE% + +IF /I "%PPLATFORM%" == "Both" ( + SET "PPLATFORM=Win32" & CALL :Main + SET "PPLATFORM=x64" & CALL :Main +) ELSE ( + CALL :Main +) +GOTO End + + +:Main +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%PPLATFORM%" == "x64" ( + SET "LAVFILTERSDIR=LAVFilters64" +) ELSE ( + SET "LAVFILTERSDIR=LAVFilters" +) + +IF /I "%CLEAN%" == "LAVFilters" CALL "src\thirdparty\LAVFilters\build_lavfilters.bat" Clean %PPLATFORM% %BUILDCFG% %COMPILER% +IF %ERRORLEVEL% NEQ 0 ENDLOCAL & EXIT /B + +IF /I "%PPLATFORM%" == "Win32" (SET ARCH=x86) ELSE (SET ARCH=amd64) +CALL "%TOOLSET%" -no_logo -arch=%ARCH% -winsdk=%MPCHC_WINSDK_VER% +IF %ERRORLEVEL% NEQ 0 GOTO MissingVar + +IF /I "%CONFIG%" == "Filters" ( + CALL :SubFilters %PPLATFORM% + IF /I "%ZIP%" == "True" CALL :SubCreatePackages Filters %PPLATFORM% + EXIT /B +) + +IF /I "%CONFIG%" == "IconLib" ( + CALL :SubMPCIconLib %PPLATFORM% + EXIT /B +) + +IF /I "%CONFIG%" == "Translation" ( + CALL :SubMPCRresources %PPLATFORM% + EXIT /B +) + +IF /I "%CONFIG%" == "API" ( + CALL :SubMPCTestAPI %PPLATFORM% + EXIT /B +) + +IF /I "%CONFIG%" NEQ "Resources" CALL :SubMPCHC %PPLATFORM% +IF /I "%CONFIG%" NEQ "Main" CALL :SubResources %PPLATFORM% + +IF /I "%INSTALLER%" == "True" CALL :SubCreateInstaller %PPLATFORM% +IF /I "%ZIP%" == "True" CALL :SubCreatePackages MPC-HC %PPLATFORM% + +IF /I "%CONFIG%" == "All" ( + CALL :SubFilters %PPLATFORM% + IF /I "%ZIP%" == "True" CALL :SubCreatePackages Filters %PPLATFORM% +) +EXIT /B + + +:End +IF %ERRORLEVEL% NEQ 0 EXIT /B +TITLE Compiling MPC-HC %COMPILER% [FINISHED] +SET END_TIME=%TIME% +CALL "%COMMON%" :SubGetDuration +CALL "%COMMON%" :SubMsg "INFO" "Compilation started on %START_DATE%-%START_TIME% and completed on %DATE%-%END_TIME% [%DURATION%]" +ENDLOCAL +EXIT /B + + +:SubFilters +IF %ERRORLEVEL% NEQ 0 EXIT /B + +TITLE Compiling MPC-HC Filters %COMPILER% - %BUILDCFG% Filter^|%1... +CALL "update_version.bat" + +MSBuild.exe mpc-hc.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration="%BUILDCFG% Filter";Platform=%1^ + /flp1:LogFile=%LOG_DIR%\filters_errors_%BUILDCFG%_%1.log;errorsonly;Verbosity=diagnostic^ + /flp2:LogFile=%LOG_DIR%\filters_warnings_%BUILDCFG%_%1.log;warningsonly;Verbosity=diagnostic +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "mpc-hc.sln %BUILDCFG% Filter %1 - Compilation failed!" + EXIT /B +) ELSE ( + CALL "%COMMON%" :SubMsg "INFO" "mpc-hc.sln %BUILDCFG% Filter %1 compiled successfully" +) +IF /I "%SIGN%" == "True" CALL :SubSign Filters *.ax +IF /I "%SIGN%" == "True" CALL :SubSign Filters VSFilter.dll +EXIT /B + + +:SubMPCHC +IF %ERRORLEVEL% NEQ 0 EXIT /B + +TITLE Compiling MPC-HC %COMPILER% - %BUILDCFG%^|%1... +CALL "update_version.bat" + +MSBuild.exe mpc-hc.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration="%BUILDCFG%";Platform=%1^ + /flp1:LogFile="%LOG_DIR%\mpc-hc_errors_%BUILDCFG%_%1.log";errorsonly;Verbosity=diagnostic^ + /flp2:LogFile="%LOG_DIR%\mpc-hc_warnings_%BUILDCFG%_%1.log";warningsonly;Verbosity=diagnostic +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "mpc-hc.sln %BUILDCFG% %1 - Compilation failed!" + EXIT /B +) ELSE ( + CALL "%COMMON%" :SubMsg "INFO" "mpc-hc.sln %BUILDCFG% %1 compiled successfully" +) +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpc-hc*.exe +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC *.dll %LAVFILTERSDIR% +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC *.ax %LAVFILTERSDIR% +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC CrashReporterDialog.dll CrashReporter + +EXIT /B + + +:SubResources +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%BUILDCFG%" == "Debug" ( + CALL "%COMMON%" :SubMsg "WARNING" "/debug was used, resources will not be built" + EXIT /B +) + +CALL :SubMPCIconLib %1 + +IF DEFINED MPCHC_LITE ( + CALL "%COMMON%" :SubMsg "WARNING" "/lite was used, translations will not be built" + EXIT /B +) + +CALL :SubMPCRresources %1 +EXIT /B + + +:SubMPCIconLib +IF %ERRORLEVEL% NEQ 0 EXIT /B + +TITLE Compiling mpciconlib %COMPILER% - Release^|%1... +MSBuild.exe mpciconlib.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration=Release;Platform=%1 +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "mpciconlib.sln %1 - Compilation failed!" + EXIT /B +) ELSE ( + CALL "%COMMON%" :SubMsg "INFO" "mpciconlib.sln %1 compiled successfully" +) +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpciconlib.dll + +IF /I "%1" == "Win32" (SET "VS_OUT_DIR=mpc-hc_x86") ELSE (SET "VS_OUT_DIR=mpc-hc_x64") +IF DEFINED MPCHC_LITE ( + PUSHD "%BIN_DIR%" + COPY /Y /V "%VS_OUT_DIR%\mpciconlib.dll" "%VS_OUT_DIR% Lite" >NUL + POPD +) + +EXIT /B + + +:SubMPCRresources +IF %ERRORLEVEL% NEQ 0 EXIT /B + +TITLE Compiling mpcresources %COMPILER%... +MSBuild.exe mpcresources.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration="Release";Platform=%1 +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpcresources.??.dll Lang +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpcresources.??_??.dll Lang +EXIT /B + + +:SubMPCTestAPI +IF %ERRORLEVEL% NEQ 0 EXIT /B + +PUSHD "src\MPCTestAPI" +TITLE Compiling MPCTestAPI %COMPILER% - %BUILDCFG%^|%1... +MSBuild.exe MPCTestAPI.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration=%BUILDCFG%;Platform=%1 +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "MPCTestAPI.sln %1 - Compilation failed!" + EXIT /B +) ELSE ( + CALL "%COMMON%" :SubMsg "INFO" "MPCTestAPI.sln %1 compiled successfully" +) +POPD +EXIT /B + + +:SubSign +IF %ERRORLEVEL% NEQ 0 EXIT /B +REM %1 is Filters or MPC-HC +REM %2 is name of the file to sign +REM %3 is the subfolder + +IF /I "%PPLATFORM%" == "Win32" PUSHD "%BIN_DIR%\%~1_x86\%3" +IF /I "%PPLATFORM%" == "x64" PUSHD "%BIN_DIR%\%~1_x64\%3" + +FOR /F "delims=" %%A IN ('DIR "%2" /b') DO ( + CALL "%FILE_DIR%contrib\sign.bat" "%%A" || (CALL "%COMMON%" :SubMsg "ERROR" "Problem signing %%A" & GOTO Break) +) +CALL "%COMMON%" :SubMsg "INFO" "%2 signed successfully." + +:Break +POPD +EXIT /B + + +:SubCopyDXDll +REM SubCopyDXDll skipped +EXIT /B +IF /I "%BUILDCFG%" == "Debug" EXIT /B +PUSHD "%BIN_DIR%" +COPY /Y /V "%WindowsSdkDir%\Redist\D3D\%~1\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" "mpc-hc_%~1%~2" >NUL +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Problem when copying %WindowsSdkDir%\Redist\D3D\%~1\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" & EXIT /B +EXPAND "%DXSDK_DIR%\Redist\Jun2010_d3dx9_%MPC_DX_SDK_NUMBER%_%~1.cab" -F:d3dx9_%MPC_DX_SDK_NUMBER%.dll "mpc-hc_%~1%~2" +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Problem when extracting Jun2010_d3dx9_%MPC_DX_SDK_NUMBER%_%~1.cab" & EXIT /B +POPD +EXIT /B + + +:SubCreateInstaller +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%~1" == "x64" ( + SET MPCHC_INNO_DEF=%MPCHC_INNO_DEF% /Dx64Build + SET MPCHC_COPY_DX_DLL_ARGS=x64 +) ELSE SET MPCHC_COPY_DX_DLL_ARGS=x86 + + +IF DEFINED MPCHC_LITE ( + SET MPCHC_INNO_DEF=%MPCHC_INNO_DEF% /DMPCHC_LITE + SET MPCHC_COPY_DX_DLL_ARGS=%MPCHC_COPY_DX_DLL_ARGS% " Lite" +) + +CALL :SubCopyDXDll %MPCHC_COPY_DX_DLL_ARGS% + +CALL "%COMMON%" :SubDetectInnoSetup + +IF NOT DEFINED InnoSetupPath ( + CALL "%COMMON%" :SubMsg "WARNING" "Inno Setup wasn't found, the %1 installer wasn't built" + EXIT /B +) + +TITLE Compiling %1 %COMPILER% installer... +"%InnoSetupPath%" /SMySignTool="cmd /c "%FILE_DIR%contrib\sign.bat" $f" /Q /O"%BIN_DIR%"^ + "distrib\mpc-hc_setup.iss" %MPCHC_INNO_DEF% +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B +CALL "%COMMON%" :SubMsg "INFO" "%1 installer successfully built" + +EXIT /B + + +:SubCreatePackages +IF %ERRORLEVEL% NEQ 0 EXIT /B + +CALL "%COMMON%" :SubDetectSevenzipPath +CALL "%COMMON%" :SubGetVersion +CALL "%COMMON%" :SubMINGWLIB + +IF NOT DEFINED SEVENZIP ( + CALL "%COMMON%" :SubMsg "WARNING" "7-Zip wasn't found, the %1 %2 package wasn't built" + EXIT /B +) + +IF /I "%~1" == "Filters" (SET "NAME=MPC-HC_standalone_filters") ELSE (SET "NAME=MPC-HC") +IF /I "%~2" == "Win32" ( + SET ARCH=x86 +) ELSE ( + SET ARCH=x64 +) + +IF DEFINED MPCHC_LITE ( + CALL :SubCopyDXDll %ARCH% " Lite" +) ELSE IF /I "%NAME%" == "MPC-HC" ( + CALL :SubCopyDXDll %ARCH% +) + +PUSHD "%BIN_DIR%" + +SET "VS_OUT_DIR=%~1_%ARCH%" +SET "PCKG_NAME=%NAME%.%MPCHC_VER%.%ARCH%" +IF DEFINED MPCHC_LITE ( + SET "VS_OUT_DIR=%VS_OUT_DIR% Lite" + SET "PCKG_NAME=%PCKG_NAME%.Lite" +) +IF /I "%BUILDCFG%" == "Debug" ( + SET "PCKG_NAME=%PCKG_NAME%.dbg" + SET "VS_OUT_DIR=%VS_OUT_DIR%_Debug" +) + +IF EXIST "%PCKG_NAME%.7z" DEL "%PCKG_NAME%.7z" +IF EXIST "%PCKG_NAME%.pdb.7z" DEL "%PCKG_NAME%.pdb.7z" +IF EXIST "%PCKG_NAME%" RD /Q /S "%PCKG_NAME%" + +SET "PDB_FILES=*.pdb" +IF NOT DEFINED MPCHC_LITE (SET "PDB_FILES=%PDB_FILES% %LAVFILTERSDIR%\*.pdb") + +REM Compress the pdb file for mpc-hc only +IF /I "%NAME%" == "MPC-HC" ( + PUSHD "%VS_OUT_DIR%" + TITLE Creating archive %PCKG_NAME%.pdb.7z... + START "7z" /B /WAIT "%SEVENZIP%" a -t7z "%PCKG_NAME%.pdb.7z" %PDB_FILES% -m0=LZMA2^ + -mmt=%NUMBER_OF_PROCESSORS% -mx9 -ms=on + IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Unable to create %PCKG_NAME%.pdb.7z!" & EXIT /B + CALL "%COMMON%" :SubMsg "INFO" "%PCKG_NAME%.pdb.7z successfully created" + IF EXIST "%PCKG_NAME%.pdb.7z" MOVE /Y "%PCKG_NAME%.pdb.7z" ".." >NUL + POPD +) + +TITLE Copying %PCKG_NAME%... +IF NOT EXIST "%PCKG_NAME%" MD "%PCKG_NAME%" + +IF /I "%NAME%" == "MPC-HC" ( + IF NOT DEFINED MPCHC_LITE ( + IF /I "%BUILDCFG%" NEQ "Debug" ( + IF NOT EXIST "%PCKG_NAME%\Lang" MD "%PCKG_NAME%\Lang" + ) + IF NOT EXIST "%PCKG_NAME%\%LAVFILTERSDIR%" MD "%PCKG_NAME%\%LAVFILTERSDIR%" + ) + IF /I "%ARCH%" == "x64" ( + COPY /Y /V "%VS_OUT_DIR%\mpc-hc64.exe" "%PCKG_NAME%\mpc-hc64.exe" >NUL + ) ELSE ( + COPY /Y /V "%VS_OUT_DIR%\mpc-hc.exe" "%PCKG_NAME%\mpc-hc.exe" >NUL + ) + COPY /Y /V "%VS_OUT_DIR%\mpciconlib.dll" "%PCKG_NAME%\*.dll" >NUL + IF NOT DEFINED MPCHC_LITE ( + COPY /Y /V "%VS_OUT_DIR%\Lang\mpcresources.??.dll" "%PCKG_NAME%\Lang\" >NUL + COPY /Y /V "%VS_OUT_DIR%\Lang\mpcresources.??_??.dll" "%PCKG_NAME%\Lang\" >NUL + COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.ax" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL + COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.dll" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL + COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.manifest" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL + ) + COPY /Y /V "%VS_OUT_DIR%\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" "%PCKG_NAME%\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" >NUL + COPY /Y /V "%VS_OUT_DIR%\d3dx9_%MPC_DX_SDK_NUMBER%.dll" "%PCKG_NAME%\d3dx9_%MPC_DX_SDK_NUMBER%.dll" >NUL + IF NOT EXIST "%PCKG_NAME%\Shaders" MD "%PCKG_NAME%\Shaders" + COPY /Y /V "..\src\mpc-hc\res\shaders\dx9\*.hlsl" "%PCKG_NAME%\Shaders" >NUL + IF NOT EXIST "%PCKG_NAME%\Shaders11" MD "%PCKG_NAME%\Shaders11" + COPY /Y /V "..\src\mpc-hc\res\shaders\dx11\*.hlsl" "%PCKG_NAME%\Shaders11" >NUL + IF /I "%BUILDCFG%" NEQ "Debug" IF /I "%BUILDCFG%" NEQ "Debug Lite" IF EXIST "%VS_OUT_DIR%\CrashReporter\crashrpt.dll" ( + IF NOT EXIST "%PCKG_NAME%\CrashReporter" MD "%PCKG_NAME%\CrashReporter" + COPY /Y /V "%VS_OUT_DIR%\CrashReporter\crashrpt.dll" "%PCKG_NAME%\CrashReporter" + COPY /Y /V "%VS_OUT_DIR%\CrashReporter\dbghelp.dll" "%PCKG_NAME%\CrashReporter" + COPY /Y /V "%VS_OUT_DIR%\CrashReporter\sendrpt.exe" "%PCKG_NAME%\CrashReporter" + COPY /Y /V "%VS_OUT_DIR%\CrashReporter\CrashReporterDialog.dll" "%PCKG_NAME%\CrashReporter" + ) +) ELSE ( + COPY /Y /V "%VS_OUT_DIR%\*.ax" "%PCKG_NAME%\*.ax" >NUL + COPY /Y /V "%VS_OUT_DIR%\VSFilter.dll" "%PCKG_NAME%\VSFilter.dll" >NUL +) + +COPY /Y /V "..\COPYING.txt" "%PCKG_NAME%" >NUL + +TITLE Creating archive %PCKG_NAME%.7z... +START "7z" /B /WAIT "%SEVENZIP%" a -t7z "%PCKG_NAME%.7z" "%PCKG_NAME%" -m0=LZMA2^ + -mmt=%NUMBER_OF_PROCESSORS% -mx9 -ms=on +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Unable to create %PCKG_NAME%.7z!" & EXIT /B +CALL "%COMMON%" :SubMsg "INFO" "%PCKG_NAME%.7z successfully created" + +IF EXIST "%PCKG_NAME%" RD /Q /S "%PCKG_NAME%" + +POPD +EXIT /B + + +:ShowHelp +TITLE %~nx0 Help +ECHO. +ECHO Usage: +ECHO %~nx0 [Clean^|Build^|Rebuild] [x86^|x64^|Both] [Main^|Resources^|MPCHC^|IconLib^|Translations^|Filters^|API^|All] [Debug^|Release] [Lite] [Packages^|Installer^|7z] [LAVFilters] [Analyze] +ECHO. +ECHO Notes: You can also prefix the commands with "-", "--" or "/". +ECHO Debug only applies to mpc-hc.sln. +ECHO The arguments are not case sensitive and can be ommitted. +ECHO. & ECHO. +ECHO Executing %~nx0 without any arguments will use the default ones: +ECHO "%~nx0 Build Both MPCHC Release" +ECHO. & ECHO. +ECHO Examples: +ECHO %~nx0 x86 Resources -Builds the x86 resources +ECHO %~nx0 Resources -Builds both x86 and x64 resources +ECHO %~nx0 x86 -Builds x86 Main exe and the x86 resources +ECHO %~nx0 x86 Debug -Builds x86 Main Debug exe and x86 resources +ECHO %~nx0 x86 Filters -Builds x86 Filters +ECHO %~nx0 x86 All -Builds x86 Main exe, x86 Filters and the x86 resources +ECHO %~nx0 x86 Packages -Builds x86 Main exe, x86 resources and creates the installer and the .7z package +ECHO %~nx0 x64 LAVFilters 7z -Rebuilds LAVFilters, builds x64 Main exe, x64 resources and creates the .7z package +ECHO. +ENDLOCAL +EXIT /B + + +:MissingVar +TITLE Compiling MPC-HC %COMPILER% [ERROR] +ECHO Not all build dependencies were found. +ECHO. +ECHO See "docs\Compilation.md" for more information. +CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B + + +:UnsupportedSwitch +ECHO. +ECHO Unsupported commandline switch! +ECHO. +ECHO "%~nx0 %*" +ECHO. +ECHO Run "%~nx0 help" for details about the commandline switches. +CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B diff --git a/contrib/sign.bat b/contrib/sign.bat index 0ae0418a3eb..adc1a0ad9a1 100755 --- a/contrib/sign.bat +++ b/contrib/sign.bat @@ -1,80 +1,80 @@ -@ECHO OFF -REM (C) 2013, 2015-2017 see Authors.txt -REM -REM This file is part of MPC-HC. -REM -REM MPC-HC is free software; you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation; either version 3 of the License, or -REM (at your option) any later version. -REM -REM MPC-HC is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with this program. If not, see . - - -SETLOCAL -SET "FILE_DIR=%~dp0" - -SET "COMMON=%FILE_DIR%..\common.bat" - -IF "%~1" == "" ( - ECHO %~nx0: No input specified! - SET SIGN_ERROR=True - GOTO END -) - -IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath -IF NOT EXIST "%MPCHC_VS_PATH%" ( - ECHO %~nx0: Visual Studio 2017 does not seem to be installed... - SET SIGN_ERROR=True - GOTO END -) -SET "TOOLSET=%MPCHC_VS_PATH%\Common7\Tools\vsdevcmd" - -IF NOT EXIST "%FILE_DIR%..\signinfo.txt" ( - ECHO %~nx0: %FILE_DIR%..\signinfo.txt is not present! - SET SIGN_ERROR=True - GOTO END -) - -signtool /? 2>NUL || CALL "%TOOLSET%" 2>NUL -IF %ERRORLEVEL% NEQ 0 ( - ECHO vcvarsall.bat call failed. - GOTO End -) - -REM Repeat n times when signing fails -SET REPEAT=5 -FOR /F "delims=" %%A IN (%FILE_DIR%..\signinfo.txt) DO (SET "SIGN_CMD=%%A" && CALL :START_SIGN %1) - -:END -IF /I "%SIGN_ERROR%" == "True" ( - IF "%~1" == "" PAUSE - ENDLOCAL - EXIT /B 1 -) -ENDLOCAL -EXIT /B - -:START_SIGN -IF /I "%SIGN_ERROR%" == "True" EXIT /B -REM %1 is name of the file to sign -TITLE Signing "%~1"... -ECHO. & ECHO Signing "%~1"... -SET TRY=0 - -:SIGN -SET /A TRY+=1 -signtool sign %SIGN_CMD% %1 -IF %ERRORLEVEL% EQU 0 EXIT /B -IF %TRY% LSS %REPEAT% ( - REM Wait 5 seconds before next try - PING -n 5 127.0.0.1 > NUL - GOTO SIGN -) -SET SIGN_ERROR=True +@ECHO OFF +REM (C) 2013, 2015-2017 see Authors.txt +REM +REM This file is part of MPC-HC. +REM +REM MPC-HC is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation; either version 3 of the License, or +REM (at your option) any later version. +REM +REM MPC-HC is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with this program. If not, see . + + +SETLOCAL +SET "FILE_DIR=%~dp0" + +SET "COMMON=%FILE_DIR%..\common.bat" + +IF "%~1" == "" ( + ECHO %~nx0: No input specified! + SET SIGN_ERROR=True + GOTO END +) + +IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath +IF NOT EXIST "%MPCHC_VS_PATH%" ( + ECHO %~nx0: Visual Studio 2017 does not seem to be installed... + SET SIGN_ERROR=True + GOTO END +) +SET "TOOLSET=%MPCHC_VS_PATH%\Common7\Tools\vsdevcmd" + +IF NOT EXIST "%FILE_DIR%..\signinfo.txt" ( + ECHO %~nx0: %FILE_DIR%..\signinfo.txt is not present! + SET SIGN_ERROR=True + GOTO END +) + +signtool /? 2>NUL || CALL "%TOOLSET%" 2>NUL +IF %ERRORLEVEL% NEQ 0 ( + ECHO vcvarsall.bat call failed. + GOTO End +) + +REM Repeat n times when signing fails +SET REPEAT=5 +FOR /F "delims=" %%A IN (%FILE_DIR%..\signinfo.txt) DO (SET "SIGN_CMD=%%A" && CALL :START_SIGN %1) + +:END +IF /I "%SIGN_ERROR%" == "True" ( + IF "%~1" == "" PAUSE + ENDLOCAL + EXIT /B 1 +) +ENDLOCAL +EXIT /B + +:START_SIGN +IF /I "%SIGN_ERROR%" == "True" EXIT /B +REM %1 is name of the file to sign +TITLE Signing "%~1"... +ECHO. & ECHO Signing "%~1"... +SET TRY=0 + +:SIGN +SET /A TRY+=1 +signtool sign %SIGN_CMD% %1 +IF %ERRORLEVEL% EQU 0 EXIT /B +IF %TRY% LSS %REPEAT% ( + REM Wait 5 seconds before next try + PING -n 5 127.0.0.1 > NUL + GOTO SIGN +) +SET SIGN_ERROR=True diff --git a/distrib/Languages/Basque.isl b/distrib/Languages/Basque.isl index a4b9cebeb13..f44148f47e9 100644 --- a/distrib/Languages/Basque.isl +++ b/distrib/Languages/Basque.isl @@ -1,339 +1,339 @@ -; *** Inno Setup version 5.5.3+ Basque messages *** -; -; Basque Translation: (EUS_Xabier Aramendi) (azpidatziak@gmail.com) -; -; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ -; -; Note: When translating this text, do not add periods (.) to the end of -; messages that didn't have them already, because on those messages Inno -; Setup adds the periods automatically (appending a period would result in -; two periods being displayed). - -[LangOptions] -; The following three entries are very important. Be sure to read and -; understand the '[LangOptions] section' topic in the help file. -LanguageName=Euskara -LanguageID=$042d -LanguageCodePage=0 -; If the language you are translating to requires special font faces or -; sizes, uncomment any of the following entries and change them accordingly. -;DialogFontName= -;DialogFontSize=8 -;WelcomeFontName=Verdana -;WelcomeFontSize=12 -;TitleFontName=Arial -;TitleFontSize=29 -;CopyrightFontName=Arial -;CopyrightFontSize=8 - -[Messages] - -; *** Application titles -SetupAppTitle=Ezarpena -SetupWindowTitle=Ezarpena - %1 -UninstallAppTitle=Kentzea -UninstallAppFullTitle=Kentzea - %1 - -; *** Misc. common -InformationTitle=Argibideak -ConfirmTitle=Baieztatu -ErrorTitle=Akatsa - -; *** SetupLdr messages -SetupLdrStartupMessage=Honek %1 ezarriko du. Jarraitzea nahi duzu? -LdrCannotCreateTemp=Ezinezkoa aldibaterako agiri bat sortzea. Ezarpena utzita -LdrCannotExecTemp=Ezinezkoa agiria exekutatzea aldibaterako zuzenbidean. Ezarpena utzita - -; *** Startup error messages -LastErrorMessage=%1.%n%nAkatsa %2: %3 -SetupFileMissing=%1 agiria ez dago ezarpen zuzenbidean. Mesedez zuzendu arazoa edo lortu programaren kopia berri bat. -SetupFileCorrupt=Ezarpen agiriak hondatuta daude. Mesedez lortu programaren kopia berri bat. -SetupFileCorruptOrWrongVer=Ezarpen agiriak hondatuta daude, edo bateraezinak dira Ezartzaile bertsio honekin. Mesedez zuzendu arazoa edo lortu programaren kopia berri bat. -InvalidParameter=Parametro baliogabe bat igaro da komando lerroan:%n%n%1 -SetupAlreadyRunning=Ezarpena jadanik ekinean dago. -WindowsVersionNotSupported=Programa honek ez du zure ordenagailuan ekinean dagoen Windows bertsioa sostengatzen. -WindowsServicePackRequired=Programa honek %1 Service Pack %2 edo berriagoa behar du. - - -NotOnThisPlatform=Programa honek ez du ekingo hemen: %1. -OnlyOnThisPlatform=Programa hau hemen ekin behar da: %1. -OnlyOnTheseArchitectures=Programa hau hurrengo Windows arkitekturatarako diseinaturiko bertsioetan bakarrik ezarri daiteke:%n%n%1 -MissingWOW64APIs=Erabiltzen ari zaren Windows bertsioak ez du Ezartzaileak 64-biteko ezarpen bat egiteko behar dituen eginkizunak barneratzen. Arazo hau zuzentzeko, mesedez ezarri Service Pack %1. -WinVersionTooLowError=Programa honek %1 bertsioa %2 edo berriagoa behar du. -WinVersionTooHighError=Programa hau ezin da %1 bertsioa %2 edo berriagoan ezarria izan. -AdminPrivilegesRequired=Administrari bezala izena-emanda egon behar zara programa hau ezartzeko. -PowerUserPrivilegesRequired=Administrari bezala izena-emanda edo Boteredun Erabiltzaile taldeko kide bezala egon behar zara programa hau ezartzerakoan. -SetupAppRunningError=Ezartzaileak %1 ekinean dagoela atzeman du.%n%nMesedez itxi bere eskabide guztiak orain, orduan klikatu Ongi jarritzeko, edo Ezeztatu irtetzeko. -UninstallAppRunningError=Kentzaileak %1 ekinean dagoela atzeman du.%n%nMesedez itxi bere eskabide guztiak orain, orduan klikatu Ongi jarritzeko, edo Ezeztatu irtetzeko. - -; *** Misc. errors -ErrorCreatingDir=Ezartzaileak ezin izan du zuzenbidea sortu "%1" -ErrorTooManyFilesInDir=Ezinezkoa agiri bat sortzea "%1" zuzenbidean agiri gehiegi dituelako - -; *** Setup common messages -ExitSetupTitle=Irten Ezartzailetik -ExitSetupMessage=Ezarpena ez dago osatuta. Orain irtetzen bazara, programa ez da ezarriko.%n%nEzartzailea berriro edonoiz abiatu dezakezu ezarpena osatzeko.%n%nIrten Ezartzailetik? -AboutSetupMenuItem=&Ezartzaileari buruz... -AboutSetupTitle=Ezartzaileari buruz -AboutSetupMessage=%1 bertsioa %2%n%3%n%n%1 webgunea:%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< &Atzera -ButtonNext=&Hurrengoa > -ButtonInstall=&Ezarri -ButtonOK=Ongi -ButtonCancel=Ezeztatu -ButtonYes=&Bai -ButtonYesToAll=Bai &Guztiari -ButtonNo=&Ez -ButtonNoToAll=E&z Guztiari -ButtonFinish=A&maitu -ButtonBrowse=&Bilatu... -ButtonWizardBrowse=B&ilatu... -ButtonNewFolder=Egi&n Agiritegi Berria - -; *** "Select Language" dialog messages -SelectLanguageTitle=Hautatu Ezarpen Hizkuntza -SelectLanguageLabel=Hautatu ezarpenean zehar erabiltzeko hizkuntza: - -; *** Common wizard text -ClickNext=Klikatu Hurrengoa jarraitzeko, edo Ezeztatu Ezartzailetik irtetzeko -BeveledLabel= -BrowseDialogTitle=Bilatu Agiritegia -BrowseDialogLabel=Hautatu agiritegi bat azpiko zerrendan, orduan klikatu Ongi -NewFolderName=Agiritegi Berria - -; *** "Welcome" wizard page -WelcomeLabel1=Ongi etorria [name] Ezarpen Laguntzailera -WelcomeLabel2=Honek [name/ver] zure ordenagailuan ezarriko du.%n%nGomendagarria da beste aplikazio guztiak istea jarraitu aurretik. - -; *** "Password" wizard page -WizardPassword=Sarhitza -PasswordLabel1=Ezarpen hau sarhitzez babestuta dago. -PasswordLabel3=Mesedez eman sarhitza, orduan klikatu Hurrengoa jarraitzeko. Sarhitzek hizki larri-xeheak bereizten dituzte. -PasswordEditLabel=&Sarhitza: -IncorrectPassword=Eman duzun sarhitza ez da zuzena. Mesedez saiatu berriro. - -; *** "License Agreement" wizard page -WizardLicense=Baimen Ituna -LicenseLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. -LicenseLabel3=Mesedez irakurri hurrengo Baimen Ituna. Itun honen baldintzak onartu behar dituzu ezarpenarekin jarraitu aurretik. -LicenseAccepted=&Onartzen dut ituna -LicenseNotAccepted=&Ez dut onartzen ituna - -; *** "Information" wizard pages -WizardInfoBefore=Argibideak -InfoBeforeLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. -InfoBeforeClickLabel=Ezarpenarekin jarraitzeko gertu zaudenean, klikatu Hurrengoa. -WizardInfoAfter=Argibideak -InfoAfterLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. -InfoAfterClickLabel=Ezarpenarekin jarraitzeko gertu zaudenean, klikatu Hurrengoa. - -; *** "User Information" wizard page -WizardUserInfo=Erabailtzaile Argibideak -UserInfoDesc=Mesedez sartu zure argibideak -UserInfoName=&Erabiltzaile Izena: -UserInfoOrg=&Antolakundea: -UserInfoSerial=&Serie Zenbakia: -UserInfoNameRequired=Izen bat sartu behar duzu. - -; *** "Select Destination Location" wizard page -WizardSelectDir=Hautatu Helmuga Kokalekua -SelectDirDesc=Non ezarri behar da [name]? -SelectDirLabel3=Ezartzaileak [name] hurrengo agiritegian ezarriko du. -SelectDirBrowseLabel=Jarraitzeko, klikatu Hurrengoa. Beste agiritegi bat hautatzea nahi baduzu, klikatu Bilatu. -DiskSpaceMBLabel=Gutxienez [mb] MB-eko toki askea behar da diska gogorrean. -CannotInstallToNetworkDrive=Ezarpena ezin da sare gidagailu batean egin. -CannotInstallToUNCPath=Ezarpena ezin da UNC helburu batean egin. -InvalidPath=Helburu osoa gidagailu hizkiarekin sartu behar duzu; adibidez:%n%nC:\APP%n%nedo UNC helburu bat forma honetan:%n%n\\server\share -InvalidDrive=Hautatu duzun gidagailua edo UNC elkarbanaketa ez dago edo sarbidea ezinezkoa da. Mesedez hautatu beste bat. -DiskSpaceWarningTitle=Ez Dago Nahikoa Toki Diskan -DiskSpaceWarning=Ezarpenak gutxienez %1 KB-eko toki askea behar du ezartzeko, baina hautaturiko gidagailuak %2 KB bakarrik ditu eskuragarri.%n%nHorrela ere jarraitzea nahi duzu? -DirNameTooLong=Agiritegi izena edo helburua luzeegia da. -InvalidDirName=Agiritegi izena ez da baliozkoa. -BadDirName32=Agiritegi izenek ezin dute hurrengo hizkietako bat ere izan:%n%n%1 -DirExistsTitle=Agiritegia Badago -DirExists=Agiritegia:%n%n%1%n%njadanik badago. Horrela ere agiritegi horretan ezartzea nahi duzu? -DirDoesntExistTitle=Agiritegia Ez Dago -DirDoesntExist=Agiritegia:%n%n%1%n%nez dago. Nahi duzu agiritegia sortzea? - -; *** "Select Components" wizard page -WizardSelectComponents=Hautatu Osagaiak -SelectComponentsDesc=Zer osagai ezarri behar dira? -SelectComponentsLabel2=Hautatu ezartzea nahi dituzun osagaiak; garbitu ezartzea nahi ez dituzun osagaiak. Klikatu Hurrengoa jarraitzeko gertu zaudenean. -FullInstallation=Ezarpen osoa -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=Ezarpen trinkoa -CustomInstallation=Norbere ezarpena -NoUninstallWarningTitle=Osagaiak Badaude -NoUninstallWarning=Ezartzaileak atzeman du hurrengo osagaiak jadanik zure ordenagailuan ezarrita daudela:%n%n%1%n%nOsagai hauek deshautatuz gero ez dira ezarriko.%n%nHorrela ere jarraitzea nahi duzu? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=Oraingo hautapenak gutxienez [mb] MB-eko tokia behar du diskan. - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=Hautatu Eginkizun Gehigarriak -SelectTasksDesc=Zer eginkizun gehigarri burutu behar dira? -SelectTasksLabel2=Hautatu Ezartzaileak [name]-ren ezarpenean zehar burutzea nahi dituzun eginkizun gehigarriak, orduan klikatu Hurrengoa - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=Hautatu Hasiera Menuko Agiritegia -SelectStartMenuFolderDesc=Non ezarri behar ditu Ezartzaileak programaren lasterbideak? -SelectStartMenuFolderLabel3=Ezartzaileak programaren lasterbideak hurrengo Hasiera Menuko agiritegian sortuko ditu. -SelectStartMenuFolderBrowseLabel=Jarraitzeko, klikatu Hurrengoa. Beste agiritegi bat hautatzea nahi baduzu, klikatu Bilatu. -MustEnterGroupName=Agiritegi izen bat sartu behar duzu. -GroupNameTooLong=Agiritegi izena edo helburua luzeegia da. -InvalidGroupName=Agiritegi izena ez da baliozkoa. -BadGroupName=Agiritegi izenak ezin du hurrengo hizkietako bat ere izan:%n%n%1 -NoProgramGroupCheck2=&Ez sortu Hasiera Menuko agiritegia - -; *** "Ready to Install" wizard page -WizardReady=Ezartzeko Gertu -ReadyLabel1=Ezartzailea orain gertu dago [name] zure ordenagailuan ezartzeko. -ReadyLabel2a=Klikatu Ezarri ezarpenarekin jarraitzeko, edo klikatu Atzera ezarpenen bat berrikustea edo aldatzea nahi baduzu. -ReadyLabel2b=Klikatu Ezarri ezarpenarekin jarraitzeko. -ReadyMemoUserInfo=Erabiltzaile argibideak: -ReadyMemoDir=Helmuga kokalekua: -ReadyMemoType=Ezarpen mota: -ReadyMemoComponents=Hautaturiko osagaiak: -ReadyMemoGroup=Hasiera Menuko agiritegia: -ReadyMemoTasks=Eginkizun gehigarriak: - -; *** "Preparing to Install" wizard page -WizardPreparing=Ezartzeko Gertatzen -PreparingDesc=Ezartzailea [name] zure ordenagailuan ezartzeko gertatzen ari da. -PreviousInstallNotCompleted=Aurreko programaren ezartze/kentzea ez dago osatuta. Zure ordenagailua berrabiarazi behar duzu ezarpena osatzeko.%n%nZure ordenagailua berrabiarazi ondoren, ekin Ezartzailea berriro [name]-ren ezarpena osatzeko. -CannotContinue=Ezarpenak ezin du jarraitu. Mesedez klikatu Ezeztatu irtetzeko. -ApplicationsFound=Hurrengo aplikazioak Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari dira. Gomendagarria da Ezartzaileari aplikazio hauek berezgaitasunez istea ahalbidetzea. -ApplicationsFound2=Hurrengo aplikazioak Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari dira. Gomendagarria da Ezartzaileari aplikazio hauek berezgaitasunez istea ahalbidetzea. Ezarpena osatu ondoren, Ezartzailea aplikazioak berrabiarazten saiatuko da. -CloseApplications=&Berezgaitasunez itxi aplikazioak -DontCloseApplications=&Ez itxi aplikazioak -ErrorCloseApplications=Ezartzaileak ezin ditu berezgaitasunez aplikazio guztiak itxi. Gomendagarria da Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari diren aplikazio guztiak istea jarraitu aurretik. - -; *** "Installing" wizard page -WizardInstalling=Ezartzen -InstallingLabel=Mesedez itxaron Ezartzaileak [name] zure ordenagailuan ezartzen duen bitartean. - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=[name] Ezarpen Laguntzailea osatzen -FinishedLabelNoIcons=Ezartzaileak amaitu du [name] zure ordenagailuan ezartzeaz. -FinishedLabel=Ezartzaileak amaitu du [name] zure ordenagailuan ezartzea. Aplikazioa ezarritako ikurren bidez abiarazi daiteke. -ClickFinish=Klikatu Amaitu Ezartzailetik irtetzeko. -FinishedRestartLabel=[name]-ren ezarpena osatzeko, Ezartzaileak zure ordenagailua berrabiarazi behar du. Orain berrabiaraztea nahi duzu? -FinishedRestartMessage=[name]-ren ezarpena osatzeko, Ezartzaileak zure ordenagailua berrabiarazi behar du.%n%nOrain berrabiaraztea nahi duzu? -ShowReadmeCheck=Bai, IRAKURRI agiria ikustea nahi dut -YesRadio=&Bai, berrabiarazi ordenagailua orain -NoRadio=&Ez, geroago berrabiaraziko dut ordenagailua -; used for example as 'Run MyProg.exe' -RunEntryExec=Ekin %1 -; used for example as 'View Readme.txt' -RunEntryShellExec=Ikusi %1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=Ezarpenak Hurrengo Diska Behar Du -SelectDiskLabel2=Mesedez txertatu %1 Diska eta klikatu Ongi.%n%nDiska honetako agiriak azpian erakutsitakoa ez den beste agiritegi batean aurkitu badaitezke, sartu helburu zuzena edo klikatu Bilatu. -PathLabel=&Helburua: -FileNotInDir2="%1" agiria ezin da hemen aurkitu: "%2". Mesedez txertatu diska zuzena edo hautatu beste agiritegi bat. -SelectDirectoryLabel=Mesedez adierazi hurrengo diskaren kokalekua. - -; *** Installation phase messages -SetupAborted=Ezarpena ez da osatu.%n%nMesedez zuzendu arazoa eta ekin Ezartzailea berriro. -EntryAbortRetryIgnore=Klikatu Bersaiatu berriro saiatzeko, Ezikusi horrela ere jarraitzeko, edo Utzi ezarpena ezeztatzeko. - -; *** Installation status messages -StatusClosingApplications=Aplikazioak isten... -StatusCreateDirs=Zuzenbideak sortzen... -StatusExtractFiles=Agiriak ateratzen... -StatusCreateIcons=Lasterbideak sortzen... -StatusCreateIniEntries=INI sarrerak sortzen... -StatusCreateRegistryEntries=Erregistro sarrerak sortzen... -StatusRegisterFiles=Agiriak erregistratzen... -StatusSavingUninstall=Kentze argibideak gordetzen... -StatusRunProgram=Ezarpena amaitzen... -StatusRestartingApplications=Aplikazioak berrabiarazten... -StatusRollback=Aldaketak leheneratzen... - -; *** Misc. errors -ErrorInternal2=Barneko akatsa: %1 -ErrorFunctionFailedNoCode=%1 hutsegitea -ErrorFunctionFailed=%1 hutsegitea; kodea %2 -ErrorFunctionFailedWithMessage=%1 hutsegitea; kodea %2.%n%3 -ErrorExecutingProgram=Ezinezkoa agiria exekutatzea:%n%1 - -; *** Registry errors -ErrorRegOpenKey=Akatsa erregistro giltza irekitzerakoan:%n%1\%2 -ErrorRegCreateKey=Akatsa erregistro giltza sortzerakoan:%n%1\%2 -ErrorRegWriteKey=Akatsa erregistro giltza idazterakoan:%n%1\%2 - -; *** INI errors -ErrorIniEntry=Akatsa INI sarrera "%1" agirian sortzerakoan. - -; *** File copying errors -FileAbortRetryIgnore=Klikatu Bersaiatu berriro saitzeko, Ezikusi agiri hau jauzteko (ez da gomendatua), edo Utzi ezarpena ezeztatzeko. -FileAbortRetryIgnore2=Klikatu Bersaiatu berriro saitzeko, Ezikusi horrela ere jarraitzeko (ez da gomendatua), edo Utzi ezarpena ezeztatzeko. -SourceIsCorrupted=Iturburu agiria hondatuta dago. -SourceDoesntExist="%1" iturburu agiria ez dago -ExistingFileReadOnly=Dagoen agiria irakurtzeko-bakarrik bezala markatuta dago.%n%nKlikatu Bersaiatu irakurtzeko-bakarrik ezaugarria kentzeko eta saiatu berriro, Ezikusi agiri hau jauzteko, edo Utzi ezarpena ezeztatzeko. -ErrorReadingExistingDest=Akats bat gertatu da dagoen agiria irakurtzen saiatzerakoan: -FileExists=Agiria jadanik badago.%n%nNahi duzu Ezartzaileak gainidaztea? -ExistingFileNewer=Dagoen agiria Ezartzailea ezartzen saiatzen ari dena baino berriagoa da. Gomendagarria da dagoen agiriari heustea.%n%nDagoen agiriari heustea nahi diozu? -ErrorChangingAttr=Akats bat gertatu da dagoen agiriaren ezaugarriak aldatzen saiatzerakoan: -ErrorCreatingTemp=Akats bat gertatu da helmuga zuzenbidean agiri bat sortzen saiatzerakoan: -ErrorReadingSource=Akats bat gertatu da iturburu agiria irakurtzen saiatzerakoan: -ErrorCopying=Akats bat gertatu da agiri bat kopiatzen saiatzerakoan: -ErrorReplacingExistingFile=Akats bat gertatu da dagoen agiria ordezten saiatzerakoan: -ErrorRestartReplace=Berrabiarazte-Ordezte hutsegitea: -ErrorRenamingTemp=Akats bat gertatu da helmuga zuzenbideko agiri bat berrizendatzen saiatzerakoan: -ErrorRegisterServer=Ezinezkoa DLL/OCX erregistratzea: %1 -ErrorRegSvr32Failed=RegSvr32 hutsegitea %1 irteera kodearekin -ErrorRegisterTypeLib=Ezinezkoa liburutegi mota erregistratzea: %1 - -; *** Post-installation errors -ErrorOpeningReadme=Akats bat gertatu da IRAKURRI agiria irekitzen saiatzerakoan. -ErrorRestartingComputer=Ezartzaileak ezin du ordenagailua berrabiarazi. Mesedez egin hau eskuz. - -; *** Uninstaller messages -UninstallNotFound="%1" agiria ez dago. Ezinezkoa kentzea -UninstallOpenError="%1" agiria ezin da ireki. Ezinezkoa kentzea -UninstallUnsupportedVer="%1" kentze ohar agiria kentzaile bertsio honek ezagutzen ez duen heuskarri batean dago. Ezinezkoa kentzea. -UninstallUnknownEntry=Sarrera ezezagun bat (%1) aurkitu da kentze oharrean -ConfirmUninstall=Zihur zaude %1 eta bere osagai guztiak erabat kentzea nahi dituzula? -UninstallOnlyOnWin64=Ezarpen hau 64-biteko Windows-etik bakarrik kendu daiteke. -OnlyAdminCanUninstall=Ezarpen hau administrari pribilegioak dituen erabiltzaile batek bakarrik kendu dezake. -UninstallStatusLabel=Mesedez itxaron %1 zure ordenagailutik kentzen den bitartean. -UninstalledAll=%1 ongi kendu da zure ordenagailutik. -UninstalledMost=%1-ren kentzea osatuta.%n%nZenbait gai ezin izan dira kendu. Hauek eskuz kendu daitezke. -UninstalledAndNeedsRestart=%1-ren kentzea osatzeko, zure ordenagailua berrabiarazi behar duzu.%n%nOrain berrabiaraztea nahi duzu? -UninstallDataCorrupted="%1" agiria hondatuta da. Ezinezkoa kentzea - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=Ezabatu Agiri Elkarbanatua? -ConfirmDeleteSharedFile2=Sistemaren arabera hurrengo agiri elkarbanatua ez du inongo programak erabiliko hemendik aurrera. Kentzaileak agiri hau ezabatu dezan nahi duzu?%n%nProgramaren bat agiri hau erabiltzen ari da oraindik eta ezabatzen baduzu, programa hori ez da egoki ibiliko. Zihur ez bazaude, hautatu Ez. Agiria sisteman uzteak ez du inongo kalterik eragingo. -SharedFileNameLabel=Agiri izena: -SharedFileLocationLabel=Kokalekua: -WizardUninstalling=Kentze Egoera -StatusUninstalling=Kentzen %1... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=Ezartzen %1. -ShutdownBlockReasonUninstallingApp=Kentzen %1. -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] -;Inno Setup Built-in Custom Messages -NameAndVersion=%1 %2 bertsioa -AdditionalIcons=Ikur gehigarriak: -CreateDesktopIcon=Sortu &mahaigain ikurra -CreateQuickLaunchIcon=Sortu &Abiarazpen Azkarreko ikurra -ProgramOnTheWeb=%1 Webean -UninstallProgram=Kendu %1 -LaunchProgram=Abiarazi %1 -AssocFileExtension=&Elkartu %1 programa %2 agiri luzapenarekin -AssocingFileExtension=%1 programa %2 agiri luzapenarekin elkartzen... -AutoStartProgramGroupDescription=Abirazpena: -AutoStartProgram=Berezgaitasunez abiarazi %1 -AddonHostProgramNotFound=%1 ezin da aurkitu hautatu duzun agiritegian.%n%nHorrela ere jarraitzea nahi duzu? +; *** Inno Setup version 5.5.3+ Basque messages *** +; +; Basque Translation: (EUS_Xabier Aramendi) (azpidatziak@gmail.com) +; +; To download user-contributed translations of this file, go to: +; http://www.jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Euskara +LanguageID=$042d +LanguageCodePage=0 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Ezarpena +SetupWindowTitle=Ezarpena - %1 +UninstallAppTitle=Kentzea +UninstallAppFullTitle=Kentzea - %1 + +; *** Misc. common +InformationTitle=Argibideak +ConfirmTitle=Baieztatu +ErrorTitle=Akatsa + +; *** SetupLdr messages +SetupLdrStartupMessage=Honek %1 ezarriko du. Jarraitzea nahi duzu? +LdrCannotCreateTemp=Ezinezkoa aldibaterako agiri bat sortzea. Ezarpena utzita +LdrCannotExecTemp=Ezinezkoa agiria exekutatzea aldibaterako zuzenbidean. Ezarpena utzita + +; *** Startup error messages +LastErrorMessage=%1.%n%nAkatsa %2: %3 +SetupFileMissing=%1 agiria ez dago ezarpen zuzenbidean. Mesedez zuzendu arazoa edo lortu programaren kopia berri bat. +SetupFileCorrupt=Ezarpen agiriak hondatuta daude. Mesedez lortu programaren kopia berri bat. +SetupFileCorruptOrWrongVer=Ezarpen agiriak hondatuta daude, edo bateraezinak dira Ezartzaile bertsio honekin. Mesedez zuzendu arazoa edo lortu programaren kopia berri bat. +InvalidParameter=Parametro baliogabe bat igaro da komando lerroan:%n%n%1 +SetupAlreadyRunning=Ezarpena jadanik ekinean dago. +WindowsVersionNotSupported=Programa honek ez du zure ordenagailuan ekinean dagoen Windows bertsioa sostengatzen. +WindowsServicePackRequired=Programa honek %1 Service Pack %2 edo berriagoa behar du. + + +NotOnThisPlatform=Programa honek ez du ekingo hemen: %1. +OnlyOnThisPlatform=Programa hau hemen ekin behar da: %1. +OnlyOnTheseArchitectures=Programa hau hurrengo Windows arkitekturatarako diseinaturiko bertsioetan bakarrik ezarri daiteke:%n%n%1 +MissingWOW64APIs=Erabiltzen ari zaren Windows bertsioak ez du Ezartzaileak 64-biteko ezarpen bat egiteko behar dituen eginkizunak barneratzen. Arazo hau zuzentzeko, mesedez ezarri Service Pack %1. +WinVersionTooLowError=Programa honek %1 bertsioa %2 edo berriagoa behar du. +WinVersionTooHighError=Programa hau ezin da %1 bertsioa %2 edo berriagoan ezarria izan. +AdminPrivilegesRequired=Administrari bezala izena-emanda egon behar zara programa hau ezartzeko. +PowerUserPrivilegesRequired=Administrari bezala izena-emanda edo Boteredun Erabiltzaile taldeko kide bezala egon behar zara programa hau ezartzerakoan. +SetupAppRunningError=Ezartzaileak %1 ekinean dagoela atzeman du.%n%nMesedez itxi bere eskabide guztiak orain, orduan klikatu Ongi jarritzeko, edo Ezeztatu irtetzeko. +UninstallAppRunningError=Kentzaileak %1 ekinean dagoela atzeman du.%n%nMesedez itxi bere eskabide guztiak orain, orduan klikatu Ongi jarritzeko, edo Ezeztatu irtetzeko. + +; *** Misc. errors +ErrorCreatingDir=Ezartzaileak ezin izan du zuzenbidea sortu "%1" +ErrorTooManyFilesInDir=Ezinezkoa agiri bat sortzea "%1" zuzenbidean agiri gehiegi dituelako + +; *** Setup common messages +ExitSetupTitle=Irten Ezartzailetik +ExitSetupMessage=Ezarpena ez dago osatuta. Orain irtetzen bazara, programa ez da ezarriko.%n%nEzartzailea berriro edonoiz abiatu dezakezu ezarpena osatzeko.%n%nIrten Ezartzailetik? +AboutSetupMenuItem=&Ezartzaileari buruz... +AboutSetupTitle=Ezartzaileari buruz +AboutSetupMessage=%1 bertsioa %2%n%3%n%n%1 webgunea:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< &Atzera +ButtonNext=&Hurrengoa > +ButtonInstall=&Ezarri +ButtonOK=Ongi +ButtonCancel=Ezeztatu +ButtonYes=&Bai +ButtonYesToAll=Bai &Guztiari +ButtonNo=&Ez +ButtonNoToAll=E&z Guztiari +ButtonFinish=A&maitu +ButtonBrowse=&Bilatu... +ButtonWizardBrowse=B&ilatu... +ButtonNewFolder=Egi&n Agiritegi Berria + +; *** "Select Language" dialog messages +SelectLanguageTitle=Hautatu Ezarpen Hizkuntza +SelectLanguageLabel=Hautatu ezarpenean zehar erabiltzeko hizkuntza: + +; *** Common wizard text +ClickNext=Klikatu Hurrengoa jarraitzeko, edo Ezeztatu Ezartzailetik irtetzeko +BeveledLabel= +BrowseDialogTitle=Bilatu Agiritegia +BrowseDialogLabel=Hautatu agiritegi bat azpiko zerrendan, orduan klikatu Ongi +NewFolderName=Agiritegi Berria + +; *** "Welcome" wizard page +WelcomeLabel1=Ongi etorria [name] Ezarpen Laguntzailera +WelcomeLabel2=Honek [name/ver] zure ordenagailuan ezarriko du.%n%nGomendagarria da beste aplikazio guztiak istea jarraitu aurretik. + +; *** "Password" wizard page +WizardPassword=Sarhitza +PasswordLabel1=Ezarpen hau sarhitzez babestuta dago. +PasswordLabel3=Mesedez eman sarhitza, orduan klikatu Hurrengoa jarraitzeko. Sarhitzek hizki larri-xeheak bereizten dituzte. +PasswordEditLabel=&Sarhitza: +IncorrectPassword=Eman duzun sarhitza ez da zuzena. Mesedez saiatu berriro. + +; *** "License Agreement" wizard page +WizardLicense=Baimen Ituna +LicenseLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. +LicenseLabel3=Mesedez irakurri hurrengo Baimen Ituna. Itun honen baldintzak onartu behar dituzu ezarpenarekin jarraitu aurretik. +LicenseAccepted=&Onartzen dut ituna +LicenseNotAccepted=&Ez dut onartzen ituna + +; *** "Information" wizard pages +WizardInfoBefore=Argibideak +InfoBeforeLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. +InfoBeforeClickLabel=Ezarpenarekin jarraitzeko gertu zaudenean, klikatu Hurrengoa. +WizardInfoAfter=Argibideak +InfoAfterLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. +InfoAfterClickLabel=Ezarpenarekin jarraitzeko gertu zaudenean, klikatu Hurrengoa. + +; *** "User Information" wizard page +WizardUserInfo=Erabailtzaile Argibideak +UserInfoDesc=Mesedez sartu zure argibideak +UserInfoName=&Erabiltzaile Izena: +UserInfoOrg=&Antolakundea: +UserInfoSerial=&Serie Zenbakia: +UserInfoNameRequired=Izen bat sartu behar duzu. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Hautatu Helmuga Kokalekua +SelectDirDesc=Non ezarri behar da [name]? +SelectDirLabel3=Ezartzaileak [name] hurrengo agiritegian ezarriko du. +SelectDirBrowseLabel=Jarraitzeko, klikatu Hurrengoa. Beste agiritegi bat hautatzea nahi baduzu, klikatu Bilatu. +DiskSpaceMBLabel=Gutxienez [mb] MB-eko toki askea behar da diska gogorrean. +CannotInstallToNetworkDrive=Ezarpena ezin da sare gidagailu batean egin. +CannotInstallToUNCPath=Ezarpena ezin da UNC helburu batean egin. +InvalidPath=Helburu osoa gidagailu hizkiarekin sartu behar duzu; adibidez:%n%nC:\APP%n%nedo UNC helburu bat forma honetan:%n%n\\server\share +InvalidDrive=Hautatu duzun gidagailua edo UNC elkarbanaketa ez dago edo sarbidea ezinezkoa da. Mesedez hautatu beste bat. +DiskSpaceWarningTitle=Ez Dago Nahikoa Toki Diskan +DiskSpaceWarning=Ezarpenak gutxienez %1 KB-eko toki askea behar du ezartzeko, baina hautaturiko gidagailuak %2 KB bakarrik ditu eskuragarri.%n%nHorrela ere jarraitzea nahi duzu? +DirNameTooLong=Agiritegi izena edo helburua luzeegia da. +InvalidDirName=Agiritegi izena ez da baliozkoa. +BadDirName32=Agiritegi izenek ezin dute hurrengo hizkietako bat ere izan:%n%n%1 +DirExistsTitle=Agiritegia Badago +DirExists=Agiritegia:%n%n%1%n%njadanik badago. Horrela ere agiritegi horretan ezartzea nahi duzu? +DirDoesntExistTitle=Agiritegia Ez Dago +DirDoesntExist=Agiritegia:%n%n%1%n%nez dago. Nahi duzu agiritegia sortzea? + +; *** "Select Components" wizard page +WizardSelectComponents=Hautatu Osagaiak +SelectComponentsDesc=Zer osagai ezarri behar dira? +SelectComponentsLabel2=Hautatu ezartzea nahi dituzun osagaiak; garbitu ezartzea nahi ez dituzun osagaiak. Klikatu Hurrengoa jarraitzeko gertu zaudenean. +FullInstallation=Ezarpen osoa +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Ezarpen trinkoa +CustomInstallation=Norbere ezarpena +NoUninstallWarningTitle=Osagaiak Badaude +NoUninstallWarning=Ezartzaileak atzeman du hurrengo osagaiak jadanik zure ordenagailuan ezarrita daudela:%n%n%1%n%nOsagai hauek deshautatuz gero ez dira ezarriko.%n%nHorrela ere jarraitzea nahi duzu? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel=Oraingo hautapenak gutxienez [mb] MB-eko tokia behar du diskan. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Hautatu Eginkizun Gehigarriak +SelectTasksDesc=Zer eginkizun gehigarri burutu behar dira? +SelectTasksLabel2=Hautatu Ezartzaileak [name]-ren ezarpenean zehar burutzea nahi dituzun eginkizun gehigarriak, orduan klikatu Hurrengoa + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Hautatu Hasiera Menuko Agiritegia +SelectStartMenuFolderDesc=Non ezarri behar ditu Ezartzaileak programaren lasterbideak? +SelectStartMenuFolderLabel3=Ezartzaileak programaren lasterbideak hurrengo Hasiera Menuko agiritegian sortuko ditu. +SelectStartMenuFolderBrowseLabel=Jarraitzeko, klikatu Hurrengoa. Beste agiritegi bat hautatzea nahi baduzu, klikatu Bilatu. +MustEnterGroupName=Agiritegi izen bat sartu behar duzu. +GroupNameTooLong=Agiritegi izena edo helburua luzeegia da. +InvalidGroupName=Agiritegi izena ez da baliozkoa. +BadGroupName=Agiritegi izenak ezin du hurrengo hizkietako bat ere izan:%n%n%1 +NoProgramGroupCheck2=&Ez sortu Hasiera Menuko agiritegia + +; *** "Ready to Install" wizard page +WizardReady=Ezartzeko Gertu +ReadyLabel1=Ezartzailea orain gertu dago [name] zure ordenagailuan ezartzeko. +ReadyLabel2a=Klikatu Ezarri ezarpenarekin jarraitzeko, edo klikatu Atzera ezarpenen bat berrikustea edo aldatzea nahi baduzu. +ReadyLabel2b=Klikatu Ezarri ezarpenarekin jarraitzeko. +ReadyMemoUserInfo=Erabiltzaile argibideak: +ReadyMemoDir=Helmuga kokalekua: +ReadyMemoType=Ezarpen mota: +ReadyMemoComponents=Hautaturiko osagaiak: +ReadyMemoGroup=Hasiera Menuko agiritegia: +ReadyMemoTasks=Eginkizun gehigarriak: + +; *** "Preparing to Install" wizard page +WizardPreparing=Ezartzeko Gertatzen +PreparingDesc=Ezartzailea [name] zure ordenagailuan ezartzeko gertatzen ari da. +PreviousInstallNotCompleted=Aurreko programaren ezartze/kentzea ez dago osatuta. Zure ordenagailua berrabiarazi behar duzu ezarpena osatzeko.%n%nZure ordenagailua berrabiarazi ondoren, ekin Ezartzailea berriro [name]-ren ezarpena osatzeko. +CannotContinue=Ezarpenak ezin du jarraitu. Mesedez klikatu Ezeztatu irtetzeko. +ApplicationsFound=Hurrengo aplikazioak Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari dira. Gomendagarria da Ezartzaileari aplikazio hauek berezgaitasunez istea ahalbidetzea. +ApplicationsFound2=Hurrengo aplikazioak Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari dira. Gomendagarria da Ezartzaileari aplikazio hauek berezgaitasunez istea ahalbidetzea. Ezarpena osatu ondoren, Ezartzailea aplikazioak berrabiarazten saiatuko da. +CloseApplications=&Berezgaitasunez itxi aplikazioak +DontCloseApplications=&Ez itxi aplikazioak +ErrorCloseApplications=Ezartzaileak ezin ditu berezgaitasunez aplikazio guztiak itxi. Gomendagarria da Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari diren aplikazio guztiak istea jarraitu aurretik. + +; *** "Installing" wizard page +WizardInstalling=Ezartzen +InstallingLabel=Mesedez itxaron Ezartzaileak [name] zure ordenagailuan ezartzen duen bitartean. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name] Ezarpen Laguntzailea osatzen +FinishedLabelNoIcons=Ezartzaileak amaitu du [name] zure ordenagailuan ezartzeaz. +FinishedLabel=Ezartzaileak amaitu du [name] zure ordenagailuan ezartzea. Aplikazioa ezarritako ikurren bidez abiarazi daiteke. +ClickFinish=Klikatu Amaitu Ezartzailetik irtetzeko. +FinishedRestartLabel=[name]-ren ezarpena osatzeko, Ezartzaileak zure ordenagailua berrabiarazi behar du. Orain berrabiaraztea nahi duzu? +FinishedRestartMessage=[name]-ren ezarpena osatzeko, Ezartzaileak zure ordenagailua berrabiarazi behar du.%n%nOrain berrabiaraztea nahi duzu? +ShowReadmeCheck=Bai, IRAKURRI agiria ikustea nahi dut +YesRadio=&Bai, berrabiarazi ordenagailua orain +NoRadio=&Ez, geroago berrabiaraziko dut ordenagailua +; used for example as 'Run MyProg.exe' +RunEntryExec=Ekin %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Ikusi %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Ezarpenak Hurrengo Diska Behar Du +SelectDiskLabel2=Mesedez txertatu %1 Diska eta klikatu Ongi.%n%nDiska honetako agiriak azpian erakutsitakoa ez den beste agiritegi batean aurkitu badaitezke, sartu helburu zuzena edo klikatu Bilatu. +PathLabel=&Helburua: +FileNotInDir2="%1" agiria ezin da hemen aurkitu: "%2". Mesedez txertatu diska zuzena edo hautatu beste agiritegi bat. +SelectDirectoryLabel=Mesedez adierazi hurrengo diskaren kokalekua. + +; *** Installation phase messages +SetupAborted=Ezarpena ez da osatu.%n%nMesedez zuzendu arazoa eta ekin Ezartzailea berriro. +EntryAbortRetryIgnore=Klikatu Bersaiatu berriro saiatzeko, Ezikusi horrela ere jarraitzeko, edo Utzi ezarpena ezeztatzeko. + +; *** Installation status messages +StatusClosingApplications=Aplikazioak isten... +StatusCreateDirs=Zuzenbideak sortzen... +StatusExtractFiles=Agiriak ateratzen... +StatusCreateIcons=Lasterbideak sortzen... +StatusCreateIniEntries=INI sarrerak sortzen... +StatusCreateRegistryEntries=Erregistro sarrerak sortzen... +StatusRegisterFiles=Agiriak erregistratzen... +StatusSavingUninstall=Kentze argibideak gordetzen... +StatusRunProgram=Ezarpena amaitzen... +StatusRestartingApplications=Aplikazioak berrabiarazten... +StatusRollback=Aldaketak leheneratzen... + +; *** Misc. errors +ErrorInternal2=Barneko akatsa: %1 +ErrorFunctionFailedNoCode=%1 hutsegitea +ErrorFunctionFailed=%1 hutsegitea; kodea %2 +ErrorFunctionFailedWithMessage=%1 hutsegitea; kodea %2.%n%3 +ErrorExecutingProgram=Ezinezkoa agiria exekutatzea:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Akatsa erregistro giltza irekitzerakoan:%n%1\%2 +ErrorRegCreateKey=Akatsa erregistro giltza sortzerakoan:%n%1\%2 +ErrorRegWriteKey=Akatsa erregistro giltza idazterakoan:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Akatsa INI sarrera "%1" agirian sortzerakoan. + +; *** File copying errors +FileAbortRetryIgnore=Klikatu Bersaiatu berriro saitzeko, Ezikusi agiri hau jauzteko (ez da gomendatua), edo Utzi ezarpena ezeztatzeko. +FileAbortRetryIgnore2=Klikatu Bersaiatu berriro saitzeko, Ezikusi horrela ere jarraitzeko (ez da gomendatua), edo Utzi ezarpena ezeztatzeko. +SourceIsCorrupted=Iturburu agiria hondatuta dago. +SourceDoesntExist="%1" iturburu agiria ez dago +ExistingFileReadOnly=Dagoen agiria irakurtzeko-bakarrik bezala markatuta dago.%n%nKlikatu Bersaiatu irakurtzeko-bakarrik ezaugarria kentzeko eta saiatu berriro, Ezikusi agiri hau jauzteko, edo Utzi ezarpena ezeztatzeko. +ErrorReadingExistingDest=Akats bat gertatu da dagoen agiria irakurtzen saiatzerakoan: +FileExists=Agiria jadanik badago.%n%nNahi duzu Ezartzaileak gainidaztea? +ExistingFileNewer=Dagoen agiria Ezartzailea ezartzen saiatzen ari dena baino berriagoa da. Gomendagarria da dagoen agiriari heustea.%n%nDagoen agiriari heustea nahi diozu? +ErrorChangingAttr=Akats bat gertatu da dagoen agiriaren ezaugarriak aldatzen saiatzerakoan: +ErrorCreatingTemp=Akats bat gertatu da helmuga zuzenbidean agiri bat sortzen saiatzerakoan: +ErrorReadingSource=Akats bat gertatu da iturburu agiria irakurtzen saiatzerakoan: +ErrorCopying=Akats bat gertatu da agiri bat kopiatzen saiatzerakoan: +ErrorReplacingExistingFile=Akats bat gertatu da dagoen agiria ordezten saiatzerakoan: +ErrorRestartReplace=Berrabiarazte-Ordezte hutsegitea: +ErrorRenamingTemp=Akats bat gertatu da helmuga zuzenbideko agiri bat berrizendatzen saiatzerakoan: +ErrorRegisterServer=Ezinezkoa DLL/OCX erregistratzea: %1 +ErrorRegSvr32Failed=RegSvr32 hutsegitea %1 irteera kodearekin +ErrorRegisterTypeLib=Ezinezkoa liburutegi mota erregistratzea: %1 + +; *** Post-installation errors +ErrorOpeningReadme=Akats bat gertatu da IRAKURRI agiria irekitzen saiatzerakoan. +ErrorRestartingComputer=Ezartzaileak ezin du ordenagailua berrabiarazi. Mesedez egin hau eskuz. + +; *** Uninstaller messages +UninstallNotFound="%1" agiria ez dago. Ezinezkoa kentzea +UninstallOpenError="%1" agiria ezin da ireki. Ezinezkoa kentzea +UninstallUnsupportedVer="%1" kentze ohar agiria kentzaile bertsio honek ezagutzen ez duen heuskarri batean dago. Ezinezkoa kentzea. +UninstallUnknownEntry=Sarrera ezezagun bat (%1) aurkitu da kentze oharrean +ConfirmUninstall=Zihur zaude %1 eta bere osagai guztiak erabat kentzea nahi dituzula? +UninstallOnlyOnWin64=Ezarpen hau 64-biteko Windows-etik bakarrik kendu daiteke. +OnlyAdminCanUninstall=Ezarpen hau administrari pribilegioak dituen erabiltzaile batek bakarrik kendu dezake. +UninstallStatusLabel=Mesedez itxaron %1 zure ordenagailutik kentzen den bitartean. +UninstalledAll=%1 ongi kendu da zure ordenagailutik. +UninstalledMost=%1-ren kentzea osatuta.%n%nZenbait gai ezin izan dira kendu. Hauek eskuz kendu daitezke. +UninstalledAndNeedsRestart=%1-ren kentzea osatzeko, zure ordenagailua berrabiarazi behar duzu.%n%nOrain berrabiaraztea nahi duzu? +UninstallDataCorrupted="%1" agiria hondatuta da. Ezinezkoa kentzea + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Ezabatu Agiri Elkarbanatua? +ConfirmDeleteSharedFile2=Sistemaren arabera hurrengo agiri elkarbanatua ez du inongo programak erabiliko hemendik aurrera. Kentzaileak agiri hau ezabatu dezan nahi duzu?%n%nProgramaren bat agiri hau erabiltzen ari da oraindik eta ezabatzen baduzu, programa hori ez da egoki ibiliko. Zihur ez bazaude, hautatu Ez. Agiria sisteman uzteak ez du inongo kalterik eragingo. +SharedFileNameLabel=Agiri izena: +SharedFileLocationLabel=Kokalekua: +WizardUninstalling=Kentze Egoera +StatusUninstalling=Kentzen %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Ezartzen %1. +ShutdownBlockReasonUninstallingApp=Kentzen %1. +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] +;Inno Setup Built-in Custom Messages +NameAndVersion=%1 %2 bertsioa +AdditionalIcons=Ikur gehigarriak: +CreateDesktopIcon=Sortu &mahaigain ikurra +CreateQuickLaunchIcon=Sortu &Abiarazpen Azkarreko ikurra +ProgramOnTheWeb=%1 Webean +UninstallProgram=Kendu %1 +LaunchProgram=Abiarazi %1 +AssocFileExtension=&Elkartu %1 programa %2 agiri luzapenarekin +AssocingFileExtension=%1 programa %2 agiri luzapenarekin elkartzen... +AutoStartProgramGroupDescription=Abirazpena: +AutoStartProgram=Berezgaitasunez abiarazi %1 +AddonHostProgramNotFound=%1 ezin da aurkitu hautatu duzun agiritegian.%n%nHorrela ere jarraitzea nahi duzu? diff --git a/distrib/Languages/Belarusian.isl b/distrib/Languages/Belarusian.isl index 25f616df81b..9bd129cd837 100644 --- a/distrib/Languages/Belarusian.isl +++ b/distrib/Languages/Belarusian.isl @@ -1,319 +1,319 @@ -; *** Inno Setup version 5.5.3+ Belarusian messages *** -; -; Translated by Aleg Azarousky, http://belazar.info/belsoft/ -; E-mail: olegtut@tut.by - -[LangOptions] -LanguageName=<0411><0435><043B><0430><0440><0443><0441><043A><0430><044F> -LanguageID=$0423 -LanguageCodePage=1251 - -[Messages] - -; *** Application titles -SetupAppTitle= -SetupWindowTitle= %1 -UninstallAppTitle= -UninstallAppFullTitle= %1 - -; *** Misc. common -InformationTitle= -ConfirmTitle= -ErrorTitle= - -; *** SetupLdr messages -SetupLdrStartupMessage= %1. ? -LdrCannotCreateTemp= . -LdrCannotExecTemp= . 븢 - -; *** Startup error messages -LastErrorMessage=%1.%n%n %2: %3 -SetupFileMissing= %1 . , , . -SetupFileCorrupt= 븢 . , . -SetupFileCorruptOrWrongVer= 븢 븢. , , . -InvalidParameter= :%n%n%1 -SetupAlreadyRunning= . -WindowsVersionNotSupported= Windows . -WindowsServicePackRequired= %1 Service Pack %2 . -NotOnThisPlatform= %1. -OnlyOnThisPlatform= %1. -OnlyOnTheseArchitectures= Windows :%n%n%1 -MissingWOW64APIs= Windows 64- . , (Service Pack) %1. -WinVersionTooLowError= %1 %2 . -WinVersionTooHighError= %1 %2 . -AdminPrivilegesRequired= , . -PowerUserPrivilegesRequired= , . -SetupAppRunningError=, %1!%n%n , , - . -UninstallAppRunningError=, %1!%n%n , , , - . - -; *** Misc. errors -ErrorCreatingDir= %1 -ErrorTooManyFilesInDir= %1, - -; *** Setup common messages -ExitSetupTitle= -ExitSetupMessage= . , .%n%n 븢 , .%n%n 븢? -AboutSetupMenuItem= ... -AboutSetupTitle= -AboutSetupMessage=%1, %2%n%3%n%n %1:%n%4 -AboutSetupNote= -TranslatorNote=Belarusian translation by Aleg Azarousky, http://belazar.info/belsoft/ - -; *** Buttons -ButtonBack=< & -ButtonNext=& > -ButtonInstall=& -ButtonOK= -ButtonCancel= -ButtonYes=& -ButtonYesToAll= & -ButtonNo=& -ButtonNoToAll=& -ButtonFinish= -ButtonBrowse=&... -ButtonWizardBrowse=&... -ButtonNewFolder=& - -; *** "Select Language" dialog messages -SelectLanguageTitle= 븢 -SelectLanguageLabel= : - -; *** Common wizard text -ClickNext= , - . -BeveledLabel=InnoSetup -BrowseDialogTitle= -BrowseDialogLabel= . -NewFolderName= - -; *** "Welcome" wizard page -WelcomeLabel1= [name] -WelcomeLabel2= [name/ver] .%n%n , . - -; *** "Password" wizard page -WizardPassword= -PasswordLabel1=븢 . -PasswordLabel3= , . . -PasswordEditLabel=&: -IncorrectPassword=ճ . . - -; *** "License Agreement" wizard page -WizardLicense=˳ -LicenseLabel= , , . -LicenseLabel3= , . . -LicenseAccepted= & -LicenseNotAccepted= & - -; *** "Information" wizard pages -WizardInfoBefore= -InfoBeforeLabel= . -InfoBeforeClickLabel= , . -WizardInfoAfter= -InfoAfterLabel= . -InfoAfterClickLabel= , . - -; *** "User Information" wizard page -WizardUserInfo= -UserInfoDesc= , . -UserInfoName= : -UserInfoOrg=&: -UserInfoSerial=& : -UserInfoNameRequired= . - -; *** "Select Destination Location" wizard page -WizardSelectDir= -SelectDirDesc= [name]? -SelectDirLabel3= [name] : -SelectDirBrowseLabel= . , . -DiskSpaceMBLabel= [mb] . -CannotInstallToNetworkDrive= . -CannotInstallToUNCPath= UNC-. -InvalidPath= , :%n%nC:\APP%n%n UNC:%n%n\\\ -InvalidDrive= . , . -DiskSpaceWarningTitle= -DiskSpaceWarning=븢 %1 , %2 .%n%n ? -DirNameTooLong= . -InvalidDirName= . -BadDirName32= :%n%n%1 -DirExistsTitle= -DirExists=:%n%n%1%n%n . ? -DirDoesntExistTitle= -DirDoesntExist=:%n%n%1%n%n . ? - -; *** "Select Components" wizard page -WizardSelectComponents= -SelectComponentsDesc= ? -SelectComponentsLabel2= , 븢; . , . -FullInstallation= -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation= -CustomInstallation= -NoUninstallWarningTitle= -NoUninstallWarning=, :%n%n%1%n%n , .%n%n ? -ComponentSize1=%1 -ComponentSize2=%1 -ComponentsDiskSpaceMBLabel= [mb] . - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks= -SelectTasksDesc= ? -SelectTasksLabel2= , [name], . - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup= -SelectStartMenuFolderDesc= , . -SelectStartMenuFolderLabel3= . -SelectStartMenuFolderBrowseLabel= - . - . -MustEnterGroupName= . -GroupNameTooLong= . -InvalidGroupName= . -BadGroupName= :%n%n%1 -NoProgramGroupCheck2=& - -; *** "Ready to Install" wizard page -WizardReady= -ReadyLabel1= [name] . -ReadyLabel2a= , - . -ReadyLabel2b= . -ReadyMemoUserInfo= : -ReadyMemoDir= : -ReadyMemoType= 븢: -ReadyMemoComponents= : -ReadyMemoGroup= : -ReadyMemoTasks= : - -; *** "Preparing to Install" wizard page -WizardPreparing= -PreparingDesc= [name] . -PreviousInstallNotCompleted= . , .%n%n 븢 , [name]. -CannotContinue= . . -ApplicationsFound= , 븢 . 븢 . -ApplicationsFound2= , 븢 . 븢 . , 븢 . -CloseApplications=& -DontCloseApplications=& -ErrorCloseApplications=븢 . , , . - -; *** "Installing" wizard page -WizardInstalling= -InstallingLabel=, [name] 븢 . - -; *** "Setup Completed" wizard page -FinishedHeadingLabel= [name]. -FinishedLabelNoIcons= [name] . -FinishedLabel= [name] . . -ClickFinish= , 븢. -FinishedRestartLabel= [name] . ? -FinishedRestartMessage= [name] .%n%n ? -ShowReadmeCheck= -YesRadio=&, -NoRadio=&, -; used for example as 'Run MyProg.exe' -RunEntryExec= %1 -; used for example as 'View Readme.txt' -RunEntryShellExec= %1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle= -SelectDiskLabel2= %1 .%n%n , , , . -PathLabel=&: -FileNotInDir2= %1 %2. . -SelectDirectoryLabel= . - -; *** Installation phase messages -SetupAborted= .%n%n , 븢 -EntryAbortRetryIgnore= , , - , - . - -; *** Installation status messages -StatusClosingApplications= ... -StatusCreateDirs= ... -StatusExtractFiles= ... -StatusCreateIcons= ... -StatusCreateIniEntries= INI-... -StatusCreateRegistryEntries= ... -StatusRegisterFiles= ... -StatusSavingUninstall= ... -StatusRunProgram= ... -StatusRestartingApplications= ... -StatusRollback= ... - -; *** Misc. errors -ErrorInternal2= %1 -ErrorFunctionFailedNoCode=%1: -ErrorFunctionFailed=%1: ; %2 -ErrorFunctionFailedWithMessage=%1: ; %2.%n%3 -ErrorExecutingProgram= :%n%1 - -; *** Registry errors -ErrorRegOpenKey= :%n%1\%2 -ErrorRegCreateKey= :%n%1\%2 -ErrorRegWriteKey= :%n%1\%2 - -; *** INI errors -ErrorIniEntry= INI- %1. - -; *** File copying errors -FileAbortRetryIgnore= , , - ( ), - . -FileAbortRetryIgnore2= , , - ( ), - . -SourceIsCorrupted= . -SourceDoesntExist= %1 . -ExistingFileReadOnly= .%n%n , , - , - . -ErrorReadingExistingDest= : -FileExists= .%n%n ? -ExistingFileNewer= , 븢. .%n%n ? -ErrorChangingAttr= : -ErrorCreatingTemp= : -ErrorReadingSource= : -ErrorCopying= : -ErrorReplacingExistingFile= : -ErrorRestartReplace= : -ErrorRenamingTemp= : -ErrorRegisterServer= DLL/OCX: %1 -ErrorRegSvr32Failed= RegSvr32, %1 -ErrorRegisterTypeLib= : %1 - -; *** Post-installation errors -ErrorOpeningReadme= README: -ErrorRestartingComputer=븢 . . - -; *** Uninstaller messages -UninstallNotFound= %1 , . -UninstallOpenError= %1, . -UninstallUnsupportedVer= %1 븢. . -UninstallUnknownEntry= (%1) -ConfirmUninstall= %1 ? -UninstallOnlyOnWin64= 64- Windows. -OnlyAdminCanUninstall= . -UninstallStatusLabel=, %1 . -UninstalledAll= %1 . -UninstalledMost= %1 .%n%n . . -UninstalledAndNeedsRestart= %1, .%n%nֳ ? -UninstallDataCorrupted= %1 . . - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle= ? -ConfirmDeleteSharedFile2=ѳ , . ?%n%n , , . - . . -SharedFileNameLabel= : -SharedFileLocationLabel=: -WizardUninstalling= -StatusUninstalling= %1... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp= %1. -ShutdownBlockReasonUninstallingApp= %1. - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] - -NameAndVersion=%1, %2 -AdditionalIcons= : -CreateDesktopIcon= & -CreateQuickLaunchIcon= & -ProgramOnTheWeb= %1 -UninstallProgram= %1 -LaunchProgram= %1 -AssocFileExtension=& %1 %2 -AssocingFileExtension= %1 %2... -AutoStartProgramGroupDescription=: -AutoStartProgram= %1 -AddonHostProgramNotFound=%1 .%n%n ? +; *** Inno Setup version 5.5.3+ Belarusian messages *** +; +; Translated by Aleg Azarousky, http://belazar.info/belsoft/ +; E-mail: olegtut@tut.by + +[LangOptions] +LanguageName=<0411><0435><043B><0430><0440><0443><0441><043A><0430><044F> +LanguageID=$0423 +LanguageCodePage=1251 + +[Messages] + +; *** Application titles +SetupAppTitle= +SetupWindowTitle= %1 +UninstallAppTitle= +UninstallAppFullTitle= %1 + +; *** Misc. common +InformationTitle= +ConfirmTitle= +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage= %1. ? +LdrCannotCreateTemp= . +LdrCannotExecTemp= . 븢 + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing= %1 . , , . +SetupFileCorrupt= 븢 . , . +SetupFileCorruptOrWrongVer= 븢 븢. , , . +InvalidParameter= :%n%n%1 +SetupAlreadyRunning= . +WindowsVersionNotSupported= Windows . +WindowsServicePackRequired= %1 Service Pack %2 . +NotOnThisPlatform= %1. +OnlyOnThisPlatform= %1. +OnlyOnTheseArchitectures= Windows :%n%n%1 +MissingWOW64APIs= Windows 64- . , (Service Pack) %1. +WinVersionTooLowError= %1 %2 . +WinVersionTooHighError= %1 %2 . +AdminPrivilegesRequired= , . +PowerUserPrivilegesRequired= , . +SetupAppRunningError=, %1!%n%n , , - . +UninstallAppRunningError=, %1!%n%n , , , - . + +; *** Misc. errors +ErrorCreatingDir= %1 +ErrorTooManyFilesInDir= %1, + +; *** Setup common messages +ExitSetupTitle= +ExitSetupMessage= . , .%n%n 븢 , .%n%n 븢? +AboutSetupMenuItem= ... +AboutSetupTitle= +AboutSetupMessage=%1, %2%n%3%n%n %1:%n%4 +AboutSetupNote= +TranslatorNote=Belarusian translation by Aleg Azarousky, http://belazar.info/belsoft/ + +; *** Buttons +ButtonBack=< & +ButtonNext=& > +ButtonInstall=& +ButtonOK= +ButtonCancel= +ButtonYes=& +ButtonYesToAll= & +ButtonNo=& +ButtonNoToAll=& +ButtonFinish= +ButtonBrowse=&... +ButtonWizardBrowse=&... +ButtonNewFolder=& + +; *** "Select Language" dialog messages +SelectLanguageTitle= 븢 +SelectLanguageLabel= : + +; *** Common wizard text +ClickNext= , - . +BeveledLabel=InnoSetup +BrowseDialogTitle= +BrowseDialogLabel= . +NewFolderName= + +; *** "Welcome" wizard page +WelcomeLabel1= [name] +WelcomeLabel2= [name/ver] .%n%n , . + +; *** "Password" wizard page +WizardPassword= +PasswordLabel1=븢 . +PasswordLabel3= , . . +PasswordEditLabel=&: +IncorrectPassword=ճ . . + +; *** "License Agreement" wizard page +WizardLicense=˳ +LicenseLabel= , , . +LicenseLabel3= , . . +LicenseAccepted= & +LicenseNotAccepted= & + +; *** "Information" wizard pages +WizardInfoBefore= +InfoBeforeLabel= . +InfoBeforeClickLabel= , . +WizardInfoAfter= +InfoAfterLabel= . +InfoAfterClickLabel= , . + +; *** "User Information" wizard page +WizardUserInfo= +UserInfoDesc= , . +UserInfoName= : +UserInfoOrg=&: +UserInfoSerial=& : +UserInfoNameRequired= . + +; *** "Select Destination Location" wizard page +WizardSelectDir= +SelectDirDesc= [name]? +SelectDirLabel3= [name] : +SelectDirBrowseLabel= . , . +DiskSpaceMBLabel= [mb] . +CannotInstallToNetworkDrive= . +CannotInstallToUNCPath= UNC-. +InvalidPath= , :%n%nC:\APP%n%n UNC:%n%n\\\ +InvalidDrive= . , . +DiskSpaceWarningTitle= +DiskSpaceWarning=븢 %1 , %2 .%n%n ? +DirNameTooLong= . +InvalidDirName= . +BadDirName32= :%n%n%1 +DirExistsTitle= +DirExists=:%n%n%1%n%n . ? +DirDoesntExistTitle= +DirDoesntExist=:%n%n%1%n%n . ? + +; *** "Select Components" wizard page +WizardSelectComponents= +SelectComponentsDesc= ? +SelectComponentsLabel2= , 븢; . , . +FullInstallation= +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation= +CustomInstallation= +NoUninstallWarningTitle= +NoUninstallWarning=, :%n%n%1%n%n , .%n%n ? +ComponentSize1=%1 +ComponentSize2=%1 +ComponentsDiskSpaceMBLabel= [mb] . + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks= +SelectTasksDesc= ? +SelectTasksLabel2= , [name], . + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup= +SelectStartMenuFolderDesc= , . +SelectStartMenuFolderLabel3= . +SelectStartMenuFolderBrowseLabel= - . - . +MustEnterGroupName= . +GroupNameTooLong= . +InvalidGroupName= . +BadGroupName= :%n%n%1 +NoProgramGroupCheck2=& + +; *** "Ready to Install" wizard page +WizardReady= +ReadyLabel1= [name] . +ReadyLabel2a= , - . +ReadyLabel2b= . +ReadyMemoUserInfo= : +ReadyMemoDir= : +ReadyMemoType= 븢: +ReadyMemoComponents= : +ReadyMemoGroup= : +ReadyMemoTasks= : + +; *** "Preparing to Install" wizard page +WizardPreparing= +PreparingDesc= [name] . +PreviousInstallNotCompleted= . , .%n%n 븢 , [name]. +CannotContinue= . . +ApplicationsFound= , 븢 . 븢 . +ApplicationsFound2= , 븢 . 븢 . , 븢 . +CloseApplications=& +DontCloseApplications=& +ErrorCloseApplications=븢 . , , . + +; *** "Installing" wizard page +WizardInstalling= +InstallingLabel=, [name] 븢 . + +; *** "Setup Completed" wizard page +FinishedHeadingLabel= [name]. +FinishedLabelNoIcons= [name] . +FinishedLabel= [name] . . +ClickFinish= , 븢. +FinishedRestartLabel= [name] . ? +FinishedRestartMessage= [name] .%n%n ? +ShowReadmeCheck= +YesRadio=&, +NoRadio=&, +; used for example as 'Run MyProg.exe' +RunEntryExec= %1 +; used for example as 'View Readme.txt' +RunEntryShellExec= %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle= +SelectDiskLabel2= %1 .%n%n , , , . +PathLabel=&: +FileNotInDir2= %1 %2. . +SelectDirectoryLabel= . + +; *** Installation phase messages +SetupAborted= .%n%n , 븢 +EntryAbortRetryIgnore= , , - , - . + +; *** Installation status messages +StatusClosingApplications= ... +StatusCreateDirs= ... +StatusExtractFiles= ... +StatusCreateIcons= ... +StatusCreateIniEntries= INI-... +StatusCreateRegistryEntries= ... +StatusRegisterFiles= ... +StatusSavingUninstall= ... +StatusRunProgram= ... +StatusRestartingApplications= ... +StatusRollback= ... + +; *** Misc. errors +ErrorInternal2= %1 +ErrorFunctionFailedNoCode=%1: +ErrorFunctionFailed=%1: ; %2 +ErrorFunctionFailedWithMessage=%1: ; %2.%n%3 +ErrorExecutingProgram= :%n%1 + +; *** Registry errors +ErrorRegOpenKey= :%n%1\%2 +ErrorRegCreateKey= :%n%1\%2 +ErrorRegWriteKey= :%n%1\%2 + +; *** INI errors +ErrorIniEntry= INI- %1. + +; *** File copying errors +FileAbortRetryIgnore= , , - ( ), - . +FileAbortRetryIgnore2= , , - ( ), - . +SourceIsCorrupted= . +SourceDoesntExist= %1 . +ExistingFileReadOnly= .%n%n , , - , - . +ErrorReadingExistingDest= : +FileExists= .%n%n ? +ExistingFileNewer= , 븢. .%n%n ? +ErrorChangingAttr= : +ErrorCreatingTemp= : +ErrorReadingSource= : +ErrorCopying= : +ErrorReplacingExistingFile= : +ErrorRestartReplace= : +ErrorRenamingTemp= : +ErrorRegisterServer= DLL/OCX: %1 +ErrorRegSvr32Failed= RegSvr32, %1 +ErrorRegisterTypeLib= : %1 + +; *** Post-installation errors +ErrorOpeningReadme= README: +ErrorRestartingComputer=븢 . . + +; *** Uninstaller messages +UninstallNotFound= %1 , . +UninstallOpenError= %1, . +UninstallUnsupportedVer= %1 븢. . +UninstallUnknownEntry= (%1) +ConfirmUninstall= %1 ? +UninstallOnlyOnWin64= 64- Windows. +OnlyAdminCanUninstall= . +UninstallStatusLabel=, %1 . +UninstalledAll= %1 . +UninstalledMost= %1 .%n%n . . +UninstalledAndNeedsRestart= %1, .%n%nֳ ? +UninstallDataCorrupted= %1 . . + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle= ? +ConfirmDeleteSharedFile2=ѳ , . ?%n%n , , . - . . +SharedFileNameLabel= : +SharedFileLocationLabel=: +WizardUninstalling= +StatusUninstalling= %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp= %1. +ShutdownBlockReasonUninstallingApp= %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1, %2 +AdditionalIcons= : +CreateDesktopIcon= & +CreateQuickLaunchIcon= & +ProgramOnTheWeb= %1 +UninstallProgram= %1 +LaunchProgram= %1 +AssocFileExtension=& %1 %2 +AssocingFileExtension= %1 %2... +AutoStartProgramGroupDescription=: +AutoStartProgram= %1 +AddonHostProgramNotFound=%1 .%n%n ? diff --git a/distrib/Languages/ChineseSimplified.isl b/distrib/Languages/ChineseSimplified.isl index 22c29815a0b..6029850d5cd 100644 --- a/distrib/Languages/ChineseSimplified.isl +++ b/distrib/Languages/ChineseSimplified.isl @@ -1,337 +1,337 @@ -; *** Inno Setup version 5.5.3+ Chinese (Simplified) messages *** -; By Qiming Li (qiming at clault.com) -; -; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ -; -; Note: When translating this text, do not add periods (.) to the end of -; messages that didn't have them already, because on those messages Inno -; Setup adds the periods automatically (appending a period would result in -; two periods being displayed). - -[LangOptions] -; The following three entries are very important. Be sure to read and -; understand the '[LangOptions] section' topic in the help file. -LanguageName=<4E2D><6587><7B80><4F53> -LanguageID=$0804 -LanguageCodePage=936 -; If the language you are translating to requires special font faces or -; sizes, uncomment any of the following entries and change them accordingly. -DialogFontName= -;DialogFontSize=8 -;WelcomeFontName=Verdana -;WelcomeFontSize=12 -;TitleFontName=Arial -;TitleFontSize=29 -;CopyrightFontName=Arial -;CopyrightFontSize=8 - -[Messages] - -; *** Application titles -SetupAppTitle=װ -SetupWindowTitle=װ - %1 -UninstallAppTitle=ж -UninstallAppFullTitle=%1ж - -; *** Misc. common -InformationTitle=Ϣ -ConfirmTitle=ȷ -ErrorTitle= - -; *** SetupLdr messages -SetupLdrStartupMessage=װ򵼽ĵϰװ%1ȷҪ -LdrCannotCreateTemp=޷ʱļװֹ -LdrCannotExecTemp=޷ʱļеļװֹ - -; *** Startup error messages -LastErrorMessage=%1.%n%n %2: %3 -SetupFileMissing=װĿ¼ȱʧļ%1⣬»ȡһݳ򿽱 -SetupFileCorrupt=װļѱ𻵡»ȡһݳ򿽱 -SetupFileCorruptOrWrongVer=װļѱ𻵣뱾װ򵼰汾ݡ⣬»ȡһݳ򿽱 -InvalidParameter=Чв%n%n%1 -SetupAlreadyRunning=װѾС -WindowsVersionNotSupported=֧еWindows汾 -WindowsServicePackRequired=Ҫ%1 Service Pack %2°汾 -NotOnThisPlatform=򲻿%1С -OnlyOnThisPlatform=%1С -OnlyOnTheseArchitectures=ֻΪ´ܹƵWindows汾ϰװ%n%n%1 -MissingWOW64APIs=ʹõWindows汾ûа64λװĹܡ밲װService Pack %1⡣ -WinVersionTooLowError=Ҫ%2汾ϵ%1 -WinVersionTooHighError=򲻿ɰװ%2߰汾%1ϡ -AdminPrivilegesRequired=¼ΪԱܰװ˳ -PowerUserPrivilegesRequired=¼ΪԱȨûܰװ˳ -SetupAppRunningError=װ򵼼⵽%1С%n%nرдڲȷȡ˳װ -UninstallAppRunningError=ж򵼼⵽%1С%n%nرдڣȻȷȡ˳ - -; *** Misc. errors -ErrorCreatingDir=װ޷ļС%1 -ErrorTooManyFilesInDir=ļС%1ļ࣬޷дļ - -; *** Setup common messages -ExitSetupTitle=˳װ -ExitSetupMessage=װδɡ˳򽫲ᱻװ %n%n´аװɳİװ%n%nȷ˳װ -AboutSetupMenuItem=ڰװ(&A) -AboutSetupTitle=ڰװ -AboutSetupMessage=%1汾%2%n%3%n%n%1ҳ%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< һ(&B) -ButtonNext=һ(&N) > -ButtonInstall=װ(&I) -ButtonOK=ȷ -ButtonCancel=ȡ -ButtonYes=(&Y) -ButtonYesToAll=ȫѡ(&A) -ButtonNo=(&N) -ButtonNoToAll=ȫѡ(&O) -ButtonFinish=(&F) -ButtonBrowse=(&B) -ButtonWizardBrowse=(&R) -ButtonNewFolder=ļ(&M) - -; *** "Select Language" dialog messages -SelectLanguageTitle=ѡ -SelectLanguageLabel=ѡװʱʹԣ - -; *** Common wizard text -ClickNext=һȡ˳װ򵼡 -BeveledLabel= -BrowseDialogTitle=ѡļ -BrowseDialogLabel=бѡȡһļУȷ -NewFolderName=½ļ - -; *** "Welcome" wizard page -WelcomeLabel1=ӭʹ[name]װ -WelcomeLabel2=򵼽ĵϰװ[name/ver]%n%nڼ֮ǰرӦó - -; *** "Password" wizard page -WizardPassword= -PasswordLabel1=װ뱣 -PasswordLabel3=룬һִСд -PasswordEditLabel=(&P) -IncorrectPassword=벻ȷԡ - -; *** "License Agreement" wizard page -WizardLicense=Э -LicenseLabel=ĶҪϢȻٽһ -LicenseLabel3=ĶЭ顣ܴЭȻܼװ -LicenseAccepted=ҽЭ(&A) -LicenseNotAccepted=ҲЭ(&D) - -; *** "Information" wizard pages -WizardInfoBefore=Ϣ -InfoBeforeLabel=ĶҪϢٽһ -InfoBeforeClickLabel=׼üװ󣬵һ -WizardInfoAfter=Ϣ -InfoAfterLabel=ĶҪϢٽһ -InfoAfterClickLabel=׼üװ󣬵һ - -; *** "User Information" wizard page -WizardUserInfo=ûϢ -UserInfoDesc=Ϣ -UserInfoName=û(&U) -UserInfoOrg=(&O) -UserInfoSerial=к(&S) -UserInfoNameRequired=û - -; *** "Select Destination Location" wizard page -WizardSelectDir=ѡװλ -SelectDirDesc=[name]װδ -SelectDirLabel3=װ򵼽[name]װļС -SelectDirBrowseLabel=һҪѡͬļУ -DiskSpaceMBLabel=[mb]ֽڣMBô̿ռ䡣 -CannotInstallToNetworkDrive=޷װ -CannotInstallToUNCPath=޷װUNC· -InvalidPath=̷·磺%n%nC:\Ӧó%n%n¸ʽUNC·%n%n\\\Ŀ¼ -InvalidDrive=ѡUNCڻ򲻿ɷʡѡһ -DiskSpaceWarningTitle=̿ռ䲻 -DiskSpaceWarning=%1ǧֽڣKBÿռſɰװѡ%2ǧֽڣKBÿռ䡣%n%nȷҪ -DirNameTooLong=ļƻ·̫ -InvalidDirName=ļЧ -BadDirName32=ļƲַܰ%n%n%1 -DirExistsTitle=ļѴ -DirExists=ļ%n%n%1%n%nѴڡȷҪװļ -DirDoesntExistTitle=ļв -DirDoesntExist=ļ%n%n%1%n%nڡҪļ - -; *** "Select Components" wizard page -WizardSelectComponents=ѡ -SelectComponentsDesc=ҪװЩ -SelectComponentsLabel2=ѡҪװҪװ׼úһ -FullInstallation=ȫװ -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=లװ -CustomInstallation=Զ尲װ -NoUninstallWarningTitle=Ѵ -NoUninstallWarning=װ򵼼⵽Ѿװ%n%n%1%n%nȡѡжЩ%n%nȷҪװ -ComponentSize1=%1ǧֽڣKB -ComponentSize2=%1ֽڣMB -ComponentsDiskSpaceMBLabel=ĿǰѡҪ[mb]ֽڣMB̿ռ䡣 - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=ѡ񸽼 -SelectTasksDesc=ҪִЩ -SelectTasksLabel2=ѡװ[name]ʱҪִеĸȻһ - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=ѡʼ˵ļ -SelectStartMenuFolderDesc=ѳݷʽŵ -SelectStartMenuFolderLabel3=װ򵼽¿ʼ˵ļдݷʽ -SelectStartMenuFolderBrowseLabel=һҪѡһļУ -MustEnterGroupName=ļ -GroupNameTooLong=ļƻ·̫ -InvalidGroupName=ļЧ -BadGroupName=ļƲַܰ%n%n%1 -NoProgramGroupCheck2=Ҫʼ˵ļ(&D) - -; *** "Ready to Install" wizard page -WizardReady=װ׼ -ReadyLabel1=װ׼ϣʼĵϰװ[name] -ReadyLabel2a=װʼװҪȷϻһ -ReadyLabel2b=װʼװ -ReadyMemoUserInfo=ûϢ -ReadyMemoDir=װλã -ReadyMemoType=װͣ -ReadyMemoComponents=ѡ -ReadyMemoGroup=ʼ˵ļУ -ReadyMemoTasks= - -; *** "Preparing to Install" wizard page -WizardPreparing=׼װ -PreparingDesc=װ׼ĵϰװ[name] -PreviousInstallNotCompleted=ϴγװ/жδɡҪϴΰװ%n%n֮аװװ[name] -CannotContinue=װ޷ȡ˳ -ApplicationsFound=װҪµļӦóռáװԶرЩӦó -ApplicationsFound2=װҪµļӦóռáװԶرЩӦó򡣰װɺ󣬰װ򵼽ЩӦó -CloseApplications=ԶرӦó(&A) -DontCloseApplications=ԶرӦó(&D) -ErrorCloseApplications=װ޷ԶرеӦóڽһ֮ǰرЩռðװҪļӦó - -; *** "Installing" wizard page -WizardInstalling=ڰװ -InstallingLabel=Ժ򣬰װĵϰװ[name] - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=[name]װ -FinishedLabelNoIcons=װĵϰװ[name] -FinishedLabel=װĵϰװ[name]ͨѰװĿݷʽ򿪴Ӧó -ClickFinish=˳װ -FinishedRestartLabel=Ϊ[name]İװװ򵼱ĵԡҪ -FinishedRestartMessage=Ϊ[name]İװװ򵼱ĵԡ%n%nҪ -ShowReadmeCheck=ǣҪĶļ -YesRadio=ǣ(&Y) -NoRadio=Ժ(&N) -; used for example as 'Run MyProg.exe' -RunEntryExec=%1 -; used for example as 'View Readme.txt' -RunEntryShellExec=%1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=װҪһŴ -SelectDiskLabel2=%1 ȷ%n%nôеļʾļУȷ· -PathLabel=·(&P) -FileNotInDir2=ļ%1ڡ%2СȷĴ̻ѡļС -SelectDirectoryLabel=ָһŴ̵λá - -; *** Installation phase messages -SetupAborted=װδɡ%n%nаװ򵼡 -EntryAbortRetryIgnore=ԡ³ԣԡװֹȡװ - -; *** Installation status messages -StatusClosingApplications=ڹرӦó -StatusCreateDirs=ڴļС -StatusExtractFiles=ȡļ -StatusCreateIcons=ڴݷʽ -StatusCreateIniEntries=ڴINIĿ -StatusCreateRegistryEntries=ڴעĿ -StatusRegisterFiles=ڴעĿ -StatusSavingUninstall=ڱжϢ -StatusRunProgram=ڽװ -StatusRestartingApplications=Ӧó -StatusRollback=ڳġ - -; *** Misc. errors -ErrorInternal2=ڲ%1 -ErrorFunctionFailedNoCode=%1ʧ -ErrorFunctionFailed=%1ʧܣ%2 -ErrorFunctionFailedWithMessage=%1ʧܣ%2%n%3 -ErrorExecutingProgram=޷г%n%1 - -; *** Registry errors -ErrorRegOpenKey=עʱ%n%1\%2 -ErrorRegCreateKey=עʱ%n%1\%2 -ErrorRegWriteKey=дעʱ%n%1\%2 - -; *** INI errors -ErrorIniEntry=ļ%1дINIĿʱ - -; *** File copying errors -FileAbortRetryIgnore=ԡ³ԣԡļƼֹȡװ -FileAbortRetryIgnore2=ԡ³ԣԡװƼֹȡװ -SourceIsCorrupted=Դļ -SourceDoesntExist=Դļ%1 -ExistingFileReadOnly=ļΪֻ%n%nԡƳֻԲ³ԣԡļֹȡװ -ErrorReadingExistingDest=ȡļʱ -FileExists=ļѴڡ%n%nðװ򵼸 -ExistingFileNewer=ļȰװͼװĻҪ¡鱣ļ%n%nҪļ -ErrorChangingAttr=ļʱ -ErrorCreatingTemp=Ŀļдļʱ -ErrorReadingSource=ȡԴļʱ -ErrorCopying=ļʱ -ErrorReplacingExistingFile=滻ļʱ -ErrorRestartReplace=滻ʧܣ -ErrorRenamingTemp=ΪĿļļʱ -ErrorRegisterServer=޷עᶯ̬ؼDLL/OCX%1 -ErrorRegSvr32Failed=RegSvr32ʧܣ䷵ֵΪ%1 -ErrorRegisterTypeLib=޷עͿ⣺%1 - -; *** Post-installation errors -ErrorOpeningReadme=ļʱ -ErrorRestartingComputer=װ޷ԡֶ - -; *** Uninstaller messages -UninstallNotFound=ļ%1ڡ޷жء -UninstallOpenError=޷ļ%1޷ж -UninstallUnsupportedVer=˰汾ж޷ʶж־ļ%1ĸʽ޷ж -UninstallUnknownEntry=ж־δ֪Ŀ (%1) -ConfirmUninstall=ǷȷҪȫɾ%1 -UninstallOnlyOnWin64=˰װֻ64λWindowsжء -OnlyAdminCanUninstall=˰װֻɾ߱ԱȨ޵ûжء -UninstallStatusLabel=Ժɾ%1 -UninstalledAll=ѳɹشĵɾ%1 -UninstalledMost=%1жϡ%n%nijЩĿ޷жعɾֶɾЩĿ -UninstalledAndNeedsRestart=Ҫ%1жأԡ%n%nҪ -UninstallDataCorrupted=ļ%1𻵡޷ж - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=ɾļ -ConfirmDeleteSharedFile2=ϵͳʾûκγʹ¹ļҪɾùļ%n%nгʹøļɾЩ޷Сȷѡ񡰷񡱡¸ļϵͳκΣ -SharedFileNameLabel=ļ -SharedFileLocationLabel=λã -WizardUninstalling=ж״̬ -StatusUninstalling=ж%1 - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=ڰװ%1 -ShutdownBlockReasonUninstallingApp=ж%1 - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] - -NameAndVersion=%1汾%2 -AdditionalIcons=ӿݷʽ -CreateDesktopIcon=ݷʽ(&D) -CreateQuickLaunchIcon=ݷʽ(&Q) -ProgramOnTheWeb=%1վ -UninstallProgram=ж%1 -LaunchProgram=%1 -AssocFileExtension=%1%2ļչ(&A) -AssocingFileExtension=ڽ%1%2ļչ -AutoStartProgramGroupDescription= -AutoStartProgram=Զ%1 -AddonHostProgramNotFound=ѡļҲ%1%n%nǷȻ +; *** Inno Setup version 5.5.3+ Chinese (Simplified) messages *** +; By Qiming Li (qiming at clault.com) +; +; To download user-contributed translations of this file, go to: +; http://www.jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=<4E2D><6587><7B80><4F53> +LanguageID=$0804 +LanguageCodePage=936 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=װ +SetupWindowTitle=װ - %1 +UninstallAppTitle=ж +UninstallAppFullTitle=%1ж + +; *** Misc. common +InformationTitle=Ϣ +ConfirmTitle=ȷ +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage=װ򵼽ĵϰװ%1ȷҪ +LdrCannotCreateTemp=޷ʱļװֹ +LdrCannotExecTemp=޷ʱļеļװֹ + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing=װĿ¼ȱʧļ%1⣬»ȡһݳ򿽱 +SetupFileCorrupt=װļѱ𻵡»ȡһݳ򿽱 +SetupFileCorruptOrWrongVer=װļѱ𻵣뱾װ򵼰汾ݡ⣬»ȡһݳ򿽱 +InvalidParameter=Чв%n%n%1 +SetupAlreadyRunning=װѾС +WindowsVersionNotSupported=֧еWindows汾 +WindowsServicePackRequired=Ҫ%1 Service Pack %2°汾 +NotOnThisPlatform=򲻿%1С +OnlyOnThisPlatform=%1С +OnlyOnTheseArchitectures=ֻΪ´ܹƵWindows汾ϰװ%n%n%1 +MissingWOW64APIs=ʹõWindows汾ûа64λװĹܡ밲װService Pack %1⡣ +WinVersionTooLowError=Ҫ%2汾ϵ%1 +WinVersionTooHighError=򲻿ɰװ%2߰汾%1ϡ +AdminPrivilegesRequired=¼ΪԱܰװ˳ +PowerUserPrivilegesRequired=¼ΪԱȨûܰװ˳ +SetupAppRunningError=װ򵼼⵽%1С%n%nرдڲȷȡ˳װ +UninstallAppRunningError=ж򵼼⵽%1С%n%nرдڣȻȷȡ˳ + +; *** Misc. errors +ErrorCreatingDir=װ޷ļС%1 +ErrorTooManyFilesInDir=ļС%1ļ࣬޷дļ + +; *** Setup common messages +ExitSetupTitle=˳װ +ExitSetupMessage=װδɡ˳򽫲ᱻװ %n%n´аװɳİװ%n%nȷ˳װ +AboutSetupMenuItem=ڰװ(&A) +AboutSetupTitle=ڰװ +AboutSetupMessage=%1汾%2%n%3%n%n%1ҳ%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< һ(&B) +ButtonNext=һ(&N) > +ButtonInstall=װ(&I) +ButtonOK=ȷ +ButtonCancel=ȡ +ButtonYes=(&Y) +ButtonYesToAll=ȫѡ(&A) +ButtonNo=(&N) +ButtonNoToAll=ȫѡ(&O) +ButtonFinish=(&F) +ButtonBrowse=(&B) +ButtonWizardBrowse=(&R) +ButtonNewFolder=ļ(&M) + +; *** "Select Language" dialog messages +SelectLanguageTitle=ѡ +SelectLanguageLabel=ѡװʱʹԣ + +; *** Common wizard text +ClickNext=һȡ˳װ򵼡 +BeveledLabel= +BrowseDialogTitle=ѡļ +BrowseDialogLabel=бѡȡһļУȷ +NewFolderName=½ļ + +; *** "Welcome" wizard page +WelcomeLabel1=ӭʹ[name]װ +WelcomeLabel2=򵼽ĵϰװ[name/ver]%n%nڼ֮ǰرӦó + +; *** "Password" wizard page +WizardPassword= +PasswordLabel1=װ뱣 +PasswordLabel3=룬һִСд +PasswordEditLabel=(&P) +IncorrectPassword=벻ȷԡ + +; *** "License Agreement" wizard page +WizardLicense=Э +LicenseLabel=ĶҪϢȻٽһ +LicenseLabel3=ĶЭ顣ܴЭȻܼװ +LicenseAccepted=ҽЭ(&A) +LicenseNotAccepted=ҲЭ(&D) + +; *** "Information" wizard pages +WizardInfoBefore=Ϣ +InfoBeforeLabel=ĶҪϢٽһ +InfoBeforeClickLabel=׼üװ󣬵һ +WizardInfoAfter=Ϣ +InfoAfterLabel=ĶҪϢٽһ +InfoAfterClickLabel=׼üװ󣬵һ + +; *** "User Information" wizard page +WizardUserInfo=ûϢ +UserInfoDesc=Ϣ +UserInfoName=û(&U) +UserInfoOrg=(&O) +UserInfoSerial=к(&S) +UserInfoNameRequired=û + +; *** "Select Destination Location" wizard page +WizardSelectDir=ѡװλ +SelectDirDesc=[name]װδ +SelectDirLabel3=װ򵼽[name]װļС +SelectDirBrowseLabel=һҪѡͬļУ +DiskSpaceMBLabel=[mb]ֽڣMBô̿ռ䡣 +CannotInstallToNetworkDrive=޷װ +CannotInstallToUNCPath=޷װUNC· +InvalidPath=̷·磺%n%nC:\Ӧó%n%n¸ʽUNC·%n%n\\\Ŀ¼ +InvalidDrive=ѡUNCڻ򲻿ɷʡѡһ +DiskSpaceWarningTitle=̿ռ䲻 +DiskSpaceWarning=%1ǧֽڣKBÿռſɰװѡ%2ǧֽڣKBÿռ䡣%n%nȷҪ +DirNameTooLong=ļƻ·̫ +InvalidDirName=ļЧ +BadDirName32=ļƲַܰ%n%n%1 +DirExistsTitle=ļѴ +DirExists=ļ%n%n%1%n%nѴڡȷҪװļ +DirDoesntExistTitle=ļв +DirDoesntExist=ļ%n%n%1%n%nڡҪļ + +; *** "Select Components" wizard page +WizardSelectComponents=ѡ +SelectComponentsDesc=ҪװЩ +SelectComponentsLabel2=ѡҪװҪװ׼úһ +FullInstallation=ȫװ +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=లװ +CustomInstallation=Զ尲װ +NoUninstallWarningTitle=Ѵ +NoUninstallWarning=װ򵼼⵽Ѿװ%n%n%1%n%nȡѡжЩ%n%nȷҪװ +ComponentSize1=%1ǧֽڣKB +ComponentSize2=%1ֽڣMB +ComponentsDiskSpaceMBLabel=ĿǰѡҪ[mb]ֽڣMB̿ռ䡣 + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=ѡ񸽼 +SelectTasksDesc=ҪִЩ +SelectTasksLabel2=ѡװ[name]ʱҪִеĸȻһ + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=ѡʼ˵ļ +SelectStartMenuFolderDesc=ѳݷʽŵ +SelectStartMenuFolderLabel3=װ򵼽¿ʼ˵ļдݷʽ +SelectStartMenuFolderBrowseLabel=һҪѡһļУ +MustEnterGroupName=ļ +GroupNameTooLong=ļƻ·̫ +InvalidGroupName=ļЧ +BadGroupName=ļƲַܰ%n%n%1 +NoProgramGroupCheck2=Ҫʼ˵ļ(&D) + +; *** "Ready to Install" wizard page +WizardReady=װ׼ +ReadyLabel1=װ׼ϣʼĵϰװ[name] +ReadyLabel2a=װʼװҪȷϻһ +ReadyLabel2b=װʼװ +ReadyMemoUserInfo=ûϢ +ReadyMemoDir=װλã +ReadyMemoType=װͣ +ReadyMemoComponents=ѡ +ReadyMemoGroup=ʼ˵ļУ +ReadyMemoTasks= + +; *** "Preparing to Install" wizard page +WizardPreparing=׼װ +PreparingDesc=װ׼ĵϰװ[name] +PreviousInstallNotCompleted=ϴγװ/жδɡҪϴΰװ%n%n֮аװװ[name] +CannotContinue=װ޷ȡ˳ +ApplicationsFound=װҪµļӦóռáװԶرЩӦó +ApplicationsFound2=װҪµļӦóռáװԶرЩӦó򡣰װɺ󣬰װ򵼽ЩӦó +CloseApplications=ԶرӦó(&A) +DontCloseApplications=ԶرӦó(&D) +ErrorCloseApplications=װ޷ԶرеӦóڽһ֮ǰرЩռðװҪļӦó + +; *** "Installing" wizard page +WizardInstalling=ڰװ +InstallingLabel=Ժ򣬰װĵϰװ[name] + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name]װ +FinishedLabelNoIcons=װĵϰװ[name] +FinishedLabel=װĵϰװ[name]ͨѰװĿݷʽ򿪴Ӧó +ClickFinish=˳װ +FinishedRestartLabel=Ϊ[name]İװװ򵼱ĵԡҪ +FinishedRestartMessage=Ϊ[name]İװװ򵼱ĵԡ%n%nҪ +ShowReadmeCheck=ǣҪĶļ +YesRadio=ǣ(&Y) +NoRadio=Ժ(&N) +; used for example as 'Run MyProg.exe' +RunEntryExec=%1 +; used for example as 'View Readme.txt' +RunEntryShellExec=%1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=װҪһŴ +SelectDiskLabel2=%1 ȷ%n%nôеļʾļУȷ· +PathLabel=·(&P) +FileNotInDir2=ļ%1ڡ%2СȷĴ̻ѡļС +SelectDirectoryLabel=ָһŴ̵λá + +; *** Installation phase messages +SetupAborted=װδɡ%n%nаװ򵼡 +EntryAbortRetryIgnore=ԡ³ԣԡװֹȡװ + +; *** Installation status messages +StatusClosingApplications=ڹرӦó +StatusCreateDirs=ڴļС +StatusExtractFiles=ȡļ +StatusCreateIcons=ڴݷʽ +StatusCreateIniEntries=ڴINIĿ +StatusCreateRegistryEntries=ڴעĿ +StatusRegisterFiles=ڴעĿ +StatusSavingUninstall=ڱжϢ +StatusRunProgram=ڽװ +StatusRestartingApplications=Ӧó +StatusRollback=ڳġ + +; *** Misc. errors +ErrorInternal2=ڲ%1 +ErrorFunctionFailedNoCode=%1ʧ +ErrorFunctionFailed=%1ʧܣ%2 +ErrorFunctionFailedWithMessage=%1ʧܣ%2%n%3 +ErrorExecutingProgram=޷г%n%1 + +; *** Registry errors +ErrorRegOpenKey=עʱ%n%1\%2 +ErrorRegCreateKey=עʱ%n%1\%2 +ErrorRegWriteKey=дעʱ%n%1\%2 + +; *** INI errors +ErrorIniEntry=ļ%1дINIĿʱ + +; *** File copying errors +FileAbortRetryIgnore=ԡ³ԣԡļƼֹȡװ +FileAbortRetryIgnore2=ԡ³ԣԡװƼֹȡװ +SourceIsCorrupted=Դļ +SourceDoesntExist=Դļ%1 +ExistingFileReadOnly=ļΪֻ%n%nԡƳֻԲ³ԣԡļֹȡװ +ErrorReadingExistingDest=ȡļʱ +FileExists=ļѴڡ%n%nðװ򵼸 +ExistingFileNewer=ļȰװͼװĻҪ¡鱣ļ%n%nҪļ +ErrorChangingAttr=ļʱ +ErrorCreatingTemp=Ŀļдļʱ +ErrorReadingSource=ȡԴļʱ +ErrorCopying=ļʱ +ErrorReplacingExistingFile=滻ļʱ +ErrorRestartReplace=滻ʧܣ +ErrorRenamingTemp=ΪĿļļʱ +ErrorRegisterServer=޷עᶯ̬ؼDLL/OCX%1 +ErrorRegSvr32Failed=RegSvr32ʧܣ䷵ֵΪ%1 +ErrorRegisterTypeLib=޷עͿ⣺%1 + +; *** Post-installation errors +ErrorOpeningReadme=ļʱ +ErrorRestartingComputer=װ޷ԡֶ + +; *** Uninstaller messages +UninstallNotFound=ļ%1ڡ޷жء +UninstallOpenError=޷ļ%1޷ж +UninstallUnsupportedVer=˰汾ж޷ʶж־ļ%1ĸʽ޷ж +UninstallUnknownEntry=ж־δ֪Ŀ (%1) +ConfirmUninstall=ǷȷҪȫɾ%1 +UninstallOnlyOnWin64=˰װֻ64λWindowsжء +OnlyAdminCanUninstall=˰װֻɾ߱ԱȨ޵ûжء +UninstallStatusLabel=Ժɾ%1 +UninstalledAll=ѳɹشĵɾ%1 +UninstalledMost=%1жϡ%n%nijЩĿ޷жعɾֶɾЩĿ +UninstalledAndNeedsRestart=Ҫ%1жأԡ%n%nҪ +UninstallDataCorrupted=ļ%1𻵡޷ж + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=ɾļ +ConfirmDeleteSharedFile2=ϵͳʾûκγʹ¹ļҪɾùļ%n%nгʹøļɾЩ޷Сȷѡ񡰷񡱡¸ļϵͳκΣ +SharedFileNameLabel=ļ +SharedFileLocationLabel=λã +WizardUninstalling=ж״̬ +StatusUninstalling=ж%1 + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=ڰװ%1 +ShutdownBlockReasonUninstallingApp=ж%1 + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1汾%2 +AdditionalIcons=ӿݷʽ +CreateDesktopIcon=ݷʽ(&D) +CreateQuickLaunchIcon=ݷʽ(&Q) +ProgramOnTheWeb=%1վ +UninstallProgram=ж%1 +LaunchProgram=%1 +AssocFileExtension=%1%2ļչ(&A) +AssocingFileExtension=ڽ%1%2ļչ +AutoStartProgramGroupDescription= +AutoStartProgram=Զ%1 +AddonHostProgramNotFound=ѡļҲ%1%n%nǷȻ diff --git a/distrib/Languages/ChineseTraditional.isl b/distrib/Languages/ChineseTraditional.isl index f4d026794a3..fc3c4b26009 100644 --- a/distrib/Languages/ChineseTraditional.isl +++ b/distrib/Languages/ChineseTraditional.isl @@ -1,331 +1,331 @@ -; *** Inno Setup version 5.5.3+ Chinese (Traditional) messages by Samuel Lee (751555749@qq.com) *** -; -; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ -; -; Note: When translating this text, do not add periods (.) to the end of -; messages that didn't have them already, because on those messages Inno -; Setup adds the periods automatically (appending a period would result in -; two periods being displayed). -[LangOptions] -; The following three entries are very important. Be sure to read and -; understand the '[LangOptions] section' topic in the help file. -LanguageName=<7e41><9ad4><4e2d><6587> -LanguageID=$0404 -LanguageCodepage=950 -; If the language you are translating to requires special font faces or -; sizes, uncomment any of the following entries and change them accordingly. -DialogFontName=sө -DialogFontSize=9 -TitleFontName=Arial -TitleFontSize=28 -WelcomeFontName=sө -WelcomeFontSize=12 -CopyrightFontName=sө -CopyrightFontSize=9 - -[Messages] -; *** Application titles -SetupAppTitle=w˵{ -SetupWindowTitle=%1 w˵{ -UninstallAppTitle=Ѱw -UninstallAppFullTitle=Ѱw %1 -; *** Misc. common -InformationTitle=T -ConfirmTitle=T{ -ErrorTitle=~ - -; *** SetupLdr messages -SetupLdrStartupMessage=oN|w %1CzQn~? -LdrCannotCreateTemp=Lkإ߼ȦsɮסCw˵{N|C -LdrCannotExecTemp=LkȦsɮסCw˵{N|C - -; *** Startup error messages -LastErrorMessage=%1%n%n~ %2: %3 -SetupFileMissing=w˸Ƨɮ %1CЭץDέsonC -SetupFileCorrupt=wɮפwglCЭsonC -SetupFileCorruptOrWrongVer=wɮפwglAλPw˵{šCЭsonC -InvalidParameter=YӵLĪܶqwQǻFROC:%n%n%1 -SetupAlreadyRunning=w˵{wgbC -WindowsVersionNotSupported=w˵{ä䴩ثebqҹB檺 Windows C -WindowsServicePackRequired=w˵{ݭn %1 Service Pack %2 ΧsC -NotOnThisPlatform=oӵ{Lkb %1 C -OnlyOnThisPlatform=oӵ{b %1 C -OnlyOnTheseArchitectures=oӵ{ubMHUBz[cӳ]p Windows Ww:%n%n%1 -MissingWOW64APIs=oӪ Windows ]tw˵{ 64 줸w˩һݪ\CЦw Service Pack %1 hץDC -WinVersionTooLowError=oӵ{b %1 %2 ΥHWtΰC -WinVersionTooHighError=oӵ{Lkw˦b %1 %2 ΥHWtΡC -AdminPrivilegesRequired=znJtκ޲zHw˳oӵ{C -PowerUserPrivilegesRequired=znJ㦳tκ޲z Power User vϥΪ̥Hw˳oӵ{C -SetupAppRunningError=w˵{ %1 bC%n%nӵ{ [Tw] ~AΫ [] }C -UninstallAppRunningError=Ѱw˵{ %1 bC%n%nӵ{ [Tw] ~AΫ [] }C - -; *** Misc. errors -ErrorCreatingDir=w˵{Lkإ߸Ƨ%1C -ErrorTooManyFilesInDir=LkbƧ%1إɮסA]ƧӦhɮסC - -; *** Setup common messages -ExitSetupTitle=w˵{ -ExitSetupMessage=w˩|CpGz{bw˵{Aoӵ{N|QwˡC%n%nziHyAw˵{Hw˵{ǡCz{bnw˵{? -AboutSetupMenuItem=w˵{(&A)... -AboutSetupTitle=w˵{ -AboutSetupMessage=%1 %2%n%3%n%n%1 }:%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< W@B(&B) -ButtonNext=U@B(&N) > -ButtonInstall=w(&I) -ButtonOK=Tw -ButtonCancel= -ButtonYes=O(&Y) -ButtonYesToAll=ҬO(&A) -ButtonNo=_(&N) -ButtonNoToAll=ҧ_(&O) -ButtonFinish=(&F) -ButtonBrowse=s(&B)... -ButtonWizardBrowse=s(&R)... -ButtonNewFolder=إ߷sƧ(&M) - -; *** "Select Language" dialog messages -SelectLanguageTitle=ܦw˻y -SelectLanguageLabel=ܦbw˹L{ϥΪy: - -; *** Common wizard text -ClickNext= [U@B] ~wˡAΫ [] w˵{C -BeveledLabel= -BrowseDialogTitle=sƧ -BrowseDialogLabel=bUƧCܤ@ӸƧAM [Tw]C -NewFolderName=sƧ - -; *** "Welcome" wizard page -WelcomeLabel1=wϥ [name] w˵{ -WelcomeLabel2=oӦw˵{N|w [name/ver] zqC%n%nڭ̱jPijzbw˹L{䥦ε{AHקKPw˵{oͨRC - -; *** "Password" wizard page -WizardPassword=KX -PasswordLabel1=oӦw˵{㦳KXO@C -PasswordLabel3=пJKXAM [U@B] ~CKXOϤjpgC -PasswordEditLabel=KX(&P): -IncorrectPassword=zJKXTAЭsJC - -; *** "License Agreement" wizard page -WizardLicense=vX -LicenseLabel=о\ŪHUvXC -LicenseLabel3=о\ŪHUvXAzXUڤ~~wˡC -LicenseAccepted=ڦPN(&A) -LicenseNotAccepted=ڤPN(&D) - -; *** "Information" wizard pages -WizardInfoBefore=T -InfoBeforeLabel=b~wˤeо\ŪHUnTC -InfoBeforeClickLabel=zdzƦn~wˡAЫ [U@B]C -WizardInfoAfter=T -InfoAfterLabel=b~wˤeо\ŪHUnTC -InfoAfterClickLabel=zdzƦn~wˡAЫ [U@B]C - -; *** "User Information" wizard page -WizardUserInfo=ϥΪ̸T -UserInfoDesc=пJzơC -UserInfoName=ϥΪ̦W(&U): -UserInfoOrg=´(&O): -UserInfoSerial=Ǹ(&S): -UserInfoNameRequired=zJzW١C - -; *** "Select Destination Location" wizard page -WizardSelectDir=ܥتƧ -SelectDirDesc=ܦw˵{w [name] mC -SelectDirLabel3=w˵{N| [name] w˨UƧC -SelectDirBrowseLabel= [U@B] ~ApGzQܥt@ӸƧAЫ [s]C -DiskSpaceMBLabel=ֻ̤ݭn [mb] MB ϺЪŶC -CannotInstallToNetworkDrive=w˵{Lkw˩ϺоC -CannotInstallToUNCPath=w˵{Lkw˩ UNC |C -InvalidPath=zJ㪺|W٤κϺоNXC%n%nҦp C:\App UNC |榡 \\A\@θƧC -InvalidDrive=zϺо UNC W٤sbεLksAпܨLتaC -DiskSpaceWarningTitle=ϺЪŶ -DiskSpaceWarning=w˵{ݭnܤ %1 KB ϺЪŶAzҿϺХu %2 KB iΪŶC%n%nzn~w˶? -DirNameTooLong=ƧW٩θ|ӪC -InvalidDirName=ƧW٤TC -BadDirName32=ƧW٤o]tHUSr:%n%n%1 -DirExistsTitle=Ƨwgsb -DirExists=Ƨ %1 wgsbC%n%nzn~w˨oӸƧ? -DirDoesntExistTitle=Ƨsb -DirDoesntExist=Ƨ %1 sbC%n%nznإ߳oӸƧ? - -; *** "Select Components" wizard page -WizardSelectComponents=ܤ -SelectComponentsDesc=ܱN|Qw˪C -SelectComponentsLabel2=ܱzQnw˪FMzQw˪CM [U@B] ~wˡC -FullInstallation=w -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=̤pw -CustomInstallation=ۭqw -NoUninstallWarningTitle=wsb -NoUninstallWarning=w˵{HUwgw˦bzqW:%n%n%1%n%nܳoǤN|̡C%n%nzMn~? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=ثeܻݭnܤ [mb] MB ϺЪŶC - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=ܪ[u@ -SelectTasksDesc=ܭn檺[u@C -SelectTasksLabel2=ܦw˵{bw [name] ɭn檺[u@AM [U@B]C - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=ܡu}lv\Ƨ -SelectStartMenuFolderDesc=ܦw˵{إߵ{|mC -SelectStartMenuFolderLabel3=w˵{N|{|إߦbUu}lv\ƧC -SelectStartMenuFolderBrowseLabel= [U@B] ~ApGzQܥt@ӸƧAЫ [s]C -MustEnterGroupName=zJ@ӸƧW١C -GroupNameTooLong=ƧW٩θ|ӪC -InvalidGroupName=ƧW٤TC -BadGroupName=ƧW٤o]tUCr:%n%n%1 -NoProgramGroupCheck2=nbu}lv\إ߸Ƨ(&D) - -; *** "Ready to Install" wizard page -WizardReady=dzƦw -ReadyLabel1=w˵{N}lw [name] zqC -ReadyLabel2a=U [w] ~wˡAΫ [W@B] s˵γ]wUﶵeC -ReadyLabel2b=U [w] ~wˡC -ReadyMemoUserInfo=ϥΪ̸T -ReadyMemoDir=تƧ: -ReadyMemoType=w˫A: -ReadyMemoComponents=ܪ: -ReadyMemoGroup=u}lv\Ƨ: -ReadyMemoTasks=[u@: -; *** "Preparing to Install" wizard page -WizardPreparing=dzƦw˵{ -PreparingDesc=w˵{dzƱN [name] w˨zqWC -PreviousInstallNotCompleted=ew/ Ѱw˩|AzsҰʹqHӦwˡC%n%nbsҰʹqAЦAoӵ{Ӧw [name]C -CannotContinue=w˵{Lk~CЫ [] }C -ApplicationsFound=Uε{bϥΦw˵{һݭnsɡCijz\w˵{۰oε{C -ApplicationsFound2=Uε{bϥΦw˵{һݭnsɡCijz\w˵{۰oε{Cw˹L{Aw˵{N|խs}Ҹε{C -CloseApplications=ε{(&A) -DontCloseApplications=nε{ (&D) -ErrorCloseApplications=w˵{Lk۰Ҧε{Cijzb~eҦε{ϥΪɮסC -; *** "Installing" wizard page -WizardInstalling=bw -InstallingLabel=еyԡAw˵{bN [name] w˨zqW - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=w˧ -FinishedLabelNoIcons=w˵{wgN [name] w˦bzqWC -FinishedLabel=w˵{wgN [name] w˦bzqAziHܵ{ϥܨӰε{C -ClickFinish= [] Hw˵{C -FinishedRestartLabel=n [name] wˡAw˵{sҰʱzqCzQn{bsҰʹq? -FinishedRestartMessage=n [name] wˡAw˵{sҰʱzqC%n%nzQn{bsҰʹq? -ShowReadmeCheck=OAڭn\ŪŪɮסC -YesRadio=OAߧYsҰʹq(&Y) -NoRadio=_Aڵy᭫sҰʹq(&N) -; used for example as 'Run MyProg.exe' -RunEntryExec= %1 -; used for example as 'View Readme.txt' -RunEntryShellExec=˵ %1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=w˵{ݭnU@iϤ -SelectDiskLabel2=дJϤ %1AM [Tw]C%n%npGɮפbHUܪƧAпJTƧW٩Ϋ [s] C -PathLabel=|(&P): -FileNotInDir2=ɮס%1Lkb%2CдJTϤοܨ䥦ƧC -SelectDirectoryLabel=ЫwU@iϤmC - -; *** Installation phase messages -SetupAborted=w˨SC%n%nЧ󥿰D᭫swˤ@C -EntryAbortRetryIgnore= [] դ@AU [L] LoɮסAΫU [] wˡC - -; *** Installation status messages -StatusClosingApplications=bε{... -StatusCreateDirs=bإ߸Ƨ... -StatusExtractFiles=bYɮ... -StatusCreateIcons=bإߵ{ϥ... -StatusCreateIniEntries=gJ INI ɮת... -StatusCreateRegistryEntries=bstεn... -StatusRegisterFiles=bnɮ... -StatusSavingUninstall=xsѰw˸T... -StatusRunProgram=bw... -StatusRestartingApplications=bs}ε{... -StatusRollback=b_ܧ... - -; *** Misc. errors -ErrorInternal2=~: %1 -ErrorFunctionFailedNoCode=%1 -ErrorFunctionFailed=%1 ѡFNX %2 -ErrorFunctionFailedWithMessage=%1 ѡFNX %2.%n%3 -ErrorExecutingProgram=Lkɮ:%n%1 - -; *** Registry errors -ErrorRegOpenKey=Lk}ҵn:%n%1\%2 -ErrorRegCreateKey=Lkإߵn:%n%1\%2 -ErrorRegWriteKey=Lkܧn:%n%1\%2 - -; *** INI errors -ErrorIniEntry=bɮס%1إ INI ؿ~C - -; *** File copying errors -FileAbortRetryIgnore= [] Aդ@A [L] Loɮס]ij^AΫ [] wˡC -FileAbortRetryIgnore2= [] Aդ@A [L] ~i]ij^AΫ [] wˡC -SourceIsCorrupted=ӷɮפwglC -SourceDoesntExist=ӷɮס%1sbC -ExistingFileReadOnly=ɮݩʤw]ŪC%n%n [] NŪݩʲ}Aդ@A [L] LoɮסAΫ [] wˡC -ErrorReadingExistingDest=Ū@Ӥwsbɮ׮ɵoͿ~: -FileExists=ɮפwgsbCznNثeɮ׶? -ExistingFileNewer=sbɮתsAijzOdثewsbɮסC%n%nznOdثewsbɮ׶? -ErrorChangingAttr=bܧɮݩʮɵoͿ~: -ErrorCreatingTemp=bتƧإɮ׮ɵoͿ~: -ErrorReadingSource=Ūlɮ׮ɵoͿ~: -ErrorCopying=_ɮ׮ɵoͿ~: -ErrorReplacingExistingFile=Nɮ׮ɵoͿ~: -ErrorRestartReplace=sҰʹqNɮץ: -ErrorRenamingTemp=bتƧܧɮצWٮɵoͿ~: -ErrorRegisterServer=Lk`U DLL/OCX ɮ: %1C -ErrorRegSvr32Failed=RegSvr32 ѡFhXNX %1 -ErrorRegisterTypeLib=Lk`Uw: %1C - -; *** Post-installation errors -ErrorOpeningReadme=}Ūɮ׮ɵoͿ~C -ErrorRestartingComputer=w˵{LksҰʹqAХHʤ覡ۦ歫sҰʹqC - -; *** Uninstaller messages -UninstallNotFound=ɮס%1sbALk{C -UninstallOpenError=Lk}ɮס%1ALk{C -UninstallUnsupportedVer=oӪѰw˵{LkѰO %1 榡ALkѰwˡC -UninstallUnknownEntry=Ѱw˰Oɤo{O (%1)C -ConfirmUninstall=zTwn %1 Ψɮ׶? -UninstallOnlyOnWin64=oӵ{ub 64 줸 Windows WѰwˡC -OnlyAdminCanUninstall=oӵ{nƨtκ޲zvϥΪ̤iѰwˡC -UninstallStatusLabel=bqzq %1 Aеy... -UninstalledAll=%1 wg\qzqC -UninstalledMost=%1 Ѱw˧C%n%nYɮפΤLkAziHۦRoɮסC -UninstalledAndNeedsRestart=n %1 Ѱw˵{ǡAzsҰʹqC%n%nzQn{bsҰʹq? -UninstallDataCorrupted=ɮס%1wglALkѰwˡC - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=@ɮ -ConfirmDeleteSharedFile2=tܤUC@ɮפwAQ{ҨϥΡAznoɮ׶?%n%n%1%n%nխYzFHWɮצ{ݭnϥΥ̡ANyoǵ{Lk`A]zYLkTwп [_]COdoɮצbztΤ|yl`C -SharedFileNameLabel=ɮצW: -SharedFileLocationLabel=m: -WizardUninstalling=Ѱw˪A -StatusUninstalling=bѰw %1... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=bw %1. -ShutdownBlockReasonUninstallingApp=bѰw %1. - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] -NameAndVersion=%1 %2 -AdditionalIcons=[ϥ: -CreateDesktopIcon=إ߮ୱϥ(&D) -CreateQuickLaunchIcon=إߧֳtҰʹϥ(&Q) -ProgramOnTheWeb=%1 -UninstallProgram=Ѱw %1 -LaunchProgram=Ұ %1 -AssocFileExtension=N %1 PɮװɦW %2 p(&A) -AssocingFileExtension=bN %1 PɮװɦW %2 p... -AutoStartProgramGroupDescription=}: -AutoStartProgram=۰ʶ} %1 -AddonHostProgramNotFound=%1 Lkbzҿ諸ƧC%n%nzO_٭n~H - +; *** Inno Setup version 5.5.3+ Chinese (Traditional) messages by Samuel Lee (751555749@qq.com) *** +; +; To download user-contributed translations of this file, go to: +; http://www.jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=<7e41><9ad4><4e2d><6587> +LanguageID=$0404 +LanguageCodepage=950 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +DialogFontName=sө +DialogFontSize=9 +TitleFontName=Arial +TitleFontSize=28 +WelcomeFontName=sө +WelcomeFontSize=12 +CopyrightFontName=sө +CopyrightFontSize=9 + +[Messages] +; *** Application titles +SetupAppTitle=w˵{ +SetupWindowTitle=%1 w˵{ +UninstallAppTitle=Ѱw +UninstallAppFullTitle=Ѱw %1 +; *** Misc. common +InformationTitle=T +ConfirmTitle=T{ +ErrorTitle=~ + +; *** SetupLdr messages +SetupLdrStartupMessage=oN|w %1CzQn~? +LdrCannotCreateTemp=Lkإ߼ȦsɮסCw˵{N|C +LdrCannotExecTemp=LkȦsɮסCw˵{N|C + +; *** Startup error messages +LastErrorMessage=%1%n%n~ %2: %3 +SetupFileMissing=w˸Ƨɮ %1CЭץDέsonC +SetupFileCorrupt=wɮפwglCЭsonC +SetupFileCorruptOrWrongVer=wɮפwglAλPw˵{šCЭsonC +InvalidParameter=YӵLĪܶqwQǻFROC:%n%n%1 +SetupAlreadyRunning=w˵{wgbC +WindowsVersionNotSupported=w˵{ä䴩ثebqҹB檺 Windows C +WindowsServicePackRequired=w˵{ݭn %1 Service Pack %2 ΧsC +NotOnThisPlatform=oӵ{Lkb %1 C +OnlyOnThisPlatform=oӵ{b %1 C +OnlyOnTheseArchitectures=oӵ{ubMHUBz[cӳ]p Windows Ww:%n%n%1 +MissingWOW64APIs=oӪ Windows ]tw˵{ 64 줸w˩һݪ\CЦw Service Pack %1 hץDC +WinVersionTooLowError=oӵ{b %1 %2 ΥHWtΰC +WinVersionTooHighError=oӵ{Lkw˦b %1 %2 ΥHWtΡC +AdminPrivilegesRequired=znJtκ޲zHw˳oӵ{C +PowerUserPrivilegesRequired=znJ㦳tκ޲z Power User vϥΪ̥Hw˳oӵ{C +SetupAppRunningError=w˵{ %1 bC%n%nӵ{ [Tw] ~AΫ [] }C +UninstallAppRunningError=Ѱw˵{ %1 bC%n%nӵ{ [Tw] ~AΫ [] }C + +; *** Misc. errors +ErrorCreatingDir=w˵{Lkإ߸Ƨ%1C +ErrorTooManyFilesInDir=LkbƧ%1إɮסA]ƧӦhɮסC + +; *** Setup common messages +ExitSetupTitle=w˵{ +ExitSetupMessage=w˩|CpGz{bw˵{Aoӵ{N|QwˡC%n%nziHyAw˵{Hw˵{ǡCz{bnw˵{? +AboutSetupMenuItem=w˵{(&A)... +AboutSetupTitle=w˵{ +AboutSetupMessage=%1 %2%n%3%n%n%1 }:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< W@B(&B) +ButtonNext=U@B(&N) > +ButtonInstall=w(&I) +ButtonOK=Tw +ButtonCancel= +ButtonYes=O(&Y) +ButtonYesToAll=ҬO(&A) +ButtonNo=_(&N) +ButtonNoToAll=ҧ_(&O) +ButtonFinish=(&F) +ButtonBrowse=s(&B)... +ButtonWizardBrowse=s(&R)... +ButtonNewFolder=إ߷sƧ(&M) + +; *** "Select Language" dialog messages +SelectLanguageTitle=ܦw˻y +SelectLanguageLabel=ܦbw˹L{ϥΪy: + +; *** Common wizard text +ClickNext= [U@B] ~wˡAΫ [] w˵{C +BeveledLabel= +BrowseDialogTitle=sƧ +BrowseDialogLabel=bUƧCܤ@ӸƧAM [Tw]C +NewFolderName=sƧ + +; *** "Welcome" wizard page +WelcomeLabel1=wϥ [name] w˵{ +WelcomeLabel2=oӦw˵{N|w [name/ver] zqC%n%nڭ̱jPijzbw˹L{䥦ε{AHקKPw˵{oͨRC + +; *** "Password" wizard page +WizardPassword=KX +PasswordLabel1=oӦw˵{㦳KXO@C +PasswordLabel3=пJKXAM [U@B] ~CKXOϤjpgC +PasswordEditLabel=KX(&P): +IncorrectPassword=zJKXTAЭsJC + +; *** "License Agreement" wizard page +WizardLicense=vX +LicenseLabel=о\ŪHUvXC +LicenseLabel3=о\ŪHUvXAzXUڤ~~wˡC +LicenseAccepted=ڦPN(&A) +LicenseNotAccepted=ڤPN(&D) + +; *** "Information" wizard pages +WizardInfoBefore=T +InfoBeforeLabel=b~wˤeо\ŪHUnTC +InfoBeforeClickLabel=zdzƦn~wˡAЫ [U@B]C +WizardInfoAfter=T +InfoAfterLabel=b~wˤeо\ŪHUnTC +InfoAfterClickLabel=zdzƦn~wˡAЫ [U@B]C + +; *** "User Information" wizard page +WizardUserInfo=ϥΪ̸T +UserInfoDesc=пJzơC +UserInfoName=ϥΪ̦W(&U): +UserInfoOrg=´(&O): +UserInfoSerial=Ǹ(&S): +UserInfoNameRequired=zJzW١C + +; *** "Select Destination Location" wizard page +WizardSelectDir=ܥتƧ +SelectDirDesc=ܦw˵{w [name] mC +SelectDirLabel3=w˵{N| [name] w˨UƧC +SelectDirBrowseLabel= [U@B] ~ApGzQܥt@ӸƧAЫ [s]C +DiskSpaceMBLabel=ֻ̤ݭn [mb] MB ϺЪŶC +CannotInstallToNetworkDrive=w˵{Lkw˩ϺоC +CannotInstallToUNCPath=w˵{Lkw˩ UNC |C +InvalidPath=zJ㪺|W٤κϺоNXC%n%nҦp C:\App UNC |榡 \\A\@θƧC +InvalidDrive=zϺо UNC W٤sbεLksAпܨLتaC +DiskSpaceWarningTitle=ϺЪŶ +DiskSpaceWarning=w˵{ݭnܤ %1 KB ϺЪŶAzҿϺХu %2 KB iΪŶC%n%nzn~w˶? +DirNameTooLong=ƧW٩θ|ӪC +InvalidDirName=ƧW٤TC +BadDirName32=ƧW٤o]tHUSr:%n%n%1 +DirExistsTitle=Ƨwgsb +DirExists=Ƨ %1 wgsbC%n%nzn~w˨oӸƧ? +DirDoesntExistTitle=Ƨsb +DirDoesntExist=Ƨ %1 sbC%n%nznإ߳oӸƧ? + +; *** "Select Components" wizard page +WizardSelectComponents=ܤ +SelectComponentsDesc=ܱN|Qw˪C +SelectComponentsLabel2=ܱzQnw˪FMzQw˪CM [U@B] ~wˡC +FullInstallation=w +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=̤pw +CustomInstallation=ۭqw +NoUninstallWarningTitle=wsb +NoUninstallWarning=w˵{HUwgw˦bzqW:%n%n%1%n%nܳoǤN|̡C%n%nzMn~? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel=ثeܻݭnܤ [mb] MB ϺЪŶC + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=ܪ[u@ +SelectTasksDesc=ܭn檺[u@C +SelectTasksLabel2=ܦw˵{bw [name] ɭn檺[u@AM [U@B]C + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=ܡu}lv\Ƨ +SelectStartMenuFolderDesc=ܦw˵{إߵ{|mC +SelectStartMenuFolderLabel3=w˵{N|{|إߦbUu}lv\ƧC +SelectStartMenuFolderBrowseLabel= [U@B] ~ApGzQܥt@ӸƧAЫ [s]C +MustEnterGroupName=zJ@ӸƧW١C +GroupNameTooLong=ƧW٩θ|ӪC +InvalidGroupName=ƧW٤TC +BadGroupName=ƧW٤o]tUCr:%n%n%1 +NoProgramGroupCheck2=nbu}lv\إ߸Ƨ(&D) + +; *** "Ready to Install" wizard page +WizardReady=dzƦw +ReadyLabel1=w˵{N}lw [name] zqC +ReadyLabel2a=U [w] ~wˡAΫ [W@B] s˵γ]wUﶵeC +ReadyLabel2b=U [w] ~wˡC +ReadyMemoUserInfo=ϥΪ̸T +ReadyMemoDir=تƧ: +ReadyMemoType=w˫A: +ReadyMemoComponents=ܪ: +ReadyMemoGroup=u}lv\Ƨ: +ReadyMemoTasks=[u@: +; *** "Preparing to Install" wizard page +WizardPreparing=dzƦw˵{ +PreparingDesc=w˵{dzƱN [name] w˨zqWC +PreviousInstallNotCompleted=ew/ Ѱw˩|AzsҰʹqHӦwˡC%n%nbsҰʹqAЦAoӵ{Ӧw [name]C +CannotContinue=w˵{Lk~CЫ [] }C +ApplicationsFound=Uε{bϥΦw˵{һݭnsɡCijz\w˵{۰oε{C +ApplicationsFound2=Uε{bϥΦw˵{һݭnsɡCijz\w˵{۰oε{Cw˹L{Aw˵{N|խs}Ҹε{C +CloseApplications=ε{(&A) +DontCloseApplications=nε{ (&D) +ErrorCloseApplications=w˵{Lk۰Ҧε{Cijzb~eҦε{ϥΪɮסC +; *** "Installing" wizard page +WizardInstalling=bw +InstallingLabel=еyԡAw˵{bN [name] w˨zqW + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=w˧ +FinishedLabelNoIcons=w˵{wgN [name] w˦bzqWC +FinishedLabel=w˵{wgN [name] w˦bzqAziHܵ{ϥܨӰε{C +ClickFinish= [] Hw˵{C +FinishedRestartLabel=n [name] wˡAw˵{sҰʱzqCzQn{bsҰʹq? +FinishedRestartMessage=n [name] wˡAw˵{sҰʱzqC%n%nzQn{bsҰʹq? +ShowReadmeCheck=OAڭn\ŪŪɮסC +YesRadio=OAߧYsҰʹq(&Y) +NoRadio=_Aڵy᭫sҰʹq(&N) +; used for example as 'Run MyProg.exe' +RunEntryExec= %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=˵ %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=w˵{ݭnU@iϤ +SelectDiskLabel2=дJϤ %1AM [Tw]C%n%npGɮפbHUܪƧAпJTƧW٩Ϋ [s] C +PathLabel=|(&P): +FileNotInDir2=ɮס%1Lkb%2CдJTϤοܨ䥦ƧC +SelectDirectoryLabel=ЫwU@iϤmC + +; *** Installation phase messages +SetupAborted=w˨SC%n%nЧ󥿰D᭫swˤ@C +EntryAbortRetryIgnore= [] դ@AU [L] LoɮסAΫU [] wˡC + +; *** Installation status messages +StatusClosingApplications=bε{... +StatusCreateDirs=bإ߸Ƨ... +StatusExtractFiles=bYɮ... +StatusCreateIcons=bإߵ{ϥ... +StatusCreateIniEntries=gJ INI ɮת... +StatusCreateRegistryEntries=bstεn... +StatusRegisterFiles=bnɮ... +StatusSavingUninstall=xsѰw˸T... +StatusRunProgram=bw... +StatusRestartingApplications=bs}ε{... +StatusRollback=b_ܧ... + +; *** Misc. errors +ErrorInternal2=~: %1 +ErrorFunctionFailedNoCode=%1 +ErrorFunctionFailed=%1 ѡFNX %2 +ErrorFunctionFailedWithMessage=%1 ѡFNX %2.%n%3 +ErrorExecutingProgram=Lkɮ:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Lk}ҵn:%n%1\%2 +ErrorRegCreateKey=Lkإߵn:%n%1\%2 +ErrorRegWriteKey=Lkܧn:%n%1\%2 + +; *** INI errors +ErrorIniEntry=bɮס%1إ INI ؿ~C + +; *** File copying errors +FileAbortRetryIgnore= [] Aդ@A [L] Loɮס]ij^AΫ [] wˡC +FileAbortRetryIgnore2= [] Aդ@A [L] ~i]ij^AΫ [] wˡC +SourceIsCorrupted=ӷɮפwglC +SourceDoesntExist=ӷɮס%1sbC +ExistingFileReadOnly=ɮݩʤw]ŪC%n%n [] NŪݩʲ}Aդ@A [L] LoɮסAΫ [] wˡC +ErrorReadingExistingDest=Ū@Ӥwsbɮ׮ɵoͿ~: +FileExists=ɮפwgsbCznNثeɮ׶? +ExistingFileNewer=sbɮתsAijzOdثewsbɮסC%n%nznOdثewsbɮ׶? +ErrorChangingAttr=bܧɮݩʮɵoͿ~: +ErrorCreatingTemp=bتƧإɮ׮ɵoͿ~: +ErrorReadingSource=Ūlɮ׮ɵoͿ~: +ErrorCopying=_ɮ׮ɵoͿ~: +ErrorReplacingExistingFile=Nɮ׮ɵoͿ~: +ErrorRestartReplace=sҰʹqNɮץ: +ErrorRenamingTemp=bتƧܧɮצWٮɵoͿ~: +ErrorRegisterServer=Lk`U DLL/OCX ɮ: %1C +ErrorRegSvr32Failed=RegSvr32 ѡFhXNX %1 +ErrorRegisterTypeLib=Lk`Uw: %1C + +; *** Post-installation errors +ErrorOpeningReadme=}Ūɮ׮ɵoͿ~C +ErrorRestartingComputer=w˵{LksҰʹqAХHʤ覡ۦ歫sҰʹqC + +; *** Uninstaller messages +UninstallNotFound=ɮס%1sbALk{C +UninstallOpenError=Lk}ɮס%1ALk{C +UninstallUnsupportedVer=oӪѰw˵{LkѰO %1 榡ALkѰwˡC +UninstallUnknownEntry=Ѱw˰Oɤo{O (%1)C +ConfirmUninstall=zTwn %1 Ψɮ׶? +UninstallOnlyOnWin64=oӵ{ub 64 줸 Windows WѰwˡC +OnlyAdminCanUninstall=oӵ{nƨtκ޲zvϥΪ̤iѰwˡC +UninstallStatusLabel=bqzq %1 Aеy... +UninstalledAll=%1 wg\qzqC +UninstalledMost=%1 Ѱw˧C%n%nYɮפΤLkAziHۦRoɮסC +UninstalledAndNeedsRestart=n %1 Ѱw˵{ǡAzsҰʹqC%n%nzQn{bsҰʹq? +UninstallDataCorrupted=ɮס%1wglALkѰwˡC + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=@ɮ +ConfirmDeleteSharedFile2=tܤUC@ɮפwAQ{ҨϥΡAznoɮ׶?%n%n%1%n%nխYzFHWɮצ{ݭnϥΥ̡ANyoǵ{Lk`A]zYLkTwп [_]COdoɮצbztΤ|yl`C +SharedFileNameLabel=ɮצW: +SharedFileLocationLabel=m: +WizardUninstalling=Ѱw˪A +StatusUninstalling=bѰw %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=bw %1. +ShutdownBlockReasonUninstallingApp=bѰw %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] +NameAndVersion=%1 %2 +AdditionalIcons=[ϥ: +CreateDesktopIcon=إ߮ୱϥ(&D) +CreateQuickLaunchIcon=إߧֳtҰʹϥ(&Q) +ProgramOnTheWeb=%1 +UninstallProgram=Ѱw %1 +LaunchProgram=Ұ %1 +AssocFileExtension=N %1 PɮװɦW %2 p(&A) +AssocingFileExtension=bN %1 PɮװɦW %2 p... +AutoStartProgramGroupDescription=}: +AutoStartProgram=۰ʶ} %1 +AddonHostProgramNotFound=%1 Lkbzҿ諸ƧC%n%nzO_٭n~H + diff --git a/distrib/Languages/Korean.isl b/distrib/Languages/Korean.isl index e775d84bb3f..d99d3fd853f 100644 --- a/distrib/Languages/Korean.isl +++ b/distrib/Languages/Korean.isl @@ -1,322 +1,322 @@ -; *** Inno Setup version 5.5.3+ Korean messages *** -; -; 5.5.3+ Translator: Domddol (domddol@gmail.com) -; Translation date: MAR 04, 2014 -; Contributors: Hansoo KIM (iryna7@gmail.com), Woong-Jae An (a183393@hanmail.net) -; Storage: http://www.jrsoftware.org/files/istrans/ -; ο ѱ Ģ ؼմϴ. - -[LangOptions] -LanguageName=Korean -LanguageID=$0412 -LanguageCodePage=949 - -[Messages] - -; *** Application titles -SetupAppTitle=ġ -SetupWindowTitle=%1 ġ -UninstallAppTitle= -UninstallAppFullTitle=%1 - -; *** Misc. common -InformationTitle= -ConfirmTitle=Ȯ -ErrorTitle= - -; *** SetupLdr messages -SetupLdrStartupMessage=%1() ġմϴ, Ͻðڽϱ? -LdrCannotCreateTemp=ӽ ϴ, ġ ߴմϴ -LdrCannotExecTemp=ӽ ϴ, ġ ߴմϴ - -; *** Startup error messages -LastErrorMessage=%1.%n%n %2: %3 -SetupFileMissing=%1 ʽϴ, ذ ų ο ġ α׷ Ͻñ ٶϴ. -SetupFileCorrupt=ġ ջǾϴ, ο ġ α׷ Ͻñ ٶϴ. -SetupFileCorruptOrWrongVer=ġ ջ̰ų ġ ȣȯ ʽϴ, ذ ų ο ġ α׷ Ͻñ ٶϴ. -InvalidParameter=߸ Ű Դϴ:%n%n%1 -SetupAlreadyRunning=ġ ̹ Դϴ. -WindowsVersionNotSupported= α׷ Windows ʽϴ. -WindowsServicePackRequired= α׷ Ϸ %1 sp%2 ̻̾ մϴ. -NotOnThisPlatform= α׷ %1 ۵ ʽϴ. -OnlyOnThisPlatform= α׷ %1 ؾ մϴ. -OnlyOnTheseArchitectures= α׷ Ʒ ó ȣȯǴ Windows ġ ֽϴ:%n%n%1 -MissingWOW64APIs= Windows 64Ʈ ġ ʿ ԵǾ ʽϴ, ذϷ sp%1() ġϽñ ٶϴ. -WinVersionTooLowError= α׷ %1 %2 ̻ ʿմϴ. -WinVersionTooHighError= α׷ %1 %2 ̻󿡼 ġ ϴ. -AdminPrivilegesRequired= α׷ ġϷ ڷ αؾ մϴ. -PowerUserPrivilegesRequired= α׷ ġϷ Ǵ ڷ αؾ մϴ. -SetupAppRunningError= %1() Դϴ!%n%n װ νϽ ݾ ֽʽÿ. ׷ Ϸ "Ȯ", Ϸ "" ŬϽʽÿ. -UninstallAppRunningError= %1() Դϴ!%n%n װ νϽ ݾ ֽʽÿ. ׷ Ϸ "Ȯ", Ϸ "" ŬϽʽÿ. - -; *** Misc. errors -ErrorCreatingDir="%1" ϴ. -ErrorTooManyFilesInDir="%1" ʹ ϴ. - -; *** Setup common messages -ExitSetupTitle=ġ Ϸ -ExitSetupMessage=ġ Ϸ ʾҽϴ, ⼭ ġ ϸ α׷ ġ ʽϴ.%n%nġ ϷϷ ߿ ٽ ġ α׷ ؾ մϴ.%n%n׷ ġ Ͻðڽϱ? -AboutSetupMenuItem=ġ (&A)... -AboutSetupTitle=ġ -AboutSetupMessage=%1 %2%n%3%n%n%1 Ȩ :%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< ڷ(&B) -ButtonNext=(&N) > -ButtonInstall=ġ(&I) -ButtonOK=Ȯ -ButtonCancel= -ButtonYes=(&Y) -ButtonYesToAll= (&A) -ButtonNo=ƴϿ(&N) -ButtonNoToAll= ƴϿ(&O) -ButtonFinish=(&F) -ButtonBrowse=ãƺ(&B)... -ButtonWizardBrowse=ãƺ(&R)... -ButtonNewFolder= (&M) - -; *** "Select Language" dialog messages -SelectLanguageTitle=ġ -SelectLanguageLabel=ġ ǥ : - -; *** Common wizard text -ClickNext=Ϸ "" Ŭϰ ġ Ϸ "" Ŭմϴ. -BeveledLabel= -BrowseDialogTitle= ãƺ -BrowseDialogLabel=Ʒ Ͽ "Ȯ" Ŭմϴ. -NewFolderName= - -; *** "Welcome" wizard page -WelcomeLabel1=[name] ġ -WelcomeLabel2= ǻͿ [name/ver]() ġ Դϴ.%n%nġϱ ٸ α׷ ñ ٶϴ. - -; *** "Password" wizard page -WizardPassword= ȣ -PasswordLabel1= ġ ȣ ȣǾ ֽϴ. -PasswordLabel3= ȣ Էϰ "" ŬϽʽÿ. ȣ ҹڸ ؾ մϴ. -PasswordEditLabel= ȣ(&P): -IncorrectPassword= ȣ Ȯ ʽϴ, ٽ ԷϽʽÿ! - -; *** "License Agreement" wizard page -WizardLicense= -LicenseLabel=ϱ ߿ оʽÿ. -LicenseLabel3= оʽÿ, ġ Ϸ ࿡ ؾ մϴ. -LicenseAccepted=մϴ(&A) -LicenseNotAccepted= ʽϴ(&D) - -; *** "Information" wizard pages -WizardInfoBefore= -InfoBeforeLabel=ϱ ߿ оʽÿ. -InfoBeforeClickLabel=ġ Ϸ "" ŬϽʽÿ. -WizardInfoAfter= -InfoAfterLabel=ϱ ߿ оʽÿ. -InfoAfterClickLabel=ġ Ϸ "" ŬϽʽÿ. - -; *** "User Information" wizard page -WizardUserInfo= -UserInfoDesc= ԷϽʽÿ. -UserInfoName= ̸(&U): -UserInfoOrg=(&O): -UserInfoSerial=Ϸ ȣ(&S): -UserInfoNameRequired= ̸ ԷϽʽÿ. - -; *** "Select Destination Location" wizard page -WizardSelectDir=ġ ġ -SelectDirDesc=[name] ġ ġ Ͻʽÿ. -SelectDirLabel3= [name]() ġմϴ. -SelectDirBrowseLabel=Ϸ "", ٸ Ϸ "ãƺ" ŬϽʽÿ. -DiskSpaceMBLabel= α׷ ּ [mb] MB ũ ʿմϴ. -CannotInstallToNetworkDrive=Ʈũ ̺꿡 ġ ϴ. -CannotInstallToUNCPath=UNC ο ġ ϴ. -InvalidPath=̺ ڸ ü θ ԷϽʽÿ.%n : C:\APP %n%nǴ, UNC θ ԷϽʽÿ.%n : \\server\share -InvalidDrive= ̺ Ǵ UNC ʰų ׼ ϴ, ٸ θ Ͻʽÿ. -DiskSpaceWarningTitle=ũ մϴ -DiskSpaceWarning=ġ ּ %1 KB ũ ʿ, ̺ %2 KB ۿ ϴ.%n%n׷ Ͻðڽϱ? -DirNameTooLong= ̸ Ǵ ΰ ʹ ϴ. -InvalidDirName= ̸ ȿ ʽϴ. -BadDirName32= ̸ ڸ ϴ:%n%n%1 -DirExistsTitle= մϴ -DirExists= %n%n%1%n%n() ̹ մϴ, ġϽðڽϱ? -DirDoesntExistTitle= ʽϴ -DirDoesntExist= %n%n%1%n%n() ʽϴ, ðڽϱ? - -; *** "Select Components" wizard page -WizardSelectComponents= -SelectComponentsDesc=ġ Ҹ Ͻʽÿ. -SelectComponentsLabel2=ʿ Ҵ üũϰ ʿ Ҵ üũ մϴ, Ϸ "" ŬϽʽÿ. -FullInstallation= ġ -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=ּ ġ -CustomInstallation= ġ -NoUninstallWarningTitle= Ұ մϴ -NoUninstallWarning= Ұ ̹ ġǾ ֽϴ:%n%n%1%n%n , α׷ Ž ҵ ŵ ̴ϴ.%n%n׷ Ͻðڽϱ? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel= ּ [mb] MB ũ ʿմϴ. - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=߰ ۾ -SelectTasksDesc= ߰ ۾ Ͻʽÿ. -SelectTasksLabel2=[name] ġ ߰ ۾ , "" ŬϽʽÿ. - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup= ޴ -SelectStartMenuFolderDesc= α׷ ٷΰ⸦ ġϰڽϱ? -SelectStartMenuFolderLabel3= ޴ α׷ ٷΰ⸦ ϴ. -SelectStartMenuFolderBrowseLabel=Ϸ "" Ŭϰ, ٸ Ϸ "ãƺ" ŬϽʽÿ. -MustEnterGroupName= ̸ ԷϽʽÿ. -GroupNameTooLong= ̸ Ǵ ΰ ʹ ϴ. -InvalidGroupName= ̸ ȿ ʽϴ. -BadGroupName= ̸ ڸ ϴ:%n%n%1 -NoProgramGroupCheck2= ޴ (&D) - -; *** "Ready to Install" wizard page -WizardReady=ġ غ Ϸ -ReadyLabel1= ǻͿ [name]() ġ غ Ǿϴ. -ReadyLabel2a=ġ Ϸ "ġ", ϰų Ϸ "ڷ" ŬϽʽÿ. -ReadyLabel2b=ġ Ϸ "ġ" ŬϽʽÿ. -ReadyMemoUserInfo= : -ReadyMemoDir=ġ ġ: -ReadyMemoType=ġ : -ReadyMemoComponents= : -ReadyMemoGroup= ޴ : -ReadyMemoTasks=߰ ۾: - -; *** "Preparing to Install" wizard page -WizardPreparing=ġ غ -PreparingDesc= ǻͿ [name] ġ غϴ Դϴ. -PreviousInstallNotCompleted= α׷ ġ/ ۾ Ϸ ʾҽϴ, ϷϷ ǻ͸ ٽ ؾ մϴ.%n%nǻ͸ ٽ , ġ 縦 ٽ Ͽ [name] ġ ϷϽñ ٶϴ. -CannotContinue=ġ ϴ, "" ŬϿ ġ Ͻʽÿ. -ApplicationsFound= α׷ ġ Ʈ ʿ ϰ ֽϴ, ġ 簡 ̷ α׷ ڵ ֵ Ͻñ ٶϴ. -ApplicationsFound2= α׷ ġ Ʈ ʿ ϰ ֽϴ, ġ 簡 ̷ α׷ ڵ ֵ Ͻñ ٶϴ. ġ ϷǸ, ġ α׷ ٽ ۵ǵ õ ̴ϴ. -CloseApplications=ڵ α׷ (&A) -DontCloseApplications=α׷ (&D) -ErrorCloseApplications=ġ 簡 α׷ ڵ ϴ, ϱ ġ Ʈ ʿ ϰ ִ α׷ Ͻñ ٶϴ. - -; *** "Installing" wizard page -WizardInstalling=ġ -InstallingLabel= ǻͿ [name]() ġϴ ... ٷ ֽʽÿ. - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=[name] ġ Ϸ -FinishedLabelNoIcons= ǻͿ [name]() ġǾϴ. -FinishedLabel= ǻͿ [name]() ġǾϴ, α׷ ġ Ͽ ֽϴ. -ClickFinish=ġ "" ŬϽʽÿ. -FinishedRestartLabel=[name] ġ ϷϷ, ǻ͸ ٽ ؾ մϴ. ٽ Ͻðڽϱ? -FinishedRestartMessage=[name] ġ ϷϷ, ǻ͸ ٽ ؾ մϴ.%n%n ٽ Ͻðڽϱ? -ShowReadmeCheck=, README ǥմϴ -YesRadio=, ٽ մϴ(&Y) -NoRadio=ƴϿ, ߿ ٽ մϴ(&N) -; used for example as 'Run MyProg.exe' -RunEntryExec=%1 -; used for example as 'View Readme.txt' -RunEntryShellExec=%1 ǥ - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=ũ ʿմϴ -SelectDiskLabel2=ũ %1() ϰ "Ȯ" ŬϽʽÿ.%n%n ũ Ʒ ΰ ƴ ִ , ùٸ θ Էϰų "ãƺ" ŬϽñ ٶϴ. -PathLabel=(&P): -FileNotInDir2=%2 %1() ġ ϴ, ùٸ ũ ϰų ٸ Ͻʽÿ. -SelectDirectoryLabel= ũ ġ Ͻʽÿ. - -; *** Installation phase messages -SetupAborted=ġ Ϸ ʾҽϴ.%n%n ذ , ٽ ġ Ͻʽÿ. -EntryAbortRetryIgnore=ٽ õϷ "õ", ϰ Ϸ "", ġ Ϸ "" ŬϽʽÿ. - -; *** Installation status messages -StatusClosingApplications=α׷ ϴ ... -StatusCreateDirs= ... -StatusExtractFiles= ϴ ... -StatusCreateIcons=ٷΰ⸦ ϴ ... -StatusCreateIniEntries=INI ׸ ... -StatusCreateRegistryEntries=Ʈ ׸ ... -StatusRegisterFiles= ϴ ... -StatusSavingUninstall= ϴ ... -StatusRunProgram=ġ Ϸϴ ... -StatusRestartingApplications=α׷ ٽ ϴ ... -StatusRollback= ϴ ... - -; *** Misc. errors -ErrorInternal2= : %1 -ErrorFunctionFailedNoCode=%1 -ErrorFunctionFailed=%1 , ڵ: %2 -ErrorFunctionFailedWithMessage=%1 , ڵ: %2.%n%3 -ErrorExecutingProgram= :%n%1 - -; *** Registry errors -ErrorRegOpenKey=Ʈ Ű :%n%1\%2 -ErrorRegCreateKey=Ʈ Ű :%n%1\%2 -ErrorRegWriteKey=Ʈ Ű :%n%1\%2 - -; *** INI errors -ErrorIniEntry=%1 Ͽ INI ׸ Դϴ. - -; *** File copying errors -FileAbortRetryIgnore=ٽ õϷ "õ", dzʶٷ ""(õ), ġ Ϸ "" ŬϽʽÿ. -FileAbortRetryIgnore2=ٽ õϷ "õ", Ϸ ""(õ), ġ Ϸ "" ŬϽʽÿ. -SourceIsCorrupted= ջ -SourceDoesntExist= %1() -ExistingFileReadOnly= б Դϴ.%n%nб Ӽ ϰ ٽ õϷ "õ", dzʶٷ "", ġ Ϸ "" ŬϽʽÿ. -ErrorReadingExistingDest= д ߻: -FileExists= ̹ մϴ.%n%n ðڽϱ? -ExistingFileNewer= ġϷ ϴ Ϻ Դϴ, Ͻñ ٶϴ.%n%n Ͻðڽϱ? -ErrorChangingAttr= Ӽ ϴ ߻: -ErrorCreatingTemp= ߻: -ErrorReadingSource= д ߻: -ErrorCopying= ϴ ߻: -ErrorReplacingExistingFile= üϴ ߻: -ErrorRestartReplace=RestartReplace : -ErrorRenamingTemp= ̸ ٲٴ ߻: -ErrorRegisterServer=DLL/OCX : %1 -ErrorRegSvr32Failed=RegSvr32 ڵ : %1 -ErrorRegisterTypeLib= ̺귯 Ͽ : %1 - -; *** Post-installation errors -ErrorOpeningReadme=README ߻߽ϴ. -ErrorRestartingComputer=ǻ͸ ٽ ϴ, ٽ Ͻʽÿ. - -; *** Uninstaller messages -UninstallNotFound= %1() ʱ , Ÿ ϴ. -UninstallOpenError= %1() , Ÿ ϴ. -UninstallUnsupportedVer= α "%1"() ν ̱ , Ÿ ϴ. -UninstallUnknownEntry= ׸ %1() α׿ ԵǾ ֽϴ. -ConfirmUninstall= %1() Ҹ Ͻðڽϱ? -UninstallOnlyOnWin64= α׷ 64Ʈ Windows ֽϴ. -OnlyAdminCanUninstall= α׷ Ϸ ʿմϴ. -UninstallStatusLabel= ǻͿ %1() ϴ ... ٷ ֽʽÿ. -UninstalledAll=%1() ŵǾϴ! -UninstalledMost=%1 Ű ϷǾϴ.%n%nϺ Ҵ , Ͻñ ٶϴ. -UninstalledAndNeedsRestart=%1 Ÿ ϷϷ, ǻ͸ ٽ ؾ մϴ.%n%n ٽ Ͻðڽϱ? -UninstallDataCorrupted= "%1"() ջǾ , Ÿ ϴ. - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle= Ͻðڽϱ? -ConfirmDeleteSharedFile2=ý  α׷ ʽϴ, Ͻðڽϱ?%n%n ٸ α׷ ϰ ִ ¿ , ش α׷ ۵ , Ȯ "ƴϿ" ϼŵ ˴ϴ. ýۿ ־ ʽϴ. -SharedFileNameLabel= ̸: -SharedFileLocationLabel=ġ: -WizardUninstalling= -StatusUninstalling=%1() ϴ ... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=%1() ġϴ Դϴ. -ShutdownBlockReasonUninstallingApp=%1() ϴ Դϴ. - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] - -NameAndVersion=%1 %2 -AdditionalIcons= ߰: -CreateDesktopIcon= ȭ鿡 ٷΰ (&D) -CreateQuickLaunchIcon= (&Q) -ProgramOnTheWeb=%1 -UninstallProgram=%1 -LaunchProgram=%1 -AssocFileExtension= Ȯ %2() %1 մϴ. -AssocingFileExtension= Ȯ %2() %1 ϴ ... -AutoStartProgramGroupDescription=: -AutoStartProgram=%1() ڵ -AddonHostProgramNotFound=%1() ġ ϴ.%n%n׷ Ͻðڽϱ? +; *** Inno Setup version 5.5.3+ Korean messages *** +; +; 5.5.3+ Translator: Domddol (domddol@gmail.com) +; Translation date: MAR 04, 2014 +; Contributors: Hansoo KIM (iryna7@gmail.com), Woong-Jae An (a183393@hanmail.net) +; Storage: http://www.jrsoftware.org/files/istrans/ +; ο ѱ Ģ ؼմϴ. + +[LangOptions] +LanguageName=Korean +LanguageID=$0412 +LanguageCodePage=949 + +[Messages] + +; *** Application titles +SetupAppTitle=ġ +SetupWindowTitle=%1 ġ +UninstallAppTitle= +UninstallAppFullTitle=%1 + +; *** Misc. common +InformationTitle= +ConfirmTitle=Ȯ +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage=%1() ġմϴ, Ͻðڽϱ? +LdrCannotCreateTemp=ӽ ϴ, ġ ߴմϴ +LdrCannotExecTemp=ӽ ϴ, ġ ߴմϴ + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing=%1 ʽϴ, ذ ų ο ġ α׷ Ͻñ ٶϴ. +SetupFileCorrupt=ġ ջǾϴ, ο ġ α׷ Ͻñ ٶϴ. +SetupFileCorruptOrWrongVer=ġ ջ̰ų ġ ȣȯ ʽϴ, ذ ų ο ġ α׷ Ͻñ ٶϴ. +InvalidParameter=߸ Ű Դϴ:%n%n%1 +SetupAlreadyRunning=ġ ̹ Դϴ. +WindowsVersionNotSupported= α׷ Windows ʽϴ. +WindowsServicePackRequired= α׷ Ϸ %1 sp%2 ̻̾ մϴ. +NotOnThisPlatform= α׷ %1 ۵ ʽϴ. +OnlyOnThisPlatform= α׷ %1 ؾ մϴ. +OnlyOnTheseArchitectures= α׷ Ʒ ó ȣȯǴ Windows ġ ֽϴ:%n%n%1 +MissingWOW64APIs= Windows 64Ʈ ġ ʿ ԵǾ ʽϴ, ذϷ sp%1() ġϽñ ٶϴ. +WinVersionTooLowError= α׷ %1 %2 ̻ ʿմϴ. +WinVersionTooHighError= α׷ %1 %2 ̻󿡼 ġ ϴ. +AdminPrivilegesRequired= α׷ ġϷ ڷ αؾ մϴ. +PowerUserPrivilegesRequired= α׷ ġϷ Ǵ ڷ αؾ մϴ. +SetupAppRunningError= %1() Դϴ!%n%n װ νϽ ݾ ֽʽÿ. ׷ Ϸ "Ȯ", Ϸ "" ŬϽʽÿ. +UninstallAppRunningError= %1() Դϴ!%n%n װ νϽ ݾ ֽʽÿ. ׷ Ϸ "Ȯ", Ϸ "" ŬϽʽÿ. + +; *** Misc. errors +ErrorCreatingDir="%1" ϴ. +ErrorTooManyFilesInDir="%1" ʹ ϴ. + +; *** Setup common messages +ExitSetupTitle=ġ Ϸ +ExitSetupMessage=ġ Ϸ ʾҽϴ, ⼭ ġ ϸ α׷ ġ ʽϴ.%n%nġ ϷϷ ߿ ٽ ġ α׷ ؾ մϴ.%n%n׷ ġ Ͻðڽϱ? +AboutSetupMenuItem=ġ (&A)... +AboutSetupTitle=ġ +AboutSetupMessage=%1 %2%n%3%n%n%1 Ȩ :%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< ڷ(&B) +ButtonNext=(&N) > +ButtonInstall=ġ(&I) +ButtonOK=Ȯ +ButtonCancel= +ButtonYes=(&Y) +ButtonYesToAll= (&A) +ButtonNo=ƴϿ(&N) +ButtonNoToAll= ƴϿ(&O) +ButtonFinish=(&F) +ButtonBrowse=ãƺ(&B)... +ButtonWizardBrowse=ãƺ(&R)... +ButtonNewFolder= (&M) + +; *** "Select Language" dialog messages +SelectLanguageTitle=ġ +SelectLanguageLabel=ġ ǥ : + +; *** Common wizard text +ClickNext=Ϸ "" Ŭϰ ġ Ϸ "" Ŭմϴ. +BeveledLabel= +BrowseDialogTitle= ãƺ +BrowseDialogLabel=Ʒ Ͽ "Ȯ" Ŭմϴ. +NewFolderName= + +; *** "Welcome" wizard page +WelcomeLabel1=[name] ġ +WelcomeLabel2= ǻͿ [name/ver]() ġ Դϴ.%n%nġϱ ٸ α׷ ñ ٶϴ. + +; *** "Password" wizard page +WizardPassword= ȣ +PasswordLabel1= ġ ȣ ȣǾ ֽϴ. +PasswordLabel3= ȣ Էϰ "" ŬϽʽÿ. ȣ ҹڸ ؾ մϴ. +PasswordEditLabel= ȣ(&P): +IncorrectPassword= ȣ Ȯ ʽϴ, ٽ ԷϽʽÿ! + +; *** "License Agreement" wizard page +WizardLicense= +LicenseLabel=ϱ ߿ оʽÿ. +LicenseLabel3= оʽÿ, ġ Ϸ ࿡ ؾ մϴ. +LicenseAccepted=մϴ(&A) +LicenseNotAccepted= ʽϴ(&D) + +; *** "Information" wizard pages +WizardInfoBefore= +InfoBeforeLabel=ϱ ߿ оʽÿ. +InfoBeforeClickLabel=ġ Ϸ "" ŬϽʽÿ. +WizardInfoAfter= +InfoAfterLabel=ϱ ߿ оʽÿ. +InfoAfterClickLabel=ġ Ϸ "" ŬϽʽÿ. + +; *** "User Information" wizard page +WizardUserInfo= +UserInfoDesc= ԷϽʽÿ. +UserInfoName= ̸(&U): +UserInfoOrg=(&O): +UserInfoSerial=Ϸ ȣ(&S): +UserInfoNameRequired= ̸ ԷϽʽÿ. + +; *** "Select Destination Location" wizard page +WizardSelectDir=ġ ġ +SelectDirDesc=[name] ġ ġ Ͻʽÿ. +SelectDirLabel3= [name]() ġմϴ. +SelectDirBrowseLabel=Ϸ "", ٸ Ϸ "ãƺ" ŬϽʽÿ. +DiskSpaceMBLabel= α׷ ּ [mb] MB ũ ʿմϴ. +CannotInstallToNetworkDrive=Ʈũ ̺꿡 ġ ϴ. +CannotInstallToUNCPath=UNC ο ġ ϴ. +InvalidPath=̺ ڸ ü θ ԷϽʽÿ.%n : C:\APP %n%nǴ, UNC θ ԷϽʽÿ.%n : \\server\share +InvalidDrive= ̺ Ǵ UNC ʰų ׼ ϴ, ٸ θ Ͻʽÿ. +DiskSpaceWarningTitle=ũ մϴ +DiskSpaceWarning=ġ ּ %1 KB ũ ʿ, ̺ %2 KB ۿ ϴ.%n%n׷ Ͻðڽϱ? +DirNameTooLong= ̸ Ǵ ΰ ʹ ϴ. +InvalidDirName= ̸ ȿ ʽϴ. +BadDirName32= ̸ ڸ ϴ:%n%n%1 +DirExistsTitle= մϴ +DirExists= %n%n%1%n%n() ̹ մϴ, ġϽðڽϱ? +DirDoesntExistTitle= ʽϴ +DirDoesntExist= %n%n%1%n%n() ʽϴ, ðڽϱ? + +; *** "Select Components" wizard page +WizardSelectComponents= +SelectComponentsDesc=ġ Ҹ Ͻʽÿ. +SelectComponentsLabel2=ʿ Ҵ üũϰ ʿ Ҵ üũ մϴ, Ϸ "" ŬϽʽÿ. +FullInstallation= ġ +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=ּ ġ +CustomInstallation= ġ +NoUninstallWarningTitle= Ұ մϴ +NoUninstallWarning= Ұ ̹ ġǾ ֽϴ:%n%n%1%n%n , α׷ Ž ҵ ŵ ̴ϴ.%n%n׷ Ͻðڽϱ? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel= ּ [mb] MB ũ ʿմϴ. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=߰ ۾ +SelectTasksDesc= ߰ ۾ Ͻʽÿ. +SelectTasksLabel2=[name] ġ ߰ ۾ , "" ŬϽʽÿ. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup= ޴ +SelectStartMenuFolderDesc= α׷ ٷΰ⸦ ġϰڽϱ? +SelectStartMenuFolderLabel3= ޴ α׷ ٷΰ⸦ ϴ. +SelectStartMenuFolderBrowseLabel=Ϸ "" Ŭϰ, ٸ Ϸ "ãƺ" ŬϽʽÿ. +MustEnterGroupName= ̸ ԷϽʽÿ. +GroupNameTooLong= ̸ Ǵ ΰ ʹ ϴ. +InvalidGroupName= ̸ ȿ ʽϴ. +BadGroupName= ̸ ڸ ϴ:%n%n%1 +NoProgramGroupCheck2= ޴ (&D) + +; *** "Ready to Install" wizard page +WizardReady=ġ غ Ϸ +ReadyLabel1= ǻͿ [name]() ġ غ Ǿϴ. +ReadyLabel2a=ġ Ϸ "ġ", ϰų Ϸ "ڷ" ŬϽʽÿ. +ReadyLabel2b=ġ Ϸ "ġ" ŬϽʽÿ. +ReadyMemoUserInfo= : +ReadyMemoDir=ġ ġ: +ReadyMemoType=ġ : +ReadyMemoComponents= : +ReadyMemoGroup= ޴ : +ReadyMemoTasks=߰ ۾: + +; *** "Preparing to Install" wizard page +WizardPreparing=ġ غ +PreparingDesc= ǻͿ [name] ġ غϴ Դϴ. +PreviousInstallNotCompleted= α׷ ġ/ ۾ Ϸ ʾҽϴ, ϷϷ ǻ͸ ٽ ؾ մϴ.%n%nǻ͸ ٽ , ġ 縦 ٽ Ͽ [name] ġ ϷϽñ ٶϴ. +CannotContinue=ġ ϴ, "" ŬϿ ġ Ͻʽÿ. +ApplicationsFound= α׷ ġ Ʈ ʿ ϰ ֽϴ, ġ 簡 ̷ α׷ ڵ ֵ Ͻñ ٶϴ. +ApplicationsFound2= α׷ ġ Ʈ ʿ ϰ ֽϴ, ġ 簡 ̷ α׷ ڵ ֵ Ͻñ ٶϴ. ġ ϷǸ, ġ α׷ ٽ ۵ǵ õ ̴ϴ. +CloseApplications=ڵ α׷ (&A) +DontCloseApplications=α׷ (&D) +ErrorCloseApplications=ġ 簡 α׷ ڵ ϴ, ϱ ġ Ʈ ʿ ϰ ִ α׷ Ͻñ ٶϴ. + +; *** "Installing" wizard page +WizardInstalling=ġ +InstallingLabel= ǻͿ [name]() ġϴ ... ٷ ֽʽÿ. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name] ġ Ϸ +FinishedLabelNoIcons= ǻͿ [name]() ġǾϴ. +FinishedLabel= ǻͿ [name]() ġǾϴ, α׷ ġ Ͽ ֽϴ. +ClickFinish=ġ "" ŬϽʽÿ. +FinishedRestartLabel=[name] ġ ϷϷ, ǻ͸ ٽ ؾ մϴ. ٽ Ͻðڽϱ? +FinishedRestartMessage=[name] ġ ϷϷ, ǻ͸ ٽ ؾ մϴ.%n%n ٽ Ͻðڽϱ? +ShowReadmeCheck=, README ǥմϴ +YesRadio=, ٽ մϴ(&Y) +NoRadio=ƴϿ, ߿ ٽ մϴ(&N) +; used for example as 'Run MyProg.exe' +RunEntryExec=%1 +; used for example as 'View Readme.txt' +RunEntryShellExec=%1 ǥ + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=ũ ʿմϴ +SelectDiskLabel2=ũ %1() ϰ "Ȯ" ŬϽʽÿ.%n%n ũ Ʒ ΰ ƴ ִ , ùٸ θ Էϰų "ãƺ" ŬϽñ ٶϴ. +PathLabel=(&P): +FileNotInDir2=%2 %1() ġ ϴ, ùٸ ũ ϰų ٸ Ͻʽÿ. +SelectDirectoryLabel= ũ ġ Ͻʽÿ. + +; *** Installation phase messages +SetupAborted=ġ Ϸ ʾҽϴ.%n%n ذ , ٽ ġ Ͻʽÿ. +EntryAbortRetryIgnore=ٽ õϷ "õ", ϰ Ϸ "", ġ Ϸ "" ŬϽʽÿ. + +; *** Installation status messages +StatusClosingApplications=α׷ ϴ ... +StatusCreateDirs= ... +StatusExtractFiles= ϴ ... +StatusCreateIcons=ٷΰ⸦ ϴ ... +StatusCreateIniEntries=INI ׸ ... +StatusCreateRegistryEntries=Ʈ ׸ ... +StatusRegisterFiles= ϴ ... +StatusSavingUninstall= ϴ ... +StatusRunProgram=ġ Ϸϴ ... +StatusRestartingApplications=α׷ ٽ ϴ ... +StatusRollback= ϴ ... + +; *** Misc. errors +ErrorInternal2= : %1 +ErrorFunctionFailedNoCode=%1 +ErrorFunctionFailed=%1 , ڵ: %2 +ErrorFunctionFailedWithMessage=%1 , ڵ: %2.%n%3 +ErrorExecutingProgram= :%n%1 + +; *** Registry errors +ErrorRegOpenKey=Ʈ Ű :%n%1\%2 +ErrorRegCreateKey=Ʈ Ű :%n%1\%2 +ErrorRegWriteKey=Ʈ Ű :%n%1\%2 + +; *** INI errors +ErrorIniEntry=%1 Ͽ INI ׸ Դϴ. + +; *** File copying errors +FileAbortRetryIgnore=ٽ õϷ "õ", dzʶٷ ""(õ), ġ Ϸ "" ŬϽʽÿ. +FileAbortRetryIgnore2=ٽ õϷ "õ", Ϸ ""(õ), ġ Ϸ "" ŬϽʽÿ. +SourceIsCorrupted= ջ +SourceDoesntExist= %1() +ExistingFileReadOnly= б Դϴ.%n%nб Ӽ ϰ ٽ õϷ "õ", dzʶٷ "", ġ Ϸ "" ŬϽʽÿ. +ErrorReadingExistingDest= д ߻: +FileExists= ̹ մϴ.%n%n ðڽϱ? +ExistingFileNewer= ġϷ ϴ Ϻ Դϴ, Ͻñ ٶϴ.%n%n Ͻðڽϱ? +ErrorChangingAttr= Ӽ ϴ ߻: +ErrorCreatingTemp= ߻: +ErrorReadingSource= д ߻: +ErrorCopying= ϴ ߻: +ErrorReplacingExistingFile= üϴ ߻: +ErrorRestartReplace=RestartReplace : +ErrorRenamingTemp= ̸ ٲٴ ߻: +ErrorRegisterServer=DLL/OCX : %1 +ErrorRegSvr32Failed=RegSvr32 ڵ : %1 +ErrorRegisterTypeLib= ̺귯 Ͽ : %1 + +; *** Post-installation errors +ErrorOpeningReadme=README ߻߽ϴ. +ErrorRestartingComputer=ǻ͸ ٽ ϴ, ٽ Ͻʽÿ. + +; *** Uninstaller messages +UninstallNotFound= %1() ʱ , Ÿ ϴ. +UninstallOpenError= %1() , Ÿ ϴ. +UninstallUnsupportedVer= α "%1"() ν ̱ , Ÿ ϴ. +UninstallUnknownEntry= ׸ %1() α׿ ԵǾ ֽϴ. +ConfirmUninstall= %1() Ҹ Ͻðڽϱ? +UninstallOnlyOnWin64= α׷ 64Ʈ Windows ֽϴ. +OnlyAdminCanUninstall= α׷ Ϸ ʿմϴ. +UninstallStatusLabel= ǻͿ %1() ϴ ... ٷ ֽʽÿ. +UninstalledAll=%1() ŵǾϴ! +UninstalledMost=%1 Ű ϷǾϴ.%n%nϺ Ҵ , Ͻñ ٶϴ. +UninstalledAndNeedsRestart=%1 Ÿ ϷϷ, ǻ͸ ٽ ؾ մϴ.%n%n ٽ Ͻðڽϱ? +UninstallDataCorrupted= "%1"() ջǾ , Ÿ ϴ. + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle= Ͻðڽϱ? +ConfirmDeleteSharedFile2=ý  α׷ ʽϴ, Ͻðڽϱ?%n%n ٸ α׷ ϰ ִ ¿ , ش α׷ ۵ , Ȯ "ƴϿ" ϼŵ ˴ϴ. ýۿ ־ ʽϴ. +SharedFileNameLabel= ̸: +SharedFileLocationLabel=ġ: +WizardUninstalling= +StatusUninstalling=%1() ϴ ... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=%1() ġϴ Դϴ. +ShutdownBlockReasonUninstallingApp=%1() ϴ Դϴ. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 %2 +AdditionalIcons= ߰: +CreateDesktopIcon= ȭ鿡 ٷΰ (&D) +CreateQuickLaunchIcon= (&Q) +ProgramOnTheWeb=%1 +UninstallProgram=%1 +LaunchProgram=%1 +AssocFileExtension= Ȯ %2() %1 մϴ. +AssocingFileExtension= Ȯ %2() %1 ϴ ... +AutoStartProgramGroupDescription=: +AutoStartProgram=%1() ڵ +AddonHostProgramNotFound=%1() ġ ϴ.%n%n׷ Ͻðڽϱ? diff --git a/distrib/Languages/Slovak.isl b/distrib/Languages/Slovak.isl index 8805791de9c..43fa0c55c58 100644 --- a/distrib/Languages/Slovak.isl +++ b/distrib/Languages/Slovak.isl @@ -1,263 +1,263 @@ -; ****************************************************** -; *** *** -; *** Inno Setup version 5.5.3+ Slovak messages *** -; *** *** -; *** Original Author: *** -; *** *** -; *** Milan Potancok (milan.potancok AT gmail.com) *** -; *** *** -; *** Contributors: *** -; *** *** -; *** Ivo Bauer (bauer AT ozm.cz) *** -; *** *** -; *** Tomas Falb (tomasf AT pobox.sk) *** -; *** Slappy (slappy AT pobox.sk) *** -; *** *** -; *** Update: 04.02.2013 *** -; *** *** -; ****************************************************** -; -; - -[LangOptions] -LanguageName=Sloven<010D>ina -LanguageID=$041b -LanguageCodePage=1250 - -[Messages] -SetupAppTitle=Sprievodca intalciou -SetupWindowTitle=Sprievodca intalciou - %1 -UninstallAppTitle=Sprievodca odintalciou -UninstallAppFullTitle=Sprievodca odintalciou - %1 -InformationTitle=Informcie -ConfirmTitle=Potvrdenie -ErrorTitle=Chyba -SetupLdrStartupMessage=Toto je sprievodca intalciou produktu %1. Prajete si pokraova? -LdrCannotCreateTemp=Nie je mon vytvori doasn sbor. Sprievodca intalciou sa ukon -LdrCannotExecTemp=Nie je mon spusti sbor v doasnom adresri. Sprievodca intalciou sa ukon -LastErrorMessage=%1.%n%nChyba %2: %3 -SetupFileMissing=Intalan adresr neobsahuje sbor %1. Opravte, prosm, tto chybu alebo si zaobstarajte nov kpiu tohto produktu. -SetupFileCorrupt=Sbory sprievodcu intalciou s pokoden. Zaobstarajte si, prosm, nov kpiu tohto produktu. -SetupFileCorruptOrWrongVer=Sbory sprievodcu intalciou s pokoden alebo sa nezhoduj s touto verziou sprievodcu instalciou. Opravte, prosm, tto chybu alebo si zaobstarajte nov kpiu tohto produktu. -InvalidParameter=Nesprvny parameter na prkazovom riadku:%n%n%1 -SetupAlreadyRunning=Intalcia u be. -WindowsVersionNotSupported=Tento program nepodporuje vau verziu Windows. -WindowsServicePackRequired=Tento program vyaduje %1 Service Pack %2 alebo nov. -NotOnThisPlatform=Tento produkt sa ned spusti v %1. -OnlyOnThisPlatform=Tento produkt mus by spusten v %1. -OnlyOnTheseArchitectures=Tento produkt je mon naintalova iba vo verzich MS Windows s podporou architektry procesorov:%n%n%1 -MissingWOW64APIs=Aktulna verzia MS Windows neobsahuje funkcie, ktor vyaduje sprievodca intalciou pre 64-bitov intalciu. Opravte, prosm, tto chybu naintalovanm aktualizcie Service Pack %1. -WinVersionTooLowError=Tento produkt vyaduje %1 verzie %2 alebo vyej. -WinVersionTooHighError=Tento produkt sa ned naintalova vo %1 verzie %2 alebo vyej. -AdminPrivilegesRequired=Na intalciu tohto produktu muste by prihlsen s prvami administrtora. -PowerUserPrivilegesRequired=Na intalciu tohto produktu muste by prihlsen s prvami administrtora alebo lena skupiny Power Users. -SetupAppRunningError=Sprievodca intalciou zistil, e produkt %1 je teraz spusten.%n%nUkonite, prosm, vetky spusten intancie tohto produktu a pokraujte kliknutm na tlaidlo OK alebo ukonite intalciu tlaidlom Zrui. -UninstallAppRunningError=Sprievodca odintalciou zistil, e produkt %1 je teraz spusten.%n%nUkonite, prosm, vetky spusten intancie tohto produktu a pokraujte kliknutm na tlaidlo OK alebo ukonite intalciu tlaidlom Zrui. -ErrorCreatingDir=Sprievodca intalciou nemohol vytvori adresr "%1" -ErrorTooManyFilesInDir=Ned sa vytvori sbor v adresri "%1", pretoe tento adresr u obsahuje prli vea sborov -ExitSetupTitle=Ukoni sprievodcu intalciou -ExitSetupMessage=Intalcia nebola celkom dokonen. Ak teraz ukonte sprievodcu intalciou, produkt nebude naintalovan.%n%nSprievodcu intalciou mete znovu spusti neskr a dokoni tak intalciu.%n%nUkoni sprievodcu intalciou? -AboutSetupMenuItem=&O sprievodcovi intalcie... -AboutSetupTitle=O sprievodcovi intalcie -AboutSetupMessage=%1 verzia %2%n%3%n%n%1 domovsk strnka:%n%4 -AboutSetupNote= -TranslatorNote=Slovak translation maintained by Milan Potancok (milan.potancok AT gmail.com), Ivo Bauer (bauer AT ozm.cz) and Tomas Falb (tomasf AT pobox.sk) + Slappy (slappy AT pobox.sk) -ButtonBack=< &Sp -ButtonNext=&alej > -ButtonInstall=&Intalova -ButtonOK=OK -ButtonCancel=Zrui -ButtonYes=&no -ButtonYesToAll=no &vetkm -ButtonNo=&Nie -ButtonNoToAll=Ni&e vetkm -ButtonFinish=&Dokoni -ButtonBrowse=&Prechdza... -ButtonWizardBrowse=&Prechdza... -ButtonNewFolder=&Vytvori nov adresr -SelectLanguageTitle=Vber jazyka sprievodcu intalciou -SelectLanguageLabel=Zvote jazyk, ktor sa m poui pri intalcii: -ClickNext=Pokraujte kliknutm na tlaidlo alej alebo ukonite sprievodcu intalciou tlaidlom Zrui. -BeveledLabel= -BrowseDialogTitle=Njs adresr -BrowseDialogLabel=Z dole uvedenho zoznamu vyberte adresr a kliknite na OK. -NewFolderName=Nov adresr -WelcomeLabel1=Vt Vs sprievodca intalciou produktu [name]. -WelcomeLabel2=Produkt [name/ver] sa naintaluje na V pota.%n%nSkr, ako budete pokraova, odporame Vm ukoni vetky spusten aplikcie. -WizardPassword=Heslo -PasswordLabel1=Tto intalcia je chrnen heslom. -PasswordLabel3=Zadajte, prosm, heslo a pokraujte kliknutm na tlaidlo alej. Pri zadvn hesla rozliujte mal a vek psmen. -PasswordEditLabel=&Heslo: -IncorrectPassword=Zadan heslo nie je sprvne. Zkste to, prosm, ete raz. -WizardLicense=Licenn zmluva -LicenseLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. -LicenseLabel3=Pretajte si, prosm, tto Licenn zmluvu. Aby mohla intalcia pokraova, muste shlasi s podmienkami tejto zmluvy. -LicenseAccepted=&Shlasm s podmienkami Licennej zmluvy -LicenseNotAccepted=&Neshlasm s podmienkami Licennej zmluvy -WizardInfoBefore=Informcie -InfoBeforeLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. -InfoBeforeClickLabel=Pokraujte v intalcii kliknutm na tlaidlo alej. -WizardInfoAfter=Informcie -InfoAfterLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. -InfoAfterClickLabel=Pokraujte v intalcii kliknutm na tlaidlo alej. -WizardUserInfo=Informcie o pouvateovi -UserInfoDesc=Zadajte, prosm, poadovan informcie. -UserInfoName=&Pouvatesk meno: -UserInfoOrg=&Organizcia: -UserInfoSerial=&Sriove slo: -UserInfoNameRequired=Pouvatesk meno mus by zadan. -WizardSelectDir=Vyberte cieov adresr -SelectDirDesc=Kam m by produkt [name] naintalovan? -SelectDirLabel3=Sprievodca naintaluje produkt [name] do nasledujceho adresra. -SelectDirBrowseLabel=Pokraujte kliknutm na tlaidlo alej. Ak chcete vybra in adresr, kliknite na tlaidlo Prechdza. -DiskSpaceMBLabel=Intalcia vyaduje najmenej [mb] MB miesta na disku. -CannotInstallToNetworkDrive=Intaltor neme intalova na sieov jednotku. -CannotInstallToUNCPath=Intaltor neme intalova na UNC cestu. -InvalidPath=Muste zadat pln cestu vrtane psmena jednotky; naprklad:%n%nC:\Aplikcia%n%nalebo cestu UNC v tvare:%n%n\\server\zdiean adresr -InvalidDrive=Vami vybran jednotka alebo cesta UNC neexistuje alebo nie je dostupn. Vyberte, prosm, in umiestnenie. -DiskSpaceWarningTitle=Nedostatok miesta na disku -DiskSpaceWarning=Sprievodca intalciou vyaduje najmenej %1 KB vonho miesta na intalciu produktu, ale na vybranej jednotke je dostupnch len %2 KB.%n%nPrajete si napriek tomu pokraova? -DirNameTooLong=Nzov adresra alebo cesta s prli dlh. -InvalidDirName=Nzov adresra nie je platn. -BadDirName32=Nzvy adresrov nesm obsahova iadny z nasledujcich znakov:%n%n%1 -DirExistsTitle=Adresr existuje -DirExists=Adresr:%n%n%1%n%nu existuje. M sa napriek tomu intalova do tohto adresra? -DirDoesntExistTitle=Adresr neexistuje -DirDoesntExist=Adresr:%n%n%1%n%nete neexistuje. M sa tento adresr vytvori? -WizardSelectComponents=Vyberte komponenty -SelectComponentsDesc=Ak komponenty maj by naintalovan? -SelectComponentsLabel2=Zakrtnite komponenty, ktor maj by naintalovan; komponenty, ktor se nemaj intalova, nechajte nezakrtnut. Pokraujte kliknutm na tlaidlo alej. -FullInstallation=pln intalcia -CompactInstallation=Kompaktn intalcia -CustomInstallation=Voliten intalcia -NoUninstallWarningTitle=Komponenty existuj -NoUninstallWarning=Sprievodca intalciou zistil, e nasledujce komponenty s u na Vaom potai naintalovan:%n%n%1%n%nAk ich teraz nezahrniete do vberu, nebud neskr odintalovan.%n%nPrajete si napriek tomu pokraova? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=Vybran komponenty vyaduj najmenej [mb] MB miesta na disku. -WizardSelectTasks=Vyberte alie lohy -SelectTasksDesc=Ktor alie lohy maj by vykonan? -SelectTasksLabel2=Vyberte alie lohy, ktor maj by vykonan v priebehu intalcie produktu [name] a pokraujte kliknutm na tlaidlo alej. -WizardSelectProgramGroup=Vyberte skupinu v ponuke tart -SelectStartMenuFolderDesc=Kam m sprievodca intalcie umiestni zstupcov aplikcie? -SelectStartMenuFolderLabel3=Sprievodca intalciou vytvor zstupcov aplikcie v nasledujcom adresri ponuky tart. -SelectStartMenuFolderBrowseLabel=Pokraujte kliknutm na tlaidlo alej. Ak chcete zvoli in adresr, kliknite na tlaidlo Prechdza. -MustEnterGroupName=Muste zada nzov skupiny. -GroupNameTooLong=Nzov adresra alebo cesta s prli dlh. -InvalidGroupName=Nzov adresra nie je platn. -BadGroupName=Nzov skupiny nesmie obsahova iadny z nasledujcich znakov:%n%n%1 -NoProgramGroupCheck2=&Nevytvra skupinu v ponuke tart -WizardReady=Intalcia je pripraven -ReadyLabel1=Sprievodca intalciou je teraz pripraven naintalova produkt [name] na V pota. -ReadyLabel2a=Pokraujte v intalcii kliknutm na tlaidlo Intalova. Ak si prajete zmeni niektor nastavenia intalcie, kliknite na tlaidlo Sp. -ReadyLabel2b=Pokraujte v intalcii kliknutm na tlaidlo Intalova. -ReadyMemoUserInfo=Informcie o pouvateovi: -ReadyMemoDir=Cieov adresr: -ReadyMemoType=Typ intalcie: -ReadyMemoComponents=Vybran komponenty: -ReadyMemoGroup=Skupina v ponuke tart: -ReadyMemoTasks=alie lohy: -WizardPreparing=Prprava intalcie -PreparingDesc=Sprievodca intalciou pripravuje intalciu produktu [name] na V pota. -PreviousInstallNotCompleted=Intalcia/odintalcia predolho produktu nebola plne dokonen. Dokonenie tohto procesu vyaduje retart potaa.%n%nPo retartovan potaa spustite znovu sprievodcu intalciou, aby bolo mon dokoni intalciu produktu [name]. -CannotContinue=Sprievodca intalciou neme pokraova. Ukonite, prosm, sprievodcu intalciou kliknutm na tlaidlo Zrui. -ApplicationsFound=Nasledujce aplikcie pracuj so sbormi, ktor mus intaltor aktualizova. Odporame Vm, aby ste povolili intaltoru automaticky ukoni tieto aplikcie. -ApplicationsFound2=Nasledujce aplikcie pracuj so sbormi, ktor mus intaltor aktualizova. Odporame Vm, aby ste povolili intaltoru automaticky ukoni tieto aplikcie. Po skonen intalcie sa intaltor poksi tieto aplikcie optovne spusti. -CloseApplications=&Automaticky ukoni aplikcie -DontCloseApplications=&Neukonova aplikcie -ErrorCloseApplications=Sprievodca nemohol automaticky zatvori vetky aplikcie. Odporame Vm, aby ste rune uzavreli vetky aplikcie, ktor pouvaj sbory, ktor m Sprievodca aktualizova. -WizardInstalling=Intalujem -InstallingLabel=Pokajte prosm, km sprievodca intalciou nedokon intalciu produktu [name] na V pota. -FinishedHeadingLabel=Dokonuje sa intalcia produktu [name] -FinishedLabelNoIcons=Sprievodca intalciou dokonil intalciu produktu [name] na V pota. -FinishedLabel=Sprievodca intalciou dokonil intalciu produktu [name] na V pota. Produkt je mon spusti pomocou naintalovanch ikon a zstupcov. -ClickFinish=Ukonite sprievodcu intalciou kliknutm na tlaidlo Dokoni. -FinishedRestartLabel=Na dokonenie intalcie produktu [name] je nutn retartova V pota. Prajete si teraz retartova V pota? -FinishedRestartMessage=Na dokonenie intalcie produktu [name] je nutn retartova V pota.%n%nPrajete si teraz retartova V pota? -ShowReadmeCheck=no, chcem zobrazi dokument "ITAJMA" -YesRadio=&no, chcem teraz retartova pota -NoRadio=&Nie, pota retartujem neskr -RunEntryExec=Spusti %1 -RunEntryShellExec=Zobrazi %1 -ChangeDiskTitle=Sprievodca intalciou vyaduje al disk -SelectDiskLabel2=Vlote, prosm, disk %1 a kliknite na tlaidlo OK.%n%nAk sa sbory na tomto disku nachdzaj v inom adresri, ako v tom, ktor je zobrazen niie, zadejte sprvnu cestu alebo kliknite na tlaidlo Prechdza. -PathLabel=&Cesta: -FileNotInDir2=Sbor "%1" sa ned njs v "%2". Vlote, prosm, sprvny disk alebo zvote in adresr. -SelectDirectoryLabel=pecifikujte,prosm, umiestnenie alieho disku. -SetupAborted=Intalcia nebola plne dokonen.%n%nOpravte, prosm, chybu a spustite sprievodcu intalciou znova. -EntryAbortRetryIgnore=Akciu zopakujete kliknutm na tlaidlo Opakova. Akciu vynechte kliknutm na tlaidlo Preskoi. Intalciu prerute kliknutm na tlaidlo Prerui. -StatusClosingApplications=Ukonovanie aplikci... -StatusCreateDirs=Vytvraj sa adresre... -StatusExtractFiles=Rozbauj sa sbory... -StatusCreateIcons=Vytvraj sa ikony a zstupcovia... -StatusCreateIniEntries=Vytvraj sa zznamy v konfiguranch sboroch... -StatusCreateRegistryEntries=Vytvraj sa zznamy v systmovom registri... -StatusRegisterFiles=Registruj sa sbory... -StatusSavingUninstall=Ukladaj sa informcie potrebn pre neskorie odintalovanie produktu... -StatusRunProgram=Dokonuje sa intalcia... -StatusRestartingApplications=Retartovanie aplikci... -StatusRollback=Vykonan zmeny sa vracaj sp... -ErrorInternal2=Intern chyba: %1 -ErrorFunctionFailedNoCode=%1 zlyhala -ErrorFunctionFailed=%1 zlyhala; kd %2 -ErrorFunctionFailedWithMessage=%1 zlyhala; kd %2.%n%3 -ErrorExecutingProgram=Ned sa spusti sbor:%n%1 -ErrorRegOpenKey=Dolo k chybe pri otvran ka systmovho registra:%n%1\%2 -ErrorRegCreateKey=Dolo k chybe pri vytvran ka systmovho registra:%n%1\%2 -ErrorRegWriteKey=Dolo k chybe pri zpise do ka systmovho registra:%n%1\%2 -ErrorIniEntry=Dolo k chybe pri vytvran zznamu v konfiguranom sbore "%1". -FileAbortRetryIgnore=Akciu zopakujete kliknutm na tlaidlo Opakova. Tento sbor preskote kliknutm na tlaidlo Preskoi (neodpora sa). Intalciu prerute tlaidlom Prerui. -FileAbortRetryIgnore2=Akciu zopakujete kliknutm na tlaidlo Opakova. Pokraujete kliknutm na tlaidlo Preskoi (neodpora sa). Intalciu prerute tlaidlom Prerui. -SourceIsCorrupted=Zdrojov sbor je pokoden -SourceDoesntExist=Zdrojov sbor "%1" neexistuje -ExistingFileReadOnly=Existujci sbor je uren len na tanie.%n%nAtribt "Iba na tanie" odstrnite a akciu zopakujete kliknutm na tlaidlo Opakova. Sbor preskote kliknutm na tlaidlo Preskoi. Intalciu prerute kliknutm na tlaidlo Prerui. -ErrorReadingExistingDest=Dolo k chybe pri pokuse o tanie existujceho sboru: -FileExists=Sbor u existuje.%n%nM ho sprievodca intalcie prepsa? -ExistingFileNewer=Existujci sbor je nov ako ten, ktor sa sprievodca intalciou poka naintalova. Odpora sa ponecha existujci sbor.%n%nPrajete si ponechat existujci sbor? -ErrorChangingAttr=Dolo k chybe pri pokuse o modifikciu atribtov existujceho sboru: -ErrorCreatingTemp=Dolo k chybe pri pokuse o vytvorenie sboru v cieovom adresri: -ErrorReadingSource=Dolo k chybe pri pokuse o tanie zdrojovho sboru: -ErrorCopying=Dolo k chybe pri pokuse o skoprovanie sboru: -ErrorReplacingExistingFile=Dolo k chybe pri pokuse o nahradenie existujceho sboru: -ErrorRestartReplace=Zlyhala funkcia "RestartReplace" sprievodcu intalciou: -ErrorRenamingTemp=Dolo k chybe pri pokuse o premenovanie sboru v cieovom adresri: -ErrorRegisterServer=Ned sa vykona registrcia DLL/OCX: %1 -ErrorRegSvr32Failed=Volanie RegSvr32 zlyhalo s nvratovm kdom %1 -ErrorRegisterTypeLib=Ned sa vykona registrcia typovej kninice: %1 -ErrorOpeningReadme=Dolo k chybe pri pokuse o otvorenie dokumentu "ITAJMA". -ErrorRestartingComputer=Sprievodcovi intalciou sa nepodarilo retartova V pota. Retartujte ho, prosm, manulne. -UninstallNotFound=Sbor "%1" neexistuje. Produkt sa ned odintalova. -UninstallOpenError=Sbor "%1" nie je mon otvori. Produkt nie je mon odintalova. -UninstallUnsupportedVer=Sprievodcovi odintalciou sa nepodarilo rozpozna formt sboru obsahujceho informcie na odintalovanie produktu "%1". Produkt sa ned odintalova -UninstallUnknownEntry=V sbore obsahujcom informcie na odintalovanie produktu bola zisten neznma poloka (%1) -ConfirmUninstall=Ste si naozaj ist, e chcete odintalova %1 a vetky jeho komponenty? -UninstallOnlyOnWin64=Tento produkt je mon odintalova iba v 64-bitovch verzich MS Windows. -OnlyAdminCanUninstall=K odintalovaniu tohto produktu muste by prihlsen s prvami administrtora. -UninstallStatusLabel=Pokajte prosm, km produkt %1 nebude odintalovan z Vho potaa. -UninstalledAll=%1 bol spene odintalovan z Vho potaa. -UninstalledMost=%1 bol odintalovan z Vho potaa.%n%nNiektor jeho komponenty sa vak nepodarilo odintalova. Mete ich odintalova manulne. -UninstalledAndNeedsRestart=Na dokonenie odintalcie produktu %1 je potrebn retartova V pota.%n%nPrajete si teraz retartova V pota? -UninstallDataCorrupted=Sbor "%1" je pokoden. Produkt sa ned odintalova -ConfirmDeleteSharedFileTitle=Odintalova zdiean sbor? -ConfirmDeleteSharedFile2=Systm indikuje, e nsledujci zdiean sbor nie je pouvan iadnymi inmi aplikciami. M sprievodca odintalcie tento zdiean sbor odstrni?%n%nAk niektor aplikcie tento sbor pouvaj, nemusia po jeho odintalovan pracova sprvne. Ak si nie ste ist, zvote Nie. Ponechanie tohoto sboru vo Vaom systme nespsob iadnu kodu. -SharedFileNameLabel=Nzov sboru: -SharedFileLocationLabel=Umiestnenie: -WizardUninstalling=Stav odintalovania -StatusUninstalling=Odintalujem %1... -ShutdownBlockReasonInstallingApp=Intalovanie %1. -ShutdownBlockReasonUninstallingApp=Odintalovanie %1. - - -[CustomMessages] -NameAndVersion=%1 verzia %2 -AdditionalIcons=al zstupcovia: -CreateDesktopIcon=Vytvori zstupcu na &ploche -CreateQuickLaunchIcon=Vytvori zstupcu na paneli &Rchle spustenie -ProgramOnTheWeb=Aplikcia %1 na internete -UninstallProgram=Odintalova aplikciu %1 -LaunchProgram=Spusti aplikciu %1 -AssocFileExtension=Vytvori &asociciu medzi sbormi typu %2 a aplikciou %1 -AssocingFileExtension=Vytvra sa asocicia medzi sbormi typu %2 a aplikciou %1... -AutoStartProgramGroupDescription=Po spusten: -AutoStartProgram=Automaticky spusti %1 -AddonHostProgramNotFound=Nepodarilo sa njs %1 v prieinku, ktor ste zvolili.%n%nChcete napriek tomu pokraova? +; ****************************************************** +; *** *** +; *** Inno Setup version 5.5.3+ Slovak messages *** +; *** *** +; *** Original Author: *** +; *** *** +; *** Milan Potancok (milan.potancok AT gmail.com) *** +; *** *** +; *** Contributors: *** +; *** *** +; *** Ivo Bauer (bauer AT ozm.cz) *** +; *** *** +; *** Tomas Falb (tomasf AT pobox.sk) *** +; *** Slappy (slappy AT pobox.sk) *** +; *** *** +; *** Update: 04.02.2013 *** +; *** *** +; ****************************************************** +; +; + +[LangOptions] +LanguageName=Sloven<010D>ina +LanguageID=$041b +LanguageCodePage=1250 + +[Messages] +SetupAppTitle=Sprievodca intalciou +SetupWindowTitle=Sprievodca intalciou - %1 +UninstallAppTitle=Sprievodca odintalciou +UninstallAppFullTitle=Sprievodca odintalciou - %1 +InformationTitle=Informcie +ConfirmTitle=Potvrdenie +ErrorTitle=Chyba +SetupLdrStartupMessage=Toto je sprievodca intalciou produktu %1. Prajete si pokraova? +LdrCannotCreateTemp=Nie je mon vytvori doasn sbor. Sprievodca intalciou sa ukon +LdrCannotExecTemp=Nie je mon spusti sbor v doasnom adresri. Sprievodca intalciou sa ukon +LastErrorMessage=%1.%n%nChyba %2: %3 +SetupFileMissing=Intalan adresr neobsahuje sbor %1. Opravte, prosm, tto chybu alebo si zaobstarajte nov kpiu tohto produktu. +SetupFileCorrupt=Sbory sprievodcu intalciou s pokoden. Zaobstarajte si, prosm, nov kpiu tohto produktu. +SetupFileCorruptOrWrongVer=Sbory sprievodcu intalciou s pokoden alebo sa nezhoduj s touto verziou sprievodcu instalciou. Opravte, prosm, tto chybu alebo si zaobstarajte nov kpiu tohto produktu. +InvalidParameter=Nesprvny parameter na prkazovom riadku:%n%n%1 +SetupAlreadyRunning=Intalcia u be. +WindowsVersionNotSupported=Tento program nepodporuje vau verziu Windows. +WindowsServicePackRequired=Tento program vyaduje %1 Service Pack %2 alebo nov. +NotOnThisPlatform=Tento produkt sa ned spusti v %1. +OnlyOnThisPlatform=Tento produkt mus by spusten v %1. +OnlyOnTheseArchitectures=Tento produkt je mon naintalova iba vo verzich MS Windows s podporou architektry procesorov:%n%n%1 +MissingWOW64APIs=Aktulna verzia MS Windows neobsahuje funkcie, ktor vyaduje sprievodca intalciou pre 64-bitov intalciu. Opravte, prosm, tto chybu naintalovanm aktualizcie Service Pack %1. +WinVersionTooLowError=Tento produkt vyaduje %1 verzie %2 alebo vyej. +WinVersionTooHighError=Tento produkt sa ned naintalova vo %1 verzie %2 alebo vyej. +AdminPrivilegesRequired=Na intalciu tohto produktu muste by prihlsen s prvami administrtora. +PowerUserPrivilegesRequired=Na intalciu tohto produktu muste by prihlsen s prvami administrtora alebo lena skupiny Power Users. +SetupAppRunningError=Sprievodca intalciou zistil, e produkt %1 je teraz spusten.%n%nUkonite, prosm, vetky spusten intancie tohto produktu a pokraujte kliknutm na tlaidlo OK alebo ukonite intalciu tlaidlom Zrui. +UninstallAppRunningError=Sprievodca odintalciou zistil, e produkt %1 je teraz spusten.%n%nUkonite, prosm, vetky spusten intancie tohto produktu a pokraujte kliknutm na tlaidlo OK alebo ukonite intalciu tlaidlom Zrui. +ErrorCreatingDir=Sprievodca intalciou nemohol vytvori adresr "%1" +ErrorTooManyFilesInDir=Ned sa vytvori sbor v adresri "%1", pretoe tento adresr u obsahuje prli vea sborov +ExitSetupTitle=Ukoni sprievodcu intalciou +ExitSetupMessage=Intalcia nebola celkom dokonen. Ak teraz ukonte sprievodcu intalciou, produkt nebude naintalovan.%n%nSprievodcu intalciou mete znovu spusti neskr a dokoni tak intalciu.%n%nUkoni sprievodcu intalciou? +AboutSetupMenuItem=&O sprievodcovi intalcie... +AboutSetupTitle=O sprievodcovi intalcie +AboutSetupMessage=%1 verzia %2%n%3%n%n%1 domovsk strnka:%n%4 +AboutSetupNote= +TranslatorNote=Slovak translation maintained by Milan Potancok (milan.potancok AT gmail.com), Ivo Bauer (bauer AT ozm.cz) and Tomas Falb (tomasf AT pobox.sk) + Slappy (slappy AT pobox.sk) +ButtonBack=< &Sp +ButtonNext=&alej > +ButtonInstall=&Intalova +ButtonOK=OK +ButtonCancel=Zrui +ButtonYes=&no +ButtonYesToAll=no &vetkm +ButtonNo=&Nie +ButtonNoToAll=Ni&e vetkm +ButtonFinish=&Dokoni +ButtonBrowse=&Prechdza... +ButtonWizardBrowse=&Prechdza... +ButtonNewFolder=&Vytvori nov adresr +SelectLanguageTitle=Vber jazyka sprievodcu intalciou +SelectLanguageLabel=Zvote jazyk, ktor sa m poui pri intalcii: +ClickNext=Pokraujte kliknutm na tlaidlo alej alebo ukonite sprievodcu intalciou tlaidlom Zrui. +BeveledLabel= +BrowseDialogTitle=Njs adresr +BrowseDialogLabel=Z dole uvedenho zoznamu vyberte adresr a kliknite na OK. +NewFolderName=Nov adresr +WelcomeLabel1=Vt Vs sprievodca intalciou produktu [name]. +WelcomeLabel2=Produkt [name/ver] sa naintaluje na V pota.%n%nSkr, ako budete pokraova, odporame Vm ukoni vetky spusten aplikcie. +WizardPassword=Heslo +PasswordLabel1=Tto intalcia je chrnen heslom. +PasswordLabel3=Zadajte, prosm, heslo a pokraujte kliknutm na tlaidlo alej. Pri zadvn hesla rozliujte mal a vek psmen. +PasswordEditLabel=&Heslo: +IncorrectPassword=Zadan heslo nie je sprvne. Zkste to, prosm, ete raz. +WizardLicense=Licenn zmluva +LicenseLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. +LicenseLabel3=Pretajte si, prosm, tto Licenn zmluvu. Aby mohla intalcia pokraova, muste shlasi s podmienkami tejto zmluvy. +LicenseAccepted=&Shlasm s podmienkami Licennej zmluvy +LicenseNotAccepted=&Neshlasm s podmienkami Licennej zmluvy +WizardInfoBefore=Informcie +InfoBeforeLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. +InfoBeforeClickLabel=Pokraujte v intalcii kliknutm na tlaidlo alej. +WizardInfoAfter=Informcie +InfoAfterLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. +InfoAfterClickLabel=Pokraujte v intalcii kliknutm na tlaidlo alej. +WizardUserInfo=Informcie o pouvateovi +UserInfoDesc=Zadajte, prosm, poadovan informcie. +UserInfoName=&Pouvatesk meno: +UserInfoOrg=&Organizcia: +UserInfoSerial=&Sriove slo: +UserInfoNameRequired=Pouvatesk meno mus by zadan. +WizardSelectDir=Vyberte cieov adresr +SelectDirDesc=Kam m by produkt [name] naintalovan? +SelectDirLabel3=Sprievodca naintaluje produkt [name] do nasledujceho adresra. +SelectDirBrowseLabel=Pokraujte kliknutm na tlaidlo alej. Ak chcete vybra in adresr, kliknite na tlaidlo Prechdza. +DiskSpaceMBLabel=Intalcia vyaduje najmenej [mb] MB miesta na disku. +CannotInstallToNetworkDrive=Intaltor neme intalova na sieov jednotku. +CannotInstallToUNCPath=Intaltor neme intalova na UNC cestu. +InvalidPath=Muste zadat pln cestu vrtane psmena jednotky; naprklad:%n%nC:\Aplikcia%n%nalebo cestu UNC v tvare:%n%n\\server\zdiean adresr +InvalidDrive=Vami vybran jednotka alebo cesta UNC neexistuje alebo nie je dostupn. Vyberte, prosm, in umiestnenie. +DiskSpaceWarningTitle=Nedostatok miesta na disku +DiskSpaceWarning=Sprievodca intalciou vyaduje najmenej %1 KB vonho miesta na intalciu produktu, ale na vybranej jednotke je dostupnch len %2 KB.%n%nPrajete si napriek tomu pokraova? +DirNameTooLong=Nzov adresra alebo cesta s prli dlh. +InvalidDirName=Nzov adresra nie je platn. +BadDirName32=Nzvy adresrov nesm obsahova iadny z nasledujcich znakov:%n%n%1 +DirExistsTitle=Adresr existuje +DirExists=Adresr:%n%n%1%n%nu existuje. M sa napriek tomu intalova do tohto adresra? +DirDoesntExistTitle=Adresr neexistuje +DirDoesntExist=Adresr:%n%n%1%n%nete neexistuje. M sa tento adresr vytvori? +WizardSelectComponents=Vyberte komponenty +SelectComponentsDesc=Ak komponenty maj by naintalovan? +SelectComponentsLabel2=Zakrtnite komponenty, ktor maj by naintalovan; komponenty, ktor se nemaj intalova, nechajte nezakrtnut. Pokraujte kliknutm na tlaidlo alej. +FullInstallation=pln intalcia +CompactInstallation=Kompaktn intalcia +CustomInstallation=Voliten intalcia +NoUninstallWarningTitle=Komponenty existuj +NoUninstallWarning=Sprievodca intalciou zistil, e nasledujce komponenty s u na Vaom potai naintalovan:%n%n%1%n%nAk ich teraz nezahrniete do vberu, nebud neskr odintalovan.%n%nPrajete si napriek tomu pokraova? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel=Vybran komponenty vyaduj najmenej [mb] MB miesta na disku. +WizardSelectTasks=Vyberte alie lohy +SelectTasksDesc=Ktor alie lohy maj by vykonan? +SelectTasksLabel2=Vyberte alie lohy, ktor maj by vykonan v priebehu intalcie produktu [name] a pokraujte kliknutm na tlaidlo alej. +WizardSelectProgramGroup=Vyberte skupinu v ponuke tart +SelectStartMenuFolderDesc=Kam m sprievodca intalcie umiestni zstupcov aplikcie? +SelectStartMenuFolderLabel3=Sprievodca intalciou vytvor zstupcov aplikcie v nasledujcom adresri ponuky tart. +SelectStartMenuFolderBrowseLabel=Pokraujte kliknutm na tlaidlo alej. Ak chcete zvoli in adresr, kliknite na tlaidlo Prechdza. +MustEnterGroupName=Muste zada nzov skupiny. +GroupNameTooLong=Nzov adresra alebo cesta s prli dlh. +InvalidGroupName=Nzov adresra nie je platn. +BadGroupName=Nzov skupiny nesmie obsahova iadny z nasledujcich znakov:%n%n%1 +NoProgramGroupCheck2=&Nevytvra skupinu v ponuke tart +WizardReady=Intalcia je pripraven +ReadyLabel1=Sprievodca intalciou je teraz pripraven naintalova produkt [name] na V pota. +ReadyLabel2a=Pokraujte v intalcii kliknutm na tlaidlo Intalova. Ak si prajete zmeni niektor nastavenia intalcie, kliknite na tlaidlo Sp. +ReadyLabel2b=Pokraujte v intalcii kliknutm na tlaidlo Intalova. +ReadyMemoUserInfo=Informcie o pouvateovi: +ReadyMemoDir=Cieov adresr: +ReadyMemoType=Typ intalcie: +ReadyMemoComponents=Vybran komponenty: +ReadyMemoGroup=Skupina v ponuke tart: +ReadyMemoTasks=alie lohy: +WizardPreparing=Prprava intalcie +PreparingDesc=Sprievodca intalciou pripravuje intalciu produktu [name] na V pota. +PreviousInstallNotCompleted=Intalcia/odintalcia predolho produktu nebola plne dokonen. Dokonenie tohto procesu vyaduje retart potaa.%n%nPo retartovan potaa spustite znovu sprievodcu intalciou, aby bolo mon dokoni intalciu produktu [name]. +CannotContinue=Sprievodca intalciou neme pokraova. Ukonite, prosm, sprievodcu intalciou kliknutm na tlaidlo Zrui. +ApplicationsFound=Nasledujce aplikcie pracuj so sbormi, ktor mus intaltor aktualizova. Odporame Vm, aby ste povolili intaltoru automaticky ukoni tieto aplikcie. +ApplicationsFound2=Nasledujce aplikcie pracuj so sbormi, ktor mus intaltor aktualizova. Odporame Vm, aby ste povolili intaltoru automaticky ukoni tieto aplikcie. Po skonen intalcie sa intaltor poksi tieto aplikcie optovne spusti. +CloseApplications=&Automaticky ukoni aplikcie +DontCloseApplications=&Neukonova aplikcie +ErrorCloseApplications=Sprievodca nemohol automaticky zatvori vetky aplikcie. Odporame Vm, aby ste rune uzavreli vetky aplikcie, ktor pouvaj sbory, ktor m Sprievodca aktualizova. +WizardInstalling=Intalujem +InstallingLabel=Pokajte prosm, km sprievodca intalciou nedokon intalciu produktu [name] na V pota. +FinishedHeadingLabel=Dokonuje sa intalcia produktu [name] +FinishedLabelNoIcons=Sprievodca intalciou dokonil intalciu produktu [name] na V pota. +FinishedLabel=Sprievodca intalciou dokonil intalciu produktu [name] na V pota. Produkt je mon spusti pomocou naintalovanch ikon a zstupcov. +ClickFinish=Ukonite sprievodcu intalciou kliknutm na tlaidlo Dokoni. +FinishedRestartLabel=Na dokonenie intalcie produktu [name] je nutn retartova V pota. Prajete si teraz retartova V pota? +FinishedRestartMessage=Na dokonenie intalcie produktu [name] je nutn retartova V pota.%n%nPrajete si teraz retartova V pota? +ShowReadmeCheck=no, chcem zobrazi dokument "ITAJMA" +YesRadio=&no, chcem teraz retartova pota +NoRadio=&Nie, pota retartujem neskr +RunEntryExec=Spusti %1 +RunEntryShellExec=Zobrazi %1 +ChangeDiskTitle=Sprievodca intalciou vyaduje al disk +SelectDiskLabel2=Vlote, prosm, disk %1 a kliknite na tlaidlo OK.%n%nAk sa sbory na tomto disku nachdzaj v inom adresri, ako v tom, ktor je zobrazen niie, zadejte sprvnu cestu alebo kliknite na tlaidlo Prechdza. +PathLabel=&Cesta: +FileNotInDir2=Sbor "%1" sa ned njs v "%2". Vlote, prosm, sprvny disk alebo zvote in adresr. +SelectDirectoryLabel=pecifikujte,prosm, umiestnenie alieho disku. +SetupAborted=Intalcia nebola plne dokonen.%n%nOpravte, prosm, chybu a spustite sprievodcu intalciou znova. +EntryAbortRetryIgnore=Akciu zopakujete kliknutm na tlaidlo Opakova. Akciu vynechte kliknutm na tlaidlo Preskoi. Intalciu prerute kliknutm na tlaidlo Prerui. +StatusClosingApplications=Ukonovanie aplikci... +StatusCreateDirs=Vytvraj sa adresre... +StatusExtractFiles=Rozbauj sa sbory... +StatusCreateIcons=Vytvraj sa ikony a zstupcovia... +StatusCreateIniEntries=Vytvraj sa zznamy v konfiguranch sboroch... +StatusCreateRegistryEntries=Vytvraj sa zznamy v systmovom registri... +StatusRegisterFiles=Registruj sa sbory... +StatusSavingUninstall=Ukladaj sa informcie potrebn pre neskorie odintalovanie produktu... +StatusRunProgram=Dokonuje sa intalcia... +StatusRestartingApplications=Retartovanie aplikci... +StatusRollback=Vykonan zmeny sa vracaj sp... +ErrorInternal2=Intern chyba: %1 +ErrorFunctionFailedNoCode=%1 zlyhala +ErrorFunctionFailed=%1 zlyhala; kd %2 +ErrorFunctionFailedWithMessage=%1 zlyhala; kd %2.%n%3 +ErrorExecutingProgram=Ned sa spusti sbor:%n%1 +ErrorRegOpenKey=Dolo k chybe pri otvran ka systmovho registra:%n%1\%2 +ErrorRegCreateKey=Dolo k chybe pri vytvran ka systmovho registra:%n%1\%2 +ErrorRegWriteKey=Dolo k chybe pri zpise do ka systmovho registra:%n%1\%2 +ErrorIniEntry=Dolo k chybe pri vytvran zznamu v konfiguranom sbore "%1". +FileAbortRetryIgnore=Akciu zopakujete kliknutm na tlaidlo Opakova. Tento sbor preskote kliknutm na tlaidlo Preskoi (neodpora sa). Intalciu prerute tlaidlom Prerui. +FileAbortRetryIgnore2=Akciu zopakujete kliknutm na tlaidlo Opakova. Pokraujete kliknutm na tlaidlo Preskoi (neodpora sa). Intalciu prerute tlaidlom Prerui. +SourceIsCorrupted=Zdrojov sbor je pokoden +SourceDoesntExist=Zdrojov sbor "%1" neexistuje +ExistingFileReadOnly=Existujci sbor je uren len na tanie.%n%nAtribt "Iba na tanie" odstrnite a akciu zopakujete kliknutm na tlaidlo Opakova. Sbor preskote kliknutm na tlaidlo Preskoi. Intalciu prerute kliknutm na tlaidlo Prerui. +ErrorReadingExistingDest=Dolo k chybe pri pokuse o tanie existujceho sboru: +FileExists=Sbor u existuje.%n%nM ho sprievodca intalcie prepsa? +ExistingFileNewer=Existujci sbor je nov ako ten, ktor sa sprievodca intalciou poka naintalova. Odpora sa ponecha existujci sbor.%n%nPrajete si ponechat existujci sbor? +ErrorChangingAttr=Dolo k chybe pri pokuse o modifikciu atribtov existujceho sboru: +ErrorCreatingTemp=Dolo k chybe pri pokuse o vytvorenie sboru v cieovom adresri: +ErrorReadingSource=Dolo k chybe pri pokuse o tanie zdrojovho sboru: +ErrorCopying=Dolo k chybe pri pokuse o skoprovanie sboru: +ErrorReplacingExistingFile=Dolo k chybe pri pokuse o nahradenie existujceho sboru: +ErrorRestartReplace=Zlyhala funkcia "RestartReplace" sprievodcu intalciou: +ErrorRenamingTemp=Dolo k chybe pri pokuse o premenovanie sboru v cieovom adresri: +ErrorRegisterServer=Ned sa vykona registrcia DLL/OCX: %1 +ErrorRegSvr32Failed=Volanie RegSvr32 zlyhalo s nvratovm kdom %1 +ErrorRegisterTypeLib=Ned sa vykona registrcia typovej kninice: %1 +ErrorOpeningReadme=Dolo k chybe pri pokuse o otvorenie dokumentu "ITAJMA". +ErrorRestartingComputer=Sprievodcovi intalciou sa nepodarilo retartova V pota. Retartujte ho, prosm, manulne. +UninstallNotFound=Sbor "%1" neexistuje. Produkt sa ned odintalova. +UninstallOpenError=Sbor "%1" nie je mon otvori. Produkt nie je mon odintalova. +UninstallUnsupportedVer=Sprievodcovi odintalciou sa nepodarilo rozpozna formt sboru obsahujceho informcie na odintalovanie produktu "%1". Produkt sa ned odintalova +UninstallUnknownEntry=V sbore obsahujcom informcie na odintalovanie produktu bola zisten neznma poloka (%1) +ConfirmUninstall=Ste si naozaj ist, e chcete odintalova %1 a vetky jeho komponenty? +UninstallOnlyOnWin64=Tento produkt je mon odintalova iba v 64-bitovch verzich MS Windows. +OnlyAdminCanUninstall=K odintalovaniu tohto produktu muste by prihlsen s prvami administrtora. +UninstallStatusLabel=Pokajte prosm, km produkt %1 nebude odintalovan z Vho potaa. +UninstalledAll=%1 bol spene odintalovan z Vho potaa. +UninstalledMost=%1 bol odintalovan z Vho potaa.%n%nNiektor jeho komponenty sa vak nepodarilo odintalova. Mete ich odintalova manulne. +UninstalledAndNeedsRestart=Na dokonenie odintalcie produktu %1 je potrebn retartova V pota.%n%nPrajete si teraz retartova V pota? +UninstallDataCorrupted=Sbor "%1" je pokoden. Produkt sa ned odintalova +ConfirmDeleteSharedFileTitle=Odintalova zdiean sbor? +ConfirmDeleteSharedFile2=Systm indikuje, e nsledujci zdiean sbor nie je pouvan iadnymi inmi aplikciami. M sprievodca odintalcie tento zdiean sbor odstrni?%n%nAk niektor aplikcie tento sbor pouvaj, nemusia po jeho odintalovan pracova sprvne. Ak si nie ste ist, zvote Nie. Ponechanie tohoto sboru vo Vaom systme nespsob iadnu kodu. +SharedFileNameLabel=Nzov sboru: +SharedFileLocationLabel=Umiestnenie: +WizardUninstalling=Stav odintalovania +StatusUninstalling=Odintalujem %1... +ShutdownBlockReasonInstallingApp=Intalovanie %1. +ShutdownBlockReasonUninstallingApp=Odintalovanie %1. + + +[CustomMessages] +NameAndVersion=%1 verzia %2 +AdditionalIcons=al zstupcovia: +CreateDesktopIcon=Vytvori zstupcu na &ploche +CreateQuickLaunchIcon=Vytvori zstupcu na paneli &Rchle spustenie +ProgramOnTheWeb=Aplikcia %1 na internete +UninstallProgram=Odintalova aplikciu %1 +LaunchProgram=Spusti aplikciu %1 +AssocFileExtension=Vytvori &asociciu medzi sbormi typu %2 a aplikciou %1 +AssocingFileExtension=Vytvra sa asocicia medzi sbormi typu %2 a aplikciou %1... +AutoStartProgramGroupDescription=Po spusten: +AutoStartProgram=Automaticky spusti %1 +AddonHostProgramNotFound=Nepodarilo sa njs %1 v prieinku, ktor ste zvolili.%n%nChcete napriek tomu pokraova? diff --git a/distrib/custom_messages.iss b/distrib/custom_messages.iss index d2f44a49317..f51c10e1cd9 100644 --- a/distrib/custom_messages.iss +++ b/distrib/custom_messages.iss @@ -1,55 +1,55 @@ -; (C) 2009-2017 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 . - - -; Do NOT translate your language's name -; Do NOT translate [name]/[ver] -; Do NOT change the langid -; Do NOT change the file encoding; it must be UTF-8 Signature -; Keep the translations close to the English strings -; comp=component, msg=Message, tsk=Task - - -[Messages] -; English -WelcomeLabel1=[name/ver] -en.WelcomeLabel2=This will install [name] on your computer.%n%nIt is recommended that you close all other applications before continuing. -en.WinVersionTooLowError=[name] requires Windows 7 or newer to run. - - -[CustomMessages] -; English -en.langid=00000000 -en.comp_mpciconlib=Icon Library -en.comp_mpcresources=Translations -en.msg_DeleteSettings=Do you also want to delete MPC-HC settings?%n%nIf you plan on installing MPC-HC again then you do not have to delete them. -#if defined(sse2_required) -en.msg_simd_sse2=This build of MPC-HC requires a CPU with SSE2 extension support.%n%nYour CPU does not have those capabilities. -#endif -en.run_DownloadToolbarImages=Visit our Wiki page to download toolbar images -en.tsk_AllUsers=For all users -en.tsk_CurrentUser=For the current user only -en.tsk_Other=Other tasks: -en.tsk_ResetSettings=Reset settings -en.types_DefaultInstallation=Default installation -en.types_CustomInstallation=Custom installation -en.ViewChangelog=View Changelog - - -#if localize == "true" - #include "custom_messages_translated.iss" -#endif +; (C) 2009-2017 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 . + + +; Do NOT translate your language's name +; Do NOT translate [name]/[ver] +; Do NOT change the langid +; Do NOT change the file encoding; it must be UTF-8 Signature +; Keep the translations close to the English strings +; comp=component, msg=Message, tsk=Task + + +[Messages] +; English +WelcomeLabel1=[name/ver] +en.WelcomeLabel2=This will install [name] on your computer.%n%nIt is recommended that you close all other applications before continuing. +en.WinVersionTooLowError=[name] requires Windows 7 or newer to run. + + +[CustomMessages] +; English +en.langid=00000000 +en.comp_mpciconlib=Icon Library +en.comp_mpcresources=Translations +en.msg_DeleteSettings=Do you also want to delete MPC-HC settings?%n%nIf you plan on installing MPC-HC again then you do not have to delete them. +#if defined(sse2_required) +en.msg_simd_sse2=This build of MPC-HC requires a CPU with SSE2 extension support.%n%nYour CPU does not have those capabilities. +#endif +en.run_DownloadToolbarImages=Visit our Wiki page to download toolbar images +en.tsk_AllUsers=For all users +en.tsk_CurrentUser=For the current user only +en.tsk_Other=Other tasks: +en.tsk_ResetSettings=Reset settings +en.types_DefaultInstallation=Default installation +en.types_CustomInstallation=Custom installation +en.ViewChangelog=View Changelog + + +#if localize == "true" + #include "custom_messages_translated.iss" +#endif diff --git a/distrib/mpc-hc_setup.iss b/distrib/mpc-hc_setup.iss index 88247b37769..8094f65b93f 100644 --- a/distrib/mpc-hc_setup.iss +++ b/distrib/mpc-hc_setup.iss @@ -1,567 +1,567 @@ -; (C) 2009-2018 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 . - - -; Requirements: -; Inno Setup Unicode: http://www.jrsoftware.org/isdl.php - - -#if VER < EncodeVer(6,3,2) - #error Update your Inno Setup version (6.3.2 or newer) -#endif - -#ifndef UNICODE - #error Use the Unicode Inno Setup -#endif - -; If you want to compile the 64-bit version define "x64build" (uncomment the define below or use build.bat) -;#define x64Build -;#define MPCHC_LITE - -; Include translations by default. You can bypass this by defining localize=whatever or false etc in build.bat or here -#if !defined(localize) - #if defined(MPCHC_LITE) - #define localize = "false" - #else - #define localize = "true" - #endif -#endif -#define sse2_required - -#if GetEnv('MPC_DRDUMP') == '1' -#define USE_DRDUMP_CRASH_REPORTER 1 -#endif - -; From now on you shouldn't need to change anything - -#include "..\include\mpc-hc_config.h" -#include "..\include\version.h" - -#define copyright_str str(MPC_COPYRIGHT_STR) -#define app_name "MPC-HC" - -#if MPC_NIGHTLY_RELEASE - #define app_ver str(MPC_VERSION_MAJOR) + "." + str(MPC_VERSION_MINOR) + "." + str(MPC_VERSION_PATCH) + "." + str(MPC_VERSION_REV) -#else - #define app_ver str(MPC_VERSION_MAJOR) + "." + str(MPC_VERSION_MINOR) + "." + str(MPC_VERSION_PATCH) -#endif - -#define app_vername = app_name + " " + app_ver -#define quick_launch "{userappdata}\Microsoft\Internet Explorer\Quick Launch" - -#define base_bindir = "..\bin" - -#ifdef x64Build - #define bindir = AddBackslash(base_bindir) + "mpc-hc_x64" - #define mpchc_exe = "mpc-hc64.exe" - #define mpchc_ini = "mpc-hc64.ini" - #define lavfiltersdir = "LAVFilters64" - #define OutFilename = app_name + "." + app_ver + ".x64" - #define platform = "x64" - #define mpcvr_ax = "MpcVideoRenderer64.ax" - #define mediainfo_dll = "..\distrib\x64\MediaInfo.dll" -#else - #define bindir = AddBackslash(base_bindir) + "mpc-hc_x86" - #define mpchc_exe = "mpc-hc.exe" - #define mpchc_ini = "mpc-hc.ini" - #define lavfiltersdir = "LAVFilters" - #define OutFilename = app_name + "." + app_ver + ".x86" - #define platform = "x86" - #define mpcvr_ax = "MpcVideoRenderer.ax" - #define mediainfo_dll = "..\distrib\x86\MediaInfo.dll" -#endif - -#if defined(MPCHC_LITE) - #define bindir = bindir + " Lite" -#endif - -#ifnexist AddBackslash(bindir) + mpchc_exe - #error Compile MPC-HC first -#endif - -#if localize != "true" - #if defined(MPCHC_LITE) - #define OutFilename = OutFilename + ".Lite" - #else - #define OutFilename = OutFilename + ".en" - #endif -#endif - -#if MPC_NIGHTLY_RELEASE - #define FullAppNameVer = app_vername + " " + "(" + str(MPCHC_HASH) + ")" -#else - #define FullAppNameVer = app_vername -#endif - -#if MPC_NIGHTLY_RELEASE - #define FullAppNameVer = FullAppNameVer + " " + str(MPC_VERSION_NIGHTLY) -#endif -#ifdef MPCHC_LITE - #define FullAppNameVer = FullAppNameVer + " " + "Lite" -#endif -#ifdef x64Build - #define FullAppNameVer = FullAppNameVer + " " + "(64-bit)" -#endif - -#ifexist "..\distrib\mpcvr\MpcVideoRenderer.ax" -#define INCLUDE_MPCVR = true -#else -#define INCLUDE_MPCVR = false -#bla -#endif - -#ifexist mediainfo_dll - #if !defined(MPCHC_LITE) -#define INCLUDE_MEDIAINFO = true - #else -#define INCLUDE_MEDIAINFO = false - #endif -#else -#define INCLUDE_MEDIAINFO = false -#endif - - -[Setup] -#ifdef x64Build -AppId = {{2ACBF1FA-F5C3-4B19-A774-B22A31F231B9} -DefaultGroupName = {#app_name} x64 -ArchitecturesAllowed = x64compatible -ArchitecturesInstallIn64BitMode = x64compatible -#else -AppId = {{2624B969-7135-4EB1-B0F6-2D8C397B45F7} -DefaultGroupName = {#app_name} -#endif - -AppName = {#app_name} -AppVersion = {#app_ver} -AppVerName = {#app_vername} -AppPublisher = MPC-HC Team -AppPublisherURL = {#WEBSITE_URL} -AppCopyright = {#copyright_str} -VersionInfoVersion = {#app_ver} -UninstallDisplayIcon = {app}\{#mpchc_exe} -UninstallDisplayName = {#FullAppNameVer} -OutputBaseFilename = {#OutFilename} -DefaultDirName = {code:GetInstallFolder} -LicenseFile = ..\COPYING.txt -OutputDir = . -SetupIconFile = ..\src\mpc-hc\res\icon.ico -WizardImageFile = WizardImageFile.bmp -WizardSmallImageFile = WizardSmallImageFile.bmp -Compression = lzma2/ultra -InternalCompressLevel = ultra -SolidCompression = yes -AllowNoIcons = yes -ShowTasksTreeLines = yes -DisableDirPage = auto -DisableProgramGroupPage = auto -MinVersion = 6.1 -CloseApplications = true -#ifexist "..\signinfo.txt" -SignTool = MySignTool -#endif -SetupMutex = 'mpchc_setup_mutex' - -[Languages] -Name: en; MessagesFile: compiler:Default.isl - -#if localize == "true" -Name: ar; MessagesFile: Languages\Arabic.isl -Name: be; MessagesFile: Languages\Belarusian.isl -Name: bn; MessagesFile: Languages\Bengali.islu -Name: bs_BA; MessagesFile: Languages\Bosnian.isl -Name: ca; MessagesFile: compiler:Languages\Catalan.isl -Name: cs; MessagesFile: compiler:Languages\Czech.isl -Name: da; MessagesFile: compiler:Languages\Danish.isl -Name: de; MessagesFile: compiler:Languages\German.isl -Name: en_GB; MessagesFile: Languages\EnglishBritish.isl -Name: es; MessagesFile: compiler:Languages\Spanish.isl -Name: eu; MessagesFile: Languages\Basque.isl -Name: fi; MessagesFile: compiler:Languages\Finnish.isl -Name: fr; MessagesFile: compiler:Languages\French.isl -Name: gl; MessagesFile: Languages\Galician.isl -Name: he; MessagesFile: compiler:Languages\Hebrew.isl -Name: hr; MessagesFile: Languages\Croatian.isl -Name: hu; MessagesFile: compiler:Languages\Hungarian.isl -Name: hy; MessagesFile: compiler:Languages\Armenian.isl -Name: id; MessagesFile: Languages\Indonesian.isl -Name: it; MessagesFile: compiler:Languages\Italian.isl -Name: ja; MessagesFile: compiler:Languages\Japanese.isl -Name: ko; MessagesFile: Languages\Korean.isl -Name: lt; MessagesFile: Languages\Lithuanian.isl -Name: ms_MY; MessagesFile: Languages\Malaysian.isl -Name: nl; MessagesFile: compiler:Languages\Dutch.isl -Name: pl; MessagesFile: compiler:Languages\Polish.isl -Name: pt_BR; MessagesFile: compiler:Languages\BrazilianPortuguese.isl -Name: pt_PT; MessagesFile: compiler:Languages\Portuguese.isl -Name: ro; MessagesFile: Languages\Romanian.isl -Name: ru; MessagesFile: compiler:Languages\Russian.isl -Name: sk; MessagesFile: Languages\Slovak.isl -Name: sl; MessagesFile: compiler:Languages\Slovenian.isl -Name: sv; MessagesFile: Languages\Swedish.isl -Name: th_TH; MessagesFile: Languages\Thai.isl -Name: tt; MessagesFile: Languages\Tatar.isl -Name: tr; MessagesFile: compiler:Languages\Turkish.isl -Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl -Name: vi; MessagesFile: Languages\Vietnamese.isl -Name: zh_CN; MessagesFile: Languages\ChineseSimplified.isl -Name: zh_TW; MessagesFile: Languages\ChineseTraditional.isl -#endif - -; Include installer's custom messages -#include "custom_messages.iss" - - -[Types] -Name: default; Description: {cm:types_DefaultInstallation} -Name: custom; Description: {cm:types_CustomInstallation}; Flags: iscustom - - -[Components] -Name: main; Description: {#app_vername}; Types: default custom; Flags: fixed -#if INCLUDE_MPCVR -Name: mpcvr; Description: MPC Video Renderer; Types: default custom -#endif -Name: mpciconlib; Description: {cm:comp_mpciconlib}; Types: default custom -#if localize == "true" -Name: mpcresources; Description: {cm:comp_mpcresources}; Types: default custom; Flags: disablenouninstallwarning -#endif - - -[Tasks] -Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons} -Name: desktopicon\user; Description: {cm:tsk_CurrentUser}; GroupDescription: {cm:AdditionalIcons}; Flags: exclusive -Name: desktopicon\common; Description: {cm:tsk_AllUsers}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked exclusive -Name: quicklaunchicon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked; OnlyBelowVersion: 6.01 -Name: reset_settings; Description: {cm:tsk_ResetSettings}; GroupDescription: {cm:tsk_Other}; Flags: checkedonce unchecked; Check: SettingsExist() - - -[Files] -Source: {#bindir}\{#mpchc_exe}; DestDir: {app}; Components: main; Flags: ignoreversion - #if localize == "true" -Source: {#bindir}\Lang\mpcresources.??.dll; DestDir: {app}\Lang; Components: mpcresources; Flags: ignoreversion -Source: {#bindir}\Lang\mpcresources.??_??.dll; DestDir: {app}\Lang; Components: mpcresources; Flags: ignoreversion - #endif -Source: {#bindir}\mpciconlib.dll; DestDir: {app}; Components: mpciconlib; Flags: ignoreversion - #ifndef MPCHC_LITE -Source: {#bindir}\{#lavfiltersdir}\*.dll; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion -Source: {#bindir}\{#lavfiltersdir}\*.ax; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion -Source: {#bindir}\{#lavfiltersdir}\*.manifest; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion - #endif -Source: {#platform}\d3dcompiler_{#MPC_D3D_COMPILER_VERSION}.dll; DestDir: {app}; Components: main; Flags: ignoreversion -Source: {#platform}\d3dx9_{#MPC_DX_SDK_NUMBER}.dll; DestDir: {app}; Components: main; Flags: ignoreversion - #if INCLUDE_MEDIAINFO -Source: {#platform}\mediainfo.dll; DestDir: {app}; Components: main; Flags: ignoreversion - #endif -Source: ..\src\mpc-hc\res\shaders\dx9\*.hlsl; DestDir: {app}\Shaders; Components: main; Flags: onlyifdoesntexist -Source: ..\src\mpc-hc\res\shaders\dx11\*.hlsl; DestDir: {app}\Shaders11; Components: main; Flags: onlyifdoesntexist -Source: ..\COPYING.txt; DestDir: {app}; Components: main; Flags: ignoreversion -Source: ..\docs\Authors.txt; DestDir: {app}; Components: main; Flags: ignoreversion - #if USE_DRDUMP_CRASH_REPORTER -Source: {#platform}\crashrpt.dll; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion -Source: {#platform}\dbghelp.dll; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion -Source: {#platform}\sendrpt.exe; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion -Source: CrashReporter_LICENSE.txt; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion - #endif - #if INCLUDE_MPCVR -Source: ..\distrib\mpcvr\{#mpcvr_ax}; DestDir: {app}\MPCVR; Components: mpcvr; Flags: ignoreversion - #endif - - -[Icons] -#ifdef x64Build -Name: {group}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0 -Name: {commondesktop}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\common -Name: {userdesktop}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\user -Name: {#quick_launch}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: quicklaunchicon -#else -Name: {group}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0 -Name: {commondesktop}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\common -Name: {userdesktop}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\user -Name: {#quick_launch}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: quicklaunchicon -#endif -Name: {group}\{cm:UninstallProgram,{#app_name}}; Filename: {uninstallexe}; Comment: {cm:UninstallProgram,{#app_name}}; WorkingDir: {app} - - -[Run] -Filename: {app}\{#mpchc_exe}; Description: {cm:LaunchProgram,{#app_name}}; WorkingDir: {app}; Flags: nowait postinstall skipifsilent unchecked - - -[InstallDelete] -Type: files; Name: {userdesktop}\{#app_name}.lnk; Check: not IsTaskSelected('desktopicon\user') and IsUpgrade() -Type: files; Name: {commondesktop}\{#app_name}.lnk; Check: not IsTaskSelected('desktopicon\common') and IsUpgrade() -Type: files; Name: {#quick_launch}\{#app_name}.lnk; Check: not IsTaskSelected('quicklaunchicon') and IsUpgrade(); OnlyBelowVersion: 6.01 -Type: files; Name: {app}\AUTHORS; Check: IsUpgrade() -Type: files; Name: {app}\COPYING; Check: IsUpgrade() - #if !USE_DRDUMP_CRASH_REPORTER -Type: filesandordirs; Name: {app}\CrashReporter; Check: IsUpgrade() - #endif - -; old shortcuts -#ifdef x64Build -Type: files; Name: {group}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() -Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() -Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() -Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() -#else -Type: files; Name: {group}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() -Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() -Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() -Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() -#endif -Type: files; Name: {group}\{cm:ProgramOnTheWeb,Media Player Classic - Home Cinema}.url; Check: IsUpgrade() -Type: files; Name: {group}\{cm:UninstallProgram,Media Player Classic - Home Cinema}.lnk; Check: IsUpgrade() - -Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('desktopicon\user') and IsUpgrade() -Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('desktopicon\common') and IsUpgrade() -Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('quicklaunchicon') and IsUpgrade(); OnlyBelowVersion: 6.01 - -; Old ffmpeg dlls from LAV Filters -Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-60.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-59.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-58.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-57.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-9.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-8.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-7.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-60.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-59.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-58.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-57.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-58.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-57.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-56.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-55.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swresample-lav-4.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-7.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-6.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-5.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-4.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avresample-lav-4.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avresample-lav-3.dll; Check: IsUpgrade() - -#ifdef x64Build -; Super old LAV files -Type: files; Name: {app}\LAVFilters\avcodec-lav-??.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\avfilter-lav-?.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\avformat-lav-??.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\avresample-lav-?.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\avutil-lav-??.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\IntelQuickSyncDecoder.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\LAVAudio.ax; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\LAVFilters.Dependencies.manifest; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\LAVSplitter.ax; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\LAVVideo.ax; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\libbluray.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\swscale-lav-?.dll; Check: IsUpgrade() -Type: dirifempty; Name: {app}\LAVFilters\; Check: IsUpgrade() -#endif - - -#if localize == "true" -; remove the old language dlls when upgrading -Type: files; Name: {app}\mpcresources.br.dll -Type: files; Name: {app}\mpcresources.by.dll -Type: files; Name: {app}\mpcresources.ca.dll -Type: files; Name: {app}\mpcresources.cz.dll -Type: files; Name: {app}\mpcresources.de.dll -Type: files; Name: {app}\mpcresources.es.dll -Type: files; Name: {app}\mpcresources.fr.dll -Type: files; Name: {app}\mpcresources.he.dll -Type: files; Name: {app}\mpcresources.hu.dll -Type: files; Name: {app}\mpcresources.hy.dll -Type: files; Name: {app}\mpcresources.it.dll -Type: files; Name: {app}\mpcresources.ja.dll -Type: files; Name: {app}\mpcresources.kr.dll -Type: files; Name: {app}\mpcresources.nl.dll -Type: files; Name: {app}\mpcresources.pl.dll -Type: files; Name: {app}\mpcresources.ru.dll -Type: files; Name: {app}\mpcresources.sc.dll -Type: files; Name: {app}\mpcresources.sk.dll -Type: files; Name: {app}\mpcresources.sv.dll -Type: files; Name: {app}\mpcresources.tc.dll -Type: files; Name: {app}\mpcresources.tr.dll -Type: files; Name: {app}\mpcresources.ua.dll -Type: files; Name: {app}\Lang\mpcresources.br.dll -Type: files; Name: {app}\Lang\mpcresources.by.dll -Type: files; Name: {app}\Lang\mpcresources.cz.dll -Type: files; Name: {app}\Lang\mpcresources.en-GB.dll -Type: files; Name: {app}\Lang\mpcresources.kr.dll -Type: files; Name: {app}\Lang\mpcresources.sc.dll -Type: files; Name: {app}\Lang\mpcresources.tc.dll -Type: files; Name: {app}\Lang\mpcresources.ua.dll -#endif - - -[Code] -#if defined(sse2_required) -function IsProcessorFeaturePresent(Feature: Integer): Boolean; -external 'IsProcessorFeaturePresent@kernel32.dll stdcall'; -#endif - - -function GetInstallFolder(Default: String): String; -var - sInstallPath: String; -begin - if not RegQueryStringValue(HKCU, 'SOFTWARE\Gabest\Media Player Classic', 'ExePath', sInstallPath) - or not RegQueryStringValue(HKCU, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath', sInstallPath) then begin - Result := ExpandConstant('{pf}\MPC-HC'); - end - else begin - RegQueryStringValue(HKCU, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath', sInstallPath); - Result := ExtractFileDir(sInstallPath); - if (Result = '') or not DirExists(Result) then begin - Result := ExpandConstant('{pf}\MPC-HC'); - end; - end; -end; - - -#if defined(sse2_required) - -function Is_SSE2_Supported(): Boolean; -begin - // PF_XMMI64_INSTRUCTIONS_AVAILABLE - Result := IsProcessorFeaturePresent(10); -end; - -#endif - - -function IsUpgrade(): Boolean; -var - sPrevPath: String; -begin - sPrevPath := WizardForm.PrevAppDir; - Result := (sPrevPath <> ''); -end; - - -// Check if MPC-HC's settings exist -function SettingsExist(): Boolean; -begin - if RegKeyExists(HKEY_CURRENT_USER, 'Software\Gabest\Media Player Classic') or - RegKeyExists(HKEY_CURRENT_USER, 'Software\MPC-HC\MPC-HC') or - FileExists(ExpandConstant('{app}\{#mpchc_ini}')) then - Result := True - else - Result := False; -end; - - -function ShouldSkipPage(PageID: Integer): Boolean; -begin - // Hide the License page - if IsUpgrade() and (PageID = wpLicense) then - Result := True; -end; - - -procedure CleanUpSettingsAndFiles(); -var - ResultCode: Integer; -begin - try - Exec(ExpandConstant('{app}\{#mpchc_exe}'), '/unregall', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); - except - end; - DeleteFile(ExpandConstant('{app}\{#mpchc_ini}')); - DelTree(ExpandConstant('{userappdata}\MPC-HC\ShaderCache'), True, True, True); - DeleteFile(ExpandConstant('{userappdata}\MPC-HC\default.mpcpl')); - RemoveDir(ExpandConstant('{userappdata}\MPC-HC')); - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-HC\Filters'); - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-HC\MPC-HC'); - RegDeleteKeyIfEmpty(HKCU, 'Software\MPC-HC'); - - #if INCLUDE_MPCVR - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-BE Filters\MPC Video Renderer'); - RegDeleteKeyIfEmpty(HKCU, 'Software\MPC-BE Filters'); - #endif -end; - - -procedure CleanUpOldSettingsAndFiles(); -begin - DeleteFile(ExpandConstant('{userappdata}\Media Player Classic\default.mpcpl')); - RemoveDir(ExpandConstant('{userappdata}\Media Player Classic')); - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\Gabest\Filters'); - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\Gabest\Media Player Classic'); - RegDeleteKeyIfEmpty(HKCU, 'Software\Gabest'); - RegDeleteValue(HKLM, 'SOFTWARE\Gabest\Media Player Classic', 'ExePath') - RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\Gabest\Media Player Classic'); - RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\Gabest'); -end; - - -procedure InitializeWizard(); -begin - WizardForm.LicenseAcceptedRadio.Checked := True; -end; - - -procedure CurStepChanged(CurStep: TSetupStep); -var - iLanguage: Integer; -begin - if CurStep = ssPostInstall then begin - if IsTaskSelected('reset_settings') then begin - CleanUpSettingsAndFiles(); - RegWriteStringValue(HKCU, 'Software\MPC-HC\MPC-HC', 'ExePath', ExpandConstant('{app}\{#mpchc_exe}')); - end; - - iLanguage := StrToInt(ExpandConstant('{cm:langid}')); - if IsComponentSelected('mpcresources') then begin - if FileExists(ExpandConstant('{app}\{#mpchc_ini}')) then - SetIniInt('Settings', 'InterfaceLanguage', iLanguage, ExpandConstant('{app}\{#mpchc_ini}')) - else - RegWriteDWordValue(HKCU, 'Software\MPC-HC\MPC-HC\Settings', 'InterfaceLanguage', iLanguage); - end; - end; - -end; - - -procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); -begin - // When uninstalling, ask the user to delete MPC-HC settings - if (CurUninstallStep = usUninstall) and SettingsExist() then begin - if SuppressibleMsgBox(CustomMessage('msg_DeleteSettings'), mbConfirmation, MB_YESNO or MB_DEFBUTTON2, IDNO) = IDYES then begin - CleanUpSettingsAndFiles(); - CleanUpOldSettingsAndFiles(); - end; - - RegDeleteValue(HKLM, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath') - RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\MPC-HC\MPC-HC'); - RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\MPC-HC'); - - end; -end; - - -function InitializeSetup(): Boolean; -begin - Result := True; - -#if defined(sse2_required) - if not Is_SSE2_Supported() then begin - SuppressibleMsgBox(CustomMessage('msg_simd_sse2'), mbCriticalError, MB_OK, MB_OK); - Result := False; - end; -#endif - -end; +; (C) 2009-2018 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 . + + +; Requirements: +; Inno Setup Unicode: http://www.jrsoftware.org/isdl.php + + +#if VER < EncodeVer(6,3,2) + #error Update your Inno Setup version (6.3.2 or newer) +#endif + +#ifndef UNICODE + #error Use the Unicode Inno Setup +#endif + +; If you want to compile the 64-bit version define "x64build" (uncomment the define below or use build.bat) +;#define x64Build +;#define MPCHC_LITE + +; Include translations by default. You can bypass this by defining localize=whatever or false etc in build.bat or here +#if !defined(localize) + #if defined(MPCHC_LITE) + #define localize = "false" + #else + #define localize = "true" + #endif +#endif +#define sse2_required + +#if GetEnv('MPC_DRDUMP') == '1' +#define USE_DRDUMP_CRASH_REPORTER 1 +#endif + +; From now on you shouldn't need to change anything + +#include "..\include\mpc-hc_config.h" +#include "..\include\version.h" + +#define copyright_str str(MPC_COPYRIGHT_STR) +#define app_name "MPC-HC" + +#if MPC_NIGHTLY_RELEASE + #define app_ver str(MPC_VERSION_MAJOR) + "." + str(MPC_VERSION_MINOR) + "." + str(MPC_VERSION_PATCH) + "." + str(MPC_VERSION_REV) +#else + #define app_ver str(MPC_VERSION_MAJOR) + "." + str(MPC_VERSION_MINOR) + "." + str(MPC_VERSION_PATCH) +#endif + +#define app_vername = app_name + " " + app_ver +#define quick_launch "{userappdata}\Microsoft\Internet Explorer\Quick Launch" + +#define base_bindir = "..\bin" + +#ifdef x64Build + #define bindir = AddBackslash(base_bindir) + "mpc-hc_x64" + #define mpchc_exe = "mpc-hc64.exe" + #define mpchc_ini = "mpc-hc64.ini" + #define lavfiltersdir = "LAVFilters64" + #define OutFilename = app_name + "." + app_ver + ".x64" + #define platform = "x64" + #define mpcvr_ax = "MpcVideoRenderer64.ax" + #define mediainfo_dll = "..\distrib\x64\MediaInfo.dll" +#else + #define bindir = AddBackslash(base_bindir) + "mpc-hc_x86" + #define mpchc_exe = "mpc-hc.exe" + #define mpchc_ini = "mpc-hc.ini" + #define lavfiltersdir = "LAVFilters" + #define OutFilename = app_name + "." + app_ver + ".x86" + #define platform = "x86" + #define mpcvr_ax = "MpcVideoRenderer.ax" + #define mediainfo_dll = "..\distrib\x86\MediaInfo.dll" +#endif + +#if defined(MPCHC_LITE) + #define bindir = bindir + " Lite" +#endif + +#ifnexist AddBackslash(bindir) + mpchc_exe + #error Compile MPC-HC first +#endif + +#if localize != "true" + #if defined(MPCHC_LITE) + #define OutFilename = OutFilename + ".Lite" + #else + #define OutFilename = OutFilename + ".en" + #endif +#endif + +#if MPC_NIGHTLY_RELEASE + #define FullAppNameVer = app_vername + " " + "(" + str(MPCHC_HASH) + ")" +#else + #define FullAppNameVer = app_vername +#endif + +#if MPC_NIGHTLY_RELEASE + #define FullAppNameVer = FullAppNameVer + " " + str(MPC_VERSION_NIGHTLY) +#endif +#ifdef MPCHC_LITE + #define FullAppNameVer = FullAppNameVer + " " + "Lite" +#endif +#ifdef x64Build + #define FullAppNameVer = FullAppNameVer + " " + "(64-bit)" +#endif + +#ifexist "..\distrib\mpcvr\MpcVideoRenderer.ax" +#define INCLUDE_MPCVR = true +#else +#define INCLUDE_MPCVR = false +#bla +#endif + +#ifexist mediainfo_dll + #if !defined(MPCHC_LITE) +#define INCLUDE_MEDIAINFO = true + #else +#define INCLUDE_MEDIAINFO = false + #endif +#else +#define INCLUDE_MEDIAINFO = false +#endif + + +[Setup] +#ifdef x64Build +AppId = {{2ACBF1FA-F5C3-4B19-A774-B22A31F231B9} +DefaultGroupName = {#app_name} x64 +ArchitecturesAllowed = x64compatible +ArchitecturesInstallIn64BitMode = x64compatible +#else +AppId = {{2624B969-7135-4EB1-B0F6-2D8C397B45F7} +DefaultGroupName = {#app_name} +#endif + +AppName = {#app_name} +AppVersion = {#app_ver} +AppVerName = {#app_vername} +AppPublisher = MPC-HC Team +AppPublisherURL = {#WEBSITE_URL} +AppCopyright = {#copyright_str} +VersionInfoVersion = {#app_ver} +UninstallDisplayIcon = {app}\{#mpchc_exe} +UninstallDisplayName = {#FullAppNameVer} +OutputBaseFilename = {#OutFilename} +DefaultDirName = {code:GetInstallFolder} +LicenseFile = ..\COPYING.txt +OutputDir = . +SetupIconFile = ..\src\mpc-hc\res\icon.ico +WizardImageFile = WizardImageFile.bmp +WizardSmallImageFile = WizardSmallImageFile.bmp +Compression = lzma2/ultra +InternalCompressLevel = ultra +SolidCompression = yes +AllowNoIcons = yes +ShowTasksTreeLines = yes +DisableDirPage = auto +DisableProgramGroupPage = auto +MinVersion = 6.1 +CloseApplications = true +#ifexist "..\signinfo.txt" +SignTool = MySignTool +#endif +SetupMutex = 'mpchc_setup_mutex' + +[Languages] +Name: en; MessagesFile: compiler:Default.isl + +#if localize == "true" +Name: ar; MessagesFile: Languages\Arabic.isl +Name: be; MessagesFile: Languages\Belarusian.isl +Name: bn; MessagesFile: Languages\Bengali.islu +Name: bs_BA; MessagesFile: Languages\Bosnian.isl +Name: ca; MessagesFile: compiler:Languages\Catalan.isl +Name: cs; MessagesFile: compiler:Languages\Czech.isl +Name: da; MessagesFile: compiler:Languages\Danish.isl +Name: de; MessagesFile: compiler:Languages\German.isl +Name: en_GB; MessagesFile: Languages\EnglishBritish.isl +Name: es; MessagesFile: compiler:Languages\Spanish.isl +Name: eu; MessagesFile: Languages\Basque.isl +Name: fi; MessagesFile: compiler:Languages\Finnish.isl +Name: fr; MessagesFile: compiler:Languages\French.isl +Name: gl; MessagesFile: Languages\Galician.isl +Name: he; MessagesFile: compiler:Languages\Hebrew.isl +Name: hr; MessagesFile: Languages\Croatian.isl +Name: hu; MessagesFile: compiler:Languages\Hungarian.isl +Name: hy; MessagesFile: compiler:Languages\Armenian.isl +Name: id; MessagesFile: Languages\Indonesian.isl +Name: it; MessagesFile: compiler:Languages\Italian.isl +Name: ja; MessagesFile: compiler:Languages\Japanese.isl +Name: ko; MessagesFile: Languages\Korean.isl +Name: lt; MessagesFile: Languages\Lithuanian.isl +Name: ms_MY; MessagesFile: Languages\Malaysian.isl +Name: nl; MessagesFile: compiler:Languages\Dutch.isl +Name: pl; MessagesFile: compiler:Languages\Polish.isl +Name: pt_BR; MessagesFile: compiler:Languages\BrazilianPortuguese.isl +Name: pt_PT; MessagesFile: compiler:Languages\Portuguese.isl +Name: ro; MessagesFile: Languages\Romanian.isl +Name: ru; MessagesFile: compiler:Languages\Russian.isl +Name: sk; MessagesFile: Languages\Slovak.isl +Name: sl; MessagesFile: compiler:Languages\Slovenian.isl +Name: sv; MessagesFile: Languages\Swedish.isl +Name: th_TH; MessagesFile: Languages\Thai.isl +Name: tt; MessagesFile: Languages\Tatar.isl +Name: tr; MessagesFile: compiler:Languages\Turkish.isl +Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl +Name: vi; MessagesFile: Languages\Vietnamese.isl +Name: zh_CN; MessagesFile: Languages\ChineseSimplified.isl +Name: zh_TW; MessagesFile: Languages\ChineseTraditional.isl +#endif + +; Include installer's custom messages +#include "custom_messages.iss" + + +[Types] +Name: default; Description: {cm:types_DefaultInstallation} +Name: custom; Description: {cm:types_CustomInstallation}; Flags: iscustom + + +[Components] +Name: main; Description: {#app_vername}; Types: default custom; Flags: fixed +#if INCLUDE_MPCVR +Name: mpcvr; Description: MPC Video Renderer; Types: default custom +#endif +Name: mpciconlib; Description: {cm:comp_mpciconlib}; Types: default custom +#if localize == "true" +Name: mpcresources; Description: {cm:comp_mpcresources}; Types: default custom; Flags: disablenouninstallwarning +#endif + + +[Tasks] +Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons} +Name: desktopicon\user; Description: {cm:tsk_CurrentUser}; GroupDescription: {cm:AdditionalIcons}; Flags: exclusive +Name: desktopicon\common; Description: {cm:tsk_AllUsers}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked exclusive +Name: quicklaunchicon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked; OnlyBelowVersion: 6.01 +Name: reset_settings; Description: {cm:tsk_ResetSettings}; GroupDescription: {cm:tsk_Other}; Flags: checkedonce unchecked; Check: SettingsExist() + + +[Files] +Source: {#bindir}\{#mpchc_exe}; DestDir: {app}; Components: main; Flags: ignoreversion + #if localize == "true" +Source: {#bindir}\Lang\mpcresources.??.dll; DestDir: {app}\Lang; Components: mpcresources; Flags: ignoreversion +Source: {#bindir}\Lang\mpcresources.??_??.dll; DestDir: {app}\Lang; Components: mpcresources; Flags: ignoreversion + #endif +Source: {#bindir}\mpciconlib.dll; DestDir: {app}; Components: mpciconlib; Flags: ignoreversion + #ifndef MPCHC_LITE +Source: {#bindir}\{#lavfiltersdir}\*.dll; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion +Source: {#bindir}\{#lavfiltersdir}\*.ax; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion +Source: {#bindir}\{#lavfiltersdir}\*.manifest; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion + #endif +Source: {#platform}\d3dcompiler_{#MPC_D3D_COMPILER_VERSION}.dll; DestDir: {app}; Components: main; Flags: ignoreversion +Source: {#platform}\d3dx9_{#MPC_DX_SDK_NUMBER}.dll; DestDir: {app}; Components: main; Flags: ignoreversion + #if INCLUDE_MEDIAINFO +Source: {#platform}\mediainfo.dll; DestDir: {app}; Components: main; Flags: ignoreversion + #endif +Source: ..\src\mpc-hc\res\shaders\dx9\*.hlsl; DestDir: {app}\Shaders; Components: main; Flags: onlyifdoesntexist +Source: ..\src\mpc-hc\res\shaders\dx11\*.hlsl; DestDir: {app}\Shaders11; Components: main; Flags: onlyifdoesntexist +Source: ..\COPYING.txt; DestDir: {app}; Components: main; Flags: ignoreversion +Source: ..\docs\Authors.txt; DestDir: {app}; Components: main; Flags: ignoreversion + #if USE_DRDUMP_CRASH_REPORTER +Source: {#platform}\crashrpt.dll; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion +Source: {#platform}\dbghelp.dll; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion +Source: {#platform}\sendrpt.exe; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion +Source: CrashReporter_LICENSE.txt; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion + #endif + #if INCLUDE_MPCVR +Source: ..\distrib\mpcvr\{#mpcvr_ax}; DestDir: {app}\MPCVR; Components: mpcvr; Flags: ignoreversion + #endif + + +[Icons] +#ifdef x64Build +Name: {group}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0 +Name: {commondesktop}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\common +Name: {userdesktop}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\user +Name: {#quick_launch}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: quicklaunchicon +#else +Name: {group}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0 +Name: {commondesktop}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\common +Name: {userdesktop}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\user +Name: {#quick_launch}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: quicklaunchicon +#endif +Name: {group}\{cm:UninstallProgram,{#app_name}}; Filename: {uninstallexe}; Comment: {cm:UninstallProgram,{#app_name}}; WorkingDir: {app} + + +[Run] +Filename: {app}\{#mpchc_exe}; Description: {cm:LaunchProgram,{#app_name}}; WorkingDir: {app}; Flags: nowait postinstall skipifsilent unchecked + + +[InstallDelete] +Type: files; Name: {userdesktop}\{#app_name}.lnk; Check: not IsTaskSelected('desktopicon\user') and IsUpgrade() +Type: files; Name: {commondesktop}\{#app_name}.lnk; Check: not IsTaskSelected('desktopicon\common') and IsUpgrade() +Type: files; Name: {#quick_launch}\{#app_name}.lnk; Check: not IsTaskSelected('quicklaunchicon') and IsUpgrade(); OnlyBelowVersion: 6.01 +Type: files; Name: {app}\AUTHORS; Check: IsUpgrade() +Type: files; Name: {app}\COPYING; Check: IsUpgrade() + #if !USE_DRDUMP_CRASH_REPORTER +Type: filesandordirs; Name: {app}\CrashReporter; Check: IsUpgrade() + #endif + +; old shortcuts +#ifdef x64Build +Type: files; Name: {group}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() +Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() +Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() +Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() +#else +Type: files; Name: {group}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() +Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() +Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() +Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() +#endif +Type: files; Name: {group}\{cm:ProgramOnTheWeb,Media Player Classic - Home Cinema}.url; Check: IsUpgrade() +Type: files; Name: {group}\{cm:UninstallProgram,Media Player Classic - Home Cinema}.lnk; Check: IsUpgrade() + +Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('desktopicon\user') and IsUpgrade() +Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('desktopicon\common') and IsUpgrade() +Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('quicklaunchicon') and IsUpgrade(); OnlyBelowVersion: 6.01 + +; Old ffmpeg dlls from LAV Filters +Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-60.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-59.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-58.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-57.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-9.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-8.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-7.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-60.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-59.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-58.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-57.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-58.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-57.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-56.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-55.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swresample-lav-4.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-7.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-6.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-5.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-4.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avresample-lav-4.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avresample-lav-3.dll; Check: IsUpgrade() + +#ifdef x64Build +; Super old LAV files +Type: files; Name: {app}\LAVFilters\avcodec-lav-??.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\avfilter-lav-?.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\avformat-lav-??.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\avresample-lav-?.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\avutil-lav-??.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\IntelQuickSyncDecoder.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\LAVAudio.ax; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\LAVFilters.Dependencies.manifest; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\LAVSplitter.ax; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\LAVVideo.ax; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\libbluray.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\swscale-lav-?.dll; Check: IsUpgrade() +Type: dirifempty; Name: {app}\LAVFilters\; Check: IsUpgrade() +#endif + + +#if localize == "true" +; remove the old language dlls when upgrading +Type: files; Name: {app}\mpcresources.br.dll +Type: files; Name: {app}\mpcresources.by.dll +Type: files; Name: {app}\mpcresources.ca.dll +Type: files; Name: {app}\mpcresources.cz.dll +Type: files; Name: {app}\mpcresources.de.dll +Type: files; Name: {app}\mpcresources.es.dll +Type: files; Name: {app}\mpcresources.fr.dll +Type: files; Name: {app}\mpcresources.he.dll +Type: files; Name: {app}\mpcresources.hu.dll +Type: files; Name: {app}\mpcresources.hy.dll +Type: files; Name: {app}\mpcresources.it.dll +Type: files; Name: {app}\mpcresources.ja.dll +Type: files; Name: {app}\mpcresources.kr.dll +Type: files; Name: {app}\mpcresources.nl.dll +Type: files; Name: {app}\mpcresources.pl.dll +Type: files; Name: {app}\mpcresources.ru.dll +Type: files; Name: {app}\mpcresources.sc.dll +Type: files; Name: {app}\mpcresources.sk.dll +Type: files; Name: {app}\mpcresources.sv.dll +Type: files; Name: {app}\mpcresources.tc.dll +Type: files; Name: {app}\mpcresources.tr.dll +Type: files; Name: {app}\mpcresources.ua.dll +Type: files; Name: {app}\Lang\mpcresources.br.dll +Type: files; Name: {app}\Lang\mpcresources.by.dll +Type: files; Name: {app}\Lang\mpcresources.cz.dll +Type: files; Name: {app}\Lang\mpcresources.en-GB.dll +Type: files; Name: {app}\Lang\mpcresources.kr.dll +Type: files; Name: {app}\Lang\mpcresources.sc.dll +Type: files; Name: {app}\Lang\mpcresources.tc.dll +Type: files; Name: {app}\Lang\mpcresources.ua.dll +#endif + + +[Code] +#if defined(sse2_required) +function IsProcessorFeaturePresent(Feature: Integer): Boolean; +external 'IsProcessorFeaturePresent@kernel32.dll stdcall'; +#endif + + +function GetInstallFolder(Default: String): String; +var + sInstallPath: String; +begin + if not RegQueryStringValue(HKCU, 'SOFTWARE\Gabest\Media Player Classic', 'ExePath', sInstallPath) + or not RegQueryStringValue(HKCU, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath', sInstallPath) then begin + Result := ExpandConstant('{pf}\MPC-HC'); + end + else begin + RegQueryStringValue(HKCU, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath', sInstallPath); + Result := ExtractFileDir(sInstallPath); + if (Result = '') or not DirExists(Result) then begin + Result := ExpandConstant('{pf}\MPC-HC'); + end; + end; +end; + + +#if defined(sse2_required) + +function Is_SSE2_Supported(): Boolean; +begin + // PF_XMMI64_INSTRUCTIONS_AVAILABLE + Result := IsProcessorFeaturePresent(10); +end; + +#endif + + +function IsUpgrade(): Boolean; +var + sPrevPath: String; +begin + sPrevPath := WizardForm.PrevAppDir; + Result := (sPrevPath <> ''); +end; + + +// Check if MPC-HC's settings exist +function SettingsExist(): Boolean; +begin + if RegKeyExists(HKEY_CURRENT_USER, 'Software\Gabest\Media Player Classic') or + RegKeyExists(HKEY_CURRENT_USER, 'Software\MPC-HC\MPC-HC') or + FileExists(ExpandConstant('{app}\{#mpchc_ini}')) then + Result := True + else + Result := False; +end; + + +function ShouldSkipPage(PageID: Integer): Boolean; +begin + // Hide the License page + if IsUpgrade() and (PageID = wpLicense) then + Result := True; +end; + + +procedure CleanUpSettingsAndFiles(); +var + ResultCode: Integer; +begin + try + Exec(ExpandConstant('{app}\{#mpchc_exe}'), '/unregall', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + except + end; + DeleteFile(ExpandConstant('{app}\{#mpchc_ini}')); + DelTree(ExpandConstant('{userappdata}\MPC-HC\ShaderCache'), True, True, True); + DeleteFile(ExpandConstant('{userappdata}\MPC-HC\default.mpcpl')); + RemoveDir(ExpandConstant('{userappdata}\MPC-HC')); + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-HC\Filters'); + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-HC\MPC-HC'); + RegDeleteKeyIfEmpty(HKCU, 'Software\MPC-HC'); + + #if INCLUDE_MPCVR + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-BE Filters\MPC Video Renderer'); + RegDeleteKeyIfEmpty(HKCU, 'Software\MPC-BE Filters'); + #endif +end; + + +procedure CleanUpOldSettingsAndFiles(); +begin + DeleteFile(ExpandConstant('{userappdata}\Media Player Classic\default.mpcpl')); + RemoveDir(ExpandConstant('{userappdata}\Media Player Classic')); + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\Gabest\Filters'); + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\Gabest\Media Player Classic'); + RegDeleteKeyIfEmpty(HKCU, 'Software\Gabest'); + RegDeleteValue(HKLM, 'SOFTWARE\Gabest\Media Player Classic', 'ExePath') + RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\Gabest\Media Player Classic'); + RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\Gabest'); +end; + + +procedure InitializeWizard(); +begin + WizardForm.LicenseAcceptedRadio.Checked := True; +end; + + +procedure CurStepChanged(CurStep: TSetupStep); +var + iLanguage: Integer; +begin + if CurStep = ssPostInstall then begin + if IsTaskSelected('reset_settings') then begin + CleanUpSettingsAndFiles(); + RegWriteStringValue(HKCU, 'Software\MPC-HC\MPC-HC', 'ExePath', ExpandConstant('{app}\{#mpchc_exe}')); + end; + + iLanguage := StrToInt(ExpandConstant('{cm:langid}')); + if IsComponentSelected('mpcresources') then begin + if FileExists(ExpandConstant('{app}\{#mpchc_ini}')) then + SetIniInt('Settings', 'InterfaceLanguage', iLanguage, ExpandConstant('{app}\{#mpchc_ini}')) + else + RegWriteDWordValue(HKCU, 'Software\MPC-HC\MPC-HC\Settings', 'InterfaceLanguage', iLanguage); + end; + end; + +end; + + +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +begin + // When uninstalling, ask the user to delete MPC-HC settings + if (CurUninstallStep = usUninstall) and SettingsExist() then begin + if SuppressibleMsgBox(CustomMessage('msg_DeleteSettings'), mbConfirmation, MB_YESNO or MB_DEFBUTTON2, IDNO) = IDYES then begin + CleanUpSettingsAndFiles(); + CleanUpOldSettingsAndFiles(); + end; + + RegDeleteValue(HKLM, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath') + RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\MPC-HC\MPC-HC'); + RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\MPC-HC'); + + end; +end; + + +function InitializeSetup(): Boolean; +begin + Result := True; + +#if defined(sse2_required) + if not Is_SSE2_Supported() then begin + SuppressibleMsgBox(CustomMessage('msg_simd_sse2'), mbCriticalError, MB_OK, MB_OK); + Result := False; + end; +#endif + +end; diff --git a/docs/Compilation.md b/docs/Compilation.md index 9c4e8b6bdcf..d018365dde6 100644 --- a/docs/Compilation.md +++ b/docs/Compilation.md @@ -1,162 +1,162 @@ -# Compilation instructions - -## Part A: Preparing the Visual Studio environment - -### Visual Studio 2019 - -1. Install Visual Studio (any edition will work fine). Select at minimum the following components: - - C++ core features - - IntelliCode - - Windows Universal C Runtime - - Windows Universal CRT SDK - - C++ build tools (x86 & x64) - - C++ ATL - - C++ MFC - - Windows 10 SDK (10.0.17763.0 or any other version) -2. Install the Windows 8.1 SDK → - - When choosing which features to install you only need to select "Windows Software Development Kit". - - Alternatively you can use Windows 10 SDK, but then resulting binaries will require at least Windows 7 SP1, so you lose compatibility with Windows 7 RTM. - - -## Part B: Install Python 3 (optional) - -This is required for building the translation DLL files. - -1. Install Python version 3.8.7 from (You can use Python 3.6 or later version) -2. Run this command to install a required library: - `C:\Program Files\Python38\Scripts\pip install --upgrade polib` - - -## Part C: Preparing the MSYS and GCC environment (optional) - -This is required for building LAV Filters, which is used as the internal codecs by MPC-HC. - -You can skip compilation of LAV Filters by selecting the "Release Lite"/"Debug Lite" build configuration -in the MPC-HC project file. This can be useful for making quick builds during development. The resulting -binary will be missing the internal filter functionality. So don't use this configuration for actual -releases. - -1. Download MSYS2 from . - If you are using a 64-bit Operating System, which you should be, get the 64-bit version. -2. Install it to for example **`C:\MSYS64\`**. The installation path should be specified in your **build.user.bat** configuration script that you will create later. -3. Run `msys2_shell.bat` -4. Install some additional required tools by running this command: - ```text - pacman -S make pkg-config diffutils - ``` -5. Then update all packages by running this command: - ```text - pacman -Syu - ``` - When you are asked to restart MSYS, say yes. Start MSYS again and repeat the above command. Once everything is updated, you can close MSYS. -6. Download the latest mingw-w64-gcc package from and extract it to folder **`C:\MSYS64\mingw64`** (overwriting any existing files). -7. It is recommended to add **`C:\MSYS64\mingw64\bin`** and **`C:\MSYS64\usr\bin`** to the %PATH% environment variable. - This allows you to run GCC and all other MSYS tools from the Windows command line. - Windows Control Panel > System > Advanced System Settings > Environment variables. - On Windows 10 you can access the legacy control panel by clicking on the Windows Start menu and typing `control.exe`. - -## Part D: Yasm - -1. Download YASM from -2. Rename it to **yasm.exe** and put it in a folder that is included in %PATH%. For example **`C:\Windows`** or **`C:\MSYS64\usr\bin`** (see part C). - -## PART E: NASM - -1. Download NASM from -2. Put nasm.exe in a folder that is included in %PATH%. For example **`C:\Windows`**. - -## Part F: Config file with paths - -Create a file named **build.user.bat** in the source code folder of MPC-HC (see part F). It should have the following contents: (with paths adapted for your system!) - -```bat -@ECHO OFF -REM [Required for LAVFilters] MSYS2/MinGW paths: -SET "MPCHC_MSYS=C:\MSYS64" -SET "MPCHC_MINGW32=C:\MSYS64\mingw64" -SET "MPCHC_MINGW64=C:\MSYS64\mingw64" -SET "MSYSTEM=MINGW32" -SET "MSYS2_PATH_TYPE=inherit" -REM [Optional] Specify GIT location if it is not already set in %PATH% -SET "MPCHC_GIT=C:\Program Files\Git" -REM [Optional] If you plan to modify the translations, install Python 3.8 and set the variable to its path -SET "MPCHC_PYTHON=C:\Program Files\Python38" -REM [Optional] If you want to customize the Windows SDK version used, set this variable -SET "MPCHC_WINSDK_VER=8.1" -``` - -Notes: - -* For Visual Studio, we will try to detect the VS installation path automatically. If that fails you need to specify the installation path yourself. For example: - ``` - SET "MPCHC_VS_PATH=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\" - ``` -* If you installed the MSYS package in another directory then make sure that you have set the correct paths in your **build.user.bat** file. -* If you don't have Git installed then the build version will be inaccurate, the revision number will be a hard-coded as zero. - - -## Part G: Downloading the MPC-HC source - -You need Git for downloading the source code. - -Install **Git for Windows** from and also **Git Extensions** from . -Choose `Use Git from the Windows command prompt`. This isn't mandatory, so if you choose -`Use Git from Git Bash only` make sure you set the `MPCHC_GIT` variable in **build.user.bat**. - -Use Git to clone MPC-HC's repository to **C:\mpc-hc** (or anywhere else you like). - -1. Install Git -2. Run these commands: - - ```text - git clone --recursive https://github.com/clsid2/mpc-hc.git - ``` - - or - - ```text - git clone https://github.com/clsid2/mpc-hc.git - git submodule update --init --recursive - ``` - - If a submodule update fails, try running: - - ```text - git submodule foreach --recursive git fetch --tags - ``` - - then run the update again - - ```text - git submodule update --init --recursive - ``` - -Note that you can add `-b master` to the `git clone` command if you want to get the latest -stable version instead of the latest development version. - -## Part H: Compiling the MPC-HC source - -1. Open the solution file **C:\mpc-hc\mpc-hc.sln**. - Change the solution's configuration to **Release** (in the toolbar). -2. Press **F7** to build the solution. -3. You now have **mpc-hc.exe** under **C:\mpc-hc\bin\mpc-hc_x86** -4. Open the solution file **C:\mpc-hc\mpciconlib.sln** -5. Press **F7** to build the solution. -6. You now have **mpciconlib.dll** under **C:\mpc-hc\bin\mpc-hc_x86** -7. Open the solution file **C:\mpc-hc\mpcresources.sln** -8. Build **BuildAll** project. -9. You now have **mpcresources.XX.dll** under **C:\mpc-hc\bin\mpc-hc_x86\Lang** - -Alternatively, you can use **build.bat** that can build everything for you (run: `build.bat help` for more info). - - -## Part I: Building the installer - -Download Inno Setup Unicode v5.5.9 or newer from . -Install everything and then go to **C:\mpc-hc\distrib**, open **mpc-hc_setup.iss** with Inno Setup, -read the first comments in the script and compile it. - -### NOTES - -* **build.bat** can build the installer by using the **installer** or the **packages** switch. -* Use Inno Setup's built-in IDE if you want to edit the iss file and don't change its encoding since it can break easily. +# Compilation instructions + +## Part A: Preparing the Visual Studio environment + +### Visual Studio 2019 + +1. Install Visual Studio (any edition will work fine). Select at minimum the following components: + - C++ core features + - IntelliCode + - Windows Universal C Runtime + - Windows Universal CRT SDK + - C++ build tools (x86 & x64) + - C++ ATL + - C++ MFC + - Windows 10 SDK (10.0.17763.0 or any other version) +2. Install the Windows 8.1 SDK → + - When choosing which features to install you only need to select "Windows Software Development Kit". + - Alternatively you can use Windows 10 SDK, but then resulting binaries will require at least Windows 7 SP1, so you lose compatibility with Windows 7 RTM. + + +## Part B: Install Python 3 (optional) + +This is required for building the translation DLL files. + +1. Install Python version 3.8.7 from (You can use Python 3.6 or later version) +2. Run this command to install a required library: + `C:\Program Files\Python38\Scripts\pip install --upgrade polib` + + +## Part C: Preparing the MSYS and GCC environment (optional) + +This is required for building LAV Filters, which is used as the internal codecs by MPC-HC. + +You can skip compilation of LAV Filters by selecting the "Release Lite"/"Debug Lite" build configuration +in the MPC-HC project file. This can be useful for making quick builds during development. The resulting +binary will be missing the internal filter functionality. So don't use this configuration for actual +releases. + +1. Download MSYS2 from . + If you are using a 64-bit Operating System, which you should be, get the 64-bit version. +2. Install it to for example **`C:\MSYS64\`**. The installation path should be specified in your **build.user.bat** configuration script that you will create later. +3. Run `msys2_shell.bat` +4. Install some additional required tools by running this command: + ```text + pacman -S make pkg-config diffutils + ``` +5. Then update all packages by running this command: + ```text + pacman -Syu + ``` + When you are asked to restart MSYS, say yes. Start MSYS again and repeat the above command. Once everything is updated, you can close MSYS. +6. Download the latest mingw-w64-gcc package from and extract it to folder **`C:\MSYS64\mingw64`** (overwriting any existing files). +7. It is recommended to add **`C:\MSYS64\mingw64\bin`** and **`C:\MSYS64\usr\bin`** to the %PATH% environment variable. + This allows you to run GCC and all other MSYS tools from the Windows command line. + Windows Control Panel > System > Advanced System Settings > Environment variables. + On Windows 10 you can access the legacy control panel by clicking on the Windows Start menu and typing `control.exe`. + +## Part D: Yasm + +1. Download YASM from +2. Rename it to **yasm.exe** and put it in a folder that is included in %PATH%. For example **`C:\Windows`** or **`C:\MSYS64\usr\bin`** (see part C). + +## PART E: NASM + +1. Download NASM from +2. Put nasm.exe in a folder that is included in %PATH%. For example **`C:\Windows`**. + +## Part F: Config file with paths + +Create a file named **build.user.bat** in the source code folder of MPC-HC (see part F). It should have the following contents: (with paths adapted for your system!) + +```bat +@ECHO OFF +REM [Required for LAVFilters] MSYS2/MinGW paths: +SET "MPCHC_MSYS=C:\MSYS64" +SET "MPCHC_MINGW32=C:\MSYS64\mingw64" +SET "MPCHC_MINGW64=C:\MSYS64\mingw64" +SET "MSYSTEM=MINGW32" +SET "MSYS2_PATH_TYPE=inherit" +REM [Optional] Specify GIT location if it is not already set in %PATH% +SET "MPCHC_GIT=C:\Program Files\Git" +REM [Optional] If you plan to modify the translations, install Python 3.8 and set the variable to its path +SET "MPCHC_PYTHON=C:\Program Files\Python38" +REM [Optional] If you want to customize the Windows SDK version used, set this variable +SET "MPCHC_WINSDK_VER=8.1" +``` + +Notes: + +* For Visual Studio, we will try to detect the VS installation path automatically. If that fails you need to specify the installation path yourself. For example: + ``` + SET "MPCHC_VS_PATH=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\" + ``` +* If you installed the MSYS package in another directory then make sure that you have set the correct paths in your **build.user.bat** file. +* If you don't have Git installed then the build version will be inaccurate, the revision number will be a hard-coded as zero. + + +## Part G: Downloading the MPC-HC source + +You need Git for downloading the source code. + +Install **Git for Windows** from and also **Git Extensions** from . +Choose `Use Git from the Windows command prompt`. This isn't mandatory, so if you choose +`Use Git from Git Bash only` make sure you set the `MPCHC_GIT` variable in **build.user.bat**. + +Use Git to clone MPC-HC's repository to **C:\mpc-hc** (or anywhere else you like). + +1. Install Git +2. Run these commands: + + ```text + git clone --recursive https://github.com/clsid2/mpc-hc.git + ``` + + or + + ```text + git clone https://github.com/clsid2/mpc-hc.git + git submodule update --init --recursive + ``` + + If a submodule update fails, try running: + + ```text + git submodule foreach --recursive git fetch --tags + ``` + + then run the update again + + ```text + git submodule update --init --recursive + ``` + +Note that you can add `-b master` to the `git clone` command if you want to get the latest +stable version instead of the latest development version. + +## Part H: Compiling the MPC-HC source + +1. Open the solution file **C:\mpc-hc\mpc-hc.sln**. + Change the solution's configuration to **Release** (in the toolbar). +2. Press **F7** to build the solution. +3. You now have **mpc-hc.exe** under **C:\mpc-hc\bin\mpc-hc_x86** +4. Open the solution file **C:\mpc-hc\mpciconlib.sln** +5. Press **F7** to build the solution. +6. You now have **mpciconlib.dll** under **C:\mpc-hc\bin\mpc-hc_x86** +7. Open the solution file **C:\mpc-hc\mpcresources.sln** +8. Build **BuildAll** project. +9. You now have **mpcresources.XX.dll** under **C:\mpc-hc\bin\mpc-hc_x86\Lang** + +Alternatively, you can use **build.bat** that can build everything for you (run: `build.bat help` for more info). + + +## Part I: Building the installer + +Download Inno Setup Unicode v5.5.9 or newer from . +Install everything and then go to **C:\mpc-hc\distrib**, open **mpc-hc_setup.iss** with Inno Setup, +read the first comments in the script and compile it. + +### NOTES + +* **build.bat** can build the installer by using the **installer** or the **packages** switch. +* Use Inno Setup's built-in IDE if you want to edit the iss file and don't change its encoding since it can break easily. diff --git a/include/IBitRateInfo.h b/include/IBitRateInfo.h index b2593838987..2cbab1e7679 100644 --- a/include/IBitRateInfo.h +++ b/include/IBitRateInfo.h @@ -1,30 +1,30 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("EB2CD9E6-BA08-4acb-AA0F-3D8D0DD521CA")) - IBitRateInfo : - public IUnknown -{ - STDMETHOD_(DWORD, GetCurrentBitRate)() PURE; - STDMETHOD_(DWORD, GetAverageBitRate)() PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("EB2CD9E6-BA08-4acb-AA0F-3D8D0DD521CA")) + IBitRateInfo : + public IUnknown +{ + STDMETHOD_(DWORD, GetCurrentBitRate)() PURE; + STDMETHOD_(DWORD, GetAverageBitRate)() PURE; +}; diff --git a/include/IBufferInfo.h b/include/IBufferInfo.h index ca6133b125a..7a1eebf9a15 100644 --- a/include/IBufferInfo.h +++ b/include/IBufferInfo.h @@ -1,31 +1,31 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("46070104-1318-4A82-8822-E99AB7CD15C1")) - IBufferInfo : - public IUnknown -{ - STDMETHOD_(int, GetCount()) = 0; - STDMETHOD(GetStatus(int i, int& samples, int& size)) = 0; - STDMETHOD_(DWORD, GetPriority()) = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("46070104-1318-4A82-8822-E99AB7CD15C1")) + IBufferInfo : + public IUnknown +{ + STDMETHOD_(int, GetCount()) = 0; + STDMETHOD(GetStatus(int i, int& samples, int& size)) = 0; + STDMETHOD_(DWORD, GetPriority()) = 0; +}; diff --git a/include/IChapterInfo.h b/include/IChapterInfo.h index dac4d58a944..9c82de438ff 100644 --- a/include/IChapterInfo.h +++ b/include/IChapterInfo.h @@ -1,66 +1,66 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -enum ChapterType { - AtomicChapter = 0, // only contain one element - SubChapter = 1 // contain a list of elements -}; - -#pragma pack(push, 1) -struct ChapterElement { - WORD Size; // size of this structure - BYTE Type; // see ChapterType - UINT ChapterId; // unique identifier for this element - REFERENCE_TIME rtStart; // REFERENCE_TIME in 100ns - REFERENCE_TIME rtStop; // REFERENCE_TIME in 100ns - ChapterElement() - : Size(sizeof(ChapterElement)) - , Type(0) - , ChapterId(0) - , rtStart(0) - , rtStop(0) - {} -}; -#pragma pack(pop) - -interface __declspec(uuid("8E128709-3DC8-4e49-B632-380FCF496B6D")) - IChapterInfo : - public IUnknown -{ -#define CHAPTER_BAD_ID 0xFFFFFFFF -#define CHAPTER_ROOT_ID 0 - - // \param aChapterID is 0 for the top level one - STDMETHOD_(UINT, GetChapterCount)(UINT aChapterID) = 0; - - // \param aIndex start from 1 to GetChapterCount(aParentChapterId) - STDMETHOD_(UINT, GetChapterId)(UINT aParentChapterId, UINT aIndex) = 0; - - STDMETHOD_(UINT, GetChapterCurrentId)() = 0; - - STDMETHOD_(BOOL, GetChapterInfo)(UINT aChapterID, struct ChapterElement* pStructureToFill) = 0; - - // \param PreferredLanguage Language code as in ISO-639-2 (3 chars) - // \param CountryCode Country code as in internet domains - STDMETHOD_(BSTR, GetChapterStringInfo)(UINT aChapterID, CHAR PreferredLanguage[3], CHAR CountryCode[2]) = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +enum ChapterType { + AtomicChapter = 0, // only contain one element + SubChapter = 1 // contain a list of elements +}; + +#pragma pack(push, 1) +struct ChapterElement { + WORD Size; // size of this structure + BYTE Type; // see ChapterType + UINT ChapterId; // unique identifier for this element + REFERENCE_TIME rtStart; // REFERENCE_TIME in 100ns + REFERENCE_TIME rtStop; // REFERENCE_TIME in 100ns + ChapterElement() + : Size(sizeof(ChapterElement)) + , Type(0) + , ChapterId(0) + , rtStart(0) + , rtStop(0) + {} +}; +#pragma pack(pop) + +interface __declspec(uuid("8E128709-3DC8-4e49-B632-380FCF496B6D")) + IChapterInfo : + public IUnknown +{ +#define CHAPTER_BAD_ID 0xFFFFFFFF +#define CHAPTER_ROOT_ID 0 + + // \param aChapterID is 0 for the top level one + STDMETHOD_(UINT, GetChapterCount)(UINT aChapterID) = 0; + + // \param aIndex start from 1 to GetChapterCount(aParentChapterId) + STDMETHOD_(UINT, GetChapterId)(UINT aParentChapterId, UINT aIndex) = 0; + + STDMETHOD_(UINT, GetChapterCurrentId)() = 0; + + STDMETHOD_(BOOL, GetChapterInfo)(UINT aChapterID, struct ChapterElement* pStructureToFill) = 0; + + // \param PreferredLanguage Language code as in ISO-639-2 (3 chars) + // \param CountryCode Country code as in internet domains + STDMETHOD_(BSTR, GetChapterStringInfo)(UINT aChapterID, CHAR PreferredLanguage[3], CHAR CountryCode[2]) = 0; +}; diff --git a/include/IFilterVersion.h b/include/IFilterVersion.h index 0f7d44bf12d..e07f077036d 100644 --- a/include/IFilterVersion.h +++ b/include/IFilterVersion.h @@ -1,29 +1,29 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("A0DD28E1-61C0-4539-A7E6-14544AFF092E")) - IFilterVersion : - public IUnknown -{ - STDMETHOD_(DWORD, GetFilterVersion)() = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("A0DD28E1-61C0-4539-A7E6-14544AFF092E")) + IFilterVersion : + public IUnknown +{ + STDMETHOD_(DWORD, GetFilterVersion)() = 0; +}; diff --git a/include/IKeyFrameInfo.h b/include/IKeyFrameInfo.h index 4bb611682a4..1ec8f486edd 100644 --- a/include/IKeyFrameInfo.h +++ b/include/IKeyFrameInfo.h @@ -1,30 +1,30 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("01A5BBD3-FE71-487C-A2EC-F585918A8724")) - IKeyFrameInfo : - public IUnknown -{ - STDMETHOD(GetKeyFrameCount)(UINT& nKFs) = 0; // returns S_FALSE when every frame is a keyframe - STDMETHOD(GetKeyFrames)(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs /* in, out*/) = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("01A5BBD3-FE71-487C-A2EC-F585918A8724")) + IKeyFrameInfo : + public IUnknown +{ + STDMETHOD(GetKeyFrameCount)(UINT& nKFs) = 0; // returns S_FALSE when every frame is a keyframe + STDMETHOD(GetKeyFrames)(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs /* in, out*/) = 0; +}; diff --git a/include/ITrackInfo.h b/include/ITrackInfo.h index 2795a36e3b1..12d1261b2cb 100644 --- a/include/ITrackInfo.h +++ b/include/ITrackInfo.h @@ -1,84 +1,84 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -enum TrackType { - TypeVideo = 1, - TypeAudio = 2, - TypeComplex = 3, - TypeLogo = 0x10, - TypeSubtitle = 0x11, - TypeControl = 0x20 -}; - -#pragma pack(push, 1) - -struct TrackElement { - WORD Size; // Size of this structure - BYTE Type; // See TrackType - BOOL FlagDefault; // Set if the track is the default for its TrackType. - BOOL FlagForced; // Set if that track MUST be used during playback. - BOOL FlagLacing; // Set if the track may contain blocks using lacing. - UINT MinCache; // The minimum number of frames a player should be able to cache during playback. - UINT MaxCache; // The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed. - CHAR Language[4]; // Specifies the language of the track, in the ISO-639-2 form. (end with '\0') -}; - -struct TrackExtendedInfoVideo { - WORD Size; // Size of this structure - BOOL Interlaced; // Set if the video is interlaced. - UINT PixelWidth; // Width of the encoded video frames in pixels. - UINT PixelHeight; // Height of the encoded video frames in pixels. - UINT DisplayWidth; // Width of the video frames to display. - UINT DisplayHeight; // Height of the video frames to display. - BYTE DisplayUnit; // Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches). - BYTE AspectRatioType; // Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed). -}; - -struct TrackExtendedInfoAudio { - WORD Size; // Size of this structure - float SamplingFreq; // Sampling frequency in Hz. - float OutputSamplingFrequency; // Real output sampling frequency in Hz (used for SBR techniques). - UINT Channels; // Numbers of channels in the track. - UINT BitDepth; // Bits per sample, mostly used for PCM. -}; - -#pragma pack(pop) - -interface __declspec(uuid("03E98D51-DDE7-43aa-B70C-42EF84A3A23D")) - ITrackInfo : - public IUnknown -{ - STDMETHOD_(UINT, GetTrackCount)() = 0; - - // \param aTrackIdx the track index (from 0 to GetTrackCount()-1) - STDMETHOD_(BOOL, GetTrackInfo)(UINT aTrackIdx, struct TrackElement* pStructureToFill) = 0; - - // Get an extended information struct relative to the track type - STDMETHOD_(BOOL, GetTrackExtendedInfo)(UINT aTrackIdx, void* pStructureToFill) = 0; - - STDMETHOD_(BSTR, GetTrackCodecID)(UINT aTrackIdx) = 0; - STDMETHOD_(BSTR, GetTrackName)(UINT aTrackIdx) = 0; - STDMETHOD_(BSTR, GetTrackCodecName)(UINT aTrackIdx) = 0; - STDMETHOD_(BSTR, GetTrackCodecInfoURL)(UINT aTrackIdx) = 0; - STDMETHOD_(BSTR, GetTrackCodecDownloadURL)(UINT aTrackIdx) = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +enum TrackType { + TypeVideo = 1, + TypeAudio = 2, + TypeComplex = 3, + TypeLogo = 0x10, + TypeSubtitle = 0x11, + TypeControl = 0x20 +}; + +#pragma pack(push, 1) + +struct TrackElement { + WORD Size; // Size of this structure + BYTE Type; // See TrackType + BOOL FlagDefault; // Set if the track is the default for its TrackType. + BOOL FlagForced; // Set if that track MUST be used during playback. + BOOL FlagLacing; // Set if the track may contain blocks using lacing. + UINT MinCache; // The minimum number of frames a player should be able to cache during playback. + UINT MaxCache; // The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed. + CHAR Language[4]; // Specifies the language of the track, in the ISO-639-2 form. (end with '\0') +}; + +struct TrackExtendedInfoVideo { + WORD Size; // Size of this structure + BOOL Interlaced; // Set if the video is interlaced. + UINT PixelWidth; // Width of the encoded video frames in pixels. + UINT PixelHeight; // Height of the encoded video frames in pixels. + UINT DisplayWidth; // Width of the video frames to display. + UINT DisplayHeight; // Height of the video frames to display. + BYTE DisplayUnit; // Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches). + BYTE AspectRatioType; // Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed). +}; + +struct TrackExtendedInfoAudio { + WORD Size; // Size of this structure + float SamplingFreq; // Sampling frequency in Hz. + float OutputSamplingFrequency; // Real output sampling frequency in Hz (used for SBR techniques). + UINT Channels; // Numbers of channels in the track. + UINT BitDepth; // Bits per sample, mostly used for PCM. +}; + +#pragma pack(pop) + +interface __declspec(uuid("03E98D51-DDE7-43aa-B70C-42EF84A3A23D")) + ITrackInfo : + public IUnknown +{ + STDMETHOD_(UINT, GetTrackCount)() = 0; + + // \param aTrackIdx the track index (from 0 to GetTrackCount()-1) + STDMETHOD_(BOOL, GetTrackInfo)(UINT aTrackIdx, struct TrackElement* pStructureToFill) = 0; + + // Get an extended information struct relative to the track type + STDMETHOD_(BOOL, GetTrackExtendedInfo)(UINT aTrackIdx, void* pStructureToFill) = 0; + + STDMETHOD_(BSTR, GetTrackCodecID)(UINT aTrackIdx) = 0; + STDMETHOD_(BSTR, GetTrackName)(UINT aTrackIdx) = 0; + STDMETHOD_(BSTR, GetTrackCodecName)(UINT aTrackIdx) = 0; + STDMETHOD_(BSTR, GetTrackCodecInfoURL)(UINT aTrackIdx) = 0; + STDMETHOD_(BSTR, GetTrackCodecDownloadURL)(UINT aTrackIdx) = 0; +}; diff --git a/include/avisynth/avisynth1.h b/include/avisynth/avisynth1.h index 3a2ef0f0174..937a9bbf75d 100644 --- a/include/avisynth/avisynth1.h +++ b/include/avisynth/avisynth1.h @@ -1,414 +1,414 @@ -// Avisynth v1.0 beta. Copyright 2000 Ben Rudiak-Gould. -// http://www.math.berkeley.edu/~benrg/avisynth.html - -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit -// http://www.gnu.org/copyleft/gpl.html . - - -#pragma once - -#ifdef _MSC_VER - #include -#else - #define _ASSERTE(x) assert(x) - #include -#endif - - -enum { AVISYNTH_INTERFACE_VERSION = 1 }; - - -// I had problems with Premiere wanting 1-byte alignment for its structures, -// so I now set the Avisynth struct alignment explicitly here. -#pragma pack(push,8) - - -// The VideoInfo struct holds global information about a clip (i.e. -// information that does not depend on the frame number). The GetVideoInfo -// method in IClip returns this struct. - -struct VideoInfo { - int width, height; // width=0 means no video - unsigned fps_numerator, fps_denominator; - int num_frames; - enum { UNKNOWN=0, BGR24=0x13, BGR32=0x14, YUY2=0x22 }; - unsigned char pixel_type; - bool field_based; - - int audio_samples_per_second; // 0 means no audio - int num_audio_samples; - bool stereo, sixteen_bit; - - // useful functions of the above - bool HasVideo() const { return !!width; } - bool HasAudio() const { return !!audio_samples_per_second; } - bool IsRGB() const { return !!(pixel_type&0x10); } - bool IsRGB24() const { return pixel_type == BGR24; } - bool IsRGB32() const { return pixel_type == BGR32; } - bool IsYUV() const { return !!(pixel_type&0x20); } - bool IsYUY2() const { return pixel_type == YUY2; } - int BytesFromPixels(int pixels) const { return pixels * (pixel_type&7); } - int RowSize() const { return BytesFromPixels(width); } - int BitsPerPixel() const { return (pixel_type&7) * 8; } - int BMPSize() const { return height * ((RowSize()+3) & -4); } - int AudioSamplesFromFrames(int frames) const { return int(__int64(frames) * audio_samples_per_second * fps_denominator / fps_numerator); } - int FramesFromAudioSamples(int samples) const { return int(__int64(samples) * fps_numerator / fps_denominator / audio_samples_per_second); } - int AudioSamplesFromBytes(int bytes) const { return bytes >> (stereo + sixteen_bit); } - int BytesFromAudioSamples(int samples) const { return samples << (stereo + sixteen_bit); } - int BytesPerAudioSample() const { return BytesFromAudioSamples(1); } - - // useful mutator - void SetFPS(unsigned numerator, unsigned denominator) { - unsigned x=numerator, y=denominator; - while (y) { // find gcd - unsigned t = x%y; x = y; y = t; - } - fps_numerator = numerator/x; - fps_denominator = denominator/x; - } -}; - - -// VideoFrameBuffer holds information about a memory block which is used -// for video data. For efficiency, instances of this class are not deleted -// when the refcount reaches zero; instead they're stored in a linked list -// to be reused. The instances are deleted when the corresponding AVS -// file is closed. - -class VideoFrameBuffer { - unsigned char* const data; - const int data_size; - // sequence_number is incremented every time the buffer is changed, so - // that stale views can tell they're no longer valid. - long sequence_number; - - friend class VideoFrame; - friend class Cache; - long refcount; - -public: - VideoFrameBuffer(int size); - VideoFrameBuffer(); - ~VideoFrameBuffer(); - - const unsigned char* GetReadPtr() const { return data; } - unsigned char* GetWritePtr() { ++sequence_number; return data; } - int GetDataSize() { return data_size; } - int GetSequenceNumber() { return sequence_number; } - int GetRefcount() { return refcount; } -}; - - -class IClip; -class PClip; -class PVideoFrame; -class IScriptEnvironment; -class AVSValue; - - -// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new -// is overloaded to recycle class instances. - -class VideoFrame { - int refcount; - VideoFrameBuffer* const vfb; - const int offset, pitch, row_size, height; - - friend class PVideoFrame; - void AddRef() { ++refcount; } - void Release() { if (refcount==1) --vfb->refcount; --refcount; } - - friend class ScriptEnvironment; - friend class Cache; - - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); - - void* operator new(size_t size); - -public: - int GetPitch() const { return pitch; } - int GetRowSize() const { return row_size; } - int GetHeight() const { return height; } - - // generally you shouldn't use these two - VideoFrameBuffer* GetFrameBuffer() const { return vfb; } - int GetOffset() const { return offset; } - - // in plugins use env->SubFrame() - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; - - const unsigned char* GetReadPtr() const { return vfb->GetReadPtr() + offset; } - - bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } - - unsigned char* GetWritePtr() const { - return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; - } - - ~VideoFrame() { --vfb->refcount; } -}; - - -// Base class for all filters. -class IClip { - friend class PClip; - friend class AVSValue; - int refcnt; - void AddRef() { ++refcnt; } - void Release() { if (!--refcnt) delete this; } -public: - IClip() : refcnt(0) {} - - virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } - - virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; - virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame - virtual void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) = 0; // start and count are in samples - virtual const VideoInfo& __stdcall GetVideoInfo() = 0; -#if defined(__INTEL_COMPILER) - virtual ~IClip() {} -#else - virtual __stdcall ~IClip() {} -#endif -}; - - -// smart pointer to IClip -class PClip { - - IClip* p; - - IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } - friend class AVSValue; - friend class VideoFrame; - - void Init(IClip* x) { - if (x) x->AddRef(); - p=x; - } - void Set(IClip* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PClip() { p = 0; } - PClip(const PClip& x) { Init(x.p); } - PClip(IClip* x) { Init(x); } - void operator=(IClip* x) { Set(x); } - void operator=(const PClip& x) { Set(x.p); } - - IClip* operator->() const { return p; } - - // useful in conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PClip() { if (p) p->Release(); } -}; - - -// smart pointer to VideoFrame -class PVideoFrame { - - VideoFrame* p; - - void Init(VideoFrame* x) { - if (x) x->AddRef(); - p=x; - } - void Set(VideoFrame* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PVideoFrame() { p = 0; } - PVideoFrame(const PVideoFrame& x) { Init(x.p); } - PVideoFrame(VideoFrame* x) { Init(x); } - void operator=(VideoFrame* x) { Set(x); } - void operator=(const PVideoFrame& x) { Set(x.p); } - - VideoFrame* operator->() const { return p; } - - // for conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PVideoFrame() { if (p) p->Release(); } -}; - - -class AVSValue { -public: - - AVSValue() { type = 'v'; } - AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } - AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } - AVSValue(bool b) { type = 'b'; boolean = b; } - AVSValue(int i) { type = 'i'; integer = i; } - AVSValue(float f) { type = 'f'; floating_pt = f; } - AVSValue(double f) { type = 'f'; floating_pt = float(f); } - AVSValue(const char* s) { type = 's'; string = s; } - AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } - AVSValue(const AVSValue& v) { Assign(&v, true); } - - ~AVSValue() { if (IsClip() && clip) clip->Release(); } - AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } - - // Note that we transparently allow 'int' to be treated as 'float'. - // There are no int<->bool conversions, though. - - bool Defined() const { return type != 'v'; } - bool IsClip() const { return type == 'c'; } - bool IsBool() const { return type == 'b'; } - bool IsInt() const { return type == 'i'; } - bool IsFloat() const { return type == 'f' || type == 'i'; } - bool IsString() const { return type == 's'; } - bool IsArray() const { return type == 'a'; } - - PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } - bool AsBool() const { _ASSERTE(IsBool()); return boolean; } - int AsInt() const { _ASSERTE(IsInt()); return integer; } - const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } - double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } - - bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } - int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } - double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } - const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } - - int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } - const AVSValue& operator[](int index) const { - _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) - src->clip->AddRef(); - if (!init && IsClip() && clip) - clip->Release(); - // make sure this copies the whole struct! - ((__int32*)this)[0] = ((__int32*)src)[0]; - ((__int32*)this)[1] = ((__int32*)src)[1]; - } -}; - - -// instantiable null filter -class GenericVideoFilter : public IClip { -protected: - PClip child; - VideoInfo vi; -public: - GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } - void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } - const VideoInfo& __stdcall GetVideoInfo() { return vi; } - bool __stdcall GetParity(int n) { return child->GetParity(n); } -}; - - -class AvisynthError /* exception */ { -public: - const char* const msg; - AvisynthError(const char* _msg) : msg(_msg) {} -}; - - -// For GetCPUFlags. These are the same as in VirtualDub. -enum { - CPUF_FORCE = 0x01, - CPUF_FPU = 0x02, - CPUF_MMX = 0x04, - CPUF_INTEGER_SSE = 0x08, // Athlon MMX extensions or Intel SSE - CPUF_SSE = 0x10, // Full SSE (PIII) - CPUF_SSE2 = 0x20, // (PIV) - CPUF_3DNOW = 0x40, - CPUF_3DNOW_EXT = 0x80, // Athlon 3DNow! extensions -}; - - -class IScriptEnvironment { -public: -#if defined(__INTEL_COMPILER) - virtual ~IScriptEnvironment() {} -#else - virtual __stdcall ~IScriptEnvironment() {} -#endif - - virtual /*static*/ long __stdcall GetCPUFlags() = 0; - - virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; - virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; - // note: val is really a va_list; I hope everyone typedefs va_list to a pointer - virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; - - __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; - - class NotFound /*exception*/ {}; // thrown by Invoke and GetVar - - typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); - - virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; - virtual bool __stdcall FunctionExists(const char* name) = 0; - virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; - - virtual AVSValue __stdcall GetVar(const char* name) = 0; - virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; - virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; - - virtual void __stdcall PushContext(int level=0) = 0; - virtual void __stdcall PopContext() = 0; - - // align should be 4 or 8 - virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=8) = 0; - - virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; - - virtual /*static*/ void __stdcall BitBlt(unsigned char* dstp, int dst_pitch, const unsigned char* srcp, int src_pitch, int row_size, int height) = 0; - - typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); - virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; - - virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; - - virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; -}; - - -// avisynth.dll exports this; it's a way to use it as a library, without -// writing an AVS script or without going through AVIFile. -IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); - - -#pragma pack(pop) - +// Avisynth v1.0 beta. Copyright 2000 Ben Rudiak-Gould. +// http://www.math.berkeley.edu/~benrg/avisynth.html + +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . + + +#pragma once + +#ifdef _MSC_VER + #include +#else + #define _ASSERTE(x) assert(x) + #include +#endif + + +enum { AVISYNTH_INTERFACE_VERSION = 1 }; + + +// I had problems with Premiere wanting 1-byte alignment for its structures, +// so I now set the Avisynth struct alignment explicitly here. +#pragma pack(push,8) + + +// The VideoInfo struct holds global information about a clip (i.e. +// information that does not depend on the frame number). The GetVideoInfo +// method in IClip returns this struct. + +struct VideoInfo { + int width, height; // width=0 means no video + unsigned fps_numerator, fps_denominator; + int num_frames; + enum { UNKNOWN=0, BGR24=0x13, BGR32=0x14, YUY2=0x22 }; + unsigned char pixel_type; + bool field_based; + + int audio_samples_per_second; // 0 means no audio + int num_audio_samples; + bool stereo, sixteen_bit; + + // useful functions of the above + bool HasVideo() const { return !!width; } + bool HasAudio() const { return !!audio_samples_per_second; } + bool IsRGB() const { return !!(pixel_type&0x10); } + bool IsRGB24() const { return pixel_type == BGR24; } + bool IsRGB32() const { return pixel_type == BGR32; } + bool IsYUV() const { return !!(pixel_type&0x20); } + bool IsYUY2() const { return pixel_type == YUY2; } + int BytesFromPixels(int pixels) const { return pixels * (pixel_type&7); } + int RowSize() const { return BytesFromPixels(width); } + int BitsPerPixel() const { return (pixel_type&7) * 8; } + int BMPSize() const { return height * ((RowSize()+3) & -4); } + int AudioSamplesFromFrames(int frames) const { return int(__int64(frames) * audio_samples_per_second * fps_denominator / fps_numerator); } + int FramesFromAudioSamples(int samples) const { return int(__int64(samples) * fps_numerator / fps_denominator / audio_samples_per_second); } + int AudioSamplesFromBytes(int bytes) const { return bytes >> (stereo + sixteen_bit); } + int BytesFromAudioSamples(int samples) const { return samples << (stereo + sixteen_bit); } + int BytesPerAudioSample() const { return BytesFromAudioSamples(1); } + + // useful mutator + void SetFPS(unsigned numerator, unsigned denominator) { + unsigned x=numerator, y=denominator; + while (y) { // find gcd + unsigned t = x%y; x = y; y = t; + } + fps_numerator = numerator/x; + fps_denominator = denominator/x; + } +}; + + +// VideoFrameBuffer holds information about a memory block which is used +// for video data. For efficiency, instances of this class are not deleted +// when the refcount reaches zero; instead they're stored in a linked list +// to be reused. The instances are deleted when the corresponding AVS +// file is closed. + +class VideoFrameBuffer { + unsigned char* const data; + const int data_size; + // sequence_number is incremented every time the buffer is changed, so + // that stale views can tell they're no longer valid. + long sequence_number; + + friend class VideoFrame; + friend class Cache; + long refcount; + +public: + VideoFrameBuffer(int size); + VideoFrameBuffer(); + ~VideoFrameBuffer(); + + const unsigned char* GetReadPtr() const { return data; } + unsigned char* GetWritePtr() { ++sequence_number; return data; } + int GetDataSize() { return data_size; } + int GetSequenceNumber() { return sequence_number; } + int GetRefcount() { return refcount; } +}; + + +class IClip; +class PClip; +class PVideoFrame; +class IScriptEnvironment; +class AVSValue; + + +// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new +// is overloaded to recycle class instances. + +class VideoFrame { + int refcount; + VideoFrameBuffer* const vfb; + const int offset, pitch, row_size, height; + + friend class PVideoFrame; + void AddRef() { ++refcount; } + void Release() { if (refcount==1) --vfb->refcount; --refcount; } + + friend class ScriptEnvironment; + friend class Cache; + + VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); + + void* operator new(size_t size); + +public: + int GetPitch() const { return pitch; } + int GetRowSize() const { return row_size; } + int GetHeight() const { return height; } + + // generally you shouldn't use these two + VideoFrameBuffer* GetFrameBuffer() const { return vfb; } + int GetOffset() const { return offset; } + + // in plugins use env->SubFrame() + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; + + const unsigned char* GetReadPtr() const { return vfb->GetReadPtr() + offset; } + + bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } + + unsigned char* GetWritePtr() const { + return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; + } + + ~VideoFrame() { --vfb->refcount; } +}; + + +// Base class for all filters. +class IClip { + friend class PClip; + friend class AVSValue; + int refcnt; + void AddRef() { ++refcnt; } + void Release() { if (!--refcnt) delete this; } +public: + IClip() : refcnt(0) {} + + virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } + + virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; + virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame + virtual void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) = 0; // start and count are in samples + virtual const VideoInfo& __stdcall GetVideoInfo() = 0; +#if defined(__INTEL_COMPILER) + virtual ~IClip() {} +#else + virtual __stdcall ~IClip() {} +#endif +}; + + +// smart pointer to IClip +class PClip { + + IClip* p; + + IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } + friend class AVSValue; + friend class VideoFrame; + + void Init(IClip* x) { + if (x) x->AddRef(); + p=x; + } + void Set(IClip* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PClip() { p = 0; } + PClip(const PClip& x) { Init(x.p); } + PClip(IClip* x) { Init(x); } + void operator=(IClip* x) { Set(x); } + void operator=(const PClip& x) { Set(x.p); } + + IClip* operator->() const { return p; } + + // useful in conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PClip() { if (p) p->Release(); } +}; + + +// smart pointer to VideoFrame +class PVideoFrame { + + VideoFrame* p; + + void Init(VideoFrame* x) { + if (x) x->AddRef(); + p=x; + } + void Set(VideoFrame* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PVideoFrame() { p = 0; } + PVideoFrame(const PVideoFrame& x) { Init(x.p); } + PVideoFrame(VideoFrame* x) { Init(x); } + void operator=(VideoFrame* x) { Set(x); } + void operator=(const PVideoFrame& x) { Set(x.p); } + + VideoFrame* operator->() const { return p; } + + // for conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PVideoFrame() { if (p) p->Release(); } +}; + + +class AVSValue { +public: + + AVSValue() { type = 'v'; } + AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } + AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } + AVSValue(bool b) { type = 'b'; boolean = b; } + AVSValue(int i) { type = 'i'; integer = i; } + AVSValue(float f) { type = 'f'; floating_pt = f; } + AVSValue(double f) { type = 'f'; floating_pt = float(f); } + AVSValue(const char* s) { type = 's'; string = s; } + AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } + AVSValue(const AVSValue& v) { Assign(&v, true); } + + ~AVSValue() { if (IsClip() && clip) clip->Release(); } + AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } + + // Note that we transparently allow 'int' to be treated as 'float'. + // There are no int<->bool conversions, though. + + bool Defined() const { return type != 'v'; } + bool IsClip() const { return type == 'c'; } + bool IsBool() const { return type == 'b'; } + bool IsInt() const { return type == 'i'; } + bool IsFloat() const { return type == 'f' || type == 'i'; } + bool IsString() const { return type == 's'; } + bool IsArray() const { return type == 'a'; } + + PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } + bool AsBool() const { _ASSERTE(IsBool()); return boolean; } + int AsInt() const { _ASSERTE(IsInt()); return integer; } + const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } + double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } + + bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } + int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } + double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } + const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } + + int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } + const AVSValue& operator[](int index) const { + _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) + src->clip->AddRef(); + if (!init && IsClip() && clip) + clip->Release(); + // make sure this copies the whole struct! + ((__int32*)this)[0] = ((__int32*)src)[0]; + ((__int32*)this)[1] = ((__int32*)src)[1]; + } +}; + + +// instantiable null filter +class GenericVideoFilter : public IClip { +protected: + PClip child; + VideoInfo vi; +public: + GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } + void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } + const VideoInfo& __stdcall GetVideoInfo() { return vi; } + bool __stdcall GetParity(int n) { return child->GetParity(n); } +}; + + +class AvisynthError /* exception */ { +public: + const char* const msg; + AvisynthError(const char* _msg) : msg(_msg) {} +}; + + +// For GetCPUFlags. These are the same as in VirtualDub. +enum { + CPUF_FORCE = 0x01, + CPUF_FPU = 0x02, + CPUF_MMX = 0x04, + CPUF_INTEGER_SSE = 0x08, // Athlon MMX extensions or Intel SSE + CPUF_SSE = 0x10, // Full SSE (PIII) + CPUF_SSE2 = 0x20, // (PIV) + CPUF_3DNOW = 0x40, + CPUF_3DNOW_EXT = 0x80, // Athlon 3DNow! extensions +}; + + +class IScriptEnvironment { +public: +#if defined(__INTEL_COMPILER) + virtual ~IScriptEnvironment() {} +#else + virtual __stdcall ~IScriptEnvironment() {} +#endif + + virtual /*static*/ long __stdcall GetCPUFlags() = 0; + + virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; + virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; + // note: val is really a va_list; I hope everyone typedefs va_list to a pointer + virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; + + __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; + + class NotFound /*exception*/ {}; // thrown by Invoke and GetVar + + typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); + + virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; + virtual bool __stdcall FunctionExists(const char* name) = 0; + virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; + + virtual AVSValue __stdcall GetVar(const char* name) = 0; + virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; + virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; + + virtual void __stdcall PushContext(int level=0) = 0; + virtual void __stdcall PopContext() = 0; + + // align should be 4 or 8 + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=8) = 0; + + virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; + + virtual /*static*/ void __stdcall BitBlt(unsigned char* dstp, int dst_pitch, const unsigned char* srcp, int src_pitch, int row_size, int height) = 0; + + typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); + virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; + + virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; + + virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; +}; + + +// avisynth.dll exports this; it's a way to use it as a library, without +// writing an AVS script or without going through AVIFile. +IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); + + +#pragma pack(pop) + diff --git a/include/avisynth/avisynth25.h b/include/avisynth/avisynth25.h index 85b9f1afd1c..c8d58cb49c5 100644 --- a/include/avisynth/avisynth25.h +++ b/include/avisynth/avisynth25.h @@ -1,795 +1,795 @@ -// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. -// http://www.avisynth.org - -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit -// http://www.gnu.org/copyleft/gpl.html . -// -// Linking Avisynth statically or dynamically with other modules is making a -// combined work based on Avisynth. Thus, the terms and conditions of the GNU -// General Public License cover the whole combination. -// -// As a special exception, the copyright holders of Avisynth give you -// permission to link Avisynth with independent modules that communicate with -// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license -// terms of these independent modules, and to copy and distribute the -// resulting combined work under terms of your choice, provided that -// every copy of the combined work is accompanied by a complete copy of -// the source code of Avisynth (the version of Avisynth used to produce the -// combined work), being distributed under the terms of the GNU General -// Public License plus this exception. An independent module is a module -// which is not derived from or based on Avisynth, such as 3rd-party filters, -// import and export plugins, or graphical user interfaces. - - - - -#ifndef __AVISYNTH_H__ -#define __AVISYNTH_H__ - -enum { AVISYNTH_INTERFACE_VERSION = 3 }; - - -/* Define all types necessary for interfacing with avisynth.dll - Moved from internal.h */ - -// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc. -#include - -#if (_MSC_VER >= 1400) -extern "C" LONG __cdecl _InterlockedIncrement(LONG volatile * pn); -extern "C" LONG __cdecl _InterlockedDecrement(LONG volatile * pn); -#pragma intrinsic(_InterlockedIncrement) -#pragma intrinsic(_InterlockedDecrement) -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#endif - -// COM interface macros -#include - - -// Raster types used by VirtualDub & Avisynth -#define in64 (__int64)(unsigned short) -typedef unsigned long Pixel; // this will break on 64-bit machines! -typedef unsigned long Pixel32; -typedef unsigned char Pixel8; -typedef long PixCoord; -typedef long PixDim; -typedef long PixOffset; - - -/* Compiler-specific crap */ - -// Tell MSVC to stop precompiling here -#ifdef _MSC_VER - #pragma hdrstop -#endif - -// Set up debugging macros for MS compilers; for others, step down to the -// standard interface -#ifdef _MSC_VER - #include -#else - #define _RPT0(a,b) ((void)0) - #define _RPT1(a,b,c) ((void)0) - #define _RPT2(a,b,c,d) ((void)0) - #define _RPT3(a,b,c,d,e) ((void)0) - #define _RPT4(a,b,c,d,e,f) ((void)0) - - #define _ASSERTE(x) assert(x) - #include -#endif - - - -// I had problems with Premiere wanting 1-byte alignment for its structures, -// so I now set the Avisynth struct alignment explicitly here. -#pragma pack(push,8) - -#define FRAME_ALIGN 16 -// Default frame alignment is 16 bytes, to help P4, when using SSE2 - -// The VideoInfo struct holds global information about a clip (i.e. -// information that does not depend on the frame number). The GetVideoInfo -// method in IClip returns this struct. - -// Audio Sample information -typedef float SFLOAT; - -enum {SAMPLE_INT8 = 1<<0, - SAMPLE_INT16 = 1<<1, - SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware. - SAMPLE_INT32 = 1<<3, - SAMPLE_FLOAT = 1<<4}; - -enum { - PLANAR_Y=1<<0, - PLANAR_U=1<<1, - PLANAR_V=1<<2, - PLANAR_ALIGNED=1<<3, - PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED, - PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED, - PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED - }; - -class AvisynthError /* exception */ { -public: - const char* const msg; - AvisynthError(const char* _msg) : msg(_msg) {} -}; - -struct VideoInfo { - int width, height; // width=0 means no video - unsigned fps_numerator, fps_denominator; - int num_frames; - // This is more extensible than previous versions. More properties can be added seeminglesly. - - // Colorspace properties. - enum { - CS_BGR = 1<<28, - CS_YUV = 1<<29, - CS_INTERLEAVED = 1<<30, - CS_PLANAR = 1<<31 - }; - - // Specific colorformats - enum { CS_UNKNOWN = 0, - CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED, - CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED, - CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED, - CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, 4:2:0 planar - CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, 4:2:0 planar - CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above - }; - int pixel_type; // changed to int as of 2.5 - - - int audio_samples_per_second; // 0 means no audio - int sample_type; // as of 2.5 - __int64 num_audio_samples; // changed as of 2.5 - int nchannels; // as of 2.5 - - // Imagetype properties - - int image_type; - - enum { - IT_BFF = 1<<0, - IT_TFF = 1<<1, - IT_FIELDBASED = 1<<2 - }; - - // useful functions of the above - bool HasVideo() const { return (width!=0); } - bool HasAudio() const { return (audio_samples_per_second!=0); } - bool IsRGB() const { return !!(pixel_type&CS_BGR); } - bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties - bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; } - bool IsYUV() const { return !!(pixel_type&CS_YUV ); } - bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; } - bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); } - bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); } - bool Is(int property) const { return ((pixel_type & property)==property ); } - bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); } - bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); } - bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); } - bool IsBFF() const { return !!(image_type & IT_BFF); } - bool IsTFF() const { return !!(image_type & IT_TFF); } - - bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this - int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes - int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images - int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); } - __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; } - int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; } - __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; } - __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); } - int AudioChannels() const { return HasAudio() ? nchannels : 0; } - int SampleType() const{ return sample_type;} - bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);} - int SamplesPerSecond() const { return audio_samples_per_second; } - int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();} - void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; } - void Set(int property) { image_type|=property; } - void Clear(int property) { image_type&=~property; } - - int BitsPerPixel() const { - switch (pixel_type) { - case CS_BGR24: - return 24; - case CS_BGR32: - return 32; - case CS_YUY2: - return 16; - case CS_YV12: - case CS_I420: - return 12; - default: - return 0; - } - } - - int BytesPerChannelSample() const { - switch (sample_type) { - case SAMPLE_INT8: - return sizeof(signed char); - case SAMPLE_INT16: - return sizeof(signed short); - case SAMPLE_INT24: - return 3; - case SAMPLE_INT32: - return sizeof(signed int); - case SAMPLE_FLOAT: - return sizeof(SFLOAT); - default: - _ASSERTE("Sample type not recognized!"); - return 0; - } - } - - // useful mutator - void SetFPS(unsigned numerator, unsigned denominator) { - if ((numerator == 0) || (denominator == 0)) { - fps_numerator = 0; - fps_denominator = 1; - } - else { - unsigned x=numerator, y=denominator; - while (y) { // find gcd - unsigned t = x%y; x = y; y = t; - } - fps_numerator = numerator/x; - fps_denominator = denominator/x; - } - } - - // Range protected multiply-divide of FPS - void MulDivFPS(unsigned multiplier, unsigned divisor) { - unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier); - unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor); - - unsigned __int64 x=numerator, y=denominator; - while (y) { // find gcd - unsigned __int64 t = x%y; x = y; y = t; - } - numerator /= x; // normalize - denominator /= x; - - unsigned __int64 temp = numerator | denominator; // Just looking top bit - unsigned u = 0; - while (temp & 0xffffffff80000000ull) { // or perhaps > 16777216*2 - temp = Int64ShrlMod32(temp, 1); - u++; - } - if (u) { // Scale to fit - const unsigned round = 1 << (u-1); - SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u), - (unsigned)Int64ShrlMod32(denominator + round, u) ); - } - else { - fps_numerator = (unsigned)numerator; - fps_denominator = (unsigned)denominator; - } - } - - // Test for same colorspace - bool IsSameColorspace(const VideoInfo& vi) const { - if (vi.pixel_type == pixel_type) return TRUE; - if (IsYV12() && vi.IsYV12()) return TRUE; - return FALSE; - } - -}; - - - - -// VideoFrameBuffer holds information about a memory block which is used -// for video data. For efficiency, instances of this class are not deleted -// when the refcount reaches zero; instead they're stored in a linked list -// to be reused. The instances are deleted when the corresponding AVS -// file is closed. - -class VideoFrameBuffer { - BYTE* const data; - const int data_size; - // sequence_number is incremented every time the buffer is changed, so - // that stale views can tell they're no longer valid. - volatile long sequence_number; - - friend class VideoFrame; - friend class Cache; - friend class CacheMT; - friend class ScriptEnvironment; - volatile long refcount; - -public: - VideoFrameBuffer(int size); - VideoFrameBuffer(); - ~VideoFrameBuffer(); - - const BYTE* GetReadPtr() const { return data; } - BYTE* GetWritePtr() { InterlockedIncrement(&sequence_number); return data; } - int GetDataSize() { return data_size; } - int GetSequenceNumber() { return sequence_number; } - int GetRefcount() { return refcount; } -}; - - -class IClip; -class PClip; -class PVideoFrame; -class IScriptEnvironment; -class AVSValue; - - -// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new -// is overloaded to recycle class instances. - -class VideoFrame { - volatile long refcount; - VideoFrameBuffer* const vfb; - const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. - - friend class PVideoFrame; - void AddRef() { InterlockedIncrement(&refcount); } - void Release() { VideoFrameBuffer* vfb_local = vfb; if (!InterlockedDecrement(&refcount)) InterlockedDecrement(&vfb_local->refcount); } - - friend class Cache; - friend class CacheMT; - friend class ScriptEnvironment; - - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV); - -#ifndef _WIN64 - void* operator new(unsigned size); -#else - void* operator new(size_t size); -#endif -// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard! -public: - int GetPitch() const { return pitch; } - int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; } - int GetRowSize() const { return row_size; } - __declspec(noinline) int GetRowSize(int plane) const { - switch (plane) { - case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0; - case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED: - if (pitchUV) { - int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize - if (r<=pitchUV) - return r; - return row_size>>1; - } else return 0; - case PLANAR_Y_ALIGNED: - int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize - if (r<=pitch) - return r; - return row_size; - } - return row_size; } - int GetHeight() const { return height; } - int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; } - - // generally you shouldn't use these three - VideoFrameBuffer* GetFrameBuffer() const { return vfb; } - int GetOffset() const { return offset; } - int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; } - - // in plugins use env->SubFrame() - //If you really want to use these remember to increase vfb->refcount before calling and decrement it afterwards. - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const; - - - const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; } - const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); } - - bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } - - BYTE* GetWritePtr() const { - if (vfb->GetRefcount()>1) { - _ASSERT(FALSE); - //throw AvisynthError("Internal Error - refcount was more than one!"); - } - return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; - } - - BYTE* GetWritePtr(int plane) const { - if (plane==PLANAR_Y) { - if (vfb->GetRefcount()>1) { - _ASSERT(FALSE); -// throw AvisynthError("Internal Error - refcount was more than one!"); - } - return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0; - } - return vfb->data + GetOffset(plane); - } - - ~VideoFrame() { VideoFrameBuffer* vfb_local = vfb; if (InterlockedDecrement(&refcount) >= 0) InterlockedDecrement(&vfb_local->refcount); } -}; - -enum { - CACHE_NOTHING=0, - CACHE_RANGE=1, - CACHE_ALL=2, - CACHE_AUDIO=3, - CACHE_AUDIO_NONE=4, - CACHE_AUDIO_AUTO=5 - }; - -// Base class for all filters. -class IClip { - friend class PClip; - friend class AVSValue; - volatile long refcnt; - void AddRef() { InterlockedIncrement(&refcnt); } - void Release() { if (!InterlockedDecrement(&refcnt)) delete this; } -public: - IClip() : refcnt(0) {} - - virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } - - virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; - virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame - virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples - virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter. - virtual const VideoInfo& __stdcall GetVideoInfo() = 0; -#if defined(__INTEL_COMPILER) - virtual ~IClip() {} -#else - virtual __stdcall ~IClip() {} -#endif -}; - - -// smart pointer to IClip -class PClip { - - IClip* p; - - IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } - friend class AVSValue; - friend class VideoFrame; - - void Init(IClip* x) { - if (x) x->AddRef(); - p=x; - } - void Set(IClip* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PClip() { p = 0; } - PClip(const PClip& x) { Init(x.p); } - PClip(IClip* x) { Init(x); } - void operator=(IClip* x) { Set(x); } - void operator=(const PClip& x) { Set(x.p); } - - IClip* operator->() const { return p; } - - // useful in conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PClip() { if (p) p->Release(); } -}; - - -// smart pointer to VideoFrame -class PVideoFrame { - - VideoFrame* p; - - void Init(VideoFrame* x) { - if (x) x->AddRef(); - p=x; - } - void Set(VideoFrame* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PVideoFrame() { p = 0; } - PVideoFrame(const PVideoFrame& x) { Init(x.p); } - PVideoFrame(VideoFrame* x) { Init(x); } - void operator=(VideoFrame* x) { Set(x); } - void operator=(const PVideoFrame& x) { Set(x.p); } - - VideoFrame* operator->() const { return p; } - - // for conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PVideoFrame() { if (p) p->Release();} -}; - - -class AVSValue { -public: - - AVSValue() { type = 'v'; } - AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } - AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } - AVSValue(bool b) { type = 'b'; boolean = b; } - AVSValue(int i) { type = 'i'; integer = i; } -// AVSValue(__int64 l) { type = 'l'; longlong = l; } - AVSValue(float f) { type = 'f'; floating_pt = f; } - AVSValue(double f) { type = 'f'; floating_pt = float(f); } - AVSValue(const char* s) { type = 's'; string = s; } - AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } - AVSValue(const AVSValue& v) { Assign(&v, true); } - - ~AVSValue() { if (IsClip() && clip) clip->Release(); } - AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } - - // Note that we transparently allow 'int' to be treated as 'float'. - // There are no int<->bool conversions, though. - - bool Defined() const { return type != 'v'; } - bool IsClip() const { return type == 'c'; } - bool IsBool() const { return type == 'b'; } - bool IsInt() const { return type == 'i'; } -// bool IsLong() const { return (type == 'l'|| type == 'i'); } - bool IsFloat() const { return type == 'f' || type == 'i'; } - bool IsString() const { return type == 's'; } - bool IsArray() const { return type == 'a'; } - - PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } - bool AsBool() const { _ASSERTE(IsBool()); return boolean; } - int AsInt() const { _ASSERTE(IsInt()); return integer; } -// int AsLong() const { _ASSERTE(IsLong()); return longlong; } - const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } - double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } - - bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } - int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } - double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } - const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } - - int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } - - const AVSValue& operator[](int index) const { - _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) - src->clip->AddRef(); - if (!init && IsClip() && clip) - clip->Release(); - // make sure this copies the whole struct! - /* UGH! what the- ? - ((__int32*)this)[0] = ((__int32*)src)[0]; - ((__int32*)this)[1] = ((__int32*)src)[1]; - */ - this->clip = src->clip; - this->type = src->type; - this->array_size = src->array_size; - } -}; - - -// instantiable null filter -class GenericVideoFilter : public IClip { -protected: - PClip child; - VideoInfo vi; -public: - GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } - void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } - const VideoInfo& __stdcall GetVideoInfo() { return vi; } - bool __stdcall GetParity(int n) { return child->GetParity(n); } - void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter. -}; - - - - - -/* Helper classes useful to plugin authors */ - -class AlignPlanar : public GenericVideoFilter -{ -public: - AlignPlanar(PClip _clip); - static PClip Create(PClip clip); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); -}; - - - -class FillBorder : public GenericVideoFilter -{ -public: - FillBorder(PClip _clip); - static PClip Create(PClip clip); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); -}; - - - -class ConvertAudio : public GenericVideoFilter -/** - * Helper class to convert audio to any format - **/ -{ -public: - ConvertAudio(PClip _clip, int prefered_format); - void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env); - void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache! - - static PClip Create(PClip clip, int sample_type, int prefered_type); - static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_8bit (AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_Any (AVSValue args, void*, IScriptEnvironment*); - virtual ~ConvertAudio(); - -private: - void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count); - void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count); - - __inline int Saturate_int8(float n); - __inline short Saturate_int16(float n); - __inline int Saturate_int24(float n); - __inline int Saturate_int32(float n); - - char src_format; - char dst_format; - int src_bps; - char *tempbuffer; - SFLOAT *floatbuffer; - int tempbuffer_size; -}; - - -// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. -enum { - /* slowest CPU to support extension */ - CPUF_FORCE = 0x01, // N/A - CPUF_FPU = 0x02, // 386/486DX - CPUF_MMX = 0x04, // P55C, K6, PII - CPUF_INTEGER_SSE = 0x08, // PIII, Athlon - CPUF_SSE = 0x10, // PIII, Athlon XP/MP - CPUF_SSE2 = 0x20, // PIV, Hammer - CPUF_3DNOW = 0x40, // K6-2 - CPUF_3DNOW_EXT = 0x80, // Athlon - CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which - // only Hammer will have anyway) - CPUF_SSE3 = 0x100, // PIV+, Hammer - CPUF_SSSE3 = 0x200, // prescott? - CPUF_SSE4 = 0x400, // penryn - CPUF_SSE4_2 = 0x800 // Core iX -}; - -//josh: changed these just bc winsdk defines them in BaseTsd.h -#define MAX_INT MAXINT32 -#define MIN_INT MININT32 // ::FIXME:: research why this is not 0x80000000 - - - -class IClipLocalStorage; - -class IScriptEnvironment { -public: -#if defined(__INTEL_COMPILER) - virtual ~IScriptEnvironment() {} -#else - virtual __stdcall ~IScriptEnvironment() {} -#endif - - virtual /*static*/ long __stdcall GetCPUFlags() = 0; - - virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; - virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; - // note: val is really a va_list; I hope everyone typedefs va_list to a pointer - virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; - - __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; - - class NotFound /*exception*/ {}; // thrown by Invoke and GetVar - - typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); - - virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; - virtual bool __stdcall FunctionExists(const char* name) = 0; - virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; - - virtual AVSValue __stdcall GetVar(const char* name) = 0; - virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; - virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; - - virtual void __stdcall PushContext(int level=0) = 0; - virtual void __stdcall PopContext() = 0; - - // align should be 4 or 8 - virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0; - - virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; - - virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; - - typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); - virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; - - virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; - - virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; - - virtual int __stdcall SetMemoryMax(int mem) = 0; - - virtual int __stdcall SetWorkingDir(const char * newdir) = 0; - - virtual void* __stdcall ManageCache(int key, void* data) = 0; - - enum PlanarChromaAlignmentMode { - PlanarChromaAlignmentOff, - PlanarChromaAlignmentOn, - PlanarChromaAlignmentTest }; - - virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0; - - virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; - - virtual void __stdcall SetMTMode(int mode,int threads,bool temporary)=0; - virtual int __stdcall GetMTMode(bool return_nthreads)=0; - - virtual IClipLocalStorage* __stdcall AllocClipLocalStorage()=0; - - virtual void __stdcall SaveClipLocalStorage()=0; - virtual void __stdcall RestoreClipLocalStorage()=0; -}; - - -// avisynth.dll exports this; it's a way to use it as a library, without -// writing an AVS script or without going through AVIFile. -IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); - - -#pragma pack(pop) - -#endif //__AVISYNTH_H__ +// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. +// http://www.avisynth.org + +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// Linking Avisynth statically or dynamically with other modules is making a +// combined work based on Avisynth. Thus, the terms and conditions of the GNU +// General Public License cover the whole combination. +// +// As a special exception, the copyright holders of Avisynth give you +// permission to link Avisynth with independent modules that communicate with +// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license +// terms of these independent modules, and to copy and distribute the +// resulting combined work under terms of your choice, provided that +// every copy of the combined work is accompanied by a complete copy of +// the source code of Avisynth (the version of Avisynth used to produce the +// combined work), being distributed under the terms of the GNU General +// Public License plus this exception. An independent module is a module +// which is not derived from or based on Avisynth, such as 3rd-party filters, +// import and export plugins, or graphical user interfaces. + + + + +#ifndef __AVISYNTH_H__ +#define __AVISYNTH_H__ + +enum { AVISYNTH_INTERFACE_VERSION = 3 }; + + +/* Define all types necessary for interfacing with avisynth.dll + Moved from internal.h */ + +// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc. +#include + +#if (_MSC_VER >= 1400) +extern "C" LONG __cdecl _InterlockedIncrement(LONG volatile * pn); +extern "C" LONG __cdecl _InterlockedDecrement(LONG volatile * pn); +#pragma intrinsic(_InterlockedIncrement) +#pragma intrinsic(_InterlockedDecrement) +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#endif + +// COM interface macros +#include + + +// Raster types used by VirtualDub & Avisynth +#define in64 (__int64)(unsigned short) +typedef unsigned long Pixel; // this will break on 64-bit machines! +typedef unsigned long Pixel32; +typedef unsigned char Pixel8; +typedef long PixCoord; +typedef long PixDim; +typedef long PixOffset; + + +/* Compiler-specific crap */ + +// Tell MSVC to stop precompiling here +#ifdef _MSC_VER + #pragma hdrstop +#endif + +// Set up debugging macros for MS compilers; for others, step down to the +// standard interface +#ifdef _MSC_VER + #include +#else + #define _RPT0(a,b) ((void)0) + #define _RPT1(a,b,c) ((void)0) + #define _RPT2(a,b,c,d) ((void)0) + #define _RPT3(a,b,c,d,e) ((void)0) + #define _RPT4(a,b,c,d,e,f) ((void)0) + + #define _ASSERTE(x) assert(x) + #include +#endif + + + +// I had problems with Premiere wanting 1-byte alignment for its structures, +// so I now set the Avisynth struct alignment explicitly here. +#pragma pack(push,8) + +#define FRAME_ALIGN 16 +// Default frame alignment is 16 bytes, to help P4, when using SSE2 + +// The VideoInfo struct holds global information about a clip (i.e. +// information that does not depend on the frame number). The GetVideoInfo +// method in IClip returns this struct. + +// Audio Sample information +typedef float SFLOAT; + +enum {SAMPLE_INT8 = 1<<0, + SAMPLE_INT16 = 1<<1, + SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware. + SAMPLE_INT32 = 1<<3, + SAMPLE_FLOAT = 1<<4}; + +enum { + PLANAR_Y=1<<0, + PLANAR_U=1<<1, + PLANAR_V=1<<2, + PLANAR_ALIGNED=1<<3, + PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED, + PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED, + PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED + }; + +class AvisynthError /* exception */ { +public: + const char* const msg; + AvisynthError(const char* _msg) : msg(_msg) {} +}; + +struct VideoInfo { + int width, height; // width=0 means no video + unsigned fps_numerator, fps_denominator; + int num_frames; + // This is more extensible than previous versions. More properties can be added seeminglesly. + + // Colorspace properties. + enum { + CS_BGR = 1<<28, + CS_YUV = 1<<29, + CS_INTERLEAVED = 1<<30, + CS_PLANAR = 1<<31 + }; + + // Specific colorformats + enum { CS_UNKNOWN = 0, + CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED, + CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED, + CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED, + CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, 4:2:0 planar + CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, 4:2:0 planar + CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above + }; + int pixel_type; // changed to int as of 2.5 + + + int audio_samples_per_second; // 0 means no audio + int sample_type; // as of 2.5 + __int64 num_audio_samples; // changed as of 2.5 + int nchannels; // as of 2.5 + + // Imagetype properties + + int image_type; + + enum { + IT_BFF = 1<<0, + IT_TFF = 1<<1, + IT_FIELDBASED = 1<<2 + }; + + // useful functions of the above + bool HasVideo() const { return (width!=0); } + bool HasAudio() const { return (audio_samples_per_second!=0); } + bool IsRGB() const { return !!(pixel_type&CS_BGR); } + bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties + bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; } + bool IsYUV() const { return !!(pixel_type&CS_YUV ); } + bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; } + bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); } + bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); } + bool Is(int property) const { return ((pixel_type & property)==property ); } + bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); } + bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); } + bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); } + bool IsBFF() const { return !!(image_type & IT_BFF); } + bool IsTFF() const { return !!(image_type & IT_TFF); } + + bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this + int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes + int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images + int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); } + __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; } + int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; } + __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; } + __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); } + int AudioChannels() const { return HasAudio() ? nchannels : 0; } + int SampleType() const{ return sample_type;} + bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);} + int SamplesPerSecond() const { return audio_samples_per_second; } + int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();} + void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; } + void Set(int property) { image_type|=property; } + void Clear(int property) { image_type&=~property; } + + int BitsPerPixel() const { + switch (pixel_type) { + case CS_BGR24: + return 24; + case CS_BGR32: + return 32; + case CS_YUY2: + return 16; + case CS_YV12: + case CS_I420: + return 12; + default: + return 0; + } + } + + int BytesPerChannelSample() const { + switch (sample_type) { + case SAMPLE_INT8: + return sizeof(signed char); + case SAMPLE_INT16: + return sizeof(signed short); + case SAMPLE_INT24: + return 3; + case SAMPLE_INT32: + return sizeof(signed int); + case SAMPLE_FLOAT: + return sizeof(SFLOAT); + default: + _ASSERTE("Sample type not recognized!"); + return 0; + } + } + + // useful mutator + void SetFPS(unsigned numerator, unsigned denominator) { + if ((numerator == 0) || (denominator == 0)) { + fps_numerator = 0; + fps_denominator = 1; + } + else { + unsigned x=numerator, y=denominator; + while (y) { // find gcd + unsigned t = x%y; x = y; y = t; + } + fps_numerator = numerator/x; + fps_denominator = denominator/x; + } + } + + // Range protected multiply-divide of FPS + void MulDivFPS(unsigned multiplier, unsigned divisor) { + unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier); + unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor); + + unsigned __int64 x=numerator, y=denominator; + while (y) { // find gcd + unsigned __int64 t = x%y; x = y; y = t; + } + numerator /= x; // normalize + denominator /= x; + + unsigned __int64 temp = numerator | denominator; // Just looking top bit + unsigned u = 0; + while (temp & 0xffffffff80000000ull) { // or perhaps > 16777216*2 + temp = Int64ShrlMod32(temp, 1); + u++; + } + if (u) { // Scale to fit + const unsigned round = 1 << (u-1); + SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u), + (unsigned)Int64ShrlMod32(denominator + round, u) ); + } + else { + fps_numerator = (unsigned)numerator; + fps_denominator = (unsigned)denominator; + } + } + + // Test for same colorspace + bool IsSameColorspace(const VideoInfo& vi) const { + if (vi.pixel_type == pixel_type) return TRUE; + if (IsYV12() && vi.IsYV12()) return TRUE; + return FALSE; + } + +}; + + + + +// VideoFrameBuffer holds information about a memory block which is used +// for video data. For efficiency, instances of this class are not deleted +// when the refcount reaches zero; instead they're stored in a linked list +// to be reused. The instances are deleted when the corresponding AVS +// file is closed. + +class VideoFrameBuffer { + BYTE* const data; + const int data_size; + // sequence_number is incremented every time the buffer is changed, so + // that stale views can tell they're no longer valid. + volatile long sequence_number; + + friend class VideoFrame; + friend class Cache; + friend class CacheMT; + friend class ScriptEnvironment; + volatile long refcount; + +public: + VideoFrameBuffer(int size); + VideoFrameBuffer(); + ~VideoFrameBuffer(); + + const BYTE* GetReadPtr() const { return data; } + BYTE* GetWritePtr() { InterlockedIncrement(&sequence_number); return data; } + int GetDataSize() { return data_size; } + int GetSequenceNumber() { return sequence_number; } + int GetRefcount() { return refcount; } +}; + + +class IClip; +class PClip; +class PVideoFrame; +class IScriptEnvironment; +class AVSValue; + + +// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new +// is overloaded to recycle class instances. + +class VideoFrame { + volatile long refcount; + VideoFrameBuffer* const vfb; + const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. + + friend class PVideoFrame; + void AddRef() { InterlockedIncrement(&refcount); } + void Release() { VideoFrameBuffer* vfb_local = vfb; if (!InterlockedDecrement(&refcount)) InterlockedDecrement(&vfb_local->refcount); } + + friend class Cache; + friend class CacheMT; + friend class ScriptEnvironment; + + VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); + VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV); + +#ifndef _WIN64 + void* operator new(unsigned size); +#else + void* operator new(size_t size); +#endif +// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard! +public: + int GetPitch() const { return pitch; } + int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; } + int GetRowSize() const { return row_size; } + __declspec(noinline) int GetRowSize(int plane) const { + switch (plane) { + case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0; + case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED: + if (pitchUV) { + int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize + if (r<=pitchUV) + return r; + return row_size>>1; + } else return 0; + case PLANAR_Y_ALIGNED: + int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize + if (r<=pitch) + return r; + return row_size; + } + return row_size; } + int GetHeight() const { return height; } + int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; } + + // generally you shouldn't use these three + VideoFrameBuffer* GetFrameBuffer() const { return vfb; } + int GetOffset() const { return offset; } + int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; } + + // in plugins use env->SubFrame() + //If you really want to use these remember to increase vfb->refcount before calling and decrement it afterwards. + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const; + + + const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; } + const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); } + + bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } + + BYTE* GetWritePtr() const { + if (vfb->GetRefcount()>1) { + _ASSERT(FALSE); + //throw AvisynthError("Internal Error - refcount was more than one!"); + } + return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; + } + + BYTE* GetWritePtr(int plane) const { + if (plane==PLANAR_Y) { + if (vfb->GetRefcount()>1) { + _ASSERT(FALSE); +// throw AvisynthError("Internal Error - refcount was more than one!"); + } + return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0; + } + return vfb->data + GetOffset(plane); + } + + ~VideoFrame() { VideoFrameBuffer* vfb_local = vfb; if (InterlockedDecrement(&refcount) >= 0) InterlockedDecrement(&vfb_local->refcount); } +}; + +enum { + CACHE_NOTHING=0, + CACHE_RANGE=1, + CACHE_ALL=2, + CACHE_AUDIO=3, + CACHE_AUDIO_NONE=4, + CACHE_AUDIO_AUTO=5 + }; + +// Base class for all filters. +class IClip { + friend class PClip; + friend class AVSValue; + volatile long refcnt; + void AddRef() { InterlockedIncrement(&refcnt); } + void Release() { if (!InterlockedDecrement(&refcnt)) delete this; } +public: + IClip() : refcnt(0) {} + + virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } + + virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; + virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame + virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples + virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter. + virtual const VideoInfo& __stdcall GetVideoInfo() = 0; +#if defined(__INTEL_COMPILER) + virtual ~IClip() {} +#else + virtual __stdcall ~IClip() {} +#endif +}; + + +// smart pointer to IClip +class PClip { + + IClip* p; + + IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } + friend class AVSValue; + friend class VideoFrame; + + void Init(IClip* x) { + if (x) x->AddRef(); + p=x; + } + void Set(IClip* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PClip() { p = 0; } + PClip(const PClip& x) { Init(x.p); } + PClip(IClip* x) { Init(x); } + void operator=(IClip* x) { Set(x); } + void operator=(const PClip& x) { Set(x.p); } + + IClip* operator->() const { return p; } + + // useful in conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PClip() { if (p) p->Release(); } +}; + + +// smart pointer to VideoFrame +class PVideoFrame { + + VideoFrame* p; + + void Init(VideoFrame* x) { + if (x) x->AddRef(); + p=x; + } + void Set(VideoFrame* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PVideoFrame() { p = 0; } + PVideoFrame(const PVideoFrame& x) { Init(x.p); } + PVideoFrame(VideoFrame* x) { Init(x); } + void operator=(VideoFrame* x) { Set(x); } + void operator=(const PVideoFrame& x) { Set(x.p); } + + VideoFrame* operator->() const { return p; } + + // for conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PVideoFrame() { if (p) p->Release();} +}; + + +class AVSValue { +public: + + AVSValue() { type = 'v'; } + AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } + AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } + AVSValue(bool b) { type = 'b'; boolean = b; } + AVSValue(int i) { type = 'i'; integer = i; } +// AVSValue(__int64 l) { type = 'l'; longlong = l; } + AVSValue(float f) { type = 'f'; floating_pt = f; } + AVSValue(double f) { type = 'f'; floating_pt = float(f); } + AVSValue(const char* s) { type = 's'; string = s; } + AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } + AVSValue(const AVSValue& v) { Assign(&v, true); } + + ~AVSValue() { if (IsClip() && clip) clip->Release(); } + AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } + + // Note that we transparently allow 'int' to be treated as 'float'. + // There are no int<->bool conversions, though. + + bool Defined() const { return type != 'v'; } + bool IsClip() const { return type == 'c'; } + bool IsBool() const { return type == 'b'; } + bool IsInt() const { return type == 'i'; } +// bool IsLong() const { return (type == 'l'|| type == 'i'); } + bool IsFloat() const { return type == 'f' || type == 'i'; } + bool IsString() const { return type == 's'; } + bool IsArray() const { return type == 'a'; } + + PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } + bool AsBool() const { _ASSERTE(IsBool()); return boolean; } + int AsInt() const { _ASSERTE(IsInt()); return integer; } +// int AsLong() const { _ASSERTE(IsLong()); return longlong; } + const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } + double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } + + bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } + int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } + double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } + const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } + + int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } + + const AVSValue& operator[](int index) const { + _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) + src->clip->AddRef(); + if (!init && IsClip() && clip) + clip->Release(); + // make sure this copies the whole struct! + /* UGH! what the- ? + ((__int32*)this)[0] = ((__int32*)src)[0]; + ((__int32*)this)[1] = ((__int32*)src)[1]; + */ + this->clip = src->clip; + this->type = src->type; + this->array_size = src->array_size; + } +}; + + +// instantiable null filter +class GenericVideoFilter : public IClip { +protected: + PClip child; + VideoInfo vi; +public: + GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } + void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } + const VideoInfo& __stdcall GetVideoInfo() { return vi; } + bool __stdcall GetParity(int n) { return child->GetParity(n); } + void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter. +}; + + + + + +/* Helper classes useful to plugin authors */ + +class AlignPlanar : public GenericVideoFilter +{ +public: + AlignPlanar(PClip _clip); + static PClip Create(PClip clip); + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); +}; + + + +class FillBorder : public GenericVideoFilter +{ +public: + FillBorder(PClip _clip); + static PClip Create(PClip clip); + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); +}; + + + +class ConvertAudio : public GenericVideoFilter +/** + * Helper class to convert audio to any format + **/ +{ +public: + ConvertAudio(PClip _clip, int prefered_format); + void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env); + void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache! + + static PClip Create(PClip clip, int sample_type, int prefered_type); + static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_8bit (AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_Any (AVSValue args, void*, IScriptEnvironment*); + virtual ~ConvertAudio(); + +private: + void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count); + void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count); + + __inline int Saturate_int8(float n); + __inline short Saturate_int16(float n); + __inline int Saturate_int24(float n); + __inline int Saturate_int32(float n); + + char src_format; + char dst_format; + int src_bps; + char *tempbuffer; + SFLOAT *floatbuffer; + int tempbuffer_size; +}; + + +// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. +enum { + /* slowest CPU to support extension */ + CPUF_FORCE = 0x01, // N/A + CPUF_FPU = 0x02, // 386/486DX + CPUF_MMX = 0x04, // P55C, K6, PII + CPUF_INTEGER_SSE = 0x08, // PIII, Athlon + CPUF_SSE = 0x10, // PIII, Athlon XP/MP + CPUF_SSE2 = 0x20, // PIV, Hammer + CPUF_3DNOW = 0x40, // K6-2 + CPUF_3DNOW_EXT = 0x80, // Athlon + CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which + // only Hammer will have anyway) + CPUF_SSE3 = 0x100, // PIV+, Hammer + CPUF_SSSE3 = 0x200, // prescott? + CPUF_SSE4 = 0x400, // penryn + CPUF_SSE4_2 = 0x800 // Core iX +}; + +//josh: changed these just bc winsdk defines them in BaseTsd.h +#define MAX_INT MAXINT32 +#define MIN_INT MININT32 // ::FIXME:: research why this is not 0x80000000 + + + +class IClipLocalStorage; + +class IScriptEnvironment { +public: +#if defined(__INTEL_COMPILER) + virtual ~IScriptEnvironment() {} +#else + virtual __stdcall ~IScriptEnvironment() {} +#endif + + virtual /*static*/ long __stdcall GetCPUFlags() = 0; + + virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; + virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; + // note: val is really a va_list; I hope everyone typedefs va_list to a pointer + virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; + + __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; + + class NotFound /*exception*/ {}; // thrown by Invoke and GetVar + + typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); + + virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; + virtual bool __stdcall FunctionExists(const char* name) = 0; + virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; + + virtual AVSValue __stdcall GetVar(const char* name) = 0; + virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; + virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; + + virtual void __stdcall PushContext(int level=0) = 0; + virtual void __stdcall PopContext() = 0; + + // align should be 4 or 8 + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0; + + virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; + + virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; + + typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); + virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; + + virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; + + virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; + + virtual int __stdcall SetMemoryMax(int mem) = 0; + + virtual int __stdcall SetWorkingDir(const char * newdir) = 0; + + virtual void* __stdcall ManageCache(int key, void* data) = 0; + + enum PlanarChromaAlignmentMode { + PlanarChromaAlignmentOff, + PlanarChromaAlignmentOn, + PlanarChromaAlignmentTest }; + + virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0; + + virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; + + virtual void __stdcall SetMTMode(int mode,int threads,bool temporary)=0; + virtual int __stdcall GetMTMode(bool return_nthreads)=0; + + virtual IClipLocalStorage* __stdcall AllocClipLocalStorage()=0; + + virtual void __stdcall SaveClipLocalStorage()=0; + virtual void __stdcall RestoreClipLocalStorage()=0; +}; + + +// avisynth.dll exports this; it's a way to use it as a library, without +// writing an AVS script or without going through AVIFile. +IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); + + +#pragma pack(pop) + +#endif //__AVISYNTH_H__ diff --git a/include/dsm/dsm.h b/include/dsm/dsm.h index dc2920dae71..981e7d2082e 100644 --- a/include/dsm/dsm.h +++ b/include/dsm/dsm.h @@ -1,37 +1,37 @@ -/* - * (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 . - * - */ - -#pragma once - -#define DSMF_VERSION 0x01 - -#define DSMSW 0x44534D53ui64 -#define DSMSW_SIZE 4 - -enum dsmp_t { - DSMP_FILEINFO = 0, - DSMP_STREAMINFO = 1, - DSMP_MEDIATYPE = 2, - DSMP_CHAPTERS = 3, - DSMP_SAMPLE = 4, - DSMP_SYNCPOINTS = 5, - DSMP_RESOURCE = 6 -}; +/* + * (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 . + * + */ + +#pragma once + +#define DSMF_VERSION 0x01 + +#define DSMSW 0x44534D53ui64 +#define DSMSW_SIZE 4 + +enum dsmp_t { + DSMP_FILEINFO = 0, + DSMP_STREAMINFO = 1, + DSMP_MEDIATYPE = 2, + DSMP_CHAPTERS = 3, + DSMP_SAMPLE = 4, + DSMP_SYNCPOINTS = 5, + DSMP_RESOURCE = 6 +}; diff --git a/include/lglcd/lglcd.h b/include/lglcd/lglcd.h index e86c2ca2088..f70145f10b5 100644 --- a/include/lglcd/lglcd.h +++ b/include/lglcd/lglcd.h @@ -1,456 +1,456 @@ -/* - - lglcd.h - - library definition for lglcd.a - part of lglcd for Microsoft(R) Windows(R) - - The Logitech LCD SDK, including all acompanying documentation, - is protected by intellectual property laws. All use of the Logitech - LCD SDK is subject to the License Agreement found in the - "ReadMe License Agreement" file and in the Reference Manual. All rights - not expressly granted by Logitech are reserved. - - - 01/14/2005 1.00 initial draft - 02/23/2005 1.01 added callbacks, implemented changes as discussed - 02/08/2006 1.02 added call to set foreground, sync update with confirmation - 05/29/2006 1.03 Added device family feature - 12/03/2007 3.00 Added support for color devices and partial event notifications (arrival and removal) - 10/03/2008 3.01 Added more event notifications - 10/27/2008 3.01 Deprecated enumeration and index-based open; Applets should use lgLcdOpenByType() (and - possibly notifications) - -*/ - -#ifndef _LGLCD_H_INCLUDED_ -#define _LGLCD_H_INCLUDED_ - -#ifdef __cplusplus -extern "C" { -#endif - -#pragma pack(push, 8) - -//// Definitions - -// Invalid handle definitions -#define LGLCD_INVALID_CONNECTION (-1) -#define LGLCD_INVALID_DEVICE (-1) - - -// Common Soft-Buttons available through the SDK -#define LGLCDBUTTON_LEFT (0x00000100) -#define LGLCDBUTTON_RIGHT (0x00000200) -#define LGLCDBUTTON_OK (0x00000400) -#define LGLCDBUTTON_CANCEL (0x00000800) -#define LGLCDBUTTON_UP (0x00001000) -#define LGLCDBUTTON_DOWN (0x00002000) -#define LGLCDBUTTON_MENU (0x00004000) - -// Soft-Button masks. Kept for backwards compatibility -#define LGLCDBUTTON_BUTTON0 (0x00000001) -#define LGLCDBUTTON_BUTTON1 (0x00000002) -#define LGLCDBUTTON_BUTTON2 (0x00000004) -#define LGLCDBUTTON_BUTTON3 (0x00000008) -#define LGLCDBUTTON_BUTTON4 (0x00000010) -#define LGLCDBUTTON_BUTTON5 (0x00000020) -#define LGLCDBUTTON_BUTTON6 (0x00000040) -#define LGLCDBUTTON_BUTTON7 (0x00000080) - -//************************************************************************ -// lgLcdDeviceDesc -//************************************************************************ -typedef struct -{ - DWORD Width; - DWORD Height; - DWORD Bpp; - DWORD NumSoftButtons; -} lgLcdDeviceDesc; - - -//************************************************************************ -// lgLcdDeviceDescEx -//************************************************************************ -typedef struct -{ - DWORD deviceFamilyId; - WCHAR deviceDisplayName[MAX_PATH]; - DWORD Width; // # of pixels (horizontally) on the LCD - DWORD Height; // # of pixels (lines) on the LCD - DWORD Bpp; // # of bits per pixel (1,8,16,24,...) - DWORD NumSoftButtons; - DWORD Reserved1; - DWORD Reserved2; -} lgLcdDeviceDescExW; - -typedef struct -{ - DWORD deviceFamilyId; - CHAR deviceDisplayName[MAX_PATH]; - DWORD Width; - DWORD Height; - DWORD Bpp; - DWORD NumSoftButtons; - DWORD Reserved1; - DWORD Reserved2; -} lgLcdDeviceDescExA; - -#ifdef UNICODE -typedef lgLcdDeviceDescExW lgLcdDeviceDescEx; -#else -typedef lgLcdDeviceDescExA lgLcdDeviceDescEx; -#endif - -//************************************************************************ -// lgLcdBitmap -//************************************************************************ - -#define LGLCD_BMP_FORMAT_160x43x1 (0x00000001) -#define LGLCD_BMP_FORMAT_QVGAx32 (0x00000003) -#define LGLCD_BMP_WIDTH (160) -#define LGLCD_BMP_HEIGHT (43) -#define LGLCD_BMP_BPP (1) -#define LGLCD_BW_BMP_WIDTH (160) -#define LGLCD_BW_BMP_HEIGHT (43) -#define LGLCD_BW_BMP_BPP (1) -#define LGLCD_QVGA_BMP_WIDTH (320) -#define LGLCD_QVGA_BMP_HEIGHT (240) -#define LGLCD_QVGA_BMP_BPP (4) - -typedef struct -{ - DWORD Format; -} lgLcdBitmapHeader; - -typedef struct -{ - lgLcdBitmapHeader hdr; - BYTE pixels[LGLCD_BMP_WIDTH * LGLCD_BMP_HEIGHT * LGLCD_BMP_BPP]; -} lgLcdBitmap160x43x1; - -typedef struct -{ - lgLcdBitmapHeader hdr; // Format = LGLCD_BMP_FORMAT_QVGAx32 - BYTE pixels[LGLCD_QVGA_BMP_WIDTH * LGLCD_QVGA_BMP_HEIGHT * LGLCD_QVGA_BMP_BPP]; -} lgLcdBitmapQVGAx32; -// -// Generic bitmap for use by both color and BW applets -// -typedef union -{ - lgLcdBitmapHeader hdr; // provides easy access to the header - lgLcdBitmap160x43x1 bmp_mono; // B/W bitmap data - lgLcdBitmapQVGAx32 bmp_qvga32; // Color bitmap data -} lgLcdBitmap; - -// Priorities -#define LGLCD_PRIORITY_IDLE_NO_SHOW (0) -#define LGLCD_PRIORITY_BACKGROUND (64) -#define LGLCD_PRIORITY_NORMAL (128) -#define LGLCD_PRIORITY_ALERT (255) -#define LGLCD_SYNC_UPDATE(priority) (0x80000000 | (priority)) -#define LGLCD_SYNC_COMPLETE_WITHIN_FRAME(priority) (0xC0000000 | (priority)) -#define LGLCD_ASYNC_UPDATE(priority) (priority) - -// Foreground mode for client applications -#define LGLCD_LCD_FOREGROUND_APP_NO (0) -#define LGLCD_LCD_FOREGROUND_APP_YES (1) - -// Device family definitions -#define LGLCD_DEVICE_FAMILY_BW_160x43_GAMING (0x00000001) -#define LGLCD_DEVICE_FAMILY_KEYBOARD_G15 (0x00000001) -#define LGLCD_DEVICE_FAMILY_BW_160x43_AUDIO (0x00000002) -#define LGLCD_DEVICE_FAMILY_SPEAKERS_Z10 (0x00000002) -#define LGLCD_DEVICE_FAMILY_JACKBOX (0x00000004) -#define LGLCD_DEVICE_FAMILY_BW_160x43_BASIC (0x00000008) -#define LGLCD_DEVICE_FAMILY_LCDEMULATOR_G15 (0x00000008) -#define LGLCD_DEVICE_FAMILY_RAINBOW (0x00000010) -#define LGLCD_DEVICE_FAMILY_QVGA_BASIC (0x00000020) -#define LGLCD_DEVICE_FAMILY_QVGA_GAMING (0x00000040) -#define LGLCD_DEVICE_FAMILY_GAMEBOARD_G13 (0x00000080) -#define LGLCD_DEVICE_FAMILY_KEYBOARD_G510 (0x00000100) -#define LGLCD_DEVICE_FAMILY_OTHER (0x80000000) - -// Combinations of device families (device clans?) -#define LGLCD_DEVICE_FAMILY_ALL_BW_160x43 (LGLCD_DEVICE_FAMILY_BW_160x43_GAMING \ - | LGLCD_DEVICE_FAMILY_BW_160x43_AUDIO \ - | LGLCD_DEVICE_FAMILY_JACKBOX \ - | LGLCD_DEVICE_FAMILY_BW_160x43_BASIC \ - | LGLCD_DEVICE_FAMILY_RAINBOW \ - | LGLCD_DEVICE_FAMILY_GAMEBOARD_G13 \ - | LGLCD_DEVICE_FAMILY_KEYBOARD_G510) - -#define LGLCD_DEVICE_FAMILY_ALL_QVGA (LGLCD_DEVICE_FAMILY_QVGA_BASIC \ - | LGLCD_DEVICE_FAMILY_QVGA_GAMING) - -#define LGLCD_DEVICE_FAMILY_ALL (LGLCD_DEVICE_FAMILY_ALL_BW_160x43 \ - | LGLCD_DEVICE_FAMILY_ALL_QVGA) - - -// Capabilities of applets connecting to LCD Manager. -#define LGLCD_APPLET_CAP_BASIC (0x00000000) -#define LGLCD_APPLET_CAP_BW (0x00000001) -#define LGLCD_APPLET_CAP_QVGA (0x00000002) - -// Notifications sent by LCD Manager to applets connected to it. -#define LGLCD_NOTIFICATION_DEVICE_ARRIVAL (0x00000001) -#define LGLCD_NOTIFICATION_DEVICE_REMOVAL (0x00000002) -#define LGLCD_NOTIFICATION_CLOSE_CONNECTION (0x00000003) -#define LGLCD_NOTIFICATION_APPLET_DISABLED (0x00000004) -#define LGLCD_NOTIFICATION_APPLET_ENABLED (0x00000005) -#define LGLCD_NOTIFICATION_TERMINATE_APPLET (0x00000006) - -// Device types used in notifications -#define LGLCD_DEVICE_BW (0x00000001) -#define LGLCD_DEVICE_QVGA (0x00000002) - -//************************************************************************ -// Callbacks -//************************************************************************ - -// Callback used to notify client of soft button change -typedef DWORD (WINAPI *lgLcdOnSoftButtonsCB)(IN int device, - IN DWORD dwButtons, - IN const PVOID pContext); - -// Callback used to allow client to pop up a "configuration panel" -typedef DWORD (WINAPI *lgLcdOnConfigureCB)(IN int connection, - IN const PVOID pContext); - -// Callback used to notify client of events, such as device arrival, ... -// Arrival, removal, applet enable/disable supported as of version 3.0. -typedef DWORD (WINAPI *lgLcdOnNotificationCB)(IN int connection, - IN const PVOID pContext, - IN DWORD notificationCode, - IN DWORD notifyParm1, - IN DWORD notifyParm2, - IN DWORD notifyParm3, - IN DWORD notifyParm4); - - -//************************************************************************ -// lgLcdConfigureContext -//************************************************************************ -typedef struct -{ - // Set to NULL if not configurable - lgLcdOnConfigureCB configCallback; - PVOID configContext; -} lgLcdConfigureContext; - -//************************************************************************ -// lgLcdNotificationContext -//************************************************************************ -typedef struct -{ - // Set to NULL if not notifiable - lgLcdOnNotificationCB notificationCallback; - PVOID notifyContext; -} lgLcdNotificationContext; - -//************************************************************************ -// lgLcdConnectContext -//************************************************************************ -typedef struct -{ - // "Friendly name" display in the listing - LPCWSTR appFriendlyName; - // isPersistent determines whether this connection persists in the list - BOOL isPersistent; - // isAutostartable determines whether the client can be started by - // LCDMon - BOOL isAutostartable; - lgLcdConfigureContext onConfigure; - // --> Connection handle - int connection; -} lgLcdConnectContextW; - -typedef struct -{ - // "Friendly name" display in the listing - LPCSTR appFriendlyName; - // isPersistent determines whether this connection persists in the list - BOOL isPersistent; - // isAutostartable determines whether the client can be started by - // LCDMon - BOOL isAutostartable; - lgLcdConfigureContext onConfigure; - // --> Connection handle - int connection; -} lgLcdConnectContextA; - -//************************************************************************ -// lgLcdConnectContextEx -//************************************************************************ -typedef struct -{ - // "Friendly name" display in the listing - LPCWSTR appFriendlyName; - // isPersistent determines whether this connection persists in the list - BOOL isPersistent; - // isAutostartable determines whether the client can be started by - // LCDMon - BOOL isAutostartable; - lgLcdConfigureContext onConfigure; - // --> Connection handle - int connection; - // New additions added in 1.03 revision - DWORD dwAppletCapabilitiesSupported; // Or'd combination of LGLCD_APPLET_CAP_... defines - DWORD dwReserved1; - lgLcdNotificationContext onNotify; -} lgLcdConnectContextExW; - -typedef struct -{ - // "Friendly name" display in the listing - LPCSTR appFriendlyName; - // isPersistent determines whether this connection persists in the list - BOOL isPersistent; - // isAutostartable determines whether the client can be started by - // LCDMon - BOOL isAutostartable; - lgLcdConfigureContext onConfigure; - // --> Connection handle - int connection; - // New additions added in 1.03 revision - DWORD dwAppletCapabilitiesSupported; // Or'd combination of LGLCD_APPLET_CAP_... defines - DWORD dwReserved1; - lgLcdNotificationContext onNotify; -} lgLcdConnectContextExA; - -#ifdef UNICODE -typedef lgLcdConnectContextW lgLcdConnectContext; -typedef lgLcdConnectContextExW lgLcdConnectContextEx; -#else -typedef lgLcdConnectContextA lgLcdConnectContext; -typedef lgLcdConnectContextExA lgLcdConnectContextEx; -#endif - -//************************************************************************ -// lgLcdOpenContext & lgLcdOpenByTypeContext -//************************************************************************ - -typedef struct -{ - // Set to NULL if no softbutton notifications are needed - lgLcdOnSoftButtonsCB softbuttonsChangedCallback; - PVOID softbuttonsChangedContext; -} lgLcdSoftbuttonsChangedContext; - -typedef struct -{ - int connection; - // Device index to open - int index; - lgLcdSoftbuttonsChangedContext onSoftbuttonsChanged; - // --> Device handle - int device; -} lgLcdOpenContext; - -typedef struct -{ - int connection; - // Device type to open (either LGLCD_DEVICE_BW or LGLCD_DEVICE_QVGA) - int deviceType; - lgLcdSoftbuttonsChangedContext onSoftbuttonsChanged; - // --> Device handle - int device; -} lgLcdOpenByTypeContext; - - -//************************************************************************ -// Prototypes -//************************************************************************ - -// Initialize the library by calling this function. -DWORD WINAPI lgLcdInit(void); - -// Must be called to release the library and free all allocated structures. -DWORD WINAPI lgLcdDeInit(void); - -// Connect as a client to the LCD subsystem. Provide name to be -// displayed for user when viewing the user interface of the LCD module, -// as well as a configuration callback and context, and a flag that states -// whether this client is startable by LCDMon -DWORD WINAPI lgLcdConnectW(IN OUT lgLcdConnectContextW *ctx); -DWORD WINAPI lgLcdConnectA(IN OUT lgLcdConnectContextA *ctx); -DWORD WINAPI lgLcdConnectExW(IN OUT lgLcdConnectContextExW *ctx); -DWORD WINAPI lgLcdConnectExA(IN OUT lgLcdConnectContextExA *ctx); -#ifdef UNICODE -#define lgLcdConnect lgLcdConnectW -#define lgLcdConnectEx lgLcdConnectExW -#else -#define lgLcdConnect lgLcdConnectA -#define lgLcdConnectEx lgLcdConnectExA -#endif // !UNICODE - -// Must be called to release the connection and free all allocated resources -DWORD WINAPI lgLcdDisconnect(int connection); - -// New additions added in 1.03 revision of API. Call this method to setup which device families the applet -// is interested in. After this call, the applet can use lgLcdEnumerateEx to determine -// if a device from the device family wanted is found. -DWORD WINAPI lgLcdSetDeviceFamiliesToUse(IN int connection, - DWORD dwDeviceFamiliesSupported, // Or'd combination of LGLCD_DEVICE_FAMILY_... defines - DWORD dwReserved1); - -// To determine all connected LCD devices supported by this library, and -// their capabilities. Start with index 0, and increment by one, until -// the library returns an error (WHICH?). -DWORD WINAPI lgLcdEnumerate(IN int connection, IN int index, - OUT lgLcdDeviceDesc *description); - -// To determine all connected LCD devices supported by this library, and -// their capabilities. Start with 0, and increment by one, until -// the library returns an error (WHICH?). -DWORD WINAPI lgLcdEnumerateExW(IN int connection, IN int index, - OUT lgLcdDeviceDescExW *description); -DWORD WINAPI lgLcdEnumerateExA(IN int connection, IN int index, - OUT lgLcdDeviceDescExA *description); -#ifdef UNICODE -#define lgLcdEnumerateEx lgLcdEnumerateExW -#else -#define lgLcdEnumerateEx lgLcdEnumerateExA -#endif // !UNICODE - -// Opens the LCD at position=index. Library sets the device parameter to -// its internal reference to the device. Calling application provides the -// device handle in all calls that access the LCD. -DWORD WINAPI lgLcdOpen(IN OUT lgLcdOpenContext *ctx); - -// Opens an LCD of the specified type. If no such device is available, returns -// an error. -DWORD WINAPI lgLcdOpenByType(IN OUT lgLcdOpenByTypeContext *ctx); - -// Closes the LCD. Must be paired with lgLcdOpen()/lgLcdOpenByType(). -DWORD WINAPI lgLcdClose(IN int device); - -// Reads the state of the soft buttons for the device. -DWORD WINAPI lgLcdReadSoftButtons(IN int device, OUT DWORD *buttons); - -// Provides a bitmap to be displayed on the LCD. The priority field -// further describes the way in which the bitmap is to be applied. -DWORD WINAPI lgLcdUpdateBitmap(IN int device, - IN const lgLcdBitmapHeader *bitmap, - IN DWORD priority); - -// Sets the calling application as the shown application on the LCD, and stops -// any type of rotation among other applications on the LCD. -DWORD WINAPI lgLcdSetAsLCDForegroundApp(IN int device, IN int foregroundYesNoFlag); - -// These API calls are being deprecated. Consider using lgLcdOpenByType() and -// device arrival/removal notifications instead. -#pragma deprecated(lgLcdEnumerate,lgLcdEnumerateExA,lgLcdEnumerateExW,lgLcdOpen) - - -#pragma pack(pop) - -#ifdef __cplusplus -} -#endif - -#endif // _LGLCD_H_INCLUDED_ - -//** end of lglcd.h *************************************************** +/* + + lglcd.h + + library definition for lglcd.a + part of lglcd for Microsoft(R) Windows(R) + + The Logitech LCD SDK, including all acompanying documentation, + is protected by intellectual property laws. All use of the Logitech + LCD SDK is subject to the License Agreement found in the + "ReadMe License Agreement" file and in the Reference Manual. All rights + not expressly granted by Logitech are reserved. + + + 01/14/2005 1.00 initial draft + 02/23/2005 1.01 added callbacks, implemented changes as discussed + 02/08/2006 1.02 added call to set foreground, sync update with confirmation + 05/29/2006 1.03 Added device family feature + 12/03/2007 3.00 Added support for color devices and partial event notifications (arrival and removal) + 10/03/2008 3.01 Added more event notifications + 10/27/2008 3.01 Deprecated enumeration and index-based open; Applets should use lgLcdOpenByType() (and + possibly notifications) + +*/ + +#ifndef _LGLCD_H_INCLUDED_ +#define _LGLCD_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(push, 8) + +//// Definitions + +// Invalid handle definitions +#define LGLCD_INVALID_CONNECTION (-1) +#define LGLCD_INVALID_DEVICE (-1) + + +// Common Soft-Buttons available through the SDK +#define LGLCDBUTTON_LEFT (0x00000100) +#define LGLCDBUTTON_RIGHT (0x00000200) +#define LGLCDBUTTON_OK (0x00000400) +#define LGLCDBUTTON_CANCEL (0x00000800) +#define LGLCDBUTTON_UP (0x00001000) +#define LGLCDBUTTON_DOWN (0x00002000) +#define LGLCDBUTTON_MENU (0x00004000) + +// Soft-Button masks. Kept for backwards compatibility +#define LGLCDBUTTON_BUTTON0 (0x00000001) +#define LGLCDBUTTON_BUTTON1 (0x00000002) +#define LGLCDBUTTON_BUTTON2 (0x00000004) +#define LGLCDBUTTON_BUTTON3 (0x00000008) +#define LGLCDBUTTON_BUTTON4 (0x00000010) +#define LGLCDBUTTON_BUTTON5 (0x00000020) +#define LGLCDBUTTON_BUTTON6 (0x00000040) +#define LGLCDBUTTON_BUTTON7 (0x00000080) + +//************************************************************************ +// lgLcdDeviceDesc +//************************************************************************ +typedef struct +{ + DWORD Width; + DWORD Height; + DWORD Bpp; + DWORD NumSoftButtons; +} lgLcdDeviceDesc; + + +//************************************************************************ +// lgLcdDeviceDescEx +//************************************************************************ +typedef struct +{ + DWORD deviceFamilyId; + WCHAR deviceDisplayName[MAX_PATH]; + DWORD Width; // # of pixels (horizontally) on the LCD + DWORD Height; // # of pixels (lines) on the LCD + DWORD Bpp; // # of bits per pixel (1,8,16,24,...) + DWORD NumSoftButtons; + DWORD Reserved1; + DWORD Reserved2; +} lgLcdDeviceDescExW; + +typedef struct +{ + DWORD deviceFamilyId; + CHAR deviceDisplayName[MAX_PATH]; + DWORD Width; + DWORD Height; + DWORD Bpp; + DWORD NumSoftButtons; + DWORD Reserved1; + DWORD Reserved2; +} lgLcdDeviceDescExA; + +#ifdef UNICODE +typedef lgLcdDeviceDescExW lgLcdDeviceDescEx; +#else +typedef lgLcdDeviceDescExA lgLcdDeviceDescEx; +#endif + +//************************************************************************ +// lgLcdBitmap +//************************************************************************ + +#define LGLCD_BMP_FORMAT_160x43x1 (0x00000001) +#define LGLCD_BMP_FORMAT_QVGAx32 (0x00000003) +#define LGLCD_BMP_WIDTH (160) +#define LGLCD_BMP_HEIGHT (43) +#define LGLCD_BMP_BPP (1) +#define LGLCD_BW_BMP_WIDTH (160) +#define LGLCD_BW_BMP_HEIGHT (43) +#define LGLCD_BW_BMP_BPP (1) +#define LGLCD_QVGA_BMP_WIDTH (320) +#define LGLCD_QVGA_BMP_HEIGHT (240) +#define LGLCD_QVGA_BMP_BPP (4) + +typedef struct +{ + DWORD Format; +} lgLcdBitmapHeader; + +typedef struct +{ + lgLcdBitmapHeader hdr; + BYTE pixels[LGLCD_BMP_WIDTH * LGLCD_BMP_HEIGHT * LGLCD_BMP_BPP]; +} lgLcdBitmap160x43x1; + +typedef struct +{ + lgLcdBitmapHeader hdr; // Format = LGLCD_BMP_FORMAT_QVGAx32 + BYTE pixels[LGLCD_QVGA_BMP_WIDTH * LGLCD_QVGA_BMP_HEIGHT * LGLCD_QVGA_BMP_BPP]; +} lgLcdBitmapQVGAx32; +// +// Generic bitmap for use by both color and BW applets +// +typedef union +{ + lgLcdBitmapHeader hdr; // provides easy access to the header + lgLcdBitmap160x43x1 bmp_mono; // B/W bitmap data + lgLcdBitmapQVGAx32 bmp_qvga32; // Color bitmap data +} lgLcdBitmap; + +// Priorities +#define LGLCD_PRIORITY_IDLE_NO_SHOW (0) +#define LGLCD_PRIORITY_BACKGROUND (64) +#define LGLCD_PRIORITY_NORMAL (128) +#define LGLCD_PRIORITY_ALERT (255) +#define LGLCD_SYNC_UPDATE(priority) (0x80000000 | (priority)) +#define LGLCD_SYNC_COMPLETE_WITHIN_FRAME(priority) (0xC0000000 | (priority)) +#define LGLCD_ASYNC_UPDATE(priority) (priority) + +// Foreground mode for client applications +#define LGLCD_LCD_FOREGROUND_APP_NO (0) +#define LGLCD_LCD_FOREGROUND_APP_YES (1) + +// Device family definitions +#define LGLCD_DEVICE_FAMILY_BW_160x43_GAMING (0x00000001) +#define LGLCD_DEVICE_FAMILY_KEYBOARD_G15 (0x00000001) +#define LGLCD_DEVICE_FAMILY_BW_160x43_AUDIO (0x00000002) +#define LGLCD_DEVICE_FAMILY_SPEAKERS_Z10 (0x00000002) +#define LGLCD_DEVICE_FAMILY_JACKBOX (0x00000004) +#define LGLCD_DEVICE_FAMILY_BW_160x43_BASIC (0x00000008) +#define LGLCD_DEVICE_FAMILY_LCDEMULATOR_G15 (0x00000008) +#define LGLCD_DEVICE_FAMILY_RAINBOW (0x00000010) +#define LGLCD_DEVICE_FAMILY_QVGA_BASIC (0x00000020) +#define LGLCD_DEVICE_FAMILY_QVGA_GAMING (0x00000040) +#define LGLCD_DEVICE_FAMILY_GAMEBOARD_G13 (0x00000080) +#define LGLCD_DEVICE_FAMILY_KEYBOARD_G510 (0x00000100) +#define LGLCD_DEVICE_FAMILY_OTHER (0x80000000) + +// Combinations of device families (device clans?) +#define LGLCD_DEVICE_FAMILY_ALL_BW_160x43 (LGLCD_DEVICE_FAMILY_BW_160x43_GAMING \ + | LGLCD_DEVICE_FAMILY_BW_160x43_AUDIO \ + | LGLCD_DEVICE_FAMILY_JACKBOX \ + | LGLCD_DEVICE_FAMILY_BW_160x43_BASIC \ + | LGLCD_DEVICE_FAMILY_RAINBOW \ + | LGLCD_DEVICE_FAMILY_GAMEBOARD_G13 \ + | LGLCD_DEVICE_FAMILY_KEYBOARD_G510) + +#define LGLCD_DEVICE_FAMILY_ALL_QVGA (LGLCD_DEVICE_FAMILY_QVGA_BASIC \ + | LGLCD_DEVICE_FAMILY_QVGA_GAMING) + +#define LGLCD_DEVICE_FAMILY_ALL (LGLCD_DEVICE_FAMILY_ALL_BW_160x43 \ + | LGLCD_DEVICE_FAMILY_ALL_QVGA) + + +// Capabilities of applets connecting to LCD Manager. +#define LGLCD_APPLET_CAP_BASIC (0x00000000) +#define LGLCD_APPLET_CAP_BW (0x00000001) +#define LGLCD_APPLET_CAP_QVGA (0x00000002) + +// Notifications sent by LCD Manager to applets connected to it. +#define LGLCD_NOTIFICATION_DEVICE_ARRIVAL (0x00000001) +#define LGLCD_NOTIFICATION_DEVICE_REMOVAL (0x00000002) +#define LGLCD_NOTIFICATION_CLOSE_CONNECTION (0x00000003) +#define LGLCD_NOTIFICATION_APPLET_DISABLED (0x00000004) +#define LGLCD_NOTIFICATION_APPLET_ENABLED (0x00000005) +#define LGLCD_NOTIFICATION_TERMINATE_APPLET (0x00000006) + +// Device types used in notifications +#define LGLCD_DEVICE_BW (0x00000001) +#define LGLCD_DEVICE_QVGA (0x00000002) + +//************************************************************************ +// Callbacks +//************************************************************************ + +// Callback used to notify client of soft button change +typedef DWORD (WINAPI *lgLcdOnSoftButtonsCB)(IN int device, + IN DWORD dwButtons, + IN const PVOID pContext); + +// Callback used to allow client to pop up a "configuration panel" +typedef DWORD (WINAPI *lgLcdOnConfigureCB)(IN int connection, + IN const PVOID pContext); + +// Callback used to notify client of events, such as device arrival, ... +// Arrival, removal, applet enable/disable supported as of version 3.0. +typedef DWORD (WINAPI *lgLcdOnNotificationCB)(IN int connection, + IN const PVOID pContext, + IN DWORD notificationCode, + IN DWORD notifyParm1, + IN DWORD notifyParm2, + IN DWORD notifyParm3, + IN DWORD notifyParm4); + + +//************************************************************************ +// lgLcdConfigureContext +//************************************************************************ +typedef struct +{ + // Set to NULL if not configurable + lgLcdOnConfigureCB configCallback; + PVOID configContext; +} lgLcdConfigureContext; + +//************************************************************************ +// lgLcdNotificationContext +//************************************************************************ +typedef struct +{ + // Set to NULL if not notifiable + lgLcdOnNotificationCB notificationCallback; + PVOID notifyContext; +} lgLcdNotificationContext; + +//************************************************************************ +// lgLcdConnectContext +//************************************************************************ +typedef struct +{ + // "Friendly name" display in the listing + LPCWSTR appFriendlyName; + // isPersistent determines whether this connection persists in the list + BOOL isPersistent; + // isAutostartable determines whether the client can be started by + // LCDMon + BOOL isAutostartable; + lgLcdConfigureContext onConfigure; + // --> Connection handle + int connection; +} lgLcdConnectContextW; + +typedef struct +{ + // "Friendly name" display in the listing + LPCSTR appFriendlyName; + // isPersistent determines whether this connection persists in the list + BOOL isPersistent; + // isAutostartable determines whether the client can be started by + // LCDMon + BOOL isAutostartable; + lgLcdConfigureContext onConfigure; + // --> Connection handle + int connection; +} lgLcdConnectContextA; + +//************************************************************************ +// lgLcdConnectContextEx +//************************************************************************ +typedef struct +{ + // "Friendly name" display in the listing + LPCWSTR appFriendlyName; + // isPersistent determines whether this connection persists in the list + BOOL isPersistent; + // isAutostartable determines whether the client can be started by + // LCDMon + BOOL isAutostartable; + lgLcdConfigureContext onConfigure; + // --> Connection handle + int connection; + // New additions added in 1.03 revision + DWORD dwAppletCapabilitiesSupported; // Or'd combination of LGLCD_APPLET_CAP_... defines + DWORD dwReserved1; + lgLcdNotificationContext onNotify; +} lgLcdConnectContextExW; + +typedef struct +{ + // "Friendly name" display in the listing + LPCSTR appFriendlyName; + // isPersistent determines whether this connection persists in the list + BOOL isPersistent; + // isAutostartable determines whether the client can be started by + // LCDMon + BOOL isAutostartable; + lgLcdConfigureContext onConfigure; + // --> Connection handle + int connection; + // New additions added in 1.03 revision + DWORD dwAppletCapabilitiesSupported; // Or'd combination of LGLCD_APPLET_CAP_... defines + DWORD dwReserved1; + lgLcdNotificationContext onNotify; +} lgLcdConnectContextExA; + +#ifdef UNICODE +typedef lgLcdConnectContextW lgLcdConnectContext; +typedef lgLcdConnectContextExW lgLcdConnectContextEx; +#else +typedef lgLcdConnectContextA lgLcdConnectContext; +typedef lgLcdConnectContextExA lgLcdConnectContextEx; +#endif + +//************************************************************************ +// lgLcdOpenContext & lgLcdOpenByTypeContext +//************************************************************************ + +typedef struct +{ + // Set to NULL if no softbutton notifications are needed + lgLcdOnSoftButtonsCB softbuttonsChangedCallback; + PVOID softbuttonsChangedContext; +} lgLcdSoftbuttonsChangedContext; + +typedef struct +{ + int connection; + // Device index to open + int index; + lgLcdSoftbuttonsChangedContext onSoftbuttonsChanged; + // --> Device handle + int device; +} lgLcdOpenContext; + +typedef struct +{ + int connection; + // Device type to open (either LGLCD_DEVICE_BW or LGLCD_DEVICE_QVGA) + int deviceType; + lgLcdSoftbuttonsChangedContext onSoftbuttonsChanged; + // --> Device handle + int device; +} lgLcdOpenByTypeContext; + + +//************************************************************************ +// Prototypes +//************************************************************************ + +// Initialize the library by calling this function. +DWORD WINAPI lgLcdInit(void); + +// Must be called to release the library and free all allocated structures. +DWORD WINAPI lgLcdDeInit(void); + +// Connect as a client to the LCD subsystem. Provide name to be +// displayed for user when viewing the user interface of the LCD module, +// as well as a configuration callback and context, and a flag that states +// whether this client is startable by LCDMon +DWORD WINAPI lgLcdConnectW(IN OUT lgLcdConnectContextW *ctx); +DWORD WINAPI lgLcdConnectA(IN OUT lgLcdConnectContextA *ctx); +DWORD WINAPI lgLcdConnectExW(IN OUT lgLcdConnectContextExW *ctx); +DWORD WINAPI lgLcdConnectExA(IN OUT lgLcdConnectContextExA *ctx); +#ifdef UNICODE +#define lgLcdConnect lgLcdConnectW +#define lgLcdConnectEx lgLcdConnectExW +#else +#define lgLcdConnect lgLcdConnectA +#define lgLcdConnectEx lgLcdConnectExA +#endif // !UNICODE + +// Must be called to release the connection and free all allocated resources +DWORD WINAPI lgLcdDisconnect(int connection); + +// New additions added in 1.03 revision of API. Call this method to setup which device families the applet +// is interested in. After this call, the applet can use lgLcdEnumerateEx to determine +// if a device from the device family wanted is found. +DWORD WINAPI lgLcdSetDeviceFamiliesToUse(IN int connection, + DWORD dwDeviceFamiliesSupported, // Or'd combination of LGLCD_DEVICE_FAMILY_... defines + DWORD dwReserved1); + +// To determine all connected LCD devices supported by this library, and +// their capabilities. Start with index 0, and increment by one, until +// the library returns an error (WHICH?). +DWORD WINAPI lgLcdEnumerate(IN int connection, IN int index, + OUT lgLcdDeviceDesc *description); + +// To determine all connected LCD devices supported by this library, and +// their capabilities. Start with 0, and increment by one, until +// the library returns an error (WHICH?). +DWORD WINAPI lgLcdEnumerateExW(IN int connection, IN int index, + OUT lgLcdDeviceDescExW *description); +DWORD WINAPI lgLcdEnumerateExA(IN int connection, IN int index, + OUT lgLcdDeviceDescExA *description); +#ifdef UNICODE +#define lgLcdEnumerateEx lgLcdEnumerateExW +#else +#define lgLcdEnumerateEx lgLcdEnumerateExA +#endif // !UNICODE + +// Opens the LCD at position=index. Library sets the device parameter to +// its internal reference to the device. Calling application provides the +// device handle in all calls that access the LCD. +DWORD WINAPI lgLcdOpen(IN OUT lgLcdOpenContext *ctx); + +// Opens an LCD of the specified type. If no such device is available, returns +// an error. +DWORD WINAPI lgLcdOpenByType(IN OUT lgLcdOpenByTypeContext *ctx); + +// Closes the LCD. Must be paired with lgLcdOpen()/lgLcdOpenByType(). +DWORD WINAPI lgLcdClose(IN int device); + +// Reads the state of the soft buttons for the device. +DWORD WINAPI lgLcdReadSoftButtons(IN int device, OUT DWORD *buttons); + +// Provides a bitmap to be displayed on the LCD. The priority field +// further describes the way in which the bitmap is to be applied. +DWORD WINAPI lgLcdUpdateBitmap(IN int device, + IN const lgLcdBitmapHeader *bitmap, + IN DWORD priority); + +// Sets the calling application as the shown application on the LCD, and stops +// any type of rotation among other applications on the LCD. +DWORD WINAPI lgLcdSetAsLCDForegroundApp(IN int device, IN int foregroundYesNoFlag); + +// These API calls are being deprecated. Consider using lgLcdOpenByType() and +// device arrival/removal notifications instead. +#pragma deprecated(lgLcdEnumerate,lgLcdEnumerateExA,lgLcdEnumerateExW,lgLcdOpen) + + +#pragma pack(pop) + +#ifdef __cplusplus +} +#endif + +#endif // _LGLCD_H_INCLUDED_ + +//** end of lglcd.h *************************************************** diff --git a/include/moreuuids.h b/include/moreuuids.h index 51f5d08ad11..a8a25fed901 100644 --- a/include/moreuuids.h +++ b/include/moreuuids.h @@ -1,1675 +1,1675 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#define WAVE_FORMAT_DOLBY_AC3 0x2000 -// {00002000-0000-0010-8000-00aa00389b71} -DEFINE_GUID(MEDIASUBTYPE_WAVE_DOLBY_AC3, WAVE_FORMAT_DOLBY_AC3, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, - 0x9b, 0x71); - -#define WAVE_FORMAT_DVD_DTS 0x2001 -// {00002001-0000-0010-8000-00aa00389b71} -DEFINE_GUID(MEDIASUBTYPE_WAVE_DTS, WAVE_FORMAT_DVD_DTS, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// Be compatible with 3ivx -#define WAVE_FORMAT_AAC 0x00FF -// {000000FF-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_AAC, WAVE_FORMAT_AAC, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_LATM_AAC 0x01FF -// {000001FF-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_LATM_AAC, WAVE_FORMAT_LATM_AAC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -// ... and also compatible with nero -// btw, older nero parsers use a lower-case fourcc, newer upper-case (why can't it just offer both?) -// {4134504D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_MP4A, 0x4134504D, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {6134706D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_mp4a, 0x6134706D, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_MP3 0x0055 -// 00000055-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MP3, WAVE_FORMAT_MP3, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_FLAC 0xF1AC -// 0000F1AC-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FLAC, WAVE_FORMAT_FLAC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {1541C5C0-CDDF-477d-BC0A-86F8AE7F8354} -DEFINE_GUID(MEDIASUBTYPE_FLAC_FRAMED, 0x1541c5c0, 0xcddf, 0x477d, 0xbc, 0xa, 0x86, 0xf8, 0xae, 0x7f, 0x83, 0x54); - -#define WAVE_FORMAT_TTA1 0x77A1 -// {000077A1-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_TTA1, WAVE_FORMAT_TTA1, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_WAVPACK4 0x5756 -// {00005756-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_WAVPACK4, WAVE_FORMAT_WAVPACK4, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_AMR, 0x000000FE, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -// {726D6173-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_SAMR, 0x726D6173, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VP70, 0x30375056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VP80, 0x30385056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VP90, 0x30395056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_AV01, 0x31305641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_IMA4, 0x34616D69, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -// {34616D69-0000-0010-8000-00AA00389B71} - -DEFINE_GUID(MEDIASUBTYPE_SAWB, 0x62776173, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {DA5B82EE-6BD2-426f-BF1E-30112DA78AE1} -DEFINE_GUID(MEDIASUBTYPE_SVCD_SUBPICTURE, 0xda5b82ee, 0x6bd2, 0x426f, 0xbf, 0x1e, 0x30, 0x11, 0x2d, 0xa7, 0x8a, 0xe1); - -// {7B57308F-5154-4c36-B903-52FE76E184FC} -DEFINE_GUID(MEDIASUBTYPE_CVD_SUBPICTURE, 0x7b57308f, 0x5154, 0x4c36, 0xb9, 0x3, 0x52, 0xfe, 0x76, 0xe1, 0x84, 0xfc); - -// {0E3A2342-F6E2-4c91-BDAE-87C71EAD0D63} -DEFINE_GUID(MEDIASUBTYPE_MPEG2_PVA, 0xe3a2342, 0xf6e2, 0x4c91, 0xbd, 0xae, 0x87, 0xc7, 0x1e, 0xad, 0xd, 0x63); - -// {6B6D0800-9ADA-11d0-A520-00A0D10129C0} -DEFINE_GUID(CLSID_NetShowSource, 0x6b6d0800, 0x9ada, 0x11d0, 0xa5, 0x20, 0x0, 0xa0, 0xd1, 0x1, 0x29, 0xc0); - -// DirectShowMedia - -// {5E9C9EE0-2E4A-4f22-9906-7BBBB75AA2B6} -DEFINE_GUID(MEDIASUBTYPE_DirectShowMedia, 0x5e9c9ee0, 0x2e4a, 0x4f22, 0x99, 0x6, 0x7b, 0xbb, 0xb7, 0x5a, 0xa2, 0xb6); - -// Dirac - -// {A29DA00F-A22B-40ea-98DE-2F7FECADA5DE} -DEFINE_GUID(MEDIASUBTYPE_Dirac, 0xa29da00f, 0xa22b, 0x40ea, 0x98, 0xde, 0x2f, 0x7f, 0xec, 0xad, 0xa5, 0xde); - -// {64726376-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_DiracVideo, 0x64726376, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {D2667A7E-4055-4244-A65F-DDDDF2B74BD7} -DEFINE_GUID(FORMAT_DiracVideoInfo, 0xd2667a7e, 0x4055, 0x4244, 0xa6, 0x5f, 0xdd, 0xdd, 0xf2, 0xb7, 0x4b, 0xd7); - -// {63617264-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_DRAC, 0x63617264, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -struct DIRACINFOHEADER -{ - VIDEOINFOHEADER2 hdr; - DWORD cbSequenceHeader; - DWORD dwSequenceHeader[1]; -}; - -// MP4 - -// {08E22ADA-B715-45ed-9D20-7B87750301D4} -DEFINE_GUID(MEDIASUBTYPE_MP4, 0x8e22ada, 0xb715, 0x45ed, 0x9d, 0x20, 0x7b, 0x87, 0x75, 0x3, 0x1, 0xd4); - -// FLV - -// {F2FAC0F1-3852-4670-AAC0-9051D400AC54} -DEFINE_GUID(MEDIASUBTYPE_FLV, 0xf2fac0f1, 0x3852, 0x4670, 0xaa, 0xc0, 0x90, 0x51, 0xd4, 0x0, 0xac, 0x54); - -// 31564C46-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FLV1, 0x31564C46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31766C66-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_flv1, 0x31766C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34564C46-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FLV4, 0x34564C46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34766C66-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_flv4, 0x34766C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30355056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP50, 0x30355056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30357076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp50, 0x30357076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP60, 0x30365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp60, 0x30367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP61, 0x31365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp61, 0x31367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP62, 0x32365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp62, 0x32367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 41365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP6A, 0x41365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 61367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp6a, 0x61367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 46365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP6F, 0x46365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 66367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp6f, 0x66367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// -// RealMedia -// - -enum -{ - WAVE_FORMAT_14_4 = 0x2002, - WAVE_FORMAT_28_8 = 0x2003, - WAVE_FORMAT_ATRC = 0x0270, // WAVE_FORMAT_SONY_SCX, - WAVE_FORMAT_COOK = 0x2004, - WAVE_FORMAT_DNET = 0x2005, - WAVE_FORMAT_RAAC = 0x2006, - WAVE_FORMAT_RACP = 0x2007, - WAVE_FORMAT_SIPR = 0x0130, // WAVE_FORMAT_SIPROLAB_ACEPLNET, -}; - -// {57428EC6-C2B2-44a2-AA9C-28F0B6A5C48E} -DEFINE_GUID(MEDIASUBTYPE_RealMedia, 0x57428ec6, 0xc2b2, 0x44a2, 0xaa, 0x9c, 0x28, 0xf0, 0xb6, 0xa5, 0xc4, 0x8e); - -// 30315652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV10, 0x30315652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30325652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV20, 0x30325652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30335652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV30, 0x30335652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30345652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV40, 0x30345652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31345652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV41, 0x31345652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 345f3431-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_14_4, 0x345f3431, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 385f3832-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_28_8, 0x385f3832, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4b4f4f43-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_COOK, 0x4b4f4f43, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 54454e44-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DNET, 0x54454e44, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 52504953-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SIPR, 0x52504953, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 00000130-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SIPR_WAVE, WAVE_FORMAT_SIPR, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43414152-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RAAC, 0x43414152, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 50434152-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RACP, 0x50434152, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -#define WAVE_FORMAT_RALF mmioFOURCC('R', 'A', 'L', 'F') -DEFINE_GUID(MEDIASUBTYPE_RALF, WAVE_FORMAT_RALF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// QuickTime PCM - -// 454E4F4E-0000-0010-8000-00AA00389B71 (unsigned 8-bit) -DEFINE_GUID(MEDIASUBTYPE_PCM_NONE, 0x454E4F4E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 20776172-0000-0010-8000-00AA00389B71 (unsigned 8-bit, signed big-endian 16 bit) -DEFINE_GUID(MEDIASUBTYPE_PCM_RAW, 0x20776172, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 736f7774-0000-0010-8000-00AA00389B71 (signed 8-bit, signed big-endian 16-bit) -DEFINE_GUID(MEDIASUBTYPE_PCM_TWOS, 0x736f7774, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 74776f73-0000-0010-8000-00AA00389B71 (signed 8-bit, signed little-endian 16-bit) -DEFINE_GUID(MEDIASUBTYPE_PCM_SOWT, 0x74776f73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34326E69-0000-0010-8000-00AA00389B71 (signed big-endian int24) -DEFINE_GUID(MEDIASUBTYPE_PCM_IN24, 0x34326E69, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32336E69-0000-0010-8000-00AA00389B71 (signed big-endian int32) -DEFINE_GUID(MEDIASUBTYPE_PCM_IN32, 0x32336E69, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32336C66-0000-0010-8000-00AA00389B71 (signed big-endian float32) -DEFINE_GUID(MEDIASUBTYPE_PCM_FL32, 0x32336C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34366C66-0000-0010-8000-00AA00389B71 (signed big-endian float64) -DEFINE_GUID(MEDIASUBTYPE_PCM_FL64, 0x34366C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Reverse GUIDs for little-endian 'in24', 'in32', 'fl32', 'fl64' -// 696E3234-0000-0010-8000-00AA00389B71 (signed little-endian int24, reverse 'in24') -DEFINE_GUID(MEDIASUBTYPE_PCM_IN24_le, 0x696E3234, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); -// 696E3332-0000-0010-8000-00AA00389B71 (signed little-endian int32, reverse 'in32') -DEFINE_GUID(MEDIASUBTYPE_PCM_IN32_le, 0x696E3332, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); -// 666C3332-0000-0010-8000-00AA00389B71 (signed little-endian float32, reverse 'fl32') -DEFINE_GUID(MEDIASUBTYPE_PCM_FL32_le, 0x666C3332, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); -// 666C3634-0000-0010-8000-00AA00389B71 (signed little-endian float64, reverse 'fl64') -DEFINE_GUID(MEDIASUBTYPE_PCM_FL64_le, 0x666C3634, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// -// PS2 -// - -#define WAVE_FORMAT_PS2_PCM 0xF521 -// 0000F521-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_PS2_PCM, WAVE_FORMAT_PS2_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_PS2_ADPCM 0xF522 -// 0000F522-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_PS2_ADPCM, WAVE_FORMAT_PS2_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -#define WAVE_FORMAT_ADPCM_SWF 0x5346 -// 00005346-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ADPCM_SWF, - WAVE_FORMAT_ADPCM_SWF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 41564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ADPCM_AMV, - 0x41564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - - -struct WAVEFORMATEXPS2 : public WAVEFORMATEX -{ - DWORD dwInterleave; - - struct WAVEFORMATEXPS2() - { - memset(this, 0, sizeof(*this)); - cbSize = sizeof(WAVEFORMATEXPS2) - sizeof(WAVEFORMATEX); - } -}; - -// {4F3D3D21-6D7C-4f73-AA05-E397B5EAE0AA} -DEFINE_GUID(MEDIASUBTYPE_PS2_SUB, 0x4f3d3d21, 0x6d7c, 0x4f73, 0xaa, 0x5, 0xe3, 0x97, 0xb5, 0xea, 0xe0, 0xaa); - -// ATRAC - -// 43525441-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ATRC, 0x43525441, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 00000270-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ATRAC3, WAVE_FORMAT_SONY_SCX, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -#define WAVE_FORMAT_ATRAC3P 0xE923AABF -// E923AABF-CB58-4471-A119-FFFA01E4CE62 -DEFINE_GUID(MEDIASUBTYPE_ATRAC3P, 0xE923AABF, 0xCB58, 0x4471, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62); - -// Haali's video renderer - -// {760A8F35-97E7-479d-AAF5-DA9EFF95D751} -DEFINE_GUID(CLSID_DXR, 0x760a8f35, 0x97e7, 0x479d, 0xaa, 0xf5, 0xda, 0x9e, 0xff, 0x95, 0xd7, 0x51); - -// {E1A8B82A-32CE-4B0D-BE0D-AA68C772E423} -DEFINE_GUID(CLSID_MadVR, 0xE1A8B82A, 0x32CE, 0x4B0D, 0xBE, 0x0D, 0xAA, 0x68, 0xC7, 0x72, 0xE4, 0x23); - -// {71F080AA-8661-4093-B15E-4F6903E77D0A} -DEFINE_GUID(CLSID_MPCVR, 0x71F080AA, 0x8661, 0x4093, 0xB1, 0x5E, 0x4F, 0x69, 0x03, 0xE7, 0x7D, 0x0A); - -// {C1F400A4-3F08-11D3-9F0B-006008039E37} -DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11D3, 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); - -// {A0025E90-E45B-11D1-ABE9-00A0C905F375} -DEFINE_GUID(CLSID_OverlayMixer2, 0xA0025E90, 0xE45B, 0x11D1, 0xAB, 0xE9, 0x00, 0xA0, 0xC9, 0x05, 0xF3, 0x75); - -// -// Ogg -// - -// 9FF48807-E133-40AA-826F-9B2959E5232D -DEFINE_GUID(CLSID_MPCHCOggSplitter, 0x9FF48807, 0xE133, 0x40AA, 0x82, 0x6F, 0x9B, 0x29, 0x59, 0xE5, 0x23, 0x2D); - -// 6D3688CE-3E9D-42F4-92CA-8A11119D25CD -DEFINE_GUID(CLSID_MPCHCOggSource, 0x6D3688CE, 0x3E9D, 0x42F4, 0x92, 0xCA, 0x8A, 0x11, 0x11, 0x9D, 0x25, 0xCD); - -// f07e245f-5a1f-4d1e-8bff-dc31d84a55ab -DEFINE_GUID(CLSID_OggSplitter, 0xf07e245f, 0x5a1f, 0x4d1e, 0x8b, 0xff, 0xdc, 0x31, 0xd8, 0x4a, 0x55, 0xab); - -// {078C3DAA-9E58-4d42-9E1C-7C8EE79539C5} -DEFINE_GUID(CLSID_OggSplitPropPage, 0x78c3daa, 0x9e58, 0x4d42, 0x9e, 0x1c, 0x7c, 0x8e, 0xe7, 0x95, 0x39, 0xc5); - -// 8cae96b7-85b1-4605-b23c-17ff5262b296 -DEFINE_GUID(CLSID_OggMux, 0x8cae96b7, 0x85b1, 0x4605, 0xb2, 0x3c, 0x17, 0xff, 0x52, 0x62, 0xb2, 0x96); - -// {AB97AFC3-D08E-4e2d-98E0-AEE6D4634BA4} -DEFINE_GUID(CLSID_OggMuxPropPage, 0xab97afc3, 0xd08e, 0x4e2d, 0x98, 0xe0, 0xae, 0xe6, 0xd4, 0x63, 0x4b, 0xa4); - -// {889EF574-0656-4B52-9091-072E52BB1B80} -DEFINE_GUID(CLSID_VorbisEnc, 0x889ef574, 0x0656, 0x4b52, 0x90, 0x91, 0x07, 0x2e, 0x52, 0xbb, 0x1b, 0x80); - -// {c5379125-fd36-4277-a7cd-fab469ef3a2f} -DEFINE_GUID(CLSID_VorbisEncPropPage, 0xc5379125, 0xfd36, 0x4277, 0xa7, 0xcd, 0xfa, 0xb4, 0x69, 0xef, 0x3a, 0x2f); - -// 02391f44-2767-4e6a-a484-9b47b506f3a4 -DEFINE_GUID(CLSID_VorbisDec, 0x02391f44, 0x2767, 0x4e6a, 0xa4, 0x84, 0x9b, 0x47, 0xb5, 0x06, 0xf3, 0xa4); - -// 77983549-ffda-4a88-b48f-b924e8d1f01c -DEFINE_GUID(CLSID_OggDSAboutPage, 0x77983549, 0xffda, 0x4a88, 0xb4, 0x8f, 0xb9, 0x24, 0xe8, 0xd1, 0xf0, 0x1c); - -// {D2855FA9-61A7-4db0-B979-71F297C17A04} -DEFINE_GUID(MEDIASUBTYPE_Ogg, 0xd2855fa9, 0x61a7, 0x4db0, 0xb9, 0x79, 0x71, 0xf2, 0x97, 0xc1, 0x7a, 0x4); - -// cddca2d5-6d75-4f98-840e-737bedd5c63b -DEFINE_GUID(MEDIASUBTYPE_Vorbis, 0xcddca2d5, 0x6d75, 0x4f98, 0x84, 0x0e, 0x73, 0x7b, 0xed, 0xd5, 0xc6, 0x3b); - -// 6bddfa7e-9f22-46a9-ab5e-884eff294d9f -DEFINE_GUID(FORMAT_VorbisFormat, 0x6bddfa7e, 0x9f22, 0x46a9, 0xab, 0x5e, 0x88, 0x4e, 0xff, 0x29, 0x4d, 0x9f); - -typedef struct tagVORBISFORMAT -{ - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nMinBitsPerSec; - DWORD nAvgBitsPerSec; - DWORD nMaxBitsPerSec; - float fQuality; -} VORBISFORMAT, *PVORBISFORMAT, FAR *LPVORBISFORMAT; - -// {8D2FD10B-5841-4a6b-8905-588FEC1ADED9} -DEFINE_GUID(MEDIASUBTYPE_Vorbis2, 0x8d2fd10b, 0x5841, 0x4a6b, 0x89, 0x5, 0x58, 0x8f, 0xec, 0x1a, 0xde, 0xd9); - -// {B36E107F-A938-4387-93C7-55E966757473} -DEFINE_GUID(FORMAT_VorbisFormat2, 0xb36e107f, 0xa938, 0x4387, 0x93, 0xc7, 0x55, 0xe9, 0x66, 0x75, 0x74, 0x73); - -typedef struct tagVORBISFORMAT2 -{ - DWORD Channels; - DWORD SamplesPerSec; - DWORD BitsPerSample; - DWORD HeaderSize[3]; // 0: Identification, 1: Comment, 2: Setup -} VORBISFORMAT2, *PVORBISFORMAT2, FAR *LPVORBISFORMAT2; - -// -// Matroska -// - -// {1AC0BEBD-4D2B-45ad-BCEB-F2C41C5E3788} -DEFINE_GUID(MEDIASUBTYPE_Matroska, 0x1ac0bebd, 0x4d2b, 0x45ad, 0xbc, 0xeb, 0xf2, 0xc4, 0x1c, 0x5e, 0x37, 0x88); - -// {E487EB08-6B26-4be9-9DD3-993434D313FD} -DEFINE_GUID(MEDIATYPE_Subtitle, 0xe487eb08, 0x6b26, 0x4be9, 0x9d, 0xd3, 0x99, 0x34, 0x34, 0xd3, 0x13, 0xfd); - -// {87C0B230-03A8-4fdf-8010-B27A5848200D} -DEFINE_GUID(MEDIASUBTYPE_UTF8, 0x87c0b230, 0x3a8, 0x4fdf, 0x80, 0x10, 0xb2, 0x7a, 0x58, 0x48, 0x20, 0xd); - -// {3020560F-255A-4ddc-806E-6C5CC6DCD70A} -DEFINE_GUID(MEDIASUBTYPE_SSA, 0x3020560f, 0x255a, 0x4ddc, 0x80, 0x6e, 0x6c, 0x5c, 0xc6, 0xdc, 0xd7, 0xa); - -// {326444F7-686F-47ff-A4B2-C8C96307B4C2} -DEFINE_GUID(MEDIASUBTYPE_ASS, 0x326444f7, 0x686f, 0x47ff, 0xa4, 0xb2, 0xc8, 0xc9, 0x63, 0x7, 0xb4, 0xc2); - -// {370689E7-B226-4f67-978D-F10BC1A9C6AE} -DEFINE_GUID(MEDIASUBTYPE_ASS2, 0x370689e7, 0xb226, 0x4f67, 0x97, 0x8d, 0xf1, 0xb, 0xc1, 0xa9, 0xc6, 0xae); - -// {76C421C4-DB89-42ec-936E-A9FBC1794714} -DEFINE_GUID(MEDIASUBTYPE_SSF, 0x76c421c4, 0xdb89, 0x42ec, 0x93, 0x6e, 0xa9, 0xfb, 0xc1, 0x79, 0x47, 0x14); - -// {B753B29A-0A96-45be-985F-68351D9CAB90} -DEFINE_GUID(MEDIASUBTYPE_USF, 0xb753b29a, 0xa96, 0x45be, 0x98, 0x5f, 0x68, 0x35, 0x1d, 0x9c, 0xab, 0x90); - -// {F7239E31-9599-4e43-8DD5-FBAF75CF37F1} -DEFINE_GUID(MEDIASUBTYPE_VOBSUB, 0xf7239e31, 0x9599, 0x4e43, 0x8d, 0xd5, 0xfb, 0xaf, 0x75, 0xcf, 0x37, 0xf1); - -// {A33D2F7D-96BC-4337-B23B-A8B9FBC295E9} -DEFINE_GUID(FORMAT_SubtitleInfo, 0xa33d2f7d, 0x96bc, 0x4337, 0xb2, 0x3b, 0xa8, 0xb9, 0xfb, 0xc2, 0x95, 0xe9); - -// {04EBA53E-9330-436c-9133-553EC87031DC} -DEFINE_GUID(MEDIASUBTYPE_HDMVSUB, 0x4eba53e, 0x9330, 0x436c, 0x91, 0x33, 0x55, 0x3e, 0xc8, 0x70, 0x31, 0xdc); - -// {C886D215-F485-40BB-8DB6-FADBC619A45D} -DEFINE_GUID(MEDIASUBTYPE_WEBVTT, 0xc886d215, 0xf485, 0x40bb, 0x8d, 0xb6, 0xfa, 0xdb, 0xc6, 0x19, 0xa4, 0x5d); - -#pragma pack(push, 1) -typedef struct -{ - DWORD dwOffset; - CHAR IsoLang[4]; // three letter lang code + terminating zero - WCHAR TrackName[256]; // 256 chars ought to be enough for everyone :) -} SUBTITLEINFO; -#pragma pack(pop) - -// SUBTITLEINFO structure content starting at dwOffset (also the content of CodecPrivate) -// -------------------------------------------------------------------------------------- -// -// Here the text should start with the Byte Order Mark, even though -// UTF-8 is preferred, it also helps identifying the encoding type. -// -// MEDIASUBTYPE_USF: -// -// -// -// -// -// -// ... every element excluding ... -// -// -// MEDIASUBTYPE_SSA/ASS: -// -// The file header and all sub-sections except [Events] -// -// MEDIATYPE_VOBSUB: -// -// TODO -// - -// Data description of the media samples (everything is UTF-8 encoded here) -// ------------------------------------------------------------------------ -// -// MEDIASUBTYPE_USF: -// -// The text _inside_ the .. element. -// -// Since timing is set on the sample, there is no need to put -// into the data. -// -// MEDIASUBTYPE_SSA/ASS: -// -// Comma separated values similar to the "Dialogue: ..." line with these fields: -// ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text -// -// With the exception of ReadOrder every field can be found in ASS files. The -// ReadOrder field is needed for the decoder to be able to reorder the streamed -// samples as they were placed originally in the file. -// -// If the source is only SSA, the Layer field can be left empty. -// -// MEDIATYPE_VOBSUB: -// -// Standard dvd subpic data, without the stream id at the beginning. -// - -// Matroska CodecID mappings -// ------------------------ -// -// S_TEXT/ASCII <-> MEDIATYPE_Text MEDIASUBTYPE_NULL FORMAT_None -// S_TEXT/UTF8 <-> MEDIATYPE_Subtitle MEDIASUBTYPE_UTF8 FORMAT_SubtitleInfo -// S_TEXT/SSA <-> MEDIATYPE_Subtitle MEDIASUBTYPE_SSA FORMAT_SubtitleInfo -// S_TEXT/ASS <-> MEDIATYPE_Subtitle MEDIASUBTYPE_ASS FORMAT_SubtitleInfo -// S_TEXT/USF <-> MEDIATYPE_Subtitle MEDIASUBTYPE_USF FORMAT_SubtitleInfo -// S_VOBSUB <-> MEDIATYPE_Subtitle MEDIASUBTYPE_VOBSUB FORMAT_SubtitleInfo -// S_VOBSUB/ZLIB<-> MEDIATYPE_Subtitle MEDIASUBTYPE_VOBSUB FORMAT_SubtitleInfo -// - -/* -DEFINE_GUID( MEDIATYPE_MPEG2_SECTIONS, - 0x455f176c, 0x4b06, 0x47ce, 0x9a, 0xef, 0x8c, 0xae, 0xf7, 0x3d, 0xf7, 0xb5); - -DEFINE_GUID(MEDIASUBTYPE_ATSC_SI, -0xb3c7397c, 0xd303, 0x414d, 0xb3, 0x3c, 0x4e, 0xd2, 0xc9, 0xd2, 0x97, 0x33); - -DEFINE_GUID(MEDIASUBTYPE_DVB_SI, -0xe9dd31a3, 0x221d, 0x4adb, 0x85, 0x32, 0x9a, 0xf3, 0x9, 0xc1, 0xa4, 0x8); - - -// {C892E55B-252D-42b5-A316-D997E7A5D995} -DEFINE_GUID(MEDIASUBTYPE_MPEG2DATA, -0xc892e55b, 0x252d, 0x42b5, 0xa3, 0x16, 0xd9, 0x97, 0xe7, 0xa5, 0xd9, 0x95); - -*/ - -// ASF -// {6B6D0801-9ADA-11D0-A520-00A0D10129C0} -DEFINE_GUID(MEDIASUBTYPE_ASF, - 0x6b6d0801, 0x9ada, 0x11d0, 0xa5, 0x20, 0x00, 0xa0, 0xd1, 0x01, 0x29, 0xc0); - -// H264 - -// 6F29D2AD-E130-45AA-B42F-F623AD354A90 -DEFINE_GUID(MEDIASUBTYPE_ArcsoftH264, 0x6F29D2AD, 0xE130, 0x45AA, 0xB4, 0x2F, 0xF6, 0x23, 0xAD, 0x35, 0x4A, 0x90); - -// 48535356-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VSSH, 0x48535356, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 68737376-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vssh, 0x68737376, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43564144-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DAVC, 0x43564144, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 63766164-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_davc, 0x63766164, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43564150-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_PAVC, 0x43564150, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 63766170-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_pavc, 0x63766170, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31637661-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_avc1, 0x31637661, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31564343-0000-0010-8000-00AA00389B71 (custom H.264 FourCC used by Haali Media Splitter) -DEFINE_GUID(MEDIASUBTYPE_CCV1, 0x31564343, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 8D2D71CB-243F-45E3-B2D8-5FD7967EC09B <= Use by MediaPortal for example... -DEFINE_GUID(MEDIASUBTYPE_H264_bis, 0x8D2D71CB, 0x243F, 0x45E3, 0xB2, 0xD8, 0x5F, 0xD7, 0x96, 0x7E, 0xC0, 0x9B); - -// 676C6178-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_xalg, 0x676C6178, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 676C7661-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_avlg, 0x676C7661, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33515653-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_SVQ3, 0x33515653, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_XVID, 0x44495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_xvid, 0x64697678, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30355844-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_DX50, 0x30355844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30357864-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_dx50, 0x30357864, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIVX, 0x58564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 78766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_divx, 0x78766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 78766944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_Divx, 0x78766944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 5634504d-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_MP4V, 0x5634504d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 7634706D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_mp4v, 0x7634706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31564933-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_3IV1, 0x31564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31766933-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_3iv1, 0x31766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32564933-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_3IV2, 0x32564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32766933-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_3iv2, 0x32766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 58564933-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_3IVX, 0x58564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 78766933-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_3ivx, 0x78766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 305A4C42-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_BLZ0, 0x305A4C42, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 307A6C62-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_blz0, 0x307A6C62, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {564F4547-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_GEOV, 0x564F4547, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56344D44-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DM4V, 0x56344D44, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 76346D64-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_dm4v, 0x76346D64, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4D475844-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DXGM, 0x4D475844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 6D677864-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_dxgm, 0x6D677864, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 53444646-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_FFDS, 0x53444646, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 73646666-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ffds, 0x73646666, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 57465646-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FVFW, 0x57465646, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 77667666-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_fvfw, 0x77667666, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D46-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FMP4, 0x34504D46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D66-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_fmp4, 0x34706D66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34584448-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HDX4, 0x34584448, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34786468-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_hdx4, 0x34786468, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D4C-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_LMP4, 0x34504D4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D6C-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_lmp4, 0x34706D6C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4749444E-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_NDIG, 0x4749444E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 6769646E-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ndig, 0x6769646E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D52-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RMP4, 0x34504D52, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D72-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_rmp4, 0x34706D72, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D53-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SMP4, 0x34504D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D73-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_smp4, 0x34706D73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 47444553-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SEDG, 0x47444553, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 67646573-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_sedg, 0x67646573, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4D475844-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DGXM, 0x4D475844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D55-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_UMP4, 0x34504D55, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D75-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ump4, 0x34706D75, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 46315657-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_WV1F, 0x46315657, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 66317677-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_wv1f, 0x66317677, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 58495658-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_XVIX, 0x58495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 78697678-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_xvix, 0x78697678, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31515653-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SVQ1, 0x31515653, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363248-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_H263, 0x33363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363268-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_h263, 0x33363268, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363249-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_I263, 0x33363249, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363269-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_i263, 0x33363269, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31363248-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_H261, 0x31363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31363268-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_h261, 0x31363268, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_S263, 0x33363273, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363273-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_s263, 0x33363273, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AMVV, 0x56564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 46564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AMVF, 0x46564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33585644-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVX3, 0x33585644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33787664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_dvx3, 0x33787664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 44564933-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_3IVD, 0x44564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV3, 0x33564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div3, 0x33766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 314C4F43-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_COL1, 0x314C4F43, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 316C6F63-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_col1, 0x316C6F63, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV4, 0x34564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div4, 0x34766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV5, 0x35564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div5, 0x35766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 36564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV6, 0x36564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 36766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div6, 0x36766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31345041-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AP41, 0x31345041, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31347061-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ap41, 0x31347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3347504D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MPG3, 0x3347504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3367706D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_mpg3, 0x3367706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV2, 0x32564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div2, 0x32766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV1, 0x31564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div1, 0x31766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3134504D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MP41, 0x3134504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3134706D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_mp41, 0x3134706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4F454854-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_THEORA, 0x4F454854, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 6F656874-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_theora, 0x6F656874, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 63637374-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_TSCC, 0x63637374, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32637374-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_TSC2, 0x32637374, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30355649-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IV50, 0x30355649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31345649-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IV41, 0x31345649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31335649-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IV31, 0x31335649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32335649-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IV32, 0x32335649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 48564443-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CDVH, 0x48564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43564443-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CDVC, 0x43564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35564443-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CDV5, 0x35564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35325644-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DV25, 0x35325644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 30355644-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DV50, 0x30355644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70637664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVCP, 0x70637664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70707664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVPP, 0x70707664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70357664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DV5P, 0x70357664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 6E357664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DV5N, 0x6E357664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70637664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVC, 0x20637664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 31687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH1, 0x31687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 32687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH2, 0x32687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 33687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH3, 0x33687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 34687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH4, 0x34687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 35687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH5, 0x35687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 36687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH6, 0x36687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 71687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVHQ, 0x71687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVHP, 0x70687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 76645641-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVdv, 0x76645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 31645641-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVd1, 0x31645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 31535046-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FPS1, 0x31535046, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 55594648-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HuffYUV, 0x55594648, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 5347414C-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_Lagarith, 0x5347414C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 64697663-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CVID, 0x64697663, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 694B4942-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_BIKI, 0x694B4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 624B4942-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_BIKB, 0x624B4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 664b4942-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_BIKf, 0x664b4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(FORMAT_RLTheora, 0xe69b30d1, 0x7d65, 0x4166, 0xb9, 0x90, 0x10, 0x3d, 0xa8, 0xc9, 0x11, 0xe3); - -// 62706A6D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MJPGB, 0x62706A6D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 30365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP30, 0x30335056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP31, 0x31335056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 324B4D53-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SMK2, 0x324B4D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 344B4D53-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SMK4, 0x344B4D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 44435343-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CSCD, 0x44435343, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 47455051-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_QPEG, 0x47455051, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 302E3151-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_QP10, 0x302E3151, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 312E3151-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_QP11, 0x312E3151, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 485A534D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MSZH, 0x485A534D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 42494C5A-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ZLIB, 0x42494C5A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 20676E70-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_PNG, 0x20676E70, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_TIFF, MAKEFOURCC('T', 'I', 'F', 'F'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_BMP, MAKEFOURCC('B', 'M', 'P', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_GIF, MAKEFOURCC('G', 'I', 'F', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_TGA, MAKEFOURCC('T', 'G', 'A', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_WEBP, MAKEFOURCC('W', 'E', 'B', 'P'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_FSV1, 0x31565346, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_CRAM, MAKEFOURCC('C', 'R', 'A', 'M'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_MSVC, MAKEFOURCC('M', 'S', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_WHAM, MAKEFOURCC('W', 'H', 'A', 'M'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_8BPS, MAKEFOURCC('8', 'B', 'P', 'S'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_LOCO, MAKEFOURCC('L', 'O', 'C', 'O'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ZMBV, MAKEFOURCC('Z', 'M', 'B', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VCR1, MAKEFOURCC('V', 'C', 'R', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_AASC, MAKEFOURCC('A', 'A', 'S', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_SNOW, MAKEFOURCC('S', 'N', 'O', 'W'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_FFV1, MAKEFOURCC('F', 'F', 'V', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_FFVH, MAKEFOURCC('F', 'F', 'V', 'H'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_v410, MAKEFOURCC('v', '4', '1', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VMNC, MAKEFOURCC('V', 'M', 'n', 'c'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// {3267706D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_MPG2, 0x3267706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Apple ProRes -DEFINE_GUID(MEDIASUBTYPE_apch, 0x68637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_apcn, 0x6e637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_apcs, 0x73637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_apco, 0x6f637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ap4h, 0x68347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ap4x, 0x78347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Apple ICOD -DEFINE_GUID(MEDIASUBTYPE_icod, 0x646F6369, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Ut Video -DEFINE_GUID(MEDIASUBTYPE_ULRA, MAKEFOURCC('U', 'L', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULRG, MAKEFOURCC('U', 'L', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULY0, MAKEFOURCC('U', 'L', 'Y', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULY2, MAKEFOURCC('U', 'L', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULY4, MAKEFOURCC('U', 'L', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UQY2, MAKEFOURCC('U', 'Q', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UQRG, MAKEFOURCC('U', 'Q', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UQRA, MAKEFOURCC('U', 'Q', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULH0, MAKEFOURCC('U', 'L', 'H', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULH2, MAKEFOURCC('U', 'L', 'H', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULH4, MAKEFOURCC('U', 'L', 'H', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMY2, MAKEFOURCC('U', 'M', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMH2, MAKEFOURCC('U', 'M', 'H', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMY4, MAKEFOURCC('U', 'M', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMH4, MAKEFOURCC('U', 'M', 'H', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMRG, MAKEFOURCC('U', 'M', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMRA, MAKEFOURCC('U', 'M', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// G2M -DEFINE_GUID(MEDIASUBTYPE_G2M2, MAKEFOURCC('G', '2', 'M', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_G2M3, MAKEFOURCC('G', '2', 'M', '3'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_G2M4, MAKEFOURCC('G', '2', 'M', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_G2M5, MAKEFOURCC('G', '2', 'M', '5'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// CFHD -DEFINE_GUID(MEDIASUBTYPE_CFHD, MAKEFOURCC('C', 'F', 'H', 'D'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// MagicYUV -DEFINE_GUID(MEDIASUBTYPE_MAGY, MAKEFOURCC('M', 'A', 'G', 'Y'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8RG, MAKEFOURCC('M', '8', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8RA, MAKEFOURCC('M', '8', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8G0, MAKEFOURCC('M', '8', 'G', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8Y0, MAKEFOURCC('M', '8', 'Y', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8Y2, MAKEFOURCC('M', '8', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8Y4, MAKEFOURCC('M', '8', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8YA, MAKEFOURCC('M', '8', 'Y', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// MagicYUV -DEFINE_GUID(MEDIASUBTYPE_FICV, MAKEFOURCC('F', 'I', 'C', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// DNxHD -// {6E645641-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_AVdn, 0x6E645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// DNxHR -// {68645641-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_AVdh, 0x68645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// JPEG2000 -// {32706A6D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_mjp2, 0x32706A6D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {43324A4D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_MJ2C, 0x43324A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {43324A4C-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_LJ2C, 0x43324A4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {4B324A4C-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_LJ2K, 0x4B324A4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {324A5049-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_IPJ2, 0x324A5049, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {D80FA03C-35C1-4FA1-8C8E-375C8667166E} -DEFINE_GUID(MEDIASUBTYPE_LAV_RAWVIDEO, 0xd80fa03c, 0x35c1, 0x4fa1, 0x8c, 0x8e, 0x37, 0x5c, 0x86, 0x67, 0x16, 0x6e); - -// {434C4641-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_FLIC, 0x434C4641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {} -DEFINE_GUID(MEDIASUBTYPE_THPV, MAKEFOURCC('T', 'H', 'P', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ROQV, MAKEFOURCC('R', 'o', 'Q', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// 31435648-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HVC1, 0x31435648, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43564548-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HEVC, 0x43564548, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30314D48-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HM10, 0x30314D48, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35363248-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_H265, 0x35363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// VVC ("VVC1") -DEFINE_GUID(MEDIASUBTYPE_VVC1, MAKEFOURCC('V', 'V', 'C', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// Full MVC -DEFINE_GUID(MEDIASUBTYPE_AMVC, MAKEFOURCC('A', 'M', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -// Full MVC in mp4-form -DEFINE_GUID(MEDIASUBTYPE_MVC1, MAKEFOURCC('M', 'V', 'C', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -// Subset MVC -DEFINE_GUID(MEDIASUBTYPE_EMVC, MAKEFOURCC('E', 'M', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -// 4B435544-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DUCK, 0x4B435544, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30324D54-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_TM20, 0x30324D54, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 20636D73-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_smc, 0x20636D73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4C584956-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VIXL, 0x4C584956, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 49544C55-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ULTI, 0x49544C55, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31564E57-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_WNV1, 0x31564E57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 76757963-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CYUV, 0x76757963, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31565341-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVS1, 0x31565341, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32565341-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVS2, 0x32565341, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31325452-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RT21, 0x31325452, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 6E525641-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVRn, 0x6E525641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 47504a4c-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_LJPG, 0x47504a4c, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4C47504A-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_JPGL, 0x4C47504A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 534c4a4d-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MJLS, 0x534c4a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 41504a4d-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MJPA, 0x41504a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 42504a4d-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MJPB, 0x42504a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 58355053-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SP5X, 0x58355053, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31706148-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_Hap1, 0x31706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35706148-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_Hap5, 0x35706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 59706148-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HapY, 0x59706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33445844-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DXD3, 0x33445844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 49445844-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DXDI, 0x49445844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 574D5632-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_2VMW, 0x574D5632, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56334357-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_WC3V, 0x56334357, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4345444D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MDEC, 0x4345444D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 564D5834-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_4XMV, 0x564D5834, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43425241-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ARBC, 0x43425241, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30345056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP40, 0x30345056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34355053-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SP54, 0x34355053, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3156474B-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_KGV1, 0x3156474B, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Audio codecs - -// 41564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IMA_AMV, 0x41564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 4C4C454E-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_NELLYMOSER, 0x4C4C454E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000006-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ALAW, WAVE_FORMAT_ALAW, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000007-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MULAW, WAVE_FORMAT_MULAW, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000031-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MSGSM610, WAVE_FORMAT_GSM610, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000002-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ADPCM_MS, WAVE_FORMAT_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000022-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_TRUESPEECH, WAVE_FORMAT_DSPGROUP_TRUESPEECH, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, - 0x38, 0x9b, 0x71); - -// 00000075-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VOXWARE_RT29, WAVE_FORMAT_VOXWARE_RT29, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, - 0x9b, 0x71); - -// 324D4451-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_QDM2, 0x324D4451, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 63616C61-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ALAC, 0x63616C61, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// B82196E9-1B3F-4796-A636-46239087B38E dsfTAKsource specific -DEFINE_GUID(MEDIASUBTYPE_TAK, 0xB82196E9, 0x1B3F, 0x4796, 0xA6, 0x36, 0x46, 0x23, 0x90, 0x87, 0xB3, 0x8E); - -// 20534C41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ALS, 0x20534C41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 0000729A-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_729A, 0x0000729A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000133-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_G729, 0x00000133, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 36323767-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_G726, 0x36323767, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000401-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IMC, 0x00000401, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 0000011-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IMA_WAV, WAVE_FORMAT_IMA_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {A23EB7FC-510B-466F-9FBF-5F878F69347C} LAVF/LAVC specific -DEFINE_GUID(MEDIASUBTYPE_BD_LPCM_AUDIO, 0xa23eb7fc, 0x510b, 0x466f, 0x9f, 0xbf, 0x5f, 0x87, 0x8f, 0x69, 0x34, 0x7c); - -// {53544441-0000-0010-8000-00AA00389B71} AAC-ADTS LAVF/LAVC specific -#define WAVE_FORMAT_AAC_ADTS mmioFOURCC('A', 'D', 'T', 'S') -DEFINE_GUID(MEDIASUBTYPE_AAC_ADTS, WAVE_FORMAT_AAC_ADTS, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {33534541-0000-0010-8000-00AA00389B71} S302M AES3 -#define WAVE_FORMAT_S302M_AES3 mmioFOURCC('A', 'E', 'S', '3') -DEFINE_GUID(MEDIASUBTYPE_AES3, WAVE_FORMAT_S302M_AES3, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {949F97FD-56F6-4527-B4AE-DDEB375AB80F} Mpc-hc specific ! -DEFINE_GUID(MEDIASUBTYPE_HDMV_LPCM_AUDIO, 0x949f97fd, 0x56f6, 0x4527, 0xb4, 0xae, 0xdd, 0xeb, 0x37, 0x5a, 0xb8, 0xf); - -#define WAVE_FORMAT_MLP mmioFOURCC('M', 'L', 'P', ' ') -DEFINE_GUID(MEDIASUBTYPE_MLP, WAVE_FORMAT_MLP, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -#define WAVE_FORMAT_SPEEX 0xA109 -DEFINE_GUID(MEDIASUBTYPE_SPEEX, WAVE_FORMAT_SPEEX, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -#ifndef WAVE_FORMAT_OPUS -#define WAVE_FORMAT_OPUS 0x704F -#endif -DEFINE_GUID(MEDIASUBTYPE_OPUS, WAVE_FORMAT_OPUS, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_OPUS_OLD mmioFOURCC('O', 'P', 'U', 'S') -DEFINE_GUID(MEDIASUBTYPE_OPUS_OLD, WAVE_FORMAT_OPUS_OLD, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_DSDL mmioFOURCC('D', 'S', 'D', 'L') -DEFINE_GUID(MEDIASUBTYPE_DSDL, WAVE_FORMAT_DSDL, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_DSDM mmioFOURCC('D', 'S', 'D', 'M') -DEFINE_GUID(MEDIASUBTYPE_DSDM, WAVE_FORMAT_DSDM, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_DSD1 mmioFOURCC('D', 'S', 'D', '1') -DEFINE_GUID(MEDIASUBTYPE_DSD1, WAVE_FORMAT_DSD1, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_DSD8 mmioFOURCC('D', 'S', 'D', '8') -DEFINE_GUID(MEDIASUBTYPE_DSD8, WAVE_FORMAT_DSD8, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000014-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_G723, 0x00000014, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000111-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VIVO_G723, 0x00000111, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 20455041-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_APE, 0x20455041, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - - -struct WAVEFORMATEX_HDMV_LPCM : public WAVEFORMATEX -{ - BYTE channel_conf; - - struct WAVEFORMATEX_HDMV_LPCM() - { - memset(this, 0, sizeof(*this)); - cbSize = sizeof(WAVEFORMATEX_HDMV_LPCM) - sizeof(WAVEFORMATEX); - } -}; - -// {AFBC2343-3DCB-4047-9655-E1E62A61B1C5} -DEFINE_GUID(MEDIASUBTYPE_FFMPEG_AUDIO, 0xafbc2343, 0x3dcb, 0x4047, 0x96, 0x55, 0xe1, 0xe6, 0x2a, 0x61, 0xb1, 0xc5); - -// {35189950-CAC9-4C8D-819D-B6FAEE15DD9D} -DEFINE_GUID(FORMAT_WaveFormatExFFMPEG, 0x35189950, 0xcac9, 0x4c8d, 0x81, 0x9d, 0xb6, 0xfa, 0xee, 0x15, 0xdd, 0x9d); - -struct WAVEFORMATEXFFMPEG -{ - int nCodecId; - WAVEFORMATEX wfex; - - struct WAVEFORMATEXFFMPEG() - { - nCodecId = 0; - } -}; - -// {20884BC2-629F-45EA-B1C5-FA4FFA438250} -DEFINE_GUID(MEDIASUBTYPE_LAVBluRay, 0x20884bc2, 0x629f, 0x45ea, 0xb1, 0xc5, 0xfa, 0x4f, 0xfa, 0x43, 0x82, 0x50); - -// {D51BD5A3-7548-11cf-A520-0080C77EF58A} -DEFINE_GUID(CLSID_MultFile, 0xd51bd5a3, 0x7548, 0x11cf, 0xa5, 0x20, 0x0, 0x80, 0xc7, 0x7e, 0xf5, 0x8a); - -// Additionnal DXVA GUIDs - -// Intel ClearVideo VC1 bitstream decoder -DEFINE_GUID(DXVA_Intel_VC1_ClearVideo, 0xBCC5DB6D, 0xA2B6, 0x4AF0, 0xAC, 0xE4, 0xAD, 0xB1, 0xF7, 0x87, 0xBC, 0x89); -DEFINE_GUID(DXVA_Intel_VC1_ClearVideo_2, 0xE07EC519, 0xE651, 0x4CD6, 0xAC, 0x84, 0x13, 0x70, 0xCC, 0xEE, 0xC8, 0x51); - -// Intel ClearVideo H264 bitstream decoder -DEFINE_GUID(DXVA_Intel_H264_ClearVideo, 0x604F8E68, 0x4951, 0x4C54, 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6); - -// Nvidia MPEG-4 ASP bitstream decoder -// 9947EC6F-689B-11DC-A320-0019DBBC4184 -DEFINE_GUID(DXVA_MPEG4_ASP, 0x9947EC6F, 0x689B, 0x11DC, 0xA3, 0x20, 0x00, 0x19, 0xDB, 0xBC, 0x41, 0x84); - -// Filter/Commercial GUIDs - -DEFINE_GUID(CLSID_AC3Filter, 0xA753A1EC, 0x973E, 0x4718, 0xAF, 0x8E, 0xA3, 0xF5, 0x54, 0xD4, 0x5C, 0x44); - -// {212690FB-83E5-4526-8FD7-74478B7939CD} from wmcodecdsp.h -DEFINE_GUID(CLSID_CMPEG2VidDecoderDS, 0x212690FB, 0x83E5, 0x4526, 0x8F, 0xD7, 0x74, 0x47, 0x8B, 0x79, 0x39, 0xCD); - -// {39F498AF-1A09-4275-B193-673B0BA3D478} -DEFINE_GUID(CLSID_CMpeg2DecFilter, 0x39F498AF, 0x1A09, 0x4275, 0xB1, 0x93, 0x67, 0x3B, 0x0B, 0xA3, 0xD4, 0x78); - -// Nvidia Video Decoder - {71E4616A-DB5E-452B-8CA5-71D9CC7805E9} -DEFINE_GUID(CLSID_NvidiaVideoDecoder, 0x71E4616A, 0xDB5E, 0x452B, 0x8C, 0xA5, 0x71, 0xD9, 0xCC, 0x78, 0x05, 0xE9); - -// Sonic Cinemaster Video Decoder - {D7D50E8D-DD72-43C2-8587-A0C197D837D2} -DEFINE_GUID(CLSID_SonicCinemasterVideoDecoder, 0xD7D50E8D, 0xDD72, 0x43C2, 0x85, 0x87, 0xA0, 0xC1, 0x97, 0xD8, 0x37, 0xD2); - -// RDP DirectShow Redirection Filter - {AB9D6472-752F-43F6-B29E-61207BDA8E06} -DEFINE_GUID(CLSID_RDPDShowRedirectionFilter, 0xAB9D6472, 0x752F, 0x43F6, 0xB2, 0x9E, 0x61, 0x20, 0x7B, 0xDA, 0x8E, 0x06); - -// ReClock - {9DC15360-914C-46B8-B9DF-E67FD36C6A} -DEFINE_GUID(CLSID_ReClock, 0x9DC15360, 0x914C, 0x46B8, 0xB9, 0xDF, 0xBF, 0xE6, 0x7F, 0xD3, 0x6C, 0x6A); - -// MPC(BE) Audio Renderer - {601D2A2B-9CDE-40BD-8650-0485E3522727} -DEFINE_GUID(CLSID_MPCBEAudioRenderer, 0x601D2A2B, 0x9CDE, 0x40BD, 0x86, 0x50, 0x04, 0x85, 0xE3, 0x52, 0x27, 0x27); - -// Morgan's Stream Switcher - {D3CD7858-971A-4838-ACEC-40CA5D529DC8} -DEFINE_GUID(CLSID_MorganStreamSwitcher, 0xD3CD7858, 0x971A, 0x4838, 0xAC, 0xEC, 0x40, 0xCA, 0x5D, 0x52, 0x9D, 0xC8); - -// FFDShow DXVA Decoder - {0B0EFF97-C750-462C-9488-B10E7D87F1A6} -DEFINE_GUID(CLSID_FFDShowDXVADecoder, 0x0B0EFF97, 0xC750, 0x462C, 0x94, 0x88, 0xB1, 0x0E, 0x7D, 0x87, 0xF1, 0xA6); - -// Microsoft DTV-DVD Audio Decoder - {E1F1A0B8-BEEE-490D-BA7C-066C40B5E2B9} -DEFINE_GUID(CLSID_MSDVTDVDAudioDecoder, 0xE1F1A0B8, 0xBEEE, 0x490D, 0xBA, 0x7C, 0x06, 0x6C, 0x40, 0xB5, 0xE2, 0xB9); - -// Old MPC-HC filters -DEFINE_GUID(CLSID_MPCMpegSplitter, 0xDC257063, 0x045F, 0x4BE2, 0xBD, 0x5B, 0xE1, 0x22, 0x79, 0xC4, 0x64, 0xF0); -DEFINE_GUID(CLSID_MPCMpegSplitterSource, 0x1365BE7A, 0xC86A, 0x473C, 0x9A, 0x41, 0xC0, 0xA6, 0xE8, 0x2C, 0x9F, 0xA3); -DEFINE_GUID(CLSID_MPCVideoDecoder, 0x008BAC12, 0xFBAF, 0x497b, 0x96, 0x70, 0xBC, 0x6F, 0x6F, 0xBA, 0xE2, 0xC4); -DEFINE_GUID(CLSID_MPCShoutcastSource, 0x68F540E9, 0x766F, 0x44d2, 0xAB, 0x07, 0xE2, 0x6C, 0xC6, 0xD2, 0x7A, 0x79); - -// DirectVobSub || VSFilter (auto-loading version) - {9852A670-F845-491B-9BE6-EBD841B8A613} -DEFINE_GUID(CLSID_VSFilter, 0x9852A670, 0xF845, 0x491B, 0x9B, 0xE6, 0xEB, 0xD8, 0x41, 0xB8, 0xA6, 0x13); - -// DirectVobSub || VSFilter - {93A22E7A-5091-45EF-BA61-6DA26156A5D0} -DEFINE_GUID(CLSID_VSFilter2, 0x93A22E7A, 0x5091, 0x45EF, 0xBA, 0x61, 0x6D, 0xA2, 0x61, 0x56, 0xA5, 0xD0); - -// XySubFilter - {2DFCB782-EC20-4A7C-B530-4577ADB33F21} -DEFINE_GUID(CLSID_XySubFilter, 0x2DFCB782, 0xEC20, 0x4A7C, 0xB5, 0x30, 0x45, 0x77, 0xAD, 0xB3, 0x3F, 0x21); - -// XySubFilterAutoLoader - {6B237877-902B-4C6C-92F6-E63169A5166C} -DEFINE_GUID(CLSID_XySubFilter_AutoLoader, 0x6B237877, 0x902B, 0x4C6C, 0x92, 0xF6, 0xE6, 0x31, 0x69, 0xA5, 0x16, 0x6C); - -// sanear (internal version) -// SaneAudioRenderer::Factory::GetFilterGuid() is the right way do optain it, -// but we link DSUtil to everything and consequently will have to link sanear to everything. -DEFINE_GUID(CLSID_SANEAR_INTERNAL, 0x2AE00773, 0x819A, 0x40FB, 0xA5, 0x54, 0x54, 0x82, 0x7E, 0x11, 0x63, 0x59); - -// sanear (standalone version) - {DF557071-C9FD-433A-9627-81E0D3640ED9} -DEFINE_GUID(CLSID_SANEAR, 0xdf557071, 0xc9fd, 0x433a, 0x96, 0x27, 0x81, 0xe0, 0xd3, 0x64, 0xe, 0xd9); - -// AssFilter - {8A3704F3-BE3B-4944-9FF3-EE8757FDBDA5} -DEFINE_GUID(CLSID_AssFilter, 0x8A3704F3, 0xBE3B, 0x4944, 0x9F, 0xF3, 0xEE, 0x87, 0x57, 0xFD, 0xBD, 0xA5); - -// AssFilterAutoLoader - {8A6DFC6A-0A79-4790-85DA-0688B8093B54} -DEFINE_GUID(CLSID_AssFilter_AutoLoader, 0x8A6DFC6A, 0x0A79, 0x4790, 0x85, 0xDA, 0x06, 0x88, 0xB8, 0x09, 0x3B, 0x54); - -// Generate Still Video - {7DF62B50-6843-11D2-9EEB-006008039E37} -DEFINE_GUID(CLSID_StillVideo, 0x7DF62B50, 0x6843, 0x11D2, 0x9E, 0xEB, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); - -// MPC Image Source - {7DB5C3B3-2419-4508-B1D0-F2D22DA8E439} -DEFINE_GUID(CLSID_MPCImageSource, 0x7DB5C3B3, 0x2419, 0x4508, 0xB1, 0xD0, 0xF2, 0xD2, 0x2D, 0xA8, 0xE4, 0x39); - -DEFINE_GUID(CLSID_Generic_WDM_FilterProxy, 0x17CCA71B, 0xECD7, 0x11D0, 0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96); - -// uncompressed -#define DEFINE_GUID_FOURCC(FOURCC) \ - DEFINE_GUID(MEDIASUBTYPE_##FOURCC, FOURCC_##FOURCC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -//uncompressed -#define FOURCC_YUY2 mmioFOURCC('Y','U','Y','2') -#define FOURCC_V422 mmioFOURCC('V','4','2','2') -#define FOURCC_YV12 mmioFOURCC('Y','V','1','2') -#define FOURCC_YVYU mmioFOURCC('Y','V','Y','U') -#define FOURCC_UYVY mmioFOURCC('U','Y','V','Y') -#define FOURCC_YUYV mmioFOURCC('Y','U','Y','V') -#define FOURCC_VYUY mmioFOURCC('V','Y','U','Y') -#define FOURCC_I420 mmioFOURCC('I','4','2','0') -#define FOURCC_IYUV mmioFOURCC('I','Y','U','V') -#define FOURCC_444P mmioFOURCC('4','4','4','P') -#define FOURCC_YV24 mmioFOURCC('Y','V','2','4') // YUV 4:4:4 -#define FOURCC_422P mmioFOURCC('4','2','2','P') -#define FOURCC_YV16 mmioFOURCC('Y','V','1','6') // YUV 4:2:2 -#define FOURCC_411P mmioFOURCC('4','1','1','P') -#define FOURCC_Y41B mmioFOURCC('Y','4','1','B') // YUV 4:1:1 -#define FOURCC_410P mmioFOURCC('4','1','0','P') -#define FOURCC_PAL1 mmioFOURCC('P','A','L','1') -#define FOURCC_PAL4 mmioFOURCC('P','A','L','4') -#define FOURCC_PAL8 mmioFOURCC('P','A','L','8') -#define FOURCC_RGB2 mmioFOURCC('R','G','B','2') -#define FOURCC_RGB3 mmioFOURCC('R','G','B','3') -#define FOURCC_RGB5 mmioFOURCC('R','G','B','5') -#define FOURCC_RGB6 mmioFOURCC('R','G','B','6') -#define FOURCC_CLJR mmioFOURCC('C','L','J','R') -#define FOURCC_Y800 mmioFOURCC('Y','8','0','0') -#define FOURCC_NV12 mmioFOURCC('N','V','1','2') -#define FOURCC_NV21 mmioFOURCC('N','V','2','1') -#define FOURCC_P010 mmioFOURCC('P','0','1','0') -#define FOURCC_P016 mmioFOURCC('P','0','1','6') -#define FOURCC_420R mmioFOURCC('4','2','0','R') -#define FOURCC_422R mmioFOURCC('4','2','2','R') -#define FOURCC_444R mmioFOURCC('4','4','4','R') -#define FOURCC_P210 mmioFOURCC('P','2','1','0') -#define FOURCC_P216 mmioFOURCC('P','2','1','6') -#define FOURCC_AYUV mmioFOURCC('A','Y','U','V') -#define FOURCC_Y416 mmioFOURCC('Y','4','1','6') - -#define FOURCC_nv12 mmioFOURCC('n','v','1','2') -#define FOURCC_yv12 mmioFOURCC('y','v','1','2') -#define FOURCC_ICM1 mmioFOURCC('I','C','M','1') -#define FOURCC_ICM2 mmioFOURCC('I','C','M','2') -#define FOURCC_ICM3 mmioFOURCC('I','C','M','3') -#define FOURCC_ICM4 mmioFOURCC('I','C','M','4') -#define FOURCC_yuy2 mmioFOURCC('y','u','y','2') -#define FOURCC_uyvy mmioFOURCC('u','y','v','y') -#define FOURCC_cyuv mmioFOURCC('c','y','u','v') -#define FOURCC_UYNV mmioFOURCC('U','Y','N','V') -#define FOURCC_UYNY mmioFOURCC('U','Y','N','Y') -#define FOURCC_HDYC mmioFOURCC('H','D','Y','C') -#define FOURCC_uyv1 mmioFOURCC('u','y','v','1') -#define FOURCC_2Vu1 mmioFOURCC('2','V','u','1') -#define FOURCC_VDTZ mmioFOURCC('V','D','T','Z') -#define FOURCC_YUV2 mmioFOURCC('Y','U','V','2') -#define FOURCC_yuv2 mmioFOURCC('y','u','v','2') -#define FOURCC_2vuy mmioFOURCC('2','v','u','y') -#define FOURCC_2Vuy mmioFOURCC('2','V','u','y') -#define FOURCC_yuvu mmioFOURCC('y','u','v','u') -#define FOURCC_yuvs mmioFOURCC('y','u','v','s') -#define FOURCC_I422 mmioFOURCC('I','4','2','2') -#define FOURCC_Y422 mmioFOURCC('Y','4','2','2') -#define FOURCC_V422 mmioFOURCC('V','4','2','2') -#define FOURCC_Y42B mmioFOURCC('Y','4','2','B') -#define FOURCC_P422 mmioFOURCC('P','4','2','2') -#define FOURCC_YUNV mmioFOURCC('Y','U','N','V') -#define FOURCC_AVUI mmioFOURCC('A','V','U','I') -#define FOURCC_I444 mmioFOURCC('I','4','4','4') -#define FOURCC_v308 mmioFOURCC('v','3','0','8') -#define FOURCC_v408 mmioFOURCC('v','4','0','8') -#define FOURCC_24BG mmioFOURCC('2','4','B','G') -#define FOURCC_BGRA mmioFOURCC('B','G','R','A') -#define FOURCC_ABGR mmioFOURCC('A','B','G','R') -#define FOURCC_RGBA mmioFOURCC('R','G','B','A') -#define FOURCC_RGB0 mmioFOURCC('R','G','B','0') -#define FOURCC_0RGB mmioFOURCC('0','R','G','B') -#define FOURCC_b48r mmioFOURCC('b','4','8','r') -#define FOURCC_RBA64 mmioFOURCC('R','B','A',64) -#define FOURCC_64RBA mmioFOURCC(64,'R','B','A') -#define FOURCC_b64a mmioFOURCC('b','6','4','a') -#define FOURCC_Y410 mmioFOURCC('Y','4','1','0') -#define FOURCC_v216 mmioFOURCC('v','2','1','6') -#define FOURCC_v416 mmioFOURCC('v','4','1','6') -#define FOURCC_Y8 mmioFOURCC('Y','8',0x20,0x20) -#define FOURCC_Y16 mmioFOURCC('Y','1',0,16) - -DEFINE_GUID_FOURCC(422P) -DEFINE_GUID_FOURCC(444P) -DEFINE_GUID_FOURCC(411P) -DEFINE_GUID_FOURCC(410P) -DEFINE_GUID_FOURCC(VYUY) -DEFINE_GUID_FOURCC(Y800) -DEFINE_GUID_FOURCC(NV21) -DEFINE_GUID_FOURCC(YV16) -DEFINE_GUID_FOURCC(YV24) -DEFINE_GUID_FOURCC(420R) -DEFINE_GUID_FOURCC(422R) -DEFINE_GUID_FOURCC(444R) -DEFINE_GUID_FOURCC(Y416) - -DEFINE_GUID_FOURCC(nv12) -DEFINE_GUID_FOURCC(yv12) -DEFINE_GUID_FOURCC(ICM1) -DEFINE_GUID_FOURCC(ICM2) -DEFINE_GUID_FOURCC(ICM3) -DEFINE_GUID_FOURCC(ICM4) -DEFINE_GUID_FOURCC(yuy2) -DEFINE_GUID_FOURCC(uyvy) -DEFINE_GUID_FOURCC(cyuv) -DEFINE_GUID_FOURCC(UYNV) -DEFINE_GUID_FOURCC(UYNY) -DEFINE_GUID_FOURCC(HDYC) -DEFINE_GUID_FOURCC(uyv1) -DEFINE_GUID_FOURCC(2Vu1) -DEFINE_GUID_FOURCC(VDTZ) -DEFINE_GUID_FOURCC(YUV2) -DEFINE_GUID_FOURCC(yuv2) -DEFINE_GUID_FOURCC(2vuy) -DEFINE_GUID_FOURCC(2Vuy) -DEFINE_GUID_FOURCC(yuvu) -DEFINE_GUID_FOURCC(yuvs) -DEFINE_GUID_FOURCC(I422) -DEFINE_GUID_FOURCC(Y422) -DEFINE_GUID_FOURCC(V422) -DEFINE_GUID_FOURCC(Y42B) -DEFINE_GUID_FOURCC(P422) -DEFINE_GUID_FOURCC(YUNV) -DEFINE_GUID_FOURCC(AVUI) -DEFINE_GUID_FOURCC(I444) -DEFINE_GUID_FOURCC(v308) -DEFINE_GUID_FOURCC(v408) -DEFINE_GUID_FOURCC(24BG) -DEFINE_GUID_FOURCC(BGRA) -DEFINE_GUID_FOURCC(ABGR) -DEFINE_GUID_FOURCC(RGBA) -DEFINE_GUID_FOURCC(RGB0) -DEFINE_GUID_FOURCC(0RGB) -DEFINE_GUID_FOURCC(b48r) -DEFINE_GUID_FOURCC(RBA64) -DEFINE_GUID_FOURCC(64RBA) -DEFINE_GUID_FOURCC(b64a) -DEFINE_GUID_FOURCC(Y410) -DEFINE_GUID_FOURCC(v216) -DEFINE_GUID_FOURCC(v416) -DEFINE_GUID_FOURCC(Y8) -DEFINE_GUID_FOURCC(Y16) +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#define WAVE_FORMAT_DOLBY_AC3 0x2000 +// {00002000-0000-0010-8000-00aa00389b71} +DEFINE_GUID(MEDIASUBTYPE_WAVE_DOLBY_AC3, WAVE_FORMAT_DOLBY_AC3, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, + 0x9b, 0x71); + +#define WAVE_FORMAT_DVD_DTS 0x2001 +// {00002001-0000-0010-8000-00aa00389b71} +DEFINE_GUID(MEDIASUBTYPE_WAVE_DTS, WAVE_FORMAT_DVD_DTS, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// Be compatible with 3ivx +#define WAVE_FORMAT_AAC 0x00FF +// {000000FF-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_AAC, WAVE_FORMAT_AAC, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_LATM_AAC 0x01FF +// {000001FF-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_LATM_AAC, WAVE_FORMAT_LATM_AAC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +// ... and also compatible with nero +// btw, older nero parsers use a lower-case fourcc, newer upper-case (why can't it just offer both?) +// {4134504D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_MP4A, 0x4134504D, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {6134706D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_mp4a, 0x6134706D, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_MP3 0x0055 +// 00000055-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MP3, WAVE_FORMAT_MP3, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_FLAC 0xF1AC +// 0000F1AC-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FLAC, WAVE_FORMAT_FLAC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {1541C5C0-CDDF-477d-BC0A-86F8AE7F8354} +DEFINE_GUID(MEDIASUBTYPE_FLAC_FRAMED, 0x1541c5c0, 0xcddf, 0x477d, 0xbc, 0xa, 0x86, 0xf8, 0xae, 0x7f, 0x83, 0x54); + +#define WAVE_FORMAT_TTA1 0x77A1 +// {000077A1-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_TTA1, WAVE_FORMAT_TTA1, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_WAVPACK4 0x5756 +// {00005756-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_WAVPACK4, WAVE_FORMAT_WAVPACK4, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_AMR, 0x000000FE, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// {726D6173-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_SAMR, 0x726D6173, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VP70, 0x30375056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VP80, 0x30385056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VP90, 0x30395056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_AV01, 0x31305641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_IMA4, 0x34616D69, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// {34616D69-0000-0010-8000-00AA00389B71} + +DEFINE_GUID(MEDIASUBTYPE_SAWB, 0x62776173, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {DA5B82EE-6BD2-426f-BF1E-30112DA78AE1} +DEFINE_GUID(MEDIASUBTYPE_SVCD_SUBPICTURE, 0xda5b82ee, 0x6bd2, 0x426f, 0xbf, 0x1e, 0x30, 0x11, 0x2d, 0xa7, 0x8a, 0xe1); + +// {7B57308F-5154-4c36-B903-52FE76E184FC} +DEFINE_GUID(MEDIASUBTYPE_CVD_SUBPICTURE, 0x7b57308f, 0x5154, 0x4c36, 0xb9, 0x3, 0x52, 0xfe, 0x76, 0xe1, 0x84, 0xfc); + +// {0E3A2342-F6E2-4c91-BDAE-87C71EAD0D63} +DEFINE_GUID(MEDIASUBTYPE_MPEG2_PVA, 0xe3a2342, 0xf6e2, 0x4c91, 0xbd, 0xae, 0x87, 0xc7, 0x1e, 0xad, 0xd, 0x63); + +// {6B6D0800-9ADA-11d0-A520-00A0D10129C0} +DEFINE_GUID(CLSID_NetShowSource, 0x6b6d0800, 0x9ada, 0x11d0, 0xa5, 0x20, 0x0, 0xa0, 0xd1, 0x1, 0x29, 0xc0); + +// DirectShowMedia + +// {5E9C9EE0-2E4A-4f22-9906-7BBBB75AA2B6} +DEFINE_GUID(MEDIASUBTYPE_DirectShowMedia, 0x5e9c9ee0, 0x2e4a, 0x4f22, 0x99, 0x6, 0x7b, 0xbb, 0xb7, 0x5a, 0xa2, 0xb6); + +// Dirac + +// {A29DA00F-A22B-40ea-98DE-2F7FECADA5DE} +DEFINE_GUID(MEDIASUBTYPE_Dirac, 0xa29da00f, 0xa22b, 0x40ea, 0x98, 0xde, 0x2f, 0x7f, 0xec, 0xad, 0xa5, 0xde); + +// {64726376-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_DiracVideo, 0x64726376, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {D2667A7E-4055-4244-A65F-DDDDF2B74BD7} +DEFINE_GUID(FORMAT_DiracVideoInfo, 0xd2667a7e, 0x4055, 0x4244, 0xa6, 0x5f, 0xdd, 0xdd, 0xf2, 0xb7, 0x4b, 0xd7); + +// {63617264-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_DRAC, 0x63617264, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +struct DIRACINFOHEADER +{ + VIDEOINFOHEADER2 hdr; + DWORD cbSequenceHeader; + DWORD dwSequenceHeader[1]; +}; + +// MP4 + +// {08E22ADA-B715-45ed-9D20-7B87750301D4} +DEFINE_GUID(MEDIASUBTYPE_MP4, 0x8e22ada, 0xb715, 0x45ed, 0x9d, 0x20, 0x7b, 0x87, 0x75, 0x3, 0x1, 0xd4); + +// FLV + +// {F2FAC0F1-3852-4670-AAC0-9051D400AC54} +DEFINE_GUID(MEDIASUBTYPE_FLV, 0xf2fac0f1, 0x3852, 0x4670, 0xaa, 0xc0, 0x90, 0x51, 0xd4, 0x0, 0xac, 0x54); + +// 31564C46-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FLV1, 0x31564C46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31766C66-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_flv1, 0x31766C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34564C46-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FLV4, 0x34564C46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34766C66-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_flv4, 0x34766C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30355056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP50, 0x30355056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30357076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp50, 0x30357076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP60, 0x30365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp60, 0x30367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP61, 0x31365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp61, 0x31367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP62, 0x32365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp62, 0x32367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 41365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP6A, 0x41365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 61367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp6a, 0x61367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 46365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP6F, 0x46365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 66367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp6f, 0x66367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// +// RealMedia +// + +enum +{ + WAVE_FORMAT_14_4 = 0x2002, + WAVE_FORMAT_28_8 = 0x2003, + WAVE_FORMAT_ATRC = 0x0270, // WAVE_FORMAT_SONY_SCX, + WAVE_FORMAT_COOK = 0x2004, + WAVE_FORMAT_DNET = 0x2005, + WAVE_FORMAT_RAAC = 0x2006, + WAVE_FORMAT_RACP = 0x2007, + WAVE_FORMAT_SIPR = 0x0130, // WAVE_FORMAT_SIPROLAB_ACEPLNET, +}; + +// {57428EC6-C2B2-44a2-AA9C-28F0B6A5C48E} +DEFINE_GUID(MEDIASUBTYPE_RealMedia, 0x57428ec6, 0xc2b2, 0x44a2, 0xaa, 0x9c, 0x28, 0xf0, 0xb6, 0xa5, 0xc4, 0x8e); + +// 30315652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV10, 0x30315652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30325652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV20, 0x30325652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30335652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV30, 0x30335652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30345652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV40, 0x30345652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31345652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV41, 0x31345652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 345f3431-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_14_4, 0x345f3431, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 385f3832-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_28_8, 0x385f3832, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4b4f4f43-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_COOK, 0x4b4f4f43, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 54454e44-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DNET, 0x54454e44, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 52504953-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SIPR, 0x52504953, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 00000130-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SIPR_WAVE, WAVE_FORMAT_SIPR, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43414152-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RAAC, 0x43414152, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 50434152-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RACP, 0x50434152, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +#define WAVE_FORMAT_RALF mmioFOURCC('R', 'A', 'L', 'F') +DEFINE_GUID(MEDIASUBTYPE_RALF, WAVE_FORMAT_RALF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// QuickTime PCM + +// 454E4F4E-0000-0010-8000-00AA00389B71 (unsigned 8-bit) +DEFINE_GUID(MEDIASUBTYPE_PCM_NONE, 0x454E4F4E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 20776172-0000-0010-8000-00AA00389B71 (unsigned 8-bit, signed big-endian 16 bit) +DEFINE_GUID(MEDIASUBTYPE_PCM_RAW, 0x20776172, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 736f7774-0000-0010-8000-00AA00389B71 (signed 8-bit, signed big-endian 16-bit) +DEFINE_GUID(MEDIASUBTYPE_PCM_TWOS, 0x736f7774, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 74776f73-0000-0010-8000-00AA00389B71 (signed 8-bit, signed little-endian 16-bit) +DEFINE_GUID(MEDIASUBTYPE_PCM_SOWT, 0x74776f73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34326E69-0000-0010-8000-00AA00389B71 (signed big-endian int24) +DEFINE_GUID(MEDIASUBTYPE_PCM_IN24, 0x34326E69, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32336E69-0000-0010-8000-00AA00389B71 (signed big-endian int32) +DEFINE_GUID(MEDIASUBTYPE_PCM_IN32, 0x32336E69, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32336C66-0000-0010-8000-00AA00389B71 (signed big-endian float32) +DEFINE_GUID(MEDIASUBTYPE_PCM_FL32, 0x32336C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34366C66-0000-0010-8000-00AA00389B71 (signed big-endian float64) +DEFINE_GUID(MEDIASUBTYPE_PCM_FL64, 0x34366C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Reverse GUIDs for little-endian 'in24', 'in32', 'fl32', 'fl64' +// 696E3234-0000-0010-8000-00AA00389B71 (signed little-endian int24, reverse 'in24') +DEFINE_GUID(MEDIASUBTYPE_PCM_IN24_le, 0x696E3234, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 696E3332-0000-0010-8000-00AA00389B71 (signed little-endian int32, reverse 'in32') +DEFINE_GUID(MEDIASUBTYPE_PCM_IN32_le, 0x696E3332, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 666C3332-0000-0010-8000-00AA00389B71 (signed little-endian float32, reverse 'fl32') +DEFINE_GUID(MEDIASUBTYPE_PCM_FL32_le, 0x666C3332, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 666C3634-0000-0010-8000-00AA00389B71 (signed little-endian float64, reverse 'fl64') +DEFINE_GUID(MEDIASUBTYPE_PCM_FL64_le, 0x666C3634, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// +// PS2 +// + +#define WAVE_FORMAT_PS2_PCM 0xF521 +// 0000F521-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_PS2_PCM, WAVE_FORMAT_PS2_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_PS2_ADPCM 0xF522 +// 0000F522-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_PS2_ADPCM, WAVE_FORMAT_PS2_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +#define WAVE_FORMAT_ADPCM_SWF 0x5346 +// 00005346-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ADPCM_SWF, + WAVE_FORMAT_ADPCM_SWF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 41564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ADPCM_AMV, + 0x41564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + + +struct WAVEFORMATEXPS2 : public WAVEFORMATEX +{ + DWORD dwInterleave; + + struct WAVEFORMATEXPS2() + { + memset(this, 0, sizeof(*this)); + cbSize = sizeof(WAVEFORMATEXPS2) - sizeof(WAVEFORMATEX); + } +}; + +// {4F3D3D21-6D7C-4f73-AA05-E397B5EAE0AA} +DEFINE_GUID(MEDIASUBTYPE_PS2_SUB, 0x4f3d3d21, 0x6d7c, 0x4f73, 0xaa, 0x5, 0xe3, 0x97, 0xb5, 0xea, 0xe0, 0xaa); + +// ATRAC + +// 43525441-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ATRC, 0x43525441, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 00000270-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ATRAC3, WAVE_FORMAT_SONY_SCX, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +#define WAVE_FORMAT_ATRAC3P 0xE923AABF +// E923AABF-CB58-4471-A119-FFFA01E4CE62 +DEFINE_GUID(MEDIASUBTYPE_ATRAC3P, 0xE923AABF, 0xCB58, 0x4471, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62); + +// Haali's video renderer + +// {760A8F35-97E7-479d-AAF5-DA9EFF95D751} +DEFINE_GUID(CLSID_DXR, 0x760a8f35, 0x97e7, 0x479d, 0xaa, 0xf5, 0xda, 0x9e, 0xff, 0x95, 0xd7, 0x51); + +// {E1A8B82A-32CE-4B0D-BE0D-AA68C772E423} +DEFINE_GUID(CLSID_MadVR, 0xE1A8B82A, 0x32CE, 0x4B0D, 0xBE, 0x0D, 0xAA, 0x68, 0xC7, 0x72, 0xE4, 0x23); + +// {71F080AA-8661-4093-B15E-4F6903E77D0A} +DEFINE_GUID(CLSID_MPCVR, 0x71F080AA, 0x8661, 0x4093, 0xB1, 0x5E, 0x4F, 0x69, 0x03, 0xE7, 0x7D, 0x0A); + +// {C1F400A4-3F08-11D3-9F0B-006008039E37} +DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11D3, 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); + +// {A0025E90-E45B-11D1-ABE9-00A0C905F375} +DEFINE_GUID(CLSID_OverlayMixer2, 0xA0025E90, 0xE45B, 0x11D1, 0xAB, 0xE9, 0x00, 0xA0, 0xC9, 0x05, 0xF3, 0x75); + +// +// Ogg +// + +// 9FF48807-E133-40AA-826F-9B2959E5232D +DEFINE_GUID(CLSID_MPCHCOggSplitter, 0x9FF48807, 0xE133, 0x40AA, 0x82, 0x6F, 0x9B, 0x29, 0x59, 0xE5, 0x23, 0x2D); + +// 6D3688CE-3E9D-42F4-92CA-8A11119D25CD +DEFINE_GUID(CLSID_MPCHCOggSource, 0x6D3688CE, 0x3E9D, 0x42F4, 0x92, 0xCA, 0x8A, 0x11, 0x11, 0x9D, 0x25, 0xCD); + +// f07e245f-5a1f-4d1e-8bff-dc31d84a55ab +DEFINE_GUID(CLSID_OggSplitter, 0xf07e245f, 0x5a1f, 0x4d1e, 0x8b, 0xff, 0xdc, 0x31, 0xd8, 0x4a, 0x55, 0xab); + +// {078C3DAA-9E58-4d42-9E1C-7C8EE79539C5} +DEFINE_GUID(CLSID_OggSplitPropPage, 0x78c3daa, 0x9e58, 0x4d42, 0x9e, 0x1c, 0x7c, 0x8e, 0xe7, 0x95, 0x39, 0xc5); + +// 8cae96b7-85b1-4605-b23c-17ff5262b296 +DEFINE_GUID(CLSID_OggMux, 0x8cae96b7, 0x85b1, 0x4605, 0xb2, 0x3c, 0x17, 0xff, 0x52, 0x62, 0xb2, 0x96); + +// {AB97AFC3-D08E-4e2d-98E0-AEE6D4634BA4} +DEFINE_GUID(CLSID_OggMuxPropPage, 0xab97afc3, 0xd08e, 0x4e2d, 0x98, 0xe0, 0xae, 0xe6, 0xd4, 0x63, 0x4b, 0xa4); + +// {889EF574-0656-4B52-9091-072E52BB1B80} +DEFINE_GUID(CLSID_VorbisEnc, 0x889ef574, 0x0656, 0x4b52, 0x90, 0x91, 0x07, 0x2e, 0x52, 0xbb, 0x1b, 0x80); + +// {c5379125-fd36-4277-a7cd-fab469ef3a2f} +DEFINE_GUID(CLSID_VorbisEncPropPage, 0xc5379125, 0xfd36, 0x4277, 0xa7, 0xcd, 0xfa, 0xb4, 0x69, 0xef, 0x3a, 0x2f); + +// 02391f44-2767-4e6a-a484-9b47b506f3a4 +DEFINE_GUID(CLSID_VorbisDec, 0x02391f44, 0x2767, 0x4e6a, 0xa4, 0x84, 0x9b, 0x47, 0xb5, 0x06, 0xf3, 0xa4); + +// 77983549-ffda-4a88-b48f-b924e8d1f01c +DEFINE_GUID(CLSID_OggDSAboutPage, 0x77983549, 0xffda, 0x4a88, 0xb4, 0x8f, 0xb9, 0x24, 0xe8, 0xd1, 0xf0, 0x1c); + +// {D2855FA9-61A7-4db0-B979-71F297C17A04} +DEFINE_GUID(MEDIASUBTYPE_Ogg, 0xd2855fa9, 0x61a7, 0x4db0, 0xb9, 0x79, 0x71, 0xf2, 0x97, 0xc1, 0x7a, 0x4); + +// cddca2d5-6d75-4f98-840e-737bedd5c63b +DEFINE_GUID(MEDIASUBTYPE_Vorbis, 0xcddca2d5, 0x6d75, 0x4f98, 0x84, 0x0e, 0x73, 0x7b, 0xed, 0xd5, 0xc6, 0x3b); + +// 6bddfa7e-9f22-46a9-ab5e-884eff294d9f +DEFINE_GUID(FORMAT_VorbisFormat, 0x6bddfa7e, 0x9f22, 0x46a9, 0xab, 0x5e, 0x88, 0x4e, 0xff, 0x29, 0x4d, 0x9f); + +typedef struct tagVORBISFORMAT +{ + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nMinBitsPerSec; + DWORD nAvgBitsPerSec; + DWORD nMaxBitsPerSec; + float fQuality; +} VORBISFORMAT, *PVORBISFORMAT, FAR *LPVORBISFORMAT; + +// {8D2FD10B-5841-4a6b-8905-588FEC1ADED9} +DEFINE_GUID(MEDIASUBTYPE_Vorbis2, 0x8d2fd10b, 0x5841, 0x4a6b, 0x89, 0x5, 0x58, 0x8f, 0xec, 0x1a, 0xde, 0xd9); + +// {B36E107F-A938-4387-93C7-55E966757473} +DEFINE_GUID(FORMAT_VorbisFormat2, 0xb36e107f, 0xa938, 0x4387, 0x93, 0xc7, 0x55, 0xe9, 0x66, 0x75, 0x74, 0x73); + +typedef struct tagVORBISFORMAT2 +{ + DWORD Channels; + DWORD SamplesPerSec; + DWORD BitsPerSample; + DWORD HeaderSize[3]; // 0: Identification, 1: Comment, 2: Setup +} VORBISFORMAT2, *PVORBISFORMAT2, FAR *LPVORBISFORMAT2; + +// +// Matroska +// + +// {1AC0BEBD-4D2B-45ad-BCEB-F2C41C5E3788} +DEFINE_GUID(MEDIASUBTYPE_Matroska, 0x1ac0bebd, 0x4d2b, 0x45ad, 0xbc, 0xeb, 0xf2, 0xc4, 0x1c, 0x5e, 0x37, 0x88); + +// {E487EB08-6B26-4be9-9DD3-993434D313FD} +DEFINE_GUID(MEDIATYPE_Subtitle, 0xe487eb08, 0x6b26, 0x4be9, 0x9d, 0xd3, 0x99, 0x34, 0x34, 0xd3, 0x13, 0xfd); + +// {87C0B230-03A8-4fdf-8010-B27A5848200D} +DEFINE_GUID(MEDIASUBTYPE_UTF8, 0x87c0b230, 0x3a8, 0x4fdf, 0x80, 0x10, 0xb2, 0x7a, 0x58, 0x48, 0x20, 0xd); + +// {3020560F-255A-4ddc-806E-6C5CC6DCD70A} +DEFINE_GUID(MEDIASUBTYPE_SSA, 0x3020560f, 0x255a, 0x4ddc, 0x80, 0x6e, 0x6c, 0x5c, 0xc6, 0xdc, 0xd7, 0xa); + +// {326444F7-686F-47ff-A4B2-C8C96307B4C2} +DEFINE_GUID(MEDIASUBTYPE_ASS, 0x326444f7, 0x686f, 0x47ff, 0xa4, 0xb2, 0xc8, 0xc9, 0x63, 0x7, 0xb4, 0xc2); + +// {370689E7-B226-4f67-978D-F10BC1A9C6AE} +DEFINE_GUID(MEDIASUBTYPE_ASS2, 0x370689e7, 0xb226, 0x4f67, 0x97, 0x8d, 0xf1, 0xb, 0xc1, 0xa9, 0xc6, 0xae); + +// {76C421C4-DB89-42ec-936E-A9FBC1794714} +DEFINE_GUID(MEDIASUBTYPE_SSF, 0x76c421c4, 0xdb89, 0x42ec, 0x93, 0x6e, 0xa9, 0xfb, 0xc1, 0x79, 0x47, 0x14); + +// {B753B29A-0A96-45be-985F-68351D9CAB90} +DEFINE_GUID(MEDIASUBTYPE_USF, 0xb753b29a, 0xa96, 0x45be, 0x98, 0x5f, 0x68, 0x35, 0x1d, 0x9c, 0xab, 0x90); + +// {F7239E31-9599-4e43-8DD5-FBAF75CF37F1} +DEFINE_GUID(MEDIASUBTYPE_VOBSUB, 0xf7239e31, 0x9599, 0x4e43, 0x8d, 0xd5, 0xfb, 0xaf, 0x75, 0xcf, 0x37, 0xf1); + +// {A33D2F7D-96BC-4337-B23B-A8B9FBC295E9} +DEFINE_GUID(FORMAT_SubtitleInfo, 0xa33d2f7d, 0x96bc, 0x4337, 0xb2, 0x3b, 0xa8, 0xb9, 0xfb, 0xc2, 0x95, 0xe9); + +// {04EBA53E-9330-436c-9133-553EC87031DC} +DEFINE_GUID(MEDIASUBTYPE_HDMVSUB, 0x4eba53e, 0x9330, 0x436c, 0x91, 0x33, 0x55, 0x3e, 0xc8, 0x70, 0x31, 0xdc); + +// {C886D215-F485-40BB-8DB6-FADBC619A45D} +DEFINE_GUID(MEDIASUBTYPE_WEBVTT, 0xc886d215, 0xf485, 0x40bb, 0x8d, 0xb6, 0xfa, 0xdb, 0xc6, 0x19, 0xa4, 0x5d); + +#pragma pack(push, 1) +typedef struct +{ + DWORD dwOffset; + CHAR IsoLang[4]; // three letter lang code + terminating zero + WCHAR TrackName[256]; // 256 chars ought to be enough for everyone :) +} SUBTITLEINFO; +#pragma pack(pop) + +// SUBTITLEINFO structure content starting at dwOffset (also the content of CodecPrivate) +// -------------------------------------------------------------------------------------- +// +// Here the text should start with the Byte Order Mark, even though +// UTF-8 is preferred, it also helps identifying the encoding type. +// +// MEDIASUBTYPE_USF: +// +// +// +// +// +// +// ... every element excluding ... +// +// +// MEDIASUBTYPE_SSA/ASS: +// +// The file header and all sub-sections except [Events] +// +// MEDIATYPE_VOBSUB: +// +// TODO +// + +// Data description of the media samples (everything is UTF-8 encoded here) +// ------------------------------------------------------------------------ +// +// MEDIASUBTYPE_USF: +// +// The text _inside_ the .. element. +// +// Since timing is set on the sample, there is no need to put +// into the data. +// +// MEDIASUBTYPE_SSA/ASS: +// +// Comma separated values similar to the "Dialogue: ..." line with these fields: +// ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text +// +// With the exception of ReadOrder every field can be found in ASS files. The +// ReadOrder field is needed for the decoder to be able to reorder the streamed +// samples as they were placed originally in the file. +// +// If the source is only SSA, the Layer field can be left empty. +// +// MEDIATYPE_VOBSUB: +// +// Standard dvd subpic data, without the stream id at the beginning. +// + +// Matroska CodecID mappings +// ------------------------ +// +// S_TEXT/ASCII <-> MEDIATYPE_Text MEDIASUBTYPE_NULL FORMAT_None +// S_TEXT/UTF8 <-> MEDIATYPE_Subtitle MEDIASUBTYPE_UTF8 FORMAT_SubtitleInfo +// S_TEXT/SSA <-> MEDIATYPE_Subtitle MEDIASUBTYPE_SSA FORMAT_SubtitleInfo +// S_TEXT/ASS <-> MEDIATYPE_Subtitle MEDIASUBTYPE_ASS FORMAT_SubtitleInfo +// S_TEXT/USF <-> MEDIATYPE_Subtitle MEDIASUBTYPE_USF FORMAT_SubtitleInfo +// S_VOBSUB <-> MEDIATYPE_Subtitle MEDIASUBTYPE_VOBSUB FORMAT_SubtitleInfo +// S_VOBSUB/ZLIB<-> MEDIATYPE_Subtitle MEDIASUBTYPE_VOBSUB FORMAT_SubtitleInfo +// + +/* +DEFINE_GUID( MEDIATYPE_MPEG2_SECTIONS, + 0x455f176c, 0x4b06, 0x47ce, 0x9a, 0xef, 0x8c, 0xae, 0xf7, 0x3d, 0xf7, 0xb5); + +DEFINE_GUID(MEDIASUBTYPE_ATSC_SI, +0xb3c7397c, 0xd303, 0x414d, 0xb3, 0x3c, 0x4e, 0xd2, 0xc9, 0xd2, 0x97, 0x33); + +DEFINE_GUID(MEDIASUBTYPE_DVB_SI, +0xe9dd31a3, 0x221d, 0x4adb, 0x85, 0x32, 0x9a, 0xf3, 0x9, 0xc1, 0xa4, 0x8); + + +// {C892E55B-252D-42b5-A316-D997E7A5D995} +DEFINE_GUID(MEDIASUBTYPE_MPEG2DATA, +0xc892e55b, 0x252d, 0x42b5, 0xa3, 0x16, 0xd9, 0x97, 0xe7, 0xa5, 0xd9, 0x95); + +*/ + +// ASF +// {6B6D0801-9ADA-11D0-A520-00A0D10129C0} +DEFINE_GUID(MEDIASUBTYPE_ASF, + 0x6b6d0801, 0x9ada, 0x11d0, 0xa5, 0x20, 0x00, 0xa0, 0xd1, 0x01, 0x29, 0xc0); + +// H264 + +// 6F29D2AD-E130-45AA-B42F-F623AD354A90 +DEFINE_GUID(MEDIASUBTYPE_ArcsoftH264, 0x6F29D2AD, 0xE130, 0x45AA, 0xB4, 0x2F, 0xF6, 0x23, 0xAD, 0x35, 0x4A, 0x90); + +// 48535356-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VSSH, 0x48535356, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 68737376-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vssh, 0x68737376, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43564144-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DAVC, 0x43564144, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 63766164-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_davc, 0x63766164, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43564150-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_PAVC, 0x43564150, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 63766170-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_pavc, 0x63766170, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31637661-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_avc1, 0x31637661, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31564343-0000-0010-8000-00AA00389B71 (custom H.264 FourCC used by Haali Media Splitter) +DEFINE_GUID(MEDIASUBTYPE_CCV1, 0x31564343, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 8D2D71CB-243F-45E3-B2D8-5FD7967EC09B <= Use by MediaPortal for example... +DEFINE_GUID(MEDIASUBTYPE_H264_bis, 0x8D2D71CB, 0x243F, 0x45E3, 0xB2, 0xD8, 0x5F, 0xD7, 0x96, 0x7E, 0xC0, 0x9B); + +// 676C6178-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_xalg, 0x676C6178, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 676C7661-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_avlg, 0x676C7661, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33515653-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_SVQ3, 0x33515653, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_XVID, 0x44495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_xvid, 0x64697678, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30355844-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_DX50, 0x30355844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30357864-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_dx50, 0x30357864, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIVX, 0x58564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 78766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_divx, 0x78766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 78766944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_Divx, 0x78766944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 5634504d-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_MP4V, 0x5634504d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 7634706D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_mp4v, 0x7634706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31564933-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_3IV1, 0x31564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31766933-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_3iv1, 0x31766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32564933-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_3IV2, 0x32564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32766933-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_3iv2, 0x32766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 58564933-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_3IVX, 0x58564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 78766933-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_3ivx, 0x78766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 305A4C42-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_BLZ0, 0x305A4C42, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 307A6C62-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_blz0, 0x307A6C62, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {564F4547-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_GEOV, 0x564F4547, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56344D44-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DM4V, 0x56344D44, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 76346D64-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_dm4v, 0x76346D64, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4D475844-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DXGM, 0x4D475844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 6D677864-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_dxgm, 0x6D677864, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 53444646-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_FFDS, 0x53444646, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 73646666-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ffds, 0x73646666, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 57465646-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FVFW, 0x57465646, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 77667666-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_fvfw, 0x77667666, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D46-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FMP4, 0x34504D46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D66-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_fmp4, 0x34706D66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34584448-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HDX4, 0x34584448, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34786468-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_hdx4, 0x34786468, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D4C-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_LMP4, 0x34504D4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D6C-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_lmp4, 0x34706D6C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4749444E-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_NDIG, 0x4749444E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 6769646E-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ndig, 0x6769646E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D52-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RMP4, 0x34504D52, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D72-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_rmp4, 0x34706D72, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D53-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SMP4, 0x34504D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D73-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_smp4, 0x34706D73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 47444553-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SEDG, 0x47444553, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 67646573-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_sedg, 0x67646573, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4D475844-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DGXM, 0x4D475844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D55-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_UMP4, 0x34504D55, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D75-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ump4, 0x34706D75, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 46315657-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_WV1F, 0x46315657, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 66317677-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_wv1f, 0x66317677, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 58495658-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_XVIX, 0x58495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 78697678-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_xvix, 0x78697678, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31515653-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SVQ1, 0x31515653, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363248-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_H263, 0x33363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363268-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_h263, 0x33363268, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363249-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_I263, 0x33363249, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363269-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_i263, 0x33363269, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31363248-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_H261, 0x31363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31363268-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_h261, 0x31363268, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_S263, 0x33363273, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363273-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_s263, 0x33363273, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AMVV, 0x56564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 46564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AMVF, 0x46564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33585644-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVX3, 0x33585644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33787664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_dvx3, 0x33787664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 44564933-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_3IVD, 0x44564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV3, 0x33564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div3, 0x33766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 314C4F43-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_COL1, 0x314C4F43, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 316C6F63-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_col1, 0x316C6F63, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV4, 0x34564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div4, 0x34766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV5, 0x35564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div5, 0x35766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 36564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV6, 0x36564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 36766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div6, 0x36766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31345041-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AP41, 0x31345041, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31347061-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ap41, 0x31347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3347504D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MPG3, 0x3347504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3367706D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_mpg3, 0x3367706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV2, 0x32564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div2, 0x32766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV1, 0x31564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div1, 0x31766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3134504D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MP41, 0x3134504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3134706D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_mp41, 0x3134706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4F454854-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_THEORA, 0x4F454854, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 6F656874-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_theora, 0x6F656874, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 63637374-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_TSCC, 0x63637374, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32637374-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_TSC2, 0x32637374, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30355649-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IV50, 0x30355649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31345649-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IV41, 0x31345649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31335649-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IV31, 0x31335649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32335649-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IV32, 0x32335649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 48564443-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CDVH, 0x48564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43564443-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CDVC, 0x43564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35564443-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CDV5, 0x35564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35325644-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DV25, 0x35325644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 30355644-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DV50, 0x30355644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70637664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVCP, 0x70637664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70707664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVPP, 0x70707664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70357664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DV5P, 0x70357664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 6E357664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DV5N, 0x6E357664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70637664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVC, 0x20637664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 31687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH1, 0x31687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 32687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH2, 0x32687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 33687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH3, 0x33687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 34687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH4, 0x34687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 35687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH5, 0x35687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 36687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH6, 0x36687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 71687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVHQ, 0x71687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVHP, 0x70687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 76645641-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVdv, 0x76645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 31645641-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVd1, 0x31645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 31535046-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FPS1, 0x31535046, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 55594648-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HuffYUV, 0x55594648, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 5347414C-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_Lagarith, 0x5347414C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 64697663-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CVID, 0x64697663, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 694B4942-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_BIKI, 0x694B4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 624B4942-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_BIKB, 0x624B4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 664b4942-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_BIKf, 0x664b4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(FORMAT_RLTheora, 0xe69b30d1, 0x7d65, 0x4166, 0xb9, 0x90, 0x10, 0x3d, 0xa8, 0xc9, 0x11, 0xe3); + +// 62706A6D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MJPGB, 0x62706A6D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 30365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP30, 0x30335056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP31, 0x31335056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 324B4D53-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SMK2, 0x324B4D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 344B4D53-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SMK4, 0x344B4D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 44435343-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CSCD, 0x44435343, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 47455051-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_QPEG, 0x47455051, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 302E3151-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_QP10, 0x302E3151, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 312E3151-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_QP11, 0x312E3151, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 485A534D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MSZH, 0x485A534D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 42494C5A-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ZLIB, 0x42494C5A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 20676E70-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_PNG, 0x20676E70, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_TIFF, MAKEFOURCC('T', 'I', 'F', 'F'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_BMP, MAKEFOURCC('B', 'M', 'P', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_GIF, MAKEFOURCC('G', 'I', 'F', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_TGA, MAKEFOURCC('T', 'G', 'A', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_WEBP, MAKEFOURCC('W', 'E', 'B', 'P'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_FSV1, 0x31565346, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_CRAM, MAKEFOURCC('C', 'R', 'A', 'M'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_MSVC, MAKEFOURCC('M', 'S', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_WHAM, MAKEFOURCC('W', 'H', 'A', 'M'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_8BPS, MAKEFOURCC('8', 'B', 'P', 'S'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_LOCO, MAKEFOURCC('L', 'O', 'C', 'O'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ZMBV, MAKEFOURCC('Z', 'M', 'B', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VCR1, MAKEFOURCC('V', 'C', 'R', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_AASC, MAKEFOURCC('A', 'A', 'S', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_SNOW, MAKEFOURCC('S', 'N', 'O', 'W'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_FFV1, MAKEFOURCC('F', 'F', 'V', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_FFVH, MAKEFOURCC('F', 'F', 'V', 'H'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_v410, MAKEFOURCC('v', '4', '1', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VMNC, MAKEFOURCC('V', 'M', 'n', 'c'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// {3267706D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_MPG2, 0x3267706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Apple ProRes +DEFINE_GUID(MEDIASUBTYPE_apch, 0x68637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_apcn, 0x6e637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_apcs, 0x73637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_apco, 0x6f637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ap4h, 0x68347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ap4x, 0x78347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Apple ICOD +DEFINE_GUID(MEDIASUBTYPE_icod, 0x646F6369, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Ut Video +DEFINE_GUID(MEDIASUBTYPE_ULRA, MAKEFOURCC('U', 'L', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULRG, MAKEFOURCC('U', 'L', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULY0, MAKEFOURCC('U', 'L', 'Y', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULY2, MAKEFOURCC('U', 'L', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULY4, MAKEFOURCC('U', 'L', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UQY2, MAKEFOURCC('U', 'Q', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UQRG, MAKEFOURCC('U', 'Q', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UQRA, MAKEFOURCC('U', 'Q', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULH0, MAKEFOURCC('U', 'L', 'H', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULH2, MAKEFOURCC('U', 'L', 'H', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULH4, MAKEFOURCC('U', 'L', 'H', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMY2, MAKEFOURCC('U', 'M', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMH2, MAKEFOURCC('U', 'M', 'H', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMY4, MAKEFOURCC('U', 'M', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMH4, MAKEFOURCC('U', 'M', 'H', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMRG, MAKEFOURCC('U', 'M', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMRA, MAKEFOURCC('U', 'M', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// G2M +DEFINE_GUID(MEDIASUBTYPE_G2M2, MAKEFOURCC('G', '2', 'M', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_G2M3, MAKEFOURCC('G', '2', 'M', '3'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_G2M4, MAKEFOURCC('G', '2', 'M', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_G2M5, MAKEFOURCC('G', '2', 'M', '5'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// CFHD +DEFINE_GUID(MEDIASUBTYPE_CFHD, MAKEFOURCC('C', 'F', 'H', 'D'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// MagicYUV +DEFINE_GUID(MEDIASUBTYPE_MAGY, MAKEFOURCC('M', 'A', 'G', 'Y'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8RG, MAKEFOURCC('M', '8', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8RA, MAKEFOURCC('M', '8', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8G0, MAKEFOURCC('M', '8', 'G', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8Y0, MAKEFOURCC('M', '8', 'Y', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8Y2, MAKEFOURCC('M', '8', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8Y4, MAKEFOURCC('M', '8', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8YA, MAKEFOURCC('M', '8', 'Y', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// MagicYUV +DEFINE_GUID(MEDIASUBTYPE_FICV, MAKEFOURCC('F', 'I', 'C', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// DNxHD +// {6E645641-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_AVdn, 0x6E645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// DNxHR +// {68645641-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_AVdh, 0x68645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// JPEG2000 +// {32706A6D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_mjp2, 0x32706A6D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {43324A4D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_MJ2C, 0x43324A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {43324A4C-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_LJ2C, 0x43324A4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {4B324A4C-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_LJ2K, 0x4B324A4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {324A5049-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_IPJ2, 0x324A5049, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {D80FA03C-35C1-4FA1-8C8E-375C8667166E} +DEFINE_GUID(MEDIASUBTYPE_LAV_RAWVIDEO, 0xd80fa03c, 0x35c1, 0x4fa1, 0x8c, 0x8e, 0x37, 0x5c, 0x86, 0x67, 0x16, 0x6e); + +// {434C4641-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_FLIC, 0x434C4641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {} +DEFINE_GUID(MEDIASUBTYPE_THPV, MAKEFOURCC('T', 'H', 'P', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ROQV, MAKEFOURCC('R', 'o', 'Q', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// 31435648-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HVC1, 0x31435648, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43564548-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HEVC, 0x43564548, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30314D48-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HM10, 0x30314D48, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35363248-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_H265, 0x35363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// VVC ("VVC1") +DEFINE_GUID(MEDIASUBTYPE_VVC1, MAKEFOURCC('V', 'V', 'C', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// Full MVC +DEFINE_GUID(MEDIASUBTYPE_AMVC, MAKEFOURCC('A', 'M', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +// Full MVC in mp4-form +DEFINE_GUID(MEDIASUBTYPE_MVC1, MAKEFOURCC('M', 'V', 'C', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +// Subset MVC +DEFINE_GUID(MEDIASUBTYPE_EMVC, MAKEFOURCC('E', 'M', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +// 4B435544-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DUCK, 0x4B435544, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30324D54-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_TM20, 0x30324D54, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 20636D73-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_smc, 0x20636D73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4C584956-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VIXL, 0x4C584956, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 49544C55-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ULTI, 0x49544C55, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31564E57-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_WNV1, 0x31564E57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 76757963-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CYUV, 0x76757963, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31565341-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVS1, 0x31565341, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32565341-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVS2, 0x32565341, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31325452-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RT21, 0x31325452, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 6E525641-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVRn, 0x6E525641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 47504a4c-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_LJPG, 0x47504a4c, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4C47504A-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_JPGL, 0x4C47504A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 534c4a4d-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MJLS, 0x534c4a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 41504a4d-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MJPA, 0x41504a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 42504a4d-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MJPB, 0x42504a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 58355053-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SP5X, 0x58355053, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31706148-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_Hap1, 0x31706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35706148-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_Hap5, 0x35706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 59706148-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HapY, 0x59706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33445844-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DXD3, 0x33445844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 49445844-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DXDI, 0x49445844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 574D5632-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_2VMW, 0x574D5632, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56334357-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_WC3V, 0x56334357, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4345444D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MDEC, 0x4345444D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 564D5834-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_4XMV, 0x564D5834, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43425241-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ARBC, 0x43425241, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30345056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP40, 0x30345056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34355053-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SP54, 0x34355053, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3156474B-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_KGV1, 0x3156474B, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Audio codecs + +// 41564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IMA_AMV, 0x41564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 4C4C454E-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_NELLYMOSER, 0x4C4C454E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000006-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ALAW, WAVE_FORMAT_ALAW, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000007-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MULAW, WAVE_FORMAT_MULAW, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000031-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MSGSM610, WAVE_FORMAT_GSM610, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000002-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ADPCM_MS, WAVE_FORMAT_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000022-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_TRUESPEECH, WAVE_FORMAT_DSPGROUP_TRUESPEECH, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, + 0x38, 0x9b, 0x71); + +// 00000075-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VOXWARE_RT29, WAVE_FORMAT_VOXWARE_RT29, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, + 0x9b, 0x71); + +// 324D4451-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_QDM2, 0x324D4451, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 63616C61-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ALAC, 0x63616C61, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// B82196E9-1B3F-4796-A636-46239087B38E dsfTAKsource specific +DEFINE_GUID(MEDIASUBTYPE_TAK, 0xB82196E9, 0x1B3F, 0x4796, 0xA6, 0x36, 0x46, 0x23, 0x90, 0x87, 0xB3, 0x8E); + +// 20534C41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ALS, 0x20534C41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 0000729A-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_729A, 0x0000729A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000133-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_G729, 0x00000133, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 36323767-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_G726, 0x36323767, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000401-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IMC, 0x00000401, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 0000011-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IMA_WAV, WAVE_FORMAT_IMA_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {A23EB7FC-510B-466F-9FBF-5F878F69347C} LAVF/LAVC specific +DEFINE_GUID(MEDIASUBTYPE_BD_LPCM_AUDIO, 0xa23eb7fc, 0x510b, 0x466f, 0x9f, 0xbf, 0x5f, 0x87, 0x8f, 0x69, 0x34, 0x7c); + +// {53544441-0000-0010-8000-00AA00389B71} AAC-ADTS LAVF/LAVC specific +#define WAVE_FORMAT_AAC_ADTS mmioFOURCC('A', 'D', 'T', 'S') +DEFINE_GUID(MEDIASUBTYPE_AAC_ADTS, WAVE_FORMAT_AAC_ADTS, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {33534541-0000-0010-8000-00AA00389B71} S302M AES3 +#define WAVE_FORMAT_S302M_AES3 mmioFOURCC('A', 'E', 'S', '3') +DEFINE_GUID(MEDIASUBTYPE_AES3, WAVE_FORMAT_S302M_AES3, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {949F97FD-56F6-4527-B4AE-DDEB375AB80F} Mpc-hc specific ! +DEFINE_GUID(MEDIASUBTYPE_HDMV_LPCM_AUDIO, 0x949f97fd, 0x56f6, 0x4527, 0xb4, 0xae, 0xdd, 0xeb, 0x37, 0x5a, 0xb8, 0xf); + +#define WAVE_FORMAT_MLP mmioFOURCC('M', 'L', 'P', ' ') +DEFINE_GUID(MEDIASUBTYPE_MLP, WAVE_FORMAT_MLP, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +#define WAVE_FORMAT_SPEEX 0xA109 +DEFINE_GUID(MEDIASUBTYPE_SPEEX, WAVE_FORMAT_SPEEX, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +#ifndef WAVE_FORMAT_OPUS +#define WAVE_FORMAT_OPUS 0x704F +#endif +DEFINE_GUID(MEDIASUBTYPE_OPUS, WAVE_FORMAT_OPUS, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_OPUS_OLD mmioFOURCC('O', 'P', 'U', 'S') +DEFINE_GUID(MEDIASUBTYPE_OPUS_OLD, WAVE_FORMAT_OPUS_OLD, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_DSDL mmioFOURCC('D', 'S', 'D', 'L') +DEFINE_GUID(MEDIASUBTYPE_DSDL, WAVE_FORMAT_DSDL, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_DSDM mmioFOURCC('D', 'S', 'D', 'M') +DEFINE_GUID(MEDIASUBTYPE_DSDM, WAVE_FORMAT_DSDM, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_DSD1 mmioFOURCC('D', 'S', 'D', '1') +DEFINE_GUID(MEDIASUBTYPE_DSD1, WAVE_FORMAT_DSD1, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_DSD8 mmioFOURCC('D', 'S', 'D', '8') +DEFINE_GUID(MEDIASUBTYPE_DSD8, WAVE_FORMAT_DSD8, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000014-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_G723, 0x00000014, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000111-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VIVO_G723, 0x00000111, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 20455041-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_APE, 0x20455041, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + + +struct WAVEFORMATEX_HDMV_LPCM : public WAVEFORMATEX +{ + BYTE channel_conf; + + struct WAVEFORMATEX_HDMV_LPCM() + { + memset(this, 0, sizeof(*this)); + cbSize = sizeof(WAVEFORMATEX_HDMV_LPCM) - sizeof(WAVEFORMATEX); + } +}; + +// {AFBC2343-3DCB-4047-9655-E1E62A61B1C5} +DEFINE_GUID(MEDIASUBTYPE_FFMPEG_AUDIO, 0xafbc2343, 0x3dcb, 0x4047, 0x96, 0x55, 0xe1, 0xe6, 0x2a, 0x61, 0xb1, 0xc5); + +// {35189950-CAC9-4C8D-819D-B6FAEE15DD9D} +DEFINE_GUID(FORMAT_WaveFormatExFFMPEG, 0x35189950, 0xcac9, 0x4c8d, 0x81, 0x9d, 0xb6, 0xfa, 0xee, 0x15, 0xdd, 0x9d); + +struct WAVEFORMATEXFFMPEG +{ + int nCodecId; + WAVEFORMATEX wfex; + + struct WAVEFORMATEXFFMPEG() + { + nCodecId = 0; + } +}; + +// {20884BC2-629F-45EA-B1C5-FA4FFA438250} +DEFINE_GUID(MEDIASUBTYPE_LAVBluRay, 0x20884bc2, 0x629f, 0x45ea, 0xb1, 0xc5, 0xfa, 0x4f, 0xfa, 0x43, 0x82, 0x50); + +// {D51BD5A3-7548-11cf-A520-0080C77EF58A} +DEFINE_GUID(CLSID_MultFile, 0xd51bd5a3, 0x7548, 0x11cf, 0xa5, 0x20, 0x0, 0x80, 0xc7, 0x7e, 0xf5, 0x8a); + +// Additionnal DXVA GUIDs + +// Intel ClearVideo VC1 bitstream decoder +DEFINE_GUID(DXVA_Intel_VC1_ClearVideo, 0xBCC5DB6D, 0xA2B6, 0x4AF0, 0xAC, 0xE4, 0xAD, 0xB1, 0xF7, 0x87, 0xBC, 0x89); +DEFINE_GUID(DXVA_Intel_VC1_ClearVideo_2, 0xE07EC519, 0xE651, 0x4CD6, 0xAC, 0x84, 0x13, 0x70, 0xCC, 0xEE, 0xC8, 0x51); + +// Intel ClearVideo H264 bitstream decoder +DEFINE_GUID(DXVA_Intel_H264_ClearVideo, 0x604F8E68, 0x4951, 0x4C54, 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6); + +// Nvidia MPEG-4 ASP bitstream decoder +// 9947EC6F-689B-11DC-A320-0019DBBC4184 +DEFINE_GUID(DXVA_MPEG4_ASP, 0x9947EC6F, 0x689B, 0x11DC, 0xA3, 0x20, 0x00, 0x19, 0xDB, 0xBC, 0x41, 0x84); + +// Filter/Commercial GUIDs + +DEFINE_GUID(CLSID_AC3Filter, 0xA753A1EC, 0x973E, 0x4718, 0xAF, 0x8E, 0xA3, 0xF5, 0x54, 0xD4, 0x5C, 0x44); + +// {212690FB-83E5-4526-8FD7-74478B7939CD} from wmcodecdsp.h +DEFINE_GUID(CLSID_CMPEG2VidDecoderDS, 0x212690FB, 0x83E5, 0x4526, 0x8F, 0xD7, 0x74, 0x47, 0x8B, 0x79, 0x39, 0xCD); + +// {39F498AF-1A09-4275-B193-673B0BA3D478} +DEFINE_GUID(CLSID_CMpeg2DecFilter, 0x39F498AF, 0x1A09, 0x4275, 0xB1, 0x93, 0x67, 0x3B, 0x0B, 0xA3, 0xD4, 0x78); + +// Nvidia Video Decoder - {71E4616A-DB5E-452B-8CA5-71D9CC7805E9} +DEFINE_GUID(CLSID_NvidiaVideoDecoder, 0x71E4616A, 0xDB5E, 0x452B, 0x8C, 0xA5, 0x71, 0xD9, 0xCC, 0x78, 0x05, 0xE9); + +// Sonic Cinemaster Video Decoder - {D7D50E8D-DD72-43C2-8587-A0C197D837D2} +DEFINE_GUID(CLSID_SonicCinemasterVideoDecoder, 0xD7D50E8D, 0xDD72, 0x43C2, 0x85, 0x87, 0xA0, 0xC1, 0x97, 0xD8, 0x37, 0xD2); + +// RDP DirectShow Redirection Filter - {AB9D6472-752F-43F6-B29E-61207BDA8E06} +DEFINE_GUID(CLSID_RDPDShowRedirectionFilter, 0xAB9D6472, 0x752F, 0x43F6, 0xB2, 0x9E, 0x61, 0x20, 0x7B, 0xDA, 0x8E, 0x06); + +// ReClock - {9DC15360-914C-46B8-B9DF-E67FD36C6A} +DEFINE_GUID(CLSID_ReClock, 0x9DC15360, 0x914C, 0x46B8, 0xB9, 0xDF, 0xBF, 0xE6, 0x7F, 0xD3, 0x6C, 0x6A); + +// MPC(BE) Audio Renderer - {601D2A2B-9CDE-40BD-8650-0485E3522727} +DEFINE_GUID(CLSID_MPCBEAudioRenderer, 0x601D2A2B, 0x9CDE, 0x40BD, 0x86, 0x50, 0x04, 0x85, 0xE3, 0x52, 0x27, 0x27); + +// Morgan's Stream Switcher - {D3CD7858-971A-4838-ACEC-40CA5D529DC8} +DEFINE_GUID(CLSID_MorganStreamSwitcher, 0xD3CD7858, 0x971A, 0x4838, 0xAC, 0xEC, 0x40, 0xCA, 0x5D, 0x52, 0x9D, 0xC8); + +// FFDShow DXVA Decoder - {0B0EFF97-C750-462C-9488-B10E7D87F1A6} +DEFINE_GUID(CLSID_FFDShowDXVADecoder, 0x0B0EFF97, 0xC750, 0x462C, 0x94, 0x88, 0xB1, 0x0E, 0x7D, 0x87, 0xF1, 0xA6); + +// Microsoft DTV-DVD Audio Decoder - {E1F1A0B8-BEEE-490D-BA7C-066C40B5E2B9} +DEFINE_GUID(CLSID_MSDVTDVDAudioDecoder, 0xE1F1A0B8, 0xBEEE, 0x490D, 0xBA, 0x7C, 0x06, 0x6C, 0x40, 0xB5, 0xE2, 0xB9); + +// Old MPC-HC filters +DEFINE_GUID(CLSID_MPCMpegSplitter, 0xDC257063, 0x045F, 0x4BE2, 0xBD, 0x5B, 0xE1, 0x22, 0x79, 0xC4, 0x64, 0xF0); +DEFINE_GUID(CLSID_MPCMpegSplitterSource, 0x1365BE7A, 0xC86A, 0x473C, 0x9A, 0x41, 0xC0, 0xA6, 0xE8, 0x2C, 0x9F, 0xA3); +DEFINE_GUID(CLSID_MPCVideoDecoder, 0x008BAC12, 0xFBAF, 0x497b, 0x96, 0x70, 0xBC, 0x6F, 0x6F, 0xBA, 0xE2, 0xC4); +DEFINE_GUID(CLSID_MPCShoutcastSource, 0x68F540E9, 0x766F, 0x44d2, 0xAB, 0x07, 0xE2, 0x6C, 0xC6, 0xD2, 0x7A, 0x79); + +// DirectVobSub || VSFilter (auto-loading version) - {9852A670-F845-491B-9BE6-EBD841B8A613} +DEFINE_GUID(CLSID_VSFilter, 0x9852A670, 0xF845, 0x491B, 0x9B, 0xE6, 0xEB, 0xD8, 0x41, 0xB8, 0xA6, 0x13); + +// DirectVobSub || VSFilter - {93A22E7A-5091-45EF-BA61-6DA26156A5D0} +DEFINE_GUID(CLSID_VSFilter2, 0x93A22E7A, 0x5091, 0x45EF, 0xBA, 0x61, 0x6D, 0xA2, 0x61, 0x56, 0xA5, 0xD0); + +// XySubFilter - {2DFCB782-EC20-4A7C-B530-4577ADB33F21} +DEFINE_GUID(CLSID_XySubFilter, 0x2DFCB782, 0xEC20, 0x4A7C, 0xB5, 0x30, 0x45, 0x77, 0xAD, 0xB3, 0x3F, 0x21); + +// XySubFilterAutoLoader - {6B237877-902B-4C6C-92F6-E63169A5166C} +DEFINE_GUID(CLSID_XySubFilter_AutoLoader, 0x6B237877, 0x902B, 0x4C6C, 0x92, 0xF6, 0xE6, 0x31, 0x69, 0xA5, 0x16, 0x6C); + +// sanear (internal version) +// SaneAudioRenderer::Factory::GetFilterGuid() is the right way do optain it, +// but we link DSUtil to everything and consequently will have to link sanear to everything. +DEFINE_GUID(CLSID_SANEAR_INTERNAL, 0x2AE00773, 0x819A, 0x40FB, 0xA5, 0x54, 0x54, 0x82, 0x7E, 0x11, 0x63, 0x59); + +// sanear (standalone version) - {DF557071-C9FD-433A-9627-81E0D3640ED9} +DEFINE_GUID(CLSID_SANEAR, 0xdf557071, 0xc9fd, 0x433a, 0x96, 0x27, 0x81, 0xe0, 0xd3, 0x64, 0xe, 0xd9); + +// AssFilter - {8A3704F3-BE3B-4944-9FF3-EE8757FDBDA5} +DEFINE_GUID(CLSID_AssFilter, 0x8A3704F3, 0xBE3B, 0x4944, 0x9F, 0xF3, 0xEE, 0x87, 0x57, 0xFD, 0xBD, 0xA5); + +// AssFilterAutoLoader - {8A6DFC6A-0A79-4790-85DA-0688B8093B54} +DEFINE_GUID(CLSID_AssFilter_AutoLoader, 0x8A6DFC6A, 0x0A79, 0x4790, 0x85, 0xDA, 0x06, 0x88, 0xB8, 0x09, 0x3B, 0x54); + +// Generate Still Video - {7DF62B50-6843-11D2-9EEB-006008039E37} +DEFINE_GUID(CLSID_StillVideo, 0x7DF62B50, 0x6843, 0x11D2, 0x9E, 0xEB, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); + +// MPC Image Source - {7DB5C3B3-2419-4508-B1D0-F2D22DA8E439} +DEFINE_GUID(CLSID_MPCImageSource, 0x7DB5C3B3, 0x2419, 0x4508, 0xB1, 0xD0, 0xF2, 0xD2, 0x2D, 0xA8, 0xE4, 0x39); + +DEFINE_GUID(CLSID_Generic_WDM_FilterProxy, 0x17CCA71B, 0xECD7, 0x11D0, 0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96); + +// uncompressed +#define DEFINE_GUID_FOURCC(FOURCC) \ + DEFINE_GUID(MEDIASUBTYPE_##FOURCC, FOURCC_##FOURCC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +//uncompressed +#define FOURCC_YUY2 mmioFOURCC('Y','U','Y','2') +#define FOURCC_V422 mmioFOURCC('V','4','2','2') +#define FOURCC_YV12 mmioFOURCC('Y','V','1','2') +#define FOURCC_YVYU mmioFOURCC('Y','V','Y','U') +#define FOURCC_UYVY mmioFOURCC('U','Y','V','Y') +#define FOURCC_YUYV mmioFOURCC('Y','U','Y','V') +#define FOURCC_VYUY mmioFOURCC('V','Y','U','Y') +#define FOURCC_I420 mmioFOURCC('I','4','2','0') +#define FOURCC_IYUV mmioFOURCC('I','Y','U','V') +#define FOURCC_444P mmioFOURCC('4','4','4','P') +#define FOURCC_YV24 mmioFOURCC('Y','V','2','4') // YUV 4:4:4 +#define FOURCC_422P mmioFOURCC('4','2','2','P') +#define FOURCC_YV16 mmioFOURCC('Y','V','1','6') // YUV 4:2:2 +#define FOURCC_411P mmioFOURCC('4','1','1','P') +#define FOURCC_Y41B mmioFOURCC('Y','4','1','B') // YUV 4:1:1 +#define FOURCC_410P mmioFOURCC('4','1','0','P') +#define FOURCC_PAL1 mmioFOURCC('P','A','L','1') +#define FOURCC_PAL4 mmioFOURCC('P','A','L','4') +#define FOURCC_PAL8 mmioFOURCC('P','A','L','8') +#define FOURCC_RGB2 mmioFOURCC('R','G','B','2') +#define FOURCC_RGB3 mmioFOURCC('R','G','B','3') +#define FOURCC_RGB5 mmioFOURCC('R','G','B','5') +#define FOURCC_RGB6 mmioFOURCC('R','G','B','6') +#define FOURCC_CLJR mmioFOURCC('C','L','J','R') +#define FOURCC_Y800 mmioFOURCC('Y','8','0','0') +#define FOURCC_NV12 mmioFOURCC('N','V','1','2') +#define FOURCC_NV21 mmioFOURCC('N','V','2','1') +#define FOURCC_P010 mmioFOURCC('P','0','1','0') +#define FOURCC_P016 mmioFOURCC('P','0','1','6') +#define FOURCC_420R mmioFOURCC('4','2','0','R') +#define FOURCC_422R mmioFOURCC('4','2','2','R') +#define FOURCC_444R mmioFOURCC('4','4','4','R') +#define FOURCC_P210 mmioFOURCC('P','2','1','0') +#define FOURCC_P216 mmioFOURCC('P','2','1','6') +#define FOURCC_AYUV mmioFOURCC('A','Y','U','V') +#define FOURCC_Y416 mmioFOURCC('Y','4','1','6') + +#define FOURCC_nv12 mmioFOURCC('n','v','1','2') +#define FOURCC_yv12 mmioFOURCC('y','v','1','2') +#define FOURCC_ICM1 mmioFOURCC('I','C','M','1') +#define FOURCC_ICM2 mmioFOURCC('I','C','M','2') +#define FOURCC_ICM3 mmioFOURCC('I','C','M','3') +#define FOURCC_ICM4 mmioFOURCC('I','C','M','4') +#define FOURCC_yuy2 mmioFOURCC('y','u','y','2') +#define FOURCC_uyvy mmioFOURCC('u','y','v','y') +#define FOURCC_cyuv mmioFOURCC('c','y','u','v') +#define FOURCC_UYNV mmioFOURCC('U','Y','N','V') +#define FOURCC_UYNY mmioFOURCC('U','Y','N','Y') +#define FOURCC_HDYC mmioFOURCC('H','D','Y','C') +#define FOURCC_uyv1 mmioFOURCC('u','y','v','1') +#define FOURCC_2Vu1 mmioFOURCC('2','V','u','1') +#define FOURCC_VDTZ mmioFOURCC('V','D','T','Z') +#define FOURCC_YUV2 mmioFOURCC('Y','U','V','2') +#define FOURCC_yuv2 mmioFOURCC('y','u','v','2') +#define FOURCC_2vuy mmioFOURCC('2','v','u','y') +#define FOURCC_2Vuy mmioFOURCC('2','V','u','y') +#define FOURCC_yuvu mmioFOURCC('y','u','v','u') +#define FOURCC_yuvs mmioFOURCC('y','u','v','s') +#define FOURCC_I422 mmioFOURCC('I','4','2','2') +#define FOURCC_Y422 mmioFOURCC('Y','4','2','2') +#define FOURCC_V422 mmioFOURCC('V','4','2','2') +#define FOURCC_Y42B mmioFOURCC('Y','4','2','B') +#define FOURCC_P422 mmioFOURCC('P','4','2','2') +#define FOURCC_YUNV mmioFOURCC('Y','U','N','V') +#define FOURCC_AVUI mmioFOURCC('A','V','U','I') +#define FOURCC_I444 mmioFOURCC('I','4','4','4') +#define FOURCC_v308 mmioFOURCC('v','3','0','8') +#define FOURCC_v408 mmioFOURCC('v','4','0','8') +#define FOURCC_24BG mmioFOURCC('2','4','B','G') +#define FOURCC_BGRA mmioFOURCC('B','G','R','A') +#define FOURCC_ABGR mmioFOURCC('A','B','G','R') +#define FOURCC_RGBA mmioFOURCC('R','G','B','A') +#define FOURCC_RGB0 mmioFOURCC('R','G','B','0') +#define FOURCC_0RGB mmioFOURCC('0','R','G','B') +#define FOURCC_b48r mmioFOURCC('b','4','8','r') +#define FOURCC_RBA64 mmioFOURCC('R','B','A',64) +#define FOURCC_64RBA mmioFOURCC(64,'R','B','A') +#define FOURCC_b64a mmioFOURCC('b','6','4','a') +#define FOURCC_Y410 mmioFOURCC('Y','4','1','0') +#define FOURCC_v216 mmioFOURCC('v','2','1','6') +#define FOURCC_v416 mmioFOURCC('v','4','1','6') +#define FOURCC_Y8 mmioFOURCC('Y','8',0x20,0x20) +#define FOURCC_Y16 mmioFOURCC('Y','1',0,16) + +DEFINE_GUID_FOURCC(422P) +DEFINE_GUID_FOURCC(444P) +DEFINE_GUID_FOURCC(411P) +DEFINE_GUID_FOURCC(410P) +DEFINE_GUID_FOURCC(VYUY) +DEFINE_GUID_FOURCC(Y800) +DEFINE_GUID_FOURCC(NV21) +DEFINE_GUID_FOURCC(YV16) +DEFINE_GUID_FOURCC(YV24) +DEFINE_GUID_FOURCC(420R) +DEFINE_GUID_FOURCC(422R) +DEFINE_GUID_FOURCC(444R) +DEFINE_GUID_FOURCC(Y416) + +DEFINE_GUID_FOURCC(nv12) +DEFINE_GUID_FOURCC(yv12) +DEFINE_GUID_FOURCC(ICM1) +DEFINE_GUID_FOURCC(ICM2) +DEFINE_GUID_FOURCC(ICM3) +DEFINE_GUID_FOURCC(ICM4) +DEFINE_GUID_FOURCC(yuy2) +DEFINE_GUID_FOURCC(uyvy) +DEFINE_GUID_FOURCC(cyuv) +DEFINE_GUID_FOURCC(UYNV) +DEFINE_GUID_FOURCC(UYNY) +DEFINE_GUID_FOURCC(HDYC) +DEFINE_GUID_FOURCC(uyv1) +DEFINE_GUID_FOURCC(2Vu1) +DEFINE_GUID_FOURCC(VDTZ) +DEFINE_GUID_FOURCC(YUV2) +DEFINE_GUID_FOURCC(yuv2) +DEFINE_GUID_FOURCC(2vuy) +DEFINE_GUID_FOURCC(2Vuy) +DEFINE_GUID_FOURCC(yuvu) +DEFINE_GUID_FOURCC(yuvs) +DEFINE_GUID_FOURCC(I422) +DEFINE_GUID_FOURCC(Y422) +DEFINE_GUID_FOURCC(V422) +DEFINE_GUID_FOURCC(Y42B) +DEFINE_GUID_FOURCC(P422) +DEFINE_GUID_FOURCC(YUNV) +DEFINE_GUID_FOURCC(AVUI) +DEFINE_GUID_FOURCC(I444) +DEFINE_GUID_FOURCC(v308) +DEFINE_GUID_FOURCC(v408) +DEFINE_GUID_FOURCC(24BG) +DEFINE_GUID_FOURCC(BGRA) +DEFINE_GUID_FOURCC(ABGR) +DEFINE_GUID_FOURCC(RGBA) +DEFINE_GUID_FOURCC(RGB0) +DEFINE_GUID_FOURCC(0RGB) +DEFINE_GUID_FOURCC(b48r) +DEFINE_GUID_FOURCC(RBA64) +DEFINE_GUID_FOURCC(64RBA) +DEFINE_GUID_FOURCC(b64a) +DEFINE_GUID_FOURCC(Y410) +DEFINE_GUID_FOURCC(v216) +DEFINE_GUID_FOURCC(v416) +DEFINE_GUID_FOURCC(Y8) +DEFINE_GUID_FOURCC(Y16) diff --git a/include/unrar.h b/include/unrar.h index 268f00a069d..7225d1420c4 100644 --- a/include/unrar.h +++ b/include/unrar.h @@ -1,185 +1,185 @@ -#ifndef _UNRAR_DLL_ -#define _UNRAR_DLL_ - -#pragma pack(1) - -#define ERAR_SUCCESS 0 -#define ERAR_END_ARCHIVE 10 -#define ERAR_NO_MEMORY 11 -#define ERAR_BAD_DATA 12 -#define ERAR_BAD_ARCHIVE 13 -#define ERAR_UNKNOWN_FORMAT 14 -#define ERAR_EOPEN 15 -#define ERAR_ECREATE 16 -#define ERAR_ECLOSE 17 -#define ERAR_EREAD 18 -#define ERAR_EWRITE 19 -#define ERAR_SMALL_BUF 20 -#define ERAR_UNKNOWN 21 -#define ERAR_MISSING_PASSWORD 22 -#define ERAR_EREFERENCE 23 -#define ERAR_BAD_PASSWORD 24 - -#define RAR_OM_LIST 0 -#define RAR_OM_EXTRACT 1 -#define RAR_OM_LIST_INCSPLIT 2 - -#define RAR_SKIP 0 -#define RAR_TEST 1 -#define RAR_EXTRACT 2 - -#define RAR_VOL_ASK 0 -#define RAR_VOL_NOTIFY 1 - -#define RAR_DLL_VERSION 8 - -#define RAR_HASH_NONE 0 -#define RAR_HASH_CRC32 1 -#define RAR_HASH_BLAKE2 2 - - -#ifdef _UNIX -#define CALLBACK -#define PASCAL -#define LONG long -#define HANDLE void * -#define LPARAM long -#define UINT unsigned int -#endif - -#define RHDF_SPLITBEFORE 0x01 -#define RHDF_SPLITAFTER 0x02 -#define RHDF_ENCRYPTED 0x04 -#define RHDF_SOLID 0x10 -#define RHDF_DIRECTORY 0x20 - - -struct RARHeaderData -{ - char ArcName[260]; - char FileName[260]; - unsigned int Flags; - unsigned int PackSize; - unsigned int UnpSize; - unsigned int HostOS; - unsigned int FileCRC; - unsigned int FileTime; - unsigned int UnpVer; - unsigned int Method; - unsigned int FileAttr; - char *CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; -}; - - -struct RARHeaderDataEx -{ - char ArcName[1024]; - wchar_t ArcNameW[1024]; - char FileName[1024]; - wchar_t FileNameW[1024]; - unsigned int Flags; - unsigned int PackSize; - unsigned int PackSizeHigh; - unsigned int UnpSize; - unsigned int UnpSizeHigh; - unsigned int HostOS; - unsigned int FileCRC; - unsigned int FileTime; - unsigned int UnpVer; - unsigned int Method; - unsigned int FileAttr; - char *CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; - unsigned int DictSize; - unsigned int HashType; - char Hash[32]; - unsigned int RedirType; - wchar_t *RedirName; - unsigned int RedirNameSize; - unsigned int DirTarget; - unsigned int MtimeLow; - unsigned int MtimeHigh; - unsigned int CtimeLow; - unsigned int CtimeHigh; - unsigned int AtimeLow; - unsigned int AtimeHigh; - unsigned int Reserved[988]; -}; - - -struct RAROpenArchiveData -{ - char *ArcName; - unsigned int OpenMode; - unsigned int OpenResult; - char *CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; -}; - -typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2); - -#define ROADF_VOLUME 0x0001 -#define ROADF_COMMENT 0x0002 -#define ROADF_LOCK 0x0004 -#define ROADF_SOLID 0x0008 -#define ROADF_NEWNUMBERING 0x0010 -#define ROADF_SIGNED 0x0020 -#define ROADF_RECOVERY 0x0040 -#define ROADF_ENCHEADERS 0x0080 -#define ROADF_FIRSTVOLUME 0x0100 - -struct RAROpenArchiveDataEx -{ - char *ArcName; - wchar_t *ArcNameW; - unsigned int OpenMode; - unsigned int OpenResult; - char *CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; - unsigned int Flags; - UNRARCALLBACK Callback; - LPARAM UserData; - unsigned int Reserved[28]; -}; - -enum UNRARCALLBACK_MESSAGES { - UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW, - UCM_NEEDPASSWORDW -}; - -typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); -typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); - -#ifdef __cplusplus -extern "C" { -#endif - -typedef HANDLE (PASCAL *RAROpenArchive)(struct RAROpenArchiveData *ArchiveData); -typedef HANDLE (PASCAL *RAROpenArchiveEx)(struct RAROpenArchiveDataEx *ArchiveData); -typedef int (PASCAL *RARCloseArchive)(HANDLE hArcData); -typedef int (PASCAL *RARReadHeader)(HANDLE hArcData,struct RARHeaderData *HeaderData); -typedef int (PASCAL *RARReadHeaderEx)(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); -typedef int (PASCAL *RARProcessFile)(HANDLE hArcData,int Operation,char *DestPath,char *DestName); -typedef int (PASCAL *RARProcessFileW)(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); -typedef void (PASCAL *RARSetCallback)(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); -typedef void (PASCAL *RARSetChangeVolProc)(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); -typedef void (PASCAL *RARSetProcessDataProc)(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); -typedef void (PASCAL *RARSetPassword)(HANDLE hArcData,char *Password); -typedef int (PASCAL *RARGetDllVersion)(); - -#ifdef __cplusplus -} -#endif - -#pragma pack() - -#endif +#ifndef _UNRAR_DLL_ +#define _UNRAR_DLL_ + +#pragma pack(1) + +#define ERAR_SUCCESS 0 +#define ERAR_END_ARCHIVE 10 +#define ERAR_NO_MEMORY 11 +#define ERAR_BAD_DATA 12 +#define ERAR_BAD_ARCHIVE 13 +#define ERAR_UNKNOWN_FORMAT 14 +#define ERAR_EOPEN 15 +#define ERAR_ECREATE 16 +#define ERAR_ECLOSE 17 +#define ERAR_EREAD 18 +#define ERAR_EWRITE 19 +#define ERAR_SMALL_BUF 20 +#define ERAR_UNKNOWN 21 +#define ERAR_MISSING_PASSWORD 22 +#define ERAR_EREFERENCE 23 +#define ERAR_BAD_PASSWORD 24 + +#define RAR_OM_LIST 0 +#define RAR_OM_EXTRACT 1 +#define RAR_OM_LIST_INCSPLIT 2 + +#define RAR_SKIP 0 +#define RAR_TEST 1 +#define RAR_EXTRACT 2 + +#define RAR_VOL_ASK 0 +#define RAR_VOL_NOTIFY 1 + +#define RAR_DLL_VERSION 8 + +#define RAR_HASH_NONE 0 +#define RAR_HASH_CRC32 1 +#define RAR_HASH_BLAKE2 2 + + +#ifdef _UNIX +#define CALLBACK +#define PASCAL +#define LONG long +#define HANDLE void * +#define LPARAM long +#define UINT unsigned int +#endif + +#define RHDF_SPLITBEFORE 0x01 +#define RHDF_SPLITAFTER 0x02 +#define RHDF_ENCRYPTED 0x04 +#define RHDF_SOLID 0x10 +#define RHDF_DIRECTORY 0x20 + + +struct RARHeaderData +{ + char ArcName[260]; + char FileName[260]; + unsigned int Flags; + unsigned int PackSize; + unsigned int UnpSize; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + + +struct RARHeaderDataEx +{ + char ArcName[1024]; + wchar_t ArcNameW[1024]; + char FileName[1024]; + wchar_t FileNameW[1024]; + unsigned int Flags; + unsigned int PackSize; + unsigned int PackSizeHigh; + unsigned int UnpSize; + unsigned int UnpSizeHigh; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int DictSize; + unsigned int HashType; + char Hash[32]; + unsigned int RedirType; + wchar_t *RedirName; + unsigned int RedirNameSize; + unsigned int DirTarget; + unsigned int MtimeLow; + unsigned int MtimeHigh; + unsigned int CtimeLow; + unsigned int CtimeHigh; + unsigned int AtimeLow; + unsigned int AtimeHigh; + unsigned int Reserved[988]; +}; + + +struct RAROpenArchiveData +{ + char *ArcName; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + +typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2); + +#define ROADF_VOLUME 0x0001 +#define ROADF_COMMENT 0x0002 +#define ROADF_LOCK 0x0004 +#define ROADF_SOLID 0x0008 +#define ROADF_NEWNUMBERING 0x0010 +#define ROADF_SIGNED 0x0020 +#define ROADF_RECOVERY 0x0040 +#define ROADF_ENCHEADERS 0x0080 +#define ROADF_FIRSTVOLUME 0x0100 + +struct RAROpenArchiveDataEx +{ + char *ArcName; + wchar_t *ArcNameW; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int Flags; + UNRARCALLBACK Callback; + LPARAM UserData; + unsigned int Reserved[28]; +}; + +enum UNRARCALLBACK_MESSAGES { + UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW, + UCM_NEEDPASSWORDW +}; + +typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); +typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); + +#ifdef __cplusplus +extern "C" { +#endif + +typedef HANDLE (PASCAL *RAROpenArchive)(struct RAROpenArchiveData *ArchiveData); +typedef HANDLE (PASCAL *RAROpenArchiveEx)(struct RAROpenArchiveDataEx *ArchiveData); +typedef int (PASCAL *RARCloseArchive)(HANDLE hArcData); +typedef int (PASCAL *RARReadHeader)(HANDLE hArcData,struct RARHeaderData *HeaderData); +typedef int (PASCAL *RARReadHeaderEx)(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); +typedef int (PASCAL *RARProcessFile)(HANDLE hArcData,int Operation,char *DestPath,char *DestName); +typedef int (PASCAL *RARProcessFileW)(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); +typedef void (PASCAL *RARSetCallback)(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); +typedef void (PASCAL *RARSetChangeVolProc)(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); +typedef void (PASCAL *RARSetProcessDataProc)(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); +typedef void (PASCAL *RARSetPassword)(HANDLE hArcData,char *Password); +typedef int (PASCAL *RARGetDllVersion)(); + +#ifdef __cplusplus +} +#endif + +#pragma pack() + +#endif diff --git a/include/vd2/Copying b/include/vd2/Copying index 92851102051..a43ea2126fb 100644 --- a/include/vd2/Copying +++ b/include/vd2/Copying @@ -1,339 +1,339 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/include/vd2/OldFilterSDK/Filter.h b/include/vd2/OldFilterSDK/Filter.h index c2a40040384..1d74e7ae38c 100644 --- a/include/vd2/OldFilterSDK/Filter.h +++ b/include/vd2/OldFilterSDK/Filter.h @@ -1,57 +1,57 @@ -#ifndef f_FILTER_H -#define f_FILTER_H - -#include -#include - -// This is really dumb, but necessary to support VTbls in C++. - -typedef struct VDXFilterVTbls { - void *pvtblVBitmap; -} FilterVTbls; - -#ifdef VDEXT_MAIN - VDXFilterVTbls g_vtbls; -#elif defined(VDEXT_NOTMAIN) - extern VDXFilterVTbls g_vtbls; -#endif - -#define INITIALIZE_VTBLS ff->InitVTables(&g_vtbls) - -#include "VBitmap.h" - -typedef ::VDXFilterInitProc FilterInitProc; -typedef ::VDXFilterDeinitProc FilterDeinitProc; -typedef ::VDXFilterRunProc FilterRunProc; -typedef ::VDXFilterParamProc FilterParamProc; -typedef ::VDXFilterConfigProc FilterConfigProc; -typedef ::VDXFilterStringProc FilterStringProc; -typedef ::VDXFilterStartProc FilterStartProc; -typedef ::VDXFilterEndProc FilterEndProc; -typedef ::VDXFilterScriptStrProc FilterScriptStrProc; -typedef ::VDXFilterStringProc2 FilterStringProc2; -typedef ::VDXFilterSerialize FilterSerialize; -typedef ::VDXFilterDeserialize FilterDeserialize; -typedef ::VDXFilterCopy FilterCopy; - -typedef ::VDXFilterModuleInitProc FilterModuleInitProc; -typedef ::VDXFilterModuleDeinitProc FilterModuleDeinitProc; - -////////// - -typedef ::VDXFilterPreviewButtonCallback FilterPreviewButtonCallback; -typedef ::VDXFilterPreviewSampleCallback FilterPreviewSampleCallback; - -typedef ::IVDXFilterPreview IFilterPreview; - -////////// - -typedef ::VDXFilterModule FilterModule; -typedef ::VDXFilterDefinition FilterDefinition; -typedef ::VDXFilterStateInfo FilterStateInfo; -typedef ::VDXFBitmap VFBitmap; - -typedef ::VDXFilterActivation FilterActivation; -typedef ::VDXFilterFunctions FilterFunctions; - -#endif +#ifndef f_FILTER_H +#define f_FILTER_H + +#include +#include + +// This is really dumb, but necessary to support VTbls in C++. + +typedef struct VDXFilterVTbls { + void *pvtblVBitmap; +} FilterVTbls; + +#ifdef VDEXT_MAIN + VDXFilterVTbls g_vtbls; +#elif defined(VDEXT_NOTMAIN) + extern VDXFilterVTbls g_vtbls; +#endif + +#define INITIALIZE_VTBLS ff->InitVTables(&g_vtbls) + +#include "VBitmap.h" + +typedef ::VDXFilterInitProc FilterInitProc; +typedef ::VDXFilterDeinitProc FilterDeinitProc; +typedef ::VDXFilterRunProc FilterRunProc; +typedef ::VDXFilterParamProc FilterParamProc; +typedef ::VDXFilterConfigProc FilterConfigProc; +typedef ::VDXFilterStringProc FilterStringProc; +typedef ::VDXFilterStartProc FilterStartProc; +typedef ::VDXFilterEndProc FilterEndProc; +typedef ::VDXFilterScriptStrProc FilterScriptStrProc; +typedef ::VDXFilterStringProc2 FilterStringProc2; +typedef ::VDXFilterSerialize FilterSerialize; +typedef ::VDXFilterDeserialize FilterDeserialize; +typedef ::VDXFilterCopy FilterCopy; + +typedef ::VDXFilterModuleInitProc FilterModuleInitProc; +typedef ::VDXFilterModuleDeinitProc FilterModuleDeinitProc; + +////////// + +typedef ::VDXFilterPreviewButtonCallback FilterPreviewButtonCallback; +typedef ::VDXFilterPreviewSampleCallback FilterPreviewSampleCallback; + +typedef ::IVDXFilterPreview IFilterPreview; + +////////// + +typedef ::VDXFilterModule FilterModule; +typedef ::VDXFilterDefinition FilterDefinition; +typedef ::VDXFilterStateInfo FilterStateInfo; +typedef ::VDXFBitmap VFBitmap; + +typedef ::VDXFilterActivation FilterActivation; +typedef ::VDXFilterFunctions FilterFunctions; + +#endif diff --git a/include/vd2/OldFilterSDK/ScriptError.h b/include/vd2/OldFilterSDK/ScriptError.h index 900a9fc0793..d024eca8419 100644 --- a/include/vd2/OldFilterSDK/ScriptError.h +++ b/include/vd2/OldFilterSDK/ScriptError.h @@ -1,8 +1,8 @@ -#ifndef f_SYLIA_SCRIPTERROR_H -#define f_SYLIA_SCRIPTERROR_H - -#include - -typedef ::VDXScriptError CScriptError; - -#endif +#ifndef f_SYLIA_SCRIPTERROR_H +#define f_SYLIA_SCRIPTERROR_H + +#include + +typedef ::VDXScriptError CScriptError; + +#endif diff --git a/include/vd2/OldFilterSDK/ScriptInterpreter.h b/include/vd2/OldFilterSDK/ScriptInterpreter.h index fd12e969e7b..62e19772a96 100644 --- a/include/vd2/OldFilterSDK/ScriptInterpreter.h +++ b/include/vd2/OldFilterSDK/ScriptInterpreter.h @@ -1,11 +1,11 @@ -#ifndef f_SYLIA_SCRIPTINTERPRETER_H -#define f_SYLIA_SCRIPTINTERPRETER_H - -#include - -typedef ::VDXScriptValue CScriptValue; -typedef ::VDXScriptError CScriptError; -typedef ::VDXScriptObject CScriptObject; -typedef ::IVDXScriptInterpreter IScriptInterpreter; - -#endif +#ifndef f_SYLIA_SCRIPTINTERPRETER_H +#define f_SYLIA_SCRIPTINTERPRETER_H + +#include + +typedef ::VDXScriptValue CScriptValue; +typedef ::VDXScriptError CScriptError; +typedef ::VDXScriptObject CScriptObject; +typedef ::IVDXScriptInterpreter IScriptInterpreter; + +#endif diff --git a/include/vd2/OldFilterSDK/ScriptValue.h b/include/vd2/OldFilterSDK/ScriptValue.h index 0d8628469a4..60aae619908 100644 --- a/include/vd2/OldFilterSDK/ScriptValue.h +++ b/include/vd2/OldFilterSDK/ScriptValue.h @@ -1,17 +1,17 @@ -#ifndef f_SYLIA_SCRIPTVALUE_H -#define f_SYLIA_SCRIPTVALUE_H - -#include - -typedef ::VDXScriptObject CScriptObject; -typedef ::VDXScriptValue CScriptValue; -typedef ::IVDXScriptInterpreter IScriptInterpreter; - -typedef ::VDXScriptFunctionPtr ScriptFunctionPtr; -typedef ::VDXVoidScriptFunctionPtr ScriptVoidFunctionPtr; -typedef ::VDXIntScriptFunctionPtr ScriptIntFunctionPtr; - -typedef ::VDXScriptFunctionDef ScriptFunctionDef; -typedef ::VDXScriptObject CScriptObject; - -#endif +#ifndef f_SYLIA_SCRIPTVALUE_H +#define f_SYLIA_SCRIPTVALUE_H + +#include + +typedef ::VDXScriptObject CScriptObject; +typedef ::VDXScriptValue CScriptValue; +typedef ::IVDXScriptInterpreter IScriptInterpreter; + +typedef ::VDXScriptFunctionPtr ScriptFunctionPtr; +typedef ::VDXVoidScriptFunctionPtr ScriptVoidFunctionPtr; +typedef ::VDXIntScriptFunctionPtr ScriptIntFunctionPtr; + +typedef ::VDXScriptFunctionDef ScriptFunctionDef; +typedef ::VDXScriptObject CScriptObject; + +#endif diff --git a/include/vd2/OldFilterSDK/VBitmap.h b/include/vd2/OldFilterSDK/VBitmap.h index 08795ac5fa2..7daa475eb84 100644 --- a/include/vd2/OldFilterSDK/VBitmap.h +++ b/include/vd2/OldFilterSDK/VBitmap.h @@ -1,16 +1,16 @@ -#ifndef f_VIRTUALDUB_VBITMAP_H -#define f_VIRTUALDUB_VBITMAP_H - -#include -#include - -typedef unsigned Pixel; -typedef unsigned Pixel32; -typedef unsigned char Pixel8; -typedef int PixCoord; -typedef int PixDim; -typedef ptrdiff_t PixOffset; - -typedef ::VDXBitmap VBitmap; - -#endif +#ifndef f_VIRTUALDUB_VBITMAP_H +#define f_VIRTUALDUB_VBITMAP_H + +#include +#include + +typedef unsigned Pixel; +typedef unsigned Pixel32; +typedef unsigned char Pixel8; +typedef int PixCoord; +typedef int PixDim; +typedef ptrdiff_t PixOffset; + +typedef ::VDXBitmap VBitmap; + +#endif diff --git a/include/vd2/OldFilterSDK/VirtualDub.h b/include/vd2/OldFilterSDK/VirtualDub.h index 25e5fd47595..5195b15f55d 100644 --- a/include/vd2/OldFilterSDK/VirtualDub.h +++ b/include/vd2/OldFilterSDK/VirtualDub.h @@ -1,7 +1,7 @@ -#pragma once - -#include "Filter.h" -#include "ScriptInterpreter.h" -#include "ScriptError.h" -#include "ScriptValue.h" -#include "VBitmap.h" +#pragma once + +#include "Filter.h" +#include "ScriptInterpreter.h" +#include "ScriptError.h" +#include "ScriptValue.h" +#include "VBitmap.h" diff --git a/include/vd2/VDXFrame/Unknown.h b/include/vd2/VDXFrame/Unknown.h index 34de61f46f2..57c6b317db5 100644 --- a/include/vd2/VDXFrame/Unknown.h +++ b/include/vd2/VDXFrame/Unknown.h @@ -1,110 +1,110 @@ -// VDXFrame - Helper library for VirtualDub plugins -// Copyright (C) 2008 Avery Lee -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_VDXFRAME_UNKNOWN_H -#define f_VD2_VDXFRAME_UNKNOWN_H - -#include - -extern "C" long _InterlockedExchangeAdd(volatile long *p, long v); -#pragma intrinsic(_InterlockedExchangeAdd) - -template class vdxunknown : public T { -public: - vdxunknown() : mRefCount(0) {} - vdxunknown(const vdxunknown& src) : mRefCount(0) {} // do not copy the refcount - virtual ~vdxunknown() {} - - vdxunknown& operator=(const vdxunknown&) {} // do not copy the refcount - - virtual int VDXAPIENTRY AddRef() { - return _InterlockedExchangeAdd(&mRefCount, 1) + 1; - } - - virtual int VDXAPIENTRY Release() { - long rc = _InterlockedExchangeAdd(&mRefCount, -1) - 1; - if (!mRefCount) { - mRefCount = 1; - delete this; - return 0; - } - - return rc; - } - - virtual void *VDXAPIENTRY AsInterface(uint32 iid) { - if (iid == T::kIID) - return static_cast(this); - - if (iid == IVDXUnknown::kIID) - return static_cast(this); - - return NULL; - } - -protected: - volatile long mRefCount; -}; - -template class vdxunknown2 : public T1, public T2 { -public: - vdxunknown2() : mRefCount(0) {} - vdxunknown2(const vdxunknown2& src) : mRefCount(0) {} // do not copy the refcount - virtual ~vdxunknown2() {} - - vdxunknown2& operator=(const vdxunknown2&) {} // do not copy the refcount - - virtual int VDXAPIENTRY AddRef() { - return _InterlockedExchangeAdd(&mRefCount, 1) + 1; - } - - virtual int VDXAPIENTRY Release() { - long rc = _InterlockedExchangeAdd(&mRefCount, -1) - 1; - if (!mRefCount) { - mRefCount = 1; - delete this; - return 0; - } - - return rc; - } - - virtual void *VDXAPIENTRY AsInterface(uint32 iid) { - if (iid == T1::kIID) - return static_cast(this); - - if (iid == T2::kIID) - return static_cast(this); - - if (iid == IVDXUnknown::kIID) - return static_cast(static_cast(this)); - - return NULL; - } - -protected: - volatile long mRefCount; -}; - -#endif +// VDXFrame - Helper library for VirtualDub plugins +// Copyright (C) 2008 Avery Lee +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_VDXFRAME_UNKNOWN_H +#define f_VD2_VDXFRAME_UNKNOWN_H + +#include + +extern "C" long _InterlockedExchangeAdd(volatile long *p, long v); +#pragma intrinsic(_InterlockedExchangeAdd) + +template class vdxunknown : public T { +public: + vdxunknown() : mRefCount(0) {} + vdxunknown(const vdxunknown& src) : mRefCount(0) {} // do not copy the refcount + virtual ~vdxunknown() {} + + vdxunknown& operator=(const vdxunknown&) {} // do not copy the refcount + + virtual int VDXAPIENTRY AddRef() { + return _InterlockedExchangeAdd(&mRefCount, 1) + 1; + } + + virtual int VDXAPIENTRY Release() { + long rc = _InterlockedExchangeAdd(&mRefCount, -1) - 1; + if (!mRefCount) { + mRefCount = 1; + delete this; + return 0; + } + + return rc; + } + + virtual void *VDXAPIENTRY AsInterface(uint32 iid) { + if (iid == T::kIID) + return static_cast(this); + + if (iid == IVDXUnknown::kIID) + return static_cast(this); + + return NULL; + } + +protected: + volatile long mRefCount; +}; + +template class vdxunknown2 : public T1, public T2 { +public: + vdxunknown2() : mRefCount(0) {} + vdxunknown2(const vdxunknown2& src) : mRefCount(0) {} // do not copy the refcount + virtual ~vdxunknown2() {} + + vdxunknown2& operator=(const vdxunknown2&) {} // do not copy the refcount + + virtual int VDXAPIENTRY AddRef() { + return _InterlockedExchangeAdd(&mRefCount, 1) + 1; + } + + virtual int VDXAPIENTRY Release() { + long rc = _InterlockedExchangeAdd(&mRefCount, -1) - 1; + if (!mRefCount) { + mRefCount = 1; + delete this; + return 0; + } + + return rc; + } + + virtual void *VDXAPIENTRY AsInterface(uint32 iid) { + if (iid == T1::kIID) + return static_cast(this); + + if (iid == T2::kIID) + return static_cast(this); + + if (iid == IVDXUnknown::kIID) + return static_cast(static_cast(this)); + + return NULL; + } + +protected: + volatile long mRefCount; +}; + +#endif diff --git a/include/vd2/VDXFrame/VideoFilter.h b/include/vd2/VDXFrame/VideoFilter.h index 78ef03bd195..219e2960b2a 100644 --- a/include/vd2/VDXFrame/VideoFilter.h +++ b/include/vd2/VDXFrame/VideoFilter.h @@ -1,221 +1,221 @@ -// VDXFrame - Helper library for VirtualDub plugins -// Copyright (C) 2008 Avery Lee -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_VDXFRAME_VIDEOFILTER_H -#define f_VD2_VDXFRAME_VIDEOFILTER_H - -#include -#include -#include - -#include - -/////////////////////////////////////////////////////////////////////////// -/// \class VDXVideoFilter -/// -/// This class handles most of the grimy work of creating the interface -/// between your filter and VirtualDub. -/// -class VDXVideoFilter { -public: - VDXVideoFilter(); - virtual ~VDXVideoFilter(); - - void SetHooks(VDXFilterActivation *fa, const VDXFilterFunctions *ff); - - // linkage routines - - virtual bool Init(); - virtual uint32 GetParams()=0; - virtual void Start(); - virtual void Run() = 0; - virtual void End(); - virtual bool Configure(VDXHWND hwnd); - virtual void GetSettingString(char *buf, int maxlen); - virtual void GetScriptString(char *buf, int maxlen); - virtual int Serialize(char *buf, int maxbuf); - virtual int Deserialize(const char *buf, int maxbuf); - virtual sint64 Prefetch(sint64 frame); - virtual bool Prefetch2(sint64 frame, IVDXVideoPrefetcher *prefetcher); - - virtual bool OnEvent(uint32 event, const void *eventData); - virtual bool OnInvalidateCaches(); - - static void __cdecl FilterDeinit (VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static int __cdecl FilterRun (const VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static long __cdecl FilterParam (VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static int __cdecl FilterConfig (VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hWnd); - static int __cdecl FilterStart (VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static int __cdecl FilterEnd (VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static void __cdecl FilterString (const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf); - static bool __cdecl FilterScriptStr(VDXFilterActivation *fa, const VDXFilterFunctions *, char *, int); - static void __cdecl FilterString2 (const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen); - static int __cdecl FilterSerialize (VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxbuf); - static void __cdecl FilterDeserialize (VDXFilterActivation *fa, const VDXFilterFunctions *ff, const char *buf, int maxbuf); - static sint64 __cdecl FilterPrefetch(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame); - static bool __cdecl FilterPrefetch2(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame, IVDXVideoPrefetcher *prefetcher); - static bool __cdecl FilterEvent(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, uint32 event, const void *eventData); - - // member variables - VDXFilterActivation *fa; - const VDXFilterFunctions *ff; - - static const VDXScriptFunctionDef sScriptMethods[]; - -protected: - void SafePrintf(char *buf, int maxbuf, const char *format, ...); -}; - -/////////////////////////////////////////////////////////////////////////// -// Script method support -// -// To declare a Config() script method, add -// -// VDXVF_DECLARE_SCRIPT_METHODS() -// -// to the public portion of your class definition, and then add a method -// table at namespace scope: -// -// VDXVF_BEGIN_SCRIPT_METHODS(YUVTransformFilter) -// VDXVF_DEFINE_SCRIPT_METHOD(YUVTransformFilter, ScriptConfig, "iii") -// VDXVF_END_SCRIPT_METHODS() -// -// Use VDXVF_DEFINE_SCRIPT_METHOD() for the first method, and then -// VDXVF_DEFINE_SCRIPT_METHOD2() for any overloads. - -#define VDXVF_DECLARE_SCRIPT_METHODS() static const VDXScriptFunctionDef sScriptMethods[] - -#define VDXVF_BEGIN_SCRIPT_METHODS(klass) const VDXScriptFunctionDef klass::sScriptMethods[] = { -#define VDXVF_DEFINE_SCRIPT_METHOD(klass, method, args) { (VDXScriptFunctionPtr)VDXVideoFilterScriptAdapter::AdaptFn, "Config", "0" args }, -#define VDXVF_DEFINE_SCRIPT_METHOD2(klass, method, args) { (VDXScriptFunctionPtr)VDXVideoFilterScriptAdapter::AdaptFn, NULL, "0" args }, -#define VDXVF_END_SCRIPT_METHODS() { NULL } }; - -extern char VDXVideoFilterConfigureOverloadTest(bool (VDXVideoFilter::*)(VDXHWND)); -extern double VDXVideoFilterConfigureOverloadTest(...); -extern char VDXVideoFilterPrefetchOverloadTest(sint64 (VDXVideoFilter::*)(sint64)); -extern double VDXVideoFilterPrefetchOverloadTest(...); -extern char VDXVideoFilterPrefetch2OverloadTest(bool (VDXVideoFilter::*)(sint64, IVDXVideoPrefetcher *)); -extern double VDXVideoFilterPrefetch2OverloadTest(...); - -template -class VDXVideoFilterScriptAdapter -{ -public: - static void AdaptFn(IVDXScriptInterpreter *isi, void *fa0, const VDXScriptValue *argv, int argc) { - VDXFilterActivation *fa = (VDXFilterActivation *)fa0; - VDXVideoFilter *base = *(VDXVideoFilter **)fa->filter_data; - (static_cast(base)->*T_Method)(isi, argv, argc); - } -}; - -template -class VDXVideoFilterScriptObjectAdapter { -public: - static const VDXScriptObject sScriptObject; -}; - -template -const VDXScriptObject VDXVideoFilterScriptObjectAdapter::sScriptObject = { - NULL, (T::sScriptMethods == VDXVideoFilter::sScriptMethods) ? NULL : (VDXScriptFunctionDef *)static_cast(T::sScriptMethods), NULL -}; - -/////////////////////////////////////////////////////////////////////////// -/// \class VDXVideoFilterDefinition -/// -/// This template creates the FilterDefinition structure for you based on -/// your filter class. -/// -template -class VDXVideoFilterDefinition : public VDXFilterDefinition { -public: - VDXVideoFilterDefinition(const char *pszAuthor, const char *pszName, const char *pszDescription) { - _next = NULL; - _prev = NULL; - _module = NULL; - - name = pszName; - desc = pszDescription; - maker = pszAuthor; - private_data = NULL; - inst_data_size = sizeof(T) + sizeof(VDXVideoFilter *); - - initProc = FilterInit; - deinitProc = T::FilterDeinit; - runProc = T::FilterRun; - paramProc = T::FilterParam; - configProc = sizeof(VDXVideoFilterConfigureOverloadTest(&T::Configure)) > 1 ? T::FilterConfig : NULL; - stringProc = T::FilterString; - startProc = T::FilterStart; - endProc = T::FilterEnd; - - script_obj = T::sScriptMethods ? const_cast(&VDXVideoFilterScriptObjectAdapter::sScriptObject) : 0; - fssProc = T::FilterScriptStr; - - stringProc2 = T::FilterString2; - serializeProc = T::FilterSerialize; - deserializeProc = T::FilterDeserialize; - copyProc = FilterCopy; - copyProc2 = FilterCopy2; - - prefetchProc = sizeof(VDXVideoFilterPrefetchOverloadTest(&T::Prefetch)) > 1 ? T::FilterPrefetch : NULL; - prefetchProc2 = sizeof(VDXVideoFilterPrefetch2OverloadTest(&T::Prefetch2)) > 1 || sizeof(VDXVideoFilterPrefetchOverloadTest(&T::Prefetch)) > 1 ? T::FilterPrefetch2 : NULL; - - eventProc = T::FilterEvent; - } - -private: - static int __cdecl FilterInit (VDXFilterActivation *fa, const VDXFilterFunctions *ff) { - T *pThis = new((char *)fa->filter_data + sizeof(VDXVideoFilter *)) T; - *(VDXVideoFilter **)fa->filter_data = static_cast(pThis); - - pThis->SetHooks(fa, ff); - - try { - if (!pThis->Init()) { - pThis->~T(); - return 1; - } - - return 0; - } catch(...) { - pThis->~T(); - throw; - } - } - - static void __cdecl FilterCopy (VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst) { - T *p = new((char *)dst + sizeof(VDXVideoFilter *)) T(*static_cast(*reinterpret_cast(fa->filter_data))); - p->ff = ff; - *(VDXVideoFilter **)dst = p; - } - - static void __cdecl FilterCopy2 (VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst, VDXFilterActivation *fanew, const VDXFilterFunctions *ffnew) { - T *p = new((char *)dst + sizeof(VDXVideoFilter *)) T(*static_cast(*reinterpret_cast(fa->filter_data))); - p->ff = ffnew; - p->fa = fanew; - *(VDXVideoFilter **)dst = p; - } -}; - -#endif +// VDXFrame - Helper library for VirtualDub plugins +// Copyright (C) 2008 Avery Lee +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_VDXFRAME_VIDEOFILTER_H +#define f_VD2_VDXFRAME_VIDEOFILTER_H + +#include +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////// +/// \class VDXVideoFilter +/// +/// This class handles most of the grimy work of creating the interface +/// between your filter and VirtualDub. +/// +class VDXVideoFilter { +public: + VDXVideoFilter(); + virtual ~VDXVideoFilter(); + + void SetHooks(VDXFilterActivation *fa, const VDXFilterFunctions *ff); + + // linkage routines + + virtual bool Init(); + virtual uint32 GetParams()=0; + virtual void Start(); + virtual void Run() = 0; + virtual void End(); + virtual bool Configure(VDXHWND hwnd); + virtual void GetSettingString(char *buf, int maxlen); + virtual void GetScriptString(char *buf, int maxlen); + virtual int Serialize(char *buf, int maxbuf); + virtual int Deserialize(const char *buf, int maxbuf); + virtual sint64 Prefetch(sint64 frame); + virtual bool Prefetch2(sint64 frame, IVDXVideoPrefetcher *prefetcher); + + virtual bool OnEvent(uint32 event, const void *eventData); + virtual bool OnInvalidateCaches(); + + static void __cdecl FilterDeinit (VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static int __cdecl FilterRun (const VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static long __cdecl FilterParam (VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static int __cdecl FilterConfig (VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hWnd); + static int __cdecl FilterStart (VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static int __cdecl FilterEnd (VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static void __cdecl FilterString (const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf); + static bool __cdecl FilterScriptStr(VDXFilterActivation *fa, const VDXFilterFunctions *, char *, int); + static void __cdecl FilterString2 (const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen); + static int __cdecl FilterSerialize (VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxbuf); + static void __cdecl FilterDeserialize (VDXFilterActivation *fa, const VDXFilterFunctions *ff, const char *buf, int maxbuf); + static sint64 __cdecl FilterPrefetch(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame); + static bool __cdecl FilterPrefetch2(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame, IVDXVideoPrefetcher *prefetcher); + static bool __cdecl FilterEvent(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, uint32 event, const void *eventData); + + // member variables + VDXFilterActivation *fa; + const VDXFilterFunctions *ff; + + static const VDXScriptFunctionDef sScriptMethods[]; + +protected: + void SafePrintf(char *buf, int maxbuf, const char *format, ...); +}; + +/////////////////////////////////////////////////////////////////////////// +// Script method support +// +// To declare a Config() script method, add +// +// VDXVF_DECLARE_SCRIPT_METHODS() +// +// to the public portion of your class definition, and then add a method +// table at namespace scope: +// +// VDXVF_BEGIN_SCRIPT_METHODS(YUVTransformFilter) +// VDXVF_DEFINE_SCRIPT_METHOD(YUVTransformFilter, ScriptConfig, "iii") +// VDXVF_END_SCRIPT_METHODS() +// +// Use VDXVF_DEFINE_SCRIPT_METHOD() for the first method, and then +// VDXVF_DEFINE_SCRIPT_METHOD2() for any overloads. + +#define VDXVF_DECLARE_SCRIPT_METHODS() static const VDXScriptFunctionDef sScriptMethods[] + +#define VDXVF_BEGIN_SCRIPT_METHODS(klass) const VDXScriptFunctionDef klass::sScriptMethods[] = { +#define VDXVF_DEFINE_SCRIPT_METHOD(klass, method, args) { (VDXScriptFunctionPtr)VDXVideoFilterScriptAdapter::AdaptFn, "Config", "0" args }, +#define VDXVF_DEFINE_SCRIPT_METHOD2(klass, method, args) { (VDXScriptFunctionPtr)VDXVideoFilterScriptAdapter::AdaptFn, NULL, "0" args }, +#define VDXVF_END_SCRIPT_METHODS() { NULL } }; + +extern char VDXVideoFilterConfigureOverloadTest(bool (VDXVideoFilter::*)(VDXHWND)); +extern double VDXVideoFilterConfigureOverloadTest(...); +extern char VDXVideoFilterPrefetchOverloadTest(sint64 (VDXVideoFilter::*)(sint64)); +extern double VDXVideoFilterPrefetchOverloadTest(...); +extern char VDXVideoFilterPrefetch2OverloadTest(bool (VDXVideoFilter::*)(sint64, IVDXVideoPrefetcher *)); +extern double VDXVideoFilterPrefetch2OverloadTest(...); + +template +class VDXVideoFilterScriptAdapter +{ +public: + static void AdaptFn(IVDXScriptInterpreter *isi, void *fa0, const VDXScriptValue *argv, int argc) { + VDXFilterActivation *fa = (VDXFilterActivation *)fa0; + VDXVideoFilter *base = *(VDXVideoFilter **)fa->filter_data; + (static_cast(base)->*T_Method)(isi, argv, argc); + } +}; + +template +class VDXVideoFilterScriptObjectAdapter { +public: + static const VDXScriptObject sScriptObject; +}; + +template +const VDXScriptObject VDXVideoFilterScriptObjectAdapter::sScriptObject = { + NULL, (T::sScriptMethods == VDXVideoFilter::sScriptMethods) ? NULL : (VDXScriptFunctionDef *)static_cast(T::sScriptMethods), NULL +}; + +/////////////////////////////////////////////////////////////////////////// +/// \class VDXVideoFilterDefinition +/// +/// This template creates the FilterDefinition structure for you based on +/// your filter class. +/// +template +class VDXVideoFilterDefinition : public VDXFilterDefinition { +public: + VDXVideoFilterDefinition(const char *pszAuthor, const char *pszName, const char *pszDescription) { + _next = NULL; + _prev = NULL; + _module = NULL; + + name = pszName; + desc = pszDescription; + maker = pszAuthor; + private_data = NULL; + inst_data_size = sizeof(T) + sizeof(VDXVideoFilter *); + + initProc = FilterInit; + deinitProc = T::FilterDeinit; + runProc = T::FilterRun; + paramProc = T::FilterParam; + configProc = sizeof(VDXVideoFilterConfigureOverloadTest(&T::Configure)) > 1 ? T::FilterConfig : NULL; + stringProc = T::FilterString; + startProc = T::FilterStart; + endProc = T::FilterEnd; + + script_obj = T::sScriptMethods ? const_cast(&VDXVideoFilterScriptObjectAdapter::sScriptObject) : 0; + fssProc = T::FilterScriptStr; + + stringProc2 = T::FilterString2; + serializeProc = T::FilterSerialize; + deserializeProc = T::FilterDeserialize; + copyProc = FilterCopy; + copyProc2 = FilterCopy2; + + prefetchProc = sizeof(VDXVideoFilterPrefetchOverloadTest(&T::Prefetch)) > 1 ? T::FilterPrefetch : NULL; + prefetchProc2 = sizeof(VDXVideoFilterPrefetch2OverloadTest(&T::Prefetch2)) > 1 || sizeof(VDXVideoFilterPrefetchOverloadTest(&T::Prefetch)) > 1 ? T::FilterPrefetch2 : NULL; + + eventProc = T::FilterEvent; + } + +private: + static int __cdecl FilterInit (VDXFilterActivation *fa, const VDXFilterFunctions *ff) { + T *pThis = new((char *)fa->filter_data + sizeof(VDXVideoFilter *)) T; + *(VDXVideoFilter **)fa->filter_data = static_cast(pThis); + + pThis->SetHooks(fa, ff); + + try { + if (!pThis->Init()) { + pThis->~T(); + return 1; + } + + return 0; + } catch(...) { + pThis->~T(); + throw; + } + } + + static void __cdecl FilterCopy (VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst) { + T *p = new((char *)dst + sizeof(VDXVideoFilter *)) T(*static_cast(*reinterpret_cast(fa->filter_data))); + p->ff = ff; + *(VDXVideoFilter **)dst = p; + } + + static void __cdecl FilterCopy2 (VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst, VDXFilterActivation *fanew, const VDXFilterFunctions *ffnew) { + T *p = new((char *)dst + sizeof(VDXVideoFilter *)) T(*static_cast(*reinterpret_cast(fa->filter_data))); + p->ff = ffnew; + p->fa = fanew; + *(VDXVideoFilter **)dst = p; + } +}; + +#endif diff --git a/include/vd2/VDXFrame/VideoFilterDialog.h b/include/vd2/VDXFrame/VideoFilterDialog.h index 1e9aa491766..51aaf2da370 100644 --- a/include/vd2/VDXFrame/VideoFilterDialog.h +++ b/include/vd2/VDXFrame/VideoFilterDialog.h @@ -1,46 +1,46 @@ -// VDXFrame - Helper library for VirtualDub plugins -// Copyright (C) 2008 Avery Lee -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_VDXFRAME_VIDEOFILTERDIALOG_H -#define f_VD2_VDXFRAME_VIDEOFILTERDIALOG_H - -#include - -class VDXVideoFilterDialog { -public: - VDXVideoFilterDialog(); - -protected: - HWND mhdlg; - - LRESULT Show(HINSTANCE hInst, LPCSTR templName, HWND parent); - LRESULT Show(HINSTANCE hInst, LPCWSTR templName, HWND parent); - HWND ShowModeless(HINSTANCE hInst, LPCSTR templName, HWND parent); - HWND ShowModeless(HINSTANCE hInst, LPCWSTR templName, HWND parent); - - static INT_PTR CALLBACK StaticDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam); - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); -}; - -#endif +// VDXFrame - Helper library for VirtualDub plugins +// Copyright (C) 2008 Avery Lee +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_VDXFRAME_VIDEOFILTERDIALOG_H +#define f_VD2_VDXFRAME_VIDEOFILTERDIALOG_H + +#include + +class VDXVideoFilterDialog { +public: + VDXVideoFilterDialog(); + +protected: + HWND mhdlg; + + LRESULT Show(HINSTANCE hInst, LPCSTR templName, HWND parent); + LRESULT Show(HINSTANCE hInst, LPCWSTR templName, HWND parent); + HWND ShowModeless(HINSTANCE hInst, LPCSTR templName, HWND parent); + HWND ShowModeless(HINSTANCE hInst, LPCWSTR templName, HWND parent); + + static INT_PTR CALLBACK StaticDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam); + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); +}; + +#endif diff --git a/include/vd2/VDXFrame/VideoFilterEntry.h b/include/vd2/VDXFrame/VideoFilterEntry.h index 112f02c3fcc..5eacf1c0bc7 100644 --- a/include/vd2/VDXFrame/VideoFilterEntry.h +++ b/include/vd2/VDXFrame/VideoFilterEntry.h @@ -1,84 +1,84 @@ -// VDXFrame - Helper library for VirtualDub plugins -// Copyright (C) 2008 Avery Lee -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_VDXFRAME_VIDEOFILTERENTRY_H -#define f_VD2_VDXFRAME_VIDEOFILTERENTRY_H - -#include - -#ifdef _MSC_VER - #pragma once -#endif - -struct VDXFilterModule; -struct VDXFilterFunctions; -struct VDXFilterDefinition; - -/////////////////////////////////////////////////////////////////////////////// -/// Video filter module entry point declaration macros -/// -/// To declare the module init and deinit functions: -/// -/// VDX_DECLARE_VFMODULE() -/// -/// By default this declares the module as requiring copy contructor support -/// (V9 / VirtualDub 1.4.12). If you need to declare a different minimum -/// version, use: -/// -/// VDX_DECLARE_VFMODULE_APIVER(version) -/// -#define VDX_DECLARE_VFMODULE() VDX_DECLARE_VFMODULE_APIVER(VIRTUALDUB_FILTERDEF_COMPATIBLE_COPYCTOR) -#define VDX_DECLARE_VFMODULE_APIVER(apiver) \ - extern "C" __declspec(dllexport) int __cdecl VirtualdubFilterModuleInit2(struct VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat) { \ - return VDXVideoFilterModuleInit2(fm, ff, vdfd_ver, vdfd_compat, (apiver)); \ - } \ - \ - extern "C" __declspec(dllexport) void __cdecl VirtualdubFilterModuleDeinit(struct VDXFilterModule *fm, const VDXFilterFunctions *ff) { \ - VDXVideoFilterModuleDeinit(fm, ff); \ - } - -/////////////////////////////////////////////////////////////////////////////// -/// Video filter declaration macros -/// -/// To declare video filters, use the following pattern: -/// -/// VDX_DECLARE_VIDEOFILTERS_BEGIN() -/// VDX_DECLARE_VIDEOFILTER(definitionSymbolName) -/// VDX_DECLARE_VIDEOFILTERS_END() -/// -/// Each entry points to a variable of type VDXFilterDefinition. Note that these must -/// be declared as _non-const_ for compatibility with older versions of VirtualDub. -/// Video filters declared this way are automatically registered by the module init -/// routine. -/// -#define VDX_DECLARE_VIDEOFILTERS_BEGIN() VDXFilterDefinition *VDXGetVideoFilterDefinition(int index) { -#define VDX_DECLARE_VIDEOFILTER(defVarName) if (!index--) { extern VDXFilterDefinition defVarName; return &defVarName; } -#define VDX_DECLARE_VIDEOFILTERS_END() return NULL; \ - } -int VDXVideoFilterModuleInit2(struct VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat, int ver_compat_target); -void VDXVideoFilterModuleDeinit(struct VDXFilterModule *fm, const VDXFilterFunctions *ff); - -int VDXGetVideoFilterAPIVersion(); - -#endif +// VDXFrame - Helper library for VirtualDub plugins +// Copyright (C) 2008 Avery Lee +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_VDXFRAME_VIDEOFILTERENTRY_H +#define f_VD2_VDXFRAME_VIDEOFILTERENTRY_H + +#include + +#ifdef _MSC_VER + #pragma once +#endif + +struct VDXFilterModule; +struct VDXFilterFunctions; +struct VDXFilterDefinition; + +/////////////////////////////////////////////////////////////////////////////// +/// Video filter module entry point declaration macros +/// +/// To declare the module init and deinit functions: +/// +/// VDX_DECLARE_VFMODULE() +/// +/// By default this declares the module as requiring copy contructor support +/// (V9 / VirtualDub 1.4.12). If you need to declare a different minimum +/// version, use: +/// +/// VDX_DECLARE_VFMODULE_APIVER(version) +/// +#define VDX_DECLARE_VFMODULE() VDX_DECLARE_VFMODULE_APIVER(VIRTUALDUB_FILTERDEF_COMPATIBLE_COPYCTOR) +#define VDX_DECLARE_VFMODULE_APIVER(apiver) \ + extern "C" __declspec(dllexport) int __cdecl VirtualdubFilterModuleInit2(struct VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat) { \ + return VDXVideoFilterModuleInit2(fm, ff, vdfd_ver, vdfd_compat, (apiver)); \ + } \ + \ + extern "C" __declspec(dllexport) void __cdecl VirtualdubFilterModuleDeinit(struct VDXFilterModule *fm, const VDXFilterFunctions *ff) { \ + VDXVideoFilterModuleDeinit(fm, ff); \ + } + +/////////////////////////////////////////////////////////////////////////////// +/// Video filter declaration macros +/// +/// To declare video filters, use the following pattern: +/// +/// VDX_DECLARE_VIDEOFILTERS_BEGIN() +/// VDX_DECLARE_VIDEOFILTER(definitionSymbolName) +/// VDX_DECLARE_VIDEOFILTERS_END() +/// +/// Each entry points to a variable of type VDXFilterDefinition. Note that these must +/// be declared as _non-const_ for compatibility with older versions of VirtualDub. +/// Video filters declared this way are automatically registered by the module init +/// routine. +/// +#define VDX_DECLARE_VIDEOFILTERS_BEGIN() VDXFilterDefinition *VDXGetVideoFilterDefinition(int index) { +#define VDX_DECLARE_VIDEOFILTER(defVarName) if (!index--) { extern VDXFilterDefinition defVarName; return &defVarName; } +#define VDX_DECLARE_VIDEOFILTERS_END() return NULL; \ + } +int VDXVideoFilterModuleInit2(struct VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat, int ver_compat_target); +void VDXVideoFilterModuleDeinit(struct VDXFilterModule *fm, const VDXFilterFunctions *ff); + +int VDXGetVideoFilterAPIVersion(); + +#endif diff --git a/include/vd2/extras/FilterSDK/Filter.h b/include/vd2/extras/FilterSDK/Filter.h index a8747a4a6b2..8e37795d4b2 100644 --- a/include/vd2/extras/FilterSDK/Filter.h +++ b/include/vd2/extras/FilterSDK/Filter.h @@ -1,244 +1,244 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - - -#ifndef f_FILTER_H -#define f_FILTER_H - -#include - -// This is really dumb, but necessary to support VTbls in C++. - -struct FilterVTbls { - void *pvtblVBitmap; -}; - -#ifdef VDEXT_MAIN -struct FilterVTbls g_vtbls; -#elif defined(VDEXT_NOTMAIN) -extern struct FilterVTbls g_vtbls; -#endif - -#define INITIALIZE_VTBLS ff->InitVTables(&g_vtbls) - -#include "VBitmap.h" - -////////////////// - -struct CScriptObject; - -////////////////// - -enum { - FILTERPARAM_SWAP_BUFFERS = 0x00000001L, - FILTERPARAM_NEEDS_LAST = 0x00000002L, -}; - -#define FILTERPARAM_HAS_LAG(frames) ((int)(frames) << 16) - -/////////////////// - -class VFBitmap; -class FilterActivation; -struct FilterFunctions; - -typedef int (*FilterInitProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef void (*FilterDeinitProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef int (*FilterRunProc )(const FilterActivation *fa, const FilterFunctions *ff); -typedef long (*FilterParamProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef int (*FilterConfigProc )(FilterActivation *fa, const FilterFunctions *ff, HWND hWnd); -typedef void (*FilterStringProc )(const FilterActivation *fa, const FilterFunctions *ff, char *buf); -typedef int (*FilterStartProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef int (*FilterEndProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef bool (*FilterScriptStrProc)(FilterActivation *fa, const FilterFunctions *, char *, int); -typedef void (*FilterStringProc2 )(const FilterActivation *fa, const FilterFunctions *ff, char *buf, int maxlen); -typedef int (*FilterSerialize )(FilterActivation *fa, const FilterFunctions *ff, char *buf, int maxbuf); -typedef void (*FilterDeserialize )(FilterActivation *fa, const FilterFunctions *ff, const char *buf, int maxbuf); -typedef void (*FilterCopy )(FilterActivation *fa, const FilterFunctions *ff, void *dst); - -typedef int (__cdecl *FilterModuleInitProc)(struct FilterModule *fm, const FilterFunctions *ff, int& vdfd_ver, int& vdfd_compat); -typedef void (__cdecl *FilterModuleDeinitProc)(struct FilterModule *fm, const FilterFunctions *ff); - -////////// - -typedef void (__cdecl *FilterPreviewButtonCallback)(bool fNewState, void *pData); -typedef void (__cdecl *FilterPreviewSampleCallback)(VFBitmap *, long lFrame, long lCount, void *pData); - -class IFilterPreview { -public: - virtual void SetButtonCallback(FilterPreviewButtonCallback, void *)=0; - virtual void SetSampleCallback(FilterPreviewSampleCallback, void *)=0; - - virtual bool isPreviewEnabled()=0; - virtual void Toggle(HWND)=0; - virtual void Display(HWND, bool)=0; - virtual void RedoFrame()=0; - virtual void RedoSystem()=0; - virtual void UndoSystem()=0; - virtual void InitButton(HWND)=0; - virtual void Close()=0; - virtual bool SampleCurrentFrame()=0; - virtual long SampleFrames()=0; -}; - -////////// - -#define VIRTUALDUB_FILTERDEF_VERSION (8) -#define VIRTUALDUB_FILTERDEF_COMPATIBLE (4) - -// v3: added lCurrentSourceFrame to FrameStateInfo -// v4 (1.2): lots of additions (VirtualDub 1.2) -// v5 (1.3d): lots of bugfixes - stretchblt bilinear, and non-zero startproc -// v6 (1.4): added error handling functions -// v7 (1.4d): added frame lag, exception handling -// v8 (1.4.11): - -typedef struct FilterModule { - struct FilterModule *next, *prev; - HINSTANCE hInstModule; - FilterModuleInitProc initProc; - FilterModuleDeinitProc deinitProc; -} FilterModule; - -typedef struct FilterDefinition { - - struct FilterDefinition *next, *prev; - FilterModule *module; - - const char * name; - const char * desc; - const char * maker; - void * private_data; - int inst_data_size; - - FilterInitProc initProc; - FilterDeinitProc deinitProc; - FilterRunProc runProc; - FilterParamProc paramProc; - FilterConfigProc configProc; - FilterStringProc stringProc; - FilterStartProc startProc; - FilterEndProc endProc; - - CScriptObject *script_obj; - - FilterScriptStrProc fssProc; - - // NEW - 1.4.11 - FilterStringProc2 stringProc2; - FilterSerialize serializeProc; - FilterDeserialize deserializeProc; - FilterCopy copyProc; -} FilterDefinition; - -////////// - -// FilterStateInfo: contains dynamic info about file being processed - -class FilterStateInfo { -public: - long lCurrentFrame; // current output frame - long lMicrosecsPerFrame; // microseconds per output frame - long lCurrentSourceFrame; // current source frame - long lMicrosecsPerSrcFrame; // microseconds per source frame - long lSourceFrameMS; // source frame timestamp - long lDestFrameMS; // output frame timestamp -}; - -// VFBitmap: VBitmap extended to hold filter-specific information - -class VFBitmap : public VBitmap { -public: - enum { - NEEDS_HDC = 0x00000001L, - }; - - DWORD dwFlags; - HDC hdc; -}; - -// FilterActivation: This is what is actually passed to filters at runtime. - -class FilterActivation { -public: - FilterDefinition *filter; - void *filter_data; - VFBitmap &dst, &src; - VFBitmap *__reserved0, *const last; - unsigned long x1, y1, x2, y2; - - FilterStateInfo *pfsi; - IFilterPreview *ifp; - - FilterActivation(VFBitmap& _dst, VFBitmap& _src, VFBitmap *_last) : dst(_dst), src(_src), last(_last) {} - FilterActivation(const FilterActivation& fa, VFBitmap& _dst, VFBitmap& _src, VFBitmap *_last); -}; - -// These flags must match those in cpuaccel.h! - -#ifndef f_VIRTUALDUB_CPUACCEL_H -#define CPUF_SUPPORTS_CPUID (0x00000001L) -#define CPUF_SUPPORTS_FPU (0x00000002L) -#define CPUF_SUPPORTS_MMX (0x00000004L) -#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) -#define CPUF_SUPPORTS_SSE (0x00000010L) -#define CPUF_SUPPORTS_SSE2 (0x00000020L) -#define CPUF_SUPPORTS_3DNOW (0x00000040L) -#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) -#endif - -struct FilterFunctions { - FilterDefinition *(*addFilter)(FilterModule *, FilterDefinition *, int fd_len); - void (*removeFilter)(FilterDefinition *); - bool (*isFPUEnabled)(); - bool (*isMMXEnabled)(); - void (*InitVTables)(struct FilterVTbls *); - - // These functions permit you to throw MyError exceptions from a filter. - // YOU MUST ONLY CALL THESE IN runProc, initProc, and startProc. - - void (*ExceptOutOfMemory)(); // ADDED: V6 (VirtualDub 1.4) - void (*Except)(const char *format, ...); // ADDED: V6 (VirtualDub 1.4) - - // These functions are callable at any time. - - long (*getCPUFlags)(); // ADDED: V6 (VirtualDub 1.4) - long (*getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d) -}; - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + + +#ifndef f_FILTER_H +#define f_FILTER_H + +#include + +// This is really dumb, but necessary to support VTbls in C++. + +struct FilterVTbls { + void *pvtblVBitmap; +}; + +#ifdef VDEXT_MAIN +struct FilterVTbls g_vtbls; +#elif defined(VDEXT_NOTMAIN) +extern struct FilterVTbls g_vtbls; +#endif + +#define INITIALIZE_VTBLS ff->InitVTables(&g_vtbls) + +#include "VBitmap.h" + +////////////////// + +struct CScriptObject; + +////////////////// + +enum { + FILTERPARAM_SWAP_BUFFERS = 0x00000001L, + FILTERPARAM_NEEDS_LAST = 0x00000002L, +}; + +#define FILTERPARAM_HAS_LAG(frames) ((int)(frames) << 16) + +/////////////////// + +class VFBitmap; +class FilterActivation; +struct FilterFunctions; + +typedef int (*FilterInitProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef void (*FilterDeinitProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef int (*FilterRunProc )(const FilterActivation *fa, const FilterFunctions *ff); +typedef long (*FilterParamProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef int (*FilterConfigProc )(FilterActivation *fa, const FilterFunctions *ff, HWND hWnd); +typedef void (*FilterStringProc )(const FilterActivation *fa, const FilterFunctions *ff, char *buf); +typedef int (*FilterStartProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef int (*FilterEndProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef bool (*FilterScriptStrProc)(FilterActivation *fa, const FilterFunctions *, char *, int); +typedef void (*FilterStringProc2 )(const FilterActivation *fa, const FilterFunctions *ff, char *buf, int maxlen); +typedef int (*FilterSerialize )(FilterActivation *fa, const FilterFunctions *ff, char *buf, int maxbuf); +typedef void (*FilterDeserialize )(FilterActivation *fa, const FilterFunctions *ff, const char *buf, int maxbuf); +typedef void (*FilterCopy )(FilterActivation *fa, const FilterFunctions *ff, void *dst); + +typedef int (__cdecl *FilterModuleInitProc)(struct FilterModule *fm, const FilterFunctions *ff, int& vdfd_ver, int& vdfd_compat); +typedef void (__cdecl *FilterModuleDeinitProc)(struct FilterModule *fm, const FilterFunctions *ff); + +////////// + +typedef void (__cdecl *FilterPreviewButtonCallback)(bool fNewState, void *pData); +typedef void (__cdecl *FilterPreviewSampleCallback)(VFBitmap *, long lFrame, long lCount, void *pData); + +class IFilterPreview { +public: + virtual void SetButtonCallback(FilterPreviewButtonCallback, void *)=0; + virtual void SetSampleCallback(FilterPreviewSampleCallback, void *)=0; + + virtual bool isPreviewEnabled()=0; + virtual void Toggle(HWND)=0; + virtual void Display(HWND, bool)=0; + virtual void RedoFrame()=0; + virtual void RedoSystem()=0; + virtual void UndoSystem()=0; + virtual void InitButton(HWND)=0; + virtual void Close()=0; + virtual bool SampleCurrentFrame()=0; + virtual long SampleFrames()=0; +}; + +////////// + +#define VIRTUALDUB_FILTERDEF_VERSION (8) +#define VIRTUALDUB_FILTERDEF_COMPATIBLE (4) + +// v3: added lCurrentSourceFrame to FrameStateInfo +// v4 (1.2): lots of additions (VirtualDub 1.2) +// v5 (1.3d): lots of bugfixes - stretchblt bilinear, and non-zero startproc +// v6 (1.4): added error handling functions +// v7 (1.4d): added frame lag, exception handling +// v8 (1.4.11): + +typedef struct FilterModule { + struct FilterModule *next, *prev; + HINSTANCE hInstModule; + FilterModuleInitProc initProc; + FilterModuleDeinitProc deinitProc; +} FilterModule; + +typedef struct FilterDefinition { + + struct FilterDefinition *next, *prev; + FilterModule *module; + + const char * name; + const char * desc; + const char * maker; + void * private_data; + int inst_data_size; + + FilterInitProc initProc; + FilterDeinitProc deinitProc; + FilterRunProc runProc; + FilterParamProc paramProc; + FilterConfigProc configProc; + FilterStringProc stringProc; + FilterStartProc startProc; + FilterEndProc endProc; + + CScriptObject *script_obj; + + FilterScriptStrProc fssProc; + + // NEW - 1.4.11 + FilterStringProc2 stringProc2; + FilterSerialize serializeProc; + FilterDeserialize deserializeProc; + FilterCopy copyProc; +} FilterDefinition; + +////////// + +// FilterStateInfo: contains dynamic info about file being processed + +class FilterStateInfo { +public: + long lCurrentFrame; // current output frame + long lMicrosecsPerFrame; // microseconds per output frame + long lCurrentSourceFrame; // current source frame + long lMicrosecsPerSrcFrame; // microseconds per source frame + long lSourceFrameMS; // source frame timestamp + long lDestFrameMS; // output frame timestamp +}; + +// VFBitmap: VBitmap extended to hold filter-specific information + +class VFBitmap : public VBitmap { +public: + enum { + NEEDS_HDC = 0x00000001L, + }; + + DWORD dwFlags; + HDC hdc; +}; + +// FilterActivation: This is what is actually passed to filters at runtime. + +class FilterActivation { +public: + FilterDefinition *filter; + void *filter_data; + VFBitmap &dst, &src; + VFBitmap *__reserved0, *const last; + unsigned long x1, y1, x2, y2; + + FilterStateInfo *pfsi; + IFilterPreview *ifp; + + FilterActivation(VFBitmap& _dst, VFBitmap& _src, VFBitmap *_last) : dst(_dst), src(_src), last(_last) {} + FilterActivation(const FilterActivation& fa, VFBitmap& _dst, VFBitmap& _src, VFBitmap *_last); +}; + +// These flags must match those in cpuaccel.h! + +#ifndef f_VIRTUALDUB_CPUACCEL_H +#define CPUF_SUPPORTS_CPUID (0x00000001L) +#define CPUF_SUPPORTS_FPU (0x00000002L) +#define CPUF_SUPPORTS_MMX (0x00000004L) +#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) +#define CPUF_SUPPORTS_SSE (0x00000010L) +#define CPUF_SUPPORTS_SSE2 (0x00000020L) +#define CPUF_SUPPORTS_3DNOW (0x00000040L) +#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) +#endif + +struct FilterFunctions { + FilterDefinition *(*addFilter)(FilterModule *, FilterDefinition *, int fd_len); + void (*removeFilter)(FilterDefinition *); + bool (*isFPUEnabled)(); + bool (*isMMXEnabled)(); + void (*InitVTables)(struct FilterVTbls *); + + // These functions permit you to throw MyError exceptions from a filter. + // YOU MUST ONLY CALL THESE IN runProc, initProc, and startProc. + + void (*ExceptOutOfMemory)(); // ADDED: V6 (VirtualDub 1.4) + void (*Except)(const char *format, ...); // ADDED: V6 (VirtualDub 1.4) + + // These functions are callable at any time. + + long (*getCPUFlags)(); // ADDED: V6 (VirtualDub 1.4) + long (*getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d) +}; + +#endif diff --git a/include/vd2/extras/FilterSDK/ScriptError.h b/include/vd2/extras/FilterSDK/ScriptError.h index ceaad8bb060..af29a72d45e 100644 --- a/include/vd2/extras/FilterSDK/ScriptError.h +++ b/include/vd2/extras/FilterSDK/ScriptError.h @@ -1,93 +1,93 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - -#ifndef f_SYLIA_SCRIPTERROR_H -#define f_SYLIA_SCRIPTERROR_H - -class CScriptError { -public: - int err; - - enum { - PARSE_ERROR=1, - SEMICOLON_EXPECTED, - IDENTIFIER_EXPECTED, - - TYPE_INT_REQUIRED, - TYPE_ARRAY_REQUIRED, - TYPE_FUNCTION_REQUIRED, - TYPE_OBJECT_REQUIRED, - - OBJECT_MEMBER_NAME_REQUIRED, - FUNCCALLEND_EXPECTED, - TOO_MANY_PARAMS, - DIVIDE_BY_ZERO, - VAR_NOT_FOUND, - MEMBER_NOT_FOUND, - OVERLOADED_FUNCTION_NOT_FOUND, - IDENT_TOO_LONG, - OPERATOR_EXPECTED, - CLOSEPARENS_EXPECTED, - CLOSEBRACKET_EXPECTED, - - VAR_UNDEFINED, - - OUT_OF_STRING_SPACE, - OUT_OF_MEMORY, - INTERNAL_ERROR, - EXTERNAL_ERROR, - - FCALL_OUT_OF_RANGE, - FCALL_INVALID_PTYPE, - FCALL_UNKNOWN_STR, - }; - - CScriptError(int err_num) : err(err_num) { } - - int getErr() { return err; } -}; - -#define SCRIPT_ERROR(x) throw CScriptError(CScriptError::##x) - -extern "C" __declspec(dllexport) char * __stdcall TranslateScriptError(int); - -char inline *TranslateScriptError(CScriptError cse) { - return TranslateScriptError(cse.getErr()); -} - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + +#ifndef f_SYLIA_SCRIPTERROR_H +#define f_SYLIA_SCRIPTERROR_H + +class CScriptError { +public: + int err; + + enum { + PARSE_ERROR=1, + SEMICOLON_EXPECTED, + IDENTIFIER_EXPECTED, + + TYPE_INT_REQUIRED, + TYPE_ARRAY_REQUIRED, + TYPE_FUNCTION_REQUIRED, + TYPE_OBJECT_REQUIRED, + + OBJECT_MEMBER_NAME_REQUIRED, + FUNCCALLEND_EXPECTED, + TOO_MANY_PARAMS, + DIVIDE_BY_ZERO, + VAR_NOT_FOUND, + MEMBER_NOT_FOUND, + OVERLOADED_FUNCTION_NOT_FOUND, + IDENT_TOO_LONG, + OPERATOR_EXPECTED, + CLOSEPARENS_EXPECTED, + CLOSEBRACKET_EXPECTED, + + VAR_UNDEFINED, + + OUT_OF_STRING_SPACE, + OUT_OF_MEMORY, + INTERNAL_ERROR, + EXTERNAL_ERROR, + + FCALL_OUT_OF_RANGE, + FCALL_INVALID_PTYPE, + FCALL_UNKNOWN_STR, + }; + + CScriptError(int err_num) : err(err_num) { } + + int getErr() { return err; } +}; + +#define SCRIPT_ERROR(x) throw CScriptError(CScriptError::##x) + +extern "C" __declspec(dllexport) char * __stdcall TranslateScriptError(int); + +char inline *TranslateScriptError(CScriptError cse) { + return TranslateScriptError(cse.getErr()); +} + +#endif diff --git a/include/vd2/extras/FilterSDK/ScriptInterpreter.h b/include/vd2/extras/FilterSDK/ScriptInterpreter.h index ad01971185b..9a9a90994c3 100644 --- a/include/vd2/extras/FilterSDK/ScriptInterpreter.h +++ b/include/vd2/extras/FilterSDK/ScriptInterpreter.h @@ -1,70 +1,70 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - -#ifndef f_SYLIA_SCRIPTINTERPRETER_H -#define f_SYLIA_SCRIPTINTERPRETER_H - -class CScriptValue; -class CScriptError; -struct CScriptObject; -class IScriptInterpreter; - -typedef CScriptValue (*ScriptRootHandlerPtr)(IScriptInterpreter *,char *,void *); - -class IScriptInterpreter { -public: - virtual void Destroy() =0; - - virtual void SetRootHandler(ScriptRootHandlerPtr, void *) =0; - - virtual void ExecuteLine(char *s) =0; - - virtual void ScriptError(int e) =0; - virtual char* TranslateScriptError(CScriptError& cse) =0; - virtual char** AllocTempString(long l) =0; - - virtual CScriptValue LookupObjectMember(CScriptObject *obj, void *, char *szIdent) = 0; -}; - -extern "C" __declspec(dllexport) IScriptInterpreter * __stdcall CreateScriptInterpreter(); - -#define GETPROC_CREATESCRIPTINTERPRETER(hInst) ((IScriptInterpreter *(__stdcall *)())GetProcAddress(hInst, "_CreateScriptInterpreter@0")) - -#define EXT_SCRIPT_ERROR(x) (isi->ScriptError((CScriptError::x))) - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + +#ifndef f_SYLIA_SCRIPTINTERPRETER_H +#define f_SYLIA_SCRIPTINTERPRETER_H + +class CScriptValue; +class CScriptError; +struct CScriptObject; +class IScriptInterpreter; + +typedef CScriptValue (*ScriptRootHandlerPtr)(IScriptInterpreter *,char *,void *); + +class IScriptInterpreter { +public: + virtual void Destroy() =0; + + virtual void SetRootHandler(ScriptRootHandlerPtr, void *) =0; + + virtual void ExecuteLine(char *s) =0; + + virtual void ScriptError(int e) =0; + virtual char* TranslateScriptError(CScriptError& cse) =0; + virtual char** AllocTempString(long l) =0; + + virtual CScriptValue LookupObjectMember(CScriptObject *obj, void *, char *szIdent) = 0; +}; + +extern "C" __declspec(dllexport) IScriptInterpreter * __stdcall CreateScriptInterpreter(); + +#define GETPROC_CREATESCRIPTINTERPRETER(hInst) ((IScriptInterpreter *(__stdcall *)())GetProcAddress(hInst, "_CreateScriptInterpreter@0")) + +#define EXT_SCRIPT_ERROR(x) (isi->ScriptError((CScriptError::x))) + +#endif diff --git a/include/vd2/extras/FilterSDK/ScriptValue.h b/include/vd2/extras/FilterSDK/ScriptValue.h index 52e629a3f3f..91eec93ea29 100644 --- a/include/vd2/extras/FilterSDK/ScriptValue.h +++ b/include/vd2/extras/FilterSDK/ScriptValue.h @@ -1,126 +1,126 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - -#ifndef f_SYLIA_SCRIPTVALUE_H -#define f_SYLIA_SCRIPTVALUE_H - -class CScriptArray; -struct CScriptObject; -class CScriptValue; -class IScriptInterpreter; -class VariableTableEntry; - -typedef CScriptValue (*ScriptObjectLookupFuncPtr)(IScriptInterpreter *, CScriptObject *, void *lpVoid, char *szName); -typedef CScriptValue (*ScriptFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); -typedef void (*ScriptVoidFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); -typedef int (*ScriptIntFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); -typedef CScriptValue (*ScriptArrayFunctionPtr)(IScriptInterpreter *, void *, int); - -typedef struct ScriptFunctionDef { - ScriptFunctionPtr func_ptr; - char *name; - char *arg_list; -} ScriptFunctionDef; - -typedef struct ScriptObjectDef { - char *name; - CScriptObject *obj; -} ScriptObjectDef; - -typedef struct CScriptObject { - ScriptObjectLookupFuncPtr Lookup; - ScriptFunctionDef *func_list; - ScriptObjectDef *obj_list; -} CScriptObject; - -class CScriptValue { -public: - enum { T_VOID, T_INT, T_PINT, T_STR, T_ARRAY, T_OBJECT, T_FNAME, T_FUNCTION, T_VARLV } type; - CScriptObject *thisPtr; - union { - int i; - int *pi; - char **s; - ScriptArrayFunctionPtr ary; - CScriptObject *obj; - ScriptFunctionPtr func; - ScriptFunctionDef *fname; - VariableTableEntry *vte; - } u; - void *lpVoid; - - CScriptValue() { type = T_VOID; } - CScriptValue(int i) { type = T_INT; u.i = i; } - CScriptValue(int *pi) { type = T_PINT; u.pi = pi; } - CScriptValue(char **s) { type = T_STR; u.s = s; } - CScriptValue(CScriptObject *obj) { type = T_OBJECT; u.obj = obj; } - CScriptValue(CScriptObject *_thisPtr, ScriptArrayFunctionPtr csa) { - type = T_ARRAY; - u.ary = csa; - thisPtr = _thisPtr; - } - CScriptValue(CScriptObject *_thisPtr, ScriptFunctionDef *sfd) { - type = T_FNAME; - u.fname = sfd; - thisPtr = _thisPtr; - } - CScriptValue(CScriptObject *_thisPtr, ScriptFunctionPtr fn) { - type = T_FUNCTION; - u.func = fn; - thisPtr = _thisPtr; - } - CScriptValue(VariableTableEntry *vte) { type = T_VARLV; u.vte = vte; } - - bool isVoid() { return type == T_VOID; } - bool isInt() { return type == T_INT; } - bool isString() { return type == T_STR; } - bool isArray() { return type == T_ARRAY; } - bool isObject() { return type == T_OBJECT; } - bool isFName() { return type == T_FNAME; } - bool isFunction() { return type == T_FUNCTION; } - bool isVarLV() { return type == T_VARLV; } - - int asInt() { return u.i; } - char ** asString() { return u.s; } - ScriptArrayFunctionPtr asArray() { return u.ary; } - CScriptObject * asObject() { return u.obj; } - ScriptFunctionPtr asFunction() { return u.func; } - VariableTableEntry* asVarLV() { return u.vte; } -}; - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + +#ifndef f_SYLIA_SCRIPTVALUE_H +#define f_SYLIA_SCRIPTVALUE_H + +class CScriptArray; +struct CScriptObject; +class CScriptValue; +class IScriptInterpreter; +class VariableTableEntry; + +typedef CScriptValue (*ScriptObjectLookupFuncPtr)(IScriptInterpreter *, CScriptObject *, void *lpVoid, char *szName); +typedef CScriptValue (*ScriptFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); +typedef void (*ScriptVoidFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); +typedef int (*ScriptIntFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); +typedef CScriptValue (*ScriptArrayFunctionPtr)(IScriptInterpreter *, void *, int); + +typedef struct ScriptFunctionDef { + ScriptFunctionPtr func_ptr; + char *name; + char *arg_list; +} ScriptFunctionDef; + +typedef struct ScriptObjectDef { + char *name; + CScriptObject *obj; +} ScriptObjectDef; + +typedef struct CScriptObject { + ScriptObjectLookupFuncPtr Lookup; + ScriptFunctionDef *func_list; + ScriptObjectDef *obj_list; +} CScriptObject; + +class CScriptValue { +public: + enum { T_VOID, T_INT, T_PINT, T_STR, T_ARRAY, T_OBJECT, T_FNAME, T_FUNCTION, T_VARLV } type; + CScriptObject *thisPtr; + union { + int i; + int *pi; + char **s; + ScriptArrayFunctionPtr ary; + CScriptObject *obj; + ScriptFunctionPtr func; + ScriptFunctionDef *fname; + VariableTableEntry *vte; + } u; + void *lpVoid; + + CScriptValue() { type = T_VOID; } + CScriptValue(int i) { type = T_INT; u.i = i; } + CScriptValue(int *pi) { type = T_PINT; u.pi = pi; } + CScriptValue(char **s) { type = T_STR; u.s = s; } + CScriptValue(CScriptObject *obj) { type = T_OBJECT; u.obj = obj; } + CScriptValue(CScriptObject *_thisPtr, ScriptArrayFunctionPtr csa) { + type = T_ARRAY; + u.ary = csa; + thisPtr = _thisPtr; + } + CScriptValue(CScriptObject *_thisPtr, ScriptFunctionDef *sfd) { + type = T_FNAME; + u.fname = sfd; + thisPtr = _thisPtr; + } + CScriptValue(CScriptObject *_thisPtr, ScriptFunctionPtr fn) { + type = T_FUNCTION; + u.func = fn; + thisPtr = _thisPtr; + } + CScriptValue(VariableTableEntry *vte) { type = T_VARLV; u.vte = vte; } + + bool isVoid() { return type == T_VOID; } + bool isInt() { return type == T_INT; } + bool isString() { return type == T_STR; } + bool isArray() { return type == T_ARRAY; } + bool isObject() { return type == T_OBJECT; } + bool isFName() { return type == T_FNAME; } + bool isFunction() { return type == T_FUNCTION; } + bool isVarLV() { return type == T_VARLV; } + + int asInt() { return u.i; } + char ** asString() { return u.s; } + ScriptArrayFunctionPtr asArray() { return u.ary; } + CScriptObject * asObject() { return u.obj; } + ScriptFunctionPtr asFunction() { return u.func; } + VariableTableEntry* asVarLV() { return u.vte; } +}; + +#endif diff --git a/include/vd2/extras/FilterSDK/VBitmap.h b/include/vd2/extras/FilterSDK/VBitmap.h index 0b95066fc87..8b1a8a00470 100644 --- a/include/vd2/extras/FilterSDK/VBitmap.h +++ b/include/vd2/extras/FilterSDK/VBitmap.h @@ -1,172 +1,172 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - -#ifndef f_VIRTUALDUB_VBITMAP_H -#define f_VIRTUALDUB_VBITMAP_H - -#include - -typedef unsigned long Pixel; -typedef unsigned long Pixel32; -typedef unsigned char Pixel8; -typedef long PixCoord; -typedef long PixDim; -typedef long PixOffset; - -#ifdef VDEXT_VIDEO_FILTER -#define NOVTABLE __declspec(novtable) -#else -#define NOVTABLE -#endif - -class NOVTABLE VBitmap { -public: - Pixel * data; - Pixel * palette; - int depth; - PixCoord w, h; - PixOffset pitch; - PixOffset modulo; - PixOffset size; - PixOffset offset; - - Pixel *Address(PixCoord x, PixCoord y) const { - return Addressi(x, h-y-1); - } - - Pixel *Addressi(PixCoord x, PixCoord y) const { - return (Pixel *)((char *)data + y*pitch + x*(depth>>3)); - } - - Pixel *Address16(PixCoord x, PixCoord y) const { - return Address16i(x, h-y-1); - } - - Pixel *Address16i(PixCoord x, PixCoord y) const { - return (Pixel *)((char *)data + y*pitch + x*2); - } - - Pixel *Address32(PixCoord x, PixCoord y) const { - return Address32i(x, h-y-1); - } - - Pixel *Address32i(PixCoord x, PixCoord y) const { - return (Pixel *)((char *)data + y*pitch + x*sizeof(Pixel)); - } - - PixOffset PitchAlign4() { - return ((w * depth + 31)/32)*4; - } - - PixOffset PitchAlign8() { - return ((w * depth + 63)/64)*8; - } - - PixOffset Modulo() { - return pitch - (w*depth+7)/8; - } - - PixOffset Size() { - return pitch*h; - } - - ////// - - VBitmap() throw() { -#ifdef VDEXT_VIDEO_FILTER - init(); -#endif - } - VBitmap(void *data, PixDim w, PixDim h, int depth) throw(); - VBitmap(void *data, BITMAPINFOHEADER *) throw(); - -#ifdef VDEXT_VIDEO_FILTER - void init() throw() { *(void **)this = g_vtbls.pvtblVBitmap; } -#endif - - virtual VBitmap& init(void *data, PixDim w, PixDim h, int depth) throw(); - virtual VBitmap& init(void *data, BITMAPINFOHEADER *) throw(); - - virtual void MakeBitmapHeader(BITMAPINFOHEADER *bih) const throw(); - - virtual void AlignTo4() throw(); - virtual void AlignTo8() throw(); - - virtual void BitBlt(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); - virtual void BitBltDither(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy, bool to565) const throw(); - virtual void BitBlt565(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy) const throw(); - - virtual bool BitBltXlat1(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel8 *tbl) const throw(); - virtual bool BitBltXlat3(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel32 *tbl) const throw(); - - virtual bool StretchBltNearestFast(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const VBitmap *src, double x2, double y2, double dx1, double dy1) const throw(); - - virtual bool StretchBltBilinearFast(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const VBitmap *src, double x2, double y2, double dx1, double dy1) const throw(); - - virtual bool RectFill(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, Pixel32 c) const throw(); - - enum { - HISTO_LUMA, - HISTO_GRAY, - HISTO_RED, - HISTO_GREEN, - HISTO_BLUE, - }; - - virtual bool Histogram(PixCoord x, PixCoord y, PixCoord dx, PixCoord dy, long *pHisto, int iHistoType) const throw(); - - //// NEW AS OF VIRTUALDUB V1.2B - - virtual bool BitBltFromYUY2(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); - virtual bool BitBltFromI420(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); - - //// NEW AS OF VIRTUALDUB V1.4C - - virtual void MakeBitmapHeaderNoPadding(BITMAPINFOHEADER *bih) const throw(); - - /////////// - - bool BitBltFromYUY2Fullscale(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); - -private: - bool dualrectclip(PixCoord& x2, PixCoord& y2, const VBitmap *src, PixCoord& x1, PixCoord& y1, PixDim& dx, PixDim& dy) const throw(); -}; - -#undef NOVTABLE - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + +#ifndef f_VIRTUALDUB_VBITMAP_H +#define f_VIRTUALDUB_VBITMAP_H + +#include + +typedef unsigned long Pixel; +typedef unsigned long Pixel32; +typedef unsigned char Pixel8; +typedef long PixCoord; +typedef long PixDim; +typedef long PixOffset; + +#ifdef VDEXT_VIDEO_FILTER +#define NOVTABLE __declspec(novtable) +#else +#define NOVTABLE +#endif + +class NOVTABLE VBitmap { +public: + Pixel * data; + Pixel * palette; + int depth; + PixCoord w, h; + PixOffset pitch; + PixOffset modulo; + PixOffset size; + PixOffset offset; + + Pixel *Address(PixCoord x, PixCoord y) const { + return Addressi(x, h-y-1); + } + + Pixel *Addressi(PixCoord x, PixCoord y) const { + return (Pixel *)((char *)data + y*pitch + x*(depth>>3)); + } + + Pixel *Address16(PixCoord x, PixCoord y) const { + return Address16i(x, h-y-1); + } + + Pixel *Address16i(PixCoord x, PixCoord y) const { + return (Pixel *)((char *)data + y*pitch + x*2); + } + + Pixel *Address32(PixCoord x, PixCoord y) const { + return Address32i(x, h-y-1); + } + + Pixel *Address32i(PixCoord x, PixCoord y) const { + return (Pixel *)((char *)data + y*pitch + x*sizeof(Pixel)); + } + + PixOffset PitchAlign4() { + return ((w * depth + 31)/32)*4; + } + + PixOffset PitchAlign8() { + return ((w * depth + 63)/64)*8; + } + + PixOffset Modulo() { + return pitch - (w*depth+7)/8; + } + + PixOffset Size() { + return pitch*h; + } + + ////// + + VBitmap() throw() { +#ifdef VDEXT_VIDEO_FILTER + init(); +#endif + } + VBitmap(void *data, PixDim w, PixDim h, int depth) throw(); + VBitmap(void *data, BITMAPINFOHEADER *) throw(); + +#ifdef VDEXT_VIDEO_FILTER + void init() throw() { *(void **)this = g_vtbls.pvtblVBitmap; } +#endif + + virtual VBitmap& init(void *data, PixDim w, PixDim h, int depth) throw(); + virtual VBitmap& init(void *data, BITMAPINFOHEADER *) throw(); + + virtual void MakeBitmapHeader(BITMAPINFOHEADER *bih) const throw(); + + virtual void AlignTo4() throw(); + virtual void AlignTo8() throw(); + + virtual void BitBlt(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); + virtual void BitBltDither(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy, bool to565) const throw(); + virtual void BitBlt565(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy) const throw(); + + virtual bool BitBltXlat1(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel8 *tbl) const throw(); + virtual bool BitBltXlat3(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel32 *tbl) const throw(); + + virtual bool StretchBltNearestFast(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const VBitmap *src, double x2, double y2, double dx1, double dy1) const throw(); + + virtual bool StretchBltBilinearFast(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const VBitmap *src, double x2, double y2, double dx1, double dy1) const throw(); + + virtual bool RectFill(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, Pixel32 c) const throw(); + + enum { + HISTO_LUMA, + HISTO_GRAY, + HISTO_RED, + HISTO_GREEN, + HISTO_BLUE, + }; + + virtual bool Histogram(PixCoord x, PixCoord y, PixCoord dx, PixCoord dy, long *pHisto, int iHistoType) const throw(); + + //// NEW AS OF VIRTUALDUB V1.2B + + virtual bool BitBltFromYUY2(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); + virtual bool BitBltFromI420(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); + + //// NEW AS OF VIRTUALDUB V1.4C + + virtual void MakeBitmapHeaderNoPadding(BITMAPINFOHEADER *bih) const throw(); + + /////////// + + bool BitBltFromYUY2Fullscale(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); + +private: + bool dualrectclip(PixCoord& x2, PixCoord& y2, const VBitmap *src, PixCoord& x1, PixCoord& y1, PixDim& dx, PixDim& dy) const throw(); +}; + +#undef NOVTABLE + +#endif diff --git a/include/vd2/extras/FilterSDK/VirtualDub.h b/include/vd2/extras/FilterSDK/VirtualDub.h index 25e5fd47595..5195b15f55d 100644 --- a/include/vd2/extras/FilterSDK/VirtualDub.h +++ b/include/vd2/extras/FilterSDK/VirtualDub.h @@ -1,7 +1,7 @@ -#pragma once - -#include "Filter.h" -#include "ScriptInterpreter.h" -#include "ScriptError.h" -#include "ScriptValue.h" -#include "VBitmap.h" +#pragma once + +#include "Filter.h" +#include "ScriptInterpreter.h" +#include "ScriptError.h" +#include "ScriptValue.h" +#include "VBitmap.h" diff --git a/include/vd2/plugin/vdaudiofilt.h b/include/vd2/plugin/vdaudiofilt.h index 2680ad794c0..e4237ec4422 100644 --- a/include/vd2/plugin/vdaudiofilt.h +++ b/include/vd2/plugin/vdaudiofilt.h @@ -1,148 +1,148 @@ -#ifndef f_VD2_PLUGIN_VDAUDIOFILT_H -#define f_VD2_PLUGIN_VDAUDIOFILT_H - -/////////////////////////////////////////////////////////////////////////// -// -// Audio filter support - -struct VDAudioFilterDefinition; -struct VDXWaveFormat; -struct VDPluginCallbacks; - -enum { - kVDPlugin_AudioAPIVersion = 2 -}; - -struct VDAudioFilterPin { - unsigned mGranularity; // Block size a filter reads/writes this pin. - unsigned mDelay; // Delay in samples on this input. - unsigned mBufferSize; // The size, in samples, of the buffer. - unsigned mCurrentLevel; // The number of samples currently in the buffer. - sint64 mLength; // Approximate length of this stream in us. - const VDXWaveFormat *mpFormat; - bool mbVBR; - bool mbEnded; - char _pad[2]; - void *mpBuffer; - unsigned mSamplesWritten; // The number of samples just written to the buffer. - unsigned mAvailSpace; // Available room pointed to by mpBuffer (output pins only). - - uint32 (VDAPIENTRY *mpReadProc)(VDAudioFilterPin *pPin, void *dst, uint32 samples, bool bAllowFill, int format); - - // These helpers are non-virtual inlines and are compiled into filters. - uint32 Read(void *dst, uint32 samples, bool bAllowFill, int format) { - return mpReadProc(this, dst, samples, bAllowFill, format); - } -}; - -struct VDAudioFilterContext; - -struct VDAudioFilterCallbacks { - VDXWaveFormat *(VDAPIENTRY *AllocPCMWaveFormat)(unsigned sampling_rate, unsigned channels, unsigned bits, bool bFloat); - VDXWaveFormat *(VDAPIENTRY *AllocCustomWaveFormat)(unsigned extra_size); - VDXWaveFormat *(VDAPIENTRY *CopyWaveFormat)(const VDXWaveFormat *); - void (VDAPIENTRY *FreeWaveFormat)(const VDXWaveFormat *); - void (VDAPIENTRY *Wake)(const VDAudioFilterContext *pContext); -}; - -struct VDAudioFilterContext { - void *mpFilterData; - VDAudioFilterPin **mpInputs; - VDAudioFilterPin **mpOutputs; - IVDPluginCallbacks *mpServices; - const VDAudioFilterCallbacks *mpAudioCallbacks; - const VDAudioFilterDefinition *mpDefinition; - uint32 mAPIVersion; - uint32 mInputSamples; // Number of input samples available on all pins. - uint32 mInputGranules; // Number of input granules available on all pins. - uint32 mInputsEnded; // Number of inputs that have ended. - uint32 mOutputSamples; // Number of output sample spaces available on all pins. - uint32 mOutputGranules; // Number of output granule spaces available on all pins. - uint32 mCommonSamples; // Number of input samples and output sample spaces. - uint32 mCommonGranules; // Number of input and output granules. -}; - -// This structure is intentionally identical to WAVEFORMATEX, with one -// exception -- mExtraSize is *always* present, even for PCM. - -struct VDXWaveFormat { - enum { kTagPCM = 1 }; - - uint16 mTag; - uint16 mChannels; - uint32 mSamplingRate; - uint32 mDataRate; - uint16 mBlockSize; - uint16 mSampleBits; - uint16 mExtraSize; -}; - -enum { - kVFARun_OK = 0, - kVFARun_Finished = 1, - kVFARun_InternalWork = 2, - - kVFAPrepare_OK = 0, - kVFAPrepare_BadFormat = 1 -}; - -enum { - kVFARead_Native = 0, - kVFARead_PCM8 = 1, - kVFARead_PCM16 = 2, - kVFARead_PCM32F = 3 -}; - -typedef void * (VDAPIENTRY *VDAudioFilterExtProc )(const VDAudioFilterContext *pContext, const char *pInterfaceName); -typedef uint32 (VDAPIENTRY *VDAudioFilterRunProc )(const VDAudioFilterContext *pContext); -typedef sint64 (VDAPIENTRY *VDAudioFilterSeekProc )(const VDAudioFilterContext *pContext, sint64 microsecs); -typedef uint32 (VDAPIENTRY *VDAudioFilterPrepareProc )(const VDAudioFilterContext *pContext); -typedef void (VDAPIENTRY *VDAudioFilterStartProc )(const VDAudioFilterContext *pContext); -typedef void (VDAPIENTRY *VDAudioFilterStopProc )(const VDAudioFilterContext *pContext); -typedef void (VDAPIENTRY *VDAudioFilterInitProc )(const VDAudioFilterContext *pContext); -typedef void (VDAPIENTRY *VDAudioFilterDestroyProc )(const VDAudioFilterContext *pContext); -typedef unsigned (VDAPIENTRY *VDAudioFilterSuspendProc )(const VDAudioFilterContext *pContext, void *dst, unsigned size); -typedef void (VDAPIENTRY *VDAudioFilterResumeProc )(const VDAudioFilterContext *pContext, const void *src, unsigned size); -typedef unsigned (VDAPIENTRY *VDAudioFilterGetParamProc )(const VDAudioFilterContext *pContext, unsigned idx, void *dst, unsigned size); -typedef void (VDAPIENTRY *VDAudioFilterSetParamProc )(const VDAudioFilterContext *pContext, unsigned idx, const void *src, unsigned variant_count); -typedef bool (VDAPIENTRY *VDAudioFilterConfigProc )(const VDAudioFilterContext *pContext, struct HWND__ *hwnd); - -enum { - kVFAF_Zero = 0, - kVFAF_HasConfig = 1, // Filter has a configuration dialog. - kVFAF_SerializedIO = 2, // Filter must execute in the serialized I/O thread. - - kVFAF_Max = 0xFFFFFFFF, -}; - -struct VDAudioFilterVtbl { - uint32 mSize; - VDAudioFilterDestroyProc mpDestroy; - VDAudioFilterPrepareProc mpPrepare; - VDAudioFilterStartProc mpStart; - VDAudioFilterStopProc mpStop; - VDAudioFilterRunProc mpRun; - VDAudioFilterSeekProc mpSeek; - VDAudioFilterSuspendProc mpSuspend; - VDAudioFilterResumeProc mpResume; - VDAudioFilterGetParamProc mpGetParam; - VDAudioFilterSetParamProc mpSetParam; - VDAudioFilterConfigProc mpConfig; - VDAudioFilterExtProc mpExt; -}; - -struct VDAudioFilterDefinition { - uint32 mSize; // size of this structure in bytes - uint32 mFlags; - - uint32 mFilterDataSize; - uint32 mInputPins; - uint32 mOutputPins; - - const VDXPluginConfigEntry *mpConfigInfo; - - VDAudioFilterInitProc mpInit; - const VDAudioFilterVtbl *mpVtbl; -}; - -#endif +#ifndef f_VD2_PLUGIN_VDAUDIOFILT_H +#define f_VD2_PLUGIN_VDAUDIOFILT_H + +/////////////////////////////////////////////////////////////////////////// +// +// Audio filter support + +struct VDAudioFilterDefinition; +struct VDXWaveFormat; +struct VDPluginCallbacks; + +enum { + kVDPlugin_AudioAPIVersion = 2 +}; + +struct VDAudioFilterPin { + unsigned mGranularity; // Block size a filter reads/writes this pin. + unsigned mDelay; // Delay in samples on this input. + unsigned mBufferSize; // The size, in samples, of the buffer. + unsigned mCurrentLevel; // The number of samples currently in the buffer. + sint64 mLength; // Approximate length of this stream in us. + const VDXWaveFormat *mpFormat; + bool mbVBR; + bool mbEnded; + char _pad[2]; + void *mpBuffer; + unsigned mSamplesWritten; // The number of samples just written to the buffer. + unsigned mAvailSpace; // Available room pointed to by mpBuffer (output pins only). + + uint32 (VDAPIENTRY *mpReadProc)(VDAudioFilterPin *pPin, void *dst, uint32 samples, bool bAllowFill, int format); + + // These helpers are non-virtual inlines and are compiled into filters. + uint32 Read(void *dst, uint32 samples, bool bAllowFill, int format) { + return mpReadProc(this, dst, samples, bAllowFill, format); + } +}; + +struct VDAudioFilterContext; + +struct VDAudioFilterCallbacks { + VDXWaveFormat *(VDAPIENTRY *AllocPCMWaveFormat)(unsigned sampling_rate, unsigned channels, unsigned bits, bool bFloat); + VDXWaveFormat *(VDAPIENTRY *AllocCustomWaveFormat)(unsigned extra_size); + VDXWaveFormat *(VDAPIENTRY *CopyWaveFormat)(const VDXWaveFormat *); + void (VDAPIENTRY *FreeWaveFormat)(const VDXWaveFormat *); + void (VDAPIENTRY *Wake)(const VDAudioFilterContext *pContext); +}; + +struct VDAudioFilterContext { + void *mpFilterData; + VDAudioFilterPin **mpInputs; + VDAudioFilterPin **mpOutputs; + IVDPluginCallbacks *mpServices; + const VDAudioFilterCallbacks *mpAudioCallbacks; + const VDAudioFilterDefinition *mpDefinition; + uint32 mAPIVersion; + uint32 mInputSamples; // Number of input samples available on all pins. + uint32 mInputGranules; // Number of input granules available on all pins. + uint32 mInputsEnded; // Number of inputs that have ended. + uint32 mOutputSamples; // Number of output sample spaces available on all pins. + uint32 mOutputGranules; // Number of output granule spaces available on all pins. + uint32 mCommonSamples; // Number of input samples and output sample spaces. + uint32 mCommonGranules; // Number of input and output granules. +}; + +// This structure is intentionally identical to WAVEFORMATEX, with one +// exception -- mExtraSize is *always* present, even for PCM. + +struct VDXWaveFormat { + enum { kTagPCM = 1 }; + + uint16 mTag; + uint16 mChannels; + uint32 mSamplingRate; + uint32 mDataRate; + uint16 mBlockSize; + uint16 mSampleBits; + uint16 mExtraSize; +}; + +enum { + kVFARun_OK = 0, + kVFARun_Finished = 1, + kVFARun_InternalWork = 2, + + kVFAPrepare_OK = 0, + kVFAPrepare_BadFormat = 1 +}; + +enum { + kVFARead_Native = 0, + kVFARead_PCM8 = 1, + kVFARead_PCM16 = 2, + kVFARead_PCM32F = 3 +}; + +typedef void * (VDAPIENTRY *VDAudioFilterExtProc )(const VDAudioFilterContext *pContext, const char *pInterfaceName); +typedef uint32 (VDAPIENTRY *VDAudioFilterRunProc )(const VDAudioFilterContext *pContext); +typedef sint64 (VDAPIENTRY *VDAudioFilterSeekProc )(const VDAudioFilterContext *pContext, sint64 microsecs); +typedef uint32 (VDAPIENTRY *VDAudioFilterPrepareProc )(const VDAudioFilterContext *pContext); +typedef void (VDAPIENTRY *VDAudioFilterStartProc )(const VDAudioFilterContext *pContext); +typedef void (VDAPIENTRY *VDAudioFilterStopProc )(const VDAudioFilterContext *pContext); +typedef void (VDAPIENTRY *VDAudioFilterInitProc )(const VDAudioFilterContext *pContext); +typedef void (VDAPIENTRY *VDAudioFilterDestroyProc )(const VDAudioFilterContext *pContext); +typedef unsigned (VDAPIENTRY *VDAudioFilterSuspendProc )(const VDAudioFilterContext *pContext, void *dst, unsigned size); +typedef void (VDAPIENTRY *VDAudioFilterResumeProc )(const VDAudioFilterContext *pContext, const void *src, unsigned size); +typedef unsigned (VDAPIENTRY *VDAudioFilterGetParamProc )(const VDAudioFilterContext *pContext, unsigned idx, void *dst, unsigned size); +typedef void (VDAPIENTRY *VDAudioFilterSetParamProc )(const VDAudioFilterContext *pContext, unsigned idx, const void *src, unsigned variant_count); +typedef bool (VDAPIENTRY *VDAudioFilterConfigProc )(const VDAudioFilterContext *pContext, struct HWND__ *hwnd); + +enum { + kVFAF_Zero = 0, + kVFAF_HasConfig = 1, // Filter has a configuration dialog. + kVFAF_SerializedIO = 2, // Filter must execute in the serialized I/O thread. + + kVFAF_Max = 0xFFFFFFFF, +}; + +struct VDAudioFilterVtbl { + uint32 mSize; + VDAudioFilterDestroyProc mpDestroy; + VDAudioFilterPrepareProc mpPrepare; + VDAudioFilterStartProc mpStart; + VDAudioFilterStopProc mpStop; + VDAudioFilterRunProc mpRun; + VDAudioFilterSeekProc mpSeek; + VDAudioFilterSuspendProc mpSuspend; + VDAudioFilterResumeProc mpResume; + VDAudioFilterGetParamProc mpGetParam; + VDAudioFilterSetParamProc mpSetParam; + VDAudioFilterConfigProc mpConfig; + VDAudioFilterExtProc mpExt; +}; + +struct VDAudioFilterDefinition { + uint32 mSize; // size of this structure in bytes + uint32 mFlags; + + uint32 mFilterDataSize; + uint32 mInputPins; + uint32 mOutputPins; + + const VDXPluginConfigEntry *mpConfigInfo; + + VDAudioFilterInitProc mpInit; + const VDAudioFilterVtbl *mpVtbl; +}; + +#endif diff --git a/include/vd2/plugin/vdinputdriver.h b/include/vd2/plugin/vdinputdriver.h index b75738c98af..a6b756e453f 100644 --- a/include/vd2/plugin/vdinputdriver.h +++ b/include/vd2/plugin/vdinputdriver.h @@ -1,284 +1,284 @@ -// VirtualDub - Video processing and capture application -// Plugin headers -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_PLUGIN_VDINPUTDRIVER_H -#define f_VD2_PLUGIN_VDINPUTDRIVER_H - -#ifdef _MSC_VER - #pragma once - #pragma pack(push, 8) -#endif - -#include "vdplugin.h" - -/// Unsigned 32-bit fraction. -struct VDXFraction { - uint32 mNumerator; - uint32 mDenominator; -}; - -typedef struct VDXHWNDStruct *VDXHWND; -typedef struct VDXBITMAPINFOHEADERStruct { - enum { kCompressionRGB = 0 }; - uint32 mSize; - sint32 mWidth; - sint32 mHeight; - uint16 mPlanes; - uint16 mBitCount; - uint32 mCompression; - uint32 mSizeImage; - sint32 mXPelsPerMeter; - sint32 mYPelsPerMeter; - uint32 mClrUsed; - uint32 mClrImportant; -} VDXBITMAPINFOHEADER; - -typedef struct VDXWAVEFORMATEXStruct { - enum { kFormatPCM = 1 }; - uint16 mFormatTag; - uint16 mChannels; - uint32 mSamplesPerSec; - uint32 mAvgBytesPerSec; - uint16 mBlockAlign; - uint16 mBitsPerSample; - uint16 mExtraSize; -} VDXWAVEFORMATEX; - -struct VDXStreamSourceInfo { - VDXFraction mSampleRate; - sint64 mSampleCount; - VDXFraction mPixelAspectRatio; -}; - -// V3+ (1.7.X) only -struct VDXStreamSourceInfoV3 { - VDXStreamSourceInfo mInfo; - - enum { - kFlagVariableSizeSamples = 0x00000001 - }; - - uint32 mFlags; - uint32 mfccHandler; ///< If non-zero, specifies the FOURCC of a codec handler that should be preferred. -}; - -class IVDXStreamSource : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 's', 't', 's') }; - - virtual void VDXAPIENTRY GetStreamSourceInfo(VDXStreamSourceInfo&) = 0; - - virtual bool VDXAPIENTRY Read(sint64 lStart, uint32 lCount, void *lpBuffer, uint32 cbBuffer, uint32 *lBytesRead, uint32 *lSamplesRead) = 0; - - virtual const void * VDXAPIENTRY GetDirectFormat() = 0; - virtual int VDXAPIENTRY GetDirectFormatLen() = 0; - - enum ErrorMode { - kErrorModeReportAll = 0, - kErrorModeConceal, - kErrorModeDecodeAnyway, - kErrorModeCount - }; - - virtual ErrorMode VDXAPIENTRY GetDecodeErrorMode() = 0; - virtual void VDXAPIENTRY SetDecodeErrorMode(ErrorMode mode) = 0; - virtual bool VDXAPIENTRY IsDecodeErrorModeSupported(ErrorMode mode) = 0; - - virtual bool VDXAPIENTRY IsVBR() = 0; - virtual sint64 VDXAPIENTRY TimeToPositionVBR(sint64 us) = 0; - virtual sint64 VDXAPIENTRY PositionToTimeVBR(sint64 samples) = 0; -}; - -// V3+ (1.7.X) -class IVDXStreamSourceV3 : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 's', 't', '2') }; - - virtual void VDXAPIENTRY GetStreamSourceInfoV3(VDXStreamSourceInfoV3&) = 0; -}; - -class IVDXVideoDecoderModel : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 'm') }; - - virtual void VDXAPIENTRY Reset() = 0; - virtual void VDXAPIENTRY SetDesiredFrame(sint64 frame_num) = 0; - virtual sint64 VDXAPIENTRY GetNextRequiredSample(bool& is_preroll) = 0; - virtual int VDXAPIENTRY GetRequiredCount() = 0; -}; - -class IVDXVideoDecoder : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 'e') }; - - virtual const void * VDXAPIENTRY DecodeFrame(const void *inputBuffer, uint32 data_len, bool is_preroll, sint64 sampleNumber, sint64 targetFrame) = 0; - virtual uint32 VDXAPIENTRY GetDecodePadding() = 0; - virtual void VDXAPIENTRY Reset() = 0; - virtual bool VDXAPIENTRY IsFrameBufferValid() = 0; - virtual const VDXPixmap& VDXAPIENTRY GetFrameBuffer() = 0; - virtual bool VDXAPIENTRY SetTargetFormat(int format, bool useDIBAlignment) = 0; - virtual bool VDXAPIENTRY SetDecompressedFormat(const VDXBITMAPINFOHEADER *pbih) = 0; - - virtual bool VDXAPIENTRY IsDecodable(sint64 sample_num) = 0; - virtual const void * VDXAPIENTRY GetFrameBufferBase() = 0; -}; - -enum VDXVideoFrameType { - kVDXVFT_Independent, - kVDXVFT_Predicted, - kVDXVFT_Bidirectional, - kVDXVFT_Null, -}; - -struct VDXVideoFrameInfo { - char mTypeChar; - uint8 mFrameType; - sint64 mBytePosition; -}; - -struct VDXVideoSourceInfo { - enum DecoderModel { - kDecoderModelCustom, ///< A custom decoder model is provided. - kDecoderModelDefaultIP ///< Use the default I/P decoder model. - }; - - enum Flags { - kFlagNone = 0, - kFlagKeyframeOnly = 0x00000001, - kFlagAll = 0xFFFFFFFF - }; - -public: - uint32 mFlags; - uint32 mWidth; - uint32 mHeight; - uint8 mDecoderModel; - uint8 unused[3]; -}; - -class IVDXVideoSource : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 's') }; - - virtual void VDXAPIENTRY GetVideoSourceInfo(VDXVideoSourceInfo& info) = 0; - - virtual bool VDXAPIENTRY CreateVideoDecoderModel(IVDXVideoDecoderModel **) = 0; - virtual bool VDXAPIENTRY CreateVideoDecoder(IVDXVideoDecoder **) = 0; - - virtual void VDXAPIENTRY GetSampleInfo(sint64 sample_num, VDXVideoFrameInfo& frameInfo) = 0; - - virtual bool VDXAPIENTRY IsKey(sint64 sample_num) = 0; - - virtual sint64 VDXAPIENTRY GetFrameNumberForSample(sint64 sample_num) = 0; - virtual sint64 VDXAPIENTRY GetSampleNumberForFrame(sint64 frame_num) = 0; - virtual sint64 VDXAPIENTRY GetRealFrame(sint64 frame_num) = 0; - - virtual sint64 VDXAPIENTRY GetSampleBytePosition(sint64 sample_num) = 0; -}; - -struct VDXAudioSourceInfo { -public: - uint32 mFlags; -}; - -class IVDXAudioSource : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'a', 'd', 's') }; - - virtual void VDXAPIENTRY GetAudioSourceInfo(VDXAudioSourceInfo& info) = 0; -}; - -class IVDXInputOptions : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'i', 'o', 'p') }; - - virtual uint32 VDXAPIENTRY Write(void *buf, uint32 buflen) = 0; -}; - -class IVDXInputFile : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'i', 'f', 'l') }; - - virtual bool VDXAPIENTRY PromptForOptions(VDXHWND, IVDXInputOptions **ppOptions) = 0; - virtual bool VDXAPIENTRY CreateOptions(const void *buf, uint32 len, IVDXInputOptions **ppOptions) = 0; - - virtual void VDXAPIENTRY Init(const wchar_t *path, IVDXInputOptions *options) = 0; - virtual bool VDXAPIENTRY Append(const wchar_t *path) = 0; - - virtual void VDXAPIENTRY DisplayInfo(VDXHWND hwndParent) = 0; - - virtual bool VDXAPIENTRY GetVideoSource(int index, IVDXVideoSource **ppVS) = 0; - virtual bool VDXAPIENTRY GetAudioSource(int index, IVDXAudioSource **ppAS) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// IVDXInputFileDriver -// -class IVDXInputFileDriver : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'i', 'f', 'd') }; - - virtual int VDXAPIENTRY DetectBySignature(const void *pHeader, sint32 nHeaderSize, const void *pFooter, sint32 nFooterSize, sint64 nFileSize) = 0; - virtual bool VDXAPIENTRY CreateInputFile(uint32 flags, IVDXInputFile **ppFile) = 0; -}; - -struct VDXInputDriverContext { - uint32 mAPIVersion; - IVDPluginCallbacks *mpCallbacks; -}; - -typedef bool (VDXAPIENTRY *VDXInputDriverCreateProc)(const VDXInputDriverContext *pContext, IVDXInputFileDriver **); - -struct VDXInputDriverDefinition { - enum { - kFlagNone = 0x00000000, - kFlagSupportsVideo = 0x00000001, - kFlagSupportsAudio = 0x00000002, - kFlagCustomSignature = 0x00010000, - kFlagAll = 0xFFFFFFFF - }; - uint32 mSize; // size of this structure in bytes - uint32 mFlags; - sint32 mPriority; - uint32 mSignatureLength; - const void *mpSignature; - const wchar_t *mpFilenameDetectPattern; - const wchar_t *mpFilenamePattern; - const wchar_t *mpDriverTagName; - - VDXInputDriverCreateProc mpCreate; -}; - -enum { - // V1 (1.7.4.28204): Initial version - // V2 (1.7.5): Default I/P frame model fixed. - kVDXPlugin_InputDriverAPIVersion = 2 -}; - -#ifdef _MSC_VER - #pragma pack(pop) -#endif - -#endif +// VirtualDub - Video processing and capture application +// Plugin headers +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_PLUGIN_VDINPUTDRIVER_H +#define f_VD2_PLUGIN_VDINPUTDRIVER_H + +#ifdef _MSC_VER + #pragma once + #pragma pack(push, 8) +#endif + +#include "vdplugin.h" + +/// Unsigned 32-bit fraction. +struct VDXFraction { + uint32 mNumerator; + uint32 mDenominator; +}; + +typedef struct VDXHWNDStruct *VDXHWND; +typedef struct VDXBITMAPINFOHEADERStruct { + enum { kCompressionRGB = 0 }; + uint32 mSize; + sint32 mWidth; + sint32 mHeight; + uint16 mPlanes; + uint16 mBitCount; + uint32 mCompression; + uint32 mSizeImage; + sint32 mXPelsPerMeter; + sint32 mYPelsPerMeter; + uint32 mClrUsed; + uint32 mClrImportant; +} VDXBITMAPINFOHEADER; + +typedef struct VDXWAVEFORMATEXStruct { + enum { kFormatPCM = 1 }; + uint16 mFormatTag; + uint16 mChannels; + uint32 mSamplesPerSec; + uint32 mAvgBytesPerSec; + uint16 mBlockAlign; + uint16 mBitsPerSample; + uint16 mExtraSize; +} VDXWAVEFORMATEX; + +struct VDXStreamSourceInfo { + VDXFraction mSampleRate; + sint64 mSampleCount; + VDXFraction mPixelAspectRatio; +}; + +// V3+ (1.7.X) only +struct VDXStreamSourceInfoV3 { + VDXStreamSourceInfo mInfo; + + enum { + kFlagVariableSizeSamples = 0x00000001 + }; + + uint32 mFlags; + uint32 mfccHandler; ///< If non-zero, specifies the FOURCC of a codec handler that should be preferred. +}; + +class IVDXStreamSource : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 's', 't', 's') }; + + virtual void VDXAPIENTRY GetStreamSourceInfo(VDXStreamSourceInfo&) = 0; + + virtual bool VDXAPIENTRY Read(sint64 lStart, uint32 lCount, void *lpBuffer, uint32 cbBuffer, uint32 *lBytesRead, uint32 *lSamplesRead) = 0; + + virtual const void * VDXAPIENTRY GetDirectFormat() = 0; + virtual int VDXAPIENTRY GetDirectFormatLen() = 0; + + enum ErrorMode { + kErrorModeReportAll = 0, + kErrorModeConceal, + kErrorModeDecodeAnyway, + kErrorModeCount + }; + + virtual ErrorMode VDXAPIENTRY GetDecodeErrorMode() = 0; + virtual void VDXAPIENTRY SetDecodeErrorMode(ErrorMode mode) = 0; + virtual bool VDXAPIENTRY IsDecodeErrorModeSupported(ErrorMode mode) = 0; + + virtual bool VDXAPIENTRY IsVBR() = 0; + virtual sint64 VDXAPIENTRY TimeToPositionVBR(sint64 us) = 0; + virtual sint64 VDXAPIENTRY PositionToTimeVBR(sint64 samples) = 0; +}; + +// V3+ (1.7.X) +class IVDXStreamSourceV3 : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 's', 't', '2') }; + + virtual void VDXAPIENTRY GetStreamSourceInfoV3(VDXStreamSourceInfoV3&) = 0; +}; + +class IVDXVideoDecoderModel : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 'm') }; + + virtual void VDXAPIENTRY Reset() = 0; + virtual void VDXAPIENTRY SetDesiredFrame(sint64 frame_num) = 0; + virtual sint64 VDXAPIENTRY GetNextRequiredSample(bool& is_preroll) = 0; + virtual int VDXAPIENTRY GetRequiredCount() = 0; +}; + +class IVDXVideoDecoder : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 'e') }; + + virtual const void * VDXAPIENTRY DecodeFrame(const void *inputBuffer, uint32 data_len, bool is_preroll, sint64 sampleNumber, sint64 targetFrame) = 0; + virtual uint32 VDXAPIENTRY GetDecodePadding() = 0; + virtual void VDXAPIENTRY Reset() = 0; + virtual bool VDXAPIENTRY IsFrameBufferValid() = 0; + virtual const VDXPixmap& VDXAPIENTRY GetFrameBuffer() = 0; + virtual bool VDXAPIENTRY SetTargetFormat(int format, bool useDIBAlignment) = 0; + virtual bool VDXAPIENTRY SetDecompressedFormat(const VDXBITMAPINFOHEADER *pbih) = 0; + + virtual bool VDXAPIENTRY IsDecodable(sint64 sample_num) = 0; + virtual const void * VDXAPIENTRY GetFrameBufferBase() = 0; +}; + +enum VDXVideoFrameType { + kVDXVFT_Independent, + kVDXVFT_Predicted, + kVDXVFT_Bidirectional, + kVDXVFT_Null, +}; + +struct VDXVideoFrameInfo { + char mTypeChar; + uint8 mFrameType; + sint64 mBytePosition; +}; + +struct VDXVideoSourceInfo { + enum DecoderModel { + kDecoderModelCustom, ///< A custom decoder model is provided. + kDecoderModelDefaultIP ///< Use the default I/P decoder model. + }; + + enum Flags { + kFlagNone = 0, + kFlagKeyframeOnly = 0x00000001, + kFlagAll = 0xFFFFFFFF + }; + +public: + uint32 mFlags; + uint32 mWidth; + uint32 mHeight; + uint8 mDecoderModel; + uint8 unused[3]; +}; + +class IVDXVideoSource : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 's') }; + + virtual void VDXAPIENTRY GetVideoSourceInfo(VDXVideoSourceInfo& info) = 0; + + virtual bool VDXAPIENTRY CreateVideoDecoderModel(IVDXVideoDecoderModel **) = 0; + virtual bool VDXAPIENTRY CreateVideoDecoder(IVDXVideoDecoder **) = 0; + + virtual void VDXAPIENTRY GetSampleInfo(sint64 sample_num, VDXVideoFrameInfo& frameInfo) = 0; + + virtual bool VDXAPIENTRY IsKey(sint64 sample_num) = 0; + + virtual sint64 VDXAPIENTRY GetFrameNumberForSample(sint64 sample_num) = 0; + virtual sint64 VDXAPIENTRY GetSampleNumberForFrame(sint64 frame_num) = 0; + virtual sint64 VDXAPIENTRY GetRealFrame(sint64 frame_num) = 0; + + virtual sint64 VDXAPIENTRY GetSampleBytePosition(sint64 sample_num) = 0; +}; + +struct VDXAudioSourceInfo { +public: + uint32 mFlags; +}; + +class IVDXAudioSource : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'a', 'd', 's') }; + + virtual void VDXAPIENTRY GetAudioSourceInfo(VDXAudioSourceInfo& info) = 0; +}; + +class IVDXInputOptions : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'i', 'o', 'p') }; + + virtual uint32 VDXAPIENTRY Write(void *buf, uint32 buflen) = 0; +}; + +class IVDXInputFile : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'i', 'f', 'l') }; + + virtual bool VDXAPIENTRY PromptForOptions(VDXHWND, IVDXInputOptions **ppOptions) = 0; + virtual bool VDXAPIENTRY CreateOptions(const void *buf, uint32 len, IVDXInputOptions **ppOptions) = 0; + + virtual void VDXAPIENTRY Init(const wchar_t *path, IVDXInputOptions *options) = 0; + virtual bool VDXAPIENTRY Append(const wchar_t *path) = 0; + + virtual void VDXAPIENTRY DisplayInfo(VDXHWND hwndParent) = 0; + + virtual bool VDXAPIENTRY GetVideoSource(int index, IVDXVideoSource **ppVS) = 0; + virtual bool VDXAPIENTRY GetAudioSource(int index, IVDXAudioSource **ppAS) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// IVDXInputFileDriver +// +class IVDXInputFileDriver : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'i', 'f', 'd') }; + + virtual int VDXAPIENTRY DetectBySignature(const void *pHeader, sint32 nHeaderSize, const void *pFooter, sint32 nFooterSize, sint64 nFileSize) = 0; + virtual bool VDXAPIENTRY CreateInputFile(uint32 flags, IVDXInputFile **ppFile) = 0; +}; + +struct VDXInputDriverContext { + uint32 mAPIVersion; + IVDPluginCallbacks *mpCallbacks; +}; + +typedef bool (VDXAPIENTRY *VDXInputDriverCreateProc)(const VDXInputDriverContext *pContext, IVDXInputFileDriver **); + +struct VDXInputDriverDefinition { + enum { + kFlagNone = 0x00000000, + kFlagSupportsVideo = 0x00000001, + kFlagSupportsAudio = 0x00000002, + kFlagCustomSignature = 0x00010000, + kFlagAll = 0xFFFFFFFF + }; + uint32 mSize; // size of this structure in bytes + uint32 mFlags; + sint32 mPriority; + uint32 mSignatureLength; + const void *mpSignature; + const wchar_t *mpFilenameDetectPattern; + const wchar_t *mpFilenamePattern; + const wchar_t *mpDriverTagName; + + VDXInputDriverCreateProc mpCreate; +}; + +enum { + // V1 (1.7.4.28204): Initial version + // V2 (1.7.5): Default I/P frame model fixed. + kVDXPlugin_InputDriverAPIVersion = 2 +}; + +#ifdef _MSC_VER + #pragma pack(pop) +#endif + +#endif diff --git a/include/vd2/plugin/vdplugin.h b/include/vd2/plugin/vdplugin.h index cec344d37f3..c909c7109ad 100644 --- a/include/vd2/plugin/vdplugin.h +++ b/include/vd2/plugin/vdplugin.h @@ -1,206 +1,206 @@ -// VirtualDub - Video processing and capture application -// Plugin headers -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_PLUGIN_VDPLUGIN_H -#define f_VD2_PLUGIN_VDPLUGIN_H - -#ifdef _MSC_VER - #pragma once - #pragma pack(push, 8) -#endif - -#include - -// Copied from . Must be in sync. -#ifndef VD_STANDARD_TYPES_DECLARED - #if defined(_MSC_VER) - typedef signed __int64 sint64; - typedef unsigned __int64 uint64; - #elif defined(__GNUC__) - typedef signed long long sint64; - typedef unsigned long long uint64; - #endif - typedef signed int sint32; - typedef unsigned int uint32; - typedef signed short sint16; - typedef unsigned short uint16; - typedef signed char sint8; - typedef unsigned char uint8; - - typedef sint64 int64; - typedef sint32 int32; - typedef sint16 int16; - typedef sint8 int8; - - typedef ptrdiff_t sintptr; - typedef size_t uintptr; -#endif - -#ifndef VDXAPIENTRY - #define VDXAPIENTRY __stdcall -#endif - -#ifndef VDXAPIENTRYV - #define VDXAPIENTRYV __cdecl -#endif - -enum VDXCPUFeatureFlags { - kVDXCPUF_CPUID = 0x00000001, - kVDXCPUF_MMX = 0x00000004, - kVDXCPUF_ISSE = 0x00000008, - kVDXCPUF_SSE = 0x00000010, - kVDXCPUF_SSE2 = 0x00000020, - kVDXCPUF_3DNOW = 0x00000040, - kVDXCPUF_3DNOW_EXT = 0x00000080, - kVDXCPUF_SSE3 = 0x00000100, - kVDXCPUF_SSSE3 = 0x00000200 -}; - -enum { - kVDXPlugin_APIVersion = 10 -}; - - -enum { - kVDXPluginType_Video, // Updated video filter API is not yet complete. - kVDXPluginType_Audio, - kVDXPluginType_Input -}; - -struct VDXPluginInfo { - uint32 mSize; // size of this structure in bytes - const wchar_t *mpName; - const wchar_t *mpAuthor; - const wchar_t *mpDescription; - uint32 mVersion; // (major<<24) + (minor<<16) + build. 1.4.1000 would be 0x010403E8. - uint32 mType; - uint32 mFlags; - uint32 mAPIVersionRequired; - uint32 mAPIVersionUsed; - uint32 mTypeAPIVersionRequired; - uint32 mTypeAPIVersionUsed; - const void * mpTypeSpecificInfo; -}; - -typedef const VDXPluginInfo *const *(VDXAPIENTRY *tpVDXGetPluginInfo)(); - -typedef VDXPluginInfo VDPluginInfo; -typedef tpVDXGetPluginInfo tpVDPluginInfo; - -class IVDXPluginCallbacks { -public: - virtual void * VDXAPIENTRY GetExtendedAPI(const char *pExtendedAPIName) = 0; - virtual void VDXAPIENTRYV SetError(const char *format, ...) = 0; - virtual void VDXAPIENTRY SetErrorOutOfMemory() = 0; - virtual uint32 VDXAPIENTRY GetCPUFeatureFlags() = 0; -}; - -typedef IVDXPluginCallbacks IVDPluginCallbacks; - -struct VDXPluginConfigEntry { - enum Type { - kTypeInvalid = 0, - kTypeU32 = 1, - kTypeS32, - kTypeU64, - kTypeS64, - kTypeDouble, - kTypeAStr, - kTypeWStr, - kTypeBlock - }; - - const VDXPluginConfigEntry *next; - - unsigned idx; - uint32 type; - const wchar_t *name; - const wchar_t *label; - const wchar_t *desc; -}; - -struct VDXPixmap { - void *data; - const uint32 *palette; - sint32 w; - sint32 h; - ptrdiff_t pitch; - sint32 format; - - // Auxiliary planes are always byte-per-pixel. - void *data2; // Cb (U) for YCbCr - ptrdiff_t pitch2; - void *data3; // Cr (V) for YCbCr - ptrdiff_t pitch3; -}; - -struct VDXPixmapLayout { - ptrdiff_t data; - const uint32 *palette; - sint32 w; - sint32 h; - ptrdiff_t pitch; - sint32 format; - - // Auxiliary planes are always byte-per-pixel. - ptrdiff_t data2; // Cb (U) for YCbCr - ptrdiff_t pitch2; - ptrdiff_t data3; // Cr (V) for YCbCr - ptrdiff_t pitch3; -}; - -namespace nsVDXPixmap { - enum VDXPixmapFormat { - kPixFormat_Null = 0, - kPixFormat_XRGB1555 = 5, - kPixFormat_RGB565 = 6, - kPixFormat_RGB888 = 7, - kPixFormat_XRGB8888 = 8, - kPixFormat_Y8 = 9, - kPixFormat_YUV422_UYVY = 10, - kPixFormat_YUV422_YUYV = 11, - kPixFormat_YUV444_Planar = 13, - kPixFormat_YUV422_Planar = 14, - kPixFormat_YUV420_Planar = 15, - kPixFormat_YUV411_Planar = 16, - kPixFormat_YUV410_Planar = 17 - }; -}; - -#define VDXMAKEFOURCC(a, b, c, d) ((uint32)(uint8)(d) + ((uint32)(uint8)(c) << 8) + ((uint32)(uint8)(b) << 16) + ((uint32)(uint8)(a) << 24)) - -class IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'u', 'n', 'k') }; - virtual int VDXAPIENTRY AddRef() = 0; - virtual int VDXAPIENTRY Release() = 0; - virtual void *VDXAPIENTRY AsInterface(uint32 iid) = 0; -}; - -#ifdef _MSC_VER - #pragma pack(pop) -#endif - -#endif +// VirtualDub - Video processing and capture application +// Plugin headers +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_PLUGIN_VDPLUGIN_H +#define f_VD2_PLUGIN_VDPLUGIN_H + +#ifdef _MSC_VER + #pragma once + #pragma pack(push, 8) +#endif + +#include + +// Copied from . Must be in sync. +#ifndef VD_STANDARD_TYPES_DECLARED + #if defined(_MSC_VER) + typedef signed __int64 sint64; + typedef unsigned __int64 uint64; + #elif defined(__GNUC__) + typedef signed long long sint64; + typedef unsigned long long uint64; + #endif + typedef signed int sint32; + typedef unsigned int uint32; + typedef signed short sint16; + typedef unsigned short uint16; + typedef signed char sint8; + typedef unsigned char uint8; + + typedef sint64 int64; + typedef sint32 int32; + typedef sint16 int16; + typedef sint8 int8; + + typedef ptrdiff_t sintptr; + typedef size_t uintptr; +#endif + +#ifndef VDXAPIENTRY + #define VDXAPIENTRY __stdcall +#endif + +#ifndef VDXAPIENTRYV + #define VDXAPIENTRYV __cdecl +#endif + +enum VDXCPUFeatureFlags { + kVDXCPUF_CPUID = 0x00000001, + kVDXCPUF_MMX = 0x00000004, + kVDXCPUF_ISSE = 0x00000008, + kVDXCPUF_SSE = 0x00000010, + kVDXCPUF_SSE2 = 0x00000020, + kVDXCPUF_3DNOW = 0x00000040, + kVDXCPUF_3DNOW_EXT = 0x00000080, + kVDXCPUF_SSE3 = 0x00000100, + kVDXCPUF_SSSE3 = 0x00000200 +}; + +enum { + kVDXPlugin_APIVersion = 10 +}; + + +enum { + kVDXPluginType_Video, // Updated video filter API is not yet complete. + kVDXPluginType_Audio, + kVDXPluginType_Input +}; + +struct VDXPluginInfo { + uint32 mSize; // size of this structure in bytes + const wchar_t *mpName; + const wchar_t *mpAuthor; + const wchar_t *mpDescription; + uint32 mVersion; // (major<<24) + (minor<<16) + build. 1.4.1000 would be 0x010403E8. + uint32 mType; + uint32 mFlags; + uint32 mAPIVersionRequired; + uint32 mAPIVersionUsed; + uint32 mTypeAPIVersionRequired; + uint32 mTypeAPIVersionUsed; + const void * mpTypeSpecificInfo; +}; + +typedef const VDXPluginInfo *const *(VDXAPIENTRY *tpVDXGetPluginInfo)(); + +typedef VDXPluginInfo VDPluginInfo; +typedef tpVDXGetPluginInfo tpVDPluginInfo; + +class IVDXPluginCallbacks { +public: + virtual void * VDXAPIENTRY GetExtendedAPI(const char *pExtendedAPIName) = 0; + virtual void VDXAPIENTRYV SetError(const char *format, ...) = 0; + virtual void VDXAPIENTRY SetErrorOutOfMemory() = 0; + virtual uint32 VDXAPIENTRY GetCPUFeatureFlags() = 0; +}; + +typedef IVDXPluginCallbacks IVDPluginCallbacks; + +struct VDXPluginConfigEntry { + enum Type { + kTypeInvalid = 0, + kTypeU32 = 1, + kTypeS32, + kTypeU64, + kTypeS64, + kTypeDouble, + kTypeAStr, + kTypeWStr, + kTypeBlock + }; + + const VDXPluginConfigEntry *next; + + unsigned idx; + uint32 type; + const wchar_t *name; + const wchar_t *label; + const wchar_t *desc; +}; + +struct VDXPixmap { + void *data; + const uint32 *palette; + sint32 w; + sint32 h; + ptrdiff_t pitch; + sint32 format; + + // Auxiliary planes are always byte-per-pixel. + void *data2; // Cb (U) for YCbCr + ptrdiff_t pitch2; + void *data3; // Cr (V) for YCbCr + ptrdiff_t pitch3; +}; + +struct VDXPixmapLayout { + ptrdiff_t data; + const uint32 *palette; + sint32 w; + sint32 h; + ptrdiff_t pitch; + sint32 format; + + // Auxiliary planes are always byte-per-pixel. + ptrdiff_t data2; // Cb (U) for YCbCr + ptrdiff_t pitch2; + ptrdiff_t data3; // Cr (V) for YCbCr + ptrdiff_t pitch3; +}; + +namespace nsVDXPixmap { + enum VDXPixmapFormat { + kPixFormat_Null = 0, + kPixFormat_XRGB1555 = 5, + kPixFormat_RGB565 = 6, + kPixFormat_RGB888 = 7, + kPixFormat_XRGB8888 = 8, + kPixFormat_Y8 = 9, + kPixFormat_YUV422_UYVY = 10, + kPixFormat_YUV422_YUYV = 11, + kPixFormat_YUV444_Planar = 13, + kPixFormat_YUV422_Planar = 14, + kPixFormat_YUV420_Planar = 15, + kPixFormat_YUV411_Planar = 16, + kPixFormat_YUV410_Planar = 17 + }; +}; + +#define VDXMAKEFOURCC(a, b, c, d) ((uint32)(uint8)(d) + ((uint32)(uint8)(c) << 8) + ((uint32)(uint8)(b) << 16) + ((uint32)(uint8)(a) << 24)) + +class IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'u', 'n', 'k') }; + virtual int VDXAPIENTRY AddRef() = 0; + virtual int VDXAPIENTRY Release() = 0; + virtual void *VDXAPIENTRY AsInterface(uint32 iid) = 0; +}; + +#ifdef _MSC_VER + #pragma pack(pop) +#endif + +#endif diff --git a/include/vd2/plugin/vdvideofilt.h b/include/vd2/plugin/vdvideofilt.h index cf331b7012c..1e00fac39e3 100644 --- a/include/vd2/plugin/vdvideofilt.h +++ b/include/vd2/plugin/vdvideofilt.h @@ -1,517 +1,517 @@ -// VirtualDub - Video processing and capture application -// Plugin headers -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_PLUGIN_VDVIDEOFILT_H -#define f_VD2_PLUGIN_VDVIDEOFILT_H - -#ifdef _MSC_VER - #pragma once - #pragma pack(push, 8) -#endif - -#include - -#include "vdplugin.h" - -typedef struct VDXHINSTANCEStruct *VDXHINSTANCE; -typedef struct VDXHDCStruct *VDXHDC; -typedef struct VDXHWNDStruct *VDXHWND; - -////////////////// - -struct VDXScriptObject; -struct VDXFilterVTbls; - -////////////////// - -enum { - /// Request distinct source and destination buffers. Otherwise, the source and destination buffers - /// alias (in-place mode). - FILTERPARAM_SWAP_BUFFERS = 0x00000001L, - - /// Request an extra buffer for the previous source frame. - FILTERPARAM_NEEDS_LAST = 0x00000002L, - - /// Filter supports image formats other than RGB32. Filters that support format negotiation must - /// set this flag for all calls to paramProc. - FILTERPARAM_SUPPORTS_ALTFORMATS = 0x00000004L, - - /// Filter requests 16 byte alignment for source and destination buffers. This guarantees that: - /// - /// - data and pitch fields are multiples of 16 bytes (aligned) - /// - an integral number of 16 byte vectors may be read, even if the last vector includes - /// some bytes beyond the end of the scanline (their values are undefined) - /// - an integral number of 16 byte vectors may be written, even if the last vector includes - /// some bytes beyong the end of the scanline (their values are ignored) - /// - FILTERPARAM_ALIGN_SCANLINES = 0x00000008L, - - /// Filter's output is purely a function of configuration parameters and source image data, and not - /// source or output frame numbers. In other words, two output frames produced by a filter instance - /// can be assumed to be identical images if: - /// - /// - the same number of source frames are prefetched - /// - the same type of prefetches are performed (direct vs. non-direct) - /// - the frame numbers for the two prefetch lists, taken in order, correspond to identical - /// source frames - /// - the prefetch cookies match - /// - /// Enabling this flag improves the ability of the host to identify identical frames and drop them - /// in preview or in the output file. - /// - FILTERPARAM_PURE_TRANSFORM = 0x00000010L, - - /// Filter cannot support the requested source format. Note that this sets all bits, so the meaning - /// of other bits is ignored. The one exception is that FILTERPARAM_SUPPORTS_ALTFORMATS is assumed - /// to be implicitly set. - FILTERPARAM_NOT_SUPPORTED = (long)0xFFFFFFFF -}; - -/// The filter has a delay from source to output. For instance, a lag of 3 indicates that the -/// filter internally buffers three frames, so when it is fed frames in sequence, frame 0 emerges -/// after frame 3 has been processed. The host attempts to correct timestamps in order to compensate. -/// -/// VirtualDub 1.9.1 or later: Setting this flag can have a performance penalty, as it causes the host -/// to request additional frames to try to produce the correct requested output frames. -/// -#define FILTERPARAM_HAS_LAG(frames) ((int)(frames) << 16) - -/////////////////// - -class VDXFBitmap; -class VDXFilterActivation; -struct VDXFilterFunctions; -struct VDXFilterModule; -class IVDXVideoPrefetcher; - -enum { - kVDXVFEvent_None = 0, - kVDXVFEvent_InvalidateCaches = 1 -}; - -typedef int (__cdecl *VDXFilterInitProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef void (__cdecl *VDXFilterDeinitProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef int (__cdecl *VDXFilterRunProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef long (__cdecl *VDXFilterParamProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef int (__cdecl *VDXFilterConfigProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hWnd); -typedef void (__cdecl *VDXFilterStringProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf); -typedef int (__cdecl *VDXFilterStartProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef int (__cdecl *VDXFilterEndProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef bool (__cdecl *VDXFilterScriptStrProc)(VDXFilterActivation *fa, const VDXFilterFunctions *, char *, int); -typedef void (__cdecl *VDXFilterStringProc2 )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen); -typedef int (__cdecl *VDXFilterSerialize )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxbuf); -typedef void (__cdecl *VDXFilterDeserialize )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, const char *buf, int maxbuf); -typedef void (__cdecl *VDXFilterCopy )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst); -typedef sint64 (__cdecl *VDXFilterPrefetch )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame); -typedef void (__cdecl *VDXFilterCopy2Proc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst, VDXFilterActivation *fa2, const VDXFilterFunctions *ff2); -typedef bool (__cdecl *VDXFilterPrefetch2Proc)(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame, IVDXVideoPrefetcher *prefetcher); -typedef bool (__cdecl *VDXFilterEventProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, uint32 event, const void *eventData); - -typedef int (__cdecl *VDXFilterModuleInitProc)(VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat); -typedef void (__cdecl *VDXFilterModuleDeinitProc)(VDXFilterModule *fm, const VDXFilterFunctions *ff); - -////////// - -typedef void (__cdecl *VDXFilterPreviewButtonCallback)(bool fNewState, void *pData); -typedef void (__cdecl *VDXFilterPreviewSampleCallback)(VDXFBitmap *, long lFrame, long lCount, void *pData); - -class IVDXFilterPreview { -public: - virtual void SetButtonCallback(VDXFilterPreviewButtonCallback, void *)=0; - virtual void SetSampleCallback(VDXFilterPreviewSampleCallback, void *)=0; - - virtual bool isPreviewEnabled()=0; - virtual void Toggle(VDXHWND)=0; - virtual void Display(VDXHWND, bool)=0; - virtual void RedoFrame()=0; - virtual void RedoSystem()=0; - virtual void UndoSystem()=0; - virtual void InitButton(VDXHWND)=0; - virtual void Close()=0; - virtual bool SampleCurrentFrame()=0; - virtual long SampleFrames()=0; -}; - -class IVDXFilterPreview2 : public IVDXFilterPreview { -public: - virtual bool IsPreviewDisplayed() = 0; -}; - -class IVDXVideoPrefetcher : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'v', 'p', 'f') }; - - /// Request a video frame fetch from an upstream source. - virtual void VDXAPIENTRY PrefetchFrame(sint32 srcIndex, sint64 frame, uint64 cookie) = 0; - - /// Request a video frame fetch from an upstream source in direct mode. - /// This specifies that the output frame is the same as the input frame. - /// There cannot be more than one direct fetch and there must be no standard - /// fetches at the same time. There can, however, be symbolic fetches. - virtual void VDXAPIENTRY PrefetchFrameDirect(sint32 srcIndex, sint64 frame) = 0; - - /// Request a symbolic fetch from a source. This does not actually fetch - /// any frames, but marks an association from source to output. This is - /// useful for indicating the approximate center of where an output derives - /// in a source, even if those frames aren't fetched (perhaps due to caching). - /// There may be either zero or one symbolic fetch per source. - /// - /// If no symbolic fetches are performed, the symbolic frame is assumed to - /// be the rounded mean of the fetched source frames. - virtual void VDXAPIENTRY PrefetchFrameSymbolic(sint32 srcIndex, sint64 frame) = 0; -}; - -////////// - -enum { - // This is the highest API version supported by this header file. - VIRTUALDUB_FILTERDEF_VERSION = 14, - - // This is the absolute lowest API version supported by this header file. - // Note that V4 is rather old, corresponding to VirtualDub 1.2. - // Chances are you will need to declare a higher version. - VIRTUALDUB_FILTERDEF_COMPATIBLE = 4, - - // API V9 is a slightly saner baseline, since it is the first API - // version that has copy constructor support. You may still need to - // declare a higher vdfd_compat version in your module init if you - // need features beyond V9 (VirtualDub 1.4.12). - VIRTUALDUB_FILTERDEF_COMPATIBLE_COPYCTOR = 9 - -}; - -// v3: added lCurrentSourceFrame to FrameStateInfo -// v4 (1.2): lots of additions (VirtualDub 1.2) -// v5 (1.3d): lots of bugfixes - stretchblt bilinear, and non-zero startproc -// v6 (1.4): added error handling functions -// v7 (1.4d): added frame lag, exception handling -// v8 (1.4.11): added string2 proc -// v9 (1.4.12): added (working) copy constructor -// v10 (1.5.10): added preview flag -// v11 (1.7.0): guaranteed src structure setup before configProc; added IVDFilterPreview2 -// v12 (1.8.0): support for frame alteration -// v13 (1.8.2): added mOutputFrame field to VDXFilterStateInfo -// v14 (1.9.1): added copyProc2, prefetchProc2, input/output frame arrays - -struct VDXFilterDefinition { - void *_next; // deprecated - set to NULL - void *_prev; // deprecated - set to NULL - void *_module; // deprecated - set to NULL - - const char * name; - const char * desc; - const char * maker; - void * private_data; - int inst_data_size; - - VDXFilterInitProc initProc; - VDXFilterDeinitProc deinitProc; - VDXFilterRunProc runProc; - VDXFilterParamProc paramProc; - VDXFilterConfigProc configProc; - VDXFilterStringProc stringProc; - VDXFilterStartProc startProc; - VDXFilterEndProc endProc; - - VDXScriptObject *script_obj; - - VDXFilterScriptStrProc fssProc; - - // NEW - 1.4.11 - VDXFilterStringProc2 stringProc2; - VDXFilterSerialize serializeProc; - VDXFilterDeserialize deserializeProc; - VDXFilterCopy copyProc; - - VDXFilterPrefetch prefetchProc; // (V12/V1.7.4+) - - // NEW - V14 / 1.9.1 - VDXFilterCopy2Proc copyProc2; - VDXFilterPrefetch2Proc prefetchProc2; - VDXFilterEventProc eventProc; -}; - -////////// - -// FilterStateInfo: contains dynamic info about file being processed - -class VDXFilterStateInfo { -public: - sint32 lCurrentFrame; // current sequence frame (previously called output frame) - sint32 lMicrosecsPerFrame; // microseconds per sequence frame - sint32 lCurrentSourceFrame; // current source frame - sint32 lMicrosecsPerSrcFrame; // microseconds per source frame - sint32 lSourceFrameMS; // source frame timestamp - sint32 lDestFrameMS; // output frame timestamp - - enum { - kStateNone = 0x00000000, - kStatePreview = 0x00000001, // (V1.5.10+) Job output is not being saved to disk. - kStateRealTime = 0x00000002, // (V1.5.10+) Operation is running in real-time (capture, playback). - kStateMax = 0xFFFFFFFF - }; - - uint32 flags; // (V10 / 1.5.10+ only) - - sint32 mOutputFrame; // (V13/V1.8.2+) current output frame -}; - -// VDXFBitmap: VBitmap extended to hold filter-specific information - -class VDXBitmap { -public: - void * _vtable; // Reserved - do not use. - uint32 * data; // Pointer to start of _bottom-most_ scanline of plane 0. - uint32 * palette; // Pointer to palette (reserved - set to NULL). - sint32 depth; // Bit depth, in bits. Set to zero if mpPixmap/mpPixmapLayout are active. - sint32 w; // Width of bitmap, in pixels. - sint32 h; // Height of bitmap, in pixels. - ptrdiff_t pitch; // Distance, in bytes, from the start of one scanline in plane 0 to the next. - ptrdiff_t modulo; // Distance, in bytes, from the end of one scanline in plane 0 to the start of the next. - ptrdiff_t size; // Size of plane 0, including padding. - ptrdiff_t offset; // Offset from beginning of buffer to beginning of plane 0. - - uint32 *Address32(int x, int y) const { - return Address32i(x, h-y-1); - } - - uint32 *Address32i(int x, int y) const { - return (uint32 *)((char *)data + y*pitch + x*4); - } - - void AlignTo4() { - pitch = w << 2; - } - - void AlignTo8() { - pitch = ((w+1)&~1) << 2; - } -}; - -class VDXFBitmap : public VDXBitmap { -public: - enum { - /// Set in paramProc if the filter requires a Win32 GDI display context - /// for a bitmap. (Deprecated as of API V12 - do not use) - NEEDS_HDC = 0x00000001L, - }; - - uint32 dwFlags; - VDXHDC hdc; - - uint32 mFrameRateHi; // Frame rate numerator (V1.7.4+) - uint32 mFrameRateLo; // Frame rate denominator (V1.7.4+) - sint64 mFrameCount; // Frame count; -1 if unlimited or indeterminate (V1.7.4+) - - VDXPixmapLayout *mpPixmapLayout; - const VDXPixmap *mpPixmap; - - uint32 mAspectRatioHi; ///< Pixel aspect ratio fraction (numerator). 0/0 = unknown - uint32 mAspectRatioLo; ///< Pixel aspect ratio fraction (denominator). - - sint64 mFrameNumber; ///< Current frame number (zero based). - sint64 mFrameTimestampStart; ///< Starting timestamp of frame, in 100ns units. - sint64 mFrameTimestampEnd; ///< Ending timestamp of frame, in 100ns units. - sint64 mCookie; ///< Cookie supplied when frame was requested. -}; - -// VDXFilterActivation: This is what is actually passed to filters at runtime. - -class VDXFilterActivation { -public: - const VDXFilterDefinition *filter; // - void *filter_data; - VDXFBitmap& dst; - VDXFBitmap& src; - VDXFBitmap *_reserved0; - VDXFBitmap *const last; - uint32 x1; - uint32 y1; - uint32 x2; - uint32 y2; - - VDXFilterStateInfo *pfsi; - IVDXFilterPreview *ifp; - IVDXFilterPreview2 *ifp2; // (V11+) - - uint32 mSourceFrameCount; // (V14+) - VDXFBitmap *const *mpSourceFrames; // (V14+) - VDXFBitmap *const *mpOutputFrames; // (V14+) -}; - -// These flags must match those in cpuaccel.h! - -#ifndef f_VIRTUALDUB_CPUACCEL_H -#define CPUF_SUPPORTS_CPUID (0x00000001L) -#define CPUF_SUPPORTS_FPU (0x00000002L) -#define CPUF_SUPPORTS_MMX (0x00000004L) -#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) -#define CPUF_SUPPORTS_SSE (0x00000010L) -#define CPUF_SUPPORTS_SSE2 (0x00000020L) -#define CPUF_SUPPORTS_3DNOW (0x00000040L) -#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) -#endif - -struct VDXFilterFunctions { - VDXFilterDefinition *(__cdecl *addFilter)(VDXFilterModule *, VDXFilterDefinition *, int fd_len); - void (__cdecl *removeFilter)(VDXFilterDefinition *); - bool (__cdecl *isFPUEnabled)(); - bool (__cdecl *isMMXEnabled)(); - void (__cdecl *InitVTables)(VDXFilterVTbls *); - - // These functions permit you to throw MyError exceptions from a filter. - // YOU MUST ONLY CALL THESE IN runProc, initProc, and startProc. - - void (__cdecl *ExceptOutOfMemory)(); // ADDED: V6 (VirtualDub 1.4) - void (__cdecl *Except)(const char *format, ...); // ADDED: V6 (VirtualDub 1.4) - - // These functions are callable at any time. - - long (__cdecl *getCPUFlags)(); // ADDED: V6 (VirtualDub 1.4) - long (__cdecl *getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d) -}; - - - - - -/////////////////////////////////////////////////////////////////////////// - -class VDXScriptValue; -class VDXScriptError; -struct VDXScriptObject; - -class VDXScriptError { -public: - enum { - PARSE_ERROR=1, - SEMICOLON_EXPECTED, - IDENTIFIER_EXPECTED, - - TYPE_INT_REQUIRED, - TYPE_ARRAY_REQUIRED, - TYPE_FUNCTION_REQUIRED, - TYPE_OBJECT_REQUIRED, - - OBJECT_MEMBER_NAME_REQUIRED, - FUNCCALLEND_EXPECTED, - TOO_MANY_PARAMS, - DIVIDE_BY_ZERO, - VAR_NOT_FOUND, - MEMBER_NOT_FOUND, - OVERLOADED_FUNCTION_NOT_FOUND, - IDENT_TOO_LONG, - OPERATOR_EXPECTED, - CLOSEPARENS_EXPECTED, - CLOSEBRACKET_EXPECTED, - - VAR_UNDEFINED, - - OUT_OF_STRING_SPACE, - OUT_OF_MEMORY, - INTERNAL_ERROR, - EXTERNAL_ERROR, - - FCALL_OUT_OF_RANGE, - FCALL_INVALID_PTYPE, - FCALL_UNKNOWN_STR, - - ARRAY_INDEX_OUT_OF_BOUNDS, - - NUMERIC_OVERFLOW, - STRING_NOT_AN_INTEGER_VALUE, - STRING_NOT_A_REAL_VALUE, - - ASSERTION_FAILED, - AMBIGUOUS_CALL, - CANNOT_CAST - }; -}; - -class IVDXScriptInterpreter { -public: - virtual void _placeholder1() {} - virtual void _placeholder2(void *, void *) {} - virtual void _placeholder3(char *s) {} - - virtual void ScriptError(int e)=0; - virtual void _placeholder4(VDXScriptError& cse) {} - virtual char** AllocTempString(long l)=0; - - virtual void _placeholder5() {} -}; - -#define EXT_SCRIPT_ERROR(x) (isi->ScriptError((VDXScriptError::x))) - -typedef VDXScriptValue (*VDXScriptFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); -typedef void (*VDXScriptVoidFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); -typedef int (*VDXScriptIntFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); - -struct VDXScriptFunctionDef { - VDXScriptFunctionPtr func_ptr; - const char *name; - const char *arg_list; -}; - -struct VDXScriptObject { - void *_lookup; // reserved - set to NULL - VDXScriptFunctionDef *func_list; - void *_obj_list; // reserved - set to NULL -}; - -class VDXScriptValue { -public: - enum { T_VOID, T_INT, T_PINT, T_STR, T_ARRAY, T_OBJECT, T_FNAME, T_FUNCTION, T_VARLV, T_LONG, T_DOUBLE } type; - VDXScriptObject *thisPtr; - union { - int i; - char **s; - sint64 l; - double d; - } u; - - VDXScriptValue() { type = T_VOID; } - VDXScriptValue(int i) { type = T_INT; u.i = i; } - VDXScriptValue(sint64 l) { type = T_LONG; u.l = l; } - VDXScriptValue(double d) { type = T_DOUBLE; u.d = d; } - VDXScriptValue(char **s) { type = T_STR; u.s = s; } - - bool isVoid() const { return type == T_VOID; } - bool isInt() const { return type == T_INT; } - bool isString() const { return type == T_STR; } - bool isLong() const { return type == T_LONG; } - bool isDouble() const { return type == T_DOUBLE; } - - int asInt() const { return u.i; } - sint64 asLong() const { return u.l; } - double asDouble() const { return u.d; } - char ** asString() const { return u.s; } -}; - -#ifdef _MSC_VER - #pragma pack(pop) -#endif - -#endif +// VirtualDub - Video processing and capture application +// Plugin headers +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_PLUGIN_VDVIDEOFILT_H +#define f_VD2_PLUGIN_VDVIDEOFILT_H + +#ifdef _MSC_VER + #pragma once + #pragma pack(push, 8) +#endif + +#include + +#include "vdplugin.h" + +typedef struct VDXHINSTANCEStruct *VDXHINSTANCE; +typedef struct VDXHDCStruct *VDXHDC; +typedef struct VDXHWNDStruct *VDXHWND; + +////////////////// + +struct VDXScriptObject; +struct VDXFilterVTbls; + +////////////////// + +enum { + /// Request distinct source and destination buffers. Otherwise, the source and destination buffers + /// alias (in-place mode). + FILTERPARAM_SWAP_BUFFERS = 0x00000001L, + + /// Request an extra buffer for the previous source frame. + FILTERPARAM_NEEDS_LAST = 0x00000002L, + + /// Filter supports image formats other than RGB32. Filters that support format negotiation must + /// set this flag for all calls to paramProc. + FILTERPARAM_SUPPORTS_ALTFORMATS = 0x00000004L, + + /// Filter requests 16 byte alignment for source and destination buffers. This guarantees that: + /// + /// - data and pitch fields are multiples of 16 bytes (aligned) + /// - an integral number of 16 byte vectors may be read, even if the last vector includes + /// some bytes beyond the end of the scanline (their values are undefined) + /// - an integral number of 16 byte vectors may be written, even if the last vector includes + /// some bytes beyong the end of the scanline (their values are ignored) + /// + FILTERPARAM_ALIGN_SCANLINES = 0x00000008L, + + /// Filter's output is purely a function of configuration parameters and source image data, and not + /// source or output frame numbers. In other words, two output frames produced by a filter instance + /// can be assumed to be identical images if: + /// + /// - the same number of source frames are prefetched + /// - the same type of prefetches are performed (direct vs. non-direct) + /// - the frame numbers for the two prefetch lists, taken in order, correspond to identical + /// source frames + /// - the prefetch cookies match + /// + /// Enabling this flag improves the ability of the host to identify identical frames and drop them + /// in preview or in the output file. + /// + FILTERPARAM_PURE_TRANSFORM = 0x00000010L, + + /// Filter cannot support the requested source format. Note that this sets all bits, so the meaning + /// of other bits is ignored. The one exception is that FILTERPARAM_SUPPORTS_ALTFORMATS is assumed + /// to be implicitly set. + FILTERPARAM_NOT_SUPPORTED = (long)0xFFFFFFFF +}; + +/// The filter has a delay from source to output. For instance, a lag of 3 indicates that the +/// filter internally buffers three frames, so when it is fed frames in sequence, frame 0 emerges +/// after frame 3 has been processed. The host attempts to correct timestamps in order to compensate. +/// +/// VirtualDub 1.9.1 or later: Setting this flag can have a performance penalty, as it causes the host +/// to request additional frames to try to produce the correct requested output frames. +/// +#define FILTERPARAM_HAS_LAG(frames) ((int)(frames) << 16) + +/////////////////// + +class VDXFBitmap; +class VDXFilterActivation; +struct VDXFilterFunctions; +struct VDXFilterModule; +class IVDXVideoPrefetcher; + +enum { + kVDXVFEvent_None = 0, + kVDXVFEvent_InvalidateCaches = 1 +}; + +typedef int (__cdecl *VDXFilterInitProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef void (__cdecl *VDXFilterDeinitProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef int (__cdecl *VDXFilterRunProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef long (__cdecl *VDXFilterParamProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef int (__cdecl *VDXFilterConfigProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hWnd); +typedef void (__cdecl *VDXFilterStringProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf); +typedef int (__cdecl *VDXFilterStartProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef int (__cdecl *VDXFilterEndProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef bool (__cdecl *VDXFilterScriptStrProc)(VDXFilterActivation *fa, const VDXFilterFunctions *, char *, int); +typedef void (__cdecl *VDXFilterStringProc2 )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen); +typedef int (__cdecl *VDXFilterSerialize )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxbuf); +typedef void (__cdecl *VDXFilterDeserialize )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, const char *buf, int maxbuf); +typedef void (__cdecl *VDXFilterCopy )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst); +typedef sint64 (__cdecl *VDXFilterPrefetch )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame); +typedef void (__cdecl *VDXFilterCopy2Proc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst, VDXFilterActivation *fa2, const VDXFilterFunctions *ff2); +typedef bool (__cdecl *VDXFilterPrefetch2Proc)(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame, IVDXVideoPrefetcher *prefetcher); +typedef bool (__cdecl *VDXFilterEventProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, uint32 event, const void *eventData); + +typedef int (__cdecl *VDXFilterModuleInitProc)(VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat); +typedef void (__cdecl *VDXFilterModuleDeinitProc)(VDXFilterModule *fm, const VDXFilterFunctions *ff); + +////////// + +typedef void (__cdecl *VDXFilterPreviewButtonCallback)(bool fNewState, void *pData); +typedef void (__cdecl *VDXFilterPreviewSampleCallback)(VDXFBitmap *, long lFrame, long lCount, void *pData); + +class IVDXFilterPreview { +public: + virtual void SetButtonCallback(VDXFilterPreviewButtonCallback, void *)=0; + virtual void SetSampleCallback(VDXFilterPreviewSampleCallback, void *)=0; + + virtual bool isPreviewEnabled()=0; + virtual void Toggle(VDXHWND)=0; + virtual void Display(VDXHWND, bool)=0; + virtual void RedoFrame()=0; + virtual void RedoSystem()=0; + virtual void UndoSystem()=0; + virtual void InitButton(VDXHWND)=0; + virtual void Close()=0; + virtual bool SampleCurrentFrame()=0; + virtual long SampleFrames()=0; +}; + +class IVDXFilterPreview2 : public IVDXFilterPreview { +public: + virtual bool IsPreviewDisplayed() = 0; +}; + +class IVDXVideoPrefetcher : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'v', 'p', 'f') }; + + /// Request a video frame fetch from an upstream source. + virtual void VDXAPIENTRY PrefetchFrame(sint32 srcIndex, sint64 frame, uint64 cookie) = 0; + + /// Request a video frame fetch from an upstream source in direct mode. + /// This specifies that the output frame is the same as the input frame. + /// There cannot be more than one direct fetch and there must be no standard + /// fetches at the same time. There can, however, be symbolic fetches. + virtual void VDXAPIENTRY PrefetchFrameDirect(sint32 srcIndex, sint64 frame) = 0; + + /// Request a symbolic fetch from a source. This does not actually fetch + /// any frames, but marks an association from source to output. This is + /// useful for indicating the approximate center of where an output derives + /// in a source, even if those frames aren't fetched (perhaps due to caching). + /// There may be either zero or one symbolic fetch per source. + /// + /// If no symbolic fetches are performed, the symbolic frame is assumed to + /// be the rounded mean of the fetched source frames. + virtual void VDXAPIENTRY PrefetchFrameSymbolic(sint32 srcIndex, sint64 frame) = 0; +}; + +////////// + +enum { + // This is the highest API version supported by this header file. + VIRTUALDUB_FILTERDEF_VERSION = 14, + + // This is the absolute lowest API version supported by this header file. + // Note that V4 is rather old, corresponding to VirtualDub 1.2. + // Chances are you will need to declare a higher version. + VIRTUALDUB_FILTERDEF_COMPATIBLE = 4, + + // API V9 is a slightly saner baseline, since it is the first API + // version that has copy constructor support. You may still need to + // declare a higher vdfd_compat version in your module init if you + // need features beyond V9 (VirtualDub 1.4.12). + VIRTUALDUB_FILTERDEF_COMPATIBLE_COPYCTOR = 9 + +}; + +// v3: added lCurrentSourceFrame to FrameStateInfo +// v4 (1.2): lots of additions (VirtualDub 1.2) +// v5 (1.3d): lots of bugfixes - stretchblt bilinear, and non-zero startproc +// v6 (1.4): added error handling functions +// v7 (1.4d): added frame lag, exception handling +// v8 (1.4.11): added string2 proc +// v9 (1.4.12): added (working) copy constructor +// v10 (1.5.10): added preview flag +// v11 (1.7.0): guaranteed src structure setup before configProc; added IVDFilterPreview2 +// v12 (1.8.0): support for frame alteration +// v13 (1.8.2): added mOutputFrame field to VDXFilterStateInfo +// v14 (1.9.1): added copyProc2, prefetchProc2, input/output frame arrays + +struct VDXFilterDefinition { + void *_next; // deprecated - set to NULL + void *_prev; // deprecated - set to NULL + void *_module; // deprecated - set to NULL + + const char * name; + const char * desc; + const char * maker; + void * private_data; + int inst_data_size; + + VDXFilterInitProc initProc; + VDXFilterDeinitProc deinitProc; + VDXFilterRunProc runProc; + VDXFilterParamProc paramProc; + VDXFilterConfigProc configProc; + VDXFilterStringProc stringProc; + VDXFilterStartProc startProc; + VDXFilterEndProc endProc; + + VDXScriptObject *script_obj; + + VDXFilterScriptStrProc fssProc; + + // NEW - 1.4.11 + VDXFilterStringProc2 stringProc2; + VDXFilterSerialize serializeProc; + VDXFilterDeserialize deserializeProc; + VDXFilterCopy copyProc; + + VDXFilterPrefetch prefetchProc; // (V12/V1.7.4+) + + // NEW - V14 / 1.9.1 + VDXFilterCopy2Proc copyProc2; + VDXFilterPrefetch2Proc prefetchProc2; + VDXFilterEventProc eventProc; +}; + +////////// + +// FilterStateInfo: contains dynamic info about file being processed + +class VDXFilterStateInfo { +public: + sint32 lCurrentFrame; // current sequence frame (previously called output frame) + sint32 lMicrosecsPerFrame; // microseconds per sequence frame + sint32 lCurrentSourceFrame; // current source frame + sint32 lMicrosecsPerSrcFrame; // microseconds per source frame + sint32 lSourceFrameMS; // source frame timestamp + sint32 lDestFrameMS; // output frame timestamp + + enum { + kStateNone = 0x00000000, + kStatePreview = 0x00000001, // (V1.5.10+) Job output is not being saved to disk. + kStateRealTime = 0x00000002, // (V1.5.10+) Operation is running in real-time (capture, playback). + kStateMax = 0xFFFFFFFF + }; + + uint32 flags; // (V10 / 1.5.10+ only) + + sint32 mOutputFrame; // (V13/V1.8.2+) current output frame +}; + +// VDXFBitmap: VBitmap extended to hold filter-specific information + +class VDXBitmap { +public: + void * _vtable; // Reserved - do not use. + uint32 * data; // Pointer to start of _bottom-most_ scanline of plane 0. + uint32 * palette; // Pointer to palette (reserved - set to NULL). + sint32 depth; // Bit depth, in bits. Set to zero if mpPixmap/mpPixmapLayout are active. + sint32 w; // Width of bitmap, in pixels. + sint32 h; // Height of bitmap, in pixels. + ptrdiff_t pitch; // Distance, in bytes, from the start of one scanline in plane 0 to the next. + ptrdiff_t modulo; // Distance, in bytes, from the end of one scanline in plane 0 to the start of the next. + ptrdiff_t size; // Size of plane 0, including padding. + ptrdiff_t offset; // Offset from beginning of buffer to beginning of plane 0. + + uint32 *Address32(int x, int y) const { + return Address32i(x, h-y-1); + } + + uint32 *Address32i(int x, int y) const { + return (uint32 *)((char *)data + y*pitch + x*4); + } + + void AlignTo4() { + pitch = w << 2; + } + + void AlignTo8() { + pitch = ((w+1)&~1) << 2; + } +}; + +class VDXFBitmap : public VDXBitmap { +public: + enum { + /// Set in paramProc if the filter requires a Win32 GDI display context + /// for a bitmap. (Deprecated as of API V12 - do not use) + NEEDS_HDC = 0x00000001L, + }; + + uint32 dwFlags; + VDXHDC hdc; + + uint32 mFrameRateHi; // Frame rate numerator (V1.7.4+) + uint32 mFrameRateLo; // Frame rate denominator (V1.7.4+) + sint64 mFrameCount; // Frame count; -1 if unlimited or indeterminate (V1.7.4+) + + VDXPixmapLayout *mpPixmapLayout; + const VDXPixmap *mpPixmap; + + uint32 mAspectRatioHi; ///< Pixel aspect ratio fraction (numerator). 0/0 = unknown + uint32 mAspectRatioLo; ///< Pixel aspect ratio fraction (denominator). + + sint64 mFrameNumber; ///< Current frame number (zero based). + sint64 mFrameTimestampStart; ///< Starting timestamp of frame, in 100ns units. + sint64 mFrameTimestampEnd; ///< Ending timestamp of frame, in 100ns units. + sint64 mCookie; ///< Cookie supplied when frame was requested. +}; + +// VDXFilterActivation: This is what is actually passed to filters at runtime. + +class VDXFilterActivation { +public: + const VDXFilterDefinition *filter; // + void *filter_data; + VDXFBitmap& dst; + VDXFBitmap& src; + VDXFBitmap *_reserved0; + VDXFBitmap *const last; + uint32 x1; + uint32 y1; + uint32 x2; + uint32 y2; + + VDXFilterStateInfo *pfsi; + IVDXFilterPreview *ifp; + IVDXFilterPreview2 *ifp2; // (V11+) + + uint32 mSourceFrameCount; // (V14+) + VDXFBitmap *const *mpSourceFrames; // (V14+) + VDXFBitmap *const *mpOutputFrames; // (V14+) +}; + +// These flags must match those in cpuaccel.h! + +#ifndef f_VIRTUALDUB_CPUACCEL_H +#define CPUF_SUPPORTS_CPUID (0x00000001L) +#define CPUF_SUPPORTS_FPU (0x00000002L) +#define CPUF_SUPPORTS_MMX (0x00000004L) +#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) +#define CPUF_SUPPORTS_SSE (0x00000010L) +#define CPUF_SUPPORTS_SSE2 (0x00000020L) +#define CPUF_SUPPORTS_3DNOW (0x00000040L) +#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) +#endif + +struct VDXFilterFunctions { + VDXFilterDefinition *(__cdecl *addFilter)(VDXFilterModule *, VDXFilterDefinition *, int fd_len); + void (__cdecl *removeFilter)(VDXFilterDefinition *); + bool (__cdecl *isFPUEnabled)(); + bool (__cdecl *isMMXEnabled)(); + void (__cdecl *InitVTables)(VDXFilterVTbls *); + + // These functions permit you to throw MyError exceptions from a filter. + // YOU MUST ONLY CALL THESE IN runProc, initProc, and startProc. + + void (__cdecl *ExceptOutOfMemory)(); // ADDED: V6 (VirtualDub 1.4) + void (__cdecl *Except)(const char *format, ...); // ADDED: V6 (VirtualDub 1.4) + + // These functions are callable at any time. + + long (__cdecl *getCPUFlags)(); // ADDED: V6 (VirtualDub 1.4) + long (__cdecl *getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d) +}; + + + + + +/////////////////////////////////////////////////////////////////////////// + +class VDXScriptValue; +class VDXScriptError; +struct VDXScriptObject; + +class VDXScriptError { +public: + enum { + PARSE_ERROR=1, + SEMICOLON_EXPECTED, + IDENTIFIER_EXPECTED, + + TYPE_INT_REQUIRED, + TYPE_ARRAY_REQUIRED, + TYPE_FUNCTION_REQUIRED, + TYPE_OBJECT_REQUIRED, + + OBJECT_MEMBER_NAME_REQUIRED, + FUNCCALLEND_EXPECTED, + TOO_MANY_PARAMS, + DIVIDE_BY_ZERO, + VAR_NOT_FOUND, + MEMBER_NOT_FOUND, + OVERLOADED_FUNCTION_NOT_FOUND, + IDENT_TOO_LONG, + OPERATOR_EXPECTED, + CLOSEPARENS_EXPECTED, + CLOSEBRACKET_EXPECTED, + + VAR_UNDEFINED, + + OUT_OF_STRING_SPACE, + OUT_OF_MEMORY, + INTERNAL_ERROR, + EXTERNAL_ERROR, + + FCALL_OUT_OF_RANGE, + FCALL_INVALID_PTYPE, + FCALL_UNKNOWN_STR, + + ARRAY_INDEX_OUT_OF_BOUNDS, + + NUMERIC_OVERFLOW, + STRING_NOT_AN_INTEGER_VALUE, + STRING_NOT_A_REAL_VALUE, + + ASSERTION_FAILED, + AMBIGUOUS_CALL, + CANNOT_CAST + }; +}; + +class IVDXScriptInterpreter { +public: + virtual void _placeholder1() {} + virtual void _placeholder2(void *, void *) {} + virtual void _placeholder3(char *s) {} + + virtual void ScriptError(int e)=0; + virtual void _placeholder4(VDXScriptError& cse) {} + virtual char** AllocTempString(long l)=0; + + virtual void _placeholder5() {} +}; + +#define EXT_SCRIPT_ERROR(x) (isi->ScriptError((VDXScriptError::x))) + +typedef VDXScriptValue (*VDXScriptFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); +typedef void (*VDXScriptVoidFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); +typedef int (*VDXScriptIntFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); + +struct VDXScriptFunctionDef { + VDXScriptFunctionPtr func_ptr; + const char *name; + const char *arg_list; +}; + +struct VDXScriptObject { + void *_lookup; // reserved - set to NULL + VDXScriptFunctionDef *func_list; + void *_obj_list; // reserved - set to NULL +}; + +class VDXScriptValue { +public: + enum { T_VOID, T_INT, T_PINT, T_STR, T_ARRAY, T_OBJECT, T_FNAME, T_FUNCTION, T_VARLV, T_LONG, T_DOUBLE } type; + VDXScriptObject *thisPtr; + union { + int i; + char **s; + sint64 l; + double d; + } u; + + VDXScriptValue() { type = T_VOID; } + VDXScriptValue(int i) { type = T_INT; u.i = i; } + VDXScriptValue(sint64 l) { type = T_LONG; u.l = l; } + VDXScriptValue(double d) { type = T_DOUBLE; u.d = d; } + VDXScriptValue(char **s) { type = T_STR; u.s = s; } + + bool isVoid() const { return type == T_VOID; } + bool isInt() const { return type == T_INT; } + bool isString() const { return type == T_STR; } + bool isLong() const { return type == T_LONG; } + bool isDouble() const { return type == T_DOUBLE; } + + int asInt() const { return u.i; } + sint64 asLong() const { return u.l; } + double asDouble() const { return u.d; } + char ** asString() const { return u.s; } +}; + +#ifdef _MSC_VER + #pragma pack(pop) +#endif + +#endif diff --git a/include/vd2/plugin/vdvideoutil.h b/include/vd2/plugin/vdvideoutil.h index 8379e4f7d9a..152bfd5f055 100644 --- a/include/vd2/plugin/vdvideoutil.h +++ b/include/vd2/plugin/vdvideoutil.h @@ -1,121 +1,121 @@ -#ifndef f_VD2_PLUGIN_VDVIDEOUTIL_H -#define f_VD2_PLUGIN_VDVIDEOUTIL_H - -template -T *vd_ptroffset(T *p, ptrdiff_t diff) { - return (T *)((char *)p + diff); -} - -template -class vd_row_iter { -public: - vd_row_iter() {} - vd_row_iter(T *p, ptrdiff_t pitch) : mp(p), mpitch(pitch) {} - vd_row_iter(T *p, ptrdiff_t pitch, int y) : mp(vd_ptroffset(p, pitch*y)), mpitch(pitch) {} - - vd_row_iter(const VFBitmap& bm, int x = 0, int y = 0) : mp(vd_ptroffset((T*)bm.data, bm.pitch*(bm.h - 1 - y))+x), mpitch(-bm.pitch) {} - - operator T*() const { return mp; } - T& operator[](int x) const { return mp[x]; } - - void mulstep(int x) { - mpitch *= x; - } - - const vd_row_iter& operator+=(int y) { - mp = vd_ptroffset(mp, mpitch * y); - return *this; - } - - const vd_row_iter& operator-=(int y) { - mp = vd_ptroffset(mp, -(mpitch * y)); - return *this; - } - - const vd_row_iter& operator++() { - mp = vd_ptroffset(mp, mpitch); - return *this; - } - - const vd_row_iter operator++(int) { - const vd_row_iter temp(*this); - mp = vd_ptroffset(mp, mpitch); - return temp; - } - - const vd_row_iter& operator--() { - mp = vd_ptroffset(mp, -mpitch); - return *this; - } - - const vd_row_iter operator--(int) { - const vd_row_iter temp(*this); - mp = vd_ptroffset(mp, -mpitch); - return temp; - } - -protected: - T *mp; - ptrdiff_t mpitch; -}; - -typedef vd_row_iter vd_pixrow_iter; - -inline uint32 vd_pixavg_down(uint32 x, uint32 y) { - return (x&y) + (((x^y)&0xfefefefe)>>1); -} - -inline uint32 vd_pixavg_up(uint32 x, uint32 y) { - return (x|y) - (((x^y)&0xfefefefe)>>1); -} - -inline void vd_pixunpack(uint32 px, int& r, int& g, int& b) { - r = (px>>16)&255; - g = (px>> 8)&255; - b = (px )&255; -} - -inline uint32 vd_pixpack(int r, int g, int b) { - if ((unsigned)r >= 256) r = ~(r>>31) & 255; - if ((unsigned)g >= 256) g = ~(g>>31) & 255; - if ((unsigned)b >= 256) b = ~(b>>31) & 255; - - return (r<<16) + (g<<8) + b; -} - -inline uint32 vd_pixpackfast(int r, int g, int b) { - return (r<<16) + (g<<8) + b; -} - -struct vd_transform_pixmap_helper { - vd_transform_pixmap_helper(const VFBitmap& dst) - : p((uint32 *)dst.data) - , pitch(dst.pitch) - , w(dst.w) - , h(dst.h) {} - - operator bool() const { return false; } - - uint32 *p; - const ptrdiff_t pitch; - const int w, h; -}; - -#define vd_transform_pixmap_blt(dst, src) \ - if(vd_transform_pixmap_helper dstinfo = dst);else \ - if(vd_transform_pixmap_helper srcinfo = src);else \ - for(int y = 0, h = dstinfo.h, w = dstinfo.w; y < h; ++y, dstinfo.p=vd_ptroffset(dstinfo.p, dstinfo.pitch), srcinfo.p=vd_ptroffset(srcinfo.p, srcinfo.pitch)) \ - for(int x = 0; x < dstinfo.w; ++x) \ - switch(unsigned& out = dstinfo.p[x]) case 0: default: \ - switch(const unsigned& in = srcinfo.p[x]) case 0: default: - -#define vd_transform_pixmap_inplace(dst) \ - if(vd_transform_pixmap_helper dstinfo = dst);else \ - for(int y = 0, h = dstinfo.h, w = dstinfo.w; y < h; ++y, dstinfo.p=vd_ptroffset(dstinfo.p, dstinfo.pitch)) \ - for(int x = 0; x < dstinfo.w; ++x) \ - switch(unsigned& px = dstinfo.p[x]) case 0: default: \ - -#define vd_maketable256_16(x) formula((x+0)),formula((x+1)),formula((x+2)),formula((x+3)),formula((x+4)),formula((x+5)),formula((x+6)),formula((x+7)),formula((x+8)),formula((x+9)),formula((x+10)),formula((x+11)),formula((x+12)),formula((x+13)),formula((x+14)),formula((x+15)) -#define vd_maketable256 vd_maketable256_16(0x00),vd_maketable256_16(0x10),vd_maketable256_16(0x20),vd_maketable256_16(0x30),vd_maketable256_16(0x40),vd_maketable256_16(0x50),vd_maketable256_16(0x60),vd_maketable256_16(0x70),vd_maketable256_16(0x80),vd_maketable256_16(0x90),vd_maketable256_16(0xA0),vd_maketable256_16(0xB0),vd_maketable256_16(0xC0),vd_maketable256_16(0xD0),vd_maketable256_16(0xE0),vd_maketable256_16(0xF0), - -#endif +#ifndef f_VD2_PLUGIN_VDVIDEOUTIL_H +#define f_VD2_PLUGIN_VDVIDEOUTIL_H + +template +T *vd_ptroffset(T *p, ptrdiff_t diff) { + return (T *)((char *)p + diff); +} + +template +class vd_row_iter { +public: + vd_row_iter() {} + vd_row_iter(T *p, ptrdiff_t pitch) : mp(p), mpitch(pitch) {} + vd_row_iter(T *p, ptrdiff_t pitch, int y) : mp(vd_ptroffset(p, pitch*y)), mpitch(pitch) {} + + vd_row_iter(const VFBitmap& bm, int x = 0, int y = 0) : mp(vd_ptroffset((T*)bm.data, bm.pitch*(bm.h - 1 - y))+x), mpitch(-bm.pitch) {} + + operator T*() const { return mp; } + T& operator[](int x) const { return mp[x]; } + + void mulstep(int x) { + mpitch *= x; + } + + const vd_row_iter& operator+=(int y) { + mp = vd_ptroffset(mp, mpitch * y); + return *this; + } + + const vd_row_iter& operator-=(int y) { + mp = vd_ptroffset(mp, -(mpitch * y)); + return *this; + } + + const vd_row_iter& operator++() { + mp = vd_ptroffset(mp, mpitch); + return *this; + } + + const vd_row_iter operator++(int) { + const vd_row_iter temp(*this); + mp = vd_ptroffset(mp, mpitch); + return temp; + } + + const vd_row_iter& operator--() { + mp = vd_ptroffset(mp, -mpitch); + return *this; + } + + const vd_row_iter operator--(int) { + const vd_row_iter temp(*this); + mp = vd_ptroffset(mp, -mpitch); + return temp; + } + +protected: + T *mp; + ptrdiff_t mpitch; +}; + +typedef vd_row_iter vd_pixrow_iter; + +inline uint32 vd_pixavg_down(uint32 x, uint32 y) { + return (x&y) + (((x^y)&0xfefefefe)>>1); +} + +inline uint32 vd_pixavg_up(uint32 x, uint32 y) { + return (x|y) - (((x^y)&0xfefefefe)>>1); +} + +inline void vd_pixunpack(uint32 px, int& r, int& g, int& b) { + r = (px>>16)&255; + g = (px>> 8)&255; + b = (px )&255; +} + +inline uint32 vd_pixpack(int r, int g, int b) { + if ((unsigned)r >= 256) r = ~(r>>31) & 255; + if ((unsigned)g >= 256) g = ~(g>>31) & 255; + if ((unsigned)b >= 256) b = ~(b>>31) & 255; + + return (r<<16) + (g<<8) + b; +} + +inline uint32 vd_pixpackfast(int r, int g, int b) { + return (r<<16) + (g<<8) + b; +} + +struct vd_transform_pixmap_helper { + vd_transform_pixmap_helper(const VFBitmap& dst) + : p((uint32 *)dst.data) + , pitch(dst.pitch) + , w(dst.w) + , h(dst.h) {} + + operator bool() const { return false; } + + uint32 *p; + const ptrdiff_t pitch; + const int w, h; +}; + +#define vd_transform_pixmap_blt(dst, src) \ + if(vd_transform_pixmap_helper dstinfo = dst);else \ + if(vd_transform_pixmap_helper srcinfo = src);else \ + for(int y = 0, h = dstinfo.h, w = dstinfo.w; y < h; ++y, dstinfo.p=vd_ptroffset(dstinfo.p, dstinfo.pitch), srcinfo.p=vd_ptroffset(srcinfo.p, srcinfo.pitch)) \ + for(int x = 0; x < dstinfo.w; ++x) \ + switch(unsigned& out = dstinfo.p[x]) case 0: default: \ + switch(const unsigned& in = srcinfo.p[x]) case 0: default: + +#define vd_transform_pixmap_inplace(dst) \ + if(vd_transform_pixmap_helper dstinfo = dst);else \ + for(int y = 0, h = dstinfo.h, w = dstinfo.w; y < h; ++y, dstinfo.p=vd_ptroffset(dstinfo.p, dstinfo.pitch)) \ + for(int x = 0; x < dstinfo.w; ++x) \ + switch(unsigned& px = dstinfo.p[x]) case 0: default: \ + +#define vd_maketable256_16(x) formula((x+0)),formula((x+1)),formula((x+2)),formula((x+3)),formula((x+4)),formula((x+5)),formula((x+6)),formula((x+7)),formula((x+8)),formula((x+9)),formula((x+10)),formula((x+11)),formula((x+12)),formula((x+13)),formula((x+14)),formula((x+15)) +#define vd_maketable256 vd_maketable256_16(0x00),vd_maketable256_16(0x10),vd_maketable256_16(0x20),vd_maketable256_16(0x30),vd_maketable256_16(0x40),vd_maketable256_16(0x50),vd_maketable256_16(0x60),vd_maketable256_16(0x70),vd_maketable256_16(0x80),vd_maketable256_16(0x90),vd_maketable256_16(0xA0),vd_maketable256_16(0xB0),vd_maketable256_16(0xC0),vd_maketable256_16(0xD0),vd_maketable256_16(0xE0),vd_maketable256_16(0xF0), + +#endif diff --git a/include/version.h b/include/version.h index 596e817179a..e554d1bc12c 100644 --- a/include/version.h +++ b/include/version.h @@ -1,117 +1,117 @@ -#ifndef ISPP_INVOKED -/* - * (C) 2010-2024 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 . - - - * Notes: - * NO_VERSION_REV_NEEDED is defined in those cases where we don't need the revision - number, but only the major/minor/patch version so the compiler does not rebuild - everything for every revision. It's currently used in mpcresources, mpciconlib - and VideoRenderers projects. - * MPC_VERSION_ARCH is currently used in VSFilter only. - */ -#endif // ISPP_INVOKED - -#ifndef MPC_VERSION_H -#define MPC_VERSION_H - -#include "mpc-hc_config.h" - -#ifndef _T -#if !defined(ISPP_INVOKED) && (defined(UNICODE) || defined(_UNICODE)) -#define _T(text) L##text -#else -#define _T(text) text -#endif -#endif - -#ifdef NO_VERSION_REV_NEEDED -#define MPC_VERSION_REV 0 -#else -#include "../build/version_rev.h" -#endif - -#define MPC_VERSION_MAJOR 2 -#define MPC_VERSION_MINOR 3 -#define MPC_VERSION_PATCH 7 - -#if MPC_VERSION_REV > 0 -#define MPC_NIGHTLY_RELEASE 1 -#else -#define MPC_NIGHTLY_RELEASE 0 -#endif - -#define MPC_COMP_NAME_STR _T("MPC-HC Team") -#define MPC_COPYRIGHT_STR _T("Copyright 2002-2024 clsid2 and others") -#define MPC_VERSION_COMMENTS WEBSITE_URL - - -#ifndef ISPP_INVOKED - -#ifdef NO_VERSION_REV_NEEDED - -#define MPC_VERSION_NUM MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCH,0 -#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) -#define MPC_VERSION_STR_FULL MPC_VERSION_STR - -#else // !NO_VERSION_REV_NEEDED - -#define MPC_VERSION_NUM MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCH,MPC_VERSION_REV - -#if MPC_NIGHTLY_RELEASE - -#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) _T(".") \ - MAKE_STR(MPC_VERSION_REV) -#define MPC_VERSION_STR_FULL MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) _T(".") \ - MAKE_STR(MPC_VERSION_REV) \ - MPC_VERSION_ADDITIONAL - -#else // !MPC_NIGHTLY_RELEASE - -#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) -#define MPC_VERSION_STR_FULL MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) \ - MPC_VERSION_ADDITIONAL - -#endif // MPC_NIGHTLY_RELEASE - -#endif // NO_VERSION_REV_NEEDED - -#endif // ISPP_INVOKED - - -#if MPC_NIGHTLY_RELEASE -#define MPC_VERSION_NIGHTLY _T("Nightly") -#endif - -#ifdef _WIN64 -#define MPC_VERSION_ARCH _T("x64") -#else -#define MPC_VERSION_ARCH _T("x86") -#endif - -#endif // MPC_VERSION_H +#ifndef ISPP_INVOKED +/* + * (C) 2010-2024 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 . + + + * Notes: + * NO_VERSION_REV_NEEDED is defined in those cases where we don't need the revision + number, but only the major/minor/patch version so the compiler does not rebuild + everything for every revision. It's currently used in mpcresources, mpciconlib + and VideoRenderers projects. + * MPC_VERSION_ARCH is currently used in VSFilter only. + */ +#endif // ISPP_INVOKED + +#ifndef MPC_VERSION_H +#define MPC_VERSION_H + +#include "mpc-hc_config.h" + +#ifndef _T +#if !defined(ISPP_INVOKED) && (defined(UNICODE) || defined(_UNICODE)) +#define _T(text) L##text +#else +#define _T(text) text +#endif +#endif + +#ifdef NO_VERSION_REV_NEEDED +#define MPC_VERSION_REV 0 +#else +#include "../build/version_rev.h" +#endif + +#define MPC_VERSION_MAJOR 2 +#define MPC_VERSION_MINOR 3 +#define MPC_VERSION_PATCH 7 + +#if MPC_VERSION_REV > 0 +#define MPC_NIGHTLY_RELEASE 1 +#else +#define MPC_NIGHTLY_RELEASE 0 +#endif + +#define MPC_COMP_NAME_STR _T("MPC-HC Team") +#define MPC_COPYRIGHT_STR _T("Copyright 2002-2024 clsid2 and others") +#define MPC_VERSION_COMMENTS WEBSITE_URL + + +#ifndef ISPP_INVOKED + +#ifdef NO_VERSION_REV_NEEDED + +#define MPC_VERSION_NUM MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCH,0 +#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) +#define MPC_VERSION_STR_FULL MPC_VERSION_STR + +#else // !NO_VERSION_REV_NEEDED + +#define MPC_VERSION_NUM MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCH,MPC_VERSION_REV + +#if MPC_NIGHTLY_RELEASE + +#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) _T(".") \ + MAKE_STR(MPC_VERSION_REV) +#define MPC_VERSION_STR_FULL MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) _T(".") \ + MAKE_STR(MPC_VERSION_REV) \ + MPC_VERSION_ADDITIONAL + +#else // !MPC_NIGHTLY_RELEASE + +#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) +#define MPC_VERSION_STR_FULL MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) \ + MPC_VERSION_ADDITIONAL + +#endif // MPC_NIGHTLY_RELEASE + +#endif // NO_VERSION_REV_NEEDED + +#endif // ISPP_INVOKED + + +#if MPC_NIGHTLY_RELEASE +#define MPC_VERSION_NIGHTLY _T("Nightly") +#endif + +#ifdef _WIN64 +#define MPC_VERSION_ARCH _T("x64") +#else +#define MPC_VERSION_ARCH _T("x86") +#endif + +#endif // MPC_VERSION_H diff --git a/include/winddk/devioctl.h b/include/winddk/devioctl.h index bcb458c74d1..fa2e6995bcb 100644 --- a/include/winddk/devioctl.h +++ b/include/winddk/devioctl.h @@ -1,164 +1,164 @@ -/*++ BUILD Version: 0004 // Increment this if a change has global effects - -Copyright (c) 1992-1999 Microsoft Corporation - -Module Name: - - devioctl.h - -Abstract: - - This module contains - - -Revision History: - - ---*/ - -// begin_winioctl - -#ifndef _DEVIOCTL_ -#define _DEVIOCTL_ - -// begin_ntddk begin_wdm begin_nthal begin_ntifs -// -// Define the various device type values. Note that values used by Microsoft -// Corporation are in the range 0-32767, and 32768-65535 are reserved for use -// by customers. -// - -#define DEVICE_TYPE ULONG - -#define FILE_DEVICE_BEEP 0x00000001 -#define FILE_DEVICE_CD_ROM 0x00000002 -#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 -#define FILE_DEVICE_CONTROLLER 0x00000004 -#define FILE_DEVICE_DATALINK 0x00000005 -#define FILE_DEVICE_DFS 0x00000006 -#define FILE_DEVICE_DISK 0x00000007 -#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 -#define FILE_DEVICE_FILE_SYSTEM 0x00000009 -#define FILE_DEVICE_INPORT_PORT 0x0000000a -#define FILE_DEVICE_KEYBOARD 0x0000000b -#define FILE_DEVICE_MAILSLOT 0x0000000c -#define FILE_DEVICE_MIDI_IN 0x0000000d -#define FILE_DEVICE_MIDI_OUT 0x0000000e -#define FILE_DEVICE_MOUSE 0x0000000f -#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 -#define FILE_DEVICE_NAMED_PIPE 0x00000011 -#define FILE_DEVICE_NETWORK 0x00000012 -#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 -#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 -#define FILE_DEVICE_NULL 0x00000015 -#define FILE_DEVICE_PARALLEL_PORT 0x00000016 -#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 -#define FILE_DEVICE_PRINTER 0x00000018 -#define FILE_DEVICE_SCANNER 0x00000019 -#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a -#define FILE_DEVICE_SERIAL_PORT 0x0000001b -#define FILE_DEVICE_SCREEN 0x0000001c -#define FILE_DEVICE_SOUND 0x0000001d -#define FILE_DEVICE_STREAMS 0x0000001e -#define FILE_DEVICE_TAPE 0x0000001f -#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 -#define FILE_DEVICE_TRANSPORT 0x00000021 -#define FILE_DEVICE_UNKNOWN 0x00000022 -#define FILE_DEVICE_VIDEO 0x00000023 -#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 -#define FILE_DEVICE_WAVE_IN 0x00000025 -#define FILE_DEVICE_WAVE_OUT 0x00000026 -#define FILE_DEVICE_8042_PORT 0x00000027 -#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 -#define FILE_DEVICE_BATTERY 0x00000029 -#define FILE_DEVICE_BUS_EXTENDER 0x0000002a -#define FILE_DEVICE_MODEM 0x0000002b -#define FILE_DEVICE_VDM 0x0000002c -#define FILE_DEVICE_MASS_STORAGE 0x0000002d -#define FILE_DEVICE_SMB 0x0000002e -#define FILE_DEVICE_KS 0x0000002f -#define FILE_DEVICE_CHANGER 0x00000030 -#define FILE_DEVICE_SMARTCARD 0x00000031 -#define FILE_DEVICE_ACPI 0x00000032 -#define FILE_DEVICE_DVD 0x00000033 -#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 -#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 -#define FILE_DEVICE_DFS_VOLUME 0x00000036 -#define FILE_DEVICE_SERENUM 0x00000037 -#define FILE_DEVICE_TERMSRV 0x00000038 -#define FILE_DEVICE_KSEC 0x00000039 -#define FILE_DEVICE_FIPS 0x0000003A -#define FILE_DEVICE_INFINIBAND 0x0000003B -#define FILE_DEVICE_VMBUS 0x0000003E -#define FILE_DEVICE_CRYPT_PROVIDER 0x0000003F -#define FILE_DEVICE_WPD 0x00000040 -#define FILE_DEVICE_BLUETOOTH 0x00000041 -#define FILE_DEVICE_MT_COMPOSITE 0x00000042 -#define FILE_DEVICE_MT_TRANSPORT 0x00000043 -#define FILE_DEVICE_BIOMETRIC 0x00000044 -#define FILE_DEVICE_PMI 0x00000045 - -// -// Macro definition for defining IOCTL and FSCTL function control codes. Note -// that function codes 0-2047 are reserved for Microsoft Corporation, and -// 2048-4095 are reserved for customers. -// - -#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ -) - -// -// Macro to extract device type out of the device io control code -// -#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16) - -// -// Macro to extract buffering method out of the device io control code -// -#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3)) - -// -// Define the method codes for how buffers are passed for I/O and FS controls -// - -#define METHOD_BUFFERED 0 -#define METHOD_IN_DIRECT 1 -#define METHOD_OUT_DIRECT 2 -#define METHOD_NEITHER 3 - -// -// Define some easier to comprehend aliases: -// METHOD_DIRECT_TO_HARDWARE (writes, aka METHOD_IN_DIRECT) -// METHOD_DIRECT_FROM_HARDWARE (reads, aka METHOD_OUT_DIRECT) -// - -#define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT -#define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT - -// -// Define the access check value for any access -// -// -// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in -// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these -// constants *MUST* always be in sync. -// -// -// FILE_SPECIAL_ACCESS is checked by the NT I/O system the same as FILE_ANY_ACCESS. -// The file systems, however, may add additional access checks for I/O and FS controls -// that use this value. -// - - -#define FILE_ANY_ACCESS 0 -#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) -#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe -#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe - -// end_ntddk end_wdm end_nthal end_ntifs - -#endif // _DEVIOCTL_ - -// end_winioctl - +/*++ BUILD Version: 0004 // Increment this if a change has global effects + +Copyright (c) 1992-1999 Microsoft Corporation + +Module Name: + + devioctl.h + +Abstract: + + This module contains + + +Revision History: + + +--*/ + +// begin_winioctl + +#ifndef _DEVIOCTL_ +#define _DEVIOCTL_ + +// begin_ntddk begin_wdm begin_nthal begin_ntifs +// +// Define the various device type values. Note that values used by Microsoft +// Corporation are in the range 0-32767, and 32768-65535 are reserved for use +// by customers. +// + +#define DEVICE_TYPE ULONG + +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000a +#define FILE_DEVICE_KEYBOARD 0x0000000b +#define FILE_DEVICE_MAILSLOT 0x0000000c +#define FILE_DEVICE_MIDI_IN 0x0000000d +#define FILE_DEVICE_MIDI_OUT 0x0000000e +#define FILE_DEVICE_MOUSE 0x0000000f +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_SCREEN 0x0000001c +#define FILE_DEVICE_SOUND 0x0000001d +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002a +#define FILE_DEVICE_MODEM 0x0000002b +#define FILE_DEVICE_VDM 0x0000002c +#define FILE_DEVICE_MASS_STORAGE 0x0000002d +#define FILE_DEVICE_SMB 0x0000002e +#define FILE_DEVICE_KS 0x0000002f +#define FILE_DEVICE_CHANGER 0x00000030 +#define FILE_DEVICE_SMARTCARD 0x00000031 +#define FILE_DEVICE_ACPI 0x00000032 +#define FILE_DEVICE_DVD 0x00000033 +#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 +#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 +#define FILE_DEVICE_DFS_VOLUME 0x00000036 +#define FILE_DEVICE_SERENUM 0x00000037 +#define FILE_DEVICE_TERMSRV 0x00000038 +#define FILE_DEVICE_KSEC 0x00000039 +#define FILE_DEVICE_FIPS 0x0000003A +#define FILE_DEVICE_INFINIBAND 0x0000003B +#define FILE_DEVICE_VMBUS 0x0000003E +#define FILE_DEVICE_CRYPT_PROVIDER 0x0000003F +#define FILE_DEVICE_WPD 0x00000040 +#define FILE_DEVICE_BLUETOOTH 0x00000041 +#define FILE_DEVICE_MT_COMPOSITE 0x00000042 +#define FILE_DEVICE_MT_TRANSPORT 0x00000043 +#define FILE_DEVICE_BIOMETRIC 0x00000044 +#define FILE_DEVICE_PMI 0x00000045 + +// +// Macro definition for defining IOCTL and FSCTL function control codes. Note +// that function codes 0-2047 are reserved for Microsoft Corporation, and +// 2048-4095 are reserved for customers. +// + +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +// +// Macro to extract device type out of the device io control code +// +#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16) + +// +// Macro to extract buffering method out of the device io control code +// +#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3)) + +// +// Define the method codes for how buffers are passed for I/O and FS controls +// + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +// +// Define some easier to comprehend aliases: +// METHOD_DIRECT_TO_HARDWARE (writes, aka METHOD_IN_DIRECT) +// METHOD_DIRECT_FROM_HARDWARE (reads, aka METHOD_OUT_DIRECT) +// + +#define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT +#define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT + +// +// Define the access check value for any access +// +// +// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in +// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these +// constants *MUST* always be in sync. +// +// +// FILE_SPECIAL_ACCESS is checked by the NT I/O system the same as FILE_ANY_ACCESS. +// The file systems, however, may add additional access checks for I/O and FS controls +// that use this value. +// + + +#define FILE_ANY_ACCESS 0 +#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe +#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe + +// end_ntddk end_wdm end_nthal end_ntifs + +#endif // _DEVIOCTL_ + +// end_winioctl + diff --git a/include/winddk/ntddcdrm.h b/include/winddk/ntddcdrm.h index 909a9d8310a..2f02b4609a5 100644 --- a/include/winddk/ntddcdrm.h +++ b/include/winddk/ntddcdrm.h @@ -1,942 +1,942 @@ -/*++ BUILD Version: 0001 // Increment this if a change has global effects - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - ntddcdrm.h - -Abstract: - - This module contains structures and definitions - associated with CDROM IOCTls. - - ---*/ - -// begin_winioctl - -#ifndef _NTDDCDRM_ -#define _NTDDCDRM_ - - -#ifdef __cplusplus -extern "C" { -#endif - - -#if _MSC_VER >= 1200 -#pragma warning(push) -#endif - -#if _MSC_VER > 1000 -#pragma once -#endif - -// -// remove some level 4 warnings for this header file: -#pragma warning(disable:4200) // array[0] -#pragma warning(disable:4201) // nameless struct/unions -#pragma warning(disable:4214) // bit fields other than int -#if defined(__INTEL_COMPILER) -#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// -// NtDeviceIoControlFile IoControlCode values for this device. -// -// Warning: Remember that the low two bits of the code specify how the -// buffers are passed to the driver! -// - -#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM - -#define IOCTL_CDROM_UNLOAD_DRIVER CTL_CODE(IOCTL_CDROM_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// CDROM Audio Device Control Functions -// - -#define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_STOP_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_PAUSE_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_RESUME_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_GET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_PLAY_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_SET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) -#if (NTDDI_VERSION < NTDDI_WS03) -#define IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) -#else -#define OBSOLETE_IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) -#endif -#define IOCTL_CDROM_GET_LAST_SESSION CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) -#define IOCTL_CDROM_DISK_TYPE CTL_CODE(IOCTL_CDROM_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0014, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_READ_TOC_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_GET_CONFIGURATION CTL_CODE(IOCTL_CDROM_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_EXCLUSIVE_ACCESS CTL_CODE(IOCTL_CDROM_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_CDROM_SET_SPEED CTL_CODE(IOCTL_CDROM_BASE, 0x0018, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_GET_INQUIRY_DATA CTL_CODE(IOCTL_CDROM_BASE, 0x0019, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_ENABLE_STREAMING CTL_CODE(IOCTL_CDROM_BASE, 0x001A, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_SEND_OPC_INFORMATION CTL_CODE(IOCTL_CDROM_BASE, 0x001B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_CDROM_GET_PERFORMANCE CTL_CODE(IOCTL_CDROM_BASE, 0x001C, METHOD_BUFFERED, FILE_READ_ACCESS) - -// end_winioctl - -// -// The following device control codes are common for all class drivers. The -// functions codes defined here must match all of the other class drivers. -// -// Warning: these codes will be replaced in the future with the IOCTL_STORAGE -// codes included below -// - -#define IOCTL_CDROM_CHECK_VERIFY CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_EJECT_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_LOAD_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_RESERVE CTL_CODE(IOCTL_CDROM_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_RELEASE CTL_CODE(IOCTL_CDROM_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_FIND_NEW_DEVICES CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// The following file contains the IOCTL_STORAGE class ioctl definitions -// - -#include "ntddstor.h" - -// begin_winioctl - - -#define MINIMUM_CDROM_INQUIRY_SIZE 36 // RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) -#define MAXIMUM_CDROM_INQUIRY_SIZE 260 // MAXUCHAR + RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength) - -// -// The following device control code is for the SIMBAD simulated bad -// sector facility. See SIMBAD.H in this directory for related structures. -// - -#define IOCTL_CDROM_SIMBAD CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// Maximum CD Rom size -// - -#define MAXIMUM_NUMBER_TRACKS 100 -#define MAXIMUM_CDROM_SIZE 804 -#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2 // two bytes min transferred - -// -// READ_TOC_EX structure -// -typedef struct _CDROM_READ_TOC_EX { - UCHAR Format : 4; - UCHAR Reserved1 : 3; // future expansion - UCHAR Msf : 1; - UCHAR SessionTrack; - UCHAR Reserved2; // future expansion - UCHAR Reserved3; // future expansion -} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX; - -#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00 -#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01 -#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02 -#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03 -#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04 -#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05 - -// -// CD ROM Table OF Contents (TOC) -// Format 0 - Get table of contents -// - -typedef struct _TRACK_DATA { - UCHAR Reserved; - UCHAR Control : 4; - UCHAR Adr : 4; - UCHAR TrackNumber; - UCHAR Reserved1; - UCHAR Address[4]; -} TRACK_DATA, *PTRACK_DATA; - -typedef struct _CDROM_TOC { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR FirstTrack; - UCHAR LastTrack; - - // - // Track data - // - - TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; -} CDROM_TOC, *PCDROM_TOC; - -#define CDROM_TOC_SIZE sizeof(CDROM_TOC) - -// -// CD ROM Table OF Contents -// Format 1 - Session Information -// - -typedef struct _CDROM_TOC_SESSION_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR FirstCompleteSession; - UCHAR LastCompleteSession; - - // - // One track, representing the first track - // of the last finished session - // - - TRACK_DATA TrackData[1]; - -} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA; - - -// -// CD ROM Table OF Contents -// Format 2 - Full TOC -// - -typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK { - UCHAR SessionNumber; - UCHAR Control : 4; - UCHAR Adr : 4; - UCHAR Reserved1; - UCHAR Point; - UCHAR MsfExtra[3]; - UCHAR Zero; - UCHAR Msf[3]; -} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK; - -typedef struct _CDROM_TOC_FULL_TOC_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR FirstCompleteSession; - UCHAR LastCompleteSession; - - // - // one to N descriptors included - // - -#if !defined(__midl) - CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; -#endif - -} CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA; - -// -// CD ROM Table OF Contents -// Format 3 - Program Memory Area -// -typedef struct _CDROM_TOC_PMA_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR Reserved1; - UCHAR Reserved2; - - // - // one to N descriptors included - // - -#if !defined(__midl) - CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; -#endif - -} CDROM_TOC_PMA_DATA, *PCDROM_TOC_PMA_DATA; - -// -// CD ROM Table OF Contents -// Format 4 - Absolute Time In Pregroove -// - -typedef struct _CDROM_TOC_ATIP_DATA_BLOCK { - - UCHAR CdrwReferenceSpeed : 3; - UCHAR Reserved3 : 1; - UCHAR WritePower : 3; - UCHAR True1 : 1; - UCHAR Reserved4 : 6; - UCHAR UnrestrictedUse : 1; - UCHAR Reserved5 : 1; - UCHAR A3Valid : 1; - UCHAR A2Valid : 1; - UCHAR A1Valid : 1; - UCHAR DiscSubType : 3; - UCHAR IsCdrw : 1; - UCHAR True2 : 1; - UCHAR Reserved7; - - UCHAR LeadInMsf[3]; - UCHAR Reserved8; - - UCHAR LeadOutMsf[3]; - UCHAR Reserved9; - - UCHAR A1Values[3]; - UCHAR Reserved10; - - UCHAR A2Values[3]; - UCHAR Reserved11; - - UCHAR A3Values[3]; - UCHAR Reserved12; - -} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK; - -typedef struct _CDROM_TOC_ATIP_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR Reserved1; - UCHAR Reserved2; - - // - // zero? to N descriptors included. - // - -#if !defined(__midl) - CDROM_TOC_ATIP_DATA_BLOCK Descriptors[0]; -#endif - -} CDROM_TOC_ATIP_DATA, *PCDROM_TOC_ATIP_DATA; - -// -// CD ROM Table OF Contents -// Format 5 - CD Text Info -// -typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK { - UCHAR PackType; - UCHAR TrackNumber : 7; - UCHAR ExtensionFlag : 1; // should be zero! - UCHAR SequenceNumber; - UCHAR CharacterPosition : 4; - UCHAR BlockNumber : 3; - UCHAR Unicode : 1; - union { - UCHAR Text[12]; - WCHAR WText[6]; - }; - UCHAR CRC[2]; -} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK; - -typedef struct _CDROM_TOC_CD_TEXT_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR Reserved1; - UCHAR Reserved2; - - // - // the text info comes in discrete blocks of - // a heavily-overloaded structure - // - -#if !defined(__midl) - CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0]; -#endif - -} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA; - -// -// These are the types used for PackType field in CDROM_TOC_CD_TEXT_DATA_BLOCK -// and also for requesting specific info from IOCTL_CDROM_READ_CD_TEXT -// -#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80 -#define CDROM_CD_TEXT_PACK_PERFORMER 0x81 -#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82 -#define CDROM_CD_TEXT_PACK_COMPOSER 0x83 -#define CDROM_CD_TEXT_PACK_ARRANGER 0x84 -#define CDROM_CD_TEXT_PACK_MESSAGES 0x85 -#define CDROM_CD_TEXT_PACK_DISC_ID 0x86 -#define CDROM_CD_TEXT_PACK_GENRE 0x87 -#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88 -#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89 -// 0x8a - 0x8d are reserved.... -#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e -#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f - -// -// Play audio starting at MSF and ending at MSF -// - -typedef struct _CDROM_PLAY_AUDIO_MSF { - UCHAR StartingM; - UCHAR StartingS; - UCHAR StartingF; - UCHAR EndingM; - UCHAR EndingS; - UCHAR EndingF; -} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF; - -// -// Seek to MSF -// - -typedef struct _CDROM_SEEK_AUDIO_MSF { - UCHAR M; - UCHAR S; - UCHAR F; -} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; - - -// -// Flags for the disk type -// - -typedef struct _CDROM_DISK_DATA { - - ULONG DiskData; - -} CDROM_DISK_DATA, *PCDROM_DISK_DATA; - -#define CDROM_DISK_AUDIO_TRACK (0x00000001) -#define CDROM_DISK_DATA_TRACK (0x00000002) - -// -// CD ROM Data Mode Codes, used with IOCTL_CDROM_READ_Q_CHANNEL -// - -#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 -#define IOCTL_CDROM_CURRENT_POSITION 0x01 -#define IOCTL_CDROM_MEDIA_CATALOG 0x02 -#define IOCTL_CDROM_TRACK_ISRC 0x03 - -typedef struct _CDROM_SUB_Q_DATA_FORMAT { - UCHAR Format; - UCHAR Track; -} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; - - -// -// CD ROM Sub-Q Channel Data Format -// - -typedef struct _SUB_Q_HEADER { - UCHAR Reserved; - UCHAR AudioStatus; - UCHAR DataLength[2]; -} SUB_Q_HEADER, *PSUB_Q_HEADER; - -typedef struct _SUB_Q_CURRENT_POSITION { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Control : 4; - UCHAR ADR : 4; - UCHAR TrackNumber; - UCHAR IndexNumber; - UCHAR AbsoluteAddress[4]; - UCHAR TrackRelativeAddress[4]; -} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; - -typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved[3]; - UCHAR Reserved1 : 7; - UCHAR Mcval : 1; - UCHAR MediaCatalog[15]; -} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; - -typedef struct _SUB_Q_TRACK_ISRC { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved0; - UCHAR Track; - UCHAR Reserved1; - UCHAR Reserved2 : 7; - UCHAR Tcval : 1; - UCHAR TrackIsrc[15]; -} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; - -typedef union _SUB_Q_CHANNEL_DATA { - SUB_Q_CURRENT_POSITION CurrentPosition; - SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; - SUB_Q_TRACK_ISRC TrackIsrc; -} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; - -// -// Audio Status Codes -// - -#define AUDIO_STATUS_NOT_SUPPORTED 0x00 -#define AUDIO_STATUS_IN_PROGRESS 0x11 -#define AUDIO_STATUS_PAUSED 0x12 -#define AUDIO_STATUS_PLAY_COMPLETE 0x13 -#define AUDIO_STATUS_PLAY_ERROR 0x14 -#define AUDIO_STATUS_NO_STATUS 0x15 - -// -// ADR Sub-channel Q Field -// - -#define ADR_NO_MODE_INFORMATION 0x0 -#define ADR_ENCODES_CURRENT_POSITION 0x1 -#define ADR_ENCODES_MEDIA_CATALOG 0x2 -#define ADR_ENCODES_ISRC 0x3 - -// -// Sub-channel Q Control Bits -// - -#define AUDIO_WITH_PREEMPHASIS 0x1 -#define DIGITAL_COPY_PERMITTED 0x2 -#define AUDIO_DATA_TRACK 0x4 -#define TWO_FOUR_CHANNEL_AUDIO 0x8 - -#if (NTDDI_VERSION < NTDDI_WS03) -typedef struct _CDROM_AUDIO_CONTROL { - UCHAR LbaFormat; - USHORT LogicalBlocksPerSecond; -} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL; -#else -#if PRAGMA_DEPRECATED_DDK -#define _CDROM_AUDIO_CONTROL _this_is_obsoleted__CDROM_AUDIO_CONTROL -#define CDROM_AUDIO_CONTROL _this_is_obsoleted_CDROM_AUDIO_CONTROL -#define PCDROM_AUDIO_CONTROL _this_is_obsoleted_PCDROM_AUDIO_CONTROL -#endif // PRAGMA_DEPRECATED_DDK -#endif - -// -// Volume control - Volume takes a value between 1 and 0xFF. -// SCSI-II CDROM audio suppports up to 4 audio ports with -// Independent volume control. -// - -typedef struct _VOLUME_CONTROL { - UCHAR PortVolume[4]; -} VOLUME_CONTROL, *PVOLUME_CONTROL; - -typedef enum _TRACK_MODE_TYPE { - YellowMode2, - XAForm2, - CDDA, - RawWithC2AndSubCode, // CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE per sector - RawWithC2, // CD_RAW_SECTOR_WITH_C2_SIZE per sector - RawWithSubCode // CD_RAW_SECTOR_WITH_SUBCODE_SIZE per sector -} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; - -#define CD_RAW_READ_C2_SIZE ( 296 ) -#define CD_RAW_READ_SUBCODE_SIZE ( 96) -#define CD_RAW_SECTOR_WITH_C2_SIZE (2352+296 ) -#define CD_RAW_SECTOR_WITH_SUBCODE_SIZE (2352 +96) -#define CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE (2352+296+96) - -// -// Passed to cdrom to describe the raw read, ie. Mode 2, Form 2, CDDA... -// - -typedef struct __RAW_READ_INFO { - LARGE_INTEGER DiskOffset; - ULONG SectorCount; - TRACK_MODE_TYPE TrackMode; -} RAW_READ_INFO, *PRAW_READ_INFO; - -typedef enum _MEDIA_BLANK_TYPE { - MediaBlankTypeFull = 0, // mandatory support - MediaBlankTypeMinimal = 1, // mandatory support - MediaBlankTypeIncompleteTrack = 2, // optional support - MediaBlankTypeUnreserveLastTrack = 3, // optional support, hairy - MediaBlankTypeTrackTail = 4, // mandatory support - MediaBlankTypeUncloseLastSession = 5, // optional support - MediaBlankTypeEraseLastSession = 6, // optional support - // MediaBlankType7 is reserved -} MEDIA_BLANK_TYPE, *PMEDIA_BLANK_TYPE; - -// -// IOCTL_CDROM_EXCLUSIVE_ACCESS can be used to get exclusive -// access to the CDROM device. -// - -#define CDROM_EXCLUSIVE_CALLER_LENGTH 64 - -// -// Input values (Flags) for ExclusiveAccessLockDevice -// -// CDROM_LOCK_IGNORE_VOLUME: -// Set it to lock the device even if the file system is mounted. -// WARNING: setting this may cause data corruption! -// -// CDROM_NO_MEDIA_NOTIFICATIONS: -// Set it to prevent sending of a media removal notification -// on exclusive access lock and a media arrival notification -// on unlock. -// - -#define CDROM_LOCK_IGNORE_VOLUME (1 << 0) -#define CDROM_NO_MEDIA_NOTIFICATIONS (1 << 1) - -// -// Output values (Flags) for ExclusiveAccessQueryState -// - -#define CDROM_NOT_IN_EXCLUSIVE_MODE 0 -#define CDROM_IN_EXCLUSIVE_MODE 1 - - -typedef enum _EXCLUSIVE_ACCESS_REQUEST_TYPE { - ExclusiveAccessQueryState, - ExclusiveAccessLockDevice, - ExclusiveAccessUnlockDevice -} EXCLUSIVE_ACCESS_REQUEST_TYPE, *PEXCLUSIVE_ACCESS_REQUEST_TYPE; - - -typedef struct _CDROM_EXCLUSIVE_ACCESS { - - // - // Request type - // - EXCLUSIVE_ACCESS_REQUEST_TYPE RequestType; - - // - // Additional parameters for each request type - // - ULONG Flags; - -} CDROM_EXCLUSIVE_ACCESS, *PCDROM_EXCLUSIVE_ACCESS; - - -typedef struct _CDROM_EXCLUSIVE_LOCK { - - CDROM_EXCLUSIVE_ACCESS Access; - - // - // Caller name string - // - UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; - -} CDROM_EXCLUSIVE_LOCK, *PCDROM_EXCLUSIVE_LOCK; - - -typedef struct _CDROM_EXCLUSIVE_LOCK_STATE { - - BOOLEAN LockState; - - // - // Caller name string - // - UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; - -} CDROM_EXCLUSIVE_LOCK_STATE, *PCDROM_EXCLUSIVE_LOCK_STATE; - -// -// Structure definitions for IOCTL_CDROM_SET_SPEED -// - -typedef enum _CDROM_SPEED_REQUEST { - CdromSetSpeed, - CdromSetStreaming -} CDROM_SPEED_REQUEST, *PCDROM_SPEED_REQUEST; - -typedef enum _WRITE_ROTATION { - CdromDefaultRotation, - CdromCAVRotation -} WRITE_ROTATION, *PWRITE_ROTATION; - -typedef struct _CDROM_SET_SPEED { - - // - // Request type for setting speed - // - CDROM_SPEED_REQUEST RequestType; - - // - // Drive read speed in KB/sec. - // - USHORT ReadSpeed; - - // - // Drive write speed in KB/sec. - // - USHORT WriteSpeed; - - // - // Drive rotation control for write - // - WRITE_ROTATION RotationControl; - -} CDROM_SET_SPEED, *PCDROM_SET_SPEED; - -typedef struct _CDROM_SET_STREAMING { - - // - // Request type for setting speed - // - CDROM_SPEED_REQUEST RequestType; - - // - // Drive read size in KB per ReadTime - // - ULONG ReadSize; - - // - // Read time in milliseconds - // - ULONG ReadTime; - - // - // Drive write size in KB per WriteTime - // - ULONG WriteSize; - - // - // Write time in milliseconds - // - ULONG WriteTime; - - // - // First Logical Block Address of the request - // - ULONG StartLba; - - // - // Last Logical Block Address of the request - // - ULONG EndLba; - - // - // Drive rotation control for write - // - WRITE_ROTATION RotationControl; - - // - // Restore drive defaults - // - BOOLEAN RestoreDefaults; - - // - // Set drive to exact value given - // - BOOLEAN SetExact; - - // - // Optimize performance for random changes - // - BOOLEAN RandomAccess; - - // - // Restore default speed on media change - // - BOOLEAN Persistent; - -} CDROM_SET_STREAMING, *PCDROM_SET_STREAMING; - - -// -// Structure definitions for IOCTL_CDROM_ENABLE_STREAMING -// - -typedef enum _STREAMING_CONTROL_REQUEST_TYPE { - CdromStreamingDisable = 1, - CdromStreamingEnableForReadOnly = 2, - CdromStreamingEnableForWriteOnly = 3, - CdromStreamingEnableForReadWrite = 4 -} STREAMING_CONTROL_REQUEST_TYPE, *PSTREAMING_CONTROL_REQUEST_TYPE; - -typedef struct _CDROM_STREAMING_CONTROL { - - // - // Request type - // - STREAMING_CONTROL_REQUEST_TYPE RequestType; - -} CDROM_STREAMING_CONTROL, *PCDROM_STREAMING_CONTROL; - - -// -// Structure definitions for IOCTL_CDROM_SEND_OPC_INFORMATION -// - -typedef enum _CDROM_OPC_INFO_TYPE { - SimpleOpcInfo = 1 -} CDROM_OPC_INFO_TYPE, *PCDROM_OPC_INFO_TYPE; - -typedef struct _CDROM_SIMPLE_OPC_INFO { - - // - // Request type (must be SimpleOpcInfo) - // - CDROM_OPC_INFO_TYPE RequestType; - - // - // Exclude Layer 0 from OPC - // - BOOLEAN Exclude0; - - // - // Exclude Layer 1 from OPC - // - BOOLEAN Exclude1; - -} CDROM_SIMPLE_OPC_INFO, *PCDROM_SIMPLE_OPC_INFO; - - -// -// Structure definitions for IOCTL_CDROM_GET_PERFORMANCE -// - -typedef enum _CDROM_PERFORMANCE_REQUEST_TYPE { - CdromPerformanceRequest = 1, - CdromWriteSpeedRequest = 2 -} CDROM_PERFORMANCE_REQUEST_TYPE, *PCDROM_PERFORMANCE_REQUEST_TYPE; - -typedef enum _CDROM_PERFORMANCE_TYPE { - CdromReadPerformance = 1, - CdromWritePerformance = 2 -} CDROM_PERFORMANCE_TYPE, *PCDROM_PERFORMANCE_TYPE; - -typedef enum _CDROM_PERFORMANCE_EXCEPTION_TYPE { - CdromNominalPerformance = 1, - CdromEntirePerformanceList = 2, - CdromPerformanceExceptionsOnly = 3 -} CDROM_PERFORMANCE_EXCEPTION_TYPE, *PCDROM_PERFORMANCE_EXCEPTION_TYPE; - -typedef enum _CDROM_PERFORMANCE_TOLERANCE_TYPE { - Cdrom10Nominal20Exceptions = 1 -} CDROM_PERFORMANCE_TOLERANCE_TYPE, *PCDROM_PERFORMANCE_TOLERANCE_TYPE; - -typedef struct _CDROM_PERFORMANCE_REQUEST { - - // - // Request type (must be CdromPerformanceRequest) - // - CDROM_PERFORMANCE_REQUEST_TYPE RequestType; - - // - // Performance type - // - CDROM_PERFORMANCE_TYPE PerformanceType; - - // - // Exceptions to be covered - // - CDROM_PERFORMANCE_EXCEPTION_TYPE Exceptions; - - // - // Tolerance to be ensured - // - CDROM_PERFORMANCE_TOLERANCE_TYPE Tolerance; - - // - // Starting LBA for entire performance list - // - ULONG StaringLba; - -} CDROM_PERFORMANCE_REQUEST, *PCDROM_PERFORMANCE_REQUEST; - -typedef struct _CDROM_WRITE_SPEED_REQUEST { - - // - // Request type (must be CdromWriteSpeedRequest) - // - CDROM_PERFORMANCE_REQUEST_TYPE RequestType; - -} CDROM_WRITE_SPEED_REQUEST, *PCDROM_WRITE_SPEED_REQUEST; - -// Header for data returned by IOCTL_CDROM_GET_PERFORMANCE -typedef struct _CDROM_PERFORMANCE_HEADER { - - // - // Size of available data (vs returned data), not including this field - // - UCHAR DataLength[4]; - - UCHAR Except : 1; - UCHAR Write : 1; - UCHAR Reserved1 : 6; - UCHAR Reserved2[3]; - - // - // Contains a list of the following records (depending on the request): - // CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR, - // CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR, - // CDROM_WRITE_SPEED_DESCRIPTOR - // - UCHAR Data[0]; - -} CDROM_PERFORMANCE_HEADER, *PCDROM_PERFORMANCE_HEADER; - -typedef struct _CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR { - UCHAR StartLba[4]; - UCHAR StartPerformance[4]; - UCHAR EndLba[4]; - UCHAR EndPerformance[4]; -} CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR, *PCDROM_NOMINAL_PERFORMANCE_DESCRIPTOR; - -typedef struct _CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR { - UCHAR Lba[4]; - UCHAR Time[2]; -} CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR, *PCDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR; - -typedef struct _CDROM_WRITE_SPEED_DESCRIPTOR { - UCHAR MixedReadWrite : 1; - UCHAR Exact : 1; - UCHAR Reserved1 : 1; - UCHAR WriteRotationControl : 2; - UCHAR Reserved2 : 3; - UCHAR Reserved3[3]; - UCHAR EndLba[4]; - UCHAR ReadSpeed[4]; - UCHAR WriteSpeed[4]; -} CDROM_WRITE_SPEED_DESCRIPTOR, *PCDROM_WRITE_SPEED_DESCRIPTOR; - - -#ifdef __cplusplus -} -#endif - - -#if _MSC_VER >= 1200 -#pragma warning(pop) // un-sets any local warning changes -#else -#pragma warning(default:4200) // array[0] is not a warning for this file -#pragma warning(default:4201) // nameless struct/unions -#pragma warning(default:4214) // bit fields other than int -#endif - - -#ifdef __cplusplus -} -#endif - -#endif // _NTDDCDRM_ - -// end_winioctl - - +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddcdrm.h + +Abstract: + + This module contains structures and definitions + associated with CDROM IOCTls. + + +--*/ + +// begin_winioctl + +#ifndef _NTDDCDRM_ +#define _NTDDCDRM_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif + +#if _MSC_VER > 1000 +#pragma once +#endif + +// +// remove some level 4 warnings for this header file: +#pragma warning(disable:4200) // array[0] +#pragma warning(disable:4201) // nameless struct/unions +#pragma warning(disable:4214) // bit fields other than int +#if defined(__INTEL_COMPILER) +#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// + +#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM + +#define IOCTL_CDROM_UNLOAD_DRIVER CTL_CODE(IOCTL_CDROM_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// CDROM Audio Device Control Functions +// + +#define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_STOP_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_PAUSE_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RESUME_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_PLAY_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) +#if (NTDDI_VERSION < NTDDI_WS03) +#define IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) +#else +#define OBSOLETE_IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) +#endif +#define IOCTL_CDROM_GET_LAST_SESSION CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) +#define IOCTL_CDROM_DISK_TYPE CTL_CODE(IOCTL_CDROM_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0014, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_READ_TOC_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_CONFIGURATION CTL_CODE(IOCTL_CDROM_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_EXCLUSIVE_ACCESS CTL_CODE(IOCTL_CDROM_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_CDROM_SET_SPEED CTL_CODE(IOCTL_CDROM_BASE, 0x0018, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_INQUIRY_DATA CTL_CODE(IOCTL_CDROM_BASE, 0x0019, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_ENABLE_STREAMING CTL_CODE(IOCTL_CDROM_BASE, 0x001A, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SEND_OPC_INFORMATION CTL_CODE(IOCTL_CDROM_BASE, 0x001B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_CDROM_GET_PERFORMANCE CTL_CODE(IOCTL_CDROM_BASE, 0x001C, METHOD_BUFFERED, FILE_READ_ACCESS) + +// end_winioctl + +// +// The following device control codes are common for all class drivers. The +// functions codes defined here must match all of the other class drivers. +// +// Warning: these codes will be replaced in the future with the IOCTL_STORAGE +// codes included below +// + +#define IOCTL_CDROM_CHECK_VERIFY CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_EJECT_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_LOAD_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RESERVE CTL_CODE(IOCTL_CDROM_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RELEASE CTL_CODE(IOCTL_CDROM_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_FIND_NEW_DEVICES CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// The following file contains the IOCTL_STORAGE class ioctl definitions +// + +#include "ntddstor.h" + +// begin_winioctl + + +#define MINIMUM_CDROM_INQUIRY_SIZE 36 // RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) +#define MAXIMUM_CDROM_INQUIRY_SIZE 260 // MAXUCHAR + RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength) + +// +// The following device control code is for the SIMBAD simulated bad +// sector facility. See SIMBAD.H in this directory for related structures. +// + +#define IOCTL_CDROM_SIMBAD CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// Maximum CD Rom size +// + +#define MAXIMUM_NUMBER_TRACKS 100 +#define MAXIMUM_CDROM_SIZE 804 +#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2 // two bytes min transferred + +// +// READ_TOC_EX structure +// +typedef struct _CDROM_READ_TOC_EX { + UCHAR Format : 4; + UCHAR Reserved1 : 3; // future expansion + UCHAR Msf : 1; + UCHAR SessionTrack; + UCHAR Reserved2; // future expansion + UCHAR Reserved3; // future expansion +} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX; + +#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00 +#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01 +#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02 +#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03 +#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04 +#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05 + +// +// CD ROM Table OF Contents (TOC) +// Format 0 - Get table of contents +// + +typedef struct _TRACK_DATA { + UCHAR Reserved; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR TrackNumber; + UCHAR Reserved1; + UCHAR Address[4]; +} TRACK_DATA, *PTRACK_DATA; + +typedef struct _CDROM_TOC { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstTrack; + UCHAR LastTrack; + + // + // Track data + // + + TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; +} CDROM_TOC, *PCDROM_TOC; + +#define CDROM_TOC_SIZE sizeof(CDROM_TOC) + +// +// CD ROM Table OF Contents +// Format 1 - Session Information +// + +typedef struct _CDROM_TOC_SESSION_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstCompleteSession; + UCHAR LastCompleteSession; + + // + // One track, representing the first track + // of the last finished session + // + + TRACK_DATA TrackData[1]; + +} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA; + + +// +// CD ROM Table OF Contents +// Format 2 - Full TOC +// + +typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK { + UCHAR SessionNumber; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR Reserved1; + UCHAR Point; + UCHAR MsfExtra[3]; + UCHAR Zero; + UCHAR Msf[3]; +} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK; + +typedef struct _CDROM_TOC_FULL_TOC_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstCompleteSession; + UCHAR LastCompleteSession; + + // + // one to N descriptors included + // + +#if !defined(__midl) + CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; +#endif + +} CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA; + +// +// CD ROM Table OF Contents +// Format 3 - Program Memory Area +// +typedef struct _CDROM_TOC_PMA_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // one to N descriptors included + // + +#if !defined(__midl) + CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; +#endif + +} CDROM_TOC_PMA_DATA, *PCDROM_TOC_PMA_DATA; + +// +// CD ROM Table OF Contents +// Format 4 - Absolute Time In Pregroove +// + +typedef struct _CDROM_TOC_ATIP_DATA_BLOCK { + + UCHAR CdrwReferenceSpeed : 3; + UCHAR Reserved3 : 1; + UCHAR WritePower : 3; + UCHAR True1 : 1; + UCHAR Reserved4 : 6; + UCHAR UnrestrictedUse : 1; + UCHAR Reserved5 : 1; + UCHAR A3Valid : 1; + UCHAR A2Valid : 1; + UCHAR A1Valid : 1; + UCHAR DiscSubType : 3; + UCHAR IsCdrw : 1; + UCHAR True2 : 1; + UCHAR Reserved7; + + UCHAR LeadInMsf[3]; + UCHAR Reserved8; + + UCHAR LeadOutMsf[3]; + UCHAR Reserved9; + + UCHAR A1Values[3]; + UCHAR Reserved10; + + UCHAR A2Values[3]; + UCHAR Reserved11; + + UCHAR A3Values[3]; + UCHAR Reserved12; + +} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK; + +typedef struct _CDROM_TOC_ATIP_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // zero? to N descriptors included. + // + +#if !defined(__midl) + CDROM_TOC_ATIP_DATA_BLOCK Descriptors[0]; +#endif + +} CDROM_TOC_ATIP_DATA, *PCDROM_TOC_ATIP_DATA; + +// +// CD ROM Table OF Contents +// Format 5 - CD Text Info +// +typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK { + UCHAR PackType; + UCHAR TrackNumber : 7; + UCHAR ExtensionFlag : 1; // should be zero! + UCHAR SequenceNumber; + UCHAR CharacterPosition : 4; + UCHAR BlockNumber : 3; + UCHAR Unicode : 1; + union { + UCHAR Text[12]; + WCHAR WText[6]; + }; + UCHAR CRC[2]; +} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK; + +typedef struct _CDROM_TOC_CD_TEXT_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // the text info comes in discrete blocks of + // a heavily-overloaded structure + // + +#if !defined(__midl) + CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0]; +#endif + +} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA; + +// +// These are the types used for PackType field in CDROM_TOC_CD_TEXT_DATA_BLOCK +// and also for requesting specific info from IOCTL_CDROM_READ_CD_TEXT +// +#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80 +#define CDROM_CD_TEXT_PACK_PERFORMER 0x81 +#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82 +#define CDROM_CD_TEXT_PACK_COMPOSER 0x83 +#define CDROM_CD_TEXT_PACK_ARRANGER 0x84 +#define CDROM_CD_TEXT_PACK_MESSAGES 0x85 +#define CDROM_CD_TEXT_PACK_DISC_ID 0x86 +#define CDROM_CD_TEXT_PACK_GENRE 0x87 +#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88 +#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89 +// 0x8a - 0x8d are reserved.... +#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e +#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f + +// +// Play audio starting at MSF and ending at MSF +// + +typedef struct _CDROM_PLAY_AUDIO_MSF { + UCHAR StartingM; + UCHAR StartingS; + UCHAR StartingF; + UCHAR EndingM; + UCHAR EndingS; + UCHAR EndingF; +} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF; + +// +// Seek to MSF +// + +typedef struct _CDROM_SEEK_AUDIO_MSF { + UCHAR M; + UCHAR S; + UCHAR F; +} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; + + +// +// Flags for the disk type +// + +typedef struct _CDROM_DISK_DATA { + + ULONG DiskData; + +} CDROM_DISK_DATA, *PCDROM_DISK_DATA; + +#define CDROM_DISK_AUDIO_TRACK (0x00000001) +#define CDROM_DISK_DATA_TRACK (0x00000002) + +// +// CD ROM Data Mode Codes, used with IOCTL_CDROM_READ_Q_CHANNEL +// + +#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 +#define IOCTL_CDROM_CURRENT_POSITION 0x01 +#define IOCTL_CDROM_MEDIA_CATALOG 0x02 +#define IOCTL_CDROM_TRACK_ISRC 0x03 + +typedef struct _CDROM_SUB_Q_DATA_FORMAT { + UCHAR Format; + UCHAR Track; +} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; + + +// +// CD ROM Sub-Q Channel Data Format +// + +typedef struct _SUB_Q_HEADER { + UCHAR Reserved; + UCHAR AudioStatus; + UCHAR DataLength[2]; +} SUB_Q_HEADER, *PSUB_Q_HEADER; + +typedef struct _SUB_Q_CURRENT_POSITION { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Control : 4; + UCHAR ADR : 4; + UCHAR TrackNumber; + UCHAR IndexNumber; + UCHAR AbsoluteAddress[4]; + UCHAR TrackRelativeAddress[4]; +} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; + +typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved[3]; + UCHAR Reserved1 : 7; + UCHAR Mcval : 1; + UCHAR MediaCatalog[15]; +} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; + +typedef struct _SUB_Q_TRACK_ISRC { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved0; + UCHAR Track; + UCHAR Reserved1; + UCHAR Reserved2 : 7; + UCHAR Tcval : 1; + UCHAR TrackIsrc[15]; +} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; + +typedef union _SUB_Q_CHANNEL_DATA { + SUB_Q_CURRENT_POSITION CurrentPosition; + SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; + SUB_Q_TRACK_ISRC TrackIsrc; +} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; + +// +// Audio Status Codes +// + +#define AUDIO_STATUS_NOT_SUPPORTED 0x00 +#define AUDIO_STATUS_IN_PROGRESS 0x11 +#define AUDIO_STATUS_PAUSED 0x12 +#define AUDIO_STATUS_PLAY_COMPLETE 0x13 +#define AUDIO_STATUS_PLAY_ERROR 0x14 +#define AUDIO_STATUS_NO_STATUS 0x15 + +// +// ADR Sub-channel Q Field +// + +#define ADR_NO_MODE_INFORMATION 0x0 +#define ADR_ENCODES_CURRENT_POSITION 0x1 +#define ADR_ENCODES_MEDIA_CATALOG 0x2 +#define ADR_ENCODES_ISRC 0x3 + +// +// Sub-channel Q Control Bits +// + +#define AUDIO_WITH_PREEMPHASIS 0x1 +#define DIGITAL_COPY_PERMITTED 0x2 +#define AUDIO_DATA_TRACK 0x4 +#define TWO_FOUR_CHANNEL_AUDIO 0x8 + +#if (NTDDI_VERSION < NTDDI_WS03) +typedef struct _CDROM_AUDIO_CONTROL { + UCHAR LbaFormat; + USHORT LogicalBlocksPerSecond; +} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL; +#else +#if PRAGMA_DEPRECATED_DDK +#define _CDROM_AUDIO_CONTROL _this_is_obsoleted__CDROM_AUDIO_CONTROL +#define CDROM_AUDIO_CONTROL _this_is_obsoleted_CDROM_AUDIO_CONTROL +#define PCDROM_AUDIO_CONTROL _this_is_obsoleted_PCDROM_AUDIO_CONTROL +#endif // PRAGMA_DEPRECATED_DDK +#endif + +// +// Volume control - Volume takes a value between 1 and 0xFF. +// SCSI-II CDROM audio suppports up to 4 audio ports with +// Independent volume control. +// + +typedef struct _VOLUME_CONTROL { + UCHAR PortVolume[4]; +} VOLUME_CONTROL, *PVOLUME_CONTROL; + +typedef enum _TRACK_MODE_TYPE { + YellowMode2, + XAForm2, + CDDA, + RawWithC2AndSubCode, // CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE per sector + RawWithC2, // CD_RAW_SECTOR_WITH_C2_SIZE per sector + RawWithSubCode // CD_RAW_SECTOR_WITH_SUBCODE_SIZE per sector +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; + +#define CD_RAW_READ_C2_SIZE ( 296 ) +#define CD_RAW_READ_SUBCODE_SIZE ( 96) +#define CD_RAW_SECTOR_WITH_C2_SIZE (2352+296 ) +#define CD_RAW_SECTOR_WITH_SUBCODE_SIZE (2352 +96) +#define CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE (2352+296+96) + +// +// Passed to cdrom to describe the raw read, ie. Mode 2, Form 2, CDDA... +// + +typedef struct __RAW_READ_INFO { + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +typedef enum _MEDIA_BLANK_TYPE { + MediaBlankTypeFull = 0, // mandatory support + MediaBlankTypeMinimal = 1, // mandatory support + MediaBlankTypeIncompleteTrack = 2, // optional support + MediaBlankTypeUnreserveLastTrack = 3, // optional support, hairy + MediaBlankTypeTrackTail = 4, // mandatory support + MediaBlankTypeUncloseLastSession = 5, // optional support + MediaBlankTypeEraseLastSession = 6, // optional support + // MediaBlankType7 is reserved +} MEDIA_BLANK_TYPE, *PMEDIA_BLANK_TYPE; + +// +// IOCTL_CDROM_EXCLUSIVE_ACCESS can be used to get exclusive +// access to the CDROM device. +// + +#define CDROM_EXCLUSIVE_CALLER_LENGTH 64 + +// +// Input values (Flags) for ExclusiveAccessLockDevice +// +// CDROM_LOCK_IGNORE_VOLUME: +// Set it to lock the device even if the file system is mounted. +// WARNING: setting this may cause data corruption! +// +// CDROM_NO_MEDIA_NOTIFICATIONS: +// Set it to prevent sending of a media removal notification +// on exclusive access lock and a media arrival notification +// on unlock. +// + +#define CDROM_LOCK_IGNORE_VOLUME (1 << 0) +#define CDROM_NO_MEDIA_NOTIFICATIONS (1 << 1) + +// +// Output values (Flags) for ExclusiveAccessQueryState +// + +#define CDROM_NOT_IN_EXCLUSIVE_MODE 0 +#define CDROM_IN_EXCLUSIVE_MODE 1 + + +typedef enum _EXCLUSIVE_ACCESS_REQUEST_TYPE { + ExclusiveAccessQueryState, + ExclusiveAccessLockDevice, + ExclusiveAccessUnlockDevice +} EXCLUSIVE_ACCESS_REQUEST_TYPE, *PEXCLUSIVE_ACCESS_REQUEST_TYPE; + + +typedef struct _CDROM_EXCLUSIVE_ACCESS { + + // + // Request type + // + EXCLUSIVE_ACCESS_REQUEST_TYPE RequestType; + + // + // Additional parameters for each request type + // + ULONG Flags; + +} CDROM_EXCLUSIVE_ACCESS, *PCDROM_EXCLUSIVE_ACCESS; + + +typedef struct _CDROM_EXCLUSIVE_LOCK { + + CDROM_EXCLUSIVE_ACCESS Access; + + // + // Caller name string + // + UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; + +} CDROM_EXCLUSIVE_LOCK, *PCDROM_EXCLUSIVE_LOCK; + + +typedef struct _CDROM_EXCLUSIVE_LOCK_STATE { + + BOOLEAN LockState; + + // + // Caller name string + // + UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; + +} CDROM_EXCLUSIVE_LOCK_STATE, *PCDROM_EXCLUSIVE_LOCK_STATE; + +// +// Structure definitions for IOCTL_CDROM_SET_SPEED +// + +typedef enum _CDROM_SPEED_REQUEST { + CdromSetSpeed, + CdromSetStreaming +} CDROM_SPEED_REQUEST, *PCDROM_SPEED_REQUEST; + +typedef enum _WRITE_ROTATION { + CdromDefaultRotation, + CdromCAVRotation +} WRITE_ROTATION, *PWRITE_ROTATION; + +typedef struct _CDROM_SET_SPEED { + + // + // Request type for setting speed + // + CDROM_SPEED_REQUEST RequestType; + + // + // Drive read speed in KB/sec. + // + USHORT ReadSpeed; + + // + // Drive write speed in KB/sec. + // + USHORT WriteSpeed; + + // + // Drive rotation control for write + // + WRITE_ROTATION RotationControl; + +} CDROM_SET_SPEED, *PCDROM_SET_SPEED; + +typedef struct _CDROM_SET_STREAMING { + + // + // Request type for setting speed + // + CDROM_SPEED_REQUEST RequestType; + + // + // Drive read size in KB per ReadTime + // + ULONG ReadSize; + + // + // Read time in milliseconds + // + ULONG ReadTime; + + // + // Drive write size in KB per WriteTime + // + ULONG WriteSize; + + // + // Write time in milliseconds + // + ULONG WriteTime; + + // + // First Logical Block Address of the request + // + ULONG StartLba; + + // + // Last Logical Block Address of the request + // + ULONG EndLba; + + // + // Drive rotation control for write + // + WRITE_ROTATION RotationControl; + + // + // Restore drive defaults + // + BOOLEAN RestoreDefaults; + + // + // Set drive to exact value given + // + BOOLEAN SetExact; + + // + // Optimize performance for random changes + // + BOOLEAN RandomAccess; + + // + // Restore default speed on media change + // + BOOLEAN Persistent; + +} CDROM_SET_STREAMING, *PCDROM_SET_STREAMING; + + +// +// Structure definitions for IOCTL_CDROM_ENABLE_STREAMING +// + +typedef enum _STREAMING_CONTROL_REQUEST_TYPE { + CdromStreamingDisable = 1, + CdromStreamingEnableForReadOnly = 2, + CdromStreamingEnableForWriteOnly = 3, + CdromStreamingEnableForReadWrite = 4 +} STREAMING_CONTROL_REQUEST_TYPE, *PSTREAMING_CONTROL_REQUEST_TYPE; + +typedef struct _CDROM_STREAMING_CONTROL { + + // + // Request type + // + STREAMING_CONTROL_REQUEST_TYPE RequestType; + +} CDROM_STREAMING_CONTROL, *PCDROM_STREAMING_CONTROL; + + +// +// Structure definitions for IOCTL_CDROM_SEND_OPC_INFORMATION +// + +typedef enum _CDROM_OPC_INFO_TYPE { + SimpleOpcInfo = 1 +} CDROM_OPC_INFO_TYPE, *PCDROM_OPC_INFO_TYPE; + +typedef struct _CDROM_SIMPLE_OPC_INFO { + + // + // Request type (must be SimpleOpcInfo) + // + CDROM_OPC_INFO_TYPE RequestType; + + // + // Exclude Layer 0 from OPC + // + BOOLEAN Exclude0; + + // + // Exclude Layer 1 from OPC + // + BOOLEAN Exclude1; + +} CDROM_SIMPLE_OPC_INFO, *PCDROM_SIMPLE_OPC_INFO; + + +// +// Structure definitions for IOCTL_CDROM_GET_PERFORMANCE +// + +typedef enum _CDROM_PERFORMANCE_REQUEST_TYPE { + CdromPerformanceRequest = 1, + CdromWriteSpeedRequest = 2 +} CDROM_PERFORMANCE_REQUEST_TYPE, *PCDROM_PERFORMANCE_REQUEST_TYPE; + +typedef enum _CDROM_PERFORMANCE_TYPE { + CdromReadPerformance = 1, + CdromWritePerformance = 2 +} CDROM_PERFORMANCE_TYPE, *PCDROM_PERFORMANCE_TYPE; + +typedef enum _CDROM_PERFORMANCE_EXCEPTION_TYPE { + CdromNominalPerformance = 1, + CdromEntirePerformanceList = 2, + CdromPerformanceExceptionsOnly = 3 +} CDROM_PERFORMANCE_EXCEPTION_TYPE, *PCDROM_PERFORMANCE_EXCEPTION_TYPE; + +typedef enum _CDROM_PERFORMANCE_TOLERANCE_TYPE { + Cdrom10Nominal20Exceptions = 1 +} CDROM_PERFORMANCE_TOLERANCE_TYPE, *PCDROM_PERFORMANCE_TOLERANCE_TYPE; + +typedef struct _CDROM_PERFORMANCE_REQUEST { + + // + // Request type (must be CdromPerformanceRequest) + // + CDROM_PERFORMANCE_REQUEST_TYPE RequestType; + + // + // Performance type + // + CDROM_PERFORMANCE_TYPE PerformanceType; + + // + // Exceptions to be covered + // + CDROM_PERFORMANCE_EXCEPTION_TYPE Exceptions; + + // + // Tolerance to be ensured + // + CDROM_PERFORMANCE_TOLERANCE_TYPE Tolerance; + + // + // Starting LBA for entire performance list + // + ULONG StaringLba; + +} CDROM_PERFORMANCE_REQUEST, *PCDROM_PERFORMANCE_REQUEST; + +typedef struct _CDROM_WRITE_SPEED_REQUEST { + + // + // Request type (must be CdromWriteSpeedRequest) + // + CDROM_PERFORMANCE_REQUEST_TYPE RequestType; + +} CDROM_WRITE_SPEED_REQUEST, *PCDROM_WRITE_SPEED_REQUEST; + +// Header for data returned by IOCTL_CDROM_GET_PERFORMANCE +typedef struct _CDROM_PERFORMANCE_HEADER { + + // + // Size of available data (vs returned data), not including this field + // + UCHAR DataLength[4]; + + UCHAR Except : 1; + UCHAR Write : 1; + UCHAR Reserved1 : 6; + UCHAR Reserved2[3]; + + // + // Contains a list of the following records (depending on the request): + // CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR, + // CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR, + // CDROM_WRITE_SPEED_DESCRIPTOR + // + UCHAR Data[0]; + +} CDROM_PERFORMANCE_HEADER, *PCDROM_PERFORMANCE_HEADER; + +typedef struct _CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR { + UCHAR StartLba[4]; + UCHAR StartPerformance[4]; + UCHAR EndLba[4]; + UCHAR EndPerformance[4]; +} CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR, *PCDROM_NOMINAL_PERFORMANCE_DESCRIPTOR; + +typedef struct _CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR { + UCHAR Lba[4]; + UCHAR Time[2]; +} CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR, *PCDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR; + +typedef struct _CDROM_WRITE_SPEED_DESCRIPTOR { + UCHAR MixedReadWrite : 1; + UCHAR Exact : 1; + UCHAR Reserved1 : 1; + UCHAR WriteRotationControl : 2; + UCHAR Reserved2 : 3; + UCHAR Reserved3[3]; + UCHAR EndLba[4]; + UCHAR ReadSpeed[4]; + UCHAR WriteSpeed[4]; +} CDROM_WRITE_SPEED_DESCRIPTOR, *PCDROM_WRITE_SPEED_DESCRIPTOR; + + +#ifdef __cplusplus +} +#endif + + +#if _MSC_VER >= 1200 +#pragma warning(pop) // un-sets any local warning changes +#else +#pragma warning(default:4200) // array[0] is not a warning for this file +#pragma warning(default:4201) // nameless struct/unions +#pragma warning(default:4214) // bit fields other than int +#endif + + +#ifdef __cplusplus +} +#endif + +#endif // _NTDDCDRM_ + +// end_winioctl + + diff --git a/include/winddk/ntddcdvd.h b/include/winddk/ntddcdvd.h index b4ded0888e1..c2baf1664e9 100644 --- a/include/winddk/ntddcdvd.h +++ b/include/winddk/ntddcdvd.h @@ -1,796 +1,796 @@ -/*++ BUILD Version: 0001 // Increment this if a change has global effects - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - ntddcdvd.h - -Abstract: - - This module contains structures and definitions - associated with DVD ioctls. - - This module is used in conjunction with ntddcdrm.h which contains the - cdrom specific ioctls which will work on CDVD drives - - ---*/ - -// begin_winioctl - -#ifndef _NTDDCDVD_ -#define _NTDDCDVD_ -#pragma warning(push) -#pragma warning(disable:4200) // zero-sized array -#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union -#pragma warning(disable:4214) // bitfield other than int -#if defined(__INTEL_COMPILER) -#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero -#endif - -#if _MSC_VER > 1000 -#pragma once -#endif - -// -// NtDeviceIoControlFile IoControlCode values for this device. -// -// Warning: Remember that the low two bits of the code specify how the -// buffers are passed to the driver! -// - -#define IOCTL_DVD_BASE FILE_DEVICE_DVD - -// -// CDVD Device Control Functions -// -// Warning: Ioctls from 200 through 300 are used for the old common class -// driver ioctls and should not be used for device specific functionality -// - -// -// CSS-related IOCTLs -// - -#define IOCTL_DVD_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_READ_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_SEND_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0403, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_SET_READ_AHEAD CTL_CODE(IOCTL_DVD_BASE, 0x0404, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_GET_REGION CTL_CODE(IOCTL_DVD_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_SEND_KEY2 CTL_CODE(IOCTL_DVD_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// AACS-related IOCTLs -// -#define IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE CTL_CODE(IOCTL_DVD_BASE, 0x430, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_MEDIA_KEY_BLOCK CTL_CODE(IOCTL_DVD_BASE, 0x431, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x432, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x433, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_SEND_CERTIFICATE CTL_CODE(IOCTL_DVD_BASE, 0x434, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_GET_CERTIFICATE CTL_CODE(IOCTL_DVD_BASE, 0x435, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_GET_CHALLENGE_KEY CTL_CODE(IOCTL_DVD_BASE, 0x436, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_SEND_CHALLENGE_KEY CTL_CODE(IOCTL_DVD_BASE, 0x437, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_VOLUME_ID CTL_CODE(IOCTL_DVD_BASE, 0x438, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_SERIAL_NUMBER CTL_CODE(IOCTL_DVD_BASE, 0x439, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_MEDIA_ID CTL_CODE(IOCTL_DVD_BASE, 0x43A, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_BINDING_NONCE CTL_CODE(IOCTL_DVD_BASE, 0x43B, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_GENERATE_BINDING_NONCE CTL_CODE(IOCTL_DVD_BASE, 0x43C, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// DVD Structure queries -// - -#define IOCTL_DVD_READ_STRUCTURE CTL_CODE(IOCTL_DVD_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// The following file contains the IOCTL_STORAGE class ioctl definitions -// - -#define IOCTL_STORAGE_SET_READ_AHEAD CTL_CODE(IOCTL_STORAGE_BASE, 0x0100, METHOD_BUFFERED, FILE_READ_ACCESS) - -// end_winioctl - -#include "ntddstor.h" - -// begin_winioctl - - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef enum { - DvdChallengeKey = 0x01, - DvdBusKey1, - DvdBusKey2, - DvdTitleKey, - DvdAsf, - DvdSetRpcKey = 0x6, - DvdGetRpcKey = 0x8, - DvdDiskKey = 0x80, - DvdInvalidateAGID = 0x3f -} DVD_KEY_TYPE; - -typedef __typefix(LONG) __range(-1,3) ULONG DVD_SESSION_ID, *PDVD_SESSION_ID; - -#include -typedef struct _DVD_COPY_PROTECT_KEY { - ULONG KeyLength; - DVD_SESSION_ID SessionId; - DVD_KEY_TYPE KeyType; - ULONG KeyFlags; - union { - HANDLE FileHandle; - LARGE_INTEGER TitleOffset; - } Parameters; - UCHAR KeyData[0]; -} DVD_COPY_PROTECT_KEY, *PDVD_COPY_PROTECT_KEY; -#include - -// -// Predefined (Mt. Fuji) key sizes -// Add sizeof(DVD_COPY_PROTECT_KEY) to get allocation size for -// the full key structure -// - -#define DVD_CHALLENGE_KEY_LENGTH (12 + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_BUS_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_TITLE_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_DISK_KEY_LENGTH (2048 + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_RPC_KEY_LENGTH (sizeof(DVD_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_SET_RPC_KEY_LENGTH (sizeof(DVD_SET_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_ASF_LENGTH (sizeof(DVD_ASF) + sizeof(DVD_COPY_PROTECT_KEY)) - -// -// Used with IOCTL_DVD_END_SESSION to end all DVD sessions at once -// - -#define DVD_END_ALL_SESSIONS ((DVD_SESSION_ID) 0xffffffff) - -// -// CGMS Copy Protection Flags -// - -#define DVD_CGMS_RESERVED_MASK 0x00000078 - -#define DVD_CGMS_COPY_PROTECT_MASK 0x00000018 -#define DVD_CGMS_COPY_PERMITTED 0x00000000 -#define DVD_CGMS_COPY_ONCE 0x00000010 -#define DVD_CGMS_NO_COPY 0x00000018 - -#define DVD_COPYRIGHT_MASK 0x00000040 -#define DVD_NOT_COPYRIGHTED 0x00000000 -#define DVD_COPYRIGHTED 0x00000040 - -#define DVD_SECTOR_PROTECT_MASK 0x00000020 -#define DVD_SECTOR_NOT_PROTECTED 0x00000000 -#define DVD_SECTOR_PROTECTED 0x00000020 - -/*++ - -IOCTL_STORAGE_SET_READ_AHEAD - -Requests that the storage device skip to TargetAddress once it has run across -TriggerAddress during the course of it's read-ahead caching operations. - -Input: - - a STORAGE_SET_READ_AHEAD structure which contains: - * the trigger address - * the target address - -Output: - - none - ---*/ - -#include -typedef struct _STORAGE_SET_READ_AHEAD { - LARGE_INTEGER TriggerAddress; - LARGE_INTEGER TargetAddress; -} STORAGE_SET_READ_AHEAD, *PSTORAGE_SET_READ_AHEAD; -#include - -/*++ - -IOCTL_DVD_READ_STRUCTURE - -Issues a READ_DVD_STRUCTURE command to the drive. - -Input: - - a DVD_READ_STRUCTURE describing what information is requested - -Output: - - a DVD Layer Descriptor as defined below - ---*/ - -typedef enum DVD_STRUCTURE_FORMAT { - DvdPhysicalDescriptor, // 0x00 - DvdCopyrightDescriptor, // 0x01 - DvdDiskKeyDescriptor, // 0x02 - DvdBCADescriptor, // 0x03 - DvdManufacturerDescriptor, // 0x04 - DvdMaxDescriptor // 0x05 -} DVD_STRUCTURE_FORMAT, *PDVD_STRUCTURE_FORMAT; - -///////////////////////////////////////////////////////////// -// ALL THE FOLLOWING STRUCTURES ARE BYTE-PACKED: -#include - -typedef struct DVD_READ_STRUCTURE { - LARGE_INTEGER BlockByteOffset; - DVD_STRUCTURE_FORMAT Format; - DVD_SESSION_ID SessionId; - UCHAR LayerNumber; -} DVD_READ_STRUCTURE, *PDVD_READ_STRUCTURE; - -typedef struct _DVD_DESCRIPTOR_HEADER { - USHORT Length; - UCHAR Reserved[2]; -#if !defined(__midl) - UCHAR Data[0]; -#endif -} DVD_DESCRIPTOR_HEADER, *PDVD_DESCRIPTOR_HEADER; -C_ASSERT(sizeof(DVD_DESCRIPTOR_HEADER) == 4); - -// format 0x00 - DvdPhysicalDescriptor -typedef struct _DVD_LAYER_DESCRIPTOR { - UCHAR BookVersion : 4; // in MMC 5 : Part Version - UCHAR BookType : 4; // Disk Category - UCHAR MinimumRate : 4; // Maximum Rate - UCHAR DiskSize : 4; - UCHAR LayerType : 4; - UCHAR TrackPath : 1; - UCHAR NumberOfLayers : 2; - UCHAR Reserved1 : 1; - UCHAR TrackDensity : 4; - UCHAR LinearDensity : 4; - ULONG StartingDataSector; // 3bytes + 1 zeroed byte - ULONG EndDataSector; // 3bytes + 1 zeroed byte - ULONG EndLayerZeroSector; // 3bytes + 1 zeroed byte - UCHAR Reserved5 : 7; - UCHAR BCAFlag : 1; - // The large Media Specific field is not declared here to enable stack allocation -} DVD_LAYER_DESCRIPTOR, *PDVD_LAYER_DESCRIPTOR; -C_ASSERT(sizeof(DVD_LAYER_DESCRIPTOR) == 17); -typedef struct _DVD_FULL_LAYER_DESCRIPTOR { - DVD_LAYER_DESCRIPTOR commonHeader; - UCHAR MediaSpecific[2031]; -} DVD_FULL_LAYER_DESCRIPTOR, *PDVD_FULL_LAYER_DESCRIPTOR; -C_ASSERT(sizeof(DVD_FULL_LAYER_DESCRIPTOR) == 2048); - -// format 0x01 - DvdCopyrightDescriptor -typedef struct _DVD_COPYRIGHT_DESCRIPTOR { - UCHAR CopyrightProtectionType; - UCHAR RegionManagementInformation; - USHORT Reserved; -} DVD_COPYRIGHT_DESCRIPTOR, *PDVD_COPYRIGHT_DESCRIPTOR; -C_ASSERT(sizeof(DVD_COPYRIGHT_DESCRIPTOR) == 4); - -// format 0x02 - DvdDiskKeyDescriptor -typedef struct _DVD_DISK_KEY_DESCRIPTOR { - UCHAR DiskKeyData[2048]; -} DVD_DISK_KEY_DESCRIPTOR, *PDVD_DISK_KEY_DESCRIPTOR; -C_ASSERT(sizeof(DVD_DISK_KEY_DESCRIPTOR) == 2048); - -// format 0x03 - DvdBCADescriptor -typedef struct _DVD_BCA_DESCRIPTOR { - UCHAR BCAInformation[0]; -} DVD_BCA_DESCRIPTOR, *PDVD_BCA_DESCRIPTOR; - -// format 0x04 - DvdManufacturerDescriptor -typedef struct _DVD_MANUFACTURER_DESCRIPTOR { - UCHAR ManufacturingInformation[2048]; -} DVD_MANUFACTURER_DESCRIPTOR, *PDVD_MANUFACTURER_DESCRIPTOR; -C_ASSERT(sizeof(DVD_MANUFACTURER_DESCRIPTOR) == 2048); - -// format 0x05 - not defined in enum -typedef struct _DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR { - union { - struct { - UCHAR CopyProtectionMode : 4; - UCHAR ContentGenerationManagementSystem : 2; - UCHAR CopyProtectedSector : 1; - UCHAR CopyProtectedMaterial : 1; - } Dvdrom; - struct { - UCHAR Reserved0001 : 4; - UCHAR ContentGenerationManagementSystem : 2; - UCHAR Reserved0002 : 1; - UCHAR CopyProtectedMaterial : 1; - } DvdRecordable_Version1; - struct { - UCHAR Reserved0003; - } Dvdram; - struct { - UCHAR Reserved0004 : 2; - UCHAR ADP_TY : 2; // what is this mean? - UCHAR Reserved0005 : 4; - } DvdRecordable; - UCHAR CPR_MAI; - }; - UCHAR Reserved0[3]; -} DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR, *PDVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR; -C_ASSERT(FIELD_OFFSET(DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR, Reserved0) == 1); -C_ASSERT(sizeof(DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR) == 4); - -// format 0x06 (media ID) is unstructured in public spec -// format 0x07 (media key block) is unstructured in public spec -// format 0x08 (DVD-RAM DDS) is unstructured in public spec - -// format 0x09 - not defined in enum -// This is valid for DVD-RAM and also HD DVD-RAM -typedef struct _DVD_RAM_MEDIUM_STATUS { - UCHAR Reserved0 : 1; - UCHAR PersistentWriteProtect : 1; - UCHAR CartridgeWriteProtect : 1; - UCHAR MediaSpecificWriteInhibit : 1; - UCHAR Reserved1 : 2; - UCHAR CartridgeNotSealed : 1; - UCHAR MediaInCartridge : 1; - UCHAR DiscTypeIdentification; - UCHAR Reserved2; - UCHAR MediaSpecificWriteInhibitInformation; -} DVD_RAM_MEDIUM_STATUS, *PDVD_RAM_MEDIUM_STATUS; -C_ASSERT(sizeof(DVD_RAM_MEDIUM_STATUS) == 4); - -// format 0x0A - not defined in enum -typedef struct _DVD_RAM_SPARE_AREA_INFORMATION { - UCHAR FreePrimarySpareSectors[4]; - UCHAR FreeSupplementalSpareSectors[4]; - UCHAR AllocatedSupplementalSpareSectors[4]; -} DVD_RAM_SPARE_AREA_INFORMATION, *PDVD_RAM_SPARE_AREA_INFORMATION; -C_ASSERT(sizeof(DVD_RAM_SPARE_AREA_INFORMATION) == 12); - -// format 0x0B - not defined in enum -typedef struct _DVD_RAM_RECORDING_TYPE { - UCHAR Reserved0 : 4; - UCHAR RealTimeData : 1; - UCHAR Reserved1 : 3; - UCHAR Reserved2[3]; -} DVD_RAM_RECORDING_TYPE, *PDVD_RAM_RECORDING_TYPE; -C_ASSERT(sizeof(DVD_RAM_RECORDING_TYPE) == 4); - -// format 0x0C (RMD in last border-out) is unstructured in public spec -// format 0x0D - not defined in enum -typedef struct _DVD_RECORDING_MANAGEMENT_AREA_DATA { - UCHAR LastRecordedRMASectorNumber[4]; -#if !defined(__midl) - UCHAR RMDBytes[0]; -#endif -} DVD_RECORDING_MANAGEMENT_AREA_DATA, *PDVD_RECORDING_MANAGEMENT_AREA_DATA; -C_ASSERT(sizeof(DVD_RECORDING_MANAGEMENT_AREA_DATA) == 4); - -// format 0x0E - not define in enum -typedef struct _DVD_PRERECORDED_INFORMATION { - UCHAR FieldID_1; - UCHAR DiscApplicationCode; - UCHAR DiscPhysicalCode; - UCHAR LastAddressOfDataRecordableArea[3]; - UCHAR ExtensionCode : 4; // -R for general/authoring v2.0 - UCHAR PartVers1on : 4; // -R for general/authoring v2.0 - UCHAR Reserved0; - UCHAR FieldID_2; - UCHAR OpcSuggestedCode; - UCHAR WavelengthCode; - UCHAR WriteStrategyCode[4]; - UCHAR Reserved2; - UCHAR FieldID_3; - UCHAR ManufacturerId_3[6]; - UCHAR Reserved3; - UCHAR FieldID_4; - UCHAR ManufacturerId_4[6]; - UCHAR Reserved4; - UCHAR FieldID_5; - UCHAR ManufacturerId_5[6]; - UCHAR Reserved5; - UCHAR Reserved99[24]; -} DVD_PRERECORDED_INFORMATION, *PDVD_PRERECORDED_INFORMATION; -C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_2) == 8); -C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_3) == 16); -C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_4) == 24); -C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_5) == 32); -C_ASSERT(sizeof(DVD_PRERECORDED_INFORMATION) == 64); - -// format 0x0F - not defined in enum -typedef struct _DVD_UNIQUE_DISC_IDENTIFIER { - UCHAR Reserved0[2]; - UCHAR RandomNumber[2]; - UCHAR Year[4]; // ASCII? - UCHAR Month[2]; // ASCII? - UCHAR Day[2]; // ASCII? - UCHAR Hour[2]; // ASCII? - UCHAR Minute[2]; // ASCII? - UCHAR Second[2]; // ASCII? -} DVD_UNIQUE_DISC_IDENTIFIER, *PDVD_UNIQUE_DISC_IDENTIFIER; -C_ASSERT(sizeof(DVD_UNIQUE_DISC_IDENTIFIER) == 18); - -// format 0x10 - not define in enum - use DVD_LAYER_DESCRIPTOR structure above -// format 0x11 (ADIP information) is unstructured in public spec -// formats 0x12, 0x15 are is unstructured in public spec -// formats 0x13, 0x14, 0x16 through 0x18 are not yet defined - -// format 0x19 - not defined in enum -typedef struct _HD_DVD_R_MEDIUM_STATUS { - UCHAR ExtendedTestZone : 1; - UCHAR Reserved1 : 7; - UCHAR NumberOfRemainingRMDsInRDZ; - UCHAR NumberOfRemainingRMDsInCurrentRMZ[2]; -} HD_DVD_R_MEDIUM_STATUS, *PHD_DVD_R_MEDIUM_STATUS; -C_ASSERT(sizeof(HD_DVD_R_MEDIUM_STATUS) == 4); - -// format 0x1A (HD DVD-R - Last recorded RMD in the latest R) is unstructured in public spec -// formats 0x1B through 0x1F are not yet defined - -// format 0x20 - not define in enum -typedef struct _DVD_DUAL_LAYER_RECORDING_INFORMATION { - UCHAR Reserved0 : 7; - UCHAR Layer0SectorsImmutable : 1; - UCHAR Reserved1[3]; - UCHAR Layer0Sectors[4]; -} DVD_DUAL_LAYER_RECORDING_INFORMATION, *PDVD_DUAL_LAYER_RECORDING_INFORMATION; - -// format 0x21 - not define in enum -typedef struct _DVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS { - UCHAR Reserved0 : 7; - UCHAR InitStatus : 1; - UCHAR Reserved1[3]; - UCHAR ShiftedMiddleAreaStartAddress[4]; -} DVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS, *PDVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS; - -// format 0x22 - not define in enum -typedef struct _DVD_DUAL_LAYER_JUMP_INTERVAL_SIZE { - UCHAR Reserved1[4]; - UCHAR JumpIntervalSize[4]; -} DVD_DUAL_LAYER_JUMP_INTERVAL_SIZE, *PDVD_DUAL_LAYER_JUMP_INTERVAL_SIZE; - -// format 0x23 - not define in enum -typedef struct _DVD_DUAL_LAYER_MANUAL_LAYER_JUMP { - UCHAR Reserved1[4]; - UCHAR ManualJumpLayerAddress[4]; -} DVD_DUAL_LAYER_MANUAL_LAYER_JUMP, *PDVD_DUAL_LAYER_MANUAL_LAYER_JUMP; - -// format 0x24 - not define in enum -typedef struct _DVD_DUAL_LAYER_REMAPPING_INFORMATION { - UCHAR Reserved1[4]; - UCHAR RemappingAddress[4]; -} DVD_DUAL_LAYER_REMAPPING_INFORMATION, *PDVD_DUAL_LAYER_REMAPPING_INFORMATION; - -// formats 0x25 through 0x2F are not yet defined - -// format 0x30 - not defined in enum (common header) -typedef struct _DVD_DISC_CONTROL_BLOCK_HEADER { - UCHAR ContentDescriptor[4]; - union { - struct { - UCHAR ReservedDoNotUse_UseAsByteInstead_0[3]; - UCHAR RecordingWithinTheUserDataArea : 1; - UCHAR ReadingDiscControlBlocks : 1; - UCHAR FormattingTheMedium : 1; - UCHAR ModificationOfThisDiscControlBlock : 1; - UCHAR ReservedDoNotUse_UseAsByteInstead_1 : 4; - }; - UCHAR AsByte[4]; - } ProhibitedActions; - UCHAR VendorId[32]; // actually "non-specified" data - // UCHAR DCBData[32728]; -} DVD_DISC_CONTROL_BLOCK_HEADER, *PDVD_DISC_CONTROL_BLOCK_HEADER; -C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_HEADER) == 40); - -// publicly defined DCB types -typedef enum _DISC_CONTROL_BLOCK_TYPE { - FormattingDiscControlBlock = 0x46444300, // 'FDC\0' - WriteInhibitDiscControlBlock = 0x57444300, // 'WDC\0' - SessionInfoDiscControlBlock = 0x53444300, // 'SDC\0' - DiscControlBlockList = 0xFFFFFFFF -} DISC_CONTROL_BLOCK_TYPE, *PDISC_CONTROL_BLOCK_TYPE; - -// format 0x30 - not defined in enum -- Format DCB, not in MMC. - -// format 0x30 - not defined in enum -- Write Inhibit DCB -typedef struct _DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT { - DVD_DISC_CONTROL_BLOCK_HEADER header; - UCHAR UpdateCount[4]; - union { - struct { - UCHAR ReservedDoNotUse_UseAsByteInstead_0[3]; - UCHAR WriteProtectStatus : 2; - UCHAR ReservedDoNotUse_UseAsByteInstead_1 : 5; - UCHAR UpdateRequiresPassword : 1; - }; - UCHAR AsByte[4]; - } WriteProtectActions; - UCHAR Reserved0[16]; - UCHAR UpdatePassword[32]; - UCHAR Reserved1[32672]; -} DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT, *PDVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT; -C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT) == (16*2048)); - -// format 0x30 - not defined in enum - Session DCB -typedef struct _DVD_DISC_CONTROL_BLOCK_SESSION_ITEM { - UCHAR AsByte[16]; // not publicly defined? -} DVD_DISC_CONTROL_BLOCK_SESSION_ITEM, *PDVD_DISC_CONTROL_BLOCK_SESSION_ITEM; -typedef struct _DVD_DISC_CONTROL_BLOCK_SESSION { - DVD_DISC_CONTROL_BLOCK_HEADER header; - UCHAR SessionNumber[2]; - UCHAR Reserved0[22]; - UCHAR DiscID[32]; - UCHAR Reserved1[32]; - DVD_DISC_CONTROL_BLOCK_SESSION_ITEM SessionItem[504]; - UCHAR Reserved2[24576]; // 3 Repetitions of bytes 0 through 8191 -} DVD_DISC_CONTROL_BLOCK_SESSION, *PDVD_DISC_CONTROL_BLOCK_SESSION; -C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_SESSION) == ((8*1024) * 4)); - -// format 0x30 - not defined in enum - DCB list -typedef struct _DVD_DISC_CONTROL_BLOCK_LIST_DCB { - UCHAR DcbIdentifier[4]; -} DVD_DISC_CONTROL_BLOCK_LIST_DCB, *PDVD_DISC_CONTROL_BLOCK_LIST_DCB; -typedef struct _DVD_DISC_CONTROL_BLOCK_LIST { - DVD_DISC_CONTROL_BLOCK_HEADER header; - UCHAR Reserved0; - UCHAR ReadabldDCBs; - UCHAR Reserved1; - UCHAR WritableDCBs; -#if !defined(__midl) - DVD_DISC_CONTROL_BLOCK_LIST_DCB Dcbs[0]; -#endif -} DVD_DISC_CONTROL_BLOCK_LIST, *PDVD_DISC_CONTROL_BLOCK_LIST; -C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_LIST) == 44); - -// format 0x31 (MTA ECC Block) is unstructured in public spec -// formats 0x32 through 0xBF are not yet defined - -// format 0xC0 - not defined in enum -typedef struct _DVD_WRITE_PROTECTION_STATUS { - UCHAR SoftwareWriteProtectUntilPowerdown : 1; - UCHAR MediaPersistentWriteProtect : 1; - UCHAR CartridgeWriteProtect : 1; - UCHAR MediaSpecificWriteProtect : 1; - UCHAR Reserved0 : 4; - UCHAR Reserved1[3]; -} DVD_WRITE_PROTECTION_STATUS, *PDVD_WRITE_PROTECTION_STATUS; -C_ASSERT(sizeof(DVD_WRITE_PROTECTION_STATUS) == 4); - -// formats 0xC1 through 0x7F are not yet defined -// format 0x80 (AACS volume identifier) is unstructured in public spec -// format 0x81 (Pre-Recorded AACS media serial number) is unstructured in public spec -// format 0x82 (AACS media identifier) is unstructured in public spec -// format 0x83 (AACS media key block) is unstructured in public spec -// formats 0x84 through 0x8F are not yet defined - -// format 0x90 - not defined in enum -typedef struct _DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE { - UCHAR TypeCodeOfFormatLayer[2]; -} DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS, *PDVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS; -typedef struct _DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS { - UCHAR NumberOfRecognizedFormatLayers; - UCHAR OnlineFormatlayer : 2; - UCHAR Reserved1 : 2; - UCHAR DefaultFormatLayer : 2; - UCHAR Reserved2 : 2; - // DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE TypeCodes[0]; -} DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE, *PDVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE; -C_ASSERT(sizeof(DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE) == 2); - -// formats 0x91 through 0xFE are not yet defined - -// format 0xFF - not defined in enum -typedef struct _DVD_STRUCTURE_LIST_ENTRY { - UCHAR FormatCode; - UCHAR Reserved0 : 6; - UCHAR Readable : 1; - UCHAR Sendable : 1; - UCHAR FormatLength[2]; -} DVD_STRUCTURE_LIST_ENTRY, *PDVD_STRUCTURE_LIST_ENTRY; -C_ASSERT(sizeof(DVD_STRUCTURE_LIST_ENTRY) == 4); - -// BD Disc Structures - -// format 0x00 (BD Disc Information) is unstructured in public spec -// format 0x08 (BD Disc Definition Structure) is unstructured in public spec -// format 0x09 (BD Cartridge Status) is identical to DVD_RAM_MEDIUM_STATUS but -// only CartridgeWriteProtect, CartridgeNotSealed and MediaInCartridge are -// valid. Other fields are reserved. - -// format 0x09 (BD Spare Area Information) - not defined in enum -typedef struct _DVD_BD_SPARE_AREA_INFORMATION { - UCHAR Reserved1[4]; - UCHAR NumberOfFreeSpareBlocks[4]; - UCHAR NumberOfAllocatedSpareBlocks[4]; -} DVD_BD_SPARE_AREA_INFORMATION, *PDVD_BD_SPARE_AREA_INFORMATION; -C_ASSERT(sizeof(DVD_BD_SPARE_AREA_INFORMATION) == 12); - -// format 0x12 (BD Raw Defect List). DFL is not fully defined in public spec - -// format 0x30 (BD Physical Access Control). -typedef struct _BD_PAC_HEADER { - UCHAR PACId[3]; - UCHAR PACFormatNumber; - UCHAR PACUpdateCount[4]; - UCHAR UnknownPACRules[4]; - UCHAR UnkownPACEntireDiscFlag; - UCHAR Reserved1[2]; - UCHAR NumberOfSegments; - UCHAR Segments[8][32]; - UCHAR Reserved2[112]; -} BD_PAC_HEADER, *PBD_PAC_HEADER; -C_ASSERT(sizeof(BD_PAC_HEADER) == 384); - -// Primary PAC is unstructured in public spec - -// Disc Write Protect PAC -typedef struct _BD_DISC_WRITE_PROTECT_PAC { - BD_PAC_HEADER Header; - UCHAR KnownPACEntireDiscFlags; - UCHAR Reserved1[3]; - UCHAR WriteProtectControlByte; - UCHAR Reserved2[7]; - UCHAR WriteProtectPassword[32]; -} BD_DISC_WRITE_PROTECT_PAC, *PBD_DISC_WRITE_PROTECT_PAC; -C_ASSERT(sizeof(BD_DISC_WRITE_PROTECT_PAC) == 428); - - -typedef struct _DVD_RPC_KEY { - UCHAR UserResetsAvailable:3; - UCHAR ManufacturerResetsAvailable:3; - UCHAR TypeCode:2; - UCHAR RegionMask; - UCHAR RpcScheme; - UCHAR Reserved02; -} DVD_RPC_KEY, * PDVD_RPC_KEY; -C_ASSERT(sizeof(DVD_RPC_KEY) == 4); - -typedef struct _DVD_SET_RPC_KEY { - UCHAR PreferredDriveRegionCode; - UCHAR Reserved[3]; -} DVD_SET_RPC_KEY, * PDVD_SET_RPC_KEY; -C_ASSERT(sizeof(DVD_SET_RPC_KEY) == 4); - -typedef struct _DVD_ASF { // Authentication Success Flag - UCHAR Reserved0[3]; - UCHAR SuccessFlag:1; - UCHAR Reserved1:7; -} DVD_ASF, * PDVD_ASF; -C_ASSERT(sizeof(DVD_ASF) == 4); - -#if 0 -typedef struct _DVD_REGION { - UCHAR CopySystem; - UCHAR RegionData; // current media region (not playable when set) - UCHAR SystemRegion; // current drive region (playable when set) - UCHAR ResetCount; // number of resets available -} DVD_REGION, *PDVD_REGION; -C_ASSERT(sizeof(DVD_REGION) == 4); -#endif - -// ALL THE ABOVE STRUCTURES ARE BYTE-PACKED: -///////////////////////////////////////////////////////////// -#include - - -#ifdef __cplusplus -} -#endif - - -///////////////////////////////////////////////////////////// -// AACS-related structures -// (mostly opaque data, but useful for allocation) - -// The AACS layer number refers to the layer of the disc a structure -// is read from. This can only be a single byte in the CDB, so limit -// the value to 0..255. -typedef __range(0,255) ULONG AACS_LAYER_NUMBER, *PAACS_LAYER_NUMBER; -typedef __range(0,255) const ULONG CAACS_LAYER_NUMBER, *PCAACS_LAYER_NUMBER; - - -// The AACS Certificate (opaque data structure) is used to validate -// the host to the logical unit, as well as to validate the logical -// unit to the host. -typedef struct _AACS_CERTIFICATE { - UCHAR Nonce[20]; - UCHAR Certificate[92]; -} AACS_CERTIFICATE, *PAACS_CERTIFICATE; -typedef const AACS_CERTIFICATE CAACS_CERTIFICATE; -typedef const AACS_CERTIFICATE *PCAACS_CERTIFICATE; -C_ASSERT(sizeof(AACS_CERTIFICATE) == 112); - -// The AACS challenge key (opaque data structure) is used to setup -// a shared bus key for AACS-protected structure transfer. -typedef struct _AACS_CHALLENGE_KEY { - UCHAR EllipticCurvePoint[40]; - UCHAR Signature[40]; -} AACS_CHALLENGE_KEY, *PAACS_CHALLENGE_KEY; -typedef const AACS_CHALLENGE_KEY CAACS_CHALLENGE_KEY; -typedef const AACS_CHALLENGE_KEY *PCAACS_CHALLENGE_KEY; -C_ASSERT(sizeof(AACS_CHALLENGE_KEY) == 80); - -// The VolumeID is one of the unique identifiers on AACS protected media -typedef struct _AACS_VOLUME_ID { - UCHAR VolumeID[16]; - UCHAR MAC[16]; // MessageAuthenticationCode -} AACS_VOLUME_ID, *PAACS_VOLUME_ID; -typedef const AACS_VOLUME_ID CAACS_VOLUME_ID; -typedef const AACS_VOLUME_ID *PCAACS_VOLUME_ID; -C_ASSERT(sizeof(AACS_VOLUME_ID) == 32); - -// The prerecorded Serial Number is one of the unique identifiers on AACS protected media -typedef struct _AACS_SERIAL_NUMBER { - UCHAR PrerecordedSerialNumber[16]; - UCHAR MAC[16]; // MessageAuthenticationCode -} AACS_SERIAL_NUMBER, *PAACS_SERIAL_NUMBER; -typedef const AACS_SERIAL_NUMBER CAACS_SERIAL_NUMBER; -typedef const AACS_SERIAL_NUMBER *PCAACS_SERIAL_NUMBER; -C_ASSERT(sizeof(AACS_SERIAL_NUMBER) == 32); - -// The MediaID is one of the unique identifiers on AACS protected media -typedef struct _AACS_MEDIA_ID { - UCHAR MediaID[16]; - UCHAR MAC[16]; // MessageAuthenticationCode -} AACS_MEDIA_ID, *PAACS_MEDIA_ID; -typedef const AACS_MEDIA_ID CAACS_MEDIA_ID; -typedef const AACS_MEDIA_ID *PCAACS_MEDIA_ID; -C_ASSERT(sizeof(AACS_MEDIA_ID) == 32); - -// When sending a certificate or challenge key, need to wrap -// the data structure with a DVD_SESSION_ID. -typedef struct _AACS_SEND_CERTIFICATE { - DVD_SESSION_ID SessionId; - AACS_CERTIFICATE Certificate; -} AACS_SEND_CERTIFICATE, *PAACS_SEND_CERTIFICATE; -typedef const AACS_SEND_CERTIFICATE CAACS_SEND_CERTIFICATE; -typedef const AACS_SEND_CERTIFICATE *PCAACS_SEND_CERTIFICATE; - -// When sending a certificate or challenge key, need to wrap -// the data structure with a DVD_SESSION_ID. -typedef struct _AACS_SEND_CHALLENGE_KEY { - DVD_SESSION_ID SessionId; - AACS_CHALLENGE_KEY ChallengeKey; -} AACS_SEND_CHALLENGE_KEY, *PAACS_SEND_CHALLENGE_KEY; -typedef const AACS_SEND_CHALLENGE_KEY CAACS_SEND_CHALLENGE_KEY; -typedef const AACS_SEND_CHALLENGE_KEY *PCAACS_SEND_CHALLENGE_KEY; - - -// The AACS binding nonce (opaque data structure) is used to -// protect individual content. -typedef struct _AACS_BINDING_NONCE { - UCHAR BindingNonce[16]; - UCHAR MAC[16]; // MessageAuthenticationCode -} AACS_BINDING_NONCE, *PAACS_BINDING_NONCE; -typedef const AACS_BINDING_NONCE CAACS_BINDING_NONCE; -typedef const AACS_BINDING_NONCE *PCAACS_BINDING_NONCE; -C_ASSERT(sizeof(AACS_BINDING_NONCE) == 32); - - -// This structure is sent when reading a binding nonce -// either from the medium or when having the logical unit -// generate a new binding nonce for a set of sectors -// NOTE: This structure must be identically aligned for 32/64 bit builds -// -typedef struct _AACS_READ_BINDING_NONCE { - DVD_SESSION_ID SessionId; - __range(0,255) ULONG NumberOfSectors; // spec only provides one byte - ULONGLONG StartLba; - - // 32-bit HANDLE is 32 bits, 64-bit HANDLE is 64 bits - union { - HANDLE Handle; - ULONGLONG ForceStructureLengthToMatch64bit; - }; -} AACS_READ_BINDING_NONCE, *PAACS_READ_BINDING_NONCE; - -///////////////////////////////////////////////////////////// - -#pragma warning(pop) -#endif // _NTDDCDVD_ - -// end_winioctl - - +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddcdvd.h + +Abstract: + + This module contains structures and definitions + associated with DVD ioctls. + + This module is used in conjunction with ntddcdrm.h which contains the + cdrom specific ioctls which will work on CDVD drives + + +--*/ + +// begin_winioctl + +#ifndef _NTDDCDVD_ +#define _NTDDCDVD_ +#pragma warning(push) +#pragma warning(disable:4200) // zero-sized array +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable:4214) // bitfield other than int +#if defined(__INTEL_COMPILER) +#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero +#endif + +#if _MSC_VER > 1000 +#pragma once +#endif + +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// + +#define IOCTL_DVD_BASE FILE_DEVICE_DVD + +// +// CDVD Device Control Functions +// +// Warning: Ioctls from 200 through 300 are used for the old common class +// driver ioctls and should not be used for device specific functionality +// + +// +// CSS-related IOCTLs +// + +#define IOCTL_DVD_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_READ_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_SEND_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0403, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_SET_READ_AHEAD CTL_CODE(IOCTL_DVD_BASE, 0x0404, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_GET_REGION CTL_CODE(IOCTL_DVD_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_SEND_KEY2 CTL_CODE(IOCTL_DVD_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// AACS-related IOCTLs +// +#define IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE CTL_CODE(IOCTL_DVD_BASE, 0x430, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_MEDIA_KEY_BLOCK CTL_CODE(IOCTL_DVD_BASE, 0x431, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x432, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x433, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_SEND_CERTIFICATE CTL_CODE(IOCTL_DVD_BASE, 0x434, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_GET_CERTIFICATE CTL_CODE(IOCTL_DVD_BASE, 0x435, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_GET_CHALLENGE_KEY CTL_CODE(IOCTL_DVD_BASE, 0x436, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_SEND_CHALLENGE_KEY CTL_CODE(IOCTL_DVD_BASE, 0x437, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_VOLUME_ID CTL_CODE(IOCTL_DVD_BASE, 0x438, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_SERIAL_NUMBER CTL_CODE(IOCTL_DVD_BASE, 0x439, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_MEDIA_ID CTL_CODE(IOCTL_DVD_BASE, 0x43A, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_BINDING_NONCE CTL_CODE(IOCTL_DVD_BASE, 0x43B, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_GENERATE_BINDING_NONCE CTL_CODE(IOCTL_DVD_BASE, 0x43C, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// DVD Structure queries +// + +#define IOCTL_DVD_READ_STRUCTURE CTL_CODE(IOCTL_DVD_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// The following file contains the IOCTL_STORAGE class ioctl definitions +// + +#define IOCTL_STORAGE_SET_READ_AHEAD CTL_CODE(IOCTL_STORAGE_BASE, 0x0100, METHOD_BUFFERED, FILE_READ_ACCESS) + +// end_winioctl + +#include "ntddstor.h" + +// begin_winioctl + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum { + DvdChallengeKey = 0x01, + DvdBusKey1, + DvdBusKey2, + DvdTitleKey, + DvdAsf, + DvdSetRpcKey = 0x6, + DvdGetRpcKey = 0x8, + DvdDiskKey = 0x80, + DvdInvalidateAGID = 0x3f +} DVD_KEY_TYPE; + +typedef __typefix(LONG) __range(-1,3) ULONG DVD_SESSION_ID, *PDVD_SESSION_ID; + +#include +typedef struct _DVD_COPY_PROTECT_KEY { + ULONG KeyLength; + DVD_SESSION_ID SessionId; + DVD_KEY_TYPE KeyType; + ULONG KeyFlags; + union { + HANDLE FileHandle; + LARGE_INTEGER TitleOffset; + } Parameters; + UCHAR KeyData[0]; +} DVD_COPY_PROTECT_KEY, *PDVD_COPY_PROTECT_KEY; +#include + +// +// Predefined (Mt. Fuji) key sizes +// Add sizeof(DVD_COPY_PROTECT_KEY) to get allocation size for +// the full key structure +// + +#define DVD_CHALLENGE_KEY_LENGTH (12 + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_BUS_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_TITLE_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_DISK_KEY_LENGTH (2048 + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_RPC_KEY_LENGTH (sizeof(DVD_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_SET_RPC_KEY_LENGTH (sizeof(DVD_SET_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_ASF_LENGTH (sizeof(DVD_ASF) + sizeof(DVD_COPY_PROTECT_KEY)) + +// +// Used with IOCTL_DVD_END_SESSION to end all DVD sessions at once +// + +#define DVD_END_ALL_SESSIONS ((DVD_SESSION_ID) 0xffffffff) + +// +// CGMS Copy Protection Flags +// + +#define DVD_CGMS_RESERVED_MASK 0x00000078 + +#define DVD_CGMS_COPY_PROTECT_MASK 0x00000018 +#define DVD_CGMS_COPY_PERMITTED 0x00000000 +#define DVD_CGMS_COPY_ONCE 0x00000010 +#define DVD_CGMS_NO_COPY 0x00000018 + +#define DVD_COPYRIGHT_MASK 0x00000040 +#define DVD_NOT_COPYRIGHTED 0x00000000 +#define DVD_COPYRIGHTED 0x00000040 + +#define DVD_SECTOR_PROTECT_MASK 0x00000020 +#define DVD_SECTOR_NOT_PROTECTED 0x00000000 +#define DVD_SECTOR_PROTECTED 0x00000020 + +/*++ + +IOCTL_STORAGE_SET_READ_AHEAD + +Requests that the storage device skip to TargetAddress once it has run across +TriggerAddress during the course of it's read-ahead caching operations. + +Input: + + a STORAGE_SET_READ_AHEAD structure which contains: + * the trigger address + * the target address + +Output: + + none + +--*/ + +#include +typedef struct _STORAGE_SET_READ_AHEAD { + LARGE_INTEGER TriggerAddress; + LARGE_INTEGER TargetAddress; +} STORAGE_SET_READ_AHEAD, *PSTORAGE_SET_READ_AHEAD; +#include + +/*++ + +IOCTL_DVD_READ_STRUCTURE + +Issues a READ_DVD_STRUCTURE command to the drive. + +Input: + + a DVD_READ_STRUCTURE describing what information is requested + +Output: + + a DVD Layer Descriptor as defined below + +--*/ + +typedef enum DVD_STRUCTURE_FORMAT { + DvdPhysicalDescriptor, // 0x00 + DvdCopyrightDescriptor, // 0x01 + DvdDiskKeyDescriptor, // 0x02 + DvdBCADescriptor, // 0x03 + DvdManufacturerDescriptor, // 0x04 + DvdMaxDescriptor // 0x05 +} DVD_STRUCTURE_FORMAT, *PDVD_STRUCTURE_FORMAT; + +///////////////////////////////////////////////////////////// +// ALL THE FOLLOWING STRUCTURES ARE BYTE-PACKED: +#include + +typedef struct DVD_READ_STRUCTURE { + LARGE_INTEGER BlockByteOffset; + DVD_STRUCTURE_FORMAT Format; + DVD_SESSION_ID SessionId; + UCHAR LayerNumber; +} DVD_READ_STRUCTURE, *PDVD_READ_STRUCTURE; + +typedef struct _DVD_DESCRIPTOR_HEADER { + USHORT Length; + UCHAR Reserved[2]; +#if !defined(__midl) + UCHAR Data[0]; +#endif +} DVD_DESCRIPTOR_HEADER, *PDVD_DESCRIPTOR_HEADER; +C_ASSERT(sizeof(DVD_DESCRIPTOR_HEADER) == 4); + +// format 0x00 - DvdPhysicalDescriptor +typedef struct _DVD_LAYER_DESCRIPTOR { + UCHAR BookVersion : 4; // in MMC 5 : Part Version + UCHAR BookType : 4; // Disk Category + UCHAR MinimumRate : 4; // Maximum Rate + UCHAR DiskSize : 4; + UCHAR LayerType : 4; + UCHAR TrackPath : 1; + UCHAR NumberOfLayers : 2; + UCHAR Reserved1 : 1; + UCHAR TrackDensity : 4; + UCHAR LinearDensity : 4; + ULONG StartingDataSector; // 3bytes + 1 zeroed byte + ULONG EndDataSector; // 3bytes + 1 zeroed byte + ULONG EndLayerZeroSector; // 3bytes + 1 zeroed byte + UCHAR Reserved5 : 7; + UCHAR BCAFlag : 1; + // The large Media Specific field is not declared here to enable stack allocation +} DVD_LAYER_DESCRIPTOR, *PDVD_LAYER_DESCRIPTOR; +C_ASSERT(sizeof(DVD_LAYER_DESCRIPTOR) == 17); +typedef struct _DVD_FULL_LAYER_DESCRIPTOR { + DVD_LAYER_DESCRIPTOR commonHeader; + UCHAR MediaSpecific[2031]; +} DVD_FULL_LAYER_DESCRIPTOR, *PDVD_FULL_LAYER_DESCRIPTOR; +C_ASSERT(sizeof(DVD_FULL_LAYER_DESCRIPTOR) == 2048); + +// format 0x01 - DvdCopyrightDescriptor +typedef struct _DVD_COPYRIGHT_DESCRIPTOR { + UCHAR CopyrightProtectionType; + UCHAR RegionManagementInformation; + USHORT Reserved; +} DVD_COPYRIGHT_DESCRIPTOR, *PDVD_COPYRIGHT_DESCRIPTOR; +C_ASSERT(sizeof(DVD_COPYRIGHT_DESCRIPTOR) == 4); + +// format 0x02 - DvdDiskKeyDescriptor +typedef struct _DVD_DISK_KEY_DESCRIPTOR { + UCHAR DiskKeyData[2048]; +} DVD_DISK_KEY_DESCRIPTOR, *PDVD_DISK_KEY_DESCRIPTOR; +C_ASSERT(sizeof(DVD_DISK_KEY_DESCRIPTOR) == 2048); + +// format 0x03 - DvdBCADescriptor +typedef struct _DVD_BCA_DESCRIPTOR { + UCHAR BCAInformation[0]; +} DVD_BCA_DESCRIPTOR, *PDVD_BCA_DESCRIPTOR; + +// format 0x04 - DvdManufacturerDescriptor +typedef struct _DVD_MANUFACTURER_DESCRIPTOR { + UCHAR ManufacturingInformation[2048]; +} DVD_MANUFACTURER_DESCRIPTOR, *PDVD_MANUFACTURER_DESCRIPTOR; +C_ASSERT(sizeof(DVD_MANUFACTURER_DESCRIPTOR) == 2048); + +// format 0x05 - not defined in enum +typedef struct _DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR { + union { + struct { + UCHAR CopyProtectionMode : 4; + UCHAR ContentGenerationManagementSystem : 2; + UCHAR CopyProtectedSector : 1; + UCHAR CopyProtectedMaterial : 1; + } Dvdrom; + struct { + UCHAR Reserved0001 : 4; + UCHAR ContentGenerationManagementSystem : 2; + UCHAR Reserved0002 : 1; + UCHAR CopyProtectedMaterial : 1; + } DvdRecordable_Version1; + struct { + UCHAR Reserved0003; + } Dvdram; + struct { + UCHAR Reserved0004 : 2; + UCHAR ADP_TY : 2; // what is this mean? + UCHAR Reserved0005 : 4; + } DvdRecordable; + UCHAR CPR_MAI; + }; + UCHAR Reserved0[3]; +} DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR, *PDVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR; +C_ASSERT(FIELD_OFFSET(DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR, Reserved0) == 1); +C_ASSERT(sizeof(DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR) == 4); + +// format 0x06 (media ID) is unstructured in public spec +// format 0x07 (media key block) is unstructured in public spec +// format 0x08 (DVD-RAM DDS) is unstructured in public spec + +// format 0x09 - not defined in enum +// This is valid for DVD-RAM and also HD DVD-RAM +typedef struct _DVD_RAM_MEDIUM_STATUS { + UCHAR Reserved0 : 1; + UCHAR PersistentWriteProtect : 1; + UCHAR CartridgeWriteProtect : 1; + UCHAR MediaSpecificWriteInhibit : 1; + UCHAR Reserved1 : 2; + UCHAR CartridgeNotSealed : 1; + UCHAR MediaInCartridge : 1; + UCHAR DiscTypeIdentification; + UCHAR Reserved2; + UCHAR MediaSpecificWriteInhibitInformation; +} DVD_RAM_MEDIUM_STATUS, *PDVD_RAM_MEDIUM_STATUS; +C_ASSERT(sizeof(DVD_RAM_MEDIUM_STATUS) == 4); + +// format 0x0A - not defined in enum +typedef struct _DVD_RAM_SPARE_AREA_INFORMATION { + UCHAR FreePrimarySpareSectors[4]; + UCHAR FreeSupplementalSpareSectors[4]; + UCHAR AllocatedSupplementalSpareSectors[4]; +} DVD_RAM_SPARE_AREA_INFORMATION, *PDVD_RAM_SPARE_AREA_INFORMATION; +C_ASSERT(sizeof(DVD_RAM_SPARE_AREA_INFORMATION) == 12); + +// format 0x0B - not defined in enum +typedef struct _DVD_RAM_RECORDING_TYPE { + UCHAR Reserved0 : 4; + UCHAR RealTimeData : 1; + UCHAR Reserved1 : 3; + UCHAR Reserved2[3]; +} DVD_RAM_RECORDING_TYPE, *PDVD_RAM_RECORDING_TYPE; +C_ASSERT(sizeof(DVD_RAM_RECORDING_TYPE) == 4); + +// format 0x0C (RMD in last border-out) is unstructured in public spec +// format 0x0D - not defined in enum +typedef struct _DVD_RECORDING_MANAGEMENT_AREA_DATA { + UCHAR LastRecordedRMASectorNumber[4]; +#if !defined(__midl) + UCHAR RMDBytes[0]; +#endif +} DVD_RECORDING_MANAGEMENT_AREA_DATA, *PDVD_RECORDING_MANAGEMENT_AREA_DATA; +C_ASSERT(sizeof(DVD_RECORDING_MANAGEMENT_AREA_DATA) == 4); + +// format 0x0E - not define in enum +typedef struct _DVD_PRERECORDED_INFORMATION { + UCHAR FieldID_1; + UCHAR DiscApplicationCode; + UCHAR DiscPhysicalCode; + UCHAR LastAddressOfDataRecordableArea[3]; + UCHAR ExtensionCode : 4; // -R for general/authoring v2.0 + UCHAR PartVers1on : 4; // -R for general/authoring v2.0 + UCHAR Reserved0; + UCHAR FieldID_2; + UCHAR OpcSuggestedCode; + UCHAR WavelengthCode; + UCHAR WriteStrategyCode[4]; + UCHAR Reserved2; + UCHAR FieldID_3; + UCHAR ManufacturerId_3[6]; + UCHAR Reserved3; + UCHAR FieldID_4; + UCHAR ManufacturerId_4[6]; + UCHAR Reserved4; + UCHAR FieldID_5; + UCHAR ManufacturerId_5[6]; + UCHAR Reserved5; + UCHAR Reserved99[24]; +} DVD_PRERECORDED_INFORMATION, *PDVD_PRERECORDED_INFORMATION; +C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_2) == 8); +C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_3) == 16); +C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_4) == 24); +C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_5) == 32); +C_ASSERT(sizeof(DVD_PRERECORDED_INFORMATION) == 64); + +// format 0x0F - not defined in enum +typedef struct _DVD_UNIQUE_DISC_IDENTIFIER { + UCHAR Reserved0[2]; + UCHAR RandomNumber[2]; + UCHAR Year[4]; // ASCII? + UCHAR Month[2]; // ASCII? + UCHAR Day[2]; // ASCII? + UCHAR Hour[2]; // ASCII? + UCHAR Minute[2]; // ASCII? + UCHAR Second[2]; // ASCII? +} DVD_UNIQUE_DISC_IDENTIFIER, *PDVD_UNIQUE_DISC_IDENTIFIER; +C_ASSERT(sizeof(DVD_UNIQUE_DISC_IDENTIFIER) == 18); + +// format 0x10 - not define in enum - use DVD_LAYER_DESCRIPTOR structure above +// format 0x11 (ADIP information) is unstructured in public spec +// formats 0x12, 0x15 are is unstructured in public spec +// formats 0x13, 0x14, 0x16 through 0x18 are not yet defined + +// format 0x19 - not defined in enum +typedef struct _HD_DVD_R_MEDIUM_STATUS { + UCHAR ExtendedTestZone : 1; + UCHAR Reserved1 : 7; + UCHAR NumberOfRemainingRMDsInRDZ; + UCHAR NumberOfRemainingRMDsInCurrentRMZ[2]; +} HD_DVD_R_MEDIUM_STATUS, *PHD_DVD_R_MEDIUM_STATUS; +C_ASSERT(sizeof(HD_DVD_R_MEDIUM_STATUS) == 4); + +// format 0x1A (HD DVD-R - Last recorded RMD in the latest R) is unstructured in public spec +// formats 0x1B through 0x1F are not yet defined + +// format 0x20 - not define in enum +typedef struct _DVD_DUAL_LAYER_RECORDING_INFORMATION { + UCHAR Reserved0 : 7; + UCHAR Layer0SectorsImmutable : 1; + UCHAR Reserved1[3]; + UCHAR Layer0Sectors[4]; +} DVD_DUAL_LAYER_RECORDING_INFORMATION, *PDVD_DUAL_LAYER_RECORDING_INFORMATION; + +// format 0x21 - not define in enum +typedef struct _DVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS { + UCHAR Reserved0 : 7; + UCHAR InitStatus : 1; + UCHAR Reserved1[3]; + UCHAR ShiftedMiddleAreaStartAddress[4]; +} DVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS, *PDVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS; + +// format 0x22 - not define in enum +typedef struct _DVD_DUAL_LAYER_JUMP_INTERVAL_SIZE { + UCHAR Reserved1[4]; + UCHAR JumpIntervalSize[4]; +} DVD_DUAL_LAYER_JUMP_INTERVAL_SIZE, *PDVD_DUAL_LAYER_JUMP_INTERVAL_SIZE; + +// format 0x23 - not define in enum +typedef struct _DVD_DUAL_LAYER_MANUAL_LAYER_JUMP { + UCHAR Reserved1[4]; + UCHAR ManualJumpLayerAddress[4]; +} DVD_DUAL_LAYER_MANUAL_LAYER_JUMP, *PDVD_DUAL_LAYER_MANUAL_LAYER_JUMP; + +// format 0x24 - not define in enum +typedef struct _DVD_DUAL_LAYER_REMAPPING_INFORMATION { + UCHAR Reserved1[4]; + UCHAR RemappingAddress[4]; +} DVD_DUAL_LAYER_REMAPPING_INFORMATION, *PDVD_DUAL_LAYER_REMAPPING_INFORMATION; + +// formats 0x25 through 0x2F are not yet defined + +// format 0x30 - not defined in enum (common header) +typedef struct _DVD_DISC_CONTROL_BLOCK_HEADER { + UCHAR ContentDescriptor[4]; + union { + struct { + UCHAR ReservedDoNotUse_UseAsByteInstead_0[3]; + UCHAR RecordingWithinTheUserDataArea : 1; + UCHAR ReadingDiscControlBlocks : 1; + UCHAR FormattingTheMedium : 1; + UCHAR ModificationOfThisDiscControlBlock : 1; + UCHAR ReservedDoNotUse_UseAsByteInstead_1 : 4; + }; + UCHAR AsByte[4]; + } ProhibitedActions; + UCHAR VendorId[32]; // actually "non-specified" data + // UCHAR DCBData[32728]; +} DVD_DISC_CONTROL_BLOCK_HEADER, *PDVD_DISC_CONTROL_BLOCK_HEADER; +C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_HEADER) == 40); + +// publicly defined DCB types +typedef enum _DISC_CONTROL_BLOCK_TYPE { + FormattingDiscControlBlock = 0x46444300, // 'FDC\0' + WriteInhibitDiscControlBlock = 0x57444300, // 'WDC\0' + SessionInfoDiscControlBlock = 0x53444300, // 'SDC\0' + DiscControlBlockList = 0xFFFFFFFF +} DISC_CONTROL_BLOCK_TYPE, *PDISC_CONTROL_BLOCK_TYPE; + +// format 0x30 - not defined in enum -- Format DCB, not in MMC. + +// format 0x30 - not defined in enum -- Write Inhibit DCB +typedef struct _DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT { + DVD_DISC_CONTROL_BLOCK_HEADER header; + UCHAR UpdateCount[4]; + union { + struct { + UCHAR ReservedDoNotUse_UseAsByteInstead_0[3]; + UCHAR WriteProtectStatus : 2; + UCHAR ReservedDoNotUse_UseAsByteInstead_1 : 5; + UCHAR UpdateRequiresPassword : 1; + }; + UCHAR AsByte[4]; + } WriteProtectActions; + UCHAR Reserved0[16]; + UCHAR UpdatePassword[32]; + UCHAR Reserved1[32672]; +} DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT, *PDVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT; +C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT) == (16*2048)); + +// format 0x30 - not defined in enum - Session DCB +typedef struct _DVD_DISC_CONTROL_BLOCK_SESSION_ITEM { + UCHAR AsByte[16]; // not publicly defined? +} DVD_DISC_CONTROL_BLOCK_SESSION_ITEM, *PDVD_DISC_CONTROL_BLOCK_SESSION_ITEM; +typedef struct _DVD_DISC_CONTROL_BLOCK_SESSION { + DVD_DISC_CONTROL_BLOCK_HEADER header; + UCHAR SessionNumber[2]; + UCHAR Reserved0[22]; + UCHAR DiscID[32]; + UCHAR Reserved1[32]; + DVD_DISC_CONTROL_BLOCK_SESSION_ITEM SessionItem[504]; + UCHAR Reserved2[24576]; // 3 Repetitions of bytes 0 through 8191 +} DVD_DISC_CONTROL_BLOCK_SESSION, *PDVD_DISC_CONTROL_BLOCK_SESSION; +C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_SESSION) == ((8*1024) * 4)); + +// format 0x30 - not defined in enum - DCB list +typedef struct _DVD_DISC_CONTROL_BLOCK_LIST_DCB { + UCHAR DcbIdentifier[4]; +} DVD_DISC_CONTROL_BLOCK_LIST_DCB, *PDVD_DISC_CONTROL_BLOCK_LIST_DCB; +typedef struct _DVD_DISC_CONTROL_BLOCK_LIST { + DVD_DISC_CONTROL_BLOCK_HEADER header; + UCHAR Reserved0; + UCHAR ReadabldDCBs; + UCHAR Reserved1; + UCHAR WritableDCBs; +#if !defined(__midl) + DVD_DISC_CONTROL_BLOCK_LIST_DCB Dcbs[0]; +#endif +} DVD_DISC_CONTROL_BLOCK_LIST, *PDVD_DISC_CONTROL_BLOCK_LIST; +C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_LIST) == 44); + +// format 0x31 (MTA ECC Block) is unstructured in public spec +// formats 0x32 through 0xBF are not yet defined + +// format 0xC0 - not defined in enum +typedef struct _DVD_WRITE_PROTECTION_STATUS { + UCHAR SoftwareWriteProtectUntilPowerdown : 1; + UCHAR MediaPersistentWriteProtect : 1; + UCHAR CartridgeWriteProtect : 1; + UCHAR MediaSpecificWriteProtect : 1; + UCHAR Reserved0 : 4; + UCHAR Reserved1[3]; +} DVD_WRITE_PROTECTION_STATUS, *PDVD_WRITE_PROTECTION_STATUS; +C_ASSERT(sizeof(DVD_WRITE_PROTECTION_STATUS) == 4); + +// formats 0xC1 through 0x7F are not yet defined +// format 0x80 (AACS volume identifier) is unstructured in public spec +// format 0x81 (Pre-Recorded AACS media serial number) is unstructured in public spec +// format 0x82 (AACS media identifier) is unstructured in public spec +// format 0x83 (AACS media key block) is unstructured in public spec +// formats 0x84 through 0x8F are not yet defined + +// format 0x90 - not defined in enum +typedef struct _DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE { + UCHAR TypeCodeOfFormatLayer[2]; +} DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS, *PDVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS; +typedef struct _DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS { + UCHAR NumberOfRecognizedFormatLayers; + UCHAR OnlineFormatlayer : 2; + UCHAR Reserved1 : 2; + UCHAR DefaultFormatLayer : 2; + UCHAR Reserved2 : 2; + // DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE TypeCodes[0]; +} DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE, *PDVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE; +C_ASSERT(sizeof(DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE) == 2); + +// formats 0x91 through 0xFE are not yet defined + +// format 0xFF - not defined in enum +typedef struct _DVD_STRUCTURE_LIST_ENTRY { + UCHAR FormatCode; + UCHAR Reserved0 : 6; + UCHAR Readable : 1; + UCHAR Sendable : 1; + UCHAR FormatLength[2]; +} DVD_STRUCTURE_LIST_ENTRY, *PDVD_STRUCTURE_LIST_ENTRY; +C_ASSERT(sizeof(DVD_STRUCTURE_LIST_ENTRY) == 4); + +// BD Disc Structures + +// format 0x00 (BD Disc Information) is unstructured in public spec +// format 0x08 (BD Disc Definition Structure) is unstructured in public spec +// format 0x09 (BD Cartridge Status) is identical to DVD_RAM_MEDIUM_STATUS but +// only CartridgeWriteProtect, CartridgeNotSealed and MediaInCartridge are +// valid. Other fields are reserved. + +// format 0x09 (BD Spare Area Information) - not defined in enum +typedef struct _DVD_BD_SPARE_AREA_INFORMATION { + UCHAR Reserved1[4]; + UCHAR NumberOfFreeSpareBlocks[4]; + UCHAR NumberOfAllocatedSpareBlocks[4]; +} DVD_BD_SPARE_AREA_INFORMATION, *PDVD_BD_SPARE_AREA_INFORMATION; +C_ASSERT(sizeof(DVD_BD_SPARE_AREA_INFORMATION) == 12); + +// format 0x12 (BD Raw Defect List). DFL is not fully defined in public spec + +// format 0x30 (BD Physical Access Control). +typedef struct _BD_PAC_HEADER { + UCHAR PACId[3]; + UCHAR PACFormatNumber; + UCHAR PACUpdateCount[4]; + UCHAR UnknownPACRules[4]; + UCHAR UnkownPACEntireDiscFlag; + UCHAR Reserved1[2]; + UCHAR NumberOfSegments; + UCHAR Segments[8][32]; + UCHAR Reserved2[112]; +} BD_PAC_HEADER, *PBD_PAC_HEADER; +C_ASSERT(sizeof(BD_PAC_HEADER) == 384); + +// Primary PAC is unstructured in public spec + +// Disc Write Protect PAC +typedef struct _BD_DISC_WRITE_PROTECT_PAC { + BD_PAC_HEADER Header; + UCHAR KnownPACEntireDiscFlags; + UCHAR Reserved1[3]; + UCHAR WriteProtectControlByte; + UCHAR Reserved2[7]; + UCHAR WriteProtectPassword[32]; +} BD_DISC_WRITE_PROTECT_PAC, *PBD_DISC_WRITE_PROTECT_PAC; +C_ASSERT(sizeof(BD_DISC_WRITE_PROTECT_PAC) == 428); + + +typedef struct _DVD_RPC_KEY { + UCHAR UserResetsAvailable:3; + UCHAR ManufacturerResetsAvailable:3; + UCHAR TypeCode:2; + UCHAR RegionMask; + UCHAR RpcScheme; + UCHAR Reserved02; +} DVD_RPC_KEY, * PDVD_RPC_KEY; +C_ASSERT(sizeof(DVD_RPC_KEY) == 4); + +typedef struct _DVD_SET_RPC_KEY { + UCHAR PreferredDriveRegionCode; + UCHAR Reserved[3]; +} DVD_SET_RPC_KEY, * PDVD_SET_RPC_KEY; +C_ASSERT(sizeof(DVD_SET_RPC_KEY) == 4); + +typedef struct _DVD_ASF { // Authentication Success Flag + UCHAR Reserved0[3]; + UCHAR SuccessFlag:1; + UCHAR Reserved1:7; +} DVD_ASF, * PDVD_ASF; +C_ASSERT(sizeof(DVD_ASF) == 4); + +#if 0 +typedef struct _DVD_REGION { + UCHAR CopySystem; + UCHAR RegionData; // current media region (not playable when set) + UCHAR SystemRegion; // current drive region (playable when set) + UCHAR ResetCount; // number of resets available +} DVD_REGION, *PDVD_REGION; +C_ASSERT(sizeof(DVD_REGION) == 4); +#endif + +// ALL THE ABOVE STRUCTURES ARE BYTE-PACKED: +///////////////////////////////////////////////////////////// +#include + + +#ifdef __cplusplus +} +#endif + + +///////////////////////////////////////////////////////////// +// AACS-related structures +// (mostly opaque data, but useful for allocation) + +// The AACS layer number refers to the layer of the disc a structure +// is read from. This can only be a single byte in the CDB, so limit +// the value to 0..255. +typedef __range(0,255) ULONG AACS_LAYER_NUMBER, *PAACS_LAYER_NUMBER; +typedef __range(0,255) const ULONG CAACS_LAYER_NUMBER, *PCAACS_LAYER_NUMBER; + + +// The AACS Certificate (opaque data structure) is used to validate +// the host to the logical unit, as well as to validate the logical +// unit to the host. +typedef struct _AACS_CERTIFICATE { + UCHAR Nonce[20]; + UCHAR Certificate[92]; +} AACS_CERTIFICATE, *PAACS_CERTIFICATE; +typedef const AACS_CERTIFICATE CAACS_CERTIFICATE; +typedef const AACS_CERTIFICATE *PCAACS_CERTIFICATE; +C_ASSERT(sizeof(AACS_CERTIFICATE) == 112); + +// The AACS challenge key (opaque data structure) is used to setup +// a shared bus key for AACS-protected structure transfer. +typedef struct _AACS_CHALLENGE_KEY { + UCHAR EllipticCurvePoint[40]; + UCHAR Signature[40]; +} AACS_CHALLENGE_KEY, *PAACS_CHALLENGE_KEY; +typedef const AACS_CHALLENGE_KEY CAACS_CHALLENGE_KEY; +typedef const AACS_CHALLENGE_KEY *PCAACS_CHALLENGE_KEY; +C_ASSERT(sizeof(AACS_CHALLENGE_KEY) == 80); + +// The VolumeID is one of the unique identifiers on AACS protected media +typedef struct _AACS_VOLUME_ID { + UCHAR VolumeID[16]; + UCHAR MAC[16]; // MessageAuthenticationCode +} AACS_VOLUME_ID, *PAACS_VOLUME_ID; +typedef const AACS_VOLUME_ID CAACS_VOLUME_ID; +typedef const AACS_VOLUME_ID *PCAACS_VOLUME_ID; +C_ASSERT(sizeof(AACS_VOLUME_ID) == 32); + +// The prerecorded Serial Number is one of the unique identifiers on AACS protected media +typedef struct _AACS_SERIAL_NUMBER { + UCHAR PrerecordedSerialNumber[16]; + UCHAR MAC[16]; // MessageAuthenticationCode +} AACS_SERIAL_NUMBER, *PAACS_SERIAL_NUMBER; +typedef const AACS_SERIAL_NUMBER CAACS_SERIAL_NUMBER; +typedef const AACS_SERIAL_NUMBER *PCAACS_SERIAL_NUMBER; +C_ASSERT(sizeof(AACS_SERIAL_NUMBER) == 32); + +// The MediaID is one of the unique identifiers on AACS protected media +typedef struct _AACS_MEDIA_ID { + UCHAR MediaID[16]; + UCHAR MAC[16]; // MessageAuthenticationCode +} AACS_MEDIA_ID, *PAACS_MEDIA_ID; +typedef const AACS_MEDIA_ID CAACS_MEDIA_ID; +typedef const AACS_MEDIA_ID *PCAACS_MEDIA_ID; +C_ASSERT(sizeof(AACS_MEDIA_ID) == 32); + +// When sending a certificate or challenge key, need to wrap +// the data structure with a DVD_SESSION_ID. +typedef struct _AACS_SEND_CERTIFICATE { + DVD_SESSION_ID SessionId; + AACS_CERTIFICATE Certificate; +} AACS_SEND_CERTIFICATE, *PAACS_SEND_CERTIFICATE; +typedef const AACS_SEND_CERTIFICATE CAACS_SEND_CERTIFICATE; +typedef const AACS_SEND_CERTIFICATE *PCAACS_SEND_CERTIFICATE; + +// When sending a certificate or challenge key, need to wrap +// the data structure with a DVD_SESSION_ID. +typedef struct _AACS_SEND_CHALLENGE_KEY { + DVD_SESSION_ID SessionId; + AACS_CHALLENGE_KEY ChallengeKey; +} AACS_SEND_CHALLENGE_KEY, *PAACS_SEND_CHALLENGE_KEY; +typedef const AACS_SEND_CHALLENGE_KEY CAACS_SEND_CHALLENGE_KEY; +typedef const AACS_SEND_CHALLENGE_KEY *PCAACS_SEND_CHALLENGE_KEY; + + +// The AACS binding nonce (opaque data structure) is used to +// protect individual content. +typedef struct _AACS_BINDING_NONCE { + UCHAR BindingNonce[16]; + UCHAR MAC[16]; // MessageAuthenticationCode +} AACS_BINDING_NONCE, *PAACS_BINDING_NONCE; +typedef const AACS_BINDING_NONCE CAACS_BINDING_NONCE; +typedef const AACS_BINDING_NONCE *PCAACS_BINDING_NONCE; +C_ASSERT(sizeof(AACS_BINDING_NONCE) == 32); + + +// This structure is sent when reading a binding nonce +// either from the medium or when having the logical unit +// generate a new binding nonce for a set of sectors +// NOTE: This structure must be identically aligned for 32/64 bit builds +// +typedef struct _AACS_READ_BINDING_NONCE { + DVD_SESSION_ID SessionId; + __range(0,255) ULONG NumberOfSectors; // spec only provides one byte + ULONGLONG StartLba; + + // 32-bit HANDLE is 32 bits, 64-bit HANDLE is 64 bits + union { + HANDLE Handle; + ULONGLONG ForceStructureLengthToMatch64bit; + }; +} AACS_READ_BINDING_NONCE, *PAACS_READ_BINDING_NONCE; + +///////////////////////////////////////////////////////////// + +#pragma warning(pop) +#endif // _NTDDCDVD_ + +// end_winioctl + + diff --git a/include/winddk/ntdddisk.h b/include/winddk/ntdddisk.h index db36802a9d0..92e91f620ae 100644 --- a/include/winddk/ntdddisk.h +++ b/include/winddk/ntdddisk.h @@ -1,1759 +1,1759 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - ntdddisk.h - -Abstract: - - This is the include file that defines all constants and types for - accessing the Disk device. - -Revision History: - ---*/ - - -// begin_winioctl - -#ifndef _NTDDDISK_H_ -#define _NTDDDISK_H_ - -// end_winioctl - -#if _MSC_VER > 1000 -#pragma once -#endif - -#if (NTDDI_VERSION >= NTDDI_WINXP) -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// begin_winioctl - -#if defined(_MSC_VER) -#if (_MSC_VER >= 1200) -#pragma warning(push) -#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union -#pragma warning(disable:4214) // nonstandard extension used : bitfield other than int -#endif -#endif - -// end_winioctl - -// -// Device Name - this string is the name of the device. It is the name -// that should be passed to NtOpenFile when accessing the device. -// -// Note: For devices that support multiple units, it should be suffixed -// with the Ascii representation of the unit number. -// - -#define DD_DISK_DEVICE_NAME "\\Device\\UNKNOWN" - - -// -// NtDeviceIoControlFile - -// begin_winioctl - -// -// IoControlCode values for disk devices. -// - -#define IOCTL_DISK_BASE FILE_DEVICE_DISK -#define IOCTL_DISK_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_GET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_FORMAT_TRACKS CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_REASSIGN_BLOCKS CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_PERFORMANCE CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_IS_WRITABLE CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_LOGGING CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_FORMAT_TRACKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_HISTOGRAM_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_HISTOGRAM_DATA CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_HISTOGRAM_RESET CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_REQUEST_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_REQUEST_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_PERFORMANCE_OFF CTL_CODE(IOCTL_DISK_BASE, 0x0018, METHOD_BUFFERED, FILE_ANY_ACCESS) - - - -#if(_WIN32_WINNT >= 0x0400) -#define IOCTL_DISK_CONTROLLER_NUMBER CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// -// IOCTL support for SMART drive fault prediction. -// - -#define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) -#define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#endif /* _WIN32_WINNT >= 0x0400 */ - -#if (_WIN32_WINNT >= 0x500) - -// -// New IOCTLs for GUID Partition tabled disks. -// - -#define IOCTL_DISK_GET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_SET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0014, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_SET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_CREATE_DISK CTL_CODE(IOCTL_DISK_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#endif /* _WIN32_WINNT >= 0x0500 */ - - -#if (_WIN32_WINNT >= 0x0502) - -// -// New IOCTL for disk devices that support 8 byte LBA -// -#define IOCTL_DISK_REASSIGN_BLOCKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x0029, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#endif //_WIN32_WINNT >= 0x0502 - -#if(_WIN32_WINNT >= 0x0500) -#define IOCTL_DISK_UPDATE_DRIVE_SIZE CTL_CODE(IOCTL_DISK_BASE, 0x0032, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GROW_PARTITION CTL_CODE(IOCTL_DISK_BASE, 0x0034, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_DISK_GET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0035, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0036, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#if (NTDDI_VERSION < NTDDI_WIN2003) -#define IOCTL_DISK_GET_WRITE_CACHE_STATE CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS) -#else -#define OBSOLETE_DISK_GET_WRITE_CACHE_STATE CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS) -#endif -#define IOCTL_DISK_DELETE_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0040, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// Called to flush cached information that the driver may have about this -// device's characteristics. Not all drivers cache characteristics, and not -// cached properties can be flushed. This simply serves as an update to the -// driver that it may want to do an expensive reexamination of the device's -// characteristics now (fixed media size, partition table, etc...) -// - -#define IOCTL_DISK_UPDATE_PROPERTIES CTL_CODE(IOCTL_DISK_BASE, 0x0050, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// -// Special IOCTLs needed to support PC-98 machines in Japan -// - -#define IOCTL_DISK_FORMAT_DRIVE CTL_CODE(IOCTL_DISK_BASE, 0x00f3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_SENSE_DEVICE CTL_CODE(IOCTL_DISK_BASE, 0x00f8, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#endif /* _WIN32_WINNT >= 0x0500 */ - -// end_winioctl - -// -// IOCTLs to report and modify our caching behavior -// - -#define IOCTL_DISK_GET_CACHE_SETTING CTL_CODE(IOCTL_DISK_BASE, 0x0038, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_CACHE_SETTING CTL_CODE(IOCTL_DISK_BASE, 0x0039, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -typedef enum _DISK_CACHE_STATE { - - DiskCacheNormal, - DiskCacheWriteThroughNotSupported, - DiskCacheModifyUnsuccessful - -} DISK_CACHE_STATE, *PDISK_CACHE_STATE; - -typedef struct _DISK_CACHE_SETTING { - - // - // The size of this structure is used for versioning - // - ULONG Version; - - // - // Indicates whether there are any issues with the disk cache - // - DISK_CACHE_STATE State; - - // - // Indicates whether the disk cache is power protected or not - // - BOOLEAN IsPowerProtected; - -} DISK_CACHE_SETTING, *PDISK_CACHE_SETTING; - - -// -// IOCTL for moving copying a run of sectors from one location of the disk -// to another. The caller of this IOCTL needs to be prepared for the call to -// fail and do the copy manually since this IOCTL will only rarely be -// implemented. -// - -#define IOCTL_DISK_COPY_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0019, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// This structure is passed in for a IOCTL_DISK_COPY_DATA call. -// - -typedef struct _DISK_COPY_DATA_PARAMETERS { - - // - // Byte offset from which to start the copy. - // - LARGE_INTEGER SourceOffset; - - // - // Byte offset of the copy destination. - // - LARGE_INTEGER DestinationOffset; - - // - // Length, in bytes, of the copy. - // - LARGE_INTEGER CopyLength; - - // - // Must be 0. - // - ULONGLONG Reserved; - - -} DISK_COPY_DATA_PARAMETERS, *PDISK_COPY_DATA_PARAMETERS; - -// -// Internal disk driver device controls to maintain the verify status bit -// for the device object. -// - -#define IOCTL_DISK_INTERNAL_SET_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS) -#define IOCTL_DISK_INTERNAL_CLEAR_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0101, METHOD_NEITHER, FILE_ANY_ACCESS) - -// -// Internal disk driver device control to set notification routine for -// the device object. Used in DiskPerf. -// - -#define IOCTL_DISK_INTERNAL_SET_NOTIFY CTL_CODE(IOCTL_DISK_BASE, 0x0102, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// begin_winioctl -// -// The following device control codes are common for all class drivers. The -// functions codes defined here must match all of the other class drivers. -// -// Warning: these codes will be replaced in the future by equivalent -// IOCTL_STORAGE codes -// - -#define IOCTL_DISK_CHECK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_MEDIA_REMOVAL CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_EJECT_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_LOAD_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_RESERVE CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_RELEASE CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_FIND_NEW_DEVICES CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_GET_MEDIA_TYPES CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// end_winioctl - -// -// The following file contains the IOCTL_STORAGE class ioctls -// - -#include - -// begin_winioctl -// -// Define the partition types returnable by known disk drivers. -// - -#define PARTITION_ENTRY_UNUSED 0x00 // Entry unused -#define PARTITION_FAT_12 0x01 // 12-bit FAT entries -#define PARTITION_XENIX_1 0x02 // Xenix -#define PARTITION_XENIX_2 0x03 // Xenix -#define PARTITION_FAT_16 0x04 // 16-bit FAT entries -#define PARTITION_EXTENDED 0x05 // Extended partition entry -#define PARTITION_HUGE 0x06 // Huge partition MS-DOS V4 -#define PARTITION_IFS 0x07 // IFS Partition -#define PARTITION_OS2BOOTMGR 0x0A // OS/2 Boot Manager/OPUS/Coherent swap -#define PARTITION_FAT32 0x0B // FAT32 -#define PARTITION_FAT32_XINT13 0x0C // FAT32 using extended int13 services -#define PARTITION_XINT13 0x0E // Win95 partition using extended int13 services -#define PARTITION_XINT13_EXTENDED 0x0F // Same as type 5 but uses extended int13 services -#define PARTITION_PREP 0x41 // PowerPC Reference Platform (PReP) Boot Partition -#define PARTITION_LDM 0x42 // Logical Disk Manager partition -#define PARTITION_UNIX 0x63 // Unix - -#define VALID_NTFT 0xC0 // NTFT uses high order bits - -// -// The high bit of the partition type code indicates that a partition -// is part of an NTFT mirror or striped array. -// - -#define PARTITION_NTFT 0x80 // NTFT partition - -// -// The following macro is used to determine which partitions should be -// assigned drive letters. -// - -//++ -// -// BOOLEAN -// IsRecognizedPartition( -// IN ULONG PartitionType -// ) -// -// Routine Description: -// -// This macro is used to determine to which partitions drive letters -// should be assigned. -// -// Arguments: -// -// PartitionType - Supplies the type of the partition being examined. -// -// Return Value: -// -// The return value is TRUE if the partition type is recognized, -// otherwise FALSE is returned. -// -//-- -#if (NTDDK_VERSION < NTDDI_VISTA) -#define IsRecognizedPartition( PartitionType ) ( \ - ((PartitionType & PARTITION_NTFT) && (((PartitionType & ~0xC0) == PARTITION_HUGE) || \ - ((PartitionType & ~0xC0) == PARTITION_IFS) || \ - ((PartitionType & ~0xC0) == PARTITION_FAT32) || \ - ((PartitionType & ~0xC0) == PARTITION_FAT32_XINT13))) || \ - ((PartitionType) == PARTITION_FAT_12) || \ - ((PartitionType) == PARTITION_FAT_16) || \ - ((PartitionType) == PARTITION_HUGE) || \ - ((PartitionType) == PARTITION_IFS) || \ - ((PartitionType) == PARTITION_FAT32) || \ - ((PartitionType) == PARTITION_FAT32_XINT13) || \ - ((PartitionType) == PARTITION_XINT13) ) -#else -#define IsRecognizedPartition( PartitionType ) ( \ - ((PartitionType) == PARTITION_FAT_12) || \ - ((PartitionType) == PARTITION_FAT_16) || \ - ((PartitionType) == PARTITION_HUGE) || \ - ((PartitionType) == PARTITION_IFS) || \ - ((PartitionType) == PARTITION_FAT32) || \ - ((PartitionType) == PARTITION_FAT32_XINT13) || \ - ((PartitionType) == PARTITION_XINT13) ) -#endif - -//++ -// -// BOOLEAN -// IsContainerPartition( -// IN ULONG PartitionType -// ) -// -// Routine Description: -// -// This macro is used to determine to which partition types are actually -// containers for other partitions (ie, extended partitions). -// -// Arguments: -// -// PartitionType - Supplies the type of the partition being examined. -// -// Return Value: -// -// The return value is TRUE if the partition type is a container, -// otherwise FALSE is returned. -// -//-- - -#define IsContainerPartition( PartitionType ) \ - ((PartitionType == PARTITION_EXTENDED) || (PartitionType == PARTITION_XINT13_EXTENDED)) - -//++ -// -// BOOLEAN -// IsFTPartition( -// IN ULONG PartitionType -// ) -// -// Routine Description: -// -// This macro is used to determine if the given partition is an FT -// partition. -// -// Arguments: -// -// PartitionType - Supplies the type of the partition being examined. -// -// Return Value: -// -// The return value is TRUE if the partition type is an FT partition, -// otherwise FALSE is returned. -// -//-- - -#define IsFTPartition( PartitionType ) \ - ((PartitionType & PARTITION_NTFT) && (((PartitionType & ~0xC0) == PARTITION_HUGE) || \ - ((PartitionType & ~0xC0) == PARTITION_IFS) || \ - ((PartitionType & ~0xC0) == PARTITION_FAT32) || \ - ((PartitionType & ~0xC0) == PARTITION_FAT32_XINT13))) - -// -// Define the media types supported by the driver. -// - -typedef enum _MEDIA_TYPE { - Unknown, // Format is unknown - F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector - F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector - F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector - F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector - F3_720_512, // 3.5", 720KB, 512 bytes/sector - F5_360_512, // 5.25", 360KB, 512 bytes/sector - F5_320_512, // 5.25", 320KB, 512 bytes/sector - F5_320_1024, // 5.25", 320KB, 1024 bytes/sector - F5_180_512, // 5.25", 180KB, 512 bytes/sector - F5_160_512, // 5.25", 160KB, 512 bytes/sector - RemovableMedia, // Removable media other than floppy - FixedMedia, // Fixed hard disk media - F3_120M_512, // 3.5", 120M Floppy - F3_640_512, // 3.5" , 640KB, 512 bytes/sector - F5_640_512, // 5.25", 640KB, 512 bytes/sector - F5_720_512, // 5.25", 720KB, 512 bytes/sector - F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector - F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector - F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector - F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector - F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector - F8_256_128, // 8", 256KB, 128 bytes/sector - F3_200Mb_512, // 3.5", 200M Floppy (HiFD) - F3_240M_512, // 3.5", 240Mb Floppy (HiFD) - F3_32M_512 // 3.5", 32Mb Floppy -} MEDIA_TYPE, *PMEDIA_TYPE; - -// -// Define the input buffer structure for the driver, when -// it is called with IOCTL_DISK_FORMAT_TRACKS. -// - -typedef struct _FORMAT_PARAMETERS { - MEDIA_TYPE MediaType; - ULONG StartCylinderNumber; - ULONG EndCylinderNumber; - ULONG StartHeadNumber; - ULONG EndHeadNumber; -} FORMAT_PARAMETERS, *PFORMAT_PARAMETERS; - -// -// Define the BAD_TRACK_NUMBER type. An array of elements of this type is -// returned by the driver on IOCTL_DISK_FORMAT_TRACKS requests, to indicate -// what tracks were bad during formatting. The length of that array is -// reported in the `Information' field of the I/O Status Block. -// - -typedef USHORT BAD_TRACK_NUMBER; -typedef USHORT *PBAD_TRACK_NUMBER; - -// -// Define the input buffer structure for the driver, when -// it is called with IOCTL_DISK_FORMAT_TRACKS_EX. -// - -typedef struct _FORMAT_EX_PARAMETERS { - MEDIA_TYPE MediaType; - ULONG StartCylinderNumber; - ULONG EndCylinderNumber; - ULONG StartHeadNumber; - ULONG EndHeadNumber; - USHORT FormatGapLength; - USHORT SectorsPerTrack; - USHORT SectorNumber[1]; -} FORMAT_EX_PARAMETERS, *PFORMAT_EX_PARAMETERS; - -// -// The following structure is returned on an IOCTL_DISK_GET_DRIVE_GEOMETRY -// request and an array of them is returned on an IOCTL_DISK_GET_MEDIA_TYPES -// request. -// - -typedef struct _DISK_GEOMETRY { - LARGE_INTEGER Cylinders; - MEDIA_TYPE MediaType; - ULONG TracksPerCylinder; - ULONG SectorsPerTrack; - ULONG BytesPerSector; -} DISK_GEOMETRY, *PDISK_GEOMETRY; - - - -// -// This wmi guid returns a DISK_GEOMETRY structure -// -#define WMI_DISK_GEOMETRY_GUID { 0x25007f51, 0x57c2, 0x11d1, { 0xa5, 0x28, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 } } - - - -// -// The following structure is returned on an IOCTL_DISK_GET_PARTITION_INFO -// and an IOCTL_DISK_GET_DRIVE_LAYOUT request. It is also used in a request -// to change the drive layout, IOCTL_DISK_SET_DRIVE_LAYOUT. -// - -typedef struct _PARTITION_INFORMATION { - LARGE_INTEGER StartingOffset; - LARGE_INTEGER PartitionLength; - ULONG HiddenSectors; - ULONG PartitionNumber; - UCHAR PartitionType; - BOOLEAN BootIndicator; - BOOLEAN RecognizedPartition; - BOOLEAN RewritePartition; -} PARTITION_INFORMATION, *PPARTITION_INFORMATION; - -// -// The following structure is used to change the partition type of a -// specified disk partition using an IOCTL_DISK_SET_PARTITION_INFO -// request. -// - -typedef struct _SET_PARTITION_INFORMATION { - UCHAR PartitionType; -} SET_PARTITION_INFORMATION, *PSET_PARTITION_INFORMATION; - -// -// The following structures is returned on an IOCTL_DISK_GET_DRIVE_LAYOUT -// request and given as input to an IOCTL_DISK_SET_DRIVE_LAYOUT request. -// - -typedef struct _DRIVE_LAYOUT_INFORMATION { - ULONG PartitionCount; - ULONG Signature; - PARTITION_INFORMATION PartitionEntry[1]; -} DRIVE_LAYOUT_INFORMATION, *PDRIVE_LAYOUT_INFORMATION; - -// -// The following structure is passed in on an IOCTL_DISK_VERIFY request. -// The offset and length parameters are both given in bytes. -// - -typedef struct _VERIFY_INFORMATION { - LARGE_INTEGER StartingOffset; - ULONG Length; -} VERIFY_INFORMATION, *PVERIFY_INFORMATION; - -// -// The following structure is passed in on an IOCTL_DISK_REASSIGN_BLOCKS -// request. -// - -typedef struct _REASSIGN_BLOCKS { - USHORT Reserved; - USHORT Count; - ULONG BlockNumber[1]; -} REASSIGN_BLOCKS, *PREASSIGN_BLOCKS; - -// -// The following structure is passed in on an IOCTL_DISK_REASSIGN_BLOCKS_EX -// request. -// - -#include -typedef struct _REASSIGN_BLOCKS_EX { - USHORT Reserved; - USHORT Count; - LARGE_INTEGER BlockNumber[1]; -} REASSIGN_BLOCKS_EX, *PREASSIGN_BLOCKS_EX; -#include - - -#if(_WIN32_WINNT >= 0x500) - -// -// Support for GUID Partition Table (GPT) disks. -// - -// -// There are currently two ways a disk can be partitioned. With a traditional -// AT-style master boot record (PARTITION_STYLE_MBR) and with a new, GPT -// partition table (PARTITION_STYLE_GPT). RAW is for an unrecognizable -// partition style. There are a very limited number of things you can -// do with a RAW partititon. -// - -typedef enum _PARTITION_STYLE { - PARTITION_STYLE_MBR, - PARTITION_STYLE_GPT, - PARTITION_STYLE_RAW -} PARTITION_STYLE; - - -// -// The following structure defines information in a GPT partition that is -// not common to both GPT and MBR partitions. -// - -typedef struct _PARTITION_INFORMATION_GPT { - GUID PartitionType; // Partition type. See table 16-3. - GUID PartitionId; // Unique GUID for this partition. - ULONG64 Attributes; // See table 16-4. - WCHAR Name [36]; // Partition Name in Unicode. -} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT; - -// -// The following are GPT partition attributes applicable for any -// partition type. These attributes are not OS-specific -// - -#define GPT_ATTRIBUTE_PLATFORM_REQUIRED (0x0000000000000001) - -// -// The following are GPT partition attributes applicable when the -// PartitionType is PARTITION_BASIC_DATA_GUID. -// - -#define GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER (0x8000000000000000) -#define GPT_BASIC_DATA_ATTRIBUTE_HIDDEN (0x4000000000000000) -#define GPT_BASIC_DATA_ATTRIBUTE_SHADOW_COPY (0x2000000000000000) -#define GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY (0x1000000000000000) - -// -// The following structure defines information in an MBR partition that is not -// common to both GPT and MBR partitions. -// - -typedef struct _PARTITION_INFORMATION_MBR { - UCHAR PartitionType; - BOOLEAN BootIndicator; - BOOLEAN RecognizedPartition; - ULONG HiddenSectors; -} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR; - - -// -// The structure SET_PARTITION_INFO_EX is used with the ioctl -// IOCTL_SET_PARTITION_INFO_EX to set information about a specific -// partition. Note that for MBR partitions, you can only set the partition -// signature, whereas GPT partitions allow setting of all fields that -// you can get. -// - -typedef SET_PARTITION_INFORMATION SET_PARTITION_INFORMATION_MBR; -typedef PARTITION_INFORMATION_GPT SET_PARTITION_INFORMATION_GPT; - - -typedef struct _SET_PARTITION_INFORMATION_EX { - PARTITION_STYLE PartitionStyle; - union { - SET_PARTITION_INFORMATION_MBR Mbr; - SET_PARTITION_INFORMATION_GPT Gpt; - } DUMMYUNIONNAME; -} SET_PARTITION_INFORMATION_EX, *PSET_PARTITION_INFORMATION_EX; - - -// -// The structure CREATE_DISK_GPT with the ioctl IOCTL_DISK_CREATE_DISK -// to initialize an virgin disk with an empty GPT partition table. -// - -typedef struct _CREATE_DISK_GPT { - GUID DiskId; // Unique disk id for the disk. - ULONG MaxPartitionCount; // Maximim number of partitions allowable. -} CREATE_DISK_GPT, *PCREATE_DISK_GPT; - -// -// The structure CREATE_DISK_MBR with the ioctl IOCTL_DISK_CREATE_DISK -// to initialize an virgin disk with an empty MBR partition table. -// - -typedef struct _CREATE_DISK_MBR { - ULONG Signature; -} CREATE_DISK_MBR, *PCREATE_DISK_MBR; - - -typedef struct _CREATE_DISK { - PARTITION_STYLE PartitionStyle; - union { - CREATE_DISK_MBR Mbr; - CREATE_DISK_GPT Gpt; - } DUMMYUNIONNAME; -} CREATE_DISK, *PCREATE_DISK; - - -// -// The structure GET_LENGTH_INFORMATION is used with the ioctl -// IOCTL_DISK_GET_LENGTH_INFO to obtain the length, in bytes, of the -// disk, partition, or volume. -// - -typedef struct _GET_LENGTH_INFORMATION { - LARGE_INTEGER Length; -} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION; - -// -// The PARTITION_INFORMATION_EX structure is used with the -// IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, -// IOCTL_DISK_GET_PARTITION_INFO_EX and IOCTL_DISK_GET_PARTITION_INFO_EX calls. -// - -typedef struct _PARTITION_INFORMATION_EX { - PARTITION_STYLE PartitionStyle; - LARGE_INTEGER StartingOffset; - LARGE_INTEGER PartitionLength; - ULONG PartitionNumber; - BOOLEAN RewritePartition; - union { - PARTITION_INFORMATION_MBR Mbr; - PARTITION_INFORMATION_GPT Gpt; - } DUMMYUNIONNAME; -} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX; - - -// -// GPT specific drive layout information. -// - -typedef struct _DRIVE_LAYOUT_INFORMATION_GPT { - GUID DiskId; - LARGE_INTEGER StartingUsableOffset; - LARGE_INTEGER UsableLength; - ULONG MaxPartitionCount; -} DRIVE_LAYOUT_INFORMATION_GPT, *PDRIVE_LAYOUT_INFORMATION_GPT; - - -// -// MBR specific drive layout information. -// - -typedef struct _DRIVE_LAYOUT_INFORMATION_MBR { - ULONG Signature; -} DRIVE_LAYOUT_INFORMATION_MBR, *PDRIVE_LAYOUT_INFORMATION_MBR; - -// -// The structure DRIVE_LAYOUT_INFORMATION_EX is used with the -// IOCTL_SET_DRIVE_LAYOUT_EX and IOCTL_GET_DRIVE_LAYOUT_EX calls. -// - -typedef struct _DRIVE_LAYOUT_INFORMATION_EX { - ULONG PartitionStyle; - ULONG PartitionCount; - union { - DRIVE_LAYOUT_INFORMATION_MBR Mbr; - DRIVE_LAYOUT_INFORMATION_GPT Gpt; - } DUMMYUNIONNAME; - PARTITION_INFORMATION_EX PartitionEntry[1]; -} DRIVE_LAYOUT_INFORMATION_EX, *PDRIVE_LAYOUT_INFORMATION_EX; - - -#endif // (_WIN32_WINNT >= 0x0500) - - -#if(_WIN32_WINNT >= 0x0500) - -// -// The DISK_GEOMETRY_EX structure is returned on issuing an -// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX ioctl. -// - -typedef enum _DETECTION_TYPE { - DetectNone, - DetectInt13, - DetectExInt13 -} DETECTION_TYPE; - -typedef struct _DISK_INT13_INFO { - USHORT DriveSelect; - ULONG MaxCylinders; - USHORT SectorsPerTrack; - USHORT MaxHeads; - USHORT NumberDrives; -} DISK_INT13_INFO, *PDISK_INT13_INFO; - -typedef struct _DISK_EX_INT13_INFO { - USHORT ExBufferSize; - USHORT ExFlags; - ULONG ExCylinders; - ULONG ExHeads; - ULONG ExSectorsPerTrack; - ULONG64 ExSectorsPerDrive; - USHORT ExSectorSize; - USHORT ExReserved; -} DISK_EX_INT13_INFO, *PDISK_EX_INT13_INFO; - -#if (_MSC_VER >= 1200) -#pragma warning(push) -#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union -#endif - -typedef struct _DISK_DETECTION_INFO { - ULONG SizeOfDetectInfo; - DETECTION_TYPE DetectionType; - union { - struct { - - // - // If DetectionType == DETECTION_INT13 then we have just the Int13 - // information. - // - - DISK_INT13_INFO Int13; - - // - // If DetectionType == DETECTION_EX_INT13, then we have the - // extended int 13 information. - // - - DISK_EX_INT13_INFO ExInt13; // If DetectionType == DetectExInt13 - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; -} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO; - - -typedef struct _DISK_PARTITION_INFO { - ULONG SizeOfPartitionInfo; - PARTITION_STYLE PartitionStyle; // PartitionStyle = RAW, GPT or MBR - union { - struct { // If PartitionStyle == MBR - ULONG Signature; // MBR Signature - ULONG CheckSum; // MBR CheckSum - } Mbr; - struct { // If PartitionStyle == GPT - GUID DiskId; - } Gpt; - } DUMMYUNIONNAME; -} DISK_PARTITION_INFO, *PDISK_PARTITION_INFO; - -#if (_MSC_VER >= 1200) -#pragma warning(pop) -#endif - -// -// The Geometry structure is a variable length structure composed of a -// DISK_GEOMETRY_EX structure followed by a DISK_PARTITION_INFO structure -// followed by a DISK_DETECTION_DATA structure. -// - -#if (NTDDI_VERSION < NTDDI_WIN2003) -#define DiskGeometryGetPartition(Geometry)\ - ((PDISK_PARTITION_INFO)((Geometry)+1)) - -#define DiskGeometryGetDetect(Geometry)\ - ((PDISK_DETECTION_INFO)(((PBYTE)DiskGeometryGetPartition(Geometry)+\ - DiskGeometryGetPartition(Geometry)->SizeOfPartitionInfo))) -#else -#define DiskGeometryGetPartition(Geometry)\ - ((PDISK_PARTITION_INFO)((Geometry)->Data)) - -#define DiskGeometryGetDetect(Geometry)\ - ((PDISK_DETECTION_INFO)(((ULONG_PTR)DiskGeometryGetPartition(Geometry)+\ - DiskGeometryGetPartition(Geometry)->SizeOfPartitionInfo))) -#endif -typedef struct _DISK_GEOMETRY_EX { - DISK_GEOMETRY Geometry; // Standard disk geometry: may be faked by driver. - LARGE_INTEGER DiskSize; // Must always be correct - UCHAR Data[1]; // Partition, Detect info -} DISK_GEOMETRY_EX, *PDISK_GEOMETRY_EX; - -#endif // (_WIN32_WINNT > 0x0500) - -#if(_WIN32_WINNT >= 0x0400) -// -// IOCTL_DISK_CONTROLLER_NUMBER returns the controller and disk -// number for the handle. This is used to determine if a disk -// is attached to the primary or secondary IDE controller. -// - -typedef struct _DISK_CONTROLLER_NUMBER { - ULONG ControllerNumber; - ULONG DiskNumber; -} DISK_CONTROLLER_NUMBER, *PDISK_CONTROLLER_NUMBER; -#endif /* _WIN32_WINNT >= 0x0400 */ - -#if(_WIN32_WINNT >= 0x0500) - -// -// IOCTL_DISK_SET_CACHE_INFORMATION -// -// Input Buffer: -// A DISK_CACHE_INFORMATION structure which describes how the disk -// read/write caches should be configured. -// -// Output Buffer: -// None -// - -// -// IOCTL_DISK_GET_CACHE_INFORMATION -// -// Input Buffer: -// None -// -// Output Buffer: -// A DISK_CACHE_INFORMATION structure which contains the current state -// of the disk read/write caches. -// - -typedef enum { - EqualPriority, - KeepPrefetchedData, - KeepReadData -} DISK_CACHE_RETENTION_PRIORITY; - -#if (OSVER(NTDDI_VERSION) == NTDDI_WINXP) -typedef enum _DISK_WRITE_CACHE_STATE { - DiskWriteCacheNormal, - DiskWriteCacheForceDisable, - DiskWriteCacheDisableNotSupported -} DISK_WRITE_CACHE_STATE, *PDISK_WRITE_CACHE_STATE; -#endif - -typedef struct _DISK_CACHE_INFORMATION { - - // - // on return indicates that the device is capable of saving any parameters - // in non-volatile storage. On send indicates that the device should - // save the state in non-volatile storage. - // - - BOOLEAN ParametersSavable; - - // - // Indicates whether the write and read caches are enabled. - // - - BOOLEAN ReadCacheEnabled; - BOOLEAN WriteCacheEnabled; - - // - // Controls the likelyhood of data remaining in the cache depending on how - // it got there. Data cached from a READ or WRITE operation may be given - // higher, lower or equal priority to data entered into the cache for other - // means (like prefetch) - // - - DISK_CACHE_RETENTION_PRIORITY ReadRetentionPriority; - DISK_CACHE_RETENTION_PRIORITY WriteRetentionPriority; - - // - // Requests for a larger number of blocks than this may have prefetching - // disabled. If this value is set to 0 prefetch will be disabled. - // - - USHORT DisablePrefetchTransferLength; - - // - // If TRUE then ScalarPrefetch (below) will be valid. If FALSE then - // the minimum and maximum values should be treated as a block count - // (BlockPrefetch) - // - - BOOLEAN PrefetchScalar; - - // - // Contains the minimum and maximum amount of data which will be - // will be prefetched into the cache on a disk operation. This value - // may either be a scalar multiplier of the transfer length of the request, - // or an abolute number of disk blocks. PrefetchScalar (above) indicates - // which interpretation is used. - // - - union { - struct { - USHORT Minimum; - USHORT Maximum; - - // - // The maximum number of blocks which will be prefetched - useful - // with the scalar limits to set definite upper limits. - // - - USHORT MaximumBlocks; - } ScalarPrefetch; - - struct { - USHORT Minimum; - USHORT Maximum; - } BlockPrefetch; - } DUMMYUNIONNAME; - -} DISK_CACHE_INFORMATION, *PDISK_CACHE_INFORMATION; - -// -// IOCTL_DISK_GROW_PARTITION will update the size of a partition -// by adding sectors to the length. The number of sectors must be -// predetermined by examining PARTITION_INFORMATION. -// - -typedef struct _DISK_GROW_PARTITION { - ULONG PartitionNumber; - LARGE_INTEGER BytesToGrow; -} DISK_GROW_PARTITION, *PDISK_GROW_PARTITION; -#endif /* _WIN32_WINNT >= 0x0500 */ - -/////////////////////////////////////////////////////// -// // -// The following structures define disk performance // -// statistics: specifically the locations of all the // -// reads and writes which have occured on the disk. // -// // -// To use these structures, you must issue an IOCTL_ // -// DISK_HIST_STRUCTURE (with a DISK_HISTOGRAM) to // -// obtain the basic histogram information. The // -// number of buckets which must allocated is part of // -// this structure. Allocate the required number of // -// buckets and call an IOCTL_DISK_HIST_DATA to fill // -// in the data // -// // -/////////////////////////////////////////////////////// - -#define HIST_NO_OF_BUCKETS 24 - -typedef struct _HISTOGRAM_BUCKET { - ULONG Reads; - ULONG Writes; -} HISTOGRAM_BUCKET, *PHISTOGRAM_BUCKET; - -#define HISTOGRAM_BUCKET_SIZE sizeof(HISTOGRAM_BUCKET) - -typedef struct _DISK_HISTOGRAM { - LARGE_INTEGER DiskSize; - LARGE_INTEGER Start; - LARGE_INTEGER End; - LARGE_INTEGER Average; - LARGE_INTEGER AverageRead; - LARGE_INTEGER AverageWrite; - ULONG Granularity; - ULONG Size; - ULONG ReadCount; - ULONG WriteCount; - PHISTOGRAM_BUCKET Histogram; -} DISK_HISTOGRAM, *PDISK_HISTOGRAM; - -#define DISK_HISTOGRAM_SIZE sizeof(DISK_HISTOGRAM) - -/////////////////////////////////////////////////////// -// // -// The following structures define disk debugging // -// capabilities. The IOCTLs are directed to one of // -// the two disk filter drivers. // -// // -// DISKPERF is a utilty for collecting disk request // -// statistics. // -// // -// SIMBAD is a utility for injecting faults in // -// IO requests to disks. // -// // -/////////////////////////////////////////////////////// - -// -// The following structure is exchanged on an IOCTL_DISK_GET_PERFORMANCE -// request. This ioctl collects summary disk request statistics used -// in measuring performance. -// - -typedef struct _DISK_PERFORMANCE { - LARGE_INTEGER BytesRead; - LARGE_INTEGER BytesWritten; - LARGE_INTEGER ReadTime; - LARGE_INTEGER WriteTime; - LARGE_INTEGER IdleTime; - ULONG ReadCount; - ULONG WriteCount; - ULONG QueueDepth; - ULONG SplitCount; - LARGE_INTEGER QueryTime; - ULONG StorageDeviceNumber; - WCHAR StorageManagerName[8]; -} DISK_PERFORMANCE, *PDISK_PERFORMANCE; - -// -// This structure defines the disk logging record. When disk logging -// is enabled, one of these is written to an internal buffer for each -// disk request. -// - -typedef struct _DISK_RECORD { - LARGE_INTEGER ByteOffset; - LARGE_INTEGER StartTime; - LARGE_INTEGER EndTime; - PVOID VirtualAddress; - ULONG NumberOfBytes; - UCHAR DeviceNumber; - BOOLEAN ReadRequest; -} DISK_RECORD, *PDISK_RECORD; - -// -// The following structure is exchanged on an IOCTL_DISK_LOG request. -// Not all fields are valid with each function type. -// - -typedef struct _DISK_LOGGING { - UCHAR Function; - PVOID BufferAddress; - ULONG BufferSize; -} DISK_LOGGING, *PDISK_LOGGING; - -// -// Disk logging functions -// -// Start disk logging. Only the Function and BufferSize fields are valid. -// - -#define DISK_LOGGING_START 0 - -// -// Stop disk logging. Only the Function field is valid. -// - -#define DISK_LOGGING_STOP 1 - -// -// Return disk log. All fields are valid. Data will be copied from internal -// buffer to buffer specified for the number of bytes requested. -// - -#define DISK_LOGGING_DUMP 2 - -// -// DISK BINNING -// -// DISKPERF will keep counters for IO that falls in each of these ranges. -// The application determines the number and size of the ranges. -// Joe Lin wanted me to keep it flexible as possible, for instance, IO -// sizes are interesting in ranges like 0-4096, 4097-16384, 16385-65536, 65537+. -// - -#define DISK_BINNING 3 - -// -// Bin types -// - -typedef enum _BIN_TYPES { - RequestSize, - RequestLocation -} BIN_TYPES; - -// -// Bin ranges -// - -typedef struct _BIN_RANGE { - LARGE_INTEGER StartValue; - LARGE_INTEGER Length; -} BIN_RANGE, *PBIN_RANGE; - -// -// Bin definition -// - -typedef struct _PERF_BIN { - ULONG NumberOfBins; - ULONG TypeOfBin; - BIN_RANGE BinsRanges[1]; -} PERF_BIN, *PPERF_BIN ; - -// -// Bin count -// - -typedef struct _BIN_COUNT { - BIN_RANGE BinRange; - ULONG BinCount; -} BIN_COUNT, *PBIN_COUNT; - -// -// Bin results -// - -typedef struct _BIN_RESULTS { - ULONG NumberOfBins; - BIN_COUNT BinCounts[1]; -} BIN_RESULTS, *PBIN_RESULTS; - -#if(_WIN32_WINNT >= 0x0400) -// -// Data structures for SMART drive fault prediction. -// -// GETVERSIONINPARAMS contains the data returned from the -// Get Driver Version function. -// - -#include -typedef struct _GETVERSIONINPARAMS { - UCHAR bVersion; // Binary driver version. - UCHAR bRevision; // Binary driver revision. - UCHAR bReserved; // Not used. - UCHAR bIDEDeviceMap; // Bit map of IDE devices. - ULONG fCapabilities; // Bit mask of driver capabilities. - ULONG dwReserved[4]; // For future use. -} GETVERSIONINPARAMS, *PGETVERSIONINPARAMS, *LPGETVERSIONINPARAMS; -#include - -// -// Bits returned in the fCapabilities member of GETVERSIONINPARAMS -// - -#define CAP_ATA_ID_CMD 1 // ATA ID command supported -#define CAP_ATAPI_ID_CMD 2 // ATAPI ID command supported -#define CAP_SMART_CMD 4 // SMART commannds supported - -// -// IDE registers -// - -#include -typedef struct _IDEREGS { - UCHAR bFeaturesReg; // Used for specifying SMART "commands". - UCHAR bSectorCountReg; // IDE sector count register - UCHAR bSectorNumberReg; // IDE sector number register - UCHAR bCylLowReg; // IDE low order cylinder value - UCHAR bCylHighReg; // IDE high order cylinder value - UCHAR bDriveHeadReg; // IDE drive/head register - UCHAR bCommandReg; // Actual IDE command. - UCHAR bReserved; // reserved for future use. Must be zero. -} IDEREGS, *PIDEREGS, *LPIDEREGS; -#include - -// -// Valid values for the bCommandReg member of IDEREGS. -// - -#define ATAPI_ID_CMD 0xA1 // Returns ID sector for ATAPI. -#define ID_CMD 0xEC // Returns ID sector for ATA. -#define SMART_CMD 0xB0 // Performs SMART cmd. - // Requires valid bFeaturesReg, - // bCylLowReg, and bCylHighReg - -// -// Cylinder register defines for SMART command -// - -#define SMART_CYL_LOW 0x4F -#define SMART_CYL_HI 0xC2 - - -// -// SENDCMDINPARAMS contains the input parameters for the -// Send Command to Drive function. -// - -#include -typedef struct _SENDCMDINPARAMS { - ULONG cBufferSize; // Buffer size in bytes - IDEREGS irDriveRegs; // Structure with drive register values. - UCHAR bDriveNumber; // Physical drive number to send - // command to (0,1,2,3). - UCHAR bReserved[3]; // Reserved for future expansion. - ULONG dwReserved[4]; // For future use. - UCHAR bBuffer[1]; // Input buffer. -} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS; -#include - -// -// Status returned from driver -// - -#include -typedef struct _DRIVERSTATUS { - UCHAR bDriverError; // Error code from driver, - // or 0 if no error. - UCHAR bIDEError; // Contents of IDE Error register. - // Only valid when bDriverError - // is SMART_IDE_ERROR. - UCHAR bReserved[2]; // Reserved for future expansion. - ULONG dwReserved[2]; // Reserved for future expansion. -} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS; -#include - -// -// bDriverError values -// - -#define SMART_NO_ERROR 0 // No error -#define SMART_IDE_ERROR 1 // Error from IDE controller -#define SMART_INVALID_FLAG 2 // Invalid command flag -#define SMART_INVALID_COMMAND 3 // Invalid command byte -#define SMART_INVALID_BUFFER 4 // Bad buffer (null, invalid addr..) -#define SMART_INVALID_DRIVE 5 // Drive number not valid -#define SMART_INVALID_IOCTL 6 // Invalid IOCTL -#define SMART_ERROR_NO_MEM 7 // Could not lock user's buffer -#define SMART_INVALID_REGISTER 8 // Some IDE Register not valid -#define SMART_NOT_SUPPORTED 9 // Invalid cmd flag set -#define SMART_NO_IDE_DEVICE 10 // Cmd issued to device not present - // although drive number is valid -// -// SMART sub commands for execute offline diags -// -#define SMART_OFFLINE_ROUTINE_OFFLINE 0 -#define SMART_SHORT_SELFTEST_OFFLINE 1 -#define SMART_EXTENDED_SELFTEST_OFFLINE 2 -#define SMART_ABORT_OFFLINE_SELFTEST 127 -#define SMART_SHORT_SELFTEST_CAPTIVE 129 -#define SMART_EXTENDED_SELFTEST_CAPTIVE 130 - - -#include -typedef struct _SENDCMDOUTPARAMS { - ULONG cBufferSize; // Size of bBuffer in bytes - DRIVERSTATUS DriverStatus; // Driver status structure. - UCHAR bBuffer[1]; // Buffer of arbitrary length in which to store the data read from the // drive. -} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS; -#include - - -#define READ_ATTRIBUTE_BUFFER_SIZE 512 -#define IDENTIFY_BUFFER_SIZE 512 -#define READ_THRESHOLD_BUFFER_SIZE 512 -#define SMART_LOG_SECTOR_SIZE 512 - -// -// Feature register defines for SMART "sub commands" -// - -#define READ_ATTRIBUTES 0xD0 -#define READ_THRESHOLDS 0xD1 -#define ENABLE_DISABLE_AUTOSAVE 0xD2 -#define SAVE_ATTRIBUTE_VALUES 0xD3 -#define EXECUTE_OFFLINE_DIAGS 0xD4 -#define SMART_READ_LOG 0xD5 -#define SMART_WRITE_LOG 0xd6 -#define ENABLE_SMART 0xD8 -#define DISABLE_SMART 0xD9 -#define RETURN_SMART_STATUS 0xDA -#define ENABLE_DISABLE_AUTO_OFFLINE 0xDB -#endif /* _WIN32_WINNT >= 0x0400 */ - -// end_winioctl - - -#if (NTDDI_VERSION >= NTDDI_VISTA) - -// -// IOCTLs to query and modify attributes -// associated with partitions. These are -// persisted within the partition table. -// - -#define IOCTL_DISK_GET_PARTITION_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003a, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_SET_PARTITION_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// IOCTL_DISK_GET_PARTITION_ATTRIBUTES -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type GET_PARTITION_ATTRIBUTES -// - -typedef struct _GET_PARTITION_ATTRIBUTES { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // For alignment purposes. - // - ULONG Reserved1; - - // - // Specifies the partition - // attributes. - // - ULONGLONG Attributes; - -} GET_PARTITION_ATTRIBUTES, *PGET_PARTITION_ATTRIBUTES; - -// -// IOCTL_DISK_SET_PARTITION_ATTRIBUTES -// -// Input Buffer: -// Structure of type SET_PARTITION_ATTRIBUTES -// -// Output Buffer: -// None -// - -typedef struct _SET_PARTITION_ATTRIBUTES { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // Indicates whether to remember - // these settings across reboots - // or not. - // - BOOLEAN Persist; - - // - // For alignment purposes. - // - BOOLEAN Reserved1[3]; - - // - // Specifies the new attributes. - // - ULONGLONG Attributes; - - // - // Specifies the attributes - // that are being modified. - // - ULONGLONG AttributesMask; - -} SET_PARTITION_ATTRIBUTES, *PSET_PARTITION_ATTRIBUTES; - - -// -// IOCTLs to query and modify attributes -// associated with the given disk. These -// are persisted within the registry. -// - -#define IOCTL_DISK_GET_DISK_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003c, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_SET_DISK_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003d, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define DISK_ATTRIBUTE_OFFLINE 0x0000000000000001 -#define DISK_ATTRIBUTE_READ_ONLY 0x0000000000000002 - -// -// IOCTL_DISK_GET_DISK_ATTRIBUTES -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type GET_DISK_ATTRIBUTES -// - -typedef struct _GET_DISK_ATTRIBUTES { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // For alignment purposes. - // - ULONG Reserved1; - - // - // Specifies the attributes - // associated with the disk. - // - ULONGLONG Attributes; - -} GET_DISK_ATTRIBUTES, *PGET_DISK_ATTRIBUTES; - -// -// IOCTL_DISK_SET_DISK_ATTRIBUTES -// -// Input Buffer: -// Structure of type SET_DISK_ATTRIBUTES -// -// Output Buffer: -// None -// - -typedef struct _SET_DISK_ATTRIBUTES { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // Indicates whether to remember - // these settings across reboots - // or not. - // - BOOLEAN Persist; - - // - // Indicates whether the ownership - // taken earlier is being released. - // - BOOLEAN RelinquishOwnership; - - // - // For alignment purposes. - // - BOOLEAN Reserved1[2]; - - // - // Specifies the new attributes. - // - ULONGLONG Attributes; - - // - // Specifies the attributes - // that are being modified. - // - ULONGLONG AttributesMask; - - // - // Specifies an identifier to be - // associated with the caller. - // This setting is not persisted - // across reboots. - // - GUID Owner; - -} SET_DISK_ATTRIBUTES, *PSET_DISK_ATTRIBUTES; - - -// -// IOCTL to determine if the disk is -// owned by the cluster service or not. -// - -#define IOCTL_DISK_IS_CLUSTERED CTL_CODE(IOCTL_DISK_BASE, 0x003e, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// -// IOCTL_DISK_IS_CLUSTERED -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type BOOLEAN -// - - -// -// IOCTLs to query and modify the current -// SAN settings. For instance, the policy -// associated with newly discovered disks. -// - -#define IOCTL_DISK_GET_SAN_SETTINGS CTL_CODE(IOCTL_DISK_BASE, 0x0080, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_SAN_SETTINGS CTL_CODE(IOCTL_DISK_BASE, 0x0081, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// IOCTL_DISK_GET_SAN_SETTINGS -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type DISK_SAN_SETTINGS -// - -// -// IOCTL_DISK_SET_SAN_SETTINGS -// -// Input Buffer: -// Structure of type DISK_SAN_SETTINGS -// -// Output Buffer: -// None -// - -typedef enum _DISK_SAN_POLICY { - - DiskSanPolicyUnknown, - DiskSanPolicyOnline, - DiskSanPolicyOfflineShared, - DiskSanPolicyOffline, - DiskSanPolicyMax - -} DISK_SAN_POLICY, *PDISK_SAN_POLICY; - -typedef struct _DISK_SAN_SETTINGS { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // Specifies the policy to be - // applied to all new disks. - // - DISK_SAN_POLICY SanPolicy; - -} DISK_SAN_SETTINGS, *PDISK_SAN_SETTINGS; - - -// -// IOCTLs to query and modify the context -// associated with snapshot disks created -// in hardware. -// - -#define IOCTL_DISK_GET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0082, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0083, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// begin_winioctl - -#define IOCTL_DISK_RESET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0084, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// end_winioctl - -// -// IOCTL_DISK_GET_SNAPSHOT_INFO -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type DISK_SNAPSHOT_INFO -// - -// -// IOCTL_DISK_SET_SNAPSHOT_INFO -// -// Input Buffer: -// Structure of type DISK_SNAPSHOT_INFO -// -// Output Buffer: -// None -// - -typedef enum _DISK_SNAPSHOT_STATE { - - DiskSnapshotNormalDisk, - DiskSnapshotSnapshotCheckRequired, - DiskSnapshotPreSnapshot, - DiskSnapshotSnapshotDisk - -} DISK_SNAPSHOT_STATE, *PDISK_SNAPSHOT_STATE; - -typedef struct _DISK_SNAPSHOT_INFO { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // Specifies the state that this - // disk is in or the state to be - // transitioned to. - // - DISK_SNAPSHOT_STATE State; - - // - // Specifies a unique id that - // represents all of the disks - // involved in this snapshot. - // - GUID SnapshotSetId; - - // - // Specifies a unique id that - // represents this snapshot. - // - GUID SnapshotId; - - // - // Specifies a unique id that - // represents the logical unit - // whose snapshot was taken. - // - GUID LunId; - - // - // Specifies the time when this - // snapshot was taken. - // - LARGE_INTEGER CreationTimeStamp; - - // - // Specifies the number of times - // that this snapshot has been - // imported. - // - ULONG ImportCount; - - // - // Specifies attributes that are - // associated with this snapshot. - // - ULONG Flags; - - // - // Specifies the size in bytes of - // the following field. - // - ULONG AdditionalDataSize; - - // - // Specifies disk meta data that - // needs to be restored in the - // event of a fast recovery. - // - UCHAR AdditionalData[ANYSIZE_ARRAY]; - -} DISK_SNAPSHOT_INFO, *PDISK_SNAPSHOT_INFO; - -#endif // NTDDI_VERSION >= NTDDI_VISTA - - -// -// The following device control code is for the SIMBAD simulated bad -// sector facility. See SIMBAD.H in this directory for related structures. -// - -#define IOCTL_DISK_SIMBAD CTL_CODE(IOCTL_DISK_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// Queue link for mapped addresses stored for unmapping. -// - -typedef struct _MAPPED_ADDRESS { - struct _MAPPED_ADDRESS *NextMappedAddress; - PVOID MappedAddress; - ULONG NumberOfBytes; - LARGE_INTEGER IoAddress; - ULONG BusNumber; -} MAPPED_ADDRESS, *PMAPPED_ADDRESS; - -// begin_winioctl - -#if defined(_MSC_VER) -#if (_MSC_VER >= 1200) -#pragma warning(pop) -#endif -#endif - -// end_winioctl - -#ifdef __cplusplus -} -#endif - -// begin_winioctl - -#endif // _NTDDDISK_H_ - -// end_winioctl - +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntdddisk.h + +Abstract: + + This is the include file that defines all constants and types for + accessing the Disk device. + +Revision History: + +--*/ + + +// begin_winioctl + +#ifndef _NTDDDISK_H_ +#define _NTDDDISK_H_ + +// end_winioctl + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if (NTDDI_VERSION >= NTDDI_WINXP) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// begin_winioctl + +#if defined(_MSC_VER) +#if (_MSC_VER >= 1200) +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable:4214) // nonstandard extension used : bitfield other than int +#endif +#endif + +// end_winioctl + +// +// Device Name - this string is the name of the device. It is the name +// that should be passed to NtOpenFile when accessing the device. +// +// Note: For devices that support multiple units, it should be suffixed +// with the Ascii representation of the unit number. +// + +#define DD_DISK_DEVICE_NAME "\\Device\\UNKNOWN" + + +// +// NtDeviceIoControlFile + +// begin_winioctl + +// +// IoControlCode values for disk devices. +// + +#define IOCTL_DISK_BASE FILE_DEVICE_DISK +#define IOCTL_DISK_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_GET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_FORMAT_TRACKS CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_REASSIGN_BLOCKS CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_PERFORMANCE CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_IS_WRITABLE CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_LOGGING CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_FORMAT_TRACKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_HISTOGRAM_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_HISTOGRAM_DATA CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_HISTOGRAM_RESET CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_REQUEST_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_REQUEST_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_PERFORMANCE_OFF CTL_CODE(IOCTL_DISK_BASE, 0x0018, METHOD_BUFFERED, FILE_ANY_ACCESS) + + + +#if(_WIN32_WINNT >= 0x0400) +#define IOCTL_DISK_CONTROLLER_NUMBER CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL support for SMART drive fault prediction. +// + +#define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) +#define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#endif /* _WIN32_WINNT >= 0x0400 */ + +#if (_WIN32_WINNT >= 0x500) + +// +// New IOCTLs for GUID Partition tabled disks. +// + +#define IOCTL_DISK_GET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_SET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0014, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_SET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_CREATE_DISK CTL_CODE(IOCTL_DISK_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif /* _WIN32_WINNT >= 0x0500 */ + + +#if (_WIN32_WINNT >= 0x0502) + +// +// New IOCTL for disk devices that support 8 byte LBA +// +#define IOCTL_DISK_REASSIGN_BLOCKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x0029, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#endif //_WIN32_WINNT >= 0x0502 + +#if(_WIN32_WINNT >= 0x0500) +#define IOCTL_DISK_UPDATE_DRIVE_SIZE CTL_CODE(IOCTL_DISK_BASE, 0x0032, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GROW_PARTITION CTL_CODE(IOCTL_DISK_BASE, 0x0034, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_DISK_GET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0035, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0036, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#if (NTDDI_VERSION < NTDDI_WIN2003) +#define IOCTL_DISK_GET_WRITE_CACHE_STATE CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS) +#else +#define OBSOLETE_DISK_GET_WRITE_CACHE_STATE CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS) +#endif +#define IOCTL_DISK_DELETE_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0040, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// Called to flush cached information that the driver may have about this +// device's characteristics. Not all drivers cache characteristics, and not +// cached properties can be flushed. This simply serves as an update to the +// driver that it may want to do an expensive reexamination of the device's +// characteristics now (fixed media size, partition table, etc...) +// + +#define IOCTL_DISK_UPDATE_PROPERTIES CTL_CODE(IOCTL_DISK_BASE, 0x0050, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// Special IOCTLs needed to support PC-98 machines in Japan +// + +#define IOCTL_DISK_FORMAT_DRIVE CTL_CODE(IOCTL_DISK_BASE, 0x00f3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_SENSE_DEVICE CTL_CODE(IOCTL_DISK_BASE, 0x00f8, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif /* _WIN32_WINNT >= 0x0500 */ + +// end_winioctl + +// +// IOCTLs to report and modify our caching behavior +// + +#define IOCTL_DISK_GET_CACHE_SETTING CTL_CODE(IOCTL_DISK_BASE, 0x0038, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_CACHE_SETTING CTL_CODE(IOCTL_DISK_BASE, 0x0039, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +typedef enum _DISK_CACHE_STATE { + + DiskCacheNormal, + DiskCacheWriteThroughNotSupported, + DiskCacheModifyUnsuccessful + +} DISK_CACHE_STATE, *PDISK_CACHE_STATE; + +typedef struct _DISK_CACHE_SETTING { + + // + // The size of this structure is used for versioning + // + ULONG Version; + + // + // Indicates whether there are any issues with the disk cache + // + DISK_CACHE_STATE State; + + // + // Indicates whether the disk cache is power protected or not + // + BOOLEAN IsPowerProtected; + +} DISK_CACHE_SETTING, *PDISK_CACHE_SETTING; + + +// +// IOCTL for moving copying a run of sectors from one location of the disk +// to another. The caller of this IOCTL needs to be prepared for the call to +// fail and do the copy manually since this IOCTL will only rarely be +// implemented. +// + +#define IOCTL_DISK_COPY_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0019, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// This structure is passed in for a IOCTL_DISK_COPY_DATA call. +// + +typedef struct _DISK_COPY_DATA_PARAMETERS { + + // + // Byte offset from which to start the copy. + // + LARGE_INTEGER SourceOffset; + + // + // Byte offset of the copy destination. + // + LARGE_INTEGER DestinationOffset; + + // + // Length, in bytes, of the copy. + // + LARGE_INTEGER CopyLength; + + // + // Must be 0. + // + ULONGLONG Reserved; + + +} DISK_COPY_DATA_PARAMETERS, *PDISK_COPY_DATA_PARAMETERS; + +// +// Internal disk driver device controls to maintain the verify status bit +// for the device object. +// + +#define IOCTL_DISK_INTERNAL_SET_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_DISK_INTERNAL_CLEAR_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0101, METHOD_NEITHER, FILE_ANY_ACCESS) + +// +// Internal disk driver device control to set notification routine for +// the device object. Used in DiskPerf. +// + +#define IOCTL_DISK_INTERNAL_SET_NOTIFY CTL_CODE(IOCTL_DISK_BASE, 0x0102, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// begin_winioctl +// +// The following device control codes are common for all class drivers. The +// functions codes defined here must match all of the other class drivers. +// +// Warning: these codes will be replaced in the future by equivalent +// IOCTL_STORAGE codes +// + +#define IOCTL_DISK_CHECK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_MEDIA_REMOVAL CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_EJECT_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_LOAD_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_RESERVE CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_RELEASE CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_FIND_NEW_DEVICES CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_GET_MEDIA_TYPES CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// end_winioctl + +// +// The following file contains the IOCTL_STORAGE class ioctls +// + +#include + +// begin_winioctl +// +// Define the partition types returnable by known disk drivers. +// + +#define PARTITION_ENTRY_UNUSED 0x00 // Entry unused +#define PARTITION_FAT_12 0x01 // 12-bit FAT entries +#define PARTITION_XENIX_1 0x02 // Xenix +#define PARTITION_XENIX_2 0x03 // Xenix +#define PARTITION_FAT_16 0x04 // 16-bit FAT entries +#define PARTITION_EXTENDED 0x05 // Extended partition entry +#define PARTITION_HUGE 0x06 // Huge partition MS-DOS V4 +#define PARTITION_IFS 0x07 // IFS Partition +#define PARTITION_OS2BOOTMGR 0x0A // OS/2 Boot Manager/OPUS/Coherent swap +#define PARTITION_FAT32 0x0B // FAT32 +#define PARTITION_FAT32_XINT13 0x0C // FAT32 using extended int13 services +#define PARTITION_XINT13 0x0E // Win95 partition using extended int13 services +#define PARTITION_XINT13_EXTENDED 0x0F // Same as type 5 but uses extended int13 services +#define PARTITION_PREP 0x41 // PowerPC Reference Platform (PReP) Boot Partition +#define PARTITION_LDM 0x42 // Logical Disk Manager partition +#define PARTITION_UNIX 0x63 // Unix + +#define VALID_NTFT 0xC0 // NTFT uses high order bits + +// +// The high bit of the partition type code indicates that a partition +// is part of an NTFT mirror or striped array. +// + +#define PARTITION_NTFT 0x80 // NTFT partition + +// +// The following macro is used to determine which partitions should be +// assigned drive letters. +// + +//++ +// +// BOOLEAN +// IsRecognizedPartition( +// IN ULONG PartitionType +// ) +// +// Routine Description: +// +// This macro is used to determine to which partitions drive letters +// should be assigned. +// +// Arguments: +// +// PartitionType - Supplies the type of the partition being examined. +// +// Return Value: +// +// The return value is TRUE if the partition type is recognized, +// otherwise FALSE is returned. +// +//-- +#if (NTDDK_VERSION < NTDDI_VISTA) +#define IsRecognizedPartition( PartitionType ) ( \ + ((PartitionType & PARTITION_NTFT) && (((PartitionType & ~0xC0) == PARTITION_HUGE) || \ + ((PartitionType & ~0xC0) == PARTITION_IFS) || \ + ((PartitionType & ~0xC0) == PARTITION_FAT32) || \ + ((PartitionType & ~0xC0) == PARTITION_FAT32_XINT13))) || \ + ((PartitionType) == PARTITION_FAT_12) || \ + ((PartitionType) == PARTITION_FAT_16) || \ + ((PartitionType) == PARTITION_HUGE) || \ + ((PartitionType) == PARTITION_IFS) || \ + ((PartitionType) == PARTITION_FAT32) || \ + ((PartitionType) == PARTITION_FAT32_XINT13) || \ + ((PartitionType) == PARTITION_XINT13) ) +#else +#define IsRecognizedPartition( PartitionType ) ( \ + ((PartitionType) == PARTITION_FAT_12) || \ + ((PartitionType) == PARTITION_FAT_16) || \ + ((PartitionType) == PARTITION_HUGE) || \ + ((PartitionType) == PARTITION_IFS) || \ + ((PartitionType) == PARTITION_FAT32) || \ + ((PartitionType) == PARTITION_FAT32_XINT13) || \ + ((PartitionType) == PARTITION_XINT13) ) +#endif + +//++ +// +// BOOLEAN +// IsContainerPartition( +// IN ULONG PartitionType +// ) +// +// Routine Description: +// +// This macro is used to determine to which partition types are actually +// containers for other partitions (ie, extended partitions). +// +// Arguments: +// +// PartitionType - Supplies the type of the partition being examined. +// +// Return Value: +// +// The return value is TRUE if the partition type is a container, +// otherwise FALSE is returned. +// +//-- + +#define IsContainerPartition( PartitionType ) \ + ((PartitionType == PARTITION_EXTENDED) || (PartitionType == PARTITION_XINT13_EXTENDED)) + +//++ +// +// BOOLEAN +// IsFTPartition( +// IN ULONG PartitionType +// ) +// +// Routine Description: +// +// This macro is used to determine if the given partition is an FT +// partition. +// +// Arguments: +// +// PartitionType - Supplies the type of the partition being examined. +// +// Return Value: +// +// The return value is TRUE if the partition type is an FT partition, +// otherwise FALSE is returned. +// +//-- + +#define IsFTPartition( PartitionType ) \ + ((PartitionType & PARTITION_NTFT) && (((PartitionType & ~0xC0) == PARTITION_HUGE) || \ + ((PartitionType & ~0xC0) == PARTITION_IFS) || \ + ((PartitionType & ~0xC0) == PARTITION_FAT32) || \ + ((PartitionType & ~0xC0) == PARTITION_FAT32_XINT13))) + +// +// Define the media types supported by the driver. +// + +typedef enum _MEDIA_TYPE { + Unknown, // Format is unknown + F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector + F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector + F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector + F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector + F3_720_512, // 3.5", 720KB, 512 bytes/sector + F5_360_512, // 5.25", 360KB, 512 bytes/sector + F5_320_512, // 5.25", 320KB, 512 bytes/sector + F5_320_1024, // 5.25", 320KB, 1024 bytes/sector + F5_180_512, // 5.25", 180KB, 512 bytes/sector + F5_160_512, // 5.25", 160KB, 512 bytes/sector + RemovableMedia, // Removable media other than floppy + FixedMedia, // Fixed hard disk media + F3_120M_512, // 3.5", 120M Floppy + F3_640_512, // 3.5" , 640KB, 512 bytes/sector + F5_640_512, // 5.25", 640KB, 512 bytes/sector + F5_720_512, // 5.25", 720KB, 512 bytes/sector + F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector + F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector + F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector + F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector + F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector + F8_256_128, // 8", 256KB, 128 bytes/sector + F3_200Mb_512, // 3.5", 200M Floppy (HiFD) + F3_240M_512, // 3.5", 240Mb Floppy (HiFD) + F3_32M_512 // 3.5", 32Mb Floppy +} MEDIA_TYPE, *PMEDIA_TYPE; + +// +// Define the input buffer structure for the driver, when +// it is called with IOCTL_DISK_FORMAT_TRACKS. +// + +typedef struct _FORMAT_PARAMETERS { + MEDIA_TYPE MediaType; + ULONG StartCylinderNumber; + ULONG EndCylinderNumber; + ULONG StartHeadNumber; + ULONG EndHeadNumber; +} FORMAT_PARAMETERS, *PFORMAT_PARAMETERS; + +// +// Define the BAD_TRACK_NUMBER type. An array of elements of this type is +// returned by the driver on IOCTL_DISK_FORMAT_TRACKS requests, to indicate +// what tracks were bad during formatting. The length of that array is +// reported in the `Information' field of the I/O Status Block. +// + +typedef USHORT BAD_TRACK_NUMBER; +typedef USHORT *PBAD_TRACK_NUMBER; + +// +// Define the input buffer structure for the driver, when +// it is called with IOCTL_DISK_FORMAT_TRACKS_EX. +// + +typedef struct _FORMAT_EX_PARAMETERS { + MEDIA_TYPE MediaType; + ULONG StartCylinderNumber; + ULONG EndCylinderNumber; + ULONG StartHeadNumber; + ULONG EndHeadNumber; + USHORT FormatGapLength; + USHORT SectorsPerTrack; + USHORT SectorNumber[1]; +} FORMAT_EX_PARAMETERS, *PFORMAT_EX_PARAMETERS; + +// +// The following structure is returned on an IOCTL_DISK_GET_DRIVE_GEOMETRY +// request and an array of them is returned on an IOCTL_DISK_GET_MEDIA_TYPES +// request. +// + +typedef struct _DISK_GEOMETRY { + LARGE_INTEGER Cylinders; + MEDIA_TYPE MediaType; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; +} DISK_GEOMETRY, *PDISK_GEOMETRY; + + + +// +// This wmi guid returns a DISK_GEOMETRY structure +// +#define WMI_DISK_GEOMETRY_GUID { 0x25007f51, 0x57c2, 0x11d1, { 0xa5, 0x28, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 } } + + + +// +// The following structure is returned on an IOCTL_DISK_GET_PARTITION_INFO +// and an IOCTL_DISK_GET_DRIVE_LAYOUT request. It is also used in a request +// to change the drive layout, IOCTL_DISK_SET_DRIVE_LAYOUT. +// + +typedef struct _PARTITION_INFORMATION { + LARGE_INTEGER StartingOffset; + LARGE_INTEGER PartitionLength; + ULONG HiddenSectors; + ULONG PartitionNumber; + UCHAR PartitionType; + BOOLEAN BootIndicator; + BOOLEAN RecognizedPartition; + BOOLEAN RewritePartition; +} PARTITION_INFORMATION, *PPARTITION_INFORMATION; + +// +// The following structure is used to change the partition type of a +// specified disk partition using an IOCTL_DISK_SET_PARTITION_INFO +// request. +// + +typedef struct _SET_PARTITION_INFORMATION { + UCHAR PartitionType; +} SET_PARTITION_INFORMATION, *PSET_PARTITION_INFORMATION; + +// +// The following structures is returned on an IOCTL_DISK_GET_DRIVE_LAYOUT +// request and given as input to an IOCTL_DISK_SET_DRIVE_LAYOUT request. +// + +typedef struct _DRIVE_LAYOUT_INFORMATION { + ULONG PartitionCount; + ULONG Signature; + PARTITION_INFORMATION PartitionEntry[1]; +} DRIVE_LAYOUT_INFORMATION, *PDRIVE_LAYOUT_INFORMATION; + +// +// The following structure is passed in on an IOCTL_DISK_VERIFY request. +// The offset and length parameters are both given in bytes. +// + +typedef struct _VERIFY_INFORMATION { + LARGE_INTEGER StartingOffset; + ULONG Length; +} VERIFY_INFORMATION, *PVERIFY_INFORMATION; + +// +// The following structure is passed in on an IOCTL_DISK_REASSIGN_BLOCKS +// request. +// + +typedef struct _REASSIGN_BLOCKS { + USHORT Reserved; + USHORT Count; + ULONG BlockNumber[1]; +} REASSIGN_BLOCKS, *PREASSIGN_BLOCKS; + +// +// The following structure is passed in on an IOCTL_DISK_REASSIGN_BLOCKS_EX +// request. +// + +#include +typedef struct _REASSIGN_BLOCKS_EX { + USHORT Reserved; + USHORT Count; + LARGE_INTEGER BlockNumber[1]; +} REASSIGN_BLOCKS_EX, *PREASSIGN_BLOCKS_EX; +#include + + +#if(_WIN32_WINNT >= 0x500) + +// +// Support for GUID Partition Table (GPT) disks. +// + +// +// There are currently two ways a disk can be partitioned. With a traditional +// AT-style master boot record (PARTITION_STYLE_MBR) and with a new, GPT +// partition table (PARTITION_STYLE_GPT). RAW is for an unrecognizable +// partition style. There are a very limited number of things you can +// do with a RAW partititon. +// + +typedef enum _PARTITION_STYLE { + PARTITION_STYLE_MBR, + PARTITION_STYLE_GPT, + PARTITION_STYLE_RAW +} PARTITION_STYLE; + + +// +// The following structure defines information in a GPT partition that is +// not common to both GPT and MBR partitions. +// + +typedef struct _PARTITION_INFORMATION_GPT { + GUID PartitionType; // Partition type. See table 16-3. + GUID PartitionId; // Unique GUID for this partition. + ULONG64 Attributes; // See table 16-4. + WCHAR Name [36]; // Partition Name in Unicode. +} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT; + +// +// The following are GPT partition attributes applicable for any +// partition type. These attributes are not OS-specific +// + +#define GPT_ATTRIBUTE_PLATFORM_REQUIRED (0x0000000000000001) + +// +// The following are GPT partition attributes applicable when the +// PartitionType is PARTITION_BASIC_DATA_GUID. +// + +#define GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER (0x8000000000000000) +#define GPT_BASIC_DATA_ATTRIBUTE_HIDDEN (0x4000000000000000) +#define GPT_BASIC_DATA_ATTRIBUTE_SHADOW_COPY (0x2000000000000000) +#define GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY (0x1000000000000000) + +// +// The following structure defines information in an MBR partition that is not +// common to both GPT and MBR partitions. +// + +typedef struct _PARTITION_INFORMATION_MBR { + UCHAR PartitionType; + BOOLEAN BootIndicator; + BOOLEAN RecognizedPartition; + ULONG HiddenSectors; +} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR; + + +// +// The structure SET_PARTITION_INFO_EX is used with the ioctl +// IOCTL_SET_PARTITION_INFO_EX to set information about a specific +// partition. Note that for MBR partitions, you can only set the partition +// signature, whereas GPT partitions allow setting of all fields that +// you can get. +// + +typedef SET_PARTITION_INFORMATION SET_PARTITION_INFORMATION_MBR; +typedef PARTITION_INFORMATION_GPT SET_PARTITION_INFORMATION_GPT; + + +typedef struct _SET_PARTITION_INFORMATION_EX { + PARTITION_STYLE PartitionStyle; + union { + SET_PARTITION_INFORMATION_MBR Mbr; + SET_PARTITION_INFORMATION_GPT Gpt; + } DUMMYUNIONNAME; +} SET_PARTITION_INFORMATION_EX, *PSET_PARTITION_INFORMATION_EX; + + +// +// The structure CREATE_DISK_GPT with the ioctl IOCTL_DISK_CREATE_DISK +// to initialize an virgin disk with an empty GPT partition table. +// + +typedef struct _CREATE_DISK_GPT { + GUID DiskId; // Unique disk id for the disk. + ULONG MaxPartitionCount; // Maximim number of partitions allowable. +} CREATE_DISK_GPT, *PCREATE_DISK_GPT; + +// +// The structure CREATE_DISK_MBR with the ioctl IOCTL_DISK_CREATE_DISK +// to initialize an virgin disk with an empty MBR partition table. +// + +typedef struct _CREATE_DISK_MBR { + ULONG Signature; +} CREATE_DISK_MBR, *PCREATE_DISK_MBR; + + +typedef struct _CREATE_DISK { + PARTITION_STYLE PartitionStyle; + union { + CREATE_DISK_MBR Mbr; + CREATE_DISK_GPT Gpt; + } DUMMYUNIONNAME; +} CREATE_DISK, *PCREATE_DISK; + + +// +// The structure GET_LENGTH_INFORMATION is used with the ioctl +// IOCTL_DISK_GET_LENGTH_INFO to obtain the length, in bytes, of the +// disk, partition, or volume. +// + +typedef struct _GET_LENGTH_INFORMATION { + LARGE_INTEGER Length; +} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION; + +// +// The PARTITION_INFORMATION_EX structure is used with the +// IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, +// IOCTL_DISK_GET_PARTITION_INFO_EX and IOCTL_DISK_GET_PARTITION_INFO_EX calls. +// + +typedef struct _PARTITION_INFORMATION_EX { + PARTITION_STYLE PartitionStyle; + LARGE_INTEGER StartingOffset; + LARGE_INTEGER PartitionLength; + ULONG PartitionNumber; + BOOLEAN RewritePartition; + union { + PARTITION_INFORMATION_MBR Mbr; + PARTITION_INFORMATION_GPT Gpt; + } DUMMYUNIONNAME; +} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX; + + +// +// GPT specific drive layout information. +// + +typedef struct _DRIVE_LAYOUT_INFORMATION_GPT { + GUID DiskId; + LARGE_INTEGER StartingUsableOffset; + LARGE_INTEGER UsableLength; + ULONG MaxPartitionCount; +} DRIVE_LAYOUT_INFORMATION_GPT, *PDRIVE_LAYOUT_INFORMATION_GPT; + + +// +// MBR specific drive layout information. +// + +typedef struct _DRIVE_LAYOUT_INFORMATION_MBR { + ULONG Signature; +} DRIVE_LAYOUT_INFORMATION_MBR, *PDRIVE_LAYOUT_INFORMATION_MBR; + +// +// The structure DRIVE_LAYOUT_INFORMATION_EX is used with the +// IOCTL_SET_DRIVE_LAYOUT_EX and IOCTL_GET_DRIVE_LAYOUT_EX calls. +// + +typedef struct _DRIVE_LAYOUT_INFORMATION_EX { + ULONG PartitionStyle; + ULONG PartitionCount; + union { + DRIVE_LAYOUT_INFORMATION_MBR Mbr; + DRIVE_LAYOUT_INFORMATION_GPT Gpt; + } DUMMYUNIONNAME; + PARTITION_INFORMATION_EX PartitionEntry[1]; +} DRIVE_LAYOUT_INFORMATION_EX, *PDRIVE_LAYOUT_INFORMATION_EX; + + +#endif // (_WIN32_WINNT >= 0x0500) + + +#if(_WIN32_WINNT >= 0x0500) + +// +// The DISK_GEOMETRY_EX structure is returned on issuing an +// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX ioctl. +// + +typedef enum _DETECTION_TYPE { + DetectNone, + DetectInt13, + DetectExInt13 +} DETECTION_TYPE; + +typedef struct _DISK_INT13_INFO { + USHORT DriveSelect; + ULONG MaxCylinders; + USHORT SectorsPerTrack; + USHORT MaxHeads; + USHORT NumberDrives; +} DISK_INT13_INFO, *PDISK_INT13_INFO; + +typedef struct _DISK_EX_INT13_INFO { + USHORT ExBufferSize; + USHORT ExFlags; + ULONG ExCylinders; + ULONG ExHeads; + ULONG ExSectorsPerTrack; + ULONG64 ExSectorsPerDrive; + USHORT ExSectorSize; + USHORT ExReserved; +} DISK_EX_INT13_INFO, *PDISK_EX_INT13_INFO; + +#if (_MSC_VER >= 1200) +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#endif + +typedef struct _DISK_DETECTION_INFO { + ULONG SizeOfDetectInfo; + DETECTION_TYPE DetectionType; + union { + struct { + + // + // If DetectionType == DETECTION_INT13 then we have just the Int13 + // information. + // + + DISK_INT13_INFO Int13; + + // + // If DetectionType == DETECTION_EX_INT13, then we have the + // extended int 13 information. + // + + DISK_EX_INT13_INFO ExInt13; // If DetectionType == DetectExInt13 + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; +} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO; + + +typedef struct _DISK_PARTITION_INFO { + ULONG SizeOfPartitionInfo; + PARTITION_STYLE PartitionStyle; // PartitionStyle = RAW, GPT or MBR + union { + struct { // If PartitionStyle == MBR + ULONG Signature; // MBR Signature + ULONG CheckSum; // MBR CheckSum + } Mbr; + struct { // If PartitionStyle == GPT + GUID DiskId; + } Gpt; + } DUMMYUNIONNAME; +} DISK_PARTITION_INFO, *PDISK_PARTITION_INFO; + +#if (_MSC_VER >= 1200) +#pragma warning(pop) +#endif + +// +// The Geometry structure is a variable length structure composed of a +// DISK_GEOMETRY_EX structure followed by a DISK_PARTITION_INFO structure +// followed by a DISK_DETECTION_DATA structure. +// + +#if (NTDDI_VERSION < NTDDI_WIN2003) +#define DiskGeometryGetPartition(Geometry)\ + ((PDISK_PARTITION_INFO)((Geometry)+1)) + +#define DiskGeometryGetDetect(Geometry)\ + ((PDISK_DETECTION_INFO)(((PBYTE)DiskGeometryGetPartition(Geometry)+\ + DiskGeometryGetPartition(Geometry)->SizeOfPartitionInfo))) +#else +#define DiskGeometryGetPartition(Geometry)\ + ((PDISK_PARTITION_INFO)((Geometry)->Data)) + +#define DiskGeometryGetDetect(Geometry)\ + ((PDISK_DETECTION_INFO)(((ULONG_PTR)DiskGeometryGetPartition(Geometry)+\ + DiskGeometryGetPartition(Geometry)->SizeOfPartitionInfo))) +#endif +typedef struct _DISK_GEOMETRY_EX { + DISK_GEOMETRY Geometry; // Standard disk geometry: may be faked by driver. + LARGE_INTEGER DiskSize; // Must always be correct + UCHAR Data[1]; // Partition, Detect info +} DISK_GEOMETRY_EX, *PDISK_GEOMETRY_EX; + +#endif // (_WIN32_WINNT > 0x0500) + +#if(_WIN32_WINNT >= 0x0400) +// +// IOCTL_DISK_CONTROLLER_NUMBER returns the controller and disk +// number for the handle. This is used to determine if a disk +// is attached to the primary or secondary IDE controller. +// + +typedef struct _DISK_CONTROLLER_NUMBER { + ULONG ControllerNumber; + ULONG DiskNumber; +} DISK_CONTROLLER_NUMBER, *PDISK_CONTROLLER_NUMBER; +#endif /* _WIN32_WINNT >= 0x0400 */ + +#if(_WIN32_WINNT >= 0x0500) + +// +// IOCTL_DISK_SET_CACHE_INFORMATION +// +// Input Buffer: +// A DISK_CACHE_INFORMATION structure which describes how the disk +// read/write caches should be configured. +// +// Output Buffer: +// None +// + +// +// IOCTL_DISK_GET_CACHE_INFORMATION +// +// Input Buffer: +// None +// +// Output Buffer: +// A DISK_CACHE_INFORMATION structure which contains the current state +// of the disk read/write caches. +// + +typedef enum { + EqualPriority, + KeepPrefetchedData, + KeepReadData +} DISK_CACHE_RETENTION_PRIORITY; + +#if (OSVER(NTDDI_VERSION) == NTDDI_WINXP) +typedef enum _DISK_WRITE_CACHE_STATE { + DiskWriteCacheNormal, + DiskWriteCacheForceDisable, + DiskWriteCacheDisableNotSupported +} DISK_WRITE_CACHE_STATE, *PDISK_WRITE_CACHE_STATE; +#endif + +typedef struct _DISK_CACHE_INFORMATION { + + // + // on return indicates that the device is capable of saving any parameters + // in non-volatile storage. On send indicates that the device should + // save the state in non-volatile storage. + // + + BOOLEAN ParametersSavable; + + // + // Indicates whether the write and read caches are enabled. + // + + BOOLEAN ReadCacheEnabled; + BOOLEAN WriteCacheEnabled; + + // + // Controls the likelyhood of data remaining in the cache depending on how + // it got there. Data cached from a READ or WRITE operation may be given + // higher, lower or equal priority to data entered into the cache for other + // means (like prefetch) + // + + DISK_CACHE_RETENTION_PRIORITY ReadRetentionPriority; + DISK_CACHE_RETENTION_PRIORITY WriteRetentionPriority; + + // + // Requests for a larger number of blocks than this may have prefetching + // disabled. If this value is set to 0 prefetch will be disabled. + // + + USHORT DisablePrefetchTransferLength; + + // + // If TRUE then ScalarPrefetch (below) will be valid. If FALSE then + // the minimum and maximum values should be treated as a block count + // (BlockPrefetch) + // + + BOOLEAN PrefetchScalar; + + // + // Contains the minimum and maximum amount of data which will be + // will be prefetched into the cache on a disk operation. This value + // may either be a scalar multiplier of the transfer length of the request, + // or an abolute number of disk blocks. PrefetchScalar (above) indicates + // which interpretation is used. + // + + union { + struct { + USHORT Minimum; + USHORT Maximum; + + // + // The maximum number of blocks which will be prefetched - useful + // with the scalar limits to set definite upper limits. + // + + USHORT MaximumBlocks; + } ScalarPrefetch; + + struct { + USHORT Minimum; + USHORT Maximum; + } BlockPrefetch; + } DUMMYUNIONNAME; + +} DISK_CACHE_INFORMATION, *PDISK_CACHE_INFORMATION; + +// +// IOCTL_DISK_GROW_PARTITION will update the size of a partition +// by adding sectors to the length. The number of sectors must be +// predetermined by examining PARTITION_INFORMATION. +// + +typedef struct _DISK_GROW_PARTITION { + ULONG PartitionNumber; + LARGE_INTEGER BytesToGrow; +} DISK_GROW_PARTITION, *PDISK_GROW_PARTITION; +#endif /* _WIN32_WINNT >= 0x0500 */ + +/////////////////////////////////////////////////////// +// // +// The following structures define disk performance // +// statistics: specifically the locations of all the // +// reads and writes which have occured on the disk. // +// // +// To use these structures, you must issue an IOCTL_ // +// DISK_HIST_STRUCTURE (with a DISK_HISTOGRAM) to // +// obtain the basic histogram information. The // +// number of buckets which must allocated is part of // +// this structure. Allocate the required number of // +// buckets and call an IOCTL_DISK_HIST_DATA to fill // +// in the data // +// // +/////////////////////////////////////////////////////// + +#define HIST_NO_OF_BUCKETS 24 + +typedef struct _HISTOGRAM_BUCKET { + ULONG Reads; + ULONG Writes; +} HISTOGRAM_BUCKET, *PHISTOGRAM_BUCKET; + +#define HISTOGRAM_BUCKET_SIZE sizeof(HISTOGRAM_BUCKET) + +typedef struct _DISK_HISTOGRAM { + LARGE_INTEGER DiskSize; + LARGE_INTEGER Start; + LARGE_INTEGER End; + LARGE_INTEGER Average; + LARGE_INTEGER AverageRead; + LARGE_INTEGER AverageWrite; + ULONG Granularity; + ULONG Size; + ULONG ReadCount; + ULONG WriteCount; + PHISTOGRAM_BUCKET Histogram; +} DISK_HISTOGRAM, *PDISK_HISTOGRAM; + +#define DISK_HISTOGRAM_SIZE sizeof(DISK_HISTOGRAM) + +/////////////////////////////////////////////////////// +// // +// The following structures define disk debugging // +// capabilities. The IOCTLs are directed to one of // +// the two disk filter drivers. // +// // +// DISKPERF is a utilty for collecting disk request // +// statistics. // +// // +// SIMBAD is a utility for injecting faults in // +// IO requests to disks. // +// // +/////////////////////////////////////////////////////// + +// +// The following structure is exchanged on an IOCTL_DISK_GET_PERFORMANCE +// request. This ioctl collects summary disk request statistics used +// in measuring performance. +// + +typedef struct _DISK_PERFORMANCE { + LARGE_INTEGER BytesRead; + LARGE_INTEGER BytesWritten; + LARGE_INTEGER ReadTime; + LARGE_INTEGER WriteTime; + LARGE_INTEGER IdleTime; + ULONG ReadCount; + ULONG WriteCount; + ULONG QueueDepth; + ULONG SplitCount; + LARGE_INTEGER QueryTime; + ULONG StorageDeviceNumber; + WCHAR StorageManagerName[8]; +} DISK_PERFORMANCE, *PDISK_PERFORMANCE; + +// +// This structure defines the disk logging record. When disk logging +// is enabled, one of these is written to an internal buffer for each +// disk request. +// + +typedef struct _DISK_RECORD { + LARGE_INTEGER ByteOffset; + LARGE_INTEGER StartTime; + LARGE_INTEGER EndTime; + PVOID VirtualAddress; + ULONG NumberOfBytes; + UCHAR DeviceNumber; + BOOLEAN ReadRequest; +} DISK_RECORD, *PDISK_RECORD; + +// +// The following structure is exchanged on an IOCTL_DISK_LOG request. +// Not all fields are valid with each function type. +// + +typedef struct _DISK_LOGGING { + UCHAR Function; + PVOID BufferAddress; + ULONG BufferSize; +} DISK_LOGGING, *PDISK_LOGGING; + +// +// Disk logging functions +// +// Start disk logging. Only the Function and BufferSize fields are valid. +// + +#define DISK_LOGGING_START 0 + +// +// Stop disk logging. Only the Function field is valid. +// + +#define DISK_LOGGING_STOP 1 + +// +// Return disk log. All fields are valid. Data will be copied from internal +// buffer to buffer specified for the number of bytes requested. +// + +#define DISK_LOGGING_DUMP 2 + +// +// DISK BINNING +// +// DISKPERF will keep counters for IO that falls in each of these ranges. +// The application determines the number and size of the ranges. +// Joe Lin wanted me to keep it flexible as possible, for instance, IO +// sizes are interesting in ranges like 0-4096, 4097-16384, 16385-65536, 65537+. +// + +#define DISK_BINNING 3 + +// +// Bin types +// + +typedef enum _BIN_TYPES { + RequestSize, + RequestLocation +} BIN_TYPES; + +// +// Bin ranges +// + +typedef struct _BIN_RANGE { + LARGE_INTEGER StartValue; + LARGE_INTEGER Length; +} BIN_RANGE, *PBIN_RANGE; + +// +// Bin definition +// + +typedef struct _PERF_BIN { + ULONG NumberOfBins; + ULONG TypeOfBin; + BIN_RANGE BinsRanges[1]; +} PERF_BIN, *PPERF_BIN ; + +// +// Bin count +// + +typedef struct _BIN_COUNT { + BIN_RANGE BinRange; + ULONG BinCount; +} BIN_COUNT, *PBIN_COUNT; + +// +// Bin results +// + +typedef struct _BIN_RESULTS { + ULONG NumberOfBins; + BIN_COUNT BinCounts[1]; +} BIN_RESULTS, *PBIN_RESULTS; + +#if(_WIN32_WINNT >= 0x0400) +// +// Data structures for SMART drive fault prediction. +// +// GETVERSIONINPARAMS contains the data returned from the +// Get Driver Version function. +// + +#include +typedef struct _GETVERSIONINPARAMS { + UCHAR bVersion; // Binary driver version. + UCHAR bRevision; // Binary driver revision. + UCHAR bReserved; // Not used. + UCHAR bIDEDeviceMap; // Bit map of IDE devices. + ULONG fCapabilities; // Bit mask of driver capabilities. + ULONG dwReserved[4]; // For future use. +} GETVERSIONINPARAMS, *PGETVERSIONINPARAMS, *LPGETVERSIONINPARAMS; +#include + +// +// Bits returned in the fCapabilities member of GETVERSIONINPARAMS +// + +#define CAP_ATA_ID_CMD 1 // ATA ID command supported +#define CAP_ATAPI_ID_CMD 2 // ATAPI ID command supported +#define CAP_SMART_CMD 4 // SMART commannds supported + +// +// IDE registers +// + +#include +typedef struct _IDEREGS { + UCHAR bFeaturesReg; // Used for specifying SMART "commands". + UCHAR bSectorCountReg; // IDE sector count register + UCHAR bSectorNumberReg; // IDE sector number register + UCHAR bCylLowReg; // IDE low order cylinder value + UCHAR bCylHighReg; // IDE high order cylinder value + UCHAR bDriveHeadReg; // IDE drive/head register + UCHAR bCommandReg; // Actual IDE command. + UCHAR bReserved; // reserved for future use. Must be zero. +} IDEREGS, *PIDEREGS, *LPIDEREGS; +#include + +// +// Valid values for the bCommandReg member of IDEREGS. +// + +#define ATAPI_ID_CMD 0xA1 // Returns ID sector for ATAPI. +#define ID_CMD 0xEC // Returns ID sector for ATA. +#define SMART_CMD 0xB0 // Performs SMART cmd. + // Requires valid bFeaturesReg, + // bCylLowReg, and bCylHighReg + +// +// Cylinder register defines for SMART command +// + +#define SMART_CYL_LOW 0x4F +#define SMART_CYL_HI 0xC2 + + +// +// SENDCMDINPARAMS contains the input parameters for the +// Send Command to Drive function. +// + +#include +typedef struct _SENDCMDINPARAMS { + ULONG cBufferSize; // Buffer size in bytes + IDEREGS irDriveRegs; // Structure with drive register values. + UCHAR bDriveNumber; // Physical drive number to send + // command to (0,1,2,3). + UCHAR bReserved[3]; // Reserved for future expansion. + ULONG dwReserved[4]; // For future use. + UCHAR bBuffer[1]; // Input buffer. +} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS; +#include + +// +// Status returned from driver +// + +#include +typedef struct _DRIVERSTATUS { + UCHAR bDriverError; // Error code from driver, + // or 0 if no error. + UCHAR bIDEError; // Contents of IDE Error register. + // Only valid when bDriverError + // is SMART_IDE_ERROR. + UCHAR bReserved[2]; // Reserved for future expansion. + ULONG dwReserved[2]; // Reserved for future expansion. +} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS; +#include + +// +// bDriverError values +// + +#define SMART_NO_ERROR 0 // No error +#define SMART_IDE_ERROR 1 // Error from IDE controller +#define SMART_INVALID_FLAG 2 // Invalid command flag +#define SMART_INVALID_COMMAND 3 // Invalid command byte +#define SMART_INVALID_BUFFER 4 // Bad buffer (null, invalid addr..) +#define SMART_INVALID_DRIVE 5 // Drive number not valid +#define SMART_INVALID_IOCTL 6 // Invalid IOCTL +#define SMART_ERROR_NO_MEM 7 // Could not lock user's buffer +#define SMART_INVALID_REGISTER 8 // Some IDE Register not valid +#define SMART_NOT_SUPPORTED 9 // Invalid cmd flag set +#define SMART_NO_IDE_DEVICE 10 // Cmd issued to device not present + // although drive number is valid +// +// SMART sub commands for execute offline diags +// +#define SMART_OFFLINE_ROUTINE_OFFLINE 0 +#define SMART_SHORT_SELFTEST_OFFLINE 1 +#define SMART_EXTENDED_SELFTEST_OFFLINE 2 +#define SMART_ABORT_OFFLINE_SELFTEST 127 +#define SMART_SHORT_SELFTEST_CAPTIVE 129 +#define SMART_EXTENDED_SELFTEST_CAPTIVE 130 + + +#include +typedef struct _SENDCMDOUTPARAMS { + ULONG cBufferSize; // Size of bBuffer in bytes + DRIVERSTATUS DriverStatus; // Driver status structure. + UCHAR bBuffer[1]; // Buffer of arbitrary length in which to store the data read from the // drive. +} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS; +#include + + +#define READ_ATTRIBUTE_BUFFER_SIZE 512 +#define IDENTIFY_BUFFER_SIZE 512 +#define READ_THRESHOLD_BUFFER_SIZE 512 +#define SMART_LOG_SECTOR_SIZE 512 + +// +// Feature register defines for SMART "sub commands" +// + +#define READ_ATTRIBUTES 0xD0 +#define READ_THRESHOLDS 0xD1 +#define ENABLE_DISABLE_AUTOSAVE 0xD2 +#define SAVE_ATTRIBUTE_VALUES 0xD3 +#define EXECUTE_OFFLINE_DIAGS 0xD4 +#define SMART_READ_LOG 0xD5 +#define SMART_WRITE_LOG 0xd6 +#define ENABLE_SMART 0xD8 +#define DISABLE_SMART 0xD9 +#define RETURN_SMART_STATUS 0xDA +#define ENABLE_DISABLE_AUTO_OFFLINE 0xDB +#endif /* _WIN32_WINNT >= 0x0400 */ + +// end_winioctl + + +#if (NTDDI_VERSION >= NTDDI_VISTA) + +// +// IOCTLs to query and modify attributes +// associated with partitions. These are +// persisted within the partition table. +// + +#define IOCTL_DISK_GET_PARTITION_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003a, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_SET_PARTITION_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTL_DISK_GET_PARTITION_ATTRIBUTES +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type GET_PARTITION_ATTRIBUTES +// + +typedef struct _GET_PARTITION_ATTRIBUTES { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // For alignment purposes. + // + ULONG Reserved1; + + // + // Specifies the partition + // attributes. + // + ULONGLONG Attributes; + +} GET_PARTITION_ATTRIBUTES, *PGET_PARTITION_ATTRIBUTES; + +// +// IOCTL_DISK_SET_PARTITION_ATTRIBUTES +// +// Input Buffer: +// Structure of type SET_PARTITION_ATTRIBUTES +// +// Output Buffer: +// None +// + +typedef struct _SET_PARTITION_ATTRIBUTES { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // Indicates whether to remember + // these settings across reboots + // or not. + // + BOOLEAN Persist; + + // + // For alignment purposes. + // + BOOLEAN Reserved1[3]; + + // + // Specifies the new attributes. + // + ULONGLONG Attributes; + + // + // Specifies the attributes + // that are being modified. + // + ULONGLONG AttributesMask; + +} SET_PARTITION_ATTRIBUTES, *PSET_PARTITION_ATTRIBUTES; + + +// +// IOCTLs to query and modify attributes +// associated with the given disk. These +// are persisted within the registry. +// + +#define IOCTL_DISK_GET_DISK_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003c, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_SET_DISK_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003d, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define DISK_ATTRIBUTE_OFFLINE 0x0000000000000001 +#define DISK_ATTRIBUTE_READ_ONLY 0x0000000000000002 + +// +// IOCTL_DISK_GET_DISK_ATTRIBUTES +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type GET_DISK_ATTRIBUTES +// + +typedef struct _GET_DISK_ATTRIBUTES { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // For alignment purposes. + // + ULONG Reserved1; + + // + // Specifies the attributes + // associated with the disk. + // + ULONGLONG Attributes; + +} GET_DISK_ATTRIBUTES, *PGET_DISK_ATTRIBUTES; + +// +// IOCTL_DISK_SET_DISK_ATTRIBUTES +// +// Input Buffer: +// Structure of type SET_DISK_ATTRIBUTES +// +// Output Buffer: +// None +// + +typedef struct _SET_DISK_ATTRIBUTES { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // Indicates whether to remember + // these settings across reboots + // or not. + // + BOOLEAN Persist; + + // + // Indicates whether the ownership + // taken earlier is being released. + // + BOOLEAN RelinquishOwnership; + + // + // For alignment purposes. + // + BOOLEAN Reserved1[2]; + + // + // Specifies the new attributes. + // + ULONGLONG Attributes; + + // + // Specifies the attributes + // that are being modified. + // + ULONGLONG AttributesMask; + + // + // Specifies an identifier to be + // associated with the caller. + // This setting is not persisted + // across reboots. + // + GUID Owner; + +} SET_DISK_ATTRIBUTES, *PSET_DISK_ATTRIBUTES; + + +// +// IOCTL to determine if the disk is +// owned by the cluster service or not. +// + +#define IOCTL_DISK_IS_CLUSTERED CTL_CODE(IOCTL_DISK_BASE, 0x003e, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL_DISK_IS_CLUSTERED +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type BOOLEAN +// + + +// +// IOCTLs to query and modify the current +// SAN settings. For instance, the policy +// associated with newly discovered disks. +// + +#define IOCTL_DISK_GET_SAN_SETTINGS CTL_CODE(IOCTL_DISK_BASE, 0x0080, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_SAN_SETTINGS CTL_CODE(IOCTL_DISK_BASE, 0x0081, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTL_DISK_GET_SAN_SETTINGS +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type DISK_SAN_SETTINGS +// + +// +// IOCTL_DISK_SET_SAN_SETTINGS +// +// Input Buffer: +// Structure of type DISK_SAN_SETTINGS +// +// Output Buffer: +// None +// + +typedef enum _DISK_SAN_POLICY { + + DiskSanPolicyUnknown, + DiskSanPolicyOnline, + DiskSanPolicyOfflineShared, + DiskSanPolicyOffline, + DiskSanPolicyMax + +} DISK_SAN_POLICY, *PDISK_SAN_POLICY; + +typedef struct _DISK_SAN_SETTINGS { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // Specifies the policy to be + // applied to all new disks. + // + DISK_SAN_POLICY SanPolicy; + +} DISK_SAN_SETTINGS, *PDISK_SAN_SETTINGS; + + +// +// IOCTLs to query and modify the context +// associated with snapshot disks created +// in hardware. +// + +#define IOCTL_DISK_GET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0082, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0083, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// begin_winioctl + +#define IOCTL_DISK_RESET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0084, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// end_winioctl + +// +// IOCTL_DISK_GET_SNAPSHOT_INFO +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type DISK_SNAPSHOT_INFO +// + +// +// IOCTL_DISK_SET_SNAPSHOT_INFO +// +// Input Buffer: +// Structure of type DISK_SNAPSHOT_INFO +// +// Output Buffer: +// None +// + +typedef enum _DISK_SNAPSHOT_STATE { + + DiskSnapshotNormalDisk, + DiskSnapshotSnapshotCheckRequired, + DiskSnapshotPreSnapshot, + DiskSnapshotSnapshotDisk + +} DISK_SNAPSHOT_STATE, *PDISK_SNAPSHOT_STATE; + +typedef struct _DISK_SNAPSHOT_INFO { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // Specifies the state that this + // disk is in or the state to be + // transitioned to. + // + DISK_SNAPSHOT_STATE State; + + // + // Specifies a unique id that + // represents all of the disks + // involved in this snapshot. + // + GUID SnapshotSetId; + + // + // Specifies a unique id that + // represents this snapshot. + // + GUID SnapshotId; + + // + // Specifies a unique id that + // represents the logical unit + // whose snapshot was taken. + // + GUID LunId; + + // + // Specifies the time when this + // snapshot was taken. + // + LARGE_INTEGER CreationTimeStamp; + + // + // Specifies the number of times + // that this snapshot has been + // imported. + // + ULONG ImportCount; + + // + // Specifies attributes that are + // associated with this snapshot. + // + ULONG Flags; + + // + // Specifies the size in bytes of + // the following field. + // + ULONG AdditionalDataSize; + + // + // Specifies disk meta data that + // needs to be restored in the + // event of a fast recovery. + // + UCHAR AdditionalData[ANYSIZE_ARRAY]; + +} DISK_SNAPSHOT_INFO, *PDISK_SNAPSHOT_INFO; + +#endif // NTDDI_VERSION >= NTDDI_VISTA + + +// +// The following device control code is for the SIMBAD simulated bad +// sector facility. See SIMBAD.H in this directory for related structures. +// + +#define IOCTL_DISK_SIMBAD CTL_CODE(IOCTL_DISK_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// Queue link for mapped addresses stored for unmapping. +// + +typedef struct _MAPPED_ADDRESS { + struct _MAPPED_ADDRESS *NextMappedAddress; + PVOID MappedAddress; + ULONG NumberOfBytes; + LARGE_INTEGER IoAddress; + ULONG BusNumber; +} MAPPED_ADDRESS, *PMAPPED_ADDRESS; + +// begin_winioctl + +#if defined(_MSC_VER) +#if (_MSC_VER >= 1200) +#pragma warning(pop) +#endif +#endif + +// end_winioctl + +#ifdef __cplusplus +} +#endif + +// begin_winioctl + +#endif // _NTDDDISK_H_ + +// end_winioctl + diff --git a/include/winddk/ntddstor.h b/include/winddk/ntddstor.h index ec1535244ad..3cdaeaf38f0 100644 --- a/include/winddk/ntddstor.h +++ b/include/winddk/ntddstor.h @@ -1,1388 +1,1388 @@ -/*++ BUILD Version: 0001 // Increment this if a change has global effects - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - ntddstor.h - -Abstract: - - This is the include file that defines all common constants and types - accessing the storage class drivers - ---*/ - -#include "devioctl.h" - -// -// Interface GUIDs -// -// need these GUIDs outside conditional includes so that user can -// #include in precompiled header -// #include in a single source file -// #include in that source file a second time to instantiate the GUIDs -// -#ifdef DEFINE_GUID -// -// Make sure FAR is defined... -// -#ifndef FAR -#ifdef _WIN32 -#define FAR -#else -#define FAR _far -#endif -#endif - -// begin_wioctlguids - -DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_CDROM, 0x53f56308L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_PARTITION, 0x53f5630aL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_TAPE, 0x53f5630bL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_WRITEONCEDISK, 0x53f5630cL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_MEDIUMCHANGER, 0x53f56310L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_FLOPPY, 0x53f56311L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_CDCHANGER, 0x53f56312L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); - -#define WDI_STORAGE_PREDICT_FAILURE_DPS_GUID {0xe9f2d03aL, 0x747c, 0x41c2, {0xbb, 0x9a, 0x02, 0xc6, 0x2b, 0x6d, 0x5f, 0xcb}}; - -// -// The interface used to discover volumes that are -// not reported by Win32 APIs. This includes those -// with an unrecognized partition type/id and ones -// with the hidden attribute. -// -DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME, 0x7f108a28L, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62); - -// end_wioctlguids - -// begin_wioctlobsoleteguids - -#define DiskClassGuid GUID_DEVINTERFACE_DISK -#define CdRomClassGuid GUID_DEVINTERFACE_CDROM -#define PartitionClassGuid GUID_DEVINTERFACE_PARTITION -#define TapeClassGuid GUID_DEVINTERFACE_TAPE -#define WriteOnceDiskClassGuid GUID_DEVINTERFACE_WRITEONCEDISK -#define VolumeClassGuid GUID_DEVINTERFACE_VOLUME -#define MediumChangerClassGuid GUID_DEVINTERFACE_MEDIUMCHANGER -#define FloppyClassGuid GUID_DEVINTERFACE_FLOPPY -#define CdChangerClassGuid GUID_DEVINTERFACE_CDCHANGER -#define StoragePortClassGuid GUID_DEVINTERFACE_STORAGEPORT -#define HiddenVolumeClassGuid GUID_DEVINTERFACE_HIDDEN_VOLUME - -// end_wioctlobsoleteguids -#endif - -// begin_winioctl - -#ifndef _NTDDSTOR_H_ -#define _NTDDSTOR_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// -// IoControlCode values for storage devices -// - -#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE - -// -// The following device control codes are common for all class drivers. They -// should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE -// common codes -// - -#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_STORAGE_EJECTION_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_MCN_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_STORAGE_GET_MEDIA_TYPES CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0304, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_GET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0305, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_SET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0306, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_BREAK_RESERVATION CTL_CODE(IOCTL_STORAGE_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_PERSISTENT_RESERVE_IN CTL_CODE(IOCTL_STORAGE_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_PERSISTENT_RESERVE_OUT CTL_CODE(IOCTL_STORAGE_BASE, 0x0407, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_PREDICT_FAILURE CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_READ_CAPACITY CTL_CODE(IOCTL_STORAGE_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// IOCTLs 0x0463 to 0x0468 reserved for dependent disk support. -// - -#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES CTL_CODE(IOCTL_STORAGE_BASE, 0x0501, METHOD_BUFFERED, FILE_WRITE_ACCESS) - -// -// IOCTLs for bandwidth contracts on storage devices -// (Move this to ntddsfio if we decide to use a new base) -// - -#define IOCTL_STORAGE_GET_BC_PROPERTIES CTL_CODE(IOCTL_STORAGE_BASE, 0x0600, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_ALLOCATE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0601, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_STORAGE_FREE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0602, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// IOCTL to check for priority support -// -#define IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT CTL_CODE(IOCTL_STORAGE_BASE, 0x0620, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// begin_winioctl - -// -// These ioctl codes are obsolete. They are defined here to avoid resuing them -// and to allow class drivers to respond to them more easily. -// - -#define OBSOLETE_IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define OBSOLETE_IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// IOCTLs 0x0643 to 0x0655 reserved for VHD disk support. -// - -// -// IOCTL_STORAGE_GET_HOTPLUG_INFO -// - -typedef struct _STORAGE_HOTPLUG_INFO { - ULONG Size; // version - BOOLEAN MediaRemovable; // ie. zip, jaz, cdrom, mo, etc. vs hdd - BOOLEAN MediaHotplug; // ie. does the device succeed a lock even though its not lockable media? - BOOLEAN DeviceHotplug; // ie. 1394, USB, etc. - BOOLEAN WriteCacheEnableOverride; // This field should not be relied upon because it is no longer used -} STORAGE_HOTPLUG_INFO, *PSTORAGE_HOTPLUG_INFO; - -// -// IOCTL_STORAGE_GET_DEVICE_NUMBER -// -// input - none -// -// output - STORAGE_DEVICE_NUMBER structure -// The values in the STORAGE_DEVICE_NUMBER structure are guaranteed -// to remain unchanged until the system is rebooted. They are not -// guaranteed to be persistant across boots. -// - -typedef struct _STORAGE_DEVICE_NUMBER { - - // - // The FILE_DEVICE_XXX type for this device. - // - - DEVICE_TYPE DeviceType; - - // - // The number of this device - // - - ULONG DeviceNumber; - - // - // If the device is partitionable, the partition number of the device. - // Otherwise -1 - // - - ULONG PartitionNumber; -} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER; - -// -// Define the structures for scsi resets -// - -typedef struct _STORAGE_BUS_RESET_REQUEST { - UCHAR PathId; -} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST; - -// -// Break reservation is sent to the Adapter/FDO with the given lun information. -// - -typedef struct STORAGE_BREAK_RESERVATION_REQUEST { - ULONG Length; - UCHAR _unused; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; -} STORAGE_BREAK_RESERVATION_REQUEST, *PSTORAGE_BREAK_RESERVATION_REQUEST; - - -// -// IOCTL_STORAGE_MEDIA_REMOVAL disables the mechanism -// on a storage device that ejects media. This function -// may or may not be supported on storage devices that -// support removable media. -// -// TRUE means prevent media from being removed. -// FALSE means allow media removal. -// - -typedef struct _PREVENT_MEDIA_REMOVAL { - BOOLEAN PreventMediaRemoval; -} PREVENT_MEDIA_REMOVAL, *PPREVENT_MEDIA_REMOVAL; - - - -// -// This is the format of TARGET_DEVICE_CUSTOM_NOTIFICATION.CustomDataBuffer -// passed to applications by the classpnp autorun code (via IoReportTargetDeviceChangeAsynchronous). -// -typedef struct _CLASS_MEDIA_CHANGE_CONTEXT { - ULONG MediaChangeCount; - ULONG NewState; // see MEDIA_CHANGE_DETECTION_STATE enum in classpnp.h in DDK -} CLASS_MEDIA_CHANGE_CONTEXT, *PCLASS_MEDIA_CHANGE_CONTEXT; - - -// begin_ntminitape - - -typedef struct _TAPE_STATISTICS { - ULONG Version; - ULONG Flags; - LARGE_INTEGER RecoveredWrites; - LARGE_INTEGER UnrecoveredWrites; - LARGE_INTEGER RecoveredReads; - LARGE_INTEGER UnrecoveredReads; - UCHAR CompressionRatioReads; - UCHAR CompressionRatioWrites; -} TAPE_STATISTICS, *PTAPE_STATISTICS; - -#define RECOVERED_WRITES_VALID 0x00000001 -#define UNRECOVERED_WRITES_VALID 0x00000002 -#define RECOVERED_READS_VALID 0x00000004 -#define UNRECOVERED_READS_VALID 0x00000008 -#define WRITE_COMPRESSION_INFO_VALID 0x00000010 -#define READ_COMPRESSION_INFO_VALID 0x00000020 - -typedef struct _TAPE_GET_STATISTICS { - ULONG Operation; -} TAPE_GET_STATISTICS, *PTAPE_GET_STATISTICS; - -#define TAPE_RETURN_STATISTICS 0L -#define TAPE_RETURN_ENV_INFO 1L -#define TAPE_RESET_STATISTICS 2L - -// -// IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO -// structures, one per supported type, embedded in the GET_MEDIA_TYPES struct. -// - -typedef enum _STORAGE_MEDIA_TYPE { - // - // Following are defined in ntdddisk.h in the MEDIA_TYPE enum - // - // Unknown, // Format is unknown - // F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector - // F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector - // F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector - // F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector - // F3_720_512, // 3.5", 720KB, 512 bytes/sector - // F5_360_512, // 5.25", 360KB, 512 bytes/sector - // F5_320_512, // 5.25", 320KB, 512 bytes/sector - // F5_320_1024, // 5.25", 320KB, 1024 bytes/sector - // F5_180_512, // 5.25", 180KB, 512 bytes/sector - // F5_160_512, // 5.25", 160KB, 512 bytes/sector - // RemovableMedia, // Removable media other than floppy - // FixedMedia, // Fixed hard disk media - // F3_120M_512, // 3.5", 120M Floppy - // F3_640_512, // 3.5" , 640KB, 512 bytes/sector - // F5_640_512, // 5.25", 640KB, 512 bytes/sector - // F5_720_512, // 5.25", 720KB, 512 bytes/sector - // F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector - // F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector - // F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector - // F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector - // F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector - // F8_256_128, // 8", 256KB, 128 bytes/sector - // F3_200Mb_512, // 3.5", 200M Floppy (HiFD) - // - - DDS_4mm = 0x20, // Tape - DAT DDS1,2,... (all vendors) - MiniQic, // Tape - miniQIC Tape - Travan, // Tape - Travan TR-1,2,3,... - QIC, // Tape - QIC - MP_8mm, // Tape - 8mm Exabyte Metal Particle - AME_8mm, // Tape - 8mm Exabyte Advanced Metal Evap - AIT1_8mm, // Tape - 8mm Sony AIT - DLT, // Tape - DLT Compact IIIxt, IV - NCTP, // Tape - Philips NCTP - IBM_3480, // Tape - IBM 3480 - IBM_3490E, // Tape - IBM 3490E - IBM_Magstar_3590, // Tape - IBM Magstar 3590 - IBM_Magstar_MP, // Tape - IBM Magstar MP - STK_DATA_D3, // Tape - STK Data D3 - SONY_DTF, // Tape - Sony DTF - DV_6mm, // Tape - 6mm Digital Video - DMI, // Tape - Exabyte DMI and compatibles - SONY_D2, // Tape - Sony D2S and D2L - CLEANER_CARTRIDGE, // Cleaner - All Drive types that support Drive Cleaners - CD_ROM, // Opt_Disk - CD - CD_R, // Opt_Disk - CD-Recordable (Write Once) - CD_RW, // Opt_Disk - CD-Rewriteable - DVD_ROM, // Opt_Disk - DVD-ROM - DVD_R, // Opt_Disk - DVD-Recordable (Write Once) - DVD_RW, // Opt_Disk - DVD-Rewriteable - MO_3_RW, // Opt_Disk - 3.5" Rewriteable MO Disk - MO_5_WO, // Opt_Disk - MO 5.25" Write Once - MO_5_RW, // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW) - MO_5_LIMDOW, // Opt_Disk - MO 5.25" Rewriteable (LIMDOW) - PC_5_WO, // Opt_Disk - Phase Change 5.25" Write Once Optical - PC_5_RW, // Opt_Disk - Phase Change 5.25" Rewriteable - PD_5_RW, // Opt_Disk - PhaseChange Dual Rewriteable - ABL_5_WO, // Opt_Disk - Ablative 5.25" Write Once Optical - PINNACLE_APEX_5_RW, // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical - SONY_12_WO, // Opt_Disk - Sony 12" Write Once - PHILIPS_12_WO, // Opt_Disk - Philips/LMS 12" Write Once - HITACHI_12_WO, // Opt_Disk - Hitachi 12" Write Once - CYGNET_12_WO, // Opt_Disk - Cygnet/ATG 12" Write Once - KODAK_14_WO, // Opt_Disk - Kodak 14" Write Once - MO_NFR_525, // Opt_Disk - Near Field Recording (Terastor) - NIKON_12_RW, // Opt_Disk - Nikon 12" Rewriteable - IOMEGA_ZIP, // Mag_Disk - Iomega Zip - IOMEGA_JAZ, // Mag_Disk - Iomega Jaz - SYQUEST_EZ135, // Mag_Disk - Syquest EZ135 - SYQUEST_EZFLYER, // Mag_Disk - Syquest EzFlyer - SYQUEST_SYJET, // Mag_Disk - Syquest SyJet - AVATAR_F2, // Mag_Disk - 2.5" Floppy - MP2_8mm, // Tape - 8mm Hitachi - DST_S, // Ampex DST Small Tapes - DST_M, // Ampex DST Medium Tapes - DST_L, // Ampex DST Large Tapes - VXATape_1, // Ecrix 8mm Tape - VXATape_2, // Ecrix 8mm Tape -#if (NTDDI_VERSION < NTDDI_WINXP) - STK_EAGLE, // STK Eagle -#else - STK_9840, // STK 9840 -#endif - LTO_Ultrium, // IBM, HP, Seagate LTO Ultrium - LTO_Accelis, // IBM, HP, Seagate LTO Accelis - DVD_RAM, // Opt_Disk - DVD-RAM - AIT_8mm, // AIT2 or higher - ADR_1, // OnStream ADR Mediatypes - ADR_2, - STK_9940, // STK 9940 - SAIT, // SAIT Tapes - VXATape // VXA (Ecrix 8mm) Tape -}STORAGE_MEDIA_TYPE, *PSTORAGE_MEDIA_TYPE; - -#define MEDIA_ERASEABLE 0x00000001 -#define MEDIA_WRITE_ONCE 0x00000002 -#define MEDIA_READ_ONLY 0x00000004 -#define MEDIA_READ_WRITE 0x00000008 - -#define MEDIA_WRITE_PROTECTED 0x00000100 -#define MEDIA_CURRENTLY_MOUNTED 0x80000000 - -// -// Define the different storage bus types -// Bus types below 128 (0x80) are reserved for Microsoft use -// - -typedef enum _STORAGE_BUS_TYPE { - BusTypeUnknown = 0x00, - BusTypeScsi, - BusTypeAtapi, - BusTypeAta, - BusType1394, - BusTypeSsa, - BusTypeFibre, - BusTypeUsb, - BusTypeRAID, - BusTypeiScsi, - BusTypeSas, - BusTypeSata, - BusTypeSd, - BusTypeMmc, - BusTypeVirtual, - BusTypeFileBackedVirtual, - BusTypeMax, - BusTypeMaxReserved = 0x7F -} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; - -typedef struct _DEVICE_MEDIA_INFO { - union { - struct { - LARGE_INTEGER Cylinders; - STORAGE_MEDIA_TYPE MediaType; - ULONG TracksPerCylinder; - ULONG SectorsPerTrack; - ULONG BytesPerSector; - ULONG NumberMediaSides; - ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. - } DiskInfo; - - struct { - LARGE_INTEGER Cylinders; - STORAGE_MEDIA_TYPE MediaType; - ULONG TracksPerCylinder; - ULONG SectorsPerTrack; - ULONG BytesPerSector; - ULONG NumberMediaSides; - ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. - } RemovableDiskInfo; - - struct { - STORAGE_MEDIA_TYPE MediaType; - ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. - ULONG CurrentBlockSize; - STORAGE_BUS_TYPE BusType; - - // - // Bus specific information describing the medium supported. - // - - union { - struct { - UCHAR MediumType; - UCHAR DensityCode; - } ScsiInformation; - } BusSpecificData; - - } TapeInfo; - } DeviceSpecific; -} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO; - -typedef struct _GET_MEDIA_TYPES { - ULONG DeviceType; // FILE_DEVICE_XXX values - ULONG MediaInfoCount; - DEVICE_MEDIA_INFO MediaInfo[1]; -} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES; - - -// -// IOCTL_STORAGE_PREDICT_FAILURE -// -// input - none -// -// output - STORAGE_PREDICT_FAILURE structure -// PredictFailure returns zero if no failure predicted and non zero -// if a failure is predicted. -// -// VendorSpecific returns 512 bytes of vendor specific information -// if a failure is predicted -// -typedef struct _STORAGE_PREDICT_FAILURE -{ - ULONG PredictFailure; - UCHAR VendorSpecific[512]; -} STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE; - -// end_ntminitape - -// -// Property Query Structures -// - -// -// IOCTL_STORAGE_QUERY_PROPERTY -// -// Input Buffer: -// a STORAGE_PROPERTY_QUERY structure which describes what type of query -// is being done, what property is being queried for, and any additional -// parameters which a particular property query requires. -// -// Output Buffer: -// Contains a buffer to place the results of the query into. Since all -// property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER, -// the IOCTL can be called once with a small buffer then again using -// a buffer as large as the header reports is necessary. -// - - -// -// Types of queries -// - -typedef enum _STORAGE_QUERY_TYPE { - PropertyStandardQuery = 0, // Retrieves the descriptor - PropertyExistsQuery, // Used to test whether the descriptor is supported - PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor - PropertyQueryMaxDefined // use to validate the value -} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; - -// -// define some initial property id's -// - -typedef enum _STORAGE_PROPERTY_ID { - StorageDeviceProperty = 0, - StorageAdapterProperty, - StorageDeviceIdProperty, - StorageDeviceUniqueIdProperty, // See storduid.h for details - StorageDeviceWriteCacheProperty, - StorageMiniportProperty, - StorageAccessAlignmentProperty, - StorageDeviceSeekPenaltyProperty, - StorageDeviceTrimProperty, - StorageDeviceWriteAggregationProperty -} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; - -// -// Query structure - additional parameters for specific queries can follow -// the header -// - -typedef struct _STORAGE_PROPERTY_QUERY { - - // - // ID of the property being retrieved - // - - STORAGE_PROPERTY_ID PropertyId; - - // - // Flags indicating the type of query being performed - // - - STORAGE_QUERY_TYPE QueryType; - - // - // Space for additional parameters if necessary - // - - UCHAR AdditionalParameters[1]; - -} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY; - -// -// Standard property descriptor header. All property pages should use this -// as their first element or should contain these two elements -// - -typedef __struct_bcount(Size) struct _STORAGE_DESCRIPTOR_HEADER { - - ULONG Version; - - ULONG Size; - -} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER; - -// -// Device property descriptor - this is really just a rehash of the inquiry -// data retrieved from a scsi device -// -// This may only be retrieved from a target device. Sending this to the bus -// will result in an error -// - -typedef __struct_bcount(Size) struct _STORAGE_DEVICE_DESCRIPTOR { - - // - // Sizeof(STORAGE_DEVICE_DESCRIPTOR) - // - - ULONG Version; - - // - // Total size of the descriptor, including the space for additional - // data and id strings - // - - ULONG Size; - - // - // The SCSI-2 device type - // - - UCHAR DeviceType; - - // - // The SCSI-2 device type modifier (if any) - this may be zero - // - - UCHAR DeviceTypeModifier; - - // - // Flag indicating whether the device's media (if any) is removable. This - // field should be ignored for media-less devices - // - - BOOLEAN RemovableMedia; - - // - // Flag indicating whether the device can support mulitple outstanding - // commands. The actual synchronization in this case is the responsibility - // of the port driver. - // - - BOOLEAN CommandQueueing; - - // - // Byte offset to the zero-terminated ascii string containing the device's - // vendor id string. For devices with no such ID this will be zero - // - - ULONG VendorIdOffset; - - // - // Byte offset to the zero-terminated ascii string containing the device's - // product id string. For devices with no such ID this will be zero - // - - ULONG ProductIdOffset; - - // - // Byte offset to the zero-terminated ascii string containing the device's - // product revision string. For devices with no such string this will be - // zero - // - - ULONG ProductRevisionOffset; - - // - // Byte offset to the zero-terminated ascii string containing the device's - // serial number. For devices with no serial number this will be zero - // - - ULONG SerialNumberOffset; - - // - // Contains the bus type (as defined above) of the device. It should be - // used to interpret the raw device properties at the end of this structure - // (if any) - // - - STORAGE_BUS_TYPE BusType; - - // - // The number of bytes of bus-specific data which have been appended to - // this descriptor - // - - ULONG RawPropertiesLength; - - // - // Place holder for the first byte of the bus specific property data - // - - UCHAR RawDeviceProperties[1]; - -} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR; - - -// -// Adapter properties -// -// This descriptor can be retrieved from a target device object of from the -// device object for the bus. Retrieving from the target device object will -// forward the request to the underlying bus -// - -typedef __struct_bcount(Size) struct _STORAGE_ADAPTER_DESCRIPTOR { - - ULONG Version; - - ULONG Size; - - ULONG MaximumTransferLength; - - ULONG MaximumPhysicalPages; - - ULONG AlignmentMask; - - BOOLEAN AdapterUsesPio; - - BOOLEAN AdapterScansDown; - - BOOLEAN CommandQueueing; - - BOOLEAN AcceleratedTransfer; - -#if (NTDDI_VERSION < NTDDI_WINXP) - BOOLEAN BusType; -#else - UCHAR BusType; -#endif - - USHORT BusMajorVersion; - - USHORT BusMinorVersion; - -} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR; - -typedef __struct_bcount(Size) struct _STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR { - - // - // Sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) - // - - ULONG Version; - - // - // Total size of the descriptor, including the space for additional - // data and id strings - // - - ULONG Size; - - // - // The number of bytes in a cache line of the device - // - - ULONG BytesPerCacheLine; - - // - // The address offset neccessary for proper cache access alignment in bytes - // - - ULONG BytesOffsetForCacheAlignment; - - // - // The number of bytes in a physical sector of the device - // - - ULONG BytesPerLogicalSector; - - // - // The number of bytes in an addressable logical sector (LBA)of the device - // - - ULONG BytesPerPhysicalSector; - - // - // The address offset neccessary for proper sector access alignment in bytes - // - - ULONG BytesOffsetForSectorAlignment; - -} STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR, *PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR; - - - -typedef enum _STORAGE_PORT_CODE_SET { - StoragePortCodeSetReserved = 0, - StoragePortCodeSetStorport = 1, - StoragePortCodeSetSCSIport = 2 -} STORAGE_PORT_CODE_SET, *PSTORAGE_PORT_CODE_SET; - -typedef struct _STORAGE_MINIPORT_DESCRIPTOR { - - ULONG Version; - - ULONG Size; - - STORAGE_PORT_CODE_SET Portdriver; - - BOOLEAN LUNResetSupported; - - BOOLEAN TargetResetSupported; - - -} STORAGE_MINIPORT_DESCRIPTOR, *PSTORAGE_MINIPORT_DESCRIPTOR; - -// -// Storage identification descriptor. -// The definitions here are based on the SCSI/SBP vital product data -// device identifier page. -// - -typedef enum _STORAGE_IDENTIFIER_CODE_SET { - StorageIdCodeSetReserved = 0, - StorageIdCodeSetBinary = 1, - StorageIdCodeSetAscii = 2, - StorageIdCodeSetUtf8 = 3 -} STORAGE_IDENTIFIER_CODE_SET, *PSTORAGE_IDENTIFIER_CODE_SET; - -typedef enum _STORAGE_IDENTIFIER_TYPE { - StorageIdTypeVendorSpecific = 0, - StorageIdTypeVendorId = 1, - StorageIdTypeEUI64 = 2, - StorageIdTypeFCPHName = 3, - StorageIdTypePortRelative = 4, - StorageIdTypeTargetPortGroup = 5, - StorageIdTypeLogicalUnitGroup = 6, - StorageIdTypeMD5LogicalUnitIdentifier = 7, - StorageIdTypeScsiNameString = 8 -} STORAGE_IDENTIFIER_TYPE, *PSTORAGE_IDENTIFIER_TYPE; - -// Mislabeled above but need to keep it for backwards compatibility -#define StorageIdTypeNAA StorageIdTypeFCPHName - -// NAA formats (Used with StorageIdTypeNAA) -typedef enum _STORAGE_ID_NAA_FORMAT { - StorageIdNAAFormatIEEEExtended = 2, - StorageIdNAAFormatIEEERegistered = 3, - StorageIdNAAFormatIEEEERegisteredExtended = 5 -} STORAGE_ID_NAA_FORMAT, *PSTORAGE_ID_NAA_FORMAT; - -typedef enum _STORAGE_ASSOCIATION_TYPE { - StorageIdAssocDevice = 0, - StorageIdAssocPort = 1, - StorageIdAssocTarget = 2 -} STORAGE_ASSOCIATION_TYPE, *PSTORAGE_ASSOCIATION_TYPE; - -typedef struct _STORAGE_IDENTIFIER { - STORAGE_IDENTIFIER_CODE_SET CodeSet; - STORAGE_IDENTIFIER_TYPE Type; - USHORT IdentifierSize; - USHORT NextOffset; - - // - // Add new fields here since existing code depends on - // the above layout not changing. - // - - STORAGE_ASSOCIATION_TYPE Association; - - // - // The identifier is a variable length array of bytes. - // - - UCHAR Identifier[1]; -} STORAGE_IDENTIFIER, *PSTORAGE_IDENTIFIER; - -typedef __struct_bcount(Size) struct _STORAGE_DEVICE_ID_DESCRIPTOR { - - ULONG Version; - - ULONG Size; - - // - // The number of identifiers reported by the device. - // - - ULONG NumberOfIdentifiers; - - // - // The following field is actually a variable length array of identification - // descriptors. Unfortunately there's no C notation for an array of - // variable length structures so we're forced to just pretend. - // - - UCHAR Identifiers[1]; -} STORAGE_DEVICE_ID_DESCRIPTOR, *PSTORAGE_DEVICE_ID_DESCRIPTOR; - -// output buffer for StorageDeviceSeekPenaltyProperty & PropertyStandardQuery -typedef struct _DEVICE_SEEK_PENALTY_DESCRIPTOR { - ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER - ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER - - BOOLEAN IncursSeekPenalty; -} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR; - -// output buffer for StorageDeviceWriteAggregationProperty & PropertyStandardQuery -typedef struct _DEVICE_WRITE_AGGREGATION_DESCRIPTOR { - ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER - ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER - - BOOLEAN BenefitsFromWriteAggregation; -} DEVICE_WRITE_AGGREGATION_DESCRIPTOR, *PDEVICE_WRITE_AGGREGATION_DESCRIPTOR; - -// output buffer for StorageDeviceTrimProperty & PropertyStandardQuery -typedef struct _DEVICE_TRIM_DESCRIPTOR { - ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER - ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER - - BOOLEAN TrimEnabled; -} DEVICE_TRIM_DESCRIPTOR, *PDEVICE_TRIM_DESCRIPTOR; - -// -// IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES -// -// Input Buffer: -// Structure of type DEVICE_MANAGE_DATA_SET_ATTRIBUTES -// -// Output Buffer: -// N/A -// -// Note: -// 1. Management of action Trim will be only allowed for kernel request. -// This request sent from user application will be rejected by kernel drivers. -// - -// -// This flag, when OR'd into an action indicates that the given action is -// non-destructive. If this flag is set then storage stack components which -// do not understand the action should forward the given request -// - -#define DeviceDsmActionFlag_NonDestructive 0x80000000 - -#define IsDsmActionNonDestructive(_Action) ((BOOLEAN)((_Action & DeviceDsmActionFlag_NonDestructive) != 0)) - -// -// Defines the various actions -// - -typedef ULONG DEVICE_DATA_MANAGEMENT_SET_ACTION; - #define DeviceDsmAction_None 0 - #define DeviceDsmAction_Trim 1 - #define DeviceDsmAction_Notification (2 | DeviceDsmActionFlag_NonDestructive) - -// -// Flags that are global across all actions -// - -#define DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE 0x00000001 // If set, the DataSetRanges fields should be 0 - - -typedef struct _DEVICE_DATA_SET_RANGE { - LONGLONG StartingOffset; //in bytes , must allign to sector - ULONGLONG LengthInBytes; // multiple of sector size. -} DEVICE_DATA_SET_RANGE, *PDEVICE_DATA_SET_RANGE; - -// -// input structure for IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES -// 1. Value ofParameterBlockOffset or ParameterBlockLength is 0 indicates that Parameter Block does not exist. -// 2. Value of DataSetRangesOffset or DataSetRangesLength is 0 indicates that DataSetRanges Block does not exist. -// If DataSetRanges Block exists, it contains contiguous DEVICE_DATA_SET_RANGE structures. -// 3. The total size of buffer should be at least: -// sizeof (DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + ParameterBlockLength + DataSetRangesLength -// -typedef struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES { - ULONG Size; // Size of structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES - DEVICE_DATA_MANAGEMENT_SET_ACTION Action; - - ULONG Flags; // Global flags across all actions - - ULONG ParameterBlockOffset; // must be alligned to corresponding structure allignment - ULONG ParameterBlockLength; // 0 means Parameter Block does not exist. - - ULONG DataSetRangesOffset; // must be alligned to DEVICE_DATA_SET_RANGE structure allignment. - ULONG DataSetRangesLength; // 0 means DataSetRanges Block does not exist. - -} DEVICE_MANAGE_DATA_SET_ATTRIBUTES, *PDEVICE_MANAGE_DATA_SET_ATTRIBUTES; - -// -// This defines the parameter block for the DeviceDsmAction_Notification -// action -// - -typedef struct _DEVICE_DSM_NOTIFICATION_PARAMETERS { - - ULONG Size; // Size of this structure - - ULONG Flags; // Flags specific to the notify operation - - ULONG NumFileTypeIDs; // Count of how many file type ID's are given - - GUID FileTypeID[1]; // Identifier for the type of file being notified - -} DEVICE_DSM_NOTIFICATION_PARAMETERS, *PDEVICE_DSM_NOTIFICATION_PARAMETERS; - -// -// DEVICE_DSM_NOTIFICATION_PARAMETERS flag definitions -// - -#define DEVICE_DSM_NOTIFY_FLAG_BEGIN 0x00000001 // The given LBA range is being used as defined by the FileID -#define DEVICE_DSM_NOTIFY_FLAG_END 0x00000002 // The given LBA range is no longer being used as defined by the FileID - -// -// There are some well known GUIDS for certail types of files. They are -// defined in NTIFS.H -// - - -// -// IOCTL_STORAGE_GET_BC_PROPERTIES -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type STORAGE_GET_BC_PROPERTIES_OUTPUT -// - -typedef struct _STORAGE_GET_BC_PROPERTIES_OUTPUT { - - // - // Specifies the maximum number of requests - // that can be scheduled per period of time - // - ULONG MaximumRequestsPerPeriod; - - // - // Specifies the minimum period that the - // device uses when scheduling requests - // - ULONG MinimumPeriod; - - // - // Specifies the maximum transfer size supported - // for bandwidth contracts on this device. To - // achieve the highest level of performance, all - // requests should be of this size - // - ULONGLONG MaximumRequestSize; - - // - // Specifies the estimated time taken to - // perform an Io operstion. This field - // is for informational purposes only - // - ULONG EstimatedTimePerRequest; - - // - // Specifies the number of requests that should be - // kept outstanding. This helps keep the device - // device busy and thus obtain maximum throughput. - // This will only be filled in if the target file - // has an outstanding contract. - // - ULONG NumOutStandingRequests; - - // - // Specifies the required size of requests in this - // stream. This will only be filled in if the - // target file has an outstanding contract. - // - ULONGLONG RequestSize; - -} STORAGE_GET_BC_PROPERTIES_OUTPUT, *PSTORAGE_GET_BC_PROPERTIES_OUTPUT; - - -// -// IOCTL_STORAGE_ALLOCATE_BC_STREAM -// -// Input Buffer: -// Structure of type STORAGE_ALLOCATE_BC_STREAM_INPUT -// -// Output Buffer: -// Structure of type STORAGE_ALLOCATE_BC_STREAM_OUTPUT -// - - -// -// Current version -// -#define IOCTL_STORAGE_BC_VERSION 1 - -typedef struct _STORAGE_ALLOCATE_BC_STREAM_INPUT { - - // - // Specifies the corresponding structure version - // - ULONG Version; - - // - // Specifies the number of requests that - // need to complete per period of time - // - ULONG RequestsPerPeriod; - - // - // Specifies the period of time wherein the - // above number of requests must complete - // - ULONG Period; - - // - // Indicates whether failures - // should be retried or not - // - BOOLEAN RetryFailures; - - // - // Indicates whether reqests that will miss - // their deadline should be discarded or not - // - BOOLEAN Discardable; - - // - // Helps align the following field - // - BOOLEAN Reserved1[2]; - - // - // Indicates whether the Io will be - // comprised of reads, writes or both - // - ULONG AccessType; - - // - // Indicates whether the Io to the - // file will be sequential or random - // - ULONG AccessMode; - -} STORAGE_ALLOCATE_BC_STREAM_INPUT, *PSTORAGE_ALLOCATE_BC_STREAM_INPUT; - -typedef struct _STORAGE_ALLOCATE_BC_STREAM_OUTPUT { - - // - // Specifies the required size - // of requests in this stream - // - ULONGLONG RequestSize; - - // - // Specifies the number of requests that should be - // kept outstanding. This helps keep the device - // device busy and thus obtain maximum throughput - // - ULONG NumOutStandingRequests; - -} STORAGE_ALLOCATE_BC_STREAM_OUTPUT, *PSTORAGE_ALLOCATE_BC_STREAM_OUTPUT; - - -// -// IOCTL_STORAGE_FREE_BC_STREAM -// -// Input Buffer: -// None -// -// Output Buffer: -// None -// - -// -// IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT -// -// Input Buffer : -// None -// Output Buffer : -// Structure of type STORAGE_PRIORITY_HINT_SUPPORT -// - -#define STORAGE_PRIORITY_HINT_SUPPORTED 0x0001 - -typedef struct _STORAGE_PRIORITY_HINT_SUPPORT { - ULONG SupportFlags; -} STORAGE_PRIORITY_HINT_SUPPORT, *PSTORAGE_PRIORITY_HINT_SUPPORT; - -#pragma warning(push) -#pragma warning(disable:4200) - -#if defined(_MSC_EXTENSIONS) - -typedef struct _STORAGE_MEDIA_SERIAL_NUMBER_DATA { - - USHORT Reserved; - - // - // the SerialNumberLength will be set to zero - // if the command is supported and the media - // does not have a valid serial number. - // - - USHORT SerialNumberLength; - - // - // the following data is binary, and is not guaranteed - // to be NULL terminated. this is an excercise for the - // caller. - // - -#if !defined(__midl) - UCHAR SerialNumber[0]; -#endif - -} STORAGE_MEDIA_SERIAL_NUMBER_DATA, *PSTORAGE_MEDIA_SERIAL_NUMBER_DATA; - -#endif /* _MSC_EXTENSIONS */ - -typedef __struct_bcount(Size) struct _STORAGE_READ_CAPACITY { - - // - // The version number, size of the STORAGE_READ_CAPACITY structure - // - ULONG Version; - - // - // The size of the date returned, size of the STORAGE_READ_CAPACITY structure - // - ULONG Size; - - // - // Number of bytes per block - // - - ULONG BlockLength; - - // - // Total number of blocks in the disk - // This will have the last LBA + 1 - // - - LARGE_INTEGER NumberOfBlocks; - - // - // Disk size in bytes - // - - LARGE_INTEGER DiskLength; - -} STORAGE_READ_CAPACITY, *PSTORAGE_READ_CAPACITY; - -#pragma warning(pop) - -// -// Device write cache property -// -// This property provides the write cache information -// about the target device. -// - -typedef enum _WRITE_CACHE_TYPE { - WriteCacheTypeUnknown, - WriteCacheTypeNone, - WriteCacheTypeWriteBack, - WriteCacheTypeWriteThrough -} WRITE_CACHE_TYPE; - -typedef enum _WRITE_CACHE_ENABLE { - WriteCacheEnableUnknown, - WriteCacheDisabled, - WriteCacheEnabled -} WRITE_CACHE_ENABLE; - -typedef enum _WRITE_CACHE_CHANGE { - WriteCacheChangeUnknown, - WriteCacheNotChangeable, - WriteCacheChangeable -} WRITE_CACHE_CHANGE; - -typedef enum _WRITE_THROUGH { - WriteThroughUnknown, - WriteThroughNotSupported, - WriteThroughSupported -} WRITE_THROUGH; - -typedef __struct_bcount(Size) struct _STORAGE_WRITE_CACHE_PROPERTY { - - // - // The version number - // Size of STORAGE_WRITE_CACHE_PROPERTY structure - // - ULONG Version; - - // - // The size of the date returned - // Size of STORAGE_WRITE_CACHE_PROPERTY structure - // - ULONG Size; - - // - // Current write cache type - // - WRITE_CACHE_TYPE WriteCacheType; - - // - // Current write cache value - // - WRITE_CACHE_ENABLE WriteCacheEnabled; - - // - // Device write cache change capability - // - WRITE_CACHE_CHANGE WriteCacheChangeable; - - // - // Device write through support capability - // - WRITE_THROUGH WriteThroughSupported; - - // - // Device flush cache capability - // - BOOLEAN FlushCacheSupported; - - // - // User selected power protection option through registry - // - BOOLEAN UserDefinedPowerProtection; - - // - // Device has battery backup for write cache - // - BOOLEAN NVCacheEnabled; - -} STORAGE_WRITE_CACHE_PROPERTY, *PSTORAGE_WRITE_CACHE_PROPERTY; - -#pragma warning(push) -#pragma warning(disable:4200) // array[0] -#pragma warning(disable:4201) // nameless struct/unions -#pragma warning(disable:4214) // bit fields other than int -#if defined(__INTEL_COMPILER) -#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero -#endif - - -#if defined(_MSC_EXTENSIONS) - -typedef struct _PERSISTENT_RESERVE_COMMAND { - - ULONG Version; - ULONG Size; - - union { - - struct { - - // - // Persistent Reserve service action. - // - - UCHAR ServiceAction : 5; - UCHAR Reserved1 : 3; - - // - // Number of bytes allocated for returned parameter list. - // - - USHORT AllocationLength; - - } PR_IN; - - struct { - - // - // Persistent Reserve service action. - // - - UCHAR ServiceAction : 5; - UCHAR Reserved1 : 3; - - // - // Persistent Reserve type and scope. - // - - UCHAR Type : 4; - UCHAR Scope : 4; - - // - // Space for additional PR Out parameters. - // - -#if !defined(__midl) - UCHAR ParameterList[0]; -#endif - - } PR_OUT; - }; - -} PERSISTENT_RESERVE_COMMAND, *PPERSISTENT_RESERVE_COMMAND; - -#endif /* _MSC_EXTENSIONS */ -#pragma warning(pop) - - -#ifdef __cplusplus -} -#endif - -#endif // _NTDDSTOR_H_ -// end_winioctl - +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddstor.h + +Abstract: + + This is the include file that defines all common constants and types + accessing the storage class drivers + +--*/ + +#include "devioctl.h" + +// +// Interface GUIDs +// +// need these GUIDs outside conditional includes so that user can +// #include in precompiled header +// #include in a single source file +// #include in that source file a second time to instantiate the GUIDs +// +#ifdef DEFINE_GUID +// +// Make sure FAR is defined... +// +#ifndef FAR +#ifdef _WIN32 +#define FAR +#else +#define FAR _far +#endif +#endif + +// begin_wioctlguids + +DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_CDROM, 0x53f56308L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_PARTITION, 0x53f5630aL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_TAPE, 0x53f5630bL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_WRITEONCEDISK, 0x53f5630cL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_MEDIUMCHANGER, 0x53f56310L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_FLOPPY, 0x53f56311L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_CDCHANGER, 0x53f56312L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); + +#define WDI_STORAGE_PREDICT_FAILURE_DPS_GUID {0xe9f2d03aL, 0x747c, 0x41c2, {0xbb, 0x9a, 0x02, 0xc6, 0x2b, 0x6d, 0x5f, 0xcb}}; + +// +// The interface used to discover volumes that are +// not reported by Win32 APIs. This includes those +// with an unrecognized partition type/id and ones +// with the hidden attribute. +// +DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME, 0x7f108a28L, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62); + +// end_wioctlguids + +// begin_wioctlobsoleteguids + +#define DiskClassGuid GUID_DEVINTERFACE_DISK +#define CdRomClassGuid GUID_DEVINTERFACE_CDROM +#define PartitionClassGuid GUID_DEVINTERFACE_PARTITION +#define TapeClassGuid GUID_DEVINTERFACE_TAPE +#define WriteOnceDiskClassGuid GUID_DEVINTERFACE_WRITEONCEDISK +#define VolumeClassGuid GUID_DEVINTERFACE_VOLUME +#define MediumChangerClassGuid GUID_DEVINTERFACE_MEDIUMCHANGER +#define FloppyClassGuid GUID_DEVINTERFACE_FLOPPY +#define CdChangerClassGuid GUID_DEVINTERFACE_CDCHANGER +#define StoragePortClassGuid GUID_DEVINTERFACE_STORAGEPORT +#define HiddenVolumeClassGuid GUID_DEVINTERFACE_HIDDEN_VOLUME + +// end_wioctlobsoleteguids +#endif + +// begin_winioctl + +#ifndef _NTDDSTOR_H_ +#define _NTDDSTOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// +// IoControlCode values for storage devices +// + +#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE + +// +// The following device control codes are common for all class drivers. They +// should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE +// common codes +// + +#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_STORAGE_EJECTION_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MCN_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_STORAGE_GET_MEDIA_TYPES CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0304, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0305, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_SET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0306, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_BREAK_RESERVATION CTL_CODE(IOCTL_STORAGE_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_PERSISTENT_RESERVE_IN CTL_CODE(IOCTL_STORAGE_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_PERSISTENT_RESERVE_OUT CTL_CODE(IOCTL_STORAGE_BASE, 0x0407, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_PREDICT_FAILURE CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_READ_CAPACITY CTL_CODE(IOCTL_STORAGE_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// IOCTLs 0x0463 to 0x0468 reserved for dependent disk support. +// + +#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES CTL_CODE(IOCTL_STORAGE_BASE, 0x0501, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +// +// IOCTLs for bandwidth contracts on storage devices +// (Move this to ntddsfio if we decide to use a new base) +// + +#define IOCTL_STORAGE_GET_BC_PROPERTIES CTL_CODE(IOCTL_STORAGE_BASE, 0x0600, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_ALLOCATE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0601, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_FREE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0602, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTL to check for priority support +// +#define IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT CTL_CODE(IOCTL_STORAGE_BASE, 0x0620, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// begin_winioctl + +// +// These ioctl codes are obsolete. They are defined here to avoid resuing them +// and to allow class drivers to respond to them more easily. +// + +#define OBSOLETE_IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define OBSOLETE_IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTLs 0x0643 to 0x0655 reserved for VHD disk support. +// + +// +// IOCTL_STORAGE_GET_HOTPLUG_INFO +// + +typedef struct _STORAGE_HOTPLUG_INFO { + ULONG Size; // version + BOOLEAN MediaRemovable; // ie. zip, jaz, cdrom, mo, etc. vs hdd + BOOLEAN MediaHotplug; // ie. does the device succeed a lock even though its not lockable media? + BOOLEAN DeviceHotplug; // ie. 1394, USB, etc. + BOOLEAN WriteCacheEnableOverride; // This field should not be relied upon because it is no longer used +} STORAGE_HOTPLUG_INFO, *PSTORAGE_HOTPLUG_INFO; + +// +// IOCTL_STORAGE_GET_DEVICE_NUMBER +// +// input - none +// +// output - STORAGE_DEVICE_NUMBER structure +// The values in the STORAGE_DEVICE_NUMBER structure are guaranteed +// to remain unchanged until the system is rebooted. They are not +// guaranteed to be persistant across boots. +// + +typedef struct _STORAGE_DEVICE_NUMBER { + + // + // The FILE_DEVICE_XXX type for this device. + // + + DEVICE_TYPE DeviceType; + + // + // The number of this device + // + + ULONG DeviceNumber; + + // + // If the device is partitionable, the partition number of the device. + // Otherwise -1 + // + + ULONG PartitionNumber; +} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER; + +// +// Define the structures for scsi resets +// + +typedef struct _STORAGE_BUS_RESET_REQUEST { + UCHAR PathId; +} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST; + +// +// Break reservation is sent to the Adapter/FDO with the given lun information. +// + +typedef struct STORAGE_BREAK_RESERVATION_REQUEST { + ULONG Length; + UCHAR _unused; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} STORAGE_BREAK_RESERVATION_REQUEST, *PSTORAGE_BREAK_RESERVATION_REQUEST; + + +// +// IOCTL_STORAGE_MEDIA_REMOVAL disables the mechanism +// on a storage device that ejects media. This function +// may or may not be supported on storage devices that +// support removable media. +// +// TRUE means prevent media from being removed. +// FALSE means allow media removal. +// + +typedef struct _PREVENT_MEDIA_REMOVAL { + BOOLEAN PreventMediaRemoval; +} PREVENT_MEDIA_REMOVAL, *PPREVENT_MEDIA_REMOVAL; + + + +// +// This is the format of TARGET_DEVICE_CUSTOM_NOTIFICATION.CustomDataBuffer +// passed to applications by the classpnp autorun code (via IoReportTargetDeviceChangeAsynchronous). +// +typedef struct _CLASS_MEDIA_CHANGE_CONTEXT { + ULONG MediaChangeCount; + ULONG NewState; // see MEDIA_CHANGE_DETECTION_STATE enum in classpnp.h in DDK +} CLASS_MEDIA_CHANGE_CONTEXT, *PCLASS_MEDIA_CHANGE_CONTEXT; + + +// begin_ntminitape + + +typedef struct _TAPE_STATISTICS { + ULONG Version; + ULONG Flags; + LARGE_INTEGER RecoveredWrites; + LARGE_INTEGER UnrecoveredWrites; + LARGE_INTEGER RecoveredReads; + LARGE_INTEGER UnrecoveredReads; + UCHAR CompressionRatioReads; + UCHAR CompressionRatioWrites; +} TAPE_STATISTICS, *PTAPE_STATISTICS; + +#define RECOVERED_WRITES_VALID 0x00000001 +#define UNRECOVERED_WRITES_VALID 0x00000002 +#define RECOVERED_READS_VALID 0x00000004 +#define UNRECOVERED_READS_VALID 0x00000008 +#define WRITE_COMPRESSION_INFO_VALID 0x00000010 +#define READ_COMPRESSION_INFO_VALID 0x00000020 + +typedef struct _TAPE_GET_STATISTICS { + ULONG Operation; +} TAPE_GET_STATISTICS, *PTAPE_GET_STATISTICS; + +#define TAPE_RETURN_STATISTICS 0L +#define TAPE_RETURN_ENV_INFO 1L +#define TAPE_RESET_STATISTICS 2L + +// +// IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO +// structures, one per supported type, embedded in the GET_MEDIA_TYPES struct. +// + +typedef enum _STORAGE_MEDIA_TYPE { + // + // Following are defined in ntdddisk.h in the MEDIA_TYPE enum + // + // Unknown, // Format is unknown + // F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector + // F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector + // F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector + // F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector + // F3_720_512, // 3.5", 720KB, 512 bytes/sector + // F5_360_512, // 5.25", 360KB, 512 bytes/sector + // F5_320_512, // 5.25", 320KB, 512 bytes/sector + // F5_320_1024, // 5.25", 320KB, 1024 bytes/sector + // F5_180_512, // 5.25", 180KB, 512 bytes/sector + // F5_160_512, // 5.25", 160KB, 512 bytes/sector + // RemovableMedia, // Removable media other than floppy + // FixedMedia, // Fixed hard disk media + // F3_120M_512, // 3.5", 120M Floppy + // F3_640_512, // 3.5" , 640KB, 512 bytes/sector + // F5_640_512, // 5.25", 640KB, 512 bytes/sector + // F5_720_512, // 5.25", 720KB, 512 bytes/sector + // F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector + // F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector + // F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector + // F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector + // F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector + // F8_256_128, // 8", 256KB, 128 bytes/sector + // F3_200Mb_512, // 3.5", 200M Floppy (HiFD) + // + + DDS_4mm = 0x20, // Tape - DAT DDS1,2,... (all vendors) + MiniQic, // Tape - miniQIC Tape + Travan, // Tape - Travan TR-1,2,3,... + QIC, // Tape - QIC + MP_8mm, // Tape - 8mm Exabyte Metal Particle + AME_8mm, // Tape - 8mm Exabyte Advanced Metal Evap + AIT1_8mm, // Tape - 8mm Sony AIT + DLT, // Tape - DLT Compact IIIxt, IV + NCTP, // Tape - Philips NCTP + IBM_3480, // Tape - IBM 3480 + IBM_3490E, // Tape - IBM 3490E + IBM_Magstar_3590, // Tape - IBM Magstar 3590 + IBM_Magstar_MP, // Tape - IBM Magstar MP + STK_DATA_D3, // Tape - STK Data D3 + SONY_DTF, // Tape - Sony DTF + DV_6mm, // Tape - 6mm Digital Video + DMI, // Tape - Exabyte DMI and compatibles + SONY_D2, // Tape - Sony D2S and D2L + CLEANER_CARTRIDGE, // Cleaner - All Drive types that support Drive Cleaners + CD_ROM, // Opt_Disk - CD + CD_R, // Opt_Disk - CD-Recordable (Write Once) + CD_RW, // Opt_Disk - CD-Rewriteable + DVD_ROM, // Opt_Disk - DVD-ROM + DVD_R, // Opt_Disk - DVD-Recordable (Write Once) + DVD_RW, // Opt_Disk - DVD-Rewriteable + MO_3_RW, // Opt_Disk - 3.5" Rewriteable MO Disk + MO_5_WO, // Opt_Disk - MO 5.25" Write Once + MO_5_RW, // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW) + MO_5_LIMDOW, // Opt_Disk - MO 5.25" Rewriteable (LIMDOW) + PC_5_WO, // Opt_Disk - Phase Change 5.25" Write Once Optical + PC_5_RW, // Opt_Disk - Phase Change 5.25" Rewriteable + PD_5_RW, // Opt_Disk - PhaseChange Dual Rewriteable + ABL_5_WO, // Opt_Disk - Ablative 5.25" Write Once Optical + PINNACLE_APEX_5_RW, // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical + SONY_12_WO, // Opt_Disk - Sony 12" Write Once + PHILIPS_12_WO, // Opt_Disk - Philips/LMS 12" Write Once + HITACHI_12_WO, // Opt_Disk - Hitachi 12" Write Once + CYGNET_12_WO, // Opt_Disk - Cygnet/ATG 12" Write Once + KODAK_14_WO, // Opt_Disk - Kodak 14" Write Once + MO_NFR_525, // Opt_Disk - Near Field Recording (Terastor) + NIKON_12_RW, // Opt_Disk - Nikon 12" Rewriteable + IOMEGA_ZIP, // Mag_Disk - Iomega Zip + IOMEGA_JAZ, // Mag_Disk - Iomega Jaz + SYQUEST_EZ135, // Mag_Disk - Syquest EZ135 + SYQUEST_EZFLYER, // Mag_Disk - Syquest EzFlyer + SYQUEST_SYJET, // Mag_Disk - Syquest SyJet + AVATAR_F2, // Mag_Disk - 2.5" Floppy + MP2_8mm, // Tape - 8mm Hitachi + DST_S, // Ampex DST Small Tapes + DST_M, // Ampex DST Medium Tapes + DST_L, // Ampex DST Large Tapes + VXATape_1, // Ecrix 8mm Tape + VXATape_2, // Ecrix 8mm Tape +#if (NTDDI_VERSION < NTDDI_WINXP) + STK_EAGLE, // STK Eagle +#else + STK_9840, // STK 9840 +#endif + LTO_Ultrium, // IBM, HP, Seagate LTO Ultrium + LTO_Accelis, // IBM, HP, Seagate LTO Accelis + DVD_RAM, // Opt_Disk - DVD-RAM + AIT_8mm, // AIT2 or higher + ADR_1, // OnStream ADR Mediatypes + ADR_2, + STK_9940, // STK 9940 + SAIT, // SAIT Tapes + VXATape // VXA (Ecrix 8mm) Tape +}STORAGE_MEDIA_TYPE, *PSTORAGE_MEDIA_TYPE; + +#define MEDIA_ERASEABLE 0x00000001 +#define MEDIA_WRITE_ONCE 0x00000002 +#define MEDIA_READ_ONLY 0x00000004 +#define MEDIA_READ_WRITE 0x00000008 + +#define MEDIA_WRITE_PROTECTED 0x00000100 +#define MEDIA_CURRENTLY_MOUNTED 0x80000000 + +// +// Define the different storage bus types +// Bus types below 128 (0x80) are reserved for Microsoft use +// + +typedef enum _STORAGE_BUS_TYPE { + BusTypeUnknown = 0x00, + BusTypeScsi, + BusTypeAtapi, + BusTypeAta, + BusType1394, + BusTypeSsa, + BusTypeFibre, + BusTypeUsb, + BusTypeRAID, + BusTypeiScsi, + BusTypeSas, + BusTypeSata, + BusTypeSd, + BusTypeMmc, + BusTypeVirtual, + BusTypeFileBackedVirtual, + BusTypeMax, + BusTypeMaxReserved = 0x7F +} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; + +typedef struct _DEVICE_MEDIA_INFO { + union { + struct { + LARGE_INTEGER Cylinders; + STORAGE_MEDIA_TYPE MediaType; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; + ULONG NumberMediaSides; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + } DiskInfo; + + struct { + LARGE_INTEGER Cylinders; + STORAGE_MEDIA_TYPE MediaType; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; + ULONG NumberMediaSides; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + } RemovableDiskInfo; + + struct { + STORAGE_MEDIA_TYPE MediaType; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + ULONG CurrentBlockSize; + STORAGE_BUS_TYPE BusType; + + // + // Bus specific information describing the medium supported. + // + + union { + struct { + UCHAR MediumType; + UCHAR DensityCode; + } ScsiInformation; + } BusSpecificData; + + } TapeInfo; + } DeviceSpecific; +} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO; + +typedef struct _GET_MEDIA_TYPES { + ULONG DeviceType; // FILE_DEVICE_XXX values + ULONG MediaInfoCount; + DEVICE_MEDIA_INFO MediaInfo[1]; +} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES; + + +// +// IOCTL_STORAGE_PREDICT_FAILURE +// +// input - none +// +// output - STORAGE_PREDICT_FAILURE structure +// PredictFailure returns zero if no failure predicted and non zero +// if a failure is predicted. +// +// VendorSpecific returns 512 bytes of vendor specific information +// if a failure is predicted +// +typedef struct _STORAGE_PREDICT_FAILURE +{ + ULONG PredictFailure; + UCHAR VendorSpecific[512]; +} STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE; + +// end_ntminitape + +// +// Property Query Structures +// + +// +// IOCTL_STORAGE_QUERY_PROPERTY +// +// Input Buffer: +// a STORAGE_PROPERTY_QUERY structure which describes what type of query +// is being done, what property is being queried for, and any additional +// parameters which a particular property query requires. +// +// Output Buffer: +// Contains a buffer to place the results of the query into. Since all +// property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER, +// the IOCTL can be called once with a small buffer then again using +// a buffer as large as the header reports is necessary. +// + + +// +// Types of queries +// + +typedef enum _STORAGE_QUERY_TYPE { + PropertyStandardQuery = 0, // Retrieves the descriptor + PropertyExistsQuery, // Used to test whether the descriptor is supported + PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor + PropertyQueryMaxDefined // use to validate the value +} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; + +// +// define some initial property id's +// + +typedef enum _STORAGE_PROPERTY_ID { + StorageDeviceProperty = 0, + StorageAdapterProperty, + StorageDeviceIdProperty, + StorageDeviceUniqueIdProperty, // See storduid.h for details + StorageDeviceWriteCacheProperty, + StorageMiniportProperty, + StorageAccessAlignmentProperty, + StorageDeviceSeekPenaltyProperty, + StorageDeviceTrimProperty, + StorageDeviceWriteAggregationProperty +} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; + +// +// Query structure - additional parameters for specific queries can follow +// the header +// + +typedef struct _STORAGE_PROPERTY_QUERY { + + // + // ID of the property being retrieved + // + + STORAGE_PROPERTY_ID PropertyId; + + // + // Flags indicating the type of query being performed + // + + STORAGE_QUERY_TYPE QueryType; + + // + // Space for additional parameters if necessary + // + + UCHAR AdditionalParameters[1]; + +} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY; + +// +// Standard property descriptor header. All property pages should use this +// as their first element or should contain these two elements +// + +typedef __struct_bcount(Size) struct _STORAGE_DESCRIPTOR_HEADER { + + ULONG Version; + + ULONG Size; + +} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER; + +// +// Device property descriptor - this is really just a rehash of the inquiry +// data retrieved from a scsi device +// +// This may only be retrieved from a target device. Sending this to the bus +// will result in an error +// + +typedef __struct_bcount(Size) struct _STORAGE_DEVICE_DESCRIPTOR { + + // + // Sizeof(STORAGE_DEVICE_DESCRIPTOR) + // + + ULONG Version; + + // + // Total size of the descriptor, including the space for additional + // data and id strings + // + + ULONG Size; + + // + // The SCSI-2 device type + // + + UCHAR DeviceType; + + // + // The SCSI-2 device type modifier (if any) - this may be zero + // + + UCHAR DeviceTypeModifier; + + // + // Flag indicating whether the device's media (if any) is removable. This + // field should be ignored for media-less devices + // + + BOOLEAN RemovableMedia; + + // + // Flag indicating whether the device can support mulitple outstanding + // commands. The actual synchronization in this case is the responsibility + // of the port driver. + // + + BOOLEAN CommandQueueing; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // vendor id string. For devices with no such ID this will be zero + // + + ULONG VendorIdOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // product id string. For devices with no such ID this will be zero + // + + ULONG ProductIdOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // product revision string. For devices with no such string this will be + // zero + // + + ULONG ProductRevisionOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // serial number. For devices with no serial number this will be zero + // + + ULONG SerialNumberOffset; + + // + // Contains the bus type (as defined above) of the device. It should be + // used to interpret the raw device properties at the end of this structure + // (if any) + // + + STORAGE_BUS_TYPE BusType; + + // + // The number of bytes of bus-specific data which have been appended to + // this descriptor + // + + ULONG RawPropertiesLength; + + // + // Place holder for the first byte of the bus specific property data + // + + UCHAR RawDeviceProperties[1]; + +} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR; + + +// +// Adapter properties +// +// This descriptor can be retrieved from a target device object of from the +// device object for the bus. Retrieving from the target device object will +// forward the request to the underlying bus +// + +typedef __struct_bcount(Size) struct _STORAGE_ADAPTER_DESCRIPTOR { + + ULONG Version; + + ULONG Size; + + ULONG MaximumTransferLength; + + ULONG MaximumPhysicalPages; + + ULONG AlignmentMask; + + BOOLEAN AdapterUsesPio; + + BOOLEAN AdapterScansDown; + + BOOLEAN CommandQueueing; + + BOOLEAN AcceleratedTransfer; + +#if (NTDDI_VERSION < NTDDI_WINXP) + BOOLEAN BusType; +#else + UCHAR BusType; +#endif + + USHORT BusMajorVersion; + + USHORT BusMinorVersion; + +} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR; + +typedef __struct_bcount(Size) struct _STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR { + + // + // Sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) + // + + ULONG Version; + + // + // Total size of the descriptor, including the space for additional + // data and id strings + // + + ULONG Size; + + // + // The number of bytes in a cache line of the device + // + + ULONG BytesPerCacheLine; + + // + // The address offset neccessary for proper cache access alignment in bytes + // + + ULONG BytesOffsetForCacheAlignment; + + // + // The number of bytes in a physical sector of the device + // + + ULONG BytesPerLogicalSector; + + // + // The number of bytes in an addressable logical sector (LBA)of the device + // + + ULONG BytesPerPhysicalSector; + + // + // The address offset neccessary for proper sector access alignment in bytes + // + + ULONG BytesOffsetForSectorAlignment; + +} STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR, *PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR; + + + +typedef enum _STORAGE_PORT_CODE_SET { + StoragePortCodeSetReserved = 0, + StoragePortCodeSetStorport = 1, + StoragePortCodeSetSCSIport = 2 +} STORAGE_PORT_CODE_SET, *PSTORAGE_PORT_CODE_SET; + +typedef struct _STORAGE_MINIPORT_DESCRIPTOR { + + ULONG Version; + + ULONG Size; + + STORAGE_PORT_CODE_SET Portdriver; + + BOOLEAN LUNResetSupported; + + BOOLEAN TargetResetSupported; + + +} STORAGE_MINIPORT_DESCRIPTOR, *PSTORAGE_MINIPORT_DESCRIPTOR; + +// +// Storage identification descriptor. +// The definitions here are based on the SCSI/SBP vital product data +// device identifier page. +// + +typedef enum _STORAGE_IDENTIFIER_CODE_SET { + StorageIdCodeSetReserved = 0, + StorageIdCodeSetBinary = 1, + StorageIdCodeSetAscii = 2, + StorageIdCodeSetUtf8 = 3 +} STORAGE_IDENTIFIER_CODE_SET, *PSTORAGE_IDENTIFIER_CODE_SET; + +typedef enum _STORAGE_IDENTIFIER_TYPE { + StorageIdTypeVendorSpecific = 0, + StorageIdTypeVendorId = 1, + StorageIdTypeEUI64 = 2, + StorageIdTypeFCPHName = 3, + StorageIdTypePortRelative = 4, + StorageIdTypeTargetPortGroup = 5, + StorageIdTypeLogicalUnitGroup = 6, + StorageIdTypeMD5LogicalUnitIdentifier = 7, + StorageIdTypeScsiNameString = 8 +} STORAGE_IDENTIFIER_TYPE, *PSTORAGE_IDENTIFIER_TYPE; + +// Mislabeled above but need to keep it for backwards compatibility +#define StorageIdTypeNAA StorageIdTypeFCPHName + +// NAA formats (Used with StorageIdTypeNAA) +typedef enum _STORAGE_ID_NAA_FORMAT { + StorageIdNAAFormatIEEEExtended = 2, + StorageIdNAAFormatIEEERegistered = 3, + StorageIdNAAFormatIEEEERegisteredExtended = 5 +} STORAGE_ID_NAA_FORMAT, *PSTORAGE_ID_NAA_FORMAT; + +typedef enum _STORAGE_ASSOCIATION_TYPE { + StorageIdAssocDevice = 0, + StorageIdAssocPort = 1, + StorageIdAssocTarget = 2 +} STORAGE_ASSOCIATION_TYPE, *PSTORAGE_ASSOCIATION_TYPE; + +typedef struct _STORAGE_IDENTIFIER { + STORAGE_IDENTIFIER_CODE_SET CodeSet; + STORAGE_IDENTIFIER_TYPE Type; + USHORT IdentifierSize; + USHORT NextOffset; + + // + // Add new fields here since existing code depends on + // the above layout not changing. + // + + STORAGE_ASSOCIATION_TYPE Association; + + // + // The identifier is a variable length array of bytes. + // + + UCHAR Identifier[1]; +} STORAGE_IDENTIFIER, *PSTORAGE_IDENTIFIER; + +typedef __struct_bcount(Size) struct _STORAGE_DEVICE_ID_DESCRIPTOR { + + ULONG Version; + + ULONG Size; + + // + // The number of identifiers reported by the device. + // + + ULONG NumberOfIdentifiers; + + // + // The following field is actually a variable length array of identification + // descriptors. Unfortunately there's no C notation for an array of + // variable length structures so we're forced to just pretend. + // + + UCHAR Identifiers[1]; +} STORAGE_DEVICE_ID_DESCRIPTOR, *PSTORAGE_DEVICE_ID_DESCRIPTOR; + +// output buffer for StorageDeviceSeekPenaltyProperty & PropertyStandardQuery +typedef struct _DEVICE_SEEK_PENALTY_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + BOOLEAN IncursSeekPenalty; +} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR; + +// output buffer for StorageDeviceWriteAggregationProperty & PropertyStandardQuery +typedef struct _DEVICE_WRITE_AGGREGATION_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + BOOLEAN BenefitsFromWriteAggregation; +} DEVICE_WRITE_AGGREGATION_DESCRIPTOR, *PDEVICE_WRITE_AGGREGATION_DESCRIPTOR; + +// output buffer for StorageDeviceTrimProperty & PropertyStandardQuery +typedef struct _DEVICE_TRIM_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + BOOLEAN TrimEnabled; +} DEVICE_TRIM_DESCRIPTOR, *PDEVICE_TRIM_DESCRIPTOR; + +// +// IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES +// +// Input Buffer: +// Structure of type DEVICE_MANAGE_DATA_SET_ATTRIBUTES +// +// Output Buffer: +// N/A +// +// Note: +// 1. Management of action Trim will be only allowed for kernel request. +// This request sent from user application will be rejected by kernel drivers. +// + +// +// This flag, when OR'd into an action indicates that the given action is +// non-destructive. If this flag is set then storage stack components which +// do not understand the action should forward the given request +// + +#define DeviceDsmActionFlag_NonDestructive 0x80000000 + +#define IsDsmActionNonDestructive(_Action) ((BOOLEAN)((_Action & DeviceDsmActionFlag_NonDestructive) != 0)) + +// +// Defines the various actions +// + +typedef ULONG DEVICE_DATA_MANAGEMENT_SET_ACTION; + #define DeviceDsmAction_None 0 + #define DeviceDsmAction_Trim 1 + #define DeviceDsmAction_Notification (2 | DeviceDsmActionFlag_NonDestructive) + +// +// Flags that are global across all actions +// + +#define DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE 0x00000001 // If set, the DataSetRanges fields should be 0 + + +typedef struct _DEVICE_DATA_SET_RANGE { + LONGLONG StartingOffset; //in bytes , must allign to sector + ULONGLONG LengthInBytes; // multiple of sector size. +} DEVICE_DATA_SET_RANGE, *PDEVICE_DATA_SET_RANGE; + +// +// input structure for IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES +// 1. Value ofParameterBlockOffset or ParameterBlockLength is 0 indicates that Parameter Block does not exist. +// 2. Value of DataSetRangesOffset or DataSetRangesLength is 0 indicates that DataSetRanges Block does not exist. +// If DataSetRanges Block exists, it contains contiguous DEVICE_DATA_SET_RANGE structures. +// 3. The total size of buffer should be at least: +// sizeof (DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + ParameterBlockLength + DataSetRangesLength +// +typedef struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES { + ULONG Size; // Size of structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES + DEVICE_DATA_MANAGEMENT_SET_ACTION Action; + + ULONG Flags; // Global flags across all actions + + ULONG ParameterBlockOffset; // must be alligned to corresponding structure allignment + ULONG ParameterBlockLength; // 0 means Parameter Block does not exist. + + ULONG DataSetRangesOffset; // must be alligned to DEVICE_DATA_SET_RANGE structure allignment. + ULONG DataSetRangesLength; // 0 means DataSetRanges Block does not exist. + +} DEVICE_MANAGE_DATA_SET_ATTRIBUTES, *PDEVICE_MANAGE_DATA_SET_ATTRIBUTES; + +// +// This defines the parameter block for the DeviceDsmAction_Notification +// action +// + +typedef struct _DEVICE_DSM_NOTIFICATION_PARAMETERS { + + ULONG Size; // Size of this structure + + ULONG Flags; // Flags specific to the notify operation + + ULONG NumFileTypeIDs; // Count of how many file type ID's are given + + GUID FileTypeID[1]; // Identifier for the type of file being notified + +} DEVICE_DSM_NOTIFICATION_PARAMETERS, *PDEVICE_DSM_NOTIFICATION_PARAMETERS; + +// +// DEVICE_DSM_NOTIFICATION_PARAMETERS flag definitions +// + +#define DEVICE_DSM_NOTIFY_FLAG_BEGIN 0x00000001 // The given LBA range is being used as defined by the FileID +#define DEVICE_DSM_NOTIFY_FLAG_END 0x00000002 // The given LBA range is no longer being used as defined by the FileID + +// +// There are some well known GUIDS for certail types of files. They are +// defined in NTIFS.H +// + + +// +// IOCTL_STORAGE_GET_BC_PROPERTIES +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type STORAGE_GET_BC_PROPERTIES_OUTPUT +// + +typedef struct _STORAGE_GET_BC_PROPERTIES_OUTPUT { + + // + // Specifies the maximum number of requests + // that can be scheduled per period of time + // + ULONG MaximumRequestsPerPeriod; + + // + // Specifies the minimum period that the + // device uses when scheduling requests + // + ULONG MinimumPeriod; + + // + // Specifies the maximum transfer size supported + // for bandwidth contracts on this device. To + // achieve the highest level of performance, all + // requests should be of this size + // + ULONGLONG MaximumRequestSize; + + // + // Specifies the estimated time taken to + // perform an Io operstion. This field + // is for informational purposes only + // + ULONG EstimatedTimePerRequest; + + // + // Specifies the number of requests that should be + // kept outstanding. This helps keep the device + // device busy and thus obtain maximum throughput. + // This will only be filled in if the target file + // has an outstanding contract. + // + ULONG NumOutStandingRequests; + + // + // Specifies the required size of requests in this + // stream. This will only be filled in if the + // target file has an outstanding contract. + // + ULONGLONG RequestSize; + +} STORAGE_GET_BC_PROPERTIES_OUTPUT, *PSTORAGE_GET_BC_PROPERTIES_OUTPUT; + + +// +// IOCTL_STORAGE_ALLOCATE_BC_STREAM +// +// Input Buffer: +// Structure of type STORAGE_ALLOCATE_BC_STREAM_INPUT +// +// Output Buffer: +// Structure of type STORAGE_ALLOCATE_BC_STREAM_OUTPUT +// + + +// +// Current version +// +#define IOCTL_STORAGE_BC_VERSION 1 + +typedef struct _STORAGE_ALLOCATE_BC_STREAM_INPUT { + + // + // Specifies the corresponding structure version + // + ULONG Version; + + // + // Specifies the number of requests that + // need to complete per period of time + // + ULONG RequestsPerPeriod; + + // + // Specifies the period of time wherein the + // above number of requests must complete + // + ULONG Period; + + // + // Indicates whether failures + // should be retried or not + // + BOOLEAN RetryFailures; + + // + // Indicates whether reqests that will miss + // their deadline should be discarded or not + // + BOOLEAN Discardable; + + // + // Helps align the following field + // + BOOLEAN Reserved1[2]; + + // + // Indicates whether the Io will be + // comprised of reads, writes or both + // + ULONG AccessType; + + // + // Indicates whether the Io to the + // file will be sequential or random + // + ULONG AccessMode; + +} STORAGE_ALLOCATE_BC_STREAM_INPUT, *PSTORAGE_ALLOCATE_BC_STREAM_INPUT; + +typedef struct _STORAGE_ALLOCATE_BC_STREAM_OUTPUT { + + // + // Specifies the required size + // of requests in this stream + // + ULONGLONG RequestSize; + + // + // Specifies the number of requests that should be + // kept outstanding. This helps keep the device + // device busy and thus obtain maximum throughput + // + ULONG NumOutStandingRequests; + +} STORAGE_ALLOCATE_BC_STREAM_OUTPUT, *PSTORAGE_ALLOCATE_BC_STREAM_OUTPUT; + + +// +// IOCTL_STORAGE_FREE_BC_STREAM +// +// Input Buffer: +// None +// +// Output Buffer: +// None +// + +// +// IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT +// +// Input Buffer : +// None +// Output Buffer : +// Structure of type STORAGE_PRIORITY_HINT_SUPPORT +// + +#define STORAGE_PRIORITY_HINT_SUPPORTED 0x0001 + +typedef struct _STORAGE_PRIORITY_HINT_SUPPORT { + ULONG SupportFlags; +} STORAGE_PRIORITY_HINT_SUPPORT, *PSTORAGE_PRIORITY_HINT_SUPPORT; + +#pragma warning(push) +#pragma warning(disable:4200) + +#if defined(_MSC_EXTENSIONS) + +typedef struct _STORAGE_MEDIA_SERIAL_NUMBER_DATA { + + USHORT Reserved; + + // + // the SerialNumberLength will be set to zero + // if the command is supported and the media + // does not have a valid serial number. + // + + USHORT SerialNumberLength; + + // + // the following data is binary, and is not guaranteed + // to be NULL terminated. this is an excercise for the + // caller. + // + +#if !defined(__midl) + UCHAR SerialNumber[0]; +#endif + +} STORAGE_MEDIA_SERIAL_NUMBER_DATA, *PSTORAGE_MEDIA_SERIAL_NUMBER_DATA; + +#endif /* _MSC_EXTENSIONS */ + +typedef __struct_bcount(Size) struct _STORAGE_READ_CAPACITY { + + // + // The version number, size of the STORAGE_READ_CAPACITY structure + // + ULONG Version; + + // + // The size of the date returned, size of the STORAGE_READ_CAPACITY structure + // + ULONG Size; + + // + // Number of bytes per block + // + + ULONG BlockLength; + + // + // Total number of blocks in the disk + // This will have the last LBA + 1 + // + + LARGE_INTEGER NumberOfBlocks; + + // + // Disk size in bytes + // + + LARGE_INTEGER DiskLength; + +} STORAGE_READ_CAPACITY, *PSTORAGE_READ_CAPACITY; + +#pragma warning(pop) + +// +// Device write cache property +// +// This property provides the write cache information +// about the target device. +// + +typedef enum _WRITE_CACHE_TYPE { + WriteCacheTypeUnknown, + WriteCacheTypeNone, + WriteCacheTypeWriteBack, + WriteCacheTypeWriteThrough +} WRITE_CACHE_TYPE; + +typedef enum _WRITE_CACHE_ENABLE { + WriteCacheEnableUnknown, + WriteCacheDisabled, + WriteCacheEnabled +} WRITE_CACHE_ENABLE; + +typedef enum _WRITE_CACHE_CHANGE { + WriteCacheChangeUnknown, + WriteCacheNotChangeable, + WriteCacheChangeable +} WRITE_CACHE_CHANGE; + +typedef enum _WRITE_THROUGH { + WriteThroughUnknown, + WriteThroughNotSupported, + WriteThroughSupported +} WRITE_THROUGH; + +typedef __struct_bcount(Size) struct _STORAGE_WRITE_CACHE_PROPERTY { + + // + // The version number + // Size of STORAGE_WRITE_CACHE_PROPERTY structure + // + ULONG Version; + + // + // The size of the date returned + // Size of STORAGE_WRITE_CACHE_PROPERTY structure + // + ULONG Size; + + // + // Current write cache type + // + WRITE_CACHE_TYPE WriteCacheType; + + // + // Current write cache value + // + WRITE_CACHE_ENABLE WriteCacheEnabled; + + // + // Device write cache change capability + // + WRITE_CACHE_CHANGE WriteCacheChangeable; + + // + // Device write through support capability + // + WRITE_THROUGH WriteThroughSupported; + + // + // Device flush cache capability + // + BOOLEAN FlushCacheSupported; + + // + // User selected power protection option through registry + // + BOOLEAN UserDefinedPowerProtection; + + // + // Device has battery backup for write cache + // + BOOLEAN NVCacheEnabled; + +} STORAGE_WRITE_CACHE_PROPERTY, *PSTORAGE_WRITE_CACHE_PROPERTY; + +#pragma warning(push) +#pragma warning(disable:4200) // array[0] +#pragma warning(disable:4201) // nameless struct/unions +#pragma warning(disable:4214) // bit fields other than int +#if defined(__INTEL_COMPILER) +#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero +#endif + + +#if defined(_MSC_EXTENSIONS) + +typedef struct _PERSISTENT_RESERVE_COMMAND { + + ULONG Version; + ULONG Size; + + union { + + struct { + + // + // Persistent Reserve service action. + // + + UCHAR ServiceAction : 5; + UCHAR Reserved1 : 3; + + // + // Number of bytes allocated for returned parameter list. + // + + USHORT AllocationLength; + + } PR_IN; + + struct { + + // + // Persistent Reserve service action. + // + + UCHAR ServiceAction : 5; + UCHAR Reserved1 : 3; + + // + // Persistent Reserve type and scope. + // + + UCHAR Type : 4; + UCHAR Scope : 4; + + // + // Space for additional PR Out parameters. + // + +#if !defined(__midl) + UCHAR ParameterList[0]; +#endif + + } PR_OUT; + }; + +} PERSISTENT_RESERVE_COMMAND, *PPERSISTENT_RESERVE_COMMAND; + +#endif /* _MSC_EXTENSIONS */ +#pragma warning(pop) + + +#ifdef __cplusplus +} +#endif + +#endif // _NTDDSTOR_H_ +// end_winioctl + diff --git a/src/CmdUI/CmdUI.cpp b/src/CmdUI/CmdUI.cpp index 13436d9db06..999cf4d52c1 100644 --- a/src/CmdUI/CmdUI.cpp +++ b/src/CmdUI/CmdUI.cpp @@ -1,196 +1,196 @@ -/* - * (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 . - * - */ - -// CmdUI.cpp : implementation file -// - -#include "stdafx.h" -#include -#include "CmdUI.h" - -// CCmdUIDialog dialog - -IMPLEMENT_DYNAMIC(CCmdUIDialog, CDialog) - -CCmdUIDialog::CCmdUIDialog() -{ -} - -CCmdUIDialog::CCmdUIDialog(UINT nIDTemplate, CWnd* pParent /*=nullptr*/) - : CDialog(nIDTemplate, pParent) -{ -} - -CCmdUIDialog::CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) - : CDialog(lpszTemplateName, pParentWnd) -{ -} - -CCmdUIDialog::~CCmdUIDialog() -{ -} - -LRESULT CCmdUIDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT ret = __super::DefWindowProc(message, wParam, lParam); - - if (message == WM_INITDIALOG) { - SendMessage(WM_KICKIDLE); - } - - return ret; -} - -BEGIN_MESSAGE_MAP(CCmdUIDialog, CDialog) - ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) - ON_WM_INITMENUPOPUP() -END_MESSAGE_MAP() - - -// CCmdUIDialog message handlers - -void CCmdUIDialog::OnKickIdle() -{ - UpdateDialogControls(this, false); - - // TODO: maybe we should send this call to modeless child cdialogs too -} - -// Q242577 - -void CCmdUIDialog::OnInitMenuPopup(CMenu* pPopupMenu, UINT /*nIndex*/, BOOL /*bSysMenu*/) -{ - ASSERT(pPopupMenu != nullptr); - // Check the enabled state of various menu items. - - CCmdUI state; - state.m_pMenu = pPopupMenu; - ASSERT(state.m_pOther == nullptr); - ASSERT(state.m_pParentMenu == nullptr); - - // Determine if menu is popup in top-level menu and set m_pOther to - // it if so (m_pParentMenu == nullptr) indicates that it is secondary popup. - if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu) { - state.m_pParentMenu = pPopupMenu; // Parent == child for tracking popup. - } else if (::GetMenu(m_hWnd) != nullptr) { - HMENU hParentMenu; - CWnd* pParent = this; - // Child windows don't have menus--need to go to the top! - if (pParent != nullptr && - (hParentMenu = ::GetMenu(pParent->m_hWnd)) != nullptr) { - int nIndexMax = ::GetMenuItemCount(hParentMenu); - for (int nIndex = 0; nIndex < nIndexMax; nIndex++) { - if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu) { - // When popup is found, m_pParentMenu is containing menu. - state.m_pParentMenu = CMenu::FromHandle(hParentMenu); - break; - } - } - } - } - - state.m_nIndexMax = pPopupMenu->GetMenuItemCount(); - for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; - state.m_nIndex++) { - state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex); - if (state.m_nID == 0) { - continue; // Menu separator or invalid cmd - ignore it. - } - - ASSERT(state.m_pOther == nullptr); - ASSERT(state.m_pMenu != nullptr); - if (state.m_nID == UINT(-1)) { - // Possibly a popup menu, route to first item of that popup. - state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex); - if (state.m_pSubMenu == nullptr || - (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || - state.m_nID == UINT(-1)) { - continue; // First item of popup can't be routed to. - } - state.DoUpdate(this, TRUE); // Popups are never auto disabled. - } else { - // Normal menu item. - // Auto enable/disable if frame window has m_bAutoMenuEnable - // set and command is _not_ a system command. - state.m_pSubMenu = nullptr; - state.DoUpdate(this, FALSE); - } - - // Adjust for menu deletions and additions. - UINT nCount = pPopupMenu->GetMenuItemCount(); - if (nCount < state.m_nIndexMax) { - state.m_nIndex -= (state.m_nIndexMax - nCount); - while (state.m_nIndex < nCount && - pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID) { - state.m_nIndex++; - } - } - state.m_nIndexMax = nCount; - } -} - -// CCmdUIPropertyPage - -IMPLEMENT_DYNAMIC(CCmdUIPropertyPage, CPropertyPage) -CCmdUIPropertyPage::CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption) - : CPropertyPage(nIDTemplate, nIDCaption) -{ -} - -CCmdUIPropertyPage::~CCmdUIPropertyPage() -{ -} - -LRESULT CCmdUIPropertyPage::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_COMMAND) { - switch (HIWORD(wParam)) { - case BN_CLICKED: - case CBN_SELCHANGE: - case EN_CHANGE: - SetModified(); - default: - ; - } - } - - LRESULT ret = __super::DefWindowProc(message, wParam, lParam); - - if (message == WM_INITDIALOG) { - SendMessage(WM_KICKIDLE); - } - - return ret; -} - -BEGIN_MESSAGE_MAP(CCmdUIPropertyPage, CPropertyPage) - ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) -END_MESSAGE_MAP() - - -// CCmdUIPropertyPage message handlers - -void CCmdUIPropertyPage::OnKickIdle() -{ - UpdateDialogControls(this, false); - - // TODO: maybe we should send this call to modeless child cPropertyPages too -} +/* + * (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 . + * + */ + +// CmdUI.cpp : implementation file +// + +#include "stdafx.h" +#include +#include "CmdUI.h" + +// CCmdUIDialog dialog + +IMPLEMENT_DYNAMIC(CCmdUIDialog, CDialog) + +CCmdUIDialog::CCmdUIDialog() +{ +} + +CCmdUIDialog::CCmdUIDialog(UINT nIDTemplate, CWnd* pParent /*=nullptr*/) + : CDialog(nIDTemplate, pParent) +{ +} + +CCmdUIDialog::CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) + : CDialog(lpszTemplateName, pParentWnd) +{ +} + +CCmdUIDialog::~CCmdUIDialog() +{ +} + +LRESULT CCmdUIDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret = __super::DefWindowProc(message, wParam, lParam); + + if (message == WM_INITDIALOG) { + SendMessage(WM_KICKIDLE); + } + + return ret; +} + +BEGIN_MESSAGE_MAP(CCmdUIDialog, CDialog) + ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) + ON_WM_INITMENUPOPUP() +END_MESSAGE_MAP() + + +// CCmdUIDialog message handlers + +void CCmdUIDialog::OnKickIdle() +{ + UpdateDialogControls(this, false); + + // TODO: maybe we should send this call to modeless child cdialogs too +} + +// Q242577 + +void CCmdUIDialog::OnInitMenuPopup(CMenu* pPopupMenu, UINT /*nIndex*/, BOOL /*bSysMenu*/) +{ + ASSERT(pPopupMenu != nullptr); + // Check the enabled state of various menu items. + + CCmdUI state; + state.m_pMenu = pPopupMenu; + ASSERT(state.m_pOther == nullptr); + ASSERT(state.m_pParentMenu == nullptr); + + // Determine if menu is popup in top-level menu and set m_pOther to + // it if so (m_pParentMenu == nullptr) indicates that it is secondary popup. + if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu) { + state.m_pParentMenu = pPopupMenu; // Parent == child for tracking popup. + } else if (::GetMenu(m_hWnd) != nullptr) { + HMENU hParentMenu; + CWnd* pParent = this; + // Child windows don't have menus--need to go to the top! + if (pParent != nullptr && + (hParentMenu = ::GetMenu(pParent->m_hWnd)) != nullptr) { + int nIndexMax = ::GetMenuItemCount(hParentMenu); + for (int nIndex = 0; nIndex < nIndexMax; nIndex++) { + if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu) { + // When popup is found, m_pParentMenu is containing menu. + state.m_pParentMenu = CMenu::FromHandle(hParentMenu); + break; + } + } + } + } + + state.m_nIndexMax = pPopupMenu->GetMenuItemCount(); + for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; + state.m_nIndex++) { + state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex); + if (state.m_nID == 0) { + continue; // Menu separator or invalid cmd - ignore it. + } + + ASSERT(state.m_pOther == nullptr); + ASSERT(state.m_pMenu != nullptr); + if (state.m_nID == UINT(-1)) { + // Possibly a popup menu, route to first item of that popup. + state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex); + if (state.m_pSubMenu == nullptr || + (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || + state.m_nID == UINT(-1)) { + continue; // First item of popup can't be routed to. + } + state.DoUpdate(this, TRUE); // Popups are never auto disabled. + } else { + // Normal menu item. + // Auto enable/disable if frame window has m_bAutoMenuEnable + // set and command is _not_ a system command. + state.m_pSubMenu = nullptr; + state.DoUpdate(this, FALSE); + } + + // Adjust for menu deletions and additions. + UINT nCount = pPopupMenu->GetMenuItemCount(); + if (nCount < state.m_nIndexMax) { + state.m_nIndex -= (state.m_nIndexMax - nCount); + while (state.m_nIndex < nCount && + pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID) { + state.m_nIndex++; + } + } + state.m_nIndexMax = nCount; + } +} + +// CCmdUIPropertyPage + +IMPLEMENT_DYNAMIC(CCmdUIPropertyPage, CPropertyPage) +CCmdUIPropertyPage::CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption) + : CPropertyPage(nIDTemplate, nIDCaption) +{ +} + +CCmdUIPropertyPage::~CCmdUIPropertyPage() +{ +} + +LRESULT CCmdUIPropertyPage::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_COMMAND) { + switch (HIWORD(wParam)) { + case BN_CLICKED: + case CBN_SELCHANGE: + case EN_CHANGE: + SetModified(); + default: + ; + } + } + + LRESULT ret = __super::DefWindowProc(message, wParam, lParam); + + if (message == WM_INITDIALOG) { + SendMessage(WM_KICKIDLE); + } + + return ret; +} + +BEGIN_MESSAGE_MAP(CCmdUIPropertyPage, CPropertyPage) + ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) +END_MESSAGE_MAP() + + +// CCmdUIPropertyPage message handlers + +void CCmdUIPropertyPage::OnKickIdle() +{ + UpdateDialogControls(this, false); + + // TODO: maybe we should send this call to modeless child cPropertyPages too +} diff --git a/src/CmdUI/CmdUI.h b/src/CmdUI/CmdUI.h index 2e22aa9248f..cf125cc673d 100644 --- a/src/CmdUI/CmdUI.h +++ b/src/CmdUI/CmdUI.h @@ -1,65 +1,65 @@ -/* - * (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 . - * - */ - -#pragma once - -// CCmdUI dialog - -#include - -class CCmdUIDialog : public CDialog -{ - DECLARE_DYNAMIC(CCmdUIDialog) - -public: - CCmdUIDialog(); - CCmdUIDialog(UINT nIDTemplate, CWnd* pParent = nullptr); - CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); - virtual ~CCmdUIDialog(); - -protected: - virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnKickIdle(); - afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); -}; - -// CCmdUIPropertyPage - -class CCmdUIPropertyPage : public CPropertyPage -{ - DECLARE_DYNAMIC(CCmdUIPropertyPage) - -public: - CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption = 0); // standard constructor - virtual ~CCmdUIPropertyPage(); - -protected: - virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnKickIdle(); -}; +/* + * (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 . + * + */ + +#pragma once + +// CCmdUI dialog + +#include + +class CCmdUIDialog : public CDialog +{ + DECLARE_DYNAMIC(CCmdUIDialog) + +public: + CCmdUIDialog(); + CCmdUIDialog(UINT nIDTemplate, CWnd* pParent = nullptr); + CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); + virtual ~CCmdUIDialog(); + +protected: + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnKickIdle(); + afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); +}; + +// CCmdUIPropertyPage + +class CCmdUIPropertyPage : public CPropertyPage +{ + DECLARE_DYNAMIC(CCmdUIPropertyPage) + +public: + CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption = 0); // standard constructor + virtual ~CCmdUIPropertyPage(); + +protected: + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnKickIdle(); +}; diff --git a/src/CmdUI/CmdUI.vcxproj b/src/CmdUI/CmdUI.vcxproj index 1f1e2449b10..bbaa7d42afd 100644 --- a/src/CmdUI/CmdUI.vcxproj +++ b/src/CmdUI/CmdUI.vcxproj @@ -1,60 +1,60 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {03208025-D5C2-426A-B0FA-251D4338F30C} - CmdUI - MFCProj - CmdUI - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - - - - - - Create - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {03208025-D5C2-426A-B0FA-251D4338F30C} + CmdUI + MFCProj + CmdUI + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + + + + + + Create + + + + + + + + + \ No newline at end of file diff --git a/src/CmdUI/CmdUI.vcxproj.filters b/src/CmdUI/CmdUI.vcxproj.filters index 7816ced3b54..84e7e50a074 100644 --- a/src/CmdUI/CmdUI.vcxproj.filters +++ b/src/CmdUI/CmdUI.vcxproj.filters @@ -1,29 +1,29 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + diff --git a/src/CmdUI/stdafx.cpp b/src/CmdUI/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/CmdUI/stdafx.cpp +++ b/src/CmdUI/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/CmdUI/stdafx.h b/src/CmdUI/stdafx.h index f7ebda4a143..323ba6af8aa 100644 --- a/src/CmdUI/stdafx.h +++ b/src/CmdUI/stdafx.h @@ -1,28 +1,28 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +/* + * (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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers diff --git a/src/DSUtil/DSMPropertyBag.cpp b/src/DSUtil/DSMPropertyBag.cpp index 2ef50216690..e4dfe40d1de 100644 --- a/src/DSUtil/DSMPropertyBag.cpp +++ b/src/DSUtil/DSMPropertyBag.cpp @@ -1,542 +1,542 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include "DSUtil.h" -#include "DSMPropertyBag.h" - -// -// IDSMPropertyBagImpl -// - -IDSMPropertyBagImpl::IDSMPropertyBagImpl() -{ -} - -IDSMPropertyBagImpl::~IDSMPropertyBagImpl() -{ -} - -// IPropertyBag - -STDMETHODIMP IDSMPropertyBagImpl::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) -{ - CheckPointer(pVar, E_POINTER); - if (pVar->vt != VT_EMPTY) { - return E_INVALIDARG; - } - CStringW value = Lookup(pszPropName); - if (value.IsEmpty()) { - return E_FAIL; - } - CComVariant(value).Detach(pVar); - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::Write(LPCOLESTR pszPropName, VARIANT* pVar) -{ - return SetProperty(pszPropName, pVar); -} - -// IPropertyBag2 - -STDMETHODIMP IDSMPropertyBagImpl::Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrLog, VARIANT* pvarValue, HRESULT* phrError) -{ - CheckPointer(pPropBag, E_POINTER); - CheckPointer(pvarValue, E_POINTER); - CheckPointer(phrError, E_POINTER); - for (ULONG i = 0; i < cProperties; phrError[i] = S_OK, i++) { - CComVariant(Lookup(pPropBag[i].pstrName)).Detach(pvarValue); - } - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::Write(ULONG cProperties, PROPBAG2* pPropBag, VARIANT* pvarValue) -{ - CheckPointer(pPropBag, E_POINTER); - CheckPointer(pvarValue, E_POINTER); - for (ULONG i = 0; i < cProperties; i++) { - SetProperty(pPropBag[i].pstrName, &pvarValue[i]); - } - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::CountProperties(ULONG* pcProperties) -{ - CheckPointer(pcProperties, E_POINTER); - *pcProperties = GetSize(); - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties) -{ - CheckPointer(pPropBag, E_POINTER); - CheckPointer(pcProperties, E_POINTER); - for (ULONG i = 0; i < cProperties; i++, iProperty++, (*pcProperties)++) { - CStringW key = GetKeyAt(iProperty); - pPropBag[i].pstrName = (BSTR)CoTaskMemAlloc((key.GetLength() + 1) * sizeof(WCHAR)); - if (!pPropBag[i].pstrName) { - return E_FAIL; - } - wcscpy_s(pPropBag[i].pstrName, key.GetLength() + 1, key); - } - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown* pUnkObject, IErrorLog* pErrLog) -{ - return E_NOTIMPL; -} - -// IDSMProperyBag - -HRESULT IDSMPropertyBagImpl::SetProperty(LPCWSTR key, LPCWSTR value) -{ - CheckPointer(key, E_POINTER); - CheckPointer(value, E_POINTER); - if (!Lookup(key).IsEmpty()) { - SetAt(key, value); - } else { - Add(key, value); - } - return S_OK; -} - -HRESULT IDSMPropertyBagImpl::SetProperty(LPCWSTR key, VARIANT* var) -{ - CheckPointer(key, E_POINTER); - CheckPointer(var, E_POINTER); - if ((var->vt & (VT_BSTR | VT_BYREF)) != VT_BSTR) { - return E_INVALIDARG; - } - return SetProperty(key, var->bstrVal); -} - -HRESULT IDSMPropertyBagImpl::GetProperty(LPCWSTR key, BSTR* value) -{ - CheckPointer(key, E_POINTER); - CheckPointer(value, E_POINTER); - int i = FindKey(key); - if (i < 0) { - return E_FAIL; - } - *value = GetValueAt(i).AllocSysString(); - return S_OK; -} - -HRESULT IDSMPropertyBagImpl::DelAllProperties() -{ - RemoveAll(); - return S_OK; -} - -HRESULT IDSMPropertyBagImpl::DelProperty(LPCWSTR key) -{ - return Remove(key) ? S_OK : S_FALSE; -} - -// -// CDSMResource -// - -CCritSec CDSMResource::m_csResources; -CAtlMap CDSMResource::m_resources; - -CDSMResource::CDSMResource() - : tag(0) - , mime(_T("application/octet-stream")) -{ - CAutoLock cAutoLock(&m_csResources); - m_resources.SetAt(reinterpret_cast(this), this); -} - -CDSMResource::CDSMResource(const CDSMResource& r) -{ - *this = r; - - CAutoLock cAutoLock(&m_csResources); - m_resources.SetAt(reinterpret_cast(this), this); -} - -CDSMResource::CDSMResource(LPCWSTR name, LPCWSTR desc, LPCWSTR mime, BYTE* pData, int len, DWORD_PTR tag) -{ - this->name = name; - this->desc = desc; - this->mime = mime; - data.SetCount(len); - memcpy(data.GetData(), pData, data.GetCount()); - this->tag = tag; - - CAutoLock cAutoLock(&m_csResources); - m_resources.SetAt(reinterpret_cast(this), this); -} - -CDSMResource::~CDSMResource() -{ - CAutoLock cAutoLock(&m_csResources); - m_resources.RemoveKey(reinterpret_cast(this)); -} - -CDSMResource& CDSMResource::operator = (const CDSMResource& r) -{ - if (this != &r) { - tag = r.tag; - name = r.name; - desc = r.desc; - mime = r.mime; - data.Copy(r.data); - } - return *this; -} - -// -// IDSMResourceBagImpl -// - -IDSMResourceBagImpl::IDSMResourceBagImpl() -{ -} - -// IDSMResourceBag - -STDMETHODIMP_(DWORD) IDSMResourceBagImpl::ResGetCount() -{ - return (DWORD)m_resources.GetCount(); -} - -STDMETHODIMP IDSMResourceBagImpl::ResGet(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag) -{ - if (ppData) { - CheckPointer(pDataLen, E_POINTER); - } - - if (iIndex >= m_resources.GetCount()) { - return E_INVALIDARG; - } - - CDSMResource& r = m_resources[iIndex]; - - if (ppName) { - *ppName = r.name.AllocSysString(); - } - if (ppDesc) { - *ppDesc = r.desc.AllocSysString(); - } - if (ppMime) { - *ppMime = r.mime.AllocSysString(); - } - if (ppData) { - *pDataLen = (DWORD)r.data.GetCount(); - memcpy(*ppData = (BYTE*)CoTaskMemAlloc(*pDataLen), r.data.GetData(), *pDataLen); - } - if (pTag) { - *pTag = r.tag; - } - - return S_OK; -} - -STDMETHODIMP IDSMResourceBagImpl::ResSet(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, const BYTE* pData, DWORD len, DWORD_PTR tag) -{ - if (iIndex >= m_resources.GetCount()) { - return E_INVALIDARG; - } - - CDSMResource& r = m_resources[iIndex]; - - if (pName) { - r.name = pName; - } - if (pDesc) { - r.desc = pDesc; - } - if (pMime) { - r.mime = pMime; - } - if (pData || len == 0) { - r.data.SetCount(len); - if (pData) { - memcpy(r.data.GetData(), pData, r.data.GetCount()); - } - } - r.tag = tag; - - return S_OK; -} - -STDMETHODIMP IDSMResourceBagImpl::ResAppend(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, BYTE* pData, DWORD len, DWORD_PTR tag) -{ - return ResSet((DWORD)m_resources.Add(CDSMResource()), pName, pDesc, pMime, pData, len, tag); -} - -STDMETHODIMP IDSMResourceBagImpl::ResRemoveAt(DWORD iIndex) -{ - if (iIndex >= m_resources.GetCount()) { - return E_INVALIDARG; - } - - m_resources.RemoveAt(iIndex); - - return S_OK; -} - -STDMETHODIMP IDSMResourceBagImpl::ResRemoveAll(DWORD_PTR tag) -{ - if (tag) { - for (ptrdiff_t i = m_resources.GetCount() - 1; i >= 0; i--) { - if (m_resources[i].tag == tag) { - m_resources.RemoveAt(i); - } - } - } else { - m_resources.RemoveAll(); - } - - return S_OK; -} - -// -// CDSMChapter -// - -CDSMChapter::CDSMChapter() -{ - order = counter++; - rt = 0; -} - -CDSMChapter::CDSMChapter(REFERENCE_TIME rt, LPCWSTR name) -{ - order = counter++; - this->rt = rt; - this->name = name; -} - -CDSMChapter& CDSMChapter::operator = (const CDSMChapter& c) -{ - if (this != &c) { - order = c.counter; - rt = c.rt; - name = c.name; - } - return *this; -} - -int CDSMChapter::counter = 0; - -// -// IDSMChapterBagImpl -// - -IDSMChapterBagImpl::IDSMChapterBagImpl() -{ - m_fSorted = false; -} - -// IDSMRChapterBag - -STDMETHODIMP_(DWORD) IDSMChapterBagImpl::ChapGetCount() -{ - return (DWORD)m_chapters.GetCount(); -} - -STDMETHODIMP IDSMChapterBagImpl::ChapGet(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName) -{ - if (iIndex >= m_chapters.GetCount()) { - return E_INVALIDARG; - } - - CDSMChapter& c = m_chapters[iIndex]; - - if (prt) { - *prt = c.rt; - } - if (ppName) { - *ppName = c.name.AllocSysString(); - } - - return S_OK; -} - -STDMETHODIMP IDSMChapterBagImpl::ChapSet(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName) -{ - if (iIndex >= m_chapters.GetCount()) { - return E_INVALIDARG; - } - - CDSMChapter& c = m_chapters[iIndex]; - - c.rt = rt; - if (pName) { - c.name = pName; - } - - m_fSorted = false; - - return S_OK; -} - -STDMETHODIMP IDSMChapterBagImpl::ChapAppend(REFERENCE_TIME rt, LPCWSTR pName) -{ - return ChapSet((DWORD)m_chapters.Add(CDSMChapter()), rt, pName); -} - -STDMETHODIMP IDSMChapterBagImpl::ChapRemoveAt(DWORD iIndex) -{ - if (iIndex >= m_chapters.GetCount()) { - return E_INVALIDARG; - } - - m_chapters.RemoveAt(iIndex); - - return S_OK; -} - -STDMETHODIMP IDSMChapterBagImpl::ChapRemoveAll() -{ - m_chapters.RemoveAll(); - - m_fSorted = false; - - return S_OK; -} - -STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookup(REFERENCE_TIME* prt, BSTR* ppName) -{ - CheckPointer(prt, -1); - if (m_chapters.IsEmpty()) { - return -1; - } - - size_t result = 0; - - if (m_fSorted) { - result = range_bsearch(m_chapters, *prt); - } - else { - // assume first entry is best, find better match - for (size_t i = 1; i < m_chapters.GetCount(); ++i) { - if (*prt >= m_chapters[i].rt && m_chapters[i].rt >= m_chapters[result].rt) { - result = i; - } - } - // validate first if it was best - if (result == 0 && *prt < m_chapters[result].rt) { - return -1; - } - } - - if (result != MAXSIZE_T) { - *prt = m_chapters[result].rt; - if (ppName) { - *ppName = m_chapters[result].name.AllocSysString(); - } - } - - return (long)result; -} - -STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookupPrevious(REFERENCE_TIME* prt, BSTR* ppName) -{ - CheckPointer(prt, -1); - - size_t chapcount = m_chapters.GetCount(); - if (chapcount < 1 || *prt < 0) { - return -1; - } - - size_t result = 0; - if (*prt < m_chapters[0].rt) { - return -1; - } else { - for (size_t i = 1; i < chapcount; ++i) { - if (*prt > m_chapters[i].rt) { - result = i; - } else { - break; - } - } - } - - *prt = m_chapters[result].rt; - if (ppName) { - *ppName = m_chapters[result].name.AllocSysString(); - } - - return (long)result; -} - -STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookupNext(REFERENCE_TIME* prt, BSTR* ppName) -{ - CheckPointer(prt, -1); - - size_t chapcount = m_chapters.GetCount(); - if (chapcount < 1) { - return -1; - } - - size_t result = 0; - if (*prt >= m_chapters[chapcount-1].rt) { - return -1; - } else { - for (size_t i = 0; i < chapcount; ++i) { - if (*prt < m_chapters[i].rt) { - result = i; - break; - } - } - } - - *prt = m_chapters[result].rt; - if (ppName) { - *ppName = m_chapters[result].name.AllocSysString(); - } - - return (long)result; -} - -STDMETHODIMP IDSMChapterBagImpl::ChapSort() -{ - if (m_fSorted) { - return S_FALSE; - } - std::sort(m_chapters.GetData(), m_chapters.GetData() + m_chapters.GetCount()); - m_fSorted = true; - return S_OK; -} - -// -// CDSMChapterBag -// - -CDSMChapterBag::CDSMChapterBag(LPUNKNOWN pUnk, HRESULT* phr) - : CUnknown(_T("CDSMChapterBag"), nullptr) -{ -} - -STDMETHODIMP CDSMChapterBag::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IDSMChapterBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include "DSUtil.h" +#include "DSMPropertyBag.h" + +// +// IDSMPropertyBagImpl +// + +IDSMPropertyBagImpl::IDSMPropertyBagImpl() +{ +} + +IDSMPropertyBagImpl::~IDSMPropertyBagImpl() +{ +} + +// IPropertyBag + +STDMETHODIMP IDSMPropertyBagImpl::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) +{ + CheckPointer(pVar, E_POINTER); + if (pVar->vt != VT_EMPTY) { + return E_INVALIDARG; + } + CStringW value = Lookup(pszPropName); + if (value.IsEmpty()) { + return E_FAIL; + } + CComVariant(value).Detach(pVar); + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::Write(LPCOLESTR pszPropName, VARIANT* pVar) +{ + return SetProperty(pszPropName, pVar); +} + +// IPropertyBag2 + +STDMETHODIMP IDSMPropertyBagImpl::Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrLog, VARIANT* pvarValue, HRESULT* phrError) +{ + CheckPointer(pPropBag, E_POINTER); + CheckPointer(pvarValue, E_POINTER); + CheckPointer(phrError, E_POINTER); + for (ULONG i = 0; i < cProperties; phrError[i] = S_OK, i++) { + CComVariant(Lookup(pPropBag[i].pstrName)).Detach(pvarValue); + } + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::Write(ULONG cProperties, PROPBAG2* pPropBag, VARIANT* pvarValue) +{ + CheckPointer(pPropBag, E_POINTER); + CheckPointer(pvarValue, E_POINTER); + for (ULONG i = 0; i < cProperties; i++) { + SetProperty(pPropBag[i].pstrName, &pvarValue[i]); + } + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::CountProperties(ULONG* pcProperties) +{ + CheckPointer(pcProperties, E_POINTER); + *pcProperties = GetSize(); + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties) +{ + CheckPointer(pPropBag, E_POINTER); + CheckPointer(pcProperties, E_POINTER); + for (ULONG i = 0; i < cProperties; i++, iProperty++, (*pcProperties)++) { + CStringW key = GetKeyAt(iProperty); + pPropBag[i].pstrName = (BSTR)CoTaskMemAlloc((key.GetLength() + 1) * sizeof(WCHAR)); + if (!pPropBag[i].pstrName) { + return E_FAIL; + } + wcscpy_s(pPropBag[i].pstrName, key.GetLength() + 1, key); + } + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown* pUnkObject, IErrorLog* pErrLog) +{ + return E_NOTIMPL; +} + +// IDSMProperyBag + +HRESULT IDSMPropertyBagImpl::SetProperty(LPCWSTR key, LPCWSTR value) +{ + CheckPointer(key, E_POINTER); + CheckPointer(value, E_POINTER); + if (!Lookup(key).IsEmpty()) { + SetAt(key, value); + } else { + Add(key, value); + } + return S_OK; +} + +HRESULT IDSMPropertyBagImpl::SetProperty(LPCWSTR key, VARIANT* var) +{ + CheckPointer(key, E_POINTER); + CheckPointer(var, E_POINTER); + if ((var->vt & (VT_BSTR | VT_BYREF)) != VT_BSTR) { + return E_INVALIDARG; + } + return SetProperty(key, var->bstrVal); +} + +HRESULT IDSMPropertyBagImpl::GetProperty(LPCWSTR key, BSTR* value) +{ + CheckPointer(key, E_POINTER); + CheckPointer(value, E_POINTER); + int i = FindKey(key); + if (i < 0) { + return E_FAIL; + } + *value = GetValueAt(i).AllocSysString(); + return S_OK; +} + +HRESULT IDSMPropertyBagImpl::DelAllProperties() +{ + RemoveAll(); + return S_OK; +} + +HRESULT IDSMPropertyBagImpl::DelProperty(LPCWSTR key) +{ + return Remove(key) ? S_OK : S_FALSE; +} + +// +// CDSMResource +// + +CCritSec CDSMResource::m_csResources; +CAtlMap CDSMResource::m_resources; + +CDSMResource::CDSMResource() + : tag(0) + , mime(_T("application/octet-stream")) +{ + CAutoLock cAutoLock(&m_csResources); + m_resources.SetAt(reinterpret_cast(this), this); +} + +CDSMResource::CDSMResource(const CDSMResource& r) +{ + *this = r; + + CAutoLock cAutoLock(&m_csResources); + m_resources.SetAt(reinterpret_cast(this), this); +} + +CDSMResource::CDSMResource(LPCWSTR name, LPCWSTR desc, LPCWSTR mime, BYTE* pData, int len, DWORD_PTR tag) +{ + this->name = name; + this->desc = desc; + this->mime = mime; + data.SetCount(len); + memcpy(data.GetData(), pData, data.GetCount()); + this->tag = tag; + + CAutoLock cAutoLock(&m_csResources); + m_resources.SetAt(reinterpret_cast(this), this); +} + +CDSMResource::~CDSMResource() +{ + CAutoLock cAutoLock(&m_csResources); + m_resources.RemoveKey(reinterpret_cast(this)); +} + +CDSMResource& CDSMResource::operator = (const CDSMResource& r) +{ + if (this != &r) { + tag = r.tag; + name = r.name; + desc = r.desc; + mime = r.mime; + data.Copy(r.data); + } + return *this; +} + +// +// IDSMResourceBagImpl +// + +IDSMResourceBagImpl::IDSMResourceBagImpl() +{ +} + +// IDSMResourceBag + +STDMETHODIMP_(DWORD) IDSMResourceBagImpl::ResGetCount() +{ + return (DWORD)m_resources.GetCount(); +} + +STDMETHODIMP IDSMResourceBagImpl::ResGet(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag) +{ + if (ppData) { + CheckPointer(pDataLen, E_POINTER); + } + + if (iIndex >= m_resources.GetCount()) { + return E_INVALIDARG; + } + + CDSMResource& r = m_resources[iIndex]; + + if (ppName) { + *ppName = r.name.AllocSysString(); + } + if (ppDesc) { + *ppDesc = r.desc.AllocSysString(); + } + if (ppMime) { + *ppMime = r.mime.AllocSysString(); + } + if (ppData) { + *pDataLen = (DWORD)r.data.GetCount(); + memcpy(*ppData = (BYTE*)CoTaskMemAlloc(*pDataLen), r.data.GetData(), *pDataLen); + } + if (pTag) { + *pTag = r.tag; + } + + return S_OK; +} + +STDMETHODIMP IDSMResourceBagImpl::ResSet(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, const BYTE* pData, DWORD len, DWORD_PTR tag) +{ + if (iIndex >= m_resources.GetCount()) { + return E_INVALIDARG; + } + + CDSMResource& r = m_resources[iIndex]; + + if (pName) { + r.name = pName; + } + if (pDesc) { + r.desc = pDesc; + } + if (pMime) { + r.mime = pMime; + } + if (pData || len == 0) { + r.data.SetCount(len); + if (pData) { + memcpy(r.data.GetData(), pData, r.data.GetCount()); + } + } + r.tag = tag; + + return S_OK; +} + +STDMETHODIMP IDSMResourceBagImpl::ResAppend(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, BYTE* pData, DWORD len, DWORD_PTR tag) +{ + return ResSet((DWORD)m_resources.Add(CDSMResource()), pName, pDesc, pMime, pData, len, tag); +} + +STDMETHODIMP IDSMResourceBagImpl::ResRemoveAt(DWORD iIndex) +{ + if (iIndex >= m_resources.GetCount()) { + return E_INVALIDARG; + } + + m_resources.RemoveAt(iIndex); + + return S_OK; +} + +STDMETHODIMP IDSMResourceBagImpl::ResRemoveAll(DWORD_PTR tag) +{ + if (tag) { + for (ptrdiff_t i = m_resources.GetCount() - 1; i >= 0; i--) { + if (m_resources[i].tag == tag) { + m_resources.RemoveAt(i); + } + } + } else { + m_resources.RemoveAll(); + } + + return S_OK; +} + +// +// CDSMChapter +// + +CDSMChapter::CDSMChapter() +{ + order = counter++; + rt = 0; +} + +CDSMChapter::CDSMChapter(REFERENCE_TIME rt, LPCWSTR name) +{ + order = counter++; + this->rt = rt; + this->name = name; +} + +CDSMChapter& CDSMChapter::operator = (const CDSMChapter& c) +{ + if (this != &c) { + order = c.counter; + rt = c.rt; + name = c.name; + } + return *this; +} + +int CDSMChapter::counter = 0; + +// +// IDSMChapterBagImpl +// + +IDSMChapterBagImpl::IDSMChapterBagImpl() +{ + m_fSorted = false; +} + +// IDSMRChapterBag + +STDMETHODIMP_(DWORD) IDSMChapterBagImpl::ChapGetCount() +{ + return (DWORD)m_chapters.GetCount(); +} + +STDMETHODIMP IDSMChapterBagImpl::ChapGet(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName) +{ + if (iIndex >= m_chapters.GetCount()) { + return E_INVALIDARG; + } + + CDSMChapter& c = m_chapters[iIndex]; + + if (prt) { + *prt = c.rt; + } + if (ppName) { + *ppName = c.name.AllocSysString(); + } + + return S_OK; +} + +STDMETHODIMP IDSMChapterBagImpl::ChapSet(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName) +{ + if (iIndex >= m_chapters.GetCount()) { + return E_INVALIDARG; + } + + CDSMChapter& c = m_chapters[iIndex]; + + c.rt = rt; + if (pName) { + c.name = pName; + } + + m_fSorted = false; + + return S_OK; +} + +STDMETHODIMP IDSMChapterBagImpl::ChapAppend(REFERENCE_TIME rt, LPCWSTR pName) +{ + return ChapSet((DWORD)m_chapters.Add(CDSMChapter()), rt, pName); +} + +STDMETHODIMP IDSMChapterBagImpl::ChapRemoveAt(DWORD iIndex) +{ + if (iIndex >= m_chapters.GetCount()) { + return E_INVALIDARG; + } + + m_chapters.RemoveAt(iIndex); + + return S_OK; +} + +STDMETHODIMP IDSMChapterBagImpl::ChapRemoveAll() +{ + m_chapters.RemoveAll(); + + m_fSorted = false; + + return S_OK; +} + +STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookup(REFERENCE_TIME* prt, BSTR* ppName) +{ + CheckPointer(prt, -1); + if (m_chapters.IsEmpty()) { + return -1; + } + + size_t result = 0; + + if (m_fSorted) { + result = range_bsearch(m_chapters, *prt); + } + else { + // assume first entry is best, find better match + for (size_t i = 1; i < m_chapters.GetCount(); ++i) { + if (*prt >= m_chapters[i].rt && m_chapters[i].rt >= m_chapters[result].rt) { + result = i; + } + } + // validate first if it was best + if (result == 0 && *prt < m_chapters[result].rt) { + return -1; + } + } + + if (result != MAXSIZE_T) { + *prt = m_chapters[result].rt; + if (ppName) { + *ppName = m_chapters[result].name.AllocSysString(); + } + } + + return (long)result; +} + +STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookupPrevious(REFERENCE_TIME* prt, BSTR* ppName) +{ + CheckPointer(prt, -1); + + size_t chapcount = m_chapters.GetCount(); + if (chapcount < 1 || *prt < 0) { + return -1; + } + + size_t result = 0; + if (*prt < m_chapters[0].rt) { + return -1; + } else { + for (size_t i = 1; i < chapcount; ++i) { + if (*prt > m_chapters[i].rt) { + result = i; + } else { + break; + } + } + } + + *prt = m_chapters[result].rt; + if (ppName) { + *ppName = m_chapters[result].name.AllocSysString(); + } + + return (long)result; +} + +STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookupNext(REFERENCE_TIME* prt, BSTR* ppName) +{ + CheckPointer(prt, -1); + + size_t chapcount = m_chapters.GetCount(); + if (chapcount < 1) { + return -1; + } + + size_t result = 0; + if (*prt >= m_chapters[chapcount-1].rt) { + return -1; + } else { + for (size_t i = 0; i < chapcount; ++i) { + if (*prt < m_chapters[i].rt) { + result = i; + break; + } + } + } + + *prt = m_chapters[result].rt; + if (ppName) { + *ppName = m_chapters[result].name.AllocSysString(); + } + + return (long)result; +} + +STDMETHODIMP IDSMChapterBagImpl::ChapSort() +{ + if (m_fSorted) { + return S_FALSE; + } + std::sort(m_chapters.GetData(), m_chapters.GetData() + m_chapters.GetCount()); + m_fSorted = true; + return S_OK; +} + +// +// CDSMChapterBag +// + +CDSMChapterBag::CDSMChapterBag(LPUNKNOWN pUnk, HRESULT* phr) + : CUnknown(_T("CDSMChapterBag"), nullptr) +{ +} + +STDMETHODIMP CDSMChapterBag::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IDSMChapterBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} diff --git a/src/DSUtil/DSMPropertyBag.h b/src/DSUtil/DSMPropertyBag.h index 9fbe466031a..662e8d4d9ba 100644 --- a/src/DSUtil/DSMPropertyBag.h +++ b/src/DSUtil/DSMPropertyBag.h @@ -1,234 +1,234 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include - -// IDSMPropertyBag - -interface __declspec(uuid("232FD5D2-4954-41E7-BF9B-09E1257B1A95")) - IDSMPropertyBag : - public IPropertyBag2 -{ - STDMETHOD(SetProperty)(LPCWSTR key, LPCWSTR value) PURE; - STDMETHOD(SetProperty)(LPCWSTR key, VARIANT* var) PURE; - STDMETHOD(GetProperty)(LPCWSTR key, BSTR* value) PURE; - STDMETHOD(DelAllProperties)() PURE; - STDMETHOD(DelProperty)(LPCWSTR key) PURE; -}; - -class IDSMPropertyBagImpl : public ATL::CSimpleMap, public IDSMPropertyBag, public IPropertyBag -{ - BOOL Add(const CStringW& key, const CStringW& val) { - return __super::Add(key, val); - } - BOOL SetAt(const CStringW& key, const CStringW& val) { - return __super::SetAt(key, val); - } - -public: - IDSMPropertyBagImpl(); - virtual ~IDSMPropertyBagImpl(); - - // IPropertyBag - - STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog); - STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT* pVar); - - // IPropertyBag2 - - STDMETHODIMP Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrLog, VARIANT* pvarValue, HRESULT* phrError); - STDMETHODIMP Write(ULONG cProperties, PROPBAG2* pPropBag, VARIANT* pvarValue); - STDMETHODIMP CountProperties(ULONG* pcProperties); - STDMETHODIMP GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties); - STDMETHODIMP LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown* pUnkObject, IErrorLog* pErrLog); - - // IDSMPropertyBag - - STDMETHODIMP SetProperty(LPCWSTR key, LPCWSTR value); - STDMETHODIMP SetProperty(LPCWSTR key, VARIANT* var); - STDMETHODIMP GetProperty(LPCWSTR key, BSTR* value); - STDMETHODIMP DelAllProperties(); - STDMETHODIMP DelProperty(LPCWSTR key); -}; - -// IDSMResourceBag - -interface __declspec(uuid("EBAFBCBE-BDE0-489A-9789-05D5692E3A93")) - IDSMResourceBag : - public IUnknown -{ - STDMETHOD_(DWORD, ResGetCount)() PURE; - STDMETHOD(ResGet)(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag) PURE; - STDMETHOD(ResSet)(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, const BYTE* pData, DWORD len, DWORD_PTR tag) PURE; - STDMETHOD(ResAppend)(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, BYTE* pData, DWORD len, DWORD_PTR tag) PURE; - STDMETHOD(ResRemoveAt)(DWORD iIndex) PURE; - STDMETHOD(ResRemoveAll)(DWORD_PTR tag) PURE; -}; - -class CDSMResource -{ -public: - DWORD_PTR tag; - CStringW name, desc, mime; - CAtlArray data; - CDSMResource(); - CDSMResource(const CDSMResource& r); - CDSMResource(LPCWSTR name, LPCWSTR desc, LPCWSTR mime, BYTE* pData, int len, DWORD_PTR tag = 0); - virtual ~CDSMResource(); - CDSMResource& operator = (const CDSMResource& r); - - // global access to all resources - static CCritSec m_csResources; - static CAtlMap m_resources; -}; - -class IDSMResourceBagImpl : public IDSMResourceBag -{ -protected: - CAtlArray m_resources; - -public: - IDSMResourceBagImpl(); - - void operator += (const CDSMResource& r) { m_resources.Add(r); } - - // IDSMResourceBag - - STDMETHODIMP_(DWORD) ResGetCount(); - STDMETHODIMP ResGet(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, - BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag = nullptr); - STDMETHODIMP ResSet(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, - const BYTE* pData, DWORD len, DWORD_PTR tag = 0); - STDMETHODIMP ResAppend(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, - BYTE* pData, DWORD len, DWORD_PTR tag = 0); - STDMETHODIMP ResRemoveAt(DWORD iIndex); - STDMETHODIMP ResRemoveAll(DWORD_PTR tag = 0); -}; - -// IDSMChapterBag - -interface __declspec(uuid("926df57d-47c3-4e32-a911-5c66b3314d05")) - IDSMChapterBag : - public IUnknown -{ - STDMETHOD_(DWORD, ChapGetCount)() PURE; - STDMETHOD(ChapGet)(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName) PURE; - STDMETHOD(ChapSet)(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName) PURE; - STDMETHOD(ChapAppend)(REFERENCE_TIME rt, LPCWSTR pName) PURE; - STDMETHOD(ChapRemoveAt)(DWORD iIndex) PURE; - STDMETHOD(ChapRemoveAll)() PURE; - STDMETHOD_(long, ChapLookup)(REFERENCE_TIME* prt, BSTR* ppName) PURE; - STDMETHOD_(long, ChapLookupPrevious)(REFERENCE_TIME* prt, BSTR* ppName) PURE; - STDMETHOD_(long, ChapLookupNext)(REFERENCE_TIME* prt, BSTR* ppName) PURE; - STDMETHOD(ChapSort)() PURE; -}; - -class CDSMChapter -{ - static int counter; - int order; - -public: - REFERENCE_TIME rt; - CStringW name; - CDSMChapter(); - CDSMChapter(REFERENCE_TIME rt, LPCWSTR name); - CDSMChapter& operator = (const CDSMChapter& c); - - bool operator <(const CDSMChapter& rhs) const { - return (rt != rhs.rt) ? rt < rhs.rt : order < rhs.order; - } -}; - -class IDSMChapterBagImpl : public IDSMChapterBag -{ -protected: - CAtlArray m_chapters; - bool m_fSorted; - -public: - IDSMChapterBagImpl(); - - void operator += (const CDSMChapter& c) { m_chapters.Add(c); m_fSorted = false; } - - // IDSMChapterBag - - STDMETHODIMP_(DWORD) ChapGetCount(); - STDMETHODIMP ChapGet(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName = nullptr); - STDMETHODIMP ChapSet(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName); - STDMETHODIMP ChapAppend(REFERENCE_TIME rt, LPCWSTR pName); - STDMETHODIMP ChapRemoveAt(DWORD iIndex); - STDMETHODIMP ChapRemoveAll(); - STDMETHODIMP_(long) ChapLookup(REFERENCE_TIME* prt, BSTR* ppName = nullptr); - STDMETHODIMP ChapSort(); - - STDMETHODIMP_(long) ChapLookupPrevious(REFERENCE_TIME* prt, BSTR* ppName = nullptr); - STDMETHODIMP_(long) ChapLookupNext(REFERENCE_TIME* prt, BSTR* ppName = nullptr); -}; - -class CDSMChapterBag : public CUnknown, public IDSMChapterBagImpl -{ -public: - CDSMChapterBag(LPUNKNOWN pUnk, HRESULT* phr); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); -}; - -template -__declspec(nothrow noalias) __forceinline size_t range_bsearch(CAtlArray const& tArray, REFERENCE_TIME rt) -{ - // MAXSIZE_T is returned by this function for status invalid - ptrdiff_t k = tArray.GetCount() - 1; - if ((k < 0) || (rt >= tArray[k].rt)) { - return k; - } - size_t ret = MAXSIZE_T; - if (!k) { - return ret; - } - - size_t i = 0, j = k; - do { - size_t mid = (i + j) >> 1; - REFERENCE_TIME midrt = tArray[mid].rt; - if (rt == midrt) { - ret = mid; - break; - } else if (rt < midrt) { - ret = MAXSIZE_T; - if (j == mid) { - --mid; - } - j = mid; - } else if (rt > midrt) { - ret = mid; - if (i == mid) { - ++mid; - } - i = mid; - } - } while (i < j); - return ret; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include + +// IDSMPropertyBag + +interface __declspec(uuid("232FD5D2-4954-41E7-BF9B-09E1257B1A95")) + IDSMPropertyBag : + public IPropertyBag2 +{ + STDMETHOD(SetProperty)(LPCWSTR key, LPCWSTR value) PURE; + STDMETHOD(SetProperty)(LPCWSTR key, VARIANT* var) PURE; + STDMETHOD(GetProperty)(LPCWSTR key, BSTR* value) PURE; + STDMETHOD(DelAllProperties)() PURE; + STDMETHOD(DelProperty)(LPCWSTR key) PURE; +}; + +class IDSMPropertyBagImpl : public ATL::CSimpleMap, public IDSMPropertyBag, public IPropertyBag +{ + BOOL Add(const CStringW& key, const CStringW& val) { + return __super::Add(key, val); + } + BOOL SetAt(const CStringW& key, const CStringW& val) { + return __super::SetAt(key, val); + } + +public: + IDSMPropertyBagImpl(); + virtual ~IDSMPropertyBagImpl(); + + // IPropertyBag + + STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog); + STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT* pVar); + + // IPropertyBag2 + + STDMETHODIMP Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrLog, VARIANT* pvarValue, HRESULT* phrError); + STDMETHODIMP Write(ULONG cProperties, PROPBAG2* pPropBag, VARIANT* pvarValue); + STDMETHODIMP CountProperties(ULONG* pcProperties); + STDMETHODIMP GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties); + STDMETHODIMP LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown* pUnkObject, IErrorLog* pErrLog); + + // IDSMPropertyBag + + STDMETHODIMP SetProperty(LPCWSTR key, LPCWSTR value); + STDMETHODIMP SetProperty(LPCWSTR key, VARIANT* var); + STDMETHODIMP GetProperty(LPCWSTR key, BSTR* value); + STDMETHODIMP DelAllProperties(); + STDMETHODIMP DelProperty(LPCWSTR key); +}; + +// IDSMResourceBag + +interface __declspec(uuid("EBAFBCBE-BDE0-489A-9789-05D5692E3A93")) + IDSMResourceBag : + public IUnknown +{ + STDMETHOD_(DWORD, ResGetCount)() PURE; + STDMETHOD(ResGet)(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag) PURE; + STDMETHOD(ResSet)(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, const BYTE* pData, DWORD len, DWORD_PTR tag) PURE; + STDMETHOD(ResAppend)(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, BYTE* pData, DWORD len, DWORD_PTR tag) PURE; + STDMETHOD(ResRemoveAt)(DWORD iIndex) PURE; + STDMETHOD(ResRemoveAll)(DWORD_PTR tag) PURE; +}; + +class CDSMResource +{ +public: + DWORD_PTR tag; + CStringW name, desc, mime; + CAtlArray data; + CDSMResource(); + CDSMResource(const CDSMResource& r); + CDSMResource(LPCWSTR name, LPCWSTR desc, LPCWSTR mime, BYTE* pData, int len, DWORD_PTR tag = 0); + virtual ~CDSMResource(); + CDSMResource& operator = (const CDSMResource& r); + + // global access to all resources + static CCritSec m_csResources; + static CAtlMap m_resources; +}; + +class IDSMResourceBagImpl : public IDSMResourceBag +{ +protected: + CAtlArray m_resources; + +public: + IDSMResourceBagImpl(); + + void operator += (const CDSMResource& r) { m_resources.Add(r); } + + // IDSMResourceBag + + STDMETHODIMP_(DWORD) ResGetCount(); + STDMETHODIMP ResGet(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, + BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag = nullptr); + STDMETHODIMP ResSet(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, + const BYTE* pData, DWORD len, DWORD_PTR tag = 0); + STDMETHODIMP ResAppend(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, + BYTE* pData, DWORD len, DWORD_PTR tag = 0); + STDMETHODIMP ResRemoveAt(DWORD iIndex); + STDMETHODIMP ResRemoveAll(DWORD_PTR tag = 0); +}; + +// IDSMChapterBag + +interface __declspec(uuid("926df57d-47c3-4e32-a911-5c66b3314d05")) + IDSMChapterBag : + public IUnknown +{ + STDMETHOD_(DWORD, ChapGetCount)() PURE; + STDMETHOD(ChapGet)(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName) PURE; + STDMETHOD(ChapSet)(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName) PURE; + STDMETHOD(ChapAppend)(REFERENCE_TIME rt, LPCWSTR pName) PURE; + STDMETHOD(ChapRemoveAt)(DWORD iIndex) PURE; + STDMETHOD(ChapRemoveAll)() PURE; + STDMETHOD_(long, ChapLookup)(REFERENCE_TIME* prt, BSTR* ppName) PURE; + STDMETHOD_(long, ChapLookupPrevious)(REFERENCE_TIME* prt, BSTR* ppName) PURE; + STDMETHOD_(long, ChapLookupNext)(REFERENCE_TIME* prt, BSTR* ppName) PURE; + STDMETHOD(ChapSort)() PURE; +}; + +class CDSMChapter +{ + static int counter; + int order; + +public: + REFERENCE_TIME rt; + CStringW name; + CDSMChapter(); + CDSMChapter(REFERENCE_TIME rt, LPCWSTR name); + CDSMChapter& operator = (const CDSMChapter& c); + + bool operator <(const CDSMChapter& rhs) const { + return (rt != rhs.rt) ? rt < rhs.rt : order < rhs.order; + } +}; + +class IDSMChapterBagImpl : public IDSMChapterBag +{ +protected: + CAtlArray m_chapters; + bool m_fSorted; + +public: + IDSMChapterBagImpl(); + + void operator += (const CDSMChapter& c) { m_chapters.Add(c); m_fSorted = false; } + + // IDSMChapterBag + + STDMETHODIMP_(DWORD) ChapGetCount(); + STDMETHODIMP ChapGet(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName = nullptr); + STDMETHODIMP ChapSet(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName); + STDMETHODIMP ChapAppend(REFERENCE_TIME rt, LPCWSTR pName); + STDMETHODIMP ChapRemoveAt(DWORD iIndex); + STDMETHODIMP ChapRemoveAll(); + STDMETHODIMP_(long) ChapLookup(REFERENCE_TIME* prt, BSTR* ppName = nullptr); + STDMETHODIMP ChapSort(); + + STDMETHODIMP_(long) ChapLookupPrevious(REFERENCE_TIME* prt, BSTR* ppName = nullptr); + STDMETHODIMP_(long) ChapLookupNext(REFERENCE_TIME* prt, BSTR* ppName = nullptr); +}; + +class CDSMChapterBag : public CUnknown, public IDSMChapterBagImpl +{ +public: + CDSMChapterBag(LPUNKNOWN pUnk, HRESULT* phr); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); +}; + +template +__declspec(nothrow noalias) __forceinline size_t range_bsearch(CAtlArray const& tArray, REFERENCE_TIME rt) +{ + // MAXSIZE_T is returned by this function for status invalid + ptrdiff_t k = tArray.GetCount() - 1; + if ((k < 0) || (rt >= tArray[k].rt)) { + return k; + } + size_t ret = MAXSIZE_T; + if (!k) { + return ret; + } + + size_t i = 0, j = k; + do { + size_t mid = (i + j) >> 1; + REFERENCE_TIME midrt = tArray[mid].rt; + if (rt == midrt) { + ret = mid; + break; + } else if (rt < midrt) { + ret = MAXSIZE_T; + if (j == mid) { + --mid; + } + j = mid; + } else if (rt > midrt) { + ret = mid; + if (i == mid) { + ++mid; + } + i = mid; + } + } while (i < j); + return ret; +} diff --git a/src/DSUtil/DSUtil.cpp b/src/DSUtil/DSUtil.cpp index f4b75e8a4a1..949661a6934 100644 --- a/src/DSUtil/DSUtil.cpp +++ b/src/DSUtil/DSUtil.cpp @@ -1,2248 +1,2248 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "winddk/devioctl.h" -#include "winddk/ntddcdrm.h" -#include "DSUtil.h" -#include "Mpeg2Def.h" -#include -#include -#include "NullRenderers.h" -#include "mvrInterfaces.h" - -#include "moreuuids.h" -#include -#include -#include - -int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC) -{ - nIn = nOut = 0; - nInC = nOutC = 0; - - BeginEnumPins(pBF, pEP, pPin) { - PIN_DIRECTION dir; - if (SUCCEEDED(pPin->QueryDirection(&dir))) { - CComPtr pPinConnectedTo; - pPin->ConnectedTo(&pPinConnectedTo); - - if (dir == PINDIR_INPUT) { - nIn++; - if (pPinConnectedTo) { - nInC++; - } - } else if (dir == PINDIR_OUTPUT) { - nOut++; - if (pPinConnectedTo) { - nOutC++; - } - } - } - } - EndEnumPins; - - return (nIn + nOut); -} - -bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly) -{ - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - return (fCountConnectedOnly ? nOutC > 1 : nOut > 1); -} - -bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly) -{ - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - return (fCountConnectedOnly ? nInC > 1 : nIn > 1); -} - -bool IsStreamStart(IBaseFilter* pBF) -{ - CComQIPtr pAMMF(pBF); - if (pAMMF && pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE) { - return true; - } - - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - AM_MEDIA_TYPE mt; - CComPtr pIn = GetFirstPin(pBF); - return ((nOut > 1) - || (nOut > 0 && nIn == 1 && pIn && SUCCEEDED(pIn->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream)); -} - -bool IsStreamEnd(IBaseFilter* pBF) -{ - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - return (nOut == 0); -} - -bool IsVideoRenderer(IBaseFilter* pBF) -{ - CLSID clsid = GetCLSID(pBF); - if (clsid == CLSID_VideoRenderer || clsid == CLSID_VideoRendererDefault || clsid == CLSID_VideoMixingRenderer9 || clsid == CLSID_EnhancedVideoRenderer || clsid == CLSID_madVR || clsid == CLSID_DXR || clsid == CLSID_MPCVR) { - return true; - } - - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - - if (nInC > 0 && nOut == 0) { - BeginEnumPins(pBF, pEP, pPin) { - AM_MEDIA_TYPE mt; - if (S_OK != pPin->ConnectionMediaType(&mt)) { - continue; - } - - FreeMediaType(mt); - - return !!(mt.majortype == MEDIATYPE_Video); - /*&& (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_VideoInfo2));*/ - } - EndEnumPins; - } - - return false; -} - -bool IsAudioWaveRenderer(IBaseFilter* pBF) -{ - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - - if (nInC > 0 && nOut == 0 && CComQIPtr(pBF)) { - BeginEnumPins(pBF, pEP, pPin) { - AM_MEDIA_TYPE mt; - if (S_OK != pPin->ConnectionMediaType(&mt)) { - continue; - } - - FreeMediaType(mt); - - return !!(mt.majortype == MEDIATYPE_Audio); - /*&& mt.formattype == FORMAT_WaveFormatEx);*/ - } - EndEnumPins; - } - - CLSID clsid; - memcpy(&clsid, &GUID_NULL, sizeof(clsid)); - pBF->GetClassID(&clsid); - - return clsid == CLSID_DSoundRender || - clsid == CLSID_AudioRender || - clsid == CLSID_SANEAR_INTERNAL || - clsid == CLSID_SANEAR || - clsid == CLSID_ReClock || - clsid == CLSID_MPCBEAudioRenderer || - clsid == GUIDFromCString(L"{EC9ED6FC-7B03-4cb6-8C01-4EABE109F26B}") || // MediaPortal Audio Renderer - clsid == GUIDFromCString(L"{50063380-2B2F-4855-9A1E-40FCA344C7AC}") || // Surodev ASIO Renderer - clsid == GUIDFromCString(L"{8DE31E85-10FC-4088-8861-E0EC8E70744A}") || // MultiChannel ASIO Renderer - clsid == GUIDFromCString(L"{205F9417-8EEF-40B4-91CF-C7C6A96936EF}") || // MBSE MultiChannel ASIO Renderer - clsid == __uuidof(CNullAudioRenderer) || - clsid == __uuidof(CNullUAudioRenderer); -} - -IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin) -{ - return GetFilterFromPin(GetUpStreamPin(pBF, pInputPin)); -} - -IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin) -{ - BeginEnumPins(pBF, pEP, pPin) { - if (pInputPin && pInputPin != pPin) { - continue; - } - - PIN_DIRECTION dir; - CComPtr pPinConnectedTo; - if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT - && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo))) { - IPin* pRet = pPinConnectedTo.Detach(); - pRet->Release(); - return pRet; - } - } - EndEnumPins; - - return nullptr; -} - -IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir) -{ - if (pBF) { - BeginEnumPins(pBF, pEP, pPin) { - PIN_DIRECTION dir2; - if (SUCCEEDED(pPin->QueryDirection(&dir2)) && dir == dir2) { - IPin* pRet = pPin.Detach(); - pRet->Release(); - return pRet; - } - } - EndEnumPins; - } - - return nullptr; -} - -IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir) -{ - if (pBF) { - BeginEnumPins(pBF, pEP, pPin) { - PIN_DIRECTION dir2; - CComPtr pPinTo; - if (SUCCEEDED(pPin->QueryDirection(&dir2)) && dir == dir2 && (S_OK != pPin->ConnectedTo(&pPinTo))) { - IPin* pRet = pPin.Detach(); - pRet->Release(); - return pRet; - } - } - EndEnumPins; - } - - return nullptr; -} - -IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG) -{ - CLSID clsid2; - CLSIDFromString(CComBSTR(clsid), &clsid2); - return FindFilter(clsid2, pFG); -} - -IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG) -{ - BeginEnumFilters(pFG, pEF, pBF) { - CLSID clsid2; - if (SUCCEEDED(pBF->GetClassID(&clsid2)) && clsid == clsid2) { - return pBF; - } - } - EndEnumFilters; - - return nullptr; -} - -IBaseFilter* FindFirstFilter(IFilterGraph* pFG) { - BeginEnumFilters(pFG, pEF, pBF) { - return pBF; - } - EndEnumFilters; - - return nullptr; -} - -IPin* FindPin(IBaseFilter* pBF, PIN_DIRECTION direction, const AM_MEDIA_TYPE* pRequestedMT) -{ - PIN_DIRECTION pindir; - BeginEnumPins(pBF, pEP, pPin) { - CComPtr pFellow; - - if (SUCCEEDED(pPin->QueryDirection(&pindir)) && - pindir == direction && - pPin->ConnectedTo(&pFellow) == VFW_E_NOT_CONNECTED) { - BeginEnumMediaTypes(pPin, pEM, pmt) { - if (pmt->majortype == pRequestedMT->majortype && pmt->subtype == pRequestedMT->subtype) { - return (pPin); - } - } - EndEnumMediaTypes(pmt); - } - } - EndEnumPins; - return nullptr; -} - -CStringW GetFilterName(IBaseFilter* pBF) -{ - CStringW name = _T(""); - - if (pBF) { - CFilterInfo fi; - if (SUCCEEDED(pBF->QueryFilterInfo(&fi))) { - name = fi.achName; - } - } - - return name; -} - -CStringW GetPinName(IPin* pPin) -{ - CStringW name; - CPinInfo pi; - if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { - name = pi.achName; - } - - return name; -} - -IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF) -{ - if (!pBF) { - return nullptr; - } - IFilterGraph* pGraph = nullptr; - CFilterInfo fi; - if (pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) { - pGraph = fi.pGraph; - } - return pGraph; -} - -IBaseFilter* GetFilterFromPin(IPin* pPin) -{ - if (!pPin) { - return nullptr; - } - IBaseFilter* pBF = nullptr; - CPinInfo pi; - if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { - pBF = pi.pFilter; - } - return pBF; -} - -IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) -{ - IPin* pRet = pPin; - - CInterfaceList pFilters; - - do { - if (!pPin || DisplayName.IsEmpty() || !pGB) { - break; - } - - CComPtr pPinTo; - PIN_DIRECTION dir; - if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) { - break; - } - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { - break; - } - - CComPtr pBF; - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { - break; - } - - CComPtr pPB; - if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { - break; - } - - CComVariant var; - if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - break; - } - - pFilters.AddTail(pBF); - BeginEnumFilters(pGB, pEnum, pBF2); - pFilters.AddTail(pBF2); - EndEnumFilters; - - if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { - break; - } - - BeginEnumFilters(pGB, pEnum, pBF2); - if (!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) { - pEnum->Reset(); - } - EndEnumFilters; - - pPinTo = GetFirstPin(pBF, PINDIR_INPUT); - if (!pPinTo) { - pGB->RemoveFilter(pBF); - break; - } - - if (FAILED(pGB->ConnectDirect(pPin, pPinTo, nullptr))) { - pGB->Connect(pPin, pPinTo); - pGB->RemoveFilter(pBF); - break; - } - - BeginEnumFilters(pGB, pEnum, pBF2); - if (!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) { - pEnum->Reset(); - } - EndEnumFilters; - - pRet = GetFirstPin(pBF, PINDIR_OUTPUT); - if (!pRet) { - pRet = pPin; - pGB->RemoveFilter(pBF); - break; - } - } while (false); - - return pRet; -} - -IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) -{ - do { - if (!pPin || DisplayName.IsEmpty() || !pGB) { - break; - } - - PIN_DIRECTION dir; - if (FAILED(pPin->QueryDirection(&dir))) { - break; - } - - CComPtr pFrom, pTo; - - if (dir == PINDIR_INPUT) { - pPin->ConnectedTo(&pFrom); - pTo = pPin; - } else if (dir == PINDIR_OUTPUT) { - pFrom = pPin; - pPin->ConnectedTo(&pTo); - } - - if (!pFrom || !pTo) { - break; - } - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { - break; - } - - CComPtr pBF; - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { - break; - } - - CComPtr pPB; - if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { - break; - } - - CComVariant var; - if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - break; - } - - if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { - break; - } - - CComPtr pFromTo = GetFirstPin(pBF, PINDIR_INPUT); - if (!pFromTo) { - pGB->RemoveFilter(pBF); - break; - } - - if (FAILED(pGB->Disconnect(pFrom)) || FAILED(pGB->Disconnect(pTo))) { - pGB->RemoveFilter(pBF); - pGB->ConnectDirect(pFrom, pTo, nullptr); - break; - } - - if (FAILED(pGB->ConnectDirect(pFrom, pFromTo, nullptr))) { - pGB->RemoveFilter(pBF); - pGB->ConnectDirect(pFrom, pTo, nullptr); - break; - } - - CComPtr pToFrom = GetFirstPin(pBF, PINDIR_OUTPUT); - if (!pToFrom) { - pGB->RemoveFilter(pBF); - pGB->ConnectDirect(pFrom, pTo, nullptr); - break; - } - - if (FAILED(pGB->ConnectDirect(pToFrom, pTo, nullptr))) { - pGB->RemoveFilter(pBF); - pGB->ConnectDirect(pFrom, pTo, nullptr); - break; - } - - pPin = pToFrom; - } while (false); - - return pPin; -} - -void ExtractMediaTypes(IPin* pPin, CAtlArray& types) -{ - types.RemoveAll(); - - BeginEnumMediaTypes(pPin, pEM, pmt) { - bool fFound = false; - - for (ptrdiff_t i = 0; !fFound && i < (int)types.GetCount(); i += 2) { - if (types[i] == pmt->majortype && types[i + 1] == pmt->subtype) { - fFound = true; - } - } - - if (!fFound) { - types.Add(pmt->majortype); - types.Add(pmt->subtype); - } - } - EndEnumMediaTypes(pmt); -} - -void ExtractMediaTypes(IPin* pPin, CAtlList& mts) -{ - mts.RemoveAll(); - - BeginEnumMediaTypes(pPin, pEM, pmt) { - bool fFound = false; - - POSITION pos = mts.GetHeadPosition(); - while (!fFound && pos) { - CMediaType& mt = mts.GetNext(pos); - if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { - fFound = true; - } - } - - if (!fFound) { - mts.AddTail(CMediaType(*pmt)); - } - } - EndEnumMediaTypes(pmt); -} - -int Eval_Exception(int n_except) -{ - if (n_except == STATUS_ACCESS_VIOLATION) { - AfxMessageBox(_T("The property page of this filter has just caused a\nmemory access violation. The application will gently die now :)")); - } - - return EXCEPTION_CONTINUE_SEARCH; -} - -void MyOleCreatePropertyFrame(HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption, ULONG cObjects, LPUNKNOWN FAR* lplpUnk, ULONG cPages, LPCLSID lpPageClsID, LCID lcid, DWORD dwReserved, LPVOID lpvReserved) -{ - __try { - OleCreatePropertyFrame(hwndOwner, x, y, lpszCaption, cObjects, lplpUnk, cPages, lpPageClsID, lcid, dwReserved, lpvReserved); - } __except (Eval_Exception(GetExceptionCode())) { - // No code; this block never executed. - } -} - -void ShowPPage(CString DisplayName, HWND hParentWnd) -{ - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBindCtx, CStringW(DisplayName), &chEaten, &pMoniker)) { - return; - } - - CComPtr pBF; - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { - return; - } - - ShowPPage(pBF, hParentWnd); -} - -void ShowPPage(IUnknown* pUnk, HWND hParentWnd) -{ - CComQIPtr pSPP = pUnk; - if (!pSPP) { - return; - } - - CString str; - - CComQIPtr pBF = pSPP; - CFilterInfo fi; - CComQIPtr pPin = pSPP; - CPinInfo pi; - if (pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) { - str = fi.achName; - } else if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { - str = pi.achName; - } - - CAUUID caGUID; - caGUID.pElems = nullptr; - if (SUCCEEDED(pSPP->GetPages(&caGUID))) { - IUnknown* lpUnk = nullptr; - pSPP.QueryInterface(&lpUnk); - MyOleCreatePropertyFrame( - hParentWnd, 0, 0, CStringW(str), - 1, (IUnknown**)&lpUnk, - caGUID.cElems, caGUID.pElems, - 0, 0, nullptr); - lpUnk->Release(); - - if (caGUID.pElems) { - CoTaskMemFree(caGUID.pElems); - } - } -} - -CLSID GetCLSID(IBaseFilter* pBF) -{ - CLSID clsid = GUID_NULL; - if (pBF) { - pBF->GetClassID(&clsid); - } - return clsid; -} - -CLSID GetCLSID(IPin* pPin) -{ - return GetCLSID(GetFilterFromPin(pPin)); -} - -CString CLSIDToString(CLSID& clsid) -{ - CComHeapPtr pStr; - if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { - return CString(pStr); - } - return CString(); -} - -bool IsCLSIDRegistered(LPCTSTR clsid) -{ - CString rootkey1(_T("CLSID\\")); - CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); - - return ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey1 + clsid, KEY_READ) - || ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey2 + clsid, KEY_READ); -} - -bool IsCLSIDRegistered(const CLSID& clsid) -{ - bool fRet = false; - - CComHeapPtr pStr; - if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { - fRet = IsCLSIDRegistered(CString(pStr)); - } - - return fRet; -} - -CString GetFilterPath(LPCTSTR clsid) -{ - CString rootkey1(_T("CLSID\\")); - CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); - - CRegKey key; - CString path; - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, rootkey1 + clsid + _T("\\InprocServer32"), KEY_READ) - || ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, rootkey2 + clsid + _T("\\InprocServer32"), KEY_READ)) { - ULONG nCount = MAX_PATH; - key.QueryStringValue(nullptr, path.GetBuffer(nCount), &nCount); - path.ReleaseBuffer(nCount); - } - - return path; -} - -CString GetFilterPath(const CLSID& clsid) -{ - CString path; - - CComHeapPtr pStr; - if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { - path = GetFilterPath(CString(pStr)); - } - - return path; -} - -void CStringToBin(CString str, CAtlArray& data) -{ - str.Trim(); - ASSERT((str.GetLength() & 1) == 0); - data.SetCount(str.GetLength() / 2); - - BYTE b = 0; - - str.MakeUpper(); - for (int i = 0, j = str.GetLength(); i < j; i++) { - TCHAR c = str[i]; - if (c >= _T('0') && c <= _T('9')) { - if (!(i & 1)) { - b = ((char(c - _T('0')) << 4) & 0xf0) | (b & 0x0f); - } else { - b = (char(c - _T('0')) & 0x0f) | (b & 0xf0); - } - } else if (c >= _T('A') && c <= _T('F')) { - if (!(i & 1)) { - b = ((char(c - _T('A') + 10) << 4) & 0xf0) | (b & 0x0f); - } else { - b = (char(c - _T('A') + 10) & 0x0f) | (b & 0xf0); - } - } else { - break; - } - - if (i & 1) { - data[i >> 1] = b; - b = 0; - } - } -} - -CString BinToCString(const BYTE* ptr, size_t len) -{ - CString ret; - - while (len-- > 0) { - TCHAR high, low; - - high = (*ptr >> 4) >= 10 ? (*ptr >> 4) - 10 + _T('A') : (*ptr >> 4) + _T('0'); - low = (*ptr & 0xf) >= 10 ? (*ptr & 0xf) - 10 + _T('A') : (*ptr & 0xf) + _T('0'); - - ret.AppendFormat(_T("%c%c"), high, low); - - ptr++; - } - - return ret; -} - -void FindFiles(CString fn, CAtlList& files) -{ - ExtendMaxPathLengthIfNeeded(fn); - CString path = fn; - path.Replace('/', '\\'); - path = path.Left(path.ReverseFind('\\') + 1); - - WIN32_FIND_DATA findData; - ZeroMemory(&findData, sizeof(WIN32_FIND_DATA)); - HANDLE h = FindFirstFile(fn, &findData); - if (h != INVALID_HANDLE_VALUE) { - do { - files.AddTail(path + findData.cFileName); - } while (FindNextFile(h, &findData)); - - FindClose(h); - } -} - -OpticalDiskType_t GetOpticalDiskType(TCHAR drive, CAtlList& files) -{ - files.RemoveAll(); - - CString path; - path.Format(_T("%c:"), drive); - - if (GetDriveType(path + _T("\\")) != DRIVE_CDROM) { - return OpticalDisk_NotFound; - } - - // Check if it contains a disc - HANDLE hDevice = CreateFile(CString(_T("\\\\.\\")) + path, FILE_READ_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (hDevice == INVALID_HANDLE_VALUE) { - return OpticalDisk_NotFound; - } - DWORD cbBytesReturned; - BOOL bSuccess = DeviceIoControl(hDevice, IOCTL_STORAGE_CHECK_VERIFY2, - NULL, 0, NULL, 0, &cbBytesReturned, (LPOVERLAPPED)NULL); - if (!bSuccess) { - return OpticalDisk_NotFound; - } - - // CDROM_DVDVideo - FindFiles(path + _T("\\VIDEO_TS\\video_ts.ifo"), files); - if (!files.IsEmpty()) { - return OpticalDisk_DVDVideo; - } - - // CDROM_BD - FindFiles(path + _T("\\BDMV\\index.bdmv"), files); - if (!files.IsEmpty()) { - return OpticalDisk_BD; - } - - // CDROM_VideoCD - FindFiles(path + _T("\\mpegav\\avseq??.dat"), files); - FindFiles(path + _T("\\mpegav\\avseq??.mpg"), files); - FindFiles(path + _T("\\mpeg2\\avseq??.dat"), files); - FindFiles(path + _T("\\mpeg2\\avseq??.mpg"), files); - FindFiles(path + _T("\\mpegav\\music??.dat"), files); - FindFiles(path + _T("\\mpegav\\music??.mpg"), files); - FindFiles(path + _T("\\mpeg2\\music??.dat"), files); - FindFiles(path + _T("\\mpeg2\\music??.mpg"), files); - if (!files.IsEmpty()) { - return OpticalDisk_VideoCD; - } - - // CDROM_Audio - HANDLE hDrive = CreateFile(CString(_T("\\\\.\\")) + path, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)nullptr); - if (hDrive != INVALID_HANDLE_VALUE) { - DWORD BytesReturned; - CDROM_TOC TOC; - if (DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &TOC, sizeof(TOC), &BytesReturned, 0)) { - ASSERT(TOC.FirstTrack >= 1u && TOC.LastTrack <= _countof(TOC.TrackData)); - TOC.FirstTrack = std::max(TOC.FirstTrack, UCHAR(1)); - TOC.LastTrack = std::min(TOC.LastTrack, UCHAR(_countof(TOC.TrackData))); - for (ptrdiff_t i = TOC.FirstTrack; i <= TOC.LastTrack; i++) { - // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field - auto& trackData = TOC.TrackData[i - 1]; - trackData.Control &= 5; - if (trackData.Control == 0 || trackData.Control == 1) { - CString fn; - fn.Format(_T("%s\\track%02Id.cda"), path.GetString(), i); - files.AddTail(fn); - } - } - } - - CloseHandle(hDrive); - } - if (!files.IsEmpty()) { - return OpticalDisk_Audio; - } - - // it is a cdrom but nothing special - return OpticalDisk_Unknown; -} - -CString GetDriveLabel(TCHAR drive) -{ - CString path; - path.Format(_T("%c:\\"), drive); - - return GetDriveLabel(CPath(path)); -} - -CString GetDriveLabel(CPath path) -{ - CString label; - path.StripToRoot(); - - TCHAR VolumeNameBuffer[MAX_PATH], FileSystemNameBuffer[MAX_PATH]; - DWORD VolumeSerialNumber, MaximumComponentLength, FileSystemFlags; - if (GetVolumeInformation(path, - VolumeNameBuffer, MAX_PATH, &VolumeSerialNumber, &MaximumComponentLength, - &FileSystemFlags, FileSystemNameBuffer, MAX_PATH)) { - label = VolumeNameBuffer; - } - - return label; -} - -bool IsDriveVirtual(CString drive) -{ - HKEY hkey; - DWORD type = REG_BINARY; - TCHAR data[1024] = { 0 }; - DWORD size = sizeof(data) - 2; - - drive=(drive+_T(":")).Left(2); - CString subkey = _T("\\DosDevices\\") + drive; - - RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\MountedDevices"), 0, KEY_READ, &hkey); - if (hkey == INVALID_HANDLE_VALUE) return 0; - RegQueryValueEx(hkey, subkey, 0, &type, (BYTE*)data, &size); - - RegCloseKey(hkey); - CString sig(data); - sig.MakeUpper(); - return sig.Find(_T("VEN_MSFT&PROD_VIRTUAL_DVD-ROM")) >= 0 - || sig.Find(_T("VEN_DISCSOFT&")) >= 0 - || sig.Find(_T("VEN_ELBY&PROD_CLONEDRIVE")) >= 0; -} - -bool GetKeyFrames(CString fn, CUIntArray& kfs) -{ - kfs.RemoveAll(); - - CString fn2 = CString(fn).MakeLower(); - if (fn2.Mid(fn2.ReverseFind('.') + 1) == _T("avi")) { - AVIFileInit(); - - PAVIFILE pfile; - if (AVIFileOpen(&pfile, fn, OF_SHARE_DENY_WRITE, 0L) == 0) { - AVIFILEINFO afi; - ZeroMemory(&afi, sizeof(afi)); - AVIFileInfo(pfile, &afi, sizeof(AVIFILEINFO)); - - CComPtr pavi; - if (AVIFileGetStream(pfile, &pavi, streamtypeVIDEO, 0) == AVIERR_OK) { - AVISTREAMINFO si; - AVIStreamInfo(pavi, &si, sizeof(si)); - - if (afi.dwCaps & AVIFILECAPS_ALLKEYFRAMES) { - kfs.SetSize(si.dwLength); - for (DWORD kf = 0; kf < si.dwLength; kf++) { - kfs[kf] = kf; - } - } else { - for (LONG kf = 0; ; kf++) { - kf = pavi->FindSample(kf, FIND_KEY | FIND_NEXT); - if (kf < 0 || !kfs.IsEmpty() && kfs[kfs.GetCount() - 1] >= (UINT)kf) { - break; - } - kfs.Add(kf); - } - - if (!kfs.IsEmpty() && kfs[kfs.GetCount() - 1] < si.dwLength - 1) { - kfs.Add(si.dwLength - 1); - } - } - } - - AVIFileRelease(pfile); - } - - AVIFileExit(); - } - - return !kfs.IsEmpty(); -} - -DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps /*= 0.0*/) // use to remember the current position -{ - DVD_HMSF_TIMECODE hmsf = { - (BYTE)((rt / 10000000 / 60 / 60)), - (BYTE)((rt / 10000000 / 60) % 60), - (BYTE)((rt / 10000000) % 60), - (BYTE)(1.0 * ((rt / 10000) % 1000) * fps / 1000) - }; - - return hmsf; -} - -DVD_HMSF_TIMECODE RT2HMS(REFERENCE_TIME rt) // used only for information (for display on the screen) -{ - rt = rt / 10000000; - DVD_HMSF_TIMECODE hmsf = { - (BYTE)(rt / 3600), - (BYTE)(rt / 60 % 60), - (BYTE)(rt % 60), - 0 - }; - - return hmsf; -} - -DVD_HMSF_TIMECODE RT2HMS_r(REFERENCE_TIME rt) // used only for information (for display on the screen) -{ - // round to nearest second - return RT2HMS(rt + 5000000); -} - -REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps /*= -1.0*/) -{ - if (fps <= 0.0) { - hmsf.bFrames = 0; - fps = 1.0; - } - return (REFERENCE_TIME)((((REFERENCE_TIME)hmsf.bHours * 60 + hmsf.bMinutes) * 60 + hmsf.bSeconds) * 1000 + 1.0 * hmsf.bFrames * 1000 / fps) * 10000; -} - -void memsetd(void* dst, unsigned int c, size_t nbytes) -{ - size_t n = nbytes / 4; - __stosd((unsigned long*)dst, c, n); -} - -void memsetw(void* dst, unsigned short c, size_t nbytes) -{ - memsetd(dst, c << 16 | c, nbytes); - - size_t n = nbytes / 2; - size_t o = (n / 2) * 2; - if ((n - o) == 1) { - ((WORD*)dst)[o] = c; - } -} - -bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih) -{ - if (pmt && bih && pmt->pbFormat) { - ZeroMemory(bih, sizeof(*bih)); - - if (pmt->formattype == FORMAT_VideoInfo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } else if (pmt->formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } else if (pmt->formattype == FORMAT_MPEGVideo) { - VIDEOINFOHEADER* vih = &((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } else if (pmt->formattype == FORMAT_MPEG2_VIDEO) { - VIDEOINFOHEADER2* vih = &((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } else if (pmt->formattype == FORMAT_DiracVideoInfo) { - VIDEOINFOHEADER2* vih = &((DIRACINFOHEADER*)pmt->pbFormat)->hdr; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } - } - - return false; -} - -bool ExtractAvgTimePerFrame(const AM_MEDIA_TYPE* pmt, REFERENCE_TIME& rtAvgTimePerFrame) -{ - if (pmt->formattype == FORMAT_VideoInfo) { - rtAvgTimePerFrame = ((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame; - } else if (pmt->formattype == FORMAT_VideoInfo2) { - rtAvgTimePerFrame = ((VIDEOINFOHEADER2*)pmt->pbFormat)->AvgTimePerFrame; - } else if (pmt->formattype == FORMAT_MPEGVideo) { - rtAvgTimePerFrame = ((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr.AvgTimePerFrame; - } else if (pmt->formattype == FORMAT_MPEG2Video) { - rtAvgTimePerFrame = ((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.AvgTimePerFrame; - } else { - return false; - } - - return true; -} - -bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih) -{ - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pMS->GetMediaType(&pmt)) && pmt) { - bool fRet = ExtractBIH(pmt, bih); - DeleteMediaType(pmt); - return fRet; - } - - return false; -} - -bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary) -{ - w = h = arx = ary = 0; - - if (pmt->formattype == FORMAT_VideoInfo || pmt->formattype == FORMAT_MPEGVideo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; - w = vih->bmiHeader.biWidth; - h = abs(vih->bmiHeader.biHeight); - arx = w * vih->bmiHeader.biYPelsPerMeter; - ary = h * vih->bmiHeader.biXPelsPerMeter; - } else if (pmt->formattype == FORMAT_VideoInfo2 || pmt->formattype == FORMAT_MPEG2_VIDEO || pmt->formattype == FORMAT_DiracVideoInfo) { - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; - w = vih->bmiHeader.biWidth; - h = abs(vih->bmiHeader.biHeight); - arx = vih->dwPictAspectRatioX; - ary = vih->dwPictAspectRatioY; - } else { - return false; - } - - if (!arx || !ary) { - BYTE* ptr = nullptr; - DWORD len = 0; - - if (pmt->formattype == FORMAT_MPEGVideo) { - ptr = ((MPEG1VIDEOINFO*)pmt->pbFormat)->bSequenceHeader; - len = ((MPEG1VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; - - if (ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { - w = (ptr[4] << 4) | (ptr[5] >> 4); - h = ((ptr[5] & 0xf) << 8) | ptr[6]; - float ar[] = { - 1.0000f, 1.0000f, 0.6735f, 0.7031f, - 0.7615f, 0.8055f, 0.8437f, 0.8935f, - 0.9157f, 0.9815f, 1.0255f, 1.0695f, - 1.0950f, 1.1575f, 1.2015f, 1.0000f, - }; - arx = (int)((float)w / ar[ptr[7] >> 4] + 0.5); - ary = h; - } - } else if (pmt->formattype == FORMAT_MPEG2_VIDEO) { - ptr = (BYTE*)((MPEG2VIDEOINFO*)pmt->pbFormat)->dwSequenceHeader; - len = ((MPEG2VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; - - if (ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { - w = (ptr[4] << 4) | (ptr[5] >> 4); - h = ((ptr[5] & 0xf) << 8) | ptr[6]; - struct { - int x, y; - } ar[] = {{w, h}, {4, 3}, {16, 9}, {221, 100}, {w, h}}; - int i = std::min(std::max(ptr[7] >> 4, 1), 5) - 1; - arx = ar[i].x; - ary = ar[i].y; - } - } - } - - if (!arx || !ary) { - arx = w; - ary = h; - } - - DWORD a = arx, b = ary; - while (a) { - int tmp = a; - a = b % tmp; - b = tmp; - } - if (b) { - arx /= b, ary /= b; - } - - return true; -} - -bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName) -{ - if (!ppBF) { - return false; - } - - *ppBF = nullptr; - FriendlyName.Empty(); - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { - return false; - } - - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(ppBF))) || !*ppBF) { - return false; - } - - CComPtr pPB; - CComVariant var; - if (SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB))) - && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - FriendlyName = var.bstrVal; - } - - return true; -} - -IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB) -{ - do { - if (!pPin || !pMoniker || !pGB) { - break; - } - - CComPtr pPinTo; - PIN_DIRECTION dir; - if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) { - break; - } - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pPB; - if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { - break; - } - - CComVariant var; - if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - break; - } - - CComPtr pBF; - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { - break; - } - - if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { - break; - } - - BeginEnumPins(pBF, pEP, pPinTo2) { - PIN_DIRECTION dir2; - if (FAILED(pPinTo2->QueryDirection(&dir2)) || dir2 != PINDIR_INPUT) { - continue; - } - - if (SUCCEEDED(pGB->ConnectDirect(pPin, pPinTo2, nullptr))) { - return pBF; - } - } - EndEnumFilters; - - pGB->RemoveFilter(pBF); - } while (false); - - return nullptr; -} - -CStringW GetFriendlyName(CStringW displayName) -{ - CStringW friendlyName; - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK == MkParseDisplayName(pBindCtx, CComBSTR(displayName), &chEaten, &pMoniker)) { - CComPtr pPB; - CComVariant var; - if (SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB))) - && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - friendlyName = var.bstrVal; - } - } - - return friendlyName; -} - -typedef HRESULT(__stdcall* fDllCanUnloadNow)(void); - -struct ExternalObject { - CString path; - HINSTANCE hInst; - CLSID clsid; - fDllCanUnloadNow fpDllCanUnloadNow; - bool bUnloadOnNextCheck; -}; - -static CAtlList s_extObjs; -static CCritSec s_csExtObjs; - -HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv, IUnknown* aggregate) -{ - CheckPointer(ppv, E_POINTER); - - CAutoLock lock(&s_csExtObjs); - - CString fullpath = MakeFullPath(path); - - HINSTANCE hInst = nullptr; - bool fFound = false; - - POSITION pos = s_extObjs.GetHeadPosition(); - while (pos) { - ExternalObject& eo = s_extObjs.GetNext(pos); - if (!eo.path.CompareNoCase(fullpath)) { - hInst = eo.hInst; - fFound = true; - eo.bUnloadOnNextCheck = false; - break; - } - } - - HRESULT hr = E_FAIL; - - if (!hInst) { - hInst = LoadLibraryEx(fullpath, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); - } - if (hInst) { - typedef HRESULT(__stdcall * PDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID * ppv); - PDllGetClassObject p = (PDllGetClassObject)GetProcAddress(hInst, "DllGetClassObject"); - - if (p && (aggregate || FAILED(hr = p(clsid, iid, ppv)))) { - CComPtr pCF; - if (SUCCEEDED(hr = p(clsid, IID_PPV_ARGS(&pCF)))) { - hr = pCF->CreateInstance(aggregate, iid, ppv); - } - } - } - - if (FAILED(hr) && hInst && !fFound) { - FreeLibrary(hInst); - return hr; - } - - if (hInst && !fFound) { - ExternalObject eo; - eo.path = fullpath; - eo.hInst = hInst; - eo.clsid = clsid; - eo.fpDllCanUnloadNow = (fDllCanUnloadNow)GetProcAddress(hInst, "DllCanUnloadNow"); - eo.bUnloadOnNextCheck = false; - s_extObjs.AddTail(eo); - } - - return hr; -} - -HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF) -{ - return LoadExternalObject(path, clsid, IID_PPV_ARGS(ppBF)); -} - -HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP) -{ - CAutoLock lock(&s_csExtObjs); - - CLSID clsid2 = GUID_NULL; - if (FAILED(pP->GetClassID(&clsid2))) { - return E_FAIL; - } - - POSITION pos = s_extObjs.GetHeadPosition(); - while (pos) { - ExternalObject& eo = s_extObjs.GetNext(pos); - if (eo.clsid == clsid2) { - return LoadExternalObject(eo.path, clsid, IID_PPV_ARGS(ppPP)); - } - } - - return E_FAIL; -} - -bool UnloadUnusedExternalObjects() -{ - CAutoLock lock(&s_csExtObjs); - - POSITION pos = s_extObjs.GetHeadPosition(), currentPos; - while (pos) { - currentPos = pos; - ExternalObject& eo = s_extObjs.GetNext(pos); - - if (eo.fpDllCanUnloadNow && eo.fpDllCanUnloadNow() == S_OK) { - // Before actually unloading it, we require that the library reports - // that it can be unloaded safely twice in a row with a 60s delay - // between the two checks. - if (eo.bUnloadOnNextCheck) { - FreeLibrary(eo.hInst); - s_extObjs.RemoveAt(currentPos); - } else { - eo.bUnloadOnNextCheck = true; - } - } else { - eo.bUnloadOnNextCheck = false; - } - } - - return s_extObjs.IsEmpty(); -} - -void ExtendMaxPathLengthIfNeeded(CString& path, bool no_url /*= false */) -{ - if (path.GetLength() >= MAX_PATH) { - if (no_url || path.Find(_T("://")) < 0) { // not URL - if (path.Left(4) != _T("\\\\?\\")) { // not already have long path prefix - if (path.Left(2) == _T("\\\\")) { // UNC - path = _T("\\\\?\\UNC") + path.Mid(1); - } else { // normal - path = _T("\\\\?\\") + path; - } - } - } - } -} - -bool ContainsWildcard(CString& path) -{ - int p = path.Find('*'); - if (p >= 0) { - return true; - } - p = path.Find('?'); - if (p >= 0) { - if (p == 2 && path.Left(4) == _T("\\\\?\\")) { - CString tmp = CString(path); - tmp.Delete(0, 3); - return tmp.Find('?') > 0; - } - return true; - } - return false; -} - -void ShortenLongPath(CString& path) -{ - if (path.GetLength() > MAX_PATH && path.Find(_T("\\\\?\\")) < 0) { - CString longpath = _T("\\\\?\\") + path; - TCHAR* buffer = DEBUG_NEW TCHAR[MAX_PATH]; - long length = GetShortPathName(longpath, buffer, MAX_PATH); - if (length > 0 && length < MAX_PATH) { - path = buffer; - path.Replace(_T("\\\\?\\"), _T("")); - delete[] buffer; - } - } -} - -CString MakeFullPath(LPCTSTR path) -{ - CString full(path); - full.Replace('/', '\\'); - - if (full.GetLength() > MAX_PATH) { - return full; - } - - if (full.GetLength() >= 2 && full[0] == '\\') { - if (full[1] != '\\') { - CString fn; - fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); - CPath p(fn); - p.StripToRoot(); - full = CString(p) + full.Mid(1); - } - } else if (full.Find(_T(":\\")) < 0) { - CString fn; - fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); - CPath p(fn); - p.RemoveFileSpec(); - p.AddBackslash(); - full = CString(p) + full; - } - - CPath c(full); - c.Canonicalize(); - return CString(c); -} - -inline bool _IsFourCC(const GUID& guid) -{ - // XXXXXXXX-0000-0010-8000-00AA00389B71 - return (guid.Data2 == 0x0000) && (guid.Data3 == 0x0010) && - (((DWORD*)guid.Data4)[0] == 0xAA000080) && - (((DWORD*)guid.Data4)[1] == 0x719b3800); -} - -bool GetMediaTypeFourCC(const GUID& guid, CString& fourCC) -{ - if (_IsFourCC(guid) && (guid.Data1 >= 0x10000)) { - fourCC.Format(_T("%c%c%c%c"), - (TCHAR)(guid.Data1 >> 0 ) & 0xFF, (TCHAR)(guid.Data1 >> 8 ) & 0xFF, - (TCHAR)(guid.Data1 >> 16) & 0xFF, (TCHAR)(guid.Data1 >> 24) & 0xFF); - fourCC.MakeUpper(); - return true; - } - - fourCC = _T("UNKN"); - return false; -} - -CString GetMediaTypeName(const GUID& guid) -{ - CString ret = guid == GUID_NULL - ? CString(_T("Any type")) - : CString(GuidNames[guid]); - - if (ret == _T("FOURCC GUID")) { - CString str; - if (guid.Data1 >= 0x10000) { - str.Format(_T("Video: %c%c%c%c"), (guid.Data1 >> 0) & 0xff, (guid.Data1 >> 8) & 0xff, (guid.Data1 >> 16) & 0xff, (guid.Data1 >> 24) & 0xff); - } else { - str.Format(_T("Audio: 0x%08x"), guid.Data1); - } - ret = str; - } else if (ret == _T("Unknown GUID Name")) { - WCHAR null[128] = {0}, buff[128]; - StringFromGUID2(GUID_NULL, null, _countof(null) - 1); - ret = CString(CStringW(StringFromGUID2(guid, buff, _countof(buff) - 1) ? buff : null)); - } - - return ret; -} - -GUID GUIDFromCString(CString str) -{ - GUID guid = GUID_NULL; - HRESULT hr = CLSIDFromString(CComBSTR(str), &guid); - ASSERT(SUCCEEDED(hr)); - UNREFERENCED_PARAMETER(hr); - return guid; -} - -HRESULT GUIDFromCString(CString str, GUID& guid) -{ - guid = GUID_NULL; - return CLSIDFromString(CComBSTR(str), &guid); -} - -CString CStringFromGUID(const GUID& guid) -{ - WCHAR null[128] = {0}, buff[128]; - StringFromGUID2(GUID_NULL, null, _countof(null) - 1); - return CString(StringFromGUID2(guid, buff, _countof(buff) - 1) > 0 ? buff : null); -} - -CStringW UTF8To16(LPCSTR utf8) -{ - CStringW str; - int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0) - 1; - if (n <= 0) { - return str; - } - str.ReleaseBuffer(MultiByteToWideChar(CP_UTF8, 0, utf8, -1, str.GetBuffer(n), n + 1) - 1); - return str; -} - -CStringA UTF16To8(LPCWSTR utf16) -{ - CStringA str; - int n = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, nullptr, 0, nullptr, nullptr) - 1; - if (n < 0) { - return str; - } - str.ReleaseBuffer(WideCharToMultiByte(CP_UTF8, 0, utf16, -1, str.GetBuffer(n), n + 1, nullptr, nullptr) - 1); - return str; -} - -CStringW UTF8ToStringW(const char* S) -{ - CStringW str; - if (S == nullptr) { - return str; - } - - // Don't use MultiByteToWideChar(), some characters are not well decoded - const unsigned char* Z = (const unsigned char*)S; - while (*Z) { //0 is end - //1 byte - if (*Z < 0x80) { - str += (wchar_t)(*Z); - Z++; - } - //2 bytes - else if ((*Z & 0xE0) == 0xC0) { - if ((*(Z + 1) & 0xC0) == 0x80) { - str += (wchar_t)((((wchar_t)(*Z & 0x1F)) << 6) | (*(Z + 1) & 0x3F)); - Z += 2; - } else { - str.Empty(); - return str; //Bad character - } - } - //3 bytes - else if ((*Z & 0xF0) == 0xE0) { - if ((*(Z + 1) & 0xC0) == 0x80 && (*(Z + 2) & 0xC0) == 0x80) { - str += (wchar_t)((((wchar_t)(*Z & 0x0F)) << 12) | ((*(Z + 1) & 0x3F) << 6) | (*(Z + 2) & 0x3F)); - Z += 3; - } else { - str.Empty(); - return str; //Bad character - } - } - //4 bytes - else if ((*Z & 0xF8) == 0xF0) { - if ((*(Z + 1) & 0xC0) == 0x80 && (*(Z + 2) & 0xC0) == 0x80 && (*(Z + 3) & 0xC0) == 0x80) { - str += (wchar_t)((((wchar_t)(*Z & 0x0F)) << 18) | ((*(Z + 1) & 0x3F) << 12) || ((*(Z + 2) & 0x3F) << 6) | (*(Z + 3) & 0x3F)); - Z += 4; - } else { - str.Empty(); - return str; //Bad character - } - } else { - str.Empty(); - return str; //Bad character - } - } - return str; -} - -CStringW LocalToStringW(const char* S) -{ - CStringW str; - if (S == nullptr) { - return str; - } - - int Size = MultiByteToWideChar(CP_ACP, 0, S, -1, nullptr, 0); - if (Size != 0) { - str.ReleaseBuffer(MultiByteToWideChar(CP_ACP, 0, S, -1, str.GetBuffer(Size), Size + 1) - 1); - } - return str; -} - -BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status) -{ - try { - return CFile::GetStatus(lpszFileName, status); - } catch (CException* e) { - // MFCBUG: E_INVALIDARG / "Parameter is incorrect" is thrown for certain cds (vs2003) - // http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8&threadm=OZuXYRzWDHA.536%40TK2MSFTNGP10.phx.gbl&rnum=1&prev=/groups%3Fhl%3Den%26lr%3D%26ie%3DISO-8859-1 - TRACE(_T("CFile::GetStatus has thrown an exception\n")); - e->Delete(); - return false; - } -} - -// filter registration helpers - -bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey) -{ - bool bOK = false; - - HKEY hKey; - LONG ec = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, pszKey, 0, KEY_ALL_ACCESS, &hKey); - if (ec == ERROR_SUCCESS) { - if (pszSubkey != 0) { - ec = ::RegDeleteKey(hKey, pszSubkey); - } - - bOK = (ec == ERROR_SUCCESS); - - ::RegCloseKey(hKey); - } - - return bOK; -} - -bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue) -{ - bool bOK = false; - - CString szKey(pszKey); - if (pszSubkey != 0) { - szKey += CString(_T("\\")) + pszSubkey; - } - - HKEY hKey; - LONG ec = ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); - if (ec == ERROR_SUCCESS) { - if (pszValue != 0) { - ec = ::RegSetValueEx(hKey, pszValueName, 0, REG_SZ, - reinterpret_cast(const_cast(pszValue)), - (DWORD)(_tcslen(pszValue) + 1) * sizeof(TCHAR)); - } - - bOK = (ec == ERROR_SUCCESS); - - ::RegCloseKey(hKey); - } - - return bOK; -} - -bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue) -{ - return SetRegKeyValue(pszKey, pszSubkey, 0, pszValue); -} - -void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext, ...) -{ - CString null = CStringFromGUID(GUID_NULL); - CString majortype = CStringFromGUID(MEDIATYPE_Stream); - CString subtype = CStringFromGUID(subtype2); - - SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("0"), chkbytes); - SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); - - DeleteRegKey(_T("Media Type\\") + null, subtype); - - va_list marker; - va_start(marker, ext); - for (; ext; ext = va_arg(marker, LPCTSTR)) { - DeleteRegKey(_T("Media Type\\Extensions"), ext); - } - va_end(marker); -} - -void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext, ...) -{ - CString null = CStringFromGUID(GUID_NULL); - CString majortype = CStringFromGUID(MEDIATYPE_Stream); - CString subtype = CStringFromGUID(subtype2); - - POSITION pos = chkbytes.GetHeadPosition(); - for (ptrdiff_t i = 0; pos; i++) { - CString idx; - idx.Format(_T("%Id"), i); - SetRegKeyValue(_T("Media Type\\") + majortype, subtype, idx, chkbytes.GetNext(pos)); - } - - SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); - - DeleteRegKey(_T("Media Type\\") + null, subtype); - - va_list marker; - va_start(marker, ext); - for (; ext; ext = va_arg(marker, LPCTSTR)) { - DeleteRegKey(_T("Media Type\\Extensions"), ext); - } - va_end(marker); -} - -void UnRegisterSourceFilter(const GUID& subtype) -{ - DeleteRegKey(_T("Media Type\\") + CStringFromGUID(MEDIATYPE_Stream), CStringFromGUID(subtype)); -} - -struct DXVA2_DECODER { - const GUID* Guid; - LPCTSTR Description; -}; - -static const DXVA2_DECODER DXVA2Decoder[] = { - {&GUID_NULL, _T("Unknown")}, - {&GUID_NULL, _T("Not using DXVA")}, - {&DXVA_Intel_H264_ClearVideo, _T("H.264 bitstream decoder, ClearVideo(tm)")}, // Intel ClearVideo H264 bitstream decoder - {&DXVA_Intel_VC1_ClearVideo, _T("VC-1 bitstream decoder, ClearVideo(tm)")}, // Intel ClearVideo VC-1 bitstream decoder - {&DXVA_Intel_VC1_ClearVideo_2, _T("VC-1 bitstream decoder 2, ClearVideo(tm)")}, // Intel ClearVideo VC-1 bitstream decoder 2 - {&DXVA_MPEG4_ASP, _T("MPEG-4 ASP bitstream decoder")}, // NVIDIA MPEG-4 ASP bitstream decoder - {&DXVA_ModeNone, _T("Mode none")}, - {&DXVA_ModeH261_A, _T("H.261 A, post processing")}, - {&DXVA_ModeH261_B, _T("H.261 B, deblocking")}, - {&DXVA_ModeH263_A, _T("H.263 A, motion compensation, no FGT")}, - {&DXVA_ModeH263_B, _T("H.263 B, motion compensation, FGT")}, - {&DXVA_ModeH263_C, _T("H.263 C, IDCT, no FGT")}, - {&DXVA_ModeH263_D, _T("H.263 D, IDCT, FGT")}, - {&DXVA_ModeH263_E, _T("H.263 E, bitstream decoder, no FGT")}, - {&DXVA_ModeH263_F, _T("H.263 F, bitstream decoder, FGT")}, - {&DXVA_ModeMPEG1_A, _T("MPEG-1 A, post processing")}, - {&DXVA_ModeMPEG2_A, _T("MPEG-2 A, motion compensation")}, - {&DXVA_ModeMPEG2_B, _T("MPEG-2 B, motion compensation + blending")}, - {&DXVA_ModeMPEG2_C, _T("MPEG-2 C, IDCT")}, - {&DXVA_ModeMPEG2_D, _T("MPEG-2 D, IDCT + blending")}, - {&DXVA_ModeH264_A, _T("H.264 A, motion compensation, no FGT")}, - {&DXVA_ModeH264_B, _T("H.264 B, motion compensation, FGT")}, - {&DXVA_ModeH264_C, _T("H.264 C, IDCT, no FGT")}, - {&DXVA_ModeH264_D, _T("H.264 D, IDCT, FGT")}, - {&DXVA_ModeH264_E, _T("H.264 E, bitstream decoder, no FGT")}, - {&DXVA_ModeH264_F, _T("H.264 F, bitstream decoder, FGT")}, - {&DXVA_ModeWMV8_A, _T("WMV8 A, post processing")}, - {&DXVA_ModeWMV8_B, _T("WMV8 B, motion compensation")}, - {&DXVA_ModeWMV9_A, _T("WMV9 A, post processing")}, - {&DXVA_ModeWMV9_B, _T("WMV9 B, motion compensation")}, - {&DXVA_ModeWMV9_C, _T("WMV9 C, IDCT")}, - {&DXVA_ModeVC1_A, _T("VC-1 A, post processing")}, - {&DXVA_ModeVC1_B, _T("VC-1 B, motion compensation")}, - {&DXVA_ModeVC1_C, _T("VC-1 C, IDCT")}, - {&DXVA_ModeVC1_D, _T("VC-1 D, bitstream decoder")}, - {&DXVA_NoEncrypt, _T("No encryption")}, - {&DXVA2_ModeMPEG2_MoComp, _T("MPEG-2 motion compensation")}, - {&DXVA2_ModeMPEG2_IDCT, _T("MPEG-2 IDCT")}, - {&DXVA2_ModeMPEG2_VLD, _T("MPEG-2 variable-length decoder")}, - {&DXVA2_ModeH264_A, _T("H.264 A, motion compensation, no FGT")}, - {&DXVA2_ModeH264_B, _T("H.264 B, motion compensation, FGT")}, - {&DXVA2_ModeH264_C, _T("H.264 C, IDCT, no FGT")}, - {&DXVA2_ModeH264_D, _T("H.264 D, IDCT, FGT")}, - {&DXVA2_ModeH264_E, _T("H.264 E, bitstream decoder, no FGT")}, - {&DXVA2_ModeH264_F, _T("H.264 F, bitstream decoder, FGT")}, - {&DXVA2_ModeWMV8_A, _T("WMV8 A, post processing")}, - {&DXVA2_ModeWMV8_B, _T("WMV8 B, motion compensation")}, - {&DXVA2_ModeWMV9_A, _T("WMV9 A, post processing")}, - {&DXVA2_ModeWMV9_B, _T("WMV9 B, motion compensation")}, - {&DXVA2_ModeWMV9_C, _T("WMV9 C, IDCT")}, - {&DXVA2_ModeVC1_A, _T("VC-1 A, post processing")}, - {&DXVA2_ModeVC1_B, _T("VC-1 B, motion compensation")}, - {&DXVA2_ModeVC1_C, _T("VC-1 C, IDCT")}, - {&DXVA2_ModeVC1_D, _T("VC-1 D, bitstream decoder")}, - {&DXVA2_NoEncrypt, _T("No encryption")}, - {&DXVA2_VideoProcProgressiveDevice, _T("Progressive scan")}, - {&DXVA2_VideoProcBobDevice, _T("Bob deinterlacing")}, - {&DXVA2_VideoProcSoftwareDevice, _T("Software processing")} -}; - -LPCTSTR GetDXVAMode(const GUID* guidDecoder) -{ - int nPos = 0; - - for (int i = 1; i < _countof(DXVA2Decoder); i++) { - if (*guidDecoder == *DXVA2Decoder[i].Guid) { - nPos = i; - break; - } - } - - return DXVA2Decoder[nPos].Description; -} - -// hour, minute, second, millisec -CString ReftimeToString(const REFERENCE_TIME& rtVal) -{ - if (rtVal == _I64_MIN) { - return _T("INVALID TIME"); - } - - CString strTemp; - LONGLONG llTotalMs = ConvertToMilliseconds(rtVal); - int lHour = (int)(llTotalMs / (1000 * 60 * 60)); - int lMinute = (llTotalMs / (1000 * 60)) % 60; - int lSecond = (llTotalMs / 1000) % 60; - int lMillisec = llTotalMs % 1000; - - strTemp.Format(_T("%02d:%02d:%02d,%03d"), lHour, lMinute, lSecond, lMillisec); - return strTemp; -} - -// hour, minute, second (round) -CString ReftimeToString2(const REFERENCE_TIME& rtVal) -{ - CString strTemp; - LONGLONG seconds = (rtVal + 5000000) / 10000000; - int lHour = (int)(seconds / 3600); - int lMinute = (int)(seconds / 60 % 60); - int lSecond = (int)(seconds % 60); - - strTemp.Format(_T("%02d:%02d:%02d"), lHour, lMinute, lSecond); - return strTemp; -} - -// minute, second (round) -CString ReftimeToString3(const REFERENCE_TIME& rtVal) -{ - CString strTemp; - LONGLONG seconds = (rtVal + 5000000) / 10000000; - int lMinute = (int)(seconds / 60 % 60); - int lSecond = (int)(seconds % 60); - - ASSERT((int)(seconds / 3600) == 0); - - strTemp.Format(_T("%02d:%02d"), lMinute, lSecond); - return strTemp; -} - -//for compatibility with mpc-be ReftimeToString2, which has option to exclude hours -CStringW ReftimeToString4(REFERENCE_TIME rt, bool showZeroHours /* = true*/) -{ - if (rt == INT64_MIN) { - return L"INVALID TIME"; - } - - DVD_HMSF_TIMECODE tc = RT2HMSF(rt); - - return DVDtimeToString(tc, showZeroHours); -} - -CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours) -{ - CString strTemp; - if (rtVal.bHours > 0 || bAlwaysShowHours) { - strTemp.Format(_T("%02u:%02u:%02u"), rtVal.bHours, rtVal.bMinutes, rtVal.bSeconds); - } else { - strTemp.Format(_T("%02u:%02u"), rtVal.bMinutes, rtVal.bSeconds); - } - return strTemp; -} - -REFERENCE_TIME StringToReftime(LPCTSTR strVal) -{ - REFERENCE_TIME rt = 0; - int lHour = 0; - int lMinute = 0; - int lSecond = 0; - int lMillisec = 0; - - if (_stscanf_s(strVal, _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { - rt = ((((lHour * 60) + lMinute) * 60 + lSecond) * MILLISECONDS + lMillisec) * (UNITS / MILLISECONDS); - } - - return rt; -} - -const wchar_t* StreamTypeToName(PES_STREAM_TYPE _Type) -{ - switch (_Type) { - case VIDEO_STREAM_MPEG1: - return L"MPEG-1"; - case VIDEO_STREAM_MPEG2: - return L"MPEG-2"; - case AUDIO_STREAM_MPEG1: - return L"MPEG-1"; - case AUDIO_STREAM_MPEG2: - return L"MPEG-2"; - case VIDEO_STREAM_H264: - return L"H264"; - case VIDEO_STREAM_HEVC: - return L"HEVC"; - case AUDIO_STREAM_LPCM: - return L"LPCM"; - case AUDIO_STREAM_AC3: - return L"Dolby Digital"; - case AUDIO_STREAM_DTS: - return L"DTS"; - case AUDIO_STREAM_AC3_TRUE_HD: - return L"Dolby TrueHD"; - case AUDIO_STREAM_AC3_PLUS: - return L"Dolby Digital Plus"; - case AUDIO_STREAM_DTS_HD: - return L"DTS-HD High Resolution Audio"; - case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: - return L"DTS-HD Master Audio"; - case PRESENTATION_GRAPHICS_STREAM: - return L"Presentation Graphics Stream"; - case INTERACTIVE_GRAPHICS_STREAM: - return L"Interactive Graphics Stream"; - case SUBTITLE_STREAM: - return L"Subtitle"; - case SECONDARY_AUDIO_AC3_PLUS: - return L"Secondary Dolby Digital Plus"; - case SECONDARY_AUDIO_DTS_HD: - return L"Secondary DTS-HD High Resolution Audio"; - case VIDEO_STREAM_VC1: - return L"VC-1"; - } - return nullptr; -} - -// -// Usage: SetThreadName (-1, "MainThread"); -// Code from http://msdn.microsoft.com/en-us/library/xcb2z8hs%28v=vs.110%29.aspx -// - -#pragma pack(push,8) -typedef struct tagTHREADNAME_INFO { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1 caller thread) - DWORD dwFlags; // reserved for future use, must be zero -} THREADNAME_INFO; -#pragma pack(pop) - -void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) -{ - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = szThreadName; - info.dwThreadID = dwThreadID; - info.dwFlags = 0; - - __try { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } __except (EXCEPTION_EXECUTE_HANDLER) { - } -} - -void CorrectComboBoxHeaderWidth(CWnd* pComboBox) -{ - if (!pComboBox) { - return; - } - - CDC* pDC = pComboBox->GetDC(); - CFont* pFont = pComboBox->GetFont(); - CFont* pOldFont = pDC->SelectObject(pFont); - - CString str; - pComboBox->GetWindowText(str); - CSize szText = pDC->GetTextExtent(str); - - TEXTMETRIC tm; - pDC->GetTextMetrics(&tm); - pDC->SelectObject(pOldFont); - pComboBox->ReleaseDC(pDC); - - CRect r; - pComboBox->GetWindowRect(r); - pComboBox->GetOwner()->ScreenToClient(r); - - r.right = r.left + ::GetSystemMetrics(SM_CXMENUCHECK) + ::GetSystemMetrics(SM_CXEDGE) + szText.cx + tm.tmAveCharWidth; - pComboBox->MoveWindow(r); -} - -CString NormalizeUnicodeStrForSearch(CString srcStr, LANGID langid) { - if (srcStr.IsEmpty()) return srcStr; - wchar_t* src; - - _locale_t locale; - LCID lcid = MAKELCID(MAKELANGID(langid, SUBLANG_DEFAULT), SORT_DEFAULT); - wchar_t localeName[32]; - if (0 == LCIDToLocaleName(lcid, localeName, 32, LOCALE_ALLOW_NEUTRAL_NAMES)) { //try to lowercase by locale, but if not, do a regular MakeLower() - srcStr.MakeLower(); - src = srcStr.GetBuffer(); - } else { - src = srcStr.GetBuffer(); - locale = _wcreate_locale(LC_ALL, localeName); - _wcslwr_s_l(src, wcslen(src) + 1, locale); - } - - int dstLen = int(wcslen(src) * 4); - wchar_t* dest = DEBUG_NEW wchar_t[dstLen]; - - int cchActual = NormalizeString(NormalizationKD, src, -1, dest, dstLen); - if (cchActual <= 0) dest[0] = 0; - WORD* rgType = DEBUG_NEW WORD[dstLen]; - GetStringTypeW(CT_CTYPE3, dest, -1, rgType); - PWSTR pszWrite = dest; - for (int i = 0; dest[i]; i++) { - if (!(rgType[i] & C3_NONSPACING)) { - *pszWrite++ = dest[i]; - } - } - *pszWrite = 0; - delete[] rgType; - - CString ret = dest; - delete[] dest; - return ret; -} - -inline const LONGLONG GetPerfCounter() { - auto GetPerfFrequency = [] { - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - return freq.QuadPart; - }; - static const LONGLONG llPerfFrequency = GetPerfFrequency(); - if (llPerfFrequency) { - LARGE_INTEGER llPerfCounter; - QueryPerformanceCounter(&llPerfCounter); - return llMulDiv(llPerfCounter.QuadPart, 10000000LL, llPerfFrequency, 0); - } else { - // ms to 100ns units - return timeGetTime() * 10000; - } -} - -bool FindStringInList(const CAtlList& list, CString& value) -{ - bool found = false; - POSITION pos = list.GetHeadPosition(); - while (pos && !found) { - if (list.GetNext(pos).CompareNoCase(value) == 0) { - found = true; - } - } - return found; -} - -CStringW ForceTrailingSlash(CStringW folder) { - if (folder.Right(1) != L'\\' && folder.GetLength() > 0) { - folder += L'\\'; - } - return folder; -} - -CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt) { - int discard; - return GetChannelStrFromMediaType(pmt, discard); -} - -CStringW ChannelsToStr(int channels) { - CStringW ret; - switch (channels) { - case 1: - return L"mono"; - case 2: - return L"2.0"; - case 6: - return L"5.1"; - case 7: - return L"6.1"; - case 8: - return L"7.1"; - default: - ret.Format(L"%uch", channels); - return ret; - } -} - -CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt, int& channels) { - if (pmt) { - if (pmt->majortype == MEDIATYPE_Audio) { - if (pmt->formattype == FORMAT_WaveFormatEx) { - channels = ((WAVEFORMATEX*)pmt->pbFormat)->nChannels; - return ChannelsToStr(channels); - } else if (pmt->formattype == FORMAT_VorbisFormat) { - channels = ((VORBISFORMAT*)pmt->pbFormat)->nChannels; - return ChannelsToStr(channels); - } else if (pmt->formattype == FORMAT_VorbisFormat2) { - channels = ((VORBISFORMAT2*)pmt->pbFormat)->Channels; - return ChannelsToStr(channels); - } else { - channels = 2; - } - } else if (pmt->majortype == MEDIATYPE_Midi) { - channels = 2; - return L""; - } - } - ASSERT(false); - return L""; -} - -CStringW GetShortAudioNameFromMediaType(AM_MEDIA_TYPE* pmt) { - if (!pmt) { - return L""; - } - if (pmt->majortype != MEDIATYPE_Audio) { - if (pmt->majortype == MEDIATYPE_Midi) { - return L"MIDI"; - } else { - return L""; - } - } - - if (pmt->subtype == MEDIASUBTYPE_AAC || pmt->subtype == MEDIASUBTYPE_LATM_AAC || pmt->subtype == MEDIASUBTYPE_AAC_ADTS || pmt->subtype == MEDIASUBTYPE_MPEG_ADTS_AAC - || pmt->subtype == MEDIASUBTYPE_MPEG_HEAAC || pmt->subtype == MEDIASUBTYPE_MP4A || pmt->subtype == MEDIASUBTYPE_mp4a) { - return L"AAC"; - } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF - || pmt->subtype == MEDIASUBTYPE_RAW_SPORT || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h || pmt->subtype == MEDIASUBTYPE_DVM) { - return L"AC3"; - } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { - return L"E-AC3"; - } else if (pmt->subtype == MEDIASUBTYPE_DTS || pmt->subtype == MEDIASUBTYPE_DTS2 || pmt->subtype == MEDIASUBTYPE_WAVE_DTS) { - return L"DTS"; - } else if (pmt->subtype == MEDIASUBTYPE_DTS_HD) { - return L"DTS-HD"; - } else if (pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { - return L"LPCM"; - } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { - return L"TrueHD"; - } else if (pmt->subtype == MEDIASUBTYPE_MLP) { - return L"MLP"; - } else if (pmt->subtype == MEDIASUBTYPE_PCM || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT) { - return L"PCM"; - } else if (pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload || pmt->subtype == MEDIASUBTYPE_MPEG1Packet || pmt->subtype == MEDIASUBTYPE_MPEG1Payload) { //are these all actually possible? - return L"MP1"; - } else if (pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO) { - return L"MP2"; - } else if (pmt->subtype == MEDIASUBTYPE_MP3) { - return L"MP3"; - } else if (pmt->subtype == MEDIASUBTYPE_FLAC || pmt->subtype == MEDIASUBTYPE_FLAC_FRAMED) { - return L"FLAC"; - } else if (pmt->subtype == MEDIASUBTYPE_Vorbis || pmt->subtype == MEDIASUBTYPE_Vorbis2) { - return L"Vorbis"; - } else if (pmt->subtype == MEDIASUBTYPE_OPUS || pmt->subtype == MEDIASUBTYPE_OPUS_OLD) { - return L"Opus"; - } else if (pmt->subtype == MEDIASUBTYPE_MSAUDIO1) { - return L"WMA1"; - } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO2) { - return L"WMA2"; - } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO3) { - return L"WMA3"; - } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO4) { - return L"WMA4"; - } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO_LOSSLESS) { - return L"WMA-LL"; - } else if (pmt->subtype == MEDIASUBTYPE_BD_LPCM_AUDIO || pmt->subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { - return L"LPCM"; - } else if (pmt->subtype == MEDIASUBTYPE_IMA_AMV || pmt->subtype == MEDIASUBTYPE_ADPCM_MS || pmt->subtype == MEDIASUBTYPE_IMA_WAV || pmt->subtype == MEDIASUBTYPE_ADPCM_SWF) { - return L"ADPCM"; - } else if (pmt->subtype == MEDIASUBTYPE_TRUESPEECH) { - return L"TrueSpeech"; - } else if (pmt->subtype == MEDIASUBTYPE_PCM_NONE || pmt->subtype == MEDIASUBTYPE_PCM_RAW || pmt->subtype == MEDIASUBTYPE_PCM_TWOS || pmt->subtype == MEDIASUBTYPE_PCM_SOWT - || pmt->subtype == MEDIASUBTYPE_PCM_IN24 || pmt->subtype == MEDIASUBTYPE_PCM_IN32 || pmt->subtype == MEDIASUBTYPE_PCM_FL32 || pmt->subtype == MEDIASUBTYPE_PCM_FL64 - || pmt->subtype == MEDIASUBTYPE_PCM_IN24_le || pmt->subtype == MEDIASUBTYPE_PCM_IN32_le || pmt->subtype == MEDIASUBTYPE_PCM_FL32_le || pmt->subtype == MEDIASUBTYPE_PCM_FL64_le) { - return L"QTPCM"; - } else if (pmt->subtype == MEDIASUBTYPE_TTA1) { - return L"TTA"; - } else if (pmt->subtype == MEDIASUBTYPE_SAMR) { - return L"SAMR"; - } else if (pmt->subtype == MEDIASUBTYPE_QDM2) { - return L"QDM2"; - } else if (pmt->subtype == MEDIASUBTYPE_MSGSM610) { - return L"GSM610"; - } else if (pmt->subtype == MEDIASUBTYPE_ALAW || pmt->subtype == MEDIASUBTYPE_MULAW) { - return L"G711"; - } else if (pmt->subtype == MEDIASUBTYPE_G723 || pmt->subtype == MEDIASUBTYPE_VIVO_G723) { - return L"G723"; - } else if (pmt->subtype == MEDIASUBTYPE_G726) { - return L"G726"; - } else if (pmt->subtype == MEDIASUBTYPE_G729 || pmt->subtype == MEDIASUBTYPE_729A) { - return L"G729"; - } else if (pmt->subtype == MEDIASUBTYPE_APE) { - return L"APE"; - } else if (pmt->subtype == MEDIASUBTYPE_TAK) { - return L"TAK"; - } else if (pmt->subtype == MEDIASUBTYPE_ALS) { - return L"ALS"; - } else if (pmt->subtype == MEDIASUBTYPE_NELLYMOSER) { - return L"NELLY"; - } else if (pmt->subtype == MEDIASUBTYPE_SPEEX) { - return L"Speex"; - } else if (pmt->subtype == MEDIASUBTYPE_AES3) { - return L"AES3"; - } else if (pmt->subtype == MEDIASUBTYPE_DSDL || pmt->subtype == MEDIASUBTYPE_DSDM || pmt->subtype == MEDIASUBTYPE_DSD1 || pmt->subtype == MEDIASUBTYPE_DSD8) { - return L"DSD"; - } else if (pmt->subtype == MEDIASUBTYPE_IMC) { - return L"IMC"; - } else if (pmt->subtype == MEDIASUBTYPE_VOXWARE_RT29) { - return L"RT29"; - } else if (pmt->subtype == MEDIASUBTYPE_MPEG_LOAS) { - return L"LOAS"; - } - - if (_IsFourCC(pmt->subtype)) { - CString fcc; - DWORD a = (pmt->subtype.Data1 >> 24) & 0xFF; - DWORD b = (pmt->subtype.Data1 >> 16) & 0xFF; - DWORD c = (pmt->subtype.Data1 >> 8) & 0xFF; - DWORD d = (pmt->subtype.Data1 >> 0) & 0xFF; - if (a != 0 || b != 0) { - fcc.Format(_T("%02x%02x%02x%02x"), a, b, c, d); - } else { - fcc.Format(_T("%02x%02x"), c, d); - } - return fcc; - } - - return L"UNKN"; -} - -bool GetVideoFormatNameFromMediaType(const GUID& guid, CString& name) { - if (GetMediaTypeFourCC(guid, name)) { - if (name == L"HVC1") { - name = L"HEVC"; - } else if (name == L"AVC1") { - name = L"H264"; - } else if (name == L"VP90") { - name = L"VP9"; - } else if (name == L"AV01") { - name = L"AV1"; - } - return true; - } else if (guid == MEDIASUBTYPE_MPEG1Payload || guid == MEDIASUBTYPE_MPEG1Video) { - name = L"MPEG1"; - return true; - } else if (guid == MEDIASUBTYPE_MPEG2_VIDEO) { - name = L"MPEG2"; - return true; - } else if (guid == MEDIASUBTYPE_ARGB32) { - name = L"ARGB"; - return true; - } else if (guid == MEDIASUBTYPE_RGB32) { - name = L"RGB"; - return true; - } else if (guid == MEDIASUBTYPE_LAV_RAWVIDEO) { - name = L"RAW"; - return true; - } else { - name = L"UNKN"; - ASSERT(false); - } - - return false; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "winddk/devioctl.h" +#include "winddk/ntddcdrm.h" +#include "DSUtil.h" +#include "Mpeg2Def.h" +#include +#include +#include "NullRenderers.h" +#include "mvrInterfaces.h" + +#include "moreuuids.h" +#include +#include +#include + +int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC) +{ + nIn = nOut = 0; + nInC = nOutC = 0; + + BeginEnumPins(pBF, pEP, pPin) { + PIN_DIRECTION dir; + if (SUCCEEDED(pPin->QueryDirection(&dir))) { + CComPtr pPinConnectedTo; + pPin->ConnectedTo(&pPinConnectedTo); + + if (dir == PINDIR_INPUT) { + nIn++; + if (pPinConnectedTo) { + nInC++; + } + } else if (dir == PINDIR_OUTPUT) { + nOut++; + if (pPinConnectedTo) { + nOutC++; + } + } + } + } + EndEnumPins; + + return (nIn + nOut); +} + +bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly) +{ + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + return (fCountConnectedOnly ? nOutC > 1 : nOut > 1); +} + +bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly) +{ + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + return (fCountConnectedOnly ? nInC > 1 : nIn > 1); +} + +bool IsStreamStart(IBaseFilter* pBF) +{ + CComQIPtr pAMMF(pBF); + if (pAMMF && pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE) { + return true; + } + + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + AM_MEDIA_TYPE mt; + CComPtr pIn = GetFirstPin(pBF); + return ((nOut > 1) + || (nOut > 0 && nIn == 1 && pIn && SUCCEEDED(pIn->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream)); +} + +bool IsStreamEnd(IBaseFilter* pBF) +{ + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + return (nOut == 0); +} + +bool IsVideoRenderer(IBaseFilter* pBF) +{ + CLSID clsid = GetCLSID(pBF); + if (clsid == CLSID_VideoRenderer || clsid == CLSID_VideoRendererDefault || clsid == CLSID_VideoMixingRenderer9 || clsid == CLSID_EnhancedVideoRenderer || clsid == CLSID_madVR || clsid == CLSID_DXR || clsid == CLSID_MPCVR) { + return true; + } + + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + + if (nInC > 0 && nOut == 0) { + BeginEnumPins(pBF, pEP, pPin) { + AM_MEDIA_TYPE mt; + if (S_OK != pPin->ConnectionMediaType(&mt)) { + continue; + } + + FreeMediaType(mt); + + return !!(mt.majortype == MEDIATYPE_Video); + /*&& (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_VideoInfo2));*/ + } + EndEnumPins; + } + + return false; +} + +bool IsAudioWaveRenderer(IBaseFilter* pBF) +{ + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + + if (nInC > 0 && nOut == 0 && CComQIPtr(pBF)) { + BeginEnumPins(pBF, pEP, pPin) { + AM_MEDIA_TYPE mt; + if (S_OK != pPin->ConnectionMediaType(&mt)) { + continue; + } + + FreeMediaType(mt); + + return !!(mt.majortype == MEDIATYPE_Audio); + /*&& mt.formattype == FORMAT_WaveFormatEx);*/ + } + EndEnumPins; + } + + CLSID clsid; + memcpy(&clsid, &GUID_NULL, sizeof(clsid)); + pBF->GetClassID(&clsid); + + return clsid == CLSID_DSoundRender || + clsid == CLSID_AudioRender || + clsid == CLSID_SANEAR_INTERNAL || + clsid == CLSID_SANEAR || + clsid == CLSID_ReClock || + clsid == CLSID_MPCBEAudioRenderer || + clsid == GUIDFromCString(L"{EC9ED6FC-7B03-4cb6-8C01-4EABE109F26B}") || // MediaPortal Audio Renderer + clsid == GUIDFromCString(L"{50063380-2B2F-4855-9A1E-40FCA344C7AC}") || // Surodev ASIO Renderer + clsid == GUIDFromCString(L"{8DE31E85-10FC-4088-8861-E0EC8E70744A}") || // MultiChannel ASIO Renderer + clsid == GUIDFromCString(L"{205F9417-8EEF-40B4-91CF-C7C6A96936EF}") || // MBSE MultiChannel ASIO Renderer + clsid == __uuidof(CNullAudioRenderer) || + clsid == __uuidof(CNullUAudioRenderer); +} + +IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin) +{ + return GetFilterFromPin(GetUpStreamPin(pBF, pInputPin)); +} + +IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin) +{ + BeginEnumPins(pBF, pEP, pPin) { + if (pInputPin && pInputPin != pPin) { + continue; + } + + PIN_DIRECTION dir; + CComPtr pPinConnectedTo; + if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT + && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo))) { + IPin* pRet = pPinConnectedTo.Detach(); + pRet->Release(); + return pRet; + } + } + EndEnumPins; + + return nullptr; +} + +IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir) +{ + if (pBF) { + BeginEnumPins(pBF, pEP, pPin) { + PIN_DIRECTION dir2; + if (SUCCEEDED(pPin->QueryDirection(&dir2)) && dir == dir2) { + IPin* pRet = pPin.Detach(); + pRet->Release(); + return pRet; + } + } + EndEnumPins; + } + + return nullptr; +} + +IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir) +{ + if (pBF) { + BeginEnumPins(pBF, pEP, pPin) { + PIN_DIRECTION dir2; + CComPtr pPinTo; + if (SUCCEEDED(pPin->QueryDirection(&dir2)) && dir == dir2 && (S_OK != pPin->ConnectedTo(&pPinTo))) { + IPin* pRet = pPin.Detach(); + pRet->Release(); + return pRet; + } + } + EndEnumPins; + } + + return nullptr; +} + +IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG) +{ + CLSID clsid2; + CLSIDFromString(CComBSTR(clsid), &clsid2); + return FindFilter(clsid2, pFG); +} + +IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG) +{ + BeginEnumFilters(pFG, pEF, pBF) { + CLSID clsid2; + if (SUCCEEDED(pBF->GetClassID(&clsid2)) && clsid == clsid2) { + return pBF; + } + } + EndEnumFilters; + + return nullptr; +} + +IBaseFilter* FindFirstFilter(IFilterGraph* pFG) { + BeginEnumFilters(pFG, pEF, pBF) { + return pBF; + } + EndEnumFilters; + + return nullptr; +} + +IPin* FindPin(IBaseFilter* pBF, PIN_DIRECTION direction, const AM_MEDIA_TYPE* pRequestedMT) +{ + PIN_DIRECTION pindir; + BeginEnumPins(pBF, pEP, pPin) { + CComPtr pFellow; + + if (SUCCEEDED(pPin->QueryDirection(&pindir)) && + pindir == direction && + pPin->ConnectedTo(&pFellow) == VFW_E_NOT_CONNECTED) { + BeginEnumMediaTypes(pPin, pEM, pmt) { + if (pmt->majortype == pRequestedMT->majortype && pmt->subtype == pRequestedMT->subtype) { + return (pPin); + } + } + EndEnumMediaTypes(pmt); + } + } + EndEnumPins; + return nullptr; +} + +CStringW GetFilterName(IBaseFilter* pBF) +{ + CStringW name = _T(""); + + if (pBF) { + CFilterInfo fi; + if (SUCCEEDED(pBF->QueryFilterInfo(&fi))) { + name = fi.achName; + } + } + + return name; +} + +CStringW GetPinName(IPin* pPin) +{ + CStringW name; + CPinInfo pi; + if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { + name = pi.achName; + } + + return name; +} + +IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF) +{ + if (!pBF) { + return nullptr; + } + IFilterGraph* pGraph = nullptr; + CFilterInfo fi; + if (pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) { + pGraph = fi.pGraph; + } + return pGraph; +} + +IBaseFilter* GetFilterFromPin(IPin* pPin) +{ + if (!pPin) { + return nullptr; + } + IBaseFilter* pBF = nullptr; + CPinInfo pi; + if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { + pBF = pi.pFilter; + } + return pBF; +} + +IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) +{ + IPin* pRet = pPin; + + CInterfaceList pFilters; + + do { + if (!pPin || DisplayName.IsEmpty() || !pGB) { + break; + } + + CComPtr pPinTo; + PIN_DIRECTION dir; + if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) { + break; + } + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { + break; + } + + CComPtr pBF; + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { + break; + } + + CComPtr pPB; + if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { + break; + } + + CComVariant var; + if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + break; + } + + pFilters.AddTail(pBF); + BeginEnumFilters(pGB, pEnum, pBF2); + pFilters.AddTail(pBF2); + EndEnumFilters; + + if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { + break; + } + + BeginEnumFilters(pGB, pEnum, pBF2); + if (!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) { + pEnum->Reset(); + } + EndEnumFilters; + + pPinTo = GetFirstPin(pBF, PINDIR_INPUT); + if (!pPinTo) { + pGB->RemoveFilter(pBF); + break; + } + + if (FAILED(pGB->ConnectDirect(pPin, pPinTo, nullptr))) { + pGB->Connect(pPin, pPinTo); + pGB->RemoveFilter(pBF); + break; + } + + BeginEnumFilters(pGB, pEnum, pBF2); + if (!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) { + pEnum->Reset(); + } + EndEnumFilters; + + pRet = GetFirstPin(pBF, PINDIR_OUTPUT); + if (!pRet) { + pRet = pPin; + pGB->RemoveFilter(pBF); + break; + } + } while (false); + + return pRet; +} + +IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) +{ + do { + if (!pPin || DisplayName.IsEmpty() || !pGB) { + break; + } + + PIN_DIRECTION dir; + if (FAILED(pPin->QueryDirection(&dir))) { + break; + } + + CComPtr pFrom, pTo; + + if (dir == PINDIR_INPUT) { + pPin->ConnectedTo(&pFrom); + pTo = pPin; + } else if (dir == PINDIR_OUTPUT) { + pFrom = pPin; + pPin->ConnectedTo(&pTo); + } + + if (!pFrom || !pTo) { + break; + } + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { + break; + } + + CComPtr pBF; + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { + break; + } + + CComPtr pPB; + if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { + break; + } + + CComVariant var; + if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + break; + } + + if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { + break; + } + + CComPtr pFromTo = GetFirstPin(pBF, PINDIR_INPUT); + if (!pFromTo) { + pGB->RemoveFilter(pBF); + break; + } + + if (FAILED(pGB->Disconnect(pFrom)) || FAILED(pGB->Disconnect(pTo))) { + pGB->RemoveFilter(pBF); + pGB->ConnectDirect(pFrom, pTo, nullptr); + break; + } + + if (FAILED(pGB->ConnectDirect(pFrom, pFromTo, nullptr))) { + pGB->RemoveFilter(pBF); + pGB->ConnectDirect(pFrom, pTo, nullptr); + break; + } + + CComPtr pToFrom = GetFirstPin(pBF, PINDIR_OUTPUT); + if (!pToFrom) { + pGB->RemoveFilter(pBF); + pGB->ConnectDirect(pFrom, pTo, nullptr); + break; + } + + if (FAILED(pGB->ConnectDirect(pToFrom, pTo, nullptr))) { + pGB->RemoveFilter(pBF); + pGB->ConnectDirect(pFrom, pTo, nullptr); + break; + } + + pPin = pToFrom; + } while (false); + + return pPin; +} + +void ExtractMediaTypes(IPin* pPin, CAtlArray& types) +{ + types.RemoveAll(); + + BeginEnumMediaTypes(pPin, pEM, pmt) { + bool fFound = false; + + for (ptrdiff_t i = 0; !fFound && i < (int)types.GetCount(); i += 2) { + if (types[i] == pmt->majortype && types[i + 1] == pmt->subtype) { + fFound = true; + } + } + + if (!fFound) { + types.Add(pmt->majortype); + types.Add(pmt->subtype); + } + } + EndEnumMediaTypes(pmt); +} + +void ExtractMediaTypes(IPin* pPin, CAtlList& mts) +{ + mts.RemoveAll(); + + BeginEnumMediaTypes(pPin, pEM, pmt) { + bool fFound = false; + + POSITION pos = mts.GetHeadPosition(); + while (!fFound && pos) { + CMediaType& mt = mts.GetNext(pos); + if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { + fFound = true; + } + } + + if (!fFound) { + mts.AddTail(CMediaType(*pmt)); + } + } + EndEnumMediaTypes(pmt); +} + +int Eval_Exception(int n_except) +{ + if (n_except == STATUS_ACCESS_VIOLATION) { + AfxMessageBox(_T("The property page of this filter has just caused a\nmemory access violation. The application will gently die now :)")); + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +void MyOleCreatePropertyFrame(HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption, ULONG cObjects, LPUNKNOWN FAR* lplpUnk, ULONG cPages, LPCLSID lpPageClsID, LCID lcid, DWORD dwReserved, LPVOID lpvReserved) +{ + __try { + OleCreatePropertyFrame(hwndOwner, x, y, lpszCaption, cObjects, lplpUnk, cPages, lpPageClsID, lcid, dwReserved, lpvReserved); + } __except (Eval_Exception(GetExceptionCode())) { + // No code; this block never executed. + } +} + +void ShowPPage(CString DisplayName, HWND hParentWnd) +{ + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBindCtx, CStringW(DisplayName), &chEaten, &pMoniker)) { + return; + } + + CComPtr pBF; + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { + return; + } + + ShowPPage(pBF, hParentWnd); +} + +void ShowPPage(IUnknown* pUnk, HWND hParentWnd) +{ + CComQIPtr pSPP = pUnk; + if (!pSPP) { + return; + } + + CString str; + + CComQIPtr pBF = pSPP; + CFilterInfo fi; + CComQIPtr pPin = pSPP; + CPinInfo pi; + if (pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) { + str = fi.achName; + } else if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { + str = pi.achName; + } + + CAUUID caGUID; + caGUID.pElems = nullptr; + if (SUCCEEDED(pSPP->GetPages(&caGUID))) { + IUnknown* lpUnk = nullptr; + pSPP.QueryInterface(&lpUnk); + MyOleCreatePropertyFrame( + hParentWnd, 0, 0, CStringW(str), + 1, (IUnknown**)&lpUnk, + caGUID.cElems, caGUID.pElems, + 0, 0, nullptr); + lpUnk->Release(); + + if (caGUID.pElems) { + CoTaskMemFree(caGUID.pElems); + } + } +} + +CLSID GetCLSID(IBaseFilter* pBF) +{ + CLSID clsid = GUID_NULL; + if (pBF) { + pBF->GetClassID(&clsid); + } + return clsid; +} + +CLSID GetCLSID(IPin* pPin) +{ + return GetCLSID(GetFilterFromPin(pPin)); +} + +CString CLSIDToString(CLSID& clsid) +{ + CComHeapPtr pStr; + if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { + return CString(pStr); + } + return CString(); +} + +bool IsCLSIDRegistered(LPCTSTR clsid) +{ + CString rootkey1(_T("CLSID\\")); + CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); + + return ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey1 + clsid, KEY_READ) + || ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey2 + clsid, KEY_READ); +} + +bool IsCLSIDRegistered(const CLSID& clsid) +{ + bool fRet = false; + + CComHeapPtr pStr; + if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { + fRet = IsCLSIDRegistered(CString(pStr)); + } + + return fRet; +} + +CString GetFilterPath(LPCTSTR clsid) +{ + CString rootkey1(_T("CLSID\\")); + CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); + + CRegKey key; + CString path; + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, rootkey1 + clsid + _T("\\InprocServer32"), KEY_READ) + || ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, rootkey2 + clsid + _T("\\InprocServer32"), KEY_READ)) { + ULONG nCount = MAX_PATH; + key.QueryStringValue(nullptr, path.GetBuffer(nCount), &nCount); + path.ReleaseBuffer(nCount); + } + + return path; +} + +CString GetFilterPath(const CLSID& clsid) +{ + CString path; + + CComHeapPtr pStr; + if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { + path = GetFilterPath(CString(pStr)); + } + + return path; +} + +void CStringToBin(CString str, CAtlArray& data) +{ + str.Trim(); + ASSERT((str.GetLength() & 1) == 0); + data.SetCount(str.GetLength() / 2); + + BYTE b = 0; + + str.MakeUpper(); + for (int i = 0, j = str.GetLength(); i < j; i++) { + TCHAR c = str[i]; + if (c >= _T('0') && c <= _T('9')) { + if (!(i & 1)) { + b = ((char(c - _T('0')) << 4) & 0xf0) | (b & 0x0f); + } else { + b = (char(c - _T('0')) & 0x0f) | (b & 0xf0); + } + } else if (c >= _T('A') && c <= _T('F')) { + if (!(i & 1)) { + b = ((char(c - _T('A') + 10) << 4) & 0xf0) | (b & 0x0f); + } else { + b = (char(c - _T('A') + 10) & 0x0f) | (b & 0xf0); + } + } else { + break; + } + + if (i & 1) { + data[i >> 1] = b; + b = 0; + } + } +} + +CString BinToCString(const BYTE* ptr, size_t len) +{ + CString ret; + + while (len-- > 0) { + TCHAR high, low; + + high = (*ptr >> 4) >= 10 ? (*ptr >> 4) - 10 + _T('A') : (*ptr >> 4) + _T('0'); + low = (*ptr & 0xf) >= 10 ? (*ptr & 0xf) - 10 + _T('A') : (*ptr & 0xf) + _T('0'); + + ret.AppendFormat(_T("%c%c"), high, low); + + ptr++; + } + + return ret; +} + +void FindFiles(CString fn, CAtlList& files) +{ + ExtendMaxPathLengthIfNeeded(fn); + CString path = fn; + path.Replace('/', '\\'); + path = path.Left(path.ReverseFind('\\') + 1); + + WIN32_FIND_DATA findData; + ZeroMemory(&findData, sizeof(WIN32_FIND_DATA)); + HANDLE h = FindFirstFile(fn, &findData); + if (h != INVALID_HANDLE_VALUE) { + do { + files.AddTail(path + findData.cFileName); + } while (FindNextFile(h, &findData)); + + FindClose(h); + } +} + +OpticalDiskType_t GetOpticalDiskType(TCHAR drive, CAtlList& files) +{ + files.RemoveAll(); + + CString path; + path.Format(_T("%c:"), drive); + + if (GetDriveType(path + _T("\\")) != DRIVE_CDROM) { + return OpticalDisk_NotFound; + } + + // Check if it contains a disc + HANDLE hDevice = CreateFile(CString(_T("\\\\.\\")) + path, FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (hDevice == INVALID_HANDLE_VALUE) { + return OpticalDisk_NotFound; + } + DWORD cbBytesReturned; + BOOL bSuccess = DeviceIoControl(hDevice, IOCTL_STORAGE_CHECK_VERIFY2, + NULL, 0, NULL, 0, &cbBytesReturned, (LPOVERLAPPED)NULL); + if (!bSuccess) { + return OpticalDisk_NotFound; + } + + // CDROM_DVDVideo + FindFiles(path + _T("\\VIDEO_TS\\video_ts.ifo"), files); + if (!files.IsEmpty()) { + return OpticalDisk_DVDVideo; + } + + // CDROM_BD + FindFiles(path + _T("\\BDMV\\index.bdmv"), files); + if (!files.IsEmpty()) { + return OpticalDisk_BD; + } + + // CDROM_VideoCD + FindFiles(path + _T("\\mpegav\\avseq??.dat"), files); + FindFiles(path + _T("\\mpegav\\avseq??.mpg"), files); + FindFiles(path + _T("\\mpeg2\\avseq??.dat"), files); + FindFiles(path + _T("\\mpeg2\\avseq??.mpg"), files); + FindFiles(path + _T("\\mpegav\\music??.dat"), files); + FindFiles(path + _T("\\mpegav\\music??.mpg"), files); + FindFiles(path + _T("\\mpeg2\\music??.dat"), files); + FindFiles(path + _T("\\mpeg2\\music??.mpg"), files); + if (!files.IsEmpty()) { + return OpticalDisk_VideoCD; + } + + // CDROM_Audio + HANDLE hDrive = CreateFile(CString(_T("\\\\.\\")) + path, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)nullptr); + if (hDrive != INVALID_HANDLE_VALUE) { + DWORD BytesReturned; + CDROM_TOC TOC; + if (DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &TOC, sizeof(TOC), &BytesReturned, 0)) { + ASSERT(TOC.FirstTrack >= 1u && TOC.LastTrack <= _countof(TOC.TrackData)); + TOC.FirstTrack = std::max(TOC.FirstTrack, UCHAR(1)); + TOC.LastTrack = std::min(TOC.LastTrack, UCHAR(_countof(TOC.TrackData))); + for (ptrdiff_t i = TOC.FirstTrack; i <= TOC.LastTrack; i++) { + // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field + auto& trackData = TOC.TrackData[i - 1]; + trackData.Control &= 5; + if (trackData.Control == 0 || trackData.Control == 1) { + CString fn; + fn.Format(_T("%s\\track%02Id.cda"), path.GetString(), i); + files.AddTail(fn); + } + } + } + + CloseHandle(hDrive); + } + if (!files.IsEmpty()) { + return OpticalDisk_Audio; + } + + // it is a cdrom but nothing special + return OpticalDisk_Unknown; +} + +CString GetDriveLabel(TCHAR drive) +{ + CString path; + path.Format(_T("%c:\\"), drive); + + return GetDriveLabel(CPath(path)); +} + +CString GetDriveLabel(CPath path) +{ + CString label; + path.StripToRoot(); + + TCHAR VolumeNameBuffer[MAX_PATH], FileSystemNameBuffer[MAX_PATH]; + DWORD VolumeSerialNumber, MaximumComponentLength, FileSystemFlags; + if (GetVolumeInformation(path, + VolumeNameBuffer, MAX_PATH, &VolumeSerialNumber, &MaximumComponentLength, + &FileSystemFlags, FileSystemNameBuffer, MAX_PATH)) { + label = VolumeNameBuffer; + } + + return label; +} + +bool IsDriveVirtual(CString drive) +{ + HKEY hkey; + DWORD type = REG_BINARY; + TCHAR data[1024] = { 0 }; + DWORD size = sizeof(data) - 2; + + drive=(drive+_T(":")).Left(2); + CString subkey = _T("\\DosDevices\\") + drive; + + RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\MountedDevices"), 0, KEY_READ, &hkey); + if (hkey == INVALID_HANDLE_VALUE) return 0; + RegQueryValueEx(hkey, subkey, 0, &type, (BYTE*)data, &size); + + RegCloseKey(hkey); + CString sig(data); + sig.MakeUpper(); + return sig.Find(_T("VEN_MSFT&PROD_VIRTUAL_DVD-ROM")) >= 0 + || sig.Find(_T("VEN_DISCSOFT&")) >= 0 + || sig.Find(_T("VEN_ELBY&PROD_CLONEDRIVE")) >= 0; +} + +bool GetKeyFrames(CString fn, CUIntArray& kfs) +{ + kfs.RemoveAll(); + + CString fn2 = CString(fn).MakeLower(); + if (fn2.Mid(fn2.ReverseFind('.') + 1) == _T("avi")) { + AVIFileInit(); + + PAVIFILE pfile; + if (AVIFileOpen(&pfile, fn, OF_SHARE_DENY_WRITE, 0L) == 0) { + AVIFILEINFO afi; + ZeroMemory(&afi, sizeof(afi)); + AVIFileInfo(pfile, &afi, sizeof(AVIFILEINFO)); + + CComPtr pavi; + if (AVIFileGetStream(pfile, &pavi, streamtypeVIDEO, 0) == AVIERR_OK) { + AVISTREAMINFO si; + AVIStreamInfo(pavi, &si, sizeof(si)); + + if (afi.dwCaps & AVIFILECAPS_ALLKEYFRAMES) { + kfs.SetSize(si.dwLength); + for (DWORD kf = 0; kf < si.dwLength; kf++) { + kfs[kf] = kf; + } + } else { + for (LONG kf = 0; ; kf++) { + kf = pavi->FindSample(kf, FIND_KEY | FIND_NEXT); + if (kf < 0 || !kfs.IsEmpty() && kfs[kfs.GetCount() - 1] >= (UINT)kf) { + break; + } + kfs.Add(kf); + } + + if (!kfs.IsEmpty() && kfs[kfs.GetCount() - 1] < si.dwLength - 1) { + kfs.Add(si.dwLength - 1); + } + } + } + + AVIFileRelease(pfile); + } + + AVIFileExit(); + } + + return !kfs.IsEmpty(); +} + +DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps /*= 0.0*/) // use to remember the current position +{ + DVD_HMSF_TIMECODE hmsf = { + (BYTE)((rt / 10000000 / 60 / 60)), + (BYTE)((rt / 10000000 / 60) % 60), + (BYTE)((rt / 10000000) % 60), + (BYTE)(1.0 * ((rt / 10000) % 1000) * fps / 1000) + }; + + return hmsf; +} + +DVD_HMSF_TIMECODE RT2HMS(REFERENCE_TIME rt) // used only for information (for display on the screen) +{ + rt = rt / 10000000; + DVD_HMSF_TIMECODE hmsf = { + (BYTE)(rt / 3600), + (BYTE)(rt / 60 % 60), + (BYTE)(rt % 60), + 0 + }; + + return hmsf; +} + +DVD_HMSF_TIMECODE RT2HMS_r(REFERENCE_TIME rt) // used only for information (for display on the screen) +{ + // round to nearest second + return RT2HMS(rt + 5000000); +} + +REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps /*= -1.0*/) +{ + if (fps <= 0.0) { + hmsf.bFrames = 0; + fps = 1.0; + } + return (REFERENCE_TIME)((((REFERENCE_TIME)hmsf.bHours * 60 + hmsf.bMinutes) * 60 + hmsf.bSeconds) * 1000 + 1.0 * hmsf.bFrames * 1000 / fps) * 10000; +} + +void memsetd(void* dst, unsigned int c, size_t nbytes) +{ + size_t n = nbytes / 4; + __stosd((unsigned long*)dst, c, n); +} + +void memsetw(void* dst, unsigned short c, size_t nbytes) +{ + memsetd(dst, c << 16 | c, nbytes); + + size_t n = nbytes / 2; + size_t o = (n / 2) * 2; + if ((n - o) == 1) { + ((WORD*)dst)[o] = c; + } +} + +bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih) +{ + if (pmt && bih && pmt->pbFormat) { + ZeroMemory(bih, sizeof(*bih)); + + if (pmt->formattype == FORMAT_VideoInfo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } else if (pmt->formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } else if (pmt->formattype == FORMAT_MPEGVideo) { + VIDEOINFOHEADER* vih = &((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } else if (pmt->formattype == FORMAT_MPEG2_VIDEO) { + VIDEOINFOHEADER2* vih = &((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } else if (pmt->formattype == FORMAT_DiracVideoInfo) { + VIDEOINFOHEADER2* vih = &((DIRACINFOHEADER*)pmt->pbFormat)->hdr; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } + } + + return false; +} + +bool ExtractAvgTimePerFrame(const AM_MEDIA_TYPE* pmt, REFERENCE_TIME& rtAvgTimePerFrame) +{ + if (pmt->formattype == FORMAT_VideoInfo) { + rtAvgTimePerFrame = ((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame; + } else if (pmt->formattype == FORMAT_VideoInfo2) { + rtAvgTimePerFrame = ((VIDEOINFOHEADER2*)pmt->pbFormat)->AvgTimePerFrame; + } else if (pmt->formattype == FORMAT_MPEGVideo) { + rtAvgTimePerFrame = ((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr.AvgTimePerFrame; + } else if (pmt->formattype == FORMAT_MPEG2Video) { + rtAvgTimePerFrame = ((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.AvgTimePerFrame; + } else { + return false; + } + + return true; +} + +bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih) +{ + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pMS->GetMediaType(&pmt)) && pmt) { + bool fRet = ExtractBIH(pmt, bih); + DeleteMediaType(pmt); + return fRet; + } + + return false; +} + +bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary) +{ + w = h = arx = ary = 0; + + if (pmt->formattype == FORMAT_VideoInfo || pmt->formattype == FORMAT_MPEGVideo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; + w = vih->bmiHeader.biWidth; + h = abs(vih->bmiHeader.biHeight); + arx = w * vih->bmiHeader.biYPelsPerMeter; + ary = h * vih->bmiHeader.biXPelsPerMeter; + } else if (pmt->formattype == FORMAT_VideoInfo2 || pmt->formattype == FORMAT_MPEG2_VIDEO || pmt->formattype == FORMAT_DiracVideoInfo) { + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; + w = vih->bmiHeader.biWidth; + h = abs(vih->bmiHeader.biHeight); + arx = vih->dwPictAspectRatioX; + ary = vih->dwPictAspectRatioY; + } else { + return false; + } + + if (!arx || !ary) { + BYTE* ptr = nullptr; + DWORD len = 0; + + if (pmt->formattype == FORMAT_MPEGVideo) { + ptr = ((MPEG1VIDEOINFO*)pmt->pbFormat)->bSequenceHeader; + len = ((MPEG1VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; + + if (ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { + w = (ptr[4] << 4) | (ptr[5] >> 4); + h = ((ptr[5] & 0xf) << 8) | ptr[6]; + float ar[] = { + 1.0000f, 1.0000f, 0.6735f, 0.7031f, + 0.7615f, 0.8055f, 0.8437f, 0.8935f, + 0.9157f, 0.9815f, 1.0255f, 1.0695f, + 1.0950f, 1.1575f, 1.2015f, 1.0000f, + }; + arx = (int)((float)w / ar[ptr[7] >> 4] + 0.5); + ary = h; + } + } else if (pmt->formattype == FORMAT_MPEG2_VIDEO) { + ptr = (BYTE*)((MPEG2VIDEOINFO*)pmt->pbFormat)->dwSequenceHeader; + len = ((MPEG2VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; + + if (ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { + w = (ptr[4] << 4) | (ptr[5] >> 4); + h = ((ptr[5] & 0xf) << 8) | ptr[6]; + struct { + int x, y; + } ar[] = {{w, h}, {4, 3}, {16, 9}, {221, 100}, {w, h}}; + int i = std::min(std::max(ptr[7] >> 4, 1), 5) - 1; + arx = ar[i].x; + ary = ar[i].y; + } + } + } + + if (!arx || !ary) { + arx = w; + ary = h; + } + + DWORD a = arx, b = ary; + while (a) { + int tmp = a; + a = b % tmp; + b = tmp; + } + if (b) { + arx /= b, ary /= b; + } + + return true; +} + +bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName) +{ + if (!ppBF) { + return false; + } + + *ppBF = nullptr; + FriendlyName.Empty(); + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { + return false; + } + + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(ppBF))) || !*ppBF) { + return false; + } + + CComPtr pPB; + CComVariant var; + if (SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB))) + && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + FriendlyName = var.bstrVal; + } + + return true; +} + +IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB) +{ + do { + if (!pPin || !pMoniker || !pGB) { + break; + } + + CComPtr pPinTo; + PIN_DIRECTION dir; + if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) { + break; + } + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pPB; + if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { + break; + } + + CComVariant var; + if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + break; + } + + CComPtr pBF; + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { + break; + } + + if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { + break; + } + + BeginEnumPins(pBF, pEP, pPinTo2) { + PIN_DIRECTION dir2; + if (FAILED(pPinTo2->QueryDirection(&dir2)) || dir2 != PINDIR_INPUT) { + continue; + } + + if (SUCCEEDED(pGB->ConnectDirect(pPin, pPinTo2, nullptr))) { + return pBF; + } + } + EndEnumFilters; + + pGB->RemoveFilter(pBF); + } while (false); + + return nullptr; +} + +CStringW GetFriendlyName(CStringW displayName) +{ + CStringW friendlyName; + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK == MkParseDisplayName(pBindCtx, CComBSTR(displayName), &chEaten, &pMoniker)) { + CComPtr pPB; + CComVariant var; + if (SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB))) + && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + friendlyName = var.bstrVal; + } + } + + return friendlyName; +} + +typedef HRESULT(__stdcall* fDllCanUnloadNow)(void); + +struct ExternalObject { + CString path; + HINSTANCE hInst; + CLSID clsid; + fDllCanUnloadNow fpDllCanUnloadNow; + bool bUnloadOnNextCheck; +}; + +static CAtlList s_extObjs; +static CCritSec s_csExtObjs; + +HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv, IUnknown* aggregate) +{ + CheckPointer(ppv, E_POINTER); + + CAutoLock lock(&s_csExtObjs); + + CString fullpath = MakeFullPath(path); + + HINSTANCE hInst = nullptr; + bool fFound = false; + + POSITION pos = s_extObjs.GetHeadPosition(); + while (pos) { + ExternalObject& eo = s_extObjs.GetNext(pos); + if (!eo.path.CompareNoCase(fullpath)) { + hInst = eo.hInst; + fFound = true; + eo.bUnloadOnNextCheck = false; + break; + } + } + + HRESULT hr = E_FAIL; + + if (!hInst) { + hInst = LoadLibraryEx(fullpath, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); + } + if (hInst) { + typedef HRESULT(__stdcall * PDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID * ppv); + PDllGetClassObject p = (PDllGetClassObject)GetProcAddress(hInst, "DllGetClassObject"); + + if (p && (aggregate || FAILED(hr = p(clsid, iid, ppv)))) { + CComPtr pCF; + if (SUCCEEDED(hr = p(clsid, IID_PPV_ARGS(&pCF)))) { + hr = pCF->CreateInstance(aggregate, iid, ppv); + } + } + } + + if (FAILED(hr) && hInst && !fFound) { + FreeLibrary(hInst); + return hr; + } + + if (hInst && !fFound) { + ExternalObject eo; + eo.path = fullpath; + eo.hInst = hInst; + eo.clsid = clsid; + eo.fpDllCanUnloadNow = (fDllCanUnloadNow)GetProcAddress(hInst, "DllCanUnloadNow"); + eo.bUnloadOnNextCheck = false; + s_extObjs.AddTail(eo); + } + + return hr; +} + +HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF) +{ + return LoadExternalObject(path, clsid, IID_PPV_ARGS(ppBF)); +} + +HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP) +{ + CAutoLock lock(&s_csExtObjs); + + CLSID clsid2 = GUID_NULL; + if (FAILED(pP->GetClassID(&clsid2))) { + return E_FAIL; + } + + POSITION pos = s_extObjs.GetHeadPosition(); + while (pos) { + ExternalObject& eo = s_extObjs.GetNext(pos); + if (eo.clsid == clsid2) { + return LoadExternalObject(eo.path, clsid, IID_PPV_ARGS(ppPP)); + } + } + + return E_FAIL; +} + +bool UnloadUnusedExternalObjects() +{ + CAutoLock lock(&s_csExtObjs); + + POSITION pos = s_extObjs.GetHeadPosition(), currentPos; + while (pos) { + currentPos = pos; + ExternalObject& eo = s_extObjs.GetNext(pos); + + if (eo.fpDllCanUnloadNow && eo.fpDllCanUnloadNow() == S_OK) { + // Before actually unloading it, we require that the library reports + // that it can be unloaded safely twice in a row with a 60s delay + // between the two checks. + if (eo.bUnloadOnNextCheck) { + FreeLibrary(eo.hInst); + s_extObjs.RemoveAt(currentPos); + } else { + eo.bUnloadOnNextCheck = true; + } + } else { + eo.bUnloadOnNextCheck = false; + } + } + + return s_extObjs.IsEmpty(); +} + +void ExtendMaxPathLengthIfNeeded(CString& path, bool no_url /*= false */) +{ + if (path.GetLength() >= MAX_PATH) { + if (no_url || path.Find(_T("://")) < 0) { // not URL + if (path.Left(4) != _T("\\\\?\\")) { // not already have long path prefix + if (path.Left(2) == _T("\\\\")) { // UNC + path = _T("\\\\?\\UNC") + path.Mid(1); + } else { // normal + path = _T("\\\\?\\") + path; + } + } + } + } +} + +bool ContainsWildcard(CString& path) +{ + int p = path.Find('*'); + if (p >= 0) { + return true; + } + p = path.Find('?'); + if (p >= 0) { + if (p == 2 && path.Left(4) == _T("\\\\?\\")) { + CString tmp = CString(path); + tmp.Delete(0, 3); + return tmp.Find('?') > 0; + } + return true; + } + return false; +} + +void ShortenLongPath(CString& path) +{ + if (path.GetLength() > MAX_PATH && path.Find(_T("\\\\?\\")) < 0) { + CString longpath = _T("\\\\?\\") + path; + TCHAR* buffer = DEBUG_NEW TCHAR[MAX_PATH]; + long length = GetShortPathName(longpath, buffer, MAX_PATH); + if (length > 0 && length < MAX_PATH) { + path = buffer; + path.Replace(_T("\\\\?\\"), _T("")); + delete[] buffer; + } + } +} + +CString MakeFullPath(LPCTSTR path) +{ + CString full(path); + full.Replace('/', '\\'); + + if (full.GetLength() > MAX_PATH) { + return full; + } + + if (full.GetLength() >= 2 && full[0] == '\\') { + if (full[1] != '\\') { + CString fn; + fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); + CPath p(fn); + p.StripToRoot(); + full = CString(p) + full.Mid(1); + } + } else if (full.Find(_T(":\\")) < 0) { + CString fn; + fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); + CPath p(fn); + p.RemoveFileSpec(); + p.AddBackslash(); + full = CString(p) + full; + } + + CPath c(full); + c.Canonicalize(); + return CString(c); +} + +inline bool _IsFourCC(const GUID& guid) +{ + // XXXXXXXX-0000-0010-8000-00AA00389B71 + return (guid.Data2 == 0x0000) && (guid.Data3 == 0x0010) && + (((DWORD*)guid.Data4)[0] == 0xAA000080) && + (((DWORD*)guid.Data4)[1] == 0x719b3800); +} + +bool GetMediaTypeFourCC(const GUID& guid, CString& fourCC) +{ + if (_IsFourCC(guid) && (guid.Data1 >= 0x10000)) { + fourCC.Format(_T("%c%c%c%c"), + (TCHAR)(guid.Data1 >> 0 ) & 0xFF, (TCHAR)(guid.Data1 >> 8 ) & 0xFF, + (TCHAR)(guid.Data1 >> 16) & 0xFF, (TCHAR)(guid.Data1 >> 24) & 0xFF); + fourCC.MakeUpper(); + return true; + } + + fourCC = _T("UNKN"); + return false; +} + +CString GetMediaTypeName(const GUID& guid) +{ + CString ret = guid == GUID_NULL + ? CString(_T("Any type")) + : CString(GuidNames[guid]); + + if (ret == _T("FOURCC GUID")) { + CString str; + if (guid.Data1 >= 0x10000) { + str.Format(_T("Video: %c%c%c%c"), (guid.Data1 >> 0) & 0xff, (guid.Data1 >> 8) & 0xff, (guid.Data1 >> 16) & 0xff, (guid.Data1 >> 24) & 0xff); + } else { + str.Format(_T("Audio: 0x%08x"), guid.Data1); + } + ret = str; + } else if (ret == _T("Unknown GUID Name")) { + WCHAR null[128] = {0}, buff[128]; + StringFromGUID2(GUID_NULL, null, _countof(null) - 1); + ret = CString(CStringW(StringFromGUID2(guid, buff, _countof(buff) - 1) ? buff : null)); + } + + return ret; +} + +GUID GUIDFromCString(CString str) +{ + GUID guid = GUID_NULL; + HRESULT hr = CLSIDFromString(CComBSTR(str), &guid); + ASSERT(SUCCEEDED(hr)); + UNREFERENCED_PARAMETER(hr); + return guid; +} + +HRESULT GUIDFromCString(CString str, GUID& guid) +{ + guid = GUID_NULL; + return CLSIDFromString(CComBSTR(str), &guid); +} + +CString CStringFromGUID(const GUID& guid) +{ + WCHAR null[128] = {0}, buff[128]; + StringFromGUID2(GUID_NULL, null, _countof(null) - 1); + return CString(StringFromGUID2(guid, buff, _countof(buff) - 1) > 0 ? buff : null); +} + +CStringW UTF8To16(LPCSTR utf8) +{ + CStringW str; + int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0) - 1; + if (n <= 0) { + return str; + } + str.ReleaseBuffer(MultiByteToWideChar(CP_UTF8, 0, utf8, -1, str.GetBuffer(n), n + 1) - 1); + return str; +} + +CStringA UTF16To8(LPCWSTR utf16) +{ + CStringA str; + int n = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, nullptr, 0, nullptr, nullptr) - 1; + if (n < 0) { + return str; + } + str.ReleaseBuffer(WideCharToMultiByte(CP_UTF8, 0, utf16, -1, str.GetBuffer(n), n + 1, nullptr, nullptr) - 1); + return str; +} + +CStringW UTF8ToStringW(const char* S) +{ + CStringW str; + if (S == nullptr) { + return str; + } + + // Don't use MultiByteToWideChar(), some characters are not well decoded + const unsigned char* Z = (const unsigned char*)S; + while (*Z) { //0 is end + //1 byte + if (*Z < 0x80) { + str += (wchar_t)(*Z); + Z++; + } + //2 bytes + else if ((*Z & 0xE0) == 0xC0) { + if ((*(Z + 1) & 0xC0) == 0x80) { + str += (wchar_t)((((wchar_t)(*Z & 0x1F)) << 6) | (*(Z + 1) & 0x3F)); + Z += 2; + } else { + str.Empty(); + return str; //Bad character + } + } + //3 bytes + else if ((*Z & 0xF0) == 0xE0) { + if ((*(Z + 1) & 0xC0) == 0x80 && (*(Z + 2) & 0xC0) == 0x80) { + str += (wchar_t)((((wchar_t)(*Z & 0x0F)) << 12) | ((*(Z + 1) & 0x3F) << 6) | (*(Z + 2) & 0x3F)); + Z += 3; + } else { + str.Empty(); + return str; //Bad character + } + } + //4 bytes + else if ((*Z & 0xF8) == 0xF0) { + if ((*(Z + 1) & 0xC0) == 0x80 && (*(Z + 2) & 0xC0) == 0x80 && (*(Z + 3) & 0xC0) == 0x80) { + str += (wchar_t)((((wchar_t)(*Z & 0x0F)) << 18) | ((*(Z + 1) & 0x3F) << 12) || ((*(Z + 2) & 0x3F) << 6) | (*(Z + 3) & 0x3F)); + Z += 4; + } else { + str.Empty(); + return str; //Bad character + } + } else { + str.Empty(); + return str; //Bad character + } + } + return str; +} + +CStringW LocalToStringW(const char* S) +{ + CStringW str; + if (S == nullptr) { + return str; + } + + int Size = MultiByteToWideChar(CP_ACP, 0, S, -1, nullptr, 0); + if (Size != 0) { + str.ReleaseBuffer(MultiByteToWideChar(CP_ACP, 0, S, -1, str.GetBuffer(Size), Size + 1) - 1); + } + return str; +} + +BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status) +{ + try { + return CFile::GetStatus(lpszFileName, status); + } catch (CException* e) { + // MFCBUG: E_INVALIDARG / "Parameter is incorrect" is thrown for certain cds (vs2003) + // http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8&threadm=OZuXYRzWDHA.536%40TK2MSFTNGP10.phx.gbl&rnum=1&prev=/groups%3Fhl%3Den%26lr%3D%26ie%3DISO-8859-1 + TRACE(_T("CFile::GetStatus has thrown an exception\n")); + e->Delete(); + return false; + } +} + +// filter registration helpers + +bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey) +{ + bool bOK = false; + + HKEY hKey; + LONG ec = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, pszKey, 0, KEY_ALL_ACCESS, &hKey); + if (ec == ERROR_SUCCESS) { + if (pszSubkey != 0) { + ec = ::RegDeleteKey(hKey, pszSubkey); + } + + bOK = (ec == ERROR_SUCCESS); + + ::RegCloseKey(hKey); + } + + return bOK; +} + +bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue) +{ + bool bOK = false; + + CString szKey(pszKey); + if (pszSubkey != 0) { + szKey += CString(_T("\\")) + pszSubkey; + } + + HKEY hKey; + LONG ec = ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); + if (ec == ERROR_SUCCESS) { + if (pszValue != 0) { + ec = ::RegSetValueEx(hKey, pszValueName, 0, REG_SZ, + reinterpret_cast(const_cast(pszValue)), + (DWORD)(_tcslen(pszValue) + 1) * sizeof(TCHAR)); + } + + bOK = (ec == ERROR_SUCCESS); + + ::RegCloseKey(hKey); + } + + return bOK; +} + +bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue) +{ + return SetRegKeyValue(pszKey, pszSubkey, 0, pszValue); +} + +void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext, ...) +{ + CString null = CStringFromGUID(GUID_NULL); + CString majortype = CStringFromGUID(MEDIATYPE_Stream); + CString subtype = CStringFromGUID(subtype2); + + SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("0"), chkbytes); + SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); + + DeleteRegKey(_T("Media Type\\") + null, subtype); + + va_list marker; + va_start(marker, ext); + for (; ext; ext = va_arg(marker, LPCTSTR)) { + DeleteRegKey(_T("Media Type\\Extensions"), ext); + } + va_end(marker); +} + +void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext, ...) +{ + CString null = CStringFromGUID(GUID_NULL); + CString majortype = CStringFromGUID(MEDIATYPE_Stream); + CString subtype = CStringFromGUID(subtype2); + + POSITION pos = chkbytes.GetHeadPosition(); + for (ptrdiff_t i = 0; pos; i++) { + CString idx; + idx.Format(_T("%Id"), i); + SetRegKeyValue(_T("Media Type\\") + majortype, subtype, idx, chkbytes.GetNext(pos)); + } + + SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); + + DeleteRegKey(_T("Media Type\\") + null, subtype); + + va_list marker; + va_start(marker, ext); + for (; ext; ext = va_arg(marker, LPCTSTR)) { + DeleteRegKey(_T("Media Type\\Extensions"), ext); + } + va_end(marker); +} + +void UnRegisterSourceFilter(const GUID& subtype) +{ + DeleteRegKey(_T("Media Type\\") + CStringFromGUID(MEDIATYPE_Stream), CStringFromGUID(subtype)); +} + +struct DXVA2_DECODER { + const GUID* Guid; + LPCTSTR Description; +}; + +static const DXVA2_DECODER DXVA2Decoder[] = { + {&GUID_NULL, _T("Unknown")}, + {&GUID_NULL, _T("Not using DXVA")}, + {&DXVA_Intel_H264_ClearVideo, _T("H.264 bitstream decoder, ClearVideo(tm)")}, // Intel ClearVideo H264 bitstream decoder + {&DXVA_Intel_VC1_ClearVideo, _T("VC-1 bitstream decoder, ClearVideo(tm)")}, // Intel ClearVideo VC-1 bitstream decoder + {&DXVA_Intel_VC1_ClearVideo_2, _T("VC-1 bitstream decoder 2, ClearVideo(tm)")}, // Intel ClearVideo VC-1 bitstream decoder 2 + {&DXVA_MPEG4_ASP, _T("MPEG-4 ASP bitstream decoder")}, // NVIDIA MPEG-4 ASP bitstream decoder + {&DXVA_ModeNone, _T("Mode none")}, + {&DXVA_ModeH261_A, _T("H.261 A, post processing")}, + {&DXVA_ModeH261_B, _T("H.261 B, deblocking")}, + {&DXVA_ModeH263_A, _T("H.263 A, motion compensation, no FGT")}, + {&DXVA_ModeH263_B, _T("H.263 B, motion compensation, FGT")}, + {&DXVA_ModeH263_C, _T("H.263 C, IDCT, no FGT")}, + {&DXVA_ModeH263_D, _T("H.263 D, IDCT, FGT")}, + {&DXVA_ModeH263_E, _T("H.263 E, bitstream decoder, no FGT")}, + {&DXVA_ModeH263_F, _T("H.263 F, bitstream decoder, FGT")}, + {&DXVA_ModeMPEG1_A, _T("MPEG-1 A, post processing")}, + {&DXVA_ModeMPEG2_A, _T("MPEG-2 A, motion compensation")}, + {&DXVA_ModeMPEG2_B, _T("MPEG-2 B, motion compensation + blending")}, + {&DXVA_ModeMPEG2_C, _T("MPEG-2 C, IDCT")}, + {&DXVA_ModeMPEG2_D, _T("MPEG-2 D, IDCT + blending")}, + {&DXVA_ModeH264_A, _T("H.264 A, motion compensation, no FGT")}, + {&DXVA_ModeH264_B, _T("H.264 B, motion compensation, FGT")}, + {&DXVA_ModeH264_C, _T("H.264 C, IDCT, no FGT")}, + {&DXVA_ModeH264_D, _T("H.264 D, IDCT, FGT")}, + {&DXVA_ModeH264_E, _T("H.264 E, bitstream decoder, no FGT")}, + {&DXVA_ModeH264_F, _T("H.264 F, bitstream decoder, FGT")}, + {&DXVA_ModeWMV8_A, _T("WMV8 A, post processing")}, + {&DXVA_ModeWMV8_B, _T("WMV8 B, motion compensation")}, + {&DXVA_ModeWMV9_A, _T("WMV9 A, post processing")}, + {&DXVA_ModeWMV9_B, _T("WMV9 B, motion compensation")}, + {&DXVA_ModeWMV9_C, _T("WMV9 C, IDCT")}, + {&DXVA_ModeVC1_A, _T("VC-1 A, post processing")}, + {&DXVA_ModeVC1_B, _T("VC-1 B, motion compensation")}, + {&DXVA_ModeVC1_C, _T("VC-1 C, IDCT")}, + {&DXVA_ModeVC1_D, _T("VC-1 D, bitstream decoder")}, + {&DXVA_NoEncrypt, _T("No encryption")}, + {&DXVA2_ModeMPEG2_MoComp, _T("MPEG-2 motion compensation")}, + {&DXVA2_ModeMPEG2_IDCT, _T("MPEG-2 IDCT")}, + {&DXVA2_ModeMPEG2_VLD, _T("MPEG-2 variable-length decoder")}, + {&DXVA2_ModeH264_A, _T("H.264 A, motion compensation, no FGT")}, + {&DXVA2_ModeH264_B, _T("H.264 B, motion compensation, FGT")}, + {&DXVA2_ModeH264_C, _T("H.264 C, IDCT, no FGT")}, + {&DXVA2_ModeH264_D, _T("H.264 D, IDCT, FGT")}, + {&DXVA2_ModeH264_E, _T("H.264 E, bitstream decoder, no FGT")}, + {&DXVA2_ModeH264_F, _T("H.264 F, bitstream decoder, FGT")}, + {&DXVA2_ModeWMV8_A, _T("WMV8 A, post processing")}, + {&DXVA2_ModeWMV8_B, _T("WMV8 B, motion compensation")}, + {&DXVA2_ModeWMV9_A, _T("WMV9 A, post processing")}, + {&DXVA2_ModeWMV9_B, _T("WMV9 B, motion compensation")}, + {&DXVA2_ModeWMV9_C, _T("WMV9 C, IDCT")}, + {&DXVA2_ModeVC1_A, _T("VC-1 A, post processing")}, + {&DXVA2_ModeVC1_B, _T("VC-1 B, motion compensation")}, + {&DXVA2_ModeVC1_C, _T("VC-1 C, IDCT")}, + {&DXVA2_ModeVC1_D, _T("VC-1 D, bitstream decoder")}, + {&DXVA2_NoEncrypt, _T("No encryption")}, + {&DXVA2_VideoProcProgressiveDevice, _T("Progressive scan")}, + {&DXVA2_VideoProcBobDevice, _T("Bob deinterlacing")}, + {&DXVA2_VideoProcSoftwareDevice, _T("Software processing")} +}; + +LPCTSTR GetDXVAMode(const GUID* guidDecoder) +{ + int nPos = 0; + + for (int i = 1; i < _countof(DXVA2Decoder); i++) { + if (*guidDecoder == *DXVA2Decoder[i].Guid) { + nPos = i; + break; + } + } + + return DXVA2Decoder[nPos].Description; +} + +// hour, minute, second, millisec +CString ReftimeToString(const REFERENCE_TIME& rtVal) +{ + if (rtVal == _I64_MIN) { + return _T("INVALID TIME"); + } + + CString strTemp; + LONGLONG llTotalMs = ConvertToMilliseconds(rtVal); + int lHour = (int)(llTotalMs / (1000 * 60 * 60)); + int lMinute = (llTotalMs / (1000 * 60)) % 60; + int lSecond = (llTotalMs / 1000) % 60; + int lMillisec = llTotalMs % 1000; + + strTemp.Format(_T("%02d:%02d:%02d,%03d"), lHour, lMinute, lSecond, lMillisec); + return strTemp; +} + +// hour, minute, second (round) +CString ReftimeToString2(const REFERENCE_TIME& rtVal) +{ + CString strTemp; + LONGLONG seconds = (rtVal + 5000000) / 10000000; + int lHour = (int)(seconds / 3600); + int lMinute = (int)(seconds / 60 % 60); + int lSecond = (int)(seconds % 60); + + strTemp.Format(_T("%02d:%02d:%02d"), lHour, lMinute, lSecond); + return strTemp; +} + +// minute, second (round) +CString ReftimeToString3(const REFERENCE_TIME& rtVal) +{ + CString strTemp; + LONGLONG seconds = (rtVal + 5000000) / 10000000; + int lMinute = (int)(seconds / 60 % 60); + int lSecond = (int)(seconds % 60); + + ASSERT((int)(seconds / 3600) == 0); + + strTemp.Format(_T("%02d:%02d"), lMinute, lSecond); + return strTemp; +} + +//for compatibility with mpc-be ReftimeToString2, which has option to exclude hours +CStringW ReftimeToString4(REFERENCE_TIME rt, bool showZeroHours /* = true*/) +{ + if (rt == INT64_MIN) { + return L"INVALID TIME"; + } + + DVD_HMSF_TIMECODE tc = RT2HMSF(rt); + + return DVDtimeToString(tc, showZeroHours); +} + +CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours) +{ + CString strTemp; + if (rtVal.bHours > 0 || bAlwaysShowHours) { + strTemp.Format(_T("%02u:%02u:%02u"), rtVal.bHours, rtVal.bMinutes, rtVal.bSeconds); + } else { + strTemp.Format(_T("%02u:%02u"), rtVal.bMinutes, rtVal.bSeconds); + } + return strTemp; +} + +REFERENCE_TIME StringToReftime(LPCTSTR strVal) +{ + REFERENCE_TIME rt = 0; + int lHour = 0; + int lMinute = 0; + int lSecond = 0; + int lMillisec = 0; + + if (_stscanf_s(strVal, _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { + rt = ((((lHour * 60) + lMinute) * 60 + lSecond) * MILLISECONDS + lMillisec) * (UNITS / MILLISECONDS); + } + + return rt; +} + +const wchar_t* StreamTypeToName(PES_STREAM_TYPE _Type) +{ + switch (_Type) { + case VIDEO_STREAM_MPEG1: + return L"MPEG-1"; + case VIDEO_STREAM_MPEG2: + return L"MPEG-2"; + case AUDIO_STREAM_MPEG1: + return L"MPEG-1"; + case AUDIO_STREAM_MPEG2: + return L"MPEG-2"; + case VIDEO_STREAM_H264: + return L"H264"; + case VIDEO_STREAM_HEVC: + return L"HEVC"; + case AUDIO_STREAM_LPCM: + return L"LPCM"; + case AUDIO_STREAM_AC3: + return L"Dolby Digital"; + case AUDIO_STREAM_DTS: + return L"DTS"; + case AUDIO_STREAM_AC3_TRUE_HD: + return L"Dolby TrueHD"; + case AUDIO_STREAM_AC3_PLUS: + return L"Dolby Digital Plus"; + case AUDIO_STREAM_DTS_HD: + return L"DTS-HD High Resolution Audio"; + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + return L"DTS-HD Master Audio"; + case PRESENTATION_GRAPHICS_STREAM: + return L"Presentation Graphics Stream"; + case INTERACTIVE_GRAPHICS_STREAM: + return L"Interactive Graphics Stream"; + case SUBTITLE_STREAM: + return L"Subtitle"; + case SECONDARY_AUDIO_AC3_PLUS: + return L"Secondary Dolby Digital Plus"; + case SECONDARY_AUDIO_DTS_HD: + return L"Secondary DTS-HD High Resolution Audio"; + case VIDEO_STREAM_VC1: + return L"VC-1"; + } + return nullptr; +} + +// +// Usage: SetThreadName (-1, "MainThread"); +// Code from http://msdn.microsoft.com/en-us/library/xcb2z8hs%28v=vs.110%29.aspx +// + +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1 caller thread) + DWORD dwFlags; // reserved for future use, must be zero +} THREADNAME_INFO; +#pragma pack(pop) + +void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } +} + +void CorrectComboBoxHeaderWidth(CWnd* pComboBox) +{ + if (!pComboBox) { + return; + } + + CDC* pDC = pComboBox->GetDC(); + CFont* pFont = pComboBox->GetFont(); + CFont* pOldFont = pDC->SelectObject(pFont); + + CString str; + pComboBox->GetWindowText(str); + CSize szText = pDC->GetTextExtent(str); + + TEXTMETRIC tm; + pDC->GetTextMetrics(&tm); + pDC->SelectObject(pOldFont); + pComboBox->ReleaseDC(pDC); + + CRect r; + pComboBox->GetWindowRect(r); + pComboBox->GetOwner()->ScreenToClient(r); + + r.right = r.left + ::GetSystemMetrics(SM_CXMENUCHECK) + ::GetSystemMetrics(SM_CXEDGE) + szText.cx + tm.tmAveCharWidth; + pComboBox->MoveWindow(r); +} + +CString NormalizeUnicodeStrForSearch(CString srcStr, LANGID langid) { + if (srcStr.IsEmpty()) return srcStr; + wchar_t* src; + + _locale_t locale; + LCID lcid = MAKELCID(MAKELANGID(langid, SUBLANG_DEFAULT), SORT_DEFAULT); + wchar_t localeName[32]; + if (0 == LCIDToLocaleName(lcid, localeName, 32, LOCALE_ALLOW_NEUTRAL_NAMES)) { //try to lowercase by locale, but if not, do a regular MakeLower() + srcStr.MakeLower(); + src = srcStr.GetBuffer(); + } else { + src = srcStr.GetBuffer(); + locale = _wcreate_locale(LC_ALL, localeName); + _wcslwr_s_l(src, wcslen(src) + 1, locale); + } + + int dstLen = int(wcslen(src) * 4); + wchar_t* dest = DEBUG_NEW wchar_t[dstLen]; + + int cchActual = NormalizeString(NormalizationKD, src, -1, dest, dstLen); + if (cchActual <= 0) dest[0] = 0; + WORD* rgType = DEBUG_NEW WORD[dstLen]; + GetStringTypeW(CT_CTYPE3, dest, -1, rgType); + PWSTR pszWrite = dest; + for (int i = 0; dest[i]; i++) { + if (!(rgType[i] & C3_NONSPACING)) { + *pszWrite++ = dest[i]; + } + } + *pszWrite = 0; + delete[] rgType; + + CString ret = dest; + delete[] dest; + return ret; +} + +inline const LONGLONG GetPerfCounter() { + auto GetPerfFrequency = [] { + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return freq.QuadPart; + }; + static const LONGLONG llPerfFrequency = GetPerfFrequency(); + if (llPerfFrequency) { + LARGE_INTEGER llPerfCounter; + QueryPerformanceCounter(&llPerfCounter); + return llMulDiv(llPerfCounter.QuadPart, 10000000LL, llPerfFrequency, 0); + } else { + // ms to 100ns units + return timeGetTime() * 10000; + } +} + +bool FindStringInList(const CAtlList& list, CString& value) +{ + bool found = false; + POSITION pos = list.GetHeadPosition(); + while (pos && !found) { + if (list.GetNext(pos).CompareNoCase(value) == 0) { + found = true; + } + } + return found; +} + +CStringW ForceTrailingSlash(CStringW folder) { + if (folder.Right(1) != L'\\' && folder.GetLength() > 0) { + folder += L'\\'; + } + return folder; +} + +CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt) { + int discard; + return GetChannelStrFromMediaType(pmt, discard); +} + +CStringW ChannelsToStr(int channels) { + CStringW ret; + switch (channels) { + case 1: + return L"mono"; + case 2: + return L"2.0"; + case 6: + return L"5.1"; + case 7: + return L"6.1"; + case 8: + return L"7.1"; + default: + ret.Format(L"%uch", channels); + return ret; + } +} + +CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt, int& channels) { + if (pmt) { + if (pmt->majortype == MEDIATYPE_Audio) { + if (pmt->formattype == FORMAT_WaveFormatEx) { + channels = ((WAVEFORMATEX*)pmt->pbFormat)->nChannels; + return ChannelsToStr(channels); + } else if (pmt->formattype == FORMAT_VorbisFormat) { + channels = ((VORBISFORMAT*)pmt->pbFormat)->nChannels; + return ChannelsToStr(channels); + } else if (pmt->formattype == FORMAT_VorbisFormat2) { + channels = ((VORBISFORMAT2*)pmt->pbFormat)->Channels; + return ChannelsToStr(channels); + } else { + channels = 2; + } + } else if (pmt->majortype == MEDIATYPE_Midi) { + channels = 2; + return L""; + } + } + ASSERT(false); + return L""; +} + +CStringW GetShortAudioNameFromMediaType(AM_MEDIA_TYPE* pmt) { + if (!pmt) { + return L""; + } + if (pmt->majortype != MEDIATYPE_Audio) { + if (pmt->majortype == MEDIATYPE_Midi) { + return L"MIDI"; + } else { + return L""; + } + } + + if (pmt->subtype == MEDIASUBTYPE_AAC || pmt->subtype == MEDIASUBTYPE_LATM_AAC || pmt->subtype == MEDIASUBTYPE_AAC_ADTS || pmt->subtype == MEDIASUBTYPE_MPEG_ADTS_AAC + || pmt->subtype == MEDIASUBTYPE_MPEG_HEAAC || pmt->subtype == MEDIASUBTYPE_MP4A || pmt->subtype == MEDIASUBTYPE_mp4a) { + return L"AAC"; + } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF + || pmt->subtype == MEDIASUBTYPE_RAW_SPORT || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h || pmt->subtype == MEDIASUBTYPE_DVM) { + return L"AC3"; + } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { + return L"E-AC3"; + } else if (pmt->subtype == MEDIASUBTYPE_DTS || pmt->subtype == MEDIASUBTYPE_DTS2 || pmt->subtype == MEDIASUBTYPE_WAVE_DTS) { + return L"DTS"; + } else if (pmt->subtype == MEDIASUBTYPE_DTS_HD) { + return L"DTS-HD"; + } else if (pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { + return L"LPCM"; + } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { + return L"TrueHD"; + } else if (pmt->subtype == MEDIASUBTYPE_MLP) { + return L"MLP"; + } else if (pmt->subtype == MEDIASUBTYPE_PCM || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT) { + return L"PCM"; + } else if (pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload || pmt->subtype == MEDIASUBTYPE_MPEG1Packet || pmt->subtype == MEDIASUBTYPE_MPEG1Payload) { //are these all actually possible? + return L"MP1"; + } else if (pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO) { + return L"MP2"; + } else if (pmt->subtype == MEDIASUBTYPE_MP3) { + return L"MP3"; + } else if (pmt->subtype == MEDIASUBTYPE_FLAC || pmt->subtype == MEDIASUBTYPE_FLAC_FRAMED) { + return L"FLAC"; + } else if (pmt->subtype == MEDIASUBTYPE_Vorbis || pmt->subtype == MEDIASUBTYPE_Vorbis2) { + return L"Vorbis"; + } else if (pmt->subtype == MEDIASUBTYPE_OPUS || pmt->subtype == MEDIASUBTYPE_OPUS_OLD) { + return L"Opus"; + } else if (pmt->subtype == MEDIASUBTYPE_MSAUDIO1) { + return L"WMA1"; + } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO2) { + return L"WMA2"; + } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO3) { + return L"WMA3"; + } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO4) { + return L"WMA4"; + } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO_LOSSLESS) { + return L"WMA-LL"; + } else if (pmt->subtype == MEDIASUBTYPE_BD_LPCM_AUDIO || pmt->subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { + return L"LPCM"; + } else if (pmt->subtype == MEDIASUBTYPE_IMA_AMV || pmt->subtype == MEDIASUBTYPE_ADPCM_MS || pmt->subtype == MEDIASUBTYPE_IMA_WAV || pmt->subtype == MEDIASUBTYPE_ADPCM_SWF) { + return L"ADPCM"; + } else if (pmt->subtype == MEDIASUBTYPE_TRUESPEECH) { + return L"TrueSpeech"; + } else if (pmt->subtype == MEDIASUBTYPE_PCM_NONE || pmt->subtype == MEDIASUBTYPE_PCM_RAW || pmt->subtype == MEDIASUBTYPE_PCM_TWOS || pmt->subtype == MEDIASUBTYPE_PCM_SOWT + || pmt->subtype == MEDIASUBTYPE_PCM_IN24 || pmt->subtype == MEDIASUBTYPE_PCM_IN32 || pmt->subtype == MEDIASUBTYPE_PCM_FL32 || pmt->subtype == MEDIASUBTYPE_PCM_FL64 + || pmt->subtype == MEDIASUBTYPE_PCM_IN24_le || pmt->subtype == MEDIASUBTYPE_PCM_IN32_le || pmt->subtype == MEDIASUBTYPE_PCM_FL32_le || pmt->subtype == MEDIASUBTYPE_PCM_FL64_le) { + return L"QTPCM"; + } else if (pmt->subtype == MEDIASUBTYPE_TTA1) { + return L"TTA"; + } else if (pmt->subtype == MEDIASUBTYPE_SAMR) { + return L"SAMR"; + } else if (pmt->subtype == MEDIASUBTYPE_QDM2) { + return L"QDM2"; + } else if (pmt->subtype == MEDIASUBTYPE_MSGSM610) { + return L"GSM610"; + } else if (pmt->subtype == MEDIASUBTYPE_ALAW || pmt->subtype == MEDIASUBTYPE_MULAW) { + return L"G711"; + } else if (pmt->subtype == MEDIASUBTYPE_G723 || pmt->subtype == MEDIASUBTYPE_VIVO_G723) { + return L"G723"; + } else if (pmt->subtype == MEDIASUBTYPE_G726) { + return L"G726"; + } else if (pmt->subtype == MEDIASUBTYPE_G729 || pmt->subtype == MEDIASUBTYPE_729A) { + return L"G729"; + } else if (pmt->subtype == MEDIASUBTYPE_APE) { + return L"APE"; + } else if (pmt->subtype == MEDIASUBTYPE_TAK) { + return L"TAK"; + } else if (pmt->subtype == MEDIASUBTYPE_ALS) { + return L"ALS"; + } else if (pmt->subtype == MEDIASUBTYPE_NELLYMOSER) { + return L"NELLY"; + } else if (pmt->subtype == MEDIASUBTYPE_SPEEX) { + return L"Speex"; + } else if (pmt->subtype == MEDIASUBTYPE_AES3) { + return L"AES3"; + } else if (pmt->subtype == MEDIASUBTYPE_DSDL || pmt->subtype == MEDIASUBTYPE_DSDM || pmt->subtype == MEDIASUBTYPE_DSD1 || pmt->subtype == MEDIASUBTYPE_DSD8) { + return L"DSD"; + } else if (pmt->subtype == MEDIASUBTYPE_IMC) { + return L"IMC"; + } else if (pmt->subtype == MEDIASUBTYPE_VOXWARE_RT29) { + return L"RT29"; + } else if (pmt->subtype == MEDIASUBTYPE_MPEG_LOAS) { + return L"LOAS"; + } + + if (_IsFourCC(pmt->subtype)) { + CString fcc; + DWORD a = (pmt->subtype.Data1 >> 24) & 0xFF; + DWORD b = (pmt->subtype.Data1 >> 16) & 0xFF; + DWORD c = (pmt->subtype.Data1 >> 8) & 0xFF; + DWORD d = (pmt->subtype.Data1 >> 0) & 0xFF; + if (a != 0 || b != 0) { + fcc.Format(_T("%02x%02x%02x%02x"), a, b, c, d); + } else { + fcc.Format(_T("%02x%02x"), c, d); + } + return fcc; + } + + return L"UNKN"; +} + +bool GetVideoFormatNameFromMediaType(const GUID& guid, CString& name) { + if (GetMediaTypeFourCC(guid, name)) { + if (name == L"HVC1") { + name = L"HEVC"; + } else if (name == L"AVC1") { + name = L"H264"; + } else if (name == L"VP90") { + name = L"VP9"; + } else if (name == L"AV01") { + name = L"AV1"; + } + return true; + } else if (guid == MEDIASUBTYPE_MPEG1Payload || guid == MEDIASUBTYPE_MPEG1Video) { + name = L"MPEG1"; + return true; + } else if (guid == MEDIASUBTYPE_MPEG2_VIDEO) { + name = L"MPEG2"; + return true; + } else if (guid == MEDIASUBTYPE_ARGB32) { + name = L"ARGB"; + return true; + } else if (guid == MEDIASUBTYPE_RGB32) { + name = L"RGB"; + return true; + } else if (guid == MEDIASUBTYPE_LAV_RAWVIDEO) { + name = L"RAW"; + return true; + } else { + name = L"UNKN"; + ASSERT(false); + } + + return false; +} diff --git a/src/DSUtil/DSUtil.h b/src/DSUtil/DSUtil.h index ee7fbd8fa5e..fe20d5b0a04 100644 --- a/src/DSUtil/DSUtil.h +++ b/src/DSUtil/DSUtil.h @@ -1,356 +1,356 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "HdmvClipInfo.h" -#include "MediaTypeEx.h" -#include "text.h" -#include "vd.h" -#include "BaseClasses/streams.h" -#include -#include -#include "MFCHelper.h" -#include "Utils.h" - -#define LCID_NOSUBTITLES -1 - -#define IsWaveFormatExtensible(wfe) (wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfe->cbSize == 22) - -extern int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC); -extern bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly = false); -extern bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly = false); -extern bool IsStreamStart(IBaseFilter* pBF); -extern bool IsStreamEnd(IBaseFilter* pBF); -extern bool IsVideoRenderer(IBaseFilter* pBF); -extern bool IsAudioWaveRenderer(IBaseFilter* pBF); -extern IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin = nullptr); -extern IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin = nullptr); -extern IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir = PINDIR_INPUT); -extern IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir); -extern void NukeDownstream(IBaseFilter* pBF, IFilterGraph* pFG); -extern void NukeDownstream(IPin* pPin, IFilterGraph* pFG); -extern IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG); -extern IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG); -extern IBaseFilter* FindFirstFilter(IFilterGraph* pFG); -extern IPin* FindPin(IBaseFilter* pBF, PIN_DIRECTION direction, const AM_MEDIA_TYPE* pRequestedMT); -extern CStringW GetFilterName(IBaseFilter* pBF); -extern CStringW GetPinName(IPin* pPin); -extern IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF); -extern IBaseFilter* GetFilterFromPin(IPin* pPin); -extern IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB); -extern IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB); -extern void ExtractMediaTypes(IPin* pPin, CAtlArray& types); -extern void ExtractMediaTypes(IPin* pPin, CAtlList& mts); -extern void ShowPPage(CString DisplayName, HWND hParentWnd); -extern void ShowPPage(IUnknown* pUnknown, HWND hParentWnd); -extern CLSID GetCLSID(IBaseFilter* pBF); -extern CLSID GetCLSID(IPin* pPin); -extern CString CLSIDToString(CLSID& clsid); -extern bool IsCLSIDRegistered(LPCTSTR clsid); -extern bool IsCLSIDRegistered(const CLSID& clsid); -extern CString GetFilterPath(LPCTSTR clsid); -extern CString GetFilterPath(const CLSID& clsid); -extern void CStringToBin(CString str, CAtlArray& data); -extern CString BinToCString(const BYTE* ptr, size_t len); -extern void FindFiles(CString fn, CAtlList& files); -enum OpticalDiskType_t { - OpticalDisk_NotFound, - OpticalDisk_Audio, - OpticalDisk_VideoCD, - OpticalDisk_DVDVideo, - OpticalDisk_BD, - OpticalDisk_Unknown -}; -extern OpticalDiskType_t GetOpticalDiskType(TCHAR drive, CAtlList& files); -extern CString GetDriveLabel(TCHAR drive); -extern CString GetDriveLabel(CPath path); -bool IsDriveVirtual(CString drive); -extern bool GetKeyFrames(CString fn, CUIntArray& kfs); -extern DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps = 0.0); // used to remember the current position -extern DVD_HMSF_TIMECODE RT2HMS(REFERENCE_TIME rt); -extern DVD_HMSF_TIMECODE RT2HMS_r(REFERENCE_TIME rt); // used only to display information with rounding to nearest second -extern REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps = -1.0); -extern void memsetd(void* dst, unsigned int c, size_t nbytes); -extern void memsetw(void* dst, unsigned short c, size_t nbytes); -extern bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih); -extern bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih); -extern bool ExtractAvgTimePerFrame(const AM_MEDIA_TYPE* pmt, REFERENCE_TIME& rtAvgTimePerFrame); -extern bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary); -extern bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName); -extern IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB); -extern CStringW GetFriendlyName(CStringW DisplayName); -extern HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv, IUnknown* aggregate = nullptr); -extern HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF); -extern HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP); -extern bool UnloadUnusedExternalObjects(); -extern void ExtendMaxPathLengthIfNeeded(CString& path, bool no_url = false); -extern bool ContainsWildcard(CString& path); -extern void ShortenLongPath(CString& path); -extern CString MakeFullPath(LPCTSTR path); -extern bool GetMediaTypeFourCC(const GUID& guid, CString& fourCC); -extern CString GetMediaTypeName(const GUID& guid); -extern GUID GUIDFromCString(CString str); -extern HRESULT GUIDFromCString(CString str, GUID& guid); -extern CString CStringFromGUID(const GUID& guid); -extern CStringW UTF8To16(LPCSTR utf8); -extern CStringA UTF16To8(LPCWSTR utf16); -extern CStringW UTF8ToStringW(const char* S); -extern CStringW LocalToStringW(const char* S); -extern BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status); -extern bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey); -extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue); -extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue); -extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext = nullptr, ...); -extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext = nullptr, ...); -extern void UnRegisterSourceFilter(const GUID& subtype); -extern LPCTSTR GetDXVAMode(const GUID* guidDecoder); -extern CString ReftimeToString(const REFERENCE_TIME& rtVal); -extern CString ReftimeToString2(const REFERENCE_TIME& rtVal); -extern CString ReftimeToString3(const REFERENCE_TIME& rtVal); -extern CStringW ReftimeToString4(REFERENCE_TIME rt, bool showZeroHours = true); -extern CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours = false); -extern REFERENCE_TIME StringToReftime(LPCTSTR strVal); -extern void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName); -extern CString FindCoverArt(const CString& path, const CString& author); -extern CString NormalizeUnicodeStrForSearch(CString srcStr, LANGID langid); -extern bool FindStringInList(const CAtlList& list, CString& value); -extern CStringW ForceTrailingSlash(CStringW folder); -extern CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt); -extern CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt, int& channels); -extern CStringW GetShortAudioNameFromMediaType(AM_MEDIA_TYPE* pmt); -extern bool GetVideoFormatNameFromMediaType(const GUID& guid, CString& name); - -extern inline const LONGLONG GetPerfCounter(); - -enum FF_FIELD_TYPE { - PICT_NONE, - PICT_TOP_FIELD, - PICT_BOTTOM_FIELD, - PICT_FRAME -}; - -class CPinInfo : public PIN_INFO -{ -public: - CPinInfo() { - pFilter = nullptr; - } - ~CPinInfo() { - if (pFilter) { - pFilter->Release(); - } - } -}; - -class CFilterInfo : public FILTER_INFO -{ -public: - CFilterInfo() { - pGraph = nullptr; - } - ~CFilterInfo() { - if (pGraph) { - pGraph->Release(); - } - } -}; - -#define BeginEnumFilters(pFilterGraph, pEnumFilters, pBaseFilter) \ -{ \ - CComPtr pEnumFilters; \ - if (pFilterGraph && SUCCEEDED(pFilterGraph->EnumFilters(&pEnumFilters))) { \ - for (CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = nullptr) { - -#define EndEnumFilters }}} - -#define BeginEnumCachedFilters(pGraphConfig, pEnumFilters, pBaseFilter) \ -{ \ - CComPtr pEnumFilters; \ - if (pGraphConfig && SUCCEEDED(pGraphConfig->EnumCacheFilter(&pEnumFilters))) { \ - for (CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = nullptr) { - -#define EndEnumCachedFilters }}} - -#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \ -{ \ - CComPtr pEnumPins; \ - if (pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) { \ - for (CComPtr pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = nullptr) { - -#define EndEnumPins }}} - -#define BeginEnumMediaTypes(pPin, pEnumMediaTypes, pMediaType) \ -{ \ - CComPtr pEnumMediaTypes; \ - if (pPin && SUCCEEDED(pPin->EnumMediaTypes(&pEnumMediaTypes))) { \ - AM_MEDIA_TYPE* pMediaType = nullptr; \ - for (; S_OK == pEnumMediaTypes->Next(1, &pMediaType, nullptr); DeleteMediaType(pMediaType), pMediaType = nullptr) { - -#define EndEnumMediaTypes(pMediaType) \ - } \ - if (pMediaType) { \ - DeleteMediaType(pMediaType); \ - } \ - } \ -} - -#define BeginEnumSysDev(clsid, pMoniker) \ -{ \ - CComPtr pDevEnum4$##clsid; \ - if (SUCCEEDED(pDevEnum4$##clsid.CoCreateInstance(CLSID_SystemDeviceEnum))) { \ - CComPtr pClassEnum4$##clsid; \ - if (SUCCEEDED(pDevEnum4$##clsid->CreateClassEnumerator(clsid, &pClassEnum4$##clsid, 0)) \ - && pClassEnum4$##clsid) { \ - for (CComPtr pMoniker; pClassEnum4$##clsid->Next(1, &pMoniker, 0) == S_OK; pMoniker = nullptr) { - -#define EndEnumSysDev }}}} - -#define PauseGraph \ - CComQIPtr _pMC(m_pGraph); \ - OAFilterState _fs = -1; \ - if (_pMC) \ - _pMC->GetState(1000, &_fs); \ - if (_fs == State_Running) \ - _pMC->Pause(); \ - \ - HRESULT _hr = E_FAIL; \ - CComQIPtr _pMS((IUnknown*)(INonDelegatingUnknown*)m_pGraph); \ - REFERENCE_TIME _rtNow = 0; \ - if (_pMS) \ - _hr = _pMS->GetCurrentPosition(&_rtNow); - -#define ResumeGraph \ - if (SUCCEEDED(_hr) && _pMS && _fs != State_Stopped) \ - _hr = _pMS->SetPositions(&_rtNow, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); \ - \ - if (_fs == State_Running && _pMS) \ - _pMC->Run(); - -#define CallQueue(call) \ - if (!m_pOutputQueue) \ - return NOERROR; \ - m_pOutputQueue->##call; \ - return NOERROR; - -#define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : -#define QI2(i) (riid == IID_##i) ? GetInterface((i*)this, ppv) : - -#define SAFE_DELETE(p) { if (p) { delete (p); (p) = nullptr; } } -#define SAFE_DELETE_ARRAY(p) { if (p) { delete [] (p); (p) = nullptr; } } -#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } } -#define SAFE_CLOSE_HANDLE(p) { if (p) { if ((p) != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(p)); (p) = nullptr; } } -#define EXIT_ON_ERROR(hres) { if (FAILED(hres)) return hres; } - -#define StrRes(id) MAKEINTRESOURCE((id)) -#define ResStr(id) CString(StrRes((id))) - -#define UNREACHABLE_CODE() \ - do { \ - ASSERT(false); \ - __assume(false); \ - } while (false) - -template -static CUnknown* WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT* phr) -{ - *phr = S_OK; - CUnknown* punk = DEBUG_NEW T(lpunk, phr); - if (punk == nullptr) { - *phr = E_OUTOFMEMORY; - } - return punk; -} - -template -typename std::enable_if::value, T>::type GCD(T a, T b) -{ - static_assert(std::is_integral::value, "GCD supports integral types only"); - if (a == 0 || b == 0) { - return std::max(std::max(a, b), T(1)); - } - while (a != b) { - if (a < b) { - b -= a; - } else if (a > b) { - a -= b; - } - } - return a; -} - -template -typename std::enable_if::value, T>::type GCD(T a, T b) -{ - using uT = typename std::make_unsigned::type; - - return T(GCD(uT(std::abs(a)), uT(std::abs(b)))); -} - -template -constexpr typename std::enable_if::value, bool>::type IsEqual(T a, T b) -{ - return a == b; -} - -template -constexpr typename std::enable_if::value, bool>::type IsEqual(T a, T b) -{ - return std::abs(a - b) < std::numeric_limits::epsilon(); -} - -template -constexpr typename std::enable_if::value, bool>::type IsNearlyEqual(T a, T b, T epsilon) -{ - return std::abs(a - b) < epsilon; -} - -template -constexpr typename std::enable_if < std::is_integral::value&& std::is_unsigned::value, int >::type SGN(T n) -{ - return T(0) < n; -} - -template -constexpr typename std::enable_if < std::is_integral::value&& std::is_signed::value, int >::type SGN(T n) -{ - return (T(0) < n) - (n < T(0)); -} - -template -constexpr typename std::enable_if ::value, int>::type SGN(T n) -{ - return IsEqual(n, T(0)) ? 0 : (n > 0 ? 1 : -1); -} - -namespace CStringUtils -{ - struct IgnoreCaseLess { - bool operator()(const CString& str1, const CString& str2) const { - return str1.CompareNoCase(str2) < 0; - } - }; - struct LogicalLess { - bool operator()(const CString& str1, const CString& str2) const { - return StrCmpLogicalW(str1, str2) < 0; - } - }; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "HdmvClipInfo.h" +#include "MediaTypeEx.h" +#include "text.h" +#include "vd.h" +#include "BaseClasses/streams.h" +#include +#include +#include "MFCHelper.h" +#include "Utils.h" + +#define LCID_NOSUBTITLES -1 + +#define IsWaveFormatExtensible(wfe) (wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfe->cbSize == 22) + +extern int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC); +extern bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly = false); +extern bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly = false); +extern bool IsStreamStart(IBaseFilter* pBF); +extern bool IsStreamEnd(IBaseFilter* pBF); +extern bool IsVideoRenderer(IBaseFilter* pBF); +extern bool IsAudioWaveRenderer(IBaseFilter* pBF); +extern IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin = nullptr); +extern IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin = nullptr); +extern IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir = PINDIR_INPUT); +extern IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir); +extern void NukeDownstream(IBaseFilter* pBF, IFilterGraph* pFG); +extern void NukeDownstream(IPin* pPin, IFilterGraph* pFG); +extern IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG); +extern IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG); +extern IBaseFilter* FindFirstFilter(IFilterGraph* pFG); +extern IPin* FindPin(IBaseFilter* pBF, PIN_DIRECTION direction, const AM_MEDIA_TYPE* pRequestedMT); +extern CStringW GetFilterName(IBaseFilter* pBF); +extern CStringW GetPinName(IPin* pPin); +extern IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF); +extern IBaseFilter* GetFilterFromPin(IPin* pPin); +extern IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB); +extern IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB); +extern void ExtractMediaTypes(IPin* pPin, CAtlArray& types); +extern void ExtractMediaTypes(IPin* pPin, CAtlList& mts); +extern void ShowPPage(CString DisplayName, HWND hParentWnd); +extern void ShowPPage(IUnknown* pUnknown, HWND hParentWnd); +extern CLSID GetCLSID(IBaseFilter* pBF); +extern CLSID GetCLSID(IPin* pPin); +extern CString CLSIDToString(CLSID& clsid); +extern bool IsCLSIDRegistered(LPCTSTR clsid); +extern bool IsCLSIDRegistered(const CLSID& clsid); +extern CString GetFilterPath(LPCTSTR clsid); +extern CString GetFilterPath(const CLSID& clsid); +extern void CStringToBin(CString str, CAtlArray& data); +extern CString BinToCString(const BYTE* ptr, size_t len); +extern void FindFiles(CString fn, CAtlList& files); +enum OpticalDiskType_t { + OpticalDisk_NotFound, + OpticalDisk_Audio, + OpticalDisk_VideoCD, + OpticalDisk_DVDVideo, + OpticalDisk_BD, + OpticalDisk_Unknown +}; +extern OpticalDiskType_t GetOpticalDiskType(TCHAR drive, CAtlList& files); +extern CString GetDriveLabel(TCHAR drive); +extern CString GetDriveLabel(CPath path); +bool IsDriveVirtual(CString drive); +extern bool GetKeyFrames(CString fn, CUIntArray& kfs); +extern DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps = 0.0); // used to remember the current position +extern DVD_HMSF_TIMECODE RT2HMS(REFERENCE_TIME rt); +extern DVD_HMSF_TIMECODE RT2HMS_r(REFERENCE_TIME rt); // used only to display information with rounding to nearest second +extern REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps = -1.0); +extern void memsetd(void* dst, unsigned int c, size_t nbytes); +extern void memsetw(void* dst, unsigned short c, size_t nbytes); +extern bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih); +extern bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih); +extern bool ExtractAvgTimePerFrame(const AM_MEDIA_TYPE* pmt, REFERENCE_TIME& rtAvgTimePerFrame); +extern bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary); +extern bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName); +extern IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB); +extern CStringW GetFriendlyName(CStringW DisplayName); +extern HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv, IUnknown* aggregate = nullptr); +extern HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF); +extern HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP); +extern bool UnloadUnusedExternalObjects(); +extern void ExtendMaxPathLengthIfNeeded(CString& path, bool no_url = false); +extern bool ContainsWildcard(CString& path); +extern void ShortenLongPath(CString& path); +extern CString MakeFullPath(LPCTSTR path); +extern bool GetMediaTypeFourCC(const GUID& guid, CString& fourCC); +extern CString GetMediaTypeName(const GUID& guid); +extern GUID GUIDFromCString(CString str); +extern HRESULT GUIDFromCString(CString str, GUID& guid); +extern CString CStringFromGUID(const GUID& guid); +extern CStringW UTF8To16(LPCSTR utf8); +extern CStringA UTF16To8(LPCWSTR utf16); +extern CStringW UTF8ToStringW(const char* S); +extern CStringW LocalToStringW(const char* S); +extern BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status); +extern bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey); +extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue); +extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue); +extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext = nullptr, ...); +extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext = nullptr, ...); +extern void UnRegisterSourceFilter(const GUID& subtype); +extern LPCTSTR GetDXVAMode(const GUID* guidDecoder); +extern CString ReftimeToString(const REFERENCE_TIME& rtVal); +extern CString ReftimeToString2(const REFERENCE_TIME& rtVal); +extern CString ReftimeToString3(const REFERENCE_TIME& rtVal); +extern CStringW ReftimeToString4(REFERENCE_TIME rt, bool showZeroHours = true); +extern CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours = false); +extern REFERENCE_TIME StringToReftime(LPCTSTR strVal); +extern void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName); +extern CString FindCoverArt(const CString& path, const CString& author); +extern CString NormalizeUnicodeStrForSearch(CString srcStr, LANGID langid); +extern bool FindStringInList(const CAtlList& list, CString& value); +extern CStringW ForceTrailingSlash(CStringW folder); +extern CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt); +extern CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt, int& channels); +extern CStringW GetShortAudioNameFromMediaType(AM_MEDIA_TYPE* pmt); +extern bool GetVideoFormatNameFromMediaType(const GUID& guid, CString& name); + +extern inline const LONGLONG GetPerfCounter(); + +enum FF_FIELD_TYPE { + PICT_NONE, + PICT_TOP_FIELD, + PICT_BOTTOM_FIELD, + PICT_FRAME +}; + +class CPinInfo : public PIN_INFO +{ +public: + CPinInfo() { + pFilter = nullptr; + } + ~CPinInfo() { + if (pFilter) { + pFilter->Release(); + } + } +}; + +class CFilterInfo : public FILTER_INFO +{ +public: + CFilterInfo() { + pGraph = nullptr; + } + ~CFilterInfo() { + if (pGraph) { + pGraph->Release(); + } + } +}; + +#define BeginEnumFilters(pFilterGraph, pEnumFilters, pBaseFilter) \ +{ \ + CComPtr pEnumFilters; \ + if (pFilterGraph && SUCCEEDED(pFilterGraph->EnumFilters(&pEnumFilters))) { \ + for (CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = nullptr) { + +#define EndEnumFilters }}} + +#define BeginEnumCachedFilters(pGraphConfig, pEnumFilters, pBaseFilter) \ +{ \ + CComPtr pEnumFilters; \ + if (pGraphConfig && SUCCEEDED(pGraphConfig->EnumCacheFilter(&pEnumFilters))) { \ + for (CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = nullptr) { + +#define EndEnumCachedFilters }}} + +#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \ +{ \ + CComPtr pEnumPins; \ + if (pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) { \ + for (CComPtr pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = nullptr) { + +#define EndEnumPins }}} + +#define BeginEnumMediaTypes(pPin, pEnumMediaTypes, pMediaType) \ +{ \ + CComPtr pEnumMediaTypes; \ + if (pPin && SUCCEEDED(pPin->EnumMediaTypes(&pEnumMediaTypes))) { \ + AM_MEDIA_TYPE* pMediaType = nullptr; \ + for (; S_OK == pEnumMediaTypes->Next(1, &pMediaType, nullptr); DeleteMediaType(pMediaType), pMediaType = nullptr) { + +#define EndEnumMediaTypes(pMediaType) \ + } \ + if (pMediaType) { \ + DeleteMediaType(pMediaType); \ + } \ + } \ +} + +#define BeginEnumSysDev(clsid, pMoniker) \ +{ \ + CComPtr pDevEnum4$##clsid; \ + if (SUCCEEDED(pDevEnum4$##clsid.CoCreateInstance(CLSID_SystemDeviceEnum))) { \ + CComPtr pClassEnum4$##clsid; \ + if (SUCCEEDED(pDevEnum4$##clsid->CreateClassEnumerator(clsid, &pClassEnum4$##clsid, 0)) \ + && pClassEnum4$##clsid) { \ + for (CComPtr pMoniker; pClassEnum4$##clsid->Next(1, &pMoniker, 0) == S_OK; pMoniker = nullptr) { + +#define EndEnumSysDev }}}} + +#define PauseGraph \ + CComQIPtr _pMC(m_pGraph); \ + OAFilterState _fs = -1; \ + if (_pMC) \ + _pMC->GetState(1000, &_fs); \ + if (_fs == State_Running) \ + _pMC->Pause(); \ + \ + HRESULT _hr = E_FAIL; \ + CComQIPtr _pMS((IUnknown*)(INonDelegatingUnknown*)m_pGraph); \ + REFERENCE_TIME _rtNow = 0; \ + if (_pMS) \ + _hr = _pMS->GetCurrentPosition(&_rtNow); + +#define ResumeGraph \ + if (SUCCEEDED(_hr) && _pMS && _fs != State_Stopped) \ + _hr = _pMS->SetPositions(&_rtNow, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); \ + \ + if (_fs == State_Running && _pMS) \ + _pMC->Run(); + +#define CallQueue(call) \ + if (!m_pOutputQueue) \ + return NOERROR; \ + m_pOutputQueue->##call; \ + return NOERROR; + +#define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : +#define QI2(i) (riid == IID_##i) ? GetInterface((i*)this, ppv) : + +#define SAFE_DELETE(p) { if (p) { delete (p); (p) = nullptr; } } +#define SAFE_DELETE_ARRAY(p) { if (p) { delete [] (p); (p) = nullptr; } } +#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } } +#define SAFE_CLOSE_HANDLE(p) { if (p) { if ((p) != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(p)); (p) = nullptr; } } +#define EXIT_ON_ERROR(hres) { if (FAILED(hres)) return hres; } + +#define StrRes(id) MAKEINTRESOURCE((id)) +#define ResStr(id) CString(StrRes((id))) + +#define UNREACHABLE_CODE() \ + do { \ + ASSERT(false); \ + __assume(false); \ + } while (false) + +template +static CUnknown* WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT* phr) +{ + *phr = S_OK; + CUnknown* punk = DEBUG_NEW T(lpunk, phr); + if (punk == nullptr) { + *phr = E_OUTOFMEMORY; + } + return punk; +} + +template +typename std::enable_if::value, T>::type GCD(T a, T b) +{ + static_assert(std::is_integral::value, "GCD supports integral types only"); + if (a == 0 || b == 0) { + return std::max(std::max(a, b), T(1)); + } + while (a != b) { + if (a < b) { + b -= a; + } else if (a > b) { + a -= b; + } + } + return a; +} + +template +typename std::enable_if::value, T>::type GCD(T a, T b) +{ + using uT = typename std::make_unsigned::type; + + return T(GCD(uT(std::abs(a)), uT(std::abs(b)))); +} + +template +constexpr typename std::enable_if::value, bool>::type IsEqual(T a, T b) +{ + return a == b; +} + +template +constexpr typename std::enable_if::value, bool>::type IsEqual(T a, T b) +{ + return std::abs(a - b) < std::numeric_limits::epsilon(); +} + +template +constexpr typename std::enable_if::value, bool>::type IsNearlyEqual(T a, T b, T epsilon) +{ + return std::abs(a - b) < epsilon; +} + +template +constexpr typename std::enable_if < std::is_integral::value&& std::is_unsigned::value, int >::type SGN(T n) +{ + return T(0) < n; +} + +template +constexpr typename std::enable_if < std::is_integral::value&& std::is_signed::value, int >::type SGN(T n) +{ + return (T(0) < n) - (n < T(0)); +} + +template +constexpr typename std::enable_if ::value, int>::type SGN(T n) +{ + return IsEqual(n, T(0)) ? 0 : (n > 0 ? 1 : -1); +} + +namespace CStringUtils +{ + struct IgnoreCaseLess { + bool operator()(const CString& str1, const CString& str2) const { + return str1.CompareNoCase(str2) < 0; + } + }; + struct LogicalLess { + bool operator()(const CString& str1, const CString& str2) const { + return StrCmpLogicalW(str1, str2) < 0; + } + }; +} diff --git a/src/DSUtil/DSUtil.vcxproj b/src/DSUtil/DSUtil.vcxproj index 3644ec33a01..02d8b530914 100644 --- a/src/DSUtil/DSUtil.vcxproj +++ b/src/DSUtil/DSUtil.vcxproj @@ -1,121 +1,121 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {FC70988B-1AE5-4381-866D-4F405E28AC42} - DSUtil - MFCProj - DSUtil - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\include;..\DSUtil;..\filters\renderer\VideoRenderers;..\thirdparty;..\thirdparty\VirtualDub\h;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {FC70988B-1AE5-4381-866D-4F405E28AC42} + DSUtil + MFCProj + DSUtil + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\include;..\DSUtil;..\filters\renderer\VideoRenderers;..\thirdparty;..\thirdparty\VirtualDub\h;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + + + \ No newline at end of file diff --git a/src/DSUtil/DSUtil.vcxproj.filters b/src/DSUtil/DSUtil.vcxproj.filters index c63c6abce35..309f889e253 100644 --- a/src/DSUtil/DSUtil.vcxproj.filters +++ b/src/DSUtil/DSUtil.vcxproj.filters @@ -1,188 +1,188 @@ - - - - - {7a9014bb-a149-4bb1-be1b-b988a38f79d0} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {2b09c18b-87fc-47da-a366-3e14c0b9d40f} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {7a9014bb-a149-4bb1-be1b-b988a38f79d0} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {2b09c18b-87fc-47da-a366-3e14c0b9d40f} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/DSUtil/FileVersionInfo.cpp b/src/DSUtil/FileVersionInfo.cpp index 8b5302ac006..cdc19fc5e5e 100644 --- a/src/DSUtil/FileVersionInfo.cpp +++ b/src/DSUtil/FileVersionInfo.cpp @@ -1,91 +1,91 @@ -/* - * (C) 2012-2014 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 . - * - */ - -#include "stdafx.h" -#include "FileVersionInfo.h" - -bool FileVersionInfo::LoadInfo(LPCTSTR filePath, VS_FIXEDFILEINFO& fileInfo) -{ - bool success = false; - - // Get the buffer size required for the version information - DWORD dwFileVersionInfoSize = GetFileVersionInfoSize(filePath, nullptr); - if (dwFileVersionInfoSize) { - // Allocate the buffer - BYTE* lpData = (BYTE*)DEBUG_NEW BYTE[dwFileVersionInfoSize]; - if (lpData) { - // Load the file-version information - if (GetFileVersionInfo(filePath, 0, dwFileVersionInfoSize, (LPVOID)lpData)) { - // Parse the version information - VS_FIXEDFILEINFO* lpInfo; - UINT unInfoLen; - if (VerQueryValue((LPVOID)lpData, _T("\\"), (LPVOID*)&lpInfo, &unInfoLen) - && unInfoLen == sizeof(VS_FIXEDFILEINFO)) { - fileInfo = *lpInfo; - success = true; - } - } - - delete [] lpData; - } - } - - return success; -} - -CString FileVersionInfo::GetFileVersionStr(LPCTSTR filePath) -{ - VS_FIXEDFILEINFO fileInfo; - CString strFileVersion; - - if (LoadInfo(filePath, fileInfo)) { - strFileVersion = FormatVersionString(fileInfo.dwFileVersionLS, fileInfo.dwFileVersionMS); - } - - return strFileVersion; -} - -QWORD FileVersionInfo::GetFileVersionNum(LPCTSTR filePath) -{ - VS_FIXEDFILEINFO fileInfo; - QWORD qwFileVersion = 0; - - if (LoadInfo(filePath, fileInfo)) { - qwFileVersion = ((QWORD)fileInfo.dwFileVersionMS << 32) | fileInfo.dwFileVersionLS; - } - - return qwFileVersion; -} - -CString FileVersionInfo::FormatVersionString(DWORD dwVersionNumberLow, DWORD dwVersionNumberHigh) -{ - CString strFileVersion; - strFileVersion.Format(_T("%lu.%lu.%lu.%lu"), - (dwVersionNumberHigh & 0xFFFF0000) >> 16, - (dwVersionNumberHigh & 0x0000FFFF), - (dwVersionNumberLow & 0xFFFF0000) >> 16, - (dwVersionNumberLow & 0x0000FFFF)); - return strFileVersion; -} - -CString FileVersionInfo::FormatVersionString(QWORD qwVersionNumber) -{ - return FormatVersionString(qwVersionNumber & DWORD_MAX, (qwVersionNumber >> 32) & DWORD_MAX); -} +/* + * (C) 2012-2014 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 . + * + */ + +#include "stdafx.h" +#include "FileVersionInfo.h" + +bool FileVersionInfo::LoadInfo(LPCTSTR filePath, VS_FIXEDFILEINFO& fileInfo) +{ + bool success = false; + + // Get the buffer size required for the version information + DWORD dwFileVersionInfoSize = GetFileVersionInfoSize(filePath, nullptr); + if (dwFileVersionInfoSize) { + // Allocate the buffer + BYTE* lpData = (BYTE*)DEBUG_NEW BYTE[dwFileVersionInfoSize]; + if (lpData) { + // Load the file-version information + if (GetFileVersionInfo(filePath, 0, dwFileVersionInfoSize, (LPVOID)lpData)) { + // Parse the version information + VS_FIXEDFILEINFO* lpInfo; + UINT unInfoLen; + if (VerQueryValue((LPVOID)lpData, _T("\\"), (LPVOID*)&lpInfo, &unInfoLen) + && unInfoLen == sizeof(VS_FIXEDFILEINFO)) { + fileInfo = *lpInfo; + success = true; + } + } + + delete [] lpData; + } + } + + return success; +} + +CString FileVersionInfo::GetFileVersionStr(LPCTSTR filePath) +{ + VS_FIXEDFILEINFO fileInfo; + CString strFileVersion; + + if (LoadInfo(filePath, fileInfo)) { + strFileVersion = FormatVersionString(fileInfo.dwFileVersionLS, fileInfo.dwFileVersionMS); + } + + return strFileVersion; +} + +QWORD FileVersionInfo::GetFileVersionNum(LPCTSTR filePath) +{ + VS_FIXEDFILEINFO fileInfo; + QWORD qwFileVersion = 0; + + if (LoadInfo(filePath, fileInfo)) { + qwFileVersion = ((QWORD)fileInfo.dwFileVersionMS << 32) | fileInfo.dwFileVersionLS; + } + + return qwFileVersion; +} + +CString FileVersionInfo::FormatVersionString(DWORD dwVersionNumberLow, DWORD dwVersionNumberHigh) +{ + CString strFileVersion; + strFileVersion.Format(_T("%lu.%lu.%lu.%lu"), + (dwVersionNumberHigh & 0xFFFF0000) >> 16, + (dwVersionNumberHigh & 0x0000FFFF), + (dwVersionNumberLow & 0xFFFF0000) >> 16, + (dwVersionNumberLow & 0x0000FFFF)); + return strFileVersion; +} + +CString FileVersionInfo::FormatVersionString(QWORD qwVersionNumber) +{ + return FormatVersionString(qwVersionNumber & DWORD_MAX, (qwVersionNumber >> 32) & DWORD_MAX); +} diff --git a/src/DSUtil/FileVersionInfo.h b/src/DSUtil/FileVersionInfo.h index aa46444f9b3..6bd0a3e84bf 100644 --- a/src/DSUtil/FileVersionInfo.h +++ b/src/DSUtil/FileVersionInfo.h @@ -1,32 +1,32 @@ -/* - * (C) 2012-2014 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 . - * - */ - -#pragma once - -namespace FileVersionInfo -{ - bool LoadInfo(LPCTSTR filePath, VS_FIXEDFILEINFO& fileInfo); - - CString GetFileVersionStr(LPCTSTR filePath); - QWORD GetFileVersionNum(LPCTSTR filePath); - - CString FormatVersionString(DWORD dwVersionNumberLow, DWORD dwVersionNumberHigh); - CString FormatVersionString(QWORD qwVersionNumber); -}; +/* + * (C) 2012-2014 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 . + * + */ + +#pragma once + +namespace FileVersionInfo +{ + bool LoadInfo(LPCTSTR filePath, VS_FIXEDFILEINFO& fileInfo); + + CString GetFileVersionStr(LPCTSTR filePath); + QWORD GetFileVersionNum(LPCTSTR filePath); + + CString FormatVersionString(DWORD dwVersionNumberLow, DWORD dwVersionNumberHigh); + CString FormatVersionString(QWORD qwVersionNumber); +}; diff --git a/src/DSUtil/FontInstaller.cpp b/src/DSUtil/FontInstaller.cpp index 53dedad86d4..4c3b32c86c5 100644 --- a/src/DSUtil/FontInstaller.cpp +++ b/src/DSUtil/FontInstaller.cpp @@ -1,139 +1,139 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "FontInstaller.h" - -CFontInstaller::CFontInstaller() - : pAddFontMemResourceEx(nullptr) - , pAddFontResourceEx(nullptr) - , pRemoveFontMemResourceEx(nullptr) - , pRemoveFontResourceEx(nullptr) - , pMoveFileEx(nullptr) -{ - if (HMODULE hGdi = GetModuleHandle(_T("gdi32.dll"))) { - pAddFontMemResourceEx = (HANDLE(WINAPI*)(PVOID, DWORD, PVOID, DWORD*))GetProcAddress(hGdi, "AddFontMemResourceEx"); - pAddFontResourceEx = (int (WINAPI*)(LPCTSTR, DWORD, PVOID))GetProcAddress(hGdi, "AddFontResourceExW"); - pRemoveFontMemResourceEx = (BOOL (WINAPI*)(HANDLE))GetProcAddress(hGdi, "RemoveFontMemResourceEx"); - pRemoveFontResourceEx = (BOOL (WINAPI*)(LPCTSTR, DWORD, PVOID))GetProcAddress(hGdi, "RemoveFontResourceExW"); - } - - if (HMODULE hGdi = GetModuleHandle(_T("kernel32.dll"))) { - pMoveFileEx = (BOOL (WINAPI*)(LPCTSTR, LPCTSTR, DWORD))GetProcAddress(hGdi, "MoveFileExW"); - } -} - -CFontInstaller::~CFontInstaller() -{ - UninstallFonts(); -} - -bool CFontInstaller::InstallFont(const CAtlArray& data) -{ - return InstallFont(data.GetData(), (UINT)data.GetCount()); -} - -bool CFontInstaller::InstallFont(const void* pData, UINT len) -{ - return InstallFontFile(pData, len) || InstallFontMemory(pData, len); -} - -void CFontInstaller::UninstallFonts() -{ - if (pRemoveFontMemResourceEx) { - POSITION pos = m_fonts.GetHeadPosition(); - while (pos) { - pRemoveFontMemResourceEx(m_fonts.GetNext(pos)); - } - m_fonts.RemoveAll(); - } - - if (pRemoveFontResourceEx) { - POSITION pos = m_files.GetHeadPosition(); - while (pos) { - CString fn = m_files.GetNext(pos); - pRemoveFontResourceEx(fn, FR_PRIVATE, 0); - if (!DeleteFile(fn) && pMoveFileEx) { - pMoveFileEx(fn, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); - } - } - - m_files.RemoveAll(); - - pos = m_tempfonts.GetHeadPosition(); - while (pos) { - CString fn = m_tempfonts.GetNext(pos); - pRemoveFontResourceEx(fn, FR_PRIVATE, 0); - } - - m_tempfonts.RemoveAll(); - } -} - -bool CFontInstaller::InstallFontMemory(const void* pData, UINT len) -{ - if (!pAddFontMemResourceEx) { - return false; - } - - DWORD nFonts = 0; - HANDLE hFont = pAddFontMemResourceEx((PVOID)pData, len, nullptr, &nFonts); - if (hFont && nFonts > 0) { - m_fonts.AddTail(hFont); - } - return hFont && nFonts > 0; -} - -bool CFontInstaller::InstallFontFile(const void* pData, UINT len) -{ - if (!pAddFontResourceEx) { - return false; - } - - CFile f; - TCHAR path[MAX_PATH], fn[MAX_PATH]; - if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("g_font"), 0, fn)) { - return false; - } - - if (f.Open(fn, CFile::modeWrite)) { - f.Write(pData, len); - f.Close(); - - if (pAddFontResourceEx(fn, FR_PRIVATE, 0) > 0) { - m_files.AddTail(fn); - return true; - } - } - - DeleteFile(fn); - return false; -} - -bool CFontInstaller::InstallTempFontFile(LPCTSTR fn) -{ - if (pAddFontResourceEx && pAddFontResourceEx(fn, FR_PRIVATE, 0) > 0) { - m_tempfonts.AddTail(fn); - return true; - } - - return false; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "FontInstaller.h" + +CFontInstaller::CFontInstaller() + : pAddFontMemResourceEx(nullptr) + , pAddFontResourceEx(nullptr) + , pRemoveFontMemResourceEx(nullptr) + , pRemoveFontResourceEx(nullptr) + , pMoveFileEx(nullptr) +{ + if (HMODULE hGdi = GetModuleHandle(_T("gdi32.dll"))) { + pAddFontMemResourceEx = (HANDLE(WINAPI*)(PVOID, DWORD, PVOID, DWORD*))GetProcAddress(hGdi, "AddFontMemResourceEx"); + pAddFontResourceEx = (int (WINAPI*)(LPCTSTR, DWORD, PVOID))GetProcAddress(hGdi, "AddFontResourceExW"); + pRemoveFontMemResourceEx = (BOOL (WINAPI*)(HANDLE))GetProcAddress(hGdi, "RemoveFontMemResourceEx"); + pRemoveFontResourceEx = (BOOL (WINAPI*)(LPCTSTR, DWORD, PVOID))GetProcAddress(hGdi, "RemoveFontResourceExW"); + } + + if (HMODULE hGdi = GetModuleHandle(_T("kernel32.dll"))) { + pMoveFileEx = (BOOL (WINAPI*)(LPCTSTR, LPCTSTR, DWORD))GetProcAddress(hGdi, "MoveFileExW"); + } +} + +CFontInstaller::~CFontInstaller() +{ + UninstallFonts(); +} + +bool CFontInstaller::InstallFont(const CAtlArray& data) +{ + return InstallFont(data.GetData(), (UINT)data.GetCount()); +} + +bool CFontInstaller::InstallFont(const void* pData, UINT len) +{ + return InstallFontFile(pData, len) || InstallFontMemory(pData, len); +} + +void CFontInstaller::UninstallFonts() +{ + if (pRemoveFontMemResourceEx) { + POSITION pos = m_fonts.GetHeadPosition(); + while (pos) { + pRemoveFontMemResourceEx(m_fonts.GetNext(pos)); + } + m_fonts.RemoveAll(); + } + + if (pRemoveFontResourceEx) { + POSITION pos = m_files.GetHeadPosition(); + while (pos) { + CString fn = m_files.GetNext(pos); + pRemoveFontResourceEx(fn, FR_PRIVATE, 0); + if (!DeleteFile(fn) && pMoveFileEx) { + pMoveFileEx(fn, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); + } + } + + m_files.RemoveAll(); + + pos = m_tempfonts.GetHeadPosition(); + while (pos) { + CString fn = m_tempfonts.GetNext(pos); + pRemoveFontResourceEx(fn, FR_PRIVATE, 0); + } + + m_tempfonts.RemoveAll(); + } +} + +bool CFontInstaller::InstallFontMemory(const void* pData, UINT len) +{ + if (!pAddFontMemResourceEx) { + return false; + } + + DWORD nFonts = 0; + HANDLE hFont = pAddFontMemResourceEx((PVOID)pData, len, nullptr, &nFonts); + if (hFont && nFonts > 0) { + m_fonts.AddTail(hFont); + } + return hFont && nFonts > 0; +} + +bool CFontInstaller::InstallFontFile(const void* pData, UINT len) +{ + if (!pAddFontResourceEx) { + return false; + } + + CFile f; + TCHAR path[MAX_PATH], fn[MAX_PATH]; + if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("g_font"), 0, fn)) { + return false; + } + + if (f.Open(fn, CFile::modeWrite)) { + f.Write(pData, len); + f.Close(); + + if (pAddFontResourceEx(fn, FR_PRIVATE, 0) > 0) { + m_files.AddTail(fn); + return true; + } + } + + DeleteFile(fn); + return false; +} + +bool CFontInstaller::InstallTempFontFile(LPCTSTR fn) +{ + if (pAddFontResourceEx && pAddFontResourceEx(fn, FR_PRIVATE, 0) > 0) { + m_tempfonts.AddTail(fn); + return true; + } + + return false; +} diff --git a/src/DSUtil/FontInstaller.h b/src/DSUtil/FontInstaller.h index 1693278838e..968448c459b 100644 --- a/src/DSUtil/FontInstaller.h +++ b/src/DSUtil/FontInstaller.h @@ -1,48 +1,48 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2014 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 . - * - */ - -#pragma once - -#include - -class CFontInstaller -{ - HANDLE(WINAPI* pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD*); - int (WINAPI* pAddFontResourceEx)(LPCTSTR, DWORD, PVOID); - BOOL (WINAPI* pRemoveFontMemResourceEx)(HANDLE); - BOOL (WINAPI* pRemoveFontResourceEx)(LPCTSTR, DWORD, PVOID); - BOOL (WINAPI* pMoveFileEx)(LPCTSTR, LPCTSTR, DWORD); - - CAtlList m_fonts; - CAtlList m_files; - CAtlList m_tempfonts; - bool InstallFontFile(const void* pData, UINT len); - -public: - CFontInstaller(); - virtual ~CFontInstaller(); - - bool InstallFont(const CAtlArray& data); - bool InstallFont(const void* pData, UINT len); - bool InstallFontMemory(const void* pData, UINT len); - bool InstallTempFontFile(LPCTSTR fn); - void UninstallFonts(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2014 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 . + * + */ + +#pragma once + +#include + +class CFontInstaller +{ + HANDLE(WINAPI* pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD*); + int (WINAPI* pAddFontResourceEx)(LPCTSTR, DWORD, PVOID); + BOOL (WINAPI* pRemoveFontMemResourceEx)(HANDLE); + BOOL (WINAPI* pRemoveFontResourceEx)(LPCTSTR, DWORD, PVOID); + BOOL (WINAPI* pMoveFileEx)(LPCTSTR, LPCTSTR, DWORD); + + CAtlList m_fonts; + CAtlList m_files; + CAtlList m_tempfonts; + bool InstallFontFile(const void* pData, UINT len); + +public: + CFontInstaller(); + virtual ~CFontInstaller(); + + bool InstallFont(const CAtlArray& data); + bool InstallFont(const void* pData, UINT len); + bool InstallFontMemory(const void* pData, UINT len); + bool InstallTempFontFile(LPCTSTR fn); + void UninstallFonts(); +}; diff --git a/src/DSUtil/GolombBuffer.cpp b/src/DSUtil/GolombBuffer.cpp index 00e23ff10f2..cc909da4b9e 100644 --- a/src/DSUtil/GolombBuffer.cpp +++ b/src/DSUtil/GolombBuffer.cpp @@ -1,205 +1,205 @@ -/* - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "GolombBuffer.h" -#include - -static void RemoveMpegEscapeCode(BYTE* dst, const BYTE* src, int& length) -{ - memset(dst, 0, length); - int si = 0; - int di = 0; - while (si + 2 < length) { - if (src[si + 2] > 3) { - dst[di++] = src[si++]; - dst[di++] = src[si++]; - } else if (src[si] == 0 && src[si + 1] == 0) { - dst[di++] = 0; - dst[di++] = 0; - if (src[si + 2] == 3) { // escape - si += 3; - } else { - si += 2; - } - continue; - } - - dst[di++] = src[si++]; - } - while (si < length) { - dst[di++] = src[si++]; - } - - length = di; -} - -CGolombBuffer::CGolombBuffer(const BYTE* pBuffer, int nSize, const bool bRemoveMpegEscapes/* = false*/) - : m_bRemoveMpegEscapes(bRemoveMpegEscapes) - , m_pTmpBuffer(nullptr) -{ - Reset(pBuffer, nSize); -} - -CGolombBuffer::~CGolombBuffer() -{ - SAFE_DELETE_ARRAY(m_pTmpBuffer); -} - -UINT64 CGolombBuffer::BitRead(const int nBits, const bool bPeek/* = false*/) -{ - //ASSERT(nBits >= 0 && nBits <= 64); - const INT64 tmp_bitbuff = m_bitbuff; - const int tmp_nBitPos = m_nBitPos; - const int tmp_bitlen = m_bitlen; - - while (m_bitlen < nBits) { - m_bitbuff <<= 8; - - if (m_nBitPos >= m_nSize) { - return 0; - } - - *(BYTE*)&m_bitbuff = m_pBuffer[m_nBitPos++]; - m_bitlen += 8; - } - - const int bitlen = m_bitlen - nBits; - - UINT64 ret; - // The shift to 64 bits can give incorrect results. - // "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." - if (nBits == 64) { - ret = m_bitbuff; - } else { - ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); - } - - if (!bPeek) { - m_bitbuff &= ((1ui64 << bitlen) - 1); - m_bitlen = bitlen; - } else { - m_bitbuff = tmp_bitbuff; - m_nBitPos = tmp_nBitPos; - m_bitlen = tmp_bitlen; - } - - return ret; -} - -UINT64 CGolombBuffer::UExpGolombRead() -{ - int n = -1; - for (BYTE b = 0; !b && !IsEOF(); n++) { - b = (BYTE)BitRead(1); - } - return (1ui64 << n) - 1 + BitRead(n); -} - -unsigned int CGolombBuffer::UintGolombRead() -{ - unsigned int value = 0, count = 0; - while (!BitRead(1) && !IsEOF()) { - count++; - value <<= 1; - value |= BitRead(1); - } - - return (1 << count) - 1 + value; -} - -INT64 CGolombBuffer::SExpGolombRead() -{ - UINT64 k = UExpGolombRead(); - return ((k&1) ? 1 : -1) * ((k + 1) >> 1); -} - -void CGolombBuffer::BitByteAlign() -{ - m_bitlen &= ~7; -} - -int CGolombBuffer::GetPos() const -{ - return m_nBitPos - (m_bitlen >> 3); -} - -void CGolombBuffer::ReadBuffer(BYTE* pDest, int nSize) -{ - ASSERT(m_nBitPos + nSize <= m_nSize); - ASSERT(m_bitlen == 0); - nSize = std::min(nSize, m_nSize - m_nBitPos); - - memcpy(pDest, m_pBuffer + m_nBitPos, nSize); - m_nBitPos += nSize; -} - -void CGolombBuffer::Reset() -{ - m_nBitPos = 0; - m_bitlen = 0; - m_bitbuff = 0; -} - -void CGolombBuffer::Reset(const BYTE* pNewBuffer, int nNewSize) -{ - if (m_bRemoveMpegEscapes) { - SAFE_DELETE_ARRAY(m_pTmpBuffer); - m_pTmpBuffer = DEBUG_NEW BYTE[nNewSize]; - - RemoveMpegEscapeCode(m_pTmpBuffer, pNewBuffer, nNewSize); - m_pBuffer = m_pTmpBuffer; - m_nSize = nNewSize; - } else { - m_pBuffer = pNewBuffer; - m_nSize = nNewSize; - } - - Reset(); -} - -void CGolombBuffer::SkipBytes(const int nCount) -{ - m_nBitPos += nCount; - m_bitlen = 0; - m_bitbuff = 0; -} - -void CGolombBuffer::Seek(const int nCount) -{ - m_nBitPos = nCount; - m_bitlen = 0; - m_bitbuff = 0; -} - -bool CGolombBuffer::NextMpegStartCode(BYTE& code) -{ - BitByteAlign(); - DWORD dw = DWORD_MAX; - do { - if (IsEOF()) { - return false; - } - dw = (dw << 8) | (BYTE)BitRead(8); - } while ((dw & 0xffffff00) != 0x00000100); - code = (BYTE)(dw & 0xff); - - return true; -} +/* + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "GolombBuffer.h" +#include + +static void RemoveMpegEscapeCode(BYTE* dst, const BYTE* src, int& length) +{ + memset(dst, 0, length); + int si = 0; + int di = 0; + while (si + 2 < length) { + if (src[si + 2] > 3) { + dst[di++] = src[si++]; + dst[di++] = src[si++]; + } else if (src[si] == 0 && src[si + 1] == 0) { + dst[di++] = 0; + dst[di++] = 0; + if (src[si + 2] == 3) { // escape + si += 3; + } else { + si += 2; + } + continue; + } + + dst[di++] = src[si++]; + } + while (si < length) { + dst[di++] = src[si++]; + } + + length = di; +} + +CGolombBuffer::CGolombBuffer(const BYTE* pBuffer, int nSize, const bool bRemoveMpegEscapes/* = false*/) + : m_bRemoveMpegEscapes(bRemoveMpegEscapes) + , m_pTmpBuffer(nullptr) +{ + Reset(pBuffer, nSize); +} + +CGolombBuffer::~CGolombBuffer() +{ + SAFE_DELETE_ARRAY(m_pTmpBuffer); +} + +UINT64 CGolombBuffer::BitRead(const int nBits, const bool bPeek/* = false*/) +{ + //ASSERT(nBits >= 0 && nBits <= 64); + const INT64 tmp_bitbuff = m_bitbuff; + const int tmp_nBitPos = m_nBitPos; + const int tmp_bitlen = m_bitlen; + + while (m_bitlen < nBits) { + m_bitbuff <<= 8; + + if (m_nBitPos >= m_nSize) { + return 0; + } + + *(BYTE*)&m_bitbuff = m_pBuffer[m_nBitPos++]; + m_bitlen += 8; + } + + const int bitlen = m_bitlen - nBits; + + UINT64 ret; + // The shift to 64 bits can give incorrect results. + // "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." + if (nBits == 64) { + ret = m_bitbuff; + } else { + ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); + } + + if (!bPeek) { + m_bitbuff &= ((1ui64 << bitlen) - 1); + m_bitlen = bitlen; + } else { + m_bitbuff = tmp_bitbuff; + m_nBitPos = tmp_nBitPos; + m_bitlen = tmp_bitlen; + } + + return ret; +} + +UINT64 CGolombBuffer::UExpGolombRead() +{ + int n = -1; + for (BYTE b = 0; !b && !IsEOF(); n++) { + b = (BYTE)BitRead(1); + } + return (1ui64 << n) - 1 + BitRead(n); +} + +unsigned int CGolombBuffer::UintGolombRead() +{ + unsigned int value = 0, count = 0; + while (!BitRead(1) && !IsEOF()) { + count++; + value <<= 1; + value |= BitRead(1); + } + + return (1 << count) - 1 + value; +} + +INT64 CGolombBuffer::SExpGolombRead() +{ + UINT64 k = UExpGolombRead(); + return ((k&1) ? 1 : -1) * ((k + 1) >> 1); +} + +void CGolombBuffer::BitByteAlign() +{ + m_bitlen &= ~7; +} + +int CGolombBuffer::GetPos() const +{ + return m_nBitPos - (m_bitlen >> 3); +} + +void CGolombBuffer::ReadBuffer(BYTE* pDest, int nSize) +{ + ASSERT(m_nBitPos + nSize <= m_nSize); + ASSERT(m_bitlen == 0); + nSize = std::min(nSize, m_nSize - m_nBitPos); + + memcpy(pDest, m_pBuffer + m_nBitPos, nSize); + m_nBitPos += nSize; +} + +void CGolombBuffer::Reset() +{ + m_nBitPos = 0; + m_bitlen = 0; + m_bitbuff = 0; +} + +void CGolombBuffer::Reset(const BYTE* pNewBuffer, int nNewSize) +{ + if (m_bRemoveMpegEscapes) { + SAFE_DELETE_ARRAY(m_pTmpBuffer); + m_pTmpBuffer = DEBUG_NEW BYTE[nNewSize]; + + RemoveMpegEscapeCode(m_pTmpBuffer, pNewBuffer, nNewSize); + m_pBuffer = m_pTmpBuffer; + m_nSize = nNewSize; + } else { + m_pBuffer = pNewBuffer; + m_nSize = nNewSize; + } + + Reset(); +} + +void CGolombBuffer::SkipBytes(const int nCount) +{ + m_nBitPos += nCount; + m_bitlen = 0; + m_bitbuff = 0; +} + +void CGolombBuffer::Seek(const int nCount) +{ + m_nBitPos = nCount; + m_bitlen = 0; + m_bitbuff = 0; +} + +bool CGolombBuffer::NextMpegStartCode(BYTE& code) +{ + BitByteAlign(); + DWORD dw = DWORD_MAX; + do { + if (IsEOF()) { + return false; + } + dw = (dw << 8) | (BYTE)BitRead(8); + } while ((dw & 0xffffff00) != 0x00000100); + code = (BYTE)(dw & 0xff); + + return true; +} diff --git a/src/DSUtil/GolombBuffer.h b/src/DSUtil/GolombBuffer.h index 14158d860db..606a7b4d027 100644 --- a/src/DSUtil/GolombBuffer.h +++ b/src/DSUtil/GolombBuffer.h @@ -1,68 +1,68 @@ -/* - * (C) 2006-2018 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 . - * - */ - -#pragma once - -class CGolombBuffer -{ -public: - CGolombBuffer(const BYTE* pBuffer, int nSize, const bool bRemoveMpegEscapes = false); - ~CGolombBuffer(); - - UINT64 BitRead(const int nBits, const bool bPeek = false); - UINT64 UExpGolombRead(); - unsigned int UintGolombRead(); - INT64 SExpGolombRead(); - void BitByteAlign(); - - inline BYTE ReadByte() { return (BYTE)BitRead(8); } - inline SHORT ReadShort() { return (SHORT)BitRead(16); } - inline DWORD ReadDword() { return (DWORD)BitRead(32); } - inline SHORT ReadShortLE() { return _byteswap_ushort((SHORT)BitRead(16)); } - inline DWORD ReadDwordLE() { return _byteswap_ulong((DWORD)BitRead(32)); } - - void ReadBuffer(BYTE* pDest, int nSize); - - void Reset(); - void Reset(const BYTE* pNewBuffer, int nNewSize); - - void SetSize(const int nValue) { m_nSize = nValue; } - int GetSize() const { return m_nSize; } - int RemainingSize() const { return m_nSize - m_nBitPos; } - int BitsLeft() const { return 8 * RemainingSize() + m_bitlen; } - bool IsEOF() const { return m_nBitPos >= m_nSize; } - int GetPos() const; - const BYTE* GetBufferPos() const { return m_pBuffer + m_nBitPos; } - - void SkipBytes(const int nCount); - void Seek(const int nPos); - - bool NextMpegStartCode(BYTE& code); - -private : - const BYTE* m_pBuffer; - int m_nSize; - int m_nBitPos; - int m_bitlen; - INT64 m_bitbuff; - - BYTE* m_pTmpBuffer; - bool m_bRemoveMpegEscapes; -}; +/* + * (C) 2006-2018 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 . + * + */ + +#pragma once + +class CGolombBuffer +{ +public: + CGolombBuffer(const BYTE* pBuffer, int nSize, const bool bRemoveMpegEscapes = false); + ~CGolombBuffer(); + + UINT64 BitRead(const int nBits, const bool bPeek = false); + UINT64 UExpGolombRead(); + unsigned int UintGolombRead(); + INT64 SExpGolombRead(); + void BitByteAlign(); + + inline BYTE ReadByte() { return (BYTE)BitRead(8); } + inline SHORT ReadShort() { return (SHORT)BitRead(16); } + inline DWORD ReadDword() { return (DWORD)BitRead(32); } + inline SHORT ReadShortLE() { return _byteswap_ushort((SHORT)BitRead(16)); } + inline DWORD ReadDwordLE() { return _byteswap_ulong((DWORD)BitRead(32)); } + + void ReadBuffer(BYTE* pDest, int nSize); + + void Reset(); + void Reset(const BYTE* pNewBuffer, int nNewSize); + + void SetSize(const int nValue) { m_nSize = nValue; } + int GetSize() const { return m_nSize; } + int RemainingSize() const { return m_nSize - m_nBitPos; } + int BitsLeft() const { return 8 * RemainingSize() + m_bitlen; } + bool IsEOF() const { return m_nBitPos >= m_nSize; } + int GetPos() const; + const BYTE* GetBufferPos() const { return m_pBuffer + m_nBitPos; } + + void SkipBytes(const int nCount); + void Seek(const int nPos); + + bool NextMpegStartCode(BYTE& code); + +private : + const BYTE* m_pBuffer; + int m_nSize; + int m_nBitPos; + int m_bitlen; + INT64 m_bitbuff; + + BYTE* m_pTmpBuffer; + bool m_bRemoveMpegEscapes; +}; diff --git a/src/DSUtil/H264Nalu.cpp b/src/DSUtil/H264Nalu.cpp index 02786343f88..d7d1482a934 100644 --- a/src/DSUtil/H264Nalu.cpp +++ b/src/DSUtil/H264Nalu.cpp @@ -1,110 +1,110 @@ -/* - * (C) 2008-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 . - * - */ - -#include "stdafx.h" -#include "H264Nalu.h" - -void CH264Nalu::SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize) -{ - m_pBuffer = pBuffer; - m_nSize = nSize; - m_nNALSize = nNALSize; - m_nCurPos = 0; - m_nNextRTP = 0; - - m_nNALStartPos = 0; - m_nNALDataPos = 0; - - // In AnnexB, the buffer is not guaranteed to start on a NAL boundary - if (nNALSize == 0 && nSize > 0) { - MoveToNextAnnexBStartcode(); - } -} - -bool CH264Nalu::MoveToNextAnnexBStartcode() -{ - if (m_nSize >= 4) { - size_t nBuffEnd = m_nSize - 4; - - for (size_t i = m_nCurPos; i <= nBuffEnd; i++) { - if ((*((DWORD*)(m_pBuffer + i)) & 0x00FFFFFF) == 0x00010000) { - // Found next AnnexB NAL - m_nCurPos = i; - return true; - } - } - } - - m_nCurPos = m_nSize; - return false; -} - -bool CH264Nalu::MoveToNextRTPStartcode() -{ - if (m_nNextRTP < m_nSize) { - m_nCurPos = m_nNextRTP; - return true; - } - - m_nCurPos = m_nSize; - return false; -} - -bool CH264Nalu::ReadNext() -{ - if (m_nCurPos >= m_nSize) { - return false; - } - - if ((m_nNALSize != 0) && (m_nCurPos == m_nNextRTP)) { - if (m_nCurPos + m_nNALSize >= m_nSize) { - return false; - } - // RTP Nalu type : (XX XX) XX XX NAL..., with XX XX XX XX or XX XX equal to NAL size - m_nNALStartPos = m_nCurPos; - m_nNALDataPos = m_nCurPos + m_nNALSize; - - // Read Length code from the buffer - unsigned nTemp = 0; - for (int i = 0; i < m_nNALSize; i++) { - nTemp = (nTemp << 8) + m_pBuffer[m_nCurPos++]; - } - - m_nNextRTP += nTemp + m_nNALSize; - MoveToNextRTPStartcode(); - } else { - // Remove trailing bits - while (m_pBuffer[m_nCurPos] == 0x00 && ((*((DWORD*)(m_pBuffer + m_nCurPos)) & 0x00FFFFFF) != 0x00010000)) { - m_nCurPos++; - } - - // AnnexB Nalu : 00 00 01 NAL... - m_nNALStartPos = m_nCurPos; - m_nCurPos += 3; - m_nNALDataPos = m_nCurPos; - MoveToNextAnnexBStartcode(); - } - - forbidden_bit = (m_pBuffer[m_nNALDataPos] >> 7) & 1; - nal_reference_idc = (m_pBuffer[m_nNALDataPos] >> 5) & 3; - nal_unit_type = (NALU_TYPE)(m_pBuffer[m_nNALDataPos] & 0x1f); - - return true; -} +/* + * (C) 2008-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 . + * + */ + +#include "stdafx.h" +#include "H264Nalu.h" + +void CH264Nalu::SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize) +{ + m_pBuffer = pBuffer; + m_nSize = nSize; + m_nNALSize = nNALSize; + m_nCurPos = 0; + m_nNextRTP = 0; + + m_nNALStartPos = 0; + m_nNALDataPos = 0; + + // In AnnexB, the buffer is not guaranteed to start on a NAL boundary + if (nNALSize == 0 && nSize > 0) { + MoveToNextAnnexBStartcode(); + } +} + +bool CH264Nalu::MoveToNextAnnexBStartcode() +{ + if (m_nSize >= 4) { + size_t nBuffEnd = m_nSize - 4; + + for (size_t i = m_nCurPos; i <= nBuffEnd; i++) { + if ((*((DWORD*)(m_pBuffer + i)) & 0x00FFFFFF) == 0x00010000) { + // Found next AnnexB NAL + m_nCurPos = i; + return true; + } + } + } + + m_nCurPos = m_nSize; + return false; +} + +bool CH264Nalu::MoveToNextRTPStartcode() +{ + if (m_nNextRTP < m_nSize) { + m_nCurPos = m_nNextRTP; + return true; + } + + m_nCurPos = m_nSize; + return false; +} + +bool CH264Nalu::ReadNext() +{ + if (m_nCurPos >= m_nSize) { + return false; + } + + if ((m_nNALSize != 0) && (m_nCurPos == m_nNextRTP)) { + if (m_nCurPos + m_nNALSize >= m_nSize) { + return false; + } + // RTP Nalu type : (XX XX) XX XX NAL..., with XX XX XX XX or XX XX equal to NAL size + m_nNALStartPos = m_nCurPos; + m_nNALDataPos = m_nCurPos + m_nNALSize; + + // Read Length code from the buffer + unsigned nTemp = 0; + for (int i = 0; i < m_nNALSize; i++) { + nTemp = (nTemp << 8) + m_pBuffer[m_nCurPos++]; + } + + m_nNextRTP += nTemp + m_nNALSize; + MoveToNextRTPStartcode(); + } else { + // Remove trailing bits + while (m_pBuffer[m_nCurPos] == 0x00 && ((*((DWORD*)(m_pBuffer + m_nCurPos)) & 0x00FFFFFF) != 0x00010000)) { + m_nCurPos++; + } + + // AnnexB Nalu : 00 00 01 NAL... + m_nNALStartPos = m_nCurPos; + m_nCurPos += 3; + m_nNALDataPos = m_nCurPos; + MoveToNextAnnexBStartcode(); + } + + forbidden_bit = (m_pBuffer[m_nNALDataPos] >> 7) & 1; + nal_reference_idc = (m_pBuffer[m_nNALDataPos] >> 5) & 3; + nal_unit_type = (NALU_TYPE)(m_pBuffer[m_nNALDataPos] & 0x1f); + + return true; +} diff --git a/src/DSUtil/H264Nalu.h b/src/DSUtil/H264Nalu.h index dc660ad91ed..0582166d2bf 100644 --- a/src/DSUtil/H264Nalu.h +++ b/src/DSUtil/H264Nalu.h @@ -1,82 +1,82 @@ -/* - * (C) 2008-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 . - * - */ - -#pragma once - -enum NALU_TYPE { - NALU_TYPE_SLICE = 1, - NALU_TYPE_DPA = 2, - NALU_TYPE_DPB = 3, - NALU_TYPE_DPC = 4, - NALU_TYPE_IDR = 5, - NALU_TYPE_SEI = 6, - NALU_TYPE_SPS = 7, - NALU_TYPE_PPS = 8, - NALU_TYPE_AUD = 9, - NALU_TYPE_EOSEQ = 10, - NALU_TYPE_EOSTREAM = 11, - NALU_TYPE_FILL = 12 -}; - - -class CH264Nalu -{ -private: - int forbidden_bit; //! should be always FALSE - int nal_reference_idc; //! NALU_PRIORITY_xxxx - NALU_TYPE nal_unit_type; //! NALU_TYPE_xxxx - - size_t m_nNALStartPos; //! NALU start (including startcode / size) - size_t m_nNALDataPos; //! Useful part - - const BYTE* m_pBuffer; - size_t m_nCurPos; - size_t m_nNextRTP; - size_t m_nSize; - int m_nNALSize; - - bool MoveToNextAnnexBStartcode(); - bool MoveToNextRTPStartcode(); - -public: - CH264Nalu() : - forbidden_bit(0), - nal_reference_idc(0), - nal_unit_type() { - SetBuffer(nullptr, 0, 0); - } - - NALU_TYPE GetType() const { return nal_unit_type; }; - bool IsRefFrame() const { return (nal_reference_idc != 0); }; - - size_t GetDataLength() const { return m_nCurPos - m_nNALDataPos; }; - const BYTE* GetDataBuffer() { return m_pBuffer + m_nNALDataPos; }; - size_t GetRoundedDataLength() const { - size_t nSize = m_nCurPos - m_nNALDataPos; - return nSize + 128 - (nSize % 128); - } - - size_t GetLength() const { return m_nCurPos - m_nNALStartPos; }; - const BYTE* GetNALBuffer() { return m_pBuffer + m_nNALStartPos; }; - bool IsEOF() const { return m_nCurPos >= m_nSize; }; - - void SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize); - bool ReadNext(); -}; +/* + * (C) 2008-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 . + * + */ + +#pragma once + +enum NALU_TYPE { + NALU_TYPE_SLICE = 1, + NALU_TYPE_DPA = 2, + NALU_TYPE_DPB = 3, + NALU_TYPE_DPC = 4, + NALU_TYPE_IDR = 5, + NALU_TYPE_SEI = 6, + NALU_TYPE_SPS = 7, + NALU_TYPE_PPS = 8, + NALU_TYPE_AUD = 9, + NALU_TYPE_EOSEQ = 10, + NALU_TYPE_EOSTREAM = 11, + NALU_TYPE_FILL = 12 +}; + + +class CH264Nalu +{ +private: + int forbidden_bit; //! should be always FALSE + int nal_reference_idc; //! NALU_PRIORITY_xxxx + NALU_TYPE nal_unit_type; //! NALU_TYPE_xxxx + + size_t m_nNALStartPos; //! NALU start (including startcode / size) + size_t m_nNALDataPos; //! Useful part + + const BYTE* m_pBuffer; + size_t m_nCurPos; + size_t m_nNextRTP; + size_t m_nSize; + int m_nNALSize; + + bool MoveToNextAnnexBStartcode(); + bool MoveToNextRTPStartcode(); + +public: + CH264Nalu() : + forbidden_bit(0), + nal_reference_idc(0), + nal_unit_type() { + SetBuffer(nullptr, 0, 0); + } + + NALU_TYPE GetType() const { return nal_unit_type; }; + bool IsRefFrame() const { return (nal_reference_idc != 0); }; + + size_t GetDataLength() const { return m_nCurPos - m_nNALDataPos; }; + const BYTE* GetDataBuffer() { return m_pBuffer + m_nNALDataPos; }; + size_t GetRoundedDataLength() const { + size_t nSize = m_nCurPos - m_nNALDataPos; + return nSize + 128 - (nSize % 128); + } + + size_t GetLength() const { return m_nCurPos - m_nNALStartPos; }; + const BYTE* GetNALBuffer() { return m_pBuffer + m_nNALStartPos; }; + bool IsEOF() const { return m_nCurPos >= m_nSize; }; + + void SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize); + bool ReadNext(); +}; diff --git a/src/DSUtil/HdmvClipInfo.cpp b/src/DSUtil/HdmvClipInfo.cpp index 85a6dc355c7..026f63f4aef 100644 --- a/src/DSUtil/HdmvClipInfo.cpp +++ b/src/DSUtil/HdmvClipInfo.cpp @@ -1,821 +1,821 @@ -/* - * (C) 2008-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include "HdmvClipInfo.h" -#include "DSUtil.h" -#include "ISOLang.h" -#include "tinyxml2/library/tinyxml2.h" -#include -#include "FileHandle.h" -#include "ISOLang.h" -using namespace tinyxml2; - -CHdmvClipInfo::CHdmvClipInfo() - : SequenceInfo_start_address(0) - , ProgramInfo_start_address(0) - , m_hFile(INVALID_HANDLE_VALUE) - , m_bIsHdmv(false) -{ -} - -CHdmvClipInfo::~CHdmvClipInfo() -{ - CloseFile(S_OK); -} - -HRESULT CHdmvClipInfo::CloseFile(HRESULT hr) -{ - if (m_hFile != INVALID_HANDLE_VALUE) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - } - return hr; -} - -DWORD CHdmvClipInfo::ReadDword() -{ - return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte(); -} - -short CHdmvClipInfo::ReadShort() -{ - return ReadByte() << 8 | ReadByte(); -} - -BYTE CHdmvClipInfo::ReadByte() -{ - BYTE bVal; - DWORD dwRead; - VERIFY(ReadFile(m_hFile, &bVal, sizeof(bVal), &dwRead, nullptr)); - - return bVal; -} - -BOOL CHdmvClipInfo::Skip(LONGLONG nLen) { - LARGE_INTEGER newPos = {}; - newPos.QuadPart = nLen; - return SetFilePointerEx(m_hFile, newPos, nullptr, FILE_CURRENT); -} - -BOOL CHdmvClipInfo::GetPos(LONGLONG& Pos) { - LARGE_INTEGER curPos = {}; - const BOOL bRet = SetFilePointerEx(m_hFile, curPos, &curPos, FILE_CURRENT); - Pos = curPos.QuadPart; - - return bRet; -} -BOOL CHdmvClipInfo::SetPos(LONGLONG Pos, DWORD dwMoveMethod/* = FILE_BEGIN*/) { - LARGE_INTEGER newPos = {}; - newPos.QuadPart = Pos; - return SetFilePointerEx(m_hFile, newPos, nullptr, dwMoveMethod); -} - -HRESULT CHdmvClipInfo::ReadLang(Stream& s) { - ReadBuffer((BYTE*)s.m_LanguageCode, 3); - s.m_LCID = ISOLang::ISO6392ToLcid(s.m_LanguageCode); - - return S_OK; -} - -void CHdmvClipInfo::ReadBuffer(BYTE* pBuff, DWORD nLen) -{ - DWORD dwRead; - VERIFY(ReadFile(m_hFile, pBuff, nLen, &dwRead, nullptr)); -} - -HRESULT CHdmvClipInfo::ReadProgramInfo() -{ - BYTE number_of_program_sequences; - LARGE_INTEGER Pos; - - m_Streams.RemoveAll(); - Pos.QuadPart = ProgramInfo_start_address; - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - - ReadDword(); //length - ReadByte(); //reserved_for_word_align - number_of_program_sequences = (BYTE)ReadByte(); - int iStream = 0; - for (size_t i = 0; i < number_of_program_sequences; i++) { - ReadDword(); //SPN_program_sequence_start - ReadShort(); //program_map_PID - BYTE number_of_streams_in_ps = (BYTE)ReadByte(); //number_of_streams_in_ps - ReadByte(); //reserved_for_future_use - - for (size_t stream_index = 0; stream_index < number_of_streams_in_ps; stream_index++) { - m_Streams.SetCount(iStream + 1); - m_Streams[iStream].m_PID = ReadShort(); // stream_PID - - // == StreamCodingInfo - Pos.QuadPart = 0; - SetFilePointerEx(m_hFile, Pos, &Pos, FILE_CURRENT); - Pos.QuadPart += ReadByte() + 1; // length - m_Streams[iStream].m_Type = (PES_STREAM_TYPE)ReadByte(); - - switch (m_Streams[iStream].m_Type) { - case VIDEO_STREAM_MPEG1: - case VIDEO_STREAM_MPEG2: - case VIDEO_STREAM_H264: - case VIDEO_STREAM_VC1: - case VIDEO_STREAM_HEVC: { - UINT8 Temp = ReadByte(); - BDVM_VideoFormat VideoFormat = (BDVM_VideoFormat)(Temp >> 4); - BDVM_FrameRate FrameRate = (BDVM_FrameRate)(Temp & 0xf); - Temp = ReadByte(); - BDVM_AspectRatio AspectRatio = (BDVM_AspectRatio)(Temp >> 4); - - m_Streams[iStream].m_VideoFormat = VideoFormat; - m_Streams[iStream].m_FrameRate = FrameRate; - m_Streams[iStream].m_AspectRatio = AspectRatio; - } - break; - case AUDIO_STREAM_MPEG1: - case AUDIO_STREAM_MPEG2: - case AUDIO_STREAM_LPCM: - case AUDIO_STREAM_AC3: - case AUDIO_STREAM_DTS: - case AUDIO_STREAM_AC3_TRUE_HD: - case AUDIO_STREAM_AC3_PLUS: - case AUDIO_STREAM_DTS_HD: - case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: - case SECONDARY_AUDIO_AC3_PLUS: - case SECONDARY_AUDIO_DTS_HD: { - UINT8 Temp = ReadByte(); - BDVM_ChannelLayout ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); - BDVM_SampleRate SampleRate = (BDVM_SampleRate)(Temp & 0xF); - - ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); - m_Streams[iStream].m_LanguageCode[3] = '\0'; - m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); - m_Streams[iStream].m_ChannelLayout = ChannelLayout; - m_Streams[iStream].m_SampleRate = SampleRate; - } - break; - case PRESENTATION_GRAPHICS_STREAM: - case INTERACTIVE_GRAPHICS_STREAM: { - ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); - m_Streams[iStream].m_LanguageCode[3] = '\0'; - m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); - } - break; - case SUBTITLE_STREAM: { - ReadByte(); // Should this really be here? - ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); - m_Streams[iStream].m_LanguageCode[3] = '\0'; - m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); - } - break; - default: - break; - } - - iStream++; - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - } - } - return S_OK; -} - -HRESULT CHdmvClipInfo::ReadInfo(LPCTSTR strFile) -{ - m_bIsHdmv = false; - m_hFile = CreateFile(strFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); - - if (m_hFile != INVALID_HANDLE_VALUE) { - BYTE Buff[100]; - ReadBuffer(Buff, 4); - if (memcmp(Buff, "HDMV", 4)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - ReadBuffer(Buff, 4); - if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - SequenceInfo_start_address = ReadDword(); - ProgramInfo_start_address = ReadDword(); - - ReadProgramInfo(); - - m_bIsHdmv = true; - - return CloseFile(S_OK); - } - - return AmHresultFromWin32(GetLastError()); -} - -CHdmvClipInfo::Stream* CHdmvClipInfo::FindStream(short wPID) -{ - size_t nStreams = m_Streams.GetCount(); - for (size_t i = 0; i < nStreams; i++) { - if (m_Streams[i].m_PID == wPID) { - return &m_Streams[i]; - } - } - - return nullptr; -} - -LPCTSTR CHdmvClipInfo::Stream::Format() -{ - switch (m_Type) { - case VIDEO_STREAM_MPEG1: - return _T("Mpeg1"); - case VIDEO_STREAM_MPEG2: - return _T("Mpeg2"); - case VIDEO_STREAM_H264: - return _T("H264"); - case VIDEO_STREAM_VC1: - return _T("VC1"); - case VIDEO_STREAM_HEVC: - return _T("HEVC"); - case AUDIO_STREAM_MPEG1: - return _T("MPEG1"); - case AUDIO_STREAM_MPEG2: - return _T("MPEG2"); - case AUDIO_STREAM_LPCM: - return _T("LPCM"); - case AUDIO_STREAM_AC3: - return _T("AC3"); - case AUDIO_STREAM_DTS: - return _T("DTS"); - case AUDIO_STREAM_AC3_TRUE_HD: - return _T("MLP"); - case AUDIO_STREAM_AC3_PLUS: - return _T("DD+"); - case AUDIO_STREAM_DTS_HD: - return _T("DTS-HD"); - case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: - return _T("DTS-HD XLL"); - case SECONDARY_AUDIO_AC3_PLUS: - return _T("Sec DD+"); - case SECONDARY_AUDIO_DTS_HD: - return _T("Sec DTS-HD"); - case PRESENTATION_GRAPHICS_STREAM: - return _T("PG"); - case INTERACTIVE_GRAPHICS_STREAM: - return _T("IG"); - case SUBTITLE_STREAM: - return _T("Text"); - default: - return _T("Unknown"); - } -} - -HRESULT CHdmvClipInfo::ReadStreamInfo() { - BYTE len = ReadByte(); - LONGLONG Pos = 0; - GetPos(Pos); - - Stream s; - const BYTE stream_type = ReadByte(); - switch (stream_type) { - case 1: - s.m_PID = ReadShort(); - break; - case 2: - case 4: - ReadShort(); - s.m_PID = ReadShort(); - break; - case 3: - ReadByte(); - s.m_PID = ReadShort(); - break; - } - - if (!SetPos(Pos + len)) { - return E_FAIL; - } - - len = ReadByte(); - GetPos(Pos); - - for (const auto& stream : stn.m_Streams) { - if (s.m_PID == stream.m_PID) { - return SetPos(Pos + len) ? S_OK : E_FAIL; - } - } - - s.m_Type = (PES_STREAM_TYPE)ReadByte(); - switch (s.m_Type) { - case VIDEO_STREAM_MPEG1: - case VIDEO_STREAM_MPEG2: - case VIDEO_STREAM_H264: - case MVC_H264: - case VIDEO_STREAM_HEVC: - case VIDEO_STREAM_VC1: { - const BYTE Temp = ReadByte(); - s.m_VideoFormat = (BDVM_VideoFormat)(Temp >> 4); - s.m_FrameRate = (BDVM_FrameRate)(Temp & 0xf); - } - break; - case AUDIO_STREAM_MPEG1: - case AUDIO_STREAM_MPEG2: - case AUDIO_STREAM_LPCM: - case AUDIO_STREAM_AC3: - case AUDIO_STREAM_DTS: - case AUDIO_STREAM_AC3_TRUE_HD: - case AUDIO_STREAM_AC3_PLUS: - case AUDIO_STREAM_DTS_HD: - case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: - case SECONDARY_AUDIO_AC3_PLUS: - case SECONDARY_AUDIO_DTS_HD: { - const BYTE Temp = ReadByte(); - s.m_ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); - s.m_SampleRate = (BDVM_SampleRate)(Temp & 0xF); - - ReadLang(s); - } - break; - case PRESENTATION_GRAPHICS_STREAM: - case INTERACTIVE_GRAPHICS_STREAM: - ReadLang(s); - break; - case SUBTITLE_STREAM: - ReadByte(); // bd_char_code - ReadLang(s); - break; - } - - stn.m_Streams.emplace_back(s); - - return SetPos(Pos + len) ? S_OK : E_FAIL; -} - -HRESULT CHdmvClipInfo::ReadSTNInfo() { - ReadShort(); // length - ReadShort(); // reserved_for_future_use - - stn.num_video = ReadByte(); // number of Primary Video Streams - stn.num_audio = ReadByte(); // number of Primary Audio Streams - stn.num_pg = ReadByte(); // number of Presentation Graphic Streams - stn.num_ig = ReadByte(); // number of Interactive Graphic Streams - stn.num_secondary_audio = ReadByte(); // number of Secondary Audio Streams - stn.num_secondary_video = ReadByte(); // number of Secondary Video Streams - stn.num_pip_pg = ReadByte(); // number of Presentation Graphic Streams - - Skip(5); // reserved_for_future_use - - for (BYTE i = 0; i < stn.num_video; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - } - - for (BYTE i = 0; i < stn.num_audio; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - } - - for (BYTE i = 0; i < (stn.num_pg + stn.num_pip_pg); i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - } - - for (BYTE i = 0; i < stn.num_ig; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - } - - for (BYTE i = 0; i < stn.num_secondary_audio; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - - // Secondary Audio Extra Attributes - const BYTE num_secondary_audio_extra = ReadByte(); - ReadByte(); - if (num_secondary_audio_extra) { - Skip(num_secondary_audio_extra); - if (num_secondary_audio_extra % 2) { - ReadByte(); - } - } - } - - for (BYTE i = 0; i < stn.num_secondary_video; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - - // Secondary Video Extra Attributes - const BYTE num_secondary_video_extra = ReadByte(); - ReadByte(); - if (num_secondary_video_extra) { - Skip(num_secondary_video_extra); - if (num_secondary_video_extra % 2) { - ReadByte(); - } - } - - const BYTE num_pip_pg_extra = ReadByte(); - ReadByte(); - if (num_pip_pg_extra) { - Skip(num_pip_pg_extra); - if (num_pip_pg_extra % 2) { - ReadByte(); - } - } - } - - return S_OK; -} - -HRESULT CHdmvClipInfo::ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, HdmvPlaylist& Playlist) -{ - CPath Path(strPlaylistFile); - rtDuration = 0; - - // Get BDMV folder - Path.RemoveFileSpec(); - Path.RemoveFileSpec(); - - m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); - - if (m_hFile != INVALID_HANDLE_VALUE) { - BYTE Buff[100]; - bool bDuplicate = false; - ReadBuffer(Buff, 4); - if (memcmp(Buff, "MPLS", 4)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - ReadBuffer(Buff, 4); - if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - LARGE_INTEGER size = {}; - GetFileSizeEx(m_hFile, &size); - Playlist.m_mpls_size = size.QuadPart; - - LARGE_INTEGER Pos; - unsigned short nPlaylistItems; - - Pos.QuadPart = ReadDword(); // PlayList_start_address - ReadDword(); // PlayListMark_start_address - - // PlayList() - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - ReadDword(); // length - ReadShort(); // reserved_for_future_use - nPlaylistItems = ReadShort(); // number_of_PlayItems - ReadShort(); // number_of_SubPaths - - Pos.QuadPart += 10; - for (size_t i = 0; i < nPlaylistItems; i++) { - DWORD dwTemp; - PlaylistItem Item; - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - Pos.QuadPart += ReadShort() + 2; - ReadBuffer(Buff, 5); - Item.m_strFileName.Format(_T("%s\\STREAM\\%c%c%c%c%c.M2TS"), static_cast(Path), Buff[0], Buff[1], Buff[2], Buff[3], Buff[4]); - - ReadBuffer(Buff, 4); - if (memcmp(Buff, "M2TS", 4)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - ReadBuffer(Buff, 3); - const BYTE is_multi_angle = (Buff[1] >> 4) & 0x1; - - dwTemp = ReadDword(); - Item.m_rtIn = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits! - - dwTemp = ReadDword(); - Item.m_rtOut = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits! - - rtDuration += (Item.m_rtOut - Item.m_rtIn); - - Skip(8); // mpls uo - ReadByte(); - ReadByte(); // still mode - ReadShort(); // still time - BYTE angle_count = 1; - if (is_multi_angle) { - angle_count = ReadByte(); - if (angle_count < 1) { - angle_count = 1; - } - ReadByte(); - } - for (BYTE j = 1; j < angle_count; j++) { - Skip(9); // M2TS file name - ReadByte(); // stc_id - } - - // stn - ReadSTNInfo(); - - if (Playlist.contains(Item)) { - bDuplicate = true; - } - Playlist.emplace_back(Item); - - //TRACE(_T("File : %s, Duration : %s, Total duration : %s\n"), strTemp, ReftimeToString (rtOut - rtIn), ReftimeToString (rtDuration)); - } - - CloseFile(S_OK); - if (!stn.m_Streams.empty()) { - for (const auto& stream : stn.m_Streams) { - switch (stream.m_VideoFormat) { - case BDVM_VideoFormat_480i: - case BDVM_VideoFormat_480p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 480u); - break; - case BDVM_VideoFormat_576i: - case BDVM_VideoFormat_576p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 576u); - break; - case BDVM_VideoFormat_720p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 720u); - break; - case BDVM_VideoFormat_1080i: - case BDVM_VideoFormat_1080p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 1080u); - break; - case BDVM_VideoFormat_2160p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 2160u); - break; - default: - break; - } - } - } - return bDuplicate ? S_FALSE : S_OK; - } - - return AmHresultFromWin32(GetLastError()); -} - -HRESULT CHdmvClipInfo::ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters) -{ - CPath Path(strPlaylistFile); - - // Get BDMV folder - Path.RemoveFileSpec(); - Path.RemoveFileSpec(); - - m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); - - if (m_hFile != INVALID_HANDLE_VALUE) { - REFERENCE_TIME* rtOffset = DEBUG_NEW REFERENCE_TIME[PlaylistItems.GetCount()]; - REFERENCE_TIME rtSum = 0; - int nIndex = 0; - BYTE Buff[100]; - - POSITION pos = PlaylistItems.GetHeadPosition(); - while (pos) { - CHdmvClipInfo::PlaylistItem& PI = PlaylistItems.GetNext(pos); - - rtOffset[nIndex] = rtSum - PI.m_rtIn; - rtSum = rtSum + PI.Duration(); - nIndex++; - } - - ReadBuffer(Buff, 4); - if (memcmp(Buff, "MPLS", 4)) { - SAFE_DELETE_ARRAY(rtOffset); - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - ReadBuffer(Buff, 4); - if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { - SAFE_DELETE_ARRAY(rtOffset); - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - LARGE_INTEGER Pos; - unsigned short nMarkCount; - - ReadDword(); // PlayList_start_address - Pos.QuadPart = ReadDword(); // PlayListMark_start_address - - // PlayListMark() - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - ReadDword(); // length - nMarkCount = ReadShort(); // number_of_PlayList_marks - for (size_t i = 0; i < nMarkCount; i++) { - PlaylistChapter Chapter; - - ReadByte(); // reserved_for_future_use - Chapter.m_nMarkType = (PlaylistMarkType)ReadByte(); // mark_type - Chapter.m_nPlayItemId = ReadShort(); // ref_to_PlayItem_id - Chapter.m_rtTimestamp = 20000i64 * ReadDword() / 90 + rtOffset[Chapter.m_nPlayItemId]; // mark_time_stamp - Chapter.m_nEntryPID = ReadShort(); // entry_ES_PID - Chapter.m_rtDuration = 20000i64 * ReadDword() / 90; // duration - - Chapters.AddTail(Chapter); - - //TRACE(_T("Chapter %d : %s\n"), i, ReftimeToString(Chapter.m_rtTimestamp)); - } - - CloseFile(S_OK); - SAFE_DELETE_ARRAY(rtOffset); - return S_OK; - } - - return AmHresultFromWin32(GetLastError()); -} - -#define MIN_LIMIT 3 - -HRESULT CHdmvClipInfo::FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, HdmvPlaylist& MainPlaylist, HdmvPlaylist& MPLSPlaylists) -{ - HRESULT hr = E_FAIL; - - CString strPath(strFolder); - CString strFilter; - - MPLSPlaylists.clear(); - - HdmvPlaylist Playlist; - WIN32_FIND_DATA fd; - ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); - - strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); - strPath.Replace(_T("\\STREAM\\"), _T("\\")); - strPath = AddSlash(strPath); - strPath += _T("BDMV\\"); - strFilter.Format(_T("%sPLAYLIST\\*.mpls"), strPath.GetString()); - - HANDLE hFind = FindFirstFile(strFilter, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - std::vector PlaylistArray; - - REFERENCE_TIME rtMax = 0; - REFERENCE_TIME rtCurrent; - CString strCurrentPlaylist; - __int64 mpls_size_max = 0; - unsigned max_video_res = 0u; - do { - strCurrentPlaylist.Format(_T("%sPLAYLIST\\%s"), strPath.GetString(), fd.cFileName); - Playlist.clear(); - - // Main movie shouldn't have duplicate M2TS filename... - if (ReadPlaylist(strCurrentPlaylist, rtCurrent, Playlist) == S_OK) { - if ((rtCurrent > rtMax && Playlist.m_max_video_res >= max_video_res) - || (rtCurrent == rtMax && Playlist.m_mpls_size > mpls_size_max) - || ((rtCurrent < rtMax && rtCurrent >= rtMax / 2) && Playlist.m_max_video_res > max_video_res)) { - rtMax = rtCurrent; - mpls_size_max = Playlist.m_mpls_size; - max_video_res = Playlist.m_max_video_res; - strPlaylistFile = strCurrentPlaylist; - MainPlaylist.clear(); - MainPlaylist.insert(std::end(MainPlaylist), std::begin(Playlist), std::end(Playlist)); - hr = S_OK; - } - - if (rtCurrent >= (REFERENCE_TIME)MIN_LIMIT * 600000000) { - // Search duplicate playlists ... - bool duplicate = false; - if (!MPLSPlaylists.empty()) { - for (const auto& item : PlaylistArray) { - if (item.size() != Playlist.size()) { - continue; - } - - duplicate = true; - for (size_t i = 0; i < item.size() && duplicate; i++) { - if (item[i] == Playlist[i]) { - continue; - } - - duplicate = false; - } - - if (duplicate) { - duplicate = (item.m_mpls_size == Playlist.m_mpls_size); - } - } - } - if (duplicate) { - continue; - } - - PlaylistItem Item; - Item.m_strFileName = strCurrentPlaylist; - Item.m_rtIn = 0; - Item.m_rtOut = rtCurrent; - MPLSPlaylists.emplace_back(Item); - PlaylistArray.emplace_back(Playlist); - } - - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - - if (MPLSPlaylists.size() > 1) { - std::sort(MPLSPlaylists.begin(), MPLSPlaylists.end(), std::greater()); - } - - return hr; -} - -//convert UTF8 const char to wstring. -std::wstring CW2WS(const char* str) -{ - int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - std::wstring wstrTo( size_needed, 0 ); - MultiByteToWideChar(CP_UTF8, 0, str, -1, &wstrTo[0], size_needed); - return wstrTo; -} - -bool CHdmvClipInfo::ReadMeta(LPCTSTR strFolder, CAtlList& meta) -{ - bool re = false; - CString strPath(strFolder); - CString strFilter; - - meta.RemoveAll(); - - strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); - strPath.Replace(_T("\\STREAM\\"), _T("\\")); - strPath += _T("\\BDMV\\"); - strPath.Replace(_T("\\\\"), _T("\\")); - strPath.Replace(_T("\\\\"), _T("\\")); - strFilter.Format(_T("%sMETA\\DL\\bdmt_*.xml"), strPath.GetString()); - - WIN32_FIND_DATA fd; - ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); - - HANDLE hFind = FindFirstFile(strFilter, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - std::wstring TempFileName(fd.cFileName); - std::match_results mr; - CHdmvClipInfo::BDMVMeta Item; - tinyxml2::XMLDocument doc; - CStringW FileName(fd.cFileName); - CStringW FilePath; - - bool matched = std::regex_search(TempFileName, mr, std::wregex(L"^bdmt_(\\w+).xml$")); - - if (matched) { - Item.langcode = mr[1].str().c_str(); - } - else { - Item.langcode = L""; - } - - FilePath.Format(L"%sMETA\\DL\\", strPath.GetString()); - FilePath += FileName; - FILE* f; - if (!_wfopen_s(&f, FilePath.GetString(), L"rb")) { - doc.LoadFile(f); - fclose(f); - - XMLElement* rootNote(doc.RootElement()); - if (rootNote && !strcmp(rootNote->Name(), "disclib")) { - XMLElement* discinfo = rootNote->FirstChildElement("di:discinfo"); - if (discinfo != NULL) { - XMLElement* title = discinfo->FirstChildElement("di:title"); - if (title != NULL) { - XMLElement* name = title->FirstChildElement("di:name"); - if (name != NULL) { - Item.title = CW2WS(name->GetText()).c_str(); - } - } - } - } - } - - if (!Item.title.IsEmpty()) { - meta.AddTail(Item); - re = true; - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - - return re; -} +/* + * (C) 2008-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include "HdmvClipInfo.h" +#include "DSUtil.h" +#include "ISOLang.h" +#include "tinyxml2/library/tinyxml2.h" +#include +#include "FileHandle.h" +#include "ISOLang.h" +using namespace tinyxml2; + +CHdmvClipInfo::CHdmvClipInfo() + : SequenceInfo_start_address(0) + , ProgramInfo_start_address(0) + , m_hFile(INVALID_HANDLE_VALUE) + , m_bIsHdmv(false) +{ +} + +CHdmvClipInfo::~CHdmvClipInfo() +{ + CloseFile(S_OK); +} + +HRESULT CHdmvClipInfo::CloseFile(HRESULT hr) +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } + return hr; +} + +DWORD CHdmvClipInfo::ReadDword() +{ + return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte(); +} + +short CHdmvClipInfo::ReadShort() +{ + return ReadByte() << 8 | ReadByte(); +} + +BYTE CHdmvClipInfo::ReadByte() +{ + BYTE bVal; + DWORD dwRead; + VERIFY(ReadFile(m_hFile, &bVal, sizeof(bVal), &dwRead, nullptr)); + + return bVal; +} + +BOOL CHdmvClipInfo::Skip(LONGLONG nLen) { + LARGE_INTEGER newPos = {}; + newPos.QuadPart = nLen; + return SetFilePointerEx(m_hFile, newPos, nullptr, FILE_CURRENT); +} + +BOOL CHdmvClipInfo::GetPos(LONGLONG& Pos) { + LARGE_INTEGER curPos = {}; + const BOOL bRet = SetFilePointerEx(m_hFile, curPos, &curPos, FILE_CURRENT); + Pos = curPos.QuadPart; + + return bRet; +} +BOOL CHdmvClipInfo::SetPos(LONGLONG Pos, DWORD dwMoveMethod/* = FILE_BEGIN*/) { + LARGE_INTEGER newPos = {}; + newPos.QuadPart = Pos; + return SetFilePointerEx(m_hFile, newPos, nullptr, dwMoveMethod); +} + +HRESULT CHdmvClipInfo::ReadLang(Stream& s) { + ReadBuffer((BYTE*)s.m_LanguageCode, 3); + s.m_LCID = ISOLang::ISO6392ToLcid(s.m_LanguageCode); + + return S_OK; +} + +void CHdmvClipInfo::ReadBuffer(BYTE* pBuff, DWORD nLen) +{ + DWORD dwRead; + VERIFY(ReadFile(m_hFile, pBuff, nLen, &dwRead, nullptr)); +} + +HRESULT CHdmvClipInfo::ReadProgramInfo() +{ + BYTE number_of_program_sequences; + LARGE_INTEGER Pos; + + m_Streams.RemoveAll(); + Pos.QuadPart = ProgramInfo_start_address; + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + + ReadDword(); //length + ReadByte(); //reserved_for_word_align + number_of_program_sequences = (BYTE)ReadByte(); + int iStream = 0; + for (size_t i = 0; i < number_of_program_sequences; i++) { + ReadDword(); //SPN_program_sequence_start + ReadShort(); //program_map_PID + BYTE number_of_streams_in_ps = (BYTE)ReadByte(); //number_of_streams_in_ps + ReadByte(); //reserved_for_future_use + + for (size_t stream_index = 0; stream_index < number_of_streams_in_ps; stream_index++) { + m_Streams.SetCount(iStream + 1); + m_Streams[iStream].m_PID = ReadShort(); // stream_PID + + // == StreamCodingInfo + Pos.QuadPart = 0; + SetFilePointerEx(m_hFile, Pos, &Pos, FILE_CURRENT); + Pos.QuadPart += ReadByte() + 1; // length + m_Streams[iStream].m_Type = (PES_STREAM_TYPE)ReadByte(); + + switch (m_Streams[iStream].m_Type) { + case VIDEO_STREAM_MPEG1: + case VIDEO_STREAM_MPEG2: + case VIDEO_STREAM_H264: + case VIDEO_STREAM_VC1: + case VIDEO_STREAM_HEVC: { + UINT8 Temp = ReadByte(); + BDVM_VideoFormat VideoFormat = (BDVM_VideoFormat)(Temp >> 4); + BDVM_FrameRate FrameRate = (BDVM_FrameRate)(Temp & 0xf); + Temp = ReadByte(); + BDVM_AspectRatio AspectRatio = (BDVM_AspectRatio)(Temp >> 4); + + m_Streams[iStream].m_VideoFormat = VideoFormat; + m_Streams[iStream].m_FrameRate = FrameRate; + m_Streams[iStream].m_AspectRatio = AspectRatio; + } + break; + case AUDIO_STREAM_MPEG1: + case AUDIO_STREAM_MPEG2: + case AUDIO_STREAM_LPCM: + case AUDIO_STREAM_AC3: + case AUDIO_STREAM_DTS: + case AUDIO_STREAM_AC3_TRUE_HD: + case AUDIO_STREAM_AC3_PLUS: + case AUDIO_STREAM_DTS_HD: + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + case SECONDARY_AUDIO_AC3_PLUS: + case SECONDARY_AUDIO_DTS_HD: { + UINT8 Temp = ReadByte(); + BDVM_ChannelLayout ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); + BDVM_SampleRate SampleRate = (BDVM_SampleRate)(Temp & 0xF); + + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LanguageCode[3] = '\0'; + m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); + m_Streams[iStream].m_ChannelLayout = ChannelLayout; + m_Streams[iStream].m_SampleRate = SampleRate; + } + break; + case PRESENTATION_GRAPHICS_STREAM: + case INTERACTIVE_GRAPHICS_STREAM: { + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LanguageCode[3] = '\0'; + m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); + } + break; + case SUBTITLE_STREAM: { + ReadByte(); // Should this really be here? + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LanguageCode[3] = '\0'; + m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); + } + break; + default: + break; + } + + iStream++; + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + } + } + return S_OK; +} + +HRESULT CHdmvClipInfo::ReadInfo(LPCTSTR strFile) +{ + m_bIsHdmv = false; + m_hFile = CreateFile(strFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); + + if (m_hFile != INVALID_HANDLE_VALUE) { + BYTE Buff[100]; + ReadBuffer(Buff, 4); + if (memcmp(Buff, "HDMV", 4)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + SequenceInfo_start_address = ReadDword(); + ProgramInfo_start_address = ReadDword(); + + ReadProgramInfo(); + + m_bIsHdmv = true; + + return CloseFile(S_OK); + } + + return AmHresultFromWin32(GetLastError()); +} + +CHdmvClipInfo::Stream* CHdmvClipInfo::FindStream(short wPID) +{ + size_t nStreams = m_Streams.GetCount(); + for (size_t i = 0; i < nStreams; i++) { + if (m_Streams[i].m_PID == wPID) { + return &m_Streams[i]; + } + } + + return nullptr; +} + +LPCTSTR CHdmvClipInfo::Stream::Format() +{ + switch (m_Type) { + case VIDEO_STREAM_MPEG1: + return _T("Mpeg1"); + case VIDEO_STREAM_MPEG2: + return _T("Mpeg2"); + case VIDEO_STREAM_H264: + return _T("H264"); + case VIDEO_STREAM_VC1: + return _T("VC1"); + case VIDEO_STREAM_HEVC: + return _T("HEVC"); + case AUDIO_STREAM_MPEG1: + return _T("MPEG1"); + case AUDIO_STREAM_MPEG2: + return _T("MPEG2"); + case AUDIO_STREAM_LPCM: + return _T("LPCM"); + case AUDIO_STREAM_AC3: + return _T("AC3"); + case AUDIO_STREAM_DTS: + return _T("DTS"); + case AUDIO_STREAM_AC3_TRUE_HD: + return _T("MLP"); + case AUDIO_STREAM_AC3_PLUS: + return _T("DD+"); + case AUDIO_STREAM_DTS_HD: + return _T("DTS-HD"); + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + return _T("DTS-HD XLL"); + case SECONDARY_AUDIO_AC3_PLUS: + return _T("Sec DD+"); + case SECONDARY_AUDIO_DTS_HD: + return _T("Sec DTS-HD"); + case PRESENTATION_GRAPHICS_STREAM: + return _T("PG"); + case INTERACTIVE_GRAPHICS_STREAM: + return _T("IG"); + case SUBTITLE_STREAM: + return _T("Text"); + default: + return _T("Unknown"); + } +} + +HRESULT CHdmvClipInfo::ReadStreamInfo() { + BYTE len = ReadByte(); + LONGLONG Pos = 0; + GetPos(Pos); + + Stream s; + const BYTE stream_type = ReadByte(); + switch (stream_type) { + case 1: + s.m_PID = ReadShort(); + break; + case 2: + case 4: + ReadShort(); + s.m_PID = ReadShort(); + break; + case 3: + ReadByte(); + s.m_PID = ReadShort(); + break; + } + + if (!SetPos(Pos + len)) { + return E_FAIL; + } + + len = ReadByte(); + GetPos(Pos); + + for (const auto& stream : stn.m_Streams) { + if (s.m_PID == stream.m_PID) { + return SetPos(Pos + len) ? S_OK : E_FAIL; + } + } + + s.m_Type = (PES_STREAM_TYPE)ReadByte(); + switch (s.m_Type) { + case VIDEO_STREAM_MPEG1: + case VIDEO_STREAM_MPEG2: + case VIDEO_STREAM_H264: + case MVC_H264: + case VIDEO_STREAM_HEVC: + case VIDEO_STREAM_VC1: { + const BYTE Temp = ReadByte(); + s.m_VideoFormat = (BDVM_VideoFormat)(Temp >> 4); + s.m_FrameRate = (BDVM_FrameRate)(Temp & 0xf); + } + break; + case AUDIO_STREAM_MPEG1: + case AUDIO_STREAM_MPEG2: + case AUDIO_STREAM_LPCM: + case AUDIO_STREAM_AC3: + case AUDIO_STREAM_DTS: + case AUDIO_STREAM_AC3_TRUE_HD: + case AUDIO_STREAM_AC3_PLUS: + case AUDIO_STREAM_DTS_HD: + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + case SECONDARY_AUDIO_AC3_PLUS: + case SECONDARY_AUDIO_DTS_HD: { + const BYTE Temp = ReadByte(); + s.m_ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); + s.m_SampleRate = (BDVM_SampleRate)(Temp & 0xF); + + ReadLang(s); + } + break; + case PRESENTATION_GRAPHICS_STREAM: + case INTERACTIVE_GRAPHICS_STREAM: + ReadLang(s); + break; + case SUBTITLE_STREAM: + ReadByte(); // bd_char_code + ReadLang(s); + break; + } + + stn.m_Streams.emplace_back(s); + + return SetPos(Pos + len) ? S_OK : E_FAIL; +} + +HRESULT CHdmvClipInfo::ReadSTNInfo() { + ReadShort(); // length + ReadShort(); // reserved_for_future_use + + stn.num_video = ReadByte(); // number of Primary Video Streams + stn.num_audio = ReadByte(); // number of Primary Audio Streams + stn.num_pg = ReadByte(); // number of Presentation Graphic Streams + stn.num_ig = ReadByte(); // number of Interactive Graphic Streams + stn.num_secondary_audio = ReadByte(); // number of Secondary Audio Streams + stn.num_secondary_video = ReadByte(); // number of Secondary Video Streams + stn.num_pip_pg = ReadByte(); // number of Presentation Graphic Streams + + Skip(5); // reserved_for_future_use + + for (BYTE i = 0; i < stn.num_video; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + } + + for (BYTE i = 0; i < stn.num_audio; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + } + + for (BYTE i = 0; i < (stn.num_pg + stn.num_pip_pg); i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + } + + for (BYTE i = 0; i < stn.num_ig; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + } + + for (BYTE i = 0; i < stn.num_secondary_audio; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + + // Secondary Audio Extra Attributes + const BYTE num_secondary_audio_extra = ReadByte(); + ReadByte(); + if (num_secondary_audio_extra) { + Skip(num_secondary_audio_extra); + if (num_secondary_audio_extra % 2) { + ReadByte(); + } + } + } + + for (BYTE i = 0; i < stn.num_secondary_video; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + + // Secondary Video Extra Attributes + const BYTE num_secondary_video_extra = ReadByte(); + ReadByte(); + if (num_secondary_video_extra) { + Skip(num_secondary_video_extra); + if (num_secondary_video_extra % 2) { + ReadByte(); + } + } + + const BYTE num_pip_pg_extra = ReadByte(); + ReadByte(); + if (num_pip_pg_extra) { + Skip(num_pip_pg_extra); + if (num_pip_pg_extra % 2) { + ReadByte(); + } + } + } + + return S_OK; +} + +HRESULT CHdmvClipInfo::ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, HdmvPlaylist& Playlist) +{ + CPath Path(strPlaylistFile); + rtDuration = 0; + + // Get BDMV folder + Path.RemoveFileSpec(); + Path.RemoveFileSpec(); + + m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); + + if (m_hFile != INVALID_HANDLE_VALUE) { + BYTE Buff[100]; + bool bDuplicate = false; + ReadBuffer(Buff, 4); + if (memcmp(Buff, "MPLS", 4)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + LARGE_INTEGER size = {}; + GetFileSizeEx(m_hFile, &size); + Playlist.m_mpls_size = size.QuadPart; + + LARGE_INTEGER Pos; + unsigned short nPlaylistItems; + + Pos.QuadPart = ReadDword(); // PlayList_start_address + ReadDword(); // PlayListMark_start_address + + // PlayList() + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + ReadDword(); // length + ReadShort(); // reserved_for_future_use + nPlaylistItems = ReadShort(); // number_of_PlayItems + ReadShort(); // number_of_SubPaths + + Pos.QuadPart += 10; + for (size_t i = 0; i < nPlaylistItems; i++) { + DWORD dwTemp; + PlaylistItem Item; + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + Pos.QuadPart += ReadShort() + 2; + ReadBuffer(Buff, 5); + Item.m_strFileName.Format(_T("%s\\STREAM\\%c%c%c%c%c.M2TS"), static_cast(Path), Buff[0], Buff[1], Buff[2], Buff[3], Buff[4]); + + ReadBuffer(Buff, 4); + if (memcmp(Buff, "M2TS", 4)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + ReadBuffer(Buff, 3); + const BYTE is_multi_angle = (Buff[1] >> 4) & 0x1; + + dwTemp = ReadDword(); + Item.m_rtIn = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits! + + dwTemp = ReadDword(); + Item.m_rtOut = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits! + + rtDuration += (Item.m_rtOut - Item.m_rtIn); + + Skip(8); // mpls uo + ReadByte(); + ReadByte(); // still mode + ReadShort(); // still time + BYTE angle_count = 1; + if (is_multi_angle) { + angle_count = ReadByte(); + if (angle_count < 1) { + angle_count = 1; + } + ReadByte(); + } + for (BYTE j = 1; j < angle_count; j++) { + Skip(9); // M2TS file name + ReadByte(); // stc_id + } + + // stn + ReadSTNInfo(); + + if (Playlist.contains(Item)) { + bDuplicate = true; + } + Playlist.emplace_back(Item); + + //TRACE(_T("File : %s, Duration : %s, Total duration : %s\n"), strTemp, ReftimeToString (rtOut - rtIn), ReftimeToString (rtDuration)); + } + + CloseFile(S_OK); + if (!stn.m_Streams.empty()) { + for (const auto& stream : stn.m_Streams) { + switch (stream.m_VideoFormat) { + case BDVM_VideoFormat_480i: + case BDVM_VideoFormat_480p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 480u); + break; + case BDVM_VideoFormat_576i: + case BDVM_VideoFormat_576p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 576u); + break; + case BDVM_VideoFormat_720p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 720u); + break; + case BDVM_VideoFormat_1080i: + case BDVM_VideoFormat_1080p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 1080u); + break; + case BDVM_VideoFormat_2160p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 2160u); + break; + default: + break; + } + } + } + return bDuplicate ? S_FALSE : S_OK; + } + + return AmHresultFromWin32(GetLastError()); +} + +HRESULT CHdmvClipInfo::ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters) +{ + CPath Path(strPlaylistFile); + + // Get BDMV folder + Path.RemoveFileSpec(); + Path.RemoveFileSpec(); + + m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); + + if (m_hFile != INVALID_HANDLE_VALUE) { + REFERENCE_TIME* rtOffset = DEBUG_NEW REFERENCE_TIME[PlaylistItems.GetCount()]; + REFERENCE_TIME rtSum = 0; + int nIndex = 0; + BYTE Buff[100]; + + POSITION pos = PlaylistItems.GetHeadPosition(); + while (pos) { + CHdmvClipInfo::PlaylistItem& PI = PlaylistItems.GetNext(pos); + + rtOffset[nIndex] = rtSum - PI.m_rtIn; + rtSum = rtSum + PI.Duration(); + nIndex++; + } + + ReadBuffer(Buff, 4); + if (memcmp(Buff, "MPLS", 4)) { + SAFE_DELETE_ARRAY(rtOffset); + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { + SAFE_DELETE_ARRAY(rtOffset); + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + LARGE_INTEGER Pos; + unsigned short nMarkCount; + + ReadDword(); // PlayList_start_address + Pos.QuadPart = ReadDword(); // PlayListMark_start_address + + // PlayListMark() + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + ReadDword(); // length + nMarkCount = ReadShort(); // number_of_PlayList_marks + for (size_t i = 0; i < nMarkCount; i++) { + PlaylistChapter Chapter; + + ReadByte(); // reserved_for_future_use + Chapter.m_nMarkType = (PlaylistMarkType)ReadByte(); // mark_type + Chapter.m_nPlayItemId = ReadShort(); // ref_to_PlayItem_id + Chapter.m_rtTimestamp = 20000i64 * ReadDword() / 90 + rtOffset[Chapter.m_nPlayItemId]; // mark_time_stamp + Chapter.m_nEntryPID = ReadShort(); // entry_ES_PID + Chapter.m_rtDuration = 20000i64 * ReadDword() / 90; // duration + + Chapters.AddTail(Chapter); + + //TRACE(_T("Chapter %d : %s\n"), i, ReftimeToString(Chapter.m_rtTimestamp)); + } + + CloseFile(S_OK); + SAFE_DELETE_ARRAY(rtOffset); + return S_OK; + } + + return AmHresultFromWin32(GetLastError()); +} + +#define MIN_LIMIT 3 + +HRESULT CHdmvClipInfo::FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, HdmvPlaylist& MainPlaylist, HdmvPlaylist& MPLSPlaylists) +{ + HRESULT hr = E_FAIL; + + CString strPath(strFolder); + CString strFilter; + + MPLSPlaylists.clear(); + + HdmvPlaylist Playlist; + WIN32_FIND_DATA fd; + ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); + + strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); + strPath.Replace(_T("\\STREAM\\"), _T("\\")); + strPath = AddSlash(strPath); + strPath += _T("BDMV\\"); + strFilter.Format(_T("%sPLAYLIST\\*.mpls"), strPath.GetString()); + + HANDLE hFind = FindFirstFile(strFilter, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + std::vector PlaylistArray; + + REFERENCE_TIME rtMax = 0; + REFERENCE_TIME rtCurrent; + CString strCurrentPlaylist; + __int64 mpls_size_max = 0; + unsigned max_video_res = 0u; + do { + strCurrentPlaylist.Format(_T("%sPLAYLIST\\%s"), strPath.GetString(), fd.cFileName); + Playlist.clear(); + + // Main movie shouldn't have duplicate M2TS filename... + if (ReadPlaylist(strCurrentPlaylist, rtCurrent, Playlist) == S_OK) { + if ((rtCurrent > rtMax && Playlist.m_max_video_res >= max_video_res) + || (rtCurrent == rtMax && Playlist.m_mpls_size > mpls_size_max) + || ((rtCurrent < rtMax && rtCurrent >= rtMax / 2) && Playlist.m_max_video_res > max_video_res)) { + rtMax = rtCurrent; + mpls_size_max = Playlist.m_mpls_size; + max_video_res = Playlist.m_max_video_res; + strPlaylistFile = strCurrentPlaylist; + MainPlaylist.clear(); + MainPlaylist.insert(std::end(MainPlaylist), std::begin(Playlist), std::end(Playlist)); + hr = S_OK; + } + + if (rtCurrent >= (REFERENCE_TIME)MIN_LIMIT * 600000000) { + // Search duplicate playlists ... + bool duplicate = false; + if (!MPLSPlaylists.empty()) { + for (const auto& item : PlaylistArray) { + if (item.size() != Playlist.size()) { + continue; + } + + duplicate = true; + for (size_t i = 0; i < item.size() && duplicate; i++) { + if (item[i] == Playlist[i]) { + continue; + } + + duplicate = false; + } + + if (duplicate) { + duplicate = (item.m_mpls_size == Playlist.m_mpls_size); + } + } + } + if (duplicate) { + continue; + } + + PlaylistItem Item; + Item.m_strFileName = strCurrentPlaylist; + Item.m_rtIn = 0; + Item.m_rtOut = rtCurrent; + MPLSPlaylists.emplace_back(Item); + PlaylistArray.emplace_back(Playlist); + } + + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + + if (MPLSPlaylists.size() > 1) { + std::sort(MPLSPlaylists.begin(), MPLSPlaylists.end(), std::greater()); + } + + return hr; +} + +//convert UTF8 const char to wstring. +std::wstring CW2WS(const char* str) +{ + int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + std::wstring wstrTo( size_needed, 0 ); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &wstrTo[0], size_needed); + return wstrTo; +} + +bool CHdmvClipInfo::ReadMeta(LPCTSTR strFolder, CAtlList& meta) +{ + bool re = false; + CString strPath(strFolder); + CString strFilter; + + meta.RemoveAll(); + + strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); + strPath.Replace(_T("\\STREAM\\"), _T("\\")); + strPath += _T("\\BDMV\\"); + strPath.Replace(_T("\\\\"), _T("\\")); + strPath.Replace(_T("\\\\"), _T("\\")); + strFilter.Format(_T("%sMETA\\DL\\bdmt_*.xml"), strPath.GetString()); + + WIN32_FIND_DATA fd; + ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); + + HANDLE hFind = FindFirstFile(strFilter, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + std::wstring TempFileName(fd.cFileName); + std::match_results mr; + CHdmvClipInfo::BDMVMeta Item; + tinyxml2::XMLDocument doc; + CStringW FileName(fd.cFileName); + CStringW FilePath; + + bool matched = std::regex_search(TempFileName, mr, std::wregex(L"^bdmt_(\\w+).xml$")); + + if (matched) { + Item.langcode = mr[1].str().c_str(); + } + else { + Item.langcode = L""; + } + + FilePath.Format(L"%sMETA\\DL\\", strPath.GetString()); + FilePath += FileName; + FILE* f; + if (!_wfopen_s(&f, FilePath.GetString(), L"rb")) { + doc.LoadFile(f); + fclose(f); + + XMLElement* rootNote(doc.RootElement()); + if (rootNote && !strcmp(rootNote->Name(), "disclib")) { + XMLElement* discinfo = rootNote->FirstChildElement("di:discinfo"); + if (discinfo != NULL) { + XMLElement* title = discinfo->FirstChildElement("di:title"); + if (title != NULL) { + XMLElement* name = title->FirstChildElement("di:name"); + if (name != NULL) { + Item.title = CW2WS(name->GetText()).c_str(); + } + } + } + } + } + + if (!Item.title.IsEmpty()) { + meta.AddTail(Item); + re = true; + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + + return re; +} diff --git a/src/DSUtil/HdmvClipInfo.h b/src/DSUtil/HdmvClipInfo.h index 75dc822cc0a..678a1dba94d 100644 --- a/src/DSUtil/HdmvClipInfo.h +++ b/src/DSUtil/HdmvClipInfo.h @@ -1,189 +1,189 @@ -/* - * (C) 2008-2013, 2016 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 . - * - */ - -#pragma once - -#include "Mpeg2Def.h" -#include -#include - -enum BDVM_VideoFormat { - BDVM_VideoFormat_Unknown = 0, - BDVM_VideoFormat_480i = 1, - BDVM_VideoFormat_576i = 2, - BDVM_VideoFormat_480p = 3, - BDVM_VideoFormat_1080i = 4, - BDVM_VideoFormat_720p = 5, - BDVM_VideoFormat_1080p = 6, - BDVM_VideoFormat_576p = 7, - BDVM_VideoFormat_2160p = 8, -}; - -enum BDVM_FrameRate { - BDVM_FrameRate_Unknown = 0, - BDVM_FrameRate_23_976 = 1, - BDVM_FrameRate_24 = 2, - BDVM_FrameRate_25 = 3, - BDVM_FrameRate_29_97 = 4, - BDVM_FrameRate_50 = 6, - BDVM_FrameRate_59_94 = 7 -}; - -enum BDVM_AspectRatio { - BDVM_AspectRatio_Unknown = 0, - BDVM_AspectRatio_4_3 = 2, - BDVM_AspectRatio_16_9 = 3, - BDVM_AspectRatio_2_21 = 4 -}; - -enum BDVM_ChannelLayout { - BDVM_ChannelLayout_Unknown = 0, - BDVM_ChannelLayout_MONO = 1, - BDVM_ChannelLayout_STEREO = 3, - BDVM_ChannelLayout_MULTI = 6, - BDVM_ChannelLayout_COMBO = 12 -}; - -enum BDVM_SampleRate { - BDVM_SampleRate_Unknown = 0, - BDVM_SampleRate_48 = 1, - BDVM_SampleRate_96 = 4, - BDVM_SampleRate_192 = 5, - BDVM_SampleRate_48_192 = 12, - BDVM_SampleRate_48_96 = 14 -}; - -class CHdmvClipInfo -{ -public: - - struct Stream { - Stream() { - ZeroMemory(this, sizeof(*this)); - } - short m_PID = 0; - PES_STREAM_TYPE m_Type = INVALID; - char m_LanguageCode[4] = {0}; - LCID m_LCID = 0; - - // Valid for video types - BDVM_VideoFormat m_VideoFormat = BDVM_VideoFormat_Unknown; - BDVM_FrameRate m_FrameRate = BDVM_FrameRate_Unknown; - BDVM_AspectRatio m_AspectRatio = BDVM_AspectRatio_Unknown; - // Valid for audio types - BDVM_ChannelLayout m_ChannelLayout = BDVM_ChannelLayout_Unknown; - BDVM_SampleRate m_SampleRate = BDVM_SampleRate_Unknown; - - LPCTSTR Format(); - }; - - struct PlaylistItem { - CString m_strFileName; - REFERENCE_TIME m_rtIn = 0; - REFERENCE_TIME m_rtOut = 0; - - REFERENCE_TIME Duration() const { return m_rtOut - m_rtIn; } - - bool operator == (const PlaylistItem& pi) const { - return pi.m_strFileName == m_strFileName; - } - bool operator >(const PlaylistItem& pi) const { - return Duration() > pi.Duration(); - } - }; - class HdmvPlaylist : public std::vector { - public: - __int64 m_mpls_size = 0; - unsigned m_max_video_res = 0u; - bool contains(PlaylistItem& pli) { return std::find(begin(), end(), pli) != end(); } - }; - - enum PlaylistMarkType { - Reserved = 0x00, - EntryMark = 0x01, - LinkPoint = 0x02 - }; - - struct PlaylistChapter { - short m_nPlayItemId = 0; - PlaylistMarkType m_nMarkType = Reserved; - REFERENCE_TIME m_rtTimestamp = 0; - short m_nEntryPID = 0; - REFERENCE_TIME m_rtDuration = 0; - }; - - struct BDMVMeta { - CString langcode; - CString title; - }; - - CHdmvClipInfo(); - ~CHdmvClipInfo(); - - HRESULT ReadInfo(LPCTSTR strFile); - Stream* FindStream(short wPID); - bool IsHdmv() const { return m_bIsHdmv; }; - size_t GetStreamNumber() { return m_Streams.GetCount(); }; - Stream* GetStreamByIndex(size_t nIndex) { return (nIndex < m_Streams.GetCount()) ? &m_Streams[nIndex] : nullptr; }; - - HRESULT FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, HdmvPlaylist& MainPlaylist, HdmvPlaylist& MPLSPlaylists); - HRESULT ReadStreamInfo(); - HRESULT ReadSTNInfo(); - HRESULT ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, HdmvPlaylist& Playlist); - HRESULT ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters); - bool ReadMeta(LPCTSTR strFolder, CAtlList& meta); - -private: - DWORD SequenceInfo_start_address; - DWORD ProgramInfo_start_address; - - HANDLE m_hFile; - - CAtlArray m_Streams; - typedef std::vector Streams; - struct { - BYTE num_video = 0; - BYTE num_audio = 0; - BYTE num_pg = 0; - BYTE num_ig = 0; - BYTE num_secondary_audio = 0; - BYTE num_secondary_video = 0; - BYTE num_pip_pg = 0; - - Streams m_Streams; - } stn; - - - bool m_bIsHdmv; - - DWORD ReadDword(); - short ReadShort(); - BYTE ReadByte(); - - BOOL Skip(LONGLONG nLen); - BOOL GetPos(LONGLONG& Pos); - BOOL SetPos(LONGLONG Pos, DWORD dwMoveMethod = FILE_BEGIN); - - void ReadBuffer(BYTE* pBuff, DWORD nLen); - - HRESULT ReadLang(Stream& s); - HRESULT ReadProgramInfo(); - HRESULT CloseFile(HRESULT hr); -}; +/* + * (C) 2008-2013, 2016 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 . + * + */ + +#pragma once + +#include "Mpeg2Def.h" +#include +#include + +enum BDVM_VideoFormat { + BDVM_VideoFormat_Unknown = 0, + BDVM_VideoFormat_480i = 1, + BDVM_VideoFormat_576i = 2, + BDVM_VideoFormat_480p = 3, + BDVM_VideoFormat_1080i = 4, + BDVM_VideoFormat_720p = 5, + BDVM_VideoFormat_1080p = 6, + BDVM_VideoFormat_576p = 7, + BDVM_VideoFormat_2160p = 8, +}; + +enum BDVM_FrameRate { + BDVM_FrameRate_Unknown = 0, + BDVM_FrameRate_23_976 = 1, + BDVM_FrameRate_24 = 2, + BDVM_FrameRate_25 = 3, + BDVM_FrameRate_29_97 = 4, + BDVM_FrameRate_50 = 6, + BDVM_FrameRate_59_94 = 7 +}; + +enum BDVM_AspectRatio { + BDVM_AspectRatio_Unknown = 0, + BDVM_AspectRatio_4_3 = 2, + BDVM_AspectRatio_16_9 = 3, + BDVM_AspectRatio_2_21 = 4 +}; + +enum BDVM_ChannelLayout { + BDVM_ChannelLayout_Unknown = 0, + BDVM_ChannelLayout_MONO = 1, + BDVM_ChannelLayout_STEREO = 3, + BDVM_ChannelLayout_MULTI = 6, + BDVM_ChannelLayout_COMBO = 12 +}; + +enum BDVM_SampleRate { + BDVM_SampleRate_Unknown = 0, + BDVM_SampleRate_48 = 1, + BDVM_SampleRate_96 = 4, + BDVM_SampleRate_192 = 5, + BDVM_SampleRate_48_192 = 12, + BDVM_SampleRate_48_96 = 14 +}; + +class CHdmvClipInfo +{ +public: + + struct Stream { + Stream() { + ZeroMemory(this, sizeof(*this)); + } + short m_PID = 0; + PES_STREAM_TYPE m_Type = INVALID; + char m_LanguageCode[4] = {0}; + LCID m_LCID = 0; + + // Valid for video types + BDVM_VideoFormat m_VideoFormat = BDVM_VideoFormat_Unknown; + BDVM_FrameRate m_FrameRate = BDVM_FrameRate_Unknown; + BDVM_AspectRatio m_AspectRatio = BDVM_AspectRatio_Unknown; + // Valid for audio types + BDVM_ChannelLayout m_ChannelLayout = BDVM_ChannelLayout_Unknown; + BDVM_SampleRate m_SampleRate = BDVM_SampleRate_Unknown; + + LPCTSTR Format(); + }; + + struct PlaylistItem { + CString m_strFileName; + REFERENCE_TIME m_rtIn = 0; + REFERENCE_TIME m_rtOut = 0; + + REFERENCE_TIME Duration() const { return m_rtOut - m_rtIn; } + + bool operator == (const PlaylistItem& pi) const { + return pi.m_strFileName == m_strFileName; + } + bool operator >(const PlaylistItem& pi) const { + return Duration() > pi.Duration(); + } + }; + class HdmvPlaylist : public std::vector { + public: + __int64 m_mpls_size = 0; + unsigned m_max_video_res = 0u; + bool contains(PlaylistItem& pli) { return std::find(begin(), end(), pli) != end(); } + }; + + enum PlaylistMarkType { + Reserved = 0x00, + EntryMark = 0x01, + LinkPoint = 0x02 + }; + + struct PlaylistChapter { + short m_nPlayItemId = 0; + PlaylistMarkType m_nMarkType = Reserved; + REFERENCE_TIME m_rtTimestamp = 0; + short m_nEntryPID = 0; + REFERENCE_TIME m_rtDuration = 0; + }; + + struct BDMVMeta { + CString langcode; + CString title; + }; + + CHdmvClipInfo(); + ~CHdmvClipInfo(); + + HRESULT ReadInfo(LPCTSTR strFile); + Stream* FindStream(short wPID); + bool IsHdmv() const { return m_bIsHdmv; }; + size_t GetStreamNumber() { return m_Streams.GetCount(); }; + Stream* GetStreamByIndex(size_t nIndex) { return (nIndex < m_Streams.GetCount()) ? &m_Streams[nIndex] : nullptr; }; + + HRESULT FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, HdmvPlaylist& MainPlaylist, HdmvPlaylist& MPLSPlaylists); + HRESULT ReadStreamInfo(); + HRESULT ReadSTNInfo(); + HRESULT ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, HdmvPlaylist& Playlist); + HRESULT ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters); + bool ReadMeta(LPCTSTR strFolder, CAtlList& meta); + +private: + DWORD SequenceInfo_start_address; + DWORD ProgramInfo_start_address; + + HANDLE m_hFile; + + CAtlArray m_Streams; + typedef std::vector Streams; + struct { + BYTE num_video = 0; + BYTE num_audio = 0; + BYTE num_pg = 0; + BYTE num_ig = 0; + BYTE num_secondary_audio = 0; + BYTE num_secondary_video = 0; + BYTE num_pip_pg = 0; + + Streams m_Streams; + } stn; + + + bool m_bIsHdmv; + + DWORD ReadDword(); + short ReadShort(); + BYTE ReadByte(); + + BOOL Skip(LONGLONG nLen); + BOOL GetPos(LONGLONG& Pos); + BOOL SetPos(LONGLONG Pos, DWORD dwMoveMethod = FILE_BEGIN); + + void ReadBuffer(BYTE* pBuff, DWORD nLen); + + HRESULT ReadLang(Stream& s); + HRESULT ReadProgramInfo(); + HRESULT CloseFile(HRESULT hr); +}; diff --git a/src/DSUtil/MediaTypeEx.cpp b/src/DSUtil/MediaTypeEx.cpp index 2c8e8555397..16111001fa0 100644 --- a/src/DSUtil/MediaTypeEx.cpp +++ b/src/DSUtil/MediaTypeEx.cpp @@ -1,751 +1,751 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "DSUtil.h" -#include "MediaTypeEx.h" - -#include -#include "moreuuids.h" - -#pragma pack(push, 1) -struct DOLBYAC3WAVEFORMAT { - WAVEFORMATEX Format; - BYTE bBigEndian; - BYTE bsid; - BYTE lfeon; - BYTE copyrightb; - BYTE nAuxBitsCode; // Aux bits per frame -}; -#pragma pack(pop) - -CMediaTypeEx::CMediaTypeEx() -{ -} - -CMediaTypeEx::~CMediaTypeEx() -{ -} - -CString CMediaTypeEx::ToString(IPin* pPin) -{ - CString packing, type, codec, dim, rate, dur; - - // TODO - - if (majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { - packing = _T("Encrypted MPEG2 Pack"); - } else if (majortype == MEDIATYPE_MPEG2_PACK) { - packing = _T("MPEG2 Pack"); - } else if (majortype == MEDIATYPE_MPEG2_PES) { - packing = _T("MPEG2 PES"); - } - - if (majortype == MEDIATYPE_Video || subtype == MEDIASUBTYPE_MPEG2_VIDEO) { - type = _T("Video"); - - BITMAPINFOHEADER bih; - bool fBIH = ExtractBIH(this, &bih); - - int w, h, arx, ary; - bool fDim = ExtractDim(this, w, h, arx, ary); - - if (fBIH) { - codec = GetVideoCodecName(subtype, bih.biCompression); - } - - if (codec.IsEmpty()) { - if (formattype == FORMAT_MPEGVideo) { - codec = _T("MPEG1 Video"); - } else if (formattype == FORMAT_MPEG2_VIDEO) { - codec = _T("MPEG2 Video"); - } else if (formattype == FORMAT_DiracVideoInfo) { - codec = _T("Dirac Video"); - } - } - - if (fDim) { - dim.Format(_T("%dx%d"), w, h); - if (w * ary != h * arx) { - dim.AppendFormat(_T(" (%d:%d)"), arx, ary); - } - } - - if (formattype == FORMAT_VideoInfo || formattype == FORMAT_MPEGVideo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pbFormat; - if (vih->AvgTimePerFrame) { - rate.Format(_T("%0.3f"), 10000000.0f / vih->AvgTimePerFrame); - rate.TrimRight(_T('0')); // remove trailing zeros - rate.TrimRight(_T('.')); // remove the trailing dot - rate += _T("fps "); - } - if (vih->dwBitRate) { - rate.AppendFormat(_T("%ukbps"), vih->dwBitRate / 1000); - } - } else if (formattype == FORMAT_VideoInfo2 || formattype == FORMAT_MPEG2_VIDEO || formattype == FORMAT_DiracVideoInfo) { - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pbFormat; - if (vih->AvgTimePerFrame) { - rate.Format(_T("%0.3f"), 10000000.0f / vih->AvgTimePerFrame); - rate.TrimRight(_T('0')); // remove trailing zeros - rate.TrimRight(_T('.')); // remove the trailing dot - rate += _T("fps "); - } - if (vih->dwBitRate) { - rate.AppendFormat(_T("%ukbps"), vih->dwBitRate / 1000); - } - } - - rate.TrimRight(); - - if (subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { - type = _T("Subtitle"); - codec = _T("DVD Subpicture"); - } - } else if (majortype == MEDIATYPE_Audio || subtype == MEDIASUBTYPE_DOLBY_AC3) { - type = _T("Audio"); - - if (formattype == FORMAT_WaveFormatEx) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)Format(); - - if (wfe->wFormatTag/* > WAVE_FORMAT_PCM && wfe->wFormatTag < WAVE_FORMAT_EXTENSIBLE - && wfe->wFormatTag != WAVE_FORMAT_IEEE_FLOAT*/ - || subtype != GUID_NULL) { - codec = GetAudioCodecName(subtype, wfe->wFormatTag); - dim.Format(_T("%uHz"), wfe->nSamplesPerSec); - if (wfe->nChannels == 1) { - dim += _T(" mono"); - } else if (wfe->nChannels == 2) { - dim += _T(" stereo"); - } else { - dim.AppendFormat(_T(" %uch"), wfe->nChannels); - } - if (wfe->nAvgBytesPerSec) { - rate.Format(_T("%ukbps"), wfe->nAvgBytesPerSec * 8 / 1000); - } - } - } else if (formattype == FORMAT_VorbisFormat) { - VORBISFORMAT* vf = (VORBISFORMAT*)Format(); - - codec = GetAudioCodecName(subtype, 0); - dim.Format(_T("%luHz"), vf->nSamplesPerSec); - if (vf->nChannels == 1) { - dim += _T(" mono"); - } else if (vf->nChannels == 2) { - dim += _T(" stereo"); - } else { - dim.AppendFormat(_T(" %uch"), vf->nChannels); - } - if (vf->nAvgBitsPerSec) { - rate.Format(_T("%lukbps"), vf->nAvgBitsPerSec / 1000); - } - } else if (formattype == FORMAT_VorbisFormat2) { - VORBISFORMAT2* vf = (VORBISFORMAT2*)Format(); - - codec = GetAudioCodecName(subtype, 0); - dim.Format(_T("%luHz"), vf->SamplesPerSec); - if (vf->Channels == 1) { - dim += _T(" mono"); - } else if (vf->Channels == 2) { - dim += _T(" stereo"); - } else { - dim.AppendFormat(_T(" %luch"), vf->Channels); - } - } - } else if (majortype == MEDIATYPE_Text) { - type = _T("Text"); - } else if (majortype == MEDIATYPE_Subtitle || subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { - type = _T("Subtitle"); - codec = GetSubtitleCodecName(subtype); - } else { - type = _T("Unknown"); - } - - if (CComQIPtr pMS = pPin) { - REFERENCE_TIME rtDur = 0; - if (SUCCEEDED(pMS->GetDuration(&rtDur)) && rtDur) { - rtDur /= 10000000; - int s = rtDur % 60; - rtDur /= 60; - int m = rtDur % 60; - rtDur /= 60; - int h = (int)rtDur; - if (h) { - dur.Format(_T("%d:%02d:%02d"), h, m, s); - } else if (m) { - dur.Format(_T("%02d:%02d"), m, s); - } else if (s) { - dur.Format(_T("%ds"), s); - } - } - } - - CString str; - if (!codec.IsEmpty()) { - str += codec + _T(" "); - } - if (!dim.IsEmpty()) { - str += dim + _T(" "); - } - if (!rate.IsEmpty()) { - str += rate + _T(" "); - } - if (!dur.IsEmpty()) { - str += dur + _T(" "); - } - str.Trim(_T(" ,")); - - if (!str.IsEmpty()) { - str = type + _T(": ") + str; - } else { - str = type; - } - - return str; -} - -CString CMediaTypeEx::GetVideoCodecName(const GUID& subtype, DWORD biCompression) -{ - CString str = _T(""); - - static CAtlMap names; - - if (names.IsEmpty()) { - names['WMV1'] = _T("Windows Media Video 7"); - names['WMV2'] = _T("Windows Media Video 8"); - names['WMV3'] = _T("Windows Media Video 9"); - names['DIV3'] = _T("DivX 3"); - names['MP43'] = _T("MSMPEG4v3"); - names['MP42'] = _T("MSMPEG4v2"); - names['MP41'] = _T("MSMPEG4v1"); - names['DX50'] = _T("DivX 5"); - names['DIVX'] = _T("DivX 6"); - names['XVID'] = _T("Xvid"); - names['MP4V'] = _T("MPEG4 Video"); - names['AVC1'] = _T("MPEG4 Video (H264)"); - names['H264'] = _T("MPEG4 Video (H264)"); - names['RV10'] = _T("RealVideo 1"); - names['RV20'] = _T("RealVideo 2"); - names['RV30'] = _T("RealVideo 3"); - names['RV40'] = _T("RealVideo 4"); - names['FLV1'] = _T("Flash Video 1"); - names['FLV4'] = _T("Flash Video 4"); - names['VP50'] = _T("On2 VP5"); - names['VP60'] = _T("On2 VP6"); - names['SVQ3'] = _T("SVQ3"); - names['SVQ1'] = _T("SVQ1"); - names['H263'] = _T("H263"); - // names[''] = _T(""); - } - - if (biCompression) { - BYTE* b = (BYTE*)&biCompression; - - for (ptrdiff_t i = 0; i < 4; i++) { - if (b[i] >= 'a' && b[i] <= 'z') { - b[i] = (BYTE)toupper(b[i]); - } - } - - if (!names.Lookup(MAKEFOURCC(b[3], b[2], b[1], b[0]), str)) { - if (subtype == MEDIASUBTYPE_DiracVideo) { - str = _T("Dirac Video"); - } - // else if (subtype == ) str = _T(""); - else if (biCompression < 256) { - str.Format(_T("%lu"), biCompression); - } else { - str.Format(_T("%4.4hs"), &biCompression); - } - } - } else { - if (subtype == MEDIASUBTYPE_RGB32) { - str = _T("RGB32"); - } else if (subtype == MEDIASUBTYPE_RGB24) { - str = _T("RGB24"); - } else if (subtype == MEDIASUBTYPE_RGB555) { - str = _T("RGB555"); - } else if (subtype == MEDIASUBTYPE_RGB565) { - str = _T("RGB565"); - } - } - - return str; -} - -CString CMediaTypeEx::GetAudioCodecName(const GUID& subtype, WORD wFormatTag) -{ - CString str; - - static CAtlMap names; - - if (names.IsEmpty()) { - // MMReg.h - names[WAVE_FORMAT_ADPCM] = _T("MS ADPCM"); - names[WAVE_FORMAT_IEEE_FLOAT] = _T("IEEE Float"); - names[WAVE_FORMAT_ALAW] = _T("aLaw"); - names[WAVE_FORMAT_MULAW] = _T("muLaw"); - names[WAVE_FORMAT_DTS] = _T("DTS"); - names[WAVE_FORMAT_DRM] = _T("DRM"); - names[WAVE_FORMAT_WMAVOICE9] = _T("WMA Voice"); - names[WAVE_FORMAT_WMAVOICE10] = _T("WMA Voice"); - names[WAVE_FORMAT_OKI_ADPCM] = _T("OKI ADPCM"); - names[WAVE_FORMAT_IMA_ADPCM] = _T("IMA ADPCM"); - names[WAVE_FORMAT_MEDIASPACE_ADPCM] = _T("Mediaspace ADPCM"); - names[WAVE_FORMAT_SIERRA_ADPCM] = _T("Sierra ADPCM"); - names[WAVE_FORMAT_G723_ADPCM] = _T("G723 ADPCM"); - names[WAVE_FORMAT_DIALOGIC_OKI_ADPCM] = _T("Dialogic OKI ADPCM"); - names[WAVE_FORMAT_MEDIAVISION_ADPCM] = _T("Media Vision ADPCM"); - names[WAVE_FORMAT_YAMAHA_ADPCM] = _T("Yamaha ADPCM"); - names[WAVE_FORMAT_DSPGROUP_TRUESPEECH] = _T("DSP Group Truespeech"); - names[WAVE_FORMAT_DOLBY_AC2] = _T("Dolby AC2"); - names[WAVE_FORMAT_GSM610] = _T("GSM610"); - names[WAVE_FORMAT_MSNAUDIO] = _T("MSN Audio"); - names[WAVE_FORMAT_ANTEX_ADPCME] = _T("Antex ADPCME"); - names[WAVE_FORMAT_CS_IMAADPCM] = _T("Crystal Semiconductor IMA ADPCM"); - names[WAVE_FORMAT_ROCKWELL_ADPCM] = _T("Rockwell ADPCM"); - names[WAVE_FORMAT_ROCKWELL_DIGITALK] = _T("Rockwell Digitalk"); - names[WAVE_FORMAT_G721_ADPCM] = _T("G721"); - names[WAVE_FORMAT_G728_CELP] = _T("G728"); - names[WAVE_FORMAT_MSG723] = _T("MSG723"); - names[WAVE_FORMAT_MPEG] = _T("MPEG Audio"); - names[WAVE_FORMAT_MPEGLAYER3] = _T("MP3"); - names[WAVE_FORMAT_LUCENT_G723] = _T("Lucent G723"); - names[WAVE_FORMAT_VOXWARE] = _T("Voxware"); - names[WAVE_FORMAT_G726_ADPCM] = _T("G726"); - names[WAVE_FORMAT_G722_ADPCM] = _T("G722"); - names[WAVE_FORMAT_G729A] = _T("G729A"); - names[WAVE_FORMAT_MEDIASONIC_G723] = _T("MediaSonic G723"); - names[WAVE_FORMAT_ZYXEL_ADPCM] = _T("ZyXEL ADPCM"); - names[WAVE_FORMAT_RAW_AAC1] = _T("AAC"); // = WAVE_FORMAT_AAC - names[WAVE_FORMAT_RHETOREX_ADPCM] = _T("Rhetorex ADPCM"); - names[WAVE_FORMAT_VIVO_G723] = _T("Vivo G723"); - names[WAVE_FORMAT_VIVO_SIREN] = _T("Vivo Siren"); - names[WAVE_FORMAT_DIGITAL_G723] = _T("Digital G723"); - names[WAVE_FORMAT_SANYO_LD_ADPCM] = _T("Sanyo LD ADPCM"); - names[WAVE_FORMAT_MSAUDIO1] = _T("WMA 1"); - names[WAVE_FORMAT_WMAUDIO2] = _T("WMA 2"); - names[WAVE_FORMAT_WMAUDIO3] = _T("WMA Pro"); - names[WAVE_FORMAT_WMAUDIO_LOSSLESS] = _T("WMA Lossless"); - names[WAVE_FORMAT_CREATIVE_ADPCM] = _T("Creative ADPCM"); - names[WAVE_FORMAT_CREATIVE_FASTSPEECH8] = _T("Creative Fastspeech 8"); - names[WAVE_FORMAT_CREATIVE_FASTSPEECH10] = _T("Creative Fastspeech 10"); - names[WAVE_FORMAT_UHER_ADPCM] = _T("UHER ADPCM"); - names[WAVE_FORMAT_DTS2] = _T("DTS"); // = WAVE_FORMAT_DVD_DTS - // other - names[WAVE_FORMAT_DOLBY_AC3] = _T("Dolby AC3"); - names[WAVE_FORMAT_LATM_AAC] = _T("AAC(LATM)"); - names[WAVE_FORMAT_FLAC] = _T("FLAC"); - names[WAVE_FORMAT_TTA1] = _T("TTA"); - names[WAVE_FORMAT_WAVPACK4] = _T("WavPack"); - names[WAVE_FORMAT_14_4] = _T("RealAudio 14.4"); - names[WAVE_FORMAT_28_8] = _T("RealAudio 28.8"); - names[WAVE_FORMAT_ATRC] = _T("RealAudio ATRC"); - names[WAVE_FORMAT_COOK] = _T("RealAudio COOK"); - names[WAVE_FORMAT_DNET] = _T("RealAudio DNET"); - names[WAVE_FORMAT_RAAC] = _T("RealAudio RAAC"); - names[WAVE_FORMAT_RACP] = _T("RealAudio RACP"); - names[WAVE_FORMAT_SIPR] = _T("RealAudio SIPR"); - names[WAVE_FORMAT_PS2_PCM] = _T("PS2 PCM"); - names[WAVE_FORMAT_PS2_ADPCM] = _T("PS2 ADPCM"); - names[WAVE_FORMAT_AAC_ADTS] = _T("AAC"); // Specific to LAV Splitter and LAV Audio Decoder - // names[] = _T(""); - } - - // Check if we are bitstreaming to S/PDIF first to avoid misdetection as PCM - if (wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) { // Note that DTS bitstreaming uses the same format tag - str = _T("S/PDIF"); - } - // Check the subtype first after special cases have been handled - else if (subtype == MEDIASUBTYPE_PCM) { - str = _T("PCM"); - } else if (subtype == MEDIASUBTYPE_IEEE_FLOAT) { - str = _T("IEEE Float"); - } else if (subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO || subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { - str = _T("LPCM"); - } else if (subtype == MEDIASUBTYPE_Vorbis) { - str = _T("Vorbis (deprecated)"); - } else if (subtype == MEDIASUBTYPE_Vorbis2) { - str = _T("Vorbis"); - } else if (subtype == MEDIASUBTYPE_MP4A) { - str = _T("MPEG4 Audio"); - } else if (subtype == MEDIASUBTYPE_FLAC_FRAMED) { - str = _T("FLAC (framed)"); - } else if (subtype == MEDIASUBTYPE_DOLBY_AC3) { - str = _T("Dolby AC3"); - } else if (subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { - str = _T("DD+"); - } else if (subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { - str = _T("TrueHD"); - } else if (subtype == MEDIASUBTYPE_DTS) { - str = _T("DTS"); - } else if (subtype == MEDIASUBTYPE_MLP) { - str = _T("MLP"); - } else if (subtype == MEDIASUBTYPE_PCM_NONE || subtype == MEDIASUBTYPE_PCM_RAW || - subtype == MEDIASUBTYPE_PCM_TWOS || subtype == MEDIASUBTYPE_PCM_SOWT || - subtype == MEDIASUBTYPE_PCM_IN24 || subtype == MEDIASUBTYPE_PCM_IN32 || - subtype == MEDIASUBTYPE_PCM_FL32 || subtype == MEDIASUBTYPE_PCM_FL64) { - str = _T("QT PCM"); - } else if (subtype == MEDIASUBTYPE_IMA4 || - subtype == MEDIASUBTYPE_ADPCM_SWF || - subtype == MEDIASUBTYPE_ADPCM_AMV) { - str = _T("ADPCM"); - } else if (subtype == MEDIASUBTYPE_ALAC) { - str = _T("ALAC"); - } else if (subtype == MEDIASUBTYPE_ALS) { - str = _T("ALS"); - } else if (subtype == MEDIASUBTYPE_QDM2) { - str = _T("QDM2"); - } else if (subtype == MEDIASUBTYPE_AMR || - subtype == MEDIASUBTYPE_SAMR || - subtype == MEDIASUBTYPE_SAWB) { - str = _T("AMR"); - } else if (subtype == MEDIASUBTYPE_OPUS) { - str = _T("Opus"); - } // If the subtype wasn't enough to find the codec name, we try the format tag - else if (!names.Lookup(wFormatTag, str)) { - // If that fails, we have an unknown audio codec - str.Format(_T("0x%04x"), wFormatTag); - } - - return str; -} - -CString CMediaTypeEx::GetSubtitleCodecName(const GUID& subtype) -{ - CString str; - - static CAtlMap names; - - if (names.IsEmpty()) { - names[MEDIASUBTYPE_UTF8] = _T("UTF-8"); - names[MEDIASUBTYPE_SSA] = _T("SubStation Alpha"); - names[MEDIASUBTYPE_ASS] = _T("Advanced SubStation Alpha"); - names[MEDIASUBTYPE_ASS2] = _T("Advanced SubStation Alpha"); - names[MEDIASUBTYPE_USF] = _T("Universal Subtitle Format"); - names[MEDIASUBTYPE_VOBSUB] = _T("VobSub"); - names[MEDIASUBTYPE_DVB_SUBTITLES] = _T("DVB Subtitles"); - names[MEDIASUBTYPE_DVD_SUBPICTURE] = _T("DVD Subtitles"); - names[MEDIASUBTYPE_WEBVTT] = _T("WebVTT"); - } - - if (names.Lookup(subtype, str)) { - - } - - return str; -} - -void CMediaTypeEx::Dump(CAtlList& sl) -{ - CString str; - - sl.RemoveAll(); - - int fmtsize = 0; - - CString major = CStringFromGUID(majortype); - CString sub = CStringFromGUID(subtype); - CString format = CStringFromGUID(formattype); - - sl.AddTail(ToString() + _T("\n")); - - sl.AddTail(_T("AM_MEDIA_TYPE: ")); - str.Format(_T("majortype: %S %s"), GuidNames[majortype], major.GetString()); - sl.AddTail(str); - str.Format(_T("subtype: %S %s"), GuidNames[subtype], sub.GetString()); - sl.AddTail(str); - str.Format(_T("formattype: %S %s"), GuidNames[formattype], format.GetString()); - sl.AddTail(str); - str.Format(_T("bFixedSizeSamples: %d"), bFixedSizeSamples); - sl.AddTail(str); - str.Format(_T("bTemporalCompression: %d"), bTemporalCompression); - sl.AddTail(str); - str.Format(_T("lSampleSize: %lu"), lSampleSize); - sl.AddTail(str); - str.Format(_T("cbFormat: %lu"), cbFormat); - sl.AddTail(str); - - sl.AddTail(_T("")); - - if (formattype == FORMAT_VideoInfo || formattype == FORMAT_VideoInfo2 - || formattype == FORMAT_MPEGVideo || formattype == FORMAT_MPEG2_VIDEO) { - fmtsize = - formattype == FORMAT_VideoInfo ? sizeof(VIDEOINFOHEADER) : - formattype == FORMAT_VideoInfo2 ? sizeof(VIDEOINFOHEADER2) : - formattype == FORMAT_MPEGVideo ? sizeof(MPEG1VIDEOINFO) - 1 : - formattype == FORMAT_MPEG2_VIDEO ? sizeof(MPEG2VIDEOINFO) - 4 : - 0; - - VIDEOINFOHEADER& vih = *(VIDEOINFOHEADER*)pbFormat; - BITMAPINFOHEADER* bih = &vih.bmiHeader; - - sl.AddTail(_T("VIDEOINFOHEADER:")); - str.Format(_T("rcSource: (%ld,%ld)-(%ld,%ld)"), vih.rcSource.left, vih.rcSource.top, vih.rcSource.right, vih.rcSource.bottom); - sl.AddTail(str); - str.Format(_T("rcTarget: (%ld,%ld)-(%ld,%ld)"), vih.rcTarget.left, vih.rcTarget.top, vih.rcTarget.right, vih.rcTarget.bottom); - sl.AddTail(str); - str.Format(_T("dwBitRate: %u"), vih.dwBitRate); - sl.AddTail(str); - str.Format(_T("dwBitErrorRate: %u"), vih.dwBitErrorRate); - sl.AddTail(str); - str.Format(_T("AvgTimePerFrame: %I64d"), vih.AvgTimePerFrame); - sl.AddTail(str); - - sl.AddTail(_T("")); - - if (formattype == FORMAT_VideoInfo2 || formattype == FORMAT_MPEG2_VIDEO) { - VIDEOINFOHEADER2& vih2 = *(VIDEOINFOHEADER2*)pbFormat; - bih = &vih2.bmiHeader; - - sl.AddTail(_T("VIDEOINFOHEADER2:")); - str.Format(_T("dwInterlaceFlags: 0x%08x"), vih2.dwInterlaceFlags); - sl.AddTail(str); - str.Format(_T("dwCopyProtectFlags: 0x%08x"), vih2.dwCopyProtectFlags); - sl.AddTail(str); - str.Format(_T("dwPictAspectRatioX: %u"), vih2.dwPictAspectRatioX); - sl.AddTail(str); - str.Format(_T("dwPictAspectRatioY: %u"), vih2.dwPictAspectRatioY); - sl.AddTail(str); - str.Format(_T("dwControlFlags: 0x%08x"), vih2.dwControlFlags); - sl.AddTail(str); - str.Format(_T("dwReserved2: 0x%08x"), vih2.dwReserved2); - sl.AddTail(str); - - sl.AddTail(_T("")); - } - - if (formattype == FORMAT_MPEGVideo) { - MPEG1VIDEOINFO& mvih = *(MPEG1VIDEOINFO*)pbFormat; - - sl.AddTail(_T("MPEG1VIDEOINFO:")); - str.Format(_T("dwStartTimeCode: %u"), mvih.dwStartTimeCode); - sl.AddTail(str); - str.Format(_T("cbSequenceHeader: %u"), mvih.cbSequenceHeader); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (formattype == FORMAT_MPEG2_VIDEO) { - MPEG2VIDEOINFO& mvih = *(MPEG2VIDEOINFO*)pbFormat; - - sl.AddTail(_T("MPEG2VIDEOINFO:")); - str.Format(_T("dwStartTimeCode: %u"), mvih.dwStartTimeCode); - sl.AddTail(str); - str.Format(_T("cbSequenceHeader: %u"), mvih.cbSequenceHeader); - sl.AddTail(str); - str.Format(_T("dwProfile: 0x%08x"), mvih.dwProfile); - sl.AddTail(str); - str.Format(_T("dwLevel: 0x%08x"), mvih.dwLevel); - sl.AddTail(str); - str.Format(_T("dwFlags: 0x%08x"), mvih.dwFlags); - sl.AddTail(str); - - sl.AddTail(_T("")); - } - - sl.AddTail(_T("BITMAPINFOHEADER:")); - str.Format(_T("biSize: %u"), bih->biSize); - sl.AddTail(str); - str.Format(_T("biWidth: %ld"), bih->biWidth); - sl.AddTail(str); - str.Format(_T("biHeight: %ld"), bih->biHeight); - sl.AddTail(str); - str.Format(_T("biPlanes: %u"), bih->biPlanes); - sl.AddTail(str); - str.Format(_T("biBitCount: %u"), bih->biBitCount); - sl.AddTail(str); - if (bih->biCompression < 256) { - str.Format(_T("biCompression: %u"), bih->biCompression); - } else { - str.Format(_T("biCompression: %4.4hs"), &bih->biCompression); - } - sl.AddTail(str); - str.Format(_T("biSizeImage: %u"), bih->biSizeImage); - sl.AddTail(str); - str.Format(_T("biXPelsPerMeter: %ld"), bih->biXPelsPerMeter); - sl.AddTail(str); - str.Format(_T("biYPelsPerMeter: %ld"), bih->biYPelsPerMeter); - sl.AddTail(str); - str.Format(_T("biClrUsed: %u"), bih->biClrUsed); - sl.AddTail(str); - str.Format(_T("biClrImportant: %u"), bih->biClrImportant); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (formattype == FORMAT_WaveFormatEx || formattype == FORMAT_WaveFormatExFFMPEG) { - WAVEFORMATEX* pWfe = nullptr; - if (formattype == FORMAT_WaveFormatExFFMPEG) { - fmtsize = sizeof(WAVEFORMATEXFFMPEG); - - WAVEFORMATEXFFMPEG* wfeff = (WAVEFORMATEXFFMPEG*)pbFormat; - pWfe = &wfeff->wfex; - - sl.AddTail(_T("WAVEFORMATEXFFMPEG:")); - str.Format(_T("nCodecId: 0x%04x"), wfeff->nCodecId); - sl.AddTail(str); - sl.AddTail(_T("")); - } else { - fmtsize = sizeof(WAVEFORMATEX); - pWfe = (WAVEFORMATEX*)pbFormat; - } - - WAVEFORMATEX& wfe = *pWfe; - - sl.AddTail(_T("WAVEFORMATEX:")); - str.Format(_T("wFormatTag: 0x%04x"), wfe.wFormatTag); - sl.AddTail(str); - str.Format(_T("nChannels: %u"), wfe.nChannels); - sl.AddTail(str); - str.Format(_T("nSamplesPerSec: %u"), wfe.nSamplesPerSec); - sl.AddTail(str); - str.Format(_T("nAvgBytesPerSec: %u"), wfe.nAvgBytesPerSec); - sl.AddTail(str); - str.Format(_T("nBlockAlign: %u"), wfe.nBlockAlign); - sl.AddTail(str); - str.Format(_T("wBitsPerSample: %u"), wfe.wBitsPerSample); - sl.AddTail(str); - str.Format(_T("cbSize: %u (extra bytes)"), wfe.cbSize); - sl.AddTail(str); - - sl.AddTail(_T("")); - - if (wfe.wFormatTag != WAVE_FORMAT_PCM && wfe.cbSize > 0 && formattype == FORMAT_WaveFormatEx) { - if (wfe.wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfe.cbSize == sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { - fmtsize = sizeof(WAVEFORMATEXTENSIBLE); - - WAVEFORMATEXTENSIBLE& wfextensible = *(WAVEFORMATEXTENSIBLE*)pbFormat; - - sl.AddTail(_T("WAVEFORMATEXTENSIBLE:")); - if (wfextensible.Format.wBitsPerSample != 0) { - str.Format(_T("wValidBitsPerSample: %u"), wfextensible.Samples.wValidBitsPerSample); - } else { - str.Format(_T("wSamplesPerBlock: %u"), wfextensible.Samples.wSamplesPerBlock); - } - sl.AddTail(str); - str.Format(_T("dwChannelMask: 0x%08x"), wfextensible.dwChannelMask); - sl.AddTail(str); - str.Format(_T("SubFormat: %s"), CStringFromGUID(wfextensible.SubFormat).GetString()); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (wfe.wFormatTag == WAVE_FORMAT_DOLBY_AC3 && wfe.cbSize == sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX)) { - fmtsize = sizeof(DOLBYAC3WAVEFORMAT); - - DOLBYAC3WAVEFORMAT& dawf = *(DOLBYAC3WAVEFORMAT*)pbFormat; - - sl.AddTail(_T("DOLBYAC3WAVEFORMAT:")); - str.Format(_T("bBigEndian: %u"), dawf.bBigEndian); - sl.AddTail(str); - str.Format(_T("bsid: %u"), dawf.bsid); - sl.AddTail(str); - str.Format(_T("lfeon: %u"), dawf.lfeon); - sl.AddTail(str); - str.Format(_T("copyrightb: %u"), dawf.copyrightb); - sl.AddTail(str); - str.Format(_T("nAuxBitsCode: %u"), dawf.nAuxBitsCode); - sl.AddTail(str); - - sl.AddTail(_T("")); - } - } - } else if (formattype == FORMAT_VorbisFormat) { - fmtsize = sizeof(VORBISFORMAT); - - VORBISFORMAT& vf = *(VORBISFORMAT*)pbFormat; - - sl.AddTail(_T("VORBISFORMAT:")); - str.Format(_T("nChannels: %u"), vf.nChannels); - sl.AddTail(str); - str.Format(_T("nSamplesPerSec: %lu"), vf.nSamplesPerSec); - sl.AddTail(str); - str.Format(_T("nMinBitsPerSec: %lu"), vf.nMinBitsPerSec); - sl.AddTail(str); - str.Format(_T("nAvgBitsPerSec: %lu"), vf.nAvgBitsPerSec); - sl.AddTail(str); - str.Format(_T("nMaxBitsPerSec: %lu"), vf.nMaxBitsPerSec); - sl.AddTail(str); - str.Format(_T("fQuality: %.3f"), vf.fQuality); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (formattype == FORMAT_VorbisFormat2) { - fmtsize = sizeof(VORBISFORMAT2); - - VORBISFORMAT2& vf = *(VORBISFORMAT2*)pbFormat; - - sl.AddTail(_T("VORBISFORMAT:")); - str.Format(_T("Channels: %lu"), vf.Channels); - sl.AddTail(str); - str.Format(_T("SamplesPerSec: %lu"), vf.SamplesPerSec); - sl.AddTail(str); - str.Format(_T("BitsPerSample: %lu"), vf.BitsPerSample); - sl.AddTail(str); - str.Format(_T("HeaderSize: {%lu, %lu, %lu}"), vf.HeaderSize[0], vf.HeaderSize[1], vf.HeaderSize[2]); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (formattype == FORMAT_SubtitleInfo) { - fmtsize = sizeof(SUBTITLEINFO); - - SUBTITLEINFO& si = *(SUBTITLEINFO*)pbFormat; - - sl.AddTail(_T("SUBTITLEINFO:")); - str.Format(_T("dwOffset: %lu"), si.dwOffset); - sl.AddTail(str); - str.Format(_T("IsoLang: %S"), CStringA(si.IsoLang, sizeof(si.IsoLang) - 1).GetString()); - sl.AddTail(str); - str.Format(_T("TrackName: %s"), CStringW(si.TrackName, sizeof(si.TrackName) - 1).GetString()); - sl.AddTail(str); - - sl.AddTail(_T("")); - } - - if (cbFormat > 0) { - sl.AddTail(_T("pbFormat:")); - - for (ptrdiff_t i = 0, j = (cbFormat + 15) & ~15; i < j; i += 16) { - str.Format(_T("%04Ix:"), i); - - for (ptrdiff_t k = i, l = std::min(i + 16, (ptrdiff_t)cbFormat); k < l; k++) { - CString byte; - byte.Format(_T("%c%02x"), fmtsize > 0 && fmtsize == k ? '|' : ' ', pbFormat[k]); - str += byte; - } - - for (ptrdiff_t k = std::min(i + 16, (ptrdiff_t)cbFormat), l = i + 16; k < l; k++) { - str += _T(" "); - } - - str += _T(' '); - - for (ptrdiff_t k = i, l = std::min(i + 16, (ptrdiff_t)cbFormat); k < l; k++) { - unsigned char c = (unsigned char)pbFormat[k]; - CString ch; - ch.Format(_T("%C"), c >= 0x20 ? c : '.'); - str += ch; - } - - sl.AddTail(str); - } - - sl.AddTail(_T("")); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "DSUtil.h" +#include "MediaTypeEx.h" + +#include +#include "moreuuids.h" + +#pragma pack(push, 1) +struct DOLBYAC3WAVEFORMAT { + WAVEFORMATEX Format; + BYTE bBigEndian; + BYTE bsid; + BYTE lfeon; + BYTE copyrightb; + BYTE nAuxBitsCode; // Aux bits per frame +}; +#pragma pack(pop) + +CMediaTypeEx::CMediaTypeEx() +{ +} + +CMediaTypeEx::~CMediaTypeEx() +{ +} + +CString CMediaTypeEx::ToString(IPin* pPin) +{ + CString packing, type, codec, dim, rate, dur; + + // TODO + + if (majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { + packing = _T("Encrypted MPEG2 Pack"); + } else if (majortype == MEDIATYPE_MPEG2_PACK) { + packing = _T("MPEG2 Pack"); + } else if (majortype == MEDIATYPE_MPEG2_PES) { + packing = _T("MPEG2 PES"); + } + + if (majortype == MEDIATYPE_Video || subtype == MEDIASUBTYPE_MPEG2_VIDEO) { + type = _T("Video"); + + BITMAPINFOHEADER bih; + bool fBIH = ExtractBIH(this, &bih); + + int w, h, arx, ary; + bool fDim = ExtractDim(this, w, h, arx, ary); + + if (fBIH) { + codec = GetVideoCodecName(subtype, bih.biCompression); + } + + if (codec.IsEmpty()) { + if (formattype == FORMAT_MPEGVideo) { + codec = _T("MPEG1 Video"); + } else if (formattype == FORMAT_MPEG2_VIDEO) { + codec = _T("MPEG2 Video"); + } else if (formattype == FORMAT_DiracVideoInfo) { + codec = _T("Dirac Video"); + } + } + + if (fDim) { + dim.Format(_T("%dx%d"), w, h); + if (w * ary != h * arx) { + dim.AppendFormat(_T(" (%d:%d)"), arx, ary); + } + } + + if (formattype == FORMAT_VideoInfo || formattype == FORMAT_MPEGVideo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pbFormat; + if (vih->AvgTimePerFrame) { + rate.Format(_T("%0.3f"), 10000000.0f / vih->AvgTimePerFrame); + rate.TrimRight(_T('0')); // remove trailing zeros + rate.TrimRight(_T('.')); // remove the trailing dot + rate += _T("fps "); + } + if (vih->dwBitRate) { + rate.AppendFormat(_T("%ukbps"), vih->dwBitRate / 1000); + } + } else if (formattype == FORMAT_VideoInfo2 || formattype == FORMAT_MPEG2_VIDEO || formattype == FORMAT_DiracVideoInfo) { + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pbFormat; + if (vih->AvgTimePerFrame) { + rate.Format(_T("%0.3f"), 10000000.0f / vih->AvgTimePerFrame); + rate.TrimRight(_T('0')); // remove trailing zeros + rate.TrimRight(_T('.')); // remove the trailing dot + rate += _T("fps "); + } + if (vih->dwBitRate) { + rate.AppendFormat(_T("%ukbps"), vih->dwBitRate / 1000); + } + } + + rate.TrimRight(); + + if (subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { + type = _T("Subtitle"); + codec = _T("DVD Subpicture"); + } + } else if (majortype == MEDIATYPE_Audio || subtype == MEDIASUBTYPE_DOLBY_AC3) { + type = _T("Audio"); + + if (formattype == FORMAT_WaveFormatEx) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)Format(); + + if (wfe->wFormatTag/* > WAVE_FORMAT_PCM && wfe->wFormatTag < WAVE_FORMAT_EXTENSIBLE + && wfe->wFormatTag != WAVE_FORMAT_IEEE_FLOAT*/ + || subtype != GUID_NULL) { + codec = GetAudioCodecName(subtype, wfe->wFormatTag); + dim.Format(_T("%uHz"), wfe->nSamplesPerSec); + if (wfe->nChannels == 1) { + dim += _T(" mono"); + } else if (wfe->nChannels == 2) { + dim += _T(" stereo"); + } else { + dim.AppendFormat(_T(" %uch"), wfe->nChannels); + } + if (wfe->nAvgBytesPerSec) { + rate.Format(_T("%ukbps"), wfe->nAvgBytesPerSec * 8 / 1000); + } + } + } else if (formattype == FORMAT_VorbisFormat) { + VORBISFORMAT* vf = (VORBISFORMAT*)Format(); + + codec = GetAudioCodecName(subtype, 0); + dim.Format(_T("%luHz"), vf->nSamplesPerSec); + if (vf->nChannels == 1) { + dim += _T(" mono"); + } else if (vf->nChannels == 2) { + dim += _T(" stereo"); + } else { + dim.AppendFormat(_T(" %uch"), vf->nChannels); + } + if (vf->nAvgBitsPerSec) { + rate.Format(_T("%lukbps"), vf->nAvgBitsPerSec / 1000); + } + } else if (formattype == FORMAT_VorbisFormat2) { + VORBISFORMAT2* vf = (VORBISFORMAT2*)Format(); + + codec = GetAudioCodecName(subtype, 0); + dim.Format(_T("%luHz"), vf->SamplesPerSec); + if (vf->Channels == 1) { + dim += _T(" mono"); + } else if (vf->Channels == 2) { + dim += _T(" stereo"); + } else { + dim.AppendFormat(_T(" %luch"), vf->Channels); + } + } + } else if (majortype == MEDIATYPE_Text) { + type = _T("Text"); + } else if (majortype == MEDIATYPE_Subtitle || subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { + type = _T("Subtitle"); + codec = GetSubtitleCodecName(subtype); + } else { + type = _T("Unknown"); + } + + if (CComQIPtr pMS = pPin) { + REFERENCE_TIME rtDur = 0; + if (SUCCEEDED(pMS->GetDuration(&rtDur)) && rtDur) { + rtDur /= 10000000; + int s = rtDur % 60; + rtDur /= 60; + int m = rtDur % 60; + rtDur /= 60; + int h = (int)rtDur; + if (h) { + dur.Format(_T("%d:%02d:%02d"), h, m, s); + } else if (m) { + dur.Format(_T("%02d:%02d"), m, s); + } else if (s) { + dur.Format(_T("%ds"), s); + } + } + } + + CString str; + if (!codec.IsEmpty()) { + str += codec + _T(" "); + } + if (!dim.IsEmpty()) { + str += dim + _T(" "); + } + if (!rate.IsEmpty()) { + str += rate + _T(" "); + } + if (!dur.IsEmpty()) { + str += dur + _T(" "); + } + str.Trim(_T(" ,")); + + if (!str.IsEmpty()) { + str = type + _T(": ") + str; + } else { + str = type; + } + + return str; +} + +CString CMediaTypeEx::GetVideoCodecName(const GUID& subtype, DWORD biCompression) +{ + CString str = _T(""); + + static CAtlMap names; + + if (names.IsEmpty()) { + names['WMV1'] = _T("Windows Media Video 7"); + names['WMV2'] = _T("Windows Media Video 8"); + names['WMV3'] = _T("Windows Media Video 9"); + names['DIV3'] = _T("DivX 3"); + names['MP43'] = _T("MSMPEG4v3"); + names['MP42'] = _T("MSMPEG4v2"); + names['MP41'] = _T("MSMPEG4v1"); + names['DX50'] = _T("DivX 5"); + names['DIVX'] = _T("DivX 6"); + names['XVID'] = _T("Xvid"); + names['MP4V'] = _T("MPEG4 Video"); + names['AVC1'] = _T("MPEG4 Video (H264)"); + names['H264'] = _T("MPEG4 Video (H264)"); + names['RV10'] = _T("RealVideo 1"); + names['RV20'] = _T("RealVideo 2"); + names['RV30'] = _T("RealVideo 3"); + names['RV40'] = _T("RealVideo 4"); + names['FLV1'] = _T("Flash Video 1"); + names['FLV4'] = _T("Flash Video 4"); + names['VP50'] = _T("On2 VP5"); + names['VP60'] = _T("On2 VP6"); + names['SVQ3'] = _T("SVQ3"); + names['SVQ1'] = _T("SVQ1"); + names['H263'] = _T("H263"); + // names[''] = _T(""); + } + + if (biCompression) { + BYTE* b = (BYTE*)&biCompression; + + for (ptrdiff_t i = 0; i < 4; i++) { + if (b[i] >= 'a' && b[i] <= 'z') { + b[i] = (BYTE)toupper(b[i]); + } + } + + if (!names.Lookup(MAKEFOURCC(b[3], b[2], b[1], b[0]), str)) { + if (subtype == MEDIASUBTYPE_DiracVideo) { + str = _T("Dirac Video"); + } + // else if (subtype == ) str = _T(""); + else if (biCompression < 256) { + str.Format(_T("%lu"), biCompression); + } else { + str.Format(_T("%4.4hs"), &biCompression); + } + } + } else { + if (subtype == MEDIASUBTYPE_RGB32) { + str = _T("RGB32"); + } else if (subtype == MEDIASUBTYPE_RGB24) { + str = _T("RGB24"); + } else if (subtype == MEDIASUBTYPE_RGB555) { + str = _T("RGB555"); + } else if (subtype == MEDIASUBTYPE_RGB565) { + str = _T("RGB565"); + } + } + + return str; +} + +CString CMediaTypeEx::GetAudioCodecName(const GUID& subtype, WORD wFormatTag) +{ + CString str; + + static CAtlMap names; + + if (names.IsEmpty()) { + // MMReg.h + names[WAVE_FORMAT_ADPCM] = _T("MS ADPCM"); + names[WAVE_FORMAT_IEEE_FLOAT] = _T("IEEE Float"); + names[WAVE_FORMAT_ALAW] = _T("aLaw"); + names[WAVE_FORMAT_MULAW] = _T("muLaw"); + names[WAVE_FORMAT_DTS] = _T("DTS"); + names[WAVE_FORMAT_DRM] = _T("DRM"); + names[WAVE_FORMAT_WMAVOICE9] = _T("WMA Voice"); + names[WAVE_FORMAT_WMAVOICE10] = _T("WMA Voice"); + names[WAVE_FORMAT_OKI_ADPCM] = _T("OKI ADPCM"); + names[WAVE_FORMAT_IMA_ADPCM] = _T("IMA ADPCM"); + names[WAVE_FORMAT_MEDIASPACE_ADPCM] = _T("Mediaspace ADPCM"); + names[WAVE_FORMAT_SIERRA_ADPCM] = _T("Sierra ADPCM"); + names[WAVE_FORMAT_G723_ADPCM] = _T("G723 ADPCM"); + names[WAVE_FORMAT_DIALOGIC_OKI_ADPCM] = _T("Dialogic OKI ADPCM"); + names[WAVE_FORMAT_MEDIAVISION_ADPCM] = _T("Media Vision ADPCM"); + names[WAVE_FORMAT_YAMAHA_ADPCM] = _T("Yamaha ADPCM"); + names[WAVE_FORMAT_DSPGROUP_TRUESPEECH] = _T("DSP Group Truespeech"); + names[WAVE_FORMAT_DOLBY_AC2] = _T("Dolby AC2"); + names[WAVE_FORMAT_GSM610] = _T("GSM610"); + names[WAVE_FORMAT_MSNAUDIO] = _T("MSN Audio"); + names[WAVE_FORMAT_ANTEX_ADPCME] = _T("Antex ADPCME"); + names[WAVE_FORMAT_CS_IMAADPCM] = _T("Crystal Semiconductor IMA ADPCM"); + names[WAVE_FORMAT_ROCKWELL_ADPCM] = _T("Rockwell ADPCM"); + names[WAVE_FORMAT_ROCKWELL_DIGITALK] = _T("Rockwell Digitalk"); + names[WAVE_FORMAT_G721_ADPCM] = _T("G721"); + names[WAVE_FORMAT_G728_CELP] = _T("G728"); + names[WAVE_FORMAT_MSG723] = _T("MSG723"); + names[WAVE_FORMAT_MPEG] = _T("MPEG Audio"); + names[WAVE_FORMAT_MPEGLAYER3] = _T("MP3"); + names[WAVE_FORMAT_LUCENT_G723] = _T("Lucent G723"); + names[WAVE_FORMAT_VOXWARE] = _T("Voxware"); + names[WAVE_FORMAT_G726_ADPCM] = _T("G726"); + names[WAVE_FORMAT_G722_ADPCM] = _T("G722"); + names[WAVE_FORMAT_G729A] = _T("G729A"); + names[WAVE_FORMAT_MEDIASONIC_G723] = _T("MediaSonic G723"); + names[WAVE_FORMAT_ZYXEL_ADPCM] = _T("ZyXEL ADPCM"); + names[WAVE_FORMAT_RAW_AAC1] = _T("AAC"); // = WAVE_FORMAT_AAC + names[WAVE_FORMAT_RHETOREX_ADPCM] = _T("Rhetorex ADPCM"); + names[WAVE_FORMAT_VIVO_G723] = _T("Vivo G723"); + names[WAVE_FORMAT_VIVO_SIREN] = _T("Vivo Siren"); + names[WAVE_FORMAT_DIGITAL_G723] = _T("Digital G723"); + names[WAVE_FORMAT_SANYO_LD_ADPCM] = _T("Sanyo LD ADPCM"); + names[WAVE_FORMAT_MSAUDIO1] = _T("WMA 1"); + names[WAVE_FORMAT_WMAUDIO2] = _T("WMA 2"); + names[WAVE_FORMAT_WMAUDIO3] = _T("WMA Pro"); + names[WAVE_FORMAT_WMAUDIO_LOSSLESS] = _T("WMA Lossless"); + names[WAVE_FORMAT_CREATIVE_ADPCM] = _T("Creative ADPCM"); + names[WAVE_FORMAT_CREATIVE_FASTSPEECH8] = _T("Creative Fastspeech 8"); + names[WAVE_FORMAT_CREATIVE_FASTSPEECH10] = _T("Creative Fastspeech 10"); + names[WAVE_FORMAT_UHER_ADPCM] = _T("UHER ADPCM"); + names[WAVE_FORMAT_DTS2] = _T("DTS"); // = WAVE_FORMAT_DVD_DTS + // other + names[WAVE_FORMAT_DOLBY_AC3] = _T("Dolby AC3"); + names[WAVE_FORMAT_LATM_AAC] = _T("AAC(LATM)"); + names[WAVE_FORMAT_FLAC] = _T("FLAC"); + names[WAVE_FORMAT_TTA1] = _T("TTA"); + names[WAVE_FORMAT_WAVPACK4] = _T("WavPack"); + names[WAVE_FORMAT_14_4] = _T("RealAudio 14.4"); + names[WAVE_FORMAT_28_8] = _T("RealAudio 28.8"); + names[WAVE_FORMAT_ATRC] = _T("RealAudio ATRC"); + names[WAVE_FORMAT_COOK] = _T("RealAudio COOK"); + names[WAVE_FORMAT_DNET] = _T("RealAudio DNET"); + names[WAVE_FORMAT_RAAC] = _T("RealAudio RAAC"); + names[WAVE_FORMAT_RACP] = _T("RealAudio RACP"); + names[WAVE_FORMAT_SIPR] = _T("RealAudio SIPR"); + names[WAVE_FORMAT_PS2_PCM] = _T("PS2 PCM"); + names[WAVE_FORMAT_PS2_ADPCM] = _T("PS2 ADPCM"); + names[WAVE_FORMAT_AAC_ADTS] = _T("AAC"); // Specific to LAV Splitter and LAV Audio Decoder + // names[] = _T(""); + } + + // Check if we are bitstreaming to S/PDIF first to avoid misdetection as PCM + if (wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) { // Note that DTS bitstreaming uses the same format tag + str = _T("S/PDIF"); + } + // Check the subtype first after special cases have been handled + else if (subtype == MEDIASUBTYPE_PCM) { + str = _T("PCM"); + } else if (subtype == MEDIASUBTYPE_IEEE_FLOAT) { + str = _T("IEEE Float"); + } else if (subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO || subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { + str = _T("LPCM"); + } else if (subtype == MEDIASUBTYPE_Vorbis) { + str = _T("Vorbis (deprecated)"); + } else if (subtype == MEDIASUBTYPE_Vorbis2) { + str = _T("Vorbis"); + } else if (subtype == MEDIASUBTYPE_MP4A) { + str = _T("MPEG4 Audio"); + } else if (subtype == MEDIASUBTYPE_FLAC_FRAMED) { + str = _T("FLAC (framed)"); + } else if (subtype == MEDIASUBTYPE_DOLBY_AC3) { + str = _T("Dolby AC3"); + } else if (subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { + str = _T("DD+"); + } else if (subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { + str = _T("TrueHD"); + } else if (subtype == MEDIASUBTYPE_DTS) { + str = _T("DTS"); + } else if (subtype == MEDIASUBTYPE_MLP) { + str = _T("MLP"); + } else if (subtype == MEDIASUBTYPE_PCM_NONE || subtype == MEDIASUBTYPE_PCM_RAW || + subtype == MEDIASUBTYPE_PCM_TWOS || subtype == MEDIASUBTYPE_PCM_SOWT || + subtype == MEDIASUBTYPE_PCM_IN24 || subtype == MEDIASUBTYPE_PCM_IN32 || + subtype == MEDIASUBTYPE_PCM_FL32 || subtype == MEDIASUBTYPE_PCM_FL64) { + str = _T("QT PCM"); + } else if (subtype == MEDIASUBTYPE_IMA4 || + subtype == MEDIASUBTYPE_ADPCM_SWF || + subtype == MEDIASUBTYPE_ADPCM_AMV) { + str = _T("ADPCM"); + } else if (subtype == MEDIASUBTYPE_ALAC) { + str = _T("ALAC"); + } else if (subtype == MEDIASUBTYPE_ALS) { + str = _T("ALS"); + } else if (subtype == MEDIASUBTYPE_QDM2) { + str = _T("QDM2"); + } else if (subtype == MEDIASUBTYPE_AMR || + subtype == MEDIASUBTYPE_SAMR || + subtype == MEDIASUBTYPE_SAWB) { + str = _T("AMR"); + } else if (subtype == MEDIASUBTYPE_OPUS) { + str = _T("Opus"); + } // If the subtype wasn't enough to find the codec name, we try the format tag + else if (!names.Lookup(wFormatTag, str)) { + // If that fails, we have an unknown audio codec + str.Format(_T("0x%04x"), wFormatTag); + } + + return str; +} + +CString CMediaTypeEx::GetSubtitleCodecName(const GUID& subtype) +{ + CString str; + + static CAtlMap names; + + if (names.IsEmpty()) { + names[MEDIASUBTYPE_UTF8] = _T("UTF-8"); + names[MEDIASUBTYPE_SSA] = _T("SubStation Alpha"); + names[MEDIASUBTYPE_ASS] = _T("Advanced SubStation Alpha"); + names[MEDIASUBTYPE_ASS2] = _T("Advanced SubStation Alpha"); + names[MEDIASUBTYPE_USF] = _T("Universal Subtitle Format"); + names[MEDIASUBTYPE_VOBSUB] = _T("VobSub"); + names[MEDIASUBTYPE_DVB_SUBTITLES] = _T("DVB Subtitles"); + names[MEDIASUBTYPE_DVD_SUBPICTURE] = _T("DVD Subtitles"); + names[MEDIASUBTYPE_WEBVTT] = _T("WebVTT"); + } + + if (names.Lookup(subtype, str)) { + + } + + return str; +} + +void CMediaTypeEx::Dump(CAtlList& sl) +{ + CString str; + + sl.RemoveAll(); + + int fmtsize = 0; + + CString major = CStringFromGUID(majortype); + CString sub = CStringFromGUID(subtype); + CString format = CStringFromGUID(formattype); + + sl.AddTail(ToString() + _T("\n")); + + sl.AddTail(_T("AM_MEDIA_TYPE: ")); + str.Format(_T("majortype: %S %s"), GuidNames[majortype], major.GetString()); + sl.AddTail(str); + str.Format(_T("subtype: %S %s"), GuidNames[subtype], sub.GetString()); + sl.AddTail(str); + str.Format(_T("formattype: %S %s"), GuidNames[formattype], format.GetString()); + sl.AddTail(str); + str.Format(_T("bFixedSizeSamples: %d"), bFixedSizeSamples); + sl.AddTail(str); + str.Format(_T("bTemporalCompression: %d"), bTemporalCompression); + sl.AddTail(str); + str.Format(_T("lSampleSize: %lu"), lSampleSize); + sl.AddTail(str); + str.Format(_T("cbFormat: %lu"), cbFormat); + sl.AddTail(str); + + sl.AddTail(_T("")); + + if (formattype == FORMAT_VideoInfo || formattype == FORMAT_VideoInfo2 + || formattype == FORMAT_MPEGVideo || formattype == FORMAT_MPEG2_VIDEO) { + fmtsize = + formattype == FORMAT_VideoInfo ? sizeof(VIDEOINFOHEADER) : + formattype == FORMAT_VideoInfo2 ? sizeof(VIDEOINFOHEADER2) : + formattype == FORMAT_MPEGVideo ? sizeof(MPEG1VIDEOINFO) - 1 : + formattype == FORMAT_MPEG2_VIDEO ? sizeof(MPEG2VIDEOINFO) - 4 : + 0; + + VIDEOINFOHEADER& vih = *(VIDEOINFOHEADER*)pbFormat; + BITMAPINFOHEADER* bih = &vih.bmiHeader; + + sl.AddTail(_T("VIDEOINFOHEADER:")); + str.Format(_T("rcSource: (%ld,%ld)-(%ld,%ld)"), vih.rcSource.left, vih.rcSource.top, vih.rcSource.right, vih.rcSource.bottom); + sl.AddTail(str); + str.Format(_T("rcTarget: (%ld,%ld)-(%ld,%ld)"), vih.rcTarget.left, vih.rcTarget.top, vih.rcTarget.right, vih.rcTarget.bottom); + sl.AddTail(str); + str.Format(_T("dwBitRate: %u"), vih.dwBitRate); + sl.AddTail(str); + str.Format(_T("dwBitErrorRate: %u"), vih.dwBitErrorRate); + sl.AddTail(str); + str.Format(_T("AvgTimePerFrame: %I64d"), vih.AvgTimePerFrame); + sl.AddTail(str); + + sl.AddTail(_T("")); + + if (formattype == FORMAT_VideoInfo2 || formattype == FORMAT_MPEG2_VIDEO) { + VIDEOINFOHEADER2& vih2 = *(VIDEOINFOHEADER2*)pbFormat; + bih = &vih2.bmiHeader; + + sl.AddTail(_T("VIDEOINFOHEADER2:")); + str.Format(_T("dwInterlaceFlags: 0x%08x"), vih2.dwInterlaceFlags); + sl.AddTail(str); + str.Format(_T("dwCopyProtectFlags: 0x%08x"), vih2.dwCopyProtectFlags); + sl.AddTail(str); + str.Format(_T("dwPictAspectRatioX: %u"), vih2.dwPictAspectRatioX); + sl.AddTail(str); + str.Format(_T("dwPictAspectRatioY: %u"), vih2.dwPictAspectRatioY); + sl.AddTail(str); + str.Format(_T("dwControlFlags: 0x%08x"), vih2.dwControlFlags); + sl.AddTail(str); + str.Format(_T("dwReserved2: 0x%08x"), vih2.dwReserved2); + sl.AddTail(str); + + sl.AddTail(_T("")); + } + + if (formattype == FORMAT_MPEGVideo) { + MPEG1VIDEOINFO& mvih = *(MPEG1VIDEOINFO*)pbFormat; + + sl.AddTail(_T("MPEG1VIDEOINFO:")); + str.Format(_T("dwStartTimeCode: %u"), mvih.dwStartTimeCode); + sl.AddTail(str); + str.Format(_T("cbSequenceHeader: %u"), mvih.cbSequenceHeader); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (formattype == FORMAT_MPEG2_VIDEO) { + MPEG2VIDEOINFO& mvih = *(MPEG2VIDEOINFO*)pbFormat; + + sl.AddTail(_T("MPEG2VIDEOINFO:")); + str.Format(_T("dwStartTimeCode: %u"), mvih.dwStartTimeCode); + sl.AddTail(str); + str.Format(_T("cbSequenceHeader: %u"), mvih.cbSequenceHeader); + sl.AddTail(str); + str.Format(_T("dwProfile: 0x%08x"), mvih.dwProfile); + sl.AddTail(str); + str.Format(_T("dwLevel: 0x%08x"), mvih.dwLevel); + sl.AddTail(str); + str.Format(_T("dwFlags: 0x%08x"), mvih.dwFlags); + sl.AddTail(str); + + sl.AddTail(_T("")); + } + + sl.AddTail(_T("BITMAPINFOHEADER:")); + str.Format(_T("biSize: %u"), bih->biSize); + sl.AddTail(str); + str.Format(_T("biWidth: %ld"), bih->biWidth); + sl.AddTail(str); + str.Format(_T("biHeight: %ld"), bih->biHeight); + sl.AddTail(str); + str.Format(_T("biPlanes: %u"), bih->biPlanes); + sl.AddTail(str); + str.Format(_T("biBitCount: %u"), bih->biBitCount); + sl.AddTail(str); + if (bih->biCompression < 256) { + str.Format(_T("biCompression: %u"), bih->biCompression); + } else { + str.Format(_T("biCompression: %4.4hs"), &bih->biCompression); + } + sl.AddTail(str); + str.Format(_T("biSizeImage: %u"), bih->biSizeImage); + sl.AddTail(str); + str.Format(_T("biXPelsPerMeter: %ld"), bih->biXPelsPerMeter); + sl.AddTail(str); + str.Format(_T("biYPelsPerMeter: %ld"), bih->biYPelsPerMeter); + sl.AddTail(str); + str.Format(_T("biClrUsed: %u"), bih->biClrUsed); + sl.AddTail(str); + str.Format(_T("biClrImportant: %u"), bih->biClrImportant); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (formattype == FORMAT_WaveFormatEx || formattype == FORMAT_WaveFormatExFFMPEG) { + WAVEFORMATEX* pWfe = nullptr; + if (formattype == FORMAT_WaveFormatExFFMPEG) { + fmtsize = sizeof(WAVEFORMATEXFFMPEG); + + WAVEFORMATEXFFMPEG* wfeff = (WAVEFORMATEXFFMPEG*)pbFormat; + pWfe = &wfeff->wfex; + + sl.AddTail(_T("WAVEFORMATEXFFMPEG:")); + str.Format(_T("nCodecId: 0x%04x"), wfeff->nCodecId); + sl.AddTail(str); + sl.AddTail(_T("")); + } else { + fmtsize = sizeof(WAVEFORMATEX); + pWfe = (WAVEFORMATEX*)pbFormat; + } + + WAVEFORMATEX& wfe = *pWfe; + + sl.AddTail(_T("WAVEFORMATEX:")); + str.Format(_T("wFormatTag: 0x%04x"), wfe.wFormatTag); + sl.AddTail(str); + str.Format(_T("nChannels: %u"), wfe.nChannels); + sl.AddTail(str); + str.Format(_T("nSamplesPerSec: %u"), wfe.nSamplesPerSec); + sl.AddTail(str); + str.Format(_T("nAvgBytesPerSec: %u"), wfe.nAvgBytesPerSec); + sl.AddTail(str); + str.Format(_T("nBlockAlign: %u"), wfe.nBlockAlign); + sl.AddTail(str); + str.Format(_T("wBitsPerSample: %u"), wfe.wBitsPerSample); + sl.AddTail(str); + str.Format(_T("cbSize: %u (extra bytes)"), wfe.cbSize); + sl.AddTail(str); + + sl.AddTail(_T("")); + + if (wfe.wFormatTag != WAVE_FORMAT_PCM && wfe.cbSize > 0 && formattype == FORMAT_WaveFormatEx) { + if (wfe.wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfe.cbSize == sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { + fmtsize = sizeof(WAVEFORMATEXTENSIBLE); + + WAVEFORMATEXTENSIBLE& wfextensible = *(WAVEFORMATEXTENSIBLE*)pbFormat; + + sl.AddTail(_T("WAVEFORMATEXTENSIBLE:")); + if (wfextensible.Format.wBitsPerSample != 0) { + str.Format(_T("wValidBitsPerSample: %u"), wfextensible.Samples.wValidBitsPerSample); + } else { + str.Format(_T("wSamplesPerBlock: %u"), wfextensible.Samples.wSamplesPerBlock); + } + sl.AddTail(str); + str.Format(_T("dwChannelMask: 0x%08x"), wfextensible.dwChannelMask); + sl.AddTail(str); + str.Format(_T("SubFormat: %s"), CStringFromGUID(wfextensible.SubFormat).GetString()); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (wfe.wFormatTag == WAVE_FORMAT_DOLBY_AC3 && wfe.cbSize == sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX)) { + fmtsize = sizeof(DOLBYAC3WAVEFORMAT); + + DOLBYAC3WAVEFORMAT& dawf = *(DOLBYAC3WAVEFORMAT*)pbFormat; + + sl.AddTail(_T("DOLBYAC3WAVEFORMAT:")); + str.Format(_T("bBigEndian: %u"), dawf.bBigEndian); + sl.AddTail(str); + str.Format(_T("bsid: %u"), dawf.bsid); + sl.AddTail(str); + str.Format(_T("lfeon: %u"), dawf.lfeon); + sl.AddTail(str); + str.Format(_T("copyrightb: %u"), dawf.copyrightb); + sl.AddTail(str); + str.Format(_T("nAuxBitsCode: %u"), dawf.nAuxBitsCode); + sl.AddTail(str); + + sl.AddTail(_T("")); + } + } + } else if (formattype == FORMAT_VorbisFormat) { + fmtsize = sizeof(VORBISFORMAT); + + VORBISFORMAT& vf = *(VORBISFORMAT*)pbFormat; + + sl.AddTail(_T("VORBISFORMAT:")); + str.Format(_T("nChannels: %u"), vf.nChannels); + sl.AddTail(str); + str.Format(_T("nSamplesPerSec: %lu"), vf.nSamplesPerSec); + sl.AddTail(str); + str.Format(_T("nMinBitsPerSec: %lu"), vf.nMinBitsPerSec); + sl.AddTail(str); + str.Format(_T("nAvgBitsPerSec: %lu"), vf.nAvgBitsPerSec); + sl.AddTail(str); + str.Format(_T("nMaxBitsPerSec: %lu"), vf.nMaxBitsPerSec); + sl.AddTail(str); + str.Format(_T("fQuality: %.3f"), vf.fQuality); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (formattype == FORMAT_VorbisFormat2) { + fmtsize = sizeof(VORBISFORMAT2); + + VORBISFORMAT2& vf = *(VORBISFORMAT2*)pbFormat; + + sl.AddTail(_T("VORBISFORMAT:")); + str.Format(_T("Channels: %lu"), vf.Channels); + sl.AddTail(str); + str.Format(_T("SamplesPerSec: %lu"), vf.SamplesPerSec); + sl.AddTail(str); + str.Format(_T("BitsPerSample: %lu"), vf.BitsPerSample); + sl.AddTail(str); + str.Format(_T("HeaderSize: {%lu, %lu, %lu}"), vf.HeaderSize[0], vf.HeaderSize[1], vf.HeaderSize[2]); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (formattype == FORMAT_SubtitleInfo) { + fmtsize = sizeof(SUBTITLEINFO); + + SUBTITLEINFO& si = *(SUBTITLEINFO*)pbFormat; + + sl.AddTail(_T("SUBTITLEINFO:")); + str.Format(_T("dwOffset: %lu"), si.dwOffset); + sl.AddTail(str); + str.Format(_T("IsoLang: %S"), CStringA(si.IsoLang, sizeof(si.IsoLang) - 1).GetString()); + sl.AddTail(str); + str.Format(_T("TrackName: %s"), CStringW(si.TrackName, sizeof(si.TrackName) - 1).GetString()); + sl.AddTail(str); + + sl.AddTail(_T("")); + } + + if (cbFormat > 0) { + sl.AddTail(_T("pbFormat:")); + + for (ptrdiff_t i = 0, j = (cbFormat + 15) & ~15; i < j; i += 16) { + str.Format(_T("%04Ix:"), i); + + for (ptrdiff_t k = i, l = std::min(i + 16, (ptrdiff_t)cbFormat); k < l; k++) { + CString byte; + byte.Format(_T("%c%02x"), fmtsize > 0 && fmtsize == k ? '|' : ' ', pbFormat[k]); + str += byte; + } + + for (ptrdiff_t k = std::min(i + 16, (ptrdiff_t)cbFormat), l = i + 16; k < l; k++) { + str += _T(" "); + } + + str += _T(' '); + + for (ptrdiff_t k = i, l = std::min(i + 16, (ptrdiff_t)cbFormat); k < l; k++) { + unsigned char c = (unsigned char)pbFormat[k]; + CString ch; + ch.Format(_T("%C"), c >= 0x20 ? c : '.'); + str += ch; + } + + sl.AddTail(str); + } + + sl.AddTail(_T("")); + } +} diff --git a/src/DSUtil/MediaTypeEx.h b/src/DSUtil/MediaTypeEx.h index 63ec7e0c1fd..10d15b436c8 100644 --- a/src/DSUtil/MediaTypeEx.h +++ b/src/DSUtil/MediaTypeEx.h @@ -1,42 +1,42 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#pragma once - -#include - -class CMediaTypeEx : public CMediaType -{ -public: - CMediaTypeEx(); - ~CMediaTypeEx(); - CMediaTypeEx(const CMediaType& mt) { - CMediaType::operator = (mt); - } - - CString ToString(IPin* pPin = nullptr); - - static CString GetVideoCodecName(const GUID& subtype, DWORD biCompression); - static CString GetAudioCodecName(const GUID& subtype, WORD wFormatTag); - static CString GetSubtitleCodecName(const GUID& subtype); - - void Dump(CAtlList& sl); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#pragma once + +#include + +class CMediaTypeEx : public CMediaType +{ +public: + CMediaTypeEx(); + ~CMediaTypeEx(); + CMediaTypeEx(const CMediaType& mt) { + CMediaType::operator = (mt); + } + + CString ToString(IPin* pPin = nullptr); + + static CString GetVideoCodecName(const GUID& subtype, DWORD biCompression); + static CString GetAudioCodecName(const GUID& subtype, WORD wFormatTag); + static CString GetSubtitleCodecName(const GUID& subtype); + + void Dump(CAtlList& sl); +}; diff --git a/src/DSUtil/MediaTypes.cpp b/src/DSUtil/MediaTypes.cpp index efa66a4c9e8..158a43be670 100644 --- a/src/DSUtil/MediaTypes.cpp +++ b/src/DSUtil/MediaTypes.cpp @@ -1,463 +1,463 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include "moreuuids.h" -#include "MediaTypes.h" -#include "DSUtil.h" - -#define VIH_NORMAL (sizeof(VIDEOINFOHEADER)) -#define VIH_BITFIELDS (sizeof(VIDEOINFOHEADER) + 3 * sizeof(RGBQUAD)) -#define VIH2_NORMAL (sizeof(VIDEOINFOHEADER2)) -#define VIH2_BITFIELDS (sizeof(VIDEOINFOHEADER2) + 3 * sizeof(RGBQUAD)) -#define BIH_SIZE (sizeof(BITMAPINFOHEADER)) - -const VIH vihs[] = { - // VYUY - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('V', 'Y', 'U', 'Y'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_VYUY // subtype - }, - // YVYU - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'V', 'Y', 'U'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_YVYU // subtype - }, - // UYVY - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_UYVY // subtype - }, - // YUY2 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_YUY2 // subtype - }, - // YV12 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_YV12 // subtype - }, - // I420 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', '4', '2', '0'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_I420 // subtype - }, - // IYUV - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', 'Y', 'U', 'V'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_IYUV // subtype - }, - // NV12 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('N', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_NV12 // subtype - }, - // 8888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_RGB32 // subtype - }, - // 8888 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_RGB32 // subtype - }, - // A888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_ARGB32 // subtype - }, - // A888 bitf (I'm not sure if this exist...) - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_ARGB32 // subtype - }, - // 888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 24, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_RGB24 // subtype - }, - // 888 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 24, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_RGB24 // subtype - }, - // 565 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_RGB565 // subtype - }, - // 565 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xF800, 0x07E0, 0x001F}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_RGB565 // subtype - }, - // 555 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_RGB555 // subtype - }, - // 555 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0x7C00, 0x03E0, 0x001F}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_RGB555 // subtype - }, -}; - -const VIH2 vih2s[] = { - // VYUY - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('V', 'Y', 'U', 'Y'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_VYUY // subtype - }, - // YVYU - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'V', 'Y', 'U'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_YVYU // subtype - }, - // UYVY - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_UYVY // subtype - }, - // YUY2 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_YUY2 // subtype - }, - // YV12 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_YV12 // subtype - }, - // I420 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', '4', '2', '0'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_I420 // subtype - }, - // IYUV - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', 'Y', 'U', 'V'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_IYUV // subtype - }, - // NV12 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('N', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_NV12 // subtype - }, - // 8888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_RGB32 // subtype - }, - // 8888 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_RGB32 // subtype - }, - // A888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_ARGB32 // subtype - }, - // A888 bitf (I'm not sure if this exist...) - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_ARGB32 // subtype - }, - // 888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 24, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_RGB24 // subtype - }, - // 888 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 24, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_RGB24 // subtype - }, - // 565 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_RGB565 // subtype - }, - // 565 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xF800, 0x07E0, 0x001F}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_RGB565 // subtype - }, - // 555 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_RGB555 // subtype - }, - // 555 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0x7C00, 0x03E0, 0x001F}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_RGB555 // subtype - }, -}; - -extern const UINT VIHSIZE = _countof(vihs); - -CString VIH2String(int i) -{ - CString ret(GuidNames[*vihs[i].subtype]); - if (!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) { - ret = ret.Mid(13); - } - if (vihs[i].vih.bmiHeader.biCompression == 3) { - ret += _T(" BITF"); - } - if (*vihs[i].subtype == MEDIASUBTYPE_I420) { - ret = _T("I420"); // FIXME - } - return ret; -} - -CString Subtype2String(const GUID& subtype) -{ - CString ret(GuidNames[subtype]); - if (!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) { - ret = ret.Mid(13); - } - if (subtype == MEDIASUBTYPE_I420) { - ret = _T("I420"); // FIXME - } - return ret; -} - -void CorrectMediaType(AM_MEDIA_TYPE* pmt) -{ - if (!pmt) { - return; - } - - CMediaType mt(*pmt); - - if (mt.formattype == FORMAT_VideoInfo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mt.pbFormat; - - for (UINT i = 0; i < VIHSIZE; i++) { - if (mt.subtype == *vihs[i].subtype - && vih->bmiHeader.biCompression == vihs[i].vih.bmiHeader.biCompression) { - mt.AllocFormatBuffer(vihs[i].size); - memcpy(mt.pbFormat, &vihs[i], vihs[i].size); - memcpy(mt.pbFormat, pmt->pbFormat, sizeof(VIDEOINFOHEADER)); - break; - } - } - } else if (mt.formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mt.pbFormat; - - for (UINT i = 0; i < VIHSIZE; i++) { - if (mt.subtype == *vih2s[i].subtype - && vih2->bmiHeader.biCompression == vih2s[i].vih.bmiHeader.biCompression) { - mt.AllocFormatBuffer(vih2s[i].size); - memcpy(mt.pbFormat, &vih2s[i], vih2s[i].size); - memcpy(mt.pbFormat, pmt->pbFormat, sizeof(VIDEOINFOHEADER2)); - break; - } - } - } - - CopyMediaType(pmt, &mt); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include "moreuuids.h" +#include "MediaTypes.h" +#include "DSUtil.h" + +#define VIH_NORMAL (sizeof(VIDEOINFOHEADER)) +#define VIH_BITFIELDS (sizeof(VIDEOINFOHEADER) + 3 * sizeof(RGBQUAD)) +#define VIH2_NORMAL (sizeof(VIDEOINFOHEADER2)) +#define VIH2_BITFIELDS (sizeof(VIDEOINFOHEADER2) + 3 * sizeof(RGBQUAD)) +#define BIH_SIZE (sizeof(BITMAPINFOHEADER)) + +const VIH vihs[] = { + // VYUY + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('V', 'Y', 'U', 'Y'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_VYUY // subtype + }, + // YVYU + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'V', 'Y', 'U'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_YVYU // subtype + }, + // UYVY + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_UYVY // subtype + }, + // YUY2 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_YUY2 // subtype + }, + // YV12 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_YV12 // subtype + }, + // I420 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', '4', '2', '0'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_I420 // subtype + }, + // IYUV + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', 'Y', 'U', 'V'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_IYUV // subtype + }, + // NV12 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('N', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_NV12 // subtype + }, + // 8888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_RGB32 // subtype + }, + // 8888 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_RGB32 // subtype + }, + // A888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_ARGB32 // subtype + }, + // A888 bitf (I'm not sure if this exist...) + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_ARGB32 // subtype + }, + // 888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 24, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_RGB24 // subtype + }, + // 888 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 24, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_RGB24 // subtype + }, + // 565 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_RGB565 // subtype + }, + // 565 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xF800, 0x07E0, 0x001F}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_RGB565 // subtype + }, + // 555 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_RGB555 // subtype + }, + // 555 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0x7C00, 0x03E0, 0x001F}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_RGB555 // subtype + }, +}; + +const VIH2 vih2s[] = { + // VYUY + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('V', 'Y', 'U', 'Y'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_VYUY // subtype + }, + // YVYU + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'V', 'Y', 'U'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_YVYU // subtype + }, + // UYVY + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_UYVY // subtype + }, + // YUY2 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_YUY2 // subtype + }, + // YV12 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_YV12 // subtype + }, + // I420 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', '4', '2', '0'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_I420 // subtype + }, + // IYUV + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', 'Y', 'U', 'V'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_IYUV // subtype + }, + // NV12 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('N', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_NV12 // subtype + }, + // 8888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_RGB32 // subtype + }, + // 8888 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_RGB32 // subtype + }, + // A888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_ARGB32 // subtype + }, + // A888 bitf (I'm not sure if this exist...) + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_ARGB32 // subtype + }, + // 888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 24, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_RGB24 // subtype + }, + // 888 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 24, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_RGB24 // subtype + }, + // 565 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_RGB565 // subtype + }, + // 565 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xF800, 0x07E0, 0x001F}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_RGB565 // subtype + }, + // 555 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_RGB555 // subtype + }, + // 555 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0x7C00, 0x03E0, 0x001F}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_RGB555 // subtype + }, +}; + +extern const UINT VIHSIZE = _countof(vihs); + +CString VIH2String(int i) +{ + CString ret(GuidNames[*vihs[i].subtype]); + if (!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) { + ret = ret.Mid(13); + } + if (vihs[i].vih.bmiHeader.biCompression == 3) { + ret += _T(" BITF"); + } + if (*vihs[i].subtype == MEDIASUBTYPE_I420) { + ret = _T("I420"); // FIXME + } + return ret; +} + +CString Subtype2String(const GUID& subtype) +{ + CString ret(GuidNames[subtype]); + if (!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) { + ret = ret.Mid(13); + } + if (subtype == MEDIASUBTYPE_I420) { + ret = _T("I420"); // FIXME + } + return ret; +} + +void CorrectMediaType(AM_MEDIA_TYPE* pmt) +{ + if (!pmt) { + return; + } + + CMediaType mt(*pmt); + + if (mt.formattype == FORMAT_VideoInfo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mt.pbFormat; + + for (UINT i = 0; i < VIHSIZE; i++) { + if (mt.subtype == *vihs[i].subtype + && vih->bmiHeader.biCompression == vihs[i].vih.bmiHeader.biCompression) { + mt.AllocFormatBuffer(vihs[i].size); + memcpy(mt.pbFormat, &vihs[i], vihs[i].size); + memcpy(mt.pbFormat, pmt->pbFormat, sizeof(VIDEOINFOHEADER)); + break; + } + } + } else if (mt.formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mt.pbFormat; + + for (UINT i = 0; i < VIHSIZE; i++) { + if (mt.subtype == *vih2s[i].subtype + && vih2->bmiHeader.biCompression == vih2s[i].vih.bmiHeader.biCompression) { + mt.AllocFormatBuffer(vih2s[i].size); + memcpy(mt.pbFormat, &vih2s[i], vih2s[i].size); + memcpy(mt.pbFormat, pmt->pbFormat, sizeof(VIDEOINFOHEADER2)); + break; + } + } + } + + CopyMediaType(pmt, &mt); +} diff --git a/src/DSUtil/MediaTypes.h b/src/DSUtil/MediaTypes.h index 91919bf3ca9..7e5f3d4466c 100644 --- a/src/DSUtil/MediaTypes.h +++ b/src/DSUtil/MediaTypes.h @@ -1,48 +1,48 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include - -#pragma pack(push, 1) -struct VIH { - VIDEOINFOHEADER vih; - UINT mask[3]; - int size; - const GUID* subtype; -}; - -struct VIH2 { - VIDEOINFOHEADER2 vih; - UINT mask[3]; - int size; - const GUID* subtype; -}; -#pragma pack(pop) - -extern const VIH vihs[]; -extern const VIH2 vih2s[]; - -extern const UINT VIHSIZE; - -extern CString VIH2String(int i), Subtype2String(const GUID& subtype); -extern void CorrectMediaType(AM_MEDIA_TYPE* pmt); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include + +#pragma pack(push, 1) +struct VIH { + VIDEOINFOHEADER vih; + UINT mask[3]; + int size; + const GUID* subtype; +}; + +struct VIH2 { + VIDEOINFOHEADER2 vih; + UINT mask[3]; + int size; + const GUID* subtype; +}; +#pragma pack(pop) + +extern const VIH vihs[]; +extern const VIH2 vih2s[]; + +extern const UINT VIHSIZE; + +extern CString VIH2String(int i), Subtype2String(const GUID& subtype); +extern void CorrectMediaType(AM_MEDIA_TYPE* pmt); diff --git a/src/DSUtil/Mpeg2Def.h b/src/DSUtil/Mpeg2Def.h index 777da480d51..39473c91289 100644 --- a/src/DSUtil/Mpeg2Def.h +++ b/src/DSUtil/Mpeg2Def.h @@ -1,200 +1,200 @@ -/* - * (C) 2009-2015 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 . - * - */ - -#pragma once - -enum PES_STREAM_TYPE { - INVALID = 0, - VIDEO_STREAM_MPEG1 = 0x01, - VIDEO_STREAM_MPEG2 = 0x02, // ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream - AUDIO_STREAM_MPEG1 = 0x03, // all layers including mp3 (ISO/IEC 11172-3 Audio) - AUDIO_STREAM_MPEG2 = 0x04, // ISO/IEC 13818-3 Audio - PRIVATE = 0x05, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections - PES_PRIVATE = 0x06, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data - PES_07 = 0x07, // ISO/IEC 13522 MHEG - PES_08 = 0x08, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC - PES_09 = 0x09, // ITU-T Rec. H.222.1 - PES_0a = 0x0a, // ISO/IEC 13818-6 type A - PES_0b = 0x0b, // ISO/IEC 13818-6 type B - PES_0c = 0x0c, // ISO/IEC 13818-6 type C - PES_0d = 0x0d, // ISO/IEC 13818-6 type D - PES_0e = 0x0e, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary - AUDIO_STREAM_AAC = 0x0f, // ISO/IEC 13818-7 Audio with ADTS transport syntax - PES_10 = 0x10, // ISO/IEC 14496-2 Visual - AUDIO_STREAM_AAC_LATM = 0x11, // ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1 - PES_12 = 0x12, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets - PES_13 = 0x13, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections. - PES_14 = 0x14, // ISO/IEC 13818-6 Synchronized Download Protocol - METADATA_PES_PACKETS = 0x15, // Metadata carried in PES packets - METADATA_SECTIONS = 0X16, // Metadata carried in metadata_sections - DATA_CAROUSEL = 0x17, // Metadata carried in ISO/IEC 13818-6 Data Carousel - OBJECT_CAROUSEL = 0x18, // Metadata carried in ISO/IEC 13818-6 Object Carousel - SYNCHRONIZED_DOWNLOAD = 0x19, // Metadata carried in ISO/IEC 13818-6 Synchronized Download Protocol - IPMP = 0x1A, // IPMP stream (defined in ISO/IEC 13818-11, MPEG-2 IPMP) - VIDEO_STREAM_H264 = 0x1B, // AVC video stream conforming to one or more profiles defined in Annex A of ITU-T Rec. H.264 - PES_1C = 0x1C, // ISO/IEC 14496-3 Audio, without using any additional transport syntax, such as DST, ALS and SLS - TEXT = 0x1D, // ISO/IEC 14496-17 Text - AUXILIARY_VIDEO_STREAM = 0x1E, // Auxiliary video stream as defined in ISO/IEC 23002-3 - SVC_H264 = 0x1F, // SVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex G of ITU-T Rec. H.264 | ISO/IEC 14496-10 - MVC_H264 = 0x20, // MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10 - VIDEO_STREAM_JPEG2000 = 0x21, // ITU - T Rec.T.800 | ISO / IEC 15444 - 1 - ADDITIONAL_VIEW_MPEG2 = 0x22, // ITU - T Rec.H.262 | ISO / IEC 13818 - 2 Additional view for compatible 3D - ADDITIONAL_VIEW_H264 = 0x23, // ITU - T Rec.H.264 | ISO / IEC 14496 - 10 Additional view for compatible 3D - VIDEO_STREAM_HEVC = 0x24, // ITU - T Rec.H.265 | ISO / IEC 23008 - 2 video stream - VIDEO_SUBSET_HEVC = 0x25, // ITU - T Rec.H.265 | ISO / IEC 23008 - 2 Annex A temporal video subset - MVCD_H264 = 0x26, // ITU - T Rec.H.264 | ISO / IEC 14496 - 10 Annex I MVCD video sub - bitstream - AUDIO_STREAM_LPCM = 0x80, - AUDIO_STREAM_AC3 = 0x81, - AUDIO_STREAM_DTS = 0x82, - AUDIO_STREAM_AC3_TRUE_HD = 0x83, - AUDIO_STREAM_AC3_PLUS = 0x84, - AUDIO_STREAM_DTS_HD = 0x85, - AUDIO_STREAM_DTS_HD_MASTER_AUDIO = 0x86, - PRESENTATION_GRAPHICS_STREAM = 0x90, - INTERACTIVE_GRAPHICS_STREAM = 0x91, - SUBTITLE_STREAM = 0x92, - SECONDARY_AUDIO_AC3_PLUS = 0xa1, - SECONDARY_AUDIO_DTS_HD = 0xa2, - VIDEO_STREAM_VC1 = 0xea -}; - -enum MPEG2_PID { - PID_PAT = 0x000, // Program Association Table - PID_CAT = 0x001, // Conditional Access Table - PID_TSDT = 0x002, // Transport Stream Description Table - PID_NIT = 0x010, // Network Identification Table - PID_BAT = 0x011, // Bouquet Association Table or ... - PID_SDT = 0x011, // ... Service Description Table - PID_EIT = 0x012, // Event Information Table - PID_RST = 0x013, // Running Status Table - PID_TDT = 0x014, // Time and Date Table or ... - PID_TOT = 0x014, // ... Time Offset Table - PID_SFN = 0x015, // SFN/MIP synchronization - PID_DIT = 0x01e, - PID_SIT = 0x01f, - PID_ATSC_PAT_E = 0x1FF7, - PID_PSIP_TS_E = 0x1FF9, - PID_PSIP = 0x1FFB, - PID_NULL = 0x1fff // Null packet -}; - -enum DVB_SI { - SI_undef = -1, - SI_PAT = 0x00, - SI_CAT = 0x01, - SI_PMT = 0x02, - SI_DSMCC_a = 0x3a, - SI_DSMCC_b = 0x3b, - SI_DSMCC_c = 0x3c, - SI_DSMCC_d = 0x3d, - SI_DSMCC_e = 0x3e, - SI_DSMCC_f = 0x3f, - SI_NIT = 0x40, - SI_SDT = 0x42, - SI_EIT_act = 0x4e, - SI_EIT_oth = 0x4f, - SI_EIT_as0, SI_EIT_as1, SI_EIT_as2, SI_EIT_as3, SI_EIT_as4, SI_EIT_as5, SI_EIT_as6, SI_EIT_as7, - SI_EIT_as8, SI_EIT_as9, SI_EIT_asa, SI_EIT_asb, SI_EIT_asc, SI_EIT_asd, SI_EIT_ase, SI_EIT_asf, - SI_EIT_os0, SI_EIT_os1, SI_EIT_os2, SI_EIT_os3, SI_EIT_os4, SI_EIT_os5, SI_EIT_os6, SI_EIT_os7, - SI_EIT_os8, SI_EIT_os9, SI_EIT_osa, SI_EIT_osb, SI_EIT_osc, SI_EIT_osd, SI_EIT_ose, SI_EIT_osf, - TID_MGT = 0xC7, - TID_TVCT = 0xC8, - TID_CVCT = 0xC9 -}; - -enum ATSC_TABLE_TYPE { - TT_TVCT_C1 = 0x0000, - TT_TVCT_C0 = 0x0001, - TT_CVCT_C1 = 0x0002, - TT_CVCT_C0 = 0x0003, - TT_ETT = 0x0004, - TT_DCCSCT = 0x0005, -}; - -enum MPEG2_DESCRIPTOR { - // http://www.coolstf.com/tsreader/descriptors.html - DT_VIDEO_STREAM = 0x02, - DT_AUDIO_STREAM = 0x03, - DT_HIERARCHY = 0x04, - DT_REGISTRATION = 0x05, - DT_DATA_STREAM_ALIGNMENT = 0x06, - DT_TARGET_BACKGROUND_GRID = 0x07, - DT_VIDEO_WINDOW = 0x08, - DT_CONDITIONAL_ACCESS = 0x09, - DT_ISO_639_LANGUAGE = 0x0a, - DT_SYSTEM_CLOCK = 0x0b, - DT_MULTIPLEX_BUFFER_UTIL = 0x0c, - DT_COPYRIGHT_DESCRIPTOR = 0x0d, - DT_MAXIMUM_BITRATE = 0x0e, - DT_PRIVATE_DATA_INDICATOR = 0x0f, - DT_SMOOTHING_BUFFER = 0x10, - DT_STD = 0x11, // System Target Decoder ? - DT_IBP = 0x12, - DT_NETWORK_NAME = 0x40, - DT_SERVICE_LIST = 0x41, - DT_VBI_DATA = 0x45, - DT_SERVICE = 0x48, - DT_LINKAGE = 0x4a, - DT_SHORT_EVENT = 0x4d, - DT_EXTENDED_EVENT = 0x4e, - DT_COMPONENT = 0x50, - DT_STREAM_IDENTIFIER = 0x52, - DT_CONTENT = 0x54, - DT_PARENTAL_RATING = 0x55, - DT_TELETEXT = 0x56, - DT_SUBTITLING = 0x59, - DT_TERRESTRIAL_DELIV_SYS = 0x5a, - DT_PRIVATE_DATA = 0x5f, - DID_DATA_BROADCAST = 0x64, - DT_DATA_BROADCAST_ID = 0x66, - DT_AC3_AUDIO = 0x6a, // DVB - DT_EXTENDED_AC3_AUDIO = 0x7a, - DT_AAC_AUDIO = 0x7c, - - DT_AC3_AUDIO__2 = 0x81, // DCII or ATSC - DT_LOGICAL_CHANNEL = 0x83, - DT_HD_SIMCAST_LOG_CHANNEL = 0x88 -}; - -enum MPEG_TYPES { - mpeg_us, - mpeg_ps, - mpeg_ts, - mpeg_es, - mpeg_pva -}; - -enum SERVICE_TYPE { - DIGITAL_TV = 0x01, - DIGITAL_RADIO = 0x02, - AVC_DIGITAL_RADIO = 0x0A, - MPEG2_HD_DIGITAL_TV = 0x11, - AVC_SD_TV = 0x16, - AVC_HD_TV = 0x19, - HEVC_TV = 0x1F -}; - -enum ATSC_SERVICE_TYPE { - ATSC_ANALOG_TV = 0x01, - ATSC_DIGITAL_TV = 0x02, - ATSC_AUDIO = 0x03 -}; - -extern const wchar_t* StreamTypeToName(PES_STREAM_TYPE _Type); +/* + * (C) 2009-2015 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 . + * + */ + +#pragma once + +enum PES_STREAM_TYPE { + INVALID = 0, + VIDEO_STREAM_MPEG1 = 0x01, + VIDEO_STREAM_MPEG2 = 0x02, // ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream + AUDIO_STREAM_MPEG1 = 0x03, // all layers including mp3 (ISO/IEC 11172-3 Audio) + AUDIO_STREAM_MPEG2 = 0x04, // ISO/IEC 13818-3 Audio + PRIVATE = 0x05, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections + PES_PRIVATE = 0x06, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data + PES_07 = 0x07, // ISO/IEC 13522 MHEG + PES_08 = 0x08, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC + PES_09 = 0x09, // ITU-T Rec. H.222.1 + PES_0a = 0x0a, // ISO/IEC 13818-6 type A + PES_0b = 0x0b, // ISO/IEC 13818-6 type B + PES_0c = 0x0c, // ISO/IEC 13818-6 type C + PES_0d = 0x0d, // ISO/IEC 13818-6 type D + PES_0e = 0x0e, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary + AUDIO_STREAM_AAC = 0x0f, // ISO/IEC 13818-7 Audio with ADTS transport syntax + PES_10 = 0x10, // ISO/IEC 14496-2 Visual + AUDIO_STREAM_AAC_LATM = 0x11, // ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1 + PES_12 = 0x12, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets + PES_13 = 0x13, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections. + PES_14 = 0x14, // ISO/IEC 13818-6 Synchronized Download Protocol + METADATA_PES_PACKETS = 0x15, // Metadata carried in PES packets + METADATA_SECTIONS = 0X16, // Metadata carried in metadata_sections + DATA_CAROUSEL = 0x17, // Metadata carried in ISO/IEC 13818-6 Data Carousel + OBJECT_CAROUSEL = 0x18, // Metadata carried in ISO/IEC 13818-6 Object Carousel + SYNCHRONIZED_DOWNLOAD = 0x19, // Metadata carried in ISO/IEC 13818-6 Synchronized Download Protocol + IPMP = 0x1A, // IPMP stream (defined in ISO/IEC 13818-11, MPEG-2 IPMP) + VIDEO_STREAM_H264 = 0x1B, // AVC video stream conforming to one or more profiles defined in Annex A of ITU-T Rec. H.264 + PES_1C = 0x1C, // ISO/IEC 14496-3 Audio, without using any additional transport syntax, such as DST, ALS and SLS + TEXT = 0x1D, // ISO/IEC 14496-17 Text + AUXILIARY_VIDEO_STREAM = 0x1E, // Auxiliary video stream as defined in ISO/IEC 23002-3 + SVC_H264 = 0x1F, // SVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex G of ITU-T Rec. H.264 | ISO/IEC 14496-10 + MVC_H264 = 0x20, // MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10 + VIDEO_STREAM_JPEG2000 = 0x21, // ITU - T Rec.T.800 | ISO / IEC 15444 - 1 + ADDITIONAL_VIEW_MPEG2 = 0x22, // ITU - T Rec.H.262 | ISO / IEC 13818 - 2 Additional view for compatible 3D + ADDITIONAL_VIEW_H264 = 0x23, // ITU - T Rec.H.264 | ISO / IEC 14496 - 10 Additional view for compatible 3D + VIDEO_STREAM_HEVC = 0x24, // ITU - T Rec.H.265 | ISO / IEC 23008 - 2 video stream + VIDEO_SUBSET_HEVC = 0x25, // ITU - T Rec.H.265 | ISO / IEC 23008 - 2 Annex A temporal video subset + MVCD_H264 = 0x26, // ITU - T Rec.H.264 | ISO / IEC 14496 - 10 Annex I MVCD video sub - bitstream + AUDIO_STREAM_LPCM = 0x80, + AUDIO_STREAM_AC3 = 0x81, + AUDIO_STREAM_DTS = 0x82, + AUDIO_STREAM_AC3_TRUE_HD = 0x83, + AUDIO_STREAM_AC3_PLUS = 0x84, + AUDIO_STREAM_DTS_HD = 0x85, + AUDIO_STREAM_DTS_HD_MASTER_AUDIO = 0x86, + PRESENTATION_GRAPHICS_STREAM = 0x90, + INTERACTIVE_GRAPHICS_STREAM = 0x91, + SUBTITLE_STREAM = 0x92, + SECONDARY_AUDIO_AC3_PLUS = 0xa1, + SECONDARY_AUDIO_DTS_HD = 0xa2, + VIDEO_STREAM_VC1 = 0xea +}; + +enum MPEG2_PID { + PID_PAT = 0x000, // Program Association Table + PID_CAT = 0x001, // Conditional Access Table + PID_TSDT = 0x002, // Transport Stream Description Table + PID_NIT = 0x010, // Network Identification Table + PID_BAT = 0x011, // Bouquet Association Table or ... + PID_SDT = 0x011, // ... Service Description Table + PID_EIT = 0x012, // Event Information Table + PID_RST = 0x013, // Running Status Table + PID_TDT = 0x014, // Time and Date Table or ... + PID_TOT = 0x014, // ... Time Offset Table + PID_SFN = 0x015, // SFN/MIP synchronization + PID_DIT = 0x01e, + PID_SIT = 0x01f, + PID_ATSC_PAT_E = 0x1FF7, + PID_PSIP_TS_E = 0x1FF9, + PID_PSIP = 0x1FFB, + PID_NULL = 0x1fff // Null packet +}; + +enum DVB_SI { + SI_undef = -1, + SI_PAT = 0x00, + SI_CAT = 0x01, + SI_PMT = 0x02, + SI_DSMCC_a = 0x3a, + SI_DSMCC_b = 0x3b, + SI_DSMCC_c = 0x3c, + SI_DSMCC_d = 0x3d, + SI_DSMCC_e = 0x3e, + SI_DSMCC_f = 0x3f, + SI_NIT = 0x40, + SI_SDT = 0x42, + SI_EIT_act = 0x4e, + SI_EIT_oth = 0x4f, + SI_EIT_as0, SI_EIT_as1, SI_EIT_as2, SI_EIT_as3, SI_EIT_as4, SI_EIT_as5, SI_EIT_as6, SI_EIT_as7, + SI_EIT_as8, SI_EIT_as9, SI_EIT_asa, SI_EIT_asb, SI_EIT_asc, SI_EIT_asd, SI_EIT_ase, SI_EIT_asf, + SI_EIT_os0, SI_EIT_os1, SI_EIT_os2, SI_EIT_os3, SI_EIT_os4, SI_EIT_os5, SI_EIT_os6, SI_EIT_os7, + SI_EIT_os8, SI_EIT_os9, SI_EIT_osa, SI_EIT_osb, SI_EIT_osc, SI_EIT_osd, SI_EIT_ose, SI_EIT_osf, + TID_MGT = 0xC7, + TID_TVCT = 0xC8, + TID_CVCT = 0xC9 +}; + +enum ATSC_TABLE_TYPE { + TT_TVCT_C1 = 0x0000, + TT_TVCT_C0 = 0x0001, + TT_CVCT_C1 = 0x0002, + TT_CVCT_C0 = 0x0003, + TT_ETT = 0x0004, + TT_DCCSCT = 0x0005, +}; + +enum MPEG2_DESCRIPTOR { + // http://www.coolstf.com/tsreader/descriptors.html + DT_VIDEO_STREAM = 0x02, + DT_AUDIO_STREAM = 0x03, + DT_HIERARCHY = 0x04, + DT_REGISTRATION = 0x05, + DT_DATA_STREAM_ALIGNMENT = 0x06, + DT_TARGET_BACKGROUND_GRID = 0x07, + DT_VIDEO_WINDOW = 0x08, + DT_CONDITIONAL_ACCESS = 0x09, + DT_ISO_639_LANGUAGE = 0x0a, + DT_SYSTEM_CLOCK = 0x0b, + DT_MULTIPLEX_BUFFER_UTIL = 0x0c, + DT_COPYRIGHT_DESCRIPTOR = 0x0d, + DT_MAXIMUM_BITRATE = 0x0e, + DT_PRIVATE_DATA_INDICATOR = 0x0f, + DT_SMOOTHING_BUFFER = 0x10, + DT_STD = 0x11, // System Target Decoder ? + DT_IBP = 0x12, + DT_NETWORK_NAME = 0x40, + DT_SERVICE_LIST = 0x41, + DT_VBI_DATA = 0x45, + DT_SERVICE = 0x48, + DT_LINKAGE = 0x4a, + DT_SHORT_EVENT = 0x4d, + DT_EXTENDED_EVENT = 0x4e, + DT_COMPONENT = 0x50, + DT_STREAM_IDENTIFIER = 0x52, + DT_CONTENT = 0x54, + DT_PARENTAL_RATING = 0x55, + DT_TELETEXT = 0x56, + DT_SUBTITLING = 0x59, + DT_TERRESTRIAL_DELIV_SYS = 0x5a, + DT_PRIVATE_DATA = 0x5f, + DID_DATA_BROADCAST = 0x64, + DT_DATA_BROADCAST_ID = 0x66, + DT_AC3_AUDIO = 0x6a, // DVB + DT_EXTENDED_AC3_AUDIO = 0x7a, + DT_AAC_AUDIO = 0x7c, + + DT_AC3_AUDIO__2 = 0x81, // DCII or ATSC + DT_LOGICAL_CHANNEL = 0x83, + DT_HD_SIMCAST_LOG_CHANNEL = 0x88 +}; + +enum MPEG_TYPES { + mpeg_us, + mpeg_ps, + mpeg_ts, + mpeg_es, + mpeg_pva +}; + +enum SERVICE_TYPE { + DIGITAL_TV = 0x01, + DIGITAL_RADIO = 0x02, + AVC_DIGITAL_RADIO = 0x0A, + MPEG2_HD_DIGITAL_TV = 0x11, + AVC_SD_TV = 0x16, + AVC_HD_TV = 0x19, + HEVC_TV = 0x1F +}; + +enum ATSC_SERVICE_TYPE { + ATSC_ANALOG_TV = 0x01, + ATSC_DIGITAL_TV = 0x02, + ATSC_AUDIO = 0x03 +}; + +extern const wchar_t* StreamTypeToName(PES_STREAM_TYPE _Type); diff --git a/src/DSUtil/NullRenderers.cpp b/src/DSUtil/NullRenderers.cpp index 4ad61e48c4b..1607e708e9e 100644 --- a/src/DSUtil/NullRenderers.cpp +++ b/src/DSUtil/NullRenderers.cpp @@ -1,453 +1,453 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "NullRenderers.h" -#include "moreuuids.h" - -#define USE_DXVA - -#ifdef USE_DXVA - -#include -#include -#include // DXVA2 -#include -#include // API Media Foundation -#include - -#pragma comment (lib, "d3d9.lib") - -// dxva.dll -typedef HRESULT(__stdcall* PTR_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager); -typedef HRESULT(__stdcall* PTR_DXVA2CreateVideoService)(IDirect3DDevice9* pDD, REFIID riid, void** ppService); - - -class CNullVideoRendererInputPin : public CRendererInputPin, - public IMFGetService, - public IDirectXVideoMemoryConfiguration, - public IMFVideoDisplayControl -{ -public: - CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name); - ~CNullVideoRendererInputPin() { - if (m_pD3DDeviceManager) { - if (m_hDevice != INVALID_HANDLE_VALUE) { - m_pD3DDeviceManager->CloseDeviceHandle(m_hDevice); - m_hDevice = INVALID_HANDLE_VALUE; - } - m_pD3DDeviceManager = nullptr; - } - if (m_pD3DDev) { - m_pD3DDev = nullptr; - } - if (m_hDXVA2Lib) { - FreeLibrary(m_hDXVA2Lib); - } - } - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator) { - // Renderer shouldn't manage allocator for DXVA - return E_NOTIMPL; - } - - STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES* pProps) { - // 1 buffer required - ZeroMemory(pProps, sizeof(ALLOCATOR_PROPERTIES)); - pProps->cbBuffer = 1; - return S_OK; - } - - // IMFGetService - STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject); - - // IDirectXVideoMemoryConfiguration - STDMETHODIMP GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType); - STDMETHODIMP SetSurfaceType(DXVA2_SurfaceType dwType); - - - // IMFVideoDisplayControl - STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) { - return E_NOTIMPL; - }; - STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) { - return E_NOTIMPL; - }; - STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, - const LPRECT prcDest) { - return E_NOTIMPL; - }; - STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, - LPRECT prcDest) { - return E_NOTIMPL; - }; - STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode) { - return E_NOTIMPL; - }; - STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode) { - return E_NOTIMPL; - }; - STDMETHODIMP SetVideoWindow(HWND hwndVideo) { - return E_NOTIMPL; - }; - STDMETHODIMP GetVideoWindow(HWND* phwndVideo); - STDMETHODIMP RepaintVideo() { - return E_NOTIMPL; - }; - STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, - DWORD* pcbDib, LONGLONG* pTimeStamp) { - return E_NOTIMPL; - }; - STDMETHODIMP SetBorderColor(COLORREF Clr) { - return E_NOTIMPL; - }; - STDMETHODIMP GetBorderColor(COLORREF* pClr) { - return E_NOTIMPL; - }; - STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags) { - return E_NOTIMPL; - }; - STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags) { - return E_NOTIMPL; - }; - STDMETHODIMP SetFullscreen(BOOL fFullscreen) { - return E_NOTIMPL; - }; - STDMETHODIMP GetFullscreen(BOOL* pfFullscreen) { - return E_NOTIMPL; - }; - -private: - HMODULE m_hDXVA2Lib; - PTR_DXVA2CreateDirect3DDeviceManager9 pfDXVA2CreateDirect3DDeviceManager9; - PTR_DXVA2CreateVideoService pfDXVA2CreateVideoService; - - CComPtr m_pD3D; - CComPtr m_pD3DDev; - CComPtr m_pD3DDeviceManager; - UINT m_nResetToken; - HANDLE m_hDevice; - HWND m_hWnd; - - void CreateSurface(); -}; - -CNullVideoRendererInputPin::CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name) - : CRendererInputPin(pRenderer, phr, Name) - , m_hDXVA2Lib(nullptr) - , pfDXVA2CreateDirect3DDeviceManager9(nullptr) - , pfDXVA2CreateVideoService(nullptr) - , m_pD3DDev(nullptr) - , m_pD3DDeviceManager(nullptr) - , m_nResetToken(0) - , m_hDevice(INVALID_HANDLE_VALUE) -{ - CreateSurface(); - - m_hDXVA2Lib = LoadLibrary(L"dxva2.dll"); - if (m_hDXVA2Lib) { - pfDXVA2CreateDirect3DDeviceManager9 = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateDirect3DDeviceManager9")); - pfDXVA2CreateVideoService = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateVideoService")); - pfDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DDeviceManager); - } - - // Initialize Device Manager with DX surface - if (m_pD3DDev) { - m_pD3DDeviceManager->ResetDevice(m_pD3DDev, m_nResetToken); - m_pD3DDeviceManager->OpenDeviceHandle(&m_hDevice); - } -} - -void CNullVideoRendererInputPin::CreateSurface() -{ - m_pD3D.Attach(Direct3DCreate9(D3D_SDK_VERSION)); - if (!m_pD3D) { - m_pD3D.Attach(Direct3DCreate9(D3D9b_SDK_VERSION)); - } - - m_hWnd = nullptr; // TODO : put true window - - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - VERIFY(SUCCEEDED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))); - - D3DPRESENT_PARAMETERS pp; - ZeroMemory(&pp, sizeof(pp)); - - pp.Windowed = TRUE; - pp.hDeviceWindow = m_hWnd; - pp.SwapEffect = D3DSWAPEFFECT_COPY; - pp.Flags = D3DPRESENTFLAG_VIDEO; - pp.BackBufferCount = 1; - pp.BackBufferWidth = d3ddm.Width; - pp.BackBufferHeight = d3ddm.Height; - pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - - VERIFY(SUCCEEDED(m_pD3D->CreateDevice( - D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, //| D3DCREATE_MANAGED, - &pp, &m_pD3DDev))); -} - -STDMETHODIMP CNullVideoRendererInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - (riid == __uuidof(IMFGetService)) ? GetInterface((IMFGetService*)this, ppv) : - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CNullVideoRendererInputPin::GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject) -{ - if (m_pD3DDeviceManager != nullptr && guidService == MR_VIDEO_ACCELERATION_SERVICE) { - if (riid == __uuidof(IDirect3DDeviceManager9)) { - return m_pD3DDeviceManager->QueryInterface(riid, ppvObject); - } else if (riid == __uuidof(IDirectXVideoDecoderService) || riid == __uuidof(IDirectXVideoProcessorService)) { - return m_pD3DDeviceManager->GetVideoService(m_hDevice, riid, ppvObject); - } else if (riid == __uuidof(IDirectXVideoAccelerationService)) { - // TODO : to be tested.... - return pfDXVA2CreateVideoService(m_pD3DDev, riid, ppvObject); - } else if (riid == __uuidof(IDirectXVideoMemoryConfiguration)) { - GetInterface((IDirectXVideoMemoryConfiguration*)this, ppvObject); - return S_OK; - } - } else if (guidService == MR_VIDEO_RENDER_SERVICE) { - if (riid == __uuidof(IMFVideoDisplayControl)) { - GetInterface((IMFVideoDisplayControl*)this, ppvObject); - return S_OK; - } - } - - return E_NOINTERFACE; -} - -STDMETHODIMP CNullVideoRendererInputPin::GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType) -{ - if (dwTypeIndex == 0) { - *pdwType = DXVA2_SurfaceType_DecoderRenderTarget; - return S_OK; - } else { - return MF_E_NO_MORE_TYPES; - } -} - -STDMETHODIMP CNullVideoRendererInputPin::SetSurfaceType(DXVA2_SurfaceType dwType) -{ - return S_OK; -} - -STDMETHODIMP CNullVideoRendererInputPin::GetVideoWindow(HWND* phwndVideo) -{ - CheckPointer(phwndVideo, E_POINTER); - *phwndVideo = m_hWnd; // Important to implement this method (used by MPC-HC) - return S_OK; -} - - -#endif // USE_DXVA - -// -// CNullRenderer -// - -CNullRenderer::CNullRenderer(REFCLSID clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr) - : CBaseRenderer(clsid, pName, pUnk, phr) -{ -} - -// -// CNullVideoRenderer -// - -CNullVideoRenderer::CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CNullRenderer(__uuidof(this), NAME("Null Video Renderer"), pUnk, phr) -{ -} - -HRESULT CNullVideoRenderer::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Video - || pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO - ? S_OK - : E_FAIL; -} - -// -// CNullUVideoRenderer -// - -CNullUVideoRenderer::CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CNullRenderer(__uuidof(this), NAME("Null Video Renderer (Uncompressed)"), pUnk, phr) -{ -#ifdef USE_DXVA - m_pInputPin = DEBUG_NEW CNullVideoRendererInputPin(this, phr, L"In"); -#endif -} - -HRESULT CNullUVideoRenderer::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Video - && (pmt->subtype == MEDIASUBTYPE_YV12 - || pmt->subtype == MEDIASUBTYPE_NV12 - || pmt->subtype == MEDIASUBTYPE_I420 - || pmt->subtype == MEDIASUBTYPE_YUYV - || pmt->subtype == MEDIASUBTYPE_IYUV - || pmt->subtype == MEDIASUBTYPE_YVU9 - || pmt->subtype == MEDIASUBTYPE_Y411 - || pmt->subtype == MEDIASUBTYPE_Y41P - || pmt->subtype == MEDIASUBTYPE_YUY2 - || pmt->subtype == MEDIASUBTYPE_YVYU - || pmt->subtype == MEDIASUBTYPE_UYVY - || pmt->subtype == MEDIASUBTYPE_Y211 - || pmt->subtype == MEDIASUBTYPE_AYUV - || pmt->subtype == MEDIASUBTYPE_YV16 - || pmt->subtype == MEDIASUBTYPE_YV24 - || pmt->subtype == MEDIASUBTYPE_P010 - || pmt->subtype == MEDIASUBTYPE_P016 - || pmt->subtype == MEDIASUBTYPE_P210 - || pmt->subtype == MEDIASUBTYPE_P216 - || pmt->subtype == MEDIASUBTYPE_RGB1 - || pmt->subtype == MEDIASUBTYPE_RGB4 - || pmt->subtype == MEDIASUBTYPE_RGB8 - || pmt->subtype == MEDIASUBTYPE_RGB565 - || pmt->subtype == MEDIASUBTYPE_RGB555 - || pmt->subtype == MEDIASUBTYPE_RGB24 - || pmt->subtype == MEDIASUBTYPE_RGB32 - || pmt->subtype == MEDIASUBTYPE_ARGB1555 - || pmt->subtype == MEDIASUBTYPE_ARGB4444 - || pmt->subtype == MEDIASUBTYPE_ARGB32 - || pmt->subtype == MEDIASUBTYPE_A2R10G10B10 - || pmt->subtype == MEDIASUBTYPE_A2B10G10R10) - ? S_OK - : E_FAIL; -} - -HRESULT CNullUVideoRenderer::DoRenderSample(IMediaSample* pSample) -{ -#ifdef USE_DXVA - CComQIPtr pService = pSample; - if (pService != nullptr) { - CComPtr pSurface; - if (SUCCEEDED(pService->GetService(MR_BUFFER_SERVICE, IID_PPV_ARGS(&pSurface)))) { - // TODO : render surface... - } - } -#endif - - return S_OK; -} - -// -// CNullAudioRenderer -// - -CNullAudioRenderer::CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer"), pUnk, phr) -{ -} - -HRESULT CNullAudioRenderer::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Audio - || pmt->majortype == MEDIATYPE_Midi - || pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO - || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 - || pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO - || pmt->subtype == MEDIASUBTYPE_DTS - || pmt->subtype == MEDIASUBTYPE_SDDS - || pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload - || pmt->subtype == MEDIASUBTYPE_MPEG1Audio - ? S_OK - : E_FAIL; -} - -// -// CNullUAudioRenderer -// - -CNullUAudioRenderer::CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer (Uncompressed)"), pUnk, phr) -{ -} - -HRESULT CNullUAudioRenderer::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Audio - && (pmt->subtype == MEDIASUBTYPE_PCM - || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT - || pmt->subtype == MEDIASUBTYPE_DRM_Audio - || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF - || pmt->subtype == MEDIASUBTYPE_RAW_SPORT - || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h) - ? S_OK - : E_FAIL; -} - -HRESULT CNullUAudioRenderer::DoRenderSample(IMediaSample* pSample) -{ -#if _DEBUG && 0 - static int nNb = 1; - if (nNb < 100) { - const long lSize = pSample->GetActualDataLength(); - BYTE* pMediaBuffer = nullptr; - HRESULT hr = pSample->GetPointer(&pMediaBuffer); - char strFile[MAX_PATH]; - - sprintf_s(strFile, "AudioData%02d.bin", nNb++); - FILE* hFile = fopen(strFile, "wb"); - if (hFile) { - fwrite(pMediaBuffer, - 1, - lSize, - hFile); - fclose(hFile); - } - } -#endif - - return S_OK; -} - -// -// CNullTextRenderer -// - -HRESULT CNullTextRenderer::CTextInputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Text - || pmt->majortype == MEDIATYPE_ScriptCommand - || pmt->majortype == MEDIATYPE_Subtitle - || pmt->subtype == MEDIASUBTYPE_DVD_SUBPICTURE - || pmt->subtype == MEDIASUBTYPE_CVD_SUBPICTURE - || pmt->subtype == MEDIASUBTYPE_SVCD_SUBPICTURE - ? S_OK - : E_FAIL; -} - -CNullTextRenderer::CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseFilter(NAME("CNullTextRenderer"), pUnk, this, __uuidof(this), phr) -{ - m_pInput.Attach(DEBUG_NEW CTextInputPin(this, this, phr)); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "NullRenderers.h" +#include "moreuuids.h" + +#define USE_DXVA + +#ifdef USE_DXVA + +#include +#include +#include // DXVA2 +#include +#include // API Media Foundation +#include + +#pragma comment (lib, "d3d9.lib") + +// dxva.dll +typedef HRESULT(__stdcall* PTR_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager); +typedef HRESULT(__stdcall* PTR_DXVA2CreateVideoService)(IDirect3DDevice9* pDD, REFIID riid, void** ppService); + + +class CNullVideoRendererInputPin : public CRendererInputPin, + public IMFGetService, + public IDirectXVideoMemoryConfiguration, + public IMFVideoDisplayControl +{ +public: + CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name); + ~CNullVideoRendererInputPin() { + if (m_pD3DDeviceManager) { + if (m_hDevice != INVALID_HANDLE_VALUE) { + m_pD3DDeviceManager->CloseDeviceHandle(m_hDevice); + m_hDevice = INVALID_HANDLE_VALUE; + } + m_pD3DDeviceManager = nullptr; + } + if (m_pD3DDev) { + m_pD3DDev = nullptr; + } + if (m_hDXVA2Lib) { + FreeLibrary(m_hDXVA2Lib); + } + } + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator) { + // Renderer shouldn't manage allocator for DXVA + return E_NOTIMPL; + } + + STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES* pProps) { + // 1 buffer required + ZeroMemory(pProps, sizeof(ALLOCATOR_PROPERTIES)); + pProps->cbBuffer = 1; + return S_OK; + } + + // IMFGetService + STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject); + + // IDirectXVideoMemoryConfiguration + STDMETHODIMP GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType); + STDMETHODIMP SetSurfaceType(DXVA2_SurfaceType dwType); + + + // IMFVideoDisplayControl + STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) { + return E_NOTIMPL; + }; + STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) { + return E_NOTIMPL; + }; + STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, + const LPRECT prcDest) { + return E_NOTIMPL; + }; + STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, + LPRECT prcDest) { + return E_NOTIMPL; + }; + STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode) { + return E_NOTIMPL; + }; + STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode) { + return E_NOTIMPL; + }; + STDMETHODIMP SetVideoWindow(HWND hwndVideo) { + return E_NOTIMPL; + }; + STDMETHODIMP GetVideoWindow(HWND* phwndVideo); + STDMETHODIMP RepaintVideo() { + return E_NOTIMPL; + }; + STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, + DWORD* pcbDib, LONGLONG* pTimeStamp) { + return E_NOTIMPL; + }; + STDMETHODIMP SetBorderColor(COLORREF Clr) { + return E_NOTIMPL; + }; + STDMETHODIMP GetBorderColor(COLORREF* pClr) { + return E_NOTIMPL; + }; + STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags) { + return E_NOTIMPL; + }; + STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags) { + return E_NOTIMPL; + }; + STDMETHODIMP SetFullscreen(BOOL fFullscreen) { + return E_NOTIMPL; + }; + STDMETHODIMP GetFullscreen(BOOL* pfFullscreen) { + return E_NOTIMPL; + }; + +private: + HMODULE m_hDXVA2Lib; + PTR_DXVA2CreateDirect3DDeviceManager9 pfDXVA2CreateDirect3DDeviceManager9; + PTR_DXVA2CreateVideoService pfDXVA2CreateVideoService; + + CComPtr m_pD3D; + CComPtr m_pD3DDev; + CComPtr m_pD3DDeviceManager; + UINT m_nResetToken; + HANDLE m_hDevice; + HWND m_hWnd; + + void CreateSurface(); +}; + +CNullVideoRendererInputPin::CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name) + : CRendererInputPin(pRenderer, phr, Name) + , m_hDXVA2Lib(nullptr) + , pfDXVA2CreateDirect3DDeviceManager9(nullptr) + , pfDXVA2CreateVideoService(nullptr) + , m_pD3DDev(nullptr) + , m_pD3DDeviceManager(nullptr) + , m_nResetToken(0) + , m_hDevice(INVALID_HANDLE_VALUE) +{ + CreateSurface(); + + m_hDXVA2Lib = LoadLibrary(L"dxva2.dll"); + if (m_hDXVA2Lib) { + pfDXVA2CreateDirect3DDeviceManager9 = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateDirect3DDeviceManager9")); + pfDXVA2CreateVideoService = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateVideoService")); + pfDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DDeviceManager); + } + + // Initialize Device Manager with DX surface + if (m_pD3DDev) { + m_pD3DDeviceManager->ResetDevice(m_pD3DDev, m_nResetToken); + m_pD3DDeviceManager->OpenDeviceHandle(&m_hDevice); + } +} + +void CNullVideoRendererInputPin::CreateSurface() +{ + m_pD3D.Attach(Direct3DCreate9(D3D_SDK_VERSION)); + if (!m_pD3D) { + m_pD3D.Attach(Direct3DCreate9(D3D9b_SDK_VERSION)); + } + + m_hWnd = nullptr; // TODO : put true window + + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + VERIFY(SUCCEEDED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))); + + D3DPRESENT_PARAMETERS pp; + ZeroMemory(&pp, sizeof(pp)); + + pp.Windowed = TRUE; + pp.hDeviceWindow = m_hWnd; + pp.SwapEffect = D3DSWAPEFFECT_COPY; + pp.Flags = D3DPRESENTFLAG_VIDEO; + pp.BackBufferCount = 1; + pp.BackBufferWidth = d3ddm.Width; + pp.BackBufferHeight = d3ddm.Height; + pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + + VERIFY(SUCCEEDED(m_pD3D->CreateDevice( + D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, //| D3DCREATE_MANAGED, + &pp, &m_pD3DDev))); +} + +STDMETHODIMP CNullVideoRendererInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + (riid == __uuidof(IMFGetService)) ? GetInterface((IMFGetService*)this, ppv) : + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CNullVideoRendererInputPin::GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject) +{ + if (m_pD3DDeviceManager != nullptr && guidService == MR_VIDEO_ACCELERATION_SERVICE) { + if (riid == __uuidof(IDirect3DDeviceManager9)) { + return m_pD3DDeviceManager->QueryInterface(riid, ppvObject); + } else if (riid == __uuidof(IDirectXVideoDecoderService) || riid == __uuidof(IDirectXVideoProcessorService)) { + return m_pD3DDeviceManager->GetVideoService(m_hDevice, riid, ppvObject); + } else if (riid == __uuidof(IDirectXVideoAccelerationService)) { + // TODO : to be tested.... + return pfDXVA2CreateVideoService(m_pD3DDev, riid, ppvObject); + } else if (riid == __uuidof(IDirectXVideoMemoryConfiguration)) { + GetInterface((IDirectXVideoMemoryConfiguration*)this, ppvObject); + return S_OK; + } + } else if (guidService == MR_VIDEO_RENDER_SERVICE) { + if (riid == __uuidof(IMFVideoDisplayControl)) { + GetInterface((IMFVideoDisplayControl*)this, ppvObject); + return S_OK; + } + } + + return E_NOINTERFACE; +} + +STDMETHODIMP CNullVideoRendererInputPin::GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType) +{ + if (dwTypeIndex == 0) { + *pdwType = DXVA2_SurfaceType_DecoderRenderTarget; + return S_OK; + } else { + return MF_E_NO_MORE_TYPES; + } +} + +STDMETHODIMP CNullVideoRendererInputPin::SetSurfaceType(DXVA2_SurfaceType dwType) +{ + return S_OK; +} + +STDMETHODIMP CNullVideoRendererInputPin::GetVideoWindow(HWND* phwndVideo) +{ + CheckPointer(phwndVideo, E_POINTER); + *phwndVideo = m_hWnd; // Important to implement this method (used by MPC-HC) + return S_OK; +} + + +#endif // USE_DXVA + +// +// CNullRenderer +// + +CNullRenderer::CNullRenderer(REFCLSID clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr) + : CBaseRenderer(clsid, pName, pUnk, phr) +{ +} + +// +// CNullVideoRenderer +// + +CNullVideoRenderer::CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CNullRenderer(__uuidof(this), NAME("Null Video Renderer"), pUnk, phr) +{ +} + +HRESULT CNullVideoRenderer::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Video + || pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO + ? S_OK + : E_FAIL; +} + +// +// CNullUVideoRenderer +// + +CNullUVideoRenderer::CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CNullRenderer(__uuidof(this), NAME("Null Video Renderer (Uncompressed)"), pUnk, phr) +{ +#ifdef USE_DXVA + m_pInputPin = DEBUG_NEW CNullVideoRendererInputPin(this, phr, L"In"); +#endif +} + +HRESULT CNullUVideoRenderer::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Video + && (pmt->subtype == MEDIASUBTYPE_YV12 + || pmt->subtype == MEDIASUBTYPE_NV12 + || pmt->subtype == MEDIASUBTYPE_I420 + || pmt->subtype == MEDIASUBTYPE_YUYV + || pmt->subtype == MEDIASUBTYPE_IYUV + || pmt->subtype == MEDIASUBTYPE_YVU9 + || pmt->subtype == MEDIASUBTYPE_Y411 + || pmt->subtype == MEDIASUBTYPE_Y41P + || pmt->subtype == MEDIASUBTYPE_YUY2 + || pmt->subtype == MEDIASUBTYPE_YVYU + || pmt->subtype == MEDIASUBTYPE_UYVY + || pmt->subtype == MEDIASUBTYPE_Y211 + || pmt->subtype == MEDIASUBTYPE_AYUV + || pmt->subtype == MEDIASUBTYPE_YV16 + || pmt->subtype == MEDIASUBTYPE_YV24 + || pmt->subtype == MEDIASUBTYPE_P010 + || pmt->subtype == MEDIASUBTYPE_P016 + || pmt->subtype == MEDIASUBTYPE_P210 + || pmt->subtype == MEDIASUBTYPE_P216 + || pmt->subtype == MEDIASUBTYPE_RGB1 + || pmt->subtype == MEDIASUBTYPE_RGB4 + || pmt->subtype == MEDIASUBTYPE_RGB8 + || pmt->subtype == MEDIASUBTYPE_RGB565 + || pmt->subtype == MEDIASUBTYPE_RGB555 + || pmt->subtype == MEDIASUBTYPE_RGB24 + || pmt->subtype == MEDIASUBTYPE_RGB32 + || pmt->subtype == MEDIASUBTYPE_ARGB1555 + || pmt->subtype == MEDIASUBTYPE_ARGB4444 + || pmt->subtype == MEDIASUBTYPE_ARGB32 + || pmt->subtype == MEDIASUBTYPE_A2R10G10B10 + || pmt->subtype == MEDIASUBTYPE_A2B10G10R10) + ? S_OK + : E_FAIL; +} + +HRESULT CNullUVideoRenderer::DoRenderSample(IMediaSample* pSample) +{ +#ifdef USE_DXVA + CComQIPtr pService = pSample; + if (pService != nullptr) { + CComPtr pSurface; + if (SUCCEEDED(pService->GetService(MR_BUFFER_SERVICE, IID_PPV_ARGS(&pSurface)))) { + // TODO : render surface... + } + } +#endif + + return S_OK; +} + +// +// CNullAudioRenderer +// + +CNullAudioRenderer::CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer"), pUnk, phr) +{ +} + +HRESULT CNullAudioRenderer::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Audio + || pmt->majortype == MEDIATYPE_Midi + || pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO + || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 + || pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO + || pmt->subtype == MEDIASUBTYPE_DTS + || pmt->subtype == MEDIASUBTYPE_SDDS + || pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload + || pmt->subtype == MEDIASUBTYPE_MPEG1Audio + ? S_OK + : E_FAIL; +} + +// +// CNullUAudioRenderer +// + +CNullUAudioRenderer::CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer (Uncompressed)"), pUnk, phr) +{ +} + +HRESULT CNullUAudioRenderer::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Audio + && (pmt->subtype == MEDIASUBTYPE_PCM + || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT + || pmt->subtype == MEDIASUBTYPE_DRM_Audio + || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF + || pmt->subtype == MEDIASUBTYPE_RAW_SPORT + || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h) + ? S_OK + : E_FAIL; +} + +HRESULT CNullUAudioRenderer::DoRenderSample(IMediaSample* pSample) +{ +#if _DEBUG && 0 + static int nNb = 1; + if (nNb < 100) { + const long lSize = pSample->GetActualDataLength(); + BYTE* pMediaBuffer = nullptr; + HRESULT hr = pSample->GetPointer(&pMediaBuffer); + char strFile[MAX_PATH]; + + sprintf_s(strFile, "AudioData%02d.bin", nNb++); + FILE* hFile = fopen(strFile, "wb"); + if (hFile) { + fwrite(pMediaBuffer, + 1, + lSize, + hFile); + fclose(hFile); + } + } +#endif + + return S_OK; +} + +// +// CNullTextRenderer +// + +HRESULT CNullTextRenderer::CTextInputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Text + || pmt->majortype == MEDIATYPE_ScriptCommand + || pmt->majortype == MEDIATYPE_Subtitle + || pmt->subtype == MEDIASUBTYPE_DVD_SUBPICTURE + || pmt->subtype == MEDIASUBTYPE_CVD_SUBPICTURE + || pmt->subtype == MEDIASUBTYPE_SVCD_SUBPICTURE + ? S_OK + : E_FAIL; +} + +CNullTextRenderer::CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseFilter(NAME("CNullTextRenderer"), pUnk, this, __uuidof(this), phr) +{ + m_pInput.Attach(DEBUG_NEW CTextInputPin(this, this, phr)); +} diff --git a/src/DSUtil/NullRenderers.h b/src/DSUtil/NullRenderers.h index 1437c20aef4..39fe97d8349 100644 --- a/src/DSUtil/NullRenderers.h +++ b/src/DSUtil/NullRenderers.h @@ -1,95 +1,95 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include "BaseClasses/streams.h" - -class CNullRenderer : public CBaseRenderer -{ -protected: - virtual HRESULT DoRenderSample(IMediaSample* pSample) { return S_OK; } - -public: - CNullRenderer(REFCLSID clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr); -}; - -class __declspec(uuid("579883A0-4E2D-481F-9436-467AAFAB7DE8")) - CNullVideoRenderer : public CNullRenderer -{ -protected: - HRESULT CheckMediaType(const CMediaType* pmt); - -public: - CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr); -}; - -class __declspec(uuid("DD9ED57D-6ABF-42E8-89A2-11D04798DC58")) - CNullUVideoRenderer : public CNullRenderer -{ -protected: - HRESULT CheckMediaType(const CMediaType* pmt); - -public: - CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr); - virtual HRESULT DoRenderSample(IMediaSample* pSample); -}; - -class __declspec(uuid("0C38BDFD-8C17-4E00-A344-F89397D3E22A")) - CNullAudioRenderer : public CNullRenderer -{ -protected: - HRESULT CheckMediaType(const CMediaType* pmt); - -public: - CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr); -}; - -class __declspec(uuid("64A45125-7343-4772-9DA4-179FAC9D462C")) - CNullUAudioRenderer : public CNullRenderer -{ -protected: - HRESULT CheckMediaType(const CMediaType* pmt); - virtual HRESULT DoRenderSample(IMediaSample* pSample); - -public: - CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr); -}; - -class __declspec(uuid("655D7613-C26C-4A25-BBBD-3C9C516122CC")) - CNullTextRenderer : public CBaseFilter, public CCritSec -{ - class CTextInputPin : public CBaseInputPin - { - public: - CTextInputPin(CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseInputPin(NAME("CTextInputPin"), pFilter, pLock, phr, L"In") {} - HRESULT CheckMediaType(const CMediaType* pmt); - }; - - CAutoPtr m_pInput; - -public: - CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr); - int GetPinCount() { return (int)!!m_pInput; } - CBasePin* GetPin(int n) { return n == 0 ? (CBasePin*)m_pInput : nullptr; } -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include "BaseClasses/streams.h" + +class CNullRenderer : public CBaseRenderer +{ +protected: + virtual HRESULT DoRenderSample(IMediaSample* pSample) { return S_OK; } + +public: + CNullRenderer(REFCLSID clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr); +}; + +class __declspec(uuid("579883A0-4E2D-481F-9436-467AAFAB7DE8")) + CNullVideoRenderer : public CNullRenderer +{ +protected: + HRESULT CheckMediaType(const CMediaType* pmt); + +public: + CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr); +}; + +class __declspec(uuid("DD9ED57D-6ABF-42E8-89A2-11D04798DC58")) + CNullUVideoRenderer : public CNullRenderer +{ +protected: + HRESULT CheckMediaType(const CMediaType* pmt); + +public: + CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr); + virtual HRESULT DoRenderSample(IMediaSample* pSample); +}; + +class __declspec(uuid("0C38BDFD-8C17-4E00-A344-F89397D3E22A")) + CNullAudioRenderer : public CNullRenderer +{ +protected: + HRESULT CheckMediaType(const CMediaType* pmt); + +public: + CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr); +}; + +class __declspec(uuid("64A45125-7343-4772-9DA4-179FAC9D462C")) + CNullUAudioRenderer : public CNullRenderer +{ +protected: + HRESULT CheckMediaType(const CMediaType* pmt); + virtual HRESULT DoRenderSample(IMediaSample* pSample); + +public: + CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr); +}; + +class __declspec(uuid("655D7613-C26C-4A25-BBBD-3C9C516122CC")) + CNullTextRenderer : public CBaseFilter, public CCritSec +{ + class CTextInputPin : public CBaseInputPin + { + public: + CTextInputPin(CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseInputPin(NAME("CTextInputPin"), pFilter, pLock, phr, L"In") {} + HRESULT CheckMediaType(const CMediaType* pmt); + }; + + CAutoPtr m_pInput; + +public: + CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr); + int GetPinCount() { return (int)!!m_pInput; } + CBasePin* GetPin(int n) { return n == 0 ? (CBasePin*)m_pInput : nullptr; } +}; diff --git a/src/DSUtil/SharedInclude.h b/src/DSUtil/SharedInclude.h index 2d1d3e8a451..ccc8a12e0d1 100644 --- a/src/DSUtil/SharedInclude.h +++ b/src/DSUtil/SharedInclude.h @@ -1,41 +1,41 @@ -/* - * (C) 2009-2013, 2016 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 . - * - */ - -#pragma once - -#pragma warning(disable:4995) -#pragma warning(disable:5054) -#pragma warning(disable:4467) - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#ifndef STRICT_TYPED_ITEMIDS -#define STRICT_TYPED_ITEMIDS -#endif - -#ifdef _DEBUG -#if 1 -#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures -#include -#else -#include "vld.h" //include visual leak detector procedures -#endif -#endif +/* + * (C) 2009-2013, 2016 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 . + * + */ + +#pragma once + +#pragma warning(disable:4995) +#pragma warning(disable:5054) +#pragma warning(disable:4467) + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#ifndef STRICT_TYPED_ITEMIDS +#define STRICT_TYPED_ITEMIDS +#endif + +#ifdef _DEBUG +#if 1 +#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures +#include +#else +#include "vld.h" //include visual leak detector procedures +#endif +#endif diff --git a/src/DSUtil/VersionHelpersInternal.h b/src/DSUtil/VersionHelpersInternal.h index 5cef19a2fb7..22c79524cd2 100644 --- a/src/DSUtil/VersionHelpersInternal.h +++ b/src/DSUtil/VersionHelpersInternal.h @@ -1,83 +1,83 @@ -/* -* (C) 2017 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 . -* -*/ - -#pragma once - -#include - -// Remove once newer SDK is used -#ifndef _WIN32_WINNT_WINTHRESHOLD -#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 - -VERSIONHELPERAPI -IsWindows10OrGreater() -{ - return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0); -} - -#endif - -static VERSIONHELPERAPI -IsWindowsVersionOrGreaterBuild(WORD wMajorVersion, WORD wMinorVersion, DWORD dwBuildNumber) { - OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; - DWORDLONG const dwlConditionMask = VerSetConditionMask( - VerSetConditionMask( - VerSetConditionMask( - 0, VER_MAJORVERSION, VER_GREATER_EQUAL), - VER_MINORVERSION, VER_GREATER_EQUAL), - VER_BUILDNUMBER, VER_GREATER_EQUAL); - - osvi.dwMajorVersion = wMajorVersion; - osvi.dwMinorVersion = wMinorVersion; - osvi.dwBuildNumber = dwBuildNumber; - - return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, dwlConditionMask) != FALSE; -} - -#ifndef IsWindows11OrGreater - -VERSIONHELPERAPI -IsWindows11OrGreater() { - return IsWindowsVersionOrGreaterBuild(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 22000); -} - -#endif - -typedef LONG NTSTATUS, * PNTSTATUS; -#define STATUS_SUCCESS (0x00000000) - -typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); - -inline RTL_OSVERSIONINFOW GetRealOSVersion() -{ - HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); - if (hMod) { - RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); - if (fxPtr != nullptr) { - RTL_OSVERSIONINFOW rovi = { 0 }; - rovi.dwOSVersionInfoSize = sizeof(rovi); - if (STATUS_SUCCESS == fxPtr(&rovi)) { - return rovi; - } - } - } - RTL_OSVERSIONINFOW rovi = { 0 }; - return rovi; -} +/* +* (C) 2017 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 . +* +*/ + +#pragma once + +#include + +// Remove once newer SDK is used +#ifndef _WIN32_WINNT_WINTHRESHOLD +#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 + +VERSIONHELPERAPI +IsWindows10OrGreater() +{ + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0); +} + +#endif + +static VERSIONHELPERAPI +IsWindowsVersionOrGreaterBuild(WORD wMajorVersion, WORD wMinorVersion, DWORD dwBuildNumber) { + OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + DWORDLONG const dwlConditionMask = VerSetConditionMask( + VerSetConditionMask( + VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_BUILDNUMBER, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = wMajorVersion; + osvi.dwMinorVersion = wMinorVersion; + osvi.dwBuildNumber = dwBuildNumber; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, dwlConditionMask) != FALSE; +} + +#ifndef IsWindows11OrGreater + +VERSIONHELPERAPI +IsWindows11OrGreater() { + return IsWindowsVersionOrGreaterBuild(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 22000); +} + +#endif + +typedef LONG NTSTATUS, * PNTSTATUS; +#define STATUS_SUCCESS (0x00000000) + +typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + +inline RTL_OSVERSIONINFOW GetRealOSVersion() +{ + HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); + if (hMod) { + RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); + if (fxPtr != nullptr) { + RTL_OSVERSIONINFOW rovi = { 0 }; + rovi.dwOSVersionInfoSize = sizeof(rovi); + if (STATUS_SUCCESS == fxPtr(&rovi)) { + return rovi; + } + } + } + RTL_OSVERSIONINFOW rovi = { 0 }; + return rovi; +} diff --git a/src/DSUtil/WinAPIUtils.cpp b/src/DSUtil/WinAPIUtils.cpp index 10ea8ff21bf..ed73a98f531 100644 --- a/src/DSUtil/WinAPIUtils.cpp +++ b/src/DSUtil/WinAPIUtils.cpp @@ -1,348 +1,348 @@ -/* - * (C) 2011-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "WinAPIUtils.h" -#include "PathUtils.h" - - -bool SetPrivilege(LPCTSTR privilege, bool bEnable) -{ - HANDLE hToken; - TOKEN_PRIVILEGES tkp; - - SetThreadExecutionState(ES_CONTINUOUS); - - // Get a token for this process. - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { - return false; - } - - // Get the LUID for the privilege. - LookupPrivilegeValue(nullptr, privilege, &tkp.Privileges[0].Luid); - - tkp.PrivilegeCount = 1; // one privilege to set - tkp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0; - - // Set the privilege for this process. - AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)nullptr, 0); - - return (GetLastError() == ERROR_SUCCESS); -} - -CString GetHiveName(const HKEY hive) -{ - switch ((ULONG_PTR)hive) { - case (ULONG_PTR)HKEY_CLASSES_ROOT: - return _T("HKEY_CLASSES_ROOT"); - case (ULONG_PTR)HKEY_CURRENT_USER: - return _T("HKEY_CURRENT_USER"); - case (ULONG_PTR)HKEY_LOCAL_MACHINE: - return _T("HKEY_LOCAL_MACHINE"); - case (ULONG_PTR)HKEY_USERS: - return _T("HKEY_USERS"); - case (ULONG_PTR)HKEY_PERFORMANCE_DATA: - return _T("HKEY_PERFORMANCE_DATA"); - case (ULONG_PTR)HKEY_CURRENT_CONFIG: - return _T("HKEY_CURRENT_CONFIG"); - case (ULONG_PTR)HKEY_DYN_DATA: - return _T("HKEY_DYN_DATA"); - case (ULONG_PTR)HKEY_PERFORMANCE_TEXT: - return _T("HKEY_PERFORMANCE_TEXT"); - case (ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT: - return _T("HKEY_PERFORMANCE_NLSTEXT"); - default: - return _T(""); - } -} - -bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName) -{ - // Registry functions don't set GetLastError(), so it needs to be set explicitly - LSTATUS errorCode = ERROR_SUCCESS; - - HKEY hKey = nullptr; - errorCode = RegOpenKeyEx(hKeyRoot, keyName, 0, KEY_READ, &hKey); - if (errorCode != ERROR_SUCCESS) { - SetLastError(errorCode); - return false; - } - - DWORD subKeysCount = 0, maxSubKeyLen = 0; - DWORD valuesCount = 0, maxValueNameLen = 0, maxValueDataLen = 0; - errorCode = RegQueryInfoKey(hKey, nullptr, nullptr, nullptr, &subKeysCount, &maxSubKeyLen, nullptr, &valuesCount, &maxValueNameLen, &maxValueDataLen, nullptr, nullptr); - if (errorCode != ERROR_SUCCESS) { - SetLastError(errorCode); - return false; - } - maxSubKeyLen += 1; - maxValueNameLen += 1; - - CString buffer; - - buffer.Format(_T("[%s\\%s]\n"), GetHiveName(hKeyRoot).GetString(), keyName.GetString()); - file.WriteString(buffer); - - CString valueName; - DWORD valueNameLen, valueDataLen, type; - BYTE* data = DEBUG_NEW BYTE[maxValueDataLen]; - - for (DWORD indexValue = 0; indexValue < valuesCount; indexValue++) { - valueNameLen = maxValueNameLen; - valueDataLen = maxValueDataLen; - - errorCode = RegEnumValue(hKey, indexValue, valueName.GetBuffer(maxValueNameLen), &valueNameLen, nullptr, &type, data, &valueDataLen); - if (errorCode != ERROR_SUCCESS) { - SetLastError(errorCode); - return false; - } - - switch (type) { - case REG_SZ: { - CString str((TCHAR*)data); - str.Replace(_T("\\"), _T("\\\\")); - str.Replace(_T("\""), _T("\\\"")); - buffer.Format(_T("\"%s\"=\"%s\"\n"), valueName.GetString(), str.GetString()); - file.WriteString(buffer); - } - break; - case REG_BINARY: - buffer.Format(_T("\"%s\"=hex:%02x"), valueName.GetString(), data[0]); - file.WriteString(buffer); - for (DWORD i = 1; i < valueDataLen; i++) { - buffer.Format(_T(",%02x"), data[i]); - file.WriteString(buffer); - } - file.WriteString(_T("\n")); - break; - case REG_DWORD: - buffer.Format(_T("\"%s\"=dword:%08lx\n"), valueName.GetString(), *((DWORD*)data)); - file.WriteString(buffer); - break; - default: { - CString msg; - msg.Format(_T("The value \"%s\\%s\\%s\" has an unsupported type and has been ignored.\nPlease report this error to the developers."), - GetHiveName(hKeyRoot).GetString(), keyName.GetString(), valueName.GetString()); - AfxMessageBox(msg, MB_ICONERROR | MB_OK); - } - delete [] data; - return false; - } - } - - delete [] data; - - file.WriteString(_T("\n")); - - CString subKeyName; - DWORD subKeyLen; - - for (DWORD indexSubKey = 0; indexSubKey < subKeysCount; indexSubKey++) { - subKeyLen = maxSubKeyLen; - - errorCode = RegEnumKeyEx(hKey, indexSubKey, subKeyName.GetBuffer(maxSubKeyLen), &subKeyLen, nullptr, nullptr, nullptr, nullptr); - if (errorCode != ERROR_SUCCESS) { - SetLastError(errorCode); - return false; - } - - buffer.Format(_T("%s\\%s"), keyName.GetString(), subKeyName.GetString()); - - if (!ExportRegistryKey(file, hKeyRoot, buffer)) { - return false; - } - } - - errorCode = RegCloseKey(hKey); - SetLastError(errorCode); - return true; -} - -UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd) -{ - if (hWnd == nullptr || pD3D == nullptr) { - return D3DADAPTER_DEFAULT; - } - - HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); - if (hMonitor == nullptr) { - return D3DADAPTER_DEFAULT; - } - - for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { - HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp); - if (hAdpMon == hMonitor) { - return adp; - } - } - - return D3DADAPTER_DEFAULT; -} - -int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX* /*lpelfe*/, NEWTEXTMETRICEX* /*lpntme*/, int /*FontType*/, LPARAM lParam) -{ - LPARAM* l = (LPARAM*)lParam; - *l = TRUE; - return TRUE; -} - -namespace -{ - void GetNonClientMetrics(NONCLIENTMETRICS* ncm) - { - ZeroMemory(ncm, sizeof(NONCLIENTMETRICS)); - ncm->cbSize = sizeof(NONCLIENTMETRICS); - VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, 0)); - } -} - -void GetMessageFont(LOGFONT* lf) -{ - NONCLIENTMETRICS ncm; - GetNonClientMetrics(&ncm); - *lf = ncm.lfMessageFont; - ASSERT(lf->lfHeight); -} - -void GetStatusFont(LOGFONT* lf) -{ - NONCLIENTMETRICS ncm; - GetNonClientMetrics(&ncm); - *lf = ncm.lfStatusFont; - ASSERT(lf->lfHeight); -} - -bool IsFontInstalled(LPCTSTR lpszFont) -{ - // Get the screen DC - CDC dc; - if (!dc.CreateCompatibleDC(nullptr)) { - return false; - } - - LOGFONT lf; - ZeroMemory(&lf, sizeof(LOGFONT)); - // Any character set will do - lf.lfCharSet = DEFAULT_CHARSET; - // Set the facename to check for - _tcscpy_s(lf.lfFaceName, lpszFont); - LPARAM lParam = 0; - // Enumerate fonts - EnumFontFamiliesEx(dc.GetSafeHdc(), &lf, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)&lParam, 0); - - return lParam ? true : false; -} - -bool ExploreToFile(LPCTSTR path) -{ - CoInitializeHelper co; - - bool success = false; - PIDLIST_ABSOLUTE pidl; - - if (PathUtils::Exists(path) && SHParseDisplayName(path, nullptr, &pidl, 0, nullptr) == S_OK) { - success = SUCCEEDED(SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0)); - CoTaskMemFree(pidl); - } - - return success; -} - -CoInitializeHelper::CoInitializeHelper() -{ - HRESULT res = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if (res == RPC_E_CHANGED_MODE) { // Try another threading model - res = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - } - if (res != S_OK && res != S_FALSE) { - throw res; - } -} - -CoInitializeHelper::~CoInitializeHelper() -{ - CoUninitialize(); -} - -HRESULT FileDelete(CString file, HWND hWnd, bool recycle /*= true*/, bool noconfirm /*= false*/) -{ - // Strings in SHFILEOPSTRUCT must be double-null terminated - file.AppendChar(_T('\0')); - - SHFILEOPSTRUCT fileOpStruct; - ZeroMemory(&fileOpStruct, sizeof(SHFILEOPSTRUCT)); - fileOpStruct.hwnd = hWnd; - fileOpStruct.wFunc = FO_DELETE; - fileOpStruct.pFrom = file; - fileOpStruct.fFlags = FOF_FILESONLY | FOF_SILENT; - if (recycle) { - fileOpStruct.fFlags |= FOF_ALLOWUNDO; - } - if (noconfirm) { - fileOpStruct.fFlags |= FOF_NOCONFIRMATION; - } else { - fileOpStruct.fFlags |= FOF_WANTNUKEWARNING; - } - int hRes = SHFileOperation(&fileOpStruct); - if (fileOpStruct.fAnyOperationsAborted) { - hRes = E_ABORT; - } - TRACE(_T("Delete recycle=%d hRes=0x%08x, file=%s\n"), recycle, hRes, file.GetString()); - return hRes; -} - -BOOL CClipboard::SetText(const CString& text) const -{ -#ifdef _UNICODE - const UINT format = CF_UNICODETEXT; -#else - const UINT format = CF_TEXT; -#endif - - BOOL bResult = FALSE; - - if(m_bOpened) { - // Allocate a global memory object for the text - int len = text.GetLength() + 1; - auto hGlob = GlobalAlloc(GMEM_MOVEABLE, len*sizeof(TCHAR)); - if (hGlob) { - // Lock the handle and copy the text to the buffer - auto pData = (LPTSTR)GlobalLock(hGlob); - if (pData) { - _tcscpy_s(pData, len, text.GetString()); - GlobalUnlock(hGlob); - - // Place the handle on the clipboard, if the call succeeds - // the system will take care of the allocated memory - if (::EmptyClipboard() && ::SetClipboardData(format, hGlob)) { - bResult = TRUE; - hGlob = nullptr; - } - } - - if (hGlob) { - GlobalFree(hGlob); - } - } - } - return bResult; -} +/* + * (C) 2011-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "WinAPIUtils.h" +#include "PathUtils.h" + + +bool SetPrivilege(LPCTSTR privilege, bool bEnable) +{ + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + + SetThreadExecutionState(ES_CONTINUOUS); + + // Get a token for this process. + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + return false; + } + + // Get the LUID for the privilege. + LookupPrivilegeValue(nullptr, privilege, &tkp.Privileges[0].Luid); + + tkp.PrivilegeCount = 1; // one privilege to set + tkp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0; + + // Set the privilege for this process. + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)nullptr, 0); + + return (GetLastError() == ERROR_SUCCESS); +} + +CString GetHiveName(const HKEY hive) +{ + switch ((ULONG_PTR)hive) { + case (ULONG_PTR)HKEY_CLASSES_ROOT: + return _T("HKEY_CLASSES_ROOT"); + case (ULONG_PTR)HKEY_CURRENT_USER: + return _T("HKEY_CURRENT_USER"); + case (ULONG_PTR)HKEY_LOCAL_MACHINE: + return _T("HKEY_LOCAL_MACHINE"); + case (ULONG_PTR)HKEY_USERS: + return _T("HKEY_USERS"); + case (ULONG_PTR)HKEY_PERFORMANCE_DATA: + return _T("HKEY_PERFORMANCE_DATA"); + case (ULONG_PTR)HKEY_CURRENT_CONFIG: + return _T("HKEY_CURRENT_CONFIG"); + case (ULONG_PTR)HKEY_DYN_DATA: + return _T("HKEY_DYN_DATA"); + case (ULONG_PTR)HKEY_PERFORMANCE_TEXT: + return _T("HKEY_PERFORMANCE_TEXT"); + case (ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT: + return _T("HKEY_PERFORMANCE_NLSTEXT"); + default: + return _T(""); + } +} + +bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName) +{ + // Registry functions don't set GetLastError(), so it needs to be set explicitly + LSTATUS errorCode = ERROR_SUCCESS; + + HKEY hKey = nullptr; + errorCode = RegOpenKeyEx(hKeyRoot, keyName, 0, KEY_READ, &hKey); + if (errorCode != ERROR_SUCCESS) { + SetLastError(errorCode); + return false; + } + + DWORD subKeysCount = 0, maxSubKeyLen = 0; + DWORD valuesCount = 0, maxValueNameLen = 0, maxValueDataLen = 0; + errorCode = RegQueryInfoKey(hKey, nullptr, nullptr, nullptr, &subKeysCount, &maxSubKeyLen, nullptr, &valuesCount, &maxValueNameLen, &maxValueDataLen, nullptr, nullptr); + if (errorCode != ERROR_SUCCESS) { + SetLastError(errorCode); + return false; + } + maxSubKeyLen += 1; + maxValueNameLen += 1; + + CString buffer; + + buffer.Format(_T("[%s\\%s]\n"), GetHiveName(hKeyRoot).GetString(), keyName.GetString()); + file.WriteString(buffer); + + CString valueName; + DWORD valueNameLen, valueDataLen, type; + BYTE* data = DEBUG_NEW BYTE[maxValueDataLen]; + + for (DWORD indexValue = 0; indexValue < valuesCount; indexValue++) { + valueNameLen = maxValueNameLen; + valueDataLen = maxValueDataLen; + + errorCode = RegEnumValue(hKey, indexValue, valueName.GetBuffer(maxValueNameLen), &valueNameLen, nullptr, &type, data, &valueDataLen); + if (errorCode != ERROR_SUCCESS) { + SetLastError(errorCode); + return false; + } + + switch (type) { + case REG_SZ: { + CString str((TCHAR*)data); + str.Replace(_T("\\"), _T("\\\\")); + str.Replace(_T("\""), _T("\\\"")); + buffer.Format(_T("\"%s\"=\"%s\"\n"), valueName.GetString(), str.GetString()); + file.WriteString(buffer); + } + break; + case REG_BINARY: + buffer.Format(_T("\"%s\"=hex:%02x"), valueName.GetString(), data[0]); + file.WriteString(buffer); + for (DWORD i = 1; i < valueDataLen; i++) { + buffer.Format(_T(",%02x"), data[i]); + file.WriteString(buffer); + } + file.WriteString(_T("\n")); + break; + case REG_DWORD: + buffer.Format(_T("\"%s\"=dword:%08lx\n"), valueName.GetString(), *((DWORD*)data)); + file.WriteString(buffer); + break; + default: { + CString msg; + msg.Format(_T("The value \"%s\\%s\\%s\" has an unsupported type and has been ignored.\nPlease report this error to the developers."), + GetHiveName(hKeyRoot).GetString(), keyName.GetString(), valueName.GetString()); + AfxMessageBox(msg, MB_ICONERROR | MB_OK); + } + delete [] data; + return false; + } + } + + delete [] data; + + file.WriteString(_T("\n")); + + CString subKeyName; + DWORD subKeyLen; + + for (DWORD indexSubKey = 0; indexSubKey < subKeysCount; indexSubKey++) { + subKeyLen = maxSubKeyLen; + + errorCode = RegEnumKeyEx(hKey, indexSubKey, subKeyName.GetBuffer(maxSubKeyLen), &subKeyLen, nullptr, nullptr, nullptr, nullptr); + if (errorCode != ERROR_SUCCESS) { + SetLastError(errorCode); + return false; + } + + buffer.Format(_T("%s\\%s"), keyName.GetString(), subKeyName.GetString()); + + if (!ExportRegistryKey(file, hKeyRoot, buffer)) { + return false; + } + } + + errorCode = RegCloseKey(hKey); + SetLastError(errorCode); + return true; +} + +UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd) +{ + if (hWnd == nullptr || pD3D == nullptr) { + return D3DADAPTER_DEFAULT; + } + + HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor == nullptr) { + return D3DADAPTER_DEFAULT; + } + + for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { + HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp); + if (hAdpMon == hMonitor) { + return adp; + } + } + + return D3DADAPTER_DEFAULT; +} + +int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX* /*lpelfe*/, NEWTEXTMETRICEX* /*lpntme*/, int /*FontType*/, LPARAM lParam) +{ + LPARAM* l = (LPARAM*)lParam; + *l = TRUE; + return TRUE; +} + +namespace +{ + void GetNonClientMetrics(NONCLIENTMETRICS* ncm) + { + ZeroMemory(ncm, sizeof(NONCLIENTMETRICS)); + ncm->cbSize = sizeof(NONCLIENTMETRICS); + VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, 0)); + } +} + +void GetMessageFont(LOGFONT* lf) +{ + NONCLIENTMETRICS ncm; + GetNonClientMetrics(&ncm); + *lf = ncm.lfMessageFont; + ASSERT(lf->lfHeight); +} + +void GetStatusFont(LOGFONT* lf) +{ + NONCLIENTMETRICS ncm; + GetNonClientMetrics(&ncm); + *lf = ncm.lfStatusFont; + ASSERT(lf->lfHeight); +} + +bool IsFontInstalled(LPCTSTR lpszFont) +{ + // Get the screen DC + CDC dc; + if (!dc.CreateCompatibleDC(nullptr)) { + return false; + } + + LOGFONT lf; + ZeroMemory(&lf, sizeof(LOGFONT)); + // Any character set will do + lf.lfCharSet = DEFAULT_CHARSET; + // Set the facename to check for + _tcscpy_s(lf.lfFaceName, lpszFont); + LPARAM lParam = 0; + // Enumerate fonts + EnumFontFamiliesEx(dc.GetSafeHdc(), &lf, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)&lParam, 0); + + return lParam ? true : false; +} + +bool ExploreToFile(LPCTSTR path) +{ + CoInitializeHelper co; + + bool success = false; + PIDLIST_ABSOLUTE pidl; + + if (PathUtils::Exists(path) && SHParseDisplayName(path, nullptr, &pidl, 0, nullptr) == S_OK) { + success = SUCCEEDED(SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0)); + CoTaskMemFree(pidl); + } + + return success; +} + +CoInitializeHelper::CoInitializeHelper() +{ + HRESULT res = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (res == RPC_E_CHANGED_MODE) { // Try another threading model + res = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + } + if (res != S_OK && res != S_FALSE) { + throw res; + } +} + +CoInitializeHelper::~CoInitializeHelper() +{ + CoUninitialize(); +} + +HRESULT FileDelete(CString file, HWND hWnd, bool recycle /*= true*/, bool noconfirm /*= false*/) +{ + // Strings in SHFILEOPSTRUCT must be double-null terminated + file.AppendChar(_T('\0')); + + SHFILEOPSTRUCT fileOpStruct; + ZeroMemory(&fileOpStruct, sizeof(SHFILEOPSTRUCT)); + fileOpStruct.hwnd = hWnd; + fileOpStruct.wFunc = FO_DELETE; + fileOpStruct.pFrom = file; + fileOpStruct.fFlags = FOF_FILESONLY | FOF_SILENT; + if (recycle) { + fileOpStruct.fFlags |= FOF_ALLOWUNDO; + } + if (noconfirm) { + fileOpStruct.fFlags |= FOF_NOCONFIRMATION; + } else { + fileOpStruct.fFlags |= FOF_WANTNUKEWARNING; + } + int hRes = SHFileOperation(&fileOpStruct); + if (fileOpStruct.fAnyOperationsAborted) { + hRes = E_ABORT; + } + TRACE(_T("Delete recycle=%d hRes=0x%08x, file=%s\n"), recycle, hRes, file.GetString()); + return hRes; +} + +BOOL CClipboard::SetText(const CString& text) const +{ +#ifdef _UNICODE + const UINT format = CF_UNICODETEXT; +#else + const UINT format = CF_TEXT; +#endif + + BOOL bResult = FALSE; + + if(m_bOpened) { + // Allocate a global memory object for the text + int len = text.GetLength() + 1; + auto hGlob = GlobalAlloc(GMEM_MOVEABLE, len*sizeof(TCHAR)); + if (hGlob) { + // Lock the handle and copy the text to the buffer + auto pData = (LPTSTR)GlobalLock(hGlob); + if (pData) { + _tcscpy_s(pData, len, text.GetString()); + GlobalUnlock(hGlob); + + // Place the handle on the clipboard, if the call succeeds + // the system will take care of the allocated memory + if (::EmptyClipboard() && ::SetClipboardData(format, hGlob)) { + bResult = TRUE; + hGlob = nullptr; + } + } + + if (hGlob) { + GlobalFree(hGlob); + } + } + } + return bResult; +} diff --git a/src/DSUtil/WinAPIUtils.h b/src/DSUtil/WinAPIUtils.h index 0e0af36489d..b34fb3b6844 100644 --- a/src/DSUtil/WinAPIUtils.h +++ b/src/DSUtil/WinAPIUtils.h @@ -1,64 +1,64 @@ -/* - * (C) 2011-2014, 2016 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 . - * - */ - -#pragma once - -struct IDirect3D9; - - -bool SetPrivilege(LPCTSTR privilege, bool bEnable = true); - -bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName = _T("")); - -UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd); - -void GetMessageFont(LOGFONT* lf); -void GetStatusFont(LOGFONT* lf); - -bool IsFontInstalled(LPCTSTR lpszFont); - -bool ExploreToFile(LPCTSTR path); - -HRESULT FileDelete(CString file, HWND hWnd, bool recycle = true, bool noconfirm = false); - -class CoInitializeHelper -{ -public: - CoInitializeHelper(); - ~CoInitializeHelper(); -}; - -class CClipboard -{ -public: - CClipboard(CWnd* pWnd = nullptr) { - m_bOpened = ::OpenClipboard(pWnd->GetSafeHwnd()); - } - ~CClipboard() { - if(m_bOpened) { - VERIFY(::CloseClipboard()); - } - } - - BOOL SetText(const CString& text) const; - -protected: - BOOL m_bOpened; -}; +/* + * (C) 2011-2014, 2016 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 . + * + */ + +#pragma once + +struct IDirect3D9; + + +bool SetPrivilege(LPCTSTR privilege, bool bEnable = true); + +bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName = _T("")); + +UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd); + +void GetMessageFont(LOGFONT* lf); +void GetStatusFont(LOGFONT* lf); + +bool IsFontInstalled(LPCTSTR lpszFont); + +bool ExploreToFile(LPCTSTR path); + +HRESULT FileDelete(CString file, HWND hWnd, bool recycle = true, bool noconfirm = false); + +class CoInitializeHelper +{ +public: + CoInitializeHelper(); + ~CoInitializeHelper(); +}; + +class CClipboard +{ +public: + CClipboard(CWnd* pWnd = nullptr) { + m_bOpened = ::OpenClipboard(pWnd->GetSafeHwnd()); + } + ~CClipboard() { + if(m_bOpened) { + VERIFY(::CloseClipboard()); + } + } + + BOOL SetText(const CString& text) const; + +protected: + BOOL m_bOpened; +}; diff --git a/src/DSUtil/deinterlace.cpp b/src/DSUtil/deinterlace.cpp index 7ef0dce756c..b329ce10624 100644 --- a/src/DSUtil/deinterlace.cpp +++ b/src/DSUtil/deinterlace.cpp @@ -1,1968 +1,1968 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include "stdafx.h" -#include -#include "vd2/system/memory.h" -#include "vd2/system/cpuaccel.h" -#include "vd2/system/vdstl.h" - -#pragma warning(disable: 4799) // warning C4799: function has no EMMS instruction - -/////////////////////////////////////////////////////////////////////////// - -#ifdef _M_IX86 -static void __declspec(naked) asm_blend_row_clipped(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - __asm { - push ebp - push edi - push esi - push ebx - - mov edi,[esp+20] - mov esi,[esp+24] - sub edi,esi - mov ebp,[esp+28] - mov edx,[esp+32] - -xloop: - mov ecx,[esi] - mov eax,0fefefefeh - - mov ebx,[esi+edx] - and eax,ecx - - shr eax,1 - and ebx,0fefefefeh - - shr ebx,1 - add esi,4 - - add eax,ebx - dec ebp - - mov [edi+esi-4],eax - jnz xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -static void __declspec(naked) asm_blend_row(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - __asm { - push ebp - push edi - push esi - push ebx - - mov edi,[esp+20] - mov esi,[esp+24] - sub edi,esi - mov ebp,[esp+28] - mov edx,[esp+32] - -xloop: - mov ecx,[esi] - mov eax,0fcfcfcfch - - mov ebx,[esi+edx] - and eax,ecx - - shr ebx,1 - mov ecx,[esi+edx*2] - - shr ecx,2 - and ebx,07f7f7f7fh - - shr eax,2 - and ecx,03f3f3f3fh - - add eax,ebx - add esi,4 - - add eax,ecx - dec ebp - - mov [edi+esi-4],eax - jnz xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -static void __declspec(naked) asm_blend_row_MMX(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - static const __declspec(align(8)) __int64 mask0 = 0xfcfcfcfcfcfcfcfci64; - static const __declspec(align(8)) __int64 mask1 = 0x7f7f7f7f7f7f7f7fi64; - static const __declspec(align(8)) __int64 mask2 = 0x3f3f3f3f3f3f3f3fi64; - __asm { - push ebp - push edi - push esi - push ebx - - mov edi,[esp+20] - mov esi,[esp+24] - sub edi,esi - mov ebp,[esp+28] - mov edx,[esp+32] - - movq mm5,mask0 - movq mm6,mask1 - movq mm7,mask2 - inc ebp - shr ebp,1 -xloop: - movq mm2,[esi] - movq mm0,mm5 - - movq mm1,[esi+edx] - pand mm0,mm2 - - psrlq mm1,1 - movq mm2,[esi+edx*2] - - psrlq mm2,2 - pand mm1,mm6 - - psrlq mm0,2 - pand mm2,mm7 - - paddb mm0,mm1 - add esi,8 - - paddb mm0,mm2 - dec ebp - - movq [edi+esi-8],mm0 - jne xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -static void __declspec(naked) asm_blend_row_ISSE(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - __asm { - push ebp - push edi - push esi - push ebx - - mov edi,[esp+20] - mov esi,[esp+24] - sub edi,esi - mov ebp,[esp+28] - mov edx,[esp+32] - - inc ebp - shr ebp,1 - pcmpeqb mm7, mm7 - - align 16 -xloop: - movq mm0, [esi] - movq mm2, mm7 - pxor mm0, mm7 - - pxor mm2, [esi+edx*2] - pavgb mm0, mm2 - pxor mm0, mm7 - - pavgb mm0, [esi+edx] - add esi,8 - - movq [edi+esi-8],mm0 - dec ebp - jne xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} -#else -static void asm_blend_row_clipped(void *dst0, const void *src0, uint32 w, ptrdiff_t srcpitch) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - const uint32 *src2 = (const uint32 *)((const char *)src + srcpitch); - - do { - const uint32 x = *src++; - const uint32 y = *src2++; - - *dst++ = (x|y) - (((x^y)&0xfefefefe)>>1); - } while(--w); -} - -static void asm_blend_row(void *dst0, const void *src0, uint32 w, ptrdiff_t srcpitch) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - const uint32 *src2 = (const uint32 *)((const char *)src + srcpitch); - const uint32 *src3 = (const uint32 *)((const char *)src2 + srcpitch); - - do { - const uint32 a = *src++; - const uint32 b = *src2++; - const uint32 c = *src3++; - const uint32 hi = (a & 0xfcfcfc) + 2*(b & 0xfcfcfc) + (c & 0xfcfcfc); - const uint32 lo = (a & 0x030303) + 2*(b & 0x030303) + (c & 0x030303) + 0x020202; - - *dst++ = (hi + (lo & 0x0c0c0c))>>2; - } while(--w); -} -#endif - -#if defined(VD_CPU_X86) || defined(VD_CPU_AMD64) - static void asm_blend_row_SSE2(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - __m128i zero = _mm_setzero_si128(); - __m128i inv = _mm_cmpeq_epi8(zero, zero); - - w = (w + 3) >> 2; - - const __m128i *src1 = (const __m128i *)src; - const __m128i *src2 = (const __m128i *)((const char *)src + srcpitch); - const __m128i *src3 = (const __m128i *)((const char *)src + srcpitch*2); - __m128i *dstrow = (__m128i *)dst; - do { - __m128i a = *src1++; - __m128i b = *src2++; - __m128i c = *src3++; - - *dstrow++ = _mm_avg_epu8(_mm_xor_si128(_mm_avg_epu8(_mm_xor_si128(a, inv), _mm_xor_si128(c, inv)), inv), b); - } while(--w); - } - - - void ela_L8_SSE2(__m128i *dst, const __m128i *srcat, const __m128i *srcab, int w16) { - do { - __m128i top0 = srcat[0]; - __m128i top1 = srcat[1]; - __m128i top2 = srcat[2]; - __m128i bot0 = srcab[0]; - __m128i bot1 = srcab[1]; - __m128i bot2 = srcab[2]; - ++srcat; - ++srcab; - - __m128i topl2 = _mm_or_si128(_mm_srli_si128(top0, 16 - 3), _mm_slli_si128(top1, 3)); - __m128i topl1 = _mm_or_si128(_mm_srli_si128(top0, 16 - 2), _mm_slli_si128(top1, 2)); - __m128i topc0 = _mm_or_si128(_mm_srli_si128(top0, 16 - 1), _mm_slli_si128(top1, 1)); - __m128i topr1 = top1; - __m128i topr2 = _mm_or_si128(_mm_srli_si128(top1, 1), _mm_slli_si128(top2, 16 - 1)); - __m128i topr3 = _mm_or_si128(_mm_srli_si128(top1, 2), _mm_slli_si128(top2, 16 - 2)); - - __m128i botl2 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 3), _mm_slli_si128(bot1, 3)); - __m128i botl1 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 2), _mm_slli_si128(bot1, 2)); - __m128i botc0 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 1), _mm_slli_si128(bot1, 1)); - __m128i botr1 = bot1; - __m128i botr2 = _mm_or_si128(_mm_srli_si128(bot1, 1), _mm_slli_si128(bot2, 16 - 1)); - __m128i botr3 = _mm_or_si128(_mm_srli_si128(bot1, 2), _mm_slli_si128(bot2, 16 - 2)); - - __m128i rawscorec0 = _mm_or_si128(_mm_subs_epu8(topc0, botc0), _mm_subs_epu8(botc0, topc0)); - __m128i rawscorel1 = _mm_or_si128(_mm_subs_epu8(topl1, botr1), _mm_subs_epu8(botr1, topl1)); - __m128i rawscorel2 = _mm_or_si128(_mm_subs_epu8(topl2, botr2), _mm_subs_epu8(botr2, topl2)); - __m128i rawscorer1 = _mm_or_si128(_mm_subs_epu8(topr1, botl1), _mm_subs_epu8(botl1, topr1)); - __m128i rawscorer2 = _mm_or_si128(_mm_subs_epu8(topr2, botl2), _mm_subs_epu8(botl2, topr2)); - - dst[0] = rawscorec0; - dst[1] = rawscorel1; - dst[2] = rawscorel2; - dst[3] = rawscorer1; - dst[4] = rawscorer2; - dst[5] = _mm_avg_epu8(topr1, botr1); - dst[6] = _mm_avg_epu8(topc0, botr2); - dst[7] = _mm_avg_epu8(topl1, botr3); - dst[8] = _mm_avg_epu8(topr2, botc0); - dst[9] = _mm_avg_epu8(topr3, botl1); - dst += 10; - } while(--w16); - } - - void nela_L8_SSE2(__m128i *dst, const __m128i *elabuf, int w16) { - __m128i zero = _mm_setzero_si128(); - __m128i x80b = _mm_set1_epi8((unsigned char)0x80); - - do { - __m128i x0, x1, x2, y; - - x0 = elabuf[0]; - y = elabuf[10]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorec0 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - x0 = elabuf[1]; - y = elabuf[11]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorel1 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - x0 = elabuf[2]; - y = elabuf[12]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorel2 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - x0 = elabuf[3]; - y = elabuf[13]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorer1 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - x0 = elabuf[4]; - y = elabuf[14]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorer2 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - scorec0 = _mm_xor_si128(scorec0, x80b); - scorel1 = _mm_xor_si128(scorel1, x80b); - scorel2 = _mm_xor_si128(scorel2, x80b); - scorer1 = _mm_xor_si128(scorer1, x80b); - scorer2 = _mm_xor_si128(scorer2, x80b); - - // result = (scorel1 < scorec0) ? (scorel2 < scorel1 ? l2 : l1) : (scorer1 < scorec0) ? (scorer2 < scorer1 ? r2 : r1) : c0 - - __m128i cmplt_l1_c0 = _mm_cmplt_epi8(scorel1, scorec0); - __m128i cmplt_r1_c0 = _mm_cmplt_epi8(scorer1, scorec0); - __m128i cmplt_l1_r1 = _mm_cmplt_epi8(scorel1, scorer1); - - __m128i is_l1 = _mm_and_si128(cmplt_l1_r1, cmplt_l1_c0); - __m128i is_r1 = _mm_andnot_si128(cmplt_l1_r1, cmplt_r1_c0); - __m128i is_c0_inv = _mm_or_si128(cmplt_l1_c0, cmplt_r1_c0); - __m128i is_c0 = _mm_andnot_si128(is_c0_inv, _mm_cmpeq_epi8(zero, zero)); - - __m128i is_l2 = _mm_and_si128(is_l1, _mm_cmplt_epi8(scorel2, scorel1)); - __m128i is_r2 = _mm_and_si128(is_r1, _mm_cmplt_epi8(scorer2, scorer1)); - - is_l1 = _mm_andnot_si128(is_l2, is_l1); - is_r1 = _mm_andnot_si128(is_r2, is_r1); - - __m128i mask_c0 = is_c0; - __m128i mask_l1 = is_l1; - __m128i mask_l2 = is_l2; - __m128i mask_r1 = is_r1; - __m128i mask_r2 = is_r2; - - __m128i result_c0 = _mm_and_si128(elabuf[5], mask_c0); - __m128i result_l1 = _mm_and_si128(elabuf[6], mask_l1); - __m128i result_l2 = _mm_and_si128(elabuf[7], mask_l2); - __m128i result_r1 = _mm_and_si128(elabuf[8], mask_r1); - __m128i result_r2 = _mm_and_si128(elabuf[9], mask_r2); - - elabuf += 10; - - __m128i pred = _mm_or_si128(_mm_or_si128(_mm_or_si128(result_l1, result_l2), _mm_or_si128(result_r1, result_r2)), result_c0); - - *dst++ = pred; - } while(--w16); - } -#endif - -#if defined(VD_CPU_X86) - void __declspec(naked) __stdcall ela_L8_MMX(void *dst, const void *srcat, const void *srcab, int w16) { - static const __declspec(align(8)) uint64 xFEb = 0xfefefefefefefefe; - __asm { - push ebx - mov ebx, [esp + 4 + 4] - mov ecx, [esp + 8 + 4] - mov edx, [esp + 12 + 4] - mov eax, [esp + 16 + 4] - movq mm7, xFEb - -xloop: - movq mm0, [ecx + 15] - movq mm1, [edx + 15] - movq mm4, mm0 - movq mm2, [ecx + 15 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 15 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx], mm0 - por mm2, mm3 - movq [ebx + 8], mm2 - - movq mm0, [ecx + 14] - movq mm1, [edx + 16] - movq mm4, mm0 - movq mm2, [ecx + 14 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 16 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 16], mm0 - por mm2, mm3 - movq [ebx + 24], mm2 - - movq mm0, [ecx + 13] - movq mm1, [edx + 17] - movq mm4, mm0 - movq mm2, [ecx + 13 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 17 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 32], mm0 - por mm2, mm3 - movq [ebx + 40], mm2 - - movq mm0, [ecx + 16] - movq mm1, [edx + 14] - movq mm4, mm0 - movq mm2, [ecx + 16 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 14 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 48], mm0 - por mm2, mm3 - movq [ebx + 56], mm2 - - movq mm0, [ecx + 17] - movq mm1, [edx + 13] - movq mm4, mm0 - movq mm2, [ecx + 17 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 13 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 64], mm0 - por mm2, mm3 - movq [ebx + 72], mm2 - - movq mm0, [ecx + 16] - movq mm1, [edx + 16] - movq mm2, [ecx + 16 + 8] - movq mm3, [edx + 16 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 80], mm1 - movq [ebx + 88], mm3 - - movq mm0, [ecx + 15] - movq mm1, [edx + 17] - movq mm2, [ecx + 15 + 8] - movq mm3, [edx + 17 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 96], mm1 - movq [ebx + 104], mm3 - - movq mm0, [ecx + 14] - movq mm1, [edx + 18] - movq mm2, [ecx + 14 + 8] - movq mm3, [edx + 18 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 112], mm1 - movq [ebx + 120], mm3 - - movq mm0, [ecx + 17] - movq mm1, [edx + 15] - movq mm2, [ecx + 17 + 8] - movq mm3, [edx + 15 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 128], mm1 - movq [ebx + 136], mm3 - - movq mm0, [ecx + 18] - movq mm1, [edx + 14] - movq mm2, [ecx + 18 + 8] - movq mm3, [edx + 14 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 144], mm1 - movq [ebx + 152], mm3 - - add ebx, 160 - add ecx, 16 - add edx, 16 - dec eax - jne xloop - - emms - pop ebx - ret 16 - } - } - - void __declspec(naked) __stdcall ela_L8_ISSE(void *dst, const void *srcat, const void *srcab, int w16) { - static const __declspec(align(8)) uint64 xFEb = 0xfefefefefefefefe; - __asm { - push ebx - mov ebx, [esp + 4 + 4] - mov ecx, [esp + 8 + 4] - mov edx, [esp + 12 + 4] - mov eax, [esp + 16 + 4] - movq mm7, xFEb - -xloop: - movq mm0, [ecx + 15] - movq mm1, [edx + 15] - movq mm4, mm0 - movq mm2, [ecx + 15 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 15 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx], mm0 - por mm2, mm3 - movq [ebx + 8], mm2 - - movq mm0, [ecx + 14] - movq mm1, [edx + 16] - movq mm4, mm0 - movq mm2, [ecx + 14 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 16 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 16], mm0 - por mm2, mm3 - movq [ebx + 24], mm2 - - movq mm0, [ecx + 13] - movq mm1, [edx + 17] - movq mm4, mm0 - movq mm2, [ecx + 13 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 17 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 32], mm0 - por mm2, mm3 - movq [ebx + 40], mm2 - - movq mm0, [ecx + 16] - movq mm1, [edx + 14] - movq mm4, mm0 - movq mm2, [ecx + 16 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 14 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 48], mm0 - por mm2, mm3 - movq [ebx + 56], mm2 - - movq mm0, [ecx + 17] - movq mm1, [edx + 13] - movq mm4, mm0 - movq mm2, [ecx + 17 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 13 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 64], mm0 - por mm2, mm3 - movq [ebx + 72], mm2 - - movq mm0, [ecx + 16] - movq mm1, [edx + 16] - movq mm2, [ecx + 16 + 8] - movq mm3, [edx + 16 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 80], mm1 - movq [ebx + 88], mm3 - - movq mm0, [ecx + 15] - movq mm1, [edx + 17] - movq mm2, [ecx + 15 + 8] - movq mm3, [edx + 17 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 96], mm1 - movq [ebx + 104], mm3 - - movq mm0, [ecx + 14] - movq mm1, [edx + 18] - movq mm2, [ecx + 14 + 8] - movq mm3, [edx + 18 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 112], mm1 - movq [ebx + 120], mm3 - - movq mm0, [ecx + 17] - movq mm1, [edx + 15] - movq mm2, [ecx + 17 + 8] - movq mm3, [edx + 15 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 128], mm1 - movq [ebx + 136], mm3 - - movq mm0, [ecx + 18] - movq mm1, [edx + 14] - movq mm2, [ecx + 18 + 8] - movq mm3, [edx + 14 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 144], mm1 - movq [ebx + 152], mm3 - - add ebx, 160 - add ecx, 16 - add edx, 16 - dec eax - jne xloop - - emms - pop ebx - ret 16 - } - } - - void __declspec(naked) __stdcall nela_L8_ISSE(void *dst, const void *elabuf, int w16) { - static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; - __asm { - mov edx, [esp+4] - mov ecx, [esp+8] - mov eax, [esp+12] -xloop: - movq mm0, [ecx+000h] - pavgb mm0, [ecx+002h] - pavgb mm0, [ecx+001h] - - movq mm1, [ecx+010h] - pavgb mm1, [ecx+012h] - pavgb mm1, [ecx+011h] - - movq mm2, [ecx+020h] - pavgb mm2, [ecx+022h] - pavgb mm2, [ecx+021h] - - movq mm3, [ecx+030h] - pavgb mm3, [ecx+032h] - pavgb mm3, [ecx+031h] - - movq mm4, [ecx+040h] - pavgb mm4, [ecx+042h] - pavgb mm4, [ecx+041h] - - movq mm5, x7fb - pxor mm0, mm5 - pxor mm1, mm5 - pxor mm2, mm5 - pxor mm3, mm5 - pxor mm4, mm5 - - ;mm0 = scorec0 - ;mm1 = scorel1 - ;mm2 = scorel2 - ;mm3 = scorer1 - ;mm4 = scorer2 - - movq mm5, mm3 - pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) - - pcmpgtb mm4, mm3 ;scorer2 > scorer1 - pcmpgtb mm2, mm1 ;scorel2 > scorel1 - - pcmpgtb mm1, mm0 ;scorel1 > scorec0 - pcmpgtb mm3, mm0 ;scorer1 > scorec0 - - movq mm6, mm1 - pcmpeqb mm0, mm0 - por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 - pxor mm0, mm6 ;mask_c0 - - pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 - pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 - - pand mm4, mm3 ;mask_r2 - pand mm2, mm5 ;mask_l2 - - pxor mm3, mm4 ;mask_r1 - pxor mm5, mm2 ;mask_l1 - - pand mm0, [ecx+050h] - pand mm5, [ecx+060h] - pand mm2, [ecx+070h] - pand mm3, [ecx+080h] - pand mm4, [ecx+090h] - por mm0, mm5 - por mm2, mm3 - por mm0, mm4 - por mm0, mm2 - movq [edx], mm0 - - movq mm0, [ecx+008h] - movq mm5, [ecx+0a0h] - movq mm6, mm0 - psrlq mm0, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm0, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm0, [ecx+008h] - pavgb mm0, mm6 - - movq mm1, [ecx+018h] - movq mm5, [ecx+0b0h] - movq mm6, mm1 - psrlq mm1, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm1, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm1, [ecx+018h] - pavgb mm1, mm6 - - movq mm2, [ecx+028h] - movq mm5, [ecx+0c0h] - movq mm6, mm2 - psrlq mm2, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm2, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm2, [ecx+028h] - pavgb mm2, mm6 - - movq mm3, [ecx+038h] - movq mm5, [ecx+0d0h] - movq mm6, mm3 - psrlq mm3, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm3, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm3, [ecx+038h] - pavgb mm3, mm6 - - movq mm4, [ecx+048h] - movq mm5, [ecx+0e0h] - movq mm6, mm4 - psrlq mm4, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm4, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm4, [ecx+048h] - pavgb mm4, mm6 - - movq mm5, x7fb - pxor mm0, mm5 - pxor mm1, mm5 - pxor mm2, mm5 - pxor mm3, mm5 - pxor mm4, mm5 - - ;mm0 = scorec0 - ;mm1 = scorel1 - ;mm2 = scorel2 - ;mm3 = scorer1 - ;mm4 = scorer2 - - movq mm5, mm3 - pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) - - pcmpgtb mm4, mm3 ;scorer2 > scorer1 - pcmpgtb mm2, mm1 ;scorel2 > scorel1 - - pcmpgtb mm1, mm0 ;scorel1 > scorec0 - pcmpgtb mm3, mm0 ;scorer1 > scorec0 - - movq mm6, mm1 - pcmpeqb mm0, mm0 - por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 - pxor mm0, mm6 ;mask_c0 - - pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 - pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 - - pand mm4, mm3 ;mask_r2 - pand mm2, mm5 ;mask_l2 - - pxor mm3, mm4 ;mask_r1 - pxor mm5, mm2 ;mask_l1 - - pand mm0, [ecx+058h] - pand mm5, [ecx+068h] - pand mm2, [ecx+078h] - pand mm3, [ecx+088h] - pand mm4, [ecx+098h] - por mm0, mm5 - por mm2, mm3 - por mm0, mm4 - por mm0, mm2 - movq [edx+8], mm0 - - add ecx, 0a0h - add edx, 16 - - dec eax - jnz xloop - - emms - ret 12 - } - } - - void __declspec(naked) __stdcall nela_L8_MMX(void *dst, const void *elabuf, int w16) { - static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; - - __asm { - mov edx, [esp+4] - mov ecx, [esp+8] - mov eax, [esp+12] -xloop: - movq mm0, [ecx+000h] - movq mm5, [ecx+002h] - movq mm6, mm0 - pxor mm0, mm5 - por mm6, mm5 - movq mm7, [ecx+001h] - psrlq mm0, 1 - pand mm0, x7fb - psubb mm6, mm0 - movq mm0, mm6 - pxor mm6, mm7 - por mm0, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm0, mm6 - - movq mm1, [ecx+010h] - movq mm5, [ecx+012h] - movq mm6, mm1 - pxor mm1, mm5 - por mm6, mm5 - movq mm7, [ecx+011h] - psrlq mm1, 1 - pand mm1, x7fb - psubb mm6, mm1 - movq mm1, mm6 - pxor mm6, mm7 - por mm1, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm1, mm6 - - movq mm2, [ecx+020h] - movq mm5, [ecx+022h] - movq mm6, mm2 - pxor mm2, mm5 - por mm6, mm5 - movq mm7, [ecx+021h] - psrlq mm2, 1 - pand mm2, x7fb - psubb mm6, mm2 - movq mm2, mm6 - pxor mm6, mm7 - por mm2, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm2, mm6 - - movq mm3, [ecx+030h] - movq mm5, [ecx+032h] - movq mm6, mm3 - pxor mm3, mm5 - por mm6, mm5 - movq mm7, [ecx+031h] - psrlq mm3, 1 - pand mm3, x7fb - psubb mm6, mm3 - movq mm3, mm6 - pxor mm6, mm7 - por mm3, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm3, mm6 - - movq mm4, [ecx+040h] - movq mm5, [ecx+042h] - movq mm6, mm4 - pxor mm4, mm5 - por mm6, mm5 - movq mm7, [ecx+041h] - psrlq mm4, 1 - pand mm4, x7fb - psubb mm6, mm4 - movq mm4, mm6 - pxor mm6, mm7 - por mm4, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm4, mm6 - - - movq mm5, x7fb - pxor mm0, mm5 - pxor mm1, mm5 - pxor mm2, mm5 - pxor mm3, mm5 - pxor mm4, mm5 - - ;mm0 = scorec0 - ;mm1 = scorel1 - ;mm2 = scorel2 - ;mm3 = scorer1 - ;mm4 = scorer2 - - movq mm5, mm3 - pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) - - pcmpgtb mm4, mm3 ;scorer2 > scorer1 - pcmpgtb mm2, mm1 ;scorel2 > scorel1 - - pcmpgtb mm1, mm0 ;scorel1 > scorec0 - pcmpgtb mm3, mm0 ;scorer1 > scorec0 - - movq mm6, mm1 - pcmpeqb mm0, mm0 - por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 - pxor mm0, mm6 ;mask_c0 - - pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 - pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 - - pand mm4, mm3 ;mask_r2 - pand mm2, mm5 ;mask_l2 - - pxor mm3, mm4 ;mask_r1 - pxor mm5, mm2 ;mask_l1 - - pand mm0, [ecx+050h] - pand mm5, [ecx+060h] - pand mm2, [ecx+070h] - pand mm3, [ecx+080h] - pand mm4, [ecx+090h] - por mm0, mm5 - por mm2, mm3 - por mm0, mm4 - por mm0, mm2 - - movq [edx], mm0 - - movq mm0, [ecx+008h] ;mm0 = x0 - movq mm5, [ecx+0a0h] ;mm5 = x1 - psrlq mm0, 16 ;mm0 = (x0 >> 16) - movq mm7, [ecx+008h] ;mm7 = y0 = x0 - psllq mm5, 48 ;mm5 = (x1 << 48) - movq mm6, mm7 ;mm6 = y0 = x0 - por mm0, mm5 ;mm0 = y2 = (x0 >> 16) | (x1 << 48) - pxor mm6, mm0 ;mm6 = y0 ^ y2 - por mm7, mm0 ;mm7 = y0 | y2 - movq mm5, [ecx+008h] ;mm5 = x0 - psrlq mm6, 1 ;mm6 = (y0 ^ y2) >> 1 - movq mm0, [ecx+0a0h] ;mm0 = x1 - psrlq mm5, 8 ;mm5 = x0 >> 8 - pand mm6, x7fb ;mm6 = ((y0 ^ y2) >> 1) & 0x7f7f7f7f7f7f7f7f - psllq mm0, 56 ;mm0 = x1 << 56 - psubb mm7, mm6 ;mm7 = t = (y0 | y2) - (((y0 ^ y2) >> 1) & 0x7f7f7f7f7f7f7f7f) = avgb(y0, y2) - por mm0, mm5 ;mm0 = y1 = (x0 >> 8) | (x1 << 56) - movq mm6, mm7 ;mm6 = t - pxor mm7, mm0 ;mm7 = t ^ y1 - por mm0, mm6 ;mm0 = t | y1 - psrlq mm7, 1 ;mm7 = (t ^ y1) >> 1 - pand mm7, x7fb ;mm7 = ((t ^ y1) >> 1) & 0x7f7f7f7f7f7f7f7f - psubb mm0, mm7 ;mm0 = (t | y1) - (((t ^ y1) >> 1) & 0x7f7f7f7f7f7f7f7f) = avgb(y1, avgb(y0, y2)) - - movq mm1, [ecx+018h] - movq mm5, [ecx+0b0h] - psrlq mm1, 16 - movq mm7, [ecx+018h] - psllq mm5, 48 - movq mm6, mm7 - por mm1, mm5 - pxor mm6, mm1 - por mm7, mm1 - movq mm5, [ecx+018h] - psrlq mm6, 1 - movq mm1, [ecx+0b0h] - psrlq mm5, 8 - pand mm6, x7fb - psllq mm1, 56 - psubb mm7, mm6 - por mm1, mm5 - movq mm6, mm7 - pxor mm7, mm1 - por mm1, mm6 - psrlq mm7, 1 - pand mm7, x7fb - psubb mm1, mm7 - - movq mm2, [ecx+028h] - movq mm5, [ecx+0c0h] - psrlq mm2, 16 - movq mm7, [ecx+028h] - psllq mm5, 48 - movq mm6, mm7 - por mm2, mm5 - pxor mm6, mm2 - por mm7, mm2 - movq mm5, [ecx+028h] - psrlq mm6, 1 - movq mm2, [ecx+0c0h] - psrlq mm5, 8 - pand mm6, x7fb - psllq mm2, 56 - psubb mm7, mm6 - por mm2, mm5 - movq mm6, mm7 - pxor mm7, mm2 - por mm2, mm6 - psrlq mm7, 1 - pand mm7, x7fb - psubb mm2, mm7 - - movq mm3, [ecx+038h] - movq mm5, [ecx+0d0h] - psrlq mm3, 16 - movq mm7, [ecx+038h] - psllq mm5, 48 - movq mm6, mm7 - por mm3, mm5 - pxor mm6, mm3 - por mm7, mm3 - movq mm5, [ecx+038h] - psrlq mm6, 1 - movq mm3, [ecx+0d0h] - psrlq mm5, 8 - pand mm6, x7fb - psllq mm3, 56 - psubb mm7, mm6 - por mm3, mm5 - movq mm6, mm7 - pxor mm7, mm3 - por mm3, mm6 - psrlq mm7, 1 - pand mm7, x7fb - psubb mm3, mm7 - - movq mm4, [ecx+048h] - movq mm5, [ecx+0e0h] - psrlq mm4, 16 - movq mm7, [ecx+048h] - psllq mm5, 48 - movq mm6, mm7 - por mm4, mm5 - pxor mm6, mm4 - por mm7, mm4 - movq mm5, [ecx+048h] - psrlq mm6, 1 - movq mm4, [ecx+0e0h] - psrlq mm5, 8 - pand mm6, x7fb - psllq mm4, 56 - psubb mm7, mm6 - por mm4, mm5 - movq mm6, mm7 - pxor mm7, mm4 - por mm4, mm6 - psrlq mm7, 1 - pand mm7, x7fb - psubb mm4, mm7 - - movq mm5, x7fb - pxor mm0, mm5 - pxor mm1, mm5 - pxor mm2, mm5 - pxor mm3, mm5 - pxor mm4, mm5 - - ;mm0 = scorec0 - ;mm1 = scorel1 - ;mm2 = scorel2 - ;mm3 = scorer1 - ;mm4 = scorer2 - - movq mm5, mm3 - pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) - - pcmpgtb mm4, mm3 ;scorer2 > scorer1 - pcmpgtb mm2, mm1 ;scorel2 > scorel1 - - pcmpgtb mm1, mm0 ;scorel1 > scorec0 - pcmpgtb mm3, mm0 ;scorer1 > scorec0 - - movq mm6, mm1 - pcmpeqb mm0, mm0 - por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 - pxor mm0, mm6 ;mask_c0 - - pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 - pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 - - pand mm4, mm3 ;mask_r2 - pand mm2, mm5 ;mask_l2 - - pxor mm3, mm4 ;mask_r1 - pxor mm5, mm2 ;mask_l1 - - pand mm0, [ecx+058h] - pand mm5, [ecx+068h] - pand mm2, [ecx+078h] - pand mm3, [ecx+088h] - pand mm4, [ecx+098h] - por mm0, mm5 - por mm2, mm3 - por mm0, mm4 - por mm0, mm2 - movq [edx+8], mm0 - - add ecx, 0a0h - add edx, 16 - - dec eax - jnz xloop - - emms - ret 12 - } - } -#endif - -namespace { - void ela_L8_scalar(uint8 *dst, const uint8 *srcat, const uint8 *srcab, int w16) { - int w = w16 << 4; - - srcat += 16; - srcab += 16; - do { - int topl2 = srcat[-3]; - int topl1 = srcat[-2]; - int topc0 = srcat[-1]; - int topr1 = srcat[0]; - int topr2 = srcat[1]; - int topr3 = srcat[2]; - - int botl2 = srcab[-3]; - int botl1 = srcab[-2]; - int botc0 = srcab[-1]; - int botr1 = srcab[0]; - int botr2 = srcab[1]; - int botr3 = srcab[2]; - ++srcat; - ++srcab; - - int rawscorec0 = abs(topc0 - botc0); - int rawscorel1 = abs(topl1 - botr1); - int rawscorel2 = abs(topl2 - botr2); - int rawscorer1 = abs(topr1 - botl1); - int rawscorer2 = abs(topr2 - botl2); - - dst[0] = (uint8)rawscorec0; - dst[1] = (uint8)rawscorel1; - dst[2] = (uint8)rawscorel2; - dst[3] = (uint8)rawscorer1; - dst[4] = (uint8)rawscorer2; - dst[5] = (uint8)((topr1 + botr1 + 1) >> 1); - dst[6] = (uint8)((topc0 + botr2 + 1) >> 1); - dst[7] = (uint8)((topl1 + botr3 + 1) >> 1); - dst[8] = (uint8)((topr2 + botc0 + 1) >> 1); - dst[9] = (uint8)((topr3 + botl1 + 1) >> 1); - dst += 10; - } while(--w); - } - - void nela_L8_scalar(uint8 *dst, const uint8 *elabuf, int w16) { - int w = w16 << 4; - - do { - int scorec0 = elabuf[10]*2 + (elabuf[0] + elabuf[20]); - int result = elabuf[5]; - - int scorel1 = elabuf[11]*2 + (elabuf[1] + elabuf[21]); - if (scorel1 < scorec0) { - result = elabuf[6]; - scorec0 = scorel1; - - int scorel2 = elabuf[12]*2 + (elabuf[2] + elabuf[22]); - if (scorel2 < scorec0) { - result = elabuf[7]; - scorec0 = scorel2; - } - } - - int scorer1 = elabuf[13]*2 + (elabuf[3] + elabuf[23]); - if (scorer1 < scorec0) { - result = elabuf[8]; - scorec0 = scorer1; - - int scorer2 = elabuf[14]*2 + (elabuf[4] + elabuf[24]); - if (scorer2 < scorec0) - result = elabuf[9]; - } - - elabuf += 10; - - *dst++ = (uint8)result; - } while(--w); - } - - void BlendScanLine_NELA_scalar(void *dst, const void *srcT, const void *srcB, uint32 w, uint8 *tempBuf) { - const uint8 *srcat = (const uint8 *)srcT; - const uint8 *srcab = (const uint8 *)srcB; - uint32 w16 = (w + 15) >> 4; - uint32 wr = w16 << 4; - - uint8 *elabuf = tempBuf; - uint8 *topbuf = elabuf + 10*wr; - uint8 *botbuf = topbuf + wr + 32; - - uint32 woffset = w & 15; - topbuf[13] = topbuf[14] = topbuf[15] = srcat[0]; - botbuf[13] = botbuf[14] = botbuf[15] = srcab[0]; - - for(uint32 x=0; x> 1); - srca += 4; - srcb += 4; - } while(--w4); - } - - void BlendScanLine_NELA_X8R8G8B8_scalar(void *dst, const void *srcT, const void *srcB, uint32 w, void *tempBuf) { - const uint32 *srcat = (const uint32 *)srcT; - const uint32 *srcab = (const uint32 *)srcB; - uint32 w4 = (w + 3) >> 2; - uint32 *elabuf = (uint32 *)tempBuf; - uint32 *topbuf = elabuf + 5*w4; - uint32 *botbuf = topbuf + w4 + 8; - - topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = srcat[0]; - botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = srcab[0]; - - for(uint32 x=0; x> 2; - uint32 *elabuf = (uint32 *)tempBuf; - uint32 *topbuf = elabuf + 5*w4; - uint32 *botbuf = topbuf + w4 + 8; - - topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = srcat[0]; - botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = srcab[0]; - - for(uint32 x=0; x> 4; - uint32 w4 = w16 * 4; - uint32 *elabuf = (uint32 *)tempBuf; - uint32 *topbuf = elabuf + 40*w16; - uint32 *botbuf = topbuf + w4 + 8; - - uint32 woffset = w & 15; - topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = (srcat[0] & 0xff) * 0x01010101; - botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = (srcab[0] & 0xff) * 0x01010101; - - for(uint32 x=0; x> 4; - __m128i *elabuf = tempBuf; - __m128i *topbuf = elabuf + 10*w16; - __m128i *botbuf = topbuf + w16 + 2; - - uint32 woffset = w & 15; - topbuf[0] = srcat[0]; - botbuf[0] = srcab[0]; - - for(uint32 x=0; x> 4; - vdfastvector > tempbuf((12 * w16 + 4) * 16); - void *elabuf = tempbuf.data(); - - if (!interpField2) - memcpy(dst, src, w16 << 4); - - int y0 = interpField2 ? 1 : 2; - for(uint32 y = y0; y < h - 1; y += 2) { - const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); - const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); - -#if defined(VD_CPU_X86) - if (MMX_enabled) - BlendScanLine_NELA_X8R8G8B8_MMX((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); - else -#endif - BlendScanLine_NELA_X8R8G8B8_scalar((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); - } - - if (interpField2) - memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w16 << 4); - } - - void InterpPlane_NELA(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, uint32 w, uint32 h, bool interpField2) { - uint32 w16 = (w + 15) >> 4; - vdfastvector > tempbuf((12 * w16 + 4) * 16); - void *elabuf = tempbuf.data(); - - if (!interpField2) - memcpy(dst, src, w16 << 4); - - int y0 = interpField2 ? 1 : 2; - if (SSE2_enabled) { - for(uint32 y = y0; y < h - 1; y += 2) { - const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); - const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); - - BlendScanLine_NELA_SSE2((char *)dst + dstpitch*y, srcat, srcab, w, (__m128i *)elabuf); - } - } -#if defined(VD_CPU_X86) - else if (MMX_enabled || ISSE_enabled) { - for(uint32 y = y0; y < h - 1; y += 2) { - const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); - const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); - - BlendScanLine_NELA_MMX_ISSE((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); - } - } -#endif - else { - for(uint32 y = y0; y < h - 1; y += 2) { - const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); - const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); - - BlendScanLine_NELA_scalar((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); - } - } - - if (interpField2) - memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w16 << 4); - } - - void Average_scalar(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { - uint32 w4 = w16 << 2; - do { - uint32 *dstv = (uint32 *)dst; - uint32 *src1v = (uint32 *)src1; - uint32 *src2v = (uint32 *)src2; - - for(uint32 i=0; i> 1); - } - - dst = (char *)dst + dstPitch; - src1 = (char *)src1 + srcPitch; - src2 = (char *)src2 + srcPitch; - } while(--h); - } - -#if defined(VD_CPU_X86) - void __declspec(naked) __cdecl Average_MMX(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { - static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; - static const __declspec(align(8)) uint64 xfeb = 0xfefefefefefefefe; - - __asm { - push ebp - push edi - push esi - push ebx - - mov esi, [esp+24+16] - mov eax, [esp+4+16] - shl esi, 4 - mov ecx, [esp+12+16] - mov edx, [esp+16+16] - mov ebp, [esp+20+16] - mov edi, [esp+8+16] - sub edi, esi - sub ebp, esi - - movq mm6, x7fb - movq mm7, xfeb - - mov esi, [esp+28+16] -yloop: - mov ebx, [esp+24+16] -mainRowLoop: - movq mm0, [ecx] - movq mm3, [ecx + 8] - movq mm1, mm0 - movq mm2, [edx] - movq mm4, mm3 - movq mm5, [edx + 8] - por mm1, mm2 - pxor mm0, mm2 - por mm4, mm5 - pxor mm3, mm5 - psrlq mm0, 1 - pand mm3, mm7 - pand mm0, mm6 - psrlq mm3, 1 - psubb mm1, mm0 - psubb mm4, mm3 - add ecx, 16 - movq [eax], mm1 - movq [eax+8], mm4 - add edx, 16 - add eax, 16 - dec ebx - jne mainRowLoop - - add eax, edi - add ecx, ebp - add edx, ebp - dec esi - jne yloop - - emms - pop ebx - pop esi - pop edi - pop ebp - ret - } - } - - void __declspec(naked) __cdecl Average_ISSE(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { - static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; - static const __declspec(align(8)) uint64 xfeb = 0xfefefefefefefefe; - - __asm { - push ebp - push edi - push esi - push ebx - - mov esi, [esp+24+16] - mov eax, [esp+4+16] - shl esi, 4 - mov ecx, [esp+12+16] - mov edx, [esp+16+16] - mov ebp, [esp+20+16] - mov edi, [esp+8+16] - sub edi, esi - sub ebp, esi - - movq mm6, x7fb - movq mm7, xfeb - - mov esi, [esp+28+16] -yloop: - mov ebx, [esp+24+16] -mainRowLoop: - movq mm0, [ecx] - movq mm1, [ecx + 8] - movq mm2, [edx] - movq mm3, [edx + 8] - pavgb mm0, mm2 - pavgb mm1, mm3 - movq [eax], mm0 - add ecx, 16 - add edx, 16 - movq [eax+8], mm1 - add eax, 16 - dec ebx - jne mainRowLoop - - add eax, edi - add ecx, ebp - add edx, ebp - dec esi - jne yloop - - emms - pop ebx - pop esi - pop edi - pop ebp - ret - } - } -#endif - -#if defined(VD_CPU_X86) || defined(VD_CPU_AMD64) - void Average_SSE2(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { - do { - __m128i *dstv = (__m128i *)dst; - __m128i *src1v = (__m128i *)src1; - __m128i *src2v = (__m128i *)src2; - - for(uint32 i=0; i> 2; - - uint32 y0 = interpField2 ? 1 : 2; - - if (!interpField2) - memcpy(dst, src, w * 4); - - if (h > y0) { - ASSERT(((UINT_PTR)dst & 0xF) == 0); - ASSERT((dstpitch & 0xF) == 0); - ASSERT(((UINT_PTR)src & 0xF) == 0); - ASSERT((srcpitch*(y0 - 1) & 0xF) == 0); - blend_func((char *)dst + dstpitch*y0, - dstpitch*2, - (const char *)src + srcpitch*(y0 - 1), - (const char *)src + srcpitch*(y0 + 1), - srcpitch*2, - (w + 3) >> 2, - (h - y0) >> 1); - } - - if (interpField2) - memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w*4); - -#ifdef _M_IX86 - if (MMX_enabled) - __asm emms -#endif - } - - void BlendPlane(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, uint32 w, uint32 h) { - void (*blend_func)(void *, const void *, uint32, ptrdiff_t); -#if defined(VD_CPU_X86) - if (SSE2_enabled && !(srcpitch % 16)) - blend_func = asm_blend_row_SSE2; - else - blend_func = ISSE_enabled ? asm_blend_row_ISSE : MMX_enabled ? asm_blend_row_MMX : asm_blend_row; -#else - blend_func = asm_blend_row_SSE2; -#endif - - w = (w + 3) >> 2; - - asm_blend_row_clipped(dst, src, w, srcpitch); - if (h-=2) - do { - dst = ((char *)dst + dstpitch); - - blend_func(dst, src, w, srcpitch); - - src = ((char *)src + srcpitch); - } while(--h); - - asm_blend_row_clipped((char *)dst + dstpitch, src, w, srcpitch); - -#ifdef _M_IX86 - if (MMX_enabled) - __asm emms -#endif - } -} - -void DeinterlaceELA_X8R8G8B8(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) -{ - topfield = !topfield; - - InterpPlane_NELA_X8R8G8B8(dst, dstpitch, src, srcpitch, w, h, topfield); -} - -void DeinterlaceELA(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) -{ - topfield = !topfield; - - InterpPlane_NELA(dst, dstpitch, src, srcpitch, w, h, topfield); -} - -void DeinterlaceBob(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) -{ - topfield = !topfield; - - InterpPlane_Bob(dst, dstpitch, src, srcpitch, w, h, topfield); -} - -void DeinterlaceBlend(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch) -{ - BlendPlane(dst, dstpitch, src, srcpitch, w, h); -} +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include "stdafx.h" +#include +#include "vd2/system/memory.h" +#include "vd2/system/cpuaccel.h" +#include "vd2/system/vdstl.h" + +#pragma warning(disable: 4799) // warning C4799: function has no EMMS instruction + +/////////////////////////////////////////////////////////////////////////// + +#ifdef _M_IX86 +static void __declspec(naked) asm_blend_row_clipped(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + __asm { + push ebp + push edi + push esi + push ebx + + mov edi,[esp+20] + mov esi,[esp+24] + sub edi,esi + mov ebp,[esp+28] + mov edx,[esp+32] + +xloop: + mov ecx,[esi] + mov eax,0fefefefeh + + mov ebx,[esi+edx] + and eax,ecx + + shr eax,1 + and ebx,0fefefefeh + + shr ebx,1 + add esi,4 + + add eax,ebx + dec ebp + + mov [edi+esi-4],eax + jnz xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +static void __declspec(naked) asm_blend_row(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + __asm { + push ebp + push edi + push esi + push ebx + + mov edi,[esp+20] + mov esi,[esp+24] + sub edi,esi + mov ebp,[esp+28] + mov edx,[esp+32] + +xloop: + mov ecx,[esi] + mov eax,0fcfcfcfch + + mov ebx,[esi+edx] + and eax,ecx + + shr ebx,1 + mov ecx,[esi+edx*2] + + shr ecx,2 + and ebx,07f7f7f7fh + + shr eax,2 + and ecx,03f3f3f3fh + + add eax,ebx + add esi,4 + + add eax,ecx + dec ebp + + mov [edi+esi-4],eax + jnz xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +static void __declspec(naked) asm_blend_row_MMX(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + static const __declspec(align(8)) __int64 mask0 = 0xfcfcfcfcfcfcfcfci64; + static const __declspec(align(8)) __int64 mask1 = 0x7f7f7f7f7f7f7f7fi64; + static const __declspec(align(8)) __int64 mask2 = 0x3f3f3f3f3f3f3f3fi64; + __asm { + push ebp + push edi + push esi + push ebx + + mov edi,[esp+20] + mov esi,[esp+24] + sub edi,esi + mov ebp,[esp+28] + mov edx,[esp+32] + + movq mm5,mask0 + movq mm6,mask1 + movq mm7,mask2 + inc ebp + shr ebp,1 +xloop: + movq mm2,[esi] + movq mm0,mm5 + + movq mm1,[esi+edx] + pand mm0,mm2 + + psrlq mm1,1 + movq mm2,[esi+edx*2] + + psrlq mm2,2 + pand mm1,mm6 + + psrlq mm0,2 + pand mm2,mm7 + + paddb mm0,mm1 + add esi,8 + + paddb mm0,mm2 + dec ebp + + movq [edi+esi-8],mm0 + jne xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +static void __declspec(naked) asm_blend_row_ISSE(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + __asm { + push ebp + push edi + push esi + push ebx + + mov edi,[esp+20] + mov esi,[esp+24] + sub edi,esi + mov ebp,[esp+28] + mov edx,[esp+32] + + inc ebp + shr ebp,1 + pcmpeqb mm7, mm7 + + align 16 +xloop: + movq mm0, [esi] + movq mm2, mm7 + pxor mm0, mm7 + + pxor mm2, [esi+edx*2] + pavgb mm0, mm2 + pxor mm0, mm7 + + pavgb mm0, [esi+edx] + add esi,8 + + movq [edi+esi-8],mm0 + dec ebp + jne xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} +#else +static void asm_blend_row_clipped(void *dst0, const void *src0, uint32 w, ptrdiff_t srcpitch) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + const uint32 *src2 = (const uint32 *)((const char *)src + srcpitch); + + do { + const uint32 x = *src++; + const uint32 y = *src2++; + + *dst++ = (x|y) - (((x^y)&0xfefefefe)>>1); + } while(--w); +} + +static void asm_blend_row(void *dst0, const void *src0, uint32 w, ptrdiff_t srcpitch) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + const uint32 *src2 = (const uint32 *)((const char *)src + srcpitch); + const uint32 *src3 = (const uint32 *)((const char *)src2 + srcpitch); + + do { + const uint32 a = *src++; + const uint32 b = *src2++; + const uint32 c = *src3++; + const uint32 hi = (a & 0xfcfcfc) + 2*(b & 0xfcfcfc) + (c & 0xfcfcfc); + const uint32 lo = (a & 0x030303) + 2*(b & 0x030303) + (c & 0x030303) + 0x020202; + + *dst++ = (hi + (lo & 0x0c0c0c))>>2; + } while(--w); +} +#endif + +#if defined(VD_CPU_X86) || defined(VD_CPU_AMD64) + static void asm_blend_row_SSE2(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + __m128i zero = _mm_setzero_si128(); + __m128i inv = _mm_cmpeq_epi8(zero, zero); + + w = (w + 3) >> 2; + + const __m128i *src1 = (const __m128i *)src; + const __m128i *src2 = (const __m128i *)((const char *)src + srcpitch); + const __m128i *src3 = (const __m128i *)((const char *)src + srcpitch*2); + __m128i *dstrow = (__m128i *)dst; + do { + __m128i a = *src1++; + __m128i b = *src2++; + __m128i c = *src3++; + + *dstrow++ = _mm_avg_epu8(_mm_xor_si128(_mm_avg_epu8(_mm_xor_si128(a, inv), _mm_xor_si128(c, inv)), inv), b); + } while(--w); + } + + + void ela_L8_SSE2(__m128i *dst, const __m128i *srcat, const __m128i *srcab, int w16) { + do { + __m128i top0 = srcat[0]; + __m128i top1 = srcat[1]; + __m128i top2 = srcat[2]; + __m128i bot0 = srcab[0]; + __m128i bot1 = srcab[1]; + __m128i bot2 = srcab[2]; + ++srcat; + ++srcab; + + __m128i topl2 = _mm_or_si128(_mm_srli_si128(top0, 16 - 3), _mm_slli_si128(top1, 3)); + __m128i topl1 = _mm_or_si128(_mm_srli_si128(top0, 16 - 2), _mm_slli_si128(top1, 2)); + __m128i topc0 = _mm_or_si128(_mm_srli_si128(top0, 16 - 1), _mm_slli_si128(top1, 1)); + __m128i topr1 = top1; + __m128i topr2 = _mm_or_si128(_mm_srli_si128(top1, 1), _mm_slli_si128(top2, 16 - 1)); + __m128i topr3 = _mm_or_si128(_mm_srli_si128(top1, 2), _mm_slli_si128(top2, 16 - 2)); + + __m128i botl2 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 3), _mm_slli_si128(bot1, 3)); + __m128i botl1 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 2), _mm_slli_si128(bot1, 2)); + __m128i botc0 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 1), _mm_slli_si128(bot1, 1)); + __m128i botr1 = bot1; + __m128i botr2 = _mm_or_si128(_mm_srli_si128(bot1, 1), _mm_slli_si128(bot2, 16 - 1)); + __m128i botr3 = _mm_or_si128(_mm_srli_si128(bot1, 2), _mm_slli_si128(bot2, 16 - 2)); + + __m128i rawscorec0 = _mm_or_si128(_mm_subs_epu8(topc0, botc0), _mm_subs_epu8(botc0, topc0)); + __m128i rawscorel1 = _mm_or_si128(_mm_subs_epu8(topl1, botr1), _mm_subs_epu8(botr1, topl1)); + __m128i rawscorel2 = _mm_or_si128(_mm_subs_epu8(topl2, botr2), _mm_subs_epu8(botr2, topl2)); + __m128i rawscorer1 = _mm_or_si128(_mm_subs_epu8(topr1, botl1), _mm_subs_epu8(botl1, topr1)); + __m128i rawscorer2 = _mm_or_si128(_mm_subs_epu8(topr2, botl2), _mm_subs_epu8(botl2, topr2)); + + dst[0] = rawscorec0; + dst[1] = rawscorel1; + dst[2] = rawscorel2; + dst[3] = rawscorer1; + dst[4] = rawscorer2; + dst[5] = _mm_avg_epu8(topr1, botr1); + dst[6] = _mm_avg_epu8(topc0, botr2); + dst[7] = _mm_avg_epu8(topl1, botr3); + dst[8] = _mm_avg_epu8(topr2, botc0); + dst[9] = _mm_avg_epu8(topr3, botl1); + dst += 10; + } while(--w16); + } + + void nela_L8_SSE2(__m128i *dst, const __m128i *elabuf, int w16) { + __m128i zero = _mm_setzero_si128(); + __m128i x80b = _mm_set1_epi8((unsigned char)0x80); + + do { + __m128i x0, x1, x2, y; + + x0 = elabuf[0]; + y = elabuf[10]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorec0 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + x0 = elabuf[1]; + y = elabuf[11]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorel1 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + x0 = elabuf[2]; + y = elabuf[12]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorel2 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + x0 = elabuf[3]; + y = elabuf[13]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorer1 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + x0 = elabuf[4]; + y = elabuf[14]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorer2 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + scorec0 = _mm_xor_si128(scorec0, x80b); + scorel1 = _mm_xor_si128(scorel1, x80b); + scorel2 = _mm_xor_si128(scorel2, x80b); + scorer1 = _mm_xor_si128(scorer1, x80b); + scorer2 = _mm_xor_si128(scorer2, x80b); + + // result = (scorel1 < scorec0) ? (scorel2 < scorel1 ? l2 : l1) : (scorer1 < scorec0) ? (scorer2 < scorer1 ? r2 : r1) : c0 + + __m128i cmplt_l1_c0 = _mm_cmplt_epi8(scorel1, scorec0); + __m128i cmplt_r1_c0 = _mm_cmplt_epi8(scorer1, scorec0); + __m128i cmplt_l1_r1 = _mm_cmplt_epi8(scorel1, scorer1); + + __m128i is_l1 = _mm_and_si128(cmplt_l1_r1, cmplt_l1_c0); + __m128i is_r1 = _mm_andnot_si128(cmplt_l1_r1, cmplt_r1_c0); + __m128i is_c0_inv = _mm_or_si128(cmplt_l1_c0, cmplt_r1_c0); + __m128i is_c0 = _mm_andnot_si128(is_c0_inv, _mm_cmpeq_epi8(zero, zero)); + + __m128i is_l2 = _mm_and_si128(is_l1, _mm_cmplt_epi8(scorel2, scorel1)); + __m128i is_r2 = _mm_and_si128(is_r1, _mm_cmplt_epi8(scorer2, scorer1)); + + is_l1 = _mm_andnot_si128(is_l2, is_l1); + is_r1 = _mm_andnot_si128(is_r2, is_r1); + + __m128i mask_c0 = is_c0; + __m128i mask_l1 = is_l1; + __m128i mask_l2 = is_l2; + __m128i mask_r1 = is_r1; + __m128i mask_r2 = is_r2; + + __m128i result_c0 = _mm_and_si128(elabuf[5], mask_c0); + __m128i result_l1 = _mm_and_si128(elabuf[6], mask_l1); + __m128i result_l2 = _mm_and_si128(elabuf[7], mask_l2); + __m128i result_r1 = _mm_and_si128(elabuf[8], mask_r1); + __m128i result_r2 = _mm_and_si128(elabuf[9], mask_r2); + + elabuf += 10; + + __m128i pred = _mm_or_si128(_mm_or_si128(_mm_or_si128(result_l1, result_l2), _mm_or_si128(result_r1, result_r2)), result_c0); + + *dst++ = pred; + } while(--w16); + } +#endif + +#if defined(VD_CPU_X86) + void __declspec(naked) __stdcall ela_L8_MMX(void *dst, const void *srcat, const void *srcab, int w16) { + static const __declspec(align(8)) uint64 xFEb = 0xfefefefefefefefe; + __asm { + push ebx + mov ebx, [esp + 4 + 4] + mov ecx, [esp + 8 + 4] + mov edx, [esp + 12 + 4] + mov eax, [esp + 16 + 4] + movq mm7, xFEb + +xloop: + movq mm0, [ecx + 15] + movq mm1, [edx + 15] + movq mm4, mm0 + movq mm2, [ecx + 15 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 15 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx], mm0 + por mm2, mm3 + movq [ebx + 8], mm2 + + movq mm0, [ecx + 14] + movq mm1, [edx + 16] + movq mm4, mm0 + movq mm2, [ecx + 14 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 16 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 16], mm0 + por mm2, mm3 + movq [ebx + 24], mm2 + + movq mm0, [ecx + 13] + movq mm1, [edx + 17] + movq mm4, mm0 + movq mm2, [ecx + 13 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 17 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 32], mm0 + por mm2, mm3 + movq [ebx + 40], mm2 + + movq mm0, [ecx + 16] + movq mm1, [edx + 14] + movq mm4, mm0 + movq mm2, [ecx + 16 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 14 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 48], mm0 + por mm2, mm3 + movq [ebx + 56], mm2 + + movq mm0, [ecx + 17] + movq mm1, [edx + 13] + movq mm4, mm0 + movq mm2, [ecx + 17 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 13 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 64], mm0 + por mm2, mm3 + movq [ebx + 72], mm2 + + movq mm0, [ecx + 16] + movq mm1, [edx + 16] + movq mm2, [ecx + 16 + 8] + movq mm3, [edx + 16 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 80], mm1 + movq [ebx + 88], mm3 + + movq mm0, [ecx + 15] + movq mm1, [edx + 17] + movq mm2, [ecx + 15 + 8] + movq mm3, [edx + 17 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 96], mm1 + movq [ebx + 104], mm3 + + movq mm0, [ecx + 14] + movq mm1, [edx + 18] + movq mm2, [ecx + 14 + 8] + movq mm3, [edx + 18 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 112], mm1 + movq [ebx + 120], mm3 + + movq mm0, [ecx + 17] + movq mm1, [edx + 15] + movq mm2, [ecx + 17 + 8] + movq mm3, [edx + 15 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 128], mm1 + movq [ebx + 136], mm3 + + movq mm0, [ecx + 18] + movq mm1, [edx + 14] + movq mm2, [ecx + 18 + 8] + movq mm3, [edx + 14 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 144], mm1 + movq [ebx + 152], mm3 + + add ebx, 160 + add ecx, 16 + add edx, 16 + dec eax + jne xloop + + emms + pop ebx + ret 16 + } + } + + void __declspec(naked) __stdcall ela_L8_ISSE(void *dst, const void *srcat, const void *srcab, int w16) { + static const __declspec(align(8)) uint64 xFEb = 0xfefefefefefefefe; + __asm { + push ebx + mov ebx, [esp + 4 + 4] + mov ecx, [esp + 8 + 4] + mov edx, [esp + 12 + 4] + mov eax, [esp + 16 + 4] + movq mm7, xFEb + +xloop: + movq mm0, [ecx + 15] + movq mm1, [edx + 15] + movq mm4, mm0 + movq mm2, [ecx + 15 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 15 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx], mm0 + por mm2, mm3 + movq [ebx + 8], mm2 + + movq mm0, [ecx + 14] + movq mm1, [edx + 16] + movq mm4, mm0 + movq mm2, [ecx + 14 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 16 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 16], mm0 + por mm2, mm3 + movq [ebx + 24], mm2 + + movq mm0, [ecx + 13] + movq mm1, [edx + 17] + movq mm4, mm0 + movq mm2, [ecx + 13 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 17 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 32], mm0 + por mm2, mm3 + movq [ebx + 40], mm2 + + movq mm0, [ecx + 16] + movq mm1, [edx + 14] + movq mm4, mm0 + movq mm2, [ecx + 16 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 14 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 48], mm0 + por mm2, mm3 + movq [ebx + 56], mm2 + + movq mm0, [ecx + 17] + movq mm1, [edx + 13] + movq mm4, mm0 + movq mm2, [ecx + 17 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 13 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 64], mm0 + por mm2, mm3 + movq [ebx + 72], mm2 + + movq mm0, [ecx + 16] + movq mm1, [edx + 16] + movq mm2, [ecx + 16 + 8] + movq mm3, [edx + 16 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 80], mm1 + movq [ebx + 88], mm3 + + movq mm0, [ecx + 15] + movq mm1, [edx + 17] + movq mm2, [ecx + 15 + 8] + movq mm3, [edx + 17 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 96], mm1 + movq [ebx + 104], mm3 + + movq mm0, [ecx + 14] + movq mm1, [edx + 18] + movq mm2, [ecx + 14 + 8] + movq mm3, [edx + 18 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 112], mm1 + movq [ebx + 120], mm3 + + movq mm0, [ecx + 17] + movq mm1, [edx + 15] + movq mm2, [ecx + 17 + 8] + movq mm3, [edx + 15 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 128], mm1 + movq [ebx + 136], mm3 + + movq mm0, [ecx + 18] + movq mm1, [edx + 14] + movq mm2, [ecx + 18 + 8] + movq mm3, [edx + 14 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 144], mm1 + movq [ebx + 152], mm3 + + add ebx, 160 + add ecx, 16 + add edx, 16 + dec eax + jne xloop + + emms + pop ebx + ret 16 + } + } + + void __declspec(naked) __stdcall nela_L8_ISSE(void *dst, const void *elabuf, int w16) { + static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; + __asm { + mov edx, [esp+4] + mov ecx, [esp+8] + mov eax, [esp+12] +xloop: + movq mm0, [ecx+000h] + pavgb mm0, [ecx+002h] + pavgb mm0, [ecx+001h] + + movq mm1, [ecx+010h] + pavgb mm1, [ecx+012h] + pavgb mm1, [ecx+011h] + + movq mm2, [ecx+020h] + pavgb mm2, [ecx+022h] + pavgb mm2, [ecx+021h] + + movq mm3, [ecx+030h] + pavgb mm3, [ecx+032h] + pavgb mm3, [ecx+031h] + + movq mm4, [ecx+040h] + pavgb mm4, [ecx+042h] + pavgb mm4, [ecx+041h] + + movq mm5, x7fb + pxor mm0, mm5 + pxor mm1, mm5 + pxor mm2, mm5 + pxor mm3, mm5 + pxor mm4, mm5 + + ;mm0 = scorec0 + ;mm1 = scorel1 + ;mm2 = scorel2 + ;mm3 = scorer1 + ;mm4 = scorer2 + + movq mm5, mm3 + pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) + + pcmpgtb mm4, mm3 ;scorer2 > scorer1 + pcmpgtb mm2, mm1 ;scorel2 > scorel1 + + pcmpgtb mm1, mm0 ;scorel1 > scorec0 + pcmpgtb mm3, mm0 ;scorer1 > scorec0 + + movq mm6, mm1 + pcmpeqb mm0, mm0 + por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 + pxor mm0, mm6 ;mask_c0 + + pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 + pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 + + pand mm4, mm3 ;mask_r2 + pand mm2, mm5 ;mask_l2 + + pxor mm3, mm4 ;mask_r1 + pxor mm5, mm2 ;mask_l1 + + pand mm0, [ecx+050h] + pand mm5, [ecx+060h] + pand mm2, [ecx+070h] + pand mm3, [ecx+080h] + pand mm4, [ecx+090h] + por mm0, mm5 + por mm2, mm3 + por mm0, mm4 + por mm0, mm2 + movq [edx], mm0 + + movq mm0, [ecx+008h] + movq mm5, [ecx+0a0h] + movq mm6, mm0 + psrlq mm0, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm0, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm0, [ecx+008h] + pavgb mm0, mm6 + + movq mm1, [ecx+018h] + movq mm5, [ecx+0b0h] + movq mm6, mm1 + psrlq mm1, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm1, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm1, [ecx+018h] + pavgb mm1, mm6 + + movq mm2, [ecx+028h] + movq mm5, [ecx+0c0h] + movq mm6, mm2 + psrlq mm2, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm2, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm2, [ecx+028h] + pavgb mm2, mm6 + + movq mm3, [ecx+038h] + movq mm5, [ecx+0d0h] + movq mm6, mm3 + psrlq mm3, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm3, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm3, [ecx+038h] + pavgb mm3, mm6 + + movq mm4, [ecx+048h] + movq mm5, [ecx+0e0h] + movq mm6, mm4 + psrlq mm4, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm4, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm4, [ecx+048h] + pavgb mm4, mm6 + + movq mm5, x7fb + pxor mm0, mm5 + pxor mm1, mm5 + pxor mm2, mm5 + pxor mm3, mm5 + pxor mm4, mm5 + + ;mm0 = scorec0 + ;mm1 = scorel1 + ;mm2 = scorel2 + ;mm3 = scorer1 + ;mm4 = scorer2 + + movq mm5, mm3 + pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) + + pcmpgtb mm4, mm3 ;scorer2 > scorer1 + pcmpgtb mm2, mm1 ;scorel2 > scorel1 + + pcmpgtb mm1, mm0 ;scorel1 > scorec0 + pcmpgtb mm3, mm0 ;scorer1 > scorec0 + + movq mm6, mm1 + pcmpeqb mm0, mm0 + por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 + pxor mm0, mm6 ;mask_c0 + + pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 + pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 + + pand mm4, mm3 ;mask_r2 + pand mm2, mm5 ;mask_l2 + + pxor mm3, mm4 ;mask_r1 + pxor mm5, mm2 ;mask_l1 + + pand mm0, [ecx+058h] + pand mm5, [ecx+068h] + pand mm2, [ecx+078h] + pand mm3, [ecx+088h] + pand mm4, [ecx+098h] + por mm0, mm5 + por mm2, mm3 + por mm0, mm4 + por mm0, mm2 + movq [edx+8], mm0 + + add ecx, 0a0h + add edx, 16 + + dec eax + jnz xloop + + emms + ret 12 + } + } + + void __declspec(naked) __stdcall nela_L8_MMX(void *dst, const void *elabuf, int w16) { + static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; + + __asm { + mov edx, [esp+4] + mov ecx, [esp+8] + mov eax, [esp+12] +xloop: + movq mm0, [ecx+000h] + movq mm5, [ecx+002h] + movq mm6, mm0 + pxor mm0, mm5 + por mm6, mm5 + movq mm7, [ecx+001h] + psrlq mm0, 1 + pand mm0, x7fb + psubb mm6, mm0 + movq mm0, mm6 + pxor mm6, mm7 + por mm0, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm0, mm6 + + movq mm1, [ecx+010h] + movq mm5, [ecx+012h] + movq mm6, mm1 + pxor mm1, mm5 + por mm6, mm5 + movq mm7, [ecx+011h] + psrlq mm1, 1 + pand mm1, x7fb + psubb mm6, mm1 + movq mm1, mm6 + pxor mm6, mm7 + por mm1, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm1, mm6 + + movq mm2, [ecx+020h] + movq mm5, [ecx+022h] + movq mm6, mm2 + pxor mm2, mm5 + por mm6, mm5 + movq mm7, [ecx+021h] + psrlq mm2, 1 + pand mm2, x7fb + psubb mm6, mm2 + movq mm2, mm6 + pxor mm6, mm7 + por mm2, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm2, mm6 + + movq mm3, [ecx+030h] + movq mm5, [ecx+032h] + movq mm6, mm3 + pxor mm3, mm5 + por mm6, mm5 + movq mm7, [ecx+031h] + psrlq mm3, 1 + pand mm3, x7fb + psubb mm6, mm3 + movq mm3, mm6 + pxor mm6, mm7 + por mm3, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm3, mm6 + + movq mm4, [ecx+040h] + movq mm5, [ecx+042h] + movq mm6, mm4 + pxor mm4, mm5 + por mm6, mm5 + movq mm7, [ecx+041h] + psrlq mm4, 1 + pand mm4, x7fb + psubb mm6, mm4 + movq mm4, mm6 + pxor mm6, mm7 + por mm4, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm4, mm6 + + + movq mm5, x7fb + pxor mm0, mm5 + pxor mm1, mm5 + pxor mm2, mm5 + pxor mm3, mm5 + pxor mm4, mm5 + + ;mm0 = scorec0 + ;mm1 = scorel1 + ;mm2 = scorel2 + ;mm3 = scorer1 + ;mm4 = scorer2 + + movq mm5, mm3 + pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) + + pcmpgtb mm4, mm3 ;scorer2 > scorer1 + pcmpgtb mm2, mm1 ;scorel2 > scorel1 + + pcmpgtb mm1, mm0 ;scorel1 > scorec0 + pcmpgtb mm3, mm0 ;scorer1 > scorec0 + + movq mm6, mm1 + pcmpeqb mm0, mm0 + por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 + pxor mm0, mm6 ;mask_c0 + + pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 + pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 + + pand mm4, mm3 ;mask_r2 + pand mm2, mm5 ;mask_l2 + + pxor mm3, mm4 ;mask_r1 + pxor mm5, mm2 ;mask_l1 + + pand mm0, [ecx+050h] + pand mm5, [ecx+060h] + pand mm2, [ecx+070h] + pand mm3, [ecx+080h] + pand mm4, [ecx+090h] + por mm0, mm5 + por mm2, mm3 + por mm0, mm4 + por mm0, mm2 + + movq [edx], mm0 + + movq mm0, [ecx+008h] ;mm0 = x0 + movq mm5, [ecx+0a0h] ;mm5 = x1 + psrlq mm0, 16 ;mm0 = (x0 >> 16) + movq mm7, [ecx+008h] ;mm7 = y0 = x0 + psllq mm5, 48 ;mm5 = (x1 << 48) + movq mm6, mm7 ;mm6 = y0 = x0 + por mm0, mm5 ;mm0 = y2 = (x0 >> 16) | (x1 << 48) + pxor mm6, mm0 ;mm6 = y0 ^ y2 + por mm7, mm0 ;mm7 = y0 | y2 + movq mm5, [ecx+008h] ;mm5 = x0 + psrlq mm6, 1 ;mm6 = (y0 ^ y2) >> 1 + movq mm0, [ecx+0a0h] ;mm0 = x1 + psrlq mm5, 8 ;mm5 = x0 >> 8 + pand mm6, x7fb ;mm6 = ((y0 ^ y2) >> 1) & 0x7f7f7f7f7f7f7f7f + psllq mm0, 56 ;mm0 = x1 << 56 + psubb mm7, mm6 ;mm7 = t = (y0 | y2) - (((y0 ^ y2) >> 1) & 0x7f7f7f7f7f7f7f7f) = avgb(y0, y2) + por mm0, mm5 ;mm0 = y1 = (x0 >> 8) | (x1 << 56) + movq mm6, mm7 ;mm6 = t + pxor mm7, mm0 ;mm7 = t ^ y1 + por mm0, mm6 ;mm0 = t | y1 + psrlq mm7, 1 ;mm7 = (t ^ y1) >> 1 + pand mm7, x7fb ;mm7 = ((t ^ y1) >> 1) & 0x7f7f7f7f7f7f7f7f + psubb mm0, mm7 ;mm0 = (t | y1) - (((t ^ y1) >> 1) & 0x7f7f7f7f7f7f7f7f) = avgb(y1, avgb(y0, y2)) + + movq mm1, [ecx+018h] + movq mm5, [ecx+0b0h] + psrlq mm1, 16 + movq mm7, [ecx+018h] + psllq mm5, 48 + movq mm6, mm7 + por mm1, mm5 + pxor mm6, mm1 + por mm7, mm1 + movq mm5, [ecx+018h] + psrlq mm6, 1 + movq mm1, [ecx+0b0h] + psrlq mm5, 8 + pand mm6, x7fb + psllq mm1, 56 + psubb mm7, mm6 + por mm1, mm5 + movq mm6, mm7 + pxor mm7, mm1 + por mm1, mm6 + psrlq mm7, 1 + pand mm7, x7fb + psubb mm1, mm7 + + movq mm2, [ecx+028h] + movq mm5, [ecx+0c0h] + psrlq mm2, 16 + movq mm7, [ecx+028h] + psllq mm5, 48 + movq mm6, mm7 + por mm2, mm5 + pxor mm6, mm2 + por mm7, mm2 + movq mm5, [ecx+028h] + psrlq mm6, 1 + movq mm2, [ecx+0c0h] + psrlq mm5, 8 + pand mm6, x7fb + psllq mm2, 56 + psubb mm7, mm6 + por mm2, mm5 + movq mm6, mm7 + pxor mm7, mm2 + por mm2, mm6 + psrlq mm7, 1 + pand mm7, x7fb + psubb mm2, mm7 + + movq mm3, [ecx+038h] + movq mm5, [ecx+0d0h] + psrlq mm3, 16 + movq mm7, [ecx+038h] + psllq mm5, 48 + movq mm6, mm7 + por mm3, mm5 + pxor mm6, mm3 + por mm7, mm3 + movq mm5, [ecx+038h] + psrlq mm6, 1 + movq mm3, [ecx+0d0h] + psrlq mm5, 8 + pand mm6, x7fb + psllq mm3, 56 + psubb mm7, mm6 + por mm3, mm5 + movq mm6, mm7 + pxor mm7, mm3 + por mm3, mm6 + psrlq mm7, 1 + pand mm7, x7fb + psubb mm3, mm7 + + movq mm4, [ecx+048h] + movq mm5, [ecx+0e0h] + psrlq mm4, 16 + movq mm7, [ecx+048h] + psllq mm5, 48 + movq mm6, mm7 + por mm4, mm5 + pxor mm6, mm4 + por mm7, mm4 + movq mm5, [ecx+048h] + psrlq mm6, 1 + movq mm4, [ecx+0e0h] + psrlq mm5, 8 + pand mm6, x7fb + psllq mm4, 56 + psubb mm7, mm6 + por mm4, mm5 + movq mm6, mm7 + pxor mm7, mm4 + por mm4, mm6 + psrlq mm7, 1 + pand mm7, x7fb + psubb mm4, mm7 + + movq mm5, x7fb + pxor mm0, mm5 + pxor mm1, mm5 + pxor mm2, mm5 + pxor mm3, mm5 + pxor mm4, mm5 + + ;mm0 = scorec0 + ;mm1 = scorel1 + ;mm2 = scorel2 + ;mm3 = scorer1 + ;mm4 = scorer2 + + movq mm5, mm3 + pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) + + pcmpgtb mm4, mm3 ;scorer2 > scorer1 + pcmpgtb mm2, mm1 ;scorel2 > scorel1 + + pcmpgtb mm1, mm0 ;scorel1 > scorec0 + pcmpgtb mm3, mm0 ;scorer1 > scorec0 + + movq mm6, mm1 + pcmpeqb mm0, mm0 + por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 + pxor mm0, mm6 ;mask_c0 + + pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 + pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 + + pand mm4, mm3 ;mask_r2 + pand mm2, mm5 ;mask_l2 + + pxor mm3, mm4 ;mask_r1 + pxor mm5, mm2 ;mask_l1 + + pand mm0, [ecx+058h] + pand mm5, [ecx+068h] + pand mm2, [ecx+078h] + pand mm3, [ecx+088h] + pand mm4, [ecx+098h] + por mm0, mm5 + por mm2, mm3 + por mm0, mm4 + por mm0, mm2 + movq [edx+8], mm0 + + add ecx, 0a0h + add edx, 16 + + dec eax + jnz xloop + + emms + ret 12 + } + } +#endif + +namespace { + void ela_L8_scalar(uint8 *dst, const uint8 *srcat, const uint8 *srcab, int w16) { + int w = w16 << 4; + + srcat += 16; + srcab += 16; + do { + int topl2 = srcat[-3]; + int topl1 = srcat[-2]; + int topc0 = srcat[-1]; + int topr1 = srcat[0]; + int topr2 = srcat[1]; + int topr3 = srcat[2]; + + int botl2 = srcab[-3]; + int botl1 = srcab[-2]; + int botc0 = srcab[-1]; + int botr1 = srcab[0]; + int botr2 = srcab[1]; + int botr3 = srcab[2]; + ++srcat; + ++srcab; + + int rawscorec0 = abs(topc0 - botc0); + int rawscorel1 = abs(topl1 - botr1); + int rawscorel2 = abs(topl2 - botr2); + int rawscorer1 = abs(topr1 - botl1); + int rawscorer2 = abs(topr2 - botl2); + + dst[0] = (uint8)rawscorec0; + dst[1] = (uint8)rawscorel1; + dst[2] = (uint8)rawscorel2; + dst[3] = (uint8)rawscorer1; + dst[4] = (uint8)rawscorer2; + dst[5] = (uint8)((topr1 + botr1 + 1) >> 1); + dst[6] = (uint8)((topc0 + botr2 + 1) >> 1); + dst[7] = (uint8)((topl1 + botr3 + 1) >> 1); + dst[8] = (uint8)((topr2 + botc0 + 1) >> 1); + dst[9] = (uint8)((topr3 + botl1 + 1) >> 1); + dst += 10; + } while(--w); + } + + void nela_L8_scalar(uint8 *dst, const uint8 *elabuf, int w16) { + int w = w16 << 4; + + do { + int scorec0 = elabuf[10]*2 + (elabuf[0] + elabuf[20]); + int result = elabuf[5]; + + int scorel1 = elabuf[11]*2 + (elabuf[1] + elabuf[21]); + if (scorel1 < scorec0) { + result = elabuf[6]; + scorec0 = scorel1; + + int scorel2 = elabuf[12]*2 + (elabuf[2] + elabuf[22]); + if (scorel2 < scorec0) { + result = elabuf[7]; + scorec0 = scorel2; + } + } + + int scorer1 = elabuf[13]*2 + (elabuf[3] + elabuf[23]); + if (scorer1 < scorec0) { + result = elabuf[8]; + scorec0 = scorer1; + + int scorer2 = elabuf[14]*2 + (elabuf[4] + elabuf[24]); + if (scorer2 < scorec0) + result = elabuf[9]; + } + + elabuf += 10; + + *dst++ = (uint8)result; + } while(--w); + } + + void BlendScanLine_NELA_scalar(void *dst, const void *srcT, const void *srcB, uint32 w, uint8 *tempBuf) { + const uint8 *srcat = (const uint8 *)srcT; + const uint8 *srcab = (const uint8 *)srcB; + uint32 w16 = (w + 15) >> 4; + uint32 wr = w16 << 4; + + uint8 *elabuf = tempBuf; + uint8 *topbuf = elabuf + 10*wr; + uint8 *botbuf = topbuf + wr + 32; + + uint32 woffset = w & 15; + topbuf[13] = topbuf[14] = topbuf[15] = srcat[0]; + botbuf[13] = botbuf[14] = botbuf[15] = srcab[0]; + + for(uint32 x=0; x> 1); + srca += 4; + srcb += 4; + } while(--w4); + } + + void BlendScanLine_NELA_X8R8G8B8_scalar(void *dst, const void *srcT, const void *srcB, uint32 w, void *tempBuf) { + const uint32 *srcat = (const uint32 *)srcT; + const uint32 *srcab = (const uint32 *)srcB; + uint32 w4 = (w + 3) >> 2; + uint32 *elabuf = (uint32 *)tempBuf; + uint32 *topbuf = elabuf + 5*w4; + uint32 *botbuf = topbuf + w4 + 8; + + topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = srcat[0]; + botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = srcab[0]; + + for(uint32 x=0; x> 2; + uint32 *elabuf = (uint32 *)tempBuf; + uint32 *topbuf = elabuf + 5*w4; + uint32 *botbuf = topbuf + w4 + 8; + + topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = srcat[0]; + botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = srcab[0]; + + for(uint32 x=0; x> 4; + uint32 w4 = w16 * 4; + uint32 *elabuf = (uint32 *)tempBuf; + uint32 *topbuf = elabuf + 40*w16; + uint32 *botbuf = topbuf + w4 + 8; + + uint32 woffset = w & 15; + topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = (srcat[0] & 0xff) * 0x01010101; + botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = (srcab[0] & 0xff) * 0x01010101; + + for(uint32 x=0; x> 4; + __m128i *elabuf = tempBuf; + __m128i *topbuf = elabuf + 10*w16; + __m128i *botbuf = topbuf + w16 + 2; + + uint32 woffset = w & 15; + topbuf[0] = srcat[0]; + botbuf[0] = srcab[0]; + + for(uint32 x=0; x> 4; + vdfastvector > tempbuf((12 * w16 + 4) * 16); + void *elabuf = tempbuf.data(); + + if (!interpField2) + memcpy(dst, src, w16 << 4); + + int y0 = interpField2 ? 1 : 2; + for(uint32 y = y0; y < h - 1; y += 2) { + const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); + const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); + +#if defined(VD_CPU_X86) + if (MMX_enabled) + BlendScanLine_NELA_X8R8G8B8_MMX((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); + else +#endif + BlendScanLine_NELA_X8R8G8B8_scalar((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); + } + + if (interpField2) + memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w16 << 4); + } + + void InterpPlane_NELA(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, uint32 w, uint32 h, bool interpField2) { + uint32 w16 = (w + 15) >> 4; + vdfastvector > tempbuf((12 * w16 + 4) * 16); + void *elabuf = tempbuf.data(); + + if (!interpField2) + memcpy(dst, src, w16 << 4); + + int y0 = interpField2 ? 1 : 2; + if (SSE2_enabled) { + for(uint32 y = y0; y < h - 1; y += 2) { + const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); + const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); + + BlendScanLine_NELA_SSE2((char *)dst + dstpitch*y, srcat, srcab, w, (__m128i *)elabuf); + } + } +#if defined(VD_CPU_X86) + else if (MMX_enabled || ISSE_enabled) { + for(uint32 y = y0; y < h - 1; y += 2) { + const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); + const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); + + BlendScanLine_NELA_MMX_ISSE((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); + } + } +#endif + else { + for(uint32 y = y0; y < h - 1; y += 2) { + const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); + const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); + + BlendScanLine_NELA_scalar((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); + } + } + + if (interpField2) + memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w16 << 4); + } + + void Average_scalar(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { + uint32 w4 = w16 << 2; + do { + uint32 *dstv = (uint32 *)dst; + uint32 *src1v = (uint32 *)src1; + uint32 *src2v = (uint32 *)src2; + + for(uint32 i=0; i> 1); + } + + dst = (char *)dst + dstPitch; + src1 = (char *)src1 + srcPitch; + src2 = (char *)src2 + srcPitch; + } while(--h); + } + +#if defined(VD_CPU_X86) + void __declspec(naked) __cdecl Average_MMX(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { + static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; + static const __declspec(align(8)) uint64 xfeb = 0xfefefefefefefefe; + + __asm { + push ebp + push edi + push esi + push ebx + + mov esi, [esp+24+16] + mov eax, [esp+4+16] + shl esi, 4 + mov ecx, [esp+12+16] + mov edx, [esp+16+16] + mov ebp, [esp+20+16] + mov edi, [esp+8+16] + sub edi, esi + sub ebp, esi + + movq mm6, x7fb + movq mm7, xfeb + + mov esi, [esp+28+16] +yloop: + mov ebx, [esp+24+16] +mainRowLoop: + movq mm0, [ecx] + movq mm3, [ecx + 8] + movq mm1, mm0 + movq mm2, [edx] + movq mm4, mm3 + movq mm5, [edx + 8] + por mm1, mm2 + pxor mm0, mm2 + por mm4, mm5 + pxor mm3, mm5 + psrlq mm0, 1 + pand mm3, mm7 + pand mm0, mm6 + psrlq mm3, 1 + psubb mm1, mm0 + psubb mm4, mm3 + add ecx, 16 + movq [eax], mm1 + movq [eax+8], mm4 + add edx, 16 + add eax, 16 + dec ebx + jne mainRowLoop + + add eax, edi + add ecx, ebp + add edx, ebp + dec esi + jne yloop + + emms + pop ebx + pop esi + pop edi + pop ebp + ret + } + } + + void __declspec(naked) __cdecl Average_ISSE(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { + static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; + static const __declspec(align(8)) uint64 xfeb = 0xfefefefefefefefe; + + __asm { + push ebp + push edi + push esi + push ebx + + mov esi, [esp+24+16] + mov eax, [esp+4+16] + shl esi, 4 + mov ecx, [esp+12+16] + mov edx, [esp+16+16] + mov ebp, [esp+20+16] + mov edi, [esp+8+16] + sub edi, esi + sub ebp, esi + + movq mm6, x7fb + movq mm7, xfeb + + mov esi, [esp+28+16] +yloop: + mov ebx, [esp+24+16] +mainRowLoop: + movq mm0, [ecx] + movq mm1, [ecx + 8] + movq mm2, [edx] + movq mm3, [edx + 8] + pavgb mm0, mm2 + pavgb mm1, mm3 + movq [eax], mm0 + add ecx, 16 + add edx, 16 + movq [eax+8], mm1 + add eax, 16 + dec ebx + jne mainRowLoop + + add eax, edi + add ecx, ebp + add edx, ebp + dec esi + jne yloop + + emms + pop ebx + pop esi + pop edi + pop ebp + ret + } + } +#endif + +#if defined(VD_CPU_X86) || defined(VD_CPU_AMD64) + void Average_SSE2(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { + do { + __m128i *dstv = (__m128i *)dst; + __m128i *src1v = (__m128i *)src1; + __m128i *src2v = (__m128i *)src2; + + for(uint32 i=0; i> 2; + + uint32 y0 = interpField2 ? 1 : 2; + + if (!interpField2) + memcpy(dst, src, w * 4); + + if (h > y0) { + ASSERT(((UINT_PTR)dst & 0xF) == 0); + ASSERT((dstpitch & 0xF) == 0); + ASSERT(((UINT_PTR)src & 0xF) == 0); + ASSERT((srcpitch*(y0 - 1) & 0xF) == 0); + blend_func((char *)dst + dstpitch*y0, + dstpitch*2, + (const char *)src + srcpitch*(y0 - 1), + (const char *)src + srcpitch*(y0 + 1), + srcpitch*2, + (w + 3) >> 2, + (h - y0) >> 1); + } + + if (interpField2) + memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w*4); + +#ifdef _M_IX86 + if (MMX_enabled) + __asm emms +#endif + } + + void BlendPlane(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, uint32 w, uint32 h) { + void (*blend_func)(void *, const void *, uint32, ptrdiff_t); +#if defined(VD_CPU_X86) + if (SSE2_enabled && !(srcpitch % 16)) + blend_func = asm_blend_row_SSE2; + else + blend_func = ISSE_enabled ? asm_blend_row_ISSE : MMX_enabled ? asm_blend_row_MMX : asm_blend_row; +#else + blend_func = asm_blend_row_SSE2; +#endif + + w = (w + 3) >> 2; + + asm_blend_row_clipped(dst, src, w, srcpitch); + if (h-=2) + do { + dst = ((char *)dst + dstpitch); + + blend_func(dst, src, w, srcpitch); + + src = ((char *)src + srcpitch); + } while(--h); + + asm_blend_row_clipped((char *)dst + dstpitch, src, w, srcpitch); + +#ifdef _M_IX86 + if (MMX_enabled) + __asm emms +#endif + } +} + +void DeinterlaceELA_X8R8G8B8(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) +{ + topfield = !topfield; + + InterpPlane_NELA_X8R8G8B8(dst, dstpitch, src, srcpitch, w, h, topfield); +} + +void DeinterlaceELA(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) +{ + topfield = !topfield; + + InterpPlane_NELA(dst, dstpitch, src, srcpitch, w, h, topfield); +} + +void DeinterlaceBob(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) +{ + topfield = !topfield; + + InterpPlane_Bob(dst, dstpitch, src, srcpitch, w, h, topfield); +} + +void DeinterlaceBlend(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch) +{ + BlendPlane(dst, dstpitch, src, srcpitch, w, h); +} diff --git a/src/DSUtil/stdafx.cpp b/src/DSUtil/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/DSUtil/stdafx.cpp +++ b/src/DSUtil/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/DSUtil/stdafx.h b/src/DSUtil/stdafx.h index e7f7ebdba9e..b099e5c0006 100644 --- a/src/DSUtil/stdafx.h +++ b/src/DSUtil/stdafx.h @@ -1,43 +1,43 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "SharedInclude.h" -#include - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include - -#include -#include - -#include "BaseClasses/streams.h" -#include - -#include -#include +/* + * (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 . + * + */ + +#pragma once + +#include "SharedInclude.h" +#include + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include + +#include +#include + +#include "BaseClasses/streams.h" +#include + +#include +#include diff --git a/src/DSUtil/text.cpp b/src/DSUtil/text.cpp index 22384bd9b18..704a934d891 100644 --- a/src/DSUtil/text.cpp +++ b/src/DSUtil/text.cpp @@ -1,419 +1,419 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "text.h" -#include - -DWORD CharSetToCodePage(DWORD dwCharSet) -{ - if (dwCharSet == CP_UTF8) { - return CP_UTF8; - } - if (dwCharSet == CP_UTF7) { - return CP_UTF7; - } - CHARSETINFO cs; - ZeroMemory(&cs, sizeof(CHARSETINFO)); - ::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwCharSet, &cs, TCI_SRCCHARSET); - return cs.ciACP; -} - -CStringA ConvertMBCS(CStringA str, DWORD SrcCharSet, DWORD DstCharSet) -{ - WCHAR* utf16 = DEBUG_NEW WCHAR[str.GetLength() + 1]; - ZeroMemory(utf16, (str.GetLength() + 1)*sizeof(WCHAR)); - - CHAR* mbcs = DEBUG_NEW CHAR[str.GetLength() * 6 + 1]; - ZeroMemory(mbcs, str.GetLength() * 6 + 1); - - int len = MultiByteToWideChar( - CharSetToCodePage(SrcCharSet), - 0, - str, - -1, // null terminated string - utf16, - str.GetLength() + 1); - - len = WideCharToMultiByte( - CharSetToCodePage(DstCharSet), - 0, - utf16, - len, - mbcs, - str.GetLength() * 6, - nullptr, - nullptr); - - str = mbcs; - - delete [] utf16; - delete [] mbcs; - - return str; -} - -CStringA UrlEncode(const CStringA& strIn) -{ - CStringA strOut; - DWORD dwStrLen = 0, dwMaxLength = 0; - // Request the buffer size needed to encode the URL - AtlEscapeUrl(strIn, strOut.GetBuffer(), &dwStrLen, dwMaxLength, ATL_URL_ENCODE_PERCENT); - dwMaxLength = dwStrLen; - // Encode the URL - if (dwMaxLength > 0) { - if (AtlEscapeUrl(strIn, strOut.GetBuffer(int(dwMaxLength)), &dwStrLen, dwMaxLength, ATL_URL_ENCODE_PERCENT)) { - dwStrLen--; - } else { - dwStrLen = 0; - } - strOut.ReleaseBuffer(dwStrLen); - } - - return strOut; -} - -CStringA EscapeJSONString(const CStringA& str) -{ - CStringA escapedString = str; - // replace all of JSON's reserved characters with their escaped - // equivalents. - escapedString.Replace("\"", "\\\""); - escapedString.Replace("\\", "\\\\"); - escapedString.Replace("/", "\\/"); - escapedString.Replace("\b", "\\b"); - escapedString.Replace("\f", "\\f"); - escapedString.Replace("\n", "\\n"); - escapedString.Replace("\r", "\\r"); - escapedString.Replace("\t", "\\t"); - return escapedString; -} - -CStringA UrlDecode(const CStringA& strIn) -{ - CStringA strOut; - DWORD dwStrLen = 0, dwMaxLength = strIn.GetLength() + 1; - - if (AtlUnescapeUrl(strIn, strOut.GetBuffer(int(dwMaxLength)), &dwStrLen, dwMaxLength)) { - dwStrLen--; - } else { - dwStrLen = 0; - } - strOut.ReleaseBuffer(dwStrLen); - - return strOut; -} - -CStringW UrlDecodeWithUTF8(CStringW in, bool keepEncodedSpecialChar) { - TCHAR t[100]; - DWORD bufSize = _countof(t); - CString tem(in); - tem.Replace(_T("+"), _T(" ")); //UrlUnescape does not deal with '+' properly - if (keepEncodedSpecialChar) { - tem.Replace(_T("%25"), _T("%2525")); // % - tem.Replace(_T("%3A"), _T("%253A")); - tem.Replace(_T("%3a"), _T("%253A")); - tem.Replace(_T("%2F"), _T("%252F")); - tem.Replace(_T("%2f"), _T("%252F")); - tem.Replace(_T("%3F"), _T("%253F")); - tem.Replace(_T("%3f"), _T("%253F")); - tem.Replace(_T("%23"), _T("%2523")); - tem.Replace(_T("%5B"), _T("%255B")); - tem.Replace(_T("%5b"), _T("%255B")); - tem.Replace(_T("%5D"), _T("%255D")); - tem.Replace(_T("%5d"), _T("%255D")); - tem.Replace(_T("%40"), _T("%2540")); - tem.Replace(_T("%21"), _T("%2521")); - tem.Replace(_T("%24"), _T("%2524")); - tem.Replace(_T("%26"), _T("%2526")); - tem.Replace(_T("%27"), _T("%2527")); - tem.Replace(_T("%28"), _T("%2528")); - tem.Replace(_T("%29"), _T("%2529")); - tem.Replace(_T("%2A"), _T("%252A")); - tem.Replace(_T("%2a"), _T("%252A")); - tem.Replace(_T("%2B"), _T("%252B")); - tem.Replace(_T("%2b"), _T("%252B")); - tem.Replace(_T("%2C"), _T("%252C")); - tem.Replace(_T("%2c"), _T("%252C")); - tem.Replace(_T("%3B"), _T("%253B")); - tem.Replace(_T("%3b"), _T("%253B")); - tem.Replace(_T("%3D"), _T("%253D")); - tem.Replace(_T("%3d"), _T("%253D")); - tem.Replace(_T("%20"), _T("%2520")); - } - HRESULT result = UrlUnescape(tem.GetBuffer(), t, &bufSize, URL_ESCAPE_AS_UTF8); //URL_ESCAPE_AS_UTF8 will work as URL_UNESCAPE_AS_UTF8 on windows 8+, otherwise it will just ignore utf-8 - - if (result == E_POINTER) { - std::shared_ptr buffer(new TCHAR[bufSize]); - if (S_OK == UrlUnescape(tem.GetBuffer(), buffer.get(), &bufSize, URL_ESCAPE_AS_UTF8)) { - CString urlDecoded(buffer.get()); - return urlDecoded; - } - } - else { - CString urlDecoded(t); - return urlDecoded; - } - return in; -} - -CStringW URLGetHostName(const CStringW in) { - CStringW t(in); - if (t.Find(_T("://")) > 1) { - t = t.Mid(t.Find(_T("://")) + 3); - } - if (t.Left(4) == _T("www.")) { - t = t.Mid(4); - } - if (t.Find(_T("/")) > 0) { - t = t.Left(t.Find(_T("/"))); - } - return UrlDecodeWithUTF8(t); -} - -CStringW ShortenURL(const CStringW url, int targetLength, bool returnHostnameIfTooLong) { - CStringW t(url); - if (t.Find(_T("://")) > 1) { - t = t.Mid(t.Find(_T("://")) + 3); - } - if (t.Left(4) == _T("www.")) { - t = t.Mid(4); - } - while (t.GetLength() > targetLength) { - int position = t.ReverseFind('#'); - if (position > 0) { - t = t.Left(position); - continue; - } - position = t.ReverseFind('&'); - if (position > 0) { - t = t.Left(position); - continue; - } - position = t.ReverseFind('?'); - if (position > 0) { - t = t.Left(position); - break; - } - break; - } - t = UrlDecodeWithUTF8(t); - if (t.GetLength() > targetLength && returnHostnameIfTooLong) return URLGetHostName(url); - return t; -} - -CString ExtractTag(CString tag, CMapStringToString& attribs, bool& fClosing) -{ - tag.Trim(); - attribs.RemoveAll(); - - fClosing = !tag.IsEmpty() ? tag[0] == '/' : false; - tag.TrimLeft('/'); - - int i = tag.Find(' '); - if (i < 0) { - i = tag.GetLength(); - } - CString type = tag.Left(i).MakeLower(); - tag = tag.Mid(i).Trim(); - - while ((i = tag.Find('=')) > 0) { - CString attrib = tag.Left(i).Trim().MakeLower(); - tag = tag.Mid(i + 1); - for (i = 0; i < tag.GetLength() && _istspace(tag[i]); i++) { - ; - } - if (i < tag.GetLength()) { - tag = tag.Mid(i); - } else { - tag.Empty(); - } - if (!tag.IsEmpty() && tag[0] == '\"') { - tag = tag.Mid(1); - i = tag.Find('\"'); - } else { - i = tag.Find(' '); - } - if (i < 0) { - i = tag.GetLength(); - } - CString param = tag.Left(i).Trim(); - if (!param.IsEmpty()) { - attribs[attrib] = param; - } - if (i + 1 < tag.GetLength()) { - tag = tag.Mid(i + 1); - } else { - tag.Empty(); - } - } - - return type; -} - -CStringA HtmlSpecialChars(CStringA str, bool bQuotes /*= false*/) -{ - str.Replace("&", "&"); - str.Replace("\"", """); - if (bQuotes) { - str.Replace("\'", "'"); - } - str.Replace("<", "<"); - str.Replace(">", ">"); - - return str; -} - -CStringA HtmlSpecialCharsDecode(CStringA str) -{ - str.Replace("&", "&"); - str.Replace(""", "\""); - str.Replace("'", "\'"); - str.Replace("<", "<"); - str.Replace(">", ">"); - str.Replace("’", "'"); - - return str; -} - -CAtlList& MakeLower(CAtlList& sl) -{ - POSITION pos = sl.GetHeadPosition(); - while (pos) { - sl.GetNext(pos).MakeLower(); - } - return sl; -} - -CAtlList& MakeUpper(CAtlList& sl) -{ - POSITION pos = sl.GetHeadPosition(); - while (pos) { - sl.GetNext(pos).MakeUpper(); - } - return sl; -} - -CString FormatNumber(CString szNumber, bool bNoFractionalDigits /*= true*/) -{ - CString ret; - - int nChars = GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNumber, nullptr, nullptr, 0); - GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNumber, nullptr, ret.GetBuffer(nChars), nChars); - ret.ReleaseBuffer(); - - if (bNoFractionalDigits) { - TCHAR szNumberFractionalDigits[2] = {0}; - GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, szNumberFractionalDigits, _countof(szNumberFractionalDigits)); - int nNumberFractionalDigits = _tcstol(szNumberFractionalDigits, nullptr, 10); - if (nNumberFractionalDigits) { - ret.Truncate(ret.GetLength() - nNumberFractionalDigits - 1); - } - } - - return ret; -} - -void GetLocaleString(LCID lcid, LCTYPE type, CString& output) { - int len = GetLocaleInfo(lcid, type, output.GetBuffer(256), 256); - output.ReleaseBufferSetLength(std::max(len - 1, 0)); -} - -int LastIndexOfCString(const CString& text, const CString& pattern) { - int found = -1; - int next_pos = 0; - while (true) { - next_pos = text.Find(pattern, next_pos); - if (next_pos > found) { - found = next_pos; - next_pos = next_pos + pattern.GetLength(); - } else { - return found; - } - } -} - -bool IsNameSimilar(const CString& title, const CString& fileName) { - if (fileName.Find(title.Left(25)) > -1) return true; - return false; -} - -CStringW ToUnicode(CStringW str, DWORD CharSet) { - CStringW ret; - DWORD cp = CharSetToCodePage(CharSet); - - for (int i = 0, j = str.GetLength(); i < j; i++) { - WCHAR wc = str.GetAt(i); - char c = wc & 0xff; - - if (IsDBCSLeadByteEx(cp, (BYTE)wc)) { - i++; - - if (i < j) { - char cc[2]; - cc[0] = c; - cc[1] = (char)str.GetAt(i); - - MultiByteToWideChar(cp, 0, cc, 2, &wc, 1); - } - } else { - MultiByteToWideChar(cp, 0, &c, 1, &wc, 1); - } - - ret += wc; - } - - return ret; -} - -void AppendWithDelimiter(CStringW &output, CStringW append, wchar_t delim) { - if (!append.IsEmpty()) { - if (!output.IsEmpty()) { - output.AppendChar(delim); - } - output.Append(append); - } -} - -bool EndsWith(CStringW str, CStringW suffix) { - const int str_len = str.GetLength(); - const int suffix_len = suffix.GetLength(); - return str_len >= suffix_len && 0 == str.Right(suffix_len).Compare(suffix); -} - -bool StartsWith(CStringW str, CStringW prefix) { - const int str_len = str.GetLength(); - const int prefix_len = prefix.GetLength(); - return str_len >= prefix_len && 0 == str.Left(prefix_len).Compare(prefix); -} - -bool EndsWithNoCase(CStringW str, CStringW suffix) { - const int str_len = str.GetLength(); - const int suffix_len = suffix.GetLength(); - return str_len >= suffix_len && 0 == str.Right(suffix_len).CompareNoCase(suffix); -} - -bool StartsWithNoCase(CStringW str, CStringW prefix) { - const int str_len = str.GetLength(); - const int prefix_len = prefix.GetLength(); - return str_len >= prefix_len && 0 == str.Left(prefix_len).CompareNoCase(prefix); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "text.h" +#include + +DWORD CharSetToCodePage(DWORD dwCharSet) +{ + if (dwCharSet == CP_UTF8) { + return CP_UTF8; + } + if (dwCharSet == CP_UTF7) { + return CP_UTF7; + } + CHARSETINFO cs; + ZeroMemory(&cs, sizeof(CHARSETINFO)); + ::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwCharSet, &cs, TCI_SRCCHARSET); + return cs.ciACP; +} + +CStringA ConvertMBCS(CStringA str, DWORD SrcCharSet, DWORD DstCharSet) +{ + WCHAR* utf16 = DEBUG_NEW WCHAR[str.GetLength() + 1]; + ZeroMemory(utf16, (str.GetLength() + 1)*sizeof(WCHAR)); + + CHAR* mbcs = DEBUG_NEW CHAR[str.GetLength() * 6 + 1]; + ZeroMemory(mbcs, str.GetLength() * 6 + 1); + + int len = MultiByteToWideChar( + CharSetToCodePage(SrcCharSet), + 0, + str, + -1, // null terminated string + utf16, + str.GetLength() + 1); + + len = WideCharToMultiByte( + CharSetToCodePage(DstCharSet), + 0, + utf16, + len, + mbcs, + str.GetLength() * 6, + nullptr, + nullptr); + + str = mbcs; + + delete [] utf16; + delete [] mbcs; + + return str; +} + +CStringA UrlEncode(const CStringA& strIn) +{ + CStringA strOut; + DWORD dwStrLen = 0, dwMaxLength = 0; + // Request the buffer size needed to encode the URL + AtlEscapeUrl(strIn, strOut.GetBuffer(), &dwStrLen, dwMaxLength, ATL_URL_ENCODE_PERCENT); + dwMaxLength = dwStrLen; + // Encode the URL + if (dwMaxLength > 0) { + if (AtlEscapeUrl(strIn, strOut.GetBuffer(int(dwMaxLength)), &dwStrLen, dwMaxLength, ATL_URL_ENCODE_PERCENT)) { + dwStrLen--; + } else { + dwStrLen = 0; + } + strOut.ReleaseBuffer(dwStrLen); + } + + return strOut; +} + +CStringA EscapeJSONString(const CStringA& str) +{ + CStringA escapedString = str; + // replace all of JSON's reserved characters with their escaped + // equivalents. + escapedString.Replace("\"", "\\\""); + escapedString.Replace("\\", "\\\\"); + escapedString.Replace("/", "\\/"); + escapedString.Replace("\b", "\\b"); + escapedString.Replace("\f", "\\f"); + escapedString.Replace("\n", "\\n"); + escapedString.Replace("\r", "\\r"); + escapedString.Replace("\t", "\\t"); + return escapedString; +} + +CStringA UrlDecode(const CStringA& strIn) +{ + CStringA strOut; + DWORD dwStrLen = 0, dwMaxLength = strIn.GetLength() + 1; + + if (AtlUnescapeUrl(strIn, strOut.GetBuffer(int(dwMaxLength)), &dwStrLen, dwMaxLength)) { + dwStrLen--; + } else { + dwStrLen = 0; + } + strOut.ReleaseBuffer(dwStrLen); + + return strOut; +} + +CStringW UrlDecodeWithUTF8(CStringW in, bool keepEncodedSpecialChar) { + TCHAR t[100]; + DWORD bufSize = _countof(t); + CString tem(in); + tem.Replace(_T("+"), _T(" ")); //UrlUnescape does not deal with '+' properly + if (keepEncodedSpecialChar) { + tem.Replace(_T("%25"), _T("%2525")); // % + tem.Replace(_T("%3A"), _T("%253A")); + tem.Replace(_T("%3a"), _T("%253A")); + tem.Replace(_T("%2F"), _T("%252F")); + tem.Replace(_T("%2f"), _T("%252F")); + tem.Replace(_T("%3F"), _T("%253F")); + tem.Replace(_T("%3f"), _T("%253F")); + tem.Replace(_T("%23"), _T("%2523")); + tem.Replace(_T("%5B"), _T("%255B")); + tem.Replace(_T("%5b"), _T("%255B")); + tem.Replace(_T("%5D"), _T("%255D")); + tem.Replace(_T("%5d"), _T("%255D")); + tem.Replace(_T("%40"), _T("%2540")); + tem.Replace(_T("%21"), _T("%2521")); + tem.Replace(_T("%24"), _T("%2524")); + tem.Replace(_T("%26"), _T("%2526")); + tem.Replace(_T("%27"), _T("%2527")); + tem.Replace(_T("%28"), _T("%2528")); + tem.Replace(_T("%29"), _T("%2529")); + tem.Replace(_T("%2A"), _T("%252A")); + tem.Replace(_T("%2a"), _T("%252A")); + tem.Replace(_T("%2B"), _T("%252B")); + tem.Replace(_T("%2b"), _T("%252B")); + tem.Replace(_T("%2C"), _T("%252C")); + tem.Replace(_T("%2c"), _T("%252C")); + tem.Replace(_T("%3B"), _T("%253B")); + tem.Replace(_T("%3b"), _T("%253B")); + tem.Replace(_T("%3D"), _T("%253D")); + tem.Replace(_T("%3d"), _T("%253D")); + tem.Replace(_T("%20"), _T("%2520")); + } + HRESULT result = UrlUnescape(tem.GetBuffer(), t, &bufSize, URL_ESCAPE_AS_UTF8); //URL_ESCAPE_AS_UTF8 will work as URL_UNESCAPE_AS_UTF8 on windows 8+, otherwise it will just ignore utf-8 + + if (result == E_POINTER) { + std::shared_ptr buffer(new TCHAR[bufSize]); + if (S_OK == UrlUnescape(tem.GetBuffer(), buffer.get(), &bufSize, URL_ESCAPE_AS_UTF8)) { + CString urlDecoded(buffer.get()); + return urlDecoded; + } + } + else { + CString urlDecoded(t); + return urlDecoded; + } + return in; +} + +CStringW URLGetHostName(const CStringW in) { + CStringW t(in); + if (t.Find(_T("://")) > 1) { + t = t.Mid(t.Find(_T("://")) + 3); + } + if (t.Left(4) == _T("www.")) { + t = t.Mid(4); + } + if (t.Find(_T("/")) > 0) { + t = t.Left(t.Find(_T("/"))); + } + return UrlDecodeWithUTF8(t); +} + +CStringW ShortenURL(const CStringW url, int targetLength, bool returnHostnameIfTooLong) { + CStringW t(url); + if (t.Find(_T("://")) > 1) { + t = t.Mid(t.Find(_T("://")) + 3); + } + if (t.Left(4) == _T("www.")) { + t = t.Mid(4); + } + while (t.GetLength() > targetLength) { + int position = t.ReverseFind('#'); + if (position > 0) { + t = t.Left(position); + continue; + } + position = t.ReverseFind('&'); + if (position > 0) { + t = t.Left(position); + continue; + } + position = t.ReverseFind('?'); + if (position > 0) { + t = t.Left(position); + break; + } + break; + } + t = UrlDecodeWithUTF8(t); + if (t.GetLength() > targetLength && returnHostnameIfTooLong) return URLGetHostName(url); + return t; +} + +CString ExtractTag(CString tag, CMapStringToString& attribs, bool& fClosing) +{ + tag.Trim(); + attribs.RemoveAll(); + + fClosing = !tag.IsEmpty() ? tag[0] == '/' : false; + tag.TrimLeft('/'); + + int i = tag.Find(' '); + if (i < 0) { + i = tag.GetLength(); + } + CString type = tag.Left(i).MakeLower(); + tag = tag.Mid(i).Trim(); + + while ((i = tag.Find('=')) > 0) { + CString attrib = tag.Left(i).Trim().MakeLower(); + tag = tag.Mid(i + 1); + for (i = 0; i < tag.GetLength() && _istspace(tag[i]); i++) { + ; + } + if (i < tag.GetLength()) { + tag = tag.Mid(i); + } else { + tag.Empty(); + } + if (!tag.IsEmpty() && tag[0] == '\"') { + tag = tag.Mid(1); + i = tag.Find('\"'); + } else { + i = tag.Find(' '); + } + if (i < 0) { + i = tag.GetLength(); + } + CString param = tag.Left(i).Trim(); + if (!param.IsEmpty()) { + attribs[attrib] = param; + } + if (i + 1 < tag.GetLength()) { + tag = tag.Mid(i + 1); + } else { + tag.Empty(); + } + } + + return type; +} + +CStringA HtmlSpecialChars(CStringA str, bool bQuotes /*= false*/) +{ + str.Replace("&", "&"); + str.Replace("\"", """); + if (bQuotes) { + str.Replace("\'", "'"); + } + str.Replace("<", "<"); + str.Replace(">", ">"); + + return str; +} + +CStringA HtmlSpecialCharsDecode(CStringA str) +{ + str.Replace("&", "&"); + str.Replace(""", "\""); + str.Replace("'", "\'"); + str.Replace("<", "<"); + str.Replace(">", ">"); + str.Replace("’", "'"); + + return str; +} + +CAtlList& MakeLower(CAtlList& sl) +{ + POSITION pos = sl.GetHeadPosition(); + while (pos) { + sl.GetNext(pos).MakeLower(); + } + return sl; +} + +CAtlList& MakeUpper(CAtlList& sl) +{ + POSITION pos = sl.GetHeadPosition(); + while (pos) { + sl.GetNext(pos).MakeUpper(); + } + return sl; +} + +CString FormatNumber(CString szNumber, bool bNoFractionalDigits /*= true*/) +{ + CString ret; + + int nChars = GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNumber, nullptr, nullptr, 0); + GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNumber, nullptr, ret.GetBuffer(nChars), nChars); + ret.ReleaseBuffer(); + + if (bNoFractionalDigits) { + TCHAR szNumberFractionalDigits[2] = {0}; + GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, szNumberFractionalDigits, _countof(szNumberFractionalDigits)); + int nNumberFractionalDigits = _tcstol(szNumberFractionalDigits, nullptr, 10); + if (nNumberFractionalDigits) { + ret.Truncate(ret.GetLength() - nNumberFractionalDigits - 1); + } + } + + return ret; +} + +void GetLocaleString(LCID lcid, LCTYPE type, CString& output) { + int len = GetLocaleInfo(lcid, type, output.GetBuffer(256), 256); + output.ReleaseBufferSetLength(std::max(len - 1, 0)); +} + +int LastIndexOfCString(const CString& text, const CString& pattern) { + int found = -1; + int next_pos = 0; + while (true) { + next_pos = text.Find(pattern, next_pos); + if (next_pos > found) { + found = next_pos; + next_pos = next_pos + pattern.GetLength(); + } else { + return found; + } + } +} + +bool IsNameSimilar(const CString& title, const CString& fileName) { + if (fileName.Find(title.Left(25)) > -1) return true; + return false; +} + +CStringW ToUnicode(CStringW str, DWORD CharSet) { + CStringW ret; + DWORD cp = CharSetToCodePage(CharSet); + + for (int i = 0, j = str.GetLength(); i < j; i++) { + WCHAR wc = str.GetAt(i); + char c = wc & 0xff; + + if (IsDBCSLeadByteEx(cp, (BYTE)wc)) { + i++; + + if (i < j) { + char cc[2]; + cc[0] = c; + cc[1] = (char)str.GetAt(i); + + MultiByteToWideChar(cp, 0, cc, 2, &wc, 1); + } + } else { + MultiByteToWideChar(cp, 0, &c, 1, &wc, 1); + } + + ret += wc; + } + + return ret; +} + +void AppendWithDelimiter(CStringW &output, CStringW append, wchar_t delim) { + if (!append.IsEmpty()) { + if (!output.IsEmpty()) { + output.AppendChar(delim); + } + output.Append(append); + } +} + +bool EndsWith(CStringW str, CStringW suffix) { + const int str_len = str.GetLength(); + const int suffix_len = suffix.GetLength(); + return str_len >= suffix_len && 0 == str.Right(suffix_len).Compare(suffix); +} + +bool StartsWith(CStringW str, CStringW prefix) { + const int str_len = str.GetLength(); + const int prefix_len = prefix.GetLength(); + return str_len >= prefix_len && 0 == str.Left(prefix_len).Compare(prefix); +} + +bool EndsWithNoCase(CStringW str, CStringW suffix) { + const int str_len = str.GetLength(); + const int suffix_len = suffix.GetLength(); + return str_len >= suffix_len && 0 == str.Right(suffix_len).CompareNoCase(suffix); +} + +bool StartsWithNoCase(CStringW str, CStringW prefix) { + const int str_len = str.GetLength(); + const int prefix_len = prefix.GetLength(); + return str_len >= prefix_len && 0 == str.Left(prefix_len).CompareNoCase(prefix); +} diff --git a/src/DSUtil/text.h b/src/DSUtil/text.h index f02682486ce..670d02de7a2 100644 --- a/src/DSUtil/text.h +++ b/src/DSUtil/text.h @@ -1,255 +1,255 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include -#include -#include - -template -T Explode(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) -{ - sl.RemoveAll(); - - for (int i = 0, j = 0; ; i = j + 1) { - j = str.Find(sep, i); - - if (j < 0 || sl.GetCount() == limit - 1) { - sl.AddTail(str.Mid(i).Trim()); - break; - } else { - sl.AddTail(str.Mid(i, j - i).Trim()); - } - } - - return sl.GetHead(); -} - -template -T ExplodeNoTrim(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) -{ - sl.RemoveAll(); - - for (int i = 0, j = 0; ; i = j + 1) { - j = str.Find(sep, i); - - if (j < 0 || sl.GetCount() == limit - 1) { - sl.AddTail(str.Mid(i)); - break; - } else { - sl.AddTail(str.Mid(i, j - i)); - } - } - - return sl.GetHead(); -} - -template -T ExplodeMin(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) -{ - Explode(str, sl, sep, limit); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - POSITION tmp = pos; - if (sl.GetNext(pos).IsEmpty()) { - sl.RemoveAt(tmp); - } - } - if (sl.IsEmpty()) { - sl.AddTail(T()); // eh - } - - return sl.GetHead(); -} - -template -T ExplodeEsc(T str, CAtlList& sl, SEP sep, size_t limit = 0, SEP esc = _T('\\')) -{ - sl.RemoveAll(); - - int split = 0; - for (int i = 0, j = 0; ; i = j + 1) { - j = str.Find(sep, i); - if (j < 0) { - break; - } - - // Skip this separator if it is escaped - if (j > 0 && str.GetAt(j - 1) == esc) { - // Delete the escape character - str.Delete(j - 1); - continue; - } - - if (sl.GetCount() < limit - 1) { - sl.AddTail(str.Mid(split, j - split).Trim()); - - // Save new splitting position - split = j + 1; - } - } - sl.AddTail(str.Mid(split).Trim()); - - return sl.GetHead(); -} - -template -std::enable_if_t<(std::is_same_v || std::is_same_v), T> -ExplodeEsc(T str, std::list& sl, SEP sep, size_t limit = 0, SEP esc = '\\') { - sl.clear(); - if (str.IsEmpty()) { - return T(); - } - - int split = 0; - for (int i = 0, j = 0; ; i = j + 1) { - j = str.Find(sep, i); - if (j < 0) { - break; - } - - // Skip this separator if it is escaped - if (j > 0 && str.GetAt(j - 1) == esc) { - // Delete the escape character - str.Delete(j - 1); - continue; - } - - if (sl.size() < limit - 1) { - sl.push_back(str.Mid(split, j - split).Trim()); - - // Save new splitting position - split = j + 1; - } - } - sl.push_back(str.Mid(split).Trim()); - - return sl.front(); -} - -template -T Implode(const CAtlList& sl, SEP sep) -{ - T ret; - POSITION pos = sl.GetHeadPosition(); - while (pos) { - ret += sl.GetNext(pos); - if (pos) { - ret += sep; - } - } - return ret; -} - -template -T ImplodeEsc(const CAtlList& sl, SEP sep, SEP esc = _T('\\')) -{ - T ret; - T escsep = T(esc) + T(sep); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - T str = sl.GetNext(pos); - str.Replace(T(sep), escsep); - ret += str; - if (pos) { - ret += sep; - } - } - return ret; -} - -extern CString ExtractTag(CString tag, CMapStringToString& attribs, bool& fClosing); -extern CStringA ConvertMBCS(CStringA str, DWORD SrcCharSet, DWORD DstCharSet); -extern CStringA UrlEncode(const CStringA& strIn); -/** - * @brief Escape the characters that JSON reserves as special. - * @param str The string that needs escaping. - * @return The input string with the special characters escaped. - */ -extern CStringA EscapeJSONString(const CStringA& str); -extern CStringA UrlDecode(const CStringA& strIn); -extern CStringW UrlDecodeWithUTF8(const CStringW in, bool keepEncodedSpecialChar = false); -extern CStringW URLGetHostName(const CStringW in); -extern CStringW ShortenURL(const CStringW url, int targetLength = 100, bool returnHostnameIfTooLong = false); -extern CStringA HtmlSpecialChars(CStringA str, bool bQuotes = false); -extern CStringA HtmlSpecialCharsDecode(CStringA str); -extern DWORD CharSetToCodePage(DWORD dwCharSet); -extern CAtlList& MakeLower(CAtlList& sl); -extern CAtlList& MakeUpper(CAtlList& sl); -extern int LastIndexOfCString(const CString& text, const CString& pattern); -extern bool IsNameSimilar(const CString& title, const CString& fileName); -extern CStringW ToUnicode(CStringW str, DWORD CharSet); -extern void AppendWithDelimiter(CStringW& output, CStringW append, wchar_t delim = L' '); -extern bool EndsWith(CStringW str, CStringW suffix); -extern bool StartsWith(CStringW str, CStringW prefix); -extern bool EndsWithNoCase(CStringW str, CStringW suffix); -extern bool StartsWithNoCase(CStringW str, CStringW prefix); -extern CString FormatNumber(CString szNumber, bool bNoFractionalDigits = true); -extern void GetLocaleString(LCID lcid, LCTYPE type, CString& output); - -template -T& FastTrimRight(T& str) -{ - if (!str.IsEmpty()) { - typename T::PCXSTR szStart = str; - typename T::PCXSTR szEnd = szStart + str.GetLength() - 1; - typename T::PCXSTR szCur = szEnd; - for (; szCur >= szStart; szCur--) { - if (!T::StrTraits::IsSpace(*szCur) || *szCur == 133) { // allow ellipsis character - break; - } - } - - if (szCur != szEnd) { - str.Truncate(int(szCur - szStart + 1)); - } - } - - return str; -} - -template -T& FastTrim(T& str) -{ - return FastTrimRight(str).TrimLeft(); -} - -template -int FindOneOf(const T& str, typename T::PCXSTR pszCharSet, int iStart) throw() -{ - ATLASSERT(AtlIsValidString(pszCharSet)); - ATLASSERT(iStart >= 0); - - if (iStart < 0 || iStart >= str.GetLength()) { - return -1; - } - - typename T::PCXSTR psz = T::StrTraits::StringScanSet(str.GetString() + iStart, pszCharSet); - return ((psz == NULL) ? -1 : int(psz - str.GetString())); -} - -template -CString NumToCString(T num) -{ - static_assert(std::numeric_limits::is_specialized, "NumToCString can be used only for numeric types."); - return std::to_string(num).c_str(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include +#include +#include + +template +T Explode(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) +{ + sl.RemoveAll(); + + for (int i = 0, j = 0; ; i = j + 1) { + j = str.Find(sep, i); + + if (j < 0 || sl.GetCount() == limit - 1) { + sl.AddTail(str.Mid(i).Trim()); + break; + } else { + sl.AddTail(str.Mid(i, j - i).Trim()); + } + } + + return sl.GetHead(); +} + +template +T ExplodeNoTrim(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) +{ + sl.RemoveAll(); + + for (int i = 0, j = 0; ; i = j + 1) { + j = str.Find(sep, i); + + if (j < 0 || sl.GetCount() == limit - 1) { + sl.AddTail(str.Mid(i)); + break; + } else { + sl.AddTail(str.Mid(i, j - i)); + } + } + + return sl.GetHead(); +} + +template +T ExplodeMin(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) +{ + Explode(str, sl, sep, limit); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + POSITION tmp = pos; + if (sl.GetNext(pos).IsEmpty()) { + sl.RemoveAt(tmp); + } + } + if (sl.IsEmpty()) { + sl.AddTail(T()); // eh + } + + return sl.GetHead(); +} + +template +T ExplodeEsc(T str, CAtlList& sl, SEP sep, size_t limit = 0, SEP esc = _T('\\')) +{ + sl.RemoveAll(); + + int split = 0; + for (int i = 0, j = 0; ; i = j + 1) { + j = str.Find(sep, i); + if (j < 0) { + break; + } + + // Skip this separator if it is escaped + if (j > 0 && str.GetAt(j - 1) == esc) { + // Delete the escape character + str.Delete(j - 1); + continue; + } + + if (sl.GetCount() < limit - 1) { + sl.AddTail(str.Mid(split, j - split).Trim()); + + // Save new splitting position + split = j + 1; + } + } + sl.AddTail(str.Mid(split).Trim()); + + return sl.GetHead(); +} + +template +std::enable_if_t<(std::is_same_v || std::is_same_v), T> +ExplodeEsc(T str, std::list& sl, SEP sep, size_t limit = 0, SEP esc = '\\') { + sl.clear(); + if (str.IsEmpty()) { + return T(); + } + + int split = 0; + for (int i = 0, j = 0; ; i = j + 1) { + j = str.Find(sep, i); + if (j < 0) { + break; + } + + // Skip this separator if it is escaped + if (j > 0 && str.GetAt(j - 1) == esc) { + // Delete the escape character + str.Delete(j - 1); + continue; + } + + if (sl.size() < limit - 1) { + sl.push_back(str.Mid(split, j - split).Trim()); + + // Save new splitting position + split = j + 1; + } + } + sl.push_back(str.Mid(split).Trim()); + + return sl.front(); +} + +template +T Implode(const CAtlList& sl, SEP sep) +{ + T ret; + POSITION pos = sl.GetHeadPosition(); + while (pos) { + ret += sl.GetNext(pos); + if (pos) { + ret += sep; + } + } + return ret; +} + +template +T ImplodeEsc(const CAtlList& sl, SEP sep, SEP esc = _T('\\')) +{ + T ret; + T escsep = T(esc) + T(sep); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + T str = sl.GetNext(pos); + str.Replace(T(sep), escsep); + ret += str; + if (pos) { + ret += sep; + } + } + return ret; +} + +extern CString ExtractTag(CString tag, CMapStringToString& attribs, bool& fClosing); +extern CStringA ConvertMBCS(CStringA str, DWORD SrcCharSet, DWORD DstCharSet); +extern CStringA UrlEncode(const CStringA& strIn); +/** + * @brief Escape the characters that JSON reserves as special. + * @param str The string that needs escaping. + * @return The input string with the special characters escaped. + */ +extern CStringA EscapeJSONString(const CStringA& str); +extern CStringA UrlDecode(const CStringA& strIn); +extern CStringW UrlDecodeWithUTF8(const CStringW in, bool keepEncodedSpecialChar = false); +extern CStringW URLGetHostName(const CStringW in); +extern CStringW ShortenURL(const CStringW url, int targetLength = 100, bool returnHostnameIfTooLong = false); +extern CStringA HtmlSpecialChars(CStringA str, bool bQuotes = false); +extern CStringA HtmlSpecialCharsDecode(CStringA str); +extern DWORD CharSetToCodePage(DWORD dwCharSet); +extern CAtlList& MakeLower(CAtlList& sl); +extern CAtlList& MakeUpper(CAtlList& sl); +extern int LastIndexOfCString(const CString& text, const CString& pattern); +extern bool IsNameSimilar(const CString& title, const CString& fileName); +extern CStringW ToUnicode(CStringW str, DWORD CharSet); +extern void AppendWithDelimiter(CStringW& output, CStringW append, wchar_t delim = L' '); +extern bool EndsWith(CStringW str, CStringW suffix); +extern bool StartsWith(CStringW str, CStringW prefix); +extern bool EndsWithNoCase(CStringW str, CStringW suffix); +extern bool StartsWithNoCase(CStringW str, CStringW prefix); +extern CString FormatNumber(CString szNumber, bool bNoFractionalDigits = true); +extern void GetLocaleString(LCID lcid, LCTYPE type, CString& output); + +template +T& FastTrimRight(T& str) +{ + if (!str.IsEmpty()) { + typename T::PCXSTR szStart = str; + typename T::PCXSTR szEnd = szStart + str.GetLength() - 1; + typename T::PCXSTR szCur = szEnd; + for (; szCur >= szStart; szCur--) { + if (!T::StrTraits::IsSpace(*szCur) || *szCur == 133) { // allow ellipsis character + break; + } + } + + if (szCur != szEnd) { + str.Truncate(int(szCur - szStart + 1)); + } + } + + return str; +} + +template +T& FastTrim(T& str) +{ + return FastTrimRight(str).TrimLeft(); +} + +template +int FindOneOf(const T& str, typename T::PCXSTR pszCharSet, int iStart) throw() +{ + ATLASSERT(AtlIsValidString(pszCharSet)); + ATLASSERT(iStart >= 0); + + if (iStart < 0 || iStart >= str.GetLength()) { + return -1; + } + + typename T::PCXSTR psz = T::StrTraits::StringScanSet(str.GetString() + iStart, pszCharSet); + return ((psz == NULL) ? -1 : int(psz - str.GetString())); +} + +template +CString NumToCString(T num) +{ + static_assert(std::numeric_limits::is_specialized, "NumToCString can be used only for numeric types."); + return std::to_string(num).c_str(); +} diff --git a/src/DSUtil/vd.cpp b/src/DSUtil/vd.cpp index 6055c609b4d..388bf3dccdb 100644 --- a/src/DSUtil/vd.cpp +++ b/src/DSUtil/vd.cpp @@ -1,392 +1,392 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// Notes: -// - VDPixmapBlt is from VirtualDub -// - sse2 yv12 to yuy2 conversion by Haali -// (- vd.cpp/h should be renamed to something more sensible already :) - - -#include "stdafx.h" -#include "vd.h" -#include "vd_asm.h" -#include - -#include "vd2/system/memory.h" -#include "vd2/system/vdstl.h" - -#include "vd2/Kasumi/pixmap.h" -#include "vd2/Kasumi/pixmaputils.h" -#include "vd2/Kasumi/pixmapops.h" -#include "vd2/Kasumi/resample.h" - -#pragma warning(disable : 4799) // no emms... blahblahblah - -bool BitBltFromI420ToI420(int w, int h, BYTE* dsty, BYTE* dstu, BYTE* dstv, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) -{ - VDPixmap srcbm = {0}; - - srcbm.data = srcy; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; - srcbm.data2 = srcu; - srcbm.pitch2 = srcpitch / 2; - srcbm.data3 = srcv; - srcbm.pitch3 = srcpitch / 2; - - VDPixmap dstpxm = {0}; - - dstpxm.data = dsty; - dstpxm.pitch = dstpitch; - dstpxm.w = w; - dstpxm.h = h; - dstpxm.format = nsVDPixmap::kPixFormat_YUV420_Planar; - dstpxm.data2 = dstu; - dstpxm.pitch2 = dstpitch / 2; - dstpxm.data3 = dstv; - dstpxm.pitch3 = dstpitch / 2; - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromYUY2ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* src, int srcpitch) -{ - VDPixmap srcbm = {0}; - - srcbm.data = src; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; - - VDPixmap dstpxm = { - dst, - NULL, - w, - h, - dstpitch - }; - - dstpxm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromI420ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) -{ - VDPixmap srcbm = {0}; - - srcbm.data = srcy; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; - srcbm.data2 = srcu; - srcbm.pitch2 = srcpitch/2; - srcbm.data3 = srcv; - srcbm.pitch3 = srcpitch/2; - - VDPixmap dstpxm = { - (char *)dst + dstpitch * (h - 1), - NULL, - w, - h, - -dstpitch - }; - - switch(dbpp) { - case 16: - dstpxm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - dstpxm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromI420ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) -{ - if (srcpitch == 0) srcpitch = w; - -#ifndef _WIN64 - if (!((DWORD_PTR)srcy&15) && !((DWORD_PTR)srcu&15) && !((DWORD_PTR)srcv&15) && !(srcpitch&31) && !((DWORD_PTR)dst&15) && !(dstpitch&15)) - { - if (w<=0 || h<=0 || (w&1) || (h&1)) - return false; - - yv12_yuy2_sse2(srcy, srcu, srcv, srcpitch/2, w/2, h, dst, dstpitch); - return true; - } -#endif - - VDPixmap srcbm = {0}; - - srcbm.data = srcy; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; - srcbm.data2 = srcu; - srcbm.pitch2 = srcpitch/2; - srcbm.data3 = srcv; - srcbm.pitch3 = srcpitch/2; - - VDPixmap dstpxm = { - dst, - NULL, - w, - h, - dstpitch - }; - - dstpxm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromRGBToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch, int sbpp) -{ - VDPixmap srcbm = { - (char *)src + srcpitch * (h - 1), - NULL, - w, - h, - -srcpitch - }; - - switch(sbpp) { - case 8: - srcbm.format = nsVDPixmap::kPixFormat_Pal8; - break; - case 16: - srcbm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - srcbm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - srcbm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - VDPixmap dstpxm = { - (char *)dst + dstpitch * (h - 1), - NULL, - w, - h, - -dstpitch - }; - - switch(dbpp) { - case 8: - dstpxm.format = nsVDPixmap::kPixFormat_Pal8; - break; - case 16: - dstpxm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - dstpxm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromRGBToRGBStretch(int dstw, int dsth, BYTE* dst, int dstpitch, int dbpp, int srcw, int srch, BYTE* src, int srcpitch, int sbpp) -{ - VDPixmap srcbm = { - src + srcpitch * (srch - 1), - nullptr, - srcw, - srch, - -srcpitch - }; - - switch (sbpp) { - case 8: - srcbm.format = nsVDPixmap::kPixFormat_Pal8; - break; - case 16: - srcbm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - srcbm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - srcbm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - VDPixmap dstpxm = { - dst + dstpitch * (dsth - 1), - nullptr, - dstw, - dsth, - -dstpitch - }; - - switch (dbpp) { - case 8: - dstpxm.format = nsVDPixmap::kPixFormat_Pal8; - break; - case 16: - dstpxm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - dstpxm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - return VDPixmapResample(dstpxm, srcbm, IVDPixmapResampler::kFilterCubic); -} - - -bool BitBltFromYUY2ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch) -{ - if (srcpitch == 0) srcpitch = w; - - VDPixmap srcbm = {0}; - - srcbm.data = src; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; - - VDPixmap dstpxm = { - (char *)dst + dstpitch * (h - 1), - NULL, - w, - h, - -dstpitch - }; - - switch(dbpp) { - case 16: - dstpxm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - dstpxm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - return VDPixmapBlt(dstpxm, srcbm); -} - -static void yuvtoyuy2row_c(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) -{ - WORD* dstw = (WORD*)dst; - for (; width > 1; width -= 2) - { - *dstw++ = (*srcu++<<8)|*srcy++; - *dstw++ = (*srcv++<<8)|*srcy++; - } -} - -static void yuvtoyuy2row_avg_c(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) -{ - WORD* dstw = (WORD*)dst; - for (; width > 1; width -= 2, srcu++, srcv++) - { - *dstw++ = (((srcu[0]+srcu[pitchuv])>>1)<<8)|*srcy++; - *dstw++ = (((srcv[0]+srcv[pitchuv])>>1)<<8)|*srcy++; - } -} - -bool BitBltFromI420ToYUY2Interlaced(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) -{ - if (w<=0 || h<=0 || (w&1) || (h&1)) - return false; - - if (srcpitch == 0) srcpitch = w; - - void (*yuvtoyuy2row)(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) = NULL; - void (*yuvtoyuy2row_avg)(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) = NULL; - -#ifndef _WIN64 - if (!((DWORD_PTR)srcy&15) && !((DWORD_PTR)srcu&15) && !((DWORD_PTR)srcv&15) && !(srcpitch&31) && !((DWORD_PTR)dst&15) && !(dstpitch&15)) - { - yv12_yuy2_sse2_interlaced(srcy, srcu, srcv, srcpitch/2, w/2, h, dst, dstpitch); - return true; - } - - if (!(w&7)) - { - yuvtoyuy2row = yuvtoyuy2row_MMX; - yuvtoyuy2row_avg = yuvtoyuy2row_avg_MMX; - } - else -#endif - { - yuvtoyuy2row = yuvtoyuy2row_c; - yuvtoyuy2row_avg = yuvtoyuy2row_avg_c; - } - - if (!yuvtoyuy2row) - return false; - - int halfsrcpitch = srcpitch/2; - do - { - yuvtoyuy2row(dst, srcy, srcu, srcv, w); - yuvtoyuy2row_avg(dst + dstpitch, srcy + srcpitch, srcu, srcv, w, halfsrcpitch); - - dst += 2*dstpitch; - srcy += 2*srcpitch; - srcu += halfsrcpitch; - srcv += halfsrcpitch; - } - while ((h -= 2) > 2); - - yuvtoyuy2row(dst, srcy, srcu, srcv, w); - yuvtoyuy2row(dst + dstpitch, srcy + srcpitch, srcu, srcv, w); - -#ifndef _WIN64 - __asm emms -#endif - - return true; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Notes: +// - VDPixmapBlt is from VirtualDub +// - sse2 yv12 to yuy2 conversion by Haali +// (- vd.cpp/h should be renamed to something more sensible already :) + + +#include "stdafx.h" +#include "vd.h" +#include "vd_asm.h" +#include + +#include "vd2/system/memory.h" +#include "vd2/system/vdstl.h" + +#include "vd2/Kasumi/pixmap.h" +#include "vd2/Kasumi/pixmaputils.h" +#include "vd2/Kasumi/pixmapops.h" +#include "vd2/Kasumi/resample.h" + +#pragma warning(disable : 4799) // no emms... blahblahblah + +bool BitBltFromI420ToI420(int w, int h, BYTE* dsty, BYTE* dstu, BYTE* dstv, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) +{ + VDPixmap srcbm = {0}; + + srcbm.data = srcy; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; + srcbm.data2 = srcu; + srcbm.pitch2 = srcpitch / 2; + srcbm.data3 = srcv; + srcbm.pitch3 = srcpitch / 2; + + VDPixmap dstpxm = {0}; + + dstpxm.data = dsty; + dstpxm.pitch = dstpitch; + dstpxm.w = w; + dstpxm.h = h; + dstpxm.format = nsVDPixmap::kPixFormat_YUV420_Planar; + dstpxm.data2 = dstu; + dstpxm.pitch2 = dstpitch / 2; + dstpxm.data3 = dstv; + dstpxm.pitch3 = dstpitch / 2; + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromYUY2ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* src, int srcpitch) +{ + VDPixmap srcbm = {0}; + + srcbm.data = src; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; + + VDPixmap dstpxm = { + dst, + NULL, + w, + h, + dstpitch + }; + + dstpxm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromI420ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) +{ + VDPixmap srcbm = {0}; + + srcbm.data = srcy; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; + srcbm.data2 = srcu; + srcbm.pitch2 = srcpitch/2; + srcbm.data3 = srcv; + srcbm.pitch3 = srcpitch/2; + + VDPixmap dstpxm = { + (char *)dst + dstpitch * (h - 1), + NULL, + w, + h, + -dstpitch + }; + + switch(dbpp) { + case 16: + dstpxm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + dstpxm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromI420ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) +{ + if (srcpitch == 0) srcpitch = w; + +#ifndef _WIN64 + if (!((DWORD_PTR)srcy&15) && !((DWORD_PTR)srcu&15) && !((DWORD_PTR)srcv&15) && !(srcpitch&31) && !((DWORD_PTR)dst&15) && !(dstpitch&15)) + { + if (w<=0 || h<=0 || (w&1) || (h&1)) + return false; + + yv12_yuy2_sse2(srcy, srcu, srcv, srcpitch/2, w/2, h, dst, dstpitch); + return true; + } +#endif + + VDPixmap srcbm = {0}; + + srcbm.data = srcy; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; + srcbm.data2 = srcu; + srcbm.pitch2 = srcpitch/2; + srcbm.data3 = srcv; + srcbm.pitch3 = srcpitch/2; + + VDPixmap dstpxm = { + dst, + NULL, + w, + h, + dstpitch + }; + + dstpxm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromRGBToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch, int sbpp) +{ + VDPixmap srcbm = { + (char *)src + srcpitch * (h - 1), + NULL, + w, + h, + -srcpitch + }; + + switch(sbpp) { + case 8: + srcbm.format = nsVDPixmap::kPixFormat_Pal8; + break; + case 16: + srcbm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + srcbm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + srcbm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + VDPixmap dstpxm = { + (char *)dst + dstpitch * (h - 1), + NULL, + w, + h, + -dstpitch + }; + + switch(dbpp) { + case 8: + dstpxm.format = nsVDPixmap::kPixFormat_Pal8; + break; + case 16: + dstpxm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + dstpxm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromRGBToRGBStretch(int dstw, int dsth, BYTE* dst, int dstpitch, int dbpp, int srcw, int srch, BYTE* src, int srcpitch, int sbpp) +{ + VDPixmap srcbm = { + src + srcpitch * (srch - 1), + nullptr, + srcw, + srch, + -srcpitch + }; + + switch (sbpp) { + case 8: + srcbm.format = nsVDPixmap::kPixFormat_Pal8; + break; + case 16: + srcbm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + srcbm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + srcbm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + VDPixmap dstpxm = { + dst + dstpitch * (dsth - 1), + nullptr, + dstw, + dsth, + -dstpitch + }; + + switch (dbpp) { + case 8: + dstpxm.format = nsVDPixmap::kPixFormat_Pal8; + break; + case 16: + dstpxm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + dstpxm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + return VDPixmapResample(dstpxm, srcbm, IVDPixmapResampler::kFilterCubic); +} + + +bool BitBltFromYUY2ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch) +{ + if (srcpitch == 0) srcpitch = w; + + VDPixmap srcbm = {0}; + + srcbm.data = src; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; + + VDPixmap dstpxm = { + (char *)dst + dstpitch * (h - 1), + NULL, + w, + h, + -dstpitch + }; + + switch(dbpp) { + case 16: + dstpxm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + dstpxm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + return VDPixmapBlt(dstpxm, srcbm); +} + +static void yuvtoyuy2row_c(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) +{ + WORD* dstw = (WORD*)dst; + for (; width > 1; width -= 2) + { + *dstw++ = (*srcu++<<8)|*srcy++; + *dstw++ = (*srcv++<<8)|*srcy++; + } +} + +static void yuvtoyuy2row_avg_c(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) +{ + WORD* dstw = (WORD*)dst; + for (; width > 1; width -= 2, srcu++, srcv++) + { + *dstw++ = (((srcu[0]+srcu[pitchuv])>>1)<<8)|*srcy++; + *dstw++ = (((srcv[0]+srcv[pitchuv])>>1)<<8)|*srcy++; + } +} + +bool BitBltFromI420ToYUY2Interlaced(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) +{ + if (w<=0 || h<=0 || (w&1) || (h&1)) + return false; + + if (srcpitch == 0) srcpitch = w; + + void (*yuvtoyuy2row)(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) = NULL; + void (*yuvtoyuy2row_avg)(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) = NULL; + +#ifndef _WIN64 + if (!((DWORD_PTR)srcy&15) && !((DWORD_PTR)srcu&15) && !((DWORD_PTR)srcv&15) && !(srcpitch&31) && !((DWORD_PTR)dst&15) && !(dstpitch&15)) + { + yv12_yuy2_sse2_interlaced(srcy, srcu, srcv, srcpitch/2, w/2, h, dst, dstpitch); + return true; + } + + if (!(w&7)) + { + yuvtoyuy2row = yuvtoyuy2row_MMX; + yuvtoyuy2row_avg = yuvtoyuy2row_avg_MMX; + } + else +#endif + { + yuvtoyuy2row = yuvtoyuy2row_c; + yuvtoyuy2row_avg = yuvtoyuy2row_avg_c; + } + + if (!yuvtoyuy2row) + return false; + + int halfsrcpitch = srcpitch/2; + do + { + yuvtoyuy2row(dst, srcy, srcu, srcv, w); + yuvtoyuy2row_avg(dst + dstpitch, srcy + srcpitch, srcu, srcv, w, halfsrcpitch); + + dst += 2*dstpitch; + srcy += 2*srcpitch; + srcu += halfsrcpitch; + srcv += halfsrcpitch; + } + while ((h -= 2) > 2); + + yuvtoyuy2row(dst, srcy, srcu, srcv, w); + yuvtoyuy2row(dst + dstpitch, srcy + srcpitch, srcu, srcv, w); + +#ifndef _WIN64 + __asm emms +#endif + + return true; +} diff --git a/src/DSUtil/vd.h b/src/DSUtil/vd.h index 5f4d890dc64..df867454c73 100644 --- a/src/DSUtil/vd.h +++ b/src/DSUtil/vd.h @@ -1,47 +1,47 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// Notes: -// - VDPixmapBlt is from VirtualDub -// - sse2 yv12 to yuy2 conversion by Haali -// (- vd.cpp/h should be renamed to something more sensible already :) - -#pragma once - -#if 0 -class CCpuID { -public: - CCpuID(); - enum flag_t {mmx=1, ssemmx=2, ssefpu=4, sse2=8, _3dnow=16} m_flags; -}; -extern CCpuID g_cpuid; -#endif - -extern bool BitBltFromI420ToI420(int w, int h, BYTE* dsty, BYTE* dstu, BYTE* dstv, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); -extern bool BitBltFromI420ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); -extern bool BitBltFromI420ToYUY2Interlaced(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); -extern bool BitBltFromI420ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch /* TODO: , bool fInterlaced = false */); -extern bool BitBltFromYUY2ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* src, int srcpitch); -extern bool BitBltFromYUY2ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch); -extern bool BitBltFromRGBToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch, int sbpp); -extern bool BitBltFromRGBToRGBStretch(int dstw, int dsth, BYTE* dst, int dstpitch, int dbpp, int srcw, int srch, BYTE* src, int srcpitch, int sbpp); - -extern void DeinterlaceBlend(BYTE* dst, BYTE* src, DWORD rowbytes, DWORD h, DWORD dstpitch, DWORD srcpitch); -extern void DeinterlaceBob(BYTE* dst, BYTE* src, DWORD rowbytes, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); -extern void DeinterlaceELA_X8R8G8B8(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); -extern void DeinterlaceELA(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Notes: +// - VDPixmapBlt is from VirtualDub +// - sse2 yv12 to yuy2 conversion by Haali +// (- vd.cpp/h should be renamed to something more sensible already :) + +#pragma once + +#if 0 +class CCpuID { +public: + CCpuID(); + enum flag_t {mmx=1, ssemmx=2, ssefpu=4, sse2=8, _3dnow=16} m_flags; +}; +extern CCpuID g_cpuid; +#endif + +extern bool BitBltFromI420ToI420(int w, int h, BYTE* dsty, BYTE* dstu, BYTE* dstv, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); +extern bool BitBltFromI420ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); +extern bool BitBltFromI420ToYUY2Interlaced(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); +extern bool BitBltFromI420ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch /* TODO: , bool fInterlaced = false */); +extern bool BitBltFromYUY2ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* src, int srcpitch); +extern bool BitBltFromYUY2ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch); +extern bool BitBltFromRGBToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch, int sbpp); +extern bool BitBltFromRGBToRGBStretch(int dstw, int dsth, BYTE* dst, int dstpitch, int dbpp, int srcw, int srch, BYTE* src, int srcpitch, int sbpp); + +extern void DeinterlaceBlend(BYTE* dst, BYTE* src, DWORD rowbytes, DWORD h, DWORD dstpitch, DWORD srcpitch); +extern void DeinterlaceBob(BYTE* dst, BYTE* src, DWORD rowbytes, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); +extern void DeinterlaceELA_X8R8G8B8(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); +extern void DeinterlaceELA(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); diff --git a/src/DSUtil/vd_asm.cpp b/src/DSUtil/vd_asm.cpp index 040dd500504..0cc10e92e80 100644 --- a/src/DSUtil/vd_asm.cpp +++ b/src/DSUtil/vd_asm.cpp @@ -1,432 +1,432 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// Notes: -// - VDPixmapBlt is from VirtualDub -// - sse2 yv12 to yuy2 conversion by Haali -// (- vd.cpp/h should be renamed to something more sensible already :) - - -#include "stdafx.h" -#include "vd_asm.h" - -#pragma warning(disable : 4799) // no emms... blahblahblah - -#ifndef _WIN64 -void __declspec(naked) yuvtoyuy2row_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) -{ - __asm { - push ebp - push edi - push esi - push ebx - - mov edi, [esp+20] // dst - mov ebp, [esp+24] // srcy - mov ebx, [esp+28] // srcu - mov esi, [esp+32] // srcv - mov ecx, [esp+36] // width - - shr ecx, 3 - -yuvtoyuy2row_loop: - - movd mm0, [ebx] - punpcklbw mm0, [esi] - - movq mm1, [ebp] - movq mm2, mm1 - punpcklbw mm1, mm0 - punpckhbw mm2, mm0 - - movq [edi], mm1 - movq [edi+8], mm2 - - add ebp, 8 - add ebx, 4 - add esi, 4 - add edi, 16 - - dec ecx - jnz yuvtoyuy2row_loop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -void __declspec(naked) yuvtoyuy2row_avg_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) -{ - static const __int64 mask = 0x7f7f7f7f7f7f7f7fi64; - - __asm { - push ebp - push edi - push esi - push ebx - - movq mm7, mask - - mov edi, [esp+20] // dst - mov ebp, [esp+24] // srcy - mov ebx, [esp+28] // srcu - mov esi, [esp+32] // srcv - mov ecx, [esp+36] // width - mov eax, [esp+40] // pitchuv - - shr ecx, 3 - -yuvtoyuy2row_avg_loop: - - movd mm0, [ebx] - punpcklbw mm0, [esi] - movq mm1, mm0 - - movd mm2, [ebx + eax] - punpcklbw mm2, [esi + eax] - movq mm3, mm2 - - // (x+y)>>1 == (x&y)+((x^y)>>1) - - pand mm0, mm2 - pxor mm1, mm3 - psrlq mm1, 1 - pand mm1, mm7 - paddb mm0, mm1 - - movq mm1, [ebp] - movq mm2, mm1 - punpcklbw mm1, mm0 - punpckhbw mm2, mm0 - - movq [edi], mm1 - movq [edi+8], mm2 - - add ebp, 8 - add ebx, 4 - add esi, 4 - add edi, 16 - - dec ecx - jnz yuvtoyuy2row_avg_loop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -void __declspec(naked) yv12_yuy2_row_sse2() { - __asm { - // ebx - Y - // edx - U - // esi - V - // edi - dest - // ecx - halfwidth - xor eax, eax - -one: - movdqa xmm0, [ebx + eax*2] // YYYYYYYY - movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY - - movdqa xmm2, [edx + eax] // UUUUUUUU - movdqa xmm3, [esi + eax] // VVVVVVVV - - movdqa xmm4, xmm2 - movdqa xmm5, xmm0 - movdqa xmm6, xmm1 - punpcklbw xmm2, xmm3 // VUVUVUVU - punpckhbw xmm4, xmm3 // VUVUVUVU - - punpcklbw xmm0, xmm2 // VYUYVYUY - punpcklbw xmm1, xmm4 - punpckhbw xmm5, xmm2 - punpckhbw xmm6, xmm4 - - movntdq [edi + eax*4], xmm0 - movntdq [edi + eax*4 + 16], xmm5 - movntdq [edi + eax*4 + 32], xmm1 - movntdq [edi + eax*4 + 48], xmm6 - - add eax, 16 - cmp eax, ecx - - jb one - - ret - }; -} - -void __declspec(naked) yv12_yuy2_row_sse2_linear() { - __asm { - // ebx - Y - // edx - U - // esi - V - // edi - dest - // ecx - width - // ebp - uv_stride - xor eax, eax - -one: - movdqa xmm0, [ebx + eax*2] // YYYYYYYY - movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY - - movdqa xmm2, [edx] - movdqa xmm3, [esi] - pavgb xmm2, [edx + ebp] // UUUUUUUU - pavgb xmm3, [esi + ebp] // VVVVVVVV - - movdqa xmm4, xmm2 - movdqa xmm5, xmm0 - movdqa xmm6, xmm1 - punpcklbw xmm2, xmm3 // VUVUVUVU - punpckhbw xmm4, xmm3 // VUVUVUVU - - punpcklbw xmm0, xmm2 // VYUYVYUY - punpcklbw xmm1, xmm4 - punpckhbw xmm5, xmm2 - punpckhbw xmm6, xmm4 - - movntdq [edi + eax*4], xmm0 - movntdq [edi + eax*4 + 16], xmm5 - movntdq [edi + eax*4 + 32], xmm1 - movntdq [edi + eax*4 + 48], xmm6 - - add eax, 16 - add edx, 16 - add esi, 16 - cmp eax, ecx - - jb one - - ret - }; -} - -void __declspec(naked) yv12_yuy2_row_sse2_linear_interlaced() { - __asm { - // ebx - Y - // edx - U - // esi - V - // edi - dest - // ecx - width - // ebp - uv_stride - xor eax, eax - -one: - movdqa xmm0, [ebx + eax*2] // YYYYYYYY - movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY - - movdqa xmm2, [edx] - movdqa xmm3, [esi] - pavgb xmm2, [edx + ebp*2] // UUUUUUUU - pavgb xmm3, [esi + ebp*2] // VVVVVVVV - - movdqa xmm4, xmm2 - movdqa xmm5, xmm0 - movdqa xmm6, xmm1 - punpcklbw xmm2, xmm3 // VUVUVUVU - punpckhbw xmm4, xmm3 // VUVUVUVU - - punpcklbw xmm0, xmm2 // VYUYVYUY - punpcklbw xmm1, xmm4 - punpckhbw xmm5, xmm2 - punpckhbw xmm6, xmm4 - - movntdq [edi + eax*4], xmm0 - movntdq [edi + eax*4 + 16], xmm5 - movntdq [edi + eax*4 + 32], xmm1 - movntdq [edi + eax*4 + 48], xmm6 - - add eax, 16 - add edx, 16 - add esi, 16 - cmp eax, ecx - - jb one - - ret - }; -} - -void __declspec(naked) yv12_yuy2_sse2(const BYTE *Y, const BYTE *U, const BYTE *V, - int halfstride, unsigned halfwidth, unsigned height, - BYTE *YUY2, int d_stride) -{ - __asm { - push ebx - push esi - push edi - push ebp - - mov ebx, [esp + 20] // Y - mov edx, [esp + 24] // U - mov esi, [esp + 28] // V - mov edi, [esp + 44] // D - mov ebp, [esp + 32] // uv_stride - mov ecx, [esp + 36] // uv_width - - mov eax, ecx - add eax, 15 - and eax, 0xfffffff0 - sub [esp + 32], eax - - cmp dword ptr [esp + 40], 2 - jbe last2 - -row: - sub dword ptr [esp + 40], 2 - call yv12_yuy2_row_sse2 - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - call yv12_yuy2_row_sse2_linear - - add edx, [esp + 32] - add esi, [esp + 32] - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - cmp dword ptr [esp + 40], 2 - ja row - -last2: - call yv12_yuy2_row_sse2 - - dec dword ptr [esp + 40] - jz done - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - call yv12_yuy2_row_sse2 -done: - - pop ebp - pop edi - pop esi - pop ebx - - ret - }; -} - -void __declspec(naked) yv12_yuy2_sse2_interlaced(const BYTE *Y, const BYTE *U, const BYTE *V, - int halfstride, unsigned halfwidth, unsigned height, - BYTE *YUY2, int d_stride) -{ - __asm { - push ebx - push esi - push edi - push ebp - - mov ebx, [esp + 20] // Y - mov edx, [esp + 24] // U - mov esi, [esp + 28] // V - mov edi, [esp + 44] // D - mov ebp, [esp + 32] // uv_stride - mov ecx, [esp + 36] // uv_width - - mov eax, ecx - add eax, 15 - and eax, 0xfffffff0 - sub [esp + 32], eax - - cmp dword ptr [esp + 40], 4 - jbe last4 - -row: - sub dword ptr [esp + 40], 4 - call yv12_yuy2_row_sse2 // first row, first field - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - add edx, ebp - add esi, ebp - - call yv12_yuy2_row_sse2 // first row, second field - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - sub edx, ebp - sub esi, ebp - - call yv12_yuy2_row_sse2_linear_interlaced // second row, first field - - add edx, [esp + 32] - add esi, [esp + 32] - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - call yv12_yuy2_row_sse2_linear_interlaced // second row, second field - - add edx, [esp + 32] - add esi, [esp + 32] - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - cmp dword ptr [esp + 40], 4 - ja row - -last4: - call yv12_yuy2_row_sse2 - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - add edx, ebp - add esi, ebp - - call yv12_yuy2_row_sse2 - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - sub edx, ebp - sub esi, ebp - - call yv12_yuy2_row_sse2 - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - add edx, ebp - add esi, ebp - - call yv12_yuy2_row_sse2 - - pop ebp - pop edi - pop esi - pop ebx - - ret - }; -} -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Notes: +// - VDPixmapBlt is from VirtualDub +// - sse2 yv12 to yuy2 conversion by Haali +// (- vd.cpp/h should be renamed to something more sensible already :) + + +#include "stdafx.h" +#include "vd_asm.h" + +#pragma warning(disable : 4799) // no emms... blahblahblah + +#ifndef _WIN64 +void __declspec(naked) yuvtoyuy2row_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) +{ + __asm { + push ebp + push edi + push esi + push ebx + + mov edi, [esp+20] // dst + mov ebp, [esp+24] // srcy + mov ebx, [esp+28] // srcu + mov esi, [esp+32] // srcv + mov ecx, [esp+36] // width + + shr ecx, 3 + +yuvtoyuy2row_loop: + + movd mm0, [ebx] + punpcklbw mm0, [esi] + + movq mm1, [ebp] + movq mm2, mm1 + punpcklbw mm1, mm0 + punpckhbw mm2, mm0 + + movq [edi], mm1 + movq [edi+8], mm2 + + add ebp, 8 + add ebx, 4 + add esi, 4 + add edi, 16 + + dec ecx + jnz yuvtoyuy2row_loop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +void __declspec(naked) yuvtoyuy2row_avg_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) +{ + static const __int64 mask = 0x7f7f7f7f7f7f7f7fi64; + + __asm { + push ebp + push edi + push esi + push ebx + + movq mm7, mask + + mov edi, [esp+20] // dst + mov ebp, [esp+24] // srcy + mov ebx, [esp+28] // srcu + mov esi, [esp+32] // srcv + mov ecx, [esp+36] // width + mov eax, [esp+40] // pitchuv + + shr ecx, 3 + +yuvtoyuy2row_avg_loop: + + movd mm0, [ebx] + punpcklbw mm0, [esi] + movq mm1, mm0 + + movd mm2, [ebx + eax] + punpcklbw mm2, [esi + eax] + movq mm3, mm2 + + // (x+y)>>1 == (x&y)+((x^y)>>1) + + pand mm0, mm2 + pxor mm1, mm3 + psrlq mm1, 1 + pand mm1, mm7 + paddb mm0, mm1 + + movq mm1, [ebp] + movq mm2, mm1 + punpcklbw mm1, mm0 + punpckhbw mm2, mm0 + + movq [edi], mm1 + movq [edi+8], mm2 + + add ebp, 8 + add ebx, 4 + add esi, 4 + add edi, 16 + + dec ecx + jnz yuvtoyuy2row_avg_loop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +void __declspec(naked) yv12_yuy2_row_sse2() { + __asm { + // ebx - Y + // edx - U + // esi - V + // edi - dest + // ecx - halfwidth + xor eax, eax + +one: + movdqa xmm0, [ebx + eax*2] // YYYYYYYY + movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY + + movdqa xmm2, [edx + eax] // UUUUUUUU + movdqa xmm3, [esi + eax] // VVVVVVVV + + movdqa xmm4, xmm2 + movdqa xmm5, xmm0 + movdqa xmm6, xmm1 + punpcklbw xmm2, xmm3 // VUVUVUVU + punpckhbw xmm4, xmm3 // VUVUVUVU + + punpcklbw xmm0, xmm2 // VYUYVYUY + punpcklbw xmm1, xmm4 + punpckhbw xmm5, xmm2 + punpckhbw xmm6, xmm4 + + movntdq [edi + eax*4], xmm0 + movntdq [edi + eax*4 + 16], xmm5 + movntdq [edi + eax*4 + 32], xmm1 + movntdq [edi + eax*4 + 48], xmm6 + + add eax, 16 + cmp eax, ecx + + jb one + + ret + }; +} + +void __declspec(naked) yv12_yuy2_row_sse2_linear() { + __asm { + // ebx - Y + // edx - U + // esi - V + // edi - dest + // ecx - width + // ebp - uv_stride + xor eax, eax + +one: + movdqa xmm0, [ebx + eax*2] // YYYYYYYY + movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY + + movdqa xmm2, [edx] + movdqa xmm3, [esi] + pavgb xmm2, [edx + ebp] // UUUUUUUU + pavgb xmm3, [esi + ebp] // VVVVVVVV + + movdqa xmm4, xmm2 + movdqa xmm5, xmm0 + movdqa xmm6, xmm1 + punpcklbw xmm2, xmm3 // VUVUVUVU + punpckhbw xmm4, xmm3 // VUVUVUVU + + punpcklbw xmm0, xmm2 // VYUYVYUY + punpcklbw xmm1, xmm4 + punpckhbw xmm5, xmm2 + punpckhbw xmm6, xmm4 + + movntdq [edi + eax*4], xmm0 + movntdq [edi + eax*4 + 16], xmm5 + movntdq [edi + eax*4 + 32], xmm1 + movntdq [edi + eax*4 + 48], xmm6 + + add eax, 16 + add edx, 16 + add esi, 16 + cmp eax, ecx + + jb one + + ret + }; +} + +void __declspec(naked) yv12_yuy2_row_sse2_linear_interlaced() { + __asm { + // ebx - Y + // edx - U + // esi - V + // edi - dest + // ecx - width + // ebp - uv_stride + xor eax, eax + +one: + movdqa xmm0, [ebx + eax*2] // YYYYYYYY + movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY + + movdqa xmm2, [edx] + movdqa xmm3, [esi] + pavgb xmm2, [edx + ebp*2] // UUUUUUUU + pavgb xmm3, [esi + ebp*2] // VVVVVVVV + + movdqa xmm4, xmm2 + movdqa xmm5, xmm0 + movdqa xmm6, xmm1 + punpcklbw xmm2, xmm3 // VUVUVUVU + punpckhbw xmm4, xmm3 // VUVUVUVU + + punpcklbw xmm0, xmm2 // VYUYVYUY + punpcklbw xmm1, xmm4 + punpckhbw xmm5, xmm2 + punpckhbw xmm6, xmm4 + + movntdq [edi + eax*4], xmm0 + movntdq [edi + eax*4 + 16], xmm5 + movntdq [edi + eax*4 + 32], xmm1 + movntdq [edi + eax*4 + 48], xmm6 + + add eax, 16 + add edx, 16 + add esi, 16 + cmp eax, ecx + + jb one + + ret + }; +} + +void __declspec(naked) yv12_yuy2_sse2(const BYTE *Y, const BYTE *U, const BYTE *V, + int halfstride, unsigned halfwidth, unsigned height, + BYTE *YUY2, int d_stride) +{ + __asm { + push ebx + push esi + push edi + push ebp + + mov ebx, [esp + 20] // Y + mov edx, [esp + 24] // U + mov esi, [esp + 28] // V + mov edi, [esp + 44] // D + mov ebp, [esp + 32] // uv_stride + mov ecx, [esp + 36] // uv_width + + mov eax, ecx + add eax, 15 + and eax, 0xfffffff0 + sub [esp + 32], eax + + cmp dword ptr [esp + 40], 2 + jbe last2 + +row: + sub dword ptr [esp + 40], 2 + call yv12_yuy2_row_sse2 + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + call yv12_yuy2_row_sse2_linear + + add edx, [esp + 32] + add esi, [esp + 32] + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + cmp dword ptr [esp + 40], 2 + ja row + +last2: + call yv12_yuy2_row_sse2 + + dec dword ptr [esp + 40] + jz done + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + call yv12_yuy2_row_sse2 +done: + + pop ebp + pop edi + pop esi + pop ebx + + ret + }; +} + +void __declspec(naked) yv12_yuy2_sse2_interlaced(const BYTE *Y, const BYTE *U, const BYTE *V, + int halfstride, unsigned halfwidth, unsigned height, + BYTE *YUY2, int d_stride) +{ + __asm { + push ebx + push esi + push edi + push ebp + + mov ebx, [esp + 20] // Y + mov edx, [esp + 24] // U + mov esi, [esp + 28] // V + mov edi, [esp + 44] // D + mov ebp, [esp + 32] // uv_stride + mov ecx, [esp + 36] // uv_width + + mov eax, ecx + add eax, 15 + and eax, 0xfffffff0 + sub [esp + 32], eax + + cmp dword ptr [esp + 40], 4 + jbe last4 + +row: + sub dword ptr [esp + 40], 4 + call yv12_yuy2_row_sse2 // first row, first field + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + add edx, ebp + add esi, ebp + + call yv12_yuy2_row_sse2 // first row, second field + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + sub edx, ebp + sub esi, ebp + + call yv12_yuy2_row_sse2_linear_interlaced // second row, first field + + add edx, [esp + 32] + add esi, [esp + 32] + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + call yv12_yuy2_row_sse2_linear_interlaced // second row, second field + + add edx, [esp + 32] + add esi, [esp + 32] + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + cmp dword ptr [esp + 40], 4 + ja row + +last4: + call yv12_yuy2_row_sse2 + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + add edx, ebp + add esi, ebp + + call yv12_yuy2_row_sse2 + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + sub edx, ebp + sub esi, ebp + + call yv12_yuy2_row_sse2 + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + add edx, ebp + add esi, ebp + + call yv12_yuy2_row_sse2 + + pop ebp + pop edi + pop esi + pop ebx + + ret + }; +} +#endif diff --git a/src/DSUtil/vd_asm.h b/src/DSUtil/vd_asm.h index 4e0fd8e9005..b637eeffb48 100644 --- a/src/DSUtil/vd_asm.h +++ b/src/DSUtil/vd_asm.h @@ -1,34 +1,34 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// Notes: -// - VDPixmapBlt is from VirtualDub -// (- vd.cpp/h should be renamed to something more sensible already :) - -#pragma once - -#ifndef _WIN64 -void yuvtoyuy2row_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width); -void yuvtoyuy2row_avg_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv); - -void yv12_yuy2_row_sse2(); -void yv12_yuy2_row_sse2_linear(); -void yv12_yuy2_row_sse2_linear_interlaced(); -void yv12_yuy2_sse2(const BYTE *Y, const BYTE *U, const BYTE *V, int halfstride, unsigned halfwidth, unsigned height, BYTE *YUY2, int d_stride); -void yv12_yuy2_sse2_interlaced(const BYTE *Y, const BYTE *U, const BYTE *V, int halfstride, unsigned halfwidth, unsigned height, BYTE *YUY2, int d_stride); -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Notes: +// - VDPixmapBlt is from VirtualDub +// (- vd.cpp/h should be renamed to something more sensible already :) + +#pragma once + +#ifndef _WIN64 +void yuvtoyuy2row_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width); +void yuvtoyuy2row_avg_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv); + +void yv12_yuy2_row_sse2(); +void yv12_yuy2_row_sse2_linear(); +void yv12_yuy2_row_sse2_linear_interlaced(); +void yv12_yuy2_sse2(const BYTE *Y, const BYTE *U, const BYTE *V, int halfstride, unsigned halfwidth, unsigned height, BYTE *YUY2, int d_stride); +void yv12_yuy2_sse2_interlaced(const BYTE *Y, const BYTE *U, const BYTE *V, int halfstride, unsigned halfwidth, unsigned height, BYTE *YUY2, int d_stride); +#endif diff --git a/src/DeCSS/CSSauth.cpp b/src/DeCSS/CSSauth.cpp index ca9142f45b3..eee0fa2f304 100644 --- a/src/DeCSS/CSSauth.cpp +++ b/src/DeCSS/CSSauth.cpp @@ -1,339 +1,339 @@ -#include "stdafx.h" - -static void CSSengine(int varient,unsigned char const *input,unsigned char *output); - -void CSSkey1(int varient,unsigned char const *challenge,unsigned char *key) -{ - static unsigned char perm_challenge[] = {1,3,0,7,5, 2,9,6,4,8}; - - unsigned char scratch[10]; - int i; - - for (i = 9; i >= 0; --i) { - scratch[i] = challenge[perm_challenge[i]]; - } - - CSSengine(varient, scratch, key); -} - -void CSSkey2(int varient,unsigned char const *challenge,unsigned char *key) -{ - static unsigned char perm_challenge[] = {6,1,9,3,8, 5,7,4,0,2}; - - static unsigned char perm_varient[] = { - 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d, - 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d, - 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05, - 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 - }; - - unsigned char scratch[10]; - int i; - - for (i = 9; i >= 0; --i) { - scratch[i] = challenge[perm_challenge[i]]; - } - - CSSengine(perm_varient[varient], scratch, key); -} - -void CSSbuskey(int varient,unsigned char const *challenge,unsigned char *key) -{ - static unsigned char perm_challenge[] = {4,0,3,5,7, 2,8,6,1,9}; - static unsigned char perm_varient[] = { - 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e, - 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c, - 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f, - 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d - }; - - unsigned char scratch[10]; - int i; - - for (i = 9; i >= 0; --i) { - scratch[i] = challenge[perm_challenge[i]]; - } - - CSSengine(perm_varient[varient], scratch, key); -} - -static void CSSgenbits(unsigned char *output, int len,unsigned char const *s) -{ - unsigned long lfsr0, lfsr1; - unsigned char b1_combined; /* Save the old value of bit 1 for feedback */ - - /* In order to ensure that the LFSR works we need to ensure that the - * initial values are non-zero. Thus when we initialise them from - * the seed, we ensure that a bit is set. - */ - lfsr0 = (s[0] << 17) | (s[1] << 9) | ((s[2] & ~7) << 1) | 8 | (s[2] & 7); - lfsr1 = (s[3] << 9) | 0x100 | s[4]; - - ++output; - - b1_combined = 0; - do { - int bit; - unsigned char val; - - for (bit = 0, val = 0; bit < 8; ++bit) { - unsigned char o_lfsr0, o_lfsr1; /* Actually only 1 bit each */ - unsigned char combined; - - o_lfsr0 = ((lfsr0 >> 24) ^ (lfsr0 >> 21) ^ (lfsr0 >> 20) ^ (lfsr0 >> 12)) & 1; - lfsr0 = (lfsr0 << 1) | o_lfsr0; - - o_lfsr1 = ((lfsr1 >> 16) ^ (lfsr1 >> 2)) & 1; - lfsr1 = (lfsr1 << 1) | o_lfsr1; - -#define BIT0(x) ((x) & 1) -#define BIT1(x) (((x) >> 1) & 1) - - combined = !o_lfsr1 + b1_combined + !o_lfsr0; - b1_combined = BIT1(combined); - val |= BIT0(combined) << bit; - } - - *--output = val; - } while (--len > 0); -} - -unsigned char CSSsecret[]; -unsigned char CSSvarients[]; -unsigned char CSStable0[]; -unsigned char CSStable1[]; -unsigned char CSStable2[]; -unsigned char CSStable3[]; - -static void CSSengine(int varient, unsigned char const *input,unsigned char *output) -{ - unsigned char cse, term, index; - unsigned char temp1[5]; - unsigned char temp2[5]; - unsigned char bits[30]; - - int i; - - /* Feed the CSSsecret into the input values such that - * we alter the seed to the LFSR's used above, then - * generate the bits to play with. - */ - for (i = 5; --i >= 0; ) { - temp1[i] = input[5 + i] ^ CSSsecret[i] ^ CSStable2[i]; - } - - CSSgenbits(&bits[29], sizeof bits, temp1); - - /* This term is used throughout the following to - * select one of 32 different variations on the - * algorithm. - */ - cse = CSSvarients[varient] ^ CSStable2[varient]; - - /* Now the actual blocks doing the encryption. Each - * of these works on 40 bits at a time and are quite - * similar. - */ - for (i = 5, term = 0; --i >= 0; term = input[i]) { - index = bits[25 + i] ^ input[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - temp1[i] = CSStable2[index] ^ CSStable3[index] ^ term; - } - temp1[4] ^= temp1[0]; - - for (i = 5, term = 0; --i >= 0; term = temp1[i]) { - index = bits[20 + i] ^ temp1[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - temp2[i] = CSStable2[index] ^ CSStable3[index] ^ term; - } - temp2[4] ^= temp2[0]; - - for (i = 5, term = 0; --i >= 0; term = temp2[i]) { - index = bits[15 + i] ^ temp2[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - index = CSStable2[index] ^ CSStable3[index] ^ term; - - temp1[i] = CSStable0[index] ^ CSStable2[index]; - } - temp1[4] ^= temp1[0]; - - for (i = 5, term = 0; --i >= 0; term = temp1[i]) { - index = bits[10 + i] ^ temp1[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - index = CSStable2[index] ^ CSStable3[index] ^ term; - - temp2[i] = CSStable0[index] ^ CSStable2[index]; - } - temp2[4] ^= temp2[0]; - - for (i = 5, term = 0; --i >= 0; term = temp2[i]) { - index = bits[5 + i] ^ temp2[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - temp1[i] = CSStable2[index] ^ CSStable3[index] ^ term; - } - temp1[4] ^= temp1[0]; - - for (i = 5, term = 0; --i >= 0; term = temp1[i]) { - index = bits[i] ^ temp1[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - output[i] = CSStable2[index] ^ CSStable3[index] ^ term; - } -} - -unsigned char CSSvarients[] = { - 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73, - 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42, - 0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B, - 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 -}; - -unsigned char CSSsecret[] = {0x55, 0xD6, 0xC4, 0xC5, 0x28}; - -unsigned char CSStable0[] = { - 0xB7, 0xF4, 0x82, 0x57, 0xDA, 0x4D, 0xDB, 0xE2, - 0x2F, 0x52, 0x1A, 0xA8, 0x68, 0x5A, 0x8A, 0xFF, - 0xFB, 0x0E, 0x6D, 0x35, 0xF7, 0x5C, 0x76, 0x12, - 0xCE, 0x25, 0x79, 0x29, 0x39, 0x62, 0x08, 0x24, - 0xA5, 0x85, 0x7B, 0x56, 0x01, 0x23, 0x68, 0xCF, - 0x0A, 0xE2, 0x5A, 0xED, 0x3D, 0x59, 0xB0, 0xA9, - 0xB0, 0x2C, 0xF2, 0xB8, 0xEF, 0x32, 0xA9, 0x40, - 0x80, 0x71, 0xAF, 0x1E, 0xDE, 0x8F, 0x58, 0x88, - 0xB8, 0x3A, 0xD0, 0xFC, 0xC4, 0x1E, 0xB5, 0xA0, - 0xBB, 0x3B, 0x0F, 0x01, 0x7E, 0x1F, 0x9F, 0xD9, - 0xAA, 0xB8, 0x3D, 0x9D, 0x74, 0x1E, 0x25, 0xDB, - 0x37, 0x56, 0x8F, 0x16, 0xBA, 0x49, 0x2B, 0xAC, - 0xD0, 0xBD, 0x95, 0x20, 0xBE, 0x7A, 0x28, 0xD0, - 0x51, 0x64, 0x63, 0x1C, 0x7F, 0x66, 0x10, 0xBB, - 0xC4, 0x56, 0x1A, 0x04, 0x6E, 0x0A, 0xEC, 0x9C, - 0xD6, 0xE8, 0x9A, 0x7A, 0xCF, 0x8C, 0xDB, 0xB1, - 0xEF, 0x71, 0xDE, 0x31, 0xFF, 0x54, 0x3E, 0x5E, - 0x07, 0x69, 0x96, 0xB0, 0xCF, 0xDD, 0x9E, 0x47, - 0xC7, 0x96, 0x8F, 0xE4, 0x2B, 0x59, 0xC6, 0xEE, - 0xB9, 0x86, 0x9A, 0x64, 0x84, 0x72, 0xE2, 0x5B, - 0xA2, 0x96, 0x58, 0x99, 0x50, 0x03, 0xF5, 0x38, - 0x4D, 0x02, 0x7D, 0xE7, 0x7D, 0x75, 0xA7, 0xB8, - 0x67, 0x87, 0x84, 0x3F, 0x1D, 0x11, 0xE5, 0xFC, - 0x1E, 0xD3, 0x83, 0x16, 0xA5, 0x29, 0xF6, 0xC7, - 0x15, 0x61, 0x29, 0x1A, 0x43, 0x4F, 0x9B, 0xAF, - 0xC5, 0x87, 0x34, 0x6C, 0x0F, 0x3B, 0xA8, 0x1D, - 0x45, 0x58, 0x25, 0xDC, 0xA8, 0xA3, 0x3B, 0xD1, - 0x79, 0x1B, 0x48, 0xF2, 0xE9, 0x93, 0x1F, 0xFC, - 0xDB, 0x2A, 0x90, 0xA9, 0x8A, 0x3D, 0x39, 0x18, - 0xA3, 0x8E, 0x58, 0x6C, 0xE0, 0x12, 0xBB, 0x25, - 0xCD, 0x71, 0x22, 0xA2, 0x64, 0xC6, 0xE7, 0xFB, - 0xAD, 0x94, 0x77, 0x04, 0x9A, 0x39, 0xCF, 0x7C -}; - -unsigned char CSStable1[] = { - 0x8C, 0x47, 0xB0, 0xE1, 0xEB, 0xFC, 0xEB, 0x56, - 0x10, 0xE5, 0x2C, 0x1A, 0x5D, 0xEF, 0xBE, 0x4F, - 0x08, 0x75, 0x97, 0x4B, 0x0E, 0x25, 0x8E, 0x6E, - 0x39, 0x5A, 0x87, 0x53, 0xC4, 0x1F, 0xF4, 0x5C, - 0x4E, 0xE6, 0x99, 0x30, 0xE0, 0x42, 0x88, 0xAB, - 0xE5, 0x85, 0xBC, 0x8F, 0xD8, 0x3C, 0x54, 0xC9, - 0x53, 0x47, 0x18, 0xD6, 0x06, 0x5B, 0x41, 0x2C, - 0x67, 0x1E, 0x41, 0x74, 0x33, 0xE2, 0xB4, 0xE0, - 0x23, 0x29, 0x42, 0xEA, 0x55, 0x0F, 0x25, 0xB4, - 0x24, 0x2C, 0x99, 0x13, 0xEB, 0x0A, 0x0B, 0xC9, - 0xF9, 0x63, 0x67, 0x43, 0x2D, 0xC7, 0x7D, 0x07, - 0x60, 0x89, 0xD1, 0xCC, 0xE7, 0x94, 0x77, 0x74, - 0x9B, 0x7E, 0xD7, 0xE6, 0xFF, 0xBB, 0x68, 0x14, - 0x1E, 0xA3, 0x25, 0xDE, 0x3A, 0xA3, 0x54, 0x7B, - 0x87, 0x9D, 0x50, 0xCA, 0x27, 0xC3, 0xA4, 0x50, - 0x91, 0x27, 0xD4, 0xB0, 0x82, 0x41, 0x97, 0x79, - 0x94, 0x82, 0xAC, 0xC7, 0x8E, 0xA5, 0x4E, 0xAA, - 0x78, 0x9E, 0xE0, 0x42, 0xBA, 0x28, 0xEA, 0xB7, - 0x74, 0xAD, 0x35, 0xDA, 0x92, 0x60, 0x7E, 0xD2, - 0x0E, 0xB9, 0x24, 0x5E, 0x39, 0x4F, 0x5E, 0x63, - 0x09, 0xB5, 0xFA, 0xBF, 0xF1, 0x22, 0x55, 0x1C, - 0xE2, 0x25, 0xDB, 0xC5, 0xD8, 0x50, 0x03, 0x98, - 0xC4, 0xAC, 0x2E, 0x11, 0xB4, 0x38, 0x4D, 0xD0, - 0xB9, 0xFC, 0x2D, 0x3C, 0x08, 0x04, 0x5A, 0xEF, - 0xCE, 0x32, 0xFB, 0x4C, 0x92, 0x1E, 0x4B, 0xFB, - 0x1A, 0xD0, 0xE2, 0x3E, 0xDA, 0x6E, 0x7C, 0x4D, - 0x56, 0xC3, 0x3F, 0x42, 0xB1, 0x3A, 0x23, 0x4D, - 0x6E, 0x84, 0x56, 0x68, 0xF4, 0x0E, 0x03, 0x64, - 0xD0, 0xA9, 0x92, 0x2F, 0x8B, 0xBC, 0x39, 0x9C, - 0xAC, 0x09, 0x5E, 0xEE, 0xE5, 0x97, 0xBF, 0xA5, - 0xCE, 0xFA, 0x28, 0x2C, 0x6D, 0x4F, 0xEF, 0x77, - 0xAA, 0x1B, 0x79, 0x8E, 0x97, 0xB4, 0xC3, 0xF4 -}; - -unsigned char CSStable2[] = { - 0xB7, 0x75, 0x81, 0xD5, 0xDC, 0xCA, 0xDE, 0x66, - 0x23, 0xDF, 0x15, 0x26, 0x62, 0xD1, 0x83, 0x77, - 0xE3, 0x97, 0x76, 0xAF, 0xE9, 0xC3, 0x6B, 0x8E, - 0xDA, 0xB0, 0x6E, 0xBF, 0x2B, 0xF1, 0x19, 0xB4, - 0x95, 0x34, 0x48, 0xE4, 0x37, 0x94, 0x5D, 0x7B, - 0x36, 0x5F, 0x65, 0x53, 0x07, 0xE2, 0x89, 0x11, - 0x98, 0x85, 0xD9, 0x12, 0xC1, 0x9D, 0x84, 0xEC, - 0xA4, 0xD4, 0x88, 0xB8, 0xFC, 0x2C, 0x79, 0x28, - 0xD8, 0xDB, 0xB3, 0x1E, 0xA2, 0xF9, 0xD0, 0x44, - 0xD7, 0xD6, 0x60, 0xEF, 0x14, 0xF4, 0xF6, 0x31, - 0xD2, 0x41, 0x46, 0x67, 0x0A, 0xE1, 0x58, 0x27, - 0x43, 0xA3, 0xF8, 0xE0, 0xC8, 0xBA, 0x5A, 0x5C, - 0x80, 0x6C, 0xC6, 0xF2, 0xE8, 0xAD, 0x7D, 0x04, - 0x0D, 0xB9, 0x3C, 0xC2, 0x25, 0xBD, 0x49, 0x63, - 0x8C, 0x9F, 0x51, 0xCE, 0x20, 0xC5, 0xA1, 0x50, - 0x92, 0x2D, 0xDD, 0xBC, 0x8D, 0x4F, 0x9A, 0x71, - 0x2F, 0x30, 0x1D, 0x73, 0x39, 0x13, 0xFB, 0x1A, - 0xCB, 0x24, 0x59, 0xFE, 0x05, 0x96, 0x57, 0x0F, - 0x1F, 0xCF, 0x54, 0xBE, 0xF5, 0x06, 0x1B, 0xB2, - 0x6D, 0xD3, 0x4D, 0x32, 0x56, 0x21, 0x33, 0x0B, - 0x52, 0xE7, 0xAB, 0xEB, 0xA6, 0x74, 0x00, 0x4C, - 0xB1, 0x7F, 0x82, 0x99, 0x87, 0x0E, 0x5E, 0xC0, - 0x8F, 0xEE, 0x6F, 0x55, 0xF3, 0x7E, 0x08, 0x90, - 0xFA, 0xB6, 0x64, 0x70, 0x47, 0x4A, 0x17, 0xA7, - 0xB5, 0x40, 0x8A, 0x38, 0xE5, 0x68, 0x3E, 0x8B, - 0x69, 0xAA, 0x9B, 0x42, 0xA5, 0x10, 0x01, 0x35, - 0xFD, 0x61, 0x9E, 0xE6, 0x16, 0x9C, 0x86, 0xED, - 0xCD, 0x2E, 0xFF, 0xC4, 0x5B, 0xA0, 0xAE, 0xCC, - 0x4B, 0x3B, 0x03, 0xBB, 0x1C, 0x2A, 0xAC, 0x0C, - 0x3F, 0x93, 0xC7, 0x72, 0x7A, 0x09, 0x22, 0x3D, - 0x45, 0x78, 0xA9, 0xA8, 0xEA, 0xC9, 0x6A, 0xF7, - 0x29, 0x91, 0xF0, 0x02, 0x18, 0x3A, 0x4E, 0x7C -}; - -unsigned char CSStable3[] = { - 0x73, 0x51, 0x95, 0xE1, 0x12, 0xE4, 0xC0, 0x58, - 0xEE, 0xF2, 0x08, 0x1B, 0xA9, 0xFA, 0x98, 0x4C, - 0xA7, 0x33, 0xE2, 0x1B, 0xA7, 0x6D, 0xF5, 0x30, - 0x97, 0x1D, 0xF3, 0x02, 0x60, 0x5A, 0x82, 0x0F, - 0x91, 0xD0, 0x9C, 0x10, 0x39, 0x7A, 0x83, 0x85, - 0x3B, 0xB2, 0xB8, 0xAE, 0x0C, 0x09, 0x52, 0xEA, - 0x1C, 0xE1, 0x8D, 0x66, 0x4F, 0xF3, 0xDA, 0x92, - 0x29, 0xB9, 0xD5, 0xC5, 0x77, 0x47, 0x22, 0x53, - 0x14, 0xF7, 0xAF, 0x22, 0x64, 0xDF, 0xC6, 0x72, - 0x12, 0xF3, 0x75, 0xDA, 0xD7, 0xD7, 0xE5, 0x02, - 0x9E, 0xED, 0xDA, 0xDB, 0x4C, 0x47, 0xCE, 0x91, - 0x06, 0x06, 0x6D, 0x55, 0x8B, 0x19, 0xC9, 0xEF, - 0x8C, 0x80, 0x1A, 0x0E, 0xEE, 0x4B, 0xAB, 0xF2, - 0x08, 0x5C, 0xE9, 0x37, 0x26, 0x5E, 0x9A, 0x90, - 0x00, 0xF3, 0x0D, 0xB2, 0xA6, 0xA3, 0xF7, 0x26, - 0x17, 0x48, 0x88, 0xC9, 0x0E, 0x2C, 0xC9, 0x02, - 0xE7, 0x18, 0x05, 0x4B, 0xF3, 0x39, 0xE1, 0x20, - 0x02, 0x0D, 0x40, 0xC7, 0xCA, 0xB9, 0x48, 0x30, - 0x57, 0x67, 0xCC, 0x06, 0xBF, 0xAC, 0x81, 0x08, - 0x24, 0x7A, 0xD4, 0x8B, 0x19, 0x8E, 0xAC, 0xB4, - 0x5A, 0x0F, 0x73, 0x13, 0xAC, 0x9E, 0xDA, 0xB6, - 0xB8, 0x96, 0x5B, 0x60, 0x88, 0xE1, 0x81, 0x3F, - 0x07, 0x86, 0x37, 0x2D, 0x79, 0x14, 0x52, 0xEA, - 0x73, 0xDF, 0x3D, 0x09, 0xC8, 0x25, 0x48, 0xD8, - 0x75, 0x60, 0x9A, 0x08, 0x27, 0x4A, 0x2C, 0xB9, - 0xA8, 0x8B, 0x8A, 0x73, 0x62, 0x37, 0x16, 0x02, - 0xBD, 0xC1, 0x0E, 0x56, 0x54, 0x3E, 0x14, 0x5F, - 0x8C, 0x8F, 0x6E, 0x75, 0x1C, 0x07, 0x39, 0x7B, - 0x4B, 0xDB, 0xD3, 0x4B, 0x1E, 0xC8, 0x7E, 0xFE, - 0x3E, 0x72, 0x16, 0x83, 0x7D, 0xEE, 0xF5, 0xCA, - 0xC5, 0x18, 0xF9, 0xD8, 0x68, 0xAB, 0x38, 0x85, - 0xA8, 0xF0, 0xA1, 0x73, 0x9F, 0x5D, 0x19, 0x0B, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x33, 0x72, 0x39, 0x25, 0x67, 0x26, 0x6D, 0x71, - 0x36, 0x77, 0x3C, 0x20, 0x62, 0x23, 0x68, 0x74, - 0xC3, 0x82, 0xC9, 0x15, 0x57, 0x16, 0x5D, 0x81 -}; +#include "stdafx.h" + +static void CSSengine(int varient,unsigned char const *input,unsigned char *output); + +void CSSkey1(int varient,unsigned char const *challenge,unsigned char *key) +{ + static unsigned char perm_challenge[] = {1,3,0,7,5, 2,9,6,4,8}; + + unsigned char scratch[10]; + int i; + + for (i = 9; i >= 0; --i) { + scratch[i] = challenge[perm_challenge[i]]; + } + + CSSengine(varient, scratch, key); +} + +void CSSkey2(int varient,unsigned char const *challenge,unsigned char *key) +{ + static unsigned char perm_challenge[] = {6,1,9,3,8, 5,7,4,0,2}; + + static unsigned char perm_varient[] = { + 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d, + 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d, + 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05, + 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 + }; + + unsigned char scratch[10]; + int i; + + for (i = 9; i >= 0; --i) { + scratch[i] = challenge[perm_challenge[i]]; + } + + CSSengine(perm_varient[varient], scratch, key); +} + +void CSSbuskey(int varient,unsigned char const *challenge,unsigned char *key) +{ + static unsigned char perm_challenge[] = {4,0,3,5,7, 2,8,6,1,9}; + static unsigned char perm_varient[] = { + 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e, + 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c, + 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f, + 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d + }; + + unsigned char scratch[10]; + int i; + + for (i = 9; i >= 0; --i) { + scratch[i] = challenge[perm_challenge[i]]; + } + + CSSengine(perm_varient[varient], scratch, key); +} + +static void CSSgenbits(unsigned char *output, int len,unsigned char const *s) +{ + unsigned long lfsr0, lfsr1; + unsigned char b1_combined; /* Save the old value of bit 1 for feedback */ + + /* In order to ensure that the LFSR works we need to ensure that the + * initial values are non-zero. Thus when we initialise them from + * the seed, we ensure that a bit is set. + */ + lfsr0 = (s[0] << 17) | (s[1] << 9) | ((s[2] & ~7) << 1) | 8 | (s[2] & 7); + lfsr1 = (s[3] << 9) | 0x100 | s[4]; + + ++output; + + b1_combined = 0; + do { + int bit; + unsigned char val; + + for (bit = 0, val = 0; bit < 8; ++bit) { + unsigned char o_lfsr0, o_lfsr1; /* Actually only 1 bit each */ + unsigned char combined; + + o_lfsr0 = ((lfsr0 >> 24) ^ (lfsr0 >> 21) ^ (lfsr0 >> 20) ^ (lfsr0 >> 12)) & 1; + lfsr0 = (lfsr0 << 1) | o_lfsr0; + + o_lfsr1 = ((lfsr1 >> 16) ^ (lfsr1 >> 2)) & 1; + lfsr1 = (lfsr1 << 1) | o_lfsr1; + +#define BIT0(x) ((x) & 1) +#define BIT1(x) (((x) >> 1) & 1) + + combined = !o_lfsr1 + b1_combined + !o_lfsr0; + b1_combined = BIT1(combined); + val |= BIT0(combined) << bit; + } + + *--output = val; + } while (--len > 0); +} + +unsigned char CSSsecret[]; +unsigned char CSSvarients[]; +unsigned char CSStable0[]; +unsigned char CSStable1[]; +unsigned char CSStable2[]; +unsigned char CSStable3[]; + +static void CSSengine(int varient, unsigned char const *input,unsigned char *output) +{ + unsigned char cse, term, index; + unsigned char temp1[5]; + unsigned char temp2[5]; + unsigned char bits[30]; + + int i; + + /* Feed the CSSsecret into the input values such that + * we alter the seed to the LFSR's used above, then + * generate the bits to play with. + */ + for (i = 5; --i >= 0; ) { + temp1[i] = input[5 + i] ^ CSSsecret[i] ^ CSStable2[i]; + } + + CSSgenbits(&bits[29], sizeof bits, temp1); + + /* This term is used throughout the following to + * select one of 32 different variations on the + * algorithm. + */ + cse = CSSvarients[varient] ^ CSStable2[varient]; + + /* Now the actual blocks doing the encryption. Each + * of these works on 40 bits at a time and are quite + * similar. + */ + for (i = 5, term = 0; --i >= 0; term = input[i]) { + index = bits[25 + i] ^ input[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + temp1[i] = CSStable2[index] ^ CSStable3[index] ^ term; + } + temp1[4] ^= temp1[0]; + + for (i = 5, term = 0; --i >= 0; term = temp1[i]) { + index = bits[20 + i] ^ temp1[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + temp2[i] = CSStable2[index] ^ CSStable3[index] ^ term; + } + temp2[4] ^= temp2[0]; + + for (i = 5, term = 0; --i >= 0; term = temp2[i]) { + index = bits[15 + i] ^ temp2[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + index = CSStable2[index] ^ CSStable3[index] ^ term; + + temp1[i] = CSStable0[index] ^ CSStable2[index]; + } + temp1[4] ^= temp1[0]; + + for (i = 5, term = 0; --i >= 0; term = temp1[i]) { + index = bits[10 + i] ^ temp1[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + index = CSStable2[index] ^ CSStable3[index] ^ term; + + temp2[i] = CSStable0[index] ^ CSStable2[index]; + } + temp2[4] ^= temp2[0]; + + for (i = 5, term = 0; --i >= 0; term = temp2[i]) { + index = bits[5 + i] ^ temp2[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + temp1[i] = CSStable2[index] ^ CSStable3[index] ^ term; + } + temp1[4] ^= temp1[0]; + + for (i = 5, term = 0; --i >= 0; term = temp1[i]) { + index = bits[i] ^ temp1[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + output[i] = CSStable2[index] ^ CSStable3[index] ^ term; + } +} + +unsigned char CSSvarients[] = { + 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73, + 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42, + 0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B, + 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 +}; + +unsigned char CSSsecret[] = {0x55, 0xD6, 0xC4, 0xC5, 0x28}; + +unsigned char CSStable0[] = { + 0xB7, 0xF4, 0x82, 0x57, 0xDA, 0x4D, 0xDB, 0xE2, + 0x2F, 0x52, 0x1A, 0xA8, 0x68, 0x5A, 0x8A, 0xFF, + 0xFB, 0x0E, 0x6D, 0x35, 0xF7, 0x5C, 0x76, 0x12, + 0xCE, 0x25, 0x79, 0x29, 0x39, 0x62, 0x08, 0x24, + 0xA5, 0x85, 0x7B, 0x56, 0x01, 0x23, 0x68, 0xCF, + 0x0A, 0xE2, 0x5A, 0xED, 0x3D, 0x59, 0xB0, 0xA9, + 0xB0, 0x2C, 0xF2, 0xB8, 0xEF, 0x32, 0xA9, 0x40, + 0x80, 0x71, 0xAF, 0x1E, 0xDE, 0x8F, 0x58, 0x88, + 0xB8, 0x3A, 0xD0, 0xFC, 0xC4, 0x1E, 0xB5, 0xA0, + 0xBB, 0x3B, 0x0F, 0x01, 0x7E, 0x1F, 0x9F, 0xD9, + 0xAA, 0xB8, 0x3D, 0x9D, 0x74, 0x1E, 0x25, 0xDB, + 0x37, 0x56, 0x8F, 0x16, 0xBA, 0x49, 0x2B, 0xAC, + 0xD0, 0xBD, 0x95, 0x20, 0xBE, 0x7A, 0x28, 0xD0, + 0x51, 0x64, 0x63, 0x1C, 0x7F, 0x66, 0x10, 0xBB, + 0xC4, 0x56, 0x1A, 0x04, 0x6E, 0x0A, 0xEC, 0x9C, + 0xD6, 0xE8, 0x9A, 0x7A, 0xCF, 0x8C, 0xDB, 0xB1, + 0xEF, 0x71, 0xDE, 0x31, 0xFF, 0x54, 0x3E, 0x5E, + 0x07, 0x69, 0x96, 0xB0, 0xCF, 0xDD, 0x9E, 0x47, + 0xC7, 0x96, 0x8F, 0xE4, 0x2B, 0x59, 0xC6, 0xEE, + 0xB9, 0x86, 0x9A, 0x64, 0x84, 0x72, 0xE2, 0x5B, + 0xA2, 0x96, 0x58, 0x99, 0x50, 0x03, 0xF5, 0x38, + 0x4D, 0x02, 0x7D, 0xE7, 0x7D, 0x75, 0xA7, 0xB8, + 0x67, 0x87, 0x84, 0x3F, 0x1D, 0x11, 0xE5, 0xFC, + 0x1E, 0xD3, 0x83, 0x16, 0xA5, 0x29, 0xF6, 0xC7, + 0x15, 0x61, 0x29, 0x1A, 0x43, 0x4F, 0x9B, 0xAF, + 0xC5, 0x87, 0x34, 0x6C, 0x0F, 0x3B, 0xA8, 0x1D, + 0x45, 0x58, 0x25, 0xDC, 0xA8, 0xA3, 0x3B, 0xD1, + 0x79, 0x1B, 0x48, 0xF2, 0xE9, 0x93, 0x1F, 0xFC, + 0xDB, 0x2A, 0x90, 0xA9, 0x8A, 0x3D, 0x39, 0x18, + 0xA3, 0x8E, 0x58, 0x6C, 0xE0, 0x12, 0xBB, 0x25, + 0xCD, 0x71, 0x22, 0xA2, 0x64, 0xC6, 0xE7, 0xFB, + 0xAD, 0x94, 0x77, 0x04, 0x9A, 0x39, 0xCF, 0x7C +}; + +unsigned char CSStable1[] = { + 0x8C, 0x47, 0xB0, 0xE1, 0xEB, 0xFC, 0xEB, 0x56, + 0x10, 0xE5, 0x2C, 0x1A, 0x5D, 0xEF, 0xBE, 0x4F, + 0x08, 0x75, 0x97, 0x4B, 0x0E, 0x25, 0x8E, 0x6E, + 0x39, 0x5A, 0x87, 0x53, 0xC4, 0x1F, 0xF4, 0x5C, + 0x4E, 0xE6, 0x99, 0x30, 0xE0, 0x42, 0x88, 0xAB, + 0xE5, 0x85, 0xBC, 0x8F, 0xD8, 0x3C, 0x54, 0xC9, + 0x53, 0x47, 0x18, 0xD6, 0x06, 0x5B, 0x41, 0x2C, + 0x67, 0x1E, 0x41, 0x74, 0x33, 0xE2, 0xB4, 0xE0, + 0x23, 0x29, 0x42, 0xEA, 0x55, 0x0F, 0x25, 0xB4, + 0x24, 0x2C, 0x99, 0x13, 0xEB, 0x0A, 0x0B, 0xC9, + 0xF9, 0x63, 0x67, 0x43, 0x2D, 0xC7, 0x7D, 0x07, + 0x60, 0x89, 0xD1, 0xCC, 0xE7, 0x94, 0x77, 0x74, + 0x9B, 0x7E, 0xD7, 0xE6, 0xFF, 0xBB, 0x68, 0x14, + 0x1E, 0xA3, 0x25, 0xDE, 0x3A, 0xA3, 0x54, 0x7B, + 0x87, 0x9D, 0x50, 0xCA, 0x27, 0xC3, 0xA4, 0x50, + 0x91, 0x27, 0xD4, 0xB0, 0x82, 0x41, 0x97, 0x79, + 0x94, 0x82, 0xAC, 0xC7, 0x8E, 0xA5, 0x4E, 0xAA, + 0x78, 0x9E, 0xE0, 0x42, 0xBA, 0x28, 0xEA, 0xB7, + 0x74, 0xAD, 0x35, 0xDA, 0x92, 0x60, 0x7E, 0xD2, + 0x0E, 0xB9, 0x24, 0x5E, 0x39, 0x4F, 0x5E, 0x63, + 0x09, 0xB5, 0xFA, 0xBF, 0xF1, 0x22, 0x55, 0x1C, + 0xE2, 0x25, 0xDB, 0xC5, 0xD8, 0x50, 0x03, 0x98, + 0xC4, 0xAC, 0x2E, 0x11, 0xB4, 0x38, 0x4D, 0xD0, + 0xB9, 0xFC, 0x2D, 0x3C, 0x08, 0x04, 0x5A, 0xEF, + 0xCE, 0x32, 0xFB, 0x4C, 0x92, 0x1E, 0x4B, 0xFB, + 0x1A, 0xD0, 0xE2, 0x3E, 0xDA, 0x6E, 0x7C, 0x4D, + 0x56, 0xC3, 0x3F, 0x42, 0xB1, 0x3A, 0x23, 0x4D, + 0x6E, 0x84, 0x56, 0x68, 0xF4, 0x0E, 0x03, 0x64, + 0xD0, 0xA9, 0x92, 0x2F, 0x8B, 0xBC, 0x39, 0x9C, + 0xAC, 0x09, 0x5E, 0xEE, 0xE5, 0x97, 0xBF, 0xA5, + 0xCE, 0xFA, 0x28, 0x2C, 0x6D, 0x4F, 0xEF, 0x77, + 0xAA, 0x1B, 0x79, 0x8E, 0x97, 0xB4, 0xC3, 0xF4 +}; + +unsigned char CSStable2[] = { + 0xB7, 0x75, 0x81, 0xD5, 0xDC, 0xCA, 0xDE, 0x66, + 0x23, 0xDF, 0x15, 0x26, 0x62, 0xD1, 0x83, 0x77, + 0xE3, 0x97, 0x76, 0xAF, 0xE9, 0xC3, 0x6B, 0x8E, + 0xDA, 0xB0, 0x6E, 0xBF, 0x2B, 0xF1, 0x19, 0xB4, + 0x95, 0x34, 0x48, 0xE4, 0x37, 0x94, 0x5D, 0x7B, + 0x36, 0x5F, 0x65, 0x53, 0x07, 0xE2, 0x89, 0x11, + 0x98, 0x85, 0xD9, 0x12, 0xC1, 0x9D, 0x84, 0xEC, + 0xA4, 0xD4, 0x88, 0xB8, 0xFC, 0x2C, 0x79, 0x28, + 0xD8, 0xDB, 0xB3, 0x1E, 0xA2, 0xF9, 0xD0, 0x44, + 0xD7, 0xD6, 0x60, 0xEF, 0x14, 0xF4, 0xF6, 0x31, + 0xD2, 0x41, 0x46, 0x67, 0x0A, 0xE1, 0x58, 0x27, + 0x43, 0xA3, 0xF8, 0xE0, 0xC8, 0xBA, 0x5A, 0x5C, + 0x80, 0x6C, 0xC6, 0xF2, 0xE8, 0xAD, 0x7D, 0x04, + 0x0D, 0xB9, 0x3C, 0xC2, 0x25, 0xBD, 0x49, 0x63, + 0x8C, 0x9F, 0x51, 0xCE, 0x20, 0xC5, 0xA1, 0x50, + 0x92, 0x2D, 0xDD, 0xBC, 0x8D, 0x4F, 0x9A, 0x71, + 0x2F, 0x30, 0x1D, 0x73, 0x39, 0x13, 0xFB, 0x1A, + 0xCB, 0x24, 0x59, 0xFE, 0x05, 0x96, 0x57, 0x0F, + 0x1F, 0xCF, 0x54, 0xBE, 0xF5, 0x06, 0x1B, 0xB2, + 0x6D, 0xD3, 0x4D, 0x32, 0x56, 0x21, 0x33, 0x0B, + 0x52, 0xE7, 0xAB, 0xEB, 0xA6, 0x74, 0x00, 0x4C, + 0xB1, 0x7F, 0x82, 0x99, 0x87, 0x0E, 0x5E, 0xC0, + 0x8F, 0xEE, 0x6F, 0x55, 0xF3, 0x7E, 0x08, 0x90, + 0xFA, 0xB6, 0x64, 0x70, 0x47, 0x4A, 0x17, 0xA7, + 0xB5, 0x40, 0x8A, 0x38, 0xE5, 0x68, 0x3E, 0x8B, + 0x69, 0xAA, 0x9B, 0x42, 0xA5, 0x10, 0x01, 0x35, + 0xFD, 0x61, 0x9E, 0xE6, 0x16, 0x9C, 0x86, 0xED, + 0xCD, 0x2E, 0xFF, 0xC4, 0x5B, 0xA0, 0xAE, 0xCC, + 0x4B, 0x3B, 0x03, 0xBB, 0x1C, 0x2A, 0xAC, 0x0C, + 0x3F, 0x93, 0xC7, 0x72, 0x7A, 0x09, 0x22, 0x3D, + 0x45, 0x78, 0xA9, 0xA8, 0xEA, 0xC9, 0x6A, 0xF7, + 0x29, 0x91, 0xF0, 0x02, 0x18, 0x3A, 0x4E, 0x7C +}; + +unsigned char CSStable3[] = { + 0x73, 0x51, 0x95, 0xE1, 0x12, 0xE4, 0xC0, 0x58, + 0xEE, 0xF2, 0x08, 0x1B, 0xA9, 0xFA, 0x98, 0x4C, + 0xA7, 0x33, 0xE2, 0x1B, 0xA7, 0x6D, 0xF5, 0x30, + 0x97, 0x1D, 0xF3, 0x02, 0x60, 0x5A, 0x82, 0x0F, + 0x91, 0xD0, 0x9C, 0x10, 0x39, 0x7A, 0x83, 0x85, + 0x3B, 0xB2, 0xB8, 0xAE, 0x0C, 0x09, 0x52, 0xEA, + 0x1C, 0xE1, 0x8D, 0x66, 0x4F, 0xF3, 0xDA, 0x92, + 0x29, 0xB9, 0xD5, 0xC5, 0x77, 0x47, 0x22, 0x53, + 0x14, 0xF7, 0xAF, 0x22, 0x64, 0xDF, 0xC6, 0x72, + 0x12, 0xF3, 0x75, 0xDA, 0xD7, 0xD7, 0xE5, 0x02, + 0x9E, 0xED, 0xDA, 0xDB, 0x4C, 0x47, 0xCE, 0x91, + 0x06, 0x06, 0x6D, 0x55, 0x8B, 0x19, 0xC9, 0xEF, + 0x8C, 0x80, 0x1A, 0x0E, 0xEE, 0x4B, 0xAB, 0xF2, + 0x08, 0x5C, 0xE9, 0x37, 0x26, 0x5E, 0x9A, 0x90, + 0x00, 0xF3, 0x0D, 0xB2, 0xA6, 0xA3, 0xF7, 0x26, + 0x17, 0x48, 0x88, 0xC9, 0x0E, 0x2C, 0xC9, 0x02, + 0xE7, 0x18, 0x05, 0x4B, 0xF3, 0x39, 0xE1, 0x20, + 0x02, 0x0D, 0x40, 0xC7, 0xCA, 0xB9, 0x48, 0x30, + 0x57, 0x67, 0xCC, 0x06, 0xBF, 0xAC, 0x81, 0x08, + 0x24, 0x7A, 0xD4, 0x8B, 0x19, 0x8E, 0xAC, 0xB4, + 0x5A, 0x0F, 0x73, 0x13, 0xAC, 0x9E, 0xDA, 0xB6, + 0xB8, 0x96, 0x5B, 0x60, 0x88, 0xE1, 0x81, 0x3F, + 0x07, 0x86, 0x37, 0x2D, 0x79, 0x14, 0x52, 0xEA, + 0x73, 0xDF, 0x3D, 0x09, 0xC8, 0x25, 0x48, 0xD8, + 0x75, 0x60, 0x9A, 0x08, 0x27, 0x4A, 0x2C, 0xB9, + 0xA8, 0x8B, 0x8A, 0x73, 0x62, 0x37, 0x16, 0x02, + 0xBD, 0xC1, 0x0E, 0x56, 0x54, 0x3E, 0x14, 0x5F, + 0x8C, 0x8F, 0x6E, 0x75, 0x1C, 0x07, 0x39, 0x7B, + 0x4B, 0xDB, 0xD3, 0x4B, 0x1E, 0xC8, 0x7E, 0xFE, + 0x3E, 0x72, 0x16, 0x83, 0x7D, 0xEE, 0xF5, 0xCA, + 0xC5, 0x18, 0xF9, 0xD8, 0x68, 0xAB, 0x38, 0x85, + 0xA8, 0xF0, 0xA1, 0x73, 0x9F, 0x5D, 0x19, 0x0B, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x72, 0x39, 0x25, 0x67, 0x26, 0x6D, 0x71, + 0x36, 0x77, 0x3C, 0x20, 0x62, 0x23, 0x68, 0x74, + 0xC3, 0x82, 0xC9, 0x15, 0x57, 0x16, 0x5D, 0x81 +}; diff --git a/src/DeCSS/CSSauth.h b/src/DeCSS/CSSauth.h index 9929ae887d7..ee2950cdf09 100644 --- a/src/DeCSS/CSSauth.h +++ b/src/DeCSS/CSSauth.h @@ -1,5 +1,5 @@ -#pragma once - -extern void CSSkey1(int varient, byte const *challenge, byte *key); -extern void CSSkey2(int varient, byte const *challenge, byte *key); -extern void CSSbuskey(int varient, byte const *challenge, byte *key); +#pragma once + +extern void CSSkey1(int varient, byte const *challenge, byte *key); +extern void CSSkey2(int varient, byte const *challenge, byte *key); +extern void CSSbuskey(int varient, byte const *challenge, byte *key); diff --git a/src/DeCSS/CSSscramble.cpp b/src/DeCSS/CSSscramble.cpp index 902c99f4fd8..43b6c3323ab 100644 --- a/src/DeCSS/CSSscramble.cpp +++ b/src/DeCSS/CSSscramble.cpp @@ -1,236 +1,236 @@ -#include "stdafx.h" - -static const unsigned int CSStab0[11]= {5,0,1,2,3,4,0,1,2,3,4}; - -static const unsigned char CSStab1[256]= { - 0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b, - 0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b, - 0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f, - 0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91, - 0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75, - 0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95, - 0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11, - 0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f, - 0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b, - 0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb, - 0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f, - 0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1, - 0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15, - 0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5, - 0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71, - 0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff -}; - -static const unsigned char CSStab2[256]= { - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, - 0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55, - 0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63, - 0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71, - 0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c, - 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e, - 0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8, - 0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa, - 0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5, - 0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, - 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1, - 0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3 -}; - -static const unsigned char CSStab3[512]= { - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff -}; - -static const unsigned char CSStab4[256]= { - 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, - 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, - 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, - 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, - 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, - 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, - 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, - 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, - 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, - 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, - 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, - 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, - 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, - 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, - 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, - 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff -}; - -static const unsigned char CSStab5[256]= { - 0xff,0x7f,0xbf,0x3f,0xdf,0x5f,0x9f,0x1f,0xef,0x6f,0xaf,0x2f,0xcf,0x4f,0x8f,0x0f, - 0xf7,0x77,0xb7,0x37,0xd7,0x57,0x97,0x17,0xe7,0x67,0xa7,0x27,0xc7,0x47,0x87,0x07, - 0xfb,0x7b,0xbb,0x3b,0xdb,0x5b,0x9b,0x1b,0xeb,0x6b,0xab,0x2b,0xcb,0x4b,0x8b,0x0b, - 0xf3,0x73,0xb3,0x33,0xd3,0x53,0x93,0x13,0xe3,0x63,0xa3,0x23,0xc3,0x43,0x83,0x03, - 0xfd,0x7d,0xbd,0x3d,0xdd,0x5d,0x9d,0x1d,0xed,0x6d,0xad,0x2d,0xcd,0x4d,0x8d,0x0d, - 0xf5,0x75,0xb5,0x35,0xd5,0x55,0x95,0x15,0xe5,0x65,0xa5,0x25,0xc5,0x45,0x85,0x05, - 0xf9,0x79,0xb9,0x39,0xd9,0x59,0x99,0x19,0xe9,0x69,0xa9,0x29,0xc9,0x49,0x89,0x09, - 0xf1,0x71,0xb1,0x31,0xd1,0x51,0x91,0x11,0xe1,0x61,0xa1,0x21,0xc1,0x41,0x81,0x01, - 0xfe,0x7e,0xbe,0x3e,0xde,0x5e,0x9e,0x1e,0xee,0x6e,0xae,0x2e,0xce,0x4e,0x8e,0x0e, - 0xf6,0x76,0xb6,0x36,0xd6,0x56,0x96,0x16,0xe6,0x66,0xa6,0x26,0xc6,0x46,0x86,0x06, - 0xfa,0x7a,0xba,0x3a,0xda,0x5a,0x9a,0x1a,0xea,0x6a,0xaa,0x2a,0xca,0x4a,0x8a,0x0a, - 0xf2,0x72,0xb2,0x32,0xd2,0x52,0x92,0x12,0xe2,0x62,0xa2,0x22,0xc2,0x42,0x82,0x02, - 0xfc,0x7c,0xbc,0x3c,0xdc,0x5c,0x9c,0x1c,0xec,0x6c,0xac,0x2c,0xcc,0x4c,0x8c,0x0c, - 0xf4,0x74,0xb4,0x34,0xd4,0x54,0x94,0x14,0xe4,0x64,0xa4,0x24,0xc4,0x44,0x84,0x04, - 0xf8,0x78,0xb8,0x38,0xd8,0x58,0x98,0x18,0xe8,0x68,0xa8,0x28,0xc8,0x48,0x88,0x08, - 0xf0,0x70,0xb0,0x30,0xd0,0x50,0x90,0x10,0xe0,0x60,0xa0,0x20,0xc0,0x40,0x80,0x00 -}; - -void CSSdescramble(unsigned char *sec,const unsigned char *tkey) -{ - unsigned int t1,t2,t3,t4,t5,t6; - unsigned char *end=sec+0x800; - - t1=tkey[0]^sec[0x54]|0x100; - t2=tkey[1]^sec[0x55]; - t3=(*((unsigned int *)(tkey+2)))^(*((unsigned int *)(sec+0x56))); - t4=t3&7; - t3=t3*2+8-t4; - sec+=0x80; - t5=0; - while(sec!=end) { - t4=CSStab2[t2]^CSStab3[t1]; - t2=t1>>1; - t1=((t1&1)<<8)^t4; - t4=CSStab5[t4]; - t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; - t3=(t3<<8)|t6; - t6=CSStab4[t6]; - t5+=t6+t4; - *sec++=CSStab1[*sec]^(t5&0xff); - t5>>=8; - } -} - -void CSSdisckey(unsigned char *dkey,const unsigned char *pkey) -{ - unsigned int t1,t2,t3,t4,t5,t6; - unsigned char k[5]; - int i; - - t1=pkey[0]|0x100; - t2=pkey[1]; - t3=*((unsigned int *)(pkey+2)); - t4=t3&7; - t3=t3*2+8-t4; - t5=0; - for(i=0; i<5; i++) { - t4=CSStab2[t2]^CSStab3[t1]; - t2=t1>>1; - t1=((t1&1)<<8)^t4; - t4=CSStab4[t4]; - t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; - t3=(t3<<8)|t6; - t6=CSStab4[t6]; - t5+=t6+t4; - k[i]=t5&0xff; - t5>>=8; - } - for(i=9; i>=0; i--) { - dkey[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[dkey[CSStab0[i+1]]]^dkey[CSStab0[i]]; - } -} - -void CSStitlekey(unsigned char *tkey,const unsigned char *dkey) -{ - unsigned int t1,t2,t3,t4,t5,t6; - unsigned char k[5]; - int i; - - t1=dkey[0]|0x100; - t2=dkey[1]; - t3=*((unsigned int *)(dkey+2)); - t4=t3&7; - t3=t3*2+8-t4; - t5=0; - for(i=0; i<5; i++) { - t4=CSStab2[t2]^CSStab3[t1]; - t2=t1>>1; - t1=((t1&1)<<8)^t4; - t4=CSStab4[t4]; - t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; - t3=(t3<<8)|t6; - t6=CSStab5[t6]; - t5+=t6+t4; - k[i]=t5&0xff; - t5>>=8; - } - for(i=9; i>=0; i--) { - tkey[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[tkey[CSStab0[i+1]]]^tkey[CSStab0[i]]; - } -} - -extern const unsigned char g_PlayerKeys[][6] = { - // from mplayer: - {0x01, 0xaf, 0xe3, 0x12, 0x80}, - {0x12, 0x11, 0xca, 0x04, 0x3b}, - {0x14, 0x0c, 0x9e, 0xd0, 0x09}, - {0x14, 0x71, 0x35, 0xba, 0xe2}, - {0x1a, 0xa4, 0x33, 0x21, 0xa6}, - {0x26, 0xec, 0xc4, 0xa7, 0x4e}, - {0x2c, 0xb2, 0xc1, 0x09, 0xee}, - {0x2f, 0x25, 0x9e, 0x96, 0xdd}, - {0x33, 0x2f, 0x49, 0x6c, 0xe0}, - {0x35, 0x5b, 0xc1, 0x31, 0x0f}, - {0x36, 0x67, 0xb2, 0xe3, 0x85}, - {0x39, 0x3d, 0xf1, 0xf1, 0xbd}, - {0x3b, 0x31, 0x34, 0x0d, 0x91}, - {0x45, 0xed, 0x28, 0xeb, 0xd3}, - {0x48, 0xb7, 0x6c, 0xce, 0x69}, - {0x4b, 0x65, 0x0d, 0xc1, 0xee}, - {0x4c, 0xbb, 0xf5, 0x5b, 0x23}, - {0x51, 0x67, 0x67, 0xc5, 0xe0}, - {0x53, 0x94, 0xe1, 0x75, 0xbf}, - {0x57, 0x2c, 0x8b, 0x31, 0xae}, - {0x63, 0xdb, 0x4c, 0x5b, 0x4a}, - {0x7b, 0x1e, 0x5e, 0x2b, 0x57}, - {0x85, 0xf3, 0x85, 0xa0, 0xe0}, - {0xab, 0x1e, 0xe7, 0x7b, 0x72}, - {0xab, 0x36, 0xe3, 0xeb, 0x76}, - {0xb1, 0xb8, 0xf9, 0x38, 0x03}, - {0xb8, 0x5d, 0xd8, 0x53, 0xbd}, - {0xbf, 0x92, 0xc3, 0xb0, 0xe2}, - {0xcf, 0x1a, 0xb2, 0xf8, 0x0a}, - {0xec, 0xa0, 0xcf, 0xb3, 0xff}, - {0xfc, 0x95, 0xa9, 0x87, 0x35} - // TODO: find more player keys -}; - -extern const int g_nPlayerKeys = _countof(g_PlayerKeys); +#include "stdafx.h" + +static const unsigned int CSStab0[11]= {5,0,1,2,3,4,0,1,2,3,4}; + +static const unsigned char CSStab1[256]= { + 0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b, + 0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b, + 0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f, + 0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91, + 0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75, + 0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95, + 0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11, + 0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f, + 0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b, + 0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb, + 0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f, + 0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1, + 0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15, + 0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5, + 0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71, + 0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff +}; + +static const unsigned char CSStab2[256]= { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, + 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, + 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, + 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, + 0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55, + 0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63, + 0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71, + 0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c, + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e, + 0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8, + 0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa, + 0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5, + 0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, + 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1, + 0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3 +}; + +static const unsigned char CSStab3[512]= { + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff +}; + +static const unsigned char CSStab4[256]= { + 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, + 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, + 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, + 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, + 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, + 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, + 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, + 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, + 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, + 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, + 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, + 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, + 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, + 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, + 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, + 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +}; + +static const unsigned char CSStab5[256]= { + 0xff,0x7f,0xbf,0x3f,0xdf,0x5f,0x9f,0x1f,0xef,0x6f,0xaf,0x2f,0xcf,0x4f,0x8f,0x0f, + 0xf7,0x77,0xb7,0x37,0xd7,0x57,0x97,0x17,0xe7,0x67,0xa7,0x27,0xc7,0x47,0x87,0x07, + 0xfb,0x7b,0xbb,0x3b,0xdb,0x5b,0x9b,0x1b,0xeb,0x6b,0xab,0x2b,0xcb,0x4b,0x8b,0x0b, + 0xf3,0x73,0xb3,0x33,0xd3,0x53,0x93,0x13,0xe3,0x63,0xa3,0x23,0xc3,0x43,0x83,0x03, + 0xfd,0x7d,0xbd,0x3d,0xdd,0x5d,0x9d,0x1d,0xed,0x6d,0xad,0x2d,0xcd,0x4d,0x8d,0x0d, + 0xf5,0x75,0xb5,0x35,0xd5,0x55,0x95,0x15,0xe5,0x65,0xa5,0x25,0xc5,0x45,0x85,0x05, + 0xf9,0x79,0xb9,0x39,0xd9,0x59,0x99,0x19,0xe9,0x69,0xa9,0x29,0xc9,0x49,0x89,0x09, + 0xf1,0x71,0xb1,0x31,0xd1,0x51,0x91,0x11,0xe1,0x61,0xa1,0x21,0xc1,0x41,0x81,0x01, + 0xfe,0x7e,0xbe,0x3e,0xde,0x5e,0x9e,0x1e,0xee,0x6e,0xae,0x2e,0xce,0x4e,0x8e,0x0e, + 0xf6,0x76,0xb6,0x36,0xd6,0x56,0x96,0x16,0xe6,0x66,0xa6,0x26,0xc6,0x46,0x86,0x06, + 0xfa,0x7a,0xba,0x3a,0xda,0x5a,0x9a,0x1a,0xea,0x6a,0xaa,0x2a,0xca,0x4a,0x8a,0x0a, + 0xf2,0x72,0xb2,0x32,0xd2,0x52,0x92,0x12,0xe2,0x62,0xa2,0x22,0xc2,0x42,0x82,0x02, + 0xfc,0x7c,0xbc,0x3c,0xdc,0x5c,0x9c,0x1c,0xec,0x6c,0xac,0x2c,0xcc,0x4c,0x8c,0x0c, + 0xf4,0x74,0xb4,0x34,0xd4,0x54,0x94,0x14,0xe4,0x64,0xa4,0x24,0xc4,0x44,0x84,0x04, + 0xf8,0x78,0xb8,0x38,0xd8,0x58,0x98,0x18,0xe8,0x68,0xa8,0x28,0xc8,0x48,0x88,0x08, + 0xf0,0x70,0xb0,0x30,0xd0,0x50,0x90,0x10,0xe0,0x60,0xa0,0x20,0xc0,0x40,0x80,0x00 +}; + +void CSSdescramble(unsigned char *sec,const unsigned char *tkey) +{ + unsigned int t1,t2,t3,t4,t5,t6; + unsigned char *end=sec+0x800; + + t1=tkey[0]^sec[0x54]|0x100; + t2=tkey[1]^sec[0x55]; + t3=(*((unsigned int *)(tkey+2)))^(*((unsigned int *)(sec+0x56))); + t4=t3&7; + t3=t3*2+8-t4; + sec+=0x80; + t5=0; + while(sec!=end) { + t4=CSStab2[t2]^CSStab3[t1]; + t2=t1>>1; + t1=((t1&1)<<8)^t4; + t4=CSStab5[t4]; + t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; + t3=(t3<<8)|t6; + t6=CSStab4[t6]; + t5+=t6+t4; + *sec++=CSStab1[*sec]^(t5&0xff); + t5>>=8; + } +} + +void CSSdisckey(unsigned char *dkey,const unsigned char *pkey) +{ + unsigned int t1,t2,t3,t4,t5,t6; + unsigned char k[5]; + int i; + + t1=pkey[0]|0x100; + t2=pkey[1]; + t3=*((unsigned int *)(pkey+2)); + t4=t3&7; + t3=t3*2+8-t4; + t5=0; + for(i=0; i<5; i++) { + t4=CSStab2[t2]^CSStab3[t1]; + t2=t1>>1; + t1=((t1&1)<<8)^t4; + t4=CSStab4[t4]; + t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; + t3=(t3<<8)|t6; + t6=CSStab4[t6]; + t5+=t6+t4; + k[i]=t5&0xff; + t5>>=8; + } + for(i=9; i>=0; i--) { + dkey[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[dkey[CSStab0[i+1]]]^dkey[CSStab0[i]]; + } +} + +void CSStitlekey(unsigned char *tkey,const unsigned char *dkey) +{ + unsigned int t1,t2,t3,t4,t5,t6; + unsigned char k[5]; + int i; + + t1=dkey[0]|0x100; + t2=dkey[1]; + t3=*((unsigned int *)(dkey+2)); + t4=t3&7; + t3=t3*2+8-t4; + t5=0; + for(i=0; i<5; i++) { + t4=CSStab2[t2]^CSStab3[t1]; + t2=t1>>1; + t1=((t1&1)<<8)^t4; + t4=CSStab4[t4]; + t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; + t3=(t3<<8)|t6; + t6=CSStab5[t6]; + t5+=t6+t4; + k[i]=t5&0xff; + t5>>=8; + } + for(i=9; i>=0; i--) { + tkey[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[tkey[CSStab0[i+1]]]^tkey[CSStab0[i]]; + } +} + +extern const unsigned char g_PlayerKeys[][6] = { + // from mplayer: + {0x01, 0xaf, 0xe3, 0x12, 0x80}, + {0x12, 0x11, 0xca, 0x04, 0x3b}, + {0x14, 0x0c, 0x9e, 0xd0, 0x09}, + {0x14, 0x71, 0x35, 0xba, 0xe2}, + {0x1a, 0xa4, 0x33, 0x21, 0xa6}, + {0x26, 0xec, 0xc4, 0xa7, 0x4e}, + {0x2c, 0xb2, 0xc1, 0x09, 0xee}, + {0x2f, 0x25, 0x9e, 0x96, 0xdd}, + {0x33, 0x2f, 0x49, 0x6c, 0xe0}, + {0x35, 0x5b, 0xc1, 0x31, 0x0f}, + {0x36, 0x67, 0xb2, 0xe3, 0x85}, + {0x39, 0x3d, 0xf1, 0xf1, 0xbd}, + {0x3b, 0x31, 0x34, 0x0d, 0x91}, + {0x45, 0xed, 0x28, 0xeb, 0xd3}, + {0x48, 0xb7, 0x6c, 0xce, 0x69}, + {0x4b, 0x65, 0x0d, 0xc1, 0xee}, + {0x4c, 0xbb, 0xf5, 0x5b, 0x23}, + {0x51, 0x67, 0x67, 0xc5, 0xe0}, + {0x53, 0x94, 0xe1, 0x75, 0xbf}, + {0x57, 0x2c, 0x8b, 0x31, 0xae}, + {0x63, 0xdb, 0x4c, 0x5b, 0x4a}, + {0x7b, 0x1e, 0x5e, 0x2b, 0x57}, + {0x85, 0xf3, 0x85, 0xa0, 0xe0}, + {0xab, 0x1e, 0xe7, 0x7b, 0x72}, + {0xab, 0x36, 0xe3, 0xeb, 0x76}, + {0xb1, 0xb8, 0xf9, 0x38, 0x03}, + {0xb8, 0x5d, 0xd8, 0x53, 0xbd}, + {0xbf, 0x92, 0xc3, 0xb0, 0xe2}, + {0xcf, 0x1a, 0xb2, 0xf8, 0x0a}, + {0xec, 0xa0, 0xcf, 0xb3, 0xff}, + {0xfc, 0x95, 0xa9, 0x87, 0x35} + // TODO: find more player keys +}; + +extern const int g_nPlayerKeys = _countof(g_PlayerKeys); diff --git a/src/DeCSS/CSSscramble.h b/src/DeCSS/CSSscramble.h index 6ca6ebd305f..09a7ab620b4 100644 --- a/src/DeCSS/CSSscramble.h +++ b/src/DeCSS/CSSscramble.h @@ -1,8 +1,8 @@ -#pragma once - -extern void CSSdisckey(unsigned char *dkey,const unsigned char *pkey); -extern void CSStitlekey(unsigned char *tkey,const unsigned char *dkey); -extern void CSSdescramble(unsigned char *sector,const unsigned char *tkey); - -extern const unsigned char g_PlayerKeys[][6]; -extern const int g_nPlayerKeys; +#pragma once + +extern void CSSdisckey(unsigned char *dkey,const unsigned char *pkey); +extern void CSStitlekey(unsigned char *tkey,const unsigned char *dkey); +extern void CSSdescramble(unsigned char *sector,const unsigned char *tkey); + +extern const unsigned char g_PlayerKeys[][6]; +extern const int g_nPlayerKeys; diff --git a/src/DeCSS/DeCSS.vcxproj b/src/DeCSS/DeCSS.vcxproj index d13569ecce2..7bc50aeff5d 100644 --- a/src/DeCSS/DeCSS.vcxproj +++ b/src/DeCSS/DeCSS.vcxproj @@ -1,71 +1,71 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {1A2DFD1A-3C6C-44D1-909D-294AF646B575} - DeCSS - MFCProj - DeCSS - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\include;..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - Create - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {1A2DFD1A-3C6C-44D1-909D-294AF646B575} + DeCSS + MFCProj + DeCSS + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\include;..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + Create + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/DeCSS/DeCSS.vcxproj.filters b/src/DeCSS/DeCSS.vcxproj.filters index 101c20ecd05..7f9579f4877 100644 --- a/src/DeCSS/DeCSS.vcxproj.filters +++ b/src/DeCSS/DeCSS.vcxproj.filters @@ -1,62 +1,62 @@ - - - - - {ad1b8b81-9c26-4439-a44f-daa5cc1dce41} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {b38c1e37-5430-46a1-a691-f642a1ec480e} - h;hpp;hxx;hm;inl;inc - - - {1f95dfa7-830f-4db4-8a34-f58af7ec4315} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - vstrip - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - vstrip - - + + + + + {ad1b8b81-9c26-4439-a44f-daa5cc1dce41} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {b38c1e37-5430-46a1-a691-f642a1ec480e} + h;hpp;hxx;hm;inl;inc + + + {1f95dfa7-830f-4db4-8a34-f58af7ec4315} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + vstrip + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + vstrip + + \ No newline at end of file diff --git a/src/DeCSS/DeCSSInputPin.cpp b/src/DeCSS/DeCSSInputPin.cpp index 96572e76221..4ded58b95b7 100644 --- a/src/DeCSS/DeCSSInputPin.cpp +++ b/src/DeCSS/DeCSSInputPin.cpp @@ -1,361 +1,361 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "BaseClasses/streams.h" -#include -#include -#include -#include "DeCSSInputPin.h" -#include "../DSUtil/DSUtil.h" -#include "CSSauth.h" -#include "CSSscramble.h" - -#include "moreuuids.h" - -// -// CDeCSSInputPin -// - -CDeCSSInputPin::CDeCSSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName) - : CTransformInputPin(pObjectName, pFilter, phr, pName) - , m_varient(-1) -{ - ZeroMemory(m_Challenge, sizeof(m_Challenge)); - ZeroMemory(m_KeyCheck, sizeof(m_KeyCheck)); - ZeroMemory(m_Key, sizeof(m_Key)); - ZeroMemory(m_DiscKey, sizeof(m_DiscKey)); - ZeroMemory(m_TitleKey, sizeof(m_TitleKey)); -} - -STDMETHODIMP CDeCSSInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IKsPropertySet) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IMemInputPin - -STDMETHODIMP CDeCSSInputPin::Receive(IMediaSample* pSample) -{ - long len = pSample->GetActualDataLength(); - - BYTE* p = nullptr; - if (SUCCEEDED(pSample->GetPointer(&p)) && len > 0) { - if (m_mt.majortype == MEDIATYPE_DVD_ENCRYPTED_PACK && len == 2048 && (p[0x14] & 0x30)) { - CSSdescramble(p, m_TitleKey); - p[0x14] &= ~0x30; - - if (CComQIPtr pMS2 = pSample) { - AM_SAMPLE2_PROPERTIES props; - ZeroMemory(&props, sizeof(props)); - if (SUCCEEDED(pMS2->GetProperties(sizeof(props), (BYTE*)&props)) - && (props.dwTypeSpecificFlags & AM_UseNewCSSKey)) { - props.dwTypeSpecificFlags &= ~AM_UseNewCSSKey; - pMS2->SetProperties(sizeof(props), (BYTE*)&props); - } - } - } - } - - HRESULT hr = Transform(pSample); - - return hr == S_OK ? __super::Receive(pSample) : - hr == S_FALSE ? S_OK : hr; -} - -void CDeCSSInputPin::StripPacket(BYTE*& p, long& len) -{ - GUID majortype = m_mt.majortype; - - if (majortype == MEDIATYPE_MPEG2_PACK || majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { - if (len > 0 && *(DWORD*)p == 0xba010000) { // MEDIATYPE_*_PACK - len -= 14; - p += 14; - if (int stuffing = (p[-1] & 7)) { - len -= stuffing; - p += stuffing; - } - majortype = MEDIATYPE_MPEG2_PES; - } - } - - if (majortype == MEDIATYPE_MPEG2_PES) { - if (len > 0 && *(DWORD*)p == 0xbb010000) { - len -= 4; - p += 4; - int hdrlen = ((p[0] << 8) | p[1]) + 2; - len -= hdrlen; - p += hdrlen; - } - - if (len > 0 - && ((*(DWORD*)p & 0xf0ffffff) == 0xe0010000 - || (*(DWORD*)p & 0xe0ffffff) == 0xc0010000 - || (*(DWORD*)p & 0xbdffffff) == 0xbd010000)) { // PES - bool ps1 = (*(DWORD*)p & 0xbdffffff) == 0xbd010000; - - len -= 4; - p += 4; - long expected = ((p[0] << 8) | p[1]); - len -= 2; - p += 2; - BYTE* p0 = p; - - for (int i = 0; i < 16 && *p == 0xff; i++, len--, p++) { - ; - } - - if ((*p & 0xc0) == 0x80) { // mpeg2 - len -= 2; - p += 2; - len -= *p + 1; - p += *p + 1; - } else { // mpeg1 - if ((*p & 0xc0) == 0x40) { - len -= 2; - p += 2; - } - - if ((*p & 0x30) == 0x30 || (*p & 0x30) == 0x20) { - bool pts = !!(*p & 0x20), dts = !!(*p & 0x10); - if (pts) { - len -= 5; - } - p += 5; - if (dts) { - ASSERT((*p & 0xf0) == 0x10); - len -= 5; - p += 5; - } - } else { - len--; - p++; - } - } - - if (ps1) { - len--; - p++; - if (m_mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { - len -= 6; - p += 6; - } else if (m_mt.subtype == MEDIASUBTYPE_DOLBY_AC3 || m_mt.subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 - || m_mt.subtype == MEDIASUBTYPE_DTS || m_mt.subtype == MEDIASUBTYPE_WAVE_DTS) { - len -= 3; - p += 3; - } - } - - if (expected > 0) { - expected -= (long)(p - p0); - len = std::min(expected, len); - } - } - } - - if (len < 0) { - ASSERT(0); - len = 0; - } -} - -// IKsPropertySet - -STDMETHODIMP CDeCSSInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength) -{ - if (PropSet != AM_KSPROPSETID_CopyProt) { - return E_NOTIMPL; - } - - switch (Id) { - case AM_PROPERTY_COPY_MACROVISION: - break; - case AM_PROPERTY_DVDCOPY_CHLG_KEY: { // 3. auth: receive drive nonce word, also store and encrypt the buskey made up of the two nonce words - AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData; - for (int i = 0; i < 10; i++) { - m_Challenge[i] = pChlgKey->ChlgKey[9 - i]; - } - - CSSkey2(m_varient, m_Challenge, &m_Key[5]); - - CSSbuskey(m_varient, m_Key, m_KeyCheck); - } - break; - case AM_PROPERTY_DVDCOPY_DISC_KEY: { // 5. receive the disckey - AM_DVDCOPY_DISCKEY* pDiscKey = (AM_DVDCOPY_DISCKEY*)pPropertyData; // pDiscKey->DiscKey holds the disckey encrypted with itself and the 408 disckeys encrypted with the playerkeys - - bool fSuccess = false; - - for (int j = 0; j < g_nPlayerKeys; j++) { - for (int k = 1; k < 409; k++) { - BYTE DiscKey[6]; - for (int i = 0; i < 5; i++) { - DiscKey[i] = pDiscKey->DiscKey[k * 5 + i] ^ m_KeyCheck[4 - i]; - } - DiscKey[5] = 0; - - CSSdisckey(DiscKey, g_PlayerKeys[j]); - - BYTE Hash[6]; - for (int i = 0; i < 5; i++) { - Hash[i] = pDiscKey->DiscKey[i] ^ m_KeyCheck[4 - i]; - } - Hash[5] = 0; - - CSSdisckey(Hash, DiscKey); - - if (!memcmp(Hash, DiscKey, 6)) { - memcpy(m_DiscKey, DiscKey, 6); - j = g_nPlayerKeys; - fSuccess = true; - break; - } - } - } - - if (!fSuccess) { - return E_FAIL; - } - } - break; - case AM_PROPERTY_DVDCOPY_DVD_KEY1: { // 2. auth: receive our drive-encrypted nonce word and decrypt it for verification - AM_DVDCOPY_BUSKEY* pKey1 = (AM_DVDCOPY_BUSKEY*)pPropertyData; - for (int i = 0; i < 5; i++) { - m_Key[i] = pKey1->BusKey[4 - i]; - } - - m_varient = -1; - - for (int i = 31; i >= 0; i--) { - CSSkey1(i, m_Challenge, m_KeyCheck); - - if (memcmp(m_KeyCheck, &m_Key[0], 5) == 0) { - m_varient = i; - } - } - } - break; - case AM_PROPERTY_DVDCOPY_REGION: - break; - case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: - break; - case AM_PROPERTY_DVDCOPY_TITLE_KEY: { // 6. receive the title key and decrypt it with the disc key - AM_DVDCOPY_TITLEKEY* pTitleKey = (AM_DVDCOPY_TITLEKEY*)pPropertyData; - for (int i = 0; i < 5; i++) { - m_TitleKey[i] = pTitleKey->TitleKey[i] ^ m_KeyCheck[4 - i]; - } - m_TitleKey[5] = 0; - CSStitlekey(m_TitleKey, m_DiscKey); - } - break; - default: - return E_PROP_ID_UNSUPPORTED; - } - - return S_OK; -} - -STDMETHODIMP CDeCSSInputPin::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned) -{ - if (PropSet != AM_KSPROPSETID_CopyProt) { - return E_NOTIMPL; - } - - switch (Id) { - case AM_PROPERTY_DVDCOPY_CHLG_KEY: { // 1. auth: send our nonce word - AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData; - for (BYTE i = 0; i < 10; i++) { - pChlgKey->ChlgKey[i] = 9 - (m_Challenge[i] = i); - } - *pBytesReturned = sizeof(AM_DVDCOPY_CHLGKEY); - } - break; - case AM_PROPERTY_DVDCOPY_DEC_KEY2: { // 4. auth: send back the encrypted drive nonce word to finish the authentication - AM_DVDCOPY_BUSKEY* pKey2 = (AM_DVDCOPY_BUSKEY*)pPropertyData; - for (int i = 0; i < 5; i++) { - pKey2->BusKey[4 - i] = m_Key[5 + i]; - } - *pBytesReturned = sizeof(AM_DVDCOPY_BUSKEY); - } - break; - case AM_PROPERTY_DVDCOPY_REGION: { - DVD_REGION* pRegion = (DVD_REGION*)pPropertyData; - pRegion->RegionData = 0; - pRegion->SystemRegion = 0; - *pBytesReturned = sizeof(DVD_REGION); - } - break; - case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: { - AM_DVDCOPY_SET_COPY_STATE* pState = (AM_DVDCOPY_SET_COPY_STATE*)pPropertyData; - pState->DVDCopyState = AM_DVDCOPYSTATE_AUTHENTICATION_REQUIRED; - *pBytesReturned = sizeof(AM_DVDCOPY_SET_COPY_STATE); - } - break; - default: - return E_PROP_ID_UNSUPPORTED; - } - - return S_OK; -} - -STDMETHODIMP CDeCSSInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) -{ - if (PropSet != AM_KSPROPSETID_CopyProt) { - return E_NOTIMPL; - } - - switch (Id) { - case AM_PROPERTY_COPY_MACROVISION: - *pTypeSupport = KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_CHLG_KEY: - *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_DEC_KEY2: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - break; - case AM_PROPERTY_DVDCOPY_DISC_KEY: - *pTypeSupport = KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_DVD_KEY1: - *pTypeSupport = KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_REGION: - *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: - *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_TITLE_KEY: - *pTypeSupport = KSPROPERTY_SUPPORT_SET; - break; - default: - return E_PROP_ID_UNSUPPORTED; - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "BaseClasses/streams.h" +#include +#include +#include +#include "DeCSSInputPin.h" +#include "../DSUtil/DSUtil.h" +#include "CSSauth.h" +#include "CSSscramble.h" + +#include "moreuuids.h" + +// +// CDeCSSInputPin +// + +CDeCSSInputPin::CDeCSSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName) + : CTransformInputPin(pObjectName, pFilter, phr, pName) + , m_varient(-1) +{ + ZeroMemory(m_Challenge, sizeof(m_Challenge)); + ZeroMemory(m_KeyCheck, sizeof(m_KeyCheck)); + ZeroMemory(m_Key, sizeof(m_Key)); + ZeroMemory(m_DiscKey, sizeof(m_DiscKey)); + ZeroMemory(m_TitleKey, sizeof(m_TitleKey)); +} + +STDMETHODIMP CDeCSSInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IKsPropertySet) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IMemInputPin + +STDMETHODIMP CDeCSSInputPin::Receive(IMediaSample* pSample) +{ + long len = pSample->GetActualDataLength(); + + BYTE* p = nullptr; + if (SUCCEEDED(pSample->GetPointer(&p)) && len > 0) { + if (m_mt.majortype == MEDIATYPE_DVD_ENCRYPTED_PACK && len == 2048 && (p[0x14] & 0x30)) { + CSSdescramble(p, m_TitleKey); + p[0x14] &= ~0x30; + + if (CComQIPtr pMS2 = pSample) { + AM_SAMPLE2_PROPERTIES props; + ZeroMemory(&props, sizeof(props)); + if (SUCCEEDED(pMS2->GetProperties(sizeof(props), (BYTE*)&props)) + && (props.dwTypeSpecificFlags & AM_UseNewCSSKey)) { + props.dwTypeSpecificFlags &= ~AM_UseNewCSSKey; + pMS2->SetProperties(sizeof(props), (BYTE*)&props); + } + } + } + } + + HRESULT hr = Transform(pSample); + + return hr == S_OK ? __super::Receive(pSample) : + hr == S_FALSE ? S_OK : hr; +} + +void CDeCSSInputPin::StripPacket(BYTE*& p, long& len) +{ + GUID majortype = m_mt.majortype; + + if (majortype == MEDIATYPE_MPEG2_PACK || majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { + if (len > 0 && *(DWORD*)p == 0xba010000) { // MEDIATYPE_*_PACK + len -= 14; + p += 14; + if (int stuffing = (p[-1] & 7)) { + len -= stuffing; + p += stuffing; + } + majortype = MEDIATYPE_MPEG2_PES; + } + } + + if (majortype == MEDIATYPE_MPEG2_PES) { + if (len > 0 && *(DWORD*)p == 0xbb010000) { + len -= 4; + p += 4; + int hdrlen = ((p[0] << 8) | p[1]) + 2; + len -= hdrlen; + p += hdrlen; + } + + if (len > 0 + && ((*(DWORD*)p & 0xf0ffffff) == 0xe0010000 + || (*(DWORD*)p & 0xe0ffffff) == 0xc0010000 + || (*(DWORD*)p & 0xbdffffff) == 0xbd010000)) { // PES + bool ps1 = (*(DWORD*)p & 0xbdffffff) == 0xbd010000; + + len -= 4; + p += 4; + long expected = ((p[0] << 8) | p[1]); + len -= 2; + p += 2; + BYTE* p0 = p; + + for (int i = 0; i < 16 && *p == 0xff; i++, len--, p++) { + ; + } + + if ((*p & 0xc0) == 0x80) { // mpeg2 + len -= 2; + p += 2; + len -= *p + 1; + p += *p + 1; + } else { // mpeg1 + if ((*p & 0xc0) == 0x40) { + len -= 2; + p += 2; + } + + if ((*p & 0x30) == 0x30 || (*p & 0x30) == 0x20) { + bool pts = !!(*p & 0x20), dts = !!(*p & 0x10); + if (pts) { + len -= 5; + } + p += 5; + if (dts) { + ASSERT((*p & 0xf0) == 0x10); + len -= 5; + p += 5; + } + } else { + len--; + p++; + } + } + + if (ps1) { + len--; + p++; + if (m_mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { + len -= 6; + p += 6; + } else if (m_mt.subtype == MEDIASUBTYPE_DOLBY_AC3 || m_mt.subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 + || m_mt.subtype == MEDIASUBTYPE_DTS || m_mt.subtype == MEDIASUBTYPE_WAVE_DTS) { + len -= 3; + p += 3; + } + } + + if (expected > 0) { + expected -= (long)(p - p0); + len = std::min(expected, len); + } + } + } + + if (len < 0) { + ASSERT(0); + len = 0; + } +} + +// IKsPropertySet + +STDMETHODIMP CDeCSSInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength) +{ + if (PropSet != AM_KSPROPSETID_CopyProt) { + return E_NOTIMPL; + } + + switch (Id) { + case AM_PROPERTY_COPY_MACROVISION: + break; + case AM_PROPERTY_DVDCOPY_CHLG_KEY: { // 3. auth: receive drive nonce word, also store and encrypt the buskey made up of the two nonce words + AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData; + for (int i = 0; i < 10; i++) { + m_Challenge[i] = pChlgKey->ChlgKey[9 - i]; + } + + CSSkey2(m_varient, m_Challenge, &m_Key[5]); + + CSSbuskey(m_varient, m_Key, m_KeyCheck); + } + break; + case AM_PROPERTY_DVDCOPY_DISC_KEY: { // 5. receive the disckey + AM_DVDCOPY_DISCKEY* pDiscKey = (AM_DVDCOPY_DISCKEY*)pPropertyData; // pDiscKey->DiscKey holds the disckey encrypted with itself and the 408 disckeys encrypted with the playerkeys + + bool fSuccess = false; + + for (int j = 0; j < g_nPlayerKeys; j++) { + for (int k = 1; k < 409; k++) { + BYTE DiscKey[6]; + for (int i = 0; i < 5; i++) { + DiscKey[i] = pDiscKey->DiscKey[k * 5 + i] ^ m_KeyCheck[4 - i]; + } + DiscKey[5] = 0; + + CSSdisckey(DiscKey, g_PlayerKeys[j]); + + BYTE Hash[6]; + for (int i = 0; i < 5; i++) { + Hash[i] = pDiscKey->DiscKey[i] ^ m_KeyCheck[4 - i]; + } + Hash[5] = 0; + + CSSdisckey(Hash, DiscKey); + + if (!memcmp(Hash, DiscKey, 6)) { + memcpy(m_DiscKey, DiscKey, 6); + j = g_nPlayerKeys; + fSuccess = true; + break; + } + } + } + + if (!fSuccess) { + return E_FAIL; + } + } + break; + case AM_PROPERTY_DVDCOPY_DVD_KEY1: { // 2. auth: receive our drive-encrypted nonce word and decrypt it for verification + AM_DVDCOPY_BUSKEY* pKey1 = (AM_DVDCOPY_BUSKEY*)pPropertyData; + for (int i = 0; i < 5; i++) { + m_Key[i] = pKey1->BusKey[4 - i]; + } + + m_varient = -1; + + for (int i = 31; i >= 0; i--) { + CSSkey1(i, m_Challenge, m_KeyCheck); + + if (memcmp(m_KeyCheck, &m_Key[0], 5) == 0) { + m_varient = i; + } + } + } + break; + case AM_PROPERTY_DVDCOPY_REGION: + break; + case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: + break; + case AM_PROPERTY_DVDCOPY_TITLE_KEY: { // 6. receive the title key and decrypt it with the disc key + AM_DVDCOPY_TITLEKEY* pTitleKey = (AM_DVDCOPY_TITLEKEY*)pPropertyData; + for (int i = 0; i < 5; i++) { + m_TitleKey[i] = pTitleKey->TitleKey[i] ^ m_KeyCheck[4 - i]; + } + m_TitleKey[5] = 0; + CSStitlekey(m_TitleKey, m_DiscKey); + } + break; + default: + return E_PROP_ID_UNSUPPORTED; + } + + return S_OK; +} + +STDMETHODIMP CDeCSSInputPin::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned) +{ + if (PropSet != AM_KSPROPSETID_CopyProt) { + return E_NOTIMPL; + } + + switch (Id) { + case AM_PROPERTY_DVDCOPY_CHLG_KEY: { // 1. auth: send our nonce word + AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData; + for (BYTE i = 0; i < 10; i++) { + pChlgKey->ChlgKey[i] = 9 - (m_Challenge[i] = i); + } + *pBytesReturned = sizeof(AM_DVDCOPY_CHLGKEY); + } + break; + case AM_PROPERTY_DVDCOPY_DEC_KEY2: { // 4. auth: send back the encrypted drive nonce word to finish the authentication + AM_DVDCOPY_BUSKEY* pKey2 = (AM_DVDCOPY_BUSKEY*)pPropertyData; + for (int i = 0; i < 5; i++) { + pKey2->BusKey[4 - i] = m_Key[5 + i]; + } + *pBytesReturned = sizeof(AM_DVDCOPY_BUSKEY); + } + break; + case AM_PROPERTY_DVDCOPY_REGION: { + DVD_REGION* pRegion = (DVD_REGION*)pPropertyData; + pRegion->RegionData = 0; + pRegion->SystemRegion = 0; + *pBytesReturned = sizeof(DVD_REGION); + } + break; + case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: { + AM_DVDCOPY_SET_COPY_STATE* pState = (AM_DVDCOPY_SET_COPY_STATE*)pPropertyData; + pState->DVDCopyState = AM_DVDCOPYSTATE_AUTHENTICATION_REQUIRED; + *pBytesReturned = sizeof(AM_DVDCOPY_SET_COPY_STATE); + } + break; + default: + return E_PROP_ID_UNSUPPORTED; + } + + return S_OK; +} + +STDMETHODIMP CDeCSSInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) +{ + if (PropSet != AM_KSPROPSETID_CopyProt) { + return E_NOTIMPL; + } + + switch (Id) { + case AM_PROPERTY_COPY_MACROVISION: + *pTypeSupport = KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_CHLG_KEY: + *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_DEC_KEY2: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + break; + case AM_PROPERTY_DVDCOPY_DISC_KEY: + *pTypeSupport = KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_DVD_KEY1: + *pTypeSupport = KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_REGION: + *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: + *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_TITLE_KEY: + *pTypeSupport = KSPROPERTY_SUPPORT_SET; + break; + default: + return E_PROP_ID_UNSUPPORTED; + } + + return S_OK; +} diff --git a/src/DeCSS/DeCSSInputPin.h b/src/DeCSS/DeCSSInputPin.h index 29c4b72c7a9..83a75faf366 100644 --- a/src/DeCSS/DeCSSInputPin.h +++ b/src/DeCSS/DeCSSInputPin.h @@ -1,50 +1,50 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -class CDeCSSInputPin : public CTransformInputPin, public IKsPropertySet -{ - int m_varient; - BYTE m_Challenge[10], m_KeyCheck[5], m_Key[10]; - BYTE m_DiscKey[6], m_TitleKey[6]; - -protected: - // return S_FALSE here if you don't want the base class - // to call CTransformFilter::Receive with this sample - virtual HRESULT Transform(IMediaSample* pSample) { return S_OK; } - -public: - CDeCSSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - void StripPacket(BYTE*& p, long& len); - - // IMemInputPin - STDMETHODIMP Receive(IMediaSample* pSample); - - // IKsPropertySet - STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength); - STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG* pBytesReturned); - STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +class CDeCSSInputPin : public CTransformInputPin, public IKsPropertySet +{ + int m_varient; + BYTE m_Challenge[10], m_KeyCheck[5], m_Key[10]; + BYTE m_DiscKey[6], m_TitleKey[6]; + +protected: + // return S_FALSE here if you don't want the base class + // to call CTransformFilter::Receive with this sample + virtual HRESULT Transform(IMediaSample* pSample) { return S_OK; } + +public: + CDeCSSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + void StripPacket(BYTE*& p, long& len); + + // IMemInputPin + STDMETHODIMP Receive(IMediaSample* pSample); + + // IKsPropertySet + STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength); + STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG* pBytesReturned); + STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport); +}; diff --git a/src/DeCSS/VobDec.cpp b/src/DeCSS/VobDec.cpp index 570c27e6e9d..e1f9b7bcbbb 100644 --- a/src/DeCSS/VobDec.cpp +++ b/src/DeCSS/VobDec.cpp @@ -1,162 +1,162 @@ -#include "stdafx.h" -#include "VobDec.h" - -static BYTE reverse[0x100], table[0x100] = { - 0x33, 0x73, 0x3B, 0x26, 0x63, 0x23, 0x6B, 0x76, 0x3E, 0x7E, 0x36, 0x2B, 0x6E, 0x2E, 0x66, 0x7B, - 0xD3, 0x93, 0xDB, 0x06, 0x43, 0x03, 0x4B, 0x96, 0xDE, 0x9E, 0xD6, 0x0B, 0x4E, 0x0E, 0x46, 0x9B, - 0x57, 0x17, 0x5F, 0x82, 0xC7, 0x87, 0xCF, 0x12, 0x5A, 0x1A, 0x52, 0x8F, 0xCA, 0x8A, 0xC2, 0x1F, - 0xD9, 0x99, 0xD1, 0x00, 0x49, 0x09, 0x41, 0x90, 0xD8, 0x98, 0xD0, 0x01, 0x48, 0x08, 0x40, 0x91, - 0x3D, 0x7D, 0x35, 0x24, 0x6D, 0x2D, 0x65, 0x74, 0x3C, 0x7C, 0x34, 0x25, 0x6C, 0x2C, 0x64, 0x75, - 0xDD, 0x9D, 0xD5, 0x04, 0x4D, 0x0D, 0x45, 0x94, 0xDC, 0x9C, 0xD4, 0x05, 0x4C, 0x0C, 0x44, 0x95, - 0x59, 0x19, 0x51, 0x80, 0xC9, 0x89, 0xC1, 0x10, 0x58, 0x18, 0x50, 0x81, 0xC8, 0x88, 0xC0, 0x11, - 0xD7, 0x97, 0xDF, 0x02, 0x47, 0x07, 0x4F, 0x92, 0xDA, 0x9A, 0xD2, 0x0F, 0x4A, 0x0A, 0x42, 0x9F, - 0x53, 0x13, 0x5B, 0x86, 0xC3, 0x83, 0xCB, 0x16, 0x5E, 0x1E, 0x56, 0x8B, 0xCE, 0x8E, 0xC6, 0x1B, - 0xB3, 0xF3, 0xBB, 0xA6, 0xE3, 0xA3, 0xEB, 0xF6, 0xBE, 0xFE, 0xB6, 0xAB, 0xEE, 0xAE, 0xE6, 0xFB, - 0x37, 0x77, 0x3F, 0x22, 0x67, 0x27, 0x6F, 0x72, 0x3A, 0x7A, 0x32, 0x2F, 0x6A, 0x2A, 0x62, 0x7F, - 0xB9, 0xF9, 0xB1, 0xA0, 0xE9, 0xA9, 0xE1, 0xF0, 0xB8, 0xF8, 0xB0, 0xA1, 0xE8, 0xA8, 0xE0, 0xF1, - 0x5D, 0x1D, 0x55, 0x84, 0xCD, 0x8D, 0xC5, 0x14, 0x5C, 0x1C, 0x54, 0x85, 0xCC, 0x8C, 0xC4, 0x15, - 0xBD, 0xFD, 0xB5, 0xA4, 0xED, 0xAD, 0xE5, 0xF4, 0xBC, 0xFC, 0xB4, 0xA5, 0xEC, 0xAC, 0xE4, 0xF5, - 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70, 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71, - 0xB7, 0xF7, 0xBF, 0xA2, 0xE7, 0xA7, 0xEF, 0xF2, 0xBA, 0xFA, 0xB2, 0xAF, 0xEA, 0xAA, 0xE2, 0xFF, -}; - -CVobDec::CVobDec() -{ - m_fFoundKey = false; - m_lfsr0 = 0; - m_lfsr1 = 0; - - for (DWORD loop0 = 0; loop0 < 0x100; loop0++) { - BYTE value = 0; - - for (DWORD loop1 = 0; loop1 < 8; loop1++) { - value |= ((loop0 >> loop1) & 1) << (7 - loop1); - } - - reverse[loop0] = value; - } - -} - -CVobDec::~CVobDec() -{ -} - -void CVobDec::ClockLfsr0Forward(int& lfsr0) -{ - int temp = (lfsr0 << 3) | (lfsr0 >> 14); - lfsr0 = (lfsr0 >> 8) | ((((((temp << 3) ^ temp) << 3) ^ temp ^ lfsr0) & 0xFF) << 9); -} - -void CVobDec::ClockLfsr1Forward(int& lfsr1) -{ - lfsr1 = (lfsr1 >> 8) | ((((((((lfsr1 >> 8) ^ lfsr1) >> 1) ^ lfsr1) >> 3) ^ lfsr1) & 0xFF) << 17); -} - -void CVobDec::ClockBackward(int& lfsr0, int& lfsr1) -{ - int temp0, temp1; - - lfsr0 = ((lfsr0 << 8) ^ ((((lfsr0 >> 3) ^ lfsr0) >> 6) & 0xFF)) & ((1 << 17) - 1); - temp0 = ((lfsr1 >> 17) ^ (lfsr1 >> 4)) & 0xFF; - temp1 = (lfsr1 << 5) | (temp0 >> 3); - temp1 = ((temp1 >> 1) ^ temp1) & 0xFF; - lfsr1 = ((lfsr1 << 8) | ((((((temp1 >> 2) ^ temp1) >> 1) ^ temp1) >> 3) ^ temp1 ^ temp0)) & ((1 << 25) - 1); -} - -void CVobDec::Salt(const BYTE salt[5], int& lfsr0, int& lfsr1) -{ - lfsr0 ^= (reverse[salt[0]] << 9) | reverse[salt[1]]; - lfsr1 ^= ((reverse[salt[2]] & 0xE0) << 17) | ((reverse[salt[2]] & 0x1F) << 16) | (reverse[salt[3]] << 8) | reverse[salt[4]]; -} - -int CVobDec::FindLfsr(const BYTE* crypt, int offset, const BYTE* plain) -{ - int count = 0; - - for (int loop0 = 0; loop0 != (1 << 18); loop0++) { - int lfsr0 = loop0 >> 1; - int carry = loop0 & 0x01; - int loop1 = 0, lfsr1 = 0; - - for (; loop1 != 4; loop1++) { - ClockLfsr0Forward(lfsr0); - carry = (table[crypt[offset + loop1]] ^ plain[loop1]) - ((lfsr0 >> 9) ^ 0xFF) - carry; - lfsr1 = (lfsr1 >> 8) | ((carry & 0xFF) << 17); - carry = (carry >> 8) & 0x01; - } - for (; loop1 != 7; loop1++) { - ClockLfsr0Forward(lfsr0); - ClockLfsr1Forward(lfsr1); - carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17); - if ((carry & 0xFF) != (table[crypt[offset + loop1]] ^ plain[loop1])) { - break; - } - carry >>= 8; - } - if (loop1 == 7) { - for (loop1 = 0; loop1 != 6; loop1++) { - ClockBackward(lfsr0, lfsr1); - } - carry = ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17) + (loop0 & 0x01); - if ((carry & 0xFF) == (table[crypt[offset]] ^ plain[0])) { - for (loop1 = 0; loop1 != offset + 1; loop1++) { - ClockBackward(lfsr0, lfsr1); - } - if (lfsr0 & 0x100 && lfsr1 & 0x200000) { - m_lfsr0 = lfsr0; - m_lfsr1 = lfsr1; - count++; - } - } - } - } - - return count; -} - -bool CVobDec::FindKey(BYTE* buff) -{ - m_fFoundKey = false; - - if (buff[0x14] & 0x30) { - //int flag = 0x01; - - if (*(DWORD*)&buff[0x00] == 0xba010000 && (*(DWORD*)&buff[0x0e] & 0xffffff) == 0x010000) { - int offset = 0x14 + (buff[0x12] << 8) + buff[0x13]; - if (0x80 <= offset && offset <= 0x7F9) { - BYTE plain[7] = { 0x00, 0x00, 0x01, 0xBE, 0x00, 0x00, 0xFF }; - int left = 0x800 - offset - 6; - plain[4] = (char)(left >> 8); - plain[5] = (char)left; - if (FindLfsr(buff + 0x80, offset - 0x80, plain) == 1) { - Salt(buff + 0x54, m_lfsr0, m_lfsr1); - m_fFoundKey = true; - } - } - } - } - - return m_fFoundKey; -} - -void CVobDec::Decrypt(BYTE* buff) -{ - if (buff[0x14] & 0x30) { - buff[0x14] &= ~0x30; - - int lfsr0 = m_lfsr0, lfsr1 = m_lfsr1; - - Salt(buff + 0x54, lfsr0, lfsr1); - - buff += 0x80; - - for (int loop0 = 0, carry = 0; loop0 != 0x800 - 0x80; loop0++, buff++) { - ClockLfsr0Forward(lfsr0); - ClockLfsr1Forward(lfsr1); - carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17); - *buff = BYTE(table[*buff] ^ carry); - carry >>= 8; - } - } -} +#include "stdafx.h" +#include "VobDec.h" + +static BYTE reverse[0x100], table[0x100] = { + 0x33, 0x73, 0x3B, 0x26, 0x63, 0x23, 0x6B, 0x76, 0x3E, 0x7E, 0x36, 0x2B, 0x6E, 0x2E, 0x66, 0x7B, + 0xD3, 0x93, 0xDB, 0x06, 0x43, 0x03, 0x4B, 0x96, 0xDE, 0x9E, 0xD6, 0x0B, 0x4E, 0x0E, 0x46, 0x9B, + 0x57, 0x17, 0x5F, 0x82, 0xC7, 0x87, 0xCF, 0x12, 0x5A, 0x1A, 0x52, 0x8F, 0xCA, 0x8A, 0xC2, 0x1F, + 0xD9, 0x99, 0xD1, 0x00, 0x49, 0x09, 0x41, 0x90, 0xD8, 0x98, 0xD0, 0x01, 0x48, 0x08, 0x40, 0x91, + 0x3D, 0x7D, 0x35, 0x24, 0x6D, 0x2D, 0x65, 0x74, 0x3C, 0x7C, 0x34, 0x25, 0x6C, 0x2C, 0x64, 0x75, + 0xDD, 0x9D, 0xD5, 0x04, 0x4D, 0x0D, 0x45, 0x94, 0xDC, 0x9C, 0xD4, 0x05, 0x4C, 0x0C, 0x44, 0x95, + 0x59, 0x19, 0x51, 0x80, 0xC9, 0x89, 0xC1, 0x10, 0x58, 0x18, 0x50, 0x81, 0xC8, 0x88, 0xC0, 0x11, + 0xD7, 0x97, 0xDF, 0x02, 0x47, 0x07, 0x4F, 0x92, 0xDA, 0x9A, 0xD2, 0x0F, 0x4A, 0x0A, 0x42, 0x9F, + 0x53, 0x13, 0x5B, 0x86, 0xC3, 0x83, 0xCB, 0x16, 0x5E, 0x1E, 0x56, 0x8B, 0xCE, 0x8E, 0xC6, 0x1B, + 0xB3, 0xF3, 0xBB, 0xA6, 0xE3, 0xA3, 0xEB, 0xF6, 0xBE, 0xFE, 0xB6, 0xAB, 0xEE, 0xAE, 0xE6, 0xFB, + 0x37, 0x77, 0x3F, 0x22, 0x67, 0x27, 0x6F, 0x72, 0x3A, 0x7A, 0x32, 0x2F, 0x6A, 0x2A, 0x62, 0x7F, + 0xB9, 0xF9, 0xB1, 0xA0, 0xE9, 0xA9, 0xE1, 0xF0, 0xB8, 0xF8, 0xB0, 0xA1, 0xE8, 0xA8, 0xE0, 0xF1, + 0x5D, 0x1D, 0x55, 0x84, 0xCD, 0x8D, 0xC5, 0x14, 0x5C, 0x1C, 0x54, 0x85, 0xCC, 0x8C, 0xC4, 0x15, + 0xBD, 0xFD, 0xB5, 0xA4, 0xED, 0xAD, 0xE5, 0xF4, 0xBC, 0xFC, 0xB4, 0xA5, 0xEC, 0xAC, 0xE4, 0xF5, + 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70, 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71, + 0xB7, 0xF7, 0xBF, 0xA2, 0xE7, 0xA7, 0xEF, 0xF2, 0xBA, 0xFA, 0xB2, 0xAF, 0xEA, 0xAA, 0xE2, 0xFF, +}; + +CVobDec::CVobDec() +{ + m_fFoundKey = false; + m_lfsr0 = 0; + m_lfsr1 = 0; + + for (DWORD loop0 = 0; loop0 < 0x100; loop0++) { + BYTE value = 0; + + for (DWORD loop1 = 0; loop1 < 8; loop1++) { + value |= ((loop0 >> loop1) & 1) << (7 - loop1); + } + + reverse[loop0] = value; + } + +} + +CVobDec::~CVobDec() +{ +} + +void CVobDec::ClockLfsr0Forward(int& lfsr0) +{ + int temp = (lfsr0 << 3) | (lfsr0 >> 14); + lfsr0 = (lfsr0 >> 8) | ((((((temp << 3) ^ temp) << 3) ^ temp ^ lfsr0) & 0xFF) << 9); +} + +void CVobDec::ClockLfsr1Forward(int& lfsr1) +{ + lfsr1 = (lfsr1 >> 8) | ((((((((lfsr1 >> 8) ^ lfsr1) >> 1) ^ lfsr1) >> 3) ^ lfsr1) & 0xFF) << 17); +} + +void CVobDec::ClockBackward(int& lfsr0, int& lfsr1) +{ + int temp0, temp1; + + lfsr0 = ((lfsr0 << 8) ^ ((((lfsr0 >> 3) ^ lfsr0) >> 6) & 0xFF)) & ((1 << 17) - 1); + temp0 = ((lfsr1 >> 17) ^ (lfsr1 >> 4)) & 0xFF; + temp1 = (lfsr1 << 5) | (temp0 >> 3); + temp1 = ((temp1 >> 1) ^ temp1) & 0xFF; + lfsr1 = ((lfsr1 << 8) | ((((((temp1 >> 2) ^ temp1) >> 1) ^ temp1) >> 3) ^ temp1 ^ temp0)) & ((1 << 25) - 1); +} + +void CVobDec::Salt(const BYTE salt[5], int& lfsr0, int& lfsr1) +{ + lfsr0 ^= (reverse[salt[0]] << 9) | reverse[salt[1]]; + lfsr1 ^= ((reverse[salt[2]] & 0xE0) << 17) | ((reverse[salt[2]] & 0x1F) << 16) | (reverse[salt[3]] << 8) | reverse[salt[4]]; +} + +int CVobDec::FindLfsr(const BYTE* crypt, int offset, const BYTE* plain) +{ + int count = 0; + + for (int loop0 = 0; loop0 != (1 << 18); loop0++) { + int lfsr0 = loop0 >> 1; + int carry = loop0 & 0x01; + int loop1 = 0, lfsr1 = 0; + + for (; loop1 != 4; loop1++) { + ClockLfsr0Forward(lfsr0); + carry = (table[crypt[offset + loop1]] ^ plain[loop1]) - ((lfsr0 >> 9) ^ 0xFF) - carry; + lfsr1 = (lfsr1 >> 8) | ((carry & 0xFF) << 17); + carry = (carry >> 8) & 0x01; + } + for (; loop1 != 7; loop1++) { + ClockLfsr0Forward(lfsr0); + ClockLfsr1Forward(lfsr1); + carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17); + if ((carry & 0xFF) != (table[crypt[offset + loop1]] ^ plain[loop1])) { + break; + } + carry >>= 8; + } + if (loop1 == 7) { + for (loop1 = 0; loop1 != 6; loop1++) { + ClockBackward(lfsr0, lfsr1); + } + carry = ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17) + (loop0 & 0x01); + if ((carry & 0xFF) == (table[crypt[offset]] ^ plain[0])) { + for (loop1 = 0; loop1 != offset + 1; loop1++) { + ClockBackward(lfsr0, lfsr1); + } + if (lfsr0 & 0x100 && lfsr1 & 0x200000) { + m_lfsr0 = lfsr0; + m_lfsr1 = lfsr1; + count++; + } + } + } + } + + return count; +} + +bool CVobDec::FindKey(BYTE* buff) +{ + m_fFoundKey = false; + + if (buff[0x14] & 0x30) { + //int flag = 0x01; + + if (*(DWORD*)&buff[0x00] == 0xba010000 && (*(DWORD*)&buff[0x0e] & 0xffffff) == 0x010000) { + int offset = 0x14 + (buff[0x12] << 8) + buff[0x13]; + if (0x80 <= offset && offset <= 0x7F9) { + BYTE plain[7] = { 0x00, 0x00, 0x01, 0xBE, 0x00, 0x00, 0xFF }; + int left = 0x800 - offset - 6; + plain[4] = (char)(left >> 8); + plain[5] = (char)left; + if (FindLfsr(buff + 0x80, offset - 0x80, plain) == 1) { + Salt(buff + 0x54, m_lfsr0, m_lfsr1); + m_fFoundKey = true; + } + } + } + } + + return m_fFoundKey; +} + +void CVobDec::Decrypt(BYTE* buff) +{ + if (buff[0x14] & 0x30) { + buff[0x14] &= ~0x30; + + int lfsr0 = m_lfsr0, lfsr1 = m_lfsr1; + + Salt(buff + 0x54, lfsr0, lfsr1); + + buff += 0x80; + + for (int loop0 = 0, carry = 0; loop0 != 0x800 - 0x80; loop0++, buff++) { + ClockLfsr0Forward(lfsr0); + ClockLfsr1Forward(lfsr1); + carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17); + *buff = BYTE(table[*buff] ^ carry); + carry >>= 8; + } + } +} diff --git a/src/DeCSS/VobDec.h b/src/DeCSS/VobDec.h index c88e2f644b0..fd86263fceb 100644 --- a/src/DeCSS/VobDec.h +++ b/src/DeCSS/VobDec.h @@ -1,21 +1,21 @@ -#pragma once - -class CVobDec -{ - int m_lfsr0, m_lfsr1; - - void ClockLfsr0Forward(int& lfsr0); - void ClockLfsr1Forward(int& lfsr1); - void ClockBackward(int& lfsr0, int& lfsr1); - void Salt(const BYTE salt[5], int& lfsr0, int& lfsr1); - int FindLfsr(const BYTE* crypt, int offset, const BYTE* plain); - -public: - CVobDec(); - virtual ~CVobDec(); - - bool m_fFoundKey; - - bool FindKey(BYTE* buff); - void Decrypt(BYTE* buff); -}; +#pragma once + +class CVobDec +{ + int m_lfsr0, m_lfsr1; + + void ClockLfsr0Forward(int& lfsr0); + void ClockLfsr1Forward(int& lfsr1); + void ClockBackward(int& lfsr0, int& lfsr1); + void Salt(const BYTE salt[5], int& lfsr0, int& lfsr1); + int FindLfsr(const BYTE* crypt, int offset, const BYTE* plain); + +public: + CVobDec(); + virtual ~CVobDec(); + + bool m_fFoundKey; + + bool FindKey(BYTE* buff); + void Decrypt(BYTE* buff); +}; diff --git a/src/DeCSS/VobFile.cpp b/src/DeCSS/VobFile.cpp index 286454e0ffd..529b7815c90 100644 --- a/src/DeCSS/VobFile.cpp +++ b/src/DeCSS/VobFile.cpp @@ -1,878 +1,878 @@ -#include "stdafx.h" -#include -#include -#include "VobFile.h" -#include "CSSauth.h" -#include "CSSscramble.h" -#include "udf.h" - -#include "../DSUtil/GolombBuffer.h" -#include "../DSUtil/DSUtil.h" -#include "../DSUtil/ISOLang.h" - -#define AUDIO_BLOCK_SIZE 66 -#define SUBTITLE_BLOCK_SIZE 194 -#define IFO_HEADER_SIZE 12 -#define VIDEO_TS_HEADER "DVDVIDEO-VMG" -#define VTS_HEADER "DVDVIDEO-VTS" - -// -// CDVDSession -// - -CDVDSession::CDVDSession() - : m_hDrive(INVALID_HANDLE_VALUE) - , m_session(DVD_END_ALL_SESSIONS) -{ - ZeroMemory(m_SessionKey, sizeof(m_SessionKey)); - ZeroMemory(m_DiscKey, sizeof(m_DiscKey)); - ZeroMemory(m_TitleKey, sizeof(m_TitleKey)); -} - -CDVDSession::~CDVDSession() -{ - EndSession(); -} - -bool CDVDSession::Open(LPCTSTR path) -{ - Close(); - - CString fn = path; - CString drive = _T("\\\\.\\") + fn.Left(fn.Find(':') + 1); - - m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); - if (m_hDrive == INVALID_HANDLE_VALUE) { - return false; - } - - return true; -} - -void CDVDSession::Close() -{ - if (m_hDrive != INVALID_HANDLE_VALUE) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - } -} - -bool CDVDSession::BeginSession() -{ - EndSession(); - - if (m_hDrive == INVALID_HANDLE_VALUE) { - return false; - } - - DWORD BytesReturned; - if (!DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, nullptr, 0, &m_session, sizeof(m_session), &BytesReturned, nullptr)) { - m_session = DVD_END_ALL_SESSIONS; - if (!DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), nullptr, 0, &BytesReturned, nullptr) - || !DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, nullptr, 0, &m_session, sizeof(m_session), &BytesReturned, nullptr)) { - Close(); - DWORD err = GetLastError(); - UNREFERENCED_PARAMETER(err); - return false; - } - } - - return true; -} - -void CDVDSession::EndSession() -{ - if (m_session != DVD_END_ALL_SESSIONS) { - DWORD BytesReturned; - DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), nullptr, 0, &BytesReturned, nullptr); - m_session = DVD_END_ALL_SESSIONS; - } -} - -bool CDVDSession::Authenticate() -{ - if (m_session == DVD_END_ALL_SESSIONS) { - return false; - } - - BYTE Challenge[10], Key[10]; - - for (BYTE i = 0; i < 10; i++) { - Challenge[i] = i; - } - - if (!SendKey(DvdChallengeKey, Challenge)) { - return false; - } - - if (!ReadKey(DvdBusKey1, Key)) { - return false; - } - - int varient = -1; - - for (int i = 31; i >= 0; i--) { - BYTE KeyCheck[5]; - CSSkey1(i, Challenge, KeyCheck); - if (!memcmp(KeyCheck, Key, 5)) { - varient = i; - } - } - - if (!ReadKey(DvdChallengeKey, Challenge)) { - return false; - } - - CSSkey2(varient, Challenge, &Key[5]); - - if (!SendKey(DvdBusKey2, &Key[5])) { - return false; - } - - CSSbuskey(varient, Key, m_SessionKey); - - return true; -} - -bool CDVDSession::GetDiscKey() -{ - if (m_session == DVD_END_ALL_SESSIONS) { - return false; - } - - BYTE DiscKeys[2048]; - if (!ReadKey(DvdDiskKey, DiscKeys)) { - return false; - } - - for (int i = 0; i < g_nPlayerKeys; i++) { - for (int j = 1; j < 409; j++) { - BYTE DiscKey[6]; - memcpy(DiscKey, &DiscKeys[j * 5], 5); - DiscKey[5] = 0; - - CSSdisckey(DiscKey, g_PlayerKeys[i]); - - BYTE Hash[6]; - memcpy(Hash, &DiscKeys[0], 5); - Hash[5] = 0; - - CSSdisckey(Hash, DiscKey); - - if (!memcmp(Hash, DiscKey, 6)) { - memcpy(m_DiscKey, DiscKey, 6); - return true; - } - } - } - - return false; -} - -bool CDVDSession::GetTitleKey(int lba, BYTE* pKey) -{ - if (m_session == DVD_END_ALL_SESSIONS) { - return false; - } - - if (!ReadKey(DvdTitleKey, pKey, lba)) { - return false; - } - - if (!(pKey[0] | pKey[1] | pKey[2] | pKey[3] | pKey[4])) { - return false; - } - - pKey[5] = 0; - - CSStitlekey(pKey, m_DiscKey); - - return true; -} - -static void Reverse(BYTE* d, BYTE* s, int len) -{ - if (d == s) { - for (s += len - 1; d < s; d++, s--) { - *d ^= *s, *s ^= *d, *d ^= *s; - } - } else { - for (int i = 0; i < len; i++) { - d[i] = s[len - 1 - i]; - } - } -} - -bool CDVDSession::SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData) -{ - CAutoVectorPtr key; - DVD_COPY_PROTECT_KEY* pKey = nullptr; - - auto allocateKey = [&](ULONG len) { - bool bSuccess = key.Allocate(len); - if (bSuccess) { - pKey = (DVD_COPY_PROTECT_KEY*)(BYTE*)key; - pKey->KeyLength = len; - } - return bSuccess; - }; - - switch (KeyType) { - case DvdChallengeKey: - if (allocateKey(DVD_CHALLENGE_KEY_LENGTH)) { - Reverse(pKey->KeyData, pKeyData, 10); - } - break; - case DvdBusKey2: - if (allocateKey(DVD_BUS_KEY_LENGTH)) { - Reverse(pKey->KeyData, pKeyData, 5); - } - break; - default: - break; - } - - if (!pKey) { - return false; - } - - pKey->SessionId = m_session; - pKey->KeyType = KeyType; - pKey->KeyFlags = 0; - - DWORD dwBytesReturned; - return !!DeviceIoControl(m_hDrive, IOCTL_DVD_SEND_KEY, pKey, pKey->KeyLength, nullptr, 0, &dwBytesReturned, nullptr); -} - -bool CDVDSession::ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba) -{ - CAutoVectorPtr key; - DVD_COPY_PROTECT_KEY* pKey = nullptr; - - auto allocateKey = [&](ULONG len) { - bool bSuccess = key.Allocate(len); - if (bSuccess) { - pKey = (DVD_COPY_PROTECT_KEY*)(BYTE*)key; - pKey->KeyLength = len; - } - return bSuccess; - }; - - switch (KeyType) { - case DvdChallengeKey: - if (allocateKey(DVD_CHALLENGE_KEY_LENGTH)) { - pKey->Parameters.TitleOffset.QuadPart = 0; - } - break; - case DvdBusKey1: - if (allocateKey(DVD_BUS_KEY_LENGTH)) { - pKey->Parameters.TitleOffset.QuadPart = 0; - } - break; - case DvdDiskKey: - if (allocateKey(DVD_DISK_KEY_LENGTH)) { - pKey->Parameters.TitleOffset.QuadPart = 0; - } - break; - case DvdTitleKey: - if (allocateKey(DVD_TITLE_KEY_LENGTH)) { - pKey->Parameters.TitleOffset.QuadPart = 2048i64 * lba; - } - break; - default: - break; - } - - if (!pKey) { - return false; - } - - pKey->SessionId = m_session; - pKey->KeyType = KeyType; - pKey->KeyFlags = 0; - - DWORD dwBytesReturned; - if (!DeviceIoControl(m_hDrive, IOCTL_DVD_READ_KEY, pKey, pKey->KeyLength, pKey, pKey->KeyLength, &dwBytesReturned, nullptr)) { - DWORD err = GetLastError(); - UNREFERENCED_PARAMETER(err); - return false; - } - - switch (KeyType) { - case DvdChallengeKey: - Reverse(pKeyData, pKey->KeyData, 10); - break; - case DvdBusKey1: - Reverse(pKeyData, pKey->KeyData, 5); - break; - case DvdDiskKey: - memcpy(pKeyData, pKey->KeyData, 2048); - for (int i = 0; i < 2048 / 5; i++) { - pKeyData[i] ^= m_SessionKey[4 - (i % 5)]; - } - break; - case DvdTitleKey: - memcpy(pKeyData, pKey->KeyData, 5); - for (int i = 0; i < 5; i++) { - pKeyData[i] ^= m_SessionKey[4 - (i % 5)]; - } - break; - default: - break; - } - - return true; -} - -// -// CLBAFile -// - -CLBAFile::CLBAFile() -{ -} - -CLBAFile::~CLBAFile() -{ -} - -bool CLBAFile::IsOpen() const -{ - return (m_hFile != hFileNull); -} - -bool CLBAFile::Open(LPCTSTR path) -{ - Close(); - - return !!CFile::Open(path, modeRead | typeBinary | shareDenyNone | osSequentialScan); -} - -void CLBAFile::Close() -{ - if (m_hFile != hFileNull) { - CFile::Close(); - } -} - -int CLBAFile::GetLengthLBA() const -{ - return (int)(CFile::GetLength() / 2048); -} - -int CLBAFile::GetPositionLBA() const -{ - return (int)(CFile::GetPosition() / 2048); -} - -int CLBAFile::Seek(int lba) -{ - return (int)(CFile::Seek(2048i64 * lba, CFile::begin) / 2048); -} - -bool CLBAFile::Read(BYTE* buff) -{ - return CFile::Read(buff, 2048) == 2048; -} - -// -// CVobFile -// - -CVobFile::CVobFile() -{ - Close(); - m_iChaptersCount = -1; -} - -CVobFile::~CVobFile() -{ -} - -bool CVobFile::IsDVD() const -{ - return m_fDVD; -} - -bool CVobFile::HasDiscKey(BYTE* key) const -{ - if (key) { - memcpy(key, m_DiscKey, 5); - } - return m_fHasDiscKey; -} - -bool CVobFile::HasTitleKey(BYTE* key) const -{ - if (key) { - memcpy(key, m_TitleKey, 5); - } - return m_fHasTitleKey; -} - -DWORD CVobFile::ReadDword() -{ - return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte(); -} - -short CVobFile::ReadShort() -{ - return (ReadByte() << 8 | ReadByte()); -} - -BYTE CVobFile::ReadByte() -{ - BYTE bVal; - m_ifoFile.Read(&bVal, sizeof(bVal)); - return bVal; -} - -void CVobFile::ReadBuffer(BYTE* pBuff, DWORD nLen) -{ - m_ifoFile.Read(pBuff, nLen); -} - -static short GetFrames(byte val) -{ - int byte0_high = val >> 4; - int byte0_low = val & 0x0F; - if (byte0_high > 11) { - return (short)(((byte0_high - 12) * 10) + byte0_low); - } - if ((byte0_high <= 3) || (byte0_high >= 8)) { - return 0; - } - return (short)(((byte0_high - 4) * 10) + byte0_low); -} - -bool CVobFile::GetTitleInfo(LPCTSTR fn, ULONG nTitleNum, ULONG& VTSN, ULONG& TTN) -{ - CFile ifoFile; - if (!ifoFile.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - - char hdr[IFO_HEADER_SIZE + 1]; - ifoFile.Read(hdr, IFO_HEADER_SIZE); - hdr[IFO_HEADER_SIZE] = '\0'; - if (strcmp(hdr, VIDEO_TS_HEADER)) { - return false; - } - - ifoFile.Seek(0xC4, CFile::begin); - DWORD TT_SRPTPosition; // Read a 32-bit unsigned big-endian integer - ifoFile.Read(&TT_SRPTPosition, sizeof(TT_SRPTPosition)); - TT_SRPTPosition = _byteswap_ulong(TT_SRPTPosition); - TT_SRPTPosition *= 2048; - ifoFile.Seek(TT_SRPTPosition + 8 + (nTitleNum - 1) * 12 + 6, CFile::begin); - BYTE tmp; - ifoFile.Read(&tmp, sizeof(tmp)); - VTSN = tmp; - ifoFile.Read(&tmp, sizeof(tmp)); - TTN = tmp; - - ifoFile.Close(); - - return true; -} - -bool CVobFile::Open(CString fn, CAtlList& vobs, ULONG nProgNum /*= 1*/, bool bAuthenticate /*= true*/) -{ - if (!m_ifoFile.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - - try { - char hdr[IFO_HEADER_SIZE + 1]; - m_ifoFile.Read(hdr, IFO_HEADER_SIZE); - hdr[IFO_HEADER_SIZE] = '\0'; - if (strcmp(hdr, VTS_HEADER)) { - return false; - } - - // Audio streams ... - m_ifoFile.Seek(0x202, CFile::begin); - BYTE buffer[SUBTITLE_BLOCK_SIZE]; - m_ifoFile.Read(buffer, AUDIO_BLOCK_SIZE); - CGolombBuffer gb(buffer, AUDIO_BLOCK_SIZE); - int stream_count = gb.ReadShort(); - for (int i = 0; i < std::min(stream_count, 8); i++) { - BYTE Coding_mode = (BYTE)gb.BitRead(3); - gb.BitRead(5);// skip - int ToAdd = 0; - switch (Coding_mode) { - case 0: - ToAdd = 0x80; - break; - case 4: - ToAdd = 0xA0; - break; - case 6: - ToAdd = 0x88; - break; - default: - break; - } - gb.ReadByte();// skip - char lang[2]; - gb.ReadBuffer((BYTE*)lang, 2); - gb.ReadDword();// skip - if (ToAdd) { - m_pStream_Lang[ToAdd + i] = ISOLang::ISO6391ToLanguage(lang); - } - } - - // Subtitle streams ... - m_ifoFile.Seek(0x254, CFile::begin); - m_ifoFile.Read(buffer, SUBTITLE_BLOCK_SIZE); - CGolombBuffer gb_s(buffer, SUBTITLE_BLOCK_SIZE); - stream_count = gb_s.ReadShort(); - for (int i = 0; i < std::min(stream_count, 32); i++) { - gb_s.ReadShort(); - char lang[2]; - gb_s.ReadBuffer((BYTE*)lang, 2); - gb_s.ReadShort(); - m_pStream_Lang[0x20 + i] = ISOLang::ISO6391ToLanguage(lang); - } - - // Chapters ... - m_ifoFile.Seek(0xCC, CFile::begin); //Get VTS_PGCI address - DWORD pcgITPosition = ReadDword() * 2048; - m_ifoFile.Seek(pcgITPosition, CFile::begin); - WORD nProgCount = (WORD)ReadShort(); - if (nProgNum > nProgCount) { - return false; - } - m_ifoFile.Seek(pcgITPosition + 8 * nProgNum + 4, CFile::begin); - DWORD chainOffset = ReadDword(); - m_ifoFile.Seek(pcgITPosition + chainOffset + 2, CFile::begin); - BYTE programChainPrograms = ReadByte(); - m_iChaptersCount = programChainPrograms; - m_ifoFile.Seek(pcgITPosition + chainOffset + 230, CFile::begin); - int programMapOffset = ReadShort(); - m_ifoFile.Seek(pcgITPosition + chainOffset + 0xE8, CFile::begin); - int cellTableOffset = ReadShort(); - REFERENCE_TIME rtDuration = 0; - m_pChapters[0] = 0; - for (BYTE currentProgram = 0; currentProgram < programChainPrograms; currentProgram++) { - m_ifoFile.Seek(pcgITPosition + chainOffset + programMapOffset + currentProgram, CFile::begin); - byte entryCell = ReadByte(); - byte exitCell = entryCell; - if (currentProgram < (programChainPrograms - 1)) { - m_ifoFile.Seek(pcgITPosition + chainOffset + programMapOffset + (currentProgram + 1), CFile::begin); - exitCell = ReadByte() - 1; - } - - REFERENCE_TIME rtTotalTime = 0; - for (int currentCell = entryCell; currentCell <= exitCell; currentCell++) { - int cellStart = cellTableOffset + ((currentCell - 1) * 0x18); - m_ifoFile.Seek(pcgITPosition + chainOffset + cellStart, CFile::begin); - BYTE bytes[4]; - ReadBuffer(bytes, 4); - int cellType = bytes[0] >> 6; - if (cellType == 0x00 || cellType == 0x01) { - m_ifoFile.Seek(pcgITPosition + chainOffset + cellStart + 4, CFile::begin); - ReadBuffer(bytes, 4); - short frames = GetFrames(bytes[3]); - int fpsMask = bytes[3] >> 6; - double fps = fpsMask == 0x01 ? 25 : fpsMask == 0x03 ? (30 / 1.001) : 0; - CString tmp; - int hours = bytes[0]; - tmp.Format(_T("%x"), hours); - _stscanf_s(tmp, _T("%d"), &hours); - int minutes = bytes[1]; - tmp.Format(_T("%x"), minutes); - _stscanf_s(tmp, _T("%d"), &minutes); - int seconds = bytes[2]; - tmp.Format(_T("%x"), seconds); - _stscanf_s(tmp, _T("%d"), &seconds); - int mmseconds = 0; - if (fps != 0) { - mmseconds = (int)(1000 * frames / fps); - } - - REFERENCE_TIME rtCurrentTime = 10000i64 * (((hours * 60 + minutes) * 60 + seconds) * 1000 + mmseconds); - rtTotalTime += rtCurrentTime; - } - } - rtDuration += rtTotalTime; - m_pChapters[currentProgram + 1] = rtDuration; - } - } - catch (...) { - m_ifoFile.Close(); - ASSERT(FALSE); - return false; - } - - m_ifoFile.Close(); - - int offset = -1; - - vobs.RemoveAll(); - - fn = fn.Left(fn.ReverseFind('.') + 1); - fn.TrimRight(_T(".0123456789")); - for (int i = 0; i < 100; i++) { - CString vob; - vob.Format(_T("%s%d.vob"), fn.GetString(), i); - - CFileStatus status; - try { - if (!CFile::GetStatus(vob, status)) { - if (i == 0) { - continue; - } - else { - break; - } - } - } - catch (...) { - break; - } - - if (status.m_size & 0x7ff) { - vobs.RemoveAll(); - break; - } - - if (status.m_size > 0) { - vobs.AddTail(vob); - } - - if (i == 0) { - offset = (int)(status.m_size / 0x800); - } - } - - return Open(vobs, offset, bAuthenticate); -} - -bool CVobFile::Open(const CAtlList& vobs, int offset /*= -1*/, bool bAuthenticate /*= true*/) -{ - Close(); - - if (vobs.IsEmpty()) { - return false; - } - - m_offsetAuth = offset; - if (vobs.GetCount() == 1) { - m_offsetAuth = -1; - } - m_offset = std::max(m_offsetAuth, 0); - - POSITION pos = vobs.GetHeadPosition(); - while (pos) { - CString fn = vobs.GetNext(pos); - - WIN32_FIND_DATA fd; - HANDLE h = FindFirstFile(fn, &fd); - if (h == INVALID_HANDLE_VALUE) { - m_files.RemoveAll(); - return false; - } - FindClose(h); - - file_t f; - f.fn = fn; - f.size = (int)(((__int64(fd.nFileSizeHigh) << 32) | fd.nFileSizeLow) / 2048); - m_files.Add(f); - - m_size += f.size; - } - - return bAuthenticate ? Authenticate() : true; -} - -bool CVobFile::Authenticate() -{ - m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false; - - if (!m_files.IsEmpty() && CDVDSession::Open(m_files[0].fn)) { - for (size_t i = 0; !m_fHasTitleKey && i < m_files.GetCount(); i++) { - if (BeginSession()) { - m_fDVD = true; - CDVDSession::Authenticate(); - m_fHasDiscKey = GetDiscKey(); - EndSession(); - } else { - CString fn = m_files[0].fn; - fn.MakeLower(); - - if (fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM) { - m_fDVD = true; - } - - break; - } - - if (tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(_T(':')) + 1)))) { - DWORD start, end; - if (udf_get_lba(m_hDrive, f, &start, &end)) { - if (BeginSession()) { - CDVDSession::Authenticate(); - m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey); - EndSession(); - } - } - - udf_free(f); - } - - BYTE key[5]; - if (HasTitleKey(key) && i == 0 && m_offsetAuth >= 0) { - i++; - - if (BeginSession()) { - m_fDVD = true; - CDVDSession::Authenticate(); - m_fHasDiscKey = GetDiscKey(); - EndSession(); - } else { - break; - } - - if (tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(_T(':')) + 1)))) { - DWORD start, end; - if (udf_get_lba(m_hDrive, f, &start, &end)) { - if (BeginSession()) { - CDVDSession::Authenticate(); - m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey); - EndSession(); - } - } - - udf_free(f); - } - - if (!m_fHasTitleKey) { - memcpy(m_TitleKey, key, 5); - m_fHasTitleKey = true; - } - } - } - } - - /*if(!m_files.IsEmpty() && !m_fDVD) { - CString fn = m_files[0].fn; - fn.MakeLower(); - - if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM) - { - m_fDVD = true; - } - }*/ - - return true; -} - -void CVobFile::Close() -{ - CDVDSession::Close(); - m_files.RemoveAll(); - m_iFile = -1; - m_pos = m_size = m_offset = m_offsetAuth = 0; - m_file.Close(); - m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false; -} - -int CVobFile::GetLength() const -{ - return (m_size - m_offset); -} - -int CVobFile::GetPosition() const -{ - return (m_pos - m_offset); -} - -int CVobFile::Seek(int pos) -{ - pos = std::min(std::max(pos + m_offset, m_offset), m_size - 1); - - int i = -1; - int size = 0; - - // this suxx, but won't take long - do { - size += m_files[++i].size; - } while (i < (int)m_files.GetCount() && pos >= size); - - if (i != m_iFile && i < (int)m_files.GetCount()) { - if (!m_file.Open(m_files[i].fn)) { - return m_pos; - } - - m_iFile = i; - } - - m_pos = pos; - - pos -= (size - m_files[i].size); - try { - m_file.Seek(pos); - } catch (...) { - return -1; - } - - return GetPosition(); -} - -bool CVobFile::Read(BYTE* buff) -{ - if (m_pos >= m_size) { - return false; - } - - if (m_file.IsOpen() && m_file.GetPositionLBA() == m_file.GetLengthLBA()) { - m_file.Close(); - } - - if (!m_file.IsOpen()) { - if (m_iFile >= (int)m_files.GetCount() - 1) { - return false; - } - - if (!m_file.Open(m_files[++m_iFile].fn)) { - m_iFile = -1; - return false; - } - } - - if (!m_file.Read(buff)) { - // dvd still locked? - return false; - } - - m_pos++; - - if (buff[0x14] & 0x30) { - if (m_fHasTitleKey) { - CSSdescramble(buff, m_TitleKey); - buff[0x14] &= ~0x30; - } else { - // under win9x this is normal, but I'm not developing under win9x :P - ASSERT(0); - } - } - - return true; -} - -BSTR CVobFile::GetTrackName(UINT aTrackIdx) const -{ - CString trackName; - m_pStream_Lang.Lookup(aTrackIdx, trackName); - return trackName.AllocSysString(); -} - -REFERENCE_TIME CVobFile::GetChapterOffset(UINT ChapterNumber) const -{ - REFERENCE_TIME rtChapterOffset = 0; - ASSERT(ChapterNumber < BYTE_MAX); - m_pChapters.Lookup((BYTE)ChapterNumber, rtChapterOffset); - return rtChapterOffset; -} +#include "stdafx.h" +#include +#include +#include "VobFile.h" +#include "CSSauth.h" +#include "CSSscramble.h" +#include "udf.h" + +#include "../DSUtil/GolombBuffer.h" +#include "../DSUtil/DSUtil.h" +#include "../DSUtil/ISOLang.h" + +#define AUDIO_BLOCK_SIZE 66 +#define SUBTITLE_BLOCK_SIZE 194 +#define IFO_HEADER_SIZE 12 +#define VIDEO_TS_HEADER "DVDVIDEO-VMG" +#define VTS_HEADER "DVDVIDEO-VTS" + +// +// CDVDSession +// + +CDVDSession::CDVDSession() + : m_hDrive(INVALID_HANDLE_VALUE) + , m_session(DVD_END_ALL_SESSIONS) +{ + ZeroMemory(m_SessionKey, sizeof(m_SessionKey)); + ZeroMemory(m_DiscKey, sizeof(m_DiscKey)); + ZeroMemory(m_TitleKey, sizeof(m_TitleKey)); +} + +CDVDSession::~CDVDSession() +{ + EndSession(); +} + +bool CDVDSession::Open(LPCTSTR path) +{ + Close(); + + CString fn = path; + CString drive = _T("\\\\.\\") + fn.Left(fn.Find(':') + 1); + + m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); + if (m_hDrive == INVALID_HANDLE_VALUE) { + return false; + } + + return true; +} + +void CDVDSession::Close() +{ + if (m_hDrive != INVALID_HANDLE_VALUE) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + } +} + +bool CDVDSession::BeginSession() +{ + EndSession(); + + if (m_hDrive == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD BytesReturned; + if (!DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, nullptr, 0, &m_session, sizeof(m_session), &BytesReturned, nullptr)) { + m_session = DVD_END_ALL_SESSIONS; + if (!DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), nullptr, 0, &BytesReturned, nullptr) + || !DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, nullptr, 0, &m_session, sizeof(m_session), &BytesReturned, nullptr)) { + Close(); + DWORD err = GetLastError(); + UNREFERENCED_PARAMETER(err); + return false; + } + } + + return true; +} + +void CDVDSession::EndSession() +{ + if (m_session != DVD_END_ALL_SESSIONS) { + DWORD BytesReturned; + DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), nullptr, 0, &BytesReturned, nullptr); + m_session = DVD_END_ALL_SESSIONS; + } +} + +bool CDVDSession::Authenticate() +{ + if (m_session == DVD_END_ALL_SESSIONS) { + return false; + } + + BYTE Challenge[10], Key[10]; + + for (BYTE i = 0; i < 10; i++) { + Challenge[i] = i; + } + + if (!SendKey(DvdChallengeKey, Challenge)) { + return false; + } + + if (!ReadKey(DvdBusKey1, Key)) { + return false; + } + + int varient = -1; + + for (int i = 31; i >= 0; i--) { + BYTE KeyCheck[5]; + CSSkey1(i, Challenge, KeyCheck); + if (!memcmp(KeyCheck, Key, 5)) { + varient = i; + } + } + + if (!ReadKey(DvdChallengeKey, Challenge)) { + return false; + } + + CSSkey2(varient, Challenge, &Key[5]); + + if (!SendKey(DvdBusKey2, &Key[5])) { + return false; + } + + CSSbuskey(varient, Key, m_SessionKey); + + return true; +} + +bool CDVDSession::GetDiscKey() +{ + if (m_session == DVD_END_ALL_SESSIONS) { + return false; + } + + BYTE DiscKeys[2048]; + if (!ReadKey(DvdDiskKey, DiscKeys)) { + return false; + } + + for (int i = 0; i < g_nPlayerKeys; i++) { + for (int j = 1; j < 409; j++) { + BYTE DiscKey[6]; + memcpy(DiscKey, &DiscKeys[j * 5], 5); + DiscKey[5] = 0; + + CSSdisckey(DiscKey, g_PlayerKeys[i]); + + BYTE Hash[6]; + memcpy(Hash, &DiscKeys[0], 5); + Hash[5] = 0; + + CSSdisckey(Hash, DiscKey); + + if (!memcmp(Hash, DiscKey, 6)) { + memcpy(m_DiscKey, DiscKey, 6); + return true; + } + } + } + + return false; +} + +bool CDVDSession::GetTitleKey(int lba, BYTE* pKey) +{ + if (m_session == DVD_END_ALL_SESSIONS) { + return false; + } + + if (!ReadKey(DvdTitleKey, pKey, lba)) { + return false; + } + + if (!(pKey[0] | pKey[1] | pKey[2] | pKey[3] | pKey[4])) { + return false; + } + + pKey[5] = 0; + + CSStitlekey(pKey, m_DiscKey); + + return true; +} + +static void Reverse(BYTE* d, BYTE* s, int len) +{ + if (d == s) { + for (s += len - 1; d < s; d++, s--) { + *d ^= *s, *s ^= *d, *d ^= *s; + } + } else { + for (int i = 0; i < len; i++) { + d[i] = s[len - 1 - i]; + } + } +} + +bool CDVDSession::SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData) +{ + CAutoVectorPtr key; + DVD_COPY_PROTECT_KEY* pKey = nullptr; + + auto allocateKey = [&](ULONG len) { + bool bSuccess = key.Allocate(len); + if (bSuccess) { + pKey = (DVD_COPY_PROTECT_KEY*)(BYTE*)key; + pKey->KeyLength = len; + } + return bSuccess; + }; + + switch (KeyType) { + case DvdChallengeKey: + if (allocateKey(DVD_CHALLENGE_KEY_LENGTH)) { + Reverse(pKey->KeyData, pKeyData, 10); + } + break; + case DvdBusKey2: + if (allocateKey(DVD_BUS_KEY_LENGTH)) { + Reverse(pKey->KeyData, pKeyData, 5); + } + break; + default: + break; + } + + if (!pKey) { + return false; + } + + pKey->SessionId = m_session; + pKey->KeyType = KeyType; + pKey->KeyFlags = 0; + + DWORD dwBytesReturned; + return !!DeviceIoControl(m_hDrive, IOCTL_DVD_SEND_KEY, pKey, pKey->KeyLength, nullptr, 0, &dwBytesReturned, nullptr); +} + +bool CDVDSession::ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba) +{ + CAutoVectorPtr key; + DVD_COPY_PROTECT_KEY* pKey = nullptr; + + auto allocateKey = [&](ULONG len) { + bool bSuccess = key.Allocate(len); + if (bSuccess) { + pKey = (DVD_COPY_PROTECT_KEY*)(BYTE*)key; + pKey->KeyLength = len; + } + return bSuccess; + }; + + switch (KeyType) { + case DvdChallengeKey: + if (allocateKey(DVD_CHALLENGE_KEY_LENGTH)) { + pKey->Parameters.TitleOffset.QuadPart = 0; + } + break; + case DvdBusKey1: + if (allocateKey(DVD_BUS_KEY_LENGTH)) { + pKey->Parameters.TitleOffset.QuadPart = 0; + } + break; + case DvdDiskKey: + if (allocateKey(DVD_DISK_KEY_LENGTH)) { + pKey->Parameters.TitleOffset.QuadPart = 0; + } + break; + case DvdTitleKey: + if (allocateKey(DVD_TITLE_KEY_LENGTH)) { + pKey->Parameters.TitleOffset.QuadPart = 2048i64 * lba; + } + break; + default: + break; + } + + if (!pKey) { + return false; + } + + pKey->SessionId = m_session; + pKey->KeyType = KeyType; + pKey->KeyFlags = 0; + + DWORD dwBytesReturned; + if (!DeviceIoControl(m_hDrive, IOCTL_DVD_READ_KEY, pKey, pKey->KeyLength, pKey, pKey->KeyLength, &dwBytesReturned, nullptr)) { + DWORD err = GetLastError(); + UNREFERENCED_PARAMETER(err); + return false; + } + + switch (KeyType) { + case DvdChallengeKey: + Reverse(pKeyData, pKey->KeyData, 10); + break; + case DvdBusKey1: + Reverse(pKeyData, pKey->KeyData, 5); + break; + case DvdDiskKey: + memcpy(pKeyData, pKey->KeyData, 2048); + for (int i = 0; i < 2048 / 5; i++) { + pKeyData[i] ^= m_SessionKey[4 - (i % 5)]; + } + break; + case DvdTitleKey: + memcpy(pKeyData, pKey->KeyData, 5); + for (int i = 0; i < 5; i++) { + pKeyData[i] ^= m_SessionKey[4 - (i % 5)]; + } + break; + default: + break; + } + + return true; +} + +// +// CLBAFile +// + +CLBAFile::CLBAFile() +{ +} + +CLBAFile::~CLBAFile() +{ +} + +bool CLBAFile::IsOpen() const +{ + return (m_hFile != hFileNull); +} + +bool CLBAFile::Open(LPCTSTR path) +{ + Close(); + + return !!CFile::Open(path, modeRead | typeBinary | shareDenyNone | osSequentialScan); +} + +void CLBAFile::Close() +{ + if (m_hFile != hFileNull) { + CFile::Close(); + } +} + +int CLBAFile::GetLengthLBA() const +{ + return (int)(CFile::GetLength() / 2048); +} + +int CLBAFile::GetPositionLBA() const +{ + return (int)(CFile::GetPosition() / 2048); +} + +int CLBAFile::Seek(int lba) +{ + return (int)(CFile::Seek(2048i64 * lba, CFile::begin) / 2048); +} + +bool CLBAFile::Read(BYTE* buff) +{ + return CFile::Read(buff, 2048) == 2048; +} + +// +// CVobFile +// + +CVobFile::CVobFile() +{ + Close(); + m_iChaptersCount = -1; +} + +CVobFile::~CVobFile() +{ +} + +bool CVobFile::IsDVD() const +{ + return m_fDVD; +} + +bool CVobFile::HasDiscKey(BYTE* key) const +{ + if (key) { + memcpy(key, m_DiscKey, 5); + } + return m_fHasDiscKey; +} + +bool CVobFile::HasTitleKey(BYTE* key) const +{ + if (key) { + memcpy(key, m_TitleKey, 5); + } + return m_fHasTitleKey; +} + +DWORD CVobFile::ReadDword() +{ + return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte(); +} + +short CVobFile::ReadShort() +{ + return (ReadByte() << 8 | ReadByte()); +} + +BYTE CVobFile::ReadByte() +{ + BYTE bVal; + m_ifoFile.Read(&bVal, sizeof(bVal)); + return bVal; +} + +void CVobFile::ReadBuffer(BYTE* pBuff, DWORD nLen) +{ + m_ifoFile.Read(pBuff, nLen); +} + +static short GetFrames(byte val) +{ + int byte0_high = val >> 4; + int byte0_low = val & 0x0F; + if (byte0_high > 11) { + return (short)(((byte0_high - 12) * 10) + byte0_low); + } + if ((byte0_high <= 3) || (byte0_high >= 8)) { + return 0; + } + return (short)(((byte0_high - 4) * 10) + byte0_low); +} + +bool CVobFile::GetTitleInfo(LPCTSTR fn, ULONG nTitleNum, ULONG& VTSN, ULONG& TTN) +{ + CFile ifoFile; + if (!ifoFile.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + + char hdr[IFO_HEADER_SIZE + 1]; + ifoFile.Read(hdr, IFO_HEADER_SIZE); + hdr[IFO_HEADER_SIZE] = '\0'; + if (strcmp(hdr, VIDEO_TS_HEADER)) { + return false; + } + + ifoFile.Seek(0xC4, CFile::begin); + DWORD TT_SRPTPosition; // Read a 32-bit unsigned big-endian integer + ifoFile.Read(&TT_SRPTPosition, sizeof(TT_SRPTPosition)); + TT_SRPTPosition = _byteswap_ulong(TT_SRPTPosition); + TT_SRPTPosition *= 2048; + ifoFile.Seek(TT_SRPTPosition + 8 + (nTitleNum - 1) * 12 + 6, CFile::begin); + BYTE tmp; + ifoFile.Read(&tmp, sizeof(tmp)); + VTSN = tmp; + ifoFile.Read(&tmp, sizeof(tmp)); + TTN = tmp; + + ifoFile.Close(); + + return true; +} + +bool CVobFile::Open(CString fn, CAtlList& vobs, ULONG nProgNum /*= 1*/, bool bAuthenticate /*= true*/) +{ + if (!m_ifoFile.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + + try { + char hdr[IFO_HEADER_SIZE + 1]; + m_ifoFile.Read(hdr, IFO_HEADER_SIZE); + hdr[IFO_HEADER_SIZE] = '\0'; + if (strcmp(hdr, VTS_HEADER)) { + return false; + } + + // Audio streams ... + m_ifoFile.Seek(0x202, CFile::begin); + BYTE buffer[SUBTITLE_BLOCK_SIZE]; + m_ifoFile.Read(buffer, AUDIO_BLOCK_SIZE); + CGolombBuffer gb(buffer, AUDIO_BLOCK_SIZE); + int stream_count = gb.ReadShort(); + for (int i = 0; i < std::min(stream_count, 8); i++) { + BYTE Coding_mode = (BYTE)gb.BitRead(3); + gb.BitRead(5);// skip + int ToAdd = 0; + switch (Coding_mode) { + case 0: + ToAdd = 0x80; + break; + case 4: + ToAdd = 0xA0; + break; + case 6: + ToAdd = 0x88; + break; + default: + break; + } + gb.ReadByte();// skip + char lang[2]; + gb.ReadBuffer((BYTE*)lang, 2); + gb.ReadDword();// skip + if (ToAdd) { + m_pStream_Lang[ToAdd + i] = ISOLang::ISO6391ToLanguage(lang); + } + } + + // Subtitle streams ... + m_ifoFile.Seek(0x254, CFile::begin); + m_ifoFile.Read(buffer, SUBTITLE_BLOCK_SIZE); + CGolombBuffer gb_s(buffer, SUBTITLE_BLOCK_SIZE); + stream_count = gb_s.ReadShort(); + for (int i = 0; i < std::min(stream_count, 32); i++) { + gb_s.ReadShort(); + char lang[2]; + gb_s.ReadBuffer((BYTE*)lang, 2); + gb_s.ReadShort(); + m_pStream_Lang[0x20 + i] = ISOLang::ISO6391ToLanguage(lang); + } + + // Chapters ... + m_ifoFile.Seek(0xCC, CFile::begin); //Get VTS_PGCI address + DWORD pcgITPosition = ReadDword() * 2048; + m_ifoFile.Seek(pcgITPosition, CFile::begin); + WORD nProgCount = (WORD)ReadShort(); + if (nProgNum > nProgCount) { + return false; + } + m_ifoFile.Seek(pcgITPosition + 8 * nProgNum + 4, CFile::begin); + DWORD chainOffset = ReadDword(); + m_ifoFile.Seek(pcgITPosition + chainOffset + 2, CFile::begin); + BYTE programChainPrograms = ReadByte(); + m_iChaptersCount = programChainPrograms; + m_ifoFile.Seek(pcgITPosition + chainOffset + 230, CFile::begin); + int programMapOffset = ReadShort(); + m_ifoFile.Seek(pcgITPosition + chainOffset + 0xE8, CFile::begin); + int cellTableOffset = ReadShort(); + REFERENCE_TIME rtDuration = 0; + m_pChapters[0] = 0; + for (BYTE currentProgram = 0; currentProgram < programChainPrograms; currentProgram++) { + m_ifoFile.Seek(pcgITPosition + chainOffset + programMapOffset + currentProgram, CFile::begin); + byte entryCell = ReadByte(); + byte exitCell = entryCell; + if (currentProgram < (programChainPrograms - 1)) { + m_ifoFile.Seek(pcgITPosition + chainOffset + programMapOffset + (currentProgram + 1), CFile::begin); + exitCell = ReadByte() - 1; + } + + REFERENCE_TIME rtTotalTime = 0; + for (int currentCell = entryCell; currentCell <= exitCell; currentCell++) { + int cellStart = cellTableOffset + ((currentCell - 1) * 0x18); + m_ifoFile.Seek(pcgITPosition + chainOffset + cellStart, CFile::begin); + BYTE bytes[4]; + ReadBuffer(bytes, 4); + int cellType = bytes[0] >> 6; + if (cellType == 0x00 || cellType == 0x01) { + m_ifoFile.Seek(pcgITPosition + chainOffset + cellStart + 4, CFile::begin); + ReadBuffer(bytes, 4); + short frames = GetFrames(bytes[3]); + int fpsMask = bytes[3] >> 6; + double fps = fpsMask == 0x01 ? 25 : fpsMask == 0x03 ? (30 / 1.001) : 0; + CString tmp; + int hours = bytes[0]; + tmp.Format(_T("%x"), hours); + _stscanf_s(tmp, _T("%d"), &hours); + int minutes = bytes[1]; + tmp.Format(_T("%x"), minutes); + _stscanf_s(tmp, _T("%d"), &minutes); + int seconds = bytes[2]; + tmp.Format(_T("%x"), seconds); + _stscanf_s(tmp, _T("%d"), &seconds); + int mmseconds = 0; + if (fps != 0) { + mmseconds = (int)(1000 * frames / fps); + } + + REFERENCE_TIME rtCurrentTime = 10000i64 * (((hours * 60 + minutes) * 60 + seconds) * 1000 + mmseconds); + rtTotalTime += rtCurrentTime; + } + } + rtDuration += rtTotalTime; + m_pChapters[currentProgram + 1] = rtDuration; + } + } + catch (...) { + m_ifoFile.Close(); + ASSERT(FALSE); + return false; + } + + m_ifoFile.Close(); + + int offset = -1; + + vobs.RemoveAll(); + + fn = fn.Left(fn.ReverseFind('.') + 1); + fn.TrimRight(_T(".0123456789")); + for (int i = 0; i < 100; i++) { + CString vob; + vob.Format(_T("%s%d.vob"), fn.GetString(), i); + + CFileStatus status; + try { + if (!CFile::GetStatus(vob, status)) { + if (i == 0) { + continue; + } + else { + break; + } + } + } + catch (...) { + break; + } + + if (status.m_size & 0x7ff) { + vobs.RemoveAll(); + break; + } + + if (status.m_size > 0) { + vobs.AddTail(vob); + } + + if (i == 0) { + offset = (int)(status.m_size / 0x800); + } + } + + return Open(vobs, offset, bAuthenticate); +} + +bool CVobFile::Open(const CAtlList& vobs, int offset /*= -1*/, bool bAuthenticate /*= true*/) +{ + Close(); + + if (vobs.IsEmpty()) { + return false; + } + + m_offsetAuth = offset; + if (vobs.GetCount() == 1) { + m_offsetAuth = -1; + } + m_offset = std::max(m_offsetAuth, 0); + + POSITION pos = vobs.GetHeadPosition(); + while (pos) { + CString fn = vobs.GetNext(pos); + + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile(fn, &fd); + if (h == INVALID_HANDLE_VALUE) { + m_files.RemoveAll(); + return false; + } + FindClose(h); + + file_t f; + f.fn = fn; + f.size = (int)(((__int64(fd.nFileSizeHigh) << 32) | fd.nFileSizeLow) / 2048); + m_files.Add(f); + + m_size += f.size; + } + + return bAuthenticate ? Authenticate() : true; +} + +bool CVobFile::Authenticate() +{ + m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false; + + if (!m_files.IsEmpty() && CDVDSession::Open(m_files[0].fn)) { + for (size_t i = 0; !m_fHasTitleKey && i < m_files.GetCount(); i++) { + if (BeginSession()) { + m_fDVD = true; + CDVDSession::Authenticate(); + m_fHasDiscKey = GetDiscKey(); + EndSession(); + } else { + CString fn = m_files[0].fn; + fn.MakeLower(); + + if (fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM) { + m_fDVD = true; + } + + break; + } + + if (tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(_T(':')) + 1)))) { + DWORD start, end; + if (udf_get_lba(m_hDrive, f, &start, &end)) { + if (BeginSession()) { + CDVDSession::Authenticate(); + m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey); + EndSession(); + } + } + + udf_free(f); + } + + BYTE key[5]; + if (HasTitleKey(key) && i == 0 && m_offsetAuth >= 0) { + i++; + + if (BeginSession()) { + m_fDVD = true; + CDVDSession::Authenticate(); + m_fHasDiscKey = GetDiscKey(); + EndSession(); + } else { + break; + } + + if (tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(_T(':')) + 1)))) { + DWORD start, end; + if (udf_get_lba(m_hDrive, f, &start, &end)) { + if (BeginSession()) { + CDVDSession::Authenticate(); + m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey); + EndSession(); + } + } + + udf_free(f); + } + + if (!m_fHasTitleKey) { + memcpy(m_TitleKey, key, 5); + m_fHasTitleKey = true; + } + } + } + } + + /*if(!m_files.IsEmpty() && !m_fDVD) { + CString fn = m_files[0].fn; + fn.MakeLower(); + + if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM) + { + m_fDVD = true; + } + }*/ + + return true; +} + +void CVobFile::Close() +{ + CDVDSession::Close(); + m_files.RemoveAll(); + m_iFile = -1; + m_pos = m_size = m_offset = m_offsetAuth = 0; + m_file.Close(); + m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false; +} + +int CVobFile::GetLength() const +{ + return (m_size - m_offset); +} + +int CVobFile::GetPosition() const +{ + return (m_pos - m_offset); +} + +int CVobFile::Seek(int pos) +{ + pos = std::min(std::max(pos + m_offset, m_offset), m_size - 1); + + int i = -1; + int size = 0; + + // this suxx, but won't take long + do { + size += m_files[++i].size; + } while (i < (int)m_files.GetCount() && pos >= size); + + if (i != m_iFile && i < (int)m_files.GetCount()) { + if (!m_file.Open(m_files[i].fn)) { + return m_pos; + } + + m_iFile = i; + } + + m_pos = pos; + + pos -= (size - m_files[i].size); + try { + m_file.Seek(pos); + } catch (...) { + return -1; + } + + return GetPosition(); +} + +bool CVobFile::Read(BYTE* buff) +{ + if (m_pos >= m_size) { + return false; + } + + if (m_file.IsOpen() && m_file.GetPositionLBA() == m_file.GetLengthLBA()) { + m_file.Close(); + } + + if (!m_file.IsOpen()) { + if (m_iFile >= (int)m_files.GetCount() - 1) { + return false; + } + + if (!m_file.Open(m_files[++m_iFile].fn)) { + m_iFile = -1; + return false; + } + } + + if (!m_file.Read(buff)) { + // dvd still locked? + return false; + } + + m_pos++; + + if (buff[0x14] & 0x30) { + if (m_fHasTitleKey) { + CSSdescramble(buff, m_TitleKey); + buff[0x14] &= ~0x30; + } else { + // under win9x this is normal, but I'm not developing under win9x :P + ASSERT(0); + } + } + + return true; +} + +BSTR CVobFile::GetTrackName(UINT aTrackIdx) const +{ + CString trackName; + m_pStream_Lang.Lookup(aTrackIdx, trackName); + return trackName.AllocSysString(); +} + +REFERENCE_TIME CVobFile::GetChapterOffset(UINT ChapterNumber) const +{ + REFERENCE_TIME rtChapterOffset = 0; + ASSERT(ChapterNumber < BYTE_MAX); + m_pChapters.Lookup((BYTE)ChapterNumber, rtChapterOffset); + return rtChapterOffset; +} diff --git a/src/DeCSS/VobFile.h b/src/DeCSS/VobFile.h index 08ef0e2e492..88f6093a6dd 100644 --- a/src/DeCSS/VobFile.h +++ b/src/DeCSS/VobFile.h @@ -1,107 +1,107 @@ -#pragma once - -#include -#include -#include "winddk/ntddcdvd.h" - -class CDVDSession -{ -protected: - HANDLE m_hDrive; - - DVD_SESSION_ID m_session; - bool BeginSession(); - void EndSession(); - - BYTE m_SessionKey[5]; - bool Authenticate(); - - BYTE m_DiscKey[6], m_TitleKey[6]; - bool GetDiscKey(); - bool GetTitleKey(int lba, BYTE* pKey); - -public: - CDVDSession(); - virtual ~CDVDSession(); - - bool Open(LPCTSTR path); - void Close(); - - operator HANDLE() const { return m_hDrive; } - operator DVD_SESSION_ID() const { return m_session; } - - bool SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData); - bool ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba = 0); -}; - -class CLBAFile : private CFile -{ -public: - CLBAFile(); - virtual ~CLBAFile(); - - bool IsOpen() const; - - bool Open(LPCTSTR path); - void Close(); - - int GetLengthLBA() const; - int GetPositionLBA() const; - int Seek(int lba); - bool Read(BYTE* buff); -}; - -class CVobFile : public CDVDSession -{ - // all files - struct file_t { - CString fn; - int size; - }; - - CAtlArray m_files; - int m_iFile; - int m_pos, m_size, m_offset, m_offsetAuth; - - // currently opened file - CLBAFile m_file; - - // attribs - bool m_fDVD, m_fHasDiscKey, m_fHasTitleKey; - - CAtlMap m_pStream_Lang; - - int m_iChaptersCount; - CAtlMap m_pChapters; -public: - CVobFile(); - virtual ~CVobFile(); - - static bool GetTitleInfo(LPCTSTR fn, ULONG nTitleNum, ULONG& VTSN /* out */, ULONG& TTN /* out */); // video_ts.ifo - - bool IsDVD() const; - bool HasDiscKey(BYTE* key) const; - bool HasTitleKey(BYTE* key) const; - - bool Open(CString fn, CAtlList& files /* out */, ULONG nProgNum = 1, bool bAuthenticate = true); // vts ifo - bool Open(const CAtlList& files, int offset = -1, bool bAuthenticate = true); // vts vobs, video vob offset in lba - bool Authenticate(); - void Close(); - - int GetLength() const; - int GetPosition() const; - int Seek(int pos); - bool Read(BYTE* buff); - - BSTR GetTrackName(UINT aTrackIdx) const; - - int GetChaptersCount() const { return m_iChaptersCount; } - LONGLONG GetChapterOffset(UINT chapterNumber) const; - -private: - CFile m_ifoFile; - DWORD ReadDword(); - short ReadShort(); - BYTE ReadByte(); - void ReadBuffer(BYTE* pBuff, DWORD nLen); -}; +#pragma once + +#include +#include +#include "winddk/ntddcdvd.h" + +class CDVDSession +{ +protected: + HANDLE m_hDrive; + + DVD_SESSION_ID m_session; + bool BeginSession(); + void EndSession(); + + BYTE m_SessionKey[5]; + bool Authenticate(); + + BYTE m_DiscKey[6], m_TitleKey[6]; + bool GetDiscKey(); + bool GetTitleKey(int lba, BYTE* pKey); + +public: + CDVDSession(); + virtual ~CDVDSession(); + + bool Open(LPCTSTR path); + void Close(); + + operator HANDLE() const { return m_hDrive; } + operator DVD_SESSION_ID() const { return m_session; } + + bool SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData); + bool ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba = 0); +}; + +class CLBAFile : private CFile +{ +public: + CLBAFile(); + virtual ~CLBAFile(); + + bool IsOpen() const; + + bool Open(LPCTSTR path); + void Close(); + + int GetLengthLBA() const; + int GetPositionLBA() const; + int Seek(int lba); + bool Read(BYTE* buff); +}; + +class CVobFile : public CDVDSession +{ + // all files + struct file_t { + CString fn; + int size; + }; + + CAtlArray m_files; + int m_iFile; + int m_pos, m_size, m_offset, m_offsetAuth; + + // currently opened file + CLBAFile m_file; + + // attribs + bool m_fDVD, m_fHasDiscKey, m_fHasTitleKey; + + CAtlMap m_pStream_Lang; + + int m_iChaptersCount; + CAtlMap m_pChapters; +public: + CVobFile(); + virtual ~CVobFile(); + + static bool GetTitleInfo(LPCTSTR fn, ULONG nTitleNum, ULONG& VTSN /* out */, ULONG& TTN /* out */); // video_ts.ifo + + bool IsDVD() const; + bool HasDiscKey(BYTE* key) const; + bool HasTitleKey(BYTE* key) const; + + bool Open(CString fn, CAtlList& files /* out */, ULONG nProgNum = 1, bool bAuthenticate = true); // vts ifo + bool Open(const CAtlList& files, int offset = -1, bool bAuthenticate = true); // vts vobs, video vob offset in lba + bool Authenticate(); + void Close(); + + int GetLength() const; + int GetPosition() const; + int Seek(int pos); + bool Read(BYTE* buff); + + BSTR GetTrackName(UINT aTrackIdx) const; + + int GetChaptersCount() const { return m_iChaptersCount; } + LONGLONG GetChapterOffset(UINT chapterNumber) const; + +private: + CFile m_ifoFile; + DWORD ReadDword(); + short ReadShort(); + BYTE ReadByte(); + void ReadBuffer(BYTE* pBuff, DWORD nLen); +}; diff --git a/src/DeCSS/stdafx.cpp b/src/DeCSS/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/DeCSS/stdafx.cpp +++ b/src/DeCSS/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/DeCSS/stdafx.h b/src/DeCSS/stdafx.h index 377c0d5ea46..3c373d921ec 100644 --- a/src/DeCSS/stdafx.h +++ b/src/DeCSS/stdafx.h @@ -1,32 +1,32 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components -#include "BaseClasses/streams.h" +/* + * (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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components +#include "BaseClasses/streams.h" diff --git a/src/DeCSS/udf.cpp b/src/DeCSS/udf.cpp index ac1e08786a5..10b6ed2445d 100644 --- a/src/DeCSS/udf.cpp +++ b/src/DeCSS/udf.cpp @@ -1,352 +1,352 @@ -/************************************************************************* - vStrip by [maven] (maven@maven.de) - udf.c: routines for udf-parsing (because windows just doesn't cut it), - refs: udf102.pdf, udf200.pdf -*************************************************************************/ - -#include "stdafx.h" -#include "udf.h" - -static bool aspi_GetSectorInfo(const HANDLE hDrive, DWORD* sec_size, DWORD* max_sec) -{ - LARGE_INTEGER size = {0, 0}; - GetFileSizeEx(hDrive, &size); - - *sec_size = 2048; - *max_sec = (DWORD)(size.QuadPart / *sec_size); - - return true; -} - -static bool aspi_ReadSectors(const HANDLE hDrive, int lba, int nSectors, DWORD sec_size, BYTE* sector) -{ - DWORD nbr = 0; - LARGE_INTEGER offset; - offset.QuadPart = lba*sec_size; - SetFilePointerEx(hDrive, offset, &offset, FILE_BEGIN); - return lba*sec_size == offset.QuadPart && ReadFile(hDrive, sector, nSectors*sec_size, &nbr, nullptr); -} - -static bool udf_GetLBA(const tp_udf_FileEntry fe, const DWORD sec_size, DWORD *start, DWORD *end) -{ - if (fe->LengthofAllocationDescriptors == 0) { - return false; - } - switch (fe->ICBTag.Flags & udf_icbf_Mask) { - case udf_icbf_ShortAd: { - tp_udf_short_ad ad = (tp_udf_short_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); - - *start = ad->Location; - *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; - return true; - } - break; - case udf_icbf_LongAd: { - tp_udf_long_ad ad = (tp_udf_long_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); - - *start = ad->Location.Location; // ignore partition number - *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; - return true; - } - break; - case udf_icbf_ExtAd: { - tp_udf_ext_ad ad = (tp_udf_ext_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); - - *start = ad->Location.Location; // ignore partition number - *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; - return true; - } - break; - } - return false; -} - -tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number) -{ - BYTE sector[fio_SECTOR_SIZE]; - tp_udf_tag tag = (tp_udf_tag)sector; - DWORD sec_size, max_sec, i; - DWORD MVDS_lba, MVDS_lba_end, MVDS_back_lba, MVDS_back_lba_end; - DWORD FileDescriptorSequence_lba = 0; - DWORD partition_lba = 0; - tp_udf_AnchorVolumeDescriptorPointer avd; - bool res, part_valid, vol_valid; - - if (!aspi_GetSectorInfo(hDrive, &sec_size, &max_sec)) { - return nullptr; - } - - if (sec_size != fio_SECTOR_SIZE || max_sec < 256) { - return nullptr; - } - - // read AnchorVolumeDescriptorPointer at 256 (or MaxSec) (Tag == 2) - res = aspi_ReadSectors(hDrive, 256, 1, sec_size, sector); - if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor) { - res = aspi_ReadSectors(hDrive, max_sec, 1, sec_size, sector); - if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor) { - return nullptr; - } - } - - // check Static Structures - - // get MainVolumeDescriptorSequence Location & Length - avd = (tp_udf_AnchorVolumeDescriptorPointer)sector; - MVDS_lba = avd->MainVolumeDescriptorSequenceExtent.Location; - MVDS_lba_end = MVDS_lba + (avd->MainVolumeDescriptorSequenceExtent.Length - 1) / sec_size; - MVDS_back_lba = avd->ReserveVolumeDescriptorSequenceExtent.Location; - MVDS_back_lba_end = MVDS_back_lba + (avd->ReserveVolumeDescriptorSequenceExtent.Length - 1) / sec_size; - - // read MVDS_Location..MVDS_Location + (MVDS_Length - 1) / SectorSize sectors - - part_valid = vol_valid = false; - i = 1; - do { - // try twice (if we need to) for ReserveAnchor - DWORD j = MVDS_lba; - do { - res = aspi_ReadSectors(hDrive, j++, 1, sec_size, sector); - if (res) { - if (tag->TagIdentifier == udf_TAG_PartitionDescriptor && !part_valid) { - // get stuff out of partition - tp_udf_PartitionDescriptor par = (tp_udf_PartitionDescriptor )sector; - - part_valid = par->PartitionNumber == partition_number; - if (part_valid) { - // extract par->PartitionStartingLocation, par->PartitionLength - partition_lba = par->PartitionStartingLocation; - } - } else if (tag->TagIdentifier == udf_TAG_LogicalVolumeDescriptor && !vol_valid) { - // get stuff out of volume - tp_udf_LogicalVolumeDescriptor vol = (tp_udf_LogicalVolumeDescriptor)sector; - - // check_volume sector size - vol_valid = (vol->LogicalBlockSize == sec_size) && (partition_number == vol->FileSetDescriptorSequence.Location.PartitionNumber); - if (vol_valid) { - // extract vol->FileSetDescriptorSequence - FileDescriptorSequence_lba = vol->FileSetDescriptorSequence.Location.Location; - // DWORD FileDescriptorSequence_lba_end = FileDescriptorSequence_lba + ((vol->FileSetDescriptorSequence.Length & udf_LengthMask) - 1) / sec_size; - } - } - } else { - tag->TagIdentifier = 0; - } - } while (j <= MVDS_lba_end && tag->TagIdentifier != udf_TAG_TerminatingDescriptor && ((!part_valid) || (!vol_valid))); - - if ((!part_valid) || (!vol_valid)) { - // try backup - MVDS_lba = MVDS_back_lba; - MVDS_lba_end = MVDS_back_lba_end; - } - } while (i-- && ((!part_valid) || (!vol_valid))); - - if (part_valid && vol_valid) { - // read FileSetDescriptor, get RootDir Location & Length, RootDir Length != 0 - res = aspi_ReadSectors(hDrive, FileDescriptorSequence_lba + partition_lba, 1, sec_size, sector); - if (res && tag->TagIdentifier == udf_TAG_FileSetDescriptor) { - tp_udf_FileSetDescriptor fsd = (tp_udf_FileSetDescriptor)sector; - - if (partition_number == fsd->RootDirectoryICB.Location.PartitionNumber) { - DWORD parent_icb = fsd->RootDirectoryICB.Location.Location; - res = aspi_ReadSectors(hDrive, partition_lba + parent_icb, 1, sec_size, sector); - if (res && tag->TagIdentifier == udf_TAG_FileEntry) { - tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; - - if (fe->ICBTag.FileType == udf_FT_Directory) { - tp_udf_file root = (tp_udf_file)malloc(sizeof *root); - - root->partition_lba = partition_lba; - udf_GetLBA(fe, sec_size, &root->dir_lba, &root->dir_end_lba); - root->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb - root->sector = nullptr; - root->fid = nullptr; - root->sec_size = sec_size; - strcpy_s(root->name, "/"); - root->is_dir = true; - root->is_parent = false; - return root; - } - } - } - } - } - - return nullptr; -} - -static void udf_GetName(const BYTE *data, const DWORD len, char *target) -{ - DWORD p = 1, i = 0; - - if (len == 0 || !(data[0] & 0x18)) { - target[0] = '\0'; - } - - if (data[0] & 0x10) { - // ignore MSB of unicode16 - p++; - - while (p < len) { - target[i++] = data[p += 2]; - } - } else { - while (p < len) { - target[i++] = data[p++]; - } - } - - target[i]='\0'; -} - -tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f) -{ - if (f->is_dir && !f->is_parent && f->fid) { - BYTE sector[fio_SECTOR_SIZE]; - tp_udf_tag tag = (tp_udf_tag)sector; - bool res; - - res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector); - if (res && tag->TagIdentifier == udf_TAG_FileEntry) { - tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; - - if (fe->ICBTag.FileType == udf_FT_Directory) { - tp_udf_file newf = (tp_udf_file)malloc(sizeof *newf); - - if (newf == nullptr) { - return nullptr; - } - - ZeroMemory(newf, sizeof(*newf)); - strcpy_s(newf->name, f->name); // maybe just ""? - newf->sec_size = f->sec_size; - newf->partition_lba = f->partition_lba; - udf_GetLBA(fe, f->sec_size, &newf->dir_lba, &newf->dir_end_lba); - newf->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb - newf->sector = nullptr; - newf->fid = nullptr; - newf->is_dir = true; - newf->is_parent = false; - return newf; - } - } - } - return nullptr; -} - -tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f) -{ - if (f->dir_left <= 0) { - f->fid = nullptr; - return nullptr; - } - - if (f->fid) { - // advance to next FileIdentifierDescriptor - DWORD ofs = 4 * ((sizeof *(f->fid) + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4); - - f->fid = (tp_udf_FileIdentifierDescriptor)((BYTE *)f->fid + ofs); - } - - if (f->fid == nullptr) { - bool res = true; - - DWORD size = f->sec_size * (f->dir_end_lba - f->dir_lba + 1); - - if (!f->sector) { - f->sector = (BYTE*)malloc(size); - } - res = aspi_ReadSectors(hDrive, f->partition_lba + f->dir_lba, (WORD)(f->dir_end_lba - f->dir_lba + 1), f->sec_size, f->sector); - if (res) { - f->fid = (tp_udf_FileIdentifierDescriptor)f->sector; - } else { - f->fid = nullptr; - } - } - - if (f->fid && f->fid->DescriptorTag.TagIdentifier == udf_TAG_FileIdentifierDescriptor) { - DWORD ofs = 4 * ((sizeof *f->fid + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4); - - f->dir_left -= ofs; - f->is_dir = (f->fid->FileCharacteristics & udf_FID_Directory) != 0; - f->is_parent = (f->fid->FileCharacteristics & udf_FID_Parent) != 0; - udf_GetName(f->fid->ImplementationUse + f->fid->LengthofImplementationUse, f->fid->LengthofFileIdentifier, f->name); - return f; - } - return nullptr; -} - -void udf_free(tp_udf_file f) -{ - if (f) { - if (f->sector) { - free(f->sector); - } - free(f); - } -} - -#pragma warning(push) -#pragma warning(disable:4995 4996) - -#define udf_PATH_DELIMITERS "/\\" - -static tp_udf_file udf_ff_traverse(const HANDLE hDrive, tp_udf_file f, char *token) -{ - while (udf_get_next(hDrive, f)) { - if (_stricmp(token, f->name) == 0) { - char *next_tok = strtok(nullptr, udf_PATH_DELIMITERS); - - if (!next_tok) { - return f; // found - } else if (f->is_dir) { - tp_udf_file f2 = udf_get_sub(hDrive, f); - - if (f2) { - tp_udf_file f3 = udf_ff_traverse(hDrive, f2, next_tok); - - if (!f3) { - udf_free(f2); - } - return f3; - } - } - } - } - return nullptr; -} - -tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name) -{ - tp_udf_file f = udf_get_root(hDrive, partition), f2 = nullptr; - - if (f) { - char tokenline[udf_MAX_PATHLEN]; - char *token; - - strcpy_s(tokenline, name); - token = strtok(tokenline, udf_PATH_DELIMITERS); - if (token) { - f2 = udf_ff_traverse(hDrive, f, token); - } - udf_free(f); - } - return f2; -} - -#pragma warning(pop) - -bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba) -{ - if (f->fid) { - BYTE sector[2048]; - tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; - bool res; - - res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector); - if (res && fe->DescriptorTag.TagIdentifier == udf_TAG_FileEntry) { - return udf_GetLBA(fe, f->sec_size, start_lba, end_lba); - } - } - return false; -} +/************************************************************************* + vStrip by [maven] (maven@maven.de) + udf.c: routines for udf-parsing (because windows just doesn't cut it), + refs: udf102.pdf, udf200.pdf +*************************************************************************/ + +#include "stdafx.h" +#include "udf.h" + +static bool aspi_GetSectorInfo(const HANDLE hDrive, DWORD* sec_size, DWORD* max_sec) +{ + LARGE_INTEGER size = {0, 0}; + GetFileSizeEx(hDrive, &size); + + *sec_size = 2048; + *max_sec = (DWORD)(size.QuadPart / *sec_size); + + return true; +} + +static bool aspi_ReadSectors(const HANDLE hDrive, int lba, int nSectors, DWORD sec_size, BYTE* sector) +{ + DWORD nbr = 0; + LARGE_INTEGER offset; + offset.QuadPart = lba*sec_size; + SetFilePointerEx(hDrive, offset, &offset, FILE_BEGIN); + return lba*sec_size == offset.QuadPart && ReadFile(hDrive, sector, nSectors*sec_size, &nbr, nullptr); +} + +static bool udf_GetLBA(const tp_udf_FileEntry fe, const DWORD sec_size, DWORD *start, DWORD *end) +{ + if (fe->LengthofAllocationDescriptors == 0) { + return false; + } + switch (fe->ICBTag.Flags & udf_icbf_Mask) { + case udf_icbf_ShortAd: { + tp_udf_short_ad ad = (tp_udf_short_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); + + *start = ad->Location; + *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; + return true; + } + break; + case udf_icbf_LongAd: { + tp_udf_long_ad ad = (tp_udf_long_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); + + *start = ad->Location.Location; // ignore partition number + *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; + return true; + } + break; + case udf_icbf_ExtAd: { + tp_udf_ext_ad ad = (tp_udf_ext_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); + + *start = ad->Location.Location; // ignore partition number + *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; + return true; + } + break; + } + return false; +} + +tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number) +{ + BYTE sector[fio_SECTOR_SIZE]; + tp_udf_tag tag = (tp_udf_tag)sector; + DWORD sec_size, max_sec, i; + DWORD MVDS_lba, MVDS_lba_end, MVDS_back_lba, MVDS_back_lba_end; + DWORD FileDescriptorSequence_lba = 0; + DWORD partition_lba = 0; + tp_udf_AnchorVolumeDescriptorPointer avd; + bool res, part_valid, vol_valid; + + if (!aspi_GetSectorInfo(hDrive, &sec_size, &max_sec)) { + return nullptr; + } + + if (sec_size != fio_SECTOR_SIZE || max_sec < 256) { + return nullptr; + } + + // read AnchorVolumeDescriptorPointer at 256 (or MaxSec) (Tag == 2) + res = aspi_ReadSectors(hDrive, 256, 1, sec_size, sector); + if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor) { + res = aspi_ReadSectors(hDrive, max_sec, 1, sec_size, sector); + if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor) { + return nullptr; + } + } + + // check Static Structures + + // get MainVolumeDescriptorSequence Location & Length + avd = (tp_udf_AnchorVolumeDescriptorPointer)sector; + MVDS_lba = avd->MainVolumeDescriptorSequenceExtent.Location; + MVDS_lba_end = MVDS_lba + (avd->MainVolumeDescriptorSequenceExtent.Length - 1) / sec_size; + MVDS_back_lba = avd->ReserveVolumeDescriptorSequenceExtent.Location; + MVDS_back_lba_end = MVDS_back_lba + (avd->ReserveVolumeDescriptorSequenceExtent.Length - 1) / sec_size; + + // read MVDS_Location..MVDS_Location + (MVDS_Length - 1) / SectorSize sectors + + part_valid = vol_valid = false; + i = 1; + do { + // try twice (if we need to) for ReserveAnchor + DWORD j = MVDS_lba; + do { + res = aspi_ReadSectors(hDrive, j++, 1, sec_size, sector); + if (res) { + if (tag->TagIdentifier == udf_TAG_PartitionDescriptor && !part_valid) { + // get stuff out of partition + tp_udf_PartitionDescriptor par = (tp_udf_PartitionDescriptor )sector; + + part_valid = par->PartitionNumber == partition_number; + if (part_valid) { + // extract par->PartitionStartingLocation, par->PartitionLength + partition_lba = par->PartitionStartingLocation; + } + } else if (tag->TagIdentifier == udf_TAG_LogicalVolumeDescriptor && !vol_valid) { + // get stuff out of volume + tp_udf_LogicalVolumeDescriptor vol = (tp_udf_LogicalVolumeDescriptor)sector; + + // check_volume sector size + vol_valid = (vol->LogicalBlockSize == sec_size) && (partition_number == vol->FileSetDescriptorSequence.Location.PartitionNumber); + if (vol_valid) { + // extract vol->FileSetDescriptorSequence + FileDescriptorSequence_lba = vol->FileSetDescriptorSequence.Location.Location; + // DWORD FileDescriptorSequence_lba_end = FileDescriptorSequence_lba + ((vol->FileSetDescriptorSequence.Length & udf_LengthMask) - 1) / sec_size; + } + } + } else { + tag->TagIdentifier = 0; + } + } while (j <= MVDS_lba_end && tag->TagIdentifier != udf_TAG_TerminatingDescriptor && ((!part_valid) || (!vol_valid))); + + if ((!part_valid) || (!vol_valid)) { + // try backup + MVDS_lba = MVDS_back_lba; + MVDS_lba_end = MVDS_back_lba_end; + } + } while (i-- && ((!part_valid) || (!vol_valid))); + + if (part_valid && vol_valid) { + // read FileSetDescriptor, get RootDir Location & Length, RootDir Length != 0 + res = aspi_ReadSectors(hDrive, FileDescriptorSequence_lba + partition_lba, 1, sec_size, sector); + if (res && tag->TagIdentifier == udf_TAG_FileSetDescriptor) { + tp_udf_FileSetDescriptor fsd = (tp_udf_FileSetDescriptor)sector; + + if (partition_number == fsd->RootDirectoryICB.Location.PartitionNumber) { + DWORD parent_icb = fsd->RootDirectoryICB.Location.Location; + res = aspi_ReadSectors(hDrive, partition_lba + parent_icb, 1, sec_size, sector); + if (res && tag->TagIdentifier == udf_TAG_FileEntry) { + tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; + + if (fe->ICBTag.FileType == udf_FT_Directory) { + tp_udf_file root = (tp_udf_file)malloc(sizeof *root); + + root->partition_lba = partition_lba; + udf_GetLBA(fe, sec_size, &root->dir_lba, &root->dir_end_lba); + root->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb + root->sector = nullptr; + root->fid = nullptr; + root->sec_size = sec_size; + strcpy_s(root->name, "/"); + root->is_dir = true; + root->is_parent = false; + return root; + } + } + } + } + } + + return nullptr; +} + +static void udf_GetName(const BYTE *data, const DWORD len, char *target) +{ + DWORD p = 1, i = 0; + + if (len == 0 || !(data[0] & 0x18)) { + target[0] = '\0'; + } + + if (data[0] & 0x10) { + // ignore MSB of unicode16 + p++; + + while (p < len) { + target[i++] = data[p += 2]; + } + } else { + while (p < len) { + target[i++] = data[p++]; + } + } + + target[i]='\0'; +} + +tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f) +{ + if (f->is_dir && !f->is_parent && f->fid) { + BYTE sector[fio_SECTOR_SIZE]; + tp_udf_tag tag = (tp_udf_tag)sector; + bool res; + + res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector); + if (res && tag->TagIdentifier == udf_TAG_FileEntry) { + tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; + + if (fe->ICBTag.FileType == udf_FT_Directory) { + tp_udf_file newf = (tp_udf_file)malloc(sizeof *newf); + + if (newf == nullptr) { + return nullptr; + } + + ZeroMemory(newf, sizeof(*newf)); + strcpy_s(newf->name, f->name); // maybe just ""? + newf->sec_size = f->sec_size; + newf->partition_lba = f->partition_lba; + udf_GetLBA(fe, f->sec_size, &newf->dir_lba, &newf->dir_end_lba); + newf->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb + newf->sector = nullptr; + newf->fid = nullptr; + newf->is_dir = true; + newf->is_parent = false; + return newf; + } + } + } + return nullptr; +} + +tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f) +{ + if (f->dir_left <= 0) { + f->fid = nullptr; + return nullptr; + } + + if (f->fid) { + // advance to next FileIdentifierDescriptor + DWORD ofs = 4 * ((sizeof *(f->fid) + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4); + + f->fid = (tp_udf_FileIdentifierDescriptor)((BYTE *)f->fid + ofs); + } + + if (f->fid == nullptr) { + bool res = true; + + DWORD size = f->sec_size * (f->dir_end_lba - f->dir_lba + 1); + + if (!f->sector) { + f->sector = (BYTE*)malloc(size); + } + res = aspi_ReadSectors(hDrive, f->partition_lba + f->dir_lba, (WORD)(f->dir_end_lba - f->dir_lba + 1), f->sec_size, f->sector); + if (res) { + f->fid = (tp_udf_FileIdentifierDescriptor)f->sector; + } else { + f->fid = nullptr; + } + } + + if (f->fid && f->fid->DescriptorTag.TagIdentifier == udf_TAG_FileIdentifierDescriptor) { + DWORD ofs = 4 * ((sizeof *f->fid + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4); + + f->dir_left -= ofs; + f->is_dir = (f->fid->FileCharacteristics & udf_FID_Directory) != 0; + f->is_parent = (f->fid->FileCharacteristics & udf_FID_Parent) != 0; + udf_GetName(f->fid->ImplementationUse + f->fid->LengthofImplementationUse, f->fid->LengthofFileIdentifier, f->name); + return f; + } + return nullptr; +} + +void udf_free(tp_udf_file f) +{ + if (f) { + if (f->sector) { + free(f->sector); + } + free(f); + } +} + +#pragma warning(push) +#pragma warning(disable:4995 4996) + +#define udf_PATH_DELIMITERS "/\\" + +static tp_udf_file udf_ff_traverse(const HANDLE hDrive, tp_udf_file f, char *token) +{ + while (udf_get_next(hDrive, f)) { + if (_stricmp(token, f->name) == 0) { + char *next_tok = strtok(nullptr, udf_PATH_DELIMITERS); + + if (!next_tok) { + return f; // found + } else if (f->is_dir) { + tp_udf_file f2 = udf_get_sub(hDrive, f); + + if (f2) { + tp_udf_file f3 = udf_ff_traverse(hDrive, f2, next_tok); + + if (!f3) { + udf_free(f2); + } + return f3; + } + } + } + } + return nullptr; +} + +tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name) +{ + tp_udf_file f = udf_get_root(hDrive, partition), f2 = nullptr; + + if (f) { + char tokenline[udf_MAX_PATHLEN]; + char *token; + + strcpy_s(tokenline, name); + token = strtok(tokenline, udf_PATH_DELIMITERS); + if (token) { + f2 = udf_ff_traverse(hDrive, f, token); + } + udf_free(f); + } + return f2; +} + +#pragma warning(pop) + +bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba) +{ + if (f->fid) { + BYTE sector[2048]; + tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; + bool res; + + res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector); + if (res && fe->DescriptorTag.TagIdentifier == udf_TAG_FileEntry) { + return udf_GetLBA(fe, f->sec_size, start_lba, end_lba); + } + } + return false; +} diff --git a/src/DeCSS/udf.h b/src/DeCSS/udf.h index d8848a8d373..6aff1bc71d2 100644 --- a/src/DeCSS/udf.h +++ b/src/DeCSS/udf.h @@ -1,256 +1,256 @@ -/************************************************************************* - vStrip by [maven] (maven@maven.de) -*************************************************************************/ - -#pragma once - -typedef char dstring; // last BYTE of string indicates encoding/length - -#define fio_SECTOR_SIZE 2048 - -#define udf_LengthMask 0x3fffffff - -#define udf_TAG_PrimaryVolumeDescriptor 0x0001 -#define udf_TAG_AnchorVolumeDescriptor 0x0002 -#define udf_TAG_PartitionDescriptor 0x0005 -#define udf_TAG_LogicalVolumeDescriptor 0x0006 -#define udf_TAG_TerminatingDescriptor 0x0008 -#define udf_TAG_FileSetDescriptor 0x0100 -#define udf_TAG_FileIdentifierDescriptor 0x0101 -#define udf_TAG_IndirectEntry 0x0103 -#define udf_TAG_TerminalEntry 0x0104 -#define udf_TAG_FileEntry 0x0105 - -#define udf_FT_IndirectEntry 0x03 -#define udf_FT_Directory 0x04 -#define udf_FT_File 0x05 -#define udf_FT_TerminalEntry 0x0b - -#define udf_icbf_Mask 0x0007 -#define udf_icbf_ShortAd 0x0000 -#define udf_icbf_LongAd 0x0001 -#define udf_icbf_ExtAd 0x0002 -#define udf_icbf_Direct 0x0003 -#define udf_icbf_Contiguous 0x0100 - -#define udf_FID_Directory 0x02 -#define udf_FID_Parent 0x08 - -#pragma pack(push, 1) - -typedef struct { - DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list - DWORD Location; // 04 -} t_udf_short_ad, *tp_udf_short_ad; // 08 - -typedef struct { - DWORD Length; // 00 - DWORD Location; // 04 -} t_udf_extent_ad, *tp_udf_extent_ad; // 08 - -typedef struct { - DWORD Location; // 00, relative to volume - WORD PartitionNumber; // 04 -} t_udf_lb_addr; // 06 - -typedef struct { - DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list - t_udf_lb_addr Location; // 04 - BYTE ImplementationUse[6]; // 10 -} t_udf_long_ad, *tp_udf_long_ad; // 16 - -typedef struct { - DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list - DWORD RecordedLength; // 04 - DWORD InformationLength; // 08 - t_udf_lb_addr Location; // 12 - BYTE ImplementationUse[2]; // 18 -} t_udf_ext_ad, *tp_udf_ext_ad; // 20 - -typedef struct { - BYTE CharacterSetType; // 00 - BYTE CharacterSetInfo[63]; // 01 -} t_udf_charspec; // 64 - -typedef struct { - /* ECMA 167 1/7.3 */ - WORD TypeAndTimezone; // 00 - WORD Year; // 02 - BYTE Month; // 04 - BYTE Day; // 05 - BYTE Hour; // 06 - BYTE Minute; // 07 - BYTE Second; // 08 - BYTE Centiseconds; // 09 - BYTE HundredsofMicroseconds; // 10 - BYTE Microseconds; // 11 -} t_udf_timestamp; // 12 - -typedef struct { - /* ISO 13346 3/7.2 */ - WORD TagIdentifier; // 00 - WORD DescriptorVersion; // 02 - BYTE TagChecksum; // 04 - BYTE Reserved; // 05 - WORD TagSerialNumber; // 06 - WORD DescriptorCRC; // 08 - WORD DescriptorCRCLength; // 10 - DWORD TagLocation; // 12 -} t_udf_tag, *tp_udf_tag; // 16 - -typedef struct { - /* ISO 13346 1/7.4 */ - BYTE Flags; // 00 - char Identifier[23]; // 01 - char IdentifierSuffix[8]; // 24 -} t_udf_EntityID; // 32 - -typedef struct { - /* ISO 13346 3/10.2 */ - t_udf_tag DescriptorTag; // 00 - t_udf_extent_ad MainVolumeDescriptorSequenceExtent; // 16 - t_udf_extent_ad ReserveVolumeDescriptorSequenceExtent; // 24 - BYTE Reserved[480]; // 32 -} t_udf_AnchorVolumeDescriptorPointer, *tp_udf_AnchorVolumeDescriptorPointer; // 512 - -typedef struct { - /* ISO 13346 3/10.6 */ - t_udf_tag DescriptorTag; // 00 - DWORD VolumeDescriptorSequenceNumber; // 16 - t_udf_charspec DescriptorCharacterSet; // 20 - dstring LogicalVolumeIdentifier[128]; // 84 - DWORD LogicalBlockSize; // 212 - t_udf_EntityID DomainIdentifier; // 244 - //BYTE LogicalVolumeContentsUse[16]; // 276 - t_udf_long_ad FileSetDescriptorSequence; // 276 - DWORD MapTableLength; // 292 - DWORD NumberofPartitionMaps; // 296 - t_udf_EntityID ImplementationIdentifier; // 300 - BYTE ImplementationUse[128]; // 332 - t_udf_extent_ad IntegritySequenceExtent; // 460 - BYTE PartitionMaps[1]; // 468 -} t_udf_LogicalVolumeDescriptor, *tp_udf_LogicalVolumeDescriptor; - -typedef struct { - t_udf_short_ad UnallocatedSpaceTable; // 00 - t_udf_short_ad UnallocatedSpaceBitmap; // 08 - t_udf_short_ad PartitionIntegrityTable; // 16 - t_udf_short_ad FreedSpaceTable; // 24 - t_udf_short_ad FreedSpaceBitmap; // 32 - BYTE Reserved[88]; // 40 -} t_udf_PartitionHeaderDescriptor; // 128 - -typedef struct { - /* ECMA 167 3/10.5 */ - t_udf_tag DescriptorTag; // 00 - DWORD VolumeDescriptorSequenceNumber; // 16 - WORD PartitionFlags; // 20 - WORD PartitionNumber; // 22 - t_udf_EntityID PartitionContents; // 24 - t_udf_PartitionHeaderDescriptor PartitionHeaderDescriptor; // 56 - DWORD AccessType; // 184, 0 unspecified, 1 read only, 2 write once, 3 rewriteable, 4 overwriteable - DWORD PartitionStartingLocation; // 188 - DWORD PartitionLength; // 192 - t_udf_EntityID ImplementationIdentifier; // 196 - BYTE ImplementationUse[128]; // 228 - BYTE Reserved[156]; // 356 -} t_udf_PartitionDescriptor, *tp_udf_PartitionDescriptor; // 512 - -typedef struct { - /* ECMA 167 4/14.1 */ - t_udf_tag DescriptorTag; // 00 - t_udf_timestamp RecordingDateandTime; // 16 - WORD InterchangeLevel; // 28 - WORD MaximumInterchangeLevel; // 30 - DWORD CharacterSetList; // 32 - DWORD MaximumCharacterSetList; // 36 - DWORD FileSetNumber; // 40 - DWORD FileSetDescriptorNumber; // 44 - t_udf_charspec LogicalVolumeIdentifierCharacterSet; // 48 - dstring LogicalVolumeIdentifier[128]; // 112 - t_udf_charspec FileSetCharacterSet; // 240 - dstring FileSetIdentifer[32]; // 304 - dstring CopyrightFileIdentifier[32]; // 336 - dstring AbstractFileIdentifier[32]; // 368 - t_udf_long_ad RootDirectoryICB; // 400 - t_udf_EntityID DomainIdentifier; // 416 - t_udf_long_ad NextExtent; // 448 - t_udf_long_ad StreamDirectoryICB; // 464 - BYTE Reserved[32]; // 480 -} t_udf_FileSetDescriptor, *tp_udf_FileSetDescriptor; // 512 - -typedef struct { - /* ECMA 167 4/14.6 */ - DWORD PriorRecordedNumberofDirectEntries; // 00 - WORD StrategyType; // 04 - BYTE StrategyParameter[2]; // 06 - WORD NumberofEntries; // 08 - BYTE Reserved; // 10 - BYTE FileType; // 11 - t_udf_lb_addr ParentICBLocation; // 12 - WORD Flags; // 18 -} t_udf_icbtag; // 20 - -typedef struct { - /* ECMA 167 4/14.9 */ - t_udf_tag DescriptorTag; // 00 - t_udf_icbtag ICBTag; // 16 - DWORD Uid; // 36 - DWORD Gid; // 40 - DWORD Permissions; // 44 - WORD FileLinkCount; // 48 - BYTE RecordFormat; // 50 - BYTE RecordDisplayAttributes; // 51 - DWORD RecordLength; // 52 - QWORD InformationLength; // 56 - QWORD LogicalBlocksRecorded; // 64 - t_udf_timestamp AccessTime; // 72 - t_udf_timestamp ModificationTime; // 84 - t_udf_timestamp AttributeTime; // 96 - DWORD Checkpoint; // 108 - t_udf_long_ad ExtendedAttributeICB; // 112 - t_udf_EntityID ImplementationIdentifier; // 128 - QWORD UniqueID; // 160 - DWORD LengthofExtendedAttributes; // 168 - DWORD LengthofAllocationDescriptors; // 172 - BYTE ExtendedAttributes[1]; // 176 - //BYTE AllocationDescriptors[]; // 176 -} t_udf_FileEntry, *tp_udf_FileEntry; // >= 176 - -typedef struct { - /* ECMA 167 4/14.4 */ - t_udf_tag DescriptorTag; // 00 - WORD FileVersionNumber; // 16 - BYTE FileCharacteristics; // 18 - BYTE LengthofFileIdentifier; // 19 - t_udf_long_ad ICB; // 20 - WORD LengthofImplementationUse; // 36 - BYTE ImplementationUse[1]; // 38 - //char FileIdentifier[]; // 38 - //BYTE Padding[]; // 38 -} t_udf_FileIdentifierDescriptor, *tp_udf_FileIdentifierDescriptor; // >= 38 - -#define udf_MAX_NAMELEN 256 -#define udf_MAX_PATHLEN 2048 - -typedef struct { - // public - char name[udf_MAX_NAMELEN]; - bool is_dir, is_parent; - // internal - BYTE *sector; - tp_udf_FileIdentifierDescriptor fid; - DWORD partition_lba; - DWORD dir_lba, dir_end_lba; - DWORD sec_size; - int dir_left; -} t_udf_file, *tp_udf_file; - -#pragma pack(pop) - -tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name); -tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number); -tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f); // advances f -tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f); // creates new f -bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba); -void udf_free(tp_udf_file f); +/************************************************************************* + vStrip by [maven] (maven@maven.de) +*************************************************************************/ + +#pragma once + +typedef char dstring; // last BYTE of string indicates encoding/length + +#define fio_SECTOR_SIZE 2048 + +#define udf_LengthMask 0x3fffffff + +#define udf_TAG_PrimaryVolumeDescriptor 0x0001 +#define udf_TAG_AnchorVolumeDescriptor 0x0002 +#define udf_TAG_PartitionDescriptor 0x0005 +#define udf_TAG_LogicalVolumeDescriptor 0x0006 +#define udf_TAG_TerminatingDescriptor 0x0008 +#define udf_TAG_FileSetDescriptor 0x0100 +#define udf_TAG_FileIdentifierDescriptor 0x0101 +#define udf_TAG_IndirectEntry 0x0103 +#define udf_TAG_TerminalEntry 0x0104 +#define udf_TAG_FileEntry 0x0105 + +#define udf_FT_IndirectEntry 0x03 +#define udf_FT_Directory 0x04 +#define udf_FT_File 0x05 +#define udf_FT_TerminalEntry 0x0b + +#define udf_icbf_Mask 0x0007 +#define udf_icbf_ShortAd 0x0000 +#define udf_icbf_LongAd 0x0001 +#define udf_icbf_ExtAd 0x0002 +#define udf_icbf_Direct 0x0003 +#define udf_icbf_Contiguous 0x0100 + +#define udf_FID_Directory 0x02 +#define udf_FID_Parent 0x08 + +#pragma pack(push, 1) + +typedef struct { + DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list + DWORD Location; // 04 +} t_udf_short_ad, *tp_udf_short_ad; // 08 + +typedef struct { + DWORD Length; // 00 + DWORD Location; // 04 +} t_udf_extent_ad, *tp_udf_extent_ad; // 08 + +typedef struct { + DWORD Location; // 00, relative to volume + WORD PartitionNumber; // 04 +} t_udf_lb_addr; // 06 + +typedef struct { + DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list + t_udf_lb_addr Location; // 04 + BYTE ImplementationUse[6]; // 10 +} t_udf_long_ad, *tp_udf_long_ad; // 16 + +typedef struct { + DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list + DWORD RecordedLength; // 04 + DWORD InformationLength; // 08 + t_udf_lb_addr Location; // 12 + BYTE ImplementationUse[2]; // 18 +} t_udf_ext_ad, *tp_udf_ext_ad; // 20 + +typedef struct { + BYTE CharacterSetType; // 00 + BYTE CharacterSetInfo[63]; // 01 +} t_udf_charspec; // 64 + +typedef struct { + /* ECMA 167 1/7.3 */ + WORD TypeAndTimezone; // 00 + WORD Year; // 02 + BYTE Month; // 04 + BYTE Day; // 05 + BYTE Hour; // 06 + BYTE Minute; // 07 + BYTE Second; // 08 + BYTE Centiseconds; // 09 + BYTE HundredsofMicroseconds; // 10 + BYTE Microseconds; // 11 +} t_udf_timestamp; // 12 + +typedef struct { + /* ISO 13346 3/7.2 */ + WORD TagIdentifier; // 00 + WORD DescriptorVersion; // 02 + BYTE TagChecksum; // 04 + BYTE Reserved; // 05 + WORD TagSerialNumber; // 06 + WORD DescriptorCRC; // 08 + WORD DescriptorCRCLength; // 10 + DWORD TagLocation; // 12 +} t_udf_tag, *tp_udf_tag; // 16 + +typedef struct { + /* ISO 13346 1/7.4 */ + BYTE Flags; // 00 + char Identifier[23]; // 01 + char IdentifierSuffix[8]; // 24 +} t_udf_EntityID; // 32 + +typedef struct { + /* ISO 13346 3/10.2 */ + t_udf_tag DescriptorTag; // 00 + t_udf_extent_ad MainVolumeDescriptorSequenceExtent; // 16 + t_udf_extent_ad ReserveVolumeDescriptorSequenceExtent; // 24 + BYTE Reserved[480]; // 32 +} t_udf_AnchorVolumeDescriptorPointer, *tp_udf_AnchorVolumeDescriptorPointer; // 512 + +typedef struct { + /* ISO 13346 3/10.6 */ + t_udf_tag DescriptorTag; // 00 + DWORD VolumeDescriptorSequenceNumber; // 16 + t_udf_charspec DescriptorCharacterSet; // 20 + dstring LogicalVolumeIdentifier[128]; // 84 + DWORD LogicalBlockSize; // 212 + t_udf_EntityID DomainIdentifier; // 244 + //BYTE LogicalVolumeContentsUse[16]; // 276 + t_udf_long_ad FileSetDescriptorSequence; // 276 + DWORD MapTableLength; // 292 + DWORD NumberofPartitionMaps; // 296 + t_udf_EntityID ImplementationIdentifier; // 300 + BYTE ImplementationUse[128]; // 332 + t_udf_extent_ad IntegritySequenceExtent; // 460 + BYTE PartitionMaps[1]; // 468 +} t_udf_LogicalVolumeDescriptor, *tp_udf_LogicalVolumeDescriptor; + +typedef struct { + t_udf_short_ad UnallocatedSpaceTable; // 00 + t_udf_short_ad UnallocatedSpaceBitmap; // 08 + t_udf_short_ad PartitionIntegrityTable; // 16 + t_udf_short_ad FreedSpaceTable; // 24 + t_udf_short_ad FreedSpaceBitmap; // 32 + BYTE Reserved[88]; // 40 +} t_udf_PartitionHeaderDescriptor; // 128 + +typedef struct { + /* ECMA 167 3/10.5 */ + t_udf_tag DescriptorTag; // 00 + DWORD VolumeDescriptorSequenceNumber; // 16 + WORD PartitionFlags; // 20 + WORD PartitionNumber; // 22 + t_udf_EntityID PartitionContents; // 24 + t_udf_PartitionHeaderDescriptor PartitionHeaderDescriptor; // 56 + DWORD AccessType; // 184, 0 unspecified, 1 read only, 2 write once, 3 rewriteable, 4 overwriteable + DWORD PartitionStartingLocation; // 188 + DWORD PartitionLength; // 192 + t_udf_EntityID ImplementationIdentifier; // 196 + BYTE ImplementationUse[128]; // 228 + BYTE Reserved[156]; // 356 +} t_udf_PartitionDescriptor, *tp_udf_PartitionDescriptor; // 512 + +typedef struct { + /* ECMA 167 4/14.1 */ + t_udf_tag DescriptorTag; // 00 + t_udf_timestamp RecordingDateandTime; // 16 + WORD InterchangeLevel; // 28 + WORD MaximumInterchangeLevel; // 30 + DWORD CharacterSetList; // 32 + DWORD MaximumCharacterSetList; // 36 + DWORD FileSetNumber; // 40 + DWORD FileSetDescriptorNumber; // 44 + t_udf_charspec LogicalVolumeIdentifierCharacterSet; // 48 + dstring LogicalVolumeIdentifier[128]; // 112 + t_udf_charspec FileSetCharacterSet; // 240 + dstring FileSetIdentifer[32]; // 304 + dstring CopyrightFileIdentifier[32]; // 336 + dstring AbstractFileIdentifier[32]; // 368 + t_udf_long_ad RootDirectoryICB; // 400 + t_udf_EntityID DomainIdentifier; // 416 + t_udf_long_ad NextExtent; // 448 + t_udf_long_ad StreamDirectoryICB; // 464 + BYTE Reserved[32]; // 480 +} t_udf_FileSetDescriptor, *tp_udf_FileSetDescriptor; // 512 + +typedef struct { + /* ECMA 167 4/14.6 */ + DWORD PriorRecordedNumberofDirectEntries; // 00 + WORD StrategyType; // 04 + BYTE StrategyParameter[2]; // 06 + WORD NumberofEntries; // 08 + BYTE Reserved; // 10 + BYTE FileType; // 11 + t_udf_lb_addr ParentICBLocation; // 12 + WORD Flags; // 18 +} t_udf_icbtag; // 20 + +typedef struct { + /* ECMA 167 4/14.9 */ + t_udf_tag DescriptorTag; // 00 + t_udf_icbtag ICBTag; // 16 + DWORD Uid; // 36 + DWORD Gid; // 40 + DWORD Permissions; // 44 + WORD FileLinkCount; // 48 + BYTE RecordFormat; // 50 + BYTE RecordDisplayAttributes; // 51 + DWORD RecordLength; // 52 + QWORD InformationLength; // 56 + QWORD LogicalBlocksRecorded; // 64 + t_udf_timestamp AccessTime; // 72 + t_udf_timestamp ModificationTime; // 84 + t_udf_timestamp AttributeTime; // 96 + DWORD Checkpoint; // 108 + t_udf_long_ad ExtendedAttributeICB; // 112 + t_udf_EntityID ImplementationIdentifier; // 128 + QWORD UniqueID; // 160 + DWORD LengthofExtendedAttributes; // 168 + DWORD LengthofAllocationDescriptors; // 172 + BYTE ExtendedAttributes[1]; // 176 + //BYTE AllocationDescriptors[]; // 176 +} t_udf_FileEntry, *tp_udf_FileEntry; // >= 176 + +typedef struct { + /* ECMA 167 4/14.4 */ + t_udf_tag DescriptorTag; // 00 + WORD FileVersionNumber; // 16 + BYTE FileCharacteristics; // 18 + BYTE LengthofFileIdentifier; // 19 + t_udf_long_ad ICB; // 20 + WORD LengthofImplementationUse; // 36 + BYTE ImplementationUse[1]; // 38 + //char FileIdentifier[]; // 38 + //BYTE Padding[]; // 38 +} t_udf_FileIdentifierDescriptor, *tp_udf_FileIdentifierDescriptor; // >= 38 + +#define udf_MAX_NAMELEN 256 +#define udf_MAX_PATHLEN 2048 + +typedef struct { + // public + char name[udf_MAX_NAMELEN]; + bool is_dir, is_parent; + // internal + BYTE *sector; + tp_udf_FileIdentifierDescriptor fid; + DWORD partition_lba; + DWORD dir_lba, dir_end_lba; + DWORD sec_size; + int dir_left; +} t_udf_file, *tp_udf_file; + +#pragma pack(pop) + +tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name); +tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number); +tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f); // advances f +tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f); // creates new f +bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba); +void udf_free(tp_udf_file f); diff --git a/src/MPCTestAPI/HScrollListBox.cpp b/src/MPCTestAPI/HScrollListBox.cpp index 9a45c901f23..a4c6bbc795a 100644 --- a/src/MPCTestAPI/HScrollListBox.cpp +++ b/src/MPCTestAPI/HScrollListBox.cpp @@ -1,169 +1,169 @@ -///////////////////////////////////////////////////////////////////////////// -// HScrollListBox.cpp : implementation file -// -// Copyright (c) 2002, Nebula Technologies, Inc. -// www.nebutech.com -// -// Nebula Technologies, Inc. grants you a royalty free -// license to use, modify and distribute this code -// provided that this copyright notice appears on all -// copies. This code is provided "AS IS," without a -// warranty of any kind. -// -///////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "HScrollListBox.h" - -///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CHScrollListBox, CListBox) - //{{AFX_MSG_MAP(CHScrollListBox) - // NOTE - the ClassWizard will add and remove mapping macros here. - //}}AFX_MSG_MAP - ON_MESSAGE(LB_ADDSTRING, OnAddString) - ON_MESSAGE(LB_INSERTSTRING, OnInsertString) - ON_MESSAGE(LB_DELETESTRING, OnDeleteString) - ON_MESSAGE(LB_DIR, OnDir) - ON_MESSAGE(LB_RESETCONTENT, OnResetContent) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CHScrollListBox -///////////////////////////////////////////////////////////////////////////// -CHScrollListBox::CHScrollListBox() -{ -} - -///////////////////////////////////////////////////////////////////////////// -CHScrollListBox::~CHScrollListBox() -{ -} - -///////////////////////////////////////////////////////////////////////////// -void CHScrollListBox::PreSubclassWindow() -{ - CListBox::PreSubclassWindow(); - -#ifdef _DEBUG - // NOTE: this list box is designed to work as a single column, system-drawn - // list box. The asserts below will ensure of that. - DWORD dwStyle = GetStyle(); - ASSERT((dwStyle & LBS_MULTICOLUMN) == 0); - ASSERT((dwStyle & LBS_OWNERDRAWFIXED) == 0); - ASSERT((dwStyle & LBS_OWNERDRAWVARIABLE) == 0); -#endif -} - -///////////////////////////////////////////////////////////////////////////// -// CHScrollListBox message handlers -/////////////////////////////////////////////////////////////////////////////// -int CHScrollListBox::GetTextLen(LPCTSTR lpszText) -{ - ASSERT(AfxIsValidString(lpszText)); - - CDC *pDC = GetDC(); - ASSERT(pDC); - - CSize size; - CFont* pOldFont = pDC->SelectObject(GetFont()); - if ((GetStyle() & LBS_USETABSTOPS) == 0) { - size = pDC->GetTextExtent(lpszText, (int) _tcslen(lpszText)); - size.cx += 3; - } else { - // Expand tabs as well - size = pDC->GetTabbedTextExtent(lpszText, (int) _tcslen(lpszText), 0, NULL); - size.cx += 2; - } - pDC->SelectObject(pOldFont); - ReleaseDC(pDC); - - return size.cx; -} - -/////////////////////////////////////////////////////////////////////////////// -void CHScrollListBox::ResetHExtent() -{ - if (GetCount() == 0) { - SetHorizontalExtent(0); - return; - } - - CWaitCursor cwc; - int iMaxHExtent = 0; - for (int i = 0; i < GetCount(); i++) { - CString csText; - GetText(i, csText); - int iExt = GetTextLen(csText); - if (iExt > iMaxHExtent) { - iMaxHExtent = iExt; - } - } - SetHorizontalExtent(iMaxHExtent); -} - -/////////////////////////////////////////////////////////////////////////////// -void CHScrollListBox::SetNewHExtent(LPCTSTR lpszNewString) -{ - int iExt = GetTextLen(lpszNewString); - if (iExt > GetHorizontalExtent()) { - SetHorizontalExtent(iExt); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// OnAddString: wParam - none, lParam - string, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnAddString(WPARAM /*wParam*/, LPARAM lParam) -{ - LRESULT lResult = Default(); - if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { - SetNewHExtent((LPCTSTR) lParam); - } - return lResult; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnInsertString: wParam - index, lParam - string, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnInsertString(WPARAM /*wParam*/, LPARAM lParam) -{ - LRESULT lResult = Default(); - if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { - SetNewHExtent((LPCTSTR) lParam); - } - return lResult; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnDeleteString: wParam - index, lParam - none, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnDeleteString(WPARAM /*wParam*/, LPARAM /*lParam*/) -{ - LRESULT lResult = Default(); - if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { - ResetHExtent(); - } - return lResult; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnDir: wParam - attr, lParam - wildcard, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnDir(WPARAM /*wParam*/, LPARAM /*lParam*/) -{ - LRESULT lResult = Default(); - if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { - ResetHExtent(); - } - return lResult; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnResetContent: wParam - none, lParam - none, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnResetContent(WPARAM /*wParam*/, LPARAM /*lParam*/) -{ - LRESULT lResult = Default(); - SetHorizontalExtent(0); - return lResult; -} +///////////////////////////////////////////////////////////////////////////// +// HScrollListBox.cpp : implementation file +// +// Copyright (c) 2002, Nebula Technologies, Inc. +// www.nebutech.com +// +// Nebula Technologies, Inc. grants you a royalty free +// license to use, modify and distribute this code +// provided that this copyright notice appears on all +// copies. This code is provided "AS IS," without a +// warranty of any kind. +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "HScrollListBox.h" + +///////////////////////////////////////////////////////////////////////////// +BEGIN_MESSAGE_MAP(CHScrollListBox, CListBox) + //{{AFX_MSG_MAP(CHScrollListBox) + // NOTE - the ClassWizard will add and remove mapping macros here. + //}}AFX_MSG_MAP + ON_MESSAGE(LB_ADDSTRING, OnAddString) + ON_MESSAGE(LB_INSERTSTRING, OnInsertString) + ON_MESSAGE(LB_DELETESTRING, OnDeleteString) + ON_MESSAGE(LB_DIR, OnDir) + ON_MESSAGE(LB_RESETCONTENT, OnResetContent) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CHScrollListBox +///////////////////////////////////////////////////////////////////////////// +CHScrollListBox::CHScrollListBox() +{ +} + +///////////////////////////////////////////////////////////////////////////// +CHScrollListBox::~CHScrollListBox() +{ +} + +///////////////////////////////////////////////////////////////////////////// +void CHScrollListBox::PreSubclassWindow() +{ + CListBox::PreSubclassWindow(); + +#ifdef _DEBUG + // NOTE: this list box is designed to work as a single column, system-drawn + // list box. The asserts below will ensure of that. + DWORD dwStyle = GetStyle(); + ASSERT((dwStyle & LBS_MULTICOLUMN) == 0); + ASSERT((dwStyle & LBS_OWNERDRAWFIXED) == 0); + ASSERT((dwStyle & LBS_OWNERDRAWVARIABLE) == 0); +#endif +} + +///////////////////////////////////////////////////////////////////////////// +// CHScrollListBox message handlers +/////////////////////////////////////////////////////////////////////////////// +int CHScrollListBox::GetTextLen(LPCTSTR lpszText) +{ + ASSERT(AfxIsValidString(lpszText)); + + CDC *pDC = GetDC(); + ASSERT(pDC); + + CSize size; + CFont* pOldFont = pDC->SelectObject(GetFont()); + if ((GetStyle() & LBS_USETABSTOPS) == 0) { + size = pDC->GetTextExtent(lpszText, (int) _tcslen(lpszText)); + size.cx += 3; + } else { + // Expand tabs as well + size = pDC->GetTabbedTextExtent(lpszText, (int) _tcslen(lpszText), 0, NULL); + size.cx += 2; + } + pDC->SelectObject(pOldFont); + ReleaseDC(pDC); + + return size.cx; +} + +/////////////////////////////////////////////////////////////////////////////// +void CHScrollListBox::ResetHExtent() +{ + if (GetCount() == 0) { + SetHorizontalExtent(0); + return; + } + + CWaitCursor cwc; + int iMaxHExtent = 0; + for (int i = 0; i < GetCount(); i++) { + CString csText; + GetText(i, csText); + int iExt = GetTextLen(csText); + if (iExt > iMaxHExtent) { + iMaxHExtent = iExt; + } + } + SetHorizontalExtent(iMaxHExtent); +} + +/////////////////////////////////////////////////////////////////////////////// +void CHScrollListBox::SetNewHExtent(LPCTSTR lpszNewString) +{ + int iExt = GetTextLen(lpszNewString); + if (iExt > GetHorizontalExtent()) { + SetHorizontalExtent(iExt); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// OnAddString: wParam - none, lParam - string, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnAddString(WPARAM /*wParam*/, LPARAM lParam) +{ + LRESULT lResult = Default(); + if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { + SetNewHExtent((LPCTSTR) lParam); + } + return lResult; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnInsertString: wParam - index, lParam - string, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnInsertString(WPARAM /*wParam*/, LPARAM lParam) +{ + LRESULT lResult = Default(); + if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { + SetNewHExtent((LPCTSTR) lParam); + } + return lResult; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnDeleteString: wParam - index, lParam - none, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnDeleteString(WPARAM /*wParam*/, LPARAM /*lParam*/) +{ + LRESULT lResult = Default(); + if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { + ResetHExtent(); + } + return lResult; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnDir: wParam - attr, lParam - wildcard, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnDir(WPARAM /*wParam*/, LPARAM /*lParam*/) +{ + LRESULT lResult = Default(); + if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { + ResetHExtent(); + } + return lResult; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnResetContent: wParam - none, lParam - none, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnResetContent(WPARAM /*wParam*/, LPARAM /*lParam*/) +{ + LRESULT lResult = Default(); + SetHorizontalExtent(0); + return lResult; +} diff --git a/src/MPCTestAPI/HScrollListBox.h b/src/MPCTestAPI/HScrollListBox.h index 5bf7765ecc0..023ea815b0a 100644 --- a/src/MPCTestAPI/HScrollListBox.h +++ b/src/MPCTestAPI/HScrollListBox.h @@ -1,62 +1,62 @@ -///////////////////////////////////////////////////////////////////////////// -// HScrollListBox.h : header file -// -// Copyright (c) 2002, Nebula Technologies, Inc. -// www.nebutech.com -// -// Nebula Technologies, Inc. grants you a royalty free -// license to use, modify and distribute this code -// provided that this copyright notice appears on all -// copies. This code is provided "AS IS," without a -// warranty of any kind. -// -///////////////////////////////////////////////////////////////////////////// - -#pragma once - -///////////////////////////////////////////////////////////////////////////// -// CHScrollListBox window -///////////////////////////////////////////////////////////////////////////// -class CHScrollListBox : public CListBox -{ - // Construction -public: - CHScrollListBox(); - - // Attributes -public: - - // Operations -public: - - // Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CHScrollListBox) -protected: - virtual void PreSubclassWindow(); - //}}AFX_VIRTUAL - - // Implementation -public: - virtual ~CHScrollListBox(); - - // Generated message map functions -protected: - //{{AFX_MSG(CHScrollListBox) - // NOTE - the ClassWizard will add and remove member functions here. - //}}AFX_MSG - - afx_msg LRESULT OnAddString(WPARAM wParam, LPARAM lParam); // wParam - none, lParam - string, returns - int - afx_msg LRESULT OnInsertString(WPARAM wParam, LPARAM lParam); // wParam - index, lParam - string, returns - int - afx_msg LRESULT OnDeleteString(WPARAM wParam, LPARAM lParam); // wParam - index, lParam - none, returns - int - afx_msg LRESULT OnResetContent(WPARAM wParam, LPARAM lParam); // wParam - none, lParam - none, returns - int - afx_msg LRESULT OnDir(WPARAM wParam, LPARAM lParam); // wParam - attr, lParam - wildcard, returns - int - - DECLARE_MESSAGE_MAP() - -private: - void ResetHExtent(); - void SetNewHExtent(LPCTSTR lpszNewString); - int GetTextLen(LPCTSTR lpszText); - -}; +///////////////////////////////////////////////////////////////////////////// +// HScrollListBox.h : header file +// +// Copyright (c) 2002, Nebula Technologies, Inc. +// www.nebutech.com +// +// Nebula Technologies, Inc. grants you a royalty free +// license to use, modify and distribute this code +// provided that this copyright notice appears on all +// copies. This code is provided "AS IS," without a +// warranty of any kind. +// +///////////////////////////////////////////////////////////////////////////// + +#pragma once + +///////////////////////////////////////////////////////////////////////////// +// CHScrollListBox window +///////////////////////////////////////////////////////////////////////////// +class CHScrollListBox : public CListBox +{ + // Construction +public: + CHScrollListBox(); + + // Attributes +public: + + // Operations +public: + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CHScrollListBox) +protected: + virtual void PreSubclassWindow(); + //}}AFX_VIRTUAL + + // Implementation +public: + virtual ~CHScrollListBox(); + + // Generated message map functions +protected: + //{{AFX_MSG(CHScrollListBox) + // NOTE - the ClassWizard will add and remove member functions here. + //}}AFX_MSG + + afx_msg LRESULT OnAddString(WPARAM wParam, LPARAM lParam); // wParam - none, lParam - string, returns - int + afx_msg LRESULT OnInsertString(WPARAM wParam, LPARAM lParam); // wParam - index, lParam - string, returns - int + afx_msg LRESULT OnDeleteString(WPARAM wParam, LPARAM lParam); // wParam - index, lParam - none, returns - int + afx_msg LRESULT OnResetContent(WPARAM wParam, LPARAM lParam); // wParam - none, lParam - none, returns - int + afx_msg LRESULT OnDir(WPARAM wParam, LPARAM lParam); // wParam - attr, lParam - wildcard, returns - int + + DECLARE_MESSAGE_MAP() + +private: + void ResetHExtent(); + void SetNewHExtent(LPCTSTR lpszNewString); + int GetTextLen(LPCTSTR lpszText); + +}; diff --git a/src/MPCTestAPI/MPCTestAPI.cpp b/src/MPCTestAPI/MPCTestAPI.cpp index 546f39b4058..f99dde54aef 100644 --- a/src/MPCTestAPI/MPCTestAPI.cpp +++ b/src/MPCTestAPI/MPCTestAPI.cpp @@ -1,81 +1,81 @@ -/* - * (C) 2008-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 . - * - */ - -// MPCTestAPI.cpp : Defines the class behaviors for the application. -// - -#include "stdafx.h" -#include "MPCTestAPI.h" -#include "MPCTestAPIDlg.h" - - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataApp - -BEGIN_MESSAGE_MAP(CRegisterCopyDataApp, CWinApp) - //{{AFX_MSG_MAP(CRegisterCopyDataApp) - // NOTE - the ClassWizard will add and remove mapping macros here. - // DO NOT EDIT what you see in these blocks of generated code! - //}}AFX_MSG - ON_COMMAND(ID_HELP, CWinApp::OnHelp) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataApp construction - -CRegisterCopyDataApp::CRegisterCopyDataApp() -{ - // TODO: add construction code here, - // Place all significant initialization in InitInstance -} - -///////////////////////////////////////////////////////////////////////////// -// The one and only CRegisterCopyDataApp object - -CRegisterCopyDataApp theApp; - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataApp initialization - -BOOL CRegisterCopyDataApp::InitInstance() -{ - AfxEnableControlContainer(); - - // Standard initialization - // If you are not using these features and wish to reduce the size - // of your final executable, you should remove from the following - // the specific initialization routines you do not need. - - CRegisterCopyDataDlg dlg; - m_pMainWnd = &dlg; - INT_PTR nResponse = dlg.DoModal(); - - if (nResponse == IDOK) { - // TODO: Place code here to handle when the dialog is - // dismissed with OK - } else if (nResponse == IDCANCEL) { - // TODO: Place code here to handle when the dialog is - // dismissed with Cancel - } - - // Since the dialog has been closed, return FALSE so that we exit the - // application, rather than start the application's message pump. - return FALSE; -} +/* + * (C) 2008-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 . + * + */ + +// MPCTestAPI.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "MPCTestAPI.h" +#include "MPCTestAPIDlg.h" + + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataApp + +BEGIN_MESSAGE_MAP(CRegisterCopyDataApp, CWinApp) + //{{AFX_MSG_MAP(CRegisterCopyDataApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataApp construction + +CRegisterCopyDataApp::CRegisterCopyDataApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CRegisterCopyDataApp object + +CRegisterCopyDataApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataApp initialization + +BOOL CRegisterCopyDataApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. + + CRegisterCopyDataDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + + if (nResponse == IDOK) { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } else if (nResponse == IDCANCEL) { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/src/MPCTestAPI/MPCTestAPI.h b/src/MPCTestAPI/MPCTestAPI.h index 8c48048a3fe..01f5a8e0f9e 100644 --- a/src/MPCTestAPI/MPCTestAPI.h +++ b/src/MPCTestAPI/MPCTestAPI.h @@ -1,52 +1,52 @@ -/* - * (C) 2008-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 . - * - */ - -// MPCTestAPI.h : main header file for the MPCTestAPI application -// - -#pragma once - -#include "resource.h" // main symbols - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataApp: -// See MPCTestAPI.cpp for the implementation of this class -// - -class CRegisterCopyDataApp : public CWinApp -{ -public: - CRegisterCopyDataApp(); - - // Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CRegisterCopyDataApp) -public: - virtual BOOL InitInstance(); - //}}AFX_VIRTUAL - - // Implementation - - //{{AFX_MSG(CRegisterCopyDataApp) - // NOTE - the ClassWizard will add and remove member functions here. - // DO NOT EDIT what you see in these blocks of generated code ! - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; +/* + * (C) 2008-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 . + * + */ + +// MPCTestAPI.h : main header file for the MPCTestAPI application +// + +#pragma once + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataApp: +// See MPCTestAPI.cpp for the implementation of this class +// + +class CRegisterCopyDataApp : public CWinApp +{ +public: + CRegisterCopyDataApp(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CRegisterCopyDataApp) +public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + + // Implementation + + //{{AFX_MSG(CRegisterCopyDataApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; diff --git a/src/MPCTestAPI/MPCTestAPI.rc b/src/MPCTestAPI/MPCTestAPI.rc index ec74497ae6b..bac32cc918c 100644 --- a/src/MPCTestAPI/MPCTestAPI.rc +++ b/src/MPCTestAPI/MPCTestAPI.rc @@ -1,260 +1,260 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\0" -END - -3 TEXTINCLUDE -BEGIN - "#define _AFX_NO_SPLITTER_RESOURCES\r\n" - "#define _AFX_NO_OLE_RESOURCES\r\n" - "#define _AFX_NO_TRACKER_RESOURCES\r\n" - "#define _AFX_NO_PROPERTY_RESOURCES\r\n" - "\r\n" - "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" - "LANGUAGE 9, 1\r\n" - "#pragma code_page(1252)\r\n" - "#include ""afxres.rc"" // Standard components\r\n" - "#endif\0" -END - -#endif // APSTUDIO_INVOKED - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDR_MAINFRAME ICON "res\\MPCTestAPI.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUTBOX DIALOGEX 0, 0, 244, 57 -STYLE DS_SHELLFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION -CAPTION "About MPC-HC Test API" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 - LTEXT "MPC-HC Test API Version 1.0.1.0",IDC_STATIC,40,10,120,10,SS_NOPREFIX - LTEXT "Copyright 2005-2013 all contributors, see Authors.txt",IDC_STATIC,40,27,197,10 - DEFPUSHBUTTON "OK",IDOK,187,7,50,14,WS_GROUP -END - -IDD_REGISTERCOPYDATA_DIALOG DIALOGEX 0, 0, 521, 406 -STYLE DS_SHELLFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_APPWINDOW -CAPTION "MPC-HC Test API" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - PUSHBUTTON "Start MPC-HC",IDC_BUTTON_FINDWINDOW,457,7,57,18 - EDITTEXT IDC_EDIT1,7,7,434,14,ES_AUTOHSCROLL - LISTBOX IDC_LOGLIST,7,89,507,310,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP - LTEXT "Messages from MPC-HC",IDC_STATIC,7,74,507,10 - EDITTEXT IDC_EDIT2,154,41,287,14,ES_AUTOHSCROLL - PUSHBUTTON "Send command",IDC_BUTTON_SENDCOMMAND,457,39,57,18 - COMBOBOX IDC_COMBO1,7,42,132,158,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,1,0 - PRODUCTVERSION 1,0,1,0 - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "MPC-HC Team" - VALUE "FileDescription", "MPC-HC Test API" - VALUE "FileVersion", "1.0.1.0" - VALUE "InternalName", "MPC-HC Test API" - VALUE "LegalCopyright", "Copyright 2005-2013 all contributors, see Authors.txt" - VALUE "OriginalFilename", "MPCTestAPI.exe" - VALUE "ProductName", "MPC-HC Test API" - VALUE "ProductVersion", "1.0.1.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_ABOUTBOX, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 237 - VERTGUIDE, 40 - TOPMARGIN, 7 - BOTTOMMARGIN, 50 - END - - IDD_REGISTERCOPYDATA_DIALOG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 514 - TOPMARGIN, 7 - BOTTOMMARGIN, 399 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog Info -// - -IDD_REGISTERCOPYDATA_DIALOG DLGINIT -BEGIN - IDC_COMBO1, 0x403, 10, 0 -0x704f, 0x6e65, 0x6620, 0x6c69, 0x0065, - IDC_COMBO1, 0x403, 5, 0 -0x7453, 0x706f, "\000" - IDC_COMBO1, 0x403, 6, 0 -0x6c43, 0x736f, 0x0065, - IDC_COMBO1, 0x403, 11, 0 -0x6c50, 0x7961, 0x502d, 0x7561, 0x6573, "\000" - IDC_COMBO1, 0x403, 16, 0 -0x6441, 0x2064, 0x6f74, 0x7020, 0x616c, 0x6c79, 0x7369, 0x0074, - IDC_COMBO1, 0x403, 15, 0 -0x7453, 0x7261, 0x2074, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" - IDC_COMBO1, 0x403, 15, 0 -0x6c43, 0x6165, 0x2072, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" - IDC_COMBO1, 0x403, 13, 0 -0x6553, 0x2074, 0x6f70, 0x6973, 0x6974, 0x6e6f, "\000" - IDC_COMBO1, 0x403, 16, 0 -0x6553, 0x2074, 0x7561, 0x6964, 0x206f, 0x6564, 0x616c, 0x0079, - IDC_COMBO1, 0x403, 19, 0 -0x6553, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x6420, 0x6c65, 0x7961, -"\000" - IDC_COMBO1, 0x403, 17, 0 -0x6547, 0x2074, 0x7561, 0x6964, 0x206f, 0x7274, 0x6361, 0x736b, "\000" - IDC_COMBO1, 0x403, 20, 0 -0x6547, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x7420, 0x6172, 0x6b63, -0x0073, - IDC_COMBO1, 0x403, 13, 0 -0x6547, 0x2074, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" - IDC_COMBO1, 0x403, 25, 0 -0x6553, 0x2074, 0x6f70, 0x6973, 0x6974, 0x6e6f, 0x6920, 0x206e, 0x6c70, -0x7961, 0x696c, 0x7473, "\000" - IDC_COMBO1, 0x403, 16, 0 -0x6553, 0x2074, 0x7561, 0x6964, 0x206f, 0x7274, 0x6361, 0x006b, - IDC_COMBO1, 0x403, 19, 0 -0x6553, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x7420, 0x6172, 0x6b63, -"\000" - IDC_COMBO1, 0x403, 11, 0 -0x7546, 0x6c6c, 0x6353, 0x6572, 0x6e65, "\000" - IDC_COMBO1, 0x403, 19, 0 -0x4d43, 0x5f44, 0x554a, 0x504d, 0x4f46, 0x5752, 0x5241, 0x4d44, 0x4445, -"\000" - IDC_COMBO1, 0x403, 20, 0 -0x4d43, 0x5f44, 0x554a, 0x504d, 0x4142, 0x4b43, 0x4157, 0x4452, 0x454d, -0x0044, - IDC_COMBO1, 0x403, 19, 0 -0x4d43, 0x5f44, 0x4e49, 0x5243, 0x4145, 0x4553, 0x4f56, 0x554c, 0x454d, -"\000" - IDC_COMBO1, 0x403, 19, 0 -0x4d43, 0x5f44, 0x4544, 0x5243, 0x4145, 0x4553, 0x4f56, 0x554c, 0x454d, -"\000" - IDC_COMBO1, 0x403, 18, 0 -0x4d43, 0x5f44, 0x4853, 0x4441, 0x5245, 0x545f, 0x474f, 0x4c47, 0x0045, - - IDC_COMBO1, 0x403, 13, 0 -0x4d43, 0x5f44, 0x4c43, 0x534f, 0x4145, 0x5050, "\000" - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_ABOUTBOX "&About MPC-HC Test API..." -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// -#define _AFX_NO_SPLITTER_RESOURCES -#define _AFX_NO_OLE_RESOURCES -#define _AFX_NO_TRACKER_RESOURCES -#define _AFX_NO_PROPERTY_RESOURCES - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE 9, 1 -#pragma code_page(1252) -#include "afxres.rc" // Standard components -#endif -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\MPCTestAPI.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 244, 57 +STYLE DS_SHELLFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "About MPC-HC Test API" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "MPC-HC Test API Version 1.0.1.0",IDC_STATIC,40,10,120,10,SS_NOPREFIX + LTEXT "Copyright 2005-2013 all contributors, see Authors.txt",IDC_STATIC,40,27,197,10 + DEFPUSHBUTTON "OK",IDOK,187,7,50,14,WS_GROUP +END + +IDD_REGISTERCOPYDATA_DIALOG DIALOGEX 0, 0, 521, 406 +STYLE DS_SHELLFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "MPC-HC Test API" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + PUSHBUTTON "Start MPC-HC",IDC_BUTTON_FINDWINDOW,457,7,57,18 + EDITTEXT IDC_EDIT1,7,7,434,14,ES_AUTOHSCROLL + LISTBOX IDC_LOGLIST,7,89,507,310,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + LTEXT "Messages from MPC-HC",IDC_STATIC,7,74,507,10 + EDITTEXT IDC_EDIT2,154,41,287,14,ES_AUTOHSCROLL + PUSHBUTTON "Send command",IDC_BUTTON_SENDCOMMAND,457,39,57,18 + COMBOBOX IDC_COMBO1,7,42,132,158,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,1,0 + PRODUCTVERSION 1,0,1,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "MPC-HC Team" + VALUE "FileDescription", "MPC-HC Test API" + VALUE "FileVersion", "1.0.1.0" + VALUE "InternalName", "MPC-HC Test API" + VALUE "LegalCopyright", "Copyright 2005-2013 all contributors, see Authors.txt" + VALUE "OriginalFilename", "MPCTestAPI.exe" + VALUE "ProductName", "MPC-HC Test API" + VALUE "ProductVersion", "1.0.1.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 237 + VERTGUIDE, 40 + TOPMARGIN, 7 + BOTTOMMARGIN, 50 + END + + IDD_REGISTERCOPYDATA_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 514 + TOPMARGIN, 7 + BOTTOMMARGIN, 399 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_REGISTERCOPYDATA_DIALOG DLGINIT +BEGIN + IDC_COMBO1, 0x403, 10, 0 +0x704f, 0x6e65, 0x6620, 0x6c69, 0x0065, + IDC_COMBO1, 0x403, 5, 0 +0x7453, 0x706f, "\000" + IDC_COMBO1, 0x403, 6, 0 +0x6c43, 0x736f, 0x0065, + IDC_COMBO1, 0x403, 11, 0 +0x6c50, 0x7961, 0x502d, 0x7561, 0x6573, "\000" + IDC_COMBO1, 0x403, 16, 0 +0x6441, 0x2064, 0x6f74, 0x7020, 0x616c, 0x6c79, 0x7369, 0x0074, + IDC_COMBO1, 0x403, 15, 0 +0x7453, 0x7261, 0x2074, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" + IDC_COMBO1, 0x403, 15, 0 +0x6c43, 0x6165, 0x2072, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" + IDC_COMBO1, 0x403, 13, 0 +0x6553, 0x2074, 0x6f70, 0x6973, 0x6974, 0x6e6f, "\000" + IDC_COMBO1, 0x403, 16, 0 +0x6553, 0x2074, 0x7561, 0x6964, 0x206f, 0x6564, 0x616c, 0x0079, + IDC_COMBO1, 0x403, 19, 0 +0x6553, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x6420, 0x6c65, 0x7961, +"\000" + IDC_COMBO1, 0x403, 17, 0 +0x6547, 0x2074, 0x7561, 0x6964, 0x206f, 0x7274, 0x6361, 0x736b, "\000" + IDC_COMBO1, 0x403, 20, 0 +0x6547, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x7420, 0x6172, 0x6b63, +0x0073, + IDC_COMBO1, 0x403, 13, 0 +0x6547, 0x2074, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" + IDC_COMBO1, 0x403, 25, 0 +0x6553, 0x2074, 0x6f70, 0x6973, 0x6974, 0x6e6f, 0x6920, 0x206e, 0x6c70, +0x7961, 0x696c, 0x7473, "\000" + IDC_COMBO1, 0x403, 16, 0 +0x6553, 0x2074, 0x7561, 0x6964, 0x206f, 0x7274, 0x6361, 0x006b, + IDC_COMBO1, 0x403, 19, 0 +0x6553, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x7420, 0x6172, 0x6b63, +"\000" + IDC_COMBO1, 0x403, 11, 0 +0x7546, 0x6c6c, 0x6353, 0x6572, 0x6e65, "\000" + IDC_COMBO1, 0x403, 19, 0 +0x4d43, 0x5f44, 0x554a, 0x504d, 0x4f46, 0x5752, 0x5241, 0x4d44, 0x4445, +"\000" + IDC_COMBO1, 0x403, 20, 0 +0x4d43, 0x5f44, 0x554a, 0x504d, 0x4142, 0x4b43, 0x4157, 0x4452, 0x454d, +0x0044, + IDC_COMBO1, 0x403, 19, 0 +0x4d43, 0x5f44, 0x4e49, 0x5243, 0x4145, 0x4553, 0x4f56, 0x554c, 0x454d, +"\000" + IDC_COMBO1, 0x403, 19, 0 +0x4d43, 0x5f44, 0x4544, 0x5243, 0x4145, 0x4553, 0x4f56, 0x554c, 0x454d, +"\000" + IDC_COMBO1, 0x403, 18, 0 +0x4d43, 0x5f44, 0x4853, 0x4441, 0x5245, 0x545f, 0x474f, 0x4c47, 0x0045, + + IDC_COMBO1, 0x403, 13, 0 +0x4d43, 0x5f44, 0x4c43, 0x534f, 0x4145, 0x5050, "\000" + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "&About MPC-HC Test API..." +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 +#pragma code_page(1252) +#include "afxres.rc" // Standard components +#endif +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/MPCTestAPI/MPCTestAPI.vcxproj b/src/MPCTestAPI/MPCTestAPI.vcxproj index 81865c17a13..f8b05464667 100644 --- a/src/MPCTestAPI/MPCTestAPI.vcxproj +++ b/src/MPCTestAPI/MPCTestAPI.vcxproj @@ -1,82 +1,82 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {A1F84246-B9A1-455F-97E4-D730AB089947} - MPCTestAPI - MFCProj - MPCTestAPI - - - - - Application - Static - Unicode - - - - - - - - - - - $(SolutionDir)bin\$(Configuration)_$(Platform)\ - $(SolutionDir)bin15\$(Configuration)_$(Platform)\ - - - - _AFX_NO_MFC_CONTROLS_IN_DIALOGS;%(PreprocessorDefinitions) - Level4 - - - $(ProjectDir)res\MPCTestAPI.exe.manifest %(AdditionalManifestFiles) - - - - - - - - Create - - - - - - - - - - - - - - - - ICO - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A1F84246-B9A1-455F-97E4-D730AB089947} + MPCTestAPI + MFCProj + MPCTestAPI + + + + + Application + Static + Unicode + + + + + + + + + + + $(SolutionDir)bin\$(Configuration)_$(Platform)\ + $(SolutionDir)bin15\$(Configuration)_$(Platform)\ + + + + _AFX_NO_MFC_CONTROLS_IN_DIALOGS;%(PreprocessorDefinitions) + Level4 + + + $(ProjectDir)res\MPCTestAPI.exe.manifest %(AdditionalManifestFiles) + + + + + + + + Create + + + + + + + + + + + + + + + + ICO + + + + + \ No newline at end of file diff --git a/src/MPCTestAPI/MPCTestAPI.vcxproj.filters b/src/MPCTestAPI/MPCTestAPI.vcxproj.filters index c41d5ada201..af8de34a0c3 100644 --- a/src/MPCTestAPI/MPCTestAPI.vcxproj.filters +++ b/src/MPCTestAPI/MPCTestAPI.vcxproj.filters @@ -1,61 +1,61 @@ - - - - - {964fcf6f-5fba-4c1a-a7f3-fe297436533d} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {ebf436b1-b3d7-4106-8d3d-2605dc6e9293} - h;hpp;hxx;hm;inl - - - {52bab2df-aaf2-4ca2-97bf-b67260438c51} - ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - - - Resource Files - - + + + + + {964fcf6f-5fba-4c1a-a7f3-fe297436533d} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {ebf436b1-b3d7-4106-8d3d-2605dc6e9293} + h;hpp;hxx;hm;inl + + + {52bab2df-aaf2-4ca2-97bf-b67260438c51} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/MPCTestAPI/MPCTestAPIDlg.cpp b/src/MPCTestAPI/MPCTestAPIDlg.cpp index 1cd03ba3b2a..debae647459 100644 --- a/src/MPCTestAPI/MPCTestAPIDlg.cpp +++ b/src/MPCTestAPI/MPCTestAPIDlg.cpp @@ -1,359 +1,359 @@ -/* - * (C) 2008-2015, 2017 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 . - * - */ - -// MPCTestAPIDlg.cpp : implementation file -// - -#include "stdafx.h" -#include "MPCTestAPI.h" -#include "MPCTestAPIDlg.h" -#include - - -LPCTSTR GetMPCCommandName(MPCAPI_COMMAND nCmd) -{ - switch (nCmd) { - case CMD_CONNECT: - return _T("CMD_CONNECT"); - case CMD_STATE: - return _T("CMD_STATE"); - case CMD_PLAYMODE: - return _T("CMD_PLAYMODE"); - case CMD_NOWPLAYING: - return _T("CMD_NOWPLAYING"); - case CMD_LISTSUBTITLETRACKS: - return _T("CMD_LISTSUBTITLETRACKS"); - case CMD_LISTAUDIOTRACKS: - return _T("CMD_LISTAUDIOTRACKS"); - case CMD_PLAYLIST: - return _T("CMD_PLAYLIST"); - default: - return _T("CMD_UNK"); - } -} - -///////////////////////////////////////////////////////////////////////////// -// CAboutDlg dialog used for App About - -class CAboutDlg : public CDialog -{ -public: - CAboutDlg(); - - // 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 - - // Implementation -protected: - //{{AFX_MSG(CAboutDlg) - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) -{ - //{{AFX_DATA_INIT(CAboutDlg) - //}}AFX_DATA_INIT -} - -void CAboutDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CAboutDlg) - //}}AFX_DATA_MAP -} - -BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) - //{{AFX_MSG_MAP(CAboutDlg) - // No message handlers - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataDlg dialog - -CRegisterCopyDataDlg::CRegisterCopyDataDlg(CWnd* pParent /*=nullptr*/) - : CDialog(CRegisterCopyDataDlg::IDD, pParent) - , m_RemoteWindow(nullptr) - , m_hWndMPC(nullptr) - , m_nCommandType(0) -{ - //{{AFX_DATA_INIT(CRegisterCopyDataDlg) - // NOTE: the ClassWizard will add member initialization here - //}}AFX_DATA_INIT - // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 - m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); -} - -void CRegisterCopyDataDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CRegisterCopyDataDlg) - // NOTE: the ClassWizard will add DDX and DDV calls here - //}}AFX_DATA_MAP - DDX_Text(pDX, IDC_EDIT1, m_strMPCPath); - DDX_Control(pDX, IDC_LOGLIST, m_listBox); - DDX_Text(pDX, IDC_EDIT2, m_txtCommand); - DDX_CBIndex(pDX, IDC_COMBO1, m_nCommandType); -} - -BEGIN_MESSAGE_MAP(CRegisterCopyDataDlg, CDialog) - //{{AFX_MSG_MAP(CRegisterCopyDataDlg) - ON_WM_SYSCOMMAND() - ON_WM_PAINT() - ON_WM_QUERYDRAGICON() - ON_BN_CLICKED(IDC_BUTTON_FINDWINDOW, OnButtonFindwindow) - ON_WM_COPYDATA() - //}}AFX_MSG_MAP - ON_BN_CLICKED(IDC_BUTTON_SENDCOMMAND, &CRegisterCopyDataDlg::OnBnClickedButtonSendcommand) -END_MESSAGE_MAP() - - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataDlg message handlers - -BOOL CRegisterCopyDataDlg::OnInitDialog() -{ - CDialog::OnInitDialog(); - - // Add "About..." menu item to system menu. - - // IDM_ABOUTBOX must be in the system command range. - ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); - ASSERT(IDM_ABOUTBOX < 0xF000); - - CMenu* pSysMenu = GetSystemMenu(FALSE); - if (pSysMenu != nullptr) { - CString strAboutMenu; - if (strAboutMenu.LoadString(IDS_ABOUTBOX)) { - pSysMenu->AppendMenu(MF_SEPARATOR); - pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); - } - } - - // Set the icon for this dialog. The framework does this automatically - // when the application's main window is not a dialog - SetIcon(m_hIcon, TRUE); // Set big icon - SetIcon(m_hIcon, FALSE); // Set small icon - - // TODO: Add extra initialization here - -#if (_MSC_VER < 1910) - m_strMPCPath = _T("..\\..\\..\\..\\bin15\\"); -#else - m_strMPCPath = _T("..\\..\\..\\..\\bin\\"); -#endif - -#if defined(_WIN64) - m_strMPCPath += _T("mpc-hc_x64"); -#else - m_strMPCPath += _T("mpc-hc_x86"); -#endif // _WIN64 - -#if defined(_DEBUG) - m_strMPCPath += _T("_Debug\\"); -#else - m_strMPCPath += _T("\\"); -#endif // _DEBUG - -#if defined(_WIN64) - m_strMPCPath += _T("mpc-hc64.exe"); -#else - m_strMPCPath += _T("mpc-hc.exe"); -#endif // _WIN64 - - UpdateData(FALSE); - - return TRUE; // return TRUE unless you set the focus to a control -} - -void CRegisterCopyDataDlg::OnSysCommand(UINT nID, LPARAM lParam) -{ - if ((nID & 0xFFF0) == IDM_ABOUTBOX) { - CAboutDlg dlgAbout; - dlgAbout.DoModal(); - } else { - CDialog::OnSysCommand(nID, lParam); - } -} - -// If you add a minimize button to your dialog, you will need the code below -// to draw the icon. For MFC applications using the document/view model, -// this is automatically done for you by the framework. - -void CRegisterCopyDataDlg::OnPaint() -{ - if (IsIconic()) { - CPaintDC dc(this); // device context for painting - - SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0); - - // Center icon in client rectangle - int cxIcon = GetSystemMetrics(SM_CXICON); - int cyIcon = GetSystemMetrics(SM_CYICON); - CRect rect; - GetClientRect(&rect); - int x = (rect.Width() - cxIcon + 1) / 2; - int y = (rect.Height() - cyIcon + 1) / 2; - - // Draw the icon - dc.DrawIcon(x, y, m_hIcon); - } else { - CDialog::OnPaint(); - } -} - -// The system calls this to obtain the cursor to display while the user drags -// the minimized window. -HCURSOR CRegisterCopyDataDlg::OnQueryDragIcon() -{ - return (HCURSOR)m_hIcon; -} - -void CRegisterCopyDataDlg::OnButtonFindwindow() -{ - CString strExec; - STARTUPINFO StartupInfo; - PROCESS_INFORMATION ProcessInfo; - - strExec.Format(_T("%s /slave %d"), (LPCTSTR)m_strMPCPath, PtrToInt(GetSafeHwnd())); - UpdateData(TRUE); - - ZeroMemory(&StartupInfo, sizeof(StartupInfo)); - StartupInfo.cb = sizeof(StartupInfo); - GetStartupInfo(&StartupInfo); - if (CreateProcess(nullptr, (LPTSTR)(LPCTSTR)strExec, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &StartupInfo, &ProcessInfo)) { - CloseHandle(ProcessInfo.hProcess); - CloseHandle(ProcessInfo.hThread); - } -} - -void CRegisterCopyDataDlg::Senddata(MPCAPI_COMMAND nCmd, LPCTSTR strCommand) -{ - if (m_hWndMPC) { - COPYDATASTRUCT MyCDS; - - MyCDS.dwData = nCmd; - MyCDS.cbData = (DWORD)(_tcslen(strCommand) + 1) * sizeof(TCHAR); - MyCDS.lpData = (LPVOID) strCommand; - - ::SendMessage(m_hWndMPC, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&MyCDS); - } -} - -BOOL CRegisterCopyDataDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) -{ - CString strMsg; - - if (pCopyDataStruct->dwData == CMD_CONNECT) { - m_hWndMPC = (HWND)IntToPtr(_ttoi((LPCTSTR)pCopyDataStruct->lpData)); - } - - strMsg.Format(_T("%s : %s"), GetMPCCommandName((MPCAPI_COMMAND)pCopyDataStruct->dwData), (LPCTSTR)pCopyDataStruct->lpData); - m_listBox.InsertString(0, strMsg); - return CDialog::OnCopyData(pWnd, pCopyDataStruct); -} - -void CRegisterCopyDataDlg::OnBnClickedButtonSendcommand() -{ - CString strEmpty(_T("")); - UpdateData(TRUE); - - switch (m_nCommandType) { - case 0: - Senddata(CMD_OPENFILE, m_txtCommand); - break; - case 1: - Senddata(CMD_STOP, strEmpty); - break; - case 2: - Senddata(CMD_CLOSEFILE, strEmpty); - break; - case 3: - Senddata(CMD_PLAYPAUSE, strEmpty); - break; - case 4: - Senddata(CMD_ADDTOPLAYLIST, m_txtCommand); - break; - case 5: - Senddata(CMD_STARTPLAYLIST, strEmpty); - break; - case 6: - Senddata(CMD_CLEARPLAYLIST, strEmpty); - break; - case 7: - Senddata(CMD_SETPOSITION, m_txtCommand); - break; - case 8: - Senddata(CMD_SETAUDIODELAY, m_txtCommand); - break; - case 9: - Senddata(CMD_SETSUBTITLEDELAY, m_txtCommand); - break; - case 10: - Senddata(CMD_GETAUDIOTRACKS, strEmpty); - break; - case 11: - Senddata(CMD_GETSUBTITLETRACKS, strEmpty); - break; - case 12: - Senddata(CMD_GETPLAYLIST, strEmpty); - break; - case 13: - Senddata(CMD_SETINDEXPLAYLIST, m_txtCommand); - break; - case 14: - Senddata(CMD_SETAUDIOTRACK, m_txtCommand); - break; - case 15: - Senddata(CMD_SETSUBTITLETRACK, m_txtCommand); - break; - case 16: - Senddata(CMD_TOGGLEFULLSCREEN, m_txtCommand); - break; - case 17: - Senddata(CMD_JUMPFORWARDMED, m_txtCommand); - break; - case 18: - Senddata(CMD_JUMPBACKWARDMED, m_txtCommand); - break; - case 19: - Senddata(CMD_INCREASEVOLUME, m_txtCommand); - break; - case 20: - Senddata(CMD_DECREASEVOLUME, m_txtCommand); - break; - case 21: - //Senddata(CMD_SHADER_TOGGLE, m_txtCommand); - break; - case 22: - Senddata(CMD_CLOSEAPP, m_txtCommand); - break; - } -} +/* + * (C) 2008-2015, 2017 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 . + * + */ + +// MPCTestAPIDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "MPCTestAPI.h" +#include "MPCTestAPIDlg.h" +#include + + +LPCTSTR GetMPCCommandName(MPCAPI_COMMAND nCmd) +{ + switch (nCmd) { + case CMD_CONNECT: + return _T("CMD_CONNECT"); + case CMD_STATE: + return _T("CMD_STATE"); + case CMD_PLAYMODE: + return _T("CMD_PLAYMODE"); + case CMD_NOWPLAYING: + return _T("CMD_NOWPLAYING"); + case CMD_LISTSUBTITLETRACKS: + return _T("CMD_LISTSUBTITLETRACKS"); + case CMD_LISTAUDIOTRACKS: + return _T("CMD_LISTAUDIOTRACKS"); + case CMD_PLAYLIST: + return _T("CMD_PLAYLIST"); + default: + return _T("CMD_UNK"); + } +} + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + + // 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 + + // Implementation +protected: + //{{AFX_MSG(CAboutDlg) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataDlg dialog + +CRegisterCopyDataDlg::CRegisterCopyDataDlg(CWnd* pParent /*=nullptr*/) + : CDialog(CRegisterCopyDataDlg::IDD, pParent) + , m_RemoteWindow(nullptr) + , m_hWndMPC(nullptr) + , m_nCommandType(0) +{ + //{{AFX_DATA_INIT(CRegisterCopyDataDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CRegisterCopyDataDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CRegisterCopyDataDlg) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP + DDX_Text(pDX, IDC_EDIT1, m_strMPCPath); + DDX_Control(pDX, IDC_LOGLIST, m_listBox); + DDX_Text(pDX, IDC_EDIT2, m_txtCommand); + DDX_CBIndex(pDX, IDC_COMBO1, m_nCommandType); +} + +BEGIN_MESSAGE_MAP(CRegisterCopyDataDlg, CDialog) + //{{AFX_MSG_MAP(CRegisterCopyDataDlg) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_BUTTON_FINDWINDOW, OnButtonFindwindow) + ON_WM_COPYDATA() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_BUTTON_SENDCOMMAND, &CRegisterCopyDataDlg::OnBnClickedButtonSendcommand) +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataDlg message handlers + +BOOL CRegisterCopyDataDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Add "About..." menu item to system menu. + + // IDM_ABOUTBOX must be in the system command range. + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != nullptr) { + CString strAboutMenu; + if (strAboutMenu.LoadString(IDS_ABOUTBOX)) { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + // TODO: Add extra initialization here + +#if (_MSC_VER < 1910) + m_strMPCPath = _T("..\\..\\..\\..\\bin15\\"); +#else + m_strMPCPath = _T("..\\..\\..\\..\\bin\\"); +#endif + +#if defined(_WIN64) + m_strMPCPath += _T("mpc-hc_x64"); +#else + m_strMPCPath += _T("mpc-hc_x86"); +#endif // _WIN64 + +#if defined(_DEBUG) + m_strMPCPath += _T("_Debug\\"); +#else + m_strMPCPath += _T("\\"); +#endif // _DEBUG + +#if defined(_WIN64) + m_strMPCPath += _T("mpc-hc64.exe"); +#else + m_strMPCPath += _T("mpc-hc.exe"); +#endif // _WIN64 + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control +} + +void CRegisterCopyDataDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } else { + CDialog::OnSysCommand(nID, lParam); + } +} + +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CRegisterCopyDataDlg::OnPaint() +{ + if (IsIconic()) { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } else { + CDialog::OnPaint(); + } +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CRegisterCopyDataDlg::OnQueryDragIcon() +{ + return (HCURSOR)m_hIcon; +} + +void CRegisterCopyDataDlg::OnButtonFindwindow() +{ + CString strExec; + STARTUPINFO StartupInfo; + PROCESS_INFORMATION ProcessInfo; + + strExec.Format(_T("%s /slave %d"), (LPCTSTR)m_strMPCPath, PtrToInt(GetSafeHwnd())); + UpdateData(TRUE); + + ZeroMemory(&StartupInfo, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + GetStartupInfo(&StartupInfo); + if (CreateProcess(nullptr, (LPTSTR)(LPCTSTR)strExec, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &StartupInfo, &ProcessInfo)) { + CloseHandle(ProcessInfo.hProcess); + CloseHandle(ProcessInfo.hThread); + } +} + +void CRegisterCopyDataDlg::Senddata(MPCAPI_COMMAND nCmd, LPCTSTR strCommand) +{ + if (m_hWndMPC) { + COPYDATASTRUCT MyCDS; + + MyCDS.dwData = nCmd; + MyCDS.cbData = (DWORD)(_tcslen(strCommand) + 1) * sizeof(TCHAR); + MyCDS.lpData = (LPVOID) strCommand; + + ::SendMessage(m_hWndMPC, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&MyCDS); + } +} + +BOOL CRegisterCopyDataDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) +{ + CString strMsg; + + if (pCopyDataStruct->dwData == CMD_CONNECT) { + m_hWndMPC = (HWND)IntToPtr(_ttoi((LPCTSTR)pCopyDataStruct->lpData)); + } + + strMsg.Format(_T("%s : %s"), GetMPCCommandName((MPCAPI_COMMAND)pCopyDataStruct->dwData), (LPCTSTR)pCopyDataStruct->lpData); + m_listBox.InsertString(0, strMsg); + return CDialog::OnCopyData(pWnd, pCopyDataStruct); +} + +void CRegisterCopyDataDlg::OnBnClickedButtonSendcommand() +{ + CString strEmpty(_T("")); + UpdateData(TRUE); + + switch (m_nCommandType) { + case 0: + Senddata(CMD_OPENFILE, m_txtCommand); + break; + case 1: + Senddata(CMD_STOP, strEmpty); + break; + case 2: + Senddata(CMD_CLOSEFILE, strEmpty); + break; + case 3: + Senddata(CMD_PLAYPAUSE, strEmpty); + break; + case 4: + Senddata(CMD_ADDTOPLAYLIST, m_txtCommand); + break; + case 5: + Senddata(CMD_STARTPLAYLIST, strEmpty); + break; + case 6: + Senddata(CMD_CLEARPLAYLIST, strEmpty); + break; + case 7: + Senddata(CMD_SETPOSITION, m_txtCommand); + break; + case 8: + Senddata(CMD_SETAUDIODELAY, m_txtCommand); + break; + case 9: + Senddata(CMD_SETSUBTITLEDELAY, m_txtCommand); + break; + case 10: + Senddata(CMD_GETAUDIOTRACKS, strEmpty); + break; + case 11: + Senddata(CMD_GETSUBTITLETRACKS, strEmpty); + break; + case 12: + Senddata(CMD_GETPLAYLIST, strEmpty); + break; + case 13: + Senddata(CMD_SETINDEXPLAYLIST, m_txtCommand); + break; + case 14: + Senddata(CMD_SETAUDIOTRACK, m_txtCommand); + break; + case 15: + Senddata(CMD_SETSUBTITLETRACK, m_txtCommand); + break; + case 16: + Senddata(CMD_TOGGLEFULLSCREEN, m_txtCommand); + break; + case 17: + Senddata(CMD_JUMPFORWARDMED, m_txtCommand); + break; + case 18: + Senddata(CMD_JUMPBACKWARDMED, m_txtCommand); + break; + case 19: + Senddata(CMD_INCREASEVOLUME, m_txtCommand); + break; + case 20: + Senddata(CMD_DECREASEVOLUME, m_txtCommand); + break; + case 21: + //Senddata(CMD_SHADER_TOGGLE, m_txtCommand); + break; + case 22: + Senddata(CMD_CLOSEAPP, m_txtCommand); + break; + } +} diff --git a/src/MPCTestAPI/MPCTestAPIDlg.h b/src/MPCTestAPI/MPCTestAPIDlg.h index c1d7126d4fe..ad3386022ef 100644 --- a/src/MPCTestAPI/MPCTestAPIDlg.h +++ b/src/MPCTestAPI/MPCTestAPIDlg.h @@ -1,74 +1,74 @@ -/* - * (C) 2008-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 . - * - */ - -// MPCTestAPIDlg.h : header file -// - -#pragma once - -#include "../mpc-hc/MpcApi.h" -#include "HScrollListBox.h" - - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataDlg dialog - -class CRegisterCopyDataDlg : public CDialog -{ - // Construction -public: - HWND m_RemoteWindow; - CRegisterCopyDataDlg(CWnd* pParent = nullptr); // standard constructor - - // Dialog Data - //{{AFX_DATA(CRegisterCopyDataDlg) - enum { IDD = IDD_REGISTERCOPYDATA_DIALOG }; - // NOTE: the ClassWizard will add data members here - //}}AFX_DATA - - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CRegisterCopyDataDlg) -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - - // Implementation -protected: - HICON m_hIcon; - HWND m_hWndMPC; - - // Generated message map functions - //{{AFX_MSG(CRegisterCopyDataDlg) - virtual BOOL OnInitDialog(); - afx_msg void OnSysCommand(UINT nID, LPARAM lParam); - afx_msg void OnPaint(); - afx_msg HCURSOR OnQueryDragIcon(); - afx_msg void OnButtonFindwindow(); - afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -public: - CString m_strMPCPath; - CHScrollListBox m_listBox; - CString m_txtCommand; - int m_nCommandType; - afx_msg void OnBnClickedButtonSendcommand(); - void Senddata(MPCAPI_COMMAND nCmd, LPCTSTR strCommand); -}; +/* + * (C) 2008-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 . + * + */ + +// MPCTestAPIDlg.h : header file +// + +#pragma once + +#include "../mpc-hc/MpcApi.h" +#include "HScrollListBox.h" + + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataDlg dialog + +class CRegisterCopyDataDlg : public CDialog +{ + // Construction +public: + HWND m_RemoteWindow; + CRegisterCopyDataDlg(CWnd* pParent = nullptr); // standard constructor + + // Dialog Data + //{{AFX_DATA(CRegisterCopyDataDlg) + enum { IDD = IDD_REGISTERCOPYDATA_DIALOG }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CRegisterCopyDataDlg) +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + + // Implementation +protected: + HICON m_hIcon; + HWND m_hWndMPC; + + // Generated message map functions + //{{AFX_MSG(CRegisterCopyDataDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnButtonFindwindow(); + afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +public: + CString m_strMPCPath; + CHScrollListBox m_listBox; + CString m_txtCommand; + int m_nCommandType; + afx_msg void OnBnClickedButtonSendcommand(); + void Senddata(MPCAPI_COMMAND nCmd, LPCTSTR strCommand); +}; diff --git a/src/MPCTestAPI/res/MPCTestAPI.exe.manifest b/src/MPCTestAPI/res/MPCTestAPI.exe.manifest index 996ed084eb2..486cc8e0ac1 100644 --- a/src/MPCTestAPI/res/MPCTestAPI.exe.manifest +++ b/src/MPCTestAPI/res/MPCTestAPI.exe.manifest @@ -1,43 +1,43 @@ - - - - MPC-HC Test API - - - - - - - - - - - - - - - - - - - - - - - - true - - + + + + MPC-HC Test API + + + + + + + + + + + + + + + + + + + + + + + + true + + \ No newline at end of file diff --git a/src/MPCTestAPI/resource.h b/src/MPCTestAPI/resource.h index f41d70f238f..2799b875ae4 100644 --- a/src/MPCTestAPI/resource.h +++ b/src/MPCTestAPI/resource.h @@ -1,30 +1,30 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by MPCTestAPI.rc -// -#define IDM_ABOUTBOX 0x0010 -#define IDD_ABOUTBOX 100 -#define IDS_ABOUTBOX 101 -#define IDD_REGISTERCOPYDATA_DIALOG 102 -#define IDR_MAINFRAME 128 -#define IDC_BUTTON_FINDWINDOW 1001 -#define IDC_EDIT_DATA 1002 -#define IDC_BUTTON_FINDWINDOW2 1002 -#define IDC_BUTTON_SENDCOMMAND 1002 -#define IDC_BUTTON_SENDDATA 1003 -#define IDC_EDIT_INTEGER 1004 -#define IDC_EDIT1 1005 -#define IDC_LOGLIST 1006 -#define IDC_EDIT2 1007 -#define IDC_COMBO1 1008 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 130 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1009 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by MPCTestAPI.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_REGISTERCOPYDATA_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON_FINDWINDOW 1001 +#define IDC_EDIT_DATA 1002 +#define IDC_BUTTON_FINDWINDOW2 1002 +#define IDC_BUTTON_SENDCOMMAND 1002 +#define IDC_BUTTON_SENDDATA 1003 +#define IDC_EDIT_INTEGER 1004 +#define IDC_EDIT1 1005 +#define IDC_LOGLIST 1006 +#define IDC_EDIT2 1007 +#define IDC_COMBO1 1008 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1009 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/MPCTestAPI/stdafx.cpp b/src/MPCTestAPI/stdafx.cpp index cfb035199b3..78ec945609e 100644 --- a/src/MPCTestAPI/stdafx.cpp +++ b/src/MPCTestAPI/stdafx.cpp @@ -1,21 +1,21 @@ -/* - * (C) 2011-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 . - * - */ - -#include "stdafx.h" +/* + * (C) 2011-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 . + * + */ + +#include "stdafx.h" diff --git a/src/MPCTestAPI/stdafx.h b/src/MPCTestAPI/stdafx.h index 98b948ca65f..cb3cf4d4068 100644 --- a/src/MPCTestAPI/stdafx.h +++ b/src/MPCTestAPI/stdafx.h @@ -1,31 +1,31 @@ -/* - * (C) 2011-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 . - * - */ - -#pragma once - -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include // MFC core and standard components -#include // MFC extensions -#include // MFC Automation classes -#include // MFC support for Internet Explorer 4 Common Controls -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT +/* + * (C) 2011-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 . + * + */ + +#pragma once + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT diff --git a/src/SubPic/CoordGeom.cpp b/src/SubPic/CoordGeom.cpp index 4bb5dfaaa40..41f70ee2ff9 100644 --- a/src/SubPic/CoordGeom.cpp +++ b/src/SubPic/CoordGeom.cpp @@ -1,568 +1,568 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "CoordGeom.h" -#include "../DSUtil/DSUtil.h" -#include - -static bool IsZero(float d) -{ - return IsEqual(d, 0.0f); -} - -// -// Vector -// - -Vector::Vector(float _x, float _y, float _z) - : x(_x), y(_y), z(_z) -{ -} - -void Vector::Set(float _x, float _y, float _z) -{ - x = _x; - y = _y; - z = _z; -} - -float Vector::Length() const -{ - return sqrt(x * x + y * y + z * z); -} - -float Vector::Sum() const -{ - return (x + y + z); -} - -float Vector::CrossSum() const -{ - return (x * y + x * z + y * z); -} - -Vector Vector::Cross() const -{ - return Vector(x * y, x * z, y * z); -} - -Vector Vector::Pow(float exp) const -{ - return (exp == 0.0f ? Vector(1.0f, 1.0f, 1.0f) : exp == 1.0f ? *this : Vector(pow(x, exp), pow(y, exp), pow(z, exp))); -} - -Vector Vector::Unit() const -{ - float l = Length(); - if (!l || l == 1.0f) { - return *this; - } - return (*this * (1.0f / l)); -} - -Vector& Vector::Unitalize() -{ - return (*this = Unit()); -} - -Vector Vector::Normal(const Vector& a, const Vector& b) const -{ - return ((a - *this) % (b - a)); -} - -float Vector::Angle(const Vector& a, const Vector& b) const -{ - return (((a - *this).Unit()).Angle((b - *this).Unit())); -} - -float Vector::Angle(const Vector& a) const -{ - float angle = *this | a; - return ((angle > 1.0f) ? 0.0f : (angle < -1.0f) ? (float)M_PI : acos(angle)); -} - -void Vector::Angle(float& u, float& v) const -{ - Vector n = Unit(); - - u = asin(n.y); - - if (IsZero(n.z)) { - v = (float)M_PI_2 * SGN(n.x); - } else if (n.z > 0) { - v = atan(n.x / n.z); - } else if (n.z < 0) { - v = IsZero(n.x) ? (float)M_PI : ((float)M_PI * SGN(n.x) + atan(n.x / n.z)); - } -} - -Vector Vector::Angle() const -{ - Vector ret; - Angle(ret.x, ret.y); - ret.z = 0; - return ret; -} - -Vector& Vector::Min(const Vector& a) -{ - x = (x < a.x) ? x : a.x; - y = (y < a.y) ? y : a.y; - z = (z < a.z) ? z : a.z; - return *this; -} - -Vector& Vector::Max(const Vector& a) -{ - x = (x > a.x) ? x : a.x; - y = (y > a.y) ? y : a.y; - z = (z > a.z) ? z : a.z; - return *this; -} - -Vector Vector::Abs() const -{ - return Vector(fabs(x), fabs(y), fabs(z)); -} - -Vector Vector::Reflect(const Vector& n) const -{ - return (n * ((-*this) | n) * 2 - (-*this)); -} - -Vector Vector::Refract(const Vector& N, float nFront, float nBack, float* nOut /*= nullptr*/) const -{ - Vector D = -*this; - - float N_dot_D = (N | D); - float n = N_dot_D >= 0.0f ? (nFront / nBack) : (nBack / nFront); - - Vector cos_D = N * N_dot_D; - Vector sin_T = (cos_D - D) * n; - - float len_sin_T = sin_T | sin_T; - - if (len_sin_T > 1.0f) { - if (nOut) { - *nOut = N_dot_D >= 0.0f ? nFront : nBack; - } - return this->Reflect(N); - } - - float N_dot_T = (float)sqrt(1.0f - len_sin_T); - if (N_dot_D < 0.0f) { - N_dot_T = -N_dot_T; - } - - if (nOut) { - *nOut = N_dot_D >= 0.0f ? nBack : nFront; - } - - return (sin_T - (N * N_dot_T)); -} - -Vector Vector::Refract2(const Vector& N, float nFrom, float nTo, float* nOut /*= nullptr*/) const -{ - Vector D = -*this; - - float N_dot_D = (N | D); - float n = nFrom / nTo; - - Vector cos_D = N * N_dot_D; - Vector sin_T = (cos_D - D) * n; - - float len_sin_T = sin_T | sin_T; - - if (len_sin_T > 1.0f) { - if (nOut) { - *nOut = nFrom; - } - return this->Reflect(N); - } - - float N_dot_T = (float)sqrt(1.0f - len_sin_T); - if (N_dot_D < 0.0f) { - N_dot_T = -N_dot_T; - } - - if (nOut) { - *nOut = nTo; - } - - return (sin_T - (N * N_dot_T)); -} - -float Vector::operator | (const Vector& v) const -{ - return (x * v.x + y * v.y + z * v.z); -} - -Vector Vector::operator % (const Vector& v) const -{ - return Vector(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); -} - -float& Vector::operator [](size_t i) -{ - return (!i ? x : (i == 1) ? y : z); -} - -Vector Vector::operator - () const -{ - return Vector(-x, -y, -z); -} - -bool Vector::operator == (const Vector& v) const -{ - return (IsZero(x - v.x) && IsZero(y - v.y) && IsZero(z - v.z)); -} - -bool Vector::operator != (const Vector& v) const -{ - return !(*this == v); -} - -Vector Vector::operator + (float d) const -{ - return Vector(x + d, y + d, z + d); -} - -Vector Vector::operator + (const Vector& v) const -{ - return Vector(x + v.x, y + v.y, z + v.z); -} - -Vector Vector::operator - (float d) const -{ - return Vector(x - d, y - d, z - d); -} - -Vector Vector::operator - (const Vector& v) const -{ - return Vector(x - v.x, y - v.y, z - v.z); -} - -Vector Vector::operator * (float d) const -{ - return Vector(x * d, y * d, z * d); -} - -Vector Vector::operator * (const Vector& v) const -{ - return Vector(x * v.x, y * v.y, z * v.z); -} - -Vector Vector::operator / (float d) const -{ - return Vector(x / d, y / d, z / d); -} - -Vector Vector::operator / (const Vector& v) const -{ - return Vector(x / v.x, y / v.y, z / v.z); -} - -Vector& Vector::operator += (float d) -{ - x += d; - y += d; - z += d; - return *this; -} - -Vector& Vector::operator += (const Vector& v) -{ - x += v.x; - y += v.y; - z += v.z; - return *this; -} - -Vector& Vector::operator -= (float d) -{ - x -= d; - y -= d; - z -= d; - return *this; -} - -Vector& Vector::operator -= (Vector& v) -{ - x -= v.x; - y -= v.y; - z -= v.z; - return *this; -} - -Vector& Vector::operator *= (float d) -{ - x *= d; - y *= d; - z *= d; - return *this; -} - -Vector& Vector::operator *= (const Vector& v) -{ - x *= v.x; - y *= v.y; - z *= v.z; - return *this; -} - -Vector& Vector::operator /= (float d) -{ - x /= d; - y /= d; - z /= d; - return *this; -} - -Vector& Vector::operator /= (const Vector& v) -{ - x /= v.x; - y /= v.y; - z /= v.z; - return *this; -} - -// -// Ray -// - -Ray::Ray(const Vector& _p, const Vector& _d) - : p(_p) - , d(_d) -{ -} - -void Ray::Set(const Vector& _p, const Vector& _d) -{ - p = _p; - d = _d; -} - -float Ray::GetDistanceFrom(const Ray& r) const -{ - float t = (d | r.d); - if (IsZero(t)) { - return -std::numeric_limits::infinity(); // plane is parallel to the ray, return -infinite - } - return (((r.p - p) | r.d) / t); -} - -float Ray::GetDistanceFrom(const Vector& v) const -{ - float t = ((v - p) | d) / (d | d); - return ((p + d * t) - v).Length(); -} - -Vector Ray::operator [](float t) const -{ - return (p + d * t); -} - -// -// XForm -// - - -XForm::XForm(const Ray& r, const Vector& s, bool isWorldToLocal /*= true*/) -{ - m_isWorldToLocal = isWorldToLocal; - if (isWorldToLocal) { - *this -= r.p; - *this >>= r.d; - *this /= s; - - } else { - *this *= s; - *this <<= r.d; - *this += r.p; - } -} - -void XForm::operator *= (const Vector& v) -{ - Matrix s; - s.mat[0][0] = v.x; - s.mat[1][1] = v.y; - s.mat[2][2] = v.z; - m *= s; -} - -void XForm::operator += (const Vector& v) -{ - Matrix t; - t.mat[3][0] = v.x; - t.mat[3][1] = v.y; - t.mat[3][2] = v.z; - m *= t; -} - -void XForm::operator <<= (const Vector& v) -{ - Matrix x; - x.mat[1][1] = cos(v.x); - x.mat[1][2] = -sin(v.x); - x.mat[2][1] = sin(v.x); - x.mat[2][2] = cos(v.x); - - Matrix y; - y.mat[0][0] = cos(v.y); - y.mat[0][2] = -sin(v.y); - y.mat[2][0] = sin(v.y); - y.mat[2][2] = cos(v.y); - - Matrix z; - z.mat[0][0] = cos(v.z); - z.mat[0][1] = -sin(v.z); - z.mat[1][0] = sin(v.z); - z.mat[1][1] = cos(v.z); - - m = m_isWorldToLocal ? (m * y * x * z) : (m * z * x * y); -} - -void XForm::operator /= (const Vector& v) -{ - Vector s; - s.x = IsZero(v.x) ? 0.0f : 1.0f / v.x; - s.y = IsZero(v.y) ? 0.0f : 1.0f / v.y; - s.z = IsZero(v.z) ? 0.0f : 1.0f / v.z; - *this *= s; -} - -void XForm::operator -= (const Vector& v) -{ - *this += -v; -} - -void XForm::operator >>= (const Vector& v) -{ - *this <<= -v; -} - -Vector XForm::operator < (const Vector& n) const -{ - Vector ret; - - ret.x = n.x * m.mat[0][0] + - n.y * m.mat[1][0] + - n.z * m.mat[2][0]; - ret.y = n.x * m.mat[0][1] + - n.y * m.mat[1][1] + - n.z * m.mat[2][1]; - ret.z = n.x * m.mat[0][2] + - n.y * m.mat[1][2] + - n.z * m.mat[2][2]; - - return ret; -} - -Vector XForm::operator << (const Vector& v) const -{ - Vector ret; - - ret.x = v.x * m.mat[0][0] + - v.y * m.mat[1][0] + - v.z * m.mat[2][0] + - m.mat[3][0]; - ret.y = v.x * m.mat[0][1] + - v.y * m.mat[1][1] + - v.z * m.mat[2][1] + - m.mat[3][1]; - ret.z = v.x * m.mat[0][2] + - v.y * m.mat[1][2] + - v.z * m.mat[2][2] + - m.mat[3][2]; - - return ret; -} - -Ray XForm::operator << (const Ray& r) const -{ - return Ray(*this << r.p, *this < r.d); -} - -bool XForm::operator == (const XForm& x) const -{ - return m_isWorldToLocal == x.m_isWorldToLocal && m == x.m; -} - -bool XForm::operator != (const XForm& x) const -{ - return !(*this == x); -} - -// -// XForm::Matrix -// - -XForm::Matrix::Matrix() -{ - mat[0][0] = 1.0f; - mat[0][1] = 0.0f; - mat[0][2] = 0.0f; - mat[0][3] = 0.0f; - mat[1][0] = 0.0f; - mat[1][1] = 1.0f; - mat[1][2] = 0.0f; - mat[1][3] = 0.0f; - mat[2][0] = 0.0f; - mat[2][1] = 0.0f; - mat[2][2] = 1.0f; - mat[2][3] = 0.0f; - mat[3][0] = 0.0f; - mat[3][1] = 0.0f; - mat[3][2] = 0.0f; - mat[3][3] = 1.0f; -} - -XForm::Matrix XForm::Matrix::operator * (const Matrix& m) const -{ - Matrix ret; - - for (ptrdiff_t i = 0; i < 4; i++) { - for (ptrdiff_t j = 0; j < 4; j++) { - ret.mat[i][j] = mat[i][0] * m.mat[0][j] + - mat[i][1] * m.mat[1][j] + - mat[i][2] * m.mat[2][j] + - mat[i][3] * m.mat[3][j]; - - if (IsZero(ret.mat[i][j])) { - ret.mat[i][j] = 0.0f; - } - } - } - - return ret; -} - -XForm::Matrix& XForm::Matrix::operator *= (XForm::Matrix& m) -{ - return (*this = *this * m); -} - -bool XForm::Matrix::operator == (const XForm::Matrix& m) const -{ - return mat == m.mat; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "CoordGeom.h" +#include "../DSUtil/DSUtil.h" +#include + +static bool IsZero(float d) +{ + return IsEqual(d, 0.0f); +} + +// +// Vector +// + +Vector::Vector(float _x, float _y, float _z) + : x(_x), y(_y), z(_z) +{ +} + +void Vector::Set(float _x, float _y, float _z) +{ + x = _x; + y = _y; + z = _z; +} + +float Vector::Length() const +{ + return sqrt(x * x + y * y + z * z); +} + +float Vector::Sum() const +{ + return (x + y + z); +} + +float Vector::CrossSum() const +{ + return (x * y + x * z + y * z); +} + +Vector Vector::Cross() const +{ + return Vector(x * y, x * z, y * z); +} + +Vector Vector::Pow(float exp) const +{ + return (exp == 0.0f ? Vector(1.0f, 1.0f, 1.0f) : exp == 1.0f ? *this : Vector(pow(x, exp), pow(y, exp), pow(z, exp))); +} + +Vector Vector::Unit() const +{ + float l = Length(); + if (!l || l == 1.0f) { + return *this; + } + return (*this * (1.0f / l)); +} + +Vector& Vector::Unitalize() +{ + return (*this = Unit()); +} + +Vector Vector::Normal(const Vector& a, const Vector& b) const +{ + return ((a - *this) % (b - a)); +} + +float Vector::Angle(const Vector& a, const Vector& b) const +{ + return (((a - *this).Unit()).Angle((b - *this).Unit())); +} + +float Vector::Angle(const Vector& a) const +{ + float angle = *this | a; + return ((angle > 1.0f) ? 0.0f : (angle < -1.0f) ? (float)M_PI : acos(angle)); +} + +void Vector::Angle(float& u, float& v) const +{ + Vector n = Unit(); + + u = asin(n.y); + + if (IsZero(n.z)) { + v = (float)M_PI_2 * SGN(n.x); + } else if (n.z > 0) { + v = atan(n.x / n.z); + } else if (n.z < 0) { + v = IsZero(n.x) ? (float)M_PI : ((float)M_PI * SGN(n.x) + atan(n.x / n.z)); + } +} + +Vector Vector::Angle() const +{ + Vector ret; + Angle(ret.x, ret.y); + ret.z = 0; + return ret; +} + +Vector& Vector::Min(const Vector& a) +{ + x = (x < a.x) ? x : a.x; + y = (y < a.y) ? y : a.y; + z = (z < a.z) ? z : a.z; + return *this; +} + +Vector& Vector::Max(const Vector& a) +{ + x = (x > a.x) ? x : a.x; + y = (y > a.y) ? y : a.y; + z = (z > a.z) ? z : a.z; + return *this; +} + +Vector Vector::Abs() const +{ + return Vector(fabs(x), fabs(y), fabs(z)); +} + +Vector Vector::Reflect(const Vector& n) const +{ + return (n * ((-*this) | n) * 2 - (-*this)); +} + +Vector Vector::Refract(const Vector& N, float nFront, float nBack, float* nOut /*= nullptr*/) const +{ + Vector D = -*this; + + float N_dot_D = (N | D); + float n = N_dot_D >= 0.0f ? (nFront / nBack) : (nBack / nFront); + + Vector cos_D = N * N_dot_D; + Vector sin_T = (cos_D - D) * n; + + float len_sin_T = sin_T | sin_T; + + if (len_sin_T > 1.0f) { + if (nOut) { + *nOut = N_dot_D >= 0.0f ? nFront : nBack; + } + return this->Reflect(N); + } + + float N_dot_T = (float)sqrt(1.0f - len_sin_T); + if (N_dot_D < 0.0f) { + N_dot_T = -N_dot_T; + } + + if (nOut) { + *nOut = N_dot_D >= 0.0f ? nBack : nFront; + } + + return (sin_T - (N * N_dot_T)); +} + +Vector Vector::Refract2(const Vector& N, float nFrom, float nTo, float* nOut /*= nullptr*/) const +{ + Vector D = -*this; + + float N_dot_D = (N | D); + float n = nFrom / nTo; + + Vector cos_D = N * N_dot_D; + Vector sin_T = (cos_D - D) * n; + + float len_sin_T = sin_T | sin_T; + + if (len_sin_T > 1.0f) { + if (nOut) { + *nOut = nFrom; + } + return this->Reflect(N); + } + + float N_dot_T = (float)sqrt(1.0f - len_sin_T); + if (N_dot_D < 0.0f) { + N_dot_T = -N_dot_T; + } + + if (nOut) { + *nOut = nTo; + } + + return (sin_T - (N * N_dot_T)); +} + +float Vector::operator | (const Vector& v) const +{ + return (x * v.x + y * v.y + z * v.z); +} + +Vector Vector::operator % (const Vector& v) const +{ + return Vector(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); +} + +float& Vector::operator [](size_t i) +{ + return (!i ? x : (i == 1) ? y : z); +} + +Vector Vector::operator - () const +{ + return Vector(-x, -y, -z); +} + +bool Vector::operator == (const Vector& v) const +{ + return (IsZero(x - v.x) && IsZero(y - v.y) && IsZero(z - v.z)); +} + +bool Vector::operator != (const Vector& v) const +{ + return !(*this == v); +} + +Vector Vector::operator + (float d) const +{ + return Vector(x + d, y + d, z + d); +} + +Vector Vector::operator + (const Vector& v) const +{ + return Vector(x + v.x, y + v.y, z + v.z); +} + +Vector Vector::operator - (float d) const +{ + return Vector(x - d, y - d, z - d); +} + +Vector Vector::operator - (const Vector& v) const +{ + return Vector(x - v.x, y - v.y, z - v.z); +} + +Vector Vector::operator * (float d) const +{ + return Vector(x * d, y * d, z * d); +} + +Vector Vector::operator * (const Vector& v) const +{ + return Vector(x * v.x, y * v.y, z * v.z); +} + +Vector Vector::operator / (float d) const +{ + return Vector(x / d, y / d, z / d); +} + +Vector Vector::operator / (const Vector& v) const +{ + return Vector(x / v.x, y / v.y, z / v.z); +} + +Vector& Vector::operator += (float d) +{ + x += d; + y += d; + z += d; + return *this; +} + +Vector& Vector::operator += (const Vector& v) +{ + x += v.x; + y += v.y; + z += v.z; + return *this; +} + +Vector& Vector::operator -= (float d) +{ + x -= d; + y -= d; + z -= d; + return *this; +} + +Vector& Vector::operator -= (Vector& v) +{ + x -= v.x; + y -= v.y; + z -= v.z; + return *this; +} + +Vector& Vector::operator *= (float d) +{ + x *= d; + y *= d; + z *= d; + return *this; +} + +Vector& Vector::operator *= (const Vector& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + return *this; +} + +Vector& Vector::operator /= (float d) +{ + x /= d; + y /= d; + z /= d; + return *this; +} + +Vector& Vector::operator /= (const Vector& v) +{ + x /= v.x; + y /= v.y; + z /= v.z; + return *this; +} + +// +// Ray +// + +Ray::Ray(const Vector& _p, const Vector& _d) + : p(_p) + , d(_d) +{ +} + +void Ray::Set(const Vector& _p, const Vector& _d) +{ + p = _p; + d = _d; +} + +float Ray::GetDistanceFrom(const Ray& r) const +{ + float t = (d | r.d); + if (IsZero(t)) { + return -std::numeric_limits::infinity(); // plane is parallel to the ray, return -infinite + } + return (((r.p - p) | r.d) / t); +} + +float Ray::GetDistanceFrom(const Vector& v) const +{ + float t = ((v - p) | d) / (d | d); + return ((p + d * t) - v).Length(); +} + +Vector Ray::operator [](float t) const +{ + return (p + d * t); +} + +// +// XForm +// + + +XForm::XForm(const Ray& r, const Vector& s, bool isWorldToLocal /*= true*/) +{ + m_isWorldToLocal = isWorldToLocal; + if (isWorldToLocal) { + *this -= r.p; + *this >>= r.d; + *this /= s; + + } else { + *this *= s; + *this <<= r.d; + *this += r.p; + } +} + +void XForm::operator *= (const Vector& v) +{ + Matrix s; + s.mat[0][0] = v.x; + s.mat[1][1] = v.y; + s.mat[2][2] = v.z; + m *= s; +} + +void XForm::operator += (const Vector& v) +{ + Matrix t; + t.mat[3][0] = v.x; + t.mat[3][1] = v.y; + t.mat[3][2] = v.z; + m *= t; +} + +void XForm::operator <<= (const Vector& v) +{ + Matrix x; + x.mat[1][1] = cos(v.x); + x.mat[1][2] = -sin(v.x); + x.mat[2][1] = sin(v.x); + x.mat[2][2] = cos(v.x); + + Matrix y; + y.mat[0][0] = cos(v.y); + y.mat[0][2] = -sin(v.y); + y.mat[2][0] = sin(v.y); + y.mat[2][2] = cos(v.y); + + Matrix z; + z.mat[0][0] = cos(v.z); + z.mat[0][1] = -sin(v.z); + z.mat[1][0] = sin(v.z); + z.mat[1][1] = cos(v.z); + + m = m_isWorldToLocal ? (m * y * x * z) : (m * z * x * y); +} + +void XForm::operator /= (const Vector& v) +{ + Vector s; + s.x = IsZero(v.x) ? 0.0f : 1.0f / v.x; + s.y = IsZero(v.y) ? 0.0f : 1.0f / v.y; + s.z = IsZero(v.z) ? 0.0f : 1.0f / v.z; + *this *= s; +} + +void XForm::operator -= (const Vector& v) +{ + *this += -v; +} + +void XForm::operator >>= (const Vector& v) +{ + *this <<= -v; +} + +Vector XForm::operator < (const Vector& n) const +{ + Vector ret; + + ret.x = n.x * m.mat[0][0] + + n.y * m.mat[1][0] + + n.z * m.mat[2][0]; + ret.y = n.x * m.mat[0][1] + + n.y * m.mat[1][1] + + n.z * m.mat[2][1]; + ret.z = n.x * m.mat[0][2] + + n.y * m.mat[1][2] + + n.z * m.mat[2][2]; + + return ret; +} + +Vector XForm::operator << (const Vector& v) const +{ + Vector ret; + + ret.x = v.x * m.mat[0][0] + + v.y * m.mat[1][0] + + v.z * m.mat[2][0] + + m.mat[3][0]; + ret.y = v.x * m.mat[0][1] + + v.y * m.mat[1][1] + + v.z * m.mat[2][1] + + m.mat[3][1]; + ret.z = v.x * m.mat[0][2] + + v.y * m.mat[1][2] + + v.z * m.mat[2][2] + + m.mat[3][2]; + + return ret; +} + +Ray XForm::operator << (const Ray& r) const +{ + return Ray(*this << r.p, *this < r.d); +} + +bool XForm::operator == (const XForm& x) const +{ + return m_isWorldToLocal == x.m_isWorldToLocal && m == x.m; +} + +bool XForm::operator != (const XForm& x) const +{ + return !(*this == x); +} + +// +// XForm::Matrix +// + +XForm::Matrix::Matrix() +{ + mat[0][0] = 1.0f; + mat[0][1] = 0.0f; + mat[0][2] = 0.0f; + mat[0][3] = 0.0f; + mat[1][0] = 0.0f; + mat[1][1] = 1.0f; + mat[1][2] = 0.0f; + mat[1][3] = 0.0f; + mat[2][0] = 0.0f; + mat[2][1] = 0.0f; + mat[2][2] = 1.0f; + mat[2][3] = 0.0f; + mat[3][0] = 0.0f; + mat[3][1] = 0.0f; + mat[3][2] = 0.0f; + mat[3][3] = 1.0f; +} + +XForm::Matrix XForm::Matrix::operator * (const Matrix& m) const +{ + Matrix ret; + + for (ptrdiff_t i = 0; i < 4; i++) { + for (ptrdiff_t j = 0; j < 4; j++) { + ret.mat[i][j] = mat[i][0] * m.mat[0][j] + + mat[i][1] * m.mat[1][j] + + mat[i][2] * m.mat[2][j] + + mat[i][3] * m.mat[3][j]; + + if (IsZero(ret.mat[i][j])) { + ret.mat[i][j] = 0.0f; + } + } + } + + return ret; +} + +XForm::Matrix& XForm::Matrix::operator *= (XForm::Matrix& m) +{ + return (*this = *this * m); +} + +bool XForm::Matrix::operator == (const XForm::Matrix& m) const +{ + return mat == m.mat; +} diff --git a/src/SubPic/CoordGeom.h b/src/SubPic/CoordGeom.h index 987a30d8283..fb86f06c4be 100644 --- a/src/SubPic/CoordGeom.h +++ b/src/SubPic/CoordGeom.h @@ -1,137 +1,137 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#pragma once - -#include -#include - -class Vector -{ -public: - float x, y, z; - - Vector() { x = y = z = 0.0f; } - Vector(float x, float y, float z); - void Set(float x, float y, float z); - - Vector Normal(const Vector& a, const Vector& b) const; - float Angle(const Vector& a, const Vector& b) const; - float Angle(const Vector& a) const; - void Angle(float& u, float& v) const; // returns spherical coords in radian, -M_PI_2 <= u <= M_PI_2, -M_PI <= v <= M_PI - Vector Angle() const; // does like prev., returns 'u' in 'ret.x', and 'v' in 'ret.y' - - Vector Unit() const; - Vector& Unitalize(); - float Length() const; - float Sum() const; // x + y + z - float CrossSum() const; // xy + xz + yz - Vector Cross() const; // xy, xz, yz - Vector Pow(float exp) const; - - Vector& Min(const Vector& a); - Vector& Max(const Vector& a); - Vector Abs() const; - - Vector Reflect(const Vector& n) const; - Vector Refract(const Vector& n, float nFront, float nBack, float* nOut = nullptr) const; - Vector Refract2(const Vector& n, float nFrom, float nTo, float* nOut = nullptr) const; - - Vector operator - () const; - float& operator [](size_t i); - - float operator | (const Vector& v) const; // dot - Vector operator % (const Vector& v) const; // cross - - bool operator == (const Vector& v) const; - bool operator != (const Vector& v) const; - - Vector operator + (float d) const; - Vector operator + (const Vector& v) const; - Vector operator - (float d) const; - Vector operator - (const Vector& v) const; - Vector operator * (float d) const; - Vector operator * (const Vector& v) const; - Vector operator / (float d) const; - Vector operator / (const Vector& v) const; - Vector& operator += (float d); - Vector& operator += (const Vector& v); - Vector& operator -= (float d); - Vector& operator -= (Vector& v); - Vector& operator *= (float d); - Vector& operator *= (const Vector& v); - Vector& operator /= (float d); - Vector& operator /= (const Vector& v); - - template static float DegToRad(T angle) { return (float)(angle * M_PI / 180); } -}; - -class Ray -{ -public: - Vector p, d; - - Ray() {} - Ray(const Vector& p, const Vector& d); - void Set(const Vector& p, const Vector& d); - - float GetDistanceFrom(const Ray& r) const; // r = plane - float GetDistanceFrom(const Vector& v) const; // v = point - - Vector operator [](float t) const; -}; - -class XForm -{ - class Matrix - { - public: - std::array, 4> mat; - - Matrix(); - - Matrix operator * (const Matrix& m) const; - Matrix& operator *= (Matrix& m); - bool operator == (const Matrix& m) const; - } m; - - bool m_isWorldToLocal; - -public: - XForm() : m_isWorldToLocal(false) {} - XForm(const Ray& r, const Vector& s, bool isWorldToLocal = true); - - void operator *= (const Vector& s); // scale - void operator += (const Vector& t); // translate - void operator <<= (const Vector& r); // rotate - - void operator /= (const Vector& s); // scale - void operator -= (const Vector& t); // translate - void operator >>= (const Vector& r); // rotate - - bool operator == (const XForm& x) const; // compare - bool operator != (const XForm& x) const; - - // transformations - Vector operator < (const Vector& n) const; // normal - Vector operator << (const Vector& v) const; // vector - Ray operator << (const Ray& r) const; // ray -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#pragma once + +#include +#include + +class Vector +{ +public: + float x, y, z; + + Vector() { x = y = z = 0.0f; } + Vector(float x, float y, float z); + void Set(float x, float y, float z); + + Vector Normal(const Vector& a, const Vector& b) const; + float Angle(const Vector& a, const Vector& b) const; + float Angle(const Vector& a) const; + void Angle(float& u, float& v) const; // returns spherical coords in radian, -M_PI_2 <= u <= M_PI_2, -M_PI <= v <= M_PI + Vector Angle() const; // does like prev., returns 'u' in 'ret.x', and 'v' in 'ret.y' + + Vector Unit() const; + Vector& Unitalize(); + float Length() const; + float Sum() const; // x + y + z + float CrossSum() const; // xy + xz + yz + Vector Cross() const; // xy, xz, yz + Vector Pow(float exp) const; + + Vector& Min(const Vector& a); + Vector& Max(const Vector& a); + Vector Abs() const; + + Vector Reflect(const Vector& n) const; + Vector Refract(const Vector& n, float nFront, float nBack, float* nOut = nullptr) const; + Vector Refract2(const Vector& n, float nFrom, float nTo, float* nOut = nullptr) const; + + Vector operator - () const; + float& operator [](size_t i); + + float operator | (const Vector& v) const; // dot + Vector operator % (const Vector& v) const; // cross + + bool operator == (const Vector& v) const; + bool operator != (const Vector& v) const; + + Vector operator + (float d) const; + Vector operator + (const Vector& v) const; + Vector operator - (float d) const; + Vector operator - (const Vector& v) const; + Vector operator * (float d) const; + Vector operator * (const Vector& v) const; + Vector operator / (float d) const; + Vector operator / (const Vector& v) const; + Vector& operator += (float d); + Vector& operator += (const Vector& v); + Vector& operator -= (float d); + Vector& operator -= (Vector& v); + Vector& operator *= (float d); + Vector& operator *= (const Vector& v); + Vector& operator /= (float d); + Vector& operator /= (const Vector& v); + + template static float DegToRad(T angle) { return (float)(angle * M_PI / 180); } +}; + +class Ray +{ +public: + Vector p, d; + + Ray() {} + Ray(const Vector& p, const Vector& d); + void Set(const Vector& p, const Vector& d); + + float GetDistanceFrom(const Ray& r) const; // r = plane + float GetDistanceFrom(const Vector& v) const; // v = point + + Vector operator [](float t) const; +}; + +class XForm +{ + class Matrix + { + public: + std::array, 4> mat; + + Matrix(); + + Matrix operator * (const Matrix& m) const; + Matrix& operator *= (Matrix& m); + bool operator == (const Matrix& m) const; + } m; + + bool m_isWorldToLocal; + +public: + XForm() : m_isWorldToLocal(false) {} + XForm(const Ray& r, const Vector& s, bool isWorldToLocal = true); + + void operator *= (const Vector& s); // scale + void operator += (const Vector& t); // translate + void operator <<= (const Vector& r); // rotate + + void operator /= (const Vector& s); // scale + void operator -= (const Vector& t); // translate + void operator >>= (const Vector& r); // rotate + + bool operator == (const XForm& x) const; // compare + bool operator != (const XForm& x) const; + + // transformations + Vector operator < (const Vector& n) const; // normal + Vector operator << (const Vector& v) const; // vector + Ray operator << (const Ray& r) const; // ray +}; diff --git a/src/SubPic/DX9SubPic.cpp b/src/SubPic/DX9SubPic.cpp index 17bf91ec9db..e6cbeb98eca 100644 --- a/src/SubPic/DX9SubPic.cpp +++ b/src/SubPic/DX9SubPic.cpp @@ -1,482 +1,482 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "DX9SubPic.h" -#include -#include - -#include "mpc-hc_config.h" - -#if !TRACE_SUBTITLES -#define TRACE(...) -#endif - -// -// CDX9SubPic -// - -CDX9SubPic::CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator* pAllocator, bool bExternalRenderer) - : m_pSurface(pSurface) - , m_pAllocator(pAllocator) - , m_bExternalRenderer(bExternalRenderer) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (SUCCEEDED(m_pSurface->GetDesc(&desc))) { - m_maxsize.SetSize(desc.Width, desc.Height); - m_rcDirty.SetRect(0, 0, desc.Width, desc.Height); - } -} - -CDX9SubPic::~CDX9SubPic() -{ - CAutoLock lock(&CDX9SubPicAllocator::ms_surfaceQueueLock); - // Add surface to cache - if (m_pAllocator) { - for (POSITION pos = m_pAllocator->m_allocatedSurfaces.GetHeadPosition(); pos;) { - POSITION thisPos = pos; - CDX9SubPic* pSubPic = m_pAllocator->m_allocatedSurfaces.GetNext(pos); - if (pSubPic == this) { - m_pAllocator->m_allocatedSurfaces.RemoveAt(thisPos); - break; - } - } - m_pAllocator->m_freeSurfaces.AddTail(m_pSurface); - } -} - - -// ISubPic - -STDMETHODIMP_(void*) CDX9SubPic::GetObject() -{ - CComPtr pTexture; - if (SUCCEEDED(m_pSurface->GetContainer(IID_PPV_ARGS(&pTexture)))) { - return (IDirect3DTexture9*)pTexture; - } - - return nullptr; -} - -STDMETHODIMP CDX9SubPic::GetDesc(SubPicDesc& spd) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(m_pSurface->GetDesc(&desc))) { - return E_FAIL; - } - - spd.type = 0; - spd.w = m_size.cx; - spd.h = m_size.cy; - spd.bpp = - desc.Format == D3DFMT_A8R8G8B8 ? 32 : - desc.Format == D3DFMT_A4R4G4B4 ? 16 : 0; - spd.pitch = 0; - spd.bits = nullptr; - spd.vidrect = m_vidrect; - - return S_OK; -} - -STDMETHODIMP CDX9SubPic::CopyTo(ISubPic* pSubPic) -{ - HRESULT hr; - if (FAILED(hr = __super::CopyTo(pSubPic))) { - return hr; - } - - if (m_rcDirty.IsRectEmpty()) { - return S_FALSE; - } - - CComPtr pD3DDev; - if (!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) { - return E_FAIL; - } - - IDirect3DTexture9* pSrcTex = (IDirect3DTexture9*)GetObject(); - CComPtr pSrcSurf; - pSrcTex->GetSurfaceLevel(0, &pSrcSurf); - if (!pSrcSurf) { - return E_FAIL; - } - D3DSURFACE_DESC srcDesc; - pSrcSurf->GetDesc(&srcDesc); - - IDirect3DTexture9* pDstTex = (IDirect3DTexture9*)pSubPic->GetObject(); - CComPtr pDstSurf; - pDstTex->GetSurfaceLevel(0, &pDstSurf); - D3DSURFACE_DESC dstDesc; - pDstSurf->GetDesc(&dstDesc); - - RECT r; - SetRect(&r, 0, 0, std::min(srcDesc.Width, dstDesc.Width), std::min(srcDesc.Height, dstDesc.Height)); - POINT p = { 0, 0 }; - hr = pD3DDev->UpdateSurface(pSrcSurf, &r, pDstSurf, &p); - - return SUCCEEDED(hr) ? S_OK : E_FAIL; -} - -STDMETHODIMP CDX9SubPic::ClearDirtyRect() -{ - if (m_rcDirty.IsRectEmpty()) { - return S_FALSE; - } - - CComPtr pD3DDev; - if (!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) { - return E_FAIL; - } - - m_rcDirty.IntersectRect(m_rcDirty, CRect(0, 0, m_maxsize.cx, m_maxsize.cy)); - - SubPicDesc spd; - if (SUCCEEDED(Lock(spd))) { - int h = m_rcDirty.Height(); - BYTE* ptr = spd.bits + spd.pitch * m_rcDirty.top + (m_rcDirty.left * spd.bpp >> 3); - - if (spd.bpp == 16) { - const unsigned short color = m_bInvAlpha ? 0x00000000 : 0xFF000000; - const int w2 = m_rcDirty.Width() * 2; - while (h-- > 0) { - memsetw(ptr, color, w2); - ptr += spd.pitch; - } - } else if (spd.bpp == 32) { - const DWORD color = m_bInvAlpha ? 0x00000000 : 0xFF000000; - const int w4 = m_rcDirty.Width() * 4; - while (h-- > 0) { - memsetd(ptr, color, w4); - ptr += spd.pitch; - } - } - Unlock(nullptr); - } - - m_rcDirty.SetRectEmpty(); - - return S_OK; -} - -STDMETHODIMP CDX9SubPic::Lock(SubPicDesc& spd) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(m_pSurface->GetDesc(&desc))) { - return E_FAIL; - } - - D3DLOCKED_RECT LockedRect; - ZeroMemory(&LockedRect, sizeof(LockedRect)); - if (FAILED(m_pSurface->LockRect(&LockedRect, nullptr, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK))) { - return E_FAIL; - } - - spd.type = 0; - spd.w = m_size.cx; - spd.h = m_size.cy; - spd.bpp = - desc.Format == D3DFMT_A8R8G8B8 ? 32 : - desc.Format == D3DFMT_A4R4G4B4 ? 16 : 0; - spd.pitch = LockedRect.Pitch; - spd.bits = (BYTE*)LockedRect.pBits; - spd.vidrect = m_vidrect; - - return S_OK; -} - -STDMETHODIMP CDX9SubPic::Unlock(RECT* pDirtyRect) -{ - m_pSurface->UnlockRect(); - - if (pDirtyRect) { - m_rcDirty = pDirtyRect; - if (!m_rcDirty.IsRectEmpty()) { - m_rcDirty.InflateRect(1, 1); - m_rcDirty.IntersectRect(m_rcDirty, CRect(0, 0, m_size.cx, m_size.cy)); - - CComPtr pTexture = (IDirect3DTexture9*)GetObject(); - if (pTexture) { - pTexture->AddDirtyRect(&m_rcDirty); - } - } - } else { - m_rcDirty = CRect(CPoint(0, 0), m_size); - } - - return S_OK; -} - -STDMETHODIMP CDX9SubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) -{ - ASSERT(pTarget == nullptr); - - if (!pSrc || !pDst) { - return E_POINTER; - } - - CRect src(*pSrc), dst(*pDst); - - CComPtr pD3DDev; - CComPtr pTexture = (IDirect3DTexture9*)GetObject(); - if (!pTexture || FAILED(pTexture->GetDevice(&pD3DDev)) || !pD3DDev) { - return E_NOINTERFACE; - } - - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile - // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly - // initialized and thus the subtitles weren't shown. - struct { - float x, y, z, rhw; - float tu, tv; - } pVertices[] = { - {float(dst.left), float(dst.top), 0.5f, 2.0f, float(src.left) / w, float(src.top) / h}, - {float(dst.right), float(dst.top), 0.5f, 2.0f, float(src.right) / w, float(src.top) / h}, - {float(dst.left), float(dst.bottom), 0.5f, 2.0f, float(src.left) / w, float(src.bottom) / h}, - {float(dst.right), float(dst.bottom), 0.5f, 2.0f, float(src.right) / w, float(src.bottom) / h}, - }; - - for (size_t i = 0; i < _countof(pVertices); i++) { - pVertices[i].x -= 0.5f; - pVertices[i].y -= 0.5f; - } - - pD3DDev->SetTexture(0, pTexture); - - // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE - // so we need to provide default values in case GetRenderState fails - DWORD abe, sb, db; - if (FAILED(pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { - abe = FALSE; - } - if (FAILED(pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { - sb = D3DBLEND_ONE; - } - if (FAILED(pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { - db = D3DBLEND_ZERO; - } - - pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... - pD3DDev->SetRenderState(D3DRS_DESTBLEND, m_bInvAlpha ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst - - pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - - if (src == dst) { - pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - } else { - pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - } - pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); - pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); - pD3DDev->SetSamplerState(0, D3DSAMP_BORDERCOLOR, m_bInvAlpha ? 0x00000000 : 0xFF000000); - - /*// - D3DCAPS9 d3dcaps9; - pD3DDev->GetDeviceCaps(&d3dcaps9); - if (d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS) { - pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE); - pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); - pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS); - } - */// - - pD3DDev->SetPixelShader(nullptr); - - if (m_bExternalRenderer && FAILED(pD3DDev->BeginScene())) { - return E_FAIL; - } - - pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); - pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); - - if (m_bExternalRenderer) { - pD3DDev->EndScene(); - } - - pD3DDev->SetTexture(0, nullptr); - - pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); - pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); - pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); - - return S_OK; -} - -// -// CDX9SubPicAllocator -// - -CDX9SubPicAllocator::CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool bExternalRenderer) - : CSubPicAllocatorImpl(maxsize, true) - , m_pD3DDev(pD3DDev) - , m_maxsize(maxsize) - , m_bExternalRenderer(bExternalRenderer) -{ -} - -CCritSec CDX9SubPicAllocator::ms_surfaceQueueLock; - -CDX9SubPicAllocator::~CDX9SubPicAllocator() -{ - ClearCache(); -} - -void CDX9SubPicAllocator::GetStats(int& nFree, int& nAlloc) const -{ - CAutoLock autoLock(&ms_surfaceQueueLock); - nFree = (int)m_freeSurfaces.GetCount(); - nAlloc = (int)m_allocatedSurfaces.GetCount(); -} - -void CDX9SubPicAllocator::ClearCache() -{ - TRACE(_T("CDX9SubPicAllocator::ClearCache\n")); - // Clear the allocator of any remaining subpics - CAutoLock autoLock(&ms_surfaceQueueLock); - for (POSITION pos = m_allocatedSurfaces.GetHeadPosition(); pos;) { - CDX9SubPic* pSubPic = m_allocatedSurfaces.GetNext(pos); - pSubPic->m_pAllocator = nullptr; - } - m_allocatedSurfaces.RemoveAll(); - m_freeSurfaces.RemoveAll(); -} - -// ISubPicAllocator - -STDMETHODIMP CDX9SubPicAllocator::ChangeDevice(IUnknown* pDev) -{ - CComQIPtr pD3DDev = pDev; - CheckPointer(pD3DDev, E_NOINTERFACE); - - CAutoLock cAutoLock(this); - HRESULT hr = S_FALSE; - if (m_pD3DDev != pD3DDev) { - ClearCache(); - m_pD3DDev = pD3DDev; - hr = __super::ChangeDevice(pDev); - } - - return hr; -} - -STDMETHODIMP CDX9SubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) -{ - CAutoLock cAutoLock(this); - -#if DEBUG_OVERRIDE_TEXTURE_SIZE - maxTextureSize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); -#endif - - if (maxTextureSize.cx > 0 && maxTextureSize.cy > 0 && m_maxsize != maxTextureSize) { - ClearCache(); - m_maxsize = maxTextureSize; - TRACE(_T("CDX9SubPicAllocator::SetMaxTextureSize %dx%d\n"), m_maxsize.cx, m_maxsize.cy); - } - - return S_OK; -} - -// ISubPicAllocatorImpl - -bool CDX9SubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) -{ - if (!ppSubPic) { - return false; - } - - if (m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { - TRACE(_T("CDX9SubPicAllocator::Alloc -> maxsize is zero\n")); - return false; - } - -#if DEBUG_OVERRIDE_TEXTURE_SIZE - ASSERT(m_maxsize.cx == DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH && m_maxsize.cy == DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); -#endif - - CAutoLock cAutoLock(this); - - *ppSubPic = nullptr; - - CComPtr pSurface; - - if (!fStatic) { - CAutoLock cAutoLock2(&ms_surfaceQueueLock); - if (!m_freeSurfaces.IsEmpty()) { - pSurface = m_freeSurfaces.RemoveHead(); - } - } - - if (!pSurface) { - CComPtr pTexture; - HRESULT hr = m_pD3DDev->CreateTexture(m_maxsize.cx, m_maxsize.cy, 1, 0, D3DFMT_A8R8G8B8, fStatic ? D3DPOOL_SYSTEMMEM : D3DPOOL_DEFAULT, &pTexture, nullptr); - if (FAILED(hr)) { - TRACE(_T("CDX9SubPicAllocator::Alloc -> CreateTexture failed (%dx%d), hr=%x\n"), m_maxsize.cx, m_maxsize.cy, hr); - return false; - } - - hr = pTexture->GetSurfaceLevel(0, &pSurface); - if (FAILED(hr)) { - TRACE(_T("CDX9SubPicAllocator::Alloc -> GetSurfaceLevel failed, hr=%x\n"), hr); - return false; - } - - TRACE(_T("CDX9SubPicAllocator::Alloc -> Surface allocated (%dx%d)\n"), m_maxsize.cx, m_maxsize.cy); - } - - try { - *ppSubPic = DEBUG_NEW CDX9SubPic(pSurface, fStatic ? nullptr : this, m_bExternalRenderer); - } catch (CMemoryException* e) { - e->Delete(); - TRACE(_T("CDX9SubPicAllocator::Alloc -> CDX9SubPic gave memory exception\n")); - return false; - } - - (*ppSubPic)->AddRef(); - (*ppSubPic)->SetInverseAlpha(m_bInvAlpha); - - if (!fStatic) { - CAutoLock cAutoLock2(&ms_surfaceQueueLock); - m_allocatedSurfaces.AddHead((CDX9SubPic*)*ppSubPic); - } - - return true; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "DX9SubPic.h" +#include +#include + +#include "mpc-hc_config.h" + +#if !TRACE_SUBTITLES +#define TRACE(...) +#endif + +// +// CDX9SubPic +// + +CDX9SubPic::CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator* pAllocator, bool bExternalRenderer) + : m_pSurface(pSurface) + , m_pAllocator(pAllocator) + , m_bExternalRenderer(bExternalRenderer) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (SUCCEEDED(m_pSurface->GetDesc(&desc))) { + m_maxsize.SetSize(desc.Width, desc.Height); + m_rcDirty.SetRect(0, 0, desc.Width, desc.Height); + } +} + +CDX9SubPic::~CDX9SubPic() +{ + CAutoLock lock(&CDX9SubPicAllocator::ms_surfaceQueueLock); + // Add surface to cache + if (m_pAllocator) { + for (POSITION pos = m_pAllocator->m_allocatedSurfaces.GetHeadPosition(); pos;) { + POSITION thisPos = pos; + CDX9SubPic* pSubPic = m_pAllocator->m_allocatedSurfaces.GetNext(pos); + if (pSubPic == this) { + m_pAllocator->m_allocatedSurfaces.RemoveAt(thisPos); + break; + } + } + m_pAllocator->m_freeSurfaces.AddTail(m_pSurface); + } +} + + +// ISubPic + +STDMETHODIMP_(void*) CDX9SubPic::GetObject() +{ + CComPtr pTexture; + if (SUCCEEDED(m_pSurface->GetContainer(IID_PPV_ARGS(&pTexture)))) { + return (IDirect3DTexture9*)pTexture; + } + + return nullptr; +} + +STDMETHODIMP CDX9SubPic::GetDesc(SubPicDesc& spd) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(m_pSurface->GetDesc(&desc))) { + return E_FAIL; + } + + spd.type = 0; + spd.w = m_size.cx; + spd.h = m_size.cy; + spd.bpp = + desc.Format == D3DFMT_A8R8G8B8 ? 32 : + desc.Format == D3DFMT_A4R4G4B4 ? 16 : 0; + spd.pitch = 0; + spd.bits = nullptr; + spd.vidrect = m_vidrect; + + return S_OK; +} + +STDMETHODIMP CDX9SubPic::CopyTo(ISubPic* pSubPic) +{ + HRESULT hr; + if (FAILED(hr = __super::CopyTo(pSubPic))) { + return hr; + } + + if (m_rcDirty.IsRectEmpty()) { + return S_FALSE; + } + + CComPtr pD3DDev; + if (!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) { + return E_FAIL; + } + + IDirect3DTexture9* pSrcTex = (IDirect3DTexture9*)GetObject(); + CComPtr pSrcSurf; + pSrcTex->GetSurfaceLevel(0, &pSrcSurf); + if (!pSrcSurf) { + return E_FAIL; + } + D3DSURFACE_DESC srcDesc; + pSrcSurf->GetDesc(&srcDesc); + + IDirect3DTexture9* pDstTex = (IDirect3DTexture9*)pSubPic->GetObject(); + CComPtr pDstSurf; + pDstTex->GetSurfaceLevel(0, &pDstSurf); + D3DSURFACE_DESC dstDesc; + pDstSurf->GetDesc(&dstDesc); + + RECT r; + SetRect(&r, 0, 0, std::min(srcDesc.Width, dstDesc.Width), std::min(srcDesc.Height, dstDesc.Height)); + POINT p = { 0, 0 }; + hr = pD3DDev->UpdateSurface(pSrcSurf, &r, pDstSurf, &p); + + return SUCCEEDED(hr) ? S_OK : E_FAIL; +} + +STDMETHODIMP CDX9SubPic::ClearDirtyRect() +{ + if (m_rcDirty.IsRectEmpty()) { + return S_FALSE; + } + + CComPtr pD3DDev; + if (!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) { + return E_FAIL; + } + + m_rcDirty.IntersectRect(m_rcDirty, CRect(0, 0, m_maxsize.cx, m_maxsize.cy)); + + SubPicDesc spd; + if (SUCCEEDED(Lock(spd))) { + int h = m_rcDirty.Height(); + BYTE* ptr = spd.bits + spd.pitch * m_rcDirty.top + (m_rcDirty.left * spd.bpp >> 3); + + if (spd.bpp == 16) { + const unsigned short color = m_bInvAlpha ? 0x00000000 : 0xFF000000; + const int w2 = m_rcDirty.Width() * 2; + while (h-- > 0) { + memsetw(ptr, color, w2); + ptr += spd.pitch; + } + } else if (spd.bpp == 32) { + const DWORD color = m_bInvAlpha ? 0x00000000 : 0xFF000000; + const int w4 = m_rcDirty.Width() * 4; + while (h-- > 0) { + memsetd(ptr, color, w4); + ptr += spd.pitch; + } + } + Unlock(nullptr); + } + + m_rcDirty.SetRectEmpty(); + + return S_OK; +} + +STDMETHODIMP CDX9SubPic::Lock(SubPicDesc& spd) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(m_pSurface->GetDesc(&desc))) { + return E_FAIL; + } + + D3DLOCKED_RECT LockedRect; + ZeroMemory(&LockedRect, sizeof(LockedRect)); + if (FAILED(m_pSurface->LockRect(&LockedRect, nullptr, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK))) { + return E_FAIL; + } + + spd.type = 0; + spd.w = m_size.cx; + spd.h = m_size.cy; + spd.bpp = + desc.Format == D3DFMT_A8R8G8B8 ? 32 : + desc.Format == D3DFMT_A4R4G4B4 ? 16 : 0; + spd.pitch = LockedRect.Pitch; + spd.bits = (BYTE*)LockedRect.pBits; + spd.vidrect = m_vidrect; + + return S_OK; +} + +STDMETHODIMP CDX9SubPic::Unlock(RECT* pDirtyRect) +{ + m_pSurface->UnlockRect(); + + if (pDirtyRect) { + m_rcDirty = pDirtyRect; + if (!m_rcDirty.IsRectEmpty()) { + m_rcDirty.InflateRect(1, 1); + m_rcDirty.IntersectRect(m_rcDirty, CRect(0, 0, m_size.cx, m_size.cy)); + + CComPtr pTexture = (IDirect3DTexture9*)GetObject(); + if (pTexture) { + pTexture->AddDirtyRect(&m_rcDirty); + } + } + } else { + m_rcDirty = CRect(CPoint(0, 0), m_size); + } + + return S_OK; +} + +STDMETHODIMP CDX9SubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) +{ + ASSERT(pTarget == nullptr); + + if (!pSrc || !pDst) { + return E_POINTER; + } + + CRect src(*pSrc), dst(*pDst); + + CComPtr pD3DDev; + CComPtr pTexture = (IDirect3DTexture9*)GetObject(); + if (!pTexture || FAILED(pTexture->GetDevice(&pD3DDev)) || !pD3DDev) { + return E_NOINTERFACE; + } + + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile + // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly + // initialized and thus the subtitles weren't shown. + struct { + float x, y, z, rhw; + float tu, tv; + } pVertices[] = { + {float(dst.left), float(dst.top), 0.5f, 2.0f, float(src.left) / w, float(src.top) / h}, + {float(dst.right), float(dst.top), 0.5f, 2.0f, float(src.right) / w, float(src.top) / h}, + {float(dst.left), float(dst.bottom), 0.5f, 2.0f, float(src.left) / w, float(src.bottom) / h}, + {float(dst.right), float(dst.bottom), 0.5f, 2.0f, float(src.right) / w, float(src.bottom) / h}, + }; + + for (size_t i = 0; i < _countof(pVertices); i++) { + pVertices[i].x -= 0.5f; + pVertices[i].y -= 0.5f; + } + + pD3DDev->SetTexture(0, pTexture); + + // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE + // so we need to provide default values in case GetRenderState fails + DWORD abe, sb, db; + if (FAILED(pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { + abe = FALSE; + } + if (FAILED(pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { + sb = D3DBLEND_ONE; + } + if (FAILED(pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { + db = D3DBLEND_ZERO; + } + + pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... + pD3DDev->SetRenderState(D3DRS_DESTBLEND, m_bInvAlpha ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst + + pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + if (src == dst) { + pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + } else { + pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + } + pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); + pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); + pD3DDev->SetSamplerState(0, D3DSAMP_BORDERCOLOR, m_bInvAlpha ? 0x00000000 : 0xFF000000); + + /*// + D3DCAPS9 d3dcaps9; + pD3DDev->GetDeviceCaps(&d3dcaps9); + if (d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS) { + pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE); + pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS); + } + */// + + pD3DDev->SetPixelShader(nullptr); + + if (m_bExternalRenderer && FAILED(pD3DDev->BeginScene())) { + return E_FAIL; + } + + pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + + if (m_bExternalRenderer) { + pD3DDev->EndScene(); + } + + pD3DDev->SetTexture(0, nullptr); + + pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); + pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); + pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); + + return S_OK; +} + +// +// CDX9SubPicAllocator +// + +CDX9SubPicAllocator::CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool bExternalRenderer) + : CSubPicAllocatorImpl(maxsize, true) + , m_pD3DDev(pD3DDev) + , m_maxsize(maxsize) + , m_bExternalRenderer(bExternalRenderer) +{ +} + +CCritSec CDX9SubPicAllocator::ms_surfaceQueueLock; + +CDX9SubPicAllocator::~CDX9SubPicAllocator() +{ + ClearCache(); +} + +void CDX9SubPicAllocator::GetStats(int& nFree, int& nAlloc) const +{ + CAutoLock autoLock(&ms_surfaceQueueLock); + nFree = (int)m_freeSurfaces.GetCount(); + nAlloc = (int)m_allocatedSurfaces.GetCount(); +} + +void CDX9SubPicAllocator::ClearCache() +{ + TRACE(_T("CDX9SubPicAllocator::ClearCache\n")); + // Clear the allocator of any remaining subpics + CAutoLock autoLock(&ms_surfaceQueueLock); + for (POSITION pos = m_allocatedSurfaces.GetHeadPosition(); pos;) { + CDX9SubPic* pSubPic = m_allocatedSurfaces.GetNext(pos); + pSubPic->m_pAllocator = nullptr; + } + m_allocatedSurfaces.RemoveAll(); + m_freeSurfaces.RemoveAll(); +} + +// ISubPicAllocator + +STDMETHODIMP CDX9SubPicAllocator::ChangeDevice(IUnknown* pDev) +{ + CComQIPtr pD3DDev = pDev; + CheckPointer(pD3DDev, E_NOINTERFACE); + + CAutoLock cAutoLock(this); + HRESULT hr = S_FALSE; + if (m_pD3DDev != pD3DDev) { + ClearCache(); + m_pD3DDev = pD3DDev; + hr = __super::ChangeDevice(pDev); + } + + return hr; +} + +STDMETHODIMP CDX9SubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) +{ + CAutoLock cAutoLock(this); + +#if DEBUG_OVERRIDE_TEXTURE_SIZE + maxTextureSize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); +#endif + + if (maxTextureSize.cx > 0 && maxTextureSize.cy > 0 && m_maxsize != maxTextureSize) { + ClearCache(); + m_maxsize = maxTextureSize; + TRACE(_T("CDX9SubPicAllocator::SetMaxTextureSize %dx%d\n"), m_maxsize.cx, m_maxsize.cy); + } + + return S_OK; +} + +// ISubPicAllocatorImpl + +bool CDX9SubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) +{ + if (!ppSubPic) { + return false; + } + + if (m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { + TRACE(_T("CDX9SubPicAllocator::Alloc -> maxsize is zero\n")); + return false; + } + +#if DEBUG_OVERRIDE_TEXTURE_SIZE + ASSERT(m_maxsize.cx == DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH && m_maxsize.cy == DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); +#endif + + CAutoLock cAutoLock(this); + + *ppSubPic = nullptr; + + CComPtr pSurface; + + if (!fStatic) { + CAutoLock cAutoLock2(&ms_surfaceQueueLock); + if (!m_freeSurfaces.IsEmpty()) { + pSurface = m_freeSurfaces.RemoveHead(); + } + } + + if (!pSurface) { + CComPtr pTexture; + HRESULT hr = m_pD3DDev->CreateTexture(m_maxsize.cx, m_maxsize.cy, 1, 0, D3DFMT_A8R8G8B8, fStatic ? D3DPOOL_SYSTEMMEM : D3DPOOL_DEFAULT, &pTexture, nullptr); + if (FAILED(hr)) { + TRACE(_T("CDX9SubPicAllocator::Alloc -> CreateTexture failed (%dx%d), hr=%x\n"), m_maxsize.cx, m_maxsize.cy, hr); + return false; + } + + hr = pTexture->GetSurfaceLevel(0, &pSurface); + if (FAILED(hr)) { + TRACE(_T("CDX9SubPicAllocator::Alloc -> GetSurfaceLevel failed, hr=%x\n"), hr); + return false; + } + + TRACE(_T("CDX9SubPicAllocator::Alloc -> Surface allocated (%dx%d)\n"), m_maxsize.cx, m_maxsize.cy); + } + + try { + *ppSubPic = DEBUG_NEW CDX9SubPic(pSurface, fStatic ? nullptr : this, m_bExternalRenderer); + } catch (CMemoryException* e) { + e->Delete(); + TRACE(_T("CDX9SubPicAllocator::Alloc -> CDX9SubPic gave memory exception\n")); + return false; + } + + (*ppSubPic)->AddRef(); + (*ppSubPic)->SetInverseAlpha(m_bInvAlpha); + + if (!fStatic) { + CAutoLock cAutoLock2(&ms_surfaceQueueLock); + m_allocatedSurfaces.AddHead((CDX9SubPic*)*ppSubPic); + } + + return true; +} diff --git a/src/SubPic/DX9SubPic.h b/src/SubPic/DX9SubPic.h index 7d871f1308b..ff4e76bd089 100644 --- a/src/SubPic/DX9SubPic.h +++ b/src/SubPic/DX9SubPic.h @@ -1,78 +1,78 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "SubPicImpl.h" -#include "SubPicAllocatorPresenterImpl.h" -#include - -// CDX9SubPic - - -class CDX9SubPicAllocator; -class CDX9SubPic : public CSubPicImpl -{ - CComPtr m_pSurface; - -protected: - STDMETHODIMP_(void*) GetObject(); // returns IDirect3DTexture9* - -public: - CDX9SubPicAllocator* m_pAllocator; - bool m_bExternalRenderer; - CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator* pAllocator, bool bExternalRenderer); - ~CDX9SubPic(); - - // ISubPic - STDMETHODIMP GetDesc(SubPicDesc& spd); - STDMETHODIMP CopyTo(ISubPic* pSubPic); - STDMETHODIMP ClearDirtyRect(); - STDMETHODIMP Lock(SubPicDesc& spd); - STDMETHODIMP Unlock(RECT* pDirtyRect); - STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget); -}; - -// CDX9SubPicAllocator - -class CDX9SubPicAllocator : public CSubPicAllocatorImpl, public CCritSec -{ - CComPtr m_pD3DDev; - CSize m_maxsize; - bool m_bExternalRenderer; - - bool Alloc(bool fStatic, ISubPic** ppSubPic); - -public: - static CCritSec ms_surfaceQueueLock; - CAtlList> m_freeSurfaces; - CAtlList m_allocatedSurfaces; - - void GetStats(int& nFree, int& nAlloc) const; - - CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool bExternalRenderer); - ~CDX9SubPicAllocator(); - void ClearCache(); - - // ISubPicAllocator - STDMETHODIMP ChangeDevice(IUnknown* pDev); - STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "SubPicImpl.h" +#include "SubPicAllocatorPresenterImpl.h" +#include + +// CDX9SubPic + + +class CDX9SubPicAllocator; +class CDX9SubPic : public CSubPicImpl +{ + CComPtr m_pSurface; + +protected: + STDMETHODIMP_(void*) GetObject(); // returns IDirect3DTexture9* + +public: + CDX9SubPicAllocator* m_pAllocator; + bool m_bExternalRenderer; + CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator* pAllocator, bool bExternalRenderer); + ~CDX9SubPic(); + + // ISubPic + STDMETHODIMP GetDesc(SubPicDesc& spd); + STDMETHODIMP CopyTo(ISubPic* pSubPic); + STDMETHODIMP ClearDirtyRect(); + STDMETHODIMP Lock(SubPicDesc& spd); + STDMETHODIMP Unlock(RECT* pDirtyRect); + STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget); +}; + +// CDX9SubPicAllocator + +class CDX9SubPicAllocator : public CSubPicAllocatorImpl, public CCritSec +{ + CComPtr m_pD3DDev; + CSize m_maxsize; + bool m_bExternalRenderer; + + bool Alloc(bool fStatic, ISubPic** ppSubPic); + +public: + static CCritSec ms_surfaceQueueLock; + CAtlList> m_freeSurfaces; + CAtlList m_allocatedSurfaces; + + void GetStats(int& nFree, int& nAlloc) const; + + CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool bExternalRenderer); + ~CDX9SubPicAllocator(); + void ClearCache(); + + // ISubPicAllocator + STDMETHODIMP ChangeDevice(IUnknown* pDev); + STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize); +}; diff --git a/src/SubPic/ISubPic.h b/src/SubPic/ISubPic.h index 189662a7d10..e78f689a94b 100644 --- a/src/SubPic/ISubPic.h +++ b/src/SubPic/ISubPic.h @@ -1,262 +1,262 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#pragma once - -#include -#include -#include "CoordGeom.h" -#include "strmif.h" - -// to force rendering subs at a specific size -#define DEBUG_OVERRIDE_TEXTURE_SIZE 0 -#define DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH 2560 -#define DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT 1440 - -#pragma pack(push, 1) -struct SubPicDesc { - int type; - int w, h, bpp, pitch, pitchUV; - BYTE* bits; - BYTE* bitsU; - BYTE* bitsV; - RECT vidrect; // video rectangle - - SubPicDesc() - : type(0) - , w(0) - , h(0) - , bpp(0) - , pitch(0) - , pitchUV(0) - , bits(nullptr) - , bitsU(nullptr) - , bitsV(nullptr) { - ZeroMemory(&vidrect, sizeof(vidrect)); - } -}; -#pragma pack(pop) - -enum RelativeTo { - WINDOW, - VIDEO, - BEST_FIT -}; - -// -// ISubPic -// - -interface __declspec(uuid("DA3A5B51-958C-4C28-BF66-68D7947577A2")) -ISubPic : -public IUnknown { - static const REFERENCE_TIME INVALID_SUBPIC_TIME = -1; - - STDMETHOD_(void*, GetObject)() PURE; - - STDMETHOD_(REFERENCE_TIME, GetStart)() const PURE; - STDMETHOD_(REFERENCE_TIME, GetStop)() const PURE; - STDMETHOD_(void, SetStart)(REFERENCE_TIME rtStart) PURE; - STDMETHOD_(void, SetStop)(REFERENCE_TIME rtStop) PURE; - - STDMETHOD(GetDesc)(SubPicDesc& spd /*[out]*/) PURE; - STDMETHOD(CopyTo)(ISubPic* pSubPic /*[in]*/) PURE; - - STDMETHOD(ClearDirtyRect)() PURE; - STDMETHOD(GetDirtyRect)(RECT* pDirtyRect /*[out]*/) const PURE; - STDMETHOD(SetDirtyRect)(const RECT* pDirtyRect /*[in]*/) PURE; - - STDMETHOD(GetMaxSize)(SIZE* pMaxSize /*[out]*/) const PURE; - STDMETHOD(SetSize)(SIZE pSize /*[in]*/, RECT vidrect /*[in]*/) PURE; - - STDMETHOD(Lock)(SubPicDesc& spd /*[out]*/) PURE; - STDMETHOD(Unlock)(RECT* pDirtyRect /*[in]*/) PURE; - - STDMETHOD(AlphaBlt)(RECT * pSrc, RECT * pDst, SubPicDesc* pTarget = nullptr /*[in]*/) PURE; - STDMETHOD(GetSourceAndDest)(RECT rcWindow /*[in]*/, RECT rcVideo /*[in]*/, - RECT* pRcSource /*[out]*/, RECT* pRcDest /*[out]*/, - const double videoStretchFactor = 1.0 /*[in]*/, - int xOffsetInPixels = 0 /*[in]*/, int yOffsetInPixels = 0 /*[in]*/) const PURE; - STDMETHOD(SetVirtualTextureSize)(const SIZE pSize, const POINT pTopLeft) PURE; - STDMETHOD(GetRelativeTo)(RelativeTo* pRelativeTo /*[out]*/) const PURE; - STDMETHOD(SetRelativeTo)(RelativeTo relativeTo /*[in]*/) PURE; - - STDMETHOD_(REFERENCE_TIME, GetSegmentStart)() const PURE; - STDMETHOD_(REFERENCE_TIME, GetSegmentStop)() const PURE; - STDMETHOD_(void, SetSegmentStart)(REFERENCE_TIME rtStart) PURE; - STDMETHOD_(void, SetSegmentStop)(REFERENCE_TIME rtStop) PURE; - - STDMETHOD_(void, SetInverseAlpha)(bool bInverted) PURE; -}; - -// -// ISubPicAllocator -// - -interface __declspec(uuid("CF7C3C23-6392-4a42-9E72-0736CFF793CB")) -ISubPicAllocator : -public IUnknown { - STDMETHOD(SetCurSize)(SIZE size /*[in]*/) PURE; - STDMETHOD(SetCurVidRect)(RECT curvidrect) PURE; - - STDMETHOD(GetStatic)(ISubPic** ppSubPic /*[out]*/) PURE; - STDMETHOD(AllocDynamic)(ISubPic** ppSubPic /*[out]*/) PURE; - - STDMETHOD_(bool, IsDynamicWriteOnly)() const PURE; - - STDMETHOD(ChangeDevice)(IUnknown * pDev) PURE; - STDMETHOD(SetMaxTextureSize)(SIZE maxTextureSize) PURE; - - STDMETHOD(FreeStatic)() PURE; - - STDMETHOD_(void, SetInverseAlpha)(bool bInverted) PURE; -}; - -// -// ISubPicProvider -// - -interface __declspec(uuid("D62B9A1A-879A-42db-AB04-88AA8F243CFD")) -ISubPicProvider : -public IUnknown { - static const REFERENCE_TIME UNKNOWN_TIME = _I64_MAX; - - STDMETHOD(Lock)() PURE; - STDMETHOD(Unlock)() PURE; - - STDMETHOD_(POSITION, GetStartPosition)(REFERENCE_TIME rt, double fps) PURE; - STDMETHOD_(POSITION, GetNext)(POSITION pos) PURE; - - STDMETHOD_(REFERENCE_TIME, GetStart)(POSITION pos, double fps) PURE; - STDMETHOD_(REFERENCE_TIME, GetStop)(POSITION pos, double fps) PURE; - - STDMETHOD_(bool, IsAnimated)(POSITION pos) PURE; - - STDMETHOD(Render)(SubPicDesc & spd, REFERENCE_TIME rt, double fps, RECT & bbox) PURE; - STDMETHOD(GetTextureSize)(POSITION pos, SIZE & MaxTextureSize, SIZE & VirtualSize, POINT & VirtualTopLeft) PURE; - STDMETHOD(GetRelativeTo)(POSITION pos, RelativeTo & relativeTo) PURE; -}; - -// -// ISubPicQueue -// - -interface __declspec(uuid("C8334466-CD1E-4ad1-9D2D-8EE8519BD180")) -ISubPicQueue : -public IUnknown { - STDMETHOD(SetSubPicProvider)(ISubPicProvider* pSubPicProvider /*[in]*/) PURE; - STDMETHOD(GetSubPicProvider)(ISubPicProvider** pSubPicProvider /*[out]*/) PURE; - - STDMETHOD(SetFPS)(double fps /*[in]*/) PURE; - STDMETHOD(SetTime)(REFERENCE_TIME rtNow /*[in]*/) PURE; - - STDMETHOD(Invalidate)(REFERENCE_TIME rtInvalidate = -1) PURE; - STDMETHOD_(bool, LookupSubPic)(REFERENCE_TIME rtNow /*[in]*/, CComPtr& pSubPic /*[out]*/) PURE; - - STDMETHOD(GetStats)(int& nSubPics, REFERENCE_TIME & rtNow, REFERENCE_TIME & rtStart, REFERENCE_TIME& rtStop /*[out]*/) PURE; - STDMETHOD(GetStats)(int nSubPic /*[in]*/, REFERENCE_TIME & rtStart, REFERENCE_TIME& rtStop /*[out]*/) PURE; - - STDMETHOD_(bool, LookupSubPic)(REFERENCE_TIME rtNow /*[in]*/, bool bAdviseBlocking, CComPtr& pSubPic /*[out]*/) PURE; -}; - -// -// ISubPicAllocatorPresenter -// -#define TARGET_FRAME 0 -#define TARGET_SCREEN 1 - -interface __declspec(uuid("CF75B1F0-535C-4074-8869-B15F177F944E")) -ISubPicAllocatorPresenter : -public IUnknown { - STDMETHOD(CreateRenderer)(IUnknown** ppRenderer) PURE; - - STDMETHOD_(SIZE, GetVideoSize)(bool bCorrectAR) const PURE; - STDMETHOD_(void, SetPosition)(RECT w, RECT v) PURE; - STDMETHOD_(bool, Paint)(bool bAll) PURE; - - STDMETHOD_(void, SetTime)(REFERENCE_TIME rtNow) PURE; - STDMETHOD_(void, SetSubtitleDelay)(int delayMs) PURE; - STDMETHOD_(int, GetSubtitleDelay)() const PURE; - STDMETHOD_(double, GetFPS)() const PURE; - - STDMETHOD_(void, SetSubPicProvider)(ISubPicProvider * pSubPicProvider) PURE; - STDMETHOD_(void, Invalidate)(REFERENCE_TIME rtInvalidate = -1) PURE; - - STDMETHOD(GetDIB)(BYTE * lpDib, DWORD * size) PURE; - STDMETHOD (GetDisplayedImage) (LPVOID* dibImage) PURE; - - STDMETHOD(SetVideoAngle)(Vector v) PURE; - STDMETHOD(SetPixelShader)(LPCSTR pSrcData, LPCSTR pTarget) PURE; - - STDMETHOD_(bool, ResetDevice)() PURE; - STDMETHOD_(bool, DisplayChange)() PURE; - - STDMETHOD_(void, GetPosition)(RECT* windowRect, RECT* videoRect) PURE; - - STDMETHOD_(void, SetVideoMediaType)(CMediaType input) PURE; -}; - -interface __declspec(uuid("767AEBA8-A084-488a-89C8-F6B74E53A90F")) -ISubPicAllocatorPresenter2 : -public ISubPicAllocatorPresenter { - STDMETHOD(SetPixelShader2)(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) PURE; - STDMETHOD_(SIZE, GetVisibleVideoSize)() const PURE; - - STDMETHOD_(bool, IsRendering)() PURE; - STDMETHOD(SetIsRendering)(bool bIsRendering) PURE; - - STDMETHOD(SetDefaultVideoAngle)(Vector v) PURE; -}; - - -interface __declspec(uuid("AD863F43-83F9-4B8E-962C-426F2BDBEAEF")) -ISubPicAllocatorPresenter3 : -public ISubPicAllocatorPresenter2 { - STDMETHOD (SetRotation) (int rotation) PURE; - STDMETHOD_(int, GetRotation) () PURE; - STDMETHOD (SetFlip) (bool flip) PURE; - STDMETHOD_(bool, GetFlip) () PURE; - STDMETHOD (GetVideoFrame) (BYTE* lpDib, DWORD* size) PURE; - STDMETHOD_(int, GetPixelShaderMode) () PURE; - STDMETHOD (ClearPixelShaders) (int target) PURE; - STDMETHOD (AddPixelShader) (int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) PURE; - STDMETHOD_(bool, ResizeDevice) () PURE; - STDMETHOD_(bool, ToggleStats) () PURE; -}; - -// -// ISubStream -// - -interface __declspec(uuid("DE11E2FB-02D3-45e4-A174-6B7CE2783BDB")) -ISubStream : -public IPersist { - STDMETHOD_(int, GetStreamCount)() PURE; - STDMETHOD(GetStreamInfo)(int i, WCHAR** ppName, LCID * pLCID) PURE; - STDMETHOD_(int, GetStream)() PURE; - STDMETHOD(SetStream)(int iStream) PURE; - STDMETHOD(Reload)() PURE; - STDMETHOD(SetSourceTargetInfo)(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) PURE; - virtual CString GetPath() { return _T(""); } - - // TODO: get rid of IPersist to identify type and use only - // interface functions to modify the settings of the substream -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#pragma once + +#include +#include +#include "CoordGeom.h" +#include "strmif.h" + +// to force rendering subs at a specific size +#define DEBUG_OVERRIDE_TEXTURE_SIZE 0 +#define DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH 2560 +#define DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT 1440 + +#pragma pack(push, 1) +struct SubPicDesc { + int type; + int w, h, bpp, pitch, pitchUV; + BYTE* bits; + BYTE* bitsU; + BYTE* bitsV; + RECT vidrect; // video rectangle + + SubPicDesc() + : type(0) + , w(0) + , h(0) + , bpp(0) + , pitch(0) + , pitchUV(0) + , bits(nullptr) + , bitsU(nullptr) + , bitsV(nullptr) { + ZeroMemory(&vidrect, sizeof(vidrect)); + } +}; +#pragma pack(pop) + +enum RelativeTo { + WINDOW, + VIDEO, + BEST_FIT +}; + +// +// ISubPic +// + +interface __declspec(uuid("DA3A5B51-958C-4C28-BF66-68D7947577A2")) +ISubPic : +public IUnknown { + static const REFERENCE_TIME INVALID_SUBPIC_TIME = -1; + + STDMETHOD_(void*, GetObject)() PURE; + + STDMETHOD_(REFERENCE_TIME, GetStart)() const PURE; + STDMETHOD_(REFERENCE_TIME, GetStop)() const PURE; + STDMETHOD_(void, SetStart)(REFERENCE_TIME rtStart) PURE; + STDMETHOD_(void, SetStop)(REFERENCE_TIME rtStop) PURE; + + STDMETHOD(GetDesc)(SubPicDesc& spd /*[out]*/) PURE; + STDMETHOD(CopyTo)(ISubPic* pSubPic /*[in]*/) PURE; + + STDMETHOD(ClearDirtyRect)() PURE; + STDMETHOD(GetDirtyRect)(RECT* pDirtyRect /*[out]*/) const PURE; + STDMETHOD(SetDirtyRect)(const RECT* pDirtyRect /*[in]*/) PURE; + + STDMETHOD(GetMaxSize)(SIZE* pMaxSize /*[out]*/) const PURE; + STDMETHOD(SetSize)(SIZE pSize /*[in]*/, RECT vidrect /*[in]*/) PURE; + + STDMETHOD(Lock)(SubPicDesc& spd /*[out]*/) PURE; + STDMETHOD(Unlock)(RECT* pDirtyRect /*[in]*/) PURE; + + STDMETHOD(AlphaBlt)(RECT * pSrc, RECT * pDst, SubPicDesc* pTarget = nullptr /*[in]*/) PURE; + STDMETHOD(GetSourceAndDest)(RECT rcWindow /*[in]*/, RECT rcVideo /*[in]*/, + RECT* pRcSource /*[out]*/, RECT* pRcDest /*[out]*/, + const double videoStretchFactor = 1.0 /*[in]*/, + int xOffsetInPixels = 0 /*[in]*/, int yOffsetInPixels = 0 /*[in]*/) const PURE; + STDMETHOD(SetVirtualTextureSize)(const SIZE pSize, const POINT pTopLeft) PURE; + STDMETHOD(GetRelativeTo)(RelativeTo* pRelativeTo /*[out]*/) const PURE; + STDMETHOD(SetRelativeTo)(RelativeTo relativeTo /*[in]*/) PURE; + + STDMETHOD_(REFERENCE_TIME, GetSegmentStart)() const PURE; + STDMETHOD_(REFERENCE_TIME, GetSegmentStop)() const PURE; + STDMETHOD_(void, SetSegmentStart)(REFERENCE_TIME rtStart) PURE; + STDMETHOD_(void, SetSegmentStop)(REFERENCE_TIME rtStop) PURE; + + STDMETHOD_(void, SetInverseAlpha)(bool bInverted) PURE; +}; + +// +// ISubPicAllocator +// + +interface __declspec(uuid("CF7C3C23-6392-4a42-9E72-0736CFF793CB")) +ISubPicAllocator : +public IUnknown { + STDMETHOD(SetCurSize)(SIZE size /*[in]*/) PURE; + STDMETHOD(SetCurVidRect)(RECT curvidrect) PURE; + + STDMETHOD(GetStatic)(ISubPic** ppSubPic /*[out]*/) PURE; + STDMETHOD(AllocDynamic)(ISubPic** ppSubPic /*[out]*/) PURE; + + STDMETHOD_(bool, IsDynamicWriteOnly)() const PURE; + + STDMETHOD(ChangeDevice)(IUnknown * pDev) PURE; + STDMETHOD(SetMaxTextureSize)(SIZE maxTextureSize) PURE; + + STDMETHOD(FreeStatic)() PURE; + + STDMETHOD_(void, SetInverseAlpha)(bool bInverted) PURE; +}; + +// +// ISubPicProvider +// + +interface __declspec(uuid("D62B9A1A-879A-42db-AB04-88AA8F243CFD")) +ISubPicProvider : +public IUnknown { + static const REFERENCE_TIME UNKNOWN_TIME = _I64_MAX; + + STDMETHOD(Lock)() PURE; + STDMETHOD(Unlock)() PURE; + + STDMETHOD_(POSITION, GetStartPosition)(REFERENCE_TIME rt, double fps) PURE; + STDMETHOD_(POSITION, GetNext)(POSITION pos) PURE; + + STDMETHOD_(REFERENCE_TIME, GetStart)(POSITION pos, double fps) PURE; + STDMETHOD_(REFERENCE_TIME, GetStop)(POSITION pos, double fps) PURE; + + STDMETHOD_(bool, IsAnimated)(POSITION pos) PURE; + + STDMETHOD(Render)(SubPicDesc & spd, REFERENCE_TIME rt, double fps, RECT & bbox) PURE; + STDMETHOD(GetTextureSize)(POSITION pos, SIZE & MaxTextureSize, SIZE & VirtualSize, POINT & VirtualTopLeft) PURE; + STDMETHOD(GetRelativeTo)(POSITION pos, RelativeTo & relativeTo) PURE; +}; + +// +// ISubPicQueue +// + +interface __declspec(uuid("C8334466-CD1E-4ad1-9D2D-8EE8519BD180")) +ISubPicQueue : +public IUnknown { + STDMETHOD(SetSubPicProvider)(ISubPicProvider* pSubPicProvider /*[in]*/) PURE; + STDMETHOD(GetSubPicProvider)(ISubPicProvider** pSubPicProvider /*[out]*/) PURE; + + STDMETHOD(SetFPS)(double fps /*[in]*/) PURE; + STDMETHOD(SetTime)(REFERENCE_TIME rtNow /*[in]*/) PURE; + + STDMETHOD(Invalidate)(REFERENCE_TIME rtInvalidate = -1) PURE; + STDMETHOD_(bool, LookupSubPic)(REFERENCE_TIME rtNow /*[in]*/, CComPtr& pSubPic /*[out]*/) PURE; + + STDMETHOD(GetStats)(int& nSubPics, REFERENCE_TIME & rtNow, REFERENCE_TIME & rtStart, REFERENCE_TIME& rtStop /*[out]*/) PURE; + STDMETHOD(GetStats)(int nSubPic /*[in]*/, REFERENCE_TIME & rtStart, REFERENCE_TIME& rtStop /*[out]*/) PURE; + + STDMETHOD_(bool, LookupSubPic)(REFERENCE_TIME rtNow /*[in]*/, bool bAdviseBlocking, CComPtr& pSubPic /*[out]*/) PURE; +}; + +// +// ISubPicAllocatorPresenter +// +#define TARGET_FRAME 0 +#define TARGET_SCREEN 1 + +interface __declspec(uuid("CF75B1F0-535C-4074-8869-B15F177F944E")) +ISubPicAllocatorPresenter : +public IUnknown { + STDMETHOD(CreateRenderer)(IUnknown** ppRenderer) PURE; + + STDMETHOD_(SIZE, GetVideoSize)(bool bCorrectAR) const PURE; + STDMETHOD_(void, SetPosition)(RECT w, RECT v) PURE; + STDMETHOD_(bool, Paint)(bool bAll) PURE; + + STDMETHOD_(void, SetTime)(REFERENCE_TIME rtNow) PURE; + STDMETHOD_(void, SetSubtitleDelay)(int delayMs) PURE; + STDMETHOD_(int, GetSubtitleDelay)() const PURE; + STDMETHOD_(double, GetFPS)() const PURE; + + STDMETHOD_(void, SetSubPicProvider)(ISubPicProvider * pSubPicProvider) PURE; + STDMETHOD_(void, Invalidate)(REFERENCE_TIME rtInvalidate = -1) PURE; + + STDMETHOD(GetDIB)(BYTE * lpDib, DWORD * size) PURE; + STDMETHOD (GetDisplayedImage) (LPVOID* dibImage) PURE; + + STDMETHOD(SetVideoAngle)(Vector v) PURE; + STDMETHOD(SetPixelShader)(LPCSTR pSrcData, LPCSTR pTarget) PURE; + + STDMETHOD_(bool, ResetDevice)() PURE; + STDMETHOD_(bool, DisplayChange)() PURE; + + STDMETHOD_(void, GetPosition)(RECT* windowRect, RECT* videoRect) PURE; + + STDMETHOD_(void, SetVideoMediaType)(CMediaType input) PURE; +}; + +interface __declspec(uuid("767AEBA8-A084-488a-89C8-F6B74E53A90F")) +ISubPicAllocatorPresenter2 : +public ISubPicAllocatorPresenter { + STDMETHOD(SetPixelShader2)(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) PURE; + STDMETHOD_(SIZE, GetVisibleVideoSize)() const PURE; + + STDMETHOD_(bool, IsRendering)() PURE; + STDMETHOD(SetIsRendering)(bool bIsRendering) PURE; + + STDMETHOD(SetDefaultVideoAngle)(Vector v) PURE; +}; + + +interface __declspec(uuid("AD863F43-83F9-4B8E-962C-426F2BDBEAEF")) +ISubPicAllocatorPresenter3 : +public ISubPicAllocatorPresenter2 { + STDMETHOD (SetRotation) (int rotation) PURE; + STDMETHOD_(int, GetRotation) () PURE; + STDMETHOD (SetFlip) (bool flip) PURE; + STDMETHOD_(bool, GetFlip) () PURE; + STDMETHOD (GetVideoFrame) (BYTE* lpDib, DWORD* size) PURE; + STDMETHOD_(int, GetPixelShaderMode) () PURE; + STDMETHOD (ClearPixelShaders) (int target) PURE; + STDMETHOD (AddPixelShader) (int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) PURE; + STDMETHOD_(bool, ResizeDevice) () PURE; + STDMETHOD_(bool, ToggleStats) () PURE; +}; + +// +// ISubStream +// + +interface __declspec(uuid("DE11E2FB-02D3-45e4-A174-6B7CE2783BDB")) +ISubStream : +public IPersist { + STDMETHOD_(int, GetStreamCount)() PURE; + STDMETHOD(GetStreamInfo)(int i, WCHAR** ppName, LCID * pLCID) PURE; + STDMETHOD_(int, GetStream)() PURE; + STDMETHOD(SetStream)(int iStream) PURE; + STDMETHOD(Reload)() PURE; + STDMETHOD(SetSourceTargetInfo)(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) PURE; + virtual CString GetPath() { return _T(""); } + + // TODO: get rid of IPersist to identify type and use only + // interface functions to modify the settings of the substream +}; diff --git a/src/SubPic/ISubRender.h b/src/SubPic/ISubRender.h index f4cafc6c469..210a897eccf 100644 --- a/src/SubPic/ISubRender.h +++ b/src/SubPic/ISubRender.h @@ -1,73 +1,73 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2022 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 . - * - */ - -#pragma once - -#include -#include - -interface IDirect3DDevice9; - -DECLARE_INTERFACE_IID_(ISubRenderCallback, IUnknown, "CD6D2AA5-20D3-4ebe-A8A9-34D3B00CC253") -{ - // NULL means release current device, textures and other resources - STDMETHOD(SetDevice)(IDirect3DDevice9* dev) PURE; - - // destination video rectangle, will be inside (0, 0)-(width, height) - // width,height is the size of the entire output window - STDMETHOD(Render)(REFERENCE_TIME rtStart, - int left, int top, int right, int bottom, - int width, int height) PURE; -}; - - -DECLARE_INTERFACE_IID_(ISubRenderCallback2, ISubRenderCallback, "E602585E-C05A-4828-AC69-AF92997F2E0C") -{ - STDMETHOD(RenderEx)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME avgTimePerFrame, - int left, int top, int right, int bottom, - int width, int height) PURE; -}; - -DECLARE_INTERFACE_IID_(ISubRenderCallback3, ISubRenderCallback2, "BAC4273A-3EAD-47F5-9710-8488E52AC618") -{ - STDMETHOD(RenderEx2)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME avgTimePerFrame, RECT croppedVideoRect, - RECT originalVideoRect, RECT viewportRect, - const double videoStretchFactor = 1.0) PURE; -}; - -// const static DWORD SUBRENDER_LEFT_EYE = 1; -// const static DWORD SUBRENDER_RIGHT_EYE = 2; - -DECLARE_INTERFACE_IID_(ISubRenderCallback4, ISubRenderCallback3, "C89CF1D4-29C5-4A96-8AAC-528EC6F7AF1E") -{ - STDMETHOD(RenderEx3)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME avgTimePerFrame, RECT croppedVideoRect, - RECT originalVideoRect, RECT viewportRect, - const double videoStretchFactor = 1.0, - int xOffsetInPixels = 0, DWORD flags = 0) PURE; -}; - -DECLARE_INTERFACE_IID_(ISubRender, IUnknown, "9CC7F9F7-3ED1-493c-AF65-527EA1D9947F") -{ - STDMETHOD(SetCallback)(ISubRenderCallback* cb) PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2022 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 . + * + */ + +#pragma once + +#include +#include + +interface IDirect3DDevice9; + +DECLARE_INTERFACE_IID_(ISubRenderCallback, IUnknown, "CD6D2AA5-20D3-4ebe-A8A9-34D3B00CC253") +{ + // NULL means release current device, textures and other resources + STDMETHOD(SetDevice)(IDirect3DDevice9* dev) PURE; + + // destination video rectangle, will be inside (0, 0)-(width, height) + // width,height is the size of the entire output window + STDMETHOD(Render)(REFERENCE_TIME rtStart, + int left, int top, int right, int bottom, + int width, int height) PURE; +}; + + +DECLARE_INTERFACE_IID_(ISubRenderCallback2, ISubRenderCallback, "E602585E-C05A-4828-AC69-AF92997F2E0C") +{ + STDMETHOD(RenderEx)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME avgTimePerFrame, + int left, int top, int right, int bottom, + int width, int height) PURE; +}; + +DECLARE_INTERFACE_IID_(ISubRenderCallback3, ISubRenderCallback2, "BAC4273A-3EAD-47F5-9710-8488E52AC618") +{ + STDMETHOD(RenderEx2)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME avgTimePerFrame, RECT croppedVideoRect, + RECT originalVideoRect, RECT viewportRect, + const double videoStretchFactor = 1.0) PURE; +}; + +// const static DWORD SUBRENDER_LEFT_EYE = 1; +// const static DWORD SUBRENDER_RIGHT_EYE = 2; + +DECLARE_INTERFACE_IID_(ISubRenderCallback4, ISubRenderCallback3, "C89CF1D4-29C5-4A96-8AAC-528EC6F7AF1E") +{ + STDMETHOD(RenderEx3)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME avgTimePerFrame, RECT croppedVideoRect, + RECT originalVideoRect, RECT viewportRect, + const double videoStretchFactor = 1.0, + int xOffsetInPixels = 0, DWORD flags = 0) PURE; +}; + +DECLARE_INTERFACE_IID_(ISubRender, IUnknown, "9CC7F9F7-3ED1-493c-AF65-527EA1D9947F") +{ + STDMETHOD(SetCallback)(ISubRenderCallback* cb) PURE; +}; diff --git a/src/SubPic/MemSubPic.cpp b/src/SubPic/MemSubPic.cpp index 43042223fd8..e54266b4ee0 100644 --- a/src/SubPic/MemSubPic.cpp +++ b/src/SubPic/MemSubPic.cpp @@ -1,781 +1,781 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include "MemSubPic.h" - -#include -#include "stb/stb_image.h" -#include "stb/stb_image_resize2.h" - -// color conv - -static unsigned char clipBase[256 * 3]; -static unsigned char* clip = clipBase + 256; - -static const int c2y_cyb = std::lround(0.114 * 219 / 255 * 65536); -static const int c2y_cyg = std::lround(0.587 * 219 / 255 * 65536); -static const int c2y_cyr = std::lround(0.299 * 219 / 255 * 65536); -static const int c2y_cu = std::lround(1.0 / 2.018 * 1024); -static const int c2y_cv = std::lround(1.0 / 1.596 * 1024); - -int c2y_yb[256]; -int c2y_yg[256]; -int c2y_yr[256]; - -static const int y2c_cbu = std::lround(2.018 * 65536); -static const int y2c_cgu = std::lround(0.391 * 65536); -static const int y2c_cgv = std::lround(0.813 * 65536); -static const int y2c_crv = std::lround(1.596 * 65536); -static int y2c_bu[256]; -static int y2c_gu[256]; -static int y2c_gv[256]; -static int y2c_rv[256]; - -static const int cy_cy = std::lround(255.0 / 219.0 * 65536); -static const int cy_cy2 = std::lround(255.0 / 219.0 * 32768); - -void ColorConvInit() -{ - static bool bColorConvInitOK = false; - if (bColorConvInitOK) { - return; - } - - for (int i = 0; i < 256; i++) { - clipBase[i] = 0; - clipBase[i + 256] = BYTE(i); - clipBase[i + 512] = 255; - } - - for (int i = 0; i < 256; i++) { - c2y_yb[i] = c2y_cyb * i; - c2y_yg[i] = c2y_cyg * i; - c2y_yr[i] = c2y_cyr * i; - - y2c_bu[i] = y2c_cbu * (i - 128); - y2c_gu[i] = y2c_cgu * (i - 128); - y2c_gv[i] = y2c_cgv * (i - 128); - y2c_rv[i] = y2c_crv * (i - 128); - } - - bColorConvInitOK = true; -} - -// -// CMemSubPic -// - -CMemSubPic::CMemSubPic(const SubPicDesc& spd, CMemSubPicAllocator* pAllocator) - : m_pAllocator(pAllocator) - , m_spd(spd) -{ - m_maxsize.SetSize(spd.w, spd.h); - m_rcDirty.SetRect(0, 0, spd.w, spd.h); -} - -CMemSubPic::~CMemSubPic() -{ - m_pAllocator->FreeSpdBits(m_spd); - if (m_resizedSpd) { - m_pAllocator->FreeSpdBits(*m_resizedSpd); - } -} - -// ISubPic - -STDMETHODIMP_(void*) CMemSubPic::GetObject() -{ - return (void*)&m_spd; -} - -STDMETHODIMP CMemSubPic::GetDesc(SubPicDesc& spd) -{ - spd.type = m_spd.type; - spd.w = m_spd.w; - spd.h = m_spd.h; - spd.bpp = m_spd.bpp; - spd.pitch = m_spd.pitch; - spd.bits = m_spd.bits; - spd.bitsU = m_spd.bitsU; - spd.bitsV = m_spd.bitsV; - spd.vidrect = m_vidrect; - - return S_OK; -} - -STDMETHODIMP CMemSubPic::CopyTo(ISubPic* pSubPic) -{ - HRESULT hr; - if (FAILED(hr = __super::CopyTo(pSubPic))) { - return hr; - } - - SubPicDesc src, dst; - if (FAILED(GetDesc(src)) || FAILED(pSubPic->GetDesc(dst))) { - return E_FAIL; - } - - if (auto subPic = dynamic_cast(pSubPic)) { - ASSERT(subPic->m_pAllocator == m_pAllocator); - ASSERT(subPic->m_resizedSpd == nullptr); - // Move because we are not going to reuse it. - subPic->m_resizedSpd = std::move(m_resizedSpd); - } - - int w = m_rcDirty.Width(), h = m_rcDirty.Height(); - BYTE* s = src.bits + src.pitch * m_rcDirty.top + m_rcDirty.left * 4; - BYTE* d = dst.bits + dst.pitch * m_rcDirty.top + m_rcDirty.left * 4; - - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - memcpy(d, s, w * 4); - } - - return S_OK; -} - -STDMETHODIMP CMemSubPic::ClearDirtyRect() -{ - if (m_rcDirty.IsRectEmpty()) { - return S_FALSE; - } - - DWORD color = m_bInvAlpha ? 0x00000000 : 0xFF000000; - - BYTE* p = m_spd.bits + m_spd.pitch * m_rcDirty.top + m_rcDirty.left * (m_spd.bpp >> 3); - for (ptrdiff_t j = 0, h = m_rcDirty.Height(); j < h; j++, p += m_spd.pitch) { - int w = m_rcDirty.Width(); -#ifdef _WIN64 - memsetd(p, color, w * 4); // nya -#else - __asm { - mov eax, color - mov ecx, w - mov edi, p - cld - rep stosd - } -#endif - } - - m_rcDirty.SetRectEmpty(); - - return S_OK; -} - -STDMETHODIMP CMemSubPic::Lock(SubPicDesc& spd) -{ - return GetDesc(spd); -} - -HRESULT CMemSubPic::UnlockARGB() { //derived from Unlock(), supports ARGB - m_rcDirty = CRect(0, 0, m_spd.w, m_spd.h); - - if (m_rcDirty.IsRectEmpty()) { - return S_OK; - } - - if (m_spd.bpp != 32 || m_spd.type != MSP_RGB32) { - return E_INVALIDARG; - } - - CRect r = m_spd.vidrect; - CRect rcDirty = m_rcDirty; - if (m_spd.h != r.Height() || m_spd.w != r.Width()) { - if (!m_resizedSpd) { - m_resizedSpd = std::unique_ptr(DEBUG_NEW SubPicDesc); - } - - m_resizedSpd->type = m_spd.type; - m_resizedSpd->w = r.Width(); - m_resizedSpd->h = r.Height(); - m_resizedSpd->pitch = r.Width() * 4; - m_resizedSpd->bpp = m_spd.bpp; - m_resizedSpd->vidrect = { 0,0,r.Width(),r.Height() }; - - if (!m_resizedSpd->bits) { - m_pAllocator->AllocSpdBits(*m_resizedSpd); - } - - auto& s = m_spd; - auto& d = *m_resizedSpd; - stbir_resize(s.bits, s.w, s.h, s.pitch, d.bits, d.w, d.h, d.pitch, STBIR_RGBA_PM, STBIR_TYPE_UINT8_SRGB, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT); - TRACE("CMemSubPic: Resized SubPic %dx%d -> %dx%d\n", m_spd.w, m_spd.h, r.Width(), r.Height()); - - // Set whole resized spd as dirty, we are not going to reuse it. - rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); - } - else if (m_resizedSpd) { - // Resize is not needed so release m_resizedSpd. - m_pAllocator->FreeSpdBits(*m_resizedSpd); - m_resizedSpd = nullptr; - } - - if (!m_resizedSpd) { - m_rcDirty = rcDirty; - } - - return S_OK; -} - - -STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) -{ - m_rcDirty = pDirtyRect ? *pDirtyRect : CRect(0, 0, m_spd.w, m_spd.h); - - if (m_rcDirty.IsRectEmpty()) { - return S_OK; - } - - CRect r = m_spd.vidrect; - CRect rcDirty = m_rcDirty; - if (m_spd.h != r.Height() || m_spd.w != r.Width()) { - if (!m_resizedSpd) { - m_resizedSpd = std::unique_ptr(DEBUG_NEW SubPicDesc); - } - - m_resizedSpd->type = m_spd.type; - m_resizedSpd->w = r.Width(); - m_resizedSpd->h = r.Height(); - m_resizedSpd->pitch = r.Width() * 4; - m_resizedSpd->bpp = m_spd.bpp; - - if (!m_resizedSpd->bits) { - m_pAllocator->AllocSpdBits(*m_resizedSpd); - } - - BitBltFromRGBToRGBStretch(m_resizedSpd->w, m_resizedSpd->h, m_resizedSpd->bits, m_resizedSpd->pitch, m_resizedSpd->bpp - , m_spd.w, m_spd.h, m_spd.bits, m_spd.pitch, m_spd.bpp); - TRACE("CMemSubPic: Resized SubPic %dx%d -> %dx%d\n", m_spd.w, m_spd.h, r.Width(), r.Height()); - - // Set whole resized spd as dirty, we are not going to reuse it. - rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); - } else if (m_resizedSpd) { - // Resize is not needed so release m_resizedSpd. - m_pAllocator->FreeSpdBits(*m_resizedSpd); - m_resizedSpd = nullptr; - } - - const SubPicDesc& subPic = m_resizedSpd ? *m_resizedSpd : m_spd; - - if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV || subPic.type == MSP_AYUV) { - ColorConvInit(); - - if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { - rcDirty.left &= ~1; - rcDirty.right = (rcDirty.right + 1) & ~1; - - if (subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { - rcDirty.top &= ~1; - rcDirty.bottom = (rcDirty.bottom + 1) & ~1; - } - } - } - - if (!m_resizedSpd) { - m_rcDirty = rcDirty; - } - - int w = rcDirty.Width(), h = rcDirty.Height(); - BYTE* top = subPic.bits + subPic.pitch * rcDirty.top + rcDirty.left * 4; - BYTE* bottom = top + subPic.pitch * h; - - if (subPic.type == MSP_RGB16) { - for (; top < bottom ; top += subPic.pitch) { - DWORD* s = (DWORD*)top; - DWORD* e = s + w; - for (; s < e; s++) { - *s = ((*s >> 3) & 0x1f000000) | ((*s >> 8) & 0xf800) | ((*s >> 5) & 0x07e0) | ((*s >> 3) & 0x001f); - //*s = (*s&0xff000000)|((*s>>8)&0xf800)|((*s>>5)&0x07e0)|((*s>>3)&0x001f); - } - } - } else if (subPic.type == MSP_RGB15) { - for (; top < bottom; top += subPic.pitch) { - DWORD* s = (DWORD*)top; - DWORD* e = s + w; - for (; s < e; s++) { - *s = ((*s >> 3) & 0x1f000000) | ((*s >> 9) & 0x7c00) | ((*s >> 6) & 0x03e0) | ((*s >> 3) & 0x001f); - //*s = (*s&0xff000000)|((*s>>9)&0x7c00)|((*s>>6)&0x03e0)|((*s>>3)&0x001f); - } - } - } else if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { - for (; top < bottom ; top += subPic.pitch) { - BYTE* s = top; - BYTE* e = s + w * 4; - for (; s < e; s += 8) { // ARGB ARGB -> AxYU AxYV - if ((s[3] + s[7]) < 0x1fe) { - s[1] = BYTE((c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16); - s[5] = BYTE((c2y_yb[s[4]] + c2y_yg[s[5]] + c2y_yr[s[6]] + 0x108000) >> 16); - - int scaled_y = (s[1] + s[5] - 32) * cy_cy2; - - s[0] = clip[(((((s[0] + s[4]) << 15) - scaled_y) >> 10) * c2y_cu + 0x800000 + 0x8000) >> 16]; - s[4] = clip[(((((s[2] + s[6]) << 15) - scaled_y) >> 10) * c2y_cv + 0x800000 + 0x8000) >> 16]; - } else { - s[1] = s[5] = 0x10; - s[0] = s[4] = 0x80; - } - } - } - } else if (subPic.type == MSP_AYUV) { - for (; top < bottom ; top += subPic.pitch) { - BYTE* s = top; - BYTE* e = s + w * 4; - - for (; s < e; s += 4) { // ARGB -> AYUV - if (s[3] < 0xff) { - auto y = BYTE((c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16); - int scaled_y = (y - 32) * cy_cy; - s[1] = clip[((((s[0] << 16) - scaled_y) >> 10) * c2y_cu + 0x800000 + 0x8000) >> 16]; - s[0] = clip[((((s[2] << 16) - scaled_y) >> 10) * c2y_cv + 0x800000 + 0x8000) >> 16]; - s[2] = y; - } else { - s[0] = s[1] = 0x80; - s[2] = 0x10; - } - } - } - } - - return S_OK; -} - -#ifdef _WIN64 -void AlphaBlt_YUY2_SSE2(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) -{ - unsigned int ia; - static const __int64 _8181 = 0x0080001000800010i64; - - for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { - DWORD* d2 = (DWORD*)d; - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - - for (; s2 < s2end; s2 += 8, d2++) { - ia = (s2[3] + s2[7]) >> 1; - if (ia < 0xff) { - unsigned int c = (s2[4] << 24) | (s2[5] << 16) | (s2[0] << 8) | s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; - - ia = (ia << 24) | (s2[7] << 16) | (ia << 8) | s2[3]; - // SSE2 - __m128i mm_zero = _mm_setzero_si128(); - __m128i mm_8181 = _mm_move_epi64(_mm_cvtsi64_si128(_8181)); - __m128i mm_c = _mm_cvtsi32_si128(c); - mm_c = _mm_unpacklo_epi8(mm_c, mm_zero); - __m128i mm_d = _mm_cvtsi32_si128(*d2); - mm_d = _mm_unpacklo_epi8(mm_d, mm_zero); - __m128i mm_a = _mm_cvtsi32_si128(ia); - mm_a = _mm_unpacklo_epi8(mm_a, mm_zero); - mm_a = _mm_srli_epi16(mm_a, 1); - mm_d = _mm_sub_epi16(mm_d, mm_8181); - mm_d = _mm_mullo_epi16(mm_d, mm_a); - mm_d = _mm_srai_epi16(mm_d, 7); - mm_d = _mm_adds_epi16(mm_d, mm_c); - mm_d = _mm_packus_epi16(mm_d, mm_d); - *d2 = (DWORD)_mm_cvtsi128_si32(mm_d); - } - } - } -} - -#else - -void AlphaBlt_YUY2_MMX(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) -{ - unsigned int ia; - static const __int64 _8181 = 0x0080001000800010i64; - - for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { - DWORD* d2 = (DWORD*)d; - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - - for (; s2 < s2end; s2 += 8, d2++) { - ia = (s2[3] + s2[7]) >> 1; - if (ia < 0xff) { - unsigned int c = (s2[4] << 24) | (s2[5] << 16) | (s2[0] << 8) | s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; - ia = (ia << 24) | (s2[7] << 16) | (ia << 8) | s2[3]; - __asm { - mov esi, s2 - mov edi, d2 - pxor mm0, mm0 - movq mm1, _8181 - movd mm2, c - punpcklbw mm2, mm0 - movd mm3, [edi] - punpcklbw mm3, mm0 - movd mm4, ia - punpcklbw mm4, mm0 - psrlw mm4, 1 - psubsw mm3, mm1 - pmullw mm3, mm4 - psraw mm3, 7 - paddsw mm3, mm2 - packuswb mm3, mm3 - movd [edi], mm3 - }; - } - } - } - _mm_empty(); -} -#endif - -void AlphaBlt_YUY2_C(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) -{ - unsigned int ia; - - for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { - DWORD* d2 = (DWORD*)d; - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - - for (; s2 < s2end; s2 += 8, d2++) { - ia = (s2[3] + s2[7]) >> 1; - if (ia < 0xff) { - //unsigned int c = (s2[4]<<24)|(s2[5]<<16)|(s2[0]<<8)|s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; - - // YUY2 colorspace fix. rewritten from sse2 asm - DWORD y1 = (DWORD)(((((*d2 & 0xff) - 0x10) * (s2[3] >> 1)) >> 7) + s2[1]) & 0xff; // y1 - DWORD uu = (DWORD)((((((*d2 >> 8) & 0xff) - 0x80) * (ia >> 1)) >> 7) + s2[0]) & 0xff; // u - DWORD y2 = (DWORD)((((((*d2 >> 16) & 0xff) - 0x10) * (s2[7] >> 1)) >> 7) + s2[5]) & 0xff; // y2 - DWORD vv = (DWORD)((((((*d2 >> 24) & 0xff) - 0x80) * (ia >> 1)) >> 7) + s2[4]) & 0xff; // v - *d2 = (y1) | (uu << 8) | (y2 << 16) | (vv << 24); - } - } - } -} - -STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) -{ - ASSERT(pTarget); - - if (!pSrc || !pDst || !pTarget) { - return E_POINTER; - } - - const SubPicDesc& src = m_resizedSpd ? *m_resizedSpd : m_spd; - SubPicDesc dst = *pTarget; // copy, because we might modify it - - if (src.type != dst.type) { - return E_INVALIDARG; - } - - CRect rs(*pSrc), rd(*pDst); - - if (m_resizedSpd) { - rs = rd = CRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); - } - - if (dst.h < 0) { - dst.h = -dst.h; - rd.bottom = dst.h - rd.bottom; - rd.top = dst.h - rd.top; - } - - if (rs.Width() != rd.Width() || rs.Height() != abs(rd.Height())) { - return E_INVALIDARG; - } - - int w = rs.Width(), h = rs.Height(); - BYTE* s = src.bits + src.pitch * rs.top + rs.left * 4; - BYTE* d = dst.bits + dst.pitch * rd.top + ((rd.left * dst.bpp) >> 3); - - if (rd.top > rd.bottom) { - if (dst.type == MSP_RGB32 || dst.type == MSP_RGB24 - || dst.type == MSP_RGB16 || dst.type == MSP_RGB15 - || dst.type == MSP_YUY2 || dst.type == MSP_AYUV) { - d = dst.bits + dst.pitch * (rd.top - 1) + (rd.left * dst.bpp >> 3); - } else if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) { - d = dst.bits + dst.pitch * (rd.top - 1) + (rd.left * 8 >> 3); - } else { - return E_NOTIMPL; - } - - dst.pitch = -dst.pitch; - } - - // TODO: m_bInvAlpha support - switch (dst.type) { - case MSP_RGBA: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - DWORD* d2 = (DWORD*)d; - for (; s2 < s2end; s2 += 4, d2++) { - if (s2[3] < 0xff) { - DWORD bd = 0x00000100 - ((DWORD) s2[3]); - DWORD B = ((*((DWORD*)s2) & 0x000000ff) << 8) / bd; - DWORD V = ((*((DWORD*)s2) & 0x0000ff00) / bd) << 8; - DWORD R = (((*((DWORD*)s2) & 0x00ff0000) >> 8) / bd) << 16; - *d2 = B | V | R - | (0xff000000 - (*((DWORD*)s2) & 0xff000000)) & 0xff000000; - } - } - } - break; - case MSP_RGB32: - case MSP_AYUV: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - DWORD* d2 = (DWORD*)d; - for (; s2 < s2end; s2 += 4, d2++) { -#ifdef _WIN64 - DWORD ia = 256 - s2[3]; - if (s2[3] < 0xff) { - *d2 = ((((*d2 & 0x00ff00ff) * s2[3]) >> 8) + (((*((DWORD*)s2) & 0x00ff00ff) * ia) >> 8) & 0x00ff00ff) - | ((((*d2 & 0x0000ff00) * s2[3]) >> 8) + (((*((DWORD*)s2) & 0x0000ff00) * ia) >> 8) & 0x0000ff00); - } -#else - if (s2[3] < 0xff) { - *d2 = ((((*d2 & 0x00ff00ff) * s2[3]) >> 8) + (*((DWORD*)s2) & 0x00ff00ff) & 0x00ff00ff) - | ((((*d2 & 0x0000ff00) * s2[3]) >> 8) + (*((DWORD*)s2) & 0x0000ff00) & 0x0000ff00); - } -#endif - } - } - break; - case MSP_RGB24: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - BYTE* d2 = d; - for (; s2 < s2end; s2 += 4, d2 += 3) { - if (s2[3] < 0xff) { - d2[0] = ((d2[0] * s2[3]) >> 8) + s2[0]; - d2[1] = ((d2[1] * s2[3]) >> 8) + s2[1]; - d2[2] = ((d2[2] * s2[3]) >> 8) + s2[2]; - } - } - } - break; - case MSP_RGB16: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - WORD* d2 = (WORD*)d; - for (; s2 < s2end; s2 += 4, d2++) { - if (s2[3] < 0x1f) { - *d2 = (WORD)((((((*d2 & 0xf81f) * s2[3]) >> 5) + (*(DWORD*)s2 & 0xf81f)) & 0xf81f) - | (((((*d2 & 0x07e0) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x07e0)) & 0x07e0)); - } - } - } - break; - case MSP_RGB15: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - WORD* d2 = (WORD*)d; - for (; s2 < s2end; s2 += 4, d2++) { - if (s2[3] < 0x1f) { - *d2 = (WORD)((((((*d2 & 0x7c1f) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x7c1f)) & 0x7c1f) - | (((((*d2 & 0x03e0) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x03e0)) & 0x03e0)); - } - } - } - break; - case MSP_YUY2: { -#ifdef _WIN64 - auto alphablt_func = AlphaBlt_YUY2_SSE2; -#else - auto alphablt_func = AlphaBlt_YUY2_MMX; -#endif - //alphablt_func = AlphaBlt_YUY2_C; - - alphablt_func(w, h, d, dst.pitch, s, src.pitch); - } - break; - case MSP_YV12: - case MSP_IYUV: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - BYTE* d2 = d; - for (; s2 < s2end; s2 += 4, d2++) { - if (s2[3] < 0xff) { - d2[0] = (((d2[0] - 0x10) * s2[3]) >> 8) + s2[1]; - } - } - } - break; - default: - return E_NOTIMPL; - } - - dst.pitch = abs(dst.pitch); - - if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) { - int h2 = h / 2; - - if (!dst.pitchUV) { - dst.pitchUV = dst.pitch / 2; - } - - BYTE* ss[2]; - ss[0] = src.bits + src.pitch * rs.top + rs.left * 4; - ss[1] = ss[0] + 4; - - if (!dst.bitsU || !dst.bitsV) { - dst.bitsU = dst.bits + dst.pitch * dst.h; - dst.bitsV = dst.bitsU + dst.pitchUV * dst.h / 2; - - if (dst.type == MSP_YV12) { - BYTE* p = dst.bitsU; - dst.bitsU = dst.bitsV; - dst.bitsV = p; - } - } - - BYTE* dd[2]; - dd[0] = dst.bitsU + dst.pitchUV * rd.top / 2 + rd.left / 2; - dd[1] = dst.bitsV + dst.pitchUV * rd.top / 2 + rd.left / 2; - - if (rd.top > rd.bottom) { - dd[0] = dst.bitsU + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; - dd[1] = dst.bitsV + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; - dst.pitchUV = -dst.pitchUV; - } - - for (ptrdiff_t i = 0; i < 2; i++) { - s = ss[i]; - d = dd[i]; - BYTE* is = ss[1 - i]; - for (ptrdiff_t j = 0; j < h2; j++, s += src.pitch * 2, d += dst.pitchUV, is += src.pitch * 2) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - BYTE* d2 = d; - BYTE* is2 = is; - for (; s2 < s2end; s2 += 8, d2++, is2 += 8) { - unsigned int ia = (s2[3] + s2[3 + src.pitch] + is2[3] + is2[3 + src.pitch]) >> 2; - if (ia < 0xff) { - *d2 = BYTE((((*d2 - 0x80) * ia) >> 8) + ((s2[0] + s2[src.pitch]) >> 1)); - } - } - } - } - } - - return S_OK; -} - -// -// CMemSubPicAllocator -// - -CMemSubPicAllocator::CMemSubPicAllocator(int type, SIZE maxsize) - : CSubPicAllocatorImpl(maxsize, false) - , m_type(type) - , m_maxsize(maxsize) -{ -} - -CMemSubPicAllocator::~CMemSubPicAllocator() -{ - CAutoLock cAutoLock(this); - - for (const auto& p : m_freeMemoryChunks) { - delete[] std::get<1>(p); - } -} - -// ISubPicAllocatorImpl - -bool CMemSubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) -{ - if (!ppSubPic || m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { - return false; - } - - SubPicDesc spd; - spd.w = m_maxsize.cx; - spd.h = m_maxsize.cy; - spd.bpp = 32; - spd.pitch = (spd.w * spd.bpp) >> 3; - spd.type = m_type; - spd.vidrect = m_curvidrect; - - if (!AllocSpdBits(spd)) { - return false; - } - - try { - *ppSubPic = DEBUG_NEW CMemSubPic(spd, this); - } catch (CMemoryException* e) { - e->Delete(); - delete [] spd.bits; - return false; - } - - (*ppSubPic)->AddRef(); - (*ppSubPic)->SetInverseAlpha(m_bInvAlpha); - - return true; -} - -bool CMemSubPicAllocator::AllocSpdBits(SubPicDesc& spd) -{ - CAutoLock cAutoLock(this); - - ASSERT(!spd.bits); - ASSERT(spd.pitch * spd.h > 0); - - auto it = std::find_if(m_freeMemoryChunks.cbegin(), m_freeMemoryChunks.cend(), [&](const std::pair& p) { - return std::get<0>(p) == size_t(spd.pitch) * spd.h; - }); - - if (it != m_freeMemoryChunks.cend()) { - spd.bits = std::get<1>(*it); - m_freeMemoryChunks.erase(it); - } else { - try { - spd.bits = DEBUG_NEW BYTE[spd.pitch * spd.h]; - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - return false; - } - } - return true; -} - -void CMemSubPicAllocator::FreeSpdBits(SubPicDesc& spd) -{ - CAutoLock cAutoLock(this); - - ASSERT(spd.bits); - m_freeMemoryChunks.emplace_back(spd.pitch * spd.h, spd.bits); - spd.bits = nullptr; -} - -STDMETHODIMP CMemSubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) -{ - if (maxTextureSize.cx > 0 && maxTextureSize.cy > 0 && m_maxsize != maxTextureSize) { - m_maxsize = maxTextureSize; - CAutoLock cAutoLock(this); - for (const auto& p : m_freeMemoryChunks) { - delete[] std::get<1>(p); - } - m_freeMemoryChunks.clear(); - } - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include "MemSubPic.h" + +#include +#include "stb/stb_image.h" +#include "stb/stb_image_resize2.h" + +// color conv + +static unsigned char clipBase[256 * 3]; +static unsigned char* clip = clipBase + 256; + +static const int c2y_cyb = std::lround(0.114 * 219 / 255 * 65536); +static const int c2y_cyg = std::lround(0.587 * 219 / 255 * 65536); +static const int c2y_cyr = std::lround(0.299 * 219 / 255 * 65536); +static const int c2y_cu = std::lround(1.0 / 2.018 * 1024); +static const int c2y_cv = std::lround(1.0 / 1.596 * 1024); + +int c2y_yb[256]; +int c2y_yg[256]; +int c2y_yr[256]; + +static const int y2c_cbu = std::lround(2.018 * 65536); +static const int y2c_cgu = std::lround(0.391 * 65536); +static const int y2c_cgv = std::lround(0.813 * 65536); +static const int y2c_crv = std::lround(1.596 * 65536); +static int y2c_bu[256]; +static int y2c_gu[256]; +static int y2c_gv[256]; +static int y2c_rv[256]; + +static const int cy_cy = std::lround(255.0 / 219.0 * 65536); +static const int cy_cy2 = std::lround(255.0 / 219.0 * 32768); + +void ColorConvInit() +{ + static bool bColorConvInitOK = false; + if (bColorConvInitOK) { + return; + } + + for (int i = 0; i < 256; i++) { + clipBase[i] = 0; + clipBase[i + 256] = BYTE(i); + clipBase[i + 512] = 255; + } + + for (int i = 0; i < 256; i++) { + c2y_yb[i] = c2y_cyb * i; + c2y_yg[i] = c2y_cyg * i; + c2y_yr[i] = c2y_cyr * i; + + y2c_bu[i] = y2c_cbu * (i - 128); + y2c_gu[i] = y2c_cgu * (i - 128); + y2c_gv[i] = y2c_cgv * (i - 128); + y2c_rv[i] = y2c_crv * (i - 128); + } + + bColorConvInitOK = true; +} + +// +// CMemSubPic +// + +CMemSubPic::CMemSubPic(const SubPicDesc& spd, CMemSubPicAllocator* pAllocator) + : m_pAllocator(pAllocator) + , m_spd(spd) +{ + m_maxsize.SetSize(spd.w, spd.h); + m_rcDirty.SetRect(0, 0, spd.w, spd.h); +} + +CMemSubPic::~CMemSubPic() +{ + m_pAllocator->FreeSpdBits(m_spd); + if (m_resizedSpd) { + m_pAllocator->FreeSpdBits(*m_resizedSpd); + } +} + +// ISubPic + +STDMETHODIMP_(void*) CMemSubPic::GetObject() +{ + return (void*)&m_spd; +} + +STDMETHODIMP CMemSubPic::GetDesc(SubPicDesc& spd) +{ + spd.type = m_spd.type; + spd.w = m_spd.w; + spd.h = m_spd.h; + spd.bpp = m_spd.bpp; + spd.pitch = m_spd.pitch; + spd.bits = m_spd.bits; + spd.bitsU = m_spd.bitsU; + spd.bitsV = m_spd.bitsV; + spd.vidrect = m_vidrect; + + return S_OK; +} + +STDMETHODIMP CMemSubPic::CopyTo(ISubPic* pSubPic) +{ + HRESULT hr; + if (FAILED(hr = __super::CopyTo(pSubPic))) { + return hr; + } + + SubPicDesc src, dst; + if (FAILED(GetDesc(src)) || FAILED(pSubPic->GetDesc(dst))) { + return E_FAIL; + } + + if (auto subPic = dynamic_cast(pSubPic)) { + ASSERT(subPic->m_pAllocator == m_pAllocator); + ASSERT(subPic->m_resizedSpd == nullptr); + // Move because we are not going to reuse it. + subPic->m_resizedSpd = std::move(m_resizedSpd); + } + + int w = m_rcDirty.Width(), h = m_rcDirty.Height(); + BYTE* s = src.bits + src.pitch * m_rcDirty.top + m_rcDirty.left * 4; + BYTE* d = dst.bits + dst.pitch * m_rcDirty.top + m_rcDirty.left * 4; + + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + memcpy(d, s, w * 4); + } + + return S_OK; +} + +STDMETHODIMP CMemSubPic::ClearDirtyRect() +{ + if (m_rcDirty.IsRectEmpty()) { + return S_FALSE; + } + + DWORD color = m_bInvAlpha ? 0x00000000 : 0xFF000000; + + BYTE* p = m_spd.bits + m_spd.pitch * m_rcDirty.top + m_rcDirty.left * (m_spd.bpp >> 3); + for (ptrdiff_t j = 0, h = m_rcDirty.Height(); j < h; j++, p += m_spd.pitch) { + int w = m_rcDirty.Width(); +#ifdef _WIN64 + memsetd(p, color, w * 4); // nya +#else + __asm { + mov eax, color + mov ecx, w + mov edi, p + cld + rep stosd + } +#endif + } + + m_rcDirty.SetRectEmpty(); + + return S_OK; +} + +STDMETHODIMP CMemSubPic::Lock(SubPicDesc& spd) +{ + return GetDesc(spd); +} + +HRESULT CMemSubPic::UnlockARGB() { //derived from Unlock(), supports ARGB + m_rcDirty = CRect(0, 0, m_spd.w, m_spd.h); + + if (m_rcDirty.IsRectEmpty()) { + return S_OK; + } + + if (m_spd.bpp != 32 || m_spd.type != MSP_RGB32) { + return E_INVALIDARG; + } + + CRect r = m_spd.vidrect; + CRect rcDirty = m_rcDirty; + if (m_spd.h != r.Height() || m_spd.w != r.Width()) { + if (!m_resizedSpd) { + m_resizedSpd = std::unique_ptr(DEBUG_NEW SubPicDesc); + } + + m_resizedSpd->type = m_spd.type; + m_resizedSpd->w = r.Width(); + m_resizedSpd->h = r.Height(); + m_resizedSpd->pitch = r.Width() * 4; + m_resizedSpd->bpp = m_spd.bpp; + m_resizedSpd->vidrect = { 0,0,r.Width(),r.Height() }; + + if (!m_resizedSpd->bits) { + m_pAllocator->AllocSpdBits(*m_resizedSpd); + } + + auto& s = m_spd; + auto& d = *m_resizedSpd; + stbir_resize(s.bits, s.w, s.h, s.pitch, d.bits, d.w, d.h, d.pitch, STBIR_RGBA_PM, STBIR_TYPE_UINT8_SRGB, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT); + TRACE("CMemSubPic: Resized SubPic %dx%d -> %dx%d\n", m_spd.w, m_spd.h, r.Width(), r.Height()); + + // Set whole resized spd as dirty, we are not going to reuse it. + rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); + } + else if (m_resizedSpd) { + // Resize is not needed so release m_resizedSpd. + m_pAllocator->FreeSpdBits(*m_resizedSpd); + m_resizedSpd = nullptr; + } + + if (!m_resizedSpd) { + m_rcDirty = rcDirty; + } + + return S_OK; +} + + +STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) +{ + m_rcDirty = pDirtyRect ? *pDirtyRect : CRect(0, 0, m_spd.w, m_spd.h); + + if (m_rcDirty.IsRectEmpty()) { + return S_OK; + } + + CRect r = m_spd.vidrect; + CRect rcDirty = m_rcDirty; + if (m_spd.h != r.Height() || m_spd.w != r.Width()) { + if (!m_resizedSpd) { + m_resizedSpd = std::unique_ptr(DEBUG_NEW SubPicDesc); + } + + m_resizedSpd->type = m_spd.type; + m_resizedSpd->w = r.Width(); + m_resizedSpd->h = r.Height(); + m_resizedSpd->pitch = r.Width() * 4; + m_resizedSpd->bpp = m_spd.bpp; + + if (!m_resizedSpd->bits) { + m_pAllocator->AllocSpdBits(*m_resizedSpd); + } + + BitBltFromRGBToRGBStretch(m_resizedSpd->w, m_resizedSpd->h, m_resizedSpd->bits, m_resizedSpd->pitch, m_resizedSpd->bpp + , m_spd.w, m_spd.h, m_spd.bits, m_spd.pitch, m_spd.bpp); + TRACE("CMemSubPic: Resized SubPic %dx%d -> %dx%d\n", m_spd.w, m_spd.h, r.Width(), r.Height()); + + // Set whole resized spd as dirty, we are not going to reuse it. + rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); + } else if (m_resizedSpd) { + // Resize is not needed so release m_resizedSpd. + m_pAllocator->FreeSpdBits(*m_resizedSpd); + m_resizedSpd = nullptr; + } + + const SubPicDesc& subPic = m_resizedSpd ? *m_resizedSpd : m_spd; + + if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV || subPic.type == MSP_AYUV) { + ColorConvInit(); + + if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { + rcDirty.left &= ~1; + rcDirty.right = (rcDirty.right + 1) & ~1; + + if (subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { + rcDirty.top &= ~1; + rcDirty.bottom = (rcDirty.bottom + 1) & ~1; + } + } + } + + if (!m_resizedSpd) { + m_rcDirty = rcDirty; + } + + int w = rcDirty.Width(), h = rcDirty.Height(); + BYTE* top = subPic.bits + subPic.pitch * rcDirty.top + rcDirty.left * 4; + BYTE* bottom = top + subPic.pitch * h; + + if (subPic.type == MSP_RGB16) { + for (; top < bottom ; top += subPic.pitch) { + DWORD* s = (DWORD*)top; + DWORD* e = s + w; + for (; s < e; s++) { + *s = ((*s >> 3) & 0x1f000000) | ((*s >> 8) & 0xf800) | ((*s >> 5) & 0x07e0) | ((*s >> 3) & 0x001f); + //*s = (*s&0xff000000)|((*s>>8)&0xf800)|((*s>>5)&0x07e0)|((*s>>3)&0x001f); + } + } + } else if (subPic.type == MSP_RGB15) { + for (; top < bottom; top += subPic.pitch) { + DWORD* s = (DWORD*)top; + DWORD* e = s + w; + for (; s < e; s++) { + *s = ((*s >> 3) & 0x1f000000) | ((*s >> 9) & 0x7c00) | ((*s >> 6) & 0x03e0) | ((*s >> 3) & 0x001f); + //*s = (*s&0xff000000)|((*s>>9)&0x7c00)|((*s>>6)&0x03e0)|((*s>>3)&0x001f); + } + } + } else if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { + for (; top < bottom ; top += subPic.pitch) { + BYTE* s = top; + BYTE* e = s + w * 4; + for (; s < e; s += 8) { // ARGB ARGB -> AxYU AxYV + if ((s[3] + s[7]) < 0x1fe) { + s[1] = BYTE((c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16); + s[5] = BYTE((c2y_yb[s[4]] + c2y_yg[s[5]] + c2y_yr[s[6]] + 0x108000) >> 16); + + int scaled_y = (s[1] + s[5] - 32) * cy_cy2; + + s[0] = clip[(((((s[0] + s[4]) << 15) - scaled_y) >> 10) * c2y_cu + 0x800000 + 0x8000) >> 16]; + s[4] = clip[(((((s[2] + s[6]) << 15) - scaled_y) >> 10) * c2y_cv + 0x800000 + 0x8000) >> 16]; + } else { + s[1] = s[5] = 0x10; + s[0] = s[4] = 0x80; + } + } + } + } else if (subPic.type == MSP_AYUV) { + for (; top < bottom ; top += subPic.pitch) { + BYTE* s = top; + BYTE* e = s + w * 4; + + for (; s < e; s += 4) { // ARGB -> AYUV + if (s[3] < 0xff) { + auto y = BYTE((c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16); + int scaled_y = (y - 32) * cy_cy; + s[1] = clip[((((s[0] << 16) - scaled_y) >> 10) * c2y_cu + 0x800000 + 0x8000) >> 16]; + s[0] = clip[((((s[2] << 16) - scaled_y) >> 10) * c2y_cv + 0x800000 + 0x8000) >> 16]; + s[2] = y; + } else { + s[0] = s[1] = 0x80; + s[2] = 0x10; + } + } + } + } + + return S_OK; +} + +#ifdef _WIN64 +void AlphaBlt_YUY2_SSE2(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) +{ + unsigned int ia; + static const __int64 _8181 = 0x0080001000800010i64; + + for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { + DWORD* d2 = (DWORD*)d; + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + + for (; s2 < s2end; s2 += 8, d2++) { + ia = (s2[3] + s2[7]) >> 1; + if (ia < 0xff) { + unsigned int c = (s2[4] << 24) | (s2[5] << 16) | (s2[0] << 8) | s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; + + ia = (ia << 24) | (s2[7] << 16) | (ia << 8) | s2[3]; + // SSE2 + __m128i mm_zero = _mm_setzero_si128(); + __m128i mm_8181 = _mm_move_epi64(_mm_cvtsi64_si128(_8181)); + __m128i mm_c = _mm_cvtsi32_si128(c); + mm_c = _mm_unpacklo_epi8(mm_c, mm_zero); + __m128i mm_d = _mm_cvtsi32_si128(*d2); + mm_d = _mm_unpacklo_epi8(mm_d, mm_zero); + __m128i mm_a = _mm_cvtsi32_si128(ia); + mm_a = _mm_unpacklo_epi8(mm_a, mm_zero); + mm_a = _mm_srli_epi16(mm_a, 1); + mm_d = _mm_sub_epi16(mm_d, mm_8181); + mm_d = _mm_mullo_epi16(mm_d, mm_a); + mm_d = _mm_srai_epi16(mm_d, 7); + mm_d = _mm_adds_epi16(mm_d, mm_c); + mm_d = _mm_packus_epi16(mm_d, mm_d); + *d2 = (DWORD)_mm_cvtsi128_si32(mm_d); + } + } + } +} + +#else + +void AlphaBlt_YUY2_MMX(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) +{ + unsigned int ia; + static const __int64 _8181 = 0x0080001000800010i64; + + for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { + DWORD* d2 = (DWORD*)d; + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + + for (; s2 < s2end; s2 += 8, d2++) { + ia = (s2[3] + s2[7]) >> 1; + if (ia < 0xff) { + unsigned int c = (s2[4] << 24) | (s2[5] << 16) | (s2[0] << 8) | s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; + ia = (ia << 24) | (s2[7] << 16) | (ia << 8) | s2[3]; + __asm { + mov esi, s2 + mov edi, d2 + pxor mm0, mm0 + movq mm1, _8181 + movd mm2, c + punpcklbw mm2, mm0 + movd mm3, [edi] + punpcklbw mm3, mm0 + movd mm4, ia + punpcklbw mm4, mm0 + psrlw mm4, 1 + psubsw mm3, mm1 + pmullw mm3, mm4 + psraw mm3, 7 + paddsw mm3, mm2 + packuswb mm3, mm3 + movd [edi], mm3 + }; + } + } + } + _mm_empty(); +} +#endif + +void AlphaBlt_YUY2_C(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) +{ + unsigned int ia; + + for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { + DWORD* d2 = (DWORD*)d; + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + + for (; s2 < s2end; s2 += 8, d2++) { + ia = (s2[3] + s2[7]) >> 1; + if (ia < 0xff) { + //unsigned int c = (s2[4]<<24)|(s2[5]<<16)|(s2[0]<<8)|s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; + + // YUY2 colorspace fix. rewritten from sse2 asm + DWORD y1 = (DWORD)(((((*d2 & 0xff) - 0x10) * (s2[3] >> 1)) >> 7) + s2[1]) & 0xff; // y1 + DWORD uu = (DWORD)((((((*d2 >> 8) & 0xff) - 0x80) * (ia >> 1)) >> 7) + s2[0]) & 0xff; // u + DWORD y2 = (DWORD)((((((*d2 >> 16) & 0xff) - 0x10) * (s2[7] >> 1)) >> 7) + s2[5]) & 0xff; // y2 + DWORD vv = (DWORD)((((((*d2 >> 24) & 0xff) - 0x80) * (ia >> 1)) >> 7) + s2[4]) & 0xff; // v + *d2 = (y1) | (uu << 8) | (y2 << 16) | (vv << 24); + } + } + } +} + +STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) +{ + ASSERT(pTarget); + + if (!pSrc || !pDst || !pTarget) { + return E_POINTER; + } + + const SubPicDesc& src = m_resizedSpd ? *m_resizedSpd : m_spd; + SubPicDesc dst = *pTarget; // copy, because we might modify it + + if (src.type != dst.type) { + return E_INVALIDARG; + } + + CRect rs(*pSrc), rd(*pDst); + + if (m_resizedSpd) { + rs = rd = CRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); + } + + if (dst.h < 0) { + dst.h = -dst.h; + rd.bottom = dst.h - rd.bottom; + rd.top = dst.h - rd.top; + } + + if (rs.Width() != rd.Width() || rs.Height() != abs(rd.Height())) { + return E_INVALIDARG; + } + + int w = rs.Width(), h = rs.Height(); + BYTE* s = src.bits + src.pitch * rs.top + rs.left * 4; + BYTE* d = dst.bits + dst.pitch * rd.top + ((rd.left * dst.bpp) >> 3); + + if (rd.top > rd.bottom) { + if (dst.type == MSP_RGB32 || dst.type == MSP_RGB24 + || dst.type == MSP_RGB16 || dst.type == MSP_RGB15 + || dst.type == MSP_YUY2 || dst.type == MSP_AYUV) { + d = dst.bits + dst.pitch * (rd.top - 1) + (rd.left * dst.bpp >> 3); + } else if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) { + d = dst.bits + dst.pitch * (rd.top - 1) + (rd.left * 8 >> 3); + } else { + return E_NOTIMPL; + } + + dst.pitch = -dst.pitch; + } + + // TODO: m_bInvAlpha support + switch (dst.type) { + case MSP_RGBA: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + DWORD* d2 = (DWORD*)d; + for (; s2 < s2end; s2 += 4, d2++) { + if (s2[3] < 0xff) { + DWORD bd = 0x00000100 - ((DWORD) s2[3]); + DWORD B = ((*((DWORD*)s2) & 0x000000ff) << 8) / bd; + DWORD V = ((*((DWORD*)s2) & 0x0000ff00) / bd) << 8; + DWORD R = (((*((DWORD*)s2) & 0x00ff0000) >> 8) / bd) << 16; + *d2 = B | V | R + | (0xff000000 - (*((DWORD*)s2) & 0xff000000)) & 0xff000000; + } + } + } + break; + case MSP_RGB32: + case MSP_AYUV: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + DWORD* d2 = (DWORD*)d; + for (; s2 < s2end; s2 += 4, d2++) { +#ifdef _WIN64 + DWORD ia = 256 - s2[3]; + if (s2[3] < 0xff) { + *d2 = ((((*d2 & 0x00ff00ff) * s2[3]) >> 8) + (((*((DWORD*)s2) & 0x00ff00ff) * ia) >> 8) & 0x00ff00ff) + | ((((*d2 & 0x0000ff00) * s2[3]) >> 8) + (((*((DWORD*)s2) & 0x0000ff00) * ia) >> 8) & 0x0000ff00); + } +#else + if (s2[3] < 0xff) { + *d2 = ((((*d2 & 0x00ff00ff) * s2[3]) >> 8) + (*((DWORD*)s2) & 0x00ff00ff) & 0x00ff00ff) + | ((((*d2 & 0x0000ff00) * s2[3]) >> 8) + (*((DWORD*)s2) & 0x0000ff00) & 0x0000ff00); + } +#endif + } + } + break; + case MSP_RGB24: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + BYTE* d2 = d; + for (; s2 < s2end; s2 += 4, d2 += 3) { + if (s2[3] < 0xff) { + d2[0] = ((d2[0] * s2[3]) >> 8) + s2[0]; + d2[1] = ((d2[1] * s2[3]) >> 8) + s2[1]; + d2[2] = ((d2[2] * s2[3]) >> 8) + s2[2]; + } + } + } + break; + case MSP_RGB16: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + WORD* d2 = (WORD*)d; + for (; s2 < s2end; s2 += 4, d2++) { + if (s2[3] < 0x1f) { + *d2 = (WORD)((((((*d2 & 0xf81f) * s2[3]) >> 5) + (*(DWORD*)s2 & 0xf81f)) & 0xf81f) + | (((((*d2 & 0x07e0) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x07e0)) & 0x07e0)); + } + } + } + break; + case MSP_RGB15: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + WORD* d2 = (WORD*)d; + for (; s2 < s2end; s2 += 4, d2++) { + if (s2[3] < 0x1f) { + *d2 = (WORD)((((((*d2 & 0x7c1f) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x7c1f)) & 0x7c1f) + | (((((*d2 & 0x03e0) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x03e0)) & 0x03e0)); + } + } + } + break; + case MSP_YUY2: { +#ifdef _WIN64 + auto alphablt_func = AlphaBlt_YUY2_SSE2; +#else + auto alphablt_func = AlphaBlt_YUY2_MMX; +#endif + //alphablt_func = AlphaBlt_YUY2_C; + + alphablt_func(w, h, d, dst.pitch, s, src.pitch); + } + break; + case MSP_YV12: + case MSP_IYUV: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + BYTE* d2 = d; + for (; s2 < s2end; s2 += 4, d2++) { + if (s2[3] < 0xff) { + d2[0] = (((d2[0] - 0x10) * s2[3]) >> 8) + s2[1]; + } + } + } + break; + default: + return E_NOTIMPL; + } + + dst.pitch = abs(dst.pitch); + + if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) { + int h2 = h / 2; + + if (!dst.pitchUV) { + dst.pitchUV = dst.pitch / 2; + } + + BYTE* ss[2]; + ss[0] = src.bits + src.pitch * rs.top + rs.left * 4; + ss[1] = ss[0] + 4; + + if (!dst.bitsU || !dst.bitsV) { + dst.bitsU = dst.bits + dst.pitch * dst.h; + dst.bitsV = dst.bitsU + dst.pitchUV * dst.h / 2; + + if (dst.type == MSP_YV12) { + BYTE* p = dst.bitsU; + dst.bitsU = dst.bitsV; + dst.bitsV = p; + } + } + + BYTE* dd[2]; + dd[0] = dst.bitsU + dst.pitchUV * rd.top / 2 + rd.left / 2; + dd[1] = dst.bitsV + dst.pitchUV * rd.top / 2 + rd.left / 2; + + if (rd.top > rd.bottom) { + dd[0] = dst.bitsU + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; + dd[1] = dst.bitsV + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; + dst.pitchUV = -dst.pitchUV; + } + + for (ptrdiff_t i = 0; i < 2; i++) { + s = ss[i]; + d = dd[i]; + BYTE* is = ss[1 - i]; + for (ptrdiff_t j = 0; j < h2; j++, s += src.pitch * 2, d += dst.pitchUV, is += src.pitch * 2) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + BYTE* d2 = d; + BYTE* is2 = is; + for (; s2 < s2end; s2 += 8, d2++, is2 += 8) { + unsigned int ia = (s2[3] + s2[3 + src.pitch] + is2[3] + is2[3 + src.pitch]) >> 2; + if (ia < 0xff) { + *d2 = BYTE((((*d2 - 0x80) * ia) >> 8) + ((s2[0] + s2[src.pitch]) >> 1)); + } + } + } + } + } + + return S_OK; +} + +// +// CMemSubPicAllocator +// + +CMemSubPicAllocator::CMemSubPicAllocator(int type, SIZE maxsize) + : CSubPicAllocatorImpl(maxsize, false) + , m_type(type) + , m_maxsize(maxsize) +{ +} + +CMemSubPicAllocator::~CMemSubPicAllocator() +{ + CAutoLock cAutoLock(this); + + for (const auto& p : m_freeMemoryChunks) { + delete[] std::get<1>(p); + } +} + +// ISubPicAllocatorImpl + +bool CMemSubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) +{ + if (!ppSubPic || m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { + return false; + } + + SubPicDesc spd; + spd.w = m_maxsize.cx; + spd.h = m_maxsize.cy; + spd.bpp = 32; + spd.pitch = (spd.w * spd.bpp) >> 3; + spd.type = m_type; + spd.vidrect = m_curvidrect; + + if (!AllocSpdBits(spd)) { + return false; + } + + try { + *ppSubPic = DEBUG_NEW CMemSubPic(spd, this); + } catch (CMemoryException* e) { + e->Delete(); + delete [] spd.bits; + return false; + } + + (*ppSubPic)->AddRef(); + (*ppSubPic)->SetInverseAlpha(m_bInvAlpha); + + return true; +} + +bool CMemSubPicAllocator::AllocSpdBits(SubPicDesc& spd) +{ + CAutoLock cAutoLock(this); + + ASSERT(!spd.bits); + ASSERT(spd.pitch * spd.h > 0); + + auto it = std::find_if(m_freeMemoryChunks.cbegin(), m_freeMemoryChunks.cend(), [&](const std::pair& p) { + return std::get<0>(p) == size_t(spd.pitch) * spd.h; + }); + + if (it != m_freeMemoryChunks.cend()) { + spd.bits = std::get<1>(*it); + m_freeMemoryChunks.erase(it); + } else { + try { + spd.bits = DEBUG_NEW BYTE[spd.pitch * spd.h]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + return false; + } + } + return true; +} + +void CMemSubPicAllocator::FreeSpdBits(SubPicDesc& spd) +{ + CAutoLock cAutoLock(this); + + ASSERT(spd.bits); + m_freeMemoryChunks.emplace_back(spd.pitch * spd.h, spd.bits); + spd.bits = nullptr; +} + +STDMETHODIMP CMemSubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) +{ + if (maxTextureSize.cx > 0 && maxTextureSize.cy > 0 && m_maxsize != maxTextureSize) { + m_maxsize = maxTextureSize; + CAutoLock cAutoLock(this); + for (const auto& p : m_freeMemoryChunks) { + delete[] std::get<1>(p); + } + m_freeMemoryChunks.clear(); + } + return S_OK; +} diff --git a/src/SubPic/MemSubPic.h b/src/SubPic/MemSubPic.h index cc82ee3b8c5..7686b2df42e 100644 --- a/src/SubPic/MemSubPic.h +++ b/src/SubPic/MemSubPic.h @@ -1,86 +1,86 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#pragma once - -#include "SubPicImpl.h" -#include -#include - -enum { - MSP_RGB32, - MSP_RGB24, - MSP_RGB16, - MSP_RGB15, - MSP_YUY2, - MSP_YV12, - MSP_IYUV, - MSP_AYUV, - MSP_RGBA -}; - -// CMemSubPic -class CMemSubPicAllocator; -class CMemSubPic : public CSubPicImpl -{ - CComPtr m_pAllocator; - - SubPicDesc m_spd; - std::unique_ptr m_resizedSpd; - -protected: - STDMETHODIMP_(void*) GetObject(); // returns SubPicDesc* - -public: - CMemSubPic(const SubPicDesc& spd, CMemSubPicAllocator* pAllocator); - virtual ~CMemSubPic(); - - HRESULT UnlockARGB(); - - // ISubPic - STDMETHODIMP GetDesc(SubPicDesc& spd); - STDMETHODIMP CopyTo(ISubPic* pSubPic); - STDMETHODIMP ClearDirtyRect(); - STDMETHODIMP Lock(SubPicDesc& spd); - STDMETHODIMP Unlock(RECT* pDirtyRect); - STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget); -}; - -// CMemSubPicAllocator - -class CMemSubPicAllocator : public CSubPicAllocatorImpl, public CCritSec -{ - int m_type; - CSize m_maxsize; - - std::vector> m_freeMemoryChunks; - - bool Alloc(bool fStatic, ISubPic** ppSubPic); - -public: - CMemSubPicAllocator(int type, SIZE maxsize); - virtual ~CMemSubPicAllocator(); - - bool AllocSpdBits(SubPicDesc& spd); - void FreeSpdBits(SubPicDesc& spd); - - STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize) override; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#pragma once + +#include "SubPicImpl.h" +#include +#include + +enum { + MSP_RGB32, + MSP_RGB24, + MSP_RGB16, + MSP_RGB15, + MSP_YUY2, + MSP_YV12, + MSP_IYUV, + MSP_AYUV, + MSP_RGBA +}; + +// CMemSubPic +class CMemSubPicAllocator; +class CMemSubPic : public CSubPicImpl +{ + CComPtr m_pAllocator; + + SubPicDesc m_spd; + std::unique_ptr m_resizedSpd; + +protected: + STDMETHODIMP_(void*) GetObject(); // returns SubPicDesc* + +public: + CMemSubPic(const SubPicDesc& spd, CMemSubPicAllocator* pAllocator); + virtual ~CMemSubPic(); + + HRESULT UnlockARGB(); + + // ISubPic + STDMETHODIMP GetDesc(SubPicDesc& spd); + STDMETHODIMP CopyTo(ISubPic* pSubPic); + STDMETHODIMP ClearDirtyRect(); + STDMETHODIMP Lock(SubPicDesc& spd); + STDMETHODIMP Unlock(RECT* pDirtyRect); + STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget); +}; + +// CMemSubPicAllocator + +class CMemSubPicAllocator : public CSubPicAllocatorImpl, public CCritSec +{ + int m_type; + CSize m_maxsize; + + std::vector> m_freeMemoryChunks; + + bool Alloc(bool fStatic, ISubPic** ppSubPic); + +public: + CMemSubPicAllocator(int type, SIZE maxsize); + virtual ~CMemSubPicAllocator(); + + bool AllocSpdBits(SubPicDesc& spd); + void FreeSpdBits(SubPicDesc& spd); + + STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize) override; +}; diff --git a/src/SubPic/SubPic.vcxproj b/src/SubPic/SubPic.vcxproj index faf266b6ee0..d134d672ea4 100644 --- a/src/SubPic/SubPic.vcxproj +++ b/src/SubPic/SubPic.vcxproj @@ -1,85 +1,85 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {D514EA4D-EAFB-47A9-A437-A582CA571251} - SubPic - MFCProj - SubPic - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\include;..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {D514EA4D-EAFB-47A9-A437-A582CA571251} + SubPic + MFCProj + SubPic + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\include;..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/SubPic/SubPic.vcxproj.filters b/src/SubPic/SubPic.vcxproj.filters index 72112ad70e9..a87f236cad7 100644 --- a/src/SubPic/SubPic.vcxproj.filters +++ b/src/SubPic/SubPic.vcxproj.filters @@ -1,101 +1,101 @@ - - - - - {bbd07979-c9e6-4936-b818-b36901e0eca8} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {c4e622a8-2caa-417f-86ec-c5c16ad85753} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {bbd07979-c9e6-4936-b818-b36901e0eca8} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c4e622a8-2caa-417f-86ec-c5c16ad85753} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/SubPic/SubPicAllocatorPresenterImpl.cpp b/src/SubPic/SubPicAllocatorPresenterImpl.cpp index c3d0fab9ff6..e643d1cc8ed 100644 --- a/src/SubPic/SubPicAllocatorPresenterImpl.cpp +++ b/src/SubPic/SubPicAllocatorPresenterImpl.cpp @@ -1,646 +1,646 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "SubPicAllocatorPresenterImpl.h" -#include "../DSUtil/DSUtil.h" -#include "../filters/renderer/VideoRenderers/RenderersSettings.h" -#include "../mpc-hc/VersionInfo.h" -#include -#include "XySubPicQueueImpl.h" -#include "XySubPicProvider.h" -#include -#include -#include -#include -#include "ScreenUtil.h" - -#include "mpc-hc_config.h" - -#if !TRACE_SUBTITLES -#define TRACE(...) -#endif - -CSubPicAllocatorPresenterImpl::CSubPicAllocatorPresenterImpl(HWND hWnd, HRESULT& hr, CString* _pError) - : CUnknown(NAME("CSubPicAllocatorPresenterImpl"), nullptr) - , m_hWnd(hWnd) - , m_rtSubtitleDelay(0) - , m_maxSubtitleTextureSize(0, 0) - , m_nativeVideoSize(0, 0) - , m_aspectRatio(0, 0) - , m_videoRect(0, 0, 0, 0) - , m_windowRect(0, 0, 0, 0) - , m_rtNow(0) - , m_fps(25.0) - , m_refreshRate(0) - , m_bDeviceResetRequested(false) - , m_bPendingResetDevice(false) - , m_bDefaultVideoAngleSwitchAR(false) - , m_bHookedNewSegment(false) - , m_bHookedReceive(false) -{ - if (!IsWindow(m_hWnd)) { - hr = E_INVALIDARG; - if (_pError) { - *_pError += _T("Invalid window handle in ISubPicAllocatorPresenterImpl\n"); - } - return; - } - GetWindowRect(m_hWnd, &m_windowRect); - hr = S_OK; -} - -CSubPicAllocatorPresenterImpl::~CSubPicAllocatorPresenterImpl() -{ -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - - return - QI(ISubPicAllocatorPresenter) - QI(ISubPicAllocatorPresenter2) - QI(ISubRenderOptions) - QI(ISubRenderConsumer) - QI(ISubRenderConsumer2) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CSubPicAllocatorPresenterImpl::InitMaxSubtitleTextureSize(int maxSizeX, int maxSizeY, CSize largestScreen) -{ - if (maxSizeX < 384 || maxSizeY < 288) { - m_maxSubtitleTextureSize = largestScreen; - } else { - if (maxSizeX * maxSizeY > largestScreen.cx * largestScreen.cy) { - m_maxSubtitleTextureSize = largestScreen; - } else { - m_maxSubtitleTextureSize.cx = maxSizeX; - m_maxSubtitleTextureSize.cy = maxSizeY; - } - } -#if DEBUG_OVERRIDE_TEXTURE_SIZE - m_maxSubtitleTextureSize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); -#endif - m_curSubtitleTextureSize = m_maxSubtitleTextureSize; - TRACE(_T("CSubPicAllocatorPresenterImpl::InitMaxSubtitleTextureSize %dx%d\n"), m_maxSubtitleTextureSize.cx, m_maxSubtitleTextureSize.cy); -} - -HRESULT CSubPicAllocatorPresenterImpl::AlphaBltSubPic(const CRect& windowRect, - const CRect& videoRect, - SubPicDesc* pTarget /*= nullptr*/, - const double videoStretchFactor /*= 1.0*/, - int xOffsetInPixels /*= 0*/, int yOffsetInPixels /*= 0*/) -{ - CComPtr pSubPic; - if (m_pSubPicQueue->LookupSubPic(m_rtNow, !IsRendering(), pSubPic)) { - CRect rcSource, rcDest; - - const CRenderersSettings& r = GetRenderersSettings(); - int yOffset = yOffsetInPixels + r.subPicVerticalShift; - if (SUCCEEDED(pSubPic->GetSourceAndDest(windowRect, videoRect, rcSource, rcDest, - videoStretchFactor, xOffsetInPixels, yOffset))) { - return pSubPic->AlphaBlt(rcSource, rcDest, pTarget); - } - } - - return E_FAIL; -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetVideoSize(CSize szVideo, CSize szAspectRatio /* = CSize(0, 0) */) -{ - if (szVideo.cx == 0 || szVideo.cy == 0) { - return; - } - - m_nativeVideoSize = szVideo; - m_aspectRatio = szAspectRatio; -} - -STDMETHODIMP_(SIZE) CSubPicAllocatorPresenterImpl::GetVideoSize(bool bCorrectAR) const -{ - CSize videoSize(GetVisibleVideoSize()); - - if (bCorrectAR && m_aspectRatio.cx > 0 && m_aspectRatio.cy > 0) { - videoSize.cx = (LONGLONG(videoSize.cy) * LONGLONG(m_aspectRatio.cx)) / LONGLONG(m_aspectRatio.cy); - } - - if (m_bDefaultVideoAngleSwitchAR) { - std::swap(videoSize.cx, videoSize.cy); - } - - return videoSize; -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetPosition(RECT w, RECT v) -{ - bool bWindowPosChanged = !!(m_windowRect != w); - bool bWindowSizeChanged = !!(m_windowRect.Size() != CRect(w).Size()); - bool bVideoRectChanged = !!(m_videoRect != v); - - m_windowRect = w; - m_videoRect = v; - - if (m_pAllocator && (bWindowPosChanged || bWindowSizeChanged || bVideoRectChanged)) { - if (m_windowRect.Width() != m_curSubtitleTextureSize.cx || m_windowRect.Height() != m_curSubtitleTextureSize.cy) { - int maxpixels = m_maxSubtitleTextureSize.cx * m_maxSubtitleTextureSize.cy; - if (m_windowRect.Width() * m_windowRect.Height() <= maxpixels) { - // use window size - m_curSubtitleTextureSize = CSize(m_windowRect.Width(), m_windowRect.Height()); - } else { - bool correct_ar = false; - if (m_maxSubtitleTextureSize.cx == 2560 && m_windowRect.Width() >= 3800 && m_windowRect.Width() <= 4096) { // not 3840, to handle a maximized window as well - m_curSubtitleTextureSize = CSize(m_windowRect.Width() / 2, m_windowRect.Height() / 2); - } else { - m_curSubtitleTextureSize = CSize(m_maxSubtitleTextureSize.cx, m_maxSubtitleTextureSize.cy); - correct_ar = true; - } - - if (correct_ar) { - double new_w = sqrt((uint64_t)m_curSubtitleTextureSize.cx * m_curSubtitleTextureSize.cy * m_windowRect.Width() / m_windowRect.Height()); - double new_h = sqrt((uint64_t)m_curSubtitleTextureSize.cx * m_curSubtitleTextureSize.cy * m_windowRect.Height() / m_windowRect.Width()); - m_curSubtitleTextureSize.cx = lround(new_w); - m_curSubtitleTextureSize.cy = lround(new_h); - } - } - } - - m_pAllocator->SetMaxTextureSize(m_curSubtitleTextureSize); - m_pAllocator->SetCurSize(m_windowRect.Size()); - m_pAllocator->SetCurVidRect(m_videoRect); - - if (m_pSubPicQueue) { - m_pSubPicQueue->Invalidate(); - } - } - - if (bWindowPosChanged || bVideoRectChanged || m_bOtherTransform) { - Paint(false); - m_bOtherTransform = false; - } -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetTime(REFERENCE_TIME rtNow) -{ - m_rtNow = rtNow - m_rtSubtitleDelay; - - if (m_pSubPicQueue) { - m_pSubPicQueue->SetTime(m_rtNow); - } -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetSubtitleDelay(int delayMs) -{ - REFERENCE_TIME delay = MILLISECONDS_TO_100NS_UNITS(delayMs); - if (m_rtSubtitleDelay != delay) { - REFERENCE_TIME oldDelay = m_rtSubtitleDelay; - m_rtSubtitleDelay = delay; - SetTime(m_rtNow + oldDelay); - Paint(false); - } -} - -STDMETHODIMP_(int) CSubPicAllocatorPresenterImpl::GetSubtitleDelay() const -{ - return (int)(m_rtSubtitleDelay / 10000); -} - -STDMETHODIMP_(double) CSubPicAllocatorPresenterImpl::GetFPS() const -{ - return m_fps; -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider) -{ - CAutoLock cAutoLock(&m_csSubPicProvider); - - m_pSubPicProvider = pSubPicProvider; - - if (m_pSubPicQueue) { - m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); - } - - if (m_pAllocator) { - m_pAllocator->SetCurSize(CSize(m_windowRect.Width(), m_windowRect.Height())); - m_pAllocator->SetCurVidRect(m_videoRect); - } - - Paint(false); -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::Invalidate(REFERENCE_TIME rtInvalidate) -{ - if (m_pSubPicQueue) { - m_pSubPicQueue->Invalidate(rtInvalidate); - } -} - -void CSubPicAllocatorPresenterImpl::Transform(CRect r, Vector v[4]) -{ - v[0] = Vector((float)r.left, (float)r.top, 0); - v[1] = Vector((float)r.right, (float)r.top, 0); - v[2] = Vector((float)r.left, (float)r.bottom, 0); - v[3] = Vector((float)r.right, (float)r.bottom, 0); - - Vector center((float)r.CenterPoint().x, (float)r.CenterPoint().y, 0); - int l = (int)(Vector((float)r.Size().cx, (float)r.Size().cy, 0).Length() * 1.5f) + 1; - - for (size_t i = 0; i < 4; i++) { - v[i] = m_xform << (v[i] - center); - v[i].z = v[i].z / l + 0.5f; - v[i].x /= v[i].z * 2; - v[i].y /= v[i].z * 2; - v[i] += center; - } -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetDefaultVideoAngle(Vector v) -{ - if (m_defaultVideoAngle != v) { - constexpr float pi_2 = float(M_PI_2); - - // In theory it should be a multiple of 90 - int zAnglePi2 = std::lround(v.z / pi_2); - //ASSERT(zAnglePi2 * pi_2 == v.z); - - // Normalize the Z angle - zAnglePi2 %= 4; - if (zAnglePi2 < 0) { - zAnglePi2 += 4; - } - v.z = zAnglePi2 * pi_2; - - // Check if the default rotation change the AR - m_bDefaultVideoAngleSwitchAR = (v.z == pi_2 || v.z == 3.0f * pi_2); - - m_defaultVideoAngle = v; - UpdateXForm(); - return S_OK; - } - return S_FALSE; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetVideoAngle(Vector v) -{ - if (m_videoAngle != v) { - m_videoAngle = v; - UpdateXForm(); - return S_OK; - } - return S_FALSE; -} - -void CSubPicAllocatorPresenterImpl::UpdateXForm() -{ - Vector v = m_defaultVideoAngle + m_videoAngle; - - auto normalizeAngle = [](float & rad) { - constexpr float twoPi = float(2.0 * M_PI); - - while (rad < 0.0f) { - rad += twoPi; - } - while (rad > twoPi) { - rad -= twoPi; - } - }; - - normalizeAngle(v.x); - normalizeAngle(v.y); - normalizeAngle(v.z); - - CSize AR = GetVideoSize(true); - float fARCorrection = m_bDefaultVideoAngleSwitchAR ? float(AR.cx) / AR.cy : 1.0f; - - m_xform = XForm(Ray(Vector(), v), Vector(1.0f / fARCorrection, fARCorrection, 1.0f), false); - - Paint(false); -} - -HRESULT CSubPicAllocatorPresenterImpl::CreateDIBFromSurfaceData(D3DSURFACE_DESC desc, D3DLOCKED_RECT r, BYTE* lpDib) const -{ - bool bNeedRotation = !IsEqual(m_defaultVideoAngle.z, 0.0f); - - BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)lpDib; - ZeroMemory(bih, sizeof(BITMAPINFOHEADER)); - bih->biSize = sizeof(BITMAPINFOHEADER); - bih->biWidth = desc.Width; - bih->biHeight = desc.Height; - bih->biBitCount = 32; - bih->biPlanes = 1; - bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount >> 3; - - UINT* pBits; - if (bNeedRotation) { - pBits = (UINT*)malloc(bih->biSizeImage); - if (!pBits) { - return E_OUTOFMEMORY; - } - } else { - pBits = (UINT*)(bih + 1); - } - - BitBltFromRGBToRGB(bih->biWidth, bih->biHeight, - (BYTE*)pBits, bih->biWidth * bih->biBitCount >> 3, bih->biBitCount, - (BYTE*)r.pBits + r.Pitch * (desc.Height - 1), -r.Pitch, 32); - - if (bNeedRotation) { - constexpr float pi_2 = float(M_PI_2); - - if (m_bDefaultVideoAngleSwitchAR) { - std::swap(bih->biWidth, bih->biHeight); - } - - std::function convCoordinates; - if (IsEqual(m_defaultVideoAngle.z, pi_2)) { - convCoordinates = [desc](UINT x, UINT y) { - return x * desc.Height + desc.Height - 1 - y; - }; - } else if (IsEqual(m_defaultVideoAngle.z, 2 * pi_2)) { - convCoordinates = [desc](UINT x, UINT y) { - return desc.Width - 1 - x + (desc.Height - 1 - y) * desc.Width; - }; - } else { - ASSERT(IsEqual(m_defaultVideoAngle.z, 3 * pi_2)); - convCoordinates = [desc](UINT x, UINT y) { - return (desc.Width - 1 - x) * desc.Height + y; - }; - } - - UINT* pBitsDest = (UINT*)(bih + 1); - for (UINT x = 0; x < desc.Width; x++) { - for (UINT y = 0; y < desc.Height; y++) { - pBitsDest[convCoordinates(x, y)] = pBits[x + y * desc.Width]; - } - } - - free(pBits); - } - - return S_OK; -} - -// ISubRenderOptions - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetBool(LPCSTR field, bool* value) -{ - CheckPointer(value, E_POINTER); - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetInt(LPCSTR field, int* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "supportedLevels")) { - if (CComQIPtr pEVR = (ISubPicAllocatorPresenter*)this) { - const CRenderersSettings& r = GetRenderersSettings(); - if (r.m_AdvRendSets.iEVROutputRange == 1) { - *value = 3; // TV preferred - } else { - *value = 2; // PC preferred - } - } else { - *value = 0; // PC only - } - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetSize(LPCSTR field, SIZE* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "originalVideoSize")) { - *value = GetVideoSize(false); - return S_OK; - } else if (!strcmp(field, "arAdjustedVideoSize")) { - *value = GetVideoSize(true); - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetRect(LPCSTR field, RECT* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "videoOutputRect") || !strcmp(field, "subtitleTargetRect")) { - if (m_videoRect.IsRectEmpty()) { - *value = m_windowRect; - } else { - value->left = 0; - value->top = 0; - value->right = m_videoRect.Width(); - value->bottom = m_videoRect.Height(); - } - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetUlonglong(LPCSTR field, ULONGLONG* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "frameRate")) { - *value = (REFERENCE_TIME)(10000000.0 / m_fps); - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetDouble(LPCSTR field, double* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "refreshRate")) { - *value = 1000.0 / m_refreshRate; - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetString(LPCSTR field, LPWSTR* value, int* chars) -{ - CheckPointer(value, E_POINTER); - CheckPointer(chars, E_POINTER); - CStringW ret = nullptr; - - if (!strcmp(field, "name")) { - ret = L"MPC-HC"; - } else if (!strcmp(field, "version")) { - ret = VersionInfo::GetVersionString(); - } else if (!strcmp(field, "yuvMatrix")) { - ret = L"None"; - - if (m_inputMediaType.IsValid() && m_inputMediaType.formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* pVIH2 = (VIDEOINFOHEADER2*)m_inputMediaType.pbFormat; - - if (pVIH2->dwControlFlags & AMCONTROL_COLORINFO_PRESENT) { - DXVA2_ExtendedFormat& flags = (DXVA2_ExtendedFormat&)pVIH2->dwControlFlags; - - ret = (flags.NominalRange == DXVA2_NominalRange_Normal) ? L"PC." : L"TV."; - - switch (flags.VideoTransferMatrix) { - case DXVA2_VideoTransferMatrix_BT601: - ret.Append(L"601"); - break; - case DXVA2_VideoTransferMatrix_BT709: - ret.Append(L"709"); - break; - case DXVA2_VideoTransferMatrix_SMPTE240M: - ret.Append(L"240M"); - break; - case 4: - ret.Append(L"2020"); - break; - default: - ret = L"None"; - break; - } - } - } - } - - if (!ret.IsEmpty()) { - int len = ret.GetLength(); - size_t sz = (len + 1) * sizeof(WCHAR); - LPWSTR buf = (LPWSTR)LocalAlloc(LPTR, sz); - - if (!buf) { - return E_OUTOFMEMORY; - } - - wcscpy_s(buf, len + 1, ret); - *chars = len; - *value = buf; - - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetBin(LPCSTR field, LPVOID* value, int* size) -{ - CheckPointer(value, E_POINTER); - CheckPointer(size, E_POINTER); - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetBool(LPCSTR field, bool value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetInt(LPCSTR field, int value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetSize(LPCSTR field, SIZE value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetRect(LPCSTR field, RECT value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetUlonglong(LPCSTR field, ULONGLONG value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetDouble(LPCSTR field, double value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetString(LPCSTR field, LPWSTR value, int chars) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetBin(LPCSTR field, LPVOID value, int size) -{ - return E_INVALIDARG; -} - -// ISubRenderConsumer - -STDMETHODIMP CSubPicAllocatorPresenterImpl::Connect(ISubRenderProvider* subtitleRenderer) -{ - HRESULT hr = E_FAIL; - - if (m_pSubPicProvider) { - return hr; - } - - hr = subtitleRenderer->SetBool("combineBitmaps", true); - if (FAILED(hr)) { - return hr; - } - - if (CComQIPtr pSubConsumer = m_pSubPicQueue) { - hr = pSubConsumer->Connect(subtitleRenderer); - } else { - CComPtr pSubPicProvider = (ISubPicProvider*)DEBUG_NEW CXySubPicProvider(subtitleRenderer); - CComPtr pSubPicQueue = (ISubPicQueue*)DEBUG_NEW CXySubPicQueueNoThread(m_pAllocator, &hr); - - if (SUCCEEDED(hr)) { - pSubPicQueue->SetSubPicProvider(pSubPicProvider); - m_pSubPicProvider = pSubPicProvider; - m_pSubPicQueue = pSubPicQueue; - m_pAllocator->SetInverseAlpha(true); - } - } - - return hr; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::Disconnect() -{ - m_pSubPicProvider = nullptr; - return m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::DeliverFrame(REFERENCE_TIME start, REFERENCE_TIME stop, LPVOID context, ISubRenderFrame* subtitleFrame) -{ - HRESULT hr = E_FAIL; - - if (CComQIPtr pXyProvider = m_pSubPicProvider) { - hr = pXyProvider->DeliverFrame(start, stop, context, subtitleFrame); - } - - return hr; -} - -// ISubRenderConsumer2 - -STDMETHODIMP CSubPicAllocatorPresenterImpl::Clear(REFERENCE_TIME clearNewerThan /* = 0 */) -{ - return m_pSubPicQueue->Invalidate(clearNewerThan); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "SubPicAllocatorPresenterImpl.h" +#include "../DSUtil/DSUtil.h" +#include "../filters/renderer/VideoRenderers/RenderersSettings.h" +#include "../mpc-hc/VersionInfo.h" +#include +#include "XySubPicQueueImpl.h" +#include "XySubPicProvider.h" +#include +#include +#include +#include +#include "ScreenUtil.h" + +#include "mpc-hc_config.h" + +#if !TRACE_SUBTITLES +#define TRACE(...) +#endif + +CSubPicAllocatorPresenterImpl::CSubPicAllocatorPresenterImpl(HWND hWnd, HRESULT& hr, CString* _pError) + : CUnknown(NAME("CSubPicAllocatorPresenterImpl"), nullptr) + , m_hWnd(hWnd) + , m_rtSubtitleDelay(0) + , m_maxSubtitleTextureSize(0, 0) + , m_nativeVideoSize(0, 0) + , m_aspectRatio(0, 0) + , m_videoRect(0, 0, 0, 0) + , m_windowRect(0, 0, 0, 0) + , m_rtNow(0) + , m_fps(25.0) + , m_refreshRate(0) + , m_bDeviceResetRequested(false) + , m_bPendingResetDevice(false) + , m_bDefaultVideoAngleSwitchAR(false) + , m_bHookedNewSegment(false) + , m_bHookedReceive(false) +{ + if (!IsWindow(m_hWnd)) { + hr = E_INVALIDARG; + if (_pError) { + *_pError += _T("Invalid window handle in ISubPicAllocatorPresenterImpl\n"); + } + return; + } + GetWindowRect(m_hWnd, &m_windowRect); + hr = S_OK; +} + +CSubPicAllocatorPresenterImpl::~CSubPicAllocatorPresenterImpl() +{ +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + + return + QI(ISubPicAllocatorPresenter) + QI(ISubPicAllocatorPresenter2) + QI(ISubRenderOptions) + QI(ISubRenderConsumer) + QI(ISubRenderConsumer2) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CSubPicAllocatorPresenterImpl::InitMaxSubtitleTextureSize(int maxSizeX, int maxSizeY, CSize largestScreen) +{ + if (maxSizeX < 384 || maxSizeY < 288) { + m_maxSubtitleTextureSize = largestScreen; + } else { + if (maxSizeX * maxSizeY > largestScreen.cx * largestScreen.cy) { + m_maxSubtitleTextureSize = largestScreen; + } else { + m_maxSubtitleTextureSize.cx = maxSizeX; + m_maxSubtitleTextureSize.cy = maxSizeY; + } + } +#if DEBUG_OVERRIDE_TEXTURE_SIZE + m_maxSubtitleTextureSize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); +#endif + m_curSubtitleTextureSize = m_maxSubtitleTextureSize; + TRACE(_T("CSubPicAllocatorPresenterImpl::InitMaxSubtitleTextureSize %dx%d\n"), m_maxSubtitleTextureSize.cx, m_maxSubtitleTextureSize.cy); +} + +HRESULT CSubPicAllocatorPresenterImpl::AlphaBltSubPic(const CRect& windowRect, + const CRect& videoRect, + SubPicDesc* pTarget /*= nullptr*/, + const double videoStretchFactor /*= 1.0*/, + int xOffsetInPixels /*= 0*/, int yOffsetInPixels /*= 0*/) +{ + CComPtr pSubPic; + if (m_pSubPicQueue->LookupSubPic(m_rtNow, !IsRendering(), pSubPic)) { + CRect rcSource, rcDest; + + const CRenderersSettings& r = GetRenderersSettings(); + int yOffset = yOffsetInPixels + r.subPicVerticalShift; + if (SUCCEEDED(pSubPic->GetSourceAndDest(windowRect, videoRect, rcSource, rcDest, + videoStretchFactor, xOffsetInPixels, yOffset))) { + return pSubPic->AlphaBlt(rcSource, rcDest, pTarget); + } + } + + return E_FAIL; +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetVideoSize(CSize szVideo, CSize szAspectRatio /* = CSize(0, 0) */) +{ + if (szVideo.cx == 0 || szVideo.cy == 0) { + return; + } + + m_nativeVideoSize = szVideo; + m_aspectRatio = szAspectRatio; +} + +STDMETHODIMP_(SIZE) CSubPicAllocatorPresenterImpl::GetVideoSize(bool bCorrectAR) const +{ + CSize videoSize(GetVisibleVideoSize()); + + if (bCorrectAR && m_aspectRatio.cx > 0 && m_aspectRatio.cy > 0) { + videoSize.cx = (LONGLONG(videoSize.cy) * LONGLONG(m_aspectRatio.cx)) / LONGLONG(m_aspectRatio.cy); + } + + if (m_bDefaultVideoAngleSwitchAR) { + std::swap(videoSize.cx, videoSize.cy); + } + + return videoSize; +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetPosition(RECT w, RECT v) +{ + bool bWindowPosChanged = !!(m_windowRect != w); + bool bWindowSizeChanged = !!(m_windowRect.Size() != CRect(w).Size()); + bool bVideoRectChanged = !!(m_videoRect != v); + + m_windowRect = w; + m_videoRect = v; + + if (m_pAllocator && (bWindowPosChanged || bWindowSizeChanged || bVideoRectChanged)) { + if (m_windowRect.Width() != m_curSubtitleTextureSize.cx || m_windowRect.Height() != m_curSubtitleTextureSize.cy) { + int maxpixels = m_maxSubtitleTextureSize.cx * m_maxSubtitleTextureSize.cy; + if (m_windowRect.Width() * m_windowRect.Height() <= maxpixels) { + // use window size + m_curSubtitleTextureSize = CSize(m_windowRect.Width(), m_windowRect.Height()); + } else { + bool correct_ar = false; + if (m_maxSubtitleTextureSize.cx == 2560 && m_windowRect.Width() >= 3800 && m_windowRect.Width() <= 4096) { // not 3840, to handle a maximized window as well + m_curSubtitleTextureSize = CSize(m_windowRect.Width() / 2, m_windowRect.Height() / 2); + } else { + m_curSubtitleTextureSize = CSize(m_maxSubtitleTextureSize.cx, m_maxSubtitleTextureSize.cy); + correct_ar = true; + } + + if (correct_ar) { + double new_w = sqrt((uint64_t)m_curSubtitleTextureSize.cx * m_curSubtitleTextureSize.cy * m_windowRect.Width() / m_windowRect.Height()); + double new_h = sqrt((uint64_t)m_curSubtitleTextureSize.cx * m_curSubtitleTextureSize.cy * m_windowRect.Height() / m_windowRect.Width()); + m_curSubtitleTextureSize.cx = lround(new_w); + m_curSubtitleTextureSize.cy = lround(new_h); + } + } + } + + m_pAllocator->SetMaxTextureSize(m_curSubtitleTextureSize); + m_pAllocator->SetCurSize(m_windowRect.Size()); + m_pAllocator->SetCurVidRect(m_videoRect); + + if (m_pSubPicQueue) { + m_pSubPicQueue->Invalidate(); + } + } + + if (bWindowPosChanged || bVideoRectChanged || m_bOtherTransform) { + Paint(false); + m_bOtherTransform = false; + } +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetTime(REFERENCE_TIME rtNow) +{ + m_rtNow = rtNow - m_rtSubtitleDelay; + + if (m_pSubPicQueue) { + m_pSubPicQueue->SetTime(m_rtNow); + } +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetSubtitleDelay(int delayMs) +{ + REFERENCE_TIME delay = MILLISECONDS_TO_100NS_UNITS(delayMs); + if (m_rtSubtitleDelay != delay) { + REFERENCE_TIME oldDelay = m_rtSubtitleDelay; + m_rtSubtitleDelay = delay; + SetTime(m_rtNow + oldDelay); + Paint(false); + } +} + +STDMETHODIMP_(int) CSubPicAllocatorPresenterImpl::GetSubtitleDelay() const +{ + return (int)(m_rtSubtitleDelay / 10000); +} + +STDMETHODIMP_(double) CSubPicAllocatorPresenterImpl::GetFPS() const +{ + return m_fps; +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider) +{ + CAutoLock cAutoLock(&m_csSubPicProvider); + + m_pSubPicProvider = pSubPicProvider; + + if (m_pSubPicQueue) { + m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); + } + + if (m_pAllocator) { + m_pAllocator->SetCurSize(CSize(m_windowRect.Width(), m_windowRect.Height())); + m_pAllocator->SetCurVidRect(m_videoRect); + } + + Paint(false); +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::Invalidate(REFERENCE_TIME rtInvalidate) +{ + if (m_pSubPicQueue) { + m_pSubPicQueue->Invalidate(rtInvalidate); + } +} + +void CSubPicAllocatorPresenterImpl::Transform(CRect r, Vector v[4]) +{ + v[0] = Vector((float)r.left, (float)r.top, 0); + v[1] = Vector((float)r.right, (float)r.top, 0); + v[2] = Vector((float)r.left, (float)r.bottom, 0); + v[3] = Vector((float)r.right, (float)r.bottom, 0); + + Vector center((float)r.CenterPoint().x, (float)r.CenterPoint().y, 0); + int l = (int)(Vector((float)r.Size().cx, (float)r.Size().cy, 0).Length() * 1.5f) + 1; + + for (size_t i = 0; i < 4; i++) { + v[i] = m_xform << (v[i] - center); + v[i].z = v[i].z / l + 0.5f; + v[i].x /= v[i].z * 2; + v[i].y /= v[i].z * 2; + v[i] += center; + } +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetDefaultVideoAngle(Vector v) +{ + if (m_defaultVideoAngle != v) { + constexpr float pi_2 = float(M_PI_2); + + // In theory it should be a multiple of 90 + int zAnglePi2 = std::lround(v.z / pi_2); + //ASSERT(zAnglePi2 * pi_2 == v.z); + + // Normalize the Z angle + zAnglePi2 %= 4; + if (zAnglePi2 < 0) { + zAnglePi2 += 4; + } + v.z = zAnglePi2 * pi_2; + + // Check if the default rotation change the AR + m_bDefaultVideoAngleSwitchAR = (v.z == pi_2 || v.z == 3.0f * pi_2); + + m_defaultVideoAngle = v; + UpdateXForm(); + return S_OK; + } + return S_FALSE; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetVideoAngle(Vector v) +{ + if (m_videoAngle != v) { + m_videoAngle = v; + UpdateXForm(); + return S_OK; + } + return S_FALSE; +} + +void CSubPicAllocatorPresenterImpl::UpdateXForm() +{ + Vector v = m_defaultVideoAngle + m_videoAngle; + + auto normalizeAngle = [](float & rad) { + constexpr float twoPi = float(2.0 * M_PI); + + while (rad < 0.0f) { + rad += twoPi; + } + while (rad > twoPi) { + rad -= twoPi; + } + }; + + normalizeAngle(v.x); + normalizeAngle(v.y); + normalizeAngle(v.z); + + CSize AR = GetVideoSize(true); + float fARCorrection = m_bDefaultVideoAngleSwitchAR ? float(AR.cx) / AR.cy : 1.0f; + + m_xform = XForm(Ray(Vector(), v), Vector(1.0f / fARCorrection, fARCorrection, 1.0f), false); + + Paint(false); +} + +HRESULT CSubPicAllocatorPresenterImpl::CreateDIBFromSurfaceData(D3DSURFACE_DESC desc, D3DLOCKED_RECT r, BYTE* lpDib) const +{ + bool bNeedRotation = !IsEqual(m_defaultVideoAngle.z, 0.0f); + + BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)lpDib; + ZeroMemory(bih, sizeof(BITMAPINFOHEADER)); + bih->biSize = sizeof(BITMAPINFOHEADER); + bih->biWidth = desc.Width; + bih->biHeight = desc.Height; + bih->biBitCount = 32; + bih->biPlanes = 1; + bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount >> 3; + + UINT* pBits; + if (bNeedRotation) { + pBits = (UINT*)malloc(bih->biSizeImage); + if (!pBits) { + return E_OUTOFMEMORY; + } + } else { + pBits = (UINT*)(bih + 1); + } + + BitBltFromRGBToRGB(bih->biWidth, bih->biHeight, + (BYTE*)pBits, bih->biWidth * bih->biBitCount >> 3, bih->biBitCount, + (BYTE*)r.pBits + r.Pitch * (desc.Height - 1), -r.Pitch, 32); + + if (bNeedRotation) { + constexpr float pi_2 = float(M_PI_2); + + if (m_bDefaultVideoAngleSwitchAR) { + std::swap(bih->biWidth, bih->biHeight); + } + + std::function convCoordinates; + if (IsEqual(m_defaultVideoAngle.z, pi_2)) { + convCoordinates = [desc](UINT x, UINT y) { + return x * desc.Height + desc.Height - 1 - y; + }; + } else if (IsEqual(m_defaultVideoAngle.z, 2 * pi_2)) { + convCoordinates = [desc](UINT x, UINT y) { + return desc.Width - 1 - x + (desc.Height - 1 - y) * desc.Width; + }; + } else { + ASSERT(IsEqual(m_defaultVideoAngle.z, 3 * pi_2)); + convCoordinates = [desc](UINT x, UINT y) { + return (desc.Width - 1 - x) * desc.Height + y; + }; + } + + UINT* pBitsDest = (UINT*)(bih + 1); + for (UINT x = 0; x < desc.Width; x++) { + for (UINT y = 0; y < desc.Height; y++) { + pBitsDest[convCoordinates(x, y)] = pBits[x + y * desc.Width]; + } + } + + free(pBits); + } + + return S_OK; +} + +// ISubRenderOptions + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetBool(LPCSTR field, bool* value) +{ + CheckPointer(value, E_POINTER); + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetInt(LPCSTR field, int* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "supportedLevels")) { + if (CComQIPtr pEVR = (ISubPicAllocatorPresenter*)this) { + const CRenderersSettings& r = GetRenderersSettings(); + if (r.m_AdvRendSets.iEVROutputRange == 1) { + *value = 3; // TV preferred + } else { + *value = 2; // PC preferred + } + } else { + *value = 0; // PC only + } + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetSize(LPCSTR field, SIZE* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "originalVideoSize")) { + *value = GetVideoSize(false); + return S_OK; + } else if (!strcmp(field, "arAdjustedVideoSize")) { + *value = GetVideoSize(true); + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetRect(LPCSTR field, RECT* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "videoOutputRect") || !strcmp(field, "subtitleTargetRect")) { + if (m_videoRect.IsRectEmpty()) { + *value = m_windowRect; + } else { + value->left = 0; + value->top = 0; + value->right = m_videoRect.Width(); + value->bottom = m_videoRect.Height(); + } + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetUlonglong(LPCSTR field, ULONGLONG* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "frameRate")) { + *value = (REFERENCE_TIME)(10000000.0 / m_fps); + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetDouble(LPCSTR field, double* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "refreshRate")) { + *value = 1000.0 / m_refreshRate; + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetString(LPCSTR field, LPWSTR* value, int* chars) +{ + CheckPointer(value, E_POINTER); + CheckPointer(chars, E_POINTER); + CStringW ret = nullptr; + + if (!strcmp(field, "name")) { + ret = L"MPC-HC"; + } else if (!strcmp(field, "version")) { + ret = VersionInfo::GetVersionString(); + } else if (!strcmp(field, "yuvMatrix")) { + ret = L"None"; + + if (m_inputMediaType.IsValid() && m_inputMediaType.formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* pVIH2 = (VIDEOINFOHEADER2*)m_inputMediaType.pbFormat; + + if (pVIH2->dwControlFlags & AMCONTROL_COLORINFO_PRESENT) { + DXVA2_ExtendedFormat& flags = (DXVA2_ExtendedFormat&)pVIH2->dwControlFlags; + + ret = (flags.NominalRange == DXVA2_NominalRange_Normal) ? L"PC." : L"TV."; + + switch (flags.VideoTransferMatrix) { + case DXVA2_VideoTransferMatrix_BT601: + ret.Append(L"601"); + break; + case DXVA2_VideoTransferMatrix_BT709: + ret.Append(L"709"); + break; + case DXVA2_VideoTransferMatrix_SMPTE240M: + ret.Append(L"240M"); + break; + case 4: + ret.Append(L"2020"); + break; + default: + ret = L"None"; + break; + } + } + } + } + + if (!ret.IsEmpty()) { + int len = ret.GetLength(); + size_t sz = (len + 1) * sizeof(WCHAR); + LPWSTR buf = (LPWSTR)LocalAlloc(LPTR, sz); + + if (!buf) { + return E_OUTOFMEMORY; + } + + wcscpy_s(buf, len + 1, ret); + *chars = len; + *value = buf; + + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetBin(LPCSTR field, LPVOID* value, int* size) +{ + CheckPointer(value, E_POINTER); + CheckPointer(size, E_POINTER); + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetBool(LPCSTR field, bool value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetInt(LPCSTR field, int value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetSize(LPCSTR field, SIZE value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetRect(LPCSTR field, RECT value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetUlonglong(LPCSTR field, ULONGLONG value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetDouble(LPCSTR field, double value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetString(LPCSTR field, LPWSTR value, int chars) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetBin(LPCSTR field, LPVOID value, int size) +{ + return E_INVALIDARG; +} + +// ISubRenderConsumer + +STDMETHODIMP CSubPicAllocatorPresenterImpl::Connect(ISubRenderProvider* subtitleRenderer) +{ + HRESULT hr = E_FAIL; + + if (m_pSubPicProvider) { + return hr; + } + + hr = subtitleRenderer->SetBool("combineBitmaps", true); + if (FAILED(hr)) { + return hr; + } + + if (CComQIPtr pSubConsumer = m_pSubPicQueue) { + hr = pSubConsumer->Connect(subtitleRenderer); + } else { + CComPtr pSubPicProvider = (ISubPicProvider*)DEBUG_NEW CXySubPicProvider(subtitleRenderer); + CComPtr pSubPicQueue = (ISubPicQueue*)DEBUG_NEW CXySubPicQueueNoThread(m_pAllocator, &hr); + + if (SUCCEEDED(hr)) { + pSubPicQueue->SetSubPicProvider(pSubPicProvider); + m_pSubPicProvider = pSubPicProvider; + m_pSubPicQueue = pSubPicQueue; + m_pAllocator->SetInverseAlpha(true); + } + } + + return hr; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::Disconnect() +{ + m_pSubPicProvider = nullptr; + return m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::DeliverFrame(REFERENCE_TIME start, REFERENCE_TIME stop, LPVOID context, ISubRenderFrame* subtitleFrame) +{ + HRESULT hr = E_FAIL; + + if (CComQIPtr pXyProvider = m_pSubPicProvider) { + hr = pXyProvider->DeliverFrame(start, stop, context, subtitleFrame); + } + + return hr; +} + +// ISubRenderConsumer2 + +STDMETHODIMP CSubPicAllocatorPresenterImpl::Clear(REFERENCE_TIME clearNewerThan /* = 0 */) +{ + return m_pSubPicQueue->Invalidate(clearNewerThan); +} diff --git a/src/SubPic/SubPicAllocatorPresenterImpl.h b/src/SubPic/SubPicAllocatorPresenterImpl.h index 8d0a964d30e..053a71d72e4 100644 --- a/src/SubPic/SubPicAllocatorPresenterImpl.h +++ b/src/SubPic/SubPicAllocatorPresenterImpl.h @@ -1,175 +1,175 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#pragma once - -#include -#include -#include -#include "ISubPic.h" -#include "CoordGeom.h" -#include "SubRenderIntf.h" -#include "ScreenUtil.h" - -class CSubPicAllocatorPresenterImpl - : public CUnknown - , public CCritSec - , public ISubPicAllocatorPresenter3 - , public ISubRenderConsumer2 -{ -private: - CCritSec m_csSubPicProvider; - -protected: - HWND m_hWnd; - REFERENCE_TIME m_rtSubtitleDelay; - - CSize m_maxSubtitleTextureSize; - CSize m_curSubtitleTextureSize; - CSize m_nativeVideoSize, m_aspectRatio; - CRect m_videoRect, m_windowRect; - bool m_bOtherTransform = false; - - REFERENCE_TIME m_rtNow = 0; - double m_fps = 25.0; - UINT m_refreshRate = 0; - - CMediaType m_inputMediaType; - - CComPtr m_pSubPicProvider; - CComPtr m_pAllocator; - CComPtr m_pSubPicQueue; - - bool m_bDeviceResetRequested; - bool m_bPendingResetDevice; - - void InitMaxSubtitleTextureSize(int maxSizeX, int maxSizeY, CSize largestScreen); - - HRESULT AlphaBltSubPic(const CRect& windowRect, - const CRect& videoRect, - SubPicDesc* pTarget = nullptr, - const double videoStretchFactor = 1.0, - int xOffsetInPixels = 0, int yOffsetInPixels = 0); - - void UpdateXForm(); - HRESULT CreateDIBFromSurfaceData(D3DSURFACE_DESC desc, D3DLOCKED_RECT r, BYTE* lpDib) const; - - Vector m_defaultVideoAngle, m_videoAngle; - bool m_bDefaultVideoAngleSwitchAR; - XForm m_xform; - void Transform(CRect r, Vector v[4]); - - bool m_bHookedNewSegment; - bool m_bHookedReceive; - -public: - CSubPicAllocatorPresenterImpl(HWND hWnd, HRESULT& hr, CString* _pError); - virtual ~CSubPicAllocatorPresenterImpl(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - STDMETHODIMP_(void) SetVideoSize(CSize szVideo, CSize szAspectRatio = CSize(0, 0)); - - // ISubPicAllocatorPresenter - - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer) PURE; - STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const; - STDMETHODIMP_(void) SetPosition(RECT w, RECT v); - STDMETHODIMP_(bool) Paint(bool bAll) PURE; - STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow); - STDMETHODIMP_(void) SetSubtitleDelay(int delayMs); - STDMETHODIMP_(int) GetSubtitleDelay() const; - STDMETHODIMP_(double) GetFPS() const; - STDMETHODIMP_(void) SetSubPicProvider(ISubPicProvider* pSubPicProvider); - STDMETHODIMP_(void) Invalidate(REFERENCE_TIME rtInvalidate = -1); - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size) { return E_NOTIMPL; } - STDMETHODIMP GetDisplayedImage(LPVOID* dibImage) { return E_NOTIMPL; } - STDMETHODIMP SetVideoAngle(Vector v); - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) { return E_NOTIMPL; } - STDMETHODIMP_(bool) ResetDevice() { return false; } - STDMETHODIMP_(bool) DisplayChange() { return false; } - STDMETHODIMP_(void) GetPosition(RECT* windowRect, RECT* videoRect) { *windowRect = m_windowRect; *videoRect = m_videoRect; } - STDMETHODIMP_(void) SetVideoMediaType(CMediaType input) { m_inputMediaType = input; } - - // ISubPicAllocatorPresenter2 - - STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) { - if (!bScreenSpace) { - return SetPixelShader(pSrcData, pTarget); - } - return E_NOTIMPL; - } - - STDMETHODIMP_(SIZE) GetVisibleVideoSize() const { - return m_nativeVideoSize; - } - - STDMETHODIMP SetIsRendering(bool bIsRendering) { return E_NOTIMPL; } - STDMETHODIMP_(bool) IsRendering() { return true; } - STDMETHODIMP SetDefaultVideoAngle(Vector v); - - // ISubPicAllocatorPresenter3 - - STDMETHODIMP SetRotation(int rotation) { return E_NOTIMPL; } - STDMETHODIMP_(int) GetRotation() { return 0; } - STDMETHODIMP SetFlip(bool flip) { return E_NOTIMPL; } - STDMETHODIMP_(bool) GetFlip() { return false; } - STDMETHODIMP GetVideoFrame(BYTE* lpDib, DWORD* size) { return E_NOTIMPL; } - STDMETHODIMP_(int) GetPixelShaderMode() { return 0; } - STDMETHODIMP ClearPixelShaders(int target) { return E_NOTIMPL; } - STDMETHODIMP AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) { return E_NOTIMPL; } - STDMETHODIMP_(bool) ResizeDevice() { return false; } - STDMETHODIMP_(bool) ToggleStats() { return false; } - - // ISubRenderOptions - - STDMETHODIMP GetBool(LPCSTR field, bool* value); - STDMETHODIMP GetInt(LPCSTR field, int* value); - STDMETHODIMP GetSize(LPCSTR field, SIZE* value); - STDMETHODIMP GetRect(LPCSTR field, RECT* value); - STDMETHODIMP GetUlonglong(LPCSTR field, ULONGLONG* value); - STDMETHODIMP GetDouble(LPCSTR field, double* value); - STDMETHODIMP GetString(LPCSTR field, LPWSTR* value, int* chars); - STDMETHODIMP GetBin(LPCSTR field, LPVOID* value, int* size); - STDMETHODIMP SetBool(LPCSTR field, bool value); - STDMETHODIMP SetInt(LPCSTR field, int value); - STDMETHODIMP SetSize(LPCSTR field, SIZE value); - STDMETHODIMP SetRect(LPCSTR field, RECT value); - STDMETHODIMP SetUlonglong(LPCSTR field, ULONGLONG value); - STDMETHODIMP SetDouble(LPCSTR field, double value); - STDMETHODIMP SetString(LPCSTR field, LPWSTR value, int chars); - STDMETHODIMP SetBin(LPCSTR field, LPVOID value, int size); - - // ISubRenderConsumer - - STDMETHODIMP GetMerit(ULONG* plMerit) { - CheckPointer(plMerit, E_POINTER); - *plMerit = 4 << 16; - return S_OK; - } - STDMETHODIMP Connect(ISubRenderProvider* subtitleRenderer); - STDMETHODIMP Disconnect(); - STDMETHODIMP DeliverFrame(REFERENCE_TIME start, REFERENCE_TIME stop, LPVOID context, ISubRenderFrame* subtitleFrame); - - // ISubRenderConsumer2 - - STDMETHODIMP Clear(REFERENCE_TIME clearNewerThan = 0); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#pragma once + +#include +#include +#include +#include "ISubPic.h" +#include "CoordGeom.h" +#include "SubRenderIntf.h" +#include "ScreenUtil.h" + +class CSubPicAllocatorPresenterImpl + : public CUnknown + , public CCritSec + , public ISubPicAllocatorPresenter3 + , public ISubRenderConsumer2 +{ +private: + CCritSec m_csSubPicProvider; + +protected: + HWND m_hWnd; + REFERENCE_TIME m_rtSubtitleDelay; + + CSize m_maxSubtitleTextureSize; + CSize m_curSubtitleTextureSize; + CSize m_nativeVideoSize, m_aspectRatio; + CRect m_videoRect, m_windowRect; + bool m_bOtherTransform = false; + + REFERENCE_TIME m_rtNow = 0; + double m_fps = 25.0; + UINT m_refreshRate = 0; + + CMediaType m_inputMediaType; + + CComPtr m_pSubPicProvider; + CComPtr m_pAllocator; + CComPtr m_pSubPicQueue; + + bool m_bDeviceResetRequested; + bool m_bPendingResetDevice; + + void InitMaxSubtitleTextureSize(int maxSizeX, int maxSizeY, CSize largestScreen); + + HRESULT AlphaBltSubPic(const CRect& windowRect, + const CRect& videoRect, + SubPicDesc* pTarget = nullptr, + const double videoStretchFactor = 1.0, + int xOffsetInPixels = 0, int yOffsetInPixels = 0); + + void UpdateXForm(); + HRESULT CreateDIBFromSurfaceData(D3DSURFACE_DESC desc, D3DLOCKED_RECT r, BYTE* lpDib) const; + + Vector m_defaultVideoAngle, m_videoAngle; + bool m_bDefaultVideoAngleSwitchAR; + XForm m_xform; + void Transform(CRect r, Vector v[4]); + + bool m_bHookedNewSegment; + bool m_bHookedReceive; + +public: + CSubPicAllocatorPresenterImpl(HWND hWnd, HRESULT& hr, CString* _pError); + virtual ~CSubPicAllocatorPresenterImpl(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + STDMETHODIMP_(void) SetVideoSize(CSize szVideo, CSize szAspectRatio = CSize(0, 0)); + + // ISubPicAllocatorPresenter + + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer) PURE; + STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const; + STDMETHODIMP_(void) SetPosition(RECT w, RECT v); + STDMETHODIMP_(bool) Paint(bool bAll) PURE; + STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow); + STDMETHODIMP_(void) SetSubtitleDelay(int delayMs); + STDMETHODIMP_(int) GetSubtitleDelay() const; + STDMETHODIMP_(double) GetFPS() const; + STDMETHODIMP_(void) SetSubPicProvider(ISubPicProvider* pSubPicProvider); + STDMETHODIMP_(void) Invalidate(REFERENCE_TIME rtInvalidate = -1); + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size) { return E_NOTIMPL; } + STDMETHODIMP GetDisplayedImage(LPVOID* dibImage) { return E_NOTIMPL; } + STDMETHODIMP SetVideoAngle(Vector v); + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) { return E_NOTIMPL; } + STDMETHODIMP_(bool) ResetDevice() { return false; } + STDMETHODIMP_(bool) DisplayChange() { return false; } + STDMETHODIMP_(void) GetPosition(RECT* windowRect, RECT* videoRect) { *windowRect = m_windowRect; *videoRect = m_videoRect; } + STDMETHODIMP_(void) SetVideoMediaType(CMediaType input) { m_inputMediaType = input; } + + // ISubPicAllocatorPresenter2 + + STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) { + if (!bScreenSpace) { + return SetPixelShader(pSrcData, pTarget); + } + return E_NOTIMPL; + } + + STDMETHODIMP_(SIZE) GetVisibleVideoSize() const { + return m_nativeVideoSize; + } + + STDMETHODIMP SetIsRendering(bool bIsRendering) { return E_NOTIMPL; } + STDMETHODIMP_(bool) IsRendering() { return true; } + STDMETHODIMP SetDefaultVideoAngle(Vector v); + + // ISubPicAllocatorPresenter3 + + STDMETHODIMP SetRotation(int rotation) { return E_NOTIMPL; } + STDMETHODIMP_(int) GetRotation() { return 0; } + STDMETHODIMP SetFlip(bool flip) { return E_NOTIMPL; } + STDMETHODIMP_(bool) GetFlip() { return false; } + STDMETHODIMP GetVideoFrame(BYTE* lpDib, DWORD* size) { return E_NOTIMPL; } + STDMETHODIMP_(int) GetPixelShaderMode() { return 0; } + STDMETHODIMP ClearPixelShaders(int target) { return E_NOTIMPL; } + STDMETHODIMP AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) { return E_NOTIMPL; } + STDMETHODIMP_(bool) ResizeDevice() { return false; } + STDMETHODIMP_(bool) ToggleStats() { return false; } + + // ISubRenderOptions + + STDMETHODIMP GetBool(LPCSTR field, bool* value); + STDMETHODIMP GetInt(LPCSTR field, int* value); + STDMETHODIMP GetSize(LPCSTR field, SIZE* value); + STDMETHODIMP GetRect(LPCSTR field, RECT* value); + STDMETHODIMP GetUlonglong(LPCSTR field, ULONGLONG* value); + STDMETHODIMP GetDouble(LPCSTR field, double* value); + STDMETHODIMP GetString(LPCSTR field, LPWSTR* value, int* chars); + STDMETHODIMP GetBin(LPCSTR field, LPVOID* value, int* size); + STDMETHODIMP SetBool(LPCSTR field, bool value); + STDMETHODIMP SetInt(LPCSTR field, int value); + STDMETHODIMP SetSize(LPCSTR field, SIZE value); + STDMETHODIMP SetRect(LPCSTR field, RECT value); + STDMETHODIMP SetUlonglong(LPCSTR field, ULONGLONG value); + STDMETHODIMP SetDouble(LPCSTR field, double value); + STDMETHODIMP SetString(LPCSTR field, LPWSTR value, int chars); + STDMETHODIMP SetBin(LPCSTR field, LPVOID value, int size); + + // ISubRenderConsumer + + STDMETHODIMP GetMerit(ULONG* plMerit) { + CheckPointer(plMerit, E_POINTER); + *plMerit = 4 << 16; + return S_OK; + } + STDMETHODIMP Connect(ISubRenderProvider* subtitleRenderer); + STDMETHODIMP Disconnect(); + STDMETHODIMP DeliverFrame(REFERENCE_TIME start, REFERENCE_TIME stop, LPVOID context, ISubRenderFrame* subtitleFrame); + + // ISubRenderConsumer2 + + STDMETHODIMP Clear(REFERENCE_TIME clearNewerThan = 0); +}; diff --git a/src/SubPic/SubPicImpl.cpp b/src/SubPic/SubPicImpl.cpp index 1cafbf88986..f49adaba4a8 100644 --- a/src/SubPic/SubPicImpl.cpp +++ b/src/SubPic/SubPicImpl.cpp @@ -1,434 +1,434 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "SubPicImpl.h" -#include "../DSUtil/DSUtil.h" - -#include "mpc-hc_config.h" - -#if !TRACE_SUBTITLES -#define TRACE(...) -#endif - -// -// CSubPicImpl -// - -CSubPicImpl::CSubPicImpl() - : CUnknown(NAME("CSubPicImpl"), nullptr) - , m_rtStart(0) - , m_rtStop(0) - , m_rtSegmentStart(0) - , m_rtSegmentStop(0) - , m_rcDirty(0, 0, 0, 0) - , m_maxsize(0, 0) - , m_size(0, 0) - , m_vidrect(0, 0, 0, 0) - , m_virtualTextureSize(0, 0) - , m_virtualTextureTopLeft(0, 0) - , m_bInvAlpha(false) - , m_relativeTo(WINDOW) -{ -} - -STDMETHODIMP CSubPicImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(ISubPic) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPic - -STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetStart() const -{ - return m_rtStart; -} - -STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetStop() const -{ - return m_rtStop; -} - -STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetSegmentStart() const -{ - return m_rtSegmentStart >= 0 ? m_rtSegmentStart : m_rtStart; -} - -STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetSegmentStop() const -{ - return m_rtSegmentStop >= 0 ? m_rtSegmentStop : m_rtStop; -} - -STDMETHODIMP_(void) CSubPicImpl::SetSegmentStart(REFERENCE_TIME rtStart) -{ - m_rtSegmentStart = rtStart; -} - -STDMETHODIMP_(void) CSubPicImpl::SetSegmentStop(REFERENCE_TIME rtStop) -{ - m_rtSegmentStop = rtStop; -} - -STDMETHODIMP_(void) CSubPicImpl::SetStart(REFERENCE_TIME rtStart) -{ - m_rtStart = rtStart; -} - -STDMETHODIMP_(void) CSubPicImpl::SetStop(REFERENCE_TIME rtStop) -{ - m_rtStop = rtStop; -} - -STDMETHODIMP CSubPicImpl::CopyTo(ISubPic* pSubPic) -{ - CheckPointer(pSubPic, E_POINTER); - - pSubPic->SetStart(m_rtStart); - pSubPic->SetStop(m_rtStop); - pSubPic->SetSegmentStart(m_rtSegmentStart); - pSubPic->SetSegmentStop(m_rtSegmentStop); - pSubPic->SetDirtyRect(m_rcDirty); - pSubPic->SetSize(m_size, m_vidrect); - pSubPic->SetVirtualTextureSize(m_virtualTextureSize, m_virtualTextureTopLeft); - pSubPic->SetInverseAlpha(m_bInvAlpha); - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::GetDirtyRect(RECT* pDirtyRect) const -{ - CheckPointer(pDirtyRect, E_POINTER); - - *pDirtyRect = m_rcDirty; - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::GetSourceAndDest(RECT rcWindow, RECT rcVideo, - RECT* pRcSource, RECT* pRcDest, - const double videoStretchFactor /*= 1.0*/, - int xOffsetInPixels /*= 0*/, int yOffsetInPixels /*= 0*/) const -{ - CheckPointer(pRcSource, E_POINTER); - CheckPointer(pRcDest, E_POINTER); - - if (m_size.cx > 0 && m_size.cy > 0 && m_rcDirty.Height() > 0) { - CRect videoRect(rcVideo); - CRect windowRect(rcWindow); - - CRect originalDirtyRect = m_rcDirty; - *pRcSource = originalDirtyRect; - originalDirtyRect.OffsetRect(m_virtualTextureTopLeft); - - CRect targetDirtyRect; - - // check if scaling is needed - if (videoRect.Size() != windowRect.Size() || videoRect.Size() != m_virtualTextureSize) { - if (m_relativeTo == BEST_FIT && m_virtualTextureSize.cx > 720 && videoStretchFactor == 1.0) { - CRect visibleRect; - visibleRect.top = videoRect.top > windowRect.top ? (videoRect.top > windowRect.bottom ? windowRect.bottom : videoRect.top) : windowRect.top; - visibleRect.bottom = videoRect.bottom < windowRect.bottom ? (videoRect.bottom < windowRect.top ? windowRect.top : videoRect.bottom) : windowRect.bottom; - visibleRect.left = videoRect.left > windowRect.left ? (videoRect.left > windowRect.right ? windowRect.right : videoRect.left) : windowRect.left; - visibleRect.right = videoRect.right < windowRect.right ? (videoRect.right < windowRect.left ? windowRect.left : videoRect.right) : windowRect.right; - if (visibleRect.Width() <= 0 || visibleRect.Height() <= 0) { - visibleRect = windowRect; - ASSERT(false); - } - CPoint offset(0, 0); - double scaleFactor; - double subtitleAR = double(m_virtualTextureSize.cx) / m_virtualTextureSize.cy; - double visibleAR = double(visibleRect.Width()) / visibleRect.Height(); - double vertical_stretch = 1.0; - if (visibleAR * 2 - subtitleAR < 0.01) { - // some PGS can be encoded with resolution at half height - vertical_stretch = 2.0; - subtitleAR /= 2.0; - } - - if (visibleAR == subtitleAR) { - // exact same AR - scaleFactor = double(visibleRect.Width()) / m_virtualTextureSize.cx; - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(visibleRect.TopLeft()); - } else if (visibleAR > subtitleAR) { - // video is cropped in height - scaleFactor = double(visibleRect.Width()) / m_virtualTextureSize.cx; - int extraheight = m_virtualTextureSize.cy * scaleFactor * vertical_stretch - visibleRect.Height(); - CRect expandedRect = visibleRect; - expandedRect.top -= extraheight / 2; - expandedRect.bottom += extraheight - extraheight / 2; - offset.x = expandedRect.left; - offset.y = expandedRect.top; - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(offset); - - if (expandedRect.left >= windowRect.left && expandedRect.top >= windowRect.top && expandedRect.right <= windowRect.right && expandedRect.bottom <= windowRect.bottom) { - // expanded fits in window - } else { - if (targetDirtyRect.left >= windowRect.left && targetDirtyRect.top >= windowRect.top && targetDirtyRect.right <= windowRect.right && targetDirtyRect.bottom <= windowRect.bottom) { - // dirty rect fits in window - } else { - // does not fit yet, rescale based on available window height - scaleFactor = double(windowRect.Height()) / m_virtualTextureSize.cy / vertical_stretch; - offset.x = lround((windowRect.Width() - scaleFactor * m_virtualTextureSize.cx) / 2.0); - offset.y = 0; - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(offset); - } - } - } else { - // video is cropped in width - scaleFactor = double(visibleRect.Height()) / m_virtualTextureSize.cy / vertical_stretch; - int extrawidth = m_virtualTextureSize.cx * scaleFactor - visibleRect.Width(); - CRect expandedRect = visibleRect; - expandedRect.left -= extrawidth / 2; - expandedRect.right += extrawidth - extrawidth / 2; - offset.x = expandedRect.left; - offset.y = expandedRect.top; - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(offset); - - if (expandedRect.left >= windowRect.left && expandedRect.top >= windowRect.top && expandedRect.right <= windowRect.right && expandedRect.bottom <= windowRect.bottom) { - // expanded fits in window - } else { - if (targetDirtyRect.left >= windowRect.left && targetDirtyRect.top >= windowRect.top && targetDirtyRect.right <= windowRect.right && targetDirtyRect.bottom <= windowRect.bottom) { - // dirty rect fits in window - } else { - // does not fit yet, rescale based on available window width - scaleFactor = double(windowRect.Width()) / m_virtualTextureSize.cx; - offset.x = 0; - offset.y = lround((windowRect.Height() - scaleFactor * m_virtualTextureSize.cy * vertical_stretch) / 2.0); - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(offset); - } - } - } - } else { - CRect rcTarget = (m_relativeTo == WINDOW) ? windowRect : videoRect; - CSize szTarget = rcTarget.Size(); - double scaleX = double(szTarget.cx) / m_virtualTextureSize.cx; - double scaleY = double(szTarget.cy) / m_virtualTextureSize.cy; - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleX), lround(originalDirtyRect.top * scaleY), lround(originalDirtyRect.right * scaleX), lround(originalDirtyRect.bottom * scaleY)); - targetDirtyRect.OffsetRect(rcTarget.TopLeft()); - } - } else { - // no scaling needed - targetDirtyRect = originalDirtyRect; - } - - if (videoStretchFactor != 1.0) { - ASSERT(FALSE); - // FIXME: when is videoStretchFactor not equal to 1.0? Test that situation. Only madvr might possibly use it. Our own renderers do not. - LONG stretch = lround(targetDirtyRect.Width() * (1.0 - 1.0 / videoStretchFactor) / 2.0); - targetDirtyRect.left += stretch; - targetDirtyRect.right -= stretch; - } - - targetDirtyRect.OffsetRect(CPoint(xOffsetInPixels, yOffsetInPixels)); - - *pRcDest = targetDirtyRect; - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicImpl::SetDirtyRect(const RECT* pDirtyRect) -{ - CheckPointer(pDirtyRect, E_POINTER); - - m_rcDirty = *pDirtyRect; - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::GetMaxSize(SIZE* pMaxSize) const -{ - CheckPointer(pMaxSize, E_POINTER); - - *pMaxSize = m_maxsize; - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::SetSize(SIZE size, RECT vidrect) -{ - m_size = size; - if (m_size.cx > m_maxsize.cx) { - m_size.cy = MulDiv(m_size.cy, m_maxsize.cx, m_size.cx); - m_size.cx = m_maxsize.cx; - } - if (m_size.cy > m_maxsize.cy) { - m_size.cx = MulDiv(m_size.cx, m_maxsize.cy, m_size.cy); - m_size.cy = m_maxsize.cy; - } - m_virtualTextureSize = m_size; - - m_vidrect = vidrect; - if (m_size.cx != size.cx || m_size.cy != size.cy) { - m_vidrect.top = MulDiv(m_vidrect.top, m_size.cx, size.cx); - m_vidrect.bottom = MulDiv(m_vidrect.bottom, m_size.cx, size.cx); - m_vidrect.left = MulDiv(m_vidrect.left, m_size.cy, size.cy); - m_vidrect.right = MulDiv(m_vidrect.right, m_size.cy, size.cy); - } - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::SetVirtualTextureSize(const SIZE pSize, const POINT pTopLeft) -{ - m_virtualTextureSize.SetSize(pSize.cx, pSize.cy); - m_virtualTextureTopLeft.SetPoint(pTopLeft.x, pTopLeft.y); - - return S_OK; -} - -STDMETHODIMP_(void) CSubPicImpl::SetInverseAlpha(bool bInverted) -{ - m_bInvAlpha = bInverted; -} - -STDMETHODIMP CSubPicImpl::GetRelativeTo(RelativeTo* pRelativeTo) const -{ - CheckPointer(pRelativeTo, E_POINTER); - - *pRelativeTo = m_relativeTo; - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::SetRelativeTo(RelativeTo relativeTo) -{ - m_relativeTo = relativeTo; - - return S_OK; -} - -// -// ISubPicAllocatorImpl -// - -CSubPicAllocatorImpl::CSubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly) - : CUnknown(NAME("ISubPicAllocatorImpl"), nullptr) - , m_cursize(cursize) - , m_fDynamicWriteOnly(fDynamicWriteOnly) -{ - m_curvidrect = CRect(CPoint(0, 0), m_cursize); -} - -STDMETHODIMP CSubPicAllocatorImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(ISubPicAllocator) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPicAllocator - -STDMETHODIMP CSubPicAllocatorImpl::SetCurSize(SIZE cursize) -{ -#if DEBUG_OVERRIDE_TEXTURE_SIZE - cursize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); -#endif - if (m_cursize != cursize) { - TRACE(_T("CSubPicAllocatorImpl::SetCurSize: %dx%d\n"), cursize.cx, cursize.cy); - m_cursize = cursize; - FreeStatic(); - } - return S_OK; -} - -STDMETHODIMP CSubPicAllocatorImpl::SetCurVidRect(RECT curvidrect) -{ -#if DEBUG_OVERRIDE_TEXTURE_SIZE - m_curvidrect = CRect(CPoint(0, 0), CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT)); -#else - m_curvidrect = curvidrect; -#endif - return S_OK; -} - -STDMETHODIMP CSubPicAllocatorImpl::GetStatic(ISubPic** ppSubPic) -{ - CheckPointer(ppSubPic, E_POINTER); - - { - CAutoLock cAutoLock(&m_staticLock); - - if (!m_pStatic) { - if (!Alloc(true, &m_pStatic) || !m_pStatic) { - TRACE(_T("CSubPicAllocatorImpl::GetStatic failed\n")); - return E_OUTOFMEMORY; - } - } - - *ppSubPic = m_pStatic; - } - - (*ppSubPic)->AddRef(); - (*ppSubPic)->SetSize(m_cursize, m_curvidrect); - - return S_OK; -} - -STDMETHODIMP CSubPicAllocatorImpl::AllocDynamic(ISubPic** ppSubPic) -{ - CheckPointer(ppSubPic, E_POINTER); - - if (!Alloc(false, ppSubPic) || !*ppSubPic) { - return E_OUTOFMEMORY; - } - - (*ppSubPic)->SetSize(m_cursize, m_curvidrect); - - return S_OK; -} - -STDMETHODIMP_(bool) CSubPicAllocatorImpl::IsDynamicWriteOnly() const -{ - return m_fDynamicWriteOnly; -} - -STDMETHODIMP CSubPicAllocatorImpl::ChangeDevice(IUnknown* pDev) -{ - return FreeStatic(); -} - -STDMETHODIMP CSubPicAllocatorImpl::FreeStatic() -{ - CAutoLock cAutoLock(&m_staticLock); - if (m_pStatic) { - m_pStatic.Release(); - } - return S_OK; -} - -STDMETHODIMP_(void) CSubPicAllocatorImpl::SetInverseAlpha(bool bInverted) -{ - m_bInvAlpha = bInverted; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "SubPicImpl.h" +#include "../DSUtil/DSUtil.h" + +#include "mpc-hc_config.h" + +#if !TRACE_SUBTITLES +#define TRACE(...) +#endif + +// +// CSubPicImpl +// + +CSubPicImpl::CSubPicImpl() + : CUnknown(NAME("CSubPicImpl"), nullptr) + , m_rtStart(0) + , m_rtStop(0) + , m_rtSegmentStart(0) + , m_rtSegmentStop(0) + , m_rcDirty(0, 0, 0, 0) + , m_maxsize(0, 0) + , m_size(0, 0) + , m_vidrect(0, 0, 0, 0) + , m_virtualTextureSize(0, 0) + , m_virtualTextureTopLeft(0, 0) + , m_bInvAlpha(false) + , m_relativeTo(WINDOW) +{ +} + +STDMETHODIMP CSubPicImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(ISubPic) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPic + +STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetStart() const +{ + return m_rtStart; +} + +STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetStop() const +{ + return m_rtStop; +} + +STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetSegmentStart() const +{ + return m_rtSegmentStart >= 0 ? m_rtSegmentStart : m_rtStart; +} + +STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetSegmentStop() const +{ + return m_rtSegmentStop >= 0 ? m_rtSegmentStop : m_rtStop; +} + +STDMETHODIMP_(void) CSubPicImpl::SetSegmentStart(REFERENCE_TIME rtStart) +{ + m_rtSegmentStart = rtStart; +} + +STDMETHODIMP_(void) CSubPicImpl::SetSegmentStop(REFERENCE_TIME rtStop) +{ + m_rtSegmentStop = rtStop; +} + +STDMETHODIMP_(void) CSubPicImpl::SetStart(REFERENCE_TIME rtStart) +{ + m_rtStart = rtStart; +} + +STDMETHODIMP_(void) CSubPicImpl::SetStop(REFERENCE_TIME rtStop) +{ + m_rtStop = rtStop; +} + +STDMETHODIMP CSubPicImpl::CopyTo(ISubPic* pSubPic) +{ + CheckPointer(pSubPic, E_POINTER); + + pSubPic->SetStart(m_rtStart); + pSubPic->SetStop(m_rtStop); + pSubPic->SetSegmentStart(m_rtSegmentStart); + pSubPic->SetSegmentStop(m_rtSegmentStop); + pSubPic->SetDirtyRect(m_rcDirty); + pSubPic->SetSize(m_size, m_vidrect); + pSubPic->SetVirtualTextureSize(m_virtualTextureSize, m_virtualTextureTopLeft); + pSubPic->SetInverseAlpha(m_bInvAlpha); + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::GetDirtyRect(RECT* pDirtyRect) const +{ + CheckPointer(pDirtyRect, E_POINTER); + + *pDirtyRect = m_rcDirty; + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::GetSourceAndDest(RECT rcWindow, RECT rcVideo, + RECT* pRcSource, RECT* pRcDest, + const double videoStretchFactor /*= 1.0*/, + int xOffsetInPixels /*= 0*/, int yOffsetInPixels /*= 0*/) const +{ + CheckPointer(pRcSource, E_POINTER); + CheckPointer(pRcDest, E_POINTER); + + if (m_size.cx > 0 && m_size.cy > 0 && m_rcDirty.Height() > 0) { + CRect videoRect(rcVideo); + CRect windowRect(rcWindow); + + CRect originalDirtyRect = m_rcDirty; + *pRcSource = originalDirtyRect; + originalDirtyRect.OffsetRect(m_virtualTextureTopLeft); + + CRect targetDirtyRect; + + // check if scaling is needed + if (videoRect.Size() != windowRect.Size() || videoRect.Size() != m_virtualTextureSize) { + if (m_relativeTo == BEST_FIT && m_virtualTextureSize.cx > 720 && videoStretchFactor == 1.0) { + CRect visibleRect; + visibleRect.top = videoRect.top > windowRect.top ? (videoRect.top > windowRect.bottom ? windowRect.bottom : videoRect.top) : windowRect.top; + visibleRect.bottom = videoRect.bottom < windowRect.bottom ? (videoRect.bottom < windowRect.top ? windowRect.top : videoRect.bottom) : windowRect.bottom; + visibleRect.left = videoRect.left > windowRect.left ? (videoRect.left > windowRect.right ? windowRect.right : videoRect.left) : windowRect.left; + visibleRect.right = videoRect.right < windowRect.right ? (videoRect.right < windowRect.left ? windowRect.left : videoRect.right) : windowRect.right; + if (visibleRect.Width() <= 0 || visibleRect.Height() <= 0) { + visibleRect = windowRect; + ASSERT(false); + } + CPoint offset(0, 0); + double scaleFactor; + double subtitleAR = double(m_virtualTextureSize.cx) / m_virtualTextureSize.cy; + double visibleAR = double(visibleRect.Width()) / visibleRect.Height(); + double vertical_stretch = 1.0; + if (visibleAR * 2 - subtitleAR < 0.01) { + // some PGS can be encoded with resolution at half height + vertical_stretch = 2.0; + subtitleAR /= 2.0; + } + + if (visibleAR == subtitleAR) { + // exact same AR + scaleFactor = double(visibleRect.Width()) / m_virtualTextureSize.cx; + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(visibleRect.TopLeft()); + } else if (visibleAR > subtitleAR) { + // video is cropped in height + scaleFactor = double(visibleRect.Width()) / m_virtualTextureSize.cx; + int extraheight = m_virtualTextureSize.cy * scaleFactor * vertical_stretch - visibleRect.Height(); + CRect expandedRect = visibleRect; + expandedRect.top -= extraheight / 2; + expandedRect.bottom += extraheight - extraheight / 2; + offset.x = expandedRect.left; + offset.y = expandedRect.top; + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(offset); + + if (expandedRect.left >= windowRect.left && expandedRect.top >= windowRect.top && expandedRect.right <= windowRect.right && expandedRect.bottom <= windowRect.bottom) { + // expanded fits in window + } else { + if (targetDirtyRect.left >= windowRect.left && targetDirtyRect.top >= windowRect.top && targetDirtyRect.right <= windowRect.right && targetDirtyRect.bottom <= windowRect.bottom) { + // dirty rect fits in window + } else { + // does not fit yet, rescale based on available window height + scaleFactor = double(windowRect.Height()) / m_virtualTextureSize.cy / vertical_stretch; + offset.x = lround((windowRect.Width() - scaleFactor * m_virtualTextureSize.cx) / 2.0); + offset.y = 0; + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(offset); + } + } + } else { + // video is cropped in width + scaleFactor = double(visibleRect.Height()) / m_virtualTextureSize.cy / vertical_stretch; + int extrawidth = m_virtualTextureSize.cx * scaleFactor - visibleRect.Width(); + CRect expandedRect = visibleRect; + expandedRect.left -= extrawidth / 2; + expandedRect.right += extrawidth - extrawidth / 2; + offset.x = expandedRect.left; + offset.y = expandedRect.top; + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(offset); + + if (expandedRect.left >= windowRect.left && expandedRect.top >= windowRect.top && expandedRect.right <= windowRect.right && expandedRect.bottom <= windowRect.bottom) { + // expanded fits in window + } else { + if (targetDirtyRect.left >= windowRect.left && targetDirtyRect.top >= windowRect.top && targetDirtyRect.right <= windowRect.right && targetDirtyRect.bottom <= windowRect.bottom) { + // dirty rect fits in window + } else { + // does not fit yet, rescale based on available window width + scaleFactor = double(windowRect.Width()) / m_virtualTextureSize.cx; + offset.x = 0; + offset.y = lround((windowRect.Height() - scaleFactor * m_virtualTextureSize.cy * vertical_stretch) / 2.0); + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(offset); + } + } + } + } else { + CRect rcTarget = (m_relativeTo == WINDOW) ? windowRect : videoRect; + CSize szTarget = rcTarget.Size(); + double scaleX = double(szTarget.cx) / m_virtualTextureSize.cx; + double scaleY = double(szTarget.cy) / m_virtualTextureSize.cy; + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleX), lround(originalDirtyRect.top * scaleY), lround(originalDirtyRect.right * scaleX), lround(originalDirtyRect.bottom * scaleY)); + targetDirtyRect.OffsetRect(rcTarget.TopLeft()); + } + } else { + // no scaling needed + targetDirtyRect = originalDirtyRect; + } + + if (videoStretchFactor != 1.0) { + ASSERT(FALSE); + // FIXME: when is videoStretchFactor not equal to 1.0? Test that situation. Only madvr might possibly use it. Our own renderers do not. + LONG stretch = lround(targetDirtyRect.Width() * (1.0 - 1.0 / videoStretchFactor) / 2.0); + targetDirtyRect.left += stretch; + targetDirtyRect.right -= stretch; + } + + targetDirtyRect.OffsetRect(CPoint(xOffsetInPixels, yOffsetInPixels)); + + *pRcDest = targetDirtyRect; + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicImpl::SetDirtyRect(const RECT* pDirtyRect) +{ + CheckPointer(pDirtyRect, E_POINTER); + + m_rcDirty = *pDirtyRect; + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::GetMaxSize(SIZE* pMaxSize) const +{ + CheckPointer(pMaxSize, E_POINTER); + + *pMaxSize = m_maxsize; + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::SetSize(SIZE size, RECT vidrect) +{ + m_size = size; + if (m_size.cx > m_maxsize.cx) { + m_size.cy = MulDiv(m_size.cy, m_maxsize.cx, m_size.cx); + m_size.cx = m_maxsize.cx; + } + if (m_size.cy > m_maxsize.cy) { + m_size.cx = MulDiv(m_size.cx, m_maxsize.cy, m_size.cy); + m_size.cy = m_maxsize.cy; + } + m_virtualTextureSize = m_size; + + m_vidrect = vidrect; + if (m_size.cx != size.cx || m_size.cy != size.cy) { + m_vidrect.top = MulDiv(m_vidrect.top, m_size.cx, size.cx); + m_vidrect.bottom = MulDiv(m_vidrect.bottom, m_size.cx, size.cx); + m_vidrect.left = MulDiv(m_vidrect.left, m_size.cy, size.cy); + m_vidrect.right = MulDiv(m_vidrect.right, m_size.cy, size.cy); + } + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::SetVirtualTextureSize(const SIZE pSize, const POINT pTopLeft) +{ + m_virtualTextureSize.SetSize(pSize.cx, pSize.cy); + m_virtualTextureTopLeft.SetPoint(pTopLeft.x, pTopLeft.y); + + return S_OK; +} + +STDMETHODIMP_(void) CSubPicImpl::SetInverseAlpha(bool bInverted) +{ + m_bInvAlpha = bInverted; +} + +STDMETHODIMP CSubPicImpl::GetRelativeTo(RelativeTo* pRelativeTo) const +{ + CheckPointer(pRelativeTo, E_POINTER); + + *pRelativeTo = m_relativeTo; + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::SetRelativeTo(RelativeTo relativeTo) +{ + m_relativeTo = relativeTo; + + return S_OK; +} + +// +// ISubPicAllocatorImpl +// + +CSubPicAllocatorImpl::CSubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly) + : CUnknown(NAME("ISubPicAllocatorImpl"), nullptr) + , m_cursize(cursize) + , m_fDynamicWriteOnly(fDynamicWriteOnly) +{ + m_curvidrect = CRect(CPoint(0, 0), m_cursize); +} + +STDMETHODIMP CSubPicAllocatorImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(ISubPicAllocator) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicAllocator + +STDMETHODIMP CSubPicAllocatorImpl::SetCurSize(SIZE cursize) +{ +#if DEBUG_OVERRIDE_TEXTURE_SIZE + cursize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); +#endif + if (m_cursize != cursize) { + TRACE(_T("CSubPicAllocatorImpl::SetCurSize: %dx%d\n"), cursize.cx, cursize.cy); + m_cursize = cursize; + FreeStatic(); + } + return S_OK; +} + +STDMETHODIMP CSubPicAllocatorImpl::SetCurVidRect(RECT curvidrect) +{ +#if DEBUG_OVERRIDE_TEXTURE_SIZE + m_curvidrect = CRect(CPoint(0, 0), CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT)); +#else + m_curvidrect = curvidrect; +#endif + return S_OK; +} + +STDMETHODIMP CSubPicAllocatorImpl::GetStatic(ISubPic** ppSubPic) +{ + CheckPointer(ppSubPic, E_POINTER); + + { + CAutoLock cAutoLock(&m_staticLock); + + if (!m_pStatic) { + if (!Alloc(true, &m_pStatic) || !m_pStatic) { + TRACE(_T("CSubPicAllocatorImpl::GetStatic failed\n")); + return E_OUTOFMEMORY; + } + } + + *ppSubPic = m_pStatic; + } + + (*ppSubPic)->AddRef(); + (*ppSubPic)->SetSize(m_cursize, m_curvidrect); + + return S_OK; +} + +STDMETHODIMP CSubPicAllocatorImpl::AllocDynamic(ISubPic** ppSubPic) +{ + CheckPointer(ppSubPic, E_POINTER); + + if (!Alloc(false, ppSubPic) || !*ppSubPic) { + return E_OUTOFMEMORY; + } + + (*ppSubPic)->SetSize(m_cursize, m_curvidrect); + + return S_OK; +} + +STDMETHODIMP_(bool) CSubPicAllocatorImpl::IsDynamicWriteOnly() const +{ + return m_fDynamicWriteOnly; +} + +STDMETHODIMP CSubPicAllocatorImpl::ChangeDevice(IUnknown* pDev) +{ + return FreeStatic(); +} + +STDMETHODIMP CSubPicAllocatorImpl::FreeStatic() +{ + CAutoLock cAutoLock(&m_staticLock); + if (m_pStatic) { + m_pStatic.Release(); + } + return S_OK; +} + +STDMETHODIMP_(void) CSubPicAllocatorImpl::SetInverseAlpha(bool bInverted) +{ + m_bInvAlpha = bInverted; +} diff --git a/src/SubPic/SubPicImpl.h b/src/SubPic/SubPicImpl.h index 11b96973e29..4e85b7e51e2 100644 --- a/src/SubPic/SubPicImpl.h +++ b/src/SubPic/SubPicImpl.h @@ -1,145 +1,145 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "ISubPic.h" - -class CSubPicImpl : public CUnknown, public ISubPic -{ -protected: - REFERENCE_TIME m_rtStart, m_rtStop; - REFERENCE_TIME m_rtSegmentStart, m_rtSegmentStop; - CRect m_rcDirty; - CSize m_maxsize; - CSize m_size; - CRect m_vidrect; - CSize m_virtualTextureSize; - CPoint m_virtualTextureTopLeft; - bool m_bInvAlpha; - RelativeTo m_relativeTo; - - /* - - Texture - +-------+---------------------------------+ - | . | . - | . m_maxsize | . - TextureTopLeft .<=============================== |======> . Video - | . . . +-------------------------------- | -----+ +-----------------------------------+ - | | . | | | m_vidrect | - | | . | | | | - | | . | | | | - | | +-----------+ . | | | | - | | | m_rcDirty | . | | | | - | | | | . | | | | - | | +-----------+ . | | | | - | +-------------------------------- | -----+ | | - | m_size | | | - | <=========================> | | | - | | | | - | | +-----------------------------------+ - | | . - | | . - | | . - +-----------------------------------------+ - m_VirtualTextureSize - <=========================================> - - */ - - -public: - CSubPicImpl(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPic - - STDMETHODIMP_(REFERENCE_TIME) GetStart() const; - STDMETHODIMP_(REFERENCE_TIME) GetStop() const; - STDMETHODIMP_(void) SetStart(REFERENCE_TIME rtStart); - STDMETHODIMP_(void) SetStop(REFERENCE_TIME rtStop); - - STDMETHODIMP GetDesc(SubPicDesc& spd) PURE; - STDMETHODIMP CopyTo(ISubPic* pSubPic); - - STDMETHODIMP ClearDirtyRect() PURE; - STDMETHODIMP GetDirtyRect(RECT* pDirtyRect) const; - STDMETHODIMP SetDirtyRect(const RECT* pDirtyRect); - - STDMETHODIMP GetMaxSize(SIZE* pMaxSize) const; - STDMETHODIMP SetSize(SIZE size, RECT vidrect); - - STDMETHODIMP Lock(SubPicDesc& spd) PURE; - STDMETHODIMP Unlock(RECT* pDirtyRect) PURE; - - STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) PURE; - - STDMETHODIMP SetVirtualTextureSize(const SIZE pSize, const POINT pTopLeft); - STDMETHODIMP GetSourceAndDest(RECT rcWindow, RECT rcVideo, RECT* pRcSource, - RECT* pRcDest, const double videoStretchFactor = 1.0, - int xOffsetInPixels = 0, int yOffsetInPixels = 0) const; - STDMETHODIMP GetRelativeTo(RelativeTo* pRelativeTo) const; - STDMETHODIMP SetRelativeTo(RelativeTo relativeTo); - - STDMETHODIMP_(REFERENCE_TIME) GetSegmentStart() const; - STDMETHODIMP_(REFERENCE_TIME) GetSegmentStop() const; - STDMETHODIMP_(void) SetSegmentStart(REFERENCE_TIME rtStart); - STDMETHODIMP_(void) SetSegmentStop(REFERENCE_TIME rtStop); - STDMETHODIMP_(void) SetInverseAlpha(bool bInverted); -}; - - -class CSubPicAllocatorImpl : public CUnknown, public ISubPicAllocator -{ -protected: - CCritSec m_staticLock; - CComPtr m_pStatic; - - CSize m_cursize; - CRect m_curvidrect; - bool m_fDynamicWriteOnly; - - virtual bool Alloc(bool fStatic, ISubPic** ppSubPic) PURE; - -protected: - bool m_bInvAlpha = false; - -public: - CSubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicAllocator - - STDMETHODIMP SetCurSize(SIZE cursize); - STDMETHODIMP SetCurVidRect(RECT curvidrect); - STDMETHODIMP GetStatic(ISubPic** ppSubPic); - STDMETHODIMP AllocDynamic(ISubPic** ppSubPic); - STDMETHODIMP_(bool) IsDynamicWriteOnly() const; - STDMETHODIMP ChangeDevice(IUnknown* pDev); - STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize) PURE; - STDMETHODIMP FreeStatic(); - STDMETHODIMP_(void) SetInverseAlpha(bool bInverted); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "ISubPic.h" + +class CSubPicImpl : public CUnknown, public ISubPic +{ +protected: + REFERENCE_TIME m_rtStart, m_rtStop; + REFERENCE_TIME m_rtSegmentStart, m_rtSegmentStop; + CRect m_rcDirty; + CSize m_maxsize; + CSize m_size; + CRect m_vidrect; + CSize m_virtualTextureSize; + CPoint m_virtualTextureTopLeft; + bool m_bInvAlpha; + RelativeTo m_relativeTo; + + /* + + Texture + +-------+---------------------------------+ + | . | . + | . m_maxsize | . + TextureTopLeft .<=============================== |======> . Video + | . . . +-------------------------------- | -----+ +-----------------------------------+ + | | . | | | m_vidrect | + | | . | | | | + | | . | | | | + | | +-----------+ . | | | | + | | | m_rcDirty | . | | | | + | | | | . | | | | + | | +-----------+ . | | | | + | +-------------------------------- | -----+ | | + | m_size | | | + | <=========================> | | | + | | | | + | | +-----------------------------------+ + | | . + | | . + | | . + +-----------------------------------------+ + m_VirtualTextureSize + <=========================================> + + */ + + +public: + CSubPicImpl(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPic + + STDMETHODIMP_(REFERENCE_TIME) GetStart() const; + STDMETHODIMP_(REFERENCE_TIME) GetStop() const; + STDMETHODIMP_(void) SetStart(REFERENCE_TIME rtStart); + STDMETHODIMP_(void) SetStop(REFERENCE_TIME rtStop); + + STDMETHODIMP GetDesc(SubPicDesc& spd) PURE; + STDMETHODIMP CopyTo(ISubPic* pSubPic); + + STDMETHODIMP ClearDirtyRect() PURE; + STDMETHODIMP GetDirtyRect(RECT* pDirtyRect) const; + STDMETHODIMP SetDirtyRect(const RECT* pDirtyRect); + + STDMETHODIMP GetMaxSize(SIZE* pMaxSize) const; + STDMETHODIMP SetSize(SIZE size, RECT vidrect); + + STDMETHODIMP Lock(SubPicDesc& spd) PURE; + STDMETHODIMP Unlock(RECT* pDirtyRect) PURE; + + STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) PURE; + + STDMETHODIMP SetVirtualTextureSize(const SIZE pSize, const POINT pTopLeft); + STDMETHODIMP GetSourceAndDest(RECT rcWindow, RECT rcVideo, RECT* pRcSource, + RECT* pRcDest, const double videoStretchFactor = 1.0, + int xOffsetInPixels = 0, int yOffsetInPixels = 0) const; + STDMETHODIMP GetRelativeTo(RelativeTo* pRelativeTo) const; + STDMETHODIMP SetRelativeTo(RelativeTo relativeTo); + + STDMETHODIMP_(REFERENCE_TIME) GetSegmentStart() const; + STDMETHODIMP_(REFERENCE_TIME) GetSegmentStop() const; + STDMETHODIMP_(void) SetSegmentStart(REFERENCE_TIME rtStart); + STDMETHODIMP_(void) SetSegmentStop(REFERENCE_TIME rtStop); + STDMETHODIMP_(void) SetInverseAlpha(bool bInverted); +}; + + +class CSubPicAllocatorImpl : public CUnknown, public ISubPicAllocator +{ +protected: + CCritSec m_staticLock; + CComPtr m_pStatic; + + CSize m_cursize; + CRect m_curvidrect; + bool m_fDynamicWriteOnly; + + virtual bool Alloc(bool fStatic, ISubPic** ppSubPic) PURE; + +protected: + bool m_bInvAlpha = false; + +public: + CSubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicAllocator + + STDMETHODIMP SetCurSize(SIZE cursize); + STDMETHODIMP SetCurVidRect(RECT curvidrect); + STDMETHODIMP GetStatic(ISubPic** ppSubPic); + STDMETHODIMP AllocDynamic(ISubPic** ppSubPic); + STDMETHODIMP_(bool) IsDynamicWriteOnly() const; + STDMETHODIMP ChangeDevice(IUnknown* pDev); + STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize) PURE; + STDMETHODIMP FreeStatic(); + STDMETHODIMP_(void) SetInverseAlpha(bool bInverted); +}; diff --git a/src/SubPic/SubPicProviderImpl.cpp b/src/SubPic/SubPicProviderImpl.cpp index 9a060886d2d..9bfc46a42fa 100644 --- a/src/SubPic/SubPicProviderImpl.cpp +++ b/src/SubPic/SubPicProviderImpl.cpp @@ -1,65 +1,65 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "SubPicProviderImpl.h" -#include "../DSUtil/DSUtil.h" - -CSubPicProviderImpl::CSubPicProviderImpl(CCritSec* pLock) - : CUnknown(NAME("CSubPicProviderImpl"), nullptr) - , m_pLock(pLock) -{ -} - -CSubPicProviderImpl::~CSubPicProviderImpl() -{ -} - -STDMETHODIMP CSubPicProviderImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(ISubPicProvider) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// CSubPicProviderImpl - -STDMETHODIMP CSubPicProviderImpl::Lock() -{ - CheckPointer(m_pLock, E_FAIL); -#if DEBUG - if (m_pLock->m_currentOwner != 0 && m_pLock->m_currentOwner != GetCurrentThreadId()) { - TRACE(_T("CSubPicProviderImpl::Lock -> Lockcount=%d Lockowner=%d Thread=%d\n"), m_pLock->m_lockCount, m_pLock->m_currentOwner, GetCurrentThreadId()); - }; -#endif - m_pLock->Lock(); - - return S_OK; -} - -STDMETHODIMP CSubPicProviderImpl::Unlock() -{ - CheckPointer(m_pLock, E_FAIL); - - m_pLock->Unlock(); - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "SubPicProviderImpl.h" +#include "../DSUtil/DSUtil.h" + +CSubPicProviderImpl::CSubPicProviderImpl(CCritSec* pLock) + : CUnknown(NAME("CSubPicProviderImpl"), nullptr) + , m_pLock(pLock) +{ +} + +CSubPicProviderImpl::~CSubPicProviderImpl() +{ +} + +STDMETHODIMP CSubPicProviderImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(ISubPicProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// CSubPicProviderImpl + +STDMETHODIMP CSubPicProviderImpl::Lock() +{ + CheckPointer(m_pLock, E_FAIL); +#if DEBUG + if (m_pLock->m_currentOwner != 0 && m_pLock->m_currentOwner != GetCurrentThreadId()) { + TRACE(_T("CSubPicProviderImpl::Lock -> Lockcount=%d Lockowner=%d Thread=%d\n"), m_pLock->m_lockCount, m_pLock->m_currentOwner, GetCurrentThreadId()); + }; +#endif + m_pLock->Lock(); + + return S_OK; +} + +STDMETHODIMP CSubPicProviderImpl::Unlock() +{ + CheckPointer(m_pLock, E_FAIL); + + m_pLock->Unlock(); + + return S_OK; +} diff --git a/src/SubPic/SubPicProviderImpl.h b/src/SubPic/SubPicProviderImpl.h index 0f0db0ddd24..7874921e3a6 100644 --- a/src/SubPic/SubPicProviderImpl.h +++ b/src/SubPic/SubPicProviderImpl.h @@ -1,52 +1,52 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "ISubPic.h" - -class CSubPicProviderImpl : public CUnknown, public ISubPicProvider -{ -protected: - CCritSec* m_pLock; - -public: - CSubPicProviderImpl(CCritSec* pLock); - virtual ~CSubPicProviderImpl(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicProvider - - STDMETHODIMP Lock(); - STDMETHODIMP Unlock(); - - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps) PURE; - STDMETHODIMP_(POSITION) GetNext(POSITION pos) PURE; - - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps) PURE; - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps) PURE; - - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) PURE; - STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft) { return E_NOTIMPL; }; - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo) { relativeTo = WINDOW; return S_OK; }; -}; +/* + * (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 . + * + */ + +#pragma once + +#include "ISubPic.h" + +class CSubPicProviderImpl : public CUnknown, public ISubPicProvider +{ +protected: + CCritSec* m_pLock; + +public: + CSubPicProviderImpl(CCritSec* pLock); + virtual ~CSubPicProviderImpl(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicProvider + + STDMETHODIMP Lock(); + STDMETHODIMP Unlock(); + + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps) PURE; + STDMETHODIMP_(POSITION) GetNext(POSITION pos) PURE; + + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps) PURE; + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps) PURE; + + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) PURE; + STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft) { return E_NOTIMPL; }; + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo) { relativeTo = WINDOW; return S_OK; }; +}; diff --git a/src/SubPic/SubPicQueueImpl.cpp b/src/SubPic/SubPicQueueImpl.cpp index 945e4dfa993..ec4df761819 100644 --- a/src/SubPic/SubPicQueueImpl.cpp +++ b/src/SubPic/SubPicQueueImpl.cpp @@ -1,894 +1,894 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "SubPicQueueImpl.h" -#include "../DSUtil/DSUtil.h" - -#define SUBPIC_TRACE_LEVEL 0 -#define SUBPIC_TRACE_DROP 0 - -#define RT2SEC(x) (double(x) / 10000000.0) - -// -// CSubPicQueueImpl -// - -const double CSubPicQueueImpl::DEFAULT_FPS = 25.0; - -CSubPicQueueImpl::CSubPicQueueImpl(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) - : CUnknown(NAME("CSubPicQueueImpl"), nullptr) - , m_fps(DEFAULT_FPS) - , m_rtTimePerFrame(std::llround(10000000.0 / DEFAULT_FPS)) - , m_rtTimePerSubFrame(std::llround(10000000.0 / (DEFAULT_FPS * settings.nAnimationRate / 100.0))) - , m_rtNow(0) - , m_settings(settings) - , m_pAllocator(pAllocator) -{ - if (phr) { - *phr = S_OK; - } - - if (!m_pAllocator) { - if (phr) { - *phr = E_FAIL; - } - return; - } -} - -CSubPicQueueImpl::~CSubPicQueueImpl() -{ -} - -STDMETHODIMP CSubPicQueueImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(ISubPicQueue) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPicQueue - -STDMETHODIMP CSubPicQueueImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider) -{ - CAutoLock cAutoLock(&m_csSubPicProvider); - - if (m_pSubPicProviderWithSharedLock && m_pSubPicProviderWithSharedLock->pSubPicProvider != pSubPicProvider) { - m_pSubPicProviderWithSharedLock->Lock(); - m_pSubPicProviderWithSharedLock->Unlock(); - // queue is now not processing anything - } - - m_pSubPicProviderWithSharedLock = std::make_shared(pSubPicProvider); - - Invalidate(); - - return S_OK; -} - -STDMETHODIMP CSubPicQueueImpl::GetSubPicProvider(ISubPicProvider** pSubPicProvider) -{ - CheckPointer(pSubPicProvider, E_POINTER); - - CAutoLock cAutoLock(&m_csSubPicProvider); - - if (m_pSubPicProviderWithSharedLock && m_pSubPicProviderWithSharedLock->pSubPicProvider) { - *pSubPicProvider = m_pSubPicProviderWithSharedLock->pSubPicProvider; - (*pSubPicProvider)->AddRef(); - } - - return *pSubPicProvider ? S_OK : E_FAIL; -} - -STDMETHODIMP CSubPicQueueImpl::SetFPS(double fps) -{ - m_fps = fps; - - return S_OK; -} - -STDMETHODIMP CSubPicQueueImpl::SetTime(REFERENCE_TIME rtNow) -{ - m_rtNow = rtNow; - - return S_OK; -} - -// private - -HRESULT CSubPicQueueImpl::RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps, BOOL bIsAnimated) -{ - CheckPointer(pSubPic, E_POINTER); - - HRESULT hr = E_FAIL; - CComPtr pSubPicProvider; - if (FAILED(GetSubPicProvider(&pSubPicProvider)) || !pSubPicProvider) { - return hr; - } - - - hr = pSubPic->ClearDirtyRect(); - - SubPicDesc spd; - if (SUCCEEDED(hr)) { - hr = pSubPic->Lock(spd); - } - if (SUCCEEDED(hr)) { - CRect r(0, 0, 0, 0); - REFERENCE_TIME rtRender; - if (bIsAnimated) { - // This is some sort of hack to avoid rendering the wrong frame - // when the start time is slightly mispredicted by the queue - rtRender = (rtStart + rtStop) / 2; - } else { - rtRender = rtStart + std::llround((rtStop - rtStart - 1) * m_settings.nRenderAtWhenAnimationIsDisabled / 100.0); - } - hr = pSubPicProvider->Render(spd, rtRender, fps, r); - - pSubPic->SetStart(rtStart); - pSubPic->SetStop(rtStop); - - pSubPic->Unlock(r); - } - - return hr; -} - -// -// CSubPicQueue -// - -CSubPicQueue::CSubPicQueue(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) - : CSubPicQueueImpl(settings, pAllocator, phr) - , m_bExitThread(false) - , m_rtNowLast(LONGLONG_ERROR) - , m_bInvalidate(false) - , m_rtInvalidate(0) -{ - if (phr && FAILED(*phr)) { - return; - } - - if (m_settings.nSize < 1) { - if (phr) { - *phr = E_INVALIDARG; - } - return; - } - - CAMThread::Create(); -} - -CSubPicQueue::~CSubPicQueue() -{ - m_bExitThread = true; - SetSubPicProvider(nullptr); - CAMThread::Close(); - if (m_pAllocator) { - m_pAllocator->FreeStatic(); - } -} - -// ISubPicQueue - -STDMETHODIMP CSubPicQueue::SetFPS(double fps) -{ - HRESULT hr = __super::SetFPS(fps); - if (FAILED(hr)) { - return hr; - } - - m_rtTimePerFrame = std::llround(10000000.0 / m_fps); - m_rtTimePerSubFrame = std::llround(10000000.0 / (m_fps * m_settings.nAnimationRate / 100.0)); - - m_runQueueEvent.Set(); - - return S_OK; -} - -STDMETHODIMP CSubPicQueue::SetTime(REFERENCE_TIME rtNow) -{ - HRESULT hr = __super::SetTime(rtNow); - if (FAILED(hr)) { - return hr; - } - - // We want the queue to stay sorted so if we seek in the past, we invalidate - if (m_rtNowLast >= 0 && m_rtNowLast - m_rtNow >= m_rtTimePerFrame) { - Invalidate(m_rtNow); - } - - m_rtNowLast = m_rtNow; - - m_runQueueEvent.Set(); - - return S_OK; -} - -STDMETHODIMP CSubPicQueue::Invalidate(REFERENCE_TIME rtInvalidate /*= -1*/) -{ - std::unique_lock lockQueue(m_mutexQueue); - -#if SUBPIC_TRACE_LEVEL > 0 - TRACE(_T("Invalidate: %.3f\n"), RT2SEC(rtInvalidate)); -#endif - - m_bInvalidate = true; - m_rtInvalidate = rtInvalidate; - m_rtNowLast = LONGLONG_ERROR; - - { - std::lock_guard lockSubpic(m_mutexSubpic); - if (m_pSubPic && m_pSubPic->GetStop() > rtInvalidate) { - m_pSubPic.Release(); - } - } - - while (!m_queue.IsEmpty() && m_queue.GetTail()->GetStop() > rtInvalidate) { -#if SUBPIC_TRACE_LEVEL > 2 - const CComPtr& pSubPic = m_queue.GetTail(); - REFERENCE_TIME rtStart = pSubPic->GetStart(); - REFERENCE_TIME rtStop = pSubPic->GetStop(); - REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); - TRACE(_T(" %.3f -> %.3f -> %.3f\n"), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop)); -#endif - m_queue.RemoveTailNoReturn(); -#if SUBPIC_TRACE_LEVEL > 0 - TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); -#endif - } - - // If we invalidate in the past, always give the queue a chance to re-render the modified subtitles - if (rtInvalidate < m_rtNow) { - m_rtNow = std::max(rtInvalidate, 0LL); - } - - lockQueue.unlock(); - m_condQueueFull.notify_one(); - m_runQueueEvent.Set(); - - return S_OK; -} - -STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, CComPtr& ppSubPic) -{ - // Old version of LookupSubPic, keep legacy behavior and never try to block - return LookupSubPic(rtNow, false, ppSubPic); -} - -STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& ppSubPic) -{ - bool bStopSearch = false; - - { - std::lock_guard lock(m_mutexSubpic); - - // See if we can reuse the latest subpic - if (m_pSubPic) { - REFERENCE_TIME rtSegmentStart = m_pSubPic->GetSegmentStart(); - REFERENCE_TIME rtSegmentStop = m_pSubPic->GetSegmentStop(); - - if (rtSegmentStart <= rtNow && rtNow < rtSegmentStop) { - ppSubPic = m_pSubPic; - - REFERENCE_TIME rtStart = m_pSubPic->GetStart(); - REFERENCE_TIME rtStop = m_pSubPic->GetStop(); - - if (rtStart <= rtNow && rtNow < rtStop) { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("LookupSubPic: Exact match on the latest subpic, rtNow=%.3f rtSegmentStart=%.3f rtSegmentStop=%.3f\n"), RT2SEC(rtNow), RT2SEC(rtSegmentStart), RT2SEC(rtSegmentStop)); -#endif - bStopSearch = true; - } else { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("LookupSubPic: Possible match on the latest subpic, rtNow=%.3f rtStart=%.3f rtStop=%.3f\n"), RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop)); -#endif - } - } else if (rtSegmentStop <= rtNow) { - m_pSubPic.Release(); - } - } - } - - bool bTryBlocking = bAdviseBlocking || !m_settings.bAllowDroppingSubpic; - while (!bStopSearch) { - // Look for the subpic in the queue - { - std::unique_lock lock(m_mutexQueue); - -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("LookupSubPic: Searching the queue, rtNow=%.3f\n"), RT2SEC(rtNow)); -#endif - - while (!m_queue.IsEmpty() && !bStopSearch) { - const CComPtr& pSubPic = m_queue.GetHead(); - REFERENCE_TIME rtSegmentStart = pSubPic->GetSegmentStart(); - - if (rtSegmentStart > rtNow) { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("rtSegmentStart > rtNow, stopping the search, rtSegmentStart=%.3f\n"), RT2SEC(rtSegmentStart)); -#endif - bStopSearch = true; - } else { // rtSegmentStart <= rtNow - bool bRemoveFromQueue = true; - REFERENCE_TIME rtStart = pSubPic->GetStart(); - REFERENCE_TIME rtStop = pSubPic->GetStop(); - REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); - - if (rtSegmentStop <= rtNow) { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("Removing old subpic (rtNow=%.3f): %.3f -> %.3f -> %.3f\n"), - RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop)); -#endif - } else { // rtNow < rtSegmentStop - if (rtStart <= rtNow && rtNow < rtStop) { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("Exact match found in the queue\n")); -#endif - ppSubPic = pSubPic; - bStopSearch = true; - } else if (rtNow >= rtStop) { - // Reuse old subpic - ppSubPic = pSubPic; - } else { // rtNow < rtStart - if (!ppSubPic || ppSubPic->GetStop() <= rtNow) { - // Should be really rare that we use a subpic in advance - // unless we mispredicted the timing slightly - ppSubPic = pSubPic; - } else { - bRemoveFromQueue = false; - } - bStopSearch = true; - } - } - - if (bRemoveFromQueue) { - m_queue.RemoveHeadNoReturn(); -#if SUBPIC_TRACE_LEVEL > 0 - TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); -#endif - } - } - } - - lock.unlock(); - m_condQueueFull.notify_one(); - } - - // If we didn't get any subpic yet and blocking is advised, just try harder to get one - if (!ppSubPic && bTryBlocking) { - bTryBlocking = false; - bStopSearch = true; - - auto pSubPicProviderWithSharedLock = GetSubPicProviderWithSharedLock(); - if (pSubPicProviderWithSharedLock && SUCCEEDED(pSubPicProviderWithSharedLock->Lock())) { - auto& pSubPicProvider = pSubPicProviderWithSharedLock->pSubPicProvider; - double fps = m_fps; - if (POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps)) { - REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); - REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); - if (rtStart <= rtNow && rtNow < rtStop) { - bStopSearch = false; - } - } - pSubPicProviderWithSharedLock->Unlock(); - - if (!bStopSearch && m_settings.nSize) { - std::unique_lock lock(m_mutexQueue); - - auto queueReady = [this, rtNow]() { - return ((int)m_queue.GetCount() == m_settings.nSize) - || (!m_queue.IsEmpty() && m_queue.GetTail()->GetStop() > rtNow); - }; - - std::chrono::milliseconds timeoutPeriod(250); - m_condQueueReady.wait_for(lock, timeoutPeriod, queueReady); - } - } - } else { - bStopSearch = true; - } - } - - if (ppSubPic) { - // Save the subpic for later reuse - std::lock_guard lock(m_mutexSubpic); - m_pSubPic = ppSubPic; - -#if SUBPIC_TRACE_LEVEL > 0 - REFERENCE_TIME rtStart = ppSubPic->GetStart(); - REFERENCE_TIME rtStop = ppSubPic->GetStop(); - REFERENCE_TIME rtSegmentStop = ppSubPic->GetSegmentStop(); - CRect r; - ppSubPic->GetDirtyRect(&r); - TRACE(_T("Display at %.3f: %.3f -> %.3f -> %.3f (%dx%d)\n"), - RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop), - r.Width(), r.Height()); -#endif - } else { -#if SUBPIC_TRACE_LEVEL > 1 - TRACE(_T("No subpicture to display at %.3f\n"), RT2SEC(rtNow)); -#endif - } - - return !!ppSubPic; -} - -STDMETHODIMP CSubPicQueue::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) -{ - std::lock_guard lock(m_mutexQueue); - - nSubPics = (int)m_queue.GetCount(); - rtNow = m_rtNow; - if (nSubPics) { - rtStart = m_queue.GetHead()->GetStart(); - rtStop = m_queue.GetTail()->GetStop(); - } else { - rtStart = rtStop = 0; - } - - return S_OK; -} - -STDMETHODIMP CSubPicQueue::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) -{ - std::lock_guard lock(m_mutexQueue); - - HRESULT hr = E_INVALIDARG; - - if (nSubPic >= 0 && nSubPic < (int)m_queue.GetCount()) { - if (POSITION pos = m_queue.FindIndex(nSubPic)) { - rtStart = m_queue.GetAt(pos)->GetStart(); - rtStop = m_queue.GetAt(pos)->GetStop(); - hr = S_OK; - } else { - // Can't happen - ASSERT(FALSE); - } - } else { - rtStart = rtStop = -1; - } - - return hr; -} - -// private - -bool CSubPicQueue::EnqueueSubPic(CComPtr& pSubPic, bool bBlocking) -{ - auto canAddToQueue = [this]() { - return (int)m_queue.GetCount() < m_settings.nSize; - }; - - bool bAdded = false; - - std::unique_lock lock(m_mutexQueue); - if (bBlocking) { - // Wait for enough room in the queue - m_condQueueFull.wait(lock, canAddToQueue); - } - - if (canAddToQueue()) { - if (m_bInvalidate && pSubPic->GetStop() > m_rtInvalidate) { -#if SUBPIC_TRACE_LEVEL > 1 | SUBPIC_TRACE_DROP - TRACE(_T("Subtitle Renderer Thread: Dropping rendered subpic because of invalidation\n")); -#endif - } else { - m_queue.AddTail(pSubPic); -#if SUBPIC_TRACE_LEVEL > 0 - TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); -#endif - lock.unlock(); - m_condQueueReady.notify_one(); - bAdded = true; - } - pSubPic.Release(); - } - - return bAdded; -} - -REFERENCE_TIME CSubPicQueue::GetCurrentRenderingTime() -{ - REFERENCE_TIME rtNow = -1; - - { - std::lock_guard lock(m_mutexQueue); - - if (!m_queue.IsEmpty()) { - rtNow = m_queue.GetTail()->GetStop(); - } - } - - return std::max(rtNow, m_rtNow); -} - -// overrides - -DWORD CSubPicQueue::ThreadProc() -{ - bool bDisableAnim = m_settings.bDisableSubtitleAnimation; - SetThreadName(DWORD(-1), "Subtitle Renderer Thread"); - SetThreadPriority(m_hThread, bDisableAnim ? THREAD_PRIORITY_LOWEST : THREAD_PRIORITY_ABOVE_NORMAL); - - bool bWaitForEvent = false; - for (; !m_bExitThread;) { - // When we have nothing to render, we just wait a bit - if (bWaitForEvent) { - bWaitForEvent = false; - m_runQueueEvent.Wait(); - } - - auto pSubPicProviderWithSharedLock = GetSubPicProviderWithSharedLock(); - if (pSubPicProviderWithSharedLock && SUCCEEDED(pSubPicProviderWithSharedLock->Lock())) { - auto& pSubPicProvider = pSubPicProviderWithSharedLock->pSubPicProvider; - double fps = m_fps; - REFERENCE_TIME rtTimePerFrame = m_rtTimePerFrame; - REFERENCE_TIME rtTimePerSubFrame = m_rtTimePerSubFrame; - m_bInvalidate = false; - CComPtr pSubPic; - - REFERENCE_TIME rtStartRendering = GetCurrentRenderingTime(); - POSITION pos = pSubPicProvider->GetStartPosition(rtStartRendering, fps); - if (!pos) { - bWaitForEvent = true; - } - for (; pos; pos = pSubPicProvider->GetNext(pos)) { - REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); - REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); - - // We are already one minute ahead, this should be enough - if (rtStart >= m_rtNow + 60 * 10000000i64) { - bWaitForEvent = true; - break; - } - -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("New subtitle sample: Start=%.3f Stop=%.3f\n"), RT2SEC(rtStart), RT2SEC(rtStop)); -#endif - - REFERENCE_TIME rtCurrent = std::max(rtStart, rtStartRendering); - if (rtCurrent < m_rtNow) { - rtCurrent = m_rtNow; - } else { -#if 0 - // FIXME: what is the purpose of this? - if (rtTimePerFrame <= rtStop - rtStart) { - // Round current time to the next estimated video frame timing - REFERENCE_TIME rtCurrentRounded = (rtCurrent / rtTimePerFrame) * rtTimePerFrame; - if (rtCurrentRounded < rtCurrent) { - rtCurrent = rtCurrentRounded + rtTimePerFrame; - } - } -#endif - } - - // Check that we aren't late already... - if (rtCurrent <= rtStop) { - bool bIsAnimated = pSubPicProvider->IsAnimated(pos) && !bDisableAnim; - bool bStopRendering = false; - - while (rtCurrent < rtStop) { - SIZE maxTextureSize, virtualSize; - POINT virtualTopLeft; - HRESULT hr2; - - if (SUCCEEDED(hr2 = pSubPicProvider->GetTextureSize(pos, maxTextureSize, virtualSize, virtualTopLeft))) { - m_pAllocator->SetMaxTextureSize(maxTextureSize); - m_pAllocator->SetCurSize(maxTextureSize); - } - - CComPtr pStatic; - if (FAILED(m_pAllocator->GetStatic(&pStatic))) { - break; - } - - REFERENCE_TIME rtStopReal; - if (rtStop == ISubPicProvider::UNKNOWN_TIME) { // Special case for subtitles with unknown end time - // Force a one frame duration - rtStopReal = rtCurrent + rtTimePerFrame; - } else { - rtStopReal = rtStop; - } - - HRESULT hr; - if (bIsAnimated) { - // 3/4 is a magic number we use to avoid reusing the wrong frame due to slight - // misprediction of the frame end time - hr = RenderTo(pStatic, rtCurrent, std::min(rtCurrent + rtTimePerSubFrame * 3 / 4, rtStopReal), fps, bIsAnimated); -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("rtCurrent=%.3f Start=%.3f SegmentStart=%.3f SegmentStop=%.3f Stop=%.3f\n"), RT2SEC(rtCurrent), RT2SEC(pStatic->GetStart()), RT2SEC(pStatic->GetSegmentStart()), RT2SEC(pStatic->GetSegmentStop()), RT2SEC(pStatic->GetStop())); -#endif - // Set the segment start and stop timings - pStatic->SetSegmentStart(rtStart); - // The stop timing can be moved so that the duration from the current start time - // of the subpic to the segment end is always at least one video frame long. This - // avoids missing subtitle frame due to rounding errors in the timings. - // At worst this can cause a segment to be displayed for one more frame than expected - // but it's much less annoying than having the subtitle disappearing for one frame - pStatic->SetSegmentStop(std::max(rtCurrent + rtTimePerFrame, rtStopReal)); - rtCurrent = std::min(rtCurrent + rtTimePerSubFrame, rtStopReal); - } else { - hr = RenderTo(pStatic, rtStart, rtStopReal, fps, false); - // Non-animated subtitles aren't part of a segment - pStatic->SetSegmentStart(ISubPic::INVALID_SUBPIC_TIME); - pStatic->SetSegmentStop(ISubPic::INVALID_SUBPIC_TIME); - rtCurrent = rtStopReal; - } - - if (FAILED(hr)) { - break; - } - -#if SUBPIC_TRACE_LEVEL > 1 - CRect r; - pStatic->GetDirtyRect(&r); - TRACE(_T("Subtitle Renderer Thread: Render %.3f -> %.3f -> %.3f -> %.3f res=%dx%d\n"), - RT2SEC(rtStart), RT2SEC(pStatic->GetStart()), RT2SEC(pStatic->GetStop()), RT2SEC(rtStop), - r.Width(), r.Height()); -#endif - - pSubPic.Release(); - if (FAILED(m_pAllocator->AllocDynamic(&pSubPic)) - || FAILED(pStatic->CopyTo(pSubPic))) { - break; - } - - if (SUCCEEDED(hr2)) { - pSubPic->SetVirtualTextureSize(virtualSize, virtualTopLeft); - } - - RelativeTo relativeTo; - if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { - pSubPic->SetRelativeTo(relativeTo); - } - - // Try to enqueue the subpic, if the queue is full stop rendering - if (!EnqueueSubPic(pSubPic, false)) { - bStopRendering = true; - break; - } - - if (m_rtNow > rtCurrent) { -#if SUBPIC_TRACE_LEVEL > 0 | SUBPIC_TRACE_DROP - TRACE(_T("Subtitle Renderer Thread: the queue is late, rtCurrent = %.03f rtNow = %.03f \n"), RT2SEC(rtCurrent), RT2SEC(m_rtNow)); -#endif - rtCurrent = m_rtNow; - } - } - - if (bStopRendering) { - break; - } - } else { -#if SUBPIC_TRACE_LEVEL > 0 | SUBPIC_TRACE_DROP - TRACE(_T("Subtitle Renderer Thread: the queue is late, rtCurrent = %.03f rtStart = %.03f rtStop = %.03f\n"), RT2SEC(rtCurrent), RT2SEC(rtStart), RT2SEC(rtStop)); -#endif - } - } - - pSubPicProviderWithSharedLock->Unlock(); - - // If we couldn't enqueue the subpic before, wait for some room in the queue - // but unsure to unlock the subpicture provider first to avoid deadlocks - if (pSubPic) { - EnqueueSubPic(pSubPic, true); - } - } else { - bWaitForEvent = true; - } - } - - return 0; -} - -// -// CSubPicQueueNoThread -// - -CSubPicQueueNoThread::CSubPicQueueNoThread(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) - : CSubPicQueueImpl(settings, pAllocator, phr) -{ - if (phr && SUCCEEDED(*phr) && m_settings.nSize != 0) { - *phr = E_INVALIDARG; - } -} - -CSubPicQueueNoThread::~CSubPicQueueNoThread() -{ - if (m_pAllocator) { - m_pAllocator->FreeStatic(); - } -} - -// ISubPicQueue - -STDMETHODIMP CSubPicQueueNoThread::SetFPS(double fps) -{ - HRESULT hr = __super::SetFPS(fps); - if (FAILED(hr)) { - return hr; - } - - if (m_settings.nAnimationRate == 100) { // Special case when rendering at full speed - // Ensure the subtitle will really be updated every frame by setting a really small duration - m_rtTimePerSubFrame = 1; - } else { - m_rtTimePerSubFrame = std::llround(10000000.0 / (m_fps * m_settings.nAnimationRate / 100.0)); - } - - return S_OK; -} - -STDMETHODIMP CSubPicQueueNoThread::Invalidate(REFERENCE_TIME rtInvalidate /*= -1*/) -{ - CAutoLock cQueueLock(&m_csLock); - - if (m_pSubPic && m_pSubPic->GetStop() > rtInvalidate) { - m_pSubPic = nullptr; - } - - return S_OK; -} - -STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, CComPtr& ppSubPic) -{ - // CSubPicQueueNoThread is always blocking so bAdviseBlocking doesn't matter anyway - return LookupSubPic(rtNow, true, ppSubPic); -} - -STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, bool /*bAdviseBlocking*/, CComPtr& ppSubPic) -{ - // CSubPicQueueNoThread is always blocking so we ignore bAdviseBlocking - - CComPtr pSubPic; - - { - CAutoLock cAutoLock(&m_csLock); - - pSubPic = m_pSubPic; - } - - if (pSubPic && pSubPic->GetStart() <= rtNow && rtNow < pSubPic->GetStop()) { - ppSubPic = pSubPic; - } else { - CComPtr pSubPicProvider; - if (SUCCEEDED(GetSubPicProvider(&pSubPicProvider)) && pSubPicProvider - && SUCCEEDED(pSubPicProvider->Lock())) { - double fps = m_fps; - POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps); - if (pos) { - REFERENCE_TIME rtStart; - REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); - bool bAnimated = pSubPicProvider->IsAnimated(pos) && !m_settings.bDisableSubtitleAnimation; - - // Special case for subtitles with unknown end time - if (rtStop == ISubPicProvider::UNKNOWN_TIME) { - // Force a one frame duration - rtStop = rtNow + 1; - } - - if (bAnimated) { - rtStart = rtNow; - rtStop = std::min(rtNow + m_rtTimePerSubFrame, rtStop); - } else { - rtStart = pSubPicProvider->GetStart(pos, fps); - } - - if (rtStart <= rtNow && rtNow < rtStop) { - bool bAllocSubPic = !pSubPic; - SIZE maxTextureSize, virtualSize; - POINT virtualTopLeft; - HRESULT hr; - if (SUCCEEDED(hr = pSubPicProvider->GetTextureSize(pos, maxTextureSize, virtualSize, virtualTopLeft))) { - m_pAllocator->SetMaxTextureSize(maxTextureSize); - m_pAllocator->SetCurSize(maxTextureSize); - if (!bAllocSubPic) { - // Ensure the previously allocated subpic is big enough to hold the subtitle to be rendered - SIZE maxSize = {0L,0L}; - bAllocSubPic = FAILED(pSubPic->GetMaxSize(&maxSize)) || maxSize.cx < maxTextureSize.cx || maxSize.cy < maxTextureSize.cy; - if (bAllocSubPic) { - TRACE(_T("AllocSubPic required: maxSize=%dx%d maxTextureSize=%dx%d\n"), maxSize.cx, maxSize.cy, maxTextureSize.cx, maxTextureSize.cy); - } - } - } - - if (bAllocSubPic) { - CAutoLock cAutoLock(&m_csLock); - - m_pSubPic.Release(); - - if (FAILED(m_pAllocator->AllocDynamic(&m_pSubPic))) { - TRACE(_T("CSubPicQueueNoThread::LookupSubPic -> AllocDynamic failed\n")); - pSubPicProvider->Unlock(); - return false; - } - - pSubPic = m_pSubPic; - } - - if (m_pAllocator->IsDynamicWriteOnly()) { - CComPtr pStatic; - if (SUCCEEDED(m_pAllocator->GetStatic(&pStatic)) - && SUCCEEDED(RenderTo(pStatic, rtStart, rtStop, fps, bAnimated)) - && SUCCEEDED(pStatic->CopyTo(pSubPic))) { - ppSubPic = pSubPic; - } - } else { - if (SUCCEEDED(RenderTo(pSubPic, rtStart, rtStop, fps, bAnimated))) { - ppSubPic = pSubPic; - } - } - - if (ppSubPic) { - if (SUCCEEDED(hr)) { - ppSubPic->SetVirtualTextureSize(virtualSize, virtualTopLeft); - } - - RelativeTo relativeTo; - if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { - ppSubPic->SetRelativeTo(relativeTo); - } - } - } - } - - pSubPicProvider->Unlock(); - } - } - - return !!ppSubPic; -} - -STDMETHODIMP CSubPicQueueNoThread::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) -{ - CAutoLock cAutoLock(&m_csLock); - - rtNow = m_rtNow; - - if (m_pSubPic) { - nSubPics = 1; - rtStart = m_pSubPic->GetStart(); - rtStop = m_pSubPic->GetStop(); - } else { - nSubPics = 0; - rtStart = rtStop = 0; - } - - return S_OK; -} - -STDMETHODIMP CSubPicQueueNoThread::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) -{ - CAutoLock cAutoLock(&m_csLock); - - if (!m_pSubPic || nSubPic != 0) { - return E_INVALIDARG; - } - - rtStart = m_pSubPic->GetStart(); - rtStop = m_pSubPic->GetStop(); - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "SubPicQueueImpl.h" +#include "../DSUtil/DSUtil.h" + +#define SUBPIC_TRACE_LEVEL 0 +#define SUBPIC_TRACE_DROP 0 + +#define RT2SEC(x) (double(x) / 10000000.0) + +// +// CSubPicQueueImpl +// + +const double CSubPicQueueImpl::DEFAULT_FPS = 25.0; + +CSubPicQueueImpl::CSubPicQueueImpl(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) + : CUnknown(NAME("CSubPicQueueImpl"), nullptr) + , m_fps(DEFAULT_FPS) + , m_rtTimePerFrame(std::llround(10000000.0 / DEFAULT_FPS)) + , m_rtTimePerSubFrame(std::llround(10000000.0 / (DEFAULT_FPS * settings.nAnimationRate / 100.0))) + , m_rtNow(0) + , m_settings(settings) + , m_pAllocator(pAllocator) +{ + if (phr) { + *phr = S_OK; + } + + if (!m_pAllocator) { + if (phr) { + *phr = E_FAIL; + } + return; + } +} + +CSubPicQueueImpl::~CSubPicQueueImpl() +{ +} + +STDMETHODIMP CSubPicQueueImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(ISubPicQueue) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicQueue + +STDMETHODIMP CSubPicQueueImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider) +{ + CAutoLock cAutoLock(&m_csSubPicProvider); + + if (m_pSubPicProviderWithSharedLock && m_pSubPicProviderWithSharedLock->pSubPicProvider != pSubPicProvider) { + m_pSubPicProviderWithSharedLock->Lock(); + m_pSubPicProviderWithSharedLock->Unlock(); + // queue is now not processing anything + } + + m_pSubPicProviderWithSharedLock = std::make_shared(pSubPicProvider); + + Invalidate(); + + return S_OK; +} + +STDMETHODIMP CSubPicQueueImpl::GetSubPicProvider(ISubPicProvider** pSubPicProvider) +{ + CheckPointer(pSubPicProvider, E_POINTER); + + CAutoLock cAutoLock(&m_csSubPicProvider); + + if (m_pSubPicProviderWithSharedLock && m_pSubPicProviderWithSharedLock->pSubPicProvider) { + *pSubPicProvider = m_pSubPicProviderWithSharedLock->pSubPicProvider; + (*pSubPicProvider)->AddRef(); + } + + return *pSubPicProvider ? S_OK : E_FAIL; +} + +STDMETHODIMP CSubPicQueueImpl::SetFPS(double fps) +{ + m_fps = fps; + + return S_OK; +} + +STDMETHODIMP CSubPicQueueImpl::SetTime(REFERENCE_TIME rtNow) +{ + m_rtNow = rtNow; + + return S_OK; +} + +// private + +HRESULT CSubPicQueueImpl::RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps, BOOL bIsAnimated) +{ + CheckPointer(pSubPic, E_POINTER); + + HRESULT hr = E_FAIL; + CComPtr pSubPicProvider; + if (FAILED(GetSubPicProvider(&pSubPicProvider)) || !pSubPicProvider) { + return hr; + } + + + hr = pSubPic->ClearDirtyRect(); + + SubPicDesc spd; + if (SUCCEEDED(hr)) { + hr = pSubPic->Lock(spd); + } + if (SUCCEEDED(hr)) { + CRect r(0, 0, 0, 0); + REFERENCE_TIME rtRender; + if (bIsAnimated) { + // This is some sort of hack to avoid rendering the wrong frame + // when the start time is slightly mispredicted by the queue + rtRender = (rtStart + rtStop) / 2; + } else { + rtRender = rtStart + std::llround((rtStop - rtStart - 1) * m_settings.nRenderAtWhenAnimationIsDisabled / 100.0); + } + hr = pSubPicProvider->Render(spd, rtRender, fps, r); + + pSubPic->SetStart(rtStart); + pSubPic->SetStop(rtStop); + + pSubPic->Unlock(r); + } + + return hr; +} + +// +// CSubPicQueue +// + +CSubPicQueue::CSubPicQueue(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) + : CSubPicQueueImpl(settings, pAllocator, phr) + , m_bExitThread(false) + , m_rtNowLast(LONGLONG_ERROR) + , m_bInvalidate(false) + , m_rtInvalidate(0) +{ + if (phr && FAILED(*phr)) { + return; + } + + if (m_settings.nSize < 1) { + if (phr) { + *phr = E_INVALIDARG; + } + return; + } + + CAMThread::Create(); +} + +CSubPicQueue::~CSubPicQueue() +{ + m_bExitThread = true; + SetSubPicProvider(nullptr); + CAMThread::Close(); + if (m_pAllocator) { + m_pAllocator->FreeStatic(); + } +} + +// ISubPicQueue + +STDMETHODIMP CSubPicQueue::SetFPS(double fps) +{ + HRESULT hr = __super::SetFPS(fps); + if (FAILED(hr)) { + return hr; + } + + m_rtTimePerFrame = std::llround(10000000.0 / m_fps); + m_rtTimePerSubFrame = std::llround(10000000.0 / (m_fps * m_settings.nAnimationRate / 100.0)); + + m_runQueueEvent.Set(); + + return S_OK; +} + +STDMETHODIMP CSubPicQueue::SetTime(REFERENCE_TIME rtNow) +{ + HRESULT hr = __super::SetTime(rtNow); + if (FAILED(hr)) { + return hr; + } + + // We want the queue to stay sorted so if we seek in the past, we invalidate + if (m_rtNowLast >= 0 && m_rtNowLast - m_rtNow >= m_rtTimePerFrame) { + Invalidate(m_rtNow); + } + + m_rtNowLast = m_rtNow; + + m_runQueueEvent.Set(); + + return S_OK; +} + +STDMETHODIMP CSubPicQueue::Invalidate(REFERENCE_TIME rtInvalidate /*= -1*/) +{ + std::unique_lock lockQueue(m_mutexQueue); + +#if SUBPIC_TRACE_LEVEL > 0 + TRACE(_T("Invalidate: %.3f\n"), RT2SEC(rtInvalidate)); +#endif + + m_bInvalidate = true; + m_rtInvalidate = rtInvalidate; + m_rtNowLast = LONGLONG_ERROR; + + { + std::lock_guard lockSubpic(m_mutexSubpic); + if (m_pSubPic && m_pSubPic->GetStop() > rtInvalidate) { + m_pSubPic.Release(); + } + } + + while (!m_queue.IsEmpty() && m_queue.GetTail()->GetStop() > rtInvalidate) { +#if SUBPIC_TRACE_LEVEL > 2 + const CComPtr& pSubPic = m_queue.GetTail(); + REFERENCE_TIME rtStart = pSubPic->GetStart(); + REFERENCE_TIME rtStop = pSubPic->GetStop(); + REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); + TRACE(_T(" %.3f -> %.3f -> %.3f\n"), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop)); +#endif + m_queue.RemoveTailNoReturn(); +#if SUBPIC_TRACE_LEVEL > 0 + TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); +#endif + } + + // If we invalidate in the past, always give the queue a chance to re-render the modified subtitles + if (rtInvalidate < m_rtNow) { + m_rtNow = std::max(rtInvalidate, 0LL); + } + + lockQueue.unlock(); + m_condQueueFull.notify_one(); + m_runQueueEvent.Set(); + + return S_OK; +} + +STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, CComPtr& ppSubPic) +{ + // Old version of LookupSubPic, keep legacy behavior and never try to block + return LookupSubPic(rtNow, false, ppSubPic); +} + +STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& ppSubPic) +{ + bool bStopSearch = false; + + { + std::lock_guard lock(m_mutexSubpic); + + // See if we can reuse the latest subpic + if (m_pSubPic) { + REFERENCE_TIME rtSegmentStart = m_pSubPic->GetSegmentStart(); + REFERENCE_TIME rtSegmentStop = m_pSubPic->GetSegmentStop(); + + if (rtSegmentStart <= rtNow && rtNow < rtSegmentStop) { + ppSubPic = m_pSubPic; + + REFERENCE_TIME rtStart = m_pSubPic->GetStart(); + REFERENCE_TIME rtStop = m_pSubPic->GetStop(); + + if (rtStart <= rtNow && rtNow < rtStop) { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("LookupSubPic: Exact match on the latest subpic, rtNow=%.3f rtSegmentStart=%.3f rtSegmentStop=%.3f\n"), RT2SEC(rtNow), RT2SEC(rtSegmentStart), RT2SEC(rtSegmentStop)); +#endif + bStopSearch = true; + } else { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("LookupSubPic: Possible match on the latest subpic, rtNow=%.3f rtStart=%.3f rtStop=%.3f\n"), RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop)); +#endif + } + } else if (rtSegmentStop <= rtNow) { + m_pSubPic.Release(); + } + } + } + + bool bTryBlocking = bAdviseBlocking || !m_settings.bAllowDroppingSubpic; + while (!bStopSearch) { + // Look for the subpic in the queue + { + std::unique_lock lock(m_mutexQueue); + +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("LookupSubPic: Searching the queue, rtNow=%.3f\n"), RT2SEC(rtNow)); +#endif + + while (!m_queue.IsEmpty() && !bStopSearch) { + const CComPtr& pSubPic = m_queue.GetHead(); + REFERENCE_TIME rtSegmentStart = pSubPic->GetSegmentStart(); + + if (rtSegmentStart > rtNow) { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("rtSegmentStart > rtNow, stopping the search, rtSegmentStart=%.3f\n"), RT2SEC(rtSegmentStart)); +#endif + bStopSearch = true; + } else { // rtSegmentStart <= rtNow + bool bRemoveFromQueue = true; + REFERENCE_TIME rtStart = pSubPic->GetStart(); + REFERENCE_TIME rtStop = pSubPic->GetStop(); + REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); + + if (rtSegmentStop <= rtNow) { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("Removing old subpic (rtNow=%.3f): %.3f -> %.3f -> %.3f\n"), + RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop)); +#endif + } else { // rtNow < rtSegmentStop + if (rtStart <= rtNow && rtNow < rtStop) { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("Exact match found in the queue\n")); +#endif + ppSubPic = pSubPic; + bStopSearch = true; + } else if (rtNow >= rtStop) { + // Reuse old subpic + ppSubPic = pSubPic; + } else { // rtNow < rtStart + if (!ppSubPic || ppSubPic->GetStop() <= rtNow) { + // Should be really rare that we use a subpic in advance + // unless we mispredicted the timing slightly + ppSubPic = pSubPic; + } else { + bRemoveFromQueue = false; + } + bStopSearch = true; + } + } + + if (bRemoveFromQueue) { + m_queue.RemoveHeadNoReturn(); +#if SUBPIC_TRACE_LEVEL > 0 + TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); +#endif + } + } + } + + lock.unlock(); + m_condQueueFull.notify_one(); + } + + // If we didn't get any subpic yet and blocking is advised, just try harder to get one + if (!ppSubPic && bTryBlocking) { + bTryBlocking = false; + bStopSearch = true; + + auto pSubPicProviderWithSharedLock = GetSubPicProviderWithSharedLock(); + if (pSubPicProviderWithSharedLock && SUCCEEDED(pSubPicProviderWithSharedLock->Lock())) { + auto& pSubPicProvider = pSubPicProviderWithSharedLock->pSubPicProvider; + double fps = m_fps; + if (POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps)) { + REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); + REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); + if (rtStart <= rtNow && rtNow < rtStop) { + bStopSearch = false; + } + } + pSubPicProviderWithSharedLock->Unlock(); + + if (!bStopSearch && m_settings.nSize) { + std::unique_lock lock(m_mutexQueue); + + auto queueReady = [this, rtNow]() { + return ((int)m_queue.GetCount() == m_settings.nSize) + || (!m_queue.IsEmpty() && m_queue.GetTail()->GetStop() > rtNow); + }; + + std::chrono::milliseconds timeoutPeriod(250); + m_condQueueReady.wait_for(lock, timeoutPeriod, queueReady); + } + } + } else { + bStopSearch = true; + } + } + + if (ppSubPic) { + // Save the subpic for later reuse + std::lock_guard lock(m_mutexSubpic); + m_pSubPic = ppSubPic; + +#if SUBPIC_TRACE_LEVEL > 0 + REFERENCE_TIME rtStart = ppSubPic->GetStart(); + REFERENCE_TIME rtStop = ppSubPic->GetStop(); + REFERENCE_TIME rtSegmentStop = ppSubPic->GetSegmentStop(); + CRect r; + ppSubPic->GetDirtyRect(&r); + TRACE(_T("Display at %.3f: %.3f -> %.3f -> %.3f (%dx%d)\n"), + RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop), + r.Width(), r.Height()); +#endif + } else { +#if SUBPIC_TRACE_LEVEL > 1 + TRACE(_T("No subpicture to display at %.3f\n"), RT2SEC(rtNow)); +#endif + } + + return !!ppSubPic; +} + +STDMETHODIMP CSubPicQueue::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) +{ + std::lock_guard lock(m_mutexQueue); + + nSubPics = (int)m_queue.GetCount(); + rtNow = m_rtNow; + if (nSubPics) { + rtStart = m_queue.GetHead()->GetStart(); + rtStop = m_queue.GetTail()->GetStop(); + } else { + rtStart = rtStop = 0; + } + + return S_OK; +} + +STDMETHODIMP CSubPicQueue::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) +{ + std::lock_guard lock(m_mutexQueue); + + HRESULT hr = E_INVALIDARG; + + if (nSubPic >= 0 && nSubPic < (int)m_queue.GetCount()) { + if (POSITION pos = m_queue.FindIndex(nSubPic)) { + rtStart = m_queue.GetAt(pos)->GetStart(); + rtStop = m_queue.GetAt(pos)->GetStop(); + hr = S_OK; + } else { + // Can't happen + ASSERT(FALSE); + } + } else { + rtStart = rtStop = -1; + } + + return hr; +} + +// private + +bool CSubPicQueue::EnqueueSubPic(CComPtr& pSubPic, bool bBlocking) +{ + auto canAddToQueue = [this]() { + return (int)m_queue.GetCount() < m_settings.nSize; + }; + + bool bAdded = false; + + std::unique_lock lock(m_mutexQueue); + if (bBlocking) { + // Wait for enough room in the queue + m_condQueueFull.wait(lock, canAddToQueue); + } + + if (canAddToQueue()) { + if (m_bInvalidate && pSubPic->GetStop() > m_rtInvalidate) { +#if SUBPIC_TRACE_LEVEL > 1 | SUBPIC_TRACE_DROP + TRACE(_T("Subtitle Renderer Thread: Dropping rendered subpic because of invalidation\n")); +#endif + } else { + m_queue.AddTail(pSubPic); +#if SUBPIC_TRACE_LEVEL > 0 + TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); +#endif + lock.unlock(); + m_condQueueReady.notify_one(); + bAdded = true; + } + pSubPic.Release(); + } + + return bAdded; +} + +REFERENCE_TIME CSubPicQueue::GetCurrentRenderingTime() +{ + REFERENCE_TIME rtNow = -1; + + { + std::lock_guard lock(m_mutexQueue); + + if (!m_queue.IsEmpty()) { + rtNow = m_queue.GetTail()->GetStop(); + } + } + + return std::max(rtNow, m_rtNow); +} + +// overrides + +DWORD CSubPicQueue::ThreadProc() +{ + bool bDisableAnim = m_settings.bDisableSubtitleAnimation; + SetThreadName(DWORD(-1), "Subtitle Renderer Thread"); + SetThreadPriority(m_hThread, bDisableAnim ? THREAD_PRIORITY_LOWEST : THREAD_PRIORITY_ABOVE_NORMAL); + + bool bWaitForEvent = false; + for (; !m_bExitThread;) { + // When we have nothing to render, we just wait a bit + if (bWaitForEvent) { + bWaitForEvent = false; + m_runQueueEvent.Wait(); + } + + auto pSubPicProviderWithSharedLock = GetSubPicProviderWithSharedLock(); + if (pSubPicProviderWithSharedLock && SUCCEEDED(pSubPicProviderWithSharedLock->Lock())) { + auto& pSubPicProvider = pSubPicProviderWithSharedLock->pSubPicProvider; + double fps = m_fps; + REFERENCE_TIME rtTimePerFrame = m_rtTimePerFrame; + REFERENCE_TIME rtTimePerSubFrame = m_rtTimePerSubFrame; + m_bInvalidate = false; + CComPtr pSubPic; + + REFERENCE_TIME rtStartRendering = GetCurrentRenderingTime(); + POSITION pos = pSubPicProvider->GetStartPosition(rtStartRendering, fps); + if (!pos) { + bWaitForEvent = true; + } + for (; pos; pos = pSubPicProvider->GetNext(pos)) { + REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); + REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); + + // We are already one minute ahead, this should be enough + if (rtStart >= m_rtNow + 60 * 10000000i64) { + bWaitForEvent = true; + break; + } + +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("New subtitle sample: Start=%.3f Stop=%.3f\n"), RT2SEC(rtStart), RT2SEC(rtStop)); +#endif + + REFERENCE_TIME rtCurrent = std::max(rtStart, rtStartRendering); + if (rtCurrent < m_rtNow) { + rtCurrent = m_rtNow; + } else { +#if 0 + // FIXME: what is the purpose of this? + if (rtTimePerFrame <= rtStop - rtStart) { + // Round current time to the next estimated video frame timing + REFERENCE_TIME rtCurrentRounded = (rtCurrent / rtTimePerFrame) * rtTimePerFrame; + if (rtCurrentRounded < rtCurrent) { + rtCurrent = rtCurrentRounded + rtTimePerFrame; + } + } +#endif + } + + // Check that we aren't late already... + if (rtCurrent <= rtStop) { + bool bIsAnimated = pSubPicProvider->IsAnimated(pos) && !bDisableAnim; + bool bStopRendering = false; + + while (rtCurrent < rtStop) { + SIZE maxTextureSize, virtualSize; + POINT virtualTopLeft; + HRESULT hr2; + + if (SUCCEEDED(hr2 = pSubPicProvider->GetTextureSize(pos, maxTextureSize, virtualSize, virtualTopLeft))) { + m_pAllocator->SetMaxTextureSize(maxTextureSize); + m_pAllocator->SetCurSize(maxTextureSize); + } + + CComPtr pStatic; + if (FAILED(m_pAllocator->GetStatic(&pStatic))) { + break; + } + + REFERENCE_TIME rtStopReal; + if (rtStop == ISubPicProvider::UNKNOWN_TIME) { // Special case for subtitles with unknown end time + // Force a one frame duration + rtStopReal = rtCurrent + rtTimePerFrame; + } else { + rtStopReal = rtStop; + } + + HRESULT hr; + if (bIsAnimated) { + // 3/4 is a magic number we use to avoid reusing the wrong frame due to slight + // misprediction of the frame end time + hr = RenderTo(pStatic, rtCurrent, std::min(rtCurrent + rtTimePerSubFrame * 3 / 4, rtStopReal), fps, bIsAnimated); +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("rtCurrent=%.3f Start=%.3f SegmentStart=%.3f SegmentStop=%.3f Stop=%.3f\n"), RT2SEC(rtCurrent), RT2SEC(pStatic->GetStart()), RT2SEC(pStatic->GetSegmentStart()), RT2SEC(pStatic->GetSegmentStop()), RT2SEC(pStatic->GetStop())); +#endif + // Set the segment start and stop timings + pStatic->SetSegmentStart(rtStart); + // The stop timing can be moved so that the duration from the current start time + // of the subpic to the segment end is always at least one video frame long. This + // avoids missing subtitle frame due to rounding errors in the timings. + // At worst this can cause a segment to be displayed for one more frame than expected + // but it's much less annoying than having the subtitle disappearing for one frame + pStatic->SetSegmentStop(std::max(rtCurrent + rtTimePerFrame, rtStopReal)); + rtCurrent = std::min(rtCurrent + rtTimePerSubFrame, rtStopReal); + } else { + hr = RenderTo(pStatic, rtStart, rtStopReal, fps, false); + // Non-animated subtitles aren't part of a segment + pStatic->SetSegmentStart(ISubPic::INVALID_SUBPIC_TIME); + pStatic->SetSegmentStop(ISubPic::INVALID_SUBPIC_TIME); + rtCurrent = rtStopReal; + } + + if (FAILED(hr)) { + break; + } + +#if SUBPIC_TRACE_LEVEL > 1 + CRect r; + pStatic->GetDirtyRect(&r); + TRACE(_T("Subtitle Renderer Thread: Render %.3f -> %.3f -> %.3f -> %.3f res=%dx%d\n"), + RT2SEC(rtStart), RT2SEC(pStatic->GetStart()), RT2SEC(pStatic->GetStop()), RT2SEC(rtStop), + r.Width(), r.Height()); +#endif + + pSubPic.Release(); + if (FAILED(m_pAllocator->AllocDynamic(&pSubPic)) + || FAILED(pStatic->CopyTo(pSubPic))) { + break; + } + + if (SUCCEEDED(hr2)) { + pSubPic->SetVirtualTextureSize(virtualSize, virtualTopLeft); + } + + RelativeTo relativeTo; + if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { + pSubPic->SetRelativeTo(relativeTo); + } + + // Try to enqueue the subpic, if the queue is full stop rendering + if (!EnqueueSubPic(pSubPic, false)) { + bStopRendering = true; + break; + } + + if (m_rtNow > rtCurrent) { +#if SUBPIC_TRACE_LEVEL > 0 | SUBPIC_TRACE_DROP + TRACE(_T("Subtitle Renderer Thread: the queue is late, rtCurrent = %.03f rtNow = %.03f \n"), RT2SEC(rtCurrent), RT2SEC(m_rtNow)); +#endif + rtCurrent = m_rtNow; + } + } + + if (bStopRendering) { + break; + } + } else { +#if SUBPIC_TRACE_LEVEL > 0 | SUBPIC_TRACE_DROP + TRACE(_T("Subtitle Renderer Thread: the queue is late, rtCurrent = %.03f rtStart = %.03f rtStop = %.03f\n"), RT2SEC(rtCurrent), RT2SEC(rtStart), RT2SEC(rtStop)); +#endif + } + } + + pSubPicProviderWithSharedLock->Unlock(); + + // If we couldn't enqueue the subpic before, wait for some room in the queue + // but unsure to unlock the subpicture provider first to avoid deadlocks + if (pSubPic) { + EnqueueSubPic(pSubPic, true); + } + } else { + bWaitForEvent = true; + } + } + + return 0; +} + +// +// CSubPicQueueNoThread +// + +CSubPicQueueNoThread::CSubPicQueueNoThread(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) + : CSubPicQueueImpl(settings, pAllocator, phr) +{ + if (phr && SUCCEEDED(*phr) && m_settings.nSize != 0) { + *phr = E_INVALIDARG; + } +} + +CSubPicQueueNoThread::~CSubPicQueueNoThread() +{ + if (m_pAllocator) { + m_pAllocator->FreeStatic(); + } +} + +// ISubPicQueue + +STDMETHODIMP CSubPicQueueNoThread::SetFPS(double fps) +{ + HRESULT hr = __super::SetFPS(fps); + if (FAILED(hr)) { + return hr; + } + + if (m_settings.nAnimationRate == 100) { // Special case when rendering at full speed + // Ensure the subtitle will really be updated every frame by setting a really small duration + m_rtTimePerSubFrame = 1; + } else { + m_rtTimePerSubFrame = std::llround(10000000.0 / (m_fps * m_settings.nAnimationRate / 100.0)); + } + + return S_OK; +} + +STDMETHODIMP CSubPicQueueNoThread::Invalidate(REFERENCE_TIME rtInvalidate /*= -1*/) +{ + CAutoLock cQueueLock(&m_csLock); + + if (m_pSubPic && m_pSubPic->GetStop() > rtInvalidate) { + m_pSubPic = nullptr; + } + + return S_OK; +} + +STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, CComPtr& ppSubPic) +{ + // CSubPicQueueNoThread is always blocking so bAdviseBlocking doesn't matter anyway + return LookupSubPic(rtNow, true, ppSubPic); +} + +STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, bool /*bAdviseBlocking*/, CComPtr& ppSubPic) +{ + // CSubPicQueueNoThread is always blocking so we ignore bAdviseBlocking + + CComPtr pSubPic; + + { + CAutoLock cAutoLock(&m_csLock); + + pSubPic = m_pSubPic; + } + + if (pSubPic && pSubPic->GetStart() <= rtNow && rtNow < pSubPic->GetStop()) { + ppSubPic = pSubPic; + } else { + CComPtr pSubPicProvider; + if (SUCCEEDED(GetSubPicProvider(&pSubPicProvider)) && pSubPicProvider + && SUCCEEDED(pSubPicProvider->Lock())) { + double fps = m_fps; + POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps); + if (pos) { + REFERENCE_TIME rtStart; + REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); + bool bAnimated = pSubPicProvider->IsAnimated(pos) && !m_settings.bDisableSubtitleAnimation; + + // Special case for subtitles with unknown end time + if (rtStop == ISubPicProvider::UNKNOWN_TIME) { + // Force a one frame duration + rtStop = rtNow + 1; + } + + if (bAnimated) { + rtStart = rtNow; + rtStop = std::min(rtNow + m_rtTimePerSubFrame, rtStop); + } else { + rtStart = pSubPicProvider->GetStart(pos, fps); + } + + if (rtStart <= rtNow && rtNow < rtStop) { + bool bAllocSubPic = !pSubPic; + SIZE maxTextureSize, virtualSize; + POINT virtualTopLeft; + HRESULT hr; + if (SUCCEEDED(hr = pSubPicProvider->GetTextureSize(pos, maxTextureSize, virtualSize, virtualTopLeft))) { + m_pAllocator->SetMaxTextureSize(maxTextureSize); + m_pAllocator->SetCurSize(maxTextureSize); + if (!bAllocSubPic) { + // Ensure the previously allocated subpic is big enough to hold the subtitle to be rendered + SIZE maxSize = {0L,0L}; + bAllocSubPic = FAILED(pSubPic->GetMaxSize(&maxSize)) || maxSize.cx < maxTextureSize.cx || maxSize.cy < maxTextureSize.cy; + if (bAllocSubPic) { + TRACE(_T("AllocSubPic required: maxSize=%dx%d maxTextureSize=%dx%d\n"), maxSize.cx, maxSize.cy, maxTextureSize.cx, maxTextureSize.cy); + } + } + } + + if (bAllocSubPic) { + CAutoLock cAutoLock(&m_csLock); + + m_pSubPic.Release(); + + if (FAILED(m_pAllocator->AllocDynamic(&m_pSubPic))) { + TRACE(_T("CSubPicQueueNoThread::LookupSubPic -> AllocDynamic failed\n")); + pSubPicProvider->Unlock(); + return false; + } + + pSubPic = m_pSubPic; + } + + if (m_pAllocator->IsDynamicWriteOnly()) { + CComPtr pStatic; + if (SUCCEEDED(m_pAllocator->GetStatic(&pStatic)) + && SUCCEEDED(RenderTo(pStatic, rtStart, rtStop, fps, bAnimated)) + && SUCCEEDED(pStatic->CopyTo(pSubPic))) { + ppSubPic = pSubPic; + } + } else { + if (SUCCEEDED(RenderTo(pSubPic, rtStart, rtStop, fps, bAnimated))) { + ppSubPic = pSubPic; + } + } + + if (ppSubPic) { + if (SUCCEEDED(hr)) { + ppSubPic->SetVirtualTextureSize(virtualSize, virtualTopLeft); + } + + RelativeTo relativeTo; + if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { + ppSubPic->SetRelativeTo(relativeTo); + } + } + } + } + + pSubPicProvider->Unlock(); + } + } + + return !!ppSubPic; +} + +STDMETHODIMP CSubPicQueueNoThread::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) +{ + CAutoLock cAutoLock(&m_csLock); + + rtNow = m_rtNow; + + if (m_pSubPic) { + nSubPics = 1; + rtStart = m_pSubPic->GetStart(); + rtStop = m_pSubPic->GetStop(); + } else { + nSubPics = 0; + rtStart = rtStop = 0; + } + + return S_OK; +} + +STDMETHODIMP CSubPicQueueNoThread::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) +{ + CAutoLock cAutoLock(&m_csLock); + + if (!m_pSubPic || nSubPic != 0) { + return E_INVALIDARG; + } + + rtStart = m_pSubPic->GetStart(); + rtStop = m_pSubPic->GetStop(); + + return S_OK; +} diff --git a/src/SubPic/SubPicQueueImpl.h b/src/SubPic/SubPicQueueImpl.h index 630bd074b9d..16d08bd6f54 100644 --- a/src/SubPic/SubPicQueueImpl.h +++ b/src/SubPic/SubPicQueueImpl.h @@ -1,193 +1,193 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include -#include -#include - -#include "ISubPic.h" -#include "SubPicQueueSettings.h" - -class CSubPicQueueImpl : public CUnknown, public ISubPicQueue -{ - static const double DEFAULT_FPS; - -protected: - struct SubPicProviderWithSharedLock { - private: - unsigned int m_nRef = 0; - std::mutex m_mutex; - - public: - const CComPtr pSubPicProvider; - - SubPicProviderWithSharedLock(const CComPtr& pSubPicProvider) - : pSubPicProvider(pSubPicProvider) { - } - - HRESULT Lock() { - HRESULT hr; - - if (pSubPicProvider) { - std::lock_guard lock(m_mutex); - - hr = S_OK; - if ((m_nRef == 0 && SUCCEEDED(hr = pSubPicProvider->Lock())) - || m_nRef > 0) { - m_nRef++; - } - } else { - hr = E_POINTER; - } - - return hr; - } - - HRESULT Unlock() { - HRESULT hr; - - if (pSubPicProvider) { - std::lock_guard lock(m_mutex); - - hr = S_OK; - if ((m_nRef == 1 && SUCCEEDED(hr = pSubPicProvider->Unlock())) - || m_nRef > 1) { - m_nRef--; - } - } else { - hr = E_POINTER; - } - - return hr; - } - }; - -private: - CCritSec m_csSubPicProvider; - std::shared_ptr m_pSubPicProviderWithSharedLock; - -protected: - double m_fps; - REFERENCE_TIME m_rtTimePerFrame; - REFERENCE_TIME m_rtTimePerSubFrame; - REFERENCE_TIME m_rtNow; - - SubPicQueueSettings m_settings; - - CComPtr m_pAllocator; - - std::shared_ptr GetSubPicProviderWithSharedLock() { - CAutoLock cAutoLock(&m_csSubPicProvider); - return m_pSubPicProviderWithSharedLock; - } - - HRESULT RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps, BOOL bIsAnimated); - -public: - CSubPicQueueImpl(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); - virtual ~CSubPicQueueImpl(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicQueue - - STDMETHODIMP SetSubPicProvider(ISubPicProvider* pSubPicProvider); - STDMETHODIMP GetSubPicProvider(ISubPicProvider** pSubPicProvider); - - STDMETHODIMP SetFPS(double fps); - STDMETHODIMP SetTime(REFERENCE_TIME rtNow); - /* - STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1) PURE; - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, ISubPic** ppSubPic) PURE; - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); - - STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) PURE; - STDMETHODIMP GetStats(int nSubPics, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) PURE; - */ -}; - -class CSubPicQueue : public CSubPicQueueImpl, protected CAMThread -{ -protected: - bool m_bExitThread; - - CComPtr m_pSubPic; - CInterfaceList m_queue; - - std::mutex m_mutexSubpic; // to protect m_pSubPic - std::mutex m_mutexQueue; // to protect m_queue - std::condition_variable m_condQueueFull; - std::condition_variable m_condQueueReady; - - CAMEvent m_runQueueEvent; - - REFERENCE_TIME m_rtNowLast; - - bool m_bInvalidate; - REFERENCE_TIME m_rtInvalidate; - - bool EnqueueSubPic(CComPtr& pSubPic, bool bBlocking); - REFERENCE_TIME GetCurrentRenderingTime(); - - // CAMThread - virtual DWORD ThreadProc(); - -public: - CSubPicQueue(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); - virtual ~CSubPicQueue(); - - // ISubPicQueue - - STDMETHODIMP SetFPS(double fps); - STDMETHODIMP SetTime(REFERENCE_TIME rtNow); - - STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1); - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, CComPtr& pSubPic); - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); - - STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); - STDMETHODIMP GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); -}; - -class CSubPicQueueNoThread : public CSubPicQueueImpl -{ -protected: - CCritSec m_csLock; - CComPtr m_pSubPic; - -public: - CSubPicQueueNoThread(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); - virtual ~CSubPicQueueNoThread(); - - // ISubPicQueue - - STDMETHODIMP SetFPS(double fps); - - STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1); - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, CComPtr& pSubPic); - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); - - STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); - STDMETHODIMP GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include +#include +#include + +#include "ISubPic.h" +#include "SubPicQueueSettings.h" + +class CSubPicQueueImpl : public CUnknown, public ISubPicQueue +{ + static const double DEFAULT_FPS; + +protected: + struct SubPicProviderWithSharedLock { + private: + unsigned int m_nRef = 0; + std::mutex m_mutex; + + public: + const CComPtr pSubPicProvider; + + SubPicProviderWithSharedLock(const CComPtr& pSubPicProvider) + : pSubPicProvider(pSubPicProvider) { + } + + HRESULT Lock() { + HRESULT hr; + + if (pSubPicProvider) { + std::lock_guard lock(m_mutex); + + hr = S_OK; + if ((m_nRef == 0 && SUCCEEDED(hr = pSubPicProvider->Lock())) + || m_nRef > 0) { + m_nRef++; + } + } else { + hr = E_POINTER; + } + + return hr; + } + + HRESULT Unlock() { + HRESULT hr; + + if (pSubPicProvider) { + std::lock_guard lock(m_mutex); + + hr = S_OK; + if ((m_nRef == 1 && SUCCEEDED(hr = pSubPicProvider->Unlock())) + || m_nRef > 1) { + m_nRef--; + } + } else { + hr = E_POINTER; + } + + return hr; + } + }; + +private: + CCritSec m_csSubPicProvider; + std::shared_ptr m_pSubPicProviderWithSharedLock; + +protected: + double m_fps; + REFERENCE_TIME m_rtTimePerFrame; + REFERENCE_TIME m_rtTimePerSubFrame; + REFERENCE_TIME m_rtNow; + + SubPicQueueSettings m_settings; + + CComPtr m_pAllocator; + + std::shared_ptr GetSubPicProviderWithSharedLock() { + CAutoLock cAutoLock(&m_csSubPicProvider); + return m_pSubPicProviderWithSharedLock; + } + + HRESULT RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps, BOOL bIsAnimated); + +public: + CSubPicQueueImpl(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); + virtual ~CSubPicQueueImpl(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicQueue + + STDMETHODIMP SetSubPicProvider(ISubPicProvider* pSubPicProvider); + STDMETHODIMP GetSubPicProvider(ISubPicProvider** pSubPicProvider); + + STDMETHODIMP SetFPS(double fps); + STDMETHODIMP SetTime(REFERENCE_TIME rtNow); + /* + STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1) PURE; + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, ISubPic** ppSubPic) PURE; + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); + + STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) PURE; + STDMETHODIMP GetStats(int nSubPics, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) PURE; + */ +}; + +class CSubPicQueue : public CSubPicQueueImpl, protected CAMThread +{ +protected: + bool m_bExitThread; + + CComPtr m_pSubPic; + CInterfaceList m_queue; + + std::mutex m_mutexSubpic; // to protect m_pSubPic + std::mutex m_mutexQueue; // to protect m_queue + std::condition_variable m_condQueueFull; + std::condition_variable m_condQueueReady; + + CAMEvent m_runQueueEvent; + + REFERENCE_TIME m_rtNowLast; + + bool m_bInvalidate; + REFERENCE_TIME m_rtInvalidate; + + bool EnqueueSubPic(CComPtr& pSubPic, bool bBlocking); + REFERENCE_TIME GetCurrentRenderingTime(); + + // CAMThread + virtual DWORD ThreadProc(); + +public: + CSubPicQueue(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); + virtual ~CSubPicQueue(); + + // ISubPicQueue + + STDMETHODIMP SetFPS(double fps); + STDMETHODIMP SetTime(REFERENCE_TIME rtNow); + + STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1); + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, CComPtr& pSubPic); + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); + + STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); + STDMETHODIMP GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); +}; + +class CSubPicQueueNoThread : public CSubPicQueueImpl +{ +protected: + CCritSec m_csLock; + CComPtr m_pSubPic; + +public: + CSubPicQueueNoThread(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); + virtual ~CSubPicQueueNoThread(); + + // ISubPicQueue + + STDMETHODIMP SetFPS(double fps); + + STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1); + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, CComPtr& pSubPic); + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); + + STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); + STDMETHODIMP GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); +}; diff --git a/src/SubPic/stdafx.cpp b/src/SubPic/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/SubPic/stdafx.cpp +++ b/src/SubPic/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/SubPic/stdafx.h b/src/SubPic/stdafx.h index dc4071968a8..eeb933aed07 100644 --- a/src/SubPic/stdafx.h +++ b/src/SubPic/stdafx.h @@ -1,39 +1,39 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include -#include "../DSUtil/DSUtil.h" - -#include -#include -#include +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include +#include "../DSUtil/DSUtil.h" + +#include +#include +#include diff --git a/src/Subtitles/CCDecoder.cpp b/src/Subtitles/CCDecoder.cpp index 5a54f73d168..56e62a956d6 100644 --- a/src/Subtitles/CCDecoder.cpp +++ b/src/Subtitles/CCDecoder.cpp @@ -1,390 +1,390 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "CCDecoder.h" -#include "SubtitleHelpers.h" - -CCDecoder::CCDecoder(CString fn, CString rawfn) : m_fn(fn), m_rawfn(rawfn) -{ - m_sts.CreateDefaultStyle(ANSI_CHARSET); - - m_time = 0; - m_fEndOfCaption = false; - ZeroMemory(m_buff, sizeof(m_buff)); - ZeroMemory(m_disp, sizeof(m_disp)); - m_cursor = CPoint(0, 0); - - if (!m_rawfn.IsEmpty()) { - _tremove(m_rawfn); - } -} - -CCDecoder::~CCDecoder() -{ - if (!m_sts.IsEmpty() && !m_fn.IsEmpty()) { - m_sts.Sort(); - m_sts.SaveAs(m_fn, Subtitle::SRT, -1, 0, CTextFile::DEFAULT_ENCODING); - m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf8.srt"), Subtitle::SRT, -1, 0, CTextFile::UTF8); - m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf16le.srt"), Subtitle::SRT, -1, 0, CTextFile::LE16); - m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf16be.srt"), Subtitle::SRT, -1, 0, CTextFile::BE16); - } -} - -void CCDecoder::MoveCursor(int x, int y) -{ - m_cursor = CPoint(x, y); - if (m_cursor.x < 0) { - m_cursor.x = 0; - } - if (m_cursor.y < 0) { - m_cursor.y = 0; - } - if (m_cursor.x >= 32) { - m_cursor.x = 0, m_cursor.y++; - } - if (m_cursor.y >= 16) { - m_cursor.y = 0; - } -} - -void CCDecoder::OffsetCursor(int x, int y) -{ - MoveCursor(m_cursor.x + x, m_cursor.y + y); -} - -void CCDecoder::PutChar(WCHAR c) -{ - m_buff[m_cursor.y][m_cursor.x] = c; - OffsetCursor(1, 0); -} - -void CCDecoder::SaveDisp(__int64 time) -{ - CStringW str; - - for (size_t row = 0; row < 16; row++) { - bool fNonEmptyRow = false; - - for (size_t col = 0; col < 32; col++) { - if (m_disp[row][col]) { - CStringW str2(&m_disp[row][col]); - if (fNonEmptyRow) { - str += L' '; - } - str += str2; - col += str2.GetLength(); - fNonEmptyRow = true; - } - } - - if (fNonEmptyRow) { - str += L'\n'; - } - } - - if (str.IsEmpty()) { - return; - } - - m_sts.Add(str, true, (int)m_time, (int)time); -} - -void CCDecoder::DecodeCC(const BYTE* buff, int len, __int64 time) -{ - if (!m_rawfn.IsEmpty()) { - FILE* f = nullptr; - if (!_tfopen_s(&f, m_rawfn, _T("at"))) { - _ftprintf_s(f, _T("%02d:%02d:%02d.%03d\n"), - (int)(time / 1000 / 60 / 60), - (int)((time / 1000 / 60) % 60), - (int)((time / 1000) % 60), - (int)(time % 1000)); - - for (ptrdiff_t i = 0; i < len; i++) { - _ftprintf_s(f, _T("%02x"), buff[i]); - if (i < len - 1) { - _ftprintf_s(f, _T(" ")); - } - if (i > 0 && (i & 15) == 15) { - _ftprintf_s(f, _T("\n")); - } - } - if (len > 0) { - _ftprintf_s(f, _T("\n\n")); - } - fclose(f); - } - } - - for (ptrdiff_t i = 0; i < len; i++) { - BYTE c = buff[i] & 0x7f; - if (c >= 0x20) { - static WCHAR charmap[0x60] = { - ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', 0xE1, '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', 0x3F, - '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', 0xE9, ']', 0xED, 0xF3, - 0xFA, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xE7, 0xF7, 'N', 'n', 0x3F - }; - - PutChar(charmap[c - 0x20]); - } else if (i < len - 1 && buff[i] != 0x80) { - // codes and special characters are supposed to be doubled - if (i < len - 3 && buff[i] == buff[i + 2] && buff[i + 1] == buff[i + 3]) { - i += 2; - } - - c = buff[i + 1] & 0x7f; - if (buff[i] == 0x91 && c >= 0x20 && c < 0x30) { // formating - // TODO - } else if (buff[i] == 0x91 && c == 0x39) { // transparent space - OffsetCursor(1, 0); - } else if (buff[i] == 0x91 && c >= 0x30 && c < 0x40) { // special characters - static WCHAR charmap[0x10] = { - 0x00ae, // (r)egistered - 0x00b0, // degree - 0x00bd, // 1/2 - 0x00bf, // inverted question mark - 0x2122, // trade mark - 0x00a2, // cent - 0x00a3, // pound - 0x266a, // music - 0x00e0, // a` - 0x00ff, // transparent space, handled above - 0x00e8, // e` - 0x00e2, // a^ - 0x00ea, // e^ - 0x00ee, // i^ - 0x00f4, // o^ - 0x00fb, // u^ - }; - - PutChar(charmap[c - 0x30]); - } else if (buff[i] == 0x92 && c >= 0x20 && c < 0x40) { // extended characters - static WCHAR charmap[0x20] = { - 0x00c0, // A' - 0x00c9, // E' - 0x00d3, // O' - 0x00da, // U' - 0x00dc, // U: - 0x00fc, // u: - 0x2018, // ` - 0x00a1, // inverted ! - 0x002a, // * - 0x2019, // ' - 0x002d, // - - 0x00a9, // (c)opyright - 0x2120, // SM - 0x00b7, // . (dot in the middle) - 0x201c, // inverted " - 0x201d, // " - - 0x00c1, // A` - 0x00c2, // A^ - 0x00c7, // C, - 0x00c8, // E` - 0x00ca, // E^ - 0x00cb, // E: - 0x00eb, // e: - 0x00ce, // I^ - 0x00cf, // I: - 0x00ef, // i: - 0x00d4, // O^ - 0x00d9, // U` - 0x00f9, // u` - 0x00db, // U^ - 0x00ab, // << - 0x00bb, // >> - }; - - PutChar(charmap[c - 0x20]); - } else if (buff[i] == 0x13 && c >= 0x20 && c < 0x40) { // more extended characters - static WCHAR charmap[0x20] = { - 0x00c3, // A~ - 0x00e3, // a~ - 0x00cd, // I' - 0x00cc, // I` - 0x00ec, // i` - 0x00d2, // O` - 0x00f2, // o` - 0x00d5, // O~ - 0x00f5, // o~ - 0x007b, // { - 0x007d, // } - 0x005c, // /* \ */ - 0x005e, // ^ - 0x005f, // _ - 0x00a6, // | - 0x007e, // ~ - - 0x00c4, // A: - 0x00e4, // a: - 0x00d6, // O: - 0x00f6, // o: - 0x00df, // B (ss in german) - 0x00a5, // Y= - 0x00a4, // ox - 0x007c, // | - 0x00c5, // Ao - 0x00e5, // ao - 0x00d8, // O/ - 0x00f8, // o/ - 0x250c, // |- - 0x2510, // -| - 0x2514, // |_ - 0x2518, // _| - }; - - PutChar(charmap[c - 0x20]); - } else if (buff[i] == 0x94 && buff[i + 1] == 0xae) { // Erase Non-displayed [buffer] Memory - ZeroMemory(m_buff, sizeof(m_buff)); - } else if (buff[i] == 0x94 && buff[i + 1] == 0x20) { // Resume Caption Loading - ZeroMemory(m_buff, sizeof(m_buff)); - } else if (buff[i] == 0x94 && buff[i + 1] == 0x2f) { // End Of Caption - if (memcmp(m_disp, m_buff, sizeof(m_disp)) != 0) { - if (m_fEndOfCaption) { - SaveDisp(time + (i / 2) * 1000 / 30); - } - - m_fEndOfCaption = true; - memcpy(m_disp, m_buff, sizeof(m_disp)); - m_time = time + (i / 2) * 1000 / 30; - } - } else if (buff[i] == 0x94 && buff[i + 1] == 0x2c) { // Erase Displayed Memory - if (m_fEndOfCaption) { - m_fEndOfCaption = false; - SaveDisp(time + (i / 2) * 1000 / 30); - } - - ZeroMemory(m_disp, sizeof(m_disp)); - } else if (buff[i] == 0x97 && (buff[i + 1] == 0xa1 || buff[i + 1] == 0xa2 || buff[i + 1] == 0x23)) { // Tab Over - OffsetCursor(buff[i + 1] & 3, 0); - } else if (buff[i] == 0x91 || buff[i] == 0x92 || buff[i] == 0x15 || buff[i] == 0x16 - || buff[i] == 0x97 || buff[i] == 0x10 || buff[i] == 0x13 || buff[i] == 0x94) { // curpos, color, underline - int row = 0; - switch (buff[i]) { - default: - case 0x91: - row = 0; - break; - case 0x92: - row = 2; - break; - case 0x15: - row = 4; - break; - case 0x16: - row = 6; - break; - case 0x97: - row = 8; - break; - case 0x10: - row = 10; - break; - case 0x13: - row = 12; - break; - case 0x94: - row = 14; - break; - } - if (buff[i + 1] & 0x20) { - row++; - } - - int col = buff[i + 1] & 0xe; - if (col == 0 || (col > 0 && !(buff[i + 1] & 0x10))) { - col = 0; - } else { - col <<= 1; - } - - MoveCursor(col, row); - } - - i++; - } - } -} - -void CCDecoder::ExtractCC(BYTE* buff, int len, __int64 time) -{ - for (ptrdiff_t i = 0; i < len - 9; i++) { - if (*(DWORD*)&buff[i] == 0xb2010000 && *(DWORD*)&buff[i + 4] == 0xf8014343) { - i += 8; - int nBytes = buff[i++] & 0x3f; - if (nBytes > 0) { - nBytes = (nBytes + 1) & ~1; - - BYTE* pData1 = DEBUG_NEW BYTE[nBytes]; - BYTE* pData2 = DEBUG_NEW BYTE[nBytes]; - - if (pData1 && pData2) { - int nBytes1 = 0, nBytes2 = 0; - - for (ptrdiff_t j = 0; j < nBytes && i < 0x800;) { - if (buff[i++] == 0xff) { - pData1[nBytes1++] = buff[i++]; - pData1[nBytes1++] = buff[i++]; - } else { - i += 2; - } - - j++; - - if (j >= nBytes) { - break; - } - - if (buff[i++] == 0xff) { - pData2[nBytes2++] = buff[i++]; - pData2[nBytes2++] = buff[i++]; - } else { - i += 2; - } - - j++; - } - - if (nBytes1 > 0) { - DecodeCC(pData1, nBytes1, time); - } - - if (nBytes2 > 0) { - DecodeCC(pData2, nBytes2, time); - } - } - - if (pData1) { - delete [] pData1; - } - if (pData2) { - delete [] pData2; - } - } - - break; - } - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "CCDecoder.h" +#include "SubtitleHelpers.h" + +CCDecoder::CCDecoder(CString fn, CString rawfn) : m_fn(fn), m_rawfn(rawfn) +{ + m_sts.CreateDefaultStyle(ANSI_CHARSET); + + m_time = 0; + m_fEndOfCaption = false; + ZeroMemory(m_buff, sizeof(m_buff)); + ZeroMemory(m_disp, sizeof(m_disp)); + m_cursor = CPoint(0, 0); + + if (!m_rawfn.IsEmpty()) { + _tremove(m_rawfn); + } +} + +CCDecoder::~CCDecoder() +{ + if (!m_sts.IsEmpty() && !m_fn.IsEmpty()) { + m_sts.Sort(); + m_sts.SaveAs(m_fn, Subtitle::SRT, -1, 0, CTextFile::DEFAULT_ENCODING); + m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf8.srt"), Subtitle::SRT, -1, 0, CTextFile::UTF8); + m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf16le.srt"), Subtitle::SRT, -1, 0, CTextFile::LE16); + m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf16be.srt"), Subtitle::SRT, -1, 0, CTextFile::BE16); + } +} + +void CCDecoder::MoveCursor(int x, int y) +{ + m_cursor = CPoint(x, y); + if (m_cursor.x < 0) { + m_cursor.x = 0; + } + if (m_cursor.y < 0) { + m_cursor.y = 0; + } + if (m_cursor.x >= 32) { + m_cursor.x = 0, m_cursor.y++; + } + if (m_cursor.y >= 16) { + m_cursor.y = 0; + } +} + +void CCDecoder::OffsetCursor(int x, int y) +{ + MoveCursor(m_cursor.x + x, m_cursor.y + y); +} + +void CCDecoder::PutChar(WCHAR c) +{ + m_buff[m_cursor.y][m_cursor.x] = c; + OffsetCursor(1, 0); +} + +void CCDecoder::SaveDisp(__int64 time) +{ + CStringW str; + + for (size_t row = 0; row < 16; row++) { + bool fNonEmptyRow = false; + + for (size_t col = 0; col < 32; col++) { + if (m_disp[row][col]) { + CStringW str2(&m_disp[row][col]); + if (fNonEmptyRow) { + str += L' '; + } + str += str2; + col += str2.GetLength(); + fNonEmptyRow = true; + } + } + + if (fNonEmptyRow) { + str += L'\n'; + } + } + + if (str.IsEmpty()) { + return; + } + + m_sts.Add(str, true, (int)m_time, (int)time); +} + +void CCDecoder::DecodeCC(const BYTE* buff, int len, __int64 time) +{ + if (!m_rawfn.IsEmpty()) { + FILE* f = nullptr; + if (!_tfopen_s(&f, m_rawfn, _T("at"))) { + _ftprintf_s(f, _T("%02d:%02d:%02d.%03d\n"), + (int)(time / 1000 / 60 / 60), + (int)((time / 1000 / 60) % 60), + (int)((time / 1000) % 60), + (int)(time % 1000)); + + for (ptrdiff_t i = 0; i < len; i++) { + _ftprintf_s(f, _T("%02x"), buff[i]); + if (i < len - 1) { + _ftprintf_s(f, _T(" ")); + } + if (i > 0 && (i & 15) == 15) { + _ftprintf_s(f, _T("\n")); + } + } + if (len > 0) { + _ftprintf_s(f, _T("\n\n")); + } + fclose(f); + } + } + + for (ptrdiff_t i = 0; i < len; i++) { + BYTE c = buff[i] & 0x7f; + if (c >= 0x20) { + static WCHAR charmap[0x60] = { + ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', 0xE1, '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', 0x3F, + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', 0xE9, ']', 0xED, 0xF3, + 0xFA, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xE7, 0xF7, 'N', 'n', 0x3F + }; + + PutChar(charmap[c - 0x20]); + } else if (i < len - 1 && buff[i] != 0x80) { + // codes and special characters are supposed to be doubled + if (i < len - 3 && buff[i] == buff[i + 2] && buff[i + 1] == buff[i + 3]) { + i += 2; + } + + c = buff[i + 1] & 0x7f; + if (buff[i] == 0x91 && c >= 0x20 && c < 0x30) { // formating + // TODO + } else if (buff[i] == 0x91 && c == 0x39) { // transparent space + OffsetCursor(1, 0); + } else if (buff[i] == 0x91 && c >= 0x30 && c < 0x40) { // special characters + static WCHAR charmap[0x10] = { + 0x00ae, // (r)egistered + 0x00b0, // degree + 0x00bd, // 1/2 + 0x00bf, // inverted question mark + 0x2122, // trade mark + 0x00a2, // cent + 0x00a3, // pound + 0x266a, // music + 0x00e0, // a` + 0x00ff, // transparent space, handled above + 0x00e8, // e` + 0x00e2, // a^ + 0x00ea, // e^ + 0x00ee, // i^ + 0x00f4, // o^ + 0x00fb, // u^ + }; + + PutChar(charmap[c - 0x30]); + } else if (buff[i] == 0x92 && c >= 0x20 && c < 0x40) { // extended characters + static WCHAR charmap[0x20] = { + 0x00c0, // A' + 0x00c9, // E' + 0x00d3, // O' + 0x00da, // U' + 0x00dc, // U: + 0x00fc, // u: + 0x2018, // ` + 0x00a1, // inverted ! + 0x002a, // * + 0x2019, // ' + 0x002d, // - + 0x00a9, // (c)opyright + 0x2120, // SM + 0x00b7, // . (dot in the middle) + 0x201c, // inverted " + 0x201d, // " + + 0x00c1, // A` + 0x00c2, // A^ + 0x00c7, // C, + 0x00c8, // E` + 0x00ca, // E^ + 0x00cb, // E: + 0x00eb, // e: + 0x00ce, // I^ + 0x00cf, // I: + 0x00ef, // i: + 0x00d4, // O^ + 0x00d9, // U` + 0x00f9, // u` + 0x00db, // U^ + 0x00ab, // << + 0x00bb, // >> + }; + + PutChar(charmap[c - 0x20]); + } else if (buff[i] == 0x13 && c >= 0x20 && c < 0x40) { // more extended characters + static WCHAR charmap[0x20] = { + 0x00c3, // A~ + 0x00e3, // a~ + 0x00cd, // I' + 0x00cc, // I` + 0x00ec, // i` + 0x00d2, // O` + 0x00f2, // o` + 0x00d5, // O~ + 0x00f5, // o~ + 0x007b, // { + 0x007d, // } + 0x005c, // /* \ */ + 0x005e, // ^ + 0x005f, // _ + 0x00a6, // | + 0x007e, // ~ + + 0x00c4, // A: + 0x00e4, // a: + 0x00d6, // O: + 0x00f6, // o: + 0x00df, // B (ss in german) + 0x00a5, // Y= + 0x00a4, // ox + 0x007c, // | + 0x00c5, // Ao + 0x00e5, // ao + 0x00d8, // O/ + 0x00f8, // o/ + 0x250c, // |- + 0x2510, // -| + 0x2514, // |_ + 0x2518, // _| + }; + + PutChar(charmap[c - 0x20]); + } else if (buff[i] == 0x94 && buff[i + 1] == 0xae) { // Erase Non-displayed [buffer] Memory + ZeroMemory(m_buff, sizeof(m_buff)); + } else if (buff[i] == 0x94 && buff[i + 1] == 0x20) { // Resume Caption Loading + ZeroMemory(m_buff, sizeof(m_buff)); + } else if (buff[i] == 0x94 && buff[i + 1] == 0x2f) { // End Of Caption + if (memcmp(m_disp, m_buff, sizeof(m_disp)) != 0) { + if (m_fEndOfCaption) { + SaveDisp(time + (i / 2) * 1000 / 30); + } + + m_fEndOfCaption = true; + memcpy(m_disp, m_buff, sizeof(m_disp)); + m_time = time + (i / 2) * 1000 / 30; + } + } else if (buff[i] == 0x94 && buff[i + 1] == 0x2c) { // Erase Displayed Memory + if (m_fEndOfCaption) { + m_fEndOfCaption = false; + SaveDisp(time + (i / 2) * 1000 / 30); + } + + ZeroMemory(m_disp, sizeof(m_disp)); + } else if (buff[i] == 0x97 && (buff[i + 1] == 0xa1 || buff[i + 1] == 0xa2 || buff[i + 1] == 0x23)) { // Tab Over + OffsetCursor(buff[i + 1] & 3, 0); + } else if (buff[i] == 0x91 || buff[i] == 0x92 || buff[i] == 0x15 || buff[i] == 0x16 + || buff[i] == 0x97 || buff[i] == 0x10 || buff[i] == 0x13 || buff[i] == 0x94) { // curpos, color, underline + int row = 0; + switch (buff[i]) { + default: + case 0x91: + row = 0; + break; + case 0x92: + row = 2; + break; + case 0x15: + row = 4; + break; + case 0x16: + row = 6; + break; + case 0x97: + row = 8; + break; + case 0x10: + row = 10; + break; + case 0x13: + row = 12; + break; + case 0x94: + row = 14; + break; + } + if (buff[i + 1] & 0x20) { + row++; + } + + int col = buff[i + 1] & 0xe; + if (col == 0 || (col > 0 && !(buff[i + 1] & 0x10))) { + col = 0; + } else { + col <<= 1; + } + + MoveCursor(col, row); + } + + i++; + } + } +} + +void CCDecoder::ExtractCC(BYTE* buff, int len, __int64 time) +{ + for (ptrdiff_t i = 0; i < len - 9; i++) { + if (*(DWORD*)&buff[i] == 0xb2010000 && *(DWORD*)&buff[i + 4] == 0xf8014343) { + i += 8; + int nBytes = buff[i++] & 0x3f; + if (nBytes > 0) { + nBytes = (nBytes + 1) & ~1; + + BYTE* pData1 = DEBUG_NEW BYTE[nBytes]; + BYTE* pData2 = DEBUG_NEW BYTE[nBytes]; + + if (pData1 && pData2) { + int nBytes1 = 0, nBytes2 = 0; + + for (ptrdiff_t j = 0; j < nBytes && i < 0x800;) { + if (buff[i++] == 0xff) { + pData1[nBytes1++] = buff[i++]; + pData1[nBytes1++] = buff[i++]; + } else { + i += 2; + } + + j++; + + if (j >= nBytes) { + break; + } + + if (buff[i++] == 0xff) { + pData2[nBytes2++] = buff[i++]; + pData2[nBytes2++] = buff[i++]; + } else { + i += 2; + } + + j++; + } + + if (nBytes1 > 0) { + DecodeCC(pData1, nBytes1, time); + } + + if (nBytes2 > 0) { + DecodeCC(pData2, nBytes2, time); + } + } + + if (pData1) { + delete [] pData1; + } + if (pData2) { + delete [] pData2; + } + } + + break; + } + } +} diff --git a/src/Subtitles/CCDecoder.h b/src/Subtitles/CCDecoder.h index 9b0e54e15f8..bb87d2975d2 100644 --- a/src/Subtitles/CCDecoder.h +++ b/src/Subtitles/CCDecoder.h @@ -1,46 +1,46 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "STS.h" - -class CCDecoder -{ - CSimpleTextSubtitle m_sts; - CString m_fn, m_rawfn; - __int64 m_time; - bool m_fEndOfCaption; - WCHAR m_buff[16][33], m_disp[16][33]; - CPoint m_cursor; - - void SaveDisp(__int64 time); - void MoveCursor(int x, int y); - void OffsetCursor(int x, int y); - void PutChar(WCHAR c); - -public: - CCDecoder(CString fn = _T(""), CString rawfn = _T("")); - virtual ~CCDecoder(); - void DecodeCC(const BYTE* buff, int len, __int64 time); - void ExtractCC(BYTE* buff, int len, __int64 time); - CSimpleTextSubtitle& GetSTS() { return m_sts; } -}; +/* + * (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 . + * + */ + +#pragma once + +#include "STS.h" + +class CCDecoder +{ + CSimpleTextSubtitle m_sts; + CString m_fn, m_rawfn; + __int64 m_time; + bool m_fEndOfCaption; + WCHAR m_buff[16][33], m_disp[16][33]; + CPoint m_cursor; + + void SaveDisp(__int64 time); + void MoveCursor(int x, int y); + void OffsetCursor(int x, int y); + void PutChar(WCHAR c); + +public: + CCDecoder(CString fn = _T(""), CString rawfn = _T("")); + virtual ~CCDecoder(); + void DecodeCC(const BYTE* buff, int len, __int64 time); + void ExtractCC(BYTE* buff, int len, __int64 time); + CSimpleTextSubtitle& GetSTS() { return m_sts; } +}; diff --git a/src/Subtitles/CompositionObject.cpp b/src/Subtitles/CompositionObject.cpp index 4993a790e03..76669558778 100644 --- a/src/Subtitles/CompositionObject.cpp +++ b/src/Subtitles/CompositionObject.cpp @@ -1,370 +1,370 @@ -/* - * (C) 2009-2015 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 . - * - */ - -#include "stdafx.h" -#include "CompositionObject.h" -#include "ColorConvTable.h" -#include "../DSUtil/GolombBuffer.h" - - -CompositionObject::CompositionObject() -{ - Init(); -} - -CompositionObject::CompositionObject(const CompositionObject& obj) - : m_object_id_ref(obj.m_object_id_ref) - , m_window_id_ref(obj.m_window_id_ref) - , m_object_cropped_flag(obj.m_object_cropped_flag) - , m_forced_on_flag(obj.m_forced_on_flag) - , m_version_number(obj.m_version_number) - , m_horizontal_position(obj.m_horizontal_position) - , m_vertical_position(obj.m_vertical_position) - , m_width(obj.m_width) - , m_height(obj.m_height) - , m_cropping_horizontal_position(obj.m_cropping_horizontal_position) - , m_cropping_vertical_position(obj.m_cropping_vertical_position) - , m_cropping_width(obj.m_cropping_width) - , m_cropping_height(obj.m_cropping_height) - , m_pRLEData(nullptr) - , m_nRLEDataSize(0) - , m_nRLEPos(0) - , m_nColorNumber(obj.m_nColorNumber) - , m_colors(obj.m_colors) -{ - if (obj.m_pRLEData) { - SetRLEData(obj.m_pRLEData, obj.m_nRLEPos, obj.m_nRLEDataSize); - } -} - -CompositionObject::~CompositionObject() -{ - delete [] m_pRLEData; -} - -void CompositionObject::Init() -{ - m_pRLEData = nullptr; - m_nRLEDataSize = m_nRLEPos = 0; - m_nColorNumber = 0; - m_object_id_ref = 0; - m_window_id_ref = 0; - m_object_cropped_flag = false; - m_forced_on_flag = false; - m_version_number = 0; - m_horizontal_position = m_vertical_position = 0; - m_width = m_height = 0; - m_cropping_horizontal_position = m_cropping_vertical_position = 0; - m_cropping_width = m_cropping_height = 0; - - m_colors.fill(0); -} - -void CompositionObject::Reset() -{ - delete[] m_pRLEData; - Init(); -} - -void CompositionObject::SetPalette(int nNbEntry, const HDMV_PALETTE* pPalette, ColorConvTable::YuvMatrixType currentMatrix) -{ - m_nColorNumber = nNbEntry; - for (int i = 0; i < nNbEntry; i++) { - m_colors[pPalette[i].entry_id] = ColorConvTable::A8Y8U8V8_TO_ARGB(pPalette[i].T, pPalette[i].Y, pPalette[i].Cb, pPalette[i].Cr, currentMatrix); - } -} - -void CompositionObject::SetRLEData(const BYTE* pBuffer, size_t nSize, size_t nTotalSize) -{ - delete [] m_pRLEData; - - if (nTotalSize > 0 && nSize <= nTotalSize) { - m_pRLEData = DEBUG_NEW BYTE[nTotalSize]; - m_nRLEDataSize = nTotalSize; - m_nRLEPos = nSize; - - memcpy(m_pRLEData, pBuffer, nSize); - } else { - m_pRLEData = nullptr; - m_nRLEDataSize = m_nRLEPos = 0; - ASSERT(FALSE); // This shouldn't happen in normal operation - } -} - -void CompositionObject::AppendRLEData(const BYTE* pBuffer, size_t nSize) -{ - if (m_nRLEPos + nSize <= m_nRLEDataSize) { - memcpy(m_pRLEData + m_nRLEPos, pBuffer, nSize); - m_nRLEPos += nSize; - } else { - ASSERT(FALSE); // This shouldn't happen in normal operation - } -} - -void CompositionObject::RenderHdmv(SubPicDesc& spd) -{ - if (!m_pRLEData || !m_nColorNumber) { - return; - } - - CGolombBuffer GBuffer(m_pRLEData, m_nRLEDataSize); - BYTE bSwitch; - BYTE nPaletteIndex = 0; - LONG nCount; - LONG nX = m_horizontal_position; - LONG nY = m_vertical_position; - - while ((nY < (m_vertical_position + m_height)) && !GBuffer.IsEOF()) { - BYTE bTemp = GBuffer.ReadByte(); - if (bTemp != 0) { - nPaletteIndex = bTemp; - nCount = 1; - } else { - bSwitch = GBuffer.ReadByte(); - if (!(bSwitch & 0x80)) { - if (!(bSwitch & 0x40)) { - nCount = bSwitch & 0x3F; - if (nCount > 0) { - nPaletteIndex = 0; - } - } else { - nCount = (bSwitch & 0x3F) << 8 | (short)GBuffer.ReadByte(); - nPaletteIndex = 0; - } - } else { - if (!(bSwitch & 0x40)) { - nCount = bSwitch & 0x3F; - nPaletteIndex = GBuffer.ReadByte(); - } else { - nCount = (bSwitch & 0x3F) << 8 | (short)GBuffer.ReadByte(); - nPaletteIndex = GBuffer.ReadByte(); - } - } - } - - if (nCount > 0) { - if (nPaletteIndex != 0xFF) { // Fully transparent (section 9.14.4.2.2.1.1) - FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); - } - nX += nCount; - } else { - nY++; - nX = m_horizontal_position; - } - } -} - -void CompositionObject::RenderDvb(SubPicDesc& spd, short nX, short nY) -{ - if (!m_pRLEData) { - return; - } - - CGolombBuffer gb(m_pRLEData, m_nRLEDataSize); - short sTopFieldLength; - short sBottomFieldLength; - - sTopFieldLength = gb.ReadShort(); - sBottomFieldLength = gb.ReadShort(); - - DvbRenderField(spd, gb, nX, nY, sTopFieldLength); - DvbRenderField(spd, gb, nX, nY + 1, sBottomFieldLength); -} - -void CompositionObject::DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, short nXStart, short nYStart, short nLength) -{ - //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0xFFFF0000); // Red opaque - //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0xCC00FF00); // Green 80% - //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0x100000FF); // Blue 60% - //return; - short nX = nXStart; - short nY = nYStart; - size_t nEnd = gb.GetPos() + nLength; - if (nEnd > gb.GetSize()) { - // Unexpected end of data, the file is probably corrupted - // but try to render the subtitles anyway - ASSERT(FALSE); - nEnd = gb.GetSize(); - } - - while (gb.GetPos() < nEnd) { - BYTE bType = gb.ReadByte(); - switch (bType) { - case 0x10: - Dvb2PixelsCodeString(spd, gb, nX, nY); - break; - case 0x11: - Dvb4PixelsCodeString(spd, gb, nX, nY); - break; - case 0x12: - Dvb8PixelsCodeString(spd, gb, nX, nY); - break; - case 0x20: - gb.SkipBytes(2); - break; - case 0x21: - gb.SkipBytes(4); - break; - case 0x22: - gb.SkipBytes(16); - break; - case 0xF0: - nX = nXStart; - nY += 2; - break; - default: - ASSERT(FALSE); - break; - } - } -} - -void CompositionObject::Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) -{ - bool bQuit = false; - - while (!bQuit && !gb.IsEOF()) { - short nCount = 0; - BYTE nPaletteIndex = 0; - BYTE bTemp = (BYTE)gb.BitRead(2); - if (bTemp != 0) { - nPaletteIndex = bTemp; - nCount = 1; - } else { - if (gb.BitRead(1) == 1) { // switch_1 - nCount = 3 + (short)gb.BitRead(3); // run_length_3-9 - nPaletteIndex = (BYTE)gb.BitRead(2); - } else { - if (gb.BitRead(1) == 0) { // switch_2 - switch (gb.BitRead(2)) { // switch_3 - case 0: - bQuit = true; - break; - case 1: - nCount = 2; - break; - case 2: // if (switch_3 == '10') - nCount = 12 + (short)gb.BitRead(4); // run_length_12-27 - nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code - break; - case 3: - nCount = 29 + gb.ReadByte(); // run_length_29-284 - nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code - break; - } - } else { - nCount = 1; - } - } - } - - if (nCount > 0) { - FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); - nX += nCount; - } - } - - gb.BitByteAlign(); -} - -void CompositionObject::Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) -{ - bool bQuit = false; - - while (!bQuit && !gb.IsEOF()) { - short nCount = 0; - BYTE nPaletteIndex = 0; - BYTE bTemp = (BYTE)gb.BitRead(4); - if (bTemp != 0) { - nPaletteIndex = bTemp; - nCount = 1; - } else { - if (gb.BitRead(1) == 0) { // switch_1 - nCount = (short)gb.BitRead(3); // run_length_3-9 - if (nCount != 0) { - nCount += 2; - } else { - bQuit = true; - } - } else { - if (gb.BitRead(1) == 0) { // switch_2 - nCount = 4 + (short)gb.BitRead(2); // run_length_4-7 - nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code - } else { - switch (gb.BitRead(2)) { // switch_3 - case 0: - nCount = 1; - break; - case 1: - nCount = 2; - break; - case 2: // if (switch_3 == '10') - nCount = 9 + (short)gb.BitRead(4); // run_length_9-24 - nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code - break; - case 3: - nCount = 25 + gb.ReadByte(); // run_length_25-280 - nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code - break; - } - } - } - } - - if (nCount > 0) { - FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); - nX += nCount; - } - } - - gb.BitByteAlign(); -} - -void CompositionObject::Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) -{ - bool bQuit = false; - - while (!bQuit && !gb.IsEOF()) { - short nCount = 0; - BYTE nPaletteIndex = 0; - BYTE bTemp = gb.ReadByte(); - if (bTemp != 0) { - nPaletteIndex = bTemp; - nCount = 1; - } else { - if (gb.BitRead(1) == 0) { // switch_1 - nCount = (short)gb.BitRead(7); // run_length_1-127 - if (nCount == 0) { - bQuit = true; - } - } else { - nCount = (short)gb.BitRead(7); // run_length_3-127 - nPaletteIndex = gb.ReadByte(); - } - } - - if (nCount > 0) { - FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); - nX += nCount; - } - } - - gb.BitByteAlign(); -} +/* + * (C) 2009-2015 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 . + * + */ + +#include "stdafx.h" +#include "CompositionObject.h" +#include "ColorConvTable.h" +#include "../DSUtil/GolombBuffer.h" + + +CompositionObject::CompositionObject() +{ + Init(); +} + +CompositionObject::CompositionObject(const CompositionObject& obj) + : m_object_id_ref(obj.m_object_id_ref) + , m_window_id_ref(obj.m_window_id_ref) + , m_object_cropped_flag(obj.m_object_cropped_flag) + , m_forced_on_flag(obj.m_forced_on_flag) + , m_version_number(obj.m_version_number) + , m_horizontal_position(obj.m_horizontal_position) + , m_vertical_position(obj.m_vertical_position) + , m_width(obj.m_width) + , m_height(obj.m_height) + , m_cropping_horizontal_position(obj.m_cropping_horizontal_position) + , m_cropping_vertical_position(obj.m_cropping_vertical_position) + , m_cropping_width(obj.m_cropping_width) + , m_cropping_height(obj.m_cropping_height) + , m_pRLEData(nullptr) + , m_nRLEDataSize(0) + , m_nRLEPos(0) + , m_nColorNumber(obj.m_nColorNumber) + , m_colors(obj.m_colors) +{ + if (obj.m_pRLEData) { + SetRLEData(obj.m_pRLEData, obj.m_nRLEPos, obj.m_nRLEDataSize); + } +} + +CompositionObject::~CompositionObject() +{ + delete [] m_pRLEData; +} + +void CompositionObject::Init() +{ + m_pRLEData = nullptr; + m_nRLEDataSize = m_nRLEPos = 0; + m_nColorNumber = 0; + m_object_id_ref = 0; + m_window_id_ref = 0; + m_object_cropped_flag = false; + m_forced_on_flag = false; + m_version_number = 0; + m_horizontal_position = m_vertical_position = 0; + m_width = m_height = 0; + m_cropping_horizontal_position = m_cropping_vertical_position = 0; + m_cropping_width = m_cropping_height = 0; + + m_colors.fill(0); +} + +void CompositionObject::Reset() +{ + delete[] m_pRLEData; + Init(); +} + +void CompositionObject::SetPalette(int nNbEntry, const HDMV_PALETTE* pPalette, ColorConvTable::YuvMatrixType currentMatrix) +{ + m_nColorNumber = nNbEntry; + for (int i = 0; i < nNbEntry; i++) { + m_colors[pPalette[i].entry_id] = ColorConvTable::A8Y8U8V8_TO_ARGB(pPalette[i].T, pPalette[i].Y, pPalette[i].Cb, pPalette[i].Cr, currentMatrix); + } +} + +void CompositionObject::SetRLEData(const BYTE* pBuffer, size_t nSize, size_t nTotalSize) +{ + delete [] m_pRLEData; + + if (nTotalSize > 0 && nSize <= nTotalSize) { + m_pRLEData = DEBUG_NEW BYTE[nTotalSize]; + m_nRLEDataSize = nTotalSize; + m_nRLEPos = nSize; + + memcpy(m_pRLEData, pBuffer, nSize); + } else { + m_pRLEData = nullptr; + m_nRLEDataSize = m_nRLEPos = 0; + ASSERT(FALSE); // This shouldn't happen in normal operation + } +} + +void CompositionObject::AppendRLEData(const BYTE* pBuffer, size_t nSize) +{ + if (m_nRLEPos + nSize <= m_nRLEDataSize) { + memcpy(m_pRLEData + m_nRLEPos, pBuffer, nSize); + m_nRLEPos += nSize; + } else { + ASSERT(FALSE); // This shouldn't happen in normal operation + } +} + +void CompositionObject::RenderHdmv(SubPicDesc& spd) +{ + if (!m_pRLEData || !m_nColorNumber) { + return; + } + + CGolombBuffer GBuffer(m_pRLEData, m_nRLEDataSize); + BYTE bSwitch; + BYTE nPaletteIndex = 0; + LONG nCount; + LONG nX = m_horizontal_position; + LONG nY = m_vertical_position; + + while ((nY < (m_vertical_position + m_height)) && !GBuffer.IsEOF()) { + BYTE bTemp = GBuffer.ReadByte(); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + bSwitch = GBuffer.ReadByte(); + if (!(bSwitch & 0x80)) { + if (!(bSwitch & 0x40)) { + nCount = bSwitch & 0x3F; + if (nCount > 0) { + nPaletteIndex = 0; + } + } else { + nCount = (bSwitch & 0x3F) << 8 | (short)GBuffer.ReadByte(); + nPaletteIndex = 0; + } + } else { + if (!(bSwitch & 0x40)) { + nCount = bSwitch & 0x3F; + nPaletteIndex = GBuffer.ReadByte(); + } else { + nCount = (bSwitch & 0x3F) << 8 | (short)GBuffer.ReadByte(); + nPaletteIndex = GBuffer.ReadByte(); + } + } + } + + if (nCount > 0) { + if (nPaletteIndex != 0xFF) { // Fully transparent (section 9.14.4.2.2.1.1) + FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); + } + nX += nCount; + } else { + nY++; + nX = m_horizontal_position; + } + } +} + +void CompositionObject::RenderDvb(SubPicDesc& spd, short nX, short nY) +{ + if (!m_pRLEData) { + return; + } + + CGolombBuffer gb(m_pRLEData, m_nRLEDataSize); + short sTopFieldLength; + short sBottomFieldLength; + + sTopFieldLength = gb.ReadShort(); + sBottomFieldLength = gb.ReadShort(); + + DvbRenderField(spd, gb, nX, nY, sTopFieldLength); + DvbRenderField(spd, gb, nX, nY + 1, sBottomFieldLength); +} + +void CompositionObject::DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, short nXStart, short nYStart, short nLength) +{ + //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0xFFFF0000); // Red opaque + //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0xCC00FF00); // Green 80% + //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0x100000FF); // Blue 60% + //return; + short nX = nXStart; + short nY = nYStart; + size_t nEnd = gb.GetPos() + nLength; + if (nEnd > gb.GetSize()) { + // Unexpected end of data, the file is probably corrupted + // but try to render the subtitles anyway + ASSERT(FALSE); + nEnd = gb.GetSize(); + } + + while (gb.GetPos() < nEnd) { + BYTE bType = gb.ReadByte(); + switch (bType) { + case 0x10: + Dvb2PixelsCodeString(spd, gb, nX, nY); + break; + case 0x11: + Dvb4PixelsCodeString(spd, gb, nX, nY); + break; + case 0x12: + Dvb8PixelsCodeString(spd, gb, nX, nY); + break; + case 0x20: + gb.SkipBytes(2); + break; + case 0x21: + gb.SkipBytes(4); + break; + case 0x22: + gb.SkipBytes(16); + break; + case 0xF0: + nX = nXStart; + nY += 2; + break; + default: + ASSERT(FALSE); + break; + } + } +} + +void CompositionObject::Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) +{ + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + short nCount = 0; + BYTE nPaletteIndex = 0; + BYTE bTemp = (BYTE)gb.BitRead(2); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 1) { // switch_1 + nCount = 3 + (short)gb.BitRead(3); // run_length_3-9 + nPaletteIndex = (BYTE)gb.BitRead(2); + } else { + if (gb.BitRead(1) == 0) { // switch_2 + switch (gb.BitRead(2)) { // switch_3 + case 0: + bQuit = true; + break; + case 1: + nCount = 2; + break; + case 2: // if (switch_3 == '10') + nCount = 12 + (short)gb.BitRead(4); // run_length_12-27 + nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code + break; + case 3: + nCount = 29 + gb.ReadByte(); // run_length_29-284 + nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code + break; + } + } else { + nCount = 1; + } + } + } + + if (nCount > 0) { + FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} + +void CompositionObject::Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) +{ + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + short nCount = 0; + BYTE nPaletteIndex = 0; + BYTE bTemp = (BYTE)gb.BitRead(4); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 0) { // switch_1 + nCount = (short)gb.BitRead(3); // run_length_3-9 + if (nCount != 0) { + nCount += 2; + } else { + bQuit = true; + } + } else { + if (gb.BitRead(1) == 0) { // switch_2 + nCount = 4 + (short)gb.BitRead(2); // run_length_4-7 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + } else { + switch (gb.BitRead(2)) { // switch_3 + case 0: + nCount = 1; + break; + case 1: + nCount = 2; + break; + case 2: // if (switch_3 == '10') + nCount = 9 + (short)gb.BitRead(4); // run_length_9-24 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + break; + case 3: + nCount = 25 + gb.ReadByte(); // run_length_25-280 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + break; + } + } + } + } + + if (nCount > 0) { + FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} + +void CompositionObject::Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) +{ + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + short nCount = 0; + BYTE nPaletteIndex = 0; + BYTE bTemp = gb.ReadByte(); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 0) { // switch_1 + nCount = (short)gb.BitRead(7); // run_length_1-127 + if (nCount == 0) { + bQuit = true; + } + } else { + nCount = (short)gb.BitRead(7); // run_length_3-127 + nPaletteIndex = gb.ReadByte(); + } + } + + if (nCount > 0) { + FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} diff --git a/src/Subtitles/CompositionObject.h b/src/Subtitles/CompositionObject.h index 767ef4630ed..3da3438ba3e 100644 --- a/src/Subtitles/CompositionObject.h +++ b/src/Subtitles/CompositionObject.h @@ -1,92 +1,92 @@ -/* - * (C) 2009-2015 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 . - * - */ - -#pragma once - -#include "Rasterizer.h" -#include "ColorConvTable.h" - - -struct HDMV_PALETTE { - BYTE entry_id; - BYTE Y; - BYTE Cr; - BYTE Cb; - BYTE T; // HDMV rule : 0 transparent, 255 opaque (compatible DirectX) -}; - -class CGolombBuffer; - -class CompositionObject : Rasterizer -{ -public: - short m_object_id_ref; - BYTE m_window_id_ref; - bool m_object_cropped_flag; - bool m_forced_on_flag; - BYTE m_version_number; - - LONG m_horizontal_position; - LONG m_vertical_position; - LONG m_width; - LONG m_height; - - LONG m_cropping_horizontal_position; - LONG m_cropping_vertical_position; - LONG m_cropping_width; - LONG m_cropping_height; - - CompositionObject(); - CompositionObject(const CompositionObject& obj); - ~CompositionObject(); - - void Init(); - void Reset(); - - void SetRLEData(const BYTE* pBuffer, size_t nSize, size_t nTotalSize); - void AppendRLEData(const BYTE* pBuffer, size_t nSize); - const BYTE* GetRLEData() const { return m_pRLEData; }; - size_t GetRLEDataSize() const { return m_nRLEDataSize; }; - size_t GetRLEPos() const { return m_nRLEPos; }; - bool IsRLEComplete() const { return m_nRLEPos >= m_nRLEDataSize; }; - void RenderHdmv(SubPicDesc& spd); - void RenderDvb(SubPicDesc& spd, short nX, short nY); - void WriteSeg(SubPicDesc& spd, short nX, short nY, short nCount, short nPaletteIndex); - void SetPalette(int nNbEntry, const HDMV_PALETTE* pPalette, ColorConvTable::YuvMatrixType currentMatrix); - bool HavePalette() const { return m_nColorNumber > 0; }; - - // Forbid the use of direct affectation for now, it would be dangerous because - // of possible leaks and double frees. We could do a deep copy to be safe but - // it could possibly hurt the performance if we forgot about this and start - // using affectation a lot. - CompositionObject& operator=(const CompositionObject&) = delete; - -private: - BYTE* m_pRLEData; - size_t m_nRLEDataSize; - size_t m_nRLEPos; - int m_nColorNumber; - std::array m_colors; - - void DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, short nXStart, short nYStart, short nLength); - void Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); - void Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); - void Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); -}; +/* + * (C) 2009-2015 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 . + * + */ + +#pragma once + +#include "Rasterizer.h" +#include "ColorConvTable.h" + + +struct HDMV_PALETTE { + BYTE entry_id; + BYTE Y; + BYTE Cr; + BYTE Cb; + BYTE T; // HDMV rule : 0 transparent, 255 opaque (compatible DirectX) +}; + +class CGolombBuffer; + +class CompositionObject : Rasterizer +{ +public: + short m_object_id_ref; + BYTE m_window_id_ref; + bool m_object_cropped_flag; + bool m_forced_on_flag; + BYTE m_version_number; + + LONG m_horizontal_position; + LONG m_vertical_position; + LONG m_width; + LONG m_height; + + LONG m_cropping_horizontal_position; + LONG m_cropping_vertical_position; + LONG m_cropping_width; + LONG m_cropping_height; + + CompositionObject(); + CompositionObject(const CompositionObject& obj); + ~CompositionObject(); + + void Init(); + void Reset(); + + void SetRLEData(const BYTE* pBuffer, size_t nSize, size_t nTotalSize); + void AppendRLEData(const BYTE* pBuffer, size_t nSize); + const BYTE* GetRLEData() const { return m_pRLEData; }; + size_t GetRLEDataSize() const { return m_nRLEDataSize; }; + size_t GetRLEPos() const { return m_nRLEPos; }; + bool IsRLEComplete() const { return m_nRLEPos >= m_nRLEDataSize; }; + void RenderHdmv(SubPicDesc& spd); + void RenderDvb(SubPicDesc& spd, short nX, short nY); + void WriteSeg(SubPicDesc& spd, short nX, short nY, short nCount, short nPaletteIndex); + void SetPalette(int nNbEntry, const HDMV_PALETTE* pPalette, ColorConvTable::YuvMatrixType currentMatrix); + bool HavePalette() const { return m_nColorNumber > 0; }; + + // Forbid the use of direct affectation for now, it would be dangerous because + // of possible leaks and double frees. We could do a deep copy to be safe but + // it could possibly hurt the performance if we forgot about this and start + // using affectation a lot. + CompositionObject& operator=(const CompositionObject&) = delete; + +private: + BYTE* m_pRLEData; + size_t m_nRLEDataSize; + size_t m_nRLEPos; + int m_nColorNumber; + std::array m_colors; + + void DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, short nXStart, short nYStart, short nLength); + void Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); + void Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); + void Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); +}; diff --git a/src/Subtitles/DVBSub.cpp b/src/Subtitles/DVBSub.cpp index cc1384869dc..45054ce3385 100644 --- a/src/Subtitles/DVBSub.cpp +++ b/src/Subtitles/DVBSub.cpp @@ -1,708 +1,708 @@ -/* - * (C) 2009-2016 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 . - * - */ - - -#include "stdafx.h" -#include "DVBSub.h" -#include "../DSUtil/GolombBuffer.h" -#include - -#if (0) // Set to 1 to activate DVB subtitles traces -#define TRACE_DVB TRACE -#else -#define TRACE_DVB __noop -#endif - -#define BUFFER_CHUNK_GROW 0x1000 - -CDVBSub::CDVBSub(CCritSec* pLock, const CString& name, LCID lcid) - : CRLECodedSubtitle(pLock, name, lcid) - , m_nBufferSize(0) - , m_nBufferReadPos(0) - , m_nBufferWritePos(0) - , m_pBuffer(nullptr) -{ - if (m_name.IsEmpty() || m_name == _T("Unknown")) { - m_name = _T("DVB Embedded Subtitle"); - } -} - -CDVBSub::~CDVBSub() -{ - Reset(); - SAFE_DELETE(m_pBuffer); -} - -// ISubPicProvider - -STDMETHODIMP_(POSITION) CDVBSub::GetStartPosition(REFERENCE_TIME rt, double fps) -{ - CAutoLock cAutoLock(&m_csCritSec); - - POSITION pos = m_pages.GetHeadPosition(); - while (pos) { - const auto& pPage = m_pages.GetAt(pos); - if (pPage->rtStop <= rt) { - m_pages.GetNext(pos); - } else { - break; - } - } - - return pos; -} - -STDMETHODIMP_(POSITION) CDVBSub::GetNext(POSITION pos) -{ - CAutoLock cAutoLock(&m_csCritSec); - m_pages.GetNext(pos); - return pos; -} - -STDMETHODIMP_(REFERENCE_TIME) CDVBSub::GetStart(POSITION pos, double fps) -{ - const auto& pPage = m_pages.GetAt(pos); - return pPage ? pPage->rtStart : INVALID_TIME; -} - -STDMETHODIMP_(REFERENCE_TIME) CDVBSub::GetStop(POSITION pos, double fps) -{ - const auto& pPage = m_pages.GetAt(pos); - return pPage ? pPage->rtStop : INVALID_TIME; -} - -STDMETHODIMP_(bool) CDVBSub::IsAnimated(POSITION pos) -{ - return false; -} - -STDMETHODIMP CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - CAutoLock cAutoLock(&m_csCritSec); - - RemoveOldPages(rt); - - if (POSITION posPage = FindPage(rt)) { - const auto& pPage = m_pages.GetAt(posPage); - if (m_eSourceMatrix == ColorConvTable::AUTO) { - m_eSourceMatrix = (m_displayInfo.width > 720) ? ColorConvTable::BT709 : ColorConvTable::BT601; - } - - pPage->rendered = true; - TRACE_DVB(_T("DVB - Renderer - %s - %s\n"), ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); - - size_t nRegion = 1; - for (const auto& regionPos : pPage->regionsPos) { - auto itRegion = FindRegion(pPage, regionPos.id); - if (itRegion != pPage->regions.cend()) { - const auto& pRegion = *itRegion; - auto itCLUT = FindClut(pPage, pRegion->CLUT_id); - - if (itCLUT != pPage->CLUTs.cend()) { - const auto& pCLUT = *itCLUT; - - size_t nObject = 1; - for (const auto& objectPos : pRegion->objects) { - auto itObject = FindObject(pPage, objectPos.object_id); - - if (itObject != pPage->objects.cend()) { - const auto& pObject = *itObject; - - short nX = regionPos.horizAddr + objectPos.object_horizontal_position; - short nY = regionPos.vertAddr + objectPos.object_vertical_position; - pObject->m_width = pRegion->width; - pObject->m_height = pRegion->height; - pObject->SetPalette(pCLUT->size, pCLUT->palette.data(), m_eSourceMatrix); - pObject->RenderDvb(spd, nX, nY); - - TRACE_DVB(_T(" --> %Iu/%Iu - %Iu/%Iu\n"), nRegion, pPage->regionsPos.size(), nObject, pRegion->objects.size()); - } - - nObject++; - } - } - } - - nRegion++; - } - - bbox.left = 0; - bbox.top = 0; - bbox.right = m_displayInfo.width; - bbox.bottom = m_displayInfo.height; - } - - return S_OK; -} - -HRESULT CDVBSub::GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) -{ - MaxTextureSize.cx = VideoSize.cx = m_displayInfo.width; - MaxTextureSize.cy = VideoSize.cy = m_displayInfo.height; - - VideoTopLeft.x = 0; - VideoTopLeft.y = 0; - - return S_OK; -} - -#define MARKER \ - if (gb.BitRead(1) != 1) { \ - ASSERT(FALSE); \ - return E_FAIL; \ - } - -HRESULT CDVBSub::ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen) -{ - CheckPointer(pData, E_POINTER); - - CAutoLock cAutoLock(&m_csCritSec); - - HRESULT hr; - DVB_SEGMENT_TYPE nCurSegment; - - - if (*((LONG*)pData) == 0xBD010000) { - CGolombBuffer gb(pData, nLen); - - size_t headerSize = 9; - - gb.SkipBytes(4); - WORD wLength = (WORD)gb.BitRead(16); - UNREFERENCED_PARAMETER(wLength); - - if (gb.BitRead(2) != 2) { - return E_FAIL; // type - } - - gb.BitRead(2); // scrambling - gb.BitRead(1); // priority - gb.BitRead(1); // alignment - gb.BitRead(1); // copyright - gb.BitRead(1); // original - BYTE fpts = (BYTE)gb.BitRead(1); // fpts - BYTE fdts = (BYTE)gb.BitRead(1); // fdts - gb.BitRead(1); // escr - gb.BitRead(1); // esrate - gb.BitRead(1); // dsmtrickmode - gb.BitRead(1); // morecopyright - gb.BitRead(1); // crc - gb.BitRead(1); // extension - gb.BitRead(8); // hdrlen - - if (fpts) { - BYTE b = (BYTE)gb.BitRead(4); - if (!(fdts && b == 3 || !fdts && b == 2)) { - ASSERT(FALSE); - return E_FAIL; - } - - REFERENCE_TIME pts = 0; - pts |= gb.BitRead(3) << 30; - MARKER; // 32..30 - pts |= gb.BitRead(15) << 15; - MARKER; // 29..15 - pts |= gb.BitRead(15); - MARKER; // 14..0 - pts = 10000 * pts / 90; - - TRACE_DVB(_T("DVB - ParseSample: Received a packet with a presentation timestamp PTS=%s\n"), ReftimeToString(pts)); - if (pts != rtStart) { - TRACE_DVB(_T("DVB - ParseSample: WARNING: The parsed PTS doesn't match the sample start time (%s)\n"), ReftimeToString(rtStart)); - ASSERT(FALSE); - rtStart = pts; - } - - headerSize += 5; - } - - nLen -= headerSize; - pData += headerSize; - } - - hr = AddToBuffer(pData, nLen); - if (hr == S_OK) { - CGolombBuffer gb(m_pBuffer + m_nBufferReadPos, m_nBufferWritePos - m_nBufferReadPos); - size_t nLastPos = 0; - - while (gb.RemainingSize() >= 6) { // Ensure there is enough data to parse the entire segment header - if (gb.ReadByte() == 0x0F) { - TRACE_DVB(_T("DVB - ParseSample\n")); - - WORD wPageId; - WORD wSegLength; - - nCurSegment = (DVB_SEGMENT_TYPE)gb.ReadByte(); - wPageId = gb.ReadShort(); - wSegLength = gb.ReadShort(); - - if (gb.RemainingSize() < wSegLength) { - TRACE_DVB(_T("DVB - Full segment isn't availabled yet, delaying parsing (%Iu/%hu)\n"), gb.RemainingSize(), wSegLength); - hr = S_FALSE; - break; - } - - hr = S_OK; - switch (nCurSegment) { - case PAGE: { - if (rtStart == INVALID_TIME) { - TRACE_DVB(_T("DVB - Page update ignored, %s\n"), ReftimeToString(rtStart)); - break; - } - - if (m_pCurrentPage) { - TRACE_DVB(_T("DVB - Force End display\n")); - EnqueuePage(rtStart); - } - UpdateTimeStamp(rtStart); - - CAutoPtr pPage; - hr = ParsePage(gb, wSegLength, pPage); - pPage->rtStart = rtStart; - pPage->rtStop = pPage->rtStart + pPage->pageTimeOut * 10000000i64; - - if (FAILED(hr)) { - pPage.Free(); - } else if (pPage->pageState == DPS_ACQUISITION || pPage->pageState == DPS_MODE_CHANGE) { - m_pCurrentPage = pPage; - - TRACE_DVB(_T("DVB - Page started [pageState = %d] %s, TimeOut = %ds\n"), m_pCurrentPage->pageState, - ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->pageTimeOut); - } else if (pPage->pageState == DPS_NORMAL && !m_pages.IsEmpty()) { - m_pCurrentPage = pPage; - - // Copy data from the previous page - const auto& pPrevPage = m_pages.GetTail(); - - for (const auto& region : pPrevPage->regions) { - m_pCurrentPage->regions.emplace_back(DEBUG_NEW DVB_REGION(*region)); - } - - for (const auto& object : pPrevPage->objects) { - m_pCurrentPage->objects.emplace_back(DEBUG_NEW CompositionObject(*object)); - } - - for (const auto& CLUT : pPrevPage->CLUTs) { - m_pCurrentPage->CLUTs.emplace_back(DEBUG_NEW DVB_CLUT(*CLUT)); - } - - TRACE_DVB(_T("DVB - Page started [update] %s, TimeOut = %ds\n"), - ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->pageTimeOut); - } else { - TRACE_DVB(_T("DVB - Page update ignored %s\n"), ReftimeToString(rtStart)); - } - } - break; - case REGION: - ParseRegion(gb, wSegLength); - TRACE_DVB(_T("DVB - Region\n")); - break; - case CLUT: - ParseClut(gb, wSegLength); - TRACE_DVB(_T("DVB - Clut\n")); - break; - case OBJECT: - ParseObject(gb, wSegLength); - TRACE_DVB(_T("DVB - Object\n")); - break; - case DISPLAY: - ParseDisplay(gb, wSegLength); - TRACE_DVB(_T("DVB - Display\n")); - break; - case END_OF_DISPLAY: - if (m_pCurrentPage == nullptr) { - TRACE_DVB(_T("DVB - Ignored End display %s: no current page\n"), ReftimeToString(rtStart)); - } else if (m_pCurrentPage->rtStart < rtStart) { - TRACE_DVB(_T("DVB - End display\n")); - EnqueuePage(rtStart); - } else { - TRACE_DVB(_T("DVB - Ignored End display %s: no information on page duration\n"), ReftimeToString(rtStart)); - } - break; - default: - TRACE_DVB(_T("DVB - Ignored segment with unknown type %d\n"), nCurSegment); - break; - } - if (FAILED(hr)) { - gb.SkipBytes(6 + wSegLength - (gb.GetPos() - nLastPos)); - TRACE_DVB(_T("Parsing failed with code %x, skipping to the end of the segment\n"), hr); - } - } - nLastPos = gb.GetPos(); - } - m_nBufferReadPos += nLastPos; - } - - return hr; -} - -void CDVBSub::EndOfStream() -{ - CAutoLock cAutoLock(&m_csCritSec); - - // Enqueue the last page if necessary. - if (m_pCurrentPage) { - TRACE_DVB(_T("DVB - EndOfStream: Enqueue last page\n")); - EnqueuePage(INVALID_TIME); - } else { - TRACE_DVB(_T("DVB - EndOfStream ignored: no page to enqueue\n")); - } -} - -void CDVBSub::Reset() -{ - CAutoLock cAutoLock(&m_csCritSec); - - m_nBufferReadPos = 0; - m_nBufferWritePos = 0; - m_pCurrentPage.Free(); - m_pages.RemoveAll(); -} - -HRESULT CDVBSub::AddToBuffer(BYTE* pData, size_t nSize) -{ - bool bFirstChunk = (*((LONG*)pData) & 0x00FFFFFF) == 0x000f0020; // DVB sub start with 0x20 0x00 0x0F ... - - if (m_nBufferWritePos > 0 || bFirstChunk) { - if (bFirstChunk) { - m_nBufferWritePos = 0; - m_nBufferReadPos = 0; - } - - if (m_nBufferWritePos + nSize > m_nBufferSize) { - if (m_nBufferWritePos + nSize > 20 * BUFFER_CHUNK_GROW) { - // Too big to be a DVB sub ! - TRACE_DVB(_T("DVB - Too much data received...\n")); - ASSERT(FALSE); - - Reset(); - return E_INVALIDARG; - } - - BYTE* pPrev = m_pBuffer; - m_nBufferSize = std::max(m_nBufferWritePos + nSize, m_nBufferSize + BUFFER_CHUNK_GROW); - m_pBuffer = DEBUG_NEW BYTE[m_nBufferSize]; - if (pPrev != nullptr) { - memcpy_s(m_pBuffer, m_nBufferSize, pPrev, m_nBufferWritePos); - SAFE_DELETE(pPrev); - } - } - memcpy_s(m_pBuffer + m_nBufferWritePos, m_nBufferSize, pData, nSize); - m_nBufferWritePos += nSize; - return S_OK; - } - return S_FALSE; -} - -POSITION CDVBSub::FindPage(REFERENCE_TIME rt) const -{ - POSITION pos = m_pages.GetHeadPosition(); - - while (pos) { - POSITION currentPos = pos; - const auto& pPage = m_pages.GetNext(pos); - - if (rt >= pPage->rtStart && rt < pPage->rtStop) { - return currentPos; - } - } - - return nullptr; -} - -CDVBSub::RegionList::const_iterator CDVBSub::FindRegion(const CAutoPtr& pPage, BYTE bRegionId) const -{ - ENSURE(pPage); - - return std::find_if(pPage->regions.cbegin(), pPage->regions.cend(), - [bRegionId](const std::unique_ptr& pRegion) { - return pRegion->id == bRegionId; - }); -} - -CDVBSub::ClutList::const_iterator CDVBSub::FindClut(const CAutoPtr& pPage, BYTE bClutId) const -{ - ENSURE(pPage); - - return std::find_if(pPage->CLUTs.cbegin(), pPage->CLUTs.cend(), - [bClutId](const std::unique_ptr& pCLUT) { - return pCLUT->id == bClutId; - }); -} - -CDVBSub::CompositionObjectList::const_iterator CDVBSub::FindObject(const CAutoPtr& pPage, short sObjectId) const -{ - ENSURE(pPage); - - return std::find_if(pPage->objects.cbegin(), pPage->objects.cend(), - [sObjectId](const std::unique_ptr& pObject) { - return pObject->m_object_id_ref == sObjectId; - }); -} - -HRESULT CDVBSub::ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage) -{ - size_t nExpectedSize = 2; - size_t nEnd = gb.GetPos() + wSegLength; - - pPage.Attach(DEBUG_NEW DVB_PAGE()); - - pPage->pageTimeOut = gb.ReadByte(); - pPage->pageVersionNumber = (BYTE)gb.BitRead(4); - pPage->pageState = (BYTE)gb.BitRead(2); - gb.BitRead(2); // Reserved - while (gb.GetPos() < nEnd) { - nExpectedSize += 6; - DVB_REGION_POS regionPos; - regionPos.id = gb.ReadByte(); - gb.ReadByte(); // Reserved - regionPos.horizAddr = gb.ReadShort(); - regionPos.vertAddr = gb.ReadShort(); - pPage->regionsPos.emplace_back(std::move(regionPos)); - } - - return (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; -} - -HRESULT CDVBSub::ParseDisplay(CGolombBuffer& gb, WORD wSegLength) -{ - int nExpectedSize = 5; - - m_displayInfo.version_number = (BYTE)gb.BitRead(4); - m_displayInfo.display_window_flag = (BYTE)gb.BitRead(1); - gb.BitRead(3); // reserved - m_displayInfo.width = gb.ReadShort() + 1; - m_displayInfo.height = gb.ReadShort() + 1; - if (m_displayInfo.display_window_flag) { - nExpectedSize += 8; - m_displayInfo.horizontal_position_minimun = gb.ReadShort(); - m_displayInfo.horizontal_position_maximum = gb.ReadShort(); - m_displayInfo.vertical_position_minimun = gb.ReadShort(); - m_displayInfo.vertical_position_maximum = gb.ReadShort(); - } - - return (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; -} - -HRESULT CDVBSub::ParseRegion(CGolombBuffer& gb, WORD wSegLength) -{ - HRESULT hr = E_POINTER; - - if (m_pCurrentPage) { - size_t nExpectedSize = 10; - size_t nEnd = gb.GetPos() + wSegLength; - - BYTE id = gb.ReadByte(); - auto itRegion = FindRegion(m_pCurrentPage, id); - if (itRegion == m_pCurrentPage->regions.cend()) { - m_pCurrentPage->regions.emplace_back(DEBUG_NEW DVB_REGION()); - itRegion = std::prev(m_pCurrentPage->regions.cend()); - } - const auto& pRegion = *itRegion; - - pRegion->id = id; - pRegion->version_number = (BYTE)gb.BitRead(4); - pRegion->fill_flag = (BYTE)gb.BitRead(1); - gb.BitRead(3); // Reserved - pRegion->width = gb.ReadShort(); - pRegion->height = gb.ReadShort(); - pRegion->level_of_compatibility = (BYTE)gb.BitRead(3); - pRegion->depth = (BYTE)gb.BitRead(3); - gb.BitRead(2); // Reserved - pRegion->CLUT_id = gb.ReadByte(); - pRegion->_8_bit_pixel_code = gb.ReadByte(); - pRegion->_4_bit_pixel_code = (BYTE)gb.BitRead(4); - pRegion->_2_bit_pixel_code = (BYTE)gb.BitRead(2); - gb.BitRead(2); // Reserved - - while (gb.GetPos() < nEnd) { - nExpectedSize += 6; - DVB_OBJECT object; - object.object_id = gb.ReadShort(); - object.object_type = (BYTE)gb.BitRead(2); - object.object_provider_flag = (BYTE)gb.BitRead(2); - object.object_horizontal_position = (short)gb.BitRead(12); - gb.BitRead(4); // Reserved - object.object_vertical_position = (short)gb.BitRead(12); - if (object.object_type == 0x01 || object.object_type == 0x02) { - nExpectedSize += 2; - object.foreground_pixel_code = gb.ReadByte(); - object.background_pixel_code = gb.ReadByte(); - } - pRegion->objects.emplace_back(std::move(object)); - } - - hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; - } - - return hr; -} - -HRESULT CDVBSub::ParseClut(CGolombBuffer& gb, WORD wSegLength) -{ - HRESULT hr = E_POINTER; - - if (m_pCurrentPage) { - size_t nExpectedSize = 2; - size_t nEnd = gb.GetPos() + wSegLength; - - BYTE id = gb.ReadByte(); - auto itClut = FindClut(m_pCurrentPage, id); - if (itClut == m_pCurrentPage->CLUTs.cend()) { - m_pCurrentPage->CLUTs.emplace_back(DEBUG_NEW DVB_CLUT()); - itClut = std::prev(m_pCurrentPage->CLUTs.cend()); - } - const auto& pClut = *itClut; - - pClut->id = id; - pClut->version_number = (BYTE)gb.BitRead(4); - gb.BitRead(4); // Reserved - - pClut->size = 0; - while (gb.GetPos() < nEnd) { - nExpectedSize += 2; - pClut->palette[pClut->size].entry_id = gb.ReadByte(); - - BYTE _2_bit = (BYTE)gb.BitRead(1); - BYTE _4_bit = (BYTE)gb.BitRead(1); - BYTE _8_bit = (BYTE)gb.BitRead(1); - UNREFERENCED_PARAMETER(_2_bit); - UNREFERENCED_PARAMETER(_4_bit); - UNREFERENCED_PARAMETER(_8_bit); - gb.BitRead(4); // Reserved - - if (gb.BitRead(1)) { - nExpectedSize += 4; - pClut->palette[pClut->size].Y = gb.ReadByte(); - pClut->palette[pClut->size].Cr = gb.ReadByte(); - pClut->palette[pClut->size].Cb = gb.ReadByte(); - pClut->palette[pClut->size].T = 0xff - gb.ReadByte(); - } else { - nExpectedSize += 2; - pClut->palette[pClut->size].Y = (BYTE)gb.BitRead(6) << 2; - pClut->palette[pClut->size].Cr = (BYTE)gb.BitRead(4) << 4; - pClut->palette[pClut->size].Cb = (BYTE)gb.BitRead(4) << 4; - pClut->palette[pClut->size].T = 0xff - ((BYTE)gb.BitRead(2) << 6); - } - if (!pClut->palette[pClut->size].Y) { - pClut->palette[pClut->size].Cr = 0; - pClut->palette[pClut->size].Cb = 0; - pClut->palette[pClut->size].T = 0; - } - - pClut->size++; - } - - hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; - } - - return hr; -} - -HRESULT CDVBSub::ParseObject(CGolombBuffer& gb, WORD wSegLength) -{ - HRESULT hr = E_POINTER; - - if (m_pCurrentPage) { - size_t nExpectedSize = 3; - // size_t nEnd = gb.GetPos() + wSegLength; - - short id = gb.ReadShort(); - auto itObject = FindObject(m_pCurrentPage, id); - if (itObject == m_pCurrentPage->objects.cend()) { - m_pCurrentPage->objects.emplace_back(DEBUG_NEW CompositionObject()); - itObject = std::prev(m_pCurrentPage->objects.cend()); - } - const auto& pObject = *itObject; - - pObject->m_object_id_ref = id; - pObject->m_version_number = (BYTE)gb.BitRead(4); - - BYTE object_coding_method = (BYTE)gb.BitRead(2); // object_coding_method - gb.BitRead(1); // non_modifying_colour_flag - gb.BitRead(1); // reserved - - if (object_coding_method == 0x00) { - pObject->SetRLEData(gb.GetBufferPos(), wSegLength - nExpectedSize, wSegLength - nExpectedSize); - gb.SkipBytes(wSegLength - 3); - - hr = (wSegLength >= nExpectedSize) ? S_OK : E_UNEXPECTED; - } else { - TRACE_DVB(_T("DVB - Text subtitles are currently not supported\n")); - m_pCurrentPage->objects.pop_back(); - hr = E_NOTIMPL; - } - } - - return hr; -} - -HRESULT CDVBSub::EnqueuePage(REFERENCE_TIME rtStop) -{ - ASSERT(m_pCurrentPage != nullptr); - if (m_pCurrentPage->rtStart < rtStop && m_pCurrentPage->rtStop > rtStop) { - m_pCurrentPage->rtStop = rtStop; - } - TRACE_DVB(_T("DVB - Enqueue page %s (%s - %s)\n"), ReftimeToString(rtStop), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); - m_pages.AddTail(m_pCurrentPage); - - return S_OK; -} - -HRESULT CDVBSub::UpdateTimeStamp(REFERENCE_TIME rtStop) -{ - HRESULT hr = S_FALSE; - POSITION pos = m_pages.GetTailPosition(); - while (pos) { - const auto& pPage = m_pages.GetPrev(pos); - if (pPage->rtStop > rtStop) { - TRACE_DVB(_T("DVB - Updated end of display %s - %s --> %s - %s\n"), - ReftimeToString(pPage->rtStart), - ReftimeToString(pPage->rtStop), - ReftimeToString(pPage->rtStart), - ReftimeToString(rtStop)); - pPage->rtStop = rtStop; - hr = S_OK; - } else { - break; - } - } - - return hr; -} - -void CDVBSub::RemoveOldPages(REFERENCE_TIME rt) -{ - // Cleanup the old pages. We keep a 2 min buffer to play nice with the queue. - while (!m_pages.IsEmpty() && m_pages.GetHead()->rtStop + 120 * 10000000i64 < rt) { - const auto& pPage = m_pages.GetHead(); - if (!pPage->rendered) { - TRACE_DVB(_T("DVB - remove unrendered object, %s - %s\n"), - ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); - } - m_pages.RemoveHeadNoReturn(); - } -} - -STDMETHODIMP CDVBSub::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) -{ - relativeTo = RelativeTo::BEST_FIT; - return S_OK; -} +/* + * (C) 2009-2016 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 . + * + */ + + +#include "stdafx.h" +#include "DVBSub.h" +#include "../DSUtil/GolombBuffer.h" +#include + +#if (0) // Set to 1 to activate DVB subtitles traces +#define TRACE_DVB TRACE +#else +#define TRACE_DVB __noop +#endif + +#define BUFFER_CHUNK_GROW 0x1000 + +CDVBSub::CDVBSub(CCritSec* pLock, const CString& name, LCID lcid) + : CRLECodedSubtitle(pLock, name, lcid) + , m_nBufferSize(0) + , m_nBufferReadPos(0) + , m_nBufferWritePos(0) + , m_pBuffer(nullptr) +{ + if (m_name.IsEmpty() || m_name == _T("Unknown")) { + m_name = _T("DVB Embedded Subtitle"); + } +} + +CDVBSub::~CDVBSub() +{ + Reset(); + SAFE_DELETE(m_pBuffer); +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CDVBSub::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + CAutoLock cAutoLock(&m_csCritSec); + + POSITION pos = m_pages.GetHeadPosition(); + while (pos) { + const auto& pPage = m_pages.GetAt(pos); + if (pPage->rtStop <= rt) { + m_pages.GetNext(pos); + } else { + break; + } + } + + return pos; +} + +STDMETHODIMP_(POSITION) CDVBSub::GetNext(POSITION pos) +{ + CAutoLock cAutoLock(&m_csCritSec); + m_pages.GetNext(pos); + return pos; +} + +STDMETHODIMP_(REFERENCE_TIME) CDVBSub::GetStart(POSITION pos, double fps) +{ + const auto& pPage = m_pages.GetAt(pos); + return pPage ? pPage->rtStart : INVALID_TIME; +} + +STDMETHODIMP_(REFERENCE_TIME) CDVBSub::GetStop(POSITION pos, double fps) +{ + const auto& pPage = m_pages.GetAt(pos); + return pPage ? pPage->rtStop : INVALID_TIME; +} + +STDMETHODIMP_(bool) CDVBSub::IsAnimated(POSITION pos) +{ + return false; +} + +STDMETHODIMP CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + CAutoLock cAutoLock(&m_csCritSec); + + RemoveOldPages(rt); + + if (POSITION posPage = FindPage(rt)) { + const auto& pPage = m_pages.GetAt(posPage); + if (m_eSourceMatrix == ColorConvTable::AUTO) { + m_eSourceMatrix = (m_displayInfo.width > 720) ? ColorConvTable::BT709 : ColorConvTable::BT601; + } + + pPage->rendered = true; + TRACE_DVB(_T("DVB - Renderer - %s - %s\n"), ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); + + size_t nRegion = 1; + for (const auto& regionPos : pPage->regionsPos) { + auto itRegion = FindRegion(pPage, regionPos.id); + if (itRegion != pPage->regions.cend()) { + const auto& pRegion = *itRegion; + auto itCLUT = FindClut(pPage, pRegion->CLUT_id); + + if (itCLUT != pPage->CLUTs.cend()) { + const auto& pCLUT = *itCLUT; + + size_t nObject = 1; + for (const auto& objectPos : pRegion->objects) { + auto itObject = FindObject(pPage, objectPos.object_id); + + if (itObject != pPage->objects.cend()) { + const auto& pObject = *itObject; + + short nX = regionPos.horizAddr + objectPos.object_horizontal_position; + short nY = regionPos.vertAddr + objectPos.object_vertical_position; + pObject->m_width = pRegion->width; + pObject->m_height = pRegion->height; + pObject->SetPalette(pCLUT->size, pCLUT->palette.data(), m_eSourceMatrix); + pObject->RenderDvb(spd, nX, nY); + + TRACE_DVB(_T(" --> %Iu/%Iu - %Iu/%Iu\n"), nRegion, pPage->regionsPos.size(), nObject, pRegion->objects.size()); + } + + nObject++; + } + } + } + + nRegion++; + } + + bbox.left = 0; + bbox.top = 0; + bbox.right = m_displayInfo.width; + bbox.bottom = m_displayInfo.height; + } + + return S_OK; +} + +HRESULT CDVBSub::GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) +{ + MaxTextureSize.cx = VideoSize.cx = m_displayInfo.width; + MaxTextureSize.cy = VideoSize.cy = m_displayInfo.height; + + VideoTopLeft.x = 0; + VideoTopLeft.y = 0; + + return S_OK; +} + +#define MARKER \ + if (gb.BitRead(1) != 1) { \ + ASSERT(FALSE); \ + return E_FAIL; \ + } + +HRESULT CDVBSub::ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen) +{ + CheckPointer(pData, E_POINTER); + + CAutoLock cAutoLock(&m_csCritSec); + + HRESULT hr; + DVB_SEGMENT_TYPE nCurSegment; + + + if (*((LONG*)pData) == 0xBD010000) { + CGolombBuffer gb(pData, nLen); + + size_t headerSize = 9; + + gb.SkipBytes(4); + WORD wLength = (WORD)gb.BitRead(16); + UNREFERENCED_PARAMETER(wLength); + + if (gb.BitRead(2) != 2) { + return E_FAIL; // type + } + + gb.BitRead(2); // scrambling + gb.BitRead(1); // priority + gb.BitRead(1); // alignment + gb.BitRead(1); // copyright + gb.BitRead(1); // original + BYTE fpts = (BYTE)gb.BitRead(1); // fpts + BYTE fdts = (BYTE)gb.BitRead(1); // fdts + gb.BitRead(1); // escr + gb.BitRead(1); // esrate + gb.BitRead(1); // dsmtrickmode + gb.BitRead(1); // morecopyright + gb.BitRead(1); // crc + gb.BitRead(1); // extension + gb.BitRead(8); // hdrlen + + if (fpts) { + BYTE b = (BYTE)gb.BitRead(4); + if (!(fdts && b == 3 || !fdts && b == 2)) { + ASSERT(FALSE); + return E_FAIL; + } + + REFERENCE_TIME pts = 0; + pts |= gb.BitRead(3) << 30; + MARKER; // 32..30 + pts |= gb.BitRead(15) << 15; + MARKER; // 29..15 + pts |= gb.BitRead(15); + MARKER; // 14..0 + pts = 10000 * pts / 90; + + TRACE_DVB(_T("DVB - ParseSample: Received a packet with a presentation timestamp PTS=%s\n"), ReftimeToString(pts)); + if (pts != rtStart) { + TRACE_DVB(_T("DVB - ParseSample: WARNING: The parsed PTS doesn't match the sample start time (%s)\n"), ReftimeToString(rtStart)); + ASSERT(FALSE); + rtStart = pts; + } + + headerSize += 5; + } + + nLen -= headerSize; + pData += headerSize; + } + + hr = AddToBuffer(pData, nLen); + if (hr == S_OK) { + CGolombBuffer gb(m_pBuffer + m_nBufferReadPos, m_nBufferWritePos - m_nBufferReadPos); + size_t nLastPos = 0; + + while (gb.RemainingSize() >= 6) { // Ensure there is enough data to parse the entire segment header + if (gb.ReadByte() == 0x0F) { + TRACE_DVB(_T("DVB - ParseSample\n")); + + WORD wPageId; + WORD wSegLength; + + nCurSegment = (DVB_SEGMENT_TYPE)gb.ReadByte(); + wPageId = gb.ReadShort(); + wSegLength = gb.ReadShort(); + + if (gb.RemainingSize() < wSegLength) { + TRACE_DVB(_T("DVB - Full segment isn't availabled yet, delaying parsing (%Iu/%hu)\n"), gb.RemainingSize(), wSegLength); + hr = S_FALSE; + break; + } + + hr = S_OK; + switch (nCurSegment) { + case PAGE: { + if (rtStart == INVALID_TIME) { + TRACE_DVB(_T("DVB - Page update ignored, %s\n"), ReftimeToString(rtStart)); + break; + } + + if (m_pCurrentPage) { + TRACE_DVB(_T("DVB - Force End display\n")); + EnqueuePage(rtStart); + } + UpdateTimeStamp(rtStart); + + CAutoPtr pPage; + hr = ParsePage(gb, wSegLength, pPage); + pPage->rtStart = rtStart; + pPage->rtStop = pPage->rtStart + pPage->pageTimeOut * 10000000i64; + + if (FAILED(hr)) { + pPage.Free(); + } else if (pPage->pageState == DPS_ACQUISITION || pPage->pageState == DPS_MODE_CHANGE) { + m_pCurrentPage = pPage; + + TRACE_DVB(_T("DVB - Page started [pageState = %d] %s, TimeOut = %ds\n"), m_pCurrentPage->pageState, + ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->pageTimeOut); + } else if (pPage->pageState == DPS_NORMAL && !m_pages.IsEmpty()) { + m_pCurrentPage = pPage; + + // Copy data from the previous page + const auto& pPrevPage = m_pages.GetTail(); + + for (const auto& region : pPrevPage->regions) { + m_pCurrentPage->regions.emplace_back(DEBUG_NEW DVB_REGION(*region)); + } + + for (const auto& object : pPrevPage->objects) { + m_pCurrentPage->objects.emplace_back(DEBUG_NEW CompositionObject(*object)); + } + + for (const auto& CLUT : pPrevPage->CLUTs) { + m_pCurrentPage->CLUTs.emplace_back(DEBUG_NEW DVB_CLUT(*CLUT)); + } + + TRACE_DVB(_T("DVB - Page started [update] %s, TimeOut = %ds\n"), + ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->pageTimeOut); + } else { + TRACE_DVB(_T("DVB - Page update ignored %s\n"), ReftimeToString(rtStart)); + } + } + break; + case REGION: + ParseRegion(gb, wSegLength); + TRACE_DVB(_T("DVB - Region\n")); + break; + case CLUT: + ParseClut(gb, wSegLength); + TRACE_DVB(_T("DVB - Clut\n")); + break; + case OBJECT: + ParseObject(gb, wSegLength); + TRACE_DVB(_T("DVB - Object\n")); + break; + case DISPLAY: + ParseDisplay(gb, wSegLength); + TRACE_DVB(_T("DVB - Display\n")); + break; + case END_OF_DISPLAY: + if (m_pCurrentPage == nullptr) { + TRACE_DVB(_T("DVB - Ignored End display %s: no current page\n"), ReftimeToString(rtStart)); + } else if (m_pCurrentPage->rtStart < rtStart) { + TRACE_DVB(_T("DVB - End display\n")); + EnqueuePage(rtStart); + } else { + TRACE_DVB(_T("DVB - Ignored End display %s: no information on page duration\n"), ReftimeToString(rtStart)); + } + break; + default: + TRACE_DVB(_T("DVB - Ignored segment with unknown type %d\n"), nCurSegment); + break; + } + if (FAILED(hr)) { + gb.SkipBytes(6 + wSegLength - (gb.GetPos() - nLastPos)); + TRACE_DVB(_T("Parsing failed with code %x, skipping to the end of the segment\n"), hr); + } + } + nLastPos = gb.GetPos(); + } + m_nBufferReadPos += nLastPos; + } + + return hr; +} + +void CDVBSub::EndOfStream() +{ + CAutoLock cAutoLock(&m_csCritSec); + + // Enqueue the last page if necessary. + if (m_pCurrentPage) { + TRACE_DVB(_T("DVB - EndOfStream: Enqueue last page\n")); + EnqueuePage(INVALID_TIME); + } else { + TRACE_DVB(_T("DVB - EndOfStream ignored: no page to enqueue\n")); + } +} + +void CDVBSub::Reset() +{ + CAutoLock cAutoLock(&m_csCritSec); + + m_nBufferReadPos = 0; + m_nBufferWritePos = 0; + m_pCurrentPage.Free(); + m_pages.RemoveAll(); +} + +HRESULT CDVBSub::AddToBuffer(BYTE* pData, size_t nSize) +{ + bool bFirstChunk = (*((LONG*)pData) & 0x00FFFFFF) == 0x000f0020; // DVB sub start with 0x20 0x00 0x0F ... + + if (m_nBufferWritePos > 0 || bFirstChunk) { + if (bFirstChunk) { + m_nBufferWritePos = 0; + m_nBufferReadPos = 0; + } + + if (m_nBufferWritePos + nSize > m_nBufferSize) { + if (m_nBufferWritePos + nSize > 20 * BUFFER_CHUNK_GROW) { + // Too big to be a DVB sub ! + TRACE_DVB(_T("DVB - Too much data received...\n")); + ASSERT(FALSE); + + Reset(); + return E_INVALIDARG; + } + + BYTE* pPrev = m_pBuffer; + m_nBufferSize = std::max(m_nBufferWritePos + nSize, m_nBufferSize + BUFFER_CHUNK_GROW); + m_pBuffer = DEBUG_NEW BYTE[m_nBufferSize]; + if (pPrev != nullptr) { + memcpy_s(m_pBuffer, m_nBufferSize, pPrev, m_nBufferWritePos); + SAFE_DELETE(pPrev); + } + } + memcpy_s(m_pBuffer + m_nBufferWritePos, m_nBufferSize, pData, nSize); + m_nBufferWritePos += nSize; + return S_OK; + } + return S_FALSE; +} + +POSITION CDVBSub::FindPage(REFERENCE_TIME rt) const +{ + POSITION pos = m_pages.GetHeadPosition(); + + while (pos) { + POSITION currentPos = pos; + const auto& pPage = m_pages.GetNext(pos); + + if (rt >= pPage->rtStart && rt < pPage->rtStop) { + return currentPos; + } + } + + return nullptr; +} + +CDVBSub::RegionList::const_iterator CDVBSub::FindRegion(const CAutoPtr& pPage, BYTE bRegionId) const +{ + ENSURE(pPage); + + return std::find_if(pPage->regions.cbegin(), pPage->regions.cend(), + [bRegionId](const std::unique_ptr& pRegion) { + return pRegion->id == bRegionId; + }); +} + +CDVBSub::ClutList::const_iterator CDVBSub::FindClut(const CAutoPtr& pPage, BYTE bClutId) const +{ + ENSURE(pPage); + + return std::find_if(pPage->CLUTs.cbegin(), pPage->CLUTs.cend(), + [bClutId](const std::unique_ptr& pCLUT) { + return pCLUT->id == bClutId; + }); +} + +CDVBSub::CompositionObjectList::const_iterator CDVBSub::FindObject(const CAutoPtr& pPage, short sObjectId) const +{ + ENSURE(pPage); + + return std::find_if(pPage->objects.cbegin(), pPage->objects.cend(), + [sObjectId](const std::unique_ptr& pObject) { + return pObject->m_object_id_ref == sObjectId; + }); +} + +HRESULT CDVBSub::ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage) +{ + size_t nExpectedSize = 2; + size_t nEnd = gb.GetPos() + wSegLength; + + pPage.Attach(DEBUG_NEW DVB_PAGE()); + + pPage->pageTimeOut = gb.ReadByte(); + pPage->pageVersionNumber = (BYTE)gb.BitRead(4); + pPage->pageState = (BYTE)gb.BitRead(2); + gb.BitRead(2); // Reserved + while (gb.GetPos() < nEnd) { + nExpectedSize += 6; + DVB_REGION_POS regionPos; + regionPos.id = gb.ReadByte(); + gb.ReadByte(); // Reserved + regionPos.horizAddr = gb.ReadShort(); + regionPos.vertAddr = gb.ReadShort(); + pPage->regionsPos.emplace_back(std::move(regionPos)); + } + + return (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; +} + +HRESULT CDVBSub::ParseDisplay(CGolombBuffer& gb, WORD wSegLength) +{ + int nExpectedSize = 5; + + m_displayInfo.version_number = (BYTE)gb.BitRead(4); + m_displayInfo.display_window_flag = (BYTE)gb.BitRead(1); + gb.BitRead(3); // reserved + m_displayInfo.width = gb.ReadShort() + 1; + m_displayInfo.height = gb.ReadShort() + 1; + if (m_displayInfo.display_window_flag) { + nExpectedSize += 8; + m_displayInfo.horizontal_position_minimun = gb.ReadShort(); + m_displayInfo.horizontal_position_maximum = gb.ReadShort(); + m_displayInfo.vertical_position_minimun = gb.ReadShort(); + m_displayInfo.vertical_position_maximum = gb.ReadShort(); + } + + return (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; +} + +HRESULT CDVBSub::ParseRegion(CGolombBuffer& gb, WORD wSegLength) +{ + HRESULT hr = E_POINTER; + + if (m_pCurrentPage) { + size_t nExpectedSize = 10; + size_t nEnd = gb.GetPos() + wSegLength; + + BYTE id = gb.ReadByte(); + auto itRegion = FindRegion(m_pCurrentPage, id); + if (itRegion == m_pCurrentPage->regions.cend()) { + m_pCurrentPage->regions.emplace_back(DEBUG_NEW DVB_REGION()); + itRegion = std::prev(m_pCurrentPage->regions.cend()); + } + const auto& pRegion = *itRegion; + + pRegion->id = id; + pRegion->version_number = (BYTE)gb.BitRead(4); + pRegion->fill_flag = (BYTE)gb.BitRead(1); + gb.BitRead(3); // Reserved + pRegion->width = gb.ReadShort(); + pRegion->height = gb.ReadShort(); + pRegion->level_of_compatibility = (BYTE)gb.BitRead(3); + pRegion->depth = (BYTE)gb.BitRead(3); + gb.BitRead(2); // Reserved + pRegion->CLUT_id = gb.ReadByte(); + pRegion->_8_bit_pixel_code = gb.ReadByte(); + pRegion->_4_bit_pixel_code = (BYTE)gb.BitRead(4); + pRegion->_2_bit_pixel_code = (BYTE)gb.BitRead(2); + gb.BitRead(2); // Reserved + + while (gb.GetPos() < nEnd) { + nExpectedSize += 6; + DVB_OBJECT object; + object.object_id = gb.ReadShort(); + object.object_type = (BYTE)gb.BitRead(2); + object.object_provider_flag = (BYTE)gb.BitRead(2); + object.object_horizontal_position = (short)gb.BitRead(12); + gb.BitRead(4); // Reserved + object.object_vertical_position = (short)gb.BitRead(12); + if (object.object_type == 0x01 || object.object_type == 0x02) { + nExpectedSize += 2; + object.foreground_pixel_code = gb.ReadByte(); + object.background_pixel_code = gb.ReadByte(); + } + pRegion->objects.emplace_back(std::move(object)); + } + + hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; + } + + return hr; +} + +HRESULT CDVBSub::ParseClut(CGolombBuffer& gb, WORD wSegLength) +{ + HRESULT hr = E_POINTER; + + if (m_pCurrentPage) { + size_t nExpectedSize = 2; + size_t nEnd = gb.GetPos() + wSegLength; + + BYTE id = gb.ReadByte(); + auto itClut = FindClut(m_pCurrentPage, id); + if (itClut == m_pCurrentPage->CLUTs.cend()) { + m_pCurrentPage->CLUTs.emplace_back(DEBUG_NEW DVB_CLUT()); + itClut = std::prev(m_pCurrentPage->CLUTs.cend()); + } + const auto& pClut = *itClut; + + pClut->id = id; + pClut->version_number = (BYTE)gb.BitRead(4); + gb.BitRead(4); // Reserved + + pClut->size = 0; + while (gb.GetPos() < nEnd) { + nExpectedSize += 2; + pClut->palette[pClut->size].entry_id = gb.ReadByte(); + + BYTE _2_bit = (BYTE)gb.BitRead(1); + BYTE _4_bit = (BYTE)gb.BitRead(1); + BYTE _8_bit = (BYTE)gb.BitRead(1); + UNREFERENCED_PARAMETER(_2_bit); + UNREFERENCED_PARAMETER(_4_bit); + UNREFERENCED_PARAMETER(_8_bit); + gb.BitRead(4); // Reserved + + if (gb.BitRead(1)) { + nExpectedSize += 4; + pClut->palette[pClut->size].Y = gb.ReadByte(); + pClut->palette[pClut->size].Cr = gb.ReadByte(); + pClut->palette[pClut->size].Cb = gb.ReadByte(); + pClut->palette[pClut->size].T = 0xff - gb.ReadByte(); + } else { + nExpectedSize += 2; + pClut->palette[pClut->size].Y = (BYTE)gb.BitRead(6) << 2; + pClut->palette[pClut->size].Cr = (BYTE)gb.BitRead(4) << 4; + pClut->palette[pClut->size].Cb = (BYTE)gb.BitRead(4) << 4; + pClut->palette[pClut->size].T = 0xff - ((BYTE)gb.BitRead(2) << 6); + } + if (!pClut->palette[pClut->size].Y) { + pClut->palette[pClut->size].Cr = 0; + pClut->palette[pClut->size].Cb = 0; + pClut->palette[pClut->size].T = 0; + } + + pClut->size++; + } + + hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; + } + + return hr; +} + +HRESULT CDVBSub::ParseObject(CGolombBuffer& gb, WORD wSegLength) +{ + HRESULT hr = E_POINTER; + + if (m_pCurrentPage) { + size_t nExpectedSize = 3; + // size_t nEnd = gb.GetPos() + wSegLength; + + short id = gb.ReadShort(); + auto itObject = FindObject(m_pCurrentPage, id); + if (itObject == m_pCurrentPage->objects.cend()) { + m_pCurrentPage->objects.emplace_back(DEBUG_NEW CompositionObject()); + itObject = std::prev(m_pCurrentPage->objects.cend()); + } + const auto& pObject = *itObject; + + pObject->m_object_id_ref = id; + pObject->m_version_number = (BYTE)gb.BitRead(4); + + BYTE object_coding_method = (BYTE)gb.BitRead(2); // object_coding_method + gb.BitRead(1); // non_modifying_colour_flag + gb.BitRead(1); // reserved + + if (object_coding_method == 0x00) { + pObject->SetRLEData(gb.GetBufferPos(), wSegLength - nExpectedSize, wSegLength - nExpectedSize); + gb.SkipBytes(wSegLength - 3); + + hr = (wSegLength >= nExpectedSize) ? S_OK : E_UNEXPECTED; + } else { + TRACE_DVB(_T("DVB - Text subtitles are currently not supported\n")); + m_pCurrentPage->objects.pop_back(); + hr = E_NOTIMPL; + } + } + + return hr; +} + +HRESULT CDVBSub::EnqueuePage(REFERENCE_TIME rtStop) +{ + ASSERT(m_pCurrentPage != nullptr); + if (m_pCurrentPage->rtStart < rtStop && m_pCurrentPage->rtStop > rtStop) { + m_pCurrentPage->rtStop = rtStop; + } + TRACE_DVB(_T("DVB - Enqueue page %s (%s - %s)\n"), ReftimeToString(rtStop), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); + m_pages.AddTail(m_pCurrentPage); + + return S_OK; +} + +HRESULT CDVBSub::UpdateTimeStamp(REFERENCE_TIME rtStop) +{ + HRESULT hr = S_FALSE; + POSITION pos = m_pages.GetTailPosition(); + while (pos) { + const auto& pPage = m_pages.GetPrev(pos); + if (pPage->rtStop > rtStop) { + TRACE_DVB(_T("DVB - Updated end of display %s - %s --> %s - %s\n"), + ReftimeToString(pPage->rtStart), + ReftimeToString(pPage->rtStop), + ReftimeToString(pPage->rtStart), + ReftimeToString(rtStop)); + pPage->rtStop = rtStop; + hr = S_OK; + } else { + break; + } + } + + return hr; +} + +void CDVBSub::RemoveOldPages(REFERENCE_TIME rt) +{ + // Cleanup the old pages. We keep a 2 min buffer to play nice with the queue. + while (!m_pages.IsEmpty() && m_pages.GetHead()->rtStop + 120 * 10000000i64 < rt) { + const auto& pPage = m_pages.GetHead(); + if (!pPage->rendered) { + TRACE_DVB(_T("DVB - remove unrendered object, %s - %s\n"), + ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); + } + m_pages.RemoveHeadNoReturn(); + } +} + +STDMETHODIMP CDVBSub::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) +{ + relativeTo = RelativeTo::BEST_FIT; + return S_OK; +} diff --git a/src/Subtitles/DVBSub.h b/src/Subtitles/DVBSub.h index 80f7465805c..9ebffeaac07 100644 --- a/src/Subtitles/DVBSub.h +++ b/src/Subtitles/DVBSub.h @@ -1,175 +1,175 @@ -/* - * (C) 2009-2015 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 . - * - */ - -#pragma once - -#include "RLECodedSubtitle.h" -#include "CompositionObject.h" -#include -#include - -class CGolombBuffer; - -class CDVBSub : public CRLECodedSubtitle -{ -public: - CDVBSub(CCritSec* pLock, const CString& name, LCID lcid); - ~CDVBSub(); - - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); - - virtual HRESULT ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen); - virtual void EndOfStream(); - virtual void Reset(); - -private: - // EN 300-743, table 2 - enum DVB_SEGMENT_TYPE { - NO_SEGMENT = 0xFFFF, - PAGE = 0x10, - REGION = 0x11, - CLUT = 0x12, - OBJECT = 0x13, - DISPLAY = 0x14, - END_OF_DISPLAY = 0x80 - }; - - // EN 300-743, table 6 - enum DVB_OBJECT_TYPE { - OT_BASIC_BITMAP = 0x00, - OT_BASIC_CHAR = 0x01, - OT_COMPOSITE_STRING = 0x02 - }; - - enum DVB_PAGE_STATE { - DPS_NORMAL = 0x00, - DPS_ACQUISITION = 0x01, - DPS_MODE_CHANGE = 0x02, - DPS_RESERVED = 0x03 - }; - - struct DVB_CLUT { - BYTE id = 0; - BYTE version_number = 0; - WORD size = 0; - - std::array palette; - - DVB_CLUT() - : palette() { - } - }; - - struct DVB_DISPLAY { - // Default value (section 5.1.3) - BYTE version_number = 0; - BYTE display_window_flag = 0; - short width = 720; - short height = 576; - short horizontal_position_minimun = 0; - short horizontal_position_maximum = 0; - short vertical_position_minimun = 0; - short vertical_position_maximum = 0; - }; - - struct DVB_OBJECT { - short object_id = 0; - BYTE object_type = 0; - BYTE object_provider_flag = 0; - short object_horizontal_position = 0; - short object_vertical_position = 0; - BYTE foreground_pixel_code = 0; - BYTE background_pixel_code = 0; - }; - - struct DVB_REGION_POS { - BYTE id = 0; - WORD horizAddr = 0; - WORD vertAddr = 0; - }; - - struct DVB_REGION { - BYTE id = 0; - BYTE version_number = 0; - BYTE fill_flag = 0; - WORD width = 0; - WORD height = 0; - BYTE level_of_compatibility = 0; - BYTE depth = 0; - BYTE CLUT_id = 0; - BYTE _8_bit_pixel_code = 0; - BYTE _4_bit_pixel_code = 0; - BYTE _2_bit_pixel_code = 0; - std::list objects; - }; - - using RegionList = std::list>; - using CompositionObjectList = std::list>; - using ClutList = std::list>; - - class DVB_PAGE - { - public: - REFERENCE_TIME rtStart = 0; - REFERENCE_TIME rtStop = 0; - BYTE pageTimeOut = 0; - BYTE pageVersionNumber = 0; - BYTE pageState = 0; - std::list regionsPos; - RegionList regions; - CompositionObjectList objects; - ClutList CLUTs; - bool rendered = false; - }; - - size_t m_nBufferSize; - size_t m_nBufferReadPos; - size_t m_nBufferWritePos; - BYTE* m_pBuffer; - CAutoPtrList m_pages; - CAutoPtr m_pCurrentPage; - DVB_DISPLAY m_displayInfo; - - HRESULT AddToBuffer(BYTE* pData, size_t nSize); - - POSITION FindPage(REFERENCE_TIME rt) const; - RegionList::const_iterator FindRegion(const CAutoPtr& pPage, BYTE bRegionId) const; - ClutList::const_iterator FindClut(const CAutoPtr& pPage, BYTE bClutId) const; - CompositionObjectList::const_iterator FindObject(const CAutoPtr& pPage, short sObjectId) const; - - HRESULT ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage); - HRESULT ParseDisplay(CGolombBuffer& gb, WORD wSegLength); - HRESULT ParseRegion(CGolombBuffer& gb, WORD wSegLength); - HRESULT ParseClut(CGolombBuffer& gb, WORD wSegLength); - HRESULT ParseObject(CGolombBuffer& gb, WORD wSegLength); - - HRESULT EnqueuePage(REFERENCE_TIME rtStop); - HRESULT UpdateTimeStamp(REFERENCE_TIME rtStop); - - void RemoveOldPages(REFERENCE_TIME rt); -}; +/* + * (C) 2009-2015 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 . + * + */ + +#pragma once + +#include "RLECodedSubtitle.h" +#include "CompositionObject.h" +#include +#include + +class CGolombBuffer; + +class CDVBSub : public CRLECodedSubtitle +{ +public: + CDVBSub(CCritSec* pLock, const CString& name, LCID lcid); + ~CDVBSub(); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); + + virtual HRESULT ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen); + virtual void EndOfStream(); + virtual void Reset(); + +private: + // EN 300-743, table 2 + enum DVB_SEGMENT_TYPE { + NO_SEGMENT = 0xFFFF, + PAGE = 0x10, + REGION = 0x11, + CLUT = 0x12, + OBJECT = 0x13, + DISPLAY = 0x14, + END_OF_DISPLAY = 0x80 + }; + + // EN 300-743, table 6 + enum DVB_OBJECT_TYPE { + OT_BASIC_BITMAP = 0x00, + OT_BASIC_CHAR = 0x01, + OT_COMPOSITE_STRING = 0x02 + }; + + enum DVB_PAGE_STATE { + DPS_NORMAL = 0x00, + DPS_ACQUISITION = 0x01, + DPS_MODE_CHANGE = 0x02, + DPS_RESERVED = 0x03 + }; + + struct DVB_CLUT { + BYTE id = 0; + BYTE version_number = 0; + WORD size = 0; + + std::array palette; + + DVB_CLUT() + : palette() { + } + }; + + struct DVB_DISPLAY { + // Default value (section 5.1.3) + BYTE version_number = 0; + BYTE display_window_flag = 0; + short width = 720; + short height = 576; + short horizontal_position_minimun = 0; + short horizontal_position_maximum = 0; + short vertical_position_minimun = 0; + short vertical_position_maximum = 0; + }; + + struct DVB_OBJECT { + short object_id = 0; + BYTE object_type = 0; + BYTE object_provider_flag = 0; + short object_horizontal_position = 0; + short object_vertical_position = 0; + BYTE foreground_pixel_code = 0; + BYTE background_pixel_code = 0; + }; + + struct DVB_REGION_POS { + BYTE id = 0; + WORD horizAddr = 0; + WORD vertAddr = 0; + }; + + struct DVB_REGION { + BYTE id = 0; + BYTE version_number = 0; + BYTE fill_flag = 0; + WORD width = 0; + WORD height = 0; + BYTE level_of_compatibility = 0; + BYTE depth = 0; + BYTE CLUT_id = 0; + BYTE _8_bit_pixel_code = 0; + BYTE _4_bit_pixel_code = 0; + BYTE _2_bit_pixel_code = 0; + std::list objects; + }; + + using RegionList = std::list>; + using CompositionObjectList = std::list>; + using ClutList = std::list>; + + class DVB_PAGE + { + public: + REFERENCE_TIME rtStart = 0; + REFERENCE_TIME rtStop = 0; + BYTE pageTimeOut = 0; + BYTE pageVersionNumber = 0; + BYTE pageState = 0; + std::list regionsPos; + RegionList regions; + CompositionObjectList objects; + ClutList CLUTs; + bool rendered = false; + }; + + size_t m_nBufferSize; + size_t m_nBufferReadPos; + size_t m_nBufferWritePos; + BYTE* m_pBuffer; + CAutoPtrList m_pages; + CAutoPtr m_pCurrentPage; + DVB_DISPLAY m_displayInfo; + + HRESULT AddToBuffer(BYTE* pData, size_t nSize); + + POSITION FindPage(REFERENCE_TIME rt) const; + RegionList::const_iterator FindRegion(const CAutoPtr& pPage, BYTE bRegionId) const; + ClutList::const_iterator FindClut(const CAutoPtr& pPage, BYTE bClutId) const; + CompositionObjectList::const_iterator FindObject(const CAutoPtr& pPage, short sObjectId) const; + + HRESULT ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage); + HRESULT ParseDisplay(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseRegion(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseClut(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseObject(CGolombBuffer& gb, WORD wSegLength); + + HRESULT EnqueuePage(REFERENCE_TIME rtStop); + HRESULT UpdateTimeStamp(REFERENCE_TIME rtStop); + + void RemoveOldPages(REFERENCE_TIME rt); +}; diff --git a/src/Subtitles/PGSSub.cpp b/src/Subtitles/PGSSub.cpp index 9399e9dc440..62554beac81 100644 --- a/src/Subtitles/PGSSub.cpp +++ b/src/Subtitles/PGSSub.cpp @@ -1,617 +1,617 @@ -/* - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "PGSSub.h" -#include "../DSUtil/GolombBuffer.h" -#include -#include -#include "SubtitleHelpers.h" - -#if (0) // Set to 1 to activate PGS subtitles traces -#define TRACE_PGSSUB TRACE -#else -#define TRACE_PGSSUB __noop -#endif - - -CPGSSub::CPGSSub(CCritSec* pLock, const CString& name, LCID lcid) - : CRLECodedSubtitle(pLock, name, lcid) - , m_nCurSegment(NO_SEGMENT) - , m_pSegBuffer(nullptr) - , m_nTotalSegBuffer(0) - , m_nSegBufferPos(0) - , m_nSegSize(0) -{ - if (m_name.IsEmpty() || m_name == _T("Unknown")) { - m_name = _T("PGS Embedded Subtitle"); - } -} - -CPGSSub::~CPGSSub() -{ - Reset(); - - delete [] m_pSegBuffer; -} - -// ISubPicProvider - -STDMETHODIMP_(POSITION) CPGSSub::GetStartPosition(REFERENCE_TIME rt, double fps) -{ - CAutoLock cAutoLock(&m_csCritSec); - - POSITION pos = m_pPresentationSegments.GetHeadPosition(); - while (pos) { - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - if (pPresentationSegment->rtStop <= rt) { - m_pPresentationSegments.GetNext(pos); - } else { - break; - } - } - - return pos; -} - -STDMETHODIMP_(POSITION) CPGSSub::GetNext(POSITION pos) -{ - CAutoLock cAutoLock(&m_csCritSec); - m_pPresentationSegments.GetNext(pos); - return pos; -} - -STDMETHODIMP_(REFERENCE_TIME) CPGSSub::GetStart(POSITION pos, double fps) -{ - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - return pPresentationSegment ? pPresentationSegment->rtStart : INVALID_TIME; -} - -STDMETHODIMP_(REFERENCE_TIME) CPGSSub::GetStop(POSITION pos, double fps) -{ - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - return pPresentationSegment ? pPresentationSegment->rtStop : INVALID_TIME; -} - -STDMETHODIMP_(bool) CPGSSub::IsAnimated(POSITION pos) -{ - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - // If the end time isn't known yet, we consider the subtitle as animated to be sure it will properly updated - return (pPresentationSegment && pPresentationSegment->rtStop == UNKNOWN_TIME); -} - -STDMETHODIMP CPGSSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - return Render(spd, rt, bbox, true); -} - -STDMETHODIMP CPGSSub::GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) -{ - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - if (pPresentationSegment) { - MaxTextureSize.cx = VideoSize.cx = pPresentationSegment->video_descriptor.nVideoWidth; - MaxTextureSize.cy = VideoSize.cy = pPresentationSegment->video_descriptor.nVideoHeight; - - // The subs will be directly rendered into the proper position! - VideoTopLeft.x = 0; //pObject->m_horizontal_position; - VideoTopLeft.y = 0; //pObject->m_vertical_position; - - return S_OK; - } - - ASSERT(FALSE); - return E_INVALIDARG; -} - -HRESULT CPGSSub::ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen) -{ - CheckPointer(pData, E_POINTER); - - CAutoLock cAutoLock(&m_csCritSec); - - CGolombBuffer sampleBuffer(pData, nLen); - - while (!sampleBuffer.IsEOF()) { - if (m_nCurSegment == NO_SEGMENT) { - HDMV_SEGMENT_TYPE nSegType = (HDMV_SEGMENT_TYPE)sampleBuffer.ReadByte(); - unsigned short nUnitSize = sampleBuffer.ReadShort(); - nLen -= 3; - - switch (nSegType) { - case PALETTE: - case OBJECT: - case PRESENTATION_SEG: - case END_OF_DISPLAY: - m_nCurSegment = nSegType; - AllocSegment(nUnitSize); - break; - - case WINDOW_DEF: - case INTERACTIVE_SEG: - case HDMV_SUB1: - case HDMV_SUB2: - // Ignored stuff... - sampleBuffer.SkipBytes(nUnitSize); - break; - default: - return VFW_E_SAMPLE_REJECTED; - } - } - - if (m_nCurSegment != NO_SEGMENT) { - if (m_nSegBufferPos < m_nSegSize) { - size_t nSize = std::min(m_nSegSize - m_nSegBufferPos, nLen); - sampleBuffer.ReadBuffer(m_pSegBuffer + m_nSegBufferPos, nSize); - m_nSegBufferPos += nSize; - } - - if (m_nSegBufferPos >= m_nSegSize) { - CGolombBuffer SegmentBuffer(m_pSegBuffer, m_nSegSize); - - switch (m_nCurSegment) { - case PALETTE: - TRACE_PGSSUB(_T("CPGSSub:PALETTE %s\n"), ReftimeToString(rtStart)); - ParsePalette(&SegmentBuffer, m_nSegSize); - break; - case OBJECT: - TRACE_PGSSUB(_T("CPGSSub:OBJECT %s\n"), ReftimeToString(rtStart)); - ParseObject(&SegmentBuffer, m_nSegSize); - break; - case PRESENTATION_SEG: - TRACE_PGSSUB(_T("CPGSSub:PRESENTATION_SEG %s (size=%d)\n"), ReftimeToString(rtStart), m_nSegSize); - - if (rtStart == INVALID_TIME) { - break; - } - - // Update the timestamp for the previous segment - UpdateTimeStamp(rtStart); - - // Parse the new presentation segment - ParsePresentationSegment(rtStart, &SegmentBuffer); - - break; - case WINDOW_DEF: - //TRACE_PGSSUB(_T("CPGSSub:WINDOW_DEF %s\n"), ReftimeToString(rtStart)); - break; - case END_OF_DISPLAY: - TRACE_PGSSUB(_T("CPGSSub:END_OF_DISPLAY %s\n"), ReftimeToString(rtStart)); - // Enqueue the current presentation segment if any - EnqueuePresentationSegment(); - break; - default: - TRACE_PGSSUB(_T("CPGSSub:UNKNOWN Seg %d %s\n"), m_nCurSegment, ReftimeToString(rtStart)); - } - - m_nCurSegment = NO_SEGMENT; - } - } - } - - return S_OK; -} - -void CPGSSub::Reset() -{ - CAutoLock cAutoLock(&m_csCritSec); - - m_nSegBufferPos = m_nSegSize = 0; - m_nCurSegment = NO_SEGMENT; - m_pCurrentPresentationSegment.Free(); - m_pPresentationSegments.RemoveAll(); - for (auto& compositionObject : m_compositionObjects) { - compositionObject.Reset(); - } -} - -void CPGSSub::AllocSegment(size_t nSize) -{ - if (nSize > m_nTotalSegBuffer) { - delete[] m_pSegBuffer; - m_pSegBuffer = DEBUG_NEW BYTE[nSize]; - m_nTotalSegBuffer = nSize; - } - m_nSegBufferPos = 0; - m_nSegSize = nSize; -} - -HRESULT CPGSSub::GetPresentationSegmentTextureSize(REFERENCE_TIME rt, CSize& size) { - POSITION posPresentationSegment = FindPresentationSegment(rt); - - if (posPresentationSegment) { - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(posPresentationSegment); - if (pPresentationSegment->video_descriptor.nVideoWidth > 0) { - size.cx = pPresentationSegment->video_descriptor.nVideoWidth; - size.cy = pPresentationSegment->video_descriptor.nVideoHeight; - return S_OK; - } - } - return E_FAIL; -} - -HRESULT CPGSSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox, bool bRemoveOldSegments) -{ - CAutoLock cAutoLock(&m_csCritSec); - - bool bRendered = false; - - if (bRemoveOldSegments) { - RemoveOldSegments(rt); - } - - POSITION posPresentationSegment = FindPresentationSegment(rt); - - if (posPresentationSegment) { - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(posPresentationSegment); - - if (m_eSourceMatrix == ColorConvTable::AUTO) { - m_eSourceMatrix = (pPresentationSegment->video_descriptor.nVideoWidth > 720) ? ColorConvTable::BT709 : ColorConvTable::BT601; - } - - TRACE_PGSSUB(_T("CPGSSub:Render Presentation segment %d --> %s - %s\n"), pPresentationSegment->composition_descriptor.nNumber, - ReftimeToString(pPresentationSegment->rtStart), - pPresentationSegment->rtStop == UNKNOWN_TIME ? _T("?") : ReftimeToString(pPresentationSegment->rtStop).GetString()); - - bbox.left = bbox.top = LONG_MAX; - bbox.right = bbox.bottom = 0; - - for (const auto& pObject : pPresentationSegment->objects) { - if (pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0 - && spd.w >= (pObject->m_horizontal_position + pObject->m_width) && spd.h >= (pObject->m_vertical_position + pObject->m_height)) { - pObject->SetPalette(pPresentationSegment->CLUT.size, pPresentationSegment->CLUT.palette.data(), m_eSourceMatrix); - bbox.left = std::min(pObject->m_horizontal_position, bbox.left); - bbox.top = std::min(pObject->m_vertical_position, bbox.top); - bbox.right = std::max(pObject->m_horizontal_position + pObject->m_width, bbox.right); - bbox.bottom = std::max(pObject->m_vertical_position + pObject->m_height, bbox.bottom); - - TRACE_PGSSUB(_T(" --> Object %d (Pos=%dx%d, Res=%dx%d, SPDRes=%dx%d)\n"), - pObject->m_object_id_ref, pObject->m_horizontal_position, pObject->m_vertical_position, pObject->m_width, pObject->m_height, spd.w, spd.h); - pObject->RenderHdmv(spd); - - bRendered = true; - } else { - TRACE_PGSSUB(_T(" --> Invalid object %d\n"), pObject->m_object_id_ref); - } - } - } - - if (!bRendered) { - bbox = { 0, 0, 0, 0 }; - } - - return S_OK; -} - -int CPGSSub::ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer) -{ - if (pGBuffer->RemainingSize() < 11) { - ASSERT(FALSE); - return 0; - } - - m_pCurrentPresentationSegment.Free(); - m_pCurrentPresentationSegment.Attach(DEBUG_NEW HDMV_PRESENTATION_SEGMENT()); - - m_pCurrentPresentationSegment->rtStart = rt; - m_pCurrentPresentationSegment->rtStop = UNKNOWN_TIME; // Unknown for now - - ParseVideoDescriptor(pGBuffer, &m_pCurrentPresentationSegment->video_descriptor); - ParseCompositionDescriptor(pGBuffer, &m_pCurrentPresentationSegment->composition_descriptor); - m_pCurrentPresentationSegment->palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); - m_pCurrentPresentationSegment->CLUT.id = pGBuffer->ReadByte(); - m_pCurrentPresentationSegment->objectCount = pGBuffer->ReadByte(); - - TRACE_PGSSUB(_T("CPGSSub::ParsePresentationSegment Size = %d, state = %#x, nObjectNumber = %d\n"), pGBuffer->GetSize(), - m_pCurrentPresentationSegment->composition_descriptor.bState, m_pCurrentPresentationSegment->objectCount); - - if (pGBuffer->RemainingSize() < (m_pCurrentPresentationSegment->objectCount * 8)) { - ASSERT(FALSE); - return 0; - } - - for (int i = 0; i < m_pCurrentPresentationSegment->objectCount; i++) { - std::unique_ptr pCompositionObject(DEBUG_NEW CompositionObject()); - if (ParseCompositionObject(pGBuffer, pCompositionObject)) { - m_pCurrentPresentationSegment->objects.emplace_back(std::move(pCompositionObject)); - } - } - - return m_pCurrentPresentationSegment->objectCount; -} - -void CPGSSub::EnqueuePresentationSegment() -{ - if (m_pCurrentPresentationSegment) { - if (m_pCurrentPresentationSegment->objectCount > 0) { - m_pCurrentPresentationSegment->CLUT = m_CLUTs[m_pCurrentPresentationSegment->CLUT.id]; - - // Get the objects' data - for (auto& pObject : m_pCurrentPresentationSegment->objects) { - const CompositionObject& pObjectData = m_compositionObjects[pObject->m_object_id_ref]; - - pObject->m_width = pObjectData.m_width; - pObject->m_height = pObjectData.m_height; - - if (pObjectData.GetRLEData()) { - pObject->SetRLEData(pObjectData.GetRLEData(), pObjectData.GetRLEPos(), pObjectData.GetRLEDataSize()); - } - } - - TRACE_PGSSUB(_T("CPGSSub: Enqueue Presentation Segment %d - %s => ?\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber, - ReftimeToString(m_pCurrentPresentationSegment->rtStart)); - m_pPresentationSegments.AddTail(m_pCurrentPresentationSegment); - } else { - TRACE_PGSSUB(_T("CPGSSub: Delete empty Presentation Segment %d\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber); - m_pCurrentPresentationSegment.Free(); - } - } -} - -void CPGSSub::UpdateTimeStamp(REFERENCE_TIME rtStop) -{ - if (!m_pPresentationSegments.IsEmpty()) { - const auto& pPresentationSegment = m_pPresentationSegments.GetTail(); - - // Since we drop empty segments we might be trying to update a segment that isn't - // in the queue so we update the timestamp only if it was previously unknown. - if (pPresentationSegment->rtStop == UNKNOWN_TIME) { - pPresentationSegment->rtStop = rtStop; - - TRACE_PGSSUB(_T("CPGSSub: Update Presentation Segment TimeStamp %d - %s => %s\n"), pPresentationSegment->composition_descriptor.nNumber, - ReftimeToString(pPresentationSegment->rtStart), - ReftimeToString(pPresentationSegment->rtStop)); - } - } -} - -void CPGSSub::ParsePalette(CGolombBuffer* pGBuffer, size_t nSize) // #497 -{ - if ((nSize - 2) % sizeof(HDMV_PALETTE) != 0) { - ASSERT(FALSE); - return; - } - - BYTE palette_id = pGBuffer->ReadByte(); - HDMV_CLUT& CLUT = m_CLUTs[palette_id]; - - CLUT.id = palette_id; - CLUT.version_number = pGBuffer->ReadByte(); - - CLUT.size = WORD((nSize - 2) / sizeof(HDMV_PALETTE)); - - for (WORD i = 0; i < CLUT.size; i++) { - CLUT.palette[i].entry_id = pGBuffer->ReadByte(); - - CLUT.palette[i].Y = pGBuffer->ReadByte(); - CLUT.palette[i].Cr = pGBuffer->ReadByte(); - CLUT.palette[i].Cb = pGBuffer->ReadByte(); - CLUT.palette[i].T = pGBuffer->ReadByte(); - } -} - -void CPGSSub::ParseObject(CGolombBuffer* pGBuffer, size_t nUnitSize) // #498 -{ - if (nUnitSize <= 4) { - return; - } - short object_id = pGBuffer->ReadShort(); - if (object_id < 0 || size_t(object_id) >= m_compositionObjects.size()) { - ASSERT(FALSE); // This is not supposed to happen - return; - } - - CompositionObject& pObject = m_compositionObjects[object_id]; - - pObject.m_version_number = pGBuffer->ReadByte(); - BYTE m_sequence_desc = pGBuffer->ReadByte(); - - if (m_sequence_desc & 0x80) { - if (nUnitSize <= 8) { - return; - } - - int object_data_length = (int)pGBuffer->BitRead(24); - - pObject.m_width = pGBuffer->ReadShort(); - pObject.m_height = pGBuffer->ReadShort(); - - pObject.SetRLEData(pGBuffer->GetBufferPos(), nUnitSize - 11, object_data_length - 4); - - TRACE_PGSSUB(_T("CPGSSub:ParseObject %d (size=%ld, %dx%d)\n"), object_id, object_data_length, pObject.m_width, pObject.m_height); - } else { - pObject.AppendRLEData(pGBuffer->GetBufferPos(), nUnitSize - 4); - } -} - -bool CPGSSub::ParseCompositionObject(CGolombBuffer* pGBuffer, const std::unique_ptr& pCompositionObject) -{ - short object_id_ref = pGBuffer->ReadShort(); - if (object_id_ref < 0 || size_t(object_id_ref) >= m_compositionObjects.size()) { - ASSERT(FALSE); // This is not supposed to happen - return false; - } - - pCompositionObject->m_object_id_ref = object_id_ref; - pCompositionObject->m_window_id_ref = pGBuffer->ReadByte(); - BYTE bTemp = pGBuffer->ReadByte(); - pCompositionObject->m_object_cropped_flag = !!(bTemp & 0x80); - pCompositionObject->m_forced_on_flag = !!(bTemp & 0x40); - pCompositionObject->m_horizontal_position = pGBuffer->ReadShort(); - pCompositionObject->m_vertical_position = pGBuffer->ReadShort(); - - if (pCompositionObject->m_object_cropped_flag) { - if (pGBuffer->RemainingSize() < 8) { - ASSERT(FALSE); - return false; - } - pCompositionObject->m_cropping_horizontal_position = pGBuffer->ReadShort(); - pCompositionObject->m_cropping_vertical_position = pGBuffer->ReadShort(); - pCompositionObject->m_cropping_width = pGBuffer->ReadShort(); - pCompositionObject->m_cropping_height = pGBuffer->ReadShort(); - } - - return true; -} - -void CPGSSub::ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor) -{ - pVideoDescriptor->nVideoWidth = pGBuffer->ReadShort(); - pVideoDescriptor->nVideoHeight = pGBuffer->ReadShort(); - pVideoDescriptor->bFrameRate = pGBuffer->ReadByte(); -} - -void CPGSSub::ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor) -{ - pCompositionDescriptor->nNumber = pGBuffer->ReadShort(); - pCompositionDescriptor->bState = pGBuffer->ReadByte() >> 6; -} - -POSITION CPGSSub::FindPresentationSegment(REFERENCE_TIME rt) const -{ - POSITION pos = m_pPresentationSegments.GetHeadPosition(); - - while (pos) { - POSITION currentPos = pos; - const auto& pPresentationSegment = m_pPresentationSegments.GetNext(pos); - - if (pPresentationSegment->rtStart <= rt && pPresentationSegment->rtStop > rt) { - return currentPos; - } - } - - return nullptr; -} - -void CPGSSub::RemoveOldSegments(REFERENCE_TIME rt) -{ - // Cleanup the old presentation segments. We keep a 2 min buffer to play nice with the queue. - while (!m_pPresentationSegments.IsEmpty() - && m_pPresentationSegments.GetHead()->rtStop != UNKNOWN_TIME - && m_pPresentationSegments.GetHead()->rtStop + 120 * 10000000i64 < rt) { - TRACE_PGSSUB(_T("CPGSSub::RemoveOldSegments Remove presentation segment %d %s => %s (rt=%s)\n"), - m_pPresentationSegments.GetHead()->composition_descriptor.nNumber, - ReftimeToString(m_pPresentationSegments.GetHead()->rtStart), - ReftimeToString(m_pPresentationSegments.GetHead()->rtStop), - ReftimeToString(rt)); - m_pPresentationSegments.RemoveHeadNoReturn(); - } -} - -STDMETHODIMP CPGSSub::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) -{ - relativeTo = RelativeTo::BEST_FIT; - return S_OK; -} - -CPGSSubFile::CPGSSubFile(CCritSec* pLock) - : CPGSSub(pLock, _T("PGS External Subtitle"), 0) - , m_bStopParsing(false) -{ -} - -CPGSSubFile::~CPGSSubFile() -{ - m_bStopParsing = true; - if (m_parsingThread.joinable()) { - m_parsingThread.join(); - } -} - -STDMETHODIMP CPGSSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - return __super::Render(spd, rt, bbox, false); -} - -bool CPGSSubFile::Open(CString fn, CString name /*= _T("")*/, CString videoName /*= _T("")*/) -{ - bool bOpened = false; - - CString tmp; - CString guessed = Subtitle::GuessSubtitleName(fn, videoName, m_lcid, tmp, m_eHearingImpaired); - if (name.IsEmpty()) { - m_name = guessed; - } else { - m_name = name; - } - - m_path = fn; - - try { - CFile f; - if (f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { - WORD wSyncCode = 0; - f.Read(&wSyncCode, sizeof(wSyncCode)); - wSyncCode = _byteswap_ushort(wSyncCode); - if (wSyncCode == PGS_SYNC_CODE) { - m_parsingThread = std::thread([this, fn] { ParseFile(fn); }); - bOpened = true; - } - } - } catch (CFileException*) { - } - - return bOpened; -} - -CString CPGSSubFile::GetPath() { - return m_path; -} - -void CPGSSubFile::ParseFile(CString fn) -{ - CFile f; - if (!f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { - return; - } - - // Header: Sync code | start time | stop time | segment type | segment size - std::array < BYTE, 2 + 2 * 4 + 1 + 2 > header; - const int nExtraSize = 1 + 2; // segment type + segment size - std::vector segBuff; - - while (!m_bStopParsing && f.Read(header.data(), (UINT)header.size()) == header.size()) { - // Parse the header - CGolombBuffer headerBuffer(header.data(), (int)header.size()); - - if (WORD(headerBuffer.ReadShort()) != PGS_SYNC_CODE) { - break; - } - - REFERENCE_TIME rtStart = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; - REFERENCE_TIME rtStop = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; - headerBuffer.ReadByte(); // segment type - WORD wLenSegment = (WORD)headerBuffer.ReadShort(); - - // Leave some room to add the segment type and size - int nLenData = nExtraSize + wLenSegment; - segBuff.resize(nLenData); - memcpy(segBuff.data(), &header[header.size() - nExtraSize], nExtraSize); - - // Read the segment - if (wLenSegment && f.Read(&segBuff[nExtraSize], wLenSegment) != wLenSegment) { - break; - } - - // Parse the data (even if the segment size is 0 because the header itself is important) - TRACE_PGSSUB(_T("--------- CPGSSubFile::ParseFile rtStart=%s, rtStop=%s, len=%d ---------\n"), - ReftimeToString(rtStart), ReftimeToString(rtStop), nLenData); - ParseSample(rtStart, rtStop, segBuff.data(), nLenData); - } -} +/* + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "PGSSub.h" +#include "../DSUtil/GolombBuffer.h" +#include +#include +#include "SubtitleHelpers.h" + +#if (0) // Set to 1 to activate PGS subtitles traces +#define TRACE_PGSSUB TRACE +#else +#define TRACE_PGSSUB __noop +#endif + + +CPGSSub::CPGSSub(CCritSec* pLock, const CString& name, LCID lcid) + : CRLECodedSubtitle(pLock, name, lcid) + , m_nCurSegment(NO_SEGMENT) + , m_pSegBuffer(nullptr) + , m_nTotalSegBuffer(0) + , m_nSegBufferPos(0) + , m_nSegSize(0) +{ + if (m_name.IsEmpty() || m_name == _T("Unknown")) { + m_name = _T("PGS Embedded Subtitle"); + } +} + +CPGSSub::~CPGSSub() +{ + Reset(); + + delete [] m_pSegBuffer; +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CPGSSub::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + CAutoLock cAutoLock(&m_csCritSec); + + POSITION pos = m_pPresentationSegments.GetHeadPosition(); + while (pos) { + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + if (pPresentationSegment->rtStop <= rt) { + m_pPresentationSegments.GetNext(pos); + } else { + break; + } + } + + return pos; +} + +STDMETHODIMP_(POSITION) CPGSSub::GetNext(POSITION pos) +{ + CAutoLock cAutoLock(&m_csCritSec); + m_pPresentationSegments.GetNext(pos); + return pos; +} + +STDMETHODIMP_(REFERENCE_TIME) CPGSSub::GetStart(POSITION pos, double fps) +{ + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + return pPresentationSegment ? pPresentationSegment->rtStart : INVALID_TIME; +} + +STDMETHODIMP_(REFERENCE_TIME) CPGSSub::GetStop(POSITION pos, double fps) +{ + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + return pPresentationSegment ? pPresentationSegment->rtStop : INVALID_TIME; +} + +STDMETHODIMP_(bool) CPGSSub::IsAnimated(POSITION pos) +{ + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + // If the end time isn't known yet, we consider the subtitle as animated to be sure it will properly updated + return (pPresentationSegment && pPresentationSegment->rtStop == UNKNOWN_TIME); +} + +STDMETHODIMP CPGSSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + return Render(spd, rt, bbox, true); +} + +STDMETHODIMP CPGSSub::GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) +{ + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + if (pPresentationSegment) { + MaxTextureSize.cx = VideoSize.cx = pPresentationSegment->video_descriptor.nVideoWidth; + MaxTextureSize.cy = VideoSize.cy = pPresentationSegment->video_descriptor.nVideoHeight; + + // The subs will be directly rendered into the proper position! + VideoTopLeft.x = 0; //pObject->m_horizontal_position; + VideoTopLeft.y = 0; //pObject->m_vertical_position; + + return S_OK; + } + + ASSERT(FALSE); + return E_INVALIDARG; +} + +HRESULT CPGSSub::ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen) +{ + CheckPointer(pData, E_POINTER); + + CAutoLock cAutoLock(&m_csCritSec); + + CGolombBuffer sampleBuffer(pData, nLen); + + while (!sampleBuffer.IsEOF()) { + if (m_nCurSegment == NO_SEGMENT) { + HDMV_SEGMENT_TYPE nSegType = (HDMV_SEGMENT_TYPE)sampleBuffer.ReadByte(); + unsigned short nUnitSize = sampleBuffer.ReadShort(); + nLen -= 3; + + switch (nSegType) { + case PALETTE: + case OBJECT: + case PRESENTATION_SEG: + case END_OF_DISPLAY: + m_nCurSegment = nSegType; + AllocSegment(nUnitSize); + break; + + case WINDOW_DEF: + case INTERACTIVE_SEG: + case HDMV_SUB1: + case HDMV_SUB2: + // Ignored stuff... + sampleBuffer.SkipBytes(nUnitSize); + break; + default: + return VFW_E_SAMPLE_REJECTED; + } + } + + if (m_nCurSegment != NO_SEGMENT) { + if (m_nSegBufferPos < m_nSegSize) { + size_t nSize = std::min(m_nSegSize - m_nSegBufferPos, nLen); + sampleBuffer.ReadBuffer(m_pSegBuffer + m_nSegBufferPos, nSize); + m_nSegBufferPos += nSize; + } + + if (m_nSegBufferPos >= m_nSegSize) { + CGolombBuffer SegmentBuffer(m_pSegBuffer, m_nSegSize); + + switch (m_nCurSegment) { + case PALETTE: + TRACE_PGSSUB(_T("CPGSSub:PALETTE %s\n"), ReftimeToString(rtStart)); + ParsePalette(&SegmentBuffer, m_nSegSize); + break; + case OBJECT: + TRACE_PGSSUB(_T("CPGSSub:OBJECT %s\n"), ReftimeToString(rtStart)); + ParseObject(&SegmentBuffer, m_nSegSize); + break; + case PRESENTATION_SEG: + TRACE_PGSSUB(_T("CPGSSub:PRESENTATION_SEG %s (size=%d)\n"), ReftimeToString(rtStart), m_nSegSize); + + if (rtStart == INVALID_TIME) { + break; + } + + // Update the timestamp for the previous segment + UpdateTimeStamp(rtStart); + + // Parse the new presentation segment + ParsePresentationSegment(rtStart, &SegmentBuffer); + + break; + case WINDOW_DEF: + //TRACE_PGSSUB(_T("CPGSSub:WINDOW_DEF %s\n"), ReftimeToString(rtStart)); + break; + case END_OF_DISPLAY: + TRACE_PGSSUB(_T("CPGSSub:END_OF_DISPLAY %s\n"), ReftimeToString(rtStart)); + // Enqueue the current presentation segment if any + EnqueuePresentationSegment(); + break; + default: + TRACE_PGSSUB(_T("CPGSSub:UNKNOWN Seg %d %s\n"), m_nCurSegment, ReftimeToString(rtStart)); + } + + m_nCurSegment = NO_SEGMENT; + } + } + } + + return S_OK; +} + +void CPGSSub::Reset() +{ + CAutoLock cAutoLock(&m_csCritSec); + + m_nSegBufferPos = m_nSegSize = 0; + m_nCurSegment = NO_SEGMENT; + m_pCurrentPresentationSegment.Free(); + m_pPresentationSegments.RemoveAll(); + for (auto& compositionObject : m_compositionObjects) { + compositionObject.Reset(); + } +} + +void CPGSSub::AllocSegment(size_t nSize) +{ + if (nSize > m_nTotalSegBuffer) { + delete[] m_pSegBuffer; + m_pSegBuffer = DEBUG_NEW BYTE[nSize]; + m_nTotalSegBuffer = nSize; + } + m_nSegBufferPos = 0; + m_nSegSize = nSize; +} + +HRESULT CPGSSub::GetPresentationSegmentTextureSize(REFERENCE_TIME rt, CSize& size) { + POSITION posPresentationSegment = FindPresentationSegment(rt); + + if (posPresentationSegment) { + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(posPresentationSegment); + if (pPresentationSegment->video_descriptor.nVideoWidth > 0) { + size.cx = pPresentationSegment->video_descriptor.nVideoWidth; + size.cy = pPresentationSegment->video_descriptor.nVideoHeight; + return S_OK; + } + } + return E_FAIL; +} + +HRESULT CPGSSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox, bool bRemoveOldSegments) +{ + CAutoLock cAutoLock(&m_csCritSec); + + bool bRendered = false; + + if (bRemoveOldSegments) { + RemoveOldSegments(rt); + } + + POSITION posPresentationSegment = FindPresentationSegment(rt); + + if (posPresentationSegment) { + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(posPresentationSegment); + + if (m_eSourceMatrix == ColorConvTable::AUTO) { + m_eSourceMatrix = (pPresentationSegment->video_descriptor.nVideoWidth > 720) ? ColorConvTable::BT709 : ColorConvTable::BT601; + } + + TRACE_PGSSUB(_T("CPGSSub:Render Presentation segment %d --> %s - %s\n"), pPresentationSegment->composition_descriptor.nNumber, + ReftimeToString(pPresentationSegment->rtStart), + pPresentationSegment->rtStop == UNKNOWN_TIME ? _T("?") : ReftimeToString(pPresentationSegment->rtStop).GetString()); + + bbox.left = bbox.top = LONG_MAX; + bbox.right = bbox.bottom = 0; + + for (const auto& pObject : pPresentationSegment->objects) { + if (pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0 + && spd.w >= (pObject->m_horizontal_position + pObject->m_width) && spd.h >= (pObject->m_vertical_position + pObject->m_height)) { + pObject->SetPalette(pPresentationSegment->CLUT.size, pPresentationSegment->CLUT.palette.data(), m_eSourceMatrix); + bbox.left = std::min(pObject->m_horizontal_position, bbox.left); + bbox.top = std::min(pObject->m_vertical_position, bbox.top); + bbox.right = std::max(pObject->m_horizontal_position + pObject->m_width, bbox.right); + bbox.bottom = std::max(pObject->m_vertical_position + pObject->m_height, bbox.bottom); + + TRACE_PGSSUB(_T(" --> Object %d (Pos=%dx%d, Res=%dx%d, SPDRes=%dx%d)\n"), + pObject->m_object_id_ref, pObject->m_horizontal_position, pObject->m_vertical_position, pObject->m_width, pObject->m_height, spd.w, spd.h); + pObject->RenderHdmv(spd); + + bRendered = true; + } else { + TRACE_PGSSUB(_T(" --> Invalid object %d\n"), pObject->m_object_id_ref); + } + } + } + + if (!bRendered) { + bbox = { 0, 0, 0, 0 }; + } + + return S_OK; +} + +int CPGSSub::ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer) +{ + if (pGBuffer->RemainingSize() < 11) { + ASSERT(FALSE); + return 0; + } + + m_pCurrentPresentationSegment.Free(); + m_pCurrentPresentationSegment.Attach(DEBUG_NEW HDMV_PRESENTATION_SEGMENT()); + + m_pCurrentPresentationSegment->rtStart = rt; + m_pCurrentPresentationSegment->rtStop = UNKNOWN_TIME; // Unknown for now + + ParseVideoDescriptor(pGBuffer, &m_pCurrentPresentationSegment->video_descriptor); + ParseCompositionDescriptor(pGBuffer, &m_pCurrentPresentationSegment->composition_descriptor); + m_pCurrentPresentationSegment->palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); + m_pCurrentPresentationSegment->CLUT.id = pGBuffer->ReadByte(); + m_pCurrentPresentationSegment->objectCount = pGBuffer->ReadByte(); + + TRACE_PGSSUB(_T("CPGSSub::ParsePresentationSegment Size = %d, state = %#x, nObjectNumber = %d\n"), pGBuffer->GetSize(), + m_pCurrentPresentationSegment->composition_descriptor.bState, m_pCurrentPresentationSegment->objectCount); + + if (pGBuffer->RemainingSize() < (m_pCurrentPresentationSegment->objectCount * 8)) { + ASSERT(FALSE); + return 0; + } + + for (int i = 0; i < m_pCurrentPresentationSegment->objectCount; i++) { + std::unique_ptr pCompositionObject(DEBUG_NEW CompositionObject()); + if (ParseCompositionObject(pGBuffer, pCompositionObject)) { + m_pCurrentPresentationSegment->objects.emplace_back(std::move(pCompositionObject)); + } + } + + return m_pCurrentPresentationSegment->objectCount; +} + +void CPGSSub::EnqueuePresentationSegment() +{ + if (m_pCurrentPresentationSegment) { + if (m_pCurrentPresentationSegment->objectCount > 0) { + m_pCurrentPresentationSegment->CLUT = m_CLUTs[m_pCurrentPresentationSegment->CLUT.id]; + + // Get the objects' data + for (auto& pObject : m_pCurrentPresentationSegment->objects) { + const CompositionObject& pObjectData = m_compositionObjects[pObject->m_object_id_ref]; + + pObject->m_width = pObjectData.m_width; + pObject->m_height = pObjectData.m_height; + + if (pObjectData.GetRLEData()) { + pObject->SetRLEData(pObjectData.GetRLEData(), pObjectData.GetRLEPos(), pObjectData.GetRLEDataSize()); + } + } + + TRACE_PGSSUB(_T("CPGSSub: Enqueue Presentation Segment %d - %s => ?\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber, + ReftimeToString(m_pCurrentPresentationSegment->rtStart)); + m_pPresentationSegments.AddTail(m_pCurrentPresentationSegment); + } else { + TRACE_PGSSUB(_T("CPGSSub: Delete empty Presentation Segment %d\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber); + m_pCurrentPresentationSegment.Free(); + } + } +} + +void CPGSSub::UpdateTimeStamp(REFERENCE_TIME rtStop) +{ + if (!m_pPresentationSegments.IsEmpty()) { + const auto& pPresentationSegment = m_pPresentationSegments.GetTail(); + + // Since we drop empty segments we might be trying to update a segment that isn't + // in the queue so we update the timestamp only if it was previously unknown. + if (pPresentationSegment->rtStop == UNKNOWN_TIME) { + pPresentationSegment->rtStop = rtStop; + + TRACE_PGSSUB(_T("CPGSSub: Update Presentation Segment TimeStamp %d - %s => %s\n"), pPresentationSegment->composition_descriptor.nNumber, + ReftimeToString(pPresentationSegment->rtStart), + ReftimeToString(pPresentationSegment->rtStop)); + } + } +} + +void CPGSSub::ParsePalette(CGolombBuffer* pGBuffer, size_t nSize) // #497 +{ + if ((nSize - 2) % sizeof(HDMV_PALETTE) != 0) { + ASSERT(FALSE); + return; + } + + BYTE palette_id = pGBuffer->ReadByte(); + HDMV_CLUT& CLUT = m_CLUTs[palette_id]; + + CLUT.id = palette_id; + CLUT.version_number = pGBuffer->ReadByte(); + + CLUT.size = WORD((nSize - 2) / sizeof(HDMV_PALETTE)); + + for (WORD i = 0; i < CLUT.size; i++) { + CLUT.palette[i].entry_id = pGBuffer->ReadByte(); + + CLUT.palette[i].Y = pGBuffer->ReadByte(); + CLUT.palette[i].Cr = pGBuffer->ReadByte(); + CLUT.palette[i].Cb = pGBuffer->ReadByte(); + CLUT.palette[i].T = pGBuffer->ReadByte(); + } +} + +void CPGSSub::ParseObject(CGolombBuffer* pGBuffer, size_t nUnitSize) // #498 +{ + if (nUnitSize <= 4) { + return; + } + short object_id = pGBuffer->ReadShort(); + if (object_id < 0 || size_t(object_id) >= m_compositionObjects.size()) { + ASSERT(FALSE); // This is not supposed to happen + return; + } + + CompositionObject& pObject = m_compositionObjects[object_id]; + + pObject.m_version_number = pGBuffer->ReadByte(); + BYTE m_sequence_desc = pGBuffer->ReadByte(); + + if (m_sequence_desc & 0x80) { + if (nUnitSize <= 8) { + return; + } + + int object_data_length = (int)pGBuffer->BitRead(24); + + pObject.m_width = pGBuffer->ReadShort(); + pObject.m_height = pGBuffer->ReadShort(); + + pObject.SetRLEData(pGBuffer->GetBufferPos(), nUnitSize - 11, object_data_length - 4); + + TRACE_PGSSUB(_T("CPGSSub:ParseObject %d (size=%ld, %dx%d)\n"), object_id, object_data_length, pObject.m_width, pObject.m_height); + } else { + pObject.AppendRLEData(pGBuffer->GetBufferPos(), nUnitSize - 4); + } +} + +bool CPGSSub::ParseCompositionObject(CGolombBuffer* pGBuffer, const std::unique_ptr& pCompositionObject) +{ + short object_id_ref = pGBuffer->ReadShort(); + if (object_id_ref < 0 || size_t(object_id_ref) >= m_compositionObjects.size()) { + ASSERT(FALSE); // This is not supposed to happen + return false; + } + + pCompositionObject->m_object_id_ref = object_id_ref; + pCompositionObject->m_window_id_ref = pGBuffer->ReadByte(); + BYTE bTemp = pGBuffer->ReadByte(); + pCompositionObject->m_object_cropped_flag = !!(bTemp & 0x80); + pCompositionObject->m_forced_on_flag = !!(bTemp & 0x40); + pCompositionObject->m_horizontal_position = pGBuffer->ReadShort(); + pCompositionObject->m_vertical_position = pGBuffer->ReadShort(); + + if (pCompositionObject->m_object_cropped_flag) { + if (pGBuffer->RemainingSize() < 8) { + ASSERT(FALSE); + return false; + } + pCompositionObject->m_cropping_horizontal_position = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_vertical_position = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_width = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_height = pGBuffer->ReadShort(); + } + + return true; +} + +void CPGSSub::ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor) +{ + pVideoDescriptor->nVideoWidth = pGBuffer->ReadShort(); + pVideoDescriptor->nVideoHeight = pGBuffer->ReadShort(); + pVideoDescriptor->bFrameRate = pGBuffer->ReadByte(); +} + +void CPGSSub::ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor) +{ + pCompositionDescriptor->nNumber = pGBuffer->ReadShort(); + pCompositionDescriptor->bState = pGBuffer->ReadByte() >> 6; +} + +POSITION CPGSSub::FindPresentationSegment(REFERENCE_TIME rt) const +{ + POSITION pos = m_pPresentationSegments.GetHeadPosition(); + + while (pos) { + POSITION currentPos = pos; + const auto& pPresentationSegment = m_pPresentationSegments.GetNext(pos); + + if (pPresentationSegment->rtStart <= rt && pPresentationSegment->rtStop > rt) { + return currentPos; + } + } + + return nullptr; +} + +void CPGSSub::RemoveOldSegments(REFERENCE_TIME rt) +{ + // Cleanup the old presentation segments. We keep a 2 min buffer to play nice with the queue. + while (!m_pPresentationSegments.IsEmpty() + && m_pPresentationSegments.GetHead()->rtStop != UNKNOWN_TIME + && m_pPresentationSegments.GetHead()->rtStop + 120 * 10000000i64 < rt) { + TRACE_PGSSUB(_T("CPGSSub::RemoveOldSegments Remove presentation segment %d %s => %s (rt=%s)\n"), + m_pPresentationSegments.GetHead()->composition_descriptor.nNumber, + ReftimeToString(m_pPresentationSegments.GetHead()->rtStart), + ReftimeToString(m_pPresentationSegments.GetHead()->rtStop), + ReftimeToString(rt)); + m_pPresentationSegments.RemoveHeadNoReturn(); + } +} + +STDMETHODIMP CPGSSub::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) +{ + relativeTo = RelativeTo::BEST_FIT; + return S_OK; +} + +CPGSSubFile::CPGSSubFile(CCritSec* pLock) + : CPGSSub(pLock, _T("PGS External Subtitle"), 0) + , m_bStopParsing(false) +{ +} + +CPGSSubFile::~CPGSSubFile() +{ + m_bStopParsing = true; + if (m_parsingThread.joinable()) { + m_parsingThread.join(); + } +} + +STDMETHODIMP CPGSSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + return __super::Render(spd, rt, bbox, false); +} + +bool CPGSSubFile::Open(CString fn, CString name /*= _T("")*/, CString videoName /*= _T("")*/) +{ + bool bOpened = false; + + CString tmp; + CString guessed = Subtitle::GuessSubtitleName(fn, videoName, m_lcid, tmp, m_eHearingImpaired); + if (name.IsEmpty()) { + m_name = guessed; + } else { + m_name = name; + } + + m_path = fn; + + try { + CFile f; + if (f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { + WORD wSyncCode = 0; + f.Read(&wSyncCode, sizeof(wSyncCode)); + wSyncCode = _byteswap_ushort(wSyncCode); + if (wSyncCode == PGS_SYNC_CODE) { + m_parsingThread = std::thread([this, fn] { ParseFile(fn); }); + bOpened = true; + } + } + } catch (CFileException*) { + } + + return bOpened; +} + +CString CPGSSubFile::GetPath() { + return m_path; +} + +void CPGSSubFile::ParseFile(CString fn) +{ + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { + return; + } + + // Header: Sync code | start time | stop time | segment type | segment size + std::array < BYTE, 2 + 2 * 4 + 1 + 2 > header; + const int nExtraSize = 1 + 2; // segment type + segment size + std::vector segBuff; + + while (!m_bStopParsing && f.Read(header.data(), (UINT)header.size()) == header.size()) { + // Parse the header + CGolombBuffer headerBuffer(header.data(), (int)header.size()); + + if (WORD(headerBuffer.ReadShort()) != PGS_SYNC_CODE) { + break; + } + + REFERENCE_TIME rtStart = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; + REFERENCE_TIME rtStop = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; + headerBuffer.ReadByte(); // segment type + WORD wLenSegment = (WORD)headerBuffer.ReadShort(); + + // Leave some room to add the segment type and size + int nLenData = nExtraSize + wLenSegment; + segBuff.resize(nLenData); + memcpy(segBuff.data(), &header[header.size() - nExtraSize], nExtraSize); + + // Read the segment + if (wLenSegment && f.Read(&segBuff[nExtraSize], wLenSegment) != wLenSegment) { + break; + } + + // Parse the data (even if the segment size is 0 because the header itself is important) + TRACE_PGSSUB(_T("--------- CPGSSubFile::ParseFile rtStart=%s, rtStop=%s, len=%d ---------\n"), + ReftimeToString(rtStart), ReftimeToString(rtStop), nLenData); + ParseSample(rtStart, rtStop, segBuff.data(), nLenData); + } +} diff --git a/src/Subtitles/PGSSub.h b/src/Subtitles/PGSSub.h index cb291de5f4c..4996da03371 100644 --- a/src/Subtitles/PGSSub.h +++ b/src/Subtitles/PGSSub.h @@ -1,161 +1,161 @@ -/* - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include "RLECodedSubtitle.h" -#include "CompositionObject.h" -#include -#include -#include - -class CGolombBuffer; - -class CPGSSub : public CRLECodedSubtitle -{ -public: - CPGSSub(CCritSec* pLock, const CString& name, LCID lcid); - virtual ~CPGSSub(); - - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); - - virtual HRESULT ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen); - virtual void EndOfStream() { /* Nothing to do */ }; - virtual void Reset(); - HRESULT GetPresentationSegmentTextureSize(REFERENCE_TIME rt, CSize& size); - -protected: - HRESULT Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox, bool bRemoveOldSegments); - -private: - enum HDMV_SEGMENT_TYPE { - NO_SEGMENT = 0xFFFF, - PALETTE = 0x14, - OBJECT = 0x15, - PRESENTATION_SEG = 0x16, - WINDOW_DEF = 0x17, - INTERACTIVE_SEG = 0x18, - END_OF_DISPLAY = 0x80, - HDMV_SUB1 = 0x81, - HDMV_SUB2 = 0x82 - }; - - - struct VIDEO_DESCRIPTOR { - int nVideoWidth; - int nVideoHeight; - BYTE bFrameRate; - }; - - struct COMPOSITION_DESCRIPTOR { - short nNumber; - BYTE bState; - }; - - struct SEQUENCE_DESCRIPTOR { - BYTE bFirstIn : 1; - BYTE bLastIn : 1; - BYTE bReserved : 6; - }; - - struct HDMV_CLUT { - BYTE id = 0; - BYTE version_number = 0; - WORD size = 0; - - std::array palette; - - HDMV_CLUT() - : palette() { - } - }; - - struct HDMV_PRESENTATION_SEGMENT { - REFERENCE_TIME rtStart = 0; - REFERENCE_TIME rtStop = 0; - - VIDEO_DESCRIPTOR video_descriptor; - COMPOSITION_DESCRIPTOR composition_descriptor; - - byte palette_update_flag = 0; - HDMV_CLUT CLUT; - - int objectCount = 0; - - std::list> objects; - }; - - HDMV_SEGMENT_TYPE m_nCurSegment; - BYTE* m_pSegBuffer; - size_t m_nTotalSegBuffer; - size_t m_nSegBufferPos; - size_t m_nSegSize; - - CAutoPtr m_pCurrentPresentationSegment; - CAutoPtrList m_pPresentationSegments; - - std::array m_CLUTs; - std::array m_compositionObjects; - - void AllocSegment(size_t nSize); - int ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer); - void EnqueuePresentationSegment(); - void UpdateTimeStamp(REFERENCE_TIME rtStop); - - void ParsePalette(CGolombBuffer* pGBuffer, size_t nSize); - void ParseObject(CGolombBuffer* pGBuffer, size_t nUnitSize); - void ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor); - void ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor); - bool ParseCompositionObject(CGolombBuffer* pGBuffer, const std::unique_ptr& pCompositionObject); - - POSITION FindPresentationSegment(REFERENCE_TIME rt) const; - - void RemoveOldSegments(REFERENCE_TIME rt); -}; - -class CPGSSubFile : public CPGSSub -{ -public: - CPGSSubFile(CCritSec* pLock); - virtual ~CPGSSubFile(); - - // ISubPicProvider - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - - bool Open(CString fn, CString name = _T(""), CString videoName = _T("")); - CString GetPath(); - -private: - static const WORD PGS_SYNC_CODE = 'PG'; - - bool m_bStopParsing; - std::thread m_parsingThread; - CString m_path; - - void ParseFile(CString fn); -}; +/* + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include "RLECodedSubtitle.h" +#include "CompositionObject.h" +#include +#include +#include + +class CGolombBuffer; + +class CPGSSub : public CRLECodedSubtitle +{ +public: + CPGSSub(CCritSec* pLock, const CString& name, LCID lcid); + virtual ~CPGSSub(); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); + + virtual HRESULT ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen); + virtual void EndOfStream() { /* Nothing to do */ }; + virtual void Reset(); + HRESULT GetPresentationSegmentTextureSize(REFERENCE_TIME rt, CSize& size); + +protected: + HRESULT Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox, bool bRemoveOldSegments); + +private: + enum HDMV_SEGMENT_TYPE { + NO_SEGMENT = 0xFFFF, + PALETTE = 0x14, + OBJECT = 0x15, + PRESENTATION_SEG = 0x16, + WINDOW_DEF = 0x17, + INTERACTIVE_SEG = 0x18, + END_OF_DISPLAY = 0x80, + HDMV_SUB1 = 0x81, + HDMV_SUB2 = 0x82 + }; + + + struct VIDEO_DESCRIPTOR { + int nVideoWidth; + int nVideoHeight; + BYTE bFrameRate; + }; + + struct COMPOSITION_DESCRIPTOR { + short nNumber; + BYTE bState; + }; + + struct SEQUENCE_DESCRIPTOR { + BYTE bFirstIn : 1; + BYTE bLastIn : 1; + BYTE bReserved : 6; + }; + + struct HDMV_CLUT { + BYTE id = 0; + BYTE version_number = 0; + WORD size = 0; + + std::array palette; + + HDMV_CLUT() + : palette() { + } + }; + + struct HDMV_PRESENTATION_SEGMENT { + REFERENCE_TIME rtStart = 0; + REFERENCE_TIME rtStop = 0; + + VIDEO_DESCRIPTOR video_descriptor; + COMPOSITION_DESCRIPTOR composition_descriptor; + + byte palette_update_flag = 0; + HDMV_CLUT CLUT; + + int objectCount = 0; + + std::list> objects; + }; + + HDMV_SEGMENT_TYPE m_nCurSegment; + BYTE* m_pSegBuffer; + size_t m_nTotalSegBuffer; + size_t m_nSegBufferPos; + size_t m_nSegSize; + + CAutoPtr m_pCurrentPresentationSegment; + CAutoPtrList m_pPresentationSegments; + + std::array m_CLUTs; + std::array m_compositionObjects; + + void AllocSegment(size_t nSize); + int ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer); + void EnqueuePresentationSegment(); + void UpdateTimeStamp(REFERENCE_TIME rtStop); + + void ParsePalette(CGolombBuffer* pGBuffer, size_t nSize); + void ParseObject(CGolombBuffer* pGBuffer, size_t nUnitSize); + void ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor); + void ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor); + bool ParseCompositionObject(CGolombBuffer* pGBuffer, const std::unique_ptr& pCompositionObject); + + POSITION FindPresentationSegment(REFERENCE_TIME rt) const; + + void RemoveOldSegments(REFERENCE_TIME rt); +}; + +class CPGSSubFile : public CPGSSub +{ +public: + CPGSSubFile(CCritSec* pLock); + virtual ~CPGSSubFile(); + + // ISubPicProvider + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + + bool Open(CString fn, CString name = _T(""), CString videoName = _T("")); + CString GetPath(); + +private: + static const WORD PGS_SYNC_CODE = 'PG'; + + bool m_bStopParsing; + std::thread m_parsingThread; + CString m_path; + + void ParseFile(CString fn); +}; diff --git a/src/Subtitles/RTS.cpp b/src/Subtitles/RTS.cpp index 545b04dccfe..a382f6e76ff 100644 --- a/src/Subtitles/RTS.cpp +++ b/src/Subtitles/RTS.cpp @@ -1,3725 +1,3725 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2022 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "ColorConvTable.h" -#include "RTS.h" -#include "../DSUtil/PathUtils.h" -#include "../filters/renderer/VideoRenderers/RenderersSettings.h" -#include "moreuuids.h" - -#if !TRACE_SUBTITLES -#undef TRACE -#define TRACE(...) -#endif - -#define MAXGDIFONTSIZE 36000 - -// WARNING: this isn't very thread safe, use only one RTS a time. We should use TLS in future. -static HDC g_hDC; -static int g_hDC_refcnt = 0; - -static long revcolor(long c) -{ - return ((c & 0xff0000) >> 16) + (c & 0xff00) + ((c & 0xff) << 16); -} - -////////////////////////////////////////////////////////////////////////////////////////////// - -void alpha_mask_deleter::operator()(CAlphaMask* ptr) const noexcept -{ - m_alphaMaskPool.emplace_front(std::move(*ptr)); - std::default_delete()(ptr); - if (m_alphaMaskPool.size() > 10) { - m_alphaMaskPool.pop_back(); - } -} - -// CMyFont - -CMyFont::CMyFont(const STSStyle& style) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - lf <<= style; - lf.lfHeight = (LONG)(style.fontSize + 0.5); - lf.lfOutPrecision = OUT_TT_PRECIS; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfQuality = ANTIALIASED_QUALITY; - lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - if (lf.lfCharSet == 0) - lf.lfCharSet = DEFAULT_CHARSET; - - if (!CreateFontIndirect(&lf)) { - _tcscpy_s(lf.lfFaceName, _T("Calibri")); - VERIFY(CreateFontIndirect(&lf)); - } - - HFONT hOldFont = SelectFont(g_hDC, *this); - -#if 0 - WCHAR selectedFontName[LF_FACESIZE]; - GetTextFaceW(g_hDC, LF_FACESIZE, selectedFontName); - if (wcsncmp(selectedFontName, lf.lfFaceName, LF_FACESIZE)) { //GDI chose a different font -- let's use default instead - SelectFont(g_hDC, hOldFont); - DeleteObject(); - _tcscpy_s(lf.lfFaceName, _T("Calibri")); - VERIFY(CreateFontIndirect(&lf)); - HFONT hOldFont = SelectFont(g_hDC, *this); - } -#endif - - TEXTMETRIC tm; - GetTextMetrics(g_hDC, &tm); - m_ascent = ((tm.tmAscent + 4) >> 3); - m_descent = ((tm.tmDescent + 4) >> 3); - SelectFont(g_hDC, hOldFont); -} - -// CWord - -CWord::CWord(const STSStyle& style, CStringW str, int ktype, int kstart, int kend, double scalex, double scaley, - RenderingCaches& renderingCaches) - : m_fDrawn(false) - , m_p(INT_MAX, INT_MAX) - , m_renderingCaches(renderingCaches) - , m_scalex(scalex) - , m_scaley(scaley) - , m_str(str) - , m_fWhiteSpaceChar(false) - , m_fLineBreak(false) - , m_style(style) - , m_pOpaqueBox(nullptr) - , m_ktype(ktype) - , m_kstart(kstart) - , m_kend(kend) - , m_width(0) - , m_ascent(0) - , m_descent(0) -{ - if (str.IsEmpty()) { - m_fWhiteSpaceChar = m_fLineBreak = true; - } - if (m_style.fontSize > MAXGDIFONTSIZE) { - double fact = m_style.fontSize / MAXGDIFONTSIZE; - m_style.fontSize = MAXGDIFONTSIZE; - m_style.fontScaleX *= fact; - m_style.fontScaleY *= fact; - } - -} - -CWord::~CWord() -{ - delete m_pOpaqueBox; -} - -bool CWord::Append(CWord* w) -{ - if (m_style != w->m_style - || m_fLineBreak || w->m_fLineBreak - || w->m_kstart != w->m_kend || m_ktype != w->m_ktype) { - return false; - } - - m_fWhiteSpaceChar = m_fWhiteSpaceChar && w->m_fWhiteSpaceChar; - m_str += w->m_str; - m_width += w->m_width; - - m_fDrawn = false; - m_p = CPoint(INT_MAX, INT_MAX); - - return true; -} - -void CWord::Paint(const CPoint& p, const CPoint& org) -{ - if (!m_str) { - return; - } - - COverlayKey overlayKey(this, p, org); - - if (m_renderingCaches.overlayCache.Lookup(overlayKey, m_pOverlayData)) { - m_fDrawn = m_renderingCaches.outlineCache.Lookup(overlayKey, m_pOutlineData); - if (m_style.borderStyle == 1) { - if (m_style.outlineWidthX > 0.0 || m_style.shadowDepthX > 0.0 || m_style.outlineWidthY > 0.0 || m_style.shadowDepthY > 0.0) { - VERIFY(CreateOpaqueBox()); - } - } - } else { - if (!m_fDrawn) { - if (m_renderingCaches.outlineCache.Lookup(overlayKey, m_pOutlineData)) { - if (m_style.borderStyle == 1) { - if (m_style.outlineWidthX > 0.0 || m_style.shadowDepthX > 0.0 || m_style.outlineWidthY > 0.0 || m_style.shadowDepthY > 0.0) { - VERIFY(CreateOpaqueBox()); - } - } - } else { - if (!CreatePath()) { - return; - } - - Transform(CPoint((org.x - p.x) * 8, (org.y - p.y) * 8)); - - if (!ScanConvert()) { - return; - } - - if (m_style.borderStyle == 0 && (m_style.outlineWidthX + m_style.outlineWidthY > 0)) { - int rx = std::max(0, std::lround(m_style.outlineWidthX)); - int ry = std::max(0, std::lround(m_style.outlineWidthY)); - - if (!m_pEllipse || m_pEllipse->GetXRadius() != rx || m_pEllipse->GetYRadius() != ry) { - CEllipseKey ellipseKey(rx, ry); - if (!m_renderingCaches.ellipseCache.Lookup(ellipseKey, m_pEllipse)) { - m_pEllipse = std::make_shared(rx, ry); - - m_renderingCaches.ellipseCache.SetAt(ellipseKey, m_pEllipse); - } - } - - if (!CreateWidenedRegion(rx, ry)) { - return; - } - } else if (m_style.borderStyle == 1) { - if (m_style.outlineWidthX > 0.0 || m_style.shadowDepthX > 0.0 || m_style.outlineWidthY > 0.0 || m_style.shadowDepthY > 0.0) { - VERIFY(CreateOpaqueBox()); - } - } - - m_renderingCaches.outlineCache.SetAt(overlayKey, m_pOutlineData); - } - - m_fDrawn = true; - - if (!Rasterize(p.x & 7, p.y & 7, m_style.fBlur, m_style.fGaussianBlur)) { - return; - } - m_renderingCaches.overlayCache.SetAt(overlayKey, m_pOverlayData); - } else if ((m_p.x & 7) != (p.x & 7) || (m_p.y & 7) != (p.y & 7)) { - Rasterize(p.x & 7, p.y & 7, m_style.fBlur, m_style.fGaussianBlur); - m_renderingCaches.overlayCache.SetAt(overlayKey, m_pOverlayData); - } - } - - m_p = p; - - if (m_pOpaqueBox) { - m_pOpaqueBox->Paint(p, org); - } -} - -void CWord::Transform(CPoint org) -{ - if ((fabs(m_style.fontAngleX) > 0.000001) || (fabs(m_style.fontAngleY) > 0.000001) || (fabs(m_style.fontAngleZ) > 0.000001) || - (fabs(m_style.fontShiftX) > 0.000001) || (fabs(m_style.fontShiftY) > 0.000001)) { - Transform_SSE2(org); - } else if ((fabs(m_style.fontScaleX - 100) > 0.000001) || (fabs(m_style.fontScaleY - 100) > 0.000001)) { - Transform_quick_SSE2(org); - } -} - -bool CWord::CreateOpaqueBox() -{ - if (m_pOpaqueBox) { - return true; - } - - STSStyle style = m_style; - style.borderStyle = 0; - - // We don't want to apply the outline and the scaling twice - style.outlineWidthX = style.outlineWidthY = 0.0; - if (m_str.GetLength() > 2) { - // some SSA subs use an opaque box to draw text backgrounds for translated signs - // these use single character with a large fontscale - // don't adjust scale in that case - style.fontScaleX = style.fontScaleY = 100.0; - } - - style.colors[0] = m_style.colors[2]; - style.alpha[0] = m_style.alpha[2]; - - int w = std::lround(m_style.outlineWidthX); - int h = std::lround(m_style.outlineWidthY); - - // Convert to pixels rounding to nearest - CStringW str; - str.Format(L"m %d %d l %d %d %d %d %d %d", - -(w + 4) / 8, -(h + 4) / 8, - (m_width + w + 4) / 8, -(h + 4) / 8, - (m_width + w + 4) / 8, (m_ascent + m_descent + h + 4) / 8, - -(w + 4) / 8, (m_ascent + m_descent + h + 4) / 8); - - try { - m_pOpaqueBox = DEBUG_NEW CPolygon(style, str, 0, 0, 0, 1.0, 1.0, 0, m_renderingCaches); - } catch (CMemoryException* e) { - e->Delete(); - m_pOpaqueBox = nullptr; - } - - return !!m_pOpaqueBox; -} - -#if 0 -void CWord::Transform_C(const CPoint& org) -{ - const double scalex = m_style.fontScaleX / 100.0; - const double scaley = m_style.fontScaleY / 100.0; - const double xzoomf = m_scalex * 20000.0; - const double yzoomf = m_scaley * 20000.0; - - const double caz = cos((M_PI / 180.0) * m_style.fontAngleZ); - const double saz = sin((M_PI / 180.0) * m_style.fontAngleZ); - const double cax = cos((M_PI / 180.0) * m_style.fontAngleX); - const double sax = sin((M_PI / 180.0) * m_style.fontAngleX); - const double cay = cos((M_PI / 180.0) * m_style.fontAngleY); - const double say = sin((M_PI / 180.0) * m_style.fontAngleY); - - double dOrgX = static_cast(org.x), dOrgY = static_cast(org.y); - for (ptrdiff_t i = 0; i < mPathPoints; i++) { - double x, y, z, xx, yy, zz; - - x = mpPathPoints[i].x; - y = mpPathPoints[i].y; - z = 0; - - const double dPPx = m_style.fontShiftX * y + x; - y = scaley * (m_style.fontShiftY * x + y) - dOrgY; - x = scalex * dPPx - dOrgX; - - xx = x * caz + y * saz; - yy = -(x * saz - y * caz); - zz = z; - - x = xx; - y = yy * cax + zz * sax; - z = yy * sax - zz * cax; - - xx = x * cay + z * say; - yy = y; - zz = x * say - z * cay; - - x = xx * xzoomf / std::max((zz + xzoomf), 1000.0); - y = yy * yzoomf / std::max((zz + yzoomf), 1000.0); - - // round to integer - mpPathPoints[i].x = std::lround(x) + org.x; - mpPathPoints[i].y = std::lround(y) + org.y; - } -} -#endif - -#if 0 -void CWord::Transform_quick_C(const CPoint& org) -{ - const double scalex = m_style.fontScaleX / 100.0; - const double scaley = m_style.fontScaleY / 100.0; - - for (ptrdiff_t i = 0; i < mPathPoints; i++) { - double x = scalex * mpPathPoints[i].x; - double y = scaley * mpPathPoints[i].y; - - // round to integer - mpPathPoints[i].x = std::lround(x); - mpPathPoints[i].y = std::lround(y); - } -} -#endif - -void CWord::Transform_quick_SSE2(const CPoint& org) -{ - const __m128 __xscale = _mm_set_ps1((float)(m_style.fontScaleX / 100.0)); - const __m128 __yscale = _mm_set_ps1((float)(m_style.fontScaleY / 100.0)); - - int mPathPointsD4 = mPathPoints / 4; - int mPathPointsM4 = mPathPoints % 4; - - for (ptrdiff_t i = 0; i < mPathPointsD4 + 1; i++) { - __m128 __pointx, __pointy; - // we can't use load .-. - if (i != mPathPointsD4) { - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, (float)mpPathPoints[4 * i + 2].x, (float)mpPathPoints[4 * i + 3].x); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, (float)mpPathPoints[4 * i + 2].y, (float)mpPathPoints[4 * i + 3].y); - } else { // last cycle - switch (mPathPointsM4) { - default: - case 0: - continue; - case 1: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, 0, 0, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, 0, 0, 0); - break; - case 2: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, 0, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, 0, 0); - break; - case 3: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, (float)mpPathPoints[4 * i + 2].x, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, (float)mpPathPoints[4 * i + 2].y, 0); - break; - } - } - - // scale - __pointx = _mm_mul_ps(__pointx, __xscale); - __pointy = _mm_mul_ps(__pointy, __yscale); - - // round to integer - __m128i __pointxRounded = _mm_cvtps_epi32(__pointx); - __m128i __pointyRounded = _mm_cvtps_epi32(__pointy); - - if (i == mPathPointsD4) { // last cycle - for (int k = 0; k < mPathPointsM4; k++) { - mpPathPoints[i * 4 + k].x = __pointxRounded.m128i_i32[3 - k]; - mpPathPoints[i * 4 + k].y = __pointyRounded.m128i_i32[3 - k]; - } - } else { - for (int k = 0; k < 4; k++) { - mpPathPoints[i * 4 + k].x = __pointxRounded.m128i_i32[3 - k]; - mpPathPoints[i * 4 + k].y = __pointyRounded.m128i_i32[3 - k]; - } - } - } -} - -void CWord::Transform_SSE2(const CPoint& org) -{ - // SSE code - // speed up ~1.5-1.7x - const __m128 __xshift = _mm_set_ps1((float)m_style.fontShiftX); - const __m128 __yshift = _mm_set_ps1((float)m_style.fontShiftY); - - const __m128 __xorg = _mm_set_ps1((float)org.x); - const __m128 __yorg = _mm_set_ps1((float)org.y); - - const __m128 __xscale = _mm_set_ps1((float)(m_style.fontScaleX / 100.0)); - const __m128 __yscale = _mm_set_ps1((float)(m_style.fontScaleY / 100.0)); - const __m128 __xzoomf = _mm_set_ps1((float)(m_scalex * 20000.0)); - const __m128 __yzoomf = _mm_set_ps1((float)(m_scaley * 20000.0)); - - const __m128 __caz = _mm_set_ps1((float)cos((M_PI / 180.0) * m_style.fontAngleZ)); - const __m128 __saz = _mm_set_ps1((float)sin((M_PI / 180.0) * m_style.fontAngleZ)); - const __m128 __cax = _mm_set_ps1((float)cos((M_PI / 180.0) * m_style.fontAngleX)); - const __m128 __sax = _mm_set_ps1((float)sin((M_PI / 180.0) * m_style.fontAngleX)); - const __m128 __cay = _mm_set_ps1((float)cos((M_PI / 180.0) * m_style.fontAngleY)); - const __m128 __say = _mm_set_ps1((float)sin((M_PI / 180.0) * m_style.fontAngleY)); - - const __m128 __1000 = _mm_set_ps1(1000.0f); - - int mPathPointsD4 = mPathPoints / 4; - int mPathPointsM4 = mPathPoints % 4; - - for (ptrdiff_t i = 0; i < mPathPointsD4 + 1; i++) { - __m128 __pointx, __pointy, __tmpx, __tmpy; - // we can't use load .-. - if (i != mPathPointsD4) { - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, (float)mpPathPoints[4 * i + 2].x, (float)mpPathPoints[4 * i + 3].x); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, (float)mpPathPoints[4 * i + 2].y, (float)mpPathPoints[4 * i + 3].y); - } else { // last cycle - switch (mPathPointsM4) { - default: - case 0: - continue; - case 1: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, 0, 0, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, 0, 0, 0); - break; - case 2: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, 0, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, 0, 0); - break; - case 3: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, (float)mpPathPoints[4 * i + 2].x, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, (float)mpPathPoints[4 * i + 2].y, 0); - break; - } - } - - // scale and shift - __tmpy = __pointx; // save a copy for calculating __pointy later - if (m_style.fontShiftX != 0) { - __tmpx = _mm_mul_ps(__xshift, __pointy); - __pointx = _mm_add_ps(__pointx, __tmpx); - } - __pointx = _mm_mul_ps(__pointx, __xscale); - __pointx = _mm_sub_ps(__pointx, __xorg); - - if (m_style.fontShiftY != 0) { - __tmpy = _mm_mul_ps(__yshift, __tmpy); // __tmpy is a copy of __pointx here, because it may otherwise be modified - __pointy = _mm_add_ps(__pointy, __tmpy); - } - __pointy = _mm_mul_ps(__pointy, __yscale); - __pointy = _mm_sub_ps(__pointy, __yorg); - - // rotate - - __m128 __xx, __yy; - __m128 __zz = _mm_setzero_ps(); - - // xx = x * caz + y * saz - __tmpx = _mm_mul_ps(__pointx, __caz); // x * caz - __tmpy = _mm_mul_ps(__pointy, __saz); // y * saz - __xx = _mm_add_ps(__tmpx, __tmpy); // xx = x * caz + y * saz; - - // yy = -(x * saz - y * caz) - __tmpx = _mm_mul_ps(__pointx, __saz); // x * saz - __tmpy = _mm_mul_ps(__pointy, __caz); // y * caz - __yy = _mm_sub_ps(__tmpy, __tmpx); // yy = -(x * saz - y * caz) = y * caz - x * saz - - __pointx = __xx; // x = xx - - // y = yy * cax + zz * sax - __tmpx = _mm_mul_ps(__zz, __sax); // zz * sax - __tmpy = _mm_mul_ps(__yy, __cax); // yy * cax - __pointy = _mm_add_ps(__tmpy, __tmpx); // y = yy * cax + zz * sax - - // z = yy * sax - zz * cax - __tmpx = _mm_mul_ps(__zz, __cax); // zz * cax - __tmpy = _mm_mul_ps(__yy, __sax); // yy * sax - __zz = _mm_sub_ps(__tmpy, __tmpx); // z = yy * sax - zz * cax - - // xx = x * cay + z * say - __tmpx = _mm_mul_ps(__pointx, __cay); // x * cay - __tmpy = _mm_mul_ps(__zz, __say); // z * say - __xx = _mm_add_ps(__tmpx, __tmpy); // xx = x * cay + z * say - - __yy = __pointy; // yy = y - - // zz = x * say - z * cay - __tmpx = _mm_mul_ps(__pointx, __say); // x * say - __zz = _mm_mul_ps(__zz, __cay); // z * cay - __zz = _mm_sub_ps(__tmpx, __zz); // zz = x * say - z * cay - - // x = xx * xzoomf / std::max((zz + xzoomf), 1000.0); - // y = yy * yzoomf / std::max((zz + yzoomf), 1000.0); - __m128 __tmpzz = _mm_add_ps(__zz, __xzoomf); // zz + xzoomf - - __xx = _mm_mul_ps(__xx, __xzoomf); // xx * xzoomf - __pointx = _mm_div_ps(__xx, _mm_max_ps(__tmpzz, __1000)); // x = (xx * xzoomf) / std::max((zz + xzoomf), 1000.0) - - __tmpzz = _mm_add_ps(__zz, __yzoomf); // zz + yzoomf - - __yy = _mm_mul_ps(__yy, __yzoomf); // yy * yzoomf - __pointy = _mm_div_ps(__yy, _mm_max_ps(__tmpzz, __1000)); // y = yy * yzoomf / std::max((zz + yzoomf), 1000.0); - - __pointx = _mm_add_ps(__pointx, __xorg); // x = x + org.x - __pointy = _mm_add_ps(__pointy, __yorg); // y = y + org.y - - // round to integer - __m128i __pointxRounded = _mm_cvtps_epi32(__pointx); - __m128i __pointyRounded = _mm_cvtps_epi32(__pointy); - - if (i == mPathPointsD4) { // last cycle - for (int k = 0; k < mPathPointsM4; k++) { - mpPathPoints[i * 4 + k].x = __pointxRounded.m128i_i32[3 - k]; - mpPathPoints[i * 4 + k].y = __pointyRounded.m128i_i32[3 - k]; - } - } else { - for (int k = 0; k < 4; k++) { - mpPathPoints[i * 4 + k].x = __pointxRounded.m128i_i32[3 - k]; - mpPathPoints[i * 4 + k].y = __pointyRounded.m128i_i32[3 - k]; - } - } - } -} - -// CText - -CText::CText(const STSStyle& style, CStringW str, int ktype, int kstart, int kend, double scalex, double scaley, - RenderingCaches& renderingCaches) - : CWord(style, str, ktype, kstart, kend, scalex, scaley, renderingCaches) -{ - if (m_str == L" ") { - m_fWhiteSpaceChar = true; - } - - CTextDimsKey textDimsKey(m_str, m_style); - CTextDims textDims; - if (!renderingCaches.textDimsCache.Lookup(textDimsKey, textDims)) { - CMyFont font(m_style); - m_ascent = font.m_ascent; - m_descent = font.m_descent; - - HFONT hOldFont = SelectFont(g_hDC, font); - - if (m_style.fontSpacing) { - for (LPCWSTR s = m_str; *s; s++) { - CSize extent; - if (!GetTextExtentPoint32W(g_hDC, s, 1, &extent)) { - SelectFont(g_hDC, hOldFont); - ASSERT(0); - return; - } - m_width += extent.cx + (int)m_style.fontSpacing; - } - // m_width -= (int)m_style.fontSpacing; // TODO: subtract only at the end of the line - } else { - CSize extent; - if (!GetTextExtentPoint32W(g_hDC, m_str, str.GetLength(), &extent)) { - SelectFont(g_hDC, hOldFont); - ASSERT(0); - return; - } - m_width += extent.cx; - } - - SelectFont(g_hDC, hOldFont); - - textDims.ascent = m_ascent; - textDims.descent = m_descent; - textDims.width = m_width; - - renderingCaches.textDimsCache.SetAt(textDimsKey, textDims); - } else { - m_ascent = textDims.ascent; - m_descent = textDims.descent; - m_width = textDims.width; - } - - m_ascent = (int)(m_style.fontScaleY / 100 * m_ascent); - m_descent = (int)(m_style.fontScaleY / 100 * m_descent); - m_width = (int)(m_style.fontScaleX / 100 * m_width + 4) >> 3; -} - -CWord* CText::Copy() -{ - return DEBUG_NEW CText(*this); -} - -bool CText::Append(CWord* w) -{ - return (dynamic_cast(w) && CWord::Append(w)); -} - -bool CText::CreatePath() -{ - CMyFont font(m_style); - - HFONT hOldFont = SelectFont(g_hDC, font); - - LONG cx = 0; - auto getExtent = [&](LPCWSTR s, int len) { - CSize extent; - if (!GetTextExtentPoint32W(g_hDC, s, len, &extent)) { - SelectFont(g_hDC, hOldFont); - ASSERT(0); - return false; - } - cx = extent.cx; - return true; - }; - - bool useFreetypePath = false; - std::wstring fontNameFT; - CStringA langHint = ""; - if (m_RTS) { - langHint = m_RTS->openTypeLangHint; - useFreetypePath = m_RTS->GetUseFreeType(); - if (useFreetypePath) { - fontNameFT = CW2W(m_style.fontName); - fontNameFT += std::to_wstring(m_style.fontSize); - } - } - - if (m_style.fontSpacing) { - int width = 0; - bool bFirstPath = true; - - if (!useFreetypePath) { - for (LPCWSTR s = m_str; *s; s++) { - if (!getExtent(s, 1)) { - return false; - } - if (cx == 0) { - // possible unhandled unprintable character - ASSERT(*s == L'\x202a' || *s == L'\x202b'); - continue; - } - PartialBeginPath(g_hDC, bFirstPath); - bFirstPath = false; - TextOutW(g_hDC, 0, 0, s, 1); - int mp = mPathPoints; - PartialEndPath(g_hDC, width, 0); - if (mp == mPathPoints && !CStringW::StrTraits::IsSpace(s[0]) && m_RTS) { //failed to add points, we will try again with FreeType as emulator - useFreetypePath = true; - fontNameFT = CW2W(m_style.fontName); - fontNameFT += std::to_wstring(m_style.fontSize); - break; - } -#if 0 - GetPathFreeType(g_hDC, false, s[0], m_style.fontSize, width+ cx + (int)m_style.fontSpacing, 0); - GetPathFreeType(g_hDC, false, s[0], m_style.fontSize, width, m_style.fontSize*2); -#endif - - width += cx + (int)m_style.fontSpacing; - } - } - if (useFreetypePath) { //try freetype - int ftWidth = 0; - bFirstPath = true; - m_RTS->m_ftLibrary.LoadCodeFaceData(g_hDC, fontNameFT); - if (!langHint.IsEmpty()) { - m_RTS->m_ftLibrary.LoadCodePoints(m_str, fontNameFT, langHint); - } - for (LPCWSTR s = m_str; *s; s++) { - if (!getExtent(s, 1)) { - return false; - } - if (cx == 0) { - // possible unhandled unprintable character - ASSERT(false); - continue; - } - - if (!GetPathFreeType(g_hDC, bFirstPath, fontNameFT, s[0], ftWidth, 0, langHint, &m_RTS->m_ftLibrary)) { - break; - } - bFirstPath = false; - ftWidth += cx + (int)m_style.fontSpacing; - } - } - } else { - int strlen = m_str.GetLength(); - - if (!getExtent(m_str, strlen) || cx == 0) { - // possible unhandled unprintable character - ASSERT(false); - return false; - } - - if (!useFreetypePath) { - BeginPath(g_hDC); - TextOutW(g_hDC, 0, 0, m_str, strlen); - EndPath(g_hDC); - - - if (mPathPoints == 0 && m_RTS && strlen > 0) { // try freetype as fallback - useFreetypePath = true; - fontNameFT = CW2W(m_style.fontName); - fontNameFT += std::to_wstring(m_style.fontSize); - } - } - - if (useFreetypePath && strlen > 0) { - int ftWidth = 0; - bool bFirstPath = true; - m_RTS->m_ftLibrary.LoadCodeFaceData(g_hDC, fontNameFT); - if (!langHint.IsEmpty()) { - m_RTS->m_ftLibrary.LoadCodePoints(m_str, fontNameFT, langHint); - } - for (LPCWSTR s = m_str; *s; s++) { - if (!getExtent(s, 1)) { - return false; - } - if (!GetPathFreeType(g_hDC, bFirstPath, fontNameFT, s[0], ftWidth, 0, langHint, &m_RTS->m_ftLibrary)) { - break; - } - bFirstPath = false; - ftWidth += cx; - } - } - } - - SelectFont(g_hDC, hOldFont); - - return true; -} - -// CPolygon - -CPolygon::CPolygon(const STSStyle& style, CStringW str, int ktype, int kstart, int kend, double scalex, double scaley, int baseline, - RenderingCaches& renderingCaches) - : CWord(style, str, ktype, kstart, kend, scalex, scaley, renderingCaches) - , m_baseline(baseline) -{ - ParseStr(); -} - -CPolygon::CPolygon(CPolygon& src) - : CWord(src.m_style, src.m_str, src.m_ktype, src.m_kstart, src.m_kend, src.m_scalex, src.m_scaley, src.m_renderingCaches) - , m_baseline(src.m_baseline) - , m_pPolygonPath(src.m_pPolygonPath) -{ - m_width = src.m_width; - m_ascent = src.m_ascent; - m_descent = src.m_descent; -} - -CPolygon::~CPolygon() -{ -} - -CWord* CPolygon::Copy() -{ - return (DEBUG_NEW CPolygon(*this)); -} - -bool CPolygon::Append(CWord* w) -{ - CPolygon* p = dynamic_cast(w); - if (!p) { - return false; - } - - // TODO - return false; - - //return true; -} - -bool CPolygon::GetPOINT(LPCWSTR& str, POINT& point) const -{ - LPWSTR xEnd = nullptr; - LPWSTR yEnd = nullptr; - - point.x = std::lround(wcstod(str, &xEnd) * m_scalex) * 64; - if (xEnd <= str) { - return false; - } - point.y = std::lround(wcstod(xEnd, &yEnd) * m_scaley) * 64; - - bool ret = yEnd > xEnd; - str = yEnd; - - return ret; -} - -bool CPolygon::ParseStr() -{ - if (m_pPolygonPath && !m_pPolygonPath->typesOrg.IsEmpty()) { - return true; - } - - CPolygonPathKey polygonPathKey(m_str, m_scalex, m_scaley); - if (!m_renderingCaches.polygonCache.Lookup(polygonPathKey, m_pPolygonPath)) { - m_pPolygonPath = std::make_shared(); - CPoint p; - bool bFoundMove = false; - size_t i, j, lastSplineStart = SIZE_T_ERROR; - - auto isValidAction = [](const WCHAR c) { - return c == L'm' || c == L'n' || c == L'l' || c == L'b' - || c == L's' || c == L'p' || c == L'c'; - }; - - for (LPCWSTR str = m_str; *str;) { - // Trim any leading invalid characters and whitespace - while (*str && !isValidAction(*str)) { - str++; - } - const WCHAR c = *str; - if (*str) { - do { - str++; - } while (isValidAction(*str)); - } - switch (c) { - case L'm': - if (!bFoundMove) { - if (m_pPolygonPath->typesOrg.GetCount() > 0) { - // move command not first so we abort - m_pPolygonPath = nullptr; - return false; - } - bFoundMove = true; - } - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_MOVETO); - m_pPolygonPath->pointsOrg.Add(p); - } - break; - case L'n': - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_MOVETONC); - m_pPolygonPath->pointsOrg.Add(p); - } - break; - case L'l': - if (m_pPolygonPath->pointsOrg.GetCount() < 1) { - break; - } - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_LINETO); - m_pPolygonPath->pointsOrg.Add(p); - } - break; - case L'b': - j = m_pPolygonPath->typesOrg.GetCount(); - if (j < 1) { - break; - } - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_BEZIERTO); - m_pPolygonPath->pointsOrg.Add(p); - ++j; - } - j = m_pPolygonPath->typesOrg.GetCount() - ((m_pPolygonPath->typesOrg.GetCount() - j) % 3); - m_pPolygonPath->typesOrg.SetCount(j); - m_pPolygonPath->pointsOrg.SetCount(j); - break; - case L's': - if (m_pPolygonPath->pointsOrg.GetCount() < 1) { - break; - } - j = lastSplineStart = m_pPolygonPath->typesOrg.GetCount(); - i = 3; - while (i-- && GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_BSPLINETO); - m_pPolygonPath->pointsOrg.Add(p); - ++j; - } - if (m_pPolygonPath->typesOrg.GetCount() - lastSplineStart < 3) { - m_pPolygonPath->typesOrg.SetCount(lastSplineStart); - m_pPolygonPath->pointsOrg.SetCount(lastSplineStart); - lastSplineStart = SIZE_T_ERROR; - } - // no break - case L'p': - if (m_pPolygonPath->pointsOrg.GetCount() < 3) { - break; - } - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_BSPLINEPATCHTO); - m_pPolygonPath->pointsOrg.Add(p); - } - break; - case L'c': - if (lastSplineStart != SIZE_T_ERROR && lastSplineStart > 0) { - m_pPolygonPath->typesOrg.Add(PT_BSPLINEPATCHTO); - m_pPolygonPath->typesOrg.Add(PT_BSPLINEPATCHTO); - m_pPolygonPath->typesOrg.Add(PT_BSPLINEPATCHTO); - p = m_pPolygonPath->pointsOrg[lastSplineStart - 1]; // we need p for temp storage, because operator [] will return a reference to CPoint and Add() may reallocate its internal buffer (this is true for MFC 7.0 but not for 6.0, hehe) - m_pPolygonPath->pointsOrg.Add(p); - p = m_pPolygonPath->pointsOrg[lastSplineStart]; - m_pPolygonPath->pointsOrg.Add(p); - p = m_pPolygonPath->pointsOrg[lastSplineStart + 1]; - m_pPolygonPath->pointsOrg.Add(p); - lastSplineStart = SIZE_T_ERROR; - } - break; - default: - break; - } - } - - if (!bFoundMove) { - // move command not found so we abort - m_pPolygonPath = nullptr; - return false; - } - - int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN; - - for (size_t m = 0; m < m_pPolygonPath->typesOrg.GetCount(); m++) { - if (minx > m_pPolygonPath->pointsOrg[m].x) { - minx = m_pPolygonPath->pointsOrg[m].x; - } - if (miny > m_pPolygonPath->pointsOrg[m].y) { - miny = m_pPolygonPath->pointsOrg[m].y; - } - if (maxx < m_pPolygonPath->pointsOrg[m].x) { - maxx = m_pPolygonPath->pointsOrg[m].x; - } - if (maxy < m_pPolygonPath->pointsOrg[m].y) { - maxy = m_pPolygonPath->pointsOrg[m].y; - } - } - - m_pPolygonPath->size.SetSize(std::max(maxx - minx, 0), std::max(maxy - miny, 0)); - - m_renderingCaches.polygonCache.SetAt(polygonPathKey, m_pPolygonPath); - } - - m_width = m_pPolygonPath->size.cx; - m_ascent = m_pPolygonPath->size.cy; - - int baseline = std::lround(m_scaley * m_baseline) * 64; - m_descent = baseline; - m_ascent -= baseline; - - m_width = ((int)(m_style.fontScaleX / 100.0 * m_width) + 4) >> 3; - m_ascent = ((int)(m_style.fontScaleY / 100.0 * m_ascent) + 4) >> 3; - m_descent = ((int)(m_style.fontScaleY / 100.0 * m_descent) + 4) >> 3; - - return true; -} - -bool CPolygon::CreatePath() -{ - int len = m_pPolygonPath ? (int)m_pPolygonPath->typesOrg.GetCount() : 0; - if (len == 0) { - return false; - } - - if (mPathPoints != len) { - BYTE* pNewPathTypes = (BYTE*)realloc(mpPathTypes, len * sizeof(BYTE)); - if (!pNewPathTypes) { - return false; - } - mpPathTypes = pNewPathTypes; - POINT* pNewPathPoints = (POINT*)realloc(mpPathPoints, len * sizeof(POINT)); - if (!pNewPathPoints) { - return false; - } - mpPathPoints = pNewPathPoints; - mPathPoints = len; - } - - memcpy(mpPathTypes, m_pPolygonPath->typesOrg.GetData(), len * sizeof(BYTE)); - memcpy(mpPathPoints, m_pPolygonPath->pointsOrg.GetData(), len * sizeof(POINT)); - - return true; -} - -// CClipper - -CClipper::CClipper(CStringW str, const CSize& size, double scalex, double scaley, bool inverse, const CPoint& cpOffset, - RenderingCaches& renderingCaches) - : CPolygon(STSStyle(), str, 0, 0, 0, scalex, scaley, 0, renderingCaches) - , m_size(size) - , m_inverse(inverse) - , m_cpOffset(cpOffset) - , m_pAlphaMask(nullptr) - , m_effectType(-1) -{ -} - -CAlphaMaskSharedPtr CClipper::GetAlphaMask(const std::shared_ptr& clipper) -{ - if (m_pAlphaMask) { - return m_pAlphaMask; - } - - ASSERT(this == clipper.get()); - if (m_size.cx <= 0 || m_size.cy <= 0) { - return nullptr; - } - - CClipperKey key(clipper); - if (m_renderingCaches.alphaMaskCache.Lookup(key, m_pAlphaMask)) { - return m_pAlphaMask; - } - - Paint(CPoint(0, 0), CPoint(0, 0)); - - if (!m_pOverlayData) { - return nullptr; - } - - int w = m_pOverlayData->mOverlayWidth, h = m_pOverlayData->mOverlayHeight; - - int x = (m_pOverlayData->mOffsetX + m_cpOffset.x + 4) >> 3, y = (m_pOverlayData->mOffsetY + m_cpOffset.y + 4) >> 3; - int xo = 0, yo = 0; - - if (x < 0) { - xo = -x; - w -= -x; - x = 0; - } - if (y < 0) { - yo = -y; - h -= -y; - y = 0; - } - if (x + w > m_size.cx) { - w = m_size.cx - x; - } - if (y + h > m_size.cy) { - h = m_size.cy - y; - } - - if (w <= 0 || h <= 0) { - return nullptr; - } - - const size_t alphaMaskSize = size_t(m_size.cx) * m_size.cy; - - try { - m_pAlphaMask = CAlphaMask::Alloc(m_renderingCaches.alphaMaskPool, alphaMaskSize); - } catch (CMemoryException* e) { - e->Delete(); - m_pAlphaMask = nullptr; - return nullptr; - } - - BYTE* pAlphaMask = m_pAlphaMask->get(); - memset(pAlphaMask, (m_inverse ? 0x40 : 0), alphaMaskSize); - - const BYTE* src = m_pOverlayData->mpOverlayBufferBody + m_pOverlayData->mOverlayPitch * yo + xo; - BYTE* dst = pAlphaMask + m_size.cx * y + x; - - if (m_inverse) { - for (ptrdiff_t i = 0; i < h; ++i) { - for (ptrdiff_t wt = 0; wt < w; ++wt) { - dst[wt] = 0x40 - src[wt]; - } - src += m_pOverlayData->mOverlayPitch; - dst += m_size.cx; - } - } else { - for (ptrdiff_t i = 0; i < h; ++i) { - memcpy(dst, src, w * sizeof(BYTE)); - src += m_pOverlayData->mOverlayPitch; - dst += m_size.cx; - } - } - - if (m_effectType == EF_SCROLL) { - int height = m_effect.param[4]; - int spd_w = m_size.cx, spd_h = m_size.cy; - int da = (64 << 8) / height; - int a = 0; - int k = m_effect.param[0] >> 3; - int l = k + height; - if (k < 0) { - a += -k * da; - k = 0; - } - if (l > spd_h) { - l = spd_h; - } - - if (k < spd_h) { - BYTE* am = &pAlphaMask[k * spd_w]; - - ZeroMemory(pAlphaMask, am - pAlphaMask); - - for (ptrdiff_t j = k; j < l; j++, a += da) { - for (ptrdiff_t i = 0; i < spd_w; i++, am++) { - *am = BYTE(((*am) * a) >> 14); - } - } - } - - da = -(64 << 8) / height; - a = 0x40 << 8; - l = m_effect.param[1] >> 3; - k = l - height; - if (k < 0) { - a += -k * da; - k = 0; - } - if (l > spd_h) { - l = spd_h; - } - - if (k < spd_h) { - BYTE* am = &pAlphaMask[k * spd_w]; - - int j = k; - for (; j < l; j++, a += da) { - for (ptrdiff_t i = 0; i < spd_w; i++, am++) { - *am = BYTE(((*am) * a) >> 14); - } - } - - ZeroMemory(am, (spd_h - j)*spd_w); - } - } else if (m_effectType == EF_BANNER) { - int width = m_effect.param[2]; - int spd_w = m_size.cx, spd_h = m_size.cy; - int da = (64 << 8) / width; - BYTE* am = pAlphaMask; - - for (ptrdiff_t j = 0; j < spd_h; j++, am += spd_w) { - int a = 0; - int k = std::min(width, spd_w); - - for (ptrdiff_t i = 0; i < k; i++, a += da) { - am[i] = BYTE((am[i] * a) >> 14); - } - - a = 0x40 << 8; - k = spd_w - width; - - if (k < 0) { - a -= -k * da; - k = 0; - } - - for (ptrdiff_t i = k; i < spd_w; i++, a -= da) { - am[i] = BYTE((am[i] * a) >> 14); - } - } - - } - m_renderingCaches.alphaMaskCache.SetAt(key, m_pAlphaMask); - return m_pAlphaMask; -} - -CWord* CClipper::Copy() -{ - return DEBUG_NEW CClipper(m_str, m_size, m_scalex, m_scaley, m_inverse, m_cpOffset, m_renderingCaches); -} - -bool CClipper::Append(CWord* w) -{ - return false; -} - -// CLine - -CLine::~CLine() -{ - POSITION pos = GetHeadPosition(); - while (pos) { - delete GetNext(pos); - } -} - -void CLine::Compact() -{ - POSITION pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - if (!w->m_fWhiteSpaceChar) { - break; - } - - m_width -= w->m_width; - delete w; - RemoveHead(); - } - - pos = GetTailPosition(); - while (pos) { - CWord* w = GetPrev(pos); - if (!w->m_fWhiteSpaceChar) { - break; - } - - m_width -= w->m_width; - delete w; - RemoveTail(); - } - - if (IsEmpty()) { - return; - } - - CLine l; - l.AddTailList(this); - RemoveAll(); - - CWord* last = nullptr; - - pos = l.GetHeadPosition(); - while (pos) { - CWord* w = l.GetNext(pos); - - if (!last || !last->Append(w)) { - AddTail(last = w->Copy()); - } - } - - m_ascent = m_descent = m_borderX = m_borderY = 0; - - pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - - if (m_ascent < w->m_ascent) { - m_ascent = w->m_ascent; - } - if (m_descent < w->m_descent) { - m_descent = w->m_descent; - } - if (m_borderX < w->m_style.outlineWidthX) { - m_borderX = (int)(w->m_style.outlineWidthX + 0.5); - } - if (m_borderY < w->m_style.outlineWidthY) { - m_borderY = (int)(w->m_style.outlineWidthY + 0.5); - } - } -} - -CRect CLine::PaintShadow(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha) -{ - CRect bbox(0, 0, 0, 0); - - POSITION pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - - if (w->m_fLineBreak) { - return bbox; // should not happen since this class is just a line of text without any breaks - } - - if (w->m_style.shadowDepthX != 0 || w->m_style.shadowDepthY != 0) { - int x = p.x + (int)(w->m_style.shadowDepthX + 0.5); - int y = p.y + m_ascent - w->m_ascent + (int)(w->m_style.shadowDepthY + 0.5); - - DWORD a = 0xff - w->m_style.alpha[3]; - if (alpha > 0) { - a = a * (0xff - static_cast(alpha)) / 0xff; - } - COLORREF shadow = revcolor(w->m_style.colors[3]) | (a << 24); - DWORD sw[6] = {shadow, DWORD_MAX}; - sw[0] = ColorConvTable::ColorCorrection(sw[0]); - - w->Paint(CPoint(x, y), org); - - if (w->m_style.borderStyle == 0) { - bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw, - w->m_ktype > 0 || w->m_style.alpha[0] < 0xff, - (w->m_style.outlineWidthX + w->m_style.outlineWidthY > 0) && !(w->m_ktype == 2 && time < w->m_kstart)); - } else if (w->m_style.borderStyle == 1 && w->m_pOpaqueBox) { - bbox |= w->m_pOpaqueBox->Draw(spd, clipRect, pAlphaMask, x, y, sw, true, false); - } - } - - p.x += w->m_width; - } - - return bbox; -} - -CRect CLine::PaintOutline(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha) -{ - CRect bbox(0, 0, 0, 0); - - POSITION pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - - if (w->m_fLineBreak) { - return bbox; // should not happen since this class is just a line of text without any breaks - } - - bool has_outline = w->m_style.outlineWidthX + w->m_style.outlineWidthY > 0.0; - if ((has_outline || w->m_style.borderStyle == 1) && !(w->m_ktype == 2 && time < w->m_kstart)) { - int x = p.x; - int y = p.y + m_ascent - w->m_ascent; - DWORD aoutline = w->m_style.alpha[2]; - if (alpha > 0) { - aoutline += alpha * (0xff - w->m_style.alpha[2]) / 0xff; - } - COLORREF outline = revcolor(has_outline ? w->m_style.colors[2] : w->m_style.colors[3]) | ((0xff - aoutline) << 24); - DWORD sw[6] = {outline, DWORD_MAX}; - sw[0] = ColorConvTable::ColorCorrection(sw[0]); - - w->Paint(CPoint(x, y), org); - - if (w->m_style.borderStyle == 0) { - bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw, !w->m_style.alpha[0] && !w->m_style.alpha[1] && !alpha, true); - } else if (w->m_style.borderStyle == 1 && w->m_pOpaqueBox) { - bbox |= w->m_pOpaqueBox->Draw(spd, clipRect, pAlphaMask, x, y, sw, true, false); - } - } - - p.x += w->m_width; - } - - return bbox; -} - -CRect CLine::PaintBody(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha) -{ - CRect bbox(0, 0, 0, 0); - - POSITION pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - - if (w->m_fLineBreak) { - return bbox; // should not happen since this class is just a line of text without any breaks - } - - int x = p.x; - int y = p.y + m_ascent - w->m_ascent; - // colors - - DWORD aprimary = w->m_style.alpha[0]; - DWORD asecondary = w->m_style.alpha[1]; - if (alpha > 0) { - aprimary += alpha * (0xff - w->m_style.alpha[0]) / 0xff; - asecondary += alpha * (0xff - w->m_style.alpha[1]) / 0xff; - } - COLORREF primary = revcolor(w->m_style.colors[0]) | ((0xff - aprimary) << 24); - COLORREF secondary = revcolor(w->m_style.colors[1]) | ((0xff - asecondary) << 24); - - DWORD sw[6] = {primary, 0, secondary}; - - // karaoke - - double t = 0.0; - - if (w->m_ktype == 0 || w->m_ktype == 2) { - t = time < w->m_kstart ? 0.0 : 1.0; - } else if (w->m_ktype == 1) { - if (time < w->m_kstart) { - t = 0.0; - } else if (time < w->m_kend) { - t = 1.0 * (time - w->m_kstart) / (w->m_kend - w->m_kstart); - - double angle = fmod(w->m_style.fontAngleZ, 360.0); - if (angle > 90 && angle < 270) { - t = 1.0 - t; - COLORREF tmp = sw[0]; - sw[0] = sw[2]; - sw[2] = tmp; - } - } else { - t = 1.0; - } - } - - if (t >= 1.0) { - sw[1] = DWORD_MAX; - } - - // move dividerpoint - int bluradjust = 0; - if (w->m_style.fGaussianBlur > 0) { - bluradjust += (int)(w->m_style.fGaussianBlur * 3 * 8 + 0.5) | 1; - } - if (w->m_style.fBlur) { - bluradjust += 8; - } - - w->Paint(CPoint(x, y), org); - - sw[0] = ColorConvTable::ColorCorrection(sw[0]); - sw[2] = ColorConvTable::ColorCorrection(sw[2]); - sw[3] = (int)(w->m_style.outlineWidthX + t * w->getOverlayWidth() + t * bluradjust) >> 3; - sw[4] = sw[2]; - sw[5] = 0x00ffffff; - - bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw, true, false); - p.x += w->m_width; - } - - return bbox; -} - - -// CSubtitle - -CSubtitle::CSubtitle(RenderingCaches& renderingCaches) - : m_renderingCaches(renderingCaches) - , m_scrAlignment(0) - , m_wrapStyle(0) - , m_fAnimated(false) - , m_bIsAnimated(false) - , m_relativeTo(STSStyle::AUTO) - , m_pClipper(nullptr) - , m_topborder(0) - , m_bottomborder(0) - , m_clipInverse(false) - , m_target_scale_x(1.0) - , m_target_scale_y(1.0) - , m_script_scale_x(1.0) - , m_script_scale_y(1.0) - , m_total_scale_x(1.0) - , m_total_scale_y(1.0) - , m_allowLinePadding(false) -{ - ZeroMemory(m_effects, sizeof(Effect*)*EF_NUMBEROFEFFECTS); -} - -CSubtitle::~CSubtitle() -{ - Empty(); -} - -void CSubtitle::Empty() -{ - POSITION pos = GetHeadPosition(); - while (pos) { - delete GetNext(pos); - } - - pos = m_words.GetHeadPosition(); - while (pos) { - delete m_words.GetNext(pos); - } - - EmptyEffects(); - - m_pClipper.reset(); -} - -void CSubtitle::EmptyEffects() -{ - for (ptrdiff_t i = 0; i < EF_NUMBEROFEFFECTS; i++) { - SAFE_DELETE(m_effects[i]); - } -} - -int CSubtitle::GetFullWidth() -{ - int width = 0; - - POSITION pos = m_words.GetHeadPosition(); - while (pos) { - width += m_words.GetNext(pos)->m_width; - } - - return width; -} - -int CSubtitle::GetFullLineWidth(POSITION pos) -{ - int width = 0; - - while (pos) { - CWord* w = m_words.GetNext(pos); - if (w->m_fLineBreak) { - break; - } - width += w->m_width; - } - - return width; -} - -int CSubtitle::GetWrapWidth(POSITION pos, int maxwidth) -{ - if (m_wrapStyle == 0 || m_wrapStyle == 3) { - if (maxwidth > 0) { - int fullwidth = GetFullLineWidth(pos); - - int minwidth = fullwidth / ((abs(fullwidth) / maxwidth) + 1); - - int width = 0, wordwidth = 0; - - while (pos && width < minwidth) { - CWord* w = m_words.GetNext(pos); - wordwidth = w->m_width; - if (abs(width + wordwidth) < abs(maxwidth)) { - width += wordwidth; - } - } - - if (m_wrapStyle == 3 && width < fullwidth && fullwidth - width + wordwidth < maxwidth) { - width -= wordwidth; - } - maxwidth = width; - } - } else if (m_wrapStyle == 1) { - // maxwidth = maxwidth; - } else if (m_wrapStyle == 2) { - maxwidth = INT_MAX; - } - - return maxwidth; -} - -CLine* CSubtitle::GetNextLine(POSITION& pos, int maxwidth) -{ - if (pos == nullptr) { - return nullptr; - } - - CLine* ret; - try { - ret = DEBUG_NEW CLine(); - } catch (CMemoryException* e) { - e->Delete(); - return nullptr; - } - - ret->m_width = ret->m_ascent = ret->m_descent = ret->m_borderX = ret->m_borderY = ret->m_linePadding = 0; - - maxwidth = GetWrapWidth(pos, maxwidth); - - bool fEmptyLine = true; - - while (pos) { - CWord* w = m_words.GetNext(pos); - - if (ret->m_ascent < w->m_ascent) { - ret->m_ascent = w->m_ascent; - } - if (ret->m_descent < w->m_descent) { - ret->m_descent = w->m_descent; - } - if (ret->m_borderX < w->m_style.outlineWidthX) { - ret->m_borderX = (int)(w->m_style.outlineWidthX + 0.5); - } - if (ret->m_borderY < w->m_style.outlineWidthY) { - ret->m_borderY = (int)(w->m_style.outlineWidthY + 0.5); - } - if (w->m_style.borderStyle == 1 && m_allowLinePadding && (ret->m_linePadding < ret->m_borderY * 2)) { - ret->m_linePadding = ret->m_borderY * 2; - } - - if (w->m_fLineBreak) { - if (fEmptyLine) { - ret->m_ascent /= 2; - ret->m_descent /= 2; - ret->m_borderX = ret->m_borderY = 0; - } - - ret->Compact(); - - return ret; - } - - fEmptyLine = false; - - bool fWSC = w->m_fWhiteSpaceChar; - - int width = w->m_width; - POSITION pos2 = pos; - while (pos2) { - if (m_words.GetAt(pos2)->m_fWhiteSpaceChar != fWSC - || m_words.GetAt(pos2)->m_fLineBreak) { - break; - } - - CWord* w2 = m_words.GetNext(pos2); - width += w2->m_width; - } - - if ((ret->m_width += width) <= maxwidth || ret->IsEmpty()) { - ret->AddTail(w->Copy()); - - while (pos != pos2) { - ret->AddTail(m_words.GetNext(pos)->Copy()); - } - - pos = pos2; - } else { - if (pos) { - m_words.GetPrev(pos); - } else { - pos = m_words.GetTailPosition(); - } - - ret->m_width -= width; - - break; - } - } - - ret->Compact(); - - return ret; -} - -void CSubtitle::CreateClippers(CSize size) -{ - size.cx >>= 3; - size.cy >>= 3; - - auto createClipper = [this](const CSize & size) { - ASSERT(!m_pClipper); - CStringW str; - str.Format(L"m %d %d l %d %d %d %d %d %d", 0, 0, size.cx, 0, size.cx, size.cy, 0, size.cy); - - try { - m_pClipper = std::make_shared(str, size, 1.0, 1.0, false, CPoint(0, 0), m_renderingCaches); - } catch (CMemoryException* e) { - e->Delete(); - } - - return !!m_pClipper; - }; - - if (m_effects[EF_BANNER] && m_effects[EF_BANNER]->param[2]) { - if (!m_pClipper && !createClipper(size)) { - return; - } - m_pClipper->SetEffect(*m_effects[EF_BANNER], EF_BANNER); - } else if (m_effects[EF_SCROLL] && m_effects[EF_SCROLL]->param[4]) { - if (!m_pClipper && !createClipper(size)) { - return; - } - m_pClipper->SetEffect(*m_effects[EF_SCROLL], EF_SCROLL); - } -} - -void CSubtitle::MakeLines(CSize size, const CRect& marginRect) -{ - CSize spaceNeeded(0, 0); - - bool fFirstLine = true; - - m_topborder = m_bottomborder = 0; - - CLine* l = nullptr; - - POSITION pos = m_words.GetHeadPosition(); - while (pos) { - l = GetNextLine(pos, size.cx - marginRect.left - marginRect.right); - if (!l) { - break; - } - - if (fFirstLine) { - m_topborder = l->m_borderY; - l->m_linePadding = 0; - fFirstLine = false; - } - - spaceNeeded.cx = std::max(l->m_width + l->m_borderX, spaceNeeded.cx); - spaceNeeded.cy += l->m_ascent + l->m_descent + l->m_linePadding; - - AddTail(l); - } - - if (l) { - m_bottomborder = l->m_borderY; - } - - m_rect = CRect( - CPoint((m_scrAlignment % 3) == 1 ? marginRect.left - : (m_scrAlignment % 3) == 2 ? (marginRect.left + (size.cx - marginRect.right) - spaceNeeded.cx + 1) / 2 - : (size.cx - marginRect.right - spaceNeeded.cx), - m_scrAlignment <= 3 ? (size.cy - marginRect.bottom - spaceNeeded.cy) - : m_scrAlignment <= 6 ? (marginRect.top + (size.cy - marginRect.bottom) - spaceNeeded.cy + 1) / 2 - : marginRect.top), - spaceNeeded); -} - -// CScreenLayoutAllocator - -void CScreenLayoutAllocator::Empty() -{ - m_subrects.RemoveAll(); -} - -void CScreenLayoutAllocator::AdvanceToSegment(int segment, const CAtlArray& sa) -{ - POSITION pos = m_subrects.GetHeadPosition(); - while (pos) { - POSITION prev = pos; - - SubRect& sr = m_subrects.GetNext(pos); - - bool fFound = false; - - if (abs(sr.segment - segment) <= 1) { // using abs() makes it possible to play the subs backwards, too :) - for (size_t i = 0; i < sa.GetCount() && !fFound; i++) { - if (sa[i] == sr.entry) { - sr.segment = segment; - fFound = true; - } - } - } - - if (!fFound) { - m_subrects.RemoveAt(prev); - } - } -} - -CRect CScreenLayoutAllocator::AllocRect(const CSubtitle* s, int segment, int entry, int layer, int collisions) -{ - // TODO: handle collisions == 1 (reversed collisions) - - POSITION pos = m_subrects.GetHeadPosition(); - while (pos) { - SubRect& sr = m_subrects.GetNext(pos); - if (sr.segment == segment && sr.entry == entry) { - return (sr.r + CRect(0, -s->m_topborder, 0, -s->m_bottomborder)); - } - } - - CRect r = s->m_rect + CRect(0, s->m_topborder, 0, s->m_bottomborder); - - bool fSearchDown = s->m_scrAlignment > 3; - - bool fOK; - - do { - fOK = true; - - pos = m_subrects.GetHeadPosition(); - while (pos) { - SubRect& sr = m_subrects.GetNext(pos); - - if (layer == sr.layer && !(r & sr.r).IsRectEmpty()) { - if (fSearchDown) { - r.bottom = sr.r.bottom + r.Height(); - r.top = sr.r.bottom; - } else { - r.top = sr.r.top - r.Height(); - r.bottom = sr.r.top; - } - - fOK = false; - } - } - } while (!fOK); - - SubRect sr; - sr.r = r; - sr.segment = segment; - sr.entry = entry; - sr.layer = layer; - m_subrects.AddTail(sr); - - return (sr.r + CRect(0, -s->m_topborder, 0, -s->m_bottomborder)); -} - -// CRenderedTextSubtitle - -CAtlMap> CRenderedTextSubtitle::s_SSATagCmds; - -CRenderedTextSubtitle::CRenderedTextSubtitle(CCritSec* pLock) - : CSubPicProviderImpl(pLock) - , m_time(0) - , m_delay(0) - , m_animStart(0) - , m_animEnd(0) - , m_animAccel(0.0) - , m_ktype(0) - , m_kstart(0) - , m_kend(0) - , m_nPolygon(0) - , m_polygonBaselineOffset(0) - , m_bOverridePlacement(false) - , m_overridePlacement(50, 90) - , m_webvtt_allow_clear(false) - , m_bUseFreeType(false) -{ - m_size = CSize(0, 0); - - if (g_hDC_refcnt == 0) { - g_hDC = CreateCompatibleDC(nullptr); - SetBkMode(g_hDC, TRANSPARENT); - SetTextColor(g_hDC, 0xffffff); - SetMapMode(g_hDC, MM_TEXT); - } - - g_hDC_refcnt++; - - if (s_SSATagCmds.IsEmpty()) { - s_SSATagCmds[L"1c"] = SSA_1c; - s_SSATagCmds[L"2c"] = SSA_2c; - s_SSATagCmds[L"3c"] = SSA_3c; - s_SSATagCmds[L"4c"] = SSA_4c; - s_SSATagCmds[L"1a"] = SSA_1a; - s_SSATagCmds[L"2a"] = SSA_2a; - s_SSATagCmds[L"3a"] = SSA_3a; - s_SSATagCmds[L"4a"] = SSA_4a; - s_SSATagCmds[L"alpha"] = SSA_alpha; - s_SSATagCmds[L"an"] = SSA_an; - s_SSATagCmds[L"a"] = SSA_a; - s_SSATagCmds[L"blur"] = SSA_blur; - s_SSATagCmds[L"bord"] = SSA_bord; - s_SSATagCmds[L"be"] = SSA_be; - s_SSATagCmds[L"b"] = SSA_b; - s_SSATagCmds[L"clip"] = SSA_clip; - s_SSATagCmds[L"iclip"] = SSA_iclip; - s_SSATagCmds[L"c"] = SSA_c; - s_SSATagCmds[L"fade"] = SSA_fade; - s_SSATagCmds[L"fad"] = SSA_fade; - s_SSATagCmds[L"fax"] = SSA_fax; - s_SSATagCmds[L"fay"] = SSA_fay; - s_SSATagCmds[L"fe"] = SSA_fe; - s_SSATagCmds[L"fn"] = SSA_fn; - s_SSATagCmds[L"frx"] = SSA_frx; - s_SSATagCmds[L"fry"] = SSA_fry; - s_SSATagCmds[L"frz"] = SSA_frz; - s_SSATagCmds[L"fr"] = SSA_fr; - s_SSATagCmds[L"fscx"] = SSA_fscx; - s_SSATagCmds[L"fscy"] = SSA_fscy; - s_SSATagCmds[L"fsc"] = SSA_fsc; - s_SSATagCmds[L"fsp"] = SSA_fsp; - s_SSATagCmds[L"fs"] = SSA_fs; - s_SSATagCmds[L"i"] = SSA_i; - s_SSATagCmds[L"kt"] = SSA_kt; - s_SSATagCmds[L"kf"] = SSA_kf; - s_SSATagCmds[L"K"] = SSA_K; - s_SSATagCmds[L"ko"] = SSA_ko; - s_SSATagCmds[L"k"] = SSA_k; - s_SSATagCmds[L"move"] = SSA_move; - s_SSATagCmds[L"org"] = SSA_org; - s_SSATagCmds[L"pbo"] = SSA_pbo; - s_SSATagCmds[L"pos"] = SSA_pos; - s_SSATagCmds[L"p"] = SSA_p; - s_SSATagCmds[L"q"] = SSA_q; - s_SSATagCmds[L"r"] = SSA_r; - s_SSATagCmds[L"shad"] = SSA_shad; - s_SSATagCmds[L"s"] = SSA_s; - s_SSATagCmds[L"t"] = SSA_t; - s_SSATagCmds[L"u"] = SSA_u; - s_SSATagCmds[L"xbord"] = SSA_xbord; - s_SSATagCmds[L"xshad"] = SSA_xshad; - s_SSATagCmds[L"ybord"] = SSA_ybord; - s_SSATagCmds[L"yshad"] = SSA_yshad; - } -} - -CRenderedTextSubtitle::~CRenderedTextSubtitle() -{ - Deinit(); - - g_hDC_refcnt--; - if (g_hDC_refcnt == 0) { - DeleteDC(g_hDC); - } -} - -void CRenderedTextSubtitle::Copy(CSimpleTextSubtitle& sts) -{ - __super::Copy(sts); - - m_size = CSize(0, 0); - - if (CRenderedTextSubtitle* pRTS = dynamic_cast(&sts)) { - m_size = pRTS->m_size; - } -} - -void CRenderedTextSubtitle::Empty() -{ - Deinit(); - - __super::Empty(); -} - -void CRenderedTextSubtitle::SetOverride(bool bOverrideDefault, bool bOverrideAll, const STSStyle& styleOverride) { - overrideANSICharset = styleOverride.charSet; - bool bOverride = bOverrideDefault || bOverrideAll; - bool changed = (bOverride && !m_bStyleOverrideActive) || (m_SubRendererSettings.overrideDefaultStyle != bOverrideDefault) || (m_SubRendererSettings.overrideAllStyles != bOverrideAll) || bOverride && (m_SubRendererSettings.defaultStyle != styleOverride); - - if (changed) { - m_bStyleOverrideActive = bOverride; - m_SubRendererSettings.defaultStyle = bOverride ? styleOverride : GetOriginalDefaultStyle(); - m_SubRendererSettings.overrideDefaultStyle = bOverride; - m_SubRendererSettings.overrideAllStyles = bOverrideAll; - - UpdateSubRelativeTo(m_subtitleType, m_SubRendererSettings.defaultStyle.relativeTo); - - if (bOverride) { - m_scaledBAS = 0; - } - - if (bOverride && m_playRes.cy != 288 && m_playRes.cx > 0 && m_playRes.cy > 0) { - /* Default style is defined relative to a 384x288 PlayRes resolution. Scale to get consistent font size. */ - double scaleX = m_playRes.cx / 384.0; - double scaleY = m_playRes.cy / 288.0; - m_SubRendererSettings.defaultStyle.fontSize *= scaleY; - m_SubRendererSettings.defaultStyle.fontSpacing *= scaleX; - m_SubRendererSettings.defaultStyle.marginRect.left = std::lround(scaleX * m_SubRendererSettings.defaultStyle.marginRect.left); - m_SubRendererSettings.defaultStyle.marginRect.top = std::lround(scaleY * m_SubRendererSettings.defaultStyle.marginRect.top); - m_SubRendererSettings.defaultStyle.marginRect.right = std::lround(scaleX * m_SubRendererSettings.defaultStyle.marginRect.right); - m_SubRendererSettings.defaultStyle.marginRect.bottom = std::lround(scaleY * m_SubRendererSettings.defaultStyle.marginRect.bottom); - } - - SetDefaultStyle(m_SubRendererSettings.defaultStyle); - -#if USE_LIBASS - if (m_LibassContext.IsLibassActive()) { - m_LibassContext.StylesChanged(); - } -#endif - } -} - -void CRenderedTextSubtitle::OnChanged() -{ - __super::OnChanged(); - CAutoLock cAutoLock(&renderLock); - - POSITION pos = m_subtitleCache.GetStartPosition(); - while (pos) { - int i; - CSubtitle* s; - m_subtitleCache.GetNextAssoc(pos, i, s); - delete s; - } - - m_subtitleCache.RemoveAll(); - - m_sla.Empty(); -} - -bool CRenderedTextSubtitle::Init(CSize size, const CRect& vidrect) -{ - if (!vidrect.Width()) { - return false; - } - - CAutoLock cAutoLock(&renderLock); - CRect newVidRect = CRect(vidrect.left * 8, vidrect.top * 8, vidrect.right * 8, vidrect.bottom * 8); - CSize newSize = CSize(size.cx * 8, size.cy * 8); - if (m_size != newSize || m_vidrect != newVidRect) { - TRACE(_T("RTS Init | texture %dx%d | vidrect %dx%d\n"), size.cx, size.cy, vidrect.Width(), vidrect.Height()); - Deinit(); - m_size = newSize; - m_vidrect = newVidRect; - } - - return true; -} - -void CRenderedTextSubtitle::Deinit() -{ - CAutoLock cAutoLock(&renderLock); - POSITION pos = m_subtitleCache.GetStartPosition(); - while (pos) { - int i; - CSubtitle* s; - m_subtitleCache.GetNextAssoc(pos, i, s); - delete s; - } - m_subtitleCache.RemoveAll(); - - m_sla.Empty(); - - m_size = CSize(0, 0); - m_vidrect.SetRectEmpty(); -} - -void CRenderedTextSubtitle::ParseEffect(CSubtitle* sub, CString str) -{ - str.Trim(); - if (!sub || str.IsEmpty()) { - return; - } - - const TCHAR* s = _tcschr(str, ';'); - if (!s) { - s = (LPTSTR)(LPCTSTR)str; - s += str.GetLength() - 1; - } - s++; - CString effect = str.Left(int(s - str)); - - if (!effect.CompareNoCase(_T("Banner;"))) { - sub->m_bIsAnimated = true; - - int delay, lefttoright = 0, fadeawaywidth = 0; - if (_stscanf_s(s, _T("%d;%d;%d"), &delay, &lefttoright, &fadeawaywidth) < 1) { - return; - } - - Effect* e; - try { - e = DEBUG_NEW Effect; - } catch (CMemoryException* e) { - e->Delete(); - return; - } - - sub->m_effects[e->type = EF_BANNER] = e; - e->param[0] = (int)(std::max(1.0 * delay / sub->m_total_scale_x, 1.0)); - e->param[1] = lefttoright; - e->param[2] = std::lround(sub->m_total_scale_x * fadeawaywidth); - - sub->m_wrapStyle = 2; - } else if (!effect.CompareNoCase(_T("Scroll up;")) || !effect.CompareNoCase(_T("Scroll down;"))) { - sub->m_bIsAnimated = true; - - int top, bottom, delay, fadeawayheight = 0; - if (_stscanf_s(s, _T("%d;%d;%d;%d"), &top, &bottom, &delay, &fadeawayheight) < 3) { - return; - } - - if (top > bottom) { - int tmp = top; - top = bottom; - bottom = tmp; - } - - Effect* e; - try { - e = DEBUG_NEW Effect; - } catch (CMemoryException* e) { - e->Delete(); - return; - } - - sub->m_effects[e->type = EF_SCROLL] = e; - e->param[0] = std::lround(sub->m_total_scale_y * top * 8.0); - e->param[1] = std::lround(sub->m_total_scale_y * bottom * 8.0); - e->param[2] = (int)(std::max(double(delay) / sub->m_total_scale_y, 1.0)); - e->param[3] = (effect.GetLength() == 12); - e->param[4] = std::lround(sub->m_total_scale_y * fadeawayheight); - } -} - -void CRenderedTextSubtitle::ParseString(CSubtitle* sub, CStringW str, STSStyle& style) -{ - if (!sub) { - return; - } - - if (str.GetLength() == 1) { - if (str[0] == L'\x202a' || str[0] == L'\x202b') { - return; // ignore Unicode control character - } - } - - str.Replace(L"
", L"\n"); - str.Replace(L"\\N", L"\n"); - str.Replace(L"\\n", (sub->m_wrapStyle < 2 || sub->m_wrapStyle == 3) ? L" " : L"\n"); - str.Replace(L"\\h", L"\x00A0"); // no-break space - - for (int i = 0, j = 0, len = str.GetLength(); j <= len; j++) { - WCHAR c = str[j]; - - if (c != L'\n' && c != L' ' && c != 0) { - continue; - } - - if (i < j) { - if (CText* w = DEBUG_NEW CText(style, str.Mid(i, j - i), m_ktype, m_kstart, m_kend, sub->m_target_scale_x, sub->m_target_scale_y, m_renderingCaches)) { - w->SetRts(this); - sub->m_words.AddTail(w); - m_kstart = m_kend; - } - } - - if (c == L'\n') { - if (CText* w = DEBUG_NEW CText(style, CStringW(), m_ktype, m_kstart, m_kend, sub->m_target_scale_x, sub->m_target_scale_y, m_renderingCaches)) { - w->SetRts(this); - sub->m_words.AddTail(w); - m_kstart = m_kend; - } - } else if (c == L' ') { - if (CText* w = DEBUG_NEW CText(style, CStringW(c), m_ktype, m_kstart, m_kend, sub->m_target_scale_x, sub->m_target_scale_y, m_renderingCaches)) { - w->SetRts(this); - sub->m_words.AddTail(w); - m_kstart = m_kend; - } - } - - i = j + 1; - } - - return; -} - -void CRenderedTextSubtitle::ParsePolygon(CSubtitle* sub, CStringW str, STSStyle& style) -{ - if (!sub || !str.GetLength() || !m_nPolygon) { - return; - } - - int s = 1 << (m_nPolygon - 1); - if (CWord* w = DEBUG_NEW CPolygon(style, str, m_ktype, m_kstart, m_kend, - sub->m_total_scale_x / s, sub->m_total_scale_y / s, - m_polygonBaselineOffset, - m_renderingCaches)) { - sub->m_words.AddTail(w); - m_kstart = m_kend; - } -} - -bool CRenderedTextSubtitle::ParseSSATag(SSATagsList& tagsList, const CStringW& str) -{ - if (m_renderingCaches.SSATagsCache.Lookup(str, tagsList)) { - //TRACE(_T("ParseSSATag (cached): %s\n"), str.GetString()); - return true; - } - //TRACE(_T("ParseSSATag: %s\n"), str.GetString()); - - int nTags = 0, nUnrecognizedTags = 0; - tagsList.reset(DEBUG_NEW CAtlList()); - - for (int i = 0, j; (j = str.Find(L'\\', i)) >= 0; i = j) { - int jOld; - // find the end of the current tag or the start of its parameters - for (jOld = ++j; str[j] && str[j] != L'(' && str[j] != L'\\'; ++j) { - ; - } - CStringW cmd = str.Mid(jOld, j - jOld); - FastTrim(cmd); - if (cmd.IsEmpty()) { - continue; - } - - nTags++; - - SSATag tag; - tag.cmd = SSA_unknown; - for (int cmdLength = std::min(SSA_CMD_MAX_LENGTH, cmd.GetLength()), cmdLengthMin = SSA_CMD_MIN_LENGTH; cmdLength >= cmdLengthMin; cmdLength--) { - if (s_SSATagCmds.Lookup(cmd.Left(cmdLength), tag.cmd)) { - break; - } - } - if (tag.cmd == SSA_unknown) { - nUnrecognizedTags++; - continue; - } - - if (str[j] == L'(') { - // complex tags search - int br = 1; // 1 bracket - // find the end of the parameters - for (jOld = ++j; str[j] && br > 0; ++j) { - if (str[j] == L'(') { - br++; - } else if (str[j] == L')') { - br--; - } - if (br == 0) { - break; - } - } - CStringW param = str.Mid(jOld, j - jOld); - FastTrim(param); - - while (!param.IsEmpty()) { - int k = param.Find(L','), l = param.Find(L'\\'); - - if (k >= 0 && (l < 0 || k < l)) { - CStringW s = param.Left(k).Trim(); - if (!s.IsEmpty()) { - tag.params.Add(s); - } - param = k + 1 < param.GetLength() ? param.Mid(k + 1).GetString() : L""; - } else { - FastTrim(param); - if (!param.IsEmpty()) { - tag.params.Add(param); - } - param.Empty(); - } - } - } - - switch (tag.cmd) { - case SSA_1c: - case SSA_2c: - case SSA_3c: - case SSA_4c: - case SSA_1a: - case SSA_2a: - case SSA_3a: - case SSA_4a: - if (cmd.GetLength() > 2) { - tag.paramsInt.Add(wcstol(cmd.Mid(2).Trim(L"&H"), nullptr, 16)); - } - break; - case SSA_alpha: - if (cmd.GetLength() > 5) { - tag.paramsInt.Add(wcstol(cmd.Mid(5).Trim(L"&H"), nullptr, 16)); - } - break; - case SSA_an: - case SSA_be: - case SSA_fe: - case SSA_kt: - case SSA_kf: - case SSA_ko: - if (cmd.GetLength() > 2) { - tag.paramsInt.Add(wcstol(cmd.Mid(2), nullptr, 10)); - } - break; - case SSA_fn: - tag.params.Add(cmd.Mid(2)); - break; - case SSA_fr: - if (cmd.GetLength() > 2) { - tag.paramsReal.Add(wcstod(cmd.Mid(2), nullptr)); - } - break; - case SSA_fs: - if (cmd.GetLength() > 2) { - int s = 2; - if (cmd[s] == L'+' || cmd[s] == L'-') { - tag.params.Add(cmd.Mid(s, 1)); - } - tag.paramsInt.Add(wcstol(cmd.Mid(s), nullptr, 10)); - } - break; - case SSA_a: - case SSA_b: - case SSA_i: - case SSA_k: - case SSA_K: - case SSA_p: - case SSA_q: - case SSA_s: - case SSA_u: - if (cmd.GetLength() > 1) { - tag.paramsInt.Add(wcstol(cmd.Mid(1), nullptr, 10)); - } - break; - case SSA_r: - tag.params.Add(cmd.Mid(1)); - break; - case SSA_blur: - case SSA_bord: - case SSA_fscx: - case SSA_fscy: - case SSA_shad: - if (cmd.GetLength() > 4) { - tag.paramsReal.Add(wcstod(cmd.Mid(4), nullptr)); - } - break; - case SSA_clip: - case SSA_iclip: { - size_t nParams = tag.params.GetCount(); - if (nParams == 2) { - tag.paramsInt.Add(wcstol(tag.params[0], nullptr, 10)); - tag.params.RemoveAt(0); - } else if (nParams == 4) { - for (size_t n = 0; n < nParams; n++) { - tag.paramsInt.Add(wcstol(tag.params[n], nullptr, 10)); - } - tag.params.RemoveAll(); - } - } - break; - case SSA_fade: { - size_t nParams = tag.params.GetCount(); - if (nParams == 7 || nParams == 2) { - for (size_t n = 0; n < nParams; n++) { - tag.paramsInt.Add(wcstol(tag.params[n], nullptr, 10)); - } - tag.params.RemoveAll(); - } - } - break; - case SSA_move: { - size_t nParams = tag.params.GetCount(); - if (nParams == 4 || nParams == 6) { - for (size_t n = 0; n < 4; n++) { - tag.paramsReal.Add(wcstod(tag.params[n], nullptr)); - } - for (size_t n = 4; n < nParams; n++) { - tag.paramsInt.Add(wcstol(tag.params[n], nullptr, 10)); - } - tag.params.RemoveAll(); - } - } - break; - case SSA_org: - case SSA_pos: { - size_t nParams = tag.params.GetCount(); - if (nParams == 2) { - for (size_t n = 0; n < nParams; n++) { - tag.paramsReal.Add(wcstod(tag.params[n], nullptr)); - } - tag.params.RemoveAll(); - } - } - break; - case SSA_c: - if (cmd.GetLength() > 1) { - tag.paramsInt.Add(wcstol(cmd.Mid(1).Trim(L"&H"), nullptr, 16)); - } - break; - case SSA_frx: - case SSA_fry: - case SSA_frz: - case SSA_fax: - case SSA_fay: - case SSA_fsc: - case SSA_fsp: - if (cmd.GetLength() > 3) { - tag.paramsReal.Add(wcstod(cmd.Mid(3), nullptr)); - } - break; - case SSA_pbo: - if (cmd.GetLength() > 3) { - tag.paramsInt.Add(wcstol(cmd.Mid(3), nullptr, 10)); - } - break; - case SSA_t: { - size_t nParams = tag.params.GetCount(); - if (nParams >= 1 && nParams <= 4) { - if (nParams == 2) { - tag.paramsReal.Add(wcstod(tag.params[0], nullptr)); - } else if (nParams == 3) { - tag.paramsReal.Add(wcstod(tag.params[0], nullptr)); - tag.paramsReal.Add(wcstod(tag.params[1], nullptr)); - } else if (nParams == 4) { - tag.paramsInt.Add(wcstol(tag.params[0], nullptr, 10)); - tag.paramsInt.Add(wcstol(tag.params[1], nullptr, 10)); - tag.paramsReal.Add(wcstod(tag.params[2], nullptr)); - } - - ParseSSATag(tag.subTagsList, tag.params[nParams - 1]); - } - tag.params.RemoveAll(); - } - break; - case SSA_xbord: - case SSA_xshad: - case SSA_ybord: - case SSA_yshad: - if (cmd.GetLength() > 5) { - tag.paramsReal.Add(wcstod(cmd.Mid(5), nullptr)); - } - break; - } - - tagsList->AddTail(tag); - } - - m_renderingCaches.SSATagsCache.SetAt(str, tagsList); - - //return (nUnrecognizedTags < nTags); - return true; // there are people keeping comments inside {}, lets make them happy now -} - -bool CRenderedTextSubtitle::CreateSubFromSSATag(CSubtitle* sub, const SSATagsList& tagsList, - STSStyle& style, STSStyle& org, bool fAnimate /*= false*/) -{ - if (!sub || !tagsList) { - return false; - } - - POSITION pos = tagsList->GetHeadPosition(); - while (pos) { - const SSATag& tag = tagsList->GetNext(pos); - - // TODO: call ParseStyleModifier(cmd, params, ..) and move the rest there - - switch (tag.cmd) { - case SSA_1c: - case SSA_2c: - case SSA_3c: - case SSA_4c: { - int k = tag.cmd - SSA_1c; - - if (!tag.paramsInt.IsEmpty()) { - DWORD c = tag.paramsInt[0]; - style.colors[k] = (((int)CalcAnimation(c & 0xff, style.colors[k] & 0xff, fAnimate)) & 0xff - | ((int)CalcAnimation(c & 0xff00, style.colors[k] & 0xff00, fAnimate)) & 0xff00 - | ((int)CalcAnimation(c & 0xff0000, style.colors[k] & 0xff0000, fAnimate)) & 0xff0000); - } else { - style.colors[k] = org.colors[k]; - } - } - break; - case SSA_1a: - case SSA_2a: - case SSA_3a: - case SSA_4a: { - int k = tag.cmd - SSA_1a; - - style.alpha[k] = !tag.paramsInt.IsEmpty() - ? (BYTE)CalcAnimation(tag.paramsInt[0] & 0xff, style.alpha[k], fAnimate) - : org.alpha[k]; - } - break; - case SSA_alpha: - for (ptrdiff_t k = 0; k < 4; k++) { - style.alpha[k] = !tag.paramsInt.IsEmpty() - ? (BYTE)CalcAnimation(tag.paramsInt[0] & 0xff, style.alpha[k], fAnimate) - : org.alpha[k]; - } - break; - case SSA_an: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : 0; - if (sub->m_scrAlignment < 0) { - sub->m_scrAlignment = (n > 0 && n < 10) ? n : org.scrAlignment; - } - } - break; - case SSA_a: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : 0; - if (sub->m_scrAlignment < 0) { - sub->m_scrAlignment = (n > 0 && n < 12) ? ((((n - 1) & 3) + 1) + ((n & 4) ? 6 : 0) + ((n & 8) ? 3 : 0)) : org.scrAlignment; - } - } - break; - case SSA_blur: - if (!tag.paramsReal.IsEmpty()) { - double n = CalcAnimation(tag.paramsReal[0], style.fGaussianBlur, fAnimate); - style.fGaussianBlur = (n < 0 ? 0 : n); - } else { - style.fGaussianBlur = org.fGaussianBlur; - } - if (style.fGaussianBlur > 25.0) { - style.fGaussianBlur = 25.0; - TRACE(L"INSANE blur value !!!\n"); - } - break; - case SSA_bord: - if (!tag.paramsReal.IsEmpty()) { - double nx = CalcAnimation(tag.paramsReal[0], style.outlineWidthX, fAnimate); - style.outlineWidthX = (nx < 0 ? 0 : nx); - double ny = CalcAnimation(tag.paramsReal[0], style.outlineWidthY, fAnimate); - style.outlineWidthY = (ny < 0 ? 0 : ny); - } else { - style.outlineWidthX = org.outlineWidthX; - style.outlineWidthY = org.outlineWidthY; - } - break; - case SSA_be: - style.fBlur = !tag.paramsInt.IsEmpty() - ? (int)(CalcAnimation(tag.paramsInt[0], style.fBlur, fAnimate) + 0.5) - : org.fBlur; - break; - case SSA_b: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : -1; - style.fontWeight = (n == 0 ? FW_NORMAL : n == 1 ? FW_BOLD : n >= 100 ? n : org.fontWeight); - } - break; - case SSA_clip: - case SSA_iclip: { - bool invert = (tag.cmd == SSA_iclip); - size_t nParams = tag.params.GetCount(); - size_t nParamsInt = tag.paramsInt.GetCount(); - - if (nParams == 1 && nParamsInt == 0 && !sub->m_pClipper) { - sub->m_pClipper = std::make_shared(tag.params[0], CSize(m_size.cx >> 3, m_size.cy >> 3), sub->m_total_scale_x, sub->m_total_scale_y, - invert, (sub->m_relativeTo == STSStyle::VIDEO) ? CPoint(m_vidrect.left, m_vidrect.top) : CPoint(0, 0), - m_renderingCaches); - } else if (nParams == 1 && nParamsInt == 1 && !sub->m_pClipper) { - long scale = tag.paramsInt[0]; - if (scale < 1) { - scale = 1; - } - long scalediv = (1 << (scale - 1)); - sub->m_pClipper = std::make_shared(tag.params[0], CSize(m_size.cx >> 3, m_size.cy >> 3), - sub->m_total_scale_x / scalediv, sub->m_total_scale_y / scalediv, invert, - (sub->m_relativeTo == STSStyle::VIDEO) ? CPoint(m_vidrect.left, m_vidrect.top) : CPoint(0, 0), - m_renderingCaches); - } else if (nParamsInt == 4) { - sub->m_clipInverse = invert; - - double dLeft = sub->m_total_scale_x * tag.paramsInt[0]; - double dTop = sub->m_total_scale_y * tag.paramsInt[1]; - double dRight = sub->m_total_scale_x * tag.paramsInt[2]; - double dBottom = sub->m_total_scale_y * tag.paramsInt[3]; - - if (sub->m_relativeTo == STSStyle::VIDEO) { - double dOffsetX = m_vidrect.left / 8.0; - double dOffsetY = m_vidrect.top / 8.0; - dLeft += dOffsetX; - dTop += dOffsetY; - dRight += dOffsetX; - dBottom += dOffsetY; - } - - sub->m_clip.SetRect( - static_cast(CalcAnimation(dLeft, sub->m_clip.left, fAnimate)), - static_cast(CalcAnimation(dTop, sub->m_clip.top, fAnimate)), - static_cast(CalcAnimation(dRight, sub->m_clip.right, fAnimate)), - static_cast(CalcAnimation(dBottom, sub->m_clip.bottom, fAnimate))); - } - } - break; - case SSA_c: - if (!tag.paramsInt.IsEmpty()) { - DWORD c = tag.paramsInt[0]; - style.colors[0] = (((int)CalcAnimation(c & 0xff, style.colors[0] & 0xff, fAnimate)) & 0xff - | ((int)CalcAnimation(c & 0xff00, style.colors[0] & 0xff00, fAnimate)) & 0xff00 - | ((int)CalcAnimation(c & 0xff0000, style.colors[0] & 0xff0000, fAnimate)) & 0xff0000); - } else { - style.colors[0] = org.colors[0]; - } - break; - case SSA_fade: { - sub->m_bIsAnimated = true; - - if (tag.paramsInt.GetCount() == 7 && !sub->m_effects[EF_FADE]) { // {\fade(a1=param[0], a2=param[1], a3=param[2], t1=t[0], t2=t[1], t3=t[2], t4=t[3]) - if (Effect* e = DEBUG_NEW Effect) { - for (size_t k = 0; k < 3; k++) { - e->param[k] = tag.paramsInt[k]; - } - for (size_t k = 0; k < 4; k++) { - e->t[k] = tag.paramsInt[3 + k]; - } - - sub->m_effects[EF_FADE] = e; - } - } else if (tag.paramsInt.GetCount() == 2 && !sub->m_effects[EF_FADE]) { // {\fad(t1=t[1], t2=t[2]) - if (Effect* e = DEBUG_NEW Effect) { - e->param[0] = e->param[2] = 0xff; - e->param[1] = 0x00; - for (size_t k = 1; k < 3; k++) { - e->t[k] = tag.paramsInt[k - 1]; - } - e->t[0] = e->t[3] = -1; // will be substituted with "start" and "end" - - sub->m_effects[EF_FADE] = e; - } - } - } - break; - case SSA_fax: - style.fontShiftX = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontShiftX, fAnimate) - : org.fontShiftX; - break; - case SSA_fay: - style.fontShiftY = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontShiftY, fAnimate) - : org.fontShiftY; - break; - case SSA_fe: - style.charSet = !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] - : org.charSet; - break; - case SSA_fn: - style.fontName = (!tag.params.IsEmpty() && !tag.params[0].IsEmpty() && tag.params[0] != L"0") - ? CString(tag.params[0]).Trim() - : org.fontName; - if (style.fontName == _T("splatter")) { - /* workaround for slow rendering with this font - slowness occurs in Windows GDI CloseFigure() function - */ - style.fontName = _T("Arial"); - } - break; - case SSA_frx: - style.fontAngleX = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontAngleX, fAnimate) - : org.fontAngleX; - break; - case SSA_fry: - style.fontAngleY = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontAngleY, fAnimate) - : org.fontAngleY; - break; - case SSA_frz: - case SSA_fr: - style.fontAngleZ = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontAngleZ, fAnimate) - : org.fontAngleZ; - break; - case SSA_fscx: - if (!tag.paramsReal.IsEmpty()) { - double n = CalcAnimation(tag.paramsReal[0], style.fontScaleX, fAnimate); - style.fontScaleX = (n < 0 ? 0 : n); - } else { - style.fontScaleX = org.fontScaleX; - } - break; - case SSA_fscy: - if (!tag.paramsReal.IsEmpty()) { - double n = CalcAnimation(tag.paramsReal[0], style.fontScaleY, fAnimate); - style.fontScaleY = (n < 0 ? 0 : n); - } else { - style.fontScaleY = org.fontScaleY; - } - break; - case SSA_fsc: - style.fontScaleX = org.fontScaleX; - style.fontScaleY = org.fontScaleY; - break; - case SSA_fsp: - style.fontSpacing = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontSpacing, fAnimate) - : org.fontSpacing; - break; - case SSA_fs: - if (!tag.paramsInt.IsEmpty()) { - if (!tag.params.IsEmpty() && (tag.params[0][0] == L'-' || tag.params[0][0] == L'+')) { - double n = CalcAnimation(style.fontSize + style.fontSize * tag.paramsInt[0] / 10, style.fontSize, fAnimate); - style.fontSize = (n > 0) ? n : org.fontSize; - } else { - double n = CalcAnimation(tag.paramsInt[0], style.fontSize, fAnimate); - style.fontSize = (n > 0) ? n : org.fontSize; - } - } else { - style.fontSize = org.fontSize; - } - break; - case SSA_i: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : -1; - style.fItalic = (n == 0 ? false : n == 1 ? true : org.fItalic); - } - break; - case SSA_kt: - sub->m_bIsAnimated = true; - - m_kstart = !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] * 10 - : 0; - m_kend = m_kstart; - break; - case SSA_kf: - case SSA_K: - sub->m_bIsAnimated = true; - - m_ktype = 1; - m_kstart = m_kend; - m_kend += !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] * 10 - : 1000; - break; - case SSA_ko: - sub->m_bIsAnimated = true; - - m_ktype = 2; - m_kstart = m_kend; - m_kend += !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] * 10 - : 1000; - break; - case SSA_k: - sub->m_bIsAnimated = true; - - m_ktype = 0; - m_kstart = m_kend; - m_kend += !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] * 10 - : 1000; - break; - case SSA_move: // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3][, t1=t[0], t2=t[1]])} - sub->m_bIsAnimated = true; - - if (tag.paramsReal.GetCount() == 4 && !sub->m_effects[EF_MOVE]) { - if (Effect* e = DEBUG_NEW Effect) { - e->param[0] = std::lround(sub->m_total_scale_x * tag.paramsReal[0] * 8.0); - e->param[1] = std::lround(sub->m_total_scale_y * tag.paramsReal[1] * 8.0); - e->param[2] = std::lround(sub->m_total_scale_x * tag.paramsReal[2] * 8.0); - e->param[3] = std::lround(sub->m_total_scale_y * tag.paramsReal[3] * 8.0); - e->t[0] = e->t[1] = -1; - - if (tag.paramsInt.GetCount() == 2) { - for (size_t k = 0; k < 2; k++) { - e->t[k] = tag.paramsInt[k]; - } - } - - sub->m_effects[EF_MOVE] = e; - } - } - break; - case SSA_org: // {\org(x=param[0], y=param[1])} - if (tag.paramsReal.GetCount() == 2 && !sub->m_effects[EF_ORG]) { - if (Effect* e = DEBUG_NEW Effect) { - e->param[0] = std::lround(sub->m_total_scale_x * tag.paramsReal[0] * 8.0); - e->param[1] = std::lround(sub->m_total_scale_y * tag.paramsReal[1] * 8.0); - - if (sub->m_relativeTo == STSStyle::VIDEO) { - e->param[0] += m_vidrect.left; - e->param[1] += m_vidrect.top; - } - - sub->m_effects[EF_ORG] = e; - } - } - break; - case SSA_pbo: - m_polygonBaselineOffset = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : 0; - break; - case SSA_pos: - if (tag.paramsReal.GetCount() == 2 && !sub->m_effects[EF_MOVE]) { - if (Effect* e = DEBUG_NEW Effect) { - e->param[0] = e->param[2] = std::lround(sub->m_total_scale_x * tag.paramsReal[0] * 8.0); - e->param[1] = e->param[3] = std::lround(sub->m_total_scale_y * tag.paramsReal[1] * 8.0); - e->t[0] = e->t[1] = 0; - - sub->m_effects[EF_MOVE] = e; - } - } - break; - case SSA_p: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : 0; - m_nPolygon = (n <= 0 ? 0 : n); - } - break; - case SSA_q: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : -1; - sub->m_wrapStyle = (0 <= n && n <= 3) - ? n - : m_defaultWrapStyle; - } - break; - case SSA_r: - if (tag.params[0].IsEmpty() || !GetStyle(tag.params[0], style)) { - style = org; - } - break; - case SSA_shad: - if (!tag.paramsReal.IsEmpty()) { - double nx = CalcAnimation(tag.paramsReal[0], style.shadowDepthX, fAnimate); - style.shadowDepthX = (nx < 0 ? 0 : nx); - double ny = CalcAnimation(tag.paramsReal[0], style.shadowDepthY, fAnimate); - style.shadowDepthY = (ny < 0 ? 0 : ny); - } else { - style.shadowDepthX = org.shadowDepthX; - style.shadowDepthY = org.shadowDepthY; - } - break; - case SSA_s: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : -1; - style.fStrikeOut = (n == 0 ? false : n == 1 ? true : org.fStrikeOut); - } - break; - case SSA_t: // \t([,,][,]\n"); - str += _T("\n"); - str += _T("\n"); - str += _T("\n"); - - f.WriteString(str); - } else if (type == Subtitle::SSA || type == Subtitle::ASS) { - CString str; - - str = _T("[Script Info]\n"); - str += _T("; Note: This file was saved by MPC-HC.\n"); - str += (type == Subtitle::SSA) ? _T("ScriptType: v4.00\n") : _T("ScriptType: v4.00+\n"); - str += (m_collisions == 0) ? _T("Collisions: Normal\n") : _T("Collisions: Reverse\n"); - if (type == Subtitle::ASS && m_scaledBAS >= 0) { - if (m_scaledBAS == 1) { - str += _T("ScaledBorderAndShadow: yes\n"); - } else { - str += _T("ScaledBorderAndShadow: no\n"); - } - } - if (m_sYCbCrMatrix.IsEmpty()) { - str += _T("YCbCr Matrix: None\n"); - } else { - str += _T("YCbCr Matrix: ") + m_sYCbCrMatrix + _T("\n"); - } - str.AppendFormat(_T("PlayResX: %d\n"), m_playRes.cx); - str.AppendFormat(_T("PlayResY: %d\n"), m_playRes.cy); - if (m_layoutRes.cx > 0 && m_layoutRes.cy > 0) { - str.AppendFormat(_T("LayoutResX: %d\n"), m_layoutRes.cx); - str.AppendFormat(_T("LayoutResY: %d\n"), m_layoutRes.cy); - } - str += _T("Timer: 100.0000\n"); - str += _T("\n"); - str += (type == Subtitle::SSA) - ? _T("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n") - : _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"); - - f.WriteString(str); - - str = (type == Subtitle::SSA) - ? _T("Style: %s,%s,%d,&H%06x,&H%06x,&H%06x,&H%06x,%d,%d,%d,%.2f,%.2f,%d,%d,%d,%d,%d,%d\n") - : _T("Style: %s,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f,%d,%d,%d,%d,%d\n"); - - POSITION pos = m_styles.GetStartPosition(); - while (pos) { - CString key; - STSStyle* s; - m_styles.GetNextAssoc(pos, key, s); - - if (type == Subtitle::SSA) { - CString str2; - str2.Format(str, key.GetString(), - s->fontName.GetString(), (int)s->fontSize, - s->colors[0] & 0xffffff, - s->colors[1] & 0xffffff, - s->colors[2] & 0xffffff, - s->colors[3] & 0xffffff, - s->fontWeight > FW_NORMAL ? -1 : 0, s->fItalic ? -1 : 0, - s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, - s->outlineWidthY, s->shadowDepthY, - s->scrAlignment <= 3 ? s->scrAlignment : s->scrAlignment <= 6 ? ((s->scrAlignment - 3) | 8) : s->scrAlignment <= 9 ? ((s->scrAlignment - 6) | 4) : 2, - s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2, - s->alpha[0], - s->charSet); - f.WriteString(str2); - } else { - CString str2; - str2.Format(str, key.GetString(), - s->fontName.GetString(), (int)s->fontSize, - (s->colors[0] & 0xffffff) | (s->alpha[0] << 24), - (s->colors[1] & 0xffffff) | (s->alpha[1] << 24), - (s->colors[2] & 0xffffff) | (s->alpha[2] << 24), - (s->colors[3] & 0xffffff) | (s->alpha[3] << 24), - s->fontWeight > FW_NORMAL ? -1 : 0, - s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, - s->fontScaleX, s->fontScaleY, - s->fontSpacing, s->fontAngleZ, - s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, - s->outlineWidthY, s->shadowDepthY, - s->scrAlignment, - s->marginRect.left, s->marginRect.right, (int)((s->marginRect.top + s->marginRect.bottom) / 2), - s->charSet); - f.WriteString(str2); - } - } - - if (!IsEmpty()) { - str = _T("\n"); - str += _T("[Events]\n"); - str += (type == Subtitle::SSA) - ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n") - : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n"); - f.WriteString(str); - } - } - - CStringW fmt = - type == Subtitle::SRT ? L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n" : - type == Subtitle::SUB ? L"{%d}{%d}%s\n" : - type == Subtitle::SMI ? L"

\n%s\n

 \n" : - type == Subtitle::PSB ? L"{%d:%02d:%02d}{%d:%02d:%02d}%s\n" : - type == Subtitle::SSA ? L"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" : - type == Subtitle::ASS ? L"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" : - L""; - // Sort(true); - - if (m_mode == FRAME) { - delay = std::lround(delay * fps / 1000.0); - } - - for (int i = 0, j = (int)GetCount(), k = 0; i < j; i++) { - STSEntry& stse = GetAt(i); - - int t1 = (int)(RT2MS(TranslateStart(i, fps)) + delay); - if (t1 < 0) { - k++; - continue; - } - - int t2 = (int)(RT2MS(TranslateEnd(i, fps)) + delay); - - int hh1 = (t1 / 60 / 60 / 1000); - int mm1 = (t1 / 60 / 1000) % 60; - int ss1 = (t1 / 1000) % 60; - int ms1 = (t1) % 1000; - int hh2 = (t2 / 60 / 60 / 1000); - int mm2 = (t2 / 60 / 1000) % 60; - int ss2 = (t2 / 1000) % 60; - int ms2 = (t2) % 1000; - - CStringW str = f.IsUnicode() - ? GetStrW(i, type == Subtitle::SSA || type == Subtitle::ASS) - : GetStrWA(i, type == Subtitle::SSA || type == Subtitle::ASS); - - CStringW str2; - - if (type == Subtitle::SRT) { - str2.Format(fmt, i - k + 1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, str.GetString()); - } else if (type == Subtitle::SUB) { - str.Replace('\n', '|'); - str2.Format(fmt, int(t1 * fps / 1000), int(t2 * fps / 1000), str.GetString()); - } else if (type == Subtitle::SMI) { - str.Replace(L"\n", L"
"); - str2.Format(fmt, t1, str.GetString(), t2); - } else if (type == Subtitle::PSB) { - str.Replace('\n', '|'); - str2.Format(fmt, hh1, mm1, ss1, hh2, mm2, ss2, str.GetString()); - } else if (type == Subtitle::SSA) { - str.Replace(L"\n", L"\\N"); - str2.Format(fmt, - hh1, mm1, ss1, ms1 / 10, - hh2, mm2, ss2, ms2 / 10, - TToW(stse.style).GetString(), TToW(stse.actor).GetString(), - stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, - TToW(stse.effect).GetString(), str.GetString()); - } else if (type == Subtitle::ASS) { - str.Replace(L"\n", L"\\N"); - str2.Format(fmt, - stse.layer, - hh1, mm1, ss1, ms1 / 10, - hh2, mm2, ss2, ms2 / 10, - TToW(stse.style).GetString(), TToW(stse.actor).GetString(), - stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, - TToW(stse.effect).GetString(), str.GetString()); - } - - f.WriteString(str2); - } - - // Sort(); - - if (type == Subtitle::SMI) { - f.WriteString(_T("\n\n")); - } - - STSStyle* s; - if (bCreateExternalStyleFile && !m_bUsingPlayerDefaultStyle && m_styles.Lookup(_T("Default"), s) && type != Subtitle::SSA && type != Subtitle::ASS) { - CTextFile file; - if (!file.Save(fn + _T(".style"), e)) { - return false; - } - - CString str, str2; - - str += _T("ScriptType: v4.00+\n"); - str += _T("PlayResX: %d\n"); - str += _T("PlayResY: %d\n"); - str += _T("\n"); - str += _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"); - str2.Format(str, m_storageRes.cx, m_storageRes.cy); - file.WriteString(str2); - - str = _T("Style: Default,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f,%d,%d,%d,%d,%d\n"); - str2.Format(str, - s->fontName.GetString(), (int)s->fontSize, - (s->colors[0] & 0xffffff) | (s->alpha[0] << 24), - (s->colors[1] & 0xffffff) | (s->alpha[1] << 24), - (s->colors[2] & 0xffffff) | (s->alpha[2] << 24), - (s->colors[3] & 0xffffff) | (s->alpha[3] << 24), - s->fontWeight > FW_NORMAL ? -1 : 0, - s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, - s->fontScaleX, s->fontScaleY, - s->fontSpacing, s->fontAngleZ, - s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, - s->outlineWidthY, s->shadowDepthY, - s->scrAlignment, - s->marginRect.left, s->marginRect.right, (int)((s->marginRect.top + s->marginRect.bottom) / 2), - s->charSet); - file.WriteString(str2); - } - - m_provider = _T("Local"); - m_path = fn; - - return true; -} - -//////////////////////////////////////////////////////////////////// - -STSStyle::STSStyle() -{ - SetDefault(); -} - -void STSStyle::SetDefault() -{ - marginRect = CRect(20, 20, 20, 20); - scrAlignment = 2; - borderStyle = 0; - outlineWidthX = outlineWidthY = 2; - shadowDepthX = shadowDepthY = 3; - colors[0] = 0x00ffffff; - colors[1] = 0x0000ffff; - colors[2] = 0x00000000; - colors[3] = 0x00000000; - alpha[0] = 0x00; - alpha[1] = 0x00; - alpha[2] = 0x00; - alpha[3] = 0x80; - charSet = DEFAULT_CHARSET; - fontName = _T("Calibri"); - fontSize = 18; - fontScaleX = fontScaleY = 100; - fontSpacing = 0; - fontWeight = FW_BOLD; - fItalic = false; - fUnderline = false; - fStrikeOut = false; - fBlur = 0; - fGaussianBlur = 0; - fontShiftX = fontShiftY = fontAngleZ = fontAngleX = fontAngleY = 0; - relativeTo = STSStyle::AUTO; - hasAnsiStyleName = false; -#if USE_LIBASS - Kerning = false; - ScaledBorderAndShadow = false; - customTags = L""; -#endif -} - -bool STSStyle::operator == (const STSStyle& s) const -{ - return (marginRect == s.marginRect - && scrAlignment == s.scrAlignment - && borderStyle == s.borderStyle - && abs(outlineWidthX - s.outlineWidthX) < 0.00000001 - && abs(outlineWidthY - s.outlineWidthY) < 0.00000001 - && abs(shadowDepthX - s.shadowDepthX) < 0.00000001 - && abs(shadowDepthY - s.shadowDepthY) < 0.00000001 - && colors == s.colors - && alpha == s.alpha - && fBlur == s.fBlur - && abs(fGaussianBlur - s.fGaussianBlur) < 0.00000001 - && relativeTo == s.relativeTo - && IsFontStyleEqual(s)); -} - -bool STSStyle::IsFontStyleEqual(const STSStyle& s) const -{ - return ( - charSet == s.charSet - && fontName == s.fontName - && fontSize == s.fontSize - && abs(fontScaleX - s.fontScaleX) < 0.00000001 - && abs(fontScaleY - s.fontScaleY) < 0.00000001 - && abs(fontSpacing - s.fontSpacing) < 0.00000001 - && fontWeight == s.fontWeight - && fItalic == s.fItalic - && fUnderline == s.fUnderline - && fStrikeOut == s.fStrikeOut - && abs(fontAngleZ - s.fontAngleZ) < 0.00000001 - && abs(fontAngleX - s.fontAngleX) < 0.00000001 - && abs(fontAngleY - s.fontAngleY) < 0.00000001 - && abs(fontShiftX - s.fontShiftX) < 0.00000001 - && abs(fontShiftY - s.fontShiftY) < 0.00000001); -} - -STSStyle& STSStyle::operator = (LOGFONT& lf) -{ - charSet = lf.lfCharSet; - fontName = lf.lfFaceName; - HDC hDC = GetDC(nullptr); - fontSize = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY)); - ReleaseDC(nullptr, hDC); - // fontAngleZ = lf.lfEscapement/10.0; - fontWeight = lf.lfWeight; - fItalic = lf.lfItalic; - fUnderline = lf.lfUnderline; - fStrikeOut = lf.lfStrikeOut; - return *this; -} - -LOGFONTA& operator <<= (LOGFONTA& lfa, const STSStyle& s) -{ - lfa.lfCharSet = (BYTE)s.charSet; - strncpy_s(lfa.lfFaceName, LF_FACESIZE, CStringA(s.fontName), _TRUNCATE); - HDC hDC = GetDC(nullptr); - lfa.lfHeight = -MulDiv((int)(s.fontSize + 0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72); - ReleaseDC(nullptr, hDC); - lfa.lfWeight = s.fontWeight; - lfa.lfItalic = s.fItalic ? -1 : 0; - lfa.lfUnderline = s.fUnderline ? -1 : 0; - lfa.lfStrikeOut = s.fStrikeOut ? -1 : 0; - return lfa; -} - -LOGFONTW& operator <<= (LOGFONTW& lfw, const STSStyle& s) -{ - lfw.lfCharSet = (BYTE)s.charSet; - wcsncpy_s(lfw.lfFaceName, LF_FACESIZE, CStringW(s.fontName), _TRUNCATE); - HDC hDC = GetDC(nullptr); - lfw.lfHeight = -MulDiv((int)(s.fontSize + 0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72); - ReleaseDC(nullptr, hDC); - lfw.lfWeight = s.fontWeight; - lfw.lfItalic = s.fItalic ? -1 : 0; - lfw.lfUnderline = s.fUnderline ? -1 : 0; - lfw.lfStrikeOut = s.fStrikeOut ? -1 : 0; - return lfw; -} - -CString& operator <<= (CString& style, const STSStyle& s) -{ - style.Format(_T("%d;%d;%d;%d;%d;%d;%f;%f;%f;%f;0x%06lx;0x%06lx;0x%06lx;0x%06lx;0x%02x;0x%02x;0x%02x;0x%02x;%d;%s;%f;%f;%f;%f;%ld;%d;%d;%d;%d;%f;%f;%f;%f;%d"), - s.marginRect.left, s.marginRect.right, s.marginRect.top, s.marginRect.bottom, - s.scrAlignment, s.borderStyle, - s.outlineWidthX, s.outlineWidthY, s.shadowDepthX, s.shadowDepthY, - s.colors[0], s.colors[1], s.colors[2], s.colors[3], - s.alpha[0], s.alpha[1], s.alpha[2], s.alpha[3], - s.charSet, - s.fontName.GetString(), s.fontSize, - s.fontScaleX, s.fontScaleY, - s.fontSpacing, s.fontWeight, - s.fItalic, s.fUnderline, s.fStrikeOut, s.fBlur, s.fGaussianBlur, - s.fontAngleZ, s.fontAngleX, s.fontAngleY, - s.relativeTo); - - return style; -} - -STSStyle& operator <<= (STSStyle& s, const CString& style) -{ - s.SetDefault(); - - try { - CStringW str = TToW(style); - LPCWSTR pszBuff = str; - int nBuffLength = str.GetLength(); - if (str.Find(';') >= 0) { - s.marginRect.left = GetInt(pszBuff, nBuffLength, L';'); - s.marginRect.right = GetInt(pszBuff, nBuffLength, L';'); - s.marginRect.top = GetInt(pszBuff, nBuffLength, L';'); - s.marginRect.bottom = GetInt(pszBuff, nBuffLength, L';'); - s.scrAlignment = GetInt(pszBuff, nBuffLength, L';'); - s.borderStyle = GetInt(pszBuff, nBuffLength, L';'); - s.outlineWidthX = GetFloat(pszBuff, nBuffLength, L';'); - s.outlineWidthY = GetFloat(pszBuff, nBuffLength, L';'); - s.shadowDepthX = GetFloat(pszBuff, nBuffLength, L';'); - s.shadowDepthY = GetFloat(pszBuff, nBuffLength, L';'); - for (size_t i = 0; i < 4; i++) { - s.colors[i] = (COLORREF)GetInt(pszBuff, nBuffLength, L';'); - } - for (size_t i = 0; i < 4; i++) { - s.alpha[i] = (BYTE)GetInt(pszBuff, nBuffLength, L';'); - } - s.charSet = GetInt(pszBuff, nBuffLength, L';'); - s.fontName = WToT(GetStrW(pszBuff, nBuffLength, L';')); - s.fontSize = GetFloat(pszBuff, nBuffLength, L';'); - s.fontScaleX = GetFloat(pszBuff, nBuffLength, L';'); - s.fontScaleY = GetFloat(pszBuff, nBuffLength, L';'); - s.fontSpacing = GetFloat(pszBuff, nBuffLength, L';'); - s.fontWeight = GetInt(pszBuff, nBuffLength, L';'); - s.fItalic = GetInt(pszBuff, nBuffLength, L';'); - s.fUnderline = GetInt(pszBuff, nBuffLength, L';'); - s.fStrikeOut = GetInt(pszBuff, nBuffLength, L';'); - s.fBlur = GetInt(pszBuff, nBuffLength, L';'); - s.fGaussianBlur = GetFloat(pszBuff, nBuffLength, L';'); - s.fontAngleZ = GetFloat(pszBuff, nBuffLength, L';'); - s.fontAngleX = GetFloat(pszBuff, nBuffLength, L';'); - s.fontAngleY = GetFloat(pszBuff, nBuffLength, L';'); - s.relativeTo = (STSStyle::RelativeTo)GetInt(pszBuff, nBuffLength, L';'); - } - } catch (...) { - s.SetDefault(); - } - - return s; -} - -static bool OpenRealText(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet) -{ - std::wstring szFile; - CStringW buff; - - while (file->ReadString(buff)) { - FastTrim(buff); - if (buff.IsEmpty()) { - continue; - } - - // Make sure that the subtitle file starts with a tag - if (szFile.empty() && buff.CompareNoCase(_T("second.c_str()), - file->IsUnicode(), - MS2RT(i->first.first), - MS2RT(i->first.second)); - } - - return !ret.IsEmpty(); -} - -void CSTSStyleMap::Free() { - POSITION pos = GetStartPosition(); - while (pos) { - CString key; - STSStyle* val; - GetNextAssoc(pos, key, val); - delete val; - } - - RemoveAll(); -} + + return fRet; +} + +bool CSimpleTextSubtitle::SaveAs(CString fn, Subtitle::SubType type, + double fps /*= -1*/, LONGLONG delay /*= 0*/, + CTextFile::enc e /*= CTextFile::DEFAULT_ENCODING*/, bool bCreateExternalStyleFile /*= true*/) +{ + LPCTSTR ext = Subtitle::GetSubtitleFileExt(type); + if (ext && fn.Mid(fn.ReverseFind('.') + 1).CompareNoCase(ext)) { + if (fn[fn.GetLength() - 1] != '.') { + fn += _T("."); + } + fn += ext; + } + + CTextFile f; + if (!f.Save(fn, e)) { + return false; + } + + if (type == Subtitle::SMI) { + CString str; + + str += _T("\n\n"); + str += _T("\n"); + str += _T("\n"); + str += _T("\n"); + str += _T("\n"); + + f.WriteString(str); + } else if (type == Subtitle::SSA || type == Subtitle::ASS) { + CString str; + + str = _T("[Script Info]\n"); + str += _T("; Note: This file was saved by MPC-HC.\n"); + str += (type == Subtitle::SSA) ? _T("ScriptType: v4.00\n") : _T("ScriptType: v4.00+\n"); + str += (m_collisions == 0) ? _T("Collisions: Normal\n") : _T("Collisions: Reverse\n"); + if (type == Subtitle::ASS && m_scaledBAS >= 0) { + if (m_scaledBAS == 1) { + str += _T("ScaledBorderAndShadow: yes\n"); + } else { + str += _T("ScaledBorderAndShadow: no\n"); + } + } + if (m_sYCbCrMatrix.IsEmpty()) { + str += _T("YCbCr Matrix: None\n"); + } else { + str += _T("YCbCr Matrix: ") + m_sYCbCrMatrix + _T("\n"); + } + str.AppendFormat(_T("PlayResX: %d\n"), m_playRes.cx); + str.AppendFormat(_T("PlayResY: %d\n"), m_playRes.cy); + if (m_layoutRes.cx > 0 && m_layoutRes.cy > 0) { + str.AppendFormat(_T("LayoutResX: %d\n"), m_layoutRes.cx); + str.AppendFormat(_T("LayoutResY: %d\n"), m_layoutRes.cy); + } + str += _T("Timer: 100.0000\n"); + str += _T("\n"); + str += (type == Subtitle::SSA) + ? _T("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n") + : _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"); + + f.WriteString(str); + + str = (type == Subtitle::SSA) + ? _T("Style: %s,%s,%d,&H%06x,&H%06x,&H%06x,&H%06x,%d,%d,%d,%.2f,%.2f,%d,%d,%d,%d,%d,%d\n") + : _T("Style: %s,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f,%d,%d,%d,%d,%d\n"); + + POSITION pos = m_styles.GetStartPosition(); + while (pos) { + CString key; + STSStyle* s; + m_styles.GetNextAssoc(pos, key, s); + + if (type == Subtitle::SSA) { + CString str2; + str2.Format(str, key.GetString(), + s->fontName.GetString(), (int)s->fontSize, + s->colors[0] & 0xffffff, + s->colors[1] & 0xffffff, + s->colors[2] & 0xffffff, + s->colors[3] & 0xffffff, + s->fontWeight > FW_NORMAL ? -1 : 0, s->fItalic ? -1 : 0, + s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, + s->outlineWidthY, s->shadowDepthY, + s->scrAlignment <= 3 ? s->scrAlignment : s->scrAlignment <= 6 ? ((s->scrAlignment - 3) | 8) : s->scrAlignment <= 9 ? ((s->scrAlignment - 6) | 4) : 2, + s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2, + s->alpha[0], + s->charSet); + f.WriteString(str2); + } else { + CString str2; + str2.Format(str, key.GetString(), + s->fontName.GetString(), (int)s->fontSize, + (s->colors[0] & 0xffffff) | (s->alpha[0] << 24), + (s->colors[1] & 0xffffff) | (s->alpha[1] << 24), + (s->colors[2] & 0xffffff) | (s->alpha[2] << 24), + (s->colors[3] & 0xffffff) | (s->alpha[3] << 24), + s->fontWeight > FW_NORMAL ? -1 : 0, + s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, + s->fontScaleX, s->fontScaleY, + s->fontSpacing, s->fontAngleZ, + s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, + s->outlineWidthY, s->shadowDepthY, + s->scrAlignment, + s->marginRect.left, s->marginRect.right, (int)((s->marginRect.top + s->marginRect.bottom) / 2), + s->charSet); + f.WriteString(str2); + } + } + + if (!IsEmpty()) { + str = _T("\n"); + str += _T("[Events]\n"); + str += (type == Subtitle::SSA) + ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n") + : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n"); + f.WriteString(str); + } + } + + CStringW fmt = + type == Subtitle::SRT ? L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n" : + type == Subtitle::SUB ? L"{%d}{%d}%s\n" : + type == Subtitle::SMI ? L"

\n%s\n

 \n" : + type == Subtitle::PSB ? L"{%d:%02d:%02d}{%d:%02d:%02d}%s\n" : + type == Subtitle::SSA ? L"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" : + type == Subtitle::ASS ? L"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" : + L""; + // Sort(true); + + if (m_mode == FRAME) { + delay = std::lround(delay * fps / 1000.0); + } + + for (int i = 0, j = (int)GetCount(), k = 0; i < j; i++) { + STSEntry& stse = GetAt(i); + + int t1 = (int)(RT2MS(TranslateStart(i, fps)) + delay); + if (t1 < 0) { + k++; + continue; + } + + int t2 = (int)(RT2MS(TranslateEnd(i, fps)) + delay); + + int hh1 = (t1 / 60 / 60 / 1000); + int mm1 = (t1 / 60 / 1000) % 60; + int ss1 = (t1 / 1000) % 60; + int ms1 = (t1) % 1000; + int hh2 = (t2 / 60 / 60 / 1000); + int mm2 = (t2 / 60 / 1000) % 60; + int ss2 = (t2 / 1000) % 60; + int ms2 = (t2) % 1000; + + CStringW str = f.IsUnicode() + ? GetStrW(i, type == Subtitle::SSA || type == Subtitle::ASS) + : GetStrWA(i, type == Subtitle::SSA || type == Subtitle::ASS); + + CStringW str2; + + if (type == Subtitle::SRT) { + str2.Format(fmt, i - k + 1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, str.GetString()); + } else if (type == Subtitle::SUB) { + str.Replace('\n', '|'); + str2.Format(fmt, int(t1 * fps / 1000), int(t2 * fps / 1000), str.GetString()); + } else if (type == Subtitle::SMI) { + str.Replace(L"\n", L"
"); + str2.Format(fmt, t1, str.GetString(), t2); + } else if (type == Subtitle::PSB) { + str.Replace('\n', '|'); + str2.Format(fmt, hh1, mm1, ss1, hh2, mm2, ss2, str.GetString()); + } else if (type == Subtitle::SSA) { + str.Replace(L"\n", L"\\N"); + str2.Format(fmt, + hh1, mm1, ss1, ms1 / 10, + hh2, mm2, ss2, ms2 / 10, + TToW(stse.style).GetString(), TToW(stse.actor).GetString(), + stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, + TToW(stse.effect).GetString(), str.GetString()); + } else if (type == Subtitle::ASS) { + str.Replace(L"\n", L"\\N"); + str2.Format(fmt, + stse.layer, + hh1, mm1, ss1, ms1 / 10, + hh2, mm2, ss2, ms2 / 10, + TToW(stse.style).GetString(), TToW(stse.actor).GetString(), + stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, + TToW(stse.effect).GetString(), str.GetString()); + } + + f.WriteString(str2); + } + + // Sort(); + + if (type == Subtitle::SMI) { + f.WriteString(_T("\n\n")); + } + + STSStyle* s; + if (bCreateExternalStyleFile && !m_bUsingPlayerDefaultStyle && m_styles.Lookup(_T("Default"), s) && type != Subtitle::SSA && type != Subtitle::ASS) { + CTextFile file; + if (!file.Save(fn + _T(".style"), e)) { + return false; + } + + CString str, str2; + + str += _T("ScriptType: v4.00+\n"); + str += _T("PlayResX: %d\n"); + str += _T("PlayResY: %d\n"); + str += _T("\n"); + str += _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"); + str2.Format(str, m_storageRes.cx, m_storageRes.cy); + file.WriteString(str2); + + str = _T("Style: Default,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f,%d,%d,%d,%d,%d\n"); + str2.Format(str, + s->fontName.GetString(), (int)s->fontSize, + (s->colors[0] & 0xffffff) | (s->alpha[0] << 24), + (s->colors[1] & 0xffffff) | (s->alpha[1] << 24), + (s->colors[2] & 0xffffff) | (s->alpha[2] << 24), + (s->colors[3] & 0xffffff) | (s->alpha[3] << 24), + s->fontWeight > FW_NORMAL ? -1 : 0, + s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, + s->fontScaleX, s->fontScaleY, + s->fontSpacing, s->fontAngleZ, + s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, + s->outlineWidthY, s->shadowDepthY, + s->scrAlignment, + s->marginRect.left, s->marginRect.right, (int)((s->marginRect.top + s->marginRect.bottom) / 2), + s->charSet); + file.WriteString(str2); + } + + m_provider = _T("Local"); + m_path = fn; + + return true; +} + +//////////////////////////////////////////////////////////////////// + +STSStyle::STSStyle() +{ + SetDefault(); +} + +void STSStyle::SetDefault() +{ + marginRect = CRect(20, 20, 20, 20); + scrAlignment = 2; + borderStyle = 0; + outlineWidthX = outlineWidthY = 2; + shadowDepthX = shadowDepthY = 3; + colors[0] = 0x00ffffff; + colors[1] = 0x0000ffff; + colors[2] = 0x00000000; + colors[3] = 0x00000000; + alpha[0] = 0x00; + alpha[1] = 0x00; + alpha[2] = 0x00; + alpha[3] = 0x80; + charSet = DEFAULT_CHARSET; + fontName = _T("Calibri"); + fontSize = 18; + fontScaleX = fontScaleY = 100; + fontSpacing = 0; + fontWeight = FW_BOLD; + fItalic = false; + fUnderline = false; + fStrikeOut = false; + fBlur = 0; + fGaussianBlur = 0; + fontShiftX = fontShiftY = fontAngleZ = fontAngleX = fontAngleY = 0; + relativeTo = STSStyle::AUTO; + hasAnsiStyleName = false; +#if USE_LIBASS + Kerning = false; + ScaledBorderAndShadow = false; + customTags = L""; +#endif +} + +bool STSStyle::operator == (const STSStyle& s) const +{ + return (marginRect == s.marginRect + && scrAlignment == s.scrAlignment + && borderStyle == s.borderStyle + && abs(outlineWidthX - s.outlineWidthX) < 0.00000001 + && abs(outlineWidthY - s.outlineWidthY) < 0.00000001 + && abs(shadowDepthX - s.shadowDepthX) < 0.00000001 + && abs(shadowDepthY - s.shadowDepthY) < 0.00000001 + && colors == s.colors + && alpha == s.alpha + && fBlur == s.fBlur + && abs(fGaussianBlur - s.fGaussianBlur) < 0.00000001 + && relativeTo == s.relativeTo + && IsFontStyleEqual(s)); +} + +bool STSStyle::IsFontStyleEqual(const STSStyle& s) const +{ + return ( + charSet == s.charSet + && fontName == s.fontName + && fontSize == s.fontSize + && abs(fontScaleX - s.fontScaleX) < 0.00000001 + && abs(fontScaleY - s.fontScaleY) < 0.00000001 + && abs(fontSpacing - s.fontSpacing) < 0.00000001 + && fontWeight == s.fontWeight + && fItalic == s.fItalic + && fUnderline == s.fUnderline + && fStrikeOut == s.fStrikeOut + && abs(fontAngleZ - s.fontAngleZ) < 0.00000001 + && abs(fontAngleX - s.fontAngleX) < 0.00000001 + && abs(fontAngleY - s.fontAngleY) < 0.00000001 + && abs(fontShiftX - s.fontShiftX) < 0.00000001 + && abs(fontShiftY - s.fontShiftY) < 0.00000001); +} + +STSStyle& STSStyle::operator = (LOGFONT& lf) +{ + charSet = lf.lfCharSet; + fontName = lf.lfFaceName; + HDC hDC = GetDC(nullptr); + fontSize = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY)); + ReleaseDC(nullptr, hDC); + // fontAngleZ = lf.lfEscapement/10.0; + fontWeight = lf.lfWeight; + fItalic = lf.lfItalic; + fUnderline = lf.lfUnderline; + fStrikeOut = lf.lfStrikeOut; + return *this; +} + +LOGFONTA& operator <<= (LOGFONTA& lfa, const STSStyle& s) +{ + lfa.lfCharSet = (BYTE)s.charSet; + strncpy_s(lfa.lfFaceName, LF_FACESIZE, CStringA(s.fontName), _TRUNCATE); + HDC hDC = GetDC(nullptr); + lfa.lfHeight = -MulDiv((int)(s.fontSize + 0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72); + ReleaseDC(nullptr, hDC); + lfa.lfWeight = s.fontWeight; + lfa.lfItalic = s.fItalic ? -1 : 0; + lfa.lfUnderline = s.fUnderline ? -1 : 0; + lfa.lfStrikeOut = s.fStrikeOut ? -1 : 0; + return lfa; +} + +LOGFONTW& operator <<= (LOGFONTW& lfw, const STSStyle& s) +{ + lfw.lfCharSet = (BYTE)s.charSet; + wcsncpy_s(lfw.lfFaceName, LF_FACESIZE, CStringW(s.fontName), _TRUNCATE); + HDC hDC = GetDC(nullptr); + lfw.lfHeight = -MulDiv((int)(s.fontSize + 0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72); + ReleaseDC(nullptr, hDC); + lfw.lfWeight = s.fontWeight; + lfw.lfItalic = s.fItalic ? -1 : 0; + lfw.lfUnderline = s.fUnderline ? -1 : 0; + lfw.lfStrikeOut = s.fStrikeOut ? -1 : 0; + return lfw; +} + +CString& operator <<= (CString& style, const STSStyle& s) +{ + style.Format(_T("%d;%d;%d;%d;%d;%d;%f;%f;%f;%f;0x%06lx;0x%06lx;0x%06lx;0x%06lx;0x%02x;0x%02x;0x%02x;0x%02x;%d;%s;%f;%f;%f;%f;%ld;%d;%d;%d;%d;%f;%f;%f;%f;%d"), + s.marginRect.left, s.marginRect.right, s.marginRect.top, s.marginRect.bottom, + s.scrAlignment, s.borderStyle, + s.outlineWidthX, s.outlineWidthY, s.shadowDepthX, s.shadowDepthY, + s.colors[0], s.colors[1], s.colors[2], s.colors[3], + s.alpha[0], s.alpha[1], s.alpha[2], s.alpha[3], + s.charSet, + s.fontName.GetString(), s.fontSize, + s.fontScaleX, s.fontScaleY, + s.fontSpacing, s.fontWeight, + s.fItalic, s.fUnderline, s.fStrikeOut, s.fBlur, s.fGaussianBlur, + s.fontAngleZ, s.fontAngleX, s.fontAngleY, + s.relativeTo); + + return style; +} + +STSStyle& operator <<= (STSStyle& s, const CString& style) +{ + s.SetDefault(); + + try { + CStringW str = TToW(style); + LPCWSTR pszBuff = str; + int nBuffLength = str.GetLength(); + if (str.Find(';') >= 0) { + s.marginRect.left = GetInt(pszBuff, nBuffLength, L';'); + s.marginRect.right = GetInt(pszBuff, nBuffLength, L';'); + s.marginRect.top = GetInt(pszBuff, nBuffLength, L';'); + s.marginRect.bottom = GetInt(pszBuff, nBuffLength, L';'); + s.scrAlignment = GetInt(pszBuff, nBuffLength, L';'); + s.borderStyle = GetInt(pszBuff, nBuffLength, L';'); + s.outlineWidthX = GetFloat(pszBuff, nBuffLength, L';'); + s.outlineWidthY = GetFloat(pszBuff, nBuffLength, L';'); + s.shadowDepthX = GetFloat(pszBuff, nBuffLength, L';'); + s.shadowDepthY = GetFloat(pszBuff, nBuffLength, L';'); + for (size_t i = 0; i < 4; i++) { + s.colors[i] = (COLORREF)GetInt(pszBuff, nBuffLength, L';'); + } + for (size_t i = 0; i < 4; i++) { + s.alpha[i] = (BYTE)GetInt(pszBuff, nBuffLength, L';'); + } + s.charSet = GetInt(pszBuff, nBuffLength, L';'); + s.fontName = WToT(GetStrW(pszBuff, nBuffLength, L';')); + s.fontSize = GetFloat(pszBuff, nBuffLength, L';'); + s.fontScaleX = GetFloat(pszBuff, nBuffLength, L';'); + s.fontScaleY = GetFloat(pszBuff, nBuffLength, L';'); + s.fontSpacing = GetFloat(pszBuff, nBuffLength, L';'); + s.fontWeight = GetInt(pszBuff, nBuffLength, L';'); + s.fItalic = GetInt(pszBuff, nBuffLength, L';'); + s.fUnderline = GetInt(pszBuff, nBuffLength, L';'); + s.fStrikeOut = GetInt(pszBuff, nBuffLength, L';'); + s.fBlur = GetInt(pszBuff, nBuffLength, L';'); + s.fGaussianBlur = GetFloat(pszBuff, nBuffLength, L';'); + s.fontAngleZ = GetFloat(pszBuff, nBuffLength, L';'); + s.fontAngleX = GetFloat(pszBuff, nBuffLength, L';'); + s.fontAngleY = GetFloat(pszBuff, nBuffLength, L';'); + s.relativeTo = (STSStyle::RelativeTo)GetInt(pszBuff, nBuffLength, L';'); + } + } catch (...) { + s.SetDefault(); + } + + return s; +} + +static bool OpenRealText(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet) +{ + std::wstring szFile; + CStringW buff; + + while (file->ReadString(buff)) { + FastTrim(buff); + if (buff.IsEmpty()) { + continue; + } + + // Make sure that the subtitle file starts with a tag + if (szFile.empty() && buff.CompareNoCase(_T("second.c_str()), + file->IsUnicode(), + MS2RT(i->first.first), + MS2RT(i->first.second)); + } + + return !ret.IsEmpty(); +} + +void CSTSStyleMap::Free() { + POSITION pos = GetStartPosition(); + while (pos) { + CString key; + STSStyle* val; + GetNextAssoc(pos, key, val); + delete val; + } + + RemoveAll(); +} diff --git a/src/Subtitles/STS.h b/src/Subtitles/STS.h index 78e0a8e2e32..7d836483ae3 100644 --- a/src/Subtitles/STS.h +++ b/src/Subtitles/STS.h @@ -1,205 +1,205 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include -#include -#include "TextFile.h" -#include "SubtitleHelpers.h" +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include +#include +#include "TextFile.h" +#include "SubtitleHelpers.h" #include "../../include/mpc-hc_config.h" #include "LibassContext.h" -#include "SubRendererSettings.h" +#include "SubRendererSettings.h" #include "OpenTypeLangTags.h" -#include "STSStyle.h" - -enum tmode { TIME, FRAME }; // the meaning of STSEntry::start/end - -struct STSEntry { - CStringW str; - bool fUnicode; - CString style, actor, effect; - CRect marginRect; - int layer; - REFERENCE_TIME start, end; - int readorder; -}; - -class STSSegment -{ -public: - REFERENCE_TIME start, end; - CAtlArray subs; - - STSSegment() - : start(0) - , end(0) {} - STSSegment(REFERENCE_TIME s, REFERENCE_TIME e) { - start = s; - end = e; - } - STSSegment(const STSSegment& stss) { - *this = stss; - } - STSSegment& operator = (const STSSegment& stss) { - if (this != &stss) { - start = stss.start; - end = stss.end; - subs.Copy(stss.subs); - } - return *this; - } -}; - -class CSimpleTextSubtitle : public CAtlArray -{ - friend class CSubtitleEditorDlg; - friend class SubtitlesProvider; - -protected: - CAtlArray m_segments; - virtual void OnChanged() {} - -public: - SubRendererSettings m_SubRendererSettings; - - CString m_name; - LCID m_lcid; - CString m_langname; - CStringA openTypeLangHint; - Subtitle::SubType m_subtitleType; - tmode m_mode; - CTextFile::enc m_encoding; - CString m_path; - - CString m_provider; - - Subtitle::HearingImpairedType m_eHearingImpaired; - - CSize m_storageRes; - CSize m_playRes; - CSize m_layoutRes; - - int m_defaultWrapStyle; - int m_collisions; - int m_scaledBAS; // -1 = unknown, 0 = no, 1 = yes - CString m_sYCbCrMatrix; - - bool m_bStyleOverrideActive; - STSStyle m_originalDefaultStyle; - bool m_bUsingPlayerDefaultStyle; - uint32_t event_param; - - CSTSStyleMap m_styles; - int overrideANSICharset; - - enum EPARCompensationType { - EPCTDisabled, - EPCTDownscale, - EPCTUpscale, - EPCTAccurateSize, - EPCTAccurateSize_ISR - }; - - EPARCompensationType m_ePARCompensationType; - double m_dPARCompensation; - -public: - CSimpleTextSubtitle(); - virtual ~CSimpleTextSubtitle(); - - virtual void Copy(CSimpleTextSubtitle& sts); - virtual void Empty(); - - void Sort(bool fRestoreReadorder = false); - void CreateSegments(); - void FlushEventsLibass(); - - void Append(CSimpleTextSubtitle& sts, REFERENCE_TIME timeoff = -1); - - bool Open(CString fn, int CharSet, CString name = _T(""), CString videoName = _T("")); - bool Open(CTextFile* f, int CharSet, CString name); - bool Open(BYTE* data, int length, int CharSet, CString provider, CString lang, CString ext = _T("")); - bool Open(CString data, CTextFile::enc SaveCharSet, int ReadCharSet, CString provider, CString lang, CString ext = _T("")); - bool Open(BYTE* data, int len, int CharSet, CString name); - bool Open(CString provider, BYTE* data, int len, int CharSet, CString name, Subtitle::HearingImpairedType eHearingImpaired, LCID lcid); - bool SaveAs(CString fn, Subtitle::SubType type, double fps = -1, LONGLONG delay = 0, CTextFile::enc e = CTextFile::DEFAULT_ENCODING, bool bCreateExternalStyleFile = true); - - void Add(CStringW str, bool fUnicode, REFERENCE_TIME start, REFERENCE_TIME end, CString style = _T("Default"), CString actor = _T(""), CString effect = _T(""), const CRect& marginRect = CRect(0, 0, 0, 0), int layer = 0, int readorder = -1); - STSStyle* CreateDefaultStyle(int CharSet); - STSStyle GetOriginalDefaultStyle(); - void ChangeUnknownStylesToDefault(); - void AddStyle(CString name, STSStyle* style); // style will be stored and freed in Empty() later - bool CopyToStyles(CSTSStyleMap& styles); - bool CopyStyles(const CSTSStyleMap& styles, bool fAppend = false); - - bool SetDefaultStyle(const STSStyle& s); - void SetStyleChanged(); - bool GetDefaultStyle(STSStyle& s) const; - - void ConvertToTimeBased(double fps); - void ConvertToFrameBased(double fps); - - REFERENCE_TIME TranslateStart(int i, double fps); - REFERENCE_TIME TranslateEnd(int i, double fps); - int SearchSub(REFERENCE_TIME t, double fps); - - REFERENCE_TIME TranslateSegmentStart(int i, double fps); - REFERENCE_TIME TranslateSegmentEnd(int i, double fps); - const STSSegment* SearchSubs(REFERENCE_TIME t, double fps, /*[out]*/ int* iSegment = nullptr, int* nSegments = nullptr); - const STSSegment* GetSegment(int iSegment) { - return iSegment >= 0 && iSegment < (int)m_segments.GetCount() ? &m_segments[iSegment] : nullptr; - } - - STSStyle* GetStyle(int i); - static void UpdateSubRelativeTo(Subtitle::SubType type, STSStyle::RelativeTo& relativeTo); - bool GetStyle(int i, STSStyle& stss); - bool GetStyle(CString styleName, STSStyle& stss); - int GetCharSet(int charSet); - int GetStyleCharSet(int i); - bool IsEntryUnicode(int i); - void ConvertUnicode(int i, bool fUnicode); - - CStringA GetStrA(int i, bool fSSA = false); - CStringW GetStrW(int i, bool fSSA = false); - CStringW GetStrWA(int i, bool fSSA = false); - - void SetStr(int i, CStringA str, bool fUnicode /* ignored */); - void SetStr(int i, CStringW str, bool fUnicode); - void SetOpenTypeLangHint(CStringA openTypeLangHint) { this->openTypeLangHint = openTypeLangHint; } +#include "STSStyle.h" + +enum tmode { TIME, FRAME }; // the meaning of STSEntry::start/end + +struct STSEntry { + CStringW str; + bool fUnicode; + CString style, actor, effect; + CRect marginRect; + int layer; + REFERENCE_TIME start, end; + int readorder; +}; + +class STSSegment +{ +public: + REFERENCE_TIME start, end; + CAtlArray subs; + + STSSegment() + : start(0) + , end(0) {} + STSSegment(REFERENCE_TIME s, REFERENCE_TIME e) { + start = s; + end = e; + } + STSSegment(const STSSegment& stss) { + *this = stss; + } + STSSegment& operator = (const STSSegment& stss) { + if (this != &stss) { + start = stss.start; + end = stss.end; + subs.Copy(stss.subs); + } + return *this; + } +}; + +class CSimpleTextSubtitle : public CAtlArray +{ + friend class CSubtitleEditorDlg; + friend class SubtitlesProvider; + +protected: + CAtlArray m_segments; + virtual void OnChanged() {} + +public: + SubRendererSettings m_SubRendererSettings; + + CString m_name; + LCID m_lcid; + CString m_langname; + CStringA openTypeLangHint; + Subtitle::SubType m_subtitleType; + tmode m_mode; + CTextFile::enc m_encoding; + CString m_path; + + CString m_provider; + + Subtitle::HearingImpairedType m_eHearingImpaired; + + CSize m_storageRes; + CSize m_playRes; + CSize m_layoutRes; + + int m_defaultWrapStyle; + int m_collisions; + int m_scaledBAS; // -1 = unknown, 0 = no, 1 = yes + CString m_sYCbCrMatrix; + + bool m_bStyleOverrideActive; + STSStyle m_originalDefaultStyle; + bool m_bUsingPlayerDefaultStyle; + uint32_t event_param; + + CSTSStyleMap m_styles; + int overrideANSICharset; + + enum EPARCompensationType { + EPCTDisabled, + EPCTDownscale, + EPCTUpscale, + EPCTAccurateSize, + EPCTAccurateSize_ISR + }; + + EPARCompensationType m_ePARCompensationType; + double m_dPARCompensation; + +public: + CSimpleTextSubtitle(); + virtual ~CSimpleTextSubtitle(); + + virtual void Copy(CSimpleTextSubtitle& sts); + virtual void Empty(); + + void Sort(bool fRestoreReadorder = false); + void CreateSegments(); + void FlushEventsLibass(); + + void Append(CSimpleTextSubtitle& sts, REFERENCE_TIME timeoff = -1); + + bool Open(CString fn, int CharSet, CString name = _T(""), CString videoName = _T("")); + bool Open(CTextFile* f, int CharSet, CString name); + bool Open(BYTE* data, int length, int CharSet, CString provider, CString lang, CString ext = _T("")); + bool Open(CString data, CTextFile::enc SaveCharSet, int ReadCharSet, CString provider, CString lang, CString ext = _T("")); + bool Open(BYTE* data, int len, int CharSet, CString name); + bool Open(CString provider, BYTE* data, int len, int CharSet, CString name, Subtitle::HearingImpairedType eHearingImpaired, LCID lcid); + bool SaveAs(CString fn, Subtitle::SubType type, double fps = -1, LONGLONG delay = 0, CTextFile::enc e = CTextFile::DEFAULT_ENCODING, bool bCreateExternalStyleFile = true); + + void Add(CStringW str, bool fUnicode, REFERENCE_TIME start, REFERENCE_TIME end, CString style = _T("Default"), CString actor = _T(""), CString effect = _T(""), const CRect& marginRect = CRect(0, 0, 0, 0), int layer = 0, int readorder = -1); + STSStyle* CreateDefaultStyle(int CharSet); + STSStyle GetOriginalDefaultStyle(); + void ChangeUnknownStylesToDefault(); + void AddStyle(CString name, STSStyle* style); // style will be stored and freed in Empty() later + bool CopyToStyles(CSTSStyleMap& styles); + bool CopyStyles(const CSTSStyleMap& styles, bool fAppend = false); + + bool SetDefaultStyle(const STSStyle& s); + void SetStyleChanged(); + bool GetDefaultStyle(STSStyle& s) const; + + void ConvertToTimeBased(double fps); + void ConvertToFrameBased(double fps); + + REFERENCE_TIME TranslateStart(int i, double fps); + REFERENCE_TIME TranslateEnd(int i, double fps); + int SearchSub(REFERENCE_TIME t, double fps); + + REFERENCE_TIME TranslateSegmentStart(int i, double fps); + REFERENCE_TIME TranslateSegmentEnd(int i, double fps); + const STSSegment* SearchSubs(REFERENCE_TIME t, double fps, /*[out]*/ int* iSegment = nullptr, int* nSegments = nullptr); + const STSSegment* GetSegment(int iSegment) { + return iSegment >= 0 && iSegment < (int)m_segments.GetCount() ? &m_segments[iSegment] : nullptr; + } + + STSStyle* GetStyle(int i); + static void UpdateSubRelativeTo(Subtitle::SubType type, STSStyle::RelativeTo& relativeTo); + bool GetStyle(int i, STSStyle& stss); + bool GetStyle(CString styleName, STSStyle& stss); + int GetCharSet(int charSet); + int GetStyleCharSet(int i); + bool IsEntryUnicode(int i); + void ConvertUnicode(int i, bool fUnicode); + + CStringA GetStrA(int i, bool fSSA = false); + CStringW GetStrW(int i, bool fSSA = false); + CStringW GetStrWA(int i, bool fSSA = false); + + void SetStr(int i, CStringA str, bool fUnicode /* ignored */); + void SetStr(int i, CStringW str, bool fUnicode); + void SetOpenTypeLangHint(CStringA openTypeLangHint) { this->openTypeLangHint = openTypeLangHint; } public: #if USE_LIBASS LibassContext m_LibassContext; #endif -}; - -extern const BYTE CharSetList[]; -extern const TCHAR* CharSetNames[]; -extern const int CharSetLen; - -class CHtmlColorMap : public CAtlMap> -{ -public: - CHtmlColorMap(); -}; - -extern const CHtmlColorMap g_colors; +}; + +extern const BYTE CharSetList[]; +extern const TCHAR* CharSetNames[]; +extern const int CharSetLen; + +class CHtmlColorMap : public CAtlMap> +{ +public: + CHtmlColorMap(); +}; + +extern const CHtmlColorMap g_colors; diff --git a/src/Subtitles/SeparableFilter.h b/src/Subtitles/SeparableFilter.h index 206112f23e9..cd38f99ae54 100644 --- a/src/Subtitles/SeparableFilter.h +++ b/src/Subtitles/SeparableFilter.h @@ -1,374 +1,374 @@ -/* -* (C) 2007 Niels Martin Hansen -* (C) 2013-2017 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 . -* -*/ - -#pragma once - -#include - -#define LIBDIVIDE_USE_SSE2 1 -#pragma warning(push) -#pragma warning(disable: 4244 4456 4702) -#include "libdivide.h" -#pragma warning(pop) - -// Filter an image in horizontal direction with a one-dimensional filter -// PixelWidth is the distance in bytes between pixels -template -void SeparableFilterX(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, - short* kernel, int kernel_size, int divisor) -{ - int* tmp = DEBUG_NEW int[width]; - - for (int y = 0; y < height; y++) { - ZeroMemory(tmp, width * sizeof(int)); - - const unsigned char* in = src + y * stride; - unsigned char* out = dst + y * stride; - - for (int k = 0; k < kernel_size; k++) { - int xOffset = k - kernel_size / 2; - int xStart = 0; - int xEnd = width; - if (xOffset < 0) { - xEnd += xOffset; - } else if (xOffset > 0) { - xStart += xOffset; - } - for (int x = xStart; x < xEnd; x++) { - tmp[x - xOffset] += (int)(in[x * PixelDist] * kernel[k]); - } - } - for (int x = 0; x < width; x++) { - int accum = tmp[x] / divisor; - if (accum > 255) { - accum = 255; - } else if (accum < 0) { - accum = 0; - } - out[x * PixelDist] = (unsigned char)accum; - } - } - - delete [] tmp; -} - - -// Filter an image in vertical direction with a one-dimensional filter -// PixelWidth is the distance in bytes between pixels -template -void SeparableFilterY(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, - short* kernel, int kernel_size, int divisor) -{ - int* tmp = DEBUG_NEW int[width]; - - for (int y = 0; y < height; y++) { - ZeroMemory(tmp, width * sizeof(int)); - - const unsigned char* in = src + y * stride; - unsigned char* out = dst + y * stride; - - int kOffset = kernel_size / 2; - int kStart = 0; - int kEnd = kernel_size; - if (y < kOffset) { // 0 > y - kOffset - kStart += kOffset - y; - } else if (height <= y + kOffset) { - kEnd -= kOffset + y + 1 - height; - } - for (int k = kStart; k < kEnd; k++) { - for (int x = 0; x < width; x++) { - tmp[x] += (int)(in[(k - kOffset) * stride + x * PixelDist] * kernel[k]); - } - } - for (int x = 0; x < width; x++) { - int accum = tmp[x] / divisor; - if (accum > 255) { - accum = 255; - } else if (accum < 0) { - accum = 0; - } - out[x * PixelDist] = (unsigned char)accum; - } - } - - delete [] tmp; -} - - -// Filter an image in horizontal direction with a one-dimensional filter -void SeparableFilterX_SSE2(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, - short* kernel, int kernel_size, int divisor) -{ - int width16 = width & ~15; - int* tmp = (int*)_aligned_malloc(stride * sizeof(int), 16); - libdivide::divider divisorLibdivide(divisor); - - for (int y = 0; y < height; y++) { - ZeroMemory(tmp, stride * sizeof(int)); - - const unsigned char* in = src + y * stride; - unsigned char* out = dst + y * stride; - - for (int k = 0; k < kernel_size; k++) { - int xOffset = k - kernel_size / 2; - int xStart = 0; - int xEnd = width; - if (xOffset < 0) { - xEnd += xOffset; - } else if (xOffset > 0) { - xStart += xOffset; - } - int xStart16 = (xStart + 15) & ~15; - int xEnd16 = xEnd & ~15; - if (xStart16 >= xEnd16) { // Don't use SSE2 at all - xStart16 = xEnd16 = xEnd; - } - for (int x = xStart; x < xStart16; x++) { - tmp[x - xOffset] += (int)(in[x] * kernel[k]); - } - __m128i coeff = _mm_set1_epi16(kernel[k]); - for (int x = xStart16; x < xEnd16; x += 16) { - // Load 16 values - __m128i data16 = _mm_load_si128((__m128i*)&in[x]); - - // Multiply the first 8 values by the coefficient to get 8 32-bit integers - __m128i data8 = _mm_unpacklo_epi8(data16, _mm_setzero_si128()); - __m128i resLo = _mm_mullo_epi16(data8, coeff); - __m128i resHi = _mm_mulhi_epi16(data8, coeff); - __m128i res32bitLo = _mm_unpacklo_epi16(resLo, resHi); - __m128i res32bitHi = _mm_unpackhi_epi16(resLo, resHi); - - // Load the 4 32-bit integers values, add the values we computed and store them back - __m128i res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset]); - res = _mm_add_epi32(res, res32bitLo); - _mm_storeu_si128((__m128i*)&tmp[x - xOffset], res); - // Repeat the same operation for the next 4 values - res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 4]); - res = _mm_add_epi32(res, res32bitHi); - _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 4], res); - - // Multiply the next 8 values by the coefficient to get 8 32-bit integers - data8 = _mm_unpackhi_epi8(data16, _mm_setzero_si128()); - resLo = _mm_mullo_epi16(data8, coeff); - resHi = _mm_mulhi_epi16(data8, coeff); - res32bitLo = _mm_unpacklo_epi16(resLo, resHi); - res32bitHi = _mm_unpackhi_epi16(resLo, resHi); - - // Load the 4 32-bit integers values, add the values we computed and store them back - res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 8]); - res = _mm_add_epi32(res, res32bitLo); - _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 8], res); - // Repeat the same operation for the next 4 values - res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 12]); - res = _mm_add_epi32(res, res32bitHi); - _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 12], res); - } - for (int x = xEnd16; x < xEnd; x++) { - tmp[x - xOffset] += (int)(in[x] * kernel[k]); - } - } - for (int x = 0; x < width16; x += 16) { - // Load 4 32-bit integer values and divide them - __m128i accum1 = _mm_load_si128((__m128i*)&tmp[x]); - accum1 = accum1 / divisorLibdivide; - // Repeat the same operation on the next 4 32-bit integer values - __m128i accum2 = _mm_load_si128((__m128i*)&tmp[x + 4]); - accum2 = accum2 / divisorLibdivide; - // Pack the 8 32-bit integers into 8 16-bit integers - accum1 = _mm_packs_epi32(accum1, accum2); - - // Load 4 32-bit integer values and divide them - __m128i accum3 = _mm_load_si128((__m128i*)&tmp[x + 8]); - accum3 = accum3 / divisorLibdivide; - // Repeat the same operation on the next 4 32-bit integer values - __m128i accum4 = _mm_load_si128((__m128i*)&tmp[x + 12]); - accum4 = accum4 / divisorLibdivide; - // Pack the 8 32-bit integers into 8 16-bit integers - accum3 = _mm_packs_epi32(accum3, accum4); - - // Pack the 16 16-bit integers into 16 8-bit unsigned integers - accum1 = _mm_packus_epi16(accum1, accum3); - - // Store the 16 8-bit unsigned integers - _mm_store_si128((__m128i*)&out[x], accum1); - } - for (int x = width16; x < width; x++) { - int accum = tmp[x] / divisor; - if (accum > 255) { - accum = 255; - } else if (accum < 0) { - accum = 0; - } - out[x] = (unsigned char)accum; - } - } - - _aligned_free(tmp); -} - - -// Filter an image in vertical direction with a one-dimensional filter -void SeparableFilterY_SSE2(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, - short* kernel, int kernel_size, int divisor) -{ - int width16 = width & ~15; - int* tmp = (int*)_aligned_malloc(stride * sizeof(int), 16); - libdivide::divider divisorLibdivide(divisor); - -#ifdef _OPENMP - #pragma omp parallel for -#endif - for (int y = 0; y < height; y++) { - ZeroMemory(tmp, stride * sizeof(int)); - - const unsigned char* in = src + y * stride; - unsigned char* out = dst + y * stride; - - int kOffset = kernel_size / 2; - int kStart = 0; - int kEnd = kernel_size; - if (y < kOffset) { // 0 > y - kOffset - kStart += kOffset - y; - } else if (height <= y + kOffset) { - kEnd -= kOffset + y + 1 - height; - } - for (int k = kStart; k < kEnd; k++) { - __m128i coeff = _mm_set1_epi16(kernel[k]); - for (int x = 0; x < width16; x += 16) { - // Load 16 values - __m128i data16 = _mm_load_si128((__m128i*)&in[(k - kOffset) * stride + x]); - - // Multiply the first 8 values by the coefficient to get 8 32-bit integers - __m128i data8 = _mm_unpacklo_epi8(data16, _mm_setzero_si128()); - __m128i resLo = _mm_mullo_epi16(data8, coeff); - __m128i resHi = _mm_mulhi_epi16(data8, coeff); - __m128i res32bitLo = _mm_unpacklo_epi16(resLo, resHi); - __m128i res32bitHi = _mm_unpackhi_epi16(resLo, resHi); - - // Load the 4 32-bit integers values, add the values we computed and store them back - __m128i res = _mm_load_si128((__m128i*)&tmp[x]); - res = _mm_add_epi32(res, res32bitLo); - _mm_store_si128((__m128i*)&tmp[x], res); - // Repeat the same operation for the next 4 values - res = _mm_load_si128((__m128i*)&tmp[x + 4]); - res = _mm_add_epi32(res, res32bitHi); - _mm_store_si128((__m128i*)&tmp[x + 4], res); - - // Multiply the next 8 values by the coefficient to get 8 32-bit integers - data8 = _mm_unpackhi_epi8(data16, _mm_setzero_si128()); - resLo = _mm_mullo_epi16(data8, coeff); - resHi = _mm_mulhi_epi16(data8, coeff); - res32bitLo = _mm_unpacklo_epi16(resLo, resHi); - res32bitHi = _mm_unpackhi_epi16(resLo, resHi); - - // Load the 4 32-bit integers values, add the values we computed and store them back - res = _mm_load_si128((__m128i*)&tmp[x + 8]); - res = _mm_add_epi32(res, res32bitLo); - _mm_store_si128((__m128i*)&tmp[x + 8], res); - // Repeat the same operation for the next 4 values - res = _mm_load_si128((__m128i*)&tmp[x + 12]); - res = _mm_add_epi32(res, res32bitHi); - _mm_store_si128((__m128i*)&tmp[x + 12], res); - } - for (int x = width16; x < width; x++) { - tmp[x] += (int)(in[(k - kOffset) * stride + x] * kernel[k]); - } - } - for (int x = 0; x < width16; x += 16) { - // Load 4 32-bit integer values and divide them - __m128i accum1 = _mm_load_si128((__m128i*)&tmp[x]); - accum1 = accum1 / divisorLibdivide; - // Repeat the same operation on the next 4 32-bit integer values - __m128i accum2 = _mm_load_si128((__m128i*)&tmp[x + 4]); - accum2 = accum2 / divisorLibdivide; - // Pack the 8 32-bit integers into 8 16-bit integers - accum1 = _mm_packs_epi32(accum1, accum2); - - // Load 4 32-bit integer values and divide them - __m128i accum3 = _mm_load_si128((__m128i*)&tmp[x + 8]); - accum3 = accum3 / divisorLibdivide; - // Repeat the same operation on the next 4 32-bit integer values - __m128i accum4 = _mm_load_si128((__m128i*)&tmp[x + 12]); - accum4 = accum4 / divisorLibdivide; - // Pack the 8 32-bit integers into 8 16-bit integers - accum3 = _mm_packs_epi32(accum3, accum4); - - // Pack the 16 16-bit integers into 16 8-bit unsigned integers - accum1 = _mm_packus_epi16(accum1, accum3); - - // Store the 16 8-bit unsigned integers - _mm_store_si128((__m128i*)&out[x], accum1); - } - for (int x = width16; x < width; x++) { - int accum = tmp[x] / divisor; - if (accum > 255) { - accum = 255; - } else if (accum < 0) { - accum = 0; - } - out[x] = (unsigned char)accum; - } - } - - _aligned_free(tmp); -} - - - -static inline double NormalDist(double sigma, double x) -{ - if (sigma <= 0.000000001) { - return (x == 0.0) ? 1.0 : 0.0; - } else { - return exp(-(x * x) / (2 * sigma * sigma)) / (sigma * sqrt(2 * M_PI)); - } -} - - -struct GaussianKernel { - short* kernel; - int width; - int divisor; - - inline GaussianKernel(double sigma) { - width = (int)(sigma * 3.0 + 0.5) | 1; // binary-or with 1 to make sure the number is odd - if (width < 3) { - width = 3; - } - kernel = DEBUG_NEW short[width]; - kernel[width / 2] = (short)(NormalDist(sigma, 0.0) * 255); - divisor = kernel[width / 2]; - for (int x = width / 2 - 1; x >= 0; x--) { - short val = (short)(NormalDist(sigma, width / 2 - x) * 255 + 0.5); - divisor += val * 2; - kernel[x] = val; - kernel[width - x - 1] = val; - } - if (divisor == 0) { divisor = 1; } // workaround to prevent crash - } - - inline ~GaussianKernel() { - delete [] kernel; - } - - GaussianKernel(const GaussianKernel&) = delete; - GaussianKernel& operator=(const GaussianKernel&) = delete; -}; +/* +* (C) 2007 Niels Martin Hansen +* (C) 2013-2017 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 . +* +*/ + +#pragma once + +#include + +#define LIBDIVIDE_USE_SSE2 1 +#pragma warning(push) +#pragma warning(disable: 4244 4456 4702) +#include "libdivide.h" +#pragma warning(pop) + +// Filter an image in horizontal direction with a one-dimensional filter +// PixelWidth is the distance in bytes between pixels +template +void SeparableFilterX(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, + short* kernel, int kernel_size, int divisor) +{ + int* tmp = DEBUG_NEW int[width]; + + for (int y = 0; y < height; y++) { + ZeroMemory(tmp, width * sizeof(int)); + + const unsigned char* in = src + y * stride; + unsigned char* out = dst + y * stride; + + for (int k = 0; k < kernel_size; k++) { + int xOffset = k - kernel_size / 2; + int xStart = 0; + int xEnd = width; + if (xOffset < 0) { + xEnd += xOffset; + } else if (xOffset > 0) { + xStart += xOffset; + } + for (int x = xStart; x < xEnd; x++) { + tmp[x - xOffset] += (int)(in[x * PixelDist] * kernel[k]); + } + } + for (int x = 0; x < width; x++) { + int accum = tmp[x] / divisor; + if (accum > 255) { + accum = 255; + } else if (accum < 0) { + accum = 0; + } + out[x * PixelDist] = (unsigned char)accum; + } + } + + delete [] tmp; +} + + +// Filter an image in vertical direction with a one-dimensional filter +// PixelWidth is the distance in bytes between pixels +template +void SeparableFilterY(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, + short* kernel, int kernel_size, int divisor) +{ + int* tmp = DEBUG_NEW int[width]; + + for (int y = 0; y < height; y++) { + ZeroMemory(tmp, width * sizeof(int)); + + const unsigned char* in = src + y * stride; + unsigned char* out = dst + y * stride; + + int kOffset = kernel_size / 2; + int kStart = 0; + int kEnd = kernel_size; + if (y < kOffset) { // 0 > y - kOffset + kStart += kOffset - y; + } else if (height <= y + kOffset) { + kEnd -= kOffset + y + 1 - height; + } + for (int k = kStart; k < kEnd; k++) { + for (int x = 0; x < width; x++) { + tmp[x] += (int)(in[(k - kOffset) * stride + x * PixelDist] * kernel[k]); + } + } + for (int x = 0; x < width; x++) { + int accum = tmp[x] / divisor; + if (accum > 255) { + accum = 255; + } else if (accum < 0) { + accum = 0; + } + out[x * PixelDist] = (unsigned char)accum; + } + } + + delete [] tmp; +} + + +// Filter an image in horizontal direction with a one-dimensional filter +void SeparableFilterX_SSE2(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, + short* kernel, int kernel_size, int divisor) +{ + int width16 = width & ~15; + int* tmp = (int*)_aligned_malloc(stride * sizeof(int), 16); + libdivide::divider divisorLibdivide(divisor); + + for (int y = 0; y < height; y++) { + ZeroMemory(tmp, stride * sizeof(int)); + + const unsigned char* in = src + y * stride; + unsigned char* out = dst + y * stride; + + for (int k = 0; k < kernel_size; k++) { + int xOffset = k - kernel_size / 2; + int xStart = 0; + int xEnd = width; + if (xOffset < 0) { + xEnd += xOffset; + } else if (xOffset > 0) { + xStart += xOffset; + } + int xStart16 = (xStart + 15) & ~15; + int xEnd16 = xEnd & ~15; + if (xStart16 >= xEnd16) { // Don't use SSE2 at all + xStart16 = xEnd16 = xEnd; + } + for (int x = xStart; x < xStart16; x++) { + tmp[x - xOffset] += (int)(in[x] * kernel[k]); + } + __m128i coeff = _mm_set1_epi16(kernel[k]); + for (int x = xStart16; x < xEnd16; x += 16) { + // Load 16 values + __m128i data16 = _mm_load_si128((__m128i*)&in[x]); + + // Multiply the first 8 values by the coefficient to get 8 32-bit integers + __m128i data8 = _mm_unpacklo_epi8(data16, _mm_setzero_si128()); + __m128i resLo = _mm_mullo_epi16(data8, coeff); + __m128i resHi = _mm_mulhi_epi16(data8, coeff); + __m128i res32bitLo = _mm_unpacklo_epi16(resLo, resHi); + __m128i res32bitHi = _mm_unpackhi_epi16(resLo, resHi); + + // Load the 4 32-bit integers values, add the values we computed and store them back + __m128i res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset]); + res = _mm_add_epi32(res, res32bitLo); + _mm_storeu_si128((__m128i*)&tmp[x - xOffset], res); + // Repeat the same operation for the next 4 values + res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 4]); + res = _mm_add_epi32(res, res32bitHi); + _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 4], res); + + // Multiply the next 8 values by the coefficient to get 8 32-bit integers + data8 = _mm_unpackhi_epi8(data16, _mm_setzero_si128()); + resLo = _mm_mullo_epi16(data8, coeff); + resHi = _mm_mulhi_epi16(data8, coeff); + res32bitLo = _mm_unpacklo_epi16(resLo, resHi); + res32bitHi = _mm_unpackhi_epi16(resLo, resHi); + + // Load the 4 32-bit integers values, add the values we computed and store them back + res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 8]); + res = _mm_add_epi32(res, res32bitLo); + _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 8], res); + // Repeat the same operation for the next 4 values + res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 12]); + res = _mm_add_epi32(res, res32bitHi); + _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 12], res); + } + for (int x = xEnd16; x < xEnd; x++) { + tmp[x - xOffset] += (int)(in[x] * kernel[k]); + } + } + for (int x = 0; x < width16; x += 16) { + // Load 4 32-bit integer values and divide them + __m128i accum1 = _mm_load_si128((__m128i*)&tmp[x]); + accum1 = accum1 / divisorLibdivide; + // Repeat the same operation on the next 4 32-bit integer values + __m128i accum2 = _mm_load_si128((__m128i*)&tmp[x + 4]); + accum2 = accum2 / divisorLibdivide; + // Pack the 8 32-bit integers into 8 16-bit integers + accum1 = _mm_packs_epi32(accum1, accum2); + + // Load 4 32-bit integer values and divide them + __m128i accum3 = _mm_load_si128((__m128i*)&tmp[x + 8]); + accum3 = accum3 / divisorLibdivide; + // Repeat the same operation on the next 4 32-bit integer values + __m128i accum4 = _mm_load_si128((__m128i*)&tmp[x + 12]); + accum4 = accum4 / divisorLibdivide; + // Pack the 8 32-bit integers into 8 16-bit integers + accum3 = _mm_packs_epi32(accum3, accum4); + + // Pack the 16 16-bit integers into 16 8-bit unsigned integers + accum1 = _mm_packus_epi16(accum1, accum3); + + // Store the 16 8-bit unsigned integers + _mm_store_si128((__m128i*)&out[x], accum1); + } + for (int x = width16; x < width; x++) { + int accum = tmp[x] / divisor; + if (accum > 255) { + accum = 255; + } else if (accum < 0) { + accum = 0; + } + out[x] = (unsigned char)accum; + } + } + + _aligned_free(tmp); +} + + +// Filter an image in vertical direction with a one-dimensional filter +void SeparableFilterY_SSE2(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, + short* kernel, int kernel_size, int divisor) +{ + int width16 = width & ~15; + int* tmp = (int*)_aligned_malloc(stride * sizeof(int), 16); + libdivide::divider divisorLibdivide(divisor); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < height; y++) { + ZeroMemory(tmp, stride * sizeof(int)); + + const unsigned char* in = src + y * stride; + unsigned char* out = dst + y * stride; + + int kOffset = kernel_size / 2; + int kStart = 0; + int kEnd = kernel_size; + if (y < kOffset) { // 0 > y - kOffset + kStart += kOffset - y; + } else if (height <= y + kOffset) { + kEnd -= kOffset + y + 1 - height; + } + for (int k = kStart; k < kEnd; k++) { + __m128i coeff = _mm_set1_epi16(kernel[k]); + for (int x = 0; x < width16; x += 16) { + // Load 16 values + __m128i data16 = _mm_load_si128((__m128i*)&in[(k - kOffset) * stride + x]); + + // Multiply the first 8 values by the coefficient to get 8 32-bit integers + __m128i data8 = _mm_unpacklo_epi8(data16, _mm_setzero_si128()); + __m128i resLo = _mm_mullo_epi16(data8, coeff); + __m128i resHi = _mm_mulhi_epi16(data8, coeff); + __m128i res32bitLo = _mm_unpacklo_epi16(resLo, resHi); + __m128i res32bitHi = _mm_unpackhi_epi16(resLo, resHi); + + // Load the 4 32-bit integers values, add the values we computed and store them back + __m128i res = _mm_load_si128((__m128i*)&tmp[x]); + res = _mm_add_epi32(res, res32bitLo); + _mm_store_si128((__m128i*)&tmp[x], res); + // Repeat the same operation for the next 4 values + res = _mm_load_si128((__m128i*)&tmp[x + 4]); + res = _mm_add_epi32(res, res32bitHi); + _mm_store_si128((__m128i*)&tmp[x + 4], res); + + // Multiply the next 8 values by the coefficient to get 8 32-bit integers + data8 = _mm_unpackhi_epi8(data16, _mm_setzero_si128()); + resLo = _mm_mullo_epi16(data8, coeff); + resHi = _mm_mulhi_epi16(data8, coeff); + res32bitLo = _mm_unpacklo_epi16(resLo, resHi); + res32bitHi = _mm_unpackhi_epi16(resLo, resHi); + + // Load the 4 32-bit integers values, add the values we computed and store them back + res = _mm_load_si128((__m128i*)&tmp[x + 8]); + res = _mm_add_epi32(res, res32bitLo); + _mm_store_si128((__m128i*)&tmp[x + 8], res); + // Repeat the same operation for the next 4 values + res = _mm_load_si128((__m128i*)&tmp[x + 12]); + res = _mm_add_epi32(res, res32bitHi); + _mm_store_si128((__m128i*)&tmp[x + 12], res); + } + for (int x = width16; x < width; x++) { + tmp[x] += (int)(in[(k - kOffset) * stride + x] * kernel[k]); + } + } + for (int x = 0; x < width16; x += 16) { + // Load 4 32-bit integer values and divide them + __m128i accum1 = _mm_load_si128((__m128i*)&tmp[x]); + accum1 = accum1 / divisorLibdivide; + // Repeat the same operation on the next 4 32-bit integer values + __m128i accum2 = _mm_load_si128((__m128i*)&tmp[x + 4]); + accum2 = accum2 / divisorLibdivide; + // Pack the 8 32-bit integers into 8 16-bit integers + accum1 = _mm_packs_epi32(accum1, accum2); + + // Load 4 32-bit integer values and divide them + __m128i accum3 = _mm_load_si128((__m128i*)&tmp[x + 8]); + accum3 = accum3 / divisorLibdivide; + // Repeat the same operation on the next 4 32-bit integer values + __m128i accum4 = _mm_load_si128((__m128i*)&tmp[x + 12]); + accum4 = accum4 / divisorLibdivide; + // Pack the 8 32-bit integers into 8 16-bit integers + accum3 = _mm_packs_epi32(accum3, accum4); + + // Pack the 16 16-bit integers into 16 8-bit unsigned integers + accum1 = _mm_packus_epi16(accum1, accum3); + + // Store the 16 8-bit unsigned integers + _mm_store_si128((__m128i*)&out[x], accum1); + } + for (int x = width16; x < width; x++) { + int accum = tmp[x] / divisor; + if (accum > 255) { + accum = 255; + } else if (accum < 0) { + accum = 0; + } + out[x] = (unsigned char)accum; + } + } + + _aligned_free(tmp); +} + + + +static inline double NormalDist(double sigma, double x) +{ + if (sigma <= 0.000000001) { + return (x == 0.0) ? 1.0 : 0.0; + } else { + return exp(-(x * x) / (2 * sigma * sigma)) / (sigma * sqrt(2 * M_PI)); + } +} + + +struct GaussianKernel { + short* kernel; + int width; + int divisor; + + inline GaussianKernel(double sigma) { + width = (int)(sigma * 3.0 + 0.5) | 1; // binary-or with 1 to make sure the number is odd + if (width < 3) { + width = 3; + } + kernel = DEBUG_NEW short[width]; + kernel[width / 2] = (short)(NormalDist(sigma, 0.0) * 255); + divisor = kernel[width / 2]; + for (int x = width / 2 - 1; x >= 0; x--) { + short val = (short)(NormalDist(sigma, width / 2 - x) * 255 + 0.5); + divisor += val * 2; + kernel[x] = val; + kernel[width - x - 1] = val; + } + if (divisor == 0) { divisor = 1; } // workaround to prevent crash + } + + inline ~GaussianKernel() { + delete [] kernel; + } + + GaussianKernel(const GaussianKernel&) = delete; + GaussianKernel& operator=(const GaussianKernel&) = delete; +}; diff --git a/src/Subtitles/SubtitleInputPin.cpp b/src/Subtitles/SubtitleInputPin.cpp index 3d0a2f8614e..b5feffb2dde 100644 --- a/src/Subtitles/SubtitleInputPin.cpp +++ b/src/Subtitles/SubtitleInputPin.cpp @@ -1,541 +1,541 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "SubtitleInputPin.h" -#include "VobSubFile.h" -#include "RTS.h" -#include "DVBSub.h" -#include "PGSSub.h" - -#include -#include "moreuuids.h" -#include "../DSUtil/ISOLang.h" - -#if !TRACE_SUBTITLES -#undef TRACE -#define TRACE(...) -#endif - -// our first format id -#define __GAB1__ "GAB1" - -// our tags for __GAB1__ (ushort) + size (ushort) - -// "lang" + '0' -#define __GAB1_LANGUAGE__ 0 -// (int)start+(int)stop+(char*)line+'0' -#define __GAB1_ENTRY__ 1 -// L"lang" + '0' -#define __GAB1_LANGUAGE_UNICODE__ 2 -// (int)start+(int)stop+(WCHAR*)line+'0' -#define __GAB1_ENTRY_UNICODE__ 3 - -// same as __GAB1__, but the size is (uint) and only __GAB1_LANGUAGE_UNICODE__ is valid -#define __GAB2__ "GAB2" - -// (BYTE*) -#define __GAB1_RAWTEXTSUBTITLE__ 4 - -CSubtitleInputPin::CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr) - : CBaseInputPin(NAME("CSubtitleInputPin"), pFilter, pLock, phr, L"Input") - , m_pSubLock(pSubLock) - , m_bExitDecodingThread(false) - , m_bStopDecoding(false) -{ - m_bCanReconnectWhenActive = true; - m_decodeThread = std::thread([this]() { - DecodeSamples(); - }); -} - -CSubtitleInputPin::~CSubtitleInputPin() -{ - m_bExitDecodingThread = m_bStopDecoding = true; - m_condQueueReady.notify_one(); - if (m_decodeThread.joinable()) { - m_decodeThread.join(); - } -} - -HRESULT CSubtitleInputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Text && (pmt->subtype == MEDIASUBTYPE_NULL || pmt->subtype == FOURCCMap((DWORD)0)) - || pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_UTF8 || pmt->subtype == MEDIASUBTYPE_SSA || pmt->subtype == MEDIASUBTYPE_ASS || pmt->subtype == MEDIASUBTYPE_ASS2 || pmt->subtype == MEDIASUBTYPE_VOBSUB || pmt->subtype == MEDIASUBTYPE_WEBVTT) - || IsRLECodedSub(pmt) - ? S_OK - : E_FAIL; -} - -HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin) -{ - InvalidateSamples(); - - if (m_mt.majortype == MEDIATYPE_Text) { - if (!(m_pSubStream = DEBUG_NEW CRenderedTextSubtitle(m_pSubLock))) { - return E_FAIL; - } - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; - pRTS->m_name = CString(GetPinName(pReceivePin)) + _T(" (embedded)"); - pRTS->m_storageRes = pRTS->m_playRes = CSize(384, 288); - pRTS->CreateDefaultStyle(DEFAULT_CHARSET); - } else if (m_mt.majortype == MEDIATYPE_Subtitle) { - SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; - DWORD dwOffset = 0; - CString name; - LCID lcid = 0; - - if (psi != nullptr) { - dwOffset = psi->dwOffset; - - lcid = ISOLang::ISO6392ToLcid(psi->IsoLang); - if (0 == lcid) { //try 639-1 in case it comes from BCP-47 (contains mix of 639-1 and 639-2) - lcid = ISOLang::ISO6391ToLcid(psi->IsoLang); - } - name = ISOLang::ISO639XToLanguage(psi->IsoLang); - - CString trackName(psi->TrackName); - trackName.Trim(); - if (!trackName.IsEmpty()) { - if (!name.IsEmpty()) { - if (trackName[0] != _T('(') && trackName[0] != _T('[')) { - name += _T(","); - } - name += _T(" "); - } - name += trackName; - } - if (name.IsEmpty()) { - name = _T("Unknown"); - } - } - - name.Replace(_T(""), _T("")); - name.Replace(_T(""), _T("")); - - bool subtype_utf8 = m_mt.subtype == MEDIASUBTYPE_UTF8; - bool subtype_vtt = m_mt.subtype == MEDIASUBTYPE_WEBVTT; - bool subtype_ass = m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2; - - if (subtype_utf8 || subtype_ass || subtype_vtt) { - if (!(m_pSubStream = DEBUG_NEW CRenderedTextSubtitle(m_pSubLock))) { - return E_FAIL; - } - - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; - pRTS->SetSubtitleTypeFromGUID(m_mt.subtype); -#if USE_LIBASS +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "SubtitleInputPin.h" +#include "VobSubFile.h" +#include "RTS.h" +#include "DVBSub.h" +#include "PGSSub.h" + +#include +#include "moreuuids.h" +#include "../DSUtil/ISOLang.h" + +#if !TRACE_SUBTITLES +#undef TRACE +#define TRACE(...) +#endif + +// our first format id +#define __GAB1__ "GAB1" + +// our tags for __GAB1__ (ushort) + size (ushort) + +// "lang" + '0' +#define __GAB1_LANGUAGE__ 0 +// (int)start+(int)stop+(char*)line+'0' +#define __GAB1_ENTRY__ 1 +// L"lang" + '0' +#define __GAB1_LANGUAGE_UNICODE__ 2 +// (int)start+(int)stop+(WCHAR*)line+'0' +#define __GAB1_ENTRY_UNICODE__ 3 + +// same as __GAB1__, but the size is (uint) and only __GAB1_LANGUAGE_UNICODE__ is valid +#define __GAB2__ "GAB2" + +// (BYTE*) +#define __GAB1_RAWTEXTSUBTITLE__ 4 + +CSubtitleInputPin::CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr) + : CBaseInputPin(NAME("CSubtitleInputPin"), pFilter, pLock, phr, L"Input") + , m_pSubLock(pSubLock) + , m_bExitDecodingThread(false) + , m_bStopDecoding(false) +{ + m_bCanReconnectWhenActive = true; + m_decodeThread = std::thread([this]() { + DecodeSamples(); + }); +} + +CSubtitleInputPin::~CSubtitleInputPin() +{ + m_bExitDecodingThread = m_bStopDecoding = true; + m_condQueueReady.notify_one(); + if (m_decodeThread.joinable()) { + m_decodeThread.join(); + } +} + +HRESULT CSubtitleInputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Text && (pmt->subtype == MEDIASUBTYPE_NULL || pmt->subtype == FOURCCMap((DWORD)0)) + || pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_UTF8 || pmt->subtype == MEDIASUBTYPE_SSA || pmt->subtype == MEDIASUBTYPE_ASS || pmt->subtype == MEDIASUBTYPE_ASS2 || pmt->subtype == MEDIASUBTYPE_VOBSUB || pmt->subtype == MEDIASUBTYPE_WEBVTT) + || IsRLECodedSub(pmt) + ? S_OK + : E_FAIL; +} + +HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin) +{ + InvalidateSamples(); + + if (m_mt.majortype == MEDIATYPE_Text) { + if (!(m_pSubStream = DEBUG_NEW CRenderedTextSubtitle(m_pSubLock))) { + return E_FAIL; + } + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; + pRTS->m_name = CString(GetPinName(pReceivePin)) + _T(" (embedded)"); + pRTS->m_storageRes = pRTS->m_playRes = CSize(384, 288); + pRTS->CreateDefaultStyle(DEFAULT_CHARSET); + } else if (m_mt.majortype == MEDIATYPE_Subtitle) { + SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; + DWORD dwOffset = 0; + CString name; + LCID lcid = 0; + + if (psi != nullptr) { + dwOffset = psi->dwOffset; + + lcid = ISOLang::ISO6392ToLcid(psi->IsoLang); + if (0 == lcid) { //try 639-1 in case it comes from BCP-47 (contains mix of 639-1 and 639-2) + lcid = ISOLang::ISO6391ToLcid(psi->IsoLang); + } + name = ISOLang::ISO639XToLanguage(psi->IsoLang); + + CString trackName(psi->TrackName); + trackName.Trim(); + if (!trackName.IsEmpty()) { + if (!name.IsEmpty()) { + if (trackName[0] != _T('(') && trackName[0] != _T('[')) { + name += _T(","); + } + name += _T(" "); + } + name += trackName; + } + if (name.IsEmpty()) { + name = _T("Unknown"); + } + } + + name.Replace(_T(""), _T("")); + name.Replace(_T(""), _T("")); + + bool subtype_utf8 = m_mt.subtype == MEDIASUBTYPE_UTF8; + bool subtype_vtt = m_mt.subtype == MEDIASUBTYPE_WEBVTT; + bool subtype_ass = m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2; + + if (subtype_utf8 || subtype_ass || subtype_vtt) { + if (!(m_pSubStream = DEBUG_NEW CRenderedTextSubtitle(m_pSubLock))) { + return E_FAIL; + } + + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; + pRTS->SetSubtitleTypeFromGUID(m_mt.subtype); +#if USE_LIBASS if (pRTS->m_LibassContext.CheckSubType()) { pRTS->m_LibassContext.SetFilterGraphFromFilter(m_pFilter); } #endif - pRTS->m_name = name; - pRTS->m_lcid = lcid; - if (lcid > 0) { - pRTS->m_langname = ISOLang::LCIDToLanguage(lcid); - } - pRTS->m_storageRes = pRTS->m_playRes = CSize(384, 288); - pRTS->CreateDefaultStyle(DEFAULT_CHARSET); - - if (dwOffset > 0 && m_mt.cbFormat - dwOffset > 0) { - CMediaType mt = m_mt; - if (mt.pbFormat[dwOffset + 0] != 0xef - && mt.pbFormat[dwOffset + 1] != 0xbb - && mt.pbFormat[dwOffset + 2] != 0xfb) { - dwOffset -= 3; - mt.pbFormat[dwOffset + 0] = 0xef; - mt.pbFormat[dwOffset + 1] = 0xbb; - mt.pbFormat[dwOffset + 2] = 0xbf; - } - - // process with own parser first, even when using libass, since we need certain info like PlayRes - pRTS->Open(mt.pbFormat + dwOffset, mt.cbFormat - dwOffset, DEFAULT_CHARSET, pRTS->m_name); -#if USE_LIBASS + pRTS->m_name = name; + pRTS->m_lcid = lcid; + if (lcid > 0) { + pRTS->m_langname = ISOLang::LCIDToLanguage(lcid); + } + pRTS->m_storageRes = pRTS->m_playRes = CSize(384, 288); + pRTS->CreateDefaultStyle(DEFAULT_CHARSET); + + if (dwOffset > 0 && m_mt.cbFormat - dwOffset > 0) { + CMediaType mt = m_mt; + if (mt.pbFormat[dwOffset + 0] != 0xef + && mt.pbFormat[dwOffset + 1] != 0xbb + && mt.pbFormat[dwOffset + 2] != 0xfb) { + dwOffset -= 3; + mt.pbFormat[dwOffset + 0] = 0xef; + mt.pbFormat[dwOffset + 1] = 0xbb; + mt.pbFormat[dwOffset + 2] = 0xbf; + } + + // process with own parser first, even when using libass, since we need certain info like PlayRes + pRTS->Open(mt.pbFormat + dwOffset, mt.cbFormat - dwOffset, DEFAULT_CHARSET, pRTS->m_name); +#if USE_LIBASS if (pRTS->m_LibassContext.m_renderUsingLibass) { bool success = pRTS->m_LibassContext.LoadASSTrack((char*)m_mt.Format() + psi->dwOffset, m_mt.FormatLength() - psi->dwOffset, subtype_ass ? Subtitle::ASS : Subtitle::SRT); pRTS->m_LibassContext.m_renderUsingLibass = success && pRTS->m_LibassContext.IsLibassActive(); } #endif - } - } else if (m_mt.subtype == MEDIASUBTYPE_VOBSUB) { - if (!(m_pSubStream = DEBUG_NEW CVobSubStream(m_pSubLock))) { - return E_FAIL; - } - CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; - pVSS->Open(name, m_mt.pbFormat + dwOffset, m_mt.cbFormat - dwOffset); - } else if (IsRLECodedSub(&m_mt)) { - if (m_mt.subtype == MEDIASUBTYPE_DVB_SUBTITLES) { - m_pSubStream = DEBUG_NEW CDVBSub(m_pSubLock, name, lcid); - } else { - m_pSubStream = DEBUG_NEW CPGSSub(m_pSubLock, name, lcid); - } - if (!m_pSubStream) { - return E_FAIL; - } - } - } - - AddSubStream(m_pSubStream); - - return __super::CompleteConnect(pReceivePin); -} - -HRESULT CSubtitleInputPin::BreakConnect() -{ - InvalidateSamples(); - - RemoveSubStream(m_pSubStream); - m_pSubStream = nullptr; - - ASSERT(IsStopped()); - - return __super::BreakConnect(); -} - -STDMETHODIMP CSubtitleInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) -{ - if (m_Connected) { - InvalidateSamples(); - - RemoveSubStream(m_pSubStream); - m_pSubStream = nullptr; - - m_Connected->Release(); - m_Connected = nullptr; - } - - return __super::ReceiveConnection(pConnector, pmt); -} - -STDMETHODIMP CSubtitleInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - CAutoLock cAutoLock(&m_csReceive); - - InvalidateSamples(); - - if (m_mt.majortype == MEDIATYPE_Text || m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_UTF8 - || m_mt.subtype == MEDIASUBTYPE_WEBVTT || m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS - || m_mt.subtype == MEDIASUBTYPE_ASS2)) { - CAutoLock cAutoLock2(m_pSubLock); - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; - if (pRTS->m_webvtt_allow_clear || pRTS->m_subtitleType != Subtitle::VTT) { - pRTS->RemoveAll(); - pRTS->CreateSegments(); - pRTS->FlushEventsLibass(); - } - // WebVTT can be read as one big blob of data during pin connection, instead of as samples during playback. - // This depends on how it is being demuxed. So clear only if we previously got data through samples. - } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_VOBSUB)) { - CAutoLock cAutoLock2(m_pSubLock); - CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; - pVSS->RemoveAll(); - } else if (IsRLECodedSub(&m_mt)) { - CAutoLock cAutoLock2(m_pSubLock); - CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; - pRLECodedSubtitle->NewSegment(tStart, tStop, dRate); - } - - TRACE(_T("NewSegment: InvalidateSubtitle %.3f\n"), RT2SEC(tStart)); - // IMPORTANT: m_pSubLock must not be locked when calling this - InvalidateSubtitle(tStart, m_pSubStream); - - return __super::NewSegment(tStart, tStop, dRate); -} - -STDMETHODIMP CSubtitleInputPin::Receive(IMediaSample* pSample) -{ - HRESULT hr = __super::Receive(pSample); - if (FAILED(hr)) { - return hr; - } - - CAutoLock cAutoLock(&m_csReceive); - - REFERENCE_TIME tStart, tStop; - hr = pSample->GetTime(&tStart, &tStop); - - switch (hr) { - case S_OK: - tStart += m_tStart; - tStop += m_tStart; - break; - case VFW_S_NO_STOP_TIME: - tStart += m_tStart; - tStop = INVALID_TIME; - break; - case VFW_E_SAMPLE_TIME_NOT_SET: - tStart = tStop = INVALID_TIME; - break; - default: - ASSERT(FALSE); - return hr; - } - - if ((tStart == INVALID_TIME || tStop == INVALID_TIME) && !IsRLECodedSub(&m_mt)) { - ASSERT(FALSE); - } else { - BYTE* pData = nullptr; - hr = pSample->GetPointer(&pData); - long len = pSample->GetActualDataLength(); - if (FAILED(hr) || pData == nullptr || len <= 0) { - return hr; - } - - { - std::unique_lock lock(m_mutexQueue); - m_sampleQueue.emplace_back(DEBUG_NEW SubtitleSample(tStart, tStop, pData, size_t(len))); - lock.unlock(); - m_condQueueReady.notify_one(); - } - } - - return S_OK; -} - -STDMETHODIMP CSubtitleInputPin::EndOfStream(void) -{ - HRESULT hr = __super::EndOfStream(); - - if (SUCCEEDED(hr)) { - std::unique_lock lock(m_mutexQueue); - m_sampleQueue.emplace_back(nullptr); // nullptr means end of stream - lock.unlock(); - m_condQueueReady.notify_one(); - } - - return hr; -} - -bool CSubtitleInputPin::IsRLECodedSub(const CMediaType* pmt) const -{ - return !!(pmt->majortype == MEDIATYPE_Subtitle - && (pmt->subtype == MEDIASUBTYPE_HDMVSUB // Blu-Ray presentation graphics - || pmt->subtype == MEDIASUBTYPE_DVB_SUBTITLES // DVB subtitles - || (pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_SubtitleInfo))); // Workaround : support for Haali PGS -} - -void CSubtitleInputPin::DecodeSamples() -{ - SetThreadName(DWORD(-1), "Subtitle Input Pin Thread"); - - for (; !m_bExitDecodingThread;) { - std::unique_lock lock(m_mutexQueue); - - auto needStopProcessing = [this]() { - return m_bStopDecoding || m_bExitDecodingThread; - }; - - auto isQueueReady = [&]() { - return !m_sampleQueue.empty() || needStopProcessing(); - }; - - m_condQueueReady.wait(lock, isQueueReady); - lock.unlock(); // Release this lock until we can acquire the other one - - REFERENCE_TIME rtInvalidate = -1; - - if (!needStopProcessing()) { - CAutoLock cAutoLock(m_pSubLock); - lock.lock(); // Reacquire the lock - - while (!m_sampleQueue.empty() && !needStopProcessing()) { - const auto& pSample = m_sampleQueue.front(); - - if (pSample) { - REFERENCE_TIME rtSampleInvalidate = DecodeSample(pSample); - if (rtSampleInvalidate >= 0 && (rtSampleInvalidate < rtInvalidate || rtInvalidate < 0)) { - rtInvalidate = rtSampleInvalidate; - } - } else { // marker for end of stream - if (IsRLECodedSub(&m_mt)) { - CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; - pRLECodedSubtitle->EndOfStream(); - } - } - - m_sampleQueue.pop_front(); - } - } - - if (rtInvalidate >= 0) { - //TRACE(_T("NewSegment: InvalidateSubtitle %.3f\n"), double(rtInvalidate) / 10000000.0); - // IMPORTANT: m_pSubLock must not be locked when calling this - InvalidateSubtitle(rtInvalidate, m_pSubStream); - } - } -} - -REFERENCE_TIME CSubtitleInputPin::DecodeSample(const std::unique_ptr& pSample) -{ - bool bInvalidate = false; - + } + } else if (m_mt.subtype == MEDIASUBTYPE_VOBSUB) { + if (!(m_pSubStream = DEBUG_NEW CVobSubStream(m_pSubLock))) { + return E_FAIL; + } + CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; + pVSS->Open(name, m_mt.pbFormat + dwOffset, m_mt.cbFormat - dwOffset); + } else if (IsRLECodedSub(&m_mt)) { + if (m_mt.subtype == MEDIASUBTYPE_DVB_SUBTITLES) { + m_pSubStream = DEBUG_NEW CDVBSub(m_pSubLock, name, lcid); + } else { + m_pSubStream = DEBUG_NEW CPGSSub(m_pSubLock, name, lcid); + } + if (!m_pSubStream) { + return E_FAIL; + } + } + } + + AddSubStream(m_pSubStream); + + return __super::CompleteConnect(pReceivePin); +} + +HRESULT CSubtitleInputPin::BreakConnect() +{ + InvalidateSamples(); + + RemoveSubStream(m_pSubStream); + m_pSubStream = nullptr; + + ASSERT(IsStopped()); + + return __super::BreakConnect(); +} + +STDMETHODIMP CSubtitleInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) +{ + if (m_Connected) { + InvalidateSamples(); + + RemoveSubStream(m_pSubStream); + m_pSubStream = nullptr; + + m_Connected->Release(); + m_Connected = nullptr; + } + + return __super::ReceiveConnection(pConnector, pmt); +} + +STDMETHODIMP CSubtitleInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CAutoLock cAutoLock(&m_csReceive); + + InvalidateSamples(); + + if (m_mt.majortype == MEDIATYPE_Text || m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_UTF8 + || m_mt.subtype == MEDIASUBTYPE_WEBVTT || m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS + || m_mt.subtype == MEDIASUBTYPE_ASS2)) { + CAutoLock cAutoLock2(m_pSubLock); + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; + if (pRTS->m_webvtt_allow_clear || pRTS->m_subtitleType != Subtitle::VTT) { + pRTS->RemoveAll(); + pRTS->CreateSegments(); + pRTS->FlushEventsLibass(); + } + // WebVTT can be read as one big blob of data during pin connection, instead of as samples during playback. + // This depends on how it is being demuxed. So clear only if we previously got data through samples. + } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_VOBSUB)) { + CAutoLock cAutoLock2(m_pSubLock); + CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; + pVSS->RemoveAll(); + } else if (IsRLECodedSub(&m_mt)) { + CAutoLock cAutoLock2(m_pSubLock); + CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; + pRLECodedSubtitle->NewSegment(tStart, tStop, dRate); + } + + TRACE(_T("NewSegment: InvalidateSubtitle %.3f\n"), RT2SEC(tStart)); + // IMPORTANT: m_pSubLock must not be locked when calling this + InvalidateSubtitle(tStart, m_pSubStream); + + return __super::NewSegment(tStart, tStop, dRate); +} + +STDMETHODIMP CSubtitleInputPin::Receive(IMediaSample* pSample) +{ + HRESULT hr = __super::Receive(pSample); + if (FAILED(hr)) { + return hr; + } + + CAutoLock cAutoLock(&m_csReceive); + + REFERENCE_TIME tStart, tStop; + hr = pSample->GetTime(&tStart, &tStop); + + switch (hr) { + case S_OK: + tStart += m_tStart; + tStop += m_tStart; + break; + case VFW_S_NO_STOP_TIME: + tStart += m_tStart; + tStop = INVALID_TIME; + break; + case VFW_E_SAMPLE_TIME_NOT_SET: + tStart = tStop = INVALID_TIME; + break; + default: + ASSERT(FALSE); + return hr; + } + + if ((tStart == INVALID_TIME || tStop == INVALID_TIME) && !IsRLECodedSub(&m_mt)) { + ASSERT(FALSE); + } else { + BYTE* pData = nullptr; + hr = pSample->GetPointer(&pData); + long len = pSample->GetActualDataLength(); + if (FAILED(hr) || pData == nullptr || len <= 0) { + return hr; + } + + { + std::unique_lock lock(m_mutexQueue); + m_sampleQueue.emplace_back(DEBUG_NEW SubtitleSample(tStart, tStop, pData, size_t(len))); + lock.unlock(); + m_condQueueReady.notify_one(); + } + } + + return S_OK; +} + +STDMETHODIMP CSubtitleInputPin::EndOfStream(void) +{ + HRESULT hr = __super::EndOfStream(); + + if (SUCCEEDED(hr)) { + std::unique_lock lock(m_mutexQueue); + m_sampleQueue.emplace_back(nullptr); // nullptr means end of stream + lock.unlock(); + m_condQueueReady.notify_one(); + } + + return hr; +} + +bool CSubtitleInputPin::IsRLECodedSub(const CMediaType* pmt) const +{ + return !!(pmt->majortype == MEDIATYPE_Subtitle + && (pmt->subtype == MEDIASUBTYPE_HDMVSUB // Blu-Ray presentation graphics + || pmt->subtype == MEDIASUBTYPE_DVB_SUBTITLES // DVB subtitles + || (pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_SubtitleInfo))); // Workaround : support for Haali PGS +} + +void CSubtitleInputPin::DecodeSamples() +{ + SetThreadName(DWORD(-1), "Subtitle Input Pin Thread"); + + for (; !m_bExitDecodingThread;) { + std::unique_lock lock(m_mutexQueue); + + auto needStopProcessing = [this]() { + return m_bStopDecoding || m_bExitDecodingThread; + }; + + auto isQueueReady = [&]() { + return !m_sampleQueue.empty() || needStopProcessing(); + }; + + m_condQueueReady.wait(lock, isQueueReady); + lock.unlock(); // Release this lock until we can acquire the other one + + REFERENCE_TIME rtInvalidate = -1; + + if (!needStopProcessing()) { + CAutoLock cAutoLock(m_pSubLock); + lock.lock(); // Reacquire the lock + + while (!m_sampleQueue.empty() && !needStopProcessing()) { + const auto& pSample = m_sampleQueue.front(); + + if (pSample) { + REFERENCE_TIME rtSampleInvalidate = DecodeSample(pSample); + if (rtSampleInvalidate >= 0 && (rtSampleInvalidate < rtInvalidate || rtInvalidate < 0)) { + rtInvalidate = rtSampleInvalidate; + } + } else { // marker for end of stream + if (IsRLECodedSub(&m_mt)) { + CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; + pRLECodedSubtitle->EndOfStream(); + } + } + + m_sampleQueue.pop_front(); + } + } + + if (rtInvalidate >= 0) { + //TRACE(_T("NewSegment: InvalidateSubtitle %.3f\n"), double(rtInvalidate) / 10000000.0); + // IMPORTANT: m_pSubLock must not be locked when calling this + InvalidateSubtitle(rtInvalidate, m_pSubStream); + } + } +} + +REFERENCE_TIME CSubtitleInputPin::DecodeSample(const std::unique_ptr& pSample) +{ + bool bInvalidate = false; + if (pSample->data.size() <= 0) { return -1; } - - if (m_mt.majortype == MEDIATYPE_Text) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; - - char* pData = (char*)pSample->data.data(); - - if (!strncmp(pData, __GAB1__, strlen(__GAB1__))) { - char* ptr = &pData[strlen(__GAB1__) + 1]; - char* end = &pData[pSample->data.size()]; - - while (ptr < end) { - WORD tag = *((WORD*)(ptr)); - ptr += 2; - WORD size = *((WORD*)(ptr)); - ptr += 2; - - if (tag == __GAB1_LANGUAGE__) { - pRTS->m_name = ptr; - } else if (tag == __GAB1_ENTRY__) { - pRTS->Add(AToW(&ptr[8]), false, MS2RT(*(int*)ptr), MS2RT(*(int*)(ptr + 4))); - bInvalidate = true; - } else if (tag == __GAB1_LANGUAGE_UNICODE__) { - pRTS->m_name = (WCHAR*)ptr; - } else if (tag == __GAB1_ENTRY_UNICODE__) { - pRTS->Add((WCHAR*)(ptr + 8), true, MS2RT(*(int*)ptr), MS2RT(*(int*)(ptr + 4))); - bInvalidate = true; - } - - ptr += size; - } - } else if (!strncmp(pData, __GAB2__, strlen(__GAB2__))) { - char* ptr = &pData[strlen(__GAB2__) + 1]; - char* end = &pData[pSample->data.size()]; - - while (ptr < end) { - WORD tag = *((WORD*)(ptr)); - ptr += 2; - DWORD size = *((DWORD*)(ptr)); - ptr += 4; - - if (tag == __GAB1_LANGUAGE_UNICODE__) { - pRTS->m_name = (WCHAR*)ptr; - } else if (tag == __GAB1_RAWTEXTSUBTITLE__) { - pRTS->Open((BYTE*)ptr, size, DEFAULT_CHARSET, pRTS->m_name); - bInvalidate = true; - } - - ptr += size; - } - } else if (pSample->data.size() > 1 && *pData != '\0') { - CStringA str(pData, (int)pSample->data.size()); - - str.Replace("\r\n", "\n"); - FastTrim(str); - - if (!str.IsEmpty()) { - pRTS->Add(AToW(str), false, pSample->rtStart, pSample->rtStop); - bInvalidate = true; - } - } - } else if (m_mt.majortype == MEDIATYPE_Subtitle) { - if (m_mt.subtype == MEDIASUBTYPE_UTF8 || m_mt.subtype == MEDIASUBTYPE_WEBVTT) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; -#if USE_LIBASS + + if (m_mt.majortype == MEDIATYPE_Text) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; + + char* pData = (char*)pSample->data.data(); + + if (!strncmp(pData, __GAB1__, strlen(__GAB1__))) { + char* ptr = &pData[strlen(__GAB1__) + 1]; + char* end = &pData[pSample->data.size()]; + + while (ptr < end) { + WORD tag = *((WORD*)(ptr)); + ptr += 2; + WORD size = *((WORD*)(ptr)); + ptr += 2; + + if (tag == __GAB1_LANGUAGE__) { + pRTS->m_name = ptr; + } else if (tag == __GAB1_ENTRY__) { + pRTS->Add(AToW(&ptr[8]), false, MS2RT(*(int*)ptr), MS2RT(*(int*)(ptr + 4))); + bInvalidate = true; + } else if (tag == __GAB1_LANGUAGE_UNICODE__) { + pRTS->m_name = (WCHAR*)ptr; + } else if (tag == __GAB1_ENTRY_UNICODE__) { + pRTS->Add((WCHAR*)(ptr + 8), true, MS2RT(*(int*)ptr), MS2RT(*(int*)(ptr + 4))); + bInvalidate = true; + } + + ptr += size; + } + } else if (!strncmp(pData, __GAB2__, strlen(__GAB2__))) { + char* ptr = &pData[strlen(__GAB2__) + 1]; + char* end = &pData[pSample->data.size()]; + + while (ptr < end) { + WORD tag = *((WORD*)(ptr)); + ptr += 2; + DWORD size = *((DWORD*)(ptr)); + ptr += 4; + + if (tag == __GAB1_LANGUAGE_UNICODE__) { + pRTS->m_name = (WCHAR*)ptr; + } else if (tag == __GAB1_RAWTEXTSUBTITLE__) { + pRTS->Open((BYTE*)ptr, size, DEFAULT_CHARSET, pRTS->m_name); + bInvalidate = true; + } + + ptr += size; + } + } else if (pSample->data.size() > 1 && *pData != '\0') { + CStringA str(pData, (int)pSample->data.size()); + + str.Replace("\r\n", "\n"); + FastTrim(str); + + if (!str.IsEmpty()) { + pRTS->Add(AToW(str), false, pSample->rtStart, pSample->rtStop); + bInvalidate = true; + } + } + } else if (m_mt.majortype == MEDIATYPE_Subtitle) { + if (m_mt.subtype == MEDIASUBTYPE_UTF8 || m_mt.subtype == MEDIASUBTYPE_WEBVTT) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; +#if USE_LIBASS if (pRTS->m_LibassContext.IsLibassActive()) { LPCSTR data = (LPCSTR)pSample->data.data(); int dataSize = (int)pSample->data.size(); pRTS->m_LibassContext.SetFilterGraphFromFilter(m_pFilter); pRTS->m_LibassContext.LoadASSSample((char*)data, dataSize, pSample->rtStart, pSample->rtStop); } else -#endif - { - CStringW str = UTF8To16(CStringA((LPCSTR)pSample->data.data(), (int)pSample->data.size())); - FastTrim(str); - if (!str.IsEmpty()) { - pRTS->Add(str, true, pSample->rtStart, pSample->rtStop); - bInvalidate = true; - if (pRTS->m_subtitleType == Subtitle::VTT) { - pRTS->m_webvtt_allow_clear = true; - } - } - } - } else if (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; +#endif + { + CStringW str = UTF8To16(CStringA((LPCSTR)pSample->data.data(), (int)pSample->data.size())); + FastTrim(str); + if (!str.IsEmpty()) { + pRTS->Add(str, true, pSample->rtStart, pSample->rtStop); + bInvalidate = true; + if (pRTS->m_subtitleType == Subtitle::VTT) { + pRTS->m_webvtt_allow_clear = true; + } + } + } + } else if (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; #if USE_LIBASS if (pRTS->m_LibassContext.IsLibassActive()) { ass_process_chunk(pRTS->m_LibassContext.m_track.get(), (char*)pSample->data.data(), (int)pSample->data.size(), pSample->rtStart / 10000, (pSample->rtStop - pSample->rtStart) / 10000); - } else -#endif - { + } else +#endif + { CStringW str = UTF8To16(CStringA((LPCSTR)pSample->data.data(), (int)pSample->data.size())); - FastTrim(str); - if (!str.IsEmpty()) { - STSEntry stse; - int fields = m_mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9; - if (pRTS->event_param == 0b011111000001) { // non-standard variant - fields = 4; - } - CAtlList sl; - ExplodeNoTrim(str, sl, ',', fields); - if (sl.GetCount() == (size_t)fields) { - stse.readorder = wcstol(sl.RemoveHead(), nullptr, 10); - stse.layer = wcstol(sl.RemoveHead(), nullptr, 10); - stse.style = sl.RemoveHead(); // no trim, its value is a lookup key - if (fields >= 9) { - stse.actor = sl.RemoveHead().Trim(); - stse.marginRect.left = wcstol(sl.RemoveHead(), nullptr, 10); - stse.marginRect.right = wcstol(sl.RemoveHead(), nullptr, 10); - stse.marginRect.top = stse.marginRect.bottom = wcstol(sl.RemoveHead(), nullptr, 10); - } - if (fields == 10) { - stse.marginRect.bottom = wcstol(sl.RemoveHead(), nullptr, 10); - } - if (fields >= 9) { - stse.effect = sl.RemoveHead().Trim(); - } - stse.str = sl.RemoveHead().Trim(); - } else { - ASSERT(false); - } - - if (!stse.str.IsEmpty()) { - pRTS->Add(stse.str, true, pSample->rtStart, pSample->rtStop, - stse.style, stse.actor, stse.effect, stse.marginRect, stse.layer, stse.readorder); - bInvalidate = true; - } - } - } - } else if (m_mt.subtype == MEDIASUBTYPE_VOBSUB) { - CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; - pVSS->Add(pSample->rtStart, pSample->rtStop, pSample->data.data(), (int)pSample->data.size()); - } else if (IsRLECodedSub(&m_mt)) { - CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; - pRLECodedSubtitle->ParseSample(pSample->rtStart, pSample->rtStop, pSample->data.data(), (int)pSample->data.size()); - } - } - - return bInvalidate ? pSample->rtStart : -1; -} - -void CSubtitleInputPin::InvalidateSamples() -{ - m_bStopDecoding = true; - { - std::lock_guard lock(m_mutexQueue); - m_sampleQueue.clear(); - m_bStopDecoding = false; - } -} + FastTrim(str); + if (!str.IsEmpty()) { + STSEntry stse; + int fields = m_mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9; + if (pRTS->event_param == 0b011111000001) { // non-standard variant + fields = 4; + } + CAtlList sl; + ExplodeNoTrim(str, sl, ',', fields); + if (sl.GetCount() == (size_t)fields) { + stse.readorder = wcstol(sl.RemoveHead(), nullptr, 10); + stse.layer = wcstol(sl.RemoveHead(), nullptr, 10); + stse.style = sl.RemoveHead(); // no trim, its value is a lookup key + if (fields >= 9) { + stse.actor = sl.RemoveHead().Trim(); + stse.marginRect.left = wcstol(sl.RemoveHead(), nullptr, 10); + stse.marginRect.right = wcstol(sl.RemoveHead(), nullptr, 10); + stse.marginRect.top = stse.marginRect.bottom = wcstol(sl.RemoveHead(), nullptr, 10); + } + if (fields == 10) { + stse.marginRect.bottom = wcstol(sl.RemoveHead(), nullptr, 10); + } + if (fields >= 9) { + stse.effect = sl.RemoveHead().Trim(); + } + stse.str = sl.RemoveHead().Trim(); + } else { + ASSERT(false); + } + + if (!stse.str.IsEmpty()) { + pRTS->Add(stse.str, true, pSample->rtStart, pSample->rtStop, + stse.style, stse.actor, stse.effect, stse.marginRect, stse.layer, stse.readorder); + bInvalidate = true; + } + } + } + } else if (m_mt.subtype == MEDIASUBTYPE_VOBSUB) { + CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; + pVSS->Add(pSample->rtStart, pSample->rtStop, pSample->data.data(), (int)pSample->data.size()); + } else if (IsRLECodedSub(&m_mt)) { + CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; + pRLECodedSubtitle->ParseSample(pSample->rtStart, pSample->rtStop, pSample->data.data(), (int)pSample->data.size()); + } + } + + return bInvalidate ? pSample->rtStart : -1; +} + +void CSubtitleInputPin::InvalidateSamples() +{ + m_bStopDecoding = true; + { + std::lock_guard lock(m_mutexQueue); + m_sampleQueue.clear(); + m_bStopDecoding = false; + } +} diff --git a/src/Subtitles/SubtitleInputPin.h b/src/Subtitles/SubtitleInputPin.h index c94635d3e15..3a0d8a09385 100644 --- a/src/Subtitles/SubtitleInputPin.h +++ b/src/Subtitles/SubtitleInputPin.h @@ -1,86 +1,86 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "../SubPic/ISubPic.h" - -// -// CSubtitleInputPin -// - -class CSubtitleInputPin : public CBaseInputPin -{ - static const REFERENCE_TIME INVALID_TIME = _I64_MIN; - - CCritSec m_csReceive; - - CCritSec* m_pSubLock; - CComPtr m_pSubStream; - - struct SubtitleSample { - REFERENCE_TIME rtStart, rtStop; - std::vector data; - - SubtitleSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t len) - : rtStart(rtStart) - , rtStop(rtStop) - , data(pData, pData + len) {} - }; - - std::list> m_sampleQueue; - - bool m_bExitDecodingThread, m_bStopDecoding; - std::thread m_decodeThread; - std::mutex m_mutexQueue; // to protect m_sampleQueue - std::condition_variable m_condQueueReady; - - void DecodeSamples(); - REFERENCE_TIME DecodeSample(const std::unique_ptr& pSample); - void InvalidateSamples(); - -protected: - virtual void AddSubStream(ISubStream* pSubStream) = 0; - virtual void RemoveSubStream(ISubStream* pSubStream) = 0; - virtual void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) = 0; - - bool IsRLECodedSub(const CMediaType* pmt) const; - -public: - CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); - ~CSubtitleInputPin(); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT CompleteConnect(IPin* pReceivePin); - HRESULT BreakConnect(); - STDMETHODIMP ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP EndOfStream(void); - - ISubStream* GetSubStream() { return m_pSubStream; } -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "../SubPic/ISubPic.h" + +// +// CSubtitleInputPin +// + +class CSubtitleInputPin : public CBaseInputPin +{ + static const REFERENCE_TIME INVALID_TIME = _I64_MIN; + + CCritSec m_csReceive; + + CCritSec* m_pSubLock; + CComPtr m_pSubStream; + + struct SubtitleSample { + REFERENCE_TIME rtStart, rtStop; + std::vector data; + + SubtitleSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t len) + : rtStart(rtStart) + , rtStop(rtStop) + , data(pData, pData + len) {} + }; + + std::list> m_sampleQueue; + + bool m_bExitDecodingThread, m_bStopDecoding; + std::thread m_decodeThread; + std::mutex m_mutexQueue; // to protect m_sampleQueue + std::condition_variable m_condQueueReady; + + void DecodeSamples(); + REFERENCE_TIME DecodeSample(const std::unique_ptr& pSample); + void InvalidateSamples(); + +protected: + virtual void AddSubStream(ISubStream* pSubStream) = 0; + virtual void RemoveSubStream(ISubStream* pSubStream) = 0; + virtual void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) = 0; + + bool IsRLECodedSub(const CMediaType* pmt) const; + +public: + CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); + ~CSubtitleInputPin(); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT CompleteConnect(IPin* pReceivePin); + HRESULT BreakConnect(); + STDMETHODIMP ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP EndOfStream(void); + + ISubStream* GetSubStream() { return m_pSubStream; } +}; diff --git a/src/Subtitles/Subtitles.vcxproj b/src/Subtitles/Subtitles.vcxproj index 63b19cecebc..4e800c43061 100644 --- a/src/Subtitles/Subtitles.vcxproj +++ b/src/Subtitles/Subtitles.vcxproj @@ -1,117 +1,117 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {5E56335F-0FB1-4EEA-B240-D8DC5E0608E4} - Subtitles - MFCProj - Subtitles - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\include;..\thirdparty;..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - 6509;26812 - 6509;26812 - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {19677dfd-c020-434d-9cb1-d0f105e72770} - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {5E56335F-0FB1-4EEA-B240-D8DC5E0608E4} + Subtitles + MFCProj + Subtitles + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\include;..\thirdparty;..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + 6509;26812 + 6509;26812 + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {19677dfd-c020-434d-9cb1-d0f105e72770} + + + + + + diff --git a/src/Subtitles/Subtitles.vcxproj.filters b/src/Subtitles/Subtitles.vcxproj.filters index 018c96b3268..47600170d57 100644 --- a/src/Subtitles/Subtitles.vcxproj.filters +++ b/src/Subtitles/Subtitles.vcxproj.filters @@ -1,176 +1,176 @@ - - - - - {11712c7b-74ef-4965-a813-5290f06e30a4} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {405fa87b-b576-4329-99eb-f6c49c3a84be} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - + + + + + {11712c7b-74ef-4965-a813-5290f06e30a4} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {405fa87b-b576-4329-99eb-f6c49c3a84be} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + diff --git a/src/Subtitles/TextFile.cpp b/src/Subtitles/TextFile.cpp index 4bddbecdd8a..12c2c50cc19 100644 --- a/src/Subtitles/TextFile.cpp +++ b/src/Subtitles/TextFile.cpp @@ -1,887 +1,887 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include -#include "TextFile.h" -#include "Utf8.h" - -#define TEXTFILE_BUFFER_SIZE (64 * 1024) - -CTextFile::CTextFile(enc e) - : m_encoding(e) - , m_defaultencoding(e) - , m_fallbackencoding(DEFAULT_ENCODING) - , m_offset(0) - , m_posInFile(0) - , m_posInBuffer(0) - , m_nInBuffer(0) -{ - m_buffer.Allocate(TEXTFILE_BUFFER_SIZE); - m_wbuffer.Allocate(TEXTFILE_BUFFER_SIZE); -} - -bool CTextFile::Open(LPCTSTR lpszFileName) -{ - if (!__super::Open(lpszFileName, modeRead | typeBinary | shareDenyNone)) { - return false; - } - - m_encoding = m_defaultencoding; - m_offset = 0; - m_nInBuffer = m_posInBuffer = 0; - - try { - if (__super::GetLength() >= 2) { - WORD w; - if (sizeof(w) != Read(&w, sizeof(w))) { - return Close(), false; - } - - if (w == 0xfeff) { - m_encoding = LE16; - m_offset = 2; - } else if (w == 0xfffe) { - m_encoding = BE16; - m_offset = 2; - } else if (w == 0xbbef && __super::GetLength() >= 3) { - BYTE b; - if (sizeof(b) != Read(&b, sizeof(b))) { - return Close(), false; - } - - if (b == 0xbf) { - m_encoding = UTF8; - m_offset = 3; - } - } - } - - if (m_encoding == DEFAULT_ENCODING) { - if (!ReopenAsText()) { - return false; - } - } else if (m_offset == 0) { // No BOM detected, ensure the file is read from the beginning - Seek(0, begin); - } else { - m_posInFile = __super::GetPosition(); - } - } catch (CFileException*) { - return false; - } - - return true; -} - -bool CTextFile::ReopenAsText() -{ - CString strFileName = m_strFileName; - - __super::Close(); // CWebTextFile::Close() would delete the temp file if we called it... - - return !!__super::Open(strFileName, modeRead | typeText | shareDenyNone); -} - -bool CTextFile::Save(LPCTSTR lpszFileName, enc e) -{ - if (!__super::Open(lpszFileName, modeCreate | modeWrite | shareDenyWrite | (e == DEFAULT_ENCODING ? typeText : typeBinary))) { - return false; - } - - if (e == UTF8) { - BYTE b[3] = {0xef, 0xbb, 0xbf}; - Write(b, sizeof(b)); - } else if (e == LE16) { - BYTE b[2] = {0xff, 0xfe}; - Write(b, sizeof(b)); - } else if (e == BE16) { - BYTE b[2] = {0xfe, 0xff}; - Write(b, sizeof(b)); - } - - m_encoding = e; - - return true; -} - -void CTextFile::SetEncoding(enc e) -{ - m_encoding = e; -} - -void CTextFile::SetFallbackEncoding(enc e) -{ - m_fallbackencoding = e; -} - -CTextFile::enc CTextFile::GetEncoding() -{ - return m_encoding; -} - -bool CTextFile::IsUnicode() -{ - return m_encoding == UTF8 || m_encoding == LE16 || m_encoding == BE16; -} - -// CFile - -CString CTextFile::GetFilePath() const -{ - // to avoid a CException coming from CTime - return m_strFileName; // __super::GetFilePath(); -} - -// CStdioFile - -ULONGLONG CTextFile::GetPosition() const -{ - return (__super::GetPosition() - m_offset - (m_nInBuffer - m_posInBuffer)); -} - -ULONGLONG CTextFile::GetLength() const -{ - return (__super::GetLength() - m_offset); -} - -ULONGLONG CTextFile::Seek(LONGLONG lOff, UINT nFrom) -{ - ULONGLONG newPos; - - // Try to reuse the buffer if any - if (m_nInBuffer > 0) { - ULONGLONG pos = GetPosition(); - ULONGLONG len = GetLength(); - - switch (nFrom) { - default: - case begin: - break; - case current: - lOff = pos + lOff; - break; - case end: - lOff = len - lOff; - break; - } - - lOff = std::max((LONGLONG)std::min((ULONGLONG)lOff, len), 0ll); - - m_posInBuffer += LONGLONG(ULONGLONG(lOff) - pos); - if (m_posInBuffer < 0 || m_posInBuffer >= m_nInBuffer) { - // If we would have to end up out of the buffer, we just reset it and seek normally - m_nInBuffer = m_posInBuffer = 0; - newPos = __super::Seek(lOff + m_offset, begin) - m_offset; - } else { // If we can reuse the buffer, we have nothing special to do - newPos = ULONGLONG(lOff); - } - } else { // No buffer, we can use the base implementation - if (nFrom == begin) { - lOff += m_offset; - } - newPos = __super::Seek(lOff, nFrom) - m_offset; - } - - m_posInFile = newPos + m_offset + (m_nInBuffer - m_posInBuffer); - - return newPos; -} - -void CTextFile::WriteString(LPCSTR lpsz/*CStringA str*/) -{ - CStringA str(lpsz); - - if (m_encoding == DEFAULT_ENCODING) { - __super::WriteString(AToT(str)); - } else if (m_encoding == ANSI) { - str.Replace("\n", "\r\n"); - Write((LPCSTR)str, str.GetLength()); - } else if (m_encoding == UTF8) { - WriteString(AToW(str)); - } else if (m_encoding == LE16) { - WriteString(AToW(str)); - } else if (m_encoding == BE16) { - WriteString(AToW(str)); - } -} - -CStringA ConvertUnicodeToUTF8(const CStringW& input) -{ - if (input.IsEmpty()) { - return ""; - } - CStringA utf8; - int cc = 0; - if ((cc = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, 0, 0) - 1) > 0) - { - char* buf = utf8.GetBuffer(cc); - if (buf) { - WideCharToMultiByte(CP_UTF8, 0, input, -1, buf, cc, 0, 0); - } - utf8.ReleaseBuffer(); - } - return utf8; -} - -void CTextFile::WriteString(LPCWSTR lpsz/*CStringW str*/) -{ - CStringW str(lpsz); - - if (m_encoding == DEFAULT_ENCODING) { - __super::WriteString(WToT(str)); - } else if (m_encoding == ANSI) { - str.Replace(L"\n", L"\r\n"); - CStringA stra(str); // TODO: codepage - Write((LPCSTR)stra, stra.GetLength()); - } else if (m_encoding == UTF8) { - str.Replace(L"\n", L"\r\n"); - CStringA utf8data = ConvertUnicodeToUTF8(str); - Write((LPCSTR)utf8data, utf8data.GetLength()); - } else if (m_encoding == LE16) { - str.Replace(L"\n", L"\r\n"); - Write((LPCWSTR)str, str.GetLength() * 2); - } else if (m_encoding == BE16) { - str.Replace(L"\n", L"\r\n"); - for (unsigned int i = 0, l = str.GetLength(); i < l; i++) { - str.SetAt(i, ((str[i] >> 8) & 0x00ff) | ((str[i] << 8) & 0xff00)); - } - Write((LPCWSTR)str, str.GetLength() * 2); - } -} - -bool CTextFile::FillBuffer() -{ - if (m_posInBuffer < m_nInBuffer) { - m_nInBuffer -= m_posInBuffer; - memcpy(m_buffer, &m_buffer[m_posInBuffer], (size_t)m_nInBuffer * sizeof(char)); - } else { - m_nInBuffer = 0; - } - m_posInBuffer = 0; - - UINT nBytesRead; - try { - nBytesRead = __super::Read(&m_buffer[m_nInBuffer], UINT(TEXTFILE_BUFFER_SIZE - m_nInBuffer) * sizeof(char)); - } catch (...) { - return true; // signal EOF in case of exception - } - if (nBytesRead) { - m_nInBuffer += nBytesRead; - } - - // Workaround for buggy text files that contain a duplicate UTF BOM - if (m_posInFile == m_offset && m_offset >= 2 && m_nInBuffer > 3) { - if (m_buffer[0] == '\xEF' && m_buffer[1] == '\xBB' && m_buffer[2] == '\xBF') { - m_posInBuffer = 3; - } else if (m_buffer[0] == '\xFE' && m_buffer[1] == '\xFF' || m_buffer[0] == '\xFF' && m_buffer[1] == '\xEF') { - m_posInBuffer = 2; - } - } - - m_posInFile = __super::GetPosition(); - - return !nBytesRead; -} - -ULONGLONG CTextFile::GetPositionFastBuffered() const -{ - return (m_posInFile - m_offset - (m_nInBuffer - m_posInBuffer)); -} - -BOOL CTextFile::ReadString(CStringA& str) -{ - bool fEOF = true; - - str.Truncate(0); - - if (m_encoding == DEFAULT_ENCODING) { - CString s; - fEOF = !__super::ReadString(s); - str = TToA(s); - // For consistency with other encodings, we continue reading - // the file even when a NUL char is encountered. - char c; - while (fEOF && (Read(&c, sizeof(c)) == sizeof(c))) { - str += c; - fEOF = !__super::ReadString(s); - str += TToA(s); - } - } else if (m_encoding == ANSI) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - - for (nCharsRead = 0; m_posInBuffer + nCharsRead < m_nInBuffer; nCharsRead++) { - if (m_buffer[m_posInBuffer + nCharsRead] == '\n') { - break; - } else if (m_buffer[m_posInBuffer + nCharsRead] == '\r') { - break; - } - } - - str.Append(&m_buffer[m_posInBuffer], nCharsRead); - - m_posInBuffer += nCharsRead; - while (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\r') { - m_posInBuffer++; - } - if (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer++; - } - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } else if (m_encoding == UTF8) { - ULONGLONG lineStartPos = GetPositionFastBuffered(); - bool bValid = true; - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - char* abuffer = (char*)(WCHAR*)m_wbuffer; - - for (nCharsRead = 0; m_posInBuffer < m_nInBuffer; m_posInBuffer++, nCharsRead++) { - if (Utf8::isSingleByte(m_buffer[m_posInBuffer])) { // 0xxxxxxx - abuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; - } else if (Utf8::isFirstOfMultibyte(m_buffer[m_posInBuffer])) { - int nContinuationBytes = Utf8::continuationBytes(m_buffer[m_posInBuffer]); - ASSERT(bValid); - - if (m_posInBuffer + nContinuationBytes >= m_nInBuffer) { - // If we are at the end of the file, the buffer won't be full - // and we won't be able to read any more continuation bytes. - bValid = (m_nInBuffer == TEXTFILE_BUFFER_SIZE); - break; - } else { - for (int j = 1; j <= nContinuationBytes; j++) { - if (!Utf8::isContinuation(m_buffer[m_posInBuffer + j])) { - bValid = false; - } - } - - switch (nContinuationBytes) { - case 0: // 0xxxxxxx - abuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; - break; - case 1: // 110xxxxx 10xxxxxx - case 2: // 1110xxxx 10xxxxxx 10xxxxxx - case 3: // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - // Unsupported for non unicode strings - abuffer[nCharsRead] = '?'; - break; - } - m_posInBuffer += nContinuationBytes; - } - } else { - bValid = false; - TRACE(_T("Invalid UTF8 character found\n")); - } - - if (!bValid) { - abuffer[nCharsRead] = '?'; - m_posInBuffer++; - nCharsRead++; - break; - } else if (abuffer[nCharsRead] == '\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer++; - break; - } else if (abuffer[nCharsRead] == '\r') { - nCharsRead--; // Skip \r - } - } - - if (bValid || m_offset) { - str.Append(abuffer, nCharsRead); - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } else { - // Switch to text and read again - m_encoding = m_fallbackencoding; - // Stop using the buffer - m_posInBuffer = m_nInBuffer = 0; - - fEOF = !ReopenAsText(); - - if (!fEOF) { - // Seek back to the beginning of the line where we stopped - Seek(lineStartPos, begin); - - fEOF = !ReadString(str); - } - } - } while (bValid && !bLineEndFound); - } else if (m_encoding == LE16) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - WCHAR* wbuffer = (WCHAR*)&m_buffer[m_posInBuffer]; - char* abuffer = (char*)(WCHAR*)m_wbuffer; - - for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { - if (wbuffer[nCharsRead] == L'\n') { - break; // Stop at end of line - } else if (wbuffer[nCharsRead] == L'\r') { - break; // Skip \r - } else if (!(wbuffer[nCharsRead] & 0xff00)) { - abuffer[nCharsRead] = char(wbuffer[nCharsRead] & 0xff); - } else { - abuffer[nCharsRead] = '?'; - } - } - - str.Append(abuffer, nCharsRead); - - while (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\r') { - nCharsRead++; - m_posInBuffer += sizeof(WCHAR); - } - if (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\n') { - bLineEndFound = true; // Stop at end of line - nCharsRead++; - m_posInBuffer += sizeof(WCHAR); - } - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } else if (m_encoding == BE16) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - char* abuffer = (char*)(WCHAR*)m_wbuffer; - - for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { - if (!m_buffer[m_posInBuffer]) { - abuffer[nCharsRead] = m_buffer[m_posInBuffer + 1]; - } else { - abuffer[nCharsRead] = '?'; - } - - if (abuffer[nCharsRead] == '\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer += sizeof(WCHAR); - break; - } else if (abuffer[nCharsRead] == L'\r') { - nCharsRead--; // Skip \r - } - } - - str.Append(abuffer, nCharsRead); - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } - - return !fEOF; -} - -BOOL CTextFile::ReadString(CStringW& str) -{ - bool fEOF = true; - - str.Truncate(0); - - if (m_encoding == DEFAULT_ENCODING) { - CString s; - fEOF = !__super::ReadString(s); - str = TToW(s); - // For consistency with other encodings, we continue reading - // the file even when a NUL char is encountered. - char c; - while (fEOF && (Read(&c, sizeof(c)) == sizeof(c))) { - str += c; - fEOF = !__super::ReadString(s); - str += TToW(s); - } - } else if (m_encoding == ANSI) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - - for (nCharsRead = 0; m_posInBuffer + nCharsRead < m_nInBuffer; nCharsRead++) { - if (m_buffer[m_posInBuffer + nCharsRead] == '\n') { - break; - } else if (m_buffer[m_posInBuffer + nCharsRead] == '\r') { - break; - } - } - - // TODO: codepage - str.Append(CStringW(&m_buffer[m_posInBuffer], nCharsRead)); - - m_posInBuffer += nCharsRead; - while (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\r') { - m_posInBuffer++; - } - if (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer++; - } - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } else if (m_encoding == UTF8) { - ULONGLONG lineStartPos = GetPositionFastBuffered(); - bool bValid = true; - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - - for (nCharsRead = 0; m_posInBuffer < m_nInBuffer; m_posInBuffer++, nCharsRead++) { - if (Utf8::isSingleByte(m_buffer[m_posInBuffer])) { // 0xxxxxxx - m_wbuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; - } else if (Utf8::isFirstOfMultibyte(m_buffer[m_posInBuffer])) { - int nContinuationBytes = Utf8::continuationBytes(m_buffer[m_posInBuffer]); - if (m_posInBuffer + nContinuationBytes >= m_nInBuffer) { - // If we are at the end of the file, the buffer won't be full - // and we won't be able to read any more continuation bytes. - bValid = (m_nInBuffer == TEXTFILE_BUFFER_SIZE); - break; - } else { - for (int j = 1; j <= nContinuationBytes; j++) { - if (!Utf8::isContinuation(m_buffer[m_posInBuffer + j])) { //maybe redundant since MultiByteToWideChar should return zero if bad utf-8? - bValid = false; - } - } - if (bValid) { - int nWchars = MultiByteToWideChar(CP_UTF8, 0, &m_buffer[m_posInBuffer], nContinuationBytes + 1, nullptr, 0); - if (nWchars > 0) { - MultiByteToWideChar(CP_UTF8, 0, &m_buffer[m_posInBuffer], nContinuationBytes + 1, &m_wbuffer[nCharsRead], nWchars); - nCharsRead += nWchars - 1; //subtract one for loop increment - } else { - bValid = false; - } - } - m_posInBuffer += nContinuationBytes; - } - } else { - bValid = false; - TRACE(_T("Invalid UTF8 character found\n")); - } - - if (!bValid) { - m_wbuffer[nCharsRead] = L'?'; - m_posInBuffer++; - nCharsRead++; - break; - } else if (m_wbuffer[nCharsRead] == L'\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer++; - break; - } else if (m_wbuffer[nCharsRead] == L'\r') { - // check if it is followed by a '\n' - if (m_posInBuffer + 1 >= m_nInBuffer) { - bLineEndFound = FillBuffer(); - } - if (!bLineEndFound && Utf8::isSingleByte(m_buffer[m_posInBuffer+1]) && ((m_buffer[m_posInBuffer+1] & 0x7f) == L'\n')) { - nCharsRead--; // Skip '\r' - } else { - // Add the missing '\n' - nCharsRead++; - m_wbuffer[nCharsRead] = L'\n'; - bLineEndFound = true; - m_posInBuffer++; - break; - } - } - } - - if (bValid || m_offset) { - if (nCharsRead > 0) { - str.Append(m_wbuffer, nCharsRead); - } - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } else { - // Switch to text and read again - m_encoding = m_fallbackencoding; - // Stop using the buffer - m_posInBuffer = m_nInBuffer = 0; - - fEOF = !ReopenAsText(); - - if (!fEOF) { - // Seek back to the beginning of the line where we stopped - Seek(lineStartPos, begin); - - fEOF = !ReadString(str); - } - } - } while (bValid && !bLineEndFound); - } else if (m_encoding == LE16) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - WCHAR* wbuffer = (WCHAR*)&m_buffer[m_posInBuffer]; - - for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { - if (wbuffer[nCharsRead] == L'\n') { - break; // Stop at end of line - } else if (wbuffer[nCharsRead] == L'\r') { - break; // Skip \r - } - } - - str.Append(wbuffer, nCharsRead); - - while (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\r') { - nCharsRead++; - m_posInBuffer += sizeof(WCHAR); - } - if (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\n') { - bLineEndFound = true; // Stop at end of line - nCharsRead++; - m_posInBuffer += sizeof(WCHAR); - } - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } else if (m_encoding == BE16) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - - for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { - m_wbuffer[nCharsRead] = ((WCHAR(m_buffer[m_posInBuffer]) << 8) & 0xff00) | (WCHAR(m_buffer[m_posInBuffer + 1]) & 0x00ff); - if (m_wbuffer[nCharsRead] == L'\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer += sizeof(WCHAR); - break; - } else if (m_wbuffer[nCharsRead] == L'\r') { - nCharsRead--; // Skip \r - } - } - - str.Append(m_wbuffer, nCharsRead); - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } - - return !fEOF; -} - -// -// CWebTextFile -// - -CWebTextFile::CWebTextFile(CTextFile::enc e, LONGLONG llMaxSize) - : CTextFile(e) - , m_llMaxSize(llMaxSize) -{ -} - -bool CWebTextFile::Open(LPCTSTR lpszFileName) -{ - CString fn(lpszFileName); - - if (fn.Find(_T("://")) == -1) { - return __super::Open(lpszFileName); - } - - try { - CInternetSession is; - - CAutoPtr f(is.OpenURL(fn, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT)); - if (!f) { - return false; - } - - TCHAR path[MAX_PATH]; - GetTempPath(MAX_PATH, path); - - fn = path + fn.Mid(fn.ReverseFind('/') + 1); - int i = fn.Find(_T("?")); - if (i > 0) { - fn = fn.Left(i); - } - CFile temp; - if (!temp.Open(fn, modeCreate | modeWrite | typeBinary | shareDenyWrite)) { - f->Close(); - return false; - } - - BYTE buff[1024]; - int len, total = 0; - while ((len = f->Read(buff, 1024)) > 0) { - total += len; - temp.Write(buff, len); - if (m_llMaxSize > 0 && total >= m_llMaxSize) { - break; - } - } - - m_tempfn = fn; - - f->Close(); // must close it because the desctructor doesn't seem to do it and we will get an exception when "is" is destroying - } catch (CInternetException* ie) { - ie->Delete(); - return false; - } - - return __super::Open(m_tempfn); -} - -bool CWebTextFile::Save(LPCTSTR lpszFileName, enc e) -{ - // CWebTextFile is read-only... - ASSERT(0); - return false; -} - -void CWebTextFile::Close() -{ - __super::Close(); - - if (!m_tempfn.IsEmpty()) { - _tremove(m_tempfn); - m_tempfn.Empty(); - } -} - -/////////////////////////////////////////////////////////////// - -CStringW AToW(CStringA str) -{ - CStringW ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (WCHAR)(BYTE)str[i]; - } - return ret; -} - -CStringA WToA(CStringW str) -{ - CStringA ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (CHAR)(WORD)str[i]; - } - return ret; -} - -CString AToT(CStringA str) -{ -#ifdef UNICODE - CString ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (TCHAR)(BYTE)str[i]; - } - return ret; -#else - return str; -#endif -} - -CString WToT(CStringW str) -{ -#ifdef UNICODE - return str; -#else - CString ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (TCHAR)(WORD)str[i]; - } - return ret; -#endif -} - -CStringA TToA(CString str) -{ -#ifdef UNICODE - CStringA ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (CHAR)(BYTE)str[i]; - } - return ret; -#else - return str; -#endif -} - -CStringW TToW(CString str) -{ -#ifdef UNICODE - return str; -#else - CStringW ret; - for (size_t i = 0, j = str.GetLength(); i < j; i++) { - ret += (WCHAR)(BYTE)str[i]; - } - return ret; -#endif -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include +#include "TextFile.h" +#include "Utf8.h" + +#define TEXTFILE_BUFFER_SIZE (64 * 1024) + +CTextFile::CTextFile(enc e) + : m_encoding(e) + , m_defaultencoding(e) + , m_fallbackencoding(DEFAULT_ENCODING) + , m_offset(0) + , m_posInFile(0) + , m_posInBuffer(0) + , m_nInBuffer(0) +{ + m_buffer.Allocate(TEXTFILE_BUFFER_SIZE); + m_wbuffer.Allocate(TEXTFILE_BUFFER_SIZE); +} + +bool CTextFile::Open(LPCTSTR lpszFileName) +{ + if (!__super::Open(lpszFileName, modeRead | typeBinary | shareDenyNone)) { + return false; + } + + m_encoding = m_defaultencoding; + m_offset = 0; + m_nInBuffer = m_posInBuffer = 0; + + try { + if (__super::GetLength() >= 2) { + WORD w; + if (sizeof(w) != Read(&w, sizeof(w))) { + return Close(), false; + } + + if (w == 0xfeff) { + m_encoding = LE16; + m_offset = 2; + } else if (w == 0xfffe) { + m_encoding = BE16; + m_offset = 2; + } else if (w == 0xbbef && __super::GetLength() >= 3) { + BYTE b; + if (sizeof(b) != Read(&b, sizeof(b))) { + return Close(), false; + } + + if (b == 0xbf) { + m_encoding = UTF8; + m_offset = 3; + } + } + } + + if (m_encoding == DEFAULT_ENCODING) { + if (!ReopenAsText()) { + return false; + } + } else if (m_offset == 0) { // No BOM detected, ensure the file is read from the beginning + Seek(0, begin); + } else { + m_posInFile = __super::GetPosition(); + } + } catch (CFileException*) { + return false; + } + + return true; +} + +bool CTextFile::ReopenAsText() +{ + CString strFileName = m_strFileName; + + __super::Close(); // CWebTextFile::Close() would delete the temp file if we called it... + + return !!__super::Open(strFileName, modeRead | typeText | shareDenyNone); +} + +bool CTextFile::Save(LPCTSTR lpszFileName, enc e) +{ + if (!__super::Open(lpszFileName, modeCreate | modeWrite | shareDenyWrite | (e == DEFAULT_ENCODING ? typeText : typeBinary))) { + return false; + } + + if (e == UTF8) { + BYTE b[3] = {0xef, 0xbb, 0xbf}; + Write(b, sizeof(b)); + } else if (e == LE16) { + BYTE b[2] = {0xff, 0xfe}; + Write(b, sizeof(b)); + } else if (e == BE16) { + BYTE b[2] = {0xfe, 0xff}; + Write(b, sizeof(b)); + } + + m_encoding = e; + + return true; +} + +void CTextFile::SetEncoding(enc e) +{ + m_encoding = e; +} + +void CTextFile::SetFallbackEncoding(enc e) +{ + m_fallbackencoding = e; +} + +CTextFile::enc CTextFile::GetEncoding() +{ + return m_encoding; +} + +bool CTextFile::IsUnicode() +{ + return m_encoding == UTF8 || m_encoding == LE16 || m_encoding == BE16; +} + +// CFile + +CString CTextFile::GetFilePath() const +{ + // to avoid a CException coming from CTime + return m_strFileName; // __super::GetFilePath(); +} + +// CStdioFile + +ULONGLONG CTextFile::GetPosition() const +{ + return (__super::GetPosition() - m_offset - (m_nInBuffer - m_posInBuffer)); +} + +ULONGLONG CTextFile::GetLength() const +{ + return (__super::GetLength() - m_offset); +} + +ULONGLONG CTextFile::Seek(LONGLONG lOff, UINT nFrom) +{ + ULONGLONG newPos; + + // Try to reuse the buffer if any + if (m_nInBuffer > 0) { + ULONGLONG pos = GetPosition(); + ULONGLONG len = GetLength(); + + switch (nFrom) { + default: + case begin: + break; + case current: + lOff = pos + lOff; + break; + case end: + lOff = len - lOff; + break; + } + + lOff = std::max((LONGLONG)std::min((ULONGLONG)lOff, len), 0ll); + + m_posInBuffer += LONGLONG(ULONGLONG(lOff) - pos); + if (m_posInBuffer < 0 || m_posInBuffer >= m_nInBuffer) { + // If we would have to end up out of the buffer, we just reset it and seek normally + m_nInBuffer = m_posInBuffer = 0; + newPos = __super::Seek(lOff + m_offset, begin) - m_offset; + } else { // If we can reuse the buffer, we have nothing special to do + newPos = ULONGLONG(lOff); + } + } else { // No buffer, we can use the base implementation + if (nFrom == begin) { + lOff += m_offset; + } + newPos = __super::Seek(lOff, nFrom) - m_offset; + } + + m_posInFile = newPos + m_offset + (m_nInBuffer - m_posInBuffer); + + return newPos; +} + +void CTextFile::WriteString(LPCSTR lpsz/*CStringA str*/) +{ + CStringA str(lpsz); + + if (m_encoding == DEFAULT_ENCODING) { + __super::WriteString(AToT(str)); + } else if (m_encoding == ANSI) { + str.Replace("\n", "\r\n"); + Write((LPCSTR)str, str.GetLength()); + } else if (m_encoding == UTF8) { + WriteString(AToW(str)); + } else if (m_encoding == LE16) { + WriteString(AToW(str)); + } else if (m_encoding == BE16) { + WriteString(AToW(str)); + } +} + +CStringA ConvertUnicodeToUTF8(const CStringW& input) +{ + if (input.IsEmpty()) { + return ""; + } + CStringA utf8; + int cc = 0; + if ((cc = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, 0, 0) - 1) > 0) + { + char* buf = utf8.GetBuffer(cc); + if (buf) { + WideCharToMultiByte(CP_UTF8, 0, input, -1, buf, cc, 0, 0); + } + utf8.ReleaseBuffer(); + } + return utf8; +} + +void CTextFile::WriteString(LPCWSTR lpsz/*CStringW str*/) +{ + CStringW str(lpsz); + + if (m_encoding == DEFAULT_ENCODING) { + __super::WriteString(WToT(str)); + } else if (m_encoding == ANSI) { + str.Replace(L"\n", L"\r\n"); + CStringA stra(str); // TODO: codepage + Write((LPCSTR)stra, stra.GetLength()); + } else if (m_encoding == UTF8) { + str.Replace(L"\n", L"\r\n"); + CStringA utf8data = ConvertUnicodeToUTF8(str); + Write((LPCSTR)utf8data, utf8data.GetLength()); + } else if (m_encoding == LE16) { + str.Replace(L"\n", L"\r\n"); + Write((LPCWSTR)str, str.GetLength() * 2); + } else if (m_encoding == BE16) { + str.Replace(L"\n", L"\r\n"); + for (unsigned int i = 0, l = str.GetLength(); i < l; i++) { + str.SetAt(i, ((str[i] >> 8) & 0x00ff) | ((str[i] << 8) & 0xff00)); + } + Write((LPCWSTR)str, str.GetLength() * 2); + } +} + +bool CTextFile::FillBuffer() +{ + if (m_posInBuffer < m_nInBuffer) { + m_nInBuffer -= m_posInBuffer; + memcpy(m_buffer, &m_buffer[m_posInBuffer], (size_t)m_nInBuffer * sizeof(char)); + } else { + m_nInBuffer = 0; + } + m_posInBuffer = 0; + + UINT nBytesRead; + try { + nBytesRead = __super::Read(&m_buffer[m_nInBuffer], UINT(TEXTFILE_BUFFER_SIZE - m_nInBuffer) * sizeof(char)); + } catch (...) { + return true; // signal EOF in case of exception + } + if (nBytesRead) { + m_nInBuffer += nBytesRead; + } + + // Workaround for buggy text files that contain a duplicate UTF BOM + if (m_posInFile == m_offset && m_offset >= 2 && m_nInBuffer > 3) { + if (m_buffer[0] == '\xEF' && m_buffer[1] == '\xBB' && m_buffer[2] == '\xBF') { + m_posInBuffer = 3; + } else if (m_buffer[0] == '\xFE' && m_buffer[1] == '\xFF' || m_buffer[0] == '\xFF' && m_buffer[1] == '\xEF') { + m_posInBuffer = 2; + } + } + + m_posInFile = __super::GetPosition(); + + return !nBytesRead; +} + +ULONGLONG CTextFile::GetPositionFastBuffered() const +{ + return (m_posInFile - m_offset - (m_nInBuffer - m_posInBuffer)); +} + +BOOL CTextFile::ReadString(CStringA& str) +{ + bool fEOF = true; + + str.Truncate(0); + + if (m_encoding == DEFAULT_ENCODING) { + CString s; + fEOF = !__super::ReadString(s); + str = TToA(s); + // For consistency with other encodings, we continue reading + // the file even when a NUL char is encountered. + char c; + while (fEOF && (Read(&c, sizeof(c)) == sizeof(c))) { + str += c; + fEOF = !__super::ReadString(s); + str += TToA(s); + } + } else if (m_encoding == ANSI) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + + for (nCharsRead = 0; m_posInBuffer + nCharsRead < m_nInBuffer; nCharsRead++) { + if (m_buffer[m_posInBuffer + nCharsRead] == '\n') { + break; + } else if (m_buffer[m_posInBuffer + nCharsRead] == '\r') { + break; + } + } + + str.Append(&m_buffer[m_posInBuffer], nCharsRead); + + m_posInBuffer += nCharsRead; + while (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\r') { + m_posInBuffer++; + } + if (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer++; + } + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } else if (m_encoding == UTF8) { + ULONGLONG lineStartPos = GetPositionFastBuffered(); + bool bValid = true; + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + char* abuffer = (char*)(WCHAR*)m_wbuffer; + + for (nCharsRead = 0; m_posInBuffer < m_nInBuffer; m_posInBuffer++, nCharsRead++) { + if (Utf8::isSingleByte(m_buffer[m_posInBuffer])) { // 0xxxxxxx + abuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; + } else if (Utf8::isFirstOfMultibyte(m_buffer[m_posInBuffer])) { + int nContinuationBytes = Utf8::continuationBytes(m_buffer[m_posInBuffer]); + ASSERT(bValid); + + if (m_posInBuffer + nContinuationBytes >= m_nInBuffer) { + // If we are at the end of the file, the buffer won't be full + // and we won't be able to read any more continuation bytes. + bValid = (m_nInBuffer == TEXTFILE_BUFFER_SIZE); + break; + } else { + for (int j = 1; j <= nContinuationBytes; j++) { + if (!Utf8::isContinuation(m_buffer[m_posInBuffer + j])) { + bValid = false; + } + } + + switch (nContinuationBytes) { + case 0: // 0xxxxxxx + abuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; + break; + case 1: // 110xxxxx 10xxxxxx + case 2: // 1110xxxx 10xxxxxx 10xxxxxx + case 3: // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // Unsupported for non unicode strings + abuffer[nCharsRead] = '?'; + break; + } + m_posInBuffer += nContinuationBytes; + } + } else { + bValid = false; + TRACE(_T("Invalid UTF8 character found\n")); + } + + if (!bValid) { + abuffer[nCharsRead] = '?'; + m_posInBuffer++; + nCharsRead++; + break; + } else if (abuffer[nCharsRead] == '\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer++; + break; + } else if (abuffer[nCharsRead] == '\r') { + nCharsRead--; // Skip \r + } + } + + if (bValid || m_offset) { + str.Append(abuffer, nCharsRead); + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } else { + // Switch to text and read again + m_encoding = m_fallbackencoding; + // Stop using the buffer + m_posInBuffer = m_nInBuffer = 0; + + fEOF = !ReopenAsText(); + + if (!fEOF) { + // Seek back to the beginning of the line where we stopped + Seek(lineStartPos, begin); + + fEOF = !ReadString(str); + } + } + } while (bValid && !bLineEndFound); + } else if (m_encoding == LE16) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + WCHAR* wbuffer = (WCHAR*)&m_buffer[m_posInBuffer]; + char* abuffer = (char*)(WCHAR*)m_wbuffer; + + for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { + if (wbuffer[nCharsRead] == L'\n') { + break; // Stop at end of line + } else if (wbuffer[nCharsRead] == L'\r') { + break; // Skip \r + } else if (!(wbuffer[nCharsRead] & 0xff00)) { + abuffer[nCharsRead] = char(wbuffer[nCharsRead] & 0xff); + } else { + abuffer[nCharsRead] = '?'; + } + } + + str.Append(abuffer, nCharsRead); + + while (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\r') { + nCharsRead++; + m_posInBuffer += sizeof(WCHAR); + } + if (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\n') { + bLineEndFound = true; // Stop at end of line + nCharsRead++; + m_posInBuffer += sizeof(WCHAR); + } + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } else if (m_encoding == BE16) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + char* abuffer = (char*)(WCHAR*)m_wbuffer; + + for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { + if (!m_buffer[m_posInBuffer]) { + abuffer[nCharsRead] = m_buffer[m_posInBuffer + 1]; + } else { + abuffer[nCharsRead] = '?'; + } + + if (abuffer[nCharsRead] == '\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer += sizeof(WCHAR); + break; + } else if (abuffer[nCharsRead] == L'\r') { + nCharsRead--; // Skip \r + } + } + + str.Append(abuffer, nCharsRead); + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } + + return !fEOF; +} + +BOOL CTextFile::ReadString(CStringW& str) +{ + bool fEOF = true; + + str.Truncate(0); + + if (m_encoding == DEFAULT_ENCODING) { + CString s; + fEOF = !__super::ReadString(s); + str = TToW(s); + // For consistency with other encodings, we continue reading + // the file even when a NUL char is encountered. + char c; + while (fEOF && (Read(&c, sizeof(c)) == sizeof(c))) { + str += c; + fEOF = !__super::ReadString(s); + str += TToW(s); + } + } else if (m_encoding == ANSI) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + + for (nCharsRead = 0; m_posInBuffer + nCharsRead < m_nInBuffer; nCharsRead++) { + if (m_buffer[m_posInBuffer + nCharsRead] == '\n') { + break; + } else if (m_buffer[m_posInBuffer + nCharsRead] == '\r') { + break; + } + } + + // TODO: codepage + str.Append(CStringW(&m_buffer[m_posInBuffer], nCharsRead)); + + m_posInBuffer += nCharsRead; + while (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\r') { + m_posInBuffer++; + } + if (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer++; + } + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } else if (m_encoding == UTF8) { + ULONGLONG lineStartPos = GetPositionFastBuffered(); + bool bValid = true; + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + + for (nCharsRead = 0; m_posInBuffer < m_nInBuffer; m_posInBuffer++, nCharsRead++) { + if (Utf8::isSingleByte(m_buffer[m_posInBuffer])) { // 0xxxxxxx + m_wbuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; + } else if (Utf8::isFirstOfMultibyte(m_buffer[m_posInBuffer])) { + int nContinuationBytes = Utf8::continuationBytes(m_buffer[m_posInBuffer]); + if (m_posInBuffer + nContinuationBytes >= m_nInBuffer) { + // If we are at the end of the file, the buffer won't be full + // and we won't be able to read any more continuation bytes. + bValid = (m_nInBuffer == TEXTFILE_BUFFER_SIZE); + break; + } else { + for (int j = 1; j <= nContinuationBytes; j++) { + if (!Utf8::isContinuation(m_buffer[m_posInBuffer + j])) { //maybe redundant since MultiByteToWideChar should return zero if bad utf-8? + bValid = false; + } + } + if (bValid) { + int nWchars = MultiByteToWideChar(CP_UTF8, 0, &m_buffer[m_posInBuffer], nContinuationBytes + 1, nullptr, 0); + if (nWchars > 0) { + MultiByteToWideChar(CP_UTF8, 0, &m_buffer[m_posInBuffer], nContinuationBytes + 1, &m_wbuffer[nCharsRead], nWchars); + nCharsRead += nWchars - 1; //subtract one for loop increment + } else { + bValid = false; + } + } + m_posInBuffer += nContinuationBytes; + } + } else { + bValid = false; + TRACE(_T("Invalid UTF8 character found\n")); + } + + if (!bValid) { + m_wbuffer[nCharsRead] = L'?'; + m_posInBuffer++; + nCharsRead++; + break; + } else if (m_wbuffer[nCharsRead] == L'\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer++; + break; + } else if (m_wbuffer[nCharsRead] == L'\r') { + // check if it is followed by a '\n' + if (m_posInBuffer + 1 >= m_nInBuffer) { + bLineEndFound = FillBuffer(); + } + if (!bLineEndFound && Utf8::isSingleByte(m_buffer[m_posInBuffer+1]) && ((m_buffer[m_posInBuffer+1] & 0x7f) == L'\n')) { + nCharsRead--; // Skip '\r' + } else { + // Add the missing '\n' + nCharsRead++; + m_wbuffer[nCharsRead] = L'\n'; + bLineEndFound = true; + m_posInBuffer++; + break; + } + } + } + + if (bValid || m_offset) { + if (nCharsRead > 0) { + str.Append(m_wbuffer, nCharsRead); + } + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } else { + // Switch to text and read again + m_encoding = m_fallbackencoding; + // Stop using the buffer + m_posInBuffer = m_nInBuffer = 0; + + fEOF = !ReopenAsText(); + + if (!fEOF) { + // Seek back to the beginning of the line where we stopped + Seek(lineStartPos, begin); + + fEOF = !ReadString(str); + } + } + } while (bValid && !bLineEndFound); + } else if (m_encoding == LE16) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + WCHAR* wbuffer = (WCHAR*)&m_buffer[m_posInBuffer]; + + for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { + if (wbuffer[nCharsRead] == L'\n') { + break; // Stop at end of line + } else if (wbuffer[nCharsRead] == L'\r') { + break; // Skip \r + } + } + + str.Append(wbuffer, nCharsRead); + + while (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\r') { + nCharsRead++; + m_posInBuffer += sizeof(WCHAR); + } + if (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\n') { + bLineEndFound = true; // Stop at end of line + nCharsRead++; + m_posInBuffer += sizeof(WCHAR); + } + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } else if (m_encoding == BE16) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + + for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { + m_wbuffer[nCharsRead] = ((WCHAR(m_buffer[m_posInBuffer]) << 8) & 0xff00) | (WCHAR(m_buffer[m_posInBuffer + 1]) & 0x00ff); + if (m_wbuffer[nCharsRead] == L'\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer += sizeof(WCHAR); + break; + } else if (m_wbuffer[nCharsRead] == L'\r') { + nCharsRead--; // Skip \r + } + } + + str.Append(m_wbuffer, nCharsRead); + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } + + return !fEOF; +} + +// +// CWebTextFile +// + +CWebTextFile::CWebTextFile(CTextFile::enc e, LONGLONG llMaxSize) + : CTextFile(e) + , m_llMaxSize(llMaxSize) +{ +} + +bool CWebTextFile::Open(LPCTSTR lpszFileName) +{ + CString fn(lpszFileName); + + if (fn.Find(_T("://")) == -1) { + return __super::Open(lpszFileName); + } + + try { + CInternetSession is; + + CAutoPtr f(is.OpenURL(fn, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT)); + if (!f) { + return false; + } + + TCHAR path[MAX_PATH]; + GetTempPath(MAX_PATH, path); + + fn = path + fn.Mid(fn.ReverseFind('/') + 1); + int i = fn.Find(_T("?")); + if (i > 0) { + fn = fn.Left(i); + } + CFile temp; + if (!temp.Open(fn, modeCreate | modeWrite | typeBinary | shareDenyWrite)) { + f->Close(); + return false; + } + + BYTE buff[1024]; + int len, total = 0; + while ((len = f->Read(buff, 1024)) > 0) { + total += len; + temp.Write(buff, len); + if (m_llMaxSize > 0 && total >= m_llMaxSize) { + break; + } + } + + m_tempfn = fn; + + f->Close(); // must close it because the desctructor doesn't seem to do it and we will get an exception when "is" is destroying + } catch (CInternetException* ie) { + ie->Delete(); + return false; + } + + return __super::Open(m_tempfn); +} + +bool CWebTextFile::Save(LPCTSTR lpszFileName, enc e) +{ + // CWebTextFile is read-only... + ASSERT(0); + return false; +} + +void CWebTextFile::Close() +{ + __super::Close(); + + if (!m_tempfn.IsEmpty()) { + _tremove(m_tempfn); + m_tempfn.Empty(); + } +} + +/////////////////////////////////////////////////////////////// + +CStringW AToW(CStringA str) +{ + CStringW ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (WCHAR)(BYTE)str[i]; + } + return ret; +} + +CStringA WToA(CStringW str) +{ + CStringA ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (CHAR)(WORD)str[i]; + } + return ret; +} + +CString AToT(CStringA str) +{ +#ifdef UNICODE + CString ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (TCHAR)(BYTE)str[i]; + } + return ret; +#else + return str; +#endif +} + +CString WToT(CStringW str) +{ +#ifdef UNICODE + return str; +#else + CString ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (TCHAR)(WORD)str[i]; + } + return ret; +#endif +} + +CStringA TToA(CString str) +{ +#ifdef UNICODE + CStringA ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (CHAR)(BYTE)str[i]; + } + return ret; +#else + return str; +#endif +} + +CStringW TToW(CString str) +{ +#ifdef UNICODE + return str; +#else + CStringW ret; + for (size_t i = 0, j = str.GetLength(); i < j; i++) { + ret += (WCHAR)(BYTE)str[i]; + } + return ret; +#endif +} diff --git a/src/Subtitles/TextFile.h b/src/Subtitles/TextFile.h index d0c381af1a7..febc3177057 100644 --- a/src/Subtitles/TextFile.h +++ b/src/Subtitles/TextFile.h @@ -1,97 +1,97 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "StdioFile64.h" - -class CTextFile : protected CStdioFile64 -{ -public: - enum enc { - DEFAULT_ENCODING, - UTF8, - LE16, - BE16, - ANSI - }; - -private: - enc m_encoding, m_defaultencoding, m_fallbackencoding; - int m_offset; - ULONGLONG m_posInFile; - CAutoVectorPtr m_buffer; - CAutoVectorPtr m_wbuffer; - LONGLONG m_posInBuffer, m_nInBuffer; - -public: - using CFile::Flush; - using CFile::Close; - CTextFile(enc e = DEFAULT_ENCODING); - - virtual bool Open(LPCTSTR lpszFileName); - virtual bool Save(LPCTSTR lpszFileName, enc e /*= DEFAULT_ENCODING*/); - - void SetEncoding(enc e); - void SetFallbackEncoding(enc e); - enc GetEncoding(); - bool IsUnicode(); - - // CFile - - CString GetFilePath() const; - - // CStdioFile - - ULONGLONG GetPosition() const; - ULONGLONG GetLength() const; - ULONGLONG Seek(LONGLONG lOff, UINT nFrom); - - void WriteString(LPCSTR lpsz/*CStringA str*/); - void WriteString(LPCWSTR lpsz/*CStringW str*/); - BOOL ReadString(CStringA& str); - BOOL ReadString(CStringW& str); - -protected: - virtual bool ReopenAsText(); - bool FillBuffer(); - ULONGLONG GetPositionFastBuffered() const; -}; - -class CWebTextFile : public CTextFile -{ - LONGLONG m_llMaxSize; - CString m_tempfn; - -public: - CWebTextFile(CTextFile::enc e = DEFAULT_ENCODING, LONGLONG llMaxSize = 64 * 1024 * 1024); - - bool Open(LPCTSTR lpszFileName); - bool Save(LPCTSTR lpszFileName, enc e /*= DEFAULT_ENCODING*/); - void Close(); -}; - -extern CStringW AToW(CStringA str); -extern CStringA WToA(CStringW str); -extern CString AToT(CStringA str); -extern CString WToT(CStringW str); -extern CStringA TToA(CString str); -extern CStringW TToW(CString str); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "StdioFile64.h" + +class CTextFile : protected CStdioFile64 +{ +public: + enum enc { + DEFAULT_ENCODING, + UTF8, + LE16, + BE16, + ANSI + }; + +private: + enc m_encoding, m_defaultencoding, m_fallbackencoding; + int m_offset; + ULONGLONG m_posInFile; + CAutoVectorPtr m_buffer; + CAutoVectorPtr m_wbuffer; + LONGLONG m_posInBuffer, m_nInBuffer; + +public: + using CFile::Flush; + using CFile::Close; + CTextFile(enc e = DEFAULT_ENCODING); + + virtual bool Open(LPCTSTR lpszFileName); + virtual bool Save(LPCTSTR lpszFileName, enc e /*= DEFAULT_ENCODING*/); + + void SetEncoding(enc e); + void SetFallbackEncoding(enc e); + enc GetEncoding(); + bool IsUnicode(); + + // CFile + + CString GetFilePath() const; + + // CStdioFile + + ULONGLONG GetPosition() const; + ULONGLONG GetLength() const; + ULONGLONG Seek(LONGLONG lOff, UINT nFrom); + + void WriteString(LPCSTR lpsz/*CStringA str*/); + void WriteString(LPCWSTR lpsz/*CStringW str*/); + BOOL ReadString(CStringA& str); + BOOL ReadString(CStringW& str); + +protected: + virtual bool ReopenAsText(); + bool FillBuffer(); + ULONGLONG GetPositionFastBuffered() const; +}; + +class CWebTextFile : public CTextFile +{ + LONGLONG m_llMaxSize; + CString m_tempfn; + +public: + CWebTextFile(CTextFile::enc e = DEFAULT_ENCODING, LONGLONG llMaxSize = 64 * 1024 * 1024); + + bool Open(LPCTSTR lpszFileName); + bool Save(LPCTSTR lpszFileName, enc e /*= DEFAULT_ENCODING*/); + void Close(); +}; + +extern CStringW AToW(CStringA str); +extern CStringA WToA(CStringW str); +extern CString AToT(CStringA str); +extern CString WToT(CStringW str); +extern CStringA TToA(CString str); +extern CStringW TToW(CString str); diff --git a/src/Subtitles/USFSubtitles.cpp b/src/Subtitles/USFSubtitles.cpp index e18df8f5912..841226f4be0 100644 --- a/src/Subtitles/USFSubtitles.cpp +++ b/src/Subtitles/USFSubtitles.cpp @@ -1,783 +1,783 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "USFSubtitles.h" -#include -#include - -#define DeclareNameAndValue(pNode, name, val) \ - CComBSTR name; \ - pNode->get_nodeName(&name); \ - name.ToLower(); \ - CComVariant val; \ - pNode->get_nodeValue(&val); - -#define BeginEnumAttribs(pNode, pChild) \ - { \ - CComPtr pAttribs; \ - if (SUCCEEDED(pNode->get_attributes(&pAttribs)) && pAttribs != nullptr) { \ - CComPtr pChild; \ - for (pAttribs->nextNode(&pChild); pChild; pChild = nullptr, pAttribs->nextNode(&pChild)) { - -#define EndEnumAttribs }}} - -#define BeginEnumChildren(pNode, pChild) \ - { \ - CComPtr pChild, pChild##Next; \ - for (pNode->get_firstChild(&pChild); pChild; pChild##Next = nullptr, pChild->get_nextSibling(&pChild##Next), pChild = pChild##Next) { - -#define EndEnumChildren }} - -static CStringW GetText(CComPtr pNode) -{ - CComBSTR bstr; - pNode->get_text(&bstr); - - return CStringW(bstr); -} - -static CStringW GetXML(CComPtr pNode) -{ - CComBSTR bstr; - pNode->get_xml(&bstr); - CStringW str(bstr); - str.Remove('\r'); - str.Replace('\n', ' '); - - for (int i = 0; (i = str.Find(L" ", i)) >= 0;) { - for (++i; i < str.GetLength() && (str[i] == ' ');) { - str.Delete(i); - } - } - return str; -} - -static CStringW GetAttrib(CStringW attrib, CComPtr pNode) -{ - CStringW ret; - - BeginEnumAttribs(pNode, pChild) { - DeclareNameAndValue(pChild, name, val); - - if (CStringW(name) == attrib && val.vt == VT_BSTR) { // TODO: prepare for other types - ret = val.bstrVal; - break; - } - } - EndEnumAttribs; - - return ret; -} - -static int TimeToInt(CStringW str) -{ - CAtlList sl; - int i = 0; - for (CStringW token = str.Tokenize(L":.,", i); !token.IsEmpty(); token = str.Tokenize(L":.,", i)) { - sl.AddHead(token); - } - - if (sl.GetCount() > 4) { - return -1; - } - - int time = 0; - int mul[4] = {1, 1000, 60 * 1000, 60 * 60 * 1000}; - POSITION pos = sl.GetHeadPosition(); - - for (i = 0; pos; i++) { - const WCHAR* s = sl.GetNext(pos); - WCHAR* tmp = nullptr; - int t = wcstol(s, &tmp, 10); - if (s >= tmp) { - return -1; - } - time += t * mul[i]; - } - - return time; -} - -static DWORD StringToDWORD(CStringW str) -{ - if (str.IsEmpty()) { - return 0; - } - if (str[0] == '#') { - return (DWORD)wcstol(str, nullptr, 16); - } else { - return (DWORD)wcstol(str, nullptr, 10); - } -} - -static DWORD ColorToDWORD(CStringW str) -{ - if (str.IsEmpty()) { - return 0; - } - - DWORD ret = 0; - - if (str[0] == '#') { - ret = (DWORD)wcstol(str.TrimLeft('#'), nullptr, 16); - } else { - g_colors.Lookup(CString(str), ret); - } - - ret = ((ret & 0xff) << 16) | (ret & 0xff00ff00) | ((ret >> 16) & 0xff); - - return ret; -} - -static int TranslateAlignment(CStringW alignment) -{ - return - !alignment.CompareNoCase(L"BottomLeft") ? 1 : - !alignment.CompareNoCase(L"BottomCenter") ? 2 : - !alignment.CompareNoCase(L"BottomRight") ? 3 : - !alignment.CompareNoCase(L"MiddleLeft") ? 4 : - !alignment.CompareNoCase(L"MiddleCenter") ? 5 : - !alignment.CompareNoCase(L"MiddleRight") ? 6 : - !alignment.CompareNoCase(L"TopLeft") ? 7 : - !alignment.CompareNoCase(L"TopCenter") ? 8 : - !alignment.CompareNoCase(L"TopRight") ? 9 : - 2; -} - -static int TranslateMargin(CStringW margin, int wndsize) -{ - int ret = 0; - - if (!margin.IsEmpty()) { - ret = wcstol(margin, nullptr, 10); - if (margin.Find('%') >= 0) { - ret = wndsize * ret / 100; - } - } - - return ret; -} - -//////////////// - -CUSFSubtitles::CUSFSubtitles() -{ -} - -CUSFSubtitles::~CUSFSubtitles() -{ -} - -bool CUSFSubtitles::Read(LPCTSTR fn) -{ - VARIANT_BOOL vb; - CComPtr pDoc; - if (FAILED(pDoc.CoCreateInstance(CLSID_DOMDocument)) - || FAILED(pDoc->put_async(VARIANT_FALSE)) - || FAILED(pDoc->load(CComVariant(fn), &vb)) || vb != VARIANT_TRUE) { - return false; - } - - styles.RemoveAll(); - effects.RemoveAll(); - texts.RemoveAll(); - - if (!ParseUSFSubtitles(CComQIPtr(pDoc))) { - return false; - } - - POSITION pos = styles.GetHeadPosition(); - while (pos) { - style_t* def = styles.GetNext(pos); - - if (def->name.CompareNoCase(L"Default")) { - continue; - } - - POSITION pos2 = styles.GetHeadPosition(); - while (pos2) { - style_t* s = styles.GetNext(pos2); - - if (!s->name.CompareNoCase(L"Default")) { - continue; - } - - if (s->fontstyle.face.IsEmpty()) { - s->fontstyle.face = def->fontstyle.face; - } - if (s->fontstyle.size.IsEmpty()) { - s->fontstyle.size = def->fontstyle.size; - } - if (s->fontstyle.color[0].IsEmpty()) { - s->fontstyle.color[0] = def->fontstyle.color[0]; - } - if (s->fontstyle.color[1].IsEmpty()) { - s->fontstyle.color[1] = def->fontstyle.color[1]; - } - if (s->fontstyle.color[2].IsEmpty()) { - s->fontstyle.color[2] = def->fontstyle.color[2]; - } - if (s->fontstyle.color[3].IsEmpty()) { - s->fontstyle.color[3] = def->fontstyle.color[3]; - } - if (s->fontstyle.italic.IsEmpty()) { - s->fontstyle.italic = def->fontstyle.italic; - } - if (s->fontstyle.weight.IsEmpty()) { - s->fontstyle.weight = def->fontstyle.weight; - } - if (s->fontstyle.underline.IsEmpty()) { - s->fontstyle.underline = def->fontstyle.underline; - } - if (s->fontstyle.alpha.IsEmpty()) { - s->fontstyle.alpha = def->fontstyle.alpha; - } - if (s->fontstyle.outline.IsEmpty()) { - s->fontstyle.outline = def->fontstyle.outline; - } - if (s->fontstyle.shadow.IsEmpty()) { - s->fontstyle.shadow = def->fontstyle.shadow; - } - if (s->fontstyle.wrap.IsEmpty()) { - s->fontstyle.wrap = def->fontstyle.wrap; - } - if (s->pal.alignment.IsEmpty()) { - s->pal.alignment = def->pal.alignment; - } - if (s->pal.relativeto.IsEmpty()) { - s->pal.relativeto = def->pal.relativeto; - } - if (s->pal.horizontal_margin.IsEmpty()) { - s->pal.horizontal_margin = def->pal.horizontal_margin; - } - if (s->pal.vertical_margin.IsEmpty()) { - s->pal.vertical_margin = def->pal.vertical_margin; - } - if (s->pal.rotate[0].IsEmpty()) { - s->pal.rotate[0] = def->pal.rotate[0]; - } - if (s->pal.rotate[1].IsEmpty()) { - s->pal.rotate[1] = def->pal.rotate[1]; - } - if (s->pal.rotate[2].IsEmpty()) { - s->pal.rotate[2] = def->pal.rotate[2]; - } - } - - break; - } - - pos = texts.GetHeadPosition(); - while (pos) { - text_t* t = texts.GetNext(pos); - if (t->style.IsEmpty()) { - t->style = L"Default"; - } - } - - return true; -} - -bool CUSFSubtitles::ConvertToSTS(CSimpleTextSubtitle& sts) -{ - sts.m_name = metadata.language.text; - sts.m_encoding = CTextFile::UTF8; - sts.m_playRes = CSize(640, 480); - sts.m_scaledBAS = 0; - sts.m_defaultWrapStyle = 1; - - // TODO: map metadata.language.code to charset num (windows doesn't have such a function...) - int charSet = DEFAULT_CHARSET; - - POSITION pos = styles.GetHeadPosition(); - while (pos) { - style_t* s = styles.GetNext(pos); - - if (!s->name.CompareNoCase(L"Default") && !s->fontstyle.wrap.IsEmpty()) { - sts.m_defaultWrapStyle = - !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 : - /*!s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :*/ - 1; - } - - STSStyle* stss = DEBUG_NEW STSStyle; - if (!stss) { - continue; - } - - if (!s->pal.horizontal_margin.IsEmpty()) { - stss->marginRect.left = stss->marginRect.right = TranslateMargin(s->pal.horizontal_margin, sts.m_playRes.cx); - } - if (!s->pal.vertical_margin.IsEmpty()) { - stss->marginRect.top = stss->marginRect.bottom = TranslateMargin(s->pal.vertical_margin, sts.m_playRes.cy); - } - - stss->scrAlignment = TranslateAlignment(s->pal.alignment); - - if (!s->pal.relativeto.IsEmpty()) stss->relativeTo = - !s->pal.relativeto.CompareNoCase(L"window") ? STSStyle::WINDOW : - !s->pal.relativeto.CompareNoCase(L"video") ? STSStyle::VIDEO : - STSStyle::WINDOW; - - stss->borderStyle = 0; - if (!s->fontstyle.outline.IsEmpty()) { - stss->outlineWidthX = stss->outlineWidthY = wcstol(s->fontstyle.outline, nullptr, 10); - } - if (!s->fontstyle.shadow.IsEmpty()) { - stss->shadowDepthX = stss->shadowDepthY = wcstol(s->fontstyle.shadow, nullptr, 10); - } - - for (size_t i = 0; i < 4; i++) { - DWORD color = ColorToDWORD(s->fontstyle.color[i]); - auto alpha = (BYTE)wcstol(s->fontstyle.alpha, nullptr, 10); - - stss->colors[i] = color & 0xffffff; - stss->alpha[i] = (BYTE)(color >> 24); - - stss->alpha[i] = BYTE(stss->alpha[i] + (255 - stss->alpha[i]) * std::min(std::max(alpha, 0ui8), 100ui8) / 100); - } - - if (!s->fontstyle.face.IsEmpty()) { - stss->fontName = s->fontstyle.face; - } - if (!s->fontstyle.size.IsEmpty()) { - stss->fontSize = wcstol(s->fontstyle.size, nullptr, 10); - } - if (!s->fontstyle.weight.IsEmpty()) stss->fontWeight = - !s->fontstyle.weight.CompareNoCase(L"normal") ? FW_NORMAL : - !s->fontstyle.weight.CompareNoCase(L"bold") ? FW_BOLD : - !s->fontstyle.weight.CompareNoCase(L"lighter") ? FW_LIGHT : - !s->fontstyle.weight.CompareNoCase(L"bolder") ? FW_SEMIBOLD : - wcstol(s->fontstyle.weight, nullptr, 10); - if (stss->fontWeight == 0) { - stss->fontWeight = FW_NORMAL; - } - if (!s->fontstyle.italic.IsEmpty()) { - stss->fItalic = s->fontstyle.italic.CompareNoCase(L"yes") == 0; - } - if (!s->fontstyle.underline.IsEmpty()) { - stss->fUnderline = s->fontstyle.underline.CompareNoCase(L"yes") == 0; - } - if (!s->pal.rotate[0].IsEmpty()) { - stss->fontAngleZ = wcstol(s->pal.rotate[0], nullptr, 10); - } - if (!s->pal.rotate[1].IsEmpty()) { - stss->fontAngleX = wcstol(s->pal.rotate[1], nullptr, 10); - } - if (!s->pal.rotate[2].IsEmpty()) { - stss->fontAngleY = wcstol(s->pal.rotate[2], nullptr, 10); - } - - stss->charSet = charSet; - - sts.AddStyle(WToT(s->name), stss); - } - - pos = texts.GetHeadPosition(); - while (pos) { - text_t* t = texts.GetNext(pos); - - if (!t->pal.alignment.IsEmpty()) { - CStringW s; - s.Format(L"{\\an%d}", TranslateAlignment(t->pal.alignment)); - t->str = s + t->str; - } - - CRect marginRect; - marginRect.SetRectEmpty(); - - if (!t->pal.horizontal_margin.IsEmpty()) { - marginRect.left = marginRect.right = TranslateMargin(t->pal.horizontal_margin, sts.m_storageRes.cx); - } - if (!t->pal.vertical_margin.IsEmpty()) { - marginRect.top = marginRect.bottom = TranslateMargin(t->pal.vertical_margin, sts.m_storageRes.cy); - } - - WCHAR rtags[3][8] = {L"{\\rz%d}", L"{\\rx%d}", L"{\\ry%d}"}; - for (size_t i = 0; i < 3; i++) { - if (int angle = wcstol(t->pal.rotate[i], nullptr, 10)) { - CStringW str; - str.Format(rtags[i], angle); - t->str = str + t->str; - } - } - - if (t->style.CompareNoCase(L"Default") != 0) { - POSITION pos2 = styles.GetHeadPosition(); - while (pos2) { - style_t* s = styles.GetNext(pos2); - if (s->name == t->style && !s->fontstyle.wrap.IsEmpty()) { - int WrapStyle = - !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 : - /*!s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :*/ - 1; - - if (WrapStyle != sts.m_defaultWrapStyle) { - CStringW str; - str.Format(L"{\\q%d}", WrapStyle); - t->str = str + t->str; - } - - break; - } - } - } - - // TODO: apply effects as {\t(..)} after usf's standard clearly defines them - - sts.Add(t->str, true, t->start, t->stop, WToT(t->style), _T(""), _T(""), marginRect); - } - - return true; -} - -bool CUSFSubtitles::ParseUSFSubtitles(CComPtr pNode) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"usfsubtitles") { - // metadata - - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"metadata") { - ParseMetadata(pChild, metadata); - } - } - EndEnumChildren; - - // styles - - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"styles") { - BeginEnumChildren(pChild, pGrandChild) { // :) - DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); - - if (grandChildName == L"style") { - CAutoPtr s(DEBUG_NEW style_t); - if (s) { - ParseStyle(pGrandChild, s); - styles.AddTail(s); - } - } - } - EndEnumChildren; - } - } - EndEnumChildren; - - // effects - - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"effects") { - BeginEnumChildren(pChild, pGrandChild) { // :) - DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); - - if (grandChildName == L"effect") { - CAutoPtr e(DEBUG_NEW effect_t); - if (e) { - ParseEffect(pGrandChild, e); - effects.AddTail(e); - } - } - } - EndEnumChildren; - } - } - EndEnumChildren; - - // subtitles - - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"subtitles") { - BeginEnumChildren(pChild, pGrandChild) { // :) - DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); - - if (grandChildName == L"subtitle") { - CStringW sstart = GetAttrib(L"start", pGrandChild); - CStringW sstop = GetAttrib(L"stop", pGrandChild); - CStringW sduration = GetAttrib(L"duration", pGrandChild); - if (sstart.IsEmpty() || (sstop.IsEmpty() && sduration.IsEmpty())) { - continue; - } - - int start = TimeToInt(sstart); - int stop = !sstop.IsEmpty() ? TimeToInt(sstop) : (start + TimeToInt(sduration)); - - ParseSubtitle(pGrandChild, start, stop); - } - } - EndEnumChildren; - } - } - EndEnumChildren; - - return true; - } - - BeginEnumChildren(pNode, pChild) { - if (ParseUSFSubtitles(pChild)) { - return true; - } - } - EndEnumChildren; - - return false; -} - -void CUSFSubtitles::ParseMetadata(CComPtr pNode, metadata_t& m) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"title") { - m.title = GetText(pNode); - } else if (name == L"date") { - m.date = GetText(pNode); - } else if (name == L"comment") { - m.comment = GetText(pNode); - } else if (name == L"author") { - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"name") { - m.author.name = GetText(pChild); - } else if (childName == L"email") { - m.author.email = GetText(pChild); - } else if (childName == L"url") { - m.author.url = GetText(pChild); - } - } - EndEnumChildren; - - return; - } else if (name == L"language") { - m.language.text = GetText(pNode); - m.language.code = GetAttrib(L"code", pNode); - } else if (name == L"languageext") { - m.languageext.text = GetText(pNode); - m.languageext.code = GetAttrib(L"code", pNode); - } - - BeginEnumChildren(pNode, pChild) { - ParseMetadata(pChild, metadata); - } - EndEnumChildren; -} - -void CUSFSubtitles::ParseStyle(CComPtr pNode, style_t* s) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"style") { - s->name = GetAttrib(L"name", pNode); - } else if (name == L"fontstyle") { - ParseFontstyle(pNode, s->fontstyle); - return; - } else if (name == L"position") { - ParsePal(pNode, s->pal); - return; - } - - BeginEnumChildren(pNode, pChild) { - ParseStyle(pChild, s); - } - EndEnumChildren; -} - -void CUSFSubtitles::ParseFontstyle(CComPtr pNode, fontstyle_t& fs) -{ - fs.face = GetAttrib(L"face", pNode); - fs.size = GetAttrib(L"size", pNode); - fs.color[0] = GetAttrib(L"color", pNode); - fs.color[1] = GetAttrib(L"back-color", pNode); - fs.color[2] = GetAttrib(L"outline-color", pNode); - fs.color[3] = GetAttrib(L"shadow-color", pNode); - fs.italic = GetAttrib(L"italic", pNode); - fs.weight = GetAttrib(L"weight", pNode); - fs.underline = GetAttrib(L"underline", pNode); - fs.alpha = GetAttrib(L"alpha", pNode); - fs.outline = GetAttrib(L"outline-level", pNode); - fs.shadow = GetAttrib(L"shadow-level", pNode); - fs.wrap = GetAttrib(L"wrap", pNode); -} - -void CUSFSubtitles::ParsePal(CComPtr pNode, posattriblist_t& pal) -{ - pal.alignment = GetAttrib(L"alignment", pNode); - pal.relativeto = GetAttrib(L"relative-to", pNode); - pal.horizontal_margin = GetAttrib(L"horizontal-margin", pNode); - pal.vertical_margin = GetAttrib(L"vertical-margin", pNode); - pal.rotate[0] = GetAttrib(L"rotate-z", pNode); - pal.rotate[1] = GetAttrib(L"rotate-x", pNode); - pal.rotate[2] = GetAttrib(L"rotate-y", pNode); -} - -void CUSFSubtitles::ParseEffect(CComPtr pNode, effect_t* e) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"effect") { - e->name = GetAttrib(L"name", pNode); - } else if (name == L"keyframes") { - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"keyframe") { - CAutoPtr k(DEBUG_NEW keyframe_t); - if (k) { - ParseKeyframe(pChild, k); - e->keyframes.AddTail(k); - } - } - } - EndEnumChildren; - - return; - } - - BeginEnumChildren(pNode, pChild) { - ParseEffect(pChild, e); - } - EndEnumChildren; -} - -void CUSFSubtitles::ParseKeyframe(CComPtr pNode, keyframe_t* k) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"keyframe") { - k->position = GetAttrib(L"position", pNode); - } else if (name == L"fontstyle") { - ParseFontstyle(pNode, k->fontstyle); - return; - } else if (name == L"position") { - ParsePal(pNode, k->pal); - return; - } -} - -void CUSFSubtitles::ParseSubtitle(CComPtr pNode, int start, int stop) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"text" || name == L"karaoke") { - CAutoPtr t(DEBUG_NEW text_t); - if (t) { - t->start = start; - t->stop = stop; - t->style = GetAttrib(L"style", pNode); - t->effect = GetAttrib(L"effect", pNode); - ParsePal(pNode, t->pal); - ParseText(pNode, t->str); - texts.AddTail(t); - } - - return; - } - // else if - - BeginEnumChildren(pNode, pChild) { - ParseSubtitle(pChild, start, stop); - } - EndEnumChildren; -} - -void CUSFSubtitles::ParseText(CComPtr pNode, CStringW& str) -{ - DeclareNameAndValue(pNode, name, val); - - CStringW prefix, postfix; - - if (name == L"b") { - prefix = L"{\\b1}"; - postfix = L"{\\b}"; - } else if (name == L"i") { - prefix = L"{\\i1}"; - postfix = L"{\\i}"; - } else if (name == L"u") { - prefix = L"{\\u1}"; - postfix = L"{\\u}"; - } else if (name == L"font") { - fontstyle_t fs; - ParseFontstyle(pNode, fs); - - if (!fs.face.IsEmpty()) { - prefix += L"{\\fn" + fs.face + L"}"; - postfix += L"{\\fn}"; - } - if (!fs.size.IsEmpty()) { - prefix += L"{\\fs" + fs.size + L"}"; - postfix += L"{\\fs}"; - } - if (!fs.outline.IsEmpty()) { - prefix += L"{\\bord" + fs.outline + L"}"; - postfix += L"{\\bord}"; - } - if (!fs.shadow.IsEmpty()) { - prefix += L"{\\shad" + fs.shadow + L"}"; - postfix += L"{\\shad}"; - } - - for (size_t i = 0; i < 4; i++) { - if (!fs.color[i].IsEmpty()) { - CStringW s; - s.Format(L"{\\%uc&H%06x&}", i + 1, ColorToDWORD(fs.color[i])); - prefix += s; - s.Format(L"{\\%uc}", i + 1); - postfix += s; - } - } - } else if (name == L"k") { - int t = wcstol(GetAttrib(L"t", pNode), nullptr, 10); - CStringW s; - s.Format(L"{\\kf%d}", t / 10); - str += s; - return; - } else if (name == L"br") { - str += L"\\N"; - return; - } else if (name == L"#text") { - str += GetXML(pNode); - return; - } - - BeginEnumChildren(pNode, pChild) { - CStringW s; - ParseText(pChild, s); - str += s; - } - EndEnumChildren; - - str = prefix + str + postfix; -} - -void CUSFSubtitles::ParseShape(CComPtr pNode) -{ - // no specs on this yet -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "USFSubtitles.h" +#include +#include + +#define DeclareNameAndValue(pNode, name, val) \ + CComBSTR name; \ + pNode->get_nodeName(&name); \ + name.ToLower(); \ + CComVariant val; \ + pNode->get_nodeValue(&val); + +#define BeginEnumAttribs(pNode, pChild) \ + { \ + CComPtr pAttribs; \ + if (SUCCEEDED(pNode->get_attributes(&pAttribs)) && pAttribs != nullptr) { \ + CComPtr pChild; \ + for (pAttribs->nextNode(&pChild); pChild; pChild = nullptr, pAttribs->nextNode(&pChild)) { + +#define EndEnumAttribs }}} + +#define BeginEnumChildren(pNode, pChild) \ + { \ + CComPtr pChild, pChild##Next; \ + for (pNode->get_firstChild(&pChild); pChild; pChild##Next = nullptr, pChild->get_nextSibling(&pChild##Next), pChild = pChild##Next) { + +#define EndEnumChildren }} + +static CStringW GetText(CComPtr pNode) +{ + CComBSTR bstr; + pNode->get_text(&bstr); + + return CStringW(bstr); +} + +static CStringW GetXML(CComPtr pNode) +{ + CComBSTR bstr; + pNode->get_xml(&bstr); + CStringW str(bstr); + str.Remove('\r'); + str.Replace('\n', ' '); + + for (int i = 0; (i = str.Find(L" ", i)) >= 0;) { + for (++i; i < str.GetLength() && (str[i] == ' ');) { + str.Delete(i); + } + } + return str; +} + +static CStringW GetAttrib(CStringW attrib, CComPtr pNode) +{ + CStringW ret; + + BeginEnumAttribs(pNode, pChild) { + DeclareNameAndValue(pChild, name, val); + + if (CStringW(name) == attrib && val.vt == VT_BSTR) { // TODO: prepare for other types + ret = val.bstrVal; + break; + } + } + EndEnumAttribs; + + return ret; +} + +static int TimeToInt(CStringW str) +{ + CAtlList sl; + int i = 0; + for (CStringW token = str.Tokenize(L":.,", i); !token.IsEmpty(); token = str.Tokenize(L":.,", i)) { + sl.AddHead(token); + } + + if (sl.GetCount() > 4) { + return -1; + } + + int time = 0; + int mul[4] = {1, 1000, 60 * 1000, 60 * 60 * 1000}; + POSITION pos = sl.GetHeadPosition(); + + for (i = 0; pos; i++) { + const WCHAR* s = sl.GetNext(pos); + WCHAR* tmp = nullptr; + int t = wcstol(s, &tmp, 10); + if (s >= tmp) { + return -1; + } + time += t * mul[i]; + } + + return time; +} + +static DWORD StringToDWORD(CStringW str) +{ + if (str.IsEmpty()) { + return 0; + } + if (str[0] == '#') { + return (DWORD)wcstol(str, nullptr, 16); + } else { + return (DWORD)wcstol(str, nullptr, 10); + } +} + +static DWORD ColorToDWORD(CStringW str) +{ + if (str.IsEmpty()) { + return 0; + } + + DWORD ret = 0; + + if (str[0] == '#') { + ret = (DWORD)wcstol(str.TrimLeft('#'), nullptr, 16); + } else { + g_colors.Lookup(CString(str), ret); + } + + ret = ((ret & 0xff) << 16) | (ret & 0xff00ff00) | ((ret >> 16) & 0xff); + + return ret; +} + +static int TranslateAlignment(CStringW alignment) +{ + return + !alignment.CompareNoCase(L"BottomLeft") ? 1 : + !alignment.CompareNoCase(L"BottomCenter") ? 2 : + !alignment.CompareNoCase(L"BottomRight") ? 3 : + !alignment.CompareNoCase(L"MiddleLeft") ? 4 : + !alignment.CompareNoCase(L"MiddleCenter") ? 5 : + !alignment.CompareNoCase(L"MiddleRight") ? 6 : + !alignment.CompareNoCase(L"TopLeft") ? 7 : + !alignment.CompareNoCase(L"TopCenter") ? 8 : + !alignment.CompareNoCase(L"TopRight") ? 9 : + 2; +} + +static int TranslateMargin(CStringW margin, int wndsize) +{ + int ret = 0; + + if (!margin.IsEmpty()) { + ret = wcstol(margin, nullptr, 10); + if (margin.Find('%') >= 0) { + ret = wndsize * ret / 100; + } + } + + return ret; +} + +//////////////// + +CUSFSubtitles::CUSFSubtitles() +{ +} + +CUSFSubtitles::~CUSFSubtitles() +{ +} + +bool CUSFSubtitles::Read(LPCTSTR fn) +{ + VARIANT_BOOL vb; + CComPtr pDoc; + if (FAILED(pDoc.CoCreateInstance(CLSID_DOMDocument)) + || FAILED(pDoc->put_async(VARIANT_FALSE)) + || FAILED(pDoc->load(CComVariant(fn), &vb)) || vb != VARIANT_TRUE) { + return false; + } + + styles.RemoveAll(); + effects.RemoveAll(); + texts.RemoveAll(); + + if (!ParseUSFSubtitles(CComQIPtr(pDoc))) { + return false; + } + + POSITION pos = styles.GetHeadPosition(); + while (pos) { + style_t* def = styles.GetNext(pos); + + if (def->name.CompareNoCase(L"Default")) { + continue; + } + + POSITION pos2 = styles.GetHeadPosition(); + while (pos2) { + style_t* s = styles.GetNext(pos2); + + if (!s->name.CompareNoCase(L"Default")) { + continue; + } + + if (s->fontstyle.face.IsEmpty()) { + s->fontstyle.face = def->fontstyle.face; + } + if (s->fontstyle.size.IsEmpty()) { + s->fontstyle.size = def->fontstyle.size; + } + if (s->fontstyle.color[0].IsEmpty()) { + s->fontstyle.color[0] = def->fontstyle.color[0]; + } + if (s->fontstyle.color[1].IsEmpty()) { + s->fontstyle.color[1] = def->fontstyle.color[1]; + } + if (s->fontstyle.color[2].IsEmpty()) { + s->fontstyle.color[2] = def->fontstyle.color[2]; + } + if (s->fontstyle.color[3].IsEmpty()) { + s->fontstyle.color[3] = def->fontstyle.color[3]; + } + if (s->fontstyle.italic.IsEmpty()) { + s->fontstyle.italic = def->fontstyle.italic; + } + if (s->fontstyle.weight.IsEmpty()) { + s->fontstyle.weight = def->fontstyle.weight; + } + if (s->fontstyle.underline.IsEmpty()) { + s->fontstyle.underline = def->fontstyle.underline; + } + if (s->fontstyle.alpha.IsEmpty()) { + s->fontstyle.alpha = def->fontstyle.alpha; + } + if (s->fontstyle.outline.IsEmpty()) { + s->fontstyle.outline = def->fontstyle.outline; + } + if (s->fontstyle.shadow.IsEmpty()) { + s->fontstyle.shadow = def->fontstyle.shadow; + } + if (s->fontstyle.wrap.IsEmpty()) { + s->fontstyle.wrap = def->fontstyle.wrap; + } + if (s->pal.alignment.IsEmpty()) { + s->pal.alignment = def->pal.alignment; + } + if (s->pal.relativeto.IsEmpty()) { + s->pal.relativeto = def->pal.relativeto; + } + if (s->pal.horizontal_margin.IsEmpty()) { + s->pal.horizontal_margin = def->pal.horizontal_margin; + } + if (s->pal.vertical_margin.IsEmpty()) { + s->pal.vertical_margin = def->pal.vertical_margin; + } + if (s->pal.rotate[0].IsEmpty()) { + s->pal.rotate[0] = def->pal.rotate[0]; + } + if (s->pal.rotate[1].IsEmpty()) { + s->pal.rotate[1] = def->pal.rotate[1]; + } + if (s->pal.rotate[2].IsEmpty()) { + s->pal.rotate[2] = def->pal.rotate[2]; + } + } + + break; + } + + pos = texts.GetHeadPosition(); + while (pos) { + text_t* t = texts.GetNext(pos); + if (t->style.IsEmpty()) { + t->style = L"Default"; + } + } + + return true; +} + +bool CUSFSubtitles::ConvertToSTS(CSimpleTextSubtitle& sts) +{ + sts.m_name = metadata.language.text; + sts.m_encoding = CTextFile::UTF8; + sts.m_playRes = CSize(640, 480); + sts.m_scaledBAS = 0; + sts.m_defaultWrapStyle = 1; + + // TODO: map metadata.language.code to charset num (windows doesn't have such a function...) + int charSet = DEFAULT_CHARSET; + + POSITION pos = styles.GetHeadPosition(); + while (pos) { + style_t* s = styles.GetNext(pos); + + if (!s->name.CompareNoCase(L"Default") && !s->fontstyle.wrap.IsEmpty()) { + sts.m_defaultWrapStyle = + !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 : + /*!s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :*/ + 1; + } + + STSStyle* stss = DEBUG_NEW STSStyle; + if (!stss) { + continue; + } + + if (!s->pal.horizontal_margin.IsEmpty()) { + stss->marginRect.left = stss->marginRect.right = TranslateMargin(s->pal.horizontal_margin, sts.m_playRes.cx); + } + if (!s->pal.vertical_margin.IsEmpty()) { + stss->marginRect.top = stss->marginRect.bottom = TranslateMargin(s->pal.vertical_margin, sts.m_playRes.cy); + } + + stss->scrAlignment = TranslateAlignment(s->pal.alignment); + + if (!s->pal.relativeto.IsEmpty()) stss->relativeTo = + !s->pal.relativeto.CompareNoCase(L"window") ? STSStyle::WINDOW : + !s->pal.relativeto.CompareNoCase(L"video") ? STSStyle::VIDEO : + STSStyle::WINDOW; + + stss->borderStyle = 0; + if (!s->fontstyle.outline.IsEmpty()) { + stss->outlineWidthX = stss->outlineWidthY = wcstol(s->fontstyle.outline, nullptr, 10); + } + if (!s->fontstyle.shadow.IsEmpty()) { + stss->shadowDepthX = stss->shadowDepthY = wcstol(s->fontstyle.shadow, nullptr, 10); + } + + for (size_t i = 0; i < 4; i++) { + DWORD color = ColorToDWORD(s->fontstyle.color[i]); + auto alpha = (BYTE)wcstol(s->fontstyle.alpha, nullptr, 10); + + stss->colors[i] = color & 0xffffff; + stss->alpha[i] = (BYTE)(color >> 24); + + stss->alpha[i] = BYTE(stss->alpha[i] + (255 - stss->alpha[i]) * std::min(std::max(alpha, 0ui8), 100ui8) / 100); + } + + if (!s->fontstyle.face.IsEmpty()) { + stss->fontName = s->fontstyle.face; + } + if (!s->fontstyle.size.IsEmpty()) { + stss->fontSize = wcstol(s->fontstyle.size, nullptr, 10); + } + if (!s->fontstyle.weight.IsEmpty()) stss->fontWeight = + !s->fontstyle.weight.CompareNoCase(L"normal") ? FW_NORMAL : + !s->fontstyle.weight.CompareNoCase(L"bold") ? FW_BOLD : + !s->fontstyle.weight.CompareNoCase(L"lighter") ? FW_LIGHT : + !s->fontstyle.weight.CompareNoCase(L"bolder") ? FW_SEMIBOLD : + wcstol(s->fontstyle.weight, nullptr, 10); + if (stss->fontWeight == 0) { + stss->fontWeight = FW_NORMAL; + } + if (!s->fontstyle.italic.IsEmpty()) { + stss->fItalic = s->fontstyle.italic.CompareNoCase(L"yes") == 0; + } + if (!s->fontstyle.underline.IsEmpty()) { + stss->fUnderline = s->fontstyle.underline.CompareNoCase(L"yes") == 0; + } + if (!s->pal.rotate[0].IsEmpty()) { + stss->fontAngleZ = wcstol(s->pal.rotate[0], nullptr, 10); + } + if (!s->pal.rotate[1].IsEmpty()) { + stss->fontAngleX = wcstol(s->pal.rotate[1], nullptr, 10); + } + if (!s->pal.rotate[2].IsEmpty()) { + stss->fontAngleY = wcstol(s->pal.rotate[2], nullptr, 10); + } + + stss->charSet = charSet; + + sts.AddStyle(WToT(s->name), stss); + } + + pos = texts.GetHeadPosition(); + while (pos) { + text_t* t = texts.GetNext(pos); + + if (!t->pal.alignment.IsEmpty()) { + CStringW s; + s.Format(L"{\\an%d}", TranslateAlignment(t->pal.alignment)); + t->str = s + t->str; + } + + CRect marginRect; + marginRect.SetRectEmpty(); + + if (!t->pal.horizontal_margin.IsEmpty()) { + marginRect.left = marginRect.right = TranslateMargin(t->pal.horizontal_margin, sts.m_storageRes.cx); + } + if (!t->pal.vertical_margin.IsEmpty()) { + marginRect.top = marginRect.bottom = TranslateMargin(t->pal.vertical_margin, sts.m_storageRes.cy); + } + + WCHAR rtags[3][8] = {L"{\\rz%d}", L"{\\rx%d}", L"{\\ry%d}"}; + for (size_t i = 0; i < 3; i++) { + if (int angle = wcstol(t->pal.rotate[i], nullptr, 10)) { + CStringW str; + str.Format(rtags[i], angle); + t->str = str + t->str; + } + } + + if (t->style.CompareNoCase(L"Default") != 0) { + POSITION pos2 = styles.GetHeadPosition(); + while (pos2) { + style_t* s = styles.GetNext(pos2); + if (s->name == t->style && !s->fontstyle.wrap.IsEmpty()) { + int WrapStyle = + !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 : + /*!s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :*/ + 1; + + if (WrapStyle != sts.m_defaultWrapStyle) { + CStringW str; + str.Format(L"{\\q%d}", WrapStyle); + t->str = str + t->str; + } + + break; + } + } + } + + // TODO: apply effects as {\t(..)} after usf's standard clearly defines them + + sts.Add(t->str, true, t->start, t->stop, WToT(t->style), _T(""), _T(""), marginRect); + } + + return true; +} + +bool CUSFSubtitles::ParseUSFSubtitles(CComPtr pNode) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"usfsubtitles") { + // metadata + + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"metadata") { + ParseMetadata(pChild, metadata); + } + } + EndEnumChildren; + + // styles + + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"styles") { + BeginEnumChildren(pChild, pGrandChild) { // :) + DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); + + if (grandChildName == L"style") { + CAutoPtr s(DEBUG_NEW style_t); + if (s) { + ParseStyle(pGrandChild, s); + styles.AddTail(s); + } + } + } + EndEnumChildren; + } + } + EndEnumChildren; + + // effects + + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"effects") { + BeginEnumChildren(pChild, pGrandChild) { // :) + DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); + + if (grandChildName == L"effect") { + CAutoPtr e(DEBUG_NEW effect_t); + if (e) { + ParseEffect(pGrandChild, e); + effects.AddTail(e); + } + } + } + EndEnumChildren; + } + } + EndEnumChildren; + + // subtitles + + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"subtitles") { + BeginEnumChildren(pChild, pGrandChild) { // :) + DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); + + if (grandChildName == L"subtitle") { + CStringW sstart = GetAttrib(L"start", pGrandChild); + CStringW sstop = GetAttrib(L"stop", pGrandChild); + CStringW sduration = GetAttrib(L"duration", pGrandChild); + if (sstart.IsEmpty() || (sstop.IsEmpty() && sduration.IsEmpty())) { + continue; + } + + int start = TimeToInt(sstart); + int stop = !sstop.IsEmpty() ? TimeToInt(sstop) : (start + TimeToInt(sduration)); + + ParseSubtitle(pGrandChild, start, stop); + } + } + EndEnumChildren; + } + } + EndEnumChildren; + + return true; + } + + BeginEnumChildren(pNode, pChild) { + if (ParseUSFSubtitles(pChild)) { + return true; + } + } + EndEnumChildren; + + return false; +} + +void CUSFSubtitles::ParseMetadata(CComPtr pNode, metadata_t& m) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"title") { + m.title = GetText(pNode); + } else if (name == L"date") { + m.date = GetText(pNode); + } else if (name == L"comment") { + m.comment = GetText(pNode); + } else if (name == L"author") { + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"name") { + m.author.name = GetText(pChild); + } else if (childName == L"email") { + m.author.email = GetText(pChild); + } else if (childName == L"url") { + m.author.url = GetText(pChild); + } + } + EndEnumChildren; + + return; + } else if (name == L"language") { + m.language.text = GetText(pNode); + m.language.code = GetAttrib(L"code", pNode); + } else if (name == L"languageext") { + m.languageext.text = GetText(pNode); + m.languageext.code = GetAttrib(L"code", pNode); + } + + BeginEnumChildren(pNode, pChild) { + ParseMetadata(pChild, metadata); + } + EndEnumChildren; +} + +void CUSFSubtitles::ParseStyle(CComPtr pNode, style_t* s) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"style") { + s->name = GetAttrib(L"name", pNode); + } else if (name == L"fontstyle") { + ParseFontstyle(pNode, s->fontstyle); + return; + } else if (name == L"position") { + ParsePal(pNode, s->pal); + return; + } + + BeginEnumChildren(pNode, pChild) { + ParseStyle(pChild, s); + } + EndEnumChildren; +} + +void CUSFSubtitles::ParseFontstyle(CComPtr pNode, fontstyle_t& fs) +{ + fs.face = GetAttrib(L"face", pNode); + fs.size = GetAttrib(L"size", pNode); + fs.color[0] = GetAttrib(L"color", pNode); + fs.color[1] = GetAttrib(L"back-color", pNode); + fs.color[2] = GetAttrib(L"outline-color", pNode); + fs.color[3] = GetAttrib(L"shadow-color", pNode); + fs.italic = GetAttrib(L"italic", pNode); + fs.weight = GetAttrib(L"weight", pNode); + fs.underline = GetAttrib(L"underline", pNode); + fs.alpha = GetAttrib(L"alpha", pNode); + fs.outline = GetAttrib(L"outline-level", pNode); + fs.shadow = GetAttrib(L"shadow-level", pNode); + fs.wrap = GetAttrib(L"wrap", pNode); +} + +void CUSFSubtitles::ParsePal(CComPtr pNode, posattriblist_t& pal) +{ + pal.alignment = GetAttrib(L"alignment", pNode); + pal.relativeto = GetAttrib(L"relative-to", pNode); + pal.horizontal_margin = GetAttrib(L"horizontal-margin", pNode); + pal.vertical_margin = GetAttrib(L"vertical-margin", pNode); + pal.rotate[0] = GetAttrib(L"rotate-z", pNode); + pal.rotate[1] = GetAttrib(L"rotate-x", pNode); + pal.rotate[2] = GetAttrib(L"rotate-y", pNode); +} + +void CUSFSubtitles::ParseEffect(CComPtr pNode, effect_t* e) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"effect") { + e->name = GetAttrib(L"name", pNode); + } else if (name == L"keyframes") { + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"keyframe") { + CAutoPtr k(DEBUG_NEW keyframe_t); + if (k) { + ParseKeyframe(pChild, k); + e->keyframes.AddTail(k); + } + } + } + EndEnumChildren; + + return; + } + + BeginEnumChildren(pNode, pChild) { + ParseEffect(pChild, e); + } + EndEnumChildren; +} + +void CUSFSubtitles::ParseKeyframe(CComPtr pNode, keyframe_t* k) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"keyframe") { + k->position = GetAttrib(L"position", pNode); + } else if (name == L"fontstyle") { + ParseFontstyle(pNode, k->fontstyle); + return; + } else if (name == L"position") { + ParsePal(pNode, k->pal); + return; + } +} + +void CUSFSubtitles::ParseSubtitle(CComPtr pNode, int start, int stop) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"text" || name == L"karaoke") { + CAutoPtr t(DEBUG_NEW text_t); + if (t) { + t->start = start; + t->stop = stop; + t->style = GetAttrib(L"style", pNode); + t->effect = GetAttrib(L"effect", pNode); + ParsePal(pNode, t->pal); + ParseText(pNode, t->str); + texts.AddTail(t); + } + + return; + } + // else if + + BeginEnumChildren(pNode, pChild) { + ParseSubtitle(pChild, start, stop); + } + EndEnumChildren; +} + +void CUSFSubtitles::ParseText(CComPtr pNode, CStringW& str) +{ + DeclareNameAndValue(pNode, name, val); + + CStringW prefix, postfix; + + if (name == L"b") { + prefix = L"{\\b1}"; + postfix = L"{\\b}"; + } else if (name == L"i") { + prefix = L"{\\i1}"; + postfix = L"{\\i}"; + } else if (name == L"u") { + prefix = L"{\\u1}"; + postfix = L"{\\u}"; + } else if (name == L"font") { + fontstyle_t fs; + ParseFontstyle(pNode, fs); + + if (!fs.face.IsEmpty()) { + prefix += L"{\\fn" + fs.face + L"}"; + postfix += L"{\\fn}"; + } + if (!fs.size.IsEmpty()) { + prefix += L"{\\fs" + fs.size + L"}"; + postfix += L"{\\fs}"; + } + if (!fs.outline.IsEmpty()) { + prefix += L"{\\bord" + fs.outline + L"}"; + postfix += L"{\\bord}"; + } + if (!fs.shadow.IsEmpty()) { + prefix += L"{\\shad" + fs.shadow + L"}"; + postfix += L"{\\shad}"; + } + + for (size_t i = 0; i < 4; i++) { + if (!fs.color[i].IsEmpty()) { + CStringW s; + s.Format(L"{\\%uc&H%06x&}", i + 1, ColorToDWORD(fs.color[i])); + prefix += s; + s.Format(L"{\\%uc}", i + 1); + postfix += s; + } + } + } else if (name == L"k") { + int t = wcstol(GetAttrib(L"t", pNode), nullptr, 10); + CStringW s; + s.Format(L"{\\kf%d}", t / 10); + str += s; + return; + } else if (name == L"br") { + str += L"\\N"; + return; + } else if (name == L"#text") { + str += GetXML(pNode); + return; + } + + BeginEnumChildren(pNode, pChild) { + CStringW s; + ParseText(pChild, s); + str += s; + } + EndEnumChildren; + + str = prefix + str + postfix; +} + +void CUSFSubtitles::ParseShape(CComPtr pNode) +{ + // no specs on this yet +} diff --git a/src/Subtitles/USFSubtitles.h b/src/Subtitles/USFSubtitles.h index 2d81a34ee89..c80eecec0ff 100644 --- a/src/Subtitles/USFSubtitles.h +++ b/src/Subtitles/USFSubtitles.h @@ -1,103 +1,103 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "STS.h" - -// metadata -struct author_t { - CStringW name, email, url; -}; - -struct language_t { - CStringW code, text; -}; - -struct metadata_t { - CStringW title, date, comment; - author_t author; - language_t language, languageext; -}; - -// style -struct posattriblist_t { - CStringW alignment, relativeto, horizontal_margin, vertical_margin, rotate[3]; -}; - -struct fontstyle_t { - CStringW face, size, color[4], weight, italic, underline, alpha, outline, shadow, wrap; -}; - -struct style_t { - CStringW name; - fontstyle_t fontstyle; - posattriblist_t pal; -}; - -// effect -struct keyframe_t { - CStringW position; - fontstyle_t fontstyle; - posattriblist_t pal; -}; - -struct effect_t { - CStringW name; - CAutoPtrList keyframes; -}; - -// subtitle/text -struct text_t { - int start, stop; - CStringW effect, style, str; - posattriblist_t pal; -}; - -class CUSFSubtitles -{ - bool ParseUSFSubtitles(CComPtr pNode); - void ParseMetadata(CComPtr pNode, metadata_t& m); - void ParseStyle(CComPtr pNode, style_t* s); - void ParseFontstyle(CComPtr pNode, fontstyle_t& fs); - void ParsePal(CComPtr pNode, posattriblist_t& pal); - void ParseEffect(CComPtr pNode, effect_t* e); - void ParseKeyframe(CComPtr pNode, keyframe_t* k); - void ParseSubtitle(CComPtr pNode, int start, int stop); - void ParseText(CComPtr pNode, CStringW& assstr); - void ParseShape(CComPtr pNode); - -public: - CUSFSubtitles(); - virtual ~CUSFSubtitles(); - - bool Read(LPCTSTR fn); - //bool Write(LPCTSTR fn); // TODO - - metadata_t metadata; - CAutoPtrList styles; - CAutoPtrList effects; - CAutoPtrList texts; - - bool ConvertToSTS(CSimpleTextSubtitle& sts); - //bool ConvertFromSTS(CSimpleTextSubtitle& sts); // TODO -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "STS.h" + +// metadata +struct author_t { + CStringW name, email, url; +}; + +struct language_t { + CStringW code, text; +}; + +struct metadata_t { + CStringW title, date, comment; + author_t author; + language_t language, languageext; +}; + +// style +struct posattriblist_t { + CStringW alignment, relativeto, horizontal_margin, vertical_margin, rotate[3]; +}; + +struct fontstyle_t { + CStringW face, size, color[4], weight, italic, underline, alpha, outline, shadow, wrap; +}; + +struct style_t { + CStringW name; + fontstyle_t fontstyle; + posattriblist_t pal; +}; + +// effect +struct keyframe_t { + CStringW position; + fontstyle_t fontstyle; + posattriblist_t pal; +}; + +struct effect_t { + CStringW name; + CAutoPtrList keyframes; +}; + +// subtitle/text +struct text_t { + int start, stop; + CStringW effect, style, str; + posattriblist_t pal; +}; + +class CUSFSubtitles +{ + bool ParseUSFSubtitles(CComPtr pNode); + void ParseMetadata(CComPtr pNode, metadata_t& m); + void ParseStyle(CComPtr pNode, style_t* s); + void ParseFontstyle(CComPtr pNode, fontstyle_t& fs); + void ParsePal(CComPtr pNode, posattriblist_t& pal); + void ParseEffect(CComPtr pNode, effect_t* e); + void ParseKeyframe(CComPtr pNode, keyframe_t* k); + void ParseSubtitle(CComPtr pNode, int start, int stop); + void ParseText(CComPtr pNode, CStringW& assstr); + void ParseShape(CComPtr pNode); + +public: + CUSFSubtitles(); + virtual ~CUSFSubtitles(); + + bool Read(LPCTSTR fn); + //bool Write(LPCTSTR fn); // TODO + + metadata_t metadata; + CAutoPtrList styles; + CAutoPtrList effects; + CAutoPtrList texts; + + bool ConvertToSTS(CSimpleTextSubtitle& sts); + //bool ConvertFromSTS(CSimpleTextSubtitle& sts); // TODO +}; diff --git a/src/Subtitles/VobSubFile.cpp b/src/Subtitles/VobSubFile.cpp index 9ee8a5210f0..afba8f9120b 100644 --- a/src/Subtitles/VobSubFile.cpp +++ b/src/Subtitles/VobSubFile.cpp @@ -1,2650 +1,2650 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "TextFile.h" -#include "VobSubFile.h" -#include "mpc-hc_config.h" - -#if !USE_STATIC_UNRAR -#include "unrar.h" -#else -#include "unrar/dll.hpp" -#endif -#include "RTS.h" -#include "../DSUtil/PathUtils.h" -#include "../DSUtil/ISOLang.h" - -// - -struct lang_type { - unsigned short id; - LPCSTR lang_long; -} static constexpr lang_tbl[] = { - {'--', "(Not detected)"}, - {'cc', "Closed Caption"}, - {'aa', "Afar"}, - {'ab', "Abkhazian"}, - {'af', "Afrikaans"}, - {'am', "Amharic"}, - {'ar', "Arabic"}, - {'as', "Assamese"}, - {'ay', "Aymara"}, - {'az', "Azerbaijani"}, - {'ba', "Bashkir"}, - {'be', "Byelorussian"}, - {'bg', "Bulgarian"}, - {'bh', "Bihari"}, - {'bi', "Bislama"}, - {'bn', "Bengali; Bangla"}, - {'bo', "Tibetan"}, - {'br', "Breton"}, - {'ca', "Catalan"}, - {'co', "Corsican"}, - {'cs', "Czech"}, - {'cy', "Welsh"}, - {'da', "Dansk"}, - {'de', "Deutsch"}, - {'dz', "Bhutani"}, - {'el', "Greek"}, - {'en', "English"}, - {'eo', "Esperanto"}, - {'es', "Espanol"}, - {'et', "Estonian"}, - {'eu', "Basque"}, - {'fa', "Persian"}, - {'fi', "Finnish"}, - {'fj', "Fiji"}, - {'fo', "Faroese"}, - {'fr', "Francais"}, - {'fy', "Frisian"}, - {'ga', "Irish"}, - {'gd', "Scots Gaelic"}, - {'gl', "Galician"}, - {'gn', "Guarani"}, - {'gu', "Gujarati"}, - {'ha', "Hausa"}, - {'he', "Hebrew"}, - {'hi', "Hindi"}, - {'hr', "Hrvatski"}, - {'hu', "Hungarian"}, - {'hy', "Armenian"}, - {'ia', "Interlingua"}, - {'id', "Indonesian"}, - {'ie', "Interlingue"}, - {'ik', "Inupiak"}, - {'in', "Indonesian"}, - {'is', "Islenska"}, - {'it', "Italiano"}, - {'iu', "Inuktitut"}, - {'iw', "Hebrew"}, - {'ja', "Japanese"}, - {'ji', "Yiddish"}, - {'jw', "Javanese"}, - {'ka', "Georgian"}, - {'kk', "Kazakh"}, - {'kl', "Greenlandic"}, - {'km', "Cambodian"}, - {'kn', "Kannada"}, - {'ko', "Korean"}, - {'ks', "Kashmiri"}, - {'ku', "Kurdish"}, - {'ky', "Kirghiz"}, - {'la', "Latin"}, - {'ln', "Lingala"}, - {'lo', "Laothian"}, - {'lt', "Lithuanian"}, - {'lv', "Latvian, Lettish"}, - {'mg', "Malagasy"}, - {'mi', "Maori"}, - {'mk', "Macedonian"}, - {'ml', "Malayalam"}, - {'mn', "Mongolian"}, - {'mo', "Moldavian"}, - {'mr', "Marathi"}, - {'ms', "Malay"}, - {'mt', "Maltese"}, - {'my', "Burmese"}, - {'na', "Nauru"}, - {'ne', "Nepali"}, - {'nl', "Nederlands"}, - {'no', "Norsk"}, - {'oc', "Occitan"}, - {'om', "(Afan) Oromo"}, - {'or', "Oriya"}, - {'pa', "Punjabi"}, - {'pl', "Polish"}, - {'ps', "Pashto, Pushto"}, - {'pt', "Portugues"}, - {'qu', "Quechua"}, - {'rm', "Rhaeto-Romance"}, - {'rn', "Kirundi"}, - {'ro', "Romanian"}, - {'ru', "Russian"}, - {'rw', "Kinyarwanda"}, - {'sa', "Sanskrit"}, - {'sd', "Sindhi"}, - {'sg', "Sangho"}, - {'sh', "Serbo-Croatian"}, - {'si', "Sinhalese"}, - {'sk', "Slovak"}, - {'sl', "Slovenian"}, - {'sm', "Samoan"}, - {'sn', "Shona"}, - {'so', "Somali"}, - {'sq', "Albanian"}, - {'sr', "Serbian"}, - {'ss', "Siswati"}, - {'st', "Sesotho"}, - {'su', "Sundanese"}, - {'sv', "Svenska"}, - {'sw', "Swahili"}, - {'ta', "Tamil"}, - {'te', "Telugu"}, - {'tg', "Tajik"}, - {'th', "Thai"}, - {'ti', "Tigrinya"}, - {'tk', "Turkmen"}, - {'tl', "Tagalog"}, - {'tn', "Setswana"}, - {'to', "Tonga"}, - {'tr', "Turkish"}, - {'ts', "Tsonga"}, - {'tt', "Tatar"}, - {'tw', "Twi"}, - {'ug', "Uighur"}, - {'uk', "Ukrainian"}, - {'ur', "Urdu"}, - {'uz', "Uzbek"}, - {'vi', "Vietnamese"}, - {'vo', "Volapuk"}, - {'wo', "Wolof"}, - {'xh', "Xhosa"}, - {'yi', "Yiddish"}, // formerly ji - {'yo', "Yoruba"}, - {'za', "Zhuang"}, - {'zh', "Chinese"}, - {'zu', "Zulu"}, -}; - -int find_lang(unsigned short id) -{ - int lo = 0, hi = _countof(lang_tbl) - 1; - - while (lo < hi) { - int mid = (lo + hi) >> 1; - - if (id < lang_tbl[mid].id) { - hi = mid; - } else if (id > lang_tbl[mid].id) { - lo = mid + 1; - } else { - return mid; - } - } - - return (id == lang_tbl[lo].id ? lo : 0); -} - -CString FindLangFromId(WORD id) -{ - return CString(lang_tbl[find_lang(id)].lang_long); -} - -// -// CVobSubFile -// - -CVobSubFile::CVobSubFile(CCritSec* pLock) - : CSubPicProviderImpl(pLock) - , m_sub(1024 * 1024) - , m_nLang(0) -{ -} - -CVobSubFile::~CVobSubFile() -{ -} - -// - -bool CVobSubFile::Copy(CVobSubFile& vsf) -{ - Close(); - - *(CVobSubSettings*)this = *(CVobSubSettings*)&vsf; - m_title = vsf.m_title; - m_nLang = vsf.m_nLang; - - m_sub.SetLength(vsf.m_sub.GetLength()); - m_sub.SeekToBegin(); - - for (size_t i = 0; i < m_langs.size(); i++) { - SubLang& src = vsf.m_langs[i]; - SubLang& dst = m_langs[i]; - - dst.id = src.id; - dst.name = src.name; - dst.alt = src.alt; - - for (size_t j = 0; j < src.subpos.GetCount(); j++) { - SubPos& sp = src.subpos[j]; - if (!sp.bValid) { - continue; - } - - if (sp.filepos != (__int64)vsf.m_sub.Seek(sp.filepos, CFile::begin)) { - continue; - } - - sp.filepos = m_sub.GetPosition(); - - BYTE buff[2048]; - UINT uRead = vsf.m_sub.Read(buff, 2048); - m_sub.Write(buff, uRead); - - WORD packetsize = (buff[buff[0x16] + 0x18] << 8) | buff[buff[0x16] + 0x19]; - - for (int k = 0, size, sizeleft = packetsize - 4; - k < packetsize - 4; - k += size, sizeleft -= size) { - int hsize = buff[0x16] + 0x18 + ((buff[0x15] & 0x80) ? 4 : 0); - size = std::min(sizeleft, 2048 - hsize); - - if (size != sizeleft) { - while ((uRead = vsf.m_sub.Read(buff, 2048)) > 0) { - if (!(buff[0x15] & 0x80) && buff[buff[0x16] + 0x17] == (i | 0x20)) { - break; - } - } - - m_sub.Write(buff, uRead); - } - } - - dst.subpos.Add(sp); - } - } - - m_sub.SetLength(m_sub.GetPosition()); - - return true; -} - -// - -void CVobSubFile::TrimExtension(CString& fn) -{ - int i = fn.ReverseFind('.'); - if (i > 0) { - CString ext = fn.Mid(i).MakeLower(); - if (ext == _T(".ifo") || ext == _T(".idx") || ext == _T(".sub") - || ext == _T(".sst") || ext == _T(".son") || ext == _T(".rar")) { - fn = fn.Left(i); - } - } -} - -bool CVobSubFile::Open(CString fn) -{ - m_path = fn; - TrimExtension(fn); - - do { - Close(); - - int ver; - if (!ReadIdx(fn + _T(".idx"), ver)) { - break; - } - - if (ver < 6 && !ReadIfo(fn + _T(".ifo"))) { - break; - } - - if (!ReadSub(fn + _T(".sub")) && !ReadRar(fn + _T(".rar"))) { - break; - } - - m_title = fn; - - for (size_t i = 0; i < m_langs.size(); i++) { - CAtlArray& sp = m_langs[i].subpos; - - for (size_t j = 0; j < sp.GetCount(); j++) { - sp[j].stop = sp[j].start; - sp[j].bForced = false; - - size_t packetSize = 0, dataSize = 0; - BYTE* buff = GetPacket(j, packetSize, dataSize, i); - if (!buff) { - sp[j].bValid = false; - continue; - } - - m_img.delay = j + 1 < sp.GetCount() ? sp[j + 1].start - sp[j].start : 3000; - m_img.GetPacketInfo(buff, packetSize, dataSize); - if (j + 1 < sp.GetCount()) { - m_img.delay = std::min(m_img.delay, sp[j + 1].start - sp[j].start); - } - - sp[j].stop = sp[j].start + m_img.delay; - sp[j].bForced = m_img.bForced; - sp[j].bAnimated = m_img.bAnimated; - - if (j > 0 && sp[j - 1].stop > sp[j].start) { - sp[j - 1].stop = sp[j].start; - } - - delete [] buff; - } - } - - return true; - } while (false); - - Close(); - - return false; -} - -bool CVobSubFile::Save(CString fn, int delay, SubFormat sf) -{ - TrimExtension(fn); - - CVobSubFile vsf(nullptr); - if (!vsf.Copy(*this)) { - return false; - } - - switch (sf) { - case VobSub: - return vsf.SaveVobSub(fn, delay); - case WinSubMux: - return vsf.SaveWinSubMux(fn, delay); - case Scenarist: - return vsf.SaveScenarist(fn, delay); - case Maestro: - return vsf.SaveMaestro(fn, delay); - default: - break; - } - - return false; -} - -void CVobSubFile::Close() -{ - InitSettings(); - m_title.Empty(); - m_sub.SetLength(0); - m_img.Invalidate(); - m_nLang = SIZE_T_ERROR; - for (auto& sl : m_langs) { - sl.id = 0; - sl.name.Empty(); - sl.alt.Empty(); - sl.subpos.RemoveAll(); - } -} - -// - -bool CVobSubFile::ReadIdx(CString fn, int& ver) -{ - CWebTextFile f; - if (!f.Open(fn)) { - return false; - } - - bool bError = false; - - int id = -1, delay = 0, vobid = -1, cellid = -1; - __int64 celltimestamp = 0; - - CString str; - for (ptrdiff_t line = 0; !bError && f.ReadString(str); line++) { - str.Trim(); - - if (line == 0) { - TCHAR buff[] = _T("VobSub index file, v"); - - const TCHAR* s = str; - - int i = str.Find(buff); - if (i < 0 || _stscanf_s(&s[i + _tcslen(buff)], _T("%d"), &ver) != 1 - || ver > VOBSUBIDXVER) { - TRACE(_T("[CVobSubFile::ReadIdx] Wrong file version!\n")); - bError = true; - continue; - } - } else if (!str.GetLength()) { - continue; - } else if (str[0] == _T('#')) { - TCHAR buff[] = _T("Vob/Cell ID:"); - - const TCHAR* s = str; - - int i = str.Find(buff); - if (i >= 0) { - _stscanf_s(&s[i + _tcslen(buff)], _T("%d, %d (PTS: %I64d)"), &vobid, &cellid, &celltimestamp); - } - - continue; - } - - int i = str.Find(':'); - if (i <= 0) { - continue; - } - - CString entry = str.Left(i).MakeLower(); - - str = str.Mid(i + 1); - str.Trim(); - if (str.IsEmpty()) { - continue; - } - - if (entry == _T("size")) { - int x, y; - if (_stscanf_s(str, _T("%dx%d"), &x, &y) != 2) { - bError = true; - } - m_size.cx = x; - m_size.cy = y; - } else if (entry == _T("org")) { - if (_stscanf_s(str, _T("%d,%d"), &m_x, &m_y) != 2) { - bError = true; - } else { - m_org = CPoint(m_x, m_y); - } - } else if (entry == _T("scale")) { - if (ver < 5) { - int scale = 100; - if (_stscanf_s(str, _T("%d%%"), &scale) != 1) { - bError = true; - } - m_scale_x = m_scale_y = scale; - } else { - if (_stscanf_s(str, _T("%d%%,%d%%"), &m_scale_x, &m_scale_y) != 2) { - bError = true; - } - } - } else if (entry == _T("alpha")) { - if (_stscanf_s(str, _T("%d"), &m_alpha) != 1) { - bError = true; - } - } else if (entry == _T("smooth")) { - str.MakeLower(); - - if (str.Find(_T("old")) >= 0 || str.Find(_T("2")) >= 0) { - m_iSmooth = 2; - } else if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { - m_iSmooth = 1; - } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { - m_iSmooth = 0; - } else { - bError = true; - } - } else if (entry == _T("fadein/out")) { - if (_stscanf_s(str, _T("%d,%d"), &m_fadein, &m_fadeout) != 2) { - bError = true; - } - } else if (entry == _T("align")) { - str.MakeLower(); - - int k = 0; - CString token; - for (int j = 0; j < 3; j++) { - token = str.Tokenize(_T(" "), k); - if (token.IsEmpty()) { - break; - } - - if (j == 0) { - if (token == _T("on") || token == _T("1")) { - m_bAlign = true; - } else if (token == _T("off") || token == _T("0")) { - m_bAlign = false; - } else { - bError = true; - break; - } - } else if (j == 1) { - if (token == _T("at")) { - j--; - continue; - } - - if (token == _T("left")) { - m_alignhor = 0; - } else if (token == _T("center")) { - m_alignhor = 1; - } else if (token == _T("right")) { - m_alignhor = 2; - } else { - bError = true; - break; - } - } else if (j == 2) { - if (token == _T("top")) { - m_alignver = 0; - } else if (token == _T("center")) { - m_alignver = 1; - } else if (token == _T("bottom")) { - m_alignver = 2; - } else { - bError = true; - break; - } - } - } - } else if (entry == _T("time offset")) { - bool bNegative = false; - if (str[0] == '-') { - bNegative = true; - } - str.TrimLeft(_T("+-")); - - TCHAR c; - int hh, mm, ss, ms; - int n = _stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms); - - switch (n) { - case 1: // We have read only one integer, interpret it as an offset expressed in milliseconds - m_toff = hh * (bNegative ? -1 : 1); - break; - case 7: // We have read 4 integers + 3 separators, interpret them as hh:mm:ss.ms - m_toff = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1); - break; - default: - bError = true; - m_toff = 0; - break; - } - } else if (entry == _T("forced subs")) { - str.MakeLower(); - - if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { - m_bOnlyShowForcedSubs = true; - } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { - m_bOnlyShowForcedSubs = false; - } else { - bError = true; - } - } else if (entry == _T("langidx")) { - int iLang = -1; - if (_stscanf_s(str, _T("%d"), &iLang) != 1) { - bError = true; - } - m_nLang = (iLang < 0 && size_t(iLang) >= m_langs.size()) ? SIZE_T_ERROR : size_t(iLang); - } else if (entry == _T("palette")) { - // The assert guarantees that the shortcut we use will work as expected - static_assert(sizeof(RGBQUAD) == 4, "Packing error"); -#pragma warning(push) -#pragma warning(disable: 4477) - if (_stscanf_s(str, _T("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"), - &m_orgpal[0], &m_orgpal[1], &m_orgpal[2], &m_orgpal[3], - &m_orgpal[4], &m_orgpal[5], &m_orgpal[6], &m_orgpal[7], - &m_orgpal[8], &m_orgpal[9], &m_orgpal[10], &m_orgpal[11], - &m_orgpal[12], &m_orgpal[13], &m_orgpal[14], &m_orgpal[15] - ) != 16) { -#pragma warning(pop) - bError = true; - } - } else if (entry == _T("custom colors")) { - str.MakeLower(); - - if (str.Find(_T("on")) == 0 || str.Find(_T("1")) == 0) { - m_bCustomPal = true; - } else if (str.Find(_T("off")) == 0 || str.Find(_T("0")) == 0) { - m_bCustomPal = false; - } else { - bError = true; - } - - i = str.Find(_T("tridx:")); - if (i < 0) { - bError = true; - continue; - } - str = str.Mid(i + (int)_tcslen(_T("tridx:"))); - - int tridx; - if (_stscanf_s(str, _T("%x"), &tridx) != 1) { - bError = true; - continue; - } - tridx = ((tridx & 0x1000) >> 12) | ((tridx & 0x100) >> 7) | ((tridx & 0x10) >> 2) | ((tridx & 1) << 3); - - i = str.Find(_T("colors:")); - if (i < 0) { - bError = true; - continue; - } - str = str.Mid(i + (int)_tcslen(_T("colors:"))); - - RGBQUAD pal[4]; -#pragma warning(push) -#pragma warning(disable: 4477) - if (_stscanf_s(str, _T("%x,%x,%x,%x"), &pal[0], &pal[1], &pal[2], &pal[3]) != 4) { -#pragma warning(pop) - bError = true; - continue; - } - - SetCustomPal(pal, tridx); - } else if (entry == _T("id")) { - str.MakeLower(); - - WORD langid = ((str[0] & 0xff) << 8) | (str[1] & 0xff); - - i = str.Find(_T("index:")); - if (i < 0) { - bError = true; - continue; - } - str = str.Mid(i + (int)_tcslen(_T("index:"))); - - if (_stscanf_s(str, _T("%d"), &id) != 1 || id < 0 || size_t(id) >= m_langs.size()) { - bError = true; - continue; - } - if (m_nLang == SIZE_T_ERROR) { - m_nLang = size_t(id); - } - - m_langs[id].id = langid; - m_langs[id].name = lang_tbl[find_lang(langid)].lang_long; - m_langs[id].alt = lang_tbl[find_lang(langid)].lang_long; - - delay = 0; - } else if (id >= 0 && entry == _T("alt")) { - m_langs[id].alt = str; - } else if (id >= 0 && entry == _T("delay")) { - bool bNegative = false; - if (str[0] == '-') { - bNegative = true; - } - str.TrimLeft(_T("+-")); - - TCHAR c; - int hh, mm, ss, ms; - if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { - bError = true; - continue; - } - - delay += (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1); - } else if (id >= 0 && entry == _T("timestamp")) { - SubPos sb; - - sb.vobid = (char)vobid; - sb.cellid = (char)cellid; - sb.celltimestamp = celltimestamp; - sb.bValid = true; - - bool bNegative = false; - if (str[0] == '-') { - bNegative = true; - } - str.TrimLeft(_T("+-")); - - TCHAR c; - int hh, mm, ss, ms; - if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { - bError = true; - continue; - } - - sb.start = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1) + delay; - - i = str.Find(_T("filepos:")); - if (i < 0) { - bError = true; - continue; - } - str = str.Mid(i + (int)_tcslen(_T("filepos:"))); - - if (_stscanf_s(str, _T("%I64x"), &sb.filepos) != 1) { - bError = true; - continue; - } - - if (delay < 0 && !m_langs[id].subpos.IsEmpty()) { - __int64 ts = m_langs[id].subpos[m_langs[id].subpos.GetCount() - 1].start; - - if (sb.start < ts) { - delay += (int)(ts - sb.start); - sb.start = ts; - } - } - - m_langs[id].subpos.Add(sb); - } else { - bError = true; - } - } - - return !bError; -} - -bool CVobSubFile::ReadSub(CString fn) -{ - CFile f; - if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - - int len; - BYTE buff[2048]; - try { - m_sub.SetLength(f.GetLength()); - m_sub.SeekToBegin(); - while ((len = f.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { - m_sub.Write(buff, len); - } - } - catch (CFileException*) { - return false; - } - - return true; -} - -static unsigned char* RARbuff = nullptr; -static unsigned int RARpos = 0; - -static int CALLBACK MyCallbackProc(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2) -{ - if (msg == UCM_PROCESSDATA) { - ASSERT(RARbuff); - - memcpy(&RARbuff[RARpos], (char*)P1, (size_t)P2); - RARpos += (unsigned int)P2; - } - - return 1; -} - -bool CVobSubFile::ReadRar(CString fn) -{ -#if !USE_STATIC_UNRAR -#ifdef _WIN64 - HMODULE h = LoadLibrary(_T("unrar64.dll")); -#else - HMODULE h = LoadLibrary(_T("unrar.dll")); -#endif - if (!h) { - return false; - } - - RAROpenArchiveEx OpenArchiveEx = (RAROpenArchiveEx)GetProcAddress(h, "RAROpenArchiveEx"); - RARCloseArchive CloseArchive = (RARCloseArchive)GetProcAddress(h, "RARCloseArchive"); - RARReadHeaderEx ReadHeaderEx = (RARReadHeaderEx)GetProcAddress(h, "RARReadHeaderEx"); - RARProcessFile ProcessFile = (RARProcessFile)GetProcAddress(h, "RARProcessFile"); - RARSetCallback SetCallback = (RARSetCallback)GetProcAddress(h, "RARSetCallback"); - - if (!(OpenArchiveEx && CloseArchive && ReadHeaderEx && ProcessFile && SetCallback)) { - FreeLibrary(h); - return false; - } - -#else - -#define OpenArchiveEx RAROpenArchiveEx -#define CloseArchive RARCloseArchive -#define ReadHeaderEx RARReadHeaderEx -#define ProcessFile RARProcessFile -#define SetCallback RARSetCallback -#endif /* USE_STATIC_UNRAR */ - - RAROpenArchiveDataEx OpenArchiveData; - ZeroMemory(&OpenArchiveData, sizeof(OpenArchiveData)); - - OpenArchiveData.ArcNameW = (LPTSTR)(LPCTSTR)fn; - char fnA[MAX_PATH]; - size_t size; - if (wcstombs_s(&size, fnA, fn, fn.GetLength())) { - fnA[0] = 0; - } - OpenArchiveData.ArcName = fnA; - OpenArchiveData.OpenMode = RAR_OM_EXTRACT; - OpenArchiveData.CmtBuf = 0; - OpenArchiveData.Callback = MyCallbackProc; - HANDLE hArcData = OpenArchiveEx(&OpenArchiveData); - if (!hArcData) { -#if !USE_STATIC_UNRAR - FreeLibrary(h); -#endif - return false; - } - - RARHeaderDataEx HeaderDataEx; - HeaderDataEx.CmtBuf = nullptr; - - while (ReadHeaderEx(hArcData, &HeaderDataEx) == 0) { - CString subfn(HeaderDataEx.FileNameW); - - if (!subfn.Right(4).CompareNoCase(_T(".sub"))) { - CAutoVectorPtr buff; - if (!buff.Allocate(HeaderDataEx.UnpSize)) { - CloseArchive(hArcData); -#if !USE_STATIC_UNRAR - FreeLibrary(h); -#endif - return false; - } - - RARbuff = buff; - RARpos = 0; - - if (ProcessFile(hArcData, RAR_TEST, nullptr, nullptr)) { - CloseArchive(hArcData); -#if !USE_STATIC_UNRAR - FreeLibrary(h); -#endif - - return false; - } - - m_sub.SetLength(HeaderDataEx.UnpSize); - m_sub.SeekToBegin(); - m_sub.Write(buff, HeaderDataEx.UnpSize); - m_sub.SeekToBegin(); - - RARbuff = nullptr; - RARpos = 0; - - break; - } - - ProcessFile(hArcData, RAR_SKIP, nullptr, nullptr); - } - - CloseArchive(hArcData); -#if !USE_STATIC_UNRAR - FreeLibrary(h); -#endif - - return true; -} - -bool CVobSubFile::ReadIfo(CString fn) -{ - CFile f; - if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - - /* PGC1 */ - - f.Seek(0xc0 + 0x0c, SEEK_SET); - - DWORD pos; - ReadBEdw(pos); - - f.Seek(pos * 0x800 + 0x0c, CFile::begin); - - DWORD offset; - ReadBEdw(offset); - - /* Subpic palette */ - - f.Seek(pos * 0x800 + offset + 0xa4, CFile::begin); - - for (size_t i = 0; i < 16; i++) { - BYTE y, u, v, tmp; - - f.Read(&tmp, 1); - f.Read(&y, 1); - f.Read(&u, 1); - f.Read(&v, 1); - - y = (y - 16) * 255 / 219; - - m_orgpal[i].rgbRed = std::min(std::max(BYTE(1.0 * y + 1.4022 * (u - 128)), 0u), 255u); - m_orgpal[i].rgbGreen = std::min(std::max(BYTE(1.0 * y - 0.3456 * (u - 128) - 0.7145 * (v - 128)), 0u), 255u); - m_orgpal[i].rgbBlue = std::min(std::max(BYTE(1.0 * y + 1.7710 * (v - 128)), 0u), 255u); - } - - return true; -} - -bool CVobSubFile::WriteIdx(CString fn, int delay) -{ - CTextFile f; - if (!f.Save(fn, CTextFile::DEFAULT_ENCODING)) { - return false; - } - - CString str; - str.Format(_T("# VobSub index file, v%d (do not modify this line!)\n"), VOBSUBIDXVER); - - f.WriteString(str); - f.WriteString(_T("# \n")); - f.WriteString(_T("# To repair desyncronization, you can insert gaps this way:\n")); - f.WriteString(_T("# (it usually happens after vob id changes)\n")); - f.WriteString(_T("# \n")); - f.WriteString(_T("#\t delay: [sign]hh:mm:ss:ms\n")); - f.WriteString(_T("# \n")); - f.WriteString(_T("# Where:\n")); - f.WriteString(_T("#\t [sign]: +, - (optional)\n")); - f.WriteString(_T("#\t hh: hours (0 <= hh)\n")); - f.WriteString(_T("#\t mm/ss: minutes/seconds (0 <= mm/ss <= 59)\n")); - f.WriteString(_T("#\t ms: milliseconds (0 <= ms <= 999)\n")); - f.WriteString(_T("# \n")); - f.WriteString(_T("#\t Note: You can't position a sub before the previous with a negative value.\n")); - f.WriteString(_T("# \n")); - f.WriteString(_T("# You can also modify timestamps or delete a few subs you don't like.\n")); - f.WriteString(_T("# Just make sure they stay in increasing order.\n")); - f.WriteString(_T("\n")); - f.WriteString(_T("\n")); - - // Settings - - f.WriteString(_T("# Settings\n\n")); - - f.WriteString(_T("# Original frame size\n")); - str.Format(_T("size: %ldx%ld\n\n"), m_size.cx, m_size.cy); - f.WriteString(str); - - f.WriteString(_T("# Origin, relative to the upper-left corner, can be overloaded by aligment\n")); - str.Format(_T("org: %d, %d\n\n"), m_x, m_y); - f.WriteString(str); - - f.WriteString(_T("# Image scaling (hor,ver), origin is at the upper-left corner or at the alignment coord (x, y)\n")); - str.Format(_T("scale: %d%%, %d%%\n\n"), m_scale_x, m_scale_y); - f.WriteString(str); - - f.WriteString(_T("# Alpha blending\n")); - str.Format(_T("alpha: %d%%\n\n"), m_alpha); - f.WriteString(str); - - f.WriteString(_T("# Smoothing for very blocky images (use OLD for no filtering)\n")); - str.Format(_T("smooth: %s\n\n"), m_iSmooth == 0 ? _T("OFF") : m_iSmooth == 1 ? _T("ON") : _T("OLD")); - f.WriteString(str); - - f.WriteString(_T("# In millisecs\n")); - str.Format(_T("fadein/out: %d, %d\n\n"), m_fadein, m_fadeout); - f.WriteString(str); - - f.WriteString(_T("# Force subtitle placement relative to (org.x, org.y)\n")); - str.Format(_T("align: %s %s %s\n\n"), - m_bAlign ? _T("ON at") : _T("OFF at"), - m_alignhor == 0 ? _T("LEFT") : m_alignhor == 1 ? _T("CENTER") : m_alignhor == 2 ? _T("RIGHT") : _T(""), - m_alignver == 0 ? _T("TOP") : m_alignver == 1 ? _T("CENTER") : m_alignver == 2 ? _T("BOTTOM") : _T("")); - f.WriteString(str); - - f.WriteString(_T("# For correcting non-progressive desync. (in millisecs or hh:mm:ss:ms)\n")); - f.WriteString(_T("# Note: Not effective in VSFilter, use \"delay: ... \" instead.\n")); - str.Format(_T("time offset: %u\n\n"), m_toff); - f.WriteString(str); - - f.WriteString(_T("# ON: displays only forced subtitles, OFF: shows everything\n")); - str.Format(_T("forced subs: %s\n\n"), m_bOnlyShowForcedSubs ? _T("ON") : _T("OFF")); - f.WriteString(str); - - f.WriteString(_T("# The original palette of the DVD\n")); - str.Format(_T("palette: %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n\n"), - *((unsigned int*)&m_orgpal[0]) & 0xffffff, - *((unsigned int*)&m_orgpal[1]) & 0xffffff, - *((unsigned int*)&m_orgpal[2]) & 0xffffff, - *((unsigned int*)&m_orgpal[3]) & 0xffffff, - *((unsigned int*)&m_orgpal[4]) & 0xffffff, - *((unsigned int*)&m_orgpal[5]) & 0xffffff, - *((unsigned int*)&m_orgpal[6]) & 0xffffff, - *((unsigned int*)&m_orgpal[7]) & 0xffffff, - *((unsigned int*)&m_orgpal[8]) & 0xffffff, - *((unsigned int*)&m_orgpal[9]) & 0xffffff, - *((unsigned int*)&m_orgpal[10]) & 0xffffff, - *((unsigned int*)&m_orgpal[11]) & 0xffffff, - *((unsigned int*)&m_orgpal[12]) & 0xffffff, - *((unsigned int*)&m_orgpal[13]) & 0xffffff, - *((unsigned int*)&m_orgpal[14]) & 0xffffff, - *((unsigned int*)&m_orgpal[15]) & 0xffffff); - f.WriteString(str); - - int tridx = (!!(m_tridx & 1)) * 0x1000 + (!!(m_tridx & 2)) * 0x100 + (!!(m_tridx & 4)) * 0x10 + (!!(m_tridx & 8)); - - f.WriteString(_T("# Custom colors (transp idxs and the four colors)\n")); - str.Format(_T("custom colors: %s, tridx: %04x, colors: %06x, %06x, %06x, %06x\n\n"), - m_bCustomPal ? _T("ON") : _T("OFF"), - tridx, - *((unsigned int*)&m_cuspal[0]) & 0xffffff, - *((unsigned int*)&m_cuspal[1]) & 0xffffff, - *((unsigned int*)&m_cuspal[2]) & 0xffffff, - *((unsigned int*)&m_cuspal[3]) & 0xffffff); - f.WriteString(str); - - f.WriteString(_T("# Language index in use\n")); - str.Format(_T("langidx: %Iu\n\n"), m_nLang); - f.WriteString(str); - - if (delay) { - str.Format(_T("delay: %s%02d:%02d:%02d:%03d\n\n"), - delay < 0 ? _T("-") : _T(""), - abs(delay / 1000 / 60 / 60) % 60, - abs(delay / 1000 / 60) % 60, - abs(delay / 1000) % 60, - abs(delay % 1000)); - f.WriteString(str); - } - - // Subs - - for (size_t i = 0; i < m_langs.size(); i++) { - SubLang& sl = m_langs[i]; - - CAtlArray& sp = sl.subpos; - if (sp.IsEmpty() && !sl.id) { - continue; - } - - str.Format(_T("# %s\n"), sl.name.GetString()); - f.WriteString(str); - - ASSERT(sl.id); - if (!sl.id) { - sl.id = '--'; - } - str.Format(_T("id: %c%c, index: %Iu\n"), sl.id >> 8, sl.id & 0xff, i); - f.WriteString(str); - - str = _T("# Uncomment next line to activate alternative name in VSFilter / Windows Media Player 6.x\n"); - f.WriteString(str); - str.Format(_T("alt: %s\n"), sl.alt.GetString()); - if (sl.name == sl.alt) { - str = _T("# ") + str; - } - f.WriteString(str); - - char vobid = -1, cellid = -1; - - for (size_t j = 0; j < sp.GetCount(); j++) { - if (!sp[j].bValid) { - continue; - } - - if (sp[j].vobid != vobid || sp[j].cellid != cellid) { - str.Format(_T("# Vob/Cell ID: %d, %d (PTS: %I64d)\n"), sp[j].vobid, sp[j].cellid, sp[j].celltimestamp); - f.WriteString(str); - vobid = sp[j].vobid; - cellid = sp[j].cellid; - } - - str.Format(_T("timestamp: %s%02d:%02d:%02d:%03d, filepos: %09I64x\n"), - sp[j].start < 0 ? _T("-") : _T(""), - abs(int((sp[j].start / 1000 / 60 / 60) % 60)), - abs(int((sp[j].start / 1000 / 60) % 60)), - abs(int((sp[j].start / 1000) % 60)), - abs(int((sp[j].start) % 1000)), - sp[j].filepos); - f.WriteString(str); - } - - f.WriteString(_T("\n")); - } - - return true; -} - -bool CVobSubFile::WriteSub(CString fn) -{ - CFile f; - if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { - return false; - } - - if (m_sub.GetLength() == 0) { - return true; // nothing to do... - } - - m_sub.SeekToBegin(); - - int len; - BYTE buff[2048]; - while ((len = m_sub.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { - f.Write(buff, len); - } - - return true; -} - -// - -BYTE* CVobSubFile::GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang /*= SIZE_T_ERROR*/) -{ - BYTE* ret = nullptr; - - if (nLang >= m_langs.size()) { - nLang = m_nLang; - } - CAtlArray& sp = m_langs[nLang].subpos; - - do { - if (idx >= sp.GetCount()) { - break; - } - - if ((__int64)m_sub.Seek(sp[idx].filepos, CFile::begin) != sp[idx].filepos) { - break; - } - - BYTE buff[0x800]; - if (sizeof(buff) != m_sub.Read(buff, sizeof(buff))) { - break; - } - - ASSERT(nLang < BYTE_MAX); - - // let's check a few things to make sure... - if (*(DWORD*)&buff[0x00] != 0xba010000 - || *(DWORD*)&buff[0x0e] != 0xbd010000 - || !(buff[0x15] & 0x80) - || (buff[0x17] & 0xf0) != 0x20 - || (buff[buff[0x16] + 0x17] & 0xe0) != 0x20 - || (buff[buff[0x16] + 0x17] & 0x1f) != (BYTE)nLang) { - break; - } - - packetSize = (buff[buff[0x16] + 0x18] << 8) + buff[buff[0x16] + 0x19]; - dataSize = (buff[buff[0x16] + 0x1a] << 8) + buff[buff[0x16] + 0x1b]; - - try { - ret = DEBUG_NEW BYTE[packetSize]; - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - break; - } - - size_t i = 0, sizeLeft = packetSize; - for (size_t size; i < packetSize; i += size, sizeLeft -= size) { - size_t hsize = 0x18 + buff[0x16]; - size = std::min(sizeLeft, 0x800 - hsize); - memcpy(&ret[i], &buff[hsize], size); - - if (size != sizeLeft) { - while (m_sub.Read(buff, sizeof(buff))) { - if (/*!(buff[0x15] & 0x80) &&*/ buff[buff[0x16] + 0x17] == (nLang | 0x20)) { - break; - } - } - } - } - - if (i != packetSize || sizeLeft > 0) { - delete [] ret; - ret = nullptr; - } - } while (false); - - return ret; -} - -const CVobSubFile::SubPos* CVobSubFile::GetFrameInfo(size_t idx, size_t nLang /*= SIZE_T_ERROR*/) const -{ - if (nLang >= m_langs.size()) { - nLang = m_nLang; - } - const CAtlArray& sp = m_langs[nLang].subpos; - - if (idx >= sp.GetCount() - || !sp[idx].bValid - || (m_bOnlyShowForcedSubs && !sp[idx].bForced)) { - return nullptr; - } - - return &sp[idx]; -} - -bool CVobSubFile::GetFrame(size_t idx, size_t nLang /*= SIZE_T_ERROR*/, REFERENCE_TIME rt /*= -1*/) -{ - if (nLang >= m_langs.size()) { - nLang = m_nLang; - } - CAtlArray& sp = m_langs[nLang].subpos; - - if (idx >= sp.GetCount()) { - return false; - } - - if (m_img.nLang != nLang || m_img.nIdx != idx - || (sp[idx].bAnimated && sp[idx].start + m_img.tCurrent <= rt)) { - size_t packetSize = 0, dataSize = 0; - CAutoVectorPtr buff; - buff.Attach(GetPacket(idx, packetSize, dataSize, nLang)); - if (!buff || packetSize == 0 || dataSize == 0) { - return false; - } - - m_img.start = sp[idx].start; - - bool ret = m_img.Decode(buff, packetSize, dataSize, rt >= 0 ? int(rt - sp[idx].start) : INT_MAX, - m_bCustomPal, m_tridx, m_orgpal, m_cuspal, true); - - m_img.delay = sp[idx].stop - sp[idx].start; - - if (!ret) { - return false; - } - - m_img.nIdx = idx; - m_img.nLang = nLang; - } - - return (m_bOnlyShowForcedSubs ? m_img.bForced : true); -} - -bool CVobSubFile::GetFrameByTimeStamp(__int64 time) -{ - return GetFrame(GetFrameIdxByTimeStamp(time)); -} - -size_t CVobSubFile::GetFrameIdxByTimeStamp(__int64 time) -{ - if (m_nLang >= m_langs.size() || m_langs[m_nLang].subpos.IsEmpty()) { - return SIZE_T_ERROR; - } - - CAtlArray& sp = m_langs[m_nLang].subpos; - - size_t i = 0, j = sp.GetCount() - 1, ret = SIZE_T_ERROR; - - if (time >= sp[j].start) { - return j; - } - - while (i < j) { - size_t mid = (i + j) >> 1; - __int64 midstart = sp[mid].start; - - if (time == midstart) { - ret = mid; - break; - } else if (time < midstart) { - ret = SIZE_T_ERROR; - if (j == mid) { - mid--; - } - j = mid; - } else if (time > midstart) { - ret = mid; - if (i == mid) { - mid++; - } - i = mid; - } - } - - return ret; -} - -// - -STDMETHODIMP CVobSubFile::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = nullptr; - - return - QI(IPersist) - QI(ISubStream) - QI(ISubPicProvider) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPicProvider - -STDMETHODIMP_(POSITION) CVobSubFile::GetStartPosition(REFERENCE_TIME rt, double fps) -{ - rt /= 10000; - - size_t i = GetFrameIdxByTimeStamp(rt); - - const SubPos* sp = GetFrameInfo(i); - if (!sp) { - return nullptr; - } - - if (rt >= sp->stop) { - if (!GetFrameInfo(++i)) { - return nullptr; - } - } - - return (POSITION)(i + 1); -} - -CString CVobSubFile::GetPath() { - return m_path; -} - -STDMETHODIMP_(POSITION) CVobSubFile::GetNext(POSITION pos) -{ - size_t i = (size_t)pos; - return (GetFrameInfo(i) ? (POSITION)(i + 1) : nullptr); -} - -STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStart(POSITION pos, double fps) -{ - size_t i = (size_t)pos - 1; - const SubPos* sp = GetFrameInfo(i); - return (sp ? 10000i64 * sp->start : 0); -} - -STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStop(POSITION pos, double fps) -{ - size_t i = (size_t)pos - 1; - const SubPos* sp = GetFrameInfo(i); - return (sp ? 10000i64 * sp->stop : 0); -} - -STDMETHODIMP_(bool) CVobSubFile::IsAnimated(POSITION pos) -{ - size_t i = (size_t)pos - 1; - const SubPos* sp = GetFrameInfo(i); - return (sp ? sp->bAnimated : false); -} - -STDMETHODIMP CVobSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - if (spd.bpp != 32) { - return E_INVALIDARG; - } - - rt /= 10000; - - if (!GetFrame(GetFrameIdxByTimeStamp(rt), SIZE_T_ERROR, rt)) { - return E_FAIL; - } - - if (rt >= (m_img.start + m_img.delay)) { - return E_FAIL; - } - - return __super::Render(spd, bbox); -} - -STDMETHODIMP CVobSubFile::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) -{ - relativeTo = VIDEO; - return S_OK; -} - -// IPersist - -STDMETHODIMP CVobSubFile::GetClassID(CLSID* pClassID) -{ - return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; -} - -// ISubStream - -STDMETHODIMP_(int) CVobSubFile::GetStreamCount() -{ - int iStreamCount = 0; - for (const auto& sl : m_langs) { - if (sl.subpos.GetCount()) { - iStreamCount++; - } - } - return iStreamCount; -} - -DWORD LangIDToLCID(WORD langid) -{ - unsigned short id = lang_tbl[find_lang(langid)].id; - CHAR tmp[3]; - tmp[0] = id / 256; - tmp[1] = id & 0xFF; - tmp[2] = 0; - return ISOLang::ISO6391ToLcid(tmp); -} - -STDMETHODIMP CVobSubFile::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID) -{ - for (const auto& sl : m_langs) { - if (sl.subpos.IsEmpty() || iStream-- > 0) { - continue; - } - - if (ppName) { - *ppName = (WCHAR*)CoTaskMemAlloc((sl.alt.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppName, sl.alt.GetLength() + 1, CStringW(sl.alt)); - } - - if (pLCID) { - *pLCID = LangIDToLCID(sl.id); - } - - return S_OK; - } - - return E_FAIL; -} - -STDMETHODIMP_(int) CVobSubFile::GetStream() -{ - int iStream = 0; - - if (m_nLang < m_langs.size()) { - for (size_t i = 0; i < m_nLang; i++) { - if (!m_langs[i].subpos.IsEmpty()) { - iStream++; - } - } - } - - return iStream; -} - -STDMETHODIMP CVobSubFile::SetStream(int iStream) -{ - for (size_t i = 0; i < m_langs.size(); i++) { - const CAtlArray& sp = m_langs[i].subpos; - - if (sp.IsEmpty() || iStream-- > 0) { - continue; - } - - m_nLang = i; - - m_img.Invalidate(); - - break; - } - - return iStream < 0 ? S_OK : E_FAIL; -} - -STDMETHODIMP CVobSubFile::Reload() -{ - if (!PathUtils::Exists(m_title + _T(".idx"))) { - return E_FAIL; - } - return !m_title.IsEmpty() && Open(m_title) ? S_OK : E_FAIL; -} - -// StretchBlt - -static void PixelAtBiLinear(RGBQUAD& c, int x, int y, CVobSubImage& src) -{ - int w = src.rect.Width(), - h = src.rect.Height(); - - int x1 = (x >> 16), y1 = (y >> 16) * w, - x2 = std::min(x1 + 1, w - 1), y2 = std::min(y1 + w, (h - 1) * w); - - RGBQUAD* ptr = src.lpPixels; - - RGBQUAD c11 = ptr[y1 + x1], c12 = ptr[y1 + x2], - c21 = ptr[y2 + x1], c22 = ptr[y2 + x2]; - - __int64 u2 = x & 0xffff, - v2 = y & 0xffff, - u1 = 0x10000 - u2, - v1 = 0x10000 - v2; - - int v1u1 = int(v1 * u1 >> 16) * c11.rgbReserved, - v1u2 = int(v1 * u2 >> 16) * c12.rgbReserved, - v2u1 = int(v2 * u1 >> 16) * c21.rgbReserved, - v2u2 = int(v2 * u2 >> 16) * c22.rgbReserved; - - c.rgbRed = (c11.rgbRed * v1u1 + c12.rgbRed * v1u2 - + c21.rgbRed * v2u1 + c22.rgbRed * v2u2) >> 24; - c.rgbGreen = (c11.rgbGreen * v1u1 + c12.rgbGreen * v1u2 - + c21.rgbGreen * v2u1 + c22.rgbGreen * v2u2) >> 24; - c.rgbBlue = (c11.rgbBlue * v1u1 + c12.rgbBlue * v1u2 - + c21.rgbBlue * v2u1 + c22.rgbBlue * v2u2) >> 24; - c.rgbReserved = BYTE((v1u1 + v1u2 - + v2u1 + v2u2) >> 16); -} - -static void StretchBlt(SubPicDesc& spd, CRect dstrect, CVobSubImage& src) -{ - if (dstrect.IsRectEmpty()) { - return; - } - - if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { - return; - } - - int sw = src.rect.Width(), - sh = src.rect.Height(), - dw = dstrect.Width(), - dh = dstrect.Height(); - - int srcx = 0, - srcy = 0, - srcdx = (sw << 16) / dw >> 1, - srcdy = (sh << 16) / dh >> 1; - - if (dstrect.left < 0) { - srcx = -dstrect.left * (srcdx << 1); - dstrect.left = 0; - } - if (dstrect.top < 0) { - srcy = -dstrect.top * (srcdy << 1); - dstrect.top = 0; - } - if (dstrect.right > spd.w) { - dstrect.right = spd.w; - } - if (dstrect.bottom > spd.h) { - dstrect.bottom = spd.h; - } - - if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { - return; - } - - dw = dstrect.Width(); - dh = dstrect.Height(); - - for (int y = dstrect.top; y < dstrect.bottom; y++, srcy += (srcdy << 1)) { - RGBQUAD* ptr = (RGBQUAD*) & ((BYTE*)spd.bits)[y * spd.pitch] + dstrect.left; - RGBQUAD* endptr = ptr + dw; - - for (int sx = srcx; ptr < endptr; sx += (srcdx << 1), ptr++) { - // PixelAtBiLinear(*ptr, sx, srcy, src); - //// - RGBQUAD cc[4]; - - PixelAtBiLinear(cc[0], sx, srcy, src); - PixelAtBiLinear(cc[1], sx + srcdx, srcy, src); - PixelAtBiLinear(cc[2], sx, srcy + srcdy, src); - PixelAtBiLinear(cc[3], sx + srcdx, srcy + srcdy, src); - - ptr->rgbRed = (cc[0].rgbRed + cc[1].rgbRed + cc[2].rgbRed + cc[3].rgbRed) >> 2; - ptr->rgbGreen = (cc[0].rgbGreen + cc[1].rgbGreen + cc[2].rgbGreen + cc[3].rgbGreen) >> 2; - ptr->rgbBlue = (cc[0].rgbBlue + cc[1].rgbBlue + cc[2].rgbBlue + cc[3].rgbBlue) >> 2; - ptr->rgbReserved = (cc[0].rgbReserved + cc[1].rgbReserved + cc[2].rgbReserved + cc[3].rgbReserved) >> 2; - //// - ptr->rgbRed = ptr->rgbRed * ptr->rgbReserved >> 8; - ptr->rgbGreen = ptr->rgbGreen * ptr->rgbReserved >> 8; - ptr->rgbBlue = ptr->rgbBlue * ptr->rgbReserved >> 8; - ptr->rgbReserved = ~ptr->rgbReserved; - - } - } -} - -// -// CVobSubSettings -// - -void CVobSubSettings::InitSettings() -{ - m_size.SetSize(720, 480); - m_toff = m_x = m_y = 0; - m_org.SetPoint(0, 0); - m_scale_x = m_scale_y = m_alpha = 100; - m_fadein = m_fadeout = 50; - m_iSmooth = 0; - m_bAlign = false; - m_alignhor = m_alignver = 0; - m_bOnlyShowForcedSubs = false; - m_bCustomPal = false; - m_tridx = 0; - ZeroMemory(m_orgpal, sizeof(m_orgpal)); - ZeroMemory(m_cuspal, sizeof(m_cuspal)); -} - -bool CVobSubSettings::GetCustomPal(RGBQUAD* cuspal, int& tridx) -{ - memcpy(cuspal, m_cuspal, sizeof(RGBQUAD) * 4); - tridx = m_tridx; - return m_bCustomPal; -} - -void CVobSubSettings::SetCustomPal(const RGBQUAD* cuspal, int tridx) -{ - memcpy(m_cuspal, cuspal, sizeof(RGBQUAD) * 4); - m_tridx = tridx & 0xf; - for (int i = 0; i < 4; i++) { - m_cuspal[i].rgbReserved = (tridx & (1 << i)) ? 0 : 0xff; - } - m_img.Invalidate(); -} - -void CVobSubSettings::GetDestrect(CRect& r) -{ - int w = MulDiv(m_img.rect.Width(), m_scale_x, 100); - int h = MulDiv(m_img.rect.Height(), m_scale_y, 100); - - if (!m_bAlign) { - r.left = MulDiv(m_img.rect.left, m_scale_x, 100); - r.right = MulDiv(m_img.rect.right, m_scale_x, 100); - r.top = MulDiv(m_img.rect.top, m_scale_y, 100); - r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); - } else { - switch (m_alignhor) { - case 0: - r.left = 0; - r.right = w; - break; // left - case 1: - r.left = -(w >> 1); - r.right = -(w >> 1) + w; - break; // center - case 2: - r.left = -w; - r.right = 0; - break; // right - default: - r.left = MulDiv(m_img.rect.left, m_scale_x, 100); - r.right = MulDiv(m_img.rect.right, m_scale_x, 100); - break; - } - - switch (m_alignver) { - case 0: - r.top = 0; - r.bottom = h; - break; // top - case 1: - r.top = -(h >> 1); - r.bottom = -(h >> 1) + h; - break; // center - case 2: - r.top = -h; - r.bottom = 0; - break; // bottom - default: - r.top = MulDiv(m_img.rect.top, m_scale_y, 100); - r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); - break; - } - } - - r += m_org; -} - -void CVobSubSettings::GetDestrect(CRect& r, int w, int h) -{ - GetDestrect(r); - - r.left = MulDiv(r.left, w, m_size.cx); - r.right = MulDiv(r.right, w, m_size.cx); - r.top = MulDiv(r.top, h, m_size.cy); - r.bottom = MulDiv(r.bottom, h, m_size.cy); -} - -void CVobSubSettings::SetAlignment(bool bAlign, int x, int y, int hor /*= 1*/, int ver /*= 1*/) -{ - m_bAlign = bAlign; - if (bAlign) { - m_org.x = MulDiv(m_size.cx, x, 100); - m_org.y = MulDiv(m_size.cy, y, 100); - m_alignhor = std::min(std::max(hor, 0), 2); - m_alignver = std::min(std::max(ver, 0), 2); - } else { - m_org.x = m_x; - m_org.y = m_y; - } -} - -HRESULT CVobSubSettings::Render(SubPicDesc& spd, RECT& bbox) -{ - CRect r; - GetDestrect(r, spd.w, spd.h); - StretchBlt(spd, r, m_img); - /* - CRenderedTextSubtitle rts(nullptr); - rts.CreateDefaultStyle(DEFAULT_CHARSET); - rts.m_storageRes.SetSize(m_size.cx, m_size.cy); - CStringW assstr; - m_img.Polygonize(assstr, false); - REFERENCE_TIME rtStart = 10000i64*m_img.start, rtStop = 10000i64*(m_img.start+m_img.delay); - rts.Add(assstr, true, rtStart, rtStop); - rts.Render(spd, (rtStart+rtStop)/2, 25, r); - */ - r &= CRect(CPoint(0, 0), CSize(spd.w, spd.h)); - bbox = r; - return !r.IsRectEmpty() ? S_OK : S_FALSE; -} - -///////////////////////////////////////////////////////// - -static bool CompressFile(CString fn) -{ - BOOL b = FALSE; - - HANDLE h = CreateFile(fn, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); - if (h != INVALID_HANDLE_VALUE) { - unsigned short us = COMPRESSION_FORMAT_DEFAULT; - DWORD nBytesReturned; - b = DeviceIoControl(h, FSCTL_SET_COMPRESSION, (LPVOID)&us, 2, nullptr, 0, (LPDWORD)&nBytesReturned, nullptr); - CloseHandle(h); - } - - return !!b; -} - -bool CVobSubFile::SaveVobSub(CString fn, int delay) -{ - if (!WriteIdx(fn + _T(".idx"), delay) || !WriteSub(fn + _T(".sub"))) { - return false; - } - m_path = fn + _T(".idx"); - return true; -} - -bool CVobSubFile::SaveWinSubMux(CString fn, int delay) -{ - TrimExtension(fn); - - CStdioFile f; - if (!f.Open(fn + _T(".sub"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { - return false; - } - - m_img.Invalidate(); - - CAutoVectorPtr p4bpp; - if (!p4bpp.Allocate(720 * 576 / 2)) { - return false; - } - - CAtlArray& sp = m_langs[m_nLang].subpos; - for (size_t i = 0; i < sp.GetCount(); i++) { - if (!GetFrame(i)) { - continue; - } - - int pal[4] = {0, 1, 2, 3}; - - for (int j = 0; j < 5; j++) { - if (j == 4 || !m_img.pal[j].tr) { - j &= 3; - memset(p4bpp, (j << 4) | j, 720 * 576 / 2); - pal[j] ^= pal[0], pal[0] ^= pal[j], pal[j] ^= pal[0]; - break; - } - } - - int tr[4] = {m_img.pal[pal[0]].tr, m_img.pal[pal[1]].tr, m_img.pal[pal[2]].tr, m_img.pal[pal[3]].tr}; - - DWORD uipal[4 + 12]; - - if (!m_bCustomPal) { - uipal[0] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[0]].pal]); - uipal[1] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[1]].pal]); - uipal[2] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[2]].pal]); - uipal[3] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[3]].pal]); - } else { - uipal[0] = *((DWORD*)&m_img.cuspal[pal[0]]) & 0xffffff; - uipal[1] = *((DWORD*)&m_img.cuspal[pal[1]]) & 0xffffff; - uipal[2] = *((DWORD*)&m_img.cuspal[pal[2]]) & 0xffffff; - uipal[3] = *((DWORD*)&m_img.cuspal[pal[3]]) & 0xffffff; - } - - CAtlMap palmap; - palmap[uipal[0]] = 0; - palmap[uipal[1]] = 1; - palmap[uipal[2]] = 2; - palmap[uipal[3]] = 3; - - uipal[0] = 0xff; // blue background - - int w = m_img.rect.Width() - 2; - int h = m_img.rect.Height() - 2; - int pitch = (((w + 1) >> 1) + 3) & ~3; - - for (ptrdiff_t y = 0; y < h; y++) { - DWORD* p = (DWORD*)&m_img.lpPixels[(y + 1) * (w + 2) + 1]; - - for (ptrdiff_t x = 0; x < w; x++, p++) { - BYTE c = 0; - - if (*p & 0xff000000) { - DWORD uic = *p & 0xffffff; - palmap.Lookup(uic, c); - } - - BYTE& c4bpp = p4bpp[(h - y - 1) * pitch + (x >> 1)]; - c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); - } - } - - int t1 = (int)m_img.start + delay; - int t2 = t1 + (int)m_img.delay /*+ (m_size.cy==480?(1000/29.97+1):(1000/25))*/; - - ASSERT(t2 > t1); - - if (t2 <= 0) { - continue; - } - if (t1 < 0) { - t1 = 0; - } - - CString bmpfn; - bmpfn.Format(_T("%s_%06Iu.bmp"), fn.GetString(), i + 1); - - CString str; - str.Format(_T("%s\t%02d:%02d:%02d:%02d %02d:%02d:%02d:%02d\t%03d %03d %03d %03d %d %d %d %d\n"), - bmpfn.GetString(), - t1 / 1000 / 60 / 60, (t1 / 1000 / 60) % 60, (t1 / 1000) % 60, (t1 % 1000) / 10, - t2 / 1000 / 60 / 60, (t2 / 1000 / 60) % 60, (t2 / 1000) % 60, (t2 % 1000) / 10, - m_img.rect.Width(), m_img.rect.Height(), m_img.rect.left, m_img.rect.top, - (tr[0] << 4) | tr[0], (tr[1] << 4) | tr[1], (tr[2] << 4) | tr[2], (tr[3] << 4) | tr[3]); - f.WriteString(str); - - BITMAPFILEHEADER fhdr = { - 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + pitch * h, - 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) - }; - - BITMAPINFOHEADER ihdr = { - sizeof(BITMAPINFOHEADER), - w, h, 1, 4, 0, - 0, - pitch * h, 0, - 16, 4 - }; - - CFile bmp; - if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { - bmp.Write(&fhdr, sizeof(fhdr)); - bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(uipal, sizeof(RGBQUAD) * 16); - bmp.Write(p4bpp, pitch * h); - bmp.Close(); - - CompressFile(bmpfn); - } - } - - m_path = fn + _T(".sub"); - - return true; -} - -bool CVobSubFile::SaveScenarist(CString fn, int delay) -{ - TrimExtension(fn); - - CStdioFile f; - if (!f.Open(fn + _T(".sst"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { - return false; - } - - m_img.Invalidate(); - - fn.Replace('\\', '/'); - CString title = fn.Mid(fn.ReverseFind('/') + 1); - - TCHAR buff[MAX_PATH], * pFilePart = buff; - if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { - return false; - } - - CString fullpath = CString(buff).Left(int(pFilePart - buff)); - fullpath.TrimRight(_T("\\/")); - if (fullpath.IsEmpty()) { - return false; - } - - CString str, str2; - str += _T("st_format\t2\n"); - str += _T("Display_Start\t%s\n"); - str += _T("TV_Type\t\t%s\n"); - str += _T("Tape_Type\tNON_DROP\n"); - str += _T("Pixel_Area\t(0 %d)\n"); - str += _T("Directory\t%s\n"); - str += _T("Subtitle\t%s\n"); - str += _T("Display_Area\t(0 2 719 %d)\n"); - str += _T("Contrast\t(15 15 15 0)\n"); - str += _T("\n"); - str += _T("PA\t(0 0 255 - - - )\n"); - str += _T("E1\t(255 0 0 - - - )\n"); - str += _T("E2\t(0 0 0 - - - )\n"); - str += _T("BG\t(255 255 255 - - - )\n"); - str += _T("\n"); - str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); - str2.Format(str, - !m_bOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), - m_size.cy == 480 ? _T("NTSC") : _T("PAL"), - m_size.cy - 3, - fullpath.GetString(), - title.GetString(), - m_size.cy == 480 ? 479 : 574); - - f.WriteString(str2); - - f.Flush(); - - RGBQUAD pal[16] = { - {255, 0, 0, 0}, - {0, 0, 255, 0}, - {0, 0, 0, 0}, - {255, 255, 255, 0}, - {0, 255, 0, 0}, - {255, 0, 255, 0}, - {0, 255, 255, 0}, - {125, 125, 0, 0}, - {125, 125, 125, 0}, - {225, 225, 225, 0}, - {0, 0, 125, 0}, - {0, 125, 0, 0}, - {125, 0, 0, 0}, - {255, 0, 222, 0}, - {0, 125, 222, 0}, - {125, 0, 125, 0}, - }; - - BITMAPFILEHEADER fhdr = { - 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), - 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) - }; - - BITMAPINFOHEADER ihdr = { - sizeof(BITMAPINFOHEADER), - 720, m_size.cy - 2, 1, 4, 0, - DWORD(360 * (m_size.cy - 2)), - 0, 0, - 16, 4 - }; - - bool bCustomPal = m_bCustomPal; - m_bCustomPal = true; - RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; - memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); - memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); - - CAutoVectorPtr p4bpp; - if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { - return false; - } - - BYTE colormap[16]; - - for (size_t i = 0; i < 16; i++) { - BYTE idx = 0; - int maxdif = 255 * 255 * 3 + 1; - - for (size_t j = 0; j < 16 && maxdif; j++) { - int rdif = pal[j].rgbRed - m_orgpal[i].rgbRed; - int gdif = pal[j].rgbGreen - m_orgpal[i].rgbGreen; - int bdif = pal[j].rgbBlue - m_orgpal[i].rgbBlue; - - int dif = rdif * rdif + gdif * gdif + bdif * bdif; - if (dif < maxdif) { - maxdif = dif; - idx = (BYTE)j; - } - } - - colormap[i] = idx + 1; - } - - int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; - - CAtlArray& sp = m_langs[m_nLang].subpos; - for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { - if (!GetFrame(i)) { - continue; - } - - for (int j = 0; j < 5; j++) { - if (j == 4 || !m_img.pal[j].tr) { - j &= 3; - memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); - break; - } - } - - for (ptrdiff_t y = std::max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { - ASSERT(m_size.cy - y - 1 >= 0); - if (m_size.cy - y - 1 < 0) { - break; - } - - DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; - - for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { - DWORD rgb = *p & 0xffffff; - BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; - BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; - c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); - } - } - - CString bmpfn; - bmpfn.Format(_T("%s_%04Iu.bmp"), fn.GetString(), i + 1); - title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); - - // E1, E2, P, Bg - int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]}; - c[0] ^= c[1], c[1] ^= c[0], c[0] ^= c[1]; - - if (memcmp(pc, c, sizeof(c))) { - memcpy(pc, c, sizeof(c)); - str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); - f.WriteString(str); - } - - // E1, E2, P, Bg - int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; - a[0] ^= a[1], a[1] ^= a[0], a[0] ^= a[1]; - - if (memcmp(pa, a, sizeof(a))) { - memcpy(pa, a, sizeof(a)); - str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); - f.WriteString(str); - } - - int t1 = (int)sp[i].start + delay; - int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; - int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); - - int t2 = (int)sp[i].stop + delay; - int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; - int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); - - if (t2 <= 0) { - continue; - } - if (t1 < 0) { - t1 = 0; - } - - if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { - f2++; - if (f2 == (m_size.cy == 480 ? 30 : 25)) { - f2 = 0; - s2++; - if (s2 == 60) { - s2 = 0; - m2++; - if (m2 == 60) { - m2 = 0; - h2++; - } - } - } - } - - if (i + 1 < sp.GetCount()) { - int t3 = (int)sp[i + 1].start + delay; - int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; - int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); - - if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { - f2--; - if (f2 == -1) { - f2 = (m_size.cy == 480 ? 29 : 24); - s2--; - if (s2 == -1) { - s2 = 59; - m2--; - if (m2 == -1) { - m2 = 59; - if (h2 > 0) { - h2--; - } - } - } - } - } - } - - if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { - continue; - } - - str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), - ++k, - h1, m1, s1, f1, - h2, m2, s2, f2, - title.GetString()); - f.WriteString(str); - - CFile bmp; - if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::modeRead | CFile::typeBinary)) { - bmp.Write(&fhdr, sizeof(fhdr)); - bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); - bmp.Write(p4bpp, 360 * (m_size.cy - 2)); - bmp.Close(); - - CompressFile(bmpfn); - } - } - - m_bCustomPal = bCustomPal; - memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); - - m_path = fn + _T(".sst"); - - return true; -} - -bool CVobSubFile::SaveMaestro(CString fn, int delay) -{ - TrimExtension(fn); - - CStdioFile f; - if (!f.Open(fn + _T(".son"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { - return false; - } - - m_img.Invalidate(); - - fn.Replace('\\', '/'); - CString title = fn.Mid(fn.ReverseFind('/') + 1); - - TCHAR buff[MAX_PATH], * pFilePart = buff; - if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { - return false; - } - - CString fullpath = CString(buff).Left(int(pFilePart - buff)); - fullpath.TrimRight(_T("\\/")); - if (fullpath.IsEmpty()) { - return false; - } - - CString str, str2; - str += _T("st_format\t2\n"); - str += _T("Display_Start\t%s\n"); - str += _T("TV_Type\t\t%s\n"); - str += _T("Tape_Type\tNON_DROP\n"); - str += _T("Pixel_Area\t(0 %d)\n"); - str += _T("Directory\t%s\n"); - str += _T("Subtitle\t%s\n"); - str += _T("Display_Area\t(0 2 719 %d)\n"); - str += _T("Contrast\t(15 15 15 0)\n"); - str += _T("\n"); - str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); - str2.Format(str, - !m_bOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), - m_size.cy == 480 ? _T("NTSC") : _T("PAL"), - m_size.cy - 3, - fullpath.GetString(), - title.GetString(), - m_size.cy == 480 ? 479 : 574); - - f.WriteString(str2); - - f.Flush(); - - BITMAPFILEHEADER fhdr = { - 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), - 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) - }; - - BITMAPINFOHEADER ihdr = { - sizeof(BITMAPINFOHEADER), - 720, m_size.cy - 2, 1, 4, 0, - DWORD(360 * (m_size.cy - 2)), - 0, 0, - 16, 4 - }; - - bool bCustomPal = m_bCustomPal; - m_bCustomPal = true; - RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; - memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); - memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); - - CAutoVectorPtr p4bpp; - if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { - return false; - } - - BYTE colormap[16]; - for (BYTE i = 0; i < 16; i++) { - colormap[i] = i; - } - - CFile spf; - if (spf.Open(fn + _T(".spf"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { - for (size_t i = 0; i < 16; i++) { - COLORREF c = (m_orgpal[i].rgbBlue << 16) | (m_orgpal[i].rgbGreen << 8) | m_orgpal[i].rgbRed; - spf.Write(&c, sizeof(COLORREF)); - } - - spf.Close(); - } - - int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; - - CAtlArray& sp = m_langs[m_nLang].subpos; - for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { - if (!GetFrame(i)) { - continue; - } - - for (int j = 0; j < 5; j++) { - if (j == 4 || !m_img.pal[j].tr) { - j &= 3; - memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); - break; - } - } - - for (ptrdiff_t y = std::max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { - ASSERT(m_size.cy - y - 1 >= 0); - if (m_size.cy - y - 1 < 0) { - break; - } - - DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; - - for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { - DWORD rgb = *p & 0xffffff; - BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; - BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; - c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); - } - } - - CString bmpfn; - bmpfn.Format(_T("%s_%04Iu.bmp"), fn.GetString(), i + 1); - title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); - - // E1, E2, P, Bg - int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]}; - - if (memcmp(pc, c, sizeof(c))) { - memcpy(pc, c, sizeof(c)); - str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); - f.WriteString(str); - } - - // E1, E2, P, Bg - int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; - - if (memcmp(pa, a, sizeof(a))) { - memcpy(pa, a, sizeof(a)); - str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); - f.WriteString(str); - } - - int t1 = (int)sp[i].start + delay; - int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; - int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); - - int t2 = (int)sp[i].stop + delay; - int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; - int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); - - if (t2 <= 0) { - continue; - } - if (t1 < 0) { - t1 = 0; - } - - if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { - f2++; - if (f2 == (m_size.cy == 480 ? 30 : 25)) { - f2 = 0; - s2++; - if (s2 == 60) { - s2 = 0; - m2++; - if (m2 == 60) { - m2 = 0; - h2++; - } - } - } - } - - if (i < sp.GetCount() - 1) { - int t3 = (int)sp[i + 1].start + delay; - int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; - int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); - - if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { - f2--; - if (f2 == -1) { - f2 = (m_size.cy == 480 ? 29 : 24); - s2--; - if (s2 == -1) { - s2 = 59; - m2--; - if (m2 == -1) { - m2 = 59; - if (h2 > 0) { - h2--; - } - } - } - } - } - } - - if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { - continue; - } - - str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), - ++k, - h1, m1, s1, f1, - h2, m2, s2, f2, - title.GetString()); - f.WriteString(str); - - CFile bmp; - if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { - bmp.Write(&fhdr, sizeof(fhdr)); - bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); - bmp.Write(p4bpp, 360 * (m_size.cy - 2)); - bmp.Close(); - - CompressFile(bmpfn); - } - } - - m_bCustomPal = bCustomPal; - memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); - - m_path = fn + _T(".son"); - - return true; -} - -// -// CVobSubStream -// - -CVobSubStream::CVobSubStream(CCritSec* pLock) - : CSubPicProviderImpl(pLock) -{ -} - -CVobSubStream::~CVobSubStream() -{ -} - -void CVobSubStream::Open(CString name, BYTE* pData, int len) -{ - CAutoLock cAutoLock(&m_csSubPics); - - m_name = name; - - CAtlList lines; - Explode(CString(CStringA((CHAR*)pData, len)), lines, _T('\n')); - while (lines.GetCount()) { - CAtlList sl; - Explode(lines.RemoveHead(), sl, ':', 2); - if (sl.GetCount() != 2) { - continue; - } - CString key = sl.GetHead(); - CString value = sl.GetTail(); - if (key == _T("size")) { - _stscanf_s(value, _T("%dx %d"), &m_size.cx, &m_size.cy); - } else if (key == _T("org")) { - _stscanf_s(value, _T("%d, %d"), &m_org.x, &m_org.y); - } else if (key == _T("scale")) { - _stscanf_s(value, _T("%d%%, %d%%"), &m_scale_x, &m_scale_y); - } else if (key == _T("alpha")) { - _stscanf_s(value, _T("%d%%"), &m_alpha); - } else if (key == _T("smooth")) - m_iSmooth = - value == _T("0") || value == _T("OFF") ? 0 : - value == _T("1") || value == _T("ON") ? 1 : - value == _T("2") || value == _T("OLD") ? 2 : - 0; - else if (key == _T("align")) { - Explode(value, sl, ' '); - if (sl.GetCount() == 4) { - sl.RemoveAt(sl.FindIndex(1)); - } - if (sl.GetCount() == 3) { - m_bAlign = sl.RemoveHead() == _T("ON"); - CString hor = sl.GetHead(), ver = sl.GetTail(); - m_alignhor = hor == _T("LEFT") ? 0 : hor == _T("CENTER") ? 1 : hor == _T("RIGHT") ? 2 : 1; - m_alignver = ver == _T("TOP") ? 0 : ver == _T("CENTER") ? 1 : /*ver == _T("BOTTOM") ? 2 :*/ 2; - } - } else if (key == _T("fade in/out")) { - _stscanf_s(value, _T("%d, %d"), &m_fadein, &m_fadeout); - } else if (key == _T("time offset")) { - m_toff = _tcstol(value, nullptr, 10); - } else if (key == _T("forced subs")) { - m_bOnlyShowForcedSubs = value == _T("1") || value == _T("ON"); - } else if (key == _T("palette")) { - Explode(value, sl, ',', 16); - for (size_t i = 0; i < 16 && sl.GetCount(); i++) { - *(DWORD*)&m_orgpal[i] = _tcstol(sl.RemoveHead(), nullptr, 16); - } - } else if (key == _T("custom colors")) { - m_bCustomPal = Explode(value, sl, ',', 3) == _T("ON"); - if (sl.GetCount() == 3) { - sl.RemoveHead(); - CAtlList tridx, colors; - - Explode(sl.RemoveHead(), tridx, ':', 2); - int _tridx = 1; - if (tridx.RemoveHead() == _T("tridx")) { - TCHAR tr[4]; - _stscanf_s(tridx.RemoveHead(), _T("%c%c%c%c"), &tr[0], 1, &tr[1], 1, &tr[2], 1, &tr[3], 1); - for (size_t i = 0; i < 4; i++) { - _tridx |= ((tr[i] == '1') ? 1 : 0) << i; - } - } - - Explode(sl.RemoveHead(), colors, ':', 2); - if (colors.RemoveHead() == _T("colors")) { - Explode(colors.RemoveHead(), colors, ',', 4); - - RGBQUAD pal[4]; - for (size_t i = 0; i < 4 && colors.GetCount(); i++) { - *(DWORD*)&pal[i] = _tcstol(colors.RemoveHead(), nullptr, 16); - } - - SetCustomPal(pal, _tridx); - } - } - } - } -} - -void CVobSubStream::Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len) -{ - if (len <= 4 || ((pData[0] << 8) | pData[1]) != len) { - return; - } - - CVobSubImage vsi; - vsi.GetPacketInfo(pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3]); - - CAutoPtr p(DEBUG_NEW SubPic()); - p->tStart = tStart; - p->tStop = vsi.delay > 0 ? (tStart + 10000i64 * vsi.delay) : tStop; - p->bAnimated = vsi.bAnimated; - p->pData.SetCount(len); - memcpy(p->pData.GetData(), pData, p->pData.GetCount()); - - CAutoLock cAutoLock(&m_csSubPics); - while (m_subpics.GetCount() && m_subpics.GetTail()->tStart >= tStart) { - m_subpics.RemoveTail(); - m_img.nIdx = SIZE_T_ERROR; - } - - // We can only render one subpicture at a time, thus if there is overlap - // we have to fix it. tStop = tStart seems to work. - if (m_subpics.GetCount() && m_subpics.GetTail()->tStop > p->tStart) { - TRACE(_T("[CVobSubStream::Add] Vobsub timestamp overlap detected! ") - _T("Subpicture #%d, StopTime %I64d > %I64d (Next StartTime), making them equal!\n"), - m_subpics.GetCount(), m_subpics.GetTail()->tStop, p->tStart); - m_subpics.GetTail()->tStop = p->tStart; - } - - m_subpics.AddTail(p); -} - -void CVobSubStream::RemoveAll() -{ - CAutoLock cAutoLock(&m_csSubPics); - m_subpics.RemoveAll(); - m_img.nIdx = SIZE_T_ERROR; -} - -STDMETHODIMP CVobSubStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = nullptr; - - return - QI(IPersist) - QI(ISubStream) - QI(ISubPicProvider) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPicProvider - -STDMETHODIMP_(POSITION) CVobSubStream::GetStartPosition(REFERENCE_TIME rt, double fps) -{ - CAutoLock cAutoLock(&m_csSubPics); - POSITION pos = m_subpics.GetTailPosition(); - for (; pos; m_subpics.GetPrev(pos)) { - SubPic* sp = m_subpics.GetAt(pos); - if (sp->tStart <= rt) { - if (sp->tStop <= rt) { - m_subpics.GetNext(pos); - } - break; - } - } - return pos; -} - -STDMETHODIMP_(POSITION) CVobSubStream::GetNext(POSITION pos) -{ - CAutoLock cAutoLock(&m_csSubPics); - m_subpics.GetNext(pos); - return pos; -} - -STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStart(POSITION pos, double fps) -{ - CAutoLock cAutoLock(&m_csSubPics); - return m_subpics.GetAt(pos)->tStart; -} - -STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStop(POSITION pos, double fps) -{ - CAutoLock cAutoLock(&m_csSubPics); - return m_subpics.GetAt(pos)->tStop; -} - -STDMETHODIMP_(bool) CVobSubStream::IsAnimated(POSITION pos) -{ - CAutoLock cAutoLock(&m_csSubPics); - return m_subpics.GetAt(pos)->bAnimated; -} - -STDMETHODIMP CVobSubStream::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - if (spd.bpp != 32) { - return E_INVALIDARG; - } - - for (POSITION pos = m_subpics.GetTailPosition(); pos; m_subpics.GetPrev(pos)) { - SubPic* sp = m_subpics.GetAt(pos); - if (sp->tStart <= rt && rt < sp->tStop) { - if (m_img.nIdx != (size_t)pos || (sp->bAnimated && sp->tStart + m_img.tCurrent * 10000i64 <= rt)) { - BYTE* pData = sp->pData.GetData(); - m_img.Decode( - pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3], int((rt - sp->tStart) / 10000i64), - m_bCustomPal, m_tridx, m_orgpal, m_cuspal, true); - m_img.nIdx = (size_t)pos; - } - - return __super::Render(spd, bbox); - } - } - - return E_FAIL; -} - -STDMETHODIMP CVobSubStream::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) -{ - relativeTo = VIDEO; - return S_OK; -} - -// IPersist - -STDMETHODIMP CVobSubStream::GetClassID(CLSID* pClassID) -{ - return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; -} - -// ISubStream - -STDMETHODIMP_(int) CVobSubStream::GetStreamCount() -{ - return 1; -} - -STDMETHODIMP CVobSubStream::GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID) -{ - CAutoLock cAutoLock(&m_csSubPics); - - if (ppName) { - *ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppName)) { - return E_OUTOFMEMORY; - } - wcscpy_s(*ppName, m_name.GetLength() + 1, CStringW(m_name)); - } - - if (pLCID) { - *pLCID = 0; // TODO - } - - return S_OK; -} - -STDMETHODIMP_(int) CVobSubStream::GetStream() -{ - return 0; -} - -STDMETHODIMP CVobSubStream::SetStream(int iStream) -{ - return iStream == 0 ? S_OK : E_FAIL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "TextFile.h" +#include "VobSubFile.h" +#include "mpc-hc_config.h" + +#if !USE_STATIC_UNRAR +#include "unrar.h" +#else +#include "unrar/dll.hpp" +#endif +#include "RTS.h" +#include "../DSUtil/PathUtils.h" +#include "../DSUtil/ISOLang.h" + +// + +struct lang_type { + unsigned short id; + LPCSTR lang_long; +} static constexpr lang_tbl[] = { + {'--', "(Not detected)"}, + {'cc', "Closed Caption"}, + {'aa', "Afar"}, + {'ab', "Abkhazian"}, + {'af', "Afrikaans"}, + {'am', "Amharic"}, + {'ar', "Arabic"}, + {'as', "Assamese"}, + {'ay', "Aymara"}, + {'az', "Azerbaijani"}, + {'ba', "Bashkir"}, + {'be', "Byelorussian"}, + {'bg', "Bulgarian"}, + {'bh', "Bihari"}, + {'bi', "Bislama"}, + {'bn', "Bengali; Bangla"}, + {'bo', "Tibetan"}, + {'br', "Breton"}, + {'ca', "Catalan"}, + {'co', "Corsican"}, + {'cs', "Czech"}, + {'cy', "Welsh"}, + {'da', "Dansk"}, + {'de', "Deutsch"}, + {'dz', "Bhutani"}, + {'el', "Greek"}, + {'en', "English"}, + {'eo', "Esperanto"}, + {'es', "Espanol"}, + {'et', "Estonian"}, + {'eu', "Basque"}, + {'fa', "Persian"}, + {'fi', "Finnish"}, + {'fj', "Fiji"}, + {'fo', "Faroese"}, + {'fr', "Francais"}, + {'fy', "Frisian"}, + {'ga', "Irish"}, + {'gd', "Scots Gaelic"}, + {'gl', "Galician"}, + {'gn', "Guarani"}, + {'gu', "Gujarati"}, + {'ha', "Hausa"}, + {'he', "Hebrew"}, + {'hi', "Hindi"}, + {'hr', "Hrvatski"}, + {'hu', "Hungarian"}, + {'hy', "Armenian"}, + {'ia', "Interlingua"}, + {'id', "Indonesian"}, + {'ie', "Interlingue"}, + {'ik', "Inupiak"}, + {'in', "Indonesian"}, + {'is', "Islenska"}, + {'it', "Italiano"}, + {'iu', "Inuktitut"}, + {'iw', "Hebrew"}, + {'ja', "Japanese"}, + {'ji', "Yiddish"}, + {'jw', "Javanese"}, + {'ka', "Georgian"}, + {'kk', "Kazakh"}, + {'kl', "Greenlandic"}, + {'km', "Cambodian"}, + {'kn', "Kannada"}, + {'ko', "Korean"}, + {'ks', "Kashmiri"}, + {'ku', "Kurdish"}, + {'ky', "Kirghiz"}, + {'la', "Latin"}, + {'ln', "Lingala"}, + {'lo', "Laothian"}, + {'lt', "Lithuanian"}, + {'lv', "Latvian, Lettish"}, + {'mg', "Malagasy"}, + {'mi', "Maori"}, + {'mk', "Macedonian"}, + {'ml', "Malayalam"}, + {'mn', "Mongolian"}, + {'mo', "Moldavian"}, + {'mr', "Marathi"}, + {'ms', "Malay"}, + {'mt', "Maltese"}, + {'my', "Burmese"}, + {'na', "Nauru"}, + {'ne', "Nepali"}, + {'nl', "Nederlands"}, + {'no', "Norsk"}, + {'oc', "Occitan"}, + {'om', "(Afan) Oromo"}, + {'or', "Oriya"}, + {'pa', "Punjabi"}, + {'pl', "Polish"}, + {'ps', "Pashto, Pushto"}, + {'pt', "Portugues"}, + {'qu', "Quechua"}, + {'rm', "Rhaeto-Romance"}, + {'rn', "Kirundi"}, + {'ro', "Romanian"}, + {'ru', "Russian"}, + {'rw', "Kinyarwanda"}, + {'sa', "Sanskrit"}, + {'sd', "Sindhi"}, + {'sg', "Sangho"}, + {'sh', "Serbo-Croatian"}, + {'si', "Sinhalese"}, + {'sk', "Slovak"}, + {'sl', "Slovenian"}, + {'sm', "Samoan"}, + {'sn', "Shona"}, + {'so', "Somali"}, + {'sq', "Albanian"}, + {'sr', "Serbian"}, + {'ss', "Siswati"}, + {'st', "Sesotho"}, + {'su', "Sundanese"}, + {'sv', "Svenska"}, + {'sw', "Swahili"}, + {'ta', "Tamil"}, + {'te', "Telugu"}, + {'tg', "Tajik"}, + {'th', "Thai"}, + {'ti', "Tigrinya"}, + {'tk', "Turkmen"}, + {'tl', "Tagalog"}, + {'tn', "Setswana"}, + {'to', "Tonga"}, + {'tr', "Turkish"}, + {'ts', "Tsonga"}, + {'tt', "Tatar"}, + {'tw', "Twi"}, + {'ug', "Uighur"}, + {'uk', "Ukrainian"}, + {'ur', "Urdu"}, + {'uz', "Uzbek"}, + {'vi', "Vietnamese"}, + {'vo', "Volapuk"}, + {'wo', "Wolof"}, + {'xh', "Xhosa"}, + {'yi', "Yiddish"}, // formerly ji + {'yo', "Yoruba"}, + {'za', "Zhuang"}, + {'zh', "Chinese"}, + {'zu', "Zulu"}, +}; + +int find_lang(unsigned short id) +{ + int lo = 0, hi = _countof(lang_tbl) - 1; + + while (lo < hi) { + int mid = (lo + hi) >> 1; + + if (id < lang_tbl[mid].id) { + hi = mid; + } else if (id > lang_tbl[mid].id) { + lo = mid + 1; + } else { + return mid; + } + } + + return (id == lang_tbl[lo].id ? lo : 0); +} + +CString FindLangFromId(WORD id) +{ + return CString(lang_tbl[find_lang(id)].lang_long); +} + +// +// CVobSubFile +// + +CVobSubFile::CVobSubFile(CCritSec* pLock) + : CSubPicProviderImpl(pLock) + , m_sub(1024 * 1024) + , m_nLang(0) +{ +} + +CVobSubFile::~CVobSubFile() +{ +} + +// + +bool CVobSubFile::Copy(CVobSubFile& vsf) +{ + Close(); + + *(CVobSubSettings*)this = *(CVobSubSettings*)&vsf; + m_title = vsf.m_title; + m_nLang = vsf.m_nLang; + + m_sub.SetLength(vsf.m_sub.GetLength()); + m_sub.SeekToBegin(); + + for (size_t i = 0; i < m_langs.size(); i++) { + SubLang& src = vsf.m_langs[i]; + SubLang& dst = m_langs[i]; + + dst.id = src.id; + dst.name = src.name; + dst.alt = src.alt; + + for (size_t j = 0; j < src.subpos.GetCount(); j++) { + SubPos& sp = src.subpos[j]; + if (!sp.bValid) { + continue; + } + + if (sp.filepos != (__int64)vsf.m_sub.Seek(sp.filepos, CFile::begin)) { + continue; + } + + sp.filepos = m_sub.GetPosition(); + + BYTE buff[2048]; + UINT uRead = vsf.m_sub.Read(buff, 2048); + m_sub.Write(buff, uRead); + + WORD packetsize = (buff[buff[0x16] + 0x18] << 8) | buff[buff[0x16] + 0x19]; + + for (int k = 0, size, sizeleft = packetsize - 4; + k < packetsize - 4; + k += size, sizeleft -= size) { + int hsize = buff[0x16] + 0x18 + ((buff[0x15] & 0x80) ? 4 : 0); + size = std::min(sizeleft, 2048 - hsize); + + if (size != sizeleft) { + while ((uRead = vsf.m_sub.Read(buff, 2048)) > 0) { + if (!(buff[0x15] & 0x80) && buff[buff[0x16] + 0x17] == (i | 0x20)) { + break; + } + } + + m_sub.Write(buff, uRead); + } + } + + dst.subpos.Add(sp); + } + } + + m_sub.SetLength(m_sub.GetPosition()); + + return true; +} + +// + +void CVobSubFile::TrimExtension(CString& fn) +{ + int i = fn.ReverseFind('.'); + if (i > 0) { + CString ext = fn.Mid(i).MakeLower(); + if (ext == _T(".ifo") || ext == _T(".idx") || ext == _T(".sub") + || ext == _T(".sst") || ext == _T(".son") || ext == _T(".rar")) { + fn = fn.Left(i); + } + } +} + +bool CVobSubFile::Open(CString fn) +{ + m_path = fn; + TrimExtension(fn); + + do { + Close(); + + int ver; + if (!ReadIdx(fn + _T(".idx"), ver)) { + break; + } + + if (ver < 6 && !ReadIfo(fn + _T(".ifo"))) { + break; + } + + if (!ReadSub(fn + _T(".sub")) && !ReadRar(fn + _T(".rar"))) { + break; + } + + m_title = fn; + + for (size_t i = 0; i < m_langs.size(); i++) { + CAtlArray& sp = m_langs[i].subpos; + + for (size_t j = 0; j < sp.GetCount(); j++) { + sp[j].stop = sp[j].start; + sp[j].bForced = false; + + size_t packetSize = 0, dataSize = 0; + BYTE* buff = GetPacket(j, packetSize, dataSize, i); + if (!buff) { + sp[j].bValid = false; + continue; + } + + m_img.delay = j + 1 < sp.GetCount() ? sp[j + 1].start - sp[j].start : 3000; + m_img.GetPacketInfo(buff, packetSize, dataSize); + if (j + 1 < sp.GetCount()) { + m_img.delay = std::min(m_img.delay, sp[j + 1].start - sp[j].start); + } + + sp[j].stop = sp[j].start + m_img.delay; + sp[j].bForced = m_img.bForced; + sp[j].bAnimated = m_img.bAnimated; + + if (j > 0 && sp[j - 1].stop > sp[j].start) { + sp[j - 1].stop = sp[j].start; + } + + delete [] buff; + } + } + + return true; + } while (false); + + Close(); + + return false; +} + +bool CVobSubFile::Save(CString fn, int delay, SubFormat sf) +{ + TrimExtension(fn); + + CVobSubFile vsf(nullptr); + if (!vsf.Copy(*this)) { + return false; + } + + switch (sf) { + case VobSub: + return vsf.SaveVobSub(fn, delay); + case WinSubMux: + return vsf.SaveWinSubMux(fn, delay); + case Scenarist: + return vsf.SaveScenarist(fn, delay); + case Maestro: + return vsf.SaveMaestro(fn, delay); + default: + break; + } + + return false; +} + +void CVobSubFile::Close() +{ + InitSettings(); + m_title.Empty(); + m_sub.SetLength(0); + m_img.Invalidate(); + m_nLang = SIZE_T_ERROR; + for (auto& sl : m_langs) { + sl.id = 0; + sl.name.Empty(); + sl.alt.Empty(); + sl.subpos.RemoveAll(); + } +} + +// + +bool CVobSubFile::ReadIdx(CString fn, int& ver) +{ + CWebTextFile f; + if (!f.Open(fn)) { + return false; + } + + bool bError = false; + + int id = -1, delay = 0, vobid = -1, cellid = -1; + __int64 celltimestamp = 0; + + CString str; + for (ptrdiff_t line = 0; !bError && f.ReadString(str); line++) { + str.Trim(); + + if (line == 0) { + TCHAR buff[] = _T("VobSub index file, v"); + + const TCHAR* s = str; + + int i = str.Find(buff); + if (i < 0 || _stscanf_s(&s[i + _tcslen(buff)], _T("%d"), &ver) != 1 + || ver > VOBSUBIDXVER) { + TRACE(_T("[CVobSubFile::ReadIdx] Wrong file version!\n")); + bError = true; + continue; + } + } else if (!str.GetLength()) { + continue; + } else if (str[0] == _T('#')) { + TCHAR buff[] = _T("Vob/Cell ID:"); + + const TCHAR* s = str; + + int i = str.Find(buff); + if (i >= 0) { + _stscanf_s(&s[i + _tcslen(buff)], _T("%d, %d (PTS: %I64d)"), &vobid, &cellid, &celltimestamp); + } + + continue; + } + + int i = str.Find(':'); + if (i <= 0) { + continue; + } + + CString entry = str.Left(i).MakeLower(); + + str = str.Mid(i + 1); + str.Trim(); + if (str.IsEmpty()) { + continue; + } + + if (entry == _T("size")) { + int x, y; + if (_stscanf_s(str, _T("%dx%d"), &x, &y) != 2) { + bError = true; + } + m_size.cx = x; + m_size.cy = y; + } else if (entry == _T("org")) { + if (_stscanf_s(str, _T("%d,%d"), &m_x, &m_y) != 2) { + bError = true; + } else { + m_org = CPoint(m_x, m_y); + } + } else if (entry == _T("scale")) { + if (ver < 5) { + int scale = 100; + if (_stscanf_s(str, _T("%d%%"), &scale) != 1) { + bError = true; + } + m_scale_x = m_scale_y = scale; + } else { + if (_stscanf_s(str, _T("%d%%,%d%%"), &m_scale_x, &m_scale_y) != 2) { + bError = true; + } + } + } else if (entry == _T("alpha")) { + if (_stscanf_s(str, _T("%d"), &m_alpha) != 1) { + bError = true; + } + } else if (entry == _T("smooth")) { + str.MakeLower(); + + if (str.Find(_T("old")) >= 0 || str.Find(_T("2")) >= 0) { + m_iSmooth = 2; + } else if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { + m_iSmooth = 1; + } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { + m_iSmooth = 0; + } else { + bError = true; + } + } else if (entry == _T("fadein/out")) { + if (_stscanf_s(str, _T("%d,%d"), &m_fadein, &m_fadeout) != 2) { + bError = true; + } + } else if (entry == _T("align")) { + str.MakeLower(); + + int k = 0; + CString token; + for (int j = 0; j < 3; j++) { + token = str.Tokenize(_T(" "), k); + if (token.IsEmpty()) { + break; + } + + if (j == 0) { + if (token == _T("on") || token == _T("1")) { + m_bAlign = true; + } else if (token == _T("off") || token == _T("0")) { + m_bAlign = false; + } else { + bError = true; + break; + } + } else if (j == 1) { + if (token == _T("at")) { + j--; + continue; + } + + if (token == _T("left")) { + m_alignhor = 0; + } else if (token == _T("center")) { + m_alignhor = 1; + } else if (token == _T("right")) { + m_alignhor = 2; + } else { + bError = true; + break; + } + } else if (j == 2) { + if (token == _T("top")) { + m_alignver = 0; + } else if (token == _T("center")) { + m_alignver = 1; + } else if (token == _T("bottom")) { + m_alignver = 2; + } else { + bError = true; + break; + } + } + } + } else if (entry == _T("time offset")) { + bool bNegative = false; + if (str[0] == '-') { + bNegative = true; + } + str.TrimLeft(_T("+-")); + + TCHAR c; + int hh, mm, ss, ms; + int n = _stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms); + + switch (n) { + case 1: // We have read only one integer, interpret it as an offset expressed in milliseconds + m_toff = hh * (bNegative ? -1 : 1); + break; + case 7: // We have read 4 integers + 3 separators, interpret them as hh:mm:ss.ms + m_toff = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1); + break; + default: + bError = true; + m_toff = 0; + break; + } + } else if (entry == _T("forced subs")) { + str.MakeLower(); + + if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { + m_bOnlyShowForcedSubs = true; + } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { + m_bOnlyShowForcedSubs = false; + } else { + bError = true; + } + } else if (entry == _T("langidx")) { + int iLang = -1; + if (_stscanf_s(str, _T("%d"), &iLang) != 1) { + bError = true; + } + m_nLang = (iLang < 0 && size_t(iLang) >= m_langs.size()) ? SIZE_T_ERROR : size_t(iLang); + } else if (entry == _T("palette")) { + // The assert guarantees that the shortcut we use will work as expected + static_assert(sizeof(RGBQUAD) == 4, "Packing error"); +#pragma warning(push) +#pragma warning(disable: 4477) + if (_stscanf_s(str, _T("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"), + &m_orgpal[0], &m_orgpal[1], &m_orgpal[2], &m_orgpal[3], + &m_orgpal[4], &m_orgpal[5], &m_orgpal[6], &m_orgpal[7], + &m_orgpal[8], &m_orgpal[9], &m_orgpal[10], &m_orgpal[11], + &m_orgpal[12], &m_orgpal[13], &m_orgpal[14], &m_orgpal[15] + ) != 16) { +#pragma warning(pop) + bError = true; + } + } else if (entry == _T("custom colors")) { + str.MakeLower(); + + if (str.Find(_T("on")) == 0 || str.Find(_T("1")) == 0) { + m_bCustomPal = true; + } else if (str.Find(_T("off")) == 0 || str.Find(_T("0")) == 0) { + m_bCustomPal = false; + } else { + bError = true; + } + + i = str.Find(_T("tridx:")); + if (i < 0) { + bError = true; + continue; + } + str = str.Mid(i + (int)_tcslen(_T("tridx:"))); + + int tridx; + if (_stscanf_s(str, _T("%x"), &tridx) != 1) { + bError = true; + continue; + } + tridx = ((tridx & 0x1000) >> 12) | ((tridx & 0x100) >> 7) | ((tridx & 0x10) >> 2) | ((tridx & 1) << 3); + + i = str.Find(_T("colors:")); + if (i < 0) { + bError = true; + continue; + } + str = str.Mid(i + (int)_tcslen(_T("colors:"))); + + RGBQUAD pal[4]; +#pragma warning(push) +#pragma warning(disable: 4477) + if (_stscanf_s(str, _T("%x,%x,%x,%x"), &pal[0], &pal[1], &pal[2], &pal[3]) != 4) { +#pragma warning(pop) + bError = true; + continue; + } + + SetCustomPal(pal, tridx); + } else if (entry == _T("id")) { + str.MakeLower(); + + WORD langid = ((str[0] & 0xff) << 8) | (str[1] & 0xff); + + i = str.Find(_T("index:")); + if (i < 0) { + bError = true; + continue; + } + str = str.Mid(i + (int)_tcslen(_T("index:"))); + + if (_stscanf_s(str, _T("%d"), &id) != 1 || id < 0 || size_t(id) >= m_langs.size()) { + bError = true; + continue; + } + if (m_nLang == SIZE_T_ERROR) { + m_nLang = size_t(id); + } + + m_langs[id].id = langid; + m_langs[id].name = lang_tbl[find_lang(langid)].lang_long; + m_langs[id].alt = lang_tbl[find_lang(langid)].lang_long; + + delay = 0; + } else if (id >= 0 && entry == _T("alt")) { + m_langs[id].alt = str; + } else if (id >= 0 && entry == _T("delay")) { + bool bNegative = false; + if (str[0] == '-') { + bNegative = true; + } + str.TrimLeft(_T("+-")); + + TCHAR c; + int hh, mm, ss, ms; + if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { + bError = true; + continue; + } + + delay += (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1); + } else if (id >= 0 && entry == _T("timestamp")) { + SubPos sb; + + sb.vobid = (char)vobid; + sb.cellid = (char)cellid; + sb.celltimestamp = celltimestamp; + sb.bValid = true; + + bool bNegative = false; + if (str[0] == '-') { + bNegative = true; + } + str.TrimLeft(_T("+-")); + + TCHAR c; + int hh, mm, ss, ms; + if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { + bError = true; + continue; + } + + sb.start = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1) + delay; + + i = str.Find(_T("filepos:")); + if (i < 0) { + bError = true; + continue; + } + str = str.Mid(i + (int)_tcslen(_T("filepos:"))); + + if (_stscanf_s(str, _T("%I64x"), &sb.filepos) != 1) { + bError = true; + continue; + } + + if (delay < 0 && !m_langs[id].subpos.IsEmpty()) { + __int64 ts = m_langs[id].subpos[m_langs[id].subpos.GetCount() - 1].start; + + if (sb.start < ts) { + delay += (int)(ts - sb.start); + sb.start = ts; + } + } + + m_langs[id].subpos.Add(sb); + } else { + bError = true; + } + } + + return !bError; +} + +bool CVobSubFile::ReadSub(CString fn) +{ + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + + int len; + BYTE buff[2048]; + try { + m_sub.SetLength(f.GetLength()); + m_sub.SeekToBegin(); + while ((len = f.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { + m_sub.Write(buff, len); + } + } + catch (CFileException*) { + return false; + } + + return true; +} + +static unsigned char* RARbuff = nullptr; +static unsigned int RARpos = 0; + +static int CALLBACK MyCallbackProc(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2) +{ + if (msg == UCM_PROCESSDATA) { + ASSERT(RARbuff); + + memcpy(&RARbuff[RARpos], (char*)P1, (size_t)P2); + RARpos += (unsigned int)P2; + } + + return 1; +} + +bool CVobSubFile::ReadRar(CString fn) +{ +#if !USE_STATIC_UNRAR +#ifdef _WIN64 + HMODULE h = LoadLibrary(_T("unrar64.dll")); +#else + HMODULE h = LoadLibrary(_T("unrar.dll")); +#endif + if (!h) { + return false; + } + + RAROpenArchiveEx OpenArchiveEx = (RAROpenArchiveEx)GetProcAddress(h, "RAROpenArchiveEx"); + RARCloseArchive CloseArchive = (RARCloseArchive)GetProcAddress(h, "RARCloseArchive"); + RARReadHeaderEx ReadHeaderEx = (RARReadHeaderEx)GetProcAddress(h, "RARReadHeaderEx"); + RARProcessFile ProcessFile = (RARProcessFile)GetProcAddress(h, "RARProcessFile"); + RARSetCallback SetCallback = (RARSetCallback)GetProcAddress(h, "RARSetCallback"); + + if (!(OpenArchiveEx && CloseArchive && ReadHeaderEx && ProcessFile && SetCallback)) { + FreeLibrary(h); + return false; + } + +#else + +#define OpenArchiveEx RAROpenArchiveEx +#define CloseArchive RARCloseArchive +#define ReadHeaderEx RARReadHeaderEx +#define ProcessFile RARProcessFile +#define SetCallback RARSetCallback +#endif /* USE_STATIC_UNRAR */ + + RAROpenArchiveDataEx OpenArchiveData; + ZeroMemory(&OpenArchiveData, sizeof(OpenArchiveData)); + + OpenArchiveData.ArcNameW = (LPTSTR)(LPCTSTR)fn; + char fnA[MAX_PATH]; + size_t size; + if (wcstombs_s(&size, fnA, fn, fn.GetLength())) { + fnA[0] = 0; + } + OpenArchiveData.ArcName = fnA; + OpenArchiveData.OpenMode = RAR_OM_EXTRACT; + OpenArchiveData.CmtBuf = 0; + OpenArchiveData.Callback = MyCallbackProc; + HANDLE hArcData = OpenArchiveEx(&OpenArchiveData); + if (!hArcData) { +#if !USE_STATIC_UNRAR + FreeLibrary(h); +#endif + return false; + } + + RARHeaderDataEx HeaderDataEx; + HeaderDataEx.CmtBuf = nullptr; + + while (ReadHeaderEx(hArcData, &HeaderDataEx) == 0) { + CString subfn(HeaderDataEx.FileNameW); + + if (!subfn.Right(4).CompareNoCase(_T(".sub"))) { + CAutoVectorPtr buff; + if (!buff.Allocate(HeaderDataEx.UnpSize)) { + CloseArchive(hArcData); +#if !USE_STATIC_UNRAR + FreeLibrary(h); +#endif + return false; + } + + RARbuff = buff; + RARpos = 0; + + if (ProcessFile(hArcData, RAR_TEST, nullptr, nullptr)) { + CloseArchive(hArcData); +#if !USE_STATIC_UNRAR + FreeLibrary(h); +#endif + + return false; + } + + m_sub.SetLength(HeaderDataEx.UnpSize); + m_sub.SeekToBegin(); + m_sub.Write(buff, HeaderDataEx.UnpSize); + m_sub.SeekToBegin(); + + RARbuff = nullptr; + RARpos = 0; + + break; + } + + ProcessFile(hArcData, RAR_SKIP, nullptr, nullptr); + } + + CloseArchive(hArcData); +#if !USE_STATIC_UNRAR + FreeLibrary(h); +#endif + + return true; +} + +bool CVobSubFile::ReadIfo(CString fn) +{ + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + + /* PGC1 */ + + f.Seek(0xc0 + 0x0c, SEEK_SET); + + DWORD pos; + ReadBEdw(pos); + + f.Seek(pos * 0x800 + 0x0c, CFile::begin); + + DWORD offset; + ReadBEdw(offset); + + /* Subpic palette */ + + f.Seek(pos * 0x800 + offset + 0xa4, CFile::begin); + + for (size_t i = 0; i < 16; i++) { + BYTE y, u, v, tmp; + + f.Read(&tmp, 1); + f.Read(&y, 1); + f.Read(&u, 1); + f.Read(&v, 1); + + y = (y - 16) * 255 / 219; + + m_orgpal[i].rgbRed = std::min(std::max(BYTE(1.0 * y + 1.4022 * (u - 128)), 0u), 255u); + m_orgpal[i].rgbGreen = std::min(std::max(BYTE(1.0 * y - 0.3456 * (u - 128) - 0.7145 * (v - 128)), 0u), 255u); + m_orgpal[i].rgbBlue = std::min(std::max(BYTE(1.0 * y + 1.7710 * (v - 128)), 0u), 255u); + } + + return true; +} + +bool CVobSubFile::WriteIdx(CString fn, int delay) +{ + CTextFile f; + if (!f.Save(fn, CTextFile::DEFAULT_ENCODING)) { + return false; + } + + CString str; + str.Format(_T("# VobSub index file, v%d (do not modify this line!)\n"), VOBSUBIDXVER); + + f.WriteString(str); + f.WriteString(_T("# \n")); + f.WriteString(_T("# To repair desyncronization, you can insert gaps this way:\n")); + f.WriteString(_T("# (it usually happens after vob id changes)\n")); + f.WriteString(_T("# \n")); + f.WriteString(_T("#\t delay: [sign]hh:mm:ss:ms\n")); + f.WriteString(_T("# \n")); + f.WriteString(_T("# Where:\n")); + f.WriteString(_T("#\t [sign]: +, - (optional)\n")); + f.WriteString(_T("#\t hh: hours (0 <= hh)\n")); + f.WriteString(_T("#\t mm/ss: minutes/seconds (0 <= mm/ss <= 59)\n")); + f.WriteString(_T("#\t ms: milliseconds (0 <= ms <= 999)\n")); + f.WriteString(_T("# \n")); + f.WriteString(_T("#\t Note: You can't position a sub before the previous with a negative value.\n")); + f.WriteString(_T("# \n")); + f.WriteString(_T("# You can also modify timestamps or delete a few subs you don't like.\n")); + f.WriteString(_T("# Just make sure they stay in increasing order.\n")); + f.WriteString(_T("\n")); + f.WriteString(_T("\n")); + + // Settings + + f.WriteString(_T("# Settings\n\n")); + + f.WriteString(_T("# Original frame size\n")); + str.Format(_T("size: %ldx%ld\n\n"), m_size.cx, m_size.cy); + f.WriteString(str); + + f.WriteString(_T("# Origin, relative to the upper-left corner, can be overloaded by aligment\n")); + str.Format(_T("org: %d, %d\n\n"), m_x, m_y); + f.WriteString(str); + + f.WriteString(_T("# Image scaling (hor,ver), origin is at the upper-left corner or at the alignment coord (x, y)\n")); + str.Format(_T("scale: %d%%, %d%%\n\n"), m_scale_x, m_scale_y); + f.WriteString(str); + + f.WriteString(_T("# Alpha blending\n")); + str.Format(_T("alpha: %d%%\n\n"), m_alpha); + f.WriteString(str); + + f.WriteString(_T("# Smoothing for very blocky images (use OLD for no filtering)\n")); + str.Format(_T("smooth: %s\n\n"), m_iSmooth == 0 ? _T("OFF") : m_iSmooth == 1 ? _T("ON") : _T("OLD")); + f.WriteString(str); + + f.WriteString(_T("# In millisecs\n")); + str.Format(_T("fadein/out: %d, %d\n\n"), m_fadein, m_fadeout); + f.WriteString(str); + + f.WriteString(_T("# Force subtitle placement relative to (org.x, org.y)\n")); + str.Format(_T("align: %s %s %s\n\n"), + m_bAlign ? _T("ON at") : _T("OFF at"), + m_alignhor == 0 ? _T("LEFT") : m_alignhor == 1 ? _T("CENTER") : m_alignhor == 2 ? _T("RIGHT") : _T(""), + m_alignver == 0 ? _T("TOP") : m_alignver == 1 ? _T("CENTER") : m_alignver == 2 ? _T("BOTTOM") : _T("")); + f.WriteString(str); + + f.WriteString(_T("# For correcting non-progressive desync. (in millisecs or hh:mm:ss:ms)\n")); + f.WriteString(_T("# Note: Not effective in VSFilter, use \"delay: ... \" instead.\n")); + str.Format(_T("time offset: %u\n\n"), m_toff); + f.WriteString(str); + + f.WriteString(_T("# ON: displays only forced subtitles, OFF: shows everything\n")); + str.Format(_T("forced subs: %s\n\n"), m_bOnlyShowForcedSubs ? _T("ON") : _T("OFF")); + f.WriteString(str); + + f.WriteString(_T("# The original palette of the DVD\n")); + str.Format(_T("palette: %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n\n"), + *((unsigned int*)&m_orgpal[0]) & 0xffffff, + *((unsigned int*)&m_orgpal[1]) & 0xffffff, + *((unsigned int*)&m_orgpal[2]) & 0xffffff, + *((unsigned int*)&m_orgpal[3]) & 0xffffff, + *((unsigned int*)&m_orgpal[4]) & 0xffffff, + *((unsigned int*)&m_orgpal[5]) & 0xffffff, + *((unsigned int*)&m_orgpal[6]) & 0xffffff, + *((unsigned int*)&m_orgpal[7]) & 0xffffff, + *((unsigned int*)&m_orgpal[8]) & 0xffffff, + *((unsigned int*)&m_orgpal[9]) & 0xffffff, + *((unsigned int*)&m_orgpal[10]) & 0xffffff, + *((unsigned int*)&m_orgpal[11]) & 0xffffff, + *((unsigned int*)&m_orgpal[12]) & 0xffffff, + *((unsigned int*)&m_orgpal[13]) & 0xffffff, + *((unsigned int*)&m_orgpal[14]) & 0xffffff, + *((unsigned int*)&m_orgpal[15]) & 0xffffff); + f.WriteString(str); + + int tridx = (!!(m_tridx & 1)) * 0x1000 + (!!(m_tridx & 2)) * 0x100 + (!!(m_tridx & 4)) * 0x10 + (!!(m_tridx & 8)); + + f.WriteString(_T("# Custom colors (transp idxs and the four colors)\n")); + str.Format(_T("custom colors: %s, tridx: %04x, colors: %06x, %06x, %06x, %06x\n\n"), + m_bCustomPal ? _T("ON") : _T("OFF"), + tridx, + *((unsigned int*)&m_cuspal[0]) & 0xffffff, + *((unsigned int*)&m_cuspal[1]) & 0xffffff, + *((unsigned int*)&m_cuspal[2]) & 0xffffff, + *((unsigned int*)&m_cuspal[3]) & 0xffffff); + f.WriteString(str); + + f.WriteString(_T("# Language index in use\n")); + str.Format(_T("langidx: %Iu\n\n"), m_nLang); + f.WriteString(str); + + if (delay) { + str.Format(_T("delay: %s%02d:%02d:%02d:%03d\n\n"), + delay < 0 ? _T("-") : _T(""), + abs(delay / 1000 / 60 / 60) % 60, + abs(delay / 1000 / 60) % 60, + abs(delay / 1000) % 60, + abs(delay % 1000)); + f.WriteString(str); + } + + // Subs + + for (size_t i = 0; i < m_langs.size(); i++) { + SubLang& sl = m_langs[i]; + + CAtlArray& sp = sl.subpos; + if (sp.IsEmpty() && !sl.id) { + continue; + } + + str.Format(_T("# %s\n"), sl.name.GetString()); + f.WriteString(str); + + ASSERT(sl.id); + if (!sl.id) { + sl.id = '--'; + } + str.Format(_T("id: %c%c, index: %Iu\n"), sl.id >> 8, sl.id & 0xff, i); + f.WriteString(str); + + str = _T("# Uncomment next line to activate alternative name in VSFilter / Windows Media Player 6.x\n"); + f.WriteString(str); + str.Format(_T("alt: %s\n"), sl.alt.GetString()); + if (sl.name == sl.alt) { + str = _T("# ") + str; + } + f.WriteString(str); + + char vobid = -1, cellid = -1; + + for (size_t j = 0; j < sp.GetCount(); j++) { + if (!sp[j].bValid) { + continue; + } + + if (sp[j].vobid != vobid || sp[j].cellid != cellid) { + str.Format(_T("# Vob/Cell ID: %d, %d (PTS: %I64d)\n"), sp[j].vobid, sp[j].cellid, sp[j].celltimestamp); + f.WriteString(str); + vobid = sp[j].vobid; + cellid = sp[j].cellid; + } + + str.Format(_T("timestamp: %s%02d:%02d:%02d:%03d, filepos: %09I64x\n"), + sp[j].start < 0 ? _T("-") : _T(""), + abs(int((sp[j].start / 1000 / 60 / 60) % 60)), + abs(int((sp[j].start / 1000 / 60) % 60)), + abs(int((sp[j].start / 1000) % 60)), + abs(int((sp[j].start) % 1000)), + sp[j].filepos); + f.WriteString(str); + } + + f.WriteString(_T("\n")); + } + + return true; +} + +bool CVobSubFile::WriteSub(CString fn) +{ + CFile f; + if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { + return false; + } + + if (m_sub.GetLength() == 0) { + return true; // nothing to do... + } + + m_sub.SeekToBegin(); + + int len; + BYTE buff[2048]; + while ((len = m_sub.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { + f.Write(buff, len); + } + + return true; +} + +// + +BYTE* CVobSubFile::GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang /*= SIZE_T_ERROR*/) +{ + BYTE* ret = nullptr; + + if (nLang >= m_langs.size()) { + nLang = m_nLang; + } + CAtlArray& sp = m_langs[nLang].subpos; + + do { + if (idx >= sp.GetCount()) { + break; + } + + if ((__int64)m_sub.Seek(sp[idx].filepos, CFile::begin) != sp[idx].filepos) { + break; + } + + BYTE buff[0x800]; + if (sizeof(buff) != m_sub.Read(buff, sizeof(buff))) { + break; + } + + ASSERT(nLang < BYTE_MAX); + + // let's check a few things to make sure... + if (*(DWORD*)&buff[0x00] != 0xba010000 + || *(DWORD*)&buff[0x0e] != 0xbd010000 + || !(buff[0x15] & 0x80) + || (buff[0x17] & 0xf0) != 0x20 + || (buff[buff[0x16] + 0x17] & 0xe0) != 0x20 + || (buff[buff[0x16] + 0x17] & 0x1f) != (BYTE)nLang) { + break; + } + + packetSize = (buff[buff[0x16] + 0x18] << 8) + buff[buff[0x16] + 0x19]; + dataSize = (buff[buff[0x16] + 0x1a] << 8) + buff[buff[0x16] + 0x1b]; + + try { + ret = DEBUG_NEW BYTE[packetSize]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + break; + } + + size_t i = 0, sizeLeft = packetSize; + for (size_t size; i < packetSize; i += size, sizeLeft -= size) { + size_t hsize = 0x18 + buff[0x16]; + size = std::min(sizeLeft, 0x800 - hsize); + memcpy(&ret[i], &buff[hsize], size); + + if (size != sizeLeft) { + while (m_sub.Read(buff, sizeof(buff))) { + if (/*!(buff[0x15] & 0x80) &&*/ buff[buff[0x16] + 0x17] == (nLang | 0x20)) { + break; + } + } + } + } + + if (i != packetSize || sizeLeft > 0) { + delete [] ret; + ret = nullptr; + } + } while (false); + + return ret; +} + +const CVobSubFile::SubPos* CVobSubFile::GetFrameInfo(size_t idx, size_t nLang /*= SIZE_T_ERROR*/) const +{ + if (nLang >= m_langs.size()) { + nLang = m_nLang; + } + const CAtlArray& sp = m_langs[nLang].subpos; + + if (idx >= sp.GetCount() + || !sp[idx].bValid + || (m_bOnlyShowForcedSubs && !sp[idx].bForced)) { + return nullptr; + } + + return &sp[idx]; +} + +bool CVobSubFile::GetFrame(size_t idx, size_t nLang /*= SIZE_T_ERROR*/, REFERENCE_TIME rt /*= -1*/) +{ + if (nLang >= m_langs.size()) { + nLang = m_nLang; + } + CAtlArray& sp = m_langs[nLang].subpos; + + if (idx >= sp.GetCount()) { + return false; + } + + if (m_img.nLang != nLang || m_img.nIdx != idx + || (sp[idx].bAnimated && sp[idx].start + m_img.tCurrent <= rt)) { + size_t packetSize = 0, dataSize = 0; + CAutoVectorPtr buff; + buff.Attach(GetPacket(idx, packetSize, dataSize, nLang)); + if (!buff || packetSize == 0 || dataSize == 0) { + return false; + } + + m_img.start = sp[idx].start; + + bool ret = m_img.Decode(buff, packetSize, dataSize, rt >= 0 ? int(rt - sp[idx].start) : INT_MAX, + m_bCustomPal, m_tridx, m_orgpal, m_cuspal, true); + + m_img.delay = sp[idx].stop - sp[idx].start; + + if (!ret) { + return false; + } + + m_img.nIdx = idx; + m_img.nLang = nLang; + } + + return (m_bOnlyShowForcedSubs ? m_img.bForced : true); +} + +bool CVobSubFile::GetFrameByTimeStamp(__int64 time) +{ + return GetFrame(GetFrameIdxByTimeStamp(time)); +} + +size_t CVobSubFile::GetFrameIdxByTimeStamp(__int64 time) +{ + if (m_nLang >= m_langs.size() || m_langs[m_nLang].subpos.IsEmpty()) { + return SIZE_T_ERROR; + } + + CAtlArray& sp = m_langs[m_nLang].subpos; + + size_t i = 0, j = sp.GetCount() - 1, ret = SIZE_T_ERROR; + + if (time >= sp[j].start) { + return j; + } + + while (i < j) { + size_t mid = (i + j) >> 1; + __int64 midstart = sp[mid].start; + + if (time == midstart) { + ret = mid; + break; + } else if (time < midstart) { + ret = SIZE_T_ERROR; + if (j == mid) { + mid--; + } + j = mid; + } else if (time > midstart) { + ret = mid; + if (i == mid) { + mid++; + } + i = mid; + } + } + + return ret; +} + +// + +STDMETHODIMP CVobSubFile::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = nullptr; + + return + QI(IPersist) + QI(ISubStream) + QI(ISubPicProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CVobSubFile::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + rt /= 10000; + + size_t i = GetFrameIdxByTimeStamp(rt); + + const SubPos* sp = GetFrameInfo(i); + if (!sp) { + return nullptr; + } + + if (rt >= sp->stop) { + if (!GetFrameInfo(++i)) { + return nullptr; + } + } + + return (POSITION)(i + 1); +} + +CString CVobSubFile::GetPath() { + return m_path; +} + +STDMETHODIMP_(POSITION) CVobSubFile::GetNext(POSITION pos) +{ + size_t i = (size_t)pos; + return (GetFrameInfo(i) ? (POSITION)(i + 1) : nullptr); +} + +STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStart(POSITION pos, double fps) +{ + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? 10000i64 * sp->start : 0); +} + +STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStop(POSITION pos, double fps) +{ + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? 10000i64 * sp->stop : 0); +} + +STDMETHODIMP_(bool) CVobSubFile::IsAnimated(POSITION pos) +{ + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? sp->bAnimated : false); +} + +STDMETHODIMP CVobSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + if (spd.bpp != 32) { + return E_INVALIDARG; + } + + rt /= 10000; + + if (!GetFrame(GetFrameIdxByTimeStamp(rt), SIZE_T_ERROR, rt)) { + return E_FAIL; + } + + if (rt >= (m_img.start + m_img.delay)) { + return E_FAIL; + } + + return __super::Render(spd, bbox); +} + +STDMETHODIMP CVobSubFile::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) +{ + relativeTo = VIDEO; + return S_OK; +} + +// IPersist + +STDMETHODIMP CVobSubFile::GetClassID(CLSID* pClassID) +{ + return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; +} + +// ISubStream + +STDMETHODIMP_(int) CVobSubFile::GetStreamCount() +{ + int iStreamCount = 0; + for (const auto& sl : m_langs) { + if (sl.subpos.GetCount()) { + iStreamCount++; + } + } + return iStreamCount; +} + +DWORD LangIDToLCID(WORD langid) +{ + unsigned short id = lang_tbl[find_lang(langid)].id; + CHAR tmp[3]; + tmp[0] = id / 256; + tmp[1] = id & 0xFF; + tmp[2] = 0; + return ISOLang::ISO6391ToLcid(tmp); +} + +STDMETHODIMP CVobSubFile::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID) +{ + for (const auto& sl : m_langs) { + if (sl.subpos.IsEmpty() || iStream-- > 0) { + continue; + } + + if (ppName) { + *ppName = (WCHAR*)CoTaskMemAlloc((sl.alt.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppName, sl.alt.GetLength() + 1, CStringW(sl.alt)); + } + + if (pLCID) { + *pLCID = LangIDToLCID(sl.id); + } + + return S_OK; + } + + return E_FAIL; +} + +STDMETHODIMP_(int) CVobSubFile::GetStream() +{ + int iStream = 0; + + if (m_nLang < m_langs.size()) { + for (size_t i = 0; i < m_nLang; i++) { + if (!m_langs[i].subpos.IsEmpty()) { + iStream++; + } + } + } + + return iStream; +} + +STDMETHODIMP CVobSubFile::SetStream(int iStream) +{ + for (size_t i = 0; i < m_langs.size(); i++) { + const CAtlArray& sp = m_langs[i].subpos; + + if (sp.IsEmpty() || iStream-- > 0) { + continue; + } + + m_nLang = i; + + m_img.Invalidate(); + + break; + } + + return iStream < 0 ? S_OK : E_FAIL; +} + +STDMETHODIMP CVobSubFile::Reload() +{ + if (!PathUtils::Exists(m_title + _T(".idx"))) { + return E_FAIL; + } + return !m_title.IsEmpty() && Open(m_title) ? S_OK : E_FAIL; +} + +// StretchBlt + +static void PixelAtBiLinear(RGBQUAD& c, int x, int y, CVobSubImage& src) +{ + int w = src.rect.Width(), + h = src.rect.Height(); + + int x1 = (x >> 16), y1 = (y >> 16) * w, + x2 = std::min(x1 + 1, w - 1), y2 = std::min(y1 + w, (h - 1) * w); + + RGBQUAD* ptr = src.lpPixels; + + RGBQUAD c11 = ptr[y1 + x1], c12 = ptr[y1 + x2], + c21 = ptr[y2 + x1], c22 = ptr[y2 + x2]; + + __int64 u2 = x & 0xffff, + v2 = y & 0xffff, + u1 = 0x10000 - u2, + v1 = 0x10000 - v2; + + int v1u1 = int(v1 * u1 >> 16) * c11.rgbReserved, + v1u2 = int(v1 * u2 >> 16) * c12.rgbReserved, + v2u1 = int(v2 * u1 >> 16) * c21.rgbReserved, + v2u2 = int(v2 * u2 >> 16) * c22.rgbReserved; + + c.rgbRed = (c11.rgbRed * v1u1 + c12.rgbRed * v1u2 + + c21.rgbRed * v2u1 + c22.rgbRed * v2u2) >> 24; + c.rgbGreen = (c11.rgbGreen * v1u1 + c12.rgbGreen * v1u2 + + c21.rgbGreen * v2u1 + c22.rgbGreen * v2u2) >> 24; + c.rgbBlue = (c11.rgbBlue * v1u1 + c12.rgbBlue * v1u2 + + c21.rgbBlue * v2u1 + c22.rgbBlue * v2u2) >> 24; + c.rgbReserved = BYTE((v1u1 + v1u2 + + v2u1 + v2u2) >> 16); +} + +static void StretchBlt(SubPicDesc& spd, CRect dstrect, CVobSubImage& src) +{ + if (dstrect.IsRectEmpty()) { + return; + } + + if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { + return; + } + + int sw = src.rect.Width(), + sh = src.rect.Height(), + dw = dstrect.Width(), + dh = dstrect.Height(); + + int srcx = 0, + srcy = 0, + srcdx = (sw << 16) / dw >> 1, + srcdy = (sh << 16) / dh >> 1; + + if (dstrect.left < 0) { + srcx = -dstrect.left * (srcdx << 1); + dstrect.left = 0; + } + if (dstrect.top < 0) { + srcy = -dstrect.top * (srcdy << 1); + dstrect.top = 0; + } + if (dstrect.right > spd.w) { + dstrect.right = spd.w; + } + if (dstrect.bottom > spd.h) { + dstrect.bottom = spd.h; + } + + if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { + return; + } + + dw = dstrect.Width(); + dh = dstrect.Height(); + + for (int y = dstrect.top; y < dstrect.bottom; y++, srcy += (srcdy << 1)) { + RGBQUAD* ptr = (RGBQUAD*) & ((BYTE*)spd.bits)[y * spd.pitch] + dstrect.left; + RGBQUAD* endptr = ptr + dw; + + for (int sx = srcx; ptr < endptr; sx += (srcdx << 1), ptr++) { + // PixelAtBiLinear(*ptr, sx, srcy, src); + //// + RGBQUAD cc[4]; + + PixelAtBiLinear(cc[0], sx, srcy, src); + PixelAtBiLinear(cc[1], sx + srcdx, srcy, src); + PixelAtBiLinear(cc[2], sx, srcy + srcdy, src); + PixelAtBiLinear(cc[3], sx + srcdx, srcy + srcdy, src); + + ptr->rgbRed = (cc[0].rgbRed + cc[1].rgbRed + cc[2].rgbRed + cc[3].rgbRed) >> 2; + ptr->rgbGreen = (cc[0].rgbGreen + cc[1].rgbGreen + cc[2].rgbGreen + cc[3].rgbGreen) >> 2; + ptr->rgbBlue = (cc[0].rgbBlue + cc[1].rgbBlue + cc[2].rgbBlue + cc[3].rgbBlue) >> 2; + ptr->rgbReserved = (cc[0].rgbReserved + cc[1].rgbReserved + cc[2].rgbReserved + cc[3].rgbReserved) >> 2; + //// + ptr->rgbRed = ptr->rgbRed * ptr->rgbReserved >> 8; + ptr->rgbGreen = ptr->rgbGreen * ptr->rgbReserved >> 8; + ptr->rgbBlue = ptr->rgbBlue * ptr->rgbReserved >> 8; + ptr->rgbReserved = ~ptr->rgbReserved; + + } + } +} + +// +// CVobSubSettings +// + +void CVobSubSettings::InitSettings() +{ + m_size.SetSize(720, 480); + m_toff = m_x = m_y = 0; + m_org.SetPoint(0, 0); + m_scale_x = m_scale_y = m_alpha = 100; + m_fadein = m_fadeout = 50; + m_iSmooth = 0; + m_bAlign = false; + m_alignhor = m_alignver = 0; + m_bOnlyShowForcedSubs = false; + m_bCustomPal = false; + m_tridx = 0; + ZeroMemory(m_orgpal, sizeof(m_orgpal)); + ZeroMemory(m_cuspal, sizeof(m_cuspal)); +} + +bool CVobSubSettings::GetCustomPal(RGBQUAD* cuspal, int& tridx) +{ + memcpy(cuspal, m_cuspal, sizeof(RGBQUAD) * 4); + tridx = m_tridx; + return m_bCustomPal; +} + +void CVobSubSettings::SetCustomPal(const RGBQUAD* cuspal, int tridx) +{ + memcpy(m_cuspal, cuspal, sizeof(RGBQUAD) * 4); + m_tridx = tridx & 0xf; + for (int i = 0; i < 4; i++) { + m_cuspal[i].rgbReserved = (tridx & (1 << i)) ? 0 : 0xff; + } + m_img.Invalidate(); +} + +void CVobSubSettings::GetDestrect(CRect& r) +{ + int w = MulDiv(m_img.rect.Width(), m_scale_x, 100); + int h = MulDiv(m_img.rect.Height(), m_scale_y, 100); + + if (!m_bAlign) { + r.left = MulDiv(m_img.rect.left, m_scale_x, 100); + r.right = MulDiv(m_img.rect.right, m_scale_x, 100); + r.top = MulDiv(m_img.rect.top, m_scale_y, 100); + r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); + } else { + switch (m_alignhor) { + case 0: + r.left = 0; + r.right = w; + break; // left + case 1: + r.left = -(w >> 1); + r.right = -(w >> 1) + w; + break; // center + case 2: + r.left = -w; + r.right = 0; + break; // right + default: + r.left = MulDiv(m_img.rect.left, m_scale_x, 100); + r.right = MulDiv(m_img.rect.right, m_scale_x, 100); + break; + } + + switch (m_alignver) { + case 0: + r.top = 0; + r.bottom = h; + break; // top + case 1: + r.top = -(h >> 1); + r.bottom = -(h >> 1) + h; + break; // center + case 2: + r.top = -h; + r.bottom = 0; + break; // bottom + default: + r.top = MulDiv(m_img.rect.top, m_scale_y, 100); + r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); + break; + } + } + + r += m_org; +} + +void CVobSubSettings::GetDestrect(CRect& r, int w, int h) +{ + GetDestrect(r); + + r.left = MulDiv(r.left, w, m_size.cx); + r.right = MulDiv(r.right, w, m_size.cx); + r.top = MulDiv(r.top, h, m_size.cy); + r.bottom = MulDiv(r.bottom, h, m_size.cy); +} + +void CVobSubSettings::SetAlignment(bool bAlign, int x, int y, int hor /*= 1*/, int ver /*= 1*/) +{ + m_bAlign = bAlign; + if (bAlign) { + m_org.x = MulDiv(m_size.cx, x, 100); + m_org.y = MulDiv(m_size.cy, y, 100); + m_alignhor = std::min(std::max(hor, 0), 2); + m_alignver = std::min(std::max(ver, 0), 2); + } else { + m_org.x = m_x; + m_org.y = m_y; + } +} + +HRESULT CVobSubSettings::Render(SubPicDesc& spd, RECT& bbox) +{ + CRect r; + GetDestrect(r, spd.w, spd.h); + StretchBlt(spd, r, m_img); + /* + CRenderedTextSubtitle rts(nullptr); + rts.CreateDefaultStyle(DEFAULT_CHARSET); + rts.m_storageRes.SetSize(m_size.cx, m_size.cy); + CStringW assstr; + m_img.Polygonize(assstr, false); + REFERENCE_TIME rtStart = 10000i64*m_img.start, rtStop = 10000i64*(m_img.start+m_img.delay); + rts.Add(assstr, true, rtStart, rtStop); + rts.Render(spd, (rtStart+rtStop)/2, 25, r); + */ + r &= CRect(CPoint(0, 0), CSize(spd.w, spd.h)); + bbox = r; + return !r.IsRectEmpty() ? S_OK : S_FALSE; +} + +///////////////////////////////////////////////////////// + +static bool CompressFile(CString fn) +{ + BOOL b = FALSE; + + HANDLE h = CreateFile(fn, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); + if (h != INVALID_HANDLE_VALUE) { + unsigned short us = COMPRESSION_FORMAT_DEFAULT; + DWORD nBytesReturned; + b = DeviceIoControl(h, FSCTL_SET_COMPRESSION, (LPVOID)&us, 2, nullptr, 0, (LPDWORD)&nBytesReturned, nullptr); + CloseHandle(h); + } + + return !!b; +} + +bool CVobSubFile::SaveVobSub(CString fn, int delay) +{ + if (!WriteIdx(fn + _T(".idx"), delay) || !WriteSub(fn + _T(".sub"))) { + return false; + } + m_path = fn + _T(".idx"); + return true; +} + +bool CVobSubFile::SaveWinSubMux(CString fn, int delay) +{ + TrimExtension(fn); + + CStdioFile f; + if (!f.Open(fn + _T(".sub"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } + + m_img.Invalidate(); + + CAutoVectorPtr p4bpp; + if (!p4bpp.Allocate(720 * 576 / 2)) { + return false; + } + + CAtlArray& sp = m_langs[m_nLang].subpos; + for (size_t i = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } + + int pal[4] = {0, 1, 2, 3}; + + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { + j &= 3; + memset(p4bpp, (j << 4) | j, 720 * 576 / 2); + pal[j] ^= pal[0], pal[0] ^= pal[j], pal[j] ^= pal[0]; + break; + } + } + + int tr[4] = {m_img.pal[pal[0]].tr, m_img.pal[pal[1]].tr, m_img.pal[pal[2]].tr, m_img.pal[pal[3]].tr}; + + DWORD uipal[4 + 12]; + + if (!m_bCustomPal) { + uipal[0] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[0]].pal]); + uipal[1] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[1]].pal]); + uipal[2] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[2]].pal]); + uipal[3] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[3]].pal]); + } else { + uipal[0] = *((DWORD*)&m_img.cuspal[pal[0]]) & 0xffffff; + uipal[1] = *((DWORD*)&m_img.cuspal[pal[1]]) & 0xffffff; + uipal[2] = *((DWORD*)&m_img.cuspal[pal[2]]) & 0xffffff; + uipal[3] = *((DWORD*)&m_img.cuspal[pal[3]]) & 0xffffff; + } + + CAtlMap palmap; + palmap[uipal[0]] = 0; + palmap[uipal[1]] = 1; + palmap[uipal[2]] = 2; + palmap[uipal[3]] = 3; + + uipal[0] = 0xff; // blue background + + int w = m_img.rect.Width() - 2; + int h = m_img.rect.Height() - 2; + int pitch = (((w + 1) >> 1) + 3) & ~3; + + for (ptrdiff_t y = 0; y < h; y++) { + DWORD* p = (DWORD*)&m_img.lpPixels[(y + 1) * (w + 2) + 1]; + + for (ptrdiff_t x = 0; x < w; x++, p++) { + BYTE c = 0; + + if (*p & 0xff000000) { + DWORD uic = *p & 0xffffff; + palmap.Lookup(uic, c); + } + + BYTE& c4bpp = p4bpp[(h - y - 1) * pitch + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); + } + } + + int t1 = (int)m_img.start + delay; + int t2 = t1 + (int)m_img.delay /*+ (m_size.cy==480?(1000/29.97+1):(1000/25))*/; + + ASSERT(t2 > t1); + + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } + + CString bmpfn; + bmpfn.Format(_T("%s_%06Iu.bmp"), fn.GetString(), i + 1); + + CString str; + str.Format(_T("%s\t%02d:%02d:%02d:%02d %02d:%02d:%02d:%02d\t%03d %03d %03d %03d %d %d %d %d\n"), + bmpfn.GetString(), + t1 / 1000 / 60 / 60, (t1 / 1000 / 60) % 60, (t1 / 1000) % 60, (t1 % 1000) / 10, + t2 / 1000 / 60 / 60, (t2 / 1000 / 60) % 60, (t2 / 1000) % 60, (t2 % 1000) / 10, + m_img.rect.Width(), m_img.rect.Height(), m_img.rect.left, m_img.rect.top, + (tr[0] << 4) | tr[0], (tr[1] << 4) | tr[1], (tr[2] << 4) | tr[2], (tr[3] << 4) | tr[3]); + f.WriteString(str); + + BITMAPFILEHEADER fhdr = { + 0x4d42, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + pitch * h, + 0, 0, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + }; + + BITMAPINFOHEADER ihdr = { + sizeof(BITMAPINFOHEADER), + w, h, 1, 4, 0, + 0, + pitch * h, 0, + 16, 4 + }; + + CFile bmp; + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { + bmp.Write(&fhdr, sizeof(fhdr)); + bmp.Write(&ihdr, sizeof(ihdr)); + bmp.Write(uipal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, pitch * h); + bmp.Close(); + + CompressFile(bmpfn); + } + } + + m_path = fn + _T(".sub"); + + return true; +} + +bool CVobSubFile::SaveScenarist(CString fn, int delay) +{ + TrimExtension(fn); + + CStdioFile f; + if (!f.Open(fn + _T(".sst"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } + + m_img.Invalidate(); + + fn.Replace('\\', '/'); + CString title = fn.Mid(fn.ReverseFind('/') + 1); + + TCHAR buff[MAX_PATH], * pFilePart = buff; + if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { + return false; + } + + CString fullpath = CString(buff).Left(int(pFilePart - buff)); + fullpath.TrimRight(_T("\\/")); + if (fullpath.IsEmpty()) { + return false; + } + + CString str, str2; + str += _T("st_format\t2\n"); + str += _T("Display_Start\t%s\n"); + str += _T("TV_Type\t\t%s\n"); + str += _T("Tape_Type\tNON_DROP\n"); + str += _T("Pixel_Area\t(0 %d)\n"); + str += _T("Directory\t%s\n"); + str += _T("Subtitle\t%s\n"); + str += _T("Display_Area\t(0 2 719 %d)\n"); + str += _T("Contrast\t(15 15 15 0)\n"); + str += _T("\n"); + str += _T("PA\t(0 0 255 - - - )\n"); + str += _T("E1\t(255 0 0 - - - )\n"); + str += _T("E2\t(0 0 0 - - - )\n"); + str += _T("BG\t(255 255 255 - - - )\n"); + str += _T("\n"); + str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); + str2.Format(str, + !m_bOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), + m_size.cy == 480 ? _T("NTSC") : _T("PAL"), + m_size.cy - 3, + fullpath.GetString(), + title.GetString(), + m_size.cy == 480 ? 479 : 574); + + f.WriteString(str2); + + f.Flush(); + + RGBQUAD pal[16] = { + {255, 0, 0, 0}, + {0, 0, 255, 0}, + {0, 0, 0, 0}, + {255, 255, 255, 0}, + {0, 255, 0, 0}, + {255, 0, 255, 0}, + {0, 255, 255, 0}, + {125, 125, 0, 0}, + {125, 125, 125, 0}, + {225, 225, 225, 0}, + {0, 0, 125, 0}, + {0, 125, 0, 0}, + {125, 0, 0, 0}, + {255, 0, 222, 0}, + {0, 125, 222, 0}, + {125, 0, 125, 0}, + }; + + BITMAPFILEHEADER fhdr = { + 0x4d42, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), + 0, 0, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + }; + + BITMAPINFOHEADER ihdr = { + sizeof(BITMAPINFOHEADER), + 720, m_size.cy - 2, 1, 4, 0, + DWORD(360 * (m_size.cy - 2)), + 0, 0, + 16, 4 + }; + + bool bCustomPal = m_bCustomPal; + m_bCustomPal = true; + RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; + memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); + memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); + + CAutoVectorPtr p4bpp; + if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { + return false; + } + + BYTE colormap[16]; + + for (size_t i = 0; i < 16; i++) { + BYTE idx = 0; + int maxdif = 255 * 255 * 3 + 1; + + for (size_t j = 0; j < 16 && maxdif; j++) { + int rdif = pal[j].rgbRed - m_orgpal[i].rgbRed; + int gdif = pal[j].rgbGreen - m_orgpal[i].rgbGreen; + int bdif = pal[j].rgbBlue - m_orgpal[i].rgbBlue; + + int dif = rdif * rdif + gdif * gdif + bdif * bdif; + if (dif < maxdif) { + maxdif = dif; + idx = (BYTE)j; + } + } + + colormap[i] = idx + 1; + } + + int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; + + CAtlArray& sp = m_langs[m_nLang].subpos; + for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } + + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { + j &= 3; + memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); + break; + } + } + + for (ptrdiff_t y = std::max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { + ASSERT(m_size.cy - y - 1 >= 0); + if (m_size.cy - y - 1 < 0) { + break; + } + + DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; + + for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { + DWORD rgb = *p & 0xffffff; + BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; + BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); + } + } + + CString bmpfn; + bmpfn.Format(_T("%s_%04Iu.bmp"), fn.GetString(), i + 1); + title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); + + // E1, E2, P, Bg + int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]}; + c[0] ^= c[1], c[1] ^= c[0], c[0] ^= c[1]; + + if (memcmp(pc, c, sizeof(c))) { + memcpy(pc, c, sizeof(c)); + str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); + f.WriteString(str); + } + + // E1, E2, P, Bg + int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; + a[0] ^= a[1], a[1] ^= a[0], a[0] ^= a[1]; + + if (memcmp(pa, a, sizeof(a))) { + memcpy(pa, a, sizeof(a)); + str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); + f.WriteString(str); + } + + int t1 = (int)sp[i].start + delay; + int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; + int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); + + int t2 = (int)sp[i].stop + delay; + int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; + int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); + + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } + + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { + f2++; + if (f2 == (m_size.cy == 480 ? 30 : 25)) { + f2 = 0; + s2++; + if (s2 == 60) { + s2 = 0; + m2++; + if (m2 == 60) { + m2 = 0; + h2++; + } + } + } + } + + if (i + 1 < sp.GetCount()) { + int t3 = (int)sp[i + 1].start + delay; + int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; + int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); + + if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { + f2--; + if (f2 == -1) { + f2 = (m_size.cy == 480 ? 29 : 24); + s2--; + if (s2 == -1) { + s2 = 59; + m2--; + if (m2 == -1) { + m2 = 59; + if (h2 > 0) { + h2--; + } + } + } + } + } + } + + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { + continue; + } + + str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), + ++k, + h1, m1, s1, f1, + h2, m2, s2, f2, + title.GetString()); + f.WriteString(str); + + CFile bmp; + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::modeRead | CFile::typeBinary)) { + bmp.Write(&fhdr, sizeof(fhdr)); + bmp.Write(&ihdr, sizeof(ihdr)); + bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, 360 * (m_size.cy - 2)); + bmp.Close(); + + CompressFile(bmpfn); + } + } + + m_bCustomPal = bCustomPal; + memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); + + m_path = fn + _T(".sst"); + + return true; +} + +bool CVobSubFile::SaveMaestro(CString fn, int delay) +{ + TrimExtension(fn); + + CStdioFile f; + if (!f.Open(fn + _T(".son"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } + + m_img.Invalidate(); + + fn.Replace('\\', '/'); + CString title = fn.Mid(fn.ReverseFind('/') + 1); + + TCHAR buff[MAX_PATH], * pFilePart = buff; + if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { + return false; + } + + CString fullpath = CString(buff).Left(int(pFilePart - buff)); + fullpath.TrimRight(_T("\\/")); + if (fullpath.IsEmpty()) { + return false; + } + + CString str, str2; + str += _T("st_format\t2\n"); + str += _T("Display_Start\t%s\n"); + str += _T("TV_Type\t\t%s\n"); + str += _T("Tape_Type\tNON_DROP\n"); + str += _T("Pixel_Area\t(0 %d)\n"); + str += _T("Directory\t%s\n"); + str += _T("Subtitle\t%s\n"); + str += _T("Display_Area\t(0 2 719 %d)\n"); + str += _T("Contrast\t(15 15 15 0)\n"); + str += _T("\n"); + str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); + str2.Format(str, + !m_bOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), + m_size.cy == 480 ? _T("NTSC") : _T("PAL"), + m_size.cy - 3, + fullpath.GetString(), + title.GetString(), + m_size.cy == 480 ? 479 : 574); + + f.WriteString(str2); + + f.Flush(); + + BITMAPFILEHEADER fhdr = { + 0x4d42, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), + 0, 0, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + }; + + BITMAPINFOHEADER ihdr = { + sizeof(BITMAPINFOHEADER), + 720, m_size.cy - 2, 1, 4, 0, + DWORD(360 * (m_size.cy - 2)), + 0, 0, + 16, 4 + }; + + bool bCustomPal = m_bCustomPal; + m_bCustomPal = true; + RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; + memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); + memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); + + CAutoVectorPtr p4bpp; + if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { + return false; + } + + BYTE colormap[16]; + for (BYTE i = 0; i < 16; i++) { + colormap[i] = i; + } + + CFile spf; + if (spf.Open(fn + _T(".spf"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { + for (size_t i = 0; i < 16; i++) { + COLORREF c = (m_orgpal[i].rgbBlue << 16) | (m_orgpal[i].rgbGreen << 8) | m_orgpal[i].rgbRed; + spf.Write(&c, sizeof(COLORREF)); + } + + spf.Close(); + } + + int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; + + CAtlArray& sp = m_langs[m_nLang].subpos; + for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } + + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { + j &= 3; + memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); + break; + } + } + + for (ptrdiff_t y = std::max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { + ASSERT(m_size.cy - y - 1 >= 0); + if (m_size.cy - y - 1 < 0) { + break; + } + + DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; + + for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { + DWORD rgb = *p & 0xffffff; + BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; + BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); + } + } + + CString bmpfn; + bmpfn.Format(_T("%s_%04Iu.bmp"), fn.GetString(), i + 1); + title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); + + // E1, E2, P, Bg + int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]}; + + if (memcmp(pc, c, sizeof(c))) { + memcpy(pc, c, sizeof(c)); + str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); + f.WriteString(str); + } + + // E1, E2, P, Bg + int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; + + if (memcmp(pa, a, sizeof(a))) { + memcpy(pa, a, sizeof(a)); + str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); + f.WriteString(str); + } + + int t1 = (int)sp[i].start + delay; + int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; + int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); + + int t2 = (int)sp[i].stop + delay; + int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; + int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); + + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } + + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { + f2++; + if (f2 == (m_size.cy == 480 ? 30 : 25)) { + f2 = 0; + s2++; + if (s2 == 60) { + s2 = 0; + m2++; + if (m2 == 60) { + m2 = 0; + h2++; + } + } + } + } + + if (i < sp.GetCount() - 1) { + int t3 = (int)sp[i + 1].start + delay; + int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; + int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); + + if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { + f2--; + if (f2 == -1) { + f2 = (m_size.cy == 480 ? 29 : 24); + s2--; + if (s2 == -1) { + s2 = 59; + m2--; + if (m2 == -1) { + m2 = 59; + if (h2 > 0) { + h2--; + } + } + } + } + } + } + + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { + continue; + } + + str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), + ++k, + h1, m1, s1, f1, + h2, m2, s2, f2, + title.GetString()); + f.WriteString(str); + + CFile bmp; + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { + bmp.Write(&fhdr, sizeof(fhdr)); + bmp.Write(&ihdr, sizeof(ihdr)); + bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, 360 * (m_size.cy - 2)); + bmp.Close(); + + CompressFile(bmpfn); + } + } + + m_bCustomPal = bCustomPal; + memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); + + m_path = fn + _T(".son"); + + return true; +} + +// +// CVobSubStream +// + +CVobSubStream::CVobSubStream(CCritSec* pLock) + : CSubPicProviderImpl(pLock) +{ +} + +CVobSubStream::~CVobSubStream() +{ +} + +void CVobSubStream::Open(CString name, BYTE* pData, int len) +{ + CAutoLock cAutoLock(&m_csSubPics); + + m_name = name; + + CAtlList lines; + Explode(CString(CStringA((CHAR*)pData, len)), lines, _T('\n')); + while (lines.GetCount()) { + CAtlList sl; + Explode(lines.RemoveHead(), sl, ':', 2); + if (sl.GetCount() != 2) { + continue; + } + CString key = sl.GetHead(); + CString value = sl.GetTail(); + if (key == _T("size")) { + _stscanf_s(value, _T("%dx %d"), &m_size.cx, &m_size.cy); + } else if (key == _T("org")) { + _stscanf_s(value, _T("%d, %d"), &m_org.x, &m_org.y); + } else if (key == _T("scale")) { + _stscanf_s(value, _T("%d%%, %d%%"), &m_scale_x, &m_scale_y); + } else if (key == _T("alpha")) { + _stscanf_s(value, _T("%d%%"), &m_alpha); + } else if (key == _T("smooth")) + m_iSmooth = + value == _T("0") || value == _T("OFF") ? 0 : + value == _T("1") || value == _T("ON") ? 1 : + value == _T("2") || value == _T("OLD") ? 2 : + 0; + else if (key == _T("align")) { + Explode(value, sl, ' '); + if (sl.GetCount() == 4) { + sl.RemoveAt(sl.FindIndex(1)); + } + if (sl.GetCount() == 3) { + m_bAlign = sl.RemoveHead() == _T("ON"); + CString hor = sl.GetHead(), ver = sl.GetTail(); + m_alignhor = hor == _T("LEFT") ? 0 : hor == _T("CENTER") ? 1 : hor == _T("RIGHT") ? 2 : 1; + m_alignver = ver == _T("TOP") ? 0 : ver == _T("CENTER") ? 1 : /*ver == _T("BOTTOM") ? 2 :*/ 2; + } + } else if (key == _T("fade in/out")) { + _stscanf_s(value, _T("%d, %d"), &m_fadein, &m_fadeout); + } else if (key == _T("time offset")) { + m_toff = _tcstol(value, nullptr, 10); + } else if (key == _T("forced subs")) { + m_bOnlyShowForcedSubs = value == _T("1") || value == _T("ON"); + } else if (key == _T("palette")) { + Explode(value, sl, ',', 16); + for (size_t i = 0; i < 16 && sl.GetCount(); i++) { + *(DWORD*)&m_orgpal[i] = _tcstol(sl.RemoveHead(), nullptr, 16); + } + } else if (key == _T("custom colors")) { + m_bCustomPal = Explode(value, sl, ',', 3) == _T("ON"); + if (sl.GetCount() == 3) { + sl.RemoveHead(); + CAtlList tridx, colors; + + Explode(sl.RemoveHead(), tridx, ':', 2); + int _tridx = 1; + if (tridx.RemoveHead() == _T("tridx")) { + TCHAR tr[4]; + _stscanf_s(tridx.RemoveHead(), _T("%c%c%c%c"), &tr[0], 1, &tr[1], 1, &tr[2], 1, &tr[3], 1); + for (size_t i = 0; i < 4; i++) { + _tridx |= ((tr[i] == '1') ? 1 : 0) << i; + } + } + + Explode(sl.RemoveHead(), colors, ':', 2); + if (colors.RemoveHead() == _T("colors")) { + Explode(colors.RemoveHead(), colors, ',', 4); + + RGBQUAD pal[4]; + for (size_t i = 0; i < 4 && colors.GetCount(); i++) { + *(DWORD*)&pal[i] = _tcstol(colors.RemoveHead(), nullptr, 16); + } + + SetCustomPal(pal, _tridx); + } + } + } + } +} + +void CVobSubStream::Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len) +{ + if (len <= 4 || ((pData[0] << 8) | pData[1]) != len) { + return; + } + + CVobSubImage vsi; + vsi.GetPacketInfo(pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3]); + + CAutoPtr p(DEBUG_NEW SubPic()); + p->tStart = tStart; + p->tStop = vsi.delay > 0 ? (tStart + 10000i64 * vsi.delay) : tStop; + p->bAnimated = vsi.bAnimated; + p->pData.SetCount(len); + memcpy(p->pData.GetData(), pData, p->pData.GetCount()); + + CAutoLock cAutoLock(&m_csSubPics); + while (m_subpics.GetCount() && m_subpics.GetTail()->tStart >= tStart) { + m_subpics.RemoveTail(); + m_img.nIdx = SIZE_T_ERROR; + } + + // We can only render one subpicture at a time, thus if there is overlap + // we have to fix it. tStop = tStart seems to work. + if (m_subpics.GetCount() && m_subpics.GetTail()->tStop > p->tStart) { + TRACE(_T("[CVobSubStream::Add] Vobsub timestamp overlap detected! ") + _T("Subpicture #%d, StopTime %I64d > %I64d (Next StartTime), making them equal!\n"), + m_subpics.GetCount(), m_subpics.GetTail()->tStop, p->tStart); + m_subpics.GetTail()->tStop = p->tStart; + } + + m_subpics.AddTail(p); +} + +void CVobSubStream::RemoveAll() +{ + CAutoLock cAutoLock(&m_csSubPics); + m_subpics.RemoveAll(); + m_img.nIdx = SIZE_T_ERROR; +} + +STDMETHODIMP CVobSubStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = nullptr; + + return + QI(IPersist) + QI(ISubStream) + QI(ISubPicProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CVobSubStream::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + CAutoLock cAutoLock(&m_csSubPics); + POSITION pos = m_subpics.GetTailPosition(); + for (; pos; m_subpics.GetPrev(pos)) { + SubPic* sp = m_subpics.GetAt(pos); + if (sp->tStart <= rt) { + if (sp->tStop <= rt) { + m_subpics.GetNext(pos); + } + break; + } + } + return pos; +} + +STDMETHODIMP_(POSITION) CVobSubStream::GetNext(POSITION pos) +{ + CAutoLock cAutoLock(&m_csSubPics); + m_subpics.GetNext(pos); + return pos; +} + +STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStart(POSITION pos, double fps) +{ + CAutoLock cAutoLock(&m_csSubPics); + return m_subpics.GetAt(pos)->tStart; +} + +STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStop(POSITION pos, double fps) +{ + CAutoLock cAutoLock(&m_csSubPics); + return m_subpics.GetAt(pos)->tStop; +} + +STDMETHODIMP_(bool) CVobSubStream::IsAnimated(POSITION pos) +{ + CAutoLock cAutoLock(&m_csSubPics); + return m_subpics.GetAt(pos)->bAnimated; +} + +STDMETHODIMP CVobSubStream::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + if (spd.bpp != 32) { + return E_INVALIDARG; + } + + for (POSITION pos = m_subpics.GetTailPosition(); pos; m_subpics.GetPrev(pos)) { + SubPic* sp = m_subpics.GetAt(pos); + if (sp->tStart <= rt && rt < sp->tStop) { + if (m_img.nIdx != (size_t)pos || (sp->bAnimated && sp->tStart + m_img.tCurrent * 10000i64 <= rt)) { + BYTE* pData = sp->pData.GetData(); + m_img.Decode( + pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3], int((rt - sp->tStart) / 10000i64), + m_bCustomPal, m_tridx, m_orgpal, m_cuspal, true); + m_img.nIdx = (size_t)pos; + } + + return __super::Render(spd, bbox); + } + } + + return E_FAIL; +} + +STDMETHODIMP CVobSubStream::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) +{ + relativeTo = VIDEO; + return S_OK; +} + +// IPersist + +STDMETHODIMP CVobSubStream::GetClassID(CLSID* pClassID) +{ + return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; +} + +// ISubStream + +STDMETHODIMP_(int) CVobSubStream::GetStreamCount() +{ + return 1; +} + +STDMETHODIMP CVobSubStream::GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID) +{ + CAutoLock cAutoLock(&m_csSubPics); + + if (ppName) { + *ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppName)) { + return E_OUTOFMEMORY; + } + wcscpy_s(*ppName, m_name.GetLength() + 1, CStringW(m_name)); + } + + if (pLCID) { + *pLCID = 0; // TODO + } + + return S_OK; +} + +STDMETHODIMP_(int) CVobSubStream::GetStream() +{ + return 0; +} + +STDMETHODIMP CVobSubStream::SetStream(int iStream) +{ + return iStream == 0 ? S_OK : E_FAIL; +} diff --git a/src/Subtitles/VobSubFile.h b/src/Subtitles/VobSubFile.h index 51d18fde508..97dc6e0d954 100644 --- a/src/Subtitles/VobSubFile.h +++ b/src/Subtitles/VobSubFile.h @@ -1,219 +1,219 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#pragma once - -#include -#include "VobSubImage.h" -#include "../SubPic/SubPicProviderImpl.h" - -#define VOBSUBIDXVER 7 - -#define ReadBEb(var) \ - f.Read(&((BYTE*)&var)[0], 1); - -#define ReadBEw(var) \ - f.Read(&((BYTE*)&var)[1], 1); \ - f.Read(&((BYTE*)&var)[0], 1); - -#define ReadBEdw(var) \ - f.Read(&((BYTE*)&var)[3], 1); \ - f.Read(&((BYTE*)&var)[2], 1); \ - f.Read(&((BYTE*)&var)[1], 1); \ - f.Read(&((BYTE*)&var)[0], 1); - -extern CString FindLangFromId(WORD id); - -class CVobSubSettings -{ -protected: - HRESULT Render(SubPicDesc& spd, RECT& bbox); - -public: - CSize m_size; - int m_x, m_y; - CPoint m_org; - int m_scale_x, m_scale_y; // % (don't set it to unsigned because as a side effect it will mess up negative coordinates in GetDestrect()) - int m_alpha; // % - int m_iSmooth; // 0: OFF, 1: ON, 2: OLD (means no filtering at all) - int m_fadein, m_fadeout; // ms - bool m_bAlign; - int m_alignhor, m_alignver; // 0: left/top, 1: center, 2: right/bottom - unsigned int m_toff; // ms - bool m_bOnlyShowForcedSubs; - bool m_bCustomPal; - int m_tridx; - RGBQUAD m_orgpal[16], m_cuspal[4]; - - CVobSubImage m_img; - - CVobSubSettings() { InitSettings(); } - void InitSettings(); - - bool GetCustomPal(RGBQUAD* cuspal, int& tridx); - void SetCustomPal(const RGBQUAD* cuspal, int tridx); - - void GetDestrect(CRect& r); // destrect of m_img, considering the current alignment mode - void GetDestrect(CRect& r, int w, int h); // this will scale it to the frame size of (w, h) - - void SetAlignment(bool bAlign, int x, int y, int hor = 1, int ver = 1); -}; - -class __declspec(uuid("998D4C9A-460F-4de6-BDCD-35AB24F94ADF")) - CVobSubFile : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl -{ -public: - struct SubPos { - __int64 filepos = 0i64; - __int64 start = 0i64; - __int64 stop = 0i64; - bool bForced = false; - bool bAnimated = false; - char vobid = 0; - char cellid = 0; - __int64 celltimestamp = 0i64; - bool bValid = false; - - bool operator <(const SubPos& rhs) const { - return start < rhs.start; - } - }; - - struct SubLang { - WORD id = 0; - CString name, alt; - CAtlArray subpos; - }; - -protected: - CString m_title; - CString m_path; - - void TrimExtension(CString& fn); - bool ReadIdx(CString fn, int& ver), ReadSub(CString fn), ReadRar(CString fn), ReadIfo(CString fn); - bool WriteIdx(CString fn, int delay), WriteSub(CString fn); - - CMemFile m_sub; - - BYTE* GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang = SIZE_T_ERROR); - const SubPos* GetFrameInfo(size_t idx, size_t nLang = SIZE_T_ERROR) const; - bool GetFrame(size_t idx, size_t nLang = SIZE_T_ERROR, REFERENCE_TIME rt = -1); - bool GetFrameByTimeStamp(__int64 time); - size_t GetFrameIdxByTimeStamp(__int64 time); - - bool SaveVobSub(CString fn, int delay); - bool SaveWinSubMux(CString fn, int delay); - bool SaveScenarist(CString fn, int delay); - bool SaveMaestro(CString fn, int delay); - -public: - size_t m_nLang; - std::array m_langs; - - CVobSubFile(CCritSec* pLock); - virtual ~CVobSubFile(); - - bool Copy(CVobSubFile& vsf); - CString GetPath(); - - enum SubFormat { - None, - VobSub, - WinSubMux, - Scenarist, - Maestro - }; - - bool Open(CString fn); - bool Save(CString fn, int delay = 0, SubFormat sf = VobSub); - void Close(); - - CString GetTitle() { return m_title; } - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); - - // IPersist - STDMETHODIMP GetClassID(CLSID* pClassID); - - // ISubStream - STDMETHODIMP_(int) GetStreamCount(); - STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); - STDMETHODIMP_(int) GetStream(); - STDMETHODIMP SetStream(int iStream); - STDMETHODIMP Reload(); - STDMETHODIMP SetSourceTargetInfo(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) { return E_NOTIMPL; }; -}; - -class __declspec(uuid("D7FBFB45-2D13-494F-9B3D-FFC9557D5C45")) - CVobSubStream : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl -{ - CString m_name; - - CCritSec m_csSubPics; - struct SubPic { - REFERENCE_TIME tStart, tStop; - bool bAnimated; - CAtlArray pData; - }; - CAutoPtrList m_subpics; - -public: - CVobSubStream(CCritSec* pLock); - virtual ~CVobSubStream(); - - void Open(CString name, BYTE* pData, int len); - - void Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len); - void RemoveAll(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); - - // IPersist - STDMETHODIMP GetClassID(CLSID* pClassID); - - // ISubStream - STDMETHODIMP_(int) GetStreamCount(); - STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); - STDMETHODIMP_(int) GetStream(); - STDMETHODIMP SetStream(int iStream); - STDMETHODIMP Reload() { return E_NOTIMPL; } - STDMETHODIMP SetSourceTargetInfo(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) { return E_NOTIMPL; } -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#pragma once + +#include +#include "VobSubImage.h" +#include "../SubPic/SubPicProviderImpl.h" + +#define VOBSUBIDXVER 7 + +#define ReadBEb(var) \ + f.Read(&((BYTE*)&var)[0], 1); + +#define ReadBEw(var) \ + f.Read(&((BYTE*)&var)[1], 1); \ + f.Read(&((BYTE*)&var)[0], 1); + +#define ReadBEdw(var) \ + f.Read(&((BYTE*)&var)[3], 1); \ + f.Read(&((BYTE*)&var)[2], 1); \ + f.Read(&((BYTE*)&var)[1], 1); \ + f.Read(&((BYTE*)&var)[0], 1); + +extern CString FindLangFromId(WORD id); + +class CVobSubSettings +{ +protected: + HRESULT Render(SubPicDesc& spd, RECT& bbox); + +public: + CSize m_size; + int m_x, m_y; + CPoint m_org; + int m_scale_x, m_scale_y; // % (don't set it to unsigned because as a side effect it will mess up negative coordinates in GetDestrect()) + int m_alpha; // % + int m_iSmooth; // 0: OFF, 1: ON, 2: OLD (means no filtering at all) + int m_fadein, m_fadeout; // ms + bool m_bAlign; + int m_alignhor, m_alignver; // 0: left/top, 1: center, 2: right/bottom + unsigned int m_toff; // ms + bool m_bOnlyShowForcedSubs; + bool m_bCustomPal; + int m_tridx; + RGBQUAD m_orgpal[16], m_cuspal[4]; + + CVobSubImage m_img; + + CVobSubSettings() { InitSettings(); } + void InitSettings(); + + bool GetCustomPal(RGBQUAD* cuspal, int& tridx); + void SetCustomPal(const RGBQUAD* cuspal, int tridx); + + void GetDestrect(CRect& r); // destrect of m_img, considering the current alignment mode + void GetDestrect(CRect& r, int w, int h); // this will scale it to the frame size of (w, h) + + void SetAlignment(bool bAlign, int x, int y, int hor = 1, int ver = 1); +}; + +class __declspec(uuid("998D4C9A-460F-4de6-BDCD-35AB24F94ADF")) + CVobSubFile : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl +{ +public: + struct SubPos { + __int64 filepos = 0i64; + __int64 start = 0i64; + __int64 stop = 0i64; + bool bForced = false; + bool bAnimated = false; + char vobid = 0; + char cellid = 0; + __int64 celltimestamp = 0i64; + bool bValid = false; + + bool operator <(const SubPos& rhs) const { + return start < rhs.start; + } + }; + + struct SubLang { + WORD id = 0; + CString name, alt; + CAtlArray subpos; + }; + +protected: + CString m_title; + CString m_path; + + void TrimExtension(CString& fn); + bool ReadIdx(CString fn, int& ver), ReadSub(CString fn), ReadRar(CString fn), ReadIfo(CString fn); + bool WriteIdx(CString fn, int delay), WriteSub(CString fn); + + CMemFile m_sub; + + BYTE* GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang = SIZE_T_ERROR); + const SubPos* GetFrameInfo(size_t idx, size_t nLang = SIZE_T_ERROR) const; + bool GetFrame(size_t idx, size_t nLang = SIZE_T_ERROR, REFERENCE_TIME rt = -1); + bool GetFrameByTimeStamp(__int64 time); + size_t GetFrameIdxByTimeStamp(__int64 time); + + bool SaveVobSub(CString fn, int delay); + bool SaveWinSubMux(CString fn, int delay); + bool SaveScenarist(CString fn, int delay); + bool SaveMaestro(CString fn, int delay); + +public: + size_t m_nLang; + std::array m_langs; + + CVobSubFile(CCritSec* pLock); + virtual ~CVobSubFile(); + + bool Copy(CVobSubFile& vsf); + CString GetPath(); + + enum SubFormat { + None, + VobSub, + WinSubMux, + Scenarist, + Maestro + }; + + bool Open(CString fn); + bool Save(CString fn, int delay = 0, SubFormat sf = VobSub); + void Close(); + + CString GetTitle() { return m_title; } + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); + + // IPersist + STDMETHODIMP GetClassID(CLSID* pClassID); + + // ISubStream + STDMETHODIMP_(int) GetStreamCount(); + STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); + STDMETHODIMP_(int) GetStream(); + STDMETHODIMP SetStream(int iStream); + STDMETHODIMP Reload(); + STDMETHODIMP SetSourceTargetInfo(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) { return E_NOTIMPL; }; +}; + +class __declspec(uuid("D7FBFB45-2D13-494F-9B3D-FFC9557D5C45")) + CVobSubStream : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl +{ + CString m_name; + + CCritSec m_csSubPics; + struct SubPic { + REFERENCE_TIME tStart, tStop; + bool bAnimated; + CAtlArray pData; + }; + CAutoPtrList m_subpics; + +public: + CVobSubStream(CCritSec* pLock); + virtual ~CVobSubStream(); + + void Open(CString name, BYTE* pData, int len); + + void Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len); + void RemoveAll(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); + + // IPersist + STDMETHODIMP GetClassID(CLSID* pClassID); + + // ISubStream + STDMETHODIMP_(int) GetStreamCount(); + STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); + STDMETHODIMP_(int) GetStream(); + STDMETHODIMP SetStream(int iStream); + STDMETHODIMP Reload() { return E_NOTIMPL; } + STDMETHODIMP SetSourceTargetInfo(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) { return E_NOTIMPL; } +}; diff --git a/src/Subtitles/VobSubFileRipper.cpp b/src/Subtitles/VobSubFileRipper.cpp index 160670b3cda..4ee4a837ce7 100644 --- a/src/Subtitles/VobSubFileRipper.cpp +++ b/src/Subtitles/VobSubFileRipper.cpp @@ -1,1184 +1,1184 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "VobSubFile.h" -#include "VobSubFileRipper.h" -#include "../DeCSS/VobDec.h" -#include "CCDecoder.h" - -// -// CVobSubFileRipper -// - -CVobSubFileRipper::CVobSubFileRipper() - : CVobSubFile(nullptr) - , m_bThreadActive(false) - , m_bBreakThread(false) - , m_bIndexing(false) -{ - m_rd.Reset(); - CAMThread::Create(); -} - -CVobSubFileRipper::~CVobSubFileRipper() -{ - CAMThread::CallWorker(CMD_EXIT); - CAMThread::Close(); -} - -STDMETHODIMP CVobSubFileRipper::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IVSFRipper) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CVobSubFileRipper::Log(log_t type, LPCTSTR lpszFormat, ...) -{ - CAutoLock cAutoLock(&m_csCallback); - if (!m_pCallback) { - return; - } - - TCHAR buff[1024]; - - va_list args; - va_start(args, lpszFormat); - _vstprintf_s(buff, _countof(buff), lpszFormat, args); - va_end(args); - - CString msg; - switch (type) { - default: - case LOG_INFO: - msg = _T(""); - break; - case LOG_WARNING: - msg = _T("WARNING: "); - break; - case LOG_ERROR: - msg = _T("ERROR: "); - break; - } - - msg += buff; - - m_pCallback->OnMessage(msg); -} - -void CVobSubFileRipper::Progress(double progress) -{ - CAutoLock cAutoLock(&m_csCallback); - if (!m_pCallback) { - return; - } - - m_pCallback->OnProgress(progress); -} - -void CVobSubFileRipper::Finished(bool bSucceeded) -{ - CAutoLock cAutoLock(&m_csCallback); - if (!m_pCallback) { - return; - } - - m_pCallback->OnFinished(bSucceeded); -} - -bool CVobSubFileRipper::LoadIfo(CString fn) -{ - CFileStatus status; - if (!CFileGetStatus(fn, status) || !status.m_size) { - Log(LOG_ERROR, _T("Invalid ifo")); - return false; - } - - CFile f; - if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - Log(LOG_ERROR, _T("Cannot open ifo")); - return false; - } - - Log(LOG_INFO, _T("Opening ifo OK")); - - char hdr[13]; - f.Read(hdr, 12); - hdr[12] = 0; - if (strcmp(hdr, "DVDVIDEO-VTS")) { - Log(LOG_ERROR, _T("Not a Video Title Set IFO file!")); - return false; - } - - // lang ids - - f.Seek(0x254, CFile::begin); - - WORD ids[32]; - ZeroMemory(ids, sizeof(ids)); - - int len = 0; - ReadBEw(len); - - for (ptrdiff_t i = 0; i < len; i++) { - f.Seek(2, CFile::current); // 01 00 ? - ReadBEw(ids[i]); - if (ids[i] == 0) { - ids[i] = '--'; - } - f.Seek(2, CFile::current); // 00 00 ? - } - - /* Video info */ - - f.Seek(0x200, CFile::begin); - f.Read(&m_rd.vidinfo, 2); - - SIZE res[4][2] = { - {{720, 480}, {720, 576}}, - {{704, 480}, {704, 576}}, - {{352, 480}, {352, 576}}, - {{352, 240}, {352, 288}} - }; - - m_rd.vidsize = res[m_rd.vidinfo.source_res][m_rd.vidinfo.system & 1]; - - double rate = (m_rd.vidinfo.system == 0) ? 30.0 / 29.97 : 1.0; - - /* PGCs */ - - { - DWORD offset; - - DWORD pgcpos; - f.Seek(0xc0 + 0x0c, CFile::begin); - ReadBEdw(pgcpos); - pgcpos *= 0x800; - - WORD nPGC; - f.Seek(pgcpos, CFile::begin); - ReadBEw(nPGC); - - m_rd.pgcs.RemoveAll(); - m_rd.pgcs.SetCount(nPGC); - - for (size_t i = 0; i < nPGC; i++) { - PGC& pgc = m_rd.pgcs[i]; - - f.Seek(pgcpos + 8 + i * 8 + 4, CFile::begin); - ReadBEdw(offset); - offset += pgcpos; - - BYTE nProgs, nCells; - f.Seek(offset + 2, CFile::begin); - ReadBEb(nProgs); - ReadBEb(nCells); - - // - - memcpy(pgc.ids, ids, sizeof(ids)); - - struct splanginfo { - BYTE res1, id1, id2, res2; - }; - splanginfo splinfo[32]; - - f.Seek(offset + 0x1c, CFile::begin); - f.Read(splinfo, 32 * 4); - - for (size_t j = 0; j < 32; j++) { - if (splinfo[j].id1 || splinfo[i].id2) { - - for (j = 0; j < 32; j++) { - if (!(splinfo[j].res1 & 0x80)) { - break; - } - - pgc.ids[splinfo[j].id1] = ids[j]; - pgc.ids[splinfo[j].id2] = ids[j]; - } - - break; - } - } - - // - - f.Seek(offset + 0xa4, CFile::begin); - - for (size_t j = 0; j < 16; j++) { - BYTE y, u, v, tmp; - - f.Read(&tmp, 1); - f.Read(&y, 1); - f.Read(&u, 1); - f.Read(&v, 1); - - y = (y - 16) * 255 / 219; - - pgc.pal[j].rgbRed = std::min(std::max(BYTE(1.0 * y + 1.4022 * (u - 128)), 0u), 255u); - pgc.pal[j].rgbGreen = std::min(std::max(BYTE(1.0 * y - 0.3456 * (u - 128) - 0.7145 * (v - 128)), 0u), 255u); - pgc.pal[j].rgbBlue = std::min(std::max(BYTE(1.0 * y + 1.7710 * (v - 128)), 0u), 255u); - } - - // - - WORD progoff, celladdroff, vobcelloff; - f.Seek(offset + 0xe6, CFile::begin); - ReadBEw(progoff); - f.Seek(offset + 0xe8, CFile::begin); - ReadBEw(celladdroff); - f.Seek(offset + 0xea, CFile::begin); - ReadBEw(vobcelloff); - - // - - CAtlArray progs; - progs.SetCount(nProgs); - f.Seek(offset + progoff, CFile::begin); - f.Read(progs.GetData(), nProgs); - - // - - pgc.angles[0].SetCount(nCells); - pgc.iSelAngle = 0; - - // - - f.Seek(offset + vobcelloff, CFile::begin); - for (size_t j = 0; j < nCells; j++) { - ReadBEw(pgc.angles[0][j].vob); - ReadBEw(pgc.angles[0][j].cell); - } - - // - - DWORD tOffset = 0, tTotal = 0; - - int iAngle = 0; - - pgc.nAngles = 0; - - f.Seek(offset + celladdroff, CFile::begin); - for (size_t j = 0; j < nCells; j++) { - BYTE b; - ReadBEb(b); - switch (b >> 6) { - case 0: - iAngle = 0; - break; // normal - case 1: - iAngle = 1; - break; // first angle block - case 2: - iAngle++; - break; // middle angle block - case 3: - iAngle++; - break; // last angle block (no more should follow) - } - pgc.angles[0][j].iAngle = iAngle; - pgc.nAngles = std::max(pgc.nAngles, iAngle); - - f.Seek(3, CFile::current); - ReadBEdw(pgc.angles[0][j].tTime); - ReadBEdw(pgc.angles[0][j].start); - f.Seek(8, CFile::current); - ReadBEdw(pgc.angles[0][j].end); - - float fps; - switch ((pgc.angles[0][j].tTime >> 6) & 0x3) { - default: - case 3: - fps = 30; - break; - case 1: - fps = 25; - break; - } - - int t = pgc.angles[0][j].tTime; - int hh = ((t >> 28) & 0xf) * 10 + ((t >> 24) & 0xf); - int mm = ((t >> 20) & 0xf) * 10 + ((t >> 16) & 0xf); - int ss = ((t >> 12) & 0xf) * 10 + ((t >> 8) & 0xf); - int ms = (int)(1000.0 * (((t >> 4) & 0x3) * 10 + ((t >> 0) & 0xf)) / fps); - pgc.angles[0][j].tTime = (DWORD)((((hh * 60 + mm) * 60 + ss) * 1000 + ms) * rate); - - // time discontinuity - if (b & 0x02) { - tOffset = tTotal; - } - pgc.angles[0][j].bDiscontinuity = !!(b & 0x02); - - pgc.angles[0][j].tTotal = tTotal; - pgc.angles[0][j].tOffset = tOffset; - - tTotal += pgc.angles[0][j].tTime; - } - - for (iAngle = 1; iAngle <= 9; iAngle++) { - tOffset = tTotal = 0; - - for (size_t j = 0, k = 0; j < nCells; j++) { - if (pgc.angles[0][j].iAngle != 0 - && pgc.angles[0][j].iAngle != iAngle) { - continue; - } - - pgc.angles[iAngle].Add(pgc.angles[0][j]); - - if (pgc.angles[iAngle][k].bDiscontinuity) { - tOffset = tTotal; - } - - pgc.angles[iAngle][k].tTotal = tTotal; - pgc.angles[iAngle][k].tOffset = tOffset; - - tTotal += pgc.angles[iAngle][k].tTime; - - k++; - } - } - } - } - - Log(LOG_INFO, _T("Parsing ifo OK")); - - return true; -} - -bool CVobSubFileRipper::LoadVob(CString fn) -{ - Log(LOG_INFO, _T("Searching vobs...")); - - CAtlList vobs; - if (!m_vob.Open(fn, vobs/*m_vobs*/)) { - Log(LOG_ERROR, _T("Cannot open vob sequence")); - return false; - } - - if (vobs.GetCount() <= 0) { - Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn.GetString()); - return false; - } - - POSITION pos = vobs.GetHeadPosition(); - while (pos) { - Log(LOG_INFO, _T("Found ") + vobs.GetNext(pos)); - } - - if (m_vob.IsDVD()) { - Log(LOG_INFO, _T("DVD detected...")); - - BYTE key[5]; - - if (m_vob.HasDiscKey(key)) { - Log(LOG_INFO, _T("Disc key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); - } else { - Log(LOG_WARNING, _T("Couldn't get the disc key")); - } - - if (m_vob.HasTitleKey(key)) { - Log(LOG_INFO, _T("Title key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); - } else { - Log(LOG_WARNING, _T("Couldn't get the title key")); - } - - BYTE buff[2048]; - - m_vob.Seek(0); - if (!m_vob.Read(buff)) { - Log(LOG_ERROR, _T("Can't read vob, please unlock it with a software player!")); - return false; - } - m_vob.Seek(0); - } - - return true; -} - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CVobSubFileRipper::ThreadProc() -{ - SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL); - - for (;;) { - DWORD cmd = GetRequest(); - - m_bThreadActive = true; - - switch (cmd) { - case CMD_EXIT: - Reply(S_OK); - return 0; - - case CMD_INDEX: - Reply(S_OK); - { - m_bIndexing = true; - bool bSucceeded = Create(); - m_bIndexing = false; - Finished(bSucceeded); - } - break; - - default: - Reply((DWORD)E_FAIL); - return DWORD_ERROR; - } - - m_bBreakThread = false; - m_bThreadActive = false; - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -bool CVobSubFileRipper::Create() -{ - CAutoLock cAutoLock(&m_csAccessLock); - - if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { - Log(LOG_ERROR, _T("Invalid program chain number (%d)!"), m_rd.iSelPGC); - return false; - } - - PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; - - if (pgc.iSelAngle < 0 || pgc.iSelAngle > 9 || pgc.angles[pgc.iSelAngle].IsEmpty()) { - Log(LOG_ERROR, _T("Invalid angle number (%d)!"), pgc.iSelAngle); - return false; - } - - CAtlArray& angle = pgc.angles[pgc.iSelAngle]; - - if (m_rd.selids.IsEmpty() && !m_rd.bClosedCaption) { - Log(LOG_ERROR, _T("No valid stream set to be extacted!")); - return false; - } - - if (m_rd.selvcs.IsEmpty()) { - Log(LOG_ERROR, _T("No valid vob/cell id set to be extacted!")); - return false; - } - - Log(LOG_INFO, _T("Indexing...")); - - // initalize CVobSubFile - CVobSubFile::Close(); - InitSettings(); - m_title = m_outfn; - m_size = m_rd.vidsize; - TrimExtension(m_title); - memcpy(m_orgpal, pgc.pal, sizeof(m_orgpal)); - m_sub.SetLength(0); - - CCDecoder ccdec(m_title + _T(".cc.srt"), m_title + _T(".cc.raw")); - - CVobDec vd; - - __int64 PTS = 0, tOffset = 0, tPrevOffset = 0, tTotal = 0, tStart = 0; - int vob = 0, cell = 0; - bool bDiscontinuity = false, bDiscontinuityFixApplied = false, bNavpackFound = false; - - int PTSframeoffset = 0, minPTSframeoffset = 0; - - if (m_rd.bResetTime) { - for (size_t i = 0; i < angle.GetCount() && (UINT)((angle[i].vob << 16) | angle[i].cell) != m_rd.selvcs[0]; i++) { - tStart += angle[i].tTime; - } - - Log(LOG_INFO, _T("Counting timestamps from %I64dms (v%02dc%02d)"), - tStart, m_rd.selvcs[0] >> 16, m_rd.selvcs[0] & 0xffff); - } - - CAtlMap selvcmap; - selvcmap.RemoveAll(); - for (size_t i = 0; i < m_rd.selvcs.GetCount(); i++) { - selvcmap[m_rd.selvcs[i]] = 90000; - } - - CAtlArray chunks, foundchunks, loadedchunks; - - if (m_vob.IsDVD()) { - Log(LOG_INFO, _T("Indexing mode: DVD")); - - for (size_t i = 0; i < angle.GetCount(); i++) { - DWORD vc = (angle[i].vob << 16) | angle[i].cell; - if (!selvcmap.Lookup(vc)) { - continue; - } - - vcchunk c = {2048i64 * angle[i].start, 2048i64 * angle[i].end + 2048, vc}; - chunks.Add(c); - - Log(LOG_INFO, _T("Adding: 0x%x - 0x%x (lba) for vob %d cell %d"), - angle[i].start, angle[i].end, angle[i].vob, angle[i].cell); - } - } else if (LoadChunks(loadedchunks)) { - Log(LOG_INFO, _T("Indexing mode: File")); - - for (size_t i = 0; i < loadedchunks.GetCount(); i++) { - DWORD vcid = loadedchunks[i].vc; - if (!selvcmap.Lookup(vcid)) { - continue; - } - - chunks.Add(loadedchunks[i]); - } - - Log(LOG_INFO, _T(".chunk file loaded")); - } else { - Log(LOG_INFO, _T("Indexing mode: File")); - - chunks.RemoveAll(); - vcchunk c = {0, 2048i64 * m_vob.GetLength(), 0}; - chunks.Add(c); - } - - __int64 sizedone = 0, sizetotal = 0; - for (size_t i = 0; i < chunks.GetCount(); i++) { - sizetotal += chunks[i].end - chunks[i].start; - } - - for (size_t i = 0; !m_bBreakThread && i < chunks.GetCount(); i++) { - __int64 curpos = chunks[i].start, endpos = chunks[i].end; - - vcchunk curchunk = {curpos, curpos, chunks[i].vc}; - - for (m_vob.Seek((int)(curpos / 2048)); !m_bBreakThread && curpos < endpos; curpos += 2048, sizedone += 2048) { - if (!(curpos & 0x7ffff)) { - Progress(1.0 * sizedone / sizetotal); - } - - static BYTE buff[2048]; - - if (!m_vob.Read(buff)) { - Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); - return false; - } - - curchunk.end = curpos; - - if (buff[0x14] & 0x30) { - if (!vd.m_fFoundKey) { - Log(LOG_INFO, _T("Encrypted sector found, searching key...")); - - __int64 savepos = curpos; - - m_vob.Seek(0); - for (__int64 pos = 0; !m_bBreakThread && pos < endpos; pos += 2048) { - if (!m_vob.Read(buff)) { - Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); - return false; - } - - if (vd.FindKey(buff)) { - break; - } - } - - if (m_bBreakThread) { - break; - } - - if (!vd.m_fFoundKey) { - Log(LOG_ERROR, _T("Key not found, can't decrypt!")); - return false; - } - - Log(LOG_INFO, _T("Key found, continuing extraction...")); - - m_vob.Seek((int)((curpos = savepos) / 2048)); - m_vob.Read(buff); - } - - vd.Decrypt(buff); - } - - if (*((DWORD*)&buff[0]) != 0xba010000) { - Log(LOG_WARNING, _T("Bad sector header at block %08d!"), (int)(curpos / 2048)); - - if (AfxMessageBox(_T("Bad packet header found, do you want to continue?"), MB_YESNO) == IDNO) { - Log(LOG_ERROR, _T("Terminated!")); - return false; - } - } - - /*__int64 SCR = (__int64(buff[0x04] & 0x38) >> 3) << 30 - | __int64(buff[0x04] & 0x03) << 28 - | __int64(buff[0x05]) << 20 - | (__int64(buff[0x06] & 0xf8) >> 3) << 15 - | __int64(buff[0x06] & 0x03) << 13 - | __int64(buff[0x07]) << 5 - | (__int64(buff[0x08] & 0xf8) >> 3) << 0;*/ - - bool hasPTS = false; - - if ((*(DWORD*)&buff[0x0e] == 0xe0010000 || *(DWORD*)&buff[0x0e] == 0xbd010000) - && buff[0x15] & 0x80) { - PTS = (__int64)(buff[0x17] & 0x0e) << 29 // 32-30 (+marker) - | ((__int64)(buff[0x18]) << 22) // 29-22 - | ((__int64)(buff[0x19] & 0xfe) << 14) // 21-15 (+marker) - | ((__int64)(buff[0x1a]) << 7) // 14-07 - | ((__int64)(buff[0x1b]) >> 1); // 06-00 (+marker) - - hasPTS = true; - } - - if (*((DWORD*)&buff[0x0e]) == 0xbb010000) { - bNavpackFound = true; - - if (vob == buff[0x420] && cell == buff[0x422]) { - continue; - } - - vob = buff[0x420]; - cell = buff[0x422]; - - tOffset = tTotal = 0; - - for (size_t j = 0; j < angle.GetCount(); j++) { - if (angle[j].vob == vob && angle[j].cell == cell) { - tPrevOffset = tOffset; - tOffset = (__int64)angle[j].tOffset; - tTotal = (__int64)angle[j].tTotal; - bDiscontinuity = angle[j].bDiscontinuity; - bDiscontinuityFixApplied = false; - break; - } - } - - if (curchunk.vc != (DWORD)((vob << 16) | cell)) { - if (curchunk.vc != 0) { - foundchunks.Add(curchunk); - } - curchunk.start = curchunk.end = curpos; - curchunk.vc = (vob << 16) | cell; - } - - CString str, str2; - str.Format(_T("v%02d c%02d lba%08d"), vob, cell, (int)(curpos / 2048)); - UINT vcid = (vob << 16) | cell; - if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { - str2 = _T(", skipping"); - } else str2.Format(_T(", total=%I64dms, off=%I64dms, corr=%I64dms, discont.:%d"), - tTotal, tOffset, -tStart, (int)bDiscontinuity); - Log(LOG_INFO, str + str2); - } - - DWORD vcid = (vob << 16) | cell; - if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { - continue; - } - - if (hasPTS && bDiscontinuity && !bDiscontinuityFixApplied) { - __int64 tDiff = tOffset - tPrevOffset; - if (tDiff > 0 && tDiff < (PTS / 90 + 1000)) { - CString str; - str.Format(_T("False discontinuity detected, correcting time by %I64dms"), -tDiff); - Log(LOG_INFO, str); - - tStart += tDiff; - } - bDiscontinuityFixApplied = true; - } - - if (*(DWORD*)&buff[0x0e] == 0xe0010000) { - if (bDiscontinuity) { - if (PTS < minPTSframeoffset) { - selvcmap[vcid] = PTSframeoffset = (int)PTS; - } - - bDiscontinuity = false; - } - - if (m_rd.bClosedCaption) { - ccdec.ExtractCC(buff, 2048, tOffset + ((PTS - PTSframeoffset) / 90) - tStart); - } - } else if (*(DWORD*)&buff[0x0e] == 0xbd010000) { - BYTE id = buff[0x17 + buff[0x16]], iLang = id & 0x1f; - - if ((id & 0xe0) == 0x20 && m_rd.selids.Lookup(iLang)) { - if (hasPTS) { - SubPos sb; - sb.filepos = m_sub.GetPosition(); - sb.start = tOffset + ((PTS - PTSframeoffset) / 90) - tStart; - sb.vobid = (char)vob; - sb.cellid = (char)cell; - sb.celltimestamp = tTotal; - sb.bValid = true; - m_langs[iLang].subpos.Add(sb); - } - - m_sub.Write(buff, 2048); - } - } - } - - if (curchunk.vc != (DWORD)((vob << 16) | cell)) { - if (curchunk.vc != 0) { - foundchunks.Add(curchunk); - } - curchunk.start = curchunk.end = curpos; - curchunk.vc = (vob << 16) | cell; - } - } - - if (sizedone < sizetotal) { - Log(LOG_ERROR, _T("Indexing terminated before reaching the end!")); - Progress(0); - return false; - } - - if (!bNavpackFound) { - Log(LOG_ERROR, _T("Could not find any system header start code! (0x000001bb)")); - if (!m_vob.IsDVD()) { - Log(LOG_ERROR, _T("Make sure the ripper doesn't strip these packets.")); - } - Progress(0); - return false; - } - - Log(LOG_INFO, _T("Indexing finished")); - Progress(1); - - for (size_t i = 0; i < m_langs.size(); i++) { - if (m_nLang == SIZE_T_ERROR && !m_langs[i].subpos.IsEmpty()) { - m_nLang = i; - } - m_langs[i].id = pgc.ids[i]; - m_langs[i].name = m_langs[i].alt = FindLangFromId(m_langs[i].id); - - CAtlArray& sp = m_langs[i].subpos; - std::sort(sp.GetData(), sp.GetData() + sp.GetCount()); - - if (m_rd.bForcedOnly) { - Log(LOG_INFO, _T("Searching for forced subs...")); - Progress(0); - - for (size_t j = 0, len = sp.GetCount(); j < len; j++) { - Progress(1.0 * j / len); - - sp[j].bValid = false; - size_t packetSize = 0, dataSize = 0; - if (BYTE* buff = GetPacket(j, packetSize, dataSize, i)) { - m_img.GetPacketInfo(buff, packetSize, dataSize); - sp[j].bValid = m_img.bForced; - delete [] buff; - } - } - - Progress(1); - } - } - - Log(LOG_INFO, _T("Saving files...")); - - if (m_nLang != SIZE_T_ERROR) { - if (!Save(m_title)) { - Log(LOG_ERROR, _T("Could not save output files!")); - return false; - } - } - - Log(LOG_INFO, _T("Subtitles saved")); - - if (!m_vob.IsDVD() && loadedchunks.IsEmpty()) { - if (SaveChunks(foundchunks)) { - Log(LOG_INFO, _T(".chunk file saved")); - } - } - - Log(LOG_INFO, _T("Done!")); - - return true; -} - -static const DWORD s_version = 1; - -bool CVobSubFileRipper::LoadChunks(CAtlArray& chunks) -{ - CFile f; - - CString fn = m_infn; - TrimExtension(fn); - fn += _T(".chunks"); - - DWORD chksum = 0, chunklen, version; - __int64 voblen = 0; - - if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - f.Read(&version, sizeof(version)); - if (version == 1) { - f.Read(&chksum, sizeof(chksum)); - f.Read(&voblen, sizeof(voblen)); - f.Read(&chunklen, sizeof(chunklen)); - chunks.SetCount(chunklen); - f.Read(chunks.GetData(), UINT(sizeof(vcchunk)*chunks.GetCount())); - } - f.Close(); - - if (voblen != m_vob.GetLength()) { - chunks.RemoveAll(); - return false; - } - - if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - DWORD dw, chksum2 = 0; - while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { - chksum2 += dw; - } - f.Close(); - - if (chksum != chksum2) { - chunks.RemoveAll(); - return false; - } - - return true; -} - -bool CVobSubFileRipper::SaveChunks(CAtlArray& chunks) -{ - CFile f; - - CString fn = m_infn; - TrimExtension(fn); - fn += _T(".chunks"); - - DWORD chksum = 0, chunklen = (DWORD)chunks.GetCount(); - __int64 voblen = m_vob.GetLength(); - - if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - DWORD dw; - while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { - chksum += dw; - } - f.Close(); - - if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { - return false; - } - f.Write(&s_version, sizeof(s_version)); - f.Write(&chksum, sizeof(chksum)); - f.Write(&voblen, sizeof(voblen)); - f.Write(&chunklen, sizeof(chunklen)); - f.Write(chunks.GetData(), sizeof(vcchunk)*chunklen); - f.Close(); - - return true; -} - -// IVSFRipper - -STDMETHODIMP CVobSubFileRipper::SetCallBack(IVSFRipperCallback* pCallback) -{ - CAutoLock cAutoLock(&m_csCallback); - m_pCallback = pCallback; - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::LoadParamFile(CString fn) -{ - CAutoLock cAutoLock(&m_csAccessLock); - - m_rd.Reset(); - - CStdioFile f; - if (!f.Open(fn, CFile::modeRead | CFile::typeText)) { - return E_FAIL; - } - - TCHAR langid[256]; - - enum { - P_INPUT, - P_OUTPUT, - P_PGC, - P_ANGLE, - P_LANGS, - P_OPTIONS - }; - int phase = P_INPUT; - - CString line; - while (f.ReadString(line)) { - if (line.Trim().IsEmpty() || line[0] == '#') { - continue; - } - - if (phase == P_INPUT) { - if (S_OK != SetInput(line)) { - break; - } - phase = P_OUTPUT; - } else if (phase == P_OUTPUT) { - if (S_OK != SetOutput(line)) { - break; - } - phase = P_PGC; - } else if (phase == P_PGC) { - m_rd.iSelPGC = _tcstol(line, nullptr, 10) - 1; - if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { - break; - } - phase = P_ANGLE; - } else if (phase == 3) { - PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; - - pgc.iSelAngle = _tcstol(line, nullptr, 10); - if (pgc.iSelAngle < 0 || pgc.iSelAngle > std::max(1, pgc.nAngles) || pgc.iSelAngle > 9) { - break; - } - - CAtlArray& angle = pgc.angles[pgc.iSelAngle]; - - if (line.Find('v') >= 0) { - int vob = 0, cell = 0; - - line += _T(' '); - - TCHAR* s = (LPTSTR)(LPCTSTR)line; - TCHAR* e = s + line.GetLength(); - while (s < e) { - if (*s == 'v' || s == e - 1) { - s++; - if (vob != 0 && cell == 0) { - for (size_t i = 0; i < angle.GetCount(); i++) { - if (angle[i].vob == vob) { - m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); - } - } - } - - vob = _tcstol(s, &s, 10); - cell = 0; - } else if (*s == 'c' && vob > 0) { - s++; - cell = _tcstol(s, &s, 10); - - for (size_t i = 0; i < angle.GetCount(); i++) { - if (angle[i].vob == vob && angle[i].cell == cell) { - m_rd.selvcs.Add((vob << 16) | cell); - break; - } - } - } else { - s++; - } - } - } else { - for (size_t i = 0; i < angle.GetCount(); i++) { - m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); - } - } - - phase = P_LANGS; - } else if (phase == 4) { - if (!line.CompareNoCase(_T("ALL"))) { - for (BYTE i = 0; i < 32; i++) { - m_rd.selids[i] = true; - } - m_rd.bClosedCaption = true; - phase = P_OPTIONS; - } else { - line += _T(' '); - - while (!line.IsEmpty()) { - int n = line.Find(_T(" ")); - - CString lang = line.Left(n); - - line = line.Mid(n); - line.TrimLeft(); - - n = 0; - if (_istdigit(lang[0])) { - int langnum; - n = _stscanf_s(lang, _T("%d"), &langnum); - if (n != 1) { - break; - } - - m_rd.selids[(BYTE)langnum] = true; - } else if (_istalpha(lang[0])) { - n = _stscanf_s(lang, _T("%s"), langid, UINT(_countof(langid))); - if (n != 1) { - break; - } - - int id = (langid[0] << 8) + langid[1]; - - if (id == 'cc') { - m_rd.bClosedCaption = true; - } else { - ASSERT(id <= BYTE_MAX); - m_rd.selids[(BYTE)id] = true; - } - } else { - break; - } - } - - if ((!m_rd.selids.IsEmpty() || m_rd.bClosedCaption) && line.IsEmpty()) { - phase = P_OPTIONS; - } - } - } else if (phase == 5 && !line.CompareNoCase(_T("CLOSE"))) { - m_rd.bClose = true; - } else if (phase == 5 && !line.CompareNoCase(_T("BEEP"))) { - m_rd.bBeep = true; - } else if (phase == 5 && !line.CompareNoCase(_T("RESETTIME"))) { - m_rd.bResetTime = true; - } else if (phase == 5 && !line.CompareNoCase(_T("FORCEDONLY"))) { - m_rd.bForcedOnly = true; - } else if (phase == 5 && !line.CompareNoCase(_T("CLOSEIGNOREERRORS"))) { - m_rd.bCloseIgnoreError = true; - } - - } - - m_rd.bAuto = true; - - return phase == P_OPTIONS ? S_OK : E_FAIL; -} - -STDMETHODIMP CVobSubFileRipper::SetInput(CString infn) -{ - CAutoLock cAutoLock(&m_csAccessLock); - - m_rd.Reset(); - - if (!LoadIfo(infn) || !LoadVob(infn)) { - return E_INVALIDARG; - } - - m_infn = infn; - - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::SetOutput(CString outfn) -{ - CAutoLock cAutoLock(&m_csAccessLock); - m_outfn = outfn; - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::GetRipperData(VSFRipperData& rd) -{ - CAutoLock cAutoLock(&m_csAccessLock); - rd.Copy(m_rd); - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::UpdateRipperData(VSFRipperData& rd) -{ - CAutoLock cAutoLock(&m_csAccessLock); - m_rd.Copy(rd); - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::Index() -{ - if (m_bIndexing) { - return E_FAIL; - } - CAMThread::CallWorker(CMD_INDEX); - return S_OK; -} - - -STDMETHODIMP CVobSubFileRipper::IsIndexing() -{ - return m_bIndexing ? S_OK : S_FALSE; -} - -STDMETHODIMP CVobSubFileRipper::Abort(bool bSavePartial) -{ - m_bBreakThread = true; - return S_OK; -} - -// - -void VSFRipperData::Reset() -{ - vidsize.SetSize(0, 0); - ZeroMemory(&vidinfo, sizeof(vidinfo)); - pgcs.RemoveAll(); - iSelPGC = -1; - bResetTime = bClosedCaption = true; - bForcedOnly = false; - bClose = bBeep = bAuto = false; - bCloseIgnoreError = false; - - selvcs.RemoveAll(); - selids.RemoveAll(); -} - -void VSFRipperData::Copy(VSFRipperData& rd) -{ - Reset(); - - vidsize = rd.vidsize; - vidinfo = rd.vidinfo; - if (size_t len = rd.pgcs.GetCount()) { - pgcs.SetCount(len); - for (size_t i = 0; i < len; i++) { - PGC& src = rd.pgcs[i]; - PGC& dst = pgcs[i]; - dst.nAngles = src.nAngles; - for (size_t j = 0; j < _countof(dst.angles); j++) { - dst.angles[j].Copy(src.angles[j]); - } - dst.iSelAngle = src.iSelAngle; - memcpy(dst.pal, src.pal, sizeof(src.pal)); - memcpy(dst.ids, src.ids, sizeof(src.ids)); - } - } - iSelPGC = rd.iSelPGC; - bResetTime = rd.bResetTime; - bClosedCaption = rd.bClosedCaption; - bForcedOnly = rd.bForcedOnly; - bClose = rd.bClose; - bBeep = rd.bBeep; - bAuto = rd.bAuto; - bCloseIgnoreError = rd.bCloseIgnoreError; - selvcs.Copy(rd.selvcs); - POSITION pos = rd.selids.GetStartPosition(); - while (pos) { - BYTE key; - bool val; - rd.selids.GetNextAssoc(pos, key, val); - selids[key] = val; - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "VobSubFile.h" +#include "VobSubFileRipper.h" +#include "../DeCSS/VobDec.h" +#include "CCDecoder.h" + +// +// CVobSubFileRipper +// + +CVobSubFileRipper::CVobSubFileRipper() + : CVobSubFile(nullptr) + , m_bThreadActive(false) + , m_bBreakThread(false) + , m_bIndexing(false) +{ + m_rd.Reset(); + CAMThread::Create(); +} + +CVobSubFileRipper::~CVobSubFileRipper() +{ + CAMThread::CallWorker(CMD_EXIT); + CAMThread::Close(); +} + +STDMETHODIMP CVobSubFileRipper::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IVSFRipper) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CVobSubFileRipper::Log(log_t type, LPCTSTR lpszFormat, ...) +{ + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } + + TCHAR buff[1024]; + + va_list args; + va_start(args, lpszFormat); + _vstprintf_s(buff, _countof(buff), lpszFormat, args); + va_end(args); + + CString msg; + switch (type) { + default: + case LOG_INFO: + msg = _T(""); + break; + case LOG_WARNING: + msg = _T("WARNING: "); + break; + case LOG_ERROR: + msg = _T("ERROR: "); + break; + } + + msg += buff; + + m_pCallback->OnMessage(msg); +} + +void CVobSubFileRipper::Progress(double progress) +{ + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } + + m_pCallback->OnProgress(progress); +} + +void CVobSubFileRipper::Finished(bool bSucceeded) +{ + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } + + m_pCallback->OnFinished(bSucceeded); +} + +bool CVobSubFileRipper::LoadIfo(CString fn) +{ + CFileStatus status; + if (!CFileGetStatus(fn, status) || !status.m_size) { + Log(LOG_ERROR, _T("Invalid ifo")); + return false; + } + + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + Log(LOG_ERROR, _T("Cannot open ifo")); + return false; + } + + Log(LOG_INFO, _T("Opening ifo OK")); + + char hdr[13]; + f.Read(hdr, 12); + hdr[12] = 0; + if (strcmp(hdr, "DVDVIDEO-VTS")) { + Log(LOG_ERROR, _T("Not a Video Title Set IFO file!")); + return false; + } + + // lang ids + + f.Seek(0x254, CFile::begin); + + WORD ids[32]; + ZeroMemory(ids, sizeof(ids)); + + int len = 0; + ReadBEw(len); + + for (ptrdiff_t i = 0; i < len; i++) { + f.Seek(2, CFile::current); // 01 00 ? + ReadBEw(ids[i]); + if (ids[i] == 0) { + ids[i] = '--'; + } + f.Seek(2, CFile::current); // 00 00 ? + } + + /* Video info */ + + f.Seek(0x200, CFile::begin); + f.Read(&m_rd.vidinfo, 2); + + SIZE res[4][2] = { + {{720, 480}, {720, 576}}, + {{704, 480}, {704, 576}}, + {{352, 480}, {352, 576}}, + {{352, 240}, {352, 288}} + }; + + m_rd.vidsize = res[m_rd.vidinfo.source_res][m_rd.vidinfo.system & 1]; + + double rate = (m_rd.vidinfo.system == 0) ? 30.0 / 29.97 : 1.0; + + /* PGCs */ + + { + DWORD offset; + + DWORD pgcpos; + f.Seek(0xc0 + 0x0c, CFile::begin); + ReadBEdw(pgcpos); + pgcpos *= 0x800; + + WORD nPGC; + f.Seek(pgcpos, CFile::begin); + ReadBEw(nPGC); + + m_rd.pgcs.RemoveAll(); + m_rd.pgcs.SetCount(nPGC); + + for (size_t i = 0; i < nPGC; i++) { + PGC& pgc = m_rd.pgcs[i]; + + f.Seek(pgcpos + 8 + i * 8 + 4, CFile::begin); + ReadBEdw(offset); + offset += pgcpos; + + BYTE nProgs, nCells; + f.Seek(offset + 2, CFile::begin); + ReadBEb(nProgs); + ReadBEb(nCells); + + // + + memcpy(pgc.ids, ids, sizeof(ids)); + + struct splanginfo { + BYTE res1, id1, id2, res2; + }; + splanginfo splinfo[32]; + + f.Seek(offset + 0x1c, CFile::begin); + f.Read(splinfo, 32 * 4); + + for (size_t j = 0; j < 32; j++) { + if (splinfo[j].id1 || splinfo[i].id2) { + + for (j = 0; j < 32; j++) { + if (!(splinfo[j].res1 & 0x80)) { + break; + } + + pgc.ids[splinfo[j].id1] = ids[j]; + pgc.ids[splinfo[j].id2] = ids[j]; + } + + break; + } + } + + // + + f.Seek(offset + 0xa4, CFile::begin); + + for (size_t j = 0; j < 16; j++) { + BYTE y, u, v, tmp; + + f.Read(&tmp, 1); + f.Read(&y, 1); + f.Read(&u, 1); + f.Read(&v, 1); + + y = (y - 16) * 255 / 219; + + pgc.pal[j].rgbRed = std::min(std::max(BYTE(1.0 * y + 1.4022 * (u - 128)), 0u), 255u); + pgc.pal[j].rgbGreen = std::min(std::max(BYTE(1.0 * y - 0.3456 * (u - 128) - 0.7145 * (v - 128)), 0u), 255u); + pgc.pal[j].rgbBlue = std::min(std::max(BYTE(1.0 * y + 1.7710 * (v - 128)), 0u), 255u); + } + + // + + WORD progoff, celladdroff, vobcelloff; + f.Seek(offset + 0xe6, CFile::begin); + ReadBEw(progoff); + f.Seek(offset + 0xe8, CFile::begin); + ReadBEw(celladdroff); + f.Seek(offset + 0xea, CFile::begin); + ReadBEw(vobcelloff); + + // + + CAtlArray progs; + progs.SetCount(nProgs); + f.Seek(offset + progoff, CFile::begin); + f.Read(progs.GetData(), nProgs); + + // + + pgc.angles[0].SetCount(nCells); + pgc.iSelAngle = 0; + + // + + f.Seek(offset + vobcelloff, CFile::begin); + for (size_t j = 0; j < nCells; j++) { + ReadBEw(pgc.angles[0][j].vob); + ReadBEw(pgc.angles[0][j].cell); + } + + // + + DWORD tOffset = 0, tTotal = 0; + + int iAngle = 0; + + pgc.nAngles = 0; + + f.Seek(offset + celladdroff, CFile::begin); + for (size_t j = 0; j < nCells; j++) { + BYTE b; + ReadBEb(b); + switch (b >> 6) { + case 0: + iAngle = 0; + break; // normal + case 1: + iAngle = 1; + break; // first angle block + case 2: + iAngle++; + break; // middle angle block + case 3: + iAngle++; + break; // last angle block (no more should follow) + } + pgc.angles[0][j].iAngle = iAngle; + pgc.nAngles = std::max(pgc.nAngles, iAngle); + + f.Seek(3, CFile::current); + ReadBEdw(pgc.angles[0][j].tTime); + ReadBEdw(pgc.angles[0][j].start); + f.Seek(8, CFile::current); + ReadBEdw(pgc.angles[0][j].end); + + float fps; + switch ((pgc.angles[0][j].tTime >> 6) & 0x3) { + default: + case 3: + fps = 30; + break; + case 1: + fps = 25; + break; + } + + int t = pgc.angles[0][j].tTime; + int hh = ((t >> 28) & 0xf) * 10 + ((t >> 24) & 0xf); + int mm = ((t >> 20) & 0xf) * 10 + ((t >> 16) & 0xf); + int ss = ((t >> 12) & 0xf) * 10 + ((t >> 8) & 0xf); + int ms = (int)(1000.0 * (((t >> 4) & 0x3) * 10 + ((t >> 0) & 0xf)) / fps); + pgc.angles[0][j].tTime = (DWORD)((((hh * 60 + mm) * 60 + ss) * 1000 + ms) * rate); + + // time discontinuity + if (b & 0x02) { + tOffset = tTotal; + } + pgc.angles[0][j].bDiscontinuity = !!(b & 0x02); + + pgc.angles[0][j].tTotal = tTotal; + pgc.angles[0][j].tOffset = tOffset; + + tTotal += pgc.angles[0][j].tTime; + } + + for (iAngle = 1; iAngle <= 9; iAngle++) { + tOffset = tTotal = 0; + + for (size_t j = 0, k = 0; j < nCells; j++) { + if (pgc.angles[0][j].iAngle != 0 + && pgc.angles[0][j].iAngle != iAngle) { + continue; + } + + pgc.angles[iAngle].Add(pgc.angles[0][j]); + + if (pgc.angles[iAngle][k].bDiscontinuity) { + tOffset = tTotal; + } + + pgc.angles[iAngle][k].tTotal = tTotal; + pgc.angles[iAngle][k].tOffset = tOffset; + + tTotal += pgc.angles[iAngle][k].tTime; + + k++; + } + } + } + } + + Log(LOG_INFO, _T("Parsing ifo OK")); + + return true; +} + +bool CVobSubFileRipper::LoadVob(CString fn) +{ + Log(LOG_INFO, _T("Searching vobs...")); + + CAtlList vobs; + if (!m_vob.Open(fn, vobs/*m_vobs*/)) { + Log(LOG_ERROR, _T("Cannot open vob sequence")); + return false; + } + + if (vobs.GetCount() <= 0) { + Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn.GetString()); + return false; + } + + POSITION pos = vobs.GetHeadPosition(); + while (pos) { + Log(LOG_INFO, _T("Found ") + vobs.GetNext(pos)); + } + + if (m_vob.IsDVD()) { + Log(LOG_INFO, _T("DVD detected...")); + + BYTE key[5]; + + if (m_vob.HasDiscKey(key)) { + Log(LOG_INFO, _T("Disc key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); + } else { + Log(LOG_WARNING, _T("Couldn't get the disc key")); + } + + if (m_vob.HasTitleKey(key)) { + Log(LOG_INFO, _T("Title key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); + } else { + Log(LOG_WARNING, _T("Couldn't get the title key")); + } + + BYTE buff[2048]; + + m_vob.Seek(0); + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Can't read vob, please unlock it with a software player!")); + return false; + } + m_vob.Seek(0); + } + + return true; +} + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CVobSubFileRipper::ThreadProc() +{ + SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL); + + for (;;) { + DWORD cmd = GetRequest(); + + m_bThreadActive = true; + + switch (cmd) { + case CMD_EXIT: + Reply(S_OK); + return 0; + + case CMD_INDEX: + Reply(S_OK); + { + m_bIndexing = true; + bool bSucceeded = Create(); + m_bIndexing = false; + Finished(bSucceeded); + } + break; + + default: + Reply((DWORD)E_FAIL); + return DWORD_ERROR; + } + + m_bBreakThread = false; + m_bThreadActive = false; + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +bool CVobSubFileRipper::Create() +{ + CAutoLock cAutoLock(&m_csAccessLock); + + if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { + Log(LOG_ERROR, _T("Invalid program chain number (%d)!"), m_rd.iSelPGC); + return false; + } + + PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; + + if (pgc.iSelAngle < 0 || pgc.iSelAngle > 9 || pgc.angles[pgc.iSelAngle].IsEmpty()) { + Log(LOG_ERROR, _T("Invalid angle number (%d)!"), pgc.iSelAngle); + return false; + } + + CAtlArray& angle = pgc.angles[pgc.iSelAngle]; + + if (m_rd.selids.IsEmpty() && !m_rd.bClosedCaption) { + Log(LOG_ERROR, _T("No valid stream set to be extacted!")); + return false; + } + + if (m_rd.selvcs.IsEmpty()) { + Log(LOG_ERROR, _T("No valid vob/cell id set to be extacted!")); + return false; + } + + Log(LOG_INFO, _T("Indexing...")); + + // initalize CVobSubFile + CVobSubFile::Close(); + InitSettings(); + m_title = m_outfn; + m_size = m_rd.vidsize; + TrimExtension(m_title); + memcpy(m_orgpal, pgc.pal, sizeof(m_orgpal)); + m_sub.SetLength(0); + + CCDecoder ccdec(m_title + _T(".cc.srt"), m_title + _T(".cc.raw")); + + CVobDec vd; + + __int64 PTS = 0, tOffset = 0, tPrevOffset = 0, tTotal = 0, tStart = 0; + int vob = 0, cell = 0; + bool bDiscontinuity = false, bDiscontinuityFixApplied = false, bNavpackFound = false; + + int PTSframeoffset = 0, minPTSframeoffset = 0; + + if (m_rd.bResetTime) { + for (size_t i = 0; i < angle.GetCount() && (UINT)((angle[i].vob << 16) | angle[i].cell) != m_rd.selvcs[0]; i++) { + tStart += angle[i].tTime; + } + + Log(LOG_INFO, _T("Counting timestamps from %I64dms (v%02dc%02d)"), + tStart, m_rd.selvcs[0] >> 16, m_rd.selvcs[0] & 0xffff); + } + + CAtlMap selvcmap; + selvcmap.RemoveAll(); + for (size_t i = 0; i < m_rd.selvcs.GetCount(); i++) { + selvcmap[m_rd.selvcs[i]] = 90000; + } + + CAtlArray chunks, foundchunks, loadedchunks; + + if (m_vob.IsDVD()) { + Log(LOG_INFO, _T("Indexing mode: DVD")); + + for (size_t i = 0; i < angle.GetCount(); i++) { + DWORD vc = (angle[i].vob << 16) | angle[i].cell; + if (!selvcmap.Lookup(vc)) { + continue; + } + + vcchunk c = {2048i64 * angle[i].start, 2048i64 * angle[i].end + 2048, vc}; + chunks.Add(c); + + Log(LOG_INFO, _T("Adding: 0x%x - 0x%x (lba) for vob %d cell %d"), + angle[i].start, angle[i].end, angle[i].vob, angle[i].cell); + } + } else if (LoadChunks(loadedchunks)) { + Log(LOG_INFO, _T("Indexing mode: File")); + + for (size_t i = 0; i < loadedchunks.GetCount(); i++) { + DWORD vcid = loadedchunks[i].vc; + if (!selvcmap.Lookup(vcid)) { + continue; + } + + chunks.Add(loadedchunks[i]); + } + + Log(LOG_INFO, _T(".chunk file loaded")); + } else { + Log(LOG_INFO, _T("Indexing mode: File")); + + chunks.RemoveAll(); + vcchunk c = {0, 2048i64 * m_vob.GetLength(), 0}; + chunks.Add(c); + } + + __int64 sizedone = 0, sizetotal = 0; + for (size_t i = 0; i < chunks.GetCount(); i++) { + sizetotal += chunks[i].end - chunks[i].start; + } + + for (size_t i = 0; !m_bBreakThread && i < chunks.GetCount(); i++) { + __int64 curpos = chunks[i].start, endpos = chunks[i].end; + + vcchunk curchunk = {curpos, curpos, chunks[i].vc}; + + for (m_vob.Seek((int)(curpos / 2048)); !m_bBreakThread && curpos < endpos; curpos += 2048, sizedone += 2048) { + if (!(curpos & 0x7ffff)) { + Progress(1.0 * sizedone / sizetotal); + } + + static BYTE buff[2048]; + + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); + return false; + } + + curchunk.end = curpos; + + if (buff[0x14] & 0x30) { + if (!vd.m_fFoundKey) { + Log(LOG_INFO, _T("Encrypted sector found, searching key...")); + + __int64 savepos = curpos; + + m_vob.Seek(0); + for (__int64 pos = 0; !m_bBreakThread && pos < endpos; pos += 2048) { + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); + return false; + } + + if (vd.FindKey(buff)) { + break; + } + } + + if (m_bBreakThread) { + break; + } + + if (!vd.m_fFoundKey) { + Log(LOG_ERROR, _T("Key not found, can't decrypt!")); + return false; + } + + Log(LOG_INFO, _T("Key found, continuing extraction...")); + + m_vob.Seek((int)((curpos = savepos) / 2048)); + m_vob.Read(buff); + } + + vd.Decrypt(buff); + } + + if (*((DWORD*)&buff[0]) != 0xba010000) { + Log(LOG_WARNING, _T("Bad sector header at block %08d!"), (int)(curpos / 2048)); + + if (AfxMessageBox(_T("Bad packet header found, do you want to continue?"), MB_YESNO) == IDNO) { + Log(LOG_ERROR, _T("Terminated!")); + return false; + } + } + + /*__int64 SCR = (__int64(buff[0x04] & 0x38) >> 3) << 30 + | __int64(buff[0x04] & 0x03) << 28 + | __int64(buff[0x05]) << 20 + | (__int64(buff[0x06] & 0xf8) >> 3) << 15 + | __int64(buff[0x06] & 0x03) << 13 + | __int64(buff[0x07]) << 5 + | (__int64(buff[0x08] & 0xf8) >> 3) << 0;*/ + + bool hasPTS = false; + + if ((*(DWORD*)&buff[0x0e] == 0xe0010000 || *(DWORD*)&buff[0x0e] == 0xbd010000) + && buff[0x15] & 0x80) { + PTS = (__int64)(buff[0x17] & 0x0e) << 29 // 32-30 (+marker) + | ((__int64)(buff[0x18]) << 22) // 29-22 + | ((__int64)(buff[0x19] & 0xfe) << 14) // 21-15 (+marker) + | ((__int64)(buff[0x1a]) << 7) // 14-07 + | ((__int64)(buff[0x1b]) >> 1); // 06-00 (+marker) + + hasPTS = true; + } + + if (*((DWORD*)&buff[0x0e]) == 0xbb010000) { + bNavpackFound = true; + + if (vob == buff[0x420] && cell == buff[0x422]) { + continue; + } + + vob = buff[0x420]; + cell = buff[0x422]; + + tOffset = tTotal = 0; + + for (size_t j = 0; j < angle.GetCount(); j++) { + if (angle[j].vob == vob && angle[j].cell == cell) { + tPrevOffset = tOffset; + tOffset = (__int64)angle[j].tOffset; + tTotal = (__int64)angle[j].tTotal; + bDiscontinuity = angle[j].bDiscontinuity; + bDiscontinuityFixApplied = false; + break; + } + } + + if (curchunk.vc != (DWORD)((vob << 16) | cell)) { + if (curchunk.vc != 0) { + foundchunks.Add(curchunk); + } + curchunk.start = curchunk.end = curpos; + curchunk.vc = (vob << 16) | cell; + } + + CString str, str2; + str.Format(_T("v%02d c%02d lba%08d"), vob, cell, (int)(curpos / 2048)); + UINT vcid = (vob << 16) | cell; + if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { + str2 = _T(", skipping"); + } else str2.Format(_T(", total=%I64dms, off=%I64dms, corr=%I64dms, discont.:%d"), + tTotal, tOffset, -tStart, (int)bDiscontinuity); + Log(LOG_INFO, str + str2); + } + + DWORD vcid = (vob << 16) | cell; + if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { + continue; + } + + if (hasPTS && bDiscontinuity && !bDiscontinuityFixApplied) { + __int64 tDiff = tOffset - tPrevOffset; + if (tDiff > 0 && tDiff < (PTS / 90 + 1000)) { + CString str; + str.Format(_T("False discontinuity detected, correcting time by %I64dms"), -tDiff); + Log(LOG_INFO, str); + + tStart += tDiff; + } + bDiscontinuityFixApplied = true; + } + + if (*(DWORD*)&buff[0x0e] == 0xe0010000) { + if (bDiscontinuity) { + if (PTS < minPTSframeoffset) { + selvcmap[vcid] = PTSframeoffset = (int)PTS; + } + + bDiscontinuity = false; + } + + if (m_rd.bClosedCaption) { + ccdec.ExtractCC(buff, 2048, tOffset + ((PTS - PTSframeoffset) / 90) - tStart); + } + } else if (*(DWORD*)&buff[0x0e] == 0xbd010000) { + BYTE id = buff[0x17 + buff[0x16]], iLang = id & 0x1f; + + if ((id & 0xe0) == 0x20 && m_rd.selids.Lookup(iLang)) { + if (hasPTS) { + SubPos sb; + sb.filepos = m_sub.GetPosition(); + sb.start = tOffset + ((PTS - PTSframeoffset) / 90) - tStart; + sb.vobid = (char)vob; + sb.cellid = (char)cell; + sb.celltimestamp = tTotal; + sb.bValid = true; + m_langs[iLang].subpos.Add(sb); + } + + m_sub.Write(buff, 2048); + } + } + } + + if (curchunk.vc != (DWORD)((vob << 16) | cell)) { + if (curchunk.vc != 0) { + foundchunks.Add(curchunk); + } + curchunk.start = curchunk.end = curpos; + curchunk.vc = (vob << 16) | cell; + } + } + + if (sizedone < sizetotal) { + Log(LOG_ERROR, _T("Indexing terminated before reaching the end!")); + Progress(0); + return false; + } + + if (!bNavpackFound) { + Log(LOG_ERROR, _T("Could not find any system header start code! (0x000001bb)")); + if (!m_vob.IsDVD()) { + Log(LOG_ERROR, _T("Make sure the ripper doesn't strip these packets.")); + } + Progress(0); + return false; + } + + Log(LOG_INFO, _T("Indexing finished")); + Progress(1); + + for (size_t i = 0; i < m_langs.size(); i++) { + if (m_nLang == SIZE_T_ERROR && !m_langs[i].subpos.IsEmpty()) { + m_nLang = i; + } + m_langs[i].id = pgc.ids[i]; + m_langs[i].name = m_langs[i].alt = FindLangFromId(m_langs[i].id); + + CAtlArray& sp = m_langs[i].subpos; + std::sort(sp.GetData(), sp.GetData() + sp.GetCount()); + + if (m_rd.bForcedOnly) { + Log(LOG_INFO, _T("Searching for forced subs...")); + Progress(0); + + for (size_t j = 0, len = sp.GetCount(); j < len; j++) { + Progress(1.0 * j / len); + + sp[j].bValid = false; + size_t packetSize = 0, dataSize = 0; + if (BYTE* buff = GetPacket(j, packetSize, dataSize, i)) { + m_img.GetPacketInfo(buff, packetSize, dataSize); + sp[j].bValid = m_img.bForced; + delete [] buff; + } + } + + Progress(1); + } + } + + Log(LOG_INFO, _T("Saving files...")); + + if (m_nLang != SIZE_T_ERROR) { + if (!Save(m_title)) { + Log(LOG_ERROR, _T("Could not save output files!")); + return false; + } + } + + Log(LOG_INFO, _T("Subtitles saved")); + + if (!m_vob.IsDVD() && loadedchunks.IsEmpty()) { + if (SaveChunks(foundchunks)) { + Log(LOG_INFO, _T(".chunk file saved")); + } + } + + Log(LOG_INFO, _T("Done!")); + + return true; +} + +static const DWORD s_version = 1; + +bool CVobSubFileRipper::LoadChunks(CAtlArray& chunks) +{ + CFile f; + + CString fn = m_infn; + TrimExtension(fn); + fn += _T(".chunks"); + + DWORD chksum = 0, chunklen, version; + __int64 voblen = 0; + + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + f.Read(&version, sizeof(version)); + if (version == 1) { + f.Read(&chksum, sizeof(chksum)); + f.Read(&voblen, sizeof(voblen)); + f.Read(&chunklen, sizeof(chunklen)); + chunks.SetCount(chunklen); + f.Read(chunks.GetData(), UINT(sizeof(vcchunk)*chunks.GetCount())); + } + f.Close(); + + if (voblen != m_vob.GetLength()) { + chunks.RemoveAll(); + return false; + } + + if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + DWORD dw, chksum2 = 0; + while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { + chksum2 += dw; + } + f.Close(); + + if (chksum != chksum2) { + chunks.RemoveAll(); + return false; + } + + return true; +} + +bool CVobSubFileRipper::SaveChunks(CAtlArray& chunks) +{ + CFile f; + + CString fn = m_infn; + TrimExtension(fn); + fn += _T(".chunks"); + + DWORD chksum = 0, chunklen = (DWORD)chunks.GetCount(); + __int64 voblen = m_vob.GetLength(); + + if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + DWORD dw; + while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { + chksum += dw; + } + f.Close(); + + if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { + return false; + } + f.Write(&s_version, sizeof(s_version)); + f.Write(&chksum, sizeof(chksum)); + f.Write(&voblen, sizeof(voblen)); + f.Write(&chunklen, sizeof(chunklen)); + f.Write(chunks.GetData(), sizeof(vcchunk)*chunklen); + f.Close(); + + return true; +} + +// IVSFRipper + +STDMETHODIMP CVobSubFileRipper::SetCallBack(IVSFRipperCallback* pCallback) +{ + CAutoLock cAutoLock(&m_csCallback); + m_pCallback = pCallback; + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::LoadParamFile(CString fn) +{ + CAutoLock cAutoLock(&m_csAccessLock); + + m_rd.Reset(); + + CStdioFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeText)) { + return E_FAIL; + } + + TCHAR langid[256]; + + enum { + P_INPUT, + P_OUTPUT, + P_PGC, + P_ANGLE, + P_LANGS, + P_OPTIONS + }; + int phase = P_INPUT; + + CString line; + while (f.ReadString(line)) { + if (line.Trim().IsEmpty() || line[0] == '#') { + continue; + } + + if (phase == P_INPUT) { + if (S_OK != SetInput(line)) { + break; + } + phase = P_OUTPUT; + } else if (phase == P_OUTPUT) { + if (S_OK != SetOutput(line)) { + break; + } + phase = P_PGC; + } else if (phase == P_PGC) { + m_rd.iSelPGC = _tcstol(line, nullptr, 10) - 1; + if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { + break; + } + phase = P_ANGLE; + } else if (phase == 3) { + PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; + + pgc.iSelAngle = _tcstol(line, nullptr, 10); + if (pgc.iSelAngle < 0 || pgc.iSelAngle > std::max(1, pgc.nAngles) || pgc.iSelAngle > 9) { + break; + } + + CAtlArray& angle = pgc.angles[pgc.iSelAngle]; + + if (line.Find('v') >= 0) { + int vob = 0, cell = 0; + + line += _T(' '); + + TCHAR* s = (LPTSTR)(LPCTSTR)line; + TCHAR* e = s + line.GetLength(); + while (s < e) { + if (*s == 'v' || s == e - 1) { + s++; + if (vob != 0 && cell == 0) { + for (size_t i = 0; i < angle.GetCount(); i++) { + if (angle[i].vob == vob) { + m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); + } + } + } + + vob = _tcstol(s, &s, 10); + cell = 0; + } else if (*s == 'c' && vob > 0) { + s++; + cell = _tcstol(s, &s, 10); + + for (size_t i = 0; i < angle.GetCount(); i++) { + if (angle[i].vob == vob && angle[i].cell == cell) { + m_rd.selvcs.Add((vob << 16) | cell); + break; + } + } + } else { + s++; + } + } + } else { + for (size_t i = 0; i < angle.GetCount(); i++) { + m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); + } + } + + phase = P_LANGS; + } else if (phase == 4) { + if (!line.CompareNoCase(_T("ALL"))) { + for (BYTE i = 0; i < 32; i++) { + m_rd.selids[i] = true; + } + m_rd.bClosedCaption = true; + phase = P_OPTIONS; + } else { + line += _T(' '); + + while (!line.IsEmpty()) { + int n = line.Find(_T(" ")); + + CString lang = line.Left(n); + + line = line.Mid(n); + line.TrimLeft(); + + n = 0; + if (_istdigit(lang[0])) { + int langnum; + n = _stscanf_s(lang, _T("%d"), &langnum); + if (n != 1) { + break; + } + + m_rd.selids[(BYTE)langnum] = true; + } else if (_istalpha(lang[0])) { + n = _stscanf_s(lang, _T("%s"), langid, UINT(_countof(langid))); + if (n != 1) { + break; + } + + int id = (langid[0] << 8) + langid[1]; + + if (id == 'cc') { + m_rd.bClosedCaption = true; + } else { + ASSERT(id <= BYTE_MAX); + m_rd.selids[(BYTE)id] = true; + } + } else { + break; + } + } + + if ((!m_rd.selids.IsEmpty() || m_rd.bClosedCaption) && line.IsEmpty()) { + phase = P_OPTIONS; + } + } + } else if (phase == 5 && !line.CompareNoCase(_T("CLOSE"))) { + m_rd.bClose = true; + } else if (phase == 5 && !line.CompareNoCase(_T("BEEP"))) { + m_rd.bBeep = true; + } else if (phase == 5 && !line.CompareNoCase(_T("RESETTIME"))) { + m_rd.bResetTime = true; + } else if (phase == 5 && !line.CompareNoCase(_T("FORCEDONLY"))) { + m_rd.bForcedOnly = true; + } else if (phase == 5 && !line.CompareNoCase(_T("CLOSEIGNOREERRORS"))) { + m_rd.bCloseIgnoreError = true; + } + + } + + m_rd.bAuto = true; + + return phase == P_OPTIONS ? S_OK : E_FAIL; +} + +STDMETHODIMP CVobSubFileRipper::SetInput(CString infn) +{ + CAutoLock cAutoLock(&m_csAccessLock); + + m_rd.Reset(); + + if (!LoadIfo(infn) || !LoadVob(infn)) { + return E_INVALIDARG; + } + + m_infn = infn; + + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::SetOutput(CString outfn) +{ + CAutoLock cAutoLock(&m_csAccessLock); + m_outfn = outfn; + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::GetRipperData(VSFRipperData& rd) +{ + CAutoLock cAutoLock(&m_csAccessLock); + rd.Copy(m_rd); + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::UpdateRipperData(VSFRipperData& rd) +{ + CAutoLock cAutoLock(&m_csAccessLock); + m_rd.Copy(rd); + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::Index() +{ + if (m_bIndexing) { + return E_FAIL; + } + CAMThread::CallWorker(CMD_INDEX); + return S_OK; +} + + +STDMETHODIMP CVobSubFileRipper::IsIndexing() +{ + return m_bIndexing ? S_OK : S_FALSE; +} + +STDMETHODIMP CVobSubFileRipper::Abort(bool bSavePartial) +{ + m_bBreakThread = true; + return S_OK; +} + +// + +void VSFRipperData::Reset() +{ + vidsize.SetSize(0, 0); + ZeroMemory(&vidinfo, sizeof(vidinfo)); + pgcs.RemoveAll(); + iSelPGC = -1; + bResetTime = bClosedCaption = true; + bForcedOnly = false; + bClose = bBeep = bAuto = false; + bCloseIgnoreError = false; + + selvcs.RemoveAll(); + selids.RemoveAll(); +} + +void VSFRipperData::Copy(VSFRipperData& rd) +{ + Reset(); + + vidsize = rd.vidsize; + vidinfo = rd.vidinfo; + if (size_t len = rd.pgcs.GetCount()) { + pgcs.SetCount(len); + for (size_t i = 0; i < len; i++) { + PGC& src = rd.pgcs[i]; + PGC& dst = pgcs[i]; + dst.nAngles = src.nAngles; + for (size_t j = 0; j < _countof(dst.angles); j++) { + dst.angles[j].Copy(src.angles[j]); + } + dst.iSelAngle = src.iSelAngle; + memcpy(dst.pal, src.pal, sizeof(src.pal)); + memcpy(dst.ids, src.ids, sizeof(src.ids)); + } + } + iSelPGC = rd.iSelPGC; + bResetTime = rd.bResetTime; + bClosedCaption = rd.bClosedCaption; + bForcedOnly = rd.bForcedOnly; + bClose = rd.bClose; + bBeep = rd.bBeep; + bAuto = rd.bAuto; + bCloseIgnoreError = rd.bCloseIgnoreError; + selvcs.Copy(rd.selvcs); + POSITION pos = rd.selids.GetStartPosition(); + while (pos) { + BYTE key; + bool val; + rd.selids.GetNextAssoc(pos, key, val); + selids[key] = val; + } +} diff --git a/src/Subtitles/VobSubFileRipper.h b/src/Subtitles/VobSubFileRipper.h index 20e3050d8c2..e0122b1e286 100644 --- a/src/Subtitles/VobSubFileRipper.h +++ b/src/Subtitles/VobSubFileRipper.h @@ -1,191 +1,191 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#pragma once - -#include -#include "../DeCSS/VobFile.h" -#include "../DSUtil/DSUtil.h" -#include "VobSubFile.h" - -#pragma pack(push, 1) -struct vidinfo { - WORD perm_displ : 2; - WORD ratio : 2; - WORD system : 2; - WORD compression : 2; - WORD mode : 1; - WORD letterboxed : 1; - WORD source_res : 2; - WORD cbrvbr : 2; - WORD line21_2 : 1; - WORD line21_1 : 1; -}; - -struct vc_t { - BYTE vob, cell; - DWORD tTime, tOffset, tTotal; - DWORD start, end; - int iAngle; - bool bDiscontinuity; -}; - -struct PGC { - int nAngles; - CAtlArray angles[10]; - int iSelAngle; - RGBQUAD pal[16]; - WORD ids[32]; -}; - -struct VSFRipperData { - CSize vidsize; - vidinfo vidinfo; - CAtlArray pgcs; - int iSelPGC; - bool bResetTime, bClosedCaption, bForcedOnly; - - bool bClose, bBeep, bAuto; // only used by the UI externally, but may be set through the parameter file - bool bCloseIgnoreError; - - CAtlArray selvcs; - CAtlMap selids; - - void Reset(); - void Copy(struct VSFRipperData& rd); -}; - -struct vcchunk { - __int64 start, end; - DWORD vc; -}; - -#pragma pack(pop) - -// note: these interfaces only meant to be used internally with static linking - -// -// IVSFRipperCallback -// - -interface __declspec(uuid("9E2EBB5C-AD7C-452f-A48B-38685716AC46")) - IVSFRipperCallback : - public IUnknown -{ - STDMETHOD(OnMessage)(LPCTSTR msg) PURE; - STDMETHOD(OnProgress)(double progress /*0.0 -> 1.0*/) PURE; - STDMETHOD(OnFinished)(bool bSucceeded) PURE; -}; - -// IVSFRipperCallbackImpl - -class IVSFRipperCallbackImpl : public CUnknown, public IVSFRipperCallback -{ -protected: - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(IVSFRipperCallback) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IVSFRipperCallback - STDMETHODIMP OnMessage(LPCTSTR msg) { return S_FALSE; } - STDMETHODIMP OnProgress(double progress /*0.0 -> 1.0*/) { return S_FALSE; } - STDMETHODIMP OnFinished(bool bSucceeded) { return S_FALSE; } - -public: - IVSFRipperCallbackImpl() : CUnknown(NAME("IVSFRipperCallbackImpl"), nullptr) {} -}; - -// -// IVSFRipper -// - -interface __declspec(uuid("69F935BB-B8D0-43f5-AA2E-BBD0851CC9A6")) - IVSFRipper : - public IUnknown -{ - STDMETHOD(SetCallBack)(IVSFRipperCallback* pCallback) PURE; - STDMETHOD(LoadParamFile)(CString fn) PURE; - STDMETHOD(SetInput)(CString infn) PURE; - STDMETHOD(SetOutput)(CString outfn) PURE; - STDMETHOD(GetRipperData)(VSFRipperData& rd) PURE; - STDMETHOD(UpdateRipperData)(VSFRipperData& rd) PURE; - STDMETHOD(Index)() PURE; - STDMETHOD(IsIndexing)() PURE; - STDMETHOD(Abort)(bool bSavePartial) PURE; -}; - -class CVobSubFileRipper : public CVobSubFile, protected CAMThread, public IVSFRipper -{ -private: - bool m_bThreadActive, m_bBreakThread, m_bIndexing; - enum { CMD_EXIT, CMD_INDEX }; - DWORD ThreadProc(); - bool Create(); - - // - - enum log_t { - LOG_INFO, - LOG_WARNING, - LOG_ERROR - }; - void Log(log_t type, LPCTSTR lpszFormat, ...); - void Progress(double progress); - void Finished(bool bSucceeded); - - // - - CCritSec m_csAccessLock; - CString m_infn, m_outfn; - CVobFile m_vob; - VSFRipperData m_rd; - - bool LoadIfo(CString fn); - bool LoadVob(CString fn); - bool LoadChunks(CAtlArray& chunks); - bool SaveChunks(CAtlArray& chunks); - - // - - CCritSec m_csCallback; - CComPtr m_pCallback; - -public: - CVobSubFileRipper(); - virtual ~CVobSubFileRipper(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IVSFRipper - STDMETHODIMP SetCallBack(IVSFRipperCallback* pCallback); - STDMETHODIMP LoadParamFile(CString fn); - STDMETHODIMP SetInput(CString infn); - STDMETHODIMP SetOutput(CString outfn); - STDMETHODIMP GetRipperData(VSFRipperData& rd); - STDMETHODIMP UpdateRipperData(VSFRipperData& rd); - STDMETHODIMP Index(); - STDMETHODIMP IsIndexing(); - STDMETHODIMP Abort(bool bSavePartial); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#pragma once + +#include +#include "../DeCSS/VobFile.h" +#include "../DSUtil/DSUtil.h" +#include "VobSubFile.h" + +#pragma pack(push, 1) +struct vidinfo { + WORD perm_displ : 2; + WORD ratio : 2; + WORD system : 2; + WORD compression : 2; + WORD mode : 1; + WORD letterboxed : 1; + WORD source_res : 2; + WORD cbrvbr : 2; + WORD line21_2 : 1; + WORD line21_1 : 1; +}; + +struct vc_t { + BYTE vob, cell; + DWORD tTime, tOffset, tTotal; + DWORD start, end; + int iAngle; + bool bDiscontinuity; +}; + +struct PGC { + int nAngles; + CAtlArray angles[10]; + int iSelAngle; + RGBQUAD pal[16]; + WORD ids[32]; +}; + +struct VSFRipperData { + CSize vidsize; + vidinfo vidinfo; + CAtlArray pgcs; + int iSelPGC; + bool bResetTime, bClosedCaption, bForcedOnly; + + bool bClose, bBeep, bAuto; // only used by the UI externally, but may be set through the parameter file + bool bCloseIgnoreError; + + CAtlArray selvcs; + CAtlMap selids; + + void Reset(); + void Copy(struct VSFRipperData& rd); +}; + +struct vcchunk { + __int64 start, end; + DWORD vc; +}; + +#pragma pack(pop) + +// note: these interfaces only meant to be used internally with static linking + +// +// IVSFRipperCallback +// + +interface __declspec(uuid("9E2EBB5C-AD7C-452f-A48B-38685716AC46")) + IVSFRipperCallback : + public IUnknown +{ + STDMETHOD(OnMessage)(LPCTSTR msg) PURE; + STDMETHOD(OnProgress)(double progress /*0.0 -> 1.0*/) PURE; + STDMETHOD(OnFinished)(bool bSucceeded) PURE; +}; + +// IVSFRipperCallbackImpl + +class IVSFRipperCallbackImpl : public CUnknown, public IVSFRipperCallback +{ +protected: + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(IVSFRipperCallback) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IVSFRipperCallback + STDMETHODIMP OnMessage(LPCTSTR msg) { return S_FALSE; } + STDMETHODIMP OnProgress(double progress /*0.0 -> 1.0*/) { return S_FALSE; } + STDMETHODIMP OnFinished(bool bSucceeded) { return S_FALSE; } + +public: + IVSFRipperCallbackImpl() : CUnknown(NAME("IVSFRipperCallbackImpl"), nullptr) {} +}; + +// +// IVSFRipper +// + +interface __declspec(uuid("69F935BB-B8D0-43f5-AA2E-BBD0851CC9A6")) + IVSFRipper : + public IUnknown +{ + STDMETHOD(SetCallBack)(IVSFRipperCallback* pCallback) PURE; + STDMETHOD(LoadParamFile)(CString fn) PURE; + STDMETHOD(SetInput)(CString infn) PURE; + STDMETHOD(SetOutput)(CString outfn) PURE; + STDMETHOD(GetRipperData)(VSFRipperData& rd) PURE; + STDMETHOD(UpdateRipperData)(VSFRipperData& rd) PURE; + STDMETHOD(Index)() PURE; + STDMETHOD(IsIndexing)() PURE; + STDMETHOD(Abort)(bool bSavePartial) PURE; +}; + +class CVobSubFileRipper : public CVobSubFile, protected CAMThread, public IVSFRipper +{ +private: + bool m_bThreadActive, m_bBreakThread, m_bIndexing; + enum { CMD_EXIT, CMD_INDEX }; + DWORD ThreadProc(); + bool Create(); + + // + + enum log_t { + LOG_INFO, + LOG_WARNING, + LOG_ERROR + }; + void Log(log_t type, LPCTSTR lpszFormat, ...); + void Progress(double progress); + void Finished(bool bSucceeded); + + // + + CCritSec m_csAccessLock; + CString m_infn, m_outfn; + CVobFile m_vob; + VSFRipperData m_rd; + + bool LoadIfo(CString fn); + bool LoadVob(CString fn); + bool LoadChunks(CAtlArray& chunks); + bool SaveChunks(CAtlArray& chunks); + + // + + CCritSec m_csCallback; + CComPtr m_pCallback; + +public: + CVobSubFileRipper(); + virtual ~CVobSubFileRipper(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IVSFRipper + STDMETHODIMP SetCallBack(IVSFRipperCallback* pCallback); + STDMETHODIMP LoadParamFile(CString fn); + STDMETHODIMP SetInput(CString infn); + STDMETHODIMP SetOutput(CString outfn); + STDMETHODIMP GetRipperData(VSFRipperData& rd); + STDMETHODIMP UpdateRipperData(VSFRipperData& rd); + STDMETHODIMP Index(); + STDMETHODIMP IsIndexing(); + STDMETHODIMP Abort(bool bSavePartial); +}; diff --git a/src/Subtitles/VobSubImage.cpp b/src/Subtitles/VobSubImage.cpp index 4229b0f0f60..70675655cc8 100644 --- a/src/Subtitles/VobSubImage.cpp +++ b/src/Subtitles/VobSubImage.cpp @@ -1,1361 +1,1361 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "VobSubImage.h" -#include "RTS.h" -#include -#include - -CVobSubImage::CVobSubImage() - : org(CSize(0, 0)) - , lpTemp1(nullptr) - , lpTemp2(nullptr) - , nPlane(0) - , bCustomPal(false) - , bAligned(true) - , tridx(0) - , orgpal(nullptr) - , cuspal(nullptr) - , nLang(SIZE_T_ERROR) - , nIdx(SIZE_T_ERROR) - , bForced(false) - , bAnimated(false) - , tCurrent(-1) - , start(0) - , delay(0) - , rect(CRect(0, 0, 0, 0)) - , lpPixels(nullptr) -{ - ZeroMemory(&pal, sizeof(pal)); -} - -CVobSubImage::~CVobSubImage() -{ - Free(); -} - -bool CVobSubImage::Alloc(int w, int h) -{ - // if there is nothing to crop TrimSubImage might even add a 1 pixel - // wide border around the text, that's why we need a bit more memory - // to be allocated. - - if (lpTemp1 == nullptr || w * h > org.cx * org.cy || (w + 2) * (h + 2) > (org.cx + 2) * (org.cy + 2)) { - Free(); - - try { - lpTemp1 = DEBUG_NEW RGBQUAD[w * h]; - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - return false; - } - - try { - lpTemp2 = DEBUG_NEW RGBQUAD[(w + 2) * (h + 2)]; - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - delete [] lpTemp1; - lpTemp1 = nullptr; - return false; - } - - org.cx = w; - org.cy = h; - } - - lpPixels = lpTemp1; - - return true; -} - -void CVobSubImage::Free() -{ - SAFE_DELETE_ARRAY(lpTemp1); - SAFE_DELETE_ARRAY(lpTemp2); - - lpPixels = nullptr; -} - -bool CVobSubImage::Decode(BYTE* _lpData, size_t _packetSize, size_t _dataSize, int _t, - bool _bCustomPal, - int _tridx, - RGBQUAD* _orgpal /*[16]*/, RGBQUAD* _cuspal /*[4]*/, - bool _bTrim) -{ - GetPacketInfo(_lpData, _packetSize, _dataSize, _t); - - if (!Alloc(rect.Width(), rect.Height())) { - return false; - } - - lpPixels = lpTemp1; - - nPlane = 0; - bAligned = true; - - bCustomPal = _bCustomPal; - orgpal = _orgpal; - tridx = _tridx; - cuspal = _cuspal; - - CPoint p = rect.TopLeft(); - - size_t end[] = { nOffset[1], _dataSize }; - - while (nOffset[nPlane] < end[nPlane]) { - DWORD code; - - if ((code = GetNibble(_lpData)) >= 0x4 - || (code = (code << 4) | GetNibble(_lpData)) >= 0x10 - || (code = (code << 4) | GetNibble(_lpData)) >= 0x40 - || (code = (code << 4) | GetNibble(_lpData)) >= 0x100) { - DrawPixels(p, code >> 2, code & 3); - if ((p.x += code >> 2) < rect.right) { - continue; - } - } - - DrawPixels(p, rect.right - p.x, code & 3); - - if (!bAligned) { - GetNibble(_lpData); // align to byte - } - - p.x = rect.left; - p.y++; - nPlane = 1 - nPlane; - } - - rect.bottom = std::min(p.y, rect.bottom); - - if (_bTrim) { - TrimSubImage(); - } - - return true; -} - -void CVobSubImage::GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t /*= INT_MAX*/) -{ - // delay = 0; - - size_t i, nextctrlblk = dataSize; - WORD _pal = 0, tr = 0; - WORD nPal = 0, nTr = 0; - - do { - i = nextctrlblk; - - tCurrent = 1024 * ((lpData[i] << 8) | lpData[i + 1]) / 90; - i += 2; - nextctrlblk = (lpData[i] << 8) | lpData[i + 1]; - i += 2; - - if (nextctrlblk > packetSize || nextctrlblk < dataSize) { - ASSERT(0); - return; - } - - if (tCurrent > t) { - break; - } - - bool bBreak = false; - - while (!bBreak) { - size_t len = 0; - - switch (lpData[i]) { - case 0x00: - len = 0; - break; - case 0x01: - len = 0; - break; - case 0x02: - len = 0; - break; - case 0x03: - len = 2; - break; - case 0x04: - len = 2; - break; - case 0x05: - len = 6; - break; - case 0x06: - len = 4; - break; - default: - len = 0; - break; - } - - if (i + len >= packetSize) { - TRACE(_T("Warning: Wrong subpicture parameter block ending\n")); - break; - } - - switch (lpData[i++]) { - case 0x00: // forced start displaying - bForced = true; - break; - case 0x01: // start displaying - bForced = false; - break; - case 0x02: // stop displaying - delay = tCurrent; - break; - case 0x03: - _pal = (lpData[i] << 8) | lpData[i + 1]; - i += 2; - nPal++; - break; - case 0x04: - tr = (lpData[i] << 8) | lpData[i + 1]; - i += 2; - nTr++; - //tr &= 0x00f0; - break; - case 0x05: - rect = CRect((lpData[i] << 4) + (lpData[i + 1] >> 4), - (lpData[i + 3] << 4) + (lpData[i + 4] >> 4), - ((lpData[i + 1] & 0x0f) << 8) + lpData[i + 2] + 1, - ((lpData[i + 4] & 0x0f) << 8) + lpData[i + 5] + 1); - i += 6; - break; - case 0x06: - nOffset[0] = (lpData[i] << 8) + lpData[i + 1]; - i += 2; - nOffset[1] = (lpData[i] << 8) + lpData[i + 1]; - i += 2; - break; - case 0xff: // end of ctrlblk - bBreak = true; - continue; - default: // skip this ctrlblk - bBreak = true; - break; - } - } - } while (i <= nextctrlblk && i < packetSize); - - for (i = 0; i < 4; i++) { - this->pal[i].pal = (_pal >> (i << 2)) & 0xf; - this->pal[i].tr = (tr >> (i << 2)) & 0xf; - } - - bAnimated = (nPal > 1 || nTr > 1); -} - -BYTE CVobSubImage::GetNibble(const BYTE* lpData) -{ - size_t& off = nOffset[nPlane]; - BYTE ret = lpData[off]; - if (bAligned) { - ret >>= 4; - } - ret &= 0x0f; - bAligned = !bAligned; - if (bAligned) { - off++; - } - return ret; -} - -void CVobSubImage::DrawPixels(CPoint p, int length, size_t colorId) -{ - if (length <= 0 - || p.x + length < rect.left - || p.x >= rect.right - || p.y < rect.top - || p.y >= rect.bottom) { - return; - } - - if (p.x < rect.left) { - p.x = rect.left; - } - if (p.x + length >= rect.right) { - length = rect.right - p.x; - } - - RGBQUAD* ptr = &lpPixels[rect.Width() * (p.y - rect.top) + (p.x - rect.left)]; - - RGBQUAD c; - - if (!bCustomPal) { - c = orgpal[pal[colorId].pal]; - c.rgbReserved = (pal[colorId].tr << 4) | pal[colorId].tr; - } else { - c = cuspal[colorId]; - } - - while (length-- > 0) { - *ptr++ = c; - } -} - -void CVobSubImage::TrimSubImage() -{ - CRect r; - r.left = rect.Width(); - r.top = rect.Height(); - r.right = 0; - r.bottom = 0; - - RGBQUAD* ptr = lpTemp1; - - for (int j = 0, y = rect.Height(); j < y; j++) { - for (int i = 0, x = rect.Width(); i < x; i++, ptr++) { - if (ptr->rgbReserved) { - if (r.top > j) { - r.top = j; - } - if (r.bottom < j) { - r.bottom = j; - } - if (r.left > i) { - r.left = i; - } - if (r.right < i) { - r.right = i; - } - } - } - } - - if (r.left > r.right || r.top > r.bottom) { - return; - } - - r += CRect(0, 0, 1, 1); - - r &= CRect(CPoint(0, 0), rect.Size()); - - int w = r.Width(), h = r.Height(); - - DWORD offset = r.top * rect.Width() + r.left; - - r += CRect(1, 1, 1, 1); - - DWORD* src = (DWORD*)&lpTemp1[offset]; - DWORD* dst = (DWORD*)&lpTemp2[1 + w + 1]; - - ZeroMemory(lpTemp2, (1 + w + 1)*sizeof(RGBQUAD)); - - for (int height = h; height; height--, src += rect.Width()) { - *dst++ = 0; - memcpy(dst, src, w * sizeof(RGBQUAD)); - dst += w; - *dst++ = 0; - } - - ZeroMemory(dst, (1 + w + 1)*sizeof(RGBQUAD)); - - lpPixels = lpTemp2; - - rect = r + rect.TopLeft(); -} - -//////////////////////////////// - -#define GP(xx, yy) (((xx) < 0 || (yy) < 0 || (xx) >= w || (yy) >= h) ? 0 : p[(yy) * w + (xx)]) - -CAutoPtrList* CVobSubImage::GetOutlineList(CPoint& topleft) -{ - int w = rect.Width(), h = rect.Height(), len = w * h; - if (len <= 0) { - return nullptr; - } - - CAutoVectorPtr p; - if (!p.Allocate(len)) { - return nullptr; - } - - CAutoPtrList* ol; - try { - ol = DEBUG_NEW CAutoPtrList(); - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - return nullptr; - } - - BYTE* cp = p; - RGBQUAD* rgbp = (RGBQUAD*)lpPixels; - - for (int i = 0; i < len; i++, cp++, rgbp++) { - *cp = !!rgbp->rgbReserved; - } - - enum { UP, RIGHT, DOWN, LEFT }; - - topleft.x = topleft.y = INT_MAX; - - for (;;) { - cp = p; - - int x = 0; - int y = 0; - - for (y = 0; y < h; y++) { - for (x = 0; x < w - 1; x++, cp++) { - if (cp[0] == 0 && cp[1] == 1) { - break; - } - } - - if (x < w - 1) { - break; - } - - cp++; - } - - if (y == h) { - break; - } - - int dir = UP; - - int ox = x, oy = y, odir = dir; - - CAutoPtr o; - try { - o.Attach(DEBUG_NEW COutline); - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - break; - } - - do { - CPoint pp; - BYTE fl = 0; - BYTE fr = 0; - BYTE br = 0; - - int prevdir = dir; - - switch (prevdir) { - case UP: - pp = CPoint(x + 1, y); - fl = GP(x, y - 1); - fr = GP(x + 1, y - 1); - br = GP(x + 1, y); - break; - case RIGHT: - pp = CPoint(x + 1, y + 1); - fl = GP(x + 1, y); - fr = GP(x + 1, y + 1); - br = GP(x, y + 1); - break; - case DOWN: - pp = CPoint(x, y + 1); - fl = GP(x, y + 1); - fr = GP(x - 1, y + 1); - br = GP(x - 1, y); - break; - case LEFT: - pp = CPoint(x, y); - fl = GP(x - 1, y); - fr = GP(x - 1, y - 1); - br = GP(x, y - 1); - break; - } - - // turning left if: - // o . | o . - // ^ o | < o - // turning right if: - // x x | x > - // ^ o | x o - // - // o set, x empty, . can be anything - - if (fl == 1) { - dir = (dir - 1 + 4) & 3; - } else if (fl != 1 && fr != 1 && br == 1) { - dir = (dir + 1) & 3; - } else if (p[y * w + x] & 16) { - ASSERT(0); // we are going around in one place (this must not happen if the starting conditions were correct) - break; - } - - p[y * w + x] = (p[y * w + x] << 1) | 2; // increase turn count (== log2(highordbit(*p))) - - switch (dir) { - case UP: - if (prevdir == LEFT) { - x--; - y--; - } - if (prevdir == UP) { - y--; - } - break; - case RIGHT: - if (prevdir == UP) { - x++; - y--; - } - if (prevdir == RIGHT) { - x++; - } - break; - case DOWN: - if (prevdir == RIGHT) { - x++; - y++; - } - if (prevdir == DOWN) { - y++; - } - break; - case LEFT: - if (prevdir == DOWN) { - x--; - y++; - } - if (prevdir == LEFT) { - x--; - } - break; - } - - int d = dir - prevdir; - o->Add(pp, d == 3 ? -1 : d == -3 ? 1 : d); - - if (topleft.x > pp.x) { - topleft.x = pp.x; - } - if (topleft.y > pp.y) { - topleft.y = pp.y; - } - } while (!(x == ox && y == oy && dir == odir)); - - if (!o->pa.IsEmpty() && (x == ox && y == oy && dir == odir)) { - ol->AddTail(o); - } else { - ASSERT(0); - } - } - - return ol; -} - -static bool FitLine(const COutline& o, int& start, int& end) -{ - int len = (int)o.pa.GetCount(); - if (len < 7) { - return false; // small segments should be handled with beziers... - } - - for (start = 0; start < len && !o.da[start]; start++) { - ; - } - for (end = len - 1; end > start && !o.da[end]; end--) { - ; - } - - if (end - start < 8 || end - start < (len - end) + (start - 0)) { - return false; - } - - CUIntArray la, ra; - - UINT i, j, k; - - for (i = start + 1, j = end, k = start; i <= j; i++) { - if (!o.da[i]) { - continue; - } - if (o.da[i] == o.da[k]) { - return false; - } - if (o.da[i] == -1) { - la.Add(i - k); - } else { - ra.Add(i - k); - } - k = i; - } - - bool fl = true, fr = true; - - // these tests are completly heuristic and might be redundant a bit... - - for (i = 0, j = (UINT)la.GetSize(); i < j && fl; i++) { - if (la[i] != 1) { - fl = false; - } - } - for (i = 0, j = (UINT)ra.GetSize(); i < j && fr; i++) { - if (ra[i] != 1) { - fr = false; - } - } - - if (!fl && !fr) { - return false; // can't be a line if there are bigger steps than one in both directions (lines are usually drawn by stepping one either horizontally or vertically) - } - if (fl && fr && 1.0 * (end - start) / ((len - end) * 2 + (start - 0) * 2) > 0.4) { - return false; // if this section is relatively too small it may only be a rounded corner - } - if (!fl && !la.IsEmpty() && la.GetSize() <= 4 && (la[0] == 1 && la[la.GetSize() - 1] == 1)) { - return false; // one step at both ends, doesn't sound good for a line (may be it was skewed, so only eliminate smaller sections where beziers going to look just as good) - } - if (!fr && !ra.IsEmpty() && ra.GetSize() <= 4 && (ra[0] == 1 && ra[ra.GetSize() - 1] == 1)) { - return false; // -''- - } - - CUIntArray& a = !fl ? la : ra; - - len = (int)a.GetSize(); - - int sum = 0; - - for (i = 0, j = INT_MAX, k = 0; i < (UINT)len; i++) { - if (j > a[i]) { - j = a[i]; - } - if (k < a[i]) { - k = a[i]; - } - sum += a[i]; - } - - if (k - j > 2 && 1.0 * sum / len < 2) { - return false; - } - if (k - j > 2 && 1.0 * sum / len >= 2 && len < 4) { - return false; - } - - if ((la.GetSize() / 2 + ra.GetSize() / 2) / 2 <= 2) { - if ((k + j) / 2 < 2 && k * j != 1) { - return false; - } - } - - double err = 0; - - CPoint sp = o.pa[start], ep = o.pa[end]; - - double minerr = 0, maxerr = 0; - - double vx = ep.x - sp.x, vy = ep.y - sp.y, l = sqrt(vx * vx + vy * vy); - vx /= l; - vy /= l; - - for (i = start + 1, j = end - 1; i <= j; i++) { - CPoint p = o.pa[i], dp = p - sp; - double t = vx * dp.x + vy * dp.y, dx = vx * t + sp.x - p.x, dy = vy * t + sp.y - p.y; - t = dx * dx + dy * dy; - err += t; - t = sqrt(t); - if (vy * dx - dy * vx < 0) { - if (minerr > -t) { - minerr = -t; - } - } else { - if (maxerr < t) { - maxerr = t; - } - } - } - - return ((maxerr - minerr) / l < 0.1 || err / l < 1.5 || (fabs(maxerr) < 8 && fabs(minerr) < 8)); -} - -static int CalcPossibleCurveDegree(const COutline& o) -{ - size_t len2 = o.da.GetCount(); - - CUIntArray la; - - for (size_t i = 0, j = 0; j < len2; j++) { - if (j + 1 == len2 || o.da[j]) { - la.Add(UINT(j - i)); - i = j; - } - } - - ptrdiff_t len = la.GetCount(); - - int ret = 0; - - // check if we can find a reason to add a penalty degree, or two :P - // it is mainly about looking for distant corners - { - int penalty = 0; - - int ma[2] = {0, 0}; - for (ptrdiff_t i = 0; i < len; i++) { - ma[i & 1] += la[i]; - } - - int ca[2] = {ma[0], ma[1]}; - for (ptrdiff_t i = 0; i < len; i++) { - ca[i & 1] -= la[i]; - - double c1 = 1.0 * ca[0] / ma[0], c2 = 1.0 * ca[1] / ma[1], c3 = 1.0 * la[i] / ma[i & 1]; - - if (len2 > 16 && (fabs(c1 - c2) > 0.7 || (c3 > 0.6 && la[i] > 5))) { - penalty = 2; - break; - } - - if (fabs(c1 - c2) > 0.6 || (c3 > 0.4 && la[i] > 5)) { - penalty = 1; - } - } - - ret += penalty; - } - - la[0] <<= 1; - la[len - 1] <<= 1; - - for (ptrdiff_t i = 0; i < len; i += 2) { - if (la[i] > 1) { - ret++; // prependicular to the last chosen section and bigger then 1 -> add a degree and continue with the other dir - i--; - } - } - - return ret; -} - -inline double vectlen(CPoint p) -{ - return sqrt((double)(p.x * p.x + p.y * p.y)); -} - -inline double vectlen(CPoint p1, CPoint p2) -{ - return vectlen(p2 - p1); -} - -static bool MinMaxCosfi(COutline& o, double& mincf, double& maxcf) // not really cosfi, it is weighted by the distance from the segment endpoints, and since it would be always between -1 and 0, the applied sign marks side -{ - CAtlArray& pa = o.pa; - - int len = (int)pa.GetCount(); - if (len < 6) { - return false; - } - - mincf = 1; - maxcf = -1; - - CPoint p = pa[len - 1] - pa[0]; - double l = vectlen(p); - UNREFERENCED_PARAMETER(l); - - for (ptrdiff_t i = 2; i < len - 2; i++) { // skip the endpoints, they aren't accurate - CPoint p1 = pa[0] - pa[i], p2 = pa[len - 1] - pa[i]; - double l1 = vectlen(p1), l2 = vectlen(p2); - int sign = p1.x * p.y - p1.y * p.x >= 0 ? 1 : -1; - - double c = (1.0 * len / 2 - fabs(i - 1.0 * len / 2)) / len * 2; // c: 0 -> 1 -> 0 - - double cosfi = (1 + (p1.x * p2.x + p1.y * p2.y) / (l1 * l2)) * sign * c; - if (mincf > cosfi) { - mincf = cosfi; - } - if (maxcf < cosfi) { - maxcf = cosfi; - } - } - - return true; -} - -static bool FitBezierVH(COutline& o, CPoint& p1, CPoint& p2) -{ - int i; - - CAtlArray& pa = o.pa; - - int len = (int)pa.GetCount(); - - if (len <= 1) { - return false; - } else if (len == 2) { - CPoint mid = pa[0] + pa[1]; - mid.x >>= 1; - mid.y >>= 1; - p1 = p2 = mid; - return true; - } - - CPoint dir1 = pa[1] - pa[0], dir2 = pa[len - 2] - pa[len - 1]; - if ((dir1.x && dir1.y) || (dir2.x && dir2.y)) { - return false; // we are only fitting beziers with hor./ver. endings - } - - if (CalcPossibleCurveDegree(o) > 3) { - return false; - } - - double mincf, maxcf; - if (MinMaxCosfi(o, mincf, maxcf)) { - if (maxcf - mincf > 0.8 - || maxcf - mincf > 0.6 && (maxcf >= 0.4 || mincf <= -0.4)) { - return false; - } - } - - CPoint p0 = p1 = pa[0]; - CPoint p3 = p2 = pa[len - 1]; - - CAtlArray pl; - pl.SetCount(len); - - double c10 = 0, c11 = 0, c12 = 0, c13 = 0, c1x = 0, c1y = 0; - double c20 = 0, c21 = 0, c22 = 0, c23 = 0, c2x = 0, c2y = 0; - double length = 0; - - for (pl[0] = 0, i = 1; i < len; i++) { - CPoint diff = (pa[i] - pa[i - 1]); - pl[i] = (length += sqrt((double)(diff.x * diff.x + diff.y * diff.y))); - } - - for (i = 0; i < len; i++) { - double t1 = pl[i] / length; - double t2 = t1 * t1; - double t3 = t2 * t1; - double it1 = 1 - t1; - double it2 = it1 * it1; - double it3 = it2 * it1; - - double dc1 = 3.0 * it2 * t1; - double dc2 = 3.0 * it1 * t2; - - c10 += it3 * dc1; - c11 += dc1 * dc1; - c12 += dc2 * dc1; - c13 += t3 * dc1; - c1x += pa[i].x * dc1; - c1y += pa[i].y * dc1; - - c20 += it3 * dc2; - c21 += dc1 * dc2; - c22 += dc2 * dc2; - c23 += t3 * dc2; - c2x += pa[i].x * dc2; - c2y += pa[i].y * dc2; - } - - if (dir1.y == 0 && dir2.x == 0) { - p1.x = (int)((c1x - c10 * p0.x - c12 * p3.x - c13 * p3.x) / c11 + 0.5); - p2.y = (int)((c2y - c20 * p0.y - c21 * p0.y - c23 * p3.y) / c22 + 0.5); - } else if (dir1.x == 0 && dir2.y == 0) { - p2.x = (int)((c2x - c20 * p0.x - c21 * p0.x - c23 * p3.x) / c22 + 0.5); - p1.y = (int)((c1y - c10 * p0.y - c12 * p3.y - c13 * p3.y) / c11 + 0.5); - } else if (dir1.y == 0 && dir2.y == 0) { - // cramer's rule - double D = c11 * c22 - c12 * c21; - p1.x = (int)(((c1x - c10 * p0.x - c13 * p3.x) * c22 - c12 * (c2x - c20 * p0.x - c23 * p3.x)) / D + 0.5); - p2.x = (int)((c11 * (c2x - c20 * p0.x - c23 * p3.x) - (c1x - c10 * p0.x - c13 * p3.x) * c21) / D + 0.5); - } else if (dir1.x == 0 && dir2.x == 0) { - // cramer's rule - double D = c11 * c22 - c12 * c21; - p1.y = (int)(((c1y - c10 * p0.y - c13 * p3.y) * c22 - c12 * (c2y - c20 * p0.y - c23 * p3.y)) / D + 0.5); - p2.y = (int)((c11 * (c2y - c20 * p0.y - c23 * p3.y) - (c1y - c10 * p0.y - c13 * p3.y) * c21) / D + 0.5); - } else { // must not happen - ASSERT(0); - return false; - } - - // check for "inside-out" beziers - CPoint dir3 = p1 - p0, dir4 = p2 - p3; - if ((dir1.x * dir3.x + dir1.y * dir3.y) <= 0 || (dir2.x * dir4.x + dir2.y * dir4.y) <= 0) { - return false; - } - - return true; -} - -int CVobSubImage::GrabSegment(int _start, const COutline& o, COutline& ret) -{ - ret.RemoveAll(); - - int len = int(o.pa.GetCount()); - - int cur = (_start) % len, first = -1, last = -1; - int lastDir = 0; - - for (ptrdiff_t i = 0; i < len; i++) { - cur = (cur + 1) % len; - - if (o.da[cur] == 0) { - continue; - } - - if (first == -1) { - first = cur; - } - - if (lastDir == o.da[cur]) { - CPoint startp = o.pa[first] + o.pa[_start]; - startp.x >>= 1; - startp.y >>= 1; - CPoint endp = o.pa[last] + o.pa[cur]; - endp.x >>= 1; - endp.y >>= 1; - - if (first < _start) { - first += len; - } - _start = ((_start + first) >> 1) + 1; - if (_start >= len) { - _start -= len; - } - if (cur < last) { - cur += len; - } - cur = ((last + cur + 1) >> 1); - if (cur >= len) { - cur -= len; - } - - ret.Add(startp, 0); - - while (_start != cur) { - ret.Add(o.pa[_start], o.da[_start]); - - _start++; - if (_start >= len) { - _start -= len; - } - } - - ret.Add(endp, 0); - - return last; - } - - lastDir = o.da[cur]; - last = cur; - } - - ASSERT(0); - - return _start; -} - -void CVobSubImage::SplitOutline(const COutline& o, COutline& o1, COutline& o2) -{ - size_t len = o.pa.GetCount(); - if (len < 4) { - return; - } - - CAtlArray la, sa, ea; - - size_t i, j, k; - - for (i = 0, j = 0; j < len; j++) { - if (j + 1 == len || o.da[j]) { - la.Add(unsigned int(j - i)); - sa.Add(unsigned int(i)); - ea.Add(unsigned int(j)); - i = j; - } - } - - size_t maxlen = 0, maxidx = SIZE_T_ERROR; - size_t maxlen2 = 0, maxidx2 = SIZE_T_ERROR; - - for (i = 0; i < la.GetCount(); i++) { - if (maxlen < la[i]) { - maxlen = la[i]; - maxidx = i; - } - - if (maxlen2 < la[i] && i > 0 && i < la.GetCount() - 1) { - maxlen2 = la[i]; - maxidx2 = i; - } - } - - ASSERT(maxidx != SIZE_T_ERROR && maxidx2 != SIZE_T_ERROR); - - if (maxlen == maxlen2) { - maxidx = maxidx2; // if equal choose the inner section - } - - j = (sa[maxidx] + ea[maxidx]) >> 1, k = (sa[maxidx] + ea[maxidx] + 1) >> 1; - - o1.RemoveAll(); - o2.RemoveAll(); - - for (i = 0; i <= j; i++) { - o1.Add(o.pa[i], o.da[i]); - } - - if (j != k) { - CPoint mid = o.pa[j] + o.pa[k]; - mid.x >>= 1; - mid.y >>= 1; - o1.Add(mid, 0); - o2.Add(mid, 0); - } - - for (i = k; i < len; i++) { - o2.Add(o.pa[i], o.da[i]); - } -} - -void CVobSubImage::AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints) -{ - int i, len = int(o.pa.GetCount()); - if (len < 3) { - return; - } - - int nLeftTurns = 0, nRightTurns = 0; - - for (i = 0; i < len; i++) { - if (o.da[i] == -1) { - nLeftTurns++; - } else if (o.da[i] == 1) { - nRightTurns++; - } - } - - if (nLeftTurns == 0 && nRightTurns == 0) { // line - pathTypes.Add(PT_LINETO); - pathPoints.Add(o.pa[len - 1]); - - return; - } - - if (nLeftTurns == 0 || nRightTurns == 0) { // b-spline - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); - - for (i = 0; i < 3; i++) { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[i]); - } - - for (; i < len; i++) { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[i]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[len - 1]); - - return; - } - - int _start, _end; - if (FitLine(o, _start, _end)) { // b-spline, line, b-spline - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); - - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[0]); - - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[1]); - - CPoint p[4], pp, d = o.pa[_end] - o.pa[_start]; - double l = sqrt((double)(d.x * d.x + d.y * d.y)), dx = 1.0 * d.x / l, dy = 1.0 * d.y / l; - - pp = o.pa[_start] - o.pa[_start - 1]; - double l1 = abs(pp.x) + abs(pp.y); - pp = o.pa[_end] - o.pa[_end + 1]; - double l2 = abs(pp.x) + abs(pp.y); - p[0] = CPoint((int)(1.0 * o.pa[_start].x + dx * l1 + 0.5), (int)(1.0 * o.pa[_start].y + dy * l1 + 0.5)); - p[1] = CPoint((int)(1.0 * o.pa[_start].x + dx * l1 * 2 + 0.5), (int)(1.0 * o.pa[_start].y + dy * l1 * 2 + 0.5)); - p[2] = CPoint((int)(1.0 * o.pa[_end].x - dx * l2 * 2 + 0.5), (int)(1.0 * o.pa[_end].y - dy * l2 * 2 + 0.5)); - p[3] = CPoint((int)(1.0 * o.pa[_end].x - dx * l2 + 0.5), (int)(1.0 * o.pa[_end].y - dy * l2 + 0.5)); - - if (_start == 1) { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(p[0]); - } else { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[2]); - - for (ptrdiff_t k = 3; k <= _start; k++) { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[k]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[0]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[1]); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(p[0]); - - pathTypes.Add(PT_LINETO); - pathPoints.Add(p[3]); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(p[2]); - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[3]); - - for (i = _end; i < len; i++) { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[i]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[len - 1]); - - return; - } - - CPoint p1, p2; - if (FitBezierVH(o, p1, p2)) { // bezier - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(p1); - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(p2); - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(o.pa[o.pa.GetCount() - 1]); - - return; - } - - COutline o1, o2; - SplitOutline(o, o1, o2); - AddSegment(o1, pathTypes, pathPoints); - AddSegment(o2, pathTypes, pathPoints); -} - -bool CVobSubImage::Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool bSmooth, int scale) -{ - CPoint topleft; - CAutoPtr> ol(GetOutlineList(topleft)); - if (!ol) { - return false; - } - - POSITION pos; - - pos = ol->GetHeadPosition(); - while (pos) { - CAtlArray& pa = ol->GetNext(pos)->pa; - for (size_t i = 0; i < pa.GetCount(); i++) { - pa[i].x = (pa[i].x - topleft.x) << scale; - pa[i].y = (pa[i].y - topleft.y) << scale; - } - } - - pos = ol->GetHeadPosition(); - while (pos) { - COutline& o = *ol->GetNext(pos), o2; - - if (bSmooth) { - int i = 0, iFirst = -1; - - for (;;) { - i = GrabSegment(i, o, o2); - - if (i == iFirst) { - break; - } - - if (iFirst < 0) { - iFirst = i; - pathTypes.Add(PT_MOVETO); - pathPoints.Add(o2.pa[0]); - } - - AddSegment(o2, pathTypes, pathPoints); - } - } else { - /* - for (ptrdiff_t i = 1, len = o.pa.GetSize(); i < len; i++) - { - if (int dir = o.da[i-1]) - { - CPoint dir2 = o.pa[i] - o.pa[i-1]; - dir2.x /= 2; dir2.y /= 2; - CPoint dir1 = dir > 0 ? CPoint(dir2.y, -dir2.x) : CPoint(-dir2.y, dir2.x); - i = i; - o.pa[i-1] -= dir1; - o.pa.InsertAt(i, o.pa[i-1] + dir2); - o.da.InsertAt(i, -dir); - o.pa.InsertAt(i+1, o.pa[i] + dir1); - o.da.InsertAt(i+1, dir); - i += 2; - len += 2; - } - } - */ - pathTypes.Add(PT_MOVETO); - pathPoints.Add(o.pa[0]); - - for (size_t i = 1, len = o.pa.GetCount(); i < len; i++) { - pathTypes.Add(PT_LINETO); - pathPoints.Add(o.pa[i]); - } - } - } - - return !pathTypes.IsEmpty(); -} - -bool CVobSubImage::Polygonize(CStringW& assstr, bool bSmooth, int scale) -{ - CAtlArray pathTypes; - CAtlArray pathPoints; - - if (!Polygonize(pathTypes, pathPoints, bSmooth, scale)) { - return false; - } - - assstr.Format(L"{\\an7\\pos(%d,%d)\\p%d}", rect.left, rect.top, 1 + scale); - // assstr.Format(L"{\\p%d}", 1+scale); - - BYTE lastType = 0; - - size_t nPoints = pathTypes.GetCount(); - - for (size_t i = 0; i < nPoints; i++) { - CStringW s; - - switch (pathTypes[i]) { - case PT_MOVETO: - if (lastType != PT_MOVETO) { - assstr += L"m "; - } - s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_MOVETONC: - if (lastType != PT_MOVETONC) { - assstr += L"n "; - } - s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_LINETO: - if (lastType != PT_LINETO) { - assstr += L"l "; - } - s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_BEZIERTO: - if (i + 2 < nPoints) { - if (lastType != PT_BEZIERTO) { - assstr += L"b "; - } - s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); - i += 2; - } - break; - case PT_BSPLINETO: - if (i + 2 < nPoints) { - if (lastType != PT_BSPLINETO) { - assstr += L"s "; - } - s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); - i += 2; - } - break; - case PT_BSPLINEPATCHTO: - if (lastType != PT_BSPLINEPATCHTO) { - assstr += L"p "; - } - s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); - break; - } - - lastType = pathTypes[i]; - - assstr += s; - } - - assstr += L"{\\p0}"; - - return nPoints > 0; -} - -void CVobSubImage::Scale2x() -{ - int w = rect.Width(), h = rect.Height(); - - if (w > 0 && h > 0) { - DWORD* src = (DWORD*)lpPixels; - DWORD* dst = DEBUG_NEW DWORD[w * h]; - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++, src++, dst++) { - DWORD E = *src; - - DWORD A = x > 0 && y > 0 ? src[-w - 1] : E; - DWORD B = y > 0 ? src[-w] : E; - DWORD C = x < w - 1 && y > 0 ? src[-w + 1] : E; - UNREFERENCED_PARAMETER(A); - UNREFERENCED_PARAMETER(C); - - DWORD D = x > 0 ? src[-1] : E; - DWORD F = x < w - 1 ? src[+1] : E; - - DWORD G = x > 0 && y < h - 1 ? src[+w - 1] : E; - DWORD H = y < h - 1 ? src[+w] : E; - DWORD I = x < w - 1 && y < h - 1 ? src[+w + 1] : E; - UNREFERENCED_PARAMETER(G); - UNREFERENCED_PARAMETER(I); - - DWORD E0 = D == B && B != F && D != H ? D : E; - DWORD E1 = B == F && B != D && F != H ? F : E; - DWORD E2 = D == H && D != B && H != F ? D : E; - DWORD E3 = H == F && D != H && B != F ? F : E; - - *dst = ((((E0 & 0x00ff00ff) + (E1 & 0x00ff00ff) + (E2 & 0x00ff00ff) + (E3 & 0x00ff00ff) + 2) >> 2) & 0x00ff00ff) - | (((((E0 >> 8) & 0x00ff00ff) + ((E1 >> 8) & 0x00ff00ff) + ((E2 >> 8) & 0x00ff00ff) + ((E3 >> 8) & 0x00ff00ff) + 2) << 6) & 0xff00ff00); - } - } - - src -= w * h; - dst -= w * h; - - memcpy(src, dst, w * h * 4); - - delete [] dst; - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "VobSubImage.h" +#include "RTS.h" +#include +#include + +CVobSubImage::CVobSubImage() + : org(CSize(0, 0)) + , lpTemp1(nullptr) + , lpTemp2(nullptr) + , nPlane(0) + , bCustomPal(false) + , bAligned(true) + , tridx(0) + , orgpal(nullptr) + , cuspal(nullptr) + , nLang(SIZE_T_ERROR) + , nIdx(SIZE_T_ERROR) + , bForced(false) + , bAnimated(false) + , tCurrent(-1) + , start(0) + , delay(0) + , rect(CRect(0, 0, 0, 0)) + , lpPixels(nullptr) +{ + ZeroMemory(&pal, sizeof(pal)); +} + +CVobSubImage::~CVobSubImage() +{ + Free(); +} + +bool CVobSubImage::Alloc(int w, int h) +{ + // if there is nothing to crop TrimSubImage might even add a 1 pixel + // wide border around the text, that's why we need a bit more memory + // to be allocated. + + if (lpTemp1 == nullptr || w * h > org.cx * org.cy || (w + 2) * (h + 2) > (org.cx + 2) * (org.cy + 2)) { + Free(); + + try { + lpTemp1 = DEBUG_NEW RGBQUAD[w * h]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + return false; + } + + try { + lpTemp2 = DEBUG_NEW RGBQUAD[(w + 2) * (h + 2)]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + delete [] lpTemp1; + lpTemp1 = nullptr; + return false; + } + + org.cx = w; + org.cy = h; + } + + lpPixels = lpTemp1; + + return true; +} + +void CVobSubImage::Free() +{ + SAFE_DELETE_ARRAY(lpTemp1); + SAFE_DELETE_ARRAY(lpTemp2); + + lpPixels = nullptr; +} + +bool CVobSubImage::Decode(BYTE* _lpData, size_t _packetSize, size_t _dataSize, int _t, + bool _bCustomPal, + int _tridx, + RGBQUAD* _orgpal /*[16]*/, RGBQUAD* _cuspal /*[4]*/, + bool _bTrim) +{ + GetPacketInfo(_lpData, _packetSize, _dataSize, _t); + + if (!Alloc(rect.Width(), rect.Height())) { + return false; + } + + lpPixels = lpTemp1; + + nPlane = 0; + bAligned = true; + + bCustomPal = _bCustomPal; + orgpal = _orgpal; + tridx = _tridx; + cuspal = _cuspal; + + CPoint p = rect.TopLeft(); + + size_t end[] = { nOffset[1], _dataSize }; + + while (nOffset[nPlane] < end[nPlane]) { + DWORD code; + + if ((code = GetNibble(_lpData)) >= 0x4 + || (code = (code << 4) | GetNibble(_lpData)) >= 0x10 + || (code = (code << 4) | GetNibble(_lpData)) >= 0x40 + || (code = (code << 4) | GetNibble(_lpData)) >= 0x100) { + DrawPixels(p, code >> 2, code & 3); + if ((p.x += code >> 2) < rect.right) { + continue; + } + } + + DrawPixels(p, rect.right - p.x, code & 3); + + if (!bAligned) { + GetNibble(_lpData); // align to byte + } + + p.x = rect.left; + p.y++; + nPlane = 1 - nPlane; + } + + rect.bottom = std::min(p.y, rect.bottom); + + if (_bTrim) { + TrimSubImage(); + } + + return true; +} + +void CVobSubImage::GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t /*= INT_MAX*/) +{ + // delay = 0; + + size_t i, nextctrlblk = dataSize; + WORD _pal = 0, tr = 0; + WORD nPal = 0, nTr = 0; + + do { + i = nextctrlblk; + + tCurrent = 1024 * ((lpData[i] << 8) | lpData[i + 1]) / 90; + i += 2; + nextctrlblk = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + + if (nextctrlblk > packetSize || nextctrlblk < dataSize) { + ASSERT(0); + return; + } + + if (tCurrent > t) { + break; + } + + bool bBreak = false; + + while (!bBreak) { + size_t len = 0; + + switch (lpData[i]) { + case 0x00: + len = 0; + break; + case 0x01: + len = 0; + break; + case 0x02: + len = 0; + break; + case 0x03: + len = 2; + break; + case 0x04: + len = 2; + break; + case 0x05: + len = 6; + break; + case 0x06: + len = 4; + break; + default: + len = 0; + break; + } + + if (i + len >= packetSize) { + TRACE(_T("Warning: Wrong subpicture parameter block ending\n")); + break; + } + + switch (lpData[i++]) { + case 0x00: // forced start displaying + bForced = true; + break; + case 0x01: // start displaying + bForced = false; + break; + case 0x02: // stop displaying + delay = tCurrent; + break; + case 0x03: + _pal = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + nPal++; + break; + case 0x04: + tr = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + nTr++; + //tr &= 0x00f0; + break; + case 0x05: + rect = CRect((lpData[i] << 4) + (lpData[i + 1] >> 4), + (lpData[i + 3] << 4) + (lpData[i + 4] >> 4), + ((lpData[i + 1] & 0x0f) << 8) + lpData[i + 2] + 1, + ((lpData[i + 4] & 0x0f) << 8) + lpData[i + 5] + 1); + i += 6; + break; + case 0x06: + nOffset[0] = (lpData[i] << 8) + lpData[i + 1]; + i += 2; + nOffset[1] = (lpData[i] << 8) + lpData[i + 1]; + i += 2; + break; + case 0xff: // end of ctrlblk + bBreak = true; + continue; + default: // skip this ctrlblk + bBreak = true; + break; + } + } + } while (i <= nextctrlblk && i < packetSize); + + for (i = 0; i < 4; i++) { + this->pal[i].pal = (_pal >> (i << 2)) & 0xf; + this->pal[i].tr = (tr >> (i << 2)) & 0xf; + } + + bAnimated = (nPal > 1 || nTr > 1); +} + +BYTE CVobSubImage::GetNibble(const BYTE* lpData) +{ + size_t& off = nOffset[nPlane]; + BYTE ret = lpData[off]; + if (bAligned) { + ret >>= 4; + } + ret &= 0x0f; + bAligned = !bAligned; + if (bAligned) { + off++; + } + return ret; +} + +void CVobSubImage::DrawPixels(CPoint p, int length, size_t colorId) +{ + if (length <= 0 + || p.x + length < rect.left + || p.x >= rect.right + || p.y < rect.top + || p.y >= rect.bottom) { + return; + } + + if (p.x < rect.left) { + p.x = rect.left; + } + if (p.x + length >= rect.right) { + length = rect.right - p.x; + } + + RGBQUAD* ptr = &lpPixels[rect.Width() * (p.y - rect.top) + (p.x - rect.left)]; + + RGBQUAD c; + + if (!bCustomPal) { + c = orgpal[pal[colorId].pal]; + c.rgbReserved = (pal[colorId].tr << 4) | pal[colorId].tr; + } else { + c = cuspal[colorId]; + } + + while (length-- > 0) { + *ptr++ = c; + } +} + +void CVobSubImage::TrimSubImage() +{ + CRect r; + r.left = rect.Width(); + r.top = rect.Height(); + r.right = 0; + r.bottom = 0; + + RGBQUAD* ptr = lpTemp1; + + for (int j = 0, y = rect.Height(); j < y; j++) { + for (int i = 0, x = rect.Width(); i < x; i++, ptr++) { + if (ptr->rgbReserved) { + if (r.top > j) { + r.top = j; + } + if (r.bottom < j) { + r.bottom = j; + } + if (r.left > i) { + r.left = i; + } + if (r.right < i) { + r.right = i; + } + } + } + } + + if (r.left > r.right || r.top > r.bottom) { + return; + } + + r += CRect(0, 0, 1, 1); + + r &= CRect(CPoint(0, 0), rect.Size()); + + int w = r.Width(), h = r.Height(); + + DWORD offset = r.top * rect.Width() + r.left; + + r += CRect(1, 1, 1, 1); + + DWORD* src = (DWORD*)&lpTemp1[offset]; + DWORD* dst = (DWORD*)&lpTemp2[1 + w + 1]; + + ZeroMemory(lpTemp2, (1 + w + 1)*sizeof(RGBQUAD)); + + for (int height = h; height; height--, src += rect.Width()) { + *dst++ = 0; + memcpy(dst, src, w * sizeof(RGBQUAD)); + dst += w; + *dst++ = 0; + } + + ZeroMemory(dst, (1 + w + 1)*sizeof(RGBQUAD)); + + lpPixels = lpTemp2; + + rect = r + rect.TopLeft(); +} + +//////////////////////////////// + +#define GP(xx, yy) (((xx) < 0 || (yy) < 0 || (xx) >= w || (yy) >= h) ? 0 : p[(yy) * w + (xx)]) + +CAutoPtrList* CVobSubImage::GetOutlineList(CPoint& topleft) +{ + int w = rect.Width(), h = rect.Height(), len = w * h; + if (len <= 0) { + return nullptr; + } + + CAutoVectorPtr p; + if (!p.Allocate(len)) { + return nullptr; + } + + CAutoPtrList* ol; + try { + ol = DEBUG_NEW CAutoPtrList(); + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + return nullptr; + } + + BYTE* cp = p; + RGBQUAD* rgbp = (RGBQUAD*)lpPixels; + + for (int i = 0; i < len; i++, cp++, rgbp++) { + *cp = !!rgbp->rgbReserved; + } + + enum { UP, RIGHT, DOWN, LEFT }; + + topleft.x = topleft.y = INT_MAX; + + for (;;) { + cp = p; + + int x = 0; + int y = 0; + + for (y = 0; y < h; y++) { + for (x = 0; x < w - 1; x++, cp++) { + if (cp[0] == 0 && cp[1] == 1) { + break; + } + } + + if (x < w - 1) { + break; + } + + cp++; + } + + if (y == h) { + break; + } + + int dir = UP; + + int ox = x, oy = y, odir = dir; + + CAutoPtr o; + try { + o.Attach(DEBUG_NEW COutline); + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + break; + } + + do { + CPoint pp; + BYTE fl = 0; + BYTE fr = 0; + BYTE br = 0; + + int prevdir = dir; + + switch (prevdir) { + case UP: + pp = CPoint(x + 1, y); + fl = GP(x, y - 1); + fr = GP(x + 1, y - 1); + br = GP(x + 1, y); + break; + case RIGHT: + pp = CPoint(x + 1, y + 1); + fl = GP(x + 1, y); + fr = GP(x + 1, y + 1); + br = GP(x, y + 1); + break; + case DOWN: + pp = CPoint(x, y + 1); + fl = GP(x, y + 1); + fr = GP(x - 1, y + 1); + br = GP(x - 1, y); + break; + case LEFT: + pp = CPoint(x, y); + fl = GP(x - 1, y); + fr = GP(x - 1, y - 1); + br = GP(x, y - 1); + break; + } + + // turning left if: + // o . | o . + // ^ o | < o + // turning right if: + // x x | x > + // ^ o | x o + // + // o set, x empty, . can be anything + + if (fl == 1) { + dir = (dir - 1 + 4) & 3; + } else if (fl != 1 && fr != 1 && br == 1) { + dir = (dir + 1) & 3; + } else if (p[y * w + x] & 16) { + ASSERT(0); // we are going around in one place (this must not happen if the starting conditions were correct) + break; + } + + p[y * w + x] = (p[y * w + x] << 1) | 2; // increase turn count (== log2(highordbit(*p))) + + switch (dir) { + case UP: + if (prevdir == LEFT) { + x--; + y--; + } + if (prevdir == UP) { + y--; + } + break; + case RIGHT: + if (prevdir == UP) { + x++; + y--; + } + if (prevdir == RIGHT) { + x++; + } + break; + case DOWN: + if (prevdir == RIGHT) { + x++; + y++; + } + if (prevdir == DOWN) { + y++; + } + break; + case LEFT: + if (prevdir == DOWN) { + x--; + y++; + } + if (prevdir == LEFT) { + x--; + } + break; + } + + int d = dir - prevdir; + o->Add(pp, d == 3 ? -1 : d == -3 ? 1 : d); + + if (topleft.x > pp.x) { + topleft.x = pp.x; + } + if (topleft.y > pp.y) { + topleft.y = pp.y; + } + } while (!(x == ox && y == oy && dir == odir)); + + if (!o->pa.IsEmpty() && (x == ox && y == oy && dir == odir)) { + ol->AddTail(o); + } else { + ASSERT(0); + } + } + + return ol; +} + +static bool FitLine(const COutline& o, int& start, int& end) +{ + int len = (int)o.pa.GetCount(); + if (len < 7) { + return false; // small segments should be handled with beziers... + } + + for (start = 0; start < len && !o.da[start]; start++) { + ; + } + for (end = len - 1; end > start && !o.da[end]; end--) { + ; + } + + if (end - start < 8 || end - start < (len - end) + (start - 0)) { + return false; + } + + CUIntArray la, ra; + + UINT i, j, k; + + for (i = start + 1, j = end, k = start; i <= j; i++) { + if (!o.da[i]) { + continue; + } + if (o.da[i] == o.da[k]) { + return false; + } + if (o.da[i] == -1) { + la.Add(i - k); + } else { + ra.Add(i - k); + } + k = i; + } + + bool fl = true, fr = true; + + // these tests are completly heuristic and might be redundant a bit... + + for (i = 0, j = (UINT)la.GetSize(); i < j && fl; i++) { + if (la[i] != 1) { + fl = false; + } + } + for (i = 0, j = (UINT)ra.GetSize(); i < j && fr; i++) { + if (ra[i] != 1) { + fr = false; + } + } + + if (!fl && !fr) { + return false; // can't be a line if there are bigger steps than one in both directions (lines are usually drawn by stepping one either horizontally or vertically) + } + if (fl && fr && 1.0 * (end - start) / ((len - end) * 2 + (start - 0) * 2) > 0.4) { + return false; // if this section is relatively too small it may only be a rounded corner + } + if (!fl && !la.IsEmpty() && la.GetSize() <= 4 && (la[0] == 1 && la[la.GetSize() - 1] == 1)) { + return false; // one step at both ends, doesn't sound good for a line (may be it was skewed, so only eliminate smaller sections where beziers going to look just as good) + } + if (!fr && !ra.IsEmpty() && ra.GetSize() <= 4 && (ra[0] == 1 && ra[ra.GetSize() - 1] == 1)) { + return false; // -''- + } + + CUIntArray& a = !fl ? la : ra; + + len = (int)a.GetSize(); + + int sum = 0; + + for (i = 0, j = INT_MAX, k = 0; i < (UINT)len; i++) { + if (j > a[i]) { + j = a[i]; + } + if (k < a[i]) { + k = a[i]; + } + sum += a[i]; + } + + if (k - j > 2 && 1.0 * sum / len < 2) { + return false; + } + if (k - j > 2 && 1.0 * sum / len >= 2 && len < 4) { + return false; + } + + if ((la.GetSize() / 2 + ra.GetSize() / 2) / 2 <= 2) { + if ((k + j) / 2 < 2 && k * j != 1) { + return false; + } + } + + double err = 0; + + CPoint sp = o.pa[start], ep = o.pa[end]; + + double minerr = 0, maxerr = 0; + + double vx = ep.x - sp.x, vy = ep.y - sp.y, l = sqrt(vx * vx + vy * vy); + vx /= l; + vy /= l; + + for (i = start + 1, j = end - 1; i <= j; i++) { + CPoint p = o.pa[i], dp = p - sp; + double t = vx * dp.x + vy * dp.y, dx = vx * t + sp.x - p.x, dy = vy * t + sp.y - p.y; + t = dx * dx + dy * dy; + err += t; + t = sqrt(t); + if (vy * dx - dy * vx < 0) { + if (minerr > -t) { + minerr = -t; + } + } else { + if (maxerr < t) { + maxerr = t; + } + } + } + + return ((maxerr - minerr) / l < 0.1 || err / l < 1.5 || (fabs(maxerr) < 8 && fabs(minerr) < 8)); +} + +static int CalcPossibleCurveDegree(const COutline& o) +{ + size_t len2 = o.da.GetCount(); + + CUIntArray la; + + for (size_t i = 0, j = 0; j < len2; j++) { + if (j + 1 == len2 || o.da[j]) { + la.Add(UINT(j - i)); + i = j; + } + } + + ptrdiff_t len = la.GetCount(); + + int ret = 0; + + // check if we can find a reason to add a penalty degree, or two :P + // it is mainly about looking for distant corners + { + int penalty = 0; + + int ma[2] = {0, 0}; + for (ptrdiff_t i = 0; i < len; i++) { + ma[i & 1] += la[i]; + } + + int ca[2] = {ma[0], ma[1]}; + for (ptrdiff_t i = 0; i < len; i++) { + ca[i & 1] -= la[i]; + + double c1 = 1.0 * ca[0] / ma[0], c2 = 1.0 * ca[1] / ma[1], c3 = 1.0 * la[i] / ma[i & 1]; + + if (len2 > 16 && (fabs(c1 - c2) > 0.7 || (c3 > 0.6 && la[i] > 5))) { + penalty = 2; + break; + } + + if (fabs(c1 - c2) > 0.6 || (c3 > 0.4 && la[i] > 5)) { + penalty = 1; + } + } + + ret += penalty; + } + + la[0] <<= 1; + la[len - 1] <<= 1; + + for (ptrdiff_t i = 0; i < len; i += 2) { + if (la[i] > 1) { + ret++; // prependicular to the last chosen section and bigger then 1 -> add a degree and continue with the other dir + i--; + } + } + + return ret; +} + +inline double vectlen(CPoint p) +{ + return sqrt((double)(p.x * p.x + p.y * p.y)); +} + +inline double vectlen(CPoint p1, CPoint p2) +{ + return vectlen(p2 - p1); +} + +static bool MinMaxCosfi(COutline& o, double& mincf, double& maxcf) // not really cosfi, it is weighted by the distance from the segment endpoints, and since it would be always between -1 and 0, the applied sign marks side +{ + CAtlArray& pa = o.pa; + + int len = (int)pa.GetCount(); + if (len < 6) { + return false; + } + + mincf = 1; + maxcf = -1; + + CPoint p = pa[len - 1] - pa[0]; + double l = vectlen(p); + UNREFERENCED_PARAMETER(l); + + for (ptrdiff_t i = 2; i < len - 2; i++) { // skip the endpoints, they aren't accurate + CPoint p1 = pa[0] - pa[i], p2 = pa[len - 1] - pa[i]; + double l1 = vectlen(p1), l2 = vectlen(p2); + int sign = p1.x * p.y - p1.y * p.x >= 0 ? 1 : -1; + + double c = (1.0 * len / 2 - fabs(i - 1.0 * len / 2)) / len * 2; // c: 0 -> 1 -> 0 + + double cosfi = (1 + (p1.x * p2.x + p1.y * p2.y) / (l1 * l2)) * sign * c; + if (mincf > cosfi) { + mincf = cosfi; + } + if (maxcf < cosfi) { + maxcf = cosfi; + } + } + + return true; +} + +static bool FitBezierVH(COutline& o, CPoint& p1, CPoint& p2) +{ + int i; + + CAtlArray& pa = o.pa; + + int len = (int)pa.GetCount(); + + if (len <= 1) { + return false; + } else if (len == 2) { + CPoint mid = pa[0] + pa[1]; + mid.x >>= 1; + mid.y >>= 1; + p1 = p2 = mid; + return true; + } + + CPoint dir1 = pa[1] - pa[0], dir2 = pa[len - 2] - pa[len - 1]; + if ((dir1.x && dir1.y) || (dir2.x && dir2.y)) { + return false; // we are only fitting beziers with hor./ver. endings + } + + if (CalcPossibleCurveDegree(o) > 3) { + return false; + } + + double mincf, maxcf; + if (MinMaxCosfi(o, mincf, maxcf)) { + if (maxcf - mincf > 0.8 + || maxcf - mincf > 0.6 && (maxcf >= 0.4 || mincf <= -0.4)) { + return false; + } + } + + CPoint p0 = p1 = pa[0]; + CPoint p3 = p2 = pa[len - 1]; + + CAtlArray pl; + pl.SetCount(len); + + double c10 = 0, c11 = 0, c12 = 0, c13 = 0, c1x = 0, c1y = 0; + double c20 = 0, c21 = 0, c22 = 0, c23 = 0, c2x = 0, c2y = 0; + double length = 0; + + for (pl[0] = 0, i = 1; i < len; i++) { + CPoint diff = (pa[i] - pa[i - 1]); + pl[i] = (length += sqrt((double)(diff.x * diff.x + diff.y * diff.y))); + } + + for (i = 0; i < len; i++) { + double t1 = pl[i] / length; + double t2 = t1 * t1; + double t3 = t2 * t1; + double it1 = 1 - t1; + double it2 = it1 * it1; + double it3 = it2 * it1; + + double dc1 = 3.0 * it2 * t1; + double dc2 = 3.0 * it1 * t2; + + c10 += it3 * dc1; + c11 += dc1 * dc1; + c12 += dc2 * dc1; + c13 += t3 * dc1; + c1x += pa[i].x * dc1; + c1y += pa[i].y * dc1; + + c20 += it3 * dc2; + c21 += dc1 * dc2; + c22 += dc2 * dc2; + c23 += t3 * dc2; + c2x += pa[i].x * dc2; + c2y += pa[i].y * dc2; + } + + if (dir1.y == 0 && dir2.x == 0) { + p1.x = (int)((c1x - c10 * p0.x - c12 * p3.x - c13 * p3.x) / c11 + 0.5); + p2.y = (int)((c2y - c20 * p0.y - c21 * p0.y - c23 * p3.y) / c22 + 0.5); + } else if (dir1.x == 0 && dir2.y == 0) { + p2.x = (int)((c2x - c20 * p0.x - c21 * p0.x - c23 * p3.x) / c22 + 0.5); + p1.y = (int)((c1y - c10 * p0.y - c12 * p3.y - c13 * p3.y) / c11 + 0.5); + } else if (dir1.y == 0 && dir2.y == 0) { + // cramer's rule + double D = c11 * c22 - c12 * c21; + p1.x = (int)(((c1x - c10 * p0.x - c13 * p3.x) * c22 - c12 * (c2x - c20 * p0.x - c23 * p3.x)) / D + 0.5); + p2.x = (int)((c11 * (c2x - c20 * p0.x - c23 * p3.x) - (c1x - c10 * p0.x - c13 * p3.x) * c21) / D + 0.5); + } else if (dir1.x == 0 && dir2.x == 0) { + // cramer's rule + double D = c11 * c22 - c12 * c21; + p1.y = (int)(((c1y - c10 * p0.y - c13 * p3.y) * c22 - c12 * (c2y - c20 * p0.y - c23 * p3.y)) / D + 0.5); + p2.y = (int)((c11 * (c2y - c20 * p0.y - c23 * p3.y) - (c1y - c10 * p0.y - c13 * p3.y) * c21) / D + 0.5); + } else { // must not happen + ASSERT(0); + return false; + } + + // check for "inside-out" beziers + CPoint dir3 = p1 - p0, dir4 = p2 - p3; + if ((dir1.x * dir3.x + dir1.y * dir3.y) <= 0 || (dir2.x * dir4.x + dir2.y * dir4.y) <= 0) { + return false; + } + + return true; +} + +int CVobSubImage::GrabSegment(int _start, const COutline& o, COutline& ret) +{ + ret.RemoveAll(); + + int len = int(o.pa.GetCount()); + + int cur = (_start) % len, first = -1, last = -1; + int lastDir = 0; + + for (ptrdiff_t i = 0; i < len; i++) { + cur = (cur + 1) % len; + + if (o.da[cur] == 0) { + continue; + } + + if (first == -1) { + first = cur; + } + + if (lastDir == o.da[cur]) { + CPoint startp = o.pa[first] + o.pa[_start]; + startp.x >>= 1; + startp.y >>= 1; + CPoint endp = o.pa[last] + o.pa[cur]; + endp.x >>= 1; + endp.y >>= 1; + + if (first < _start) { + first += len; + } + _start = ((_start + first) >> 1) + 1; + if (_start >= len) { + _start -= len; + } + if (cur < last) { + cur += len; + } + cur = ((last + cur + 1) >> 1); + if (cur >= len) { + cur -= len; + } + + ret.Add(startp, 0); + + while (_start != cur) { + ret.Add(o.pa[_start], o.da[_start]); + + _start++; + if (_start >= len) { + _start -= len; + } + } + + ret.Add(endp, 0); + + return last; + } + + lastDir = o.da[cur]; + last = cur; + } + + ASSERT(0); + + return _start; +} + +void CVobSubImage::SplitOutline(const COutline& o, COutline& o1, COutline& o2) +{ + size_t len = o.pa.GetCount(); + if (len < 4) { + return; + } + + CAtlArray la, sa, ea; + + size_t i, j, k; + + for (i = 0, j = 0; j < len; j++) { + if (j + 1 == len || o.da[j]) { + la.Add(unsigned int(j - i)); + sa.Add(unsigned int(i)); + ea.Add(unsigned int(j)); + i = j; + } + } + + size_t maxlen = 0, maxidx = SIZE_T_ERROR; + size_t maxlen2 = 0, maxidx2 = SIZE_T_ERROR; + + for (i = 0; i < la.GetCount(); i++) { + if (maxlen < la[i]) { + maxlen = la[i]; + maxidx = i; + } + + if (maxlen2 < la[i] && i > 0 && i < la.GetCount() - 1) { + maxlen2 = la[i]; + maxidx2 = i; + } + } + + ASSERT(maxidx != SIZE_T_ERROR && maxidx2 != SIZE_T_ERROR); + + if (maxlen == maxlen2) { + maxidx = maxidx2; // if equal choose the inner section + } + + j = (sa[maxidx] + ea[maxidx]) >> 1, k = (sa[maxidx] + ea[maxidx] + 1) >> 1; + + o1.RemoveAll(); + o2.RemoveAll(); + + for (i = 0; i <= j; i++) { + o1.Add(o.pa[i], o.da[i]); + } + + if (j != k) { + CPoint mid = o.pa[j] + o.pa[k]; + mid.x >>= 1; + mid.y >>= 1; + o1.Add(mid, 0); + o2.Add(mid, 0); + } + + for (i = k; i < len; i++) { + o2.Add(o.pa[i], o.da[i]); + } +} + +void CVobSubImage::AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints) +{ + int i, len = int(o.pa.GetCount()); + if (len < 3) { + return; + } + + int nLeftTurns = 0, nRightTurns = 0; + + for (i = 0; i < len; i++) { + if (o.da[i] == -1) { + nLeftTurns++; + } else if (o.da[i] == 1) { + nRightTurns++; + } + } + + if (nLeftTurns == 0 && nRightTurns == 0) { // line + pathTypes.Add(PT_LINETO); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + if (nLeftTurns == 0 || nRightTurns == 0) { // b-spline + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); + + for (i = 0; i < 3; i++) { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[i]); + } + + for (; i < len; i++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[i]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + int _start, _end; + if (FitLine(o, _start, _end)) { // b-spline, line, b-spline + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); + + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[0]); + + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[1]); + + CPoint p[4], pp, d = o.pa[_end] - o.pa[_start]; + double l = sqrt((double)(d.x * d.x + d.y * d.y)), dx = 1.0 * d.x / l, dy = 1.0 * d.y / l; + + pp = o.pa[_start] - o.pa[_start - 1]; + double l1 = abs(pp.x) + abs(pp.y); + pp = o.pa[_end] - o.pa[_end + 1]; + double l2 = abs(pp.x) + abs(pp.y); + p[0] = CPoint((int)(1.0 * o.pa[_start].x + dx * l1 + 0.5), (int)(1.0 * o.pa[_start].y + dy * l1 + 0.5)); + p[1] = CPoint((int)(1.0 * o.pa[_start].x + dx * l1 * 2 + 0.5), (int)(1.0 * o.pa[_start].y + dy * l1 * 2 + 0.5)); + p[2] = CPoint((int)(1.0 * o.pa[_end].x - dx * l2 * 2 + 0.5), (int)(1.0 * o.pa[_end].y - dy * l2 * 2 + 0.5)); + p[3] = CPoint((int)(1.0 * o.pa[_end].x - dx * l2 + 0.5), (int)(1.0 * o.pa[_end].y - dy * l2 + 0.5)); + + if (_start == 1) { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(p[0]); + } else { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[2]); + + for (ptrdiff_t k = 3; k <= _start; k++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[k]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[0]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[1]); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(p[0]); + + pathTypes.Add(PT_LINETO); + pathPoints.Add(p[3]); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(p[2]); + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[3]); + + for (i = _end; i < len; i++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[i]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + CPoint p1, p2; + if (FitBezierVH(o, p1, p2)) { // bezier + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(p1); + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(p2); + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(o.pa[o.pa.GetCount() - 1]); + + return; + } + + COutline o1, o2; + SplitOutline(o, o1, o2); + AddSegment(o1, pathTypes, pathPoints); + AddSegment(o2, pathTypes, pathPoints); +} + +bool CVobSubImage::Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool bSmooth, int scale) +{ + CPoint topleft; + CAutoPtr> ol(GetOutlineList(topleft)); + if (!ol) { + return false; + } + + POSITION pos; + + pos = ol->GetHeadPosition(); + while (pos) { + CAtlArray& pa = ol->GetNext(pos)->pa; + for (size_t i = 0; i < pa.GetCount(); i++) { + pa[i].x = (pa[i].x - topleft.x) << scale; + pa[i].y = (pa[i].y - topleft.y) << scale; + } + } + + pos = ol->GetHeadPosition(); + while (pos) { + COutline& o = *ol->GetNext(pos), o2; + + if (bSmooth) { + int i = 0, iFirst = -1; + + for (;;) { + i = GrabSegment(i, o, o2); + + if (i == iFirst) { + break; + } + + if (iFirst < 0) { + iFirst = i; + pathTypes.Add(PT_MOVETO); + pathPoints.Add(o2.pa[0]); + } + + AddSegment(o2, pathTypes, pathPoints); + } + } else { + /* + for (ptrdiff_t i = 1, len = o.pa.GetSize(); i < len; i++) + { + if (int dir = o.da[i-1]) + { + CPoint dir2 = o.pa[i] - o.pa[i-1]; + dir2.x /= 2; dir2.y /= 2; + CPoint dir1 = dir > 0 ? CPoint(dir2.y, -dir2.x) : CPoint(-dir2.y, dir2.x); + i = i; + o.pa[i-1] -= dir1; + o.pa.InsertAt(i, o.pa[i-1] + dir2); + o.da.InsertAt(i, -dir); + o.pa.InsertAt(i+1, o.pa[i] + dir1); + o.da.InsertAt(i+1, dir); + i += 2; + len += 2; + } + } + */ + pathTypes.Add(PT_MOVETO); + pathPoints.Add(o.pa[0]); + + for (size_t i = 1, len = o.pa.GetCount(); i < len; i++) { + pathTypes.Add(PT_LINETO); + pathPoints.Add(o.pa[i]); + } + } + } + + return !pathTypes.IsEmpty(); +} + +bool CVobSubImage::Polygonize(CStringW& assstr, bool bSmooth, int scale) +{ + CAtlArray pathTypes; + CAtlArray pathPoints; + + if (!Polygonize(pathTypes, pathPoints, bSmooth, scale)) { + return false; + } + + assstr.Format(L"{\\an7\\pos(%d,%d)\\p%d}", rect.left, rect.top, 1 + scale); + // assstr.Format(L"{\\p%d}", 1+scale); + + BYTE lastType = 0; + + size_t nPoints = pathTypes.GetCount(); + + for (size_t i = 0; i < nPoints; i++) { + CStringW s; + + switch (pathTypes[i]) { + case PT_MOVETO: + if (lastType != PT_MOVETO) { + assstr += L"m "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_MOVETONC: + if (lastType != PT_MOVETONC) { + assstr += L"n "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_LINETO: + if (lastType != PT_LINETO) { + assstr += L"l "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_BEZIERTO: + if (i + 2 < nPoints) { + if (lastType != PT_BEZIERTO) { + assstr += L"b "; + } + s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); + i += 2; + } + break; + case PT_BSPLINETO: + if (i + 2 < nPoints) { + if (lastType != PT_BSPLINETO) { + assstr += L"s "; + } + s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); + i += 2; + } + break; + case PT_BSPLINEPATCHTO: + if (lastType != PT_BSPLINEPATCHTO) { + assstr += L"p "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + } + + lastType = pathTypes[i]; + + assstr += s; + } + + assstr += L"{\\p0}"; + + return nPoints > 0; +} + +void CVobSubImage::Scale2x() +{ + int w = rect.Width(), h = rect.Height(); + + if (w > 0 && h > 0) { + DWORD* src = (DWORD*)lpPixels; + DWORD* dst = DEBUG_NEW DWORD[w * h]; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src++, dst++) { + DWORD E = *src; + + DWORD A = x > 0 && y > 0 ? src[-w - 1] : E; + DWORD B = y > 0 ? src[-w] : E; + DWORD C = x < w - 1 && y > 0 ? src[-w + 1] : E; + UNREFERENCED_PARAMETER(A); + UNREFERENCED_PARAMETER(C); + + DWORD D = x > 0 ? src[-1] : E; + DWORD F = x < w - 1 ? src[+1] : E; + + DWORD G = x > 0 && y < h - 1 ? src[+w - 1] : E; + DWORD H = y < h - 1 ? src[+w] : E; + DWORD I = x < w - 1 && y < h - 1 ? src[+w + 1] : E; + UNREFERENCED_PARAMETER(G); + UNREFERENCED_PARAMETER(I); + + DWORD E0 = D == B && B != F && D != H ? D : E; + DWORD E1 = B == F && B != D && F != H ? F : E; + DWORD E2 = D == H && D != B && H != F ? D : E; + DWORD E3 = H == F && D != H && B != F ? F : E; + + *dst = ((((E0 & 0x00ff00ff) + (E1 & 0x00ff00ff) + (E2 & 0x00ff00ff) + (E3 & 0x00ff00ff) + 2) >> 2) & 0x00ff00ff) + | (((((E0 >> 8) & 0x00ff00ff) + ((E1 >> 8) & 0x00ff00ff) + ((E2 >> 8) & 0x00ff00ff) + ((E3 >> 8) & 0x00ff00ff) + 2) << 6) & 0xff00ff00); + } + } + + src -= w * h; + dst -= w * h; + + memcpy(src, dst, w * h * 4); + + delete [] dst; + } +} diff --git a/src/Subtitles/VobSubImage.h b/src/Subtitles/VobSubImage.h index bee6464321e..6665668ee18 100644 --- a/src/Subtitles/VobSubImage.h +++ b/src/Subtitles/VobSubImage.h @@ -1,96 +1,96 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include - -struct COutline { - CAtlArray pa; - CAtlArray da; - void RemoveAll() { - pa.RemoveAll(); - da.RemoveAll(); - } - void Add(CPoint p, int d) { - pa.Add(p); - da.Add(d); - } -}; - -class CVobSubImage -{ - friend class CVobSubFile; - -private: - CSize org; - RGBQUAD* lpTemp1; - RGBQUAD* lpTemp2; - - size_t nOffset[2], nPlane; - bool bCustomPal; - bool bAligned; - int tridx; - RGBQUAD* orgpal /*[16]*/, * cuspal /*[4]*/; - - bool Alloc(int w, int h); - void Free(); - - BYTE GetNibble(const BYTE* lpData); - void DrawPixels(CPoint p, int length, size_t colorId); - void TrimSubImage(); - -public: - size_t nLang, nIdx; - bool bForced, bAnimated; - int tCurrent; - __int64 start, delay; - CRect rect; - struct SubPal { - BYTE pal: 4, tr: 4; - }; - SubPal pal[4]; - RGBQUAD* lpPixels; - - CVobSubImage(); - virtual ~CVobSubImage(); - - void Invalidate() { nLang = nIdx = SIZE_T_ERROR; } - - void GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t = INT_MAX); - bool Decode(BYTE* lpData, size_t packetSize, size_t dataSize, int t, - bool bCustomPal, - int tridx, - RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/, - bool bTrim); - -private: - CAutoPtrList* GetOutlineList(CPoint& topleft); - int GrabSegment(int start, const COutline& o, COutline& ret); - void SplitOutline(const COutline& o, COutline& o1, COutline& o2); - void AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints); - -public: - bool Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool bSmooth, int scale); - bool Polygonize(CStringW& assstr, bool bSmooth = true, int scale = 3); - - void Scale2x(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include + +struct COutline { + CAtlArray pa; + CAtlArray da; + void RemoveAll() { + pa.RemoveAll(); + da.RemoveAll(); + } + void Add(CPoint p, int d) { + pa.Add(p); + da.Add(d); + } +}; + +class CVobSubImage +{ + friend class CVobSubFile; + +private: + CSize org; + RGBQUAD* lpTemp1; + RGBQUAD* lpTemp2; + + size_t nOffset[2], nPlane; + bool bCustomPal; + bool bAligned; + int tridx; + RGBQUAD* orgpal /*[16]*/, * cuspal /*[4]*/; + + bool Alloc(int w, int h); + void Free(); + + BYTE GetNibble(const BYTE* lpData); + void DrawPixels(CPoint p, int length, size_t colorId); + void TrimSubImage(); + +public: + size_t nLang, nIdx; + bool bForced, bAnimated; + int tCurrent; + __int64 start, delay; + CRect rect; + struct SubPal { + BYTE pal: 4, tr: 4; + }; + SubPal pal[4]; + RGBQUAD* lpPixels; + + CVobSubImage(); + virtual ~CVobSubImage(); + + void Invalidate() { nLang = nIdx = SIZE_T_ERROR; } + + void GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t = INT_MAX); + bool Decode(BYTE* lpData, size_t packetSize, size_t dataSize, int t, + bool bCustomPal, + int tridx, + RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/, + bool bTrim); + +private: + CAutoPtrList* GetOutlineList(CPoint& topleft); + int GrabSegment(int start, const COutline& o, COutline& ret); + void SplitOutline(const COutline& o, COutline& o1, COutline& o2); + void AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints); + +public: + bool Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool bSmooth, int scale); + bool Polygonize(CStringW& assstr, bool bSmooth = true, int scale = 3); + + void Scale2x(); +}; diff --git a/src/Subtitles/stdafx.cpp b/src/Subtitles/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/Subtitles/stdafx.cpp +++ b/src/Subtitles/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/Subtitles/stdafx.h b/src/Subtitles/stdafx.h index de33d75ce66..eb9cc29dc39 100644 --- a/src/Subtitles/stdafx.h +++ b/src/Subtitles/stdafx.h @@ -1,43 +1,43 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components -#include - -#include "BaseClasses/streams.h" - -#include "../DSUtil/DSUtil.h" -#include -#include -#include -#include -#include -#include -#include +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components +#include + +#include "BaseClasses/streams.h" + +#include "../DSUtil/DSUtil.h" +#include +#include +#include +#include +#include +#include +#include diff --git a/src/YASM.props b/src/YASM.props index b47f531ba8c..aa361845b12 100644 --- a/src/YASM.props +++ b/src/YASM.props @@ -1,35 +1,35 @@ - - - - Midl - CustomBuild - - - _SelectedFiles;$(YASMDependsOn) - - - - yasm.exe -X vc [Platform] [Debug] [Defines] [IncludePaths] -o "$(IntDir)%(Filename).obj" "%(FullPath)" - $(IntDir)%(Filename).obj - YASM: Assembling %(Filename)%(Extension) - False - - - - - win32 - - - - - win64 - - - - - True - - + + + + Midl + CustomBuild + + + _SelectedFiles;$(YASMDependsOn) + + + + yasm.exe -X vc [Platform] [Debug] [Defines] [IncludePaths] -o "$(IntDir)%(Filename).obj" "%(FullPath)" + $(IntDir)%(Filename).obj + YASM: Assembling %(Filename)%(Extension) + False + + + + + win32 + + + + + win64 + + + + + True + + \ No newline at end of file diff --git a/src/YASM.targets b/src/YASM.targets index b6c857ed579..45663c9389d 100644 --- a/src/YASM.targets +++ b/src/YASM.targets @@ -1,85 +1,85 @@ - - - - - - _YASM - - - - $(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml - - - - - - - - @(YASM, '|') - - - - - - - - - $(ComputeLinkInputsTargets); - ComputeYASMOutput; - - - $(ComputeLibInputsTargets); - ComputeYASMOutput; - - - - - - - - - - - + + + + + + _YASM + + + + $(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml + + + + + + + + @(YASM, '|') + + + + + + + + + $(ComputeLinkInputsTargets); + ComputeYASMOutput; + + + $(ComputeLibInputsTargets); + ComputeYASMOutput; + + + + + + + + + + + \ No newline at end of file diff --git a/src/YASM.xml b/src/YASM.xml index 510b2065fbd..39a50bd5bbe 100644 --- a/src/YASM.xml +++ b/src/YASM.xml @@ -1,149 +1,149 @@ - - - - - - - - - - General - - - - - Command Line - - - - - - + + + + + + + + + General + + + + + Command Line + + + + + + - - - - - - - - - Execute Before - - - Specifies the targets for the build customization to run before. - - - - - - - - - - - Execute After - - - Specifies the targets for the build customization to run after. - - - - - - - - - - - - + + + + + + + + + Execute Before + + + Specifies the targets for the build customization to run before. + + + + + + + + + + + Execute After + + + Specifies the targets for the build customization to run after. + + + + + + + + + + + + - - - Additional Options - - - Additional Options - - - - - - + Switch="-I "[value]"" /> + + + Additional Options + + + Additional Options + + + + + + \ No newline at end of file diff --git a/src/common.props b/src/common.props index 4e2e30ec11e..91fda207f75 100644 --- a/src/common.props +++ b/src/common.props @@ -1,96 +1,96 @@ - - - - $(SolutionDir)bin\obj\$(Configuration)_$(PlatformName)\$(ProjectName)\ - $(SolutionDir)bin\lib\$(Configuration)_$(PlatformName)\ - $(SolutionDir)bin\Filters_x86_Debug\ - $(SolutionDir)bin\Filters_x64_Debug\ - $(SolutionDir)bin\Filters_x86\ - $(SolutionDir)bin\Filters_x64\ - true - false - True - - - - stdcpp17 - /w34127 /w34701 /w34706 /Zo /Zc:inline,referenceBinding,rvalueCast,ternary,throwingNew /Gw %(AdditionalOptions) - /wd4005 /wd6031 /wd6246 /wd6309 /wd6387 /wd28204 %(AdditionalOptions) - true - true - Sync - true - true - Use - stdafx.h - _WINDOWS;WINDOWS;WINVER=0x06010000;_WIN32_WINNT=0x06010000;_WIN32_IE=0x0800;PSAPI_VERSION=1;_USE_MATH_DEFINES;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) - NOMINMAX;%(PreprocessorDefinitions) - STANDALONE_FILTER;_USRDLL;_AFX_NO_MFC_CONTROLS_IN_DIALOGS;%(PreprocessorDefinitions) - WIN32;%(PreprocessorDefinitions) - _WIN64;WIN64;%(PreprocessorDefinitions) - Level3 - - - MachineX86 - MachineX64 - - - true - Debug - true - Windows - MachineX86 - MachineX64 - notelemetry.obj;%(AdditionalDependencies) - - - 0x0409 - WIN32;%(PreprocessorDefinitions) - _WIN64;%(PreprocessorDefinitions) - - - - - EnableFastChecks - EditAndContinue - ProgramDatabase - Disabled - _DEBUG;DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug - - - _DEBUG;%(PreprocessorDefinitions) - - - false - DebugFastLink - - - - - ProgramDatabase - StreamingSIMDExtensions2 - AnySuitable - true - Speed - MaxSpeed - NDEBUG;%(PreprocessorDefinitions) - MultiThreaded - true - true - - - true - - - /OPT:ICF=3 %(AdditionalOptions) - true - UseFastLinkTimeCodeGeneration - true - true - - - NDEBUG;%(PreprocessorDefinitions) - - - + + + + $(SolutionDir)bin\obj\$(Configuration)_$(PlatformName)\$(ProjectName)\ + $(SolutionDir)bin\lib\$(Configuration)_$(PlatformName)\ + $(SolutionDir)bin\Filters_x86_Debug\ + $(SolutionDir)bin\Filters_x64_Debug\ + $(SolutionDir)bin\Filters_x86\ + $(SolutionDir)bin\Filters_x64\ + true + false + True + + + + stdcpp17 + /w34127 /w34701 /w34706 /Zo /Zc:inline,referenceBinding,rvalueCast,ternary,throwingNew /Gw %(AdditionalOptions) + /wd4005 /wd6031 /wd6246 /wd6309 /wd6387 /wd28204 %(AdditionalOptions) + true + true + Sync + true + true + Use + stdafx.h + _WINDOWS;WINDOWS;WINVER=0x06010000;_WIN32_WINNT=0x06010000;_WIN32_IE=0x0800;PSAPI_VERSION=1;_USE_MATH_DEFINES;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) + NOMINMAX;%(PreprocessorDefinitions) + STANDALONE_FILTER;_USRDLL;_AFX_NO_MFC_CONTROLS_IN_DIALOGS;%(PreprocessorDefinitions) + WIN32;%(PreprocessorDefinitions) + _WIN64;WIN64;%(PreprocessorDefinitions) + Level3 + + + MachineX86 + MachineX64 + + + true + Debug + true + Windows + MachineX86 + MachineX64 + notelemetry.obj;%(AdditionalDependencies) + + + 0x0409 + WIN32;%(PreprocessorDefinitions) + _WIN64;%(PreprocessorDefinitions) + + + + + EnableFastChecks + EditAndContinue + ProgramDatabase + Disabled + _DEBUG;DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebug + + + _DEBUG;%(PreprocessorDefinitions) + + + false + DebugFastLink + + + + + ProgramDatabase + StreamingSIMDExtensions2 + AnySuitable + true + Speed + MaxSpeed + NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + true + + + true + + + /OPT:ICF=3 %(AdditionalOptions) + true + UseFastLinkTimeCodeGeneration + true + true + + + NDEBUG;%(PreprocessorDefinitions) + + + diff --git a/src/filters/FilterApp.cpp b/src/filters/FilterApp.cpp index b7a2c899fbe..4ac03a34c33 100644 --- a/src/filters/FilterApp.cpp +++ b/src/filters/FilterApp.cpp @@ -1,52 +1,52 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include "FilterApp.h" - -extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); - -CFilterApp::CFilterApp() -{ -} - -BOOL CFilterApp::InitInstance() -{ - if (!__super::InitInstance()) { - return FALSE; - } - - SetRegistryKey(_T("Gabest")); - - DllEntryPoint(AfxGetInstanceHandle(), DLL_PROCESS_ATTACH, 0); - - return TRUE; -} - -BOOL CFilterApp::ExitInstance() -{ - DllEntryPoint(AfxGetInstanceHandle(), DLL_PROCESS_DETACH, 0); - - return __super::ExitInstance(); -} - -BEGIN_MESSAGE_MAP(CFilterApp, CWinApp) -END_MESSAGE_MAP() +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include "FilterApp.h" + +extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); + +CFilterApp::CFilterApp() +{ +} + +BOOL CFilterApp::InitInstance() +{ + if (!__super::InitInstance()) { + return FALSE; + } + + SetRegistryKey(_T("Gabest")); + + DllEntryPoint(AfxGetInstanceHandle(), DLL_PROCESS_ATTACH, 0); + + return TRUE; +} + +BOOL CFilterApp::ExitInstance() +{ + DllEntryPoint(AfxGetInstanceHandle(), DLL_PROCESS_DETACH, 0); + + return __super::ExitInstance(); +} + +BEGIN_MESSAGE_MAP(CFilterApp, CWinApp) +END_MESSAGE_MAP() diff --git a/src/filters/FilterApp.h b/src/filters/FilterApp.h index dcd8f97cd4e..3997ea2f558 100644 --- a/src/filters/FilterApp.h +++ b/src/filters/FilterApp.h @@ -1,33 +1,33 @@ -/* - * (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 . - * - */ - -#pragma once - -class CFilterApp : public CWinApp -{ -public: - CFilterApp(); - - BOOL InitInstance(); - BOOL ExitInstance(); - - DECLARE_MESSAGE_MAP() -}; +/* + * (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 . + * + */ + +#pragma once + +class CFilterApp : public CWinApp +{ +public: + CFilterApp(); + + BOOL InitInstance(); + BOOL ExitInstance(); + + DECLARE_MESSAGE_MAP() +}; diff --git a/src/filters/Filters.h b/src/filters/Filters.h index 0eafc3e8e6c..a859d9cf258 100644 --- a/src/filters/Filters.h +++ b/src/filters/Filters.h @@ -1,38 +1,38 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "muxer/DSMMuxer/DSMMuxer.h" -#include "muxer/MatroskaMuxer/MatroskaMuxer.h" -#include "muxer/WavDest/WavDest.h" -#include "parser/DSMSplitter/DSMSplitter.h" -#include "parser/StreamDriveThru/StreamDriveThru.h" -#include "reader/CDDAReader/CDDAReader.h" -#include "reader/CDXAReader/CDXAReader.h" -#include "reader/VTSReader/VTSReader.h" -#include "renderer/SyncClock/SyncClock.h" -#include "source/SubtitleSource/SubtitleSource.h" -#include "switcher/AudioSwitcher/AudioSwitcher.h" -#include "transform/AVI2AC3Filter/AVI2AC3Filter.h" -#include "transform/BufferFilter/BufferFilter.h" -#include "transform/DeCSSFilter/DeCSSFilter.h" -#include "RARFileSource/RFS.h" +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "muxer/DSMMuxer/DSMMuxer.h" +#include "muxer/MatroskaMuxer/MatroskaMuxer.h" +#include "muxer/WavDest/WavDest.h" +#include "parser/DSMSplitter/DSMSplitter.h" +#include "parser/StreamDriveThru/StreamDriveThru.h" +#include "reader/CDDAReader/CDDAReader.h" +#include "reader/CDXAReader/CDXAReader.h" +#include "reader/VTSReader/VTSReader.h" +#include "renderer/SyncClock/SyncClock.h" +#include "source/SubtitleSource/SubtitleSource.h" +#include "switcher/AudioSwitcher/AudioSwitcher.h" +#include "transform/AVI2AC3Filter/AVI2AC3Filter.h" +#include "transform/BufferFilter/BufferFilter.h" +#include "transform/DeCSSFilter/DeCSSFilter.h" +#include "RARFileSource/RFS.h" diff --git a/src/filters/Filters.vcxproj b/src/filters/Filters.vcxproj index 4bf90f69f49..fdcf00f9045 100644 --- a/src/filters/Filters.vcxproj +++ b/src/filters/Filters.vcxproj @@ -1,75 +1,75 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {273B3149-3192-4B75-A791-470320B90812} - Filters - MFCProj - Filters - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\thirdparty;..\DSUtil;..\filters\renderer\VideoRenderers;..\..\Include;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - Create - - - - - - - - - - - - {981574ae-5a5e-4f27-bdf1-1b841e374cff} - false - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {273B3149-3192-4B75-A791-470320B90812} + Filters + MFCProj + Filters + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\thirdparty;..\DSUtil;..\filters\renderer\VideoRenderers;..\..\Include;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + Create + + + + + + + + + + + + {981574ae-5a5e-4f27-bdf1-1b841e374cff} + false + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/filters/Filters.vcxproj.filters b/src/filters/Filters.vcxproj.filters index d5e04f35298..f153249f14f 100644 --- a/src/filters/Filters.vcxproj.filters +++ b/src/filters/Filters.vcxproj.filters @@ -1,44 +1,44 @@ - - - - - {f8b5bbc2-2fe8-4b4f-bc46-236e4ad3d92d} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {d27517d8-49af-491a-b3a8-9a7531f9cc28} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {f8b5bbc2-2fe8-4b4f-bc46-236e4ad3d92d} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {d27517d8-49af-491a-b3a8-9a7531f9cc28} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/InternalPropertyPage.cpp b/src/filters/InternalPropertyPage.cpp index d2b8efe293e..64b2779fe26 100644 --- a/src/filters/InternalPropertyPage.cpp +++ b/src/filters/InternalPropertyPage.cpp @@ -1,357 +1,357 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "InternalPropertyPage.h" -#include "../DSUtil/DSUtil.h" - - -// -// CInternalPropertyPageWnd -// - -void CInternalPropertyPageWnd::CalcTextRect(CRect& rect, long x, long y, long w, long border) -{ - rect.left = x; - rect.top = y; - rect.right = x + w; - rect.bottom = y + border; - m_dpi.ScaleRect(rect); - rect.bottom += m_fontheight; -} - -void CInternalPropertyPageWnd::CalcRect(CRect& rect, long x, long y, long w, long h) -{ - rect.left = x; - rect.top = y; - rect.right = x + w; - rect.bottom = y + h; - m_dpi.ScaleRect(rect); -} -CInternalPropertyPageWnd::CInternalPropertyPageWnd() - : m_fDirty(false) - , m_fontheight(IPP_FONTSIZE) -{ -} - -BOOL CInternalPropertyPageWnd::Create(IPropertyPageSite* pPageSite, LPCRECT pRect, CWnd* pParentWnd) -{ - if (!pPageSite || !pRect) { - return FALSE; - } - - m_pPageSite = pPageSite; - - if (!m_font.m_hObject) { - CString face; - WORD height; - extern BOOL AFXAPI AfxGetPropSheetFont(CString & strFace, WORD & wSize, BOOL bWizard); // yay - if (!AfxGetPropSheetFont(face, height, FALSE)) { - return FALSE; - } - - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - _tcscpy_s(lf.lfFaceName, face); - HDC hDC = ::GetDC(nullptr); - lf.lfHeight = -MulDiv(height, GetDeviceCaps(hDC, LOGPIXELSY), 72); - ::ReleaseDC(nullptr, hDC); - lf.lfWeight = FW_NORMAL; - lf.lfCharSet = DEFAULT_CHARSET; - if (!m_font.CreateFontIndirect(&lf)) { - return FALSE; - } - - lf.lfHeight -= -1; - _tcscpy_s(lf.lfFaceName, _T("Lucida Console")); - if (!m_monospacefont.CreateFontIndirect(&lf)) { - _tcscpy_s(lf.lfFaceName, _T("Courier New")); - if (!m_monospacefont.CreateFontIndirect(&lf)) { - return FALSE; - } - } - - hDC = ::GetDC(nullptr); - HFONT hFontOld = (HFONT)::SelectObject(hDC, m_font.m_hObject); - CSize size; - ::GetTextExtentPoint32(hDC, _T("x"), 1, &size); - ::SelectObject(hDC, hFontOld); - ::ReleaseDC(nullptr, hDC); - - m_fontheight = size.cy; - } - - LPCTSTR wc = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS, 0, (HBRUSH)(COLOR_BTNFACE + 1)); - if (!CreateEx(0, wc, _T("CInternalPropertyPageWnd"), WS_CHILDWINDOW, *pRect, pParentWnd, 0)) { - return FALSE; - } - - SetFont(&m_font); - - return TRUE; -} - -BOOL CInternalPropertyPageWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) -{ - if (message == WM_COMMAND || message == WM_HSCROLL || message == WM_VSCROLL) { - WORD notify = HIWORD(wParam); - // check only notifications that change the state of a control, otherwise false positives are possible. - if (notify == BN_CLICKED - || notify == CBN_SELCHANGE - || notify == EN_CHANGE - || notify == CLBN_CHKCHANGE) { - SetDirty(true); - } - } - - return __super::OnWndMsg(message, wParam, lParam, pResult); -} - -BEGIN_MESSAGE_MAP(CInternalPropertyPageWnd, CWnd) -END_MESSAGE_MAP() - -// -// CInternalPropertyPage -// - -CInternalPropertyPage::CInternalPropertyPage(LPUNKNOWN lpunk, HRESULT* phr) - : CUnknown(_T("CInternalPropertyPage"), lpunk) - , m_pWnd(nullptr) -{ - if (phr) { - *phr = S_OK; - } -} - -CInternalPropertyPage::~CInternalPropertyPage() -{ - if (m_pWnd) { - if (m_pWnd->m_hWnd) { - ASSERT(0); - m_pWnd->DestroyWindow(); - } - delete m_pWnd; - m_pWnd = nullptr; - } -} - -STDMETHODIMP CInternalPropertyPage::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI2(IPropertyPage) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IPropertyPage - -STDMETHODIMP CInternalPropertyPage::SetPageSite(IPropertyPageSite* pPageSite) -{ - CAutoLock cAutoLock(this); - - if (pPageSite && m_pPageSite || !pPageSite && !m_pPageSite) { - return E_UNEXPECTED; - } - - m_pPageSite = pPageSite; - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Activate(HWND hwndParent, LPCRECT pRect, BOOL fModal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - CheckPointer(pRect, E_POINTER); - - if (!m_pWnd || m_pWnd->m_hWnd || m_pUnks.IsEmpty()) { - return E_UNEXPECTED; - } - - if (!m_pWnd->Create(m_pPageSite, pRect, CWnd::FromHandle(hwndParent))) { - return E_OUTOFMEMORY; - } - - if (!m_pWnd->OnActivate()) { - m_pWnd->DestroyWindow(); - return E_FAIL; - } - - m_pWnd->ModifyStyleEx(WS_EX_DLGMODALFRAME, WS_EX_CONTROLPARENT); - m_pWnd->ShowWindow(SW_SHOWNORMAL); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Deactivate() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - if (!m_pWnd || !m_pWnd->m_hWnd) { - return E_UNEXPECTED; - } - - m_pWnd->OnDeactivate(); - - m_pWnd->ModifyStyleEx(WS_EX_CONTROLPARENT, 0); - m_pWnd->DestroyWindow(); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::GetPageInfo(PROPPAGEINFO* pPageInfo) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPageInfo, E_POINTER); - - LPOLESTR pszTitle; - HRESULT hr = AMGetWideString(CStringW(GetWindowTitle()), &pszTitle); - if (FAILED(hr)) { - return hr; - } - - pPageInfo->cb = sizeof(PROPPAGEINFO); - pPageInfo->pszTitle = pszTitle; - pPageInfo->pszDocString = nullptr; - pPageInfo->pszHelpFile = nullptr; - pPageInfo->dwHelpContext = 0; - pPageInfo->size = GetWindowSize(); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::SetObjects(ULONG cObjects, LPUNKNOWN* ppUnk) -{ - CAutoLock cAutoLock(this); - - if (cObjects && m_pWnd || !cObjects && !m_pWnd) { - return E_UNEXPECTED; - } - - m_pUnks.RemoveAll(); - - if (cObjects > 0) { - CheckPointer(ppUnk, E_POINTER); - - for (ULONG i = 0; i < cObjects; i++) { - m_pUnks.AddTail(ppUnk[i]); - } - - m_pWnd = GetWindow(); - if (!m_pWnd) { - return E_OUTOFMEMORY; - } - - if (!m_pWnd->OnConnect(m_pUnks)) { - delete m_pWnd; - m_pWnd = nullptr; - - return E_FAIL; - } - } else { - m_pWnd->OnDisconnect(); - - m_pWnd->DestroyWindow(); - delete m_pWnd; - m_pWnd = nullptr; - } - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Show(UINT nCmdShow) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - if (!m_pWnd) { - return E_UNEXPECTED; - } - - if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { - return E_INVALIDARG; - } - - m_pWnd->ShowWindow(nCmdShow); - m_pWnd->Invalidate(); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Move(LPCRECT pRect) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - CheckPointer(pRect, E_POINTER); - - if (!m_pWnd) { - return E_UNEXPECTED; - } - - m_pWnd->MoveWindow(pRect, TRUE); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::IsPageDirty() -{ - CAutoLock cAutoLock(this); - - return m_pWnd && m_pWnd->GetDirty() ? S_OK : S_FALSE; -} - -STDMETHODIMP CInternalPropertyPage::Apply() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - if (!m_pWnd || m_pUnks.IsEmpty() || !m_pPageSite) { - return E_UNEXPECTED; - } - - if (m_pWnd->GetDirty() && m_pWnd->OnApply()) { - m_pWnd->SetDirty(false); - } - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Help(LPCWSTR lpszHelpDir) -{ - CAutoLock cAutoLock(this); - - return E_NOTIMPL; -} - -STDMETHODIMP CInternalPropertyPage::TranslateAccelerator(LPMSG lpMsg) -{ - CAutoLock cAutoLock(this); - - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "InternalPropertyPage.h" +#include "../DSUtil/DSUtil.h" + + +// +// CInternalPropertyPageWnd +// + +void CInternalPropertyPageWnd::CalcTextRect(CRect& rect, long x, long y, long w, long border) +{ + rect.left = x; + rect.top = y; + rect.right = x + w; + rect.bottom = y + border; + m_dpi.ScaleRect(rect); + rect.bottom += m_fontheight; +} + +void CInternalPropertyPageWnd::CalcRect(CRect& rect, long x, long y, long w, long h) +{ + rect.left = x; + rect.top = y; + rect.right = x + w; + rect.bottom = y + h; + m_dpi.ScaleRect(rect); +} +CInternalPropertyPageWnd::CInternalPropertyPageWnd() + : m_fDirty(false) + , m_fontheight(IPP_FONTSIZE) +{ +} + +BOOL CInternalPropertyPageWnd::Create(IPropertyPageSite* pPageSite, LPCRECT pRect, CWnd* pParentWnd) +{ + if (!pPageSite || !pRect) { + return FALSE; + } + + m_pPageSite = pPageSite; + + if (!m_font.m_hObject) { + CString face; + WORD height; + extern BOOL AFXAPI AfxGetPropSheetFont(CString & strFace, WORD & wSize, BOOL bWizard); // yay + if (!AfxGetPropSheetFont(face, height, FALSE)) { + return FALSE; + } + + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + _tcscpy_s(lf.lfFaceName, face); + HDC hDC = ::GetDC(nullptr); + lf.lfHeight = -MulDiv(height, GetDeviceCaps(hDC, LOGPIXELSY), 72); + ::ReleaseDC(nullptr, hDC); + lf.lfWeight = FW_NORMAL; + lf.lfCharSet = DEFAULT_CHARSET; + if (!m_font.CreateFontIndirect(&lf)) { + return FALSE; + } + + lf.lfHeight -= -1; + _tcscpy_s(lf.lfFaceName, _T("Lucida Console")); + if (!m_monospacefont.CreateFontIndirect(&lf)) { + _tcscpy_s(lf.lfFaceName, _T("Courier New")); + if (!m_monospacefont.CreateFontIndirect(&lf)) { + return FALSE; + } + } + + hDC = ::GetDC(nullptr); + HFONT hFontOld = (HFONT)::SelectObject(hDC, m_font.m_hObject); + CSize size; + ::GetTextExtentPoint32(hDC, _T("x"), 1, &size); + ::SelectObject(hDC, hFontOld); + ::ReleaseDC(nullptr, hDC); + + m_fontheight = size.cy; + } + + LPCTSTR wc = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS, 0, (HBRUSH)(COLOR_BTNFACE + 1)); + if (!CreateEx(0, wc, _T("CInternalPropertyPageWnd"), WS_CHILDWINDOW, *pRect, pParentWnd, 0)) { + return FALSE; + } + + SetFont(&m_font); + + return TRUE; +} + +BOOL CInternalPropertyPageWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + if (message == WM_COMMAND || message == WM_HSCROLL || message == WM_VSCROLL) { + WORD notify = HIWORD(wParam); + // check only notifications that change the state of a control, otherwise false positives are possible. + if (notify == BN_CLICKED + || notify == CBN_SELCHANGE + || notify == EN_CHANGE + || notify == CLBN_CHKCHANGE) { + SetDirty(true); + } + } + + return __super::OnWndMsg(message, wParam, lParam, pResult); +} + +BEGIN_MESSAGE_MAP(CInternalPropertyPageWnd, CWnd) +END_MESSAGE_MAP() + +// +// CInternalPropertyPage +// + +CInternalPropertyPage::CInternalPropertyPage(LPUNKNOWN lpunk, HRESULT* phr) + : CUnknown(_T("CInternalPropertyPage"), lpunk) + , m_pWnd(nullptr) +{ + if (phr) { + *phr = S_OK; + } +} + +CInternalPropertyPage::~CInternalPropertyPage() +{ + if (m_pWnd) { + if (m_pWnd->m_hWnd) { + ASSERT(0); + m_pWnd->DestroyWindow(); + } + delete m_pWnd; + m_pWnd = nullptr; + } +} + +STDMETHODIMP CInternalPropertyPage::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI2(IPropertyPage) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IPropertyPage + +STDMETHODIMP CInternalPropertyPage::SetPageSite(IPropertyPageSite* pPageSite) +{ + CAutoLock cAutoLock(this); + + if (pPageSite && m_pPageSite || !pPageSite && !m_pPageSite) { + return E_UNEXPECTED; + } + + m_pPageSite = pPageSite; + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Activate(HWND hwndParent, LPCRECT pRect, BOOL fModal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + CheckPointer(pRect, E_POINTER); + + if (!m_pWnd || m_pWnd->m_hWnd || m_pUnks.IsEmpty()) { + return E_UNEXPECTED; + } + + if (!m_pWnd->Create(m_pPageSite, pRect, CWnd::FromHandle(hwndParent))) { + return E_OUTOFMEMORY; + } + + if (!m_pWnd->OnActivate()) { + m_pWnd->DestroyWindow(); + return E_FAIL; + } + + m_pWnd->ModifyStyleEx(WS_EX_DLGMODALFRAME, WS_EX_CONTROLPARENT); + m_pWnd->ShowWindow(SW_SHOWNORMAL); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Deactivate() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + if (!m_pWnd || !m_pWnd->m_hWnd) { + return E_UNEXPECTED; + } + + m_pWnd->OnDeactivate(); + + m_pWnd->ModifyStyleEx(WS_EX_CONTROLPARENT, 0); + m_pWnd->DestroyWindow(); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::GetPageInfo(PROPPAGEINFO* pPageInfo) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPageInfo, E_POINTER); + + LPOLESTR pszTitle; + HRESULT hr = AMGetWideString(CStringW(GetWindowTitle()), &pszTitle); + if (FAILED(hr)) { + return hr; + } + + pPageInfo->cb = sizeof(PROPPAGEINFO); + pPageInfo->pszTitle = pszTitle; + pPageInfo->pszDocString = nullptr; + pPageInfo->pszHelpFile = nullptr; + pPageInfo->dwHelpContext = 0; + pPageInfo->size = GetWindowSize(); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::SetObjects(ULONG cObjects, LPUNKNOWN* ppUnk) +{ + CAutoLock cAutoLock(this); + + if (cObjects && m_pWnd || !cObjects && !m_pWnd) { + return E_UNEXPECTED; + } + + m_pUnks.RemoveAll(); + + if (cObjects > 0) { + CheckPointer(ppUnk, E_POINTER); + + for (ULONG i = 0; i < cObjects; i++) { + m_pUnks.AddTail(ppUnk[i]); + } + + m_pWnd = GetWindow(); + if (!m_pWnd) { + return E_OUTOFMEMORY; + } + + if (!m_pWnd->OnConnect(m_pUnks)) { + delete m_pWnd; + m_pWnd = nullptr; + + return E_FAIL; + } + } else { + m_pWnd->OnDisconnect(); + + m_pWnd->DestroyWindow(); + delete m_pWnd; + m_pWnd = nullptr; + } + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Show(UINT nCmdShow) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + if (!m_pWnd) { + return E_UNEXPECTED; + } + + if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { + return E_INVALIDARG; + } + + m_pWnd->ShowWindow(nCmdShow); + m_pWnd->Invalidate(); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Move(LPCRECT pRect) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + CheckPointer(pRect, E_POINTER); + + if (!m_pWnd) { + return E_UNEXPECTED; + } + + m_pWnd->MoveWindow(pRect, TRUE); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::IsPageDirty() +{ + CAutoLock cAutoLock(this); + + return m_pWnd && m_pWnd->GetDirty() ? S_OK : S_FALSE; +} + +STDMETHODIMP CInternalPropertyPage::Apply() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + if (!m_pWnd || m_pUnks.IsEmpty() || !m_pPageSite) { + return E_UNEXPECTED; + } + + if (m_pWnd->GetDirty() && m_pWnd->OnApply()) { + m_pWnd->SetDirty(false); + } + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Help(LPCWSTR lpszHelpDir) +{ + CAutoLock cAutoLock(this); + + return E_NOTIMPL; +} + +STDMETHODIMP CInternalPropertyPage::TranslateAccelerator(LPMSG lpMsg) +{ + CAutoLock cAutoLock(this); + + return E_NOTIMPL; +} diff --git a/src/filters/InternalPropertyPage.h b/src/filters/InternalPropertyPage.h index 8807f4f5fd2..6315a8a30eb 100644 --- a/src/filters/InternalPropertyPage.h +++ b/src/filters/InternalPropertyPage.h @@ -1,124 +1,124 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -#include -#include "../mpc-hc/dpihelper.h" - -#define IPP_FONTSIZE 13 -#define IPP_SCALE(size) ((size) * m_fontheight / IPP_FONTSIZE) - -interface __declspec(uuid("03481710-D73E-4674-839F-03EDE2D60ED8")) - ISpecifyPropertyPages2 : - public ISpecifyPropertyPages -{ - STDMETHOD(CreatePage)(const GUID& guid, IPropertyPage** ppPage) = 0; -}; - -class CInternalPropertyPageWnd : public CWnd -{ - bool m_fDirty; - CComPtr m_pPageSite; - DpiHelper m_dpi; - -protected: - CFont m_font, m_monospacefont; - int m_fontheight; - - void CalcTextRect(CRect& rect, long x, long y, long w, long border = 0); - void CalcRect(CRect& rect, long x, long y, long w, long h); - virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); - -public: - CInternalPropertyPageWnd(); - - void SetDirty(bool fDirty = true) { - m_fDirty = fDirty; - if (m_pPageSite) { - if (fDirty) { - m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY); - } else { - m_pPageSite->OnStatusChange(PROPPAGESTATUS_CLEAN); - } - } - } - bool GetDirty() { return m_fDirty; } - - virtual BOOL Create(IPropertyPageSite* pPageSite, LPCRECT pRect, CWnd* pParentWnd); - - virtual bool OnConnect(const CInterfaceList& pUnks) { return true; } - virtual void OnDisconnect() {} - virtual bool OnActivate() { m_dpi.Override(GetSafeHwnd()); return true; } - virtual void OnDeactivate() {} - virtual bool OnApply() { return true; } - - DECLARE_MESSAGE_MAP() -}; - -class CInternalPropertyPage - : public CUnknown - , public IPropertyPage - , public CCritSec -{ - CComPtr m_pPageSite; - CInterfaceList m_pUnks; - CInternalPropertyPageWnd* m_pWnd; - -protected: - virtual CInternalPropertyPageWnd* GetWindow() = 0; - virtual LPCTSTR GetWindowTitle() = 0; - virtual CSize GetWindowSize() = 0; - -public: - CInternalPropertyPage(LPUNKNOWN lpunk, HRESULT* phr); - virtual ~CInternalPropertyPage(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IPropertyPage - - STDMETHODIMP SetPageSite(IPropertyPageSite* pPageSite); - STDMETHODIMP Activate(HWND hwndParent, LPCRECT pRect, BOOL fModal); - STDMETHODIMP Deactivate(); - STDMETHODIMP GetPageInfo(PROPPAGEINFO* pPageInfo); - STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN* ppUnk); - STDMETHODIMP Show(UINT nCmdShow); - STDMETHODIMP Move(LPCRECT prect); - STDMETHODIMP IsPageDirty(); - STDMETHODIMP Apply(); - STDMETHODIMP Help(LPCWSTR lpszHelpDir); - STDMETHODIMP TranslateAccelerator(LPMSG lpMsg); -}; - -template -class CInternalPropertyPageTempl : public CInternalPropertyPage -{ - virtual CInternalPropertyPageWnd* GetWindow() { return DEBUG_NEW WndClass(); } - virtual LPCTSTR GetWindowTitle() { return WndClass::GetWindowTitle(); } - virtual CSize GetWindowSize() { return WndClass::GetWindowSize(); } - -public: - CInternalPropertyPageTempl(LPUNKNOWN lpunk, HRESULT* phr) - : CInternalPropertyPage(lpunk, phr) { - } -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +#include +#include "../mpc-hc/dpihelper.h" + +#define IPP_FONTSIZE 13 +#define IPP_SCALE(size) ((size) * m_fontheight / IPP_FONTSIZE) + +interface __declspec(uuid("03481710-D73E-4674-839F-03EDE2D60ED8")) + ISpecifyPropertyPages2 : + public ISpecifyPropertyPages +{ + STDMETHOD(CreatePage)(const GUID& guid, IPropertyPage** ppPage) = 0; +}; + +class CInternalPropertyPageWnd : public CWnd +{ + bool m_fDirty; + CComPtr m_pPageSite; + DpiHelper m_dpi; + +protected: + CFont m_font, m_monospacefont; + int m_fontheight; + + void CalcTextRect(CRect& rect, long x, long y, long w, long border = 0); + void CalcRect(CRect& rect, long x, long y, long w, long h); + virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); + +public: + CInternalPropertyPageWnd(); + + void SetDirty(bool fDirty = true) { + m_fDirty = fDirty; + if (m_pPageSite) { + if (fDirty) { + m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY); + } else { + m_pPageSite->OnStatusChange(PROPPAGESTATUS_CLEAN); + } + } + } + bool GetDirty() { return m_fDirty; } + + virtual BOOL Create(IPropertyPageSite* pPageSite, LPCRECT pRect, CWnd* pParentWnd); + + virtual bool OnConnect(const CInterfaceList& pUnks) { return true; } + virtual void OnDisconnect() {} + virtual bool OnActivate() { m_dpi.Override(GetSafeHwnd()); return true; } + virtual void OnDeactivate() {} + virtual bool OnApply() { return true; } + + DECLARE_MESSAGE_MAP() +}; + +class CInternalPropertyPage + : public CUnknown + , public IPropertyPage + , public CCritSec +{ + CComPtr m_pPageSite; + CInterfaceList m_pUnks; + CInternalPropertyPageWnd* m_pWnd; + +protected: + virtual CInternalPropertyPageWnd* GetWindow() = 0; + virtual LPCTSTR GetWindowTitle() = 0; + virtual CSize GetWindowSize() = 0; + +public: + CInternalPropertyPage(LPUNKNOWN lpunk, HRESULT* phr); + virtual ~CInternalPropertyPage(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IPropertyPage + + STDMETHODIMP SetPageSite(IPropertyPageSite* pPageSite); + STDMETHODIMP Activate(HWND hwndParent, LPCRECT pRect, BOOL fModal); + STDMETHODIMP Deactivate(); + STDMETHODIMP GetPageInfo(PROPPAGEINFO* pPageInfo); + STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN* ppUnk); + STDMETHODIMP Show(UINT nCmdShow); + STDMETHODIMP Move(LPCRECT prect); + STDMETHODIMP IsPageDirty(); + STDMETHODIMP Apply(); + STDMETHODIMP Help(LPCWSTR lpszHelpDir); + STDMETHODIMP TranslateAccelerator(LPMSG lpMsg); +}; + +template +class CInternalPropertyPageTempl : public CInternalPropertyPage +{ + virtual CInternalPropertyPageWnd* GetWindow() { return DEBUG_NEW WndClass(); } + virtual LPCTSTR GetWindowTitle() { return WndClass::GetWindowTitle(); } + virtual CSize GetWindowSize() { return WndClass::GetWindowSize(); } + +public: + CInternalPropertyPageTempl(LPUNKNOWN lpunk, HRESULT* phr) + : CInternalPropertyPage(lpunk, phr) { + } +}; diff --git a/src/filters/PinInfoWnd.cpp b/src/filters/PinInfoWnd.cpp index 8debee5a971..30727dd1bf6 100644 --- a/src/filters/PinInfoWnd.cpp +++ b/src/filters/PinInfoWnd.cpp @@ -1,286 +1,286 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "PinInfoWnd.h" -#include "../DSUtil/DSUtil.h" -#include "../mpc-hc/DpiHelper.h" -#include "../DSUtil/MediaTypeEx.h" - -// -// CPinInfoWnd -// - -CPinInfoWnd::CPinInfoWnd() -{ -} - -bool CPinInfoWnd::OnConnect(const CInterfaceList& pUnks) -{ - ASSERT(!m_pBF); - - m_pBF.Release(); - - POSITION pos = pUnks.GetHeadPosition(); - while (pos && !(m_pBF = pUnks.GetNext(pos))) { - ; - } - - if (!m_pBF) { - return false; - } - - return true; -} - -void CPinInfoWnd::OnDisconnect() -{ - m_pBF.Release(); -} - -static WNDPROC OldControlProc; -static LRESULT CALLBACK ControlProc(HWND control, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_KEYDOWN) { - if (LOWORD(wParam) == VK_ESCAPE) { - return 0; // just ignore ESCAPE in edit control - } - 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 -} - -bool CPinInfoWnd::OnActivate() -{ - m_dpi.Override(GetSafeHwnd()); - - DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP; - CPoint p(m_dpi.ScaleX(10), m_dpi.ScaleY(10)); - - m_pin_static.Create(_T("Pin:"), dwStyle, - CRect(p + CPoint(m_dpi.ScaleX(0), m_dpi.ScaleY(3)), CSize(m_dpi.ScaleX(30), m_fontheight)), - this); - m_pin_combo.Create(dwStyle | CBS_DROPDOWNLIST, - CRect(p + CPoint(m_dpi.ScaleX(30), m_dpi.ScaleY(0)), CSize(m_dpi.ScaleX(520), m_dpi.ScaleY(200))), - this, IDC_PP_COMBO1); - BeginEnumPins(m_pBF, pEP, pPin) { - CPinInfo pi; - if (FAILED(pPin->QueryPinInfo(&pi))) { - continue; - } - CString str(pi.achName); - if (!str.Find(_T("Apple"))) { - str.Delete(0, 1); - } - CString dir = _T("[?] "); - if (pi.dir == PINDIR_INPUT) { - dir = _T("[IN] "); - } else if (pi.dir == PINDIR_OUTPUT) { - dir = _T("[OUT] "); - } - m_pin_combo.SetItemDataPtr(m_pin_combo.AddString(dir + str), pPin); - } - EndEnumPins; - m_pin_combo.SetCurSel(0); - - p.y += m_fontheight + m_dpi.ScaleY(20); - - m_info_edit.CreateEx(WS_EX_CLIENTEDGE, - _T("EDIT"), - _T(""), - dwStyle | - /* WS_BORDER | */ // equivalent to WS_EX_CLIENTEDGE - WS_VSCROLL | - WS_HSCROLL | - ES_MULTILINE | - ES_READONLY, - CRect(p, CSize(m_dpi.ScaleX(550), m_fontheight * 30)), - this, - IDC_PP_EDIT1); - m_info_edit.SetLimitText(60000); - - OnSelectedPinChange(); - - for (CWnd* pWnd = GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) { - pWnd->SetFont(&m_font, FALSE); - } - - m_info_edit.SetFixedWidthFont(m_monospacefont); - - // subclass the edit control - OldControlProc = (WNDPROC)SetWindowLongPtr(m_info_edit.m_hWnd, GWLP_WNDPROC, (LONG_PTR)ControlProc); - - return true; -} - -void CPinInfoWnd::OnDeactivate() -{ -} - -bool CPinInfoWnd::OnApply() -{ - OnDeactivate(); - - if (m_pBF) { - } - - return true; -} - -BOOL CPinInfoWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) -{ - //we don't need this anymore, as we bypass the CInternalPropertyPageWnd which is what sets it dirty - //SetDirty(false); - //we call CWnd implementation because CInternalPropertyPageWnd will set it right back to dirty on a scroll/command message - return CWnd::OnWndMsg(message, wParam, lParam, pResult); -} - -BEGIN_MESSAGE_MAP(CPinInfoWnd, CInternalPropertyPageWnd) - ON_CBN_SELCHANGE(IDC_PP_COMBO1, OnSelectedPinChange) - ON_WM_CTLCOLOR() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -void CPinInfoWnd::AddLine(CString str) -{ - str.Replace(_T("\n"), _T("\r\n")); - int len = m_info_edit.GetWindowTextLength(); - m_info_edit.SetSel(len, len, TRUE); - m_info_edit.ReplaceSel(str); -} - -void CPinInfoWnd::OnSelectedPinChange() -{ - m_info_edit.SetRedraw(FALSE); - m_info_edit.SetWindowText(_T("")); - - int i = m_pin_combo.GetCurSel(); - if (i < 0) { - return; - } - - CComPtr pPin = (IPin*)m_pin_combo.GetItemDataPtr(i); - if (!pPin) { - return; - } - - CString str; - CPinInfo pinInfo; - - if (SUCCEEDED(pPin->QueryPinInfo(&pinInfo))) { - CString strName; - CLSID filterClsid; - CFilterInfo filterInfo; - - if (SUCCEEDED(pinInfo.pFilter->QueryFilterInfo(&filterInfo))) { - CRegKey key; - pinInfo.pFilter->GetClassID(&filterClsid); - TCHAR buff[128]; - ULONG len = _countof(buff); - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\") + CStringFromGUID(filterClsid), KEY_READ) - && ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), buff, &len)) { - strName = CString(buff); - } else { - strName = filterInfo.achName; - } - str.Format(_T("Filter : %s - CLSID : %s\n\n"), strName.GetString(), CStringFromGUID(filterClsid).GetString()); - AddLine(str); - } - } - - CMediaTypeEx cmt; - - CComPtr pPinTo; - if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { - str.Format(_T("- Connected to:\n\nCLSID: %s\nFilter: %s\nPin: %s\n\n"), - CStringFromGUID(GetCLSID(pPinTo)).GetString(), - static_cast(GetFilterName(GetFilterFromPin(pPinTo))), - static_cast(GetPinName(pPinTo))); - - AddLine(str); - - AddLine(_T("- Connection media type:\n\n")); - - if (SUCCEEDED(pPin->ConnectionMediaType(&cmt))) { - CAtlList sl; - cmt.Dump(sl); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - AddLine(sl.GetNext(pos) + '\n'); - } - } - } else { - str = _T("- Not connected\n\n"); - } - - int iMT = 0; - - BeginEnumMediaTypes(pPin, pEMT, pmt) { - CMediaTypeEx mt(*pmt); - - str.Format(_T("- Enumerated media type %d:\n\n"), iMT++); - AddLine(str); - - if (cmt.majortype != GUID_NULL && mt == cmt) { - AddLine(_T("Set as the current media type\n\n")); - } else { - CAtlList sl; - mt.Dump(sl); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - AddLine(sl.GetNext(pos) + '\n'); - } - } - } - EndEnumMediaTypes(pmt); - - m_info_edit.SetSel(0, 0); - m_info_edit.SetRedraw(TRUE); - m_info_edit.RedrawWindow(NULL); -} - - -HBRUSH CPinInfoWnd::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} - -BOOL CPinInfoWnd::OnEraseBkgnd(CDC* pDC) -{ - bool ret = MPCThemeEraseBkgnd(pDC, this, CTLCOLOR_DLG); - if (ret) { - return ret; - } else { - return __super::OnEraseBkgnd(pDC); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "PinInfoWnd.h" +#include "../DSUtil/DSUtil.h" +#include "../mpc-hc/DpiHelper.h" +#include "../DSUtil/MediaTypeEx.h" + +// +// CPinInfoWnd +// + +CPinInfoWnd::CPinInfoWnd() +{ +} + +bool CPinInfoWnd::OnConnect(const CInterfaceList& pUnks) +{ + ASSERT(!m_pBF); + + m_pBF.Release(); + + POSITION pos = pUnks.GetHeadPosition(); + while (pos && !(m_pBF = pUnks.GetNext(pos))) { + ; + } + + if (!m_pBF) { + return false; + } + + return true; +} + +void CPinInfoWnd::OnDisconnect() +{ + m_pBF.Release(); +} + +static WNDPROC OldControlProc; +static LRESULT CALLBACK ControlProc(HWND control, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_KEYDOWN) { + if (LOWORD(wParam) == VK_ESCAPE) { + return 0; // just ignore ESCAPE in edit control + } + 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 +} + +bool CPinInfoWnd::OnActivate() +{ + m_dpi.Override(GetSafeHwnd()); + + DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP; + CPoint p(m_dpi.ScaleX(10), m_dpi.ScaleY(10)); + + m_pin_static.Create(_T("Pin:"), dwStyle, + CRect(p + CPoint(m_dpi.ScaleX(0), m_dpi.ScaleY(3)), CSize(m_dpi.ScaleX(30), m_fontheight)), + this); + m_pin_combo.Create(dwStyle | CBS_DROPDOWNLIST, + CRect(p + CPoint(m_dpi.ScaleX(30), m_dpi.ScaleY(0)), CSize(m_dpi.ScaleX(520), m_dpi.ScaleY(200))), + this, IDC_PP_COMBO1); + BeginEnumPins(m_pBF, pEP, pPin) { + CPinInfo pi; + if (FAILED(pPin->QueryPinInfo(&pi))) { + continue; + } + CString str(pi.achName); + if (!str.Find(_T("Apple"))) { + str.Delete(0, 1); + } + CString dir = _T("[?] "); + if (pi.dir == PINDIR_INPUT) { + dir = _T("[IN] "); + } else if (pi.dir == PINDIR_OUTPUT) { + dir = _T("[OUT] "); + } + m_pin_combo.SetItemDataPtr(m_pin_combo.AddString(dir + str), pPin); + } + EndEnumPins; + m_pin_combo.SetCurSel(0); + + p.y += m_fontheight + m_dpi.ScaleY(20); + + m_info_edit.CreateEx(WS_EX_CLIENTEDGE, + _T("EDIT"), + _T(""), + dwStyle | + /* WS_BORDER | */ // equivalent to WS_EX_CLIENTEDGE + WS_VSCROLL | + WS_HSCROLL | + ES_MULTILINE | + ES_READONLY, + CRect(p, CSize(m_dpi.ScaleX(550), m_fontheight * 30)), + this, + IDC_PP_EDIT1); + m_info_edit.SetLimitText(60000); + + OnSelectedPinChange(); + + for (CWnd* pWnd = GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) { + pWnd->SetFont(&m_font, FALSE); + } + + m_info_edit.SetFixedWidthFont(m_monospacefont); + + // subclass the edit control + OldControlProc = (WNDPROC)SetWindowLongPtr(m_info_edit.m_hWnd, GWLP_WNDPROC, (LONG_PTR)ControlProc); + + return true; +} + +void CPinInfoWnd::OnDeactivate() +{ +} + +bool CPinInfoWnd::OnApply() +{ + OnDeactivate(); + + if (m_pBF) { + } + + return true; +} + +BOOL CPinInfoWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + //we don't need this anymore, as we bypass the CInternalPropertyPageWnd which is what sets it dirty + //SetDirty(false); + //we call CWnd implementation because CInternalPropertyPageWnd will set it right back to dirty on a scroll/command message + return CWnd::OnWndMsg(message, wParam, lParam, pResult); +} + +BEGIN_MESSAGE_MAP(CPinInfoWnd, CInternalPropertyPageWnd) + ON_CBN_SELCHANGE(IDC_PP_COMBO1, OnSelectedPinChange) + ON_WM_CTLCOLOR() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +void CPinInfoWnd::AddLine(CString str) +{ + str.Replace(_T("\n"), _T("\r\n")); + int len = m_info_edit.GetWindowTextLength(); + m_info_edit.SetSel(len, len, TRUE); + m_info_edit.ReplaceSel(str); +} + +void CPinInfoWnd::OnSelectedPinChange() +{ + m_info_edit.SetRedraw(FALSE); + m_info_edit.SetWindowText(_T("")); + + int i = m_pin_combo.GetCurSel(); + if (i < 0) { + return; + } + + CComPtr pPin = (IPin*)m_pin_combo.GetItemDataPtr(i); + if (!pPin) { + return; + } + + CString str; + CPinInfo pinInfo; + + if (SUCCEEDED(pPin->QueryPinInfo(&pinInfo))) { + CString strName; + CLSID filterClsid; + CFilterInfo filterInfo; + + if (SUCCEEDED(pinInfo.pFilter->QueryFilterInfo(&filterInfo))) { + CRegKey key; + pinInfo.pFilter->GetClassID(&filterClsid); + TCHAR buff[128]; + ULONG len = _countof(buff); + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\") + CStringFromGUID(filterClsid), KEY_READ) + && ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), buff, &len)) { + strName = CString(buff); + } else { + strName = filterInfo.achName; + } + str.Format(_T("Filter : %s - CLSID : %s\n\n"), strName.GetString(), CStringFromGUID(filterClsid).GetString()); + AddLine(str); + } + } + + CMediaTypeEx cmt; + + CComPtr pPinTo; + if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { + str.Format(_T("- Connected to:\n\nCLSID: %s\nFilter: %s\nPin: %s\n\n"), + CStringFromGUID(GetCLSID(pPinTo)).GetString(), + static_cast(GetFilterName(GetFilterFromPin(pPinTo))), + static_cast(GetPinName(pPinTo))); + + AddLine(str); + + AddLine(_T("- Connection media type:\n\n")); + + if (SUCCEEDED(pPin->ConnectionMediaType(&cmt))) { + CAtlList sl; + cmt.Dump(sl); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + AddLine(sl.GetNext(pos) + '\n'); + } + } + } else { + str = _T("- Not connected\n\n"); + } + + int iMT = 0; + + BeginEnumMediaTypes(pPin, pEMT, pmt) { + CMediaTypeEx mt(*pmt); + + str.Format(_T("- Enumerated media type %d:\n\n"), iMT++); + AddLine(str); + + if (cmt.majortype != GUID_NULL && mt == cmt) { + AddLine(_T("Set as the current media type\n\n")); + } else { + CAtlList sl; + mt.Dump(sl); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + AddLine(sl.GetNext(pos) + '\n'); + } + } + } + EndEnumMediaTypes(pmt); + + m_info_edit.SetSel(0, 0); + m_info_edit.SetRedraw(TRUE); + m_info_edit.RedrawWindow(NULL); +} + + +HBRUSH CPinInfoWnd::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} + +BOOL CPinInfoWnd::OnEraseBkgnd(CDC* pDC) +{ + bool ret = MPCThemeEraseBkgnd(pDC, this, CTLCOLOR_DLG); + if (ret) { + return ret; + } else { + return __super::OnEraseBkgnd(pDC); + } +} diff --git a/src/filters/PinInfoWnd.h b/src/filters/PinInfoWnd.h index 0fa17412109..f84dc55e0ee 100644 --- a/src/filters/PinInfoWnd.h +++ b/src/filters/PinInfoWnd.h @@ -1,70 +1,70 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2015 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 . - * - */ - -#pragma once - -#include "InternalPropertyPage.h" -#include "stdafx.h" -#include "../mpc-hc/DpiHelper.h" -#include "../mpc-hc/CMPCThemeStatic.h" -#include "../mpc-hc/CMPCThemeComboBox.h" -#include "../mpc-hc/CMPCThemeEdit.h" -#include "../mpc-hc/CMPCThemeUtil.h" -#include - -class __declspec(uuid("A1EB391C-6089-4A87-9988-BE50872317D4")) - CPinInfoWnd : public CInternalPropertyPageWnd, CMPCThemeUtil -{ - CComQIPtr m_pBF; - - enum { - IDC_PP_COMBO1 = 10000, - IDC_PP_EDIT1 - }; - - CMPCThemeStatic m_pin_static; - CMPCThemeComboBox m_pin_combo; - CMPCThemeEdit m_info_edit; - - DpiHelper m_dpi; - - void AddLine(CString str); - -public: - CPinInfoWnd(); - - bool OnConnect(const CInterfaceList& pUnks); - void OnDisconnect(); - bool OnActivate(); - void OnDeactivate(); - bool OnApply(); - - static LPCTSTR GetWindowTitle() { return _T("Pin Info"); } - static CSize GetWindowSize() { return { 0, 0 }; } - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - void OnSelectedPinChange(); - -protected: - virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2015 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 . + * + */ + +#pragma once + +#include "InternalPropertyPage.h" +#include "stdafx.h" +#include "../mpc-hc/DpiHelper.h" +#include "../mpc-hc/CMPCThemeStatic.h" +#include "../mpc-hc/CMPCThemeComboBox.h" +#include "../mpc-hc/CMPCThemeEdit.h" +#include "../mpc-hc/CMPCThemeUtil.h" +#include + +class __declspec(uuid("A1EB391C-6089-4A87-9988-BE50872317D4")) + CPinInfoWnd : public CInternalPropertyPageWnd, CMPCThemeUtil +{ + CComQIPtr m_pBF; + + enum { + IDC_PP_COMBO1 = 10000, + IDC_PP_EDIT1 + }; + + CMPCThemeStatic m_pin_static; + CMPCThemeComboBox m_pin_combo; + CMPCThemeEdit m_info_edit; + + DpiHelper m_dpi; + + void AddLine(CString str); + +public: + CPinInfoWnd(); + + bool OnConnect(const CInterfaceList& pUnks); + void OnDisconnect(); + bool OnActivate(); + void OnDeactivate(); + bool OnApply(); + + static LPCTSTR GetWindowTitle() { return _T("Pin Info"); } + static CSize GetWindowSize() { return { 0, 0 }; } + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + void OnSelectedPinChange(); + +protected: + virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); +}; diff --git a/src/filters/muxer/BaseMuxer/BaseMuxer.cpp b/src/filters/muxer/BaseMuxer/BaseMuxer.cpp index 25368cbd07e..3a0506879ca 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxer.cpp +++ b/src/filters/muxer/BaseMuxer/BaseMuxer.cpp @@ -1,521 +1,521 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "BaseMuxer.h" - -// -// CBaseMuxerFilter -// - -CBaseMuxerFilter::CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid) - : CBaseFilter(NAME("CBaseMuxerFilter"), pUnk, this, clsid) - , m_rtCurrent(0) -{ - if (phr) { - *phr = S_OK; - } - m_pOutput.Attach(DEBUG_NEW CBaseMuxerOutputPin(L"Output", this, this, phr)); - AddInput(); -} - -CBaseMuxerFilter::~CBaseMuxerFilter() -{ -} - -STDMETHODIMP CBaseMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - return - QI(IMediaSeeking) - QI(IPropertyBag) - QI(IPropertyBag2) - QI(IDSMPropertyBag) - QI(IDSMResourceBag) - QI(IDSMChapterBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// - -void CBaseMuxerFilter::AddInput() -{ - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CBasePin* pPin = m_pInputs.GetNext(pos); - if (!pPin->IsConnected()) { - return; - } - } - - CStringW name; - - name.Format(L"Input %u", m_pInputs.GetCount() + 1); - - CBaseMuxerInputPin* pInputPin = nullptr; - if (FAILED(CreateInput(name, &pInputPin)) || !pInputPin) { - ASSERT(0); - return; - } - CAutoPtr pAutoPtrInputPin(pInputPin); - - name.Format(L"~Output %u", m_pRawOutputs.GetCount() + 1); - - CBaseMuxerRawOutputPin* pRawOutputPin = nullptr; - if (FAILED(CreateRawOutput(name, &pRawOutputPin)) || !pRawOutputPin) { - ASSERT(0); - return; - } - CAutoPtr pAutoPtrRawOutputPin(pRawOutputPin); - - pInputPin->SetRelatedPin(pRawOutputPin); - pRawOutputPin->SetRelatedPin(pInputPin); - - m_pInputs.AddTail(pAutoPtrInputPin); - m_pRawOutputs.AddTail(pAutoPtrRawOutputPin); -} - -HRESULT CBaseMuxerFilter::CreateInput(CStringW name, CBaseMuxerInputPin** ppPin) -{ - CheckPointer(ppPin, E_POINTER); - HRESULT hr = S_OK; - *ppPin = DEBUG_NEW CBaseMuxerInputPin(name, this, this, &hr); - return hr; -} - -HRESULT CBaseMuxerFilter::CreateRawOutput(CStringW name, CBaseMuxerRawOutputPin** ppPin) -{ - CheckPointer(ppPin, E_POINTER); - HRESULT hr = S_OK; - *ppPin = DEBUG_NEW CBaseMuxerRawOutputPin(name, this, this, &hr); - return hr; -} - -// - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CBaseMuxerFilter::ThreadProc() -{ - SetThreadPriority(m_hThread, THREAD_PRIORITY_ABOVE_NORMAL); - - POSITION pos; - - for (;;) { - DWORD cmd = GetRequest(); - - switch (cmd) { - default: - case CMD_EXIT: - CAMThread::m_hThread = nullptr; - Reply(S_OK); - return 0; - - case CMD_RUN: - m_pActivePins.RemoveAll(); - m_pPins.RemoveAll(); - - pos = m_pInputs.GetHeadPosition(); - while (pos) { - CBaseMuxerInputPin* pPin = m_pInputs.GetNext(pos); - if (pPin->IsConnected()) { - m_pActivePins.AddTail(pPin); - m_pPins.AddTail(pPin); - } - } - - m_rtCurrent = 0; - - Reply(S_OK); - - MuxInit(); - - try { - MuxHeaderInternal(); - - while (!CheckRequest(nullptr) && m_pActivePins.GetCount()) { - if (m_State == State_Paused) { - Sleep(10); - continue; - } - - CAutoPtr pPacket(GetPacket().Detach()); - if (!pPacket) { - Sleep(1); - continue; - } - - if (pPacket->IsTimeValid()) { - m_rtCurrent = pPacket->rtStart; - } - - if (pPacket->IsEOS()) { - m_pActivePins.RemoveAt(m_pActivePins.Find(pPacket->pPin)); - } - - MuxPacketInternal(pPacket); - } - - MuxFooterInternal(); - } catch (HRESULT hr) { - CComQIPtr(m_pGraph)->Notify(EC_ERRORABORT, hr, 0); - } - - m_pOutput->DeliverEndOfStream(); - - pos = m_pRawOutputs.GetHeadPosition(); - while (pos) { - m_pRawOutputs.GetNext(pos)->DeliverEndOfStream(); - } - - m_pActivePins.RemoveAll(); - m_pPins.RemoveAll(); - - break; - } - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -void CBaseMuxerFilter::MuxHeaderInternal() -{ - TRACE(_T("MuxHeader\n")); - - if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { - MuxHeader(pBitStream); - } - - MuxHeader(); - - // - - POSITION pos = m_pPins.GetHeadPosition(); - while (pos) { - if (CBaseMuxerInputPin* pInput = m_pPins.GetNext(pos)) - if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { - pOutput->MuxHeader(pInput->CurrentMediaType()); - } - } -} - -void CBaseMuxerFilter::MuxPacketInternal(const MuxerPacket* pPacket) -{ - TRACE(_T("MuxPacket pPin=%x, size=%d, s%d e%d b%d, rt=(%I64d-%I64d)\n"), - pPacket->pPin->GetID(), - pPacket->pData.GetCount(), - !!(pPacket->flags & MuxerPacket::syncpoint), - !!(pPacket->flags & MuxerPacket::eos), - !!(pPacket->flags & MuxerPacket::bogus), - pPacket->rtStart / 10000, pPacket->rtStop / 10000); - - if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { - MuxPacket(pBitStream, pPacket); - } - - MuxPacket(pPacket); - - if (CBaseMuxerInputPin* pInput = pPacket->pPin) - if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { - pOutput->MuxPacket(pInput->CurrentMediaType(), pPacket); - } -} - -void CBaseMuxerFilter::MuxFooterInternal() -{ - TRACE(_T("MuxFooter\n")); - - if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { - MuxFooter(pBitStream); - } - - MuxFooter(); - - // - - POSITION pos = m_pPins.GetHeadPosition(); - while (pos) { - if (CBaseMuxerInputPin* pInput = m_pPins.GetNext(pos)) - if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { - pOutput->MuxFooter(pInput->CurrentMediaType()); - } - } -} - -CAutoPtr CBaseMuxerFilter::GetPacket() -{ - REFERENCE_TIME rtMin = _I64_MAX; - CBaseMuxerInputPin* pPinMin = nullptr; - int i = int(m_pActivePins.GetCount()); - - POSITION pos = m_pActivePins.GetHeadPosition(); - while (pos) { - CBaseMuxerInputPin* pPin = m_pActivePins.GetNext(pos); - - CAutoLock cAutoLock(&pPin->m_csQueue); - if (!pPin->m_queue.GetCount()) { - continue; - } - - MuxerPacket* p = pPin->m_queue.GetHead(); - - if (p->IsBogus() || !p->IsTimeValid() || p->IsEOS()) { - pPinMin = pPin; - i = 0; - break; - } - - if (p->rtStart < rtMin) { - rtMin = p->rtStart; - pPinMin = pPin; - } - - i--; - } - - CAutoPtr pPacket; - - if (pPinMin && i == 0) { - pPacket.Attach(pPinMin->PopPacket().Detach()); - } else { - pos = m_pActivePins.GetHeadPosition(); - while (pos) { - m_pActivePins.GetNext(pos)->m_evAcceptPacket.Set(); - } - } - - return pPacket; -} - -// - -int CBaseMuxerFilter::GetPinCount() -{ - return int(m_pInputs.GetCount()) + (m_pOutput ? 1 : 0) + int(m_pRawOutputs.GetCount()); -} - -CBasePin* CBaseMuxerFilter::GetPin(int n) -{ - CAutoLock cAutoLock(this); - - if (n >= 0 && n < (int)m_pInputs.GetCount()) { - if (POSITION pos = m_pInputs.FindIndex(n)) { - return m_pInputs.GetAt(pos); - } - } - - n -= int(m_pInputs.GetCount()); - - if (n == 0 && m_pOutput) { - return m_pOutput; - } - - n--; - - if (n >= 0 && n < (int)m_pRawOutputs.GetCount()) { - if (POSITION pos = m_pRawOutputs.FindIndex(n)) { - return m_pRawOutputs.GetAt(pos); - } - } - - //n -= int(m_pRawOutputs.GetCount()); - - return nullptr; -} - -STDMETHODIMP CBaseMuxerFilter::Stop() -{ - CAutoLock cAutoLock(this); - - HRESULT hr = __super::Stop(); - if (FAILED(hr)) { - return hr; - } - - CallWorker(CMD_EXIT); - - return hr; -} - -STDMETHODIMP CBaseMuxerFilter::Pause() -{ - CAutoLock cAutoLock(this); - - FILTER_STATE fs = m_State; - - HRESULT hr = __super::Pause(); - if (FAILED(hr)) { - return hr; - } - - if (fs == State_Stopped && m_pOutput) { - CAMThread::Create(); - CallWorker(CMD_RUN); - } - - return hr; -} - -STDMETHODIMP CBaseMuxerFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cAutoLock(this); - - HRESULT hr = __super::Run(tStart); - if (FAILED(hr)) { - return hr; - } - - return hr; -} - -// IMediaSeeking - -STDMETHODIMP CBaseMuxerFilter::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanGetDuration | AM_SEEKING_CanGetCurrentPos; - - return S_OK; -} - -STDMETHODIMP CBaseMuxerFilter::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - if (*pCapabilities == 0) { - return S_OK; - } - DWORD caps; - GetCapabilities(&caps); - caps &= *pCapabilities; - return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseMuxerFilter::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseMuxerFilter::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseMuxerFilter::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CBaseMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CBaseMuxerFilter::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CBaseMuxerFilter::GetDuration(LONGLONG* pDuration) -{ - CheckPointer(pDuration, E_POINTER); - *pDuration = 0; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - REFERENCE_TIME rt = m_pInputs.GetNext(pos)->GetDuration(); - if (rt > *pDuration) { - *pDuration = rt; - } - } - return S_OK; -} - -STDMETHODIMP CBaseMuxerFilter::GetStopPosition(LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent) -{ - CheckPointer(pCurrent, E_POINTER); - *pCurrent = m_rtCurrent; - return S_OK; -} - -STDMETHODIMP CBaseMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - FILTER_STATE fs; - - if (SUCCEEDED(GetState(0, &fs)) && fs == State_Stopped) { - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CBasePin* pPin = m_pInputs.GetNext(pos); - CComQIPtr pMS = pPin->GetConnected(); - if (!pMS) { - pMS = GetFilterFromPin(pPin->GetConnected()); - } - if (pMS) { - pMS->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); - } - } - - return S_OK; - } - - return VFW_E_WRONG_STATE; -} - -STDMETHODIMP CBaseMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::SetRate(double dRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::GetRate(double* pdRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::GetPreroll(LONGLONG* pllPreroll) -{ - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "BaseMuxer.h" + +// +// CBaseMuxerFilter +// + +CBaseMuxerFilter::CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid) + : CBaseFilter(NAME("CBaseMuxerFilter"), pUnk, this, clsid) + , m_rtCurrent(0) +{ + if (phr) { + *phr = S_OK; + } + m_pOutput.Attach(DEBUG_NEW CBaseMuxerOutputPin(L"Output", this, this, phr)); + AddInput(); +} + +CBaseMuxerFilter::~CBaseMuxerFilter() +{ +} + +STDMETHODIMP CBaseMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + return + QI(IMediaSeeking) + QI(IPropertyBag) + QI(IPropertyBag2) + QI(IDSMPropertyBag) + QI(IDSMResourceBag) + QI(IDSMChapterBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// + +void CBaseMuxerFilter::AddInput() +{ + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CBasePin* pPin = m_pInputs.GetNext(pos); + if (!pPin->IsConnected()) { + return; + } + } + + CStringW name; + + name.Format(L"Input %u", m_pInputs.GetCount() + 1); + + CBaseMuxerInputPin* pInputPin = nullptr; + if (FAILED(CreateInput(name, &pInputPin)) || !pInputPin) { + ASSERT(0); + return; + } + CAutoPtr pAutoPtrInputPin(pInputPin); + + name.Format(L"~Output %u", m_pRawOutputs.GetCount() + 1); + + CBaseMuxerRawOutputPin* pRawOutputPin = nullptr; + if (FAILED(CreateRawOutput(name, &pRawOutputPin)) || !pRawOutputPin) { + ASSERT(0); + return; + } + CAutoPtr pAutoPtrRawOutputPin(pRawOutputPin); + + pInputPin->SetRelatedPin(pRawOutputPin); + pRawOutputPin->SetRelatedPin(pInputPin); + + m_pInputs.AddTail(pAutoPtrInputPin); + m_pRawOutputs.AddTail(pAutoPtrRawOutputPin); +} + +HRESULT CBaseMuxerFilter::CreateInput(CStringW name, CBaseMuxerInputPin** ppPin) +{ + CheckPointer(ppPin, E_POINTER); + HRESULT hr = S_OK; + *ppPin = DEBUG_NEW CBaseMuxerInputPin(name, this, this, &hr); + return hr; +} + +HRESULT CBaseMuxerFilter::CreateRawOutput(CStringW name, CBaseMuxerRawOutputPin** ppPin) +{ + CheckPointer(ppPin, E_POINTER); + HRESULT hr = S_OK; + *ppPin = DEBUG_NEW CBaseMuxerRawOutputPin(name, this, this, &hr); + return hr; +} + +// + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CBaseMuxerFilter::ThreadProc() +{ + SetThreadPriority(m_hThread, THREAD_PRIORITY_ABOVE_NORMAL); + + POSITION pos; + + for (;;) { + DWORD cmd = GetRequest(); + + switch (cmd) { + default: + case CMD_EXIT: + CAMThread::m_hThread = nullptr; + Reply(S_OK); + return 0; + + case CMD_RUN: + m_pActivePins.RemoveAll(); + m_pPins.RemoveAll(); + + pos = m_pInputs.GetHeadPosition(); + while (pos) { + CBaseMuxerInputPin* pPin = m_pInputs.GetNext(pos); + if (pPin->IsConnected()) { + m_pActivePins.AddTail(pPin); + m_pPins.AddTail(pPin); + } + } + + m_rtCurrent = 0; + + Reply(S_OK); + + MuxInit(); + + try { + MuxHeaderInternal(); + + while (!CheckRequest(nullptr) && m_pActivePins.GetCount()) { + if (m_State == State_Paused) { + Sleep(10); + continue; + } + + CAutoPtr pPacket(GetPacket().Detach()); + if (!pPacket) { + Sleep(1); + continue; + } + + if (pPacket->IsTimeValid()) { + m_rtCurrent = pPacket->rtStart; + } + + if (pPacket->IsEOS()) { + m_pActivePins.RemoveAt(m_pActivePins.Find(pPacket->pPin)); + } + + MuxPacketInternal(pPacket); + } + + MuxFooterInternal(); + } catch (HRESULT hr) { + CComQIPtr(m_pGraph)->Notify(EC_ERRORABORT, hr, 0); + } + + m_pOutput->DeliverEndOfStream(); + + pos = m_pRawOutputs.GetHeadPosition(); + while (pos) { + m_pRawOutputs.GetNext(pos)->DeliverEndOfStream(); + } + + m_pActivePins.RemoveAll(); + m_pPins.RemoveAll(); + + break; + } + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +void CBaseMuxerFilter::MuxHeaderInternal() +{ + TRACE(_T("MuxHeader\n")); + + if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { + MuxHeader(pBitStream); + } + + MuxHeader(); + + // + + POSITION pos = m_pPins.GetHeadPosition(); + while (pos) { + if (CBaseMuxerInputPin* pInput = m_pPins.GetNext(pos)) + if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { + pOutput->MuxHeader(pInput->CurrentMediaType()); + } + } +} + +void CBaseMuxerFilter::MuxPacketInternal(const MuxerPacket* pPacket) +{ + TRACE(_T("MuxPacket pPin=%x, size=%d, s%d e%d b%d, rt=(%I64d-%I64d)\n"), + pPacket->pPin->GetID(), + pPacket->pData.GetCount(), + !!(pPacket->flags & MuxerPacket::syncpoint), + !!(pPacket->flags & MuxerPacket::eos), + !!(pPacket->flags & MuxerPacket::bogus), + pPacket->rtStart / 10000, pPacket->rtStop / 10000); + + if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { + MuxPacket(pBitStream, pPacket); + } + + MuxPacket(pPacket); + + if (CBaseMuxerInputPin* pInput = pPacket->pPin) + if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { + pOutput->MuxPacket(pInput->CurrentMediaType(), pPacket); + } +} + +void CBaseMuxerFilter::MuxFooterInternal() +{ + TRACE(_T("MuxFooter\n")); + + if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { + MuxFooter(pBitStream); + } + + MuxFooter(); + + // + + POSITION pos = m_pPins.GetHeadPosition(); + while (pos) { + if (CBaseMuxerInputPin* pInput = m_pPins.GetNext(pos)) + if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { + pOutput->MuxFooter(pInput->CurrentMediaType()); + } + } +} + +CAutoPtr CBaseMuxerFilter::GetPacket() +{ + REFERENCE_TIME rtMin = _I64_MAX; + CBaseMuxerInputPin* pPinMin = nullptr; + int i = int(m_pActivePins.GetCount()); + + POSITION pos = m_pActivePins.GetHeadPosition(); + while (pos) { + CBaseMuxerInputPin* pPin = m_pActivePins.GetNext(pos); + + CAutoLock cAutoLock(&pPin->m_csQueue); + if (!pPin->m_queue.GetCount()) { + continue; + } + + MuxerPacket* p = pPin->m_queue.GetHead(); + + if (p->IsBogus() || !p->IsTimeValid() || p->IsEOS()) { + pPinMin = pPin; + i = 0; + break; + } + + if (p->rtStart < rtMin) { + rtMin = p->rtStart; + pPinMin = pPin; + } + + i--; + } + + CAutoPtr pPacket; + + if (pPinMin && i == 0) { + pPacket.Attach(pPinMin->PopPacket().Detach()); + } else { + pos = m_pActivePins.GetHeadPosition(); + while (pos) { + m_pActivePins.GetNext(pos)->m_evAcceptPacket.Set(); + } + } + + return pPacket; +} + +// + +int CBaseMuxerFilter::GetPinCount() +{ + return int(m_pInputs.GetCount()) + (m_pOutput ? 1 : 0) + int(m_pRawOutputs.GetCount()); +} + +CBasePin* CBaseMuxerFilter::GetPin(int n) +{ + CAutoLock cAutoLock(this); + + if (n >= 0 && n < (int)m_pInputs.GetCount()) { + if (POSITION pos = m_pInputs.FindIndex(n)) { + return m_pInputs.GetAt(pos); + } + } + + n -= int(m_pInputs.GetCount()); + + if (n == 0 && m_pOutput) { + return m_pOutput; + } + + n--; + + if (n >= 0 && n < (int)m_pRawOutputs.GetCount()) { + if (POSITION pos = m_pRawOutputs.FindIndex(n)) { + return m_pRawOutputs.GetAt(pos); + } + } + + //n -= int(m_pRawOutputs.GetCount()); + + return nullptr; +} + +STDMETHODIMP CBaseMuxerFilter::Stop() +{ + CAutoLock cAutoLock(this); + + HRESULT hr = __super::Stop(); + if (FAILED(hr)) { + return hr; + } + + CallWorker(CMD_EXIT); + + return hr; +} + +STDMETHODIMP CBaseMuxerFilter::Pause() +{ + CAutoLock cAutoLock(this); + + FILTER_STATE fs = m_State; + + HRESULT hr = __super::Pause(); + if (FAILED(hr)) { + return hr; + } + + if (fs == State_Stopped && m_pOutput) { + CAMThread::Create(); + CallWorker(CMD_RUN); + } + + return hr; +} + +STDMETHODIMP CBaseMuxerFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cAutoLock(this); + + HRESULT hr = __super::Run(tStart); + if (FAILED(hr)) { + return hr; + } + + return hr; +} + +// IMediaSeeking + +STDMETHODIMP CBaseMuxerFilter::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanGetDuration | AM_SEEKING_CanGetCurrentPos; + + return S_OK; +} + +STDMETHODIMP CBaseMuxerFilter::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + if (*pCapabilities == 0) { + return S_OK; + } + DWORD caps; + GetCapabilities(&caps); + caps &= *pCapabilities; + return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseMuxerFilter::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseMuxerFilter::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseMuxerFilter::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CBaseMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CBaseMuxerFilter::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CBaseMuxerFilter::GetDuration(LONGLONG* pDuration) +{ + CheckPointer(pDuration, E_POINTER); + *pDuration = 0; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + REFERENCE_TIME rt = m_pInputs.GetNext(pos)->GetDuration(); + if (rt > *pDuration) { + *pDuration = rt; + } + } + return S_OK; +} + +STDMETHODIMP CBaseMuxerFilter::GetStopPosition(LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent) +{ + CheckPointer(pCurrent, E_POINTER); + *pCurrent = m_rtCurrent; + return S_OK; +} + +STDMETHODIMP CBaseMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + FILTER_STATE fs; + + if (SUCCEEDED(GetState(0, &fs)) && fs == State_Stopped) { + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CBasePin* pPin = m_pInputs.GetNext(pos); + CComQIPtr pMS = pPin->GetConnected(); + if (!pMS) { + pMS = GetFilterFromPin(pPin->GetConnected()); + } + if (pMS) { + pMS->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); + } + } + + return S_OK; + } + + return VFW_E_WRONG_STATE; +} + +STDMETHODIMP CBaseMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::SetRate(double dRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::GetRate(double* pdRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::GetPreroll(LONGLONG* pllPreroll) +{ + return E_NOTIMPL; +} diff --git a/src/filters/muxer/BaseMuxer/BaseMuxer.h b/src/filters/muxer/BaseMuxer/BaseMuxer.h index be367f7b629..942627830ea 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxer.h +++ b/src/filters/muxer/BaseMuxer/BaseMuxer.h @@ -1,110 +1,110 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "BaseMuxerInputPin.h" -#include "BaseMuxerOutputPin.h" - -class CBaseMuxerFilter - : public CBaseFilter - , public CCritSec - , public CAMThread - , public IMediaSeeking - , public IDSMPropertyBagImpl - , public IDSMResourceBagImpl - , public IDSMChapterBagImpl -{ -private: - CAutoPtrList m_pInputs; - CAutoPtr m_pOutput; - CAutoPtrList m_pRawOutputs; - - enum { CMD_EXIT, CMD_RUN }; - DWORD ThreadProc(); - - REFERENCE_TIME m_rtCurrent; - CAtlList m_pActivePins; - - CAutoPtr GetPacket(); - - void MuxHeaderInternal(); - void MuxPacketInternal(const MuxerPacket* pPacket); - void MuxFooterInternal(); - -protected: - CAtlList m_pPins; - CBaseMuxerOutputPin* GetOutputPin() { return m_pOutput; } - - virtual void MuxInit() = 0; - - // only called when the output pin is connected - virtual void MuxHeader(IBitStream* pBS) {} - virtual void MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket) {} - virtual void MuxFooter(IBitStream* pBS) {} - - // always called (useful if the derived class wants to write somewhere else than downstream) - virtual void MuxHeader() {} - virtual void MuxPacket(const MuxerPacket* pPacket) {} - virtual void MuxFooter() {} - - // allows customized pins in derived classes - virtual HRESULT CreateInput(CStringW name, CBaseMuxerInputPin** ppPin); - virtual HRESULT CreateRawOutput(CStringW name, CBaseMuxerRawOutputPin** ppPin); - -public: - CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid); - virtual ~CBaseMuxerFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - void AddInput(); - - int GetPinCount(); - CBasePin* GetPin(int n); - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "BaseMuxerInputPin.h" +#include "BaseMuxerOutputPin.h" + +class CBaseMuxerFilter + : public CBaseFilter + , public CCritSec + , public CAMThread + , public IMediaSeeking + , public IDSMPropertyBagImpl + , public IDSMResourceBagImpl + , public IDSMChapterBagImpl +{ +private: + CAutoPtrList m_pInputs; + CAutoPtr m_pOutput; + CAutoPtrList m_pRawOutputs; + + enum { CMD_EXIT, CMD_RUN }; + DWORD ThreadProc(); + + REFERENCE_TIME m_rtCurrent; + CAtlList m_pActivePins; + + CAutoPtr GetPacket(); + + void MuxHeaderInternal(); + void MuxPacketInternal(const MuxerPacket* pPacket); + void MuxFooterInternal(); + +protected: + CAtlList m_pPins; + CBaseMuxerOutputPin* GetOutputPin() { return m_pOutput; } + + virtual void MuxInit() = 0; + + // only called when the output pin is connected + virtual void MuxHeader(IBitStream* pBS) {} + virtual void MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket) {} + virtual void MuxFooter(IBitStream* pBS) {} + + // always called (useful if the derived class wants to write somewhere else than downstream) + virtual void MuxHeader() {} + virtual void MuxPacket(const MuxerPacket* pPacket) {} + virtual void MuxFooter() {} + + // allows customized pins in derived classes + virtual HRESULT CreateInput(CStringW name, CBaseMuxerInputPin** ppPin); + virtual HRESULT CreateRawOutput(CStringW name, CBaseMuxerRawOutputPin** ppPin); + +public: + CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid); + virtual ~CBaseMuxerFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + void AddInput(); + + int GetPinCount(); + CBasePin* GetPin(int n); + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); +}; diff --git a/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj b/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj index 0b774cefb9c..177c2b27430 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj +++ b/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj @@ -1,74 +1,74 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {DB5F93B2-54D0-4474-A588-D259BE36C832} - BaseMuxer - MFCProj - BaseMuxer - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - - - Create - - - - - - - - - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {DB5F93B2-54D0-4474-A588-D259BE36C832} + BaseMuxer + MFCProj + BaseMuxer + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + + + Create + + + + + + + + + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj.filters b/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj.filters index 5b978fca968..67f63e1d486 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj.filters +++ b/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj.filters @@ -1,53 +1,53 @@ - - - - - {b0dec0e2-a0fd-4979-b3c8-e2a8b7b8a7b9} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {09ccdde9-0352-4031-8414-81a0579c014b} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {b0dec0e2-a0fd-4979-b3c8-e2a8b7b8a7b9} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {09ccdde9-0352-4031-8414-81a0579c014b} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.cpp b/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.cpp index a55ade0e728..537bd233280 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.cpp +++ b/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.cpp @@ -1,286 +1,286 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "BaseMuxer.h" -#include "../../../DSUtil/DSUtil.h" -#include "moreuuids.h" - -#define MAXQUEUESIZE 100 - -// -// CBaseMuxerInputPin -// - -CBaseMuxerInputPin::CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseInputPin(NAME("CBaseMuxerInputPin"), pFilter, pLock, phr, pName) - , m_rtMaxStart(_I64_MIN) - , m_rtDuration(0) - , m_fEOS(false) - , m_iPacketIndex(0) - , m_evAcceptPacket(TRUE) -{ - static int s_iID = 0; - m_iID = s_iID++; -} - -CBaseMuxerInputPin::~CBaseMuxerInputPin() -{ -} - -STDMETHODIMP CBaseMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IBaseMuxerRelatedPin) - QI(IPropertyBag) - QI(IPropertyBag2) - QI(IDSMPropertyBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -bool CBaseMuxerInputPin::IsSubtitleStream() -{ - return m_mt.majortype == MEDIATYPE_Subtitle || m_mt.majortype == MEDIATYPE_Text; -} - -void CBaseMuxerInputPin::PushPacket(CAutoPtr pPacket) -{ - for (int i = 0; m_pFilter->IsActive() && !m_bFlushing - && !m_evAcceptPacket.Wait(1) - && i < 1000; - i++) { - ; - } - - if (!m_pFilter->IsActive() || m_bFlushing) { - return; - } - - CAutoLock cAutoLock(&m_csQueue); - - m_queue.AddTail(pPacket); - - if (m_queue.GetCount() >= MAXQUEUESIZE) { - m_evAcceptPacket.Reset(); - } -} - -CAutoPtr CBaseMuxerInputPin::PopPacket() -{ - CAutoPtr pPacket; - - CAutoLock cAutoLock(&m_csQueue); - - if (m_queue.GetCount()) { - pPacket.Attach(m_queue.RemoveHead().Detach()); - } - - if (m_queue.GetCount() < MAXQUEUESIZE) { - m_evAcceptPacket.Set(); - } - - return pPacket; -} - -HRESULT CBaseMuxerInputPin::CheckMediaType(const CMediaType* pmt) -{ - if (pmt->formattype == FORMAT_WaveFormatEx) { - WORD wFormatTag = ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag; - if ((wFormatTag == WAVE_FORMAT_PCM - || wFormatTag == WAVE_FORMAT_EXTENSIBLE - || wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - && pmt->subtype != FOURCCMap(wFormatTag) - && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_EXTENSIBLE) - && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - && pmt->subtype != MEDIASUBTYPE_DVD_LPCM_AUDIO - && pmt->subtype != MEDIASUBTYPE_DOLBY_AC3 - && pmt->subtype != MEDIASUBTYPE_DTS) { - return E_INVALIDARG; - } - } - - return pmt->majortype == MEDIATYPE_Video - || pmt->majortype == MEDIATYPE_Audio && pmt->formattype != FORMAT_VorbisFormat - || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None - || pmt->majortype == MEDIATYPE_Subtitle - ? S_OK - : E_INVALIDARG; -} - -HRESULT CBaseMuxerInputPin::BreakConnect() -{ - HRESULT hr = __super::BreakConnect(); - if (FAILED(hr)) { - return hr; - } - - RemoveAll(); - - // TODO: remove extra disconnected pins, leave one - - return hr; -} - -HRESULT CBaseMuxerInputPin::CompleteConnect(IPin* pReceivePin) -{ - HRESULT hr = __super::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - // duration - - m_rtDuration = 0; - CComQIPtr pMS; - if ((pMS = GetFilterFromPin(pReceivePin)) || (pMS = pReceivePin)) { - pMS->GetDuration(&m_rtDuration); - } - - // properties - - for (CComPtr pPin = pReceivePin; pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { - if (CComQIPtr pPB = pPin) { - ULONG cProperties = 0; - if (SUCCEEDED(pPB->CountProperties(&cProperties)) && cProperties > 0) { - for (ULONG iProperty = 0; iProperty < cProperties; iProperty++) { - PROPBAG2 PropBag; - ZeroMemory(&PropBag, sizeof(PropBag)); - ULONG cPropertiesReturned = 0; - if (FAILED(pPB->GetPropertyInfo(iProperty, 1, &PropBag, &cPropertiesReturned))) { - continue; - } - - HRESULT hr2; - CComVariant var; - if (SUCCEEDED(pPB->Read(1, &PropBag, nullptr, &var, &hr2)) && SUCCEEDED(hr2)) { - SetProperty(PropBag.pstrName, &var); - } - - CoTaskMemFree(PropBag.pstrName); - } - } - } - } - - (static_cast(m_pFilter))->AddInput(); - - return S_OK; -} - -HRESULT CBaseMuxerInputPin::Active() -{ - m_rtMaxStart = _I64_MIN; - m_fEOS = false; - m_iPacketIndex = 0; - m_evAcceptPacket.Set(); - return __super::Active(); -} - -HRESULT CBaseMuxerInputPin::Inactive() -{ - CAutoLock cAutoLock(&m_csQueue); - m_queue.RemoveAll(); - return __super::Inactive(); -} - -STDMETHODIMP CBaseMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - CAutoLock cAutoLock(&m_csReceive); - - return __super::NewSegment(tStart, tStop, dRate); -} - -STDMETHODIMP CBaseMuxerInputPin::Receive(IMediaSample* pSample) -{ - CAutoLock cAutoLock(&m_csReceive); - - HRESULT hr = __super::Receive(pSample); - if (FAILED(hr)) { - return hr; - } - - CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); - - long len = pSample->GetActualDataLength(); - - BYTE* pData = nullptr; - if (FAILED(pSample->GetPointer(&pData)) || !pData) { - return S_OK; - } - - pPacket->pData.SetCount(len); - memcpy(pPacket->pData.GetData(), pData, len); - - if (S_OK == pSample->IsSyncPoint() || m_mt.majortype == MEDIATYPE_Audio && !m_mt.bTemporalCompression) { - pPacket->flags |= MuxerPacket::syncpoint; - } - - if (S_OK == pSample->GetTime(&pPacket->rtStart, &pPacket->rtStop)) { - pPacket->flags |= MuxerPacket::timevalid; - - pPacket->rtStart += m_tStart; - pPacket->rtStop += m_tStart; - - if ((pPacket->flags & MuxerPacket::syncpoint) && pPacket->rtStart < m_rtMaxStart) { - pPacket->flags &= ~MuxerPacket::syncpoint; - pPacket->flags |= MuxerPacket::bogus; - } - - m_rtMaxStart = std::max(m_rtMaxStart, pPacket->rtStart); - } else if (pPacket->flags & MuxerPacket::syncpoint) { - pPacket->flags &= ~MuxerPacket::syncpoint; - pPacket->flags |= MuxerPacket::bogus; - } - - if (S_OK == pSample->IsDiscontinuity()) { - pPacket->flags |= MuxerPacket::discontinuity; - } - - pPacket->index = m_iPacketIndex++; - - PushPacket(pPacket); - - return S_OK; -} - -STDMETHODIMP CBaseMuxerInputPin::EndOfStream() -{ - CAutoLock cAutoLock(&m_csReceive); - - HRESULT hr = __super::EndOfStream(); - if (FAILED(hr)) { - return hr; - } - - ASSERT(!m_fEOS); - - CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); - pPacket->flags |= MuxerPacket::eos; - PushPacket(pPacket); - - m_fEOS = true; - - return hr; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "BaseMuxer.h" +#include "../../../DSUtil/DSUtil.h" +#include "moreuuids.h" + +#define MAXQUEUESIZE 100 + +// +// CBaseMuxerInputPin +// + +CBaseMuxerInputPin::CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseInputPin(NAME("CBaseMuxerInputPin"), pFilter, pLock, phr, pName) + , m_rtMaxStart(_I64_MIN) + , m_rtDuration(0) + , m_fEOS(false) + , m_iPacketIndex(0) + , m_evAcceptPacket(TRUE) +{ + static int s_iID = 0; + m_iID = s_iID++; +} + +CBaseMuxerInputPin::~CBaseMuxerInputPin() +{ +} + +STDMETHODIMP CBaseMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IBaseMuxerRelatedPin) + QI(IPropertyBag) + QI(IPropertyBag2) + QI(IDSMPropertyBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +bool CBaseMuxerInputPin::IsSubtitleStream() +{ + return m_mt.majortype == MEDIATYPE_Subtitle || m_mt.majortype == MEDIATYPE_Text; +} + +void CBaseMuxerInputPin::PushPacket(CAutoPtr pPacket) +{ + for (int i = 0; m_pFilter->IsActive() && !m_bFlushing + && !m_evAcceptPacket.Wait(1) + && i < 1000; + i++) { + ; + } + + if (!m_pFilter->IsActive() || m_bFlushing) { + return; + } + + CAutoLock cAutoLock(&m_csQueue); + + m_queue.AddTail(pPacket); + + if (m_queue.GetCount() >= MAXQUEUESIZE) { + m_evAcceptPacket.Reset(); + } +} + +CAutoPtr CBaseMuxerInputPin::PopPacket() +{ + CAutoPtr pPacket; + + CAutoLock cAutoLock(&m_csQueue); + + if (m_queue.GetCount()) { + pPacket.Attach(m_queue.RemoveHead().Detach()); + } + + if (m_queue.GetCount() < MAXQUEUESIZE) { + m_evAcceptPacket.Set(); + } + + return pPacket; +} + +HRESULT CBaseMuxerInputPin::CheckMediaType(const CMediaType* pmt) +{ + if (pmt->formattype == FORMAT_WaveFormatEx) { + WORD wFormatTag = ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag; + if ((wFormatTag == WAVE_FORMAT_PCM + || wFormatTag == WAVE_FORMAT_EXTENSIBLE + || wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + && pmt->subtype != FOURCCMap(wFormatTag) + && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_EXTENSIBLE) + && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + && pmt->subtype != MEDIASUBTYPE_DVD_LPCM_AUDIO + && pmt->subtype != MEDIASUBTYPE_DOLBY_AC3 + && pmt->subtype != MEDIASUBTYPE_DTS) { + return E_INVALIDARG; + } + } + + return pmt->majortype == MEDIATYPE_Video + || pmt->majortype == MEDIATYPE_Audio && pmt->formattype != FORMAT_VorbisFormat + || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None + || pmt->majortype == MEDIATYPE_Subtitle + ? S_OK + : E_INVALIDARG; +} + +HRESULT CBaseMuxerInputPin::BreakConnect() +{ + HRESULT hr = __super::BreakConnect(); + if (FAILED(hr)) { + return hr; + } + + RemoveAll(); + + // TODO: remove extra disconnected pins, leave one + + return hr; +} + +HRESULT CBaseMuxerInputPin::CompleteConnect(IPin* pReceivePin) +{ + HRESULT hr = __super::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + // duration + + m_rtDuration = 0; + CComQIPtr pMS; + if ((pMS = GetFilterFromPin(pReceivePin)) || (pMS = pReceivePin)) { + pMS->GetDuration(&m_rtDuration); + } + + // properties + + for (CComPtr pPin = pReceivePin; pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { + if (CComQIPtr pPB = pPin) { + ULONG cProperties = 0; + if (SUCCEEDED(pPB->CountProperties(&cProperties)) && cProperties > 0) { + for (ULONG iProperty = 0; iProperty < cProperties; iProperty++) { + PROPBAG2 PropBag; + ZeroMemory(&PropBag, sizeof(PropBag)); + ULONG cPropertiesReturned = 0; + if (FAILED(pPB->GetPropertyInfo(iProperty, 1, &PropBag, &cPropertiesReturned))) { + continue; + } + + HRESULT hr2; + CComVariant var; + if (SUCCEEDED(pPB->Read(1, &PropBag, nullptr, &var, &hr2)) && SUCCEEDED(hr2)) { + SetProperty(PropBag.pstrName, &var); + } + + CoTaskMemFree(PropBag.pstrName); + } + } + } + } + + (static_cast(m_pFilter))->AddInput(); + + return S_OK; +} + +HRESULT CBaseMuxerInputPin::Active() +{ + m_rtMaxStart = _I64_MIN; + m_fEOS = false; + m_iPacketIndex = 0; + m_evAcceptPacket.Set(); + return __super::Active(); +} + +HRESULT CBaseMuxerInputPin::Inactive() +{ + CAutoLock cAutoLock(&m_csQueue); + m_queue.RemoveAll(); + return __super::Inactive(); +} + +STDMETHODIMP CBaseMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CAutoLock cAutoLock(&m_csReceive); + + return __super::NewSegment(tStart, tStop, dRate); +} + +STDMETHODIMP CBaseMuxerInputPin::Receive(IMediaSample* pSample) +{ + CAutoLock cAutoLock(&m_csReceive); + + HRESULT hr = __super::Receive(pSample); + if (FAILED(hr)) { + return hr; + } + + CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); + + long len = pSample->GetActualDataLength(); + + BYTE* pData = nullptr; + if (FAILED(pSample->GetPointer(&pData)) || !pData) { + return S_OK; + } + + pPacket->pData.SetCount(len); + memcpy(pPacket->pData.GetData(), pData, len); + + if (S_OK == pSample->IsSyncPoint() || m_mt.majortype == MEDIATYPE_Audio && !m_mt.bTemporalCompression) { + pPacket->flags |= MuxerPacket::syncpoint; + } + + if (S_OK == pSample->GetTime(&pPacket->rtStart, &pPacket->rtStop)) { + pPacket->flags |= MuxerPacket::timevalid; + + pPacket->rtStart += m_tStart; + pPacket->rtStop += m_tStart; + + if ((pPacket->flags & MuxerPacket::syncpoint) && pPacket->rtStart < m_rtMaxStart) { + pPacket->flags &= ~MuxerPacket::syncpoint; + pPacket->flags |= MuxerPacket::bogus; + } + + m_rtMaxStart = std::max(m_rtMaxStart, pPacket->rtStart); + } else if (pPacket->flags & MuxerPacket::syncpoint) { + pPacket->flags &= ~MuxerPacket::syncpoint; + pPacket->flags |= MuxerPacket::bogus; + } + + if (S_OK == pSample->IsDiscontinuity()) { + pPacket->flags |= MuxerPacket::discontinuity; + } + + pPacket->index = m_iPacketIndex++; + + PushPacket(pPacket); + + return S_OK; +} + +STDMETHODIMP CBaseMuxerInputPin::EndOfStream() +{ + CAutoLock cAutoLock(&m_csReceive); + + HRESULT hr = __super::EndOfStream(); + if (FAILED(hr)) { + return hr; + } + + ASSERT(!m_fEOS); + + CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); + pPacket->flags |= MuxerPacket::eos; + PushPacket(pPacket); + + m_fEOS = true; + + return hr; +} diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.h b/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.h index eebaa293063..6b0023cb01c 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.h +++ b/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.h @@ -1,97 +1,97 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "BaseMuxerRelatedPin.h" -#include "../../../DSUtil/DSMPropertyBag.h" - -class CBaseMuxerInputPin; - -struct MuxerPacket { - CBaseMuxerInputPin* pPin; - REFERENCE_TIME rtStart, rtStop; - CAtlArray pData; - enum flag_t { - empty = 0, - timevalid = 1, - syncpoint = 2, - discontinuity = 4, - eos = 8, - bogus = 16 - }; - DWORD flags; - int index; - struct MuxerPacket(CBaseMuxerInputPin* pPin) { - this->pPin = pPin; - rtStart = rtStop = _I64_MIN; - flags = empty; - index = -1; - } - - bool IsTimeValid() const { return !!(flags & timevalid); } - bool IsSyncPoint() const { return !!(flags & syncpoint); } - bool IsDiscontinuity() const { return !!(flags & discontinuity); } - bool IsEOS() const { return !!(flags & eos); } - bool IsBogus() const { return !!(flags & bogus); } -}; - -class CBaseMuxerInputPin : public CBaseInputPin, public CBaseMuxerRelatedPin, public IDSMPropertyBagImpl -{ -private: - int m_iID; - - CCritSec m_csReceive; - REFERENCE_TIME m_rtMaxStart, m_rtDuration; - bool m_fEOS; - int m_iPacketIndex; - - CCritSec m_csQueue; - CAutoPtrList m_queue; - void PushPacket(CAutoPtr pPacket); - CAutoPtr PopPacket(); - CAMEvent m_evAcceptPacket; - - friend class CBaseMuxerFilter; - -public: - CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CBaseMuxerInputPin(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - REFERENCE_TIME GetDuration() { return m_rtDuration; } - int GetID() { return m_iID; } - CMediaType& CurrentMediaType() { return m_mt; } - bool IsSubtitleStream(); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pReceivePin); - - HRESULT Active(); - HRESULT Inactive(); - - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP EndOfStream(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "BaseMuxerRelatedPin.h" +#include "../../../DSUtil/DSMPropertyBag.h" + +class CBaseMuxerInputPin; + +struct MuxerPacket { + CBaseMuxerInputPin* pPin; + REFERENCE_TIME rtStart, rtStop; + CAtlArray pData; + enum flag_t { + empty = 0, + timevalid = 1, + syncpoint = 2, + discontinuity = 4, + eos = 8, + bogus = 16 + }; + DWORD flags; + int index; + struct MuxerPacket(CBaseMuxerInputPin* pPin) { + this->pPin = pPin; + rtStart = rtStop = _I64_MIN; + flags = empty; + index = -1; + } + + bool IsTimeValid() const { return !!(flags & timevalid); } + bool IsSyncPoint() const { return !!(flags & syncpoint); } + bool IsDiscontinuity() const { return !!(flags & discontinuity); } + bool IsEOS() const { return !!(flags & eos); } + bool IsBogus() const { return !!(flags & bogus); } +}; + +class CBaseMuxerInputPin : public CBaseInputPin, public CBaseMuxerRelatedPin, public IDSMPropertyBagImpl +{ +private: + int m_iID; + + CCritSec m_csReceive; + REFERENCE_TIME m_rtMaxStart, m_rtDuration; + bool m_fEOS; + int m_iPacketIndex; + + CCritSec m_csQueue; + CAutoPtrList m_queue; + void PushPacket(CAutoPtr pPacket); + CAutoPtr PopPacket(); + CAMEvent m_evAcceptPacket; + + friend class CBaseMuxerFilter; + +public: + CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CBaseMuxerInputPin(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + REFERENCE_TIME GetDuration() { return m_rtDuration; } + int GetID() { return m_iID; } + CMediaType& CurrentMediaType() { return m_mt; } + bool IsSubtitleStream(); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pReceivePin); + + HRESULT Active(); + HRESULT Inactive(); + + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP EndOfStream(); +}; diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.cpp b/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.cpp index 764ba3b6c4b..fa570482ed8 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.cpp +++ b/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.cpp @@ -1,487 +1,487 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "BaseMuxerOutputPin.h" - -#include -#include -#include - -#include "moreuuids.h" -#include "../DSUtil/ISOLang.h" - -// -// CBaseMuxerOutputPin -// - -CBaseMuxerOutputPin::CBaseMuxerOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseOutputPin(_T("CBaseMuxerOutputPin"), pFilter, pLock, phr, pName) -{ -} - -IBitStream* CBaseMuxerOutputPin::GetBitStream() -{ - if (!m_pBitStream) { - if (CComQIPtr pStream = GetConnected()) { - m_pBitStream = DEBUG_NEW CBitStream(pStream, true); - } - } - - return m_pBitStream; -} - -HRESULT CBaseMuxerOutputPin::BreakConnect() -{ - m_pBitStream = nullptr; - - return __super::BreakConnect(); -} - -HRESULT CBaseMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = 1; - pProperties->cbBuffer = 1; - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CBaseMuxerOutputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_NULL - ? S_OK - : E_INVALIDARG; -} - -HRESULT CBaseMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CAutoLock cAutoLock(m_pLock); - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - pmt->ResetFormatBuffer(); - pmt->InitMediaType(); - pmt->majortype = MEDIATYPE_Stream; - pmt->subtype = MEDIASUBTYPE_NULL; - pmt->formattype = FORMAT_None; - - return S_OK; -} - -HRESULT CBaseMuxerOutputPin::DeliverEndOfStream() -{ - m_pBitStream = nullptr; - - return __super::DeliverEndOfStream(); -} - -STDMETHODIMP CBaseMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} - -// -// CBaseMuxerRawOutputPin -// - -CBaseMuxerRawOutputPin::CBaseMuxerRawOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseMuxerOutputPin(pName, pFilter, pLock, phr) -{ -} - -STDMETHODIMP CBaseMuxerRawOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IBaseMuxerRelatedPin) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CBaseMuxerRawOutputPin::MuxHeader(const CMediaType& mt) -{ - CComQIPtr pBitStream = GetBitStream(); - if (!pBitStream) { - return; - } - - const BYTE utf8bom[3] = {0xef, 0xbb, 0xbf}; - - if ((mt.subtype == FOURCCMap('1CVA') || mt.subtype == FOURCCMap('1cva')) && mt.formattype == FORMAT_MPEG2_VIDEO) { - MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.Format(); - - for (DWORD i = 0; i < vih->cbSequenceHeader - 2; i += 2) { - pBitStream->BitWrite(0x00000001, 32); - WORD size = (((BYTE*)vih->dwSequenceHeader)[i + 0] << 8) | ((BYTE*)vih->dwSequenceHeader)[i + 1]; - pBitStream->ByteWrite(&((BYTE*)vih->dwSequenceHeader)[i + 2], size); - i += size; - } - } else if (mt.subtype == MEDIASUBTYPE_UTF8) { - pBitStream->ByteWrite(utf8bom, sizeof(utf8bom)); - } else if (mt.subtype == MEDIASUBTYPE_SSA || mt.subtype == MEDIASUBTYPE_ASS || mt.subtype == MEDIASUBTYPE_ASS2) { - SUBTITLEINFO* si = (SUBTITLEINFO*)mt.Format(); - BYTE* p = (BYTE*)si + si->dwOffset; - - if (memcmp(utf8bom, p, 3) != 0) { - pBitStream->ByteWrite(utf8bom, sizeof(utf8bom)); - } - - CStringA str((char*)p, mt.FormatLength() - (ULONG)(p - mt.Format())); - pBitStream->StrWrite(str + '\n', true); - - if (str.Find("[Events]") < 0) { - pBitStream->StrWrite("\n\n[Events]\n", true); - } - } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { - m_idx.RemoveAll(); - } else if (mt.majortype == MEDIATYPE_Audio - && (mt.subtype == MEDIASUBTYPE_PCM - || mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO - || mt.subtype == FOURCCMap(WAVE_FORMAT_EXTENSIBLE) - || mt.subtype == FOURCCMap(WAVE_FORMAT_IEEE_FLOAT)) - && mt.formattype == FORMAT_WaveFormatEx) { - pBitStream->BitWrite('RIFF', 32); - pBitStream->BitWrite(0, 32); // file length - 8, set later - pBitStream->BitWrite('WAVE', 32); - - pBitStream->BitWrite('fmt ', 32); - pBitStream->ByteWrite(&mt.cbFormat, 4); - pBitStream->ByteWrite(mt.pbFormat, mt.cbFormat); - - pBitStream->BitWrite('data', 32); - pBitStream->BitWrite(0, 32); // data length, set later - } -} - -void CBaseMuxerRawOutputPin::MuxPacket(const CMediaType& mt, const MuxerPacket* pPacket) -{ - CComQIPtr pBitStream = GetBitStream(); - if (!pBitStream) { - return; - } - - const BYTE* pData = pPacket->pData.GetData(); - const int DataSize = int(pPacket->pData.GetCount()); - - if (mt.subtype == MEDIASUBTYPE_AAC && mt.formattype == FORMAT_WaveFormatEx) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); - - int profile = 0; - - int srate_idx = 11; - if (92017 <= wfe->nSamplesPerSec) { - srate_idx = 0; - } else if (75132 <= wfe->nSamplesPerSec) { - srate_idx = 1; - } else if (55426 <= wfe->nSamplesPerSec) { - srate_idx = 2; - } else if (46009 <= wfe->nSamplesPerSec) { - srate_idx = 3; - } else if (37566 <= wfe->nSamplesPerSec) { - srate_idx = 4; - } else if (27713 <= wfe->nSamplesPerSec) { - srate_idx = 5; - } else if (23004 <= wfe->nSamplesPerSec) { - srate_idx = 6; - } else if (18783 <= wfe->nSamplesPerSec) { - srate_idx = 7; - } else if (13856 <= wfe->nSamplesPerSec) { - srate_idx = 8; - } else if (11502 <= wfe->nSamplesPerSec) { - srate_idx = 9; - } else if (9391 <= wfe->nSamplesPerSec) { - srate_idx = 10; - } - - int channels = wfe->nChannels; - - if (wfe->cbSize >= 2) { - BYTE* p = (BYTE*)(wfe + 1); - profile = (p[0] >> 3) - 1; - srate_idx = ((p[0] & 7) << 1) | ((p[1] & 0x80) >> 7); - channels = (p[1] >> 3) & 15; - } - - int len = (DataSize + 7) & 0x1fff; - - BYTE hdr[7] = {0xff, 0xf9}; - hdr[2] = BYTE((profile << 6) | (srate_idx << 2) | ((channels & 4) >> 2)); - hdr[3] = BYTE(((channels & 3) << 6) | (len >> 11)); - hdr[4] = (len >> 3) & 0xff; - hdr[5] = ((len & 7) << 5) | 0x1f; - hdr[6] = 0xfc; - - pBitStream->ByteWrite(hdr, sizeof(hdr)); - } else if ((mt.subtype == FOURCCMap('1CVA') || mt.subtype == FOURCCMap('1cva')) && mt.formattype == FORMAT_MPEG2_VIDEO) { - const BYTE* p = pData; - int i = DataSize; - - while (i >= 4) { - DWORD len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - - i -= len + 4; - p += len + 4; - } - - if (i == 0) { - p = pData; - i = DataSize; - - while (i >= 4) { - DWORD len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - - pBitStream->BitWrite(0x00000001, 32); - - p += 4; - i -= 4; - - if (len > (DWORD)i || len == 1) { - len = i; - ASSERT(0); - } - - pBitStream->ByteWrite(p, len); - - p += len; - i -= len; - } - - return; - } - } else if (mt.subtype == MEDIASUBTYPE_UTF8 || mt.majortype == MEDIATYPE_Text) { - CStringA str((char*)pData, DataSize); - str.Trim(); - if (str.IsEmpty()) { - return; - } - - DVD_HMSF_TIMECODE start = RT2HMSF(pPacket->rtStart, 25); - DVD_HMSF_TIMECODE stop = RT2HMSF(pPacket->rtStop, 25); - - str.Format("%d\n%02u:%02u:%02u,%03d --> %02u:%02u:%02u,%03d\n%s\n\n", - pPacket->index + 1, - start.bHours, start.bMinutes, start.bSeconds, (int)((pPacket->rtStart / 10000) % 1000), - stop.bHours, stop.bMinutes, stop.bSeconds, (int)((pPacket->rtStop / 10000) % 1000), - CStringA(str).GetString()); - - pBitStream->StrWrite(str, true); - - return; - } else if (mt.subtype == MEDIASUBTYPE_SSA || mt.subtype == MEDIASUBTYPE_ASS || mt.subtype == MEDIASUBTYPE_ASS2) { - CStringA str((char*)pData, DataSize); - str.Trim(); - if (str.IsEmpty()) { - return; - } - - DVD_HMSF_TIMECODE start = RT2HMSF(pPacket->rtStart, 25); - DVD_HMSF_TIMECODE stop = RT2HMSF(pPacket->rtStop, 25); - - size_t fields = mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9; - - CAtlList sl; - Explode(str, sl, ',', fields); - if (sl.GetCount() < fields) { - return; - } - - CStringA readorder = sl.RemoveHead(); // TODO - CStringA layer = sl.RemoveHead(); - CStringA style = sl.RemoveHead(); - CStringA actor = sl.RemoveHead(); - CStringA left = sl.RemoveHead(); - CStringA right = sl.RemoveHead(); - CStringA top = sl.RemoveHead(); - if (fields == 10) { - top += ',' + sl.RemoveHead(); // bottom - } - CStringA effect = sl.RemoveHead(); - str = sl.RemoveHead(); - - if (mt.subtype == MEDIASUBTYPE_SSA) { - layer = "Marked=0"; - } - - str.Format("Dialogue: %s,%u:%02u:%02u.%02d,%u:%02u:%02u.%02d,%s,%s,%s,%s,%s,%s,%s\n", - layer.GetString(), - start.bHours, start.bMinutes, start.bSeconds, (int)((pPacket->rtStart / 100000) % 100), - stop.bHours, stop.bMinutes, stop.bSeconds, (int)((pPacket->rtStop / 100000) % 100), - style.GetString(), actor.GetString(), left.GetString(), right.GetString(), top.GetString(), effect.GetString(), - CStringA(str).GetString()); - - pBitStream->StrWrite(str, true); - - return; - } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { - bool fTimeValid = pPacket->IsTimeValid(); - - if (fTimeValid) { - idx_t i; - i.rt = pPacket->rtStart; - i.fp = pBitStream->GetPos(); - m_idx.AddTail(i); - } - - int DataSizeLeft = DataSize; - - while (DataSizeLeft > 0) { - int BytesAvail = 0x7ec - (fTimeValid ? 9 : 4); - int Size = std::min(BytesAvail, DataSizeLeft); - int Padding = 0x800 - Size - 20 - (fTimeValid ? 9 : 4); - - pBitStream->BitWrite(0x000001ba, 32); - pBitStream->BitWrite(0x440004000401ui64, 48); - pBitStream->BitWrite(0x000003f8, 32); - pBitStream->BitWrite(0x000001bd, 32); - - if (fTimeValid) { - pBitStream->BitWrite(Size + 9, 16); - pBitStream->BitWrite(0x8180052100010001ui64, 64); - } else { - pBitStream->BitWrite(Size + 4, 16); - pBitStream->BitWrite(0x810000, 24); - } - - pBitStream->BitWrite(0x20, 8); - - pBitStream->ByteWrite(pData, Size); - - pData += Size; - DataSizeLeft -= Size; - - if (Padding > 0) { - Padding -= 6; - ASSERT(Padding >= 0); - pBitStream->BitWrite(0x000001be, 32); - pBitStream->BitWrite(Padding, 16); - while (Padding-- > 0) { - pBitStream->BitWrite(0xff, 8); - } - } - - fTimeValid = false; - } - - return; - } else if (mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); - - // This code is probably totally broken for anything but 16 bits - for (int i = 0, bps = wfe->wBitsPerSample / 8; i < DataSize; i += bps) - for (int j = bps - 1; j >= 0; j--) { - pBitStream->BitWrite(pData[i + j], 8); - } - - return; - } - // else // TODO: restore more streams (vorbis to ogg) - - pBitStream->ByteWrite(pData, DataSize); -} - -void CBaseMuxerRawOutputPin::MuxFooter(const CMediaType& mt) -{ - CComQIPtr pBitStream = GetBitStream(); - if (!pBitStream) { - return; - } - - if (mt.majortype == MEDIATYPE_Audio - && (mt.subtype == MEDIASUBTYPE_PCM - || mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO - || mt.subtype == FOURCCMap(WAVE_FORMAT_EXTENSIBLE) - || mt.subtype == FOURCCMap(WAVE_FORMAT_IEEE_FLOAT)) - && mt.formattype == FORMAT_WaveFormatEx) { - pBitStream->BitFlush(); - - ASSERT(pBitStream->GetPos() <= 0xffffffff); - UINT32 size = (UINT32)pBitStream->GetPos(); - - size -= 8; - pBitStream->Seek(4); - pBitStream->ByteWrite(&size, 4); - - size -= sizeof(RIFFLIST) + sizeof(RIFFCHUNK) + mt.FormatLength(); - pBitStream->Seek(sizeof(RIFFLIST) + sizeof(RIFFCHUNK) + mt.FormatLength() + 4); - pBitStream->ByteWrite(&size, 4); - } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { - if (CComQIPtr pFSF = GetFilterFromPin(GetConnected())) { - WCHAR* fn = nullptr; - if (SUCCEEDED(pFSF->GetCurFile(&fn, nullptr))) { - CPathW p(fn); - p.RenameExtension(L".idx"); - CoTaskMemFree(fn); - - FILE* f; - if (!_tfopen_s(&f, CString((LPCWSTR)p), _T("w"))) { - SUBTITLEINFO* si = (SUBTITLEINFO*)mt.Format(); - - _ftprintf_s(f, _T("%s\n"), _T("# VobSub index file, v7 (do not modify this line!)")); - - fwrite(mt.Format() + si->dwOffset, mt.FormatLength() - si->dwOffset, 1, f); - - CString iso6391 = ISOLang::ISO6392To6391(si->IsoLang); - if (iso6391.IsEmpty()) { - iso6391 = _T("--"); - } - _ftprintf_s(f, _T("\nlangidx: 0\n\nid: %s, index: 0\n"), iso6391.GetString()); - - CString alt = CString(CStringW(si->TrackName)); - if (!alt.IsEmpty()) { - _ftprintf_s(f, _T("alt: %s\n"), alt.GetString()); - } - - POSITION pos = m_idx.GetHeadPosition(); - while (pos) { - const idx_t& i = m_idx.GetNext(pos); - DVD_HMSF_TIMECODE start = RT2HMSF(i.rt, 25); - _ftprintf_s(f, _T("timestamp: %02u:%02u:%02u:%03d, filepos: %09I64x\n"), - start.bHours, start.bMinutes, start.bSeconds, (int)((i.rt / 10000) % 1000), - i.fp); - } - - fclose(f); - } - } - } - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "BaseMuxerOutputPin.h" + +#include +#include +#include + +#include "moreuuids.h" +#include "../DSUtil/ISOLang.h" + +// +// CBaseMuxerOutputPin +// + +CBaseMuxerOutputPin::CBaseMuxerOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseOutputPin(_T("CBaseMuxerOutputPin"), pFilter, pLock, phr, pName) +{ +} + +IBitStream* CBaseMuxerOutputPin::GetBitStream() +{ + if (!m_pBitStream) { + if (CComQIPtr pStream = GetConnected()) { + m_pBitStream = DEBUG_NEW CBitStream(pStream, true); + } + } + + return m_pBitStream; +} + +HRESULT CBaseMuxerOutputPin::BreakConnect() +{ + m_pBitStream = nullptr; + + return __super::BreakConnect(); +} + +HRESULT CBaseMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = 1; + pProperties->cbBuffer = 1; + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CBaseMuxerOutputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_NULL + ? S_OK + : E_INVALIDARG; +} + +HRESULT CBaseMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CAutoLock cAutoLock(m_pLock); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + pmt->ResetFormatBuffer(); + pmt->InitMediaType(); + pmt->majortype = MEDIATYPE_Stream; + pmt->subtype = MEDIASUBTYPE_NULL; + pmt->formattype = FORMAT_None; + + return S_OK; +} + +HRESULT CBaseMuxerOutputPin::DeliverEndOfStream() +{ + m_pBitStream = nullptr; + + return __super::DeliverEndOfStream(); +} + +STDMETHODIMP CBaseMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} + +// +// CBaseMuxerRawOutputPin +// + +CBaseMuxerRawOutputPin::CBaseMuxerRawOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseMuxerOutputPin(pName, pFilter, pLock, phr) +{ +} + +STDMETHODIMP CBaseMuxerRawOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IBaseMuxerRelatedPin) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CBaseMuxerRawOutputPin::MuxHeader(const CMediaType& mt) +{ + CComQIPtr pBitStream = GetBitStream(); + if (!pBitStream) { + return; + } + + const BYTE utf8bom[3] = {0xef, 0xbb, 0xbf}; + + if ((mt.subtype == FOURCCMap('1CVA') || mt.subtype == FOURCCMap('1cva')) && mt.formattype == FORMAT_MPEG2_VIDEO) { + MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.Format(); + + for (DWORD i = 0; i < vih->cbSequenceHeader - 2; i += 2) { + pBitStream->BitWrite(0x00000001, 32); + WORD size = (((BYTE*)vih->dwSequenceHeader)[i + 0] << 8) | ((BYTE*)vih->dwSequenceHeader)[i + 1]; + pBitStream->ByteWrite(&((BYTE*)vih->dwSequenceHeader)[i + 2], size); + i += size; + } + } else if (mt.subtype == MEDIASUBTYPE_UTF8) { + pBitStream->ByteWrite(utf8bom, sizeof(utf8bom)); + } else if (mt.subtype == MEDIASUBTYPE_SSA || mt.subtype == MEDIASUBTYPE_ASS || mt.subtype == MEDIASUBTYPE_ASS2) { + SUBTITLEINFO* si = (SUBTITLEINFO*)mt.Format(); + BYTE* p = (BYTE*)si + si->dwOffset; + + if (memcmp(utf8bom, p, 3) != 0) { + pBitStream->ByteWrite(utf8bom, sizeof(utf8bom)); + } + + CStringA str((char*)p, mt.FormatLength() - (ULONG)(p - mt.Format())); + pBitStream->StrWrite(str + '\n', true); + + if (str.Find("[Events]") < 0) { + pBitStream->StrWrite("\n\n[Events]\n", true); + } + } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { + m_idx.RemoveAll(); + } else if (mt.majortype == MEDIATYPE_Audio + && (mt.subtype == MEDIASUBTYPE_PCM + || mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO + || mt.subtype == FOURCCMap(WAVE_FORMAT_EXTENSIBLE) + || mt.subtype == FOURCCMap(WAVE_FORMAT_IEEE_FLOAT)) + && mt.formattype == FORMAT_WaveFormatEx) { + pBitStream->BitWrite('RIFF', 32); + pBitStream->BitWrite(0, 32); // file length - 8, set later + pBitStream->BitWrite('WAVE', 32); + + pBitStream->BitWrite('fmt ', 32); + pBitStream->ByteWrite(&mt.cbFormat, 4); + pBitStream->ByteWrite(mt.pbFormat, mt.cbFormat); + + pBitStream->BitWrite('data', 32); + pBitStream->BitWrite(0, 32); // data length, set later + } +} + +void CBaseMuxerRawOutputPin::MuxPacket(const CMediaType& mt, const MuxerPacket* pPacket) +{ + CComQIPtr pBitStream = GetBitStream(); + if (!pBitStream) { + return; + } + + const BYTE* pData = pPacket->pData.GetData(); + const int DataSize = int(pPacket->pData.GetCount()); + + if (mt.subtype == MEDIASUBTYPE_AAC && mt.formattype == FORMAT_WaveFormatEx) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); + + int profile = 0; + + int srate_idx = 11; + if (92017 <= wfe->nSamplesPerSec) { + srate_idx = 0; + } else if (75132 <= wfe->nSamplesPerSec) { + srate_idx = 1; + } else if (55426 <= wfe->nSamplesPerSec) { + srate_idx = 2; + } else if (46009 <= wfe->nSamplesPerSec) { + srate_idx = 3; + } else if (37566 <= wfe->nSamplesPerSec) { + srate_idx = 4; + } else if (27713 <= wfe->nSamplesPerSec) { + srate_idx = 5; + } else if (23004 <= wfe->nSamplesPerSec) { + srate_idx = 6; + } else if (18783 <= wfe->nSamplesPerSec) { + srate_idx = 7; + } else if (13856 <= wfe->nSamplesPerSec) { + srate_idx = 8; + } else if (11502 <= wfe->nSamplesPerSec) { + srate_idx = 9; + } else if (9391 <= wfe->nSamplesPerSec) { + srate_idx = 10; + } + + int channels = wfe->nChannels; + + if (wfe->cbSize >= 2) { + BYTE* p = (BYTE*)(wfe + 1); + profile = (p[0] >> 3) - 1; + srate_idx = ((p[0] & 7) << 1) | ((p[1] & 0x80) >> 7); + channels = (p[1] >> 3) & 15; + } + + int len = (DataSize + 7) & 0x1fff; + + BYTE hdr[7] = {0xff, 0xf9}; + hdr[2] = BYTE((profile << 6) | (srate_idx << 2) | ((channels & 4) >> 2)); + hdr[3] = BYTE(((channels & 3) << 6) | (len >> 11)); + hdr[4] = (len >> 3) & 0xff; + hdr[5] = ((len & 7) << 5) | 0x1f; + hdr[6] = 0xfc; + + pBitStream->ByteWrite(hdr, sizeof(hdr)); + } else if ((mt.subtype == FOURCCMap('1CVA') || mt.subtype == FOURCCMap('1cva')) && mt.formattype == FORMAT_MPEG2_VIDEO) { + const BYTE* p = pData; + int i = DataSize; + + while (i >= 4) { + DWORD len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + + i -= len + 4; + p += len + 4; + } + + if (i == 0) { + p = pData; + i = DataSize; + + while (i >= 4) { + DWORD len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + + pBitStream->BitWrite(0x00000001, 32); + + p += 4; + i -= 4; + + if (len > (DWORD)i || len == 1) { + len = i; + ASSERT(0); + } + + pBitStream->ByteWrite(p, len); + + p += len; + i -= len; + } + + return; + } + } else if (mt.subtype == MEDIASUBTYPE_UTF8 || mt.majortype == MEDIATYPE_Text) { + CStringA str((char*)pData, DataSize); + str.Trim(); + if (str.IsEmpty()) { + return; + } + + DVD_HMSF_TIMECODE start = RT2HMSF(pPacket->rtStart, 25); + DVD_HMSF_TIMECODE stop = RT2HMSF(pPacket->rtStop, 25); + + str.Format("%d\n%02u:%02u:%02u,%03d --> %02u:%02u:%02u,%03d\n%s\n\n", + pPacket->index + 1, + start.bHours, start.bMinutes, start.bSeconds, (int)((pPacket->rtStart / 10000) % 1000), + stop.bHours, stop.bMinutes, stop.bSeconds, (int)((pPacket->rtStop / 10000) % 1000), + CStringA(str).GetString()); + + pBitStream->StrWrite(str, true); + + return; + } else if (mt.subtype == MEDIASUBTYPE_SSA || mt.subtype == MEDIASUBTYPE_ASS || mt.subtype == MEDIASUBTYPE_ASS2) { + CStringA str((char*)pData, DataSize); + str.Trim(); + if (str.IsEmpty()) { + return; + } + + DVD_HMSF_TIMECODE start = RT2HMSF(pPacket->rtStart, 25); + DVD_HMSF_TIMECODE stop = RT2HMSF(pPacket->rtStop, 25); + + size_t fields = mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9; + + CAtlList sl; + Explode(str, sl, ',', fields); + if (sl.GetCount() < fields) { + return; + } + + CStringA readorder = sl.RemoveHead(); // TODO + CStringA layer = sl.RemoveHead(); + CStringA style = sl.RemoveHead(); + CStringA actor = sl.RemoveHead(); + CStringA left = sl.RemoveHead(); + CStringA right = sl.RemoveHead(); + CStringA top = sl.RemoveHead(); + if (fields == 10) { + top += ',' + sl.RemoveHead(); // bottom + } + CStringA effect = sl.RemoveHead(); + str = sl.RemoveHead(); + + if (mt.subtype == MEDIASUBTYPE_SSA) { + layer = "Marked=0"; + } + + str.Format("Dialogue: %s,%u:%02u:%02u.%02d,%u:%02u:%02u.%02d,%s,%s,%s,%s,%s,%s,%s\n", + layer.GetString(), + start.bHours, start.bMinutes, start.bSeconds, (int)((pPacket->rtStart / 100000) % 100), + stop.bHours, stop.bMinutes, stop.bSeconds, (int)((pPacket->rtStop / 100000) % 100), + style.GetString(), actor.GetString(), left.GetString(), right.GetString(), top.GetString(), effect.GetString(), + CStringA(str).GetString()); + + pBitStream->StrWrite(str, true); + + return; + } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { + bool fTimeValid = pPacket->IsTimeValid(); + + if (fTimeValid) { + idx_t i; + i.rt = pPacket->rtStart; + i.fp = pBitStream->GetPos(); + m_idx.AddTail(i); + } + + int DataSizeLeft = DataSize; + + while (DataSizeLeft > 0) { + int BytesAvail = 0x7ec - (fTimeValid ? 9 : 4); + int Size = std::min(BytesAvail, DataSizeLeft); + int Padding = 0x800 - Size - 20 - (fTimeValid ? 9 : 4); + + pBitStream->BitWrite(0x000001ba, 32); + pBitStream->BitWrite(0x440004000401ui64, 48); + pBitStream->BitWrite(0x000003f8, 32); + pBitStream->BitWrite(0x000001bd, 32); + + if (fTimeValid) { + pBitStream->BitWrite(Size + 9, 16); + pBitStream->BitWrite(0x8180052100010001ui64, 64); + } else { + pBitStream->BitWrite(Size + 4, 16); + pBitStream->BitWrite(0x810000, 24); + } + + pBitStream->BitWrite(0x20, 8); + + pBitStream->ByteWrite(pData, Size); + + pData += Size; + DataSizeLeft -= Size; + + if (Padding > 0) { + Padding -= 6; + ASSERT(Padding >= 0); + pBitStream->BitWrite(0x000001be, 32); + pBitStream->BitWrite(Padding, 16); + while (Padding-- > 0) { + pBitStream->BitWrite(0xff, 8); + } + } + + fTimeValid = false; + } + + return; + } else if (mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); + + // This code is probably totally broken for anything but 16 bits + for (int i = 0, bps = wfe->wBitsPerSample / 8; i < DataSize; i += bps) + for (int j = bps - 1; j >= 0; j--) { + pBitStream->BitWrite(pData[i + j], 8); + } + + return; + } + // else // TODO: restore more streams (vorbis to ogg) + + pBitStream->ByteWrite(pData, DataSize); +} + +void CBaseMuxerRawOutputPin::MuxFooter(const CMediaType& mt) +{ + CComQIPtr pBitStream = GetBitStream(); + if (!pBitStream) { + return; + } + + if (mt.majortype == MEDIATYPE_Audio + && (mt.subtype == MEDIASUBTYPE_PCM + || mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO + || mt.subtype == FOURCCMap(WAVE_FORMAT_EXTENSIBLE) + || mt.subtype == FOURCCMap(WAVE_FORMAT_IEEE_FLOAT)) + && mt.formattype == FORMAT_WaveFormatEx) { + pBitStream->BitFlush(); + + ASSERT(pBitStream->GetPos() <= 0xffffffff); + UINT32 size = (UINT32)pBitStream->GetPos(); + + size -= 8; + pBitStream->Seek(4); + pBitStream->ByteWrite(&size, 4); + + size -= sizeof(RIFFLIST) + sizeof(RIFFCHUNK) + mt.FormatLength(); + pBitStream->Seek(sizeof(RIFFLIST) + sizeof(RIFFCHUNK) + mt.FormatLength() + 4); + pBitStream->ByteWrite(&size, 4); + } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { + if (CComQIPtr pFSF = GetFilterFromPin(GetConnected())) { + WCHAR* fn = nullptr; + if (SUCCEEDED(pFSF->GetCurFile(&fn, nullptr))) { + CPathW p(fn); + p.RenameExtension(L".idx"); + CoTaskMemFree(fn); + + FILE* f; + if (!_tfopen_s(&f, CString((LPCWSTR)p), _T("w"))) { + SUBTITLEINFO* si = (SUBTITLEINFO*)mt.Format(); + + _ftprintf_s(f, _T("%s\n"), _T("# VobSub index file, v7 (do not modify this line!)")); + + fwrite(mt.Format() + si->dwOffset, mt.FormatLength() - si->dwOffset, 1, f); + + CString iso6391 = ISOLang::ISO6392To6391(si->IsoLang); + if (iso6391.IsEmpty()) { + iso6391 = _T("--"); + } + _ftprintf_s(f, _T("\nlangidx: 0\n\nid: %s, index: 0\n"), iso6391.GetString()); + + CString alt = CString(CStringW(si->TrackName)); + if (!alt.IsEmpty()) { + _ftprintf_s(f, _T("alt: %s\n"), alt.GetString()); + } + + POSITION pos = m_idx.GetHeadPosition(); + while (pos) { + const idx_t& i = m_idx.GetNext(pos); + DVD_HMSF_TIMECODE start = RT2HMSF(i.rt, 25); + _ftprintf_s(f, _T("timestamp: %02u:%02u:%02u:%03d, filepos: %09I64x\n"), + start.bHours, start.bMinutes, start.bSeconds, (int)((i.rt / 10000) % 1000), + i.fp); + } + + fclose(f); + } + } + } + } +} diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.h b/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.h index eb9dd9d762f..4fb99dbda40 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.h +++ b/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.h @@ -1,68 +1,68 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "BitStream.h" -#include "BaseMuxerInputPin.h" -#include "BaseMuxerRelatedPin.h" - -class CBaseMuxerOutputPin : public CBaseOutputPin -{ - CComPtr m_pBitStream; - -public: - CBaseMuxerOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CBaseMuxerOutputPin() {} - - IBitStream* GetBitStream(); - - HRESULT BreakConnect(); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - - HRESULT DeliverEndOfStream(); - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; - -class CBaseMuxerRawOutputPin : public CBaseMuxerOutputPin, public CBaseMuxerRelatedPin -{ - struct idx_t { - REFERENCE_TIME rt; - __int64 fp; - }; - CAtlList m_idx; - -public: - CBaseMuxerRawOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CBaseMuxerRawOutputPin() {} - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - virtual void MuxHeader(const CMediaType& mt); - virtual void MuxPacket(const CMediaType& mt, const MuxerPacket* pPacket); - virtual void MuxFooter(const CMediaType& mt); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "BitStream.h" +#include "BaseMuxerInputPin.h" +#include "BaseMuxerRelatedPin.h" + +class CBaseMuxerOutputPin : public CBaseOutputPin +{ + CComPtr m_pBitStream; + +public: + CBaseMuxerOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CBaseMuxerOutputPin() {} + + IBitStream* GetBitStream(); + + HRESULT BreakConnect(); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + + HRESULT DeliverEndOfStream(); + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; + +class CBaseMuxerRawOutputPin : public CBaseMuxerOutputPin, public CBaseMuxerRelatedPin +{ + struct idx_t { + REFERENCE_TIME rt; + __int64 fp; + }; + CAtlList m_idx; + +public: + CBaseMuxerRawOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CBaseMuxerRawOutputPin() {} + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + virtual void MuxHeader(const CMediaType& mt); + virtual void MuxPacket(const CMediaType& mt, const MuxerPacket* pPacket); + virtual void MuxFooter(const CMediaType& mt); +}; diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.cpp b/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.cpp index 2505c3dba9d..7f6d6f33439 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.cpp +++ b/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.cpp @@ -1,49 +1,49 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "BaseMuxerRelatedPin.h" - -// -// CBaseMuxerRelatedPin -// - -CBaseMuxerRelatedPin::CBaseMuxerRelatedPin() - : m_pRelatedPin(nullptr) -{ -} - -CBaseMuxerRelatedPin::~CBaseMuxerRelatedPin() -{ -} - -// IBaseMuxerRelatedPin - -STDMETHODIMP CBaseMuxerRelatedPin::SetRelatedPin(CBasePin* pPin) -{ - m_pRelatedPin = pPin; - return S_OK; -} - -STDMETHODIMP_(CBasePin*) CBaseMuxerRelatedPin::GetRelatedPin() -{ - return m_pRelatedPin; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "BaseMuxerRelatedPin.h" + +// +// CBaseMuxerRelatedPin +// + +CBaseMuxerRelatedPin::CBaseMuxerRelatedPin() + : m_pRelatedPin(nullptr) +{ +} + +CBaseMuxerRelatedPin::~CBaseMuxerRelatedPin() +{ +} + +// IBaseMuxerRelatedPin + +STDMETHODIMP CBaseMuxerRelatedPin::SetRelatedPin(CBasePin* pPin) +{ + m_pRelatedPin = pPin; + return S_OK; +} + +STDMETHODIMP_(CBasePin*) CBaseMuxerRelatedPin::GetRelatedPin() +{ + return m_pRelatedPin; +} diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.h b/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.h index 4a2b8d0f1dd..c886917484c 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.h +++ b/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.h @@ -1,44 +1,44 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("EE6F2741-7DB4-4AAD-A3CB-545208EE4C0A")) - IBaseMuxerRelatedPin : - public IUnknown -{ - STDMETHOD(SetRelatedPin)(CBasePin* pPin) PURE; - STDMETHOD_(CBasePin*, GetRelatedPin)() PURE; -}; - -class CBaseMuxerRelatedPin : public IBaseMuxerRelatedPin -{ - CBasePin* m_pRelatedPin; // should not hold a reference because it would be circular - -public: - CBaseMuxerRelatedPin(); - virtual ~CBaseMuxerRelatedPin(); - - // IBaseMuxerRelatedPin - - STDMETHODIMP SetRelatedPin(CBasePin* pPin); - STDMETHODIMP_(CBasePin*) GetRelatedPin(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("EE6F2741-7DB4-4AAD-A3CB-545208EE4C0A")) + IBaseMuxerRelatedPin : + public IUnknown +{ + STDMETHOD(SetRelatedPin)(CBasePin* pPin) PURE; + STDMETHOD_(CBasePin*, GetRelatedPin)() PURE; +}; + +class CBaseMuxerRelatedPin : public IBaseMuxerRelatedPin +{ + CBasePin* m_pRelatedPin; // should not hold a reference because it would be circular + +public: + CBaseMuxerRelatedPin(); + virtual ~CBaseMuxerRelatedPin(); + + // IBaseMuxerRelatedPin + + STDMETHODIMP SetRelatedPin(CBasePin* pPin); + STDMETHODIMP_(CBasePin*) GetRelatedPin(); +}; diff --git a/src/filters/muxer/BaseMuxer/BitStream.cpp b/src/filters/muxer/BaseMuxer/BitStream.cpp index c58c45d881f..3327092a133 100644 --- a/src/filters/muxer/BaseMuxer/BitStream.cpp +++ b/src/filters/muxer/BaseMuxer/BitStream.cpp @@ -1,162 +1,162 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "BitStream.h" - -// -// CBitStream -// - -CBitStream::CBitStream(IStream* pStream, bool fThrowError) - : CUnknown(_T("CBitStream"), nullptr) - , m_pStream(pStream) - , m_fThrowError(fThrowError) - , m_bitbuff(0) - , m_bitlen(0) -{ - ASSERT(m_pStream); - - LARGE_INTEGER li = {0}; - m_pStream->Seek(li, STREAM_SEEK_SET, nullptr); - - ULARGE_INTEGER uli = {0}; - m_pStream->SetSize(uli); // not that it worked... - - m_pStream->Commit(S_OK); // also seems to have no effect, but maybe in the future... -} - -CBitStream::~CBitStream() -{ - BitFlush(); -} - -STDMETHODIMP CBitStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - return - QI(IBitStream) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IBitStream - -STDMETHODIMP_(UINT64) CBitStream::GetPos() -{ - ULARGE_INTEGER pos = {0, 0}; - m_pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos); - return pos.QuadPart; -} - -STDMETHODIMP_(UINT64) CBitStream::Seek(UINT64 pos) -{ - BitFlush(); - - LARGE_INTEGER li; - li.QuadPart = pos; - ULARGE_INTEGER linew; - linew.QuadPart = (ULONGLONG) - 1; - m_pStream->Seek(li, STREAM_SEEK_SET, &linew); - ASSERT(li.QuadPart == (LONGLONG)linew.QuadPart); - return linew.QuadPart; -} - -STDMETHODIMP CBitStream::ByteWrite(const void* pData, int len) -{ - HRESULT hr = S_OK; - - BitFlush(); - - if (len > 0) { - ULONG cbWritten = 0; - hr = m_pStream->Write(pData, len, &cbWritten); - - ASSERT(SUCCEEDED(hr)); - if (m_fThrowError && FAILED(hr)) { - throw hr; - } - } - - return hr; -} - -STDMETHODIMP CBitStream::BitWrite(UINT64 data, int len) -{ - HRESULT hr = S_OK; - - ASSERT(len >= 0 && len <= 64); - - if (len > 56) { - BitWrite(data >> 56, len - 56); - len = 56; - } - - m_bitbuff <<= len; - m_bitbuff |= data & ((1ui64 << len) - 1); - m_bitlen += len; - - while (m_bitlen >= 8) { - BYTE b = (BYTE)(m_bitbuff >> (m_bitlen - 8)); - hr = m_pStream->Write(&b, 1, nullptr); - m_bitlen -= 8; - - ASSERT(SUCCEEDED(hr)); - if (m_fThrowError && FAILED(hr)) { - throw E_FAIL; - } - } - - return hr; -} - -STDMETHODIMP CBitStream::BitFlush() -{ - HRESULT hr = S_OK; - - if (m_bitlen > 0) { - ASSERT(m_bitlen < 8); - BYTE b = (BYTE)(m_bitbuff << (8 - m_bitlen)); - hr = m_pStream->Write(&b, 1, nullptr); - m_bitlen = 0; - - ASSERT(SUCCEEDED(hr)); - if (m_fThrowError && FAILED(hr)) { - throw E_FAIL; - } - } - - return hr; -} - -STDMETHODIMP CBitStream::StrWrite(LPCSTR pData, BOOL bFixNewLine) -{ - CStringA str = pData; - - if (bFixNewLine) { - str.Replace("\r", ""); - str.Replace("\n", "\r\n"); - } - - return ByteWrite((LPCSTR)str, str.GetLength()); -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "BitStream.h" + +// +// CBitStream +// + +CBitStream::CBitStream(IStream* pStream, bool fThrowError) + : CUnknown(_T("CBitStream"), nullptr) + , m_pStream(pStream) + , m_fThrowError(fThrowError) + , m_bitbuff(0) + , m_bitlen(0) +{ + ASSERT(m_pStream); + + LARGE_INTEGER li = {0}; + m_pStream->Seek(li, STREAM_SEEK_SET, nullptr); + + ULARGE_INTEGER uli = {0}; + m_pStream->SetSize(uli); // not that it worked... + + m_pStream->Commit(S_OK); // also seems to have no effect, but maybe in the future... +} + +CBitStream::~CBitStream() +{ + BitFlush(); +} + +STDMETHODIMP CBitStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + return + QI(IBitStream) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IBitStream + +STDMETHODIMP_(UINT64) CBitStream::GetPos() +{ + ULARGE_INTEGER pos = {0, 0}; + m_pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos); + return pos.QuadPart; +} + +STDMETHODIMP_(UINT64) CBitStream::Seek(UINT64 pos) +{ + BitFlush(); + + LARGE_INTEGER li; + li.QuadPart = pos; + ULARGE_INTEGER linew; + linew.QuadPart = (ULONGLONG) - 1; + m_pStream->Seek(li, STREAM_SEEK_SET, &linew); + ASSERT(li.QuadPart == (LONGLONG)linew.QuadPart); + return linew.QuadPart; +} + +STDMETHODIMP CBitStream::ByteWrite(const void* pData, int len) +{ + HRESULT hr = S_OK; + + BitFlush(); + + if (len > 0) { + ULONG cbWritten = 0; + hr = m_pStream->Write(pData, len, &cbWritten); + + ASSERT(SUCCEEDED(hr)); + if (m_fThrowError && FAILED(hr)) { + throw hr; + } + } + + return hr; +} + +STDMETHODIMP CBitStream::BitWrite(UINT64 data, int len) +{ + HRESULT hr = S_OK; + + ASSERT(len >= 0 && len <= 64); + + if (len > 56) { + BitWrite(data >> 56, len - 56); + len = 56; + } + + m_bitbuff <<= len; + m_bitbuff |= data & ((1ui64 << len) - 1); + m_bitlen += len; + + while (m_bitlen >= 8) { + BYTE b = (BYTE)(m_bitbuff >> (m_bitlen - 8)); + hr = m_pStream->Write(&b, 1, nullptr); + m_bitlen -= 8; + + ASSERT(SUCCEEDED(hr)); + if (m_fThrowError && FAILED(hr)) { + throw E_FAIL; + } + } + + return hr; +} + +STDMETHODIMP CBitStream::BitFlush() +{ + HRESULT hr = S_OK; + + if (m_bitlen > 0) { + ASSERT(m_bitlen < 8); + BYTE b = (BYTE)(m_bitbuff << (8 - m_bitlen)); + hr = m_pStream->Write(&b, 1, nullptr); + m_bitlen = 0; + + ASSERT(SUCCEEDED(hr)); + if (m_fThrowError && FAILED(hr)) { + throw E_FAIL; + } + } + + return hr; +} + +STDMETHODIMP CBitStream::StrWrite(LPCSTR pData, BOOL bFixNewLine) +{ + CStringA str = pData; + + if (bFixNewLine) { + str.Replace("\r", ""); + str.Replace("\n", "\r\n"); + } + + return ByteWrite((LPCSTR)str, str.GetLength()); +} diff --git a/src/filters/muxer/BaseMuxer/BitStream.h b/src/filters/muxer/BaseMuxer/BitStream.h index a5b6d0340cc..64791d95d60 100644 --- a/src/filters/muxer/BaseMuxer/BitStream.h +++ b/src/filters/muxer/BaseMuxer/BitStream.h @@ -1,58 +1,58 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("30AB78C7-5259-4594-AEFE-9C0FC2F08A5E")) - IBitStream : - public IUnknown -{ - STDMETHOD_(UINT64, GetPos)() PURE; - STDMETHOD_(UINT64, Seek)(UINT64 pos) PURE; // it's a _stream_, please don't seek if you don't have to - STDMETHOD(ByteWrite)(const void* pData, int len) PURE; - STDMETHOD(BitWrite)(UINT64 data, int len) PURE; - STDMETHOD(BitFlush)() PURE; - STDMETHOD(StrWrite)(LPCSTR pData, BOOL bFixNewLine) PURE; -}; - -class CBitStream : public CUnknown, public IBitStream -{ - CComPtr m_pStream; - bool m_fThrowError; - UINT64 m_bitbuff; - int m_bitlen; - -public: - CBitStream(IStream* pStream, bool m_fThrowError = false); - virtual ~CBitStream(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IBitStream - - STDMETHODIMP_(UINT64) GetPos(); - STDMETHODIMP_(UINT64) Seek(UINT64 pos); - STDMETHODIMP ByteWrite(const void* pData, int len); - STDMETHODIMP BitWrite(UINT64 data, int len); - STDMETHODIMP BitFlush(); - STDMETHODIMP StrWrite(LPCSTR pData, BOOL bFixNewLine); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("30AB78C7-5259-4594-AEFE-9C0FC2F08A5E")) + IBitStream : + public IUnknown +{ + STDMETHOD_(UINT64, GetPos)() PURE; + STDMETHOD_(UINT64, Seek)(UINT64 pos) PURE; // it's a _stream_, please don't seek if you don't have to + STDMETHOD(ByteWrite)(const void* pData, int len) PURE; + STDMETHOD(BitWrite)(UINT64 data, int len) PURE; + STDMETHOD(BitFlush)() PURE; + STDMETHOD(StrWrite)(LPCSTR pData, BOOL bFixNewLine) PURE; +}; + +class CBitStream : public CUnknown, public IBitStream +{ + CComPtr m_pStream; + bool m_fThrowError; + UINT64 m_bitbuff; + int m_bitlen; + +public: + CBitStream(IStream* pStream, bool m_fThrowError = false); + virtual ~CBitStream(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IBitStream + + STDMETHODIMP_(UINT64) GetPos(); + STDMETHODIMP_(UINT64) Seek(UINT64 pos); + STDMETHODIMP ByteWrite(const void* pData, int len); + STDMETHODIMP BitWrite(UINT64 data, int len); + STDMETHODIMP BitFlush(); + STDMETHODIMP StrWrite(LPCSTR pData, BOOL bFixNewLine); +}; diff --git a/src/filters/muxer/BaseMuxer/stdafx.cpp b/src/filters/muxer/BaseMuxer/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/muxer/BaseMuxer/stdafx.cpp +++ b/src/filters/muxer/BaseMuxer/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/muxer/BaseMuxer/stdafx.h b/src/filters/muxer/BaseMuxer/stdafx.h index 0ebf71a1710..75ebfbc6a9d 100644 --- a/src/filters/muxer/BaseMuxer/stdafx.h +++ b/src/filters/muxer/BaseMuxer/stdafx.h @@ -1,37 +1,37 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include - -#include "BaseClasses/streams.h" -#include "../../../DSUtil/DSUtil.h" +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include + +#include "BaseClasses/streams.h" +#include "../../../DSUtil/DSUtil.h" diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.cpp b/src/filters/muxer/DSMMuxer/DSMMuxer.cpp index 93ab3852272..951322fc3ea 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.cpp +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.cpp @@ -1,450 +1,450 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "DSMMuxer.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include -#include "moreuuids.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia} -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, nullptr, 0, nullptr}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CDSMMuxerFilter), DSMMuxerName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -template static T myabs(T n) -{ - return n >= 0 ? n : -n; -} - -static int GetByteLength(UINT64 data, int min = 0) -{ - int i = 7; - while (i >= min && ((BYTE*)&data)[i] == 0) { - i--; - } - return ++i; -} - -// -// CDSMMuxerFilter -// - -CDSMMuxerFilter::CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap, bool fAutoRes) - : CBaseMuxerFilter(pUnk, phr, __uuidof(this)) - , m_fAutoChap(fAutoChap) - , m_fAutoRes(fAutoRes) - , m_rtPrevSyncPoint(_I64_MIN) -{ - if (phr) { - *phr = S_OK; - } -} - -CDSMMuxerFilter::~CDSMMuxerFilter() -{ -} - -STDMETHODIMP CDSMMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CDSMMuxerFilter::MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len) -{ - ASSERT(type < 32); - - int i = GetByteLength(len, 1); - - pBS->BitWrite(DSMSW, DSMSW_SIZE << 3); - pBS->BitWrite(type, 5); - pBS->BitWrite(i - 1, 3); - pBS->BitWrite(len, i << 3); -} - -void CDSMMuxerFilter::MuxFileInfo(IBitStream* pBS) -{ - int len = 1; - CSimpleMap si; - - for (int i = 0; i < GetSize(); i++) { - CStringA key = CStringA(CString(GetKeyAt(i))), value = UTF16To8(GetValueAt(i)); - if (key.GetLength() != 4) { - continue; - } - si.Add(key, value); - len += 4 + value.GetLength() + 1; - } - - MuxPacketHeader(pBS, DSMP_FILEINFO, len); - pBS->BitWrite(DSMF_VERSION, 8); - for (int i = 0; i < si.GetSize(); i++) { - CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i); - pBS->ByteWrite((LPCSTR)key, 4); - pBS->ByteWrite((LPCSTR)value, value.GetLength() + 1); - } - -} - -void CDSMMuxerFilter::MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin) -{ - int len = 1; - CSimpleMap si; - - for (int i = 0; i < pPin->GetSize(); i++) { - CStringA key = CStringA(CString(pPin->GetKeyAt(i))), value = UTF16To8(pPin->GetValueAt(i)); - if (key.GetLength() != 4) { - continue; - } - si.Add(key, value); - len += 4 + value.GetLength() + 1; - } - - if (len > 1) { - MuxPacketHeader(pBS, DSMP_STREAMINFO, len); - pBS->BitWrite(pPin->GetID(), 8); - for (int i = 0; i < si.GetSize(); i++) { - CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i); - pBS->ByteWrite((LPCSTR)key, 4); - pBS->ByteWrite((LPCSTR)value, value.GetLength() + 1); - } - } -} - -void CDSMMuxerFilter::MuxInit() -{ - m_sps.RemoveAll(); - m_isps.RemoveAll(); - m_rtPrevSyncPoint = _I64_MIN; -} - -void CDSMMuxerFilter::MuxHeader(IBitStream* pBS) -{ - CString muxer; - muxer.Format(_T("DSM Muxer (%S)"), __TIMESTAMP__); - - SetProperty(L"MUXR", CStringW(muxer)); - SetProperty(L"DATE", CStringW(CTime::GetCurrentTime().FormatGmt(_T("%Y-%m-%d %H:%M:%S")))); - - MuxFileInfo(pBS); - - POSITION pos = m_pPins.GetHeadPosition(); - while (pos) { - CBaseMuxerInputPin* pPin = m_pPins.GetNext(pos); - const CMediaType& mt = pPin->CurrentMediaType(); - - ASSERT((mt.lSampleSize >> 30) == 0); // you don't need >1GB samples, do you? - - MuxPacketHeader(pBS, DSMP_MEDIATYPE, 5 + sizeof(GUID) * 3 + mt.FormatLength()); - pBS->BitWrite(pPin->GetID(), 8); - pBS->ByteWrite(&mt.majortype, sizeof(mt.majortype)); - pBS->ByteWrite(&mt.subtype, sizeof(mt.subtype)); - pBS->BitWrite(mt.bFixedSizeSamples, 1); - pBS->BitWrite(mt.bTemporalCompression, 1); - pBS->BitWrite(mt.lSampleSize, 30); - pBS->ByteWrite(&mt.formattype, sizeof(mt.formattype)); - pBS->ByteWrite(mt.Format(), mt.FormatLength()); - - MuxStreamInfo(pBS, pPin); - } - - // resources & chapters - - CInterfaceList pRBs; - pRBs.AddTail(this); - - CComQIPtr pCB = (IUnknown*)(INonDelegatingUnknown*)this; - - pos = m_pPins.GetHeadPosition(); - while (pos) { - for (CComPtr pPin = m_pPins.GetNext(pos)->GetConnected(); pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { - if (m_fAutoRes) { - CComQIPtr pPB = GetFilterFromPin(pPin); - if (pPB && !pRBs.Find(pPB)) { - pRBs.AddTail(pPB); - } - } - - if (m_fAutoChap) { - if (!pCB || pCB->ChapGetCount() == 0) { - pCB = GetFilterFromPin(pPin); - } - } - } - } - - // resources - - pos = pRBs.GetHeadPosition(); - while (pos) { - IDSMResourceBag* pRB = pRBs.GetNext(pos); - - for (DWORD i = 0, j = pRB->ResGetCount(); i < j; i++) { - CComBSTR name, desc, mime; - BYTE* pData = nullptr; - DWORD len = 0; - if (SUCCEEDED(pRB->ResGet(i, &name, &desc, &mime, &pData, &len, nullptr))) { - CStringA utf8_name = UTF16To8(name); - CStringA utf8_desc = UTF16To8(desc); - CStringA utf8_mime = UTF16To8(mime); - - MuxPacketHeader(pBS, DSMP_RESOURCE, - 1 + - utf8_name.GetLength() + 1 + - utf8_desc.GetLength() + 1 + - utf8_mime.GetLength() + 1 + - len); - - pBS->BitWrite(0, 2); - pBS->BitWrite(0, 6); // reserved - pBS->ByteWrite(utf8_name, utf8_name.GetLength() + 1); - pBS->ByteWrite(utf8_desc, utf8_desc.GetLength() + 1); - pBS->ByteWrite(utf8_mime, utf8_mime.GetLength() + 1); - pBS->ByteWrite(pData, len); - - CoTaskMemFree(pData); - } - } - } - - // chapters - - if (pCB) { - CAtlList chapters; - REFERENCE_TIME rtPrev = 0; - int len = 0; - - pCB->ChapSort(); - - for (DWORD i = 0; i < pCB->ChapGetCount(); i++) { - CDSMChapter c; - CComBSTR name; - if (SUCCEEDED(pCB->ChapGet(i, &c.rt, &name))) { - REFERENCE_TIME rtDiff = c.rt - rtPrev; - rtPrev = c.rt; - c.rt = rtDiff; - c.name = name; - len += 1 + GetByteLength(myabs(c.rt)) + UTF16To8(c.name).GetLength() + 1; - chapters.AddTail(c); - } - } - - if (chapters.GetCount()) { - MuxPacketHeader(pBS, DSMP_CHAPTERS, len); - - pos = chapters.GetHeadPosition(); - while (pos) { - CDSMChapter& c = chapters.GetNext(pos); - CStringA name = UTF16To8(c.name); - int irt = GetByteLength(myabs(c.rt)); - pBS->BitWrite(c.rt < 0, 1); - pBS->BitWrite(irt, 3); - pBS->BitWrite(0, 4); - pBS->BitWrite(myabs(c.rt), irt << 3); - pBS->ByteWrite((LPCSTR)name, name.GetLength() + 1); - } - } - } -} - -void CDSMMuxerFilter::MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket) -{ - if (pPacket->IsEOS()) { - return; - } - - if (pPacket->pPin->CurrentMediaType().majortype == MEDIATYPE_Text) { - CStringA str((char*)pPacket->pData.GetData(), (int)pPacket->pData.GetCount()); - str.Replace("\xff", " "); - str.Replace(" ", " "); - str.Replace(" ", " "); - str.Trim(); - if (str.IsEmpty()) { - return; - } - } - - ASSERT(!pPacket->IsSyncPoint() || pPacket->IsTimeValid()); - - REFERENCE_TIME rtTimeStamp = _I64_MIN, rtDuration = 0; - int iTimeStamp = 0, iDuration = 0; - - if (pPacket->IsTimeValid()) { - rtTimeStamp = pPacket->rtStart; - rtDuration = std::max(pPacket->rtStop - pPacket->rtStart, 0ll); - - iTimeStamp = GetByteLength(myabs(rtTimeStamp)); - ASSERT(iTimeStamp <= 7); - - iDuration = GetByteLength(rtDuration); - ASSERT(iDuration <= 7); - - IndexSyncPoint(pPacket, pBS->GetPos()); - } - - UINT64 len = 2 + iTimeStamp + iDuration + pPacket->pData.GetCount(); // id + flags + data - - MuxPacketHeader(pBS, DSMP_SAMPLE, len); - pBS->BitWrite(pPacket->pPin->GetID(), 8); - pBS->BitWrite(pPacket->IsSyncPoint(), 1); - pBS->BitWrite(rtTimeStamp < 0, 1); - pBS->BitWrite(iTimeStamp, 3); - pBS->BitWrite(iDuration, 3); - pBS->BitWrite(myabs(rtTimeStamp), iTimeStamp << 3); - pBS->BitWrite(rtDuration, iDuration << 3); - pBS->ByteWrite(pPacket->pData.GetData(), (int)pPacket->pData.GetCount()); -} - -void CDSMMuxerFilter::MuxFooter(IBitStream* pBS) -{ - // syncpoints - - int len = 0; - CAtlList isps; - REFERENCE_TIME rtPrev = 0, rt; - UINT64 fpPrev = 0, fp; - - POSITION pos = m_isps.GetHeadPosition(); - while (pos) { - IndexedSyncPoint& isp = m_isps.GetNext(pos); - TRACE(_T("sp[%d]: %I64d %I64x\n"), isp.id, isp.rt, isp.fp); - - rt = isp.rt - rtPrev; - rtPrev = isp.rt; - fp = isp.fp - fpPrev; - fpPrev = isp.fp; - - IndexedSyncPoint isp2; - isp2.fp = fp; - isp2.rt = rt; - isps.AddTail(isp2); - - len += 1 + GetByteLength(myabs(rt)) + GetByteLength(fp); // flags + rt + fp - } - - MuxPacketHeader(pBS, DSMP_SYNCPOINTS, len); - - pos = isps.GetHeadPosition(); - while (pos) { - IndexedSyncPoint& isp = isps.GetNext(pos); - - int irt = GetByteLength(myabs(isp.rt)); - int ifp = GetByteLength(isp.fp); - - pBS->BitWrite(isp.rt < 0, 1); - pBS->BitWrite(irt, 3); - pBS->BitWrite(ifp, 3); - pBS->BitWrite(0, 1); // reserved - pBS->BitWrite(myabs(isp.rt), irt << 3); - pBS->BitWrite(isp.fp, ifp << 3); - } -} - -void CDSMMuxerFilter::IndexSyncPoint(const MuxerPacket* p, __int64 fp) -{ - // Yes, this is as complicated as it looks. - // Rule #1: don't write this packet if you can't do it reliably. - // (think about overlapped subtitles, line1: 0->10, line2: 1->9) - - // FIXME: the very last syncpoints won't get moved to m_isps because there are no more syncpoints to trigger it! - - if (fp < 0 || !p || !p->IsTimeValid() || !p->IsSyncPoint()) { - return; - } - - ASSERT(p->rtStart >= m_rtPrevSyncPoint); - m_rtPrevSyncPoint = p->rtStart; - - SyncPoint sp; - sp.id = (BYTE)p->pPin->GetID(); - sp.rtStart = p->rtStart; - sp.rtStop = p->pPin->IsSubtitleStream() ? p->rtStop : _I64_MAX; - sp.fp = fp; - - { - SyncPoint& head = !m_sps.IsEmpty() ? m_sps.GetHead() : sp; - SyncPoint& tail = !m_sps.IsEmpty() ? m_sps.GetTail() : sp; - REFERENCE_TIME rtfp = !m_isps.IsEmpty() ? m_isps.GetTail().rtfp : _I64_MIN; - - if (head.rtStart > rtfp + 1000000) { // 100ms limit, just in case every stream had only keyframes, then sycnpoints would be too frequent - IndexedSyncPoint isp; - isp.id = head.id; - isp.rt = tail.rtStart; - isp.rtfp = head.rtStart; - isp.fp = head.fp; - m_isps.AddTail(isp); - } - } - - POSITION pos = m_sps.GetHeadPosition(); - while (pos) { - POSITION cur = pos; - SyncPoint& sp2 = m_sps.GetNext(pos); - if (sp2.id == sp.id && sp2.rtStop <= sp.rtStop || sp2.rtStop <= sp.rtStart) { - m_sps.RemoveAt(cur); - } - } - - m_sps.AddTail(sp); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "DSMMuxer.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include +#include "moreuuids.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia} +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, nullptr, 0, nullptr}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CDSMMuxerFilter), DSMMuxerName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +template static T myabs(T n) +{ + return n >= 0 ? n : -n; +} + +static int GetByteLength(UINT64 data, int min = 0) +{ + int i = 7; + while (i >= min && ((BYTE*)&data)[i] == 0) { + i--; + } + return ++i; +} + +// +// CDSMMuxerFilter +// + +CDSMMuxerFilter::CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap, bool fAutoRes) + : CBaseMuxerFilter(pUnk, phr, __uuidof(this)) + , m_fAutoChap(fAutoChap) + , m_fAutoRes(fAutoRes) + , m_rtPrevSyncPoint(_I64_MIN) +{ + if (phr) { + *phr = S_OK; + } +} + +CDSMMuxerFilter::~CDSMMuxerFilter() +{ +} + +STDMETHODIMP CDSMMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CDSMMuxerFilter::MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len) +{ + ASSERT(type < 32); + + int i = GetByteLength(len, 1); + + pBS->BitWrite(DSMSW, DSMSW_SIZE << 3); + pBS->BitWrite(type, 5); + pBS->BitWrite(i - 1, 3); + pBS->BitWrite(len, i << 3); +} + +void CDSMMuxerFilter::MuxFileInfo(IBitStream* pBS) +{ + int len = 1; + CSimpleMap si; + + for (int i = 0; i < GetSize(); i++) { + CStringA key = CStringA(CString(GetKeyAt(i))), value = UTF16To8(GetValueAt(i)); + if (key.GetLength() != 4) { + continue; + } + si.Add(key, value); + len += 4 + value.GetLength() + 1; + } + + MuxPacketHeader(pBS, DSMP_FILEINFO, len); + pBS->BitWrite(DSMF_VERSION, 8); + for (int i = 0; i < si.GetSize(); i++) { + CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i); + pBS->ByteWrite((LPCSTR)key, 4); + pBS->ByteWrite((LPCSTR)value, value.GetLength() + 1); + } + +} + +void CDSMMuxerFilter::MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin) +{ + int len = 1; + CSimpleMap si; + + for (int i = 0; i < pPin->GetSize(); i++) { + CStringA key = CStringA(CString(pPin->GetKeyAt(i))), value = UTF16To8(pPin->GetValueAt(i)); + if (key.GetLength() != 4) { + continue; + } + si.Add(key, value); + len += 4 + value.GetLength() + 1; + } + + if (len > 1) { + MuxPacketHeader(pBS, DSMP_STREAMINFO, len); + pBS->BitWrite(pPin->GetID(), 8); + for (int i = 0; i < si.GetSize(); i++) { + CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i); + pBS->ByteWrite((LPCSTR)key, 4); + pBS->ByteWrite((LPCSTR)value, value.GetLength() + 1); + } + } +} + +void CDSMMuxerFilter::MuxInit() +{ + m_sps.RemoveAll(); + m_isps.RemoveAll(); + m_rtPrevSyncPoint = _I64_MIN; +} + +void CDSMMuxerFilter::MuxHeader(IBitStream* pBS) +{ + CString muxer; + muxer.Format(_T("DSM Muxer (%S)"), __TIMESTAMP__); + + SetProperty(L"MUXR", CStringW(muxer)); + SetProperty(L"DATE", CStringW(CTime::GetCurrentTime().FormatGmt(_T("%Y-%m-%d %H:%M:%S")))); + + MuxFileInfo(pBS); + + POSITION pos = m_pPins.GetHeadPosition(); + while (pos) { + CBaseMuxerInputPin* pPin = m_pPins.GetNext(pos); + const CMediaType& mt = pPin->CurrentMediaType(); + + ASSERT((mt.lSampleSize >> 30) == 0); // you don't need >1GB samples, do you? + + MuxPacketHeader(pBS, DSMP_MEDIATYPE, 5 + sizeof(GUID) * 3 + mt.FormatLength()); + pBS->BitWrite(pPin->GetID(), 8); + pBS->ByteWrite(&mt.majortype, sizeof(mt.majortype)); + pBS->ByteWrite(&mt.subtype, sizeof(mt.subtype)); + pBS->BitWrite(mt.bFixedSizeSamples, 1); + pBS->BitWrite(mt.bTemporalCompression, 1); + pBS->BitWrite(mt.lSampleSize, 30); + pBS->ByteWrite(&mt.formattype, sizeof(mt.formattype)); + pBS->ByteWrite(mt.Format(), mt.FormatLength()); + + MuxStreamInfo(pBS, pPin); + } + + // resources & chapters + + CInterfaceList pRBs; + pRBs.AddTail(this); + + CComQIPtr pCB = (IUnknown*)(INonDelegatingUnknown*)this; + + pos = m_pPins.GetHeadPosition(); + while (pos) { + for (CComPtr pPin = m_pPins.GetNext(pos)->GetConnected(); pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { + if (m_fAutoRes) { + CComQIPtr pPB = GetFilterFromPin(pPin); + if (pPB && !pRBs.Find(pPB)) { + pRBs.AddTail(pPB); + } + } + + if (m_fAutoChap) { + if (!pCB || pCB->ChapGetCount() == 0) { + pCB = GetFilterFromPin(pPin); + } + } + } + } + + // resources + + pos = pRBs.GetHeadPosition(); + while (pos) { + IDSMResourceBag* pRB = pRBs.GetNext(pos); + + for (DWORD i = 0, j = pRB->ResGetCount(); i < j; i++) { + CComBSTR name, desc, mime; + BYTE* pData = nullptr; + DWORD len = 0; + if (SUCCEEDED(pRB->ResGet(i, &name, &desc, &mime, &pData, &len, nullptr))) { + CStringA utf8_name = UTF16To8(name); + CStringA utf8_desc = UTF16To8(desc); + CStringA utf8_mime = UTF16To8(mime); + + MuxPacketHeader(pBS, DSMP_RESOURCE, + 1 + + utf8_name.GetLength() + 1 + + utf8_desc.GetLength() + 1 + + utf8_mime.GetLength() + 1 + + len); + + pBS->BitWrite(0, 2); + pBS->BitWrite(0, 6); // reserved + pBS->ByteWrite(utf8_name, utf8_name.GetLength() + 1); + pBS->ByteWrite(utf8_desc, utf8_desc.GetLength() + 1); + pBS->ByteWrite(utf8_mime, utf8_mime.GetLength() + 1); + pBS->ByteWrite(pData, len); + + CoTaskMemFree(pData); + } + } + } + + // chapters + + if (pCB) { + CAtlList chapters; + REFERENCE_TIME rtPrev = 0; + int len = 0; + + pCB->ChapSort(); + + for (DWORD i = 0; i < pCB->ChapGetCount(); i++) { + CDSMChapter c; + CComBSTR name; + if (SUCCEEDED(pCB->ChapGet(i, &c.rt, &name))) { + REFERENCE_TIME rtDiff = c.rt - rtPrev; + rtPrev = c.rt; + c.rt = rtDiff; + c.name = name; + len += 1 + GetByteLength(myabs(c.rt)) + UTF16To8(c.name).GetLength() + 1; + chapters.AddTail(c); + } + } + + if (chapters.GetCount()) { + MuxPacketHeader(pBS, DSMP_CHAPTERS, len); + + pos = chapters.GetHeadPosition(); + while (pos) { + CDSMChapter& c = chapters.GetNext(pos); + CStringA name = UTF16To8(c.name); + int irt = GetByteLength(myabs(c.rt)); + pBS->BitWrite(c.rt < 0, 1); + pBS->BitWrite(irt, 3); + pBS->BitWrite(0, 4); + pBS->BitWrite(myabs(c.rt), irt << 3); + pBS->ByteWrite((LPCSTR)name, name.GetLength() + 1); + } + } + } +} + +void CDSMMuxerFilter::MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket) +{ + if (pPacket->IsEOS()) { + return; + } + + if (pPacket->pPin->CurrentMediaType().majortype == MEDIATYPE_Text) { + CStringA str((char*)pPacket->pData.GetData(), (int)pPacket->pData.GetCount()); + str.Replace("\xff", " "); + str.Replace(" ", " "); + str.Replace(" ", " "); + str.Trim(); + if (str.IsEmpty()) { + return; + } + } + + ASSERT(!pPacket->IsSyncPoint() || pPacket->IsTimeValid()); + + REFERENCE_TIME rtTimeStamp = _I64_MIN, rtDuration = 0; + int iTimeStamp = 0, iDuration = 0; + + if (pPacket->IsTimeValid()) { + rtTimeStamp = pPacket->rtStart; + rtDuration = std::max(pPacket->rtStop - pPacket->rtStart, 0ll); + + iTimeStamp = GetByteLength(myabs(rtTimeStamp)); + ASSERT(iTimeStamp <= 7); + + iDuration = GetByteLength(rtDuration); + ASSERT(iDuration <= 7); + + IndexSyncPoint(pPacket, pBS->GetPos()); + } + + UINT64 len = 2 + iTimeStamp + iDuration + pPacket->pData.GetCount(); // id + flags + data + + MuxPacketHeader(pBS, DSMP_SAMPLE, len); + pBS->BitWrite(pPacket->pPin->GetID(), 8); + pBS->BitWrite(pPacket->IsSyncPoint(), 1); + pBS->BitWrite(rtTimeStamp < 0, 1); + pBS->BitWrite(iTimeStamp, 3); + pBS->BitWrite(iDuration, 3); + pBS->BitWrite(myabs(rtTimeStamp), iTimeStamp << 3); + pBS->BitWrite(rtDuration, iDuration << 3); + pBS->ByteWrite(pPacket->pData.GetData(), (int)pPacket->pData.GetCount()); +} + +void CDSMMuxerFilter::MuxFooter(IBitStream* pBS) +{ + // syncpoints + + int len = 0; + CAtlList isps; + REFERENCE_TIME rtPrev = 0, rt; + UINT64 fpPrev = 0, fp; + + POSITION pos = m_isps.GetHeadPosition(); + while (pos) { + IndexedSyncPoint& isp = m_isps.GetNext(pos); + TRACE(_T("sp[%d]: %I64d %I64x\n"), isp.id, isp.rt, isp.fp); + + rt = isp.rt - rtPrev; + rtPrev = isp.rt; + fp = isp.fp - fpPrev; + fpPrev = isp.fp; + + IndexedSyncPoint isp2; + isp2.fp = fp; + isp2.rt = rt; + isps.AddTail(isp2); + + len += 1 + GetByteLength(myabs(rt)) + GetByteLength(fp); // flags + rt + fp + } + + MuxPacketHeader(pBS, DSMP_SYNCPOINTS, len); + + pos = isps.GetHeadPosition(); + while (pos) { + IndexedSyncPoint& isp = isps.GetNext(pos); + + int irt = GetByteLength(myabs(isp.rt)); + int ifp = GetByteLength(isp.fp); + + pBS->BitWrite(isp.rt < 0, 1); + pBS->BitWrite(irt, 3); + pBS->BitWrite(ifp, 3); + pBS->BitWrite(0, 1); // reserved + pBS->BitWrite(myabs(isp.rt), irt << 3); + pBS->BitWrite(isp.fp, ifp << 3); + } +} + +void CDSMMuxerFilter::IndexSyncPoint(const MuxerPacket* p, __int64 fp) +{ + // Yes, this is as complicated as it looks. + // Rule #1: don't write this packet if you can't do it reliably. + // (think about overlapped subtitles, line1: 0->10, line2: 1->9) + + // FIXME: the very last syncpoints won't get moved to m_isps because there are no more syncpoints to trigger it! + + if (fp < 0 || !p || !p->IsTimeValid() || !p->IsSyncPoint()) { + return; + } + + ASSERT(p->rtStart >= m_rtPrevSyncPoint); + m_rtPrevSyncPoint = p->rtStart; + + SyncPoint sp; + sp.id = (BYTE)p->pPin->GetID(); + sp.rtStart = p->rtStart; + sp.rtStop = p->pPin->IsSubtitleStream() ? p->rtStop : _I64_MAX; + sp.fp = fp; + + { + SyncPoint& head = !m_sps.IsEmpty() ? m_sps.GetHead() : sp; + SyncPoint& tail = !m_sps.IsEmpty() ? m_sps.GetTail() : sp; + REFERENCE_TIME rtfp = !m_isps.IsEmpty() ? m_isps.GetTail().rtfp : _I64_MIN; + + if (head.rtStart > rtfp + 1000000) { // 100ms limit, just in case every stream had only keyframes, then sycnpoints would be too frequent + IndexedSyncPoint isp; + isp.id = head.id; + isp.rt = tail.rtStart; + isp.rtfp = head.rtStart; + isp.fp = head.fp; + m_isps.AddTail(isp); + } + } + + POSITION pos = m_sps.GetHeadPosition(); + while (pos) { + POSITION cur = pos; + SyncPoint& sp2 = m_sps.GetNext(pos); + if (sp2.id == sp.id && sp2.rtStop <= sp.rtStop || sp2.rtStop <= sp.rtStart) { + m_sps.RemoveAt(cur); + } + } + + m_sps.AddTail(sp); +} diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.def b/src/filters/muxer/DSMMuxer/DSMMuxer.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.def +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.h b/src/filters/muxer/DSMMuxer/DSMMuxer.h index 893267dcc9c..c955e1897b0 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.h +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.h @@ -1,66 +1,66 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../BaseMuxer/BaseMuxer.h" -#include "dsm/dsm.h" - -#define DSMMuxerName L"MPC DSM Muxer" - -class __declspec(uuid("C6590B76-587E-4082-9125-680D0693A97B")) - CDSMMuxerFilter : public CBaseMuxerFilter -{ - bool m_fAutoChap, m_fAutoRes; - - struct SyncPoint { - BYTE id; - REFERENCE_TIME rtStart, rtStop; - __int64 fp; - }; - struct IndexedSyncPoint { - BYTE id; - REFERENCE_TIME rt, rtfp; - __int64 fp; - }; - CAtlList m_sps; - CAtlList m_isps; - REFERENCE_TIME m_rtPrevSyncPoint; - void IndexSyncPoint(const MuxerPacket* p, __int64 fp); - - void MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len); - void MuxFileInfo(IBitStream* pBS); - void MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin); - -protected: - void MuxInit(); - - void MuxHeader(IBitStream* pBS); - void MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket); - void MuxFooter(IBitStream* pBS); - -public: - CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap = true, bool fAutoRes = true); - virtual ~CDSMMuxerFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "../BaseMuxer/BaseMuxer.h" +#include "dsm/dsm.h" + +#define DSMMuxerName L"MPC DSM Muxer" + +class __declspec(uuid("C6590B76-587E-4082-9125-680D0693A97B")) + CDSMMuxerFilter : public CBaseMuxerFilter +{ + bool m_fAutoChap, m_fAutoRes; + + struct SyncPoint { + BYTE id; + REFERENCE_TIME rtStart, rtStop; + __int64 fp; + }; + struct IndexedSyncPoint { + BYTE id; + REFERENCE_TIME rt, rtfp; + __int64 fp; + }; + CAtlList m_sps; + CAtlList m_isps; + REFERENCE_TIME m_rtPrevSyncPoint; + void IndexSyncPoint(const MuxerPacket* p, __int64 fp); + + void MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len); + void MuxFileInfo(IBitStream* pBS); + void MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin); + +protected: + void MuxInit(); + + void MuxHeader(IBitStream* pBS); + void MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket); + void MuxFooter(IBitStream* pBS); + +public: + CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap = true, bool fAutoRes = true); + virtual ~CDSMMuxerFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); +}; diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.rc b/src/filters/muxer/DSMMuxer/DSMMuxer.rc index 9a5513dcfef..02b928f6dde 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.rc +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "DirectShow Media Muxer" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "DirectShow Media Muxer" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "DSMMuxer.ax" - VALUE "ProductName", "DirectShow Media Muxer" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "DirectShow Media Muxer" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "DirectShow Media Muxer" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "DSMMuxer.ax" + VALUE "ProductName", "DirectShow Media Muxer" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj b/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj index 3f17d32a7df..5ab0c3293ab 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj @@ -1,127 +1,127 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {65361C7C-83D6-42E4-870C-4DC85AE641FE} - DSMMuxer - Win32Proj - DSMMuxer - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - DSMMuxer.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {db5f93b2-54d0-4474-a588-d259be36c832} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {65361C7C-83D6-42E4-870C-4DC85AE641FE} + DSMMuxer + Win32Proj + DSMMuxer + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + DSMMuxer.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {db5f93b2-54d0-4474-a588-d259be36c832} + + + + + \ No newline at end of file diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj.filters b/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj.filters index 23b96ae456b..3bddc44d39f 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj.filters +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {f2a0afa9-5123-40d6-9344-b1620d9ab714} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {181a9f13-cf46-4334-9042-2a7f21566a7f} - h;hpp;hxx;hm;inl;inc - - - {6e2d23f9-16bb-4682-ac30-1ab1b61e5774} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {f2a0afa9-5123-40d6-9344-b1620d9ab714} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {181a9f13-cf46-4334-9042-2a7f21566a7f} + h;hpp;hxx;hm;inl;inc + + + {6e2d23f9-16bb-4682-ac30-1ab1b61e5774} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/muxer/DSMMuxer/resource.h b/src/filters/muxer/DSMMuxer/resource.h index 07b0c93390a..1db5c7362b2 100644 --- a/src/filters/muxer/DSMMuxer/resource.h +++ b/src/filters/muxer/DSMMuxer/resource.h @@ -1,15 +1,15 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by DSMMuxer.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DSMMuxer.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/muxer/DSMMuxer/stdafx.cpp b/src/filters/muxer/DSMMuxer/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/muxer/DSMMuxer/stdafx.cpp +++ b/src/filters/muxer/DSMMuxer/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/muxer/DSMMuxer/stdafx.h b/src/filters/muxer/DSMMuxer/stdafx.h index 3d1feeda544..2cd026b0419 100644 --- a/src/filters/muxer/DSMMuxer/stdafx.h +++ b/src/filters/muxer/DSMMuxer/stdafx.h @@ -1,39 +1,39 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include -#include - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include +#include + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaFile.cpp b/src/filters/muxer/MatroskaMuxer/MatroskaFile.cpp index f2c1e0d8278..32e3bdbdb70 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaFile.cpp +++ b/src/filters/muxer/MatroskaMuxer/MatroskaFile.cpp @@ -1,937 +1,937 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include -#include "MatroskaFile.h" -#include "../../../DSUtil/DSUtil.h" - -using namespace MatroskaWriter; - -static void bswap(BYTE* s, int len) -{ - for (BYTE* d = s + len - 1; s < d; s++, d--) { - *s ^= *d, *d ^= *s, *s ^= *d; - } -} - -// - -CID::CID(DWORD id) - : m_id(id) -{ -} - -QWORD CID::Size(bool fWithHeader) -{ - return CUInt(0, m_id).Size(false); -} - -HRESULT CID::Write(IStream* pStream) -{ - QWORD len = CID::Size(); - DWORD id = m_id; - bswap((BYTE*)&id, (int)len); - *(BYTE*)&id = ((*(BYTE*)&id) & (1 << (8 - len)) - 1) | (1 << (8 - len)); - return pStream->Write(&id, (ULONG)len, nullptr); -} - -QWORD CID::HeaderSize(QWORD len) -{ - return CID::Size() + CLength(len).Size(); -} - -HRESULT CID::HeaderWrite(IStream* pStream) -{ - CID::Write(pStream); - CLength(Size(false)).Write(pStream); - return S_OK; -} - -QWORD CBinary::Size(bool fWithHeader) -{ - if (IsEmpty()) { - return 0; - } - - QWORD len = 0; - len += GetCount(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CBinary::Write(IStream* pStream) -{ - if (IsEmpty()) { - return S_OK; - } - - HeaderWrite(pStream); - return pStream->Write(GetData(), (ULONG)GetCount(), nullptr); -} - -QWORD CANSI::Size(bool fWithHeader) -{ - if (IsEmpty()) { - return 0; - } - - QWORD len = 0; - len += GetLength(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CANSI::Write(IStream* pStream) -{ - if (IsEmpty()) { - return S_OK; - } - - HeaderWrite(pStream); - return pStream->Write((LPCSTR) * this, GetLength(), nullptr); -} - -QWORD CUTF8::Size(bool fWithHeader) -{ - if (IsEmpty()) { - return 0; - } - - QWORD len = 0; - len += UTF16To8(*this).GetLength(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CUTF8::Write(IStream* pStream) -{ - if (IsEmpty()) { - return S_OK; - } - - HeaderWrite(pStream); - CStringA str = UTF16To8(*this); - return pStream->Write((BYTE*)(LPCSTR)str, str.GetLength(), nullptr); -} - -template -QWORD CSimpleVar::Size(bool fWithHeader) -{ - if (!m_fSet) { - return 0; - } - - QWORD len = 0; - len += sizeof(T); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -template -HRESULT CSimpleVar::Write(IStream* pStream) -{ - if (!m_fSet) { - return S_OK; - } - - HeaderWrite(pStream); - T val = m_val; - bswap((BYTE*)&val, sizeof(T)); - return pStream->Write(&val, sizeof(T), nullptr); -} - -QWORD CUInt::Size(bool fWithHeader) -{ - if (!m_fSet) { - return 0; - } - - QWORD len = 0; - - if (m_val == 0) { - len++; - } else { - for (int i = 8; i > 0; i--) { - if (((0xffi64 << ((i - 1) * 8))&m_val)) { - len += i; - break; - } - } - } - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CUInt::Write(IStream* pStream) -{ - if (!m_fSet) { - return S_OK; - } - - CID::Write(pStream); - CLength l(Size(false)); - l.Write(pStream); - UINT64 val = m_val; - bswap((BYTE*)&val, (int)l); - return pStream->Write(&val, (ULONG)l, nullptr); -} - -QWORD CInt::Size(bool fWithHeader) -{ - if (!m_fSet) { - return 0; - } - - QWORD len = 0; - - if (m_val == 0) { - len++; - } else { - UINT64 val = m_val >= 0 ? m_val : -m_val; - for (int i = 8; i > 0; i--) { - if (((0xffi64 << ((i - 1) * 8))&val)) { - len += i; - if (m_val < 0 && !(m_val & (0x80 << (i - 1)))) { - len++; - } - break; - } - } - } - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CInt::Write(IStream* pStream) -{ - if (!m_fSet) { - return S_OK; - } - - CID::Write(pStream); - CLength l(Size(false)); - l.Write(pStream); - UINT64 val = m_val; - bswap((BYTE*)&val, (int)l); - return pStream->Write(&val, (ULONG)l, nullptr); -} - -QWORD CLength::Size(bool fWithHeader) -{ - if (m_len == 0x00FFFFFFFFFFFFFFi64) { - return 8; - } - - QWORD len = 0; - for (int i = 1; i <= 8; i++) { - if (!(m_len & (~((QWORD(1) << (7 * i)) - 1))) && (m_len & ((QWORD(1) << (7 * i)) - 1)) != ((QWORD(1) << (7 * i)) - 1)) { - len += i; - break; - } - } - return len; -} - -HRESULT CLength::Write(IStream* pStream) -{ - QWORD len = Size(false); - UINT64 val = m_len; - bswap((BYTE*)&val, (int)len); - *(BYTE*)&val = ((*(BYTE*)&val) & (1 << (8 - len)) - 1) | (1 << (8 - len)); - return pStream->Write(&val, (ULONG)len, nullptr); -} - -// - -EBML::EBML(DWORD id) - : CID(id) - , EBMLVersion(0x4286) - , EBMLReadVersion(0x42F7) - , EBMLMaxIDLength(0x42F2) - , EBMLMaxSizeLength(0x42F3) - , DocType(0x4282) - , DocTypeVersion(0x4287) - , DocTypeReadVersion(0x4285) -{ -} - -QWORD EBML::Size(bool fWithHeader) -{ - QWORD len = 0; - len += EBMLVersion.Size(); - len += EBMLReadVersion.Size(); - len += EBMLMaxIDLength.Size(); - len += EBMLMaxSizeLength.Size(); - len += DocType.Size(); - len += DocTypeVersion.Size(); - len += DocTypeReadVersion.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT EBML::Write(IStream* pStream) -{ - HeaderWrite(pStream); - EBMLVersion.Write(pStream); - EBMLReadVersion.Write(pStream); - EBMLMaxIDLength.Write(pStream); - EBMLMaxSizeLength.Write(pStream); - DocType.Write(pStream); - DocTypeVersion.Write(pStream); - DocTypeReadVersion.Write(pStream); - return S_OK; -} - -Info::Info(DWORD id) - : CID(id) - , SegmentUID(0x73A4) - , SegmentFilename(0x7384) - , PrevUID(0x3CB923) - , PrevFilename(0x3C83AB) - , NextUID(0x3EB923) - , NextFilename(0x3E83BB) - , TimeCodeScale(0x2AD7B1, 1000000ui64) - , Duration(0x4489) - , DateUTC(0x4461) - , Title(0x7BA9) - , MuxingApp(0x4D80) - , WritingApp(0x5741) -{ -} - -QWORD Info::Size(bool fWithHeader) -{ - QWORD len = 0; - len += SegmentUID.Size(); - len += PrevUID.Size(); - len += NextUID.Size(); - len += SegmentFilename.Size(); - len += PrevFilename.Size(); - len += NextFilename.Size(); - len += TimeCodeScale.Size(); - len += Duration.Size(); - len += DateUTC.Size(); - len += Title.Size(); - len += MuxingApp.Size(); - len += WritingApp.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Info::Write(IStream* pStream) -{ - HeaderWrite(pStream); - SegmentUID.Write(pStream); - PrevUID.Write(pStream); - NextUID.Write(pStream); - SegmentFilename.Write(pStream); - PrevFilename.Write(pStream); - NextFilename.Write(pStream); - TimeCodeScale.Write(pStream); - Duration.Write(pStream); - DateUTC.Write(pStream); - Title.Write(pStream); - MuxingApp.Write(pStream); - WritingApp.Write(pStream); - return S_OK; -} - -Segment::Segment(DWORD id) - : CID(id) -{ -} - -QWORD Segment::Size(bool fWithHeader) -{ - return 0x00FFFFFFFFFFFFFFi64; - /* - QWORD len = 0; - if (fWithHeader) len += HeaderSize(len); - return len; - */ -} - -HRESULT Segment::Write(IStream* pStream) -{ - HeaderWrite(pStream); - return S_OK; -} - -Track::Track(DWORD id) - : CID(id) -{ -} - -QWORD Track::Size(bool fWithHeader) -{ - QWORD len = 0; - len += TrackEntries.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Track::Write(IStream* pStream) -{ - HeaderWrite(pStream); - TrackEntries.Write(pStream); - return S_OK; -} - -TrackEntry::TrackEntry(DWORD id) - : CID(id) - , TrackNumber(0xD7) - , TrackUID(0x73C5) - , TrackType(0x83) - , FlagEnabled(0xB9) - , FlagDefault(0x88) - , FlagLacing(0x9C) - , MinCache(0x6DE7) - , MaxCache(0x6DF8) - , Name(0x536E) - , Language(0x22B59C) - , CodecID(0x86) - , CodecPrivate(0x63A2) - , CodecName(0x258688) - , CodecSettings(0x3A9697) - , CodecInfoURL(0x3B4040) - , CodecDownloadURL(0x26B240) - , CodecDecodeAll(0xAA) - , TrackOverlay(0x6FAB) - , DefaultDuration(0x23E383) - , v(0xE0) - , a(0xE1) -{ - DescType = NoDesc; -} - -QWORD TrackEntry::Size(bool fWithHeader) -{ - QWORD len = 0; - len += TrackNumber.Size(); - len += TrackUID.Size(); - len += TrackType.Size(); - len += FlagEnabled.Size(); - len += FlagDefault.Size(); - len += FlagLacing.Size(); - len += MinCache.Size(); - len += MaxCache.Size(); - len += Name.Size(); - len += Language.Size(); - len += CodecID.Size(); - len += CodecPrivate.Size(); - len += CodecName.Size(); - len += CodecSettings.Size(); - len += CodecInfoURL.Size(); - len += CodecDownloadURL.Size(); - len += CodecDecodeAll.Size(); - len += TrackOverlay.Size(); - len += DefaultDuration.Size(); - if (DescType == TypeVideo) { - len += v.Size(); - } - if (DescType == TypeAudio) { - len += a.Size(); - } - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT TrackEntry::Write(IStream* pStream) -{ - HeaderWrite(pStream); - TrackNumber.Write(pStream); - TrackUID.Write(pStream); - TrackType.Write(pStream); - FlagEnabled.Write(pStream); - FlagDefault.Write(pStream); - FlagLacing.Write(pStream); - MinCache.Write(pStream); - MaxCache.Write(pStream); - Name.Write(pStream); - Language.Write(pStream); - CodecID.Write(pStream); - CodecPrivate.Write(pStream); - CodecName.Write(pStream); - CodecSettings.Write(pStream); - CodecInfoURL.Write(pStream); - CodecDownloadURL.Write(pStream); - CodecDecodeAll.Write(pStream); - TrackOverlay.Write(pStream); - DefaultDuration.Write(pStream); - if (DescType == TypeVideo) { - v.Write(pStream); - } - if (DescType == TypeAudio) { - a.Write(pStream); - } - return S_OK; -} - -Video::Video(DWORD id) - : CID(id) - , FlagInterlaced(0x9A) - , StereoMode(0x53B8) - , PixelWidth(0xB0) - , PixelHeight(0xBA) - , DisplayWidth(0x54B0) - , DisplayHeight(0x54BA) - , DisplayUnit(0x54B2) - , AspectRatioType(0x54B3) - , ColourSpace(0x2EB524) - , GammaValue(0x2FB523) - , FramePerSec(0x2383E3) -{ -} - -QWORD Video::Size(bool fWithHeader) -{ - QWORD len = 0; - len += FlagInterlaced.Size(); - len += StereoMode.Size(); - len += PixelWidth.Size(); - len += PixelHeight.Size(); - len += DisplayWidth.Size(); - len += DisplayHeight.Size(); - len += DisplayUnit.Size(); - len += AspectRatioType.Size(); - len += ColourSpace.Size(); - len += GammaValue.Size(); - len += FramePerSec.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Video::Write(IStream* pStream) -{ - HeaderWrite(pStream); - FlagInterlaced.Write(pStream); - StereoMode.Write(pStream); - PixelWidth.Write(pStream); - PixelHeight.Write(pStream); - DisplayWidth.Write(pStream); - DisplayHeight.Write(pStream); - DisplayUnit.Write(pStream); - AspectRatioType.Write(pStream); - ColourSpace.Write(pStream); - GammaValue.Write(pStream); - FramePerSec.Write(pStream); - return S_OK; -} - -Audio::Audio(DWORD id) - : CID(id) - , SamplingFrequency(0xB5) - , OutputSamplingFrequency(0x78B5) - , Channels(0x9F) - , ChannelPositions(0x7D7B) - , BitDepth(0x6264) -{ -} - -QWORD Audio::Size(bool fWithHeader) -{ - QWORD len = 0; - len += SamplingFrequency.Size(); - len += OutputSamplingFrequency.Size(); - len += Channels.Size(); - len += ChannelPositions.Size(); - len += BitDepth.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Audio::Write(IStream* pStream) -{ - HeaderWrite(pStream); - SamplingFrequency.Write(pStream); - OutputSamplingFrequency.Write(pStream); - Channels.Write(pStream); - ChannelPositions.Write(pStream); - BitDepth.Write(pStream); - return S_OK; -} - -Cluster::Cluster(DWORD id) - : CID(id) - , TimeCode(0xE7) - , Position(0xA7) - , PrevSize(0xAB) -{ -} - -QWORD Cluster::Size(bool fWithHeader) -{ - QWORD len = 0; - len += TimeCode.Size(); - len += Position.Size(); - len += PrevSize.Size(); - len += BlockGroups.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Cluster::Write(IStream* pStream) -{ - HeaderWrite(pStream); - TimeCode.Write(pStream); - Position.Write(pStream); - PrevSize.Write(pStream); - BlockGroups.Write(pStream); - return S_OK; -} - -BlockGroup::BlockGroup(DWORD id) - : CID(id) - , BlockDuration(0x9B) - , ReferencePriority(0xFA) - , ReferenceBlock(0xFB) - , ReferenceVirtual(0xFD) - , CodecState(0xA4) -{ -} - -QWORD BlockGroup::Size(bool fWithHeader) -{ - QWORD len = 0; - len += BlockDuration.Size(); - len += ReferencePriority.Size(); - len += ReferenceBlock.Size(); - len += ReferenceVirtual.Size(); - len += CodecState.Size(); - len += Block.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT BlockGroup::Write(IStream* pStream) -{ - HeaderWrite(pStream); - BlockDuration.Write(pStream); - ReferencePriority.Write(pStream); - ReferenceBlock.Write(pStream); - ReferenceVirtual.Write(pStream); - CodecState.Write(pStream); - Block.Write(pStream); - return S_OK; -} - -CBlock::CBlock(DWORD id) - : CID(id) - , TimeCode(0) - , TimeCodeStop(0) -{ -} - -QWORD CBlock::Size(bool fWithHeader) -{ - QWORD len = 0; - len += TrackNumber.Size() + 2 + 1; // TrackNumber + TimeCode + Lacing - if (BlockData.GetCount() > 1) { - len += 1; // nBlockData - POSITION pos = BlockData.GetHeadPosition(); - while (pos) { - CBinary* b = BlockData.GetNext(pos); - if (pos) { - len += b->GetCount() / 255 + 1; - } - } - } - POSITION pos = BlockData.GetHeadPosition(); - while (pos) { - CBinary* b = BlockData.GetNext(pos); - len += b->GetCount(); - } - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CBlock::Write(IStream* pStream) -{ - HeaderWrite(pStream); - TrackNumber.Write(pStream); - short t = (short)TimeCode; - bswap((BYTE*)&t, 2); - pStream->Write(&t, 2, nullptr); - BYTE Lacing = 0; - BYTE n = (BYTE)BlockData.GetCount(); - if (n > 1) { - Lacing |= 2; - } - pStream->Write(&Lacing, 1, nullptr); - if (n > 1) { - pStream->Write(&n, 1, nullptr); - POSITION pos = BlockData.GetHeadPosition(); - while (pos) { - CBinary* b = BlockData.GetNext(pos); - if (pos) { - INT_PTR len = b->GetCount(); - while (len >= 0) { - n = (BYTE)std::min(len, 255); - pStream->Write(&n, 1, nullptr); - len -= 255; - } - } - } - } - POSITION pos = BlockData.GetHeadPosition(); - while (pos) { - CBinary* b = BlockData.GetNext(pos); - pStream->Write(b->GetData(), (ULONG)b->GetCount(), nullptr); - } - return S_OK; -} - -Cue::Cue(DWORD id) - : CID(id) -{ -} - -QWORD Cue::Size(bool fWithHeader) -{ - QWORD len = 0; - len += CuePoints.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Cue::Write(IStream* pStream) -{ - HeaderWrite(pStream); - CuePoints.Write(pStream); - return S_OK; -} - -CuePoint::CuePoint(DWORD id) - : CID(id) - , CueTime(0xB3) -{ -} - -QWORD CuePoint::Size(bool fWithHeader) -{ - QWORD len = 0; - len += CueTime.Size(); - len += CueTrackPositions.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CuePoint::Write(IStream* pStream) -{ - HeaderWrite(pStream); - CueTime.Write(pStream); - CueTrackPositions.Write(pStream); - return S_OK; -} - -CueTrackPosition::CueTrackPosition(DWORD id) - : CID(id) - , CueTrack(0xF7) - , CueClusterPosition(0xF1) - , CueBlockNumber(0x5387) - , CueCodecState(0xEA) -{ -} - -QWORD CueTrackPosition::Size(bool fWithHeader) -{ - QWORD len = 0; - len += CueTrack.Size(); - len += CueClusterPosition.Size(); - len += CueBlockNumber.Size(); - len += CueCodecState.Size(); - // len += CueReferences.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CueTrackPosition::Write(IStream* pStream) -{ - HeaderWrite(pStream); - CueTrack.Write(pStream); - CueClusterPosition.Write(pStream); - CueBlockNumber.Write(pStream); - CueCodecState.Write(pStream); - // CueReferences.Write(pStream); - return S_OK; -} - -Seek::Seek(DWORD id) - : CID(id) -{ -} - -QWORD Seek::Size(bool fWithHeader) -{ - QWORD len = 0; - len += SeekHeads.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Seek::Write(IStream* pStream) -{ - HeaderWrite(pStream); - SeekHeads.Write(pStream); - return S_OK; -} - -SeekID::SeekID(DWORD id) - : CID(id) - , m_cid(0) -{ -} - -QWORD SeekID::Size(bool fWithHeader) -{ - QWORD len = 0; - len += m_cid.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT SeekID::Write(IStream* pStream) -{ - HeaderWrite(pStream); - m_cid.Write(pStream); - return S_OK; -} - -SeekHead::SeekHead(DWORD id) - : CID(id) - , Position(0x53AC) -{ -} - -QWORD SeekHead::Size(bool fWithHeader) -{ - QWORD len = 0; - len += ID.Size(); - len += Position.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT SeekHead::Write(IStream* pStream) -{ - HeaderWrite(pStream); - ID.Write(pStream); - Position.Write(pStream); - return S_OK; -} - -Tags::Tags(DWORD id) - : CID(id) -{ -} - -QWORD Tags::Size(bool fWithHeader) -{ - QWORD len = 0; - // len += .Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Tags::Write(IStream* pStream) -{ - HeaderWrite(pStream); - // .Write(pStream); - return S_OK; -} - -Void::Void(QWORD len, DWORD id) - : CID(id) - , m_len(len) -{ -} - -QWORD Void::Size(bool fWithHeader) -{ - QWORD len = 0; - len += m_len; - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Void::Write(IStream* pStream) -{ - HeaderWrite(pStream); - BYTE buff[64]; - memset(buff, 0x80, sizeof(buff)); - QWORD len = m_len; - for (; len >= sizeof(buff); len -= sizeof(buff)) { - pStream->Write(buff, sizeof(buff), nullptr); - } - - if (len > 0) { - pStream->Write(buff, (ULONG)len, nullptr); - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include +#include "MatroskaFile.h" +#include "../../../DSUtil/DSUtil.h" + +using namespace MatroskaWriter; + +static void bswap(BYTE* s, int len) +{ + for (BYTE* d = s + len - 1; s < d; s++, d--) { + *s ^= *d, *d ^= *s, *s ^= *d; + } +} + +// + +CID::CID(DWORD id) + : m_id(id) +{ +} + +QWORD CID::Size(bool fWithHeader) +{ + return CUInt(0, m_id).Size(false); +} + +HRESULT CID::Write(IStream* pStream) +{ + QWORD len = CID::Size(); + DWORD id = m_id; + bswap((BYTE*)&id, (int)len); + *(BYTE*)&id = ((*(BYTE*)&id) & (1 << (8 - len)) - 1) | (1 << (8 - len)); + return pStream->Write(&id, (ULONG)len, nullptr); +} + +QWORD CID::HeaderSize(QWORD len) +{ + return CID::Size() + CLength(len).Size(); +} + +HRESULT CID::HeaderWrite(IStream* pStream) +{ + CID::Write(pStream); + CLength(Size(false)).Write(pStream); + return S_OK; +} + +QWORD CBinary::Size(bool fWithHeader) +{ + if (IsEmpty()) { + return 0; + } + + QWORD len = 0; + len += GetCount(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CBinary::Write(IStream* pStream) +{ + if (IsEmpty()) { + return S_OK; + } + + HeaderWrite(pStream); + return pStream->Write(GetData(), (ULONG)GetCount(), nullptr); +} + +QWORD CANSI::Size(bool fWithHeader) +{ + if (IsEmpty()) { + return 0; + } + + QWORD len = 0; + len += GetLength(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CANSI::Write(IStream* pStream) +{ + if (IsEmpty()) { + return S_OK; + } + + HeaderWrite(pStream); + return pStream->Write((LPCSTR) * this, GetLength(), nullptr); +} + +QWORD CUTF8::Size(bool fWithHeader) +{ + if (IsEmpty()) { + return 0; + } + + QWORD len = 0; + len += UTF16To8(*this).GetLength(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CUTF8::Write(IStream* pStream) +{ + if (IsEmpty()) { + return S_OK; + } + + HeaderWrite(pStream); + CStringA str = UTF16To8(*this); + return pStream->Write((BYTE*)(LPCSTR)str, str.GetLength(), nullptr); +} + +template +QWORD CSimpleVar::Size(bool fWithHeader) +{ + if (!m_fSet) { + return 0; + } + + QWORD len = 0; + len += sizeof(T); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +template +HRESULT CSimpleVar::Write(IStream* pStream) +{ + if (!m_fSet) { + return S_OK; + } + + HeaderWrite(pStream); + T val = m_val; + bswap((BYTE*)&val, sizeof(T)); + return pStream->Write(&val, sizeof(T), nullptr); +} + +QWORD CUInt::Size(bool fWithHeader) +{ + if (!m_fSet) { + return 0; + } + + QWORD len = 0; + + if (m_val == 0) { + len++; + } else { + for (int i = 8; i > 0; i--) { + if (((0xffi64 << ((i - 1) * 8))&m_val)) { + len += i; + break; + } + } + } + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CUInt::Write(IStream* pStream) +{ + if (!m_fSet) { + return S_OK; + } + + CID::Write(pStream); + CLength l(Size(false)); + l.Write(pStream); + UINT64 val = m_val; + bswap((BYTE*)&val, (int)l); + return pStream->Write(&val, (ULONG)l, nullptr); +} + +QWORD CInt::Size(bool fWithHeader) +{ + if (!m_fSet) { + return 0; + } + + QWORD len = 0; + + if (m_val == 0) { + len++; + } else { + UINT64 val = m_val >= 0 ? m_val : -m_val; + for (int i = 8; i > 0; i--) { + if (((0xffi64 << ((i - 1) * 8))&val)) { + len += i; + if (m_val < 0 && !(m_val & (0x80 << (i - 1)))) { + len++; + } + break; + } + } + } + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CInt::Write(IStream* pStream) +{ + if (!m_fSet) { + return S_OK; + } + + CID::Write(pStream); + CLength l(Size(false)); + l.Write(pStream); + UINT64 val = m_val; + bswap((BYTE*)&val, (int)l); + return pStream->Write(&val, (ULONG)l, nullptr); +} + +QWORD CLength::Size(bool fWithHeader) +{ + if (m_len == 0x00FFFFFFFFFFFFFFi64) { + return 8; + } + + QWORD len = 0; + for (int i = 1; i <= 8; i++) { + if (!(m_len & (~((QWORD(1) << (7 * i)) - 1))) && (m_len & ((QWORD(1) << (7 * i)) - 1)) != ((QWORD(1) << (7 * i)) - 1)) { + len += i; + break; + } + } + return len; +} + +HRESULT CLength::Write(IStream* pStream) +{ + QWORD len = Size(false); + UINT64 val = m_len; + bswap((BYTE*)&val, (int)len); + *(BYTE*)&val = ((*(BYTE*)&val) & (1 << (8 - len)) - 1) | (1 << (8 - len)); + return pStream->Write(&val, (ULONG)len, nullptr); +} + +// + +EBML::EBML(DWORD id) + : CID(id) + , EBMLVersion(0x4286) + , EBMLReadVersion(0x42F7) + , EBMLMaxIDLength(0x42F2) + , EBMLMaxSizeLength(0x42F3) + , DocType(0x4282) + , DocTypeVersion(0x4287) + , DocTypeReadVersion(0x4285) +{ +} + +QWORD EBML::Size(bool fWithHeader) +{ + QWORD len = 0; + len += EBMLVersion.Size(); + len += EBMLReadVersion.Size(); + len += EBMLMaxIDLength.Size(); + len += EBMLMaxSizeLength.Size(); + len += DocType.Size(); + len += DocTypeVersion.Size(); + len += DocTypeReadVersion.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT EBML::Write(IStream* pStream) +{ + HeaderWrite(pStream); + EBMLVersion.Write(pStream); + EBMLReadVersion.Write(pStream); + EBMLMaxIDLength.Write(pStream); + EBMLMaxSizeLength.Write(pStream); + DocType.Write(pStream); + DocTypeVersion.Write(pStream); + DocTypeReadVersion.Write(pStream); + return S_OK; +} + +Info::Info(DWORD id) + : CID(id) + , SegmentUID(0x73A4) + , SegmentFilename(0x7384) + , PrevUID(0x3CB923) + , PrevFilename(0x3C83AB) + , NextUID(0x3EB923) + , NextFilename(0x3E83BB) + , TimeCodeScale(0x2AD7B1, 1000000ui64) + , Duration(0x4489) + , DateUTC(0x4461) + , Title(0x7BA9) + , MuxingApp(0x4D80) + , WritingApp(0x5741) +{ +} + +QWORD Info::Size(bool fWithHeader) +{ + QWORD len = 0; + len += SegmentUID.Size(); + len += PrevUID.Size(); + len += NextUID.Size(); + len += SegmentFilename.Size(); + len += PrevFilename.Size(); + len += NextFilename.Size(); + len += TimeCodeScale.Size(); + len += Duration.Size(); + len += DateUTC.Size(); + len += Title.Size(); + len += MuxingApp.Size(); + len += WritingApp.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Info::Write(IStream* pStream) +{ + HeaderWrite(pStream); + SegmentUID.Write(pStream); + PrevUID.Write(pStream); + NextUID.Write(pStream); + SegmentFilename.Write(pStream); + PrevFilename.Write(pStream); + NextFilename.Write(pStream); + TimeCodeScale.Write(pStream); + Duration.Write(pStream); + DateUTC.Write(pStream); + Title.Write(pStream); + MuxingApp.Write(pStream); + WritingApp.Write(pStream); + return S_OK; +} + +Segment::Segment(DWORD id) + : CID(id) +{ +} + +QWORD Segment::Size(bool fWithHeader) +{ + return 0x00FFFFFFFFFFFFFFi64; + /* + QWORD len = 0; + if (fWithHeader) len += HeaderSize(len); + return len; + */ +} + +HRESULT Segment::Write(IStream* pStream) +{ + HeaderWrite(pStream); + return S_OK; +} + +Track::Track(DWORD id) + : CID(id) +{ +} + +QWORD Track::Size(bool fWithHeader) +{ + QWORD len = 0; + len += TrackEntries.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Track::Write(IStream* pStream) +{ + HeaderWrite(pStream); + TrackEntries.Write(pStream); + return S_OK; +} + +TrackEntry::TrackEntry(DWORD id) + : CID(id) + , TrackNumber(0xD7) + , TrackUID(0x73C5) + , TrackType(0x83) + , FlagEnabled(0xB9) + , FlagDefault(0x88) + , FlagLacing(0x9C) + , MinCache(0x6DE7) + , MaxCache(0x6DF8) + , Name(0x536E) + , Language(0x22B59C) + , CodecID(0x86) + , CodecPrivate(0x63A2) + , CodecName(0x258688) + , CodecSettings(0x3A9697) + , CodecInfoURL(0x3B4040) + , CodecDownloadURL(0x26B240) + , CodecDecodeAll(0xAA) + , TrackOverlay(0x6FAB) + , DefaultDuration(0x23E383) + , v(0xE0) + , a(0xE1) +{ + DescType = NoDesc; +} + +QWORD TrackEntry::Size(bool fWithHeader) +{ + QWORD len = 0; + len += TrackNumber.Size(); + len += TrackUID.Size(); + len += TrackType.Size(); + len += FlagEnabled.Size(); + len += FlagDefault.Size(); + len += FlagLacing.Size(); + len += MinCache.Size(); + len += MaxCache.Size(); + len += Name.Size(); + len += Language.Size(); + len += CodecID.Size(); + len += CodecPrivate.Size(); + len += CodecName.Size(); + len += CodecSettings.Size(); + len += CodecInfoURL.Size(); + len += CodecDownloadURL.Size(); + len += CodecDecodeAll.Size(); + len += TrackOverlay.Size(); + len += DefaultDuration.Size(); + if (DescType == TypeVideo) { + len += v.Size(); + } + if (DescType == TypeAudio) { + len += a.Size(); + } + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT TrackEntry::Write(IStream* pStream) +{ + HeaderWrite(pStream); + TrackNumber.Write(pStream); + TrackUID.Write(pStream); + TrackType.Write(pStream); + FlagEnabled.Write(pStream); + FlagDefault.Write(pStream); + FlagLacing.Write(pStream); + MinCache.Write(pStream); + MaxCache.Write(pStream); + Name.Write(pStream); + Language.Write(pStream); + CodecID.Write(pStream); + CodecPrivate.Write(pStream); + CodecName.Write(pStream); + CodecSettings.Write(pStream); + CodecInfoURL.Write(pStream); + CodecDownloadURL.Write(pStream); + CodecDecodeAll.Write(pStream); + TrackOverlay.Write(pStream); + DefaultDuration.Write(pStream); + if (DescType == TypeVideo) { + v.Write(pStream); + } + if (DescType == TypeAudio) { + a.Write(pStream); + } + return S_OK; +} + +Video::Video(DWORD id) + : CID(id) + , FlagInterlaced(0x9A) + , StereoMode(0x53B8) + , PixelWidth(0xB0) + , PixelHeight(0xBA) + , DisplayWidth(0x54B0) + , DisplayHeight(0x54BA) + , DisplayUnit(0x54B2) + , AspectRatioType(0x54B3) + , ColourSpace(0x2EB524) + , GammaValue(0x2FB523) + , FramePerSec(0x2383E3) +{ +} + +QWORD Video::Size(bool fWithHeader) +{ + QWORD len = 0; + len += FlagInterlaced.Size(); + len += StereoMode.Size(); + len += PixelWidth.Size(); + len += PixelHeight.Size(); + len += DisplayWidth.Size(); + len += DisplayHeight.Size(); + len += DisplayUnit.Size(); + len += AspectRatioType.Size(); + len += ColourSpace.Size(); + len += GammaValue.Size(); + len += FramePerSec.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Video::Write(IStream* pStream) +{ + HeaderWrite(pStream); + FlagInterlaced.Write(pStream); + StereoMode.Write(pStream); + PixelWidth.Write(pStream); + PixelHeight.Write(pStream); + DisplayWidth.Write(pStream); + DisplayHeight.Write(pStream); + DisplayUnit.Write(pStream); + AspectRatioType.Write(pStream); + ColourSpace.Write(pStream); + GammaValue.Write(pStream); + FramePerSec.Write(pStream); + return S_OK; +} + +Audio::Audio(DWORD id) + : CID(id) + , SamplingFrequency(0xB5) + , OutputSamplingFrequency(0x78B5) + , Channels(0x9F) + , ChannelPositions(0x7D7B) + , BitDepth(0x6264) +{ +} + +QWORD Audio::Size(bool fWithHeader) +{ + QWORD len = 0; + len += SamplingFrequency.Size(); + len += OutputSamplingFrequency.Size(); + len += Channels.Size(); + len += ChannelPositions.Size(); + len += BitDepth.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Audio::Write(IStream* pStream) +{ + HeaderWrite(pStream); + SamplingFrequency.Write(pStream); + OutputSamplingFrequency.Write(pStream); + Channels.Write(pStream); + ChannelPositions.Write(pStream); + BitDepth.Write(pStream); + return S_OK; +} + +Cluster::Cluster(DWORD id) + : CID(id) + , TimeCode(0xE7) + , Position(0xA7) + , PrevSize(0xAB) +{ +} + +QWORD Cluster::Size(bool fWithHeader) +{ + QWORD len = 0; + len += TimeCode.Size(); + len += Position.Size(); + len += PrevSize.Size(); + len += BlockGroups.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Cluster::Write(IStream* pStream) +{ + HeaderWrite(pStream); + TimeCode.Write(pStream); + Position.Write(pStream); + PrevSize.Write(pStream); + BlockGroups.Write(pStream); + return S_OK; +} + +BlockGroup::BlockGroup(DWORD id) + : CID(id) + , BlockDuration(0x9B) + , ReferencePriority(0xFA) + , ReferenceBlock(0xFB) + , ReferenceVirtual(0xFD) + , CodecState(0xA4) +{ +} + +QWORD BlockGroup::Size(bool fWithHeader) +{ + QWORD len = 0; + len += BlockDuration.Size(); + len += ReferencePriority.Size(); + len += ReferenceBlock.Size(); + len += ReferenceVirtual.Size(); + len += CodecState.Size(); + len += Block.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT BlockGroup::Write(IStream* pStream) +{ + HeaderWrite(pStream); + BlockDuration.Write(pStream); + ReferencePriority.Write(pStream); + ReferenceBlock.Write(pStream); + ReferenceVirtual.Write(pStream); + CodecState.Write(pStream); + Block.Write(pStream); + return S_OK; +} + +CBlock::CBlock(DWORD id) + : CID(id) + , TimeCode(0) + , TimeCodeStop(0) +{ +} + +QWORD CBlock::Size(bool fWithHeader) +{ + QWORD len = 0; + len += TrackNumber.Size() + 2 + 1; // TrackNumber + TimeCode + Lacing + if (BlockData.GetCount() > 1) { + len += 1; // nBlockData + POSITION pos = BlockData.GetHeadPosition(); + while (pos) { + CBinary* b = BlockData.GetNext(pos); + if (pos) { + len += b->GetCount() / 255 + 1; + } + } + } + POSITION pos = BlockData.GetHeadPosition(); + while (pos) { + CBinary* b = BlockData.GetNext(pos); + len += b->GetCount(); + } + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CBlock::Write(IStream* pStream) +{ + HeaderWrite(pStream); + TrackNumber.Write(pStream); + short t = (short)TimeCode; + bswap((BYTE*)&t, 2); + pStream->Write(&t, 2, nullptr); + BYTE Lacing = 0; + BYTE n = (BYTE)BlockData.GetCount(); + if (n > 1) { + Lacing |= 2; + } + pStream->Write(&Lacing, 1, nullptr); + if (n > 1) { + pStream->Write(&n, 1, nullptr); + POSITION pos = BlockData.GetHeadPosition(); + while (pos) { + CBinary* b = BlockData.GetNext(pos); + if (pos) { + INT_PTR len = b->GetCount(); + while (len >= 0) { + n = (BYTE)std::min(len, 255); + pStream->Write(&n, 1, nullptr); + len -= 255; + } + } + } + } + POSITION pos = BlockData.GetHeadPosition(); + while (pos) { + CBinary* b = BlockData.GetNext(pos); + pStream->Write(b->GetData(), (ULONG)b->GetCount(), nullptr); + } + return S_OK; +} + +Cue::Cue(DWORD id) + : CID(id) +{ +} + +QWORD Cue::Size(bool fWithHeader) +{ + QWORD len = 0; + len += CuePoints.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Cue::Write(IStream* pStream) +{ + HeaderWrite(pStream); + CuePoints.Write(pStream); + return S_OK; +} + +CuePoint::CuePoint(DWORD id) + : CID(id) + , CueTime(0xB3) +{ +} + +QWORD CuePoint::Size(bool fWithHeader) +{ + QWORD len = 0; + len += CueTime.Size(); + len += CueTrackPositions.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CuePoint::Write(IStream* pStream) +{ + HeaderWrite(pStream); + CueTime.Write(pStream); + CueTrackPositions.Write(pStream); + return S_OK; +} + +CueTrackPosition::CueTrackPosition(DWORD id) + : CID(id) + , CueTrack(0xF7) + , CueClusterPosition(0xF1) + , CueBlockNumber(0x5387) + , CueCodecState(0xEA) +{ +} + +QWORD CueTrackPosition::Size(bool fWithHeader) +{ + QWORD len = 0; + len += CueTrack.Size(); + len += CueClusterPosition.Size(); + len += CueBlockNumber.Size(); + len += CueCodecState.Size(); + // len += CueReferences.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CueTrackPosition::Write(IStream* pStream) +{ + HeaderWrite(pStream); + CueTrack.Write(pStream); + CueClusterPosition.Write(pStream); + CueBlockNumber.Write(pStream); + CueCodecState.Write(pStream); + // CueReferences.Write(pStream); + return S_OK; +} + +Seek::Seek(DWORD id) + : CID(id) +{ +} + +QWORD Seek::Size(bool fWithHeader) +{ + QWORD len = 0; + len += SeekHeads.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Seek::Write(IStream* pStream) +{ + HeaderWrite(pStream); + SeekHeads.Write(pStream); + return S_OK; +} + +SeekID::SeekID(DWORD id) + : CID(id) + , m_cid(0) +{ +} + +QWORD SeekID::Size(bool fWithHeader) +{ + QWORD len = 0; + len += m_cid.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT SeekID::Write(IStream* pStream) +{ + HeaderWrite(pStream); + m_cid.Write(pStream); + return S_OK; +} + +SeekHead::SeekHead(DWORD id) + : CID(id) + , Position(0x53AC) +{ +} + +QWORD SeekHead::Size(bool fWithHeader) +{ + QWORD len = 0; + len += ID.Size(); + len += Position.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT SeekHead::Write(IStream* pStream) +{ + HeaderWrite(pStream); + ID.Write(pStream); + Position.Write(pStream); + return S_OK; +} + +Tags::Tags(DWORD id) + : CID(id) +{ +} + +QWORD Tags::Size(bool fWithHeader) +{ + QWORD len = 0; + // len += .Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Tags::Write(IStream* pStream) +{ + HeaderWrite(pStream); + // .Write(pStream); + return S_OK; +} + +Void::Void(QWORD len, DWORD id) + : CID(id) + , m_len(len) +{ +} + +QWORD Void::Size(bool fWithHeader) +{ + QWORD len = 0; + len += m_len; + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Void::Write(IStream* pStream) +{ + HeaderWrite(pStream); + BYTE buff[64]; + memset(buff, 0x80, sizeof(buff)); + QWORD len = m_len; + for (; len >= sizeof(buff); len -= sizeof(buff)) { + pStream->Write(buff, sizeof(buff), nullptr); + } + + if (len > 0) { + pStream->Write(buff, (ULONG)len, nullptr); + } + + return S_OK; +} diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaFile.h b/src/filters/muxer/MatroskaMuxer/MatroskaFile.h index 5f2f183241e..b8faf06c39f 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaFile.h +++ b/src/filters/muxer/MatroskaMuxer/MatroskaFile.h @@ -1,427 +1,427 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include -#include - -namespace MatroskaWriter -{ - class CID - { - protected: - DWORD m_id; - QWORD HeaderSize(QWORD len); - HRESULT HeaderWrite(IStream* pStream); - - public: - CID(DWORD id); - DWORD GetID() const { - return m_id; - } - virtual QWORD Size(bool fWithHeader = true); - virtual HRESULT Write(IStream* pStream); - }; - - class CLength : public CID - { - UINT64 m_len; - public: - CLength(UINT64 len = 0) : CID(0), m_len(len) {} - operator UINT64() { - return m_len; - } - QWORD Size(bool fWithHeader = false); - HRESULT Write(IStream* pStream); - }; - - class CBinary : public CAtlArray, public CID - { - public: - CBinary(DWORD id) : CID(id) {} - CBinary& operator = (const CBinary& b) { - Copy(b); - return *this; - } - operator BYTE* () { - return (BYTE*)GetData(); - } - CBinary& Set(CStringA str) { - SetCount(str.GetLength() + 1); - strcpy_s((char*)GetData(), str.GetLength() + 1, str); - return *this; - } - //CBinary& Set(CStringA str) {SetCount(str.GetLength()); memcpy((char*)GetData(), str, str.GetLength()); return *this;} - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CANSI : public CStringA, public CID - { - public: - CANSI(DWORD id) : CID(id) {} - CANSI& Set(CStringA str) { - CStringA::operator = (str); - return *this; - } - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CUTF8 : public CStringW, public CID - { - public: - CUTF8(DWORD id) : CID(id) {} - CUTF8& Set(CStringW str) { - CStringW::operator = (str); - return *this; - } - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - template - class CSimpleVar : public CID - { - protected: - T m_val; - bool m_fSet; - public: - explicit CSimpleVar(DWORD id, T val = 0) : CID(id), m_val(val) { - m_fSet = !!val; - } - operator T() { - return m_val; - } - BASE& Set(T val) { - m_val = val; - m_fSet = true; - return (*(BASE*)this); - } - void UnSet() { - m_fSet = false; - } - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CUInt : public CSimpleVar - { - public: - explicit CUInt(DWORD id, UINT64 val = 0) : CSimpleVar(id, val) {} - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CInt : public CSimpleVar - { - public: - explicit CInt(DWORD id, INT64 val = 0) : CSimpleVar(id, val) {} - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CByte : public CSimpleVar - { - public: - explicit CByte(DWORD id, BYTE val = 0) : CSimpleVar(id, val) {} - }; - - class CShort : public CSimpleVar - { - public: - explicit CShort(DWORD id, short val = 0) : CSimpleVar(id, val) {} - }; - - class CFloat : public CSimpleVar - { - public: - explicit CFloat(DWORD id, float val = 0) : CSimpleVar(id, val) {} - }; - - template - class CNode : public CAutoPtrList - { - public: - QWORD Size(bool fWithHeader = true) { - QWORD len = 0; - POSITION pos = CAutoPtrList::GetHeadPosition(); - while (pos) { - len += CAutoPtrList::GetNext(pos)->Size(fWithHeader); - } - return len; - } - HRESULT Write(IStream* pStream) { - POSITION pos = CAutoPtrList::GetHeadPosition(); - while (pos) { - HRESULT hr; - if (FAILED(hr = CAutoPtrList::GetNext(pos)->Write(pStream))) { - return hr; - } - } - return S_OK; - } - }; - - class EBML : public CID - { - public: - CUInt EBMLVersion, EBMLReadVersion; - CUInt EBMLMaxIDLength, EBMLMaxSizeLength; - CANSI DocType; - CUInt DocTypeVersion, DocTypeReadVersion; - - EBML(DWORD id = 0x1A45DFA3); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Info : public CID - { - public: - CBinary SegmentUID, PrevUID, NextUID; - CUTF8 SegmentFilename, PrevFilename, NextFilename; - CUInt TimeCodeScale; // [ns], default: 1.000.000 - CFloat Duration; - CInt DateUTC; - CUTF8 Title, MuxingApp, WritingApp; - - Info(DWORD id = 0x1549A966); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Video : public CID - { - public: - CUInt FlagInterlaced, StereoMode; - CUInt PixelWidth, PixelHeight, DisplayWidth, DisplayHeight, DisplayUnit; - CUInt AspectRatioType; - CUInt ColourSpace; - CFloat GammaValue; - CFloat FramePerSec; - - Video(DWORD id = 0xE0); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Audio : public CID - { - public: - CFloat SamplingFrequency; - CFloat OutputSamplingFrequency; - CUInt Channels; - CBinary ChannelPositions; - CUInt BitDepth; - - Audio(DWORD id = 0xE1); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class TrackEntry : public CID - { - public: - enum { - TypeVideo = 1, - TypeAudio = 2, - TypeComplex = 3, - TypeLogo = 0x10, - TypeSubtitle = 0x11, - TypeControl = 0x20 - }; - CUInt TrackNumber, TrackUID, TrackType; - CUInt FlagEnabled, FlagDefault, FlagLacing; - CUInt MinCache, MaxCache; - CUTF8 Name; - CANSI Language; - CBinary CodecID; - CBinary CodecPrivate; - CUTF8 CodecName; - CUTF8 CodecSettings; - CANSI CodecInfoURL; - CANSI CodecDownloadURL; - CUInt CodecDecodeAll; - CUInt TrackOverlay; - CUInt DefaultDuration; - enum { NoDesc = 0, DescVideo = 1, DescAudio = 2 }; - int DescType; - Video v; - Audio a; - - TrackEntry(DWORD id = 0xAE); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Track : public CID - { - public: - CNode TrackEntries; - - Track(DWORD id = 0x1654AE6B); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CBlock : public CID - { - public: - CLength TrackNumber; - REFERENCE_TIME TimeCode, TimeCodeStop; - CNode BlockData; - - CBlock(DWORD id = 0xA1); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class BlockGroup : public CID - { - public: - CUInt BlockDuration; - CUInt ReferencePriority; - CInt ReferenceBlock; - CInt ReferenceVirtual; - CBinary CodecState; - CBlock Block; - //CNode TimeSlices; - - BlockGroup(DWORD id = 0xA0); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Cluster : public CID - { - public: - CUInt TimeCode, Position, PrevSize; - CNode BlockGroups; - - Cluster(DWORD id = 0x1F43B675); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - /*class CueReference : public CID - { - public: - CUInt CueRefTime, CueRefCluster, CueRefNumber, CueRefCodecState; - - CueReference(DWORD id = 0xDB); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - };*/ - - class CueTrackPosition : public CID - { - public: - CUInt CueTrack, CueClusterPosition, CueBlockNumber, CueCodecState; - // CNode CueReferences; - - CueTrackPosition(DWORD id = 0xB7); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CuePoint : public CID - { - public: - CUInt CueTime; - CNode CueTrackPositions; - - CuePoint(DWORD id = 0xBB); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Cue : public CID - { - public: - CNode CuePoints; - - Cue(DWORD id = 0x1C53BB6B); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class SeekID : public CID - { - CID m_cid; - public: - SeekID(DWORD id = 0x53AB); - void Set(DWORD id) { - m_cid = id; - } - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class SeekHead : public CID - { - public: - SeekID ID; - CUInt Position; - - SeekHead(DWORD id = 0x4DBB); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Seek : public CID - { - public: - CNode SeekHeads; - - Seek(DWORD id = 0x114D9B74); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Segment : public CID - { - public: - Segment(DWORD id = 0x18538067); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Tags : public CID - { - public: - // TODO - - Tags(DWORD id = 0x1254C367); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Void : public CID - { - QWORD m_len; - public: - Void(QWORD len, DWORD id = 0xEC); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include +#include + +namespace MatroskaWriter +{ + class CID + { + protected: + DWORD m_id; + QWORD HeaderSize(QWORD len); + HRESULT HeaderWrite(IStream* pStream); + + public: + CID(DWORD id); + DWORD GetID() const { + return m_id; + } + virtual QWORD Size(bool fWithHeader = true); + virtual HRESULT Write(IStream* pStream); + }; + + class CLength : public CID + { + UINT64 m_len; + public: + CLength(UINT64 len = 0) : CID(0), m_len(len) {} + operator UINT64() { + return m_len; + } + QWORD Size(bool fWithHeader = false); + HRESULT Write(IStream* pStream); + }; + + class CBinary : public CAtlArray, public CID + { + public: + CBinary(DWORD id) : CID(id) {} + CBinary& operator = (const CBinary& b) { + Copy(b); + return *this; + } + operator BYTE* () { + return (BYTE*)GetData(); + } + CBinary& Set(CStringA str) { + SetCount(str.GetLength() + 1); + strcpy_s((char*)GetData(), str.GetLength() + 1, str); + return *this; + } + //CBinary& Set(CStringA str) {SetCount(str.GetLength()); memcpy((char*)GetData(), str, str.GetLength()); return *this;} + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CANSI : public CStringA, public CID + { + public: + CANSI(DWORD id) : CID(id) {} + CANSI& Set(CStringA str) { + CStringA::operator = (str); + return *this; + } + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CUTF8 : public CStringW, public CID + { + public: + CUTF8(DWORD id) : CID(id) {} + CUTF8& Set(CStringW str) { + CStringW::operator = (str); + return *this; + } + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + template + class CSimpleVar : public CID + { + protected: + T m_val; + bool m_fSet; + public: + explicit CSimpleVar(DWORD id, T val = 0) : CID(id), m_val(val) { + m_fSet = !!val; + } + operator T() { + return m_val; + } + BASE& Set(T val) { + m_val = val; + m_fSet = true; + return (*(BASE*)this); + } + void UnSet() { + m_fSet = false; + } + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CUInt : public CSimpleVar + { + public: + explicit CUInt(DWORD id, UINT64 val = 0) : CSimpleVar(id, val) {} + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CInt : public CSimpleVar + { + public: + explicit CInt(DWORD id, INT64 val = 0) : CSimpleVar(id, val) {} + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CByte : public CSimpleVar + { + public: + explicit CByte(DWORD id, BYTE val = 0) : CSimpleVar(id, val) {} + }; + + class CShort : public CSimpleVar + { + public: + explicit CShort(DWORD id, short val = 0) : CSimpleVar(id, val) {} + }; + + class CFloat : public CSimpleVar + { + public: + explicit CFloat(DWORD id, float val = 0) : CSimpleVar(id, val) {} + }; + + template + class CNode : public CAutoPtrList + { + public: + QWORD Size(bool fWithHeader = true) { + QWORD len = 0; + POSITION pos = CAutoPtrList::GetHeadPosition(); + while (pos) { + len += CAutoPtrList::GetNext(pos)->Size(fWithHeader); + } + return len; + } + HRESULT Write(IStream* pStream) { + POSITION pos = CAutoPtrList::GetHeadPosition(); + while (pos) { + HRESULT hr; + if (FAILED(hr = CAutoPtrList::GetNext(pos)->Write(pStream))) { + return hr; + } + } + return S_OK; + } + }; + + class EBML : public CID + { + public: + CUInt EBMLVersion, EBMLReadVersion; + CUInt EBMLMaxIDLength, EBMLMaxSizeLength; + CANSI DocType; + CUInt DocTypeVersion, DocTypeReadVersion; + + EBML(DWORD id = 0x1A45DFA3); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Info : public CID + { + public: + CBinary SegmentUID, PrevUID, NextUID; + CUTF8 SegmentFilename, PrevFilename, NextFilename; + CUInt TimeCodeScale; // [ns], default: 1.000.000 + CFloat Duration; + CInt DateUTC; + CUTF8 Title, MuxingApp, WritingApp; + + Info(DWORD id = 0x1549A966); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Video : public CID + { + public: + CUInt FlagInterlaced, StereoMode; + CUInt PixelWidth, PixelHeight, DisplayWidth, DisplayHeight, DisplayUnit; + CUInt AspectRatioType; + CUInt ColourSpace; + CFloat GammaValue; + CFloat FramePerSec; + + Video(DWORD id = 0xE0); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Audio : public CID + { + public: + CFloat SamplingFrequency; + CFloat OutputSamplingFrequency; + CUInt Channels; + CBinary ChannelPositions; + CUInt BitDepth; + + Audio(DWORD id = 0xE1); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class TrackEntry : public CID + { + public: + enum { + TypeVideo = 1, + TypeAudio = 2, + TypeComplex = 3, + TypeLogo = 0x10, + TypeSubtitle = 0x11, + TypeControl = 0x20 + }; + CUInt TrackNumber, TrackUID, TrackType; + CUInt FlagEnabled, FlagDefault, FlagLacing; + CUInt MinCache, MaxCache; + CUTF8 Name; + CANSI Language; + CBinary CodecID; + CBinary CodecPrivate; + CUTF8 CodecName; + CUTF8 CodecSettings; + CANSI CodecInfoURL; + CANSI CodecDownloadURL; + CUInt CodecDecodeAll; + CUInt TrackOverlay; + CUInt DefaultDuration; + enum { NoDesc = 0, DescVideo = 1, DescAudio = 2 }; + int DescType; + Video v; + Audio a; + + TrackEntry(DWORD id = 0xAE); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Track : public CID + { + public: + CNode TrackEntries; + + Track(DWORD id = 0x1654AE6B); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CBlock : public CID + { + public: + CLength TrackNumber; + REFERENCE_TIME TimeCode, TimeCodeStop; + CNode BlockData; + + CBlock(DWORD id = 0xA1); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class BlockGroup : public CID + { + public: + CUInt BlockDuration; + CUInt ReferencePriority; + CInt ReferenceBlock; + CInt ReferenceVirtual; + CBinary CodecState; + CBlock Block; + //CNode TimeSlices; + + BlockGroup(DWORD id = 0xA0); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Cluster : public CID + { + public: + CUInt TimeCode, Position, PrevSize; + CNode BlockGroups; + + Cluster(DWORD id = 0x1F43B675); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + /*class CueReference : public CID + { + public: + CUInt CueRefTime, CueRefCluster, CueRefNumber, CueRefCodecState; + + CueReference(DWORD id = 0xDB); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + };*/ + + class CueTrackPosition : public CID + { + public: + CUInt CueTrack, CueClusterPosition, CueBlockNumber, CueCodecState; + // CNode CueReferences; + + CueTrackPosition(DWORD id = 0xB7); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CuePoint : public CID + { + public: + CUInt CueTime; + CNode CueTrackPositions; + + CuePoint(DWORD id = 0xBB); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Cue : public CID + { + public: + CNode CuePoints; + + Cue(DWORD id = 0x1C53BB6B); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class SeekID : public CID + { + CID m_cid; + public: + SeekID(DWORD id = 0x53AB); + void Set(DWORD id) { + m_cid = id; + } + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class SeekHead : public CID + { + public: + SeekID ID; + CUInt Position; + + SeekHead(DWORD id = 0x4DBB); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Seek : public CID + { + public: + CNode SeekHeads; + + Seek(DWORD id = 0x114D9B74); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Segment : public CID + { + public: + Segment(DWORD id = 0x18538067); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Tags : public CID + { + public: + // TODO + + Tags(DWORD id = 0x1254C367); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Void : public CID + { + QWORD m_len; + public: + Void(QWORD len, DWORD id = 0xEC); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; +} diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.cpp b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.cpp index 81bd5e803a5..ddd726bf32d 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.cpp +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.cpp @@ -1,1419 +1,1419 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "MatroskaMuxer.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -using namespace MatroskaWriter; - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_Matroska} -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, nullptr, 0, nullptr}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CMatroskaMuxerFilter), MatroskaMuxerName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CMatroskaMuxerFilter -// - -CMatroskaMuxerFilter::CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseFilter(NAME("CMatroskaMuxerFilter"), pUnk, this, __uuidof(this)) - , m_rtCurrent(0) - , m_fNegative(true) - , m_fPositive(false) -{ - if (phr) { - *phr = S_OK; - } - - m_pOutput.Attach(DEBUG_NEW CMatroskaMuxerOutputPin(NAME("CMatroskaMuxerOutputPin"), this, this, phr)); - - AddInput(); - - srand(clock()); -} - -CMatroskaMuxerFilter::~CMatroskaMuxerFilter() -{ - CAutoLock cAutoLock(this); -} - -STDMETHODIMP CMatroskaMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - return - // QI(IAMFilterMiscFlags) - QI(IMediaSeeking) - QI(IMatroskaMuxer) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -UINT CMatroskaMuxerFilter::GetTrackNumber(const CBasePin* pPin) -{ - UINT nTrackNumber = 0; - - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - nTrackNumber++; - if (m_pInputs.GetNext(pos) == pPin) { - return nTrackNumber; - } - } - - return 0; -} - -void CMatroskaMuxerFilter::AddInput() -{ - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CBasePin* pPin = m_pInputs.GetNext(pos); - if (!pPin->IsConnected()) { - return; - } - } - - CStringW name; - name.Format(L"Track %u", m_pInputs.GetCount() + 1); - - HRESULT hr; - CAutoPtr pPin(DEBUG_NEW CMatroskaMuxerInputPin(name, this, this, &hr)); - m_pInputs.AddTail(pPin); -} - -int CMatroskaMuxerFilter::GetPinCount() -{ - return (int)m_pInputs.GetCount() + (m_pOutput ? 1 : 0); -} - -CBasePin* CMatroskaMuxerFilter::GetPin(int n) -{ - CAutoLock cAutoLock(this); - - if (n >= 0 && n < (int)m_pInputs.GetCount()) { - if (POSITION pos = m_pInputs.FindIndex(n)) { - return m_pInputs.GetAt(pos); - } - } - - if (n == (int)m_pInputs.GetCount() && m_pOutput) { - return m_pOutput; - } - - return nullptr; -} - -STDMETHODIMP CMatroskaMuxerFilter::Stop() -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (FAILED(hr = __super::Stop())) { - return hr; - } - - CallWorker(CMD_EXIT); - - return hr; -} - -STDMETHODIMP CMatroskaMuxerFilter::Pause() -{ - CAutoLock cAutoLock(this); - - FILTER_STATE fs = m_State; - - HRESULT hr; - - if (FAILED(hr = __super::Pause())) { - return hr; - } - - if (fs == State_Stopped && m_pOutput) { - CAMThread::Create(); - CallWorker(CMD_RUN); - } - - return hr; -} - -STDMETHODIMP CMatroskaMuxerFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (FAILED(hr = __super::Run(tStart))) { - return hr; - } - - return hr; -} - -// IAMFilterMiscFlags - -STDMETHODIMP_(ULONG) CMatroskaMuxerFilter::GetMiscFlags() -{ - return AM_FILTER_MISC_FLAGS_IS_RENDERER; -} - -// IMediaSeeking - -STDMETHODIMP CMatroskaMuxerFilter::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanGetDuration | AM_SEEKING_CanGetCurrentPos; - - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerFilter::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - if (*pCapabilities == 0) { - return S_OK; - } - DWORD caps; - GetCapabilities(&caps); - caps &= *pCapabilities; - return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE; -} - -STDMETHODIMP CMatroskaMuxerFilter::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CMatroskaMuxerFilter::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CMatroskaMuxerFilter::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CMatroskaMuxerFilter::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetDuration(LONGLONG* pDuration) -{ - CheckPointer(pDuration, E_POINTER); - *pDuration = 0; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - REFERENCE_TIME rt = m_pInputs.GetNext(pos)->m_rtDur; - if (rt > *pDuration) { - *pDuration = rt; - } - } - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetStopPosition(LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent) -{ - CheckPointer(pCurrent, E_POINTER); - *pCurrent = m_rtCurrent; - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::SetRate(double dRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetRate(double* pdRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetPreroll(LONGLONG* pllPreroll) -{ - return E_NOTIMPL; -} - -// IMatroskaMuxer - -STDMETHODIMP CMatroskaMuxerFilter::CorrectTimeOffset(bool fNegative, bool fPositive) -{ - m_fNegative = fNegative; - m_fPositive = fPositive; - return S_OK; -} - -// - -ULONGLONG GetStreamPosition(IStream* pStream) -{ - ULARGE_INTEGER pos = {0, 0}; - pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos); - return pos.QuadPart; -} - -ULONGLONG SetStreamPosition(IStream* pStream, ULONGLONG seekpos) -{ - LARGE_INTEGER pos; - pos.QuadPart = seekpos; - ULARGE_INTEGER posnew; - posnew.QuadPart = GetStreamPosition(pStream); - pStream->Seek(pos, STREAM_SEEK_SET, &posnew); - return posnew.QuadPart; -} - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CMatroskaMuxerFilter::ThreadProc() -{ - CComQIPtr pStream; - - if (!m_pOutput || !(pStream = m_pOutput->GetConnected())) { - for (;;) { - DWORD cmd = GetRequest(); - if (cmd == CMD_EXIT) { - CAMThread::m_hThread = nullptr; - } - Reply(S_OK); - if (cmd == CMD_EXIT) { - return 0; - } - } - } - - REFERENCE_TIME rtDur = 0; - GetDuration(&rtDur); - - SetStreamPosition(pStream, 0); - - ULARGE_INTEGER uli = {0}; - pStream->SetSize(uli); - - EBML hdr; - hdr.DocType.Set("matroska"); - hdr.DocTypeVersion.Set(1); - hdr.DocTypeReadVersion.Set(1); - hdr.Write(pStream); - - Segment().Write(pStream); - ULONGLONG segpos = GetStreamPosition(pStream); - - // TODO - QWORD voidlen = 100; - if (rtDur > 0) { - voidlen += QWORD(1.0 * rtDur / MAXCLUSTERTIME / 10000 + 0.5) * 20; - } else { - voidlen += QWORD(1.0 * 1000 * 60 * 60 * 24 / MAXCLUSTERTIME + 0.5) * 20; // when no duration is known, allocate for 24 hours (~340k) - } - ULONGLONG voidpos = GetStreamPosition(pStream); - { - Void v(voidlen); - voidlen = v.Size(); - v.Write(pStream); - } - - // Meta Seek - - Seek seek; - CAutoPtr sh; - - // Segment Info - - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(0x1549A966); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - ULONGLONG infopos = GetStreamPosition(pStream); - Info info; - info.MuxingApp.Set(L"DirectShow Matroska Muxer"); - info.TimeCodeScale.Set(1000000); - info.Duration.Set((float)rtDur / 10000); - struct tm _2001 = {0, 0, 0, 1, 0, 101, 0, 0, 1}; - info.DateUTC.Set((_time64(nullptr) - _mktime64(&_2001)) * 1000000000); - info.Write(pStream); - - // Tracks - - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(0x1654AE6B); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - UINT64 TrackNumber = 0; - /* - CNode Tracks; - CAutoPtr pT(DEBUG_NEW Track()); - POSITION pos = m_pInputs.GetHeadPosition(); - for (int i = 1; pos; i++) - { - CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos); - if (!pPin->IsConnected()) continue; - - CAutoPtr pTE(DEBUG_NEW TrackEntry()); - *pTE = *pPin->GetTrackEntry(); - if (TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo) - TrackNumber = pTE->TrackNumber; - pT->TrackEntries.AddTail(pTE); - } - Tracks.AddTail(pT); - Tracks.Write(pStream); - - if (TrackNumber == 0) TrackNumber = 1; - */ - bool fTracksWritten = false; - - // - - Cluster c; - c.TimeCode.Set(0); - - bool fFirstBlock = true; - INT64 firstTimeCode = 0; - - CAtlList pActivePins; - - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos); - if (pPin->IsConnected()) { - pActivePins.AddTail(pPin); - } - } - - for (;;) { - DWORD cmd = GetRequest(); - - switch (cmd) { - default: - case CMD_EXIT: - CAMThread::m_hThread = nullptr; - Reply(S_OK); - return 0; - - case CMD_RUN: - Reply(S_OK); - - Cue cue; - ULONGLONG lastcueclusterpos = (ULONGLONG) - 1; - INT64 lastcuetimecode = (INT64) - 1; - UINT64 nBlocksInCueTrack = 0; - - while (!CheckRequest(nullptr)) { - if (m_State == State_Paused) { - Sleep(10); - continue; - } - - int nPinsGotSomething = 0, nPinsNeeded = 0; - CMatroskaMuxerInputPin* pPin = nullptr; - REFERENCE_TIME rtMin = _I64_MAX; - - pos = pActivePins.GetHeadPosition(); - while (pos) { - CMatroskaMuxerInputPin* pTmp = pActivePins.GetNext(pos); - - CAutoLock cAutoLock(&pTmp->m_csQueue); - - if (pTmp->m_blocks.IsEmpty() && pTmp->m_fEndOfStreamReceived) { - pActivePins.RemoveAt(pActivePins.Find(pTmp)); - continue; - } - - if (pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle) { - nPinsNeeded++; - } - - if (!pTmp->m_blocks.IsEmpty()) { - if (pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle) { - nPinsGotSomething++; - } - - if (!pTmp->m_blocks.IsEmpty()) { - REFERENCE_TIME rt = pTmp->m_blocks.GetHead()->Block.TimeCode; - if (rt < rtMin) { - rtMin = rt; - pPin = pTmp; - } - } - } - } - - if (pActivePins.IsEmpty()) { - break; - } - - if (!pPin || nPinsNeeded > nPinsGotSomething || !pPin && nPinsGotSomething == 0) { - Sleep(1); - continue; - } - - if (!fTracksWritten) { - CNode Tracks; - CAutoPtr pT(DEBUG_NEW Track()); - pos = pActivePins.GetHeadPosition(); - for (int i = 1; pos; i++) { - CMatroskaMuxerInputPin* pActivePin = pActivePins.GetNext(pos); - - CAutoPtr pTE(DEBUG_NEW TrackEntry()); - *pTE = *pActivePin->GetTrackEntry(); - if (TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo) { - TrackNumber = pTE->TrackNumber; - } - pT->TrackEntries.AddTail(pTE); - } - Tracks.AddTail(pT); - Tracks.Write(pStream); - - if (TrackNumber == 0) { - TrackNumber = 1; - } - - fTracksWritten = true; - } - - ASSERT(pPin); - - CAutoPtr b; - - { - CAutoLock cAutoLock(&pPin->m_csQueue); - b.Attach(pPin->m_blocks.RemoveHead().Detach()); - } - - if (b) { - if (fFirstBlock) { - if (b->Block.TimeCode < 0 && m_fNegative || b->Block.TimeCode > 0 && m_fPositive) { - firstTimeCode = b->Block.TimeCode; - } - fFirstBlock = false; - } - - b->Block.TimeCode -= firstTimeCode; - b->Block.TimeCodeStop -= firstTimeCode; - - /* - TRACE(_T("Muxing (%d): %I64d-%I64d dur=%I64d (c=%d, co=%dms), cnt=%d, ref=%d\n"), - GetTrackNumber(pPin), - (INT64)b->Block.TimeCode, (INT64)b->Block.TimeCodeStop, (UINT64)b->BlockDuration, - (int)((b->Block.TimeCode)/MAXCLUSTERTIME), (int)(b->Block.TimeCode%MAXCLUSTERTIME), - b->Block.BlockData.GetCount(), (int)b->ReferenceBlock); - */ - if (b->Block.TimeCode < SHRT_MIN /*0*/) { - ASSERT(0); - continue; - } - - while ((INT64)(c.TimeCode + MAXCLUSTERTIME) < b->Block.TimeCode) { - if (!c.BlockGroups.IsEmpty()) { - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(c.GetID()/*0x1F43B675*/); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - c.Write(pStream); // TODO: write blocks - } - - c.TimeCode.Set(c.TimeCode + MAXCLUSTERTIME); - c.BlockGroups.RemoveAll(); - nBlocksInCueTrack = 0; - } - - if (b->Block.TrackNumber == TrackNumber) { - nBlocksInCueTrack++; - } - - if (b->ReferenceBlock == 0 && b->Block.TrackNumber == TrackNumber) { - ULONGLONG clusterpos = GetStreamPosition(pStream) - segpos; - if (lastcueclusterpos != clusterpos || lastcuetimecode + 1000 < b->Block.TimeCode) { - CAutoPtr ctp(DEBUG_NEW CueTrackPosition()); - ctp->CueTrack.Set(b->Block.TrackNumber); - ctp->CueClusterPosition.Set(clusterpos); - if (!c.BlockGroups.IsEmpty()) { - ctp->CueBlockNumber.Set(nBlocksInCueTrack); - } - CAutoPtr cp(DEBUG_NEW CuePoint()); - cp->CueTime.Set(b->Block.TimeCode); - cp->CueTrackPositions.AddTail(ctp); - cue.CuePoints.AddTail(cp); - lastcueclusterpos = clusterpos; - lastcuetimecode = b->Block.TimeCode; - } - } - - info.Duration.Set(std::max(info.Duration, (float)b->Block.TimeCodeStop)); - - m_rtCurrent = b->Block.TimeCode * 10000; - - b->Block.TimeCode -= c.TimeCode; - c.BlockGroups.AddTail(b); - } - } - - if (!c.BlockGroups.IsEmpty()) { - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(c.GetID()/*0x1F43B675*/); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - c.Write(pStream); - } - - if (!cue.CuePoints.IsEmpty()) { - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(cue.GetID()/*0x1C53BB6B*/); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - cue.Write(pStream); - } - - { - Tags tags; - - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(tags.GetID()); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - tags.Write(pStream); - } - - SetStreamPosition(pStream, voidpos); - QWORD len = voidlen - seek.Size(); - ASSERT(len >= 0 && len != 1); - seek.Write(pStream); - - if (len == 0) { - // nothing to do - } else if (len >= 2) { - for (QWORD i = 0; i < 8; i++) { - if (len >= (QWORD(1) << i * 7) - 2 && len <= (QWORD(1) << (i + 1) * 7) - 2) { - Void(len - 2 - i).Write(pStream); - break; - } - } - } - - if (abs(m_rtCurrent - (REFERENCE_TIME)info.Duration * 10000) > 10000000i64) { - info.Duration.Set((float)m_rtCurrent / 10000 + 1); - } - - SetStreamPosition(pStream, infopos); - info.Write(pStream); - - // TODO: write some tags - - m_pOutput->DeliverEndOfStream(); - - break; - } - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -// -// CMatroskaMuxerInputPin -// - -CMatroskaMuxerInputPin::CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseInputPin(NAME("CMatroskaMuxerInputPin"), pFilter, pLock, phr, pName) - , m_fActive(false) - , m_rtLastStart(0) - , m_rtLastStop(0) - , m_rtDur(0) - , m_fEndOfStreamReceived(false) -{ -} - -CMatroskaMuxerInputPin::~CMatroskaMuxerInputPin() -{ -} - -STDMETHODIMP CMatroskaMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CMatroskaMuxerInputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Video && (pmt->formattype == FORMAT_VideoInfo - || pmt->formattype == FORMAT_VideoInfo2) - // || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG1Payload && pmt->formattype == FORMAT_MPEGVideo - // || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO && pmt->formattype == FORMAT_MPEG2_VIDEO - || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_DiracVideo && pmt->formattype == FORMAT_DiracVideoInfo - || pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->subtype == FOURCCMap(((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag) - || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis && pmt->formattype == FORMAT_VorbisFormat - || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis2 && pmt->formattype == FORMAT_VorbisFormat2 - || pmt->majortype == MEDIATYPE_Audio && (pmt->subtype == MEDIASUBTYPE_14_4 - || pmt->subtype == MEDIASUBTYPE_28_8 - || pmt->subtype == MEDIASUBTYPE_ATRC - || pmt->subtype == MEDIASUBTYPE_COOK - || pmt->subtype == MEDIASUBTYPE_DNET - || pmt->subtype == MEDIASUBTYPE_SIPR) && pmt->formattype == FORMAT_WaveFormatEx - || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None - || pmt->majortype == MEDIATYPE_Subtitle && pmt->formattype == FORMAT_SubtitleInfo - ? S_OK - : E_INVALIDARG; -} - -HRESULT CMatroskaMuxerInputPin::BreakConnect() -{ - HRESULT hr; - - if (FAILED(hr = __super::BreakConnect())) { - return hr; - } - - m_pTE.Free(); - - return hr; -} - -HRESULT CMatroskaMuxerInputPin::CompleteConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CompleteConnect(pPin))) { - return hr; - } - - m_rtDur = 0; - CComQIPtr pMS; - if ((pMS = GetFilterFromPin(pPin)) || (pMS = pPin)) { - pMS->GetDuration(&m_rtDur); - } - - m_pTE.Free(); - m_pTE.Attach(DEBUG_NEW TrackEntry()); - - m_pTE->TrackUID.Set(rand()); - m_pTE->MinCache.Set(1); - m_pTE->MaxCache.Set(1); - m_pTE->TrackNumber.Set((static_cast(m_pFilter))->GetTrackNumber(this)); - - hr = E_FAIL; - - if (m_mt.majortype == MEDIATYPE_Video) { - m_pTE->TrackType.Set(TrackEntry::TypeVideo); - - if (m_mt.formattype == FORMAT_VideoInfo - && m_mt.subtype == MEDIASUBTYPE_RV10 || m_mt.subtype == MEDIASUBTYPE_RV20 - || m_mt.subtype == MEDIASUBTYPE_RV30 || m_mt.subtype == MEDIASUBTYPE_RV40) { - m_pTE->CodecID.Set("V_REAL/RV00"); - m_pTE->CodecID.SetAt(9, (BYTE)(m_mt.subtype.Data1 >> 16)); - - if (m_mt.formattype == FORMAT_VideoInfo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat; - if (m_mt.cbFormat > sizeof(VIDEOINFOHEADER)) { - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - sizeof(VIDEOINFOHEADER)); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER), m_pTE->CodecPrivate.GetCount()); - } - m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); - if (vih->AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); - } - } else if (m_mt.formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat; - if (m_mt.cbFormat > sizeof(VIDEOINFOHEADER2)) { - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - sizeof(VIDEOINFOHEADER2)); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER2), m_pTE->CodecPrivate.GetCount()); - } - m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); - if (vih->AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); - } - m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); - m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); - } else { - ASSERT(0); - return hr; - } - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_VideoInfo) { - m_pTE->CodecID.Set("V_MS/VFW/FOURCC"); - - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); - memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); - if (vih->AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); - } - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_VideoInfo2) { - m_pTE->CodecID.Set("V_MS/VFW/FOURCC"); - - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader)); - memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); - m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); - m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); - if (vih->AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); - } - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_DiracVideoInfo) { - m_pTE->CodecID.Set("V_DIRAC"); - - DIRACINFOHEADER* vih = (DIRACINFOHEADER*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(vih->cbSequenceHeader); - memcpy(m_pTE->CodecPrivate, (BYTE*)&vih->dwSequenceHeader[0], m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(vih->hdr.AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->hdr.bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->hdr.bmiHeader.biHeight)); - // m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); - // m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); - if (vih->hdr.AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->hdr.AvgTimePerFrame)); - } - - hr = S_OK; - } - /* - else if (m_mt.formattype == FORMAT_MPEGVideo) - { - m_pTE->CodecID.Set("V_DSHOW/MPEG1VIDEO"); // V_MPEG1 - - MPEG1VIDEOINFO* pm1vi = (MPEG1VIDEOINFO*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.FormatLength()); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(pm1vi->hdr.AvgTimePerFrame*100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(pm1vi->hdr.bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(pm1vi->hdr.bmiHeader.biHeight)); - if (pm1vi->hdr.AvgTimePerFrame > 0) - m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm1vi->hdr.AvgTimePerFrame)); - - hr = S_OK; - } - else if (m_mt.formattype == FORMAT_MPEG2_VIDEO) - { - m_pTE->CodecID.Set("V_DSHOW/MPEG2VIDEO"); // V_MPEG2 - - MPEG2VIDEOINFO* pm2vi = (MPEG2VIDEOINFO*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.FormatLength()); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(pm2vi->hdr.AvgTimePerFrame*100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(pm2vi->hdr.bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(pm2vi->hdr.bmiHeader.biHeight)); - if (pm2vi->hdr.AvgTimePerFrame > 0) - m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm2vi->hdr.AvgTimePerFrame)); - - hr = S_OK; - } - */ - } else if (m_mt.majortype == MEDIATYPE_Audio) { - m_pTE->TrackType.Set(TrackEntry::TypeAudio); - - if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_AAC - && m_mt.cbFormat >= sizeof(WAVEFORMATEX) + 2) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - BYTE* p = (BYTE*)(wfe + 1); - - DWORD nSamplesPerSec = wfe->nSamplesPerSec; - - int profile = (p[0] >> 3) - 1; - int rate1 = ((p[0] & 7) << 1) | (p[1] >> 7); - int channels = ((p[1] >> 3) & 15); - int rate2 = rate1; - - if (wfe->cbSize >= 5) { - profile = 4; - - int exttype = (p[2] << 3) | (p[3] >> 5); - ASSERT(exttype == 0x2B7); - ASSERT((p[3] & 31) == 5); - ASSERT((p[4] >> 7) == 1); - rate2 = ((p[4] >> 3) & 15); - - if (rate2 < rate1) { - m_pTE->a.OutputSamplingFrequency.Set((float)nSamplesPerSec); - nSamplesPerSec /= 2; - } - } - - switch (profile) { - default: - case 0: - m_pTE->CodecID.Set("A_AAC/MPEG2/MAIN"); - break; - case 1: - m_pTE->CodecID.Set("A_AAC/MPEG2/LC"); - break; - case 2: - m_pTE->CodecID.Set("A_AAC/MPEG2/SSR"); - break; - case 3: - m_pTE->CodecID.Set("A_AAC/MPEG4/LTP"); - break; - case 4: - m_pTE->CodecID.Set("A_AAC/MPEG4/LC/SBR"); - break; - } - - ASSERT(channels == wfe->nChannels); - - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)nSamplesPerSec); - m_pTE->a.Channels.Set(channels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3) { - m_pTE->CodecID.Set("A_AC3"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS) { - m_pTE->CodecID.Set("A_DTS"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_FLAC) { - m_pTE->CodecID.Set("A_FLAC"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - if (wfe->cbSize) { - m_pTE->CodecPrivate.SetCount(wfe->cbSize); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(WAVEFORMATEX), wfe->cbSize); - } - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && (m_mt.subtype == MEDIASUBTYPE_14_4 - || m_mt.subtype == MEDIASUBTYPE_28_8 - || m_mt.subtype == MEDIASUBTYPE_ATRC - || m_mt.subtype == MEDIASUBTYPE_COOK - || m_mt.subtype == MEDIASUBTYPE_DNET - || m_mt.subtype == MEDIASUBTYPE_SIPR)) { - CStringA id; - id.Format("A_REAL/%c%c%c%c", - (char)((m_mt.subtype.Data1 >> 0) & 0xff), - (char)((m_mt.subtype.Data1 >> 8) & 0xff), - (char)((m_mt.subtype.Data1 >> 16) & 0xff), - (char)((m_mt.subtype.Data1 >> 24) & 0xff)); - - m_pTE->CodecID.Set(id); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - DWORD cbSize = sizeof(WAVEFORMATEX) + wfe->cbSize; - if (m_mt.cbFormat > cbSize) { - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - cbSize); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + cbSize, m_pTE->CodecPrivate.GetCount()); - } - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM) { - m_pTE->CodecID.Set("A_PCM/INT/LIT"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx) { - m_pTE->CodecID.Set("A_MS/ACM"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat); - memcpy(m_pTE->CodecPrivate, wfe, m_pTE->CodecPrivate.GetCount()); - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_VorbisFormat) { - m_pTE->CodecID.Set("A_VORBIS"); - - VORBISFORMAT* pvf = (VORBISFORMAT*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)pvf->nSamplesPerSec); - m_pTE->a.Channels.Set(pvf->nChannels); - - // m_pTE->CodecPrivate will be filled later - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_VorbisFormat2) { - m_pTE->CodecID.Set("A_VORBIS"); - - VORBISFORMAT2* pvf2 = (VORBISFORMAT2*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)pvf2->SamplesPerSec); - m_pTE->a.Channels.Set(pvf2->Channels); - m_pTE->a.BitDepth.Set(pvf2->BitsPerSample); - - int len = 1; - for (int i = 0; i < 2; i++) { - len += pvf2->HeaderSize[i] / 255 + 1; - } - for (int i = 0; i < 3; i++) { - len += pvf2->HeaderSize[i]; - } - m_pTE->CodecPrivate.SetCount(len); - - BYTE* src = (BYTE*)m_mt.pbFormat + sizeof(VORBISFORMAT2); - BYTE* dst = m_pTE->CodecPrivate.GetData(); - - *dst++ = 2; - for (int i = 0; i < 2; i++) { - for (int len2 = pvf2->HeaderSize[i]; len2 >= 0; len2 -= 255) { - *dst++ = (BYTE)std::min(len2, BYTE_MAX); - } - } - - memcpy(dst, src, pvf2->HeaderSize[0]); - dst += pvf2->HeaderSize[0]; - src += pvf2->HeaderSize[0]; - memcpy(dst, src, pvf2->HeaderSize[1]); - dst += pvf2->HeaderSize[1]; - src += pvf2->HeaderSize[1]; - memcpy(dst, src, pvf2->HeaderSize[2]); - dst += pvf2->HeaderSize[2]; - src += pvf2->HeaderSize[2]; - - ASSERT(src <= m_mt.pbFormat + m_mt.cbFormat); - ASSERT(dst <= m_pTE->CodecPrivate.GetData() + m_pTE->CodecPrivate.GetCount()); - - hr = S_OK; - } - } else if (m_mt.majortype == MEDIATYPE_Text) { - m_pTE->TrackType.Set(TrackEntry::TypeSubtitle); - - if (m_mt.formattype == FORMAT_None) { - m_pTE->CodecID.Set("S_TEXT/ASCII"); - hr = S_OK; - } - } else if (m_mt.majortype == MEDIATYPE_Subtitle) { - m_pTE->TrackType.Set(TrackEntry::TypeSubtitle); - - m_pTE->CodecID.Set( - m_mt.subtype == MEDIASUBTYPE_UTF8 ? "S_TEXT/UTF8" : - m_mt.subtype == MEDIASUBTYPE_SSA ? "S_TEXT/SSA" : - m_mt.subtype == MEDIASUBTYPE_ASS ? "S_TEXT/ASS" : - m_mt.subtype == MEDIASUBTYPE_USF ? "S_TEXT/USF" : - m_mt.subtype == MEDIASUBTYPE_VOBSUB ? "S_VOBSUB" : - ""); - - if (!m_pTE->CodecID.IsEmpty()) { - hr = S_OK; - - SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; - if (psi->dwOffset) { - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - psi->dwOffset); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + psi->dwOffset, m_pTE->CodecPrivate.GetCount()); - } - } - } - - if (S_OK == hr) { - (static_cast(m_pFilter))->AddInput(); - } - - return hr; -} - -HRESULT CMatroskaMuxerInputPin::Active() -{ - m_fActive = true; - m_rtLastStart = m_rtLastStop = -1; - m_fEndOfStreamReceived = false; - return __super::Active(); -} - -HRESULT CMatroskaMuxerInputPin::Inactive() -{ - m_fActive = false; - CAutoLock cAutoLock(&m_csQueue); - m_blocks.RemoveAll(); - m_pVorbisHdrs.RemoveAll(); - return __super::Inactive(); -} - -STDMETHODIMP CMatroskaMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - CAutoLock cAutoLock(&m_csReceive); - return __super::NewSegment(tStart, tStop, dRate); -} - -STDMETHODIMP CMatroskaMuxerInputPin::BeginFlush() -{ - return __super::BeginFlush(); -} - -STDMETHODIMP CMatroskaMuxerInputPin::EndFlush() -{ - return __super::EndFlush(); -} - -STDMETHODIMP CMatroskaMuxerInputPin::Receive(IMediaSample* pSample) -{ - if (m_fEndOfStreamReceived) { - /*ASSERT(0);*/ - return S_FALSE; - } - - CAutoLock cAutoLock(&m_csReceive); - - while (m_fActive) { - { - CAutoLock cAutoLock2(&m_csQueue); - if (m_blocks.GetCount() < MAXBLOCKS) { - break; - } - } - - Sleep(1); - } - - if (!m_fActive) { - return S_FALSE; - } - - HRESULT hr; - - if (FAILED(hr = __super::Receive(pSample))) { - return hr; - } - - BYTE* pData = nullptr; - if (FAILED(hr = pSample->GetPointer(&pData)) || !pData) { - return hr; - } - - long inputLen = pSample->GetActualDataLength(); - - REFERENCE_TIME rtStart = -1, rtStop = -1; - hr = pSample->GetTime(&rtStart, &rtStop); - - if (FAILED(hr) || rtStart == -1 || rtStop == -1) { - TRACE(_T("No timestamp was set on the sample!!!")); - m_pFilter->NotifyEvent(EC_ERRORABORT, VFW_E_SAMPLE_TIME_NOT_SET, 0); - return VFW_E_SAMPLE_TIME_NOT_SET; - } - - //rtStart += m_tStart; - //rtStop += m_tStart; - - TRACE(_T("Received (%u): %I64d-%I64d (c=%d, co=%dms), len=%ld, d%d p%d s%d\n"), - (static_cast(m_pFilter))->GetTrackNumber(this), - rtStart, rtStop, (int)((rtStart / 10000) / MAXCLUSTERTIME), (int)((rtStart / 10000) % MAXCLUSTERTIME), - inputLen, - pSample->IsDiscontinuity() == S_OK ? 1 : 0, - pSample->IsPreroll() == S_OK ? 1 : 0, - pSample->IsSyncPoint() == S_OK ? 1 : 0); - - if (m_mt.subtype == MEDIASUBTYPE_Vorbis && m_pVorbisHdrs.GetCount() < 3) { - CAutoPtr data(DEBUG_NEW CBinary(0)); - data->SetCount(inputLen); - memcpy(data->GetData(), pData, inputLen); - m_pVorbisHdrs.Add(data); - - if (m_pVorbisHdrs.GetCount() == 3) { - int len = 1; - for (size_t i = 0; i < 2; i++) { - len += (int)m_pVorbisHdrs[i]->GetCount() / 255 + 1; - } - for (size_t i = 0; i < 3; i++) { - len += (int)m_pVorbisHdrs[i]->GetCount(); - } - m_pTE->CodecPrivate.SetCount(len); - - BYTE* dst = m_pTE->CodecPrivate.GetData(); - - *dst++ = 2; - for (size_t i = 0; i < 2; i++) { - for (INT_PTR len2 = m_pVorbisHdrs[i]->GetCount(); len2 >= 0; len2 -= 255) { - *dst++ = (BYTE)std::min(len2, 255); - } - } - - for (size_t i = 0; i < 3; i++) { - memcpy(dst, m_pVorbisHdrs[i]->GetData(), m_pVorbisHdrs[i]->GetCount()); - dst += m_pVorbisHdrs[i]->GetCount(); - } - } - - return S_OK; - } - - if (m_mt.formattype == FORMAT_WaveFormatEx - && (((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM - || ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_MPEGLAYER3)) { - pSample->SetSyncPoint(TRUE); // HACK: some capture filters don't set this - } - - CAutoPtr b(DEBUG_NEW BlockGroup()); - /* - // TODO: test this with a longer capture (pcm, mp3) - if (S_OK == pSample->IsSyncPoint() && rtStart < m_rtLastStart) - { - TRACE(_T("!!! timestamp went backwards, dropping this frame !!! rtStart (%I64) < m_rtLastStart (%I64)"), rtStart, m_rtLastStart); - return S_OK; - } - */ - if ((S_OK != pSample->IsSyncPoint() || m_rtLastStart == rtStart) && m_rtLastStart >= 0 /*&& m_rtLastStart < rtStart*/) { - ASSERT(m_rtLastStart - rtStart <= 0); - REFERENCE_TIME rtDiff = m_rtLastStart - rtStart; - b->ReferenceBlock.Set((rtDiff + (rtDiff >= 0 ? 5000 : -5000)) / 10000); - } - - b->Block.TrackNumber = (static_cast(m_pFilter))->GetTrackNumber(this); - - b->Block.TimeCode = (rtStart + 5000) / 10000; - b->Block.TimeCodeStop = (rtStop + 5000) / 10000; - - if (m_pTE->TrackType == TrackEntry::TypeSubtitle) { - b->BlockDuration.Set((rtStop - rtStart + 5000) / 10000); - } - - CAutoPtr data(DEBUG_NEW CBinary(0)); - data->SetCount(inputLen); - memcpy(data->GetData(), pData, inputLen); - b->Block.BlockData.AddTail(data); - - CAutoLock cAutoLock2(&m_csQueue); - m_blocks.AddTail(b); // TODO: lacing for audio - - m_rtLastStart = rtStart; - m_rtLastStop = rtStop; - - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerInputPin::EndOfStream() -{ - HRESULT hr; - - if (FAILED(hr = __super::EndOfStream())) { - return hr; - } - - CAutoLock cAutoLock(&m_csQueue); - - m_fEndOfStreamReceived = true; - - return hr; -} - -// -// CMatroskaMuxerOutputPin -// - -CMatroskaMuxerOutputPin::CMatroskaMuxerOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output") -{ -} - -CMatroskaMuxerOutputPin::~CMatroskaMuxerOutputPin() -{ -} - -STDMETHODIMP CMatroskaMuxerOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CMatroskaMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = 1; - pProperties->cbBuffer = 1; - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CMatroskaMuxerOutputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_Matroska - ? S_OK - : E_INVALIDARG; -} - -HRESULT CMatroskaMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CAutoLock cAutoLock(m_pLock); - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - pmt->ResetFormatBuffer(); - pmt->InitMediaType(); - pmt->majortype = MEDIATYPE_Stream; - pmt->subtype = MEDIASUBTYPE_Matroska; - pmt->formattype = FORMAT_None; - - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "MatroskaMuxer.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +using namespace MatroskaWriter; + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_Matroska} +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, nullptr, 0, nullptr}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CMatroskaMuxerFilter), MatroskaMuxerName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CMatroskaMuxerFilter +// + +CMatroskaMuxerFilter::CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseFilter(NAME("CMatroskaMuxerFilter"), pUnk, this, __uuidof(this)) + , m_rtCurrent(0) + , m_fNegative(true) + , m_fPositive(false) +{ + if (phr) { + *phr = S_OK; + } + + m_pOutput.Attach(DEBUG_NEW CMatroskaMuxerOutputPin(NAME("CMatroskaMuxerOutputPin"), this, this, phr)); + + AddInput(); + + srand(clock()); +} + +CMatroskaMuxerFilter::~CMatroskaMuxerFilter() +{ + CAutoLock cAutoLock(this); +} + +STDMETHODIMP CMatroskaMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + return + // QI(IAMFilterMiscFlags) + QI(IMediaSeeking) + QI(IMatroskaMuxer) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +UINT CMatroskaMuxerFilter::GetTrackNumber(const CBasePin* pPin) +{ + UINT nTrackNumber = 0; + + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + nTrackNumber++; + if (m_pInputs.GetNext(pos) == pPin) { + return nTrackNumber; + } + } + + return 0; +} + +void CMatroskaMuxerFilter::AddInput() +{ + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CBasePin* pPin = m_pInputs.GetNext(pos); + if (!pPin->IsConnected()) { + return; + } + } + + CStringW name; + name.Format(L"Track %u", m_pInputs.GetCount() + 1); + + HRESULT hr; + CAutoPtr pPin(DEBUG_NEW CMatroskaMuxerInputPin(name, this, this, &hr)); + m_pInputs.AddTail(pPin); +} + +int CMatroskaMuxerFilter::GetPinCount() +{ + return (int)m_pInputs.GetCount() + (m_pOutput ? 1 : 0); +} + +CBasePin* CMatroskaMuxerFilter::GetPin(int n) +{ + CAutoLock cAutoLock(this); + + if (n >= 0 && n < (int)m_pInputs.GetCount()) { + if (POSITION pos = m_pInputs.FindIndex(n)) { + return m_pInputs.GetAt(pos); + } + } + + if (n == (int)m_pInputs.GetCount() && m_pOutput) { + return m_pOutput; + } + + return nullptr; +} + +STDMETHODIMP CMatroskaMuxerFilter::Stop() +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (FAILED(hr = __super::Stop())) { + return hr; + } + + CallWorker(CMD_EXIT); + + return hr; +} + +STDMETHODIMP CMatroskaMuxerFilter::Pause() +{ + CAutoLock cAutoLock(this); + + FILTER_STATE fs = m_State; + + HRESULT hr; + + if (FAILED(hr = __super::Pause())) { + return hr; + } + + if (fs == State_Stopped && m_pOutput) { + CAMThread::Create(); + CallWorker(CMD_RUN); + } + + return hr; +} + +STDMETHODIMP CMatroskaMuxerFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (FAILED(hr = __super::Run(tStart))) { + return hr; + } + + return hr; +} + +// IAMFilterMiscFlags + +STDMETHODIMP_(ULONG) CMatroskaMuxerFilter::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_RENDERER; +} + +// IMediaSeeking + +STDMETHODIMP CMatroskaMuxerFilter::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanGetDuration | AM_SEEKING_CanGetCurrentPos; + + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerFilter::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + if (*pCapabilities == 0) { + return S_OK; + } + DWORD caps; + GetCapabilities(&caps); + caps &= *pCapabilities; + return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE; +} + +STDMETHODIMP CMatroskaMuxerFilter::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CMatroskaMuxerFilter::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CMatroskaMuxerFilter::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CMatroskaMuxerFilter::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetDuration(LONGLONG* pDuration) +{ + CheckPointer(pDuration, E_POINTER); + *pDuration = 0; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + REFERENCE_TIME rt = m_pInputs.GetNext(pos)->m_rtDur; + if (rt > *pDuration) { + *pDuration = rt; + } + } + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetStopPosition(LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent) +{ + CheckPointer(pCurrent, E_POINTER); + *pCurrent = m_rtCurrent; + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::SetRate(double dRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetRate(double* pdRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetPreroll(LONGLONG* pllPreroll) +{ + return E_NOTIMPL; +} + +// IMatroskaMuxer + +STDMETHODIMP CMatroskaMuxerFilter::CorrectTimeOffset(bool fNegative, bool fPositive) +{ + m_fNegative = fNegative; + m_fPositive = fPositive; + return S_OK; +} + +// + +ULONGLONG GetStreamPosition(IStream* pStream) +{ + ULARGE_INTEGER pos = {0, 0}; + pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos); + return pos.QuadPart; +} + +ULONGLONG SetStreamPosition(IStream* pStream, ULONGLONG seekpos) +{ + LARGE_INTEGER pos; + pos.QuadPart = seekpos; + ULARGE_INTEGER posnew; + posnew.QuadPart = GetStreamPosition(pStream); + pStream->Seek(pos, STREAM_SEEK_SET, &posnew); + return posnew.QuadPart; +} + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CMatroskaMuxerFilter::ThreadProc() +{ + CComQIPtr pStream; + + if (!m_pOutput || !(pStream = m_pOutput->GetConnected())) { + for (;;) { + DWORD cmd = GetRequest(); + if (cmd == CMD_EXIT) { + CAMThread::m_hThread = nullptr; + } + Reply(S_OK); + if (cmd == CMD_EXIT) { + return 0; + } + } + } + + REFERENCE_TIME rtDur = 0; + GetDuration(&rtDur); + + SetStreamPosition(pStream, 0); + + ULARGE_INTEGER uli = {0}; + pStream->SetSize(uli); + + EBML hdr; + hdr.DocType.Set("matroska"); + hdr.DocTypeVersion.Set(1); + hdr.DocTypeReadVersion.Set(1); + hdr.Write(pStream); + + Segment().Write(pStream); + ULONGLONG segpos = GetStreamPosition(pStream); + + // TODO + QWORD voidlen = 100; + if (rtDur > 0) { + voidlen += QWORD(1.0 * rtDur / MAXCLUSTERTIME / 10000 + 0.5) * 20; + } else { + voidlen += QWORD(1.0 * 1000 * 60 * 60 * 24 / MAXCLUSTERTIME + 0.5) * 20; // when no duration is known, allocate for 24 hours (~340k) + } + ULONGLONG voidpos = GetStreamPosition(pStream); + { + Void v(voidlen); + voidlen = v.Size(); + v.Write(pStream); + } + + // Meta Seek + + Seek seek; + CAutoPtr sh; + + // Segment Info + + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(0x1549A966); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + ULONGLONG infopos = GetStreamPosition(pStream); + Info info; + info.MuxingApp.Set(L"DirectShow Matroska Muxer"); + info.TimeCodeScale.Set(1000000); + info.Duration.Set((float)rtDur / 10000); + struct tm _2001 = {0, 0, 0, 1, 0, 101, 0, 0, 1}; + info.DateUTC.Set((_time64(nullptr) - _mktime64(&_2001)) * 1000000000); + info.Write(pStream); + + // Tracks + + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(0x1654AE6B); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + UINT64 TrackNumber = 0; + /* + CNode Tracks; + CAutoPtr pT(DEBUG_NEW Track()); + POSITION pos = m_pInputs.GetHeadPosition(); + for (int i = 1; pos; i++) + { + CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos); + if (!pPin->IsConnected()) continue; + + CAutoPtr pTE(DEBUG_NEW TrackEntry()); + *pTE = *pPin->GetTrackEntry(); + if (TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo) + TrackNumber = pTE->TrackNumber; + pT->TrackEntries.AddTail(pTE); + } + Tracks.AddTail(pT); + Tracks.Write(pStream); + + if (TrackNumber == 0) TrackNumber = 1; + */ + bool fTracksWritten = false; + + // + + Cluster c; + c.TimeCode.Set(0); + + bool fFirstBlock = true; + INT64 firstTimeCode = 0; + + CAtlList pActivePins; + + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos); + if (pPin->IsConnected()) { + pActivePins.AddTail(pPin); + } + } + + for (;;) { + DWORD cmd = GetRequest(); + + switch (cmd) { + default: + case CMD_EXIT: + CAMThread::m_hThread = nullptr; + Reply(S_OK); + return 0; + + case CMD_RUN: + Reply(S_OK); + + Cue cue; + ULONGLONG lastcueclusterpos = (ULONGLONG) - 1; + INT64 lastcuetimecode = (INT64) - 1; + UINT64 nBlocksInCueTrack = 0; + + while (!CheckRequest(nullptr)) { + if (m_State == State_Paused) { + Sleep(10); + continue; + } + + int nPinsGotSomething = 0, nPinsNeeded = 0; + CMatroskaMuxerInputPin* pPin = nullptr; + REFERENCE_TIME rtMin = _I64_MAX; + + pos = pActivePins.GetHeadPosition(); + while (pos) { + CMatroskaMuxerInputPin* pTmp = pActivePins.GetNext(pos); + + CAutoLock cAutoLock(&pTmp->m_csQueue); + + if (pTmp->m_blocks.IsEmpty() && pTmp->m_fEndOfStreamReceived) { + pActivePins.RemoveAt(pActivePins.Find(pTmp)); + continue; + } + + if (pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle) { + nPinsNeeded++; + } + + if (!pTmp->m_blocks.IsEmpty()) { + if (pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle) { + nPinsGotSomething++; + } + + if (!pTmp->m_blocks.IsEmpty()) { + REFERENCE_TIME rt = pTmp->m_blocks.GetHead()->Block.TimeCode; + if (rt < rtMin) { + rtMin = rt; + pPin = pTmp; + } + } + } + } + + if (pActivePins.IsEmpty()) { + break; + } + + if (!pPin || nPinsNeeded > nPinsGotSomething || !pPin && nPinsGotSomething == 0) { + Sleep(1); + continue; + } + + if (!fTracksWritten) { + CNode Tracks; + CAutoPtr pT(DEBUG_NEW Track()); + pos = pActivePins.GetHeadPosition(); + for (int i = 1; pos; i++) { + CMatroskaMuxerInputPin* pActivePin = pActivePins.GetNext(pos); + + CAutoPtr pTE(DEBUG_NEW TrackEntry()); + *pTE = *pActivePin->GetTrackEntry(); + if (TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo) { + TrackNumber = pTE->TrackNumber; + } + pT->TrackEntries.AddTail(pTE); + } + Tracks.AddTail(pT); + Tracks.Write(pStream); + + if (TrackNumber == 0) { + TrackNumber = 1; + } + + fTracksWritten = true; + } + + ASSERT(pPin); + + CAutoPtr b; + + { + CAutoLock cAutoLock(&pPin->m_csQueue); + b.Attach(pPin->m_blocks.RemoveHead().Detach()); + } + + if (b) { + if (fFirstBlock) { + if (b->Block.TimeCode < 0 && m_fNegative || b->Block.TimeCode > 0 && m_fPositive) { + firstTimeCode = b->Block.TimeCode; + } + fFirstBlock = false; + } + + b->Block.TimeCode -= firstTimeCode; + b->Block.TimeCodeStop -= firstTimeCode; + + /* + TRACE(_T("Muxing (%d): %I64d-%I64d dur=%I64d (c=%d, co=%dms), cnt=%d, ref=%d\n"), + GetTrackNumber(pPin), + (INT64)b->Block.TimeCode, (INT64)b->Block.TimeCodeStop, (UINT64)b->BlockDuration, + (int)((b->Block.TimeCode)/MAXCLUSTERTIME), (int)(b->Block.TimeCode%MAXCLUSTERTIME), + b->Block.BlockData.GetCount(), (int)b->ReferenceBlock); + */ + if (b->Block.TimeCode < SHRT_MIN /*0*/) { + ASSERT(0); + continue; + } + + while ((INT64)(c.TimeCode + MAXCLUSTERTIME) < b->Block.TimeCode) { + if (!c.BlockGroups.IsEmpty()) { + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(c.GetID()/*0x1F43B675*/); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + c.Write(pStream); // TODO: write blocks + } + + c.TimeCode.Set(c.TimeCode + MAXCLUSTERTIME); + c.BlockGroups.RemoveAll(); + nBlocksInCueTrack = 0; + } + + if (b->Block.TrackNumber == TrackNumber) { + nBlocksInCueTrack++; + } + + if (b->ReferenceBlock == 0 && b->Block.TrackNumber == TrackNumber) { + ULONGLONG clusterpos = GetStreamPosition(pStream) - segpos; + if (lastcueclusterpos != clusterpos || lastcuetimecode + 1000 < b->Block.TimeCode) { + CAutoPtr ctp(DEBUG_NEW CueTrackPosition()); + ctp->CueTrack.Set(b->Block.TrackNumber); + ctp->CueClusterPosition.Set(clusterpos); + if (!c.BlockGroups.IsEmpty()) { + ctp->CueBlockNumber.Set(nBlocksInCueTrack); + } + CAutoPtr cp(DEBUG_NEW CuePoint()); + cp->CueTime.Set(b->Block.TimeCode); + cp->CueTrackPositions.AddTail(ctp); + cue.CuePoints.AddTail(cp); + lastcueclusterpos = clusterpos; + lastcuetimecode = b->Block.TimeCode; + } + } + + info.Duration.Set(std::max(info.Duration, (float)b->Block.TimeCodeStop)); + + m_rtCurrent = b->Block.TimeCode * 10000; + + b->Block.TimeCode -= c.TimeCode; + c.BlockGroups.AddTail(b); + } + } + + if (!c.BlockGroups.IsEmpty()) { + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(c.GetID()/*0x1F43B675*/); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + c.Write(pStream); + } + + if (!cue.CuePoints.IsEmpty()) { + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(cue.GetID()/*0x1C53BB6B*/); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + cue.Write(pStream); + } + + { + Tags tags; + + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(tags.GetID()); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + tags.Write(pStream); + } + + SetStreamPosition(pStream, voidpos); + QWORD len = voidlen - seek.Size(); + ASSERT(len >= 0 && len != 1); + seek.Write(pStream); + + if (len == 0) { + // nothing to do + } else if (len >= 2) { + for (QWORD i = 0; i < 8; i++) { + if (len >= (QWORD(1) << i * 7) - 2 && len <= (QWORD(1) << (i + 1) * 7) - 2) { + Void(len - 2 - i).Write(pStream); + break; + } + } + } + + if (abs(m_rtCurrent - (REFERENCE_TIME)info.Duration * 10000) > 10000000i64) { + info.Duration.Set((float)m_rtCurrent / 10000 + 1); + } + + SetStreamPosition(pStream, infopos); + info.Write(pStream); + + // TODO: write some tags + + m_pOutput->DeliverEndOfStream(); + + break; + } + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +// +// CMatroskaMuxerInputPin +// + +CMatroskaMuxerInputPin::CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseInputPin(NAME("CMatroskaMuxerInputPin"), pFilter, pLock, phr, pName) + , m_fActive(false) + , m_rtLastStart(0) + , m_rtLastStop(0) + , m_rtDur(0) + , m_fEndOfStreamReceived(false) +{ +} + +CMatroskaMuxerInputPin::~CMatroskaMuxerInputPin() +{ +} + +STDMETHODIMP CMatroskaMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CMatroskaMuxerInputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Video && (pmt->formattype == FORMAT_VideoInfo + || pmt->formattype == FORMAT_VideoInfo2) + // || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG1Payload && pmt->formattype == FORMAT_MPEGVideo + // || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO && pmt->formattype == FORMAT_MPEG2_VIDEO + || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_DiracVideo && pmt->formattype == FORMAT_DiracVideoInfo + || pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->subtype == FOURCCMap(((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag) + || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis && pmt->formattype == FORMAT_VorbisFormat + || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis2 && pmt->formattype == FORMAT_VorbisFormat2 + || pmt->majortype == MEDIATYPE_Audio && (pmt->subtype == MEDIASUBTYPE_14_4 + || pmt->subtype == MEDIASUBTYPE_28_8 + || pmt->subtype == MEDIASUBTYPE_ATRC + || pmt->subtype == MEDIASUBTYPE_COOK + || pmt->subtype == MEDIASUBTYPE_DNET + || pmt->subtype == MEDIASUBTYPE_SIPR) && pmt->formattype == FORMAT_WaveFormatEx + || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None + || pmt->majortype == MEDIATYPE_Subtitle && pmt->formattype == FORMAT_SubtitleInfo + ? S_OK + : E_INVALIDARG; +} + +HRESULT CMatroskaMuxerInputPin::BreakConnect() +{ + HRESULT hr; + + if (FAILED(hr = __super::BreakConnect())) { + return hr; + } + + m_pTE.Free(); + + return hr; +} + +HRESULT CMatroskaMuxerInputPin::CompleteConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CompleteConnect(pPin))) { + return hr; + } + + m_rtDur = 0; + CComQIPtr pMS; + if ((pMS = GetFilterFromPin(pPin)) || (pMS = pPin)) { + pMS->GetDuration(&m_rtDur); + } + + m_pTE.Free(); + m_pTE.Attach(DEBUG_NEW TrackEntry()); + + m_pTE->TrackUID.Set(rand()); + m_pTE->MinCache.Set(1); + m_pTE->MaxCache.Set(1); + m_pTE->TrackNumber.Set((static_cast(m_pFilter))->GetTrackNumber(this)); + + hr = E_FAIL; + + if (m_mt.majortype == MEDIATYPE_Video) { + m_pTE->TrackType.Set(TrackEntry::TypeVideo); + + if (m_mt.formattype == FORMAT_VideoInfo + && m_mt.subtype == MEDIASUBTYPE_RV10 || m_mt.subtype == MEDIASUBTYPE_RV20 + || m_mt.subtype == MEDIASUBTYPE_RV30 || m_mt.subtype == MEDIASUBTYPE_RV40) { + m_pTE->CodecID.Set("V_REAL/RV00"); + m_pTE->CodecID.SetAt(9, (BYTE)(m_mt.subtype.Data1 >> 16)); + + if (m_mt.formattype == FORMAT_VideoInfo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat; + if (m_mt.cbFormat > sizeof(VIDEOINFOHEADER)) { + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - sizeof(VIDEOINFOHEADER)); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER), m_pTE->CodecPrivate.GetCount()); + } + m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); + if (vih->AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); + } + } else if (m_mt.formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat; + if (m_mt.cbFormat > sizeof(VIDEOINFOHEADER2)) { + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - sizeof(VIDEOINFOHEADER2)); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER2), m_pTE->CodecPrivate.GetCount()); + } + m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); + if (vih->AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); + } + m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); + m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); + } else { + ASSERT(0); + return hr; + } + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_VideoInfo) { + m_pTE->CodecID.Set("V_MS/VFW/FOURCC"); + + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); + memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); + if (vih->AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); + } + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_VideoInfo2) { + m_pTE->CodecID.Set("V_MS/VFW/FOURCC"); + + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader)); + memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); + m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); + m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); + if (vih->AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); + } + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_DiracVideoInfo) { + m_pTE->CodecID.Set("V_DIRAC"); + + DIRACINFOHEADER* vih = (DIRACINFOHEADER*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(vih->cbSequenceHeader); + memcpy(m_pTE->CodecPrivate, (BYTE*)&vih->dwSequenceHeader[0], m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(vih->hdr.AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->hdr.bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->hdr.bmiHeader.biHeight)); + // m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); + // m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); + if (vih->hdr.AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->hdr.AvgTimePerFrame)); + } + + hr = S_OK; + } + /* + else if (m_mt.formattype == FORMAT_MPEGVideo) + { + m_pTE->CodecID.Set("V_DSHOW/MPEG1VIDEO"); // V_MPEG1 + + MPEG1VIDEOINFO* pm1vi = (MPEG1VIDEOINFO*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.FormatLength()); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(pm1vi->hdr.AvgTimePerFrame*100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(pm1vi->hdr.bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(pm1vi->hdr.bmiHeader.biHeight)); + if (pm1vi->hdr.AvgTimePerFrame > 0) + m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm1vi->hdr.AvgTimePerFrame)); + + hr = S_OK; + } + else if (m_mt.formattype == FORMAT_MPEG2_VIDEO) + { + m_pTE->CodecID.Set("V_DSHOW/MPEG2VIDEO"); // V_MPEG2 + + MPEG2VIDEOINFO* pm2vi = (MPEG2VIDEOINFO*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.FormatLength()); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(pm2vi->hdr.AvgTimePerFrame*100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(pm2vi->hdr.bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(pm2vi->hdr.bmiHeader.biHeight)); + if (pm2vi->hdr.AvgTimePerFrame > 0) + m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm2vi->hdr.AvgTimePerFrame)); + + hr = S_OK; + } + */ + } else if (m_mt.majortype == MEDIATYPE_Audio) { + m_pTE->TrackType.Set(TrackEntry::TypeAudio); + + if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_AAC + && m_mt.cbFormat >= sizeof(WAVEFORMATEX) + 2) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + BYTE* p = (BYTE*)(wfe + 1); + + DWORD nSamplesPerSec = wfe->nSamplesPerSec; + + int profile = (p[0] >> 3) - 1; + int rate1 = ((p[0] & 7) << 1) | (p[1] >> 7); + int channels = ((p[1] >> 3) & 15); + int rate2 = rate1; + + if (wfe->cbSize >= 5) { + profile = 4; + + int exttype = (p[2] << 3) | (p[3] >> 5); + ASSERT(exttype == 0x2B7); + ASSERT((p[3] & 31) == 5); + ASSERT((p[4] >> 7) == 1); + rate2 = ((p[4] >> 3) & 15); + + if (rate2 < rate1) { + m_pTE->a.OutputSamplingFrequency.Set((float)nSamplesPerSec); + nSamplesPerSec /= 2; + } + } + + switch (profile) { + default: + case 0: + m_pTE->CodecID.Set("A_AAC/MPEG2/MAIN"); + break; + case 1: + m_pTE->CodecID.Set("A_AAC/MPEG2/LC"); + break; + case 2: + m_pTE->CodecID.Set("A_AAC/MPEG2/SSR"); + break; + case 3: + m_pTE->CodecID.Set("A_AAC/MPEG4/LTP"); + break; + case 4: + m_pTE->CodecID.Set("A_AAC/MPEG4/LC/SBR"); + break; + } + + ASSERT(channels == wfe->nChannels); + + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)nSamplesPerSec); + m_pTE->a.Channels.Set(channels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3) { + m_pTE->CodecID.Set("A_AC3"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS) { + m_pTE->CodecID.Set("A_DTS"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_FLAC) { + m_pTE->CodecID.Set("A_FLAC"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + if (wfe->cbSize) { + m_pTE->CodecPrivate.SetCount(wfe->cbSize); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(WAVEFORMATEX), wfe->cbSize); + } + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && (m_mt.subtype == MEDIASUBTYPE_14_4 + || m_mt.subtype == MEDIASUBTYPE_28_8 + || m_mt.subtype == MEDIASUBTYPE_ATRC + || m_mt.subtype == MEDIASUBTYPE_COOK + || m_mt.subtype == MEDIASUBTYPE_DNET + || m_mt.subtype == MEDIASUBTYPE_SIPR)) { + CStringA id; + id.Format("A_REAL/%c%c%c%c", + (char)((m_mt.subtype.Data1 >> 0) & 0xff), + (char)((m_mt.subtype.Data1 >> 8) & 0xff), + (char)((m_mt.subtype.Data1 >> 16) & 0xff), + (char)((m_mt.subtype.Data1 >> 24) & 0xff)); + + m_pTE->CodecID.Set(id); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + DWORD cbSize = sizeof(WAVEFORMATEX) + wfe->cbSize; + if (m_mt.cbFormat > cbSize) { + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - cbSize); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + cbSize, m_pTE->CodecPrivate.GetCount()); + } + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM) { + m_pTE->CodecID.Set("A_PCM/INT/LIT"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx) { + m_pTE->CodecID.Set("A_MS/ACM"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat); + memcpy(m_pTE->CodecPrivate, wfe, m_pTE->CodecPrivate.GetCount()); + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_VorbisFormat) { + m_pTE->CodecID.Set("A_VORBIS"); + + VORBISFORMAT* pvf = (VORBISFORMAT*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)pvf->nSamplesPerSec); + m_pTE->a.Channels.Set(pvf->nChannels); + + // m_pTE->CodecPrivate will be filled later + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_VorbisFormat2) { + m_pTE->CodecID.Set("A_VORBIS"); + + VORBISFORMAT2* pvf2 = (VORBISFORMAT2*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)pvf2->SamplesPerSec); + m_pTE->a.Channels.Set(pvf2->Channels); + m_pTE->a.BitDepth.Set(pvf2->BitsPerSample); + + int len = 1; + for (int i = 0; i < 2; i++) { + len += pvf2->HeaderSize[i] / 255 + 1; + } + for (int i = 0; i < 3; i++) { + len += pvf2->HeaderSize[i]; + } + m_pTE->CodecPrivate.SetCount(len); + + BYTE* src = (BYTE*)m_mt.pbFormat + sizeof(VORBISFORMAT2); + BYTE* dst = m_pTE->CodecPrivate.GetData(); + + *dst++ = 2; + for (int i = 0; i < 2; i++) { + for (int len2 = pvf2->HeaderSize[i]; len2 >= 0; len2 -= 255) { + *dst++ = (BYTE)std::min(len2, BYTE_MAX); + } + } + + memcpy(dst, src, pvf2->HeaderSize[0]); + dst += pvf2->HeaderSize[0]; + src += pvf2->HeaderSize[0]; + memcpy(dst, src, pvf2->HeaderSize[1]); + dst += pvf2->HeaderSize[1]; + src += pvf2->HeaderSize[1]; + memcpy(dst, src, pvf2->HeaderSize[2]); + dst += pvf2->HeaderSize[2]; + src += pvf2->HeaderSize[2]; + + ASSERT(src <= m_mt.pbFormat + m_mt.cbFormat); + ASSERT(dst <= m_pTE->CodecPrivate.GetData() + m_pTE->CodecPrivate.GetCount()); + + hr = S_OK; + } + } else if (m_mt.majortype == MEDIATYPE_Text) { + m_pTE->TrackType.Set(TrackEntry::TypeSubtitle); + + if (m_mt.formattype == FORMAT_None) { + m_pTE->CodecID.Set("S_TEXT/ASCII"); + hr = S_OK; + } + } else if (m_mt.majortype == MEDIATYPE_Subtitle) { + m_pTE->TrackType.Set(TrackEntry::TypeSubtitle); + + m_pTE->CodecID.Set( + m_mt.subtype == MEDIASUBTYPE_UTF8 ? "S_TEXT/UTF8" : + m_mt.subtype == MEDIASUBTYPE_SSA ? "S_TEXT/SSA" : + m_mt.subtype == MEDIASUBTYPE_ASS ? "S_TEXT/ASS" : + m_mt.subtype == MEDIASUBTYPE_USF ? "S_TEXT/USF" : + m_mt.subtype == MEDIASUBTYPE_VOBSUB ? "S_VOBSUB" : + ""); + + if (!m_pTE->CodecID.IsEmpty()) { + hr = S_OK; + + SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; + if (psi->dwOffset) { + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - psi->dwOffset); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + psi->dwOffset, m_pTE->CodecPrivate.GetCount()); + } + } + } + + if (S_OK == hr) { + (static_cast(m_pFilter))->AddInput(); + } + + return hr; +} + +HRESULT CMatroskaMuxerInputPin::Active() +{ + m_fActive = true; + m_rtLastStart = m_rtLastStop = -1; + m_fEndOfStreamReceived = false; + return __super::Active(); +} + +HRESULT CMatroskaMuxerInputPin::Inactive() +{ + m_fActive = false; + CAutoLock cAutoLock(&m_csQueue); + m_blocks.RemoveAll(); + m_pVorbisHdrs.RemoveAll(); + return __super::Inactive(); +} + +STDMETHODIMP CMatroskaMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CAutoLock cAutoLock(&m_csReceive); + return __super::NewSegment(tStart, tStop, dRate); +} + +STDMETHODIMP CMatroskaMuxerInputPin::BeginFlush() +{ + return __super::BeginFlush(); +} + +STDMETHODIMP CMatroskaMuxerInputPin::EndFlush() +{ + return __super::EndFlush(); +} + +STDMETHODIMP CMatroskaMuxerInputPin::Receive(IMediaSample* pSample) +{ + if (m_fEndOfStreamReceived) { + /*ASSERT(0);*/ + return S_FALSE; + } + + CAutoLock cAutoLock(&m_csReceive); + + while (m_fActive) { + { + CAutoLock cAutoLock2(&m_csQueue); + if (m_blocks.GetCount() < MAXBLOCKS) { + break; + } + } + + Sleep(1); + } + + if (!m_fActive) { + return S_FALSE; + } + + HRESULT hr; + + if (FAILED(hr = __super::Receive(pSample))) { + return hr; + } + + BYTE* pData = nullptr; + if (FAILED(hr = pSample->GetPointer(&pData)) || !pData) { + return hr; + } + + long inputLen = pSample->GetActualDataLength(); + + REFERENCE_TIME rtStart = -1, rtStop = -1; + hr = pSample->GetTime(&rtStart, &rtStop); + + if (FAILED(hr) || rtStart == -1 || rtStop == -1) { + TRACE(_T("No timestamp was set on the sample!!!")); + m_pFilter->NotifyEvent(EC_ERRORABORT, VFW_E_SAMPLE_TIME_NOT_SET, 0); + return VFW_E_SAMPLE_TIME_NOT_SET; + } + + //rtStart += m_tStart; + //rtStop += m_tStart; + + TRACE(_T("Received (%u): %I64d-%I64d (c=%d, co=%dms), len=%ld, d%d p%d s%d\n"), + (static_cast(m_pFilter))->GetTrackNumber(this), + rtStart, rtStop, (int)((rtStart / 10000) / MAXCLUSTERTIME), (int)((rtStart / 10000) % MAXCLUSTERTIME), + inputLen, + pSample->IsDiscontinuity() == S_OK ? 1 : 0, + pSample->IsPreroll() == S_OK ? 1 : 0, + pSample->IsSyncPoint() == S_OK ? 1 : 0); + + if (m_mt.subtype == MEDIASUBTYPE_Vorbis && m_pVorbisHdrs.GetCount() < 3) { + CAutoPtr data(DEBUG_NEW CBinary(0)); + data->SetCount(inputLen); + memcpy(data->GetData(), pData, inputLen); + m_pVorbisHdrs.Add(data); + + if (m_pVorbisHdrs.GetCount() == 3) { + int len = 1; + for (size_t i = 0; i < 2; i++) { + len += (int)m_pVorbisHdrs[i]->GetCount() / 255 + 1; + } + for (size_t i = 0; i < 3; i++) { + len += (int)m_pVorbisHdrs[i]->GetCount(); + } + m_pTE->CodecPrivate.SetCount(len); + + BYTE* dst = m_pTE->CodecPrivate.GetData(); + + *dst++ = 2; + for (size_t i = 0; i < 2; i++) { + for (INT_PTR len2 = m_pVorbisHdrs[i]->GetCount(); len2 >= 0; len2 -= 255) { + *dst++ = (BYTE)std::min(len2, 255); + } + } + + for (size_t i = 0; i < 3; i++) { + memcpy(dst, m_pVorbisHdrs[i]->GetData(), m_pVorbisHdrs[i]->GetCount()); + dst += m_pVorbisHdrs[i]->GetCount(); + } + } + + return S_OK; + } + + if (m_mt.formattype == FORMAT_WaveFormatEx + && (((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM + || ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_MPEGLAYER3)) { + pSample->SetSyncPoint(TRUE); // HACK: some capture filters don't set this + } + + CAutoPtr b(DEBUG_NEW BlockGroup()); + /* + // TODO: test this with a longer capture (pcm, mp3) + if (S_OK == pSample->IsSyncPoint() && rtStart < m_rtLastStart) + { + TRACE(_T("!!! timestamp went backwards, dropping this frame !!! rtStart (%I64) < m_rtLastStart (%I64)"), rtStart, m_rtLastStart); + return S_OK; + } + */ + if ((S_OK != pSample->IsSyncPoint() || m_rtLastStart == rtStart) && m_rtLastStart >= 0 /*&& m_rtLastStart < rtStart*/) { + ASSERT(m_rtLastStart - rtStart <= 0); + REFERENCE_TIME rtDiff = m_rtLastStart - rtStart; + b->ReferenceBlock.Set((rtDiff + (rtDiff >= 0 ? 5000 : -5000)) / 10000); + } + + b->Block.TrackNumber = (static_cast(m_pFilter))->GetTrackNumber(this); + + b->Block.TimeCode = (rtStart + 5000) / 10000; + b->Block.TimeCodeStop = (rtStop + 5000) / 10000; + + if (m_pTE->TrackType == TrackEntry::TypeSubtitle) { + b->BlockDuration.Set((rtStop - rtStart + 5000) / 10000); + } + + CAutoPtr data(DEBUG_NEW CBinary(0)); + data->SetCount(inputLen); + memcpy(data->GetData(), pData, inputLen); + b->Block.BlockData.AddTail(data); + + CAutoLock cAutoLock2(&m_csQueue); + m_blocks.AddTail(b); // TODO: lacing for audio + + m_rtLastStart = rtStart; + m_rtLastStop = rtStop; + + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerInputPin::EndOfStream() +{ + HRESULT hr; + + if (FAILED(hr = __super::EndOfStream())) { + return hr; + } + + CAutoLock cAutoLock(&m_csQueue); + + m_fEndOfStreamReceived = true; + + return hr; +} + +// +// CMatroskaMuxerOutputPin +// + +CMatroskaMuxerOutputPin::CMatroskaMuxerOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output") +{ +} + +CMatroskaMuxerOutputPin::~CMatroskaMuxerOutputPin() +{ +} + +STDMETHODIMP CMatroskaMuxerOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CMatroskaMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = 1; + pProperties->cbBuffer = 1; + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CMatroskaMuxerOutputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_Matroska + ? S_OK + : E_INVALIDARG; +} + +HRESULT CMatroskaMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CAutoLock cAutoLock(m_pLock); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + pmt->ResetFormatBuffer(); + pmt->InitMediaType(); + pmt->majortype = MEDIATYPE_Stream; + pmt->subtype = MEDIASUBTYPE_Matroska; + pmt->formattype = FORMAT_None; + + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.def b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.def +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.h b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.h index b6237e62f01..2fe06d8cf2e 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.h +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.h @@ -1,162 +1,162 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include -#include "MatroskaFile.h" - -#define MAXCLUSTERTIME 1000 -#define MAXBLOCKS 50 - -#define MatroskaMuxerName L"MPC Matroska Muxer" - -class CMatroskaMuxerInputPin : public CBaseInputPin -{ - CAutoPtr m_pTE; - CAutoPtrArray m_pVorbisHdrs; - - bool m_fActive; - CCritSec m_csReceive; - - REFERENCE_TIME m_rtLastStart, m_rtLastStop; - -public: - CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CMatroskaMuxerInputPin(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - MatroskaWriter::TrackEntry* GetTrackEntry() { return m_pTE; } - - REFERENCE_TIME m_rtDur; - - CCritSec m_csQueue; - CAutoPtrList m_blocks; - bool m_fEndOfStreamReceived; - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pPin); - HRESULT Active(), Inactive(); - - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP EndOfStream(); -}; - -class CMatroskaMuxerOutputPin : public CBaseOutputPin -{ -public: - CMatroskaMuxerOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CMatroskaMuxerOutputPin(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; - -interface __declspec(uuid("38E2D43D-915D-493C-B373-888DB16EE3DC")) - IMatroskaMuxer : - public IUnknown -{ - STDMETHOD(CorrectTimeOffset)(bool fNegative, bool fPositive) PURE; - // TODO: chapters -}; - -class __declspec(uuid("1E1299A2-9D42-4F12-8791-D79E376F4143")) - CMatroskaMuxerFilter - : public CBaseFilter - , public CCritSec - , public CAMThread - , public IAMFilterMiscFlags - , public IMediaSeeking - , public IMatroskaMuxer -{ -protected: - CAutoPtrList m_pInputs; - CAutoPtr m_pOutput; - - REFERENCE_TIME m_rtCurrent; - - bool m_fNegative, m_fPositive; - - enum { CMD_EXIT, CMD_RUN }; - DWORD ThreadProc(); - -public: - CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr); - virtual ~CMatroskaMuxerFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - void AddInput(); - UINT GetTrackNumber(const CBasePin* pPin); - - int GetPinCount(); - CBasePin* GetPin(int n); - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // IAMFilterMiscFlags - - STDMETHODIMP_(ULONG) GetMiscFlags(); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - - // IMatroskaMuxer - - STDMETHODIMP CorrectTimeOffset(bool fNegative, bool fPositive); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include +#include "MatroskaFile.h" + +#define MAXCLUSTERTIME 1000 +#define MAXBLOCKS 50 + +#define MatroskaMuxerName L"MPC Matroska Muxer" + +class CMatroskaMuxerInputPin : public CBaseInputPin +{ + CAutoPtr m_pTE; + CAutoPtrArray m_pVorbisHdrs; + + bool m_fActive; + CCritSec m_csReceive; + + REFERENCE_TIME m_rtLastStart, m_rtLastStop; + +public: + CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CMatroskaMuxerInputPin(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + MatroskaWriter::TrackEntry* GetTrackEntry() { return m_pTE; } + + REFERENCE_TIME m_rtDur; + + CCritSec m_csQueue; + CAutoPtrList m_blocks; + bool m_fEndOfStreamReceived; + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pPin); + HRESULT Active(), Inactive(); + + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP EndOfStream(); +}; + +class CMatroskaMuxerOutputPin : public CBaseOutputPin +{ +public: + CMatroskaMuxerOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CMatroskaMuxerOutputPin(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; + +interface __declspec(uuid("38E2D43D-915D-493C-B373-888DB16EE3DC")) + IMatroskaMuxer : + public IUnknown +{ + STDMETHOD(CorrectTimeOffset)(bool fNegative, bool fPositive) PURE; + // TODO: chapters +}; + +class __declspec(uuid("1E1299A2-9D42-4F12-8791-D79E376F4143")) + CMatroskaMuxerFilter + : public CBaseFilter + , public CCritSec + , public CAMThread + , public IAMFilterMiscFlags + , public IMediaSeeking + , public IMatroskaMuxer +{ +protected: + CAutoPtrList m_pInputs; + CAutoPtr m_pOutput; + + REFERENCE_TIME m_rtCurrent; + + bool m_fNegative, m_fPositive; + + enum { CMD_EXIT, CMD_RUN }; + DWORD ThreadProc(); + +public: + CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr); + virtual ~CMatroskaMuxerFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + void AddInput(); + UINT GetTrackNumber(const CBasePin* pPin); + + int GetPinCount(); + CBasePin* GetPin(int n); + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // IAMFilterMiscFlags + + STDMETHODIMP_(ULONG) GetMiscFlags(); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + + // IMatroskaMuxer + + STDMETHODIMP CorrectTimeOffset(bool fNegative, bool fPositive); +}; diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.rc b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.rc index 956a55e56eb..a19cf668c10 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.rc +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "Matroska Muxer" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "Matroska Muxer" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "MatroskaMuxer.ax" - VALUE "ProductName", "Matroska Muxer" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "Matroska Muxer" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "Matroska Muxer" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "MatroskaMuxer.ax" + VALUE "ProductName", "Matroska Muxer" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj index 0bf08977290..5ae5862291a 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj @@ -1,126 +1,126 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {67827491-8162-4039-9132-F934ABC836A0} - MatroskaMuxer - MFCProj - MatroskaMuxer - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - MatroskaMuxer.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - - Create - - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {67827491-8162-4039-9132-F934ABC836A0} + MatroskaMuxer + MFCProj + MatroskaMuxer + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + MatroskaMuxer.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + + Create + + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj.filters b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj.filters index 3b9080e4865..9c1e88ed197 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj.filters +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj.filters @@ -1,52 +1,52 @@ - - - - - {5ba8ecdf-2b3a-4c43-8d71-30a1bbc63dbb} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {3325ae0c-9fde-43fb-905c-ba603cc0378f} - h;hpp;hxx;hm;inl;inc - - - {9e126e2d-b3ce-4bd5-bde1-9874e3a354d7} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {5ba8ecdf-2b3a-4c43-8d71-30a1bbc63dbb} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {3325ae0c-9fde-43fb-905c-ba603cc0378f} + h;hpp;hxx;hm;inl;inc + + + {9e126e2d-b3ce-4bd5-bde1-9874e3a354d7} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/muxer/MatroskaMuxer/resource.h b/src/filters/muxer/MatroskaMuxer/resource.h index 22bd5aaf892..ef1214d7bc0 100644 --- a/src/filters/muxer/MatroskaMuxer/resource.h +++ b/src/filters/muxer/MatroskaMuxer/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by MatroskaMuxer.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by MatroskaMuxer.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/muxer/MatroskaMuxer/stdafx.cpp b/src/filters/muxer/MatroskaMuxer/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/muxer/MatroskaMuxer/stdafx.cpp +++ b/src/filters/muxer/MatroskaMuxer/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/muxer/MatroskaMuxer/stdafx.h b/src/filters/muxer/MatroskaMuxer/stdafx.h index 619304dd68e..a8517b3e334 100644 --- a/src/filters/muxer/MatroskaMuxer/stdafx.h +++ b/src/filters/muxer/MatroskaMuxer/stdafx.h @@ -1,35 +1,35 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/muxer/WavDest/WavDest.cpp b/src/filters/muxer/WavDest/WavDest.cpp index f2f292e1dc2..af62b991850 100644 --- a/src/filters/muxer/WavDest/WavDest.cpp +++ b/src/filters/muxer/WavDest/WavDest.cpp @@ -1,334 +1,334 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include "BaseClasses/streams.h" -#include -#include "WavDest.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CWavDestFilter), WavDestName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {L"WavDest", &__uuidof(CWavDestFilter), CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CWavDestFilter -// - -CWavDestFilter::CWavDestFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CTransformFilter(NAME("WavDest filter"), pUnk, __uuidof(this)) - , m_cbWavData(0) - , m_cbHeader(0) -{ - if (CWavDestOutputPin* pOut = DEBUG_NEW CWavDestOutputPin(this, phr)) { - if (SUCCEEDED(*phr)) { - m_pOutput = pOut; - } else { - delete pOut; - } - } else { - *phr = E_OUTOFMEMORY; - return; - } - - if (CTransformInputPin* pIn = DEBUG_NEW CTransformInputPin(NAME("Transform input pin"), this, phr, L"In")) { - if (SUCCEEDED(*phr)) { - m_pInput = pIn; - } else { - delete pIn; - } - } else { - *phr = E_OUTOFMEMORY; - return; - } -} - -CWavDestFilter::~CWavDestFilter() -{ -} - -HRESULT CWavDestFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return CheckInputType(mtIn); -} - -HRESULT CWavDestFilter::Receive(IMediaSample* pSample) -{ - ULONG cbOld = m_cbWavData; - HRESULT hr = CTransformFilter::Receive(pSample); - - // don't update the count if Deliver() downstream fails. - if (hr != S_OK) { - m_cbWavData = cbOld; - } - - return hr; -} - -HRESULT CWavDestFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - REFERENCE_TIME rtStart, rtEnd; - - HRESULT hr = Copy(pIn, pOut); - if (FAILED(hr)) { - return hr; - } - - // Prepare it for writing - LONG lActual = pOut->GetActualDataLength(); - - if (m_cbWavData + m_cbHeader + lActual < m_cbWavData + m_cbHeader) { // overflow - return E_FAIL; - } - - rtStart = m_cbWavData + m_cbHeader; - rtEnd = rtStart + lActual; - m_cbWavData += lActual; - - EXECUTE_ASSERT(pOut->SetTime(&rtStart, &rtEnd) == S_OK); - - return S_OK; -} - -HRESULT CWavDestFilter::Copy(IMediaSample* pSource, IMediaSample* pDest) const -{ - BYTE* pSourceBuffer, * pDestBuffer; - long lSourceSize = pSource->GetActualDataLength(); - -#ifdef _DEBUG - long lDestSize = pDest->GetSize(); - ASSERT(lDestSize >= lSourceSize); -#endif - - if (FAILED(pSource->GetPointer(&pSourceBuffer)) || !pSourceBuffer) { - return E_FAIL; - } - if (FAILED(pDest->GetPointer(&pDestBuffer)) || !pDestBuffer) { - return E_FAIL; - } - - CopyMemory((PVOID)pDestBuffer, (PVOID)pSourceBuffer, lSourceSize); - - // Copy the sample times - - REFERENCE_TIME rtTimeStart, rtTimeEnd; - if (SUCCEEDED(pSource->GetTime(&rtTimeStart, &rtTimeEnd))) { - pDest->SetTime(&rtTimeStart, &rtTimeEnd); - } - - LONGLONG rtMediaStart, rtMediaEnd; - if (SUCCEEDED(pSource->GetMediaTime(&rtMediaStart, &rtMediaEnd))) { - pDest->SetMediaTime(&rtMediaStart, &rtMediaEnd); - } - - // Copy the media type - AM_MEDIA_TYPE* pMediaType; - if (SUCCEEDED(pSource->GetMediaType(&pMediaType)) && pMediaType) { - pDest->SetMediaType(pMediaType); - DeleteMediaType(pMediaType); - } - - // Copy the actual data length - long lDataLength = pSource->GetActualDataLength(); - pDest->SetActualDataLength(lDataLength); - - return NOERROR; -} - -HRESULT CWavDestFilter::CheckInputType(const CMediaType* mtIn) -{ - return mtIn->formattype == FORMAT_WaveFormatEx ? S_OK : S_FALSE; -} - -HRESULT CWavDestFilter::GetMediaType(int iPosition, CMediaType* pMediaType) -{ - ASSERT(iPosition == 0 || iPosition == 1); - - if (iPosition == 0) { - pMediaType->SetType(&MEDIATYPE_Stream); - pMediaType->SetSubtype(&MEDIASUBTYPE_WAVE); - return S_OK; - } - - return VFW_S_NO_MORE_ITEMS; -} - -HRESULT CWavDestFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = 1; - pProperties->cbAlign = 1; - - CComPtr pInAlloc; - ALLOCATOR_PROPERTIES InProps; - if (SUCCEEDED(hr = m_pInput->GetAllocator(&pInAlloc)) - && SUCCEEDED(hr = pInAlloc->GetProperties(&InProps))) { - pProperties->cbBuffer = InProps.cbBuffer; - } else { - return hr; - } - - ASSERT(pProperties->cbBuffer); - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - ASSERT(Actual.cBuffers == 1); - - if (pProperties->cBuffers > Actual.cBuffers - || pProperties->cbBuffer > Actual.cbBuffer) { - return E_FAIL; - } - - return NOERROR; -} - -// Compute the header size to allow space for us to write it at the end. -// -// 00000000 RIFF (00568BFE) 'WAVE' -// 0000000C fmt (00000010) -// 00000024 data (00568700) -// 0056872C -// - -HRESULT CWavDestFilter::StartStreaming() -{ - // leave space for the header - m_cbHeader = sizeof(RIFFLIST) + - sizeof(RIFFCHUNK) + - m_pInput->CurrentMediaType().FormatLength() + - sizeof(RIFFCHUNK); - - m_cbWavData = 0; - - return S_OK; -} - -HRESULT CWavDestFilter::StopStreaming() -{ - IStream* pStream; - if (m_pOutput->IsConnected() == FALSE) { - return E_FAIL; - } - - IPin* pDwnstrmInputPin = m_pOutput->GetConnected(); - - if (!pDwnstrmInputPin) { - return E_FAIL; - } - - HRESULT hr = ((IMemInputPin*) pDwnstrmInputPin)->QueryInterface(IID_PPV_ARGS(&pStream)); - if (SUCCEEDED(hr)) { - BYTE* pb = (BYTE*)_alloca(m_cbHeader); - - RIFFLIST* pRiffWave = (RIFFLIST*)pb; - RIFFCHUNK* pRiffFmt = (RIFFCHUNK*)(pRiffWave + 1); - RIFFCHUNK* pRiffData = (RIFFCHUNK*)(((BYTE*)(pRiffFmt + 1)) + m_pInput->CurrentMediaType().FormatLength()); - - pRiffData->fcc = FCC('data'); - pRiffData->cb = m_cbWavData; - - pRiffFmt->fcc = FCC('fmt '); - pRiffFmt->cb = m_pInput->CurrentMediaType().FormatLength(); - CopyMemory(pRiffFmt + 1, m_pInput->CurrentMediaType().Format(), pRiffFmt->cb); - - pRiffWave->fcc = FCC('RIFF'); - pRiffWave->cb = m_cbWavData + m_cbHeader - sizeof(RIFFCHUNK); - pRiffWave->fccListType = FCC('WAVE'); - - LARGE_INTEGER li; - ZeroMemory(&li, sizeof(li)); - - hr = pStream->Seek(li, STREAM_SEEK_SET, 0); - if (SUCCEEDED(hr)) { - hr = pStream->Write(pb, m_cbHeader, 0); - } - pStream->Release(); - } - - return hr; -} - -CWavDestOutputPin::CWavDestOutputPin(CTransformFilter* pFilter, HRESULT* phr) - : CTransformOutputPin(NAME("WavDest output pin"), pFilter, phr, L"Out") -{ -} - -STDMETHODIMP CWavDestOutputPin::EnumMediaTypes(IEnumMediaTypes** ppEnum) -{ - return CBaseOutputPin::EnumMediaTypes(ppEnum); -} - -HRESULT CWavDestOutputPin::CheckMediaType(const CMediaType* pmt) -{ - if (pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_WAVE) { - return S_OK; - } else { - return S_FALSE; - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include "BaseClasses/streams.h" +#include +#include "WavDest.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CWavDestFilter), WavDestName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {L"WavDest", &__uuidof(CWavDestFilter), CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CWavDestFilter +// + +CWavDestFilter::CWavDestFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CTransformFilter(NAME("WavDest filter"), pUnk, __uuidof(this)) + , m_cbWavData(0) + , m_cbHeader(0) +{ + if (CWavDestOutputPin* pOut = DEBUG_NEW CWavDestOutputPin(this, phr)) { + if (SUCCEEDED(*phr)) { + m_pOutput = pOut; + } else { + delete pOut; + } + } else { + *phr = E_OUTOFMEMORY; + return; + } + + if (CTransformInputPin* pIn = DEBUG_NEW CTransformInputPin(NAME("Transform input pin"), this, phr, L"In")) { + if (SUCCEEDED(*phr)) { + m_pInput = pIn; + } else { + delete pIn; + } + } else { + *phr = E_OUTOFMEMORY; + return; + } +} + +CWavDestFilter::~CWavDestFilter() +{ +} + +HRESULT CWavDestFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return CheckInputType(mtIn); +} + +HRESULT CWavDestFilter::Receive(IMediaSample* pSample) +{ + ULONG cbOld = m_cbWavData; + HRESULT hr = CTransformFilter::Receive(pSample); + + // don't update the count if Deliver() downstream fails. + if (hr != S_OK) { + m_cbWavData = cbOld; + } + + return hr; +} + +HRESULT CWavDestFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + REFERENCE_TIME rtStart, rtEnd; + + HRESULT hr = Copy(pIn, pOut); + if (FAILED(hr)) { + return hr; + } + + // Prepare it for writing + LONG lActual = pOut->GetActualDataLength(); + + if (m_cbWavData + m_cbHeader + lActual < m_cbWavData + m_cbHeader) { // overflow + return E_FAIL; + } + + rtStart = m_cbWavData + m_cbHeader; + rtEnd = rtStart + lActual; + m_cbWavData += lActual; + + EXECUTE_ASSERT(pOut->SetTime(&rtStart, &rtEnd) == S_OK); + + return S_OK; +} + +HRESULT CWavDestFilter::Copy(IMediaSample* pSource, IMediaSample* pDest) const +{ + BYTE* pSourceBuffer, * pDestBuffer; + long lSourceSize = pSource->GetActualDataLength(); + +#ifdef _DEBUG + long lDestSize = pDest->GetSize(); + ASSERT(lDestSize >= lSourceSize); +#endif + + if (FAILED(pSource->GetPointer(&pSourceBuffer)) || !pSourceBuffer) { + return E_FAIL; + } + if (FAILED(pDest->GetPointer(&pDestBuffer)) || !pDestBuffer) { + return E_FAIL; + } + + CopyMemory((PVOID)pDestBuffer, (PVOID)pSourceBuffer, lSourceSize); + + // Copy the sample times + + REFERENCE_TIME rtTimeStart, rtTimeEnd; + if (SUCCEEDED(pSource->GetTime(&rtTimeStart, &rtTimeEnd))) { + pDest->SetTime(&rtTimeStart, &rtTimeEnd); + } + + LONGLONG rtMediaStart, rtMediaEnd; + if (SUCCEEDED(pSource->GetMediaTime(&rtMediaStart, &rtMediaEnd))) { + pDest->SetMediaTime(&rtMediaStart, &rtMediaEnd); + } + + // Copy the media type + AM_MEDIA_TYPE* pMediaType; + if (SUCCEEDED(pSource->GetMediaType(&pMediaType)) && pMediaType) { + pDest->SetMediaType(pMediaType); + DeleteMediaType(pMediaType); + } + + // Copy the actual data length + long lDataLength = pSource->GetActualDataLength(); + pDest->SetActualDataLength(lDataLength); + + return NOERROR; +} + +HRESULT CWavDestFilter::CheckInputType(const CMediaType* mtIn) +{ + return mtIn->formattype == FORMAT_WaveFormatEx ? S_OK : S_FALSE; +} + +HRESULT CWavDestFilter::GetMediaType(int iPosition, CMediaType* pMediaType) +{ + ASSERT(iPosition == 0 || iPosition == 1); + + if (iPosition == 0) { + pMediaType->SetType(&MEDIATYPE_Stream); + pMediaType->SetSubtype(&MEDIASUBTYPE_WAVE); + return S_OK; + } + + return VFW_S_NO_MORE_ITEMS; +} + +HRESULT CWavDestFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = 1; + pProperties->cbAlign = 1; + + CComPtr pInAlloc; + ALLOCATOR_PROPERTIES InProps; + if (SUCCEEDED(hr = m_pInput->GetAllocator(&pInAlloc)) + && SUCCEEDED(hr = pInAlloc->GetProperties(&InProps))) { + pProperties->cbBuffer = InProps.cbBuffer; + } else { + return hr; + } + + ASSERT(pProperties->cbBuffer); + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + ASSERT(Actual.cBuffers == 1); + + if (pProperties->cBuffers > Actual.cBuffers + || pProperties->cbBuffer > Actual.cbBuffer) { + return E_FAIL; + } + + return NOERROR; +} + +// Compute the header size to allow space for us to write it at the end. +// +// 00000000 RIFF (00568BFE) 'WAVE' +// 0000000C fmt (00000010) +// 00000024 data (00568700) +// 0056872C +// + +HRESULT CWavDestFilter::StartStreaming() +{ + // leave space for the header + m_cbHeader = sizeof(RIFFLIST) + + sizeof(RIFFCHUNK) + + m_pInput->CurrentMediaType().FormatLength() + + sizeof(RIFFCHUNK); + + m_cbWavData = 0; + + return S_OK; +} + +HRESULT CWavDestFilter::StopStreaming() +{ + IStream* pStream; + if (m_pOutput->IsConnected() == FALSE) { + return E_FAIL; + } + + IPin* pDwnstrmInputPin = m_pOutput->GetConnected(); + + if (!pDwnstrmInputPin) { + return E_FAIL; + } + + HRESULT hr = ((IMemInputPin*) pDwnstrmInputPin)->QueryInterface(IID_PPV_ARGS(&pStream)); + if (SUCCEEDED(hr)) { + BYTE* pb = (BYTE*)_alloca(m_cbHeader); + + RIFFLIST* pRiffWave = (RIFFLIST*)pb; + RIFFCHUNK* pRiffFmt = (RIFFCHUNK*)(pRiffWave + 1); + RIFFCHUNK* pRiffData = (RIFFCHUNK*)(((BYTE*)(pRiffFmt + 1)) + m_pInput->CurrentMediaType().FormatLength()); + + pRiffData->fcc = FCC('data'); + pRiffData->cb = m_cbWavData; + + pRiffFmt->fcc = FCC('fmt '); + pRiffFmt->cb = m_pInput->CurrentMediaType().FormatLength(); + CopyMemory(pRiffFmt + 1, m_pInput->CurrentMediaType().Format(), pRiffFmt->cb); + + pRiffWave->fcc = FCC('RIFF'); + pRiffWave->cb = m_cbWavData + m_cbHeader - sizeof(RIFFCHUNK); + pRiffWave->fccListType = FCC('WAVE'); + + LARGE_INTEGER li; + ZeroMemory(&li, sizeof(li)); + + hr = pStream->Seek(li, STREAM_SEEK_SET, 0); + if (SUCCEEDED(hr)) { + hr = pStream->Write(pb, m_cbHeader, 0); + } + pStream->Release(); + } + + return hr; +} + +CWavDestOutputPin::CWavDestOutputPin(CTransformFilter* pFilter, HRESULT* phr) + : CTransformOutputPin(NAME("WavDest output pin"), pFilter, phr, L"Out") +{ +} + +STDMETHODIMP CWavDestOutputPin::EnumMediaTypes(IEnumMediaTypes** ppEnum) +{ + return CBaseOutputPin::EnumMediaTypes(ppEnum); +} + +HRESULT CWavDestOutputPin::CheckMediaType(const CMediaType* pmt) +{ + if (pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_WAVE) { + return S_OK; + } else { + return S_FALSE; + } +} diff --git a/src/filters/muxer/WavDest/WavDest.def b/src/filters/muxer/WavDest/WavDest.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/muxer/WavDest/WavDest.def +++ b/src/filters/muxer/WavDest/WavDest.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/muxer/WavDest/WavDest.h b/src/filters/muxer/WavDest/WavDest.h index 985ce1c5563..50267c0bd26 100644 --- a/src/filters/muxer/WavDest/WavDest.h +++ b/src/filters/muxer/WavDest/WavDest.h @@ -1,66 +1,66 @@ -/* - * (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 . - * - */ - -#pragma once - -#include - -#define WavDestName L"MPC WavDest" - -class CWavDestOutputPin : public CTransformOutputPin -{ -public: - CWavDestOutputPin(CTransformFilter* pFilter, HRESULT* phr); - - STDMETHODIMP EnumMediaTypes(IEnumMediaTypes** ppEnum); - HRESULT CheckMediaType(const CMediaType* pmt); -}; - -class __declspec(uuid("8685214E-4D32-4058-BE04-D01104F00B0C")) - CWavDestFilter : public CTransformFilter -{ -public: - CWavDestFilter(LPUNKNOWN pUnk, HRESULT* pHr); - ~CWavDestFilter(); - - DECLARE_IUNKNOWN; - - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT Receive(IMediaSample* pSample); - - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - - HRESULT StartStreaming(); - HRESULT StopStreaming(); - -private: - - HRESULT Copy(IMediaSample* pSource, IMediaSample* pDest) const; - HRESULT Transform(IMediaSample* pMediaSample); - HRESULT Transform(AM_MEDIA_TYPE* pType, const signed char ContrastLevel) const; - - ULONG m_cbWavData; - ULONG m_cbHeader; -}; +/* + * (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 . + * + */ + +#pragma once + +#include + +#define WavDestName L"MPC WavDest" + +class CWavDestOutputPin : public CTransformOutputPin +{ +public: + CWavDestOutputPin(CTransformFilter* pFilter, HRESULT* phr); + + STDMETHODIMP EnumMediaTypes(IEnumMediaTypes** ppEnum); + HRESULT CheckMediaType(const CMediaType* pmt); +}; + +class __declspec(uuid("8685214E-4D32-4058-BE04-D01104F00B0C")) + CWavDestFilter : public CTransformFilter +{ +public: + CWavDestFilter(LPUNKNOWN pUnk, HRESULT* pHr); + ~CWavDestFilter(); + + DECLARE_IUNKNOWN; + + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT Receive(IMediaSample* pSample); + + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + + HRESULT StartStreaming(); + HRESULT StopStreaming(); + +private: + + HRESULT Copy(IMediaSample* pSource, IMediaSample* pDest) const; + HRESULT Transform(IMediaSample* pMediaSample); + HRESULT Transform(AM_MEDIA_TYPE* pType, const signed char ContrastLevel) const; + + ULONG m_cbWavData; + ULONG m_cbHeader; +}; diff --git a/src/filters/muxer/WavDest/WavDest.rc b/src/filters/muxer/WavDest/WavDest.rc index 709a122ad18..d522de7f2fe 100644 --- a/src/filters/muxer/WavDest/WavDest.rc +++ b/src/filters/muxer/WavDest/WavDest.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "WavDest" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "WavDest" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "WavDest.ax" - VALUE "ProductName", "WavDest" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "WavDest" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "WavDest" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "WavDest.ax" + VALUE "ProductName", "WavDest" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/muxer/WavDest/WavDest.vcxproj b/src/filters/muxer/WavDest/WavDest.vcxproj index 7552a4fb863..c2dbb38e4eb 100644 --- a/src/filters/muxer/WavDest/WavDest.vcxproj +++ b/src/filters/muxer/WavDest/WavDest.vcxproj @@ -1,114 +1,114 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {EB202B68-8029-4985-B914-E94B44D2E230} - WavDest - MFCProj - WavDest - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - WavDest.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - Create - - - - - - - - - true - - - - - - - true - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {EB202B68-8029-4985-B914-E94B44D2E230} + WavDest + MFCProj + WavDest + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + WavDest.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + Create + + + + + + + + + true + + + + + + + true + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/muxer/WavDest/WavDest.vcxproj.filters b/src/filters/muxer/WavDest/WavDest.vcxproj.filters index d6dec716288..1bc74cb9ced 100644 --- a/src/filters/muxer/WavDest/WavDest.vcxproj.filters +++ b/src/filters/muxer/WavDest/WavDest.vcxproj.filters @@ -1,45 +1,45 @@ - - - - - {4e8bc353-99a5-4a8a-8345-30fa00f8868c} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {352161b2-c379-4cb2-a6ea-2e55002639bc} - h;hpp;hxx;hm;inl;inc - - - {6939da75-f71e-49a0-a70e-feb331e5a56a} - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {4e8bc353-99a5-4a8a-8345-30fa00f8868c} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {352161b2-c379-4cb2-a6ea-2e55002639bc} + h;hpp;hxx;hm;inl;inc + + + {6939da75-f71e-49a0-a70e-feb331e5a56a} + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/muxer/WavDest/resource.h b/src/filters/muxer/WavDest/resource.h index b1483d5bbe1..513732d0a97 100644 --- a/src/filters/muxer/WavDest/resource.h +++ b/src/filters/muxer/WavDest/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by WavDest.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by WavDest.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/muxer/WavDest/stdafx.cpp b/src/filters/muxer/WavDest/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/muxer/WavDest/stdafx.cpp +++ b/src/filters/muxer/WavDest/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/muxer/WavDest/stdafx.h b/src/filters/muxer/WavDest/stdafx.h index 505867e46c6..844252f231b 100644 --- a/src/filters/muxer/WavDest/stdafx.h +++ b/src/filters/muxer/WavDest/stdafx.h @@ -1,31 +1,31 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components diff --git a/src/filters/parser/BaseSplitter/AsyncReader.cpp b/src/filters/parser/BaseSplitter/AsyncReader.cpp index 128072c8a8d..ca950c119ca 100644 --- a/src/filters/parser/BaseSplitter/AsyncReader.cpp +++ b/src/filters/parser/BaseSplitter/AsyncReader.cpp @@ -1,240 +1,240 @@ -/* - * (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 . - * - */ - - -#include "stdafx.h" -#include "AsyncReader.h" -#include -#include -#include "../../../DSUtil/DSUtil.h" - -// -// CAsyncFileReader -// - -CAsyncFileReader::CAsyncFileReader(CString fn, HRESULT& hr) - : CUnknown(NAME("CAsyncFileReader"), nullptr, &hr) - , m_len(ULONGLONG_MAX) - , m_hBreakEvent(nullptr) - , m_lOsError(0) -{ - hr = Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL; - if (SUCCEEDED(hr)) { - m_len = GetLength(); - } -} - -CAsyncFileReader::CAsyncFileReader(CAtlList& Items, HRESULT& hr) - : CUnknown(NAME("CAsyncFileReader"), nullptr, &hr) - , m_len(ULONGLONG_MAX) - , m_hBreakEvent(nullptr) - , m_lOsError(0) -{ - hr = OpenFiles(Items, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL; - if (SUCCEEDED(hr)) { - m_len = GetLength(); - } -} - -STDMETHODIMP CAsyncFileReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IAsyncReader) - QI(ISyncReader) - QI(IFileHandle) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IAsyncReader - -STDMETHODIMP CAsyncFileReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer) -{ - do { - try { - if ((ULONGLONG)llPosition + lLength > GetLength()) { - return E_FAIL; // strange, but the Seek below can return llPosition even if the file is not that big (?) - } - if ((ULONGLONG)llPosition != Seek(llPosition, begin)) { - return E_FAIL; - } - if ((UINT)lLength < Read(pBuffer, lLength)) { - return E_FAIL; - } - -#if 0 // def DEBUG - static __int64 s_total = 0, s_laststoppos = 0; - s_total += lLength; - if (s_laststoppos > llPosition) { - TRACE(_T("[%I64d - %I64d] %d (%I64d)\n"), llPosition, llPosition + lLength, lLength, s_total); - } - s_laststoppos = llPosition + lLength; -#endif - - return S_OK; - } catch (CFileException* e) { - m_lOsError = e->m_lOsError; - e->Delete(); - Sleep(1); - CString fn = m_strFileName; - try { - Close(); - } catch (CFileException* fe) { - fe->Delete(); - } - try { - Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan); - } catch (CFileException* fe) { - fe->Delete(); - } - m_strFileName = fn; - } - } while (m_hBreakEvent && WaitForSingleObject(m_hBreakEvent, 0) == WAIT_TIMEOUT); - - return E_FAIL; -} - -STDMETHODIMP CAsyncFileReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable) -{ - LONGLONG len = (m_len != ULONGLONG_MAX) ? m_len : GetLength(); - if (pTotal) { - *pTotal = len; - } - if (pAvailable) { - *pAvailable = len; - } - return S_OK; -} - -// IFileHandle - -STDMETHODIMP_(HANDLE) CAsyncFileReader::GetFileHandle() -{ - return m_hFile; -} - -STDMETHODIMP_(LPCTSTR) CAsyncFileReader::GetFileName() -{ - return m_nCurPart != -1 ? m_strFiles[m_nCurPart] : m_strFiles[0]; -} - -// -// CAsyncUrlReader -// - -CAsyncUrlReader::CAsyncUrlReader(CString url, HRESULT& hr) - : CAsyncFileReader(url, hr) -{ - if (SUCCEEDED(hr)) { - return; - } - - m_url = url; - - if (CAMThread::Create()) { - CallWorker(CMD_INIT); - } - - hr = Open(m_fn, modeRead | shareDenyRead | typeBinary | osSequentialScan) ? S_OK : E_FAIL; - m_len = ULONGLONG_MAX; // force GetLength() return actual length always -} - -CAsyncUrlReader::~CAsyncUrlReader() -{ - if (ThreadExists()) { - CallWorker(CMD_EXIT); - } - - if (!m_fn.IsEmpty()) { - CMultiFiles::Close(); - DeleteFile(m_fn); - } -} - -// IAsyncReader - -STDMETHODIMP CAsyncUrlReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable) -{ - if (pTotal) { - *pTotal = 0; - } - return __super::Length(nullptr, pAvailable); -} - -// CAMThread - -DWORD CAsyncUrlReader::ThreadProc() -{ - AfxSocketInit(nullptr); - - DWORD cmd = GetRequest(); - if (cmd != CMD_INIT) { - Reply((DWORD)E_FAIL); - return DWORD_ERROR; - } - - try { - CInternetSession is; - CAutoPtr fin(is.OpenURL(m_url, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_CACHE_WRITE)); - - TCHAR path[MAX_PATH], fn[MAX_PATH]; - CFile fout; - if (GetTempPath(MAX_PATH, path) && GetTempFileName(path, _T("mpc_http"), 0, fn) - && fout.Open(fn, modeCreate | modeWrite | shareDenyWrite | typeBinary)) { - m_fn = fn; - - char buff[1024]; - int len = fin->Read(buff, sizeof(buff)); - if (len > 0) { - fout.Write(buff, len); - } - - Reply(S_OK); - - while (!CheckRequest(&cmd)) { - int len2 = fin->Read(buff, sizeof(buff)); - if (len2 > 0) { - fout.Write(buff, len2); - } - } - } else { - Reply((DWORD)E_FAIL); - } - - fin->Close(); // must close it because the destructor doesn't seem to do it and we will get an exception when "is" is destroying - } catch (CInternetException* ie) { - ie->Delete(); - Reply((DWORD)E_FAIL); - } - - // - - cmd = GetRequest(); - ASSERT(cmd == CMD_EXIT); - Reply(S_OK); - - // - - m_hThread = nullptr; - - return S_OK; -} +/* + * (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 . + * + */ + + +#include "stdafx.h" +#include "AsyncReader.h" +#include +#include +#include "../../../DSUtil/DSUtil.h" + +// +// CAsyncFileReader +// + +CAsyncFileReader::CAsyncFileReader(CString fn, HRESULT& hr) + : CUnknown(NAME("CAsyncFileReader"), nullptr, &hr) + , m_len(ULONGLONG_MAX) + , m_hBreakEvent(nullptr) + , m_lOsError(0) +{ + hr = Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) { + m_len = GetLength(); + } +} + +CAsyncFileReader::CAsyncFileReader(CAtlList& Items, HRESULT& hr) + : CUnknown(NAME("CAsyncFileReader"), nullptr, &hr) + , m_len(ULONGLONG_MAX) + , m_hBreakEvent(nullptr) + , m_lOsError(0) +{ + hr = OpenFiles(Items, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) { + m_len = GetLength(); + } +} + +STDMETHODIMP CAsyncFileReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IAsyncReader) + QI(ISyncReader) + QI(IFileHandle) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IAsyncReader + +STDMETHODIMP CAsyncFileReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer) +{ + do { + try { + if ((ULONGLONG)llPosition + lLength > GetLength()) { + return E_FAIL; // strange, but the Seek below can return llPosition even if the file is not that big (?) + } + if ((ULONGLONG)llPosition != Seek(llPosition, begin)) { + return E_FAIL; + } + if ((UINT)lLength < Read(pBuffer, lLength)) { + return E_FAIL; + } + +#if 0 // def DEBUG + static __int64 s_total = 0, s_laststoppos = 0; + s_total += lLength; + if (s_laststoppos > llPosition) { + TRACE(_T("[%I64d - %I64d] %d (%I64d)\n"), llPosition, llPosition + lLength, lLength, s_total); + } + s_laststoppos = llPosition + lLength; +#endif + + return S_OK; + } catch (CFileException* e) { + m_lOsError = e->m_lOsError; + e->Delete(); + Sleep(1); + CString fn = m_strFileName; + try { + Close(); + } catch (CFileException* fe) { + fe->Delete(); + } + try { + Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan); + } catch (CFileException* fe) { + fe->Delete(); + } + m_strFileName = fn; + } + } while (m_hBreakEvent && WaitForSingleObject(m_hBreakEvent, 0) == WAIT_TIMEOUT); + + return E_FAIL; +} + +STDMETHODIMP CAsyncFileReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable) +{ + LONGLONG len = (m_len != ULONGLONG_MAX) ? m_len : GetLength(); + if (pTotal) { + *pTotal = len; + } + if (pAvailable) { + *pAvailable = len; + } + return S_OK; +} + +// IFileHandle + +STDMETHODIMP_(HANDLE) CAsyncFileReader::GetFileHandle() +{ + return m_hFile; +} + +STDMETHODIMP_(LPCTSTR) CAsyncFileReader::GetFileName() +{ + return m_nCurPart != -1 ? m_strFiles[m_nCurPart] : m_strFiles[0]; +} + +// +// CAsyncUrlReader +// + +CAsyncUrlReader::CAsyncUrlReader(CString url, HRESULT& hr) + : CAsyncFileReader(url, hr) +{ + if (SUCCEEDED(hr)) { + return; + } + + m_url = url; + + if (CAMThread::Create()) { + CallWorker(CMD_INIT); + } + + hr = Open(m_fn, modeRead | shareDenyRead | typeBinary | osSequentialScan) ? S_OK : E_FAIL; + m_len = ULONGLONG_MAX; // force GetLength() return actual length always +} + +CAsyncUrlReader::~CAsyncUrlReader() +{ + if (ThreadExists()) { + CallWorker(CMD_EXIT); + } + + if (!m_fn.IsEmpty()) { + CMultiFiles::Close(); + DeleteFile(m_fn); + } +} + +// IAsyncReader + +STDMETHODIMP CAsyncUrlReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable) +{ + if (pTotal) { + *pTotal = 0; + } + return __super::Length(nullptr, pAvailable); +} + +// CAMThread + +DWORD CAsyncUrlReader::ThreadProc() +{ + AfxSocketInit(nullptr); + + DWORD cmd = GetRequest(); + if (cmd != CMD_INIT) { + Reply((DWORD)E_FAIL); + return DWORD_ERROR; + } + + try { + CInternetSession is; + CAutoPtr fin(is.OpenURL(m_url, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_CACHE_WRITE)); + + TCHAR path[MAX_PATH], fn[MAX_PATH]; + CFile fout; + if (GetTempPath(MAX_PATH, path) && GetTempFileName(path, _T("mpc_http"), 0, fn) + && fout.Open(fn, modeCreate | modeWrite | shareDenyWrite | typeBinary)) { + m_fn = fn; + + char buff[1024]; + int len = fin->Read(buff, sizeof(buff)); + if (len > 0) { + fout.Write(buff, len); + } + + Reply(S_OK); + + while (!CheckRequest(&cmd)) { + int len2 = fin->Read(buff, sizeof(buff)); + if (len2 > 0) { + fout.Write(buff, len2); + } + } + } else { + Reply((DWORD)E_FAIL); + } + + fin->Close(); // must close it because the destructor doesn't seem to do it and we will get an exception when "is" is destroying + } catch (CInternetException* ie) { + ie->Delete(); + Reply((DWORD)E_FAIL); + } + + // + + cmd = GetRequest(); + ASSERT(cmd == CMD_EXIT); + Reply(S_OK); + + // + + m_hThread = nullptr; + + return S_OK; +} diff --git a/src/filters/parser/BaseSplitter/AsyncReader.h b/src/filters/parser/BaseSplitter/AsyncReader.h index e1ee7d8c43b..e171589ed45 100644 --- a/src/filters/parser/BaseSplitter/AsyncReader.h +++ b/src/filters/parser/BaseSplitter/AsyncReader.h @@ -1,104 +1,104 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include "MultiFiles.h" - -interface __declspec(uuid("6DDB4EE7-45A0-4459-A508-BD77B32C91B2")) - ISyncReader : - public IUnknown -{ - STDMETHOD_(void, SetBreakEvent)(HANDLE hBreakEvent) PURE; - STDMETHOD_(bool, HasErrors)() PURE; - STDMETHOD_(void, ClearErrors)() PURE; - STDMETHOD_(void, SetPTSOffset)(REFERENCE_TIME* rtPTSOffset) PURE; -}; - -interface __declspec(uuid("7D55F67A-826E-40B9-8A7D-3DF0CBBD272D")) - IFileHandle : - public IUnknown -{ - STDMETHOD_(HANDLE, GetFileHandle)() PURE; - STDMETHOD_(LPCTSTR, GetFileName)() PURE; -}; - -class CAsyncFileReader : public CUnknown, public CMultiFiles, public IAsyncReader, public ISyncReader, public IFileHandle -{ -protected: - ULONGLONG m_len; - HANDLE m_hBreakEvent; - LONG m_lOsError; // CFileException::m_lOsError - -public: - CAsyncFileReader(CString fn, HRESULT& hr); - CAsyncFileReader(CAtlList& Items, HRESULT& hr); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IAsyncReader - - STDMETHODIMP RequestAllocator(IMemAllocator* pPreferred, ALLOCATOR_PROPERTIES* pProps, IMemAllocator** ppActual) { - return E_NOTIMPL; - } - STDMETHODIMP Request(IMediaSample* pSample, DWORD_PTR dwUser) { - return E_NOTIMPL; - } - STDMETHODIMP WaitForNext(DWORD dwTimeout, IMediaSample** ppSample, DWORD_PTR* pdwUser) { - return E_NOTIMPL; - } - STDMETHODIMP SyncReadAligned(IMediaSample* pSample) { return E_NOTIMPL; } - STDMETHODIMP SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer); - STDMETHODIMP Length(LONGLONG* pTotal, LONGLONG* pAvailable); - STDMETHODIMP BeginFlush() { return E_NOTIMPL; } - STDMETHODIMP EndFlush() { return E_NOTIMPL; } - - // ISyncReader - - STDMETHODIMP_(void) SetBreakEvent(HANDLE hBreakEvent) { m_hBreakEvent = hBreakEvent; } - STDMETHODIMP_(bool) HasErrors() { return m_lOsError != 0; } - STDMETHODIMP_(void) ClearErrors() { m_lOsError = 0; } - STDMETHODIMP_(void) SetPTSOffset(REFERENCE_TIME* rtPTSOffset) { m_pCurrentPTSOffset = rtPTSOffset; }; - - // IFileHandle - - STDMETHODIMP_(HANDLE) GetFileHandle(); - STDMETHODIMP_(LPCTSTR) GetFileName(); - -}; - -class CAsyncUrlReader : public CAsyncFileReader, protected CAMThread -{ - CString m_url, m_fn; - -protected: - enum { CMD_EXIT, CMD_INIT }; - DWORD ThreadProc(); - -public: - CAsyncUrlReader(CString url, HRESULT& hr); - virtual ~CAsyncUrlReader(); - - // IAsyncReader - - STDMETHODIMP Length(LONGLONG* pTotal, LONGLONG* pAvailable); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include "MultiFiles.h" + +interface __declspec(uuid("6DDB4EE7-45A0-4459-A508-BD77B32C91B2")) + ISyncReader : + public IUnknown +{ + STDMETHOD_(void, SetBreakEvent)(HANDLE hBreakEvent) PURE; + STDMETHOD_(bool, HasErrors)() PURE; + STDMETHOD_(void, ClearErrors)() PURE; + STDMETHOD_(void, SetPTSOffset)(REFERENCE_TIME* rtPTSOffset) PURE; +}; + +interface __declspec(uuid("7D55F67A-826E-40B9-8A7D-3DF0CBBD272D")) + IFileHandle : + public IUnknown +{ + STDMETHOD_(HANDLE, GetFileHandle)() PURE; + STDMETHOD_(LPCTSTR, GetFileName)() PURE; +}; + +class CAsyncFileReader : public CUnknown, public CMultiFiles, public IAsyncReader, public ISyncReader, public IFileHandle +{ +protected: + ULONGLONG m_len; + HANDLE m_hBreakEvent; + LONG m_lOsError; // CFileException::m_lOsError + +public: + CAsyncFileReader(CString fn, HRESULT& hr); + CAsyncFileReader(CAtlList& Items, HRESULT& hr); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IAsyncReader + + STDMETHODIMP RequestAllocator(IMemAllocator* pPreferred, ALLOCATOR_PROPERTIES* pProps, IMemAllocator** ppActual) { + return E_NOTIMPL; + } + STDMETHODIMP Request(IMediaSample* pSample, DWORD_PTR dwUser) { + return E_NOTIMPL; + } + STDMETHODIMP WaitForNext(DWORD dwTimeout, IMediaSample** ppSample, DWORD_PTR* pdwUser) { + return E_NOTIMPL; + } + STDMETHODIMP SyncReadAligned(IMediaSample* pSample) { return E_NOTIMPL; } + STDMETHODIMP SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer); + STDMETHODIMP Length(LONGLONG* pTotal, LONGLONG* pAvailable); + STDMETHODIMP BeginFlush() { return E_NOTIMPL; } + STDMETHODIMP EndFlush() { return E_NOTIMPL; } + + // ISyncReader + + STDMETHODIMP_(void) SetBreakEvent(HANDLE hBreakEvent) { m_hBreakEvent = hBreakEvent; } + STDMETHODIMP_(bool) HasErrors() { return m_lOsError != 0; } + STDMETHODIMP_(void) ClearErrors() { m_lOsError = 0; } + STDMETHODIMP_(void) SetPTSOffset(REFERENCE_TIME* rtPTSOffset) { m_pCurrentPTSOffset = rtPTSOffset; }; + + // IFileHandle + + STDMETHODIMP_(HANDLE) GetFileHandle(); + STDMETHODIMP_(LPCTSTR) GetFileName(); + +}; + +class CAsyncUrlReader : public CAsyncFileReader, protected CAMThread +{ + CString m_url, m_fn; + +protected: + enum { CMD_EXIT, CMD_INIT }; + DWORD ThreadProc(); + +public: + CAsyncUrlReader(CString url, HRESULT& hr); + virtual ~CAsyncUrlReader(); + + // IAsyncReader + + STDMETHODIMP Length(LONGLONG* pTotal, LONGLONG* pAvailable); +}; diff --git a/src/filters/parser/BaseSplitter/BaseSplitter.cpp b/src/filters/parser/BaseSplitter/BaseSplitter.cpp index f2644dc051a..656c464fdd7 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitter.cpp +++ b/src/filters/parser/BaseSplitter/BaseSplitter.cpp @@ -1,1636 +1,1636 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "../../../DSUtil/DSUtil.h" -#include "moreuuids.h" -#include "../../switcher/AudioSwitcher/AudioSwitcher.h" -#include "BaseSplitter.h" -#include - - -// -// CPacketQueue2 -// - -CPacketQueue2::CPacketQueue2() : m_size(0) -{ -} - -void CPacketQueue2::Add(CAutoPtr p) -{ - CAutoLock cAutoLock(this); - - if (p) { - m_size += p->GetDataSize(); - - if (p->bAppendable && !p->bDiscontinuity && !p->pmt - && p->rtStart == Packet::INVALID_TIME - && !IsEmpty() && GetTail()->rtStart != Packet::INVALID_TIME) { - Packet* tail = GetTail(); - size_t oldsize = tail->GetCount(); - size_t newsize = tail->GetCount() + p->GetCount(); - tail->SetCount(newsize, std::max(1024, (int)newsize)); // doubles the reserved buffer size - memcpy(tail->GetData() + oldsize, p->GetData(), p->GetCount()); - /* - GetTail()->Append(*p); // too slow - */ - return; - } - } - - AddTail(p); -} - -CAutoPtr CPacketQueue2::Remove() -{ - CAutoLock cAutoLock(this); - ASSERT(__super::GetCount() > 0); - CAutoPtr p(RemoveHead().Detach()); - if (p) { - m_size -= p->GetDataSize(); - } - return p; -} - -void CPacketQueue2::RemoveAll() -{ - CAutoLock cAutoLock(this); - m_size = 0; - __super::RemoveAll(); -} - -int CPacketQueue2::GetCount() -{ - CAutoLock cAutoLock(this); - return (int)__super::GetCount(); -} - -int CPacketQueue2::GetSize() -{ - CAutoLock cAutoLock(this); - return m_size; -} - -// -// CBaseSplitterInputPin -// - -CBaseSplitterInputPin::CBaseSplitterInputPin(LPCTSTR pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT) -{ -} - -CBaseSplitterInputPin::~CBaseSplitterInputPin() -{ -} - -HRESULT CBaseSplitterInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader) -{ - CheckPointer(ppAsyncReader, E_POINTER); - *ppAsyncReader = nullptr; - CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED); - (*ppAsyncReader = m_pAsyncReader)->AddRef(); - return S_OK; -} - -STDMETHODIMP CBaseSplitterInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CBaseSplitterInputPin::CheckMediaType(const CMediaType* pmt) -{ - return S_OK; - /* - return pmt->majortype == MEDIATYPE_Stream - ? S_OK - : E_INVALIDARG; - */ -} - -HRESULT CBaseSplitterInputPin::CheckConnect(IPin* pPin) -{ - HRESULT hr; - if (FAILED(hr = __super::CheckConnect(pPin))) { - return hr; - } - - return CComQIPtr(pPin) ? S_OK : E_NOINTERFACE; -} - -HRESULT CBaseSplitterInputPin::BreakConnect() -{ - HRESULT hr; - - if (FAILED(hr = __super::BreakConnect())) { - return hr; - } - - if (FAILED(hr = (static_cast(m_pFilter))->BreakConnect(PINDIR_INPUT, this))) { - return hr; - } - - m_pAsyncReader.Release(); - - return S_OK; -} - -HRESULT CBaseSplitterInputPin::CompleteConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CompleteConnect(pPin))) { - return hr; - } - - CheckPointer(pPin, E_POINTER); - m_pAsyncReader = pPin; - CheckPointer(m_pAsyncReader, E_NOINTERFACE); - - if (FAILED(hr = (static_cast(m_pFilter))->CompleteConnect(PINDIR_INPUT, this))) { - return hr; - } - - return S_OK; -} - -STDMETHODIMP CBaseSplitterInputPin::BeginFlush() -{ - return E_UNEXPECTED; -} - -STDMETHODIMP CBaseSplitterInputPin::EndFlush() -{ - return E_UNEXPECTED; -} - -// -// CBaseSplitterOutputPin -// - -CBaseSplitterOutputPin::CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers, int QueueMaxPackets) - : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName) - , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it - , m_fFlushing(false) - , m_fFlushed(false) - , m_eEndFlush(TRUE) - , m_QueueMaxPackets(QueueMaxPackets) - , m_rtStart(0) -{ - m_mts.Copy(mts); - m_nBuffers = std::max(nBuffers, 1); -} - -CBaseSplitterOutputPin::CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers, int QueueMaxPackets) - : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName) - , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it - , m_fFlushing(false) - , m_fFlushed(false) - , m_eEndFlush(TRUE) - , m_QueueMaxPackets(QueueMaxPackets) - , m_rtStart(0) -{ - m_nBuffers = std::max(nBuffers, 1); -} - -CBaseSplitterOutputPin::~CBaseSplitterOutputPin() -{ -} - -STDMETHODIMP CBaseSplitterOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - // riid == __uuidof(IMediaSeeking) ? m_pFilter->QueryInterface(riid, ppv) : - QI(IMediaSeeking) - QI(IPropertyBag) - QI(IPropertyBag2) - QI(IDSMPropertyBag) - QI(IBitRateInfo) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CBaseSplitterOutputPin::SetName(LPCWSTR pName) -{ - CheckPointer(pName, E_POINTER); - if (m_pName) { - delete [] m_pName; - } - m_pName = DEBUG_NEW WCHAR[wcslen(pName) + 1]; - CheckPointer(m_pName, E_OUTOFMEMORY); - wcscpy_s(m_pName, wcslen(pName) + 1, pName); - return S_OK; -} - -HRESULT CBaseSplitterOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = std::max(pProperties->cBuffers, m_nBuffers); - pProperties->cbBuffer = std::max((long)m_mt.lSampleSize, 1l); - - // TODO: is this still needed ? - if (m_mt.subtype == MEDIASUBTYPE_Vorbis && m_mt.formattype == FORMAT_VorbisFormat) { - // oh great, the oggds vorbis decoder assumes there will be two at least, stupid thing... - pProperties->cBuffers = std::max(pProperties->cBuffers, 2l); - } - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CBaseSplitterOutputPin::CheckMediaType(const CMediaType* pmt) -{ - for (size_t i = 0; i < m_mts.GetCount(); i++) { - if (*pmt == m_mts[i]) { - return S_OK; - } - } - - return E_INVALIDARG; -} - -HRESULT CBaseSplitterOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CAutoLock cAutoLock(m_pLock); - - if (iPosition < 0) { - return E_INVALIDARG; - } - if ((size_t)iPosition >= m_mts.GetCount()) { - return VFW_S_NO_MORE_ITEMS; - } - - *pmt = m_mts[iPosition]; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} - -// - -HRESULT CBaseSplitterOutputPin::Active() -{ - CAutoLock cAutoLock(m_pLock); - - if (m_Connected) { - Create(); - } - - return __super::Active(); -} - -HRESULT CBaseSplitterOutputPin::Inactive() -{ - CAutoLock cAutoLock(m_pLock); - - if (ThreadExists()) { - CallWorker(CMD_EXIT); - } - - return __super::Inactive(); -} - -HRESULT CBaseSplitterOutputPin::DeliverBeginFlush() -{ - m_eEndFlush.Reset(); - m_fFlushed = false; - m_fFlushing = true; - m_hrDeliver = S_FALSE; - m_queue.RemoveAll(); - HRESULT hr = IsConnected() ? GetConnected()->BeginFlush() : S_OK; - if (S_OK != hr) { - m_eEndFlush.Set(); - } - return hr; -} - -HRESULT CBaseSplitterOutputPin::DeliverEndFlush() -{ - if (!ThreadExists()) { - return S_FALSE; - } - HRESULT hr = IsConnected() ? GetConnected()->EndFlush() : S_OK; - m_hrDeliver = S_OK; - m_fFlushing = false; - m_fFlushed = true; - m_eEndFlush.Set(); - return hr; -} - -HRESULT CBaseSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - m_BitRate.rtLastDeliverTime = Packet::INVALID_TIME; - if (m_fFlushing) { - return S_FALSE; - } - m_rtStart = tStart; - if (!ThreadExists()) { - return S_FALSE; - } - HRESULT hr = __super::DeliverNewSegment(tStart, tStop, dRate); - if (S_OK != hr) { - return hr; - } - MakeISCRHappy(); - return hr; -} - -int CBaseSplitterOutputPin::QueueCount() -{ - return m_queue.GetCount(); -} - -int CBaseSplitterOutputPin::QueueSize() -{ - return m_queue.GetSize(); -} - -HRESULT CBaseSplitterOutputPin::QueueEndOfStream() -{ - CAutoPtr p; - return QueuePacket(p); // NULL means EndOfStream -} - -HRESULT CBaseSplitterOutputPin::QueuePacket(CAutoPtr p) -{ - if (!ThreadExists()) { - return S_FALSE; - } - - while (S_OK == m_hrDeliver - && ((m_queue.GetCount() > (m_QueueMaxPackets * 2) || m_queue.GetSize() > (MAXPACKETSIZE * 3 / 2)) - || ((m_queue.GetCount() > m_QueueMaxPackets || m_queue.GetSize() > MAXPACKETSIZE) && !(static_cast(m_pFilter))->IsAnyPinDrying()))) { - Sleep(10); - } - - if (S_OK != m_hrDeliver) { - return m_hrDeliver; - } - - m_queue.Add(p); - - return m_hrDeliver; -} - -bool CBaseSplitterOutputPin::IsDiscontinuous() -{ - return m_mt.majortype == MEDIATYPE_Text - || m_mt.majortype == MEDIATYPE_ScriptCommand - || m_mt.majortype == MEDIATYPE_Subtitle - || m_mt.subtype == MEDIASUBTYPE_DVD_SUBPICTURE - || m_mt.subtype == MEDIASUBTYPE_CVD_SUBPICTURE - || m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE; -} - -bool CBaseSplitterOutputPin::IsActive() -{ - CComPtr pPin = this; - do { - CComPtr pPinTo; - CComQIPtr pSSIP; - if (S_OK == pPin->ConnectedTo(&pPinTo) && (pSSIP = pPinTo) && !pSSIP->IsActive()) { - return false; - } - pPin = GetFirstPin(GetFilterFromPin(pPinTo), PINDIR_OUTPUT); - } while (pPin); - - return true; -} - -DWORD CBaseSplitterOutputPin::ThreadProc() -{ - SetThreadName(DWORD(-1), "CBaseSplitterOutputPin"); - m_hrDeliver = S_OK; - m_fFlushing = m_fFlushed = false; - m_eEndFlush.Set(); - - // fix for Microsoft DTV-DVD Video Decoder - video freeze after STOP/PLAY - bool iHaaliRenderConnect = false; - CComPtr pPinTo = this, pTmp; - while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { - pTmp = nullptr; - CComPtr pBF = GetFilterFromPin(pPinTo); - if (GetCLSID(pBF) == CLSID_DXR) { // Haali Renderer - iHaaliRenderConnect = true; - break; - } - pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); - } - if (IsConnected() && !iHaaliRenderConnect) { - GetConnected()->BeginFlush(); - GetConnected()->EndFlush(); - } - - for (;;) { - Sleep(1); - - DWORD cmd; - if (CheckRequest(&cmd)) { - m_hThread = nullptr; - cmd = GetRequest(); - Reply(S_OK); - ASSERT(cmd == CMD_EXIT); - return 0; - } - - int cnt = 0; - do { - CAutoPtr p; - - { - CAutoLock cAutoLock(&m_queue); - if ((cnt = m_queue.GetCount()) > 0) { - p.Attach(m_queue.Remove().Detach()); - } - } - - if (S_OK == m_hrDeliver && cnt > 0) { - ASSERT(!m_fFlushing); - - m_fFlushed = false; - - // flushing can still start here, to release a blocked deliver call - - HRESULT hr = p - ? DeliverPacket(p) - : DeliverEndOfStream(); - - m_eEndFlush.Wait(); // .. so we have to wait until it is done - - if (hr != S_OK && !m_fFlushed) { // and only report the error in m_hrDeliver if we didn't flush the stream - // CAutoLock cAutoLock(&m_csQueueLock); - m_hrDeliver = hr; - break; - } - } - } while (--cnt > 0); - } -} - -HRESULT CBaseSplitterOutputPin::DeliverPacket(CAutoPtr p) -{ - HRESULT hr; - - long nBytes = (long)p->GetCount(); - - if (nBytes == 0) { - return S_OK; - } - - m_BitRate.nBytesSinceLastDeliverTime += nBytes; - - if (p->rtStart != Packet::INVALID_TIME) { - if (m_BitRate.rtLastDeliverTime == Packet::INVALID_TIME) { - m_BitRate.rtLastDeliverTime = p->rtStart; - m_BitRate.nBytesSinceLastDeliverTime = 0; - } - - if (m_BitRate.rtLastDeliverTime + 10000000 < p->rtStart) { - REFERENCE_TIME rtDiff = p->rtStart - m_BitRate.rtLastDeliverTime; - - double dSecs, dBits; - - dSecs = rtDiff / 10000000.0; - dBits = 8.0 * m_BitRate.nBytesSinceLastDeliverTime; - m_BitRate.nCurrentBitRate = (DWORD)(dBits / dSecs); - - m_BitRate.rtTotalTimeDelivered += rtDiff; - m_BitRate.nTotalBytesDelivered += m_BitRate.nBytesSinceLastDeliverTime; - - dSecs = m_BitRate.rtTotalTimeDelivered / 10000000.0; - dBits = 8.0 * m_BitRate.nTotalBytesDelivered; - m_BitRate.nAverageBitRate = (DWORD)(dBits / dSecs); - - m_BitRate.rtLastDeliverTime = p->rtStart; - m_BitRate.nBytesSinceLastDeliverTime = 0; - /* - TRACE(_T("[%d] c: %d kbps, a: %d kbps\n"), - p->TrackNumber, - (m_brs.nCurrentBitRate+500)/1000, - (m_brs.nAverageBitRate+500)/1000); - */ - } - - double dRate = 1.0; - if (SUCCEEDED((static_cast(m_pFilter))->GetRate(&dRate))) { - p->rtStart = (REFERENCE_TIME)((double)p->rtStart / dRate); - p->rtStop = (REFERENCE_TIME)((double)p->rtStop / dRate); - } - } - - do { - CComPtr pSample; - if (S_OK != (hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0))) { - break; - } - - if (nBytes > pSample->GetSize()) { - pSample.Release(); - - ALLOCATOR_PROPERTIES props, actual; - if (S_OK != (hr = m_pAllocator->GetProperties(&props))) { - break; - } - props.cbBuffer = nBytes * 3 / 2; - - if (props.cBuffers > 1) { - if (S_OK != (hr = __super::DeliverBeginFlush())) { - break; - } - if (S_OK != (hr = __super::DeliverEndFlush())) { - break; - } - } - - if (S_OK != (hr = m_pAllocator->Decommit())) { - break; - } - if (S_OK != (hr = m_pAllocator->SetProperties(&props, &actual))) { - break; - } - if (S_OK != (hr = m_pAllocator->Commit())) { - break; - } - if (S_OK != (hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0))) { - break; - } - } - - if (p->pmt) { - pSample->SetMediaType(p->pmt); - p->bDiscontinuity = true; - - CAutoLock cAutoLock(m_pLock); - m_mts.RemoveAll(); - m_mts.Add(*p->pmt); - } - - bool fTimeValid = p->rtStart != Packet::INVALID_TIME; - -#if defined(_DEBUG) && 0 - TRACE(_T("[%d]: d%d s%d p%d, b=%d, [%20I64d - %20I64d]\n"), - p->TrackNumber, - p->bDiscontinuity, p->bSyncPoint, fTimeValid && p->rtStart < 0, - nBytes, p->rtStart, p->rtStop); -#endif - - ASSERT(!p->bSyncPoint || fTimeValid); - - BYTE* pData = nullptr; - if (S_OK != (hr = pSample->GetPointer(&pData)) || !pData) { - break; - } - memcpy(pData, p->GetData(), nBytes); - if (S_OK != (hr = pSample->SetActualDataLength(nBytes))) { - break; - } - if (S_OK != (hr = pSample->SetTime(fTimeValid ? &p->rtStart : nullptr, fTimeValid ? &p->rtStop : nullptr))) { - break; - } - if (S_OK != (hr = pSample->SetMediaTime(nullptr, nullptr))) { - break; - } - if (S_OK != (hr = pSample->SetDiscontinuity(p->bDiscontinuity))) { - break; - } - if (S_OK != (hr = pSample->SetSyncPoint(p->bSyncPoint))) { - break; - } - if (S_OK != (hr = pSample->SetPreroll(fTimeValid && p->rtStart < 0))) { - break; - } - if (S_OK != (hr = Deliver(pSample))) { - break; - } - } while (false); - - return hr; -} - -void CBaseSplitterOutputPin::MakeISCRHappy() -{ - CComPtr pPinTo = this, pTmp; - while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { - pTmp = nullptr; - - CComPtr pBF = GetFilterFromPin(pPinTo); - - if (GetCLSID(pBF) == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) { // ISCR - CAutoPtr p(DEBUG_NEW Packet()); - p->TrackNumber = DWORD_ERROR; - p->rtStart = -1; - p->rtStop = 0; - p->bSyncPoint = FALSE; - p->SetData(" ", 2); - QueuePacket(p); - break; - } - - pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); - } -} - -HRESULT CBaseSplitterOutputPin::GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags) -{ - return __super::GetDeliveryBuffer(ppSample, pStartTime, pEndTime, dwFlags); -} - -HRESULT CBaseSplitterOutputPin::Deliver(IMediaSample* pSample) -{ - return __super::Deliver(pSample); -} - -// IMediaSeeking - -STDMETHODIMP CBaseSplitterOutputPin::GetCapabilities(DWORD* pCapabilities) -{ - return (static_cast(m_pFilter))->GetCapabilities(pCapabilities); -} - -STDMETHODIMP CBaseSplitterOutputPin::CheckCapabilities(DWORD* pCapabilities) -{ - return (static_cast(m_pFilter))->CheckCapabilities(pCapabilities); -} - -STDMETHODIMP CBaseSplitterOutputPin::IsFormatSupported(const GUID* pFormat) -{ - return (static_cast(m_pFilter))->IsFormatSupported(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::QueryPreferredFormat(GUID* pFormat) -{ - return (static_cast(m_pFilter))->QueryPreferredFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetTimeFormat(GUID* pFormat) -{ - return (static_cast(m_pFilter))->GetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::IsUsingTimeFormat(const GUID* pFormat) -{ - return (static_cast(m_pFilter))->IsUsingTimeFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::SetTimeFormat(const GUID* pFormat) -{ - return (static_cast(m_pFilter))->SetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetDuration(LONGLONG* pDuration) -{ - return (static_cast(m_pFilter))->GetDuration(pDuration); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetStopPosition(LONGLONG* pStop) -{ - return (static_cast(m_pFilter))->GetStopPosition(pStop); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetCurrentPosition(LONGLONG* pCurrent) -{ - return (static_cast(m_pFilter))->GetCurrentPosition(pCurrent); -} - -STDMETHODIMP CBaseSplitterOutputPin::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return (static_cast(m_pFilter))->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return (static_cast(m_pFilter))->SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return (static_cast(m_pFilter))->GetPositions(pCurrent, pStop); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return (static_cast(m_pFilter))->GetAvailable(pEarliest, pLatest); -} - -STDMETHODIMP CBaseSplitterOutputPin::SetRate(double dRate) -{ - return (static_cast(m_pFilter))->SetRate(dRate); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetRate(double* pdRate) -{ - return (static_cast(m_pFilter))->GetRate(pdRate); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetPreroll(LONGLONG* pllPreroll) -{ - return (static_cast(m_pFilter))->GetPreroll(pllPreroll); -} - -// -// CBaseSplitterFilter -// - -CBaseSplitterFilter::CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid, int QueueMaxPackets) - : CBaseFilter(pName, pUnk, this, clsid) - , m_nOpenProgress(100) - , m_fAbort(false) - , m_rtDuration(0) - , m_rtStart(0) - , m_rtStop(0) - , m_rtCurrent(0) - , m_rtNewStart(0) - , m_rtNewStop(0) - , m_dRate(1.0) - , m_fFlushing(false) - , m_priority(THREAD_PRIORITY_NORMAL) - , m_QueueMaxPackets(QueueMaxPackets) - , m_rtLastStart(_I64_MIN) - , m_rtLastStop(_I64_MIN) -{ - if (phr) { - *phr = S_OK; - } - - m_pInput.Attach(DEBUG_NEW CBaseSplitterInputPin(NAME("CBaseSplitterInputPin"), this, this, phr)); -} - -CBaseSplitterFilter::~CBaseSplitterFilter() -{ - CAutoLock cAutoLock(this); - - CAMThread::CallWorker(CMD_EXIT); - CAMThread::Close(); -} - -STDMETHODIMP CBaseSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - if (m_pInput && riid == __uuidof(IFileSourceFilter)) { - return E_NOINTERFACE; - } - - return - QI(IFileSourceFilter) - QI(IMediaSeeking) - QI(IAMOpenProgress) - QI2(IAMMediaContent) - QI2(IAMExtendedSeeking) - QI(IKeyFrameInfo) - QI(IBufferInfo) - QI(IPropertyBag) - QI(IPropertyBag2) - QI(IDSMPropertyBag) - QI(IDSMResourceBag) - QI(IDSMChapterBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -CBaseSplitterOutputPin* CBaseSplitterFilter::GetOutputPin(DWORD TrackNum) -{ - CAutoLock cAutoLock(&m_csPinMap); - - CBaseSplitterOutputPin* pPin = nullptr; - m_pPinMap.Lookup(TrackNum, pPin); - return pPin; -} - -DWORD CBaseSplitterFilter::GetOutputTrackNum(CBaseSplitterOutputPin* pPin) -{ - CAutoLock cAutoLock(&m_csPinMap); - - POSITION pos = m_pPinMap.GetStartPosition(); - while (pos) { - DWORD TrackNum; - CBaseSplitterOutputPin* pPinTmp; - m_pPinMap.GetNextAssoc(pos, TrackNum, pPinTmp); - if (pPinTmp == pPin) { - return TrackNum; - } - } - - return DWORD_ERROR; -} - -HRESULT CBaseSplitterFilter::RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt) -{ - CAutoLock cAutoLock(&m_csPinMap); - - CBaseSplitterOutputPin* pPin; - if (m_pPinMap.Lookup(TrackNumSrc, pPin)) { - if (CComQIPtr pPinTo = pPin->GetConnected()) { - if (pmt && S_OK != pPinTo->QueryAccept(pmt)) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } - - m_pPinMap.RemoveKey(TrackNumSrc); - m_pPinMap[TrackNumDst] = pPin; - - if (pmt) { - CAutoLock cAutoLock2(&m_csmtnew); - m_mtnew[TrackNumDst] = *pmt; - } - - return S_OK; - } - - return E_FAIL; -} - -HRESULT CBaseSplitterFilter::AddOutputPin(DWORD TrackNum, CAutoPtr pPin) -{ - CAutoLock cAutoLock(&m_csPinMap); - - if (!pPin) { - return E_INVALIDARG; - } - m_pPinMap[TrackNum] = pPin; - m_pOutputs.AddTail(pPin); - return S_OK; -} - -HRESULT CBaseSplitterFilter::DeleteOutputs() -{ - m_rtDuration = 0; - - m_pRetiredOutputs.RemoveAll(); - - CAutoLock cAutoLockF(this); - if (m_State != State_Stopped) { - return VFW_E_NOT_STOPPED; - } - - while (m_pOutputs.GetCount()) { - CAutoPtr pPin(m_pOutputs.RemoveHead().Detach()); - if (IPin* pPinTo = pPin->GetConnected()) { - pPinTo->Disconnect(); - } - pPin->Disconnect(); - // we can't just let it be deleted now, something might have AddRefed on it (graphedit...) - m_pRetiredOutputs.AddTail(pPin); - } - - CAutoLock cAutoLockPM(&m_csPinMap); - m_pPinMap.RemoveAll(); - - CAutoLock cAutoLockMT(&m_csmtnew); - m_mtnew.RemoveAll(); - - RemoveAll(); - ResRemoveAll(); - ChapRemoveAll(); - - m_fontinst.UninstallFonts(); - - m_pSyncReader.Release(); - - return S_OK; -} - -void CBaseSplitterFilter::DeliverBeginFlush() -{ - m_fFlushing = true; - POSITION pos = m_pOutputs.GetHeadPosition(); - while (pos) { - m_pOutputs.GetNext(pos)->DeliverBeginFlush(); - } -} - -void CBaseSplitterFilter::DeliverEndFlush() -{ - POSITION pos = m_pOutputs.GetHeadPosition(); - while (pos) { - m_pOutputs.GetNext(pos)->DeliverEndFlush(); - } - m_fFlushing = false; - m_eEndFlush.Set(); -} - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CBaseSplitterFilter::ThreadProc() -{ - if (m_pSyncReader) { - m_pSyncReader->SetBreakEvent(GetRequestHandle()); - } - - if (!DemuxInit()) { - for (;;) { - DWORD cmd = GetRequest(); - if (cmd == CMD_EXIT) { - CAMThread::m_hThread = nullptr; - } - Reply(S_OK); - if (cmd == CMD_EXIT) { - return 0; - } - } - } - - m_eEndFlush.Set(); - m_fFlushing = false; - - for (DWORD cmd = DWORD_ERROR; ; cmd = GetRequest()) { - if (cmd == CMD_EXIT) { - m_hThread = nullptr; - Reply(S_OK); - return 0; - } - - SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); - - m_rtStart = m_rtNewStart; - m_rtStop = m_rtNewStop; - - DemuxSeek(m_rtStart); - - if (cmd != DWORD_ERROR) { - Reply(S_OK); - } - - m_eEndFlush.Wait(); - - m_pActivePins.RemoveAll(); - - POSITION pos = m_pOutputs.GetHeadPosition(); - while (pos && !m_fFlushing) { - CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos); - if (pPin->IsConnected() && pPin->IsActive()) { - m_pActivePins.AddTail(pPin); - pPin->DeliverNewSegment(m_rtStart, m_rtStop, m_dRate); - } - } - - do { - m_bDiscontinuitySent.RemoveAll(); - } while (!DemuxLoop()); - - pos = m_pActivePins.GetHeadPosition(); - while (pos && !CheckRequest(&cmd)) { - m_pActivePins.GetNext(pos)->QueueEndOfStream(); - } - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -HRESULT CBaseSplitterFilter::DeliverPacket(CAutoPtr p) -{ - HRESULT hr = S_FALSE; - - CBaseSplitterOutputPin* pPin = GetOutputPin(p->TrackNumber); - if (!pPin || !pPin->IsConnected() || !m_pActivePins.Find(pPin)) { - return S_FALSE; - } - - if (p->rtStart != Packet::INVALID_TIME) { - m_rtCurrent = p->rtStart; - - p->rtStart -= m_rtStart; - p->rtStop -= m_rtStart; - - ASSERT(p->rtStart <= p->rtStop); - } - - { - CAutoLock cAutoLock(&m_csmtnew); - - CMediaType mt; - if (m_mtnew.Lookup(p->TrackNumber, mt)) { - p->pmt = CreateMediaType(&mt); - m_mtnew.RemoveKey(p->TrackNumber); - } - } - - if (!m_bDiscontinuitySent.Find(p->TrackNumber)) { - p->bDiscontinuity = TRUE; - } - - DWORD TrackNumber = p->TrackNumber; - BOOL bDiscontinuity = p->bDiscontinuity; - -#if defined(_DEBUG) && 0 - TRACE(_T("[%d]: d%d s%d p%d, b=%d, [%20I64d - %20I64d]\n"), - p->TrackNumber, - p->bDiscontinuity, p->bSyncPoint, p->rtStart != Packet::INVALID_TIME && p->rtStart < 0, - p->GetCount(), p->rtStart, p->rtStop); -#endif - - hr = pPin->QueuePacket(p); - - if (S_OK != hr) { - if (POSITION pos = m_pActivePins.Find(pPin)) { - m_pActivePins.RemoveAt(pos); - } - - if (!m_pActivePins.IsEmpty()) { // only die when all pins are down - hr = S_OK; - } - - return hr; - } - - if (bDiscontinuity) { - m_bDiscontinuitySent.AddTail(TrackNumber); - } - - return hr; -} - -bool CBaseSplitterFilter::IsAnyPinDrying() -{ - int totalcount = 0, totalsize = 0; - - POSITION pos = m_pActivePins.GetHeadPosition(); - while (pos) { - CBaseSplitterOutputPin* pPin = m_pActivePins.GetNext(pos); - int count = pPin->QueueCount(); - int size = pPin->QueueSize(); - if (!pPin->IsDiscontinuous() && (count < MINPACKETS || size < MINPACKETSIZE)) { - // if (m_priority != THREAD_PRIORITY_ABOVE_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3)) - if (m_priority != THREAD_PRIORITY_BELOW_NORMAL && (count < MINPACKETS / 3 || size < MINPACKETSIZE / 3)) { - // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_ABOVE_NORMAL); - POSITION pos2 = m_pOutputs.GetHeadPosition(); - while (pos2) { - m_pOutputs.GetNext(pos2)->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); - } - m_priority = THREAD_PRIORITY_BELOW_NORMAL; - } - return true; - } - totalcount += count; - totalsize += size; - } - - if (m_priority != THREAD_PRIORITY_NORMAL && (totalcount > m_QueueMaxPackets * 2 / 3 || totalsize > MAXPACKETSIZE * 2 / 3)) { - // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); - POSITION pos2 = m_pOutputs.GetHeadPosition(); - while (pos2) { - m_pOutputs.GetNext(pos2)->SetThreadPriority(THREAD_PRIORITY_NORMAL); - } - m_priority = THREAD_PRIORITY_NORMAL; - } - - if (totalcount < m_QueueMaxPackets && totalsize < MAXPACKETSIZE) { - return true; - } - - return false; -} - -HRESULT CBaseSplitterFilter::BreakConnect(PIN_DIRECTION dir, CBasePin* pPin) -{ - CheckPointer(pPin, E_POINTER); - - if (dir == PINDIR_INPUT) { - DeleteOutputs(); - } else if (dir == PINDIR_OUTPUT) { - } else { - return E_UNEXPECTED; - } - - return S_OK; -} - -HRESULT CBaseSplitterFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin) -{ - CheckPointer(pPin, E_POINTER); - - if (dir == PINDIR_INPUT) { - CBaseSplitterInputPin* pIn = static_cast(pPin); - - HRESULT hr; - - CComPtr pAsyncReader; - if (FAILED(hr = pIn->GetAsyncReader(&pAsyncReader)) - || FAILED(hr = DeleteOutputs()) - || FAILED(hr = CreateOutputs(pAsyncReader))) { - return hr; - } - - ChapSort(); - - m_pSyncReader = pAsyncReader; - } else if (dir == PINDIR_OUTPUT) { - m_pRetiredOutputs.RemoveAll(); - } else { - return E_UNEXPECTED; - } - - return S_OK; -} - -int CBaseSplitterFilter::GetPinCount() -{ - return (m_pInput ? 1 : 0) + (int)m_pOutputs.GetCount(); -} - -CBasePin* CBaseSplitterFilter::GetPin(int n) -{ - CAutoLock cAutoLock(this); - - if (n >= 0 && n < (int)m_pOutputs.GetCount()) { - if (POSITION pos = m_pOutputs.FindIndex(n)) { - return m_pOutputs.GetAt(pos); - } - } - - if (n == (int)m_pOutputs.GetCount() && m_pInput) { - return m_pInput; - } - - return nullptr; -} - -STDMETHODIMP CBaseSplitterFilter::Stop() -{ - CAutoLock cAutoLock(this); - - DeliverBeginFlush(); - CallWorker(CMD_EXIT); - DeliverEndFlush(); - - HRESULT hr; - if (FAILED(hr = __super::Stop())) { - return hr; - } - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::Pause() -{ - CAutoLock cAutoLock(this); - - FILTER_STATE fs = m_State; - - HRESULT hr; - if (FAILED(hr = __super::Pause())) { - return hr; - } - - if (fs == State_Stopped) { - Create(); - } - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - if (FAILED(hr = __super::Run(tStart))) { - return hr; - } - - return S_OK; -} - -// IFileSourceFilter - -STDMETHODIMP CBaseSplitterFilter::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - CheckPointer(pszFileName, E_POINTER); - - m_fn = pszFileName; - HRESULT hr = E_FAIL; - CComPtr pAsyncReader; - CAtlList Items; - CAtlList Chapters; - - if (BuildPlaylist(pszFileName, Items)) { - pAsyncReader = (IAsyncReader*)DEBUG_NEW CAsyncFileReader(Items, hr); - } else { - pAsyncReader = (IAsyncReader*)DEBUG_NEW CAsyncFileReader(CString(pszFileName), hr); - } - - if (FAILED(hr) - || FAILED(hr = DeleteOutputs()) - || FAILED(hr = CreateOutputs(pAsyncReader))) { - m_fn.Empty(); - return hr; - } - - if (BuildChapters(pszFileName, Items, Chapters)) { - POSITION pos = Chapters.GetHeadPosition(); - int i = 1; - while (pos) { - CString str; - CHdmvClipInfo::PlaylistChapter& chap = Chapters.GetNext(pos); - if (chap.m_nMarkType == CHdmvClipInfo::EntryMark) { - str.Format(_T("Chapter %d"), i); - ChapAppend(chap.m_rtTimestamp, str); - i++; - } - } - } - - ChapSort(); - - m_pSyncReader = pAsyncReader; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - return S_OK; -} - -LPCTSTR CBaseSplitterFilter::GetPartFilename(IAsyncReader* pAsyncReader) -{ - CComQIPtr pFH = pAsyncReader; - return pFH ? pFH->GetFileName() : (LPCWSTR)m_fn; -} - -// IMediaSeeking - -STDMETHODIMP CBaseSplitterFilter::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration - | AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanSeekForwards | AM_SEEKING_CanSeekBackwards; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - if (*pCapabilities == 0) { - return S_OK; - } - DWORD caps; - GetCapabilities(&caps); - if ((caps&*pCapabilities) == 0) { - return E_FAIL; - } - if (caps == *pCapabilities) { - return S_OK; - } - return S_FALSE; -} - -STDMETHODIMP CBaseSplitterFilter::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseSplitterFilter::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterFilter::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CBaseSplitterFilter::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CBaseSplitterFilter::GetDuration(LONGLONG* pDuration) -{ - CheckPointer(pDuration, E_POINTER); - *pDuration = m_rtDuration; - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetStopPosition(LONGLONG* pStop) -{ - return GetDuration(pStop); -} - -STDMETHODIMP CBaseSplitterFilter::GetCurrentPosition(LONGLONG* pCurrent) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseSplitterFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseSplitterFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags); -} - -STDMETHODIMP CBaseSplitterFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - if (pCurrent) { - *pCurrent = m_rtCurrent; - } - if (pStop) { - *pStop = m_rtStop; - } - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - if (pEarliest) { - *pEarliest = 0; - } - return GetDuration(pLatest); -} - -STDMETHODIMP CBaseSplitterFilter::SetRate(double dRate) -{ - HRESULT hr = E_INVALIDARG; - - if (dRate > 0.0) { - m_dRate = dRate; - hr = S_OK; - } - - return hr; -} - -STDMETHODIMP CBaseSplitterFilter::GetRate(double* pdRate) -{ - CheckPointer(pdRate, E_POINTER); - - *pdRate = m_dRate; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetPreroll(LONGLONG* pllPreroll) -{ - CheckPointer(pllPreroll, E_POINTER); - - *pllPreroll = 0; - - return S_OK; -} - -HRESULT CBaseSplitterFilter::SetPositionsInternal(void* id, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - CAutoLock cAutoLock(this); - - if (!pCurrent && !pStop - || (dwCurrentFlags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning - && (dwStopFlags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning) { - return S_OK; - } - - REFERENCE_TIME rtCurrent = m_rtCurrent; - REFERENCE_TIME rtStop = m_rtStop; - - if (pCurrent) - switch (dwCurrentFlags & AM_SEEKING_PositioningBitsMask) { - case AM_SEEKING_NoPositioning: - break; - case AM_SEEKING_AbsolutePositioning: - rtCurrent = *pCurrent; - break; - case AM_SEEKING_RelativePositioning: - rtCurrent = rtCurrent + *pCurrent; - break; - case AM_SEEKING_IncrementalPositioning: - rtCurrent = rtCurrent + *pCurrent; - break; - } - - if (pStop) - switch (dwStopFlags & AM_SEEKING_PositioningBitsMask) { - case AM_SEEKING_NoPositioning: - break; - case AM_SEEKING_AbsolutePositioning: - rtStop = *pStop; - break; - case AM_SEEKING_RelativePositioning: - rtStop += *pStop; - break; - case AM_SEEKING_IncrementalPositioning: - rtStop = rtCurrent + *pStop; - break; - } - - if (m_rtCurrent == rtCurrent && m_rtStop == rtStop) { - return S_OK; - } - - if (m_rtLastStart == rtCurrent && m_rtLastStop == rtStop && !m_LastSeekers.Find(id)) { - m_LastSeekers.AddTail(id); - return S_OK; - } - - m_rtLastStart = rtCurrent; - m_rtLastStop = rtStop; - m_LastSeekers.RemoveAll(); - m_LastSeekers.AddTail(id); - - DbgLog((LOG_TRACE, 0, _T("Seek Started %I64d"), rtCurrent)); - - m_rtNewStart = m_rtCurrent = rtCurrent; - m_rtNewStop = rtStop; - - if (ThreadExists()) { - DeliverBeginFlush(); - CallWorker(CMD_SEEK); - DeliverEndFlush(); - } - - DbgLog((LOG_TRACE, 0, _T("Seek Ended"))); - - return S_OK; -} - -// IAMOpenProgress - -STDMETHODIMP CBaseSplitterFilter::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent) -{ - CheckPointer(pllTotal, E_POINTER); - CheckPointer(pllCurrent, E_POINTER); - - *pllTotal = 100; - *pllCurrent = m_nOpenProgress; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::AbortOperation() -{ - m_fAbort = true; - return S_OK; -} - -// IAMMediaContent - -STDMETHODIMP CBaseSplitterFilter::get_AuthorName(BSTR* pbstrAuthorName) -{ - return GetProperty(L"AUTH", pbstrAuthorName); -} - -STDMETHODIMP CBaseSplitterFilter::get_Title(BSTR* pbstrTitle) -{ - return GetProperty(L"TITL", pbstrTitle); -} - -STDMETHODIMP CBaseSplitterFilter::get_Rating(BSTR* pbstrRating) -{ - return GetProperty(L"RTNG", pbstrRating); -} - -STDMETHODIMP CBaseSplitterFilter::get_Description(BSTR* pbstrDescription) -{ - return GetProperty(L"DESC", pbstrDescription); -} - -STDMETHODIMP CBaseSplitterFilter::get_Copyright(BSTR* pbstrCopyright) -{ - return GetProperty(L"CPYR", pbstrCopyright); -} - -// IAMExtendedSeeking - -STDMETHODIMP CBaseSplitterFilter::get_ExSeekCapabilities(long* pExCapabilities) -{ - CheckPointer(pExCapabilities, E_POINTER); - *pExCapabilities = AM_EXSEEK_CANSEEK; - if (ChapGetCount()) { - *pExCapabilities |= AM_EXSEEK_MARKERSEEK; - } - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::get_MarkerCount(long* pMarkerCount) -{ - CheckPointer(pMarkerCount, E_POINTER); - *pMarkerCount = (long)ChapGetCount(); - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::get_CurrentMarker(long* pCurrentMarker) -{ - CheckPointer(pCurrentMarker, E_POINTER); - REFERENCE_TIME rt = m_rtCurrent; - long i = ChapLookup(&rt); - if (i < 0) { - return E_FAIL; - } - *pCurrentMarker = i + 1; - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetMarkerTime(long MarkerNum, double* pMarkerTime) -{ - CheckPointer(pMarkerTime, E_POINTER); - REFERENCE_TIME rt; - if (FAILED(ChapGet((int)MarkerNum - 1, &rt))) { - return E_FAIL; - } - *pMarkerTime = (double)rt / 10000000; - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName) -{ - return ChapGet((int)MarkerNum - 1, nullptr, pbstrMarkerName); -} - -// IKeyFrameInfo - -STDMETHODIMP CBaseSplitterFilter::GetKeyFrameCount(UINT& nKFs) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs) -{ - return E_NOTIMPL; -} - -// IBufferInfo - -STDMETHODIMP_(int) CBaseSplitterFilter::GetCount() -{ - CAutoLock cAutoLock(m_pLock); - - return (int)m_pOutputs.GetCount(); -} - -STDMETHODIMP CBaseSplitterFilter::GetStatus(int i, int& samples, int& size) -{ - CAutoLock cAutoLock(m_pLock); - - if (POSITION pos = m_pOutputs.FindIndex(i)) { - CBaseSplitterOutputPin* pPin = m_pOutputs.GetAt(pos); - samples = pPin->QueueCount(); - size = pPin->QueueSize(); - return pPin->IsConnected() ? S_OK : S_FALSE; - } - - return E_INVALIDARG; -} - -STDMETHODIMP_(DWORD) CBaseSplitterFilter::GetPriority() -{ - return m_priority; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "../../../DSUtil/DSUtil.h" +#include "moreuuids.h" +#include "../../switcher/AudioSwitcher/AudioSwitcher.h" +#include "BaseSplitter.h" +#include + + +// +// CPacketQueue2 +// + +CPacketQueue2::CPacketQueue2() : m_size(0) +{ +} + +void CPacketQueue2::Add(CAutoPtr p) +{ + CAutoLock cAutoLock(this); + + if (p) { + m_size += p->GetDataSize(); + + if (p->bAppendable && !p->bDiscontinuity && !p->pmt + && p->rtStart == Packet::INVALID_TIME + && !IsEmpty() && GetTail()->rtStart != Packet::INVALID_TIME) { + Packet* tail = GetTail(); + size_t oldsize = tail->GetCount(); + size_t newsize = tail->GetCount() + p->GetCount(); + tail->SetCount(newsize, std::max(1024, (int)newsize)); // doubles the reserved buffer size + memcpy(tail->GetData() + oldsize, p->GetData(), p->GetCount()); + /* + GetTail()->Append(*p); // too slow + */ + return; + } + } + + AddTail(p); +} + +CAutoPtr CPacketQueue2::Remove() +{ + CAutoLock cAutoLock(this); + ASSERT(__super::GetCount() > 0); + CAutoPtr p(RemoveHead().Detach()); + if (p) { + m_size -= p->GetDataSize(); + } + return p; +} + +void CPacketQueue2::RemoveAll() +{ + CAutoLock cAutoLock(this); + m_size = 0; + __super::RemoveAll(); +} + +int CPacketQueue2::GetCount() +{ + CAutoLock cAutoLock(this); + return (int)__super::GetCount(); +} + +int CPacketQueue2::GetSize() +{ + CAutoLock cAutoLock(this); + return m_size; +} + +// +// CBaseSplitterInputPin +// + +CBaseSplitterInputPin::CBaseSplitterInputPin(LPCTSTR pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT) +{ +} + +CBaseSplitterInputPin::~CBaseSplitterInputPin() +{ +} + +HRESULT CBaseSplitterInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader) +{ + CheckPointer(ppAsyncReader, E_POINTER); + *ppAsyncReader = nullptr; + CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED); + (*ppAsyncReader = m_pAsyncReader)->AddRef(); + return S_OK; +} + +STDMETHODIMP CBaseSplitterInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CBaseSplitterInputPin::CheckMediaType(const CMediaType* pmt) +{ + return S_OK; + /* + return pmt->majortype == MEDIATYPE_Stream + ? S_OK + : E_INVALIDARG; + */ +} + +HRESULT CBaseSplitterInputPin::CheckConnect(IPin* pPin) +{ + HRESULT hr; + if (FAILED(hr = __super::CheckConnect(pPin))) { + return hr; + } + + return CComQIPtr(pPin) ? S_OK : E_NOINTERFACE; +} + +HRESULT CBaseSplitterInputPin::BreakConnect() +{ + HRESULT hr; + + if (FAILED(hr = __super::BreakConnect())) { + return hr; + } + + if (FAILED(hr = (static_cast(m_pFilter))->BreakConnect(PINDIR_INPUT, this))) { + return hr; + } + + m_pAsyncReader.Release(); + + return S_OK; +} + +HRESULT CBaseSplitterInputPin::CompleteConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CompleteConnect(pPin))) { + return hr; + } + + CheckPointer(pPin, E_POINTER); + m_pAsyncReader = pPin; + CheckPointer(m_pAsyncReader, E_NOINTERFACE); + + if (FAILED(hr = (static_cast(m_pFilter))->CompleteConnect(PINDIR_INPUT, this))) { + return hr; + } + + return S_OK; +} + +STDMETHODIMP CBaseSplitterInputPin::BeginFlush() +{ + return E_UNEXPECTED; +} + +STDMETHODIMP CBaseSplitterInputPin::EndFlush() +{ + return E_UNEXPECTED; +} + +// +// CBaseSplitterOutputPin +// + +CBaseSplitterOutputPin::CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers, int QueueMaxPackets) + : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName) + , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it + , m_fFlushing(false) + , m_fFlushed(false) + , m_eEndFlush(TRUE) + , m_QueueMaxPackets(QueueMaxPackets) + , m_rtStart(0) +{ + m_mts.Copy(mts); + m_nBuffers = std::max(nBuffers, 1); +} + +CBaseSplitterOutputPin::CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers, int QueueMaxPackets) + : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName) + , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it + , m_fFlushing(false) + , m_fFlushed(false) + , m_eEndFlush(TRUE) + , m_QueueMaxPackets(QueueMaxPackets) + , m_rtStart(0) +{ + m_nBuffers = std::max(nBuffers, 1); +} + +CBaseSplitterOutputPin::~CBaseSplitterOutputPin() +{ +} + +STDMETHODIMP CBaseSplitterOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + // riid == __uuidof(IMediaSeeking) ? m_pFilter->QueryInterface(riid, ppv) : + QI(IMediaSeeking) + QI(IPropertyBag) + QI(IPropertyBag2) + QI(IDSMPropertyBag) + QI(IBitRateInfo) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CBaseSplitterOutputPin::SetName(LPCWSTR pName) +{ + CheckPointer(pName, E_POINTER); + if (m_pName) { + delete [] m_pName; + } + m_pName = DEBUG_NEW WCHAR[wcslen(pName) + 1]; + CheckPointer(m_pName, E_OUTOFMEMORY); + wcscpy_s(m_pName, wcslen(pName) + 1, pName); + return S_OK; +} + +HRESULT CBaseSplitterOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = std::max(pProperties->cBuffers, m_nBuffers); + pProperties->cbBuffer = std::max((long)m_mt.lSampleSize, 1l); + + // TODO: is this still needed ? + if (m_mt.subtype == MEDIASUBTYPE_Vorbis && m_mt.formattype == FORMAT_VorbisFormat) { + // oh great, the oggds vorbis decoder assumes there will be two at least, stupid thing... + pProperties->cBuffers = std::max(pProperties->cBuffers, 2l); + } + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CBaseSplitterOutputPin::CheckMediaType(const CMediaType* pmt) +{ + for (size_t i = 0; i < m_mts.GetCount(); i++) { + if (*pmt == m_mts[i]) { + return S_OK; + } + } + + return E_INVALIDARG; +} + +HRESULT CBaseSplitterOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CAutoLock cAutoLock(m_pLock); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if ((size_t)iPosition >= m_mts.GetCount()) { + return VFW_S_NO_MORE_ITEMS; + } + + *pmt = m_mts[iPosition]; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} + +// + +HRESULT CBaseSplitterOutputPin::Active() +{ + CAutoLock cAutoLock(m_pLock); + + if (m_Connected) { + Create(); + } + + return __super::Active(); +} + +HRESULT CBaseSplitterOutputPin::Inactive() +{ + CAutoLock cAutoLock(m_pLock); + + if (ThreadExists()) { + CallWorker(CMD_EXIT); + } + + return __super::Inactive(); +} + +HRESULT CBaseSplitterOutputPin::DeliverBeginFlush() +{ + m_eEndFlush.Reset(); + m_fFlushed = false; + m_fFlushing = true; + m_hrDeliver = S_FALSE; + m_queue.RemoveAll(); + HRESULT hr = IsConnected() ? GetConnected()->BeginFlush() : S_OK; + if (S_OK != hr) { + m_eEndFlush.Set(); + } + return hr; +} + +HRESULT CBaseSplitterOutputPin::DeliverEndFlush() +{ + if (!ThreadExists()) { + return S_FALSE; + } + HRESULT hr = IsConnected() ? GetConnected()->EndFlush() : S_OK; + m_hrDeliver = S_OK; + m_fFlushing = false; + m_fFlushed = true; + m_eEndFlush.Set(); + return hr; +} + +HRESULT CBaseSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + m_BitRate.rtLastDeliverTime = Packet::INVALID_TIME; + if (m_fFlushing) { + return S_FALSE; + } + m_rtStart = tStart; + if (!ThreadExists()) { + return S_FALSE; + } + HRESULT hr = __super::DeliverNewSegment(tStart, tStop, dRate); + if (S_OK != hr) { + return hr; + } + MakeISCRHappy(); + return hr; +} + +int CBaseSplitterOutputPin::QueueCount() +{ + return m_queue.GetCount(); +} + +int CBaseSplitterOutputPin::QueueSize() +{ + return m_queue.GetSize(); +} + +HRESULT CBaseSplitterOutputPin::QueueEndOfStream() +{ + CAutoPtr p; + return QueuePacket(p); // NULL means EndOfStream +} + +HRESULT CBaseSplitterOutputPin::QueuePacket(CAutoPtr p) +{ + if (!ThreadExists()) { + return S_FALSE; + } + + while (S_OK == m_hrDeliver + && ((m_queue.GetCount() > (m_QueueMaxPackets * 2) || m_queue.GetSize() > (MAXPACKETSIZE * 3 / 2)) + || ((m_queue.GetCount() > m_QueueMaxPackets || m_queue.GetSize() > MAXPACKETSIZE) && !(static_cast(m_pFilter))->IsAnyPinDrying()))) { + Sleep(10); + } + + if (S_OK != m_hrDeliver) { + return m_hrDeliver; + } + + m_queue.Add(p); + + return m_hrDeliver; +} + +bool CBaseSplitterOutputPin::IsDiscontinuous() +{ + return m_mt.majortype == MEDIATYPE_Text + || m_mt.majortype == MEDIATYPE_ScriptCommand + || m_mt.majortype == MEDIATYPE_Subtitle + || m_mt.subtype == MEDIASUBTYPE_DVD_SUBPICTURE + || m_mt.subtype == MEDIASUBTYPE_CVD_SUBPICTURE + || m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE; +} + +bool CBaseSplitterOutputPin::IsActive() +{ + CComPtr pPin = this; + do { + CComPtr pPinTo; + CComQIPtr pSSIP; + if (S_OK == pPin->ConnectedTo(&pPinTo) && (pSSIP = pPinTo) && !pSSIP->IsActive()) { + return false; + } + pPin = GetFirstPin(GetFilterFromPin(pPinTo), PINDIR_OUTPUT); + } while (pPin); + + return true; +} + +DWORD CBaseSplitterOutputPin::ThreadProc() +{ + SetThreadName(DWORD(-1), "CBaseSplitterOutputPin"); + m_hrDeliver = S_OK; + m_fFlushing = m_fFlushed = false; + m_eEndFlush.Set(); + + // fix for Microsoft DTV-DVD Video Decoder - video freeze after STOP/PLAY + bool iHaaliRenderConnect = false; + CComPtr pPinTo = this, pTmp; + while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { + pTmp = nullptr; + CComPtr pBF = GetFilterFromPin(pPinTo); + if (GetCLSID(pBF) == CLSID_DXR) { // Haali Renderer + iHaaliRenderConnect = true; + break; + } + pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); + } + if (IsConnected() && !iHaaliRenderConnect) { + GetConnected()->BeginFlush(); + GetConnected()->EndFlush(); + } + + for (;;) { + Sleep(1); + + DWORD cmd; + if (CheckRequest(&cmd)) { + m_hThread = nullptr; + cmd = GetRequest(); + Reply(S_OK); + ASSERT(cmd == CMD_EXIT); + return 0; + } + + int cnt = 0; + do { + CAutoPtr p; + + { + CAutoLock cAutoLock(&m_queue); + if ((cnt = m_queue.GetCount()) > 0) { + p.Attach(m_queue.Remove().Detach()); + } + } + + if (S_OK == m_hrDeliver && cnt > 0) { + ASSERT(!m_fFlushing); + + m_fFlushed = false; + + // flushing can still start here, to release a blocked deliver call + + HRESULT hr = p + ? DeliverPacket(p) + : DeliverEndOfStream(); + + m_eEndFlush.Wait(); // .. so we have to wait until it is done + + if (hr != S_OK && !m_fFlushed) { // and only report the error in m_hrDeliver if we didn't flush the stream + // CAutoLock cAutoLock(&m_csQueueLock); + m_hrDeliver = hr; + break; + } + } + } while (--cnt > 0); + } +} + +HRESULT CBaseSplitterOutputPin::DeliverPacket(CAutoPtr p) +{ + HRESULT hr; + + long nBytes = (long)p->GetCount(); + + if (nBytes == 0) { + return S_OK; + } + + m_BitRate.nBytesSinceLastDeliverTime += nBytes; + + if (p->rtStart != Packet::INVALID_TIME) { + if (m_BitRate.rtLastDeliverTime == Packet::INVALID_TIME) { + m_BitRate.rtLastDeliverTime = p->rtStart; + m_BitRate.nBytesSinceLastDeliverTime = 0; + } + + if (m_BitRate.rtLastDeliverTime + 10000000 < p->rtStart) { + REFERENCE_TIME rtDiff = p->rtStart - m_BitRate.rtLastDeliverTime; + + double dSecs, dBits; + + dSecs = rtDiff / 10000000.0; + dBits = 8.0 * m_BitRate.nBytesSinceLastDeliverTime; + m_BitRate.nCurrentBitRate = (DWORD)(dBits / dSecs); + + m_BitRate.rtTotalTimeDelivered += rtDiff; + m_BitRate.nTotalBytesDelivered += m_BitRate.nBytesSinceLastDeliverTime; + + dSecs = m_BitRate.rtTotalTimeDelivered / 10000000.0; + dBits = 8.0 * m_BitRate.nTotalBytesDelivered; + m_BitRate.nAverageBitRate = (DWORD)(dBits / dSecs); + + m_BitRate.rtLastDeliverTime = p->rtStart; + m_BitRate.nBytesSinceLastDeliverTime = 0; + /* + TRACE(_T("[%d] c: %d kbps, a: %d kbps\n"), + p->TrackNumber, + (m_brs.nCurrentBitRate+500)/1000, + (m_brs.nAverageBitRate+500)/1000); + */ + } + + double dRate = 1.0; + if (SUCCEEDED((static_cast(m_pFilter))->GetRate(&dRate))) { + p->rtStart = (REFERENCE_TIME)((double)p->rtStart / dRate); + p->rtStop = (REFERENCE_TIME)((double)p->rtStop / dRate); + } + } + + do { + CComPtr pSample; + if (S_OK != (hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0))) { + break; + } + + if (nBytes > pSample->GetSize()) { + pSample.Release(); + + ALLOCATOR_PROPERTIES props, actual; + if (S_OK != (hr = m_pAllocator->GetProperties(&props))) { + break; + } + props.cbBuffer = nBytes * 3 / 2; + + if (props.cBuffers > 1) { + if (S_OK != (hr = __super::DeliverBeginFlush())) { + break; + } + if (S_OK != (hr = __super::DeliverEndFlush())) { + break; + } + } + + if (S_OK != (hr = m_pAllocator->Decommit())) { + break; + } + if (S_OK != (hr = m_pAllocator->SetProperties(&props, &actual))) { + break; + } + if (S_OK != (hr = m_pAllocator->Commit())) { + break; + } + if (S_OK != (hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0))) { + break; + } + } + + if (p->pmt) { + pSample->SetMediaType(p->pmt); + p->bDiscontinuity = true; + + CAutoLock cAutoLock(m_pLock); + m_mts.RemoveAll(); + m_mts.Add(*p->pmt); + } + + bool fTimeValid = p->rtStart != Packet::INVALID_TIME; + +#if defined(_DEBUG) && 0 + TRACE(_T("[%d]: d%d s%d p%d, b=%d, [%20I64d - %20I64d]\n"), + p->TrackNumber, + p->bDiscontinuity, p->bSyncPoint, fTimeValid && p->rtStart < 0, + nBytes, p->rtStart, p->rtStop); +#endif + + ASSERT(!p->bSyncPoint || fTimeValid); + + BYTE* pData = nullptr; + if (S_OK != (hr = pSample->GetPointer(&pData)) || !pData) { + break; + } + memcpy(pData, p->GetData(), nBytes); + if (S_OK != (hr = pSample->SetActualDataLength(nBytes))) { + break; + } + if (S_OK != (hr = pSample->SetTime(fTimeValid ? &p->rtStart : nullptr, fTimeValid ? &p->rtStop : nullptr))) { + break; + } + if (S_OK != (hr = pSample->SetMediaTime(nullptr, nullptr))) { + break; + } + if (S_OK != (hr = pSample->SetDiscontinuity(p->bDiscontinuity))) { + break; + } + if (S_OK != (hr = pSample->SetSyncPoint(p->bSyncPoint))) { + break; + } + if (S_OK != (hr = pSample->SetPreroll(fTimeValid && p->rtStart < 0))) { + break; + } + if (S_OK != (hr = Deliver(pSample))) { + break; + } + } while (false); + + return hr; +} + +void CBaseSplitterOutputPin::MakeISCRHappy() +{ + CComPtr pPinTo = this, pTmp; + while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { + pTmp = nullptr; + + CComPtr pBF = GetFilterFromPin(pPinTo); + + if (GetCLSID(pBF) == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) { // ISCR + CAutoPtr p(DEBUG_NEW Packet()); + p->TrackNumber = DWORD_ERROR; + p->rtStart = -1; + p->rtStop = 0; + p->bSyncPoint = FALSE; + p->SetData(" ", 2); + QueuePacket(p); + break; + } + + pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); + } +} + +HRESULT CBaseSplitterOutputPin::GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags) +{ + return __super::GetDeliveryBuffer(ppSample, pStartTime, pEndTime, dwFlags); +} + +HRESULT CBaseSplitterOutputPin::Deliver(IMediaSample* pSample) +{ + return __super::Deliver(pSample); +} + +// IMediaSeeking + +STDMETHODIMP CBaseSplitterOutputPin::GetCapabilities(DWORD* pCapabilities) +{ + return (static_cast(m_pFilter))->GetCapabilities(pCapabilities); +} + +STDMETHODIMP CBaseSplitterOutputPin::CheckCapabilities(DWORD* pCapabilities) +{ + return (static_cast(m_pFilter))->CheckCapabilities(pCapabilities); +} + +STDMETHODIMP CBaseSplitterOutputPin::IsFormatSupported(const GUID* pFormat) +{ + return (static_cast(m_pFilter))->IsFormatSupported(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::QueryPreferredFormat(GUID* pFormat) +{ + return (static_cast(m_pFilter))->QueryPreferredFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetTimeFormat(GUID* pFormat) +{ + return (static_cast(m_pFilter))->GetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::IsUsingTimeFormat(const GUID* pFormat) +{ + return (static_cast(m_pFilter))->IsUsingTimeFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::SetTimeFormat(const GUID* pFormat) +{ + return (static_cast(m_pFilter))->SetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetDuration(LONGLONG* pDuration) +{ + return (static_cast(m_pFilter))->GetDuration(pDuration); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetStopPosition(LONGLONG* pStop) +{ + return (static_cast(m_pFilter))->GetStopPosition(pStop); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetCurrentPosition(LONGLONG* pCurrent) +{ + return (static_cast(m_pFilter))->GetCurrentPosition(pCurrent); +} + +STDMETHODIMP CBaseSplitterOutputPin::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return (static_cast(m_pFilter))->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return (static_cast(m_pFilter))->SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return (static_cast(m_pFilter))->GetPositions(pCurrent, pStop); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return (static_cast(m_pFilter))->GetAvailable(pEarliest, pLatest); +} + +STDMETHODIMP CBaseSplitterOutputPin::SetRate(double dRate) +{ + return (static_cast(m_pFilter))->SetRate(dRate); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetRate(double* pdRate) +{ + return (static_cast(m_pFilter))->GetRate(pdRate); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetPreroll(LONGLONG* pllPreroll) +{ + return (static_cast(m_pFilter))->GetPreroll(pllPreroll); +} + +// +// CBaseSplitterFilter +// + +CBaseSplitterFilter::CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid, int QueueMaxPackets) + : CBaseFilter(pName, pUnk, this, clsid) + , m_nOpenProgress(100) + , m_fAbort(false) + , m_rtDuration(0) + , m_rtStart(0) + , m_rtStop(0) + , m_rtCurrent(0) + , m_rtNewStart(0) + , m_rtNewStop(0) + , m_dRate(1.0) + , m_fFlushing(false) + , m_priority(THREAD_PRIORITY_NORMAL) + , m_QueueMaxPackets(QueueMaxPackets) + , m_rtLastStart(_I64_MIN) + , m_rtLastStop(_I64_MIN) +{ + if (phr) { + *phr = S_OK; + } + + m_pInput.Attach(DEBUG_NEW CBaseSplitterInputPin(NAME("CBaseSplitterInputPin"), this, this, phr)); +} + +CBaseSplitterFilter::~CBaseSplitterFilter() +{ + CAutoLock cAutoLock(this); + + CAMThread::CallWorker(CMD_EXIT); + CAMThread::Close(); +} + +STDMETHODIMP CBaseSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + if (m_pInput && riid == __uuidof(IFileSourceFilter)) { + return E_NOINTERFACE; + } + + return + QI(IFileSourceFilter) + QI(IMediaSeeking) + QI(IAMOpenProgress) + QI2(IAMMediaContent) + QI2(IAMExtendedSeeking) + QI(IKeyFrameInfo) + QI(IBufferInfo) + QI(IPropertyBag) + QI(IPropertyBag2) + QI(IDSMPropertyBag) + QI(IDSMResourceBag) + QI(IDSMChapterBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +CBaseSplitterOutputPin* CBaseSplitterFilter::GetOutputPin(DWORD TrackNum) +{ + CAutoLock cAutoLock(&m_csPinMap); + + CBaseSplitterOutputPin* pPin = nullptr; + m_pPinMap.Lookup(TrackNum, pPin); + return pPin; +} + +DWORD CBaseSplitterFilter::GetOutputTrackNum(CBaseSplitterOutputPin* pPin) +{ + CAutoLock cAutoLock(&m_csPinMap); + + POSITION pos = m_pPinMap.GetStartPosition(); + while (pos) { + DWORD TrackNum; + CBaseSplitterOutputPin* pPinTmp; + m_pPinMap.GetNextAssoc(pos, TrackNum, pPinTmp); + if (pPinTmp == pPin) { + return TrackNum; + } + } + + return DWORD_ERROR; +} + +HRESULT CBaseSplitterFilter::RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt) +{ + CAutoLock cAutoLock(&m_csPinMap); + + CBaseSplitterOutputPin* pPin; + if (m_pPinMap.Lookup(TrackNumSrc, pPin)) { + if (CComQIPtr pPinTo = pPin->GetConnected()) { + if (pmt && S_OK != pPinTo->QueryAccept(pmt)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } + + m_pPinMap.RemoveKey(TrackNumSrc); + m_pPinMap[TrackNumDst] = pPin; + + if (pmt) { + CAutoLock cAutoLock2(&m_csmtnew); + m_mtnew[TrackNumDst] = *pmt; + } + + return S_OK; + } + + return E_FAIL; +} + +HRESULT CBaseSplitterFilter::AddOutputPin(DWORD TrackNum, CAutoPtr pPin) +{ + CAutoLock cAutoLock(&m_csPinMap); + + if (!pPin) { + return E_INVALIDARG; + } + m_pPinMap[TrackNum] = pPin; + m_pOutputs.AddTail(pPin); + return S_OK; +} + +HRESULT CBaseSplitterFilter::DeleteOutputs() +{ + m_rtDuration = 0; + + m_pRetiredOutputs.RemoveAll(); + + CAutoLock cAutoLockF(this); + if (m_State != State_Stopped) { + return VFW_E_NOT_STOPPED; + } + + while (m_pOutputs.GetCount()) { + CAutoPtr pPin(m_pOutputs.RemoveHead().Detach()); + if (IPin* pPinTo = pPin->GetConnected()) { + pPinTo->Disconnect(); + } + pPin->Disconnect(); + // we can't just let it be deleted now, something might have AddRefed on it (graphedit...) + m_pRetiredOutputs.AddTail(pPin); + } + + CAutoLock cAutoLockPM(&m_csPinMap); + m_pPinMap.RemoveAll(); + + CAutoLock cAutoLockMT(&m_csmtnew); + m_mtnew.RemoveAll(); + + RemoveAll(); + ResRemoveAll(); + ChapRemoveAll(); + + m_fontinst.UninstallFonts(); + + m_pSyncReader.Release(); + + return S_OK; +} + +void CBaseSplitterFilter::DeliverBeginFlush() +{ + m_fFlushing = true; + POSITION pos = m_pOutputs.GetHeadPosition(); + while (pos) { + m_pOutputs.GetNext(pos)->DeliverBeginFlush(); + } +} + +void CBaseSplitterFilter::DeliverEndFlush() +{ + POSITION pos = m_pOutputs.GetHeadPosition(); + while (pos) { + m_pOutputs.GetNext(pos)->DeliverEndFlush(); + } + m_fFlushing = false; + m_eEndFlush.Set(); +} + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CBaseSplitterFilter::ThreadProc() +{ + if (m_pSyncReader) { + m_pSyncReader->SetBreakEvent(GetRequestHandle()); + } + + if (!DemuxInit()) { + for (;;) { + DWORD cmd = GetRequest(); + if (cmd == CMD_EXIT) { + CAMThread::m_hThread = nullptr; + } + Reply(S_OK); + if (cmd == CMD_EXIT) { + return 0; + } + } + } + + m_eEndFlush.Set(); + m_fFlushing = false; + + for (DWORD cmd = DWORD_ERROR; ; cmd = GetRequest()) { + if (cmd == CMD_EXIT) { + m_hThread = nullptr; + Reply(S_OK); + return 0; + } + + SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); + + m_rtStart = m_rtNewStart; + m_rtStop = m_rtNewStop; + + DemuxSeek(m_rtStart); + + if (cmd != DWORD_ERROR) { + Reply(S_OK); + } + + m_eEndFlush.Wait(); + + m_pActivePins.RemoveAll(); + + POSITION pos = m_pOutputs.GetHeadPosition(); + while (pos && !m_fFlushing) { + CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos); + if (pPin->IsConnected() && pPin->IsActive()) { + m_pActivePins.AddTail(pPin); + pPin->DeliverNewSegment(m_rtStart, m_rtStop, m_dRate); + } + } + + do { + m_bDiscontinuitySent.RemoveAll(); + } while (!DemuxLoop()); + + pos = m_pActivePins.GetHeadPosition(); + while (pos && !CheckRequest(&cmd)) { + m_pActivePins.GetNext(pos)->QueueEndOfStream(); + } + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +HRESULT CBaseSplitterFilter::DeliverPacket(CAutoPtr p) +{ + HRESULT hr = S_FALSE; + + CBaseSplitterOutputPin* pPin = GetOutputPin(p->TrackNumber); + if (!pPin || !pPin->IsConnected() || !m_pActivePins.Find(pPin)) { + return S_FALSE; + } + + if (p->rtStart != Packet::INVALID_TIME) { + m_rtCurrent = p->rtStart; + + p->rtStart -= m_rtStart; + p->rtStop -= m_rtStart; + + ASSERT(p->rtStart <= p->rtStop); + } + + { + CAutoLock cAutoLock(&m_csmtnew); + + CMediaType mt; + if (m_mtnew.Lookup(p->TrackNumber, mt)) { + p->pmt = CreateMediaType(&mt); + m_mtnew.RemoveKey(p->TrackNumber); + } + } + + if (!m_bDiscontinuitySent.Find(p->TrackNumber)) { + p->bDiscontinuity = TRUE; + } + + DWORD TrackNumber = p->TrackNumber; + BOOL bDiscontinuity = p->bDiscontinuity; + +#if defined(_DEBUG) && 0 + TRACE(_T("[%d]: d%d s%d p%d, b=%d, [%20I64d - %20I64d]\n"), + p->TrackNumber, + p->bDiscontinuity, p->bSyncPoint, p->rtStart != Packet::INVALID_TIME && p->rtStart < 0, + p->GetCount(), p->rtStart, p->rtStop); +#endif + + hr = pPin->QueuePacket(p); + + if (S_OK != hr) { + if (POSITION pos = m_pActivePins.Find(pPin)) { + m_pActivePins.RemoveAt(pos); + } + + if (!m_pActivePins.IsEmpty()) { // only die when all pins are down + hr = S_OK; + } + + return hr; + } + + if (bDiscontinuity) { + m_bDiscontinuitySent.AddTail(TrackNumber); + } + + return hr; +} + +bool CBaseSplitterFilter::IsAnyPinDrying() +{ + int totalcount = 0, totalsize = 0; + + POSITION pos = m_pActivePins.GetHeadPosition(); + while (pos) { + CBaseSplitterOutputPin* pPin = m_pActivePins.GetNext(pos); + int count = pPin->QueueCount(); + int size = pPin->QueueSize(); + if (!pPin->IsDiscontinuous() && (count < MINPACKETS || size < MINPACKETSIZE)) { + // if (m_priority != THREAD_PRIORITY_ABOVE_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3)) + if (m_priority != THREAD_PRIORITY_BELOW_NORMAL && (count < MINPACKETS / 3 || size < MINPACKETSIZE / 3)) { + // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_ABOVE_NORMAL); + POSITION pos2 = m_pOutputs.GetHeadPosition(); + while (pos2) { + m_pOutputs.GetNext(pos2)->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); + } + m_priority = THREAD_PRIORITY_BELOW_NORMAL; + } + return true; + } + totalcount += count; + totalsize += size; + } + + if (m_priority != THREAD_PRIORITY_NORMAL && (totalcount > m_QueueMaxPackets * 2 / 3 || totalsize > MAXPACKETSIZE * 2 / 3)) { + // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); + POSITION pos2 = m_pOutputs.GetHeadPosition(); + while (pos2) { + m_pOutputs.GetNext(pos2)->SetThreadPriority(THREAD_PRIORITY_NORMAL); + } + m_priority = THREAD_PRIORITY_NORMAL; + } + + if (totalcount < m_QueueMaxPackets && totalsize < MAXPACKETSIZE) { + return true; + } + + return false; +} + +HRESULT CBaseSplitterFilter::BreakConnect(PIN_DIRECTION dir, CBasePin* pPin) +{ + CheckPointer(pPin, E_POINTER); + + if (dir == PINDIR_INPUT) { + DeleteOutputs(); + } else if (dir == PINDIR_OUTPUT) { + } else { + return E_UNEXPECTED; + } + + return S_OK; +} + +HRESULT CBaseSplitterFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin) +{ + CheckPointer(pPin, E_POINTER); + + if (dir == PINDIR_INPUT) { + CBaseSplitterInputPin* pIn = static_cast(pPin); + + HRESULT hr; + + CComPtr pAsyncReader; + if (FAILED(hr = pIn->GetAsyncReader(&pAsyncReader)) + || FAILED(hr = DeleteOutputs()) + || FAILED(hr = CreateOutputs(pAsyncReader))) { + return hr; + } + + ChapSort(); + + m_pSyncReader = pAsyncReader; + } else if (dir == PINDIR_OUTPUT) { + m_pRetiredOutputs.RemoveAll(); + } else { + return E_UNEXPECTED; + } + + return S_OK; +} + +int CBaseSplitterFilter::GetPinCount() +{ + return (m_pInput ? 1 : 0) + (int)m_pOutputs.GetCount(); +} + +CBasePin* CBaseSplitterFilter::GetPin(int n) +{ + CAutoLock cAutoLock(this); + + if (n >= 0 && n < (int)m_pOutputs.GetCount()) { + if (POSITION pos = m_pOutputs.FindIndex(n)) { + return m_pOutputs.GetAt(pos); + } + } + + if (n == (int)m_pOutputs.GetCount() && m_pInput) { + return m_pInput; + } + + return nullptr; +} + +STDMETHODIMP CBaseSplitterFilter::Stop() +{ + CAutoLock cAutoLock(this); + + DeliverBeginFlush(); + CallWorker(CMD_EXIT); + DeliverEndFlush(); + + HRESULT hr; + if (FAILED(hr = __super::Stop())) { + return hr; + } + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::Pause() +{ + CAutoLock cAutoLock(this); + + FILTER_STATE fs = m_State; + + HRESULT hr; + if (FAILED(hr = __super::Pause())) { + return hr; + } + + if (fs == State_Stopped) { + Create(); + } + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + if (FAILED(hr = __super::Run(tStart))) { + return hr; + } + + return S_OK; +} + +// IFileSourceFilter + +STDMETHODIMP CBaseSplitterFilter::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + CheckPointer(pszFileName, E_POINTER); + + m_fn = pszFileName; + HRESULT hr = E_FAIL; + CComPtr pAsyncReader; + CAtlList Items; + CAtlList Chapters; + + if (BuildPlaylist(pszFileName, Items)) { + pAsyncReader = (IAsyncReader*)DEBUG_NEW CAsyncFileReader(Items, hr); + } else { + pAsyncReader = (IAsyncReader*)DEBUG_NEW CAsyncFileReader(CString(pszFileName), hr); + } + + if (FAILED(hr) + || FAILED(hr = DeleteOutputs()) + || FAILED(hr = CreateOutputs(pAsyncReader))) { + m_fn.Empty(); + return hr; + } + + if (BuildChapters(pszFileName, Items, Chapters)) { + POSITION pos = Chapters.GetHeadPosition(); + int i = 1; + while (pos) { + CString str; + CHdmvClipInfo::PlaylistChapter& chap = Chapters.GetNext(pos); + if (chap.m_nMarkType == CHdmvClipInfo::EntryMark) { + str.Format(_T("Chapter %d"), i); + ChapAppend(chap.m_rtTimestamp, str); + i++; + } + } + } + + ChapSort(); + + m_pSyncReader = pAsyncReader; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + return S_OK; +} + +LPCTSTR CBaseSplitterFilter::GetPartFilename(IAsyncReader* pAsyncReader) +{ + CComQIPtr pFH = pAsyncReader; + return pFH ? pFH->GetFileName() : (LPCWSTR)m_fn; +} + +// IMediaSeeking + +STDMETHODIMP CBaseSplitterFilter::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration + | AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanSeekForwards | AM_SEEKING_CanSeekBackwards; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + if (*pCapabilities == 0) { + return S_OK; + } + DWORD caps; + GetCapabilities(&caps); + if ((caps&*pCapabilities) == 0) { + return E_FAIL; + } + if (caps == *pCapabilities) { + return S_OK; + } + return S_FALSE; +} + +STDMETHODIMP CBaseSplitterFilter::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseSplitterFilter::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterFilter::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CBaseSplitterFilter::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CBaseSplitterFilter::GetDuration(LONGLONG* pDuration) +{ + CheckPointer(pDuration, E_POINTER); + *pDuration = m_rtDuration; + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetStopPosition(LONGLONG* pStop) +{ + return GetDuration(pStop); +} + +STDMETHODIMP CBaseSplitterFilter::GetCurrentPosition(LONGLONG* pCurrent) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseSplitterFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseSplitterFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags); +} + +STDMETHODIMP CBaseSplitterFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + if (pCurrent) { + *pCurrent = m_rtCurrent; + } + if (pStop) { + *pStop = m_rtStop; + } + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + if (pEarliest) { + *pEarliest = 0; + } + return GetDuration(pLatest); +} + +STDMETHODIMP CBaseSplitterFilter::SetRate(double dRate) +{ + HRESULT hr = E_INVALIDARG; + + if (dRate > 0.0) { + m_dRate = dRate; + hr = S_OK; + } + + return hr; +} + +STDMETHODIMP CBaseSplitterFilter::GetRate(double* pdRate) +{ + CheckPointer(pdRate, E_POINTER); + + *pdRate = m_dRate; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetPreroll(LONGLONG* pllPreroll) +{ + CheckPointer(pllPreroll, E_POINTER); + + *pllPreroll = 0; + + return S_OK; +} + +HRESULT CBaseSplitterFilter::SetPositionsInternal(void* id, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + CAutoLock cAutoLock(this); + + if (!pCurrent && !pStop + || (dwCurrentFlags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning + && (dwStopFlags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning) { + return S_OK; + } + + REFERENCE_TIME rtCurrent = m_rtCurrent; + REFERENCE_TIME rtStop = m_rtStop; + + if (pCurrent) + switch (dwCurrentFlags & AM_SEEKING_PositioningBitsMask) { + case AM_SEEKING_NoPositioning: + break; + case AM_SEEKING_AbsolutePositioning: + rtCurrent = *pCurrent; + break; + case AM_SEEKING_RelativePositioning: + rtCurrent = rtCurrent + *pCurrent; + break; + case AM_SEEKING_IncrementalPositioning: + rtCurrent = rtCurrent + *pCurrent; + break; + } + + if (pStop) + switch (dwStopFlags & AM_SEEKING_PositioningBitsMask) { + case AM_SEEKING_NoPositioning: + break; + case AM_SEEKING_AbsolutePositioning: + rtStop = *pStop; + break; + case AM_SEEKING_RelativePositioning: + rtStop += *pStop; + break; + case AM_SEEKING_IncrementalPositioning: + rtStop = rtCurrent + *pStop; + break; + } + + if (m_rtCurrent == rtCurrent && m_rtStop == rtStop) { + return S_OK; + } + + if (m_rtLastStart == rtCurrent && m_rtLastStop == rtStop && !m_LastSeekers.Find(id)) { + m_LastSeekers.AddTail(id); + return S_OK; + } + + m_rtLastStart = rtCurrent; + m_rtLastStop = rtStop; + m_LastSeekers.RemoveAll(); + m_LastSeekers.AddTail(id); + + DbgLog((LOG_TRACE, 0, _T("Seek Started %I64d"), rtCurrent)); + + m_rtNewStart = m_rtCurrent = rtCurrent; + m_rtNewStop = rtStop; + + if (ThreadExists()) { + DeliverBeginFlush(); + CallWorker(CMD_SEEK); + DeliverEndFlush(); + } + + DbgLog((LOG_TRACE, 0, _T("Seek Ended"))); + + return S_OK; +} + +// IAMOpenProgress + +STDMETHODIMP CBaseSplitterFilter::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent) +{ + CheckPointer(pllTotal, E_POINTER); + CheckPointer(pllCurrent, E_POINTER); + + *pllTotal = 100; + *pllCurrent = m_nOpenProgress; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::AbortOperation() +{ + m_fAbort = true; + return S_OK; +} + +// IAMMediaContent + +STDMETHODIMP CBaseSplitterFilter::get_AuthorName(BSTR* pbstrAuthorName) +{ + return GetProperty(L"AUTH", pbstrAuthorName); +} + +STDMETHODIMP CBaseSplitterFilter::get_Title(BSTR* pbstrTitle) +{ + return GetProperty(L"TITL", pbstrTitle); +} + +STDMETHODIMP CBaseSplitterFilter::get_Rating(BSTR* pbstrRating) +{ + return GetProperty(L"RTNG", pbstrRating); +} + +STDMETHODIMP CBaseSplitterFilter::get_Description(BSTR* pbstrDescription) +{ + return GetProperty(L"DESC", pbstrDescription); +} + +STDMETHODIMP CBaseSplitterFilter::get_Copyright(BSTR* pbstrCopyright) +{ + return GetProperty(L"CPYR", pbstrCopyright); +} + +// IAMExtendedSeeking + +STDMETHODIMP CBaseSplitterFilter::get_ExSeekCapabilities(long* pExCapabilities) +{ + CheckPointer(pExCapabilities, E_POINTER); + *pExCapabilities = AM_EXSEEK_CANSEEK; + if (ChapGetCount()) { + *pExCapabilities |= AM_EXSEEK_MARKERSEEK; + } + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::get_MarkerCount(long* pMarkerCount) +{ + CheckPointer(pMarkerCount, E_POINTER); + *pMarkerCount = (long)ChapGetCount(); + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::get_CurrentMarker(long* pCurrentMarker) +{ + CheckPointer(pCurrentMarker, E_POINTER); + REFERENCE_TIME rt = m_rtCurrent; + long i = ChapLookup(&rt); + if (i < 0) { + return E_FAIL; + } + *pCurrentMarker = i + 1; + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetMarkerTime(long MarkerNum, double* pMarkerTime) +{ + CheckPointer(pMarkerTime, E_POINTER); + REFERENCE_TIME rt; + if (FAILED(ChapGet((int)MarkerNum - 1, &rt))) { + return E_FAIL; + } + *pMarkerTime = (double)rt / 10000000; + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName) +{ + return ChapGet((int)MarkerNum - 1, nullptr, pbstrMarkerName); +} + +// IKeyFrameInfo + +STDMETHODIMP CBaseSplitterFilter::GetKeyFrameCount(UINT& nKFs) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs) +{ + return E_NOTIMPL; +} + +// IBufferInfo + +STDMETHODIMP_(int) CBaseSplitterFilter::GetCount() +{ + CAutoLock cAutoLock(m_pLock); + + return (int)m_pOutputs.GetCount(); +} + +STDMETHODIMP CBaseSplitterFilter::GetStatus(int i, int& samples, int& size) +{ + CAutoLock cAutoLock(m_pLock); + + if (POSITION pos = m_pOutputs.FindIndex(i)) { + CBaseSplitterOutputPin* pPin = m_pOutputs.GetAt(pos); + samples = pPin->QueueCount(); + size = pPin->QueueSize(); + return pPin->IsConnected() ? S_OK : S_FALSE; + } + + return E_INVALIDARG; +} + +STDMETHODIMP_(DWORD) CBaseSplitterFilter::GetPriority() +{ + return m_priority; +} diff --git a/src/filters/parser/BaseSplitter/BaseSplitter.h b/src/filters/parser/BaseSplitter/BaseSplitter.h index 4b47b95093e..f705d95bb85 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitter.h +++ b/src/filters/parser/BaseSplitter/BaseSplitter.h @@ -1,416 +1,416 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#pragma once - -#include -#include -#include -#include "IKeyFrameInfo.h" -#include "IBufferInfo.h" -#include "IBitRateInfo.h" -#include "AsyncReader.h" -#include "../../../DSUtil/DSMPropertyBag.h" -#include "../../../DSUtil/FontInstaller.h" - -#define MINPACKETS 100 // Beliyaal: Changed the min number of packets to allow Bluray playback over network -#define MINPACKETSIZE 256*1024 // Beliyaal: Changed the min packet size to allow Bluray playback over network -#define MAXPACKETS 2000 -#define MAXPACKETSIZE 128*1024*1024 - -class Packet : public CAtlArray -{ -public: - DWORD TrackNumber; - BOOL bDiscontinuity, bSyncPoint, bAppendable; - static const REFERENCE_TIME INVALID_TIME = _I64_MIN; - REFERENCE_TIME rtStart, rtStop; - AM_MEDIA_TYPE* pmt; - Packet() - : TrackNumber(0) - , bDiscontinuity(FALSE) - , bSyncPoint(FALSE) - , bAppendable(FALSE) - , rtStart(0) - , rtStop(0) - , pmt(nullptr) { - } - virtual ~Packet() { - if (pmt) { - DeleteMediaType(pmt); - } - } - virtual int GetDataSize() { return (int)GetCount(); } - void SetData(const void* ptr, DWORD len) { - SetCount(len); - memcpy(GetData(), ptr, len); - } -}; - -class CPacketQueue2 - : public CCritSec - , protected CAutoPtrList -{ - int m_size; - -public: - CPacketQueue2(); - void Add(CAutoPtr p); - CAutoPtr Remove(); - void RemoveAll(); - int GetCount(), GetSize(); -}; - -class CBaseSplitterFilter; - -class CBaseSplitterInputPin - : public CBasePin -{ -protected: - CComQIPtr m_pAsyncReader; - -public: - CBaseSplitterInputPin(LPCTSTR pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CBaseSplitterInputPin(); - - HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT CheckMediaType(const CMediaType* pmt); - - HRESULT CheckConnect(IPin* pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pPin); - - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); -}; - -class CBaseSplitterOutputPin - : public CBaseOutputPin - , public IDSMPropertyBagImpl - , protected CAMThread - , public IMediaSeeking - , public IBitRateInfo -{ -protected: - CAtlArray m_mts; - int m_nBuffers; - -private: - CPacketQueue2 m_queue; - - HRESULT m_hrDeliver; - - bool m_fFlushing, m_fFlushed; - CAMEvent m_eEndFlush; - - enum { CMD_EXIT }; - DWORD ThreadProc(); - - void MakeISCRHappy(); - - // please only use DeliverPacket from the derived class - HRESULT GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags); - HRESULT Deliver(IMediaSample* pSample); - - // IBitRateInfo - struct BitRateInfo { - UINT64 nTotalBytesDelivered = 0; - REFERENCE_TIME rtTotalTimeDelivered = 0; - UINT64 nBytesSinceLastDeliverTime = 0; - REFERENCE_TIME rtLastDeliverTime = Packet::INVALID_TIME; - DWORD nCurrentBitRate = 0; - DWORD nAverageBitRate = 0; - } m_BitRate; - - int m_QueueMaxPackets; - -protected: - REFERENCE_TIME m_rtStart; - - // override this if you need some second level stream specific demuxing (optional) - // the default implementation will send the sample as is - virtual HRESULT DeliverPacket(CAutoPtr p); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - -public: - CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, - CBaseFilter* pFilter, CCritSec* pLock, - HRESULT* phr, int nBuffers = 0, - int QueueMaxPackets = MAXPACKETS); - CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, - CCritSec* pLock, HRESULT* phr, - int nBuffers = 0, - int QueueMaxPackets = MAXPACKETS); - virtual ~CBaseSplitterOutputPin(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT SetName(LPCWSTR pName); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - CMediaType& CurrentMediaType() { return m_mt; } - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); - - // Queueing - - HANDLE GetThreadHandle() { - ASSERT(m_hThread != nullptr); - return m_hThread; - } - void SetThreadPriority(int nPriority) { - if (m_hThread) { - ::SetThreadPriority(m_hThread, nPriority); - } - } - - HRESULT Active(); - HRESULT Inactive(); - - HRESULT DeliverBeginFlush(); - HRESULT DeliverEndFlush(); - HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - - int QueueCount(); - int QueueSize(); - HRESULT QueueEndOfStream(); - HRESULT QueuePacket(CAutoPtr p); - - // returns true for everything which (the lack of) would not block other streams (subtitle streams, basically) - virtual bool IsDiscontinuous(); - - // returns IStreamsSwitcherInputPin::IsActive(), when it can find one downstream - bool IsActive(); - - // IBitRateInfo - - STDMETHODIMP_(DWORD) GetCurrentBitRate() { return m_BitRate.nCurrentBitRate; } - STDMETHODIMP_(DWORD) GetAverageBitRate() { return m_BitRate.nAverageBitRate; } -}; - -class CBaseSplitterFilter - : public CBaseFilter - , public CCritSec - , public IDSMPropertyBagImpl - , public IDSMResourceBagImpl - , public IDSMChapterBagImpl - , protected CAMThread - , public IFileSourceFilter - , public IMediaSeeking - , public IAMOpenProgress - , public IAMMediaContent - , public IAMExtendedSeeking - , public IKeyFrameInfo - , public IBufferInfo -{ - CCritSec m_csPinMap; - CAtlMap m_pPinMap; - - CCritSec m_csmtnew; - CAtlMap m_mtnew; - - CAutoPtrList m_pRetiredOutputs; - - CComQIPtr m_pSyncReader; - -protected: - CStringW m_fn; - - CAutoPtr m_pInput; - CAutoPtrList m_pOutputs; - - CBaseSplitterOutputPin* GetOutputPin(DWORD TrackNum); - DWORD GetOutputTrackNum(CBaseSplitterOutputPin* pPin); - HRESULT AddOutputPin(DWORD TrackNum, CAutoPtr pPin); - HRESULT RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt); - virtual HRESULT DeleteOutputs(); - virtual HRESULT CreateOutputs(IAsyncReader* pAsyncReader) = 0; // override this ... - virtual LPCTSTR GetPartFilename(IAsyncReader* pAsyncReader); - - LONGLONG m_nOpenProgress; - bool m_fAbort; - - REFERENCE_TIME m_rtDuration; // derived filter should set this at the end of CreateOutputs - REFERENCE_TIME m_rtStart, m_rtStop, m_rtCurrent, m_rtNewStart, m_rtNewStop; - double m_dRate; - - CAtlList m_bDiscontinuitySent; - CAtlList m_pActivePins; - - CAMEvent m_eEndFlush; - bool m_fFlushing; - - void DeliverBeginFlush(); - void DeliverEndFlush(); - HRESULT DeliverPacket(CAutoPtr p); - - int m_priority; - - CFontInstaller m_fontinst; - - int m_QueueMaxPackets; - -protected: - enum { CMD_EXIT, CMD_SEEK }; - DWORD ThreadProc(); - - // ... and also override all these too - virtual bool DemuxInit() = 0; - virtual void DemuxSeek(REFERENCE_TIME rt) = 0; - virtual bool DemuxLoop() = 0; - virtual bool BuildPlaylist(LPCTSTR pszFileName, CAtlList& Items) { return false; }; - virtual bool BuildChapters(LPCTSTR pszFileName, CAtlList& PlaylistItems, CAtlList& Items) { return false; }; - -public: - CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, - const CLSID& clsid, int QueueMaxPackets = MAXPACKETS); - virtual ~CBaseSplitterFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - bool IsAnyPinDrying(); - - HRESULT BreakConnect(PIN_DIRECTION dir, CBasePin* pPin); - HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin); - - int GetPinCount(); - CBasePin* GetPin(int n); - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // IFileSourceFilter - - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - -protected: - friend class CBaseSplitterOutputPin; - virtual HRESULT SetPositionsInternal(void* id, LONGLONG* pCurrent, - DWORD dwCurrentFlags, LONGLONG* pStop, - DWORD dwStopFlags); - -private: - REFERENCE_TIME m_rtLastStart, m_rtLastStop; - CAtlList m_LastSeekers; - -public: - // IAMOpenProgress - - STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent); - STDMETHODIMP AbortOperation(); - - // IDispatch - - STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } - STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { return E_NOTIMPL; } - STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { return E_NOTIMPL; } - STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) { return E_NOTIMPL; } - - // IAMMediaContent - - STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName); - STDMETHODIMP get_Title(BSTR* pbstrTitle); - STDMETHODIMP get_Rating(BSTR* pbstrRating); - STDMETHODIMP get_Description(BSTR* pbstrDescription); - STDMETHODIMP get_Copyright(BSTR* pbstrCopyright); - STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL) { return E_NOTIMPL; } - STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; } - STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; } - STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL) { return E_NOTIMPL; } - STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL) { return E_NOTIMPL; } - STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) { return E_NOTIMPL; } - STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) { return E_NOTIMPL; } - STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText) { return E_NOTIMPL; } - - // IAMExtendedSeeking - - STDMETHODIMP get_ExSeekCapabilities(long* pExCapabilities); - STDMETHODIMP get_MarkerCount(long* pMarkerCount); - STDMETHODIMP get_CurrentMarker(long* pCurrentMarker); - STDMETHODIMP GetMarkerTime(long MarkerNum, double* pMarkerTime); - STDMETHODIMP GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName); - STDMETHODIMP put_PlaybackSpeed(double Speed) { return E_NOTIMPL; } - STDMETHODIMP get_PlaybackSpeed(double* pSpeed) { return E_NOTIMPL; } - - // IKeyFrameInfo - - STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs); - STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs); - - // IBufferInfo - - STDMETHODIMP_(int) GetCount(); - STDMETHODIMP GetStatus(int i, int& samples, int& size); - STDMETHODIMP_(DWORD) GetPriority(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#pragma once + +#include +#include +#include +#include "IKeyFrameInfo.h" +#include "IBufferInfo.h" +#include "IBitRateInfo.h" +#include "AsyncReader.h" +#include "../../../DSUtil/DSMPropertyBag.h" +#include "../../../DSUtil/FontInstaller.h" + +#define MINPACKETS 100 // Beliyaal: Changed the min number of packets to allow Bluray playback over network +#define MINPACKETSIZE 256*1024 // Beliyaal: Changed the min packet size to allow Bluray playback over network +#define MAXPACKETS 2000 +#define MAXPACKETSIZE 128*1024*1024 + +class Packet : public CAtlArray +{ +public: + DWORD TrackNumber; + BOOL bDiscontinuity, bSyncPoint, bAppendable; + static const REFERENCE_TIME INVALID_TIME = _I64_MIN; + REFERENCE_TIME rtStart, rtStop; + AM_MEDIA_TYPE* pmt; + Packet() + : TrackNumber(0) + , bDiscontinuity(FALSE) + , bSyncPoint(FALSE) + , bAppendable(FALSE) + , rtStart(0) + , rtStop(0) + , pmt(nullptr) { + } + virtual ~Packet() { + if (pmt) { + DeleteMediaType(pmt); + } + } + virtual int GetDataSize() { return (int)GetCount(); } + void SetData(const void* ptr, DWORD len) { + SetCount(len); + memcpy(GetData(), ptr, len); + } +}; + +class CPacketQueue2 + : public CCritSec + , protected CAutoPtrList +{ + int m_size; + +public: + CPacketQueue2(); + void Add(CAutoPtr p); + CAutoPtr Remove(); + void RemoveAll(); + int GetCount(), GetSize(); +}; + +class CBaseSplitterFilter; + +class CBaseSplitterInputPin + : public CBasePin +{ +protected: + CComQIPtr m_pAsyncReader; + +public: + CBaseSplitterInputPin(LPCTSTR pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CBaseSplitterInputPin(); + + HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT CheckMediaType(const CMediaType* pmt); + + HRESULT CheckConnect(IPin* pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pPin); + + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); +}; + +class CBaseSplitterOutputPin + : public CBaseOutputPin + , public IDSMPropertyBagImpl + , protected CAMThread + , public IMediaSeeking + , public IBitRateInfo +{ +protected: + CAtlArray m_mts; + int m_nBuffers; + +private: + CPacketQueue2 m_queue; + + HRESULT m_hrDeliver; + + bool m_fFlushing, m_fFlushed; + CAMEvent m_eEndFlush; + + enum { CMD_EXIT }; + DWORD ThreadProc(); + + void MakeISCRHappy(); + + // please only use DeliverPacket from the derived class + HRESULT GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags); + HRESULT Deliver(IMediaSample* pSample); + + // IBitRateInfo + struct BitRateInfo { + UINT64 nTotalBytesDelivered = 0; + REFERENCE_TIME rtTotalTimeDelivered = 0; + UINT64 nBytesSinceLastDeliverTime = 0; + REFERENCE_TIME rtLastDeliverTime = Packet::INVALID_TIME; + DWORD nCurrentBitRate = 0; + DWORD nAverageBitRate = 0; + } m_BitRate; + + int m_QueueMaxPackets; + +protected: + REFERENCE_TIME m_rtStart; + + // override this if you need some second level stream specific demuxing (optional) + // the default implementation will send the sample as is + virtual HRESULT DeliverPacket(CAutoPtr p); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + +public: + CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, + CBaseFilter* pFilter, CCritSec* pLock, + HRESULT* phr, int nBuffers = 0, + int QueueMaxPackets = MAXPACKETS); + CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, + CCritSec* pLock, HRESULT* phr, + int nBuffers = 0, + int QueueMaxPackets = MAXPACKETS); + virtual ~CBaseSplitterOutputPin(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT SetName(LPCWSTR pName); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + CMediaType& CurrentMediaType() { return m_mt; } + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); + + // Queueing + + HANDLE GetThreadHandle() { + ASSERT(m_hThread != nullptr); + return m_hThread; + } + void SetThreadPriority(int nPriority) { + if (m_hThread) { + ::SetThreadPriority(m_hThread, nPriority); + } + } + + HRESULT Active(); + HRESULT Inactive(); + + HRESULT DeliverBeginFlush(); + HRESULT DeliverEndFlush(); + HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + int QueueCount(); + int QueueSize(); + HRESULT QueueEndOfStream(); + HRESULT QueuePacket(CAutoPtr p); + + // returns true for everything which (the lack of) would not block other streams (subtitle streams, basically) + virtual bool IsDiscontinuous(); + + // returns IStreamsSwitcherInputPin::IsActive(), when it can find one downstream + bool IsActive(); + + // IBitRateInfo + + STDMETHODIMP_(DWORD) GetCurrentBitRate() { return m_BitRate.nCurrentBitRate; } + STDMETHODIMP_(DWORD) GetAverageBitRate() { return m_BitRate.nAverageBitRate; } +}; + +class CBaseSplitterFilter + : public CBaseFilter + , public CCritSec + , public IDSMPropertyBagImpl + , public IDSMResourceBagImpl + , public IDSMChapterBagImpl + , protected CAMThread + , public IFileSourceFilter + , public IMediaSeeking + , public IAMOpenProgress + , public IAMMediaContent + , public IAMExtendedSeeking + , public IKeyFrameInfo + , public IBufferInfo +{ + CCritSec m_csPinMap; + CAtlMap m_pPinMap; + + CCritSec m_csmtnew; + CAtlMap m_mtnew; + + CAutoPtrList m_pRetiredOutputs; + + CComQIPtr m_pSyncReader; + +protected: + CStringW m_fn; + + CAutoPtr m_pInput; + CAutoPtrList m_pOutputs; + + CBaseSplitterOutputPin* GetOutputPin(DWORD TrackNum); + DWORD GetOutputTrackNum(CBaseSplitterOutputPin* pPin); + HRESULT AddOutputPin(DWORD TrackNum, CAutoPtr pPin); + HRESULT RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt); + virtual HRESULT DeleteOutputs(); + virtual HRESULT CreateOutputs(IAsyncReader* pAsyncReader) = 0; // override this ... + virtual LPCTSTR GetPartFilename(IAsyncReader* pAsyncReader); + + LONGLONG m_nOpenProgress; + bool m_fAbort; + + REFERENCE_TIME m_rtDuration; // derived filter should set this at the end of CreateOutputs + REFERENCE_TIME m_rtStart, m_rtStop, m_rtCurrent, m_rtNewStart, m_rtNewStop; + double m_dRate; + + CAtlList m_bDiscontinuitySent; + CAtlList m_pActivePins; + + CAMEvent m_eEndFlush; + bool m_fFlushing; + + void DeliverBeginFlush(); + void DeliverEndFlush(); + HRESULT DeliverPacket(CAutoPtr p); + + int m_priority; + + CFontInstaller m_fontinst; + + int m_QueueMaxPackets; + +protected: + enum { CMD_EXIT, CMD_SEEK }; + DWORD ThreadProc(); + + // ... and also override all these too + virtual bool DemuxInit() = 0; + virtual void DemuxSeek(REFERENCE_TIME rt) = 0; + virtual bool DemuxLoop() = 0; + virtual bool BuildPlaylist(LPCTSTR pszFileName, CAtlList& Items) { return false; }; + virtual bool BuildChapters(LPCTSTR pszFileName, CAtlList& PlaylistItems, CAtlList& Items) { return false; }; + +public: + CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, + const CLSID& clsid, int QueueMaxPackets = MAXPACKETS); + virtual ~CBaseSplitterFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + bool IsAnyPinDrying(); + + HRESULT BreakConnect(PIN_DIRECTION dir, CBasePin* pPin); + HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin); + + int GetPinCount(); + CBasePin* GetPin(int n); + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // IFileSourceFilter + + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + +protected: + friend class CBaseSplitterOutputPin; + virtual HRESULT SetPositionsInternal(void* id, LONGLONG* pCurrent, + DWORD dwCurrentFlags, LONGLONG* pStop, + DWORD dwStopFlags); + +private: + REFERENCE_TIME m_rtLastStart, m_rtLastStop; + CAtlList m_LastSeekers; + +public: + // IAMOpenProgress + + STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent); + STDMETHODIMP AbortOperation(); + + // IDispatch + + STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } + STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { return E_NOTIMPL; } + STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { return E_NOTIMPL; } + STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) { return E_NOTIMPL; } + + // IAMMediaContent + + STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName); + STDMETHODIMP get_Title(BSTR* pbstrTitle); + STDMETHODIMP get_Rating(BSTR* pbstrRating); + STDMETHODIMP get_Description(BSTR* pbstrDescription); + STDMETHODIMP get_Copyright(BSTR* pbstrCopyright); + STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL) { return E_NOTIMPL; } + STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; } + STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; } + STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL) { return E_NOTIMPL; } + STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL) { return E_NOTIMPL; } + STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) { return E_NOTIMPL; } + STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) { return E_NOTIMPL; } + STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText) { return E_NOTIMPL; } + + // IAMExtendedSeeking + + STDMETHODIMP get_ExSeekCapabilities(long* pExCapabilities); + STDMETHODIMP get_MarkerCount(long* pMarkerCount); + STDMETHODIMP get_CurrentMarker(long* pCurrentMarker); + STDMETHODIMP GetMarkerTime(long MarkerNum, double* pMarkerTime); + STDMETHODIMP GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName); + STDMETHODIMP put_PlaybackSpeed(double Speed) { return E_NOTIMPL; } + STDMETHODIMP get_PlaybackSpeed(double* pSpeed) { return E_NOTIMPL; } + + // IKeyFrameInfo + + STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs); + STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs); + + // IBufferInfo + + STDMETHODIMP_(int) GetCount(); + STDMETHODIMP GetStatus(int i, int& samples, int& size); + STDMETHODIMP_(DWORD) GetPriority(); +}; diff --git a/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj b/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj index ababd13b4a5..35ba07511b3 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj +++ b/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj @@ -1,72 +1,72 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {37768B3F-89BC-4C16-B2A8-767C5DA84C3F} - BaseSplitter - MFCProj - BaseSplitter - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - - Create - - - - - - - - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {37768B3F-89BC-4C16-B2A8-767C5DA84C3F} + BaseSplitter + MFCProj + BaseSplitter + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + + Create + + + + + + + + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj.filters b/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj.filters index 0d75cd1e58f..652569ca26a 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj.filters +++ b/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj.filters @@ -1,47 +1,47 @@ - - - - - {b95be5c7-0978-4aad-b33b-140fbdb42012} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {c2020e7a-be9e-43da-8a23-fe30c723d21d} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {b95be5c7-0978-4aad-b33b-140fbdb42012} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2020e7a-be9e-43da-8a23-fe30c723d21d} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/parser/BaseSplitter/BaseSplitterFile.cpp b/src/filters/parser/BaseSplitter/BaseSplitterFile.cpp index f549c0aa65e..597b5e5d040 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitterFile.cpp +++ b/src/filters/parser/BaseSplitter/BaseSplitterFile.cpp @@ -1,259 +1,259 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "BaseSplitterFile.h" -#include "../../../DSUtil/DSUtil.h" - -// -// CBaseSplitterFile -// - -CBaseSplitterFile::CBaseSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr, int cachelen, bool fRandomAccess, bool fStreaming) - : m_pAsyncReader(pAsyncReader) - , m_cachepos(0) - , m_cachelen(0) - , m_cachetotal(0) - , m_fStreaming(false) - , m_fRandomAccess(false) - , m_pos(0) - , m_len(0) - , m_bitbuff(0) - , m_bitlen(0) -{ - if (!m_pAsyncReader) { - hr = E_UNEXPECTED; - return; - } - - LONGLONG total = 0, available; - hr = m_pAsyncReader->Length(&total, &available); - - m_fStreaming = total == 0 && available > 0; - m_fRandomAccess = total > 0 && total == available; - m_len = total; - - if (FAILED(hr) || fRandomAccess && !m_fRandomAccess || !fStreaming && m_fStreaming || m_len < 0) { - hr = E_FAIL; - return; - } - - if (!SetCacheSize(cachelen)) { - hr = E_OUTOFMEMORY; - return; - } - - hr = S_OK; -} - -bool CBaseSplitterFile::SetCacheSize(int cachelen) -{ - m_pCache.Free(); - m_cachetotal = 0; - if (!m_pCache.Allocate((size_t)cachelen)) { - return false; - } - m_cachetotal = cachelen; - m_cachelen = 0; - return true; -} - -__int64 CBaseSplitterFile::GetPos() -{ - return m_pos - (m_bitlen >> 3); -} - -__int64 CBaseSplitterFile::GetAvailable() -{ - LONGLONG total, available = 0; - m_pAsyncReader->Length(&total, &available); - return available; -} - -__int64 CBaseSplitterFile::GetLength(bool fUpdate) -{ - if (m_fStreaming) { - m_len = GetAvailable(); - } else if (fUpdate) { - LONGLONG total = 0, available; - m_pAsyncReader->Length(&total, &available); - m_len = total; - } - - return m_len; -} - -void CBaseSplitterFile::Seek(__int64 pos) -{ - __int64 len = GetLength(); - m_pos = std::min(std::max(pos, 0ll), len); - BitFlush(); -} - -HRESULT CBaseSplitterFile::Read(BYTE* pData, __int64 len) -{ - CheckPointer(m_pAsyncReader, E_NOINTERFACE); - - HRESULT hr = S_OK; - - if (!m_fRandomAccess) { - LONGLONG total = 0, available = -1; - m_pAsyncReader->Length(&total, &available); - if (total == available) { - m_fRandomAccess = true; - OnComplete(); - } - } - - if (m_cachetotal == 0 || !m_pCache) { - hr = m_pAsyncReader->SyncRead(m_pos, (long)len, pData); - m_pos += len; - return hr; - } - - BYTE* pCache = m_pCache; - - if (m_cachepos <= m_pos && m_pos < m_cachepos + m_cachelen) { - __int64 minlen = std::min(len, m_cachelen - (m_pos - m_cachepos)); - - memcpy(pData, &pCache[m_pos - m_cachepos], (size_t)minlen); - - len -= minlen; - m_pos += minlen; - pData += minlen; - } - - while (len > m_cachetotal) { - hr = m_pAsyncReader->SyncRead(m_pos, (long)m_cachetotal, pData); - if (S_OK != hr) { - return hr; - } - - len -= m_cachetotal; - m_pos += m_cachetotal; - pData += m_cachetotal; - } - - while (len > 0) { - __int64 tmplen = GetLength(); - __int64 maxlen = std::min(tmplen - m_pos, m_cachetotal); - __int64 minlen = std::min(len, maxlen); - if (minlen <= 0) { - return S_FALSE; - } - - hr = m_pAsyncReader->SyncRead(m_pos, (long)maxlen, pCache); - if (S_OK != hr) { - return hr; - } - - m_cachepos = m_pos; - m_cachelen = maxlen; - - memcpy(pData, pCache, (size_t)minlen); - - len -= minlen; - m_pos += minlen; - pData += minlen; - } - - return hr; -} - -UINT64 CBaseSplitterFile::BitRead(int nBits, bool fPeek) -{ - ASSERT(nBits >= 0 && nBits <= 64); - - while (m_bitlen < nBits) { - m_bitbuff <<= 8; - if (S_OK != Read((BYTE*)&m_bitbuff, 1)) { - return 0; // EOF? // ASSERT(0); - } - m_bitlen += 8; - } - - int bitlen = m_bitlen - nBits; - - UINT64 ret; - // The shift to 64 bits can give incorrect results. - // "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." - if (nBits == 64) { - ret = m_bitbuff; - } else { - ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); - } - - if (!fPeek) { - m_bitbuff &= ((1ui64 << bitlen) - 1); - m_bitlen = bitlen; - } - - return ret; -} - -void CBaseSplitterFile::BitByteAlign() -{ - m_bitlen &= ~7; -} - -void CBaseSplitterFile::BitFlush() -{ - m_bitlen = 0; -} - -HRESULT CBaseSplitterFile::ByteRead(BYTE* pData, __int64 len) -{ - Seek(GetPos()); - return Read(pData, len); -} - -UINT64 CBaseSplitterFile::UExpGolombRead() -{ - int n = -1; - for (BYTE b = 0; !b; n++) { - b = (BYTE)BitRead(1); - } - return (1ui64 << n) - 1 + BitRead(n); -} - -INT64 CBaseSplitterFile::SExpGolombRead() -{ - UINT64 k = UExpGolombRead(); - return ((k & 1) ? 1 : -1) * ((k + 1) >> 1); -} - -HRESULT CBaseSplitterFile::HasMoreData(__int64 len, DWORD ms) -{ - __int64 available = GetLength() - GetPos(); - - if (!m_fStreaming) { - return available < 1 ? E_FAIL : S_OK; - } - - if (available < len) { - if (ms > 0) { - Sleep(ms); - } - return S_FALSE; - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "BaseSplitterFile.h" +#include "../../../DSUtil/DSUtil.h" + +// +// CBaseSplitterFile +// + +CBaseSplitterFile::CBaseSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr, int cachelen, bool fRandomAccess, bool fStreaming) + : m_pAsyncReader(pAsyncReader) + , m_cachepos(0) + , m_cachelen(0) + , m_cachetotal(0) + , m_fStreaming(false) + , m_fRandomAccess(false) + , m_pos(0) + , m_len(0) + , m_bitbuff(0) + , m_bitlen(0) +{ + if (!m_pAsyncReader) { + hr = E_UNEXPECTED; + return; + } + + LONGLONG total = 0, available; + hr = m_pAsyncReader->Length(&total, &available); + + m_fStreaming = total == 0 && available > 0; + m_fRandomAccess = total > 0 && total == available; + m_len = total; + + if (FAILED(hr) || fRandomAccess && !m_fRandomAccess || !fStreaming && m_fStreaming || m_len < 0) { + hr = E_FAIL; + return; + } + + if (!SetCacheSize(cachelen)) { + hr = E_OUTOFMEMORY; + return; + } + + hr = S_OK; +} + +bool CBaseSplitterFile::SetCacheSize(int cachelen) +{ + m_pCache.Free(); + m_cachetotal = 0; + if (!m_pCache.Allocate((size_t)cachelen)) { + return false; + } + m_cachetotal = cachelen; + m_cachelen = 0; + return true; +} + +__int64 CBaseSplitterFile::GetPos() +{ + return m_pos - (m_bitlen >> 3); +} + +__int64 CBaseSplitterFile::GetAvailable() +{ + LONGLONG total, available = 0; + m_pAsyncReader->Length(&total, &available); + return available; +} + +__int64 CBaseSplitterFile::GetLength(bool fUpdate) +{ + if (m_fStreaming) { + m_len = GetAvailable(); + } else if (fUpdate) { + LONGLONG total = 0, available; + m_pAsyncReader->Length(&total, &available); + m_len = total; + } + + return m_len; +} + +void CBaseSplitterFile::Seek(__int64 pos) +{ + __int64 len = GetLength(); + m_pos = std::min(std::max(pos, 0ll), len); + BitFlush(); +} + +HRESULT CBaseSplitterFile::Read(BYTE* pData, __int64 len) +{ + CheckPointer(m_pAsyncReader, E_NOINTERFACE); + + HRESULT hr = S_OK; + + if (!m_fRandomAccess) { + LONGLONG total = 0, available = -1; + m_pAsyncReader->Length(&total, &available); + if (total == available) { + m_fRandomAccess = true; + OnComplete(); + } + } + + if (m_cachetotal == 0 || !m_pCache) { + hr = m_pAsyncReader->SyncRead(m_pos, (long)len, pData); + m_pos += len; + return hr; + } + + BYTE* pCache = m_pCache; + + if (m_cachepos <= m_pos && m_pos < m_cachepos + m_cachelen) { + __int64 minlen = std::min(len, m_cachelen - (m_pos - m_cachepos)); + + memcpy(pData, &pCache[m_pos - m_cachepos], (size_t)minlen); + + len -= minlen; + m_pos += minlen; + pData += minlen; + } + + while (len > m_cachetotal) { + hr = m_pAsyncReader->SyncRead(m_pos, (long)m_cachetotal, pData); + if (S_OK != hr) { + return hr; + } + + len -= m_cachetotal; + m_pos += m_cachetotal; + pData += m_cachetotal; + } + + while (len > 0) { + __int64 tmplen = GetLength(); + __int64 maxlen = std::min(tmplen - m_pos, m_cachetotal); + __int64 minlen = std::min(len, maxlen); + if (minlen <= 0) { + return S_FALSE; + } + + hr = m_pAsyncReader->SyncRead(m_pos, (long)maxlen, pCache); + if (S_OK != hr) { + return hr; + } + + m_cachepos = m_pos; + m_cachelen = maxlen; + + memcpy(pData, pCache, (size_t)minlen); + + len -= minlen; + m_pos += minlen; + pData += minlen; + } + + return hr; +} + +UINT64 CBaseSplitterFile::BitRead(int nBits, bool fPeek) +{ + ASSERT(nBits >= 0 && nBits <= 64); + + while (m_bitlen < nBits) { + m_bitbuff <<= 8; + if (S_OK != Read((BYTE*)&m_bitbuff, 1)) { + return 0; // EOF? // ASSERT(0); + } + m_bitlen += 8; + } + + int bitlen = m_bitlen - nBits; + + UINT64 ret; + // The shift to 64 bits can give incorrect results. + // "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." + if (nBits == 64) { + ret = m_bitbuff; + } else { + ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); + } + + if (!fPeek) { + m_bitbuff &= ((1ui64 << bitlen) - 1); + m_bitlen = bitlen; + } + + return ret; +} + +void CBaseSplitterFile::BitByteAlign() +{ + m_bitlen &= ~7; +} + +void CBaseSplitterFile::BitFlush() +{ + m_bitlen = 0; +} + +HRESULT CBaseSplitterFile::ByteRead(BYTE* pData, __int64 len) +{ + Seek(GetPos()); + return Read(pData, len); +} + +UINT64 CBaseSplitterFile::UExpGolombRead() +{ + int n = -1; + for (BYTE b = 0; !b; n++) { + b = (BYTE)BitRead(1); + } + return (1ui64 << n) - 1 + BitRead(n); +} + +INT64 CBaseSplitterFile::SExpGolombRead() +{ + UINT64 k = UExpGolombRead(); + return ((k & 1) ? 1 : -1) * ((k + 1) >> 1); +} + +HRESULT CBaseSplitterFile::HasMoreData(__int64 len, DWORD ms) +{ + __int64 available = GetLength() - GetPos(); + + if (!m_fStreaming) { + return available < 1 ? E_FAIL : S_OK; + } + + if (available < len) { + if (ms > 0) { + Sleep(ms); + } + return S_FALSE; + } + + return S_OK; +} diff --git a/src/filters/parser/BaseSplitter/BaseSplitterFile.h b/src/filters/parser/BaseSplitter/BaseSplitterFile.h index 1069832ecdc..ddcff2321ec 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitterFile.h +++ b/src/filters/parser/BaseSplitter/BaseSplitterFile.h @@ -1,71 +1,71 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include - -#define DEFAULT_CACHE_LENGTH 64*1024 // Beliyaal: Changed the default cache length to allow Bluray playback over network - -class CBaseSplitterFile -{ - CComPtr m_pAsyncReader; - CAutoVectorPtr m_pCache; - __int64 m_cachepos, m_cachelen, m_cachetotal; - - bool m_fStreaming, m_fRandomAccess; - __int64 m_pos, m_len; - - virtual HRESULT Read(BYTE* pData, __int64 len); // use ByteRead - -protected: - UINT64 m_bitbuff; - int m_bitlen; - - virtual void OnComplete() {} - -public: - CBaseSplitterFile(IAsyncReader* pReader, HRESULT& hr, - int cachelen = DEFAULT_CACHE_LENGTH, - bool fRandomAccess = true, bool fStreaming = false); - virtual ~CBaseSplitterFile() {} - - bool SetCacheSize(int cachelen = DEFAULT_CACHE_LENGTH); - - __int64 GetPos(); - __int64 GetAvailable(); - __int64 GetLength(bool fUpdate = false); - __int64 GetRemaining() { return std::max(0ll, GetLength() - GetPos()); } - virtual void Seek(__int64 pos); - - UINT64 UExpGolombRead(); - INT64 SExpGolombRead(); - - UINT64 BitRead(int nBits, bool fPeek = false); - void BitByteAlign(), BitFlush(); - HRESULT ByteRead(BYTE* pData, __int64 len); - - bool IsStreaming() const { return m_fStreaming; } - bool IsRandomAccess() const { return m_fRandomAccess; } - - HRESULT HasMoreData(__int64 len = 1, DWORD ms = 1); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include + +#define DEFAULT_CACHE_LENGTH 64*1024 // Beliyaal: Changed the default cache length to allow Bluray playback over network + +class CBaseSplitterFile +{ + CComPtr m_pAsyncReader; + CAutoVectorPtr m_pCache; + __int64 m_cachepos, m_cachelen, m_cachetotal; + + bool m_fStreaming, m_fRandomAccess; + __int64 m_pos, m_len; + + virtual HRESULT Read(BYTE* pData, __int64 len); // use ByteRead + +protected: + UINT64 m_bitbuff; + int m_bitlen; + + virtual void OnComplete() {} + +public: + CBaseSplitterFile(IAsyncReader* pReader, HRESULT& hr, + int cachelen = DEFAULT_CACHE_LENGTH, + bool fRandomAccess = true, bool fStreaming = false); + virtual ~CBaseSplitterFile() {} + + bool SetCacheSize(int cachelen = DEFAULT_CACHE_LENGTH); + + __int64 GetPos(); + __int64 GetAvailable(); + __int64 GetLength(bool fUpdate = false); + __int64 GetRemaining() { return std::max(0ll, GetLength() - GetPos()); } + virtual void Seek(__int64 pos); + + UINT64 UExpGolombRead(); + INT64 SExpGolombRead(); + + UINT64 BitRead(int nBits, bool fPeek = false); + void BitByteAlign(), BitFlush(); + HRESULT ByteRead(BYTE* pData, __int64 len); + + bool IsStreaming() const { return m_fStreaming; } + bool IsRandomAccess() const { return m_fRandomAccess; } + + HRESULT HasMoreData(__int64 len = 1, DWORD ms = 1); +}; diff --git a/src/filters/parser/BaseSplitter/MultiFiles.cpp b/src/filters/parser/BaseSplitter/MultiFiles.cpp index d422f85ff2d..eabd492d907 100644 --- a/src/filters/parser/BaseSplitter/MultiFiles.cpp +++ b/src/filters/parser/BaseSplitter/MultiFiles.cpp @@ -1,198 +1,198 @@ -/* - * (C) 2009-2014 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 . - * - */ - - -#include "stdafx.h" -#include "MultiFiles.h" - - -IMPLEMENT_DYNAMIC(CMultiFiles, CObject) - -CMultiFiles::CMultiFiles() - : m_pCurrentPTSOffset(nullptr) - , m_hFile(INVALID_HANDLE_VALUE) - , m_nCurPart(-1) - , m_llTotalLength(0) -{ -} - -void CMultiFiles::Reset() -{ - m_strFiles.RemoveAll(); - m_FilesSize.RemoveAll(); - m_rtPtsOffsets.RemoveAll(); - m_llTotalLength = 0; -} - -BOOL CMultiFiles::Open(LPCTSTR lpszFileName, UINT nOpenFlags) -{ - Reset(); - m_strFiles.Add(lpszFileName); - - return OpenPart(0); -} - -BOOL CMultiFiles::OpenFiles(CAtlList& files, UINT nOpenFlags) -{ - POSITION pos = files.GetHeadPosition(); - LARGE_INTEGER llSize; - int nPos = 0; - REFERENCE_TIME rtDur = 0; - - Reset(); - while (pos) { - CHdmvClipInfo::PlaylistItem& s = files.GetNext(pos); - m_strFiles.Add(s.m_strFileName); - if (!OpenPart(nPos)) { - return false; - } - - llSize.QuadPart = 0; - GetFileSizeEx(m_hFile, &llSize); - m_llTotalLength += llSize.QuadPart; - m_FilesSize.Add(llSize.QuadPart); - m_rtPtsOffsets.Add(rtDur); - rtDur += s.Duration(); - nPos++; - } - - if (files.GetCount() > 1) { - ClosePart(); - } - - return TRUE; -} - -ULONGLONG CMultiFiles::Seek(LONGLONG lOff, UINT nFrom) -{ - LARGE_INTEGER llNewPos; - LARGE_INTEGER llOff; - - if (m_strFiles.GetCount() == 1) { - llOff.QuadPart = lOff; - SetFilePointerEx(m_hFile, llOff, &llNewPos, nFrom); - - return llNewPos.QuadPart; - } else { - ULONGLONG lAbsolutePos = GetAbsolutePosition(lOff, nFrom); - int nNewPart = 0; - ULONGLONG llSum = 0; - - while (m_FilesSize[nNewPart] + llSum <= lAbsolutePos) { - llSum += m_FilesSize[nNewPart]; - nNewPart++; - } - - OpenPart(nNewPart); - llOff.QuadPart = lAbsolutePos - llSum; - SetFilePointerEx(m_hFile, llOff, &llNewPos, FILE_BEGIN); - - return llSum + llNewPos.QuadPart; - } -} - -ULONGLONG CMultiFiles::GetAbsolutePosition(LONGLONG lOff, UINT nFrom) -{ - LARGE_INTEGER llNoMove = {0, 0}; - LARGE_INTEGER llCurPos; - - switch (nFrom) { - case begin: - return lOff; - case current: - SetFilePointerEx(m_hFile, llNoMove, &llCurPos, FILE_CURRENT); - return llCurPos.QuadPart + lOff; - case end: - return m_llTotalLength - lOff; - default: - return 0; // just used to quash "not all control paths return a value" warning - } -} - -ULONGLONG CMultiFiles::GetLength() const -{ - if (m_strFiles.GetCount() == 1) { - LARGE_INTEGER llSize; - GetFileSizeEx(m_hFile, &llSize); - return llSize.QuadPart; - } else { - return m_llTotalLength; - } -} - -UINT CMultiFiles::Read(void* lpBuf, UINT nCount) -{ - DWORD dwRead; - do { - if (!ReadFile(m_hFile, lpBuf, nCount, &dwRead, nullptr)) { - break; - } - - if (dwRead != nCount && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)) { - OpenPart(m_nCurPart + 1); - lpBuf = (void*)((BYTE*)lpBuf + dwRead); - nCount -= dwRead; - } - } while (nCount != dwRead && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)); - return dwRead; -} - -void CMultiFiles::Close() -{ - ClosePart(); - Reset(); -} - -CMultiFiles::~CMultiFiles() -{ - Close(); -} - -BOOL CMultiFiles::OpenPart(int nPart) -{ - if (m_nCurPart == nPart) { - return TRUE; - } else { - CString fn; - - ClosePart(); - - fn = m_strFiles.GetAt(nPart); - m_hFile = CreateFile(fn, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); - - if (m_hFile != INVALID_HANDLE_VALUE) { - m_nCurPart = nPart; - if (m_pCurrentPTSOffset != nullptr) { - *m_pCurrentPTSOffset = m_rtPtsOffsets[nPart]; - } - } - - return (m_hFile != INVALID_HANDLE_VALUE); - } -} - -void CMultiFiles::ClosePart() -{ - if (m_hFile != INVALID_HANDLE_VALUE) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - m_nCurPart = -1; - } -} +/* + * (C) 2009-2014 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 . + * + */ + + +#include "stdafx.h" +#include "MultiFiles.h" + + +IMPLEMENT_DYNAMIC(CMultiFiles, CObject) + +CMultiFiles::CMultiFiles() + : m_pCurrentPTSOffset(nullptr) + , m_hFile(INVALID_HANDLE_VALUE) + , m_nCurPart(-1) + , m_llTotalLength(0) +{ +} + +void CMultiFiles::Reset() +{ + m_strFiles.RemoveAll(); + m_FilesSize.RemoveAll(); + m_rtPtsOffsets.RemoveAll(); + m_llTotalLength = 0; +} + +BOOL CMultiFiles::Open(LPCTSTR lpszFileName, UINT nOpenFlags) +{ + Reset(); + m_strFiles.Add(lpszFileName); + + return OpenPart(0); +} + +BOOL CMultiFiles::OpenFiles(CAtlList& files, UINT nOpenFlags) +{ + POSITION pos = files.GetHeadPosition(); + LARGE_INTEGER llSize; + int nPos = 0; + REFERENCE_TIME rtDur = 0; + + Reset(); + while (pos) { + CHdmvClipInfo::PlaylistItem& s = files.GetNext(pos); + m_strFiles.Add(s.m_strFileName); + if (!OpenPart(nPos)) { + return false; + } + + llSize.QuadPart = 0; + GetFileSizeEx(m_hFile, &llSize); + m_llTotalLength += llSize.QuadPart; + m_FilesSize.Add(llSize.QuadPart); + m_rtPtsOffsets.Add(rtDur); + rtDur += s.Duration(); + nPos++; + } + + if (files.GetCount() > 1) { + ClosePart(); + } + + return TRUE; +} + +ULONGLONG CMultiFiles::Seek(LONGLONG lOff, UINT nFrom) +{ + LARGE_INTEGER llNewPos; + LARGE_INTEGER llOff; + + if (m_strFiles.GetCount() == 1) { + llOff.QuadPart = lOff; + SetFilePointerEx(m_hFile, llOff, &llNewPos, nFrom); + + return llNewPos.QuadPart; + } else { + ULONGLONG lAbsolutePos = GetAbsolutePosition(lOff, nFrom); + int nNewPart = 0; + ULONGLONG llSum = 0; + + while (m_FilesSize[nNewPart] + llSum <= lAbsolutePos) { + llSum += m_FilesSize[nNewPart]; + nNewPart++; + } + + OpenPart(nNewPart); + llOff.QuadPart = lAbsolutePos - llSum; + SetFilePointerEx(m_hFile, llOff, &llNewPos, FILE_BEGIN); + + return llSum + llNewPos.QuadPart; + } +} + +ULONGLONG CMultiFiles::GetAbsolutePosition(LONGLONG lOff, UINT nFrom) +{ + LARGE_INTEGER llNoMove = {0, 0}; + LARGE_INTEGER llCurPos; + + switch (nFrom) { + case begin: + return lOff; + case current: + SetFilePointerEx(m_hFile, llNoMove, &llCurPos, FILE_CURRENT); + return llCurPos.QuadPart + lOff; + case end: + return m_llTotalLength - lOff; + default: + return 0; // just used to quash "not all control paths return a value" warning + } +} + +ULONGLONG CMultiFiles::GetLength() const +{ + if (m_strFiles.GetCount() == 1) { + LARGE_INTEGER llSize; + GetFileSizeEx(m_hFile, &llSize); + return llSize.QuadPart; + } else { + return m_llTotalLength; + } +} + +UINT CMultiFiles::Read(void* lpBuf, UINT nCount) +{ + DWORD dwRead; + do { + if (!ReadFile(m_hFile, lpBuf, nCount, &dwRead, nullptr)) { + break; + } + + if (dwRead != nCount && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)) { + OpenPart(m_nCurPart + 1); + lpBuf = (void*)((BYTE*)lpBuf + dwRead); + nCount -= dwRead; + } + } while (nCount != dwRead && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)); + return dwRead; +} + +void CMultiFiles::Close() +{ + ClosePart(); + Reset(); +} + +CMultiFiles::~CMultiFiles() +{ + Close(); +} + +BOOL CMultiFiles::OpenPart(int nPart) +{ + if (m_nCurPart == nPart) { + return TRUE; + } else { + CString fn; + + ClosePart(); + + fn = m_strFiles.GetAt(nPart); + m_hFile = CreateFile(fn, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + + if (m_hFile != INVALID_HANDLE_VALUE) { + m_nCurPart = nPart; + if (m_pCurrentPTSOffset != nullptr) { + *m_pCurrentPTSOffset = m_rtPtsOffsets[nPart]; + } + } + + return (m_hFile != INVALID_HANDLE_VALUE); + } +} + +void CMultiFiles::ClosePart() +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + m_nCurPart = -1; + } +} diff --git a/src/filters/parser/BaseSplitter/MultiFiles.h b/src/filters/parser/BaseSplitter/MultiFiles.h index 7ea468fe98c..1bddbdb77dc 100644 --- a/src/filters/parser/BaseSplitter/MultiFiles.h +++ b/src/filters/parser/BaseSplitter/MultiFiles.h @@ -1,101 +1,101 @@ -/* - * (C) 2009-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 . - * - */ - -#pragma once - -#include -#include "../../../DSUtil/DSUtil.h" - -class CMultiFiles : public CObject -{ - DECLARE_DYNAMIC(CMultiFiles) - -public: - // Flag values - enum OpenFlags { - modeRead = (int)0x00000, - modeWrite = (int)0x00001, - modeReadWrite = (int)0x00002, - shareCompat = (int)0x00000, - shareExclusive = (int)0x00010, - shareDenyWrite = (int)0x00020, - shareDenyRead = (int)0x00030, - shareDenyNone = (int)0x00040, - modeNoInherit = (int)0x00080, - modeCreate = (int)0x01000, - modeNoTruncate = (int)0x02000, - typeText = (int)0x04000, // typeText and typeBinary are used in derived classes only - typeBinary = (int)0x08000, - osNoBuffer = (int)0x10000, - osWriteThrough = (int)0x20000, - osRandomAccess = (int)0x40000, - osSequentialScan = (int)0x80000 - }; - - enum Attribute { - normal = 0x00, - readOnly = 0x01, - hidden = 0x02, - system = 0x04, - volume = 0x08, - directory = 0x10, - archive = 0x20 - }; - - enum SeekPosition { - begin = 0x0, - current = 0x1, - end = 0x2 - }; - - // Constructors - CMultiFiles(); - - CString m_strFileName; - - // Operations - virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags); - virtual BOOL OpenFiles(CAtlList& files, UINT nOpenFlags); - - - virtual ULONGLONG Seek(LONGLONG lOff, UINT nFrom); - virtual ULONGLONG GetLength() const; - - virtual UINT Read(void* lpBuf, UINT nCount); - virtual void Close(); - - // Implementation -public: - virtual ~CMultiFiles(); - -protected: - REFERENCE_TIME* m_pCurrentPTSOffset; - CAtlArray m_strFiles; - CAtlArray m_FilesSize; - CAtlArray m_rtPtsOffsets; - HANDLE m_hFile; - int m_nCurPart; - ULONGLONG m_llTotalLength; - - BOOL OpenPart(int nPart); - void ClosePart(); - ULONGLONG GetAbsolutePosition(LONGLONG lOff, UINT nFrom); - void Reset(); -}; +/* + * (C) 2009-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 . + * + */ + +#pragma once + +#include +#include "../../../DSUtil/DSUtil.h" + +class CMultiFiles : public CObject +{ + DECLARE_DYNAMIC(CMultiFiles) + +public: + // Flag values + enum OpenFlags { + modeRead = (int)0x00000, + modeWrite = (int)0x00001, + modeReadWrite = (int)0x00002, + shareCompat = (int)0x00000, + shareExclusive = (int)0x00010, + shareDenyWrite = (int)0x00020, + shareDenyRead = (int)0x00030, + shareDenyNone = (int)0x00040, + modeNoInherit = (int)0x00080, + modeCreate = (int)0x01000, + modeNoTruncate = (int)0x02000, + typeText = (int)0x04000, // typeText and typeBinary are used in derived classes only + typeBinary = (int)0x08000, + osNoBuffer = (int)0x10000, + osWriteThrough = (int)0x20000, + osRandomAccess = (int)0x40000, + osSequentialScan = (int)0x80000 + }; + + enum Attribute { + normal = 0x00, + readOnly = 0x01, + hidden = 0x02, + system = 0x04, + volume = 0x08, + directory = 0x10, + archive = 0x20 + }; + + enum SeekPosition { + begin = 0x0, + current = 0x1, + end = 0x2 + }; + + // Constructors + CMultiFiles(); + + CString m_strFileName; + + // Operations + virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags); + virtual BOOL OpenFiles(CAtlList& files, UINT nOpenFlags); + + + virtual ULONGLONG Seek(LONGLONG lOff, UINT nFrom); + virtual ULONGLONG GetLength() const; + + virtual UINT Read(void* lpBuf, UINT nCount); + virtual void Close(); + + // Implementation +public: + virtual ~CMultiFiles(); + +protected: + REFERENCE_TIME* m_pCurrentPTSOffset; + CAtlArray m_strFiles; + CAtlArray m_FilesSize; + CAtlArray m_rtPtsOffsets; + HANDLE m_hFile; + int m_nCurPart; + ULONGLONG m_llTotalLength; + + BOOL OpenPart(int nPart); + void ClosePart(); + ULONGLONG GetAbsolutePosition(LONGLONG lOff, UINT nFrom); + void Reset(); +}; diff --git a/src/filters/parser/BaseSplitter/stdafx.cpp b/src/filters/parser/BaseSplitter/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/parser/BaseSplitter/stdafx.cpp +++ b/src/filters/parser/BaseSplitter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/parser/BaseSplitter/stdafx.h b/src/filters/parser/BaseSplitter/stdafx.h index 619304dd68e..a8517b3e334 100644 --- a/src/filters/parser/BaseSplitter/stdafx.h +++ b/src/filters/parser/BaseSplitter/stdafx.h @@ -1,35 +1,35 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.cpp b/src/filters/parser/DSMSplitter/DSMSplitter.cpp index d67b3f29f93..cc6cd4cf88f 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.cpp +++ b/src/filters/parser/DSMSplitter/DSMSplitter.cpp @@ -1,291 +1,291 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include "../../../DSUtil/DSUtil.h" -#include "../../../DSUtil/ISOLang.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" -#include "DSMSplitter.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia}, - {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, 0, nullptr} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CDSMSplitterFilter), DSMSplitterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CDSMSourceFilter), DSMSourceName, MERIT_NORMAL, 0, nullptr, CLSID_LegacyAmFilterCategory}, -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, - {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - CString str; - str.Format(_T("0,%d,,%%0%dI64x"), DSMSW_SIZE, DSMSW_SIZE * 2); - str.Format(CString(str), DSMSW); - - RegisterSourceFilter( - CLSID_AsyncReader, - MEDIASUBTYPE_DirectShowMedia, - str, nullptr); - - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - UnRegisterSourceFilter(MEDIASUBTYPE_DirectShowMedia); - - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CDSMSplitterFilter -// - -CDSMSplitterFilter::CDSMSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseSplitterFilter(NAME("CDSMSplitterFilter"), pUnk, phr, __uuidof(this)) -{ -} - -CDSMSplitterFilter::~CDSMSplitterFilter() -{ -} - -STDMETHODIMP CDSMSplitterFilter::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - - if (m_pName && m_pName[0] == L'M' && m_pName[1] == L'P' && m_pName[2] == L'C') { - (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); - } else { - wcscpy_s(pInfo->achName, DSMSourceName); - } - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -HRESULT CDSMSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader) -{ - CheckPointer(pAsyncReader, E_POINTER); - - HRESULT hr = E_FAIL; - - m_pFile.Free(); - m_pFile.Attach(DEBUG_NEW CDSMSplitterFile(pAsyncReader, hr, *this, *this)); - if (!m_pFile) { - return E_OUTOFMEMORY; - } - if (FAILED(hr)) { - m_pFile.Free(); - return hr; - } - - m_rtNewStart = m_rtCurrent = 0; - m_rtNewStop = m_rtStop = m_rtDuration = m_pFile->m_rtDuration; - - CAtlArray ids; - - POSITION pos = m_pFile->m_mts.GetStartPosition(); - while (pos) { - BYTE id; - CMediaType mt; - m_pFile->m_mts.GetNextAssoc(pos, id, mt); - ids.Add(id); - } - - std::sort(ids.GetData(), ids.GetData() + ids.GetCount()); - - for (size_t i = 0; i < ids.GetCount(); i++) { - BYTE id = ids[i]; - CMediaType& mt = m_pFile->m_mts[id]; - - CStringW name, lang; - name.Format(L"Output %02u", id); - - CAtlArray mts; - mts.Add(mt); - - CAutoPtr pPinOut(DEBUG_NEW CBaseSplitterOutputPin(mts, name, this, this, &hr)); - - name.Empty(); - - pos = m_pFile->m_sim[id].GetStartPosition(); - while (pos) { - CStringA key; - CStringW value; - m_pFile->m_sim[id].GetNextAssoc(pos, key, value); - pPinOut->SetProperty(CStringW(key), value); - - if (key == "NAME") { - name = value; - } - if (key == "LANG") { - lang = ISOLang::ISO6392ToLanguage(CStringA(value)); - if (lang.IsEmpty()) { - lang = value; - } - } - } - - if (!name.IsEmpty() || !lang.IsEmpty()) { - if (!name.IsEmpty()) { - if (!lang.IsEmpty()) { - name += L" (" + lang + L")"; - } - } else if (!lang.IsEmpty()) { - name = lang; - } - pPinOut->SetName(name); - } - - EXECUTE_ASSERT(SUCCEEDED(AddOutputPin(id, pPinOut))); - } - - pos = m_pFile->m_fim.GetStartPosition(); - while (pos) { - CStringA key; - CStringW value; - m_pFile->m_fim.GetNextAssoc(pos, key, value); - SetProperty(CStringW(key), value); - } - - for (size_t i = 0; i < m_resources.GetCount(); i++) { - const CDSMResource& r = m_resources[i]; - if (r.mime == L"application/x-truetype-font" || - r.mime == L"application/x-font-ttf" || - r.mime == L"application/vnd.ms-opentype") { - //m_fontinst.InstallFont(r.data); - m_fontinst.InstallFontMemory(r.data.GetData(), (UINT)r.data.GetCount()); - } - } - - return !m_pOutputs.IsEmpty() ? S_OK : E_FAIL; -} - -bool CDSMSplitterFilter::DemuxInit() -{ - SetThreadName(DWORD(-1), "CDSMSplitterFilter"); - return true; -} - -void CDSMSplitterFilter::DemuxSeek(REFERENCE_TIME rt) -{ - m_pFile->Seek(m_pFile->FindSyncPoint(rt)); -} - -bool CDSMSplitterFilter::DemuxLoop() -{ - HRESULT hr = S_OK; - - while (SUCCEEDED(hr) && !CheckRequest(nullptr) && m_pFile->GetRemaining()) { - dsmp_t type; - UINT64 len; - - if (!m_pFile->Sync(type, len)) { - continue; - } - - __int64 pos = m_pFile->GetPos(); - - if (type == DSMP_SAMPLE) { - CAutoPtr p(DEBUG_NEW Packet()); - if (m_pFile->Read(len, p)) { - if (p->rtStart != Packet::INVALID_TIME) { - p->rtStart -= m_pFile->m_rtFirst; - p->rtStop -= m_pFile->m_rtFirst; - } - - hr = DeliverPacket(p); - } - } - - m_pFile->Seek(pos + len); - } - - return true; -} - -// IKeyFrameInfo - -STDMETHODIMP CDSMSplitterFilter::GetKeyFrameCount(UINT& nKFs) -{ - CheckPointer(m_pFile, E_UNEXPECTED); - nKFs = (UINT)m_pFile->m_sps.GetCount(); - return S_OK; -} - -STDMETHODIMP CDSMSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs) -{ - CheckPointer(pFormat, E_POINTER); - CheckPointer(pKFs, E_POINTER); - CheckPointer(m_pFile, E_UNEXPECTED); - - if (*pFormat != TIME_FORMAT_MEDIA_TIME) { - return E_INVALIDARG; - } - - // these aren't really the keyframes, but quicky accessable points in the stream - for (nKFs = 0; nKFs < m_pFile->m_sps.GetCount(); nKFs++) { - pKFs[nKFs] = m_pFile->m_sps[nKFs].rt; - } - - return S_OK; -} - -// -// CDSMSourceFilter -// - -CDSMSourceFilter::CDSMSourceFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CDSMSplitterFilter(pUnk, phr) -{ - m_clsid = __uuidof(this); - m_pInput.Free(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include "../../../DSUtil/DSUtil.h" +#include "../../../DSUtil/ISOLang.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" +#include "DSMSplitter.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia}, + {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, 0, nullptr} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CDSMSplitterFilter), DSMSplitterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CDSMSourceFilter), DSMSourceName, MERIT_NORMAL, 0, nullptr, CLSID_LegacyAmFilterCategory}, +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, + {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + CString str; + str.Format(_T("0,%d,,%%0%dI64x"), DSMSW_SIZE, DSMSW_SIZE * 2); + str.Format(CString(str), DSMSW); + + RegisterSourceFilter( + CLSID_AsyncReader, + MEDIASUBTYPE_DirectShowMedia, + str, nullptr); + + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + UnRegisterSourceFilter(MEDIASUBTYPE_DirectShowMedia); + + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CDSMSplitterFilter +// + +CDSMSplitterFilter::CDSMSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseSplitterFilter(NAME("CDSMSplitterFilter"), pUnk, phr, __uuidof(this)) +{ +} + +CDSMSplitterFilter::~CDSMSplitterFilter() +{ +} + +STDMETHODIMP CDSMSplitterFilter::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + + if (m_pName && m_pName[0] == L'M' && m_pName[1] == L'P' && m_pName[2] == L'C') { + (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); + } else { + wcscpy_s(pInfo->achName, DSMSourceName); + } + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +HRESULT CDSMSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader) +{ + CheckPointer(pAsyncReader, E_POINTER); + + HRESULT hr = E_FAIL; + + m_pFile.Free(); + m_pFile.Attach(DEBUG_NEW CDSMSplitterFile(pAsyncReader, hr, *this, *this)); + if (!m_pFile) { + return E_OUTOFMEMORY; + } + if (FAILED(hr)) { + m_pFile.Free(); + return hr; + } + + m_rtNewStart = m_rtCurrent = 0; + m_rtNewStop = m_rtStop = m_rtDuration = m_pFile->m_rtDuration; + + CAtlArray ids; + + POSITION pos = m_pFile->m_mts.GetStartPosition(); + while (pos) { + BYTE id; + CMediaType mt; + m_pFile->m_mts.GetNextAssoc(pos, id, mt); + ids.Add(id); + } + + std::sort(ids.GetData(), ids.GetData() + ids.GetCount()); + + for (size_t i = 0; i < ids.GetCount(); i++) { + BYTE id = ids[i]; + CMediaType& mt = m_pFile->m_mts[id]; + + CStringW name, lang; + name.Format(L"Output %02u", id); + + CAtlArray mts; + mts.Add(mt); + + CAutoPtr pPinOut(DEBUG_NEW CBaseSplitterOutputPin(mts, name, this, this, &hr)); + + name.Empty(); + + pos = m_pFile->m_sim[id].GetStartPosition(); + while (pos) { + CStringA key; + CStringW value; + m_pFile->m_sim[id].GetNextAssoc(pos, key, value); + pPinOut->SetProperty(CStringW(key), value); + + if (key == "NAME") { + name = value; + } + if (key == "LANG") { + lang = ISOLang::ISO6392ToLanguage(CStringA(value)); + if (lang.IsEmpty()) { + lang = value; + } + } + } + + if (!name.IsEmpty() || !lang.IsEmpty()) { + if (!name.IsEmpty()) { + if (!lang.IsEmpty()) { + name += L" (" + lang + L")"; + } + } else if (!lang.IsEmpty()) { + name = lang; + } + pPinOut->SetName(name); + } + + EXECUTE_ASSERT(SUCCEEDED(AddOutputPin(id, pPinOut))); + } + + pos = m_pFile->m_fim.GetStartPosition(); + while (pos) { + CStringA key; + CStringW value; + m_pFile->m_fim.GetNextAssoc(pos, key, value); + SetProperty(CStringW(key), value); + } + + for (size_t i = 0; i < m_resources.GetCount(); i++) { + const CDSMResource& r = m_resources[i]; + if (r.mime == L"application/x-truetype-font" || + r.mime == L"application/x-font-ttf" || + r.mime == L"application/vnd.ms-opentype") { + //m_fontinst.InstallFont(r.data); + m_fontinst.InstallFontMemory(r.data.GetData(), (UINT)r.data.GetCount()); + } + } + + return !m_pOutputs.IsEmpty() ? S_OK : E_FAIL; +} + +bool CDSMSplitterFilter::DemuxInit() +{ + SetThreadName(DWORD(-1), "CDSMSplitterFilter"); + return true; +} + +void CDSMSplitterFilter::DemuxSeek(REFERENCE_TIME rt) +{ + m_pFile->Seek(m_pFile->FindSyncPoint(rt)); +} + +bool CDSMSplitterFilter::DemuxLoop() +{ + HRESULT hr = S_OK; + + while (SUCCEEDED(hr) && !CheckRequest(nullptr) && m_pFile->GetRemaining()) { + dsmp_t type; + UINT64 len; + + if (!m_pFile->Sync(type, len)) { + continue; + } + + __int64 pos = m_pFile->GetPos(); + + if (type == DSMP_SAMPLE) { + CAutoPtr p(DEBUG_NEW Packet()); + if (m_pFile->Read(len, p)) { + if (p->rtStart != Packet::INVALID_TIME) { + p->rtStart -= m_pFile->m_rtFirst; + p->rtStop -= m_pFile->m_rtFirst; + } + + hr = DeliverPacket(p); + } + } + + m_pFile->Seek(pos + len); + } + + return true; +} + +// IKeyFrameInfo + +STDMETHODIMP CDSMSplitterFilter::GetKeyFrameCount(UINT& nKFs) +{ + CheckPointer(m_pFile, E_UNEXPECTED); + nKFs = (UINT)m_pFile->m_sps.GetCount(); + return S_OK; +} + +STDMETHODIMP CDSMSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs) +{ + CheckPointer(pFormat, E_POINTER); + CheckPointer(pKFs, E_POINTER); + CheckPointer(m_pFile, E_UNEXPECTED); + + if (*pFormat != TIME_FORMAT_MEDIA_TIME) { + return E_INVALIDARG; + } + + // these aren't really the keyframes, but quicky accessable points in the stream + for (nKFs = 0; nKFs < m_pFile->m_sps.GetCount(); nKFs++) { + pKFs[nKFs] = m_pFile->m_sps[nKFs].rt; + } + + return S_OK; +} + +// +// CDSMSourceFilter +// + +CDSMSourceFilter::CDSMSourceFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CDSMSplitterFilter(pUnk, phr) +{ + m_clsid = __uuidof(this); + m_pInput.Free(); +} diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.def b/src/filters/parser/DSMSplitter/DSMSplitter.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.def +++ b/src/filters/parser/DSMSplitter/DSMSplitter.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.h b/src/filters/parser/DSMSplitter/DSMSplitter.h index 0bdc7fab2e4..e12b1f823fc 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.h +++ b/src/filters/parser/DSMSplitter/DSMSplitter.h @@ -1,61 +1,61 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include -#include "DSMSplitterFile.h" -#include "../BaseSplitter/BaseSplitter.h" - -#define DSMSplitterName L"MPC-HC DSM Splitter" -#define DSMSourceName L"MPC-HC DSM Source" - -class __declspec(uuid("0912B4DD-A30A-4568-B590-7179EBB420EC")) - CDSMSplitterFilter : public CBaseSplitterFilter -{ -protected: - CAutoPtr m_pFile; - HRESULT CreateOutputs(IAsyncReader* pAsyncReader); - - bool DemuxInit(); - void DemuxSeek(REFERENCE_TIME rt); - bool DemuxLoop(); - -public: - CDSMSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr); - virtual ~CDSMSplitterFilter(); - - // CBaseFilter - STDMETHODIMP_(HRESULT) QueryFilterInfo(FILTER_INFO* pInfo); - - // IKeyFrameInfo - - STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs); - STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs); -}; - -class __declspec(uuid("803E8280-F3CE-4201-982C-8CD8FB512004")) - CDSMSourceFilter : public CDSMSplitterFilter -{ -public: - CDSMSourceFilter(LPUNKNOWN pUnk, HRESULT* phr); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include +#include "DSMSplitterFile.h" +#include "../BaseSplitter/BaseSplitter.h" + +#define DSMSplitterName L"MPC-HC DSM Splitter" +#define DSMSourceName L"MPC-HC DSM Source" + +class __declspec(uuid("0912B4DD-A30A-4568-B590-7179EBB420EC")) + CDSMSplitterFilter : public CBaseSplitterFilter +{ +protected: + CAutoPtr m_pFile; + HRESULT CreateOutputs(IAsyncReader* pAsyncReader); + + bool DemuxInit(); + void DemuxSeek(REFERENCE_TIME rt); + bool DemuxLoop(); + +public: + CDSMSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr); + virtual ~CDSMSplitterFilter(); + + // CBaseFilter + STDMETHODIMP_(HRESULT) QueryFilterInfo(FILTER_INFO* pInfo); + + // IKeyFrameInfo + + STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs); + STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs); +}; + +class __declspec(uuid("803E8280-F3CE-4201-982C-8CD8FB512004")) + CDSMSourceFilter : public CDSMSplitterFilter +{ +public: + CDSMSourceFilter(LPUNKNOWN pUnk, HRESULT* phr); +}; diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.rc b/src/filters/parser/DSMSplitter/DSMSplitter.rc index 8f450206304..fd5892bd66f 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.rc +++ b/src/filters/parser/DSMSplitter/DSMSplitter.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "DSM Splitter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "DSM Splitter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "DSMSplitter.ax" - VALUE "ProductName", "DSM Splitter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "DSM Splitter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "DSM Splitter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "DSMSplitter.ax" + VALUE "ProductName", "DSM Splitter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj b/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj index baefd385d19..db6ce9500f0 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj +++ b/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj @@ -1,129 +1,129 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {1E91F58C-0BAE-4021-8087-D1864D8EC066} - DSMSplitter - MFCProj - DSMSplitter - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - DSMSplitter.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - - Create - - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {37768b3f-89bc-4c16-b2a8-767c5da84c3f} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {1E91F58C-0BAE-4021-8087-D1864D8EC066} + DSMSplitter + MFCProj + DSMSplitter + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + DSMSplitter.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + + Create + + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {37768b3f-89bc-4c16-b2a8-767c5da84c3f} + + + + + \ No newline at end of file diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj.filters b/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj.filters index 83f06422a24..d6d733cba22 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj.filters +++ b/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj.filters @@ -1,52 +1,52 @@ - - - - - {a337cc5d-54f7-4fa2-9559-6c88116d892c} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {a0724c80-5211-43cc-a621-b2d8fe3f71eb} - h;hpp;hxx;hm;inl;inc - - - {5e9cd397-d7f8-4cb7-8db8-10f28ea7ef1c} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {a337cc5d-54f7-4fa2-9559-6c88116d892c} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {a0724c80-5211-43cc-a621-b2d8fe3f71eb} + h;hpp;hxx;hm;inl;inc + + + {5e9cd397-d7f8-4cb7-8db8-10f28ea7ef1c} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/parser/DSMSplitter/DSMSplitterFile.cpp b/src/filters/parser/DSMSplitter/DSMSplitterFile.cpp index 6d03e913a6d..e25c9c0a047 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitterFile.cpp +++ b/src/filters/parser/DSMSplitter/DSMSplitterFile.cpp @@ -1,425 +1,425 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "DSMSplitterFile.h" -#include "../../../DSUtil/DSUtil.h" -#include "moreuuids.h" - -CDSMSplitterFile::CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap) - : CBaseSplitterFile(pReader, hr, DEFAULT_CACHE_LENGTH, false) - , m_rtFirst(0) - , m_rtDuration(0) -{ - if (FAILED(hr)) { - return; - } - - hr = Init(res, chap); -} - -HRESULT CDSMSplitterFile::Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap) -{ - Seek(0); - - if (BitRead(DSMSW_SIZE << 3) != DSMSW || BitRead(5) != DSMP_FILEINFO) { - return E_FAIL; - } - - Seek(0); - - m_mts.RemoveAll(); - m_rtFirst = m_rtDuration = 0; - m_fim.RemoveAll(); - m_sim.RemoveAll(); - res.ResRemoveAll(); - chap.ChapRemoveAll(); - - dsmp_t type; - UINT64 len; - - // examine the beginning of the file ... - - while (Sync(type, len, 0)) { - __int64 pos = GetPos(); - - if (type == DSMP_MEDIATYPE) { - BYTE id; - CMediaType mt; - if (Read(len, id, mt)) { - m_mts[id] = mt; - } - } else if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { - m_rtFirst = p.rtStart; - break; - } - } else if (type == DSMP_FILEINFO) { - if ((BYTE)BitRead(8) > DSMF_VERSION) { - return E_FAIL; - } - Read(len - 1, m_fim); - } else if (type == DSMP_STREAMINFO) { - Read(len - 1, m_sim[(BYTE)BitRead(8)]); - } else if (type == DSMP_SYNCPOINTS) { - Read(len, m_sps); - } else if (type == DSMP_RESOURCE) { - Read(len, res); - } else if (type == DSMP_CHAPTERS) { - Read(len, chap); - } - - Seek(pos + len); - } - - if (type != DSMP_SAMPLE) { - return E_FAIL; - } - - // ... and the end - - if (IsRandomAccess()) { - int limit = MAX_PROBE_SIZE; - - for (int i = 1, j = (int)((GetLength() + limit / 2) / limit); i <= j; i++) { - __int64 seekpos = std::max(0ll, GetLength() - i * limit); - Seek(seekpos); - - while (Sync(type, len, limit) && GetPos() < seekpos + limit) { - __int64 pos = GetPos(); - - if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { - m_rtDuration = std::max(m_rtDuration, p.rtStop - m_rtFirst); // max isn't really needed, only for safety - i = j; - } - } else if (type == DSMP_SYNCPOINTS) { - Read(len, m_sps); - } else if (type == DSMP_RESOURCE) { - Read(len, res); - } else if (type == DSMP_CHAPTERS) { - Read(len, chap); - } - - Seek(pos + len); - } - } - } - - if (m_rtFirst < 0) { - m_rtDuration += m_rtFirst; - m_rtFirst = 0; - } - - return !m_mts.IsEmpty() ? S_OK : E_FAIL; -} - -bool CDSMSplitterFile::Sync(dsmp_t& type, UINT64& len, __int64 limit) -{ - UINT64 pos; - return Sync(pos, type, len, limit); -} - -bool CDSMSplitterFile::Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit) -{ - BitByteAlign(); - - limit += DSMSW_SIZE; - - for (UINT64 id = 0; (id & ((1ui64 << (DSMSW_SIZE << 3)) - 1)) != DSMSW; id = (id << 8) | (BYTE)BitRead(8)) { - if (limit-- <= 0 || GetRemaining() <= 2) { - return false; - } - } - - syncpos = GetPos() - (DSMSW_SIZE << 3); - type = (dsmp_t)BitRead(5); - len = BitRead(((int)BitRead(3) + 1) << 3); - - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, BYTE& id, CMediaType& mt) -{ - id = (BYTE)BitRead(8); - ByteRead((BYTE*)&mt.majortype, sizeof(mt.majortype)); - ByteRead((BYTE*)&mt.subtype, sizeof(mt.subtype)); - mt.bFixedSizeSamples = (BOOL)BitRead(1); - mt.bTemporalCompression = (BOOL)BitRead(1); - mt.lSampleSize = (ULONG)BitRead(30); - ByteRead((BYTE*)&mt.formattype, sizeof(mt.formattype)); - len -= 5 + sizeof(GUID) * 3; - ASSERT(len >= 0); - if (len > 0) { - mt.AllocFormatBuffer((LONG)len); - ByteRead(mt.Format(), mt.FormatLength()); - } else { - mt.ResetFormatBuffer(); - } - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, Packet* p, bool fData) -{ - if (!p) { - return false; - } - - p->TrackNumber = (DWORD)BitRead(8); - p->bSyncPoint = (BOOL)BitRead(1); - bool fSign = !!BitRead(1); - int iTimeStamp = (int)BitRead(3); - int iDuration = (int)BitRead(3); - - if (fSign && !iTimeStamp) { - ASSERT(!iDuration); - p->rtStart = Packet::INVALID_TIME; - p->rtStop = Packet::INVALID_TIME + 1; - } else { - p->rtStart = (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); - p->rtStop = p->rtStart + BitRead(iDuration << 3); - } - - if (fData) { - p->SetCount((INT_PTR)len - (2 + iTimeStamp + iDuration)); - ByteRead(p->GetData(), p->GetCount()); - } - - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, CAtlArray& sps) -{ - SyncPoint sp = {0, 0}; - sps.RemoveAll(); - - while (len > 0) { - bool fSign = !!BitRead(1); - int iTimeStamp = (int)BitRead(3); - int iFilePos = (int)BitRead(3); - BitRead(1); // reserved - - sp.rt += (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); - sp.fp += BitRead(iFilePos << 3); - sps.Add(sp); - - len -= 1 + iTimeStamp + iFilePos; - } - - if (len != 0) { - sps.RemoveAll(); - return false; - } - - // TODO: sort sps - - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, CStreamInfoMap& im) -{ - while (len >= 5) { - CStringA key; - ByteRead((BYTE*)key.GetBufferSetLength(4), 4); - len -= 4; - len -= Read(len, im[key]); - } - - return len == 0; -} - -bool CDSMSplitterFile::Read(__int64 len, IDSMResourceBagImpl& res) -{ - BYTE compression = (BYTE)BitRead(2); - BYTE reserved = (BYTE)BitRead(6); - UNREFERENCED_PARAMETER(reserved); - len--; - - CDSMResource r; - len -= Read(len, r.name); - len -= Read(len, r.desc); - len -= Read(len, r.mime); - - if (compression != 0) { - return false; // TODO - } - - r.data.SetCount((size_t)len); - ByteRead(r.data.GetData(), r.data.GetCount()); - - res += r; - - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, IDSMChapterBagImpl& chap) -{ - CDSMChapter c(0, L""); - - while (len > 0) { - bool fSign = !!BitRead(1); - int iTimeStamp = (int)BitRead(3); - BitRead(4); // reserved - len--; - - c.rt += (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); - len -= iTimeStamp; - len -= Read(len, c.name); - - chap += c; - } - - chap.ChapSort(); - - return len == 0; -} - -__int64 CDSMSplitterFile::Read(__int64 len, CStringW& str) -{ - char c; - CStringA s; - __int64 i = 0; - while (i++ < len && (c = (char)BitRead(8)) != 0) { - s += c; - } - str = UTF8To16(s); - return i; -} - -__int64 CDSMSplitterFile::FindSyncPoint(REFERENCE_TIME rt) -{ - if (/*!m_sps.IsEmpty()*/ m_sps.GetCount() > 1) { - size_t i = range_bsearch(m_sps, m_rtFirst + rt); - return (i != MAXSIZE_T) ? m_sps[i].fp : 0; - } - - if (m_rtDuration <= 0 || rt <= m_rtFirst) { - return 0; - } - - // ok, do the hard way then - - dsmp_t type; - UINT64 syncpos, len; - - // 1. find some boundaries close to rt's position (minpos, maxpos) - - __int64 minpos = 0, maxpos = GetLength(); - - for (int i = 0; i < 10 && (maxpos - minpos) >= 1024 * 1024; i++) { - Seek((minpos + maxpos) / 2); - - while (GetPos() < maxpos) { - if (!Sync(syncpos, type, len)) { - continue; - } - - __int64 pos = GetPos(); - - if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { - REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt; - if (dt >= 0) { - maxpos = std::max((__int64)syncpos - MAX_PROBE_SIZE, minpos); - } else { - minpos = syncpos; - } - break; - } - } - - Seek(pos + len); - } - } - - // 2. find the first packet just after rt (maxpos) - - Seek(minpos); - - while (GetRemaining()) { - if (!Sync(syncpos, type, len)) { - continue; - } - - __int64 pos = GetPos(); - - if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { - REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt; - if (dt >= 0) { - maxpos = (__int64)syncpos; - break; - } - } - } - - Seek(pos + len); - } - - // 3. iterate backwards from maxpos and find at least one syncpoint for every stream, except for subtitle streams - - CAtlMap ids; - - { - POSITION pos = m_mts.GetStartPosition(); - while (pos) { - BYTE id; - CMediaType mt; - m_mts.GetNextAssoc(pos, id, mt); - if (mt.majortype != MEDIATYPE_Text && mt.majortype != MEDIATYPE_Subtitle) { - ids[id] = 0; - } - } - } - - __int64 ret = maxpos; - - while (maxpos > 0 && !ids.IsEmpty()) { - minpos = std::max(0ll, maxpos - MAX_PROBE_SIZE); - - Seek(minpos); - - while (Sync(syncpos, type, len) && GetPos() < maxpos) { - UINT64 pos = GetPos(); - - if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME && p.bSyncPoint) { - BYTE id = (BYTE)p.TrackNumber, tmp; - if (ids.Lookup(id, tmp)) { - ids.RemoveKey((BYTE)p.TrackNumber); - ret = std::min(ret, (__int64)syncpos); - } - } - } - - Seek(pos + len); - } - - maxpos = minpos; - } - - return ret; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "DSMSplitterFile.h" +#include "../../../DSUtil/DSUtil.h" +#include "moreuuids.h" + +CDSMSplitterFile::CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap) + : CBaseSplitterFile(pReader, hr, DEFAULT_CACHE_LENGTH, false) + , m_rtFirst(0) + , m_rtDuration(0) +{ + if (FAILED(hr)) { + return; + } + + hr = Init(res, chap); +} + +HRESULT CDSMSplitterFile::Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap) +{ + Seek(0); + + if (BitRead(DSMSW_SIZE << 3) != DSMSW || BitRead(5) != DSMP_FILEINFO) { + return E_FAIL; + } + + Seek(0); + + m_mts.RemoveAll(); + m_rtFirst = m_rtDuration = 0; + m_fim.RemoveAll(); + m_sim.RemoveAll(); + res.ResRemoveAll(); + chap.ChapRemoveAll(); + + dsmp_t type; + UINT64 len; + + // examine the beginning of the file ... + + while (Sync(type, len, 0)) { + __int64 pos = GetPos(); + + if (type == DSMP_MEDIATYPE) { + BYTE id; + CMediaType mt; + if (Read(len, id, mt)) { + m_mts[id] = mt; + } + } else if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { + m_rtFirst = p.rtStart; + break; + } + } else if (type == DSMP_FILEINFO) { + if ((BYTE)BitRead(8) > DSMF_VERSION) { + return E_FAIL; + } + Read(len - 1, m_fim); + } else if (type == DSMP_STREAMINFO) { + Read(len - 1, m_sim[(BYTE)BitRead(8)]); + } else if (type == DSMP_SYNCPOINTS) { + Read(len, m_sps); + } else if (type == DSMP_RESOURCE) { + Read(len, res); + } else if (type == DSMP_CHAPTERS) { + Read(len, chap); + } + + Seek(pos + len); + } + + if (type != DSMP_SAMPLE) { + return E_FAIL; + } + + // ... and the end + + if (IsRandomAccess()) { + int limit = MAX_PROBE_SIZE; + + for (int i = 1, j = (int)((GetLength() + limit / 2) / limit); i <= j; i++) { + __int64 seekpos = std::max(0ll, GetLength() - i * limit); + Seek(seekpos); + + while (Sync(type, len, limit) && GetPos() < seekpos + limit) { + __int64 pos = GetPos(); + + if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { + m_rtDuration = std::max(m_rtDuration, p.rtStop - m_rtFirst); // max isn't really needed, only for safety + i = j; + } + } else if (type == DSMP_SYNCPOINTS) { + Read(len, m_sps); + } else if (type == DSMP_RESOURCE) { + Read(len, res); + } else if (type == DSMP_CHAPTERS) { + Read(len, chap); + } + + Seek(pos + len); + } + } + } + + if (m_rtFirst < 0) { + m_rtDuration += m_rtFirst; + m_rtFirst = 0; + } + + return !m_mts.IsEmpty() ? S_OK : E_FAIL; +} + +bool CDSMSplitterFile::Sync(dsmp_t& type, UINT64& len, __int64 limit) +{ + UINT64 pos; + return Sync(pos, type, len, limit); +} + +bool CDSMSplitterFile::Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit) +{ + BitByteAlign(); + + limit += DSMSW_SIZE; + + for (UINT64 id = 0; (id & ((1ui64 << (DSMSW_SIZE << 3)) - 1)) != DSMSW; id = (id << 8) | (BYTE)BitRead(8)) { + if (limit-- <= 0 || GetRemaining() <= 2) { + return false; + } + } + + syncpos = GetPos() - (DSMSW_SIZE << 3); + type = (dsmp_t)BitRead(5); + len = BitRead(((int)BitRead(3) + 1) << 3); + + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, BYTE& id, CMediaType& mt) +{ + id = (BYTE)BitRead(8); + ByteRead((BYTE*)&mt.majortype, sizeof(mt.majortype)); + ByteRead((BYTE*)&mt.subtype, sizeof(mt.subtype)); + mt.bFixedSizeSamples = (BOOL)BitRead(1); + mt.bTemporalCompression = (BOOL)BitRead(1); + mt.lSampleSize = (ULONG)BitRead(30); + ByteRead((BYTE*)&mt.formattype, sizeof(mt.formattype)); + len -= 5 + sizeof(GUID) * 3; + ASSERT(len >= 0); + if (len > 0) { + mt.AllocFormatBuffer((LONG)len); + ByteRead(mt.Format(), mt.FormatLength()); + } else { + mt.ResetFormatBuffer(); + } + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, Packet* p, bool fData) +{ + if (!p) { + return false; + } + + p->TrackNumber = (DWORD)BitRead(8); + p->bSyncPoint = (BOOL)BitRead(1); + bool fSign = !!BitRead(1); + int iTimeStamp = (int)BitRead(3); + int iDuration = (int)BitRead(3); + + if (fSign && !iTimeStamp) { + ASSERT(!iDuration); + p->rtStart = Packet::INVALID_TIME; + p->rtStop = Packet::INVALID_TIME + 1; + } else { + p->rtStart = (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); + p->rtStop = p->rtStart + BitRead(iDuration << 3); + } + + if (fData) { + p->SetCount((INT_PTR)len - (2 + iTimeStamp + iDuration)); + ByteRead(p->GetData(), p->GetCount()); + } + + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, CAtlArray& sps) +{ + SyncPoint sp = {0, 0}; + sps.RemoveAll(); + + while (len > 0) { + bool fSign = !!BitRead(1); + int iTimeStamp = (int)BitRead(3); + int iFilePos = (int)BitRead(3); + BitRead(1); // reserved + + sp.rt += (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); + sp.fp += BitRead(iFilePos << 3); + sps.Add(sp); + + len -= 1 + iTimeStamp + iFilePos; + } + + if (len != 0) { + sps.RemoveAll(); + return false; + } + + // TODO: sort sps + + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, CStreamInfoMap& im) +{ + while (len >= 5) { + CStringA key; + ByteRead((BYTE*)key.GetBufferSetLength(4), 4); + len -= 4; + len -= Read(len, im[key]); + } + + return len == 0; +} + +bool CDSMSplitterFile::Read(__int64 len, IDSMResourceBagImpl& res) +{ + BYTE compression = (BYTE)BitRead(2); + BYTE reserved = (BYTE)BitRead(6); + UNREFERENCED_PARAMETER(reserved); + len--; + + CDSMResource r; + len -= Read(len, r.name); + len -= Read(len, r.desc); + len -= Read(len, r.mime); + + if (compression != 0) { + return false; // TODO + } + + r.data.SetCount((size_t)len); + ByteRead(r.data.GetData(), r.data.GetCount()); + + res += r; + + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, IDSMChapterBagImpl& chap) +{ + CDSMChapter c(0, L""); + + while (len > 0) { + bool fSign = !!BitRead(1); + int iTimeStamp = (int)BitRead(3); + BitRead(4); // reserved + len--; + + c.rt += (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); + len -= iTimeStamp; + len -= Read(len, c.name); + + chap += c; + } + + chap.ChapSort(); + + return len == 0; +} + +__int64 CDSMSplitterFile::Read(__int64 len, CStringW& str) +{ + char c; + CStringA s; + __int64 i = 0; + while (i++ < len && (c = (char)BitRead(8)) != 0) { + s += c; + } + str = UTF8To16(s); + return i; +} + +__int64 CDSMSplitterFile::FindSyncPoint(REFERENCE_TIME rt) +{ + if (/*!m_sps.IsEmpty()*/ m_sps.GetCount() > 1) { + size_t i = range_bsearch(m_sps, m_rtFirst + rt); + return (i != MAXSIZE_T) ? m_sps[i].fp : 0; + } + + if (m_rtDuration <= 0 || rt <= m_rtFirst) { + return 0; + } + + // ok, do the hard way then + + dsmp_t type; + UINT64 syncpos, len; + + // 1. find some boundaries close to rt's position (minpos, maxpos) + + __int64 minpos = 0, maxpos = GetLength(); + + for (int i = 0; i < 10 && (maxpos - minpos) >= 1024 * 1024; i++) { + Seek((minpos + maxpos) / 2); + + while (GetPos() < maxpos) { + if (!Sync(syncpos, type, len)) { + continue; + } + + __int64 pos = GetPos(); + + if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { + REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt; + if (dt >= 0) { + maxpos = std::max((__int64)syncpos - MAX_PROBE_SIZE, minpos); + } else { + minpos = syncpos; + } + break; + } + } + + Seek(pos + len); + } + } + + // 2. find the first packet just after rt (maxpos) + + Seek(minpos); + + while (GetRemaining()) { + if (!Sync(syncpos, type, len)) { + continue; + } + + __int64 pos = GetPos(); + + if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { + REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt; + if (dt >= 0) { + maxpos = (__int64)syncpos; + break; + } + } + } + + Seek(pos + len); + } + + // 3. iterate backwards from maxpos and find at least one syncpoint for every stream, except for subtitle streams + + CAtlMap ids; + + { + POSITION pos = m_mts.GetStartPosition(); + while (pos) { + BYTE id; + CMediaType mt; + m_mts.GetNextAssoc(pos, id, mt); + if (mt.majortype != MEDIATYPE_Text && mt.majortype != MEDIATYPE_Subtitle) { + ids[id] = 0; + } + } + } + + __int64 ret = maxpos; + + while (maxpos > 0 && !ids.IsEmpty()) { + minpos = std::max(0ll, maxpos - MAX_PROBE_SIZE); + + Seek(minpos); + + while (Sync(syncpos, type, len) && GetPos() < maxpos) { + UINT64 pos = GetPos(); + + if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME && p.bSyncPoint) { + BYTE id = (BYTE)p.TrackNumber, tmp; + if (ids.Lookup(id, tmp)) { + ids.RemoveKey((BYTE)p.TrackNumber); + ret = std::min(ret, (__int64)syncpos); + } + } + } + + Seek(pos + len); + } + + maxpos = minpos; + } + + return ret; +} diff --git a/src/filters/parser/DSMSplitter/DSMSplitterFile.h b/src/filters/parser/DSMSplitter/DSMSplitterFile.h index e9f041c2585..27a6c119bd8 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitterFile.h +++ b/src/filters/parser/DSMSplitter/DSMSplitterFile.h @@ -1,62 +1,62 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../BaseSplitter/BaseSplitter.h" -#include "../BaseSplitter/BaseSplitterFile.h" -#include "dsm/dsm.h" -#include "../../../DSUtil/DSMPropertyBag.h" - -#define MAX_PROBE_SIZE (64 * 1024) - -class CDSMSplitterFile : public CBaseSplitterFile -{ - HRESULT Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap); - -public: - CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap); - - CAtlMap m_mts; - REFERENCE_TIME m_rtFirst, m_rtDuration; - - struct SyncPoint { - REFERENCE_TIME rt; - __int64 fp; - }; - CAtlArray m_sps; - - typedef CAtlMap, CStringElementTraits> CStreamInfoMap; - CStreamInfoMap m_fim; - CAtlMap m_sim; - - bool Sync(dsmp_t& type, UINT64& len, __int64 limit = MAX_PROBE_SIZE); - bool Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit = MAX_PROBE_SIZE); - bool Read(__int64 len, BYTE& id, CMediaType& mt); - bool Read(__int64 len, Packet* p, bool fData = true); - bool Read(__int64 len, CAtlArray& sps); - bool Read(__int64 len, CStreamInfoMap& im); - bool Read(__int64 len, IDSMResourceBagImpl& res); - bool Read(__int64 len, IDSMChapterBagImpl& chap); - __int64 Read(__int64 len, CStringW& str); - - __int64 FindSyncPoint(REFERENCE_TIME rt); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "../BaseSplitter/BaseSplitter.h" +#include "../BaseSplitter/BaseSplitterFile.h" +#include "dsm/dsm.h" +#include "../../../DSUtil/DSMPropertyBag.h" + +#define MAX_PROBE_SIZE (64 * 1024) + +class CDSMSplitterFile : public CBaseSplitterFile +{ + HRESULT Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap); + +public: + CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap); + + CAtlMap m_mts; + REFERENCE_TIME m_rtFirst, m_rtDuration; + + struct SyncPoint { + REFERENCE_TIME rt; + __int64 fp; + }; + CAtlArray m_sps; + + typedef CAtlMap, CStringElementTraits> CStreamInfoMap; + CStreamInfoMap m_fim; + CAtlMap m_sim; + + bool Sync(dsmp_t& type, UINT64& len, __int64 limit = MAX_PROBE_SIZE); + bool Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit = MAX_PROBE_SIZE); + bool Read(__int64 len, BYTE& id, CMediaType& mt); + bool Read(__int64 len, Packet* p, bool fData = true); + bool Read(__int64 len, CAtlArray& sps); + bool Read(__int64 len, CStreamInfoMap& im); + bool Read(__int64 len, IDSMResourceBagImpl& res); + bool Read(__int64 len, IDSMChapterBagImpl& chap); + __int64 Read(__int64 len, CStringW& str); + + __int64 FindSyncPoint(REFERENCE_TIME rt); +}; diff --git a/src/filters/parser/DSMSplitter/resource.h b/src/filters/parser/DSMSplitter/resource.h index 66d1331cb8d..e7b2ca36c3a 100644 --- a/src/filters/parser/DSMSplitter/resource.h +++ b/src/filters/parser/DSMSplitter/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by DSMSplitter.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DSMSplitter.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/parser/DSMSplitter/stdafx.cpp b/src/filters/parser/DSMSplitter/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/parser/DSMSplitter/stdafx.cpp +++ b/src/filters/parser/DSMSplitter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/parser/DSMSplitter/stdafx.h b/src/filters/parser/DSMSplitter/stdafx.h index 5647391d25c..2095b5f2385 100644 --- a/src/filters/parser/DSMSplitter/stdafx.h +++ b/src/filters/parser/DSMSplitter/stdafx.h @@ -1,36 +1,36 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components -#include - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components +#include + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.cpp b/src/filters/parser/StreamDriveThru/StreamDriveThru.cpp index c654f20cfe8..cef9f0513c6 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.cpp +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.cpp @@ -1,624 +1,624 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "StreamDriveThru.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CStreamDriveThruFilter), StreamDriveThruName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CStreamDriveThruFilter -// - -CStreamDriveThruFilter::CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseFilter(NAME("CStreamDriveThruFilter"), pUnk, &m_csLock, __uuidof(this)) - , m_position(0) -{ - if (phr) { - *phr = S_OK; - } - - m_pInput = DEBUG_NEW CStreamDriveThruInputPin(NAME("CStreamDriveThruInputPin"), this, &m_csLock, phr); - m_pOutput = DEBUG_NEW CStreamDriveThruOutputPin(NAME("CStreamDriveThruOutputPin"), this, &m_csLock, phr); - - CAMThread::Create(); -} - -CStreamDriveThruFilter::~CStreamDriveThruFilter() -{ - CAutoLock csAutoLock(&m_csLock); - - CAMThread::CallWorker(CMD_EXIT); - CAMThread::Close(); - - delete m_pInput; - delete m_pOutput; -} - -STDMETHODIMP CStreamDriveThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IMediaSeeking) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -#define PACKETSIZE 65536 - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CStreamDriveThruFilter::ThreadProc() -{ - for (;;) { - DWORD cmd = GetRequest(); - - switch (cmd) { - default: - case CMD_EXIT: - Reply(S_OK); - return 0; - case CMD_STOP: - Reply(S_OK); - break; - case CMD_PAUSE: - Reply(S_OK); - break; - case CMD_RUN: - Reply(S_OK); - - do { - CComPtr pAsyncReader; - CComPtr pStream; - - if (!m_pInput || !m_pInput->IsConnected() || FAILED(m_pInput->GetAsyncReader(&pAsyncReader)) - || !m_pOutput || !m_pOutput->IsConnected() || FAILED(m_pOutput->GetStream(&pStream))) { - break; - } - - LARGE_INTEGER li = {0}; - ULARGE_INTEGER uli = {0}; - - if (FAILED(pStream->Seek(li, STREAM_SEEK_SET, nullptr)) - || FAILED(pStream->SetSize(uli))) { - break; - } - - if (CComQIPtr pFSF = GetFilterFromPin(m_pOutput->GetConnected())) { - pFSF->SetMode(AM_FILE_OVERWRITE); - - CComHeapPtr pfn; - if (SUCCEEDED(pFSF->GetCurFile(&pfn, nullptr))) { - pFSF->SetFileName(pfn, nullptr); - } - } - - m_position = 0; - BYTE buff[PACKETSIZE]; - - do { - while (!CheckRequest(&cmd)) { - CAutoLock csAutoLock(&m_csLock); - - LONGLONG total = 0, available = 0; - if (FAILED(pAsyncReader->Length(&total, &available)) || m_position >= total) { - cmd = CMD_STOP; - break; - } - - LONG size = std::min(PACKETSIZE, LONG(total - m_position)); - if (FAILED(pAsyncReader->SyncRead(m_position, size, buff))) { - cmd = CMD_STOP; - break; - } - - ULONG written = 0; - if (FAILED(pStream->Write(buff, (ULONG)size, &written)) || (ULONG)size != written) { - cmd = CMD_STOP; - break; - } - - m_position += size; - } - - if (cmd == CMD_PAUSE) { - Reply(S_OK); // reply to CMD_PAUSE - - while (!CheckRequest(&cmd)) { - Sleep(50); - } - - Reply(S_OK); // reply to something - } - } while (cmd == CMD_RUN); - - uli.QuadPart = m_position; - pStream->SetSize(uli); - - if (CComPtr pPin = m_pOutput->GetConnected()) { - pPin->EndOfStream(); - } - } while (false); - - break; - } - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -int CStreamDriveThruFilter::GetPinCount() -{ - return 2; -} - -CBasePin* CStreamDriveThruFilter::GetPin(int n) -{ - CAutoLock csAutoLock(&m_csLock); - - if (n == 0) { - return m_pInput; - } else if (n == 1) { - return m_pOutput; - } - - return nullptr; -} - -STDMETHODIMP CStreamDriveThruFilter::Stop() -{ - HRESULT hr; - - if (FAILED(hr = __super::Stop())) { - return hr; - } - - CallWorker(CMD_STOP); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::Pause() -{ - HRESULT hr; - - if (FAILED(hr = __super::Pause())) { - return hr; - } - - CallWorker(CMD_PAUSE); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::Run(REFERENCE_TIME tStart) -{ - HRESULT hr; - - if (FAILED(hr = __super::Run(tStart))) { - return hr; - } - - CallWorker(CMD_RUN); - - return S_OK; -} - -// IMediaSeeking - -STDMETHODIMP CStreamDriveThruFilter::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanGetCurrentPos | AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration; - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - if (*pCapabilities == 0) { - return S_OK; - } - - DWORD caps; - GetCapabilities(&caps); - - DWORD caps2 = caps & *pCapabilities; - - return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE; -} - -STDMETHODIMP CStreamDriveThruFilter::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CStreamDriveThruFilter::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CStreamDriveThruFilter::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CStreamDriveThruFilter::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CStreamDriveThruFilter::GetDuration(LONGLONG* pDuration) -{ - CheckPointer(pDuration, E_POINTER); - CheckPointer(m_pInput, VFW_E_NOT_CONNECTED); - - if (CComQIPtr pAsyncReader = m_pInput->GetConnected()) { - LONGLONG total, available; - if (SUCCEEDED(pAsyncReader->Length(&total, &available))) { - *pDuration = total; - return S_OK; - } - } - - return E_NOINTERFACE; -} - -STDMETHODIMP CStreamDriveThruFilter::GetStopPosition(LONGLONG* pStop) -{ - return GetDuration(pStop); -} - -STDMETHODIMP CStreamDriveThruFilter::GetCurrentPosition(LONGLONG* pCurrent) -{ - CheckPointer(pCurrent, E_POINTER); - - *pCurrent = m_position; - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::SetRate(double dRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::GetRate(double* pdRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::GetPreroll(LONGLONG* pllPreroll) -{ - CheckPointer(pllPreroll, E_POINTER); - - *pllPreroll = 0; - - return S_OK; -} - -// -// CStreamDriveThruInputPin -// - -CStreamDriveThruInputPin::CStreamDriveThruInputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT) -{ -} - -CStreamDriveThruInputPin::~CStreamDriveThruInputPin() -{ -} - -HRESULT CStreamDriveThruInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader) -{ - CheckPointer(ppAsyncReader, E_POINTER); - - *ppAsyncReader = nullptr; - - CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED); - - (*ppAsyncReader = m_pAsyncReader)->AddRef(); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CStreamDriveThruInputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Stream || pmt->majortype == MEDIATYPE_NULL - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CStreamDriveThruInputPin::CheckConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CheckConnect(pPin))) { - return hr; - } - - if (!CComQIPtr(pPin)) { - return E_NOINTERFACE; - } - - return S_OK; -} - -HRESULT CStreamDriveThruInputPin::BreakConnect() -{ - HRESULT hr; - - if (FAILED(hr = __super::BreakConnect())) { - return hr; - } - - m_pAsyncReader.Release(); - - return S_OK; -} - -HRESULT CStreamDriveThruInputPin::CompleteConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CompleteConnect(pPin))) { - return hr; - } - - CheckPointer(pPin, E_POINTER); - m_pAsyncReader = pPin; - CheckPointer(m_pAsyncReader, E_NOINTERFACE); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruInputPin::BeginFlush() -{ - return E_UNEXPECTED; -} - -STDMETHODIMP CStreamDriveThruInputPin::EndFlush() -{ - return E_UNEXPECTED; -} - -// -// CStreamDriveThruOutputPin -// - -CStreamDriveThruOutputPin::CStreamDriveThruOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output") -{ -} - -CStreamDriveThruOutputPin::~CStreamDriveThruOutputPin() -{ -} - -HRESULT CStreamDriveThruOutputPin::GetStream(IStream** ppStream) -{ - CheckPointer(ppStream, E_POINTER); - - *ppStream = nullptr; - - CheckPointer(m_pStream, VFW_E_NOT_CONNECTED); - - (*ppStream = m_pStream)->AddRef(); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CStreamDriveThruOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = 1; - pProperties->cbBuffer = PACKETSIZE; - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CStreamDriveThruOutputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Stream - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CStreamDriveThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CAutoLock cAutoLock(m_pLock); - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - pmt->majortype = MEDIATYPE_Stream; - pmt->subtype = GUID_NULL; - pmt->formattype = GUID_NULL; - pmt->SetSampleSize(PACKETSIZE); - - return S_OK; -} - -HRESULT CStreamDriveThruOutputPin::CheckConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CheckConnect(pPin))) { - return hr; - } - - if (!CComQIPtr(pPin)) { - return E_NOINTERFACE; - } - - return S_OK; -} - -HRESULT CStreamDriveThruOutputPin::BreakConnect() -{ - HRESULT hr; - - if (FAILED(hr = __super::BreakConnect())) { - return hr; - } - - m_pStream.Release(); - - return S_OK; -} - -HRESULT CStreamDriveThruOutputPin::CompleteConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CompleteConnect(pPin))) { - return hr; - } - - CheckPointer(pPin, E_POINTER); - m_pStream = pPin; - CheckPointer(m_pStream, E_NOINTERFACE); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruOutputPin::BeginFlush() -{ - return E_UNEXPECTED; -} - -STDMETHODIMP CStreamDriveThruOutputPin::EndFlush() -{ - return E_UNEXPECTED; -} - -STDMETHODIMP CStreamDriveThruOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "StreamDriveThru.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CStreamDriveThruFilter), StreamDriveThruName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CStreamDriveThruFilter +// + +CStreamDriveThruFilter::CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseFilter(NAME("CStreamDriveThruFilter"), pUnk, &m_csLock, __uuidof(this)) + , m_position(0) +{ + if (phr) { + *phr = S_OK; + } + + m_pInput = DEBUG_NEW CStreamDriveThruInputPin(NAME("CStreamDriveThruInputPin"), this, &m_csLock, phr); + m_pOutput = DEBUG_NEW CStreamDriveThruOutputPin(NAME("CStreamDriveThruOutputPin"), this, &m_csLock, phr); + + CAMThread::Create(); +} + +CStreamDriveThruFilter::~CStreamDriveThruFilter() +{ + CAutoLock csAutoLock(&m_csLock); + + CAMThread::CallWorker(CMD_EXIT); + CAMThread::Close(); + + delete m_pInput; + delete m_pOutput; +} + +STDMETHODIMP CStreamDriveThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IMediaSeeking) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +#define PACKETSIZE 65536 + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CStreamDriveThruFilter::ThreadProc() +{ + for (;;) { + DWORD cmd = GetRequest(); + + switch (cmd) { + default: + case CMD_EXIT: + Reply(S_OK); + return 0; + case CMD_STOP: + Reply(S_OK); + break; + case CMD_PAUSE: + Reply(S_OK); + break; + case CMD_RUN: + Reply(S_OK); + + do { + CComPtr pAsyncReader; + CComPtr pStream; + + if (!m_pInput || !m_pInput->IsConnected() || FAILED(m_pInput->GetAsyncReader(&pAsyncReader)) + || !m_pOutput || !m_pOutput->IsConnected() || FAILED(m_pOutput->GetStream(&pStream))) { + break; + } + + LARGE_INTEGER li = {0}; + ULARGE_INTEGER uli = {0}; + + if (FAILED(pStream->Seek(li, STREAM_SEEK_SET, nullptr)) + || FAILED(pStream->SetSize(uli))) { + break; + } + + if (CComQIPtr pFSF = GetFilterFromPin(m_pOutput->GetConnected())) { + pFSF->SetMode(AM_FILE_OVERWRITE); + + CComHeapPtr pfn; + if (SUCCEEDED(pFSF->GetCurFile(&pfn, nullptr))) { + pFSF->SetFileName(pfn, nullptr); + } + } + + m_position = 0; + BYTE buff[PACKETSIZE]; + + do { + while (!CheckRequest(&cmd)) { + CAutoLock csAutoLock(&m_csLock); + + LONGLONG total = 0, available = 0; + if (FAILED(pAsyncReader->Length(&total, &available)) || m_position >= total) { + cmd = CMD_STOP; + break; + } + + LONG size = std::min(PACKETSIZE, LONG(total - m_position)); + if (FAILED(pAsyncReader->SyncRead(m_position, size, buff))) { + cmd = CMD_STOP; + break; + } + + ULONG written = 0; + if (FAILED(pStream->Write(buff, (ULONG)size, &written)) || (ULONG)size != written) { + cmd = CMD_STOP; + break; + } + + m_position += size; + } + + if (cmd == CMD_PAUSE) { + Reply(S_OK); // reply to CMD_PAUSE + + while (!CheckRequest(&cmd)) { + Sleep(50); + } + + Reply(S_OK); // reply to something + } + } while (cmd == CMD_RUN); + + uli.QuadPart = m_position; + pStream->SetSize(uli); + + if (CComPtr pPin = m_pOutput->GetConnected()) { + pPin->EndOfStream(); + } + } while (false); + + break; + } + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +int CStreamDriveThruFilter::GetPinCount() +{ + return 2; +} + +CBasePin* CStreamDriveThruFilter::GetPin(int n) +{ + CAutoLock csAutoLock(&m_csLock); + + if (n == 0) { + return m_pInput; + } else if (n == 1) { + return m_pOutput; + } + + return nullptr; +} + +STDMETHODIMP CStreamDriveThruFilter::Stop() +{ + HRESULT hr; + + if (FAILED(hr = __super::Stop())) { + return hr; + } + + CallWorker(CMD_STOP); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::Pause() +{ + HRESULT hr; + + if (FAILED(hr = __super::Pause())) { + return hr; + } + + CallWorker(CMD_PAUSE); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::Run(REFERENCE_TIME tStart) +{ + HRESULT hr; + + if (FAILED(hr = __super::Run(tStart))) { + return hr; + } + + CallWorker(CMD_RUN); + + return S_OK; +} + +// IMediaSeeking + +STDMETHODIMP CStreamDriveThruFilter::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanGetCurrentPos | AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration; + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + if (*pCapabilities == 0) { + return S_OK; + } + + DWORD caps; + GetCapabilities(&caps); + + DWORD caps2 = caps & *pCapabilities; + + return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE; +} + +STDMETHODIMP CStreamDriveThruFilter::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CStreamDriveThruFilter::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CStreamDriveThruFilter::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CStreamDriveThruFilter::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CStreamDriveThruFilter::GetDuration(LONGLONG* pDuration) +{ + CheckPointer(pDuration, E_POINTER); + CheckPointer(m_pInput, VFW_E_NOT_CONNECTED); + + if (CComQIPtr pAsyncReader = m_pInput->GetConnected()) { + LONGLONG total, available; + if (SUCCEEDED(pAsyncReader->Length(&total, &available))) { + *pDuration = total; + return S_OK; + } + } + + return E_NOINTERFACE; +} + +STDMETHODIMP CStreamDriveThruFilter::GetStopPosition(LONGLONG* pStop) +{ + return GetDuration(pStop); +} + +STDMETHODIMP CStreamDriveThruFilter::GetCurrentPosition(LONGLONG* pCurrent) +{ + CheckPointer(pCurrent, E_POINTER); + + *pCurrent = m_position; + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::SetRate(double dRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::GetRate(double* pdRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::GetPreroll(LONGLONG* pllPreroll) +{ + CheckPointer(pllPreroll, E_POINTER); + + *pllPreroll = 0; + + return S_OK; +} + +// +// CStreamDriveThruInputPin +// + +CStreamDriveThruInputPin::CStreamDriveThruInputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT) +{ +} + +CStreamDriveThruInputPin::~CStreamDriveThruInputPin() +{ +} + +HRESULT CStreamDriveThruInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader) +{ + CheckPointer(ppAsyncReader, E_POINTER); + + *ppAsyncReader = nullptr; + + CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED); + + (*ppAsyncReader = m_pAsyncReader)->AddRef(); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CStreamDriveThruInputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Stream || pmt->majortype == MEDIATYPE_NULL + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CStreamDriveThruInputPin::CheckConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CheckConnect(pPin))) { + return hr; + } + + if (!CComQIPtr(pPin)) { + return E_NOINTERFACE; + } + + return S_OK; +} + +HRESULT CStreamDriveThruInputPin::BreakConnect() +{ + HRESULT hr; + + if (FAILED(hr = __super::BreakConnect())) { + return hr; + } + + m_pAsyncReader.Release(); + + return S_OK; +} + +HRESULT CStreamDriveThruInputPin::CompleteConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CompleteConnect(pPin))) { + return hr; + } + + CheckPointer(pPin, E_POINTER); + m_pAsyncReader = pPin; + CheckPointer(m_pAsyncReader, E_NOINTERFACE); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruInputPin::BeginFlush() +{ + return E_UNEXPECTED; +} + +STDMETHODIMP CStreamDriveThruInputPin::EndFlush() +{ + return E_UNEXPECTED; +} + +// +// CStreamDriveThruOutputPin +// + +CStreamDriveThruOutputPin::CStreamDriveThruOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output") +{ +} + +CStreamDriveThruOutputPin::~CStreamDriveThruOutputPin() +{ +} + +HRESULT CStreamDriveThruOutputPin::GetStream(IStream** ppStream) +{ + CheckPointer(ppStream, E_POINTER); + + *ppStream = nullptr; + + CheckPointer(m_pStream, VFW_E_NOT_CONNECTED); + + (*ppStream = m_pStream)->AddRef(); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CStreamDriveThruOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = 1; + pProperties->cbBuffer = PACKETSIZE; + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CStreamDriveThruOutputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Stream + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CStreamDriveThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CAutoLock cAutoLock(m_pLock); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + pmt->majortype = MEDIATYPE_Stream; + pmt->subtype = GUID_NULL; + pmt->formattype = GUID_NULL; + pmt->SetSampleSize(PACKETSIZE); + + return S_OK; +} + +HRESULT CStreamDriveThruOutputPin::CheckConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CheckConnect(pPin))) { + return hr; + } + + if (!CComQIPtr(pPin)) { + return E_NOINTERFACE; + } + + return S_OK; +} + +HRESULT CStreamDriveThruOutputPin::BreakConnect() +{ + HRESULT hr; + + if (FAILED(hr = __super::BreakConnect())) { + return hr; + } + + m_pStream.Release(); + + return S_OK; +} + +HRESULT CStreamDriveThruOutputPin::CompleteConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CompleteConnect(pPin))) { + return hr; + } + + CheckPointer(pPin, E_POINTER); + m_pStream = pPin; + CheckPointer(m_pStream, E_NOINTERFACE); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruOutputPin::BeginFlush() +{ + return E_UNEXPECTED; +} + +STDMETHODIMP CStreamDriveThruOutputPin::EndFlush() +{ + return E_UNEXPECTED; +} + +STDMETHODIMP CStreamDriveThruOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.def b/src/filters/parser/StreamDriveThru/StreamDriveThru.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.def +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.h b/src/filters/parser/StreamDriveThru/StreamDriveThru.h index ddf052ef832..a2cb8fd3e6a 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.h +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.h @@ -1,129 +1,129 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include "../../../DSUtil/DSUtil.h" - -#define StreamDriveThruName L"MPC-HC StreamDriveThru" - -class CStreamDriveThruInputPin : public CBasePin -{ - CComQIPtr m_pAsyncReader; - -public: - CStreamDriveThruInputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CStreamDriveThruInputPin(); - - HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT CheckMediaType(const CMediaType* pmt); - - HRESULT CheckConnect(IPin* pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pPin); - - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); -}; - -class CStreamDriveThruOutputPin : public CBaseOutputPin -{ - CComQIPtr m_pStream; - -public: - CStreamDriveThruOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CStreamDriveThruOutputPin(); - - HRESULT GetStream(IStream** ppStream); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - - HRESULT CheckConnect(IPin* pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pPin); - - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; - -class __declspec(uuid("534FE6FD-F1F0-4aec-9F45-FF397320CE33")) - CStreamDriveThruFilter : public CBaseFilter, protected CAMThread, public IMediaSeeking -{ - CCritSec m_csLock; - - CStreamDriveThruInputPin* m_pInput; - CStreamDriveThruOutputPin* m_pOutput; - -protected: - enum { CMD_EXIT, CMD_STOP, CMD_PAUSE, CMD_RUN }; - DWORD ThreadProc(); - - LONGLONG m_position; - -public: - CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr); - virtual ~CStreamDriveThruFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - int GetPinCount(); - CBasePin* GetPin(int n); - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include "../../../DSUtil/DSUtil.h" + +#define StreamDriveThruName L"MPC-HC StreamDriveThru" + +class CStreamDriveThruInputPin : public CBasePin +{ + CComQIPtr m_pAsyncReader; + +public: + CStreamDriveThruInputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CStreamDriveThruInputPin(); + + HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT CheckMediaType(const CMediaType* pmt); + + HRESULT CheckConnect(IPin* pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pPin); + + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); +}; + +class CStreamDriveThruOutputPin : public CBaseOutputPin +{ + CComQIPtr m_pStream; + +public: + CStreamDriveThruOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CStreamDriveThruOutputPin(); + + HRESULT GetStream(IStream** ppStream); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + + HRESULT CheckConnect(IPin* pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pPin); + + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; + +class __declspec(uuid("534FE6FD-F1F0-4aec-9F45-FF397320CE33")) + CStreamDriveThruFilter : public CBaseFilter, protected CAMThread, public IMediaSeeking +{ + CCritSec m_csLock; + + CStreamDriveThruInputPin* m_pInput; + CStreamDriveThruOutputPin* m_pOutput; + +protected: + enum { CMD_EXIT, CMD_STOP, CMD_PAUSE, CMD_RUN }; + DWORD ThreadProc(); + + LONGLONG m_position; + +public: + CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr); + virtual ~CStreamDriveThruFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + int GetPinCount(); + CBasePin* GetPin(int n); + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); +}; diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.rc b/src/filters/parser/StreamDriveThru/StreamDriveThru.rc index 12c9437e836..695f23e0795 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.rc +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "StreamDriverThru Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "StreamDriverThru Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "StreamDriverThru.ax" - VALUE "ProductName", "StreamDriverThru Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "StreamDriverThru Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "StreamDriverThru Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "StreamDriverThru.ax" + VALUE "ProductName", "StreamDriverThru Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj b/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj index 319a169a21d..d3e2e52b3c8 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj @@ -1,124 +1,124 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {AE399B7E-2B2C-4A96-9016-C5C74B0A2FA0} - streamdrivethru - MFCProj - StreamDriveThru - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - StreamDriveThru.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - Create - - - - - - - - - true - - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {AE399B7E-2B2C-4A96-9016-C5C74B0A2FA0} + streamdrivethru + MFCProj + StreamDriveThru + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + StreamDriveThru.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + Create + + + + + + + + + true + + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj.filters b/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj.filters index 173cd5f6f51..2a354a75d9e 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj.filters +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {28a35247-c38a-473b-8877-78de4c5a56e6} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {825cda28-5045-4bb1-bbf5-803ad068b185} - h;hpp;hxx;hm;inl;inc - - - {3e459df1-b036-4307-9bf5-af9011f90631} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {28a35247-c38a-473b-8877-78de4c5a56e6} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {825cda28-5045-4bb1-bbf5-803ad068b185} + h;hpp;hxx;hm;inl;inc + + + {3e459df1-b036-4307-9bf5-af9011f90631} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/parser/StreamDriveThru/resource.h b/src/filters/parser/StreamDriveThru/resource.h index 94c5f77b99c..6f0cb1db6fa 100644 --- a/src/filters/parser/StreamDriveThru/resource.h +++ b/src/filters/parser/StreamDriveThru/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by StreamDriveThru.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by StreamDriveThru.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/parser/StreamDriveThru/stdafx.cpp b/src/filters/parser/StreamDriveThru/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/parser/StreamDriveThru/stdafx.cpp +++ b/src/filters/parser/StreamDriveThru/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/parser/StreamDriveThru/stdafx.h b/src/filters/parser/StreamDriveThru/stdafx.h index 104edd03d59..2dd14e5c1a9 100644 --- a/src/filters/parser/StreamDriveThru/stdafx.h +++ b/src/filters/parser/StreamDriveThru/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include "BaseClasses/streams.h" +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include "BaseClasses/streams.h" diff --git a/src/filters/reader/CDDAReader/CDDAReader.cpp b/src/filters/reader/CDDAReader/CDDAReader.cpp index 9659c123f5e..0549ad6f387 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.cpp +++ b/src/filters/reader/CDDAReader/CDDAReader.cpp @@ -1,560 +1,560 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#ifdef STANDALONE_FILTER -#include -#endif -#include "CDDAReader.h" -#include "../../../DSUtil/DSUtil.h" - -#define RAW_SECTOR_SIZE 2352 -#define MSF2UINT(hgs) ((hgs[1] * 4500) + (hgs[2] * 75) + (hgs[3])) - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE}, -}; - -const AMOVIESETUP_PIN sudOpPin[] = { - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}, -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CCDDAReader), CCDDAReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"), - _T("0"), _T("0,4,,52494646,8,4,,43444441")); // "RIFFxxxxCDDA" - - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"), - _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".cda"), - _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); - - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".cda")); - - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CCDDAReader -// - -CCDDAReader::CCDDAReader(IUnknown* pUnk, HRESULT* phr) - : CAsyncReader(NAME("CCDDAReader"), pUnk, &m_stream, phr, __uuidof(this)) -{ - if (phr) { - *phr = S_OK; - } -} - -CCDDAReader::~CCDDAReader() -{ -} - -STDMETHODIMP CCDDAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFileSourceFilter) - QI2(IAMMediaContent) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CCDDAReader::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - - wcscpy_s(pInfo->achName, CCDDAReaderName); - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -// IFileSourceFilter - -STDMETHODIMP CCDDAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - if (!m_stream.Load(pszFileName)) { - return E_FAIL; - } - - m_fn = pszFileName; - - CMediaType mt; - mt.majortype = MEDIATYPE_Stream; - mt.subtype = m_stream.IsDTS() ? MEDIASUBTYPE_DTS : MEDIASUBTYPE_WAVE; - m_mt = mt; - - return S_OK; -} - -STDMETHODIMP CCDDAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - - return S_OK; -} - -// IAMMediaContent - -STDMETHODIMP CCDDAReader::GetTypeInfoCount(UINT* pctinfo) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_AuthorName(BSTR* pbstrAuthorName) -{ - CheckPointer(pbstrAuthorName, E_POINTER); - CString str = m_stream.m_trackArtist; - if (str.IsEmpty()) { - str = m_stream.m_discArtist; - } - *pbstrAuthorName = str.AllocSysString(); - return S_OK; -} - -STDMETHODIMP CCDDAReader::get_Title(BSTR* pbstrTitle) -{ - CheckPointer(pbstrTitle, E_POINTER); - CString str = m_stream.m_trackTitle; - if (str.IsEmpty()) { - str = m_stream.m_discTitle; - } - *pbstrTitle = str.AllocSysString(); - return S_OK; -} - -STDMETHODIMP CCDDAReader::get_Rating(BSTR* pbstrRating) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_Description(BSTR* pbstrDescription) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_Copyright(BSTR* pbstrCopyright) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_BaseURL(BSTR* pbstrBaseURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_LogoURL(BSTR* pbstrLogoURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_LogoIconURL(BSTR* pbstrLogoURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_WatermarkURL(BSTR* pbstrWatermarkURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_MoreInfoURL(BSTR* pbstrMoreInfoURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_MoreInfoText(BSTR* pbstrMoreInfoText) -{ - return E_NOTIMPL; -} - -// CCDDAStream - -CCDDAStream::CCDDAStream() -{ - m_hDrive = INVALID_HANDLE_VALUE; - - m_llPosition = m_llLength = 0; - - ZeroMemory(&m_TOC, sizeof(m_TOC)); - m_nFirstSector = m_nStartSector = m_nStopSector = 0; - - ZeroMemory(&m_header, sizeof(m_header)); - m_header.riff.hdr.chunkID = RIFFID; - m_header.riff.WAVE = WAVEID; - m_header.frm.hdr.chunkID = FormatID; - m_header.frm.hdr.chunkSize = sizeof(m_header.frm.pcm); - m_header.frm.pcm.wf.wFormatTag = WAVE_FORMAT_PCM; - m_header.frm.pcm.wf.nSamplesPerSec = 44100; - m_header.frm.pcm.wf.nChannels = 2; - m_header.frm.pcm.wBitsPerSample = 16; - m_header.frm.pcm.wf.nBlockAlign = m_header.frm.pcm.wf.nChannels * m_header.frm.pcm.wBitsPerSample / 8; - m_header.frm.pcm.wf.nAvgBytesPerSec = m_header.frm.pcm.wf.nSamplesPerSec * m_header.frm.pcm.wf.nBlockAlign; - m_header.data.hdr.chunkID = DataID; - - m_bDTS = false; -} - -CCDDAStream::~CCDDAStream() -{ - if (m_hDrive != INVALID_HANDLE_VALUE) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - } -} - -bool CCDDAStream::Load(const WCHAR* fnw) -{ - CString path(fnw); - - int iDriveLetter = path.Find(_T(":\\")) - 1; - int iTrackIndex = CString(path).MakeLower().Find(_T(".cda")) - 1; - if (iDriveLetter < 0 || iTrackIndex <= iDriveLetter) { - return false; - } - - CString drive = CString(_T("\\\\.\\")) + path[iDriveLetter] + _T(":"); - while (iTrackIndex > 0 && _istdigit(path[iTrackIndex - 1])) { - iTrackIndex--; - } - if (1 != _stscanf_s(path.Mid(iTrackIndex), _T("%d"), &iTrackIndex)) { - return false; - } - - if (m_hDrive != INVALID_HANDLE_VALUE) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - } - - m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); - if (m_hDrive == INVALID_HANDLE_VALUE) { - return false; - } - - DWORD BytesReturned; - if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &m_TOC, sizeof(m_TOC), &BytesReturned, 0) - || !(m_TOC.FirstTrack <= iTrackIndex && iTrackIndex <= m_TOC.LastTrack)) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - return false; - } - - // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field - m_TOC.TrackData[iTrackIndex - 1].Control &= 5; - if (!(m_TOC.TrackData[iTrackIndex - 1].Control == 0 || m_TOC.TrackData[iTrackIndex - 1].Control == 1)) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - return false; - } - - if (m_TOC.TrackData[iTrackIndex - 1].Control & 8) { - m_header.frm.pcm.wf.nChannels = 4; - } - - m_nStartSector = MSF2UINT(m_TOC.TrackData[iTrackIndex - 1].Address) - 150; - m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150; - - m_llLength = LONGLONG(m_nStopSector - m_nStartSector) * RAW_SECTOR_SIZE; - - m_header.riff.hdr.chunkSize = (long)(m_llLength + sizeof(m_header) - 8); - m_header.data.hdr.chunkSize = (long)(m_llLength); - - // Detect DTS Music Disk - m_bDTS = false; - - // DCA syncwords - const DWORD DCA_MARKER_RAW_BE = 0x7FFE8001; - const DWORD DCA_MARKER_RAW_LE = 0xFE7F0180; - const DWORD DCA_MARKER_14B_BE = 0x1FFFE800; - const DWORD DCA_MARKER_14B_LE = 0xFF1F00E8; - UINT nMarkerFound = 0, nAttempt = 0; - DWORD marker = DWORD_MAX; - - std::vector data(16384); - DWORD dwSizeRead = 0; - while (SUCCEEDED(Read(data.data(), (DWORD)data.size(), TRUE, &dwSizeRead)) && dwSizeRead && nAttempt < (4 + nMarkerFound)) { - nAttempt++; - - for (DWORD i = 0; i < dwSizeRead; i++) { - marker = (marker << 8) | data[i]; - if ((marker == DCA_MARKER_14B_LE && (i < dwSizeRead - 2) && (data[i + 1] & 0xF0) == 0xF0 && data[i + 2] == 0x07) - || (marker == DCA_MARKER_14B_BE && (i < dwSizeRead - 2) && data[i + 1] == 0x07 && (data[i + 2] & 0xF0) == 0xF0) - || marker == DCA_MARKER_RAW_LE || marker == DCA_MARKER_RAW_BE) { - nMarkerFound++; - } - } - dwSizeRead = 0; - - if (nMarkerFound >= 4) { - m_bDTS = true; - break; - } - } - SetPointer(0); - - CDROM_READ_TOC_EX TOCEx; - ZeroMemory(&TOCEx, sizeof(TOCEx)); - TOCEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT; - BYTE header[4] = { 0 }; - static_assert(sizeof(header) >= MINIMUM_CDROM_READ_TOC_EX_SIZE, "sizeof(header) must be greater or equal to MINIMUM_CDROM_READ_TOC_EX_SIZE"); - if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), header, sizeof(header), &BytesReturned, 0)) { - return true; - } - - DWORD size = 2 + (WORD(header[0]) << 8) + header[1]; - if (size <= 4) { // No cd-text information - return true; - } - - CAutoVectorPtr pCDTextData; - if (!pCDTextData.Allocate(size)) { - return true; - } - ZeroMemory(pCDTextData, size); - - if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), pCDTextData, size, &BytesReturned, 0)) { - return true; - } - - size = (WORD)(BytesReturned - sizeof(CDROM_TOC_CD_TEXT_DATA)); - CDROM_TOC_CD_TEXT_DATA_BLOCK* pDesc = ((CDROM_TOC_CD_TEXT_DATA*)(BYTE*)pCDTextData)->Descriptors; - - CStringArray str[16]; - for (int i = 0; i < _countof(str); i++) { - str[i].SetSize(1 + m_TOC.LastTrack); - } - CString last; - - for (int i = 0; size >= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK); i++, size -= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK), pDesc++) { - if (pDesc->TrackNumber > m_TOC.LastTrack) { - continue; - } - - CString text; - CString tmp; - if (pDesc->Unicode) { - const int lenW = _countof(pDesc->WText); - text = CString(CStringW((WCHAR*)pDesc->WText, lenW)); - int tlen = text.GetLength(); - int nLength = lenW - (tlen + 1); - if (nLength > 0 && tlen < 11) { - tmp = CString(CStringW((WCHAR*)pDesc->WText + tlen + 1, nLength)); - } else { - tmp = CString(_T("")); - } - } else { - const int lenU = _countof(pDesc->Text); - text = CString(CStringA((CHAR*)pDesc->Text, lenU)); - int tlen = text.GetLength(); - int nLength = lenU - (tlen + 1); - if (nLength > 0 && tlen < 11) { - tmp = CString(CStringA( (CHAR*)pDesc->Text + tlen + 1, nLength)); - } else { - tmp = CString(""); - } - } - - if (pDesc->PackType < 0x80 || pDesc->PackType >= 0x80 + 0x10) { - continue; - } - pDesc->PackType -= 0x80; - - if (pDesc->CharacterPosition == 0) { - str[pDesc->PackType][pDesc->TrackNumber] = text; - } else { // pDesc->CharacterPosition <= 0xf since CharacterPosition is a 4-bit field - if (pDesc->CharacterPosition < 0xf && !last.IsEmpty()) { - str[pDesc->PackType][pDesc->TrackNumber] = last + text; - } else { - str[pDesc->PackType][pDesc->TrackNumber] += text; - } - } - - last = tmp; - } - - m_discTitle = str[0][0]; - m_trackTitle = str[0][iTrackIndex]; - m_discArtist = str[1][0]; - m_trackArtist = str[1][iTrackIndex]; - - return true; -} - -HRESULT CCDDAStream::SetPointer(LONGLONG llPos) -{ - if (llPos < 0 || llPos > m_llLength) { - return S_FALSE; - } - m_llPosition = llPos; - return S_OK; -} - -HRESULT CCDDAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) -{ - CAutoLock lck(&m_csLock); - - PBYTE pbBufferOrg = pbBuffer; - LONGLONG pos = m_llPosition; - size_t len = dwBytesToRead; - - if (!m_bDTS) { - if (pos < sizeof(m_header) && len > 0) { - size_t l = std::min(len, size_t(sizeof(m_header) - pos)); - memcpy(pbBuffer, &((BYTE*)&m_header)[pos], l); - pbBuffer += l; - pos += l; - len -= l; - } - - pos -= sizeof(m_header); - } - - while (pos >= 0 && pos < m_llLength && len > 0) { - RAW_READ_INFO rawreadinfo; - rawreadinfo.TrackMode = CDDA; - - UINT sector = m_nStartSector + UINT(pos / RAW_SECTOR_SIZE); - UINT offset = pos % RAW_SECTOR_SIZE; - - // Reading 20 sectors at once seems to be a good trade-off between performance and compatibility - rawreadinfo.SectorCount = std::min(20u, m_nStopSector - sector); - - if (m_buff.size() < rawreadinfo.SectorCount * RAW_SECTOR_SIZE) { - m_buff.resize(rawreadinfo.SectorCount * RAW_SECTOR_SIZE); - } - - rawreadinfo.DiskOffset.QuadPart = sector * 2048; - DWORD dwBytesReturned = 0; - VERIFY(DeviceIoControl(m_hDrive, IOCTL_CDROM_RAW_READ, - &rawreadinfo, sizeof(rawreadinfo), - m_buff.data(), (DWORD)m_buff.size(), - &dwBytesReturned, 0)); - - size_t l = std::min(std::min(len, m_buff.size() - offset), size_t(m_llLength - pos)); - memcpy(pbBuffer, &m_buff[offset], l); - - pbBuffer += l; - pos += l; - len -= l; - } - - if (pdwBytesRead) { - *pdwBytesRead = DWORD(pbBuffer - pbBufferOrg); - } - m_llPosition += pbBuffer - pbBufferOrg; - - return S_OK; -} - -LONGLONG CCDDAStream::Size(LONGLONG* pSizeAvailable) -{ - LONGLONG size = m_llLength; - if (!m_bDTS) { - size += sizeof(m_header); - } - if (pSizeAvailable) { - *pSizeAvailable = size; - } - return size; -} - -DWORD CCDDAStream::Alignment() -{ - return 1; -} - -void CCDDAStream::Lock() -{ - m_csLock.Lock(); -} - -void CCDDAStream::Unlock() -{ - m_csLock.Unlock(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#ifdef STANDALONE_FILTER +#include +#endif +#include "CDDAReader.h" +#include "../../../DSUtil/DSUtil.h" + +#define RAW_SECTOR_SIZE 2352 +#define MSF2UINT(hgs) ((hgs[1] * 4500) + (hgs[2] * 75) + (hgs[3])) + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE}, +}; + +const AMOVIESETUP_PIN sudOpPin[] = { + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}, +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CCDDAReader), CCDDAReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"), + _T("0"), _T("0,4,,52494646,8,4,,43444441")); // "RIFFxxxxCDDA" + + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"), + _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".cda"), + _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); + + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".cda")); + + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CCDDAReader +// + +CCDDAReader::CCDDAReader(IUnknown* pUnk, HRESULT* phr) + : CAsyncReader(NAME("CCDDAReader"), pUnk, &m_stream, phr, __uuidof(this)) +{ + if (phr) { + *phr = S_OK; + } +} + +CCDDAReader::~CCDDAReader() +{ +} + +STDMETHODIMP CCDDAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFileSourceFilter) + QI2(IAMMediaContent) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CCDDAReader::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + + wcscpy_s(pInfo->achName, CCDDAReaderName); + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +// IFileSourceFilter + +STDMETHODIMP CCDDAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + if (!m_stream.Load(pszFileName)) { + return E_FAIL; + } + + m_fn = pszFileName; + + CMediaType mt; + mt.majortype = MEDIATYPE_Stream; + mt.subtype = m_stream.IsDTS() ? MEDIASUBTYPE_DTS : MEDIASUBTYPE_WAVE; + m_mt = mt; + + return S_OK; +} + +STDMETHODIMP CCDDAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + + return S_OK; +} + +// IAMMediaContent + +STDMETHODIMP CCDDAReader::GetTypeInfoCount(UINT* pctinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_AuthorName(BSTR* pbstrAuthorName) +{ + CheckPointer(pbstrAuthorName, E_POINTER); + CString str = m_stream.m_trackArtist; + if (str.IsEmpty()) { + str = m_stream.m_discArtist; + } + *pbstrAuthorName = str.AllocSysString(); + return S_OK; +} + +STDMETHODIMP CCDDAReader::get_Title(BSTR* pbstrTitle) +{ + CheckPointer(pbstrTitle, E_POINTER); + CString str = m_stream.m_trackTitle; + if (str.IsEmpty()) { + str = m_stream.m_discTitle; + } + *pbstrTitle = str.AllocSysString(); + return S_OK; +} + +STDMETHODIMP CCDDAReader::get_Rating(BSTR* pbstrRating) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_Description(BSTR* pbstrDescription) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_Copyright(BSTR* pbstrCopyright) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_BaseURL(BSTR* pbstrBaseURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_LogoURL(BSTR* pbstrLogoURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_LogoIconURL(BSTR* pbstrLogoURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_WatermarkURL(BSTR* pbstrWatermarkURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_MoreInfoURL(BSTR* pbstrMoreInfoURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_MoreInfoText(BSTR* pbstrMoreInfoText) +{ + return E_NOTIMPL; +} + +// CCDDAStream + +CCDDAStream::CCDDAStream() +{ + m_hDrive = INVALID_HANDLE_VALUE; + + m_llPosition = m_llLength = 0; + + ZeroMemory(&m_TOC, sizeof(m_TOC)); + m_nFirstSector = m_nStartSector = m_nStopSector = 0; + + ZeroMemory(&m_header, sizeof(m_header)); + m_header.riff.hdr.chunkID = RIFFID; + m_header.riff.WAVE = WAVEID; + m_header.frm.hdr.chunkID = FormatID; + m_header.frm.hdr.chunkSize = sizeof(m_header.frm.pcm); + m_header.frm.pcm.wf.wFormatTag = WAVE_FORMAT_PCM; + m_header.frm.pcm.wf.nSamplesPerSec = 44100; + m_header.frm.pcm.wf.nChannels = 2; + m_header.frm.pcm.wBitsPerSample = 16; + m_header.frm.pcm.wf.nBlockAlign = m_header.frm.pcm.wf.nChannels * m_header.frm.pcm.wBitsPerSample / 8; + m_header.frm.pcm.wf.nAvgBytesPerSec = m_header.frm.pcm.wf.nSamplesPerSec * m_header.frm.pcm.wf.nBlockAlign; + m_header.data.hdr.chunkID = DataID; + + m_bDTS = false; +} + +CCDDAStream::~CCDDAStream() +{ + if (m_hDrive != INVALID_HANDLE_VALUE) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + } +} + +bool CCDDAStream::Load(const WCHAR* fnw) +{ + CString path(fnw); + + int iDriveLetter = path.Find(_T(":\\")) - 1; + int iTrackIndex = CString(path).MakeLower().Find(_T(".cda")) - 1; + if (iDriveLetter < 0 || iTrackIndex <= iDriveLetter) { + return false; + } + + CString drive = CString(_T("\\\\.\\")) + path[iDriveLetter] + _T(":"); + while (iTrackIndex > 0 && _istdigit(path[iTrackIndex - 1])) { + iTrackIndex--; + } + if (1 != _stscanf_s(path.Mid(iTrackIndex), _T("%d"), &iTrackIndex)) { + return false; + } + + if (m_hDrive != INVALID_HANDLE_VALUE) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + } + + m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); + if (m_hDrive == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD BytesReturned; + if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &m_TOC, sizeof(m_TOC), &BytesReturned, 0) + || !(m_TOC.FirstTrack <= iTrackIndex && iTrackIndex <= m_TOC.LastTrack)) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + return false; + } + + // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field + m_TOC.TrackData[iTrackIndex - 1].Control &= 5; + if (!(m_TOC.TrackData[iTrackIndex - 1].Control == 0 || m_TOC.TrackData[iTrackIndex - 1].Control == 1)) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + return false; + } + + if (m_TOC.TrackData[iTrackIndex - 1].Control & 8) { + m_header.frm.pcm.wf.nChannels = 4; + } + + m_nStartSector = MSF2UINT(m_TOC.TrackData[iTrackIndex - 1].Address) - 150; + m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150; + + m_llLength = LONGLONG(m_nStopSector - m_nStartSector) * RAW_SECTOR_SIZE; + + m_header.riff.hdr.chunkSize = (long)(m_llLength + sizeof(m_header) - 8); + m_header.data.hdr.chunkSize = (long)(m_llLength); + + // Detect DTS Music Disk + m_bDTS = false; + + // DCA syncwords + const DWORD DCA_MARKER_RAW_BE = 0x7FFE8001; + const DWORD DCA_MARKER_RAW_LE = 0xFE7F0180; + const DWORD DCA_MARKER_14B_BE = 0x1FFFE800; + const DWORD DCA_MARKER_14B_LE = 0xFF1F00E8; + UINT nMarkerFound = 0, nAttempt = 0; + DWORD marker = DWORD_MAX; + + std::vector data(16384); + DWORD dwSizeRead = 0; + while (SUCCEEDED(Read(data.data(), (DWORD)data.size(), TRUE, &dwSizeRead)) && dwSizeRead && nAttempt < (4 + nMarkerFound)) { + nAttempt++; + + for (DWORD i = 0; i < dwSizeRead; i++) { + marker = (marker << 8) | data[i]; + if ((marker == DCA_MARKER_14B_LE && (i < dwSizeRead - 2) && (data[i + 1] & 0xF0) == 0xF0 && data[i + 2] == 0x07) + || (marker == DCA_MARKER_14B_BE && (i < dwSizeRead - 2) && data[i + 1] == 0x07 && (data[i + 2] & 0xF0) == 0xF0) + || marker == DCA_MARKER_RAW_LE || marker == DCA_MARKER_RAW_BE) { + nMarkerFound++; + } + } + dwSizeRead = 0; + + if (nMarkerFound >= 4) { + m_bDTS = true; + break; + } + } + SetPointer(0); + + CDROM_READ_TOC_EX TOCEx; + ZeroMemory(&TOCEx, sizeof(TOCEx)); + TOCEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT; + BYTE header[4] = { 0 }; + static_assert(sizeof(header) >= MINIMUM_CDROM_READ_TOC_EX_SIZE, "sizeof(header) must be greater or equal to MINIMUM_CDROM_READ_TOC_EX_SIZE"); + if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), header, sizeof(header), &BytesReturned, 0)) { + return true; + } + + DWORD size = 2 + (WORD(header[0]) << 8) + header[1]; + if (size <= 4) { // No cd-text information + return true; + } + + CAutoVectorPtr pCDTextData; + if (!pCDTextData.Allocate(size)) { + return true; + } + ZeroMemory(pCDTextData, size); + + if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), pCDTextData, size, &BytesReturned, 0)) { + return true; + } + + size = (WORD)(BytesReturned - sizeof(CDROM_TOC_CD_TEXT_DATA)); + CDROM_TOC_CD_TEXT_DATA_BLOCK* pDesc = ((CDROM_TOC_CD_TEXT_DATA*)(BYTE*)pCDTextData)->Descriptors; + + CStringArray str[16]; + for (int i = 0; i < _countof(str); i++) { + str[i].SetSize(1 + m_TOC.LastTrack); + } + CString last; + + for (int i = 0; size >= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK); i++, size -= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK), pDesc++) { + if (pDesc->TrackNumber > m_TOC.LastTrack) { + continue; + } + + CString text; + CString tmp; + if (pDesc->Unicode) { + const int lenW = _countof(pDesc->WText); + text = CString(CStringW((WCHAR*)pDesc->WText, lenW)); + int tlen = text.GetLength(); + int nLength = lenW - (tlen + 1); + if (nLength > 0 && tlen < 11) { + tmp = CString(CStringW((WCHAR*)pDesc->WText + tlen + 1, nLength)); + } else { + tmp = CString(_T("")); + } + } else { + const int lenU = _countof(pDesc->Text); + text = CString(CStringA((CHAR*)pDesc->Text, lenU)); + int tlen = text.GetLength(); + int nLength = lenU - (tlen + 1); + if (nLength > 0 && tlen < 11) { + tmp = CString(CStringA( (CHAR*)pDesc->Text + tlen + 1, nLength)); + } else { + tmp = CString(""); + } + } + + if (pDesc->PackType < 0x80 || pDesc->PackType >= 0x80 + 0x10) { + continue; + } + pDesc->PackType -= 0x80; + + if (pDesc->CharacterPosition == 0) { + str[pDesc->PackType][pDesc->TrackNumber] = text; + } else { // pDesc->CharacterPosition <= 0xf since CharacterPosition is a 4-bit field + if (pDesc->CharacterPosition < 0xf && !last.IsEmpty()) { + str[pDesc->PackType][pDesc->TrackNumber] = last + text; + } else { + str[pDesc->PackType][pDesc->TrackNumber] += text; + } + } + + last = tmp; + } + + m_discTitle = str[0][0]; + m_trackTitle = str[0][iTrackIndex]; + m_discArtist = str[1][0]; + m_trackArtist = str[1][iTrackIndex]; + + return true; +} + +HRESULT CCDDAStream::SetPointer(LONGLONG llPos) +{ + if (llPos < 0 || llPos > m_llLength) { + return S_FALSE; + } + m_llPosition = llPos; + return S_OK; +} + +HRESULT CCDDAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) +{ + CAutoLock lck(&m_csLock); + + PBYTE pbBufferOrg = pbBuffer; + LONGLONG pos = m_llPosition; + size_t len = dwBytesToRead; + + if (!m_bDTS) { + if (pos < sizeof(m_header) && len > 0) { + size_t l = std::min(len, size_t(sizeof(m_header) - pos)); + memcpy(pbBuffer, &((BYTE*)&m_header)[pos], l); + pbBuffer += l; + pos += l; + len -= l; + } + + pos -= sizeof(m_header); + } + + while (pos >= 0 && pos < m_llLength && len > 0) { + RAW_READ_INFO rawreadinfo; + rawreadinfo.TrackMode = CDDA; + + UINT sector = m_nStartSector + UINT(pos / RAW_SECTOR_SIZE); + UINT offset = pos % RAW_SECTOR_SIZE; + + // Reading 20 sectors at once seems to be a good trade-off between performance and compatibility + rawreadinfo.SectorCount = std::min(20u, m_nStopSector - sector); + + if (m_buff.size() < rawreadinfo.SectorCount * RAW_SECTOR_SIZE) { + m_buff.resize(rawreadinfo.SectorCount * RAW_SECTOR_SIZE); + } + + rawreadinfo.DiskOffset.QuadPart = sector * 2048; + DWORD dwBytesReturned = 0; + VERIFY(DeviceIoControl(m_hDrive, IOCTL_CDROM_RAW_READ, + &rawreadinfo, sizeof(rawreadinfo), + m_buff.data(), (DWORD)m_buff.size(), + &dwBytesReturned, 0)); + + size_t l = std::min(std::min(len, m_buff.size() - offset), size_t(m_llLength - pos)); + memcpy(pbBuffer, &m_buff[offset], l); + + pbBuffer += l; + pos += l; + len -= l; + } + + if (pdwBytesRead) { + *pdwBytesRead = DWORD(pbBuffer - pbBufferOrg); + } + m_llPosition += pbBuffer - pbBufferOrg; + + return S_OK; +} + +LONGLONG CCDDAStream::Size(LONGLONG* pSizeAvailable) +{ + LONGLONG size = m_llLength; + if (!m_bDTS) { + size += sizeof(m_header); + } + if (pSizeAvailable) { + *pSizeAvailable = size; + } + return size; +} + +DWORD CCDDAStream::Alignment() +{ + return 1; +} + +void CCDDAStream::Lock() +{ + m_csLock.Lock(); +} + +void CCDDAStream::Unlock() +{ + m_csLock.Unlock(); +} diff --git a/src/filters/reader/CDDAReader/CDDAReader.def b/src/filters/reader/CDDAReader/CDDAReader.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.def +++ b/src/filters/reader/CDDAReader/CDDAReader.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/reader/CDDAReader/CDDAReader.h b/src/filters/reader/CDDAReader/CDDAReader.h index fb34c6722ee..6b38e9a4d6d 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.h +++ b/src/filters/reader/CDDAReader/CDDAReader.h @@ -1,143 +1,143 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include -#include -#include "winddk/devioctl.h" -#include "winddk/ntddcdrm.h" -#include -#include "AsyncReader/asyncio.h" -#include "AsyncReader/asyncrdr.h" - -#define CCDDAReaderName L"MPC-HC CDDA Reader" - -struct ChunkHeader { - UINT chunkID; - long chunkSize; -}; - -#define RIFFID 'FFIR' -#define WAVEID 'EVAW' -struct RIFFChunk { - ChunkHeader hdr; - UINT WAVE; -}; - -#define FormatID ' tmf' -struct FormatChunk { - ChunkHeader hdr; - PCMWAVEFORMAT pcm; -}; - -#define DataID 'atad' -struct DataChunk { - ChunkHeader hdr; -}; - -struct WAVEChunck { - RIFFChunk riff; - FormatChunk frm; - DataChunk data; -}; - -class CCDDAStream : public CAsyncStream -{ -private: - CCritSec m_csLock; - - LONGLONG m_llPosition, m_llLength; - - HANDLE m_hDrive; - CDROM_TOC m_TOC; - UINT m_nFirstSector, m_nStartSector, m_nStopSector; - bool m_bDTS; - - WAVEChunck m_header; - - std::vector m_buff; -public: - CCDDAStream(); - virtual ~CCDDAStream(); - - CString m_discTitle, m_trackTitle; - CString m_discArtist, m_trackArtist; - - bool Load(const WCHAR* fnw); - - bool IsDTS() const { return m_bDTS; }; - - // overrides - HRESULT SetPointer(LONGLONG llPos); - HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); - LONGLONG Size(LONGLONG* pSizeAvailable); - DWORD Alignment(); - void Lock(); - void Unlock(); -}; - -class __declspec(uuid("54A35221-2C8D-4a31-A5DF-6D809847E393")) - CCDDAReader - : public CAsyncReader - , public IFileSourceFilter - , public IAMMediaContent -{ - CCDDAStream m_stream; - CStringW m_fn; - -public: - CCDDAReader(IUnknown* pUnk, HRESULT* phr); - ~CCDDAReader(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // CBaseFilter - - STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); - - // IFileSourceFilter - - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); - - // IAMMediaContent - - STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); - STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo); - STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid); - STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr); - - STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName); - STDMETHODIMP get_Title(BSTR* pbstrTitle); - STDMETHODIMP get_Rating(BSTR* pbstrRating); - STDMETHODIMP get_Description(BSTR* pbstrDescription); - STDMETHODIMP get_Copyright(BSTR* pbstrCopyright); - STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL); - STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL); - STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL); - STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL); - STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL); - STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage); - STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL); - STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include +#include +#include "winddk/devioctl.h" +#include "winddk/ntddcdrm.h" +#include +#include "AsyncReader/asyncio.h" +#include "AsyncReader/asyncrdr.h" + +#define CCDDAReaderName L"MPC-HC CDDA Reader" + +struct ChunkHeader { + UINT chunkID; + long chunkSize; +}; + +#define RIFFID 'FFIR' +#define WAVEID 'EVAW' +struct RIFFChunk { + ChunkHeader hdr; + UINT WAVE; +}; + +#define FormatID ' tmf' +struct FormatChunk { + ChunkHeader hdr; + PCMWAVEFORMAT pcm; +}; + +#define DataID 'atad' +struct DataChunk { + ChunkHeader hdr; +}; + +struct WAVEChunck { + RIFFChunk riff; + FormatChunk frm; + DataChunk data; +}; + +class CCDDAStream : public CAsyncStream +{ +private: + CCritSec m_csLock; + + LONGLONG m_llPosition, m_llLength; + + HANDLE m_hDrive; + CDROM_TOC m_TOC; + UINT m_nFirstSector, m_nStartSector, m_nStopSector; + bool m_bDTS; + + WAVEChunck m_header; + + std::vector m_buff; +public: + CCDDAStream(); + virtual ~CCDDAStream(); + + CString m_discTitle, m_trackTitle; + CString m_discArtist, m_trackArtist; + + bool Load(const WCHAR* fnw); + + bool IsDTS() const { return m_bDTS; }; + + // overrides + HRESULT SetPointer(LONGLONG llPos); + HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); + LONGLONG Size(LONGLONG* pSizeAvailable); + DWORD Alignment(); + void Lock(); + void Unlock(); +}; + +class __declspec(uuid("54A35221-2C8D-4a31-A5DF-6D809847E393")) + CCDDAReader + : public CAsyncReader + , public IFileSourceFilter + , public IAMMediaContent +{ + CCDDAStream m_stream; + CStringW m_fn; + +public: + CCDDAReader(IUnknown* pUnk, HRESULT* phr); + ~CCDDAReader(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // CBaseFilter + + STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); + + // IFileSourceFilter + + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); + + // IAMMediaContent + + STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); + STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo); + STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid); + STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr); + + STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName); + STDMETHODIMP get_Title(BSTR* pbstrTitle); + STDMETHODIMP get_Rating(BSTR* pbstrRating); + STDMETHODIMP get_Description(BSTR* pbstrDescription); + STDMETHODIMP get_Copyright(BSTR* pbstrCopyright); + STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL); + STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL); + STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL); + STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL); + STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL); + STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage); + STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL); + STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText); +}; diff --git a/src/filters/reader/CDDAReader/CDDAReader.rc b/src/filters/reader/CDDAReader/CDDAReader.rc index b11cb32ed5c..8ec8c11ffbe 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.rc +++ b/src/filters/reader/CDDAReader/CDDAReader.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "CDDA Reader Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "CDDA Reader Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "CDDAReader.ax" - VALUE "ProductName", "CDDA Reader Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "CDDA Reader Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "CDDA Reader Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "CDDAReader.ax" + VALUE "ProductName", "CDDA Reader Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/reader/CDDAReader/CDDAReader.vcxproj b/src/filters/reader/CDDAReader/CDDAReader.vcxproj index d8a4dbe97e7..f9c2db96ff3 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.vcxproj +++ b/src/filters/reader/CDDAReader/CDDAReader.vcxproj @@ -1,127 +1,127 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {543D40E9-8CA6-4E4B-9936-90CBA562B268} - CDDAReader - MFCProj - CDDAReader - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - CDDAReader.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {9f31d122-e84d-485a-a58d-09dad01a56ce} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {543D40E9-8CA6-4E4B-9936-90CBA562B268} + CDDAReader + MFCProj + CDDAReader + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + CDDAReader.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {9f31d122-e84d-485a-a58d-09dad01a56ce} + + + + + \ No newline at end of file diff --git a/src/filters/reader/CDDAReader/CDDAReader.vcxproj.filters b/src/filters/reader/CDDAReader/CDDAReader.vcxproj.filters index 0df042c209b..b346ad121af 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.vcxproj.filters +++ b/src/filters/reader/CDDAReader/CDDAReader.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {3251baa6-81ad-4ee0-a183-a0ace02fd96c} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {4e594eac-878e-4f75-84cf-61b6779dd162} - h;hpp;hxx;hm;inl;inc - - - {edb78716-8ad1-4c34-9651-495ae470c32a} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {3251baa6-81ad-4ee0-a183-a0ace02fd96c} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {4e594eac-878e-4f75-84cf-61b6779dd162} + h;hpp;hxx;hm;inl;inc + + + {edb78716-8ad1-4c34-9651-495ae470c32a} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/reader/CDDAReader/resource.h b/src/filters/reader/CDDAReader/resource.h index 6fd241bb55d..0b70277da3b 100644 --- a/src/filters/reader/CDDAReader/resource.h +++ b/src/filters/reader/CDDAReader/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by CDDAReader.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by CDDAReader.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/reader/CDDAReader/stdafx.cpp b/src/filters/reader/CDDAReader/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/reader/CDDAReader/stdafx.cpp +++ b/src/filters/reader/CDDAReader/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/reader/CDDAReader/stdafx.h b/src/filters/reader/CDDAReader/stdafx.h index d8320f2c878..12bbe2db0a7 100644 --- a/src/filters/reader/CDDAReader/stdafx.h +++ b/src/filters/reader/CDDAReader/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/reader/CDXAReader/CDXAReader.cpp b/src/filters/reader/CDXAReader/CDXAReader.cpp index bd042a1f189..6ddbdd4ce1d 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.cpp +++ b/src/filters/reader/CDXAReader/CDXAReader.cpp @@ -1,561 +1,561 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "CDXAReader.h" -#include "../../../DSUtil/DSUtil.h" -#ifdef STANDALONE_FILTER -#include -#endif -#include -#include "moreuuids.h" - -///////// - -static constexpr DWORD EDC_crctable[256] = { - 0x00000000l, 0x90910101l, 0x91210201l, 0x01b00300l, - 0x92410401l, 0x02d00500l, 0x03600600l, 0x93f10701l, - 0x94810801l, 0x04100900l, 0x05a00a00l, 0x95310b01l, - 0x06c00c00l, 0x96510d01l, 0x97e10e01l, 0x07700f00l, - 0x99011001l, 0x09901100l, 0x08201200l, 0x98b11301l, - 0x0b401400l, 0x9bd11501l, 0x9a611601l, 0x0af01700l, - 0x0d801800l, 0x9d111901l, 0x9ca11a01l, 0x0c301b00l, - 0x9fc11c01l, 0x0f501d00l, 0x0ee01e00l, 0x9e711f01l, - 0x82012001l, 0x12902100l, 0x13202200l, 0x83b12301l, - 0x10402400l, 0x80d12501l, 0x81612601l, 0x11f02700l, - 0x16802800l, 0x86112901l, 0x87a12a01l, 0x17302b00l, - 0x84c12c01l, 0x14502d00l, 0x15e02e00l, 0x85712f01l, - 0x1b003000l, 0x8b913101l, 0x8a213201l, 0x1ab03300l, - 0x89413401l, 0x19d03500l, 0x18603600l, 0x88f13701l, - 0x8f813801l, 0x1f103900l, 0x1ea03a00l, 0x8e313b01l, - 0x1dc03c00l, 0x8d513d01l, 0x8ce13e01l, 0x1c703f00l, - 0xb4014001l, 0x24904100l, 0x25204200l, 0xb5b14301l, - 0x26404400l, 0xb6d14501l, 0xb7614601l, 0x27f04700l, - 0x20804800l, 0xb0114901l, 0xb1a14a01l, 0x21304b00l, - 0xb2c14c01l, 0x22504d00l, 0x23e04e00l, 0xb3714f01l, - 0x2d005000l, 0xbd915101l, 0xbc215201l, 0x2cb05300l, - 0xbf415401l, 0x2fd05500l, 0x2e605600l, 0xbef15701l, - 0xb9815801l, 0x29105900l, 0x28a05a00l, 0xb8315b01l, - 0x2bc05c00l, 0xbb515d01l, 0xbae15e01l, 0x2a705f00l, - 0x36006000l, 0xa6916101l, 0xa7216201l, 0x37b06300l, - 0xa4416401l, 0x34d06500l, 0x35606600l, 0xa5f16701l, - 0xa2816801l, 0x32106900l, 0x33a06a00l, 0xa3316b01l, - 0x30c06c00l, 0xa0516d01l, 0xa1e16e01l, 0x31706f00l, - 0xaf017001l, 0x3f907100l, 0x3e207200l, 0xaeb17301l, - 0x3d407400l, 0xadd17501l, 0xac617601l, 0x3cf07700l, - 0x3b807800l, 0xab117901l, 0xaaa17a01l, 0x3a307b00l, - 0xa9c17c01l, 0x39507d00l, 0x38e07e00l, 0xa8717f01l, - 0xd8018001l, 0x48908100l, 0x49208200l, 0xd9b18301l, - 0x4a408400l, 0xdad18501l, 0xdb618601l, 0x4bf08700l, - 0x4c808800l, 0xdc118901l, 0xdda18a01l, 0x4d308b00l, - 0xdec18c01l, 0x4e508d00l, 0x4fe08e00l, 0xdf718f01l, - 0x41009000l, 0xd1919101l, 0xd0219201l, 0x40b09300l, - 0xd3419401l, 0x43d09500l, 0x42609600l, 0xd2f19701l, - 0xd5819801l, 0x45109900l, 0x44a09a00l, 0xd4319b01l, - 0x47c09c00l, 0xd7519d01l, 0xd6e19e01l, 0x46709f00l, - 0x5a00a000l, 0xca91a101l, 0xcb21a201l, 0x5bb0a300l, - 0xc841a401l, 0x58d0a500l, 0x5960a600l, 0xc9f1a701l, - 0xce81a801l, 0x5e10a900l, 0x5fa0aa00l, 0xcf31ab01l, - 0x5cc0ac00l, 0xcc51ad01l, 0xcde1ae01l, 0x5d70af00l, - 0xc301b001l, 0x5390b100l, 0x5220b200l, 0xc2b1b301l, - 0x5140b400l, 0xc1d1b501l, 0xc061b601l, 0x50f0b700l, - 0x5780b800l, 0xc711b901l, 0xc6a1ba01l, 0x5630bb00l, - 0xc5c1bc01l, 0x5550bd00l, 0x54e0be00l, 0xc471bf01l, - 0x6c00c000l, 0xfc91c101l, 0xfd21c201l, 0x6db0c300l, - 0xfe41c401l, 0x6ed0c500l, 0x6f60c600l, 0xfff1c701l, - 0xf881c801l, 0x6810c900l, 0x69a0ca00l, 0xf931cb01l, - 0x6ac0cc00l, 0xfa51cd01l, 0xfbe1ce01l, 0x6b70cf00l, - 0xf501d001l, 0x6590d100l, 0x6420d200l, 0xf4b1d301l, - 0x6740d400l, 0xf7d1d501l, 0xf661d601l, 0x66f0d700l, - 0x6180d800l, 0xf111d901l, 0xf0a1da01l, 0x6030db00l, - 0xf3c1dc01l, 0x6350dd00l, 0x62e0de00l, 0xf271df01l, - 0xee01e001l, 0x7e90e100l, 0x7f20e200l, 0xefb1e301l, - 0x7c40e400l, 0xecd1e501l, 0xed61e601l, 0x7df0e700l, - 0x7a80e800l, 0xea11e901l, 0xeba1ea01l, 0x7b30eb00l, - 0xe8c1ec01l, 0x7850ed00l, 0x79e0ee00l, 0xe971ef01l, - 0x7700f000l, 0xe791f101l, 0xe621f201l, 0x76b0f300l, - 0xe541f401l, 0x75d0f500l, 0x7460f600l, 0xe4f1f701l, - 0xe381f801l, 0x7310f900l, 0x72a0fa00l, 0xe231fb01l, - 0x71c0fc00l, 0xe151fd01l, 0xe0e1fe01l, 0x7070ff00l -}; - -static DWORD build_edc(const void* in, unsigned from, unsigned upto) -{ - const BYTE* p = (BYTE*)in + from; - DWORD result = 0; - - for (; from < upto; from++) { - result = EDC_crctable[(result ^ *p++) & 0xffL] ^ (result >> 8); - } - - return result; -} - -///////// - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL} -}; - -const AMOVIESETUP_PIN sudOpPin[] = { - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CCDXAReader), CCDXAReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}"), - _T("0"), _T("0,4,,52494646,8,4,,43445841")); // "RIFFxxxxCDXA" - - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}"), - _T("Source Filter"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}")); - - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}")); - - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CCDXAReader -// - -CCDXAReader::CCDXAReader(IUnknown* pUnk, HRESULT* phr) - : CAsyncReader(NAME("CCDXAReader"), pUnk, &m_stream, phr, __uuidof(this)) -{ - if (phr) { - *phr = S_OK; - } -} - -CCDXAReader::~CCDXAReader() -{ -} - -STDMETHODIMP CCDXAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IFileSourceFilter) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CCDXAReader::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - - wcscpy_s(pInfo->achName, CCDXAReaderName); - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -STDMETHODIMP CCDXAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - CMediaType mt; - m_mt = mt; - - if (!m_stream.Load(pszFileName)) { - return E_FAIL; - } - - m_fn = pszFileName; - - mt.majortype = MEDIATYPE_Stream; - mt.subtype = m_stream.m_subtype; - m_mt = mt; - - return S_OK; -} - -STDMETHODIMP CCDXAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - - return S_OK; -} - -// CCDXAStream - -CCDXAStream::CCDXAStream() -{ - m_subtype = MEDIASUBTYPE_NULL; - - m_hFile = INVALID_HANDLE_VALUE; - - m_llPosition = m_llLength = 0; - m_nFirstSector = 0; - m_nBufferedSector = -1; - ZeroMemory(m_sector, sizeof(m_sector)); -} - -CCDXAStream::~CCDXAStream() -{ - if (m_hFile != INVALID_HANDLE_VALUE) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - } -} - -bool CCDXAStream::Load(const WCHAR* fnw) -{ - if (m_hFile != INVALID_HANDLE_VALUE) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - } - - m_hFile = CreateFile(CString(fnw), GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); - if (m_hFile == INVALID_HANDLE_VALUE) { - return false; - } - - BYTE hdr[RIFFCDXA_HEADER_SIZE]; - DWORD NumberOfBytesRead; - if (!ReadFile(m_hFile, (LPVOID)hdr, RIFFCDXA_HEADER_SIZE, &NumberOfBytesRead, nullptr) - || *((DWORD*)&hdr[0]) != 'FFIR' || *((DWORD*)&hdr[8]) != 'AXDC' - || *((DWORD*)&hdr[4]) != (*((DWORD*)&hdr[0x28]) + 0x24)) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - return false; - } - - LARGE_INTEGER size = {0, 0}; - GetFileSizeEx(m_hFile, &size); - - m_llLength = ((size.QuadPart - RIFFCDXA_HEADER_SIZE) / RAW_SECTOR_SIZE) * RAW_DATA_SIZE; - - if (!LookForMediaSubType()) { - m_llPosition = m_llLength = 0; - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - return false; - } - - m_llPosition = 0; - - m_nBufferedSector = -1; - - return true; -} - -HRESULT CCDXAStream::SetPointer(LONGLONG llPos) -{ - HRESULT hr = S_FALSE; - - if (llPos >= 0 && llPos < m_llLength) { - m_llPosition = llPos; - hr = S_OK; - } - - return hr; -} - -HRESULT CCDXAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) -{ - CAutoLock lck(&m_csLock); - - PBYTE pbBufferOrg = pbBuffer; - LONGLONG pos = m_llPosition; - - while (pos >= 0 && pos < m_llLength && dwBytesToRead > 0) { - UINT sector = m_nFirstSector + int(pos / RAW_DATA_SIZE); - __int64 offset = pos % RAW_DATA_SIZE; - - if (m_nBufferedSector != (int)sector) { - LARGE_INTEGER FilePointer; - FilePointer.QuadPart = RIFFCDXA_HEADER_SIZE + sector * RAW_SECTOR_SIZE; - SetFilePointerEx(m_hFile, FilePointer, &FilePointer, FILE_BEGIN); - - ZeroMemory(m_sector, sizeof(m_sector)); - - DWORD NumberOfBytesRead = 0; - - int nRetries = 3; - while (nRetries--) { - NumberOfBytesRead = 0; - if (!ReadFile(m_hFile, m_sector, RAW_SECTOR_SIZE, &NumberOfBytesRead, nullptr) - || NumberOfBytesRead != RAW_SECTOR_SIZE) { - break; - } - - if (*(DWORD*)&m_sector[RAW_SECTOR_SIZE - 4] == 0) { // no CRC? it happens... - break; - } - - if (build_edc(m_sector, RAW_SYNC_SIZE + RAW_HEADER_SIZE, RAW_SECTOR_SIZE) == 0) { - break; - } - - TRACE(_T("CCDXAStream: CRC error at sector %u (fp=0x%I64x, retriesleft=%d)\n"), sector, FilePointer.QuadPart, nRetries); - } - - m_nBufferedSector = sector; - } - - DWORD l = std::min(dwBytesToRead, (DWORD)std::min(RAW_DATA_SIZE - offset, m_llLength - pos)); - memcpy(pbBuffer, &m_sector[RAW_SYNC_SIZE + RAW_HEADER_SIZE + RAW_SUBHEADER_SIZE + offset], l); - - pbBuffer += l; - pos += l; - dwBytesToRead -= l; - } - - if (pdwBytesRead) { - *pdwBytesRead = DWORD(pbBuffer - pbBufferOrg); - } - m_llPosition += pbBuffer - pbBufferOrg; - - if (dwBytesToRead != 0) { - return S_FALSE; - } - - return S_OK; -} - -LONGLONG CCDXAStream::Size(LONGLONG* pSizeAvailable) -{ - if (pSizeAvailable) { - *pSizeAvailable = m_llLength; - } - return m_llLength; -} - -DWORD CCDXAStream::Alignment() -{ - return 1; -} - -void CCDXAStream::Lock() -{ - m_csLock.Lock(); -} - -void CCDXAStream::Unlock() -{ - m_csLock.Unlock(); -} - -// - -bool CCDXAStream::LookForMediaSubType() -{ - BYTE buff[RAW_DATA_SIZE]; - - m_subtype = MEDIASUBTYPE_NULL; - - m_llPosition = 0; - - for (int iSectorsRead = 0; - Read(buff, RAW_DATA_SIZE, 1, nullptr) == S_OK && iSectorsRead < 1000; - iSectorsRead++) { - if (*((DWORD*)&buff[0]) == 0xba010000) { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - if ((buff[4] & 0xc4) == 0x44) { - m_subtype = MEDIASUBTYPE_MPEG2_PROGRAM; - } else if ((buff[4] & 0xf1) == 0x21) { - m_subtype = MEDIASUBTYPE_MPEG1System; - } - - return !!(m_subtype != MEDIASUBTYPE_NULL); - } else if (*((DWORD*)&buff[0]) == 'SggO') { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_Ogg; - - return true; - } else if (*((DWORD*)&buff[0]) == 0xA3DF451A) { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_Matroska; - - return true; - } else if (*((DWORD*)&buff[0]) == 'FMR.') { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_RealMedia; - - return true; - } else if (*((DWORD*)&buff[0]) == 'FFIR' && *((DWORD*)&buff[8]) == ' IVA') { - m_llPosition = 0; - m_llLength = std::min(m_llLength, LONGLONG(*((DWORD*)&buff[4])) + 8); - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_Avi; - - return true; - } else if (*((DWORD*)&buff[4]) == 'voom' || *((DWORD*)&buff[4]) == 'tadm' - || *((DWORD*)&buff[4]) == 'pytf' && *((DWORD*)&buff[8]) == 'mosi' && *((DWORD*)&buff[16]) == '14pm') { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_QTMovie; - - return true; - } - } - - m_llPosition = 0; - - CRegKey majorkey; - CString majortype = _T("\\Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"); - if (ERROR_SUCCESS == majorkey.Open(HKEY_CLASSES_ROOT, majortype, KEY_READ)) { - TCHAR subtype[256 + 1]; - DWORD len = 256; - for (int i = 0; ERROR_SUCCESS == majorkey.EnumKey(i, subtype, &len); i++, len = 256) { - CRegKey subkey; - if (ERROR_SUCCESS != subkey.Open(HKEY_CLASSES_ROOT, majortype + _T("\\") + subtype, KEY_READ)) { - continue; - } - - for (int j = 0; true; j++) { - TCHAR number[10]; - _stprintf_s(number, _countof(number), _T("%d"), j); - - TCHAR pattern[256 + 1]; - ULONG lenValue = 256; - if (ERROR_SUCCESS != subkey.QueryStringValue(number, pattern, &lenValue)) { - break; - } - - CString p = pattern; - p += _T(','); - - __int64 offset = 0; - DWORD cb = 0; - CAtlArray mask, val; - - int nMatches = 0, nTries = 0; - - for (int k = 0, l; nTries >= 0 && (l = p.Find(',', k)) >= 0; k = l + 1, nTries++) { - CString s = p.Mid(k, l - k); - TRACE(s + '\n'); - - TCHAR* end = nullptr; - - switch (nTries & 3) { - case 0: - offset = _tcstol(s, &end, 10); - break; - case 1: - cb = _tcstol(s, &end, 10); - break; - case 2: - CStringToBin(s, mask); - break; - case 3: - CStringToBin(s, val); - break; - default: - ASSERT(FALSE); // Shouldn't happen - nTries = -1; - break; - } - - if (nTries >= 0 && (nTries & 3) == 3) { - if (cb > 0 && !val.IsEmpty() && cb == val.GetCount()) { - if (offset >= 0 && S_OK == SetPointer(offset) - || S_OK == SetPointer(m_llLength + offset)) { - CAutoVectorPtr pData; - if (pData.Allocate(cb)) { - DWORD BytesRead = 0; - if (S_OK == Read(pData, cb, 1, &BytesRead) && cb == BytesRead) { - if (mask.GetCount() < cb) { - size_t x = mask.GetCount(); - mask.SetCount(cb); - for (; x < cb; x++) { - mask[x] = 0xff; - } - } - - for (unsigned int x = 0; x < cb; x++) { - pData[x] &= (BYTE)mask[x]; - } - - if (memcmp(pData, val.GetData(), cb) == 0) { - nMatches++; - } - } - } - } - - offset = 0; - cb = 0; - mask.RemoveAll(); - val.RemoveAll(); - } - } - } - - if (nMatches > 0 && nMatches * 4 == nTries) { - m_subtype = GUIDFromCString(subtype); - return S_OK; - } - } - } - } - - return false; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "CDXAReader.h" +#include "../../../DSUtil/DSUtil.h" +#ifdef STANDALONE_FILTER +#include +#endif +#include +#include "moreuuids.h" + +///////// + +static constexpr DWORD EDC_crctable[256] = { + 0x00000000l, 0x90910101l, 0x91210201l, 0x01b00300l, + 0x92410401l, 0x02d00500l, 0x03600600l, 0x93f10701l, + 0x94810801l, 0x04100900l, 0x05a00a00l, 0x95310b01l, + 0x06c00c00l, 0x96510d01l, 0x97e10e01l, 0x07700f00l, + 0x99011001l, 0x09901100l, 0x08201200l, 0x98b11301l, + 0x0b401400l, 0x9bd11501l, 0x9a611601l, 0x0af01700l, + 0x0d801800l, 0x9d111901l, 0x9ca11a01l, 0x0c301b00l, + 0x9fc11c01l, 0x0f501d00l, 0x0ee01e00l, 0x9e711f01l, + 0x82012001l, 0x12902100l, 0x13202200l, 0x83b12301l, + 0x10402400l, 0x80d12501l, 0x81612601l, 0x11f02700l, + 0x16802800l, 0x86112901l, 0x87a12a01l, 0x17302b00l, + 0x84c12c01l, 0x14502d00l, 0x15e02e00l, 0x85712f01l, + 0x1b003000l, 0x8b913101l, 0x8a213201l, 0x1ab03300l, + 0x89413401l, 0x19d03500l, 0x18603600l, 0x88f13701l, + 0x8f813801l, 0x1f103900l, 0x1ea03a00l, 0x8e313b01l, + 0x1dc03c00l, 0x8d513d01l, 0x8ce13e01l, 0x1c703f00l, + 0xb4014001l, 0x24904100l, 0x25204200l, 0xb5b14301l, + 0x26404400l, 0xb6d14501l, 0xb7614601l, 0x27f04700l, + 0x20804800l, 0xb0114901l, 0xb1a14a01l, 0x21304b00l, + 0xb2c14c01l, 0x22504d00l, 0x23e04e00l, 0xb3714f01l, + 0x2d005000l, 0xbd915101l, 0xbc215201l, 0x2cb05300l, + 0xbf415401l, 0x2fd05500l, 0x2e605600l, 0xbef15701l, + 0xb9815801l, 0x29105900l, 0x28a05a00l, 0xb8315b01l, + 0x2bc05c00l, 0xbb515d01l, 0xbae15e01l, 0x2a705f00l, + 0x36006000l, 0xa6916101l, 0xa7216201l, 0x37b06300l, + 0xa4416401l, 0x34d06500l, 0x35606600l, 0xa5f16701l, + 0xa2816801l, 0x32106900l, 0x33a06a00l, 0xa3316b01l, + 0x30c06c00l, 0xa0516d01l, 0xa1e16e01l, 0x31706f00l, + 0xaf017001l, 0x3f907100l, 0x3e207200l, 0xaeb17301l, + 0x3d407400l, 0xadd17501l, 0xac617601l, 0x3cf07700l, + 0x3b807800l, 0xab117901l, 0xaaa17a01l, 0x3a307b00l, + 0xa9c17c01l, 0x39507d00l, 0x38e07e00l, 0xa8717f01l, + 0xd8018001l, 0x48908100l, 0x49208200l, 0xd9b18301l, + 0x4a408400l, 0xdad18501l, 0xdb618601l, 0x4bf08700l, + 0x4c808800l, 0xdc118901l, 0xdda18a01l, 0x4d308b00l, + 0xdec18c01l, 0x4e508d00l, 0x4fe08e00l, 0xdf718f01l, + 0x41009000l, 0xd1919101l, 0xd0219201l, 0x40b09300l, + 0xd3419401l, 0x43d09500l, 0x42609600l, 0xd2f19701l, + 0xd5819801l, 0x45109900l, 0x44a09a00l, 0xd4319b01l, + 0x47c09c00l, 0xd7519d01l, 0xd6e19e01l, 0x46709f00l, + 0x5a00a000l, 0xca91a101l, 0xcb21a201l, 0x5bb0a300l, + 0xc841a401l, 0x58d0a500l, 0x5960a600l, 0xc9f1a701l, + 0xce81a801l, 0x5e10a900l, 0x5fa0aa00l, 0xcf31ab01l, + 0x5cc0ac00l, 0xcc51ad01l, 0xcde1ae01l, 0x5d70af00l, + 0xc301b001l, 0x5390b100l, 0x5220b200l, 0xc2b1b301l, + 0x5140b400l, 0xc1d1b501l, 0xc061b601l, 0x50f0b700l, + 0x5780b800l, 0xc711b901l, 0xc6a1ba01l, 0x5630bb00l, + 0xc5c1bc01l, 0x5550bd00l, 0x54e0be00l, 0xc471bf01l, + 0x6c00c000l, 0xfc91c101l, 0xfd21c201l, 0x6db0c300l, + 0xfe41c401l, 0x6ed0c500l, 0x6f60c600l, 0xfff1c701l, + 0xf881c801l, 0x6810c900l, 0x69a0ca00l, 0xf931cb01l, + 0x6ac0cc00l, 0xfa51cd01l, 0xfbe1ce01l, 0x6b70cf00l, + 0xf501d001l, 0x6590d100l, 0x6420d200l, 0xf4b1d301l, + 0x6740d400l, 0xf7d1d501l, 0xf661d601l, 0x66f0d700l, + 0x6180d800l, 0xf111d901l, 0xf0a1da01l, 0x6030db00l, + 0xf3c1dc01l, 0x6350dd00l, 0x62e0de00l, 0xf271df01l, + 0xee01e001l, 0x7e90e100l, 0x7f20e200l, 0xefb1e301l, + 0x7c40e400l, 0xecd1e501l, 0xed61e601l, 0x7df0e700l, + 0x7a80e800l, 0xea11e901l, 0xeba1ea01l, 0x7b30eb00l, + 0xe8c1ec01l, 0x7850ed00l, 0x79e0ee00l, 0xe971ef01l, + 0x7700f000l, 0xe791f101l, 0xe621f201l, 0x76b0f300l, + 0xe541f401l, 0x75d0f500l, 0x7460f600l, 0xe4f1f701l, + 0xe381f801l, 0x7310f900l, 0x72a0fa00l, 0xe231fb01l, + 0x71c0fc00l, 0xe151fd01l, 0xe0e1fe01l, 0x7070ff00l +}; + +static DWORD build_edc(const void* in, unsigned from, unsigned upto) +{ + const BYTE* p = (BYTE*)in + from; + DWORD result = 0; + + for (; from < upto; from++) { + result = EDC_crctable[(result ^ *p++) & 0xffL] ^ (result >> 8); + } + + return result; +} + +///////// + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL} +}; + +const AMOVIESETUP_PIN sudOpPin[] = { + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CCDXAReader), CCDXAReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}"), + _T("0"), _T("0,4,,52494646,8,4,,43445841")); // "RIFFxxxxCDXA" + + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}"), + _T("Source Filter"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}")); + + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}")); + + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CCDXAReader +// + +CCDXAReader::CCDXAReader(IUnknown* pUnk, HRESULT* phr) + : CAsyncReader(NAME("CCDXAReader"), pUnk, &m_stream, phr, __uuidof(this)) +{ + if (phr) { + *phr = S_OK; + } +} + +CCDXAReader::~CCDXAReader() +{ +} + +STDMETHODIMP CCDXAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IFileSourceFilter) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CCDXAReader::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + + wcscpy_s(pInfo->achName, CCDXAReaderName); + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP CCDXAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + CMediaType mt; + m_mt = mt; + + if (!m_stream.Load(pszFileName)) { + return E_FAIL; + } + + m_fn = pszFileName; + + mt.majortype = MEDIATYPE_Stream; + mt.subtype = m_stream.m_subtype; + m_mt = mt; + + return S_OK; +} + +STDMETHODIMP CCDXAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + + return S_OK; +} + +// CCDXAStream + +CCDXAStream::CCDXAStream() +{ + m_subtype = MEDIASUBTYPE_NULL; + + m_hFile = INVALID_HANDLE_VALUE; + + m_llPosition = m_llLength = 0; + m_nFirstSector = 0; + m_nBufferedSector = -1; + ZeroMemory(m_sector, sizeof(m_sector)); +} + +CCDXAStream::~CCDXAStream() +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } +} + +bool CCDXAStream::Load(const WCHAR* fnw) +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } + + m_hFile = CreateFile(CString(fnw), GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); + if (m_hFile == INVALID_HANDLE_VALUE) { + return false; + } + + BYTE hdr[RIFFCDXA_HEADER_SIZE]; + DWORD NumberOfBytesRead; + if (!ReadFile(m_hFile, (LPVOID)hdr, RIFFCDXA_HEADER_SIZE, &NumberOfBytesRead, nullptr) + || *((DWORD*)&hdr[0]) != 'FFIR' || *((DWORD*)&hdr[8]) != 'AXDC' + || *((DWORD*)&hdr[4]) != (*((DWORD*)&hdr[0x28]) + 0x24)) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + return false; + } + + LARGE_INTEGER size = {0, 0}; + GetFileSizeEx(m_hFile, &size); + + m_llLength = ((size.QuadPart - RIFFCDXA_HEADER_SIZE) / RAW_SECTOR_SIZE) * RAW_DATA_SIZE; + + if (!LookForMediaSubType()) { + m_llPosition = m_llLength = 0; + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + return false; + } + + m_llPosition = 0; + + m_nBufferedSector = -1; + + return true; +} + +HRESULT CCDXAStream::SetPointer(LONGLONG llPos) +{ + HRESULT hr = S_FALSE; + + if (llPos >= 0 && llPos < m_llLength) { + m_llPosition = llPos; + hr = S_OK; + } + + return hr; +} + +HRESULT CCDXAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) +{ + CAutoLock lck(&m_csLock); + + PBYTE pbBufferOrg = pbBuffer; + LONGLONG pos = m_llPosition; + + while (pos >= 0 && pos < m_llLength && dwBytesToRead > 0) { + UINT sector = m_nFirstSector + int(pos / RAW_DATA_SIZE); + __int64 offset = pos % RAW_DATA_SIZE; + + if (m_nBufferedSector != (int)sector) { + LARGE_INTEGER FilePointer; + FilePointer.QuadPart = RIFFCDXA_HEADER_SIZE + sector * RAW_SECTOR_SIZE; + SetFilePointerEx(m_hFile, FilePointer, &FilePointer, FILE_BEGIN); + + ZeroMemory(m_sector, sizeof(m_sector)); + + DWORD NumberOfBytesRead = 0; + + int nRetries = 3; + while (nRetries--) { + NumberOfBytesRead = 0; + if (!ReadFile(m_hFile, m_sector, RAW_SECTOR_SIZE, &NumberOfBytesRead, nullptr) + || NumberOfBytesRead != RAW_SECTOR_SIZE) { + break; + } + + if (*(DWORD*)&m_sector[RAW_SECTOR_SIZE - 4] == 0) { // no CRC? it happens... + break; + } + + if (build_edc(m_sector, RAW_SYNC_SIZE + RAW_HEADER_SIZE, RAW_SECTOR_SIZE) == 0) { + break; + } + + TRACE(_T("CCDXAStream: CRC error at sector %u (fp=0x%I64x, retriesleft=%d)\n"), sector, FilePointer.QuadPart, nRetries); + } + + m_nBufferedSector = sector; + } + + DWORD l = std::min(dwBytesToRead, (DWORD)std::min(RAW_DATA_SIZE - offset, m_llLength - pos)); + memcpy(pbBuffer, &m_sector[RAW_SYNC_SIZE + RAW_HEADER_SIZE + RAW_SUBHEADER_SIZE + offset], l); + + pbBuffer += l; + pos += l; + dwBytesToRead -= l; + } + + if (pdwBytesRead) { + *pdwBytesRead = DWORD(pbBuffer - pbBufferOrg); + } + m_llPosition += pbBuffer - pbBufferOrg; + + if (dwBytesToRead != 0) { + return S_FALSE; + } + + return S_OK; +} + +LONGLONG CCDXAStream::Size(LONGLONG* pSizeAvailable) +{ + if (pSizeAvailable) { + *pSizeAvailable = m_llLength; + } + return m_llLength; +} + +DWORD CCDXAStream::Alignment() +{ + return 1; +} + +void CCDXAStream::Lock() +{ + m_csLock.Lock(); +} + +void CCDXAStream::Unlock() +{ + m_csLock.Unlock(); +} + +// + +bool CCDXAStream::LookForMediaSubType() +{ + BYTE buff[RAW_DATA_SIZE]; + + m_subtype = MEDIASUBTYPE_NULL; + + m_llPosition = 0; + + for (int iSectorsRead = 0; + Read(buff, RAW_DATA_SIZE, 1, nullptr) == S_OK && iSectorsRead < 1000; + iSectorsRead++) { + if (*((DWORD*)&buff[0]) == 0xba010000) { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + if ((buff[4] & 0xc4) == 0x44) { + m_subtype = MEDIASUBTYPE_MPEG2_PROGRAM; + } else if ((buff[4] & 0xf1) == 0x21) { + m_subtype = MEDIASUBTYPE_MPEG1System; + } + + return !!(m_subtype != MEDIASUBTYPE_NULL); + } else if (*((DWORD*)&buff[0]) == 'SggO') { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_Ogg; + + return true; + } else if (*((DWORD*)&buff[0]) == 0xA3DF451A) { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_Matroska; + + return true; + } else if (*((DWORD*)&buff[0]) == 'FMR.') { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_RealMedia; + + return true; + } else if (*((DWORD*)&buff[0]) == 'FFIR' && *((DWORD*)&buff[8]) == ' IVA') { + m_llPosition = 0; + m_llLength = std::min(m_llLength, LONGLONG(*((DWORD*)&buff[4])) + 8); + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_Avi; + + return true; + } else if (*((DWORD*)&buff[4]) == 'voom' || *((DWORD*)&buff[4]) == 'tadm' + || *((DWORD*)&buff[4]) == 'pytf' && *((DWORD*)&buff[8]) == 'mosi' && *((DWORD*)&buff[16]) == '14pm') { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_QTMovie; + + return true; + } + } + + m_llPosition = 0; + + CRegKey majorkey; + CString majortype = _T("\\Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"); + if (ERROR_SUCCESS == majorkey.Open(HKEY_CLASSES_ROOT, majortype, KEY_READ)) { + TCHAR subtype[256 + 1]; + DWORD len = 256; + for (int i = 0; ERROR_SUCCESS == majorkey.EnumKey(i, subtype, &len); i++, len = 256) { + CRegKey subkey; + if (ERROR_SUCCESS != subkey.Open(HKEY_CLASSES_ROOT, majortype + _T("\\") + subtype, KEY_READ)) { + continue; + } + + for (int j = 0; true; j++) { + TCHAR number[10]; + _stprintf_s(number, _countof(number), _T("%d"), j); + + TCHAR pattern[256 + 1]; + ULONG lenValue = 256; + if (ERROR_SUCCESS != subkey.QueryStringValue(number, pattern, &lenValue)) { + break; + } + + CString p = pattern; + p += _T(','); + + __int64 offset = 0; + DWORD cb = 0; + CAtlArray mask, val; + + int nMatches = 0, nTries = 0; + + for (int k = 0, l; nTries >= 0 && (l = p.Find(',', k)) >= 0; k = l + 1, nTries++) { + CString s = p.Mid(k, l - k); + TRACE(s + '\n'); + + TCHAR* end = nullptr; + + switch (nTries & 3) { + case 0: + offset = _tcstol(s, &end, 10); + break; + case 1: + cb = _tcstol(s, &end, 10); + break; + case 2: + CStringToBin(s, mask); + break; + case 3: + CStringToBin(s, val); + break; + default: + ASSERT(FALSE); // Shouldn't happen + nTries = -1; + break; + } + + if (nTries >= 0 && (nTries & 3) == 3) { + if (cb > 0 && !val.IsEmpty() && cb == val.GetCount()) { + if (offset >= 0 && S_OK == SetPointer(offset) + || S_OK == SetPointer(m_llLength + offset)) { + CAutoVectorPtr pData; + if (pData.Allocate(cb)) { + DWORD BytesRead = 0; + if (S_OK == Read(pData, cb, 1, &BytesRead) && cb == BytesRead) { + if (mask.GetCount() < cb) { + size_t x = mask.GetCount(); + mask.SetCount(cb); + for (; x < cb; x++) { + mask[x] = 0xff; + } + } + + for (unsigned int x = 0; x < cb; x++) { + pData[x] &= (BYTE)mask[x]; + } + + if (memcmp(pData, val.GetData(), cb) == 0) { + nMatches++; + } + } + } + } + + offset = 0; + cb = 0; + mask.RemoveAll(); + val.RemoveAll(); + } + } + } + + if (nMatches > 0 && nMatches * 4 == nTries) { + m_subtype = GUIDFromCString(subtype); + return S_OK; + } + } + } + } + + return false; +} diff --git a/src/filters/reader/CDXAReader/CDXAReader.def b/src/filters/reader/CDXAReader/CDXAReader.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.def +++ b/src/filters/reader/CDXAReader/CDXAReader.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/reader/CDXAReader/CDXAReader.h b/src/filters/reader/CDXAReader/CDXAReader.h index 145975abfae..bd9bae446db 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.h +++ b/src/filters/reader/CDXAReader/CDXAReader.h @@ -1,93 +1,93 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "AsyncReader/asyncio.h" -#include "AsyncReader/asyncrdr.h" - -#define CCDXAReaderName L"MPC-HC CDXA Reader" - -class CCDXAStream : public CAsyncStream -{ -private: - enum { - RIFFCDXA_HEADER_SIZE = 44, // usually... - RAW_SYNC_SIZE = 12, // 00 FF .. FF 00 - RAW_HEADER_SIZE = 4, - RAW_SUBHEADER_SIZE = 8, - RAW_DATA_SIZE = 2324, - RAW_EDC_SIZE = 4, - RAW_SECTOR_SIZE = 2352 - }; - - CCritSec m_csLock; - - HANDLE m_hFile; - LONGLONG m_llPosition, m_llLength; - int m_nFirstSector; - - int m_nBufferedSector; - BYTE m_sector[RAW_SECTOR_SIZE]; - - bool LookForMediaSubType(); - -public: - CCDXAStream(); - virtual ~CCDXAStream(); - - bool Load(const WCHAR* fnw); - - HRESULT SetPointer(LONGLONG llPos); - HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); - LONGLONG Size(LONGLONG* pSizeAvailable); - DWORD Alignment(); - void Lock(); - void Unlock(); - - GUID m_subtype; -}; - -class __declspec(uuid("D367878E-F3B8-4235-A968-F378EF1B9A44")) - CCDXAReader - : public CAsyncReader - , public IFileSourceFilter -{ - CCDXAStream m_stream; - CStringW m_fn; - -public: - CCDXAReader(IUnknown* pUnk, HRESULT* phr); - ~CCDXAReader(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // CBaseFilter - - STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); - - // IFileSourceFilter - - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "AsyncReader/asyncio.h" +#include "AsyncReader/asyncrdr.h" + +#define CCDXAReaderName L"MPC-HC CDXA Reader" + +class CCDXAStream : public CAsyncStream +{ +private: + enum { + RIFFCDXA_HEADER_SIZE = 44, // usually... + RAW_SYNC_SIZE = 12, // 00 FF .. FF 00 + RAW_HEADER_SIZE = 4, + RAW_SUBHEADER_SIZE = 8, + RAW_DATA_SIZE = 2324, + RAW_EDC_SIZE = 4, + RAW_SECTOR_SIZE = 2352 + }; + + CCritSec m_csLock; + + HANDLE m_hFile; + LONGLONG m_llPosition, m_llLength; + int m_nFirstSector; + + int m_nBufferedSector; + BYTE m_sector[RAW_SECTOR_SIZE]; + + bool LookForMediaSubType(); + +public: + CCDXAStream(); + virtual ~CCDXAStream(); + + bool Load(const WCHAR* fnw); + + HRESULT SetPointer(LONGLONG llPos); + HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); + LONGLONG Size(LONGLONG* pSizeAvailable); + DWORD Alignment(); + void Lock(); + void Unlock(); + + GUID m_subtype; +}; + +class __declspec(uuid("D367878E-F3B8-4235-A968-F378EF1B9A44")) + CCDXAReader + : public CAsyncReader + , public IFileSourceFilter +{ + CCDXAStream m_stream; + CStringW m_fn; + +public: + CCDXAReader(IUnknown* pUnk, HRESULT* phr); + ~CCDXAReader(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // CBaseFilter + + STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); + + // IFileSourceFilter + + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); +}; diff --git a/src/filters/reader/CDXAReader/CDXAReader.rc b/src/filters/reader/CDXAReader/CDXAReader.rc index 7946b3f5e55..e695cc122f5 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.rc +++ b/src/filters/reader/CDXAReader/CDXAReader.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "CDXA Reader Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "CDXA Reader Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "CDXAReader.ax" - VALUE "ProductName", "CDXA Reader Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "CDXA Reader Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "CDXA Reader Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "CDXAReader.ax" + VALUE "ProductName", "CDXA Reader Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/reader/CDXAReader/CDXAReader.vcxproj b/src/filters/reader/CDXAReader/CDXAReader.vcxproj index c593478c486..cc00795704a 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.vcxproj +++ b/src/filters/reader/CDXAReader/CDXAReader.vcxproj @@ -1,127 +1,127 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {4D3B4FF4-535A-4201-AB7D-9AEC1E737A95} - CDXAReader - MFCProj - CDXAReader - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - CDXAReader.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {9f31d122-e84d-485a-a58d-09dad01a56ce} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {4D3B4FF4-535A-4201-AB7D-9AEC1E737A95} + CDXAReader + MFCProj + CDXAReader + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + CDXAReader.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {9f31d122-e84d-485a-a58d-09dad01a56ce} + + + + + \ No newline at end of file diff --git a/src/filters/reader/CDXAReader/CDXAReader.vcxproj.filters b/src/filters/reader/CDXAReader/CDXAReader.vcxproj.filters index 47d4a3b5068..6b899deab44 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.vcxproj.filters +++ b/src/filters/reader/CDXAReader/CDXAReader.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {bee90cb9-7ace-4e7d-b77a-1b4d710b5a25} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {a9a7c9a3-58c8-46f9-92fb-16b5ffdbdef2} - h;hpp;hxx;hm;inl;inc - - - {5dd4b870-4b51-419e-82bb-72ca9bd24680} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {bee90cb9-7ace-4e7d-b77a-1b4d710b5a25} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {a9a7c9a3-58c8-46f9-92fb-16b5ffdbdef2} + h;hpp;hxx;hm;inl;inc + + + {5dd4b870-4b51-419e-82bb-72ca9bd24680} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/reader/CDXAReader/resource.h b/src/filters/reader/CDXAReader/resource.h index fbfb65fad76..142004466c2 100644 --- a/src/filters/reader/CDXAReader/resource.h +++ b/src/filters/reader/CDXAReader/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by CDXAReader.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by CDXAReader.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/reader/CDXAReader/stdafx.cpp b/src/filters/reader/CDXAReader/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/reader/CDXAReader/stdafx.cpp +++ b/src/filters/reader/CDXAReader/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/reader/CDXAReader/stdafx.h b/src/filters/reader/CDXAReader/stdafx.h index d8320f2c878..12bbe2db0a7 100644 --- a/src/filters/reader/CDXAReader/stdafx.h +++ b/src/filters/reader/CDXAReader/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/reader/VTSReader/VTSReader.cpp b/src/filters/reader/VTSReader/VTSReader.cpp index c1296539368..e5aa7a295f1 100644 --- a/src/filters/reader/VTSReader/VTSReader.cpp +++ b/src/filters/reader/VTSReader/VTSReader.cpp @@ -1,297 +1,297 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "../../../DeCSS/VobFile.h" -#include "VTSReader.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG2_PROGRAM}, -}; - -const AMOVIESETUP_PIN sudOpPin[] = { - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CVTSReader), VTSReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}"), - _T("0"), _T("0,12,,445644564944454F2D565453")); // "DVDVIDEO-VTS" - - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}"), - _T("Source Filter"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")); - - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")); - - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CVTSReader -// - -CVTSReader::CVTSReader(IUnknown* pUnk, HRESULT* phr) - : CAsyncReader(NAME("CVTSReader"), pUnk, &m_stream, phr, __uuidof(this)) -{ - if (phr) { - *phr = S_OK; - } -} - -CVTSReader::~CVTSReader() -{ -} - -STDMETHODIMP CVTSReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFileSourceFilter) - QI(ITrackInfo) - QI(IDSMChapterBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CVTSReader::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - - wcscpy_s(pInfo->achName, VTSReaderName); - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -// IFileSourceFilter - -STDMETHODIMP CVTSReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - if (!m_stream.Load(pszFileName)) { - return E_FAIL; - } - - ChapRemoveAll(); - for (int i = 0; i < m_stream.GetChaptersCount(); i++) { - CString chap; - chap.Format(_T("Chapter %d"), i + 1); - ChapAppend(m_stream.GetChapterOffset(i), chap); - } - - - m_fn = pszFileName; - - CMediaType mt; - mt.majortype = MEDIATYPE_Stream; - mt.subtype = MEDIASUBTYPE_MPEG2_PROGRAM; - m_mt = mt; - - return S_OK; -} - -STDMETHODIMP CVTSReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - - return S_OK; -} - -// ITrackInfo - -STDMETHODIMP_(UINT) CVTSReader::GetTrackCount() -{ - return 0; // Not implemented yet -} - -STDMETHODIMP_(BOOL) CVTSReader::GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill) -{ - return FALSE; // Not implemented yet -} - -STDMETHODIMP_(BOOL) CVTSReader::GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill) -{ - return FALSE; // Not implemented yet -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackName(UINT aTrackIdx) -{ - return m_stream.GetTrackName(aTrackIdx); // return stream's language -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecID(UINT aTrackIdx) -{ - return nullptr; // Not implemented yet -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecName(UINT aTrackIdx) -{ - return nullptr; // Not implemented yet -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecInfoURL(UINT aTrackIdx) -{ - return nullptr; // Not implemented yet -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecDownloadURL(UINT aTrackIdx) -{ - return nullptr; // Not implemented yet -} - -// CVTSStream - -CVTSStream::CVTSStream() : m_off(0) -{ - m_vob.Attach(DEBUG_NEW CVobFile()); -} - -CVTSStream::~CVTSStream() -{ -} - -bool CVTSStream::Load(const WCHAR* fnw) -{ - CAtlList sl; - return (m_vob && m_vob->Open(CString(fnw), sl) /*&& m_vob->IsDVD()*/); -} - -HRESULT CVTSStream::SetPointer(LONGLONG llPos) -{ - m_off = (int)(llPos & 2047); - int lba = (int)(llPos / 2048); - - return lba == m_vob->Seek(lba) ? S_OK : S_FALSE; -} - -HRESULT CVTSStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) -{ - CAutoLock lck(&m_csLock); - - DWORD len = dwBytesToRead; - BYTE* ptr = pbBuffer; - - TRY - while (len > 0) { - BYTE buff[2048]; - if (!m_vob->Read(buff)) { - break; - } - - int size = std::min(2048 - m_off, (int)std::min(len, 2048ul)); - - memcpy(ptr, &buff[m_off], size); - - m_off = (m_off + size) & 2047; - - if (m_off > 0) { - m_vob->Seek(m_vob->GetPosition() - 1); - } - - ptr += size; - len -= size; - } - - if (pdwBytesRead) { - *pdwBytesRead = DWORD(ptr - pbBuffer); - } - CATCH(CFileException, e) - return S_FALSE; - END_CATCH - - return S_OK; -} - -LONGLONG CVTSStream::Size(LONGLONG* pSizeAvailable) -{ - LONGLONG len = 2048i64 * m_vob->GetLength(); - if (pSizeAvailable) { - *pSizeAvailable = len; - } - return len; -} - -DWORD CVTSStream::Alignment() -{ - return 1; -} - -void CVTSStream::Lock() -{ - m_csLock.Lock(); -} - -void CVTSStream::Unlock() -{ - m_csLock.Unlock(); -} - -BSTR CVTSStream::GetTrackName(UINT aTrackIdx) -{ - return m_vob->GetTrackName(aTrackIdx); -} - -int CVTSStream::GetChaptersCount() -{ - return m_vob->GetChaptersCount(); -} - -REFERENCE_TIME CVTSStream::GetChapterOffset(UINT ChapterNumber) -{ - return m_vob->GetChapterOffset(ChapterNumber); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "../../../DeCSS/VobFile.h" +#include "VTSReader.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG2_PROGRAM}, +}; + +const AMOVIESETUP_PIN sudOpPin[] = { + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CVTSReader), VTSReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}"), + _T("0"), _T("0,12,,445644564944454F2D565453")); // "DVDVIDEO-VTS" + + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}"), + _T("Source Filter"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")); + + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")); + + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CVTSReader +// + +CVTSReader::CVTSReader(IUnknown* pUnk, HRESULT* phr) + : CAsyncReader(NAME("CVTSReader"), pUnk, &m_stream, phr, __uuidof(this)) +{ + if (phr) { + *phr = S_OK; + } +} + +CVTSReader::~CVTSReader() +{ +} + +STDMETHODIMP CVTSReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFileSourceFilter) + QI(ITrackInfo) + QI(IDSMChapterBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CVTSReader::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + + wcscpy_s(pInfo->achName, VTSReaderName); + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +// IFileSourceFilter + +STDMETHODIMP CVTSReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + if (!m_stream.Load(pszFileName)) { + return E_FAIL; + } + + ChapRemoveAll(); + for (int i = 0; i < m_stream.GetChaptersCount(); i++) { + CString chap; + chap.Format(_T("Chapter %d"), i + 1); + ChapAppend(m_stream.GetChapterOffset(i), chap); + } + + + m_fn = pszFileName; + + CMediaType mt; + mt.majortype = MEDIATYPE_Stream; + mt.subtype = MEDIASUBTYPE_MPEG2_PROGRAM; + m_mt = mt; + + return S_OK; +} + +STDMETHODIMP CVTSReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + + return S_OK; +} + +// ITrackInfo + +STDMETHODIMP_(UINT) CVTSReader::GetTrackCount() +{ + return 0; // Not implemented yet +} + +STDMETHODIMP_(BOOL) CVTSReader::GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill) +{ + return FALSE; // Not implemented yet +} + +STDMETHODIMP_(BOOL) CVTSReader::GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill) +{ + return FALSE; // Not implemented yet +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackName(UINT aTrackIdx) +{ + return m_stream.GetTrackName(aTrackIdx); // return stream's language +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecID(UINT aTrackIdx) +{ + return nullptr; // Not implemented yet +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecName(UINT aTrackIdx) +{ + return nullptr; // Not implemented yet +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecInfoURL(UINT aTrackIdx) +{ + return nullptr; // Not implemented yet +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecDownloadURL(UINT aTrackIdx) +{ + return nullptr; // Not implemented yet +} + +// CVTSStream + +CVTSStream::CVTSStream() : m_off(0) +{ + m_vob.Attach(DEBUG_NEW CVobFile()); +} + +CVTSStream::~CVTSStream() +{ +} + +bool CVTSStream::Load(const WCHAR* fnw) +{ + CAtlList sl; + return (m_vob && m_vob->Open(CString(fnw), sl) /*&& m_vob->IsDVD()*/); +} + +HRESULT CVTSStream::SetPointer(LONGLONG llPos) +{ + m_off = (int)(llPos & 2047); + int lba = (int)(llPos / 2048); + + return lba == m_vob->Seek(lba) ? S_OK : S_FALSE; +} + +HRESULT CVTSStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) +{ + CAutoLock lck(&m_csLock); + + DWORD len = dwBytesToRead; + BYTE* ptr = pbBuffer; + + TRY + while (len > 0) { + BYTE buff[2048]; + if (!m_vob->Read(buff)) { + break; + } + + int size = std::min(2048 - m_off, (int)std::min(len, 2048ul)); + + memcpy(ptr, &buff[m_off], size); + + m_off = (m_off + size) & 2047; + + if (m_off > 0) { + m_vob->Seek(m_vob->GetPosition() - 1); + } + + ptr += size; + len -= size; + } + + if (pdwBytesRead) { + *pdwBytesRead = DWORD(ptr - pbBuffer); + } + CATCH(CFileException, e) + return S_FALSE; + END_CATCH + + return S_OK; +} + +LONGLONG CVTSStream::Size(LONGLONG* pSizeAvailable) +{ + LONGLONG len = 2048i64 * m_vob->GetLength(); + if (pSizeAvailable) { + *pSizeAvailable = len; + } + return len; +} + +DWORD CVTSStream::Alignment() +{ + return 1; +} + +void CVTSStream::Lock() +{ + m_csLock.Lock(); +} + +void CVTSStream::Unlock() +{ + m_csLock.Unlock(); +} + +BSTR CVTSStream::GetTrackName(UINT aTrackIdx) +{ + return m_vob->GetTrackName(aTrackIdx); +} + +int CVTSStream::GetChaptersCount() +{ + return m_vob->GetChaptersCount(); +} + +REFERENCE_TIME CVTSStream::GetChapterOffset(UINT ChapterNumber) +{ + return m_vob->GetChapterOffset(ChapterNumber); +} diff --git a/src/filters/reader/VTSReader/VTSReader.def b/src/filters/reader/VTSReader/VTSReader.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/reader/VTSReader/VTSReader.def +++ b/src/filters/reader/VTSReader/VTSReader.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/reader/VTSReader/VTSReader.h b/src/filters/reader/VTSReader/VTSReader.h index 763f125f3e3..c1a95d08d38 100644 --- a/src/filters/reader/VTSReader/VTSReader.h +++ b/src/filters/reader/VTSReader/VTSReader.h @@ -1,96 +1,96 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "AsyncReader/asyncio.h" -#include "AsyncReader/asyncrdr.h" - -#include "ITrackInfo.h" -#include "../../../DSUtil/DSMPropertyBag.h" - -#define VTSReaderName L"MPC-HC VTS Reader" - -class CVobFile; - -class CVTSStream : public CAsyncStream -{ -private: - CCritSec m_csLock; - - CAutoPtr m_vob; - int m_off; - -public: - CVTSStream(); - virtual ~CVTSStream(); - - bool Load(const WCHAR* fnw); - - HRESULT SetPointer(LONGLONG llPos); - HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); - LONGLONG Size(LONGLONG* pSizeAvailable); - DWORD Alignment(); - void Lock(); - void Unlock(); - - BSTR GetTrackName(UINT aTrackIdx); - int GetChaptersCount(); - REFERENCE_TIME GetChapterOffset(UINT ChapterNumber); -}; - -class __declspec(uuid("773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73")) - CVTSReader - : public CAsyncReader - , public IFileSourceFilter - , public ITrackInfo - , public IDSMChapterBagImpl -{ - CVTSStream m_stream; - CStringW m_fn; - -public: - CVTSReader(IUnknown* pUnk, HRESULT* phr); - ~CVTSReader(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // CBaseFilter - - STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); - - // IFileSourceFilter - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); - - // ITrackInfo - - STDMETHODIMP_(UINT) GetTrackCount(); - STDMETHODIMP_(BOOL) GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill); - STDMETHODIMP_(BOOL) GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill); - STDMETHODIMP_(BSTR) GetTrackName(UINT aTrackIdx); - STDMETHODIMP_(BSTR) GetTrackCodecID(UINT aTrackIdx); - STDMETHODIMP_(BSTR) GetTrackCodecName(UINT aTrackIdx); - STDMETHODIMP_(BSTR) GetTrackCodecInfoURL(UINT aTrackIdx); - STDMETHODIMP_(BSTR) GetTrackCodecDownloadURL(UINT aTrackIdx); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "AsyncReader/asyncio.h" +#include "AsyncReader/asyncrdr.h" + +#include "ITrackInfo.h" +#include "../../../DSUtil/DSMPropertyBag.h" + +#define VTSReaderName L"MPC-HC VTS Reader" + +class CVobFile; + +class CVTSStream : public CAsyncStream +{ +private: + CCritSec m_csLock; + + CAutoPtr m_vob; + int m_off; + +public: + CVTSStream(); + virtual ~CVTSStream(); + + bool Load(const WCHAR* fnw); + + HRESULT SetPointer(LONGLONG llPos); + HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); + LONGLONG Size(LONGLONG* pSizeAvailable); + DWORD Alignment(); + void Lock(); + void Unlock(); + + BSTR GetTrackName(UINT aTrackIdx); + int GetChaptersCount(); + REFERENCE_TIME GetChapterOffset(UINT ChapterNumber); +}; + +class __declspec(uuid("773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73")) + CVTSReader + : public CAsyncReader + , public IFileSourceFilter + , public ITrackInfo + , public IDSMChapterBagImpl +{ + CVTSStream m_stream; + CStringW m_fn; + +public: + CVTSReader(IUnknown* pUnk, HRESULT* phr); + ~CVTSReader(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // CBaseFilter + + STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); + + // IFileSourceFilter + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); + + // ITrackInfo + + STDMETHODIMP_(UINT) GetTrackCount(); + STDMETHODIMP_(BOOL) GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill); + STDMETHODIMP_(BOOL) GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill); + STDMETHODIMP_(BSTR) GetTrackName(UINT aTrackIdx); + STDMETHODIMP_(BSTR) GetTrackCodecID(UINT aTrackIdx); + STDMETHODIMP_(BSTR) GetTrackCodecName(UINT aTrackIdx); + STDMETHODIMP_(BSTR) GetTrackCodecInfoURL(UINT aTrackIdx); + STDMETHODIMP_(BSTR) GetTrackCodecDownloadURL(UINT aTrackIdx); +}; diff --git a/src/filters/reader/VTSReader/VTSReader.rc b/src/filters/reader/VTSReader/VTSReader.rc index e76b362299d..60283ee822d 100644 --- a/src/filters/reader/VTSReader/VTSReader.rc +++ b/src/filters/reader/VTSReader/VTSReader.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "VTS Reader Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "VTS Reader Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "VTSReader.ax" - VALUE "ProductName", "VTS Reader Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "VTS Reader Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "VTS Reader Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "VTSReader.ax" + VALUE "ProductName", "VTS Reader Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/reader/VTSReader/VTSReader.vcxproj b/src/filters/reader/VTSReader/VTSReader.vcxproj index 9f960ef2c06..1c1768bf83a 100644 --- a/src/filters/reader/VTSReader/VTSReader.vcxproj +++ b/src/filters/reader/VTSReader/VTSReader.vcxproj @@ -1,130 +1,130 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {664E726B-EEEE-403A-AC15-345D9C9E1375} - VTSReader - MFCProj - VTSReader - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - VTSReader.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - Create - - - - - - - - - true - - - - - - - true - - - - - {1a2dfd1a-3c6c-44d1-909d-294af646b575} - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {9f31d122-e84d-485a-a58d-09dad01a56ce} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {664E726B-EEEE-403A-AC15-345D9C9E1375} + VTSReader + MFCProj + VTSReader + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + VTSReader.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + Create + + + + + + + + + true + + + + + + + true + + + + + {1a2dfd1a-3c6c-44d1-909d-294af646b575} + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {9f31d122-e84d-485a-a58d-09dad01a56ce} + + + + + \ No newline at end of file diff --git a/src/filters/reader/VTSReader/VTSReader.vcxproj.filters b/src/filters/reader/VTSReader/VTSReader.vcxproj.filters index 1f898d5d80a..68903cdd427 100644 --- a/src/filters/reader/VTSReader/VTSReader.vcxproj.filters +++ b/src/filters/reader/VTSReader/VTSReader.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {6f84c2e5-5b7f-4a7e-8f4b-1f45a45a3078} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {92ae839d-6d37-4f6d-97e5-1e143db42aaf} - h;hpp;hxx;hm;inl;inc - - - {8d71235c-8fc1-4df3-a231-dc67993f1081} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {6f84c2e5-5b7f-4a7e-8f4b-1f45a45a3078} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {92ae839d-6d37-4f6d-97e5-1e143db42aaf} + h;hpp;hxx;hm;inl;inc + + + {8d71235c-8fc1-4df3-a231-dc67993f1081} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/reader/VTSReader/resource.h b/src/filters/reader/VTSReader/resource.h index c9290f108cf..39ae18f4a39 100644 --- a/src/filters/reader/VTSReader/resource.h +++ b/src/filters/reader/VTSReader/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by VTSReader.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by VTSReader.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/reader/VTSReader/stdafx.cpp b/src/filters/reader/VTSReader/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/reader/VTSReader/stdafx.cpp +++ b/src/filters/reader/VTSReader/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/reader/VTSReader/stdafx.h b/src/filters/reader/VTSReader/stdafx.h index 26a845cddf4..d8cc4bd3628 100644 --- a/src/filters/reader/VTSReader/stdafx.h +++ b/src/filters/reader/VTSReader/stdafx.h @@ -1,33 +1,33 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" diff --git a/src/filters/renderer/SyncClock/Interfaces.h b/src/filters/renderer/SyncClock/Interfaces.h index b50c046b2a0..471f9c801c9 100644 --- a/src/filters/renderer/SyncClock/Interfaces.h +++ b/src/filters/renderer/SyncClock/Interfaces.h @@ -1,33 +1,33 @@ -/* - * (C) 2010-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 . - * - */ - -#pragma once - -const IID IID_ISyncClock = {0xa62888fb, 0x8e37, 0x44d2, {0x88, 0x50, 0xb3, 0xe3, 0xf2, 0xc1, 0x16, 0x9f}}; - -MIDL_INTERFACE("A62888FB-8E37-44d2-8850-B3E3F2C1169F") -ISyncClock: -public IUnknown { -public: - STDMETHOD(AdjustClock)(double adjustment) PURE; - STDMETHOD(SetBias)(double bias) PURE; - STDMETHOD(GetBias)(double * bias) PURE; - STDMETHOD(GetStartTime)(REFERENCE_TIME * startTime); -}; +/* + * (C) 2010-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 . + * + */ + +#pragma once + +const IID IID_ISyncClock = {0xa62888fb, 0x8e37, 0x44d2, {0x88, 0x50, 0xb3, 0xe3, 0xf2, 0xc1, 0x16, 0x9f}}; + +MIDL_INTERFACE("A62888FB-8E37-44d2-8850-B3E3F2C1169F") +ISyncClock: +public IUnknown { +public: + STDMETHOD(AdjustClock)(double adjustment) PURE; + STDMETHOD(SetBias)(double bias) PURE; + STDMETHOD(GetBias)(double * bias) PURE; + STDMETHOD(GetStartTime)(REFERENCE_TIME * startTime); +}; diff --git a/src/filters/renderer/SyncClock/SyncClock.cpp b/src/filters/renderer/SyncClock/SyncClock.cpp index 6b2356c0cc3..4e327460c65 100644 --- a/src/filters/renderer/SyncClock/SyncClock.cpp +++ b/src/filters/renderer/SyncClock/SyncClock.cpp @@ -1,120 +1,120 @@ -/* - * (C) 2010-2014 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 . - * - */ - -#include "stdafx.h" -#include "SyncClock.h" - -CSyncClockFilter::CSyncClockFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseFilter(NAME("SyncClock"), nullptr, &m_Lock, CLSID_NULL) - , m_Clock(static_cast(this), phr) -{ -} - -CSyncClockFilter::~CSyncClockFilter() -{ -} - -STDMETHODIMP CSyncClockFilter::AdjustClock(double adjustment) -{ - m_Clock.adjustment = adjustment; - return S_OK; -} - -STDMETHODIMP CSyncClockFilter::SetBias(double bias) -{ - m_Clock.bias = bias; - return S_OK; -} - -STDMETHODIMP CSyncClockFilter::GetBias(double* bias) -{ - *bias = m_Clock.bias; - return S_OK; -} - -STDMETHODIMP CSyncClockFilter::GetStartTime(REFERENCE_TIME* startTime) -{ - *startTime = m_tStart; - return S_OK; -} - -STDMETHODIMP CSyncClockFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - if (riid == IID_IReferenceClock) { - return GetInterface(static_cast(&m_Clock), ppv); - } else if (riid == IID_ISyncClock) { - return GetInterface(static_cast(this), ppv); - } else { - return CBaseFilter::NonDelegatingQueryInterface(riid, ppv); - } -} - -int CSyncClockFilter::GetPinCount() -{ - return 0; -} - -CBasePin* CSyncClockFilter::GetPin(int i) -{ - UNREFERENCED_PARAMETER(i); - return nullptr; -} - -// CSyncClock methods -CSyncClock::CSyncClock(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseReferenceClock(NAME("SyncClock"), pUnk, phr) - , adjustment(1.0) - , bias(1.0) - , m_rtPrivateTime(GetTicks100ns()) - , m_llPerfFrequency(0) - , m_rtPrevTime(m_rtPrivateTime) - , m_pCurrentRefClock(0) - , m_pPrevRefClock(0) -{ - QueryPerformanceFrequency((LARGE_INTEGER*)&m_llPerfFrequency); -} - -REFERENCE_TIME CSyncClock::GetPrivateTime() -{ - CAutoLock cObjectLock(this); - - REFERENCE_TIME rtTime = GetTicks100ns(); - - REFERENCE_TIME delta = rtTime - m_rtPrevTime; - // We ignore that rtTime may wrap around. Not gonna happen too often - m_rtPrevTime = rtTime; - - delta = (REFERENCE_TIME)((double)delta * adjustment * bias); - m_rtPrivateTime = m_rtPrivateTime + delta; - return m_rtPrivateTime; -} - -REFERENCE_TIME CSyncClock::GetTicks100ns() -{ - LONGLONG i64Ticks100ns; - if (m_llPerfFrequency != 0) { - QueryPerformanceCounter((LARGE_INTEGER*)&i64Ticks100ns); - i64Ticks100ns = LONGLONG((double(i64Ticks100ns) * 10000000) / double(m_llPerfFrequency) + 0.5); - return (REFERENCE_TIME)i64Ticks100ns; - } - return 0; -} +/* + * (C) 2010-2014 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 . + * + */ + +#include "stdafx.h" +#include "SyncClock.h" + +CSyncClockFilter::CSyncClockFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseFilter(NAME("SyncClock"), nullptr, &m_Lock, CLSID_NULL) + , m_Clock(static_cast(this), phr) +{ +} + +CSyncClockFilter::~CSyncClockFilter() +{ +} + +STDMETHODIMP CSyncClockFilter::AdjustClock(double adjustment) +{ + m_Clock.adjustment = adjustment; + return S_OK; +} + +STDMETHODIMP CSyncClockFilter::SetBias(double bias) +{ + m_Clock.bias = bias; + return S_OK; +} + +STDMETHODIMP CSyncClockFilter::GetBias(double* bias) +{ + *bias = m_Clock.bias; + return S_OK; +} + +STDMETHODIMP CSyncClockFilter::GetStartTime(REFERENCE_TIME* startTime) +{ + *startTime = m_tStart; + return S_OK; +} + +STDMETHODIMP CSyncClockFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + if (riid == IID_IReferenceClock) { + return GetInterface(static_cast(&m_Clock), ppv); + } else if (riid == IID_ISyncClock) { + return GetInterface(static_cast(this), ppv); + } else { + return CBaseFilter::NonDelegatingQueryInterface(riid, ppv); + } +} + +int CSyncClockFilter::GetPinCount() +{ + return 0; +} + +CBasePin* CSyncClockFilter::GetPin(int i) +{ + UNREFERENCED_PARAMETER(i); + return nullptr; +} + +// CSyncClock methods +CSyncClock::CSyncClock(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseReferenceClock(NAME("SyncClock"), pUnk, phr) + , adjustment(1.0) + , bias(1.0) + , m_rtPrivateTime(GetTicks100ns()) + , m_llPerfFrequency(0) + , m_rtPrevTime(m_rtPrivateTime) + , m_pCurrentRefClock(0) + , m_pPrevRefClock(0) +{ + QueryPerformanceFrequency((LARGE_INTEGER*)&m_llPerfFrequency); +} + +REFERENCE_TIME CSyncClock::GetPrivateTime() +{ + CAutoLock cObjectLock(this); + + REFERENCE_TIME rtTime = GetTicks100ns(); + + REFERENCE_TIME delta = rtTime - m_rtPrevTime; + // We ignore that rtTime may wrap around. Not gonna happen too often + m_rtPrevTime = rtTime; + + delta = (REFERENCE_TIME)((double)delta * adjustment * bias); + m_rtPrivateTime = m_rtPrivateTime + delta; + return m_rtPrivateTime; +} + +REFERENCE_TIME CSyncClock::GetTicks100ns() +{ + LONGLONG i64Ticks100ns; + if (m_llPerfFrequency != 0) { + QueryPerformanceCounter((LARGE_INTEGER*)&i64Ticks100ns); + i64Ticks100ns = LONGLONG((double(i64Ticks100ns) * 10000000) / double(m_llPerfFrequency) + 0.5); + return (REFERENCE_TIME)i64Ticks100ns; + } + return 0; +} diff --git a/src/filters/renderer/SyncClock/SyncClock.h b/src/filters/renderer/SyncClock/SyncClock.h index 40be493e985..3d1ff252ddd 100644 --- a/src/filters/renderer/SyncClock/SyncClock.h +++ b/src/filters/renderer/SyncClock/SyncClock.h @@ -1,71 +1,71 @@ -/* - * (C) 2010-2013, 2016 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 . - * - */ - -#pragma once - -#include "Interfaces.h" - -class CSyncClockFilter; - -class CSyncClock: public CBaseReferenceClock -{ - friend class CSyncClockFilter; -public: - CSyncClock(LPUNKNOWN pUnk, HRESULT* phr); - - REFERENCE_TIME GetPrivateTime(); - IUnknown* pUnk() { return static_cast(static_cast(this)); } - double adjustment; // For adjusting speed temporarily - double bias; // For changing speed permanently - -private: - REFERENCE_TIME m_rtPrivateTime; - LONGLONG m_llPerfFrequency; - REFERENCE_TIME m_rtPrevTime; - CCritSec m_csClock; - IReferenceClock* m_pCurrentRefClock; - IReferenceClock* m_pPrevRefClock; - REFERENCE_TIME GetTicks100ns(); -}; - -class __declspec(uuid("57797fe5-ee9b-4408-98a9-20b134e7e8f0")) - CSyncClockFilter: public ISyncClock, public CBaseFilter -{ -public: - CSyncClockFilter(LPUNKNOWN pUnk, HRESULT* phr); - virtual ~CSyncClockFilter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISyncClock - STDMETHODIMP AdjustClock(double adjustment); - STDMETHODIMP SetBias(double bias); - STDMETHODIMP GetBias(double* bias); - STDMETHODIMP GetStartTime(REFERENCE_TIME* startTime); - - // CBaseFilter methods - int GetPinCount(); - CBasePin* GetPin(int iPin); - -private: - CSyncClock m_Clock; - CCritSec m_Lock; -}; +/* + * (C) 2010-2013, 2016 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 . + * + */ + +#pragma once + +#include "Interfaces.h" + +class CSyncClockFilter; + +class CSyncClock: public CBaseReferenceClock +{ + friend class CSyncClockFilter; +public: + CSyncClock(LPUNKNOWN pUnk, HRESULT* phr); + + REFERENCE_TIME GetPrivateTime(); + IUnknown* pUnk() { return static_cast(static_cast(this)); } + double adjustment; // For adjusting speed temporarily + double bias; // For changing speed permanently + +private: + REFERENCE_TIME m_rtPrivateTime; + LONGLONG m_llPerfFrequency; + REFERENCE_TIME m_rtPrevTime; + CCritSec m_csClock; + IReferenceClock* m_pCurrentRefClock; + IReferenceClock* m_pPrevRefClock; + REFERENCE_TIME GetTicks100ns(); +}; + +class __declspec(uuid("57797fe5-ee9b-4408-98a9-20b134e7e8f0")) + CSyncClockFilter: public ISyncClock, public CBaseFilter +{ +public: + CSyncClockFilter(LPUNKNOWN pUnk, HRESULT* phr); + virtual ~CSyncClockFilter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISyncClock + STDMETHODIMP AdjustClock(double adjustment); + STDMETHODIMP SetBias(double bias); + STDMETHODIMP GetBias(double* bias); + STDMETHODIMP GetStartTime(REFERENCE_TIME* startTime); + + // CBaseFilter methods + int GetPinCount(); + CBasePin* GetPin(int iPin); + +private: + CSyncClock m_Clock; + CCritSec m_Lock; +}; diff --git a/src/filters/renderer/SyncClock/SyncClock.vcxproj b/src/filters/renderer/SyncClock/SyncClock.vcxproj index 2d0e93dd6ec..3709dcc5908 100644 --- a/src/filters/renderer/SyncClock/SyncClock.vcxproj +++ b/src/filters/renderer/SyncClock/SyncClock.vcxproj @@ -1,62 +1,62 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {0B63409D-674D-47F8-A84E-87DBB7783189} - SyncClock - MFCProj - SyncClock - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - Create - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0B63409D-674D-47F8-A84E-87DBB7783189} + SyncClock + MFCProj + SyncClock + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + Create + + + + + + + + + + + \ No newline at end of file diff --git a/src/filters/renderer/SyncClock/SyncClock.vcxproj.filters b/src/filters/renderer/SyncClock/SyncClock.vcxproj.filters index 0703860a34c..fcaaa752862 100644 --- a/src/filters/renderer/SyncClock/SyncClock.vcxproj.filters +++ b/src/filters/renderer/SyncClock/SyncClock.vcxproj.filters @@ -1,32 +1,32 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/renderer/SyncClock/stdafx.cpp b/src/filters/renderer/SyncClock/stdafx.cpp index 42728ce2ef5..3bf3e3572f9 100644 --- a/src/filters/renderer/SyncClock/stdafx.cpp +++ b/src/filters/renderer/SyncClock/stdafx.cpp @@ -1,21 +1,21 @@ -/* - * (C) 2009-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 . - * - */ - -#include "stdafx.h" +/* + * (C) 2009-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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/renderer/SyncClock/stdafx.h b/src/filters/renderer/SyncClock/stdafx.h index b0b8d199896..1a049dcf932 100644 --- a/src/filters/renderer/SyncClock/stdafx.h +++ b/src/filters/renderer/SyncClock/stdafx.h @@ -1,32 +1,32 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp b/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp index aece023177e..5622d203158 100644 --- a/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp +++ b/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp @@ -1,321 +1,321 @@ -/* - * (C) 2006-2013, 2016 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 . - * - */ - -#include "stdafx.h" -#include "AllocatorCommon.h" -#include "../DSUtil/DSUtil.h" - -#include "VMR9AllocatorPresenter.h" -#include "DXRAllocatorPresenter.h" -#include "madVRAllocatorPresenter.h" -#include "EVRAllocatorPresenter.h" -#include "MPCVRAllocatorPresenter.h" - -bool IsVMR9InGraph(IFilterGraph* pFG) -{ - BeginEnumFilters(pFG, pEF, pBF); - if (CComQIPtr(pBF)) { - return true; - } - EndEnumFilters; - return false; -} - -// - -HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP) -{ - CheckPointer(ppAP, E_POINTER); - - *ppAP = nullptr; - - using namespace DSObjects; - - HRESULT hr = E_FAIL; - CString Error; - - if (IsEqualCLSID(clsid, CLSID_VMR9AllocatorPresenter)) { - *ppAP = DEBUG_NEW CVMR9AllocatorPresenter(hWnd, bFullscreen, hr, Error); - } else if (IsEqualCLSID(clsid, CLSID_DXRAllocatorPresenter)) { - *ppAP = DEBUG_NEW CDXRAllocatorPresenter(hWnd, hr, Error); - } else if (IsEqualCLSID(clsid, CLSID_madVRAllocatorPresenter)) { - *ppAP = DEBUG_NEW CmadVRAllocatorPresenter(hWnd, hr, Error); - } else if (IsEqualCLSID(clsid, CLSID_MPCVRAllocatorPresenter)) { - *ppAP = DEBUG_NEW CMPCVRAllocatorPresenter(hWnd, hr, Error); - } else { - return E_FAIL; - } - - if (*ppAP == nullptr) { - return E_OUTOFMEMORY; - } - - (*ppAP)->AddRef(); - - if (FAILED(hr)) { - Error += L"\n"; - Error += GetWindowsErrorMessage(hr, nullptr); - - MessageBox(hWnd, Error, L"Error creating DX9 allocation presenter", MB_OK | MB_ICONERROR); - (*ppAP)->Release(); - *ppAP = nullptr; - } else if (!Error.IsEmpty()) { - MessageBox(hWnd, Error, L"Warning creating DX9 allocation presenter", MB_OK | MB_ICONWARNING); - } - - return hr; -} - -HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP, bool isPreview) -{ - HRESULT hr = E_FAIL; - if (clsid == CLSID_EVRAllocatorPresenter) { - CString Error; - *ppAP = DEBUG_NEW DSObjects::CEVRAllocatorPresenter(hWnd, bFullscreen, hr, Error, isPreview); - if (*ppAP == nullptr) { - return E_OUTOFMEMORY; - } - (*ppAP)->AddRef(); - - if (FAILED(hr)) { - Error += L"\n"; - Error += GetWindowsErrorMessage(hr, nullptr); - MessageBox(hWnd, Error, L"Error creating EVR Custom renderer", MB_OK | MB_ICONERROR); - (*ppAP)->Release(); - *ppAP = nullptr; - } else if (!Error.IsEmpty()) { - MessageBox(hWnd, Error, L"Warning creating EVR Custom renderer", MB_OK | MB_ICONWARNING); - } - - } - - return hr; -} - -CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module) -{ - - switch (_Error) { - case D3DERR_WRONGTEXTUREFORMAT: - return _T("D3DERR_WRONGTEXTUREFORMAT"); - case D3DERR_UNSUPPORTEDCOLOROPERATION: - return _T("D3DERR_UNSUPPORTEDCOLOROPERATION"); - case D3DERR_UNSUPPORTEDCOLORARG: - return _T("D3DERR_UNSUPPORTEDCOLORARG"); - case D3DERR_UNSUPPORTEDALPHAOPERATION: - return _T("D3DERR_UNSUPPORTEDALPHAOPERATION"); - case D3DERR_UNSUPPORTEDALPHAARG: - return _T("D3DERR_UNSUPPORTEDALPHAARG"); - case D3DERR_TOOMANYOPERATIONS: - return _T("D3DERR_TOOMANYOPERATIONS"); - case D3DERR_CONFLICTINGTEXTUREFILTER: - return _T("D3DERR_CONFLICTINGTEXTUREFILTER"); - case D3DERR_UNSUPPORTEDFACTORVALUE: - return _T("D3DERR_UNSUPPORTEDFACTORVALUE"); - case D3DERR_CONFLICTINGRENDERSTATE: - return _T("D3DERR_CONFLICTINGRENDERSTATE"); - case D3DERR_UNSUPPORTEDTEXTUREFILTER: - return _T("D3DERR_UNSUPPORTEDTEXTUREFILTER"); - case D3DERR_CONFLICTINGTEXTUREPALETTE: - return _T("D3DERR_CONFLICTINGTEXTUREPALETTE"); - case D3DERR_DRIVERINTERNALERROR: - return _T("D3DERR_DRIVERINTERNALERROR"); - case D3DERR_NOTFOUND: - return _T("D3DERR_NOTFOUND"); - case D3DERR_MOREDATA: - return _T("D3DERR_MOREDATA"); - case D3DERR_DEVICELOST: - return _T("D3DERR_DEVICELOST"); - case D3DERR_DEVICENOTRESET: - return _T("D3DERR_DEVICENOTRESET"); - case D3DERR_NOTAVAILABLE: - return _T("D3DERR_NOTAVAILABLE"); - case D3DERR_OUTOFVIDEOMEMORY: - return _T("D3DERR_OUTOFVIDEOMEMORY"); - case D3DERR_INVALIDDEVICE: - return _T("D3DERR_INVALIDDEVICE"); - case D3DERR_INVALIDCALL: - return _T("D3DERR_INVALIDCALL"); - case D3DERR_DRIVERINVALIDCALL: - return _T("D3DERR_DRIVERINVALIDCALL"); - case D3DERR_WASSTILLDRAWING: - return _T("D3DERR_WASSTILLDRAWING"); - case D3DOK_NOAUTOGEN: - return _T("D3DOK_NOAUTOGEN"); - case D3DERR_DEVICEREMOVED: - return _T("D3DERR_DEVICEREMOVED"); - case S_NOT_RESIDENT: - return _T("S_NOT_RESIDENT"); - case S_RESIDENT_IN_SHARED_MEMORY: - return _T("S_RESIDENT_IN_SHARED_MEMORY"); - case S_PRESENT_MODE_CHANGED: - return _T("S_PRESENT_MODE_CHANGED"); - case S_PRESENT_OCCLUDED: - return _T("S_PRESENT_OCCLUDED"); - case D3DERR_DEVICEHUNG: - return _T("D3DERR_DEVICEHUNG"); - case E_UNEXPECTED: - return _T("E_UNEXPECTED"); - } - - CString errmsg; - LPVOID lpMsgBuf; - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, - _Module, _Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, nullptr)) { - errmsg = (LPCTSTR)lpMsgBuf; - LocalFree(lpMsgBuf); - } - CString Temp; - Temp.Format(L"0x%08lx ", _Error); - return Temp + errmsg; -} - -const wchar_t* GetD3DFormatStr(D3DFORMAT Format) -{ - switch (Format) { - case D3DFMT_R8G8B8: - return L"R8G8B8"; - case D3DFMT_A8R8G8B8: - return L"A8R8G8B8"; - case D3DFMT_X8R8G8B8: - return L"X8R8G8B8"; - case D3DFMT_R5G6B5: - return L"R5G6B5"; - case D3DFMT_X1R5G5B5: - return L"X1R5G5B5"; - case D3DFMT_A1R5G5B5: - return L"A1R5G5B5"; - case D3DFMT_A4R4G4B4: - return L"A4R4G4B4"; - case D3DFMT_R3G3B2: - return L"R3G3B2"; - case D3DFMT_A8: - return L"A8"; - case D3DFMT_A8R3G3B2: - return L"A8R3G3B2"; - case D3DFMT_X4R4G4B4: - return L"X4R4G4B4"; - case D3DFMT_A2B10G10R10: - return L"A2B10G10R10"; - case D3DFMT_A8B8G8R8: - return L"A8B8G8R8"; - case D3DFMT_X8B8G8R8: - return L"X8B8G8R8"; - case D3DFMT_G16R16: - return L"G16R16"; - case D3DFMT_A2R10G10B10: - return L"A2R10G10B10"; - case D3DFMT_A16B16G16R16: - return L"A16B16G16R16"; - case D3DFMT_A8P8: - return L"A8P8"; - case D3DFMT_P8: - return L"P8"; - case D3DFMT_L8: - return L"L8"; - case D3DFMT_A8L8: - return L"A8L8"; - case D3DFMT_A4L4: - return L"A4L4"; - case D3DFMT_V8U8: - return L"V8U8"; - case D3DFMT_L6V5U5: - return L"L6V5U5"; - case D3DFMT_X8L8V8U8: - return L"X8L8V8U8"; - case D3DFMT_Q8W8V8U8: - return L"Q8W8V8U8"; - case D3DFMT_V16U16: - return L"V16U16"; - case D3DFMT_A2W10V10U10: - return L"A2W10V10U10"; - case D3DFMT_UYVY: - return L"UYVY"; - case D3DFMT_R8G8_B8G8: - return L"R8G8_B8G8"; - case D3DFMT_YUY2: - return L"YUY2"; - case D3DFMT_G8R8_G8B8: - return L"G8R8_G8B8"; - case D3DFMT_DXT1: - return L"DXT1"; - case D3DFMT_DXT2: - return L"DXT2"; - case D3DFMT_DXT3: - return L"DXT3"; - case D3DFMT_DXT4: - return L"DXT4"; - case D3DFMT_DXT5: - return L"DXT5"; - case D3DFMT_D16_LOCKABLE: - return L"D16_LOCKABLE"; - case D3DFMT_D32: - return L"D32"; - case D3DFMT_D15S1: - return L"D15S1"; - case D3DFMT_D24S8: - return L"D24S8"; - case D3DFMT_D24X8: - return L"D24X8"; - case D3DFMT_D24X4S4: - return L"D24X4S4"; - case D3DFMT_D16: - return L"D16"; - case D3DFMT_D32F_LOCKABLE: - return L"D32F_LOCKABLE"; - case D3DFMT_D24FS8: - return L"D24FS8"; - case D3DFMT_D32_LOCKABLE: - return L"D32_LOCKABLE"; - case D3DFMT_S8_LOCKABLE: - return L"S8_LOCKABLE"; - case D3DFMT_L16: - return L"L16"; - case D3DFMT_VERTEXDATA: - return L"VERTEXDATA"; - case D3DFMT_INDEX16: - return L"INDEX16"; - case D3DFMT_INDEX32: - return L"INDEX32"; - case D3DFMT_Q16W16V16U16: - return L"Q16W16V16U16"; - case D3DFMT_MULTI2_ARGB8: - return L"MULTI2_ARGB8"; - case D3DFMT_R16F: - return L"R16F"; - case D3DFMT_G16R16F: - return L"G16R16F"; - case D3DFMT_A16B16G16R16F: - return L"A16B16G16R16F"; - case D3DFMT_R32F: - return L"R32F"; - case D3DFMT_G32R32F: - return L"G32R32F"; - case D3DFMT_A32B32G32R32F: - return L"A32B32G32R32F"; - case D3DFMT_CxV8U8: - return L"CxV8U8"; - case D3DFMT_A1: - return L"A1"; - case D3DFMT_BINARYBUFFER: - return L"BINARYBUFFER"; - } - return L"Unknown"; -} +/* + * (C) 2006-2013, 2016 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 . + * + */ + +#include "stdafx.h" +#include "AllocatorCommon.h" +#include "../DSUtil/DSUtil.h" + +#include "VMR9AllocatorPresenter.h" +#include "DXRAllocatorPresenter.h" +#include "madVRAllocatorPresenter.h" +#include "EVRAllocatorPresenter.h" +#include "MPCVRAllocatorPresenter.h" + +bool IsVMR9InGraph(IFilterGraph* pFG) +{ + BeginEnumFilters(pFG, pEF, pBF); + if (CComQIPtr(pBF)) { + return true; + } + EndEnumFilters; + return false; +} + +// + +HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP) +{ + CheckPointer(ppAP, E_POINTER); + + *ppAP = nullptr; + + using namespace DSObjects; + + HRESULT hr = E_FAIL; + CString Error; + + if (IsEqualCLSID(clsid, CLSID_VMR9AllocatorPresenter)) { + *ppAP = DEBUG_NEW CVMR9AllocatorPresenter(hWnd, bFullscreen, hr, Error); + } else if (IsEqualCLSID(clsid, CLSID_DXRAllocatorPresenter)) { + *ppAP = DEBUG_NEW CDXRAllocatorPresenter(hWnd, hr, Error); + } else if (IsEqualCLSID(clsid, CLSID_madVRAllocatorPresenter)) { + *ppAP = DEBUG_NEW CmadVRAllocatorPresenter(hWnd, hr, Error); + } else if (IsEqualCLSID(clsid, CLSID_MPCVRAllocatorPresenter)) { + *ppAP = DEBUG_NEW CMPCVRAllocatorPresenter(hWnd, hr, Error); + } else { + return E_FAIL; + } + + if (*ppAP == nullptr) { + return E_OUTOFMEMORY; + } + + (*ppAP)->AddRef(); + + if (FAILED(hr)) { + Error += L"\n"; + Error += GetWindowsErrorMessage(hr, nullptr); + + MessageBox(hWnd, Error, L"Error creating DX9 allocation presenter", MB_OK | MB_ICONERROR); + (*ppAP)->Release(); + *ppAP = nullptr; + } else if (!Error.IsEmpty()) { + MessageBox(hWnd, Error, L"Warning creating DX9 allocation presenter", MB_OK | MB_ICONWARNING); + } + + return hr; +} + +HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP, bool isPreview) +{ + HRESULT hr = E_FAIL; + if (clsid == CLSID_EVRAllocatorPresenter) { + CString Error; + *ppAP = DEBUG_NEW DSObjects::CEVRAllocatorPresenter(hWnd, bFullscreen, hr, Error, isPreview); + if (*ppAP == nullptr) { + return E_OUTOFMEMORY; + } + (*ppAP)->AddRef(); + + if (FAILED(hr)) { + Error += L"\n"; + Error += GetWindowsErrorMessage(hr, nullptr); + MessageBox(hWnd, Error, L"Error creating EVR Custom renderer", MB_OK | MB_ICONERROR); + (*ppAP)->Release(); + *ppAP = nullptr; + } else if (!Error.IsEmpty()) { + MessageBox(hWnd, Error, L"Warning creating EVR Custom renderer", MB_OK | MB_ICONWARNING); + } + + } + + return hr; +} + +CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module) +{ + + switch (_Error) { + case D3DERR_WRONGTEXTUREFORMAT: + return _T("D3DERR_WRONGTEXTUREFORMAT"); + case D3DERR_UNSUPPORTEDCOLOROPERATION: + return _T("D3DERR_UNSUPPORTEDCOLOROPERATION"); + case D3DERR_UNSUPPORTEDCOLORARG: + return _T("D3DERR_UNSUPPORTEDCOLORARG"); + case D3DERR_UNSUPPORTEDALPHAOPERATION: + return _T("D3DERR_UNSUPPORTEDALPHAOPERATION"); + case D3DERR_UNSUPPORTEDALPHAARG: + return _T("D3DERR_UNSUPPORTEDALPHAARG"); + case D3DERR_TOOMANYOPERATIONS: + return _T("D3DERR_TOOMANYOPERATIONS"); + case D3DERR_CONFLICTINGTEXTUREFILTER: + return _T("D3DERR_CONFLICTINGTEXTUREFILTER"); + case D3DERR_UNSUPPORTEDFACTORVALUE: + return _T("D3DERR_UNSUPPORTEDFACTORVALUE"); + case D3DERR_CONFLICTINGRENDERSTATE: + return _T("D3DERR_CONFLICTINGRENDERSTATE"); + case D3DERR_UNSUPPORTEDTEXTUREFILTER: + return _T("D3DERR_UNSUPPORTEDTEXTUREFILTER"); + case D3DERR_CONFLICTINGTEXTUREPALETTE: + return _T("D3DERR_CONFLICTINGTEXTUREPALETTE"); + case D3DERR_DRIVERINTERNALERROR: + return _T("D3DERR_DRIVERINTERNALERROR"); + case D3DERR_NOTFOUND: + return _T("D3DERR_NOTFOUND"); + case D3DERR_MOREDATA: + return _T("D3DERR_MOREDATA"); + case D3DERR_DEVICELOST: + return _T("D3DERR_DEVICELOST"); + case D3DERR_DEVICENOTRESET: + return _T("D3DERR_DEVICENOTRESET"); + case D3DERR_NOTAVAILABLE: + return _T("D3DERR_NOTAVAILABLE"); + case D3DERR_OUTOFVIDEOMEMORY: + return _T("D3DERR_OUTOFVIDEOMEMORY"); + case D3DERR_INVALIDDEVICE: + return _T("D3DERR_INVALIDDEVICE"); + case D3DERR_INVALIDCALL: + return _T("D3DERR_INVALIDCALL"); + case D3DERR_DRIVERINVALIDCALL: + return _T("D3DERR_DRIVERINVALIDCALL"); + case D3DERR_WASSTILLDRAWING: + return _T("D3DERR_WASSTILLDRAWING"); + case D3DOK_NOAUTOGEN: + return _T("D3DOK_NOAUTOGEN"); + case D3DERR_DEVICEREMOVED: + return _T("D3DERR_DEVICEREMOVED"); + case S_NOT_RESIDENT: + return _T("S_NOT_RESIDENT"); + case S_RESIDENT_IN_SHARED_MEMORY: + return _T("S_RESIDENT_IN_SHARED_MEMORY"); + case S_PRESENT_MODE_CHANGED: + return _T("S_PRESENT_MODE_CHANGED"); + case S_PRESENT_OCCLUDED: + return _T("S_PRESENT_OCCLUDED"); + case D3DERR_DEVICEHUNG: + return _T("D3DERR_DEVICEHUNG"); + case E_UNEXPECTED: + return _T("E_UNEXPECTED"); + } + + CString errmsg; + LPVOID lpMsgBuf; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, + _Module, _Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, nullptr)) { + errmsg = (LPCTSTR)lpMsgBuf; + LocalFree(lpMsgBuf); + } + CString Temp; + Temp.Format(L"0x%08lx ", _Error); + return Temp + errmsg; +} + +const wchar_t* GetD3DFormatStr(D3DFORMAT Format) +{ + switch (Format) { + case D3DFMT_R8G8B8: + return L"R8G8B8"; + case D3DFMT_A8R8G8B8: + return L"A8R8G8B8"; + case D3DFMT_X8R8G8B8: + return L"X8R8G8B8"; + case D3DFMT_R5G6B5: + return L"R5G6B5"; + case D3DFMT_X1R5G5B5: + return L"X1R5G5B5"; + case D3DFMT_A1R5G5B5: + return L"A1R5G5B5"; + case D3DFMT_A4R4G4B4: + return L"A4R4G4B4"; + case D3DFMT_R3G3B2: + return L"R3G3B2"; + case D3DFMT_A8: + return L"A8"; + case D3DFMT_A8R3G3B2: + return L"A8R3G3B2"; + case D3DFMT_X4R4G4B4: + return L"X4R4G4B4"; + case D3DFMT_A2B10G10R10: + return L"A2B10G10R10"; + case D3DFMT_A8B8G8R8: + return L"A8B8G8R8"; + case D3DFMT_X8B8G8R8: + return L"X8B8G8R8"; + case D3DFMT_G16R16: + return L"G16R16"; + case D3DFMT_A2R10G10B10: + return L"A2R10G10B10"; + case D3DFMT_A16B16G16R16: + return L"A16B16G16R16"; + case D3DFMT_A8P8: + return L"A8P8"; + case D3DFMT_P8: + return L"P8"; + case D3DFMT_L8: + return L"L8"; + case D3DFMT_A8L8: + return L"A8L8"; + case D3DFMT_A4L4: + return L"A4L4"; + case D3DFMT_V8U8: + return L"V8U8"; + case D3DFMT_L6V5U5: + return L"L6V5U5"; + case D3DFMT_X8L8V8U8: + return L"X8L8V8U8"; + case D3DFMT_Q8W8V8U8: + return L"Q8W8V8U8"; + case D3DFMT_V16U16: + return L"V16U16"; + case D3DFMT_A2W10V10U10: + return L"A2W10V10U10"; + case D3DFMT_UYVY: + return L"UYVY"; + case D3DFMT_R8G8_B8G8: + return L"R8G8_B8G8"; + case D3DFMT_YUY2: + return L"YUY2"; + case D3DFMT_G8R8_G8B8: + return L"G8R8_G8B8"; + case D3DFMT_DXT1: + return L"DXT1"; + case D3DFMT_DXT2: + return L"DXT2"; + case D3DFMT_DXT3: + return L"DXT3"; + case D3DFMT_DXT4: + return L"DXT4"; + case D3DFMT_DXT5: + return L"DXT5"; + case D3DFMT_D16_LOCKABLE: + return L"D16_LOCKABLE"; + case D3DFMT_D32: + return L"D32"; + case D3DFMT_D15S1: + return L"D15S1"; + case D3DFMT_D24S8: + return L"D24S8"; + case D3DFMT_D24X8: + return L"D24X8"; + case D3DFMT_D24X4S4: + return L"D24X4S4"; + case D3DFMT_D16: + return L"D16"; + case D3DFMT_D32F_LOCKABLE: + return L"D32F_LOCKABLE"; + case D3DFMT_D24FS8: + return L"D24FS8"; + case D3DFMT_D32_LOCKABLE: + return L"D32_LOCKABLE"; + case D3DFMT_S8_LOCKABLE: + return L"S8_LOCKABLE"; + case D3DFMT_L16: + return L"L16"; + case D3DFMT_VERTEXDATA: + return L"VERTEXDATA"; + case D3DFMT_INDEX16: + return L"INDEX16"; + case D3DFMT_INDEX32: + return L"INDEX32"; + case D3DFMT_Q16W16V16U16: + return L"Q16W16V16U16"; + case D3DFMT_MULTI2_ARGB8: + return L"MULTI2_ARGB8"; + case D3DFMT_R16F: + return L"R16F"; + case D3DFMT_G16R16F: + return L"G16R16F"; + case D3DFMT_A16B16G16R16F: + return L"A16B16G16R16F"; + case D3DFMT_R32F: + return L"R32F"; + case D3DFMT_G32R32F: + return L"G32R32F"; + case D3DFMT_A32B32G32R32F: + return L"A32B32G32R32F"; + case D3DFMT_CxV8U8: + return L"CxV8U8"; + case D3DFMT_A1: + return L"A1"; + case D3DFMT_BINARYBUFFER: + return L"BINARYBUFFER"; + } + return L"Unknown"; +} diff --git a/src/filters/renderer/VideoRenderers/AllocatorCommon.h b/src/filters/renderer/VideoRenderers/AllocatorCommon.h index a58e7a37a2b..78b89480957 100644 --- a/src/filters/renderer/VideoRenderers/AllocatorCommon.h +++ b/src/filters/renderer/VideoRenderers/AllocatorCommon.h @@ -1,61 +1,61 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include -#include "../../../SubPic/ISubPic.h" -#include "PixelShaderCompiler.h" - -// {4E4834FA-22C2-40e2-9446-F77DD05D245E} -DEFINE_GUID(CLSID_VMR9AllocatorPresenter, - 0x4e4834fa, 0x22c2, 0x40e2, 0x94, 0x46, 0xf7, 0x7d, 0xd0, 0x5d, 0x24, 0x5e); - -// {B72EBDD4-831D-440f-A656-B48F5486CD82} -DEFINE_GUID(CLSID_DXRAllocatorPresenter, - 0xb72ebdd4, 0x831d, 0x440f, 0xa6, 0x56, 0xb4, 0x8f, 0x54, 0x86, 0xcd, 0x82); - -// {C7ED3100-9002-4595-9DCA-B30B30413429} -DEFINE_GUID(CLSID_madVRAllocatorPresenter, - 0xc7ed3100, 0x9002, 0x4595, 0x9d, 0xca, 0xb3, 0xb, 0x30, 0x41, 0x34, 0x29); - -DEFINE_GUID(CLSID_MPCVRAllocatorPresenter, - 0x28789E29, 0x5BDD, 0x4374, 0xAD, 0xEC, 0xAB, 0x2E, 0xB9, 0x21, 0x2C, 0x0D); - -DEFINE_GUID(CLSID_EVRAllocatorPresenter, - 0x7612b889, 0xe070, 0x4bcc, 0xb8, 0x8, 0x91, 0xcb, 0x79, 0x41, 0x74, 0xab); - -extern bool IsVMR9InGraph(IFilterGraph* pFG); -extern CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module); -extern const wchar_t* GetD3DFormatStr(D3DFORMAT Format); - -extern HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP); -extern HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP, bool isPreview = false); - -// Set and query D3DFullscreen mode. -interface __declspec(uuid("8EA1E899-B77D-4777-9F0E-66421BEA50F8")) - ID3DFullscreenControl : - public IUnknown -{ - STDMETHOD(SetD3DFullscreen)(bool fEnabled) PURE; - STDMETHOD(GetD3DFullscreen)(bool* pfEnabled) PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include +#include "../../../SubPic/ISubPic.h" +#include "PixelShaderCompiler.h" + +// {4E4834FA-22C2-40e2-9446-F77DD05D245E} +DEFINE_GUID(CLSID_VMR9AllocatorPresenter, + 0x4e4834fa, 0x22c2, 0x40e2, 0x94, 0x46, 0xf7, 0x7d, 0xd0, 0x5d, 0x24, 0x5e); + +// {B72EBDD4-831D-440f-A656-B48F5486CD82} +DEFINE_GUID(CLSID_DXRAllocatorPresenter, + 0xb72ebdd4, 0x831d, 0x440f, 0xa6, 0x56, 0xb4, 0x8f, 0x54, 0x86, 0xcd, 0x82); + +// {C7ED3100-9002-4595-9DCA-B30B30413429} +DEFINE_GUID(CLSID_madVRAllocatorPresenter, + 0xc7ed3100, 0x9002, 0x4595, 0x9d, 0xca, 0xb3, 0xb, 0x30, 0x41, 0x34, 0x29); + +DEFINE_GUID(CLSID_MPCVRAllocatorPresenter, + 0x28789E29, 0x5BDD, 0x4374, 0xAD, 0xEC, 0xAB, 0x2E, 0xB9, 0x21, 0x2C, 0x0D); + +DEFINE_GUID(CLSID_EVRAllocatorPresenter, + 0x7612b889, 0xe070, 0x4bcc, 0xb8, 0x8, 0x91, 0xcb, 0x79, 0x41, 0x74, 0xab); + +extern bool IsVMR9InGraph(IFilterGraph* pFG); +extern CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module); +extern const wchar_t* GetD3DFormatStr(D3DFORMAT Format); + +extern HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP); +extern HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP, bool isPreview = false); + +// Set and query D3DFullscreen mode. +interface __declspec(uuid("8EA1E899-B77D-4777-9F0E-66421BEA50F8")) + ID3DFullscreenControl : + public IUnknown +{ + STDMETHOD(SetD3DFullscreen)(bool fEnabled) PURE; + STDMETHOD(GetD3DFullscreen)(bool* pfEnabled) PURE; +}; diff --git a/src/filters/renderer/VideoRenderers/D3DFont.cpp b/src/filters/renderer/VideoRenderers/D3DFont.cpp index 901dc32d762..af6551b65d2 100644 --- a/src/filters/renderer/VideoRenderers/D3DFont.cpp +++ b/src/filters/renderer/VideoRenderers/D3DFont.cpp @@ -1,877 +1,877 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include -#include -#include "d3dx9/d3dx9.h" -#include "D3DFont.h" -#include "../../../DSUtil/DSUtil.h" - -//----------------------------------------------------------------------------- -// Custom vertex types for rendering text -//----------------------------------------------------------------------------- -#define MAX_NUM_VERTICES 50 * 6 - -struct FONT2DVERTEX { - D3DXVECTOR4 p; - DWORD color; - float tu, tv; -}; - -struct FONT3DVERTEX { - D3DXVECTOR3 p; - D3DXVECTOR3 n; - float tu, tv; -}; - -#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1) -#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) - - -inline FONT2DVERTEX InitFont2DVertex(const D3DXVECTOR4& p, D3DCOLOR color, - float tu, float tv) -{ - FONT2DVERTEX v; - v.p = p; - v.color = color; - v.tu = tu; - v.tv = tv; - return v; -} - -inline FONT3DVERTEX InitFont3DVertex(const D3DXVECTOR3& p, const D3DXVECTOR3& n, - float tu, float tv) -{ - FONT3DVERTEX v; - v.p = p; - v.n = n; - v.tu = tu; - v.tv = tv; - return v; -} - - - -//----------------------------------------------------------------------------- -// Name: CD3DFont() -// Desc: Font class constructor -//----------------------------------------------------------------------------- -CD3DFont::CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags) -{ - _tcsncpy_s(m_strFontName, strFontName, _countof(m_strFontName)); - m_strFontName[_countof(m_strFontName) - 1] = _T('\0'); - m_dwFontHeight = dwHeight; - m_dwFontFlags = dwFlags; - m_dwSpacing = 0; - m_dwTexWidth = 0; - m_dwTexHeight = 0; - m_fTextScale = 0.0f; - ZeroMemory(m_fTexCoords, sizeof(m_fTexCoords)); - - m_pd3dDevice = nullptr; - m_pTexture = nullptr; - m_pVB = nullptr; - - m_pStateBlockSaved = nullptr; - m_pStateBlockDrawText = nullptr; -} - - - -//----------------------------------------------------------------------------- -// Name: ~CD3DFont() -// Desc: Font class destructor -//----------------------------------------------------------------------------- -CD3DFont::~CD3DFont() -{ - InvalidateDeviceObjects(); - DeleteDeviceObjects(); -} - - - -//----------------------------------------------------------------------------- -// Name: CreateGDIFont -// Desc: Create a font based on the current state of related member variables -// and return the handle (or null on error) -//----------------------------------------------------------------------------- -HRESULT CD3DFont::CreateGDIFont(HDC hDC, HFONT* pFont) -{ - // Create a font. By specifying ANTIALIASED_QUALITY, we might get an - // antialiased font, but this is not guaranteed. - int nHeight = -MulDiv(m_dwFontHeight, - (int)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), - 72); - DWORD dwBold = (m_dwFontFlags & D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL; - DWORD dwItalic = (m_dwFontFlags & D3DFONT_ITALIC) ? TRUE : FALSE; - *pFont = CreateFont(nHeight, 0, 0, 0, dwBold, dwItalic, - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, - VARIABLE_PITCH, m_strFontName); - - if (*pFont == nullptr) { - return E_FAIL; - } - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: PaintAlphabet -// Desc: Paint the printable characters for the given GDI font onto the -// provided device context. If the bMeasureOnly flag is set, no drawing -// will occur. -//----------------------------------------------------------------------------- -HRESULT CD3DFont::PaintAlphabet(HDC hDC, BOOL bMeasureOnly) -{ - SIZE size; - TCHAR str[2] = _T("x"); // One-character, null-terminated string - - // Calculate the spacing between characters based on line height - if (0 == GetTextExtentPoint32(hDC, str, 1, &size)) { - return E_FAIL; - } - m_dwSpacing = (DWORD) ceil(size.cy * 0.3f); - - // Set the starting point for the drawing - DWORD x = m_dwSpacing; - DWORD y = 0; - - // For each character, draw text on the DC and advance the current position - for (char c = 32; c < 127; c++) { - str[0] = c; - if (0 == GetTextExtentPoint32(hDC, str, 1, &size)) { - return E_FAIL; - } - - if ((DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth) { - x = m_dwSpacing; - y += size.cy + 1; - } - - // Check to see if there's room to write the character here - if (y + size.cy > m_dwTexHeight) { - return D3DERR_MOREDATA; - } - - if (!bMeasureOnly) { - // Perform the actual drawing - if (0 == ExtTextOut(hDC, x + 0, y + 0, ETO_OPAQUE, nullptr, str, 1, nullptr)) { - return E_FAIL; - } - - m_fTexCoords[c - 32][0] = ((float)(x + 0 - m_dwSpacing)) / m_dwTexWidth; - m_fTexCoords[c - 32][1] = ((float)(y + 0 + 0)) / m_dwTexHeight; - m_fTexCoords[c - 32][2] = ((float)(x + size.cx + m_dwSpacing)) / m_dwTexWidth; - m_fTexCoords[c - 32][3] = ((float)(y + size.cy + 0)) / m_dwTexHeight; - } - - x += size.cx + (2 * m_dwSpacing); - } - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: InitDeviceObjects() -// Desc: Initializes device-dependent objects, including the vertex buffer used -// for rendering text and the texture map which stores the font image. -//----------------------------------------------------------------------------- -HRESULT CD3DFont::InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice) -{ - HRESULT hr; - HFONT hFont = nullptr; - HFONT hFontOld = nullptr; - HDC hDC = nullptr; - HBITMAP hbmBitmap = nullptr; - HGDIOBJ hbmOld = nullptr; - - // Keep a local copy of the device - m_pd3dDevice = pd3dDevice; - - // Assume we will draw fonts into texture without scaling unless the - // required texture size is found to be larger than the device max - m_fTextScale = 1.0f; - - hDC = CreateCompatibleDC(nullptr); - SetMapMode(hDC, MM_TEXT); - - hr = CreateGDIFont(hDC, &hFont); - if (FAILED(hr)) { - goto LCleanReturn; - } - - hFontOld = (HFONT) SelectObject(hDC, hFont); - - // Calculate the dimensions for the smallest power-of-two texture which - // can hold all the printable characters - m_dwTexWidth = m_dwTexHeight = 128; - while (D3DERR_MOREDATA == (hr = PaintAlphabet(hDC, true))) { - m_dwTexWidth *= 2; - m_dwTexHeight *= 2; - } - - if (FAILED(hr)) { - goto LCleanReturn; - } - - // If requested texture is too big, use a smaller texture and smaller font, - // and scale up when rendering. - D3DCAPS9 d3dCaps; - m_pd3dDevice->GetDeviceCaps(&d3dCaps); - - if (m_dwTexWidth > d3dCaps.MaxTextureWidth) { - m_fTextScale = (float)d3dCaps.MaxTextureWidth / (float)m_dwTexWidth; - m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth; - - bool bFirstRun = true; // Flag clear after first run - - do { - // If we've already tried fitting the new text, the scale is still - // too large. Reduce and try again. - if (!bFirstRun) { - m_fTextScale *= 0.9f; - } - - // The font has to be scaled to fit on the maximum texture size; our - // current font is too big and needs to be recreated to scale. - DeleteObject(SelectObject(hDC, hFontOld)); - - hr = CreateGDIFont(hDC, &hFont); - if (FAILED(hr)) { - goto LCleanReturn; - } - - hFontOld = (HFONT) SelectObject(hDC, hFont); - - bFirstRun = false; - } while (D3DERR_MOREDATA == (hr = PaintAlphabet(hDC, true))); - } - - - // Create a new texture for the font - hr = m_pd3dDevice->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, - 0, D3DFMT_A4R4G4B4, - D3DPOOL_MANAGED, &m_pTexture, nullptr); - if (FAILED(hr)) { - goto LCleanReturn; - } - - // Prepare to create a bitmap - DWORD* pBitmapBits; - BITMAPINFO bmi; - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; - - // Create a bitmap for the font - hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, - (void**)&pBitmapBits, nullptr, 0); - - hbmOld = SelectObject(hDC, hbmBitmap); - - // Set text properties - SetTextColor(hDC, RGB(255, 255, 255)); - SetBkColor(hDC, 0x00000000); - SetTextAlign(hDC, TA_TOP); - - // Paint the alphabet onto the selected bitmap - hr = PaintAlphabet(hDC, false); - if (FAILED(hr)) { - goto LCleanReturn; - } - - // Lock the surface and write the alpha values for the set pixels - D3DLOCKED_RECT d3dlr; - m_pTexture->LockRect(0, &d3dlr, 0, 0); - BYTE* pDstRow = (BYTE*)d3dlr.pBits; - for (DWORD y = 0; y < m_dwTexHeight; y++) { - WORD* pDst16 = (WORD*)pDstRow; - for (DWORD x = 0; x < m_dwTexWidth; x++) { - // 4-bit measure of pixel intensity - BYTE bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4); - if (bAlpha > 0) { - *pDst16++ = (WORD)((bAlpha << 12) | 0x0fff); - } else { - *pDst16++ = 0x0000; - } - } - pDstRow += d3dlr.Pitch; - } - - hr = S_OK; - - // Done updating texture, so clean up used objects -LCleanReturn: - if (m_pTexture) { - m_pTexture->UnlockRect(0); - } - - SelectObject(hDC, hbmOld); - SelectObject(hDC, hFontOld); - DeleteObject(hbmBitmap); - DeleteObject(hFont); - DeleteDC(hDC); - - return hr; -} - - -//----------------------------------------------------------------------------- -// Name: RestoreDeviceObjects() -// Desc: -//----------------------------------------------------------------------------- -HRESULT CD3DFont::RestoreDeviceObjects() -{ - HRESULT hr; - - // Create vertex buffer for the letters - UINT vertexSize = std::max(sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX)); - if (FAILED(hr = m_pd3dDevice->CreateVertexBuffer(MAX_NUM_VERTICES * vertexSize, - D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, - D3DPOOL_DEFAULT, &m_pVB, nullptr))) { - return hr; - } - - bool bSupportsAlphaBlend = true; - LPDIRECT3D9 pd3d9 = nullptr; - if (SUCCEEDED(m_pd3dDevice->GetDirect3D(&pd3d9))) { - D3DCAPS9 Caps; - D3DDISPLAYMODE Mode; - LPDIRECT3DSURFACE9 pSurf = nullptr; - D3DSURFACE_DESC Desc; - m_pd3dDevice->GetDeviceCaps(&Caps); - m_pd3dDevice->GetDisplayMode(0, &Mode); - if (SUCCEEDED(m_pd3dDevice->GetRenderTarget(0, &pSurf))) { - pSurf->GetDesc(&Desc); - if (FAILED(pd3d9->CheckDeviceFormat(Caps.AdapterOrdinal, Caps.DeviceType, Mode.Format, - D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_SURFACE, - Desc.Format))) { - bSupportsAlphaBlend = false; - } - SAFE_RELEASE(pSurf); - } - SAFE_RELEASE(pd3d9); - } - - // Create the state blocks for rendering text - for (UINT which = 0; which < 2; which++) { - m_pd3dDevice->BeginStateBlock(); - m_pd3dDevice->SetTexture(0, m_pTexture); - - if (D3DFONT_ZENABLE & m_dwFontFlags) { - m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE); - } else { - m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); - } - - if (bSupportsAlphaBlend) { - m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - } else { - m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - } - m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); - m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x08); - m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); - m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); - m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); - m_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); - m_pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE); - m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE); - m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); - m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); - m_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); - m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, - D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | - D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); - m_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - if (which == 0) { - m_pd3dDevice->EndStateBlock(&m_pStateBlockSaved); - } else { - m_pd3dDevice->EndStateBlock(&m_pStateBlockDrawText); - } - } - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: InvalidateDeviceObjects() -// Desc: Destroys all device-dependent objects -//----------------------------------------------------------------------------- -HRESULT CD3DFont::InvalidateDeviceObjects() -{ - SAFE_RELEASE(m_pVB); - SAFE_RELEASE(m_pStateBlockSaved); - SAFE_RELEASE(m_pStateBlockDrawText); - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: DeleteDeviceObjects() -// Desc: Destroys all device-dependent objects -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DeleteDeviceObjects() -{ - SAFE_RELEASE(m_pTexture); - m_pd3dDevice = nullptr; - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: GetTextExtent() -// Desc: Get the dimensions of a text string -//----------------------------------------------------------------------------- -HRESULT CD3DFont::GetTextExtent(const TCHAR* strText, SIZE* pSize) -{ - if (nullptr == strText || nullptr == pSize) { - return E_FAIL; - } - - float fRowWidth = 0.0f; - float fRowHeight = (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; - float fWidth = 0.0f; - float fHeight = fRowHeight; - - while (*strText) { - TCHAR c = *strText++; - - if (c == _T('\n')) { - fRowWidth = 0.0f; - fHeight += fRowHeight; - } - - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float tx2 = m_fTexCoords[c - 32][2]; - - fRowWidth += (tx2 - tx1) * m_dwTexWidth - 2 * m_dwSpacing; - - if (fRowWidth > fWidth) { - fWidth = fRowWidth; - } - } - - pSize->cx = (int)fWidth; - pSize->cy = (int)fHeight; - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: DrawTextScaled() -// Desc: Draws scaled 2D text. Note that x and y are in viewport coordinates -// (ranging from -1 to +1). fXScale and fYScale are the size fraction -// relative to the entire viewport. For example, a fXScale of 0.25 is -// 1/8th of the screen width. This allows you to output text at a fixed -// fraction of the viewport, even if the screen or window size changes. -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DrawTextScaled(float x, float y, float z, - float fXScale, float fYScale, DWORD dwColor, - const TCHAR* strText, DWORD dwFlags) -{ - if (m_pd3dDevice == nullptr) { - return E_FAIL; - } - - // Set up renderstate - m_pStateBlockSaved->Capture(); - m_pStateBlockDrawText->Apply(); - m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX); - m_pd3dDevice->SetPixelShader(nullptr); - m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); - - // Set filter states - if (dwFlags & D3DFONT_FILTERED) { - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - } - - D3DVIEWPORT9 vp; - m_pd3dDevice->GetViewport(&vp); - float fLineHeight = (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; - - // Center the text block in the viewport - if (dwFlags & D3DFONT_CENTERED_X) { - const TCHAR* strTextTmp = strText; - float xFinal = 0.0f; - - while (*strTextTmp) { - TCHAR c = *strTextTmp++; - - if (c == _T('\n')) { - break; // Isn't supported. - } - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float tx2 = m_fTexCoords[c - 32][2]; - - float w = (tx2 - tx1) * m_dwTexWidth; - - w *= (fXScale * vp.Height) / fLineHeight; - - xFinal += w - (2 * m_dwSpacing) * (fXScale * vp.Height) / fLineHeight; - } - - x = -xFinal / vp.Width; - } - if (dwFlags & D3DFONT_CENTERED_Y) { - y = -fLineHeight / vp.Height; - } - - float sx = (x + 1.0f) * vp.Width / 2; - float sy = (y + 1.0f) * vp.Height / 2; - float sz = z; - float rhw = 1.0f; - - // Adjust for character spacing - sx -= m_dwSpacing * (fXScale * vp.Height) / fLineHeight; - float fStartX = sx; - - // Fill vertex buffer - FONT2DVERTEX* pVertices; - DWORD dwNumTriangles = 0L; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - - while (*strText) { - TCHAR c = *strText++; - - if (c == _T('\n')) { - sx = fStartX; - sy += fYScale * vp.Height; - } - - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float ty1 = m_fTexCoords[c - 32][1]; - float tx2 = m_fTexCoords[c - 32][2]; - float ty2 = m_fTexCoords[c - 32][3]; - - float w = (tx2 - tx1) * m_dwTexWidth; - float h = (ty2 - ty1) * m_dwTexHeight; - - w *= (fXScale * vp.Height) / fLineHeight; - h *= (fYScale * vp.Height) / fLineHeight; - - if (c != _T(' ')) { - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx1, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx1, ty1); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx2, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx2, ty1); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx2, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx1, ty1); - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - dwNumTriangles = 0L; - } - } - - sx += w - (2 * m_dwSpacing) * (fXScale * vp.Height) / fLineHeight; - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if (dwNumTriangles > 0) { - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - } - - // Restore the modified renderstates - m_pStateBlockSaved->Apply(); - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: DrawText() -// Desc: Draws 2D text. Note that sx and sy are in pixels -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DrawText(float sx, float sy, DWORD dwColor, - const TCHAR* strText, DWORD dwFlags) -{ - if (m_pd3dDevice == nullptr) { - return E_FAIL; - } - - // Setup renderstate - m_pStateBlockSaved->Capture(); - m_pStateBlockDrawText->Apply(); - m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX); - m_pd3dDevice->SetPixelShader(nullptr); - m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); - - // Set filter states - if (dwFlags & D3DFONT_FILTERED) { - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - } - - // Center the text block in the viewport - if (dwFlags & D3DFONT_CENTERED_X) { - D3DVIEWPORT9 vp; - m_pd3dDevice->GetViewport(&vp); - const TCHAR* strTextTmp = strText; - float xFinal = 0.0f; - - while (*strTextTmp) { - TCHAR c = *strTextTmp++; - - if (c == _T('\n')) { - break; // Isn't supported. - } - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float tx2 = m_fTexCoords[c - 32][2]; - - float w = (tx2 - tx1) * m_dwTexWidth / m_fTextScale; - - xFinal += w - (2 * m_dwSpacing); - } - - sx = (vp.Width - xFinal) / 2.0f; - } - if (dwFlags & D3DFONT_CENTERED_Y) { - D3DVIEWPORT9 vp; - m_pd3dDevice->GetViewport(&vp); - float fLineHeight = ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight); - sy = (vp.Height - fLineHeight) / 2; - } - - // Adjust for character spacing - sx -= m_dwSpacing; - float fStartX = sx; - - // Fill vertex buffer - FONT2DVERTEX* pVertices = nullptr; - DWORD dwNumTriangles = 0; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - - while (*strText) { - TCHAR c = *strText++; - - if (c == _T('\n')) { - sx = fStartX; - sy += (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; - } - - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float ty1 = m_fTexCoords[c - 32][1]; - float tx2 = m_fTexCoords[c - 32][2]; - float ty2 = m_fTexCoords[c - 32][3]; - - float w = (tx2 - tx1) * m_dwTexWidth / m_fTextScale; - float h = (ty2 - ty1) * m_dwTexHeight / m_fTextScale; - - if (c != _T(' ')) { - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty1); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty1); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty1); - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - pVertices = nullptr; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - dwNumTriangles = 0L; - } - } - - sx += w - (2 * m_dwSpacing); - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if (dwNumTriangles > 0) { - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - } - - // Restore the modified renderstates - m_pStateBlockSaved->Apply(); - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: Render3DText() -// Desc: Renders 3D text -//----------------------------------------------------------------------------- -HRESULT CD3DFont::Render3DText(const TCHAR* strText, DWORD dwFlags) -{ - if (m_pd3dDevice == nullptr) { - return E_FAIL; - } - - // Setup renderstate - m_pStateBlockSaved->Capture(); - m_pStateBlockDrawText->Apply(); - m_pd3dDevice->SetFVF(D3DFVF_FONT3DVERTEX); - m_pd3dDevice->SetPixelShader(nullptr); - m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT3DVERTEX)); - - // Set filter states - if (dwFlags & D3DFONT_FILTERED) { - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - } - - // Position for each text element - float x = 0.0f; - float y = 0.0f; - - // Center the text block at the origin (not the viewport) - if (dwFlags & D3DFONT_CENTERED_X) { - SIZE sz; - GetTextExtent(strText, &sz); - x = -(((float)sz.cx) / 10.0f) / 2.0f; - } - if (dwFlags & D3DFONT_CENTERED_Y) { - SIZE sz; - GetTextExtent(strText, &sz); - y = -(((float)sz.cy) / 10.0f) / 2.0f; - } - - // Turn off culling for two-sided text - if (dwFlags & D3DFONT_TWOSIDED) { - m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - } - - // Adjust for character spacing - x -= m_dwSpacing / 10.0f; - float fStartX = x; - TCHAR c; - - // Fill vertex buffer - FONT3DVERTEX* pVertices; - DWORD dwNumTriangles = 0L; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - - while ((c = *strText++) != 0) { - if (c == '\n') { - x = fStartX; - y -= (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight / 10.0f; - } - - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float ty1 = m_fTexCoords[c - 32][1]; - float tx2 = m_fTexCoords[c - 32][2]; - float ty2 = m_fTexCoords[c - 32][3]; - - float w = (tx2 - tx1) * m_dwTexWidth / (10.0f * m_fTextScale); - float h = (ty2 - ty1) * m_dwTexHeight / (10.0f * m_fTextScale); - - if (c != _T(' ')) { - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx1, ty2); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + h, 0), D3DXVECTOR3(0, 0, -1), tx1, ty1); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx2, ty2); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + h, 0), D3DXVECTOR3(0, 0, -1), tx2, ty1); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx2, ty2); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + h, 0), D3DXVECTOR3(0, 0, -1), tx1, ty1); - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - dwNumTriangles = 0L; - } - } - - x += w - (2 * m_dwSpacing) / 10.0f; - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if (dwNumTriangles > 0) { - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - } - - // Restore the modified renderstates - m_pStateBlockSaved->Apply(); - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include +#include +#include "d3dx9/d3dx9.h" +#include "D3DFont.h" +#include "../../../DSUtil/DSUtil.h" + +//----------------------------------------------------------------------------- +// Custom vertex types for rendering text +//----------------------------------------------------------------------------- +#define MAX_NUM_VERTICES 50 * 6 + +struct FONT2DVERTEX { + D3DXVECTOR4 p; + DWORD color; + float tu, tv; +}; + +struct FONT3DVERTEX { + D3DXVECTOR3 p; + D3DXVECTOR3 n; + float tu, tv; +}; + +#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1) +#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) + + +inline FONT2DVERTEX InitFont2DVertex(const D3DXVECTOR4& p, D3DCOLOR color, + float tu, float tv) +{ + FONT2DVERTEX v; + v.p = p; + v.color = color; + v.tu = tu; + v.tv = tv; + return v; +} + +inline FONT3DVERTEX InitFont3DVertex(const D3DXVECTOR3& p, const D3DXVECTOR3& n, + float tu, float tv) +{ + FONT3DVERTEX v; + v.p = p; + v.n = n; + v.tu = tu; + v.tv = tv; + return v; +} + + + +//----------------------------------------------------------------------------- +// Name: CD3DFont() +// Desc: Font class constructor +//----------------------------------------------------------------------------- +CD3DFont::CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags) +{ + _tcsncpy_s(m_strFontName, strFontName, _countof(m_strFontName)); + m_strFontName[_countof(m_strFontName) - 1] = _T('\0'); + m_dwFontHeight = dwHeight; + m_dwFontFlags = dwFlags; + m_dwSpacing = 0; + m_dwTexWidth = 0; + m_dwTexHeight = 0; + m_fTextScale = 0.0f; + ZeroMemory(m_fTexCoords, sizeof(m_fTexCoords)); + + m_pd3dDevice = nullptr; + m_pTexture = nullptr; + m_pVB = nullptr; + + m_pStateBlockSaved = nullptr; + m_pStateBlockDrawText = nullptr; +} + + + +//----------------------------------------------------------------------------- +// Name: ~CD3DFont() +// Desc: Font class destructor +//----------------------------------------------------------------------------- +CD3DFont::~CD3DFont() +{ + InvalidateDeviceObjects(); + DeleteDeviceObjects(); +} + + + +//----------------------------------------------------------------------------- +// Name: CreateGDIFont +// Desc: Create a font based on the current state of related member variables +// and return the handle (or null on error) +//----------------------------------------------------------------------------- +HRESULT CD3DFont::CreateGDIFont(HDC hDC, HFONT* pFont) +{ + // Create a font. By specifying ANTIALIASED_QUALITY, we might get an + // antialiased font, but this is not guaranteed. + int nHeight = -MulDiv(m_dwFontHeight, + (int)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), + 72); + DWORD dwBold = (m_dwFontFlags & D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL; + DWORD dwItalic = (m_dwFontFlags & D3DFONT_ITALIC) ? TRUE : FALSE; + *pFont = CreateFont(nHeight, 0, 0, 0, dwBold, dwItalic, + FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, + VARIABLE_PITCH, m_strFontName); + + if (*pFont == nullptr) { + return E_FAIL; + } + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: PaintAlphabet +// Desc: Paint the printable characters for the given GDI font onto the +// provided device context. If the bMeasureOnly flag is set, no drawing +// will occur. +//----------------------------------------------------------------------------- +HRESULT CD3DFont::PaintAlphabet(HDC hDC, BOOL bMeasureOnly) +{ + SIZE size; + TCHAR str[2] = _T("x"); // One-character, null-terminated string + + // Calculate the spacing between characters based on line height + if (0 == GetTextExtentPoint32(hDC, str, 1, &size)) { + return E_FAIL; + } + m_dwSpacing = (DWORD) ceil(size.cy * 0.3f); + + // Set the starting point for the drawing + DWORD x = m_dwSpacing; + DWORD y = 0; + + // For each character, draw text on the DC and advance the current position + for (char c = 32; c < 127; c++) { + str[0] = c; + if (0 == GetTextExtentPoint32(hDC, str, 1, &size)) { + return E_FAIL; + } + + if ((DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth) { + x = m_dwSpacing; + y += size.cy + 1; + } + + // Check to see if there's room to write the character here + if (y + size.cy > m_dwTexHeight) { + return D3DERR_MOREDATA; + } + + if (!bMeasureOnly) { + // Perform the actual drawing + if (0 == ExtTextOut(hDC, x + 0, y + 0, ETO_OPAQUE, nullptr, str, 1, nullptr)) { + return E_FAIL; + } + + m_fTexCoords[c - 32][0] = ((float)(x + 0 - m_dwSpacing)) / m_dwTexWidth; + m_fTexCoords[c - 32][1] = ((float)(y + 0 + 0)) / m_dwTexHeight; + m_fTexCoords[c - 32][2] = ((float)(x + size.cx + m_dwSpacing)) / m_dwTexWidth; + m_fTexCoords[c - 32][3] = ((float)(y + size.cy + 0)) / m_dwTexHeight; + } + + x += size.cx + (2 * m_dwSpacing); + } + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: InitDeviceObjects() +// Desc: Initializes device-dependent objects, including the vertex buffer used +// for rendering text and the texture map which stores the font image. +//----------------------------------------------------------------------------- +HRESULT CD3DFont::InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice) +{ + HRESULT hr; + HFONT hFont = nullptr; + HFONT hFontOld = nullptr; + HDC hDC = nullptr; + HBITMAP hbmBitmap = nullptr; + HGDIOBJ hbmOld = nullptr; + + // Keep a local copy of the device + m_pd3dDevice = pd3dDevice; + + // Assume we will draw fonts into texture without scaling unless the + // required texture size is found to be larger than the device max + m_fTextScale = 1.0f; + + hDC = CreateCompatibleDC(nullptr); + SetMapMode(hDC, MM_TEXT); + + hr = CreateGDIFont(hDC, &hFont); + if (FAILED(hr)) { + goto LCleanReturn; + } + + hFontOld = (HFONT) SelectObject(hDC, hFont); + + // Calculate the dimensions for the smallest power-of-two texture which + // can hold all the printable characters + m_dwTexWidth = m_dwTexHeight = 128; + while (D3DERR_MOREDATA == (hr = PaintAlphabet(hDC, true))) { + m_dwTexWidth *= 2; + m_dwTexHeight *= 2; + } + + if (FAILED(hr)) { + goto LCleanReturn; + } + + // If requested texture is too big, use a smaller texture and smaller font, + // and scale up when rendering. + D3DCAPS9 d3dCaps; + m_pd3dDevice->GetDeviceCaps(&d3dCaps); + + if (m_dwTexWidth > d3dCaps.MaxTextureWidth) { + m_fTextScale = (float)d3dCaps.MaxTextureWidth / (float)m_dwTexWidth; + m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth; + + bool bFirstRun = true; // Flag clear after first run + + do { + // If we've already tried fitting the new text, the scale is still + // too large. Reduce and try again. + if (!bFirstRun) { + m_fTextScale *= 0.9f; + } + + // The font has to be scaled to fit on the maximum texture size; our + // current font is too big and needs to be recreated to scale. + DeleteObject(SelectObject(hDC, hFontOld)); + + hr = CreateGDIFont(hDC, &hFont); + if (FAILED(hr)) { + goto LCleanReturn; + } + + hFontOld = (HFONT) SelectObject(hDC, hFont); + + bFirstRun = false; + } while (D3DERR_MOREDATA == (hr = PaintAlphabet(hDC, true))); + } + + + // Create a new texture for the font + hr = m_pd3dDevice->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, + 0, D3DFMT_A4R4G4B4, + D3DPOOL_MANAGED, &m_pTexture, nullptr); + if (FAILED(hr)) { + goto LCleanReturn; + } + + // Prepare to create a bitmap + DWORD* pBitmapBits; + BITMAPINFO bmi; + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = (int)m_dwTexWidth; + bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biBitCount = 32; + + // Create a bitmap for the font + hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, + (void**)&pBitmapBits, nullptr, 0); + + hbmOld = SelectObject(hDC, hbmBitmap); + + // Set text properties + SetTextColor(hDC, RGB(255, 255, 255)); + SetBkColor(hDC, 0x00000000); + SetTextAlign(hDC, TA_TOP); + + // Paint the alphabet onto the selected bitmap + hr = PaintAlphabet(hDC, false); + if (FAILED(hr)) { + goto LCleanReturn; + } + + // Lock the surface and write the alpha values for the set pixels + D3DLOCKED_RECT d3dlr; + m_pTexture->LockRect(0, &d3dlr, 0, 0); + BYTE* pDstRow = (BYTE*)d3dlr.pBits; + for (DWORD y = 0; y < m_dwTexHeight; y++) { + WORD* pDst16 = (WORD*)pDstRow; + for (DWORD x = 0; x < m_dwTexWidth; x++) { + // 4-bit measure of pixel intensity + BYTE bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4); + if (bAlpha > 0) { + *pDst16++ = (WORD)((bAlpha << 12) | 0x0fff); + } else { + *pDst16++ = 0x0000; + } + } + pDstRow += d3dlr.Pitch; + } + + hr = S_OK; + + // Done updating texture, so clean up used objects +LCleanReturn: + if (m_pTexture) { + m_pTexture->UnlockRect(0); + } + + SelectObject(hDC, hbmOld); + SelectObject(hDC, hFontOld); + DeleteObject(hbmBitmap); + DeleteObject(hFont); + DeleteDC(hDC); + + return hr; +} + + +//----------------------------------------------------------------------------- +// Name: RestoreDeviceObjects() +// Desc: +//----------------------------------------------------------------------------- +HRESULT CD3DFont::RestoreDeviceObjects() +{ + HRESULT hr; + + // Create vertex buffer for the letters + UINT vertexSize = std::max(sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX)); + if (FAILED(hr = m_pd3dDevice->CreateVertexBuffer(MAX_NUM_VERTICES * vertexSize, + D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, + D3DPOOL_DEFAULT, &m_pVB, nullptr))) { + return hr; + } + + bool bSupportsAlphaBlend = true; + LPDIRECT3D9 pd3d9 = nullptr; + if (SUCCEEDED(m_pd3dDevice->GetDirect3D(&pd3d9))) { + D3DCAPS9 Caps; + D3DDISPLAYMODE Mode; + LPDIRECT3DSURFACE9 pSurf = nullptr; + D3DSURFACE_DESC Desc; + m_pd3dDevice->GetDeviceCaps(&Caps); + m_pd3dDevice->GetDisplayMode(0, &Mode); + if (SUCCEEDED(m_pd3dDevice->GetRenderTarget(0, &pSurf))) { + pSurf->GetDesc(&Desc); + if (FAILED(pd3d9->CheckDeviceFormat(Caps.AdapterOrdinal, Caps.DeviceType, Mode.Format, + D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_SURFACE, + Desc.Format))) { + bSupportsAlphaBlend = false; + } + SAFE_RELEASE(pSurf); + } + SAFE_RELEASE(pd3d9); + } + + // Create the state blocks for rendering text + for (UINT which = 0; which < 2; which++) { + m_pd3dDevice->BeginStateBlock(); + m_pd3dDevice->SetTexture(0, m_pTexture); + + if (D3DFONT_ZENABLE & m_dwFontFlags) { + m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + } else { + m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + } + + if (bSupportsAlphaBlend) { + m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } else { + m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x08); + m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); + m_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + m_pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE); + m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); + m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); + m_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, + D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | + D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + m_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + if (which == 0) { + m_pd3dDevice->EndStateBlock(&m_pStateBlockSaved); + } else { + m_pd3dDevice->EndStateBlock(&m_pStateBlockDrawText); + } + } + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: InvalidateDeviceObjects() +// Desc: Destroys all device-dependent objects +//----------------------------------------------------------------------------- +HRESULT CD3DFont::InvalidateDeviceObjects() +{ + SAFE_RELEASE(m_pVB); + SAFE_RELEASE(m_pStateBlockSaved); + SAFE_RELEASE(m_pStateBlockDrawText); + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: DeleteDeviceObjects() +// Desc: Destroys all device-dependent objects +//----------------------------------------------------------------------------- +HRESULT CD3DFont::DeleteDeviceObjects() +{ + SAFE_RELEASE(m_pTexture); + m_pd3dDevice = nullptr; + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: GetTextExtent() +// Desc: Get the dimensions of a text string +//----------------------------------------------------------------------------- +HRESULT CD3DFont::GetTextExtent(const TCHAR* strText, SIZE* pSize) +{ + if (nullptr == strText || nullptr == pSize) { + return E_FAIL; + } + + float fRowWidth = 0.0f; + float fRowHeight = (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; + float fWidth = 0.0f; + float fHeight = fRowHeight; + + while (*strText) { + TCHAR c = *strText++; + + if (c == _T('\n')) { + fRowWidth = 0.0f; + fHeight += fRowHeight; + } + + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float tx2 = m_fTexCoords[c - 32][2]; + + fRowWidth += (tx2 - tx1) * m_dwTexWidth - 2 * m_dwSpacing; + + if (fRowWidth > fWidth) { + fWidth = fRowWidth; + } + } + + pSize->cx = (int)fWidth; + pSize->cy = (int)fHeight; + + return S_OK; +} + + +//----------------------------------------------------------------------------- +// Name: DrawTextScaled() +// Desc: Draws scaled 2D text. Note that x and y are in viewport coordinates +// (ranging from -1 to +1). fXScale and fYScale are the size fraction +// relative to the entire viewport. For example, a fXScale of 0.25 is +// 1/8th of the screen width. This allows you to output text at a fixed +// fraction of the viewport, even if the screen or window size changes. +//----------------------------------------------------------------------------- +HRESULT CD3DFont::DrawTextScaled(float x, float y, float z, + float fXScale, float fYScale, DWORD dwColor, + const TCHAR* strText, DWORD dwFlags) +{ + if (m_pd3dDevice == nullptr) { + return E_FAIL; + } + + // Set up renderstate + m_pStateBlockSaved->Capture(); + m_pStateBlockDrawText->Apply(); + m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX); + m_pd3dDevice->SetPixelShader(nullptr); + m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); + + // Set filter states + if (dwFlags & D3DFONT_FILTERED) { + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + + D3DVIEWPORT9 vp; + m_pd3dDevice->GetViewport(&vp); + float fLineHeight = (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; + + // Center the text block in the viewport + if (dwFlags & D3DFONT_CENTERED_X) { + const TCHAR* strTextTmp = strText; + float xFinal = 0.0f; + + while (*strTextTmp) { + TCHAR c = *strTextTmp++; + + if (c == _T('\n')) { + break; // Isn't supported. + } + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float tx2 = m_fTexCoords[c - 32][2]; + + float w = (tx2 - tx1) * m_dwTexWidth; + + w *= (fXScale * vp.Height) / fLineHeight; + + xFinal += w - (2 * m_dwSpacing) * (fXScale * vp.Height) / fLineHeight; + } + + x = -xFinal / vp.Width; + } + if (dwFlags & D3DFONT_CENTERED_Y) { + y = -fLineHeight / vp.Height; + } + + float sx = (x + 1.0f) * vp.Width / 2; + float sy = (y + 1.0f) * vp.Height / 2; + float sz = z; + float rhw = 1.0f; + + // Adjust for character spacing + sx -= m_dwSpacing * (fXScale * vp.Height) / fLineHeight; + float fStartX = sx; + + // Fill vertex buffer + FONT2DVERTEX* pVertices; + DWORD dwNumTriangles = 0L; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + + while (*strText) { + TCHAR c = *strText++; + + if (c == _T('\n')) { + sx = fStartX; + sy += fYScale * vp.Height; + } + + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float ty1 = m_fTexCoords[c - 32][1]; + float tx2 = m_fTexCoords[c - 32][2]; + float ty2 = m_fTexCoords[c - 32][3]; + + float w = (tx2 - tx1) * m_dwTexWidth; + float h = (ty2 - ty1) * m_dwTexHeight; + + w *= (fXScale * vp.Height) / fLineHeight; + h *= (fYScale * vp.Height) / fLineHeight; + + if (c != _T(' ')) { + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx1, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx1, ty1); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx2, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx2, ty1); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx2, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx1, ty1); + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { + // Unlock, render, and relock the vertex buffer + m_pVB->Unlock(); + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + dwNumTriangles = 0L; + } + } + + sx += w - (2 * m_dwSpacing) * (fXScale * vp.Height) / fLineHeight; + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if (dwNumTriangles > 0) { + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + } + + // Restore the modified renderstates + m_pStateBlockSaved->Apply(); + + return S_OK; +} + + +//----------------------------------------------------------------------------- +// Name: DrawText() +// Desc: Draws 2D text. Note that sx and sy are in pixels +//----------------------------------------------------------------------------- +HRESULT CD3DFont::DrawText(float sx, float sy, DWORD dwColor, + const TCHAR* strText, DWORD dwFlags) +{ + if (m_pd3dDevice == nullptr) { + return E_FAIL; + } + + // Setup renderstate + m_pStateBlockSaved->Capture(); + m_pStateBlockDrawText->Apply(); + m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX); + m_pd3dDevice->SetPixelShader(nullptr); + m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); + + // Set filter states + if (dwFlags & D3DFONT_FILTERED) { + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + + // Center the text block in the viewport + if (dwFlags & D3DFONT_CENTERED_X) { + D3DVIEWPORT9 vp; + m_pd3dDevice->GetViewport(&vp); + const TCHAR* strTextTmp = strText; + float xFinal = 0.0f; + + while (*strTextTmp) { + TCHAR c = *strTextTmp++; + + if (c == _T('\n')) { + break; // Isn't supported. + } + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float tx2 = m_fTexCoords[c - 32][2]; + + float w = (tx2 - tx1) * m_dwTexWidth / m_fTextScale; + + xFinal += w - (2 * m_dwSpacing); + } + + sx = (vp.Width - xFinal) / 2.0f; + } + if (dwFlags & D3DFONT_CENTERED_Y) { + D3DVIEWPORT9 vp; + m_pd3dDevice->GetViewport(&vp); + float fLineHeight = ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight); + sy = (vp.Height - fLineHeight) / 2; + } + + // Adjust for character spacing + sx -= m_dwSpacing; + float fStartX = sx; + + // Fill vertex buffer + FONT2DVERTEX* pVertices = nullptr; + DWORD dwNumTriangles = 0; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + + while (*strText) { + TCHAR c = *strText++; + + if (c == _T('\n')) { + sx = fStartX; + sy += (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; + } + + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float ty1 = m_fTexCoords[c - 32][1]; + float tx2 = m_fTexCoords[c - 32][2]; + float ty2 = m_fTexCoords[c - 32][3]; + + float w = (tx2 - tx1) * m_dwTexWidth / m_fTextScale; + float h = (ty2 - ty1) * m_dwTexHeight / m_fTextScale; + + if (c != _T(' ')) { + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty1); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty1); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty1); + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { + // Unlock, render, and relock the vertex buffer + m_pVB->Unlock(); + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + pVertices = nullptr; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + dwNumTriangles = 0L; + } + } + + sx += w - (2 * m_dwSpacing); + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if (dwNumTriangles > 0) { + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + } + + // Restore the modified renderstates + m_pStateBlockSaved->Apply(); + + return S_OK; +} + + +//----------------------------------------------------------------------------- +// Name: Render3DText() +// Desc: Renders 3D text +//----------------------------------------------------------------------------- +HRESULT CD3DFont::Render3DText(const TCHAR* strText, DWORD dwFlags) +{ + if (m_pd3dDevice == nullptr) { + return E_FAIL; + } + + // Setup renderstate + m_pStateBlockSaved->Capture(); + m_pStateBlockDrawText->Apply(); + m_pd3dDevice->SetFVF(D3DFVF_FONT3DVERTEX); + m_pd3dDevice->SetPixelShader(nullptr); + m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT3DVERTEX)); + + // Set filter states + if (dwFlags & D3DFONT_FILTERED) { + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + + // Position for each text element + float x = 0.0f; + float y = 0.0f; + + // Center the text block at the origin (not the viewport) + if (dwFlags & D3DFONT_CENTERED_X) { + SIZE sz; + GetTextExtent(strText, &sz); + x = -(((float)sz.cx) / 10.0f) / 2.0f; + } + if (dwFlags & D3DFONT_CENTERED_Y) { + SIZE sz; + GetTextExtent(strText, &sz); + y = -(((float)sz.cy) / 10.0f) / 2.0f; + } + + // Turn off culling for two-sided text + if (dwFlags & D3DFONT_TWOSIDED) { + m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + // Adjust for character spacing + x -= m_dwSpacing / 10.0f; + float fStartX = x; + TCHAR c; + + // Fill vertex buffer + FONT3DVERTEX* pVertices; + DWORD dwNumTriangles = 0L; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + + while ((c = *strText++) != 0) { + if (c == '\n') { + x = fStartX; + y -= (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight / 10.0f; + } + + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float ty1 = m_fTexCoords[c - 32][1]; + float tx2 = m_fTexCoords[c - 32][2]; + float ty2 = m_fTexCoords[c - 32][3]; + + float w = (tx2 - tx1) * m_dwTexWidth / (10.0f * m_fTextScale); + float h = (ty2 - ty1) * m_dwTexHeight / (10.0f * m_fTextScale); + + if (c != _T(' ')) { + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx1, ty2); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + h, 0), D3DXVECTOR3(0, 0, -1), tx1, ty1); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx2, ty2); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + h, 0), D3DXVECTOR3(0, 0, -1), tx2, ty1); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx2, ty2); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + h, 0), D3DXVECTOR3(0, 0, -1), tx1, ty1); + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { + // Unlock, render, and relock the vertex buffer + m_pVB->Unlock(); + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + dwNumTriangles = 0L; + } + } + + x += w - (2 * m_dwSpacing) / 10.0f; + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if (dwNumTriangles > 0) { + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + } + + // Restore the modified renderstates + m_pStateBlockSaved->Apply(); + + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/D3DFont.h b/src/filters/renderer/VideoRenderers/D3DFont.h index 24f00bd7f11..f5fdd129a6c 100644 --- a/src/filters/renderer/VideoRenderers/D3DFont.h +++ b/src/filters/renderer/VideoRenderers/D3DFont.h @@ -1,78 +1,78 @@ -/* - * (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 . - * - */ - -#pragma once - -// Font creation flags -#define D3DFONT_BOLD 0x0001 -#define D3DFONT_ITALIC 0x0002 -#define D3DFONT_ZENABLE 0x0004 - -// Font rendering flags -#define D3DFONT_CENTERED_X 0x0001 -#define D3DFONT_CENTERED_Y 0x0002 -#define D3DFONT_TWOSIDED 0x0004 -#define D3DFONT_FILTERED 0x0008 - - -class CD3DFont -{ - TCHAR m_strFontName[80]; // Font properties - DWORD m_dwFontHeight; - DWORD m_dwFontFlags; - - LPDIRECT3DDEVICE9 m_pd3dDevice; // A D3DDevice used for rendering - LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font - LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text - DWORD m_dwTexWidth; // Texture dimensions - DWORD m_dwTexHeight; - float m_fTextScale; - float m_fTexCoords[128 - 32][4]; - DWORD m_dwSpacing; // Character pixel spacing per side - - // Stateblocks for setting and restoring render states - LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved; - LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText; - - HRESULT CreateGDIFont(HDC hDC, HFONT* pFont); - HRESULT PaintAlphabet(HDC hDC, BOOL bMeasureOnly = FALSE); - -public: - // 2D and 3D text drawing functions - HRESULT DrawText(float x, float y, DWORD dwColor, const TCHAR* strText, DWORD dwFlags = 0L); - HRESULT DrawTextScaled(float x, float y, float z, - float fXScale, float fYScale, DWORD dwColor, - const TCHAR* strText, DWORD dwFlags = 0L); - HRESULT Render3DText(const TCHAR* strText, DWORD dwFlags = 0L); - - // Function to get extent of text - HRESULT GetTextExtent(const TCHAR* strText, SIZE* pSize); - - // Initializing and destroying device-dependent objects - HRESULT InitDeviceObjects(IDirect3DDevice9* pd3dDevice); - HRESULT RestoreDeviceObjects(); - HRESULT InvalidateDeviceObjects(); - HRESULT DeleteDeviceObjects(); - - // Constructor / destructor - CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags = 0L); - ~CD3DFont(); -}; +/* + * (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 . + * + */ + +#pragma once + +// Font creation flags +#define D3DFONT_BOLD 0x0001 +#define D3DFONT_ITALIC 0x0002 +#define D3DFONT_ZENABLE 0x0004 + +// Font rendering flags +#define D3DFONT_CENTERED_X 0x0001 +#define D3DFONT_CENTERED_Y 0x0002 +#define D3DFONT_TWOSIDED 0x0004 +#define D3DFONT_FILTERED 0x0008 + + +class CD3DFont +{ + TCHAR m_strFontName[80]; // Font properties + DWORD m_dwFontHeight; + DWORD m_dwFontFlags; + + LPDIRECT3DDEVICE9 m_pd3dDevice; // A D3DDevice used for rendering + LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font + LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text + DWORD m_dwTexWidth; // Texture dimensions + DWORD m_dwTexHeight; + float m_fTextScale; + float m_fTexCoords[128 - 32][4]; + DWORD m_dwSpacing; // Character pixel spacing per side + + // Stateblocks for setting and restoring render states + LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved; + LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText; + + HRESULT CreateGDIFont(HDC hDC, HFONT* pFont); + HRESULT PaintAlphabet(HDC hDC, BOOL bMeasureOnly = FALSE); + +public: + // 2D and 3D text drawing functions + HRESULT DrawText(float x, float y, DWORD dwColor, const TCHAR* strText, DWORD dwFlags = 0L); + HRESULT DrawTextScaled(float x, float y, float z, + float fXScale, float fYScale, DWORD dwColor, + const TCHAR* strText, DWORD dwFlags = 0L); + HRESULT Render3DText(const TCHAR* strText, DWORD dwFlags = 0L); + + // Function to get extent of text + HRESULT GetTextExtent(const TCHAR* strText, SIZE* pSize); + + // Initializing and destroying device-dependent objects + HRESULT InitDeviceObjects(IDirect3DDevice9* pd3dDevice); + HRESULT RestoreDeviceObjects(); + HRESULT InvalidateDeviceObjects(); + HRESULT DeleteDeviceObjects(); + + // Constructor / destructor + CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags = 0L); + ~CD3DFont(); +}; diff --git a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp index 74124737945..125637771d8 100644 --- a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp @@ -1,2309 +1,2309 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "RenderersSettings.h" -#include "DX9AllocatorPresenter.h" -#include -#include "../../../SubPic/DX9SubPic.h" -#include "../../../SubPic/SubPicQueueImpl.h" -#include "IPinHook.h" -#include "FocusThread.h" -#include "../../../DSUtil/vd.h" -#include - -#define FRAMERATE_MAX_DELTA 3000 - -#define REFERENCE_WIDTH 1920 -#define FONT_HEIGHT 21 -#define BOLD_THRESHOLD 11 -#define TEXT_PADDING 2 -#define GRAPH_HEIGHT 360 -#define GRAPH_WIDTH 1000 - -using namespace DSObjects; - -#pragma warning(push) -#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized -// CDX9AllocatorPresenter -CDX9AllocatorPresenter::CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString& _Error, bool isPreview) - : CDX9RenderingEngine(hWnd, hr, &_Error) - , m_bAlternativeVSync(false) - , m_bCompositionEnabled(false) - , m_bIsEVR(bIsEVR) - , m_OrderedPaint(0) - , m_VSyncMode(0) - , m_bDesktopCompositionDisabled(false) - , m_bIsFullscreen(bFullscreen) - , fullScreenChanged(false) - , m_bNeedCheckSample(true) - , m_MainThreadId(0) - , m_bIsRendering(false) - , m_hDWMAPI(nullptr) - , m_pDwmIsCompositionEnabled(nullptr) - , m_pDwmEnableComposition(nullptr) - , m_pDirectDraw(nullptr) - , m_LastAdapterCheck(0) - , m_nTearingPos(0) - , m_VMR9AlphaBitmapWidthBytes(0) - , m_pD3DXLoadSurfaceFromMemory(nullptr) - , m_pD3DXLoadSurfaceFromSurface(nullptr) - , m_pD3DXCreateLine(nullptr) - , m_pD3DXCreateFont(nullptr) - , m_pD3DXCreateSprite(nullptr) - , m_nVMR9Surfaces(0) - , m_iVMR9Surface(0) - , m_nUsedBuffer(0) - , m_fAvrFps(0.0) - , m_fJitterStdDev(0.0) - , m_fJitterMean(0.0) - , m_fSyncOffsetStdDev(0.0) - , m_fSyncOffsetAvr(0.0) - , m_DetectedRefreshRate(0) - , m_DetectedRefreshTime(0.0) - , m_DetectedRefreshTimePrim(0) - , m_DetectedScanlineTime(0) - , m_DetectedScanlineTimePrim(0) - , m_DetectedScanlinesPerFrame(0.0) - , m_ldDetectedRefreshRateList() - , m_ldDetectedScanlineRateList() - , m_DetectedRefreshRatePos(0) - , m_bSyncStatsAvailable(false) - , m_pllJitter() - , m_pllSyncOffset() - , m_llLastPerf(0) - , m_JitterStdDev(0) - , m_MaxJitter(MINLONG64) - , m_MinJitter(MAXLONG64) - , m_MaxSyncOffset(0) - , m_MinSyncOffset(0) - , m_nNextJitter(0) - , m_nNextSyncOffset(0) - , m_rtTimePerFrame(0) - , m_DetectedFrameRate(0.0) - , m_DetectedFrameTime(0.0) - , m_DetectedFrameTimeStdDev(0.0) - , m_DetectedLock(false) - , m_DetectedFrameTimeHistory() - , m_DetectedFrameTimeHistoryHistory() - , m_DetectedFrameTimePos(0) - , m_bInterlaced(false) - , m_VBlankEndWait(0) - , m_VBlankStartWait(0) - , m_VBlankWaitTime(0) - , m_VBlankLockTime(0) - , m_VBlankMin(300000) - , m_VBlankMinCalc(300000) - , m_VBlankMax(0) - , m_VBlankEndPresent(-100000) - , m_VBlankStartMeasureTime(0) - , m_VBlankStartMeasure(0) - , m_PresentWaitTime(0) - , m_PresentWaitTimeMin(3000000000) - , m_PresentWaitTimeMax(0) - , m_PaintTime(0) - , m_PaintTimeMin(3000000000) - , m_PaintTimeMax(0) - , m_WaitForGPUTime(0) - , m_RasterStatusWaitTime(0) - , m_RasterStatusWaitTimeMin(3000000000) - , m_RasterStatusWaitTimeMax(0) - , m_RasterStatusWaitTimeMaxCalc(0) - , m_ClockDiffCalc(0.0) - , m_ClockDiffPrim(0.0) - , m_ClockDiff(0.0) - , m_TimeChangeHistory() - , m_ClockChangeHistory() - , m_ClockTimeChangeHistoryPos(0) - , m_ModeratedTimeSpeed(1.0) - , m_ModeratedTimeSpeedPrim(0.0) - , m_ModeratedTimeSpeedDiff(0.0) - , m_bCorrectedFrameTime(0) - , m_FrameTimeCorrection(0) - , m_LastFrameDuration(0) - , m_LastSampleTime(0) - , m_FocusThread(nullptr) - , m_hFocusWindow(nullptr) - , m_bIsPreview(isPreview) -{ - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - - if (FAILED(hr)) { - _Error += _T("ISubPicAllocatorPresenterImpl failed\n"); - return; - } - - HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); - - if (hDll) { - (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory"); - (FARPROC&)m_pD3DXLoadSurfaceFromSurface = GetProcAddress(hDll, "D3DXLoadSurfaceFromSurface"); - (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine"); - (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW"); - (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite"); - } else { - _Error += _T("Your system is missing the file d3dx9_43.dll\n\nTo acquire this file you must install \"DirectX End-User Runtime\" or update your MPC-HC installation."); - } - - m_hDWMAPI = LoadLibrary(L"dwmapi.dll"); - if (m_hDWMAPI) { - (FARPROC&)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled"); - (FARPROC&)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition"); - } - - Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); - if (m_pD3DEx) { - m_pD3D = m_pD3DEx; - } - - const CRenderersSettings& r = GetRenderersSettings(); - - if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { - m_bDesktopCompositionDisabled = true; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(0); - } - } else { - m_bDesktopCompositionDisabled = false; - } - - hr = CreateDevice(_Error); -} -#pragma warning(pop) - -CDX9AllocatorPresenter::~CDX9AllocatorPresenter() -{ - if (m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = false; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(1); - } - } - - m_pFont = nullptr; - m_pLine = nullptr; - m_pSprite = nullptr; - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - - m_pAlphaBitmapTexture.Release(); - CleanupRenderingEngine(); - - m_pD3D = nullptr; - m_pD3DEx = nullptr; - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - - if (m_FocusThread) { - m_FocusThread->PostThreadMessage(WM_QUIT, 0, 0); - if (WaitForSingleObject(m_FocusThread->m_hThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_FocusThread->m_hThread, 0xDEAD); - } - } - - if (m_hDWMAPI) { - FreeLibrary(m_hDWMAPI); - m_hDWMAPI = nullptr; - } -} - -void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed); - -#if 0 -class CRandom31 -{ -public: - - CRandom31() { - m_Seed = 12164; - } - - void f_SetSeed(int32 _Seed) { - m_Seed = _Seed; - } - int32 f_GetSeed() { - return m_Seed; - } - /* - Park and Miller's psuedo-random number generator. - */ - int32 m_Seed; - int32 f_Get() { - static const int32 A = 16807; - static const int32 M = 2147483647; // 2^31 - 1 - static const int32 q = M / A; // M / A - static const int32 r = M % A; // M % A - m_Seed = A * (m_Seed % q) - r * (m_Seed / q); - if (m_Seed < 0) { - m_Seed += M; - } - return m_Seed; - } - - static int32 fs_Max() { - return 2147483646; - } - - double f_GetFloat() { - return double(f_Get()) * (1.0 / double(fs_Max())); - } -}; - -class CVSyncEstimation -{ -private: - class CHistoryEntry - { - public: - CHistoryEntry() { - m_Time = 0; - m_ScanLine = -1; - } - LONGLONG m_Time; - int m_ScanLine; - }; - - class CSolution - { - public: - CSolution() { - m_ScanLines = 1000; - m_ScanLinesPerSecond = m_ScanLines * 100; - } - int m_ScanLines; - double m_ScanLinesPerSecond; - double m_SqrSum; - - void f_Mutate(double _Amount, CRandom31& _Random, int _MinScans) { - int ToDo = _Random.f_Get() % 10; - if (ToDo == 0) { - m_ScanLines = m_ScanLines / 2; - } else if (ToDo == 1) { - m_ScanLines = m_ScanLines * 2; - } - - m_ScanLines = m_ScanLines * (1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5); - m_ScanLines = max(m_ScanLines, _MinScans); - - if (ToDo == 2) { - m_ScanLinesPerSecond /= (_Random.f_Get() % 4) + 1; - } else if (ToDo == 3) { - m_ScanLinesPerSecond *= (_Random.f_Get() % 4) + 1; - } - - m_ScanLinesPerSecond *= 1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5; - } - - void f_SpawnInto(CSolution& _Other, CRandom31& _Random, int _MinScans) { - _Other = *this; - _Other.f_Mutate(_Random.f_GetFloat() * 0.1, _Random, _MinScans); - } - - static int fs_Compare(const void* _pFirst, const void* _pSecond) { - const CSolution* pFirst = (const CSolution*)_pFirst; - const CSolution* pSecond = (const CSolution*)_pSecond; - if (pFirst->m_SqrSum < pSecond->m_SqrSum) { - return -1; - } else if (pFirst->m_SqrSum > pSecond->m_SqrSum) { - return 1; - } - return 0; - } - - - }; - - enum { - ENumHistory = 128 - }; - - CHistoryEntry m_History[ENumHistory]; - int m_iHistory; - CSolution m_OldSolutions[2]; - - CRandom31 m_Random; - - - double fp_GetSquareSum(double _ScansPerSecond, double _ScanLines) { - double SquareSum = 0; - int nHistory = min(m_nHistory, ENumHistory); - int iHistory = m_iHistory - nHistory; - if (iHistory < 0) { - iHistory += ENumHistory; - } - for (int i = 1; i < nHistory; ++i) { - int iHistory0 = iHistory + i - 1; - int iHistory1 = iHistory + i; - if (iHistory0 < 0) { - iHistory0 += ENumHistory; - } - iHistory0 = iHistory0 % ENumHistory; - iHistory1 = iHistory1 % ENumHistory; - ASSERT(m_History[iHistory0].m_Time != 0); - ASSERT(m_History[iHistory1].m_Time != 0); - - double DeltaTime = (m_History[iHistory1].m_Time - m_History[iHistory0].m_Time) / 10000000.0; - double PredictedScanLine = m_History[iHistory0].m_ScanLine + DeltaTime * _ScansPerSecond; - PredictedScanLine = fmod(PredictedScanLine, _ScanLines); - double Delta = (m_History[iHistory1].m_ScanLine - PredictedScanLine); - double DeltaSqr = Delta * Delta; - SquareSum += DeltaSqr; - } - return SquareSum; - } - - int m_nHistory; -public: - - CVSyncEstimation() { - m_iHistory = 0; - m_nHistory = 0; - } - - void f_AddSample(int _ScanLine, LONGLONG _Time) { - m_History[m_iHistory].m_ScanLine = _ScanLine; - m_History[m_iHistory].m_Time = _Time; - ++m_nHistory; - m_iHistory = (m_iHistory + 1) % ENumHistory; - } - - void f_GetEstimation(double& _RefreshRate, int& _ScanLines, int _ScreenSizeY, int _WindowsRefreshRate) { - _RefreshRate = 0; - _ScanLines = 0; - - int iHistory = m_iHistory; - // We have a full history - if (m_nHistory > 10) { - for (int l = 0; l < 5; ++l) { - const int nSol = 3 + 5 + 5 + 3; - CSolution Solutions[nSol]; - - Solutions[0] = m_OldSolutions[0]; - Solutions[1] = m_OldSolutions[1]; - Solutions[2].m_ScanLines = _ScreenSizeY; - Solutions[2].m_ScanLinesPerSecond = _ScreenSizeY * _WindowsRefreshRate; - - int iStart = 3; - for (int i = iStart; i < iStart + 5; ++i) { - Solutions[0].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); - } - iStart += 5; - for (int i = iStart; i < iStart + 5; ++i) { - Solutions[1].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); - } - iStart += 5; - for (int i = iStart; i < iStart + 3; ++i) { - Solutions[2].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); - } - - int Start = 2; - if (l == 0) { - Start = 0; - } - for (int i = Start; i < nSol; ++i) { - Solutions[i].m_SqrSum = fp_GetSquareSum(Solutions[i].m_ScanLinesPerSecond, Solutions[i].m_ScanLines); - } - - qsort(Solutions, nSol, sizeof(Solutions[0]), &CSolution::fs_Compare); - for (int i = 0; i < 2; ++i) { - m_OldSolutions[i] = Solutions[i]; - } - } - - _ScanLines = m_OldSolutions[0].m_ScanLines + 0.5; - _RefreshRate = 1.0 / (m_OldSolutions[0].m_ScanLines / m_OldSolutions[0].m_ScanLinesPerSecond); - } else { - m_OldSolutions[0].m_ScanLines = _ScreenSizeY; - m_OldSolutions[1].m_ScanLines = _ScreenSizeY; - } - } -}; -#endif - -bool CDX9AllocatorPresenter::SettingsNeedResetDevice(CRenderersSettings& r) -{ - CRenderersSettings::CAdvRendererSettings& New = r.m_AdvRendSets; - CRenderersSettings::CAdvRendererSettings& Current = m_LastRendererSettings; - - bool bRet = false; - - bRet = bRet || New.bVMR9AlterativeVSync != Current.bVMR9AlterativeVSync; - bRet = bRet || New.bVMR9VSyncAccurate != Current.bVMR9VSyncAccurate; - - if (m_bIsFullscreen) { - bRet = bRet || New.bVMR9FullscreenGUISupport != Current.bVMR9FullscreenGUISupport; - } else { - if (Current.bVMRDisableDesktopComposition) { - if (!m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = true; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(0); - } - } - } else { - if (m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = false; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(1); - } - } - } - } - - if (m_bIsEVR) { - bRet = bRet || New.bEVRHighColorResolution != Current.bEVRHighColorResolution; - bRet = bRet || New.bEVRForceInputHighColorResolution != Current.bEVRForceInputHighColorResolution; - } - - m_LastRendererSettings = r.m_AdvRendSets; - - return bRet; -} - -HRESULT CDX9AllocatorPresenter::CreateDevice(CString& _Error) -{ - const CRenderersSettings& r = GetRenderersSettings(); - CRenderersData* rd = GetRenderersData(); - - m_VBlankEndWait = 0; - m_VBlankMin = 300000; - m_VBlankMinCalc = 300000; - m_VBlankMax = 0; - m_VBlankStartWait = 0; - m_VBlankWaitTime = 0; - m_VBlankLockTime = 0; - m_PresentWaitTime = 0; - m_PresentWaitTimeMin = 3000000000; - m_PresentWaitTimeMax = 0; - - m_LastRendererSettings = r.m_AdvRendSets; - - m_VBlankEndPresent = -100000; - m_VBlankStartMeasureTime = 0; - m_VBlankStartMeasure = 0; - - m_PaintTime = 0; - m_PaintTimeMin = 3000000000; - m_PaintTimeMax = 0; - - m_RasterStatusWaitTime = 0; - m_RasterStatusWaitTimeMin = 3000000000; - m_RasterStatusWaitTimeMax = 0; - m_RasterStatusWaitTimeMaxCalc = 0; - - m_ClockDiff = 0.0; - m_ClockDiffPrim = 0.0; - m_ClockDiffCalc = 0.0; - - m_ModeratedTimeSpeed = 1.0; - m_ModeratedTimeSpeedDiff = 0.0; - m_ModeratedTimeSpeedPrim = 0; - ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory)); - ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory)); - m_ClockTimeChangeHistoryPos = 0; - - m_pSprite = nullptr; - m_pLine = nullptr; - m_pFont = nullptr; - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - m_pDirectDraw = nullptr; - - m_bAlphaBitmapEnable = false; - m_pAlphaBitmapTexture.Release(); - ZeroMemory(&m_AlphaBitmapParams, sizeof(m_AlphaBitmapParams)); - - CleanupRenderingEngine(); - - UINT currentAdapter = GetAdapter(m_pD3D); - bool bTryToReset = (currentAdapter == m_CurrentAdapter); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - m_CurrentAdapter = currentAdapter; - } - - if (!m_pD3D) { - _Error += L"Failed to create D3D9\n"; - return E_UNEXPECTED; - } - - HRESULT hr = S_OK; - - /*// TODO : add NVIDIA PerfHUD !!! - - // Set default settings - UINT AdapterToUse=D3DADAPTER_DEFAULT; - D3DDEVTYPE DeviceType=D3DDEVTYPE_HAL; - - #if SHIPPING_VERSION - // When building a shipping version, disable PerfHUD (opt-out) - #else - // Look for 'NVIDIA PerfHUD' adapter - // If it is present, override default settings - for (UINT Adapter=0;AdapterGetAdapterCount();Adapter++) - { - D3DADAPTER_IDENTIFIER9 Identifier; - HRESULT Res; - - Res = g_pD3D->GetAdapterIdentifier(Adapter,0,&Identifier); - if (strstr(Identifier.Description,"PerfHUD") != 0) - { - AdapterToUse=Adapter; - DeviceType=D3DDEVTYPE_REF; - break; - } - } - #endif - - if (FAILED(g_pD3D->CreateDevice( AdapterToUse, DeviceType, hWnd, - D3DCREATE_HARDWARE_VERTEXPROCESSING, - &d3dpp, &g_pd3dDevice) ) ) - { - return E_FAIL; - } - */ - - - //#define ENABLE_DDRAWSYNC -#ifdef ENABLE_DDRAWSYNC - hr = DirectDrawCreate(nullptr, &m_pDirectDraw, nullptr); - if (hr == S_OK) { - hr = m_pDirectDraw->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL); - } -#endif - - D3DPRESENT_PARAMETERS pp; - ZeroMemory(&pp, sizeof(pp)); - - BOOL bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - - m_bCompositionEnabled = !!bCompositionEnabled; - m_bAlternativeVSync = r.m_AdvRendSets.bVMR9AlterativeVSync; - - // detect FP16 textures support - rd->m_bFP16Support = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_VOLUMETEXTURE, D3DFMT_A16B16G16R16F)); - - // detect FP32 textures support - rd->m_bFP32Support = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_VOLUMETEXTURE, D3DFMT_A32B32G32R32F)); - - // detect 10-bit textures support - rd->m_b10bitSupport = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, D3DFMT_A2R10G10B10)); - - // detect 10-bit device support - bool bHighColorSupport = SUCCEEDED(m_pD3D->CheckDeviceType(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_A2R10G10B10, D3DFMT_A2R10G10B10, FALSE)); - - // set settings that depend on hardware feature support - m_bForceInputHighColorResolution = r.m_AdvRendSets.bEVRForceInputHighColorResolution && m_bIsEVR && rd->m_b10bitSupport; - m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution && m_bIsEVR && rd->m_b10bitSupport && bHighColorSupport; - m_bFullFloatingPointProcessing = r.m_AdvRendSets.bVMR9FullFloatingPointProcessing && rd->m_bFP32Support; - m_bHalfFloatingPointProcessing = r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing && rd->m_bFP16Support && !m_bFullFloatingPointProcessing; - - // set color formats - if (m_bFullFloatingPointProcessing) { - m_SurfaceType = D3DFMT_A32B32G32R32F; - } else if (m_bHalfFloatingPointProcessing) { - m_SurfaceType = D3DFMT_A16B16G16R16F; - } else if (m_bForceInputHighColorResolution || m_bHighColorResolution) { - m_SurfaceType = D3DFMT_A2R10G10B10; - } else { - m_SurfaceType = D3DFMT_X8R8G8B8; - } - - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - - D3DDISPLAYMODEEX DisplayMode; - ZeroMemory(&DisplayMode, sizeof(DisplayMode)); - DisplayMode.Size = sizeof(DisplayMode); - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - - if (m_bIsFullscreen) { - if (m_bHighColorResolution) { - pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } else { - pp.BackBufferFormat = D3DFMT_X8R8G8B8; - } - pp.Windowed = false; - pp.BackBufferCount = 3; - pp.SwapEffect = D3DSWAPEFFECT_FLIP; - // there's no Desktop composition to take care of alternative vSync in exclusive mode, alternative vSync is therefore unused - pp.hDeviceWindow = m_hWnd; - pp.Flags = D3DPRESENTFLAG_VIDEO; - if (r.m_AdvRendSets.bVMR9FullscreenGUISupport && !m_bHighColorResolution) { - pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; - } - m_D3DDevExError = _T("No m_pD3DEx"); - - if (!m_FocusThread) { - m_FocusThread = (CFocusThread*)AfxBeginThread(RUNTIME_CLASS(CFocusThread), 0, 0, 0); - } - - HWND hFocusWindow = m_FocusThread->GetFocusWindow(); - bTryToReset &= (m_hFocusWindow == hFocusWindow || fullScreenChanged); - m_hFocusWindow = hFocusWindow; - - if (m_pD3DEx) { - CHECK_HR(m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr)); - - m_ScreenSize.SetSize(DisplayMode.Width, DisplayMode.Height); - m_BackBufferSize = m_ScreenSize; - - DisplayMode.Format = pp.BackBufferFormat; - pp.FullScreen_RefreshRateInHz = m_refreshRate = DisplayMode.RefreshRate; - pp.BackBufferWidth = m_BackBufferSize.cx; - pp.BackBufferHeight = m_BackBufferSize.cy; - - bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&pp, &DisplayMode)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - hr = m_pD3DEx->CreateDeviceEx( - m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS | D3DCREATE_NOWINDOWCHANGES, //D3DCREATE_MANAGED - &pp, &DisplayMode, &m_pD3DDevEx); - } - - if (FAILED(hr)) { - m_D3DDevExError = GetWindowsErrorMessage(hr, nullptr); - } else { - m_D3DDevExError.Empty(); - } - - if (m_pD3DDevEx) { - m_pD3DDev = m_pD3DDevEx; - m_BackbufferType = pp.BackBufferFormat; - m_DisplayType = DisplayMode.Format; - } - } - if (bTryToReset && m_pD3DDev && !m_pD3DDevEx) { - if (FAILED(hr = m_pD3DDev->Reset(&pp))) { - m_pD3DDev = nullptr; - } - } - if (!m_pD3DDev) { - CHECK_HR(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)); - d3ddm.Format = pp.BackBufferFormat; - - m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); - m_BackBufferSize = m_ScreenSize; - - pp.FullScreen_RefreshRateInHz = m_refreshRate = d3ddm.RefreshRate; - pp.BackBufferWidth = m_BackBufferSize.cx; - pp.BackBufferHeight = m_BackBufferSize.cy; - - hr = m_pD3D->CreateDevice( - m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_NOWINDOWCHANGES, //D3DCREATE_MANAGED - &pp, &m_pD3DDev); - m_DisplayType = d3ddm.Format; - m_BackbufferType = pp.BackBufferFormat; - } - if (m_pD3DDev && r.m_AdvRendSets.bVMR9FullscreenGUISupport && !m_bHighColorResolution) { - m_pD3DDev->SetDialogBoxMode(true); - //if (m_pD3DDev->SetDialogBoxMode(true) != S_OK) - // ExitProcess(0); - } - } else { - pp.Windowed = TRUE; - pp.hDeviceWindow = m_hWnd; - pp.SwapEffect = D3DSWAPEFFECT_COPY; - pp.Flags = D3DPRESENTFLAG_VIDEO; - pp.BackBufferCount = 1; - if (bCompositionEnabled || m_bAlternativeVSync) { - // Desktop composition takes care of the VSYNC - pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - } - - bTryToReset &= (m_hFocusWindow == m_hWnd || fullScreenChanged); - m_hFocusWindow = m_hWnd; - - if (m_pD3DEx) { - HRESULT getModeResult = m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); - - if (getModeResult == D3DERR_NOTAVAILABLE) { - m_pD3DEx = nullptr; - Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); - if (nullptr != m_pD3DEx) { - getModeResult = m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); - } - } - CHECK_HR(getModeResult); - - m_ScreenSize.SetSize(DisplayMode.Width, DisplayMode.Height); - m_refreshRate = DisplayMode.RefreshRate; - m_BackBufferSize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); - pp.BackBufferWidth = m_BackBufferSize.cx; - pp.BackBufferHeight = m_BackBufferSize.cy; - - bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&pp, nullptr)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - // We can get 0x8876086a here when switching from two displays to one display using Win + P (Windows 7) - // Cause: We might not reinitialize dx correctly during the switch - hr = m_pD3DEx->CreateDeviceEx( - m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS, //D3DCREATE_MANAGED - &pp, nullptr, &m_pD3DDevEx); - } - if (m_pD3DDevEx) { - m_pD3DDev = m_pD3DDevEx; - m_DisplayType = DisplayMode.Format; - } - } - if (bTryToReset && m_pD3DDev && !m_pD3DDevEx) { - if (FAILED(hr = m_pD3DDev->Reset(&pp))) { - m_pD3DDev = nullptr; - } - } - if (!m_pD3DDev) { - CHECK_HR(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)); - m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); - m_refreshRate = d3ddm.RefreshRate; - m_BackBufferSize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); - pp.BackBufferWidth = m_BackBufferSize.cx; - pp.BackBufferHeight = m_BackBufferSize.cy; - - hr = m_pD3D->CreateDevice( - m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED - &pp, &m_pD3DDev); - m_DisplayType = d3ddm.Format; - } - m_BackbufferType = pp.BackBufferFormat; - } - - if (m_pD3DDev) { - while (hr == D3DERR_DEVICELOST) { - TRACE(_T("D3DERR_DEVICELOST. Trying to Reset.\n")); - hr = m_pD3DDev->TestCooperativeLevel(); - } - if (hr == D3DERR_DEVICENOTRESET) { - TRACE(_T("D3DERR_DEVICENOTRESET\n")); - hr = m_pD3DDev->Reset(&pp); - } - - if (m_pD3DDevEx) { - m_pD3DDevEx->SetGPUThreadPriority(7); - } - } - - if (FAILED(hr)) { - _Error += L"CreateDevice failed\n"; - CStringW str; - str.Format(L"Error code: 0x%X\n", hr); - _Error += str; - - return hr; - } - - ASSERT(m_pD3DDev); - - if (m_ScreenSize.cx <= 0 || m_ScreenSize.cy <= 0) { - _Error += L"Invalid screen size\n"; - return E_FAIL; - } - - m_MainThreadId = GetCurrentThreadId(); - - // Get the device caps - ZeroMemory(&m_Caps, sizeof(m_Caps)); - m_pD3DDev->GetDeviceCaps(&m_Caps); - - // Initialize the rendering engine - InitRenderingEngine(); - - if (!m_bIsPreview) { - CComPtr pSubPicProvider; - if (m_pSubPicQueue) { - m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); - } - - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(m_pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); - } - - hr = S_OK; - if (!m_pSubPicQueue) { - CAutoLock cAutoLock(this); - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - m_pSubPicQueue->Invalidate(); - } - - if (FAILED(hr)) { - _Error += L"m_pSubPicQueue failed\n"; - - return hr; - } - - if (pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); - } - } - - m_LastAdapterCheck = rd->GetPerfCounter(); - - return S_OK; -} - -HRESULT CDX9AllocatorPresenter::AllocSurfaces() -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - return CreateVideoSurfaces(); -} - -void CDX9AllocatorPresenter::DeleteSurfaces() -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - FreeVideoSurfaces(); -} - -UINT CDX9AllocatorPresenter::GetAdapter(IDirect3D9* pD3D, bool bGetAdapter) -{ - if (m_hWnd == nullptr || pD3D == nullptr) { - return D3DADAPTER_DEFAULT; - } - - m_D3D9Device = _T(""); - - const CRenderersSettings& r = GetRenderersSettings(); - if (bGetAdapter && (pD3D->GetAdapterCount() > 1) && !r.D3D9RenderDevice.IsEmpty()) { - TCHAR strGUID[50]; - D3DADAPTER_IDENTIFIER9 adapterIdentifier; - - for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { - if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK) { - if ((::StringFromGUID2(adapterIdentifier.DeviceIdentifier, strGUID, 50) > 0) && (r.D3D9RenderDevice == strGUID)) { - m_D3D9Device = adapterIdentifier.Description; - return adp; - } - } - } - } - - HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); - if (hMonitor == nullptr) { - return D3DADAPTER_DEFAULT; - } - - for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { - HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp); - if (hAdpMon == hMonitor) { - if (bGetAdapter) { - D3DADAPTER_IDENTIFIER9 adapterIdentifier; - if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK) { - m_D3D9Device = adapterIdentifier.Description; - } - } - return adp; - } - } - - return D3DADAPTER_DEFAULT; -} - -DWORD CDX9AllocatorPresenter::GetVertexProcessing() -{ - HRESULT hr; - D3DCAPS9 caps; - - hr = m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &caps); - if (FAILED(hr)) { - return D3DCREATE_SOFTWARE_VERTEXPROCESSING; - } - - if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 || - caps.VertexShaderVersion < D3DVS_VERSION(2, 0)) { - return D3DCREATE_SOFTWARE_VERTEXPROCESSING; - } - - return D3DCREATE_HARDWARE_VERTEXPROCESSING; -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP CDX9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - return E_NOTIMPL; -} - -void CDX9AllocatorPresenter::CalculateJitter(LONGLONG PerfCounter) -{ - // Calculate the jitter! - LONGLONG llPerf = PerfCounter; - if ((m_rtTimePerFrame != 0) && (labs((long)(llPerf - m_llLastPerf)) < m_rtTimePerFrame * 3)) { - m_nNextJitter = (m_nNextJitter + 1) % NB_JITTER; - m_pllJitter[m_nNextJitter] = llPerf - m_llLastPerf; - - m_MaxJitter = MINLONG64; - m_MinJitter = MAXLONG64; - - // Calculate the real FPS - LONGLONG llJitterSum = 0; - LONGLONG llJitterSumAvg = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG Jitter = m_pllJitter[i]; - llJitterSum += Jitter; - llJitterSumAvg += Jitter; - } - double FrameTimeMean = double(llJitterSumAvg) / NB_JITTER; - m_fJitterMean = FrameTimeMean; - double DeviationSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG DevInt = m_pllJitter[i] - (LONGLONG)FrameTimeMean; - double Deviation = (double)DevInt; - DeviationSum += Deviation * Deviation; - m_MaxJitter = std::max(m_MaxJitter, DevInt); - m_MinJitter = std::min(m_MinJitter, DevInt); - } - double StdDev = sqrt(DeviationSum / NB_JITTER); - - m_fJitterStdDev = StdDev; - m_fAvrFps = 10000000.0 / (double(llJitterSum) / NB_JITTER); - } - - m_llLastPerf = llPerf; -} - -bool CDX9AllocatorPresenter::GetVBlank(int& _ScanLine, int& _bInVBlank, bool _bMeasureTime) -{ - LONGLONG llPerf = 0; - if (_bMeasureTime) { - llPerf = GetRenderersData()->GetPerfCounter(); - } - - int ScanLine = 0; - _ScanLine = 0; - _bInVBlank = 0; - - if (m_pDirectDraw) { - DWORD ScanLineGet = 0; - m_pDirectDraw->GetScanLine(&ScanLineGet); - BOOL InVBlank; - if (m_pDirectDraw->GetVerticalBlankStatus(&InVBlank) != S_OK) { - return false; - } - ScanLine = ScanLineGet; - _bInVBlank = InVBlank; - if (InVBlank) { - ScanLine = 0; - } - } else { - D3DRASTER_STATUS RasterStatus; - if (m_pD3DDev->GetRasterStatus(0, &RasterStatus) != S_OK) { - return false; - } - ScanLine = RasterStatus.ScanLine; - _bInVBlank = RasterStatus.InVBlank; - } - if (_bMeasureTime) { - m_VBlankMax = std::max(m_VBlankMax, ScanLine); - if (ScanLine != 0 && !_bInVBlank) { - m_VBlankMinCalc = std::min(m_VBlankMinCalc, ScanLine); - } - m_VBlankMin = m_VBlankMax - m_ScreenSize.cy; - } - if (_bInVBlank) { - _ScanLine = 0; - } else if (m_VBlankMin != 300000) { - _ScanLine = ScanLine - m_VBlankMin; - } else { - _ScanLine = ScanLine; - } - - if (_bMeasureTime) { - LONGLONG Time = GetRenderersData()->GetPerfCounter() - llPerf; - if (Time > 5000000) { // 0.5 sec - TRACE(_T("GetVBlank too long (%f sec)\n"), Time / 10000000.0); - } - m_RasterStatusWaitTimeMaxCalc = std::max(m_RasterStatusWaitTimeMaxCalc, Time); - } - - return true; -} - -bool CDX9AllocatorPresenter::WaitForVBlankRange(int& _RasterStart, int _RasterSize, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, HANDLE& lockOwner) -{ - if (_bMeasure) { - m_RasterStatusWaitTimeMaxCalc = 0; - } - bool bWaited = false; - int ScanLine = 0; - int InVBlank = 0; - LONGLONG llPerf = 0; - if (_bMeasure) { - llPerf = GetRenderersData()->GetPerfCounter(); - } - GetVBlank(ScanLine, InVBlank, _bMeasure); - if (_bMeasure) { - m_VBlankStartWait = ScanLine; - } - - static bool bOneWait = true; - if (bOneWait && _bMeasure) { - bOneWait = false; - // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate - int nInVBlank = 0; - for (;;) { - if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { - break; - } - - if (InVBlank && nInVBlank == 0) { - nInVBlank = 1; - } else if (!InVBlank && nInVBlank == 1) { - nInVBlank = 2; - } else if (InVBlank && nInVBlank == 2) { - nInVBlank = 3; - } else if (!InVBlank && nInVBlank == 3) { - break; - } - } - } - if (_bWaitIfInside) { - int ScanLineDiff = long(ScanLine) - _RasterStart; - if (ScanLineDiff > m_ScreenSize.cy / 2) { - ScanLineDiff -= m_ScreenSize.cy; - } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { - ScanLineDiff += m_ScreenSize.cy; - } - - if (ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) { - bWaited = true; - // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate - int LastLineDiff = ScanLineDiff; - for (;;) { - if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { - break; - } - ScanLineDiff = long(ScanLine) - _RasterStart; - if (ScanLineDiff > m_ScreenSize.cy / 2) { - ScanLineDiff -= m_ScreenSize.cy; - } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { - ScanLineDiff += m_ScreenSize.cy; - } - if (!(ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0)) { - break; - } - LastLineDiff = ScanLineDiff; - Sleep(1); // Just sleep - } - } - } - double RefreshRate = GetRefreshRate(); - LONG ScanLines = GetScanLines(); - int MinRange = std::max(std::min(long(0.0015 * ScanLines * RefreshRate + 0.5), ScanLines / 3l), 5l); // 1.5 ms or max 33 % of Time - int NoSleepStart = _RasterStart - MinRange; - int NoSleepRange = MinRange; - if (NoSleepStart < 0) { - NoSleepStart += m_ScreenSize.cy; - } - - int MinRange2 = std::max(std::min(long(0.0050 * ScanLines * RefreshRate + 0.5), ScanLines / 3l), 5l); // 5 ms or max 33 % of Time - int D3DDevLockStart = _RasterStart - MinRange2; - int D3DDevLockRange = MinRange2; - if (D3DDevLockStart < 0) { - D3DDevLockStart += m_ScreenSize.cy; - } - - int ScanLineDiff = ScanLine - _RasterStart; - if (ScanLineDiff > m_ScreenSize.cy / 2) { - ScanLineDiff -= m_ScreenSize.cy; - } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { - ScanLineDiff += m_ScreenSize.cy; - } - int LastLineDiff = ScanLineDiff; - - - int ScanLineDiffSleep = long(ScanLine) - NoSleepStart; - if (ScanLineDiffSleep > m_ScreenSize.cy / 2) { - ScanLineDiffSleep -= m_ScreenSize.cy; - } else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2) { - ScanLineDiffSleep += m_ScreenSize.cy; - } - int LastLineDiffSleep = ScanLineDiffSleep; - - - int ScanLineDiffLock = long(ScanLine) - D3DDevLockStart; - if (ScanLineDiffLock > m_ScreenSize.cy / 2) { - ScanLineDiffLock -= m_ScreenSize.cy; - } else if (ScanLineDiffLock < -m_ScreenSize.cy / 2) { - ScanLineDiffLock += m_ScreenSize.cy; - } - int LastLineDiffLock = ScanLineDiffLock; - - LONGLONG llPerfLock = 0; - - for (;;) { - if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { - break; - } - ScanLineDiff = long(ScanLine) - _RasterStart; - if (ScanLineDiff > m_ScreenSize.cy / 2) { - ScanLineDiff -= m_ScreenSize.cy; - } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { - ScanLineDiff += m_ScreenSize.cy; - } - if ((ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0)) { - break; - } - - LastLineDiff = ScanLineDiff; - - bWaited = true; - - ScanLineDiffLock = long(ScanLine) - D3DDevLockStart; - if (ScanLineDiffLock > m_ScreenSize.cy / 2) { - ScanLineDiffLock -= m_ScreenSize.cy; - } else if (ScanLineDiffLock < -m_ScreenSize.cy / 2) { - ScanLineDiffLock += m_ScreenSize.cy; - } - - if (((ScanLineDiffLock >= 0 && ScanLineDiffLock <= D3DDevLockRange) || (LastLineDiffLock < 0 && ScanLineDiffLock > 0))) { - if (!lockOwner && _bMeasure) { - llPerfLock = GetRenderersData()->GetPerfCounter(); - lockOwner = LockD3DDevice(); - } - } - LastLineDiffLock = ScanLineDiffLock; - - - ScanLineDiffSleep = long(ScanLine) - NoSleepStart; - if (ScanLineDiffSleep > m_ScreenSize.cy / 2) { - ScanLineDiffSleep -= m_ScreenSize.cy; - } else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2) { - ScanLineDiffSleep += m_ScreenSize.cy; - } - - if (!((ScanLineDiffSleep >= 0 && ScanLineDiffSleep <= NoSleepRange) || (LastLineDiffSleep < 0 && ScanLineDiffSleep > 0)) || !_bNeedAccurate) { - //TRACE(_T("%d\n"), RasterStatus.ScanLine); - Sleep(1); // Don't sleep for the last 1.5 ms scan lines, so we get maximum precision - } - LastLineDiffSleep = ScanLineDiffSleep; - } - _RasterStart = ScanLine; - if (_bMeasure) { - m_VBlankEndWait = ScanLine; - m_VBlankWaitTime = GetRenderersData()->GetPerfCounter() - llPerf; - - if (lockOwner) { - m_VBlankLockTime = GetRenderersData()->GetPerfCounter() - llPerfLock; - } else { - m_VBlankLockTime = 0; - } - - m_RasterStatusWaitTime = m_RasterStatusWaitTimeMaxCalc; - m_RasterStatusWaitTimeMin = std::min(m_RasterStatusWaitTimeMin, m_RasterStatusWaitTime); - m_RasterStatusWaitTimeMax = std::max(m_RasterStatusWaitTimeMax, m_RasterStatusWaitTime); - } - - return bWaited; -} - -int CDX9AllocatorPresenter::GetVBlackPos() -{ - BOOL bCompositionEnabled = m_bCompositionEnabled; - - int WaitRange = std::max(m_ScreenSize.cy / 40l, 5l); - if (!bCompositionEnabled) { - if (m_bAlternativeVSync) { - const CRenderersSettings& r = GetRenderersSettings(); - return r.m_AdvRendSets.iVMR9VSyncOffset; - } else { - int MinRange = std::max(std::min(long(0.005 * m_ScreenSize.cy * GetRefreshRate() + 0.5), m_ScreenSize.cy / 3l), 5l); // 5 ms or max 33 % of Time - int WaitFor = m_ScreenSize.cy - (MinRange + WaitRange); - return WaitFor; - } - } else { - int WaitFor = m_ScreenSize.cy / 2; - return WaitFor; - } -} - -bool CDX9AllocatorPresenter::WaitForVBlank(bool& _Waited, HANDLE& lockOwner) -{ - const CRenderersSettings& r = GetRenderersSettings(); - if (!r.m_AdvRendSets.bVMR9VSync) { - _Waited = true; - m_VBlankWaitTime = 0; - m_VBlankLockTime = 0; - m_VBlankEndWait = 0; - m_VBlankStartWait = 0; - return true; - } - //_Waited = true; - //return false; - - BOOL bCompositionEnabled = m_bCompositionEnabled; - int WaitFor = GetVBlackPos(); - - if (!bCompositionEnabled) { - if (m_bAlternativeVSync) { - _Waited = WaitForVBlankRange(WaitFor, 0, false, true, true, lockOwner); - return false; - } else { - _Waited = WaitForVBlankRange(WaitFor, 0, false, r.m_AdvRendSets.bVMR9VSyncAccurate, true, lockOwner); - return true; - } - } else { - // Instead we wait for VBlack after the present, this seems to fix the stuttering problem. It'r also possible to fix by removing the Sleep above, but that isn't an option. - WaitForVBlankRange(WaitFor, 0, false, r.m_AdvRendSets.bVMR9VSyncAccurate, true, lockOwner); - - return false; - } -} - -void CDX9AllocatorPresenter::UpdateAlphaBitmap() -{ - m_VMR9AlphaBitmapData.Free(); - - if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0) { - HBITMAP hBitmap = (HBITMAP)GetCurrentObject(m_VMR9AlphaBitmap.hdc, OBJ_BITMAP); - if (!hBitmap) { - return; - } - DIBSECTION info; - ZeroMemory(&info, sizeof(DIBSECTION)); - if (!::GetObject(hBitmap, sizeof(DIBSECTION), &info)) { - return; - } - - m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight); - m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes; - - if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight)) { - memcpy((BYTE*)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight); - } - } -} - -STDMETHODIMP_(bool) CDX9AllocatorPresenter::Paint(bool bAll) -{ - if (m_bPendingResetDevice) { - SendResetRequest(); - return false; - } - - CRenderersSettings& r = GetRenderersSettings(); - if (&r == nullptr) { - return false; - } - - //TRACE(_T("Thread: %d\n"), (LONG)((CRITICAL_SECTION &)m_RenderLock).OwningThread); - -#if 0 - if (TryEnterCriticalSection(&(CRITICAL_SECTION&)(*((CCritSec*)this)))) { - LeaveCriticalSection((&(CRITICAL_SECTION&)(*((CCritSec*)this)))); - } else { - __debugbreak(); - } -#endif - - CRenderersData* rd = GetRenderersData(); - - LONGLONG StartPaint = rd->GetPerfCounter(); - CAutoLock cRenderLock(&m_RenderLock); - - if (m_windowRect.right <= m_windowRect.left || m_windowRect.bottom <= m_windowRect.top - || m_nativeVideoSize.cx <= 0 || m_nativeVideoSize.cy <= 0 - || !m_pVideoSurface[m_nCurSurface]) { - if (m_OrderedPaint) { - --m_OrderedPaint; - } else { - //TRACE(_T("UNORDERED PAINT!!!!!!\n")); - } - - - return false; - } - - HRESULT hr; - - m_pD3DDev->BeginScene(); - - CComPtr pBackBuffer; - m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); - // FIXME: GetBackBuffer can fail, check return value and reset device - - // Clear the backbuffer - m_pD3DDev->SetRenderTarget(0, pBackBuffer); - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); - - CRect rSrcVid(CPoint(0, 0), GetVisibleVideoSize()); - CRect rDstVid(m_videoRect); - - CRect rSrcPri(CPoint(0, 0), m_windowRect.Size()); - CRect rDstPri(rSrcPri); - - // Render the current video frame - hr = RenderVideo(pBackBuffer, rSrcVid, rDstVid); - - if (FAILED(hr)) { - if (m_RenderingPath == RENDERING_PATH_STRETCHRECT) { - // Support ffdshow queueing - // m_pD3DDev->StretchRect may fail if ffdshow is using queue output samples. - // Here we don't want to show the black buffer. - if (m_OrderedPaint) { - --m_OrderedPaint; - } else { - //TRACE(_T("UNORDERED PAINT!!!!!!\n")); - } - - return false; - } - } - - if (!m_bIsPreview) { - // paint the text on the backbuffer - AlphaBltSubPic(rDstPri, rDstVid); - - // Casimir666 : show OSD - if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE) { - CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock); - CRect rcSrc(m_VMR9AlphaBitmap.rSrc); - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE*)m_VMR9AlphaBitmapData) { - if ((m_pD3DXLoadSurfaceFromMemory != nullptr) && - SUCCEEDED(hr = m_pD3DDev->CreateTexture(rcSrc.Width(), rcSrc.Height(), 1, - D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, &m_pOSDTexture, nullptr))) { - if (SUCCEEDED(hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface))) { - hr = m_pD3DXLoadSurfaceFromMemory(m_pOSDSurface, - nullptr, - nullptr, - (BYTE*)m_VMR9AlphaBitmapData, - D3DFMT_A8R8G8B8, - m_VMR9AlphaBitmapWidthBytes, - nullptr, - &m_VMR9AlphaBitmapRect, - D3DX_FILTER_NONE, - m_VMR9AlphaBitmap.clrSrcKey); - } - if (FAILED(hr)) { - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - } - } - } - m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE; - - } - - if (m_bAlphaBitmapEnable && m_pAlphaBitmapTexture) { - CRect rcDst(rSrcPri); - AlphaBlt(rSrcPri, rcDst, m_pAlphaBitmapTexture); - } - - if (rd->m_bResetStats) { - ResetStats(); - rd->m_bResetStats = false; - } - - if (rd->m_iDisplayStats) { - DrawStats(); - } - - if (m_pOSDTexture) { - AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture); - } - } - - m_pD3DDev->EndScene(); - - BOOL bCompositionEnabled = m_bCompositionEnabled; - - bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !r.m_AdvRendSets.bVMR9VSync; - - CComPtr pEventQueryFlushBeforeVSync; - m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQueryFlushBeforeVSync); - if (pEventQueryFlushBeforeVSync) { - pEventQueryFlushBeforeVSync->Issue(D3DISSUE_END); - } - - if (r.m_AdvRendSets.bVMRFlushGPUBeforeVSync && pEventQueryFlushBeforeVSync) { - LONGLONG llPerf = rd->GetPerfCounter(); - BOOL Data; - //Sleep(5); - LONGLONG FlushStartTime = rd->GetPerfCounter(); - while (S_FALSE == pEventQueryFlushBeforeVSync->GetData(&Data, sizeof(Data), D3DGETDATA_FLUSH)) { - if (!r.m_AdvRendSets.bVMRFlushGPUWait) { - break; - } - Sleep(1); - if (rd->GetPerfCounter() - FlushStartTime > 500000) { - break; // timeout after 50 ms - } - } - if (r.m_AdvRendSets.bVMRFlushGPUWait) { - m_WaitForGPUTime = rd->GetPerfCounter() - llPerf; - } else { - m_WaitForGPUTime = 0; - } - } else { - m_WaitForGPUTime = 0; - } - - if (bAll) { - m_PaintTime = (rd->GetPerfCounter() - StartPaint); - m_PaintTimeMin = std::min(m_PaintTimeMin, m_PaintTime); - m_PaintTimeMax = std::max(m_PaintTimeMax, m_PaintTime); - } - - bool bWaited = false; - HANDLE lockOwner = nullptr; - if (bAll) { - // Only sync to refresh when redrawing all - bool bTest = WaitForVBlank(bWaited, lockOwner); - ASSERT(bTest == bDoVSyncInPresent); - if (!bDoVSyncInPresent) { - LONGLONG Time = rd->GetPerfCounter(); - OnVBlankFinished(bAll, Time); - if (!m_bIsEVR || m_OrderedPaint) { - CalculateJitter(Time); - } - } - } - - // Create a device pointer m_pd3dDevice - - // Create a query object - { - CComPtr pEventQueryFlushAfterVSync; - m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQueryFlushAfterVSync); - - LONGLONG llPerf = rd->GetPerfCounter(); - CRect presentationSrcRect(rDstPri), presentationDestRect(m_windowRect); - // PresentEx() / Present() performs the clipping - // TODO: fix the race and uncomment the assert - //ASSERT(presentationSrcRect.Size() == presentationDestRect.Size()); - if (m_pD3DDevEx) { - if (m_bIsFullscreen) { - hr = m_pD3DDevEx->PresentEx(nullptr, nullptr, nullptr, nullptr, 0); - } else { - hr = m_pD3DDevEx->PresentEx(presentationSrcRect, presentationDestRect, nullptr, nullptr, 0); - } - } else { - if (m_bIsFullscreen) { - hr = m_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr); - } else { - hr = m_pD3DDev->Present(presentationSrcRect, presentationDestRect, nullptr, nullptr); - } - } - // Issue an End event - if (pEventQueryFlushAfterVSync) { - pEventQueryFlushAfterVSync->Issue(D3DISSUE_END); - } - - BOOL Data; - - if (r.m_AdvRendSets.bVMRFlushGPUAfterPresent && pEventQueryFlushAfterVSync) { - LONGLONG FlushStartTime = rd->GetPerfCounter(); - while (S_FALSE == pEventQueryFlushAfterVSync->GetData(&Data, sizeof(Data), D3DGETDATA_FLUSH)) { - if (!r.m_AdvRendSets.bVMRFlushGPUWait) { - break; - } - if (rd->GetPerfCounter() - FlushStartTime > 500000) { - break; // timeout after 50 ms - } - } - } - - int ScanLine; - int bInVBlank; - GetVBlank(ScanLine, bInVBlank, false); - - if (bAll && (!m_bIsEVR || m_OrderedPaint)) { - m_VBlankEndPresent = ScanLine; - } - - while (ScanLine == 0 || bInVBlank) { - GetVBlank(ScanLine, bInVBlank, false); - - } - m_VBlankStartMeasureTime = rd->GetPerfCounter(); - m_VBlankStartMeasure = ScanLine; - - if (bAll && bDoVSyncInPresent) { - m_PresentWaitTime = rd->GetPerfCounter() - llPerf; - m_PresentWaitTimeMin = std::min(m_PresentWaitTimeMin, m_PresentWaitTime); - m_PresentWaitTimeMax = std::max(m_PresentWaitTimeMax, m_PresentWaitTime); - } else { - m_PresentWaitTime = 0; - m_PresentWaitTimeMin = std::min(m_PresentWaitTimeMin, m_PresentWaitTime); - m_PresentWaitTimeMax = std::max(m_PresentWaitTimeMax, m_PresentWaitTime); - } - } - - if (bDoVSyncInPresent) { - LONGLONG Time = rd->GetPerfCounter(); - if (!m_bIsEVR || m_OrderedPaint) { - CalculateJitter(Time); - } - OnVBlankFinished(bAll, Time); - } - - if (lockOwner) { - UnlockD3DDevice(lockOwner); - } - - /*if (!bWaited) - { - bWaited = true; - WaitForVBlank(bWaited); - TRACE(_T("Double VBlank\n")); - ASSERT(bWaited); - if (!bDoVSyncInPresent) - { - CalculateJitter(); - OnVBlankFinished(bAll); - } - }*/ - - if (!m_bPendingResetDevice) { - bool fResetDevice = false; - - if (hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { - TRACE(_T("Reset Device: D3D Device Lost\n")); - fResetDevice = true; - } - - if (hr == S_PRESENT_MODE_CHANGED) { - TRACE(_T("Reset Device: D3D Device mode changed\n")); - fResetDevice = true; - } - - if (SettingsNeedResetDevice(r)) { - TRACE(_T("Reset Device: settings changed\n")); - fResetDevice = true; - } - - bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - if ((bCompositionEnabled != 0) != m_bCompositionEnabled) { - if (m_bIsFullscreen) { - m_bCompositionEnabled = (bCompositionEnabled != 0); - } else { - TRACE(_T("Reset Device: DWM composition changed\n")); - fResetDevice = true; - } - } - - if (r.fResetDevice) { - LONGLONG time = rd->GetPerfCounter(); - if (time > m_LastAdapterCheck + 20000000) { // check every 2 sec. - m_LastAdapterCheck = time; -#ifdef _DEBUG - D3DDEVICE_CREATION_PARAMETERS Parameters; - if (SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))) { - ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter); - } -#endif - if (m_CurrentAdapter != GetAdapter(m_pD3D)) { - TRACE(_T("Reset Device: D3D adapter changed\n")); - fResetDevice = true; - } -#ifdef _DEBUG - else { - ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D))); - } -#endif - } - } - - if (fResetDevice) { - m_bPendingResetDevice = true; - SendResetRequest(); - } - } - - if (m_OrderedPaint) { - --m_OrderedPaint; - } else { - //if (m_bIsEVR) - // TRACE(_T("UNORDERED PAINT!!!!!!\n")); - } - return true; -} - -double CDX9AllocatorPresenter::GetFrameTime() const -{ - if (m_DetectedLock) { - return m_DetectedFrameTime; - } - - return m_rtTimePerFrame / 10000000.0; -} - -double CDX9AllocatorPresenter::GetFrameRate() const -{ - if (m_DetectedLock) { - return m_DetectedFrameRate; - } - - return 10000000.0 / m_rtTimePerFrame; -} - -void CDX9AllocatorPresenter::SendResetRequest() -{ - if (!m_bDeviceResetRequested) { - m_bDeviceResetRequested = true; - AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE); - } -} - -STDMETHODIMP_(bool) CDX9AllocatorPresenter::ResetDevice() -{ - TRACE(_T("ResetDevice\n")); - ASSERT(m_MainThreadId == GetCurrentThreadId()); - - // In VMR-9 deleting the surfaces before we are told to is bad ! - // Can't comment out this because CDX9AllocatorPresenter is used by EVR Custom - // Why is EVR using a presenter for DX9 anyway ?! - DeleteSurfaces(); - - if (m_pD3DEx) { - m_pD3DEx.Release(); - m_pD3D = nullptr; - Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); - if (m_pD3DEx) { - m_pD3D = m_pD3DEx; - } else { - ASSERT(FALSE); - m_bDeviceResetRequested = false; - return false; - } - } - - HRESULT hr; - CString Error; - // TODO: Report error messages here - - // In VMR-9 'AllocSurfaces' call is redundant afaik because - // 'CreateDevice' calls 'm_pIVMRSurfAllocNotify->ChangeD3DDevice' which in turn calls - // 'CVMR9AllocatorPresenter::InitializeDevice' which calls 'AllocSurfaces' - if (FAILED(hr = CreateDevice(Error)) || FAILED(hr = AllocSurfaces())) { - // TODO: We should probably pause player -#ifdef _DEBUG - Error += GetWindowsErrorMessage(hr, nullptr); - TRACE(_T("D3D Reset Error\n%ws\n\n"), Error.GetBuffer()); -#endif - m_bDeviceResetRequested = false; - return false; - } - OnResetDevice(); - m_bDeviceResetRequested = false; - m_bPendingResetDevice = false; - - return true; -} - -STDMETHODIMP_(bool) CDX9AllocatorPresenter::DisplayChange() -{ - m_bPendingResetDevice = true; - SendResetRequest(); - return true; -} - -void CDX9AllocatorPresenter::ResetStats() -{ - CRenderersData* rd = GetRenderersData(); - LONGLONG Time = rd->GetPerfCounter(); - - m_PaintTime = 0; - m_PaintTimeMin = 3000000000; - m_PaintTimeMax = 0; - - m_RasterStatusWaitTime = 0; - m_RasterStatusWaitTimeMin = 3000000000; - m_RasterStatusWaitTimeMax = 0; - - m_MinSyncOffset = 0; - m_MaxSyncOffset = 0; - m_fSyncOffsetAvr = 0; - m_fSyncOffsetStdDev = 0; - - CalculateJitter(Time); -} - -void CDX9AllocatorPresenter::InitStats() -{ - ASSERT(m_pD3DDev); - static LONG currentHeight = 0; - int newHeight = lround(FONT_HEIGHT * (double(m_windowRect.Width()) / REFERENCE_WIDTH)); - - if (m_pD3DXCreateFont && (!m_pFont || currentHeight != newHeight)) { - m_pFont = nullptr; - if (newHeight <= 0) { - ASSERT(FALSE); - } - m_pD3DXCreateFont(m_pD3DDev, newHeight, 0, newHeight < BOLD_THRESHOLD ? FW_NORMAL : FW_BOLD, - 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, - FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont); - currentHeight = newHeight; - } - - if (m_pD3DXCreateSprite && !m_pSprite) { - m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite); - } - - if (m_pD3DXCreateLine && !m_pLine) { - m_pD3DXCreateLine(m_pD3DDev, &m_pLine); - } -} - -void CDX9AllocatorPresenter::DrawStats() -{ - const CRenderersData* rd = GetRenderersData(); - - int iDetailedStats; - switch (rd->m_iDisplayStats) { - case 1: - iDetailedStats = 2; - break; - case 2: - iDetailedStats = 1; - break; - case 3: - iDetailedStats = 0; - break; - default: - ASSERT(FALSE); - return; - } - - InitStats(); - const float textScale = float(m_windowRect.Width()) / REFERENCE_WIDTH; - const int lineHeight = lround((FONT_HEIGHT + TEXT_PADDING) * textScale); - - if (m_pFont && m_pSprite) { - auto drawText = [&](CRect & rc, const CString & strText) { - D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f); - D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f); - - RECT shadowRect = rc; - OffsetRect(&shadowRect, 2, 2); - - // Draw shadow - m_pFont->DrawText(m_pSprite, strText, -1, &shadowRect, DT_NOCLIP, Color0); - // Draw text - m_pFont->DrawText(m_pSprite, strText, -1, rc, DT_NOCLIP, Color1); - rc.OffsetRect(0, lineHeight); - }; - - const CRenderersSettings& r = GetRenderersSettings(); - LONGLONG llMaxJitter = m_MaxJitter; - LONGLONG llMinJitter = m_MinJitter; - LONGLONG llMaxSyncOffset = m_MaxSyncOffset; - LONGLONG llMinSyncOffset = m_MinSyncOffset; - CRect rc(lineHeight, lineHeight, 0, 0); - - m_pSprite->Begin(D3DXSPRITE_ALPHABLEND); - CString strText; - if (iDetailedStats > 1) { - if (m_bIsEVR) { - strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s) (%7.3f ms = %.03f%s, %2.03f StdDev) Clock: %1.4f %%", - m_fAvrFps, - double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), - m_bInterlaced ? L"I" : L"P", GetFrameTime() * 1000.0, GetFrameRate(), - m_DetectedLock ? L" L" : L"", m_DetectedFrameTimeStdDev / 10000.0, - m_ModeratedTimeSpeed * 100.0); - } else { - strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s)", - m_fAvrFps, - double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), - m_bInterlaced ? L"I" : L"P"); - } - } else { - strText.Format(L"Frame rate : %7.03f (%.03f%s)", m_fAvrFps, GetFrameRate(), m_DetectedLock ? L" L" : L""); - } - drawText(rc, strText); - - if (iDetailedStats > 1) { - strText = _T("Settings : "); - - if (m_bIsEVR) { - strText += _T("EVR "); - } else { - strText += _T("VMR9 "); - } - - if (m_bIsFullscreen) { - strText += _T("FS "); - } - if (r.m_AdvRendSets.bVMR9FullscreenGUISupport) { - strText += _T("FSGui "); - } - - if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { - strText += _T("DisDC "); - } - - if (m_bColorManagement) { - strText += _T("ColorMan "); - } - - if (r.m_AdvRendSets.bVMRFlushGPUBeforeVSync) { - strText += _T("GPUFlushBV "); - } - if (r.m_AdvRendSets.bVMRFlushGPUAfterPresent) { - strText += _T("GPUFlushAP "); - } - - if (r.m_AdvRendSets.bVMRFlushGPUWait) { - strText += _T("GPUFlushWt "); - } - - if (r.m_AdvRendSets.bVMR9VSync) { - strText += _T("VS "); - } - if (r.m_AdvRendSets.bVMR9AlterativeVSync) { - strText += _T("AltVS "); - } - if (r.m_AdvRendSets.bVMR9VSyncAccurate) { - strText += _T("AccVS "); - } - if (r.m_AdvRendSets.iVMR9VSyncOffset) { - strText.AppendFormat(_T("VSOfst(%d)"), r.m_AdvRendSets.iVMR9VSyncOffset); - } - - if (m_bFullFloatingPointProcessing) { - strText += _T("FullFP "); - } - - if (m_bHalfFloatingPointProcessing) { - strText += _T("HalfFP "); - } - - if (m_bIsEVR) { - if (m_bHighColorResolution) { - strText += _T("10bitOut "); - } - if (m_bForceInputHighColorResolution) { - strText += _T("For10bitIn "); - } - if (r.m_AdvRendSets.bEVREnableFrameTimeCorrection) { - strText += _T("FTC "); - } - if (r.m_AdvRendSets.iEVROutputRange == 0) { - strText += _T("0-255 "); - } else if (r.m_AdvRendSets.iEVROutputRange == 1) { - strText += _T("16-235 "); - } - } - - - drawText(rc, strText); - - strText.Format(L"Formats : Surface %s Backbuffer %s Display %s Device %s %s", - GetD3DFormatStr(m_SurfaceType), GetD3DFormatStr(m_BackbufferType), - GetD3DFormatStr(m_DisplayType), m_pD3DDevEx ? L"D3DDevEx" : L"D3DDev", - m_D3DDevExError.IsEmpty() ? _T("") : (_T("D3DExError: ") + m_D3DDevExError).GetString()); - drawText(rc, strText); - - if (m_bIsEVR) { - if (r.m_AdvRendSets.bVMR9VSync) { - strText.Format(_T("Refresh rate : %.05f Hz SL: %4d (%3u Hz) "), - m_DetectedRefreshRate, int(m_DetectedScanlinesPerFrame + 0.5), m_refreshRate); - } else { - strText.Format(_T("Refresh rate : %3u Hz "), m_refreshRate); - } - strText.AppendFormat(_T("Last Duration: %10.6f Corrected Frame Time: %s"), - double(m_LastFrameDuration) / 10000.0, m_bCorrectedFrameTime ? _T("Yes") : _T("No")); - drawText(rc, strText); - } - } - - if (m_bSyncStatsAvailable) { - if (iDetailedStats > 1) { - strText.Format(_T("Sync offset : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms, Avr = %7.3f ms, Mode = %d"), - (double(llMinSyncOffset) / 10000.0), (double(llMaxSyncOffset) / 10000.0), - m_fSyncOffsetStdDev / 10000.0, m_fSyncOffsetAvr / 10000.0, m_VSyncMode); - } else { - strText.Format(_T("Sync offset : Mode = %d"), m_VSyncMode); - } - drawText(rc, strText); - } - - if (iDetailedStats > 1) { - strText.Format(_T("Jitter : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms"), - (double(llMinJitter) / 10000.0), - (double(llMaxJitter) / 10000.0), - m_fJitterStdDev / 10000.0); - drawText(rc, strText); - } - - if (m_pAllocator && iDetailedStats > 1) { - CDX9SubPicAllocator* pAlloc = (CDX9SubPicAllocator*)m_pAllocator.p; - int nFree = 0; - int nAlloc = 0; - int nSubPic = 0; - REFERENCE_TIME rtQueueStart = 0; - REFERENCE_TIME rtQueueEnd = 0; - - if (m_pSubPicQueue) { - REFERENCE_TIME rtQueueNow = 0; - m_pSubPicQueue->GetStats(nSubPic, rtQueueNow, rtQueueStart, rtQueueEnd); - } - - pAlloc->GetStats(nFree, nAlloc); - strText.Format(_T("Subtitles : Free %d Allocated %d Buffered %d QueueStart %7.3f QueueEnd %7.3f"), - nFree, nAlloc, nSubPic, (double(rtQueueStart) / 10000000.0), - (double(rtQueueEnd) / 10000000.0)); - drawText(rc, strText); - } - - if (iDetailedStats > 1) { - if (m_VBlankEndPresent == -100000) { - strText.Format(_T("VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d"), - m_VBlankStartWait, m_VBlankEndWait, - (double(m_VBlankWaitTime) / 10000.0), - (double(m_VBlankLockTime) / 10000.0), - m_VBlankMin, m_VBlankMax - m_VBlankMin); - } else { - strText.Format(_T("VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d EndPresent %4d"), - m_VBlankStartWait, m_VBlankEndWait, - (double(m_VBlankWaitTime) / 10000.0), - (double(m_VBlankLockTime) / 10000.0), - m_VBlankMin, - m_VBlankMax - m_VBlankMin, - m_VBlankEndPresent); - } - } else { - if (m_VBlankEndPresent == -100000) { - strText.Format(_T("VBlank Wait : Start %4d End %4d"), m_VBlankStartWait, m_VBlankEndWait); - } else { - strText.Format(_T("VBlank Wait : Start %4d End %4d EP %4d"), m_VBlankStartWait, m_VBlankEndWait, - m_VBlankEndPresent); - } - } - drawText(rc, strText); - - BOOL bCompositionEnabled = m_bCompositionEnabled; - - bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !r.m_AdvRendSets.bVMR9VSync; - - if (iDetailedStats > 1 && bDoVSyncInPresent) { - strText.Format(_T("Present Wait : Wait %7.3f ms Min %7.3f ms Max %7.3f ms"), - (double(m_PresentWaitTime) / 10000.0), - (double(m_PresentWaitTimeMin) / 10000.0), - (double(m_PresentWaitTimeMax) / 10000.0)); - drawText(rc, strText); - } - - if (iDetailedStats > 1) { - if (m_WaitForGPUTime) { - strText.Format(_T("Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms GPU %7.3f ms"), - (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), - (double(m_PaintTimeMin) / 10000.0), - (double(m_PaintTimeMax) / 10000.0), - (double(m_WaitForGPUTime) / 10000.0)); - } else { - strText.Format(_T("Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms"), - (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), - (double(m_PaintTimeMin) / 10000.0), - (double(m_PaintTimeMax) / 10000.0)); - } - } else { - if (m_WaitForGPUTime) { - strText.Format(_T("Paint Time : Draw %7.3f ms GPU %7.3f ms"), - (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), - (double(m_WaitForGPUTime) / 10000.0)); - } else { - strText.Format(_T("Paint Time : Draw %7.3f ms"), - (double(m_PaintTime - m_WaitForGPUTime) / 10000.0)); - } - } - drawText(rc, strText); - - if (iDetailedStats > 1 && r.m_AdvRendSets.bVMR9VSync) { - strText.Format(_T("Raster Status: Wait %7.3f ms Min %7.3f ms Max %7.3f ms"), - (double(m_RasterStatusWaitTime) / 10000.0), - (double(m_RasterStatusWaitTimeMin) / 10000.0), - (double(m_RasterStatusWaitTimeMax) / 10000.0)); - drawText(rc, strText); - } - - if (iDetailedStats > 1) { - if (m_bIsEVR) { - strText.Format(_T("Buffering : Buffered %3ld Free %3ld Current Surface %3d"), - m_nUsedBuffer, m_nNbDXSurface - m_nUsedBuffer, m_nCurSurface); - } else { - strText.Format(_T("Buffering : VMR9Surfaces %3d VMR9Surface %3d"), - m_nVMR9Surfaces, m_iVMR9Surface); - } - } else { - strText.Format(_T("Buffered : %3ld"), m_nUsedBuffer); - } - drawText(rc, strText); - - - if (iDetailedStats > 1) { - strText.Format(_T("Video size : %ld x %ld (AR = %ld : %ld)"), - m_nativeVideoSize.cx, m_nativeVideoSize.cy, m_aspectRatio.cx, m_aspectRatio.cy); - drawText(rc, strText); - if (m_pVideoTexture[0] || m_pVideoSurface[0]) { - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (m_pVideoTexture[0]) { - m_pVideoTexture[0]->GetLevelDesc(0, &desc); - } else if (m_pVideoSurface[0]) { - m_pVideoSurface[0]->GetDesc(&desc); - } - - if (desc.Width != (UINT)m_nativeVideoSize.cx || desc.Height != (UINT)m_nativeVideoSize.cy) { - strText.Format(_T("Texture size : %u x %u"), desc.Width, desc.Height); - drawText(rc, strText); - } - } - - - drawText(rc, rd->m_strDXVAInfo); - - strText.Format(_T("DirectX SDK : %u"), rd->GetDXSdkRelease()); - drawText(rc, strText); - - if (!m_D3D9Device.IsEmpty()) { - strText = _T("Render device: ") + m_D3D9Device; - drawText(rc, strText); - } - - if (!m_Decoder.IsEmpty()) { - strText = _T("Decoder : ") + m_Decoder; - drawText(rc, strText); - } - - for (int i = 0; i < 6; i++) { - if (m_strStatsMsg[i][0]) { - drawText(rc, m_strStatsMsg[i]); - } - } - } - m_pSprite->End(); - } - - if (m_pLine && iDetailedStats) { - D3DXVECTOR2 points[NB_JITTER]; - const float graphWidth = GRAPH_WIDTH * textScale; - const float graphHeight = GRAPH_HEIGHT * textScale; - const float topLeftX = m_windowRect.Width() - (graphWidth + lineHeight); - const float topLeftY = m_windowRect.Height() - (graphHeight + lineHeight); - const float gridStepY = graphHeight / 24.0f; - const float gridStepX = graphWidth / NB_JITTER; - - // Draw background - DrawRect(RGB(0, 0, 0), 80, CRect(int(topLeftX), - int(topLeftY), - int(topLeftX + graphWidth), - int(topLeftY + graphHeight))); - - m_pLine->SetWidth(2.5f * textScale); - m_pLine->SetAntialias(TRUE); - m_pLine->Begin(); - - // Draw grid lines - for (int i = 1; i < 24; ++i) { - points[0].x = topLeftX; - points[0].y = topLeftY + i * gridStepY; - points[1].y = points[0].y; - - float lineLength; - D3DCOLOR color; - if (i % 12 == 0) { - lineLength = 1.0f; - color = D3DCOLOR_XRGB(100, 100, 255); - } else if (i % 4 == 0) { - lineLength = 0.96f; - color = D3DCOLOR_XRGB(100, 100, 180); - } else { - lineLength = 0.04f; - color = D3DCOLOR_XRGB(100, 100, 140); - } - points[1].x = topLeftX + graphWidth * lineLength; - m_pLine->Draw(points, 2, color); - } - - if (m_rtTimePerFrame) { - // Draw jitter - for (int i = 1; i <= NB_JITTER; ++i) { - int nIndex = (m_nNextJitter + i) % NB_JITTER; - if (nIndex < 0) { - nIndex += NB_JITTER; - ASSERT(FALSE); - } - float jitter = float(m_pllJitter[nIndex] - m_fJitterMean); - points[i - 1].x = topLeftX + i * gridStepX; - points[i - 1].y = topLeftY + (jitter * textScale / 2000.0f + graphHeight / 2.0f); - } - m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100)); - - if (m_bSyncStatsAvailable) { - // Draw sync offset - for (int i = 1; i <= NB_JITTER; ++i) { - int nIndex = (m_nNextSyncOffset + i) % NB_JITTER; - if (nIndex < 0) { - nIndex += NB_JITTER; - } - points[i - 1].x = topLeftX + i * gridStepX; - points[i - 1].y = topLeftY + (m_pllSyncOffset[nIndex] * textScale / 2000.0f + graphHeight / 2.0f); - } - m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100)); - } - } - m_pLine->End(); - } -} - -STDMETHODIMP CDX9AllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) -{ - CheckPointer(size, E_POINTER); - - // Keep a reference so that we can safely work on the surface - // without having to lock everything - CComPtr pVideoSurface; - { - CAutoLock cAutoLock(this); - CheckPointer(m_pVideoSurface[m_nCurSurface], E_FAIL); - pVideoSurface = m_pVideoSurface[m_nCurSurface]; - } - - HRESULT hr; - - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(hr = pVideoSurface->GetDesc(&desc))) { - return hr; - } - - CSize framesize = GetVideoSize(false); - const CSize dar = GetVideoSize(true); - - bool resize = false; - if (dar.cx > 0 && dar.cy > 0 && (dar.cx != desc.Width || dar.cy != desc.Height)) { - framesize.cx = MulDiv(framesize.cy, dar.cx, dar.cy); - resize = true; - desc.Width = framesize.cx; - desc.Height = framesize.cy; - } - - DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3); - if (!lpDib) { - *size = required; - return S_OK; - } - if (*size < required) { - return E_OUTOFMEMORY; - } - *size = required; - - CComPtr pSurface, tSurface; - // Convert to 8-bit when using 10-bit or full/half processing modes - if (desc.Format != D3DFMT_X8R8G8B8) { - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tSurface, nullptr)) - || FAILED(hr = m_pD3DXLoadSurfaceFromSurface(tSurface, nullptr, nullptr, pVideoSurface, nullptr, nullptr, D3DX_DEFAULT, 0))) { - return hr; - } - } else { - tSurface = pVideoSurface; - } - - if (resize) { - CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; - if (FAILED(hr = m_pD3DDevEx->CreateRenderTarget(framesize.cx, framesize.cy, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurface, nullptr)) - || FAILED(hr = m_pD3DDevEx->SetRenderTarget(0, pSurface)) - || FAILED(hr = Resize(pVideoTexture, { CPoint(0, 0), m_nativeVideoSize }, { CPoint(0, 0), framesize }))) { - return hr; - } - } else { - pSurface = tSurface; - } - - D3DLOCKED_RECT r; - if (FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { - // If this fails, we try to use a surface allocated from the system memory - CComPtr pInputSurface = pSurface; - pSurface = nullptr; - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, nullptr)) - || FAILED(hr = m_pD3DDev->GetRenderTargetData(pInputSurface, pSurface)) - || FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { - return hr; - } - } - - hr = CreateDIBFromSurfaceData(desc, r, lpDib); - - pSurface->UnlockRect(); - - return hr; -} - -STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) -{ - return SetPixelShader2(pSrcData, pTarget, false); -} - -STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) -{ - CAutoLock cRenderLock(&m_RenderLock); - - return SetCustomPixelShader(pSrcData, pTarget, bScreenSpace); -} - -STDMETHODIMP CDX9AllocatorPresenter::SetD3DFullscreen(bool fEnabled) -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - fullScreenChanged = (fEnabled != m_bIsFullscreen); - m_bIsFullscreen = fEnabled; - return S_OK; -} - -STDMETHODIMP CDX9AllocatorPresenter::GetD3DFullscreen(bool* pfEnabled) -{ - CheckPointer(pfEnabled, E_POINTER); - *pfEnabled = m_bIsFullscreen; - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "RenderersSettings.h" +#include "DX9AllocatorPresenter.h" +#include +#include "../../../SubPic/DX9SubPic.h" +#include "../../../SubPic/SubPicQueueImpl.h" +#include "IPinHook.h" +#include "FocusThread.h" +#include "../../../DSUtil/vd.h" +#include + +#define FRAMERATE_MAX_DELTA 3000 + +#define REFERENCE_WIDTH 1920 +#define FONT_HEIGHT 21 +#define BOLD_THRESHOLD 11 +#define TEXT_PADDING 2 +#define GRAPH_HEIGHT 360 +#define GRAPH_WIDTH 1000 + +using namespace DSObjects; + +#pragma warning(push) +#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized +// CDX9AllocatorPresenter +CDX9AllocatorPresenter::CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString& _Error, bool isPreview) + : CDX9RenderingEngine(hWnd, hr, &_Error) + , m_bAlternativeVSync(false) + , m_bCompositionEnabled(false) + , m_bIsEVR(bIsEVR) + , m_OrderedPaint(0) + , m_VSyncMode(0) + , m_bDesktopCompositionDisabled(false) + , m_bIsFullscreen(bFullscreen) + , fullScreenChanged(false) + , m_bNeedCheckSample(true) + , m_MainThreadId(0) + , m_bIsRendering(false) + , m_hDWMAPI(nullptr) + , m_pDwmIsCompositionEnabled(nullptr) + , m_pDwmEnableComposition(nullptr) + , m_pDirectDraw(nullptr) + , m_LastAdapterCheck(0) + , m_nTearingPos(0) + , m_VMR9AlphaBitmapWidthBytes(0) + , m_pD3DXLoadSurfaceFromMemory(nullptr) + , m_pD3DXLoadSurfaceFromSurface(nullptr) + , m_pD3DXCreateLine(nullptr) + , m_pD3DXCreateFont(nullptr) + , m_pD3DXCreateSprite(nullptr) + , m_nVMR9Surfaces(0) + , m_iVMR9Surface(0) + , m_nUsedBuffer(0) + , m_fAvrFps(0.0) + , m_fJitterStdDev(0.0) + , m_fJitterMean(0.0) + , m_fSyncOffsetStdDev(0.0) + , m_fSyncOffsetAvr(0.0) + , m_DetectedRefreshRate(0) + , m_DetectedRefreshTime(0.0) + , m_DetectedRefreshTimePrim(0) + , m_DetectedScanlineTime(0) + , m_DetectedScanlineTimePrim(0) + , m_DetectedScanlinesPerFrame(0.0) + , m_ldDetectedRefreshRateList() + , m_ldDetectedScanlineRateList() + , m_DetectedRefreshRatePos(0) + , m_bSyncStatsAvailable(false) + , m_pllJitter() + , m_pllSyncOffset() + , m_llLastPerf(0) + , m_JitterStdDev(0) + , m_MaxJitter(MINLONG64) + , m_MinJitter(MAXLONG64) + , m_MaxSyncOffset(0) + , m_MinSyncOffset(0) + , m_nNextJitter(0) + , m_nNextSyncOffset(0) + , m_rtTimePerFrame(0) + , m_DetectedFrameRate(0.0) + , m_DetectedFrameTime(0.0) + , m_DetectedFrameTimeStdDev(0.0) + , m_DetectedLock(false) + , m_DetectedFrameTimeHistory() + , m_DetectedFrameTimeHistoryHistory() + , m_DetectedFrameTimePos(0) + , m_bInterlaced(false) + , m_VBlankEndWait(0) + , m_VBlankStartWait(0) + , m_VBlankWaitTime(0) + , m_VBlankLockTime(0) + , m_VBlankMin(300000) + , m_VBlankMinCalc(300000) + , m_VBlankMax(0) + , m_VBlankEndPresent(-100000) + , m_VBlankStartMeasureTime(0) + , m_VBlankStartMeasure(0) + , m_PresentWaitTime(0) + , m_PresentWaitTimeMin(3000000000) + , m_PresentWaitTimeMax(0) + , m_PaintTime(0) + , m_PaintTimeMin(3000000000) + , m_PaintTimeMax(0) + , m_WaitForGPUTime(0) + , m_RasterStatusWaitTime(0) + , m_RasterStatusWaitTimeMin(3000000000) + , m_RasterStatusWaitTimeMax(0) + , m_RasterStatusWaitTimeMaxCalc(0) + , m_ClockDiffCalc(0.0) + , m_ClockDiffPrim(0.0) + , m_ClockDiff(0.0) + , m_TimeChangeHistory() + , m_ClockChangeHistory() + , m_ClockTimeChangeHistoryPos(0) + , m_ModeratedTimeSpeed(1.0) + , m_ModeratedTimeSpeedPrim(0.0) + , m_ModeratedTimeSpeedDiff(0.0) + , m_bCorrectedFrameTime(0) + , m_FrameTimeCorrection(0) + , m_LastFrameDuration(0) + , m_LastSampleTime(0) + , m_FocusThread(nullptr) + , m_hFocusWindow(nullptr) + , m_bIsPreview(isPreview) +{ + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + + if (FAILED(hr)) { + _Error += _T("ISubPicAllocatorPresenterImpl failed\n"); + return; + } + + HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); + + if (hDll) { + (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory"); + (FARPROC&)m_pD3DXLoadSurfaceFromSurface = GetProcAddress(hDll, "D3DXLoadSurfaceFromSurface"); + (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine"); + (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW"); + (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite"); + } else { + _Error += _T("Your system is missing the file d3dx9_43.dll\n\nTo acquire this file you must install \"DirectX End-User Runtime\" or update your MPC-HC installation."); + } + + m_hDWMAPI = LoadLibrary(L"dwmapi.dll"); + if (m_hDWMAPI) { + (FARPROC&)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled"); + (FARPROC&)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition"); + } + + Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); + if (m_pD3DEx) { + m_pD3D = m_pD3DEx; + } + + const CRenderersSettings& r = GetRenderersSettings(); + + if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { + m_bDesktopCompositionDisabled = true; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(0); + } + } else { + m_bDesktopCompositionDisabled = false; + } + + hr = CreateDevice(_Error); +} +#pragma warning(pop) + +CDX9AllocatorPresenter::~CDX9AllocatorPresenter() +{ + if (m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = false; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(1); + } + } + + m_pFont = nullptr; + m_pLine = nullptr; + m_pSprite = nullptr; + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + + m_pAlphaBitmapTexture.Release(); + CleanupRenderingEngine(); + + m_pD3D = nullptr; + m_pD3DEx = nullptr; + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + + if (m_FocusThread) { + m_FocusThread->PostThreadMessage(WM_QUIT, 0, 0); + if (WaitForSingleObject(m_FocusThread->m_hThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_FocusThread->m_hThread, 0xDEAD); + } + } + + if (m_hDWMAPI) { + FreeLibrary(m_hDWMAPI); + m_hDWMAPI = nullptr; + } +} + +void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed); + +#if 0 +class CRandom31 +{ +public: + + CRandom31() { + m_Seed = 12164; + } + + void f_SetSeed(int32 _Seed) { + m_Seed = _Seed; + } + int32 f_GetSeed() { + return m_Seed; + } + /* + Park and Miller's psuedo-random number generator. + */ + int32 m_Seed; + int32 f_Get() { + static const int32 A = 16807; + static const int32 M = 2147483647; // 2^31 - 1 + static const int32 q = M / A; // M / A + static const int32 r = M % A; // M % A + m_Seed = A * (m_Seed % q) - r * (m_Seed / q); + if (m_Seed < 0) { + m_Seed += M; + } + return m_Seed; + } + + static int32 fs_Max() { + return 2147483646; + } + + double f_GetFloat() { + return double(f_Get()) * (1.0 / double(fs_Max())); + } +}; + +class CVSyncEstimation +{ +private: + class CHistoryEntry + { + public: + CHistoryEntry() { + m_Time = 0; + m_ScanLine = -1; + } + LONGLONG m_Time; + int m_ScanLine; + }; + + class CSolution + { + public: + CSolution() { + m_ScanLines = 1000; + m_ScanLinesPerSecond = m_ScanLines * 100; + } + int m_ScanLines; + double m_ScanLinesPerSecond; + double m_SqrSum; + + void f_Mutate(double _Amount, CRandom31& _Random, int _MinScans) { + int ToDo = _Random.f_Get() % 10; + if (ToDo == 0) { + m_ScanLines = m_ScanLines / 2; + } else if (ToDo == 1) { + m_ScanLines = m_ScanLines * 2; + } + + m_ScanLines = m_ScanLines * (1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5); + m_ScanLines = max(m_ScanLines, _MinScans); + + if (ToDo == 2) { + m_ScanLinesPerSecond /= (_Random.f_Get() % 4) + 1; + } else if (ToDo == 3) { + m_ScanLinesPerSecond *= (_Random.f_Get() % 4) + 1; + } + + m_ScanLinesPerSecond *= 1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5; + } + + void f_SpawnInto(CSolution& _Other, CRandom31& _Random, int _MinScans) { + _Other = *this; + _Other.f_Mutate(_Random.f_GetFloat() * 0.1, _Random, _MinScans); + } + + static int fs_Compare(const void* _pFirst, const void* _pSecond) { + const CSolution* pFirst = (const CSolution*)_pFirst; + const CSolution* pSecond = (const CSolution*)_pSecond; + if (pFirst->m_SqrSum < pSecond->m_SqrSum) { + return -1; + } else if (pFirst->m_SqrSum > pSecond->m_SqrSum) { + return 1; + } + return 0; + } + + + }; + + enum { + ENumHistory = 128 + }; + + CHistoryEntry m_History[ENumHistory]; + int m_iHistory; + CSolution m_OldSolutions[2]; + + CRandom31 m_Random; + + + double fp_GetSquareSum(double _ScansPerSecond, double _ScanLines) { + double SquareSum = 0; + int nHistory = min(m_nHistory, ENumHistory); + int iHistory = m_iHistory - nHistory; + if (iHistory < 0) { + iHistory += ENumHistory; + } + for (int i = 1; i < nHistory; ++i) { + int iHistory0 = iHistory + i - 1; + int iHistory1 = iHistory + i; + if (iHistory0 < 0) { + iHistory0 += ENumHistory; + } + iHistory0 = iHistory0 % ENumHistory; + iHistory1 = iHistory1 % ENumHistory; + ASSERT(m_History[iHistory0].m_Time != 0); + ASSERT(m_History[iHistory1].m_Time != 0); + + double DeltaTime = (m_History[iHistory1].m_Time - m_History[iHistory0].m_Time) / 10000000.0; + double PredictedScanLine = m_History[iHistory0].m_ScanLine + DeltaTime * _ScansPerSecond; + PredictedScanLine = fmod(PredictedScanLine, _ScanLines); + double Delta = (m_History[iHistory1].m_ScanLine - PredictedScanLine); + double DeltaSqr = Delta * Delta; + SquareSum += DeltaSqr; + } + return SquareSum; + } + + int m_nHistory; +public: + + CVSyncEstimation() { + m_iHistory = 0; + m_nHistory = 0; + } + + void f_AddSample(int _ScanLine, LONGLONG _Time) { + m_History[m_iHistory].m_ScanLine = _ScanLine; + m_History[m_iHistory].m_Time = _Time; + ++m_nHistory; + m_iHistory = (m_iHistory + 1) % ENumHistory; + } + + void f_GetEstimation(double& _RefreshRate, int& _ScanLines, int _ScreenSizeY, int _WindowsRefreshRate) { + _RefreshRate = 0; + _ScanLines = 0; + + int iHistory = m_iHistory; + // We have a full history + if (m_nHistory > 10) { + for (int l = 0; l < 5; ++l) { + const int nSol = 3 + 5 + 5 + 3; + CSolution Solutions[nSol]; + + Solutions[0] = m_OldSolutions[0]; + Solutions[1] = m_OldSolutions[1]; + Solutions[2].m_ScanLines = _ScreenSizeY; + Solutions[2].m_ScanLinesPerSecond = _ScreenSizeY * _WindowsRefreshRate; + + int iStart = 3; + for (int i = iStart; i < iStart + 5; ++i) { + Solutions[0].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); + } + iStart += 5; + for (int i = iStart; i < iStart + 5; ++i) { + Solutions[1].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); + } + iStart += 5; + for (int i = iStart; i < iStart + 3; ++i) { + Solutions[2].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); + } + + int Start = 2; + if (l == 0) { + Start = 0; + } + for (int i = Start; i < nSol; ++i) { + Solutions[i].m_SqrSum = fp_GetSquareSum(Solutions[i].m_ScanLinesPerSecond, Solutions[i].m_ScanLines); + } + + qsort(Solutions, nSol, sizeof(Solutions[0]), &CSolution::fs_Compare); + for (int i = 0; i < 2; ++i) { + m_OldSolutions[i] = Solutions[i]; + } + } + + _ScanLines = m_OldSolutions[0].m_ScanLines + 0.5; + _RefreshRate = 1.0 / (m_OldSolutions[0].m_ScanLines / m_OldSolutions[0].m_ScanLinesPerSecond); + } else { + m_OldSolutions[0].m_ScanLines = _ScreenSizeY; + m_OldSolutions[1].m_ScanLines = _ScreenSizeY; + } + } +}; +#endif + +bool CDX9AllocatorPresenter::SettingsNeedResetDevice(CRenderersSettings& r) +{ + CRenderersSettings::CAdvRendererSettings& New = r.m_AdvRendSets; + CRenderersSettings::CAdvRendererSettings& Current = m_LastRendererSettings; + + bool bRet = false; + + bRet = bRet || New.bVMR9AlterativeVSync != Current.bVMR9AlterativeVSync; + bRet = bRet || New.bVMR9VSyncAccurate != Current.bVMR9VSyncAccurate; + + if (m_bIsFullscreen) { + bRet = bRet || New.bVMR9FullscreenGUISupport != Current.bVMR9FullscreenGUISupport; + } else { + if (Current.bVMRDisableDesktopComposition) { + if (!m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = true; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(0); + } + } + } else { + if (m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = false; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(1); + } + } + } + } + + if (m_bIsEVR) { + bRet = bRet || New.bEVRHighColorResolution != Current.bEVRHighColorResolution; + bRet = bRet || New.bEVRForceInputHighColorResolution != Current.bEVRForceInputHighColorResolution; + } + + m_LastRendererSettings = r.m_AdvRendSets; + + return bRet; +} + +HRESULT CDX9AllocatorPresenter::CreateDevice(CString& _Error) +{ + const CRenderersSettings& r = GetRenderersSettings(); + CRenderersData* rd = GetRenderersData(); + + m_VBlankEndWait = 0; + m_VBlankMin = 300000; + m_VBlankMinCalc = 300000; + m_VBlankMax = 0; + m_VBlankStartWait = 0; + m_VBlankWaitTime = 0; + m_VBlankLockTime = 0; + m_PresentWaitTime = 0; + m_PresentWaitTimeMin = 3000000000; + m_PresentWaitTimeMax = 0; + + m_LastRendererSettings = r.m_AdvRendSets; + + m_VBlankEndPresent = -100000; + m_VBlankStartMeasureTime = 0; + m_VBlankStartMeasure = 0; + + m_PaintTime = 0; + m_PaintTimeMin = 3000000000; + m_PaintTimeMax = 0; + + m_RasterStatusWaitTime = 0; + m_RasterStatusWaitTimeMin = 3000000000; + m_RasterStatusWaitTimeMax = 0; + m_RasterStatusWaitTimeMaxCalc = 0; + + m_ClockDiff = 0.0; + m_ClockDiffPrim = 0.0; + m_ClockDiffCalc = 0.0; + + m_ModeratedTimeSpeed = 1.0; + m_ModeratedTimeSpeedDiff = 0.0; + m_ModeratedTimeSpeedPrim = 0; + ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory)); + ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory)); + m_ClockTimeChangeHistoryPos = 0; + + m_pSprite = nullptr; + m_pLine = nullptr; + m_pFont = nullptr; + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + m_pDirectDraw = nullptr; + + m_bAlphaBitmapEnable = false; + m_pAlphaBitmapTexture.Release(); + ZeroMemory(&m_AlphaBitmapParams, sizeof(m_AlphaBitmapParams)); + + CleanupRenderingEngine(); + + UINT currentAdapter = GetAdapter(m_pD3D); + bool bTryToReset = (currentAdapter == m_CurrentAdapter); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + m_CurrentAdapter = currentAdapter; + } + + if (!m_pD3D) { + _Error += L"Failed to create D3D9\n"; + return E_UNEXPECTED; + } + + HRESULT hr = S_OK; + + /*// TODO : add NVIDIA PerfHUD !!! + + // Set default settings + UINT AdapterToUse=D3DADAPTER_DEFAULT; + D3DDEVTYPE DeviceType=D3DDEVTYPE_HAL; + + #if SHIPPING_VERSION + // When building a shipping version, disable PerfHUD (opt-out) + #else + // Look for 'NVIDIA PerfHUD' adapter + // If it is present, override default settings + for (UINT Adapter=0;AdapterGetAdapterCount();Adapter++) + { + D3DADAPTER_IDENTIFIER9 Identifier; + HRESULT Res; + + Res = g_pD3D->GetAdapterIdentifier(Adapter,0,&Identifier); + if (strstr(Identifier.Description,"PerfHUD") != 0) + { + AdapterToUse=Adapter; + DeviceType=D3DDEVTYPE_REF; + break; + } + } + #endif + + if (FAILED(g_pD3D->CreateDevice( AdapterToUse, DeviceType, hWnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING, + &d3dpp, &g_pd3dDevice) ) ) + { + return E_FAIL; + } + */ + + + //#define ENABLE_DDRAWSYNC +#ifdef ENABLE_DDRAWSYNC + hr = DirectDrawCreate(nullptr, &m_pDirectDraw, nullptr); + if (hr == S_OK) { + hr = m_pDirectDraw->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL); + } +#endif + + D3DPRESENT_PARAMETERS pp; + ZeroMemory(&pp, sizeof(pp)); + + BOOL bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + + m_bCompositionEnabled = !!bCompositionEnabled; + m_bAlternativeVSync = r.m_AdvRendSets.bVMR9AlterativeVSync; + + // detect FP16 textures support + rd->m_bFP16Support = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_VOLUMETEXTURE, D3DFMT_A16B16G16R16F)); + + // detect FP32 textures support + rd->m_bFP32Support = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_VOLUMETEXTURE, D3DFMT_A32B32G32R32F)); + + // detect 10-bit textures support + rd->m_b10bitSupport = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, D3DFMT_A2R10G10B10)); + + // detect 10-bit device support + bool bHighColorSupport = SUCCEEDED(m_pD3D->CheckDeviceType(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_A2R10G10B10, D3DFMT_A2R10G10B10, FALSE)); + + // set settings that depend on hardware feature support + m_bForceInputHighColorResolution = r.m_AdvRendSets.bEVRForceInputHighColorResolution && m_bIsEVR && rd->m_b10bitSupport; + m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution && m_bIsEVR && rd->m_b10bitSupport && bHighColorSupport; + m_bFullFloatingPointProcessing = r.m_AdvRendSets.bVMR9FullFloatingPointProcessing && rd->m_bFP32Support; + m_bHalfFloatingPointProcessing = r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing && rd->m_bFP16Support && !m_bFullFloatingPointProcessing; + + // set color formats + if (m_bFullFloatingPointProcessing) { + m_SurfaceType = D3DFMT_A32B32G32R32F; + } else if (m_bHalfFloatingPointProcessing) { + m_SurfaceType = D3DFMT_A16B16G16R16F; + } else if (m_bForceInputHighColorResolution || m_bHighColorResolution) { + m_SurfaceType = D3DFMT_A2R10G10B10; + } else { + m_SurfaceType = D3DFMT_X8R8G8B8; + } + + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + + D3DDISPLAYMODEEX DisplayMode; + ZeroMemory(&DisplayMode, sizeof(DisplayMode)); + DisplayMode.Size = sizeof(DisplayMode); + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + + if (m_bIsFullscreen) { + if (m_bHighColorResolution) { + pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } else { + pp.BackBufferFormat = D3DFMT_X8R8G8B8; + } + pp.Windowed = false; + pp.BackBufferCount = 3; + pp.SwapEffect = D3DSWAPEFFECT_FLIP; + // there's no Desktop composition to take care of alternative vSync in exclusive mode, alternative vSync is therefore unused + pp.hDeviceWindow = m_hWnd; + pp.Flags = D3DPRESENTFLAG_VIDEO; + if (r.m_AdvRendSets.bVMR9FullscreenGUISupport && !m_bHighColorResolution) { + pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + } + m_D3DDevExError = _T("No m_pD3DEx"); + + if (!m_FocusThread) { + m_FocusThread = (CFocusThread*)AfxBeginThread(RUNTIME_CLASS(CFocusThread), 0, 0, 0); + } + + HWND hFocusWindow = m_FocusThread->GetFocusWindow(); + bTryToReset &= (m_hFocusWindow == hFocusWindow || fullScreenChanged); + m_hFocusWindow = hFocusWindow; + + if (m_pD3DEx) { + CHECK_HR(m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr)); + + m_ScreenSize.SetSize(DisplayMode.Width, DisplayMode.Height); + m_BackBufferSize = m_ScreenSize; + + DisplayMode.Format = pp.BackBufferFormat; + pp.FullScreen_RefreshRateInHz = m_refreshRate = DisplayMode.RefreshRate; + pp.BackBufferWidth = m_BackBufferSize.cx; + pp.BackBufferHeight = m_BackBufferSize.cy; + + bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&pp, &DisplayMode)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + hr = m_pD3DEx->CreateDeviceEx( + m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS | D3DCREATE_NOWINDOWCHANGES, //D3DCREATE_MANAGED + &pp, &DisplayMode, &m_pD3DDevEx); + } + + if (FAILED(hr)) { + m_D3DDevExError = GetWindowsErrorMessage(hr, nullptr); + } else { + m_D3DDevExError.Empty(); + } + + if (m_pD3DDevEx) { + m_pD3DDev = m_pD3DDevEx; + m_BackbufferType = pp.BackBufferFormat; + m_DisplayType = DisplayMode.Format; + } + } + if (bTryToReset && m_pD3DDev && !m_pD3DDevEx) { + if (FAILED(hr = m_pD3DDev->Reset(&pp))) { + m_pD3DDev = nullptr; + } + } + if (!m_pD3DDev) { + CHECK_HR(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)); + d3ddm.Format = pp.BackBufferFormat; + + m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); + m_BackBufferSize = m_ScreenSize; + + pp.FullScreen_RefreshRateInHz = m_refreshRate = d3ddm.RefreshRate; + pp.BackBufferWidth = m_BackBufferSize.cx; + pp.BackBufferHeight = m_BackBufferSize.cy; + + hr = m_pD3D->CreateDevice( + m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_NOWINDOWCHANGES, //D3DCREATE_MANAGED + &pp, &m_pD3DDev); + m_DisplayType = d3ddm.Format; + m_BackbufferType = pp.BackBufferFormat; + } + if (m_pD3DDev && r.m_AdvRendSets.bVMR9FullscreenGUISupport && !m_bHighColorResolution) { + m_pD3DDev->SetDialogBoxMode(true); + //if (m_pD3DDev->SetDialogBoxMode(true) != S_OK) + // ExitProcess(0); + } + } else { + pp.Windowed = TRUE; + pp.hDeviceWindow = m_hWnd; + pp.SwapEffect = D3DSWAPEFFECT_COPY; + pp.Flags = D3DPRESENTFLAG_VIDEO; + pp.BackBufferCount = 1; + if (bCompositionEnabled || m_bAlternativeVSync) { + // Desktop composition takes care of the VSYNC + pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } + + bTryToReset &= (m_hFocusWindow == m_hWnd || fullScreenChanged); + m_hFocusWindow = m_hWnd; + + if (m_pD3DEx) { + HRESULT getModeResult = m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); + + if (getModeResult == D3DERR_NOTAVAILABLE) { + m_pD3DEx = nullptr; + Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); + if (nullptr != m_pD3DEx) { + getModeResult = m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); + } + } + CHECK_HR(getModeResult); + + m_ScreenSize.SetSize(DisplayMode.Width, DisplayMode.Height); + m_refreshRate = DisplayMode.RefreshRate; + m_BackBufferSize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); + pp.BackBufferWidth = m_BackBufferSize.cx; + pp.BackBufferHeight = m_BackBufferSize.cy; + + bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&pp, nullptr)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + // We can get 0x8876086a here when switching from two displays to one display using Win + P (Windows 7) + // Cause: We might not reinitialize dx correctly during the switch + hr = m_pD3DEx->CreateDeviceEx( + m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS, //D3DCREATE_MANAGED + &pp, nullptr, &m_pD3DDevEx); + } + if (m_pD3DDevEx) { + m_pD3DDev = m_pD3DDevEx; + m_DisplayType = DisplayMode.Format; + } + } + if (bTryToReset && m_pD3DDev && !m_pD3DDevEx) { + if (FAILED(hr = m_pD3DDev->Reset(&pp))) { + m_pD3DDev = nullptr; + } + } + if (!m_pD3DDev) { + CHECK_HR(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)); + m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); + m_refreshRate = d3ddm.RefreshRate; + m_BackBufferSize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); + pp.BackBufferWidth = m_BackBufferSize.cx; + pp.BackBufferHeight = m_BackBufferSize.cy; + + hr = m_pD3D->CreateDevice( + m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED + &pp, &m_pD3DDev); + m_DisplayType = d3ddm.Format; + } + m_BackbufferType = pp.BackBufferFormat; + } + + if (m_pD3DDev) { + while (hr == D3DERR_DEVICELOST) { + TRACE(_T("D3DERR_DEVICELOST. Trying to Reset.\n")); + hr = m_pD3DDev->TestCooperativeLevel(); + } + if (hr == D3DERR_DEVICENOTRESET) { + TRACE(_T("D3DERR_DEVICENOTRESET\n")); + hr = m_pD3DDev->Reset(&pp); + } + + if (m_pD3DDevEx) { + m_pD3DDevEx->SetGPUThreadPriority(7); + } + } + + if (FAILED(hr)) { + _Error += L"CreateDevice failed\n"; + CStringW str; + str.Format(L"Error code: 0x%X\n", hr); + _Error += str; + + return hr; + } + + ASSERT(m_pD3DDev); + + if (m_ScreenSize.cx <= 0 || m_ScreenSize.cy <= 0) { + _Error += L"Invalid screen size\n"; + return E_FAIL; + } + + m_MainThreadId = GetCurrentThreadId(); + + // Get the device caps + ZeroMemory(&m_Caps, sizeof(m_Caps)); + m_pD3DDev->GetDeviceCaps(&m_Caps); + + // Initialize the rendering engine + InitRenderingEngine(); + + if (!m_bIsPreview) { + CComPtr pSubPicProvider; + if (m_pSubPicQueue) { + m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); + } + + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(m_pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); + } + + hr = S_OK; + if (!m_pSubPicQueue) { + CAutoLock cAutoLock(this); + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + m_pSubPicQueue->Invalidate(); + } + + if (FAILED(hr)) { + _Error += L"m_pSubPicQueue failed\n"; + + return hr; + } + + if (pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); + } + } + + m_LastAdapterCheck = rd->GetPerfCounter(); + + return S_OK; +} + +HRESULT CDX9AllocatorPresenter::AllocSurfaces() +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + return CreateVideoSurfaces(); +} + +void CDX9AllocatorPresenter::DeleteSurfaces() +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + FreeVideoSurfaces(); +} + +UINT CDX9AllocatorPresenter::GetAdapter(IDirect3D9* pD3D, bool bGetAdapter) +{ + if (m_hWnd == nullptr || pD3D == nullptr) { + return D3DADAPTER_DEFAULT; + } + + m_D3D9Device = _T(""); + + const CRenderersSettings& r = GetRenderersSettings(); + if (bGetAdapter && (pD3D->GetAdapterCount() > 1) && !r.D3D9RenderDevice.IsEmpty()) { + TCHAR strGUID[50]; + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + + for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { + if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK) { + if ((::StringFromGUID2(adapterIdentifier.DeviceIdentifier, strGUID, 50) > 0) && (r.D3D9RenderDevice == strGUID)) { + m_D3D9Device = adapterIdentifier.Description; + return adp; + } + } + } + } + + HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor == nullptr) { + return D3DADAPTER_DEFAULT; + } + + for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { + HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp); + if (hAdpMon == hMonitor) { + if (bGetAdapter) { + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK) { + m_D3D9Device = adapterIdentifier.Description; + } + } + return adp; + } + } + + return D3DADAPTER_DEFAULT; +} + +DWORD CDX9AllocatorPresenter::GetVertexProcessing() +{ + HRESULT hr; + D3DCAPS9 caps; + + hr = m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &caps); + if (FAILED(hr)) { + return D3DCREATE_SOFTWARE_VERTEXPROCESSING; + } + + if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 || + caps.VertexShaderVersion < D3DVS_VERSION(2, 0)) { + return D3DCREATE_SOFTWARE_VERTEXPROCESSING; + } + + return D3DCREATE_HARDWARE_VERTEXPROCESSING; +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP CDX9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + return E_NOTIMPL; +} + +void CDX9AllocatorPresenter::CalculateJitter(LONGLONG PerfCounter) +{ + // Calculate the jitter! + LONGLONG llPerf = PerfCounter; + if ((m_rtTimePerFrame != 0) && (labs((long)(llPerf - m_llLastPerf)) < m_rtTimePerFrame * 3)) { + m_nNextJitter = (m_nNextJitter + 1) % NB_JITTER; + m_pllJitter[m_nNextJitter] = llPerf - m_llLastPerf; + + m_MaxJitter = MINLONG64; + m_MinJitter = MAXLONG64; + + // Calculate the real FPS + LONGLONG llJitterSum = 0; + LONGLONG llJitterSumAvg = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG Jitter = m_pllJitter[i]; + llJitterSum += Jitter; + llJitterSumAvg += Jitter; + } + double FrameTimeMean = double(llJitterSumAvg) / NB_JITTER; + m_fJitterMean = FrameTimeMean; + double DeviationSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG DevInt = m_pllJitter[i] - (LONGLONG)FrameTimeMean; + double Deviation = (double)DevInt; + DeviationSum += Deviation * Deviation; + m_MaxJitter = std::max(m_MaxJitter, DevInt); + m_MinJitter = std::min(m_MinJitter, DevInt); + } + double StdDev = sqrt(DeviationSum / NB_JITTER); + + m_fJitterStdDev = StdDev; + m_fAvrFps = 10000000.0 / (double(llJitterSum) / NB_JITTER); + } + + m_llLastPerf = llPerf; +} + +bool CDX9AllocatorPresenter::GetVBlank(int& _ScanLine, int& _bInVBlank, bool _bMeasureTime) +{ + LONGLONG llPerf = 0; + if (_bMeasureTime) { + llPerf = GetRenderersData()->GetPerfCounter(); + } + + int ScanLine = 0; + _ScanLine = 0; + _bInVBlank = 0; + + if (m_pDirectDraw) { + DWORD ScanLineGet = 0; + m_pDirectDraw->GetScanLine(&ScanLineGet); + BOOL InVBlank; + if (m_pDirectDraw->GetVerticalBlankStatus(&InVBlank) != S_OK) { + return false; + } + ScanLine = ScanLineGet; + _bInVBlank = InVBlank; + if (InVBlank) { + ScanLine = 0; + } + } else { + D3DRASTER_STATUS RasterStatus; + if (m_pD3DDev->GetRasterStatus(0, &RasterStatus) != S_OK) { + return false; + } + ScanLine = RasterStatus.ScanLine; + _bInVBlank = RasterStatus.InVBlank; + } + if (_bMeasureTime) { + m_VBlankMax = std::max(m_VBlankMax, ScanLine); + if (ScanLine != 0 && !_bInVBlank) { + m_VBlankMinCalc = std::min(m_VBlankMinCalc, ScanLine); + } + m_VBlankMin = m_VBlankMax - m_ScreenSize.cy; + } + if (_bInVBlank) { + _ScanLine = 0; + } else if (m_VBlankMin != 300000) { + _ScanLine = ScanLine - m_VBlankMin; + } else { + _ScanLine = ScanLine; + } + + if (_bMeasureTime) { + LONGLONG Time = GetRenderersData()->GetPerfCounter() - llPerf; + if (Time > 5000000) { // 0.5 sec + TRACE(_T("GetVBlank too long (%f sec)\n"), Time / 10000000.0); + } + m_RasterStatusWaitTimeMaxCalc = std::max(m_RasterStatusWaitTimeMaxCalc, Time); + } + + return true; +} + +bool CDX9AllocatorPresenter::WaitForVBlankRange(int& _RasterStart, int _RasterSize, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, HANDLE& lockOwner) +{ + if (_bMeasure) { + m_RasterStatusWaitTimeMaxCalc = 0; + } + bool bWaited = false; + int ScanLine = 0; + int InVBlank = 0; + LONGLONG llPerf = 0; + if (_bMeasure) { + llPerf = GetRenderersData()->GetPerfCounter(); + } + GetVBlank(ScanLine, InVBlank, _bMeasure); + if (_bMeasure) { + m_VBlankStartWait = ScanLine; + } + + static bool bOneWait = true; + if (bOneWait && _bMeasure) { + bOneWait = false; + // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate + int nInVBlank = 0; + for (;;) { + if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { + break; + } + + if (InVBlank && nInVBlank == 0) { + nInVBlank = 1; + } else if (!InVBlank && nInVBlank == 1) { + nInVBlank = 2; + } else if (InVBlank && nInVBlank == 2) { + nInVBlank = 3; + } else if (!InVBlank && nInVBlank == 3) { + break; + } + } + } + if (_bWaitIfInside) { + int ScanLineDiff = long(ScanLine) - _RasterStart; + if (ScanLineDiff > m_ScreenSize.cy / 2) { + ScanLineDiff -= m_ScreenSize.cy; + } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { + ScanLineDiff += m_ScreenSize.cy; + } + + if (ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) { + bWaited = true; + // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate + int LastLineDiff = ScanLineDiff; + for (;;) { + if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { + break; + } + ScanLineDiff = long(ScanLine) - _RasterStart; + if (ScanLineDiff > m_ScreenSize.cy / 2) { + ScanLineDiff -= m_ScreenSize.cy; + } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { + ScanLineDiff += m_ScreenSize.cy; + } + if (!(ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0)) { + break; + } + LastLineDiff = ScanLineDiff; + Sleep(1); // Just sleep + } + } + } + double RefreshRate = GetRefreshRate(); + LONG ScanLines = GetScanLines(); + int MinRange = std::max(std::min(long(0.0015 * ScanLines * RefreshRate + 0.5), ScanLines / 3l), 5l); // 1.5 ms or max 33 % of Time + int NoSleepStart = _RasterStart - MinRange; + int NoSleepRange = MinRange; + if (NoSleepStart < 0) { + NoSleepStart += m_ScreenSize.cy; + } + + int MinRange2 = std::max(std::min(long(0.0050 * ScanLines * RefreshRate + 0.5), ScanLines / 3l), 5l); // 5 ms or max 33 % of Time + int D3DDevLockStart = _RasterStart - MinRange2; + int D3DDevLockRange = MinRange2; + if (D3DDevLockStart < 0) { + D3DDevLockStart += m_ScreenSize.cy; + } + + int ScanLineDiff = ScanLine - _RasterStart; + if (ScanLineDiff > m_ScreenSize.cy / 2) { + ScanLineDiff -= m_ScreenSize.cy; + } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { + ScanLineDiff += m_ScreenSize.cy; + } + int LastLineDiff = ScanLineDiff; + + + int ScanLineDiffSleep = long(ScanLine) - NoSleepStart; + if (ScanLineDiffSleep > m_ScreenSize.cy / 2) { + ScanLineDiffSleep -= m_ScreenSize.cy; + } else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2) { + ScanLineDiffSleep += m_ScreenSize.cy; + } + int LastLineDiffSleep = ScanLineDiffSleep; + + + int ScanLineDiffLock = long(ScanLine) - D3DDevLockStart; + if (ScanLineDiffLock > m_ScreenSize.cy / 2) { + ScanLineDiffLock -= m_ScreenSize.cy; + } else if (ScanLineDiffLock < -m_ScreenSize.cy / 2) { + ScanLineDiffLock += m_ScreenSize.cy; + } + int LastLineDiffLock = ScanLineDiffLock; + + LONGLONG llPerfLock = 0; + + for (;;) { + if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { + break; + } + ScanLineDiff = long(ScanLine) - _RasterStart; + if (ScanLineDiff > m_ScreenSize.cy / 2) { + ScanLineDiff -= m_ScreenSize.cy; + } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { + ScanLineDiff += m_ScreenSize.cy; + } + if ((ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0)) { + break; + } + + LastLineDiff = ScanLineDiff; + + bWaited = true; + + ScanLineDiffLock = long(ScanLine) - D3DDevLockStart; + if (ScanLineDiffLock > m_ScreenSize.cy / 2) { + ScanLineDiffLock -= m_ScreenSize.cy; + } else if (ScanLineDiffLock < -m_ScreenSize.cy / 2) { + ScanLineDiffLock += m_ScreenSize.cy; + } + + if (((ScanLineDiffLock >= 0 && ScanLineDiffLock <= D3DDevLockRange) || (LastLineDiffLock < 0 && ScanLineDiffLock > 0))) { + if (!lockOwner && _bMeasure) { + llPerfLock = GetRenderersData()->GetPerfCounter(); + lockOwner = LockD3DDevice(); + } + } + LastLineDiffLock = ScanLineDiffLock; + + + ScanLineDiffSleep = long(ScanLine) - NoSleepStart; + if (ScanLineDiffSleep > m_ScreenSize.cy / 2) { + ScanLineDiffSleep -= m_ScreenSize.cy; + } else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2) { + ScanLineDiffSleep += m_ScreenSize.cy; + } + + if (!((ScanLineDiffSleep >= 0 && ScanLineDiffSleep <= NoSleepRange) || (LastLineDiffSleep < 0 && ScanLineDiffSleep > 0)) || !_bNeedAccurate) { + //TRACE(_T("%d\n"), RasterStatus.ScanLine); + Sleep(1); // Don't sleep for the last 1.5 ms scan lines, so we get maximum precision + } + LastLineDiffSleep = ScanLineDiffSleep; + } + _RasterStart = ScanLine; + if (_bMeasure) { + m_VBlankEndWait = ScanLine; + m_VBlankWaitTime = GetRenderersData()->GetPerfCounter() - llPerf; + + if (lockOwner) { + m_VBlankLockTime = GetRenderersData()->GetPerfCounter() - llPerfLock; + } else { + m_VBlankLockTime = 0; + } + + m_RasterStatusWaitTime = m_RasterStatusWaitTimeMaxCalc; + m_RasterStatusWaitTimeMin = std::min(m_RasterStatusWaitTimeMin, m_RasterStatusWaitTime); + m_RasterStatusWaitTimeMax = std::max(m_RasterStatusWaitTimeMax, m_RasterStatusWaitTime); + } + + return bWaited; +} + +int CDX9AllocatorPresenter::GetVBlackPos() +{ + BOOL bCompositionEnabled = m_bCompositionEnabled; + + int WaitRange = std::max(m_ScreenSize.cy / 40l, 5l); + if (!bCompositionEnabled) { + if (m_bAlternativeVSync) { + const CRenderersSettings& r = GetRenderersSettings(); + return r.m_AdvRendSets.iVMR9VSyncOffset; + } else { + int MinRange = std::max(std::min(long(0.005 * m_ScreenSize.cy * GetRefreshRate() + 0.5), m_ScreenSize.cy / 3l), 5l); // 5 ms or max 33 % of Time + int WaitFor = m_ScreenSize.cy - (MinRange + WaitRange); + return WaitFor; + } + } else { + int WaitFor = m_ScreenSize.cy / 2; + return WaitFor; + } +} + +bool CDX9AllocatorPresenter::WaitForVBlank(bool& _Waited, HANDLE& lockOwner) +{ + const CRenderersSettings& r = GetRenderersSettings(); + if (!r.m_AdvRendSets.bVMR9VSync) { + _Waited = true; + m_VBlankWaitTime = 0; + m_VBlankLockTime = 0; + m_VBlankEndWait = 0; + m_VBlankStartWait = 0; + return true; + } + //_Waited = true; + //return false; + + BOOL bCompositionEnabled = m_bCompositionEnabled; + int WaitFor = GetVBlackPos(); + + if (!bCompositionEnabled) { + if (m_bAlternativeVSync) { + _Waited = WaitForVBlankRange(WaitFor, 0, false, true, true, lockOwner); + return false; + } else { + _Waited = WaitForVBlankRange(WaitFor, 0, false, r.m_AdvRendSets.bVMR9VSyncAccurate, true, lockOwner); + return true; + } + } else { + // Instead we wait for VBlack after the present, this seems to fix the stuttering problem. It'r also possible to fix by removing the Sleep above, but that isn't an option. + WaitForVBlankRange(WaitFor, 0, false, r.m_AdvRendSets.bVMR9VSyncAccurate, true, lockOwner); + + return false; + } +} + +void CDX9AllocatorPresenter::UpdateAlphaBitmap() +{ + m_VMR9AlphaBitmapData.Free(); + + if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0) { + HBITMAP hBitmap = (HBITMAP)GetCurrentObject(m_VMR9AlphaBitmap.hdc, OBJ_BITMAP); + if (!hBitmap) { + return; + } + DIBSECTION info; + ZeroMemory(&info, sizeof(DIBSECTION)); + if (!::GetObject(hBitmap, sizeof(DIBSECTION), &info)) { + return; + } + + m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight); + m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes; + + if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight)) { + memcpy((BYTE*)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight); + } + } +} + +STDMETHODIMP_(bool) CDX9AllocatorPresenter::Paint(bool bAll) +{ + if (m_bPendingResetDevice) { + SendResetRequest(); + return false; + } + + CRenderersSettings& r = GetRenderersSettings(); + if (&r == nullptr) { + return false; + } + + //TRACE(_T("Thread: %d\n"), (LONG)((CRITICAL_SECTION &)m_RenderLock).OwningThread); + +#if 0 + if (TryEnterCriticalSection(&(CRITICAL_SECTION&)(*((CCritSec*)this)))) { + LeaveCriticalSection((&(CRITICAL_SECTION&)(*((CCritSec*)this)))); + } else { + __debugbreak(); + } +#endif + + CRenderersData* rd = GetRenderersData(); + + LONGLONG StartPaint = rd->GetPerfCounter(); + CAutoLock cRenderLock(&m_RenderLock); + + if (m_windowRect.right <= m_windowRect.left || m_windowRect.bottom <= m_windowRect.top + || m_nativeVideoSize.cx <= 0 || m_nativeVideoSize.cy <= 0 + || !m_pVideoSurface[m_nCurSurface]) { + if (m_OrderedPaint) { + --m_OrderedPaint; + } else { + //TRACE(_T("UNORDERED PAINT!!!!!!\n")); + } + + + return false; + } + + HRESULT hr; + + m_pD3DDev->BeginScene(); + + CComPtr pBackBuffer; + m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); + // FIXME: GetBackBuffer can fail, check return value and reset device + + // Clear the backbuffer + m_pD3DDev->SetRenderTarget(0, pBackBuffer); + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); + + CRect rSrcVid(CPoint(0, 0), GetVisibleVideoSize()); + CRect rDstVid(m_videoRect); + + CRect rSrcPri(CPoint(0, 0), m_windowRect.Size()); + CRect rDstPri(rSrcPri); + + // Render the current video frame + hr = RenderVideo(pBackBuffer, rSrcVid, rDstVid); + + if (FAILED(hr)) { + if (m_RenderingPath == RENDERING_PATH_STRETCHRECT) { + // Support ffdshow queueing + // m_pD3DDev->StretchRect may fail if ffdshow is using queue output samples. + // Here we don't want to show the black buffer. + if (m_OrderedPaint) { + --m_OrderedPaint; + } else { + //TRACE(_T("UNORDERED PAINT!!!!!!\n")); + } + + return false; + } + } + + if (!m_bIsPreview) { + // paint the text on the backbuffer + AlphaBltSubPic(rDstPri, rDstVid); + + // Casimir666 : show OSD + if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE) { + CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock); + CRect rcSrc(m_VMR9AlphaBitmap.rSrc); + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE*)m_VMR9AlphaBitmapData) { + if ((m_pD3DXLoadSurfaceFromMemory != nullptr) && + SUCCEEDED(hr = m_pD3DDev->CreateTexture(rcSrc.Width(), rcSrc.Height(), 1, + D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, &m_pOSDTexture, nullptr))) { + if (SUCCEEDED(hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface))) { + hr = m_pD3DXLoadSurfaceFromMemory(m_pOSDSurface, + nullptr, + nullptr, + (BYTE*)m_VMR9AlphaBitmapData, + D3DFMT_A8R8G8B8, + m_VMR9AlphaBitmapWidthBytes, + nullptr, + &m_VMR9AlphaBitmapRect, + D3DX_FILTER_NONE, + m_VMR9AlphaBitmap.clrSrcKey); + } + if (FAILED(hr)) { + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + } + } + } + m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE; + + } + + if (m_bAlphaBitmapEnable && m_pAlphaBitmapTexture) { + CRect rcDst(rSrcPri); + AlphaBlt(rSrcPri, rcDst, m_pAlphaBitmapTexture); + } + + if (rd->m_bResetStats) { + ResetStats(); + rd->m_bResetStats = false; + } + + if (rd->m_iDisplayStats) { + DrawStats(); + } + + if (m_pOSDTexture) { + AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture); + } + } + + m_pD3DDev->EndScene(); + + BOOL bCompositionEnabled = m_bCompositionEnabled; + + bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !r.m_AdvRendSets.bVMR9VSync; + + CComPtr pEventQueryFlushBeforeVSync; + m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQueryFlushBeforeVSync); + if (pEventQueryFlushBeforeVSync) { + pEventQueryFlushBeforeVSync->Issue(D3DISSUE_END); + } + + if (r.m_AdvRendSets.bVMRFlushGPUBeforeVSync && pEventQueryFlushBeforeVSync) { + LONGLONG llPerf = rd->GetPerfCounter(); + BOOL Data; + //Sleep(5); + LONGLONG FlushStartTime = rd->GetPerfCounter(); + while (S_FALSE == pEventQueryFlushBeforeVSync->GetData(&Data, sizeof(Data), D3DGETDATA_FLUSH)) { + if (!r.m_AdvRendSets.bVMRFlushGPUWait) { + break; + } + Sleep(1); + if (rd->GetPerfCounter() - FlushStartTime > 500000) { + break; // timeout after 50 ms + } + } + if (r.m_AdvRendSets.bVMRFlushGPUWait) { + m_WaitForGPUTime = rd->GetPerfCounter() - llPerf; + } else { + m_WaitForGPUTime = 0; + } + } else { + m_WaitForGPUTime = 0; + } + + if (bAll) { + m_PaintTime = (rd->GetPerfCounter() - StartPaint); + m_PaintTimeMin = std::min(m_PaintTimeMin, m_PaintTime); + m_PaintTimeMax = std::max(m_PaintTimeMax, m_PaintTime); + } + + bool bWaited = false; + HANDLE lockOwner = nullptr; + if (bAll) { + // Only sync to refresh when redrawing all + bool bTest = WaitForVBlank(bWaited, lockOwner); + ASSERT(bTest == bDoVSyncInPresent); + if (!bDoVSyncInPresent) { + LONGLONG Time = rd->GetPerfCounter(); + OnVBlankFinished(bAll, Time); + if (!m_bIsEVR || m_OrderedPaint) { + CalculateJitter(Time); + } + } + } + + // Create a device pointer m_pd3dDevice + + // Create a query object + { + CComPtr pEventQueryFlushAfterVSync; + m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQueryFlushAfterVSync); + + LONGLONG llPerf = rd->GetPerfCounter(); + CRect presentationSrcRect(rDstPri), presentationDestRect(m_windowRect); + // PresentEx() / Present() performs the clipping + // TODO: fix the race and uncomment the assert + //ASSERT(presentationSrcRect.Size() == presentationDestRect.Size()); + if (m_pD3DDevEx) { + if (m_bIsFullscreen) { + hr = m_pD3DDevEx->PresentEx(nullptr, nullptr, nullptr, nullptr, 0); + } else { + hr = m_pD3DDevEx->PresentEx(presentationSrcRect, presentationDestRect, nullptr, nullptr, 0); + } + } else { + if (m_bIsFullscreen) { + hr = m_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr); + } else { + hr = m_pD3DDev->Present(presentationSrcRect, presentationDestRect, nullptr, nullptr); + } + } + // Issue an End event + if (pEventQueryFlushAfterVSync) { + pEventQueryFlushAfterVSync->Issue(D3DISSUE_END); + } + + BOOL Data; + + if (r.m_AdvRendSets.bVMRFlushGPUAfterPresent && pEventQueryFlushAfterVSync) { + LONGLONG FlushStartTime = rd->GetPerfCounter(); + while (S_FALSE == pEventQueryFlushAfterVSync->GetData(&Data, sizeof(Data), D3DGETDATA_FLUSH)) { + if (!r.m_AdvRendSets.bVMRFlushGPUWait) { + break; + } + if (rd->GetPerfCounter() - FlushStartTime > 500000) { + break; // timeout after 50 ms + } + } + } + + int ScanLine; + int bInVBlank; + GetVBlank(ScanLine, bInVBlank, false); + + if (bAll && (!m_bIsEVR || m_OrderedPaint)) { + m_VBlankEndPresent = ScanLine; + } + + while (ScanLine == 0 || bInVBlank) { + GetVBlank(ScanLine, bInVBlank, false); + + } + m_VBlankStartMeasureTime = rd->GetPerfCounter(); + m_VBlankStartMeasure = ScanLine; + + if (bAll && bDoVSyncInPresent) { + m_PresentWaitTime = rd->GetPerfCounter() - llPerf; + m_PresentWaitTimeMin = std::min(m_PresentWaitTimeMin, m_PresentWaitTime); + m_PresentWaitTimeMax = std::max(m_PresentWaitTimeMax, m_PresentWaitTime); + } else { + m_PresentWaitTime = 0; + m_PresentWaitTimeMin = std::min(m_PresentWaitTimeMin, m_PresentWaitTime); + m_PresentWaitTimeMax = std::max(m_PresentWaitTimeMax, m_PresentWaitTime); + } + } + + if (bDoVSyncInPresent) { + LONGLONG Time = rd->GetPerfCounter(); + if (!m_bIsEVR || m_OrderedPaint) { + CalculateJitter(Time); + } + OnVBlankFinished(bAll, Time); + } + + if (lockOwner) { + UnlockD3DDevice(lockOwner); + } + + /*if (!bWaited) + { + bWaited = true; + WaitForVBlank(bWaited); + TRACE(_T("Double VBlank\n")); + ASSERT(bWaited); + if (!bDoVSyncInPresent) + { + CalculateJitter(); + OnVBlankFinished(bAll); + } + }*/ + + if (!m_bPendingResetDevice) { + bool fResetDevice = false; + + if (hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { + TRACE(_T("Reset Device: D3D Device Lost\n")); + fResetDevice = true; + } + + if (hr == S_PRESENT_MODE_CHANGED) { + TRACE(_T("Reset Device: D3D Device mode changed\n")); + fResetDevice = true; + } + + if (SettingsNeedResetDevice(r)) { + TRACE(_T("Reset Device: settings changed\n")); + fResetDevice = true; + } + + bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + if ((bCompositionEnabled != 0) != m_bCompositionEnabled) { + if (m_bIsFullscreen) { + m_bCompositionEnabled = (bCompositionEnabled != 0); + } else { + TRACE(_T("Reset Device: DWM composition changed\n")); + fResetDevice = true; + } + } + + if (r.fResetDevice) { + LONGLONG time = rd->GetPerfCounter(); + if (time > m_LastAdapterCheck + 20000000) { // check every 2 sec. + m_LastAdapterCheck = time; +#ifdef _DEBUG + D3DDEVICE_CREATION_PARAMETERS Parameters; + if (SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))) { + ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter); + } +#endif + if (m_CurrentAdapter != GetAdapter(m_pD3D)) { + TRACE(_T("Reset Device: D3D adapter changed\n")); + fResetDevice = true; + } +#ifdef _DEBUG + else { + ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D))); + } +#endif + } + } + + if (fResetDevice) { + m_bPendingResetDevice = true; + SendResetRequest(); + } + } + + if (m_OrderedPaint) { + --m_OrderedPaint; + } else { + //if (m_bIsEVR) + // TRACE(_T("UNORDERED PAINT!!!!!!\n")); + } + return true; +} + +double CDX9AllocatorPresenter::GetFrameTime() const +{ + if (m_DetectedLock) { + return m_DetectedFrameTime; + } + + return m_rtTimePerFrame / 10000000.0; +} + +double CDX9AllocatorPresenter::GetFrameRate() const +{ + if (m_DetectedLock) { + return m_DetectedFrameRate; + } + + return 10000000.0 / m_rtTimePerFrame; +} + +void CDX9AllocatorPresenter::SendResetRequest() +{ + if (!m_bDeviceResetRequested) { + m_bDeviceResetRequested = true; + AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE); + } +} + +STDMETHODIMP_(bool) CDX9AllocatorPresenter::ResetDevice() +{ + TRACE(_T("ResetDevice\n")); + ASSERT(m_MainThreadId == GetCurrentThreadId()); + + // In VMR-9 deleting the surfaces before we are told to is bad ! + // Can't comment out this because CDX9AllocatorPresenter is used by EVR Custom + // Why is EVR using a presenter for DX9 anyway ?! + DeleteSurfaces(); + + if (m_pD3DEx) { + m_pD3DEx.Release(); + m_pD3D = nullptr; + Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); + if (m_pD3DEx) { + m_pD3D = m_pD3DEx; + } else { + ASSERT(FALSE); + m_bDeviceResetRequested = false; + return false; + } + } + + HRESULT hr; + CString Error; + // TODO: Report error messages here + + // In VMR-9 'AllocSurfaces' call is redundant afaik because + // 'CreateDevice' calls 'm_pIVMRSurfAllocNotify->ChangeD3DDevice' which in turn calls + // 'CVMR9AllocatorPresenter::InitializeDevice' which calls 'AllocSurfaces' + if (FAILED(hr = CreateDevice(Error)) || FAILED(hr = AllocSurfaces())) { + // TODO: We should probably pause player +#ifdef _DEBUG + Error += GetWindowsErrorMessage(hr, nullptr); + TRACE(_T("D3D Reset Error\n%ws\n\n"), Error.GetBuffer()); +#endif + m_bDeviceResetRequested = false; + return false; + } + OnResetDevice(); + m_bDeviceResetRequested = false; + m_bPendingResetDevice = false; + + return true; +} + +STDMETHODIMP_(bool) CDX9AllocatorPresenter::DisplayChange() +{ + m_bPendingResetDevice = true; + SendResetRequest(); + return true; +} + +void CDX9AllocatorPresenter::ResetStats() +{ + CRenderersData* rd = GetRenderersData(); + LONGLONG Time = rd->GetPerfCounter(); + + m_PaintTime = 0; + m_PaintTimeMin = 3000000000; + m_PaintTimeMax = 0; + + m_RasterStatusWaitTime = 0; + m_RasterStatusWaitTimeMin = 3000000000; + m_RasterStatusWaitTimeMax = 0; + + m_MinSyncOffset = 0; + m_MaxSyncOffset = 0; + m_fSyncOffsetAvr = 0; + m_fSyncOffsetStdDev = 0; + + CalculateJitter(Time); +} + +void CDX9AllocatorPresenter::InitStats() +{ + ASSERT(m_pD3DDev); + static LONG currentHeight = 0; + int newHeight = lround(FONT_HEIGHT * (double(m_windowRect.Width()) / REFERENCE_WIDTH)); + + if (m_pD3DXCreateFont && (!m_pFont || currentHeight != newHeight)) { + m_pFont = nullptr; + if (newHeight <= 0) { + ASSERT(FALSE); + } + m_pD3DXCreateFont(m_pD3DDev, newHeight, 0, newHeight < BOLD_THRESHOLD ? FW_NORMAL : FW_BOLD, + 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, + FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont); + currentHeight = newHeight; + } + + if (m_pD3DXCreateSprite && !m_pSprite) { + m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite); + } + + if (m_pD3DXCreateLine && !m_pLine) { + m_pD3DXCreateLine(m_pD3DDev, &m_pLine); + } +} + +void CDX9AllocatorPresenter::DrawStats() +{ + const CRenderersData* rd = GetRenderersData(); + + int iDetailedStats; + switch (rd->m_iDisplayStats) { + case 1: + iDetailedStats = 2; + break; + case 2: + iDetailedStats = 1; + break; + case 3: + iDetailedStats = 0; + break; + default: + ASSERT(FALSE); + return; + } + + InitStats(); + const float textScale = float(m_windowRect.Width()) / REFERENCE_WIDTH; + const int lineHeight = lround((FONT_HEIGHT + TEXT_PADDING) * textScale); + + if (m_pFont && m_pSprite) { + auto drawText = [&](CRect & rc, const CString & strText) { + D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f); + D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f); + + RECT shadowRect = rc; + OffsetRect(&shadowRect, 2, 2); + + // Draw shadow + m_pFont->DrawText(m_pSprite, strText, -1, &shadowRect, DT_NOCLIP, Color0); + // Draw text + m_pFont->DrawText(m_pSprite, strText, -1, rc, DT_NOCLIP, Color1); + rc.OffsetRect(0, lineHeight); + }; + + const CRenderersSettings& r = GetRenderersSettings(); + LONGLONG llMaxJitter = m_MaxJitter; + LONGLONG llMinJitter = m_MinJitter; + LONGLONG llMaxSyncOffset = m_MaxSyncOffset; + LONGLONG llMinSyncOffset = m_MinSyncOffset; + CRect rc(lineHeight, lineHeight, 0, 0); + + m_pSprite->Begin(D3DXSPRITE_ALPHABLEND); + CString strText; + if (iDetailedStats > 1) { + if (m_bIsEVR) { + strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s) (%7.3f ms = %.03f%s, %2.03f StdDev) Clock: %1.4f %%", + m_fAvrFps, + double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), + m_bInterlaced ? L"I" : L"P", GetFrameTime() * 1000.0, GetFrameRate(), + m_DetectedLock ? L" L" : L"", m_DetectedFrameTimeStdDev / 10000.0, + m_ModeratedTimeSpeed * 100.0); + } else { + strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s)", + m_fAvrFps, + double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), + m_bInterlaced ? L"I" : L"P"); + } + } else { + strText.Format(L"Frame rate : %7.03f (%.03f%s)", m_fAvrFps, GetFrameRate(), m_DetectedLock ? L" L" : L""); + } + drawText(rc, strText); + + if (iDetailedStats > 1) { + strText = _T("Settings : "); + + if (m_bIsEVR) { + strText += _T("EVR "); + } else { + strText += _T("VMR9 "); + } + + if (m_bIsFullscreen) { + strText += _T("FS "); + } + if (r.m_AdvRendSets.bVMR9FullscreenGUISupport) { + strText += _T("FSGui "); + } + + if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { + strText += _T("DisDC "); + } + + if (m_bColorManagement) { + strText += _T("ColorMan "); + } + + if (r.m_AdvRendSets.bVMRFlushGPUBeforeVSync) { + strText += _T("GPUFlushBV "); + } + if (r.m_AdvRendSets.bVMRFlushGPUAfterPresent) { + strText += _T("GPUFlushAP "); + } + + if (r.m_AdvRendSets.bVMRFlushGPUWait) { + strText += _T("GPUFlushWt "); + } + + if (r.m_AdvRendSets.bVMR9VSync) { + strText += _T("VS "); + } + if (r.m_AdvRendSets.bVMR9AlterativeVSync) { + strText += _T("AltVS "); + } + if (r.m_AdvRendSets.bVMR9VSyncAccurate) { + strText += _T("AccVS "); + } + if (r.m_AdvRendSets.iVMR9VSyncOffset) { + strText.AppendFormat(_T("VSOfst(%d)"), r.m_AdvRendSets.iVMR9VSyncOffset); + } + + if (m_bFullFloatingPointProcessing) { + strText += _T("FullFP "); + } + + if (m_bHalfFloatingPointProcessing) { + strText += _T("HalfFP "); + } + + if (m_bIsEVR) { + if (m_bHighColorResolution) { + strText += _T("10bitOut "); + } + if (m_bForceInputHighColorResolution) { + strText += _T("For10bitIn "); + } + if (r.m_AdvRendSets.bEVREnableFrameTimeCorrection) { + strText += _T("FTC "); + } + if (r.m_AdvRendSets.iEVROutputRange == 0) { + strText += _T("0-255 "); + } else if (r.m_AdvRendSets.iEVROutputRange == 1) { + strText += _T("16-235 "); + } + } + + + drawText(rc, strText); + + strText.Format(L"Formats : Surface %s Backbuffer %s Display %s Device %s %s", + GetD3DFormatStr(m_SurfaceType), GetD3DFormatStr(m_BackbufferType), + GetD3DFormatStr(m_DisplayType), m_pD3DDevEx ? L"D3DDevEx" : L"D3DDev", + m_D3DDevExError.IsEmpty() ? _T("") : (_T("D3DExError: ") + m_D3DDevExError).GetString()); + drawText(rc, strText); + + if (m_bIsEVR) { + if (r.m_AdvRendSets.bVMR9VSync) { + strText.Format(_T("Refresh rate : %.05f Hz SL: %4d (%3u Hz) "), + m_DetectedRefreshRate, int(m_DetectedScanlinesPerFrame + 0.5), m_refreshRate); + } else { + strText.Format(_T("Refresh rate : %3u Hz "), m_refreshRate); + } + strText.AppendFormat(_T("Last Duration: %10.6f Corrected Frame Time: %s"), + double(m_LastFrameDuration) / 10000.0, m_bCorrectedFrameTime ? _T("Yes") : _T("No")); + drawText(rc, strText); + } + } + + if (m_bSyncStatsAvailable) { + if (iDetailedStats > 1) { + strText.Format(_T("Sync offset : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms, Avr = %7.3f ms, Mode = %d"), + (double(llMinSyncOffset) / 10000.0), (double(llMaxSyncOffset) / 10000.0), + m_fSyncOffsetStdDev / 10000.0, m_fSyncOffsetAvr / 10000.0, m_VSyncMode); + } else { + strText.Format(_T("Sync offset : Mode = %d"), m_VSyncMode); + } + drawText(rc, strText); + } + + if (iDetailedStats > 1) { + strText.Format(_T("Jitter : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms"), + (double(llMinJitter) / 10000.0), + (double(llMaxJitter) / 10000.0), + m_fJitterStdDev / 10000.0); + drawText(rc, strText); + } + + if (m_pAllocator && iDetailedStats > 1) { + CDX9SubPicAllocator* pAlloc = (CDX9SubPicAllocator*)m_pAllocator.p; + int nFree = 0; + int nAlloc = 0; + int nSubPic = 0; + REFERENCE_TIME rtQueueStart = 0; + REFERENCE_TIME rtQueueEnd = 0; + + if (m_pSubPicQueue) { + REFERENCE_TIME rtQueueNow = 0; + m_pSubPicQueue->GetStats(nSubPic, rtQueueNow, rtQueueStart, rtQueueEnd); + } + + pAlloc->GetStats(nFree, nAlloc); + strText.Format(_T("Subtitles : Free %d Allocated %d Buffered %d QueueStart %7.3f QueueEnd %7.3f"), + nFree, nAlloc, nSubPic, (double(rtQueueStart) / 10000000.0), + (double(rtQueueEnd) / 10000000.0)); + drawText(rc, strText); + } + + if (iDetailedStats > 1) { + if (m_VBlankEndPresent == -100000) { + strText.Format(_T("VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d"), + m_VBlankStartWait, m_VBlankEndWait, + (double(m_VBlankWaitTime) / 10000.0), + (double(m_VBlankLockTime) / 10000.0), + m_VBlankMin, m_VBlankMax - m_VBlankMin); + } else { + strText.Format(_T("VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d EndPresent %4d"), + m_VBlankStartWait, m_VBlankEndWait, + (double(m_VBlankWaitTime) / 10000.0), + (double(m_VBlankLockTime) / 10000.0), + m_VBlankMin, + m_VBlankMax - m_VBlankMin, + m_VBlankEndPresent); + } + } else { + if (m_VBlankEndPresent == -100000) { + strText.Format(_T("VBlank Wait : Start %4d End %4d"), m_VBlankStartWait, m_VBlankEndWait); + } else { + strText.Format(_T("VBlank Wait : Start %4d End %4d EP %4d"), m_VBlankStartWait, m_VBlankEndWait, + m_VBlankEndPresent); + } + } + drawText(rc, strText); + + BOOL bCompositionEnabled = m_bCompositionEnabled; + + bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !r.m_AdvRendSets.bVMR9VSync; + + if (iDetailedStats > 1 && bDoVSyncInPresent) { + strText.Format(_T("Present Wait : Wait %7.3f ms Min %7.3f ms Max %7.3f ms"), + (double(m_PresentWaitTime) / 10000.0), + (double(m_PresentWaitTimeMin) / 10000.0), + (double(m_PresentWaitTimeMax) / 10000.0)); + drawText(rc, strText); + } + + if (iDetailedStats > 1) { + if (m_WaitForGPUTime) { + strText.Format(_T("Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms GPU %7.3f ms"), + (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), + (double(m_PaintTimeMin) / 10000.0), + (double(m_PaintTimeMax) / 10000.0), + (double(m_WaitForGPUTime) / 10000.0)); + } else { + strText.Format(_T("Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms"), + (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), + (double(m_PaintTimeMin) / 10000.0), + (double(m_PaintTimeMax) / 10000.0)); + } + } else { + if (m_WaitForGPUTime) { + strText.Format(_T("Paint Time : Draw %7.3f ms GPU %7.3f ms"), + (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), + (double(m_WaitForGPUTime) / 10000.0)); + } else { + strText.Format(_T("Paint Time : Draw %7.3f ms"), + (double(m_PaintTime - m_WaitForGPUTime) / 10000.0)); + } + } + drawText(rc, strText); + + if (iDetailedStats > 1 && r.m_AdvRendSets.bVMR9VSync) { + strText.Format(_T("Raster Status: Wait %7.3f ms Min %7.3f ms Max %7.3f ms"), + (double(m_RasterStatusWaitTime) / 10000.0), + (double(m_RasterStatusWaitTimeMin) / 10000.0), + (double(m_RasterStatusWaitTimeMax) / 10000.0)); + drawText(rc, strText); + } + + if (iDetailedStats > 1) { + if (m_bIsEVR) { + strText.Format(_T("Buffering : Buffered %3ld Free %3ld Current Surface %3d"), + m_nUsedBuffer, m_nNbDXSurface - m_nUsedBuffer, m_nCurSurface); + } else { + strText.Format(_T("Buffering : VMR9Surfaces %3d VMR9Surface %3d"), + m_nVMR9Surfaces, m_iVMR9Surface); + } + } else { + strText.Format(_T("Buffered : %3ld"), m_nUsedBuffer); + } + drawText(rc, strText); + + + if (iDetailedStats > 1) { + strText.Format(_T("Video size : %ld x %ld (AR = %ld : %ld)"), + m_nativeVideoSize.cx, m_nativeVideoSize.cy, m_aspectRatio.cx, m_aspectRatio.cy); + drawText(rc, strText); + if (m_pVideoTexture[0] || m_pVideoSurface[0]) { + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (m_pVideoTexture[0]) { + m_pVideoTexture[0]->GetLevelDesc(0, &desc); + } else if (m_pVideoSurface[0]) { + m_pVideoSurface[0]->GetDesc(&desc); + } + + if (desc.Width != (UINT)m_nativeVideoSize.cx || desc.Height != (UINT)m_nativeVideoSize.cy) { + strText.Format(_T("Texture size : %u x %u"), desc.Width, desc.Height); + drawText(rc, strText); + } + } + + + drawText(rc, rd->m_strDXVAInfo); + + strText.Format(_T("DirectX SDK : %u"), rd->GetDXSdkRelease()); + drawText(rc, strText); + + if (!m_D3D9Device.IsEmpty()) { + strText = _T("Render device: ") + m_D3D9Device; + drawText(rc, strText); + } + + if (!m_Decoder.IsEmpty()) { + strText = _T("Decoder : ") + m_Decoder; + drawText(rc, strText); + } + + for (int i = 0; i < 6; i++) { + if (m_strStatsMsg[i][0]) { + drawText(rc, m_strStatsMsg[i]); + } + } + } + m_pSprite->End(); + } + + if (m_pLine && iDetailedStats) { + D3DXVECTOR2 points[NB_JITTER]; + const float graphWidth = GRAPH_WIDTH * textScale; + const float graphHeight = GRAPH_HEIGHT * textScale; + const float topLeftX = m_windowRect.Width() - (graphWidth + lineHeight); + const float topLeftY = m_windowRect.Height() - (graphHeight + lineHeight); + const float gridStepY = graphHeight / 24.0f; + const float gridStepX = graphWidth / NB_JITTER; + + // Draw background + DrawRect(RGB(0, 0, 0), 80, CRect(int(topLeftX), + int(topLeftY), + int(topLeftX + graphWidth), + int(topLeftY + graphHeight))); + + m_pLine->SetWidth(2.5f * textScale); + m_pLine->SetAntialias(TRUE); + m_pLine->Begin(); + + // Draw grid lines + for (int i = 1; i < 24; ++i) { + points[0].x = topLeftX; + points[0].y = topLeftY + i * gridStepY; + points[1].y = points[0].y; + + float lineLength; + D3DCOLOR color; + if (i % 12 == 0) { + lineLength = 1.0f; + color = D3DCOLOR_XRGB(100, 100, 255); + } else if (i % 4 == 0) { + lineLength = 0.96f; + color = D3DCOLOR_XRGB(100, 100, 180); + } else { + lineLength = 0.04f; + color = D3DCOLOR_XRGB(100, 100, 140); + } + points[1].x = topLeftX + graphWidth * lineLength; + m_pLine->Draw(points, 2, color); + } + + if (m_rtTimePerFrame) { + // Draw jitter + for (int i = 1; i <= NB_JITTER; ++i) { + int nIndex = (m_nNextJitter + i) % NB_JITTER; + if (nIndex < 0) { + nIndex += NB_JITTER; + ASSERT(FALSE); + } + float jitter = float(m_pllJitter[nIndex] - m_fJitterMean); + points[i - 1].x = topLeftX + i * gridStepX; + points[i - 1].y = topLeftY + (jitter * textScale / 2000.0f + graphHeight / 2.0f); + } + m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100)); + + if (m_bSyncStatsAvailable) { + // Draw sync offset + for (int i = 1; i <= NB_JITTER; ++i) { + int nIndex = (m_nNextSyncOffset + i) % NB_JITTER; + if (nIndex < 0) { + nIndex += NB_JITTER; + } + points[i - 1].x = topLeftX + i * gridStepX; + points[i - 1].y = topLeftY + (m_pllSyncOffset[nIndex] * textScale / 2000.0f + graphHeight / 2.0f); + } + m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100)); + } + } + m_pLine->End(); + } +} + +STDMETHODIMP CDX9AllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) +{ + CheckPointer(size, E_POINTER); + + // Keep a reference so that we can safely work on the surface + // without having to lock everything + CComPtr pVideoSurface; + { + CAutoLock cAutoLock(this); + CheckPointer(m_pVideoSurface[m_nCurSurface], E_FAIL); + pVideoSurface = m_pVideoSurface[m_nCurSurface]; + } + + HRESULT hr; + + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(hr = pVideoSurface->GetDesc(&desc))) { + return hr; + } + + CSize framesize = GetVideoSize(false); + const CSize dar = GetVideoSize(true); + + bool resize = false; + if (dar.cx > 0 && dar.cy > 0 && (dar.cx != desc.Width || dar.cy != desc.Height)) { + framesize.cx = MulDiv(framesize.cy, dar.cx, dar.cy); + resize = true; + desc.Width = framesize.cx; + desc.Height = framesize.cy; + } + + DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3); + if (!lpDib) { + *size = required; + return S_OK; + } + if (*size < required) { + return E_OUTOFMEMORY; + } + *size = required; + + CComPtr pSurface, tSurface; + // Convert to 8-bit when using 10-bit or full/half processing modes + if (desc.Format != D3DFMT_X8R8G8B8) { + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tSurface, nullptr)) + || FAILED(hr = m_pD3DXLoadSurfaceFromSurface(tSurface, nullptr, nullptr, pVideoSurface, nullptr, nullptr, D3DX_DEFAULT, 0))) { + return hr; + } + } else { + tSurface = pVideoSurface; + } + + if (resize) { + CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; + if (FAILED(hr = m_pD3DDevEx->CreateRenderTarget(framesize.cx, framesize.cy, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurface, nullptr)) + || FAILED(hr = m_pD3DDevEx->SetRenderTarget(0, pSurface)) + || FAILED(hr = Resize(pVideoTexture, { CPoint(0, 0), m_nativeVideoSize }, { CPoint(0, 0), framesize }))) { + return hr; + } + } else { + pSurface = tSurface; + } + + D3DLOCKED_RECT r; + if (FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { + // If this fails, we try to use a surface allocated from the system memory + CComPtr pInputSurface = pSurface; + pSurface = nullptr; + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, nullptr)) + || FAILED(hr = m_pD3DDev->GetRenderTargetData(pInputSurface, pSurface)) + || FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { + return hr; + } + } + + hr = CreateDIBFromSurfaceData(desc, r, lpDib); + + pSurface->UnlockRect(); + + return hr; +} + +STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) +{ + return SetPixelShader2(pSrcData, pTarget, false); +} + +STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) +{ + CAutoLock cRenderLock(&m_RenderLock); + + return SetCustomPixelShader(pSrcData, pTarget, bScreenSpace); +} + +STDMETHODIMP CDX9AllocatorPresenter::SetD3DFullscreen(bool fEnabled) +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + fullScreenChanged = (fEnabled != m_bIsFullscreen); + m_bIsFullscreen = fEnabled; + return S_OK; +} + +STDMETHODIMP CDX9AllocatorPresenter::GetD3DFullscreen(bool* pfEnabled) +{ + CheckPointer(pfEnabled, E_POINTER); + *pfEnabled = m_bIsFullscreen; + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h index 940e7badbb9..06d18892a57 100644 --- a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h @@ -1,313 +1,313 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#pragma once - -#include "DX9RenderingEngine.h" -#include - -#define VMRBITMAP_UPDATE 0x80000000 -#define NB_JITTER 126 - -class CFocusThread; - -namespace DSObjects -{ - - class CDX9AllocatorPresenter - : public CDX9RenderingEngine - , public ID3DFullscreenControl - { - public: - CCritSec m_VMR9AlphaBitmapLock; - void UpdateAlphaBitmap(); - protected: - bool m_bAlternativeVSync; - bool m_bCompositionEnabled; - bool m_bIsEVR; - int m_OrderedPaint; - int m_VSyncMode; - bool m_bDesktopCompositionDisabled; - bool m_bIsFullscreen, fullScreenChanged; - bool m_bNeedCheckSample; - DWORD m_MainThreadId; - bool m_bIsPreview; - bool m_bIsRendering; - - CRenderersSettings::CAdvRendererSettings m_LastRendererSettings; - - HMODULE m_hDWMAPI; - - HRESULT(__stdcall* m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled); - HRESULT(__stdcall* m_pDwmEnableComposition)(UINT uCompositionAction); - - CCritSec m_RenderLock; - CComPtr m_pDirectDraw; - - HANDLE LockD3DDevice() { - if (m_pD3DDev) { - _RTL_CRITICAL_SECTION* pCritSec = (_RTL_CRITICAL_SECTION*)((size_t)m_pD3DDev.p + sizeof(size_t)); - - if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec)) - && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo)))) { - if (pCritSec->DebugInfo->CriticalSection == pCritSec) { - EnterCriticalSection(pCritSec); - return pCritSec->OwningThread; - } - } - } - return 0; - } - - void UnlockD3DDevice(HANDLE& lockOwner) { - if (m_pD3DDev) { - _RTL_CRITICAL_SECTION* pCritSec = (_RTL_CRITICAL_SECTION*)((size_t)m_pD3DDev.p + sizeof(size_t)); - - if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec)) - && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo)))) { - if (pCritSec->DebugInfo->CriticalSection == pCritSec && pCritSec->OwningThread == lockOwner) { - LeaveCriticalSection(pCritSec); - } - } - } - } - - CString m_D3DDevExError; - CComPtr m_pOSDTexture; - CComPtr m_pOSDSurface; - CComPtr m_pLine; - CComPtr m_pFont; - bool m_bAlphaBitmapEnable = false; - CComPtr m_pAlphaBitmapTexture; - MFVideoAlphaBitmapParams m_AlphaBitmapParams = {}; - - CComPtr m_pSprite; - - bool SettingsNeedResetDevice(CRenderersSettings& r); - - virtual HRESULT CreateDevice(CString& _Error); - virtual HRESULT AllocSurfaces(); - virtual void DeleteSurfaces(); - - LONGLONG m_LastAdapterCheck; - UINT GetAdapter(IDirect3D9* pD3D, bool bGetAdapter = true); - DWORD GetVertexProcessing(); - - bool GetVBlank(int& _ScanLine, int& _bInVBlank, bool _bMeasureTime); - bool WaitForVBlankRange(int& _RasterStart, int _RasterEnd, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, HANDLE& lockOwner); - bool WaitForVBlank(bool& _Waited, HANDLE& lockOwner); - int GetVBlackPos(); - void CalculateJitter(LONGLONG PerformanceCounter); - virtual void OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter) {} - - // Casimir666 - typedef HRESULT(WINAPI* D3DXLoadSurfaceFromMemoryPtr)( - LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY* pDestPalette, - CONST RECT* pDestRect, - LPCVOID pSrcMemory, - D3DFORMAT SrcFormat, - UINT SrcPitch, - CONST PALETTEENTRY* pSrcPalette, - CONST RECT* pSrcRect, - DWORD Filter, - D3DCOLOR ColorKey); - - typedef HRESULT(WINAPI* D3DXLoadSurfaceFromSurfacePtr)( - LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY* pDestPalette, - CONST RECT* pDestRect, - LPDIRECT3DSURFACE9 pSrcSurface, - CONST PALETTEENTRY* pSrcPalette, - CONST RECT* pSrcRect, - DWORD Filter, - D3DCOLOR ColorKey); - - typedef HRESULT(WINAPI* D3DXCreateLinePtr)(LPDIRECT3DDEVICE9 pDevice, LPD3DXLINE* ppLine); - - typedef HRESULT(WINAPI* D3DXCreateFontPtr)( - LPDIRECT3DDEVICE9 pDevice, - int Height, - UINT Width, - UINT Weight, - UINT MipLevels, - bool Italic, - DWORD CharSet, - DWORD OutputPrecision, - DWORD Quality, - DWORD PitchAndFamily, - LPCWSTR pFaceName, - LPD3DXFONT* ppFont); - - void InitStats(); - void ResetStats(); - void DrawStats(); - virtual void OnResetDevice() {}; - void SendResetRequest(); - - double GetFrameTime() const; - double GetFrameRate() const; - - - int m_nTearingPos; - VMR9AlphaBitmap m_VMR9AlphaBitmap; - CAutoVectorPtr m_VMR9AlphaBitmapData; - CRect m_VMR9AlphaBitmapRect; - int m_VMR9AlphaBitmapWidthBytes; - - D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory; - D3DXLoadSurfaceFromSurfacePtr m_pD3DXLoadSurfaceFromSurface; - D3DXCreateLinePtr m_pD3DXCreateLine; - D3DXCreateFontPtr m_pD3DXCreateFont; - HRESULT(__stdcall* m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); - - - - int m_nVMR9Surfaces; // Total number of DX Surfaces - int m_iVMR9Surface; - long m_nUsedBuffer; - - double m_fAvrFps; // Estimate the real FPS - double m_fJitterStdDev; // Estimate the Jitter std dev - double m_fJitterMean; - double m_fSyncOffsetStdDev; - double m_fSyncOffsetAvr; - double m_DetectedRefreshRate; - - CCritSec m_refreshRateLock; - double m_DetectedRefreshTime; - double m_DetectedRefreshTimePrim; - double m_DetectedScanlineTime; - double m_DetectedScanlineTimePrim; - double m_DetectedScanlinesPerFrame; - - double GetRefreshRate() const { - if (m_DetectedRefreshRate) { - return m_DetectedRefreshRate; - } - return m_refreshRate; - } - - LONG GetScanLines() const { - if (m_DetectedRefreshRate) { - return (LONG)m_DetectedScanlinesPerFrame; - } - return m_ScreenSize.cy; - } - - double m_ldDetectedRefreshRateList[100]; - double m_ldDetectedScanlineRateList[100]; - int m_DetectedRefreshRatePos; - bool m_bSyncStatsAvailable; - LONGLONG m_pllJitter [NB_JITTER]; // Jitter buffer for stats - LONGLONG m_pllSyncOffset [NB_JITTER]; // Jitter buffer for stats - LONGLONG m_llLastPerf; - LONGLONG m_JitterStdDev; - LONGLONG m_MaxJitter; - LONGLONG m_MinJitter; - LONGLONG m_MaxSyncOffset; - LONGLONG m_MinSyncOffset; - int m_nNextJitter; - int m_nNextSyncOffset; - REFERENCE_TIME m_rtTimePerFrame; - double m_DetectedFrameRate; - double m_DetectedFrameTime; - double m_DetectedFrameTimeStdDev; - bool m_DetectedLock; - LONGLONG m_DetectedFrameTimeHistory[60]; - double m_DetectedFrameTimeHistoryHistory[500]; - int m_DetectedFrameTimePos; - int m_bInterlaced; - - int m_VBlankEndWait; - int m_VBlankStartWait; - LONGLONG m_VBlankWaitTime; - LONGLONG m_VBlankLockTime; - int m_VBlankMin; - int m_VBlankMinCalc; - int m_VBlankMax; - int m_VBlankEndPresent; - LONGLONG m_VBlankStartMeasureTime; - int m_VBlankStartMeasure; - - LONGLONG m_PresentWaitTime; - LONGLONG m_PresentWaitTimeMin; - LONGLONG m_PresentWaitTimeMax; - - LONGLONG m_PaintTime; - LONGLONG m_PaintTimeMin; - LONGLONG m_PaintTimeMax; - - LONGLONG m_WaitForGPUTime; - - LONGLONG m_RasterStatusWaitTime; - LONGLONG m_RasterStatusWaitTimeMin; - LONGLONG m_RasterStatusWaitTimeMax; - LONGLONG m_RasterStatusWaitTimeMaxCalc; - - double m_ClockDiffCalc; - double m_ClockDiffPrim; - double m_ClockDiff; - - double m_TimeChangeHistory[100]; - double m_ClockChangeHistory[100]; - int m_ClockTimeChangeHistoryPos; - double m_ModeratedTimeSpeed; - double m_ModeratedTimeSpeedPrim; - double m_ModeratedTimeSpeedDiff; - - bool m_bCorrectedFrameTime; - int m_FrameTimeCorrection; - LONGLONG m_LastFrameDuration; - LONGLONG m_LastSampleTime; - - CString m_strStatsMsg[10]; - - CString m_D3D9Device; - - CString m_Decoder; - - CFocusThread* m_FocusThread; - HWND m_hFocusWindow; - - public: - CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString& _Error, bool isPreview = false); - ~CDX9AllocatorPresenter(); - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); - STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); - STDMETHODIMP_(bool) ResetDevice(); - STDMETHODIMP_(bool) DisplayChange(); - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() { - return m_bIsRendering; - } - - // ID3DFullscreenControl - STDMETHODIMP SetD3DFullscreen(bool fEnabled); - STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); - }; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#pragma once + +#include "DX9RenderingEngine.h" +#include + +#define VMRBITMAP_UPDATE 0x80000000 +#define NB_JITTER 126 + +class CFocusThread; + +namespace DSObjects +{ + + class CDX9AllocatorPresenter + : public CDX9RenderingEngine + , public ID3DFullscreenControl + { + public: + CCritSec m_VMR9AlphaBitmapLock; + void UpdateAlphaBitmap(); + protected: + bool m_bAlternativeVSync; + bool m_bCompositionEnabled; + bool m_bIsEVR; + int m_OrderedPaint; + int m_VSyncMode; + bool m_bDesktopCompositionDisabled; + bool m_bIsFullscreen, fullScreenChanged; + bool m_bNeedCheckSample; + DWORD m_MainThreadId; + bool m_bIsPreview; + bool m_bIsRendering; + + CRenderersSettings::CAdvRendererSettings m_LastRendererSettings; + + HMODULE m_hDWMAPI; + + HRESULT(__stdcall* m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled); + HRESULT(__stdcall* m_pDwmEnableComposition)(UINT uCompositionAction); + + CCritSec m_RenderLock; + CComPtr m_pDirectDraw; + + HANDLE LockD3DDevice() { + if (m_pD3DDev) { + _RTL_CRITICAL_SECTION* pCritSec = (_RTL_CRITICAL_SECTION*)((size_t)m_pD3DDev.p + sizeof(size_t)); + + if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec)) + && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo)))) { + if (pCritSec->DebugInfo->CriticalSection == pCritSec) { + EnterCriticalSection(pCritSec); + return pCritSec->OwningThread; + } + } + } + return 0; + } + + void UnlockD3DDevice(HANDLE& lockOwner) { + if (m_pD3DDev) { + _RTL_CRITICAL_SECTION* pCritSec = (_RTL_CRITICAL_SECTION*)((size_t)m_pD3DDev.p + sizeof(size_t)); + + if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec)) + && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo)))) { + if (pCritSec->DebugInfo->CriticalSection == pCritSec && pCritSec->OwningThread == lockOwner) { + LeaveCriticalSection(pCritSec); + } + } + } + } + + CString m_D3DDevExError; + CComPtr m_pOSDTexture; + CComPtr m_pOSDSurface; + CComPtr m_pLine; + CComPtr m_pFont; + bool m_bAlphaBitmapEnable = false; + CComPtr m_pAlphaBitmapTexture; + MFVideoAlphaBitmapParams m_AlphaBitmapParams = {}; + + CComPtr m_pSprite; + + bool SettingsNeedResetDevice(CRenderersSettings& r); + + virtual HRESULT CreateDevice(CString& _Error); + virtual HRESULT AllocSurfaces(); + virtual void DeleteSurfaces(); + + LONGLONG m_LastAdapterCheck; + UINT GetAdapter(IDirect3D9* pD3D, bool bGetAdapter = true); + DWORD GetVertexProcessing(); + + bool GetVBlank(int& _ScanLine, int& _bInVBlank, bool _bMeasureTime); + bool WaitForVBlankRange(int& _RasterStart, int _RasterEnd, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, HANDLE& lockOwner); + bool WaitForVBlank(bool& _Waited, HANDLE& lockOwner); + int GetVBlackPos(); + void CalculateJitter(LONGLONG PerformanceCounter); + virtual void OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter) {} + + // Casimir666 + typedef HRESULT(WINAPI* D3DXLoadSurfaceFromMemoryPtr)( + LPDIRECT3DSURFACE9 pDestSurface, + CONST PALETTEENTRY* pDestPalette, + CONST RECT* pDestRect, + LPCVOID pSrcMemory, + D3DFORMAT SrcFormat, + UINT SrcPitch, + CONST PALETTEENTRY* pSrcPalette, + CONST RECT* pSrcRect, + DWORD Filter, + D3DCOLOR ColorKey); + + typedef HRESULT(WINAPI* D3DXLoadSurfaceFromSurfacePtr)( + LPDIRECT3DSURFACE9 pDestSurface, + CONST PALETTEENTRY* pDestPalette, + CONST RECT* pDestRect, + LPDIRECT3DSURFACE9 pSrcSurface, + CONST PALETTEENTRY* pSrcPalette, + CONST RECT* pSrcRect, + DWORD Filter, + D3DCOLOR ColorKey); + + typedef HRESULT(WINAPI* D3DXCreateLinePtr)(LPDIRECT3DDEVICE9 pDevice, LPD3DXLINE* ppLine); + + typedef HRESULT(WINAPI* D3DXCreateFontPtr)( + LPDIRECT3DDEVICE9 pDevice, + int Height, + UINT Width, + UINT Weight, + UINT MipLevels, + bool Italic, + DWORD CharSet, + DWORD OutputPrecision, + DWORD Quality, + DWORD PitchAndFamily, + LPCWSTR pFaceName, + LPD3DXFONT* ppFont); + + void InitStats(); + void ResetStats(); + void DrawStats(); + virtual void OnResetDevice() {}; + void SendResetRequest(); + + double GetFrameTime() const; + double GetFrameRate() const; + + + int m_nTearingPos; + VMR9AlphaBitmap m_VMR9AlphaBitmap; + CAutoVectorPtr m_VMR9AlphaBitmapData; + CRect m_VMR9AlphaBitmapRect; + int m_VMR9AlphaBitmapWidthBytes; + + D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory; + D3DXLoadSurfaceFromSurfacePtr m_pD3DXLoadSurfaceFromSurface; + D3DXCreateLinePtr m_pD3DXCreateLine; + D3DXCreateFontPtr m_pD3DXCreateFont; + HRESULT(__stdcall* m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); + + + + int m_nVMR9Surfaces; // Total number of DX Surfaces + int m_iVMR9Surface; + long m_nUsedBuffer; + + double m_fAvrFps; // Estimate the real FPS + double m_fJitterStdDev; // Estimate the Jitter std dev + double m_fJitterMean; + double m_fSyncOffsetStdDev; + double m_fSyncOffsetAvr; + double m_DetectedRefreshRate; + + CCritSec m_refreshRateLock; + double m_DetectedRefreshTime; + double m_DetectedRefreshTimePrim; + double m_DetectedScanlineTime; + double m_DetectedScanlineTimePrim; + double m_DetectedScanlinesPerFrame; + + double GetRefreshRate() const { + if (m_DetectedRefreshRate) { + return m_DetectedRefreshRate; + } + return m_refreshRate; + } + + LONG GetScanLines() const { + if (m_DetectedRefreshRate) { + return (LONG)m_DetectedScanlinesPerFrame; + } + return m_ScreenSize.cy; + } + + double m_ldDetectedRefreshRateList[100]; + double m_ldDetectedScanlineRateList[100]; + int m_DetectedRefreshRatePos; + bool m_bSyncStatsAvailable; + LONGLONG m_pllJitter [NB_JITTER]; // Jitter buffer for stats + LONGLONG m_pllSyncOffset [NB_JITTER]; // Jitter buffer for stats + LONGLONG m_llLastPerf; + LONGLONG m_JitterStdDev; + LONGLONG m_MaxJitter; + LONGLONG m_MinJitter; + LONGLONG m_MaxSyncOffset; + LONGLONG m_MinSyncOffset; + int m_nNextJitter; + int m_nNextSyncOffset; + REFERENCE_TIME m_rtTimePerFrame; + double m_DetectedFrameRate; + double m_DetectedFrameTime; + double m_DetectedFrameTimeStdDev; + bool m_DetectedLock; + LONGLONG m_DetectedFrameTimeHistory[60]; + double m_DetectedFrameTimeHistoryHistory[500]; + int m_DetectedFrameTimePos; + int m_bInterlaced; + + int m_VBlankEndWait; + int m_VBlankStartWait; + LONGLONG m_VBlankWaitTime; + LONGLONG m_VBlankLockTime; + int m_VBlankMin; + int m_VBlankMinCalc; + int m_VBlankMax; + int m_VBlankEndPresent; + LONGLONG m_VBlankStartMeasureTime; + int m_VBlankStartMeasure; + + LONGLONG m_PresentWaitTime; + LONGLONG m_PresentWaitTimeMin; + LONGLONG m_PresentWaitTimeMax; + + LONGLONG m_PaintTime; + LONGLONG m_PaintTimeMin; + LONGLONG m_PaintTimeMax; + + LONGLONG m_WaitForGPUTime; + + LONGLONG m_RasterStatusWaitTime; + LONGLONG m_RasterStatusWaitTimeMin; + LONGLONG m_RasterStatusWaitTimeMax; + LONGLONG m_RasterStatusWaitTimeMaxCalc; + + double m_ClockDiffCalc; + double m_ClockDiffPrim; + double m_ClockDiff; + + double m_TimeChangeHistory[100]; + double m_ClockChangeHistory[100]; + int m_ClockTimeChangeHistoryPos; + double m_ModeratedTimeSpeed; + double m_ModeratedTimeSpeedPrim; + double m_ModeratedTimeSpeedDiff; + + bool m_bCorrectedFrameTime; + int m_FrameTimeCorrection; + LONGLONG m_LastFrameDuration; + LONGLONG m_LastSampleTime; + + CString m_strStatsMsg[10]; + + CString m_D3D9Device; + + CString m_Decoder; + + CFocusThread* m_FocusThread; + HWND m_hFocusWindow; + + public: + CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString& _Error, bool isPreview = false); + ~CDX9AllocatorPresenter(); + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); + STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); + STDMETHODIMP_(bool) ResetDevice(); + STDMETHODIMP_(bool) DisplayChange(); + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() { + return m_bIsRendering; + } + + // ID3DFullscreenControl + STDMETHODIMP SetD3DFullscreen(bool fEnabled); + STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); + }; +} diff --git a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp index 27a1e9cc907..5f4e51c6a48 100644 --- a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp +++ b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp @@ -1,1755 +1,1755 @@ -/* - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#pragma warning(disable: 5033) // warning C5033: 'register' is no longer a supported storage class -#include "lcms2/library/include/lcms2.h" -#include "../../../mpc-hc/resource.h" -#include "Dither.h" -#include "DX9RenderingEngine.h" -#include "../../../mpc-hc/ColorProfileUtil.h" - -// UUID for vorpX hack -static const IID IID_D3D9VorpVideoCaptureTexture = { 0x8a49d79, 0x8646, 0x4867, { 0xb9, 0x34, 0x13, 0x12, 0xe4, 0x4b, 0x23, 0xdb } }; - -#pragma pack(push, 1) -template -struct MYD3DVERTEX { - float x, y, z, rhw; - struct { - float u, v; - } t[texcoords]; -}; - -template<> -struct MYD3DVERTEX<0> { - float x, y, z, rhw; - DWORD Diffuse; -}; -#pragma pack(pop) - -template -static void AdjustQuad(MYD3DVERTEX* v, double dx, double dy) -{ - float offset = 0.5; - - for (int i = 0; i < 4; i++) { - v[i].x -= offset; - v[i].y -= offset; - - for (int j = 0; j < std::max(texcoords - 1, 1); j++) { - v[i].t[j].u -= (float)(offset * dx); - v[i].t[j].v -= (float)(offset * dy); - } - - if constexpr(texcoords > 1) { - v[i].t[texcoords - 1].u -= offset; - v[i].t[texcoords - 1].v -= offset; - } - } -} - -template -static HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter) -{ - CheckPointer(pD3DDev, E_POINTER); - - DWORD FVF = 0; - - switch (texcoords) { - case 1: - FVF = D3DFVF_TEX1; - break; - case 2: - FVF = D3DFVF_TEX2; - break; - case 3: - FVF = D3DFVF_TEX3; - break; - case 4: - FVF = D3DFVF_TEX4; - break; - case 5: - FVF = D3DFVF_TEX5; - break; - case 6: - FVF = D3DFVF_TEX6; - break; - case 7: - FVF = D3DFVF_TEX7; - break; - case 8: - FVF = D3DFVF_TEX8; - break; - default: - return E_FAIL; - } - - pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); - - for (int i = 0; i < texcoords; i++) { - pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); - pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter); - pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - } - - // - - pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF); - //pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0])); - - MYD3DVERTEX tmp = v[2]; - v[2] = v[3]; - v[3] = tmp; - pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); - - // - - for (int i = 0; i < texcoords; i++) { - pD3DDev->SetTexture(i, nullptr); - } - - return S_OK; -} - - -using namespace DSObjects; - -CDX9RenderingEngine::CDX9RenderingEngine(HWND hWnd, HRESULT& hr, CString* _pError) - : CSubPicAllocatorPresenterImpl(hWnd, hr, _pError) - , m_CurrentAdapter(UINT_ERROR) - , m_BackbufferType(D3DFMT_UNKNOWN) - , m_DisplayType(D3DFMT_UNKNOWN) - , m_ScreenSize(0, 0) - , m_nNbDXSurface(1) - , m_nCurSurface(0) - , m_bHighColorResolution(false) - , m_bForceInputHighColorResolution(false) - , m_RenderingPath(RENDERING_PATH_DRAW) - , m_SurfaceType(D3DFMT_UNKNOWN) - , m_bFullFloatingPointProcessing(false) - , m_bHalfFloatingPointProcessing(false) - , m_bColorManagement(false) - , m_InputVideoSystem(VIDEO_SYSTEM_UNKNOWN) - , m_AmbientLight(AMBIENT_LIGHT_BRIGHT) - , m_RenderingIntent(COLOR_RENDERING_INTENT_PERCEPTUAL) - , m_ScreenSpacePassCount(1) - , m_ScreenSpacePassSrc(0) - , m_ScreenSpacePassDest(1) - , m_pRenderTarget(nullptr) - , m_BicubicA(0) - , m_bFinalPass(false) - , m_Lut3DSize(64) - , m_Lut3DEntryCount(64 * 64 * 64) - , m_StretchRectFilter(D3DTEXF_NONE) - , m_pD3DXFloat32To16Array(nullptr) -{ - ZeroMemory(&m_Caps, sizeof(m_Caps)); - HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); - m_bD3DX = hDll != nullptr; - - if (m_bD3DX) { - (FARPROC&)m_pD3DXFloat32To16Array = GetProcAddress(hDll, "D3DXFloat32To16Array"); - } -} - -void CDX9RenderingEngine::InitRenderingEngine() -{ - m_StretchRectFilter = D3DTEXF_LINEAR;// eliminate this chain ASAP - - // Initialize the pixel shader compiler - m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); - - // Initialize settings - m_BicubicA = 0; -} - -void CDX9RenderingEngine::CleanupRenderingEngine() -{ - m_pPSC.Free(); - - for (int i = 0; i < 4; i++) { - m_pResizerPixelShaders[i] = nullptr; - } - - CleanupFinalPass(); - - POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - pos = m_pCustomPixelShaders.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - - for (int i = 0; i < 2; i++) { - m_pTemporaryVideoTextures[i] = nullptr; - m_pTemporaryScreenSpaceTextures[i] = nullptr; - } -} - -HRESULT CDX9RenderingEngine::CreateVideoSurfaces() -{ - HRESULT hr; - const CRenderersSettings& r = GetRenderersSettings(); - - // Free previously allocated video surfaces - FreeVideoSurfaces(); - - // Free previously allocated temporary video textures, because the native video size might have been changed! - for (int i = 0; i < 2; i++) { - m_pTemporaryVideoTextures[i] = nullptr; - } - - CheckPointer(m_pD3DDev, E_POINTER); - - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { - int nTexturesNeeded = r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nNbDXSurface : 1; - - for (int i = 0; i < nTexturesNeeded; i++) { - if (FAILED(hr = m_pD3DDev->CreateTexture( - m_nativeVideoSize.cx, - m_nativeVideoSize.cy, 1, - D3DUSAGE_RENDERTARGET, - m_SurfaceType, - D3DPOOL_DEFAULT, - &m_pVideoTexture[i], - nullptr))) { - return hr; - } - - if (FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i]))) { - return hr; - } - } - - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D) { - m_RenderingPath = RENDERING_PATH_STRETCHRECT; - - for (int i = 0; i < m_nNbDXSurface; i++) { - m_pVideoTexture[i] = nullptr; - } - } else { - m_RenderingPath = RENDERING_PATH_DRAW; - } - } else { - m_RenderingPath = RENDERING_PATH_STRETCHRECT; - - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface( - m_nativeVideoSize.cx, m_nativeVideoSize.cy, - m_SurfaceType, - D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], nullptr))) { - return hr; - } - } - - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1, 0); - - return S_OK; -} - -void CDX9RenderingEngine::FreeVideoSurfaces() -{ - for (int i = 0; i < m_nNbDXSurface; i++) { - m_pVideoTexture[i] = nullptr; - m_pVideoSurface[i] = nullptr; - } -} - -HRESULT CDX9RenderingEngine::RenderVideo(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) -{ - if (destRect.IsRectEmpty()) { - return S_OK; - } - - if (m_RenderingPath == RENDERING_PATH_DRAW) { - return RenderVideoDrawPath(pRenderTarget, srcRect, destRect); - } else { - return RenderVideoStretchRectPath(pRenderTarget, srcRect, destRect); - } -} - -HRESULT CDX9RenderingEngine::RenderVideoDrawPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) -{ - HRESULT hr; - - // Return if the video texture is not initialized - if (m_pVideoTexture[m_nCurSurface] == 0) { - return S_OK; - } - - const CRenderersSettings& r = GetRenderersSettings(); - - // Initialize the processing pipeline - bool bCustomPixelShaders; - bool bResizerShaders; - bool bCustomScreenSpacePixelShaders; - bool bFinalPass; - - int screenSpacePassCount = 0; - DWORD iDX9Resizer = r.iDX9Resizer; - - if (m_bD3DX) { - // Final pass. Must be initialized first! - hr = InitFinalPass(); - if (SUCCEEDED(hr)) { - bFinalPass = m_bFinalPass; - } else { - bFinalPass = false; - } - - if (bFinalPass) { - ++screenSpacePassCount; - } - - // Resizers - float bicubicA = 0; - switch (iDX9Resizer) { - case 3: - bicubicA = -0.60f; - break; - case 4: - bicubicA = -0.751f; - break; // FIXME : 0.75 crash recent D3D, or eat CPU - case 5: - bicubicA = -1.00f; - break; - } - - hr = InitResizers(bicubicA); - bResizerShaders = SUCCEEDED(hr); - screenSpacePassCount += 1; // currently all resizers are 1-pass - - // Custom screen space pixel shaders - bCustomScreenSpacePixelShaders = !m_pCustomScreenSpacePixelShaders.IsEmpty(); - - if (bCustomScreenSpacePixelShaders) { - screenSpacePassCount += (int)m_pCustomScreenSpacePixelShaders.GetCount(); - } - - // Custom pixel shaders - bCustomPixelShaders = !m_pCustomPixelShaders.IsEmpty(); - - hr = InitTemporaryVideoTextures(std::min((int)m_pCustomPixelShaders.GetCount(), 2)); - if (FAILED(hr)) { - bCustomPixelShaders = false; - } - } else { - bCustomPixelShaders = false; - bResizerShaders = false; - bCustomScreenSpacePixelShaders = false; - bFinalPass = false; - } - - hr = InitScreenSpacePipeline(screenSpacePassCount, pRenderTarget); - if (FAILED(hr)) { - bCustomScreenSpacePixelShaders = false; - bFinalPass = false; - } - - // Apply the custom pixel shaders if there are any. Result: pVideoTexture - CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; - - if (bCustomPixelShaders) { - static __int64 counter = 0; - static long start = clock(); - - long stop = clock(); - long diff = stop - start; - - if (diff >= 10 * 60 * CLOCKS_PER_SEC) { - start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) - } - -#if 1 - D3DSURFACE_DESC desc; - m_pVideoTexture[m_nCurSurface]->GetLevelDesc(0, &desc); - - float fConstData[][4] = { - {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, - }; -#else - CSize VideoSize = GetVisibleVideoSize(); - - float fConstData[][4] = { - {(float)VideoSize.cx, (float)VideoSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / VideoSize.cx, 1.0f / VideoSize.cy, 0, 0}, - }; -#endif - - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - int src = 1; - int dest = 0; - bool first = true; - - POSITION pos = m_pCustomPixelShaders.GetHeadPosition(); - while (pos) { - CComPtr pTemporarySurface; - hr = m_pTemporaryVideoTextures[dest]->GetSurfaceLevel(0, &pTemporarySurface); - hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); - - CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); - if (!Shader.m_pPixelShader) { - Shader.Compile(m_pPSC); - } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); - - if (first) { - TextureCopy(m_pVideoTexture[m_nCurSurface]); - first = false; - } else { - TextureCopy(m_pTemporaryVideoTextures[src]); - } - - std::swap(src, dest); - } - - pVideoTexture = m_pTemporaryVideoTextures[src]; - } - - // Hack to send the pre-resize video texture to vorpX. - void* pVorpTex = pVideoTexture; // Prevent the pointer being overwritten. - m_pD3DDev->QueryInterface(IID_D3D9VorpVideoCaptureTexture, (void**)&pVorpTex); - - // Resize the frame - Vector dst[4]; - Transform(destRect, dst); - - hr = BeginScreenSpacePass(); - - if (m_ScreenSpacePassCount > 0) { - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); - } - - if (srcRect.Size() != destRect.Size()) { - if (iDX9Resizer == 0 || iDX9Resizer == 1 || !bResizerShaders) { - D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; - hr = TextureResize(pVideoTexture, dst, Filter, srcRect); - } else if (iDX9Resizer == 2) { - hr = TextureResizeBilinear(pVideoTexture, dst, srcRect); - } else if (iDX9Resizer >= 3) { - hr = TextureResizeBicubic1pass(pVideoTexture, dst, srcRect); - } - } else { - hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, srcRect); - } - - // Apply the custom screen size pixel shaders - if (bCustomScreenSpacePixelShaders) { - static __int64 counter = 555; - static long start = clock() + 333; - - long stop = clock() + 333; - long diff = stop - start; - - if (diff >= 10 * 60 * CLOCKS_PER_SEC) { - start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) - } - - float fConstData[][4] = { - {(float)m_TemporaryScreenSpaceTextureSize.cx, (float)m_TemporaryScreenSpaceTextureSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / m_TemporaryScreenSpaceTextureSize.cx, 1.0f / m_TemporaryScreenSpaceTextureSize.cy, 0, 0}, - }; - - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); - while (pos) { - BeginScreenSpacePass(); - - CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); - if (!Shader.m_pPixelShader) { - Shader.Compile(m_pPSC); - } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); - TextureCopy(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); - } - } - - // Final pass - if (bFinalPass) { - hr = BeginScreenSpacePass(); - hr = FinalPass(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); - } - - hr = m_pD3DDev->SetPixelShader(nullptr); - - return hr; -} - -HRESULT CDX9RenderingEngine::RenderVideoStretchRectPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) -{ - HRESULT hr; - - // Return if the render target or the video surface is not initialized - if (pRenderTarget == 0 || m_pVideoSurface[m_nCurSurface] == 0) { - return S_OK; - } - - CRect rSrcVid(srcRect); - CRect rDstVid(destRect); - - ClipToSurface(pRenderTarget, rSrcVid, rDstVid); // grrr - // IMPORTANT: rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect!!! - rSrcVid.left &= ~1; - rSrcVid.right &= ~1; - rSrcVid.top &= ~1; - rSrcVid.bottom &= ~1; - hr = m_pD3DDev->StretchRect(m_pVideoSurface[m_nCurSurface], rSrcVid, pRenderTarget, rDstVid, m_StretchRectFilter); - - return hr; -} - -HRESULT CDX9RenderingEngine::InitTemporaryVideoTextures(int count) -{ - HRESULT hr = S_OK; - - for (int i = 0; i < count; i++) { - if (m_pTemporaryVideoTextures[i] == nullptr) { - hr = m_pD3DDev->CreateTexture( - m_nativeVideoSize.cx, - m_nativeVideoSize.cy, - 1, - D3DUSAGE_RENDERTARGET, - m_SurfaceType, - D3DPOOL_DEFAULT, - &m_pTemporaryVideoTextures[i], - nullptr); - - if (FAILED(hr)) { - // Free all textures - for (int j = 0; j < 2; j++) { - m_pTemporaryVideoTextures[j] = nullptr; - } - - return hr; - } - } - } - - // Free unnecessary textures - for (int i = count; i < 2; i++) { - m_pTemporaryVideoTextures[i] = nullptr; - } - - return hr; -} - -HRESULT CDX9RenderingEngine::InitScreenSpacePipeline(int passCount, IDirect3DSurface9* pRenderTarget) -{ - m_pRenderTarget = pRenderTarget; - m_ScreenSpacePassCount = passCount; - m_ScreenSpacePassSrc = 0; - m_ScreenSpacePassDest = 1; - - HRESULT hr = InitTemporaryScreenSpaceTextures(std::min(passCount - 1, 2)); - - // If the initialized have failed, disable the pipeline - if (FAILED(hr)) { - m_ScreenSpacePassCount = 1; - } - - return hr; -} - -HRESULT CDX9RenderingEngine::InitTemporaryScreenSpaceTextures(int count) -{ - HRESULT hr = S_OK; - - for (int i = 0; i < count; i++) { - if (m_pTemporaryScreenSpaceTextures[i] == nullptr) { - m_TemporaryScreenSpaceTextureSize = CSize(std::min(std::max(m_BackBufferSize.cx, m_nativeVideoSize.cx), (long)m_Caps.MaxTextureWidth), - std::min(std::max(m_BackBufferSize.cy, m_nativeVideoSize.cy), (long)m_Caps.MaxTextureHeight)); - hr = m_pD3DDev->CreateTexture( - m_TemporaryScreenSpaceTextureSize.cx, - m_TemporaryScreenSpaceTextureSize.cy, - 1, - D3DUSAGE_RENDERTARGET, - m_SurfaceType, - D3DPOOL_DEFAULT, - &m_pTemporaryScreenSpaceTextures[i], - nullptr); - - if (FAILED(hr)) { - // Free all textures - for (int j = 0; j < 2; j++) { - m_pTemporaryScreenSpaceTextures[j] = nullptr; - } - - return hr; - } - } - } - - // Free unnecessary textures - for (int i = count; i < 2; i++) { - m_pTemporaryScreenSpaceTextures[i] = nullptr; - } - - return hr; -} - -HRESULT CDX9RenderingEngine::BeginScreenSpacePass() -{ - HRESULT hr; - - std::swap(m_ScreenSpacePassSrc, m_ScreenSpacePassDest); - --m_ScreenSpacePassCount; - - if (m_ScreenSpacePassCount > 0) { - CComPtr pTemporarySurface; - hr = m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassDest]->GetSurfaceLevel(0, &pTemporarySurface); - - if (SUCCEEDED(hr)) { - hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); - } - } else { - hr = m_pD3DDev->SetRenderTarget(0, m_pRenderTarget); - } - - return hr; -} - -HRESULT CDX9RenderingEngine::InitResizers(float bicubicA) -{ - HRESULT hr; - - // Check whether the resizer pixel shaders must be initialized - bool bInitRequired = false; - - if (bicubicA) { - for (int i = 0; i < 4; i++) { - if (!m_pResizerPixelShaders[i]) { - bInitRequired = true; - } - } - - if (m_BicubicA != bicubicA) { - bInitRequired = true; - } - } else { - if (!m_pResizerPixelShaders[0]) { - bInitRequired = true; - } - } - - if (!bInitRequired) { - return S_OK; - } - - // Initialize the resizer pixel shaders - m_BicubicA = bicubicA; - - for (int i = 0; i < _countof(m_pResizerPixelShaders); i++) { - m_pResizerPixelShaders[i] = nullptr; - } - - if (m_Caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { - return E_FAIL; - } - - LPCSTR pProfile = m_Caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; - - CStringA str; - if (!LoadResource(IDF_SHADER_RESIZER, str, _T("SHADER"))) { - return E_FAIL; - } - - CStringA A; - A.Format("(%f)", bicubicA); - str.Replace("_The_Value_Of_A_Is_Set_Here_", A); - - LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass_pass1", "main_bicubic2pass_pass2"}; - - ASSERT(_countof(pEntries) == _countof(m_pResizerPixelShaders)); - - for (int i = 0; i < _countof(pEntries); i++) { - CString ErrorMessage; - CString DissAssembly; - hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShaders[i], &DissAssembly, &ErrorMessage); - if (FAILED(hr)) { - TRACE(_T("%ws"), ErrorMessage.GetString()); - ASSERT(0); - return hr; - } - /* - if (i == 2 || i == 3) - { - const wchar_t *pStr = DissAssembly.GetString(); - TRACE(_T("DisAsm: %s\n"), pEntries[i]); - const wchar_t *pStrStart = pStr; - while (*pStr) - { - while (*pStr && *pStr != '\n') - ++pStr; - if (*pStr == '\n') - ++pStr; - if (*pStr == '\r') - ++pStr; - CString Test(pStrStart, pStr - pStrStart); - TRACE(_T("%ws"), Test.GetString()); - pStrStart = pStr; - } - } - */ - } - - return S_OK; -} - -HRESULT CDX9RenderingEngine::TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& srcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - float dx2 = 1.0f / w; - float dy2 = 1.0f / h; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, srcRect.left * dx2, srcRect.top * dy2}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, srcRect.right * dx2, srcRect.top * dy2}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, srcRect.left * dx2, srcRect.bottom * dy2}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, srcRect.right * dx2, srcRect.bottom * dy2}, - }; - - AdjustQuad(v, 0, 0); - - hr = m_pD3DDev->SetTexture(0, pTexture); - hr = m_pD3DDev->SetPixelShader(nullptr); - hr = TextureBlt(m_pD3DDev, v, filter); - - return hr; -} - -HRESULT CDX9RenderingEngine::TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway - const float dx = 1.0f / (float)desc.Width; - const float dy = 1.0f / (float)desc.Height; - const float tx0 = (float)srcRect.left; - const float tx1 = (float)srcRect.right; - const float ty0 = (float)srcRect.top; - const float ty1 = (float)srcRect.bottom; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, - }; - - AdjustQuad(v, 1.0, 1.0); - - hr = m_pD3DDev->SetTexture(0, pTexture); - - float fConstData[][4] = {{dx * 0.5f, dy * 0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - hr = m_pD3DDev->SetTexture(0, pTexture); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[0]); - - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - return hr; -} - -HRESULT CDX9RenderingEngine::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway - const float dx = 1.0f / (float)desc.Width; - const float dy = 1.0f / (float)desc.Height; - const float tx0 = (float)srcRect.left; - const float tx1 = (float)srcRect.right; - const float ty0 = (float)srcRect.top; - const float ty1 = (float)srcRect.bottom; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, - }; - - AdjustQuad(v, 1.0, 1.0); - - hr = m_pD3DDev->SetTexture(0, pTexture); - - float fConstData[][4] = {{dx * 0.5f, dy * 0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[1]); - - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - return hr; -} - -/* -// The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction. -HRESULT CDX9RenderingEngine::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect &srcRect) -{ - HRESULT hr; - - // rotated? - if (dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z - || dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x) - return TextureResizeBicubic1pass(pTexture, dst, srcRect); - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) - return E_FAIL; - - float Tex0_Width = desc.Width; - float Tex0_Height = desc.Height; - - double dx0 = 1.0/desc.Width; - UNREFERENCED_PARAMETER(dx0); - double dy0 = 1.0/desc.Height; - UNREFERENCED_PARAMETER(dy0); - - CSize SrcTextSize = CSize(desc.Width, desc.Height); - double w = (double)srcRect.Width(); - double h = (double)srcRect.Height(); - UNREFERENCED_PARAMETER(w); - - CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h); - - if (!m_pTemporaryScreenSpaceTextures[0] || FAILED(m_pTemporaryScreenSpaceTextures[0]->GetLevelDesc(0, &desc))) - return TextureResizeBicubic1pass(pTexture, dst, srcRect); - - float Tex1_Width = desc.Width; - float Tex1_Height = desc.Height; - - double dx1 = 1.0/desc.Width; - UNREFERENCED_PARAMETER(dx1); - double dy1 = 1.0/desc.Height; - UNREFERENCED_PARAMETER(dy1); - - double dw = (double)dst1.Width() / desc.Width; - UNREFERENCED_PARAMETER(dw); - double dh = (double)dst1.Height() / desc.Height; - UNREFERENCED_PARAMETER(dh); - - float dx2 = 1.0f/SrcTextSize.cx; - UNREFERENCED_PARAMETER(dx2); - float dy2 = 1.0f/SrcTextSize.cy; - UNREFERENCED_PARAMETER(dy2); - - float tx0 = srcRect.left; - float tx1 = srcRect.right; - float ty0 = srcRect.top; - float ty1 = srcRect.bottom; - - float tx0_2 = 0; - float tx1_2 = dst1.Width(); - float ty0_2 = 0; - float ty1_2 = h; - - // ASSERT(dst1.Height() == desc.Height); - - if (dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height) - // if (dst1.Width() != desc.Width || dst1.Height() != desc.Height) - return TextureResizeBicubic1pass(pTexture, dst, srcRect); - - MYD3DVERTEX<1> vx[] = - { - {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0}, - {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0}, - {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1}, - {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1}, - }; - - AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug here, create vertical lines ! TODO : why ?????? - - MYD3DVERTEX<1> vy[] = - { - {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2}, - {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2}, - {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2}, - {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2}, - }; - - - AdjustQuad(vy, 0.0, 1.0); // Casimir666 : bug here, create horizontal lines ! TODO : why ?????? - - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[2]); - { - float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - } - - hr = m_pD3DDev->SetTexture(0, pTexture); - - CComPtr pRTOld; - hr = m_pD3DDev->GetRenderTarget(0, &pRTOld); - - CComPtr pRT; - hr = m_pTemporaryScreenSpaceTextures[0]->GetSurfaceLevel(0, &pRT); - hr = m_pD3DDev->SetRenderTarget(0, pRT); - - hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT); - - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[3]); - { - float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - } - - hr = m_pD3DDev->SetTexture(0, m_pTemporaryScreenSpaceTextures[0]); - - hr = m_pD3DDev->SetRenderTarget(0, pRTOld); - - hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT); - return hr; -} -*/ - -HRESULT CDX9RenderingEngine::Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect) -{ - HRESULT hr = E_FAIL; - - const CRenderersSettings& r = GetRenderersSettings(); - - DWORD iDX9Resizer = r.iDX9Resizer; - Vector dst[4]; - Transform(destRect, dst); - - if (iDX9Resizer == 0 || iDX9Resizer == 1) { - D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; - hr = TextureResize(pTexture, dst, Filter, srcRect); - } else if (iDX9Resizer == 2) { - hr = TextureResizeBilinear(pTexture, dst, srcRect); - } else if (iDX9Resizer >= 3) { - hr = TextureResizeBicubic1pass(pTexture, dst, srcRect); - } - - return hr; -} - -HRESULT CDX9RenderingEngine::InitFinalPass() -{ - HRESULT hr; - - const CRenderersSettings& r = GetRenderersSettings(); - const CRenderersData* rd = GetRenderersData(); - - // Check whether the final pass must be initialized - bool bColorManagement = r.m_AdvRendSets.bVMR9ColorManagementEnable; - VideoSystem inputVideoSystem = static_cast(r.m_AdvRendSets.iVMR9ColorManagementInput); - AmbientLight ambientLight = static_cast(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight); - ColorRenderingIntent renderingIntent = static_cast(r.m_AdvRendSets.iVMR9ColorManagementIntent); - - bool bInitRequired = false; - - if (m_bColorManagement != bColorManagement) { - bInitRequired = true; - } - - if (m_bColorManagement && bColorManagement) { - if ((m_InputVideoSystem != inputVideoSystem) || - (m_RenderingIntent != renderingIntent) || - (m_AmbientLight != ambientLight)) { - bInitRequired = true; - } - } - - if (!m_bFinalPass) { - bInitRequired = true; - } - - if (!bInitRequired) { - return S_OK; - } - - // Check whether the final pass is supported by the hardware - m_bFinalPass = rd->m_bFP16Support; - if (!m_bFinalPass) { - return S_OK; - } - - // Update the settings - m_bColorManagement = bColorManagement; - m_InputVideoSystem = inputVideoSystem; - m_AmbientLight = ambientLight; - m_RenderingIntent = renderingIntent; - - // Check whether the final pass is required - m_bFinalPass = bColorManagement || m_bFullFloatingPointProcessing || m_bHalfFloatingPointProcessing || ((m_bForceInputHighColorResolution || m_bHighColorResolution) && (m_DisplayType != D3DFMT_A2R10G10B10)); - - if (!m_bFinalPass) { - return S_OK; - } - - // Initial cleanup - m_pLut3DTexture = nullptr; - m_pFinalPixelShader = nullptr; - - if (!m_pDitherTexture) { - // Create the dither texture - hr = m_pD3DDev->CreateTexture(DITHER_MATRIX_SIZE, DITHER_MATRIX_SIZE, - 1, - D3DUSAGE_DYNAMIC, - D3DFMT_A16B16G16R16F, - D3DPOOL_DEFAULT, - &m_pDitherTexture, - nullptr); - - if (FAILED(hr)) { - CleanupFinalPass(); - return hr; - } - - D3DLOCKED_RECT lockedRect; - hr = m_pDitherTexture->LockRect(0, &lockedRect, nullptr, D3DLOCK_DISCARD); - if (FAILED(hr)) { - CleanupFinalPass(); - return hr; - } - - char* outputRowIterator = static_cast(lockedRect.pBits); - for (int y = 0; y < DITHER_MATRIX_SIZE; y++) { - unsigned short* outputIterator = reinterpret_cast(outputRowIterator); - for (int x = 0; x < DITHER_MATRIX_SIZE; x++) { - for (int i = 0; i < 4; i++) { - *outputIterator++ = DITHER_MATRIX[y][x]; - } - } - - outputRowIterator += lockedRect.Pitch; - } - - hr = m_pDitherTexture->UnlockRect(0); - if (FAILED(hr)) { - CleanupFinalPass(); - return hr; - } - } - - // Initialize the color management if necessary - if (bColorManagement) { - // Get the ICC profile path - TCHAR* iccProfilePath = ColorProfileUtil::getIccProfilePath(m_hWnd); - - // Create the 3D LUT texture - m_Lut3DSize = 64; // 64x64x64 LUT is enough for high-quality color management - m_Lut3DEntryCount = m_Lut3DSize * m_Lut3DSize * m_Lut3DSize; - - hr = m_pD3DDev->CreateVolumeTexture(m_Lut3DSize, m_Lut3DSize, m_Lut3DSize, - 1, - D3DUSAGE_DYNAMIC, - D3DFMT_A16B16G16R16F, - D3DPOOL_DEFAULT, - &m_pLut3DTexture, - nullptr); - - if (FAILED(hr)) { - delete [] iccProfilePath; - CleanupFinalPass(); - return hr; - } - - float* lut3DFloat32 = DEBUG_NEW float[m_Lut3DEntryCount * 3]; - hr = CreateIccProfileLut(iccProfilePath, lut3DFloat32); - delete [] iccProfilePath; - if (FAILED(hr)) { - delete [] lut3DFloat32; - CleanupFinalPass(); - return hr; - } - - D3DXFLOAT16* lut3DFloat16 = DEBUG_NEW D3DXFLOAT16[m_Lut3DEntryCount * 3]; - m_pD3DXFloat32To16Array(lut3DFloat16, lut3DFloat32, m_Lut3DEntryCount * 3); - delete [] lut3DFloat32; - - const float oneFloat32 = 1.0f; - D3DXFLOAT16 oneFloat16; - m_pD3DXFloat32To16Array(&oneFloat16, &oneFloat32, 1); - - D3DLOCKED_BOX lockedBox; - hr = m_pLut3DTexture->LockBox(0, &lockedBox, nullptr, D3DLOCK_DISCARD); - if (FAILED(hr)) { - delete [] lut3DFloat16; - CleanupFinalPass(); - return hr; - } - - D3DXFLOAT16* lut3DFloat16Iterator = lut3DFloat16; - char* outputSliceIterator = static_cast(lockedBox.pBits); - for (int b = 0; b < m_Lut3DSize; b++) { - char* outputRowIterator = outputSliceIterator; - - for (int g = 0; g < m_Lut3DSize; g++) { - D3DXFLOAT16* outputIterator = reinterpret_cast(outputRowIterator); - - for (int i = 0; i < m_Lut3DSize; i++) { - // R, G, B - for (int j = 0; j < 3; j++) { - *outputIterator++ = *lut3DFloat16Iterator++; - } - - // A - *outputIterator++ = oneFloat16; - } - - outputRowIterator += lockedBox.RowPitch; - } - - outputSliceIterator += lockedBox.SlicePitch; - } - - hr = m_pLut3DTexture->UnlockBox(0); - delete [] lut3DFloat16; - if (FAILED(hr)) { - CleanupFinalPass(); - return hr; - } - } - - // Compile the final pixel shader - LPCSTR pProfile = m_Caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; - - CStringA shaderSourceCode; - if (!LoadResource(IDF_SHADER_FINAL, shaderSourceCode, _T("SHADER"))) { - CleanupFinalPass(); - return E_FAIL; - } - - int quantization; - if (m_DisplayType == D3DFMT_A2R10G10B10) { - quantization = 1023; // 10-bit - } else { - quantization = 255; // 8-bit - } - - CStringA quantizationString; - quantizationString.Format("%d.", quantization); - shaderSourceCode.Replace("_QUANTIZATION_VALUE_", quantizationString); - - CStringA lut3DEnabledString; - lut3DEnabledString.Format("%d", static_cast(bColorManagement)); - shaderSourceCode.Replace("_LUT3D_ENABLED_VALUE_", lut3DEnabledString); - - if (bColorManagement) { - CStringA lut3DSizeString; - lut3DSizeString.Format("%d.", m_Lut3DSize); - shaderSourceCode.Replace("_LUT3D_SIZE_VALUE_", lut3DSizeString); - } - - CString ErrorMessage; - CString DissAssembly; - hr = m_pPSC->CompileShader(shaderSourceCode, "main", pProfile, 0, &m_pFinalPixelShader, &DissAssembly, &ErrorMessage); - if (FAILED(hr)) { - TRACE(_T("%ws"), ErrorMessage.GetString()); - ASSERT(0); - CleanupFinalPass(); - return hr; - } - - return S_OK; -} - -void CDX9RenderingEngine::CleanupFinalPass() -{ - m_bFinalPass = false; - m_pDitherTexture = nullptr; - m_pLut3DTexture = nullptr; - m_pFinalPixelShader = nullptr; -} - -HRESULT CDX9RenderingEngine::CreateIccProfileLut(TCHAR* profilePath, float* lut3D) -{ - // Get the input video system - VideoSystem videoSystem; - - if (m_InputVideoSystem == VIDEO_SYSTEM_UNKNOWN) { - static const int ntscSizes[][2] = {{720, 480}, {720, 486}, {704, 480}}; - static const int palSizes[][2] = {{720, 576}, {704, 576}}; - - videoSystem = VIDEO_SYSTEM_HDTV; // default - - for (int i = 0; i < _countof(ntscSizes); i++) { - if (m_nativeVideoSize.cx == ntscSizes[i][0] && m_nativeVideoSize.cy == ntscSizes[i][1]) { - videoSystem = VIDEO_SYSTEM_SDTV_NTSC; - } - } - - for (int i = 0; i < _countof(palSizes); i++) { - if (m_nativeVideoSize.cx == palSizes[i][0] && m_nativeVideoSize.cy == palSizes[i][1]) { - videoSystem = VIDEO_SYSTEM_SDTV_PAL; - } - } - } else { - videoSystem = m_InputVideoSystem; - } - - // Get the gamma - double gamma; - - switch (m_AmbientLight) { - case AMBIENT_LIGHT_BRIGHT: - gamma = 2.2; - break; - - case AMBIENT_LIGHT_DIM: - gamma = 2.35; - break; - - case AMBIENT_LIGHT_DARK: - gamma = 2.4; - break; - - default: - return E_FAIL; - } - - // Get the rendering intent - cmsUInt32Number intent; - - switch (m_RenderingIntent) { - case COLOR_RENDERING_INTENT_PERCEPTUAL: - intent = INTENT_PERCEPTUAL; - break; - - case COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC: - intent = INTENT_RELATIVE_COLORIMETRIC; - break; - - case COLOR_RENDERING_INTENT_SATURATION: - intent = INTENT_SATURATION; - break; - - case COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC: - intent = INTENT_ABSOLUTE_COLORIMETRIC; - break; - - default: - return E_FAIL; - } - - // Set the input white point. It's D65 in all cases. - cmsCIExyY whitePoint; - - whitePoint.x = 0.312713; - whitePoint.y = 0.329016; - whitePoint.Y = 1.0; - - // Set the input primaries - cmsCIExyYTRIPLE primaries; - - switch (videoSystem) { - case VIDEO_SYSTEM_HDTV: - // Rec. 709 - primaries.Red.x = 0.64; - primaries.Red.y = 0.33; - primaries.Green.x = 0.30; - primaries.Green.y = 0.60; - primaries.Blue.x = 0.15; - primaries.Blue.y = 0.06; - break; - - case VIDEO_SYSTEM_SDTV_NTSC: - // SMPTE-C - primaries.Red.x = 0.630; - primaries.Red.y = 0.340; - primaries.Green.x = 0.310; - primaries.Green.y = 0.595; - primaries.Blue.x = 0.155; - primaries.Blue.y = 0.070; - break; - - case VIDEO_SYSTEM_SDTV_PAL: - // PAL/SECAM - primaries.Red.x = 0.64; - primaries.Red.y = 0.33; - primaries.Green.x = 0.29; - primaries.Green.y = 0.60; - primaries.Blue.x = 0.15; - primaries.Blue.y = 0.06; - break; - - default: - return E_FAIL; - } - - primaries.Red.Y = 1.0; - primaries.Green.Y = 1.0; - primaries.Blue.Y = 1.0; - - // Set the input gamma, which is the gamma of a reference studio display we want to simulate - // For more information, see the paper at http://www.poynton.com/notes/PU-PR-IS/Poynton-PU-PR-IS.pdf - cmsToneCurve* transferFunction = cmsBuildGamma(0, gamma); - - cmsToneCurve* transferFunctionRGB[3]; - for (int i = 0; i < 3; i++) { - transferFunctionRGB[i] = transferFunction; - } - - // Create the input profile - cmsHPROFILE hInputProfile = cmsCreateRGBProfile(&whitePoint, &primaries, transferFunctionRGB); - cmsFreeToneCurve(transferFunction); - - if (hInputProfile == nullptr) { - return E_FAIL; - } - - // Open the output profile - cmsHPROFILE hOutputProfile; - FILE* outputProfileStream = nullptr; - - if (profilePath != 0) { - if (_wfopen_s(&outputProfileStream, T2W(profilePath), L"rb") != 0) { - cmsCloseProfile(hInputProfile); - return E_FAIL; - } - - hOutputProfile = cmsOpenProfileFromStream(outputProfileStream, "r"); - } else { - hOutputProfile = cmsCreate_sRGBProfile(); - } - - if (hOutputProfile == nullptr) { - if (profilePath != 0) { - fclose(outputProfileStream); - } - - cmsCloseProfile(hInputProfile); - return E_FAIL; - } - - // Create the transform - cmsHTRANSFORM hTransform = cmsCreateTransform(hInputProfile, TYPE_RGB_16, hOutputProfile, TYPE_RGB_16, intent, cmsFLAGS_HIGHRESPRECALC); - - cmsCloseProfile(hOutputProfile); - - if (profilePath != 0) { - fclose(outputProfileStream); - } - - cmsCloseProfile(hInputProfile); - - if (hTransform == nullptr) { - return E_FAIL; - } - - uint16_t* lut3DOutput = nullptr; - uint16_t* lut3DInput = nullptr; - - try { - // Create the 3D LUT input - lut3DOutput = DEBUG_NEW uint16_t[m_Lut3DEntryCount * 3]; - lut3DInput = DEBUG_NEW uint16_t[m_Lut3DEntryCount * 3]; - - uint16_t* lut3DInputIterator = lut3DInput; - - for (int b = 0; b < m_Lut3DSize; b++) { - for (int g = 0; g < m_Lut3DSize; g++) { - for (int r = 0; r < m_Lut3DSize; r++) { - *lut3DInputIterator++ = uint16_t(r * 65535 / (m_Lut3DSize - 1)); - *lut3DInputIterator++ = uint16_t(g * 65535 / (m_Lut3DSize - 1)); - *lut3DInputIterator++ = uint16_t(b * 65535 / (m_Lut3DSize - 1)); - } - } - } - - // Do the transform - cmsDoTransform(hTransform, lut3DInput, lut3DOutput, m_Lut3DEntryCount); - - // Convert the output to floating point - for (int i = 0; i < m_Lut3DEntryCount * 3; i++) { - lut3D[i] = static_cast(lut3DOutput[i]) * (1.0f / 65535.0f); - } - - // Cleanup - delete [] lut3DOutput; - delete [] lut3DInput; - cmsDeleteTransform(hTransform); - } catch (...) { - // Cleanup - delete [] lut3DOutput; - delete [] lut3DInput; - cmsDeleteTransform(hTransform); - - return E_FAIL; - } - - return S_OK; -} - -HRESULT CDX9RenderingEngine::FinalPass(IDirect3DTexture9* pTexture) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - MYD3DVERTEX<1> v[] = { - {0, 0, 0.5f, 2.0f, 0, 0}, - {w, 0, 0.5f, 2.0f, 1, 0}, - {0, h, 0.5f, 2.0f, 0, 1}, - {w, h, 0.5f, 2.0f, 1, 1}, - }; - - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - - hr = m_pD3DDev->SetPixelShader(m_pFinalPixelShader); - - // Set sampler: image - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - - hr = m_pD3DDev->SetTexture(0, pTexture); - - // Set sampler: ditherMap - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - - hr = m_pD3DDev->SetTexture(1, m_pDitherTexture); - - if (m_bColorManagement) { - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); - - hr = m_pD3DDev->SetTexture(2, m_pLut3DTexture); - } - - // Set constants - float fConstData[][4] = {{(float)w / DITHER_MATRIX_SIZE, (float)h / DITHER_MATRIX_SIZE, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - - hr = m_pD3DDev->SetTexture(1, nullptr); - - if (m_bColorManagement) { - hr = m_pD3DDev->SetTexture(2, nullptr); - } - - return hr; -} - -HRESULT CDX9RenderingEngine::TextureCopy(IDirect3DTexture9* pTexture) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - MYD3DVERTEX<1> v[] = { - {0, 0, 0.5f, 2.0f, 0, 0}, - {w, 0, 0.5f, 2.0f, 1, 0}, - {0, h, 0.5f, 2.0f, 0, 1}, - {w, h, 0.5f, 2.0f, 1, 1}, - }; - - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - - hr = m_pD3DDev->SetTexture(0, pTexture); - - // use D3DTEXF_LINEAR here if wanting to support hw linear sampling in pixel shaders - return TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); -} - -bool CDX9RenderingEngine::ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pSurface->GetDesc(&desc))) { - return false; - } - - int w = desc.Width, h = desc.Height; - int sw = s.Width(), sh = s.Height(); - int dw = d.Width(), dh = d.Height(); - - if (d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0 - || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) { - s.SetRectEmpty(); - d.SetRectEmpty(); - return true; - } - - if (d.right > w) { - s.right -= (d.right - w) * sw / dw; - d.right = w; - } - if (d.bottom > h) { - s.bottom -= (d.bottom - h) * sh / dh; - d.bottom = h; - } - if (d.left < 0) { - s.left += (0 - d.left) * sw / dw; - d.left = 0; - } - if (d.top < 0) { - s.top += (0 - d.top) * sh / dh; - d.top = 0; - } - - return true; -} - -HRESULT CDX9RenderingEngine::DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect) -{ - CheckPointer(m_pD3DDev, E_POINTER); - - DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color)); - MYD3DVERTEX<0> v[] = { - {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color}, - {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color}, - {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color}, - {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color}, - }; - - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - - HRESULT hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - //D3DRS_COLORVERTEX - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - - - hr = m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); - - hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE); - // hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0])); - - MYD3DVERTEX<0> tmp = v[2]; - v[2] = v[3]; - v[3] = tmp; - hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); - - return S_OK; -} - -HRESULT CDX9RenderingEngine::AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture) -{ - if (!pSrc || !pDst) { - return E_POINTER; - } - - CRect src(*pSrc), dst(*pDst); - - HRESULT hr; - - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile - // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly - // initialized and thus the subtitles weren't shown. - struct { - float x, y, z, rhw; - float tu, tv; - } pVertices[] = { - {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, - {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, - {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, - {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, - }; - - for (size_t i = 0; i < _countof(pVertices); i++) { - pVertices[i].x -= 0.5f; - pVertices[i].y -= 0.5f; - } - - hr = m_pD3DDev->SetTexture(0, pTexture); - - // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE - // so we need to provide default values in case GetRenderState fails - DWORD abe, sb, db; - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { - abe = FALSE; - } - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { - sb = D3DBLEND_ONE; - } - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { - db = D3DBLEND_ZERO; - } - - hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... - hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst - - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - - /*// - - D3DCAPS9 d3dcaps9; - hr = m_pD3DDev->GetDeviceCaps(&d3dcaps9); - if (d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS) - { - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS); - } - - */// - - hr = m_pD3DDev->SetPixelShader(nullptr); - - hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); - hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); - - // - - m_pD3DDev->SetTexture(0, nullptr); - - m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); - m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); - m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); - - return S_OK; -} - -HRESULT CDX9RenderingEngine::SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) -{ - CAtlList* pPixelShaders; - if (bScreenSpace) { - pPixelShaders = &m_pCustomScreenSpacePixelShaders; - } else { - pPixelShaders = &m_pCustomPixelShaders; - } - - if (!pSrcData && !pTarget) { - pPixelShaders->RemoveAll(); - if (m_pD3DDev) { - m_pD3DDev->SetPixelShader(nullptr); - } - return S_OK; - } - - if (!pSrcData) { - return E_INVALIDARG; - } - - CExternalPixelShader Shader; - Shader.m_SourceData = pSrcData; - Shader.m_SourceTarget = pTarget; - - if (Shader.m_SourceData.Find("$MinimumShaderProfile: ps_4_0") > 0 || Shader.m_SourceData.Find("$MinimumShaderProfile: ps_5_0") > 0) { - // incompatible shader - return E_INVALIDARG; - } - - CComPtr pPixelShader; - - HRESULT hr = Shader.Compile(m_pPSC); - if (FAILED(hr)) { - return hr; - } - - pPixelShaders->AddTail(Shader); - - Paint(false); - - return S_OK; -} +/* + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#pragma warning(disable: 5033) // warning C5033: 'register' is no longer a supported storage class +#include "lcms2/library/include/lcms2.h" +#include "../../../mpc-hc/resource.h" +#include "Dither.h" +#include "DX9RenderingEngine.h" +#include "../../../mpc-hc/ColorProfileUtil.h" + +// UUID for vorpX hack +static const IID IID_D3D9VorpVideoCaptureTexture = { 0x8a49d79, 0x8646, 0x4867, { 0xb9, 0x34, 0x13, 0x12, 0xe4, 0x4b, 0x23, 0xdb } }; + +#pragma pack(push, 1) +template +struct MYD3DVERTEX { + float x, y, z, rhw; + struct { + float u, v; + } t[texcoords]; +}; + +template<> +struct MYD3DVERTEX<0> { + float x, y, z, rhw; + DWORD Diffuse; +}; +#pragma pack(pop) + +template +static void AdjustQuad(MYD3DVERTEX* v, double dx, double dy) +{ + float offset = 0.5; + + for (int i = 0; i < 4; i++) { + v[i].x -= offset; + v[i].y -= offset; + + for (int j = 0; j < std::max(texcoords - 1, 1); j++) { + v[i].t[j].u -= (float)(offset * dx); + v[i].t[j].v -= (float)(offset * dy); + } + + if constexpr(texcoords > 1) { + v[i].t[texcoords - 1].u -= offset; + v[i].t[texcoords - 1].v -= offset; + } + } +} + +template +static HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter) +{ + CheckPointer(pD3DDev, E_POINTER); + + DWORD FVF = 0; + + switch (texcoords) { + case 1: + FVF = D3DFVF_TEX1; + break; + case 2: + FVF = D3DFVF_TEX2; + break; + case 3: + FVF = D3DFVF_TEX3; + break; + case 4: + FVF = D3DFVF_TEX4; + break; + case 5: + FVF = D3DFVF_TEX5; + break; + case 6: + FVF = D3DFVF_TEX6; + break; + case 7: + FVF = D3DFVF_TEX7; + break; + case 8: + FVF = D3DFVF_TEX8; + break; + default: + return E_FAIL; + } + + pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + + for (int i = 0; i < texcoords; i++) { + pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); + pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter); + pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + // + + pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF); + //pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0])); + + MYD3DVERTEX tmp = v[2]; + v[2] = v[3]; + v[3] = tmp; + pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); + + // + + for (int i = 0; i < texcoords; i++) { + pD3DDev->SetTexture(i, nullptr); + } + + return S_OK; +} + + +using namespace DSObjects; + +CDX9RenderingEngine::CDX9RenderingEngine(HWND hWnd, HRESULT& hr, CString* _pError) + : CSubPicAllocatorPresenterImpl(hWnd, hr, _pError) + , m_CurrentAdapter(UINT_ERROR) + , m_BackbufferType(D3DFMT_UNKNOWN) + , m_DisplayType(D3DFMT_UNKNOWN) + , m_ScreenSize(0, 0) + , m_nNbDXSurface(1) + , m_nCurSurface(0) + , m_bHighColorResolution(false) + , m_bForceInputHighColorResolution(false) + , m_RenderingPath(RENDERING_PATH_DRAW) + , m_SurfaceType(D3DFMT_UNKNOWN) + , m_bFullFloatingPointProcessing(false) + , m_bHalfFloatingPointProcessing(false) + , m_bColorManagement(false) + , m_InputVideoSystem(VIDEO_SYSTEM_UNKNOWN) + , m_AmbientLight(AMBIENT_LIGHT_BRIGHT) + , m_RenderingIntent(COLOR_RENDERING_INTENT_PERCEPTUAL) + , m_ScreenSpacePassCount(1) + , m_ScreenSpacePassSrc(0) + , m_ScreenSpacePassDest(1) + , m_pRenderTarget(nullptr) + , m_BicubicA(0) + , m_bFinalPass(false) + , m_Lut3DSize(64) + , m_Lut3DEntryCount(64 * 64 * 64) + , m_StretchRectFilter(D3DTEXF_NONE) + , m_pD3DXFloat32To16Array(nullptr) +{ + ZeroMemory(&m_Caps, sizeof(m_Caps)); + HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); + m_bD3DX = hDll != nullptr; + + if (m_bD3DX) { + (FARPROC&)m_pD3DXFloat32To16Array = GetProcAddress(hDll, "D3DXFloat32To16Array"); + } +} + +void CDX9RenderingEngine::InitRenderingEngine() +{ + m_StretchRectFilter = D3DTEXF_LINEAR;// eliminate this chain ASAP + + // Initialize the pixel shader compiler + m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); + + // Initialize settings + m_BicubicA = 0; +} + +void CDX9RenderingEngine::CleanupRenderingEngine() +{ + m_pPSC.Free(); + + for (int i = 0; i < 4; i++) { + m_pResizerPixelShaders[i] = nullptr; + } + + CleanupFinalPass(); + + POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + pos = m_pCustomPixelShaders.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + + for (int i = 0; i < 2; i++) { + m_pTemporaryVideoTextures[i] = nullptr; + m_pTemporaryScreenSpaceTextures[i] = nullptr; + } +} + +HRESULT CDX9RenderingEngine::CreateVideoSurfaces() +{ + HRESULT hr; + const CRenderersSettings& r = GetRenderersSettings(); + + // Free previously allocated video surfaces + FreeVideoSurfaces(); + + // Free previously allocated temporary video textures, because the native video size might have been changed! + for (int i = 0; i < 2; i++) { + m_pTemporaryVideoTextures[i] = nullptr; + } + + CheckPointer(m_pD3DDev, E_POINTER); + + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { + int nTexturesNeeded = r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nNbDXSurface : 1; + + for (int i = 0; i < nTexturesNeeded; i++) { + if (FAILED(hr = m_pD3DDev->CreateTexture( + m_nativeVideoSize.cx, + m_nativeVideoSize.cy, 1, + D3DUSAGE_RENDERTARGET, + m_SurfaceType, + D3DPOOL_DEFAULT, + &m_pVideoTexture[i], + nullptr))) { + return hr; + } + + if (FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i]))) { + return hr; + } + } + + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D) { + m_RenderingPath = RENDERING_PATH_STRETCHRECT; + + for (int i = 0; i < m_nNbDXSurface; i++) { + m_pVideoTexture[i] = nullptr; + } + } else { + m_RenderingPath = RENDERING_PATH_DRAW; + } + } else { + m_RenderingPath = RENDERING_PATH_STRETCHRECT; + + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface( + m_nativeVideoSize.cx, m_nativeVideoSize.cy, + m_SurfaceType, + D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], nullptr))) { + return hr; + } + } + + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1, 0); + + return S_OK; +} + +void CDX9RenderingEngine::FreeVideoSurfaces() +{ + for (int i = 0; i < m_nNbDXSurface; i++) { + m_pVideoTexture[i] = nullptr; + m_pVideoSurface[i] = nullptr; + } +} + +HRESULT CDX9RenderingEngine::RenderVideo(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) +{ + if (destRect.IsRectEmpty()) { + return S_OK; + } + + if (m_RenderingPath == RENDERING_PATH_DRAW) { + return RenderVideoDrawPath(pRenderTarget, srcRect, destRect); + } else { + return RenderVideoStretchRectPath(pRenderTarget, srcRect, destRect); + } +} + +HRESULT CDX9RenderingEngine::RenderVideoDrawPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) +{ + HRESULT hr; + + // Return if the video texture is not initialized + if (m_pVideoTexture[m_nCurSurface] == 0) { + return S_OK; + } + + const CRenderersSettings& r = GetRenderersSettings(); + + // Initialize the processing pipeline + bool bCustomPixelShaders; + bool bResizerShaders; + bool bCustomScreenSpacePixelShaders; + bool bFinalPass; + + int screenSpacePassCount = 0; + DWORD iDX9Resizer = r.iDX9Resizer; + + if (m_bD3DX) { + // Final pass. Must be initialized first! + hr = InitFinalPass(); + if (SUCCEEDED(hr)) { + bFinalPass = m_bFinalPass; + } else { + bFinalPass = false; + } + + if (bFinalPass) { + ++screenSpacePassCount; + } + + // Resizers + float bicubicA = 0; + switch (iDX9Resizer) { + case 3: + bicubicA = -0.60f; + break; + case 4: + bicubicA = -0.751f; + break; // FIXME : 0.75 crash recent D3D, or eat CPU + case 5: + bicubicA = -1.00f; + break; + } + + hr = InitResizers(bicubicA); + bResizerShaders = SUCCEEDED(hr); + screenSpacePassCount += 1; // currently all resizers are 1-pass + + // Custom screen space pixel shaders + bCustomScreenSpacePixelShaders = !m_pCustomScreenSpacePixelShaders.IsEmpty(); + + if (bCustomScreenSpacePixelShaders) { + screenSpacePassCount += (int)m_pCustomScreenSpacePixelShaders.GetCount(); + } + + // Custom pixel shaders + bCustomPixelShaders = !m_pCustomPixelShaders.IsEmpty(); + + hr = InitTemporaryVideoTextures(std::min((int)m_pCustomPixelShaders.GetCount(), 2)); + if (FAILED(hr)) { + bCustomPixelShaders = false; + } + } else { + bCustomPixelShaders = false; + bResizerShaders = false; + bCustomScreenSpacePixelShaders = false; + bFinalPass = false; + } + + hr = InitScreenSpacePipeline(screenSpacePassCount, pRenderTarget); + if (FAILED(hr)) { + bCustomScreenSpacePixelShaders = false; + bFinalPass = false; + } + + // Apply the custom pixel shaders if there are any. Result: pVideoTexture + CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; + + if (bCustomPixelShaders) { + static __int64 counter = 0; + static long start = clock(); + + long stop = clock(); + long diff = stop - start; + + if (diff >= 10 * 60 * CLOCKS_PER_SEC) { + start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) + } + +#if 1 + D3DSURFACE_DESC desc; + m_pVideoTexture[m_nCurSurface]->GetLevelDesc(0, &desc); + + float fConstData[][4] = { + {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, + }; +#else + CSize VideoSize = GetVisibleVideoSize(); + + float fConstData[][4] = { + {(float)VideoSize.cx, (float)VideoSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / VideoSize.cx, 1.0f / VideoSize.cy, 0, 0}, + }; +#endif + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + int src = 1; + int dest = 0; + bool first = true; + + POSITION pos = m_pCustomPixelShaders.GetHeadPosition(); + while (pos) { + CComPtr pTemporarySurface; + hr = m_pTemporaryVideoTextures[dest]->GetSurfaceLevel(0, &pTemporarySurface); + hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); + + CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); + if (!Shader.m_pPixelShader) { + Shader.Compile(m_pPSC); + } + hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + + if (first) { + TextureCopy(m_pVideoTexture[m_nCurSurface]); + first = false; + } else { + TextureCopy(m_pTemporaryVideoTextures[src]); + } + + std::swap(src, dest); + } + + pVideoTexture = m_pTemporaryVideoTextures[src]; + } + + // Hack to send the pre-resize video texture to vorpX. + void* pVorpTex = pVideoTexture; // Prevent the pointer being overwritten. + m_pD3DDev->QueryInterface(IID_D3D9VorpVideoCaptureTexture, (void**)&pVorpTex); + + // Resize the frame + Vector dst[4]; + Transform(destRect, dst); + + hr = BeginScreenSpacePass(); + + if (m_ScreenSpacePassCount > 0) { + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); + } + + if (srcRect.Size() != destRect.Size()) { + if (iDX9Resizer == 0 || iDX9Resizer == 1 || !bResizerShaders) { + D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; + hr = TextureResize(pVideoTexture, dst, Filter, srcRect); + } else if (iDX9Resizer == 2) { + hr = TextureResizeBilinear(pVideoTexture, dst, srcRect); + } else if (iDX9Resizer >= 3) { + hr = TextureResizeBicubic1pass(pVideoTexture, dst, srcRect); + } + } else { + hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, srcRect); + } + + // Apply the custom screen size pixel shaders + if (bCustomScreenSpacePixelShaders) { + static __int64 counter = 555; + static long start = clock() + 333; + + long stop = clock() + 333; + long diff = stop - start; + + if (diff >= 10 * 60 * CLOCKS_PER_SEC) { + start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) + } + + float fConstData[][4] = { + {(float)m_TemporaryScreenSpaceTextureSize.cx, (float)m_TemporaryScreenSpaceTextureSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / m_TemporaryScreenSpaceTextureSize.cx, 1.0f / m_TemporaryScreenSpaceTextureSize.cy, 0, 0}, + }; + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); + while (pos) { + BeginScreenSpacePass(); + + CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); + if (!Shader.m_pPixelShader) { + Shader.Compile(m_pPSC); + } + hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + TextureCopy(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); + } + } + + // Final pass + if (bFinalPass) { + hr = BeginScreenSpacePass(); + hr = FinalPass(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); + } + + hr = m_pD3DDev->SetPixelShader(nullptr); + + return hr; +} + +HRESULT CDX9RenderingEngine::RenderVideoStretchRectPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) +{ + HRESULT hr; + + // Return if the render target or the video surface is not initialized + if (pRenderTarget == 0 || m_pVideoSurface[m_nCurSurface] == 0) { + return S_OK; + } + + CRect rSrcVid(srcRect); + CRect rDstVid(destRect); + + ClipToSurface(pRenderTarget, rSrcVid, rDstVid); // grrr + // IMPORTANT: rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect!!! + rSrcVid.left &= ~1; + rSrcVid.right &= ~1; + rSrcVid.top &= ~1; + rSrcVid.bottom &= ~1; + hr = m_pD3DDev->StretchRect(m_pVideoSurface[m_nCurSurface], rSrcVid, pRenderTarget, rDstVid, m_StretchRectFilter); + + return hr; +} + +HRESULT CDX9RenderingEngine::InitTemporaryVideoTextures(int count) +{ + HRESULT hr = S_OK; + + for (int i = 0; i < count; i++) { + if (m_pTemporaryVideoTextures[i] == nullptr) { + hr = m_pD3DDev->CreateTexture( + m_nativeVideoSize.cx, + m_nativeVideoSize.cy, + 1, + D3DUSAGE_RENDERTARGET, + m_SurfaceType, + D3DPOOL_DEFAULT, + &m_pTemporaryVideoTextures[i], + nullptr); + + if (FAILED(hr)) { + // Free all textures + for (int j = 0; j < 2; j++) { + m_pTemporaryVideoTextures[j] = nullptr; + } + + return hr; + } + } + } + + // Free unnecessary textures + for (int i = count; i < 2; i++) { + m_pTemporaryVideoTextures[i] = nullptr; + } + + return hr; +} + +HRESULT CDX9RenderingEngine::InitScreenSpacePipeline(int passCount, IDirect3DSurface9* pRenderTarget) +{ + m_pRenderTarget = pRenderTarget; + m_ScreenSpacePassCount = passCount; + m_ScreenSpacePassSrc = 0; + m_ScreenSpacePassDest = 1; + + HRESULT hr = InitTemporaryScreenSpaceTextures(std::min(passCount - 1, 2)); + + // If the initialized have failed, disable the pipeline + if (FAILED(hr)) { + m_ScreenSpacePassCount = 1; + } + + return hr; +} + +HRESULT CDX9RenderingEngine::InitTemporaryScreenSpaceTextures(int count) +{ + HRESULT hr = S_OK; + + for (int i = 0; i < count; i++) { + if (m_pTemporaryScreenSpaceTextures[i] == nullptr) { + m_TemporaryScreenSpaceTextureSize = CSize(std::min(std::max(m_BackBufferSize.cx, m_nativeVideoSize.cx), (long)m_Caps.MaxTextureWidth), + std::min(std::max(m_BackBufferSize.cy, m_nativeVideoSize.cy), (long)m_Caps.MaxTextureHeight)); + hr = m_pD3DDev->CreateTexture( + m_TemporaryScreenSpaceTextureSize.cx, + m_TemporaryScreenSpaceTextureSize.cy, + 1, + D3DUSAGE_RENDERTARGET, + m_SurfaceType, + D3DPOOL_DEFAULT, + &m_pTemporaryScreenSpaceTextures[i], + nullptr); + + if (FAILED(hr)) { + // Free all textures + for (int j = 0; j < 2; j++) { + m_pTemporaryScreenSpaceTextures[j] = nullptr; + } + + return hr; + } + } + } + + // Free unnecessary textures + for (int i = count; i < 2; i++) { + m_pTemporaryScreenSpaceTextures[i] = nullptr; + } + + return hr; +} + +HRESULT CDX9RenderingEngine::BeginScreenSpacePass() +{ + HRESULT hr; + + std::swap(m_ScreenSpacePassSrc, m_ScreenSpacePassDest); + --m_ScreenSpacePassCount; + + if (m_ScreenSpacePassCount > 0) { + CComPtr pTemporarySurface; + hr = m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassDest]->GetSurfaceLevel(0, &pTemporarySurface); + + if (SUCCEEDED(hr)) { + hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); + } + } else { + hr = m_pD3DDev->SetRenderTarget(0, m_pRenderTarget); + } + + return hr; +} + +HRESULT CDX9RenderingEngine::InitResizers(float bicubicA) +{ + HRESULT hr; + + // Check whether the resizer pixel shaders must be initialized + bool bInitRequired = false; + + if (bicubicA) { + for (int i = 0; i < 4; i++) { + if (!m_pResizerPixelShaders[i]) { + bInitRequired = true; + } + } + + if (m_BicubicA != bicubicA) { + bInitRequired = true; + } + } else { + if (!m_pResizerPixelShaders[0]) { + bInitRequired = true; + } + } + + if (!bInitRequired) { + return S_OK; + } + + // Initialize the resizer pixel shaders + m_BicubicA = bicubicA; + + for (int i = 0; i < _countof(m_pResizerPixelShaders); i++) { + m_pResizerPixelShaders[i] = nullptr; + } + + if (m_Caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { + return E_FAIL; + } + + LPCSTR pProfile = m_Caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; + + CStringA str; + if (!LoadResource(IDF_SHADER_RESIZER, str, _T("SHADER"))) { + return E_FAIL; + } + + CStringA A; + A.Format("(%f)", bicubicA); + str.Replace("_The_Value_Of_A_Is_Set_Here_", A); + + LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass_pass1", "main_bicubic2pass_pass2"}; + + ASSERT(_countof(pEntries) == _countof(m_pResizerPixelShaders)); + + for (int i = 0; i < _countof(pEntries); i++) { + CString ErrorMessage; + CString DissAssembly; + hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShaders[i], &DissAssembly, &ErrorMessage); + if (FAILED(hr)) { + TRACE(_T("%ws"), ErrorMessage.GetString()); + ASSERT(0); + return hr; + } + /* + if (i == 2 || i == 3) + { + const wchar_t *pStr = DissAssembly.GetString(); + TRACE(_T("DisAsm: %s\n"), pEntries[i]); + const wchar_t *pStrStart = pStr; + while (*pStr) + { + while (*pStr && *pStr != '\n') + ++pStr; + if (*pStr == '\n') + ++pStr; + if (*pStr == '\r') + ++pStr; + CString Test(pStrStart, pStr - pStrStart); + TRACE(_T("%ws"), Test.GetString()); + pStrStart = pStr; + } + } + */ + } + + return S_OK; +} + +HRESULT CDX9RenderingEngine::TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& srcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + float dx2 = 1.0f / w; + float dy2 = 1.0f / h; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, srcRect.left * dx2, srcRect.top * dy2}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, srcRect.right * dx2, srcRect.top * dy2}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, srcRect.left * dx2, srcRect.bottom * dy2}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, srcRect.right * dx2, srcRect.bottom * dy2}, + }; + + AdjustQuad(v, 0, 0); + + hr = m_pD3DDev->SetTexture(0, pTexture); + hr = m_pD3DDev->SetPixelShader(nullptr); + hr = TextureBlt(m_pD3DDev, v, filter); + + return hr; +} + +HRESULT CDX9RenderingEngine::TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway + const float dx = 1.0f / (float)desc.Width; + const float dy = 1.0f / (float)desc.Height; + const float tx0 = (float)srcRect.left; + const float tx1 = (float)srcRect.right; + const float ty0 = (float)srcRect.top; + const float ty1 = (float)srcRect.bottom; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, + }; + + AdjustQuad(v, 1.0, 1.0); + + hr = m_pD3DDev->SetTexture(0, pTexture); + + float fConstData[][4] = {{dx * 0.5f, dy * 0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + hr = m_pD3DDev->SetTexture(0, pTexture); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[0]); + + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + return hr; +} + +HRESULT CDX9RenderingEngine::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway + const float dx = 1.0f / (float)desc.Width; + const float dy = 1.0f / (float)desc.Height; + const float tx0 = (float)srcRect.left; + const float tx1 = (float)srcRect.right; + const float ty0 = (float)srcRect.top; + const float ty1 = (float)srcRect.bottom; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, + }; + + AdjustQuad(v, 1.0, 1.0); + + hr = m_pD3DDev->SetTexture(0, pTexture); + + float fConstData[][4] = {{dx * 0.5f, dy * 0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[1]); + + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + return hr; +} + +/* +// The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction. +HRESULT CDX9RenderingEngine::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect &srcRect) +{ + HRESULT hr; + + // rotated? + if (dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z + || dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x) + return TextureResizeBicubic1pass(pTexture, dst, srcRect); + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) + return E_FAIL; + + float Tex0_Width = desc.Width; + float Tex0_Height = desc.Height; + + double dx0 = 1.0/desc.Width; + UNREFERENCED_PARAMETER(dx0); + double dy0 = 1.0/desc.Height; + UNREFERENCED_PARAMETER(dy0); + + CSize SrcTextSize = CSize(desc.Width, desc.Height); + double w = (double)srcRect.Width(); + double h = (double)srcRect.Height(); + UNREFERENCED_PARAMETER(w); + + CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h); + + if (!m_pTemporaryScreenSpaceTextures[0] || FAILED(m_pTemporaryScreenSpaceTextures[0]->GetLevelDesc(0, &desc))) + return TextureResizeBicubic1pass(pTexture, dst, srcRect); + + float Tex1_Width = desc.Width; + float Tex1_Height = desc.Height; + + double dx1 = 1.0/desc.Width; + UNREFERENCED_PARAMETER(dx1); + double dy1 = 1.0/desc.Height; + UNREFERENCED_PARAMETER(dy1); + + double dw = (double)dst1.Width() / desc.Width; + UNREFERENCED_PARAMETER(dw); + double dh = (double)dst1.Height() / desc.Height; + UNREFERENCED_PARAMETER(dh); + + float dx2 = 1.0f/SrcTextSize.cx; + UNREFERENCED_PARAMETER(dx2); + float dy2 = 1.0f/SrcTextSize.cy; + UNREFERENCED_PARAMETER(dy2); + + float tx0 = srcRect.left; + float tx1 = srcRect.right; + float ty0 = srcRect.top; + float ty1 = srcRect.bottom; + + float tx0_2 = 0; + float tx1_2 = dst1.Width(); + float ty0_2 = 0; + float ty1_2 = h; + + // ASSERT(dst1.Height() == desc.Height); + + if (dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height) + // if (dst1.Width() != desc.Width || dst1.Height() != desc.Height) + return TextureResizeBicubic1pass(pTexture, dst, srcRect); + + MYD3DVERTEX<1> vx[] = + { + {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0}, + {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0}, + {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1}, + {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1}, + }; + + AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug here, create vertical lines ! TODO : why ?????? + + MYD3DVERTEX<1> vy[] = + { + {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2}, + {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2}, + {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2}, + {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2}, + }; + + + AdjustQuad(vy, 0.0, 1.0); // Casimir666 : bug here, create horizontal lines ! TODO : why ?????? + + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[2]); + { + float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + } + + hr = m_pD3DDev->SetTexture(0, pTexture); + + CComPtr pRTOld; + hr = m_pD3DDev->GetRenderTarget(0, &pRTOld); + + CComPtr pRT; + hr = m_pTemporaryScreenSpaceTextures[0]->GetSurfaceLevel(0, &pRT); + hr = m_pD3DDev->SetRenderTarget(0, pRT); + + hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT); + + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[3]); + { + float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + } + + hr = m_pD3DDev->SetTexture(0, m_pTemporaryScreenSpaceTextures[0]); + + hr = m_pD3DDev->SetRenderTarget(0, pRTOld); + + hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT); + return hr; +} +*/ + +HRESULT CDX9RenderingEngine::Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect) +{ + HRESULT hr = E_FAIL; + + const CRenderersSettings& r = GetRenderersSettings(); + + DWORD iDX9Resizer = r.iDX9Resizer; + Vector dst[4]; + Transform(destRect, dst); + + if (iDX9Resizer == 0 || iDX9Resizer == 1) { + D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; + hr = TextureResize(pTexture, dst, Filter, srcRect); + } else if (iDX9Resizer == 2) { + hr = TextureResizeBilinear(pTexture, dst, srcRect); + } else if (iDX9Resizer >= 3) { + hr = TextureResizeBicubic1pass(pTexture, dst, srcRect); + } + + return hr; +} + +HRESULT CDX9RenderingEngine::InitFinalPass() +{ + HRESULT hr; + + const CRenderersSettings& r = GetRenderersSettings(); + const CRenderersData* rd = GetRenderersData(); + + // Check whether the final pass must be initialized + bool bColorManagement = r.m_AdvRendSets.bVMR9ColorManagementEnable; + VideoSystem inputVideoSystem = static_cast(r.m_AdvRendSets.iVMR9ColorManagementInput); + AmbientLight ambientLight = static_cast(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight); + ColorRenderingIntent renderingIntent = static_cast(r.m_AdvRendSets.iVMR9ColorManagementIntent); + + bool bInitRequired = false; + + if (m_bColorManagement != bColorManagement) { + bInitRequired = true; + } + + if (m_bColorManagement && bColorManagement) { + if ((m_InputVideoSystem != inputVideoSystem) || + (m_RenderingIntent != renderingIntent) || + (m_AmbientLight != ambientLight)) { + bInitRequired = true; + } + } + + if (!m_bFinalPass) { + bInitRequired = true; + } + + if (!bInitRequired) { + return S_OK; + } + + // Check whether the final pass is supported by the hardware + m_bFinalPass = rd->m_bFP16Support; + if (!m_bFinalPass) { + return S_OK; + } + + // Update the settings + m_bColorManagement = bColorManagement; + m_InputVideoSystem = inputVideoSystem; + m_AmbientLight = ambientLight; + m_RenderingIntent = renderingIntent; + + // Check whether the final pass is required + m_bFinalPass = bColorManagement || m_bFullFloatingPointProcessing || m_bHalfFloatingPointProcessing || ((m_bForceInputHighColorResolution || m_bHighColorResolution) && (m_DisplayType != D3DFMT_A2R10G10B10)); + + if (!m_bFinalPass) { + return S_OK; + } + + // Initial cleanup + m_pLut3DTexture = nullptr; + m_pFinalPixelShader = nullptr; + + if (!m_pDitherTexture) { + // Create the dither texture + hr = m_pD3DDev->CreateTexture(DITHER_MATRIX_SIZE, DITHER_MATRIX_SIZE, + 1, + D3DUSAGE_DYNAMIC, + D3DFMT_A16B16G16R16F, + D3DPOOL_DEFAULT, + &m_pDitherTexture, + nullptr); + + if (FAILED(hr)) { + CleanupFinalPass(); + return hr; + } + + D3DLOCKED_RECT lockedRect; + hr = m_pDitherTexture->LockRect(0, &lockedRect, nullptr, D3DLOCK_DISCARD); + if (FAILED(hr)) { + CleanupFinalPass(); + return hr; + } + + char* outputRowIterator = static_cast(lockedRect.pBits); + for (int y = 0; y < DITHER_MATRIX_SIZE; y++) { + unsigned short* outputIterator = reinterpret_cast(outputRowIterator); + for (int x = 0; x < DITHER_MATRIX_SIZE; x++) { + for (int i = 0; i < 4; i++) { + *outputIterator++ = DITHER_MATRIX[y][x]; + } + } + + outputRowIterator += lockedRect.Pitch; + } + + hr = m_pDitherTexture->UnlockRect(0); + if (FAILED(hr)) { + CleanupFinalPass(); + return hr; + } + } + + // Initialize the color management if necessary + if (bColorManagement) { + // Get the ICC profile path + TCHAR* iccProfilePath = ColorProfileUtil::getIccProfilePath(m_hWnd); + + // Create the 3D LUT texture + m_Lut3DSize = 64; // 64x64x64 LUT is enough for high-quality color management + m_Lut3DEntryCount = m_Lut3DSize * m_Lut3DSize * m_Lut3DSize; + + hr = m_pD3DDev->CreateVolumeTexture(m_Lut3DSize, m_Lut3DSize, m_Lut3DSize, + 1, + D3DUSAGE_DYNAMIC, + D3DFMT_A16B16G16R16F, + D3DPOOL_DEFAULT, + &m_pLut3DTexture, + nullptr); + + if (FAILED(hr)) { + delete [] iccProfilePath; + CleanupFinalPass(); + return hr; + } + + float* lut3DFloat32 = DEBUG_NEW float[m_Lut3DEntryCount * 3]; + hr = CreateIccProfileLut(iccProfilePath, lut3DFloat32); + delete [] iccProfilePath; + if (FAILED(hr)) { + delete [] lut3DFloat32; + CleanupFinalPass(); + return hr; + } + + D3DXFLOAT16* lut3DFloat16 = DEBUG_NEW D3DXFLOAT16[m_Lut3DEntryCount * 3]; + m_pD3DXFloat32To16Array(lut3DFloat16, lut3DFloat32, m_Lut3DEntryCount * 3); + delete [] lut3DFloat32; + + const float oneFloat32 = 1.0f; + D3DXFLOAT16 oneFloat16; + m_pD3DXFloat32To16Array(&oneFloat16, &oneFloat32, 1); + + D3DLOCKED_BOX lockedBox; + hr = m_pLut3DTexture->LockBox(0, &lockedBox, nullptr, D3DLOCK_DISCARD); + if (FAILED(hr)) { + delete [] lut3DFloat16; + CleanupFinalPass(); + return hr; + } + + D3DXFLOAT16* lut3DFloat16Iterator = lut3DFloat16; + char* outputSliceIterator = static_cast(lockedBox.pBits); + for (int b = 0; b < m_Lut3DSize; b++) { + char* outputRowIterator = outputSliceIterator; + + for (int g = 0; g < m_Lut3DSize; g++) { + D3DXFLOAT16* outputIterator = reinterpret_cast(outputRowIterator); + + for (int i = 0; i < m_Lut3DSize; i++) { + // R, G, B + for (int j = 0; j < 3; j++) { + *outputIterator++ = *lut3DFloat16Iterator++; + } + + // A + *outputIterator++ = oneFloat16; + } + + outputRowIterator += lockedBox.RowPitch; + } + + outputSliceIterator += lockedBox.SlicePitch; + } + + hr = m_pLut3DTexture->UnlockBox(0); + delete [] lut3DFloat16; + if (FAILED(hr)) { + CleanupFinalPass(); + return hr; + } + } + + // Compile the final pixel shader + LPCSTR pProfile = m_Caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; + + CStringA shaderSourceCode; + if (!LoadResource(IDF_SHADER_FINAL, shaderSourceCode, _T("SHADER"))) { + CleanupFinalPass(); + return E_FAIL; + } + + int quantization; + if (m_DisplayType == D3DFMT_A2R10G10B10) { + quantization = 1023; // 10-bit + } else { + quantization = 255; // 8-bit + } + + CStringA quantizationString; + quantizationString.Format("%d.", quantization); + shaderSourceCode.Replace("_QUANTIZATION_VALUE_", quantizationString); + + CStringA lut3DEnabledString; + lut3DEnabledString.Format("%d", static_cast(bColorManagement)); + shaderSourceCode.Replace("_LUT3D_ENABLED_VALUE_", lut3DEnabledString); + + if (bColorManagement) { + CStringA lut3DSizeString; + lut3DSizeString.Format("%d.", m_Lut3DSize); + shaderSourceCode.Replace("_LUT3D_SIZE_VALUE_", lut3DSizeString); + } + + CString ErrorMessage; + CString DissAssembly; + hr = m_pPSC->CompileShader(shaderSourceCode, "main", pProfile, 0, &m_pFinalPixelShader, &DissAssembly, &ErrorMessage); + if (FAILED(hr)) { + TRACE(_T("%ws"), ErrorMessage.GetString()); + ASSERT(0); + CleanupFinalPass(); + return hr; + } + + return S_OK; +} + +void CDX9RenderingEngine::CleanupFinalPass() +{ + m_bFinalPass = false; + m_pDitherTexture = nullptr; + m_pLut3DTexture = nullptr; + m_pFinalPixelShader = nullptr; +} + +HRESULT CDX9RenderingEngine::CreateIccProfileLut(TCHAR* profilePath, float* lut3D) +{ + // Get the input video system + VideoSystem videoSystem; + + if (m_InputVideoSystem == VIDEO_SYSTEM_UNKNOWN) { + static const int ntscSizes[][2] = {{720, 480}, {720, 486}, {704, 480}}; + static const int palSizes[][2] = {{720, 576}, {704, 576}}; + + videoSystem = VIDEO_SYSTEM_HDTV; // default + + for (int i = 0; i < _countof(ntscSizes); i++) { + if (m_nativeVideoSize.cx == ntscSizes[i][0] && m_nativeVideoSize.cy == ntscSizes[i][1]) { + videoSystem = VIDEO_SYSTEM_SDTV_NTSC; + } + } + + for (int i = 0; i < _countof(palSizes); i++) { + if (m_nativeVideoSize.cx == palSizes[i][0] && m_nativeVideoSize.cy == palSizes[i][1]) { + videoSystem = VIDEO_SYSTEM_SDTV_PAL; + } + } + } else { + videoSystem = m_InputVideoSystem; + } + + // Get the gamma + double gamma; + + switch (m_AmbientLight) { + case AMBIENT_LIGHT_BRIGHT: + gamma = 2.2; + break; + + case AMBIENT_LIGHT_DIM: + gamma = 2.35; + break; + + case AMBIENT_LIGHT_DARK: + gamma = 2.4; + break; + + default: + return E_FAIL; + } + + // Get the rendering intent + cmsUInt32Number intent; + + switch (m_RenderingIntent) { + case COLOR_RENDERING_INTENT_PERCEPTUAL: + intent = INTENT_PERCEPTUAL; + break; + + case COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC: + intent = INTENT_RELATIVE_COLORIMETRIC; + break; + + case COLOR_RENDERING_INTENT_SATURATION: + intent = INTENT_SATURATION; + break; + + case COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC: + intent = INTENT_ABSOLUTE_COLORIMETRIC; + break; + + default: + return E_FAIL; + } + + // Set the input white point. It's D65 in all cases. + cmsCIExyY whitePoint; + + whitePoint.x = 0.312713; + whitePoint.y = 0.329016; + whitePoint.Y = 1.0; + + // Set the input primaries + cmsCIExyYTRIPLE primaries; + + switch (videoSystem) { + case VIDEO_SYSTEM_HDTV: + // Rec. 709 + primaries.Red.x = 0.64; + primaries.Red.y = 0.33; + primaries.Green.x = 0.30; + primaries.Green.y = 0.60; + primaries.Blue.x = 0.15; + primaries.Blue.y = 0.06; + break; + + case VIDEO_SYSTEM_SDTV_NTSC: + // SMPTE-C + primaries.Red.x = 0.630; + primaries.Red.y = 0.340; + primaries.Green.x = 0.310; + primaries.Green.y = 0.595; + primaries.Blue.x = 0.155; + primaries.Blue.y = 0.070; + break; + + case VIDEO_SYSTEM_SDTV_PAL: + // PAL/SECAM + primaries.Red.x = 0.64; + primaries.Red.y = 0.33; + primaries.Green.x = 0.29; + primaries.Green.y = 0.60; + primaries.Blue.x = 0.15; + primaries.Blue.y = 0.06; + break; + + default: + return E_FAIL; + } + + primaries.Red.Y = 1.0; + primaries.Green.Y = 1.0; + primaries.Blue.Y = 1.0; + + // Set the input gamma, which is the gamma of a reference studio display we want to simulate + // For more information, see the paper at http://www.poynton.com/notes/PU-PR-IS/Poynton-PU-PR-IS.pdf + cmsToneCurve* transferFunction = cmsBuildGamma(0, gamma); + + cmsToneCurve* transferFunctionRGB[3]; + for (int i = 0; i < 3; i++) { + transferFunctionRGB[i] = transferFunction; + } + + // Create the input profile + cmsHPROFILE hInputProfile = cmsCreateRGBProfile(&whitePoint, &primaries, transferFunctionRGB); + cmsFreeToneCurve(transferFunction); + + if (hInputProfile == nullptr) { + return E_FAIL; + } + + // Open the output profile + cmsHPROFILE hOutputProfile; + FILE* outputProfileStream = nullptr; + + if (profilePath != 0) { + if (_wfopen_s(&outputProfileStream, T2W(profilePath), L"rb") != 0) { + cmsCloseProfile(hInputProfile); + return E_FAIL; + } + + hOutputProfile = cmsOpenProfileFromStream(outputProfileStream, "r"); + } else { + hOutputProfile = cmsCreate_sRGBProfile(); + } + + if (hOutputProfile == nullptr) { + if (profilePath != 0) { + fclose(outputProfileStream); + } + + cmsCloseProfile(hInputProfile); + return E_FAIL; + } + + // Create the transform + cmsHTRANSFORM hTransform = cmsCreateTransform(hInputProfile, TYPE_RGB_16, hOutputProfile, TYPE_RGB_16, intent, cmsFLAGS_HIGHRESPRECALC); + + cmsCloseProfile(hOutputProfile); + + if (profilePath != 0) { + fclose(outputProfileStream); + } + + cmsCloseProfile(hInputProfile); + + if (hTransform == nullptr) { + return E_FAIL; + } + + uint16_t* lut3DOutput = nullptr; + uint16_t* lut3DInput = nullptr; + + try { + // Create the 3D LUT input + lut3DOutput = DEBUG_NEW uint16_t[m_Lut3DEntryCount * 3]; + lut3DInput = DEBUG_NEW uint16_t[m_Lut3DEntryCount * 3]; + + uint16_t* lut3DInputIterator = lut3DInput; + + for (int b = 0; b < m_Lut3DSize; b++) { + for (int g = 0; g < m_Lut3DSize; g++) { + for (int r = 0; r < m_Lut3DSize; r++) { + *lut3DInputIterator++ = uint16_t(r * 65535 / (m_Lut3DSize - 1)); + *lut3DInputIterator++ = uint16_t(g * 65535 / (m_Lut3DSize - 1)); + *lut3DInputIterator++ = uint16_t(b * 65535 / (m_Lut3DSize - 1)); + } + } + } + + // Do the transform + cmsDoTransform(hTransform, lut3DInput, lut3DOutput, m_Lut3DEntryCount); + + // Convert the output to floating point + for (int i = 0; i < m_Lut3DEntryCount * 3; i++) { + lut3D[i] = static_cast(lut3DOutput[i]) * (1.0f / 65535.0f); + } + + // Cleanup + delete [] lut3DOutput; + delete [] lut3DInput; + cmsDeleteTransform(hTransform); + } catch (...) { + // Cleanup + delete [] lut3DOutput; + delete [] lut3DInput; + cmsDeleteTransform(hTransform); + + return E_FAIL; + } + + return S_OK; +} + +HRESULT CDX9RenderingEngine::FinalPass(IDirect3DTexture9* pTexture) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + MYD3DVERTEX<1> v[] = { + {0, 0, 0.5f, 2.0f, 0, 0}, + {w, 0, 0.5f, 2.0f, 1, 0}, + {0, h, 0.5f, 2.0f, 0, 1}, + {w, h, 0.5f, 2.0f, 1, 1}, + }; + + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + + hr = m_pD3DDev->SetPixelShader(m_pFinalPixelShader); + + // Set sampler: image + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + hr = m_pD3DDev->SetTexture(0, pTexture); + + // Set sampler: ditherMap + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + + hr = m_pD3DDev->SetTexture(1, m_pDitherTexture); + + if (m_bColorManagement) { + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); + + hr = m_pD3DDev->SetTexture(2, m_pLut3DTexture); + } + + // Set constants + float fConstData[][4] = {{(float)w / DITHER_MATRIX_SIZE, (float)h / DITHER_MATRIX_SIZE, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + + hr = m_pD3DDev->SetTexture(1, nullptr); + + if (m_bColorManagement) { + hr = m_pD3DDev->SetTexture(2, nullptr); + } + + return hr; +} + +HRESULT CDX9RenderingEngine::TextureCopy(IDirect3DTexture9* pTexture) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + MYD3DVERTEX<1> v[] = { + {0, 0, 0.5f, 2.0f, 0, 0}, + {w, 0, 0.5f, 2.0f, 1, 0}, + {0, h, 0.5f, 2.0f, 0, 1}, + {w, h, 0.5f, 2.0f, 1, 1}, + }; + + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + + hr = m_pD3DDev->SetTexture(0, pTexture); + + // use D3DTEXF_LINEAR here if wanting to support hw linear sampling in pixel shaders + return TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); +} + +bool CDX9RenderingEngine::ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pSurface->GetDesc(&desc))) { + return false; + } + + int w = desc.Width, h = desc.Height; + int sw = s.Width(), sh = s.Height(); + int dw = d.Width(), dh = d.Height(); + + if (d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0 + || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) { + s.SetRectEmpty(); + d.SetRectEmpty(); + return true; + } + + if (d.right > w) { + s.right -= (d.right - w) * sw / dw; + d.right = w; + } + if (d.bottom > h) { + s.bottom -= (d.bottom - h) * sh / dh; + d.bottom = h; + } + if (d.left < 0) { + s.left += (0 - d.left) * sw / dw; + d.left = 0; + } + if (d.top < 0) { + s.top += (0 - d.top) * sh / dh; + d.top = 0; + } + + return true; +} + +HRESULT CDX9RenderingEngine::DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect) +{ + CheckPointer(m_pD3DDev, E_POINTER); + + DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color)); + MYD3DVERTEX<0> v[] = { + {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color}, + {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color}, + {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color}, + {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color}, + }; + + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + + HRESULT hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + //D3DRS_COLORVERTEX + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + + hr = m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE); + // hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0])); + + MYD3DVERTEX<0> tmp = v[2]; + v[2] = v[3]; + v[3] = tmp; + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); + + return S_OK; +} + +HRESULT CDX9RenderingEngine::AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture) +{ + if (!pSrc || !pDst) { + return E_POINTER; + } + + CRect src(*pSrc), dst(*pDst); + + HRESULT hr; + + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile + // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly + // initialized and thus the subtitles weren't shown. + struct { + float x, y, z, rhw; + float tu, tv; + } pVertices[] = { + {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, + {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, + {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, + {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, + }; + + for (size_t i = 0; i < _countof(pVertices); i++) { + pVertices[i].x -= 0.5f; + pVertices[i].y -= 0.5f; + } + + hr = m_pD3DDev->SetTexture(0, pTexture); + + // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE + // so we need to provide default values in case GetRenderState fails + DWORD abe, sb, db; + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { + abe = FALSE; + } + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { + sb = D3DBLEND_ONE; + } + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { + db = D3DBLEND_ZERO; + } + + hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst + + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + /*// + + D3DCAPS9 d3dcaps9; + hr = m_pD3DDev->GetDeviceCaps(&d3dcaps9); + if (d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS) + { + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS); + } + + */// + + hr = m_pD3DDev->SetPixelShader(nullptr); + + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + + // + + m_pD3DDev->SetTexture(0, nullptr); + + m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); + m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); + m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); + + return S_OK; +} + +HRESULT CDX9RenderingEngine::SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) +{ + CAtlList* pPixelShaders; + if (bScreenSpace) { + pPixelShaders = &m_pCustomScreenSpacePixelShaders; + } else { + pPixelShaders = &m_pCustomPixelShaders; + } + + if (!pSrcData && !pTarget) { + pPixelShaders->RemoveAll(); + if (m_pD3DDev) { + m_pD3DDev->SetPixelShader(nullptr); + } + return S_OK; + } + + if (!pSrcData) { + return E_INVALIDARG; + } + + CExternalPixelShader Shader; + Shader.m_SourceData = pSrcData; + Shader.m_SourceTarget = pTarget; + + if (Shader.m_SourceData.Find("$MinimumShaderProfile: ps_4_0") > 0 || Shader.m_SourceData.Find("$MinimumShaderProfile: ps_5_0") > 0) { + // incompatible shader + return E_INVALIDARG; + } + + CComPtr pPixelShader; + + HRESULT hr = Shader.Compile(m_pPSC); + if (FAILED(hr)) { + return hr; + } + + pPixelShaders->AddTail(Shader); + + Paint(false); + + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h index df4790451e7..9f210947d1f 100644 --- a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h +++ b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h @@ -1,185 +1,185 @@ -/* - * (C) 2006-2013, 2016-2017 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 . - * - */ - -#pragma once - -#include "AllocatorCommon.h" -#include "RenderersSettings.h" -#include -#include "d3dx9/d3dx9.h" -#include "../SubPic/SubPicAllocatorPresenterImpl.h" - - -namespace DSObjects -{ - - class CDX9RenderingEngine - : public CSubPicAllocatorPresenterImpl - { - protected: - enum RenderingPath { - RENDERING_PATH_STRETCHRECT, - RENDERING_PATH_DRAW - }; - - static const int MAX_VIDEO_SURFACES = 60; - - // Variables initialized/managed by the allocator-presenter! - CComPtr m_pD3D; - CComPtr m_pD3DEx; - CComPtr m_pD3DDev; - CComPtr m_pD3DDevEx; - UINT m_CurrentAdapter; - D3DCAPS9 m_Caps; - D3DFORMAT m_BackbufferType; - D3DFORMAT m_DisplayType; - CSize m_ScreenSize; - CSize m_BackBufferSize; - int m_nNbDXSurface; // Total number of DX Surfaces - int m_nCurSurface; // Surface currently displayed - - bool m_bHighColorResolution; - bool m_bForceInputHighColorResolution; - - // Variables initialized/managed by this class but can be accessed by the allocator-presenter - bool m_bD3DX; - RenderingPath m_RenderingPath; - D3DFORMAT m_SurfaceType; - CComPtr m_pVideoTexture[MAX_VIDEO_SURFACES]; - CComPtr m_pVideoSurface[MAX_VIDEO_SURFACES]; - - bool m_bFullFloatingPointProcessing; - bool m_bHalfFloatingPointProcessing; - bool m_bColorManagement; - - CDX9RenderingEngine(HWND hWnd, HRESULT& hr, CString* _pError); - virtual ~CDX9RenderingEngine() = default; - - void InitRenderingEngine(); - void CleanupRenderingEngine(); - - HRESULT CreateVideoSurfaces(); - void FreeVideoSurfaces(); - - HRESULT RenderVideo(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); - - HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect); - HRESULT AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); - - HRESULT SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); - - - private: - class CExternalPixelShader - { - public: - CComPtr m_pPixelShader; - CStringA m_SourceData; - CStringA m_SourceTarget; - HRESULT Compile(CPixelShaderCompiler* pCompiler) { - HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); - if (FAILED(hr)) { - return hr; - } - - return S_OK; - } - }; - - // D3DX functions - typedef D3DXFLOAT16* (WINAPI* D3DXFloat32To16ArrayPtr)( - D3DXFLOAT16* pOut, - CONST float* pIn, - UINT n); - - - CAutoPtr m_pPSC; - - // Settings - VideoSystem m_InputVideoSystem; - AmbientLight m_AmbientLight; - ColorRenderingIntent m_RenderingIntent; - - // Custom pixel shaders - CAtlList m_pCustomPixelShaders; - CComPtr m_pTemporaryVideoTextures[2]; - - // Screen space pipeline - int m_ScreenSpacePassCount; - int m_ScreenSpacePassSrc; - int m_ScreenSpacePassDest; - CSize m_TemporaryScreenSpaceTextureSize; - CComPtr m_pTemporaryScreenSpaceTextures[2]; - IDirect3DSurface9* m_pRenderTarget; - - // Resizers - float m_BicubicA; - CComPtr m_pResizerPixelShaders[4]; // bl, bc1, bc2_1, bc2_2 - - // Final pass - bool m_bFinalPass; - int m_Lut3DSize; - int m_Lut3DEntryCount; - CComPtr m_pLut3DTexture; - CComPtr m_pDitherTexture; - CComPtr m_pFinalPixelShader; - - // Custom screen space pixel shaders - CAtlList m_pCustomScreenSpacePixelShaders; - - // StetchRect rendering path - D3DTEXTUREFILTERTYPE m_StretchRectFilter; - - // D3DX function pointers - D3DXFloat32To16ArrayPtr m_pD3DXFloat32To16Array; - - - // Video rendering paths - HRESULT RenderVideoDrawPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); - HRESULT RenderVideoStretchRectPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); - - // Custom pixel shaders - HRESULT InitTemporaryVideoTextures(int count); - - // Screen space pipeline - HRESULT InitScreenSpacePipeline(int passCount, IDirect3DSurface9* pRenderTarget); - HRESULT InitTemporaryScreenSpaceTextures(int count); - HRESULT BeginScreenSpacePass(); - - // Resizers - HRESULT InitResizers(float bicubicA); - HRESULT TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& srcRect); - HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect); - HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect); - //HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect &srcRect); - protected: - HRESULT Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect); - private: - // Final pass - HRESULT InitFinalPass(); - void CleanupFinalPass(); - HRESULT CreateIccProfileLut(TCHAR* profilePath, float* lut3D); - HRESULT FinalPass(IDirect3DTexture9* pTexture); - - HRESULT TextureCopy(IDirect3DTexture9* pTexture); - bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d); - }; - -} +/* + * (C) 2006-2013, 2016-2017 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 . + * + */ + +#pragma once + +#include "AllocatorCommon.h" +#include "RenderersSettings.h" +#include +#include "d3dx9/d3dx9.h" +#include "../SubPic/SubPicAllocatorPresenterImpl.h" + + +namespace DSObjects +{ + + class CDX9RenderingEngine + : public CSubPicAllocatorPresenterImpl + { + protected: + enum RenderingPath { + RENDERING_PATH_STRETCHRECT, + RENDERING_PATH_DRAW + }; + + static const int MAX_VIDEO_SURFACES = 60; + + // Variables initialized/managed by the allocator-presenter! + CComPtr m_pD3D; + CComPtr m_pD3DEx; + CComPtr m_pD3DDev; + CComPtr m_pD3DDevEx; + UINT m_CurrentAdapter; + D3DCAPS9 m_Caps; + D3DFORMAT m_BackbufferType; + D3DFORMAT m_DisplayType; + CSize m_ScreenSize; + CSize m_BackBufferSize; + int m_nNbDXSurface; // Total number of DX Surfaces + int m_nCurSurface; // Surface currently displayed + + bool m_bHighColorResolution; + bool m_bForceInputHighColorResolution; + + // Variables initialized/managed by this class but can be accessed by the allocator-presenter + bool m_bD3DX; + RenderingPath m_RenderingPath; + D3DFORMAT m_SurfaceType; + CComPtr m_pVideoTexture[MAX_VIDEO_SURFACES]; + CComPtr m_pVideoSurface[MAX_VIDEO_SURFACES]; + + bool m_bFullFloatingPointProcessing; + bool m_bHalfFloatingPointProcessing; + bool m_bColorManagement; + + CDX9RenderingEngine(HWND hWnd, HRESULT& hr, CString* _pError); + virtual ~CDX9RenderingEngine() = default; + + void InitRenderingEngine(); + void CleanupRenderingEngine(); + + HRESULT CreateVideoSurfaces(); + void FreeVideoSurfaces(); + + HRESULT RenderVideo(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); + + HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect); + HRESULT AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); + + HRESULT SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); + + + private: + class CExternalPixelShader + { + public: + CComPtr m_pPixelShader; + CStringA m_SourceData; + CStringA m_SourceTarget; + HRESULT Compile(CPixelShaderCompiler* pCompiler) { + HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); + if (FAILED(hr)) { + return hr; + } + + return S_OK; + } + }; + + // D3DX functions + typedef D3DXFLOAT16* (WINAPI* D3DXFloat32To16ArrayPtr)( + D3DXFLOAT16* pOut, + CONST float* pIn, + UINT n); + + + CAutoPtr m_pPSC; + + // Settings + VideoSystem m_InputVideoSystem; + AmbientLight m_AmbientLight; + ColorRenderingIntent m_RenderingIntent; + + // Custom pixel shaders + CAtlList m_pCustomPixelShaders; + CComPtr m_pTemporaryVideoTextures[2]; + + // Screen space pipeline + int m_ScreenSpacePassCount; + int m_ScreenSpacePassSrc; + int m_ScreenSpacePassDest; + CSize m_TemporaryScreenSpaceTextureSize; + CComPtr m_pTemporaryScreenSpaceTextures[2]; + IDirect3DSurface9* m_pRenderTarget; + + // Resizers + float m_BicubicA; + CComPtr m_pResizerPixelShaders[4]; // bl, bc1, bc2_1, bc2_2 + + // Final pass + bool m_bFinalPass; + int m_Lut3DSize; + int m_Lut3DEntryCount; + CComPtr m_pLut3DTexture; + CComPtr m_pDitherTexture; + CComPtr m_pFinalPixelShader; + + // Custom screen space pixel shaders + CAtlList m_pCustomScreenSpacePixelShaders; + + // StetchRect rendering path + D3DTEXTUREFILTERTYPE m_StretchRectFilter; + + // D3DX function pointers + D3DXFloat32To16ArrayPtr m_pD3DXFloat32To16Array; + + + // Video rendering paths + HRESULT RenderVideoDrawPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); + HRESULT RenderVideoStretchRectPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); + + // Custom pixel shaders + HRESULT InitTemporaryVideoTextures(int count); + + // Screen space pipeline + HRESULT InitScreenSpacePipeline(int passCount, IDirect3DSurface9* pRenderTarget); + HRESULT InitTemporaryScreenSpaceTextures(int count); + HRESULT BeginScreenSpacePass(); + + // Resizers + HRESULT InitResizers(float bicubicA); + HRESULT TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& srcRect); + HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect); + HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect); + //HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect &srcRect); + protected: + HRESULT Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect); + private: + // Final pass + HRESULT InitFinalPass(); + void CleanupFinalPass(); + HRESULT CreateIccProfileLut(TCHAR* profilePath, float* lut3D); + HRESULT FinalPass(IDirect3DTexture9* pTexture); + + HRESULT TextureCopy(IDirect3DTexture9* pTexture); + bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d); + }; + +} diff --git a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp index c421f65bce1..6435d5517e6 100644 --- a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp @@ -1,228 +1,228 @@ -/* - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "RenderersSettings.h" -#include "DXRAllocatorPresenter.h" -#include "../../../SubPic/DX9SubPic.h" -#include "../../../SubPic/SubPicQueueImpl.h" -#include "moreuuids.h" - -using namespace DSObjects; - -// -// CDXRAllocatorPresenter -// - -CDXRAllocatorPresenter::CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error) - : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) - , m_ScreenSize(0, 0) -{ - if (FAILED(hr)) { - _Error += L"ISubPicAllocatorPresenterImpl failed\n"; - return; - } - - hr = S_OK; -} - -CDXRAllocatorPresenter::~CDXRAllocatorPresenter() -{ - if (m_pSRCB) { - // nasty, but we have to let it know about our death somehow - ((CSubRenderCallback*)(ISubRenderCallback*)m_pSRCB)->SetDXRAP(nullptr); - } - - // the order is important here - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - m_pDXR = nullptr; -} - -STDMETHODIMP CDXRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - /* - if (riid == __uuidof(IVideoWindow)) - return GetInterface((IVideoWindow*)this, ppv); - if (riid == __uuidof(IBasicVideo)) - return GetInterface((IBasicVideo*)this, ppv); - if (riid == __uuidof(IBasicVideo2)) - return GetInterface((IBasicVideo2*)this, ppv); - */ - /* - if (riid == __uuidof(IVMRWindowlessControl)) - return GetInterface((IVMRWindowlessControl*)this, ppv); - */ - - if (riid != IID_IUnknown && m_pDXR) { - if (SUCCEEDED(m_pDXR->QueryInterface(riid, ppv))) { - return S_OK; - } - } - - return __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CDXRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev) -{ - HRESULT hr = S_OK; - - if (!pD3DDev) { - // release all resources - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - __super::SetPosition(CRect(), CRect()); - return hr; - } - - const CRenderersSettings& r = GetRenderersSettings(); - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(pD3DDev, m_maxSubtitleTextureSize, true); - if (!m_pAllocator) { - return E_FAIL; - } - } - - { - // Lock before check because m_pSubPicQueue might be initialized in CSubPicAllocatorPresenterImpl::Connect - CAutoLock cAutoLock(this); - if (!m_pSubPicQueue) { - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - this->Unlock(); - m_pSubPicQueue->Invalidate(); - } - } - - if (SUCCEEDED(hr) && m_pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); - } - - return hr; -} - -HRESULT CDXRAllocatorPresenter::Render( - REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, - int left, int top, int right, int bottom, int width, int height) -{ - CRect wndRect(0, 0, width, height); - CRect videoRect(left, top, right, bottom); - __super::SetPosition(wndRect, videoRect); // needed? should be already set by the player - SetTime(rtStart); - if (atpf > 0 && m_pSubPicQueue) { - m_pSubPicQueue->SetFPS(10000000.0 / atpf); - } - AlphaBltSubPic(wndRect, videoRect); - return S_OK; -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP CDXRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - - if (m_pDXR) { - return E_UNEXPECTED; - } - m_pDXR.CoCreateInstance(CLSID_DXR, GetOwner()); - if (!m_pDXR) { - return E_FAIL; - } - - CComQIPtr pSR = m_pDXR; - if (!pSR) { - m_pDXR = nullptr; - return E_FAIL; - } - - m_pSRCB = DEBUG_NEW CSubRenderCallback(this); - if (FAILED(pSR->SetCallback(m_pSRCB))) { - m_pDXR = nullptr; - return E_FAIL; - } - - (*ppRenderer = (IUnknown*)(INonDelegatingUnknown*)(this))->AddRef(); - - MONITORINFO mi; - mi.cbSize = sizeof(MONITORINFO); - if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { - m_ScreenSize.SetSize(mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top); - } - - return S_OK; -} - -STDMETHODIMP_(void) CDXRAllocatorPresenter::SetPosition(RECT w, RECT v) -{ - if (CComQIPtr pBV = m_pDXR) { - pBV->SetDefaultSourcePosition(); - pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top); - } - - if (CComQIPtr pVW = m_pDXR) { - pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top); - } - - SetVideoSize(GetVideoSize(false), GetVideoSize(true)); -} - -STDMETHODIMP_(SIZE) CDXRAllocatorPresenter::GetVideoSize(bool bCorrectAR) const -{ - SIZE size = {0, 0}; - - if (!bCorrectAR) { - if (CComQIPtr pBV = m_pDXR) { - pBV->GetVideoSize(&size.cx, &size.cy); - } - } else { - if (CComQIPtr pBV2 = m_pDXR) { - pBV2->GetPreferredAspectRatio(&size.cx, &size.cy); - } - } - - return size; -} - -STDMETHODIMP_(bool) CDXRAllocatorPresenter::Paint(bool bAll) -{ - return false; // TODO -} - -STDMETHODIMP CDXRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) -{ - HRESULT hr = E_NOTIMPL; - if (CComQIPtr pBV = m_pDXR) { - hr = pBV->GetCurrentImage((long*)size, (long*)lpDib); - } - return hr; -} - -STDMETHODIMP CDXRAllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) -{ - return E_NOTIMPL; // TODO -} +/* + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "RenderersSettings.h" +#include "DXRAllocatorPresenter.h" +#include "../../../SubPic/DX9SubPic.h" +#include "../../../SubPic/SubPicQueueImpl.h" +#include "moreuuids.h" + +using namespace DSObjects; + +// +// CDXRAllocatorPresenter +// + +CDXRAllocatorPresenter::CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error) + : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) + , m_ScreenSize(0, 0) +{ + if (FAILED(hr)) { + _Error += L"ISubPicAllocatorPresenterImpl failed\n"; + return; + } + + hr = S_OK; +} + +CDXRAllocatorPresenter::~CDXRAllocatorPresenter() +{ + if (m_pSRCB) { + // nasty, but we have to let it know about our death somehow + ((CSubRenderCallback*)(ISubRenderCallback*)m_pSRCB)->SetDXRAP(nullptr); + } + + // the order is important here + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + m_pDXR = nullptr; +} + +STDMETHODIMP CDXRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + /* + if (riid == __uuidof(IVideoWindow)) + return GetInterface((IVideoWindow*)this, ppv); + if (riid == __uuidof(IBasicVideo)) + return GetInterface((IBasicVideo*)this, ppv); + if (riid == __uuidof(IBasicVideo2)) + return GetInterface((IBasicVideo2*)this, ppv); + */ + /* + if (riid == __uuidof(IVMRWindowlessControl)) + return GetInterface((IVMRWindowlessControl*)this, ppv); + */ + + if (riid != IID_IUnknown && m_pDXR) { + if (SUCCEEDED(m_pDXR->QueryInterface(riid, ppv))) { + return S_OK; + } + } + + return __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CDXRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev) +{ + HRESULT hr = S_OK; + + if (!pD3DDev) { + // release all resources + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + __super::SetPosition(CRect(), CRect()); + return hr; + } + + const CRenderersSettings& r = GetRenderersSettings(); + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(pD3DDev, m_maxSubtitleTextureSize, true); + if (!m_pAllocator) { + return E_FAIL; + } + } + + { + // Lock before check because m_pSubPicQueue might be initialized in CSubPicAllocatorPresenterImpl::Connect + CAutoLock cAutoLock(this); + if (!m_pSubPicQueue) { + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + this->Unlock(); + m_pSubPicQueue->Invalidate(); + } + } + + if (SUCCEEDED(hr) && m_pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); + } + + return hr; +} + +HRESULT CDXRAllocatorPresenter::Render( + REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, + int left, int top, int right, int bottom, int width, int height) +{ + CRect wndRect(0, 0, width, height); + CRect videoRect(left, top, right, bottom); + __super::SetPosition(wndRect, videoRect); // needed? should be already set by the player + SetTime(rtStart); + if (atpf > 0 && m_pSubPicQueue) { + m_pSubPicQueue->SetFPS(10000000.0 / atpf); + } + AlphaBltSubPic(wndRect, videoRect); + return S_OK; +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP CDXRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + + if (m_pDXR) { + return E_UNEXPECTED; + } + m_pDXR.CoCreateInstance(CLSID_DXR, GetOwner()); + if (!m_pDXR) { + return E_FAIL; + } + + CComQIPtr pSR = m_pDXR; + if (!pSR) { + m_pDXR = nullptr; + return E_FAIL; + } + + m_pSRCB = DEBUG_NEW CSubRenderCallback(this); + if (FAILED(pSR->SetCallback(m_pSRCB))) { + m_pDXR = nullptr; + return E_FAIL; + } + + (*ppRenderer = (IUnknown*)(INonDelegatingUnknown*)(this))->AddRef(); + + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { + m_ScreenSize.SetSize(mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top); + } + + return S_OK; +} + +STDMETHODIMP_(void) CDXRAllocatorPresenter::SetPosition(RECT w, RECT v) +{ + if (CComQIPtr pBV = m_pDXR) { + pBV->SetDefaultSourcePosition(); + pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top); + } + + if (CComQIPtr pVW = m_pDXR) { + pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top); + } + + SetVideoSize(GetVideoSize(false), GetVideoSize(true)); +} + +STDMETHODIMP_(SIZE) CDXRAllocatorPresenter::GetVideoSize(bool bCorrectAR) const +{ + SIZE size = {0, 0}; + + if (!bCorrectAR) { + if (CComQIPtr pBV = m_pDXR) { + pBV->GetVideoSize(&size.cx, &size.cy); + } + } else { + if (CComQIPtr pBV2 = m_pDXR) { + pBV2->GetPreferredAspectRatio(&size.cx, &size.cy); + } + } + + return size; +} + +STDMETHODIMP_(bool) CDXRAllocatorPresenter::Paint(bool bAll) +{ + return false; // TODO +} + +STDMETHODIMP CDXRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) +{ + HRESULT hr = E_NOTIMPL; + if (CComQIPtr pBV = m_pDXR) { + hr = pBV->GetCurrentImage((long*)size, (long*)lpDib); + } + return hr; +} + +STDMETHODIMP CDXRAllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) +{ + return E_NOTIMPL; // TODO +} diff --git a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h index 169b5017ed0..d8168673035 100644 --- a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h @@ -1,103 +1,103 @@ -/* - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "AllocatorCommon.h" -#include "../SubPic/SubPicAllocatorPresenterImpl.h" -#include "../SubPic/ISubRender.h" - -namespace DSObjects -{ - class CDXRAllocatorPresenter - : public CSubPicAllocatorPresenterImpl - { - class CSubRenderCallback : public CUnknown, public ISubRenderCallback, public CCritSec - { - CDXRAllocatorPresenter* m_pDXRAP; - - public: - CSubRenderCallback(CDXRAllocatorPresenter* pDXRAP) - : CUnknown(_T("CSubRender"), nullptr) - , m_pDXRAP(pDXRAP) { - } - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(ISubRenderCallback) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - void SetDXRAP(CDXRAllocatorPresenter* pDXRAP) { - CAutoLock cAutoLock(this); - m_pDXRAP = pDXRAP; - } - - // ISubRenderCallback - - STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev) { - CAutoLock cAutoLock(this); - return m_pDXRAP ? m_pDXRAP->SetDevice(pD3DDev) : E_UNEXPECTED; - } - - STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, int bottom, int width, int height) { - CAutoLock cAutoLock(this); - return m_pDXRAP ? m_pDXRAP->Render(rtStart, 0, 0, left, top, right, bottom, width, height) : E_UNEXPECTED; - } - - // ISubRendererCallback2 - - STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME AvgTimePerFrame, int left, int top, int right, int bottom, int width, int height) { - CAutoLock cAutoLock(this); - return m_pDXRAP ? m_pDXRAP->Render(rtStart, rtStop, AvgTimePerFrame, left, top, right, bottom, width, height) : E_UNEXPECTED; - } - }; - - CComPtr m_pDXR; - CComPtr m_pSRCB; - CSize m_ScreenSize; - - public: - CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error); - virtual ~CDXRAllocatorPresenter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT SetDevice(IDirect3DDevice9* pD3DDev); - HRESULT Render( - REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, - int left, int top, int bottom, int right, int width, int height); - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(void) SetPosition(RECT w, RECT v); - STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const; - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() { - return true; // We don't know so we always pretend to be rendering - } - }; -} +/* + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "AllocatorCommon.h" +#include "../SubPic/SubPicAllocatorPresenterImpl.h" +#include "../SubPic/ISubRender.h" + +namespace DSObjects +{ + class CDXRAllocatorPresenter + : public CSubPicAllocatorPresenterImpl + { + class CSubRenderCallback : public CUnknown, public ISubRenderCallback, public CCritSec + { + CDXRAllocatorPresenter* m_pDXRAP; + + public: + CSubRenderCallback(CDXRAllocatorPresenter* pDXRAP) + : CUnknown(_T("CSubRender"), nullptr) + , m_pDXRAP(pDXRAP) { + } + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(ISubRenderCallback) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + void SetDXRAP(CDXRAllocatorPresenter* pDXRAP) { + CAutoLock cAutoLock(this); + m_pDXRAP = pDXRAP; + } + + // ISubRenderCallback + + STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev) { + CAutoLock cAutoLock(this); + return m_pDXRAP ? m_pDXRAP->SetDevice(pD3DDev) : E_UNEXPECTED; + } + + STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, int bottom, int width, int height) { + CAutoLock cAutoLock(this); + return m_pDXRAP ? m_pDXRAP->Render(rtStart, 0, 0, left, top, right, bottom, width, height) : E_UNEXPECTED; + } + + // ISubRendererCallback2 + + STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME AvgTimePerFrame, int left, int top, int right, int bottom, int width, int height) { + CAutoLock cAutoLock(this); + return m_pDXRAP ? m_pDXRAP->Render(rtStart, rtStop, AvgTimePerFrame, left, top, right, bottom, width, height) : E_UNEXPECTED; + } + }; + + CComPtr m_pDXR; + CComPtr m_pSRCB; + CSize m_ScreenSize; + + public: + CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error); + virtual ~CDXRAllocatorPresenter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT SetDevice(IDirect3DDevice9* pD3DDev); + HRESULT Render( + REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, + int left, int top, int bottom, int right, int width, int height); + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(void) SetPosition(RECT w, RECT v); + STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const; + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() { + return true; // We don't know so we always pretend to be rendering + } + }; +} diff --git a/src/filters/renderer/VideoRenderers/Dither.cpp b/src/filters/renderer/VideoRenderers/Dither.cpp index 3e1ce88ef18..d4dec88044e 100644 --- a/src/filters/renderer/VideoRenderers/Dither.cpp +++ b/src/filters/renderer/VideoRenderers/Dither.cpp @@ -1,90 +1,90 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "Dither.h" - -// Dither matrix in 16-bit floating point format -const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE] = { - 0x2c90, 0x38f4, 0x3bba, 0x29e0, 0x35f4, 0x3230, 0x3bbc, 0x3924, 0x3a46, 0x3644, 0x39e2, 0x370c, 0x3444, 0x3b1a, 0x3140, 0x39d2, - 0x385a, 0x3b24, 0x2c10, 0x38c6, 0x3808, 0x2780, 0x3bbe, 0x37f8, 0x350c, 0x3a6c, 0x3368, 0x3bc0, 0x3000, 0x3886, 0x31b0, 0x3554, - 0x3a94, 0x3618, 0x3430, 0x3a34, 0x3834, 0x39fe, 0x2740, 0x3758, 0x3494, 0x3b7a, 0x2700, 0x3958, 0x3858, 0x3a24, 0x364c, 0x3bc2, - 0x3278, 0x3a22, 0x353c, 0x39de, 0x3268, 0x3a98, 0x36fc, 0x2ed0, 0x39e0, 0x30f0, 0x381a, 0x3996, 0x35ac, 0x3af2, 0x39b8, 0x37bc, - 0x3250, 0x39dc, 0x3800, 0x30e8, 0x3b42, 0x34d4, 0x3970, 0x3afe, 0x3020, 0x3898, 0x33e8, 0x3b34, 0x2e10, 0x3320, 0x391a, 0x26c0, - 0x3784, 0x38de, 0x3060, 0x3b5c, 0x3600, 0x38e6, 0x3490, 0x3b2a, 0x387a, 0x365c, 0x3b3c, 0x2be0, 0x37ac, 0x33d8, 0x2680, 0x3b98, - 0x38d6, 0x2a60, 0x3b7e, 0x391e, 0x36d0, 0x2fe0, 0x3812, 0x32a0, 0x3a84, 0x36b0, 0x3a50, 0x357c, 0x37dc, 0x3b68, 0x3594, 0x3aca, - 0x344c, 0x3a7c, 0x3674, 0x3884, 0x2d30, 0x3a48, 0x3170, 0x398e, 0x2900, 0x3a30, 0x34bc, 0x38ea, 0x3b70, 0x3a3c, 0x3852, 0x3460, - 0x3b04, 0x37a0, 0x351c, 0x2d40, 0x3a80, 0x394e, 0x3b84, 0x3614, 0x3900, 0x2b20, 0x396c, 0x31b8, 0x38ca, 0x3a0c, 0x3038, 0x385c, - 0x39a2, 0x2c70, 0x3ba2, 0x3464, 0x3992, 0x36dc, 0x3bc4, 0x3580, 0x3824, 0x32d0, 0x3abc, 0x2ec0, 0x3560, 0x30f8, 0x3974, 0x3610, - 0x3a12, 0x3110, 0x3aaa, 0x38a2, 0x35e4, 0x341c, 0x28c0, 0x3a02, 0x34a8, 0x3b60, 0x3790, 0x3aa2, 0x2c40, 0x346c, 0x373c, 0x3bc6, - 0x32f0, 0x37e8, 0x391c, 0x3100, 0x3af6, 0x2640, 0x3868, 0x3098, 0x3b3e, 0x3944, 0x3620, 0x3870, 0x39da, 0x374c, 0x3bc8, 0x2e20, - 0x3804, 0x3932, 0x3660, 0x3260, 0x3bca, 0x38ce, 0x3ade, 0x382e, 0x30a0, 0x389e, 0x33a0, 0x363c, 0x3b86, 0x3910, 0x3a58, 0x2820, - 0x36a0, 0x3b28, 0x34e0, 0x3a40, 0x3768, 0x3510, 0x3a54, 0x390e, 0x36e8, 0x2ae0, 0x3bcc, 0x31a0, 0x3aa4, 0x2600, 0x38cc, 0x3400, - 0x3ac4, 0x2800, 0x3b4a, 0x39ee, 0x2cc0, 0x3764, 0x31c8, 0x35cc, 0x3bb6, 0x39a8, 0x2f30, 0x3a1e, 0x3816, 0x3160, 0x35b0, 0x389a, - 0x3a86, 0x3070, 0x3848, 0x2d70, 0x38ba, 0x3baa, 0x2e60, 0x3414, 0x3ae4, 0x3544, 0x3a06, 0x37fc, 0x347c, 0x36d8, 0x3b12, 0x35a4, - 0x3248, 0x3866, 0x34f8, 0x3814, 0x33f8, 0x39c2, 0x3a8a, 0x38e2, 0x25c0, 0x3720, 0x3b26, 0x3508, 0x2980, 0x39b4, 0x3b4c, 0x33a8, - 0x3976, 0x3534, 0x39c4, 0x3b40, 0x3604, 0x31c0, 0x397c, 0x37b0, 0x39d0, 0x3218, 0x38d8, 0x2e30, 0x3b52, 0x39bc, 0x2fa0, 0x3980, - 0x3b9a, 0x39d4, 0x2f40, 0x3960, 0x3b64, 0x3680, 0x2f60, 0x34c8, 0x3acc, 0x3228, 0x3850, 0x395c, 0x3bce, 0x354c, 0x3840, 0x2db0, - 0x37a4, 0x3bd0, 0x2580, 0x33c8, 0x392a, 0x3a82, 0x3530, 0x3b48, 0x2540, 0x3760, 0x3a42, 0x35dc, 0x3890, 0x3308, 0x3844, 0x3710, - 0x3418, 0x366c, 0x3a9a, 0x3590, 0x2500, 0x3888, 0x3bd2, 0x3984, 0x3668, 0x39e4, 0x345c, 0x2d20, 0x371c, 0x3288, 0x3aae, 0x39d6, - 0x31e0, 0x38c8, 0x36e4, 0x3ab2, 0x380c, 0x2b00, 0x389c, 0x3280, 0x392c, 0x3bd4, 0x33b8, 0x3ad6, 0x24c0, 0x3bd6, 0x3a32, 0x2c60, - 0x3b1c, 0x38aa, 0x3238, 0x3902, 0x3ae8, 0x3528, 0x3118, 0x3818, 0x2c50, 0x3ba0, 0x38bc, 0x3ad8, 0x3a20, 0x38f0, 0x2480, 0x36b4, - 0x3b02, 0x34b0, 0x3a00, 0x30a8, 0x3518, 0x3bd8, 0x3688, 0x3a92, 0x34b4, 0x36c0, 0x2f70, 0x3968, 0x3798, 0x3448, 0x35ec, 0x3930, - 0x3750, 0x2a40, 0x3bda, 0x3728, 0x32e8, 0x3a4a, 0x38d2, 0x3b38, 0x33d0, 0x3738, 0x30b8, 0x3628, 0x340c, 0x37d4, 0x3bb2, 0x3428, - 0x3934, 0x2b40, 0x3856, 0x3b0e, 0x3964, 0x31d0, 0x39b0, 0x2e80, 0x38d4, 0x3b1e, 0x3a28, 0x387e, 0x30e0, 0x39a0, 0x3ae2, 0x3208, - 0x3a56, 0x352c, 0x3a14, 0x2d90, 0x3978, 0x3794, 0x2960, 0x35e0, 0x39c6, 0x3a88, 0x3862, 0x3b76, 0x2e40, 0x3988, 0x3128, 0x3a4c, - 0x378c, 0x3b8e, 0x359c, 0x2ea0, 0x36ac, 0x383e, 0x3af8, 0x3404, 0x3780, 0x2a20, 0x3360, 0x3598, 0x3b90, 0x37d0, 0x2dd0, 0x3880, - 0x3358, 0x3946, 0x381c, 0x348c, 0x3b50, 0x3198, 0x3ad4, 0x3940, 0x3050, 0x3540, 0x2440, 0x39cc, 0x3770, 0x3b0a, 0x35d8, 0x386c, - 0x2f00, 0x3380, 0x3a5a, 0x3948, 0x3ba4, 0x2400, 0x35a0, 0x393e, 0x3ba6, 0x39ea, 0x3838, 0x3ab0, 0x27c0, 0x3a38, 0x3538, 0x3bb4, - 0x2380, 0x3b62, 0x30d8, 0x3a62, 0x360c, 0x388c, 0x342c, 0x37e0, 0x3bdc, 0x38f2, 0x3ad0, 0x3488, 0x3168, 0x38da, 0x2300, 0x39ca, - 0x3aee, 0x3630, 0x387c, 0x31a8, 0x34e4, 0x38b8, 0x3a3e, 0x2dc0, 0x3640, 0x3130, 0x34ec, 0x3972, 0x36ec, 0x3318, 0x3950, 0x3714, - 0x3914, 0x356c, 0x38b6, 0x376c, 0x2280, 0x3b9c, 0x39c8, 0x2d50, 0x35e8, 0x32c0, 0x3704, 0x388a, 0x3a64, 0x3558, 0x3bde, 0x3440, - 0x3724, 0x3982, 0x28e0, 0x3ada, 0x375c, 0x3b30, 0x3300, 0x384a, 0x3a74, 0x38e8, 0x3b66, 0x2ee0, 0x385e, 0x3b46, 0x2f90, 0x3ab8, - 0x3178, 0x3a52, 0x2e00, 0x3b08, 0x3918, 0x3150, 0x3678, 0x3aa6, 0x3922, 0x3b14, 0x2fd0, 0x3b8a, 0x2ce0, 0x39a4, 0x379c, 0x2fb0, - 0x3b5a, 0x3240, 0x3a2e, 0x3390, 0x3916, 0x2e90, 0x36c4, 0x3be0, 0x349c, 0x2200, 0x3694, 0x39b2, 0x3478, 0x39f0, 0x35c4, 0x3828, - 0x3be2, 0x36d4, 0x3994, 0x3548, 0x3328, 0x3a04, 0x3854, 0x3498, 0x28a0, 0x3810, 0x39fc, 0x3520, 0x3846, 0x32d8, 0x3ab4, 0x393c, - 0x3864, 0x35b4, 0x380e, 0x3be4, 0x3570, 0x3a96, 0x39ac, 0x3090, 0x3962, 0x37c0, 0x3a9e, 0x3120, 0x3be6, 0x2a00, 0x38f6, 0x3410, - 0x2180, 0x386e, 0x3088, 0x3b82, 0x37a8, 0x3ae6, 0x2f10, 0x3be8, 0x399a, 0x3634, 0x31e8, 0x3912, 0x3b06, 0x36f0, 0x2c30, 0x3504, - 0x3a76, 0x2aa0, 0x39e8, 0x3040, 0x3878, 0x2880, 0x383a, 0x35f8, 0x3aec, 0x32a8, 0x3936, 0x3550, 0x3892, 0x3740, 0x3aea, 0x398c, - 0x3a72, 0x34c4, 0x3a1c, 0x38ac, 0x2860, 0x3584, 0x38fa, 0x372c, 0x3388, 0x3a3a, 0x3b9e, 0x2100, 0x3420, 0x395a, 0x3bae, 0x37d8, - 0x3398, 0x3b6c, 0x3734, 0x34d0, 0x39c0, 0x3b78, 0x3474, 0x3a2c, 0x2b80, 0x3830, 0x3b56, 0x2cb0, 0x3a78, 0x33b0, 0x3018, 0x3650, - 0x30d0, 0x3b20, 0x3690, 0x3350, 0x39ae, 0x3a90, 0x3148, 0x3b44, 0x2cd0, 0x38a0, 0x355c, 0x382a, 0x3a8e, 0x35b8, 0x3190, 0x39ec, - 0x38c4, 0x3068, 0x3938, 0x3b2e, 0x32c8, 0x3748, 0x3008, 0x3894, 0x3bb8, 0x3438, 0x36c8, 0x3904, 0x35fc, 0x396e, 0x3bac, 0x38a6, - 0x397a, 0x37ec, 0x2ca0, 0x3bea, 0x3754, 0x34a4, 0x3836, 0x3956, 0x362c, 0x3b00, 0x30c0, 0x39a6, 0x2fc0, 0x38ae, 0x3abe, 0x2080, - 0x3684, 0x3a70, 0x3568, 0x2000, 0x38c2, 0x3af0, 0x3998, 0x368c, 0x30b0, 0x39ba, 0x3aa8, 0x3200, 0x3b16, 0x2d80, 0x377c, 0x3480, - 0x3b6e, 0x3270, 0x39fa, 0x386a, 0x2ff0, 0x3b10, 0x1f00, 0x3a44, 0x343c, 0x3802, 0x3a66, 0x34b8, 0x3bec, 0x3708, 0x3340, 0x3882, - 0x3bee, 0x3298, 0x3806, 0x3a08, 0x3638, 0x2d00, 0x34ac, 0x3a60, 0x38ee, 0x35c8, 0x29c0, 0x380a, 0x34f0, 0x38f8, 0x3aac, 0x1e00, - 0x3564, 0x38fe, 0x3468, 0x3ace, 0x35d0, 0x394a, 0x37b4, 0x31f8, 0x3bf0, 0x2bc0, 0x38d0, 0x36b8, 0x2940, 0x3926, 0x3b32, 0x35a8, - 0x2d60, 0x38e0, 0x3b58, 0x3078, 0x3a9c, 0x37e4, 0x3bf2, 0x2e50, 0x33f0, 0x3b72, 0x38b4, 0x39e6, 0x3bf4, 0x3290, 0x3670, 0x3a1a, - 0x3842, 0x3a68, 0x2920, 0x37c4, 0x32b8, 0x3b88, 0x34c0, 0x396a, 0x3664, 0x39b6, 0x3330, 0x3b5e, 0x39ce, 0x3484, 0x3080, 0x39aa, - 0x3a4e, 0x3700, 0x34e8, 0x395e, 0x3310, 0x3908, 0x3588, 0x384e, 0x3ac6, 0x3730, 0x3220, 0x3574, 0x2de0, 0x37f0, 0x399c, 0x2ef0, - 0x3188, 0x369c, 0x3bf6, 0x390a, 0x39f2, 0x2b60, 0x3872, 0x3aa0, 0x2df0, 0x3b0c, 0x37cc, 0x2da0, 0x382c, 0x3ae0, 0x38b0, 0x3788, - 0x33c0, 0x3afa, 0x2ba0, 0x3826, 0x3b6a, 0x1d00, 0x39f8, 0x3108, 0x3920, 0x1c00, 0x3a26, 0x3b22, 0x38ec, 0x3ac2, 0x3458, 0x3b7c, - 0x3a8c, 0x38a8, 0x34d8, 0x3048, 0x3654, 0x3adc, 0x3138, 0x3744, 0x3450, 0x38be, 0x34f4, 0x3a10, 0x3210, 0x35bc, 0x2840, 0x3b92, - 0x3058, 0x3986, 0x3698, 0x39d8, 0x3434, 0x36f8, 0x3b18, 0x3524, 0x3a7a, 0x35d4, 0x3822, 0x3408, 0x36bc, 0x2ac0, 0x3896, 0x3624, - 0x1a00, 0x3378, 0x3a16, 0x3b3a, 0x381e, 0x3338, 0x3906, 0x39f6, 0x3bf8, 0x3158, 0x3ad2, 0x36e0, 0x3bfa, 0x392e, 0x3a5c, 0x3648, - 0x38dc, 0x34cc, 0x3bfc, 0x30c8, 0x3ab6, 0x3942, 0x32b0, 0x38a4, 0x2d10, 0x3b96, 0x394c, 0x2f80, 0x3bfe, 0x3966, 0x3258, 0x39be, - 0x3bb0, 0x3928, 0x361c, 0x2c00, 0x3990, 0x3b8c, 0x3578, 0x2a80, 0x36cc, 0x3952, 0x1800, 0x388e, 0x33e0, 0x2f20, 0x384c, 0x31d8, - 0x3a18, 0x1400, 0x3876, 0x358c, 0x383c, 0x2c20, 0x3b80, 0x3774, 0x3a36, 0x3470, 0x31f0, 0x3a0a, 0x3832, 0x3514, 0x3a6a, 0x37f4, - 0x367c, 0x3028, 0x3ac8, 0x37b8, 0x34a0, 0x2f50, 0x3a5e, 0x3874, 0x3b36, 0x34fc, 0x3a6e, 0x35f0, 0x399e, 0x3aba, 0x3500, 0x3b74, - 0x37c8, 0x3ac0, 0x398a, 0x3010, 0x3a7e, 0x3658, 0x38e4, 0x3030, 0x3608, 0x3860, 0x3af4, 0x3718, 0x29a0, 0x3b2c, 0x2eb0, 0x3424, - 0x3a0e, 0x3820, 0x32f8, 0x3954, 0x3afc, 0x38c0, 0x36a4, 0x3370, 0x2e70, 0x38b2, 0x3180, 0x3ba8, 0x2c80, 0x3778, 0x390c, 0x2cf0, - 0x35c0, 0x32e0, 0x36f4, 0x3b94, 0x3454, 0x39f4, 0x3348, 0x397e, 0x3b4e, 0x0000, 0x38fc, 0x34dc, 0x3a2a, 0x36a8, 0x393a, 0x3b54, -}; +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "Dither.h" + +// Dither matrix in 16-bit floating point format +const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE] = { + 0x2c90, 0x38f4, 0x3bba, 0x29e0, 0x35f4, 0x3230, 0x3bbc, 0x3924, 0x3a46, 0x3644, 0x39e2, 0x370c, 0x3444, 0x3b1a, 0x3140, 0x39d2, + 0x385a, 0x3b24, 0x2c10, 0x38c6, 0x3808, 0x2780, 0x3bbe, 0x37f8, 0x350c, 0x3a6c, 0x3368, 0x3bc0, 0x3000, 0x3886, 0x31b0, 0x3554, + 0x3a94, 0x3618, 0x3430, 0x3a34, 0x3834, 0x39fe, 0x2740, 0x3758, 0x3494, 0x3b7a, 0x2700, 0x3958, 0x3858, 0x3a24, 0x364c, 0x3bc2, + 0x3278, 0x3a22, 0x353c, 0x39de, 0x3268, 0x3a98, 0x36fc, 0x2ed0, 0x39e0, 0x30f0, 0x381a, 0x3996, 0x35ac, 0x3af2, 0x39b8, 0x37bc, + 0x3250, 0x39dc, 0x3800, 0x30e8, 0x3b42, 0x34d4, 0x3970, 0x3afe, 0x3020, 0x3898, 0x33e8, 0x3b34, 0x2e10, 0x3320, 0x391a, 0x26c0, + 0x3784, 0x38de, 0x3060, 0x3b5c, 0x3600, 0x38e6, 0x3490, 0x3b2a, 0x387a, 0x365c, 0x3b3c, 0x2be0, 0x37ac, 0x33d8, 0x2680, 0x3b98, + 0x38d6, 0x2a60, 0x3b7e, 0x391e, 0x36d0, 0x2fe0, 0x3812, 0x32a0, 0x3a84, 0x36b0, 0x3a50, 0x357c, 0x37dc, 0x3b68, 0x3594, 0x3aca, + 0x344c, 0x3a7c, 0x3674, 0x3884, 0x2d30, 0x3a48, 0x3170, 0x398e, 0x2900, 0x3a30, 0x34bc, 0x38ea, 0x3b70, 0x3a3c, 0x3852, 0x3460, + 0x3b04, 0x37a0, 0x351c, 0x2d40, 0x3a80, 0x394e, 0x3b84, 0x3614, 0x3900, 0x2b20, 0x396c, 0x31b8, 0x38ca, 0x3a0c, 0x3038, 0x385c, + 0x39a2, 0x2c70, 0x3ba2, 0x3464, 0x3992, 0x36dc, 0x3bc4, 0x3580, 0x3824, 0x32d0, 0x3abc, 0x2ec0, 0x3560, 0x30f8, 0x3974, 0x3610, + 0x3a12, 0x3110, 0x3aaa, 0x38a2, 0x35e4, 0x341c, 0x28c0, 0x3a02, 0x34a8, 0x3b60, 0x3790, 0x3aa2, 0x2c40, 0x346c, 0x373c, 0x3bc6, + 0x32f0, 0x37e8, 0x391c, 0x3100, 0x3af6, 0x2640, 0x3868, 0x3098, 0x3b3e, 0x3944, 0x3620, 0x3870, 0x39da, 0x374c, 0x3bc8, 0x2e20, + 0x3804, 0x3932, 0x3660, 0x3260, 0x3bca, 0x38ce, 0x3ade, 0x382e, 0x30a0, 0x389e, 0x33a0, 0x363c, 0x3b86, 0x3910, 0x3a58, 0x2820, + 0x36a0, 0x3b28, 0x34e0, 0x3a40, 0x3768, 0x3510, 0x3a54, 0x390e, 0x36e8, 0x2ae0, 0x3bcc, 0x31a0, 0x3aa4, 0x2600, 0x38cc, 0x3400, + 0x3ac4, 0x2800, 0x3b4a, 0x39ee, 0x2cc0, 0x3764, 0x31c8, 0x35cc, 0x3bb6, 0x39a8, 0x2f30, 0x3a1e, 0x3816, 0x3160, 0x35b0, 0x389a, + 0x3a86, 0x3070, 0x3848, 0x2d70, 0x38ba, 0x3baa, 0x2e60, 0x3414, 0x3ae4, 0x3544, 0x3a06, 0x37fc, 0x347c, 0x36d8, 0x3b12, 0x35a4, + 0x3248, 0x3866, 0x34f8, 0x3814, 0x33f8, 0x39c2, 0x3a8a, 0x38e2, 0x25c0, 0x3720, 0x3b26, 0x3508, 0x2980, 0x39b4, 0x3b4c, 0x33a8, + 0x3976, 0x3534, 0x39c4, 0x3b40, 0x3604, 0x31c0, 0x397c, 0x37b0, 0x39d0, 0x3218, 0x38d8, 0x2e30, 0x3b52, 0x39bc, 0x2fa0, 0x3980, + 0x3b9a, 0x39d4, 0x2f40, 0x3960, 0x3b64, 0x3680, 0x2f60, 0x34c8, 0x3acc, 0x3228, 0x3850, 0x395c, 0x3bce, 0x354c, 0x3840, 0x2db0, + 0x37a4, 0x3bd0, 0x2580, 0x33c8, 0x392a, 0x3a82, 0x3530, 0x3b48, 0x2540, 0x3760, 0x3a42, 0x35dc, 0x3890, 0x3308, 0x3844, 0x3710, + 0x3418, 0x366c, 0x3a9a, 0x3590, 0x2500, 0x3888, 0x3bd2, 0x3984, 0x3668, 0x39e4, 0x345c, 0x2d20, 0x371c, 0x3288, 0x3aae, 0x39d6, + 0x31e0, 0x38c8, 0x36e4, 0x3ab2, 0x380c, 0x2b00, 0x389c, 0x3280, 0x392c, 0x3bd4, 0x33b8, 0x3ad6, 0x24c0, 0x3bd6, 0x3a32, 0x2c60, + 0x3b1c, 0x38aa, 0x3238, 0x3902, 0x3ae8, 0x3528, 0x3118, 0x3818, 0x2c50, 0x3ba0, 0x38bc, 0x3ad8, 0x3a20, 0x38f0, 0x2480, 0x36b4, + 0x3b02, 0x34b0, 0x3a00, 0x30a8, 0x3518, 0x3bd8, 0x3688, 0x3a92, 0x34b4, 0x36c0, 0x2f70, 0x3968, 0x3798, 0x3448, 0x35ec, 0x3930, + 0x3750, 0x2a40, 0x3bda, 0x3728, 0x32e8, 0x3a4a, 0x38d2, 0x3b38, 0x33d0, 0x3738, 0x30b8, 0x3628, 0x340c, 0x37d4, 0x3bb2, 0x3428, + 0x3934, 0x2b40, 0x3856, 0x3b0e, 0x3964, 0x31d0, 0x39b0, 0x2e80, 0x38d4, 0x3b1e, 0x3a28, 0x387e, 0x30e0, 0x39a0, 0x3ae2, 0x3208, + 0x3a56, 0x352c, 0x3a14, 0x2d90, 0x3978, 0x3794, 0x2960, 0x35e0, 0x39c6, 0x3a88, 0x3862, 0x3b76, 0x2e40, 0x3988, 0x3128, 0x3a4c, + 0x378c, 0x3b8e, 0x359c, 0x2ea0, 0x36ac, 0x383e, 0x3af8, 0x3404, 0x3780, 0x2a20, 0x3360, 0x3598, 0x3b90, 0x37d0, 0x2dd0, 0x3880, + 0x3358, 0x3946, 0x381c, 0x348c, 0x3b50, 0x3198, 0x3ad4, 0x3940, 0x3050, 0x3540, 0x2440, 0x39cc, 0x3770, 0x3b0a, 0x35d8, 0x386c, + 0x2f00, 0x3380, 0x3a5a, 0x3948, 0x3ba4, 0x2400, 0x35a0, 0x393e, 0x3ba6, 0x39ea, 0x3838, 0x3ab0, 0x27c0, 0x3a38, 0x3538, 0x3bb4, + 0x2380, 0x3b62, 0x30d8, 0x3a62, 0x360c, 0x388c, 0x342c, 0x37e0, 0x3bdc, 0x38f2, 0x3ad0, 0x3488, 0x3168, 0x38da, 0x2300, 0x39ca, + 0x3aee, 0x3630, 0x387c, 0x31a8, 0x34e4, 0x38b8, 0x3a3e, 0x2dc0, 0x3640, 0x3130, 0x34ec, 0x3972, 0x36ec, 0x3318, 0x3950, 0x3714, + 0x3914, 0x356c, 0x38b6, 0x376c, 0x2280, 0x3b9c, 0x39c8, 0x2d50, 0x35e8, 0x32c0, 0x3704, 0x388a, 0x3a64, 0x3558, 0x3bde, 0x3440, + 0x3724, 0x3982, 0x28e0, 0x3ada, 0x375c, 0x3b30, 0x3300, 0x384a, 0x3a74, 0x38e8, 0x3b66, 0x2ee0, 0x385e, 0x3b46, 0x2f90, 0x3ab8, + 0x3178, 0x3a52, 0x2e00, 0x3b08, 0x3918, 0x3150, 0x3678, 0x3aa6, 0x3922, 0x3b14, 0x2fd0, 0x3b8a, 0x2ce0, 0x39a4, 0x379c, 0x2fb0, + 0x3b5a, 0x3240, 0x3a2e, 0x3390, 0x3916, 0x2e90, 0x36c4, 0x3be0, 0x349c, 0x2200, 0x3694, 0x39b2, 0x3478, 0x39f0, 0x35c4, 0x3828, + 0x3be2, 0x36d4, 0x3994, 0x3548, 0x3328, 0x3a04, 0x3854, 0x3498, 0x28a0, 0x3810, 0x39fc, 0x3520, 0x3846, 0x32d8, 0x3ab4, 0x393c, + 0x3864, 0x35b4, 0x380e, 0x3be4, 0x3570, 0x3a96, 0x39ac, 0x3090, 0x3962, 0x37c0, 0x3a9e, 0x3120, 0x3be6, 0x2a00, 0x38f6, 0x3410, + 0x2180, 0x386e, 0x3088, 0x3b82, 0x37a8, 0x3ae6, 0x2f10, 0x3be8, 0x399a, 0x3634, 0x31e8, 0x3912, 0x3b06, 0x36f0, 0x2c30, 0x3504, + 0x3a76, 0x2aa0, 0x39e8, 0x3040, 0x3878, 0x2880, 0x383a, 0x35f8, 0x3aec, 0x32a8, 0x3936, 0x3550, 0x3892, 0x3740, 0x3aea, 0x398c, + 0x3a72, 0x34c4, 0x3a1c, 0x38ac, 0x2860, 0x3584, 0x38fa, 0x372c, 0x3388, 0x3a3a, 0x3b9e, 0x2100, 0x3420, 0x395a, 0x3bae, 0x37d8, + 0x3398, 0x3b6c, 0x3734, 0x34d0, 0x39c0, 0x3b78, 0x3474, 0x3a2c, 0x2b80, 0x3830, 0x3b56, 0x2cb0, 0x3a78, 0x33b0, 0x3018, 0x3650, + 0x30d0, 0x3b20, 0x3690, 0x3350, 0x39ae, 0x3a90, 0x3148, 0x3b44, 0x2cd0, 0x38a0, 0x355c, 0x382a, 0x3a8e, 0x35b8, 0x3190, 0x39ec, + 0x38c4, 0x3068, 0x3938, 0x3b2e, 0x32c8, 0x3748, 0x3008, 0x3894, 0x3bb8, 0x3438, 0x36c8, 0x3904, 0x35fc, 0x396e, 0x3bac, 0x38a6, + 0x397a, 0x37ec, 0x2ca0, 0x3bea, 0x3754, 0x34a4, 0x3836, 0x3956, 0x362c, 0x3b00, 0x30c0, 0x39a6, 0x2fc0, 0x38ae, 0x3abe, 0x2080, + 0x3684, 0x3a70, 0x3568, 0x2000, 0x38c2, 0x3af0, 0x3998, 0x368c, 0x30b0, 0x39ba, 0x3aa8, 0x3200, 0x3b16, 0x2d80, 0x377c, 0x3480, + 0x3b6e, 0x3270, 0x39fa, 0x386a, 0x2ff0, 0x3b10, 0x1f00, 0x3a44, 0x343c, 0x3802, 0x3a66, 0x34b8, 0x3bec, 0x3708, 0x3340, 0x3882, + 0x3bee, 0x3298, 0x3806, 0x3a08, 0x3638, 0x2d00, 0x34ac, 0x3a60, 0x38ee, 0x35c8, 0x29c0, 0x380a, 0x34f0, 0x38f8, 0x3aac, 0x1e00, + 0x3564, 0x38fe, 0x3468, 0x3ace, 0x35d0, 0x394a, 0x37b4, 0x31f8, 0x3bf0, 0x2bc0, 0x38d0, 0x36b8, 0x2940, 0x3926, 0x3b32, 0x35a8, + 0x2d60, 0x38e0, 0x3b58, 0x3078, 0x3a9c, 0x37e4, 0x3bf2, 0x2e50, 0x33f0, 0x3b72, 0x38b4, 0x39e6, 0x3bf4, 0x3290, 0x3670, 0x3a1a, + 0x3842, 0x3a68, 0x2920, 0x37c4, 0x32b8, 0x3b88, 0x34c0, 0x396a, 0x3664, 0x39b6, 0x3330, 0x3b5e, 0x39ce, 0x3484, 0x3080, 0x39aa, + 0x3a4e, 0x3700, 0x34e8, 0x395e, 0x3310, 0x3908, 0x3588, 0x384e, 0x3ac6, 0x3730, 0x3220, 0x3574, 0x2de0, 0x37f0, 0x399c, 0x2ef0, + 0x3188, 0x369c, 0x3bf6, 0x390a, 0x39f2, 0x2b60, 0x3872, 0x3aa0, 0x2df0, 0x3b0c, 0x37cc, 0x2da0, 0x382c, 0x3ae0, 0x38b0, 0x3788, + 0x33c0, 0x3afa, 0x2ba0, 0x3826, 0x3b6a, 0x1d00, 0x39f8, 0x3108, 0x3920, 0x1c00, 0x3a26, 0x3b22, 0x38ec, 0x3ac2, 0x3458, 0x3b7c, + 0x3a8c, 0x38a8, 0x34d8, 0x3048, 0x3654, 0x3adc, 0x3138, 0x3744, 0x3450, 0x38be, 0x34f4, 0x3a10, 0x3210, 0x35bc, 0x2840, 0x3b92, + 0x3058, 0x3986, 0x3698, 0x39d8, 0x3434, 0x36f8, 0x3b18, 0x3524, 0x3a7a, 0x35d4, 0x3822, 0x3408, 0x36bc, 0x2ac0, 0x3896, 0x3624, + 0x1a00, 0x3378, 0x3a16, 0x3b3a, 0x381e, 0x3338, 0x3906, 0x39f6, 0x3bf8, 0x3158, 0x3ad2, 0x36e0, 0x3bfa, 0x392e, 0x3a5c, 0x3648, + 0x38dc, 0x34cc, 0x3bfc, 0x30c8, 0x3ab6, 0x3942, 0x32b0, 0x38a4, 0x2d10, 0x3b96, 0x394c, 0x2f80, 0x3bfe, 0x3966, 0x3258, 0x39be, + 0x3bb0, 0x3928, 0x361c, 0x2c00, 0x3990, 0x3b8c, 0x3578, 0x2a80, 0x36cc, 0x3952, 0x1800, 0x388e, 0x33e0, 0x2f20, 0x384c, 0x31d8, + 0x3a18, 0x1400, 0x3876, 0x358c, 0x383c, 0x2c20, 0x3b80, 0x3774, 0x3a36, 0x3470, 0x31f0, 0x3a0a, 0x3832, 0x3514, 0x3a6a, 0x37f4, + 0x367c, 0x3028, 0x3ac8, 0x37b8, 0x34a0, 0x2f50, 0x3a5e, 0x3874, 0x3b36, 0x34fc, 0x3a6e, 0x35f0, 0x399e, 0x3aba, 0x3500, 0x3b74, + 0x37c8, 0x3ac0, 0x398a, 0x3010, 0x3a7e, 0x3658, 0x38e4, 0x3030, 0x3608, 0x3860, 0x3af4, 0x3718, 0x29a0, 0x3b2c, 0x2eb0, 0x3424, + 0x3a0e, 0x3820, 0x32f8, 0x3954, 0x3afc, 0x38c0, 0x36a4, 0x3370, 0x2e70, 0x38b2, 0x3180, 0x3ba8, 0x2c80, 0x3778, 0x390c, 0x2cf0, + 0x35c0, 0x32e0, 0x36f4, 0x3b94, 0x3454, 0x39f4, 0x3348, 0x397e, 0x3b4e, 0x0000, 0x38fc, 0x34dc, 0x3a2a, 0x36a8, 0x393a, 0x3b54, +}; diff --git a/src/filters/renderer/VideoRenderers/Dither.h b/src/filters/renderer/VideoRenderers/Dither.h index 8cfef960f21..e6c961fff2f 100644 --- a/src/filters/renderer/VideoRenderers/Dither.h +++ b/src/filters/renderer/VideoRenderers/Dither.h @@ -1,24 +1,24 @@ -/* - * (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 . - * - */ - -#pragma once - -const int DITHER_MATRIX_SIZE = 32; -extern const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE]; +/* + * (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 . + * + */ + +#pragma once + +const int DITHER_MATRIX_SIZE = 32; +extern const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE]; diff --git a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp index 0df67bd07b9..7789bd8ba26 100644 --- a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp @@ -1,2996 +1,2996 @@ -/* - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "EVRAllocatorPresenter.h" -#include "OuterEVR.h" -#include -#include "IPinHook.h" -#include "MacrovisionKicker.h" -#include "IMPCVideoDecFilter.h" -#include "Utils.h" -#include "Variables.h" - -#if (0) // Set to 1 to activate EVR traces -#define TRACE_EVR TRACE -#else -#define TRACE_EVR __noop -#endif - -#define MIN_FRAME_TIME 15000 - -enum EVR_STATS_MSG { - MSG_MIXERIN, - MSG_MIXEROUT -}; - -// Guid to tag IMFSample with a group id -static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } }; -// Guid to tag IMFSample with DirectX surface index -static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } }; - - -// === Helper functions -MFOffset MakeOffset(float v) -{ - MFOffset offset; - offset.value = short(v); - offset.fract = WORD(65536 * (v - offset.value)); - return offset; -} - -MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height) -{ - MFVideoArea area; - area.OffsetX = MakeOffset(x); - area.OffsetY = MakeOffset(y); - area.Area.cx = width; - area.Area.cy = height; - return area; -} - -using namespace DSObjects; - -CEVRAllocatorPresenter::CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error, bool isPreview) - : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, true, _Error, isPreview) - , m_ModeratedTime(0) - , m_ModeratedTimeLast(-1) - , m_ModeratedClockLast(-1) - , m_ModeratedTimer(0) - , m_LastClockState(MFCLOCK_STATE_INVALID) - , m_pOuterEVR(nullptr) - , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture) - , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0) - , m_BorderColor(RGB(0, 0, 0)) - , m_hEvtQuit(nullptr) - , m_bEvtQuit(0) - , m_hEvtFlush(nullptr) - , m_bEvtFlush(0) - , m_fUseInternalTimer(false) - , m_LastSetOutputRange(-1) - , m_bPendingRenegotiate(false) - , m_bPendingMediaFinished(false) - , m_hThread(nullptr) - , m_hGetMixerThread(nullptr) - , m_hVSyncThread(nullptr) - , m_nRenderState(Shutdown) - , m_nCurrentGroupId(0) - , m_bLastSampleOffsetValid(false) - , m_LastScheduledSampleTime(-1) - , m_LastScheduledSampleTimeFP(-1) - , m_LastScheduledUncorrectedSampleTime(-1) - , m_MaxSampleDuration(0) - , m_LastSampleOffset(0) - , m_LastPredictedSync(0) - , m_VSyncOffsetHistoryPos(0) - , m_nResetToken(0) - , m_nStepCount(0) - , m_bSignaledStarvation(false) - , m_StarvationClock(0) - , m_SampleFreeCallback(this, &CEVRAllocatorPresenter::OnSampleFree) - , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9") - , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer") - , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface") - , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType") - , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW") - , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority") - , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics") -{ - const CRenderersSettings& r = GetRenderersSettings(); - - ZeroMemory(m_VSyncOffsetHistory, sizeof(m_VSyncOffsetHistory)); - ResetStats(); - - if (FAILED(hr)) { - _Error += L"DX9AllocatorPresenter failed\n"; - return; - } - - if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) { - if (!fnDXVA2CreateDirect3DDeviceManager9) { - _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n"; - } - if (!fnMFCreateDXSurfaceBuffer) { - _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n"; - } - if (!fnMFCreateVideoSampleFromSurface) { - _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n"; - } - if (!fnMFCreateMediaType) { - _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n"; - } - hr = E_FAIL; - return; - } - - // Init DXVA manager - hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager); - if (SUCCEEDED(hr) && m_pD3DManager) { - hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); - if (FAILED(hr)) { - _Error += L"m_pD3DManager->ResetDevice failed\n"; - } - } else { - _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n"; - } - - - // Bufferize frame only with 3D texture! - if (!m_bIsPreview && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { - m_nNbDXSurface = std::max(std::min(r.iEvrBuffers, MAX_VIDEO_SURFACES), 4); - } else { - m_nNbDXSurface = 1; - } -} - -CEVRAllocatorPresenter::~CEVRAllocatorPresenter() -{ - StopWorkerThreads(); // If not already done... - m_pMediaType = nullptr; - m_pClock = nullptr; - m_pD3DManager = nullptr; - - if (m_bHookedNewSegment) { - UnhookNewSegment(); - } -} - -void CEVRAllocatorPresenter::ResetStats() -{ - m_pcFrames = 0; - m_nDroppedUpdate = 0; - m_pcFramesDrawn = 0; - m_piAvg = 0; - m_piDev = 0; -} - -HRESULT CEVRAllocatorPresenter::CheckShutdown() const -{ - if (m_nRenderState == Shutdown) { - return MF_E_SHUTDOWN; - } else { - return S_OK; - } -} - -void CEVRAllocatorPresenter::StartWorkerThreads() -{ - DWORD dwThreadId; - - if (m_nRenderState == Shutdown) { - m_hEvtQuit = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hEvtFlush = CreateEvent(nullptr, TRUE, FALSE, nullptr); - - m_hThread = ::CreateThread(nullptr, 0, PresentThread, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL); - m_hGetMixerThread = ::CreateThread(nullptr, 0, GetMixerThreadStatic, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hGetMixerThread, THREAD_PRIORITY_HIGHEST); - m_hVSyncThread = ::CreateThread(nullptr, 0, VSyncThreadStatic, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hVSyncThread, THREAD_PRIORITY_HIGHEST); - - m_nRenderState = Stopped; - TRACE_EVR("EVR: Worker threads started...\n"); - } -} - -void CEVRAllocatorPresenter::StopWorkerThreads() -{ - if (m_nRenderState != Shutdown) { - SetEvent(m_hEvtFlush); - m_bEvtFlush = true; - SetEvent(m_hEvtQuit); - m_bEvtQuit = true; - if (m_hThread && WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hThread, 0xDEAD); - } - if (m_hGetMixerThread && WaitForSingleObject(m_hGetMixerThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hGetMixerThread, 0xDEAD); - } - if (m_hVSyncThread && WaitForSingleObject(m_hVSyncThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hVSyncThread, 0xDEAD); - } - - SAFE_CLOSE_HANDLE(m_hThread); - SAFE_CLOSE_HANDLE(m_hGetMixerThread); - SAFE_CLOSE_HANDLE(m_hVSyncThread); - SAFE_CLOSE_HANDLE(m_hEvtFlush); - SAFE_CLOSE_HANDLE(m_hEvtQuit); - - m_bEvtFlush = false; - m_bEvtQuit = false; - - TRACE_EVR("EVR: Worker threads stopped...\n"); - } - m_nRenderState = Shutdown; -} - -STDMETHODIMP CEVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - - *ppRenderer = nullptr; - HRESULT hr = S_OK; - - CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; - - COuterEVR* pOuterEVR = DEBUG_NEW COuterEVR(NAME("COuterEVR"), pUnk, hr, &m_VMR9AlphaBitmap, this); - m_pOuterEVR = pOuterEVR; - - pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR); - CComQIPtr pBF = pUnk; - - if (FAILED(hr)) { - return E_FAIL; - } - - // Set EVR custom presenter - CComPtr pVP; - CComPtr pMFVR; - CComQIPtr pMFGS = pBF; - CComQIPtr pConfig = pBF; - if (SUCCEEDED(hr)) { - if (FAILED(pConfig->SetNumberOfStreams(m_bIsPreview?1:3))) { // TODO - maybe need other number of input stream ... - return E_FAIL; - } - } - - hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVR)); - - if (SUCCEEDED(hr)) { - hr = QueryInterface(IID_PPV_ARGS(&pVP)); - } - if (SUCCEEDED(hr)) { - hr = pMFVR->InitializeRenderer(nullptr, pVP); - } - - if (SUCCEEDED(hr)) { - if (!m_bIsPreview) { - CComPtr pPin = GetFirstPin(pBF); - if (HookNewSegment((IPinC*)(IPin*)pPin)) { - m_fUseInternalTimer = true; - m_bHookedNewSegment = true; - }; - } - *ppRenderer = pBF.Detach(); - } else { - *ppRenderer = nullptr; - } - - return hr; -} - -STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(bool bAll) -{ - return __super::Paint(bAll); -} - -STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(IMFSample* pMFSample) -{ - CAutoLock lock(&m_RenderLock); - - m_pCurrentlyDisplayedSample = pMFSample; - pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface); - - auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { - UINT32 nGroupId; - return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); - }; - ASSERT(sampleHasCurrentGroupId(pMFSample)); - - return Paint(true); -} - -STDMETHODIMP CEVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - HRESULT hr; - if (riid == __uuidof(IMFClockStateSink)) { - hr = GetInterface((IMFClockStateSink*)this, ppv); - } else if (riid == __uuidof(IMFVideoPresenter)) { - hr = GetInterface((IMFVideoPresenter*)this, ppv); - } else if (riid == __uuidof(IMFTopologyServiceLookupClient)) { - hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv); - } else if (riid == __uuidof(IMFVideoDeviceID)) { - hr = GetInterface((IMFVideoDeviceID*)this, ppv); - } else if (riid == __uuidof(IMFGetService)) { - hr = GetInterface((IMFGetService*)this, ppv); - } else if (riid == __uuidof(IMFAsyncCallback)) { - hr = GetInterface((IMFAsyncCallback*)this, ppv); - } else if (riid == __uuidof(IMFVideoDisplayControl)) { - hr = GetInterface((IMFVideoDisplayControl*)this, ppv); - } else if (riid == __uuidof(IMFVideoMixerBitmap)) { - hr = GetInterface((IMFVideoMixerBitmap*)this, ppv); - } else if (riid == __uuidof(IEVRTrustedVideoPlugin)) { - hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv); - } else if (riid == IID_IQualProp) { - hr = GetInterface((IQualProp*)this, ppv); - } else if (riid == __uuidof(IMFRateSupport)) { - hr = GetInterface((IMFRateSupport*)this, ppv); - } else if (riid == __uuidof(IDirect3DDeviceManager9)) - // hr = GetInterface((IDirect3DDeviceManager9*)this, ppv); - { - hr = m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppv); - } else if (riid == __uuidof(ID3DFullscreenControl)) { - hr = GetInterface((ID3DFullscreenControl*)this, ppv); - } else { - hr = __super::NonDelegatingQueryInterface(riid, ppv); - } - - return hr; -} - -// IMFClockStateSink -STDMETHODIMP CEVRAllocatorPresenter::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - - m_nRenderState = Started; - - TRACE_EVR("EVR: OnClockStart hnsSystemTime = %I64d, llClockStartOffset = %I64d\n", hnsSystemTime, llClockStartOffset); - m_ModeratedTimeLast = -1; - m_ModeratedClockLast = -1; - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::OnClockStop(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - - TRACE_EVR("EVR: OnClockStop hnsSystemTime = %I64d\n", hnsSystemTime); - m_nRenderState = Stopped; - - m_ModeratedClockLast = -1; - m_ModeratedTimeLast = -1; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::OnClockPause(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - - TRACE_EVR("EVR: OnClockPause hnsSystemTime = %I64d\n", hnsSystemTime); - if (!m_bSignaledStarvation) { - m_nRenderState = Paused; - } - m_ModeratedTimeLast = -1; - m_ModeratedClockLast = -1; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::OnClockRestart(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - - m_nRenderState = Started; - - m_ModeratedTimeLast = -1; - m_ModeratedClockLast = -1; - TRACE_EVR("EVR: OnClockRestart hnsSystemTime = %I64d\n", hnsSystemTime); - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::OnClockSetRate(MFTIME hnsSystemTime, float flRate) -{ - ASSERT(FALSE); - return E_NOTIMPL; -} - -// IBaseFilter delegate -bool CEVRAllocatorPresenter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue) -{ - CAutoLock lock(&m_SampleQueueLock); - - if (m_bSignaledStarvation) { - size_t nSamples = std::max(m_nNbDXSurface / 2, 1); - if ((m_ScheduledSamples.GetCount() < nSamples || m_LastSampleOffset < -m_rtTimePerFrame * 2) && !g_bNoDuration) { - *State = (FILTER_STATE)Paused; - _ReturnValue = VFW_S_STATE_INTERMEDIATE; - return true; - } - m_bSignaledStarvation = false; - } - return false; -} - -// IQualProp -STDMETHODIMP CEVRAllocatorPresenter::get_FramesDroppedInRenderer(int* pcFrames) -{ - *pcFrames = m_pcFrames; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_FramesDrawn(int* pcFramesDrawn) -{ - *pcFramesDrawn = m_pcFramesDrawn; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_AvgFrameRate(int* piAvgFrameRate) -{ - *piAvgFrameRate = (int)(m_fAvrFps * 100); - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_Jitter(int* iJitter) -{ - *iJitter = (int)((m_fJitterStdDev / 10000.0) + 0.5); - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_AvgSyncOffset(int* piAvg) -{ - *piAvg = (int)((m_fSyncOffsetAvr / 10000.0) + 0.5); - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_DevSyncOffset(int* piDev) -{ - *piDev = (int)((m_fSyncOffsetStdDev / 10000.0) + 0.5); - return S_OK; -} - -// IMFRateSupport - -STDMETHODIMP CEVRAllocatorPresenter::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) -{ - // TODO : not finished... - *pflRate = 0; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) -{ - HRESULT hr = S_OK; - float fMaxRate = 0.0f; - - CAutoLock lock(this); - - CheckPointer(pflRate, E_POINTER); - CHECK_HR(CheckShutdown()); - - // Get the maximum forward rate. - fMaxRate = GetMaxRate(fThin); - - // For reverse playback, swap the sign. - if (eDirection == MFRATE_REVERSE) { - fMaxRate = -fMaxRate; - } - - *pflRate = fMaxRate; - - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate) -{ - // fRate can be negative for reverse playback. - // pfNearestSupportedRate can be NULL. - - CAutoLock lock(this); - - HRESULT hr = S_OK; - float fMaxRate = 0.0f; - float fNearestRate = flRate; // Default. - - CheckPointer(pflNearestSupportedRate, E_POINTER); - CHECK_HR(CheckShutdown()); - - // Find the maximum forward rate. - fMaxRate = GetMaxRate(fThin); - - if (fabsf(flRate) > fMaxRate) { - // The (absolute) requested rate exceeds the maximum rate. - hr = MF_E_UNSUPPORTED_RATE; - - // The nearest supported rate is fMaxRate. - fNearestRate = fMaxRate; - if (flRate < 0) { - // For reverse playback, swap the sign. - fNearestRate = -fNearestRate; - } - } - - // Return the nearest supported rate if the caller requested it. - if (pflNearestSupportedRate != nullptr) { - *pflNearestSupportedRate = fNearestRate; - } - - return hr; -} - -float CEVRAllocatorPresenter::GetMaxRate(BOOL bThin) -{ - float fMaxRate = FLT_MAX; // Default. - UINT32 fpsNumerator = 0, fpsDenominator = 0; - - if (!bThin && (m_pMediaType != nullptr)) { - // Non-thinned: Use the frame rate and monitor refresh rate. - - // Frame rate: - MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE, - &fpsNumerator, &fpsDenominator); - - // Monitor refresh rate: - UINT MonitorRateHz = m_refreshRate; // D3DDISPLAYMODE - - if (fpsDenominator && fpsNumerator && MonitorRateHz) { - // Max Rate = Refresh Rate / Frame Rate - fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator); - } - } - return fMaxRate; -} - -void CEVRAllocatorPresenter::CompleteFrameStep(bool bCancel) -{ - if (m_nStepCount > 0) { - if (bCancel || (m_nStepCount == 1)) { - m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0); - m_nStepCount = 0; - } else { - m_nStepCount--; - } - } -} - -// IMFVideoPresenter -STDMETHODIMP CEVRAllocatorPresenter::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) -{ - HRESULT hr = S_OK; - CHECK_HR(CheckShutdown()); - - switch (eMessage) { - case MFVP_MESSAGE_BEGINSTREAMING: // The EVR switched from stopped to paused. The presenter should allocate resources - m_nRenderState = Paused; - ResetStats(); - TRACE_EVR("EVR: MFVP_MESSAGE_BEGINSTREAMING\n"); - break; - - case MFVP_MESSAGE_CANCELSTEP: // Cancels a frame step - TRACE_EVR("EVR: MFVP_MESSAGE_CANCELSTEP\n"); - CompleteFrameStep(true); - break; - - case MFVP_MESSAGE_ENDOFSTREAM: // All input streams have ended. - TRACE_EVR("EVR: MFVP_MESSAGE_ENDOFSTREAM\n"); - m_bPendingMediaFinished = true; - break; - - case MFVP_MESSAGE_ENDSTREAMING: // The EVR switched from running or paused to stopped. The presenter should free resources - m_nRenderState = Stopped; - TRACE_EVR("EVR: MFVP_MESSAGE_ENDSTREAMING\n"); - break; - - case MFVP_MESSAGE_FLUSH: // The presenter should discard any pending samples - SetEvent(m_hEvtFlush); - m_bEvtFlush = true; - TRACE_EVR("EVR: MFVP_MESSAGE_FLUSH\n"); - while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0) { - ; - } - break; - - case MFVP_MESSAGE_INVALIDATEMEDIATYPE: // The mixer's output format has changed. The EVR will initiate format negotiation, as described previously - /* - 1) The EVR sets the media type on the reference stream. - 2) The EVR calls IMFVideoPresenter::ProcessMessage on the presenter with the MFVP_MESSAGE_INVALIDATEMEDIATYPE message. - 3) The presenter sets the media type on the mixer's output stream. - 4) The EVR sets the media type on the substreams. - */ - m_bPendingRenegotiate = true; - while (m_bPendingRenegotiate) { - Sleep(1); - } - break; - - case MFVP_MESSAGE_PROCESSINPUTNOTIFY: // One input stream on the mixer has received a new sample - // GetImageFromMixer(); - break; - - case MFVP_MESSAGE_STEP: // Requests a frame step. - TRACE_EVR("EVR: MFVP_MESSAGE_STEP\n"); - m_nStepCount = (int)ulParam; - hr = S_OK; - break; - - default: - ASSERT(FALSE); - break; - } - return hr; -} - -HRESULT CEVRAllocatorPresenter::IsMediaTypeSupported(IMFMediaType* pMixerType) -{ - HRESULT hr; - - // We support only video types - GUID MajorType; - hr = pMixerType->GetMajorType(&MajorType); - - if (SUCCEEDED(hr)) { - if (MajorType != MFMediaType_Video) { - hr = MF_E_INVALIDMEDIATYPE; - } - } - - // We support only progressive formats - MFVideoInterlaceMode InterlaceMode = MFVideoInterlace_Unknown; - - if (SUCCEEDED(hr)) { - hr = pMixerType->GetUINT32(MF_MT_INTERLACE_MODE, (UINT32*)&InterlaceMode); - } - - if (SUCCEEDED(hr)) { - if (InterlaceMode != MFVideoInterlace_Progressive) { - hr = MF_E_INVALIDMEDIATYPE; - } - } - - // Check whether we support the surface format - int Merit = 0; - - if (SUCCEEDED(hr)) { - hr = GetMediaTypeMerit(pMixerType, &Merit); - } - - if (SUCCEEDED(hr)) { - if (Merit == 0) { - hr = MF_E_INVALIDMEDIATYPE; - } - } - - return hr; -} - -HRESULT CEVRAllocatorPresenter::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType) -{ - HRESULT hr; - IMFMediaType* pOptimalMediaType; - - CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType)); - CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType)); - - const GUID colorAttributes[] = { - MF_MT_VIDEO_LIGHTING, - MF_MT_VIDEO_PRIMARIES, - MF_MT_TRANSFER_FUNCTION, - MF_MT_YUV_MATRIX, - MF_MT_VIDEO_CHROMA_SITING - }; - - auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) { - PROPVARIANT val; - HRESULT hr = pFrom->GetItem(guidKey, &val); - - if (SUCCEEDED(hr)) { - hr = pTo->SetItem(guidKey, val); - PropVariantClear(&val); - } else if (hr == MF_E_ATTRIBUTENOTFOUND) { - hr = pTo->DeleteItem(guidKey); - } - return hr; - }; - - for (REFGUID guidKey : colorAttributes) { - if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) { - TRACE_EVR(_T("Copying color attribute %s failed: 0x%08x\n"), CComBSTR(guidKey), hr); - } - } - - pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0); - - const CRenderersSettings& r = GetRenderersSettings(); - - UINT32 nominalRange; - if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)) - && nominalRange == MFNominalRange_0_255) { - // EVR mixer always assumes 16-235 input. Bug? - // To keep untouched 0-255 range and avoid unwanted expansion we need to request 16-235 as output. - // To get 16-235 output we need to request 48-208 as output. - nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_48_208 : MFNominalRange_16_235; - } else { - nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255; - } - pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange); - m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange; - - ULARGE_INTEGER ui64Size; - pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart); - - CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart); - MFVideoArea Area = MakeArea(0, 0, videoSize.cx, videoSize.cy); - pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea)); - - ULARGE_INTEGER ui64AspectRatio; - pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart); - - UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart; - UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart; - UINT64 gcd = GCD(ui64ARx, ui64ARy); - if (gcd > 1) { - ui64ARx /= gcd; - ui64ARy /= gcd; - } - - CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy); - if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) { - SetVideoSize(videoSize, aspectRatio); - - // Notify the graph about the change - if (m_pSink) { - m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_nativeVideoSize.cx, m_nativeVideoSize.cy), 0); - } - } - - *ppType = pOptimalMediaType; - (*ppType)->AddRef(); - - return hr; -} - -HRESULT CEVRAllocatorPresenter::SetMediaType(IMFMediaType* pType) -{ - HRESULT hr = S_OK; - AM_MEDIA_TYPE* pAMMedia = nullptr; - - CHECK_HR(CheckShutdown()); - - if (!pType) { - // Release - RemoveAllSamples(); - DeleteSurfaces(); - CAutoLock lock(&m_MediaTypeLock); - m_pMediaType = nullptr; - return hr; - } - - DWORD dwFlags = 0; - if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) { - // Nothing to do - return hr; - } - - CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); - - hr = InitializeDevice(pType); - if (SUCCEEDED(hr)) { - CAutoLock lock(&m_MediaTypeLock); - m_pMediaType = pType; - - CString strTemp = GetMediaTypeName(pAMMedia->subtype); - strTemp.Replace(L"MEDIASUBTYPE_", L""); - CString strTemp1 = GetMediaTypeFormatDesc(pType); - strTemp1.Replace(L"D3DFMT_", L""); - m_strStatsMsg[MSG_MIXEROUT].Format(L"Mixer output : %-10s Type %-10s", strTemp.GetString(), strTemp1.GetString()); - } - - pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); - - return hr; -} - -HRESULT CEVRAllocatorPresenter::GetMediaTypeFourCC(IMFMediaType* pType, DWORD* pFourCC) -{ - CheckPointer(pFourCC, E_POINTER); - - HRESULT hr = S_OK; - GUID guidSubType = GUID_NULL; - - if (SUCCEEDED(hr)) { - hr = pType->GetGUID(MF_MT_SUBTYPE, &guidSubType); - } - - if (SUCCEEDED(hr)) { - *pFourCC = guidSubType.Data1; - } - - return hr; -} - -HRESULT CEVRAllocatorPresenter::GetMediaTypeMerit(IMFMediaType* pType, int* pMerit) -{ - DWORD Format; - HRESULT hr = GetMediaTypeFourCC(pType, &Format); - - if (SUCCEEDED(hr)) { - switch (Format) { - case FCC('AI44'): // Palettized, 4:4:4 - *pMerit = 31; - break; - case FCC('YVU9'): // 8-bit, 16:1:1 - *pMerit = 30; - break; - case FCC('NV11'): // 8-bit, 4:1:1 - *pMerit = 29; - break; - case FCC('Y41P'): - *pMerit = 28; - break; - case FCC('Y41T'): - *pMerit = 27; - break; - case FCC('P016'): // 4:2:0 - *pMerit = 26; - break; - case FCC('P010'): - *pMerit = 25; - break; - case FCC('IMC1'): - *pMerit = 24; - break; - case FCC('IMC3'): - *pMerit = 23; - break; - case FCC('IMC2'): - *pMerit = 22; - break; - case FCC('IMC4'): - *pMerit = 21; - break; - case FCC('YV12'): - *pMerit = 20; - break; - case FCC('NV12'): - *pMerit = 19; - break; - case FCC('I420'): - *pMerit = 18; - break; - case FCC('IYUV'): - *pMerit = 17; - break; - case FCC('Y216'): // 4:2:2 - *pMerit = 16; - break; - case FCC('v216'): - *pMerit = 15; - break; - case FCC('P216'): - *pMerit = 14; - break; - case FCC('Y210'): - *pMerit = 13; - break; - case FCC('v210'): - *pMerit = 12; - break; - case FCC('P210'): - *pMerit = 11; - break; - case FCC('YUY2'): - *pMerit = 10; - break; - case FCC('UYVY'): - *pMerit = 9; - break; - case FCC('Y42T'): - *pMerit = 8; - break; - case FCC('YVYU'): - *pMerit = 7; - break; - case FCC('Y416'): // 4:4:4 - *pMerit = 6; - break; - case FCC('Y410'): - *pMerit = 5; - break; - case FCC('v410'): - *pMerit = 4; - break; - case FCC('AYUV'): - *pMerit = 3; - break; - case D3DFMT_X8R8G8B8: - if (m_bForceInputHighColorResolution) { - *pMerit = 63; - } else { - *pMerit = 1; - } - break; - case D3DFMT_A8R8G8B8: // an accepted format, but fails on most surface types - case D3DFMT_A8B8G8R8: - case D3DFMT_X8B8G8R8: - case D3DFMT_R8G8B8: - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: - case D3DFMT_A1R5G5B5: - case D3DFMT_A4R4G4B4: - case D3DFMT_R3G3B2: - case D3DFMT_A8R3G3B2: - case D3DFMT_X4R4G4B4: - case D3DFMT_A8P8: - case D3DFMT_P8: - *pMerit = 0; - break; - default: - *pMerit = 2; - break; - } - } - - return hr; -} - -LPCTSTR FindD3DFormat(const D3DFORMAT Format); - -LPCTSTR CEVRAllocatorPresenter::GetMediaTypeFormatDesc(IMFMediaType* pMediaType) -{ - D3DFORMAT Format = D3DFMT_UNKNOWN; - GetMediaTypeFourCC(pMediaType, (DWORD*)&Format); - return FindD3DFormat(Format); -} - -HRESULT CEVRAllocatorPresenter::RenegotiateMediaType() -{ - HRESULT hr = S_OK; - - CComPtr pMixerType; - CComPtr pMixerInputType; - CComPtr pType; - - if (!m_pMixer) { - return MF_E_INVALIDREQUEST; - } - - CInterfaceArray ValidMixerTypes; - - // Get the mixer's input type - hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType); - if (SUCCEEDED(hr)) { - AM_MEDIA_TYPE* pMT; - hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT); - if (SUCCEEDED(hr)) { - m_inputMediaType = *pMT; - pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT); - } - } - - // Loop through all of the mixer's proposed output types. - DWORD iTypeIndex = 0; - while ((hr != MF_E_NO_MORE_TYPES)) { - pMixerType = nullptr; - pType = nullptr; - - // Step 1. Get the next media type supported by mixer. - hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType); - if (FAILED(hr)) { - break; - } - - // Step 2. Check if we support this media type. - if (SUCCEEDED(hr)) { - hr = IsMediaTypeSupported(pMixerType); - } - - if (SUCCEEDED(hr)) { - hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType); - } - - // Step 4. Check if the mixer will accept this media type. - if (SUCCEEDED(hr)) { - hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY); - } - - int Merit = 0; - if (SUCCEEDED(hr)) { - hr = GetMediaTypeMerit(pType, &Merit); - } - - if (SUCCEEDED(hr)) { - size_t nTypes = ValidMixerTypes.GetCount(); - size_t iInsertPos = 0; - for (size_t i = 0; i < nTypes; ++i) { - int ThisMerit; - GetMediaTypeMerit(ValidMixerTypes[i], &ThisMerit); - - if (Merit > ThisMerit) { - iInsertPos = i; - break; - } else { - iInsertPos = i + 1; - } - } - - ValidMixerTypes.InsertAt(iInsertPos, pType); - } - } - - - size_t nValidTypes = ValidMixerTypes.GetCount(); -#ifdef _DEBUG - for (size_t i = 0; i < nValidTypes; ++i) { - // Step 3. Adjust the mixer's type to match our requirements. - pType = ValidMixerTypes[i]; - TRACE_EVR("EVR: Valid mixer output type: %ws\n", GetMediaTypeFormatDesc(pType)); - } -#endif - for (size_t i = 0; i < nValidTypes; ++i) { - // Step 4. Adjust the mixer's type to match our requirements. - pType = ValidMixerTypes[i]; - - TRACE_EVR("EVR: Trying mixer output type: %ws\n", GetMediaTypeFormatDesc(pType)); - - // Step 5. Try to set the media type on ourselves. - hr = SetMediaType(pType); - - // Step 6. Set output media type on mixer. - if (SUCCEEDED(hr)) { - hr = m_pMixer->SetOutputType(0, pType, 0); - - // If something went wrong, clear the media type. - if (FAILED(hr)) { - SetMediaType(nullptr); - } else { - break; - } - } - } - - pMixerType = nullptr; - pType = nullptr; - return hr; -} - -bool CEVRAllocatorPresenter::GetImageFromMixer() -{ - MFT_OUTPUT_DATA_BUFFER dataBuffer; - HRESULT hr = S_OK; - DWORD dwStatus; - REFERENCE_TIME nsSampleTime; - LONGLONG llClockBefore = 0; - LONGLONG llClockAfter = 0; - LONGLONG llMixerLatency; - UINT dwSurface; - - bool bDoneSomething = false; - - auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { - UINT32 nGroupId; - return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); - }; - - while (SUCCEEDED(hr)) { - CComPtr pSample; - - if (FAILED(GetFreeSample(&pSample))) { - break; - } - - ZeroMemory(&dataBuffer, sizeof(dataBuffer)); - dataBuffer.pSample = pSample; - pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface); - ASSERT(sampleHasCurrentGroupId(pSample)); - - { - llClockBefore = GetRenderersData()->GetPerfCounter(); - if (!m_pMixer) { - ASSERT(FALSE); - break; - } - hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus); - llClockAfter = GetRenderersData()->GetPerfCounter(); - } - - if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { - AddToFreeList(pSample, false); - pSample = nullptr; // The sample should not be used after being queued - // Important: Release any events returned from the ProcessOutput method. - SAFE_RELEASE(dataBuffer.pEvents); - break; - } - - if (m_pSink) { - //CAutoLock autolock(this); We shouldn't need to lock here, m_pSink is thread safe - llMixerLatency = llClockAfter - llClockBefore; - m_pSink->Notify(EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0); - } - - pSample->GetSampleTime(&nsSampleTime); - REFERENCE_TIME nsDuration; - pSample->GetSampleDuration(&nsDuration); - - if (GetRenderersData()->m_bTearingTest) { - RECT rcTearing; - - rcTearing.left = m_nTearingPos; - rcTearing.top = 0; - rcTearing.right = rcTearing.left + 4; - rcTearing.bottom = m_nativeVideoSize.cy; - m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - - rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; - rcTearing.right = rcTearing.left + 4; - m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; - } - - TRACE_EVR("EVR: Get from Mixer : %u (%I64d) (%I64d)\n", dwSurface, nsSampleTime, m_rtTimePerFrame ? nsSampleTime / m_rtTimePerFrame : 0); - - if (SUCCEEDED(TrackSample(pSample))) { - AddToScheduledList(pSample, false); - pSample = nullptr; // The sample should not be used after being queued - bDoneSomething = true; - } else { - ASSERT(FALSE); - } - - // Important: Release any events returned from the ProcessOutput method. - SAFE_RELEASE(dataBuffer.pEvents); - - if (m_rtTimePerFrame == 0) { - break; - } - } - - return bDoneSomething; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType) -{ - HRESULT hr = S_OK; - CAutoLock lock(&m_MediaTypeLock); - - CheckPointer(ppMediaType, E_POINTER); - CHECK_HR(CheckShutdown()); - - if (!m_pMediaType) { - return MF_E_NOT_INITIALIZED; - } - - CHECK_HR(m_pMediaType->QueryInterface(IID_PPV_ARGS(ppMediaType))); - - return hr; -} - -// IMFTopologyServiceLookupClient -STDMETHODIMP CEVRAllocatorPresenter::InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup) -{ - HRESULT hr = S_OK; - DWORD dwObjects = 1; - - CAutoLock cThreadsLock(&m_ThreadsLock); - - TRACE_EVR("EVR: CEVRAllocatorPresenter::InitServicePointers\n"); - CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, - IID_PPV_ARGS(&m_pMixer), &dwObjects)); - - CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, - IID_PPV_ARGS(&m_pSink), &dwObjects)); - - pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, - IID_PPV_ARGS(&m_pClock), &dwObjects); - - - StartWorkerThreads(); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::ReleaseServicePointers() -{ - TRACE_EVR("EVR: CEVRAllocatorPresenter::ReleaseServicePointers\n"); - CAutoLock cThreadsLock(&m_ThreadsLock); - - StopWorkerThreads(); - - m_pMixer.Release(); - m_pSink.Release(); - m_pClock.Release(); - return S_OK; -} - -// IMFVideoDeviceID -STDMETHODIMP CEVRAllocatorPresenter::GetDeviceID(/* [out] */ __out IID* pDeviceID) -{ - CheckPointer(pDeviceID, E_POINTER); - *pDeviceID = IID_IDirect3DDevice9; - return S_OK; -} - -// IMFGetService -STDMETHODIMP CEVRAllocatorPresenter::GetService(/* [in] */ __RPC__in REFGUID guidService, - /* [in] */ __RPC__in REFIID riid, - /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject) -{ - if (guidService == MR_VIDEO_RENDER_SERVICE) { - return NonDelegatingQueryInterface(riid, ppvObject); - } else if (guidService == MR_VIDEO_ACCELERATION_SERVICE) { - return m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppvObject); - } - - return E_NOINTERFACE; -} - -// IMFAsyncCallback -STDMETHODIMP CEVRAllocatorPresenter::GetParameters(/* [out] */ __RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CEVRAllocatorPresenter::Invoke(/* [in] */ __RPC__in_opt IMFAsyncResult* pAsyncResult) -{ - return E_NOTIMPL; -} - -// IMFVideoDisplayControl -STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) -{ - if (pszVideo) { - pszVideo->cx = m_nativeVideoSize.cx; - pszVideo->cy = m_nativeVideoSize.cy; - } - if (pszARVideo) { - pszARVideo->cx = m_aspectRatio.cx; - pszARVideo->cy = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) -{ - if (pszMin) { - pszMin->cx = 1; - pszMin->cy = 1; - } - - if (pszMax) { - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - - if (SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D), &d3ddm))) { - pszMax->cx = d3ddm.Width; - pszMax->cy = d3ddm.Height; - } - } - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) -{ - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) -{ - // Always all source rectangle ? - if (pnrcSource) { - pnrcSource->left = 0.0; - pnrcSource->top = 0.0; - pnrcSource->right = 1.0; - pnrcSource->bottom = 1.0; - } - - if (prcDest) { - memcpy(prcDest, &m_videoRect, sizeof(m_videoRect)); //GetClientRect (m_hWnd, prcDest); - } - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetAspectRatioMode(DWORD dwAspectRatioMode) -{ - m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetAspectRatioMode(DWORD* pdwAspectRatioMode) -{ - CheckPointer(pdwAspectRatioMode, E_POINTER); - *pdwAspectRatioMode = m_dwVideoAspectRatioMode; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetVideoWindow(HWND hwndVideo) -{ - if (m_hWnd != hwndVideo) { - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_RenderLock); - - m_hWnd = hwndVideo; - m_bPendingResetDevice = true; - if (m_pSink) { - m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); - } - SendResetRequest(); - } - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetVideoWindow(HWND* phwndVideo) -{ - CheckPointer(phwndVideo, E_POINTER); - *phwndVideo = m_hWnd; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::RepaintVideo() -{ - Paint(true); - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetCurrentImage(BITMAPINFOHEADER *pBih, BYTE **pDib, DWORD *pcbDib, LONGLONG *pTimeStamp) -{ - if (!pBih || !pDib || !pcbDib) { - return E_POINTER; - } - CheckPointer(m_pD3DDevEx, E_ABORT); - - HRESULT hr = S_OK; - const unsigned width = m_windowRect.Width(); - const unsigned height = m_windowRect.Height(); - const unsigned len = width * height * 4; - - memset(pBih, 0, sizeof(BITMAPINFOHEADER)); - pBih->biSize = sizeof(BITMAPINFOHEADER); - pBih->biWidth = width; - pBih->biHeight = height; - pBih->biBitCount = 32; - pBih->biPlanes = 1; - pBih->biSizeImage = DIBSIZE(*pBih); - - BYTE* p = (BYTE*)CoTaskMemAlloc(len); // only this allocator can be used - if (!p) { - return E_OUTOFMEMORY; - } - - CComPtr pBackBuffer; - CComPtr pDestSurface; - D3DLOCKED_RECT r; - if (FAILED(hr = m_pD3DDevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)) - || FAILED(hr = m_pD3DDevEx->CreateRenderTarget(width, height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pDestSurface, nullptr)) - || (FAILED(hr = m_pD3DDevEx->StretchRect(pBackBuffer, m_windowRect, pDestSurface, nullptr, D3DTEXF_NONE))) - || (FAILED(hr = pDestSurface->LockRect(&r, nullptr, D3DLOCK_READONLY)))) { - CString Error = GetWindowsErrorMessage(hr, nullptr); - TRACE_EVR(L"CEVRAllocatorPresenter::GetCurrentImage failed : %s", S_OK == hr ? L"S_OK" : Error.GetBuffer()); - CoTaskMemFree(p); - return hr; - } - - RetrieveBitmapData(width, height, 32, p, (BYTE*)r.pBits, r.Pitch); - - pDestSurface->UnlockRect(); - - *pDib = p; - *pcbDib = len; - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetBorderColor(COLORREF Clr) -{ - m_BorderColor = Clr; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetBorderColor(COLORREF* pClr) -{ - CheckPointer(pClr, E_POINTER); - *pClr = m_BorderColor; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetRenderingPrefs(DWORD dwRenderFlags) -{ - m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetRenderingPrefs(DWORD* pdwRenderFlags) -{ - CheckPointer(pdwRenderFlags, E_POINTER); - *pdwRenderFlags = m_dwVideoRenderPrefs; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetFullscreen(BOOL fFullscreen) -{ - m_bIsFullscreen = !!fFullscreen; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetFullscreen(BOOL* pfFullscreen) -{ - CheckPointer(pfFullscreen, E_POINTER); - *pfFullscreen = m_bIsFullscreen; - return S_OK; -} - -// IMFVideoMixerBitmap -STDMETHODIMP CEVRAllocatorPresenter::ClearAlphaBitmap() -{ - CAutoLock cRenderLock(&m_RenderLock); - m_bAlphaBitmapEnable = false; - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetAlphaBitmapParameters(MFVideoAlphaBitmapParams *pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock cRenderLock(&m_RenderLock); - - if (m_bAlphaBitmapEnable && m_pAlphaBitmapTexture) { - *pBmpParms = m_AlphaBitmapParams; // formal implementation, don't believe it - return S_OK; - } else { - return MF_E_NOT_INITIALIZED; - } -} - -STDMETHODIMP CEVRAllocatorPresenter::SetAlphaBitmap(const MFVideoAlphaBitmap *pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock cRenderLock(&m_RenderLock); - - CheckPointer(m_pD3DDevEx, E_ABORT); - HRESULT hr = S_OK; - - if (pBmpParms->GetBitmapFromDC && pBmpParms->bitmap.hdc) { - HBITMAP hBitmap = (HBITMAP)GetCurrentObject(pBmpParms->bitmap.hdc, OBJ_BITMAP); - if (!hBitmap) { - return E_INVALIDARG; - } - DIBSECTION info = { 0 }; - if (!::GetObjectW(hBitmap, sizeof(DIBSECTION), &info)) { - return E_INVALIDARG; - } - BITMAP& bm = info.dsBm; - if (!bm.bmWidth || !bm.bmHeight || bm.bmBitsPixel != 32 || !bm.bmBits) { - return E_INVALIDARG; - } - - if (m_pAlphaBitmapTexture) { - D3DSURFACE_DESC desc = {}; - m_pAlphaBitmapTexture->GetLevelDesc(0, &desc); - if (bm.bmWidth != desc.Width || bm.bmHeight != desc.Height) { - m_pAlphaBitmapTexture.Release(); - } - } - - if (!m_pAlphaBitmapTexture) { - hr = m_pD3DDevEx->CreateTexture(bm.bmWidth, bm.bmHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pAlphaBitmapTexture, nullptr); - } - - if (SUCCEEDED(hr)) { - CComPtr pSurface; - hr = m_pAlphaBitmapTexture->GetSurfaceLevel(0, &pSurface); - if (SUCCEEDED(hr)) { - D3DLOCKED_RECT lr; - hr = pSurface->LockRect(&lr, nullptr, D3DLOCK_DISCARD); - if (S_OK == hr) { - if (bm.bmWidthBytes == lr.Pitch) { - memcpy(lr.pBits, bm.bmBits, bm.bmWidthBytes * bm.bmHeight); - } - else { - LONG linesize = std::min(bm.bmWidthBytes, (LONG)lr.Pitch); - BYTE* src = (BYTE*)bm.bmBits; - BYTE* dst = (BYTE*)lr.pBits; - for (LONG y = 0; y < bm.bmHeight; ++y) { - memcpy(dst, src, linesize); - src += bm.bmWidthBytes; - dst += lr.Pitch; - } - } - hr = pSurface->UnlockRect(); - } - } - } - } else { - return E_INVALIDARG; - } - - m_bAlphaBitmapEnable = SUCCEEDED(hr) && m_pAlphaBitmapTexture; - - if (m_bAlphaBitmapEnable) { - hr = UpdateAlphaBitmapParameters(&pBmpParms->params); - } - - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams *pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock cRenderLock(&m_RenderLock); - - m_AlphaBitmapParams = *pBmpParms; // formal implementation, don't believe it - - return S_OK; -} - -// IEVRTrustedVideoPlugin -STDMETHODIMP CEVRAllocatorPresenter::IsInTrustedVideoMode(BOOL* pYes) -{ - CheckPointer(pYes, E_POINTER); - *pYes = TRUE; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::CanConstrict(BOOL* pYes) -{ - CheckPointer(pYes, E_POINTER); - *pYes = TRUE; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetConstriction(DWORD dwKPix) -{ - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::DisableImageExport(BOOL bDisable) -{ - return S_OK; -} - - -// IDirect3DDeviceManager9 -STDMETHODIMP CEVRAllocatorPresenter::ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken) -{ - HRESULT hr = m_pD3DManager->ResetDevice(pDevice, resetToken); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::OpenDeviceHandle(HANDLE* phDevice) -{ - HRESULT hr = m_pD3DManager->OpenDeviceHandle(phDevice); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::CloseDeviceHandle(HANDLE hDevice) -{ - HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::TestDevice(HANDLE hDevice) -{ - HRESULT hr = m_pD3DManager->TestDevice(hDevice); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock) -{ - HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::UnlockDevice(HANDLE hDevice, BOOL fSaveState) -{ - HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetVideoService(HANDLE hDevice, REFIID riid, void** ppService) -{ - HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService); - - if (riid == __uuidof(IDirectXVideoDecoderService)) { - UINT nNbDecoder = 5; - GUID* pDecoderGuid; - IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService; - pDXVAVideoDecoder->GetDecoderDeviceGuids(&nNbDecoder, &pDecoderGuid); - } else if (riid == __uuidof(IDirectXVideoProcessorService)) { - IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService; - UNREFERENCED_PARAMETER(pDXVAProcessor); - } - - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) -{ - // This function should be called... - ASSERT(FALSE); - - if (lpWidth) { - *lpWidth = m_nativeVideoSize.cx; - } - if (lpHeight) { - *lpHeight = m_nativeVideoSize.cy; - } - if (lpARWidth) { - *lpARWidth = m_aspectRatio.cx; - } - if (lpARHeight) { - *lpARHeight = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::InitializeDevice(IMFMediaType* pMediaType) -{ - HRESULT hr; - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_RenderLock); - - RemoveAllSamples(); - DeleteSurfaces(); - - // Retrieve the surface size and format - UINT32 Width; - UINT32 Height; - hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &Width, &Height); - - D3DFORMAT Format; - if (SUCCEEDED(hr)) { - SetVideoSize(CSize(Width, Height), m_aspectRatio); - hr = GetMediaTypeFourCC(pMediaType, (DWORD*)&Format); - } - - if (SUCCEEDED(hr)) { - hr = AllocSurfaces(); - } - - if (SUCCEEDED(hr)) { - for (int i = 0; i < m_nNbDXSurface; i++) { - CComPtr pMFSample; - hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); - - if (SUCCEEDED(hr)) { - pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); - pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - m_FreeSamples.AddTail(pMFSample); - pMFSample = nullptr; // The sample should not be used after being queued - } - ASSERT(SUCCEEDED(hr)); - } - } - - return hr; -} - -DWORD WINAPI CEVRAllocatorPresenter::GetMixerThreadStatic(LPVOID lpParam) -{ - SetThreadName(DWORD(-1), "CEVRPresenter::MixerThread"); - CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; - pThis->GetMixerThread(); - return 0; -} - -DWORD WINAPI CEVRAllocatorPresenter::PresentThread(LPVOID lpParam) -{ - SetThreadName(DWORD(-1), "CEVRPresenter::PresentThread"); - CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; - pThis->RenderThread(); - return 0; -} - -bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt) -{ - if (pmt->formattype == FORMAT_VideoInfo) { - return false; - } else if (pmt->formattype == FORMAT_VideoInfo2) { - return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; - } else if (pmt->formattype == FORMAT_MPEGVideo) { - return false; - } else if (pmt->formattype == FORMAT_MPEG2Video) { - return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; - } else { - return false; - } -} - -void CEVRAllocatorPresenter::GetMixerThread() -{ - HANDLE hEvts[] = { m_hEvtQuit}; - bool bQuit = false; - TIMECAPS tc; - DWORD dwResolution; - - // Tell Multimedia Class Scheduler we are a playback thread (increase priority) - //HANDLE hAvrt = 0; - //if (pfAvSetMmThreadCharacteristicsW) { - // DWORD dwTaskIndex = 0; - // hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); - // if (pfAvSetMmThreadPriority) { - // pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); - // } - //} - - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - timeBeginPeriod(dwResolution); - - while (!bQuit) { - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); - switch (dwObject) { - case WAIT_OBJECT_0: - bQuit = true; - break; - case WAIT_TIMEOUT: { - bool bDoneSomething = false; - { - CAutoLock AutoLock(&m_ImageProcessingLock); - bDoneSomething = GetImageFromMixer(); - } - if (m_rtTimePerFrame == 0 && bDoneSomething) { - //CAutoLock lock(this); - //CAutoLock lock2(&m_ImageProcessingLock); - //CAutoLock cRenderLock(&m_RenderLock); - - // Use the code from VMR9 to get the movie fps, as this method is reliable. - CComPtr pPin; - CMediaType mt; - if ( - SUCCEEDED(m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) && - SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); - - m_bInterlaced = ExtractInterlaced(&mt); - - CComPtr pPinTo; - if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { - m_Decoder = GetFilterName(GetFilterFromPin(pPinTo)); - } - } - // If framerate not set by Video Decoder choose 23.97... - if (m_rtTimePerFrame == 0) { - m_rtTimePerFrame = 417166; - } - - // Update internal subtitle clock - if (m_fUseInternalTimer && m_pSubPicQueue) { - m_fps = 10000000.0 / m_rtTimePerFrame; - m_pSubPicQueue->SetFPS(m_fps); - } - } - } - break; - } - } - - timeEndPeriod(dwResolution); - // if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt); -} - -void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed) -{ - double xbiss = (-(ChangeSpeed) * (ValuePrim) - (Value - Target) * (ChangeSpeed * ChangeSpeed) * 0.25f); - ValuePrim += xbiss; - Value += ValuePrim; -} - -LONGLONG CEVRAllocatorPresenter::GetClockTime(LONGLONG PerformanceCounter) -{ - LONGLONG llClockTime; - MFTIME nsCurrentTime; - m_pClock->GetCorrelatedTime(0, &llClockTime, &nsCurrentTime); - DWORD Characteristics = 0; - m_pClock->GetClockCharacteristics(&Characteristics); - MFCLOCK_STATE State; - m_pClock->GetState(0, &State); - - if (!(Characteristics & MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ)) { - MFCLOCK_PROPERTIES Props; - if (m_pClock->GetProperties(&Props) == S_OK) { - llClockTime = (llClockTime * 10000000) / Props.qwClockFrequency; // Make 10 MHz - } - - } - LONGLONG llPerf = PerformanceCounter; - //return llClockTime + (llPerf - nsCurrentTime); - double Target = llClockTime + (llPerf - nsCurrentTime) * m_ModeratedTimeSpeed; - - bool bReset = false; - if (m_ModeratedTimeLast < 0 || State != m_LastClockState || m_ModeratedClockLast < 0) { - bReset = true; - m_ModeratedTimeLast = llPerf; - m_ModeratedClockLast = llClockTime; - } - - m_LastClockState = State; - - LONGLONG TimeChangeM = llPerf - m_ModeratedTimeLast; - LONGLONG ClockChangeM = llClockTime - m_ModeratedClockLast; - UNREFERENCED_PARAMETER(ClockChangeM); - - m_ModeratedTimeLast = llPerf; - m_ModeratedClockLast = llClockTime; - -#if 1 - - if (bReset) { - m_ModeratedTimeSpeed = 1.0; - m_ModeratedTimeSpeedPrim = 0.0; - ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory)); - ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory)); - m_ClockTimeChangeHistoryPos = 0; - } - if (TimeChangeM) { - int Pos = m_ClockTimeChangeHistoryPos % 100; - int nHistory = std::min(m_ClockTimeChangeHistoryPos, 100); - ++m_ClockTimeChangeHistoryPos; - if (nHistory > 50) { - int iLastPos = (Pos - (nHistory)) % 100; - if (iLastPos < 0) { - iLastPos += 100; - } - - double TimeChange = llPerf - m_TimeChangeHistory[iLastPos]; - double ClockChange = llClockTime - m_ClockChangeHistory[iLastPos]; - - double ClockSpeedTarget = ClockChange / TimeChange; - double ChangeSpeed = 0.1; - if (ClockSpeedTarget > m_ModeratedTimeSpeed) { - if (ClockSpeedTarget / m_ModeratedTimeSpeed > 0.1) { - ChangeSpeed = 0.1; - } else { - ChangeSpeed = 0.01; - } - } else { - if (m_ModeratedTimeSpeed / ClockSpeedTarget > 0.1) { - ChangeSpeed = 0.1; - } else { - ChangeSpeed = 0.01; - } - } - ModerateFloat(m_ModeratedTimeSpeed, ClockSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed); - //m_ModeratedTimeSpeed = TimeChange / ClockChange; - } - m_TimeChangeHistory[Pos] = (double)llPerf; - m_ClockChangeHistory[Pos] = (double)llClockTime; - } - - return (LONGLONG)Target; -#else - double EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed + m_ClockDiffCalc; - double Diff = Target - EstimateTime; - - // > 5 ms just set it - if ((fabs(Diff) > 50000.0 || bReset)) { - - // TRACE_EVR("EVR: Reset clock at diff: %f ms\n", (m_ModeratedTime - Target) /10000.0); - if (State == MFCLOCK_STATE_RUNNING) { - if (bReset) { - m_ModeratedTimeSpeed = 1.0; - m_ModeratedTimeSpeedPrim = 0.0; - m_ClockDiffCalc = 0; - m_ClockDiffPrim = 0; - m_ModeratedTime = Target; - m_ModeratedTimer = llPerf; - } else { - EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed; - Diff = Target - EstimateTime; - m_ClockDiffCalc = Diff; - m_ClockDiffPrim = 0; - } - } else { - m_ModeratedTimeSpeed = 0.0; - m_ModeratedTimeSpeedPrim = 0.0; - m_ClockDiffCalc = 0; - m_ClockDiffPrim = 0; - m_ModeratedTime = Target; - m_ModeratedTimer = llPerf; - } - } - - { - LONGLONG ModerateTime = 10000; - double ChangeSpeed = 1.00; - /*if (m_ModeratedTimeSpeedPrim != 0.0) - { - if (m_ModeratedTimeSpeedPrim < 0.1) - ChangeSpeed = 0.1; - }*/ - - int nModerate = 0; - double Change = 0; - while (m_ModeratedTimer < llPerf - ModerateTime) { - m_ModeratedTimer += ModerateTime; - m_ModeratedTime += double(ModerateTime) * m_ModeratedTimeSpeed; - - double TimerDiff = llPerf - m_ModeratedTimer; - - double Diff = (double)(m_ModeratedTime - (Target - TimerDiff)); - - double TimeSpeedTarget; - double AbsDiff = fabs(Diff); - TimeSpeedTarget = 1.0 - (Diff / 1000000.0); - // TimeSpeedTarget = m_ModeratedTimeSpeed - (Diff / 100000000000.0); - //if (AbsDiff > 20000.0) - // TimeSpeedTarget = 1.0 - (Diff / 1000000.0); - /*else if (AbsDiff > 5000.0) - TimeSpeedTarget = 1.0 - (Diff / 100000000.0); - else - TimeSpeedTarget = 1.0 - (Diff / 500000000.0);*/ - double StartMod = m_ModeratedTimeSpeed; - ModerateFloat(m_ModeratedTimeSpeed, TimeSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed); - m_ModeratedTimeSpeed = TimeSpeedTarget; - ++nModerate; - Change += m_ModeratedTimeSpeed - StartMod; - } - if (nModerate) { - m_ModeratedTimeSpeedDiff = Change / nModerate; - } - - double Ret = m_ModeratedTime + double(llPerf - m_ModeratedTimer) * m_ModeratedTimeSpeed; - double Diff = Target - Ret; - ModerateFloat(m_ClockDiffCalc, Diff, m_ClockDiffPrim, ChangeSpeed * 0.1); - - Ret += m_ClockDiffCalc; - Diff = Target - Ret; - m_ClockDiff = Diff; - return LONGLONG(Ret + 0.5); - } - - return Target; - return LONGLONG(m_ModeratedTime + 0.5); -#endif -} - -void CEVRAllocatorPresenter::OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter) -{ - // This function is meant to be called only from the rendering function - // so with the ownership on m_RenderLock. - if (!m_pCurrentlyDisplayedSample || !m_OrderedPaint || !bAll) { - return; - } - - LONGLONG llClockTime; - LONGLONG nsSampleTime; - LONGLONG SampleDuration = 0; - LONGLONG TimePerFrame = m_rtTimePerFrame; - if (!TimePerFrame) { - return; - } - - if (!m_bSignaledStarvation) { - llClockTime = GetClockTime(PerformanceCounter); - m_StarvationClock = llClockTime; - } else { - llClockTime = m_StarvationClock; - } - - if (SUCCEEDED(m_pCurrentlyDisplayedSample->GetSampleDuration(&SampleDuration))) { - // Some filters return invalid values, ignore them - if (SampleDuration > MIN_FRAME_TIME) { - TimePerFrame = SampleDuration; - } - } - - if (FAILED(m_pCurrentlyDisplayedSample->GetSampleTime(&nsSampleTime))) { - nsSampleTime = llClockTime; - } - - { - m_nNextSyncOffset = (m_nNextSyncOffset + 1) % NB_JITTER; - LONGLONG SyncOffset = nsSampleTime - llClockTime; - - m_pllSyncOffset[m_nNextSyncOffset] = SyncOffset; - //TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d \n", m_nCurSurface, m_VSyncMode, m_LastPredictedSync, -SyncOffset, m_LastPredictedSync - (-SyncOffset)); - - m_MaxSyncOffset = MINLONG64; - m_MinSyncOffset = MAXLONG64; - - LONGLONG AvrageSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG Offset = m_pllSyncOffset[i]; - AvrageSum += Offset; - m_MaxSyncOffset = std::max(m_MaxSyncOffset, Offset); - m_MinSyncOffset = std::min(m_MinSyncOffset, Offset); - } - double MeanOffset = double(AvrageSum) / NB_JITTER; - double DeviationSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - double Deviation = double(m_pllSyncOffset[i]) - MeanOffset; - DeviationSum += Deviation * Deviation; - } - double StdDev = sqrt(DeviationSum / NB_JITTER); - - m_fSyncOffsetAvr = MeanOffset; - m_bSyncStatsAvailable = true; - m_fSyncOffsetStdDev = StdDev; - } -} - -STDMETHODIMP_(bool) CEVRAllocatorPresenter::ResetDevice() -{ - CAutoLock cThreadsLock(&m_ThreadsLock); - - StopWorkerThreads(); - - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_RenderLock); - - RemoveAllSamples(); - - bool bResult = __super::ResetDevice(); - - for (int i = 0; i < m_nNbDXSurface; i++) { - CComPtr pMFSample; - HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); - - if (SUCCEEDED(hr)) { - pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); - pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - m_FreeSamples.AddTail(pMFSample); - pMFSample = nullptr; // The sample should not be used after being queued - } - ASSERT(SUCCEEDED(hr)); - } - - if (bResult) { - StartWorkerThreads(); - } - - return bResult; -} - -STDMETHODIMP_(bool) CEVRAllocatorPresenter::DisplayChange() -{ - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_RenderLock); - - bool bResult = __super::DisplayChange(); - - m_DetectedFrameRate = 0.0; - m_DetectedFrameTime = 0.0; - m_DetectedFrameTimeStdDev = 0.0; - m_DetectedLock = false; - ZeroMemory(m_DetectedFrameTimeHistory, sizeof(m_DetectedFrameTimeHistory)); - ZeroMemory(m_DetectedFrameTimeHistoryHistory, sizeof(m_DetectedFrameTimeHistoryHistory)); - m_DetectedFrameTimePos = 0; - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - ZeroMemory(m_ldDetectedRefreshRateList, sizeof(m_ldDetectedRefreshRateList)); - ZeroMemory(m_ldDetectedScanlineRateList, sizeof(m_ldDetectedScanlineRateList)); - m_DetectedRefreshRatePos = 0; - m_DetectedRefreshTimePrim = 0; - m_DetectedScanlineTime = 0; - m_DetectedScanlineTimePrim = 0; - m_DetectedRefreshRate = 0; - - ZeroMemory(m_pllJitter, sizeof(m_pllJitter)); - ZeroMemory(m_pllSyncOffset, sizeof(m_pllSyncOffset)); - m_nNextJitter = 0; - m_nNextSyncOffset = 0; - m_llLastPerf = 0; - m_fAvrFps = 0.0; - m_fJitterStdDev = 0.0; - m_fSyncOffsetStdDev = 0.0; - m_fSyncOffsetAvr = 0.0; - m_bSyncStatsAvailable = false; - - return bResult; -} - -void CEVRAllocatorPresenter::RenderThread() -{ - HANDLE hEvts[] = { m_hEvtQuit, m_hEvtFlush}; - bool bQuit = false, bForcePaint = false; - TIMECAPS tc; - MFTIME nsSampleTime; - LONGLONG llClockTime; - - // Tell Multimedia Class Scheduler we are a playback thread (increase priority) - HANDLE hAvrt = 0; - if (fnAvSetMmThreadCharacteristicsW) { - DWORD dwTaskIndex = 0; - hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); - if (fnAvSetMmThreadPriority) { - fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); - } - } - - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - VERIFY(timeBeginPeriod(dwResolution) == 0); - - auto checkPendingMediaFinished = [this]() { - if (m_bPendingMediaFinished && m_nRenderState != Stopped) { - CAutoLock lock(&m_SampleQueueLock); - if (m_ScheduledSamples.IsEmpty()) { - m_bPendingMediaFinished = false; - m_pSink->Notify(EC_COMPLETE, 0, 0); - TRACE_EVR("EVR: send EC_COMPLETE\n"); - } - } - }; - - const CRenderersSettings& r = GetRenderersSettings(); - - auto SubPicSetTime = [&] { - if (!g_bExternalSubtitleTime && !m_bIsPreview) { - CSubPicAllocatorPresenterImpl::SetTime(g_tSegmentStart + nsSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); - } - }; - - int NextSleepTime = 1; - while (!bQuit) { - LONGLONG llPerf = GetRenderersData()->GetPerfCounter(); - UNREFERENCED_PARAMETER(llPerf); - if (!r.m_AdvRendSets.bVMR9VSyncAccurate && NextSleepTime == 0) { - NextSleepTime = 1; - } - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, std::max(NextSleepTime < 0 ? 1 : NextSleepTime, 0)); - /* dwObject = WAIT_TIMEOUT; - if (m_bEvtFlush) - dwObject = WAIT_OBJECT_0 + 1; - else if (m_bEvtQuit) - dwObject = WAIT_OBJECT_0;*/ - // if (NextSleepTime) - // TRACE_EVR("EVR: Sleep: %7.3f\n", double(GetRenderersData()->GetPerfCounter()-llPerf) / 10000.0); - if (NextSleepTime > 1) { - NextSleepTime = 0; - } else if (NextSleepTime == 0) { - NextSleepTime = -1; - } - switch (dwObject) { - case WAIT_OBJECT_0: - bQuit = true; - break; - case WAIT_OBJECT_0 + 1: - // Flush pending samples! - FlushSamples(); - m_bEvtFlush = false; - ResetEvent(m_hEvtFlush); - bForcePaint = true; - TRACE_EVR("EVR: Flush done!\n"); - break; - - case WAIT_TIMEOUT: - - if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != r.m_AdvRendSets.iEVROutputRange || m_bPendingRenegotiate) { - FlushSamples(); - RenegotiateMediaType(); - m_bPendingRenegotiate = false; - } - if (m_bPendingResetDevice) { - SendResetRequest(); - } - - // Discard timer events if playback stop - //if ((dwObject == WAIT_OBJECT_0 + 3) && (m_nRenderState != Started)) continue; - - //TRACE_EVR ("EVR: RenderThread ==>> Waiting buffer\n"); - - //if (WaitForMultipleObjects (_countof(hEvtsBuff), hEvtsBuff, FALSE, INFINITE) == WAIT_OBJECT_0+2) - { - CComPtr pMFSample; - //LONGLONG llPerf2 = GetRenderersData()->GetPerfCounter(); - //UNREFERENCED_PARAMETER(llPerf2); - int nSamplesLeft = 0; - if (SUCCEEDED(GetScheduledSample(&pMFSample, nSamplesLeft))) { - //UINT32 nSurface; - //pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&nSurface); - - bool bValidSampleTime = true; - HRESULT hrGetSampleTime = pMFSample->GetSampleTime(&nsSampleTime); - if (hrGetSampleTime != S_OK || nsSampleTime == 0) { - bValidSampleTime = false; - } - // We assume that all samples have the same duration - LONGLONG SampleDuration = 0; - bool bValidSampleDuration = true; - HRESULT hrGetSampleDuration = pMFSample->GetSampleDuration(&SampleDuration); - // Some filters return invalid values, ignore them - if (hrGetSampleDuration != S_OK || SampleDuration <= MIN_FRAME_TIME) { - bValidSampleDuration = false; - } - - //TRACE_EVR("EVR: RenderThread ==>> Presenting surface %d (%I64d)\n", nSurface, nsSampleTime); - - bool bStepForward = false; - - if (m_nStepCount < 0) { - // Drop frame - TRACE_EVR("EVR: Dropped frame\n"); - m_pcFrames++; - bStepForward = true; - m_nStepCount = 0; - /* - } else if (m_nStepCount > 0) { - ++m_OrderedPaint; - SubPicSetTime(); - Paint(pMFSample); - m_nDroppedUpdate = 0; - CompleteFrameStep(false); - bStepForward = true; - */ - } else if (m_nRenderState == Started) { - LONGLONG CurrentCounter = GetRenderersData()->GetPerfCounter(); - // Calculate wake up timer - if (!m_bSignaledStarvation) { - llClockTime = GetClockTime(CurrentCounter); - m_StarvationClock = llClockTime; - } else { - llClockTime = m_StarvationClock; - } - - if (!bValidSampleTime) { - // Just play as fast as possible - bStepForward = true; - ++m_OrderedPaint; - SubPicSetTime(); - Paint(pMFSample); - } else { - LONGLONG TimePerFrame = (LONGLONG)(GetFrameTime() * 10000000.0); - LONGLONG SyncOffset = 0; - LONGLONG VSyncTime = 0; - LONGLONG TimeToNextVSync = -1; - bool bVSyncCorrection = false; - double DetectedRefreshTime; - double DetectedScanlinesPerFrame; - double DetectedScanlineTime; - int DetectedRefreshRatePos; - { - CAutoLock Lock(&m_refreshRateLock); - DetectedRefreshTime = m_DetectedRefreshTime; - DetectedRefreshRatePos = m_DetectedRefreshRatePos; - DetectedScanlinesPerFrame = m_DetectedScanlinesPerFrame; - DetectedScanlineTime = m_DetectedScanlineTime; - } - - if (DetectedRefreshRatePos < 20 || !DetectedRefreshTime || !DetectedScanlinesPerFrame) { - DetectedRefreshTime = 1.0 / m_refreshRate; - DetectedScanlinesPerFrame = m_ScreenSize.cy; - DetectedScanlineTime = DetectedRefreshTime / double(m_ScreenSize.cy); - } - - if (r.m_AdvRendSets.bVMR9VSync) { - bVSyncCorrection = true; - double TargetVSyncPos = GetVBlackPos(); - double RefreshLines = DetectedScanlinesPerFrame; - double ScanlinesPerSecond = 1.0 / DetectedScanlineTime; - double CurrentVSyncPos = fmod(double(m_VBlankStartMeasure) + ScanlinesPerSecond * ((CurrentCounter - m_VBlankStartMeasureTime) / 10000000.0), RefreshLines); - double LinesUntilVSync = 0; - //TargetVSyncPos -= ScanlinesPerSecond * (DrawTime/10000000.0); - //TargetVSyncPos -= 10; - TargetVSyncPos = fmod(TargetVSyncPos, RefreshLines); - if (TargetVSyncPos < 0) { - TargetVSyncPos += RefreshLines; - } - if (TargetVSyncPos > CurrentVSyncPos) { - LinesUntilVSync = TargetVSyncPos - CurrentVSyncPos; - } else { - LinesUntilVSync = (RefreshLines - CurrentVSyncPos) + TargetVSyncPos; - } - double TimeUntilVSync = LinesUntilVSync * DetectedScanlineTime; - TimeToNextVSync = (LONGLONG)(TimeUntilVSync * 10000000.0); - VSyncTime = (LONGLONG)(DetectedRefreshTime * 10000000.0); - - LONGLONG ClockTimeAtNextVSync = llClockTime + (LONGLONG)(TimeUntilVSync * 10000000.0 * m_ModeratedTimeSpeed); - - SyncOffset = (nsSampleTime - ClockTimeAtNextVSync); - - //if (SyncOffset < 0) - // TRACE_EVR("EVR: SyncOffset(%d): %I64d %I64d %I64d\n", m_nCurSurface, SyncOffset, TimePerFrame, VSyncTime); - } else { - SyncOffset = (nsSampleTime - llClockTime); - } - - //LONGLONG SyncOffset = nsSampleTime - llClockTime; - TRACE_EVR("EVR: SyncOffset: %I64d SampleFrame: %I64d ClockFrame: %I64d\n", SyncOffset, TimePerFrame != 0 ? nsSampleTime / TimePerFrame : 0, TimePerFrame != 0 ? llClockTime / TimePerFrame : 0); - if (bValidSampleDuration && !m_DetectedLock) { - TimePerFrame = SampleDuration; - } - - LONGLONG MinMargin = MIN_FRAME_TIME + std::min(LONGLONG(m_DetectedFrameTimeStdDev), 20000ll); - //if (m_FrameTimeCorrection) { - // MinMargin = MIN_FRAME_TIME; - //} else { - // MinMargin = MIN_FRAME_TIME + std::min(LONGLONG(m_DetectedFrameTimeStdDev), 20000ll); - //} - LONGLONG TimePerFrameMargin = std::min(std::max(TimePerFrame * 2l / 100l, MinMargin), TimePerFrame * 11l / 100l); // (0.02..0.11)TimePerFrame - LONGLONG TimePerFrameMargin0 = TimePerFrameMargin / 2; - LONGLONG TimePerFrameMargin1 = 0; - - if (m_DetectedLock && TimePerFrame < VSyncTime) { - VSyncTime = TimePerFrame; - } - - if (m_VSyncMode == 1) { - TimePerFrameMargin1 = -TimePerFrameMargin; - } else if (m_VSyncMode == 2) { - TimePerFrameMargin1 = TimePerFrameMargin; - } - - m_LastSampleOffset = SyncOffset; - m_bLastSampleOffsetValid = true; - - LONGLONG VSyncOffset0 = 0; - bool bDoVSyncCorrection = false; - if ((SyncOffset < -(TimePerFrame + TimePerFrameMargin0 - TimePerFrameMargin1)) && nSamplesLeft > 0) { // Only drop if we have something else to display at once - // Drop frame - TRACE_EVR("EVR: Dropped frame\n"); - m_pcFrames++; - bStepForward = true; - ++m_nDroppedUpdate; - NextSleepTime = 0; - //VSyncOffset0 = (-SyncOffset) - VSyncTime; - //VSyncOffset0 = (-SyncOffset) - VSyncTime + TimePerFrameMargin1; - //m_LastPredictedSync = VSyncOffset0; - bDoVSyncCorrection = false; - } else if (SyncOffset < TimePerFrameMargin1) { - - if (bVSyncCorrection) { - VSyncOffset0 = -SyncOffset; - bDoVSyncCorrection = true; - } - - // Paint and prepare for next frame - TRACE_EVR("EVR: Normalframe\n"); - m_nDroppedUpdate = 0; - bStepForward = true; - m_LastFrameDuration = nsSampleTime - m_LastSampleTime; - m_LastSampleTime = nsSampleTime; - m_LastPredictedSync = VSyncOffset0; - - if (m_nStepCount > 0) { - CompleteFrameStep(false); - } - - ++m_OrderedPaint; - - SubPicSetTime(); - Paint(pMFSample); - - NextSleepTime = 0; - m_pcFramesDrawn++; - } else { - if (TimeToNextVSync >= 0 && SyncOffset > 0) { - NextSleepTime = (int)(TimeToNextVSync / 10000 - 2); - } else { - NextSleepTime = (int)(SyncOffset / 10000 - 2); - } - - if (NextSleepTime > TimePerFrame) { - NextSleepTime = 1; - } - - if (NextSleepTime < 0) { - NextSleepTime = 0; - } - NextSleepTime = 1; - //TRACE_EVR ("EVR: Delay\n"); - } - - if (bDoVSyncCorrection) { - //LONGLONG VSyncOffset0 = (((SyncOffset) % VSyncTime) + VSyncTime) % VSyncTime; - LONGLONG Margin = TimePerFrameMargin; - - LONGLONG VSyncOffsetMin = 30000000000000; - LONGLONG VSyncOffsetMax = -30000000000000; - for (int i = 0; i < 5; ++i) { - VSyncOffsetMin = std::min(m_VSyncOffsetHistory[i], VSyncOffsetMin); - VSyncOffsetMax = std::max(m_VSyncOffsetHistory[i], VSyncOffsetMax); - } - - m_VSyncOffsetHistory[m_VSyncOffsetHistoryPos] = VSyncOffset0; - m_VSyncOffsetHistoryPos = (m_VSyncOffsetHistoryPos + 1) % 5; - - //LONGLONG VSyncTime2 = VSyncTime2 + (VSyncOffsetMax - VSyncOffsetMin); - //VSyncOffsetMin; = (((VSyncOffsetMin) % VSyncTime) + VSyncTime) % VSyncTime; - //VSyncOffsetMax = (((VSyncOffsetMax) % VSyncTime) + VSyncTime) % VSyncTime; - - //TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d %8I64d\n", m_nCurSurface, m_VSyncMode,VSyncOffset0, VSyncOffsetMin, VSyncOffsetMax, VSyncOffsetMax - VSyncOffsetMin); - - if (m_VSyncMode == 0) { - // 23.976 in 60 Hz - if (VSyncOffset0 < Margin && VSyncOffsetMax > (VSyncTime - Margin)) { - m_VSyncMode = 2; - } else if (VSyncOffset0 > (VSyncTime - Margin) && VSyncOffsetMin < Margin) { - m_VSyncMode = 1; - } - } else if (m_VSyncMode == 2) { - if (VSyncOffsetMin > (Margin)) { - m_VSyncMode = 0; - } - } else if (m_VSyncMode == 1) { - if (VSyncOffsetMax < (VSyncTime - Margin)) { - m_VSyncMode = 0; - } - } - } - } - } else if (m_nRenderState == Paused) { - if (bForcePaint) { - bStepForward = true; - // Ensure that the renderer is properly updated after seeking when paused - SubPicSetTime(); - Paint(pMFSample); - } - NextSleepTime = int(SampleDuration / 10000 - 2); - } - - if (bStepForward) { - m_MaxSampleDuration = std::max(SampleDuration, m_MaxSampleDuration); - checkPendingMediaFinished(); - } else { - AddToScheduledList(pMFSample, true); - pMFSample = nullptr; // The sample should not be used after being queued - } - - bForcePaint = false; - } else if (m_bLastSampleOffsetValid && m_LastSampleOffset < -10000000) { // Only starve if we are 1 seconds behind - if (m_nRenderState == Started && !g_bNoDuration) { - m_pSink->Notify(EC_STARVATION, 0, 0); - m_bSignaledStarvation = true; - } - } else { - checkPendingMediaFinished(); - } - } - //else - //{ - // TRACE_EVR ("EVR: RenderThread ==>> Flush before rendering frame!\n"); - //} - - break; - } - } - - timeEndPeriod(dwResolution); - if (fnAvRevertMmThreadCharacteristics) { - fnAvRevertMmThreadCharacteristics(hAvrt); - } -} - -void CEVRAllocatorPresenter::VSyncThread() -{ - HANDLE hEvts[] = { m_hEvtQuit}; - bool bQuit = false; - TIMECAPS tc; - DWORD dwResolution; - - // Tell Multimedia Class Scheduler we are a playback thread (increase priority) - //HANDLE hAvrt = 0; - //if (pfAvSetMmThreadCharacteristicsW) { - // DWORD dwTaskIndex = 0; - // hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); - // if (pfAvSetMmThreadPriority) { - // pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); - // } - //} - - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - timeBeginPeriod(dwResolution); - const CRenderersData* rd = GetRenderersData(); - const CRenderersSettings& r = GetRenderersSettings(); - - while (!bQuit) { - - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); - switch (dwObject) { - case WAIT_OBJECT_0: - bQuit = true; - break; - case WAIT_TIMEOUT: { - // Do our stuff - if (m_pD3DDev && r.m_AdvRendSets.bVMR9VSync) { - if (m_nRenderState == Started) { - int VSyncPos = GetVBlackPos(); - int WaitRange = std::max(m_ScreenSize.cy / 40l, 5l); - int MinRange = std::max(std::min(long(0.003 * m_ScreenSize.cy * m_refreshRate + 0.5), m_ScreenSize.cy / 3l), 5l); // 1.8 ms or max 33 % of Time - - VSyncPos += MinRange + WaitRange; - - VSyncPos = VSyncPos % m_ScreenSize.cy; - if (VSyncPos < 0) { - VSyncPos += m_ScreenSize.cy; - } - - int ScanLine = 0; - int StartScanLine = ScanLine; - UNREFERENCED_PARAMETER(StartScanLine); - int LastPos = ScanLine; - UNREFERENCED_PARAMETER(LastPos); - ScanLine = (VSyncPos + 1) % m_ScreenSize.cy; - if (ScanLine < 0) { - ScanLine += m_ScreenSize.cy; - } - int ScanLineMiddle = ScanLine + m_ScreenSize.cy / 2; - ScanLineMiddle = ScanLineMiddle % m_ScreenSize.cy; - if (ScanLineMiddle < 0) { - ScanLineMiddle += m_ScreenSize.cy; - } - - int ScanlineStart = ScanLine; - HANDLE lockOwner = nullptr; - WaitForVBlankRange(ScanlineStart, 5, true, true, false, lockOwner); - LONGLONG TimeStart = rd->GetPerfCounter(); - - WaitForVBlankRange(ScanLineMiddle, 5, true, true, false, lockOwner); - LONGLONG TimeMiddle = rd->GetPerfCounter(); - - int ScanlineEnd = ScanLine; - WaitForVBlankRange(ScanlineEnd, 5, true, true, false, lockOwner); - LONGLONG TimeEnd = rd->GetPerfCounter(); - - double nSeconds = (TimeEnd - TimeStart) / 10000000.0; - LONGLONG llDiffMiddle = TimeMiddle - TimeStart; - ASSERT(llDiffMiddle > 0); - - if (nSeconds > 0.003 && llDiffMiddle > 0) { - double dDiffMiddle = double(llDiffMiddle); - double dDiffEnd = double(TimeEnd - TimeMiddle); - - double dDiffDiff = dDiffEnd / dDiffMiddle; - if (dDiffDiff < 1.3 && dDiffDiff > (1 / 1.3)) { - double ScanLineSeconds; - double nScanLines; - if (ScanLineMiddle > ScanlineEnd) { - ScanLineSeconds = dDiffMiddle / 10000000.0; - nScanLines = ScanLineMiddle - ScanlineStart; - } else { - ScanLineSeconds = dDiffEnd / 10000000.0; - nScanLines = ScanlineEnd - ScanLineMiddle; - } - - double ScanLineTime = ScanLineSeconds / nScanLines; - - int iPos = m_DetectedRefreshRatePos % 100; - m_ldDetectedScanlineRateList[iPos] = ScanLineTime; - if (m_DetectedScanlineTime && ScanlineStart != ScanlineEnd) { - int Diff = ScanlineEnd - ScanlineStart; - nSeconds -= double(Diff) * m_DetectedScanlineTime; - } - m_ldDetectedRefreshRateList[iPos] = nSeconds; - double Average = 0; - double AverageScanline = 0; - int nPos = std::min(iPos + 1, 100); - for (int i = 0; i < nPos; ++i) { - Average += m_ldDetectedRefreshRateList[i]; - AverageScanline += m_ldDetectedScanlineRateList[i]; - } - - if (nPos) { - Average /= double(nPos); - AverageScanline /= double(nPos); - } else { - Average = 0; - AverageScanline = 0; - } - - double ThisValue = Average; - - if (Average > 0.0 && AverageScanline > 0.0) { - CAutoLock Lock(&m_refreshRateLock); - ++m_DetectedRefreshRatePos; - if (m_DetectedRefreshTime == 0 || m_DetectedRefreshTime / ThisValue > 1.01 || m_DetectedRefreshTime / ThisValue < 0.99) { - m_DetectedRefreshTime = ThisValue; - m_DetectedRefreshTimePrim = 0; - } - if (_isnan(m_DetectedRefreshTime)) { - m_DetectedRefreshTime = 0.0; - } - if (_isnan(m_DetectedRefreshTimePrim)) { - m_DetectedRefreshTimePrim = 0.0; - } - - ModerateFloat(m_DetectedRefreshTime, ThisValue, m_DetectedRefreshTimePrim, 1.5); - if (m_DetectedRefreshTime > 0.0) { - m_DetectedRefreshRate = 1.0 / m_DetectedRefreshTime; - } else { - m_DetectedRefreshRate = 0.0; - } - - if (m_DetectedScanlineTime == 0 || m_DetectedScanlineTime / AverageScanline > 1.01 || m_DetectedScanlineTime / AverageScanline < 0.99) { - m_DetectedScanlineTime = AverageScanline; - m_DetectedScanlineTimePrim = 0; - } - ModerateFloat(m_DetectedScanlineTime, AverageScanline, m_DetectedScanlineTimePrim, 1.5); - if (m_DetectedScanlineTime > 0.0) { - m_DetectedScanlinesPerFrame = m_DetectedRefreshTime / m_DetectedScanlineTime; - } else { - m_DetectedScanlinesPerFrame = 0; - } - } - //TRACE(_T("Refresh: %f\n"), RefreshRate); - } - } - } - } else { - m_DetectedRefreshRate = 0.0; - m_DetectedScanlinesPerFrame = 0.0; - } - } - break; - } - } - - timeEndPeriod(dwResolution); - //if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt); -} - -DWORD WINAPI CEVRAllocatorPresenter::VSyncThreadStatic(LPVOID lpParam) -{ - SetThreadName(DWORD(-1), "CEVRAllocatorPresenter::VSyncThread"); - CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; - pThis->VSyncThread(); - return 0; -} - -void CEVRAllocatorPresenter::OnResetDevice() -{ - // Reset DXVA Manager, and get new buffers - m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); - - // Not necessary, but Microsoft documentation say Presenter should send this message... - if (m_pSink) { - m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); - } -} - -void CEVRAllocatorPresenter::RemoveAllSamples() -{ - CAutoLock imageProcesssingLock(&m_ImageProcessingLock); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - - FlushSamples(); - m_FreeSamples.RemoveAll(); - m_LastScheduledUncorrectedSampleTime = -1; - m_nUsedBuffer = 0; - // Increment the group id to make sure old samples will really be deleted - m_nCurrentGroupId++; -} - -HRESULT CEVRAllocatorPresenter::GetFreeSample(IMFSample** ppSample) -{ - CAutoLock lock(&m_SampleQueueLock); - HRESULT hr = S_OK; - - if (!m_FreeSamples.IsEmpty()) { - m_nUsedBuffer++; - *ppSample = m_FreeSamples.RemoveHead().Detach(); - } else { - hr = MF_E_SAMPLEALLOCATOR_EMPTY; - } - - return hr; -} - -HRESULT CEVRAllocatorPresenter::GetScheduledSample(IMFSample** ppSample, int& count) -{ - CAutoLock lock(&m_SampleQueueLock); - HRESULT hr = S_OK; - - count = (int)m_ScheduledSamples.GetCount(); - if (count > 0) { - *ppSample = m_ScheduledSamples.RemoveHead().Detach(); - --count; - } else { - hr = MF_E_SAMPLEALLOCATOR_EMPTY; - } - - return hr; -} - -void CEVRAllocatorPresenter::AddToFreeList(IMFSample* pSample, bool bTail) -{ - CAutoLock lock(&m_SampleQueueLock); - - m_nUsedBuffer--; - if (bTail) { - m_FreeSamples.AddTail(pSample); - } else { - m_FreeSamples.AddHead(pSample); - } -} - -void CEVRAllocatorPresenter::AddToScheduledList(IMFSample* pSample, bool bSorted) -{ - CAutoLock lock(&m_SampleQueueLock); - - if (bSorted) { - // Insert sorted - /*POSITION Iterator = m_ScheduledSamples.GetHeadPosition(); - - LONGLONG NewSampleTime; - pSample->GetSampleTime(&NewSampleTime); - - while (Iterator != nullptr) - { - POSITION CurrentPos = Iterator; - IMFSample *pIter = m_ScheduledSamples.GetNext(Iterator); - LONGLONG SampleTime; - pIter->GetSampleTime(&SampleTime); - if (NewSampleTime < SampleTime) - { - m_ScheduledSamples.InsertBefore(CurrentPos, pSample); - return; - } - }*/ - - m_ScheduledSamples.AddHead(pSample); - } else { - const CRenderersSettings& r = GetRenderersSettings(); - double ForceFPS = 0.0; - //double ForceFPS = 59.94; - //double ForceFPS = 23.976; - if (ForceFPS != 0.0) { - m_rtTimePerFrame = (REFERENCE_TIME)(10000000.0 / ForceFPS); - } - LONGLONG Duration = m_rtTimePerFrame; - UNREFERENCED_PARAMETER(Duration); - LONGLONG PrevTime = m_LastScheduledUncorrectedSampleTime; - LONGLONG Time; - LONGLONG SetDuration; - pSample->GetSampleDuration(&SetDuration); - pSample->GetSampleTime(&Time); - m_LastScheduledUncorrectedSampleTime = Time; - - m_bCorrectedFrameTime = false; - - LONGLONG Diff2 = PrevTime - (LONGLONG)(m_LastScheduledSampleTimeFP * 10000000.0); - LONGLONG Diff = Time - PrevTime; - if (PrevTime == -1) { - Diff = 0; - } - if (Diff < 0) { - Diff = -Diff; - } - if (Diff2 < 0) { - Diff2 = -Diff2; - } - if (Diff < m_rtTimePerFrame * 8 && m_rtTimePerFrame && Diff2 < m_rtTimePerFrame * 8) { // Detect seeking - int iPos = (m_DetectedFrameTimePos++) % 60; - Diff = Time - PrevTime; - if (PrevTime == -1) { - Diff = 0; - } - m_DetectedFrameTimeHistory[iPos] = Diff; - - if (m_DetectedFrameTimePos >= 10) { - int nFrames = std::min(m_DetectedFrameTimePos, 60); - LONGLONG DectedSum = 0; - for (int i = 0; i < nFrames; ++i) { - DectedSum += m_DetectedFrameTimeHistory[i]; - } - - double Average = double(DectedSum) / double(nFrames); - double DeviationSum = 0.0; - for (int i = 0; i < nFrames; ++i) { - double Deviation = m_DetectedFrameTimeHistory[i] - Average; - DeviationSum += Deviation * Deviation; - } - - double StdDev = sqrt(DeviationSum / double(nFrames)); - - m_DetectedFrameTimeStdDev = StdDev; - - double DetectedRate = 1.0 / (double(DectedSum) / (nFrames * 10000000.0)); - double AllowedError = 0.0003; - - static double AllowedValues[] = {60.0, 59.94, 50.0, 48.0, 47.952, 30.0, 29.97, 25.0, 24.0, 23.976}; - - int nAllowed = _countof(AllowedValues); - for (int i = 0; i < nAllowed; ++i) { - if (fabs(1.0 - DetectedRate / AllowedValues[i]) < AllowedError) { - DetectedRate = AllowedValues[i]; - break; - } - } - - m_DetectedFrameTimeHistoryHistory[m_DetectedFrameTimePos % 500] = DetectedRate; - - class CAutoInt - { - public: - - int m_Int; - - CAutoInt() { - m_Int = 0; - } - CAutoInt(int _Other) { - m_Int = _Other; - } - - operator int () const { - return m_Int; - } - - CAutoInt& operator ++ () { - ++m_Int; - return *this; - } - }; - - - CMap Map; - - for (int i = 0; i < 500; ++i) { - ++Map[m_DetectedFrameTimeHistoryHistory[i]]; - } - - POSITION Pos = Map.GetStartPosition(); - double BestVal = 0.0; - int BestNum = 5; - while (Pos) { - double Key; - CAutoInt Value; - Map.GetNextAssoc(Pos, Key, Value); - if (Value.m_Int > BestNum && Key != 0.0) { - BestNum = Value.m_Int; - BestVal = Key; - } - } - - m_DetectedLock = false; - for (int i = 0; i < nAllowed; ++i) { - if (BestVal == AllowedValues[i]) { - m_DetectedLock = true; - break; - } - } - if (BestVal != 0.0) { - m_DetectedFrameRate = BestVal; - m_DetectedFrameTime = 1.0 / BestVal; - } - } - - LONGLONG PredictedNext = PrevTime + m_rtTimePerFrame; - LONGLONG PredictedDiff = PredictedNext - Time; - if (PredictedDiff < 0) { - PredictedDiff = -PredictedDiff; - } - - if (m_DetectedFrameTime != 0.0 - //&& PredictedDiff > MIN_FRAME_TIME - && m_DetectedLock && r.m_AdvRendSets.bEVREnableFrameTimeCorrection) { - double CurrentTime = Time / 10000000.0; - double LastTime = m_LastScheduledSampleTimeFP; - double PredictedTime = LastTime + m_DetectedFrameTime; - if (fabs(PredictedTime - CurrentTime) > 0.0015) { // 1.5 ms wrong, lets correct - CurrentTime = PredictedTime; - Time = (LONGLONG)(CurrentTime * 10000000.0); - pSample->SetSampleTime(Time); - pSample->SetSampleDuration(LONGLONG(m_DetectedFrameTime * 10000000.0)); - m_bCorrectedFrameTime = true; - m_FrameTimeCorrection = 30; - } - m_LastScheduledSampleTimeFP = CurrentTime; - } else { - m_LastScheduledSampleTimeFP = Time / 10000000.0; - } - } else { - m_LastScheduledSampleTimeFP = Time / 10000000.0; - if (Diff > m_rtTimePerFrame * 8) { - // Seek - m_bSignaledStarvation = false; - m_DetectedFrameTimePos = 0; - m_DetectedLock = false; - } - } - - // TRACE_EVR("EVR: Time: %f %f %f\n", Time / 10000000.0, SetDuration / 10000000.0, m_DetectedFrameRate); - if (!m_bCorrectedFrameTime && m_FrameTimeCorrection) { - --m_FrameTimeCorrection; - } - -#if 0 - if (Time <= m_LastScheduledUncorrectedSampleTime && m_LastScheduledSampleTime >= 0) { - PrevTime = m_LastScheduledSampleTime; - } - - m_bCorrectedFrameTime = false; - if (PrevTime != -1 && (Time >= PrevTime - ((Duration * 20) / 9) || Time == 0) || ForceFPS != 0.0) { - if (Time - PrevTime > ((Duration * 20) / 9) && Time - PrevTime < Duration * 8 || Time == 0 || ((Time - PrevTime) < (Duration / 11)) || ForceFPS != 0.0) { - // Error!!!! - Time = PrevTime + Duration; - pSample->SetSampleTime(Time); - pSample->SetSampleDuration(Duration); - m_bCorrectedFrameTime = true; - TRACE_EVR("EVR: Corrected invalid sample time\n"); - } - } - if (Time + Duration * 10 < m_LastScheduledSampleTime) { - // Flush when repeating movie - FlushSamplesInternal(); - } -#endif - -#if 0 - static LONGLONG LastDuration = 0; - LONGLONG SetDuration = m_rtTimePerFrame; - pSample->GetSampleDuration(&SetDuration); - if (SetDuration != LastDuration) { - TRACE_EVR("EVR: Old duration: %I64d New duration: %I64d\n", LastDuration, SetDuration); - } - LastDuration = SetDuration; -#endif - m_LastScheduledSampleTime = Time; - - m_ScheduledSamples.AddTail(pSample); - } -} - -void CEVRAllocatorPresenter::FlushSamples() -{ - CAutoLock lock(this); - CAutoLock lock2(&m_SampleQueueLock); - CAutoLock lock3(&m_RenderLock); - - m_pCurrentlyDisplayedSample = nullptr; - m_ScheduledSamples.RemoveAll(); - - m_LastSampleOffset = 0; - m_bLastSampleOffsetValid = false; - m_bSignaledStarvation = false; - m_LastScheduledSampleTime = -1; -} - -HRESULT CEVRAllocatorPresenter::TrackSample(IMFSample* pSample) -{ - HRESULT hr = E_FAIL; - if (CComQIPtr pTracked = pSample) { - hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr); - } - return hr; -} - -HRESULT CEVRAllocatorPresenter::OnSampleFree(IMFAsyncResult* pResult) -{ - CComPtr pObject; - HRESULT hr = pResult->GetObject(&pObject); - if (SUCCEEDED(hr)) { - if (CComQIPtr pSample = pObject) { - // Ignore the sample if it is from an old group - UINT32 nGroupId; - CAutoLock sampleQueueLock(&m_SampleQueueLock); - if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) { - AddToFreeList(pSample, true); - pSample = nullptr; // The sample should not be used after being queued - } - } - } - return hr; -} +/* + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "EVRAllocatorPresenter.h" +#include "OuterEVR.h" +#include +#include "IPinHook.h" +#include "MacrovisionKicker.h" +#include "IMPCVideoDecFilter.h" +#include "Utils.h" +#include "Variables.h" + +#if (0) // Set to 1 to activate EVR traces +#define TRACE_EVR TRACE +#else +#define TRACE_EVR __noop +#endif + +#define MIN_FRAME_TIME 15000 + +enum EVR_STATS_MSG { + MSG_MIXERIN, + MSG_MIXEROUT +}; + +// Guid to tag IMFSample with a group id +static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } }; +// Guid to tag IMFSample with DirectX surface index +static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } }; + + +// === Helper functions +MFOffset MakeOffset(float v) +{ + MFOffset offset; + offset.value = short(v); + offset.fract = WORD(65536 * (v - offset.value)); + return offset; +} + +MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height) +{ + MFVideoArea area; + area.OffsetX = MakeOffset(x); + area.OffsetY = MakeOffset(y); + area.Area.cx = width; + area.Area.cy = height; + return area; +} + +using namespace DSObjects; + +CEVRAllocatorPresenter::CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error, bool isPreview) + : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, true, _Error, isPreview) + , m_ModeratedTime(0) + , m_ModeratedTimeLast(-1) + , m_ModeratedClockLast(-1) + , m_ModeratedTimer(0) + , m_LastClockState(MFCLOCK_STATE_INVALID) + , m_pOuterEVR(nullptr) + , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture) + , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0) + , m_BorderColor(RGB(0, 0, 0)) + , m_hEvtQuit(nullptr) + , m_bEvtQuit(0) + , m_hEvtFlush(nullptr) + , m_bEvtFlush(0) + , m_fUseInternalTimer(false) + , m_LastSetOutputRange(-1) + , m_bPendingRenegotiate(false) + , m_bPendingMediaFinished(false) + , m_hThread(nullptr) + , m_hGetMixerThread(nullptr) + , m_hVSyncThread(nullptr) + , m_nRenderState(Shutdown) + , m_nCurrentGroupId(0) + , m_bLastSampleOffsetValid(false) + , m_LastScheduledSampleTime(-1) + , m_LastScheduledSampleTimeFP(-1) + , m_LastScheduledUncorrectedSampleTime(-1) + , m_MaxSampleDuration(0) + , m_LastSampleOffset(0) + , m_LastPredictedSync(0) + , m_VSyncOffsetHistoryPos(0) + , m_nResetToken(0) + , m_nStepCount(0) + , m_bSignaledStarvation(false) + , m_StarvationClock(0) + , m_SampleFreeCallback(this, &CEVRAllocatorPresenter::OnSampleFree) + , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9") + , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer") + , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface") + , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType") + , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW") + , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority") + , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics") +{ + const CRenderersSettings& r = GetRenderersSettings(); + + ZeroMemory(m_VSyncOffsetHistory, sizeof(m_VSyncOffsetHistory)); + ResetStats(); + + if (FAILED(hr)) { + _Error += L"DX9AllocatorPresenter failed\n"; + return; + } + + if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) { + if (!fnDXVA2CreateDirect3DDeviceManager9) { + _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n"; + } + if (!fnMFCreateDXSurfaceBuffer) { + _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n"; + } + if (!fnMFCreateVideoSampleFromSurface) { + _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n"; + } + if (!fnMFCreateMediaType) { + _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n"; + } + hr = E_FAIL; + return; + } + + // Init DXVA manager + hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager); + if (SUCCEEDED(hr) && m_pD3DManager) { + hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); + if (FAILED(hr)) { + _Error += L"m_pD3DManager->ResetDevice failed\n"; + } + } else { + _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n"; + } + + + // Bufferize frame only with 3D texture! + if (!m_bIsPreview && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { + m_nNbDXSurface = std::max(std::min(r.iEvrBuffers, MAX_VIDEO_SURFACES), 4); + } else { + m_nNbDXSurface = 1; + } +} + +CEVRAllocatorPresenter::~CEVRAllocatorPresenter() +{ + StopWorkerThreads(); // If not already done... + m_pMediaType = nullptr; + m_pClock = nullptr; + m_pD3DManager = nullptr; + + if (m_bHookedNewSegment) { + UnhookNewSegment(); + } +} + +void CEVRAllocatorPresenter::ResetStats() +{ + m_pcFrames = 0; + m_nDroppedUpdate = 0; + m_pcFramesDrawn = 0; + m_piAvg = 0; + m_piDev = 0; +} + +HRESULT CEVRAllocatorPresenter::CheckShutdown() const +{ + if (m_nRenderState == Shutdown) { + return MF_E_SHUTDOWN; + } else { + return S_OK; + } +} + +void CEVRAllocatorPresenter::StartWorkerThreads() +{ + DWORD dwThreadId; + + if (m_nRenderState == Shutdown) { + m_hEvtQuit = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hEvtFlush = CreateEvent(nullptr, TRUE, FALSE, nullptr); + + m_hThread = ::CreateThread(nullptr, 0, PresentThread, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL); + m_hGetMixerThread = ::CreateThread(nullptr, 0, GetMixerThreadStatic, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hGetMixerThread, THREAD_PRIORITY_HIGHEST); + m_hVSyncThread = ::CreateThread(nullptr, 0, VSyncThreadStatic, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hVSyncThread, THREAD_PRIORITY_HIGHEST); + + m_nRenderState = Stopped; + TRACE_EVR("EVR: Worker threads started...\n"); + } +} + +void CEVRAllocatorPresenter::StopWorkerThreads() +{ + if (m_nRenderState != Shutdown) { + SetEvent(m_hEvtFlush); + m_bEvtFlush = true; + SetEvent(m_hEvtQuit); + m_bEvtQuit = true; + if (m_hThread && WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hThread, 0xDEAD); + } + if (m_hGetMixerThread && WaitForSingleObject(m_hGetMixerThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hGetMixerThread, 0xDEAD); + } + if (m_hVSyncThread && WaitForSingleObject(m_hVSyncThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hVSyncThread, 0xDEAD); + } + + SAFE_CLOSE_HANDLE(m_hThread); + SAFE_CLOSE_HANDLE(m_hGetMixerThread); + SAFE_CLOSE_HANDLE(m_hVSyncThread); + SAFE_CLOSE_HANDLE(m_hEvtFlush); + SAFE_CLOSE_HANDLE(m_hEvtQuit); + + m_bEvtFlush = false; + m_bEvtQuit = false; + + TRACE_EVR("EVR: Worker threads stopped...\n"); + } + m_nRenderState = Shutdown; +} + +STDMETHODIMP CEVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + + *ppRenderer = nullptr; + HRESULT hr = S_OK; + + CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; + + COuterEVR* pOuterEVR = DEBUG_NEW COuterEVR(NAME("COuterEVR"), pUnk, hr, &m_VMR9AlphaBitmap, this); + m_pOuterEVR = pOuterEVR; + + pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR); + CComQIPtr pBF = pUnk; + + if (FAILED(hr)) { + return E_FAIL; + } + + // Set EVR custom presenter + CComPtr pVP; + CComPtr pMFVR; + CComQIPtr pMFGS = pBF; + CComQIPtr pConfig = pBF; + if (SUCCEEDED(hr)) { + if (FAILED(pConfig->SetNumberOfStreams(m_bIsPreview?1:3))) { // TODO - maybe need other number of input stream ... + return E_FAIL; + } + } + + hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVR)); + + if (SUCCEEDED(hr)) { + hr = QueryInterface(IID_PPV_ARGS(&pVP)); + } + if (SUCCEEDED(hr)) { + hr = pMFVR->InitializeRenderer(nullptr, pVP); + } + + if (SUCCEEDED(hr)) { + if (!m_bIsPreview) { + CComPtr pPin = GetFirstPin(pBF); + if (HookNewSegment((IPinC*)(IPin*)pPin)) { + m_fUseInternalTimer = true; + m_bHookedNewSegment = true; + }; + } + *ppRenderer = pBF.Detach(); + } else { + *ppRenderer = nullptr; + } + + return hr; +} + +STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(bool bAll) +{ + return __super::Paint(bAll); +} + +STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(IMFSample* pMFSample) +{ + CAutoLock lock(&m_RenderLock); + + m_pCurrentlyDisplayedSample = pMFSample; + pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface); + + auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { + UINT32 nGroupId; + return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); + }; + ASSERT(sampleHasCurrentGroupId(pMFSample)); + + return Paint(true); +} + +STDMETHODIMP CEVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + HRESULT hr; + if (riid == __uuidof(IMFClockStateSink)) { + hr = GetInterface((IMFClockStateSink*)this, ppv); + } else if (riid == __uuidof(IMFVideoPresenter)) { + hr = GetInterface((IMFVideoPresenter*)this, ppv); + } else if (riid == __uuidof(IMFTopologyServiceLookupClient)) { + hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv); + } else if (riid == __uuidof(IMFVideoDeviceID)) { + hr = GetInterface((IMFVideoDeviceID*)this, ppv); + } else if (riid == __uuidof(IMFGetService)) { + hr = GetInterface((IMFGetService*)this, ppv); + } else if (riid == __uuidof(IMFAsyncCallback)) { + hr = GetInterface((IMFAsyncCallback*)this, ppv); + } else if (riid == __uuidof(IMFVideoDisplayControl)) { + hr = GetInterface((IMFVideoDisplayControl*)this, ppv); + } else if (riid == __uuidof(IMFVideoMixerBitmap)) { + hr = GetInterface((IMFVideoMixerBitmap*)this, ppv); + } else if (riid == __uuidof(IEVRTrustedVideoPlugin)) { + hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv); + } else if (riid == IID_IQualProp) { + hr = GetInterface((IQualProp*)this, ppv); + } else if (riid == __uuidof(IMFRateSupport)) { + hr = GetInterface((IMFRateSupport*)this, ppv); + } else if (riid == __uuidof(IDirect3DDeviceManager9)) + // hr = GetInterface((IDirect3DDeviceManager9*)this, ppv); + { + hr = m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppv); + } else if (riid == __uuidof(ID3DFullscreenControl)) { + hr = GetInterface((ID3DFullscreenControl*)this, ppv); + } else { + hr = __super::NonDelegatingQueryInterface(riid, ppv); + } + + return hr; +} + +// IMFClockStateSink +STDMETHODIMP CEVRAllocatorPresenter::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + + m_nRenderState = Started; + + TRACE_EVR("EVR: OnClockStart hnsSystemTime = %I64d, llClockStartOffset = %I64d\n", hnsSystemTime, llClockStartOffset); + m_ModeratedTimeLast = -1; + m_ModeratedClockLast = -1; + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::OnClockStop(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + + TRACE_EVR("EVR: OnClockStop hnsSystemTime = %I64d\n", hnsSystemTime); + m_nRenderState = Stopped; + + m_ModeratedClockLast = -1; + m_ModeratedTimeLast = -1; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::OnClockPause(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + + TRACE_EVR("EVR: OnClockPause hnsSystemTime = %I64d\n", hnsSystemTime); + if (!m_bSignaledStarvation) { + m_nRenderState = Paused; + } + m_ModeratedTimeLast = -1; + m_ModeratedClockLast = -1; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::OnClockRestart(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + + m_nRenderState = Started; + + m_ModeratedTimeLast = -1; + m_ModeratedClockLast = -1; + TRACE_EVR("EVR: OnClockRestart hnsSystemTime = %I64d\n", hnsSystemTime); + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::OnClockSetRate(MFTIME hnsSystemTime, float flRate) +{ + ASSERT(FALSE); + return E_NOTIMPL; +} + +// IBaseFilter delegate +bool CEVRAllocatorPresenter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue) +{ + CAutoLock lock(&m_SampleQueueLock); + + if (m_bSignaledStarvation) { + size_t nSamples = std::max(m_nNbDXSurface / 2, 1); + if ((m_ScheduledSamples.GetCount() < nSamples || m_LastSampleOffset < -m_rtTimePerFrame * 2) && !g_bNoDuration) { + *State = (FILTER_STATE)Paused; + _ReturnValue = VFW_S_STATE_INTERMEDIATE; + return true; + } + m_bSignaledStarvation = false; + } + return false; +} + +// IQualProp +STDMETHODIMP CEVRAllocatorPresenter::get_FramesDroppedInRenderer(int* pcFrames) +{ + *pcFrames = m_pcFrames; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_FramesDrawn(int* pcFramesDrawn) +{ + *pcFramesDrawn = m_pcFramesDrawn; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_AvgFrameRate(int* piAvgFrameRate) +{ + *piAvgFrameRate = (int)(m_fAvrFps * 100); + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_Jitter(int* iJitter) +{ + *iJitter = (int)((m_fJitterStdDev / 10000.0) + 0.5); + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_AvgSyncOffset(int* piAvg) +{ + *piAvg = (int)((m_fSyncOffsetAvr / 10000.0) + 0.5); + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_DevSyncOffset(int* piDev) +{ + *piDev = (int)((m_fSyncOffsetStdDev / 10000.0) + 0.5); + return S_OK; +} + +// IMFRateSupport + +STDMETHODIMP CEVRAllocatorPresenter::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) +{ + // TODO : not finished... + *pflRate = 0; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) +{ + HRESULT hr = S_OK; + float fMaxRate = 0.0f; + + CAutoLock lock(this); + + CheckPointer(pflRate, E_POINTER); + CHECK_HR(CheckShutdown()); + + // Get the maximum forward rate. + fMaxRate = GetMaxRate(fThin); + + // For reverse playback, swap the sign. + if (eDirection == MFRATE_REVERSE) { + fMaxRate = -fMaxRate; + } + + *pflRate = fMaxRate; + + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate) +{ + // fRate can be negative for reverse playback. + // pfNearestSupportedRate can be NULL. + + CAutoLock lock(this); + + HRESULT hr = S_OK; + float fMaxRate = 0.0f; + float fNearestRate = flRate; // Default. + + CheckPointer(pflNearestSupportedRate, E_POINTER); + CHECK_HR(CheckShutdown()); + + // Find the maximum forward rate. + fMaxRate = GetMaxRate(fThin); + + if (fabsf(flRate) > fMaxRate) { + // The (absolute) requested rate exceeds the maximum rate. + hr = MF_E_UNSUPPORTED_RATE; + + // The nearest supported rate is fMaxRate. + fNearestRate = fMaxRate; + if (flRate < 0) { + // For reverse playback, swap the sign. + fNearestRate = -fNearestRate; + } + } + + // Return the nearest supported rate if the caller requested it. + if (pflNearestSupportedRate != nullptr) { + *pflNearestSupportedRate = fNearestRate; + } + + return hr; +} + +float CEVRAllocatorPresenter::GetMaxRate(BOOL bThin) +{ + float fMaxRate = FLT_MAX; // Default. + UINT32 fpsNumerator = 0, fpsDenominator = 0; + + if (!bThin && (m_pMediaType != nullptr)) { + // Non-thinned: Use the frame rate and monitor refresh rate. + + // Frame rate: + MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE, + &fpsNumerator, &fpsDenominator); + + // Monitor refresh rate: + UINT MonitorRateHz = m_refreshRate; // D3DDISPLAYMODE + + if (fpsDenominator && fpsNumerator && MonitorRateHz) { + // Max Rate = Refresh Rate / Frame Rate + fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator); + } + } + return fMaxRate; +} + +void CEVRAllocatorPresenter::CompleteFrameStep(bool bCancel) +{ + if (m_nStepCount > 0) { + if (bCancel || (m_nStepCount == 1)) { + m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0); + m_nStepCount = 0; + } else { + m_nStepCount--; + } + } +} + +// IMFVideoPresenter +STDMETHODIMP CEVRAllocatorPresenter::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) +{ + HRESULT hr = S_OK; + CHECK_HR(CheckShutdown()); + + switch (eMessage) { + case MFVP_MESSAGE_BEGINSTREAMING: // The EVR switched from stopped to paused. The presenter should allocate resources + m_nRenderState = Paused; + ResetStats(); + TRACE_EVR("EVR: MFVP_MESSAGE_BEGINSTREAMING\n"); + break; + + case MFVP_MESSAGE_CANCELSTEP: // Cancels a frame step + TRACE_EVR("EVR: MFVP_MESSAGE_CANCELSTEP\n"); + CompleteFrameStep(true); + break; + + case MFVP_MESSAGE_ENDOFSTREAM: // All input streams have ended. + TRACE_EVR("EVR: MFVP_MESSAGE_ENDOFSTREAM\n"); + m_bPendingMediaFinished = true; + break; + + case MFVP_MESSAGE_ENDSTREAMING: // The EVR switched from running or paused to stopped. The presenter should free resources + m_nRenderState = Stopped; + TRACE_EVR("EVR: MFVP_MESSAGE_ENDSTREAMING\n"); + break; + + case MFVP_MESSAGE_FLUSH: // The presenter should discard any pending samples + SetEvent(m_hEvtFlush); + m_bEvtFlush = true; + TRACE_EVR("EVR: MFVP_MESSAGE_FLUSH\n"); + while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0) { + ; + } + break; + + case MFVP_MESSAGE_INVALIDATEMEDIATYPE: // The mixer's output format has changed. The EVR will initiate format negotiation, as described previously + /* + 1) The EVR sets the media type on the reference stream. + 2) The EVR calls IMFVideoPresenter::ProcessMessage on the presenter with the MFVP_MESSAGE_INVALIDATEMEDIATYPE message. + 3) The presenter sets the media type on the mixer's output stream. + 4) The EVR sets the media type on the substreams. + */ + m_bPendingRenegotiate = true; + while (m_bPendingRenegotiate) { + Sleep(1); + } + break; + + case MFVP_MESSAGE_PROCESSINPUTNOTIFY: // One input stream on the mixer has received a new sample + // GetImageFromMixer(); + break; + + case MFVP_MESSAGE_STEP: // Requests a frame step. + TRACE_EVR("EVR: MFVP_MESSAGE_STEP\n"); + m_nStepCount = (int)ulParam; + hr = S_OK; + break; + + default: + ASSERT(FALSE); + break; + } + return hr; +} + +HRESULT CEVRAllocatorPresenter::IsMediaTypeSupported(IMFMediaType* pMixerType) +{ + HRESULT hr; + + // We support only video types + GUID MajorType; + hr = pMixerType->GetMajorType(&MajorType); + + if (SUCCEEDED(hr)) { + if (MajorType != MFMediaType_Video) { + hr = MF_E_INVALIDMEDIATYPE; + } + } + + // We support only progressive formats + MFVideoInterlaceMode InterlaceMode = MFVideoInterlace_Unknown; + + if (SUCCEEDED(hr)) { + hr = pMixerType->GetUINT32(MF_MT_INTERLACE_MODE, (UINT32*)&InterlaceMode); + } + + if (SUCCEEDED(hr)) { + if (InterlaceMode != MFVideoInterlace_Progressive) { + hr = MF_E_INVALIDMEDIATYPE; + } + } + + // Check whether we support the surface format + int Merit = 0; + + if (SUCCEEDED(hr)) { + hr = GetMediaTypeMerit(pMixerType, &Merit); + } + + if (SUCCEEDED(hr)) { + if (Merit == 0) { + hr = MF_E_INVALIDMEDIATYPE; + } + } + + return hr; +} + +HRESULT CEVRAllocatorPresenter::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType) +{ + HRESULT hr; + IMFMediaType* pOptimalMediaType; + + CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType)); + CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType)); + + const GUID colorAttributes[] = { + MF_MT_VIDEO_LIGHTING, + MF_MT_VIDEO_PRIMARIES, + MF_MT_TRANSFER_FUNCTION, + MF_MT_YUV_MATRIX, + MF_MT_VIDEO_CHROMA_SITING + }; + + auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) { + PROPVARIANT val; + HRESULT hr = pFrom->GetItem(guidKey, &val); + + if (SUCCEEDED(hr)) { + hr = pTo->SetItem(guidKey, val); + PropVariantClear(&val); + } else if (hr == MF_E_ATTRIBUTENOTFOUND) { + hr = pTo->DeleteItem(guidKey); + } + return hr; + }; + + for (REFGUID guidKey : colorAttributes) { + if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) { + TRACE_EVR(_T("Copying color attribute %s failed: 0x%08x\n"), CComBSTR(guidKey), hr); + } + } + + pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0); + + const CRenderersSettings& r = GetRenderersSettings(); + + UINT32 nominalRange; + if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)) + && nominalRange == MFNominalRange_0_255) { + // EVR mixer always assumes 16-235 input. Bug? + // To keep untouched 0-255 range and avoid unwanted expansion we need to request 16-235 as output. + // To get 16-235 output we need to request 48-208 as output. + nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_48_208 : MFNominalRange_16_235; + } else { + nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255; + } + pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange); + m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange; + + ULARGE_INTEGER ui64Size; + pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart); + + CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart); + MFVideoArea Area = MakeArea(0, 0, videoSize.cx, videoSize.cy); + pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea)); + + ULARGE_INTEGER ui64AspectRatio; + pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart); + + UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart; + UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart; + UINT64 gcd = GCD(ui64ARx, ui64ARy); + if (gcd > 1) { + ui64ARx /= gcd; + ui64ARy /= gcd; + } + + CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy); + if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) { + SetVideoSize(videoSize, aspectRatio); + + // Notify the graph about the change + if (m_pSink) { + m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_nativeVideoSize.cx, m_nativeVideoSize.cy), 0); + } + } + + *ppType = pOptimalMediaType; + (*ppType)->AddRef(); + + return hr; +} + +HRESULT CEVRAllocatorPresenter::SetMediaType(IMFMediaType* pType) +{ + HRESULT hr = S_OK; + AM_MEDIA_TYPE* pAMMedia = nullptr; + + CHECK_HR(CheckShutdown()); + + if (!pType) { + // Release + RemoveAllSamples(); + DeleteSurfaces(); + CAutoLock lock(&m_MediaTypeLock); + m_pMediaType = nullptr; + return hr; + } + + DWORD dwFlags = 0; + if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) { + // Nothing to do + return hr; + } + + CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); + + hr = InitializeDevice(pType); + if (SUCCEEDED(hr)) { + CAutoLock lock(&m_MediaTypeLock); + m_pMediaType = pType; + + CString strTemp = GetMediaTypeName(pAMMedia->subtype); + strTemp.Replace(L"MEDIASUBTYPE_", L""); + CString strTemp1 = GetMediaTypeFormatDesc(pType); + strTemp1.Replace(L"D3DFMT_", L""); + m_strStatsMsg[MSG_MIXEROUT].Format(L"Mixer output : %-10s Type %-10s", strTemp.GetString(), strTemp1.GetString()); + } + + pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); + + return hr; +} + +HRESULT CEVRAllocatorPresenter::GetMediaTypeFourCC(IMFMediaType* pType, DWORD* pFourCC) +{ + CheckPointer(pFourCC, E_POINTER); + + HRESULT hr = S_OK; + GUID guidSubType = GUID_NULL; + + if (SUCCEEDED(hr)) { + hr = pType->GetGUID(MF_MT_SUBTYPE, &guidSubType); + } + + if (SUCCEEDED(hr)) { + *pFourCC = guidSubType.Data1; + } + + return hr; +} + +HRESULT CEVRAllocatorPresenter::GetMediaTypeMerit(IMFMediaType* pType, int* pMerit) +{ + DWORD Format; + HRESULT hr = GetMediaTypeFourCC(pType, &Format); + + if (SUCCEEDED(hr)) { + switch (Format) { + case FCC('AI44'): // Palettized, 4:4:4 + *pMerit = 31; + break; + case FCC('YVU9'): // 8-bit, 16:1:1 + *pMerit = 30; + break; + case FCC('NV11'): // 8-bit, 4:1:1 + *pMerit = 29; + break; + case FCC('Y41P'): + *pMerit = 28; + break; + case FCC('Y41T'): + *pMerit = 27; + break; + case FCC('P016'): // 4:2:0 + *pMerit = 26; + break; + case FCC('P010'): + *pMerit = 25; + break; + case FCC('IMC1'): + *pMerit = 24; + break; + case FCC('IMC3'): + *pMerit = 23; + break; + case FCC('IMC2'): + *pMerit = 22; + break; + case FCC('IMC4'): + *pMerit = 21; + break; + case FCC('YV12'): + *pMerit = 20; + break; + case FCC('NV12'): + *pMerit = 19; + break; + case FCC('I420'): + *pMerit = 18; + break; + case FCC('IYUV'): + *pMerit = 17; + break; + case FCC('Y216'): // 4:2:2 + *pMerit = 16; + break; + case FCC('v216'): + *pMerit = 15; + break; + case FCC('P216'): + *pMerit = 14; + break; + case FCC('Y210'): + *pMerit = 13; + break; + case FCC('v210'): + *pMerit = 12; + break; + case FCC('P210'): + *pMerit = 11; + break; + case FCC('YUY2'): + *pMerit = 10; + break; + case FCC('UYVY'): + *pMerit = 9; + break; + case FCC('Y42T'): + *pMerit = 8; + break; + case FCC('YVYU'): + *pMerit = 7; + break; + case FCC('Y416'): // 4:4:4 + *pMerit = 6; + break; + case FCC('Y410'): + *pMerit = 5; + break; + case FCC('v410'): + *pMerit = 4; + break; + case FCC('AYUV'): + *pMerit = 3; + break; + case D3DFMT_X8R8G8B8: + if (m_bForceInputHighColorResolution) { + *pMerit = 63; + } else { + *pMerit = 1; + } + break; + case D3DFMT_A8R8G8B8: // an accepted format, but fails on most surface types + case D3DFMT_A8B8G8R8: + case D3DFMT_X8B8G8R8: + case D3DFMT_R8G8B8: + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + case D3DFMT_A4R4G4B4: + case D3DFMT_R3G3B2: + case D3DFMT_A8R3G3B2: + case D3DFMT_X4R4G4B4: + case D3DFMT_A8P8: + case D3DFMT_P8: + *pMerit = 0; + break; + default: + *pMerit = 2; + break; + } + } + + return hr; +} + +LPCTSTR FindD3DFormat(const D3DFORMAT Format); + +LPCTSTR CEVRAllocatorPresenter::GetMediaTypeFormatDesc(IMFMediaType* pMediaType) +{ + D3DFORMAT Format = D3DFMT_UNKNOWN; + GetMediaTypeFourCC(pMediaType, (DWORD*)&Format); + return FindD3DFormat(Format); +} + +HRESULT CEVRAllocatorPresenter::RenegotiateMediaType() +{ + HRESULT hr = S_OK; + + CComPtr pMixerType; + CComPtr pMixerInputType; + CComPtr pType; + + if (!m_pMixer) { + return MF_E_INVALIDREQUEST; + } + + CInterfaceArray ValidMixerTypes; + + // Get the mixer's input type + hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType); + if (SUCCEEDED(hr)) { + AM_MEDIA_TYPE* pMT; + hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT); + if (SUCCEEDED(hr)) { + m_inputMediaType = *pMT; + pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT); + } + } + + // Loop through all of the mixer's proposed output types. + DWORD iTypeIndex = 0; + while ((hr != MF_E_NO_MORE_TYPES)) { + pMixerType = nullptr; + pType = nullptr; + + // Step 1. Get the next media type supported by mixer. + hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType); + if (FAILED(hr)) { + break; + } + + // Step 2. Check if we support this media type. + if (SUCCEEDED(hr)) { + hr = IsMediaTypeSupported(pMixerType); + } + + if (SUCCEEDED(hr)) { + hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType); + } + + // Step 4. Check if the mixer will accept this media type. + if (SUCCEEDED(hr)) { + hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY); + } + + int Merit = 0; + if (SUCCEEDED(hr)) { + hr = GetMediaTypeMerit(pType, &Merit); + } + + if (SUCCEEDED(hr)) { + size_t nTypes = ValidMixerTypes.GetCount(); + size_t iInsertPos = 0; + for (size_t i = 0; i < nTypes; ++i) { + int ThisMerit; + GetMediaTypeMerit(ValidMixerTypes[i], &ThisMerit); + + if (Merit > ThisMerit) { + iInsertPos = i; + break; + } else { + iInsertPos = i + 1; + } + } + + ValidMixerTypes.InsertAt(iInsertPos, pType); + } + } + + + size_t nValidTypes = ValidMixerTypes.GetCount(); +#ifdef _DEBUG + for (size_t i = 0; i < nValidTypes; ++i) { + // Step 3. Adjust the mixer's type to match our requirements. + pType = ValidMixerTypes[i]; + TRACE_EVR("EVR: Valid mixer output type: %ws\n", GetMediaTypeFormatDesc(pType)); + } +#endif + for (size_t i = 0; i < nValidTypes; ++i) { + // Step 4. Adjust the mixer's type to match our requirements. + pType = ValidMixerTypes[i]; + + TRACE_EVR("EVR: Trying mixer output type: %ws\n", GetMediaTypeFormatDesc(pType)); + + // Step 5. Try to set the media type on ourselves. + hr = SetMediaType(pType); + + // Step 6. Set output media type on mixer. + if (SUCCEEDED(hr)) { + hr = m_pMixer->SetOutputType(0, pType, 0); + + // If something went wrong, clear the media type. + if (FAILED(hr)) { + SetMediaType(nullptr); + } else { + break; + } + } + } + + pMixerType = nullptr; + pType = nullptr; + return hr; +} + +bool CEVRAllocatorPresenter::GetImageFromMixer() +{ + MFT_OUTPUT_DATA_BUFFER dataBuffer; + HRESULT hr = S_OK; + DWORD dwStatus; + REFERENCE_TIME nsSampleTime; + LONGLONG llClockBefore = 0; + LONGLONG llClockAfter = 0; + LONGLONG llMixerLatency; + UINT dwSurface; + + bool bDoneSomething = false; + + auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { + UINT32 nGroupId; + return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); + }; + + while (SUCCEEDED(hr)) { + CComPtr pSample; + + if (FAILED(GetFreeSample(&pSample))) { + break; + } + + ZeroMemory(&dataBuffer, sizeof(dataBuffer)); + dataBuffer.pSample = pSample; + pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface); + ASSERT(sampleHasCurrentGroupId(pSample)); + + { + llClockBefore = GetRenderersData()->GetPerfCounter(); + if (!m_pMixer) { + ASSERT(FALSE); + break; + } + hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus); + llClockAfter = GetRenderersData()->GetPerfCounter(); + } + + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { + AddToFreeList(pSample, false); + pSample = nullptr; // The sample should not be used after being queued + // Important: Release any events returned from the ProcessOutput method. + SAFE_RELEASE(dataBuffer.pEvents); + break; + } + + if (m_pSink) { + //CAutoLock autolock(this); We shouldn't need to lock here, m_pSink is thread safe + llMixerLatency = llClockAfter - llClockBefore; + m_pSink->Notify(EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0); + } + + pSample->GetSampleTime(&nsSampleTime); + REFERENCE_TIME nsDuration; + pSample->GetSampleDuration(&nsDuration); + + if (GetRenderersData()->m_bTearingTest) { + RECT rcTearing; + + rcTearing.left = m_nTearingPos; + rcTearing.top = 0; + rcTearing.right = rcTearing.left + 4; + rcTearing.bottom = m_nativeVideoSize.cy; + m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + + rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; + rcTearing.right = rcTearing.left + 4; + m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; + } + + TRACE_EVR("EVR: Get from Mixer : %u (%I64d) (%I64d)\n", dwSurface, nsSampleTime, m_rtTimePerFrame ? nsSampleTime / m_rtTimePerFrame : 0); + + if (SUCCEEDED(TrackSample(pSample))) { + AddToScheduledList(pSample, false); + pSample = nullptr; // The sample should not be used after being queued + bDoneSomething = true; + } else { + ASSERT(FALSE); + } + + // Important: Release any events returned from the ProcessOutput method. + SAFE_RELEASE(dataBuffer.pEvents); + + if (m_rtTimePerFrame == 0) { + break; + } + } + + return bDoneSomething; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType) +{ + HRESULT hr = S_OK; + CAutoLock lock(&m_MediaTypeLock); + + CheckPointer(ppMediaType, E_POINTER); + CHECK_HR(CheckShutdown()); + + if (!m_pMediaType) { + return MF_E_NOT_INITIALIZED; + } + + CHECK_HR(m_pMediaType->QueryInterface(IID_PPV_ARGS(ppMediaType))); + + return hr; +} + +// IMFTopologyServiceLookupClient +STDMETHODIMP CEVRAllocatorPresenter::InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup) +{ + HRESULT hr = S_OK; + DWORD dwObjects = 1; + + CAutoLock cThreadsLock(&m_ThreadsLock); + + TRACE_EVR("EVR: CEVRAllocatorPresenter::InitServicePointers\n"); + CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, + IID_PPV_ARGS(&m_pMixer), &dwObjects)); + + CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, + IID_PPV_ARGS(&m_pSink), &dwObjects)); + + pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, + IID_PPV_ARGS(&m_pClock), &dwObjects); + + + StartWorkerThreads(); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::ReleaseServicePointers() +{ + TRACE_EVR("EVR: CEVRAllocatorPresenter::ReleaseServicePointers\n"); + CAutoLock cThreadsLock(&m_ThreadsLock); + + StopWorkerThreads(); + + m_pMixer.Release(); + m_pSink.Release(); + m_pClock.Release(); + return S_OK; +} + +// IMFVideoDeviceID +STDMETHODIMP CEVRAllocatorPresenter::GetDeviceID(/* [out] */ __out IID* pDeviceID) +{ + CheckPointer(pDeviceID, E_POINTER); + *pDeviceID = IID_IDirect3DDevice9; + return S_OK; +} + +// IMFGetService +STDMETHODIMP CEVRAllocatorPresenter::GetService(/* [in] */ __RPC__in REFGUID guidService, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject) +{ + if (guidService == MR_VIDEO_RENDER_SERVICE) { + return NonDelegatingQueryInterface(riid, ppvObject); + } else if (guidService == MR_VIDEO_ACCELERATION_SERVICE) { + return m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppvObject); + } + + return E_NOINTERFACE; +} + +// IMFAsyncCallback +STDMETHODIMP CEVRAllocatorPresenter::GetParameters(/* [out] */ __RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CEVRAllocatorPresenter::Invoke(/* [in] */ __RPC__in_opt IMFAsyncResult* pAsyncResult) +{ + return E_NOTIMPL; +} + +// IMFVideoDisplayControl +STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) +{ + if (pszVideo) { + pszVideo->cx = m_nativeVideoSize.cx; + pszVideo->cy = m_nativeVideoSize.cy; + } + if (pszARVideo) { + pszARVideo->cx = m_aspectRatio.cx; + pszARVideo->cy = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) +{ + if (pszMin) { + pszMin->cx = 1; + pszMin->cy = 1; + } + + if (pszMax) { + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + + if (SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D), &d3ddm))) { + pszMax->cx = d3ddm.Width; + pszMax->cy = d3ddm.Height; + } + } + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) +{ + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) +{ + // Always all source rectangle ? + if (pnrcSource) { + pnrcSource->left = 0.0; + pnrcSource->top = 0.0; + pnrcSource->right = 1.0; + pnrcSource->bottom = 1.0; + } + + if (prcDest) { + memcpy(prcDest, &m_videoRect, sizeof(m_videoRect)); //GetClientRect (m_hWnd, prcDest); + } + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetAspectRatioMode(DWORD dwAspectRatioMode) +{ + m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetAspectRatioMode(DWORD* pdwAspectRatioMode) +{ + CheckPointer(pdwAspectRatioMode, E_POINTER); + *pdwAspectRatioMode = m_dwVideoAspectRatioMode; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetVideoWindow(HWND hwndVideo) +{ + if (m_hWnd != hwndVideo) { + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_RenderLock); + + m_hWnd = hwndVideo; + m_bPendingResetDevice = true; + if (m_pSink) { + m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); + } + SendResetRequest(); + } + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetVideoWindow(HWND* phwndVideo) +{ + CheckPointer(phwndVideo, E_POINTER); + *phwndVideo = m_hWnd; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::RepaintVideo() +{ + Paint(true); + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetCurrentImage(BITMAPINFOHEADER *pBih, BYTE **pDib, DWORD *pcbDib, LONGLONG *pTimeStamp) +{ + if (!pBih || !pDib || !pcbDib) { + return E_POINTER; + } + CheckPointer(m_pD3DDevEx, E_ABORT); + + HRESULT hr = S_OK; + const unsigned width = m_windowRect.Width(); + const unsigned height = m_windowRect.Height(); + const unsigned len = width * height * 4; + + memset(pBih, 0, sizeof(BITMAPINFOHEADER)); + pBih->biSize = sizeof(BITMAPINFOHEADER); + pBih->biWidth = width; + pBih->biHeight = height; + pBih->biBitCount = 32; + pBih->biPlanes = 1; + pBih->biSizeImage = DIBSIZE(*pBih); + + BYTE* p = (BYTE*)CoTaskMemAlloc(len); // only this allocator can be used + if (!p) { + return E_OUTOFMEMORY; + } + + CComPtr pBackBuffer; + CComPtr pDestSurface; + D3DLOCKED_RECT r; + if (FAILED(hr = m_pD3DDevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)) + || FAILED(hr = m_pD3DDevEx->CreateRenderTarget(width, height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pDestSurface, nullptr)) + || (FAILED(hr = m_pD3DDevEx->StretchRect(pBackBuffer, m_windowRect, pDestSurface, nullptr, D3DTEXF_NONE))) + || (FAILED(hr = pDestSurface->LockRect(&r, nullptr, D3DLOCK_READONLY)))) { + CString Error = GetWindowsErrorMessage(hr, nullptr); + TRACE_EVR(L"CEVRAllocatorPresenter::GetCurrentImage failed : %s", S_OK == hr ? L"S_OK" : Error.GetBuffer()); + CoTaskMemFree(p); + return hr; + } + + RetrieveBitmapData(width, height, 32, p, (BYTE*)r.pBits, r.Pitch); + + pDestSurface->UnlockRect(); + + *pDib = p; + *pcbDib = len; + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetBorderColor(COLORREF Clr) +{ + m_BorderColor = Clr; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetBorderColor(COLORREF* pClr) +{ + CheckPointer(pClr, E_POINTER); + *pClr = m_BorderColor; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetRenderingPrefs(DWORD dwRenderFlags) +{ + m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetRenderingPrefs(DWORD* pdwRenderFlags) +{ + CheckPointer(pdwRenderFlags, E_POINTER); + *pdwRenderFlags = m_dwVideoRenderPrefs; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetFullscreen(BOOL fFullscreen) +{ + m_bIsFullscreen = !!fFullscreen; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetFullscreen(BOOL* pfFullscreen) +{ + CheckPointer(pfFullscreen, E_POINTER); + *pfFullscreen = m_bIsFullscreen; + return S_OK; +} + +// IMFVideoMixerBitmap +STDMETHODIMP CEVRAllocatorPresenter::ClearAlphaBitmap() +{ + CAutoLock cRenderLock(&m_RenderLock); + m_bAlphaBitmapEnable = false; + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetAlphaBitmapParameters(MFVideoAlphaBitmapParams *pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock cRenderLock(&m_RenderLock); + + if (m_bAlphaBitmapEnable && m_pAlphaBitmapTexture) { + *pBmpParms = m_AlphaBitmapParams; // formal implementation, don't believe it + return S_OK; + } else { + return MF_E_NOT_INITIALIZED; + } +} + +STDMETHODIMP CEVRAllocatorPresenter::SetAlphaBitmap(const MFVideoAlphaBitmap *pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock cRenderLock(&m_RenderLock); + + CheckPointer(m_pD3DDevEx, E_ABORT); + HRESULT hr = S_OK; + + if (pBmpParms->GetBitmapFromDC && pBmpParms->bitmap.hdc) { + HBITMAP hBitmap = (HBITMAP)GetCurrentObject(pBmpParms->bitmap.hdc, OBJ_BITMAP); + if (!hBitmap) { + return E_INVALIDARG; + } + DIBSECTION info = { 0 }; + if (!::GetObjectW(hBitmap, sizeof(DIBSECTION), &info)) { + return E_INVALIDARG; + } + BITMAP& bm = info.dsBm; + if (!bm.bmWidth || !bm.bmHeight || bm.bmBitsPixel != 32 || !bm.bmBits) { + return E_INVALIDARG; + } + + if (m_pAlphaBitmapTexture) { + D3DSURFACE_DESC desc = {}; + m_pAlphaBitmapTexture->GetLevelDesc(0, &desc); + if (bm.bmWidth != desc.Width || bm.bmHeight != desc.Height) { + m_pAlphaBitmapTexture.Release(); + } + } + + if (!m_pAlphaBitmapTexture) { + hr = m_pD3DDevEx->CreateTexture(bm.bmWidth, bm.bmHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pAlphaBitmapTexture, nullptr); + } + + if (SUCCEEDED(hr)) { + CComPtr pSurface; + hr = m_pAlphaBitmapTexture->GetSurfaceLevel(0, &pSurface); + if (SUCCEEDED(hr)) { + D3DLOCKED_RECT lr; + hr = pSurface->LockRect(&lr, nullptr, D3DLOCK_DISCARD); + if (S_OK == hr) { + if (bm.bmWidthBytes == lr.Pitch) { + memcpy(lr.pBits, bm.bmBits, bm.bmWidthBytes * bm.bmHeight); + } + else { + LONG linesize = std::min(bm.bmWidthBytes, (LONG)lr.Pitch); + BYTE* src = (BYTE*)bm.bmBits; + BYTE* dst = (BYTE*)lr.pBits; + for (LONG y = 0; y < bm.bmHeight; ++y) { + memcpy(dst, src, linesize); + src += bm.bmWidthBytes; + dst += lr.Pitch; + } + } + hr = pSurface->UnlockRect(); + } + } + } + } else { + return E_INVALIDARG; + } + + m_bAlphaBitmapEnable = SUCCEEDED(hr) && m_pAlphaBitmapTexture; + + if (m_bAlphaBitmapEnable) { + hr = UpdateAlphaBitmapParameters(&pBmpParms->params); + } + + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams *pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock cRenderLock(&m_RenderLock); + + m_AlphaBitmapParams = *pBmpParms; // formal implementation, don't believe it + + return S_OK; +} + +// IEVRTrustedVideoPlugin +STDMETHODIMP CEVRAllocatorPresenter::IsInTrustedVideoMode(BOOL* pYes) +{ + CheckPointer(pYes, E_POINTER); + *pYes = TRUE; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::CanConstrict(BOOL* pYes) +{ + CheckPointer(pYes, E_POINTER); + *pYes = TRUE; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetConstriction(DWORD dwKPix) +{ + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::DisableImageExport(BOOL bDisable) +{ + return S_OK; +} + + +// IDirect3DDeviceManager9 +STDMETHODIMP CEVRAllocatorPresenter::ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken) +{ + HRESULT hr = m_pD3DManager->ResetDevice(pDevice, resetToken); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::OpenDeviceHandle(HANDLE* phDevice) +{ + HRESULT hr = m_pD3DManager->OpenDeviceHandle(phDevice); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::CloseDeviceHandle(HANDLE hDevice) +{ + HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::TestDevice(HANDLE hDevice) +{ + HRESULT hr = m_pD3DManager->TestDevice(hDevice); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock) +{ + HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::UnlockDevice(HANDLE hDevice, BOOL fSaveState) +{ + HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetVideoService(HANDLE hDevice, REFIID riid, void** ppService) +{ + HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService); + + if (riid == __uuidof(IDirectXVideoDecoderService)) { + UINT nNbDecoder = 5; + GUID* pDecoderGuid; + IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService; + pDXVAVideoDecoder->GetDecoderDeviceGuids(&nNbDecoder, &pDecoderGuid); + } else if (riid == __uuidof(IDirectXVideoProcessorService)) { + IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService; + UNREFERENCED_PARAMETER(pDXVAProcessor); + } + + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) +{ + // This function should be called... + ASSERT(FALSE); + + if (lpWidth) { + *lpWidth = m_nativeVideoSize.cx; + } + if (lpHeight) { + *lpHeight = m_nativeVideoSize.cy; + } + if (lpARWidth) { + *lpARWidth = m_aspectRatio.cx; + } + if (lpARHeight) { + *lpARHeight = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::InitializeDevice(IMFMediaType* pMediaType) +{ + HRESULT hr; + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_RenderLock); + + RemoveAllSamples(); + DeleteSurfaces(); + + // Retrieve the surface size and format + UINT32 Width; + UINT32 Height; + hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &Width, &Height); + + D3DFORMAT Format; + if (SUCCEEDED(hr)) { + SetVideoSize(CSize(Width, Height), m_aspectRatio); + hr = GetMediaTypeFourCC(pMediaType, (DWORD*)&Format); + } + + if (SUCCEEDED(hr)) { + hr = AllocSurfaces(); + } + + if (SUCCEEDED(hr)) { + for (int i = 0; i < m_nNbDXSurface; i++) { + CComPtr pMFSample; + hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); + + if (SUCCEEDED(hr)) { + pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); + pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + m_FreeSamples.AddTail(pMFSample); + pMFSample = nullptr; // The sample should not be used after being queued + } + ASSERT(SUCCEEDED(hr)); + } + } + + return hr; +} + +DWORD WINAPI CEVRAllocatorPresenter::GetMixerThreadStatic(LPVOID lpParam) +{ + SetThreadName(DWORD(-1), "CEVRPresenter::MixerThread"); + CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; + pThis->GetMixerThread(); + return 0; +} + +DWORD WINAPI CEVRAllocatorPresenter::PresentThread(LPVOID lpParam) +{ + SetThreadName(DWORD(-1), "CEVRPresenter::PresentThread"); + CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; + pThis->RenderThread(); + return 0; +} + +bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt) +{ + if (pmt->formattype == FORMAT_VideoInfo) { + return false; + } else if (pmt->formattype == FORMAT_VideoInfo2) { + return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; + } else if (pmt->formattype == FORMAT_MPEGVideo) { + return false; + } else if (pmt->formattype == FORMAT_MPEG2Video) { + return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; + } else { + return false; + } +} + +void CEVRAllocatorPresenter::GetMixerThread() +{ + HANDLE hEvts[] = { m_hEvtQuit}; + bool bQuit = false; + TIMECAPS tc; + DWORD dwResolution; + + // Tell Multimedia Class Scheduler we are a playback thread (increase priority) + //HANDLE hAvrt = 0; + //if (pfAvSetMmThreadCharacteristicsW) { + // DWORD dwTaskIndex = 0; + // hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); + // if (pfAvSetMmThreadPriority) { + // pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); + // } + //} + + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + timeBeginPeriod(dwResolution); + + while (!bQuit) { + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); + switch (dwObject) { + case WAIT_OBJECT_0: + bQuit = true; + break; + case WAIT_TIMEOUT: { + bool bDoneSomething = false; + { + CAutoLock AutoLock(&m_ImageProcessingLock); + bDoneSomething = GetImageFromMixer(); + } + if (m_rtTimePerFrame == 0 && bDoneSomething) { + //CAutoLock lock(this); + //CAutoLock lock2(&m_ImageProcessingLock); + //CAutoLock cRenderLock(&m_RenderLock); + + // Use the code from VMR9 to get the movie fps, as this method is reliable. + CComPtr pPin; + CMediaType mt; + if ( + SUCCEEDED(m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) && + SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); + + m_bInterlaced = ExtractInterlaced(&mt); + + CComPtr pPinTo; + if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { + m_Decoder = GetFilterName(GetFilterFromPin(pPinTo)); + } + } + // If framerate not set by Video Decoder choose 23.97... + if (m_rtTimePerFrame == 0) { + m_rtTimePerFrame = 417166; + } + + // Update internal subtitle clock + if (m_fUseInternalTimer && m_pSubPicQueue) { + m_fps = 10000000.0 / m_rtTimePerFrame; + m_pSubPicQueue->SetFPS(m_fps); + } + } + } + break; + } + } + + timeEndPeriod(dwResolution); + // if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt); +} + +void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed) +{ + double xbiss = (-(ChangeSpeed) * (ValuePrim) - (Value - Target) * (ChangeSpeed * ChangeSpeed) * 0.25f); + ValuePrim += xbiss; + Value += ValuePrim; +} + +LONGLONG CEVRAllocatorPresenter::GetClockTime(LONGLONG PerformanceCounter) +{ + LONGLONG llClockTime; + MFTIME nsCurrentTime; + m_pClock->GetCorrelatedTime(0, &llClockTime, &nsCurrentTime); + DWORD Characteristics = 0; + m_pClock->GetClockCharacteristics(&Characteristics); + MFCLOCK_STATE State; + m_pClock->GetState(0, &State); + + if (!(Characteristics & MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ)) { + MFCLOCK_PROPERTIES Props; + if (m_pClock->GetProperties(&Props) == S_OK) { + llClockTime = (llClockTime * 10000000) / Props.qwClockFrequency; // Make 10 MHz + } + + } + LONGLONG llPerf = PerformanceCounter; + //return llClockTime + (llPerf - nsCurrentTime); + double Target = llClockTime + (llPerf - nsCurrentTime) * m_ModeratedTimeSpeed; + + bool bReset = false; + if (m_ModeratedTimeLast < 0 || State != m_LastClockState || m_ModeratedClockLast < 0) { + bReset = true; + m_ModeratedTimeLast = llPerf; + m_ModeratedClockLast = llClockTime; + } + + m_LastClockState = State; + + LONGLONG TimeChangeM = llPerf - m_ModeratedTimeLast; + LONGLONG ClockChangeM = llClockTime - m_ModeratedClockLast; + UNREFERENCED_PARAMETER(ClockChangeM); + + m_ModeratedTimeLast = llPerf; + m_ModeratedClockLast = llClockTime; + +#if 1 + + if (bReset) { + m_ModeratedTimeSpeed = 1.0; + m_ModeratedTimeSpeedPrim = 0.0; + ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory)); + ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory)); + m_ClockTimeChangeHistoryPos = 0; + } + if (TimeChangeM) { + int Pos = m_ClockTimeChangeHistoryPos % 100; + int nHistory = std::min(m_ClockTimeChangeHistoryPos, 100); + ++m_ClockTimeChangeHistoryPos; + if (nHistory > 50) { + int iLastPos = (Pos - (nHistory)) % 100; + if (iLastPos < 0) { + iLastPos += 100; + } + + double TimeChange = llPerf - m_TimeChangeHistory[iLastPos]; + double ClockChange = llClockTime - m_ClockChangeHistory[iLastPos]; + + double ClockSpeedTarget = ClockChange / TimeChange; + double ChangeSpeed = 0.1; + if (ClockSpeedTarget > m_ModeratedTimeSpeed) { + if (ClockSpeedTarget / m_ModeratedTimeSpeed > 0.1) { + ChangeSpeed = 0.1; + } else { + ChangeSpeed = 0.01; + } + } else { + if (m_ModeratedTimeSpeed / ClockSpeedTarget > 0.1) { + ChangeSpeed = 0.1; + } else { + ChangeSpeed = 0.01; + } + } + ModerateFloat(m_ModeratedTimeSpeed, ClockSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed); + //m_ModeratedTimeSpeed = TimeChange / ClockChange; + } + m_TimeChangeHistory[Pos] = (double)llPerf; + m_ClockChangeHistory[Pos] = (double)llClockTime; + } + + return (LONGLONG)Target; +#else + double EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed + m_ClockDiffCalc; + double Diff = Target - EstimateTime; + + // > 5 ms just set it + if ((fabs(Diff) > 50000.0 || bReset)) { + + // TRACE_EVR("EVR: Reset clock at diff: %f ms\n", (m_ModeratedTime - Target) /10000.0); + if (State == MFCLOCK_STATE_RUNNING) { + if (bReset) { + m_ModeratedTimeSpeed = 1.0; + m_ModeratedTimeSpeedPrim = 0.0; + m_ClockDiffCalc = 0; + m_ClockDiffPrim = 0; + m_ModeratedTime = Target; + m_ModeratedTimer = llPerf; + } else { + EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed; + Diff = Target - EstimateTime; + m_ClockDiffCalc = Diff; + m_ClockDiffPrim = 0; + } + } else { + m_ModeratedTimeSpeed = 0.0; + m_ModeratedTimeSpeedPrim = 0.0; + m_ClockDiffCalc = 0; + m_ClockDiffPrim = 0; + m_ModeratedTime = Target; + m_ModeratedTimer = llPerf; + } + } + + { + LONGLONG ModerateTime = 10000; + double ChangeSpeed = 1.00; + /*if (m_ModeratedTimeSpeedPrim != 0.0) + { + if (m_ModeratedTimeSpeedPrim < 0.1) + ChangeSpeed = 0.1; + }*/ + + int nModerate = 0; + double Change = 0; + while (m_ModeratedTimer < llPerf - ModerateTime) { + m_ModeratedTimer += ModerateTime; + m_ModeratedTime += double(ModerateTime) * m_ModeratedTimeSpeed; + + double TimerDiff = llPerf - m_ModeratedTimer; + + double Diff = (double)(m_ModeratedTime - (Target - TimerDiff)); + + double TimeSpeedTarget; + double AbsDiff = fabs(Diff); + TimeSpeedTarget = 1.0 - (Diff / 1000000.0); + // TimeSpeedTarget = m_ModeratedTimeSpeed - (Diff / 100000000000.0); + //if (AbsDiff > 20000.0) + // TimeSpeedTarget = 1.0 - (Diff / 1000000.0); + /*else if (AbsDiff > 5000.0) + TimeSpeedTarget = 1.0 - (Diff / 100000000.0); + else + TimeSpeedTarget = 1.0 - (Diff / 500000000.0);*/ + double StartMod = m_ModeratedTimeSpeed; + ModerateFloat(m_ModeratedTimeSpeed, TimeSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed); + m_ModeratedTimeSpeed = TimeSpeedTarget; + ++nModerate; + Change += m_ModeratedTimeSpeed - StartMod; + } + if (nModerate) { + m_ModeratedTimeSpeedDiff = Change / nModerate; + } + + double Ret = m_ModeratedTime + double(llPerf - m_ModeratedTimer) * m_ModeratedTimeSpeed; + double Diff = Target - Ret; + ModerateFloat(m_ClockDiffCalc, Diff, m_ClockDiffPrim, ChangeSpeed * 0.1); + + Ret += m_ClockDiffCalc; + Diff = Target - Ret; + m_ClockDiff = Diff; + return LONGLONG(Ret + 0.5); + } + + return Target; + return LONGLONG(m_ModeratedTime + 0.5); +#endif +} + +void CEVRAllocatorPresenter::OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter) +{ + // This function is meant to be called only from the rendering function + // so with the ownership on m_RenderLock. + if (!m_pCurrentlyDisplayedSample || !m_OrderedPaint || !bAll) { + return; + } + + LONGLONG llClockTime; + LONGLONG nsSampleTime; + LONGLONG SampleDuration = 0; + LONGLONG TimePerFrame = m_rtTimePerFrame; + if (!TimePerFrame) { + return; + } + + if (!m_bSignaledStarvation) { + llClockTime = GetClockTime(PerformanceCounter); + m_StarvationClock = llClockTime; + } else { + llClockTime = m_StarvationClock; + } + + if (SUCCEEDED(m_pCurrentlyDisplayedSample->GetSampleDuration(&SampleDuration))) { + // Some filters return invalid values, ignore them + if (SampleDuration > MIN_FRAME_TIME) { + TimePerFrame = SampleDuration; + } + } + + if (FAILED(m_pCurrentlyDisplayedSample->GetSampleTime(&nsSampleTime))) { + nsSampleTime = llClockTime; + } + + { + m_nNextSyncOffset = (m_nNextSyncOffset + 1) % NB_JITTER; + LONGLONG SyncOffset = nsSampleTime - llClockTime; + + m_pllSyncOffset[m_nNextSyncOffset] = SyncOffset; + //TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d \n", m_nCurSurface, m_VSyncMode, m_LastPredictedSync, -SyncOffset, m_LastPredictedSync - (-SyncOffset)); + + m_MaxSyncOffset = MINLONG64; + m_MinSyncOffset = MAXLONG64; + + LONGLONG AvrageSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG Offset = m_pllSyncOffset[i]; + AvrageSum += Offset; + m_MaxSyncOffset = std::max(m_MaxSyncOffset, Offset); + m_MinSyncOffset = std::min(m_MinSyncOffset, Offset); + } + double MeanOffset = double(AvrageSum) / NB_JITTER; + double DeviationSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + double Deviation = double(m_pllSyncOffset[i]) - MeanOffset; + DeviationSum += Deviation * Deviation; + } + double StdDev = sqrt(DeviationSum / NB_JITTER); + + m_fSyncOffsetAvr = MeanOffset; + m_bSyncStatsAvailable = true; + m_fSyncOffsetStdDev = StdDev; + } +} + +STDMETHODIMP_(bool) CEVRAllocatorPresenter::ResetDevice() +{ + CAutoLock cThreadsLock(&m_ThreadsLock); + + StopWorkerThreads(); + + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_RenderLock); + + RemoveAllSamples(); + + bool bResult = __super::ResetDevice(); + + for (int i = 0; i < m_nNbDXSurface; i++) { + CComPtr pMFSample; + HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); + + if (SUCCEEDED(hr)) { + pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); + pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + m_FreeSamples.AddTail(pMFSample); + pMFSample = nullptr; // The sample should not be used after being queued + } + ASSERT(SUCCEEDED(hr)); + } + + if (bResult) { + StartWorkerThreads(); + } + + return bResult; +} + +STDMETHODIMP_(bool) CEVRAllocatorPresenter::DisplayChange() +{ + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_RenderLock); + + bool bResult = __super::DisplayChange(); + + m_DetectedFrameRate = 0.0; + m_DetectedFrameTime = 0.0; + m_DetectedFrameTimeStdDev = 0.0; + m_DetectedLock = false; + ZeroMemory(m_DetectedFrameTimeHistory, sizeof(m_DetectedFrameTimeHistory)); + ZeroMemory(m_DetectedFrameTimeHistoryHistory, sizeof(m_DetectedFrameTimeHistoryHistory)); + m_DetectedFrameTimePos = 0; + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + ZeroMemory(m_ldDetectedRefreshRateList, sizeof(m_ldDetectedRefreshRateList)); + ZeroMemory(m_ldDetectedScanlineRateList, sizeof(m_ldDetectedScanlineRateList)); + m_DetectedRefreshRatePos = 0; + m_DetectedRefreshTimePrim = 0; + m_DetectedScanlineTime = 0; + m_DetectedScanlineTimePrim = 0; + m_DetectedRefreshRate = 0; + + ZeroMemory(m_pllJitter, sizeof(m_pllJitter)); + ZeroMemory(m_pllSyncOffset, sizeof(m_pllSyncOffset)); + m_nNextJitter = 0; + m_nNextSyncOffset = 0; + m_llLastPerf = 0; + m_fAvrFps = 0.0; + m_fJitterStdDev = 0.0; + m_fSyncOffsetStdDev = 0.0; + m_fSyncOffsetAvr = 0.0; + m_bSyncStatsAvailable = false; + + return bResult; +} + +void CEVRAllocatorPresenter::RenderThread() +{ + HANDLE hEvts[] = { m_hEvtQuit, m_hEvtFlush}; + bool bQuit = false, bForcePaint = false; + TIMECAPS tc; + MFTIME nsSampleTime; + LONGLONG llClockTime; + + // Tell Multimedia Class Scheduler we are a playback thread (increase priority) + HANDLE hAvrt = 0; + if (fnAvSetMmThreadCharacteristicsW) { + DWORD dwTaskIndex = 0; + hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); + if (fnAvSetMmThreadPriority) { + fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); + } + } + + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + VERIFY(timeBeginPeriod(dwResolution) == 0); + + auto checkPendingMediaFinished = [this]() { + if (m_bPendingMediaFinished && m_nRenderState != Stopped) { + CAutoLock lock(&m_SampleQueueLock); + if (m_ScheduledSamples.IsEmpty()) { + m_bPendingMediaFinished = false; + m_pSink->Notify(EC_COMPLETE, 0, 0); + TRACE_EVR("EVR: send EC_COMPLETE\n"); + } + } + }; + + const CRenderersSettings& r = GetRenderersSettings(); + + auto SubPicSetTime = [&] { + if (!g_bExternalSubtitleTime && !m_bIsPreview) { + CSubPicAllocatorPresenterImpl::SetTime(g_tSegmentStart + nsSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); + } + }; + + int NextSleepTime = 1; + while (!bQuit) { + LONGLONG llPerf = GetRenderersData()->GetPerfCounter(); + UNREFERENCED_PARAMETER(llPerf); + if (!r.m_AdvRendSets.bVMR9VSyncAccurate && NextSleepTime == 0) { + NextSleepTime = 1; + } + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, std::max(NextSleepTime < 0 ? 1 : NextSleepTime, 0)); + /* dwObject = WAIT_TIMEOUT; + if (m_bEvtFlush) + dwObject = WAIT_OBJECT_0 + 1; + else if (m_bEvtQuit) + dwObject = WAIT_OBJECT_0;*/ + // if (NextSleepTime) + // TRACE_EVR("EVR: Sleep: %7.3f\n", double(GetRenderersData()->GetPerfCounter()-llPerf) / 10000.0); + if (NextSleepTime > 1) { + NextSleepTime = 0; + } else if (NextSleepTime == 0) { + NextSleepTime = -1; + } + switch (dwObject) { + case WAIT_OBJECT_0: + bQuit = true; + break; + case WAIT_OBJECT_0 + 1: + // Flush pending samples! + FlushSamples(); + m_bEvtFlush = false; + ResetEvent(m_hEvtFlush); + bForcePaint = true; + TRACE_EVR("EVR: Flush done!\n"); + break; + + case WAIT_TIMEOUT: + + if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != r.m_AdvRendSets.iEVROutputRange || m_bPendingRenegotiate) { + FlushSamples(); + RenegotiateMediaType(); + m_bPendingRenegotiate = false; + } + if (m_bPendingResetDevice) { + SendResetRequest(); + } + + // Discard timer events if playback stop + //if ((dwObject == WAIT_OBJECT_0 + 3) && (m_nRenderState != Started)) continue; + + //TRACE_EVR ("EVR: RenderThread ==>> Waiting buffer\n"); + + //if (WaitForMultipleObjects (_countof(hEvtsBuff), hEvtsBuff, FALSE, INFINITE) == WAIT_OBJECT_0+2) + { + CComPtr pMFSample; + //LONGLONG llPerf2 = GetRenderersData()->GetPerfCounter(); + //UNREFERENCED_PARAMETER(llPerf2); + int nSamplesLeft = 0; + if (SUCCEEDED(GetScheduledSample(&pMFSample, nSamplesLeft))) { + //UINT32 nSurface; + //pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&nSurface); + + bool bValidSampleTime = true; + HRESULT hrGetSampleTime = pMFSample->GetSampleTime(&nsSampleTime); + if (hrGetSampleTime != S_OK || nsSampleTime == 0) { + bValidSampleTime = false; + } + // We assume that all samples have the same duration + LONGLONG SampleDuration = 0; + bool bValidSampleDuration = true; + HRESULT hrGetSampleDuration = pMFSample->GetSampleDuration(&SampleDuration); + // Some filters return invalid values, ignore them + if (hrGetSampleDuration != S_OK || SampleDuration <= MIN_FRAME_TIME) { + bValidSampleDuration = false; + } + + //TRACE_EVR("EVR: RenderThread ==>> Presenting surface %d (%I64d)\n", nSurface, nsSampleTime); + + bool bStepForward = false; + + if (m_nStepCount < 0) { + // Drop frame + TRACE_EVR("EVR: Dropped frame\n"); + m_pcFrames++; + bStepForward = true; + m_nStepCount = 0; + /* + } else if (m_nStepCount > 0) { + ++m_OrderedPaint; + SubPicSetTime(); + Paint(pMFSample); + m_nDroppedUpdate = 0; + CompleteFrameStep(false); + bStepForward = true; + */ + } else if (m_nRenderState == Started) { + LONGLONG CurrentCounter = GetRenderersData()->GetPerfCounter(); + // Calculate wake up timer + if (!m_bSignaledStarvation) { + llClockTime = GetClockTime(CurrentCounter); + m_StarvationClock = llClockTime; + } else { + llClockTime = m_StarvationClock; + } + + if (!bValidSampleTime) { + // Just play as fast as possible + bStepForward = true; + ++m_OrderedPaint; + SubPicSetTime(); + Paint(pMFSample); + } else { + LONGLONG TimePerFrame = (LONGLONG)(GetFrameTime() * 10000000.0); + LONGLONG SyncOffset = 0; + LONGLONG VSyncTime = 0; + LONGLONG TimeToNextVSync = -1; + bool bVSyncCorrection = false; + double DetectedRefreshTime; + double DetectedScanlinesPerFrame; + double DetectedScanlineTime; + int DetectedRefreshRatePos; + { + CAutoLock Lock(&m_refreshRateLock); + DetectedRefreshTime = m_DetectedRefreshTime; + DetectedRefreshRatePos = m_DetectedRefreshRatePos; + DetectedScanlinesPerFrame = m_DetectedScanlinesPerFrame; + DetectedScanlineTime = m_DetectedScanlineTime; + } + + if (DetectedRefreshRatePos < 20 || !DetectedRefreshTime || !DetectedScanlinesPerFrame) { + DetectedRefreshTime = 1.0 / m_refreshRate; + DetectedScanlinesPerFrame = m_ScreenSize.cy; + DetectedScanlineTime = DetectedRefreshTime / double(m_ScreenSize.cy); + } + + if (r.m_AdvRendSets.bVMR9VSync) { + bVSyncCorrection = true; + double TargetVSyncPos = GetVBlackPos(); + double RefreshLines = DetectedScanlinesPerFrame; + double ScanlinesPerSecond = 1.0 / DetectedScanlineTime; + double CurrentVSyncPos = fmod(double(m_VBlankStartMeasure) + ScanlinesPerSecond * ((CurrentCounter - m_VBlankStartMeasureTime) / 10000000.0), RefreshLines); + double LinesUntilVSync = 0; + //TargetVSyncPos -= ScanlinesPerSecond * (DrawTime/10000000.0); + //TargetVSyncPos -= 10; + TargetVSyncPos = fmod(TargetVSyncPos, RefreshLines); + if (TargetVSyncPos < 0) { + TargetVSyncPos += RefreshLines; + } + if (TargetVSyncPos > CurrentVSyncPos) { + LinesUntilVSync = TargetVSyncPos - CurrentVSyncPos; + } else { + LinesUntilVSync = (RefreshLines - CurrentVSyncPos) + TargetVSyncPos; + } + double TimeUntilVSync = LinesUntilVSync * DetectedScanlineTime; + TimeToNextVSync = (LONGLONG)(TimeUntilVSync * 10000000.0); + VSyncTime = (LONGLONG)(DetectedRefreshTime * 10000000.0); + + LONGLONG ClockTimeAtNextVSync = llClockTime + (LONGLONG)(TimeUntilVSync * 10000000.0 * m_ModeratedTimeSpeed); + + SyncOffset = (nsSampleTime - ClockTimeAtNextVSync); + + //if (SyncOffset < 0) + // TRACE_EVR("EVR: SyncOffset(%d): %I64d %I64d %I64d\n", m_nCurSurface, SyncOffset, TimePerFrame, VSyncTime); + } else { + SyncOffset = (nsSampleTime - llClockTime); + } + + //LONGLONG SyncOffset = nsSampleTime - llClockTime; + TRACE_EVR("EVR: SyncOffset: %I64d SampleFrame: %I64d ClockFrame: %I64d\n", SyncOffset, TimePerFrame != 0 ? nsSampleTime / TimePerFrame : 0, TimePerFrame != 0 ? llClockTime / TimePerFrame : 0); + if (bValidSampleDuration && !m_DetectedLock) { + TimePerFrame = SampleDuration; + } + + LONGLONG MinMargin = MIN_FRAME_TIME + std::min(LONGLONG(m_DetectedFrameTimeStdDev), 20000ll); + //if (m_FrameTimeCorrection) { + // MinMargin = MIN_FRAME_TIME; + //} else { + // MinMargin = MIN_FRAME_TIME + std::min(LONGLONG(m_DetectedFrameTimeStdDev), 20000ll); + //} + LONGLONG TimePerFrameMargin = std::min(std::max(TimePerFrame * 2l / 100l, MinMargin), TimePerFrame * 11l / 100l); // (0.02..0.11)TimePerFrame + LONGLONG TimePerFrameMargin0 = TimePerFrameMargin / 2; + LONGLONG TimePerFrameMargin1 = 0; + + if (m_DetectedLock && TimePerFrame < VSyncTime) { + VSyncTime = TimePerFrame; + } + + if (m_VSyncMode == 1) { + TimePerFrameMargin1 = -TimePerFrameMargin; + } else if (m_VSyncMode == 2) { + TimePerFrameMargin1 = TimePerFrameMargin; + } + + m_LastSampleOffset = SyncOffset; + m_bLastSampleOffsetValid = true; + + LONGLONG VSyncOffset0 = 0; + bool bDoVSyncCorrection = false; + if ((SyncOffset < -(TimePerFrame + TimePerFrameMargin0 - TimePerFrameMargin1)) && nSamplesLeft > 0) { // Only drop if we have something else to display at once + // Drop frame + TRACE_EVR("EVR: Dropped frame\n"); + m_pcFrames++; + bStepForward = true; + ++m_nDroppedUpdate; + NextSleepTime = 0; + //VSyncOffset0 = (-SyncOffset) - VSyncTime; + //VSyncOffset0 = (-SyncOffset) - VSyncTime + TimePerFrameMargin1; + //m_LastPredictedSync = VSyncOffset0; + bDoVSyncCorrection = false; + } else if (SyncOffset < TimePerFrameMargin1) { + + if (bVSyncCorrection) { + VSyncOffset0 = -SyncOffset; + bDoVSyncCorrection = true; + } + + // Paint and prepare for next frame + TRACE_EVR("EVR: Normalframe\n"); + m_nDroppedUpdate = 0; + bStepForward = true; + m_LastFrameDuration = nsSampleTime - m_LastSampleTime; + m_LastSampleTime = nsSampleTime; + m_LastPredictedSync = VSyncOffset0; + + if (m_nStepCount > 0) { + CompleteFrameStep(false); + } + + ++m_OrderedPaint; + + SubPicSetTime(); + Paint(pMFSample); + + NextSleepTime = 0; + m_pcFramesDrawn++; + } else { + if (TimeToNextVSync >= 0 && SyncOffset > 0) { + NextSleepTime = (int)(TimeToNextVSync / 10000 - 2); + } else { + NextSleepTime = (int)(SyncOffset / 10000 - 2); + } + + if (NextSleepTime > TimePerFrame) { + NextSleepTime = 1; + } + + if (NextSleepTime < 0) { + NextSleepTime = 0; + } + NextSleepTime = 1; + //TRACE_EVR ("EVR: Delay\n"); + } + + if (bDoVSyncCorrection) { + //LONGLONG VSyncOffset0 = (((SyncOffset) % VSyncTime) + VSyncTime) % VSyncTime; + LONGLONG Margin = TimePerFrameMargin; + + LONGLONG VSyncOffsetMin = 30000000000000; + LONGLONG VSyncOffsetMax = -30000000000000; + for (int i = 0; i < 5; ++i) { + VSyncOffsetMin = std::min(m_VSyncOffsetHistory[i], VSyncOffsetMin); + VSyncOffsetMax = std::max(m_VSyncOffsetHistory[i], VSyncOffsetMax); + } + + m_VSyncOffsetHistory[m_VSyncOffsetHistoryPos] = VSyncOffset0; + m_VSyncOffsetHistoryPos = (m_VSyncOffsetHistoryPos + 1) % 5; + + //LONGLONG VSyncTime2 = VSyncTime2 + (VSyncOffsetMax - VSyncOffsetMin); + //VSyncOffsetMin; = (((VSyncOffsetMin) % VSyncTime) + VSyncTime) % VSyncTime; + //VSyncOffsetMax = (((VSyncOffsetMax) % VSyncTime) + VSyncTime) % VSyncTime; + + //TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d %8I64d\n", m_nCurSurface, m_VSyncMode,VSyncOffset0, VSyncOffsetMin, VSyncOffsetMax, VSyncOffsetMax - VSyncOffsetMin); + + if (m_VSyncMode == 0) { + // 23.976 in 60 Hz + if (VSyncOffset0 < Margin && VSyncOffsetMax > (VSyncTime - Margin)) { + m_VSyncMode = 2; + } else if (VSyncOffset0 > (VSyncTime - Margin) && VSyncOffsetMin < Margin) { + m_VSyncMode = 1; + } + } else if (m_VSyncMode == 2) { + if (VSyncOffsetMin > (Margin)) { + m_VSyncMode = 0; + } + } else if (m_VSyncMode == 1) { + if (VSyncOffsetMax < (VSyncTime - Margin)) { + m_VSyncMode = 0; + } + } + } + } + } else if (m_nRenderState == Paused) { + if (bForcePaint) { + bStepForward = true; + // Ensure that the renderer is properly updated after seeking when paused + SubPicSetTime(); + Paint(pMFSample); + } + NextSleepTime = int(SampleDuration / 10000 - 2); + } + + if (bStepForward) { + m_MaxSampleDuration = std::max(SampleDuration, m_MaxSampleDuration); + checkPendingMediaFinished(); + } else { + AddToScheduledList(pMFSample, true); + pMFSample = nullptr; // The sample should not be used after being queued + } + + bForcePaint = false; + } else if (m_bLastSampleOffsetValid && m_LastSampleOffset < -10000000) { // Only starve if we are 1 seconds behind + if (m_nRenderState == Started && !g_bNoDuration) { + m_pSink->Notify(EC_STARVATION, 0, 0); + m_bSignaledStarvation = true; + } + } else { + checkPendingMediaFinished(); + } + } + //else + //{ + // TRACE_EVR ("EVR: RenderThread ==>> Flush before rendering frame!\n"); + //} + + break; + } + } + + timeEndPeriod(dwResolution); + if (fnAvRevertMmThreadCharacteristics) { + fnAvRevertMmThreadCharacteristics(hAvrt); + } +} + +void CEVRAllocatorPresenter::VSyncThread() +{ + HANDLE hEvts[] = { m_hEvtQuit}; + bool bQuit = false; + TIMECAPS tc; + DWORD dwResolution; + + // Tell Multimedia Class Scheduler we are a playback thread (increase priority) + //HANDLE hAvrt = 0; + //if (pfAvSetMmThreadCharacteristicsW) { + // DWORD dwTaskIndex = 0; + // hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); + // if (pfAvSetMmThreadPriority) { + // pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); + // } + //} + + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + timeBeginPeriod(dwResolution); + const CRenderersData* rd = GetRenderersData(); + const CRenderersSettings& r = GetRenderersSettings(); + + while (!bQuit) { + + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); + switch (dwObject) { + case WAIT_OBJECT_0: + bQuit = true; + break; + case WAIT_TIMEOUT: { + // Do our stuff + if (m_pD3DDev && r.m_AdvRendSets.bVMR9VSync) { + if (m_nRenderState == Started) { + int VSyncPos = GetVBlackPos(); + int WaitRange = std::max(m_ScreenSize.cy / 40l, 5l); + int MinRange = std::max(std::min(long(0.003 * m_ScreenSize.cy * m_refreshRate + 0.5), m_ScreenSize.cy / 3l), 5l); // 1.8 ms or max 33 % of Time + + VSyncPos += MinRange + WaitRange; + + VSyncPos = VSyncPos % m_ScreenSize.cy; + if (VSyncPos < 0) { + VSyncPos += m_ScreenSize.cy; + } + + int ScanLine = 0; + int StartScanLine = ScanLine; + UNREFERENCED_PARAMETER(StartScanLine); + int LastPos = ScanLine; + UNREFERENCED_PARAMETER(LastPos); + ScanLine = (VSyncPos + 1) % m_ScreenSize.cy; + if (ScanLine < 0) { + ScanLine += m_ScreenSize.cy; + } + int ScanLineMiddle = ScanLine + m_ScreenSize.cy / 2; + ScanLineMiddle = ScanLineMiddle % m_ScreenSize.cy; + if (ScanLineMiddle < 0) { + ScanLineMiddle += m_ScreenSize.cy; + } + + int ScanlineStart = ScanLine; + HANDLE lockOwner = nullptr; + WaitForVBlankRange(ScanlineStart, 5, true, true, false, lockOwner); + LONGLONG TimeStart = rd->GetPerfCounter(); + + WaitForVBlankRange(ScanLineMiddle, 5, true, true, false, lockOwner); + LONGLONG TimeMiddle = rd->GetPerfCounter(); + + int ScanlineEnd = ScanLine; + WaitForVBlankRange(ScanlineEnd, 5, true, true, false, lockOwner); + LONGLONG TimeEnd = rd->GetPerfCounter(); + + double nSeconds = (TimeEnd - TimeStart) / 10000000.0; + LONGLONG llDiffMiddle = TimeMiddle - TimeStart; + ASSERT(llDiffMiddle > 0); + + if (nSeconds > 0.003 && llDiffMiddle > 0) { + double dDiffMiddle = double(llDiffMiddle); + double dDiffEnd = double(TimeEnd - TimeMiddle); + + double dDiffDiff = dDiffEnd / dDiffMiddle; + if (dDiffDiff < 1.3 && dDiffDiff > (1 / 1.3)) { + double ScanLineSeconds; + double nScanLines; + if (ScanLineMiddle > ScanlineEnd) { + ScanLineSeconds = dDiffMiddle / 10000000.0; + nScanLines = ScanLineMiddle - ScanlineStart; + } else { + ScanLineSeconds = dDiffEnd / 10000000.0; + nScanLines = ScanlineEnd - ScanLineMiddle; + } + + double ScanLineTime = ScanLineSeconds / nScanLines; + + int iPos = m_DetectedRefreshRatePos % 100; + m_ldDetectedScanlineRateList[iPos] = ScanLineTime; + if (m_DetectedScanlineTime && ScanlineStart != ScanlineEnd) { + int Diff = ScanlineEnd - ScanlineStart; + nSeconds -= double(Diff) * m_DetectedScanlineTime; + } + m_ldDetectedRefreshRateList[iPos] = nSeconds; + double Average = 0; + double AverageScanline = 0; + int nPos = std::min(iPos + 1, 100); + for (int i = 0; i < nPos; ++i) { + Average += m_ldDetectedRefreshRateList[i]; + AverageScanline += m_ldDetectedScanlineRateList[i]; + } + + if (nPos) { + Average /= double(nPos); + AverageScanline /= double(nPos); + } else { + Average = 0; + AverageScanline = 0; + } + + double ThisValue = Average; + + if (Average > 0.0 && AverageScanline > 0.0) { + CAutoLock Lock(&m_refreshRateLock); + ++m_DetectedRefreshRatePos; + if (m_DetectedRefreshTime == 0 || m_DetectedRefreshTime / ThisValue > 1.01 || m_DetectedRefreshTime / ThisValue < 0.99) { + m_DetectedRefreshTime = ThisValue; + m_DetectedRefreshTimePrim = 0; + } + if (_isnan(m_DetectedRefreshTime)) { + m_DetectedRefreshTime = 0.0; + } + if (_isnan(m_DetectedRefreshTimePrim)) { + m_DetectedRefreshTimePrim = 0.0; + } + + ModerateFloat(m_DetectedRefreshTime, ThisValue, m_DetectedRefreshTimePrim, 1.5); + if (m_DetectedRefreshTime > 0.0) { + m_DetectedRefreshRate = 1.0 / m_DetectedRefreshTime; + } else { + m_DetectedRefreshRate = 0.0; + } + + if (m_DetectedScanlineTime == 0 || m_DetectedScanlineTime / AverageScanline > 1.01 || m_DetectedScanlineTime / AverageScanline < 0.99) { + m_DetectedScanlineTime = AverageScanline; + m_DetectedScanlineTimePrim = 0; + } + ModerateFloat(m_DetectedScanlineTime, AverageScanline, m_DetectedScanlineTimePrim, 1.5); + if (m_DetectedScanlineTime > 0.0) { + m_DetectedScanlinesPerFrame = m_DetectedRefreshTime / m_DetectedScanlineTime; + } else { + m_DetectedScanlinesPerFrame = 0; + } + } + //TRACE(_T("Refresh: %f\n"), RefreshRate); + } + } + } + } else { + m_DetectedRefreshRate = 0.0; + m_DetectedScanlinesPerFrame = 0.0; + } + } + break; + } + } + + timeEndPeriod(dwResolution); + //if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt); +} + +DWORD WINAPI CEVRAllocatorPresenter::VSyncThreadStatic(LPVOID lpParam) +{ + SetThreadName(DWORD(-1), "CEVRAllocatorPresenter::VSyncThread"); + CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; + pThis->VSyncThread(); + return 0; +} + +void CEVRAllocatorPresenter::OnResetDevice() +{ + // Reset DXVA Manager, and get new buffers + m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); + + // Not necessary, but Microsoft documentation say Presenter should send this message... + if (m_pSink) { + m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); + } +} + +void CEVRAllocatorPresenter::RemoveAllSamples() +{ + CAutoLock imageProcesssingLock(&m_ImageProcessingLock); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + + FlushSamples(); + m_FreeSamples.RemoveAll(); + m_LastScheduledUncorrectedSampleTime = -1; + m_nUsedBuffer = 0; + // Increment the group id to make sure old samples will really be deleted + m_nCurrentGroupId++; +} + +HRESULT CEVRAllocatorPresenter::GetFreeSample(IMFSample** ppSample) +{ + CAutoLock lock(&m_SampleQueueLock); + HRESULT hr = S_OK; + + if (!m_FreeSamples.IsEmpty()) { + m_nUsedBuffer++; + *ppSample = m_FreeSamples.RemoveHead().Detach(); + } else { + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + } + + return hr; +} + +HRESULT CEVRAllocatorPresenter::GetScheduledSample(IMFSample** ppSample, int& count) +{ + CAutoLock lock(&m_SampleQueueLock); + HRESULT hr = S_OK; + + count = (int)m_ScheduledSamples.GetCount(); + if (count > 0) { + *ppSample = m_ScheduledSamples.RemoveHead().Detach(); + --count; + } else { + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + } + + return hr; +} + +void CEVRAllocatorPresenter::AddToFreeList(IMFSample* pSample, bool bTail) +{ + CAutoLock lock(&m_SampleQueueLock); + + m_nUsedBuffer--; + if (bTail) { + m_FreeSamples.AddTail(pSample); + } else { + m_FreeSamples.AddHead(pSample); + } +} + +void CEVRAllocatorPresenter::AddToScheduledList(IMFSample* pSample, bool bSorted) +{ + CAutoLock lock(&m_SampleQueueLock); + + if (bSorted) { + // Insert sorted + /*POSITION Iterator = m_ScheduledSamples.GetHeadPosition(); + + LONGLONG NewSampleTime; + pSample->GetSampleTime(&NewSampleTime); + + while (Iterator != nullptr) + { + POSITION CurrentPos = Iterator; + IMFSample *pIter = m_ScheduledSamples.GetNext(Iterator); + LONGLONG SampleTime; + pIter->GetSampleTime(&SampleTime); + if (NewSampleTime < SampleTime) + { + m_ScheduledSamples.InsertBefore(CurrentPos, pSample); + return; + } + }*/ + + m_ScheduledSamples.AddHead(pSample); + } else { + const CRenderersSettings& r = GetRenderersSettings(); + double ForceFPS = 0.0; + //double ForceFPS = 59.94; + //double ForceFPS = 23.976; + if (ForceFPS != 0.0) { + m_rtTimePerFrame = (REFERENCE_TIME)(10000000.0 / ForceFPS); + } + LONGLONG Duration = m_rtTimePerFrame; + UNREFERENCED_PARAMETER(Duration); + LONGLONG PrevTime = m_LastScheduledUncorrectedSampleTime; + LONGLONG Time; + LONGLONG SetDuration; + pSample->GetSampleDuration(&SetDuration); + pSample->GetSampleTime(&Time); + m_LastScheduledUncorrectedSampleTime = Time; + + m_bCorrectedFrameTime = false; + + LONGLONG Diff2 = PrevTime - (LONGLONG)(m_LastScheduledSampleTimeFP * 10000000.0); + LONGLONG Diff = Time - PrevTime; + if (PrevTime == -1) { + Diff = 0; + } + if (Diff < 0) { + Diff = -Diff; + } + if (Diff2 < 0) { + Diff2 = -Diff2; + } + if (Diff < m_rtTimePerFrame * 8 && m_rtTimePerFrame && Diff2 < m_rtTimePerFrame * 8) { // Detect seeking + int iPos = (m_DetectedFrameTimePos++) % 60; + Diff = Time - PrevTime; + if (PrevTime == -1) { + Diff = 0; + } + m_DetectedFrameTimeHistory[iPos] = Diff; + + if (m_DetectedFrameTimePos >= 10) { + int nFrames = std::min(m_DetectedFrameTimePos, 60); + LONGLONG DectedSum = 0; + for (int i = 0; i < nFrames; ++i) { + DectedSum += m_DetectedFrameTimeHistory[i]; + } + + double Average = double(DectedSum) / double(nFrames); + double DeviationSum = 0.0; + for (int i = 0; i < nFrames; ++i) { + double Deviation = m_DetectedFrameTimeHistory[i] - Average; + DeviationSum += Deviation * Deviation; + } + + double StdDev = sqrt(DeviationSum / double(nFrames)); + + m_DetectedFrameTimeStdDev = StdDev; + + double DetectedRate = 1.0 / (double(DectedSum) / (nFrames * 10000000.0)); + double AllowedError = 0.0003; + + static double AllowedValues[] = {60.0, 59.94, 50.0, 48.0, 47.952, 30.0, 29.97, 25.0, 24.0, 23.976}; + + int nAllowed = _countof(AllowedValues); + for (int i = 0; i < nAllowed; ++i) { + if (fabs(1.0 - DetectedRate / AllowedValues[i]) < AllowedError) { + DetectedRate = AllowedValues[i]; + break; + } + } + + m_DetectedFrameTimeHistoryHistory[m_DetectedFrameTimePos % 500] = DetectedRate; + + class CAutoInt + { + public: + + int m_Int; + + CAutoInt() { + m_Int = 0; + } + CAutoInt(int _Other) { + m_Int = _Other; + } + + operator int () const { + return m_Int; + } + + CAutoInt& operator ++ () { + ++m_Int; + return *this; + } + }; + + + CMap Map; + + for (int i = 0; i < 500; ++i) { + ++Map[m_DetectedFrameTimeHistoryHistory[i]]; + } + + POSITION Pos = Map.GetStartPosition(); + double BestVal = 0.0; + int BestNum = 5; + while (Pos) { + double Key; + CAutoInt Value; + Map.GetNextAssoc(Pos, Key, Value); + if (Value.m_Int > BestNum && Key != 0.0) { + BestNum = Value.m_Int; + BestVal = Key; + } + } + + m_DetectedLock = false; + for (int i = 0; i < nAllowed; ++i) { + if (BestVal == AllowedValues[i]) { + m_DetectedLock = true; + break; + } + } + if (BestVal != 0.0) { + m_DetectedFrameRate = BestVal; + m_DetectedFrameTime = 1.0 / BestVal; + } + } + + LONGLONG PredictedNext = PrevTime + m_rtTimePerFrame; + LONGLONG PredictedDiff = PredictedNext - Time; + if (PredictedDiff < 0) { + PredictedDiff = -PredictedDiff; + } + + if (m_DetectedFrameTime != 0.0 + //&& PredictedDiff > MIN_FRAME_TIME + && m_DetectedLock && r.m_AdvRendSets.bEVREnableFrameTimeCorrection) { + double CurrentTime = Time / 10000000.0; + double LastTime = m_LastScheduledSampleTimeFP; + double PredictedTime = LastTime + m_DetectedFrameTime; + if (fabs(PredictedTime - CurrentTime) > 0.0015) { // 1.5 ms wrong, lets correct + CurrentTime = PredictedTime; + Time = (LONGLONG)(CurrentTime * 10000000.0); + pSample->SetSampleTime(Time); + pSample->SetSampleDuration(LONGLONG(m_DetectedFrameTime * 10000000.0)); + m_bCorrectedFrameTime = true; + m_FrameTimeCorrection = 30; + } + m_LastScheduledSampleTimeFP = CurrentTime; + } else { + m_LastScheduledSampleTimeFP = Time / 10000000.0; + } + } else { + m_LastScheduledSampleTimeFP = Time / 10000000.0; + if (Diff > m_rtTimePerFrame * 8) { + // Seek + m_bSignaledStarvation = false; + m_DetectedFrameTimePos = 0; + m_DetectedLock = false; + } + } + + // TRACE_EVR("EVR: Time: %f %f %f\n", Time / 10000000.0, SetDuration / 10000000.0, m_DetectedFrameRate); + if (!m_bCorrectedFrameTime && m_FrameTimeCorrection) { + --m_FrameTimeCorrection; + } + +#if 0 + if (Time <= m_LastScheduledUncorrectedSampleTime && m_LastScheduledSampleTime >= 0) { + PrevTime = m_LastScheduledSampleTime; + } + + m_bCorrectedFrameTime = false; + if (PrevTime != -1 && (Time >= PrevTime - ((Duration * 20) / 9) || Time == 0) || ForceFPS != 0.0) { + if (Time - PrevTime > ((Duration * 20) / 9) && Time - PrevTime < Duration * 8 || Time == 0 || ((Time - PrevTime) < (Duration / 11)) || ForceFPS != 0.0) { + // Error!!!! + Time = PrevTime + Duration; + pSample->SetSampleTime(Time); + pSample->SetSampleDuration(Duration); + m_bCorrectedFrameTime = true; + TRACE_EVR("EVR: Corrected invalid sample time\n"); + } + } + if (Time + Duration * 10 < m_LastScheduledSampleTime) { + // Flush when repeating movie + FlushSamplesInternal(); + } +#endif + +#if 0 + static LONGLONG LastDuration = 0; + LONGLONG SetDuration = m_rtTimePerFrame; + pSample->GetSampleDuration(&SetDuration); + if (SetDuration != LastDuration) { + TRACE_EVR("EVR: Old duration: %I64d New duration: %I64d\n", LastDuration, SetDuration); + } + LastDuration = SetDuration; +#endif + m_LastScheduledSampleTime = Time; + + m_ScheduledSamples.AddTail(pSample); + } +} + +void CEVRAllocatorPresenter::FlushSamples() +{ + CAutoLock lock(this); + CAutoLock lock2(&m_SampleQueueLock); + CAutoLock lock3(&m_RenderLock); + + m_pCurrentlyDisplayedSample = nullptr; + m_ScheduledSamples.RemoveAll(); + + m_LastSampleOffset = 0; + m_bLastSampleOffsetValid = false; + m_bSignaledStarvation = false; + m_LastScheduledSampleTime = -1; +} + +HRESULT CEVRAllocatorPresenter::TrackSample(IMFSample* pSample) +{ + HRESULT hr = E_FAIL; + if (CComQIPtr pTracked = pSample) { + hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr); + } + return hr; +} + +HRESULT CEVRAllocatorPresenter::OnSampleFree(IMFAsyncResult* pResult) +{ + CComPtr pObject; + HRESULT hr = pResult->GetObject(&pObject); + if (SUCCEEDED(hr)) { + if (CComQIPtr pSample = pObject) { + // Ignore the sample if it is from an old group + UINT32 nGroupId; + CAutoLock sampleQueueLock(&m_SampleQueueLock); + if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) { + AddToFreeList(pSample, true); + pSample = nullptr; // The sample should not be used after being queued + } + } + } + return hr; +} diff --git a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h index 5f272b58346..3444f99ed3d 100644 --- a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h @@ -1,280 +1,280 @@ -/* - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include "DX9AllocatorPresenter.h" -#include // API Media Foundation -#include -#include "../../../DSUtil/WinapiFunc.h" -#include "AsyncCallback.h" - -namespace DSObjects -{ - class COuterEVR; - - class CEVRAllocatorPresenter : - public CDX9AllocatorPresenter, - public IMFGetService, - public IMFTopologyServiceLookupClient, - public IMFVideoDeviceID, - public IMFVideoPresenter, - public IDirect3DDeviceManager9, - - public IMFAsyncCallback, - public IQualProp, - public IMFRateSupport, - public IMFVideoDisplayControl, - public IMFVideoMixerBitmap, - public IEVRTrustedVideoPlugin - /* public IMFVideoPositionMapper, // Non mandatory EVR Presenter Interfaces (see later...) */ - { - public: - CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error, bool isPreview=false); - ~CEVRAllocatorPresenter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); - STDMETHODIMP InitializeDevice(IMFMediaType* pMediaType); - STDMETHODIMP_(bool) ResetDevice(); - STDMETHODIMP_(bool) DisplayChange(); - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() { - return (m_nRenderState == Started); - } - - // IMFClockStateSink - STDMETHODIMP OnClockStart(/* [in] */ MFTIME hnsSystemTime, /* [in] */ LONGLONG llClockStartOffset); - STDMETHODIMP OnClockStop(/* [in] */ MFTIME hnsSystemTime); - STDMETHODIMP OnClockPause(/* [in] */ MFTIME hnsSystemTime); - STDMETHODIMP OnClockRestart(/* [in] */ MFTIME hnsSystemTime); - STDMETHODIMP OnClockSetRate(/* [in] */ MFTIME hnsSystemTime, /* [in] */ float flRate); - - // IBaseFilter delegate - bool GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue); - - // IQualProp (EVR statistics window) - STDMETHODIMP get_FramesDroppedInRenderer(int* pcFrames); - STDMETHODIMP get_FramesDrawn(int* pcFramesDrawn); - STDMETHODIMP get_AvgFrameRate(int* piAvgFrameRate); - STDMETHODIMP get_Jitter(int* iJitter); - STDMETHODIMP get_AvgSyncOffset(int* piAvg); - STDMETHODIMP get_DevSyncOffset(int* piDev); - - - // IMFRateSupport - STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); - STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); - STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate); - - float GetMaxRate(BOOL bThin); - - - // IMFVideoPresenter - STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam); - STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType); - - // IMFTopologyServiceLookupClient - STDMETHODIMP InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup); - STDMETHODIMP ReleaseServicePointers(); - - // IMFVideoDeviceID - STDMETHODIMP GetDeviceID(/* [out] */ __out IID* pDeviceID); - - // IMFGetService - STDMETHODIMP GetService(/* [in] */ __RPC__in REFGUID guidService, - /* [in] */ __RPC__in REFIID riid, - /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject); - - // IMFAsyncCallback - STDMETHODIMP GetParameters(/* [out] */ __RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue); - STDMETHODIMP Invoke(/* [in] */ __RPC__in_opt IMFAsyncResult* pAsyncResult); - - // IMFVideoDisplayControl - STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo); - STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax); - STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest); - STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest); - STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode); - STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode); - STDMETHODIMP SetVideoWindow(HWND hwndVideo); - STDMETHODIMP GetVideoWindow(HWND* phwndVideo); - STDMETHODIMP RepaintVideo(); - STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp); - STDMETHODIMP SetBorderColor(COLORREF Clr); - STDMETHODIMP GetBorderColor(COLORREF* pClr); - STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags); - STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags); - STDMETHODIMP SetFullscreen(BOOL fFullscreen); - STDMETHODIMP GetFullscreen(BOOL* pfFullscreen); - - // IMFVideoMixerBitmap - STDMETHODIMP ClearAlphaBitmap(); - STDMETHODIMP GetAlphaBitmapParameters(MFVideoAlphaBitmapParams *pBmpParms); - STDMETHODIMP SetAlphaBitmap(const MFVideoAlphaBitmap *pBmpParms); - STDMETHODIMP UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams *pBmpParms); - - // IEVRTrustedVideoPlugin - STDMETHODIMP IsInTrustedVideoMode(BOOL* pYes); - STDMETHODIMP CanConstrict(BOOL* pYes); - STDMETHODIMP SetConstriction(DWORD dwKPix); - STDMETHODIMP DisableImageExport(BOOL bDisable); - - // IDirect3DDeviceManager9 - STDMETHODIMP ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken); - STDMETHODIMP OpenDeviceHandle(HANDLE* phDevice); - STDMETHODIMP CloseDeviceHandle(HANDLE hDevice); - STDMETHODIMP TestDevice(HANDLE hDevice); - STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock); - STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState); - STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void** ppService); - - protected: - STDMETHODIMP_(bool) Paint(IMFSample* pMFSample); - void OnResetDevice(); - virtual void OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter); - - double m_ModeratedTime; - LONGLONG m_ModeratedTimeLast; - LONGLONG m_ModeratedClockLast; - LONGLONG m_ModeratedTimer; - MFCLOCK_STATE m_LastClockState; - LONGLONG GetClockTime(LONGLONG PerformanceCounter); - - private: - - enum RENDER_STATE { - Stopped = State_Stopped, - Paused = State_Paused, - Started = State_Running, - Shutdown = State_Running + 1 - }; - - COuterEVR* m_pOuterEVR; - CComPtr m_pClock; - CComPtr m_pD3DManager; - CComPtr m_pMixer; - CComPtr m_pSink; - CComPtr m_pMediaType; - MFVideoAspectRatioMode m_dwVideoAspectRatioMode; - MFVideoRenderPrefs m_dwVideoRenderPrefs; - COLORREF m_BorderColor; - - - HANDLE m_hEvtQuit; // Stop rendering thread event - bool m_bEvtQuit; - HANDLE m_hEvtFlush; // Discard all buffers - bool m_bEvtFlush; - - bool m_fUseInternalTimer; - INT32 m_LastSetOutputRange; - std::atomic_bool m_bPendingRenegotiate; - bool m_bPendingMediaFinished; - - HANDLE m_hThread; - HANDLE m_hGetMixerThread; - HANDLE m_hVSyncThread; - RENDER_STATE m_nRenderState; - - CCritSec m_SampleQueueLock; - CCritSec m_ImageProcessingLock; - CCritSec m_MediaTypeLock; - CCritSec m_ThreadsLock; - - UINT32 m_nCurrentGroupId; - CInterfaceList m_FreeSamples; - CInterfaceList m_ScheduledSamples; - CComPtr m_pCurrentlyDisplayedSample; - bool m_bLastSampleOffsetValid; - LONGLONG m_LastScheduledSampleTime; - double m_LastScheduledSampleTimeFP; - LONGLONG m_LastScheduledUncorrectedSampleTime; - LONGLONG m_MaxSampleDuration; - LONGLONG m_LastSampleOffset; - LONGLONG m_VSyncOffsetHistory[5]; - LONGLONG m_LastPredictedSync; - int m_VSyncOffsetHistoryPos; - - UINT m_nResetToken; - int m_nStepCount; - - bool m_bSignaledStarvation; - LONGLONG m_StarvationClock; - - // Stats variable for IQualProp - UINT m_pcFrames; - UINT m_nDroppedUpdate; - UINT m_pcFramesDrawn; // Retrieves the number of frames drawn since streaming started - UINT m_piAvg; - UINT m_piDev; - - - void GetMixerThread(); - static DWORD WINAPI GetMixerThreadStatic(LPVOID lpParam); - - bool GetImageFromMixer(); - void RenderThread(); - static DWORD WINAPI PresentThread(LPVOID lpParam); - void ResetStats(); - void StartWorkerThreads(); - void StopWorkerThreads(); - HRESULT CheckShutdown() const; - void CompleteFrameStep(bool bCancel); - static DWORD WINAPI VSyncThreadStatic(LPVOID lpParam); - void VSyncThread(); - - void RemoveAllSamples(); - HRESULT GetFreeSample(IMFSample** ppSample); - HRESULT GetScheduledSample(IMFSample** ppSample, int& count); - void AddToFreeList(IMFSample* pSample, bool bTail); - void AddToScheduledList(IMFSample* pSample, bool bSorted); - void FlushSamples(); - - HRESULT TrackSample(IMFSample* pSample); - - // Callback when a video sample is released. - HRESULT OnSampleFree(IMFAsyncResult* pResult); - AsyncCallback m_SampleFreeCallback; - - // === Media type negotiation functions - HRESULT RenegotiateMediaType(); - HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType); - HRESULT CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** pType); - HRESULT SetMediaType(IMFMediaType* pType); - HRESULT GetMediaTypeFourCC(IMFMediaType* pType, DWORD* pFourCC); - HRESULT GetMediaTypeMerit(IMFMediaType* pType, int* pMerit); - LPCTSTR GetMediaTypeFormatDesc(IMFMediaType* pMediaType); - - const WinapiFunc fnDXVA2CreateDirect3DDeviceManager9; - const WinapiFunc fnMFCreateDXSurfaceBuffer; - const WinapiFunc fnMFCreateVideoSampleFromSurface; - const WinapiFunc fnMFCreateMediaType; - - const WinapiFunc fnAvSetMmThreadCharacteristicsW; - const WinapiFunc fnAvSetMmThreadPriority; - const WinapiFunc fnAvRevertMmThreadCharacteristics; - }; - -} +/* + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include "DX9AllocatorPresenter.h" +#include // API Media Foundation +#include +#include "../../../DSUtil/WinapiFunc.h" +#include "AsyncCallback.h" + +namespace DSObjects +{ + class COuterEVR; + + class CEVRAllocatorPresenter : + public CDX9AllocatorPresenter, + public IMFGetService, + public IMFTopologyServiceLookupClient, + public IMFVideoDeviceID, + public IMFVideoPresenter, + public IDirect3DDeviceManager9, + + public IMFAsyncCallback, + public IQualProp, + public IMFRateSupport, + public IMFVideoDisplayControl, + public IMFVideoMixerBitmap, + public IEVRTrustedVideoPlugin + /* public IMFVideoPositionMapper, // Non mandatory EVR Presenter Interfaces (see later...) */ + { + public: + CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error, bool isPreview=false); + ~CEVRAllocatorPresenter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); + STDMETHODIMP InitializeDevice(IMFMediaType* pMediaType); + STDMETHODIMP_(bool) ResetDevice(); + STDMETHODIMP_(bool) DisplayChange(); + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() { + return (m_nRenderState == Started); + } + + // IMFClockStateSink + STDMETHODIMP OnClockStart(/* [in] */ MFTIME hnsSystemTime, /* [in] */ LONGLONG llClockStartOffset); + STDMETHODIMP OnClockStop(/* [in] */ MFTIME hnsSystemTime); + STDMETHODIMP OnClockPause(/* [in] */ MFTIME hnsSystemTime); + STDMETHODIMP OnClockRestart(/* [in] */ MFTIME hnsSystemTime); + STDMETHODIMP OnClockSetRate(/* [in] */ MFTIME hnsSystemTime, /* [in] */ float flRate); + + // IBaseFilter delegate + bool GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue); + + // IQualProp (EVR statistics window) + STDMETHODIMP get_FramesDroppedInRenderer(int* pcFrames); + STDMETHODIMP get_FramesDrawn(int* pcFramesDrawn); + STDMETHODIMP get_AvgFrameRate(int* piAvgFrameRate); + STDMETHODIMP get_Jitter(int* iJitter); + STDMETHODIMP get_AvgSyncOffset(int* piAvg); + STDMETHODIMP get_DevSyncOffset(int* piDev); + + + // IMFRateSupport + STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); + STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); + STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate); + + float GetMaxRate(BOOL bThin); + + + // IMFVideoPresenter + STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam); + STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType); + + // IMFTopologyServiceLookupClient + STDMETHODIMP InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup); + STDMETHODIMP ReleaseServicePointers(); + + // IMFVideoDeviceID + STDMETHODIMP GetDeviceID(/* [out] */ __out IID* pDeviceID); + + // IMFGetService + STDMETHODIMP GetService(/* [in] */ __RPC__in REFGUID guidService, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject); + + // IMFAsyncCallback + STDMETHODIMP GetParameters(/* [out] */ __RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue); + STDMETHODIMP Invoke(/* [in] */ __RPC__in_opt IMFAsyncResult* pAsyncResult); + + // IMFVideoDisplayControl + STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo); + STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax); + STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest); + STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest); + STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode); + STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode); + STDMETHODIMP SetVideoWindow(HWND hwndVideo); + STDMETHODIMP GetVideoWindow(HWND* phwndVideo); + STDMETHODIMP RepaintVideo(); + STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp); + STDMETHODIMP SetBorderColor(COLORREF Clr); + STDMETHODIMP GetBorderColor(COLORREF* pClr); + STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags); + STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags); + STDMETHODIMP SetFullscreen(BOOL fFullscreen); + STDMETHODIMP GetFullscreen(BOOL* pfFullscreen); + + // IMFVideoMixerBitmap + STDMETHODIMP ClearAlphaBitmap(); + STDMETHODIMP GetAlphaBitmapParameters(MFVideoAlphaBitmapParams *pBmpParms); + STDMETHODIMP SetAlphaBitmap(const MFVideoAlphaBitmap *pBmpParms); + STDMETHODIMP UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams *pBmpParms); + + // IEVRTrustedVideoPlugin + STDMETHODIMP IsInTrustedVideoMode(BOOL* pYes); + STDMETHODIMP CanConstrict(BOOL* pYes); + STDMETHODIMP SetConstriction(DWORD dwKPix); + STDMETHODIMP DisableImageExport(BOOL bDisable); + + // IDirect3DDeviceManager9 + STDMETHODIMP ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken); + STDMETHODIMP OpenDeviceHandle(HANDLE* phDevice); + STDMETHODIMP CloseDeviceHandle(HANDLE hDevice); + STDMETHODIMP TestDevice(HANDLE hDevice); + STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock); + STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState); + STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void** ppService); + + protected: + STDMETHODIMP_(bool) Paint(IMFSample* pMFSample); + void OnResetDevice(); + virtual void OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter); + + double m_ModeratedTime; + LONGLONG m_ModeratedTimeLast; + LONGLONG m_ModeratedClockLast; + LONGLONG m_ModeratedTimer; + MFCLOCK_STATE m_LastClockState; + LONGLONG GetClockTime(LONGLONG PerformanceCounter); + + private: + + enum RENDER_STATE { + Stopped = State_Stopped, + Paused = State_Paused, + Started = State_Running, + Shutdown = State_Running + 1 + }; + + COuterEVR* m_pOuterEVR; + CComPtr m_pClock; + CComPtr m_pD3DManager; + CComPtr m_pMixer; + CComPtr m_pSink; + CComPtr m_pMediaType; + MFVideoAspectRatioMode m_dwVideoAspectRatioMode; + MFVideoRenderPrefs m_dwVideoRenderPrefs; + COLORREF m_BorderColor; + + + HANDLE m_hEvtQuit; // Stop rendering thread event + bool m_bEvtQuit; + HANDLE m_hEvtFlush; // Discard all buffers + bool m_bEvtFlush; + + bool m_fUseInternalTimer; + INT32 m_LastSetOutputRange; + std::atomic_bool m_bPendingRenegotiate; + bool m_bPendingMediaFinished; + + HANDLE m_hThread; + HANDLE m_hGetMixerThread; + HANDLE m_hVSyncThread; + RENDER_STATE m_nRenderState; + + CCritSec m_SampleQueueLock; + CCritSec m_ImageProcessingLock; + CCritSec m_MediaTypeLock; + CCritSec m_ThreadsLock; + + UINT32 m_nCurrentGroupId; + CInterfaceList m_FreeSamples; + CInterfaceList m_ScheduledSamples; + CComPtr m_pCurrentlyDisplayedSample; + bool m_bLastSampleOffsetValid; + LONGLONG m_LastScheduledSampleTime; + double m_LastScheduledSampleTimeFP; + LONGLONG m_LastScheduledUncorrectedSampleTime; + LONGLONG m_MaxSampleDuration; + LONGLONG m_LastSampleOffset; + LONGLONG m_VSyncOffsetHistory[5]; + LONGLONG m_LastPredictedSync; + int m_VSyncOffsetHistoryPos; + + UINT m_nResetToken; + int m_nStepCount; + + bool m_bSignaledStarvation; + LONGLONG m_StarvationClock; + + // Stats variable for IQualProp + UINT m_pcFrames; + UINT m_nDroppedUpdate; + UINT m_pcFramesDrawn; // Retrieves the number of frames drawn since streaming started + UINT m_piAvg; + UINT m_piDev; + + + void GetMixerThread(); + static DWORD WINAPI GetMixerThreadStatic(LPVOID lpParam); + + bool GetImageFromMixer(); + void RenderThread(); + static DWORD WINAPI PresentThread(LPVOID lpParam); + void ResetStats(); + void StartWorkerThreads(); + void StopWorkerThreads(); + HRESULT CheckShutdown() const; + void CompleteFrameStep(bool bCancel); + static DWORD WINAPI VSyncThreadStatic(LPVOID lpParam); + void VSyncThread(); + + void RemoveAllSamples(); + HRESULT GetFreeSample(IMFSample** ppSample); + HRESULT GetScheduledSample(IMFSample** ppSample, int& count); + void AddToFreeList(IMFSample* pSample, bool bTail); + void AddToScheduledList(IMFSample* pSample, bool bSorted); + void FlushSamples(); + + HRESULT TrackSample(IMFSample* pSample); + + // Callback when a video sample is released. + HRESULT OnSampleFree(IMFAsyncResult* pResult); + AsyncCallback m_SampleFreeCallback; + + // === Media type negotiation functions + HRESULT RenegotiateMediaType(); + HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType); + HRESULT CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** pType); + HRESULT SetMediaType(IMFMediaType* pType); + HRESULT GetMediaTypeFourCC(IMFMediaType* pType, DWORD* pFourCC); + HRESULT GetMediaTypeMerit(IMFMediaType* pType, int* pMerit); + LPCTSTR GetMediaTypeFormatDesc(IMFMediaType* pMediaType); + + const WinapiFunc fnDXVA2CreateDirect3DDeviceManager9; + const WinapiFunc fnMFCreateDXSurfaceBuffer; + const WinapiFunc fnMFCreateVideoSampleFromSurface; + const WinapiFunc fnMFCreateMediaType; + + const WinapiFunc fnAvSetMmThreadCharacteristicsW; + const WinapiFunc fnAvSetMmThreadPriority; + const WinapiFunc fnAvRevertMmThreadCharacteristics; + }; + +} diff --git a/src/filters/renderer/VideoRenderers/IPinHook.cpp b/src/filters/renderer/VideoRenderers/IPinHook.cpp index 2e973f4d1d4..c52478ba305 100644 --- a/src/filters/renderer/VideoRenderers/IPinHook.cpp +++ b/src/filters/renderer/VideoRenderers/IPinHook.cpp @@ -1,294 +1,294 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" - -#include -#include -#include -#include "moreuuids.h" - -#include "IPinHook.h" -#include "AllocatorCommon.h" - -#include "../../../mpc-hc/FGFilterLAV.h" -#include "Variables.h" - -REFERENCE_TIME g_tSegmentStart = 0; -REFERENCE_TIME g_tSampleStart = 0; -extern double g_dRate; - -IPinCVtbl* g_pPinCVtbl_NewSegment = nullptr; -IPinCVtbl* g_pPinCVtbl_ReceiveConnection = nullptr; -IMemInputPinCVtbl* g_pMemInputPinCVtbl = nullptr; -IPinC* g_pPinC_NewSegment = nullptr; - -struct D3DFORMAT_TYPE { - int Format; - LPCTSTR Description; -}; - -const D3DFORMAT_TYPE D3DFormatType[] = { - { D3DFMT_UNKNOWN, _T("D3DFMT_UNKNOWN ") }, - { D3DFMT_R8G8B8, _T("D3DFMT_R8G8B8 ") }, - { D3DFMT_A8R8G8B8, _T("D3DFMT_A8R8G8B8 ") }, - { D3DFMT_X8R8G8B8, _T("D3DFMT_X8R8G8B8 ") }, - { D3DFMT_R5G6B5, _T("D3DFMT_R5G6B5 ") }, - { D3DFMT_X1R5G5B5, _T("D3DFMT_X1R5G5B5 ") }, - { D3DFMT_A1R5G5B5, _T("D3DFMT_A1R5G5B5 ") }, - { D3DFMT_A4R4G4B4, _T("D3DFMT_A4R4G4B4 ") }, - { D3DFMT_R3G3B2, _T("D3DFMT_R3G3B2 ") }, - { D3DFMT_A8, _T("D3DFMT_A8 ") }, - { D3DFMT_A8R3G3B2, _T("D3DFMT_A8R3G3B2 ") }, - { D3DFMT_X4R4G4B4, _T("D3DFMT_X4R4G4B4 ") }, - { D3DFMT_A2B10G10R10, _T("D3DFMT_A2B10G10R10 ") }, - { D3DFMT_A8B8G8R8, _T("D3DFMT_A8B8G8R8 ") }, - { D3DFMT_X8B8G8R8, _T("D3DFMT_X8B8G8R8 ") }, - { D3DFMT_G16R16, _T("D3DFMT_G16R16 ") }, - { D3DFMT_A2R10G10B10, _T("D3DFMT_A2R10G10B10 ") }, - { D3DFMT_A16B16G16R16, _T("D3DFMT_A16B16G16R16 ") }, - { D3DFMT_A8P8, _T("D3DFMT_A8P8 ") }, - { D3DFMT_P8, _T("D3DFMT_P8 ") }, - { D3DFMT_L8, _T("D3DFMT_L8 ") }, - { D3DFMT_A8L8, _T("D3DFMT_A8L8 ") }, - { D3DFMT_A4L4, _T("D3DFMT_A4L4 ") }, - { D3DFMT_X8L8V8U8, _T("D3DFMT_X8L8V8U8 ") }, - { D3DFMT_Q8W8V8U8, _T("D3DFMT_Q8W8V8U8 ") }, - { D3DFMT_V16U16, _T("D3DFMT_V16U16 ") }, - { D3DFMT_A2W10V10U10, _T("D3DFMT_A2W10V10U10 ") }, - { D3DFMT_UYVY, _T("D3DFMT_UYVY ") }, - { D3DFMT_R8G8_B8G8, _T("D3DFMT_R8G8_B8G8 ") }, - { D3DFMT_YUY2, _T("D3DFMT_YUY2 ") }, - { D3DFMT_G8R8_G8B8, _T("D3DFMT_G8R8_G8B8 ") }, - { D3DFMT_DXT1, _T("D3DFMT_DXT1 ") }, - { D3DFMT_DXT2, _T("D3DFMT_DXT2 ") }, - { D3DFMT_DXT3, _T("D3DFMT_DXT3 ") }, - { D3DFMT_DXT4, _T("D3DFMT_DXT4 ") }, - { D3DFMT_DXT5, _T("D3DFMT_DXT5 ") }, - { D3DFMT_D16_LOCKABLE, _T("D3DFMT_D16_LOCKABLE ") }, - { D3DFMT_D32, _T("D3DFMT_D32 ") }, - { D3DFMT_D15S1, _T("D3DFMT_D15S1 ") }, - { D3DFMT_D24S8, _T("D3DFMT_D24S8 ") }, - { D3DFMT_D24X8, _T("D3DFMT_D24X8 ") }, - { D3DFMT_D24X4S4, _T("D3DFMT_D24X4S4 ") }, - { D3DFMT_D16, _T("D3DFMT_D16 ") }, - { D3DFMT_D32F_LOCKABLE, _T("D3DFMT_D32F_LOCKABLE") }, - { D3DFMT_D24FS8, _T("D3DFMT_D24FS8 ") }, - { D3DFMT_L16, _T("D3DFMT_L16 ") }, - { D3DFMT_VERTEXDATA, _T("D3DFMT_VERTEXDATA ") }, - { D3DFMT_INDEX16, _T("D3DFMT_INDEX16 ") }, - { D3DFMT_INDEX32, _T("D3DFMT_INDEX32 ") }, - { D3DFMT_Q16W16V16U16, _T("D3DFMT_Q16W16V16U16 ") }, - - { MAKEFOURCC('N', 'V', '1', '2'), _T("D3DFMT_NV12") }, - { MAKEFOURCC('N', 'V', '2', '4'), _T("D3DFMT_NV24") }, -}; - -LPCTSTR FindD3DFormat(const D3DFORMAT Format) -{ - for (int i = 0; i < _countof(D3DFormatType); i++) { - if (Format == D3DFormatType[i].Format) { - return D3DFormatType[i].Description; - } - } - - return D3DFormatType[0].Description; -} - -// === DirectShow hooks -static HRESULT(STDMETHODCALLTYPE* NewSegmentOrg)(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) = nullptr; - -static HRESULT STDMETHODCALLTYPE NewSegmentMine(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) -{ - if (g_pPinC_NewSegment == This) { - g_tSegmentStart = tStart; - g_dRate = dRate; - } - - return NewSegmentOrg(This, tStart, tStop, dRate); -} - -static HRESULT(STDMETHODCALLTYPE* ReceiveConnectionOrg)(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt) = nullptr; - -static HRESULT STDMETHODCALLTYPE ReceiveConnectionMine(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt) -{ - // Force-reject P010 and P016 pixel formats due to Microsoft bug ... - if (pmt && (pmt->subtype == MEDIASUBTYPE_P010 || pmt->subtype == MEDIASUBTYPE_P016)) { - // ... but allow LAV Video Decoder to do that itself in order to support 10bit DXVA. - if (GetCLSID((IPin*)pConnector) != GUID_LAVVideo) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } - - return ReceiveConnectionOrg(This, pConnector, pmt); -} - - -static HRESULT(STDMETHODCALLTYPE* ReceiveOrg)(IMemInputPinC* This, IMediaSample* pSample) = nullptr; - -static HRESULT STDMETHODCALLTYPE ReceiveMine(IMemInputPinC* This, IMediaSample* pSample) -{ - REFERENCE_TIME rtStart, rtStop; - if (pSample && SUCCEEDED(pSample->GetTime(&rtStart, &rtStop))) { - g_tSampleStart = rtStart; - } - return ReceiveOrg(This, pSample); -} - -bool HookReceiveConnection(IBaseFilter* pBF) -{ - if (!pBF || g_pPinCVtbl_ReceiveConnection) { - return false; - } - - if (CComPtr pPin = GetFirstPin(pBF)) { - IPinC* pPinC = (IPinC*)(IPin*)pPin; - - DWORD flOldProtect = 0; - if (VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - if (ReceiveConnectionOrg == nullptr) { - ReceiveConnectionOrg = pPinC->lpVtbl->ReceiveConnection; - } - pPinC->lpVtbl->ReceiveConnection = ReceiveConnectionMine; - FlushInstructionCache(GetCurrentProcess(), pPinC->lpVtbl, sizeof(IPinCVtbl)); - VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); - g_pPinCVtbl_ReceiveConnection = pPinC->lpVtbl; - return true; - } else { - TRACE(_T("HookWorkAroundVideoDriversBug: Could not hook the VTable")); - ASSERT(FALSE); - } - } - return false; -} - -void UnhookReceiveConnection() -{ - // Unhook previous VTable - if (g_pPinCVtbl_ReceiveConnection) { - DWORD flOldProtect = 0; - if (VirtualProtect(g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - if (g_pPinCVtbl_ReceiveConnection->ReceiveConnection == ReceiveConnectionMine) { - g_pPinCVtbl_ReceiveConnection->ReceiveConnection = ReceiveConnectionOrg; - } - ReceiveConnectionOrg = nullptr; - FlushInstructionCache(GetCurrentProcess(), g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl)); - VirtualProtect(g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); - g_pPinCVtbl_ReceiveConnection = nullptr; - } else { - TRACE(_T("UnhookReceiveConnection: Could not unhook previous VTable")); - ASSERT(FALSE); - } - } -} - -void UnhookNewSegment() -{ - // Unhook previous VTables - if (g_pPinCVtbl_NewSegment) { - DWORD flOldProtect = 0; - if (VirtualProtect(g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - if (g_pPinCVtbl_NewSegment->NewSegment == NewSegmentMine) { - g_pPinCVtbl_NewSegment->NewSegment = NewSegmentOrg; - } - FlushInstructionCache(GetCurrentProcess(), g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl)); - VirtualProtect(g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); - g_pPinCVtbl_NewSegment = nullptr; - g_pPinC_NewSegment = nullptr; - NewSegmentOrg = nullptr; - } else { - TRACE(_T("UnhookNewSegment: Could not unhook g_pPinCVtbl VTable")); - ASSERT(FALSE); - } - } -} - -void UnhookReceive() -{ - // Unhook previous VTables - if (g_pMemInputPinCVtbl) { - DWORD flOldProtect = 0; - if (VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - if (g_pMemInputPinCVtbl->Receive == ReceiveMine) { - g_pMemInputPinCVtbl->Receive = ReceiveOrg; - } - FlushInstructionCache(GetCurrentProcess(), g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl)); - VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect); - g_pMemInputPinCVtbl = nullptr; - ReceiveOrg = nullptr; - } else { - TRACE(_T("UnhookReceive: Could not unhook g_pMemInputPinCVtbl VTable")); - ASSERT(FALSE); - } - } -} - -bool HookNewSegment(IPinC* pPinC) -{ - if (!pPinC || g_pPinCVtbl_NewSegment) { - return false; - } - - DWORD flOldProtect = 0; - if (VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - g_tSegmentStart = 0; - g_dRate = 1.0; - if (NewSegmentOrg == nullptr) { - NewSegmentOrg = pPinC->lpVtbl->NewSegment; - } - pPinC->lpVtbl->NewSegment = NewSegmentMine; // Function sets global variable(s) - FlushInstructionCache(GetCurrentProcess(), pPinC->lpVtbl, sizeof(IPinCVtbl)); - VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); - g_pPinCVtbl_NewSegment = pPinC->lpVtbl; - g_pPinC_NewSegment = pPinC; - return true; - } else { - TRACE(_T("HookNewSegment: Could not unhook VTable")); - ASSERT(FALSE); - } - - return false; -} - -bool HookReceive(IMemInputPinC* pMemInputPinC) -{ - if (!pMemInputPinC || g_pMemInputPinCVtbl) { - return false; - } - - DWORD flOldProtect = 0; - if (VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - g_tSampleStart = 0; - if (ReceiveOrg == nullptr) { - ReceiveOrg = pMemInputPinC->lpVtbl->Receive; - } - pMemInputPinC->lpVtbl->Receive = ReceiveMine; // Function sets global variable(s) - FlushInstructionCache(GetCurrentProcess(), pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl)); - VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect); - g_pMemInputPinCVtbl = pMemInputPinC->lpVtbl; - return true; - } else { - TRACE(_T("HookReceive: Could not unhook VTable")); - ASSERT(FALSE); - } - - return false; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" + +#include +#include +#include +#include "moreuuids.h" + +#include "IPinHook.h" +#include "AllocatorCommon.h" + +#include "../../../mpc-hc/FGFilterLAV.h" +#include "Variables.h" + +REFERENCE_TIME g_tSegmentStart = 0; +REFERENCE_TIME g_tSampleStart = 0; +extern double g_dRate; + +IPinCVtbl* g_pPinCVtbl_NewSegment = nullptr; +IPinCVtbl* g_pPinCVtbl_ReceiveConnection = nullptr; +IMemInputPinCVtbl* g_pMemInputPinCVtbl = nullptr; +IPinC* g_pPinC_NewSegment = nullptr; + +struct D3DFORMAT_TYPE { + int Format; + LPCTSTR Description; +}; + +const D3DFORMAT_TYPE D3DFormatType[] = { + { D3DFMT_UNKNOWN, _T("D3DFMT_UNKNOWN ") }, + { D3DFMT_R8G8B8, _T("D3DFMT_R8G8B8 ") }, + { D3DFMT_A8R8G8B8, _T("D3DFMT_A8R8G8B8 ") }, + { D3DFMT_X8R8G8B8, _T("D3DFMT_X8R8G8B8 ") }, + { D3DFMT_R5G6B5, _T("D3DFMT_R5G6B5 ") }, + { D3DFMT_X1R5G5B5, _T("D3DFMT_X1R5G5B5 ") }, + { D3DFMT_A1R5G5B5, _T("D3DFMT_A1R5G5B5 ") }, + { D3DFMT_A4R4G4B4, _T("D3DFMT_A4R4G4B4 ") }, + { D3DFMT_R3G3B2, _T("D3DFMT_R3G3B2 ") }, + { D3DFMT_A8, _T("D3DFMT_A8 ") }, + { D3DFMT_A8R3G3B2, _T("D3DFMT_A8R3G3B2 ") }, + { D3DFMT_X4R4G4B4, _T("D3DFMT_X4R4G4B4 ") }, + { D3DFMT_A2B10G10R10, _T("D3DFMT_A2B10G10R10 ") }, + { D3DFMT_A8B8G8R8, _T("D3DFMT_A8B8G8R8 ") }, + { D3DFMT_X8B8G8R8, _T("D3DFMT_X8B8G8R8 ") }, + { D3DFMT_G16R16, _T("D3DFMT_G16R16 ") }, + { D3DFMT_A2R10G10B10, _T("D3DFMT_A2R10G10B10 ") }, + { D3DFMT_A16B16G16R16, _T("D3DFMT_A16B16G16R16 ") }, + { D3DFMT_A8P8, _T("D3DFMT_A8P8 ") }, + { D3DFMT_P8, _T("D3DFMT_P8 ") }, + { D3DFMT_L8, _T("D3DFMT_L8 ") }, + { D3DFMT_A8L8, _T("D3DFMT_A8L8 ") }, + { D3DFMT_A4L4, _T("D3DFMT_A4L4 ") }, + { D3DFMT_X8L8V8U8, _T("D3DFMT_X8L8V8U8 ") }, + { D3DFMT_Q8W8V8U8, _T("D3DFMT_Q8W8V8U8 ") }, + { D3DFMT_V16U16, _T("D3DFMT_V16U16 ") }, + { D3DFMT_A2W10V10U10, _T("D3DFMT_A2W10V10U10 ") }, + { D3DFMT_UYVY, _T("D3DFMT_UYVY ") }, + { D3DFMT_R8G8_B8G8, _T("D3DFMT_R8G8_B8G8 ") }, + { D3DFMT_YUY2, _T("D3DFMT_YUY2 ") }, + { D3DFMT_G8R8_G8B8, _T("D3DFMT_G8R8_G8B8 ") }, + { D3DFMT_DXT1, _T("D3DFMT_DXT1 ") }, + { D3DFMT_DXT2, _T("D3DFMT_DXT2 ") }, + { D3DFMT_DXT3, _T("D3DFMT_DXT3 ") }, + { D3DFMT_DXT4, _T("D3DFMT_DXT4 ") }, + { D3DFMT_DXT5, _T("D3DFMT_DXT5 ") }, + { D3DFMT_D16_LOCKABLE, _T("D3DFMT_D16_LOCKABLE ") }, + { D3DFMT_D32, _T("D3DFMT_D32 ") }, + { D3DFMT_D15S1, _T("D3DFMT_D15S1 ") }, + { D3DFMT_D24S8, _T("D3DFMT_D24S8 ") }, + { D3DFMT_D24X8, _T("D3DFMT_D24X8 ") }, + { D3DFMT_D24X4S4, _T("D3DFMT_D24X4S4 ") }, + { D3DFMT_D16, _T("D3DFMT_D16 ") }, + { D3DFMT_D32F_LOCKABLE, _T("D3DFMT_D32F_LOCKABLE") }, + { D3DFMT_D24FS8, _T("D3DFMT_D24FS8 ") }, + { D3DFMT_L16, _T("D3DFMT_L16 ") }, + { D3DFMT_VERTEXDATA, _T("D3DFMT_VERTEXDATA ") }, + { D3DFMT_INDEX16, _T("D3DFMT_INDEX16 ") }, + { D3DFMT_INDEX32, _T("D3DFMT_INDEX32 ") }, + { D3DFMT_Q16W16V16U16, _T("D3DFMT_Q16W16V16U16 ") }, + + { MAKEFOURCC('N', 'V', '1', '2'), _T("D3DFMT_NV12") }, + { MAKEFOURCC('N', 'V', '2', '4'), _T("D3DFMT_NV24") }, +}; + +LPCTSTR FindD3DFormat(const D3DFORMAT Format) +{ + for (int i = 0; i < _countof(D3DFormatType); i++) { + if (Format == D3DFormatType[i].Format) { + return D3DFormatType[i].Description; + } + } + + return D3DFormatType[0].Description; +} + +// === DirectShow hooks +static HRESULT(STDMETHODCALLTYPE* NewSegmentOrg)(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) = nullptr; + +static HRESULT STDMETHODCALLTYPE NewSegmentMine(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) +{ + if (g_pPinC_NewSegment == This) { + g_tSegmentStart = tStart; + g_dRate = dRate; + } + + return NewSegmentOrg(This, tStart, tStop, dRate); +} + +static HRESULT(STDMETHODCALLTYPE* ReceiveConnectionOrg)(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt) = nullptr; + +static HRESULT STDMETHODCALLTYPE ReceiveConnectionMine(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt) +{ + // Force-reject P010 and P016 pixel formats due to Microsoft bug ... + if (pmt && (pmt->subtype == MEDIASUBTYPE_P010 || pmt->subtype == MEDIASUBTYPE_P016)) { + // ... but allow LAV Video Decoder to do that itself in order to support 10bit DXVA. + if (GetCLSID((IPin*)pConnector) != GUID_LAVVideo) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } + + return ReceiveConnectionOrg(This, pConnector, pmt); +} + + +static HRESULT(STDMETHODCALLTYPE* ReceiveOrg)(IMemInputPinC* This, IMediaSample* pSample) = nullptr; + +static HRESULT STDMETHODCALLTYPE ReceiveMine(IMemInputPinC* This, IMediaSample* pSample) +{ + REFERENCE_TIME rtStart, rtStop; + if (pSample && SUCCEEDED(pSample->GetTime(&rtStart, &rtStop))) { + g_tSampleStart = rtStart; + } + return ReceiveOrg(This, pSample); +} + +bool HookReceiveConnection(IBaseFilter* pBF) +{ + if (!pBF || g_pPinCVtbl_ReceiveConnection) { + return false; + } + + if (CComPtr pPin = GetFirstPin(pBF)) { + IPinC* pPinC = (IPinC*)(IPin*)pPin; + + DWORD flOldProtect = 0; + if (VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + if (ReceiveConnectionOrg == nullptr) { + ReceiveConnectionOrg = pPinC->lpVtbl->ReceiveConnection; + } + pPinC->lpVtbl->ReceiveConnection = ReceiveConnectionMine; + FlushInstructionCache(GetCurrentProcess(), pPinC->lpVtbl, sizeof(IPinCVtbl)); + VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); + g_pPinCVtbl_ReceiveConnection = pPinC->lpVtbl; + return true; + } else { + TRACE(_T("HookWorkAroundVideoDriversBug: Could not hook the VTable")); + ASSERT(FALSE); + } + } + return false; +} + +void UnhookReceiveConnection() +{ + // Unhook previous VTable + if (g_pPinCVtbl_ReceiveConnection) { + DWORD flOldProtect = 0; + if (VirtualProtect(g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + if (g_pPinCVtbl_ReceiveConnection->ReceiveConnection == ReceiveConnectionMine) { + g_pPinCVtbl_ReceiveConnection->ReceiveConnection = ReceiveConnectionOrg; + } + ReceiveConnectionOrg = nullptr; + FlushInstructionCache(GetCurrentProcess(), g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl)); + VirtualProtect(g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); + g_pPinCVtbl_ReceiveConnection = nullptr; + } else { + TRACE(_T("UnhookReceiveConnection: Could not unhook previous VTable")); + ASSERT(FALSE); + } + } +} + +void UnhookNewSegment() +{ + // Unhook previous VTables + if (g_pPinCVtbl_NewSegment) { + DWORD flOldProtect = 0; + if (VirtualProtect(g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + if (g_pPinCVtbl_NewSegment->NewSegment == NewSegmentMine) { + g_pPinCVtbl_NewSegment->NewSegment = NewSegmentOrg; + } + FlushInstructionCache(GetCurrentProcess(), g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl)); + VirtualProtect(g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); + g_pPinCVtbl_NewSegment = nullptr; + g_pPinC_NewSegment = nullptr; + NewSegmentOrg = nullptr; + } else { + TRACE(_T("UnhookNewSegment: Could not unhook g_pPinCVtbl VTable")); + ASSERT(FALSE); + } + } +} + +void UnhookReceive() +{ + // Unhook previous VTables + if (g_pMemInputPinCVtbl) { + DWORD flOldProtect = 0; + if (VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + if (g_pMemInputPinCVtbl->Receive == ReceiveMine) { + g_pMemInputPinCVtbl->Receive = ReceiveOrg; + } + FlushInstructionCache(GetCurrentProcess(), g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl)); + VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect); + g_pMemInputPinCVtbl = nullptr; + ReceiveOrg = nullptr; + } else { + TRACE(_T("UnhookReceive: Could not unhook g_pMemInputPinCVtbl VTable")); + ASSERT(FALSE); + } + } +} + +bool HookNewSegment(IPinC* pPinC) +{ + if (!pPinC || g_pPinCVtbl_NewSegment) { + return false; + } + + DWORD flOldProtect = 0; + if (VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + g_tSegmentStart = 0; + g_dRate = 1.0; + if (NewSegmentOrg == nullptr) { + NewSegmentOrg = pPinC->lpVtbl->NewSegment; + } + pPinC->lpVtbl->NewSegment = NewSegmentMine; // Function sets global variable(s) + FlushInstructionCache(GetCurrentProcess(), pPinC->lpVtbl, sizeof(IPinCVtbl)); + VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); + g_pPinCVtbl_NewSegment = pPinC->lpVtbl; + g_pPinC_NewSegment = pPinC; + return true; + } else { + TRACE(_T("HookNewSegment: Could not unhook VTable")); + ASSERT(FALSE); + } + + return false; +} + +bool HookReceive(IMemInputPinC* pMemInputPinC) +{ + if (!pMemInputPinC || g_pMemInputPinCVtbl) { + return false; + } + + DWORD flOldProtect = 0; + if (VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + g_tSampleStart = 0; + if (ReceiveOrg == nullptr) { + ReceiveOrg = pMemInputPinC->lpVtbl->Receive; + } + pMemInputPinC->lpVtbl->Receive = ReceiveMine; // Function sets global variable(s) + FlushInstructionCache(GetCurrentProcess(), pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl)); + VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect); + g_pMemInputPinCVtbl = pMemInputPinC->lpVtbl; + return true; + } else { + TRACE(_T("HookReceive: Could not unhook VTable")); + ASSERT(FALSE); + } + + return false; +} diff --git a/src/filters/renderer/VideoRenderers/IPinHook.h b/src/filters/renderer/VideoRenderers/IPinHook.h index ccaa75c3d6a..bf7108b751c 100644 --- a/src/filters/renderer/VideoRenderers/IPinHook.h +++ b/src/filters/renderer/VideoRenderers/IPinHook.h @@ -1,82 +1,82 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#pragma once - -interface IPinC; - -typedef struct IPinCVtbl { - BEGIN_INTERFACE - HRESULT(STDMETHODCALLTYPE* QueryInterface)(IPinC* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject); - ULONG(STDMETHODCALLTYPE* AddRef)(IPinC* This); - ULONG(STDMETHODCALLTYPE* Release)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* Connect)(IPinC* This, /* [in] */ IPinC* pReceivePin, /* [in] */ const AM_MEDIA_TYPE* pmt); - HRESULT(STDMETHODCALLTYPE* ReceiveConnection)(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt); - HRESULT(STDMETHODCALLTYPE* Disconnect)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* ConnectedTo)(IPinC* This, /* [out] */ IPinC** pPin); - HRESULT(STDMETHODCALLTYPE* ConnectionMediaType)(IPinC* This, /* [out] */ AM_MEDIA_TYPE* pmt); - HRESULT(STDMETHODCALLTYPE* QueryPinInfo)(IPinC* This, /* [out] */ PIN_INFO* pInfo); - HRESULT(STDMETHODCALLTYPE* QueryDirection)(IPinC* This, /* [out] */ PIN_DIRECTION* pPinDir); - HRESULT(STDMETHODCALLTYPE* QueryId)(IPinC* This, /* [out] */ LPWSTR* Id); - HRESULT(STDMETHODCALLTYPE* QueryAccept)(IPinC* This, /* [in] */ const AM_MEDIA_TYPE* pmt); - HRESULT(STDMETHODCALLTYPE* EnumMediaTypes)(IPinC* This, /* [out] */ IEnumMediaTypes** ppEnum); - HRESULT(STDMETHODCALLTYPE* QueryInternalConnections)(IPinC* This, /* [out] */ IPinC** apPin, /* [out][in] */ ULONG* nPin); - HRESULT(STDMETHODCALLTYPE* EndOfStream)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* BeginFlush)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* EndFlush)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* NewSegment)(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate); - END_INTERFACE -} IPinCVtbl; - -interface IPinC -{ - CONST_VTBL struct IPinCVtbl* lpVtbl; -}; - -interface IMemInputPinC; - -typedef struct IMemInputPinCVtbl { - BEGIN_INTERFACE - HRESULT(STDMETHODCALLTYPE* QueryInterface)(IPinC* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject); - ULONG(STDMETHODCALLTYPE* AddRef)(IPinC* This); - ULONG(STDMETHODCALLTYPE* Release)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* GetAllocator)(IMemInputPinC* This, IMemAllocator** ppAllocator); - HRESULT(STDMETHODCALLTYPE* NotifyAllocator)(IMemInputPinC* This, IMemAllocator* pAllocator, BOOL bReadOnly); - HRESULT(STDMETHODCALLTYPE* GetAllocatorRequirements)(IMemInputPinC* This, ALLOCATOR_PROPERTIES* pProps); - HRESULT(STDMETHODCALLTYPE* Receive)(IMemInputPinC* This, IMediaSample* pSample); - HRESULT(STDMETHODCALLTYPE* ReceiveMultiple)(IMemInputPinC* This, IMediaSample** pSamples, long nSamples, long* nSamplesProcessed); - HRESULT(STDMETHODCALLTYPE* ReceiveCanBlock)(IMemInputPinC* This); - END_INTERFACE -} IMemInputPinCVtbl; - -interface IMemInputPinC -{ - CONST_VTBL struct IMemInputPinCVtbl* lpVtbl; -}; - -extern bool HookNewSegment(IPinC* pPinC); -extern bool HookReceive(IMemInputPinC* pMemInputPin); -extern void UnhookNewSegment(); -extern void UnhookReceive(); -extern REFERENCE_TIME g_tSegmentStart, g_tSampleStart, g_rtTimePerFrame; - -extern bool HookReceiveConnection(IBaseFilter* pBF); -extern void UnhookReceiveConnection(); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#pragma once + +interface IPinC; + +typedef struct IPinCVtbl { + BEGIN_INTERFACE + HRESULT(STDMETHODCALLTYPE* QueryInterface)(IPinC* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject); + ULONG(STDMETHODCALLTYPE* AddRef)(IPinC* This); + ULONG(STDMETHODCALLTYPE* Release)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* Connect)(IPinC* This, /* [in] */ IPinC* pReceivePin, /* [in] */ const AM_MEDIA_TYPE* pmt); + HRESULT(STDMETHODCALLTYPE* ReceiveConnection)(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt); + HRESULT(STDMETHODCALLTYPE* Disconnect)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* ConnectedTo)(IPinC* This, /* [out] */ IPinC** pPin); + HRESULT(STDMETHODCALLTYPE* ConnectionMediaType)(IPinC* This, /* [out] */ AM_MEDIA_TYPE* pmt); + HRESULT(STDMETHODCALLTYPE* QueryPinInfo)(IPinC* This, /* [out] */ PIN_INFO* pInfo); + HRESULT(STDMETHODCALLTYPE* QueryDirection)(IPinC* This, /* [out] */ PIN_DIRECTION* pPinDir); + HRESULT(STDMETHODCALLTYPE* QueryId)(IPinC* This, /* [out] */ LPWSTR* Id); + HRESULT(STDMETHODCALLTYPE* QueryAccept)(IPinC* This, /* [in] */ const AM_MEDIA_TYPE* pmt); + HRESULT(STDMETHODCALLTYPE* EnumMediaTypes)(IPinC* This, /* [out] */ IEnumMediaTypes** ppEnum); + HRESULT(STDMETHODCALLTYPE* QueryInternalConnections)(IPinC* This, /* [out] */ IPinC** apPin, /* [out][in] */ ULONG* nPin); + HRESULT(STDMETHODCALLTYPE* EndOfStream)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* BeginFlush)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* EndFlush)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* NewSegment)(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate); + END_INTERFACE +} IPinCVtbl; + +interface IPinC +{ + CONST_VTBL struct IPinCVtbl* lpVtbl; +}; + +interface IMemInputPinC; + +typedef struct IMemInputPinCVtbl { + BEGIN_INTERFACE + HRESULT(STDMETHODCALLTYPE* QueryInterface)(IPinC* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject); + ULONG(STDMETHODCALLTYPE* AddRef)(IPinC* This); + ULONG(STDMETHODCALLTYPE* Release)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* GetAllocator)(IMemInputPinC* This, IMemAllocator** ppAllocator); + HRESULT(STDMETHODCALLTYPE* NotifyAllocator)(IMemInputPinC* This, IMemAllocator* pAllocator, BOOL bReadOnly); + HRESULT(STDMETHODCALLTYPE* GetAllocatorRequirements)(IMemInputPinC* This, ALLOCATOR_PROPERTIES* pProps); + HRESULT(STDMETHODCALLTYPE* Receive)(IMemInputPinC* This, IMediaSample* pSample); + HRESULT(STDMETHODCALLTYPE* ReceiveMultiple)(IMemInputPinC* This, IMediaSample** pSamples, long nSamples, long* nSamplesProcessed); + HRESULT(STDMETHODCALLTYPE* ReceiveCanBlock)(IMemInputPinC* This); + END_INTERFACE +} IMemInputPinCVtbl; + +interface IMemInputPinC +{ + CONST_VTBL struct IMemInputPinCVtbl* lpVtbl; +}; + +extern bool HookNewSegment(IPinC* pPinC); +extern bool HookReceive(IMemInputPinC* pMemInputPin); +extern void UnhookNewSegment(); +extern void UnhookReceive(); +extern REFERENCE_TIME g_tSegmentStart, g_tSampleStart, g_rtTimePerFrame; + +extern bool HookReceiveConnection(IBaseFilter* pBF); +extern void UnhookReceiveConnection(); diff --git a/src/filters/renderer/VideoRenderers/IQTVideoSurface.h b/src/filters/renderer/VideoRenderers/IQTVideoSurface.h index 6b23954b00f..066be1a64db 100644 --- a/src/filters/renderer/VideoRenderers/IQTVideoSurface.h +++ b/src/filters/renderer/VideoRenderers/IQTVideoSurface.h @@ -1,34 +1,34 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -// -// IQTVideoSurface -// - -interface __declspec(uuid("A6AE36F7-A6F2-4157-AF54-6599857E4E20")) - IQTVideoSurface : - public IUnknown -{ - STDMETHOD(BeginBlt)(const BITMAP& bm) PURE; - STDMETHOD(DoBlt)(const BITMAP& bm) PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +// +// IQTVideoSurface +// + +interface __declspec(uuid("A6AE36F7-A6F2-4157-AF54-6599857E4E20")) + IQTVideoSurface : + public IUnknown +{ + STDMETHOD(BeginBlt)(const BITMAP& bm) PURE; + STDMETHOD(DoBlt)(const BITMAP& bm) PURE; +}; diff --git a/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp b/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp index 8bf96ea5556..8715410a66f 100644 --- a/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp +++ b/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp @@ -1,98 +1,98 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "MacrovisionKicker.h" - - -// -// CMacrovisionKicker -// - -CMacrovisionKicker::CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk) - : CUnknown(pName, pUnk) -{ -} - -CMacrovisionKicker::~CMacrovisionKicker() -{ -} - -void CMacrovisionKicker::SetInner(IUnknown* pUnk) -{ - m_pInner = pUnk; -} - -STDMETHODIMP CMacrovisionKicker::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - if (riid == __uuidof(IUnknown)) { - return __super::NonDelegatingQueryInterface(riid, ppv); - } - if (riid == __uuidof(IKsPropertySet) && CComQIPtr(m_pInner)) { - return GetInterface((IKsPropertySet*)this, ppv); - } - - HRESULT hr = m_pInner ? m_pInner->QueryInterface(riid, ppv) : E_NOINTERFACE; - - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IKsPropertySet - -STDMETHODIMP CMacrovisionKicker::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength) -{ - if (PropSet == AM_KSPROPSETID_CopyProt && (Id == AM_PROPERTY_COPY_MACROVISION || Id == AM_PROPERTY_COPY_DIGITAL_CP)) { - TRACE(_T("Bypassing macrovision DVD protection\n")); - return S_OK; - } - if (CComQIPtr pKsPS = m_pInner) { - return pKsPS->Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength); - } - return E_UNEXPECTED; -} - -STDMETHODIMP CMacrovisionKicker::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned) -{ - if (PropSet == AM_KSPROPSETID_CopyProt) { - if (Id == AM_PROPERTY_COPY_ANALOG_COMPONENT) { - if (pPropertyData && DataLength >= sizeof(ULONG) && pBytesReturned) { - *(ULONG*)pPropertyData = FALSE; - *pBytesReturned = sizeof(ULONG); - return S_OK; - } - return E_INVALIDARG; - } - } - if (CComQIPtr pKsPS = m_pInner) { - return pKsPS->Get(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength, pBytesReturned); - } - - return E_UNEXPECTED; -} - -STDMETHODIMP CMacrovisionKicker::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) -{ - if (CComQIPtr pKsPS = m_pInner) { - return pKsPS->QuerySupported(PropSet, Id, pTypeSupport); - } - - return E_UNEXPECTED; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "MacrovisionKicker.h" + + +// +// CMacrovisionKicker +// + +CMacrovisionKicker::CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk) + : CUnknown(pName, pUnk) +{ +} + +CMacrovisionKicker::~CMacrovisionKicker() +{ +} + +void CMacrovisionKicker::SetInner(IUnknown* pUnk) +{ + m_pInner = pUnk; +} + +STDMETHODIMP CMacrovisionKicker::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + if (riid == __uuidof(IUnknown)) { + return __super::NonDelegatingQueryInterface(riid, ppv); + } + if (riid == __uuidof(IKsPropertySet) && CComQIPtr(m_pInner)) { + return GetInterface((IKsPropertySet*)this, ppv); + } + + HRESULT hr = m_pInner ? m_pInner->QueryInterface(riid, ppv) : E_NOINTERFACE; + + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IKsPropertySet + +STDMETHODIMP CMacrovisionKicker::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength) +{ + if (PropSet == AM_KSPROPSETID_CopyProt && (Id == AM_PROPERTY_COPY_MACROVISION || Id == AM_PROPERTY_COPY_DIGITAL_CP)) { + TRACE(_T("Bypassing macrovision DVD protection\n")); + return S_OK; + } + if (CComQIPtr pKsPS = m_pInner) { + return pKsPS->Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength); + } + return E_UNEXPECTED; +} + +STDMETHODIMP CMacrovisionKicker::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned) +{ + if (PropSet == AM_KSPROPSETID_CopyProt) { + if (Id == AM_PROPERTY_COPY_ANALOG_COMPONENT) { + if (pPropertyData && DataLength >= sizeof(ULONG) && pBytesReturned) { + *(ULONG*)pPropertyData = FALSE; + *pBytesReturned = sizeof(ULONG); + return S_OK; + } + return E_INVALIDARG; + } + } + if (CComQIPtr pKsPS = m_pInner) { + return pKsPS->Get(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength, pBytesReturned); + } + + return E_UNEXPECTED; +} + +STDMETHODIMP CMacrovisionKicker::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) +{ + if (CComQIPtr pKsPS = m_pInner) { + return pKsPS->QuerySupported(PropSet, Id, pTypeSupport); + } + + return E_UNEXPECTED; +} diff --git a/src/filters/renderer/VideoRenderers/MacrovisionKicker.h b/src/filters/renderer/VideoRenderers/MacrovisionKicker.h index 628fa38d495..566753a8bf9 100644 --- a/src/filters/renderer/VideoRenderers/MacrovisionKicker.h +++ b/src/filters/renderer/VideoRenderers/MacrovisionKicker.h @@ -1,43 +1,43 @@ -/* - * (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 . - * - */ - -#pragma once - -class CMacrovisionKicker - : public CUnknown - , public IKsPropertySet -{ - CComPtr m_pInner; - -public: - CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk); - virtual ~CMacrovisionKicker(); - - void SetInner(IUnknown* pUnk); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IKsPropertySet - STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength); - STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned); - STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport); -}; +/* + * (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 . + * + */ + +#pragma once + +class CMacrovisionKicker + : public CUnknown + , public IKsPropertySet +{ + CComPtr m_pInner; + +public: + CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk); + virtual ~CMacrovisionKicker(); + + void SetInner(IUnknown* pUnk); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IKsPropertySet + STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength); + STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned); + STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport); +}; diff --git a/src/filters/renderer/VideoRenderers/OuterEVR.cpp b/src/filters/renderer/VideoRenderers/OuterEVR.cpp index a3d65c24dba..9dcf3331dd4 100644 --- a/src/filters/renderer/VideoRenderers/OuterEVR.cpp +++ b/src/filters/renderer/VideoRenderers/OuterEVR.cpp @@ -1,154 +1,154 @@ -/* - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "AllocatorCommon.h" -#include "EVRAllocatorPresenter.h" -#include "OuterEVR.h" - -using namespace DSObjects; - -STDMETHODIMP COuterEVR::EnumPins(__out IEnumPins** ppEnum) -{ - if (m_pEVRBase) { - return m_pEVRBase->EnumPins(ppEnum); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::FindPin(LPCWSTR Id, __out IPin** ppPin) -{ - if (m_pEVRBase) { - return m_pEVRBase->FindPin(Id, ppPin); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::QueryFilterInfo(__out FILTER_INFO* pInfo) -{ - if (m_pEVRBase) { - return m_pEVRBase->QueryFilterInfo(pInfo); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName) -{ - if (m_pEVRBase) { - return m_pEVRBase->JoinFilterGraph(pGraph, pName); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::QueryVendorInfo(__out LPWSTR* pVendorInfo) -{ - if (m_pEVRBase) { - return m_pEVRBase->QueryVendorInfo(pVendorInfo); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::Stop() -{ - if (m_pEVRBase) { - return m_pEVRBase->Stop(); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::Pause() -{ - if (m_pEVRBase) { - return m_pEVRBase->Pause(); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::Run(REFERENCE_TIME tStart) -{ - if (m_pEVRBase) { - return m_pEVRBase->Run(tStart); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State) -{ - HRESULT ReturnValue; - if (m_pAllocatorPresenter->GetState(dwMilliSecsTimeout, State, ReturnValue)) { - return ReturnValue; - } - if (m_pEVRBase) { - return m_pEVRBase->GetState(dwMilliSecsTimeout, State); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::SetSyncSource(__in_opt IReferenceClock* pClock) -{ - if (m_pEVRBase) { - return m_pEVRBase->SetSyncSource(pClock); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::GetSyncSource(__deref_out_opt IReferenceClock** pClock) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetSyncSource(pClock); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::GetClassID(__RPC__out CLSID* pClassID) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetClassID(pClassID); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); - return S_OK; -} - -STDMETHODIMP COuterEVR::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} - -STDMETHODIMP COuterEVR::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} +/* + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "AllocatorCommon.h" +#include "EVRAllocatorPresenter.h" +#include "OuterEVR.h" + +using namespace DSObjects; + +STDMETHODIMP COuterEVR::EnumPins(__out IEnumPins** ppEnum) +{ + if (m_pEVRBase) { + return m_pEVRBase->EnumPins(ppEnum); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::FindPin(LPCWSTR Id, __out IPin** ppPin) +{ + if (m_pEVRBase) { + return m_pEVRBase->FindPin(Id, ppPin); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::QueryFilterInfo(__out FILTER_INFO* pInfo) +{ + if (m_pEVRBase) { + return m_pEVRBase->QueryFilterInfo(pInfo); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName) +{ + if (m_pEVRBase) { + return m_pEVRBase->JoinFilterGraph(pGraph, pName); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::QueryVendorInfo(__out LPWSTR* pVendorInfo) +{ + if (m_pEVRBase) { + return m_pEVRBase->QueryVendorInfo(pVendorInfo); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::Stop() +{ + if (m_pEVRBase) { + return m_pEVRBase->Stop(); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::Pause() +{ + if (m_pEVRBase) { + return m_pEVRBase->Pause(); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::Run(REFERENCE_TIME tStart) +{ + if (m_pEVRBase) { + return m_pEVRBase->Run(tStart); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State) +{ + HRESULT ReturnValue; + if (m_pAllocatorPresenter->GetState(dwMilliSecsTimeout, State, ReturnValue)) { + return ReturnValue; + } + if (m_pEVRBase) { + return m_pEVRBase->GetState(dwMilliSecsTimeout, State); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::SetSyncSource(__in_opt IReferenceClock* pClock) +{ + if (m_pEVRBase) { + return m_pEVRBase->SetSyncSource(pClock); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::GetSyncSource(__deref_out_opt IReferenceClock** pClock) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetSyncSource(pClock); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::GetClassID(__RPC__out CLSID* pClassID) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetClassID(pClassID); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); + return S_OK; +} + +STDMETHODIMP COuterEVR::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} + +STDMETHODIMP COuterEVR::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/OuterEVR.h b/src/filters/renderer/VideoRenderers/OuterEVR.h index 0209f558f21..b8e10dddf03 100644 --- a/src/filters/renderer/VideoRenderers/OuterEVR.h +++ b/src/filters/renderer/VideoRenderers/OuterEVR.h @@ -1,91 +1,91 @@ -/* - * (C) 2006-2014 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 . - * - */ - -#pragma once - -/// === Outer EVR -namespace DSObjects -{ - class COuterEVR - : public CUnknown - , public IVMRMixerBitmap9 - , public IBaseFilter - { - CComPtr m_pEVR; - IBaseFilter* m_pEVRBase; - VMR9AlphaBitmap* m_pVMR9AlphaBitmap; - CEVRAllocatorPresenter* m_pAllocatorPresenter; - - public: - COuterEVR(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CEVRAllocatorPresenter* pAllocatorPresenter) : CUnknown(pName, pUnk) { - hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner()); - CComQIPtr pEVRBase = m_pEVR; - m_pEVRBase = pEVRBase; // Don't keep a second reference on the EVR filter - m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; - m_pAllocatorPresenter = pAllocatorPresenter; - } - - ~COuterEVR() {} - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - HRESULT hr; - - if (riid == __uuidof(IVMRMixerBitmap9)) { - return GetInterface((IVMRMixerBitmap9*)this, ppv); - } - if (riid == __uuidof(IMediaFilter)) { - return GetInterface((IMediaFilter*)this, ppv); - } - if (riid == __uuidof(IPersist)) { - return GetInterface((IPersist*)this, ppv); - } - if (riid == __uuidof(IBaseFilter)) { - return GetInterface((IBaseFilter*)this, ppv); - } - - hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE; - if (m_pEVR && FAILED(hr)) { - hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; - } - - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IBaseFilter - STDMETHODIMP EnumPins(__out IEnumPins** ppEnum); - STDMETHODIMP FindPin(LPCWSTR Id, __out IPin** ppPin); - STDMETHODIMP QueryFilterInfo(__out FILTER_INFO* pInfo); - STDMETHODIMP JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName); - STDMETHODIMP QueryVendorInfo(__out LPWSTR* pVendorInfo); - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - STDMETHODIMP GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State); - STDMETHODIMP SetSyncSource(__in_opt IReferenceClock* pClock); - STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock** pClock); - STDMETHODIMP GetClassID(__RPC__out CLSID* pClassID); - - // IVMRMixerBitmap9 - STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); - }; -} +/* + * (C) 2006-2014 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 . + * + */ + +#pragma once + +/// === Outer EVR +namespace DSObjects +{ + class COuterEVR + : public CUnknown + , public IVMRMixerBitmap9 + , public IBaseFilter + { + CComPtr m_pEVR; + IBaseFilter* m_pEVRBase; + VMR9AlphaBitmap* m_pVMR9AlphaBitmap; + CEVRAllocatorPresenter* m_pAllocatorPresenter; + + public: + COuterEVR(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CEVRAllocatorPresenter* pAllocatorPresenter) : CUnknown(pName, pUnk) { + hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner()); + CComQIPtr pEVRBase = m_pEVR; + m_pEVRBase = pEVRBase; // Don't keep a second reference on the EVR filter + m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; + m_pAllocatorPresenter = pAllocatorPresenter; + } + + ~COuterEVR() {} + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + HRESULT hr; + + if (riid == __uuidof(IVMRMixerBitmap9)) { + return GetInterface((IVMRMixerBitmap9*)this, ppv); + } + if (riid == __uuidof(IMediaFilter)) { + return GetInterface((IMediaFilter*)this, ppv); + } + if (riid == __uuidof(IPersist)) { + return GetInterface((IPersist*)this, ppv); + } + if (riid == __uuidof(IBaseFilter)) { + return GetInterface((IBaseFilter*)this, ppv); + } + + hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE; + if (m_pEVR && FAILED(hr)) { + hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; + } + + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IBaseFilter + STDMETHODIMP EnumPins(__out IEnumPins** ppEnum); + STDMETHODIMP FindPin(LPCWSTR Id, __out IPin** ppPin); + STDMETHODIMP QueryFilterInfo(__out FILTER_INFO* pInfo); + STDMETHODIMP JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName); + STDMETHODIMP QueryVendorInfo(__out LPWSTR* pVendorInfo); + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + STDMETHODIMP GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State); + STDMETHODIMP SetSyncSource(__in_opt IReferenceClock* pClock); + STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock** pClock); + STDMETHODIMP GetClassID(__RPC__out CLSID* pClassID); + + // IVMRMixerBitmap9 + STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); + }; +} diff --git a/src/filters/renderer/VideoRenderers/OuterVMR.cpp b/src/filters/renderer/VideoRenderers/OuterVMR.cpp index c62b26c8234..1da243c44e6 100644 --- a/src/filters/renderer/VideoRenderers/OuterVMR.cpp +++ b/src/filters/renderer/VideoRenderers/OuterVMR.cpp @@ -1,170 +1,170 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "AllocatorCommon.h" -#include "VMR9AllocatorPresenter.h" -#include "OuterVMR.h" - -using namespace DSObjects; - -STDMETHODIMP COuterVMR9::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) -{ - if (CComQIPtr pWC9 = m_pVMR) { - return pWC9->GetNativeVideoSize(lpWidth, lpHeight, lpARWidth, lpARHeight); - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect) -{ - if (CComQIPtr pWC9 = m_pVMR) { - return pWC9->GetVideoPosition(lpSRCRect, lpDSTRect); - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::GetAspectRatioMode(DWORD* lpAspectRatioMode) -{ - if (CComQIPtr pWC9 = m_pVMR) { - *lpAspectRatioMode = VMR_ARMODE_NONE; - return S_OK; - } - - return E_NOTIMPL; -} - -// IVideoWindow -STDMETHODIMP COuterVMR9::get_Width(long* pWidth) -{ - if (CComQIPtr pWC9 = m_pVMR) { - CRect s, d; - HRESULT hr = pWC9->GetVideoPosition(&s, &d); - *pWidth = d.Width(); - return hr; - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::get_Height(long* pHeight) -{ - if (CComQIPtr pWC9 = m_pVMR) { - CRect s, d; - HRESULT hr = pWC9->GetVideoPosition(&s, &d); - *pHeight = d.Height(); - return hr; - } - - return E_NOTIMPL; -} - -// IBasicVideo2 -STDMETHODIMP COuterVMR9::GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - // DVD Nav. bug workaround fix - { - *pLeft = *pTop = 0; - return GetVideoSize(pWidth, pHeight); - } - /* - if (CComQIPtr pWC9 = m_pVMR) - { - CRect s, d; - HRESULT hr = pWC9->GetVideoPosition(&s, &d); - *pLeft = s.left; - *pTop = s.top; - *pWidth = s.Width(); - *pHeight = s.Height(); - return hr; - } - return E_NOTIMPL; - */ -} - -STDMETHODIMP COuterVMR9::GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - if (CComQIPtr pWC9 = m_pVMR) { - CRect s, d; - HRESULT hr = pWC9->GetVideoPosition(&s, &d); - *pLeft = d.left; - *pTop = d.top; - *pWidth = d.Width(); - *pHeight = d.Height(); - return hr; - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::GetVideoSize(long* pWidth, long* pHeight) -{ - if (CComQIPtr pWC9 = m_pVMR) { - LONG aw, ah; - //return pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah); - // DVD Nav. bug workaround fix - HRESULT hr = pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah); - *pWidth = *pHeight * aw / ah; - return hr; - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::GetPreferredAspectRatio(long* plAspectX, long* plAspectY) -{ - if (CComQIPtr pWC9 = m_pVMR) { - LONG w, h; - return pWC9->GetNativeVideoSize(&w, &h, plAspectX, plAspectY); - } - - return E_NOTIMPL; -} - -// IVMRMixerBitmap9 -STDMETHODIMP COuterVMR9::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); - return S_OK; -} - -STDMETHODIMP COuterVMR9::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} - -STDMETHODIMP COuterVMR9::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "AllocatorCommon.h" +#include "VMR9AllocatorPresenter.h" +#include "OuterVMR.h" + +using namespace DSObjects; + +STDMETHODIMP COuterVMR9::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) +{ + if (CComQIPtr pWC9 = m_pVMR) { + return pWC9->GetNativeVideoSize(lpWidth, lpHeight, lpARWidth, lpARHeight); + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect) +{ + if (CComQIPtr pWC9 = m_pVMR) { + return pWC9->GetVideoPosition(lpSRCRect, lpDSTRect); + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::GetAspectRatioMode(DWORD* lpAspectRatioMode) +{ + if (CComQIPtr pWC9 = m_pVMR) { + *lpAspectRatioMode = VMR_ARMODE_NONE; + return S_OK; + } + + return E_NOTIMPL; +} + +// IVideoWindow +STDMETHODIMP COuterVMR9::get_Width(long* pWidth) +{ + if (CComQIPtr pWC9 = m_pVMR) { + CRect s, d; + HRESULT hr = pWC9->GetVideoPosition(&s, &d); + *pWidth = d.Width(); + return hr; + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::get_Height(long* pHeight) +{ + if (CComQIPtr pWC9 = m_pVMR) { + CRect s, d; + HRESULT hr = pWC9->GetVideoPosition(&s, &d); + *pHeight = d.Height(); + return hr; + } + + return E_NOTIMPL; +} + +// IBasicVideo2 +STDMETHODIMP COuterVMR9::GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + // DVD Nav. bug workaround fix + { + *pLeft = *pTop = 0; + return GetVideoSize(pWidth, pHeight); + } + /* + if (CComQIPtr pWC9 = m_pVMR) + { + CRect s, d; + HRESULT hr = pWC9->GetVideoPosition(&s, &d); + *pLeft = s.left; + *pTop = s.top; + *pWidth = s.Width(); + *pHeight = s.Height(); + return hr; + } + return E_NOTIMPL; + */ +} + +STDMETHODIMP COuterVMR9::GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + if (CComQIPtr pWC9 = m_pVMR) { + CRect s, d; + HRESULT hr = pWC9->GetVideoPosition(&s, &d); + *pLeft = d.left; + *pTop = d.top; + *pWidth = d.Width(); + *pHeight = d.Height(); + return hr; + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::GetVideoSize(long* pWidth, long* pHeight) +{ + if (CComQIPtr pWC9 = m_pVMR) { + LONG aw, ah; + //return pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah); + // DVD Nav. bug workaround fix + HRESULT hr = pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah); + *pWidth = *pHeight * aw / ah; + return hr; + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::GetPreferredAspectRatio(long* plAspectX, long* plAspectY) +{ + if (CComQIPtr pWC9 = m_pVMR) { + LONG w, h; + return pWC9->GetNativeVideoSize(&w, &h, plAspectX, plAspectY); + } + + return E_NOTIMPL; +} + +// IVMRMixerBitmap9 +STDMETHODIMP COuterVMR9::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); + return S_OK; +} + +STDMETHODIMP COuterVMR9::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} + +STDMETHODIMP COuterVMR9::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/OuterVMR.h b/src/filters/renderer/VideoRenderers/OuterVMR.h index 34fe9e8e325..3d01d5d6955 100644 --- a/src/filters/renderer/VideoRenderers/OuterVMR.h +++ b/src/filters/renderer/VideoRenderers/OuterVMR.h @@ -1,201 +1,201 @@ -/* - * (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 . - * - */ - -#pragma once - -namespace DSObjects -{ - class COuterVMR9 - : public CUnknown - , public IVideoWindow - , public IBasicVideo2 - , public IVMRWindowlessControl - , public IVMRMixerBitmap9 - { - CComPtr m_pVMR; - VMR9AlphaBitmap* m_pVMR9AlphaBitmap; - CVMR9AllocatorPresenter* m_pAllocatorPresenter; - - public: - - COuterVMR9(const TCHAR* pName, LPUNKNOWN pUnk, VMR9AlphaBitmap* pVMR9AlphaBitmap, CVMR9AllocatorPresenter* pAllocatorPresenter) : CUnknown(pName, pUnk) { - m_pVMR.CoCreateInstance(CLSID_VideoMixingRenderer9, GetOwner()); - m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; - m_pAllocatorPresenter = pAllocatorPresenter; - } - - ~COuterVMR9() { - m_pVMR = nullptr; - } - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - HRESULT hr; - - // Casimir666 : in renderless mode, do the inlaying in place of VMR - if (riid == __uuidof(IVMRMixerBitmap9)) { - return GetInterface((IVMRMixerBitmap9*)this, ppv); - } - - hr = m_pVMR ? m_pVMR->QueryInterface(riid, ppv) : E_NOINTERFACE; - if (m_pVMR && FAILED(hr)) { - hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; - if (FAILED(hr)) { - if (riid == __uuidof(IVideoWindow)) { - return GetInterface((IVideoWindow*)this, ppv); - } - if (riid == __uuidof(IBasicVideo)) { - return GetInterface((IBasicVideo*)this, ppv); - } - if (riid == __uuidof(IBasicVideo2)) { - return GetInterface((IBasicVideo2*)this, ppv); - } - /*if (riid == __uuidof(IVMRWindowlessControl)) - return GetInterface((IVMRWindowlessControl*)this, ppv); - */ - } - } - - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IVMRWindowlessControl - - STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); - - STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) { return E_NOTIMPL; } - STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) { return E_NOTIMPL; } - STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) { return E_NOTIMPL; } - STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect); - - STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode); - STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode) { return E_NOTIMPL; } - STDMETHODIMP SetVideoClippingWindow(HWND hwnd) { return E_NOTIMPL; } - STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc) { return E_NOTIMPL; } - STDMETHODIMP DisplayModeChanged() { return E_NOTIMPL; } - STDMETHODIMP GetCurrentImage(BYTE** lpDib) { return E_NOTIMPL; } - STDMETHODIMP SetBorderColor(COLORREF Clr) { return E_NOTIMPL; } - STDMETHODIMP GetBorderColor(COLORREF* lpClr) { return E_NOTIMPL; } - STDMETHODIMP SetColorKey(COLORREF Clr) { return E_NOTIMPL; } - STDMETHODIMP GetColorKey(COLORREF* lpClr) { return E_NOTIMPL; } - - // IVideoWindow - STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } - STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; } - STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { - return E_NOTIMPL; - } - STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, - VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { - return E_NOTIMPL; - } - STDMETHODIMP put_Caption(BSTR strCaption) { return E_NOTIMPL; } - STDMETHODIMP get_Caption(BSTR* strCaption) { return E_NOTIMPL; } - STDMETHODIMP put_WindowStyle(long WindowStyle) { return E_NOTIMPL; } - STDMETHODIMP get_WindowStyle(long* WindowStyle) { return E_NOTIMPL; } - STDMETHODIMP put_WindowStyleEx(long WindowStyleEx) { return E_NOTIMPL; } - STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx) { return E_NOTIMPL; } - STDMETHODIMP put_AutoShow(long AutoShow) { return E_NOTIMPL; } - STDMETHODIMP get_AutoShow(long* AutoShow) { return E_NOTIMPL; } - STDMETHODIMP put_WindowState(long WindowState) { return E_NOTIMPL; } - STDMETHODIMP get_WindowState(long* WindowState) { return E_NOTIMPL; } - STDMETHODIMP put_BackgroundPalette(long BackgroundPalette) { return E_NOTIMPL; } - STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette) { return E_NOTIMPL; } - STDMETHODIMP put_Visible(long Visible) { return E_NOTIMPL; } - STDMETHODIMP get_Visible(long* pVisible) { return E_NOTIMPL; } - STDMETHODIMP put_Left(long Left) { return E_NOTIMPL; } - STDMETHODIMP get_Left(long* pLeft) { return E_NOTIMPL; } - STDMETHODIMP put_Width(long Width) { return E_NOTIMPL; } - STDMETHODIMP get_Width(long* pWidth); - - STDMETHODIMP put_Top(long Top) { return E_NOTIMPL; } - STDMETHODIMP get_Top(long* pTop) { return E_NOTIMPL; } - STDMETHODIMP put_Height(long Height) { return E_NOTIMPL; } - STDMETHODIMP get_Height(long* pHeight); - - STDMETHODIMP put_Owner(OAHWND Owner) { return E_NOTIMPL; } - STDMETHODIMP get_Owner(OAHWND* Owner) { return E_NOTIMPL; } - STDMETHODIMP put_MessageDrain(OAHWND Drain) { return E_NOTIMPL; } - STDMETHODIMP get_MessageDrain(OAHWND* Drain) { return E_NOTIMPL; } - STDMETHODIMP get_BorderColor(long* Color) { return E_NOTIMPL; } - STDMETHODIMP put_BorderColor(long Color) { return E_NOTIMPL; } - STDMETHODIMP get_FullScreenMode(long* FullScreenMode) { return E_NOTIMPL; } - STDMETHODIMP put_FullScreenMode(long FullScreenMode) { return E_NOTIMPL; } - STDMETHODIMP SetWindowForeground(long Focus) { return E_NOTIMPL; } - STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) { - return E_NOTIMPL; - } - STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } - STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) { - return E_NOTIMPL; - } - STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight) { return E_NOTIMPL; } - STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight) { return E_NOTIMPL; } - STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) { return E_NOTIMPL; } - STDMETHODIMP HideCursor(long HideCursor) { return E_NOTIMPL; } - STDMETHODIMP IsCursorHidden(long* CursorHidden) { return E_NOTIMPL; } - - // IBasicVideo2 - STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) { return E_NOTIMPL; } - STDMETHODIMP get_BitRate(long* pBitRate) { return E_NOTIMPL; } - STDMETHODIMP get_BitErrorRate(long* pBitErrorRate) { return E_NOTIMPL; } - STDMETHODIMP get_VideoWidth(long* pVideoWidth) { return E_NOTIMPL; } - STDMETHODIMP get_VideoHeight(long* pVideoHeight) { return E_NOTIMPL; } - STDMETHODIMP put_SourceLeft(long SourceLeft) { return E_NOTIMPL; } - STDMETHODIMP get_SourceLeft(long* pSourceLeft) { return E_NOTIMPL; } - STDMETHODIMP put_SourceWidth(long SourceWidth) { return E_NOTIMPL; } - STDMETHODIMP get_SourceWidth(long* pSourceWidth) { return E_NOTIMPL; } - STDMETHODIMP put_SourceTop(long SourceTop) { return E_NOTIMPL; } - STDMETHODIMP get_SourceTop(long* pSourceTop) { return E_NOTIMPL; } - STDMETHODIMP put_SourceHeight(long SourceHeight) { return E_NOTIMPL; } - STDMETHODIMP get_SourceHeight(long* pSourceHeight) { return E_NOTIMPL; } - STDMETHODIMP put_DestinationLeft(long DestinationLeft) { return E_NOTIMPL; } - STDMETHODIMP get_DestinationLeft(long* pDestinationLeft) { return E_NOTIMPL; } - STDMETHODIMP put_DestinationWidth(long DestinationWidth) { return E_NOTIMPL; } - STDMETHODIMP get_DestinationWidth(long* pDestinationWidth) { return E_NOTIMPL; } - STDMETHODIMP put_DestinationTop(long DestinationTop) { return E_NOTIMPL; } - STDMETHODIMP get_DestinationTop(long* pDestinationTop) { return E_NOTIMPL; } - STDMETHODIMP put_DestinationHeight(long DestinationHeight) { return E_NOTIMPL; } - STDMETHODIMP get_DestinationHeight(long* pDestinationHeight) { return E_NOTIMPL; } - STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } - STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - - STDMETHODIMP SetDefaultSourcePosition() { return E_NOTIMPL; } - STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } - STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - - STDMETHODIMP SetDefaultDestinationPosition() { return E_NOTIMPL; } - STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight); - - STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) { - return E_NOTIMPL; - } - STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage) { return E_NOTIMPL; } - STDMETHODIMP IsUsingDefaultSource() { return E_NOTIMPL; } - STDMETHODIMP IsUsingDefaultDestination() { return E_NOTIMPL; } - - STDMETHODIMP GetPreferredAspectRatio(long* plAspectX, long* plAspectY); - - // IVMRMixerBitmap9 - STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); - }; -} +/* + * (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 . + * + */ + +#pragma once + +namespace DSObjects +{ + class COuterVMR9 + : public CUnknown + , public IVideoWindow + , public IBasicVideo2 + , public IVMRWindowlessControl + , public IVMRMixerBitmap9 + { + CComPtr m_pVMR; + VMR9AlphaBitmap* m_pVMR9AlphaBitmap; + CVMR9AllocatorPresenter* m_pAllocatorPresenter; + + public: + + COuterVMR9(const TCHAR* pName, LPUNKNOWN pUnk, VMR9AlphaBitmap* pVMR9AlphaBitmap, CVMR9AllocatorPresenter* pAllocatorPresenter) : CUnknown(pName, pUnk) { + m_pVMR.CoCreateInstance(CLSID_VideoMixingRenderer9, GetOwner()); + m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; + m_pAllocatorPresenter = pAllocatorPresenter; + } + + ~COuterVMR9() { + m_pVMR = nullptr; + } + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + HRESULT hr; + + // Casimir666 : in renderless mode, do the inlaying in place of VMR + if (riid == __uuidof(IVMRMixerBitmap9)) { + return GetInterface((IVMRMixerBitmap9*)this, ppv); + } + + hr = m_pVMR ? m_pVMR->QueryInterface(riid, ppv) : E_NOINTERFACE; + if (m_pVMR && FAILED(hr)) { + hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; + if (FAILED(hr)) { + if (riid == __uuidof(IVideoWindow)) { + return GetInterface((IVideoWindow*)this, ppv); + } + if (riid == __uuidof(IBasicVideo)) { + return GetInterface((IBasicVideo*)this, ppv); + } + if (riid == __uuidof(IBasicVideo2)) { + return GetInterface((IBasicVideo2*)this, ppv); + } + /*if (riid == __uuidof(IVMRWindowlessControl)) + return GetInterface((IVMRWindowlessControl*)this, ppv); + */ + } + } + + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IVMRWindowlessControl + + STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); + + STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) { return E_NOTIMPL; } + STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) { return E_NOTIMPL; } + STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) { return E_NOTIMPL; } + STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect); + + STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode); + STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode) { return E_NOTIMPL; } + STDMETHODIMP SetVideoClippingWindow(HWND hwnd) { return E_NOTIMPL; } + STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc) { return E_NOTIMPL; } + STDMETHODIMP DisplayModeChanged() { return E_NOTIMPL; } + STDMETHODIMP GetCurrentImage(BYTE** lpDib) { return E_NOTIMPL; } + STDMETHODIMP SetBorderColor(COLORREF Clr) { return E_NOTIMPL; } + STDMETHODIMP GetBorderColor(COLORREF* lpClr) { return E_NOTIMPL; } + STDMETHODIMP SetColorKey(COLORREF Clr) { return E_NOTIMPL; } + STDMETHODIMP GetColorKey(COLORREF* lpClr) { return E_NOTIMPL; } + + // IVideoWindow + STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } + STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; } + STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { + return E_NOTIMPL; + } + STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { + return E_NOTIMPL; + } + STDMETHODIMP put_Caption(BSTR strCaption) { return E_NOTIMPL; } + STDMETHODIMP get_Caption(BSTR* strCaption) { return E_NOTIMPL; } + STDMETHODIMP put_WindowStyle(long WindowStyle) { return E_NOTIMPL; } + STDMETHODIMP get_WindowStyle(long* WindowStyle) { return E_NOTIMPL; } + STDMETHODIMP put_WindowStyleEx(long WindowStyleEx) { return E_NOTIMPL; } + STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx) { return E_NOTIMPL; } + STDMETHODIMP put_AutoShow(long AutoShow) { return E_NOTIMPL; } + STDMETHODIMP get_AutoShow(long* AutoShow) { return E_NOTIMPL; } + STDMETHODIMP put_WindowState(long WindowState) { return E_NOTIMPL; } + STDMETHODIMP get_WindowState(long* WindowState) { return E_NOTIMPL; } + STDMETHODIMP put_BackgroundPalette(long BackgroundPalette) { return E_NOTIMPL; } + STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette) { return E_NOTIMPL; } + STDMETHODIMP put_Visible(long Visible) { return E_NOTIMPL; } + STDMETHODIMP get_Visible(long* pVisible) { return E_NOTIMPL; } + STDMETHODIMP put_Left(long Left) { return E_NOTIMPL; } + STDMETHODIMP get_Left(long* pLeft) { return E_NOTIMPL; } + STDMETHODIMP put_Width(long Width) { return E_NOTIMPL; } + STDMETHODIMP get_Width(long* pWidth); + + STDMETHODIMP put_Top(long Top) { return E_NOTIMPL; } + STDMETHODIMP get_Top(long* pTop) { return E_NOTIMPL; } + STDMETHODIMP put_Height(long Height) { return E_NOTIMPL; } + STDMETHODIMP get_Height(long* pHeight); + + STDMETHODIMP put_Owner(OAHWND Owner) { return E_NOTIMPL; } + STDMETHODIMP get_Owner(OAHWND* Owner) { return E_NOTIMPL; } + STDMETHODIMP put_MessageDrain(OAHWND Drain) { return E_NOTIMPL; } + STDMETHODIMP get_MessageDrain(OAHWND* Drain) { return E_NOTIMPL; } + STDMETHODIMP get_BorderColor(long* Color) { return E_NOTIMPL; } + STDMETHODIMP put_BorderColor(long Color) { return E_NOTIMPL; } + STDMETHODIMP get_FullScreenMode(long* FullScreenMode) { return E_NOTIMPL; } + STDMETHODIMP put_FullScreenMode(long FullScreenMode) { return E_NOTIMPL; } + STDMETHODIMP SetWindowForeground(long Focus) { return E_NOTIMPL; } + STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) { + return E_NOTIMPL; + } + STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } + STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) { + return E_NOTIMPL; + } + STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight) { return E_NOTIMPL; } + STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight) { return E_NOTIMPL; } + STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) { return E_NOTIMPL; } + STDMETHODIMP HideCursor(long HideCursor) { return E_NOTIMPL; } + STDMETHODIMP IsCursorHidden(long* CursorHidden) { return E_NOTIMPL; } + + // IBasicVideo2 + STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) { return E_NOTIMPL; } + STDMETHODIMP get_BitRate(long* pBitRate) { return E_NOTIMPL; } + STDMETHODIMP get_BitErrorRate(long* pBitErrorRate) { return E_NOTIMPL; } + STDMETHODIMP get_VideoWidth(long* pVideoWidth) { return E_NOTIMPL; } + STDMETHODIMP get_VideoHeight(long* pVideoHeight) { return E_NOTIMPL; } + STDMETHODIMP put_SourceLeft(long SourceLeft) { return E_NOTIMPL; } + STDMETHODIMP get_SourceLeft(long* pSourceLeft) { return E_NOTIMPL; } + STDMETHODIMP put_SourceWidth(long SourceWidth) { return E_NOTIMPL; } + STDMETHODIMP get_SourceWidth(long* pSourceWidth) { return E_NOTIMPL; } + STDMETHODIMP put_SourceTop(long SourceTop) { return E_NOTIMPL; } + STDMETHODIMP get_SourceTop(long* pSourceTop) { return E_NOTIMPL; } + STDMETHODIMP put_SourceHeight(long SourceHeight) { return E_NOTIMPL; } + STDMETHODIMP get_SourceHeight(long* pSourceHeight) { return E_NOTIMPL; } + STDMETHODIMP put_DestinationLeft(long DestinationLeft) { return E_NOTIMPL; } + STDMETHODIMP get_DestinationLeft(long* pDestinationLeft) { return E_NOTIMPL; } + STDMETHODIMP put_DestinationWidth(long DestinationWidth) { return E_NOTIMPL; } + STDMETHODIMP get_DestinationWidth(long* pDestinationWidth) { return E_NOTIMPL; } + STDMETHODIMP put_DestinationTop(long DestinationTop) { return E_NOTIMPL; } + STDMETHODIMP get_DestinationTop(long* pDestinationTop) { return E_NOTIMPL; } + STDMETHODIMP put_DestinationHeight(long DestinationHeight) { return E_NOTIMPL; } + STDMETHODIMP get_DestinationHeight(long* pDestinationHeight) { return E_NOTIMPL; } + STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } + STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + + STDMETHODIMP SetDefaultSourcePosition() { return E_NOTIMPL; } + STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } + STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + + STDMETHODIMP SetDefaultDestinationPosition() { return E_NOTIMPL; } + STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight); + + STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) { + return E_NOTIMPL; + } + STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage) { return E_NOTIMPL; } + STDMETHODIMP IsUsingDefaultSource() { return E_NOTIMPL; } + STDMETHODIMP IsUsingDefaultDestination() { return E_NOTIMPL; } + + STDMETHODIMP GetPreferredAspectRatio(long* plAspectX, long* plAspectY); + + // IVMRMixerBitmap9 + STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); + }; +} diff --git a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp index f117331d086..ab1d69817a9 100644 --- a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp +++ b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp @@ -1,230 +1,230 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "PixelShaderCompiler.h" -#include "../../../mpc-hc/resource.h" -#include -#include - -CPixelShaderCompiler::CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent) - : m_hDll(nullptr) - , m_pD3DCompile(nullptr) - , m_pD3DDisassemble(nullptr) - , m_pD3DDev(pD3DDev) - , m_Cache(pD3DDev) -{ - static_assert(D3D_COMPILER_VERSION == MPC_D3D_COMPILER_VERSION, - "MPC_D3D_COMPILER_VERSION define used in the installer needs to be updated."); - m_hDll = LoadLibrary(D3DCOMPILER_DLL); - - if (m_hDll) { - m_pD3DCompile = (pD3DCompile)GetProcAddress(m_hDll, "D3DCompile"); - m_pD3DDisassemble = (pD3DDisassemble)GetProcAddress(m_hDll, "D3DDisassemble"); - } - - if (!fStaySilent) { - if (!m_hDll) { - CString msg; - msg.Format(IDS_SHADER_DLL_ERR_0, D3DCOMPILER_DLL); - AfxMessageBox(msg, MB_ICONWARNING | MB_OK); - } else if (!m_pD3DCompile || !m_pD3DDisassemble) { - CString msg; - msg.Format(IDS_SHADER_DLL_ERR_1, D3DCOMPILER_DLL); - AfxMessageBox(msg, MB_ICONWARNING | MB_OK); - } - } -} - -CPixelShaderCompiler::~CPixelShaderCompiler() -{ - if (m_hDll) { - VERIFY(FreeLibrary(m_hDll)); - } -} - -HRESULT CPixelShaderCompiler::InternalCompile( - LPCSTR pSrcData, - SIZE_T SrcDataSize, - LPCSTR pSourceName, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg) -{ - if (!m_pD3DCompile) { - return E_FAIL; - } - - if (pDisasm && !m_pD3DDisassemble) { - return E_FAIL; - } - - if (ppPixelShader && !m_pD3DDev) { - return E_FAIL; - } - - LPCSTR pSelProfile = pProfile; - if (!pSelProfile || *pSelProfile == '\0') { - D3DCAPS9 caps; - if (m_pD3DDev && m_pD3DDev->GetDeviceCaps(&caps) == D3D_OK) { - switch (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion)) { - case 2: - if (caps.PS20Caps.NumInstructionSlots < 512) { - pSelProfile = "ps_2_0"; - } else if (caps.PS20Caps.Caps > 0) { - pSelProfile = "ps_2_a"; - } else { - pSelProfile = "ps_2_b"; - } - break; - case 3: - pSelProfile = "ps_3_0"; - break; - } - } else { - ASSERT(FALSE); - } - } - - if (!pSelProfile || *pSelProfile == '\0') { - return E_FAIL; - } - - LPCSTR defProfile = "MPC_HC_SHADER_PROFILE"; - LPCSTR defProfileVal; - if (!strcmp(pSelProfile, "ps_2_0")) { - defProfileVal = "0"; - } else if (!strcmp(pSelProfile, "ps_2_b")) { - defProfileVal = "1"; - } else if (!strcmp(pSelProfile, "ps_2_a") || !strcmp(pSelProfile, "ps_2_sw")) { - defProfileVal = "2"; - } else if (!strcmp(pSelProfile, "ps_3_0") || !strcmp(pSelProfile, "ps_3_sw")) { - defProfileVal = "3"; - } else { - defProfileVal = "-1"; - } - - if (ppPixelShader && SUCCEEDED(m_Cache.CreatePixelShader(defProfileVal, pSrcData, SrcDataSize, ppPixelShader))) { - return S_OK; - } - - D3D_SHADER_MACRO macros[] = { { defProfile, defProfileVal }, { 0 } }; - - CComPtr pShaderBlob, pErrorBlob; - HRESULT hr = m_pD3DCompile(pSrcData, SrcDataSize, pSourceName, macros, nullptr, pEntrypoint, - pSelProfile, Flags, 0, &pShaderBlob, &pErrorBlob); - - if (pErrMsg) { - CStringA msg; - if (pErrorBlob) { - auto len = pErrorBlob->GetBufferSize(); - VERIFY(memcpy_s(msg.GetBufferSetLength((int)len), len, pErrorBlob->GetBufferPointer(), len) == 0); - msg.ReleaseBuffer((int)len); - } - *pErrMsg = msg; - } - - if (FAILED(hr)) { - return hr; - } - - if (ppPixelShader) { - hr = m_pD3DDev->CreatePixelShader((DWORD*)pShaderBlob->GetBufferPointer(), ppPixelShader); - if (FAILED(hr)) { - return hr; - } - - m_Cache.SavePixelShader(defProfileVal, pSrcData, SrcDataSize, - (void*)pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize()); - } - - if (pDisasm) { - CComPtr pDisasmBlob; - CStringA defs; - for (auto pMacro = macros; pMacro && pMacro->Name && pMacro->Definition; pMacro++) { - defs.Append("// #define "); - defs.Append(pMacro->Name); - defs.Append(" "); - defs.Append(pMacro->Definition); - defs.Append("\n"); - } - hr = m_pD3DDisassemble(pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), - 0, defs, &pDisasmBlob); - if (SUCCEEDED(hr)) { - CStringA disasm; - auto len = pDisasmBlob->GetBufferSize(); - VERIFY(memcpy_s(disasm.GetBufferSetLength((int)len), len, pDisasmBlob->GetBufferPointer(), len) == 0); - disasm.ReleaseBuffer((int)len); - *pDisasm = disasm; - } - } - - return S_OK; -} - -HRESULT CPixelShaderCompiler::CompileShader( - LPCSTR pSrcData, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg) -{ - return InternalCompile(pSrcData, strlen(pSrcData), nullptr, pEntrypoint, - pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); -} - -HRESULT CPixelShaderCompiler::CompileShaderFromFile( - LPCTSTR pSrcFile, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg) -{ - HRESULT ret = E_FAIL; - if (FILE* fp = _tfsopen(pSrcFile, _T("rb"), _SH_SECURE)) { - VERIFY(fseek(fp, 0, SEEK_END) == 0); - long size = ftell(fp); - rewind(fp); - if (size > 0) { - auto data = new (std::nothrow) char[(size_t)size]; - if (data) { - if (fread(data, size, 1, fp) == 1) { - ret = InternalCompile(data, (size_t)size, CT2A(pSrcFile), pEntrypoint, - pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); - } else { - ASSERT(FALSE); - } - delete[] data; - } else { - ASSERT(FALSE); - } - } - VERIFY(fclose(fp) == 0); - } - return ret; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "PixelShaderCompiler.h" +#include "../../../mpc-hc/resource.h" +#include +#include + +CPixelShaderCompiler::CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent) + : m_hDll(nullptr) + , m_pD3DCompile(nullptr) + , m_pD3DDisassemble(nullptr) + , m_pD3DDev(pD3DDev) + , m_Cache(pD3DDev) +{ + static_assert(D3D_COMPILER_VERSION == MPC_D3D_COMPILER_VERSION, + "MPC_D3D_COMPILER_VERSION define used in the installer needs to be updated."); + m_hDll = LoadLibrary(D3DCOMPILER_DLL); + + if (m_hDll) { + m_pD3DCompile = (pD3DCompile)GetProcAddress(m_hDll, "D3DCompile"); + m_pD3DDisassemble = (pD3DDisassemble)GetProcAddress(m_hDll, "D3DDisassemble"); + } + + if (!fStaySilent) { + if (!m_hDll) { + CString msg; + msg.Format(IDS_SHADER_DLL_ERR_0, D3DCOMPILER_DLL); + AfxMessageBox(msg, MB_ICONWARNING | MB_OK); + } else if (!m_pD3DCompile || !m_pD3DDisassemble) { + CString msg; + msg.Format(IDS_SHADER_DLL_ERR_1, D3DCOMPILER_DLL); + AfxMessageBox(msg, MB_ICONWARNING | MB_OK); + } + } +} + +CPixelShaderCompiler::~CPixelShaderCompiler() +{ + if (m_hDll) { + VERIFY(FreeLibrary(m_hDll)); + } +} + +HRESULT CPixelShaderCompiler::InternalCompile( + LPCSTR pSrcData, + SIZE_T SrcDataSize, + LPCSTR pSourceName, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm, + CString* pErrMsg) +{ + if (!m_pD3DCompile) { + return E_FAIL; + } + + if (pDisasm && !m_pD3DDisassemble) { + return E_FAIL; + } + + if (ppPixelShader && !m_pD3DDev) { + return E_FAIL; + } + + LPCSTR pSelProfile = pProfile; + if (!pSelProfile || *pSelProfile == '\0') { + D3DCAPS9 caps; + if (m_pD3DDev && m_pD3DDev->GetDeviceCaps(&caps) == D3D_OK) { + switch (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion)) { + case 2: + if (caps.PS20Caps.NumInstructionSlots < 512) { + pSelProfile = "ps_2_0"; + } else if (caps.PS20Caps.Caps > 0) { + pSelProfile = "ps_2_a"; + } else { + pSelProfile = "ps_2_b"; + } + break; + case 3: + pSelProfile = "ps_3_0"; + break; + } + } else { + ASSERT(FALSE); + } + } + + if (!pSelProfile || *pSelProfile == '\0') { + return E_FAIL; + } + + LPCSTR defProfile = "MPC_HC_SHADER_PROFILE"; + LPCSTR defProfileVal; + if (!strcmp(pSelProfile, "ps_2_0")) { + defProfileVal = "0"; + } else if (!strcmp(pSelProfile, "ps_2_b")) { + defProfileVal = "1"; + } else if (!strcmp(pSelProfile, "ps_2_a") || !strcmp(pSelProfile, "ps_2_sw")) { + defProfileVal = "2"; + } else if (!strcmp(pSelProfile, "ps_3_0") || !strcmp(pSelProfile, "ps_3_sw")) { + defProfileVal = "3"; + } else { + defProfileVal = "-1"; + } + + if (ppPixelShader && SUCCEEDED(m_Cache.CreatePixelShader(defProfileVal, pSrcData, SrcDataSize, ppPixelShader))) { + return S_OK; + } + + D3D_SHADER_MACRO macros[] = { { defProfile, defProfileVal }, { 0 } }; + + CComPtr pShaderBlob, pErrorBlob; + HRESULT hr = m_pD3DCompile(pSrcData, SrcDataSize, pSourceName, macros, nullptr, pEntrypoint, + pSelProfile, Flags, 0, &pShaderBlob, &pErrorBlob); + + if (pErrMsg) { + CStringA msg; + if (pErrorBlob) { + auto len = pErrorBlob->GetBufferSize(); + VERIFY(memcpy_s(msg.GetBufferSetLength((int)len), len, pErrorBlob->GetBufferPointer(), len) == 0); + msg.ReleaseBuffer((int)len); + } + *pErrMsg = msg; + } + + if (FAILED(hr)) { + return hr; + } + + if (ppPixelShader) { + hr = m_pD3DDev->CreatePixelShader((DWORD*)pShaderBlob->GetBufferPointer(), ppPixelShader); + if (FAILED(hr)) { + return hr; + } + + m_Cache.SavePixelShader(defProfileVal, pSrcData, SrcDataSize, + (void*)pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize()); + } + + if (pDisasm) { + CComPtr pDisasmBlob; + CStringA defs; + for (auto pMacro = macros; pMacro && pMacro->Name && pMacro->Definition; pMacro++) { + defs.Append("// #define "); + defs.Append(pMacro->Name); + defs.Append(" "); + defs.Append(pMacro->Definition); + defs.Append("\n"); + } + hr = m_pD3DDisassemble(pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), + 0, defs, &pDisasmBlob); + if (SUCCEEDED(hr)) { + CStringA disasm; + auto len = pDisasmBlob->GetBufferSize(); + VERIFY(memcpy_s(disasm.GetBufferSetLength((int)len), len, pDisasmBlob->GetBufferPointer(), len) == 0); + disasm.ReleaseBuffer((int)len); + *pDisasm = disasm; + } + } + + return S_OK; +} + +HRESULT CPixelShaderCompiler::CompileShader( + LPCSTR pSrcData, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm, + CString* pErrMsg) +{ + return InternalCompile(pSrcData, strlen(pSrcData), nullptr, pEntrypoint, + pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); +} + +HRESULT CPixelShaderCompiler::CompileShaderFromFile( + LPCTSTR pSrcFile, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm, + CString* pErrMsg) +{ + HRESULT ret = E_FAIL; + if (FILE* fp = _tfsopen(pSrcFile, _T("rb"), _SH_SECURE)) { + VERIFY(fseek(fp, 0, SEEK_END) == 0); + long size = ftell(fp); + rewind(fp); + if (size > 0) { + auto data = new (std::nothrow) char[(size_t)size]; + if (data) { + if (fread(data, size, 1, fp) == 1) { + ret = InternalCompile(data, (size_t)size, CT2A(pSrcFile), pEntrypoint, + pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); + } else { + ASSERT(FALSE); + } + delete[] data; + } else { + ASSERT(FALSE); + } + } + VERIFY(fclose(fp) == 0); + } + return ret; +} diff --git a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h index 5aab64950ec..c5166205efd 100644 --- a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h +++ b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h @@ -1,70 +1,70 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#pragma once - -#include "PixelShaderCache.h" -#include - -class CPixelShaderCompiler -{ - HINSTANCE m_hDll; - - pD3DCompile m_pD3DCompile; - pD3DDisassemble m_pD3DDisassemble; - - CComPtr m_pD3DDev; - - CPixelShaderCache m_Cache; - - HRESULT InternalCompile( - LPCSTR pSrcData, - SIZE_T SrcDataSize, - LPCSTR pSourceName, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg); - -public: - CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent = false); - ~CPixelShaderCompiler(); - - HRESULT CompileShader( - LPCSTR pSrcData, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm = nullptr, - CString* pErrMsg = nullptr); - - HRESULT CompileShaderFromFile( - LPCTSTR pSrcFile, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm = nullptr, - CString* pErrMsg = nullptr); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#pragma once + +#include "PixelShaderCache.h" +#include + +class CPixelShaderCompiler +{ + HINSTANCE m_hDll; + + pD3DCompile m_pD3DCompile; + pD3DDisassemble m_pD3DDisassemble; + + CComPtr m_pD3DDev; + + CPixelShaderCache m_Cache; + + HRESULT InternalCompile( + LPCSTR pSrcData, + SIZE_T SrcDataSize, + LPCSTR pSourceName, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm, + CString* pErrMsg); + +public: + CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent = false); + ~CPixelShaderCompiler(); + + HRESULT CompileShader( + LPCSTR pSrcData, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm = nullptr, + CString* pErrMsg = nullptr); + + HRESULT CompileShaderFromFile( + LPCTSTR pSrcFile, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm = nullptr, + CString* pErrMsg = nullptr); +}; diff --git a/src/filters/renderer/VideoRenderers/RenderersSettings.cpp b/src/filters/renderer/VideoRenderers/RenderersSettings.cpp index 4002ba5e872..b07b4442c78 100644 --- a/src/filters/renderer/VideoRenderers/RenderersSettings.cpp +++ b/src/filters/renderer/VideoRenderers/RenderersSettings.cpp @@ -1,129 +1,129 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "RenderersSettings.h" -#include -#include -#include -#include "d3dx9/d3dx9.h" - -void CRenderersSettings::CAdvRendererSettings::SetDefault() -{ - bVMR9AlterativeVSync = false; - iVMR9VSyncOffset = 0; - bVMR9VSyncAccurate = false; - bVMR9FullscreenGUISupport = false; - bVMR9VSync = false; - bVMR9FullFloatingPointProcessing = false; - bVMR9HalfFloatingPointProcessing = false; - bVMR9ColorManagementEnable = false; - iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; - iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; - iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; - bVMRDisableDesktopComposition = false; - bVMRFlushGPUBeforeVSync = true; - bVMRFlushGPUAfterPresent = true; - bVMRFlushGPUWait = false; - bEVRHighColorResolution = false; - bEVRForceInputHighColorResolution = false; - bEVREnableFrameTimeCorrection = false; - iEVROutputRange = 0; - bSynchronizeVideo = false; - bSynchronizeDisplay = false; - bSynchronizeNearest = true; - iLineDelta = 0; - iColumnDelta = 0; - fCycleDelta = 0.0012; - fTargetSyncOffset = 12.0; - fControlLimit = 2.0; - bCacheShaders = false; - bDesktopSizeBackBuffer = false; -} - -void CRenderersSettings::CAdvRendererSettings::SetOptimal() -{ - bVMR9AlterativeVSync = true; - iVMR9VSyncOffset = 0; - bVMR9VSyncAccurate = true; - bVMR9FullscreenGUISupport = false; - bVMR9VSync = false; - bVMR9FullFloatingPointProcessing = false; - bVMR9HalfFloatingPointProcessing = false; - bVMR9ColorManagementEnable = false; - iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; - iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; - iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; - bVMRDisableDesktopComposition = false; - bVMRFlushGPUBeforeVSync = true; - bVMRFlushGPUAfterPresent = true; - bVMRFlushGPUWait = false; - bEVRHighColorResolution = false; - bEVRForceInputHighColorResolution = false; - bEVREnableFrameTimeCorrection = false; - iEVROutputRange = 0; - bSynchronizeVideo = false; - bSynchronizeDisplay = false; - bSynchronizeNearest = true; - iLineDelta = 0; - iColumnDelta = 0; - fCycleDelta = 0.0012; - fTargetSyncOffset = 12.0; - fControlLimit = 2.0; - bCacheShaders = false; -} - -///////////////////////////////////////////////////////////////////////////// -// CRenderersData construction - -CRenderersData::CRenderersData() - : m_hD3DX9Dll(nullptr) - , m_nDXSdkRelease(D3DX_SDK_VERSION) - , m_bTearingTest(false) - , m_iDisplayStats(0) - , m_bResetStats(false) - // Don't disable hardware features before initializing a renderer - , m_bFP16Support(true) - , m_bFP32Support(true) - , m_b10bitSupport(true) -{ - QueryPerformanceFrequency(&llPerfFrequency); -} - -LONGLONG CRenderersData::GetPerfCounter() const -{ - LARGE_INTEGER i64Ticks100ns; - - QueryPerformanceCounter(&i64Ticks100ns); - return llMulDiv(i64Ticks100ns.QuadPart, 10000000, llPerfFrequency.QuadPart, 0); -} - -HINSTANCE CRenderersData::GetD3X9Dll() -{ - // D3DX9 v43 is the latest available and will not get any update. We support only this specific version. - static_assert(D3DX_SDK_VERSION == MPC_DX_SDK_NUMBER, "Different D3DX9 version?"); - if (m_hD3DX9Dll == nullptr) { - m_strD3DX9Version.Format(_T("d3dx9_%u.dll"), D3DX_SDK_VERSION); - m_hD3DX9Dll = LoadLibrary(m_strD3DX9Version); - } - - return m_hD3DX9Dll; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "RenderersSettings.h" +#include +#include +#include +#include "d3dx9/d3dx9.h" + +void CRenderersSettings::CAdvRendererSettings::SetDefault() +{ + bVMR9AlterativeVSync = false; + iVMR9VSyncOffset = 0; + bVMR9VSyncAccurate = false; + bVMR9FullscreenGUISupport = false; + bVMR9VSync = false; + bVMR9FullFloatingPointProcessing = false; + bVMR9HalfFloatingPointProcessing = false; + bVMR9ColorManagementEnable = false; + iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; + iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; + iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; + bVMRDisableDesktopComposition = false; + bVMRFlushGPUBeforeVSync = true; + bVMRFlushGPUAfterPresent = true; + bVMRFlushGPUWait = false; + bEVRHighColorResolution = false; + bEVRForceInputHighColorResolution = false; + bEVREnableFrameTimeCorrection = false; + iEVROutputRange = 0; + bSynchronizeVideo = false; + bSynchronizeDisplay = false; + bSynchronizeNearest = true; + iLineDelta = 0; + iColumnDelta = 0; + fCycleDelta = 0.0012; + fTargetSyncOffset = 12.0; + fControlLimit = 2.0; + bCacheShaders = false; + bDesktopSizeBackBuffer = false; +} + +void CRenderersSettings::CAdvRendererSettings::SetOptimal() +{ + bVMR9AlterativeVSync = true; + iVMR9VSyncOffset = 0; + bVMR9VSyncAccurate = true; + bVMR9FullscreenGUISupport = false; + bVMR9VSync = false; + bVMR9FullFloatingPointProcessing = false; + bVMR9HalfFloatingPointProcessing = false; + bVMR9ColorManagementEnable = false; + iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; + iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; + iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; + bVMRDisableDesktopComposition = false; + bVMRFlushGPUBeforeVSync = true; + bVMRFlushGPUAfterPresent = true; + bVMRFlushGPUWait = false; + bEVRHighColorResolution = false; + bEVRForceInputHighColorResolution = false; + bEVREnableFrameTimeCorrection = false; + iEVROutputRange = 0; + bSynchronizeVideo = false; + bSynchronizeDisplay = false; + bSynchronizeNearest = true; + iLineDelta = 0; + iColumnDelta = 0; + fCycleDelta = 0.0012; + fTargetSyncOffset = 12.0; + fControlLimit = 2.0; + bCacheShaders = false; +} + +///////////////////////////////////////////////////////////////////////////// +// CRenderersData construction + +CRenderersData::CRenderersData() + : m_hD3DX9Dll(nullptr) + , m_nDXSdkRelease(D3DX_SDK_VERSION) + , m_bTearingTest(false) + , m_iDisplayStats(0) + , m_bResetStats(false) + // Don't disable hardware features before initializing a renderer + , m_bFP16Support(true) + , m_bFP32Support(true) + , m_b10bitSupport(true) +{ + QueryPerformanceFrequency(&llPerfFrequency); +} + +LONGLONG CRenderersData::GetPerfCounter() const +{ + LARGE_INTEGER i64Ticks100ns; + + QueryPerformanceCounter(&i64Ticks100ns); + return llMulDiv(i64Ticks100ns.QuadPart, 10000000, llPerfFrequency.QuadPart, 0); +} + +HINSTANCE CRenderersData::GetD3X9Dll() +{ + // D3DX9 v43 is the latest available and will not get any update. We support only this specific version. + static_assert(D3DX_SDK_VERSION == MPC_DX_SDK_NUMBER, "Different D3DX9 version?"); + if (m_hD3DX9Dll == nullptr) { + m_strD3DX9Version.Format(_T("d3dx9_%u.dll"), D3DX_SDK_VERSION); + m_hD3DX9Dll = LoadLibrary(m_strD3DX9Version); + } + + return m_hD3DX9Dll; +} diff --git a/src/filters/renderer/VideoRenderers/RenderersSettings.h b/src/filters/renderer/VideoRenderers/RenderersSettings.h index 1ba0dc3457d..7723f61c3fd 100644 --- a/src/filters/renderer/VideoRenderers/RenderersSettings.h +++ b/src/filters/renderer/VideoRenderers/RenderersSettings.h @@ -1,155 +1,155 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "../../../SubPic/SubPicQueueSettings.h" - -enum { - WM_REARRANGERENDERLESS = WM_APP + 1, - WM_RESET_DEVICE -}; - -#define WM_MYMOUSELAST WM_XBUTTONDBLCLK - -enum { - VIDRNDT_AP_SURFACE, - VIDRNDT_AP_TEXTURE2D, - VIDRNDT_AP_TEXTURE3D -}; - -enum VideoSystem { - VIDEO_SYSTEM_UNKNOWN, - VIDEO_SYSTEM_HDTV, - VIDEO_SYSTEM_SDTV_NTSC, - VIDEO_SYSTEM_SDTV_PAL -}; - -enum AmbientLight { - AMBIENT_LIGHT_BRIGHT, - AMBIENT_LIGHT_DIM, - AMBIENT_LIGHT_DARK -}; - -enum ColorRenderingIntent { - COLOR_RENDERING_INTENT_PERCEPTUAL, - COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, - COLOR_RENDERING_INTENT_SATURATION, - COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC -}; - -class CRenderersSettings -{ - -public: - bool fResetDevice; - - class CAdvRendererSettings - { - public: - CAdvRendererSettings() { SetDefault(); } - - bool bVMR9AlterativeVSync; - int iVMR9VSyncOffset; - bool bVMR9VSyncAccurate; - bool bVMR9FullscreenGUISupport; - bool bVMR9VSync; - bool bVMR9FullFloatingPointProcessing; - bool bVMR9HalfFloatingPointProcessing; - bool bVMR9ColorManagementEnable; - int iVMR9ColorManagementInput; - int iVMR9ColorManagementAmbientLight; - int iVMR9ColorManagementIntent; - bool bVMRDisableDesktopComposition; - bool bVMRFlushGPUBeforeVSync; - bool bVMRFlushGPUAfterPresent; - bool bVMRFlushGPUWait; - bool bDesktopSizeBackBuffer; - - // EVR - bool bEVRHighColorResolution; - bool bEVRForceInputHighColorResolution; - bool bEVREnableFrameTimeCorrection; - int iEVROutputRange; - - // SyncRenderer settings - bool bSynchronizeVideo; - bool bSynchronizeDisplay; - bool bSynchronizeNearest; - int iLineDelta; - int iColumnDelta; - double fCycleDelta; - double fTargetSyncOffset; - double fControlLimit; - - // Other settings - bool bCacheShaders; - CString sShaderCachePath; - - void SetDefault(); - void SetOptimal(); - }; - - CAdvRendererSettings m_AdvRendSets; - - int iAPSurfaceUsage; - int iDX9Resizer; - bool fVMR9MixerMode; - int iEvrBuffers; - - SubPicQueueSettings subPicQueueSettings; - - int subPicVerticalShift; - double fontScaleOverride; - - CString D3D9RenderDevice; - void UpdateData(bool fSave); -}; - -class CRenderersData -{ - HINSTANCE m_hD3DX9Dll; - const UINT m_nDXSdkRelease; - LARGE_INTEGER llPerfFrequency; - -public: - CRenderersData(); - - bool m_bTearingTest; - int m_iDisplayStats; - bool m_bResetStats; // Set to reset the presentation statistics - CString m_strD3DX9Version; - - // Hardware feature support - bool m_bFP16Support; - bool m_bFP32Support; - bool m_b10bitSupport; - CString m_strDXVAInfo; - - LONGLONG GetPerfCounter() const; - HINSTANCE GetD3X9Dll(); - UINT GetDXSdkRelease() const { return m_nDXSdkRelease; }; -}; - -extern CRenderersData* GetRenderersData(); -extern CRenderersSettings& GetRenderersSettings(); - -extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "../../../SubPic/SubPicQueueSettings.h" + +enum { + WM_REARRANGERENDERLESS = WM_APP + 1, + WM_RESET_DEVICE +}; + +#define WM_MYMOUSELAST WM_XBUTTONDBLCLK + +enum { + VIDRNDT_AP_SURFACE, + VIDRNDT_AP_TEXTURE2D, + VIDRNDT_AP_TEXTURE3D +}; + +enum VideoSystem { + VIDEO_SYSTEM_UNKNOWN, + VIDEO_SYSTEM_HDTV, + VIDEO_SYSTEM_SDTV_NTSC, + VIDEO_SYSTEM_SDTV_PAL +}; + +enum AmbientLight { + AMBIENT_LIGHT_BRIGHT, + AMBIENT_LIGHT_DIM, + AMBIENT_LIGHT_DARK +}; + +enum ColorRenderingIntent { + COLOR_RENDERING_INTENT_PERCEPTUAL, + COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, + COLOR_RENDERING_INTENT_SATURATION, + COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC +}; + +class CRenderersSettings +{ + +public: + bool fResetDevice; + + class CAdvRendererSettings + { + public: + CAdvRendererSettings() { SetDefault(); } + + bool bVMR9AlterativeVSync; + int iVMR9VSyncOffset; + bool bVMR9VSyncAccurate; + bool bVMR9FullscreenGUISupport; + bool bVMR9VSync; + bool bVMR9FullFloatingPointProcessing; + bool bVMR9HalfFloatingPointProcessing; + bool bVMR9ColorManagementEnable; + int iVMR9ColorManagementInput; + int iVMR9ColorManagementAmbientLight; + int iVMR9ColorManagementIntent; + bool bVMRDisableDesktopComposition; + bool bVMRFlushGPUBeforeVSync; + bool bVMRFlushGPUAfterPresent; + bool bVMRFlushGPUWait; + bool bDesktopSizeBackBuffer; + + // EVR + bool bEVRHighColorResolution; + bool bEVRForceInputHighColorResolution; + bool bEVREnableFrameTimeCorrection; + int iEVROutputRange; + + // SyncRenderer settings + bool bSynchronizeVideo; + bool bSynchronizeDisplay; + bool bSynchronizeNearest; + int iLineDelta; + int iColumnDelta; + double fCycleDelta; + double fTargetSyncOffset; + double fControlLimit; + + // Other settings + bool bCacheShaders; + CString sShaderCachePath; + + void SetDefault(); + void SetOptimal(); + }; + + CAdvRendererSettings m_AdvRendSets; + + int iAPSurfaceUsage; + int iDX9Resizer; + bool fVMR9MixerMode; + int iEvrBuffers; + + SubPicQueueSettings subPicQueueSettings; + + int subPicVerticalShift; + double fontScaleOverride; + + CString D3D9RenderDevice; + void UpdateData(bool fSave); +}; + +class CRenderersData +{ + HINSTANCE m_hD3DX9Dll; + const UINT m_nDXSdkRelease; + LARGE_INTEGER llPerfFrequency; + +public: + CRenderersData(); + + bool m_bTearingTest; + int m_iDisplayStats; + bool m_bResetStats; // Set to reset the presentation statistics + CString m_strD3DX9Version; + + // Hardware feature support + bool m_bFP16Support; + bool m_bFP32Support; + bool m_b10bitSupport; + CString m_strDXVAInfo; + + LONGLONG GetPerfCounter() const; + HINSTANCE GetD3X9Dll(); + UINT GetDXSdkRelease() const { return m_nDXSdkRelease; }; +}; + +extern CRenderersData* GetRenderersData(); +extern CRenderersSettings& GetRenderersSettings(); + +extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); diff --git a/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h index b07d5d098b8..0a6aa2c072d 100644 --- a/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h @@ -1,33 +1,33 @@ -/* - * (C) 2010-2012, 2017 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 . - * - */ - -#pragma once - -// {F9F62627-E3EF-4a2e-B6C9-5D4C0DC3326B} -DEFINE_GUID(CLSID_SyncAllocatorPresenter, 0xf9f62627, 0xe3ef, 0x4a2e, 0xb6, 0xc9, 0x5d, 0x4c, 0xd, 0xc3, 0x32, 0x6b); - -interface __declspec(uuid("F891C2A9-1DFF-45e0-9129-30C0990C5A9F")) - ISyncClockAdviser : - public IUnknown -{ - STDMETHOD(AdviseSyncClock)(ISyncClock* sC) PURE; -}; - -HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP); +/* + * (C) 2010-2012, 2017 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 . + * + */ + +#pragma once + +// {F9F62627-E3EF-4a2e-B6C9-5D4C0DC3326B} +DEFINE_GUID(CLSID_SyncAllocatorPresenter, 0xf9f62627, 0xe3ef, 0x4a2e, 0xb6, 0xc9, 0x5d, 0x4c, 0xd, 0xc3, 0x32, 0x6b); + +interface __declspec(uuid("F891C2A9-1DFF-45e0-9129-30C0990C5A9F")) + ISyncClockAdviser : + public IUnknown +{ + STDMETHOD(AdviseSyncClock)(ISyncClock* sC) PURE; +}; + +HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP); diff --git a/src/filters/renderer/VideoRenderers/SyncRenderer.cpp b/src/filters/renderer/VideoRenderers/SyncRenderer.cpp index cd152a56d7f..abc017d3a69 100644 --- a/src/filters/renderer/VideoRenderers/SyncRenderer.cpp +++ b/src/filters/renderer/VideoRenderers/SyncRenderer.cpp @@ -1,4720 +1,4720 @@ -/* - * (C) 2010-2017 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 . - * - */ - -#include "stdafx.h" -#include "../SyncClock/Interfaces.h" -#include -#include -#include -#include "../../../mpc-hc/resource.h" -#include "../../../DSUtil/DSUtil.h" -#include "../../../DSUtil/WinAPIUtils.h" -#include // Required in CGenlock -#include -#include -#include "d3dx9/d3dx9.h" -#include -#include -#include -#include -#include "../../../SubPic/DX9SubPic.h" -#include "../../../SubPic/SubPicQueueImpl.h" -#include "moreuuids.h" -#include "MacrovisionKicker.h" -#include "IPinHook.h" -#include "PixelShaderCompiler.h" -#include "FocusThread.h" -#include "../../../DSUtil/vd.h" -#include - -#include -#include -#include "SyncRenderer.h" -#include "Utils.h" -#include "Variables.h" - -#if (0) // Set to 1 to activate SyncRenderer traces -#define TRACE_SR TRACE -#else -#define TRACE_SR __noop -#endif - - -#define REFERENCE_WIDTH 1920 -#define FONT_HEIGHT 21 -#define BOLD_THRESHOLD 11 -#define TEXT_PADDING 2 -#define GRAPH_HEIGHT 360 -#define GRAPH_WIDTH 1000 - -using namespace GothSync; - -extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); - -CBaseAP::CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) - : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) - , m_hDWMAPI(nullptr) - , m_pDwmIsCompositionEnabled(nullptr) - , m_pDwmEnableComposition(nullptr) - , m_pOuterEVR(nullptr) - , m_SurfaceType(D3DFMT_UNKNOWN) - , m_BackbufferType(D3DFMT_UNKNOWN) - , m_DisplayType(D3DFMT_UNKNOWN) - , m_filter(D3DTEXF_NONE) - , m_LastAdapterCheck(0) - , m_CurrentAdapter(UINT_ERROR) - , m_bicubicA(0) - , m_nTearingPos(0) - , m_VMR9AlphaBitmapWidthBytes() - , m_pD3DXLoadSurfaceFromMemory(nullptr) - , m_pD3DXLoadSurfaceFromSurface(nullptr) - , m_pD3DXCreateLine(nullptr) - , m_pD3DXCreateFont(nullptr) - , m_pD3DXCreateSprite(nullptr) - , m_nDXSurface(1) - , m_nVMR9Surfaces(0) - , m_iVMR9Surface(0) - , m_nCurSurface(0) - , m_nUsedBuffer(0) - , m_lNextSampleWait(1) - , m_bSnapToVSync(false) - , m_uScanLineEnteringPaint(0) - , m_llEstVBlankTime(0) - , m_fAvrFps(0.0) - , m_fJitterStdDev(0.0) - , m_fJitterMean(0) - , m_fSyncOffsetAvr(0.0) - , m_fSyncOffsetStdDev(0.0) - , m_bHighColorResolution(false) - , m_bCompositionEnabled(false) - , m_bDesktopCompositionDisabled(false) - , m_bIsFullscreen(bFullscreen) - , fullScreenChanged(false) - , m_bNeedCheckSample(true) - , m_dMainThreadId(0) - , m_ScreenSize(0, 0) - , m_dDetectedScanlineTime(0.0) - , m_dD3DRefreshCycle(0) - , m_dEstRefreshCycle(0.0) - , m_dFrameCycle(0.0) - , m_dOptimumDisplayCycle(0.0) - , m_dCycleDifference(1.0) - , m_pcFramesDropped(0) - , m_pcFramesDuplicated(0) - , m_pcFramesDrawn(0) - , m_nNextJitter(0) - , m_nNextSyncOffset(0) - , m_JitterStdDev(0) - , m_llLastSyncTime(LONGLONG_ERROR) - , m_MaxJitter(MINLONG64) - , m_MinJitter(MAXLONG64) - , m_MaxSyncOffset(MINLONG64) - , m_MinSyncOffset(MAXLONG64) - , m_uSyncGlitches(0) - , m_llSampleTime(0) - , m_llLastSampleTime(0) - , m_llHysteresis(0) - , m_lShiftToNearest(0) - , m_lShiftToNearestPrev(0) - , m_bVideoSlowerThanDisplay(0) - , m_rtTimePerFrame(0) - , m_bInterlaced(false) - , m_TextScale(1.0) - , m_pGenlock(nullptr) - , m_pAudioStats(nullptr) - , m_lAudioLag(0) - , m_lAudioLagMin(10000) - , m_lAudioLagMax(-10000) - , m_lAudioSlaveMode(0) - , m_FocusThread(nullptr) - , m_hFocusWindow(nullptr) -{ - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - ZeroMemory(&m_caps, sizeof(m_caps)); - ZeroMemory(&m_pp, sizeof(m_pp)); - - if (FAILED(hr)) { - _Error += _T("ISubPicAllocatorPresenterImpl failed\n"); - return; - } - - HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); - - if (hDll) { - (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory"); - (FARPROC&)m_pD3DXLoadSurfaceFromSurface = GetProcAddress(hDll, "D3DXLoadSurfaceFromSurface"); - (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine"); - (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW"); - (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite"); - } else { - _Error += _T("The installed DirectX End-User Runtime is outdated. Please download and install the "); - _Error += MPC_DX_SDK_MONTH _T(" ") MAKE_STR(MPC_DX_SDK_YEAR); - _Error += _T(" release or newer in order for MPC-HC to function properly.\n"); - } - - m_hDWMAPI = LoadLibrary(L"dwmapi.dll"); - if (m_hDWMAPI) { - (FARPROC&)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled"); - (FARPROC&)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition"); - } - - Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); - if (m_pD3DEx) { - m_pD3D = m_pD3DEx; - } - - const CRenderersSettings& r = GetRenderersSettings(); - if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { - m_bDesktopCompositionDisabled = true; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(0); - } - } else { - m_bDesktopCompositionDisabled = false; - } - - m_pGenlock = DEBUG_NEW CGenlock(r.m_AdvRendSets.fTargetSyncOffset, r.m_AdvRendSets.fControlLimit, r.m_AdvRendSets.iLineDelta, r.m_AdvRendSets.iColumnDelta, r.m_AdvRendSets.fCycleDelta, 0); // Must be done before CreateDXDevice - hr = CreateDXDevice(_Error); - ZeroMemory(m_pllJitter, sizeof(m_pllJitter)); - ZeroMemory(m_pllSyncOffset, sizeof(m_pllSyncOffset)); -} - -CBaseAP::~CBaseAP() -{ - if (m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = false; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(1); - } - } - - m_pFont = nullptr; - m_pLine = nullptr; - m_pSprite = nullptr; - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - m_pPSC.Free(); - m_pD3D = nullptr; - m_pD3DEx = nullptr; - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - - m_pAudioStats = nullptr; - SAFE_DELETE(m_pGenlock); - - if (m_FocusThread) { - m_FocusThread->PostThreadMessage(WM_QUIT, 0, 0); - if (WaitForSingleObject(m_FocusThread->m_hThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_FocusThread->m_hThread, 0xDEAD); - } - } - - if (m_hDWMAPI) { - FreeLibrary(m_hDWMAPI); - m_hDWMAPI = nullptr; - } -} - -template -void CBaseAP::AdjustQuad(MYD3DVERTEX* v, double dx, double dy) -{ - float offset = 0.5; - - for (int i = 0; i < 4; i++) { - v[i].x -= offset; - v[i].y -= offset; - - for (int j = 0; j < std::max(texcoords - 1, 1); j++) { - v[i].t[j].u -= (float)(offset * dx); - v[i].t[j].v -= (float)(offset * dy); - } - - if constexpr(texcoords > 1) { - v[i].t[texcoords - 1].u -= offset; - v[i].t[texcoords - 1].v -= offset; - } - } -} - -template -HRESULT CBaseAP::TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter = D3DTEXF_LINEAR) -{ - CheckPointer(pD3DDev, E_POINTER); - - DWORD FVF = 0; - switch (texcoords) { - case 1: - FVF = D3DFVF_TEX1; - break; - case 2: - FVF = D3DFVF_TEX2; - break; - case 3: - FVF = D3DFVF_TEX3; - break; - case 4: - FVF = D3DFVF_TEX4; - break; - case 5: - FVF = D3DFVF_TEX5; - break; - case 6: - FVF = D3DFVF_TEX6; - break; - case 7: - FVF = D3DFVF_TEX7; - break; - case 8: - FVF = D3DFVF_TEX8; - break; - default: - return E_FAIL; - } - - HRESULT hr; - hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); - - for (int i = 0; i < texcoords; i++) { - hr = pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); - hr = pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter); - hr = pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - } - - hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF); - - MYD3DVERTEX tmp = v[2]; - v[2] = v[3]; - v[3] = tmp; - hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); - - for (int i = 0; i < texcoords; i++) { - pD3DDev->SetTexture(i, nullptr); - } - - return S_OK; -} - -HRESULT CBaseAP::DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]) -{ - CheckPointer(pD3DDev, E_POINTER); - - HRESULT hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - hr = pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - hr = pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - - hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); - - hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE); - - MYD3DVERTEX<0> tmp = v[2]; - v[2] = v[3]; - v[3] = tmp; - hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); - - return S_OK; -} - -MFOffset CBaseAP::GetOffset(float v) -{ - MFOffset offset; - offset.value = short(v); - offset.fract = WORD(65536 * (v - offset.value)); - return offset; -} - -MFVideoArea CBaseAP::GetArea(float x, float y, DWORD width, DWORD height) -{ - MFVideoArea area; - area.OffsetX = GetOffset(x); - area.OffsetY = GetOffset(y); - area.Area.cx = width; - area.Area.cy = height; - return area; -} - -void CBaseAP::ResetStats() -{ - m_pGenlock->ResetStats(); - m_lAudioLag = 0; - m_lAudioLagMin = 10000; - m_lAudioLagMax = -10000; - m_MinJitter = MAXLONG64; - m_MaxJitter = MINLONG64; - m_MinSyncOffset = MAXLONG64; - m_MaxSyncOffset = MINLONG64; - m_uSyncGlitches = 0; - m_pcFramesDropped = 0; - m_llLastSyncTime = LONGLONG_ERROR; -} - -bool CBaseAP::SettingsNeedResetDevice() -{ - CRenderersSettings& r = GetRenderersSettings(); - CRenderersSettings::CAdvRendererSettings& New = r.m_AdvRendSets; - CRenderersSettings::CAdvRendererSettings& Current = m_LastRendererSettings; - - bool bRet = false; - if (!m_bIsFullscreen) { - if (Current.bVMRDisableDesktopComposition) { - if (!m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = true; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(0); - } - } - } else { - if (m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = false; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(1); - } - } - } - } - bRet = bRet || New.bEVRHighColorResolution != Current.bEVRHighColorResolution; - m_LastRendererSettings = r.m_AdvRendSets; - return bRet; -} - -HRESULT CBaseAP::CreateDXDevice(CString& _Error) -{ - TRACE(_T("--> CBaseAP::CreateDXDevice on thread: %lu\n"), GetCurrentThreadId()); - const CRenderersSettings& r = GetRenderersSettings(); - m_LastRendererSettings = r.m_AdvRendSets; - HRESULT hr = E_FAIL; - - m_pFont = nullptr; - m_pSprite = nullptr; - m_pLine = nullptr; - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - - m_pPSC.Free(); - - m_pResizerPixelShader[0] = 0; - m_pResizerPixelShader[1] = 0; - m_pResizerPixelShader[2] = 0; - m_pResizerPixelShader[3] = 0; - - POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - pos = m_pPixelShaders.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - - UINT currentAdapter = GetAdapter(m_pD3D, m_hWnd); - bool bTryToReset = (currentAdapter == m_CurrentAdapter); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - m_CurrentAdapter = currentAdapter; - } - - if (!m_pD3D) { - _Error += L"Failed to create Direct3D device\n"; - return E_UNEXPECTED; - } - - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - if (FAILED(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)) - || d3ddm.Width <= 0 || d3ddm.Height <= 0) { - _Error += L"Can not retrieve display mode data\n"; - return E_UNEXPECTED; - } - - if (FAILED(m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &m_caps))) { - if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0) { - _Error += L"Video card does not have scanline access. Display synchronization is not possible.\n"; - return E_UNEXPECTED; - } - } - - m_refreshRate = d3ddm.RefreshRate; - m_dD3DRefreshCycle = 1000.0 / m_refreshRate; // In ms - m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); - m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height); - - BOOL bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - m_bCompositionEnabled = bCompositionEnabled != 0; - - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - - ZeroMemory(&m_pp, sizeof(m_pp)); - if (m_bIsFullscreen) { // Exclusive mode fullscreen - m_pp.Windowed = FALSE; - m_pp.BackBufferWidth = d3ddm.Width; - m_pp.BackBufferHeight = d3ddm.Height; - m_pp.hDeviceWindow = m_hWnd; - TRACE(_T("Wnd in CreateDXDevice: %p\n"), m_hWnd); - m_pp.BackBufferCount = 3; - m_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - m_pp.Flags = D3DPRESENTFLAG_VIDEO; - m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; - if (m_bHighColorResolution) { - if (FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false))) { - m_strStatsMsg[MSG_ERROR] = L"10 bit RGB is not supported by this graphics device in this resolution."; - m_bHighColorResolution = false; - } - } - - if (m_bHighColorResolution) { - m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } else { - m_pp.BackBufferFormat = d3ddm.Format; - } - - if (!m_FocusThread) { - m_FocusThread = (CFocusThread*)AfxBeginThread(RUNTIME_CLASS(CFocusThread), 0, 0, 0); - } - - HWND hFocusWindow = m_FocusThread->GetFocusWindow(); - bTryToReset &= (m_hFocusWindow == hFocusWindow || fullScreenChanged); - m_hFocusWindow = hFocusWindow; - - if (m_pD3DEx) { - D3DDISPLAYMODEEX DisplayMode; - ZeroMemory(&DisplayMode, sizeof(DisplayMode)); - DisplayMode.Size = sizeof(DisplayMode); - m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); - - DisplayMode.Format = m_pp.BackBufferFormat; - m_pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate; - - bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&m_pp, &DisplayMode)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - hr = m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS | D3DCREATE_NOWINDOWCHANGES, - &m_pp, &DisplayMode, &m_pD3DDevEx); - } - - if (m_pD3DDevEx) { - m_pD3DDev = m_pD3DDevEx; - m_BackbufferType = m_pp.BackBufferFormat; - m_DisplayType = DisplayMode.Format; - } - } else { - bTryToReset = bTryToReset && m_pD3DDev && SUCCEEDED(hr = m_pD3DDev->Reset(&m_pp)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - hr = m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_NOWINDOWCHANGES, - &m_pp, &m_pD3DDev); - } - TRACE(_T("Created full-screen device\n")); - if (m_pD3DDev) { - m_BackbufferType = m_pp.BackBufferFormat; - m_DisplayType = d3ddm.Format; - } - } - } else { // Windowed - m_pp.Windowed = TRUE; - m_pp.hDeviceWindow = m_hWnd; - m_pp.SwapEffect = D3DSWAPEFFECT_COPY; - m_pp.Flags = D3DPRESENTFLAG_VIDEO; - m_pp.BackBufferCount = 1; - CSize bbsize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); - m_pp.BackBufferWidth = bbsize.cx; - m_pp.BackBufferHeight = bbsize.cy; - m_BackbufferType = d3ddm.Format; - m_DisplayType = d3ddm.Format; - m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; - if (m_bHighColorResolution) { - if (FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false))) { - m_strStatsMsg[MSG_ERROR] = L"10 bit RGB is not supported by this graphics device in this resolution."; - m_bHighColorResolution = false; - } - } - - if (m_bHighColorResolution) { - m_BackbufferType = D3DFMT_A2R10G10B10; - m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } - if (bCompositionEnabled) { - // Desktop composition presents the whole desktop - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - } else { - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - } - - bTryToReset &= (m_hFocusWindow == m_hWnd || fullScreenChanged); - m_hFocusWindow = m_hWnd; - - if (m_pD3DEx) { - bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&m_pp, nullptr)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - hr = m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS, - &m_pp, nullptr, &m_pD3DDevEx); - } - - if (m_pD3DDevEx) { - m_pD3DDev = m_pD3DDevEx; - } - } else { - if (bTryToReset) { - if (!m_pD3DDev || FAILED(hr = m_pD3DDev->Reset(&m_pp))) { - bTryToReset = false; - } - } - if (!bTryToReset) { - hr = m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED, - &m_pp, &m_pD3DDev); - } - TRACE(_T("Created windowed device\n")); - } - } - - if (m_pD3DDev) { - while (hr == D3DERR_DEVICELOST) { - TRACE(_T("D3DERR_DEVICELOST. Trying to Reset.\n")); - hr = m_pD3DDev->TestCooperativeLevel(); - } - if (hr == D3DERR_DEVICENOTRESET) { - TRACE(_T("D3DERR_DEVICENOTRESET\n")); - hr = m_pD3DDev->Reset(&m_pp); - } - - if (m_pD3DDevEx) { - m_pD3DDevEx->SetGPUThreadPriority(7); - } - } - - if (FAILED(hr)) { - _Error.AppendFormat(_T("CreateDevice failed: %s\n"), GetWindowsErrorMessage(hr, nullptr).GetString()); - - return hr; - } - - m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); - m_filter = D3DTEXF_NONE; - - if (m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR && m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR) { - m_filter = D3DTEXF_LINEAR; - } - - m_bicubicA = 0; - - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(m_pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); - } - - hr = S_OK; - - CComPtr pSubPicProvider; - if (m_pSubPicQueue) { - TRACE(_T("m_pSubPicQueue != nullptr\n")); - m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); - } - - if (!m_pSubPicQueue) { - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - m_pSubPicQueue->Invalidate(); - } - - if (FAILED(hr)) { - _Error += L"m_pSubPicQueue failed\n"; - return hr; - } - - if (pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); - } - - m_LastAdapterCheck = GetRenderersData()->GetPerfCounter(); - return S_OK; -} - -HRESULT CBaseAP::ResetDXDevice(CString& _Error) -{ - const CRenderersSettings& r = GetRenderersSettings(); - m_LastRendererSettings = r.m_AdvRendSets; - HRESULT hr = E_FAIL; - - hr = m_pD3DDev->TestCooperativeLevel(); - if ((hr != D3DERR_DEVICENOTRESET) && (hr != D3D_OK)) { - return hr; - } - - CComPtr rendererInputEnum; - std::vector> decoderOutput; - std::vector> rendererInput; - CFilterInfo filterInfo; - - bool disconnected = false; - - // Disconnect all pins to release video memory resources - if (m_pD3DDev) { - m_pOuterEVR->QueryFilterInfo(&filterInfo); - if (SUCCEEDED(m_pOuterEVR->EnumPins(&rendererInputEnum))) { - CComPtr input; - CComPtr output; - while (hr = rendererInputEnum->Next(1, &input.p, 0), hr == S_OK) { // Must have .p here - TRACE(_T("Pin found\n")); - input->ConnectedTo(&output.p); - if (output != nullptr) { - rendererInput.push_back(input); - decoderOutput.push_back(output); - } - input.Release(); - output.Release(); - } - } else { - return hr; - } - if (filterInfo.pGraph) { - for (size_t i = 0; i < decoderOutput.size(); i++) { - TRACE(_T("Disconnecting pin\n")); - filterInfo.pGraph->Disconnect(decoderOutput[i].p); - filterInfo.pGraph->Disconnect(rendererInput[i].p); - TRACE(_T("Pin disconnected\n")); - } - disconnected = true; - } - } - - // Release more resources - m_pSubPicQueue = nullptr; - m_pFont = nullptr; - m_pSprite = nullptr; - m_pLine = nullptr; - m_pPSC.Free(); - - m_pResizerPixelShader[0] = 0; - m_pResizerPixelShader[1] = 0; - m_pResizerPixelShader[2] = 0; - m_pResizerPixelShader[3] = 0; - - POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - pos = m_pPixelShaders.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - if (FAILED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D, m_hWnd), &d3ddm)) - || d3ddm.Width <= 0 || d3ddm.Height <= 0) { - _Error += L"Can not retrieve display mode data\n"; - return E_UNEXPECTED; - } - - m_refreshRate = d3ddm.RefreshRate; - m_dD3DRefreshCycle = 1000.0 / m_refreshRate; // In ms - m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); - m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height); - CSize szDesktopSize(GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)); - - ZeroMemory(&m_pp, sizeof(m_pp)); - - BOOL bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - m_bCompositionEnabled = bCompositionEnabled != 0; - m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; - - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - - if (m_bIsFullscreen) { // Exclusive mode fullscreen - m_pp.BackBufferWidth = d3ddm.Width; - m_pp.BackBufferHeight = d3ddm.Height; - if (m_bHighColorResolution) { - m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } else { - m_pp.BackBufferFormat = d3ddm.Format; - } - if (FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_pp.BackBufferFormat, m_pp.BackBufferFormat, false))) { - _Error += L"10 bit RGB is not supported by this graphics device in exclusive mode fullscreen.\n"; - return hr; - } - - D3DDISPLAYMODEEX DisplayMode; - ZeroMemory(&DisplayMode, sizeof(DisplayMode)); - DisplayMode.Size = sizeof(DisplayMode); - if (m_pD3DDevEx) { - m_pD3DEx->GetAdapterDisplayModeEx(GetAdapter(m_pD3DEx, m_hWnd), &DisplayMode, nullptr); - DisplayMode.Format = m_pp.BackBufferFormat; - m_pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate; - if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { - _Error += GetWindowsErrorMessage(hr, nullptr); - return hr; - } - } else if (m_pD3DDev) { - if (FAILED(m_pD3DDev->Reset(&m_pp))) { - _Error += GetWindowsErrorMessage(hr, nullptr); - return hr; - } - } else { - _Error += L"No device.\n"; - return hr; - } - m_BackbufferType = m_pp.BackBufferFormat; - m_DisplayType = d3ddm.Format; - } else { // Windowed - CSize bbsize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); - m_pp.BackBufferWidth = bbsize.cx; - m_pp.BackBufferHeight = bbsize.cy; - m_BackbufferType = d3ddm.Format; - m_DisplayType = d3ddm.Format; - if (m_bHighColorResolution) { - m_BackbufferType = D3DFMT_A2R10G10B10; - m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } - if (FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_pp.BackBufferFormat, m_pp.BackBufferFormat, false))) { - _Error += L"10 bit RGB is not supported by this graphics device in windowed mode.\n"; - return hr; - } - if (bCompositionEnabled) { - // Desktop composition presents the whole desktop - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - } else { - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - } - if (m_pD3DDevEx) - if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { - _Error += GetWindowsErrorMessage(hr, nullptr); - return hr; - } else if (m_pD3DDev) - if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { - _Error += GetWindowsErrorMessage(hr, nullptr); - return hr; - } else { - _Error += L"No device.\n"; - return hr; - } - } - - if (disconnected) { - for (size_t i = 0; i < decoderOutput.size(); i++) { - if (FAILED(filterInfo.pGraph->ConnectDirect(decoderOutput[i].p, rendererInput[i].p, nullptr))) { - return hr; - } - } - } - - m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); - m_filter = D3DTEXF_NONE; - - if ((m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) - && (m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)) { - m_filter = D3DTEXF_LINEAR; - } - - m_bicubicA = 0; - - CComPtr pSubPicProvider; - if (m_pSubPicQueue) { - m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); - } - - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(m_pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); - } - - hr = S_OK; - if (!m_pSubPicQueue) { - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - m_pSubPicQueue->Invalidate(); - } - - if (FAILED(hr)) { - _Error += L"m_pSubPicQueue failed\n"; - - return hr; - } - - if (pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); - } - - m_pFont = nullptr; - m_pSprite = nullptr; - m_pLine = nullptr; - - return S_OK; -} - -HRESULT CBaseAP::AllocSurfaces(D3DFORMAT Format) -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_allocatorLock); - - CheckPointer(m_pD3DDev, E_POINTER); - - const CRenderersSettings& r = GetRenderersSettings(); - - for (int i = 0; i < m_nDXSurface + 2; i++) { - m_pVideoTexture[i] = nullptr; - m_pVideoSurface[i] = nullptr; - } - - m_pScreenSizeTemporaryTexture[0] = nullptr; - m_pScreenSizeTemporaryTexture[1] = nullptr; - m_SurfaceType = Format; - - HRESULT hr; - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { - int nTexturesNeeded = r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nDXSurface + 2 : 1; - - for (int i = 0; i < nTexturesNeeded; i++) { - if (FAILED(hr = m_pD3DDev->CreateTexture( - m_nativeVideoSize.cx, - m_nativeVideoSize.cy, - 1, - D3DUSAGE_RENDERTARGET, - Format, - D3DPOOL_DEFAULT, - &m_pVideoTexture[i], - nullptr))) { - return hr; - } - - if (FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i]))) { - return hr; - } - } - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D) { - for (int i = 0; i < m_nDXSurface + 2; i++) { - m_pVideoTexture[i] = nullptr; - } - } - } else { - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(m_nativeVideoSize.cx, m_nativeVideoSize.cy, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], nullptr))) { - return hr; - } - } - - hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], nullptr, 0); - return S_OK; -} - -void CBaseAP::DeleteSurfaces() -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_allocatorLock); - - for (int i = 0; i < m_nDXSurface + 2; i++) { - m_pVideoTexture[i] = nullptr; - m_pVideoSurface[i] = nullptr; - } -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP CBaseAP::CreateRenderer(IUnknown** ppRenderer) -{ - return E_NOTIMPL; -} - -bool CBaseAP::ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pSurface->GetDesc(&desc))) { - return false; - } - - int w = desc.Width, h = desc.Height; - int sw = s.Width(), sh = s.Height(); - int dw = d.Width(), dh = d.Height(); - - if (d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0 - || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) { - s.SetRectEmpty(); - d.SetRectEmpty(); - return true; - } - if (d.right > w) { - s.right -= (d.right - w) * sw / dw; - d.right = w; - } - if (d.bottom > h) { - s.bottom -= (d.bottom - h) * sh / dh; - d.bottom = h; - } - if (d.left < 0) { - s.left += (0 - d.left) * sw / dw; - d.left = 0; - } - if (d.top < 0) { - s.top += (0 - d.top) * sh / dh; - d.top = 0; - } - return true; -} - -HRESULT CBaseAP::InitResizers(float bicubicA, bool bNeedScreenSizeTexture) -{ - HRESULT hr; - do { - if (bicubicA) { - if (!m_pResizerPixelShader[0]) { - break; - } - if (!m_pResizerPixelShader[1]) { - break; - } - if (!m_pResizerPixelShader[2]) { - break; - } - if (!m_pResizerPixelShader[3]) { - break; - } - if (m_bicubicA != bicubicA) { - break; - } - if (!m_pScreenSizeTemporaryTexture[0]) { - break; - } - if (bNeedScreenSizeTexture) { - if (!m_pScreenSizeTemporaryTexture[1]) { - break; - } - } - } else { - if (!m_pResizerPixelShader[0]) { - break; - } - if (bNeedScreenSizeTexture) { - if (!m_pScreenSizeTemporaryTexture[0]) { - break; - } - if (!m_pScreenSizeTemporaryTexture[1]) { - break; - } - } - } - return S_OK; - } while (0); - - m_bicubicA = bicubicA; - m_pScreenSizeTemporaryTexture[0] = nullptr; - m_pScreenSizeTemporaryTexture[1] = nullptr; - - for (int i = 0; i < _countof(m_pResizerPixelShader); i++) { - m_pResizerPixelShader[i] = nullptr; - } - - if (m_caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { - return E_FAIL; - } - - LPCSTR pProfile = m_caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; - - CStringA str; - if (!LoadResource(IDF_SHADER_RESIZER, str, _T("SHADER"))) { - return E_FAIL; - } - - CStringA A; - A.Format("(%f)", bicubicA); - str.Replace("_The_Value_Of_A_Is_Set_Here_", A); - - LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass_pass1", "main_bicubic2pass_pass2"}; - - ASSERT(_countof(pEntries) == _countof(m_pResizerPixelShader)); - for (int i = 0; i < _countof(pEntries); i++) { - CString ErrorMessage; - CString DissAssembly; - hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShader[i], &DissAssembly, &ErrorMessage); - if (FAILED(hr)) { - TRACE(_T("%ws"), ErrorMessage.GetString()); - ASSERT(0); - return hr; - } - } - if (m_bicubicA || bNeedScreenSizeTexture) { - if (FAILED(m_pD3DDev->CreateTexture( - std::min((DWORD)m_ScreenSize.cx, m_caps.MaxTextureWidth), - std::min((DWORD)std::max(m_ScreenSize.cy, m_nativeVideoSize.cy), m_caps.MaxTextureHeight), - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - &m_pScreenSizeTemporaryTexture[0], - nullptr))) { - ASSERT(0); - m_pScreenSizeTemporaryTexture[0] = nullptr; // will do 1 pass then - } - - if (FAILED(m_pD3DDev->CreateTexture( - std::min((DWORD)m_ScreenSize.cx, m_caps.MaxTextureWidth), - std::min((DWORD)std::max(m_ScreenSize.cy, m_nativeVideoSize.cy), m_caps.MaxTextureHeight), - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - &m_pScreenSizeTemporaryTexture[1], - nullptr))) { - ASSERT(0); - m_pScreenSizeTemporaryTexture[1] = nullptr; // will do 1 pass then - } - } - return S_OK; -} - -HRESULT CBaseAP::TextureCopy(IDirect3DTexture9* pTexture) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - MYD3DVERTEX<1> v[] = { - {0, 0, 0.5f, 2.0f, 0, 0}, - {w, 0, 0.5f, 2.0f, 1, 0}, - {0, h, 0.5f, 2.0f, 0, 1}, - {w, h, 0.5f, 2.0f, 1, 1}, - }; - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - hr = m_pD3DDev->SetTexture(0, pTexture); - return TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); -} - -HRESULT CBaseAP::DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect) -{ - DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color)); - MYD3DVERTEX<0> v[] = { - {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color}, - {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color}, - {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color}, - {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color}, - }; - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - return DrawRectBase(m_pD3DDev, v); -} - -HRESULT CBaseAP::TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& SrcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - float dx2 = 1.0f / w; - float dy2 = 1.0f / h; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, SrcRect.left * dx2, SrcRect.top * dy2}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, SrcRect.right * dx2, SrcRect.top * dy2}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, SrcRect.left * dx2, SrcRect.bottom * dy2}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, SrcRect.right * dx2, SrcRect.bottom * dy2}, - }; - AdjustQuad(v, 0, 0); - hr = m_pD3DDev->SetTexture(0, pTexture); - hr = m_pD3DDev->SetPixelShader(nullptr); - hr = TextureBlt(m_pD3DDev, v, filter); - return hr; -} - -HRESULT CBaseAP::TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - float tx0 = (float)SrcRect.left; - float tx1 = (float)SrcRect.right; - float ty0 = (float)SrcRect.top; - float ty1 = (float)SrcRect.bottom; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, - }; - AdjustQuad(v, 1.0, 1.0); - float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - hr = m_pD3DDev->SetTexture(0, pTexture); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[0]); - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - m_pD3DDev->SetPixelShader(nullptr); - return hr; -} - -HRESULT CBaseAP::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - float tx0 = (float)SrcRect.left; - float tx1 = (float)SrcRect.right; - float ty0 = (float)SrcRect.top; - float ty1 = (float)SrcRect.bottom; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, - }; - AdjustQuad(v, 1.0, 1.0); - hr = m_pD3DDev->SetTexture(0, pTexture); - float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[1]); - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - m_pD3DDev->SetPixelShader(nullptr); - return hr; -} - -HRESULT CBaseAP::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) -{ - // The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction. - return TextureResizeBicubic1pass(pTexture, dst, SrcRect); - - /*HRESULT hr; - - // rotated? - if (dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z - || dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x) - return TextureResizeBicubic1pass(pTexture, dst, SrcRect); - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) - return E_FAIL; - - float Tex0_Width = desc.Width; - float Tex0_Height = desc.Height; - - CSize SrcTextSize = CSize(desc.Width, desc.Height); - double w = (double)SrcRect.Width(); - double h = (double)SrcRect.Height(); - UNREFERENCED_PARAMETER(w); - - CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h); - - if (!m_pScreenSizeTemporaryTexture[0] || FAILED(m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc))) - return TextureResizeBicubic1pass(pTexture, dst, SrcRect); - - float Tex1_Width = desc.Width; - float Tex1_Height = desc.Height; - - float tx0 = SrcRect.left; - float tx1 = SrcRect.right; - float ty0 = SrcRect.top; - float ty1 = SrcRect.bottom; - - float tx0_2 = 0; - float tx1_2 = dst1.Width(); - float ty0_2 = 0; - float ty1_2 = h; - - if (dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height) - return TextureResizeBicubic1pass(pTexture, dst, SrcRect); - - MYD3DVERTEX<1> vx[] = - { - {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0}, - {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0}, - {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1}, - {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1}, - }; - AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug here, create vertical lines ! TODO : why ?????? - MYD3DVERTEX<1> vy[] = - { - {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2}, - {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2}, - {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2}, - {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2}, - }; - AdjustQuad(vy, 0.0, 1.0); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[2]); - { - float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - } - hr = m_pD3DDev->SetTexture(0, pTexture); - CComPtr pRTOld; - hr = m_pD3DDev->GetRenderTarget(0, &pRTOld); - CComPtr pRT; - hr = m_pScreenSizeTemporaryTexture[0]->GetSurfaceLevel(0, &pRT); - hr = m_pD3DDev->SetRenderTarget(0, pRT); - hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[3]); - { - float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - } - hr = m_pD3DDev->SetTexture(0, m_pScreenSizeTemporaryTexture[0]); - hr = m_pD3DDev->SetRenderTarget(0, pRTOld); - hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT); - m_pD3DDev->SetPixelShader(nullptr); - return hr;*/ -} - -HRESULT CBaseAP::AlphaBlt(RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture) -{ - if (!pSrc || !pDst) { - return E_POINTER; - } - - CRect src(*pSrc), dst(*pDst); - - HRESULT hr; - - do { - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { - break; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile - // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly - // initialized and thus the subtitles weren't shown. - struct { - float x, y, z, rhw; - float tu, tv; - } pVertices[] = { - {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, - {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, - {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, - {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, - }; - - for (size_t i = 0; i < _countof(pVertices); i++) { - pVertices[i].x -= 0.5f; - pVertices[i].y -= 0.5f; - } - - hr = m_pD3DDev->SetTexture(0, pTexture); - - // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE - // so we need to provide default values in case GetRenderState fails - DWORD abe, sb, db; - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { - abe = FALSE; - } - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { - sb = D3DBLEND_ONE; - } - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { - db = D3DBLEND_ZERO; - } - - hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... - hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst - - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - - hr = m_pD3DDev->SetPixelShader(nullptr); - - hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); - hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); - - m_pD3DDev->SetTexture(0, nullptr); - - m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); - m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); - m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); - - return S_OK; - } while (0); - return E_FAIL; -} - -// Update the array m_pllJitter with a new vsync period. Calculate min, max and stddev. -void CBaseAP::SyncStats(LONGLONG syncTime) -{ - if (m_llLastSyncTime == LONGLONG_ERROR) { - m_llLastSyncTime = syncTime; - } - - m_nNextJitter = (m_nNextJitter + 1) % NB_JITTER; - LONGLONG jitter = syncTime - m_llLastSyncTime; - m_pllJitter[m_nNextJitter] = jitter; - double syncDeviation = (m_pllJitter[m_nNextJitter] - m_fJitterMean) / 10000.0; - if (abs(syncDeviation) > (GetDisplayCycle() / 2)) { - m_uSyncGlitches++; - } - - LONGLONG llJitterSum = 0; - LONGLONG llJitterSumAvg = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG Jitter = m_pllJitter[i]; - llJitterSum += Jitter; - llJitterSumAvg += Jitter; - } - m_fJitterMean = double(llJitterSumAvg) / NB_JITTER; - double DeviationSum = 0; - - for (int i = 0; i < NB_JITTER; i++) { - double deviation = m_pllJitter[i] - m_fJitterMean; - DeviationSum += deviation * deviation; - LONGLONG deviationInt = std::llround(deviation); - m_MaxJitter = std::max(m_MaxJitter, deviationInt); - m_MinJitter = std::min(m_MinJitter, deviationInt); - } - - m_fJitterStdDev = sqrt(DeviationSum / NB_JITTER); - m_fAvrFps = 10000000.0 / (double(llJitterSum) / NB_JITTER); - m_llLastSyncTime = syncTime; -} - -// Collect the difference between periodEnd and periodStart in an array, calculate mean and stddev. -void CBaseAP::SyncOffsetStats(LONGLONG syncOffset) -{ - m_nNextSyncOffset = (m_nNextSyncOffset + 1) % NB_JITTER; - m_pllSyncOffset[m_nNextSyncOffset] = syncOffset; - - LONGLONG AvrageSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG Offset = m_pllSyncOffset[i]; - AvrageSum += Offset; - m_MaxSyncOffset = std::max(m_MaxSyncOffset, Offset); - m_MinSyncOffset = std::min(m_MinSyncOffset, Offset); - } - double MeanOffset = double(AvrageSum) / NB_JITTER; - double DeviationSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - double Deviation = double(m_pllSyncOffset[i]) - MeanOffset; - DeviationSum += Deviation * Deviation; - } - double StdDev = sqrt(DeviationSum / NB_JITTER); - - m_fSyncOffsetAvr = MeanOffset; - m_fSyncOffsetStdDev = StdDev; -} - -void CBaseAP::UpdateAlphaBitmap() -{ - m_VMR9AlphaBitmapData.Free(); - - if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0) { - HBITMAP hBitmap = (HBITMAP)GetCurrentObject(m_VMR9AlphaBitmap.hdc, OBJ_BITMAP); - if (!hBitmap) { - return; - } - DIBSECTION info; - ZeroMemory(&info, sizeof(DIBSECTION)); - if (!::GetObject(hBitmap, sizeof(DIBSECTION), &info)) { - return; - } - - m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight); - m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes; - - if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight)) { - memcpy((BYTE*)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight); - } - } -} - -// Present a sample (frame) using DirectX. -STDMETHODIMP_(bool) CBaseAP::Paint(bool bAll) -{ - if (m_bPendingResetDevice) { - SendResetRequest(); - return false; - } - - const CRenderersSettings& r = GetRenderersSettings(); - CRenderersData* rd = GetRenderersData(); - D3DRASTER_STATUS rasterStatus; - REFERENCE_TIME llCurRefTime = 0; - REFERENCE_TIME llSyncOffset = 0; - double dSyncOffset = 0.0; - - CAutoLock cRenderLock(&m_allocatorLock); - - // Estimate time for next vblank based on number of remaining lines in this frame. This algorithm seems to be - // accurate within one ms why there should not be any need for a more accurate one. The wiggly line seen - // when using sync to nearest and sync display is most likely due to inaccuracies in the audio-card-based - // reference clock. The wiggles are not seen with the perfcounter-based reference clock of the sync to video option. - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - m_uScanLineEnteringPaint = rasterStatus.ScanLine; - if (m_pRefClock) { - m_pRefClock->GetTime(&llCurRefTime); - } - int dScanLines = std::max(int(m_ScreenSize.cy - m_uScanLineEnteringPaint), 0); - dSyncOffset = dScanLines * m_dDetectedScanlineTime; // ms - llSyncOffset = REFERENCE_TIME(10000.0 * dSyncOffset); // Reference time units (100 ns) - m_llEstVBlankTime = llCurRefTime + llSyncOffset; // Estimated time for the start of next vblank - - if (m_windowRect.right <= m_windowRect.left || m_windowRect.bottom <= m_windowRect.top - || m_nativeVideoSize.cx <= 0 || m_nativeVideoSize.cy <= 0 - || !m_pVideoSurface[m_nCurSurface]) { - return false; - } - - HRESULT hr; - CRect rSrcVid(CPoint(0, 0), m_nativeVideoSize); - CRect rDstVid(m_videoRect); - CRect rSrcPri(CPoint(0, 0), m_windowRect.Size()); - CRect rDstPri(rSrcPri); - - m_pD3DDev->BeginScene(); - CComPtr pBackBuffer; - m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); - m_pD3DDev->SetRenderTarget(0, pBackBuffer); - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); - if (!rDstVid.IsRectEmpty()) { - if (m_pVideoTexture[m_nCurSurface]) { - CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; - - if (m_pVideoTexture[m_nDXSurface] && m_pVideoTexture[m_nDXSurface + 1] && !m_pPixelShaders.IsEmpty()) { - static __int64 counter = 0; - static long start = clock(); - - long stop = clock(); - long diff = stop - start; - - if (diff >= 10 * 60 * CLOCKS_PER_SEC) { - start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) - } - - int src = m_nCurSurface, dst = m_nDXSurface; - - D3DSURFACE_DESC desc; - m_pVideoTexture[src]->GetLevelDesc(0, &desc); - - float fConstData[][4] = { - {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, - }; - - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - CComPtr pRT; - hr = m_pD3DDev->GetRenderTarget(0, &pRT); - - POSITION pos = m_pPixelShaders.GetHeadPosition(); - while (pos) { - pVideoTexture = m_pVideoTexture[dst]; - - hr = m_pD3DDev->SetRenderTarget(0, m_pVideoSurface[dst]); - CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); - if (!Shader.m_pPixelShader) { - Shader.Compile(m_pPSC); - } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); - TextureCopy(m_pVideoTexture[src]); - - src = dst; - if (++dst >= m_nDXSurface + 2) { - dst = m_nDXSurface; - } - } - - hr = m_pD3DDev->SetRenderTarget(0, pRT); - hr = m_pD3DDev->SetPixelShader(nullptr); - } - - Vector dst[4]; - Transform(rDstVid, dst); - - DWORD iDX9Resizer = r.iDX9Resizer; - - float A = 0; - - switch (iDX9Resizer) { - case 3: - A = -0.60f; - break; - case 4: - A = -0.751f; - break; // FIXME : 0.75 crash recent D3D, or eat CPU - case 5: - A = -1.00f; - break; - } - bool bScreenSpacePixelShaders = !m_pPixelShadersScreenSpace.IsEmpty(); - - hr = InitResizers(A, bScreenSpacePixelShaders); - - if (!m_pScreenSizeTemporaryTexture[0] || !m_pScreenSizeTemporaryTexture[1]) { - bScreenSpacePixelShaders = false; - } - - if (bScreenSpacePixelShaders) { - CComPtr pRT; - hr = m_pScreenSizeTemporaryTexture[1]->GetSurfaceLevel(0, &pRT); - if (hr != S_OK) { - bScreenSpacePixelShaders = false; - } - if (bScreenSpacePixelShaders) { - hr = m_pD3DDev->SetRenderTarget(0, pRT); - if (hr != S_OK) { - bScreenSpacePixelShaders = false; - } - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); - } - } - - if (rSrcVid.Size() != rDstVid.Size()) { - if (iDX9Resizer == 0 || iDX9Resizer == 1) { - D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; - hr = TextureResize(pVideoTexture, dst, Filter, rSrcVid); - } else if (iDX9Resizer == 2) { - hr = TextureResizeBilinear(pVideoTexture, dst, rSrcVid); - } else if (iDX9Resizer >= 3) { - hr = TextureResizeBicubic2pass(pVideoTexture, dst, rSrcVid); - } - } else { - hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, rSrcVid); - } - - if (bScreenSpacePixelShaders) { - static __int64 counter = 555; - static long start = clock() + 333; - - long stop = clock() + 333; - long diff = stop - start; - - if (diff >= 10 * 60 * CLOCKS_PER_SEC) { - start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) - } - - D3DSURFACE_DESC desc; - m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc); - - float fConstData[][4] = { - {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, - }; - - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - int srcTexture = 1, dstTexture = 0; - - POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); - while (pos) { - if (m_pPixelShadersScreenSpace.GetTailPosition() == pos) { - m_pD3DDev->SetRenderTarget(0, pBackBuffer); - } else { - CComPtr pRT; - hr = m_pScreenSizeTemporaryTexture[dstTexture]->GetSurfaceLevel(0, &pRT); - m_pD3DDev->SetRenderTarget(0, pRT); - } - - CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); - if (!Shader.m_pPixelShader) { - Shader.Compile(m_pPSC); - } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); - TextureCopy(m_pScreenSizeTemporaryTexture[srcTexture]); - - std::swap(srcTexture, dstTexture); - } - - hr = m_pD3DDev->SetPixelShader(nullptr); - } - } else { - if (pBackBuffer) { - ClipToSurface(pBackBuffer, rSrcVid, rDstVid); - // rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect - rSrcVid.left &= ~1; - rSrcVid.right &= ~1; - rSrcVid.top &= ~1; - rSrcVid.bottom &= ~1; - hr = m_pD3DDev->StretchRect(m_pVideoSurface[m_nCurSurface], rSrcVid, pBackBuffer, rDstVid, m_filter); - if (FAILED(hr)) { - return false; - } - } - } - } - - AlphaBltSubPic(rDstPri, rDstVid); - - if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE) { - CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock); - CRect rcSrc(m_VMR9AlphaBitmap.rSrc); - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE*)m_VMR9AlphaBitmapData) { - if ((m_pD3DXLoadSurfaceFromMemory != nullptr) && - SUCCEEDED(hr = m_pD3DDev->CreateTexture( - rcSrc.Width(), - rcSrc.Height(), - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - &m_pOSDTexture, - nullptr))) { - if (SUCCEEDED(hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface))) { - hr = m_pD3DXLoadSurfaceFromMemory(m_pOSDSurface, nullptr, nullptr, (BYTE*)m_VMR9AlphaBitmapData, D3DFMT_A8R8G8B8, m_VMR9AlphaBitmapWidthBytes, - nullptr, &m_VMR9AlphaBitmapRect, D3DX_FILTER_NONE, m_VMR9AlphaBitmap.clrSrcKey); - } - if (FAILED(hr)) { - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - } - } - } - m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE; - } - if (rd->m_iDisplayStats) { - DrawStats(); - } - if (m_pOSDTexture) { - AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture); - } - m_pD3DDev->EndScene(); - - CRect presentationSrcRect(rDstPri), presentationDestRect(m_windowRect); - // PresentEx() / Present() performs the clipping - // TODO: fix the race and uncomment the assert - //ASSERT(presentationSrcRect.Size() == presentationDestRect.Size()); - if (m_pD3DDevEx) { - if (m_bIsFullscreen) { - hr = m_pD3DDevEx->PresentEx(nullptr, nullptr, nullptr, nullptr, 0); - } else { - hr = m_pD3DDevEx->PresentEx(presentationSrcRect, presentationDestRect, nullptr, nullptr, 0); - } - } else { - if (m_bIsFullscreen) { - hr = m_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr); - } else { - hr = m_pD3DDev->Present(presentationSrcRect, presentationDestRect, nullptr, nullptr); - } - } - if (FAILED(hr)) { - TRACE(_T("Device lost or something\n")); - } - // Calculate timing statistics - if (m_pRefClock) { - m_pRefClock->GetTime(&llCurRefTime); // To check if we called Present too late to hit the right vsync - } - m_llEstVBlankTime = std::max(m_llEstVBlankTime, llCurRefTime); // Sometimes the real value is larger than the estimated value (but never smaller) - if (rd->m_iDisplayStats < 3) { // Partial on-screen statistics - SyncStats(m_llEstVBlankTime); // Max of estimate and real. Sometimes Present may actually return immediately so we need the estimate as a lower bound - } - if (rd->m_iDisplayStats == 1) { // Full on-screen statistics - SyncOffsetStats(-llSyncOffset); // Minus because we want time to flow downward in the graph in DrawStats - } - - // Adjust sync - double frameCycle = (m_llSampleTime - m_llLastSampleTime) / 10000.0; - if (frameCycle < 0) { - frameCycle = 0.0; // Happens when searching. - } - - if (r.m_AdvRendSets.bSynchronizeVideo) { - m_pGenlock->ControlClock(dSyncOffset, frameCycle); - } else if (r.m_AdvRendSets.bSynchronizeDisplay) { - m_pGenlock->ControlDisplay(dSyncOffset, frameCycle); - } else { - m_pGenlock->UpdateStats(dSyncOffset, frameCycle); // No sync or sync to nearest neighbor - } - - m_dFrameCycle = m_pGenlock->frameCycleAvg; - m_dCycleDifference = GetCycleDifference(); - if (abs(m_dCycleDifference) < 0.05) { // If less than 5% speed difference - m_bSnapToVSync = true; - } else { - m_bSnapToVSync = false; - } - - // Check how well audio is matching rate (if at all) - DWORD tmp; - if (m_pAudioStats != nullptr) { - m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_ACCUMERROR, &m_lAudioLag, &tmp); - m_lAudioLagMin = std::min((long)m_lAudioLag, m_lAudioLagMin); - m_lAudioLagMax = std::max((long)m_lAudioLag, m_lAudioLagMax); - m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_MODE, &m_lAudioSlaveMode, &tmp); - } - - if (rd->m_bResetStats) { - ResetStats(); - rd->m_bResetStats = false; - } - - bool fResetDevice = m_bPendingResetDevice; - if (hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET || hr == S_PRESENT_MODE_CHANGED) { - fResetDevice = true; - } - if (SettingsNeedResetDevice()) { - fResetDevice = true; - } - - BOOL bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - if ((bCompositionEnabled != 0) != m_bCompositionEnabled) { - if (m_bIsFullscreen) { - m_bCompositionEnabled = (bCompositionEnabled != 0); - } else { - fResetDevice = true; - } - } - - if (r.fResetDevice) { - LONGLONG time = rd->GetPerfCounter(); - if (time > m_LastAdapterCheck + 20000000) { // check every 2 sec. - m_LastAdapterCheck = time; -#ifdef _DEBUG - D3DDEVICE_CREATION_PARAMETERS Parameters; - if (SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))) { - ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter); - } -#endif - if (m_CurrentAdapter != GetAdapter(m_pD3D, m_hWnd)) { - fResetDevice = true; - } -#ifdef _DEBUG - else { - ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D, m_hWnd))); - } -#endif - } - } - - if (fResetDevice) { - m_bPendingResetDevice = true; - SendResetRequest(); - } - return true; -} - -void CBaseAP::SendResetRequest() -{ - if (!m_bDeviceResetRequested) { - m_bDeviceResetRequested = true; - AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE); - } -} - -STDMETHODIMP_(bool) CBaseAP::ResetDevice() -{ - DeleteSurfaces(); - HRESULT hr; - CString Error; - if (FAILED(hr = CreateDXDevice(Error)) || FAILED(hr = AllocSurfaces())) { - m_bDeviceResetRequested = false; - return false; - } - m_pGenlock->SetMonitor(GetAdapter(m_pD3D, m_hWnd)); - m_pGenlock->GetTiming(); - OnResetDevice(); - m_bDeviceResetRequested = false; - m_bPendingResetDevice = false; - return true; -} - -STDMETHODIMP_(bool) CBaseAP::DisplayChange() -{ - m_bPendingResetDevice = true; - SendResetRequest(); - return true; -} - -void CBaseAP::InitStats() -{ - ASSERT(m_pD3DDev); - static LONG currentHeight = 0; - int newHeight = lround(FONT_HEIGHT * (double(m_windowRect.Width()) / REFERENCE_WIDTH)); - - if (m_pD3DXCreateFont && (!m_pFont || currentHeight != newHeight)) { - m_pFont = nullptr; - if (newHeight <= 0) { - ASSERT(FALSE); - } - m_pD3DXCreateFont(m_pD3DDev, newHeight, 0, newHeight < BOLD_THRESHOLD ? FW_NORMAL : FW_BOLD, - 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, - FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont); - currentHeight = newHeight; - } - - if (m_pD3DXCreateSprite && !m_pSprite) { - m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite); - } - - if (m_pD3DXCreateLine && !m_pLine) { - m_pD3DXCreateLine(m_pD3DDev, &m_pLine); - } -} - -void CBaseAP::DrawStats() -{ - const CRenderersData* rd = GetRenderersData(); - - InitStats(); - const float textScale = float(m_windowRect.Width()) / REFERENCE_WIDTH; - const int lineHeight = lround((FONT_HEIGHT + TEXT_PADDING) * textScale); - - // pApp->m_iDisplayStats = 1 for full stats, 2 for little less, 3 for basic, 0 for no stats - if (m_pFont && m_pSprite) { - auto drawText = [&](CRect & rc, const CString & strText) { - D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f); - D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f); - - RECT shadowRect = rc; - OffsetRect(&shadowRect, 2, 2); - - // Draw shadow - m_pFont->DrawText(m_pSprite, strText, -1, &shadowRect, DT_NOCLIP, Color0); - // Draw text - m_pFont->DrawText(m_pSprite, strText, -1, rc, DT_NOCLIP, Color1); - rc.OffsetRect(0, lineHeight); - }; - - const CRenderersSettings& r = GetRenderersSettings(); - LONGLONG llMaxJitter = m_MaxJitter; - LONGLONG llMinJitter = m_MinJitter; - CRect rc(lineHeight, lineHeight, 0, 0); - - m_pSprite->Begin(D3DXSPRITE_ALPHABLEND); - CString strText; - - strText.Format(_T("Frames drawn from stream start: %u | Sample time stamp: %ld ms"), - m_pcFramesDrawn, (LONG)(m_llSampleTime / 10000)); - drawText(rc, strText); - - if (rd->m_iDisplayStats == 1) { - strText.Format(_T("Frame cycle : %.3f ms [%.3f ms, %.3f ms] Actual %+5.3f ms [%+.3f ms, %+.3f ms]"), - m_dFrameCycle, m_pGenlock->minFrameCycle, m_pGenlock->maxFrameCycle, - m_fJitterMean / 10000.0, (double(llMinJitter) / 10000.0), - (double(llMaxJitter) / 10000.0)); - drawText(rc, strText); - - strText.Format(_T("Display cycle: Measured closest match %.3f ms Measured base %.3f ms"), - m_dOptimumDisplayCycle, m_dEstRefreshCycle); - drawText(rc, strText); - - strText.Format(_T("Frame rate : %.3f fps Actual frame rate: %.3f fps"), - 1000.0 / m_dFrameCycle, 10000000.0 / m_fJitterMean); - drawText(rc, strText); - - strText.Format(_T("Windows : Display cycle %.3f ms Display refresh rate %u Hz"), - m_dD3DRefreshCycle, m_refreshRate); - drawText(rc, strText); - - if (m_pGenlock->powerstripTimingExists) { - strText.Format(_T("Powerstrip : Display cycle %.3f ms Display refresh rate %.3f Hz"), - 1000.0 / m_pGenlock->curDisplayFreq, m_pGenlock->curDisplayFreq); - drawText(rc, strText); - } - - if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0) { - strText = _T("Scan line err: Graphics device does not support scan line access. No sync is possible"); - drawText(rc, strText); - } - -#ifdef _DEBUG - if (m_pD3DDevEx) { - CComPtr pSC; - HRESULT hr = m_pD3DDevEx->GetSwapChain(0, &pSC); - CComQIPtr pSCEx = pSC; - if (pSCEx) { - D3DPRESENTSTATS stats; - hr = pSCEx->GetPresentStats(&stats); - if (SUCCEEDED(hr)) { - strText = _T("Graphics device present stats:"); - drawText(rc, strText); - - strText.Format(_T(" PresentCount %u PresentRefreshCount %u SyncRefreshCount %u"), - stats.PresentCount, stats.PresentRefreshCount, stats.SyncRefreshCount); - drawText(rc, strText); - - LARGE_INTEGER Freq; - QueryPerformanceFrequency(&Freq); - Freq.QuadPart /= 1000; - strText.Format(_T(" SyncQPCTime %dms SyncGPUTime %dms"), - stats.SyncQPCTime.QuadPart / Freq.QuadPart, - stats.SyncGPUTime.QuadPart / Freq.QuadPart); - drawText(rc, strText); - } else { - strText = L"Graphics device does not support present stats"; - drawText(rc, strText); - } - } - } -#endif - - strText.Format(_T("Video size : %ld x %ld (AR = %ld : %ld) Display resolution %ld x %ld "), - m_nativeVideoSize.cx, m_nativeVideoSize.cy, m_aspectRatio.cx, m_aspectRatio.cy, - m_ScreenSize.cx, m_ScreenSize.cy); - drawText(rc, strText); - - if (r.m_AdvRendSets.bSynchronizeDisplay || r.m_AdvRendSets.bSynchronizeVideo) { - if (r.m_AdvRendSets.bSynchronizeDisplay && !m_pGenlock->PowerstripRunning()) { - strText = _T("Sync error : PowerStrip is not running. No display sync is possible."); - drawText(rc, strText); - } else { - strText.Format(_T("Sync adjust : %d | # of adjustments: %u"), - m_pGenlock->adjDelta, - (m_pGenlock->clockAdjustmentsMade + m_pGenlock->displayAdjustmentsMade) / 2); - drawText(rc, strText); - } - } - } - - strText.Format(_T("Sync offset : Average %3.1f ms [%.1f ms, %.1f ms] Target %3.1f ms"), - m_pGenlock->syncOffsetAvg, m_pGenlock->minSyncOffset, - m_pGenlock->maxSyncOffset, r.m_AdvRendSets.fTargetSyncOffset); - drawText(rc, strText); - - strText.Format(_T("Sync status : glitches %u, display-frame cycle mismatch: %7.3f %%, dropped frames %u"), - m_uSyncGlitches, 100 * m_dCycleDifference, m_pcFramesDropped); - drawText(rc, strText); - - if (rd->m_iDisplayStats == 1) { - if (m_pAudioStats && r.m_AdvRendSets.bSynchronizeVideo) { - strText.Format(_T("Audio lag : %3lu ms [%ld ms, %ld ms] | %s"), - m_lAudioLag, m_lAudioLagMin, m_lAudioLagMax, - (m_lAudioSlaveMode == 4) ? - _T("Audio renderer is matching rate (for analog sound output)") : - _T("Audio renderer is not matching rate")); - drawText(rc, strText); - } - - strText.Format(_T("Sample time : waiting %3ld ms"), m_lNextSampleWait); - if (r.m_AdvRendSets.bSynchronizeNearest) { - CString temp; - temp.Format(_T(" paint time correction: %3ld ms Hysteresis: %I64d"), - m_lShiftToNearest, m_llHysteresis / 10000); - strText += temp; - } - drawText(rc, strText); - - strText.Format(_T("Buffering : Buffered %3ld Free %3ld Current Surface %3d"), - m_nUsedBuffer, m_nDXSurface - m_nUsedBuffer, m_nCurSurface); - drawText(rc, strText); - - strText = _T("Settings : "); - - if (m_bIsFullscreen) { - strText += _T("D3DFS "); - } - if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { - strText += _T("DisDC "); - } - if (r.m_AdvRendSets.bSynchronizeVideo) { - strText += _T("SyncVideo "); - } - if (r.m_AdvRendSets.bSynchronizeDisplay) { - strText += _T("SyncDisplay "); - } - if (r.m_AdvRendSets.bSynchronizeNearest) { - strText += _T("SyncNearest "); - } - if (m_bHighColorResolution) { - strText += _T("10 bit "); - } - if (r.m_AdvRendSets.iEVROutputRange == 0) { - strText += _T("0-255 "); - } else if (r.m_AdvRendSets.iEVROutputRange == 1) { - strText += _T("16-235 "); - } - - drawText(rc, strText); - drawText(rc, rd->m_strDXVAInfo); - - strText.Format(L"DirectX SDK : %u", rd->GetDXSdkRelease()); - drawText(rc, strText); - - for (int i = 0; i < 6; i++) { - if (m_strStatsMsg[i][0]) { - drawText(rc, m_strStatsMsg[i]); - } - } - } - m_pSprite->End(); - } - - if (m_pLine && (rd->m_iDisplayStats < 3)) { - D3DXVECTOR2 points[NB_JITTER]; - const float graphWidth = GRAPH_WIDTH * textScale; - const float graphHeight = GRAPH_HEIGHT * textScale; - const float topLeftX = m_windowRect.Width() - (graphWidth + lineHeight); - const float topLeftY = m_windowRect.Height() - (graphHeight + lineHeight); - const float gridStepY = graphHeight / 24.0f; - const float gridStepX = graphWidth / NB_JITTER; - - // Draw background - DrawRect(RGB(0, 0, 0), 80, CRect(int(topLeftX), - int(topLeftY), - int(topLeftX + graphWidth), - int(topLeftY + graphHeight))); - - m_pLine->SetWidth(2.5f * textScale); - m_pLine->SetAntialias(TRUE); - m_pLine->Begin(); - - // Draw grid lines - for (int i = 1; i < 24; ++i) { - points[0].x = topLeftX; - points[0].y = topLeftY + i * gridStepY; - points[1].y = points[0].y; - - float lineLength; - D3DCOLOR color; - if (i % 12 == 0) { - lineLength = 1.0f; - color = D3DCOLOR_XRGB(100, 100, 255); - } else if (i % 4 == 0) { - lineLength = 0.96f; - color = D3DCOLOR_XRGB(100, 100, 180); - } else { - lineLength = 0.04f; - color = D3DCOLOR_XRGB(100, 100, 140); - } - points[1].x = topLeftX + graphWidth * lineLength; - m_pLine->Draw(points, 2, color); - } - - // Draw jitter - for (int i = 1; i <= NB_JITTER; ++i) { - int nIndex = (m_nNextJitter + i) % NB_JITTER; - if (nIndex < 0) { - nIndex += NB_JITTER; - ASSERT(FALSE); - } - float jitter = float(m_pllJitter[nIndex] - m_fJitterMean); - points[i - 1].x = topLeftX + i * gridStepX; - points[i - 1].y = topLeftY + (jitter * textScale / 2000.0f + graphHeight / 2.0f); - } - m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100)); - - if (rd->m_iDisplayStats == 1) { // Full on-screen statistics - // Draw sync offset - for (int i = 1; i <= NB_JITTER; ++i) { - int nIndex = (m_nNextSyncOffset + i) % NB_JITTER; - if (nIndex < 0) { - nIndex += NB_JITTER; - } - points[i - 1].x = topLeftX + i * gridStepX; - points[i - 1].y = topLeftY + (m_pllSyncOffset[nIndex] * textScale / 2000.0f + graphHeight / 2.0f); - } - m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100)); - } - m_pLine->End(); - } -} - -double CBaseAP::GetRefreshRate() -{ - if (m_pGenlock->powerstripTimingExists) { - return m_pGenlock->curDisplayFreq; - } else { - return (double)m_refreshRate; - } -} - -double CBaseAP::GetDisplayCycle() -{ - if (m_pGenlock->powerstripTimingExists) { - return 1000.0 / m_pGenlock->curDisplayFreq; - } else { - return (double)m_dD3DRefreshCycle; - } -} - -double CBaseAP::GetCycleDifference() -{ - double dBaseDisplayCycle = GetDisplayCycle(); - double minDiff = 1.0; - if (dBaseDisplayCycle == 0.0 || m_dFrameCycle == 0.0) { - return 1.0; - } else { - for (UINT i = 1; i <= 8; i++) { // Try a lot of multiples of the display frequency - double dDisplayCycle = i * dBaseDisplayCycle; - double diff = (dDisplayCycle - m_dFrameCycle) / m_dFrameCycle; - if (abs(diff) < abs(minDiff)) { - minDiff = diff; - m_dOptimumDisplayCycle = dDisplayCycle; - } - } - } - return minDiff; -} - -void CBaseAP::EstimateRefreshTimings() -{ - if (m_pD3DDev) { - const CRenderersData* rd = GetRenderersData(); - D3DRASTER_STATUS rasterStatus; - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - while (rasterStatus.ScanLine != 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - while (rasterStatus.ScanLine == 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - LONGLONG startTime = rd->GetPerfCounter(); - UINT startLine = rasterStatus.ScanLine; - LONGLONG endTime = 0; - UINT endLine = 0; - bool done = false; - while (!done) { // Estimate time for one scan line - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - UINT line = rasterStatus.ScanLine; - LONGLONG time = rd->GetPerfCounter(); - if (line > 0) { - endLine = line; - endTime = time; - } else { - done = true; - } - } - m_dDetectedScanlineTime = (endTime - startTime) / ((endLine - startLine) * 10000.0); - - // Estimate the display refresh rate from the vsyncs - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - while (rasterStatus.ScanLine != 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - // Now we're at the start of a vsync - startTime = rd->GetPerfCounter(); - UINT i; - for (i = 1; i <= 50; i++) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - while (rasterStatus.ScanLine == 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - while (rasterStatus.ScanLine != 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - // Now we're at the next vsync - } - endTime = rd->GetPerfCounter(); - m_dEstRefreshCycle = (endTime - startTime) / ((i - 1) * 10000.0); - } -} - -bool CBaseAP::ExtractInterlaced(const AM_MEDIA_TYPE* pmt) -{ - if (pmt->formattype == FORMAT_VideoInfo) { - return false; - } else if (pmt->formattype == FORMAT_VideoInfo2) { - return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; - } else if (pmt->formattype == FORMAT_MPEGVideo) { - return false; - } else if (pmt->formattype == FORMAT_MPEG2Video) { - return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; - } else { - return false; - } -} - -HRESULT CBaseAP::Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect) { - HRESULT hr = E_FAIL; - - const CRenderersSettings& r = GetRenderersSettings(); - - DWORD iDX9Resizer = r.iDX9Resizer; - Vector dst[4]; - Transform(destRect, dst); - - if (iDX9Resizer == 0 || iDX9Resizer == 1) { - D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; - hr = TextureResize(pTexture, dst, Filter, srcRect); - } else if (iDX9Resizer == 2) { - hr = TextureResizeBilinear(pTexture, dst, srcRect); - } else if (iDX9Resizer >= 3) { - hr = TextureResizeBicubic1pass(pTexture, dst, srcRect); - } - - return hr; -} - -STDMETHODIMP CBaseAP::GetDIB(BYTE* lpDib, DWORD* size) -{ - CheckPointer(size, E_POINTER); - - // Keep a reference so that we can safely work on the surface - // without having to lock everything - CComPtr pVideoSurface; - { - CAutoLock cAutoLock(this); - CheckPointer(m_pVideoSurface[m_nCurSurface], E_FAIL); - pVideoSurface = m_pVideoSurface[m_nCurSurface]; - } - - HRESULT hr; - - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(hr = pVideoSurface->GetDesc(&desc))) { - return hr; - } - - CSize framesize = GetVideoSize(false); - const CSize dar = GetVideoSize(true); - - bool resize = false; - if (dar.cx > 0 && dar.cy > 0 && (dar.cx != desc.Width || dar.cy != desc.Height)) { - framesize.cx = MulDiv(framesize.cy, dar.cx, dar.cy); - resize = true; - desc.Width = framesize.cx; - desc.Height = framesize.cy; - } - - DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3); - if (!lpDib) { - *size = required; - return S_OK; - } - if (*size < required) { - return E_OUTOFMEMORY; - } - *size = required; - - CComPtr pSurface, tSurface; - // Convert to 8-bit when using 10-bit or full/half processing modes - if (desc.Format != D3DFMT_X8R8G8B8) { - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tSurface, nullptr)) - || FAILED(hr = m_pD3DXLoadSurfaceFromSurface(tSurface, nullptr, nullptr, pVideoSurface, nullptr, nullptr, D3DX_DEFAULT, 0))) { - return hr; - } - } else { - tSurface = pVideoSurface; - } - - if (resize) { - CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; - if (FAILED(hr = m_pD3DDevEx->CreateRenderTarget(framesize.cx, framesize.cy, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurface, nullptr)) - || FAILED(hr = m_pD3DDevEx->SetRenderTarget(0, pSurface)) - || FAILED(hr = Resize(pVideoTexture, { CPoint(0, 0), m_nativeVideoSize }, { CPoint(0, 0), framesize }))) { - return hr; - } - } else { - pSurface = tSurface; - } - - D3DLOCKED_RECT r; - if (FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { - // If this fails, we try to use a surface allocated from the system memory - CComPtr pInputSurface = pSurface; - pSurface = nullptr; - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, nullptr)) - || FAILED(hr = m_pD3DDev->GetRenderTargetData(pInputSurface, pSurface)) - || FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { - return hr; - } - } - - hr = CreateDIBFromSurfaceData(desc, r, lpDib); - - pSurface->UnlockRect(); - - return hr; -} - -STDMETHODIMP CBaseAP::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) -{ - return SetPixelShader2(pSrcData, pTarget, false); -} - -STDMETHODIMP CBaseAP::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) -{ - CAutoLock cRenderLock(&m_allocatorLock); - - CAtlList* pPixelShaders; - if (bScreenSpace) { - pPixelShaders = &m_pPixelShadersScreenSpace; - } else { - pPixelShaders = &m_pPixelShaders; - } - - if (!pSrcData && !pTarget) { - pPixelShaders->RemoveAll(); - m_pD3DDev->SetPixelShader(nullptr); - return S_OK; - } - - if (!pSrcData) { - return E_INVALIDARG; - } - - CExternalPixelShader Shader; - Shader.m_SourceData = pSrcData; - Shader.m_SourceTarget = pTarget; - - CComPtr pPixelShader; - - HRESULT hr = Shader.Compile(m_pPSC); - if (FAILED(hr)) { - return hr; - } - - pPixelShaders->AddTail(Shader); - Paint(true); - return S_OK; -} - -CSyncAP::CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) - : CBaseAP(hWnd, bFullscreen, hr, _Error) - , m_LastClockState(MFCLOCK_STATE_INVALID) - , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture) - , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0) - , m_BorderColor(RGB(0, 0, 0)) - , m_hEvtQuit(nullptr) - , m_bEvtQuit(0) - , m_hEvtFlush(nullptr) - , m_bEvtFlush(0) - , m_hEvtSkip(nullptr) - , m_bEvtSkip(false) - , m_bUseInternalTimer(false) - , m_LastSetOutputRange(-1) - , m_bPendingRenegotiate(false) - , m_bPendingMediaFinished(false) - , m_bPrerolled(false) - , m_hRenderThread(nullptr) - , m_hMixerThread(nullptr) - , m_nRenderState(Shutdown) - , m_bStepping(false) - , m_nCurrentGroupId(0) - , m_nResetToken(0) - , m_nStepCount(0) - , m_SampleFreeCallback(this, &CSyncAP::OnSampleFree) - , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9") - , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer") - , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface") - , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType") - , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW") - , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority") - , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics") -{ - const CRenderersSettings& r = GetRenderersSettings(); - - if (FAILED(hr)) { - _Error += L"SyncAP failed\n"; - return; - } - - if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) { - if (!fnDXVA2CreateDirect3DDeviceManager9) { - _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n"; - } - if (!fnMFCreateDXSurfaceBuffer) { - _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n"; - } - if (!fnMFCreateVideoSampleFromSurface) { - _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n"; - } - if (!fnMFCreateMediaType) { - _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n"; - } - hr = E_FAIL; - return; - } - - // Init DXVA manager - hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager); - if (SUCCEEDED(hr) && m_pD3DManager) { - hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); - if (FAILED(hr)) { - _Error += L"m_pD3DManager->ResetDevice failed\n"; - } - } else { - _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n"; - } - - // Bufferize frame only with 3D texture - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { - m_nDXSurface = std::max(std::min(r.iEvrBuffers, MAX_PICTURE_SLOTS - 2), 4); - } else { - m_nDXSurface = 1; - } - - m_pOuterEVR = nullptr; - m_lShiftToNearest = -1; // Illegal value to start with -} - -CSyncAP::~CSyncAP() -{ - StopWorkerThreads(); - m_pMediaType = nullptr; - m_pClock = nullptr; - m_pD3DManager = nullptr; - - if (m_bHookedNewSegment) { - UnhookNewSegment(); - } -} - -HRESULT CSyncAP::CheckShutdown() const -{ - if (m_nRenderState == Shutdown) { - return MF_E_SHUTDOWN; - } else { - return S_OK; - } -} - -void CSyncAP::StartWorkerThreads() -{ - DWORD dwThreadId; - if (m_nRenderState == Shutdown) { - m_hEvtQuit = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hEvtFlush = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hEvtSkip = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hMixerThread = ::CreateThread(nullptr, 0, MixerThreadStatic, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hMixerThread, THREAD_PRIORITY_HIGHEST); - m_hRenderThread = ::CreateThread(nullptr, 0, RenderThreadStatic, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hRenderThread, THREAD_PRIORITY_TIME_CRITICAL); - m_nRenderState = Stopped; - } -} - -void CSyncAP::StopWorkerThreads() -{ - if (m_nRenderState != Shutdown) { - SetEvent(m_hEvtFlush); - m_bEvtFlush = true; - SetEvent(m_hEvtQuit); - m_bEvtQuit = true; - SetEvent(m_hEvtSkip); - m_bEvtSkip = true; - - if (m_hRenderThread && WaitForSingleObject(m_hRenderThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hRenderThread, 0xDEAD); - } - - SAFE_CLOSE_HANDLE(m_hRenderThread); - - if (m_hMixerThread && WaitForSingleObject(m_hMixerThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hMixerThread, 0xDEAD); - } - - SAFE_CLOSE_HANDLE(m_hMixerThread); - SAFE_CLOSE_HANDLE(m_hEvtFlush); - SAFE_CLOSE_HANDLE(m_hEvtQuit); - SAFE_CLOSE_HANDLE(m_hEvtSkip); - - m_bEvtFlush = false; - m_bEvtQuit = false; - m_bEvtSkip = false; - } - m_nRenderState = Shutdown; -} - -STDMETHODIMP CSyncAP::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - *ppRenderer = nullptr; - HRESULT hr = E_FAIL; - - do { - CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; - - CSyncRenderer* pOuterEVR = DEBUG_NEW CSyncRenderer(NAME("CSyncRenderer"), pUnk, hr, &m_VMR9AlphaBitmap, this); - m_pOuterEVR = pOuterEVR; - - pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR); - CComQIPtr pBF = pUnk; - - if (FAILED(hr)) { - break; - } - - // Set EVR custom presenter - CComPtr pVP; - CComPtr pMFVR; - CComQIPtr pMFGS = pBF; - CComQIPtr pConfig = pBF; - if (SUCCEEDED(hr)) { - if (FAILED(pConfig->SetNumberOfStreams(3))) { // TODO - maybe need other number of input stream ... - break; - } - } - - hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVR)); - - if (SUCCEEDED(hr)) { - hr = QueryInterface(IID_PPV_ARGS(&pVP)); - } - if (SUCCEEDED(hr)) { - hr = pMFVR->InitializeRenderer(nullptr, pVP); - } - - if (SUCCEEDED(hr)) { - CComPtr pPin = GetFirstPin(pBF); - if (HookNewSegment((IPinC*)(IPin*)pPin)) { - m_bUseInternalTimer = true; - m_bHookedNewSegment = true; - } - *ppRenderer = pBF.Detach(); - } else { - *ppRenderer = nullptr; - } - } while (0); - - return hr; -} - -STDMETHODIMP_(bool) CSyncAP::Paint(bool bAll) -{ - return __super::Paint(bAll); -} - -STDMETHODIMP_(bool) CSyncAP::Paint(IMFSample* pMFSample) -{ - m_pCurrentlyDisplayedSample = pMFSample; - pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface); - - auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { - UINT32 nGroupId; - return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); - }; - ASSERT(sampleHasCurrentGroupId(pMFSample)); - - return Paint(true); -} - -STDMETHODIMP CSyncAP::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - HRESULT hr; - if (riid == __uuidof(IMFClockStateSink)) { - hr = GetInterface((IMFClockStateSink*)this, ppv); - } else if (riid == __uuidof(IMFVideoPresenter)) { - hr = GetInterface((IMFVideoPresenter*)this, ppv); - } else if (riid == __uuidof(IMFTopologyServiceLookupClient)) { - hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv); - } else if (riid == __uuidof(IMFVideoDeviceID)) { - hr = GetInterface((IMFVideoDeviceID*)this, ppv); - } else if (riid == __uuidof(IMFGetService)) { - hr = GetInterface((IMFGetService*)this, ppv); - } else if (riid == __uuidof(IMFAsyncCallback)) { - hr = GetInterface((IMFAsyncCallback*)this, ppv); - } else if (riid == __uuidof(IMFVideoDisplayControl)) { - hr = GetInterface((IMFVideoDisplayControl*)this, ppv); - } else if (riid == __uuidof(IEVRTrustedVideoPlugin)) { - hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv); - } else if (riid == IID_IQualProp) { - hr = GetInterface((IQualProp*)this, ppv); - } else if (riid == __uuidof(IMFRateSupport)) { - hr = GetInterface((IMFRateSupport*)this, ppv); - } else if (riid == __uuidof(IDirect3DDeviceManager9)) { - hr = m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppv); - } else if (riid == __uuidof(ISyncClockAdviser)) { - hr = GetInterface((ISyncClockAdviser*)this, ppv); - } else if (riid == __uuidof(ID3DFullscreenControl)) { - hr = GetInterface((ID3DFullscreenControl*)this, ppv); - } else { - hr = __super::NonDelegatingQueryInterface(riid, ppv); - } - - return hr; -} - -// IMFClockStateSink -STDMETHODIMP CSyncAP::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - m_nRenderState = Started; - return S_OK; -} - -STDMETHODIMP CSyncAP::OnClockStop(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - m_nRenderState = Stopped; - return S_OK; -} - -STDMETHODIMP CSyncAP::OnClockPause(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - m_nRenderState = Paused; - return S_OK; -} - -STDMETHODIMP CSyncAP::OnClockRestart(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - m_nRenderState = Started; - return S_OK; -} - -STDMETHODIMP CSyncAP::OnClockSetRate(MFTIME hnsSystemTime, float flRate) -{ - return E_NOTIMPL; -} - -// IBaseFilter delegate -bool CSyncAP::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue) -{ - CAutoLock lock(&m_SampleQueueLock); - switch (m_nRenderState) { - case Started: - *State = State_Running; - break; - case Paused: - *State = State_Paused; - break; - case Stopped: - *State = State_Stopped; - break; - default: - *State = State_Stopped; - _ReturnValue = E_FAIL; - } - _ReturnValue = S_OK; - return true; -} - -// IQualProp -STDMETHODIMP CSyncAP::get_FramesDroppedInRenderer(int* pcFrames) -{ - *pcFrames = m_pcFramesDropped; - return S_OK; -} - -STDMETHODIMP CSyncAP::get_FramesDrawn(int* pcFramesDrawn) -{ - *pcFramesDrawn = m_pcFramesDrawn; - return S_OK; -} - -STDMETHODIMP CSyncAP::get_AvgFrameRate(int* piAvgFrameRate) -{ - *piAvgFrameRate = (int)(m_fAvrFps * 100); - return S_OK; -} - -STDMETHODIMP CSyncAP::get_Jitter(int* iJitter) -{ - *iJitter = (int)((m_fJitterStdDev / 10000.0) + 0.5); - return S_OK; -} - -STDMETHODIMP CSyncAP::get_AvgSyncOffset(int* piAvg) -{ - *piAvg = (int)((m_fSyncOffsetAvr / 10000.0) + 0.5); - return S_OK; -} - -STDMETHODIMP CSyncAP::get_DevSyncOffset(int* piDev) -{ - *piDev = (int)((m_fSyncOffsetStdDev / 10000.0) + 0.5); - return S_OK; -} - -// IMFRateSupport -STDMETHODIMP CSyncAP::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) -{ - *pflRate = 0; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) -{ - HRESULT hr = S_OK; - float fMaxRate = 0.0f; - - CAutoLock lock(this); - - CheckPointer(pflRate, E_POINTER); - CHECK_HR(CheckShutdown()); - - // Get the maximum forward rate. - fMaxRate = GetMaxRate(fThin); - - // For reverse playback, swap the sign. - if (eDirection == MFRATE_REVERSE) { - fMaxRate = -fMaxRate; - } - - *pflRate = fMaxRate; - return hr; -} - -STDMETHODIMP CSyncAP::IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate) -{ - // fRate can be negative for reverse playback. - // pfNearestSupportedRate can be NULL. - CAutoLock lock(this); - HRESULT hr = S_OK; - float fMaxRate = 0.0f; - float fNearestRate = flRate; // Default. - - CheckPointer(pflNearestSupportedRate, E_POINTER); - CHECK_HR(CheckShutdown()); - - // Find the maximum forward rate. - fMaxRate = GetMaxRate(fThin); - - if (fabsf(flRate) > fMaxRate) { - // The (absolute) requested rate exceeds the maximum rate. - hr = MF_E_UNSUPPORTED_RATE; - - // The nearest supported rate is fMaxRate. - fNearestRate = fMaxRate; - if (flRate < 0) { - // For reverse playback, swap the sign. - fNearestRate = -fNearestRate; - } - } - // Return the nearest supported rate if the caller requested it. - if (pflNearestSupportedRate != nullptr) { - *pflNearestSupportedRate = fNearestRate; - } - return hr; -} - -float CSyncAP::GetMaxRate(BOOL bThin) -{ - float fMaxRate = FLT_MAX; // Default. - UINT32 fpsNumerator = 0, fpsDenominator = 0; - - if (!bThin && m_pMediaType) { - // Non-thinned: Use the frame rate and monitor refresh rate. - - // Frame rate: - MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE, - &fpsNumerator, &fpsDenominator); - - // Monitor refresh rate: - UINT MonitorRateHz = m_refreshRate; // D3DDISPLAYMODE - - if (fpsDenominator && fpsNumerator && MonitorRateHz) { - // Max Rate = Refresh Rate / Frame Rate - fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator); - } - } - return fMaxRate; -} - -void CSyncAP::CompleteFrameStep(bool bCancel) -{ - if (m_nStepCount > 0) { - if (bCancel || (m_nStepCount == 1)) { - m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0); - m_nStepCount = 0; - } else { - m_nStepCount--; - } - } -} - -// IMFVideoPresenter -STDMETHODIMP CSyncAP::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) -{ - HRESULT hr = S_OK; - CHECK_HR(CheckShutdown()); - - switch (eMessage) { - case MFVP_MESSAGE_BEGINSTREAMING: - hr = BeginStreaming(); - m_llHysteresis = 0; - m_lShiftToNearest = 0; - m_bStepping = false; - break; - - case MFVP_MESSAGE_CANCELSTEP: - m_bStepping = false; - CompleteFrameStep(true); - break; - - case MFVP_MESSAGE_ENDOFSTREAM: - m_bPendingMediaFinished = true; - break; - - case MFVP_MESSAGE_ENDSTREAMING: - m_pGenlock->ResetTiming(); - m_pRefClock = nullptr; - m_nRenderState = Stopped; - break; - - case MFVP_MESSAGE_FLUSH: - SetEvent(m_hEvtFlush); - m_bEvtFlush = true; - while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0) { - ; - } - break; - - case MFVP_MESSAGE_INVALIDATEMEDIATYPE: - m_bPendingRenegotiate = true; - while (m_bPendingRenegotiate) { - Sleep(1); - } - break; - - case MFVP_MESSAGE_PROCESSINPUTNOTIFY: - break; - - case MFVP_MESSAGE_STEP: - m_nStepCount = (int)ulParam; - m_bStepping = true; - break; - - default: - ASSERT(FALSE); - break; - } - return hr; -} - -HRESULT CSyncAP::IsMediaTypeSupported(IMFMediaType* pMixerType) -{ - HRESULT hr; - AM_MEDIA_TYPE* pAMMedia; - UINT nInterlaceMode; - - CHECK_HR(pMixerType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); - CHECK_HR(pMixerType->GetUINT32(MF_MT_INTERLACE_MODE, &nInterlaceMode)); - - if ((pAMMedia->majortype != MEDIATYPE_Video)) { - hr = MF_E_INVALIDMEDIATYPE; - } - pMixerType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); - return hr; -} - -HRESULT CSyncAP::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType) -{ - HRESULT hr; - IMFMediaType* pOptimalMediaType; - - CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType)); - CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType)); - - const GUID colorAttributes[] = { - MF_MT_VIDEO_LIGHTING, - MF_MT_VIDEO_PRIMARIES, - MF_MT_TRANSFER_FUNCTION, - MF_MT_YUV_MATRIX, - MF_MT_VIDEO_CHROMA_SITING - }; - - auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) { - PROPVARIANT val; - HRESULT hr = pFrom->GetItem(guidKey, &val); - - if (SUCCEEDED(hr)) { - hr = pTo->SetItem(guidKey, val); - PropVariantClear(&val); - } else if (hr == MF_E_ATTRIBUTENOTFOUND) { - hr = pTo->DeleteItem(guidKey); - } - return hr; - }; - - for (REFGUID guidKey : colorAttributes) { - if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) { - TRACE(_T("Copying color attribute %s failed: 0x%08x\n"), static_cast(CComBSTR(guidKey)), hr); - } - } - - pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0); - - const CRenderersSettings& r = GetRenderersSettings(); - - UINT32 nominalRange; - if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)) - && nominalRange == MFNominalRange_0_255) { - // EVR mixer always assumes 16-235 input. Bug? - // To keep untouched 0-255 range and avoid unwanted expansion we need to request 16-235 as output. - // To get 16-235 output we need to request 48-208 as output. - nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_48_208 : MFNominalRange_16_235; - } else { - nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255; - } - pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange); - m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange; - - ULARGE_INTEGER ui64Size; - pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart); - - CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart); - MFVideoArea Area = GetArea(0, 0, videoSize.cx, videoSize.cy); - pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea)); - - ULARGE_INTEGER ui64AspectRatio; - pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart); - - UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart; - UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart; - UINT64 gcd = GCD(ui64ARx, ui64ARy); - if (gcd > 1) { - ui64ARx /= gcd; - ui64ARy /= gcd; - } - CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy); - - if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) { - SetVideoSize(videoSize, aspectRatio); - - // Notify the graph about the change - if (m_pSink) { - m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_nativeVideoSize.cx, m_nativeVideoSize.cy), 0); - } - } - - *ppType = pOptimalMediaType; - (*ppType)->AddRef(); - - return hr; -} - -HRESULT CSyncAP::SetMediaType(IMFMediaType* pType) -{ - HRESULT hr = S_OK; - AM_MEDIA_TYPE* pAMMedia = nullptr; - CString strTemp; - - CHECK_HR(CheckShutdown()); - - if (pType == nullptr) { - // Release - RemoveAllSamples(); - DeleteSurfaces(); - CAutoLock lock(this); - m_pMediaType = nullptr; - return hr; - } - - DWORD dwFlags = 0; - if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) { - // Nothing to do - return hr; - } - - CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); - - hr = InitializeDevice(pAMMedia); - if (SUCCEEDED(hr)) { - CAutoLock lock(this); - m_pMediaType = pType; - - strTemp = GetMediaTypeName(pAMMedia->subtype); - strTemp.Replace(L"MEDIASUBTYPE_", L""); - m_strStatsMsg[MSG_MIXEROUT].Format(L"Mixer output : %s", strTemp.GetString()); - } - - pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); - - return hr; -} - -LONGLONG CSyncAP::GetMediaTypeMerit(IMFMediaType* pMediaType) -{ - AM_MEDIA_TYPE* pAMMedia = nullptr; - MFVIDEOFORMAT* VideoFormat; - - HRESULT hr; - CHECK_HR(pMediaType->GetRepresentation(FORMAT_MFVideoFormat, (void**)&pAMMedia)); - VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat; - - LONGLONG Merit = 0; - switch (VideoFormat->surfaceInfo.Format) { - case FCC('NV12'): - Merit = 90000000; - break; - case FCC('YV12'): - Merit = 80000000; - break; - case FCC('YUY2'): - Merit = 70000000; - break; - case FCC('UYVY'): - Merit = 60000000; - break; - - case D3DFMT_X8R8G8B8: // Never opt for RGB - case D3DFMT_A8R8G8B8: - case D3DFMT_R8G8B8: - case D3DFMT_R5G6B5: - Merit = 0; - break; - default: - Merit = 1000; - break; - } - pMediaType->FreeRepresentation(FORMAT_MFVideoFormat, (void*)pAMMedia); - return Merit; -} - -HRESULT CSyncAP::RenegotiateMediaType() -{ - HRESULT hr = S_OK; - - CComPtr pMixerType; - CComPtr pMixerInputType; - CComPtr pType; - - if (!m_pMixer) { - return MF_E_INVALIDREQUEST; - } - - // Get the mixer's input type - hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType); - if (SUCCEEDED(hr)) { - AM_MEDIA_TYPE* pMT; - hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT); - if (SUCCEEDED(hr)) { - m_inputMediaType = *pMT; - pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT); - } - } - - CInterfaceArray ValidMixerTypes; - // Loop through all of the mixer's proposed output types. - DWORD iTypeIndex = 0; - while ((hr != MF_E_NO_MORE_TYPES)) { - pMixerType = nullptr; - pType = nullptr; - - // Step 1. Get the next media type supported by mixer. - hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType); - if (FAILED(hr)) { - break; - } - // Step 2. Check if we support this media type. - if (SUCCEEDED(hr)) { - hr = IsMediaTypeSupported(pMixerType); - } - if (SUCCEEDED(hr)) { - hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType); - } - // Step 4. Check if the mixer will accept this media type. - if (SUCCEEDED(hr)) { - hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY); - } - if (SUCCEEDED(hr)) { - LONGLONG Merit = GetMediaTypeMerit(pType); - - size_t nTypes = ValidMixerTypes.GetCount(); - size_t iInsertPos = 0; - for (size_t i = 0; i < nTypes; ++i) { - LONGLONG ThisMerit = GetMediaTypeMerit(ValidMixerTypes[i]); - if (Merit > ThisMerit) { - iInsertPos = i; - break; - } else { - iInsertPos = i + 1; - } - } - ValidMixerTypes.InsertAt(iInsertPos, pType); - } - } - - size_t nValidTypes = ValidMixerTypes.GetCount(); - for (size_t i = 0; i < nValidTypes; ++i) { - pType = ValidMixerTypes[i]; - } - - for (size_t i = 0; i < nValidTypes; ++i) { - pType = ValidMixerTypes[i]; - hr = SetMediaType(pType); - if (SUCCEEDED(hr)) { - hr = m_pMixer->SetOutputType(0, pType, 0); - // If something went wrong, clear the media type. - if (FAILED(hr)) { - SetMediaType(nullptr); - } else { - break; - } - } - } - - pMixerType = nullptr; - pType = nullptr; - return hr; -} - -bool CSyncAP::GetSampleFromMixer() -{ - MFT_OUTPUT_DATA_BUFFER dataBuffer; - HRESULT hr = S_OK; - DWORD dwStatus; - LONGLONG llClockBefore = 0; - LONGLONG llClockAfter = 0; - LONGLONG llMixerLatency; - - UINT dwSurface; - bool newSample = false; - - auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { - UINT32 nGroupId; - return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); - }; - - while (SUCCEEDED(hr)) { // Get as many frames as there are and that we have samples for - CComPtr pSample; - if (FAILED(GetFreeSample(&pSample))) { // All samples are taken for the moment. Better luck next time - break; - } - - ZeroMemory(&dataBuffer, sizeof(dataBuffer)); - dataBuffer.pSample = pSample; - pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface); - ASSERT(sampleHasCurrentGroupId(pSample)); - - { - llClockBefore = GetRenderersData()->GetPerfCounter(); - hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus); - llClockAfter = GetRenderersData()->GetPerfCounter(); - } - - if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { // There are no samples left in the mixer - AddToFreeList(pSample, false); - pSample = nullptr; // The sample should not be used after being queued - // Important: Release any events returned from the ProcessOutput method. - SAFE_RELEASE(dataBuffer.pEvents); - break; - } - - if (m_pSink) { - llMixerLatency = llClockAfter - llClockBefore; - m_pSink->Notify(EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0); - } - - newSample = true; - - if (GetRenderersData()->m_bTearingTest) { - RECT rcTearing; - - rcTearing.left = m_nTearingPos; - rcTearing.top = 0; - rcTearing.right = rcTearing.left + 4; - rcTearing.bottom = m_nativeVideoSize.cy; - m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - - rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; - rcTearing.right = rcTearing.left + 4; - m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; - } - - if (SUCCEEDED(TrackSample(pSample))) { - AddToScheduledList(pSample, false); // Schedule, then go back to see if there is more where that came from - pSample = nullptr; // The sample should not be used after being queued - } else { - ASSERT(FALSE); - } - - // Important: Release any events returned from the ProcessOutput method. - SAFE_RELEASE(dataBuffer.pEvents); - } - return newSample; -} - -STDMETHODIMP CSyncAP::GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType) -{ - HRESULT hr = S_OK; - CAutoLock lock(this); - CheckPointer(ppMediaType, E_POINTER); - CHECK_HR(CheckShutdown()); - - if (!m_pMediaType) { - return MF_E_NOT_INITIALIZED; - } - - CHECK_HR(m_pMediaType->QueryInterface(IID_PPV_ARGS(ppMediaType))); - return hr; -} - -// IMFTopologyServiceLookupClient -STDMETHODIMP CSyncAP::InitServicePointers(__in IMFTopologyServiceLookup* pLookup) -{ - DWORD dwObjects = 1; - pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_pMixer), &dwObjects); - pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pSink), &dwObjects); - pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pClock), &dwObjects); - StartWorkerThreads(); - return S_OK; -} - -STDMETHODIMP CSyncAP::ReleaseServicePointers() -{ - StopWorkerThreads(); - m_pMixer = nullptr; - m_pSink = nullptr; - m_pClock = nullptr; - return S_OK; -} - -// IMFVideoDeviceID -STDMETHODIMP CSyncAP::GetDeviceID(__out IID* pDeviceID) -{ - CheckPointer(pDeviceID, E_POINTER); - *pDeviceID = IID_IDirect3DDevice9; - return S_OK; -} - -// IMFGetService -STDMETHODIMP CSyncAP::GetService(__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppvObject) -{ - if (guidService == MR_VIDEO_RENDER_SERVICE) { - return NonDelegatingQueryInterface(riid, ppvObject); - } else if (guidService == MR_VIDEO_ACCELERATION_SERVICE) { - return m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppvObject); - } - - return E_NOINTERFACE; -} - -// IMFAsyncCallback -STDMETHODIMP CSyncAP::GetParameters(__RPC__out DWORD* pdwFlags, __RPC__out DWORD* pdwQueue) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CSyncAP::Invoke(__RPC__in_opt IMFAsyncResult* pAsyncResult) -{ - return E_NOTIMPL; -} - -// IMFVideoDisplayControl -STDMETHODIMP CSyncAP::GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) -{ - if (pszVideo) { - pszVideo->cx = m_nativeVideoSize.cx; - pszVideo->cy = m_nativeVideoSize.cy; - } - if (pszARVideo) { - pszARVideo->cx = m_aspectRatio.cx; - pszARVideo->cy = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CSyncAP::GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) -{ - if (pszMin) { - pszMin->cx = 1; - pszMin->cy = 1; - } - - if (pszMax) { - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - - if (SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D, m_hWnd), &d3ddm))) { - pszMax->cx = d3ddm.Width; - pszMax->cy = d3ddm.Height; - } - } - return S_OK; -} - -STDMETHODIMP CSyncAP::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) -{ - return S_OK; -} - -STDMETHODIMP CSyncAP::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) -{ - if (pnrcSource) { - pnrcSource->left = 0.0; - pnrcSource->top = 0.0; - pnrcSource->right = 1.0; - pnrcSource->bottom = 1.0; - } - if (prcDest) { - memcpy(prcDest, &m_videoRect, sizeof(m_videoRect)); //GetClientRect (m_hWnd, prcDest); - } - return S_OK; -} - -STDMETHODIMP CSyncAP::SetAspectRatioMode(DWORD dwAspectRatioMode) -{ - m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetAspectRatioMode(DWORD* pdwAspectRatioMode) -{ - CheckPointer(pdwAspectRatioMode, E_POINTER); - *pdwAspectRatioMode = m_dwVideoAspectRatioMode; - return S_OK; -} - -STDMETHODIMP CSyncAP::SetVideoWindow(HWND hwndVideo) -{ - if (m_hWnd != hwndVideo) { - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_allocatorLock); - - m_hWnd = hwndVideo; - m_bPendingResetDevice = true; - if (m_pSink) { - m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); - } - - SendResetRequest(); - } - return S_OK; -} - -STDMETHODIMP CSyncAP::GetVideoWindow(HWND* phwndVideo) -{ - CheckPointer(phwndVideo, E_POINTER); - *phwndVideo = m_hWnd; - return S_OK; -} - -STDMETHODIMP CSyncAP::RepaintVideo() -{ - Paint(true); - return S_OK; -} - -STDMETHODIMP CSyncAP::GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp) { - if (!pBih || !pDib || !pcbDib) { - return E_POINTER; - } - CheckPointer(m_pD3DDevEx, E_ABORT); - - HRESULT hr = S_OK; - const unsigned width = m_windowRect.Width(); - const unsigned height = m_windowRect.Height(); - const unsigned len = width * height * 4; - - memset(pBih, 0, sizeof(BITMAPINFOHEADER)); - pBih->biSize = sizeof(BITMAPINFOHEADER); - pBih->biWidth = width; - pBih->biHeight = height; - pBih->biBitCount = 32; - pBih->biPlanes = 1; - pBih->biSizeImage = DIBSIZE(*pBih); - - BYTE* p = (BYTE*)CoTaskMemAlloc(len); // only this allocator can be used - if (!p) { - return E_OUTOFMEMORY; - } - - CComPtr pBackBuffer; - CComPtr pDestSurface; - D3DLOCKED_RECT r; - if (FAILED(hr = m_pD3DDevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)) - || FAILED(hr = m_pD3DDevEx->CreateRenderTarget(width, height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pDestSurface, nullptr)) - || (FAILED(hr = m_pD3DDevEx->StretchRect(pBackBuffer, m_windowRect, pDestSurface, nullptr, D3DTEXF_NONE))) - || (FAILED(hr = pDestSurface->LockRect(&r, nullptr, D3DLOCK_READONLY)))) { - CString Error = GetWindowsErrorMessage(hr, nullptr); - TRACE_SR(L"CSyncAP::GetCurrentImage failed : %s", S_OK == hr ? L"S_OK" : Error.GetBuffer()); - CoTaskMemFree(p); - return hr; - } - - RetrieveBitmapData(width, height, 32, p ? (BYTE*)p : (BYTE*)(pBih + 1), (BYTE*)r.pBits, r.Pitch); - - pDestSurface->UnlockRect(); - - *pDib = p; - *pcbDib = len; - - return S_OK; -} - -STDMETHODIMP CSyncAP::SetBorderColor(COLORREF Clr) -{ - m_BorderColor = Clr; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetBorderColor(COLORREF* pClr) -{ - CheckPointer(pClr, E_POINTER); - *pClr = m_BorderColor; - return S_OK; -} - -STDMETHODIMP CSyncAP::SetRenderingPrefs(DWORD dwRenderFlags) -{ - m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetRenderingPrefs(DWORD* pdwRenderFlags) -{ - CheckPointer(pdwRenderFlags, E_POINTER); - *pdwRenderFlags = m_dwVideoRenderPrefs; - return S_OK; -} - -STDMETHODIMP CSyncAP::SetFullscreen(BOOL fFullscreen) -{ - m_bIsFullscreen = !!fFullscreen; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetFullscreen(BOOL* pfFullscreen) -{ - CheckPointer(pfFullscreen, E_POINTER); - *pfFullscreen = m_bIsFullscreen; - return S_OK; -} - -// IEVRTrustedVideoPlugin -STDMETHODIMP CSyncAP::IsInTrustedVideoMode(BOOL* pYes) -{ - CheckPointer(pYes, E_POINTER); - *pYes = TRUE; - return S_OK; -} - -STDMETHODIMP CSyncAP::CanConstrict(BOOL* pYes) -{ - CheckPointer(pYes, E_POINTER); - *pYes = TRUE; - return S_OK; -} - -STDMETHODIMP CSyncAP::SetConstriction(DWORD dwKPix) -{ - return S_OK; -} - -STDMETHODIMP CSyncAP::DisableImageExport(BOOL bDisable) -{ - return S_OK; -} - -// IDirect3DDeviceManager9 -STDMETHODIMP CSyncAP::ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken) -{ - HRESULT hr = m_pD3DManager->ResetDevice(pDevice, resetToken); - return hr; -} - -STDMETHODIMP CSyncAP::OpenDeviceHandle(HANDLE* phDevice) -{ - HRESULT hr = m_pD3DManager->OpenDeviceHandle(phDevice); - return hr; -} - -STDMETHODIMP CSyncAP::CloseDeviceHandle(HANDLE hDevice) -{ - HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice); - return hr; -} - -STDMETHODIMP CSyncAP::TestDevice(HANDLE hDevice) -{ - HRESULT hr = m_pD3DManager->TestDevice(hDevice); - return hr; -} - -STDMETHODIMP CSyncAP::LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock) -{ - HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock); - return hr; -} - -STDMETHODIMP CSyncAP::UnlockDevice(HANDLE hDevice, BOOL fSaveState) -{ - HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState); - return hr; -} - -STDMETHODIMP CSyncAP::GetVideoService(HANDLE hDevice, REFIID riid, void** ppService) -{ - HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService); - - if (riid == __uuidof(IDirectXVideoDecoderService)) { - UINT nNbDecoder = 5; - GUID* pDecoderGuid; - IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService; - pDXVAVideoDecoder->GetDecoderDeviceGuids(&nNbDecoder, &pDecoderGuid); - } else if (riid == __uuidof(IDirectXVideoProcessorService)) { - IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService; - UNREFERENCED_PARAMETER(pDXVAProcessor); - } - - return hr; -} - -STDMETHODIMP CSyncAP::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) -{ - // This function should be called... - ASSERT(FALSE); - - if (lpWidth) { - *lpWidth = m_nativeVideoSize.cx; - } - if (lpHeight) { - *lpHeight = m_nativeVideoSize.cy; - } - if (lpARWidth) { - *lpARWidth = m_aspectRatio.cx; - } - if (lpARHeight) { - *lpARHeight = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CSyncAP::InitializeDevice(AM_MEDIA_TYPE* pMediaType) -{ - HRESULT hr; - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_allocatorLock); - - RemoveAllSamples(); - DeleteSurfaces(); - - VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*) pMediaType->pbFormat; - int w = vih2->bmiHeader.biWidth; - int h = abs(vih2->bmiHeader.biHeight); - - SetVideoSize(CSize(w, h), m_aspectRatio); - if (m_bHighColorResolution) { - hr = AllocSurfaces(D3DFMT_A2R10G10B10); - } else { - hr = AllocSurfaces(D3DFMT_X8R8G8B8); - } - - for (int i = 0; i < m_nDXSurface; i++) { - CComPtr pMFSample; - hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); - if (SUCCEEDED(hr)) { - pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); - pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - m_FreeSamples.AddTail(pMFSample); - pMFSample = nullptr; // The sample should not be used after being queued - } - ASSERT(SUCCEEDED(hr)); - } - return hr; -} - -DWORD WINAPI CSyncAP::MixerThreadStatic(LPVOID lpParam) -{ - CSyncAP* pThis = (CSyncAP*) lpParam; - pThis->MixerThread(); - return 0; -} - -void CSyncAP::MixerThread() -{ - HANDLE hEvts[] = {m_hEvtQuit}; - bool bQuit = false; - TIMECAPS tc; - DWORD dwResolution; - - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - timeBeginPeriod(dwResolution); - - while (!bQuit) { - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); - switch (dwObject) { - case WAIT_OBJECT_0: - bQuit = true; - break; - case WAIT_TIMEOUT: { - bool bNewSample; - { - CAutoLock AutoLock(&m_ImageProcessingLock); - bNewSample = GetSampleFromMixer(); - } - - if (m_rtTimePerFrame == 0 && bNewSample) { - // Use the code from VMR9 to get the movie fps, as this method is reliable. - CComPtr pPin; - CMediaType mt; - if (SUCCEEDED(m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) && - SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); - - m_bInterlaced = ExtractInterlaced(&mt); - - if (m_rtTimePerFrame > 0) { - m_fps = 10000000.0 / m_rtTimePerFrame; - } - } - - // Update internal subtitle clock - if (m_bUseInternalTimer && m_pSubPicQueue) { - m_pSubPicQueue->SetFPS(m_fps); - } - } - } - break; - } - } - timeEndPeriod(dwResolution); -} - -DWORD WINAPI CSyncAP::RenderThreadStatic(LPVOID lpParam) -{ - CSyncAP* pThis = (CSyncAP*)lpParam; - pThis->RenderThread(); - return 0; -} - -// Get samples that have been received and queued up by MixerThread() and present them at the correct time by calling Paint(). -void CSyncAP::RenderThread() -{ - HANDLE hEvts[] = {m_hEvtQuit, m_hEvtFlush, m_hEvtSkip}; - bool bQuit = false; - TIMECAPS tc; - CComPtr pNewSample; // The sample next in line to be presented - - // Tell Multimedia Class Scheduler we are doing threaded playback (increase priority) - HANDLE hAvrt = 0; - if (fnAvSetMmThreadCharacteristicsW) { - DWORD dwTaskIndex = 0; - hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); - if (fnAvSetMmThreadPriority) { - fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH); - } - } - - // Set timer resolution - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - VERIFY(timeBeginPeriod(dwResolution) == 0); - - auto SubPicSetTime = [&] { - if (!g_bExternalSubtitleTime) { - CSubPicAllocatorPresenterImpl::SetTime(g_tSegmentStart + m_llSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); - } - }; - - auto checkPendingMediaFinished = [this]() { - if (m_bPendingMediaFinished) { - CAutoLock lock(&m_SampleQueueLock); - if (m_ScheduledSamples.IsEmpty()) { - m_bPendingMediaFinished = false; - m_pSink->Notify(EC_COMPLETE, 0, 0); - } - } - }; - - while (!bQuit) { - m_lNextSampleWait = 1; // Default value for running this loop - int nSamplesLeft = 0; - bool stepForward = false; - LONG lDisplayCycle = (LONG)(GetDisplayCycle()); - LONG lDisplayCycle2 = (LONG)(GetDisplayCycle() / 2.0); // These are a couple of empirically determined constants used the control the "snap" function - LONG lDisplayCycle4 = (LONG)(GetDisplayCycle() / 4.0); - - const CRenderersSettings& r = GetRenderersSettings(); - double dTargetSyncOffset = (&r == nullptr) ? 12.0 : r.m_AdvRendSets.fTargetSyncOffset; - - if ((m_nRenderState == Started || !m_bPrerolled) && !pNewSample) { // If either streaming or the pre-roll sample and no sample yet fetched - if (SUCCEEDED(GetScheduledSample(&pNewSample, nSamplesLeft))) { // Get the next sample - m_llLastSampleTime = m_llSampleTime; - if (!m_bPrerolled) { - m_bPrerolled = true; // m_bPrerolled is a ticket to show one (1) frame immediately - m_lNextSampleWait = 0; // Present immediately - } else if (SUCCEEDED(pNewSample->GetSampleTime(&m_llSampleTime))) { // Get zero-based sample due time - if (m_llLastSampleTime == m_llSampleTime) { // In the rare case there are duplicate frames in the movie. There really shouldn't be but it happens. - checkPendingMediaFinished(); - pNewSample = nullptr; - m_lNextSampleWait = 0; - } else { - MFTIME llSystemTime; - LONGLONG llRefClockTime; - m_pClock->GetCorrelatedTime(0, &llRefClockTime, &llSystemTime); // Get zero-based reference clock time. llSystemTime is not used for anything here - m_lNextSampleWait = (LONG)((m_llSampleTime - llRefClockTime) / 10000); // Time left until sample is due, in ms - if (m_bStepping) { - m_lNextSampleWait = 0; - } else if (r.m_AdvRendSets.bSynchronizeNearest) { // Present at the closest "safe" occasion at dTargetSyncOffset ms before vsync to avoid tearing - if (m_lNextSampleWait < -lDisplayCycle) { // We have to allow slightly negative numbers at this stage. Otherwise we get "choking" when frame rate > refresh rate - SetEvent(m_hEvtSkip); - m_bEvtSkip = true; - } - REFERENCE_TIME rtRefClockTimeNow = 0; - if (m_pRefClock) { - m_pRefClock->GetTime(&rtRefClockTimeNow); // Reference clock time now - } - LONG lLastVsyncTime = (LONG)((m_llEstVBlankTime - rtRefClockTimeNow) / 10000); // Last vsync time relative to now - if (abs(lLastVsyncTime) > lDisplayCycle) { - lLastVsyncTime = - lDisplayCycle; // To even out glitches in the beginning - } - - LONGLONG llNextSampleWait = (LONGLONG)((lLastVsyncTime + GetDisplayCycle() - dTargetSyncOffset) * 10000); // Time from now util next safe time to Paint() - while ((llRefClockTime + llNextSampleWait) < (m_llSampleTime + m_llHysteresis)) { // While the proposed time is in the past of sample presentation time - llNextSampleWait = llNextSampleWait + (LONGLONG)(GetDisplayCycle() * 10000); // Try the next possible time, one display cycle ahead - } - m_lNextSampleWait = (LONG)(llNextSampleWait / 10000); - m_lShiftToNearestPrev = m_lShiftToNearest; - m_lShiftToNearest = (LONG)((llRefClockTime + llNextSampleWait - m_llSampleTime) / 10000); // The adjustment made to get to the sweet point in time, in ms - - // If m_lShiftToNearest is pushed a whole cycle into the future, then we are getting more frames - // than we can chew and we need to throw one away. We don't want to wait many cycles and skip many - // frames. - if (m_lShiftToNearest > (lDisplayCycle + 1)) { - SetEvent(m_hEvtSkip); - m_bEvtSkip = true; - } - - // We need to add a hysteresis to the control of the timing adjustment to avoid judder when - // presentation time is close to vsync and the renderer couldn't otherwise make up its mind - // whether to present before the vsync or after. That kind of indecisiveness leads to judder. - if (m_bSnapToVSync) { - - if ((m_lShiftToNearestPrev - m_lShiftToNearest) > lDisplayCycle2) { // If a step down in the m_lShiftToNearest function. Display slower than video. - m_bVideoSlowerThanDisplay = false; - m_llHysteresis = -(LONGLONG)lDisplayCycle4 * 10000; - } else if ((m_lShiftToNearest - m_lShiftToNearestPrev) > lDisplayCycle2) { // If a step up - m_bVideoSlowerThanDisplay = true; - m_llHysteresis = (LONGLONG)lDisplayCycle4 * 10000; - } else if ((m_lShiftToNearest < (3 * lDisplayCycle4)) && (m_lShiftToNearest > lDisplayCycle4)) { - m_llHysteresis = 0; // Reset when between 1/4 and 3/4 of the way either way - } - - if ((m_lShiftToNearest < lDisplayCycle2) && (m_llHysteresis > 0)) { - m_llHysteresis = 0; // Should never really be in this territory. - } - if (m_lShiftToNearest < 0) { - m_llHysteresis = 0; // A glitch might get us to a sticky state where both these numbers are negative. - } - if ((m_lShiftToNearest > lDisplayCycle2) && (m_llHysteresis < 0)) { - m_llHysteresis = 0; - } - } - } - - if (m_lNextSampleWait < 0) { // Skip late or duplicate sample. - SetEvent(m_hEvtSkip); - m_bEvtSkip = true; - } - - if (m_lNextSampleWait > 1000) { - m_lNextSampleWait = 1000; // So as to avoid full a full stop when sample is far in the future (shouldn't really happen). - } - } - } // if got new sample - } else { - checkPendingMediaFinished(); - } - } - // Wait for the next presentation time (m_lNextSampleWait) or some other event. - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, (DWORD)m_lNextSampleWait); - switch (dwObject) { - case WAIT_OBJECT_0: // Quit - bQuit = true; - break; - - case WAIT_OBJECT_0 + 1: // Flush - checkPendingMediaFinished(); - pNewSample = nullptr; - FlushSamples(); - m_bEvtFlush = false; - ResetEvent(m_hEvtFlush); - m_bPrerolled = false; - m_lShiftToNearest = 0; - stepForward = true; - break; - - case WAIT_OBJECT_0 + 2: // Skip sample - m_pcFramesDropped++; - m_llSampleTime = m_llLastSampleTime; // This sample will never be shown - m_bEvtSkip = false; - ResetEvent(m_hEvtSkip); - stepForward = true; - break; - - case WAIT_TIMEOUT: // Time to show the sample or something - if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != r.m_AdvRendSets.iEVROutputRange || m_bPendingRenegotiate) { - checkPendingMediaFinished(); - pNewSample = nullptr; - FlushSamples(); - RenegotiateMediaType(); - m_bPendingRenegotiate = false; - } - - if (m_bPendingResetDevice) { - checkPendingMediaFinished(); - pNewSample = nullptr; - SendResetRequest(); - } else if (m_nStepCount < 0) { - m_nStepCount = 0; - m_pcFramesDropped++; - stepForward = true; - } else if (pNewSample && (m_nStepCount > 0)) { - SubPicSetTime(); - Paint(pNewSample); - CompleteFrameStep(false); - m_pcFramesDrawn++; - stepForward = true; - } else if (pNewSample && !m_bStepping) { // When a stepped frame is shown, a new one is fetched that we don't want to show here while stepping - SubPicSetTime(); - Paint(pNewSample); - m_pcFramesDrawn++; - stepForward = true; - } - break; - } // switch - if (stepForward) { - checkPendingMediaFinished(); - pNewSample = nullptr; - } - } // while - pNewSample = nullptr; - timeEndPeriod(dwResolution); - if (fnAvRevertMmThreadCharacteristics) { - fnAvRevertMmThreadCharacteristics(hAvrt); - } -} - -STDMETHODIMP_(bool) CSyncAP::ResetDevice() -{ - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_allocatorLock); - - RemoveAllSamples(); - - bool bResult = __super::ResetDevice(); - - for (int i = 0; i < m_nDXSurface; i++) { - CComPtr pMFSample; - HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); - if (SUCCEEDED(hr)) { - pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); - pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - m_FreeSamples.AddTail(pMFSample); - pMFSample = nullptr; // The sample should not be used after being queued - } - ASSERT(SUCCEEDED(hr)); - } - return bResult; -} - -void CSyncAP::OnResetDevice() -{ - TRACE(_T("--> CSyncAP::OnResetDevice on thread: %lu\n"), GetCurrentThreadId()); - m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); - if (m_pSink) { - m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); - } - CSize videoSize = GetVisibleVideoSize(); - if (m_pSink) { - m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(videoSize.cx, videoSize.cy), 0); - } -} - -void CSyncAP::RemoveAllSamples() -{ - CAutoLock imageProcesssingLock(&m_ImageProcessingLock); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - - FlushSamples(); - m_ScheduledSamples.RemoveAll(); - m_FreeSamples.RemoveAll(); - m_nUsedBuffer = 0; - // Increment the group id to make sure old samples will really be deleted - m_nCurrentGroupId++; -} - -HRESULT CSyncAP::GetFreeSample(IMFSample** ppSample) -{ - CAutoLock lock(&m_SampleQueueLock); - HRESULT hr = S_OK; - - if (!m_FreeSamples.IsEmpty()) { - m_nUsedBuffer++; - *ppSample = m_FreeSamples.RemoveHead().Detach(); - } else { - hr = MF_E_SAMPLEALLOCATOR_EMPTY; - } - - return hr; -} - -HRESULT CSyncAP::GetScheduledSample(IMFSample** ppSample, int& count) -{ - CAutoLock lock(&m_SampleQueueLock); - HRESULT hr = S_OK; - - count = (int)m_ScheduledSamples.GetCount(); - if (count > 0) { - *ppSample = m_ScheduledSamples.RemoveHead().Detach(); - --count; - } else { - hr = MF_E_SAMPLEALLOCATOR_EMPTY; - } - - return hr; -} - -void CSyncAP::AddToFreeList(IMFSample* pSample, bool bTail) -{ - CAutoLock lock(&m_SampleQueueLock); - - m_nUsedBuffer--; - if (bTail) { - m_FreeSamples.AddTail(pSample); - } else { - m_FreeSamples.AddHead(pSample); - } -} - -void CSyncAP::AddToScheduledList(IMFSample* pSample, bool bSorted) -{ - CAutoLock lock(&m_SampleQueueLock); - - if (bSorted) { - m_ScheduledSamples.AddHead(pSample); - } else { - m_ScheduledSamples.AddTail(pSample); - } -} - -void CSyncAP::FlushSamples() -{ - CAutoLock lock(this); - CAutoLock lock2(&m_SampleQueueLock); - - m_bPrerolled = false; - m_pCurrentlyDisplayedSample = nullptr; - m_ScheduledSamples.RemoveAll(); -} - -HRESULT CSyncAP::TrackSample(IMFSample* pSample) -{ - HRESULT hr = E_FAIL; - if (CComQIPtr pTracked = pSample) { - hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr); - } - return hr; -} - -HRESULT CSyncAP::OnSampleFree(IMFAsyncResult* pResult) -{ - CComPtr pObject; - HRESULT hr = pResult->GetObject(&pObject); - if (SUCCEEDED(hr)) { - if (CComQIPtr pSample = pObject) { - // Ignore the sample if it is from an old group - UINT32 nGroupId; - CAutoLock sampleQueueLock(&m_SampleQueueLock); - if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) { - AddToFreeList(pSample, true); - pSample = nullptr; // The sample should not be used after being queued - } - } - } - return hr; -} - -HRESULT CSyncAP::AdviseSyncClock(ISyncClock* sC) -{ - return m_pGenlock->AdviseSyncClock(sC); -} - -HRESULT CSyncAP::BeginStreaming() -{ - m_pcFramesDropped = 0; - m_pcFramesDrawn = 0; - - CComPtr pEVR; - CFilterInfo filterInfo; - m_pOuterEVR->QueryInterface(IID_PPV_ARGS(&pEVR)); - pEVR->QueryFilterInfo(&filterInfo); - - BeginEnumFilters(filterInfo.pGraph, pEF, pBF); - if (CComQIPtr pAS = pBF) { - m_pAudioStats = pAS; - }; - EndEnumFilters; - - pEVR->GetSyncSource(&m_pRefClock); - m_pGenlock->SetMonitor(GetAdapter(m_pD3D, m_hWnd)); - m_pGenlock->GetTiming(); - - ResetStats(); - EstimateRefreshTimings(); - if (m_dFrameCycle > 0.0) { - m_dCycleDifference = GetCycleDifference(); // Might have moved to another display - } - - m_nRenderState = Paused; - - return S_OK; -} - -HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP) -{ - HRESULT hr = E_FAIL; - if (clsid == CLSID_SyncAllocatorPresenter) { - CString Error; - *ppAP = DEBUG_NEW CSyncAP(hWnd, bFullscreen, hr, Error); - (*ppAP)->AddRef(); - - if (FAILED(hr)) { - Error += L"\n"; - Error += GetWindowsErrorMessage(hr, nullptr); - MessageBox(hWnd, Error, L"Error creating EVR Sync", MB_OK | MB_ICONERROR); - (*ppAP)->Release(); - *ppAP = nullptr; - } else if (!Error.IsEmpty()) { - MessageBox(hWnd, Error, L"Warning creating EVR Sync", MB_OK | MB_ICONWARNING); - } - } - return hr; -} - -CSyncRenderer::CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP* pAllocatorPresenter): CUnknown(pName, pUnk) -{ - hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner()); - CComQIPtr pEVRBase = m_pEVR; - m_pEVRBase = pEVRBase; // Don't keep a second reference on the EVR filter - m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; - m_pAllocatorPresenter = pAllocatorPresenter; -} - -CSyncRenderer::~CSyncRenderer() -{ -} - -HRESULT STDMETHODCALLTYPE CSyncRenderer::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetState(dwMilliSecsTimeout, State); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::EnumPins(__out IEnumPins** ppEnum) -{ - if (m_pEVRBase) { - return m_pEVRBase->EnumPins(ppEnum); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::FindPin(LPCWSTR Id, __out IPin** ppPin) -{ - if (m_pEVRBase) { - return m_pEVRBase->FindPin(Id, ppPin); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::QueryFilterInfo(__out FILTER_INFO* pInfo) -{ - if (m_pEVRBase) { - return m_pEVRBase->QueryFilterInfo(pInfo); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName) -{ - if (m_pEVRBase) { - return m_pEVRBase->JoinFilterGraph(pGraph, pName); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::QueryVendorInfo(__out LPWSTR* pVendorInfo) -{ - if (m_pEVRBase) { - return m_pEVRBase->QueryVendorInfo(pVendorInfo); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::Stop() -{ - if (m_pEVRBase) { - return m_pEVRBase->Stop(); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::Pause() -{ - if (m_pEVRBase) { - return m_pEVRBase->Pause(); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::Run(REFERENCE_TIME tStart) -{ - if (m_pEVRBase) { - return m_pEVRBase->Run(tStart); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::SetSyncSource(__in_opt IReferenceClock* pClock) -{ - if (m_pEVRBase) { - return m_pEVRBase->SetSyncSource(pClock); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::GetSyncSource(__deref_out_opt IReferenceClock** pClock) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetSyncSource(pClock); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::GetClassID(__RPC__out CLSID* pClassID) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetClassID(pClassID); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); - return S_OK; -} - -STDMETHODIMP CSyncRenderer::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} - -STDMETHODIMP CSyncRenderer::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} - -STDMETHODIMP CSyncRenderer::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - HRESULT hr; - - if (riid == __uuidof(IVMRMixerBitmap9)) { - return GetInterface((IVMRMixerBitmap9*)this, ppv); - } - - if (riid == __uuidof(IBaseFilter)) { - return GetInterface((IBaseFilter*)this, ppv); - } - - if (riid == __uuidof(IMediaFilter)) { - return GetInterface((IMediaFilter*)this, ppv); - } - if (riid == __uuidof(IPersist)) { - return GetInterface((IPersist*)this, ppv); - } - if (riid == __uuidof(IBaseFilter)) { - return GetInterface((IBaseFilter*)this, ppv); - } - - hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE; - if (m_pEVR && FAILED(hr)) { - hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; - } - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); -} - -CGenlock::CGenlock(double target, double limit, int lineD, int colD, double clockD, UINT mon) - : powerstripTimingExists(false) - , liveSource(false) - , adjDelta(0) // Number of rows used in display frequency adjustment, typically 1 (one) - , lineDelta(lineD) // Number of columns used in display frequency adjustment, typically 1 - 2 - , columnDelta(colD) // Delta used in clock speed adjustment. In fractions of 1.0. Typically around 0.001 - , cycleDelta(clockD) // The monitor to be adjusted if the display refresh rate is the controlled parameter - , displayAdjustmentsMade(0) - , clockAdjustmentsMade(0) - , totalLines(0) - , totalColumns(0) - , visibleLines(0) - , visibleColumns(0) - , syncOffsetFifo(64) - , frameCycleFifo(4) - , minSyncOffset(DBL_MAX) - , maxSyncOffset(DBL_MIN) - , syncOffsetAvg(0.0) - , minFrameCycle(DBL_MAX) - , maxFrameCycle(DBL_MIN) - , frameCycleAvg(0.0) - , pixelClock(0) - , displayFreqCruise(0.0) - , displayFreqSlower(0.0) - , displayFreqFaster(0.0) - , curDisplayFreq(0.0) - , controlLimit(limit) // How much sync offset is allowed to drift from target sync offset before control kicks in - , monitor(mon) - , psWnd(nullptr) - , displayTiming() - , displayTimingSave() - , lowSyncOffset(target - limit) - , targetSyncOffset(target) // Target sync offset, typically around 10 ms - , highSyncOffset(target + limit) -{ - ZeroMemory(faster, MAX_LOADSTRING); - ZeroMemory(cruise, MAX_LOADSTRING); - ZeroMemory(slower, MAX_LOADSTRING); - ZeroMemory(savedTiming, MAX_LOADSTRING); -} - -CGenlock::~CGenlock() -{ - ResetTiming(); - syncClock = nullptr; -}; - -BOOL CGenlock::PowerstripRunning() -{ - psWnd = FindWindow(_T("TPShidden"), nullptr); - if (!psWnd) { - return FALSE; // Powerstrip is not running - } else { - return TRUE; - } -} - -// Get the display timing parameters through PowerStrip (if running). -HRESULT CGenlock::GetTiming() -{ - ATOM getTiming; - LPARAM lParam = 0; - WPARAM wParam = monitor; - int i = 0; - int j = 0; - int params = 0; - TCHAR tmpStr[MAX_LOADSTRING] = _T(""); - - CAutoLock lock(&csGenlockLock); - if (!PowerstripRunning()) { - return E_FAIL; - } - - getTiming = static_cast(SendMessage(psWnd, UM_GETTIMING, wParam, lParam)); - GlobalGetAtomName(getTiming, savedTiming, MAX_LOADSTRING); - - while (params < TIMING_PARAM_CNT) { - while (savedTiming[i] != _T(',') && savedTiming[i] != _T('\0')) { - tmpStr[j++] = savedTiming[i]; - tmpStr[j] = _T('\0'); - i++; - } - i++; // Skip trailing comma - j = 0; - displayTiming[params] = _ttoi(tmpStr); - displayTimingSave[params] = displayTiming[params]; - params++; - } - - // The display update frequency is controlled by adding and subtracting pixels form the - // image. This is done by either subtracting columns or rows or both. Some displays like - // row adjustments and some column adjustments. One should probably not do both. - StringCchPrintf(faster, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), - displayTiming[0], - displayTiming[HFRONTPORCH] - columnDelta, - displayTiming[2], - displayTiming[3], - displayTiming[4], - displayTiming[VFRONTPORCH] - lineDelta, - displayTiming[6], - displayTiming[7], - displayTiming[PIXELCLOCK], - displayTiming[9] - ); - - // Nominal update frequency - StringCchPrintf(cruise, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), - displayTiming[0], - displayTiming[HFRONTPORCH], - displayTiming[2], - displayTiming[3], - displayTiming[4], - displayTiming[VFRONTPORCH], - displayTiming[6], - displayTiming[7], - displayTiming[PIXELCLOCK], - displayTiming[9] - ); - - // Lower than nominal update frequency - StringCchPrintf(slower, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), - displayTiming[0], - displayTiming[HFRONTPORCH] + columnDelta, - displayTiming[2], - displayTiming[3], - displayTiming[4], - displayTiming[VFRONTPORCH] + lineDelta, - displayTiming[6], - displayTiming[7], - displayTiming[PIXELCLOCK], - displayTiming[9] - ); - - totalColumns = displayTiming[HACTIVE] + displayTiming[HFRONTPORCH] + displayTiming[HSYNCWIDTH] + displayTiming[HBACKPORCH]; - totalLines = displayTiming[VACTIVE] + displayTiming[VFRONTPORCH] + displayTiming[VSYNCWIDTH] + displayTiming[VBACKPORCH]; - pixelClock = 1000 * displayTiming[PIXELCLOCK]; // Pixels/s - displayFreqCruise = (double)pixelClock / (totalLines * totalColumns); // Frames/s - displayFreqSlower = (double)pixelClock / ((totalLines + lineDelta) * (totalColumns + columnDelta)); - displayFreqFaster = (double)pixelClock / ((totalLines - lineDelta) * (totalColumns - columnDelta)); - curDisplayFreq = displayFreqCruise; - GlobalDeleteAtom(getTiming); - adjDelta = 0; - powerstripTimingExists = true; - return S_OK; -} - -// Reset display timing parameters to nominal. -HRESULT CGenlock::ResetTiming() -{ - CAutoLock lock(&csGenlockLock); - - if (!PowerstripRunning()) { - return E_FAIL; - } - - if (displayAdjustmentsMade > 0) { - ATOM setTiming = GlobalAddAtom(cruise); - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, monitor, (LPARAM)setTiming); - GlobalDeleteAtom(setTiming); - curDisplayFreq = displayFreqCruise; - } - adjDelta = 0; - return S_OK; -} - -// Reset reference clock speed to nominal. -HRESULT CGenlock::ResetClock() -{ - adjDelta = 0; - if (syncClock == nullptr) { - return E_FAIL; - } else { - return syncClock->AdjustClock(1.0); - } -} - -HRESULT CGenlock::SetTargetSyncOffset(double targetD) -{ - targetSyncOffset = targetD; - lowSyncOffset = targetD - controlLimit; - highSyncOffset = targetD + controlLimit; - return S_OK; -} - -HRESULT CGenlock::GetTargetSyncOffset(double* targetD) -{ - *targetD = targetSyncOffset; - return S_OK; -} - -HRESULT CGenlock::SetControlLimit(double cL) -{ - controlLimit = cL; - return S_OK; -} - -HRESULT CGenlock::GetControlLimit(double* cL) -{ - *cL = controlLimit; - return S_OK; -} - -HRESULT CGenlock::SetDisplayResolution(UINT columns, UINT lines) -{ - visibleColumns = columns; - visibleLines = lines; - return S_OK; -} - -HRESULT CGenlock::AdviseSyncClock(ISyncClock* sC) -{ - if (!sC) { - return E_FAIL; - } - if (syncClock) { - syncClock = nullptr; // Release any outstanding references if this is called repeatedly - } - syncClock = sC; - return S_OK; -} - -// Set the monitor to control. This is best done manually as not all monitors can be controlled -// so automatic detection of monitor to control might have unintended effects. -// The PowerStrip API uses zero-based monitor numbers, i.e. the default monitor is 0. -HRESULT CGenlock::SetMonitor(UINT mon) -{ - monitor = mon; - return S_OK; -} - -HRESULT CGenlock::ResetStats() -{ - CAutoLock lock(&csGenlockLock); - minSyncOffset = DBL_MAX; - maxSyncOffset = DBL_MIN; - minFrameCycle = DBL_MAX; - maxFrameCycle = DBL_MIN; - displayAdjustmentsMade = 0; - clockAdjustmentsMade = 0; - return S_OK; -} - -// Synchronize by adjusting display refresh rate -HRESULT CGenlock::ControlDisplay(double syncOffset, double frameCycle) -{ - LPARAM lParam = 0; - WPARAM wParam = monitor; - ATOM setTiming; - - const CRenderersSettings& r = GetRenderersSettings(); - targetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset; - lowSyncOffset = targetSyncOffset - r.m_AdvRendSets.fControlLimit; - highSyncOffset = targetSyncOffset + r.m_AdvRendSets.fControlLimit; - - syncOffsetAvg = syncOffsetFifo.Average(syncOffset); - minSyncOffset = std::min(minSyncOffset, syncOffset); - maxSyncOffset = std::max(maxSyncOffset, syncOffset); - frameCycleAvg = frameCycleFifo.Average(frameCycle); - minFrameCycle = std::min(minFrameCycle, frameCycle); - maxFrameCycle = std::max(maxFrameCycle, frameCycle); - - if (!PowerstripRunning() || !powerstripTimingExists) { - return E_FAIL; - } - // Adjust as seldom as possible by checking the current controlState before changing it. - if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1)) - // Speed up display refresh rate by subtracting pixels from the image. - { - adjDelta = 1; // Increase refresh rate - curDisplayFreq = displayFreqFaster; - setTiming = GlobalAddAtom(faster); - lParam = setTiming; - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); - GlobalDeleteAtom(setTiming); - displayAdjustmentsMade++; - } else - // Slow down display refresh rate by adding pixels to the image. - if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1)) { - adjDelta = -1; - curDisplayFreq = displayFreqSlower; - setTiming = GlobalAddAtom(slower); - lParam = setTiming; - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); - GlobalDeleteAtom(setTiming); - displayAdjustmentsMade++; - } else - // Cruise. - if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1)) { - adjDelta = 0; - curDisplayFreq = displayFreqCruise; - setTiming = GlobalAddAtom(cruise); - lParam = setTiming; - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); - GlobalDeleteAtom(setTiming); - displayAdjustmentsMade++; - } else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1)) { - adjDelta = 0; - curDisplayFreq = displayFreqCruise; - setTiming = GlobalAddAtom(cruise); - lParam = setTiming; - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); - GlobalDeleteAtom(setTiming); - displayAdjustmentsMade++; - } - return S_OK; -} - -// Synchronize by adjusting reference clock rate (and therefore video FPS). -// Todo: check so that we don't have a live source -HRESULT CGenlock::ControlClock(double syncOffset, double frameCycle) -{ - const CRenderersSettings& r = GetRenderersSettings(); - targetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset; - lowSyncOffset = targetSyncOffset - r.m_AdvRendSets.fControlLimit; - highSyncOffset = targetSyncOffset + r.m_AdvRendSets.fControlLimit; - - syncOffsetAvg = syncOffsetFifo.Average(syncOffset); - minSyncOffset = std::min(minSyncOffset, syncOffset); - maxSyncOffset = std::max(maxSyncOffset, syncOffset); - frameCycleAvg = frameCycleFifo.Average(frameCycle); - minFrameCycle = std::min(minFrameCycle, frameCycle); - maxFrameCycle = std::max(maxFrameCycle, frameCycle); - - if (!syncClock) { - return E_FAIL; - } - // Adjust as seldom as possible by checking the current controlState before changing it. - if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1)) - // Slow down video stream. - { - adjDelta = 1; - syncClock->AdjustClock(1.0 - cycleDelta); // Makes the clock move slower by providing smaller increments - clockAdjustmentsMade++; - } else - // Speed up video stream. - if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1)) { - adjDelta = -1; - syncClock->AdjustClock(1.0 + cycleDelta); - clockAdjustmentsMade++; - } else - // Cruise. - if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1)) { - adjDelta = 0; - syncClock->AdjustClock(1.0); - clockAdjustmentsMade++; - } else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1)) { - adjDelta = 0; - syncClock->AdjustClock(1.0); - clockAdjustmentsMade++; - } - return S_OK; -} - -// Don't adjust anything, just update the syncOffset stats -HRESULT CGenlock::UpdateStats(double syncOffset, double frameCycle) -{ - syncOffsetAvg = syncOffsetFifo.Average(syncOffset); - minSyncOffset = std::min(minSyncOffset, syncOffset); - maxSyncOffset = std::max(maxSyncOffset, syncOffset); - frameCycleAvg = frameCycleFifo.Average(frameCycle); - minFrameCycle = std::min(minFrameCycle, frameCycle); - maxFrameCycle = std::max(maxFrameCycle, frameCycle); - return S_OK; -} - -STDMETHODIMP CSyncAP::SetD3DFullscreen(bool fEnabled) -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_allocatorLock); - - fullScreenChanged = (fEnabled != m_bIsFullscreen); - m_bIsFullscreen = fEnabled; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetD3DFullscreen(bool* pfEnabled) -{ - CheckPointer(pfEnabled, E_POINTER); - *pfEnabled = m_bIsFullscreen; - return S_OK; -} +/* + * (C) 2010-2017 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 . + * + */ + +#include "stdafx.h" +#include "../SyncClock/Interfaces.h" +#include +#include +#include +#include "../../../mpc-hc/resource.h" +#include "../../../DSUtil/DSUtil.h" +#include "../../../DSUtil/WinAPIUtils.h" +#include // Required in CGenlock +#include +#include +#include "d3dx9/d3dx9.h" +#include +#include +#include +#include +#include "../../../SubPic/DX9SubPic.h" +#include "../../../SubPic/SubPicQueueImpl.h" +#include "moreuuids.h" +#include "MacrovisionKicker.h" +#include "IPinHook.h" +#include "PixelShaderCompiler.h" +#include "FocusThread.h" +#include "../../../DSUtil/vd.h" +#include + +#include +#include +#include "SyncRenderer.h" +#include "Utils.h" +#include "Variables.h" + +#if (0) // Set to 1 to activate SyncRenderer traces +#define TRACE_SR TRACE +#else +#define TRACE_SR __noop +#endif + + +#define REFERENCE_WIDTH 1920 +#define FONT_HEIGHT 21 +#define BOLD_THRESHOLD 11 +#define TEXT_PADDING 2 +#define GRAPH_HEIGHT 360 +#define GRAPH_WIDTH 1000 + +using namespace GothSync; + +extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); + +CBaseAP::CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) + : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) + , m_hDWMAPI(nullptr) + , m_pDwmIsCompositionEnabled(nullptr) + , m_pDwmEnableComposition(nullptr) + , m_pOuterEVR(nullptr) + , m_SurfaceType(D3DFMT_UNKNOWN) + , m_BackbufferType(D3DFMT_UNKNOWN) + , m_DisplayType(D3DFMT_UNKNOWN) + , m_filter(D3DTEXF_NONE) + , m_LastAdapterCheck(0) + , m_CurrentAdapter(UINT_ERROR) + , m_bicubicA(0) + , m_nTearingPos(0) + , m_VMR9AlphaBitmapWidthBytes() + , m_pD3DXLoadSurfaceFromMemory(nullptr) + , m_pD3DXLoadSurfaceFromSurface(nullptr) + , m_pD3DXCreateLine(nullptr) + , m_pD3DXCreateFont(nullptr) + , m_pD3DXCreateSprite(nullptr) + , m_nDXSurface(1) + , m_nVMR9Surfaces(0) + , m_iVMR9Surface(0) + , m_nCurSurface(0) + , m_nUsedBuffer(0) + , m_lNextSampleWait(1) + , m_bSnapToVSync(false) + , m_uScanLineEnteringPaint(0) + , m_llEstVBlankTime(0) + , m_fAvrFps(0.0) + , m_fJitterStdDev(0.0) + , m_fJitterMean(0) + , m_fSyncOffsetAvr(0.0) + , m_fSyncOffsetStdDev(0.0) + , m_bHighColorResolution(false) + , m_bCompositionEnabled(false) + , m_bDesktopCompositionDisabled(false) + , m_bIsFullscreen(bFullscreen) + , fullScreenChanged(false) + , m_bNeedCheckSample(true) + , m_dMainThreadId(0) + , m_ScreenSize(0, 0) + , m_dDetectedScanlineTime(0.0) + , m_dD3DRefreshCycle(0) + , m_dEstRefreshCycle(0.0) + , m_dFrameCycle(0.0) + , m_dOptimumDisplayCycle(0.0) + , m_dCycleDifference(1.0) + , m_pcFramesDropped(0) + , m_pcFramesDuplicated(0) + , m_pcFramesDrawn(0) + , m_nNextJitter(0) + , m_nNextSyncOffset(0) + , m_JitterStdDev(0) + , m_llLastSyncTime(LONGLONG_ERROR) + , m_MaxJitter(MINLONG64) + , m_MinJitter(MAXLONG64) + , m_MaxSyncOffset(MINLONG64) + , m_MinSyncOffset(MAXLONG64) + , m_uSyncGlitches(0) + , m_llSampleTime(0) + , m_llLastSampleTime(0) + , m_llHysteresis(0) + , m_lShiftToNearest(0) + , m_lShiftToNearestPrev(0) + , m_bVideoSlowerThanDisplay(0) + , m_rtTimePerFrame(0) + , m_bInterlaced(false) + , m_TextScale(1.0) + , m_pGenlock(nullptr) + , m_pAudioStats(nullptr) + , m_lAudioLag(0) + , m_lAudioLagMin(10000) + , m_lAudioLagMax(-10000) + , m_lAudioSlaveMode(0) + , m_FocusThread(nullptr) + , m_hFocusWindow(nullptr) +{ + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + ZeroMemory(&m_caps, sizeof(m_caps)); + ZeroMemory(&m_pp, sizeof(m_pp)); + + if (FAILED(hr)) { + _Error += _T("ISubPicAllocatorPresenterImpl failed\n"); + return; + } + + HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); + + if (hDll) { + (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory"); + (FARPROC&)m_pD3DXLoadSurfaceFromSurface = GetProcAddress(hDll, "D3DXLoadSurfaceFromSurface"); + (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine"); + (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW"); + (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite"); + } else { + _Error += _T("The installed DirectX End-User Runtime is outdated. Please download and install the "); + _Error += MPC_DX_SDK_MONTH _T(" ") MAKE_STR(MPC_DX_SDK_YEAR); + _Error += _T(" release or newer in order for MPC-HC to function properly.\n"); + } + + m_hDWMAPI = LoadLibrary(L"dwmapi.dll"); + if (m_hDWMAPI) { + (FARPROC&)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled"); + (FARPROC&)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition"); + } + + Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); + if (m_pD3DEx) { + m_pD3D = m_pD3DEx; + } + + const CRenderersSettings& r = GetRenderersSettings(); + if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { + m_bDesktopCompositionDisabled = true; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(0); + } + } else { + m_bDesktopCompositionDisabled = false; + } + + m_pGenlock = DEBUG_NEW CGenlock(r.m_AdvRendSets.fTargetSyncOffset, r.m_AdvRendSets.fControlLimit, r.m_AdvRendSets.iLineDelta, r.m_AdvRendSets.iColumnDelta, r.m_AdvRendSets.fCycleDelta, 0); // Must be done before CreateDXDevice + hr = CreateDXDevice(_Error); + ZeroMemory(m_pllJitter, sizeof(m_pllJitter)); + ZeroMemory(m_pllSyncOffset, sizeof(m_pllSyncOffset)); +} + +CBaseAP::~CBaseAP() +{ + if (m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = false; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(1); + } + } + + m_pFont = nullptr; + m_pLine = nullptr; + m_pSprite = nullptr; + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + m_pPSC.Free(); + m_pD3D = nullptr; + m_pD3DEx = nullptr; + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + + m_pAudioStats = nullptr; + SAFE_DELETE(m_pGenlock); + + if (m_FocusThread) { + m_FocusThread->PostThreadMessage(WM_QUIT, 0, 0); + if (WaitForSingleObject(m_FocusThread->m_hThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_FocusThread->m_hThread, 0xDEAD); + } + } + + if (m_hDWMAPI) { + FreeLibrary(m_hDWMAPI); + m_hDWMAPI = nullptr; + } +} + +template +void CBaseAP::AdjustQuad(MYD3DVERTEX* v, double dx, double dy) +{ + float offset = 0.5; + + for (int i = 0; i < 4; i++) { + v[i].x -= offset; + v[i].y -= offset; + + for (int j = 0; j < std::max(texcoords - 1, 1); j++) { + v[i].t[j].u -= (float)(offset * dx); + v[i].t[j].v -= (float)(offset * dy); + } + + if constexpr(texcoords > 1) { + v[i].t[texcoords - 1].u -= offset; + v[i].t[texcoords - 1].v -= offset; + } + } +} + +template +HRESULT CBaseAP::TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter = D3DTEXF_LINEAR) +{ + CheckPointer(pD3DDev, E_POINTER); + + DWORD FVF = 0; + switch (texcoords) { + case 1: + FVF = D3DFVF_TEX1; + break; + case 2: + FVF = D3DFVF_TEX2; + break; + case 3: + FVF = D3DFVF_TEX3; + break; + case 4: + FVF = D3DFVF_TEX4; + break; + case 5: + FVF = D3DFVF_TEX5; + break; + case 6: + FVF = D3DFVF_TEX6; + break; + case 7: + FVF = D3DFVF_TEX7; + break; + case 8: + FVF = D3DFVF_TEX8; + break; + default: + return E_FAIL; + } + + HRESULT hr; + hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + + for (int i = 0; i < texcoords; i++) { + hr = pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); + hr = pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter); + hr = pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF); + + MYD3DVERTEX tmp = v[2]; + v[2] = v[3]; + v[3] = tmp; + hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); + + for (int i = 0; i < texcoords; i++) { + pD3DDev->SetTexture(i, nullptr); + } + + return S_OK; +} + +HRESULT CBaseAP::DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]) +{ + CheckPointer(pD3DDev, E_POINTER); + + HRESULT hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + hr = pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + + hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE); + + MYD3DVERTEX<0> tmp = v[2]; + v[2] = v[3]; + v[3] = tmp; + hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); + + return S_OK; +} + +MFOffset CBaseAP::GetOffset(float v) +{ + MFOffset offset; + offset.value = short(v); + offset.fract = WORD(65536 * (v - offset.value)); + return offset; +} + +MFVideoArea CBaseAP::GetArea(float x, float y, DWORD width, DWORD height) +{ + MFVideoArea area; + area.OffsetX = GetOffset(x); + area.OffsetY = GetOffset(y); + area.Area.cx = width; + area.Area.cy = height; + return area; +} + +void CBaseAP::ResetStats() +{ + m_pGenlock->ResetStats(); + m_lAudioLag = 0; + m_lAudioLagMin = 10000; + m_lAudioLagMax = -10000; + m_MinJitter = MAXLONG64; + m_MaxJitter = MINLONG64; + m_MinSyncOffset = MAXLONG64; + m_MaxSyncOffset = MINLONG64; + m_uSyncGlitches = 0; + m_pcFramesDropped = 0; + m_llLastSyncTime = LONGLONG_ERROR; +} + +bool CBaseAP::SettingsNeedResetDevice() +{ + CRenderersSettings& r = GetRenderersSettings(); + CRenderersSettings::CAdvRendererSettings& New = r.m_AdvRendSets; + CRenderersSettings::CAdvRendererSettings& Current = m_LastRendererSettings; + + bool bRet = false; + if (!m_bIsFullscreen) { + if (Current.bVMRDisableDesktopComposition) { + if (!m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = true; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(0); + } + } + } else { + if (m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = false; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(1); + } + } + } + } + bRet = bRet || New.bEVRHighColorResolution != Current.bEVRHighColorResolution; + m_LastRendererSettings = r.m_AdvRendSets; + return bRet; +} + +HRESULT CBaseAP::CreateDXDevice(CString& _Error) +{ + TRACE(_T("--> CBaseAP::CreateDXDevice on thread: %lu\n"), GetCurrentThreadId()); + const CRenderersSettings& r = GetRenderersSettings(); + m_LastRendererSettings = r.m_AdvRendSets; + HRESULT hr = E_FAIL; + + m_pFont = nullptr; + m_pSprite = nullptr; + m_pLine = nullptr; + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + + m_pPSC.Free(); + + m_pResizerPixelShader[0] = 0; + m_pResizerPixelShader[1] = 0; + m_pResizerPixelShader[2] = 0; + m_pResizerPixelShader[3] = 0; + + POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + pos = m_pPixelShaders.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + + UINT currentAdapter = GetAdapter(m_pD3D, m_hWnd); + bool bTryToReset = (currentAdapter == m_CurrentAdapter); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + m_CurrentAdapter = currentAdapter; + } + + if (!m_pD3D) { + _Error += L"Failed to create Direct3D device\n"; + return E_UNEXPECTED; + } + + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + if (FAILED(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)) + || d3ddm.Width <= 0 || d3ddm.Height <= 0) { + _Error += L"Can not retrieve display mode data\n"; + return E_UNEXPECTED; + } + + if (FAILED(m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &m_caps))) { + if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0) { + _Error += L"Video card does not have scanline access. Display synchronization is not possible.\n"; + return E_UNEXPECTED; + } + } + + m_refreshRate = d3ddm.RefreshRate; + m_dD3DRefreshCycle = 1000.0 / m_refreshRate; // In ms + m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); + m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height); + + BOOL bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + m_bCompositionEnabled = bCompositionEnabled != 0; + + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + + ZeroMemory(&m_pp, sizeof(m_pp)); + if (m_bIsFullscreen) { // Exclusive mode fullscreen + m_pp.Windowed = FALSE; + m_pp.BackBufferWidth = d3ddm.Width; + m_pp.BackBufferHeight = d3ddm.Height; + m_pp.hDeviceWindow = m_hWnd; + TRACE(_T("Wnd in CreateDXDevice: %p\n"), m_hWnd); + m_pp.BackBufferCount = 3; + m_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + m_pp.Flags = D3DPRESENTFLAG_VIDEO; + m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; + if (m_bHighColorResolution) { + if (FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false))) { + m_strStatsMsg[MSG_ERROR] = L"10 bit RGB is not supported by this graphics device in this resolution."; + m_bHighColorResolution = false; + } + } + + if (m_bHighColorResolution) { + m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } else { + m_pp.BackBufferFormat = d3ddm.Format; + } + + if (!m_FocusThread) { + m_FocusThread = (CFocusThread*)AfxBeginThread(RUNTIME_CLASS(CFocusThread), 0, 0, 0); + } + + HWND hFocusWindow = m_FocusThread->GetFocusWindow(); + bTryToReset &= (m_hFocusWindow == hFocusWindow || fullScreenChanged); + m_hFocusWindow = hFocusWindow; + + if (m_pD3DEx) { + D3DDISPLAYMODEEX DisplayMode; + ZeroMemory(&DisplayMode, sizeof(DisplayMode)); + DisplayMode.Size = sizeof(DisplayMode); + m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); + + DisplayMode.Format = m_pp.BackBufferFormat; + m_pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate; + + bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&m_pp, &DisplayMode)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + hr = m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS | D3DCREATE_NOWINDOWCHANGES, + &m_pp, &DisplayMode, &m_pD3DDevEx); + } + + if (m_pD3DDevEx) { + m_pD3DDev = m_pD3DDevEx; + m_BackbufferType = m_pp.BackBufferFormat; + m_DisplayType = DisplayMode.Format; + } + } else { + bTryToReset = bTryToReset && m_pD3DDev && SUCCEEDED(hr = m_pD3DDev->Reset(&m_pp)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + hr = m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_NOWINDOWCHANGES, + &m_pp, &m_pD3DDev); + } + TRACE(_T("Created full-screen device\n")); + if (m_pD3DDev) { + m_BackbufferType = m_pp.BackBufferFormat; + m_DisplayType = d3ddm.Format; + } + } + } else { // Windowed + m_pp.Windowed = TRUE; + m_pp.hDeviceWindow = m_hWnd; + m_pp.SwapEffect = D3DSWAPEFFECT_COPY; + m_pp.Flags = D3DPRESENTFLAG_VIDEO; + m_pp.BackBufferCount = 1; + CSize bbsize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); + m_pp.BackBufferWidth = bbsize.cx; + m_pp.BackBufferHeight = bbsize.cy; + m_BackbufferType = d3ddm.Format; + m_DisplayType = d3ddm.Format; + m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; + if (m_bHighColorResolution) { + if (FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false))) { + m_strStatsMsg[MSG_ERROR] = L"10 bit RGB is not supported by this graphics device in this resolution."; + m_bHighColorResolution = false; + } + } + + if (m_bHighColorResolution) { + m_BackbufferType = D3DFMT_A2R10G10B10; + m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } + if (bCompositionEnabled) { + // Desktop composition presents the whole desktop + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } else { + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + } + + bTryToReset &= (m_hFocusWindow == m_hWnd || fullScreenChanged); + m_hFocusWindow = m_hWnd; + + if (m_pD3DEx) { + bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&m_pp, nullptr)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + hr = m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS, + &m_pp, nullptr, &m_pD3DDevEx); + } + + if (m_pD3DDevEx) { + m_pD3DDev = m_pD3DDevEx; + } + } else { + if (bTryToReset) { + if (!m_pD3DDev || FAILED(hr = m_pD3DDev->Reset(&m_pp))) { + bTryToReset = false; + } + } + if (!bTryToReset) { + hr = m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED, + &m_pp, &m_pD3DDev); + } + TRACE(_T("Created windowed device\n")); + } + } + + if (m_pD3DDev) { + while (hr == D3DERR_DEVICELOST) { + TRACE(_T("D3DERR_DEVICELOST. Trying to Reset.\n")); + hr = m_pD3DDev->TestCooperativeLevel(); + } + if (hr == D3DERR_DEVICENOTRESET) { + TRACE(_T("D3DERR_DEVICENOTRESET\n")); + hr = m_pD3DDev->Reset(&m_pp); + } + + if (m_pD3DDevEx) { + m_pD3DDevEx->SetGPUThreadPriority(7); + } + } + + if (FAILED(hr)) { + _Error.AppendFormat(_T("CreateDevice failed: %s\n"), GetWindowsErrorMessage(hr, nullptr).GetString()); + + return hr; + } + + m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); + m_filter = D3DTEXF_NONE; + + if (m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR && m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR) { + m_filter = D3DTEXF_LINEAR; + } + + m_bicubicA = 0; + + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(m_pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); + } + + hr = S_OK; + + CComPtr pSubPicProvider; + if (m_pSubPicQueue) { + TRACE(_T("m_pSubPicQueue != nullptr\n")); + m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); + } + + if (!m_pSubPicQueue) { + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + m_pSubPicQueue->Invalidate(); + } + + if (FAILED(hr)) { + _Error += L"m_pSubPicQueue failed\n"; + return hr; + } + + if (pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); + } + + m_LastAdapterCheck = GetRenderersData()->GetPerfCounter(); + return S_OK; +} + +HRESULT CBaseAP::ResetDXDevice(CString& _Error) +{ + const CRenderersSettings& r = GetRenderersSettings(); + m_LastRendererSettings = r.m_AdvRendSets; + HRESULT hr = E_FAIL; + + hr = m_pD3DDev->TestCooperativeLevel(); + if ((hr != D3DERR_DEVICENOTRESET) && (hr != D3D_OK)) { + return hr; + } + + CComPtr rendererInputEnum; + std::vector> decoderOutput; + std::vector> rendererInput; + CFilterInfo filterInfo; + + bool disconnected = false; + + // Disconnect all pins to release video memory resources + if (m_pD3DDev) { + m_pOuterEVR->QueryFilterInfo(&filterInfo); + if (SUCCEEDED(m_pOuterEVR->EnumPins(&rendererInputEnum))) { + CComPtr input; + CComPtr output; + while (hr = rendererInputEnum->Next(1, &input.p, 0), hr == S_OK) { // Must have .p here + TRACE(_T("Pin found\n")); + input->ConnectedTo(&output.p); + if (output != nullptr) { + rendererInput.push_back(input); + decoderOutput.push_back(output); + } + input.Release(); + output.Release(); + } + } else { + return hr; + } + if (filterInfo.pGraph) { + for (size_t i = 0; i < decoderOutput.size(); i++) { + TRACE(_T("Disconnecting pin\n")); + filterInfo.pGraph->Disconnect(decoderOutput[i].p); + filterInfo.pGraph->Disconnect(rendererInput[i].p); + TRACE(_T("Pin disconnected\n")); + } + disconnected = true; + } + } + + // Release more resources + m_pSubPicQueue = nullptr; + m_pFont = nullptr; + m_pSprite = nullptr; + m_pLine = nullptr; + m_pPSC.Free(); + + m_pResizerPixelShader[0] = 0; + m_pResizerPixelShader[1] = 0; + m_pResizerPixelShader[2] = 0; + m_pResizerPixelShader[3] = 0; + + POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + pos = m_pPixelShaders.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + if (FAILED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D, m_hWnd), &d3ddm)) + || d3ddm.Width <= 0 || d3ddm.Height <= 0) { + _Error += L"Can not retrieve display mode data\n"; + return E_UNEXPECTED; + } + + m_refreshRate = d3ddm.RefreshRate; + m_dD3DRefreshCycle = 1000.0 / m_refreshRate; // In ms + m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); + m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height); + CSize szDesktopSize(GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)); + + ZeroMemory(&m_pp, sizeof(m_pp)); + + BOOL bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + m_bCompositionEnabled = bCompositionEnabled != 0; + m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; + + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + + if (m_bIsFullscreen) { // Exclusive mode fullscreen + m_pp.BackBufferWidth = d3ddm.Width; + m_pp.BackBufferHeight = d3ddm.Height; + if (m_bHighColorResolution) { + m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } else { + m_pp.BackBufferFormat = d3ddm.Format; + } + if (FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_pp.BackBufferFormat, m_pp.BackBufferFormat, false))) { + _Error += L"10 bit RGB is not supported by this graphics device in exclusive mode fullscreen.\n"; + return hr; + } + + D3DDISPLAYMODEEX DisplayMode; + ZeroMemory(&DisplayMode, sizeof(DisplayMode)); + DisplayMode.Size = sizeof(DisplayMode); + if (m_pD3DDevEx) { + m_pD3DEx->GetAdapterDisplayModeEx(GetAdapter(m_pD3DEx, m_hWnd), &DisplayMode, nullptr); + DisplayMode.Format = m_pp.BackBufferFormat; + m_pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate; + if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { + _Error += GetWindowsErrorMessage(hr, nullptr); + return hr; + } + } else if (m_pD3DDev) { + if (FAILED(m_pD3DDev->Reset(&m_pp))) { + _Error += GetWindowsErrorMessage(hr, nullptr); + return hr; + } + } else { + _Error += L"No device.\n"; + return hr; + } + m_BackbufferType = m_pp.BackBufferFormat; + m_DisplayType = d3ddm.Format; + } else { // Windowed + CSize bbsize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); + m_pp.BackBufferWidth = bbsize.cx; + m_pp.BackBufferHeight = bbsize.cy; + m_BackbufferType = d3ddm.Format; + m_DisplayType = d3ddm.Format; + if (m_bHighColorResolution) { + m_BackbufferType = D3DFMT_A2R10G10B10; + m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } + if (FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_pp.BackBufferFormat, m_pp.BackBufferFormat, false))) { + _Error += L"10 bit RGB is not supported by this graphics device in windowed mode.\n"; + return hr; + } + if (bCompositionEnabled) { + // Desktop composition presents the whole desktop + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } else { + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + } + if (m_pD3DDevEx) + if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { + _Error += GetWindowsErrorMessage(hr, nullptr); + return hr; + } else if (m_pD3DDev) + if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { + _Error += GetWindowsErrorMessage(hr, nullptr); + return hr; + } else { + _Error += L"No device.\n"; + return hr; + } + } + + if (disconnected) { + for (size_t i = 0; i < decoderOutput.size(); i++) { + if (FAILED(filterInfo.pGraph->ConnectDirect(decoderOutput[i].p, rendererInput[i].p, nullptr))) { + return hr; + } + } + } + + m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); + m_filter = D3DTEXF_NONE; + + if ((m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) + && (m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)) { + m_filter = D3DTEXF_LINEAR; + } + + m_bicubicA = 0; + + CComPtr pSubPicProvider; + if (m_pSubPicQueue) { + m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); + } + + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(m_pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); + } + + hr = S_OK; + if (!m_pSubPicQueue) { + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + m_pSubPicQueue->Invalidate(); + } + + if (FAILED(hr)) { + _Error += L"m_pSubPicQueue failed\n"; + + return hr; + } + + if (pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); + } + + m_pFont = nullptr; + m_pSprite = nullptr; + m_pLine = nullptr; + + return S_OK; +} + +HRESULT CBaseAP::AllocSurfaces(D3DFORMAT Format) +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_allocatorLock); + + CheckPointer(m_pD3DDev, E_POINTER); + + const CRenderersSettings& r = GetRenderersSettings(); + + for (int i = 0; i < m_nDXSurface + 2; i++) { + m_pVideoTexture[i] = nullptr; + m_pVideoSurface[i] = nullptr; + } + + m_pScreenSizeTemporaryTexture[0] = nullptr; + m_pScreenSizeTemporaryTexture[1] = nullptr; + m_SurfaceType = Format; + + HRESULT hr; + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { + int nTexturesNeeded = r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nDXSurface + 2 : 1; + + for (int i = 0; i < nTexturesNeeded; i++) { + if (FAILED(hr = m_pD3DDev->CreateTexture( + m_nativeVideoSize.cx, + m_nativeVideoSize.cy, + 1, + D3DUSAGE_RENDERTARGET, + Format, + D3DPOOL_DEFAULT, + &m_pVideoTexture[i], + nullptr))) { + return hr; + } + + if (FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i]))) { + return hr; + } + } + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D) { + for (int i = 0; i < m_nDXSurface + 2; i++) { + m_pVideoTexture[i] = nullptr; + } + } + } else { + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(m_nativeVideoSize.cx, m_nativeVideoSize.cy, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], nullptr))) { + return hr; + } + } + + hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], nullptr, 0); + return S_OK; +} + +void CBaseAP::DeleteSurfaces() +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_allocatorLock); + + for (int i = 0; i < m_nDXSurface + 2; i++) { + m_pVideoTexture[i] = nullptr; + m_pVideoSurface[i] = nullptr; + } +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP CBaseAP::CreateRenderer(IUnknown** ppRenderer) +{ + return E_NOTIMPL; +} + +bool CBaseAP::ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pSurface->GetDesc(&desc))) { + return false; + } + + int w = desc.Width, h = desc.Height; + int sw = s.Width(), sh = s.Height(); + int dw = d.Width(), dh = d.Height(); + + if (d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0 + || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) { + s.SetRectEmpty(); + d.SetRectEmpty(); + return true; + } + if (d.right > w) { + s.right -= (d.right - w) * sw / dw; + d.right = w; + } + if (d.bottom > h) { + s.bottom -= (d.bottom - h) * sh / dh; + d.bottom = h; + } + if (d.left < 0) { + s.left += (0 - d.left) * sw / dw; + d.left = 0; + } + if (d.top < 0) { + s.top += (0 - d.top) * sh / dh; + d.top = 0; + } + return true; +} + +HRESULT CBaseAP::InitResizers(float bicubicA, bool bNeedScreenSizeTexture) +{ + HRESULT hr; + do { + if (bicubicA) { + if (!m_pResizerPixelShader[0]) { + break; + } + if (!m_pResizerPixelShader[1]) { + break; + } + if (!m_pResizerPixelShader[2]) { + break; + } + if (!m_pResizerPixelShader[3]) { + break; + } + if (m_bicubicA != bicubicA) { + break; + } + if (!m_pScreenSizeTemporaryTexture[0]) { + break; + } + if (bNeedScreenSizeTexture) { + if (!m_pScreenSizeTemporaryTexture[1]) { + break; + } + } + } else { + if (!m_pResizerPixelShader[0]) { + break; + } + if (bNeedScreenSizeTexture) { + if (!m_pScreenSizeTemporaryTexture[0]) { + break; + } + if (!m_pScreenSizeTemporaryTexture[1]) { + break; + } + } + } + return S_OK; + } while (0); + + m_bicubicA = bicubicA; + m_pScreenSizeTemporaryTexture[0] = nullptr; + m_pScreenSizeTemporaryTexture[1] = nullptr; + + for (int i = 0; i < _countof(m_pResizerPixelShader); i++) { + m_pResizerPixelShader[i] = nullptr; + } + + if (m_caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { + return E_FAIL; + } + + LPCSTR pProfile = m_caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; + + CStringA str; + if (!LoadResource(IDF_SHADER_RESIZER, str, _T("SHADER"))) { + return E_FAIL; + } + + CStringA A; + A.Format("(%f)", bicubicA); + str.Replace("_The_Value_Of_A_Is_Set_Here_", A); + + LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass_pass1", "main_bicubic2pass_pass2"}; + + ASSERT(_countof(pEntries) == _countof(m_pResizerPixelShader)); + for (int i = 0; i < _countof(pEntries); i++) { + CString ErrorMessage; + CString DissAssembly; + hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShader[i], &DissAssembly, &ErrorMessage); + if (FAILED(hr)) { + TRACE(_T("%ws"), ErrorMessage.GetString()); + ASSERT(0); + return hr; + } + } + if (m_bicubicA || bNeedScreenSizeTexture) { + if (FAILED(m_pD3DDev->CreateTexture( + std::min((DWORD)m_ScreenSize.cx, m_caps.MaxTextureWidth), + std::min((DWORD)std::max(m_ScreenSize.cy, m_nativeVideoSize.cy), m_caps.MaxTextureHeight), + 1, + D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + &m_pScreenSizeTemporaryTexture[0], + nullptr))) { + ASSERT(0); + m_pScreenSizeTemporaryTexture[0] = nullptr; // will do 1 pass then + } + + if (FAILED(m_pD3DDev->CreateTexture( + std::min((DWORD)m_ScreenSize.cx, m_caps.MaxTextureWidth), + std::min((DWORD)std::max(m_ScreenSize.cy, m_nativeVideoSize.cy), m_caps.MaxTextureHeight), + 1, + D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + &m_pScreenSizeTemporaryTexture[1], + nullptr))) { + ASSERT(0); + m_pScreenSizeTemporaryTexture[1] = nullptr; // will do 1 pass then + } + } + return S_OK; +} + +HRESULT CBaseAP::TextureCopy(IDirect3DTexture9* pTexture) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + MYD3DVERTEX<1> v[] = { + {0, 0, 0.5f, 2.0f, 0, 0}, + {w, 0, 0.5f, 2.0f, 1, 0}, + {0, h, 0.5f, 2.0f, 0, 1}, + {w, h, 0.5f, 2.0f, 1, 1}, + }; + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + hr = m_pD3DDev->SetTexture(0, pTexture); + return TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); +} + +HRESULT CBaseAP::DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect) +{ + DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color)); + MYD3DVERTEX<0> v[] = { + {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color}, + {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color}, + {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color}, + {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color}, + }; + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + return DrawRectBase(m_pD3DDev, v); +} + +HRESULT CBaseAP::TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& SrcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + float dx2 = 1.0f / w; + float dy2 = 1.0f / h; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, SrcRect.left * dx2, SrcRect.top * dy2}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, SrcRect.right * dx2, SrcRect.top * dy2}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, SrcRect.left * dx2, SrcRect.bottom * dy2}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, SrcRect.right * dx2, SrcRect.bottom * dy2}, + }; + AdjustQuad(v, 0, 0); + hr = m_pD3DDev->SetTexture(0, pTexture); + hr = m_pD3DDev->SetPixelShader(nullptr); + hr = TextureBlt(m_pD3DDev, v, filter); + return hr; +} + +HRESULT CBaseAP::TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + float tx0 = (float)SrcRect.left; + float tx1 = (float)SrcRect.right; + float ty0 = (float)SrcRect.top; + float ty1 = (float)SrcRect.bottom; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, + }; + AdjustQuad(v, 1.0, 1.0); + float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + hr = m_pD3DDev->SetTexture(0, pTexture); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[0]); + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + m_pD3DDev->SetPixelShader(nullptr); + return hr; +} + +HRESULT CBaseAP::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + float tx0 = (float)SrcRect.left; + float tx1 = (float)SrcRect.right; + float ty0 = (float)SrcRect.top; + float ty1 = (float)SrcRect.bottom; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, + }; + AdjustQuad(v, 1.0, 1.0); + hr = m_pD3DDev->SetTexture(0, pTexture); + float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[1]); + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + m_pD3DDev->SetPixelShader(nullptr); + return hr; +} + +HRESULT CBaseAP::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) +{ + // The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction. + return TextureResizeBicubic1pass(pTexture, dst, SrcRect); + + /*HRESULT hr; + + // rotated? + if (dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z + || dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x) + return TextureResizeBicubic1pass(pTexture, dst, SrcRect); + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) + return E_FAIL; + + float Tex0_Width = desc.Width; + float Tex0_Height = desc.Height; + + CSize SrcTextSize = CSize(desc.Width, desc.Height); + double w = (double)SrcRect.Width(); + double h = (double)SrcRect.Height(); + UNREFERENCED_PARAMETER(w); + + CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h); + + if (!m_pScreenSizeTemporaryTexture[0] || FAILED(m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc))) + return TextureResizeBicubic1pass(pTexture, dst, SrcRect); + + float Tex1_Width = desc.Width; + float Tex1_Height = desc.Height; + + float tx0 = SrcRect.left; + float tx1 = SrcRect.right; + float ty0 = SrcRect.top; + float ty1 = SrcRect.bottom; + + float tx0_2 = 0; + float tx1_2 = dst1.Width(); + float ty0_2 = 0; + float ty1_2 = h; + + if (dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height) + return TextureResizeBicubic1pass(pTexture, dst, SrcRect); + + MYD3DVERTEX<1> vx[] = + { + {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0}, + {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0}, + {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1}, + {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1}, + }; + AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug here, create vertical lines ! TODO : why ?????? + MYD3DVERTEX<1> vy[] = + { + {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2}, + {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2}, + {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2}, + {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2}, + }; + AdjustQuad(vy, 0.0, 1.0); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[2]); + { + float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + } + hr = m_pD3DDev->SetTexture(0, pTexture); + CComPtr pRTOld; + hr = m_pD3DDev->GetRenderTarget(0, &pRTOld); + CComPtr pRT; + hr = m_pScreenSizeTemporaryTexture[0]->GetSurfaceLevel(0, &pRT); + hr = m_pD3DDev->SetRenderTarget(0, pRT); + hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[3]); + { + float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + } + hr = m_pD3DDev->SetTexture(0, m_pScreenSizeTemporaryTexture[0]); + hr = m_pD3DDev->SetRenderTarget(0, pRTOld); + hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT); + m_pD3DDev->SetPixelShader(nullptr); + return hr;*/ +} + +HRESULT CBaseAP::AlphaBlt(RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture) +{ + if (!pSrc || !pDst) { + return E_POINTER; + } + + CRect src(*pSrc), dst(*pDst); + + HRESULT hr; + + do { + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { + break; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile + // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly + // initialized and thus the subtitles weren't shown. + struct { + float x, y, z, rhw; + float tu, tv; + } pVertices[] = { + {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, + {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, + {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, + {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, + }; + + for (size_t i = 0; i < _countof(pVertices); i++) { + pVertices[i].x -= 0.5f; + pVertices[i].y -= 0.5f; + } + + hr = m_pD3DDev->SetTexture(0, pTexture); + + // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE + // so we need to provide default values in case GetRenderState fails + DWORD abe, sb, db; + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { + abe = FALSE; + } + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { + sb = D3DBLEND_ONE; + } + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { + db = D3DBLEND_ZERO; + } + + hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst + + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + hr = m_pD3DDev->SetPixelShader(nullptr); + + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + + m_pD3DDev->SetTexture(0, nullptr); + + m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); + m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); + m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); + + return S_OK; + } while (0); + return E_FAIL; +} + +// Update the array m_pllJitter with a new vsync period. Calculate min, max and stddev. +void CBaseAP::SyncStats(LONGLONG syncTime) +{ + if (m_llLastSyncTime == LONGLONG_ERROR) { + m_llLastSyncTime = syncTime; + } + + m_nNextJitter = (m_nNextJitter + 1) % NB_JITTER; + LONGLONG jitter = syncTime - m_llLastSyncTime; + m_pllJitter[m_nNextJitter] = jitter; + double syncDeviation = (m_pllJitter[m_nNextJitter] - m_fJitterMean) / 10000.0; + if (abs(syncDeviation) > (GetDisplayCycle() / 2)) { + m_uSyncGlitches++; + } + + LONGLONG llJitterSum = 0; + LONGLONG llJitterSumAvg = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG Jitter = m_pllJitter[i]; + llJitterSum += Jitter; + llJitterSumAvg += Jitter; + } + m_fJitterMean = double(llJitterSumAvg) / NB_JITTER; + double DeviationSum = 0; + + for (int i = 0; i < NB_JITTER; i++) { + double deviation = m_pllJitter[i] - m_fJitterMean; + DeviationSum += deviation * deviation; + LONGLONG deviationInt = std::llround(deviation); + m_MaxJitter = std::max(m_MaxJitter, deviationInt); + m_MinJitter = std::min(m_MinJitter, deviationInt); + } + + m_fJitterStdDev = sqrt(DeviationSum / NB_JITTER); + m_fAvrFps = 10000000.0 / (double(llJitterSum) / NB_JITTER); + m_llLastSyncTime = syncTime; +} + +// Collect the difference between periodEnd and periodStart in an array, calculate mean and stddev. +void CBaseAP::SyncOffsetStats(LONGLONG syncOffset) +{ + m_nNextSyncOffset = (m_nNextSyncOffset + 1) % NB_JITTER; + m_pllSyncOffset[m_nNextSyncOffset] = syncOffset; + + LONGLONG AvrageSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG Offset = m_pllSyncOffset[i]; + AvrageSum += Offset; + m_MaxSyncOffset = std::max(m_MaxSyncOffset, Offset); + m_MinSyncOffset = std::min(m_MinSyncOffset, Offset); + } + double MeanOffset = double(AvrageSum) / NB_JITTER; + double DeviationSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + double Deviation = double(m_pllSyncOffset[i]) - MeanOffset; + DeviationSum += Deviation * Deviation; + } + double StdDev = sqrt(DeviationSum / NB_JITTER); + + m_fSyncOffsetAvr = MeanOffset; + m_fSyncOffsetStdDev = StdDev; +} + +void CBaseAP::UpdateAlphaBitmap() +{ + m_VMR9AlphaBitmapData.Free(); + + if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0) { + HBITMAP hBitmap = (HBITMAP)GetCurrentObject(m_VMR9AlphaBitmap.hdc, OBJ_BITMAP); + if (!hBitmap) { + return; + } + DIBSECTION info; + ZeroMemory(&info, sizeof(DIBSECTION)); + if (!::GetObject(hBitmap, sizeof(DIBSECTION), &info)) { + return; + } + + m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight); + m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes; + + if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight)) { + memcpy((BYTE*)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight); + } + } +} + +// Present a sample (frame) using DirectX. +STDMETHODIMP_(bool) CBaseAP::Paint(bool bAll) +{ + if (m_bPendingResetDevice) { + SendResetRequest(); + return false; + } + + const CRenderersSettings& r = GetRenderersSettings(); + CRenderersData* rd = GetRenderersData(); + D3DRASTER_STATUS rasterStatus; + REFERENCE_TIME llCurRefTime = 0; + REFERENCE_TIME llSyncOffset = 0; + double dSyncOffset = 0.0; + + CAutoLock cRenderLock(&m_allocatorLock); + + // Estimate time for next vblank based on number of remaining lines in this frame. This algorithm seems to be + // accurate within one ms why there should not be any need for a more accurate one. The wiggly line seen + // when using sync to nearest and sync display is most likely due to inaccuracies in the audio-card-based + // reference clock. The wiggles are not seen with the perfcounter-based reference clock of the sync to video option. + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + m_uScanLineEnteringPaint = rasterStatus.ScanLine; + if (m_pRefClock) { + m_pRefClock->GetTime(&llCurRefTime); + } + int dScanLines = std::max(int(m_ScreenSize.cy - m_uScanLineEnteringPaint), 0); + dSyncOffset = dScanLines * m_dDetectedScanlineTime; // ms + llSyncOffset = REFERENCE_TIME(10000.0 * dSyncOffset); // Reference time units (100 ns) + m_llEstVBlankTime = llCurRefTime + llSyncOffset; // Estimated time for the start of next vblank + + if (m_windowRect.right <= m_windowRect.left || m_windowRect.bottom <= m_windowRect.top + || m_nativeVideoSize.cx <= 0 || m_nativeVideoSize.cy <= 0 + || !m_pVideoSurface[m_nCurSurface]) { + return false; + } + + HRESULT hr; + CRect rSrcVid(CPoint(0, 0), m_nativeVideoSize); + CRect rDstVid(m_videoRect); + CRect rSrcPri(CPoint(0, 0), m_windowRect.Size()); + CRect rDstPri(rSrcPri); + + m_pD3DDev->BeginScene(); + CComPtr pBackBuffer; + m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); + m_pD3DDev->SetRenderTarget(0, pBackBuffer); + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); + if (!rDstVid.IsRectEmpty()) { + if (m_pVideoTexture[m_nCurSurface]) { + CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; + + if (m_pVideoTexture[m_nDXSurface] && m_pVideoTexture[m_nDXSurface + 1] && !m_pPixelShaders.IsEmpty()) { + static __int64 counter = 0; + static long start = clock(); + + long stop = clock(); + long diff = stop - start; + + if (diff >= 10 * 60 * CLOCKS_PER_SEC) { + start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) + } + + int src = m_nCurSurface, dst = m_nDXSurface; + + D3DSURFACE_DESC desc; + m_pVideoTexture[src]->GetLevelDesc(0, &desc); + + float fConstData[][4] = { + {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, + }; + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + CComPtr pRT; + hr = m_pD3DDev->GetRenderTarget(0, &pRT); + + POSITION pos = m_pPixelShaders.GetHeadPosition(); + while (pos) { + pVideoTexture = m_pVideoTexture[dst]; + + hr = m_pD3DDev->SetRenderTarget(0, m_pVideoSurface[dst]); + CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); + if (!Shader.m_pPixelShader) { + Shader.Compile(m_pPSC); + } + hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + TextureCopy(m_pVideoTexture[src]); + + src = dst; + if (++dst >= m_nDXSurface + 2) { + dst = m_nDXSurface; + } + } + + hr = m_pD3DDev->SetRenderTarget(0, pRT); + hr = m_pD3DDev->SetPixelShader(nullptr); + } + + Vector dst[4]; + Transform(rDstVid, dst); + + DWORD iDX9Resizer = r.iDX9Resizer; + + float A = 0; + + switch (iDX9Resizer) { + case 3: + A = -0.60f; + break; + case 4: + A = -0.751f; + break; // FIXME : 0.75 crash recent D3D, or eat CPU + case 5: + A = -1.00f; + break; + } + bool bScreenSpacePixelShaders = !m_pPixelShadersScreenSpace.IsEmpty(); + + hr = InitResizers(A, bScreenSpacePixelShaders); + + if (!m_pScreenSizeTemporaryTexture[0] || !m_pScreenSizeTemporaryTexture[1]) { + bScreenSpacePixelShaders = false; + } + + if (bScreenSpacePixelShaders) { + CComPtr pRT; + hr = m_pScreenSizeTemporaryTexture[1]->GetSurfaceLevel(0, &pRT); + if (hr != S_OK) { + bScreenSpacePixelShaders = false; + } + if (bScreenSpacePixelShaders) { + hr = m_pD3DDev->SetRenderTarget(0, pRT); + if (hr != S_OK) { + bScreenSpacePixelShaders = false; + } + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); + } + } + + if (rSrcVid.Size() != rDstVid.Size()) { + if (iDX9Resizer == 0 || iDX9Resizer == 1) { + D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; + hr = TextureResize(pVideoTexture, dst, Filter, rSrcVid); + } else if (iDX9Resizer == 2) { + hr = TextureResizeBilinear(pVideoTexture, dst, rSrcVid); + } else if (iDX9Resizer >= 3) { + hr = TextureResizeBicubic2pass(pVideoTexture, dst, rSrcVid); + } + } else { + hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, rSrcVid); + } + + if (bScreenSpacePixelShaders) { + static __int64 counter = 555; + static long start = clock() + 333; + + long stop = clock() + 333; + long diff = stop - start; + + if (diff >= 10 * 60 * CLOCKS_PER_SEC) { + start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) + } + + D3DSURFACE_DESC desc; + m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc); + + float fConstData[][4] = { + {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, + }; + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + int srcTexture = 1, dstTexture = 0; + + POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); + while (pos) { + if (m_pPixelShadersScreenSpace.GetTailPosition() == pos) { + m_pD3DDev->SetRenderTarget(0, pBackBuffer); + } else { + CComPtr pRT; + hr = m_pScreenSizeTemporaryTexture[dstTexture]->GetSurfaceLevel(0, &pRT); + m_pD3DDev->SetRenderTarget(0, pRT); + } + + CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); + if (!Shader.m_pPixelShader) { + Shader.Compile(m_pPSC); + } + hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + TextureCopy(m_pScreenSizeTemporaryTexture[srcTexture]); + + std::swap(srcTexture, dstTexture); + } + + hr = m_pD3DDev->SetPixelShader(nullptr); + } + } else { + if (pBackBuffer) { + ClipToSurface(pBackBuffer, rSrcVid, rDstVid); + // rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect + rSrcVid.left &= ~1; + rSrcVid.right &= ~1; + rSrcVid.top &= ~1; + rSrcVid.bottom &= ~1; + hr = m_pD3DDev->StretchRect(m_pVideoSurface[m_nCurSurface], rSrcVid, pBackBuffer, rDstVid, m_filter); + if (FAILED(hr)) { + return false; + } + } + } + } + + AlphaBltSubPic(rDstPri, rDstVid); + + if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE) { + CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock); + CRect rcSrc(m_VMR9AlphaBitmap.rSrc); + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE*)m_VMR9AlphaBitmapData) { + if ((m_pD3DXLoadSurfaceFromMemory != nullptr) && + SUCCEEDED(hr = m_pD3DDev->CreateTexture( + rcSrc.Width(), + rcSrc.Height(), + 1, + D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + &m_pOSDTexture, + nullptr))) { + if (SUCCEEDED(hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface))) { + hr = m_pD3DXLoadSurfaceFromMemory(m_pOSDSurface, nullptr, nullptr, (BYTE*)m_VMR9AlphaBitmapData, D3DFMT_A8R8G8B8, m_VMR9AlphaBitmapWidthBytes, + nullptr, &m_VMR9AlphaBitmapRect, D3DX_FILTER_NONE, m_VMR9AlphaBitmap.clrSrcKey); + } + if (FAILED(hr)) { + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + } + } + } + m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE; + } + if (rd->m_iDisplayStats) { + DrawStats(); + } + if (m_pOSDTexture) { + AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture); + } + m_pD3DDev->EndScene(); + + CRect presentationSrcRect(rDstPri), presentationDestRect(m_windowRect); + // PresentEx() / Present() performs the clipping + // TODO: fix the race and uncomment the assert + //ASSERT(presentationSrcRect.Size() == presentationDestRect.Size()); + if (m_pD3DDevEx) { + if (m_bIsFullscreen) { + hr = m_pD3DDevEx->PresentEx(nullptr, nullptr, nullptr, nullptr, 0); + } else { + hr = m_pD3DDevEx->PresentEx(presentationSrcRect, presentationDestRect, nullptr, nullptr, 0); + } + } else { + if (m_bIsFullscreen) { + hr = m_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr); + } else { + hr = m_pD3DDev->Present(presentationSrcRect, presentationDestRect, nullptr, nullptr); + } + } + if (FAILED(hr)) { + TRACE(_T("Device lost or something\n")); + } + // Calculate timing statistics + if (m_pRefClock) { + m_pRefClock->GetTime(&llCurRefTime); // To check if we called Present too late to hit the right vsync + } + m_llEstVBlankTime = std::max(m_llEstVBlankTime, llCurRefTime); // Sometimes the real value is larger than the estimated value (but never smaller) + if (rd->m_iDisplayStats < 3) { // Partial on-screen statistics + SyncStats(m_llEstVBlankTime); // Max of estimate and real. Sometimes Present may actually return immediately so we need the estimate as a lower bound + } + if (rd->m_iDisplayStats == 1) { // Full on-screen statistics + SyncOffsetStats(-llSyncOffset); // Minus because we want time to flow downward in the graph in DrawStats + } + + // Adjust sync + double frameCycle = (m_llSampleTime - m_llLastSampleTime) / 10000.0; + if (frameCycle < 0) { + frameCycle = 0.0; // Happens when searching. + } + + if (r.m_AdvRendSets.bSynchronizeVideo) { + m_pGenlock->ControlClock(dSyncOffset, frameCycle); + } else if (r.m_AdvRendSets.bSynchronizeDisplay) { + m_pGenlock->ControlDisplay(dSyncOffset, frameCycle); + } else { + m_pGenlock->UpdateStats(dSyncOffset, frameCycle); // No sync or sync to nearest neighbor + } + + m_dFrameCycle = m_pGenlock->frameCycleAvg; + m_dCycleDifference = GetCycleDifference(); + if (abs(m_dCycleDifference) < 0.05) { // If less than 5% speed difference + m_bSnapToVSync = true; + } else { + m_bSnapToVSync = false; + } + + // Check how well audio is matching rate (if at all) + DWORD tmp; + if (m_pAudioStats != nullptr) { + m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_ACCUMERROR, &m_lAudioLag, &tmp); + m_lAudioLagMin = std::min((long)m_lAudioLag, m_lAudioLagMin); + m_lAudioLagMax = std::max((long)m_lAudioLag, m_lAudioLagMax); + m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_MODE, &m_lAudioSlaveMode, &tmp); + } + + if (rd->m_bResetStats) { + ResetStats(); + rd->m_bResetStats = false; + } + + bool fResetDevice = m_bPendingResetDevice; + if (hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET || hr == S_PRESENT_MODE_CHANGED) { + fResetDevice = true; + } + if (SettingsNeedResetDevice()) { + fResetDevice = true; + } + + BOOL bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + if ((bCompositionEnabled != 0) != m_bCompositionEnabled) { + if (m_bIsFullscreen) { + m_bCompositionEnabled = (bCompositionEnabled != 0); + } else { + fResetDevice = true; + } + } + + if (r.fResetDevice) { + LONGLONG time = rd->GetPerfCounter(); + if (time > m_LastAdapterCheck + 20000000) { // check every 2 sec. + m_LastAdapterCheck = time; +#ifdef _DEBUG + D3DDEVICE_CREATION_PARAMETERS Parameters; + if (SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))) { + ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter); + } +#endif + if (m_CurrentAdapter != GetAdapter(m_pD3D, m_hWnd)) { + fResetDevice = true; + } +#ifdef _DEBUG + else { + ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D, m_hWnd))); + } +#endif + } + } + + if (fResetDevice) { + m_bPendingResetDevice = true; + SendResetRequest(); + } + return true; +} + +void CBaseAP::SendResetRequest() +{ + if (!m_bDeviceResetRequested) { + m_bDeviceResetRequested = true; + AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE); + } +} + +STDMETHODIMP_(bool) CBaseAP::ResetDevice() +{ + DeleteSurfaces(); + HRESULT hr; + CString Error; + if (FAILED(hr = CreateDXDevice(Error)) || FAILED(hr = AllocSurfaces())) { + m_bDeviceResetRequested = false; + return false; + } + m_pGenlock->SetMonitor(GetAdapter(m_pD3D, m_hWnd)); + m_pGenlock->GetTiming(); + OnResetDevice(); + m_bDeviceResetRequested = false; + m_bPendingResetDevice = false; + return true; +} + +STDMETHODIMP_(bool) CBaseAP::DisplayChange() +{ + m_bPendingResetDevice = true; + SendResetRequest(); + return true; +} + +void CBaseAP::InitStats() +{ + ASSERT(m_pD3DDev); + static LONG currentHeight = 0; + int newHeight = lround(FONT_HEIGHT * (double(m_windowRect.Width()) / REFERENCE_WIDTH)); + + if (m_pD3DXCreateFont && (!m_pFont || currentHeight != newHeight)) { + m_pFont = nullptr; + if (newHeight <= 0) { + ASSERT(FALSE); + } + m_pD3DXCreateFont(m_pD3DDev, newHeight, 0, newHeight < BOLD_THRESHOLD ? FW_NORMAL : FW_BOLD, + 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, + FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont); + currentHeight = newHeight; + } + + if (m_pD3DXCreateSprite && !m_pSprite) { + m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite); + } + + if (m_pD3DXCreateLine && !m_pLine) { + m_pD3DXCreateLine(m_pD3DDev, &m_pLine); + } +} + +void CBaseAP::DrawStats() +{ + const CRenderersData* rd = GetRenderersData(); + + InitStats(); + const float textScale = float(m_windowRect.Width()) / REFERENCE_WIDTH; + const int lineHeight = lround((FONT_HEIGHT + TEXT_PADDING) * textScale); + + // pApp->m_iDisplayStats = 1 for full stats, 2 for little less, 3 for basic, 0 for no stats + if (m_pFont && m_pSprite) { + auto drawText = [&](CRect & rc, const CString & strText) { + D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f); + D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f); + + RECT shadowRect = rc; + OffsetRect(&shadowRect, 2, 2); + + // Draw shadow + m_pFont->DrawText(m_pSprite, strText, -1, &shadowRect, DT_NOCLIP, Color0); + // Draw text + m_pFont->DrawText(m_pSprite, strText, -1, rc, DT_NOCLIP, Color1); + rc.OffsetRect(0, lineHeight); + }; + + const CRenderersSettings& r = GetRenderersSettings(); + LONGLONG llMaxJitter = m_MaxJitter; + LONGLONG llMinJitter = m_MinJitter; + CRect rc(lineHeight, lineHeight, 0, 0); + + m_pSprite->Begin(D3DXSPRITE_ALPHABLEND); + CString strText; + + strText.Format(_T("Frames drawn from stream start: %u | Sample time stamp: %ld ms"), + m_pcFramesDrawn, (LONG)(m_llSampleTime / 10000)); + drawText(rc, strText); + + if (rd->m_iDisplayStats == 1) { + strText.Format(_T("Frame cycle : %.3f ms [%.3f ms, %.3f ms] Actual %+5.3f ms [%+.3f ms, %+.3f ms]"), + m_dFrameCycle, m_pGenlock->minFrameCycle, m_pGenlock->maxFrameCycle, + m_fJitterMean / 10000.0, (double(llMinJitter) / 10000.0), + (double(llMaxJitter) / 10000.0)); + drawText(rc, strText); + + strText.Format(_T("Display cycle: Measured closest match %.3f ms Measured base %.3f ms"), + m_dOptimumDisplayCycle, m_dEstRefreshCycle); + drawText(rc, strText); + + strText.Format(_T("Frame rate : %.3f fps Actual frame rate: %.3f fps"), + 1000.0 / m_dFrameCycle, 10000000.0 / m_fJitterMean); + drawText(rc, strText); + + strText.Format(_T("Windows : Display cycle %.3f ms Display refresh rate %u Hz"), + m_dD3DRefreshCycle, m_refreshRate); + drawText(rc, strText); + + if (m_pGenlock->powerstripTimingExists) { + strText.Format(_T("Powerstrip : Display cycle %.3f ms Display refresh rate %.3f Hz"), + 1000.0 / m_pGenlock->curDisplayFreq, m_pGenlock->curDisplayFreq); + drawText(rc, strText); + } + + if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0) { + strText = _T("Scan line err: Graphics device does not support scan line access. No sync is possible"); + drawText(rc, strText); + } + +#ifdef _DEBUG + if (m_pD3DDevEx) { + CComPtr pSC; + HRESULT hr = m_pD3DDevEx->GetSwapChain(0, &pSC); + CComQIPtr pSCEx = pSC; + if (pSCEx) { + D3DPRESENTSTATS stats; + hr = pSCEx->GetPresentStats(&stats); + if (SUCCEEDED(hr)) { + strText = _T("Graphics device present stats:"); + drawText(rc, strText); + + strText.Format(_T(" PresentCount %u PresentRefreshCount %u SyncRefreshCount %u"), + stats.PresentCount, stats.PresentRefreshCount, stats.SyncRefreshCount); + drawText(rc, strText); + + LARGE_INTEGER Freq; + QueryPerformanceFrequency(&Freq); + Freq.QuadPart /= 1000; + strText.Format(_T(" SyncQPCTime %dms SyncGPUTime %dms"), + stats.SyncQPCTime.QuadPart / Freq.QuadPart, + stats.SyncGPUTime.QuadPart / Freq.QuadPart); + drawText(rc, strText); + } else { + strText = L"Graphics device does not support present stats"; + drawText(rc, strText); + } + } + } +#endif + + strText.Format(_T("Video size : %ld x %ld (AR = %ld : %ld) Display resolution %ld x %ld "), + m_nativeVideoSize.cx, m_nativeVideoSize.cy, m_aspectRatio.cx, m_aspectRatio.cy, + m_ScreenSize.cx, m_ScreenSize.cy); + drawText(rc, strText); + + if (r.m_AdvRendSets.bSynchronizeDisplay || r.m_AdvRendSets.bSynchronizeVideo) { + if (r.m_AdvRendSets.bSynchronizeDisplay && !m_pGenlock->PowerstripRunning()) { + strText = _T("Sync error : PowerStrip is not running. No display sync is possible."); + drawText(rc, strText); + } else { + strText.Format(_T("Sync adjust : %d | # of adjustments: %u"), + m_pGenlock->adjDelta, + (m_pGenlock->clockAdjustmentsMade + m_pGenlock->displayAdjustmentsMade) / 2); + drawText(rc, strText); + } + } + } + + strText.Format(_T("Sync offset : Average %3.1f ms [%.1f ms, %.1f ms] Target %3.1f ms"), + m_pGenlock->syncOffsetAvg, m_pGenlock->minSyncOffset, + m_pGenlock->maxSyncOffset, r.m_AdvRendSets.fTargetSyncOffset); + drawText(rc, strText); + + strText.Format(_T("Sync status : glitches %u, display-frame cycle mismatch: %7.3f %%, dropped frames %u"), + m_uSyncGlitches, 100 * m_dCycleDifference, m_pcFramesDropped); + drawText(rc, strText); + + if (rd->m_iDisplayStats == 1) { + if (m_pAudioStats && r.m_AdvRendSets.bSynchronizeVideo) { + strText.Format(_T("Audio lag : %3lu ms [%ld ms, %ld ms] | %s"), + m_lAudioLag, m_lAudioLagMin, m_lAudioLagMax, + (m_lAudioSlaveMode == 4) ? + _T("Audio renderer is matching rate (for analog sound output)") : + _T("Audio renderer is not matching rate")); + drawText(rc, strText); + } + + strText.Format(_T("Sample time : waiting %3ld ms"), m_lNextSampleWait); + if (r.m_AdvRendSets.bSynchronizeNearest) { + CString temp; + temp.Format(_T(" paint time correction: %3ld ms Hysteresis: %I64d"), + m_lShiftToNearest, m_llHysteresis / 10000); + strText += temp; + } + drawText(rc, strText); + + strText.Format(_T("Buffering : Buffered %3ld Free %3ld Current Surface %3d"), + m_nUsedBuffer, m_nDXSurface - m_nUsedBuffer, m_nCurSurface); + drawText(rc, strText); + + strText = _T("Settings : "); + + if (m_bIsFullscreen) { + strText += _T("D3DFS "); + } + if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { + strText += _T("DisDC "); + } + if (r.m_AdvRendSets.bSynchronizeVideo) { + strText += _T("SyncVideo "); + } + if (r.m_AdvRendSets.bSynchronizeDisplay) { + strText += _T("SyncDisplay "); + } + if (r.m_AdvRendSets.bSynchronizeNearest) { + strText += _T("SyncNearest "); + } + if (m_bHighColorResolution) { + strText += _T("10 bit "); + } + if (r.m_AdvRendSets.iEVROutputRange == 0) { + strText += _T("0-255 "); + } else if (r.m_AdvRendSets.iEVROutputRange == 1) { + strText += _T("16-235 "); + } + + drawText(rc, strText); + drawText(rc, rd->m_strDXVAInfo); + + strText.Format(L"DirectX SDK : %u", rd->GetDXSdkRelease()); + drawText(rc, strText); + + for (int i = 0; i < 6; i++) { + if (m_strStatsMsg[i][0]) { + drawText(rc, m_strStatsMsg[i]); + } + } + } + m_pSprite->End(); + } + + if (m_pLine && (rd->m_iDisplayStats < 3)) { + D3DXVECTOR2 points[NB_JITTER]; + const float graphWidth = GRAPH_WIDTH * textScale; + const float graphHeight = GRAPH_HEIGHT * textScale; + const float topLeftX = m_windowRect.Width() - (graphWidth + lineHeight); + const float topLeftY = m_windowRect.Height() - (graphHeight + lineHeight); + const float gridStepY = graphHeight / 24.0f; + const float gridStepX = graphWidth / NB_JITTER; + + // Draw background + DrawRect(RGB(0, 0, 0), 80, CRect(int(topLeftX), + int(topLeftY), + int(topLeftX + graphWidth), + int(topLeftY + graphHeight))); + + m_pLine->SetWidth(2.5f * textScale); + m_pLine->SetAntialias(TRUE); + m_pLine->Begin(); + + // Draw grid lines + for (int i = 1; i < 24; ++i) { + points[0].x = topLeftX; + points[0].y = topLeftY + i * gridStepY; + points[1].y = points[0].y; + + float lineLength; + D3DCOLOR color; + if (i % 12 == 0) { + lineLength = 1.0f; + color = D3DCOLOR_XRGB(100, 100, 255); + } else if (i % 4 == 0) { + lineLength = 0.96f; + color = D3DCOLOR_XRGB(100, 100, 180); + } else { + lineLength = 0.04f; + color = D3DCOLOR_XRGB(100, 100, 140); + } + points[1].x = topLeftX + graphWidth * lineLength; + m_pLine->Draw(points, 2, color); + } + + // Draw jitter + for (int i = 1; i <= NB_JITTER; ++i) { + int nIndex = (m_nNextJitter + i) % NB_JITTER; + if (nIndex < 0) { + nIndex += NB_JITTER; + ASSERT(FALSE); + } + float jitter = float(m_pllJitter[nIndex] - m_fJitterMean); + points[i - 1].x = topLeftX + i * gridStepX; + points[i - 1].y = topLeftY + (jitter * textScale / 2000.0f + graphHeight / 2.0f); + } + m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100)); + + if (rd->m_iDisplayStats == 1) { // Full on-screen statistics + // Draw sync offset + for (int i = 1; i <= NB_JITTER; ++i) { + int nIndex = (m_nNextSyncOffset + i) % NB_JITTER; + if (nIndex < 0) { + nIndex += NB_JITTER; + } + points[i - 1].x = topLeftX + i * gridStepX; + points[i - 1].y = topLeftY + (m_pllSyncOffset[nIndex] * textScale / 2000.0f + graphHeight / 2.0f); + } + m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100)); + } + m_pLine->End(); + } +} + +double CBaseAP::GetRefreshRate() +{ + if (m_pGenlock->powerstripTimingExists) { + return m_pGenlock->curDisplayFreq; + } else { + return (double)m_refreshRate; + } +} + +double CBaseAP::GetDisplayCycle() +{ + if (m_pGenlock->powerstripTimingExists) { + return 1000.0 / m_pGenlock->curDisplayFreq; + } else { + return (double)m_dD3DRefreshCycle; + } +} + +double CBaseAP::GetCycleDifference() +{ + double dBaseDisplayCycle = GetDisplayCycle(); + double minDiff = 1.0; + if (dBaseDisplayCycle == 0.0 || m_dFrameCycle == 0.0) { + return 1.0; + } else { + for (UINT i = 1; i <= 8; i++) { // Try a lot of multiples of the display frequency + double dDisplayCycle = i * dBaseDisplayCycle; + double diff = (dDisplayCycle - m_dFrameCycle) / m_dFrameCycle; + if (abs(diff) < abs(minDiff)) { + minDiff = diff; + m_dOptimumDisplayCycle = dDisplayCycle; + } + } + } + return minDiff; +} + +void CBaseAP::EstimateRefreshTimings() +{ + if (m_pD3DDev) { + const CRenderersData* rd = GetRenderersData(); + D3DRASTER_STATUS rasterStatus; + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + while (rasterStatus.ScanLine != 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + while (rasterStatus.ScanLine == 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + LONGLONG startTime = rd->GetPerfCounter(); + UINT startLine = rasterStatus.ScanLine; + LONGLONG endTime = 0; + UINT endLine = 0; + bool done = false; + while (!done) { // Estimate time for one scan line + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + UINT line = rasterStatus.ScanLine; + LONGLONG time = rd->GetPerfCounter(); + if (line > 0) { + endLine = line; + endTime = time; + } else { + done = true; + } + } + m_dDetectedScanlineTime = (endTime - startTime) / ((endLine - startLine) * 10000.0); + + // Estimate the display refresh rate from the vsyncs + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + while (rasterStatus.ScanLine != 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + // Now we're at the start of a vsync + startTime = rd->GetPerfCounter(); + UINT i; + for (i = 1; i <= 50; i++) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + while (rasterStatus.ScanLine == 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + while (rasterStatus.ScanLine != 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + // Now we're at the next vsync + } + endTime = rd->GetPerfCounter(); + m_dEstRefreshCycle = (endTime - startTime) / ((i - 1) * 10000.0); + } +} + +bool CBaseAP::ExtractInterlaced(const AM_MEDIA_TYPE* pmt) +{ + if (pmt->formattype == FORMAT_VideoInfo) { + return false; + } else if (pmt->formattype == FORMAT_VideoInfo2) { + return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; + } else if (pmt->formattype == FORMAT_MPEGVideo) { + return false; + } else if (pmt->formattype == FORMAT_MPEG2Video) { + return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; + } else { + return false; + } +} + +HRESULT CBaseAP::Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect) { + HRESULT hr = E_FAIL; + + const CRenderersSettings& r = GetRenderersSettings(); + + DWORD iDX9Resizer = r.iDX9Resizer; + Vector dst[4]; + Transform(destRect, dst); + + if (iDX9Resizer == 0 || iDX9Resizer == 1) { + D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; + hr = TextureResize(pTexture, dst, Filter, srcRect); + } else if (iDX9Resizer == 2) { + hr = TextureResizeBilinear(pTexture, dst, srcRect); + } else if (iDX9Resizer >= 3) { + hr = TextureResizeBicubic1pass(pTexture, dst, srcRect); + } + + return hr; +} + +STDMETHODIMP CBaseAP::GetDIB(BYTE* lpDib, DWORD* size) +{ + CheckPointer(size, E_POINTER); + + // Keep a reference so that we can safely work on the surface + // without having to lock everything + CComPtr pVideoSurface; + { + CAutoLock cAutoLock(this); + CheckPointer(m_pVideoSurface[m_nCurSurface], E_FAIL); + pVideoSurface = m_pVideoSurface[m_nCurSurface]; + } + + HRESULT hr; + + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(hr = pVideoSurface->GetDesc(&desc))) { + return hr; + } + + CSize framesize = GetVideoSize(false); + const CSize dar = GetVideoSize(true); + + bool resize = false; + if (dar.cx > 0 && dar.cy > 0 && (dar.cx != desc.Width || dar.cy != desc.Height)) { + framesize.cx = MulDiv(framesize.cy, dar.cx, dar.cy); + resize = true; + desc.Width = framesize.cx; + desc.Height = framesize.cy; + } + + DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3); + if (!lpDib) { + *size = required; + return S_OK; + } + if (*size < required) { + return E_OUTOFMEMORY; + } + *size = required; + + CComPtr pSurface, tSurface; + // Convert to 8-bit when using 10-bit or full/half processing modes + if (desc.Format != D3DFMT_X8R8G8B8) { + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tSurface, nullptr)) + || FAILED(hr = m_pD3DXLoadSurfaceFromSurface(tSurface, nullptr, nullptr, pVideoSurface, nullptr, nullptr, D3DX_DEFAULT, 0))) { + return hr; + } + } else { + tSurface = pVideoSurface; + } + + if (resize) { + CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; + if (FAILED(hr = m_pD3DDevEx->CreateRenderTarget(framesize.cx, framesize.cy, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurface, nullptr)) + || FAILED(hr = m_pD3DDevEx->SetRenderTarget(0, pSurface)) + || FAILED(hr = Resize(pVideoTexture, { CPoint(0, 0), m_nativeVideoSize }, { CPoint(0, 0), framesize }))) { + return hr; + } + } else { + pSurface = tSurface; + } + + D3DLOCKED_RECT r; + if (FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { + // If this fails, we try to use a surface allocated from the system memory + CComPtr pInputSurface = pSurface; + pSurface = nullptr; + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, nullptr)) + || FAILED(hr = m_pD3DDev->GetRenderTargetData(pInputSurface, pSurface)) + || FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { + return hr; + } + } + + hr = CreateDIBFromSurfaceData(desc, r, lpDib); + + pSurface->UnlockRect(); + + return hr; +} + +STDMETHODIMP CBaseAP::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) +{ + return SetPixelShader2(pSrcData, pTarget, false); +} + +STDMETHODIMP CBaseAP::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) +{ + CAutoLock cRenderLock(&m_allocatorLock); + + CAtlList* pPixelShaders; + if (bScreenSpace) { + pPixelShaders = &m_pPixelShadersScreenSpace; + } else { + pPixelShaders = &m_pPixelShaders; + } + + if (!pSrcData && !pTarget) { + pPixelShaders->RemoveAll(); + m_pD3DDev->SetPixelShader(nullptr); + return S_OK; + } + + if (!pSrcData) { + return E_INVALIDARG; + } + + CExternalPixelShader Shader; + Shader.m_SourceData = pSrcData; + Shader.m_SourceTarget = pTarget; + + CComPtr pPixelShader; + + HRESULT hr = Shader.Compile(m_pPSC); + if (FAILED(hr)) { + return hr; + } + + pPixelShaders->AddTail(Shader); + Paint(true); + return S_OK; +} + +CSyncAP::CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) + : CBaseAP(hWnd, bFullscreen, hr, _Error) + , m_LastClockState(MFCLOCK_STATE_INVALID) + , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture) + , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0) + , m_BorderColor(RGB(0, 0, 0)) + , m_hEvtQuit(nullptr) + , m_bEvtQuit(0) + , m_hEvtFlush(nullptr) + , m_bEvtFlush(0) + , m_hEvtSkip(nullptr) + , m_bEvtSkip(false) + , m_bUseInternalTimer(false) + , m_LastSetOutputRange(-1) + , m_bPendingRenegotiate(false) + , m_bPendingMediaFinished(false) + , m_bPrerolled(false) + , m_hRenderThread(nullptr) + , m_hMixerThread(nullptr) + , m_nRenderState(Shutdown) + , m_bStepping(false) + , m_nCurrentGroupId(0) + , m_nResetToken(0) + , m_nStepCount(0) + , m_SampleFreeCallback(this, &CSyncAP::OnSampleFree) + , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9") + , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer") + , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface") + , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType") + , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW") + , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority") + , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics") +{ + const CRenderersSettings& r = GetRenderersSettings(); + + if (FAILED(hr)) { + _Error += L"SyncAP failed\n"; + return; + } + + if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) { + if (!fnDXVA2CreateDirect3DDeviceManager9) { + _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n"; + } + if (!fnMFCreateDXSurfaceBuffer) { + _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n"; + } + if (!fnMFCreateVideoSampleFromSurface) { + _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n"; + } + if (!fnMFCreateMediaType) { + _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n"; + } + hr = E_FAIL; + return; + } + + // Init DXVA manager + hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager); + if (SUCCEEDED(hr) && m_pD3DManager) { + hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); + if (FAILED(hr)) { + _Error += L"m_pD3DManager->ResetDevice failed\n"; + } + } else { + _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n"; + } + + // Bufferize frame only with 3D texture + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { + m_nDXSurface = std::max(std::min(r.iEvrBuffers, MAX_PICTURE_SLOTS - 2), 4); + } else { + m_nDXSurface = 1; + } + + m_pOuterEVR = nullptr; + m_lShiftToNearest = -1; // Illegal value to start with +} + +CSyncAP::~CSyncAP() +{ + StopWorkerThreads(); + m_pMediaType = nullptr; + m_pClock = nullptr; + m_pD3DManager = nullptr; + + if (m_bHookedNewSegment) { + UnhookNewSegment(); + } +} + +HRESULT CSyncAP::CheckShutdown() const +{ + if (m_nRenderState == Shutdown) { + return MF_E_SHUTDOWN; + } else { + return S_OK; + } +} + +void CSyncAP::StartWorkerThreads() +{ + DWORD dwThreadId; + if (m_nRenderState == Shutdown) { + m_hEvtQuit = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hEvtFlush = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hEvtSkip = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hMixerThread = ::CreateThread(nullptr, 0, MixerThreadStatic, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hMixerThread, THREAD_PRIORITY_HIGHEST); + m_hRenderThread = ::CreateThread(nullptr, 0, RenderThreadStatic, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hRenderThread, THREAD_PRIORITY_TIME_CRITICAL); + m_nRenderState = Stopped; + } +} + +void CSyncAP::StopWorkerThreads() +{ + if (m_nRenderState != Shutdown) { + SetEvent(m_hEvtFlush); + m_bEvtFlush = true; + SetEvent(m_hEvtQuit); + m_bEvtQuit = true; + SetEvent(m_hEvtSkip); + m_bEvtSkip = true; + + if (m_hRenderThread && WaitForSingleObject(m_hRenderThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hRenderThread, 0xDEAD); + } + + SAFE_CLOSE_HANDLE(m_hRenderThread); + + if (m_hMixerThread && WaitForSingleObject(m_hMixerThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hMixerThread, 0xDEAD); + } + + SAFE_CLOSE_HANDLE(m_hMixerThread); + SAFE_CLOSE_HANDLE(m_hEvtFlush); + SAFE_CLOSE_HANDLE(m_hEvtQuit); + SAFE_CLOSE_HANDLE(m_hEvtSkip); + + m_bEvtFlush = false; + m_bEvtQuit = false; + m_bEvtSkip = false; + } + m_nRenderState = Shutdown; +} + +STDMETHODIMP CSyncAP::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + *ppRenderer = nullptr; + HRESULT hr = E_FAIL; + + do { + CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; + + CSyncRenderer* pOuterEVR = DEBUG_NEW CSyncRenderer(NAME("CSyncRenderer"), pUnk, hr, &m_VMR9AlphaBitmap, this); + m_pOuterEVR = pOuterEVR; + + pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR); + CComQIPtr pBF = pUnk; + + if (FAILED(hr)) { + break; + } + + // Set EVR custom presenter + CComPtr pVP; + CComPtr pMFVR; + CComQIPtr pMFGS = pBF; + CComQIPtr pConfig = pBF; + if (SUCCEEDED(hr)) { + if (FAILED(pConfig->SetNumberOfStreams(3))) { // TODO - maybe need other number of input stream ... + break; + } + } + + hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVR)); + + if (SUCCEEDED(hr)) { + hr = QueryInterface(IID_PPV_ARGS(&pVP)); + } + if (SUCCEEDED(hr)) { + hr = pMFVR->InitializeRenderer(nullptr, pVP); + } + + if (SUCCEEDED(hr)) { + CComPtr pPin = GetFirstPin(pBF); + if (HookNewSegment((IPinC*)(IPin*)pPin)) { + m_bUseInternalTimer = true; + m_bHookedNewSegment = true; + } + *ppRenderer = pBF.Detach(); + } else { + *ppRenderer = nullptr; + } + } while (0); + + return hr; +} + +STDMETHODIMP_(bool) CSyncAP::Paint(bool bAll) +{ + return __super::Paint(bAll); +} + +STDMETHODIMP_(bool) CSyncAP::Paint(IMFSample* pMFSample) +{ + m_pCurrentlyDisplayedSample = pMFSample; + pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface); + + auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { + UINT32 nGroupId; + return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); + }; + ASSERT(sampleHasCurrentGroupId(pMFSample)); + + return Paint(true); +} + +STDMETHODIMP CSyncAP::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + HRESULT hr; + if (riid == __uuidof(IMFClockStateSink)) { + hr = GetInterface((IMFClockStateSink*)this, ppv); + } else if (riid == __uuidof(IMFVideoPresenter)) { + hr = GetInterface((IMFVideoPresenter*)this, ppv); + } else if (riid == __uuidof(IMFTopologyServiceLookupClient)) { + hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv); + } else if (riid == __uuidof(IMFVideoDeviceID)) { + hr = GetInterface((IMFVideoDeviceID*)this, ppv); + } else if (riid == __uuidof(IMFGetService)) { + hr = GetInterface((IMFGetService*)this, ppv); + } else if (riid == __uuidof(IMFAsyncCallback)) { + hr = GetInterface((IMFAsyncCallback*)this, ppv); + } else if (riid == __uuidof(IMFVideoDisplayControl)) { + hr = GetInterface((IMFVideoDisplayControl*)this, ppv); + } else if (riid == __uuidof(IEVRTrustedVideoPlugin)) { + hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv); + } else if (riid == IID_IQualProp) { + hr = GetInterface((IQualProp*)this, ppv); + } else if (riid == __uuidof(IMFRateSupport)) { + hr = GetInterface((IMFRateSupport*)this, ppv); + } else if (riid == __uuidof(IDirect3DDeviceManager9)) { + hr = m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppv); + } else if (riid == __uuidof(ISyncClockAdviser)) { + hr = GetInterface((ISyncClockAdviser*)this, ppv); + } else if (riid == __uuidof(ID3DFullscreenControl)) { + hr = GetInterface((ID3DFullscreenControl*)this, ppv); + } else { + hr = __super::NonDelegatingQueryInterface(riid, ppv); + } + + return hr; +} + +// IMFClockStateSink +STDMETHODIMP CSyncAP::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + m_nRenderState = Started; + return S_OK; +} + +STDMETHODIMP CSyncAP::OnClockStop(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + m_nRenderState = Stopped; + return S_OK; +} + +STDMETHODIMP CSyncAP::OnClockPause(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + m_nRenderState = Paused; + return S_OK; +} + +STDMETHODIMP CSyncAP::OnClockRestart(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + m_nRenderState = Started; + return S_OK; +} + +STDMETHODIMP CSyncAP::OnClockSetRate(MFTIME hnsSystemTime, float flRate) +{ + return E_NOTIMPL; +} + +// IBaseFilter delegate +bool CSyncAP::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue) +{ + CAutoLock lock(&m_SampleQueueLock); + switch (m_nRenderState) { + case Started: + *State = State_Running; + break; + case Paused: + *State = State_Paused; + break; + case Stopped: + *State = State_Stopped; + break; + default: + *State = State_Stopped; + _ReturnValue = E_FAIL; + } + _ReturnValue = S_OK; + return true; +} + +// IQualProp +STDMETHODIMP CSyncAP::get_FramesDroppedInRenderer(int* pcFrames) +{ + *pcFrames = m_pcFramesDropped; + return S_OK; +} + +STDMETHODIMP CSyncAP::get_FramesDrawn(int* pcFramesDrawn) +{ + *pcFramesDrawn = m_pcFramesDrawn; + return S_OK; +} + +STDMETHODIMP CSyncAP::get_AvgFrameRate(int* piAvgFrameRate) +{ + *piAvgFrameRate = (int)(m_fAvrFps * 100); + return S_OK; +} + +STDMETHODIMP CSyncAP::get_Jitter(int* iJitter) +{ + *iJitter = (int)((m_fJitterStdDev / 10000.0) + 0.5); + return S_OK; +} + +STDMETHODIMP CSyncAP::get_AvgSyncOffset(int* piAvg) +{ + *piAvg = (int)((m_fSyncOffsetAvr / 10000.0) + 0.5); + return S_OK; +} + +STDMETHODIMP CSyncAP::get_DevSyncOffset(int* piDev) +{ + *piDev = (int)((m_fSyncOffsetStdDev / 10000.0) + 0.5); + return S_OK; +} + +// IMFRateSupport +STDMETHODIMP CSyncAP::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) +{ + *pflRate = 0; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) +{ + HRESULT hr = S_OK; + float fMaxRate = 0.0f; + + CAutoLock lock(this); + + CheckPointer(pflRate, E_POINTER); + CHECK_HR(CheckShutdown()); + + // Get the maximum forward rate. + fMaxRate = GetMaxRate(fThin); + + // For reverse playback, swap the sign. + if (eDirection == MFRATE_REVERSE) { + fMaxRate = -fMaxRate; + } + + *pflRate = fMaxRate; + return hr; +} + +STDMETHODIMP CSyncAP::IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate) +{ + // fRate can be negative for reverse playback. + // pfNearestSupportedRate can be NULL. + CAutoLock lock(this); + HRESULT hr = S_OK; + float fMaxRate = 0.0f; + float fNearestRate = flRate; // Default. + + CheckPointer(pflNearestSupportedRate, E_POINTER); + CHECK_HR(CheckShutdown()); + + // Find the maximum forward rate. + fMaxRate = GetMaxRate(fThin); + + if (fabsf(flRate) > fMaxRate) { + // The (absolute) requested rate exceeds the maximum rate. + hr = MF_E_UNSUPPORTED_RATE; + + // The nearest supported rate is fMaxRate. + fNearestRate = fMaxRate; + if (flRate < 0) { + // For reverse playback, swap the sign. + fNearestRate = -fNearestRate; + } + } + // Return the nearest supported rate if the caller requested it. + if (pflNearestSupportedRate != nullptr) { + *pflNearestSupportedRate = fNearestRate; + } + return hr; +} + +float CSyncAP::GetMaxRate(BOOL bThin) +{ + float fMaxRate = FLT_MAX; // Default. + UINT32 fpsNumerator = 0, fpsDenominator = 0; + + if (!bThin && m_pMediaType) { + // Non-thinned: Use the frame rate and monitor refresh rate. + + // Frame rate: + MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE, + &fpsNumerator, &fpsDenominator); + + // Monitor refresh rate: + UINT MonitorRateHz = m_refreshRate; // D3DDISPLAYMODE + + if (fpsDenominator && fpsNumerator && MonitorRateHz) { + // Max Rate = Refresh Rate / Frame Rate + fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator); + } + } + return fMaxRate; +} + +void CSyncAP::CompleteFrameStep(bool bCancel) +{ + if (m_nStepCount > 0) { + if (bCancel || (m_nStepCount == 1)) { + m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0); + m_nStepCount = 0; + } else { + m_nStepCount--; + } + } +} + +// IMFVideoPresenter +STDMETHODIMP CSyncAP::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) +{ + HRESULT hr = S_OK; + CHECK_HR(CheckShutdown()); + + switch (eMessage) { + case MFVP_MESSAGE_BEGINSTREAMING: + hr = BeginStreaming(); + m_llHysteresis = 0; + m_lShiftToNearest = 0; + m_bStepping = false; + break; + + case MFVP_MESSAGE_CANCELSTEP: + m_bStepping = false; + CompleteFrameStep(true); + break; + + case MFVP_MESSAGE_ENDOFSTREAM: + m_bPendingMediaFinished = true; + break; + + case MFVP_MESSAGE_ENDSTREAMING: + m_pGenlock->ResetTiming(); + m_pRefClock = nullptr; + m_nRenderState = Stopped; + break; + + case MFVP_MESSAGE_FLUSH: + SetEvent(m_hEvtFlush); + m_bEvtFlush = true; + while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0) { + ; + } + break; + + case MFVP_MESSAGE_INVALIDATEMEDIATYPE: + m_bPendingRenegotiate = true; + while (m_bPendingRenegotiate) { + Sleep(1); + } + break; + + case MFVP_MESSAGE_PROCESSINPUTNOTIFY: + break; + + case MFVP_MESSAGE_STEP: + m_nStepCount = (int)ulParam; + m_bStepping = true; + break; + + default: + ASSERT(FALSE); + break; + } + return hr; +} + +HRESULT CSyncAP::IsMediaTypeSupported(IMFMediaType* pMixerType) +{ + HRESULT hr; + AM_MEDIA_TYPE* pAMMedia; + UINT nInterlaceMode; + + CHECK_HR(pMixerType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); + CHECK_HR(pMixerType->GetUINT32(MF_MT_INTERLACE_MODE, &nInterlaceMode)); + + if ((pAMMedia->majortype != MEDIATYPE_Video)) { + hr = MF_E_INVALIDMEDIATYPE; + } + pMixerType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); + return hr; +} + +HRESULT CSyncAP::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType) +{ + HRESULT hr; + IMFMediaType* pOptimalMediaType; + + CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType)); + CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType)); + + const GUID colorAttributes[] = { + MF_MT_VIDEO_LIGHTING, + MF_MT_VIDEO_PRIMARIES, + MF_MT_TRANSFER_FUNCTION, + MF_MT_YUV_MATRIX, + MF_MT_VIDEO_CHROMA_SITING + }; + + auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) { + PROPVARIANT val; + HRESULT hr = pFrom->GetItem(guidKey, &val); + + if (SUCCEEDED(hr)) { + hr = pTo->SetItem(guidKey, val); + PropVariantClear(&val); + } else if (hr == MF_E_ATTRIBUTENOTFOUND) { + hr = pTo->DeleteItem(guidKey); + } + return hr; + }; + + for (REFGUID guidKey : colorAttributes) { + if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) { + TRACE(_T("Copying color attribute %s failed: 0x%08x\n"), static_cast(CComBSTR(guidKey)), hr); + } + } + + pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0); + + const CRenderersSettings& r = GetRenderersSettings(); + + UINT32 nominalRange; + if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)) + && nominalRange == MFNominalRange_0_255) { + // EVR mixer always assumes 16-235 input. Bug? + // To keep untouched 0-255 range and avoid unwanted expansion we need to request 16-235 as output. + // To get 16-235 output we need to request 48-208 as output. + nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_48_208 : MFNominalRange_16_235; + } else { + nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255; + } + pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange); + m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange; + + ULARGE_INTEGER ui64Size; + pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart); + + CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart); + MFVideoArea Area = GetArea(0, 0, videoSize.cx, videoSize.cy); + pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea)); + + ULARGE_INTEGER ui64AspectRatio; + pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart); + + UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart; + UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart; + UINT64 gcd = GCD(ui64ARx, ui64ARy); + if (gcd > 1) { + ui64ARx /= gcd; + ui64ARy /= gcd; + } + CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy); + + if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) { + SetVideoSize(videoSize, aspectRatio); + + // Notify the graph about the change + if (m_pSink) { + m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_nativeVideoSize.cx, m_nativeVideoSize.cy), 0); + } + } + + *ppType = pOptimalMediaType; + (*ppType)->AddRef(); + + return hr; +} + +HRESULT CSyncAP::SetMediaType(IMFMediaType* pType) +{ + HRESULT hr = S_OK; + AM_MEDIA_TYPE* pAMMedia = nullptr; + CString strTemp; + + CHECK_HR(CheckShutdown()); + + if (pType == nullptr) { + // Release + RemoveAllSamples(); + DeleteSurfaces(); + CAutoLock lock(this); + m_pMediaType = nullptr; + return hr; + } + + DWORD dwFlags = 0; + if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) { + // Nothing to do + return hr; + } + + CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); + + hr = InitializeDevice(pAMMedia); + if (SUCCEEDED(hr)) { + CAutoLock lock(this); + m_pMediaType = pType; + + strTemp = GetMediaTypeName(pAMMedia->subtype); + strTemp.Replace(L"MEDIASUBTYPE_", L""); + m_strStatsMsg[MSG_MIXEROUT].Format(L"Mixer output : %s", strTemp.GetString()); + } + + pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); + + return hr; +} + +LONGLONG CSyncAP::GetMediaTypeMerit(IMFMediaType* pMediaType) +{ + AM_MEDIA_TYPE* pAMMedia = nullptr; + MFVIDEOFORMAT* VideoFormat; + + HRESULT hr; + CHECK_HR(pMediaType->GetRepresentation(FORMAT_MFVideoFormat, (void**)&pAMMedia)); + VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat; + + LONGLONG Merit = 0; + switch (VideoFormat->surfaceInfo.Format) { + case FCC('NV12'): + Merit = 90000000; + break; + case FCC('YV12'): + Merit = 80000000; + break; + case FCC('YUY2'): + Merit = 70000000; + break; + case FCC('UYVY'): + Merit = 60000000; + break; + + case D3DFMT_X8R8G8B8: // Never opt for RGB + case D3DFMT_A8R8G8B8: + case D3DFMT_R8G8B8: + case D3DFMT_R5G6B5: + Merit = 0; + break; + default: + Merit = 1000; + break; + } + pMediaType->FreeRepresentation(FORMAT_MFVideoFormat, (void*)pAMMedia); + return Merit; +} + +HRESULT CSyncAP::RenegotiateMediaType() +{ + HRESULT hr = S_OK; + + CComPtr pMixerType; + CComPtr pMixerInputType; + CComPtr pType; + + if (!m_pMixer) { + return MF_E_INVALIDREQUEST; + } + + // Get the mixer's input type + hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType); + if (SUCCEEDED(hr)) { + AM_MEDIA_TYPE* pMT; + hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT); + if (SUCCEEDED(hr)) { + m_inputMediaType = *pMT; + pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT); + } + } + + CInterfaceArray ValidMixerTypes; + // Loop through all of the mixer's proposed output types. + DWORD iTypeIndex = 0; + while ((hr != MF_E_NO_MORE_TYPES)) { + pMixerType = nullptr; + pType = nullptr; + + // Step 1. Get the next media type supported by mixer. + hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType); + if (FAILED(hr)) { + break; + } + // Step 2. Check if we support this media type. + if (SUCCEEDED(hr)) { + hr = IsMediaTypeSupported(pMixerType); + } + if (SUCCEEDED(hr)) { + hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType); + } + // Step 4. Check if the mixer will accept this media type. + if (SUCCEEDED(hr)) { + hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY); + } + if (SUCCEEDED(hr)) { + LONGLONG Merit = GetMediaTypeMerit(pType); + + size_t nTypes = ValidMixerTypes.GetCount(); + size_t iInsertPos = 0; + for (size_t i = 0; i < nTypes; ++i) { + LONGLONG ThisMerit = GetMediaTypeMerit(ValidMixerTypes[i]); + if (Merit > ThisMerit) { + iInsertPos = i; + break; + } else { + iInsertPos = i + 1; + } + } + ValidMixerTypes.InsertAt(iInsertPos, pType); + } + } + + size_t nValidTypes = ValidMixerTypes.GetCount(); + for (size_t i = 0; i < nValidTypes; ++i) { + pType = ValidMixerTypes[i]; + } + + for (size_t i = 0; i < nValidTypes; ++i) { + pType = ValidMixerTypes[i]; + hr = SetMediaType(pType); + if (SUCCEEDED(hr)) { + hr = m_pMixer->SetOutputType(0, pType, 0); + // If something went wrong, clear the media type. + if (FAILED(hr)) { + SetMediaType(nullptr); + } else { + break; + } + } + } + + pMixerType = nullptr; + pType = nullptr; + return hr; +} + +bool CSyncAP::GetSampleFromMixer() +{ + MFT_OUTPUT_DATA_BUFFER dataBuffer; + HRESULT hr = S_OK; + DWORD dwStatus; + LONGLONG llClockBefore = 0; + LONGLONG llClockAfter = 0; + LONGLONG llMixerLatency; + + UINT dwSurface; + bool newSample = false; + + auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { + UINT32 nGroupId; + return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); + }; + + while (SUCCEEDED(hr)) { // Get as many frames as there are and that we have samples for + CComPtr pSample; + if (FAILED(GetFreeSample(&pSample))) { // All samples are taken for the moment. Better luck next time + break; + } + + ZeroMemory(&dataBuffer, sizeof(dataBuffer)); + dataBuffer.pSample = pSample; + pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface); + ASSERT(sampleHasCurrentGroupId(pSample)); + + { + llClockBefore = GetRenderersData()->GetPerfCounter(); + hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus); + llClockAfter = GetRenderersData()->GetPerfCounter(); + } + + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { // There are no samples left in the mixer + AddToFreeList(pSample, false); + pSample = nullptr; // The sample should not be used after being queued + // Important: Release any events returned from the ProcessOutput method. + SAFE_RELEASE(dataBuffer.pEvents); + break; + } + + if (m_pSink) { + llMixerLatency = llClockAfter - llClockBefore; + m_pSink->Notify(EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0); + } + + newSample = true; + + if (GetRenderersData()->m_bTearingTest) { + RECT rcTearing; + + rcTearing.left = m_nTearingPos; + rcTearing.top = 0; + rcTearing.right = rcTearing.left + 4; + rcTearing.bottom = m_nativeVideoSize.cy; + m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + + rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; + rcTearing.right = rcTearing.left + 4; + m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; + } + + if (SUCCEEDED(TrackSample(pSample))) { + AddToScheduledList(pSample, false); // Schedule, then go back to see if there is more where that came from + pSample = nullptr; // The sample should not be used after being queued + } else { + ASSERT(FALSE); + } + + // Important: Release any events returned from the ProcessOutput method. + SAFE_RELEASE(dataBuffer.pEvents); + } + return newSample; +} + +STDMETHODIMP CSyncAP::GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType) +{ + HRESULT hr = S_OK; + CAutoLock lock(this); + CheckPointer(ppMediaType, E_POINTER); + CHECK_HR(CheckShutdown()); + + if (!m_pMediaType) { + return MF_E_NOT_INITIALIZED; + } + + CHECK_HR(m_pMediaType->QueryInterface(IID_PPV_ARGS(ppMediaType))); + return hr; +} + +// IMFTopologyServiceLookupClient +STDMETHODIMP CSyncAP::InitServicePointers(__in IMFTopologyServiceLookup* pLookup) +{ + DWORD dwObjects = 1; + pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_pMixer), &dwObjects); + pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pSink), &dwObjects); + pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pClock), &dwObjects); + StartWorkerThreads(); + return S_OK; +} + +STDMETHODIMP CSyncAP::ReleaseServicePointers() +{ + StopWorkerThreads(); + m_pMixer = nullptr; + m_pSink = nullptr; + m_pClock = nullptr; + return S_OK; +} + +// IMFVideoDeviceID +STDMETHODIMP CSyncAP::GetDeviceID(__out IID* pDeviceID) +{ + CheckPointer(pDeviceID, E_POINTER); + *pDeviceID = IID_IDirect3DDevice9; + return S_OK; +} + +// IMFGetService +STDMETHODIMP CSyncAP::GetService(__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppvObject) +{ + if (guidService == MR_VIDEO_RENDER_SERVICE) { + return NonDelegatingQueryInterface(riid, ppvObject); + } else if (guidService == MR_VIDEO_ACCELERATION_SERVICE) { + return m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppvObject); + } + + return E_NOINTERFACE; +} + +// IMFAsyncCallback +STDMETHODIMP CSyncAP::GetParameters(__RPC__out DWORD* pdwFlags, __RPC__out DWORD* pdwQueue) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CSyncAP::Invoke(__RPC__in_opt IMFAsyncResult* pAsyncResult) +{ + return E_NOTIMPL; +} + +// IMFVideoDisplayControl +STDMETHODIMP CSyncAP::GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) +{ + if (pszVideo) { + pszVideo->cx = m_nativeVideoSize.cx; + pszVideo->cy = m_nativeVideoSize.cy; + } + if (pszARVideo) { + pszARVideo->cx = m_aspectRatio.cx; + pszARVideo->cy = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CSyncAP::GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) +{ + if (pszMin) { + pszMin->cx = 1; + pszMin->cy = 1; + } + + if (pszMax) { + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + + if (SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D, m_hWnd), &d3ddm))) { + pszMax->cx = d3ddm.Width; + pszMax->cy = d3ddm.Height; + } + } + return S_OK; +} + +STDMETHODIMP CSyncAP::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) +{ + return S_OK; +} + +STDMETHODIMP CSyncAP::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) +{ + if (pnrcSource) { + pnrcSource->left = 0.0; + pnrcSource->top = 0.0; + pnrcSource->right = 1.0; + pnrcSource->bottom = 1.0; + } + if (prcDest) { + memcpy(prcDest, &m_videoRect, sizeof(m_videoRect)); //GetClientRect (m_hWnd, prcDest); + } + return S_OK; +} + +STDMETHODIMP CSyncAP::SetAspectRatioMode(DWORD dwAspectRatioMode) +{ + m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetAspectRatioMode(DWORD* pdwAspectRatioMode) +{ + CheckPointer(pdwAspectRatioMode, E_POINTER); + *pdwAspectRatioMode = m_dwVideoAspectRatioMode; + return S_OK; +} + +STDMETHODIMP CSyncAP::SetVideoWindow(HWND hwndVideo) +{ + if (m_hWnd != hwndVideo) { + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_allocatorLock); + + m_hWnd = hwndVideo; + m_bPendingResetDevice = true; + if (m_pSink) { + m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); + } + + SendResetRequest(); + } + return S_OK; +} + +STDMETHODIMP CSyncAP::GetVideoWindow(HWND* phwndVideo) +{ + CheckPointer(phwndVideo, E_POINTER); + *phwndVideo = m_hWnd; + return S_OK; +} + +STDMETHODIMP CSyncAP::RepaintVideo() +{ + Paint(true); + return S_OK; +} + +STDMETHODIMP CSyncAP::GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp) { + if (!pBih || !pDib || !pcbDib) { + return E_POINTER; + } + CheckPointer(m_pD3DDevEx, E_ABORT); + + HRESULT hr = S_OK; + const unsigned width = m_windowRect.Width(); + const unsigned height = m_windowRect.Height(); + const unsigned len = width * height * 4; + + memset(pBih, 0, sizeof(BITMAPINFOHEADER)); + pBih->biSize = sizeof(BITMAPINFOHEADER); + pBih->biWidth = width; + pBih->biHeight = height; + pBih->biBitCount = 32; + pBih->biPlanes = 1; + pBih->biSizeImage = DIBSIZE(*pBih); + + BYTE* p = (BYTE*)CoTaskMemAlloc(len); // only this allocator can be used + if (!p) { + return E_OUTOFMEMORY; + } + + CComPtr pBackBuffer; + CComPtr pDestSurface; + D3DLOCKED_RECT r; + if (FAILED(hr = m_pD3DDevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)) + || FAILED(hr = m_pD3DDevEx->CreateRenderTarget(width, height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pDestSurface, nullptr)) + || (FAILED(hr = m_pD3DDevEx->StretchRect(pBackBuffer, m_windowRect, pDestSurface, nullptr, D3DTEXF_NONE))) + || (FAILED(hr = pDestSurface->LockRect(&r, nullptr, D3DLOCK_READONLY)))) { + CString Error = GetWindowsErrorMessage(hr, nullptr); + TRACE_SR(L"CSyncAP::GetCurrentImage failed : %s", S_OK == hr ? L"S_OK" : Error.GetBuffer()); + CoTaskMemFree(p); + return hr; + } + + RetrieveBitmapData(width, height, 32, p ? (BYTE*)p : (BYTE*)(pBih + 1), (BYTE*)r.pBits, r.Pitch); + + pDestSurface->UnlockRect(); + + *pDib = p; + *pcbDib = len; + + return S_OK; +} + +STDMETHODIMP CSyncAP::SetBorderColor(COLORREF Clr) +{ + m_BorderColor = Clr; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetBorderColor(COLORREF* pClr) +{ + CheckPointer(pClr, E_POINTER); + *pClr = m_BorderColor; + return S_OK; +} + +STDMETHODIMP CSyncAP::SetRenderingPrefs(DWORD dwRenderFlags) +{ + m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetRenderingPrefs(DWORD* pdwRenderFlags) +{ + CheckPointer(pdwRenderFlags, E_POINTER); + *pdwRenderFlags = m_dwVideoRenderPrefs; + return S_OK; +} + +STDMETHODIMP CSyncAP::SetFullscreen(BOOL fFullscreen) +{ + m_bIsFullscreen = !!fFullscreen; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetFullscreen(BOOL* pfFullscreen) +{ + CheckPointer(pfFullscreen, E_POINTER); + *pfFullscreen = m_bIsFullscreen; + return S_OK; +} + +// IEVRTrustedVideoPlugin +STDMETHODIMP CSyncAP::IsInTrustedVideoMode(BOOL* pYes) +{ + CheckPointer(pYes, E_POINTER); + *pYes = TRUE; + return S_OK; +} + +STDMETHODIMP CSyncAP::CanConstrict(BOOL* pYes) +{ + CheckPointer(pYes, E_POINTER); + *pYes = TRUE; + return S_OK; +} + +STDMETHODIMP CSyncAP::SetConstriction(DWORD dwKPix) +{ + return S_OK; +} + +STDMETHODIMP CSyncAP::DisableImageExport(BOOL bDisable) +{ + return S_OK; +} + +// IDirect3DDeviceManager9 +STDMETHODIMP CSyncAP::ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken) +{ + HRESULT hr = m_pD3DManager->ResetDevice(pDevice, resetToken); + return hr; +} + +STDMETHODIMP CSyncAP::OpenDeviceHandle(HANDLE* phDevice) +{ + HRESULT hr = m_pD3DManager->OpenDeviceHandle(phDevice); + return hr; +} + +STDMETHODIMP CSyncAP::CloseDeviceHandle(HANDLE hDevice) +{ + HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice); + return hr; +} + +STDMETHODIMP CSyncAP::TestDevice(HANDLE hDevice) +{ + HRESULT hr = m_pD3DManager->TestDevice(hDevice); + return hr; +} + +STDMETHODIMP CSyncAP::LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock) +{ + HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock); + return hr; +} + +STDMETHODIMP CSyncAP::UnlockDevice(HANDLE hDevice, BOOL fSaveState) +{ + HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState); + return hr; +} + +STDMETHODIMP CSyncAP::GetVideoService(HANDLE hDevice, REFIID riid, void** ppService) +{ + HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService); + + if (riid == __uuidof(IDirectXVideoDecoderService)) { + UINT nNbDecoder = 5; + GUID* pDecoderGuid; + IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService; + pDXVAVideoDecoder->GetDecoderDeviceGuids(&nNbDecoder, &pDecoderGuid); + } else if (riid == __uuidof(IDirectXVideoProcessorService)) { + IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService; + UNREFERENCED_PARAMETER(pDXVAProcessor); + } + + return hr; +} + +STDMETHODIMP CSyncAP::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) +{ + // This function should be called... + ASSERT(FALSE); + + if (lpWidth) { + *lpWidth = m_nativeVideoSize.cx; + } + if (lpHeight) { + *lpHeight = m_nativeVideoSize.cy; + } + if (lpARWidth) { + *lpARWidth = m_aspectRatio.cx; + } + if (lpARHeight) { + *lpARHeight = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CSyncAP::InitializeDevice(AM_MEDIA_TYPE* pMediaType) +{ + HRESULT hr; + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_allocatorLock); + + RemoveAllSamples(); + DeleteSurfaces(); + + VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*) pMediaType->pbFormat; + int w = vih2->bmiHeader.biWidth; + int h = abs(vih2->bmiHeader.biHeight); + + SetVideoSize(CSize(w, h), m_aspectRatio); + if (m_bHighColorResolution) { + hr = AllocSurfaces(D3DFMT_A2R10G10B10); + } else { + hr = AllocSurfaces(D3DFMT_X8R8G8B8); + } + + for (int i = 0; i < m_nDXSurface; i++) { + CComPtr pMFSample; + hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); + if (SUCCEEDED(hr)) { + pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); + pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + m_FreeSamples.AddTail(pMFSample); + pMFSample = nullptr; // The sample should not be used after being queued + } + ASSERT(SUCCEEDED(hr)); + } + return hr; +} + +DWORD WINAPI CSyncAP::MixerThreadStatic(LPVOID lpParam) +{ + CSyncAP* pThis = (CSyncAP*) lpParam; + pThis->MixerThread(); + return 0; +} + +void CSyncAP::MixerThread() +{ + HANDLE hEvts[] = {m_hEvtQuit}; + bool bQuit = false; + TIMECAPS tc; + DWORD dwResolution; + + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + timeBeginPeriod(dwResolution); + + while (!bQuit) { + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); + switch (dwObject) { + case WAIT_OBJECT_0: + bQuit = true; + break; + case WAIT_TIMEOUT: { + bool bNewSample; + { + CAutoLock AutoLock(&m_ImageProcessingLock); + bNewSample = GetSampleFromMixer(); + } + + if (m_rtTimePerFrame == 0 && bNewSample) { + // Use the code from VMR9 to get the movie fps, as this method is reliable. + CComPtr pPin; + CMediaType mt; + if (SUCCEEDED(m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) && + SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); + + m_bInterlaced = ExtractInterlaced(&mt); + + if (m_rtTimePerFrame > 0) { + m_fps = 10000000.0 / m_rtTimePerFrame; + } + } + + // Update internal subtitle clock + if (m_bUseInternalTimer && m_pSubPicQueue) { + m_pSubPicQueue->SetFPS(m_fps); + } + } + } + break; + } + } + timeEndPeriod(dwResolution); +} + +DWORD WINAPI CSyncAP::RenderThreadStatic(LPVOID lpParam) +{ + CSyncAP* pThis = (CSyncAP*)lpParam; + pThis->RenderThread(); + return 0; +} + +// Get samples that have been received and queued up by MixerThread() and present them at the correct time by calling Paint(). +void CSyncAP::RenderThread() +{ + HANDLE hEvts[] = {m_hEvtQuit, m_hEvtFlush, m_hEvtSkip}; + bool bQuit = false; + TIMECAPS tc; + CComPtr pNewSample; // The sample next in line to be presented + + // Tell Multimedia Class Scheduler we are doing threaded playback (increase priority) + HANDLE hAvrt = 0; + if (fnAvSetMmThreadCharacteristicsW) { + DWORD dwTaskIndex = 0; + hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); + if (fnAvSetMmThreadPriority) { + fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH); + } + } + + // Set timer resolution + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + VERIFY(timeBeginPeriod(dwResolution) == 0); + + auto SubPicSetTime = [&] { + if (!g_bExternalSubtitleTime) { + CSubPicAllocatorPresenterImpl::SetTime(g_tSegmentStart + m_llSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); + } + }; + + auto checkPendingMediaFinished = [this]() { + if (m_bPendingMediaFinished) { + CAutoLock lock(&m_SampleQueueLock); + if (m_ScheduledSamples.IsEmpty()) { + m_bPendingMediaFinished = false; + m_pSink->Notify(EC_COMPLETE, 0, 0); + } + } + }; + + while (!bQuit) { + m_lNextSampleWait = 1; // Default value for running this loop + int nSamplesLeft = 0; + bool stepForward = false; + LONG lDisplayCycle = (LONG)(GetDisplayCycle()); + LONG lDisplayCycle2 = (LONG)(GetDisplayCycle() / 2.0); // These are a couple of empirically determined constants used the control the "snap" function + LONG lDisplayCycle4 = (LONG)(GetDisplayCycle() / 4.0); + + const CRenderersSettings& r = GetRenderersSettings(); + double dTargetSyncOffset = (&r == nullptr) ? 12.0 : r.m_AdvRendSets.fTargetSyncOffset; + + if ((m_nRenderState == Started || !m_bPrerolled) && !pNewSample) { // If either streaming or the pre-roll sample and no sample yet fetched + if (SUCCEEDED(GetScheduledSample(&pNewSample, nSamplesLeft))) { // Get the next sample + m_llLastSampleTime = m_llSampleTime; + if (!m_bPrerolled) { + m_bPrerolled = true; // m_bPrerolled is a ticket to show one (1) frame immediately + m_lNextSampleWait = 0; // Present immediately + } else if (SUCCEEDED(pNewSample->GetSampleTime(&m_llSampleTime))) { // Get zero-based sample due time + if (m_llLastSampleTime == m_llSampleTime) { // In the rare case there are duplicate frames in the movie. There really shouldn't be but it happens. + checkPendingMediaFinished(); + pNewSample = nullptr; + m_lNextSampleWait = 0; + } else { + MFTIME llSystemTime; + LONGLONG llRefClockTime; + m_pClock->GetCorrelatedTime(0, &llRefClockTime, &llSystemTime); // Get zero-based reference clock time. llSystemTime is not used for anything here + m_lNextSampleWait = (LONG)((m_llSampleTime - llRefClockTime) / 10000); // Time left until sample is due, in ms + if (m_bStepping) { + m_lNextSampleWait = 0; + } else if (r.m_AdvRendSets.bSynchronizeNearest) { // Present at the closest "safe" occasion at dTargetSyncOffset ms before vsync to avoid tearing + if (m_lNextSampleWait < -lDisplayCycle) { // We have to allow slightly negative numbers at this stage. Otherwise we get "choking" when frame rate > refresh rate + SetEvent(m_hEvtSkip); + m_bEvtSkip = true; + } + REFERENCE_TIME rtRefClockTimeNow = 0; + if (m_pRefClock) { + m_pRefClock->GetTime(&rtRefClockTimeNow); // Reference clock time now + } + LONG lLastVsyncTime = (LONG)((m_llEstVBlankTime - rtRefClockTimeNow) / 10000); // Last vsync time relative to now + if (abs(lLastVsyncTime) > lDisplayCycle) { + lLastVsyncTime = - lDisplayCycle; // To even out glitches in the beginning + } + + LONGLONG llNextSampleWait = (LONGLONG)((lLastVsyncTime + GetDisplayCycle() - dTargetSyncOffset) * 10000); // Time from now util next safe time to Paint() + while ((llRefClockTime + llNextSampleWait) < (m_llSampleTime + m_llHysteresis)) { // While the proposed time is in the past of sample presentation time + llNextSampleWait = llNextSampleWait + (LONGLONG)(GetDisplayCycle() * 10000); // Try the next possible time, one display cycle ahead + } + m_lNextSampleWait = (LONG)(llNextSampleWait / 10000); + m_lShiftToNearestPrev = m_lShiftToNearest; + m_lShiftToNearest = (LONG)((llRefClockTime + llNextSampleWait - m_llSampleTime) / 10000); // The adjustment made to get to the sweet point in time, in ms + + // If m_lShiftToNearest is pushed a whole cycle into the future, then we are getting more frames + // than we can chew and we need to throw one away. We don't want to wait many cycles and skip many + // frames. + if (m_lShiftToNearest > (lDisplayCycle + 1)) { + SetEvent(m_hEvtSkip); + m_bEvtSkip = true; + } + + // We need to add a hysteresis to the control of the timing adjustment to avoid judder when + // presentation time is close to vsync and the renderer couldn't otherwise make up its mind + // whether to present before the vsync or after. That kind of indecisiveness leads to judder. + if (m_bSnapToVSync) { + + if ((m_lShiftToNearestPrev - m_lShiftToNearest) > lDisplayCycle2) { // If a step down in the m_lShiftToNearest function. Display slower than video. + m_bVideoSlowerThanDisplay = false; + m_llHysteresis = -(LONGLONG)lDisplayCycle4 * 10000; + } else if ((m_lShiftToNearest - m_lShiftToNearestPrev) > lDisplayCycle2) { // If a step up + m_bVideoSlowerThanDisplay = true; + m_llHysteresis = (LONGLONG)lDisplayCycle4 * 10000; + } else if ((m_lShiftToNearest < (3 * lDisplayCycle4)) && (m_lShiftToNearest > lDisplayCycle4)) { + m_llHysteresis = 0; // Reset when between 1/4 and 3/4 of the way either way + } + + if ((m_lShiftToNearest < lDisplayCycle2) && (m_llHysteresis > 0)) { + m_llHysteresis = 0; // Should never really be in this territory. + } + if (m_lShiftToNearest < 0) { + m_llHysteresis = 0; // A glitch might get us to a sticky state where both these numbers are negative. + } + if ((m_lShiftToNearest > lDisplayCycle2) && (m_llHysteresis < 0)) { + m_llHysteresis = 0; + } + } + } + + if (m_lNextSampleWait < 0) { // Skip late or duplicate sample. + SetEvent(m_hEvtSkip); + m_bEvtSkip = true; + } + + if (m_lNextSampleWait > 1000) { + m_lNextSampleWait = 1000; // So as to avoid full a full stop when sample is far in the future (shouldn't really happen). + } + } + } // if got new sample + } else { + checkPendingMediaFinished(); + } + } + // Wait for the next presentation time (m_lNextSampleWait) or some other event. + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, (DWORD)m_lNextSampleWait); + switch (dwObject) { + case WAIT_OBJECT_0: // Quit + bQuit = true; + break; + + case WAIT_OBJECT_0 + 1: // Flush + checkPendingMediaFinished(); + pNewSample = nullptr; + FlushSamples(); + m_bEvtFlush = false; + ResetEvent(m_hEvtFlush); + m_bPrerolled = false; + m_lShiftToNearest = 0; + stepForward = true; + break; + + case WAIT_OBJECT_0 + 2: // Skip sample + m_pcFramesDropped++; + m_llSampleTime = m_llLastSampleTime; // This sample will never be shown + m_bEvtSkip = false; + ResetEvent(m_hEvtSkip); + stepForward = true; + break; + + case WAIT_TIMEOUT: // Time to show the sample or something + if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != r.m_AdvRendSets.iEVROutputRange || m_bPendingRenegotiate) { + checkPendingMediaFinished(); + pNewSample = nullptr; + FlushSamples(); + RenegotiateMediaType(); + m_bPendingRenegotiate = false; + } + + if (m_bPendingResetDevice) { + checkPendingMediaFinished(); + pNewSample = nullptr; + SendResetRequest(); + } else if (m_nStepCount < 0) { + m_nStepCount = 0; + m_pcFramesDropped++; + stepForward = true; + } else if (pNewSample && (m_nStepCount > 0)) { + SubPicSetTime(); + Paint(pNewSample); + CompleteFrameStep(false); + m_pcFramesDrawn++; + stepForward = true; + } else if (pNewSample && !m_bStepping) { // When a stepped frame is shown, a new one is fetched that we don't want to show here while stepping + SubPicSetTime(); + Paint(pNewSample); + m_pcFramesDrawn++; + stepForward = true; + } + break; + } // switch + if (stepForward) { + checkPendingMediaFinished(); + pNewSample = nullptr; + } + } // while + pNewSample = nullptr; + timeEndPeriod(dwResolution); + if (fnAvRevertMmThreadCharacteristics) { + fnAvRevertMmThreadCharacteristics(hAvrt); + } +} + +STDMETHODIMP_(bool) CSyncAP::ResetDevice() +{ + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_allocatorLock); + + RemoveAllSamples(); + + bool bResult = __super::ResetDevice(); + + for (int i = 0; i < m_nDXSurface; i++) { + CComPtr pMFSample; + HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); + if (SUCCEEDED(hr)) { + pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); + pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + m_FreeSamples.AddTail(pMFSample); + pMFSample = nullptr; // The sample should not be used after being queued + } + ASSERT(SUCCEEDED(hr)); + } + return bResult; +} + +void CSyncAP::OnResetDevice() +{ + TRACE(_T("--> CSyncAP::OnResetDevice on thread: %lu\n"), GetCurrentThreadId()); + m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); + if (m_pSink) { + m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); + } + CSize videoSize = GetVisibleVideoSize(); + if (m_pSink) { + m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(videoSize.cx, videoSize.cy), 0); + } +} + +void CSyncAP::RemoveAllSamples() +{ + CAutoLock imageProcesssingLock(&m_ImageProcessingLock); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + + FlushSamples(); + m_ScheduledSamples.RemoveAll(); + m_FreeSamples.RemoveAll(); + m_nUsedBuffer = 0; + // Increment the group id to make sure old samples will really be deleted + m_nCurrentGroupId++; +} + +HRESULT CSyncAP::GetFreeSample(IMFSample** ppSample) +{ + CAutoLock lock(&m_SampleQueueLock); + HRESULT hr = S_OK; + + if (!m_FreeSamples.IsEmpty()) { + m_nUsedBuffer++; + *ppSample = m_FreeSamples.RemoveHead().Detach(); + } else { + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + } + + return hr; +} + +HRESULT CSyncAP::GetScheduledSample(IMFSample** ppSample, int& count) +{ + CAutoLock lock(&m_SampleQueueLock); + HRESULT hr = S_OK; + + count = (int)m_ScheduledSamples.GetCount(); + if (count > 0) { + *ppSample = m_ScheduledSamples.RemoveHead().Detach(); + --count; + } else { + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + } + + return hr; +} + +void CSyncAP::AddToFreeList(IMFSample* pSample, bool bTail) +{ + CAutoLock lock(&m_SampleQueueLock); + + m_nUsedBuffer--; + if (bTail) { + m_FreeSamples.AddTail(pSample); + } else { + m_FreeSamples.AddHead(pSample); + } +} + +void CSyncAP::AddToScheduledList(IMFSample* pSample, bool bSorted) +{ + CAutoLock lock(&m_SampleQueueLock); + + if (bSorted) { + m_ScheduledSamples.AddHead(pSample); + } else { + m_ScheduledSamples.AddTail(pSample); + } +} + +void CSyncAP::FlushSamples() +{ + CAutoLock lock(this); + CAutoLock lock2(&m_SampleQueueLock); + + m_bPrerolled = false; + m_pCurrentlyDisplayedSample = nullptr; + m_ScheduledSamples.RemoveAll(); +} + +HRESULT CSyncAP::TrackSample(IMFSample* pSample) +{ + HRESULT hr = E_FAIL; + if (CComQIPtr pTracked = pSample) { + hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr); + } + return hr; +} + +HRESULT CSyncAP::OnSampleFree(IMFAsyncResult* pResult) +{ + CComPtr pObject; + HRESULT hr = pResult->GetObject(&pObject); + if (SUCCEEDED(hr)) { + if (CComQIPtr pSample = pObject) { + // Ignore the sample if it is from an old group + UINT32 nGroupId; + CAutoLock sampleQueueLock(&m_SampleQueueLock); + if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) { + AddToFreeList(pSample, true); + pSample = nullptr; // The sample should not be used after being queued + } + } + } + return hr; +} + +HRESULT CSyncAP::AdviseSyncClock(ISyncClock* sC) +{ + return m_pGenlock->AdviseSyncClock(sC); +} + +HRESULT CSyncAP::BeginStreaming() +{ + m_pcFramesDropped = 0; + m_pcFramesDrawn = 0; + + CComPtr pEVR; + CFilterInfo filterInfo; + m_pOuterEVR->QueryInterface(IID_PPV_ARGS(&pEVR)); + pEVR->QueryFilterInfo(&filterInfo); + + BeginEnumFilters(filterInfo.pGraph, pEF, pBF); + if (CComQIPtr pAS = pBF) { + m_pAudioStats = pAS; + }; + EndEnumFilters; + + pEVR->GetSyncSource(&m_pRefClock); + m_pGenlock->SetMonitor(GetAdapter(m_pD3D, m_hWnd)); + m_pGenlock->GetTiming(); + + ResetStats(); + EstimateRefreshTimings(); + if (m_dFrameCycle > 0.0) { + m_dCycleDifference = GetCycleDifference(); // Might have moved to another display + } + + m_nRenderState = Paused; + + return S_OK; +} + +HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP) +{ + HRESULT hr = E_FAIL; + if (clsid == CLSID_SyncAllocatorPresenter) { + CString Error; + *ppAP = DEBUG_NEW CSyncAP(hWnd, bFullscreen, hr, Error); + (*ppAP)->AddRef(); + + if (FAILED(hr)) { + Error += L"\n"; + Error += GetWindowsErrorMessage(hr, nullptr); + MessageBox(hWnd, Error, L"Error creating EVR Sync", MB_OK | MB_ICONERROR); + (*ppAP)->Release(); + *ppAP = nullptr; + } else if (!Error.IsEmpty()) { + MessageBox(hWnd, Error, L"Warning creating EVR Sync", MB_OK | MB_ICONWARNING); + } + } + return hr; +} + +CSyncRenderer::CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP* pAllocatorPresenter): CUnknown(pName, pUnk) +{ + hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner()); + CComQIPtr pEVRBase = m_pEVR; + m_pEVRBase = pEVRBase; // Don't keep a second reference on the EVR filter + m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; + m_pAllocatorPresenter = pAllocatorPresenter; +} + +CSyncRenderer::~CSyncRenderer() +{ +} + +HRESULT STDMETHODCALLTYPE CSyncRenderer::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetState(dwMilliSecsTimeout, State); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::EnumPins(__out IEnumPins** ppEnum) +{ + if (m_pEVRBase) { + return m_pEVRBase->EnumPins(ppEnum); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::FindPin(LPCWSTR Id, __out IPin** ppPin) +{ + if (m_pEVRBase) { + return m_pEVRBase->FindPin(Id, ppPin); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::QueryFilterInfo(__out FILTER_INFO* pInfo) +{ + if (m_pEVRBase) { + return m_pEVRBase->QueryFilterInfo(pInfo); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName) +{ + if (m_pEVRBase) { + return m_pEVRBase->JoinFilterGraph(pGraph, pName); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::QueryVendorInfo(__out LPWSTR* pVendorInfo) +{ + if (m_pEVRBase) { + return m_pEVRBase->QueryVendorInfo(pVendorInfo); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::Stop() +{ + if (m_pEVRBase) { + return m_pEVRBase->Stop(); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::Pause() +{ + if (m_pEVRBase) { + return m_pEVRBase->Pause(); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::Run(REFERENCE_TIME tStart) +{ + if (m_pEVRBase) { + return m_pEVRBase->Run(tStart); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::SetSyncSource(__in_opt IReferenceClock* pClock) +{ + if (m_pEVRBase) { + return m_pEVRBase->SetSyncSource(pClock); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::GetSyncSource(__deref_out_opt IReferenceClock** pClock) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetSyncSource(pClock); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::GetClassID(__RPC__out CLSID* pClassID) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetClassID(pClassID); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); + return S_OK; +} + +STDMETHODIMP CSyncRenderer::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} + +STDMETHODIMP CSyncRenderer::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} + +STDMETHODIMP CSyncRenderer::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + HRESULT hr; + + if (riid == __uuidof(IVMRMixerBitmap9)) { + return GetInterface((IVMRMixerBitmap9*)this, ppv); + } + + if (riid == __uuidof(IBaseFilter)) { + return GetInterface((IBaseFilter*)this, ppv); + } + + if (riid == __uuidof(IMediaFilter)) { + return GetInterface((IMediaFilter*)this, ppv); + } + if (riid == __uuidof(IPersist)) { + return GetInterface((IPersist*)this, ppv); + } + if (riid == __uuidof(IBaseFilter)) { + return GetInterface((IBaseFilter*)this, ppv); + } + + hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE; + if (m_pEVR && FAILED(hr)) { + hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; + } + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); +} + +CGenlock::CGenlock(double target, double limit, int lineD, int colD, double clockD, UINT mon) + : powerstripTimingExists(false) + , liveSource(false) + , adjDelta(0) // Number of rows used in display frequency adjustment, typically 1 (one) + , lineDelta(lineD) // Number of columns used in display frequency adjustment, typically 1 - 2 + , columnDelta(colD) // Delta used in clock speed adjustment. In fractions of 1.0. Typically around 0.001 + , cycleDelta(clockD) // The monitor to be adjusted if the display refresh rate is the controlled parameter + , displayAdjustmentsMade(0) + , clockAdjustmentsMade(0) + , totalLines(0) + , totalColumns(0) + , visibleLines(0) + , visibleColumns(0) + , syncOffsetFifo(64) + , frameCycleFifo(4) + , minSyncOffset(DBL_MAX) + , maxSyncOffset(DBL_MIN) + , syncOffsetAvg(0.0) + , minFrameCycle(DBL_MAX) + , maxFrameCycle(DBL_MIN) + , frameCycleAvg(0.0) + , pixelClock(0) + , displayFreqCruise(0.0) + , displayFreqSlower(0.0) + , displayFreqFaster(0.0) + , curDisplayFreq(0.0) + , controlLimit(limit) // How much sync offset is allowed to drift from target sync offset before control kicks in + , monitor(mon) + , psWnd(nullptr) + , displayTiming() + , displayTimingSave() + , lowSyncOffset(target - limit) + , targetSyncOffset(target) // Target sync offset, typically around 10 ms + , highSyncOffset(target + limit) +{ + ZeroMemory(faster, MAX_LOADSTRING); + ZeroMemory(cruise, MAX_LOADSTRING); + ZeroMemory(slower, MAX_LOADSTRING); + ZeroMemory(savedTiming, MAX_LOADSTRING); +} + +CGenlock::~CGenlock() +{ + ResetTiming(); + syncClock = nullptr; +}; + +BOOL CGenlock::PowerstripRunning() +{ + psWnd = FindWindow(_T("TPShidden"), nullptr); + if (!psWnd) { + return FALSE; // Powerstrip is not running + } else { + return TRUE; + } +} + +// Get the display timing parameters through PowerStrip (if running). +HRESULT CGenlock::GetTiming() +{ + ATOM getTiming; + LPARAM lParam = 0; + WPARAM wParam = monitor; + int i = 0; + int j = 0; + int params = 0; + TCHAR tmpStr[MAX_LOADSTRING] = _T(""); + + CAutoLock lock(&csGenlockLock); + if (!PowerstripRunning()) { + return E_FAIL; + } + + getTiming = static_cast(SendMessage(psWnd, UM_GETTIMING, wParam, lParam)); + GlobalGetAtomName(getTiming, savedTiming, MAX_LOADSTRING); + + while (params < TIMING_PARAM_CNT) { + while (savedTiming[i] != _T(',') && savedTiming[i] != _T('\0')) { + tmpStr[j++] = savedTiming[i]; + tmpStr[j] = _T('\0'); + i++; + } + i++; // Skip trailing comma + j = 0; + displayTiming[params] = _ttoi(tmpStr); + displayTimingSave[params] = displayTiming[params]; + params++; + } + + // The display update frequency is controlled by adding and subtracting pixels form the + // image. This is done by either subtracting columns or rows or both. Some displays like + // row adjustments and some column adjustments. One should probably not do both. + StringCchPrintf(faster, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), + displayTiming[0], + displayTiming[HFRONTPORCH] - columnDelta, + displayTiming[2], + displayTiming[3], + displayTiming[4], + displayTiming[VFRONTPORCH] - lineDelta, + displayTiming[6], + displayTiming[7], + displayTiming[PIXELCLOCK], + displayTiming[9] + ); + + // Nominal update frequency + StringCchPrintf(cruise, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), + displayTiming[0], + displayTiming[HFRONTPORCH], + displayTiming[2], + displayTiming[3], + displayTiming[4], + displayTiming[VFRONTPORCH], + displayTiming[6], + displayTiming[7], + displayTiming[PIXELCLOCK], + displayTiming[9] + ); + + // Lower than nominal update frequency + StringCchPrintf(slower, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), + displayTiming[0], + displayTiming[HFRONTPORCH] + columnDelta, + displayTiming[2], + displayTiming[3], + displayTiming[4], + displayTiming[VFRONTPORCH] + lineDelta, + displayTiming[6], + displayTiming[7], + displayTiming[PIXELCLOCK], + displayTiming[9] + ); + + totalColumns = displayTiming[HACTIVE] + displayTiming[HFRONTPORCH] + displayTiming[HSYNCWIDTH] + displayTiming[HBACKPORCH]; + totalLines = displayTiming[VACTIVE] + displayTiming[VFRONTPORCH] + displayTiming[VSYNCWIDTH] + displayTiming[VBACKPORCH]; + pixelClock = 1000 * displayTiming[PIXELCLOCK]; // Pixels/s + displayFreqCruise = (double)pixelClock / (totalLines * totalColumns); // Frames/s + displayFreqSlower = (double)pixelClock / ((totalLines + lineDelta) * (totalColumns + columnDelta)); + displayFreqFaster = (double)pixelClock / ((totalLines - lineDelta) * (totalColumns - columnDelta)); + curDisplayFreq = displayFreqCruise; + GlobalDeleteAtom(getTiming); + adjDelta = 0; + powerstripTimingExists = true; + return S_OK; +} + +// Reset display timing parameters to nominal. +HRESULT CGenlock::ResetTiming() +{ + CAutoLock lock(&csGenlockLock); + + if (!PowerstripRunning()) { + return E_FAIL; + } + + if (displayAdjustmentsMade > 0) { + ATOM setTiming = GlobalAddAtom(cruise); + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, monitor, (LPARAM)setTiming); + GlobalDeleteAtom(setTiming); + curDisplayFreq = displayFreqCruise; + } + adjDelta = 0; + return S_OK; +} + +// Reset reference clock speed to nominal. +HRESULT CGenlock::ResetClock() +{ + adjDelta = 0; + if (syncClock == nullptr) { + return E_FAIL; + } else { + return syncClock->AdjustClock(1.0); + } +} + +HRESULT CGenlock::SetTargetSyncOffset(double targetD) +{ + targetSyncOffset = targetD; + lowSyncOffset = targetD - controlLimit; + highSyncOffset = targetD + controlLimit; + return S_OK; +} + +HRESULT CGenlock::GetTargetSyncOffset(double* targetD) +{ + *targetD = targetSyncOffset; + return S_OK; +} + +HRESULT CGenlock::SetControlLimit(double cL) +{ + controlLimit = cL; + return S_OK; +} + +HRESULT CGenlock::GetControlLimit(double* cL) +{ + *cL = controlLimit; + return S_OK; +} + +HRESULT CGenlock::SetDisplayResolution(UINT columns, UINT lines) +{ + visibleColumns = columns; + visibleLines = lines; + return S_OK; +} + +HRESULT CGenlock::AdviseSyncClock(ISyncClock* sC) +{ + if (!sC) { + return E_FAIL; + } + if (syncClock) { + syncClock = nullptr; // Release any outstanding references if this is called repeatedly + } + syncClock = sC; + return S_OK; +} + +// Set the monitor to control. This is best done manually as not all monitors can be controlled +// so automatic detection of monitor to control might have unintended effects. +// The PowerStrip API uses zero-based monitor numbers, i.e. the default monitor is 0. +HRESULT CGenlock::SetMonitor(UINT mon) +{ + monitor = mon; + return S_OK; +} + +HRESULT CGenlock::ResetStats() +{ + CAutoLock lock(&csGenlockLock); + minSyncOffset = DBL_MAX; + maxSyncOffset = DBL_MIN; + minFrameCycle = DBL_MAX; + maxFrameCycle = DBL_MIN; + displayAdjustmentsMade = 0; + clockAdjustmentsMade = 0; + return S_OK; +} + +// Synchronize by adjusting display refresh rate +HRESULT CGenlock::ControlDisplay(double syncOffset, double frameCycle) +{ + LPARAM lParam = 0; + WPARAM wParam = monitor; + ATOM setTiming; + + const CRenderersSettings& r = GetRenderersSettings(); + targetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset; + lowSyncOffset = targetSyncOffset - r.m_AdvRendSets.fControlLimit; + highSyncOffset = targetSyncOffset + r.m_AdvRendSets.fControlLimit; + + syncOffsetAvg = syncOffsetFifo.Average(syncOffset); + minSyncOffset = std::min(minSyncOffset, syncOffset); + maxSyncOffset = std::max(maxSyncOffset, syncOffset); + frameCycleAvg = frameCycleFifo.Average(frameCycle); + minFrameCycle = std::min(minFrameCycle, frameCycle); + maxFrameCycle = std::max(maxFrameCycle, frameCycle); + + if (!PowerstripRunning() || !powerstripTimingExists) { + return E_FAIL; + } + // Adjust as seldom as possible by checking the current controlState before changing it. + if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1)) + // Speed up display refresh rate by subtracting pixels from the image. + { + adjDelta = 1; // Increase refresh rate + curDisplayFreq = displayFreqFaster; + setTiming = GlobalAddAtom(faster); + lParam = setTiming; + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); + GlobalDeleteAtom(setTiming); + displayAdjustmentsMade++; + } else + // Slow down display refresh rate by adding pixels to the image. + if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1)) { + adjDelta = -1; + curDisplayFreq = displayFreqSlower; + setTiming = GlobalAddAtom(slower); + lParam = setTiming; + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); + GlobalDeleteAtom(setTiming); + displayAdjustmentsMade++; + } else + // Cruise. + if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1)) { + adjDelta = 0; + curDisplayFreq = displayFreqCruise; + setTiming = GlobalAddAtom(cruise); + lParam = setTiming; + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); + GlobalDeleteAtom(setTiming); + displayAdjustmentsMade++; + } else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1)) { + adjDelta = 0; + curDisplayFreq = displayFreqCruise; + setTiming = GlobalAddAtom(cruise); + lParam = setTiming; + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); + GlobalDeleteAtom(setTiming); + displayAdjustmentsMade++; + } + return S_OK; +} + +// Synchronize by adjusting reference clock rate (and therefore video FPS). +// Todo: check so that we don't have a live source +HRESULT CGenlock::ControlClock(double syncOffset, double frameCycle) +{ + const CRenderersSettings& r = GetRenderersSettings(); + targetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset; + lowSyncOffset = targetSyncOffset - r.m_AdvRendSets.fControlLimit; + highSyncOffset = targetSyncOffset + r.m_AdvRendSets.fControlLimit; + + syncOffsetAvg = syncOffsetFifo.Average(syncOffset); + minSyncOffset = std::min(minSyncOffset, syncOffset); + maxSyncOffset = std::max(maxSyncOffset, syncOffset); + frameCycleAvg = frameCycleFifo.Average(frameCycle); + minFrameCycle = std::min(minFrameCycle, frameCycle); + maxFrameCycle = std::max(maxFrameCycle, frameCycle); + + if (!syncClock) { + return E_FAIL; + } + // Adjust as seldom as possible by checking the current controlState before changing it. + if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1)) + // Slow down video stream. + { + adjDelta = 1; + syncClock->AdjustClock(1.0 - cycleDelta); // Makes the clock move slower by providing smaller increments + clockAdjustmentsMade++; + } else + // Speed up video stream. + if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1)) { + adjDelta = -1; + syncClock->AdjustClock(1.0 + cycleDelta); + clockAdjustmentsMade++; + } else + // Cruise. + if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1)) { + adjDelta = 0; + syncClock->AdjustClock(1.0); + clockAdjustmentsMade++; + } else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1)) { + adjDelta = 0; + syncClock->AdjustClock(1.0); + clockAdjustmentsMade++; + } + return S_OK; +} + +// Don't adjust anything, just update the syncOffset stats +HRESULT CGenlock::UpdateStats(double syncOffset, double frameCycle) +{ + syncOffsetAvg = syncOffsetFifo.Average(syncOffset); + minSyncOffset = std::min(minSyncOffset, syncOffset); + maxSyncOffset = std::max(maxSyncOffset, syncOffset); + frameCycleAvg = frameCycleFifo.Average(frameCycle); + minFrameCycle = std::min(minFrameCycle, frameCycle); + maxFrameCycle = std::max(maxFrameCycle, frameCycle); + return S_OK; +} + +STDMETHODIMP CSyncAP::SetD3DFullscreen(bool fEnabled) +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_allocatorLock); + + fullScreenChanged = (fEnabled != m_bIsFullscreen); + m_bIsFullscreen = fEnabled; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetD3DFullscreen(bool* pfEnabled) +{ + CheckPointer(pfEnabled, E_POINTER); + *pfEnabled = m_bIsFullscreen; + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/SyncRenderer.h b/src/filters/renderer/VideoRenderers/SyncRenderer.h index f0f176b8ab9..8ec1120e38c 100644 --- a/src/filters/renderer/VideoRenderers/SyncRenderer.h +++ b/src/filters/renderer/VideoRenderers/SyncRenderer.h @@ -1,686 +1,686 @@ -/* - * (C) 2010-2015, 2017 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 . - * - */ - -#pragma once - -#include "../../../SubPic/ISubPic.h" -#include "RenderersSettings.h" -#include "SyncAllocatorPresenter.h" -#include "AllocatorCommon.h" -#include "../../../DSUtil/WinapiFunc.h" -#include -#include -#include "d3dx9/d3dx9.h" - -#define VMRBITMAP_UPDATE 0x80000000 -#define MAX_PICTURE_SLOTS (60 + 2) // Last 2 for pixels shader! -#define NB_JITTER 126 -#include "AsyncCallback.h" - -class CFocusThread; - -// Possible messages to the PowerStrip API. PowerStrip is used to control -// the display frequency in one of the video - display synchronization modes. -// Powerstrip can also through a CGenlock object give very accurate timing data -// (given) that the gfx board is supported by PS. -#define UM_SETCUSTOMTIMING (WM_USER + 200) -#define UM_SETREFRESHRATE (WM_USER + 201) -#define UM_SETPOLARITY (WM_USER + 202) -#define UM_REMOTECONTROL (WM_USER + 210) -#define UM_SETGAMMARAMP (WM_USER + 203) -#define UM_CREATERESOLUTION (WM_USER + 204) -#define UM_GETTIMING (WM_USER + 205) -#define UM_SETCUSTOMTIMINGFAST (WM_USER + 211) // Sets timing without writing to file. Faster - -#define PositiveHorizontalPolarity 0x00 -#define PositiveVerticalPolarity 0x00 -#define NegativeHorizontalPolarity 0x02 -#define NegativeVerticalPolarity 0x04 -#define HideTrayIcon 0x00 -#define ShowTrayIcon 0x01 -#define ClosePowerStrip 0x63 - -#define HACTIVE 0 -#define HFRONTPORCH 1 -#define HSYNCWIDTH 2 -#define HBACKPORCH 3 -#define VACTIVE 4 -#define VFRONTPORCH 5 -#define VSYNCWIDTH 6 -#define VBACKPORCH 7 -#define PIXELCLOCK 8 -#define UNKNOWN 9 - -// Guid to tag IMFSample with a group id -static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } }; -// Guid to tag IMFSample with DirectX surface index -static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } }; - -namespace GothSync -{ - enum EVR_STATS_MSG { - MSG_MIXERIN, - MSG_MIXEROUT, - MSG_ERROR - }; - -#pragma pack(push, 1) - - template - struct MYD3DVERTEX { - float x, y, z, rhw; - struct { - float u, v; - } t[texcoords]; - }; - - template<> - struct MYD3DVERTEX<0> { - float x, y, z, rhw; - DWORD Diffuse; - }; - -#pragma pack(pop) - - class CGenlock; - class CSyncRenderer; - - // Base allocator-presenter - class CBaseAP: - public CSubPicAllocatorPresenterImpl - { - protected: - CRenderersSettings::CAdvRendererSettings m_LastRendererSettings; - - HMODULE m_hDWMAPI; - HRESULT(__stdcall* m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled); - HRESULT(__stdcall* m_pDwmEnableComposition)(UINT uCompositionAction); - - CCritSec m_allocatorLock; - CComPtr m_pD3DEx; - CComPtr m_pD3D; - CComPtr m_pD3DDevEx; - CComPtr m_pD3DDev; - - CComPtr m_pVideoTexture[MAX_PICTURE_SLOTS]; - CComPtr m_pVideoSurface[MAX_PICTURE_SLOTS]; - CComPtr m_pOSDTexture; - CComPtr m_pOSDSurface; - CComPtr m_pLine; - CComPtr m_pFont; - CComPtr m_pSprite; - CSyncRenderer* m_pOuterEVR; - - class CExternalPixelShader - { - public: - CComPtr m_pPixelShader; - CStringA m_SourceData; - CStringA m_SourceTarget; - HRESULT Compile(CPixelShaderCompiler* pCompiler) { - HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); - if (FAILED(hr)) { - return hr; - } - return S_OK; - } - }; - - CAutoPtr m_pPSC; - CAtlList m_pPixelShaders; - CAtlList m_pPixelShadersScreenSpace; - CComPtr m_pResizerPixelShader[4]; // bl, bc1, bc2_1, bc2_2 - CComPtr m_pScreenSizeTemporaryTexture[2]; - - D3DFORMAT m_SurfaceType; - D3DFORMAT m_BackbufferType; - D3DFORMAT m_DisplayType; - D3DTEXTUREFILTERTYPE m_filter; - D3DCAPS9 m_caps; - D3DPRESENT_PARAMETERS m_pp; - - bool SettingsNeedResetDevice(); - void SendResetRequest(); - virtual HRESULT CreateDXDevice(CString& _Error); - virtual HRESULT ResetDXDevice(CString& _Error); - virtual HRESULT AllocSurfaces(D3DFORMAT Format = D3DFMT_A8R8G8B8); - virtual void DeleteSurfaces(); - - LONGLONG m_LastAdapterCheck; - UINT m_CurrentAdapter; - - float m_bicubicA; - HRESULT InitResizers(float bicubicA, bool bNeedScreenSizeTexture); - - // Functions to trace timing performance - void SyncStats(LONGLONG syncTime); - void SyncOffsetStats(LONGLONG syncOffset); - void InitStats(); - void DrawStats(); - - template - void AdjustQuad(MYD3DVERTEX* v, double dx, double dy); - template - HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter); - MFOffset GetOffset(float v); - MFVideoArea GetArea(float x, float y, DWORD width, DWORD height); - bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d); - - HRESULT DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]); - HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect); - HRESULT TextureCopy(IDirect3DTexture9* pTexture); - HRESULT TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& SrcRect); - HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); - HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); - HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); - HRESULT Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect); - - typedef HRESULT(WINAPI* D3DXLoadSurfaceFromMemoryPtr)( - LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY* pDestPalette, - CONST RECT* pDestRect, - LPCVOID pSrcMemory, - D3DFORMAT SrcFormat, - UINT SrcPitch, - CONST PALETTEENTRY* pSrcPalette, - CONST RECT* pSrcRect, - DWORD Filter, - D3DCOLOR ColorKey); - - typedef HRESULT(WINAPI* D3DXLoadSurfaceFromSurfacePtr)( - LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY* pDestPalette, - CONST RECT* pDestRect, - LPDIRECT3DSURFACE9 pSrcSurface, - CONST PALETTEENTRY* pSrcPalette, - CONST RECT* pSrcRect, - DWORD Filter, - D3DCOLOR ColorKey); - - typedef HRESULT(WINAPI* D3DXCreateLinePtr) - (LPDIRECT3DDEVICE9 pDevice, - LPD3DXLINE* ppLine); - - typedef HRESULT(WINAPI* D3DXCreateFontPtr)( - LPDIRECT3DDEVICE9 pDevice, - int Height, - UINT Width, - UINT Weight, - UINT MipLevels, - bool Italic, - DWORD CharSet, - DWORD OutputPrecision, - DWORD Quality, - DWORD PitchAndFamily, - LPCWSTR pFaceName, - LPD3DXFONT* ppFont); - - HRESULT AlphaBlt(RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); - - virtual void OnResetDevice() {}; - - int m_nTearingPos; - VMR9AlphaBitmap m_VMR9AlphaBitmap; - CAutoVectorPtr m_VMR9AlphaBitmapData; - CRect m_VMR9AlphaBitmapRect; - int m_VMR9AlphaBitmapWidthBytes; - - D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory; - D3DXLoadSurfaceFromSurfacePtr m_pD3DXLoadSurfaceFromSurface; - D3DXCreateLinePtr m_pD3DXCreateLine; - D3DXCreateFontPtr m_pD3DXCreateFont; - HRESULT(__stdcall* m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); - - int m_nDXSurface; // Total number of DX Surfaces - int m_nVMR9Surfaces; - int m_iVMR9Surface; - int m_nCurSurface; // Surface currently displayed - long m_nUsedBuffer; - - LONG m_lNextSampleWait; // Waiting time for next sample in EVR - bool m_bSnapToVSync; // True if framerate is low enough so that snap to vsync makes sense - - UINT m_uScanLineEnteringPaint; // The active scan line when entering Paint() - REFERENCE_TIME m_llEstVBlankTime; // Next vblank start time in reference clock "coordinates" - - double m_fAvrFps; // Estimate the true FPS as given by the distance between vsyncs when a frame has been presented - double m_fJitterStdDev; // VSync estimate std dev - double m_fJitterMean; // Means time between two syncpulses when a frame has been presented (i.e. when Paint() has been called - - double m_fSyncOffsetAvr; // Means time between the call of Paint() and vsync. To avoid tearing this should be several ms at least - double m_fSyncOffsetStdDev; // The std dev of the above - - bool m_bHighColorResolution; - bool m_bCompositionEnabled; - bool m_bDesktopCompositionDisabled; - bool m_bIsFullscreen, fullScreenChanged; - bool m_bNeedCheckSample; - DWORD m_dMainThreadId; - - CSize m_ScreenSize; - - // Display and frame rates and cycles - double m_dDetectedScanlineTime; // Time for one (horizontal) scan line. Extracted at stream start and used to calculate vsync time - double m_dD3DRefreshCycle; // Display refresh cycle ms - double m_dEstRefreshCycle; // As estimated from scan lines - double m_dFrameCycle; // Average sample time, extracted from the samples themselves - // double m_fps is defined in ISubPic.h - double m_dOptimumDisplayCycle; // The display cycle that is closest to the frame rate. A multiple of the actual display cycle - double m_dCycleDifference; // Difference in video and display cycle time relative to the video cycle time - - UINT m_pcFramesDropped; - UINT m_pcFramesDuplicated; - UINT m_pcFramesDrawn; - - LONGLONG m_pllJitter [NB_JITTER]; // Vertical sync time stats - LONGLONG m_pllSyncOffset [NB_JITTER]; // Sync offset time stats - int m_nNextJitter; - int m_nNextSyncOffset; - LONGLONG m_JitterStdDev; - - LONGLONG m_llLastSyncTime; - - LONGLONG m_MaxJitter; - LONGLONG m_MinJitter; - LONGLONG m_MaxSyncOffset; - LONGLONG m_MinSyncOffset; - UINT m_uSyncGlitches; - - LONGLONG m_llSampleTime, m_llLastSampleTime; // Present time for the current sample - LONGLONG m_llHysteresis; - LONG m_lShiftToNearest, m_lShiftToNearestPrev; - bool m_bVideoSlowerThanDisplay; - - REFERENCE_TIME m_rtTimePerFrame; - bool m_bInterlaced; - double m_TextScale; - CString m_strStatsMsg[10]; - - CGenlock* m_pGenlock; // The video - display synchronizer class - CComPtr m_pRefClock; // The reference clock. Used in Paint() - CComPtr m_pAudioStats; // Audio statistics from audio renderer. To check so that audio is in sync - DWORD m_lAudioLag; // Time difference between audio and video when the audio renderer is matching rate to the external reference clock - long m_lAudioLagMin, m_lAudioLagMax; // The accumulated difference between the audio renderer and the master clock - DWORD m_lAudioSlaveMode; // To check whether the audio renderer matches rate with SyncClock (returns the value 4 if it does) - - double GetRefreshRate(); // Get the best estimate of the display refresh rate in Hz - double GetDisplayCycle(); // Get the best estimate of the display cycle time in milliseconds - double GetCycleDifference(); // Get the difference in video and display cycle times. - void EstimateRefreshTimings(); // Estimate the times for one scan line and one frame respectively from the actual refresh data - bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt); - - CFocusThread* m_FocusThread; - HWND m_hFocusWindow; - - public: - CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); - ~CBaseAP(); - - CCritSec m_VMR9AlphaBitmapLock; - void UpdateAlphaBitmap(); - void ResetStats(); - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); - STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); - STDMETHODIMP_(bool) ResetDevice(); - STDMETHODIMP_(bool) DisplayChange(); - }; - - class CSyncAP: - public CBaseAP, - public IMFGetService, - public IMFTopologyServiceLookupClient, - public IMFVideoDeviceID, - public IMFVideoPresenter, - public IDirect3DDeviceManager9, - public IMFAsyncCallback, - public IQualProp, - public IMFRateSupport, - public IMFVideoDisplayControl, - public IEVRTrustedVideoPlugin, - public ISyncClockAdviser, - public ID3DFullscreenControl - { - public: - CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); - ~CSyncAP(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); - STDMETHODIMP InitializeDevice(AM_MEDIA_TYPE* pMediaType); - STDMETHODIMP_(bool) ResetDevice(); - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() { - return (m_nRenderState == Started); - } - - // IMFClockStateSink - STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset); - STDMETHODIMP OnClockStop(MFTIME hnsSystemTime); - STDMETHODIMP OnClockPause(MFTIME hnsSystemTime); - STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime); - STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate); - - // IBaseFilter delegate - bool GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue); - - // IQualProp (EVR statistics window). These are incompletely implemented currently - STDMETHODIMP get_FramesDroppedInRenderer(int* pcFrames); - STDMETHODIMP get_FramesDrawn(int* pcFramesDrawn); - STDMETHODIMP get_AvgFrameRate(int* piAvgFrameRate); - STDMETHODIMP get_Jitter(int* iJitter); - STDMETHODIMP get_AvgSyncOffset(int* piAvg); - STDMETHODIMP get_DevSyncOffset(int* piDev); - - // IMFRateSupport - STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); - STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); - STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate); - float GetMaxRate(BOOL bThin); - - // IMFVideoPresenter - STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam); - STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType); - - // IMFTopologyServiceLookupClient - STDMETHODIMP InitServicePointers(__in IMFTopologyServiceLookup* pLookup); - STDMETHODIMP ReleaseServicePointers(); - - // IMFVideoDeviceID - STDMETHODIMP GetDeviceID(__out IID* pDeviceID); - - // IMFGetService - STDMETHODIMP GetService(__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppvObject); - - // IMFAsyncCallback - STDMETHODIMP GetParameters(__RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue); - STDMETHODIMP Invoke(__RPC__in_opt IMFAsyncResult* pAsyncResult); - - // IMFVideoDisplayControl - STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo); - STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax); - STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest); - STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest); - STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode); - STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode); - STDMETHODIMP SetVideoWindow(HWND hwndVideo); - STDMETHODIMP GetVideoWindow(HWND* phwndVideo); - STDMETHODIMP RepaintVideo(); - STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp); - STDMETHODIMP SetBorderColor(COLORREF Clr); - STDMETHODIMP GetBorderColor(COLORREF* pClr); - STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags); - STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags); - STDMETHODIMP SetFullscreen(BOOL fFullscreen); - STDMETHODIMP GetFullscreen(BOOL* pfFullscreen); - - // IEVRTrustedVideoPlugin - STDMETHODIMP IsInTrustedVideoMode(BOOL* pYes); - STDMETHODIMP CanConstrict(BOOL* pYes); - STDMETHODIMP SetConstriction(DWORD dwKPix); - STDMETHODIMP DisableImageExport(BOOL bDisable); - - // IDirect3DDeviceManager9 - STDMETHODIMP ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken); - STDMETHODIMP OpenDeviceHandle(HANDLE* phDevice); - STDMETHODIMP CloseDeviceHandle(HANDLE hDevice); - STDMETHODIMP TestDevice(HANDLE hDevice); - STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock); - STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState); - STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void** ppService); - - // ID3DFullscreenControl - STDMETHODIMP SetD3DFullscreen(bool fEnabled); - STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); - - protected: - STDMETHODIMP_(bool) Paint(IMFSample* pMFSample); - void OnResetDevice(); - MFCLOCK_STATE m_LastClockState; - - private: - enum RENDER_STATE { - Started = State_Running, - Stopped = State_Stopped, - Paused = State_Paused, - Shutdown = State_Running + 1 - }; - - CComPtr m_pClock; - CComPtr m_pD3DManager; - CComPtr m_pMixer; - CComPtr m_pSink; - CComPtr m_pMediaType; - MFVideoAspectRatioMode m_dwVideoAspectRatioMode; - MFVideoRenderPrefs m_dwVideoRenderPrefs; - COLORREF m_BorderColor; - - HANDLE m_hEvtQuit; // Stop rendering thread event - bool m_bEvtQuit; - HANDLE m_hEvtFlush; // Discard all buffers - bool m_bEvtFlush; - HANDLE m_hEvtSkip; // Skip frame - bool m_bEvtSkip; - - bool m_bUseInternalTimer; - INT32 m_LastSetOutputRange; - std::atomic_bool m_bPendingRenegotiate; - bool m_bPendingMediaFinished; - bool m_bPrerolled; // true if first sample has been displayed. - - HANDLE m_hRenderThread; - HANDLE m_hMixerThread; - RENDER_STATE m_nRenderState; - bool m_bStepping; - - CCritSec m_SampleQueueLock; - CCritSec m_ImageProcessingLock; - - UINT32 m_nCurrentGroupId; - CInterfaceList m_FreeSamples; - CInterfaceList m_ScheduledSamples; - CComPtr m_pCurrentlyDisplayedSample; - UINT m_nResetToken; - int m_nStepCount; - - bool GetSampleFromMixer(); - void MixerThread(); - static DWORD WINAPI MixerThreadStatic(LPVOID lpParam); - void RenderThread(); - static DWORD WINAPI RenderThreadStatic(LPVOID lpParam); - - void StartWorkerThreads(); - void StopWorkerThreads(); - HRESULT CheckShutdown() const; - void CompleteFrameStep(bool bCancel); - - void RemoveAllSamples(); - STDMETHODIMP AdviseSyncClock(ISyncClock* sC); - HRESULT BeginStreaming(); - HRESULT GetFreeSample(IMFSample** ppSample); - HRESULT GetScheduledSample(IMFSample** ppSample, int& count); - void AddToFreeList(IMFSample* pSample, bool bTail); - void AddToScheduledList(IMFSample* pSample, bool bSorted); - void FlushSamples(); - - HRESULT TrackSample(IMFSample* pSample); - - // Callback when a video sample is released. - HRESULT OnSampleFree(IMFAsyncResult* pResult); - AsyncCallback m_SampleFreeCallback; - - LONGLONG GetMediaTypeMerit(IMFMediaType* pMediaType); - HRESULT RenegotiateMediaType(); - HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType); - HRESULT CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType); - HRESULT SetMediaType(IMFMediaType* pType); - - const WinapiFunc fnDXVA2CreateDirect3DDeviceManager9; - const WinapiFunc fnMFCreateDXSurfaceBuffer; - const WinapiFunc fnMFCreateVideoSampleFromSurface; - const WinapiFunc fnMFCreateMediaType; - - const WinapiFunc fnAvSetMmThreadCharacteristicsW; - const WinapiFunc fnAvSetMmThreadPriority; - const WinapiFunc fnAvRevertMmThreadCharacteristics; - }; - - class CSyncRenderer: - public CUnknown, - public IVMRMixerBitmap9, - public IBaseFilter - { - CComPtr m_pEVR; - IBaseFilter* m_pEVRBase; - VMR9AlphaBitmap* m_pVMR9AlphaBitmap; - CSyncAP* m_pAllocatorPresenter; - - public: - CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP* pAllocatorPresenter); - ~CSyncRenderer(); - - // IBaseFilter - virtual HRESULT STDMETHODCALLTYPE EnumPins(__out IEnumPins** ppEnum); - virtual HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, __out IPin** ppPin); - virtual HRESULT STDMETHODCALLTYPE QueryFilterInfo(__out FILTER_INFO* pInfo); - virtual HRESULT STDMETHODCALLTYPE JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName); - virtual HRESULT STDMETHODCALLTYPE QueryVendorInfo(__out LPWSTR* pVendorInfo); - virtual HRESULT STDMETHODCALLTYPE Stop(); - virtual HRESULT STDMETHODCALLTYPE Pause(); - virtual HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); - virtual HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State); - virtual HRESULT STDMETHODCALLTYPE SetSyncSource(__in_opt IReferenceClock* pClock); - virtual HRESULT STDMETHODCALLTYPE GetSyncSource(__deref_out_opt IReferenceClock** pClock); - virtual HRESULT STDMETHODCALLTYPE GetClassID(__RPC__out CLSID* pClassID); - - // IVMRMixerBitmap9 - STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); - - DECLARE_IUNKNOWN; - virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid, void** ppvObject); - }; - - class CGenlock - { - public: - class MovingAverage - { - public: - MovingAverage(size_t size) - : fifoSize(size) - , fifo(fifoSize) - , oldestSample(0) - , sum(0.0) { - } - - double Average(double sample) { - sum = sum + sample - fifo[oldestSample]; - fifo[oldestSample] = sample; - oldestSample++; - if (oldestSample == fifoSize) { - oldestSample = 0; - } - return sum / fifoSize; - } - - private: - size_t fifoSize; - std::vector fifo; - size_t oldestSample; - double sum; - }; - - CGenlock(double target, double limit, int rowD, int colD, double clockD, UINT mon); - CGenlock(const CGenlock&) = delete; - ~CGenlock(); - - CGenlock& operator=(const CGenlock&) = delete; - - BOOL PowerstripRunning(); // TRUE if PowerStrip is running - HRESULT GetTiming(); // Get the string representing the display's current timing parameters - HRESULT ResetTiming(); // Reset timing to what was last registered by GetTiming() - HRESULT ResetClock(); // Reset reference clock speed to nominal - HRESULT SetTargetSyncOffset(double targetD); - HRESULT GetTargetSyncOffset(double* targetD); - HRESULT SetControlLimit(double cL); - HRESULT GetControlLimit(double* cL); - HRESULT SetDisplayResolution(UINT columns, UINT lines); - HRESULT AdviseSyncClock(ISyncClock* sC); - HRESULT SetMonitor(UINT mon); // Set the number of the monitor to synchronize - HRESULT ResetStats(); // Reset timing statistics - - HRESULT ControlDisplay(double syncOffset, double frameCycle); // Adjust the frequency of the display if needed - HRESULT ControlClock(double syncOffset, double frameCycle); // Adjust the frequency of the clock if needed - HRESULT UpdateStats(double syncOffset, double frameCycle); // Don't adjust anything, just update the syncOffset stats - - bool powerstripTimingExists; // true if display timing has been got through Powerstrip - bool liveSource; // true if live source -> display sync is the only option - int adjDelta; // -1 for display slower in relation to video, 0 for keep, 1 for faster - int lineDelta; // The number of rows added or subtracted when adjusting display fps - int columnDelta; // The number of colums added or subtracted when adjusting display fps - double cycleDelta; // Adjustment factor for cycle time as fraction of nominal value - UINT displayAdjustmentsMade; // The number of adjustments made to display refresh rate - UINT clockAdjustmentsMade; // The number of adjustments made to clock frequency - - UINT totalLines, totalColumns; // Including the porches and sync widths - UINT visibleLines, visibleColumns; // The nominal resolution - MovingAverage syncOffsetFifo; - MovingAverage frameCycleFifo; - double minSyncOffset, maxSyncOffset; - double syncOffsetAvg; // Average of the above - double minFrameCycle, maxFrameCycle; - double frameCycleAvg; - - UINT pixelClock; // In pixels/s - double displayFreqCruise; // Nominal display frequency in frames/s - double displayFreqSlower; - double displayFreqFaster; - double curDisplayFreq; // Current (adjusted) display frequency - double controlLimit; // How much the sync offset is allowed to drift from target sync offset - WPARAM monitor; // The monitor to be controlled. 0-based. - CComPtr syncClock; // Interface to an adjustable reference clock - - private: - HWND psWnd; // PowerStrip window - const static int TIMING_PARAM_CNT = 10; - const static int MAX_LOADSTRING = 100; - std::array displayTiming; // Display timing parameters - std::array displayTimingSave; // So that we can reset the display at exit - TCHAR faster[MAX_LOADSTRING]; // String corresponding to faster display frequency - TCHAR cruise[MAX_LOADSTRING]; // String corresponding to nominal display frequency - TCHAR slower[MAX_LOADSTRING]; // String corresponding to slower display frequency - TCHAR savedTiming[MAX_LOADSTRING]; // String version of saved timing (to be restored upon exit) - double lowSyncOffset; // The closest we want to let the scheduled render time to get to the next vsync. In % of the frame time - double targetSyncOffset; // Where we want the scheduled render time to be in relation to the next vsync - double highSyncOffset; // The furthers we want to let the scheduled render time to get to the next vsync - CCritSec csGenlockLock; - }; -} +/* + * (C) 2010-2015, 2017 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 . + * + */ + +#pragma once + +#include "../../../SubPic/ISubPic.h" +#include "RenderersSettings.h" +#include "SyncAllocatorPresenter.h" +#include "AllocatorCommon.h" +#include "../../../DSUtil/WinapiFunc.h" +#include +#include +#include "d3dx9/d3dx9.h" + +#define VMRBITMAP_UPDATE 0x80000000 +#define MAX_PICTURE_SLOTS (60 + 2) // Last 2 for pixels shader! +#define NB_JITTER 126 +#include "AsyncCallback.h" + +class CFocusThread; + +// Possible messages to the PowerStrip API. PowerStrip is used to control +// the display frequency in one of the video - display synchronization modes. +// Powerstrip can also through a CGenlock object give very accurate timing data +// (given) that the gfx board is supported by PS. +#define UM_SETCUSTOMTIMING (WM_USER + 200) +#define UM_SETREFRESHRATE (WM_USER + 201) +#define UM_SETPOLARITY (WM_USER + 202) +#define UM_REMOTECONTROL (WM_USER + 210) +#define UM_SETGAMMARAMP (WM_USER + 203) +#define UM_CREATERESOLUTION (WM_USER + 204) +#define UM_GETTIMING (WM_USER + 205) +#define UM_SETCUSTOMTIMINGFAST (WM_USER + 211) // Sets timing without writing to file. Faster + +#define PositiveHorizontalPolarity 0x00 +#define PositiveVerticalPolarity 0x00 +#define NegativeHorizontalPolarity 0x02 +#define NegativeVerticalPolarity 0x04 +#define HideTrayIcon 0x00 +#define ShowTrayIcon 0x01 +#define ClosePowerStrip 0x63 + +#define HACTIVE 0 +#define HFRONTPORCH 1 +#define HSYNCWIDTH 2 +#define HBACKPORCH 3 +#define VACTIVE 4 +#define VFRONTPORCH 5 +#define VSYNCWIDTH 6 +#define VBACKPORCH 7 +#define PIXELCLOCK 8 +#define UNKNOWN 9 + +// Guid to tag IMFSample with a group id +static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } }; +// Guid to tag IMFSample with DirectX surface index +static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } }; + +namespace GothSync +{ + enum EVR_STATS_MSG { + MSG_MIXERIN, + MSG_MIXEROUT, + MSG_ERROR + }; + +#pragma pack(push, 1) + + template + struct MYD3DVERTEX { + float x, y, z, rhw; + struct { + float u, v; + } t[texcoords]; + }; + + template<> + struct MYD3DVERTEX<0> { + float x, y, z, rhw; + DWORD Diffuse; + }; + +#pragma pack(pop) + + class CGenlock; + class CSyncRenderer; + + // Base allocator-presenter + class CBaseAP: + public CSubPicAllocatorPresenterImpl + { + protected: + CRenderersSettings::CAdvRendererSettings m_LastRendererSettings; + + HMODULE m_hDWMAPI; + HRESULT(__stdcall* m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled); + HRESULT(__stdcall* m_pDwmEnableComposition)(UINT uCompositionAction); + + CCritSec m_allocatorLock; + CComPtr m_pD3DEx; + CComPtr m_pD3D; + CComPtr m_pD3DDevEx; + CComPtr m_pD3DDev; + + CComPtr m_pVideoTexture[MAX_PICTURE_SLOTS]; + CComPtr m_pVideoSurface[MAX_PICTURE_SLOTS]; + CComPtr m_pOSDTexture; + CComPtr m_pOSDSurface; + CComPtr m_pLine; + CComPtr m_pFont; + CComPtr m_pSprite; + CSyncRenderer* m_pOuterEVR; + + class CExternalPixelShader + { + public: + CComPtr m_pPixelShader; + CStringA m_SourceData; + CStringA m_SourceTarget; + HRESULT Compile(CPixelShaderCompiler* pCompiler) { + HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); + if (FAILED(hr)) { + return hr; + } + return S_OK; + } + }; + + CAutoPtr m_pPSC; + CAtlList m_pPixelShaders; + CAtlList m_pPixelShadersScreenSpace; + CComPtr m_pResizerPixelShader[4]; // bl, bc1, bc2_1, bc2_2 + CComPtr m_pScreenSizeTemporaryTexture[2]; + + D3DFORMAT m_SurfaceType; + D3DFORMAT m_BackbufferType; + D3DFORMAT m_DisplayType; + D3DTEXTUREFILTERTYPE m_filter; + D3DCAPS9 m_caps; + D3DPRESENT_PARAMETERS m_pp; + + bool SettingsNeedResetDevice(); + void SendResetRequest(); + virtual HRESULT CreateDXDevice(CString& _Error); + virtual HRESULT ResetDXDevice(CString& _Error); + virtual HRESULT AllocSurfaces(D3DFORMAT Format = D3DFMT_A8R8G8B8); + virtual void DeleteSurfaces(); + + LONGLONG m_LastAdapterCheck; + UINT m_CurrentAdapter; + + float m_bicubicA; + HRESULT InitResizers(float bicubicA, bool bNeedScreenSizeTexture); + + // Functions to trace timing performance + void SyncStats(LONGLONG syncTime); + void SyncOffsetStats(LONGLONG syncOffset); + void InitStats(); + void DrawStats(); + + template + void AdjustQuad(MYD3DVERTEX* v, double dx, double dy); + template + HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter); + MFOffset GetOffset(float v); + MFVideoArea GetArea(float x, float y, DWORD width, DWORD height); + bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d); + + HRESULT DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]); + HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect); + HRESULT TextureCopy(IDirect3DTexture9* pTexture); + HRESULT TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& SrcRect); + HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); + HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); + HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); + HRESULT Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect); + + typedef HRESULT(WINAPI* D3DXLoadSurfaceFromMemoryPtr)( + LPDIRECT3DSURFACE9 pDestSurface, + CONST PALETTEENTRY* pDestPalette, + CONST RECT* pDestRect, + LPCVOID pSrcMemory, + D3DFORMAT SrcFormat, + UINT SrcPitch, + CONST PALETTEENTRY* pSrcPalette, + CONST RECT* pSrcRect, + DWORD Filter, + D3DCOLOR ColorKey); + + typedef HRESULT(WINAPI* D3DXLoadSurfaceFromSurfacePtr)( + LPDIRECT3DSURFACE9 pDestSurface, + CONST PALETTEENTRY* pDestPalette, + CONST RECT* pDestRect, + LPDIRECT3DSURFACE9 pSrcSurface, + CONST PALETTEENTRY* pSrcPalette, + CONST RECT* pSrcRect, + DWORD Filter, + D3DCOLOR ColorKey); + + typedef HRESULT(WINAPI* D3DXCreateLinePtr) + (LPDIRECT3DDEVICE9 pDevice, + LPD3DXLINE* ppLine); + + typedef HRESULT(WINAPI* D3DXCreateFontPtr)( + LPDIRECT3DDEVICE9 pDevice, + int Height, + UINT Width, + UINT Weight, + UINT MipLevels, + bool Italic, + DWORD CharSet, + DWORD OutputPrecision, + DWORD Quality, + DWORD PitchAndFamily, + LPCWSTR pFaceName, + LPD3DXFONT* ppFont); + + HRESULT AlphaBlt(RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); + + virtual void OnResetDevice() {}; + + int m_nTearingPos; + VMR9AlphaBitmap m_VMR9AlphaBitmap; + CAutoVectorPtr m_VMR9AlphaBitmapData; + CRect m_VMR9AlphaBitmapRect; + int m_VMR9AlphaBitmapWidthBytes; + + D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory; + D3DXLoadSurfaceFromSurfacePtr m_pD3DXLoadSurfaceFromSurface; + D3DXCreateLinePtr m_pD3DXCreateLine; + D3DXCreateFontPtr m_pD3DXCreateFont; + HRESULT(__stdcall* m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); + + int m_nDXSurface; // Total number of DX Surfaces + int m_nVMR9Surfaces; + int m_iVMR9Surface; + int m_nCurSurface; // Surface currently displayed + long m_nUsedBuffer; + + LONG m_lNextSampleWait; // Waiting time for next sample in EVR + bool m_bSnapToVSync; // True if framerate is low enough so that snap to vsync makes sense + + UINT m_uScanLineEnteringPaint; // The active scan line when entering Paint() + REFERENCE_TIME m_llEstVBlankTime; // Next vblank start time in reference clock "coordinates" + + double m_fAvrFps; // Estimate the true FPS as given by the distance between vsyncs when a frame has been presented + double m_fJitterStdDev; // VSync estimate std dev + double m_fJitterMean; // Means time between two syncpulses when a frame has been presented (i.e. when Paint() has been called + + double m_fSyncOffsetAvr; // Means time between the call of Paint() and vsync. To avoid tearing this should be several ms at least + double m_fSyncOffsetStdDev; // The std dev of the above + + bool m_bHighColorResolution; + bool m_bCompositionEnabled; + bool m_bDesktopCompositionDisabled; + bool m_bIsFullscreen, fullScreenChanged; + bool m_bNeedCheckSample; + DWORD m_dMainThreadId; + + CSize m_ScreenSize; + + // Display and frame rates and cycles + double m_dDetectedScanlineTime; // Time for one (horizontal) scan line. Extracted at stream start and used to calculate vsync time + double m_dD3DRefreshCycle; // Display refresh cycle ms + double m_dEstRefreshCycle; // As estimated from scan lines + double m_dFrameCycle; // Average sample time, extracted from the samples themselves + // double m_fps is defined in ISubPic.h + double m_dOptimumDisplayCycle; // The display cycle that is closest to the frame rate. A multiple of the actual display cycle + double m_dCycleDifference; // Difference in video and display cycle time relative to the video cycle time + + UINT m_pcFramesDropped; + UINT m_pcFramesDuplicated; + UINT m_pcFramesDrawn; + + LONGLONG m_pllJitter [NB_JITTER]; // Vertical sync time stats + LONGLONG m_pllSyncOffset [NB_JITTER]; // Sync offset time stats + int m_nNextJitter; + int m_nNextSyncOffset; + LONGLONG m_JitterStdDev; + + LONGLONG m_llLastSyncTime; + + LONGLONG m_MaxJitter; + LONGLONG m_MinJitter; + LONGLONG m_MaxSyncOffset; + LONGLONG m_MinSyncOffset; + UINT m_uSyncGlitches; + + LONGLONG m_llSampleTime, m_llLastSampleTime; // Present time for the current sample + LONGLONG m_llHysteresis; + LONG m_lShiftToNearest, m_lShiftToNearestPrev; + bool m_bVideoSlowerThanDisplay; + + REFERENCE_TIME m_rtTimePerFrame; + bool m_bInterlaced; + double m_TextScale; + CString m_strStatsMsg[10]; + + CGenlock* m_pGenlock; // The video - display synchronizer class + CComPtr m_pRefClock; // The reference clock. Used in Paint() + CComPtr m_pAudioStats; // Audio statistics from audio renderer. To check so that audio is in sync + DWORD m_lAudioLag; // Time difference between audio and video when the audio renderer is matching rate to the external reference clock + long m_lAudioLagMin, m_lAudioLagMax; // The accumulated difference between the audio renderer and the master clock + DWORD m_lAudioSlaveMode; // To check whether the audio renderer matches rate with SyncClock (returns the value 4 if it does) + + double GetRefreshRate(); // Get the best estimate of the display refresh rate in Hz + double GetDisplayCycle(); // Get the best estimate of the display cycle time in milliseconds + double GetCycleDifference(); // Get the difference in video and display cycle times. + void EstimateRefreshTimings(); // Estimate the times for one scan line and one frame respectively from the actual refresh data + bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt); + + CFocusThread* m_FocusThread; + HWND m_hFocusWindow; + + public: + CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); + ~CBaseAP(); + + CCritSec m_VMR9AlphaBitmapLock; + void UpdateAlphaBitmap(); + void ResetStats(); + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); + STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); + STDMETHODIMP_(bool) ResetDevice(); + STDMETHODIMP_(bool) DisplayChange(); + }; + + class CSyncAP: + public CBaseAP, + public IMFGetService, + public IMFTopologyServiceLookupClient, + public IMFVideoDeviceID, + public IMFVideoPresenter, + public IDirect3DDeviceManager9, + public IMFAsyncCallback, + public IQualProp, + public IMFRateSupport, + public IMFVideoDisplayControl, + public IEVRTrustedVideoPlugin, + public ISyncClockAdviser, + public ID3DFullscreenControl + { + public: + CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); + ~CSyncAP(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); + STDMETHODIMP InitializeDevice(AM_MEDIA_TYPE* pMediaType); + STDMETHODIMP_(bool) ResetDevice(); + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() { + return (m_nRenderState == Started); + } + + // IMFClockStateSink + STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset); + STDMETHODIMP OnClockStop(MFTIME hnsSystemTime); + STDMETHODIMP OnClockPause(MFTIME hnsSystemTime); + STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime); + STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate); + + // IBaseFilter delegate + bool GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue); + + // IQualProp (EVR statistics window). These are incompletely implemented currently + STDMETHODIMP get_FramesDroppedInRenderer(int* pcFrames); + STDMETHODIMP get_FramesDrawn(int* pcFramesDrawn); + STDMETHODIMP get_AvgFrameRate(int* piAvgFrameRate); + STDMETHODIMP get_Jitter(int* iJitter); + STDMETHODIMP get_AvgSyncOffset(int* piAvg); + STDMETHODIMP get_DevSyncOffset(int* piDev); + + // IMFRateSupport + STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); + STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); + STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate); + float GetMaxRate(BOOL bThin); + + // IMFVideoPresenter + STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam); + STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType); + + // IMFTopologyServiceLookupClient + STDMETHODIMP InitServicePointers(__in IMFTopologyServiceLookup* pLookup); + STDMETHODIMP ReleaseServicePointers(); + + // IMFVideoDeviceID + STDMETHODIMP GetDeviceID(__out IID* pDeviceID); + + // IMFGetService + STDMETHODIMP GetService(__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppvObject); + + // IMFAsyncCallback + STDMETHODIMP GetParameters(__RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue); + STDMETHODIMP Invoke(__RPC__in_opt IMFAsyncResult* pAsyncResult); + + // IMFVideoDisplayControl + STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo); + STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax); + STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest); + STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest); + STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode); + STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode); + STDMETHODIMP SetVideoWindow(HWND hwndVideo); + STDMETHODIMP GetVideoWindow(HWND* phwndVideo); + STDMETHODIMP RepaintVideo(); + STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp); + STDMETHODIMP SetBorderColor(COLORREF Clr); + STDMETHODIMP GetBorderColor(COLORREF* pClr); + STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags); + STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags); + STDMETHODIMP SetFullscreen(BOOL fFullscreen); + STDMETHODIMP GetFullscreen(BOOL* pfFullscreen); + + // IEVRTrustedVideoPlugin + STDMETHODIMP IsInTrustedVideoMode(BOOL* pYes); + STDMETHODIMP CanConstrict(BOOL* pYes); + STDMETHODIMP SetConstriction(DWORD dwKPix); + STDMETHODIMP DisableImageExport(BOOL bDisable); + + // IDirect3DDeviceManager9 + STDMETHODIMP ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken); + STDMETHODIMP OpenDeviceHandle(HANDLE* phDevice); + STDMETHODIMP CloseDeviceHandle(HANDLE hDevice); + STDMETHODIMP TestDevice(HANDLE hDevice); + STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock); + STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState); + STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void** ppService); + + // ID3DFullscreenControl + STDMETHODIMP SetD3DFullscreen(bool fEnabled); + STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); + + protected: + STDMETHODIMP_(bool) Paint(IMFSample* pMFSample); + void OnResetDevice(); + MFCLOCK_STATE m_LastClockState; + + private: + enum RENDER_STATE { + Started = State_Running, + Stopped = State_Stopped, + Paused = State_Paused, + Shutdown = State_Running + 1 + }; + + CComPtr m_pClock; + CComPtr m_pD3DManager; + CComPtr m_pMixer; + CComPtr m_pSink; + CComPtr m_pMediaType; + MFVideoAspectRatioMode m_dwVideoAspectRatioMode; + MFVideoRenderPrefs m_dwVideoRenderPrefs; + COLORREF m_BorderColor; + + HANDLE m_hEvtQuit; // Stop rendering thread event + bool m_bEvtQuit; + HANDLE m_hEvtFlush; // Discard all buffers + bool m_bEvtFlush; + HANDLE m_hEvtSkip; // Skip frame + bool m_bEvtSkip; + + bool m_bUseInternalTimer; + INT32 m_LastSetOutputRange; + std::atomic_bool m_bPendingRenegotiate; + bool m_bPendingMediaFinished; + bool m_bPrerolled; // true if first sample has been displayed. + + HANDLE m_hRenderThread; + HANDLE m_hMixerThread; + RENDER_STATE m_nRenderState; + bool m_bStepping; + + CCritSec m_SampleQueueLock; + CCritSec m_ImageProcessingLock; + + UINT32 m_nCurrentGroupId; + CInterfaceList m_FreeSamples; + CInterfaceList m_ScheduledSamples; + CComPtr m_pCurrentlyDisplayedSample; + UINT m_nResetToken; + int m_nStepCount; + + bool GetSampleFromMixer(); + void MixerThread(); + static DWORD WINAPI MixerThreadStatic(LPVOID lpParam); + void RenderThread(); + static DWORD WINAPI RenderThreadStatic(LPVOID lpParam); + + void StartWorkerThreads(); + void StopWorkerThreads(); + HRESULT CheckShutdown() const; + void CompleteFrameStep(bool bCancel); + + void RemoveAllSamples(); + STDMETHODIMP AdviseSyncClock(ISyncClock* sC); + HRESULT BeginStreaming(); + HRESULT GetFreeSample(IMFSample** ppSample); + HRESULT GetScheduledSample(IMFSample** ppSample, int& count); + void AddToFreeList(IMFSample* pSample, bool bTail); + void AddToScheduledList(IMFSample* pSample, bool bSorted); + void FlushSamples(); + + HRESULT TrackSample(IMFSample* pSample); + + // Callback when a video sample is released. + HRESULT OnSampleFree(IMFAsyncResult* pResult); + AsyncCallback m_SampleFreeCallback; + + LONGLONG GetMediaTypeMerit(IMFMediaType* pMediaType); + HRESULT RenegotiateMediaType(); + HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType); + HRESULT CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType); + HRESULT SetMediaType(IMFMediaType* pType); + + const WinapiFunc fnDXVA2CreateDirect3DDeviceManager9; + const WinapiFunc fnMFCreateDXSurfaceBuffer; + const WinapiFunc fnMFCreateVideoSampleFromSurface; + const WinapiFunc fnMFCreateMediaType; + + const WinapiFunc fnAvSetMmThreadCharacteristicsW; + const WinapiFunc fnAvSetMmThreadPriority; + const WinapiFunc fnAvRevertMmThreadCharacteristics; + }; + + class CSyncRenderer: + public CUnknown, + public IVMRMixerBitmap9, + public IBaseFilter + { + CComPtr m_pEVR; + IBaseFilter* m_pEVRBase; + VMR9AlphaBitmap* m_pVMR9AlphaBitmap; + CSyncAP* m_pAllocatorPresenter; + + public: + CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP* pAllocatorPresenter); + ~CSyncRenderer(); + + // IBaseFilter + virtual HRESULT STDMETHODCALLTYPE EnumPins(__out IEnumPins** ppEnum); + virtual HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, __out IPin** ppPin); + virtual HRESULT STDMETHODCALLTYPE QueryFilterInfo(__out FILTER_INFO* pInfo); + virtual HRESULT STDMETHODCALLTYPE JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName); + virtual HRESULT STDMETHODCALLTYPE QueryVendorInfo(__out LPWSTR* pVendorInfo); + virtual HRESULT STDMETHODCALLTYPE Stop(); + virtual HRESULT STDMETHODCALLTYPE Pause(); + virtual HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); + virtual HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State); + virtual HRESULT STDMETHODCALLTYPE SetSyncSource(__in_opt IReferenceClock* pClock); + virtual HRESULT STDMETHODCALLTYPE GetSyncSource(__deref_out_opt IReferenceClock** pClock); + virtual HRESULT STDMETHODCALLTYPE GetClassID(__RPC__out CLSID* pClassID); + + // IVMRMixerBitmap9 + STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); + + DECLARE_IUNKNOWN; + virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid, void** ppvObject); + }; + + class CGenlock + { + public: + class MovingAverage + { + public: + MovingAverage(size_t size) + : fifoSize(size) + , fifo(fifoSize) + , oldestSample(0) + , sum(0.0) { + } + + double Average(double sample) { + sum = sum + sample - fifo[oldestSample]; + fifo[oldestSample] = sample; + oldestSample++; + if (oldestSample == fifoSize) { + oldestSample = 0; + } + return sum / fifoSize; + } + + private: + size_t fifoSize; + std::vector fifo; + size_t oldestSample; + double sum; + }; + + CGenlock(double target, double limit, int rowD, int colD, double clockD, UINT mon); + CGenlock(const CGenlock&) = delete; + ~CGenlock(); + + CGenlock& operator=(const CGenlock&) = delete; + + BOOL PowerstripRunning(); // TRUE if PowerStrip is running + HRESULT GetTiming(); // Get the string representing the display's current timing parameters + HRESULT ResetTiming(); // Reset timing to what was last registered by GetTiming() + HRESULT ResetClock(); // Reset reference clock speed to nominal + HRESULT SetTargetSyncOffset(double targetD); + HRESULT GetTargetSyncOffset(double* targetD); + HRESULT SetControlLimit(double cL); + HRESULT GetControlLimit(double* cL); + HRESULT SetDisplayResolution(UINT columns, UINT lines); + HRESULT AdviseSyncClock(ISyncClock* sC); + HRESULT SetMonitor(UINT mon); // Set the number of the monitor to synchronize + HRESULT ResetStats(); // Reset timing statistics + + HRESULT ControlDisplay(double syncOffset, double frameCycle); // Adjust the frequency of the display if needed + HRESULT ControlClock(double syncOffset, double frameCycle); // Adjust the frequency of the clock if needed + HRESULT UpdateStats(double syncOffset, double frameCycle); // Don't adjust anything, just update the syncOffset stats + + bool powerstripTimingExists; // true if display timing has been got through Powerstrip + bool liveSource; // true if live source -> display sync is the only option + int adjDelta; // -1 for display slower in relation to video, 0 for keep, 1 for faster + int lineDelta; // The number of rows added or subtracted when adjusting display fps + int columnDelta; // The number of colums added or subtracted when adjusting display fps + double cycleDelta; // Adjustment factor for cycle time as fraction of nominal value + UINT displayAdjustmentsMade; // The number of adjustments made to display refresh rate + UINT clockAdjustmentsMade; // The number of adjustments made to clock frequency + + UINT totalLines, totalColumns; // Including the porches and sync widths + UINT visibleLines, visibleColumns; // The nominal resolution + MovingAverage syncOffsetFifo; + MovingAverage frameCycleFifo; + double minSyncOffset, maxSyncOffset; + double syncOffsetAvg; // Average of the above + double minFrameCycle, maxFrameCycle; + double frameCycleAvg; + + UINT pixelClock; // In pixels/s + double displayFreqCruise; // Nominal display frequency in frames/s + double displayFreqSlower; + double displayFreqFaster; + double curDisplayFreq; // Current (adjusted) display frequency + double controlLimit; // How much the sync offset is allowed to drift from target sync offset + WPARAM monitor; // The monitor to be controlled. 0-based. + CComPtr syncClock; // Interface to an adjustable reference clock + + private: + HWND psWnd; // PowerStrip window + const static int TIMING_PARAM_CNT = 10; + const static int MAX_LOADSTRING = 100; + std::array displayTiming; // Display timing parameters + std::array displayTimingSave; // So that we can reset the display at exit + TCHAR faster[MAX_LOADSTRING]; // String corresponding to faster display frequency + TCHAR cruise[MAX_LOADSTRING]; // String corresponding to nominal display frequency + TCHAR slower[MAX_LOADSTRING]; // String corresponding to slower display frequency + TCHAR savedTiming[MAX_LOADSTRING]; // String version of saved timing (to be restored upon exit) + double lowSyncOffset; // The closest we want to let the scheduled render time to get to the next vsync. In % of the frame time + double targetSyncOffset; // Where we want the scheduled render time to be in relation to the next vsync + double highSyncOffset; // The furthers we want to let the scheduled render time to get to the next vsync + CCritSec csGenlockLock; + }; +} diff --git a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp index 3d2a01dddc0..cc029075d75 100644 --- a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp @@ -1,582 +1,582 @@ -/* - * (C) 2006-2014, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "RenderersSettings.h" -#include "VMR9AllocatorPresenter.h" -#include "OuterVMR.h" -#include "IPinHook.h" -#include "MacrovisionKicker.h" -#include "Variables.h" - -// ISubPicAllocatorPresenter - - -using namespace DSObjects; - -// -// CVMR9AllocatorPresenter -// - -#define MY_USER_ID 0x6ABE51 - -CVMR9AllocatorPresenter::CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) - : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, false, _Error) - , m_fUseInternalTimer(false) - , m_rtPrevStart(-1) -{ -} - -CVMR9AllocatorPresenter::~CVMR9AllocatorPresenter() -{ - if (m_bHookedNewSegment) { - UnhookNewSegment(); - } - if (m_bHookedReceive) { - UnhookReceive(); - } -} - -STDMETHODIMP CVMR9AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IVMRSurfaceAllocator9) - QI(IVMRImagePresenter9) - QI(IVMRWindowlessControl9) - QI(ID3DFullscreenControl) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CVMR9AllocatorPresenter::CreateDevice(CString& _Error) -{ - HRESULT hr = __super::CreateDevice(_Error); - if (FAILED(hr)) { - return hr; - } - - if (m_pIVMRSurfAllocNotify) { - HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(m_CurrentAdapter); - if (FAILED(hr = m_pIVMRSurfAllocNotify->ChangeD3DDevice(m_pD3DDev, hMonitor))) { - _Error += L"m_pIVMRSurfAllocNotify->ChangeD3DDevice failed"; - return hr; //return false; - } - } - - return hr; -} - -void CVMR9AllocatorPresenter::DeleteSurfaces() -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - m_pSurfaces.RemoveAll(); - - return __super::DeleteSurfaces(); -} - -STDMETHODIMP CVMR9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - *ppRenderer = nullptr; - - CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; - - COuterVMR9* pOuter = DEBUG_NEW COuterVMR9(NAME("COuterVMR9"), pUnk, &m_VMR9AlphaBitmap, this); - - pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuter); - CComQIPtr pBF = pUnk; - - CComPtr pPin = GetFirstPin(pBF); - if (!m_bIsPreview) { - if (HookNewSegment((IPinC*)(IPin*)pPin)) { - m_bHookedNewSegment = true; - CComQIPtr pMemInputPin = pPin; - if (HookReceive((IMemInputPinC*)(IMemInputPin*)pMemInputPin)) { - m_fUseInternalTimer = true; - m_bHookedReceive = true; - } - } - } - - CComQIPtr pConfig = pBF; - if (!pConfig) { - return E_FAIL; - } - - const CRenderersSettings& r = GetRenderersSettings(); - - if (r.fVMR9MixerMode) { - if (FAILED(pConfig->SetNumberOfStreams(1))) { - return E_FAIL; - } - - if (CComQIPtr pMC = pBF) { - DWORD dwPrefs; - pMC->GetMixingPrefs(&dwPrefs); - - // See http://msdn.microsoft.com/en-us/library/dd390928(VS.85).aspx - dwPrefs |= MixerPref9_NonSquareMixing; - dwPrefs |= MixerPref9_NoDecimation; - pMC->SetMixingPrefs(dwPrefs); - } - } - - if (FAILED(pConfig->SetRenderingMode(VMR9Mode_Renderless))) { - return E_FAIL; - } - - CComQIPtr pSAN = pBF; - if (!pSAN) { - return E_FAIL; - } - - if (FAILED(pSAN->AdviseSurfaceAllocator(MY_USER_ID, static_cast(this))) - || FAILED(AdviseNotify(pSAN))) { - return E_FAIL; - } - - *ppRenderer = (IUnknown*)pBF.Detach(); - - return S_OK; -} - -STDMETHODIMP_(void) CVMR9AllocatorPresenter::SetTime(REFERENCE_TIME rtNow) -{ - __super::SetTime(rtNow); -} - -// IVMRSurfaceAllocator9 - -STDMETHODIMP CVMR9AllocatorPresenter::InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers) -{ - CAutoLock lock(this); - CAutoLock cRenderLock(&m_RenderLock); - - if (!lpAllocInfo || !lpNumBuffers) { - return E_POINTER; - } - - if (!m_pIVMRSurfAllocNotify) { - return E_FAIL; - } - - // WTF: Is this some kind of forgotten debug code ? - if ((GetAsyncKeyState(VK_CONTROL) & 0x80000000)) - if (lpAllocInfo->Format == '21VY' || lpAllocInfo->Format == '024I') { - return E_FAIL; - } - - // The surfaces should already be free when InitializeDevice is called - DeleteSurfaces(); - - DWORD nOriginal = *lpNumBuffers; - - if (*lpNumBuffers == 1) { - *lpNumBuffers = 4; - m_nVMR9Surfaces = 4; - } else { - m_nVMR9Surfaces = 0; - } - m_pSurfaces.SetCount(*lpNumBuffers); - - int w = lpAllocInfo->dwWidth; - int h = abs((int)lpAllocInfo->dwHeight); - - HRESULT hr; - - if (lpAllocInfo->dwFlags & VMR9AllocFlag_3DRenderTarget) { - lpAllocInfo->dwFlags |= VMR9AllocFlag_TextureSurface; - } - - hr = m_pIVMRSurfAllocNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, &m_pSurfaces[0]); - if (FAILED(hr)) { - return hr; - } - - m_pSurfaces.SetCount(*lpNumBuffers); - - m_bNeedCheckSample = true; - CSize VideoSize(w, h); - CSize AspectRatio(lpAllocInfo->szAspectRatio.cx, lpAllocInfo->szAspectRatio.cy); - SetVideoSize(VideoSize, AspectRatio); - - if (FAILED(hr = AllocSurfaces())) { - return hr; - } - - if (!(lpAllocInfo->dwFlags & VMR9AllocFlag_TextureSurface)) { - // test if the colorspace is acceptable - if (FAILED(hr = m_pD3DDev->StretchRect(m_pSurfaces[0], nullptr, m_pVideoSurface[m_nCurSurface], nullptr, D3DTEXF_NONE))) { - DeleteSurfaces(); - return E_FAIL; - } - } - - hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], nullptr, 0); - - if (m_nVMR9Surfaces && m_nVMR9Surfaces != (int)*lpNumBuffers) { - m_nVMR9Surfaces = *lpNumBuffers; - } - *lpNumBuffers = std::min(nOriginal, *lpNumBuffers); - m_iVMR9Surface = 0; - - return hr; -} - -STDMETHODIMP CVMR9AllocatorPresenter::TerminateDevice(DWORD_PTR dwUserID) -{ - // We should not free the surfaces until we are told to ! - // Thats what TerminateDevice is for - DeleteSurfaces(); - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface) -{ - CheckPointer(lplpSurface, E_POINTER); - - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - /* - SurfaceIndex = 0 - m_pSurfaces.GetCount() = 0 - - Scenario: - Thread 1: - Wait on m_RenderLock in this function - Thread 2: - Have m_RenderLock and removes all m_pSurfaces - (Happens by calling ex CDX9AllocatorPresenter::ResetDevice) - - When thread 2 releases the lock thread 1 gets it and boom! - - Possible solution: Adding object lock and moving m_RenderLock to try to fix this threading issue. - This problem occurs when moving the window from display a to display b. - - NOTE: This is just a workaround. - CDX9AllocatorPresenter doesn't follow the rules which is why this happened. - And it is used by EVR custom (which it really shouldn't) so i can't easily fix it without breaking EVR custom. - */ - if (SurfaceIndex >= m_pSurfaces.GetCount()) { - return E_FAIL; - } - - if (m_nVMR9Surfaces) { - ++m_iVMR9Surface; - m_iVMR9Surface = m_iVMR9Surface % m_nVMR9Surfaces; - *lplpSurface = m_pSurfaces[m_iVMR9Surface + SurfaceIndex]; - (*lplpSurface)->AddRef(); - } else { - m_iVMR9Surface = SurfaceIndex; - *lplpSurface = m_pSurfaces[SurfaceIndex]; - (*lplpSurface)->AddRef(); - } - - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify) -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - m_pIVMRSurfAllocNotify = lpIVMRSurfAllocNotify; - - HRESULT hr; - HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D)); - if (FAILED(hr = m_pIVMRSurfAllocNotify->SetD3DDevice(m_pD3DDev, hMonitor))) { - return hr; - } - - return S_OK; -} - -// IVMRImagePresenter9 - -STDMETHODIMP CVMR9AllocatorPresenter::StartPresenting(DWORD_PTR dwUserID) -{ - if (!m_bPendingResetDevice) { - ASSERT(m_pD3DDev); - } - - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - CComPtr pVMR9; - CComPtr pPin; - if (SUCCEEDED(m_pIVMRSurfAllocNotify->QueryInterface(IID_PPV_ARGS(&pVMR9))) && - SUCCEEDED(pVMR9->FindPin(L"VMR Input0", &pPin))) { - VERIFY(SUCCEEDED(pPin->ConnectionMediaType(&m_inputMediaType))); - } - - m_bIsRendering = true; - - return m_pD3DDev ? S_OK : E_FAIL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::StopPresenting(DWORD_PTR dwUserID) -{ - m_bIsRendering = false; - - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo) -{ - SetThreadName(DWORD(-1), "CVMR9AllocatorPresenter"); - CheckPointer(m_pIVMRSurfAllocNotify, E_UNEXPECTED); - - if (m_rtTimePerFrame == 0 || m_bNeedCheckSample) { - m_bNeedCheckSample = false; - CComPtr pVMR9; - CComPtr pPin; - CMediaType mt; - - if (SUCCEEDED(m_pIVMRSurfAllocNotify->QueryInterface(IID_PPV_ARGS(&pVMR9))) && - SUCCEEDED(pVMR9->FindPin(L"VMR Input0", &pPin)) && - SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); - - CSize NativeVideoSize = m_nativeVideoSize; - CSize AspectRatio = m_aspectRatio; - if (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_MPEGVideo) { - VIDEOINFOHEADER* vh = (VIDEOINFOHEADER*)mt.pbFormat; - - NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight)); - if (vh->rcTarget.right - vh->rcTarget.left > 0) { - NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left; - } else if (vh->rcSource.right - vh->rcSource.left > 0) { - NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left; - } - - if (vh->rcTarget.bottom - vh->rcTarget.top > 0) { - NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top; - } else if (vh->rcSource.bottom - vh->rcSource.top > 0) { - NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top; - } - } else if (mt.formattype == FORMAT_VideoInfo2 || mt.formattype == FORMAT_MPEG2Video) { - VIDEOINFOHEADER2* vh = (VIDEOINFOHEADER2*)mt.pbFormat; - - if (vh->dwPictAspectRatioX && vh->dwPictAspectRatioY) { - AspectRatio = CSize(vh->dwPictAspectRatioX, vh->dwPictAspectRatioY); - } - - NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight)); - if (vh->rcTarget.right - vh->rcTarget.left > 0) { - NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left; - } else if (vh->rcSource.right - vh->rcSource.left > 0) { - NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left; - } - - if (vh->rcTarget.bottom - vh->rcTarget.top > 0) { - NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top; - } else if (vh->rcSource.bottom - vh->rcSource.top > 0) { - NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top; - } - } - if (m_nativeVideoSize != NativeVideoSize || m_aspectRatio != AspectRatio) { - SetVideoSize(NativeVideoSize, AspectRatio); - AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS); - } - } - // If framerate not set by Video Decoder choose 23.976 - if (m_rtTimePerFrame == 0) { - m_rtTimePerFrame = 417083; - //ASSERT(FALSE); - } - - m_fps = 10000000.0 / m_rtTimePerFrame; - } - - if (!lpPresInfo || !lpPresInfo->lpSurf) { - return E_POINTER; - } - - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - if (m_pSubPicQueue) { - m_pSubPicQueue->SetFPS(m_fps); - - if (m_fUseInternalTimer && !g_bExternalSubtitleTime) { - REFERENCE_TIME rtCurFrameTime = lpPresInfo->rtEnd - lpPresInfo->rtStart; - REFERENCE_TIME rtSampleTime = 0; - // check if present timestamps are valid, rtStart can be invalid after a seek, while rtEnd always seems to be correct - // rtStart is reliable when rtEnd equals duration of two frames (+2 ms because timestamps are sometimes rounded to ms values) - // or if frame duration seems normal - if (lpPresInfo->rtEnd > lpPresInfo->rtStart && (lpPresInfo->rtEnd >= 2 * m_rtTimePerFrame + 20000LL || abs(rtCurFrameTime - m_rtTimePerFrame) < 10000LL)) { - rtSampleTime = lpPresInfo->rtStart; - //TRACE(_T("VMR9: Present %s -> %s | g_tSampleStart %s | g_tSegmentStart %s | rtCurFrameTime %ld\n"), ReftimeToString(lpPresInfo->rtStart).GetString(), ReftimeToString(lpPresInfo->rtEnd).GetString(), ReftimeToString(g_tSampleStart).GetString(), ReftimeToString(g_tSegmentStart).GetString(), rtCurFrameTime); - } else { - if (lpPresInfo->rtEnd > m_rtTimePerFrame) { - rtSampleTime = lpPresInfo->rtEnd - m_rtTimePerFrame; - } - //TRACE(_T("VMR9: Present %s -> %s INVALID! | g_tSampleStart %s | g_tSegmentStart %s | m_rtTimePerFrame %ld\n"), ReftimeToString(lpPresInfo->rtStart).GetString(), ReftimeToString(lpPresInfo->rtEnd).GetString(), ReftimeToString(g_tSampleStart).GetString(), ReftimeToString(g_tSegmentStart).GetString(), m_rtTimePerFrame); - } - __super::SetTime(g_tSegmentStart + rtSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); - } - } - - CSize ar(lpPresInfo->szAspectRatio.cx, lpPresInfo->szAspectRatio.cy); - if (ar != m_aspectRatio) { - SetVideoSize(m_nativeVideoSize, ar); - AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS); - } - - if (!m_bPendingResetDevice) { - CComPtr pTexture; - lpPresInfo->lpSurf->GetContainer(IID_PPV_ARGS(&pTexture)); - - if (pTexture) { - m_pVideoSurface[m_nCurSurface] = lpPresInfo->lpSurf; - if (m_pVideoTexture[m_nCurSurface]) { - m_pVideoTexture[m_nCurSurface] = pTexture; - } - } else { - m_pD3DDev->StretchRect(lpPresInfo->lpSurf, nullptr, m_pVideoSurface[m_nCurSurface], nullptr, D3DTEXF_NONE); - } - - // Tear test bars - if (GetRenderersData()->m_bTearingTest) { - RECT rcTearing; - - rcTearing.left = m_nTearingPos; - rcTearing.top = 0; - rcTearing.right = rcTearing.left + 4; - rcTearing.bottom = m_nativeVideoSize.cy; - m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - - rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; - rcTearing.right = rcTearing.left + 4; - m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - - m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; - } - } - - Paint(true); - - return S_OK; -} - -// IVMRWindowlessControl9 -// -// It is only implemented (partially) for the dvd navigator's -// menu handling, which needs to know a few things about the -// location of our window. - -STDMETHODIMP CVMR9AllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) -{ - if (lpWidth) { - *lpWidth = m_nativeVideoSize.cx; - } - if (lpHeight) { - *lpHeight = m_nativeVideoSize.cy; - } - if (lpARWidth) { - *lpARWidth = m_aspectRatio.cx; - } - if (lpARHeight) { - *lpARHeight = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) -{ - return E_NOTIMPL; // we have our own method for this -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect) -{ - CopyRect(lpSRCRect, CRect(CPoint(0, 0), GetVisibleVideoSize())); - CopyRect(lpDSTRect, &m_videoRect); - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetAspectRatioMode(DWORD* lpAspectRatioMode) -{ - if (lpAspectRatioMode) { - *lpAspectRatioMode = AM_ARMODE_STRETCHED; - } - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::SetAspectRatioMode(DWORD AspectRatioMode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::SetVideoClippingWindow(HWND hwnd) -{ - if (m_hWnd != hwnd) { - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - m_hWnd = hwnd; - m_bPendingResetDevice = true; - SendResetRequest(); - } - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::RepaintVideo(HWND hwnd, HDC hdc) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::DisplayModeChanged() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetCurrentImage(BYTE** lpDib) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::SetBorderColor(COLORREF Clr) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetBorderColor(COLORREF* lpClr) -{ - if (lpClr) { - *lpClr = 0; - } - return S_OK; -} +/* + * (C) 2006-2014, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "RenderersSettings.h" +#include "VMR9AllocatorPresenter.h" +#include "OuterVMR.h" +#include "IPinHook.h" +#include "MacrovisionKicker.h" +#include "Variables.h" + +// ISubPicAllocatorPresenter + + +using namespace DSObjects; + +// +// CVMR9AllocatorPresenter +// + +#define MY_USER_ID 0x6ABE51 + +CVMR9AllocatorPresenter::CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) + : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, false, _Error) + , m_fUseInternalTimer(false) + , m_rtPrevStart(-1) +{ +} + +CVMR9AllocatorPresenter::~CVMR9AllocatorPresenter() +{ + if (m_bHookedNewSegment) { + UnhookNewSegment(); + } + if (m_bHookedReceive) { + UnhookReceive(); + } +} + +STDMETHODIMP CVMR9AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IVMRSurfaceAllocator9) + QI(IVMRImagePresenter9) + QI(IVMRWindowlessControl9) + QI(ID3DFullscreenControl) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CVMR9AllocatorPresenter::CreateDevice(CString& _Error) +{ + HRESULT hr = __super::CreateDevice(_Error); + if (FAILED(hr)) { + return hr; + } + + if (m_pIVMRSurfAllocNotify) { + HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(m_CurrentAdapter); + if (FAILED(hr = m_pIVMRSurfAllocNotify->ChangeD3DDevice(m_pD3DDev, hMonitor))) { + _Error += L"m_pIVMRSurfAllocNotify->ChangeD3DDevice failed"; + return hr; //return false; + } + } + + return hr; +} + +void CVMR9AllocatorPresenter::DeleteSurfaces() +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + m_pSurfaces.RemoveAll(); + + return __super::DeleteSurfaces(); +} + +STDMETHODIMP CVMR9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + *ppRenderer = nullptr; + + CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; + + COuterVMR9* pOuter = DEBUG_NEW COuterVMR9(NAME("COuterVMR9"), pUnk, &m_VMR9AlphaBitmap, this); + + pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuter); + CComQIPtr pBF = pUnk; + + CComPtr pPin = GetFirstPin(pBF); + if (!m_bIsPreview) { + if (HookNewSegment((IPinC*)(IPin*)pPin)) { + m_bHookedNewSegment = true; + CComQIPtr pMemInputPin = pPin; + if (HookReceive((IMemInputPinC*)(IMemInputPin*)pMemInputPin)) { + m_fUseInternalTimer = true; + m_bHookedReceive = true; + } + } + } + + CComQIPtr pConfig = pBF; + if (!pConfig) { + return E_FAIL; + } + + const CRenderersSettings& r = GetRenderersSettings(); + + if (r.fVMR9MixerMode) { + if (FAILED(pConfig->SetNumberOfStreams(1))) { + return E_FAIL; + } + + if (CComQIPtr pMC = pBF) { + DWORD dwPrefs; + pMC->GetMixingPrefs(&dwPrefs); + + // See http://msdn.microsoft.com/en-us/library/dd390928(VS.85).aspx + dwPrefs |= MixerPref9_NonSquareMixing; + dwPrefs |= MixerPref9_NoDecimation; + pMC->SetMixingPrefs(dwPrefs); + } + } + + if (FAILED(pConfig->SetRenderingMode(VMR9Mode_Renderless))) { + return E_FAIL; + } + + CComQIPtr pSAN = pBF; + if (!pSAN) { + return E_FAIL; + } + + if (FAILED(pSAN->AdviseSurfaceAllocator(MY_USER_ID, static_cast(this))) + || FAILED(AdviseNotify(pSAN))) { + return E_FAIL; + } + + *ppRenderer = (IUnknown*)pBF.Detach(); + + return S_OK; +} + +STDMETHODIMP_(void) CVMR9AllocatorPresenter::SetTime(REFERENCE_TIME rtNow) +{ + __super::SetTime(rtNow); +} + +// IVMRSurfaceAllocator9 + +STDMETHODIMP CVMR9AllocatorPresenter::InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers) +{ + CAutoLock lock(this); + CAutoLock cRenderLock(&m_RenderLock); + + if (!lpAllocInfo || !lpNumBuffers) { + return E_POINTER; + } + + if (!m_pIVMRSurfAllocNotify) { + return E_FAIL; + } + + // WTF: Is this some kind of forgotten debug code ? + if ((GetAsyncKeyState(VK_CONTROL) & 0x80000000)) + if (lpAllocInfo->Format == '21VY' || lpAllocInfo->Format == '024I') { + return E_FAIL; + } + + // The surfaces should already be free when InitializeDevice is called + DeleteSurfaces(); + + DWORD nOriginal = *lpNumBuffers; + + if (*lpNumBuffers == 1) { + *lpNumBuffers = 4; + m_nVMR9Surfaces = 4; + } else { + m_nVMR9Surfaces = 0; + } + m_pSurfaces.SetCount(*lpNumBuffers); + + int w = lpAllocInfo->dwWidth; + int h = abs((int)lpAllocInfo->dwHeight); + + HRESULT hr; + + if (lpAllocInfo->dwFlags & VMR9AllocFlag_3DRenderTarget) { + lpAllocInfo->dwFlags |= VMR9AllocFlag_TextureSurface; + } + + hr = m_pIVMRSurfAllocNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, &m_pSurfaces[0]); + if (FAILED(hr)) { + return hr; + } + + m_pSurfaces.SetCount(*lpNumBuffers); + + m_bNeedCheckSample = true; + CSize VideoSize(w, h); + CSize AspectRatio(lpAllocInfo->szAspectRatio.cx, lpAllocInfo->szAspectRatio.cy); + SetVideoSize(VideoSize, AspectRatio); + + if (FAILED(hr = AllocSurfaces())) { + return hr; + } + + if (!(lpAllocInfo->dwFlags & VMR9AllocFlag_TextureSurface)) { + // test if the colorspace is acceptable + if (FAILED(hr = m_pD3DDev->StretchRect(m_pSurfaces[0], nullptr, m_pVideoSurface[m_nCurSurface], nullptr, D3DTEXF_NONE))) { + DeleteSurfaces(); + return E_FAIL; + } + } + + hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], nullptr, 0); + + if (m_nVMR9Surfaces && m_nVMR9Surfaces != (int)*lpNumBuffers) { + m_nVMR9Surfaces = *lpNumBuffers; + } + *lpNumBuffers = std::min(nOriginal, *lpNumBuffers); + m_iVMR9Surface = 0; + + return hr; +} + +STDMETHODIMP CVMR9AllocatorPresenter::TerminateDevice(DWORD_PTR dwUserID) +{ + // We should not free the surfaces until we are told to ! + // Thats what TerminateDevice is for + DeleteSurfaces(); + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface) +{ + CheckPointer(lplpSurface, E_POINTER); + + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + /* + SurfaceIndex = 0 + m_pSurfaces.GetCount() = 0 + + Scenario: + Thread 1: + Wait on m_RenderLock in this function + Thread 2: + Have m_RenderLock and removes all m_pSurfaces + (Happens by calling ex CDX9AllocatorPresenter::ResetDevice) + + When thread 2 releases the lock thread 1 gets it and boom! + + Possible solution: Adding object lock and moving m_RenderLock to try to fix this threading issue. + This problem occurs when moving the window from display a to display b. + + NOTE: This is just a workaround. + CDX9AllocatorPresenter doesn't follow the rules which is why this happened. + And it is used by EVR custom (which it really shouldn't) so i can't easily fix it without breaking EVR custom. + */ + if (SurfaceIndex >= m_pSurfaces.GetCount()) { + return E_FAIL; + } + + if (m_nVMR9Surfaces) { + ++m_iVMR9Surface; + m_iVMR9Surface = m_iVMR9Surface % m_nVMR9Surfaces; + *lplpSurface = m_pSurfaces[m_iVMR9Surface + SurfaceIndex]; + (*lplpSurface)->AddRef(); + } else { + m_iVMR9Surface = SurfaceIndex; + *lplpSurface = m_pSurfaces[SurfaceIndex]; + (*lplpSurface)->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify) +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + m_pIVMRSurfAllocNotify = lpIVMRSurfAllocNotify; + + HRESULT hr; + HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D)); + if (FAILED(hr = m_pIVMRSurfAllocNotify->SetD3DDevice(m_pD3DDev, hMonitor))) { + return hr; + } + + return S_OK; +} + +// IVMRImagePresenter9 + +STDMETHODIMP CVMR9AllocatorPresenter::StartPresenting(DWORD_PTR dwUserID) +{ + if (!m_bPendingResetDevice) { + ASSERT(m_pD3DDev); + } + + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + CComPtr pVMR9; + CComPtr pPin; + if (SUCCEEDED(m_pIVMRSurfAllocNotify->QueryInterface(IID_PPV_ARGS(&pVMR9))) && + SUCCEEDED(pVMR9->FindPin(L"VMR Input0", &pPin))) { + VERIFY(SUCCEEDED(pPin->ConnectionMediaType(&m_inputMediaType))); + } + + m_bIsRendering = true; + + return m_pD3DDev ? S_OK : E_FAIL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::StopPresenting(DWORD_PTR dwUserID) +{ + m_bIsRendering = false; + + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo) +{ + SetThreadName(DWORD(-1), "CVMR9AllocatorPresenter"); + CheckPointer(m_pIVMRSurfAllocNotify, E_UNEXPECTED); + + if (m_rtTimePerFrame == 0 || m_bNeedCheckSample) { + m_bNeedCheckSample = false; + CComPtr pVMR9; + CComPtr pPin; + CMediaType mt; + + if (SUCCEEDED(m_pIVMRSurfAllocNotify->QueryInterface(IID_PPV_ARGS(&pVMR9))) && + SUCCEEDED(pVMR9->FindPin(L"VMR Input0", &pPin)) && + SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); + + CSize NativeVideoSize = m_nativeVideoSize; + CSize AspectRatio = m_aspectRatio; + if (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_MPEGVideo) { + VIDEOINFOHEADER* vh = (VIDEOINFOHEADER*)mt.pbFormat; + + NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight)); + if (vh->rcTarget.right - vh->rcTarget.left > 0) { + NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left; + } else if (vh->rcSource.right - vh->rcSource.left > 0) { + NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left; + } + + if (vh->rcTarget.bottom - vh->rcTarget.top > 0) { + NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top; + } else if (vh->rcSource.bottom - vh->rcSource.top > 0) { + NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top; + } + } else if (mt.formattype == FORMAT_VideoInfo2 || mt.formattype == FORMAT_MPEG2Video) { + VIDEOINFOHEADER2* vh = (VIDEOINFOHEADER2*)mt.pbFormat; + + if (vh->dwPictAspectRatioX && vh->dwPictAspectRatioY) { + AspectRatio = CSize(vh->dwPictAspectRatioX, vh->dwPictAspectRatioY); + } + + NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight)); + if (vh->rcTarget.right - vh->rcTarget.left > 0) { + NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left; + } else if (vh->rcSource.right - vh->rcSource.left > 0) { + NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left; + } + + if (vh->rcTarget.bottom - vh->rcTarget.top > 0) { + NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top; + } else if (vh->rcSource.bottom - vh->rcSource.top > 0) { + NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top; + } + } + if (m_nativeVideoSize != NativeVideoSize || m_aspectRatio != AspectRatio) { + SetVideoSize(NativeVideoSize, AspectRatio); + AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS); + } + } + // If framerate not set by Video Decoder choose 23.976 + if (m_rtTimePerFrame == 0) { + m_rtTimePerFrame = 417083; + //ASSERT(FALSE); + } + + m_fps = 10000000.0 / m_rtTimePerFrame; + } + + if (!lpPresInfo || !lpPresInfo->lpSurf) { + return E_POINTER; + } + + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + if (m_pSubPicQueue) { + m_pSubPicQueue->SetFPS(m_fps); + + if (m_fUseInternalTimer && !g_bExternalSubtitleTime) { + REFERENCE_TIME rtCurFrameTime = lpPresInfo->rtEnd - lpPresInfo->rtStart; + REFERENCE_TIME rtSampleTime = 0; + // check if present timestamps are valid, rtStart can be invalid after a seek, while rtEnd always seems to be correct + // rtStart is reliable when rtEnd equals duration of two frames (+2 ms because timestamps are sometimes rounded to ms values) + // or if frame duration seems normal + if (lpPresInfo->rtEnd > lpPresInfo->rtStart && (lpPresInfo->rtEnd >= 2 * m_rtTimePerFrame + 20000LL || abs(rtCurFrameTime - m_rtTimePerFrame) < 10000LL)) { + rtSampleTime = lpPresInfo->rtStart; + //TRACE(_T("VMR9: Present %s -> %s | g_tSampleStart %s | g_tSegmentStart %s | rtCurFrameTime %ld\n"), ReftimeToString(lpPresInfo->rtStart).GetString(), ReftimeToString(lpPresInfo->rtEnd).GetString(), ReftimeToString(g_tSampleStart).GetString(), ReftimeToString(g_tSegmentStart).GetString(), rtCurFrameTime); + } else { + if (lpPresInfo->rtEnd > m_rtTimePerFrame) { + rtSampleTime = lpPresInfo->rtEnd - m_rtTimePerFrame; + } + //TRACE(_T("VMR9: Present %s -> %s INVALID! | g_tSampleStart %s | g_tSegmentStart %s | m_rtTimePerFrame %ld\n"), ReftimeToString(lpPresInfo->rtStart).GetString(), ReftimeToString(lpPresInfo->rtEnd).GetString(), ReftimeToString(g_tSampleStart).GetString(), ReftimeToString(g_tSegmentStart).GetString(), m_rtTimePerFrame); + } + __super::SetTime(g_tSegmentStart + rtSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); + } + } + + CSize ar(lpPresInfo->szAspectRatio.cx, lpPresInfo->szAspectRatio.cy); + if (ar != m_aspectRatio) { + SetVideoSize(m_nativeVideoSize, ar); + AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS); + } + + if (!m_bPendingResetDevice) { + CComPtr pTexture; + lpPresInfo->lpSurf->GetContainer(IID_PPV_ARGS(&pTexture)); + + if (pTexture) { + m_pVideoSurface[m_nCurSurface] = lpPresInfo->lpSurf; + if (m_pVideoTexture[m_nCurSurface]) { + m_pVideoTexture[m_nCurSurface] = pTexture; + } + } else { + m_pD3DDev->StretchRect(lpPresInfo->lpSurf, nullptr, m_pVideoSurface[m_nCurSurface], nullptr, D3DTEXF_NONE); + } + + // Tear test bars + if (GetRenderersData()->m_bTearingTest) { + RECT rcTearing; + + rcTearing.left = m_nTearingPos; + rcTearing.top = 0; + rcTearing.right = rcTearing.left + 4; + rcTearing.bottom = m_nativeVideoSize.cy; + m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + + rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; + rcTearing.right = rcTearing.left + 4; + m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + + m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; + } + } + + Paint(true); + + return S_OK; +} + +// IVMRWindowlessControl9 +// +// It is only implemented (partially) for the dvd navigator's +// menu handling, which needs to know a few things about the +// location of our window. + +STDMETHODIMP CVMR9AllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) +{ + if (lpWidth) { + *lpWidth = m_nativeVideoSize.cx; + } + if (lpHeight) { + *lpHeight = m_nativeVideoSize.cy; + } + if (lpARWidth) { + *lpARWidth = m_aspectRatio.cx; + } + if (lpARHeight) { + *lpARHeight = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) +{ + return E_NOTIMPL; // we have our own method for this +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect) +{ + CopyRect(lpSRCRect, CRect(CPoint(0, 0), GetVisibleVideoSize())); + CopyRect(lpDSTRect, &m_videoRect); + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetAspectRatioMode(DWORD* lpAspectRatioMode) +{ + if (lpAspectRatioMode) { + *lpAspectRatioMode = AM_ARMODE_STRETCHED; + } + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::SetAspectRatioMode(DWORD AspectRatioMode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::SetVideoClippingWindow(HWND hwnd) +{ + if (m_hWnd != hwnd) { + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + m_hWnd = hwnd; + m_bPendingResetDevice = true; + SendResetRequest(); + } + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::RepaintVideo(HWND hwnd, HDC hdc) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::DisplayModeChanged() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetCurrentImage(BYTE** lpDib) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::SetBorderColor(COLORREF Clr) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetBorderColor(COLORREF* lpClr) +{ + if (lpClr) { + *lpClr = 0; + } + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h index de339f0210a..84c58f1b3fd 100644 --- a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h @@ -1,80 +1,80 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "DX9AllocatorPresenter.h" - -namespace DSObjects -{ - class CVMR9AllocatorPresenter - : public CDX9AllocatorPresenter - , public IVMRSurfaceAllocator9 - , public IVMRImagePresenter9 - , public IVMRWindowlessControl9 - { - protected: - CComPtr m_pIVMRSurfAllocNotify; - CInterfaceArray m_pSurfaces; - - HRESULT CreateDevice(CString& _Error); - void DeleteSurfaces(); - - bool m_fUseInternalTimer; - REFERENCE_TIME m_rtPrevStart; - - public: - CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); - ~CVMR9AllocatorPresenter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow); - - // IVMRSurfaceAllocator9 - STDMETHODIMP InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers); - STDMETHODIMP TerminateDevice(DWORD_PTR dwID); - STDMETHODIMP GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface); - STDMETHODIMP AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify); - - // IVMRImagePresenter9 - STDMETHODIMP StartPresenting(DWORD_PTR dwUserID); - STDMETHODIMP StopPresenting(DWORD_PTR dwUserID); - STDMETHODIMP PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo); - - // IVMRWindowlessControl9 - STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); - STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight); - STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight); - STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect); - STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect); - STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode); - STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode); - STDMETHODIMP SetVideoClippingWindow(HWND hwnd); - STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc); - STDMETHODIMP DisplayModeChanged(); - STDMETHODIMP GetCurrentImage(BYTE** lpDib); - STDMETHODIMP SetBorderColor(COLORREF Clr); - STDMETHODIMP GetBorderColor(COLORREF* lpClr); - }; -} +/* + * (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 . + * + */ + +#pragma once + +#include "DX9AllocatorPresenter.h" + +namespace DSObjects +{ + class CVMR9AllocatorPresenter + : public CDX9AllocatorPresenter + , public IVMRSurfaceAllocator9 + , public IVMRImagePresenter9 + , public IVMRWindowlessControl9 + { + protected: + CComPtr m_pIVMRSurfAllocNotify; + CInterfaceArray m_pSurfaces; + + HRESULT CreateDevice(CString& _Error); + void DeleteSurfaces(); + + bool m_fUseInternalTimer; + REFERENCE_TIME m_rtPrevStart; + + public: + CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); + ~CVMR9AllocatorPresenter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow); + + // IVMRSurfaceAllocator9 + STDMETHODIMP InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers); + STDMETHODIMP TerminateDevice(DWORD_PTR dwID); + STDMETHODIMP GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface); + STDMETHODIMP AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify); + + // IVMRImagePresenter9 + STDMETHODIMP StartPresenting(DWORD_PTR dwUserID); + STDMETHODIMP StopPresenting(DWORD_PTR dwUserID); + STDMETHODIMP PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo); + + // IVMRWindowlessControl9 + STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); + STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight); + STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight); + STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect); + STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect); + STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode); + STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode); + STDMETHODIMP SetVideoClippingWindow(HWND hwnd); + STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc); + STDMETHODIMP DisplayModeChanged(); + STDMETHODIMP GetCurrentImage(BYTE** lpDib); + STDMETHODIMP SetBorderColor(COLORREF Clr); + STDMETHODIMP GetBorderColor(COLORREF* lpClr); + }; +} diff --git a/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj b/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj index 6c4e3d6f9b5..a41fadd9579 100644 --- a/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj +++ b/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj @@ -1,106 +1,106 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {FB565A7A-50DC-4A0D-852D-5E7F74DAB82C} - VideoRenderers - MFCProj - VideoRenderers - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - $(IncludePath);$(DXSDK_DIR)Include - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {FB565A7A-50DC-4A0D-852D-5E7F74DAB82C} + VideoRenderers + MFCProj + VideoRenderers + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + $(IncludePath);$(DXSDK_DIR)Include + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj.filters b/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj.filters index 275d6df73e4..60592c01d72 100644 --- a/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj.filters +++ b/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj.filters @@ -1,155 +1,155 @@ - - - - - {91abd446-f660-4356-a9fe-c6f7f9dee6cb} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {48be6b66-cd30-4af5-b7d8-22839d28baaa} - h;hpp;hxx;hm;inl - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {91abd446-f660-4356-a9fe-c6f7f9dee6cb} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {48be6b66-cd30-4af5-b7d8-22839d28baaa} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp index fd54422cc7f..0d71621a0b0 100644 --- a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp @@ -1,299 +1,299 @@ -/* - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "madVRAllocatorPresenter.h" -#include "../../../SubPic/DX9SubPic.h" -#include "../../../SubPic/SubPicQueueImpl.h" -#include "RenderersSettings.h" -#include -#include -#include "IPinHook.h" -#include "Variables.h" -#include "Utils.h" - -using namespace DSObjects; - -CmadVRAllocatorPresenter::CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error) - : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) -{ - if (FAILED(hr)) { - _Error += L"ISubPicAllocatorPresenterImpl failed\n"; - return; - } - - hr = S_OK; -} - -CmadVRAllocatorPresenter::~CmadVRAllocatorPresenter() -{ - // the order is important here - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - m_pMVR = nullptr; - - if (m_bHookedNewSegment) { - UnhookNewSegment(); - } -} - -STDMETHODIMP CmadVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - if (riid != IID_IUnknown && m_pMVR) { - if (SUCCEEDED(m_pMVR->QueryInterface(riid, ppv))) { - return S_OK; - } - } - - return QI(ISubRenderCallback) - QI(ISubRenderCallback2) - QI(ISubRenderCallback3) - QI(ISubRenderCallback4) - QI(ISubPicAllocatorPresenter3) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubRenderCallback - -HRESULT CmadVRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev) -{ - if (!pD3DDev) { - // release all resources - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - __super::SetPosition(CRect(), CRect()); - return S_OK; - } - - const CRenderersSettings& r = GetRenderersSettings(); - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(pD3DDev, m_maxSubtitleTextureSize, true); - } - - HRESULT hr = S_OK; - if (!m_pSubPicQueue) { - CAutoLock cAutoLock(this); - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - m_pSubPicQueue->Invalidate(); - } - - if (SUCCEEDED(hr) && m_pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); - } - - return hr; -} - -// ISubRenderCallback3 - -HRESULT CmadVRAllocatorPresenter::RenderEx3(REFERENCE_TIME rtStart, - REFERENCE_TIME /*rtStop*/, - REFERENCE_TIME atpf, - RECT croppedVideoRect, - RECT /*originalVideoRect*/, - RECT viewportRect, - const double videoStretchFactor /*= 1.0*/, - int xOffsetInPixels /*= 0*/, DWORD flags /*= 0*/) -{ - CheckPointer(m_pSubPicQueue, E_UNEXPECTED); - - __super::SetPosition(viewportRect, croppedVideoRect); - if (!g_bExternalSubtitleTime) { - if (g_bExternalSubtitle && g_dRate != 0.0) { - const REFERENCE_TIME sampleTime = rtStart - g_tSegmentStart; - SetTime(g_tSegmentStart + sampleTime * g_dRate); - } else { - SetTime(rtStart); - } - } - if (atpf > 0 && m_pSubPicQueue) { - m_fps = 10000000.0 / atpf; - m_pSubPicQueue->SetFPS(m_fps); - } - AlphaBltSubPic(viewportRect, croppedVideoRect, nullptr, videoStretchFactor, xOffsetInPixels); - return S_OK; -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP CmadVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - ASSERT(!m_pMVR); - - HRESULT hr = S_FALSE; - - CHECK_HR(m_pMVR.CoCreateInstance(CLSID_madVR, GetOwner())); - - if (CComQIPtr pSR = m_pMVR) { - VERIFY(SUCCEEDED(pSR->SetCallback(this))); - } - - (*ppRenderer = (IUnknown*)(INonDelegatingUnknown*)(this))->AddRef(); - - CComQIPtr pBF = m_pMVR; - CComPtr pPin = GetFirstPin(pBF); - m_bHookedNewSegment = HookNewSegment((IPinC*)(IPin*)pPin); - - return S_OK; -} - -STDMETHODIMP_(void) CmadVRAllocatorPresenter::SetPosition(RECT w, RECT v) -{ - if (CComQIPtr pBV = m_pMVR) { - pBV->SetDefaultSourcePosition(); - pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top); - } - - if (CComQIPtr pVW = m_pMVR) { - pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top); - } - - SetVideoSize(GetVideoSize(false), GetVideoSize(true)); -} - -STDMETHODIMP CmadVRAllocatorPresenter::SetRotation(int rotation) -{ - if (AngleStep90(rotation)) { - HRESULT hr = E_NOTIMPL; - int curRotation = rotation; - if (CComQIPtr pMVRI = m_pMVR) { - pMVRI->GetInt("rotation", &curRotation); - } - if (CComQIPtr pMVRC = m_pMVR) { - hr = pMVRC->SendCommandInt("rotate", rotation); - if (SUCCEEDED(hr) && curRotation != rotation) { - hr = pMVRC->SendCommand("redraw"); - } - } - return hr; - } - return E_INVALIDARG; -} - -STDMETHODIMP_(int) CmadVRAllocatorPresenter::GetRotation() -{ - if (CComQIPtr pMVRI = m_pMVR) { - int rotation = 0; - if (SUCCEEDED(pMVRI->GetInt("rotation", &rotation))) { - return rotation; - } - } - return 0; -} - -STDMETHODIMP_(SIZE) CmadVRAllocatorPresenter::GetVideoSize(bool bCorrectAR) const -{ - CSize size = { 0, 0 }; - - if (!bCorrectAR) { - if (CComQIPtr pBV = m_pMVR) { - // Final size of the video, after all scaling and cropping operations - // This is also aspect ratio adjusted - pBV->GetVideoSize(&size.cx, &size.cy); - } - } else { - if (CComQIPtr pBV2 = m_pMVR) { - pBV2->GetPreferredAspectRatio(&size.cx, &size.cy); - } - } - - return size; -} - -STDMETHODIMP_(bool) CmadVRAllocatorPresenter::Paint(bool /*bAll*/) -{ - if (CComQIPtr pMVRC = m_pMVR) { - return SUCCEEDED(pMVRC->SendCommand("redraw")); - } - return false; -} - -STDMETHODIMP CmadVRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) -{ - HRESULT hr = E_NOTIMPL; - if (CComQIPtr pBV = m_pMVR) { - hr = pBV->GetCurrentImage((long*)size, (long*)lpDib); - } - return hr; -} - -STDMETHODIMP CmadVRAllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) -{ - HRESULT hr = E_NOTIMPL; - - if (CComQIPtr pMVREPS = m_pMVR) { - if (!pSrcData && !pTarget) { - hr = pMVREPS->ClearPixelShaders(bScreenSpace ? ShaderStage_PostScale : ShaderStage_PreScale); - } else { - hr = pMVREPS->AddPixelShader(pSrcData, pTarget, bScreenSpace ? ShaderStage_PostScale : ShaderStage_PreScale, nullptr); - } - } - - return hr; -} - -// ISubPicAllocatorPresenter2 - -STDMETHODIMP_(bool) CmadVRAllocatorPresenter::IsRendering() -{ - if (CComQIPtr pMVRI = m_pMVR) { - int playbackState; - if (SUCCEEDED(pMVRI->GetInt("playbackState", &playbackState))) { - return playbackState == State_Running; - } - } - return false; -} -// ISubPicAllocatorPresenter3 - -STDMETHODIMP CmadVRAllocatorPresenter::ClearPixelShaders(int target) -{ - ASSERT(TARGET_FRAME == ShaderStage_PreScale && TARGET_SCREEN == ShaderStage_PostScale); - HRESULT hr = E_NOTIMPL; - - if (CComQIPtr pMVREPS = m_pMVR) { - hr = pMVREPS->ClearPixelShaders(target); - } - return hr; -} - -STDMETHODIMP CmadVRAllocatorPresenter::AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) -{ - ASSERT(TARGET_FRAME == ShaderStage_PreScale && TARGET_SCREEN == ShaderStage_PostScale); - HRESULT hr = E_NOTIMPL; - - if (CComQIPtr pMVREPS = m_pMVR) { - hr = pMVREPS->AddPixelShader(sourceCode, profile, target, nullptr); - } - return hr; -} - -STDMETHODIMP_(bool) CmadVRAllocatorPresenter::ToggleStats() { - return false; -} +/* + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "madVRAllocatorPresenter.h" +#include "../../../SubPic/DX9SubPic.h" +#include "../../../SubPic/SubPicQueueImpl.h" +#include "RenderersSettings.h" +#include +#include +#include "IPinHook.h" +#include "Variables.h" +#include "Utils.h" + +using namespace DSObjects; + +CmadVRAllocatorPresenter::CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error) + : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) +{ + if (FAILED(hr)) { + _Error += L"ISubPicAllocatorPresenterImpl failed\n"; + return; + } + + hr = S_OK; +} + +CmadVRAllocatorPresenter::~CmadVRAllocatorPresenter() +{ + // the order is important here + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + m_pMVR = nullptr; + + if (m_bHookedNewSegment) { + UnhookNewSegment(); + } +} + +STDMETHODIMP CmadVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + if (riid != IID_IUnknown && m_pMVR) { + if (SUCCEEDED(m_pMVR->QueryInterface(riid, ppv))) { + return S_OK; + } + } + + return QI(ISubRenderCallback) + QI(ISubRenderCallback2) + QI(ISubRenderCallback3) + QI(ISubRenderCallback4) + QI(ISubPicAllocatorPresenter3) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubRenderCallback + +HRESULT CmadVRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev) +{ + if (!pD3DDev) { + // release all resources + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + __super::SetPosition(CRect(), CRect()); + return S_OK; + } + + const CRenderersSettings& r = GetRenderersSettings(); + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(pD3DDev, m_maxSubtitleTextureSize, true); + } + + HRESULT hr = S_OK; + if (!m_pSubPicQueue) { + CAutoLock cAutoLock(this); + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + m_pSubPicQueue->Invalidate(); + } + + if (SUCCEEDED(hr) && m_pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); + } + + return hr; +} + +// ISubRenderCallback3 + +HRESULT CmadVRAllocatorPresenter::RenderEx3(REFERENCE_TIME rtStart, + REFERENCE_TIME /*rtStop*/, + REFERENCE_TIME atpf, + RECT croppedVideoRect, + RECT /*originalVideoRect*/, + RECT viewportRect, + const double videoStretchFactor /*= 1.0*/, + int xOffsetInPixels /*= 0*/, DWORD flags /*= 0*/) +{ + CheckPointer(m_pSubPicQueue, E_UNEXPECTED); + + __super::SetPosition(viewportRect, croppedVideoRect); + if (!g_bExternalSubtitleTime) { + if (g_bExternalSubtitle && g_dRate != 0.0) { + const REFERENCE_TIME sampleTime = rtStart - g_tSegmentStart; + SetTime(g_tSegmentStart + sampleTime * g_dRate); + } else { + SetTime(rtStart); + } + } + if (atpf > 0 && m_pSubPicQueue) { + m_fps = 10000000.0 / atpf; + m_pSubPicQueue->SetFPS(m_fps); + } + AlphaBltSubPic(viewportRect, croppedVideoRect, nullptr, videoStretchFactor, xOffsetInPixels); + return S_OK; +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP CmadVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + ASSERT(!m_pMVR); + + HRESULT hr = S_FALSE; + + CHECK_HR(m_pMVR.CoCreateInstance(CLSID_madVR, GetOwner())); + + if (CComQIPtr pSR = m_pMVR) { + VERIFY(SUCCEEDED(pSR->SetCallback(this))); + } + + (*ppRenderer = (IUnknown*)(INonDelegatingUnknown*)(this))->AddRef(); + + CComQIPtr pBF = m_pMVR; + CComPtr pPin = GetFirstPin(pBF); + m_bHookedNewSegment = HookNewSegment((IPinC*)(IPin*)pPin); + + return S_OK; +} + +STDMETHODIMP_(void) CmadVRAllocatorPresenter::SetPosition(RECT w, RECT v) +{ + if (CComQIPtr pBV = m_pMVR) { + pBV->SetDefaultSourcePosition(); + pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top); + } + + if (CComQIPtr pVW = m_pMVR) { + pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top); + } + + SetVideoSize(GetVideoSize(false), GetVideoSize(true)); +} + +STDMETHODIMP CmadVRAllocatorPresenter::SetRotation(int rotation) +{ + if (AngleStep90(rotation)) { + HRESULT hr = E_NOTIMPL; + int curRotation = rotation; + if (CComQIPtr pMVRI = m_pMVR) { + pMVRI->GetInt("rotation", &curRotation); + } + if (CComQIPtr pMVRC = m_pMVR) { + hr = pMVRC->SendCommandInt("rotate", rotation); + if (SUCCEEDED(hr) && curRotation != rotation) { + hr = pMVRC->SendCommand("redraw"); + } + } + return hr; + } + return E_INVALIDARG; +} + +STDMETHODIMP_(int) CmadVRAllocatorPresenter::GetRotation() +{ + if (CComQIPtr pMVRI = m_pMVR) { + int rotation = 0; + if (SUCCEEDED(pMVRI->GetInt("rotation", &rotation))) { + return rotation; + } + } + return 0; +} + +STDMETHODIMP_(SIZE) CmadVRAllocatorPresenter::GetVideoSize(bool bCorrectAR) const +{ + CSize size = { 0, 0 }; + + if (!bCorrectAR) { + if (CComQIPtr pBV = m_pMVR) { + // Final size of the video, after all scaling and cropping operations + // This is also aspect ratio adjusted + pBV->GetVideoSize(&size.cx, &size.cy); + } + } else { + if (CComQIPtr pBV2 = m_pMVR) { + pBV2->GetPreferredAspectRatio(&size.cx, &size.cy); + } + } + + return size; +} + +STDMETHODIMP_(bool) CmadVRAllocatorPresenter::Paint(bool /*bAll*/) +{ + if (CComQIPtr pMVRC = m_pMVR) { + return SUCCEEDED(pMVRC->SendCommand("redraw")); + } + return false; +} + +STDMETHODIMP CmadVRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) +{ + HRESULT hr = E_NOTIMPL; + if (CComQIPtr pBV = m_pMVR) { + hr = pBV->GetCurrentImage((long*)size, (long*)lpDib); + } + return hr; +} + +STDMETHODIMP CmadVRAllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) +{ + HRESULT hr = E_NOTIMPL; + + if (CComQIPtr pMVREPS = m_pMVR) { + if (!pSrcData && !pTarget) { + hr = pMVREPS->ClearPixelShaders(bScreenSpace ? ShaderStage_PostScale : ShaderStage_PreScale); + } else { + hr = pMVREPS->AddPixelShader(pSrcData, pTarget, bScreenSpace ? ShaderStage_PostScale : ShaderStage_PreScale, nullptr); + } + } + + return hr; +} + +// ISubPicAllocatorPresenter2 + +STDMETHODIMP_(bool) CmadVRAllocatorPresenter::IsRendering() +{ + if (CComQIPtr pMVRI = m_pMVR) { + int playbackState; + if (SUCCEEDED(pMVRI->GetInt("playbackState", &playbackState))) { + return playbackState == State_Running; + } + } + return false; +} +// ISubPicAllocatorPresenter3 + +STDMETHODIMP CmadVRAllocatorPresenter::ClearPixelShaders(int target) +{ + ASSERT(TARGET_FRAME == ShaderStage_PreScale && TARGET_SCREEN == ShaderStage_PostScale); + HRESULT hr = E_NOTIMPL; + + if (CComQIPtr pMVREPS = m_pMVR) { + hr = pMVREPS->ClearPixelShaders(target); + } + return hr; +} + +STDMETHODIMP CmadVRAllocatorPresenter::AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) +{ + ASSERT(TARGET_FRAME == ShaderStage_PreScale && TARGET_SCREEN == ShaderStage_PostScale); + HRESULT hr = E_NOTIMPL; + + if (CComQIPtr pMVREPS = m_pMVR) { + hr = pMVREPS->AddPixelShader(sourceCode, profile, target, nullptr); + } + return hr; +} + +STDMETHODIMP_(bool) CmadVRAllocatorPresenter::ToggleStats() { + return false; +} diff --git a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h index 089c7b3d355..9cb736c6af2 100644 --- a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h @@ -1,89 +1,89 @@ -/* - * (C) 2006-2016 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 . - * - */ - -#pragma once - -#include "../SubPic/SubPicAllocatorPresenterImpl.h" -#include "../SubPic/ISubRender.h" - -namespace DSObjects -{ - class CmadVRAllocatorPresenter : public CSubPicAllocatorPresenterImpl, ISubRenderCallback4 - { - CComPtr m_pMVR; - public: - CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error); - virtual ~CmadVRAllocatorPresenter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override; - - // ISubRenderCallback - STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev) override; - STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, - int bottom, int width, int height) override { - return RenderEx(rtStart, 0, 0, left, top, right, bottom, width, height); - } - - // ISubRenderCallback2 - STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, - int left, int top, int right, int bottom, int width, int height) override { - return RenderEx2(rtStart, rtStop, atpf, { left, top, right, bottom }, - { left, top, right, bottom }, { 0, 0, width, height }); - } - - // ISubRenderCallback3 - STDMETHODIMP RenderEx2(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME atpf, RECT croppedVideoRect, - RECT originalVideoRect, RECT viewportRect, - const double videoStretchFactor = 1.0) override { - return RenderEx3(std::move(rtStart), std::move(rtStop), std::move(atpf), std::move(croppedVideoRect), - std::move(originalVideoRect), std::move(viewportRect), std::move(videoStretchFactor)); - } - - // ISubRenderCallback4 - STDMETHODIMP RenderEx3(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME atpf, RECT croppedVideoRect, - RECT originalVideoRect, RECT viewportRect, - const double videoStretchFactor = 1.0, - int xOffsetInPixels = 0, DWORD flags = 0) override; - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer) override; - STDMETHODIMP_(void) SetPosition(RECT w, RECT v) override; - STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const override; - STDMETHODIMP_(bool) Paint(bool bAll) override; - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size) override; - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) override { - return SetPixelShader2(pSrcData, pTarget, false); - } - STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) override; - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() override; - // ISubPicAllocatorPresenter3 - STDMETHODIMP SetRotation(int rotation) override; - STDMETHODIMP_(int) GetRotation() override; - STDMETHODIMP_(int) GetPixelShaderMode() override { return 9; } - STDMETHODIMP ClearPixelShaders(int target) override; - STDMETHODIMP AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) override; - STDMETHODIMP_(bool) ToggleStats() override; - }; -} +/* + * (C) 2006-2016 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 . + * + */ + +#pragma once + +#include "../SubPic/SubPicAllocatorPresenterImpl.h" +#include "../SubPic/ISubRender.h" + +namespace DSObjects +{ + class CmadVRAllocatorPresenter : public CSubPicAllocatorPresenterImpl, ISubRenderCallback4 + { + CComPtr m_pMVR; + public: + CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error); + virtual ~CmadVRAllocatorPresenter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override; + + // ISubRenderCallback + STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev) override; + STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, + int bottom, int width, int height) override { + return RenderEx(rtStart, 0, 0, left, top, right, bottom, width, height); + } + + // ISubRenderCallback2 + STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, + int left, int top, int right, int bottom, int width, int height) override { + return RenderEx2(rtStart, rtStop, atpf, { left, top, right, bottom }, + { left, top, right, bottom }, { 0, 0, width, height }); + } + + // ISubRenderCallback3 + STDMETHODIMP RenderEx2(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME atpf, RECT croppedVideoRect, + RECT originalVideoRect, RECT viewportRect, + const double videoStretchFactor = 1.0) override { + return RenderEx3(std::move(rtStart), std::move(rtStop), std::move(atpf), std::move(croppedVideoRect), + std::move(originalVideoRect), std::move(viewportRect), std::move(videoStretchFactor)); + } + + // ISubRenderCallback4 + STDMETHODIMP RenderEx3(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME atpf, RECT croppedVideoRect, + RECT originalVideoRect, RECT viewportRect, + const double videoStretchFactor = 1.0, + int xOffsetInPixels = 0, DWORD flags = 0) override; + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer) override; + STDMETHODIMP_(void) SetPosition(RECT w, RECT v) override; + STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const override; + STDMETHODIMP_(bool) Paint(bool bAll) override; + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size) override; + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) override { + return SetPixelShader2(pSrcData, pTarget, false); + } + STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) override; + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() override; + // ISubPicAllocatorPresenter3 + STDMETHODIMP SetRotation(int rotation) override; + STDMETHODIMP_(int) GetRotation() override; + STDMETHODIMP_(int) GetPixelShaderMode() override { return 9; } + STDMETHODIMP ClearPixelShaders(int target) override; + STDMETHODIMP AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) override; + STDMETHODIMP_(bool) ToggleStats() override; + }; +} diff --git a/src/filters/renderer/VideoRenderers/stdafx.cpp b/src/filters/renderer/VideoRenderers/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/renderer/VideoRenderers/stdafx.cpp +++ b/src/filters/renderer/VideoRenderers/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/renderer/VideoRenderers/stdafx.h b/src/filters/renderer/VideoRenderers/stdafx.h index dee6132a0c6..01abc636047 100644 --- a/src/filters/renderer/VideoRenderers/stdafx.h +++ b/src/filters/renderer/VideoRenderers/stdafx.h @@ -1,36 +1,36 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include -#include "BaseClasses/streams.h" -#include -#include - -#include "../../../DSUtil/DSUtil.h" - -#define CHECK_HR(exp) { if (FAILED(hr = exp)) return hr; } +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include +#include "BaseClasses/streams.h" +#include +#include + +#include "../../../DSUtil/DSUtil.h" + +#define CHECK_HR(exp) { if (FAILED(hr = exp)) return hr; } diff --git a/src/filters/source/BaseSource/BaseSource.cpp b/src/filters/source/BaseSource/BaseSource.cpp index df2549943e3..c145096e814 100644 --- a/src/filters/source/BaseSource/BaseSource.cpp +++ b/src/filters/source/BaseSource/BaseSource.cpp @@ -1,192 +1,192 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "BaseSource.h" -#include "../../../DSUtil/DSUtil.h" - -// -// CBaseSource -// - -// -// CBaseStream -// - -CBaseStream::CBaseStream(TCHAR* name, CSource* pParent, HRESULT* phr) - : CSourceStream(name, phr, pParent, L"Output") - , CSourceSeeking(name, (IPin*)this, phr, &m_cSharedState) - , m_AvgTimePerFrame(0) - , m_rtSampleTime(0) - , m_rtPosition(0) - , m_bDiscontinuity(FALSE) - , m_bFlushing(FALSE) -{ - CAutoLock cAutoLock(&m_cSharedState); - m_rtDuration = m_rtStop = 0; -} - -CBaseStream::~CBaseStream() -{ - CAutoLock cAutoLock(&m_cSharedState); -} - -STDMETHODIMP CBaseStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) - : CSourceStream::NonDelegatingQueryInterface(riid, ppv); -} - -void CBaseStream::UpdateFromSeek() -{ - if (ThreadExists()) { - // next time around the loop, the worker thread will - // pick up the position change. - // We need to flush all the existing data - we must do that here - // as our thread will probably be blocked in GetBuffer otherwise - - m_bFlushing = TRUE; - - DeliverBeginFlush(); - // make sure we have stopped pushing - Stop(); - // complete the flush - DeliverEndFlush(); - - m_bFlushing = FALSE; - - // restart - Run(); - } -} - -HRESULT CBaseStream::SetRate(double dRate) -{ - if (dRate <= 0) { - return E_INVALIDARG; - } - - { - CAutoLock lock(CSourceSeeking::m_pLock); - m_dRateSeeking = dRate; - } - - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CBaseStream::OnThreadStartPlay() -{ - m_bDiscontinuity = TRUE; - return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); -} - -HRESULT CBaseStream::ChangeStart() -{ - { - CAutoLock lock(CSourceSeeking::m_pLock); - m_rtSampleTime = 0; - m_rtPosition = m_rtStart; - } - - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CBaseStream::ChangeStop() -{ - { - CAutoLock lock(CSourceSeeking::m_pLock); - if (m_rtPosition < m_rtStop) { - return S_OK; - } - } - - // We're already past the new stop time -- better flush the graph. - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CBaseStream::OnThreadCreate() -{ - CAutoLock cAutoLockShared(&m_cSharedState); - - m_rtSampleTime = 0; - m_rtPosition = m_rtStart; - - return CSourceStream::OnThreadCreate(); -} - -HRESULT CBaseStream::FillBuffer(IMediaSample* pSample) -{ - { - HRESULT hr; - CAutoLock cAutoLockShared(&m_cSharedState); - - if (m_rtPosition >= m_rtStop) { - return S_FALSE; - } - - BYTE* pOut = nullptr; - if (FAILED(hr = pSample->GetPointer(&pOut)) || !pOut) { - return S_FALSE; - } - - int nFrame = (int)(m_rtPosition / m_AvgTimePerFrame); - - long len = pSample->GetSize(); - - hr = FillBuffer(pSample, nFrame, pOut, len); - if (hr != S_OK) { - return hr; - } - - pSample->SetActualDataLength(len); - - REFERENCE_TIME rtStart, rtStop; - // The sample times are modified by the current rate. - rtStart = static_cast(m_rtSampleTime / m_dRateSeeking); - rtStop = rtStart + static_cast(m_AvgTimePerFrame / m_dRateSeeking); - pSample->SetTime(&rtStart, &rtStop); - - m_rtSampleTime += m_AvgTimePerFrame; - m_rtPosition += m_AvgTimePerFrame; - } - - pSample->SetSyncPoint(TRUE); - - if (m_bDiscontinuity) { - pSample->SetDiscontinuity(TRUE); - m_bDiscontinuity = FALSE; - } - - return S_OK; -} - -STDMETHODIMP CBaseStream::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "BaseSource.h" +#include "../../../DSUtil/DSUtil.h" + +// +// CBaseSource +// + +// +// CBaseStream +// + +CBaseStream::CBaseStream(TCHAR* name, CSource* pParent, HRESULT* phr) + : CSourceStream(name, phr, pParent, L"Output") + , CSourceSeeking(name, (IPin*)this, phr, &m_cSharedState) + , m_AvgTimePerFrame(0) + , m_rtSampleTime(0) + , m_rtPosition(0) + , m_bDiscontinuity(FALSE) + , m_bFlushing(FALSE) +{ + CAutoLock cAutoLock(&m_cSharedState); + m_rtDuration = m_rtStop = 0; +} + +CBaseStream::~CBaseStream() +{ + CAutoLock cAutoLock(&m_cSharedState); +} + +STDMETHODIMP CBaseStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) + : CSourceStream::NonDelegatingQueryInterface(riid, ppv); +} + +void CBaseStream::UpdateFromSeek() +{ + if (ThreadExists()) { + // next time around the loop, the worker thread will + // pick up the position change. + // We need to flush all the existing data - we must do that here + // as our thread will probably be blocked in GetBuffer otherwise + + m_bFlushing = TRUE; + + DeliverBeginFlush(); + // make sure we have stopped pushing + Stop(); + // complete the flush + DeliverEndFlush(); + + m_bFlushing = FALSE; + + // restart + Run(); + } +} + +HRESULT CBaseStream::SetRate(double dRate) +{ + if (dRate <= 0) { + return E_INVALIDARG; + } + + { + CAutoLock lock(CSourceSeeking::m_pLock); + m_dRateSeeking = dRate; + } + + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CBaseStream::OnThreadStartPlay() +{ + m_bDiscontinuity = TRUE; + return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); +} + +HRESULT CBaseStream::ChangeStart() +{ + { + CAutoLock lock(CSourceSeeking::m_pLock); + m_rtSampleTime = 0; + m_rtPosition = m_rtStart; + } + + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CBaseStream::ChangeStop() +{ + { + CAutoLock lock(CSourceSeeking::m_pLock); + if (m_rtPosition < m_rtStop) { + return S_OK; + } + } + + // We're already past the new stop time -- better flush the graph. + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CBaseStream::OnThreadCreate() +{ + CAutoLock cAutoLockShared(&m_cSharedState); + + m_rtSampleTime = 0; + m_rtPosition = m_rtStart; + + return CSourceStream::OnThreadCreate(); +} + +HRESULT CBaseStream::FillBuffer(IMediaSample* pSample) +{ + { + HRESULT hr; + CAutoLock cAutoLockShared(&m_cSharedState); + + if (m_rtPosition >= m_rtStop) { + return S_FALSE; + } + + BYTE* pOut = nullptr; + if (FAILED(hr = pSample->GetPointer(&pOut)) || !pOut) { + return S_FALSE; + } + + int nFrame = (int)(m_rtPosition / m_AvgTimePerFrame); + + long len = pSample->GetSize(); + + hr = FillBuffer(pSample, nFrame, pOut, len); + if (hr != S_OK) { + return hr; + } + + pSample->SetActualDataLength(len); + + REFERENCE_TIME rtStart, rtStop; + // The sample times are modified by the current rate. + rtStart = static_cast(m_rtSampleTime / m_dRateSeeking); + rtStop = rtStart + static_cast(m_AvgTimePerFrame / m_dRateSeeking); + pSample->SetTime(&rtStart, &rtStop); + + m_rtSampleTime += m_AvgTimePerFrame; + m_rtPosition += m_AvgTimePerFrame; + } + + pSample->SetSyncPoint(TRUE); + + if (m_bDiscontinuity) { + pSample->SetDiscontinuity(TRUE); + m_bDiscontinuity = FALSE; + } + + return S_OK; +} + +STDMETHODIMP CBaseStream::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} diff --git a/src/filters/source/BaseSource/BaseSource.h b/src/filters/source/BaseSource/BaseSource.h index 548fe2c093a..d24977ba73b 100644 --- a/src/filters/source/BaseSource/BaseSource.h +++ b/src/filters/source/BaseSource/BaseSource.h @@ -1,130 +1,130 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2014 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 . - * - */ - -#pragma once - -#include "../../../DSUtil/DSUtil.h" - -template -class CBaseSource - : public CSource - , public IFileSourceFilter - , public IAMFilterMiscFlags -{ -protected: - CStringW m_fn; - -public: - CBaseSource(TCHAR* name, LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) - : CSource(name, lpunk, clsid) { - if (phr) { - *phr = S_OK; - } - } - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - CheckPointer(ppv, E_POINTER); - - return - QI(IFileSourceFilter) - QI(IAMFilterMiscFlags) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IFileSourceFilter - - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) { - // TODO: destroy any already existing pins and create new, now we are just going die nicely instead of doing it :) - if (GetPinCount() > 0) { - return VFW_E_ALREADY_CONNECTED; - } - - HRESULT hr = S_OK; - if (!(DEBUG_NEW TStream(pszFileName, this, &hr))) { - return E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - return hr; - } - - m_fn = pszFileName; - - return S_OK; - } - - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) { - CheckPointer(ppszFileName, E_POINTER); - - size_t nCount = m_fn.GetLength() + 1; - *ppszFileName = (LPOLESTR)CoTaskMemAlloc(nCount * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, nCount, m_fn); - - return S_OK; - } - - // IAMFilterMiscFlags - - STDMETHODIMP_(ULONG) GetMiscFlags() { - return AM_FILTER_MISC_FLAGS_IS_SOURCE; - } -}; - -class CBaseStream - : public CSourceStream - , public CSourceSeeking -{ -protected: - CCritSec m_cSharedState; - - REFERENCE_TIME m_AvgTimePerFrame; - REFERENCE_TIME m_rtSampleTime, m_rtPosition; - - BOOL m_bDiscontinuity, m_bFlushing; - - HRESULT OnThreadStartPlay(); - HRESULT OnThreadCreate(); - -private: - void UpdateFromSeek(); - STDMETHODIMP SetRate(double dRate); - - HRESULT ChangeStart(); - HRESULT ChangeStop(); - HRESULT ChangeRate() { return S_OK; } - -public: - CBaseStream(TCHAR* name, CSource* pParent, HRESULT* phr); - virtual ~CBaseStream(); - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT FillBuffer(IMediaSample* pSample); - - virtual HRESULT FillBuffer(IMediaSample* pSample, int nFrame, BYTE* pOut, long& len /*in+out*/) = 0; - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2014 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 . + * + */ + +#pragma once + +#include "../../../DSUtil/DSUtil.h" + +template +class CBaseSource + : public CSource + , public IFileSourceFilter + , public IAMFilterMiscFlags +{ +protected: + CStringW m_fn; + +public: + CBaseSource(TCHAR* name, LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) + : CSource(name, lpunk, clsid) { + if (phr) { + *phr = S_OK; + } + } + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + CheckPointer(ppv, E_POINTER); + + return + QI(IFileSourceFilter) + QI(IAMFilterMiscFlags) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IFileSourceFilter + + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) { + // TODO: destroy any already existing pins and create new, now we are just going die nicely instead of doing it :) + if (GetPinCount() > 0) { + return VFW_E_ALREADY_CONNECTED; + } + + HRESULT hr = S_OK; + if (!(DEBUG_NEW TStream(pszFileName, this, &hr))) { + return E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + return hr; + } + + m_fn = pszFileName; + + return S_OK; + } + + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) { + CheckPointer(ppszFileName, E_POINTER); + + size_t nCount = m_fn.GetLength() + 1; + *ppszFileName = (LPOLESTR)CoTaskMemAlloc(nCount * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, nCount, m_fn); + + return S_OK; + } + + // IAMFilterMiscFlags + + STDMETHODIMP_(ULONG) GetMiscFlags() { + return AM_FILTER_MISC_FLAGS_IS_SOURCE; + } +}; + +class CBaseStream + : public CSourceStream + , public CSourceSeeking +{ +protected: + CCritSec m_cSharedState; + + REFERENCE_TIME m_AvgTimePerFrame; + REFERENCE_TIME m_rtSampleTime, m_rtPosition; + + BOOL m_bDiscontinuity, m_bFlushing; + + HRESULT OnThreadStartPlay(); + HRESULT OnThreadCreate(); + +private: + void UpdateFromSeek(); + STDMETHODIMP SetRate(double dRate); + + HRESULT ChangeStart(); + HRESULT ChangeStop(); + HRESULT ChangeRate() { return S_OK; } + +public: + CBaseStream(TCHAR* name, CSource* pParent, HRESULT* phr); + virtual ~CBaseStream(); + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT FillBuffer(IMediaSample* pSample); + + virtual HRESULT FillBuffer(IMediaSample* pSample, int nFrame, BYTE* pOut, long& len /*in+out*/) = 0; + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; diff --git a/src/filters/source/BaseSource/BaseSource.vcxproj b/src/filters/source/BaseSource/BaseSource.vcxproj index 22eb871f703..8d7a4ab760d 100644 --- a/src/filters/source/BaseSource/BaseSource.vcxproj +++ b/src/filters/source/BaseSource/BaseSource.vcxproj @@ -1,66 +1,66 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F50E74C2-5BE7-4C9B-B1E7-6CA19CFAD34E} - BaseSource - MFCProj - BaseSource - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - Create - - - - - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F50E74C2-5BE7-4C9B-B1E7-6CA19CFAD34E} + BaseSource + MFCProj + BaseSource + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + Create + + + + + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/filters/source/BaseSource/BaseSource.vcxproj.filters b/src/filters/source/BaseSource/BaseSource.vcxproj.filters index 5bb15a89444..c6f97d0aa21 100644 --- a/src/filters/source/BaseSource/BaseSource.vcxproj.filters +++ b/src/filters/source/BaseSource/BaseSource.vcxproj.filters @@ -1,29 +1,29 @@ - - - - - {d55d7ca3-f025-4f7c-bfa1-01bb4db7f6cd} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {76184793-16c1-467e-90ad-b83f2bab29f7} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - + + + + + {d55d7ca3-f025-4f7c-bfa1-01bb4db7f6cd} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {76184793-16c1-467e-90ad-b83f2bab29f7} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/source/BaseSource/stdafx.cpp b/src/filters/source/BaseSource/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/source/BaseSource/stdafx.cpp +++ b/src/filters/source/BaseSource/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/source/BaseSource/stdafx.h b/src/filters/source/BaseSource/stdafx.h index 619304dd68e..a8517b3e334 100644 --- a/src/filters/source/BaseSource/stdafx.h +++ b/src/filters/source/BaseSource/stdafx.h @@ -1,35 +1,35 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/source/SubtitleSource/SubtitleSource.cpp b/src/filters/source/SubtitleSource/SubtitleSource.cpp index ee9a0a87969..5305853feba 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.cpp +++ b/src/filters/source/SubtitleSource/SubtitleSource.cpp @@ -1,801 +1,801 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "SubtitleSource.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -static int _WIDTH = 640; -static int _HEIGHT = 480; -static int _ATPF = 400000; - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Subtitle, &MEDIASUBTYPE_NULL}, - {&MEDIATYPE_Text, &MEDIASUBTYPE_NULL}, - {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB32}, -}; - -const AMOVIESETUP_PIN sudOpPin[] = { - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}, -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CSubtitleSourceASCII), L"MPC-HC SubtitleSource (S_TEXT/ASCII)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceUTF8), L"MPC-HC SubtitleSource (S_TEXT/UTF8)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceSSA), L"MPC-HC SubtitleSource (S_TEXT/SSA)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceASS), L"MPC-HC SubtitleSource (S_TEXT/ASS)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceUSF), L"MPC-HC SubtitleSource (S_TEXT/USF)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourcePreview), L"MPC-HC SubtitleSource (Preview)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceARGB), L"MPC-HC SubtitleSource (ARGB)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, - {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, - {sudFilter[2].strName, sudFilter[2].clsID, CreateInstance, nullptr, &sudFilter[2]}, - {sudFilter[3].strName, sudFilter[3].clsID, CreateInstance, nullptr, &sudFilter[3]}, - // {sudFilter[4].strName, sudFilter[4].clsID, CreateInstance, nullptr, &sudFilter[4]}, - {sudFilter[5].strName, sudFilter[5].clsID, CreateInstance, nullptr, &sudFilter[5]}, - {sudFilter[6].strName, sudFilter[6].clsID, CreateInstance, nullptr, &sudFilter[6]}, -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - /*CString clsid = CStringFromGUID(__uuidof(CSubtitleSourcePreview)); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".sub"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".srt"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".smi"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".ssa"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".ass"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".xss"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".usf"), - _T("Source Filter"), clsid);*/ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - DeleteRegKey(_T("Media Type\\Extensions"), _T(".sub")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".srt")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".smi")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".ssa")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".ass")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".xss")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".usf")); - /**/ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -class CSubtitleSourceApp : public CFilterApp -{ -public: - BOOL InitInstance() { - if (!__super::InitInstance()) { - return FALSE; - } - - _WIDTH = GetProfileInt(_T("SubtitleSource"), _T("w"), 640); - _HEIGHT = GetProfileInt(_T("SubtitleSource"), _T("h"), 480); - _ATPF = GetProfileInt(_T("SubtitleSource"), _T("atpf"), 400000); - if (_ATPF <= 0) { - _ATPF = 400000; - } - WriteProfileInt(_T("SubtitleSource"), _T("w"), _WIDTH); - WriteProfileInt(_T("SubtitleSource"), _T("h"), _HEIGHT); - WriteProfileInt(_T("SubtitleSource"), _T("atpf"), _ATPF); - - return TRUE; - } -}; - -CSubtitleSourceApp theApp; - -#endif - -// -// CSubtitleSource -// - -CSubtitleSource::CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) - : CSource(NAME("CSubtitleSource"), lpunk, clsid) -{ -} - -CSubtitleSource::~CSubtitleSource() -{ -} - -STDMETHODIMP CSubtitleSource::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFileSourceFilter) - QI(IAMFilterMiscFlags) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IFileSourceFilter - -STDMETHODIMP CSubtitleSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - if (GetPinCount() > 0) { - return VFW_E_ALREADY_CONNECTED; - } - - HRESULT hr = S_OK; - if (!(DEBUG_NEW CSubtitleStream(pszFileName, this, &hr))) { - return E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - return hr; - } - - m_fn = pszFileName; - - return S_OK; -} - -STDMETHODIMP CSubtitleSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!*ppszFileName) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - - return S_OK; -} - -// IAMFilterMiscFlags - -ULONG CSubtitleSource::GetMiscFlags() -{ - return AM_FILTER_MISC_FLAGS_IS_SOURCE; -} - -STDMETHODIMP CSubtitleSource::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - wcscpy_s(pInfo->achName, SubtitleSourceName); - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -// -// CSubtitleStream -// - -CSubtitleStream::CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr) - : CSourceStream(NAME("SubtitleStream"), phr, pParent, L"Output") - , CSourceSeeking(NAME("SubtitleStream"), (IPin*)this, phr, &m_cSharedState) - , m_nPosition(0) - , m_bDiscontinuity(FALSE) - , m_bFlushing(FALSE) - , m_rts(nullptr) -{ - CAutoLock cAutoLock(&m_cSharedState); - - CString fn(wfn); - - if (!m_rts.Open(fn, DEFAULT_CHARSET)) { - *phr = E_FAIL; - return; - } - - m_rts.CreateDefaultStyle(DEFAULT_CHARSET); - m_rts.ConvertToTimeBased(25); - m_rts.Sort(); - - m_rtDuration = 0; - for (size_t i = 0, cnt = m_rts.GetCount(); i < cnt; i++) { - m_rtDuration = std::max(m_rtDuration, 10000i64 * m_rts[i].end); - } - - m_rtStop = m_rtDuration; - - *phr = m_rtDuration > 0 ? S_OK : E_FAIL; -} - -CSubtitleStream::~CSubtitleStream() -{ - CAutoLock cAutoLock(&m_cSharedState); -} - -STDMETHODIMP CSubtitleStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) //GetInterface((IMediaSeeking*)this, ppv) - : CSourceStream::NonDelegatingQueryInterface(riid, ppv); -} - -void CSubtitleStream::UpdateFromSeek() -{ - if (ThreadExists()) { - // next time around the loop, the worker thread will - // pick up the position change. - // We need to flush all the existing data - we must do that here - // as our thread will probably be blocked in GetBuffer otherwise - - m_bFlushing = TRUE; - - DeliverBeginFlush(); - // make sure we have stopped pushing - Stop(); - // complete the flush - DeliverEndFlush(); - - m_bFlushing = FALSE; - - // restart - Run(); - } -} - -HRESULT CSubtitleStream::SetRate(double dRate) -{ - if (dRate <= 0) { - return E_INVALIDARG; - } - - { - CAutoLock lock(CSourceSeeking::m_pLock); - m_dRateSeeking = dRate; - } - - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CSubtitleStream::OnThreadStartPlay() -{ - m_bDiscontinuity = TRUE; - return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); -} - -HRESULT CSubtitleStream::ChangeStart() -{ - { - CAutoLock lock(CSourceSeeking::m_pLock); - - OnThreadCreate(); - /*if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) - { - m_nPosition = (int)(m_rtStart/10000)*1/1000; - } - else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) - { - int m_nSegments = 0; - if (!m_rts.SearchSubs((int)(m_rtStart/10000), 25, &m_nPosition, &m_nSegments)) - m_nPosition = m_nSegments; - } - else - { - m_nPosition = m_rts.SearchSub((int)(m_rtStart/10000), 25); - if (m_nPosition < 0) m_nPosition = 0; - else if (m_rts[m_nPosition].end <= (int)(m_rtStart/10000)) m_nPosition++; - }*/ - } - - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CSubtitleStream::ChangeStop() -{ - /*{ - CAutoLock lock(CSourceSeeking::m_pLock); - if (m_rtPosition < m_rtStop) - return S_OK; - }*/ - // We're already past the new stop time -- better flush the graph. - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CSubtitleStream::OnThreadCreate() -{ - CAutoLock cAutoLockShared(&m_cSharedState); - - if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { - m_nPosition = (int)(m_rtStart / _ATPF); - } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { - int m_nSegments = 0; - if (!m_rts.SearchSubs((int)(m_rtStart / 10000), 10000000.0 / _ATPF, &m_nPosition, &m_nSegments)) { - m_nPosition = m_nSegments; - } - } else { - m_nPosition = m_rts.SearchSub((int)(m_rtStart / 10000), 25); - if (m_nPosition < 0) { - m_nPosition = 0; - } else if (m_rts[m_nPosition].end <= (int)(m_rtStart / 10000)) { - m_nPosition++; - } - } - - return CSourceStream::OnThreadCreate(); -} - -HRESULT CSubtitleStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - //CAutoLock cAutoLock(m_pFilter->pStateLock()); - - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - if (m_mt.majortype == MEDIATYPE_Video) { - pProperties->cBuffers = 2; - pProperties->cbBuffer = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader.biSizeImage; - } else { - pProperties->cBuffers = 1; - pProperties->cbBuffer = 0x10000; - } - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CSubtitleStream::FillBuffer(IMediaSample* pSample) -{ - { - CAutoLock cAutoLockShared(&m_cSharedState); - - BYTE* pData = nullptr; - if (FAILED(pSample->GetPointer(&pData)) || !pData) { - return S_FALSE; - } - - AM_MEDIA_TYPE* pmt; - if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { - CMediaType mt(*pmt); - SetMediaType(&mt); - DeleteMediaType(pmt); - } - - int len = 0; - REFERENCE_TIME rtStart, rtStop; - - if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { - rtStart = (REFERENCE_TIME)((m_nPosition * _ATPF - m_rtStart) / m_dRateSeeking); - rtStop = (REFERENCE_TIME)(((m_nPosition + 1) * _ATPF - m_rtStart) / m_dRateSeeking); - if (m_rtStart + rtStart >= m_rtDuration) { - return S_FALSE; - } - - BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; - - SubPicDesc spd; - spd.w = _WIDTH; - spd.h = _HEIGHT; - spd.bpp = 32; - spd.pitch = bmi.biWidth * 4; - spd.bits = pData; - - len = spd.h * spd.pitch; - - for (int y = 0; y < spd.h; y++) { - memsetd((DWORD*)(pData + spd.pitch * y), 0xff000000, spd.w * 4); - } - - RECT bbox; - m_rts.Render(spd, m_nPosition * _ATPF, 10000000.0 / _ATPF, bbox); - - for (int y = 0; y < spd.h; y++) { - DWORD* p = (DWORD*)(pData + spd.pitch * y); - for (int x = 0; x < spd.w; x++, p++) { - *p = (0xff000000 - (*p & 0xff000000)) | (*p & 0xffffff); - } - } - } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { - const STSSegment* stss = m_rts.GetSegment(m_nPosition); - if (!stss) { - return S_FALSE; - } - - BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; - - SubPicDesc spd; - spd.w = _WIDTH; - spd.h = _HEIGHT; - spd.bpp = 32; - spd.pitch = bmi.biWidth * 4; - spd.bits = pData; - - len = spd.h * spd.pitch; - - for (int y = 0; y < spd.h; y++) { - DWORD c1 = 0xff606060, c2 = 0xffa0a0a0; - if (y & 32) { - c1 ^= c2, c2 ^= c1, c1 ^= c2; - } - DWORD* p = (DWORD*)(pData + spd.pitch * y); - for (int x = 0; x < spd.w; x += 32, p += 32) { - memsetd(p, (x & 32) ? c1 : c2, std::min(spd.w - x, 32) * 4); - } - } - - RECT bbox; - m_rts.Render(spd, 10000i64 * (stss->start + stss->end) / 2, 10000000.0 / _ATPF, bbox); - - rtStart = (REFERENCE_TIME)((10000i64 * stss->start - m_rtStart) / m_dRateSeeking); - rtStop = (REFERENCE_TIME)((10000i64 * stss->end - m_rtStart) / m_dRateSeeking); - } else { - if ((size_t)m_nPosition >= m_rts.GetCount()) { - return S_FALSE; - } - - STSEntry& stse = m_rts[m_nPosition]; - - if (stse.start >= m_rtStop / 10000) { - return S_FALSE; - } - - if (m_mt.majortype == MEDIATYPE_Subtitle && m_mt.subtype == MEDIASUBTYPE_UTF8) { - CStringA str = UTF16To8(m_rts.GetStrW(m_nPosition, false)); - memcpy((char*)pData, str, len = str.GetLength()); - } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS)) { - CStringW line; - line.Format(L"%d,%d,%s,%s,%d,%d,%d,%s,%s", - stse.readorder, stse.layer, stse.style.GetString(), stse.actor.GetString(), - stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, - stse.effect.GetString(), m_rts.GetStrW(m_nPosition, true).GetString()); - - CStringA str = UTF16To8(line); - memcpy((char*)pData, str, len = str.GetLength()); - } else if (m_mt.majortype == MEDIATYPE_Text && m_mt.subtype == MEDIASUBTYPE_NULL) { - CStringA str = m_rts.GetStrA(m_nPosition, false); - memcpy((char*)pData, str, len = str.GetLength()); - } else { - return S_FALSE; - } - - rtStart = (REFERENCE_TIME)((10000i64 * stse.start - m_rtStart) / m_dRateSeeking); - rtStop = (REFERENCE_TIME)((10000i64 * stse.end - m_rtStart) / m_dRateSeeking); - } - - pSample->SetTime(&rtStart, &rtStop); - pSample->SetActualDataLength(len); - - m_nPosition++; - } - - pSample->SetSyncPoint(TRUE); - - if (m_bDiscontinuity) { - pSample->SetDiscontinuity(TRUE); - m_bDiscontinuity = FALSE; - } - - return S_OK; -} - -HRESULT CSubtitleStream::GetMediaType(CMediaType* pmt) -{ - return (static_cast(m_pFilter))->GetMediaType(pmt); -} - -HRESULT CSubtitleStream::CheckMediaType(const CMediaType* pmt) -{ - CAutoLock lock(m_pFilter->pStateLock()); - - CMediaType mt; - GetMediaType(&mt); - - if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { - return NOERROR; - } - - return E_FAIL; -} - -STDMETHODIMP CSubtitleStream::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} - -// -// CSubtitleSourceASCII -// - -CSubtitleSourceASCII::CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceASCII::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Text); - pmt->SetSubtype(&MEDIASUBTYPE_NULL); - pmt->SetFormatType(&FORMAT_None); - pmt->ResetFormatBuffer(); - - return NOERROR; -} - -// -// CSubtitleSourceUTF8 -// - -CSubtitleSourceUTF8::CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceUTF8::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Subtitle); - pmt->SetSubtype(&MEDIASUBTYPE_UTF8); - pmt->SetFormatType(&FORMAT_SubtitleInfo); - SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); - ZeroMemory(psi, pmt->FormatLength()); - strcpy_s(psi->IsoLang, "eng"); - - return NOERROR; -} - -// -// CSubtitleSourceSSA -// - -CSubtitleSourceSSA::CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceSSA::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Subtitle); - pmt->SetSubtype(&MEDIASUBTYPE_SSA); - pmt->SetFormatType(&FORMAT_SubtitleInfo); - - CSimpleTextSubtitle sts; - sts.Open(CString(m_fn), DEFAULT_CHARSET); - sts.RemoveAll(); - - CFile f; - TCHAR path[MAX_PATH], fn[MAX_PATH]; - if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { - return E_FAIL; - } - - _tremove(fn); - - _tcscat_s(fn, _T(".ssa")); - - if (!sts.SaveAs(fn, Subtitle::SSA, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { - return E_FAIL; - } - - int len = (int)f.GetLength() - 3; - f.Seek(3, CFile::begin); - - SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); - ZeroMemory(psi, pmt->FormatLength()); - psi->dwOffset = sizeof(SUBTITLEINFO); - strcpy_s(psi->IsoLang, "eng"); - f.Read(pmt->pbFormat + psi->dwOffset, len); - f.Close(); - - _tremove(fn); - - return NOERROR; -} - -// -// CSubtitleSourceASS -// - -CSubtitleSourceASS::CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceASS::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Subtitle); - pmt->SetSubtype(&MEDIASUBTYPE_ASS); - pmt->SetFormatType(&FORMAT_SubtitleInfo); - - CSimpleTextSubtitle sts; - sts.Open(CString(m_fn), DEFAULT_CHARSET); - sts.RemoveAll(); - - CFile f; - TCHAR path[MAX_PATH], fn[MAX_PATH]; - if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { - return E_FAIL; - } - - _tremove(fn); - - _tcscat_s(fn, _T(".ass")); - - if (!sts.SaveAs(fn, Subtitle::ASS, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { - return E_FAIL; - } - - int len = (int)f.GetLength(); - - SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); - ZeroMemory(psi, pmt->FormatLength()); - psi->dwOffset = sizeof(SUBTITLEINFO); - strcpy_s(psi->IsoLang, "eng"); - f.Read(pmt->pbFormat + psi->dwOffset, len); - f.Close(); - - _tremove(fn); - - return NOERROR; -} - -// -// CSubtitleSourceUSF -// - -CSubtitleSourceUSF::CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceUSF::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Subtitle); - pmt->SetSubtype(&MEDIASUBTYPE_USF); - pmt->SetFormatType(&FORMAT_SubtitleInfo); - SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); - ZeroMemory(psi, pmt->FormatLength()); - strcpy_s(psi->IsoLang, "eng"); - // TODO: ... - - return NOERROR; -} - -// -// CSubtitleSourcePreview -// - -CSubtitleSourcePreview::CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourcePreview::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Video); - pmt->SetSubtype(&MEDIASUBTYPE_RGB32); - pmt->SetFormatType(&FORMAT_VideoInfo); - VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); - ZeroMemory(pvih, pmt->FormatLength()); - pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); - pvih->bmiHeader.biWidth = _WIDTH; - pvih->bmiHeader.biHeight = _HEIGHT; - pvih->bmiHeader.biBitCount = 32; - pvih->bmiHeader.biCompression = BI_RGB; - pvih->bmiHeader.biPlanes = 1; - pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth * abs(pvih->bmiHeader.biHeight) * pvih->bmiHeader.biBitCount >> 3; - - return NOERROR; -} - -// -// CSubtitleSourceARGB -// - -CSubtitleSourceARGB::CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceARGB::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Video); - pmt->SetSubtype(&MEDIASUBTYPE_ARGB32); - pmt->SetFormatType(&FORMAT_VideoInfo); - VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); - ZeroMemory(pvih, pmt->FormatLength()); - pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); - // TODO: read w,h,fps from a config file or registry - pvih->bmiHeader.biWidth = _WIDTH; - pvih->bmiHeader.biHeight = _HEIGHT; - pvih->bmiHeader.biBitCount = 32; - pvih->bmiHeader.biCompression = BI_RGB; - pvih->bmiHeader.biPlanes = 1; - pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth * abs(pvih->bmiHeader.biHeight) * pvih->bmiHeader.biBitCount >> 3; - - return NOERROR; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "SubtitleSource.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +static int _WIDTH = 640; +static int _HEIGHT = 480; +static int _ATPF = 400000; + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Subtitle, &MEDIASUBTYPE_NULL}, + {&MEDIATYPE_Text, &MEDIASUBTYPE_NULL}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB32}, +}; + +const AMOVIESETUP_PIN sudOpPin[] = { + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}, +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CSubtitleSourceASCII), L"MPC-HC SubtitleSource (S_TEXT/ASCII)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceUTF8), L"MPC-HC SubtitleSource (S_TEXT/UTF8)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceSSA), L"MPC-HC SubtitleSource (S_TEXT/SSA)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceASS), L"MPC-HC SubtitleSource (S_TEXT/ASS)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceUSF), L"MPC-HC SubtitleSource (S_TEXT/USF)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourcePreview), L"MPC-HC SubtitleSource (Preview)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceARGB), L"MPC-HC SubtitleSource (ARGB)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, + {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, + {sudFilter[2].strName, sudFilter[2].clsID, CreateInstance, nullptr, &sudFilter[2]}, + {sudFilter[3].strName, sudFilter[3].clsID, CreateInstance, nullptr, &sudFilter[3]}, + // {sudFilter[4].strName, sudFilter[4].clsID, CreateInstance, nullptr, &sudFilter[4]}, + {sudFilter[5].strName, sudFilter[5].clsID, CreateInstance, nullptr, &sudFilter[5]}, + {sudFilter[6].strName, sudFilter[6].clsID, CreateInstance, nullptr, &sudFilter[6]}, +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + /*CString clsid = CStringFromGUID(__uuidof(CSubtitleSourcePreview)); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".sub"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".srt"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".smi"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".ssa"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".ass"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".xss"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".usf"), + _T("Source Filter"), clsid);*/ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + DeleteRegKey(_T("Media Type\\Extensions"), _T(".sub")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".srt")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".smi")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".ssa")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".ass")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".xss")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".usf")); + /**/ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +class CSubtitleSourceApp : public CFilterApp +{ +public: + BOOL InitInstance() { + if (!__super::InitInstance()) { + return FALSE; + } + + _WIDTH = GetProfileInt(_T("SubtitleSource"), _T("w"), 640); + _HEIGHT = GetProfileInt(_T("SubtitleSource"), _T("h"), 480); + _ATPF = GetProfileInt(_T("SubtitleSource"), _T("atpf"), 400000); + if (_ATPF <= 0) { + _ATPF = 400000; + } + WriteProfileInt(_T("SubtitleSource"), _T("w"), _WIDTH); + WriteProfileInt(_T("SubtitleSource"), _T("h"), _HEIGHT); + WriteProfileInt(_T("SubtitleSource"), _T("atpf"), _ATPF); + + return TRUE; + } +}; + +CSubtitleSourceApp theApp; + +#endif + +// +// CSubtitleSource +// + +CSubtitleSource::CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) + : CSource(NAME("CSubtitleSource"), lpunk, clsid) +{ +} + +CSubtitleSource::~CSubtitleSource() +{ +} + +STDMETHODIMP CSubtitleSource::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFileSourceFilter) + QI(IAMFilterMiscFlags) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IFileSourceFilter + +STDMETHODIMP CSubtitleSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + if (GetPinCount() > 0) { + return VFW_E_ALREADY_CONNECTED; + } + + HRESULT hr = S_OK; + if (!(DEBUG_NEW CSubtitleStream(pszFileName, this, &hr))) { + return E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + return hr; + } + + m_fn = pszFileName; + + return S_OK; +} + +STDMETHODIMP CSubtitleSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!*ppszFileName) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + + return S_OK; +} + +// IAMFilterMiscFlags + +ULONG CSubtitleSource::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_SOURCE; +} + +STDMETHODIMP CSubtitleSource::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + wcscpy_s(pInfo->achName, SubtitleSourceName); + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +// +// CSubtitleStream +// + +CSubtitleStream::CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr) + : CSourceStream(NAME("SubtitleStream"), phr, pParent, L"Output") + , CSourceSeeking(NAME("SubtitleStream"), (IPin*)this, phr, &m_cSharedState) + , m_nPosition(0) + , m_bDiscontinuity(FALSE) + , m_bFlushing(FALSE) + , m_rts(nullptr) +{ + CAutoLock cAutoLock(&m_cSharedState); + + CString fn(wfn); + + if (!m_rts.Open(fn, DEFAULT_CHARSET)) { + *phr = E_FAIL; + return; + } + + m_rts.CreateDefaultStyle(DEFAULT_CHARSET); + m_rts.ConvertToTimeBased(25); + m_rts.Sort(); + + m_rtDuration = 0; + for (size_t i = 0, cnt = m_rts.GetCount(); i < cnt; i++) { + m_rtDuration = std::max(m_rtDuration, 10000i64 * m_rts[i].end); + } + + m_rtStop = m_rtDuration; + + *phr = m_rtDuration > 0 ? S_OK : E_FAIL; +} + +CSubtitleStream::~CSubtitleStream() +{ + CAutoLock cAutoLock(&m_cSharedState); +} + +STDMETHODIMP CSubtitleStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) //GetInterface((IMediaSeeking*)this, ppv) + : CSourceStream::NonDelegatingQueryInterface(riid, ppv); +} + +void CSubtitleStream::UpdateFromSeek() +{ + if (ThreadExists()) { + // next time around the loop, the worker thread will + // pick up the position change. + // We need to flush all the existing data - we must do that here + // as our thread will probably be blocked in GetBuffer otherwise + + m_bFlushing = TRUE; + + DeliverBeginFlush(); + // make sure we have stopped pushing + Stop(); + // complete the flush + DeliverEndFlush(); + + m_bFlushing = FALSE; + + // restart + Run(); + } +} + +HRESULT CSubtitleStream::SetRate(double dRate) +{ + if (dRate <= 0) { + return E_INVALIDARG; + } + + { + CAutoLock lock(CSourceSeeking::m_pLock); + m_dRateSeeking = dRate; + } + + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CSubtitleStream::OnThreadStartPlay() +{ + m_bDiscontinuity = TRUE; + return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); +} + +HRESULT CSubtitleStream::ChangeStart() +{ + { + CAutoLock lock(CSourceSeeking::m_pLock); + + OnThreadCreate(); + /*if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) + { + m_nPosition = (int)(m_rtStart/10000)*1/1000; + } + else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) + { + int m_nSegments = 0; + if (!m_rts.SearchSubs((int)(m_rtStart/10000), 25, &m_nPosition, &m_nSegments)) + m_nPosition = m_nSegments; + } + else + { + m_nPosition = m_rts.SearchSub((int)(m_rtStart/10000), 25); + if (m_nPosition < 0) m_nPosition = 0; + else if (m_rts[m_nPosition].end <= (int)(m_rtStart/10000)) m_nPosition++; + }*/ + } + + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CSubtitleStream::ChangeStop() +{ + /*{ + CAutoLock lock(CSourceSeeking::m_pLock); + if (m_rtPosition < m_rtStop) + return S_OK; + }*/ + // We're already past the new stop time -- better flush the graph. + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CSubtitleStream::OnThreadCreate() +{ + CAutoLock cAutoLockShared(&m_cSharedState); + + if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { + m_nPosition = (int)(m_rtStart / _ATPF); + } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { + int m_nSegments = 0; + if (!m_rts.SearchSubs((int)(m_rtStart / 10000), 10000000.0 / _ATPF, &m_nPosition, &m_nSegments)) { + m_nPosition = m_nSegments; + } + } else { + m_nPosition = m_rts.SearchSub((int)(m_rtStart / 10000), 25); + if (m_nPosition < 0) { + m_nPosition = 0; + } else if (m_rts[m_nPosition].end <= (int)(m_rtStart / 10000)) { + m_nPosition++; + } + } + + return CSourceStream::OnThreadCreate(); +} + +HRESULT CSubtitleStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + //CAutoLock cAutoLock(m_pFilter->pStateLock()); + + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + if (m_mt.majortype == MEDIATYPE_Video) { + pProperties->cBuffers = 2; + pProperties->cbBuffer = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader.biSizeImage; + } else { + pProperties->cBuffers = 1; + pProperties->cbBuffer = 0x10000; + } + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CSubtitleStream::FillBuffer(IMediaSample* pSample) +{ + { + CAutoLock cAutoLockShared(&m_cSharedState); + + BYTE* pData = nullptr; + if (FAILED(pSample->GetPointer(&pData)) || !pData) { + return S_FALSE; + } + + AM_MEDIA_TYPE* pmt; + if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { + CMediaType mt(*pmt); + SetMediaType(&mt); + DeleteMediaType(pmt); + } + + int len = 0; + REFERENCE_TIME rtStart, rtStop; + + if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { + rtStart = (REFERENCE_TIME)((m_nPosition * _ATPF - m_rtStart) / m_dRateSeeking); + rtStop = (REFERENCE_TIME)(((m_nPosition + 1) * _ATPF - m_rtStart) / m_dRateSeeking); + if (m_rtStart + rtStart >= m_rtDuration) { + return S_FALSE; + } + + BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; + + SubPicDesc spd; + spd.w = _WIDTH; + spd.h = _HEIGHT; + spd.bpp = 32; + spd.pitch = bmi.biWidth * 4; + spd.bits = pData; + + len = spd.h * spd.pitch; + + for (int y = 0; y < spd.h; y++) { + memsetd((DWORD*)(pData + spd.pitch * y), 0xff000000, spd.w * 4); + } + + RECT bbox; + m_rts.Render(spd, m_nPosition * _ATPF, 10000000.0 / _ATPF, bbox); + + for (int y = 0; y < spd.h; y++) { + DWORD* p = (DWORD*)(pData + spd.pitch * y); + for (int x = 0; x < spd.w; x++, p++) { + *p = (0xff000000 - (*p & 0xff000000)) | (*p & 0xffffff); + } + } + } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { + const STSSegment* stss = m_rts.GetSegment(m_nPosition); + if (!stss) { + return S_FALSE; + } + + BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; + + SubPicDesc spd; + spd.w = _WIDTH; + spd.h = _HEIGHT; + spd.bpp = 32; + spd.pitch = bmi.biWidth * 4; + spd.bits = pData; + + len = spd.h * spd.pitch; + + for (int y = 0; y < spd.h; y++) { + DWORD c1 = 0xff606060, c2 = 0xffa0a0a0; + if (y & 32) { + c1 ^= c2, c2 ^= c1, c1 ^= c2; + } + DWORD* p = (DWORD*)(pData + spd.pitch * y); + for (int x = 0; x < spd.w; x += 32, p += 32) { + memsetd(p, (x & 32) ? c1 : c2, std::min(spd.w - x, 32) * 4); + } + } + + RECT bbox; + m_rts.Render(spd, 10000i64 * (stss->start + stss->end) / 2, 10000000.0 / _ATPF, bbox); + + rtStart = (REFERENCE_TIME)((10000i64 * stss->start - m_rtStart) / m_dRateSeeking); + rtStop = (REFERENCE_TIME)((10000i64 * stss->end - m_rtStart) / m_dRateSeeking); + } else { + if ((size_t)m_nPosition >= m_rts.GetCount()) { + return S_FALSE; + } + + STSEntry& stse = m_rts[m_nPosition]; + + if (stse.start >= m_rtStop / 10000) { + return S_FALSE; + } + + if (m_mt.majortype == MEDIATYPE_Subtitle && m_mt.subtype == MEDIASUBTYPE_UTF8) { + CStringA str = UTF16To8(m_rts.GetStrW(m_nPosition, false)); + memcpy((char*)pData, str, len = str.GetLength()); + } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS)) { + CStringW line; + line.Format(L"%d,%d,%s,%s,%d,%d,%d,%s,%s", + stse.readorder, stse.layer, stse.style.GetString(), stse.actor.GetString(), + stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, + stse.effect.GetString(), m_rts.GetStrW(m_nPosition, true).GetString()); + + CStringA str = UTF16To8(line); + memcpy((char*)pData, str, len = str.GetLength()); + } else if (m_mt.majortype == MEDIATYPE_Text && m_mt.subtype == MEDIASUBTYPE_NULL) { + CStringA str = m_rts.GetStrA(m_nPosition, false); + memcpy((char*)pData, str, len = str.GetLength()); + } else { + return S_FALSE; + } + + rtStart = (REFERENCE_TIME)((10000i64 * stse.start - m_rtStart) / m_dRateSeeking); + rtStop = (REFERENCE_TIME)((10000i64 * stse.end - m_rtStart) / m_dRateSeeking); + } + + pSample->SetTime(&rtStart, &rtStop); + pSample->SetActualDataLength(len); + + m_nPosition++; + } + + pSample->SetSyncPoint(TRUE); + + if (m_bDiscontinuity) { + pSample->SetDiscontinuity(TRUE); + m_bDiscontinuity = FALSE; + } + + return S_OK; +} + +HRESULT CSubtitleStream::GetMediaType(CMediaType* pmt) +{ + return (static_cast(m_pFilter))->GetMediaType(pmt); +} + +HRESULT CSubtitleStream::CheckMediaType(const CMediaType* pmt) +{ + CAutoLock lock(m_pFilter->pStateLock()); + + CMediaType mt; + GetMediaType(&mt); + + if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { + return NOERROR; + } + + return E_FAIL; +} + +STDMETHODIMP CSubtitleStream::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} + +// +// CSubtitleSourceASCII +// + +CSubtitleSourceASCII::CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceASCII::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Text); + pmt->SetSubtype(&MEDIASUBTYPE_NULL); + pmt->SetFormatType(&FORMAT_None); + pmt->ResetFormatBuffer(); + + return NOERROR; +} + +// +// CSubtitleSourceUTF8 +// + +CSubtitleSourceUTF8::CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceUTF8::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Subtitle); + pmt->SetSubtype(&MEDIASUBTYPE_UTF8); + pmt->SetFormatType(&FORMAT_SubtitleInfo); + SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); + ZeroMemory(psi, pmt->FormatLength()); + strcpy_s(psi->IsoLang, "eng"); + + return NOERROR; +} + +// +// CSubtitleSourceSSA +// + +CSubtitleSourceSSA::CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceSSA::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Subtitle); + pmt->SetSubtype(&MEDIASUBTYPE_SSA); + pmt->SetFormatType(&FORMAT_SubtitleInfo); + + CSimpleTextSubtitle sts; + sts.Open(CString(m_fn), DEFAULT_CHARSET); + sts.RemoveAll(); + + CFile f; + TCHAR path[MAX_PATH], fn[MAX_PATH]; + if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { + return E_FAIL; + } + + _tremove(fn); + + _tcscat_s(fn, _T(".ssa")); + + if (!sts.SaveAs(fn, Subtitle::SSA, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { + return E_FAIL; + } + + int len = (int)f.GetLength() - 3; + f.Seek(3, CFile::begin); + + SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); + ZeroMemory(psi, pmt->FormatLength()); + psi->dwOffset = sizeof(SUBTITLEINFO); + strcpy_s(psi->IsoLang, "eng"); + f.Read(pmt->pbFormat + psi->dwOffset, len); + f.Close(); + + _tremove(fn); + + return NOERROR; +} + +// +// CSubtitleSourceASS +// + +CSubtitleSourceASS::CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceASS::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Subtitle); + pmt->SetSubtype(&MEDIASUBTYPE_ASS); + pmt->SetFormatType(&FORMAT_SubtitleInfo); + + CSimpleTextSubtitle sts; + sts.Open(CString(m_fn), DEFAULT_CHARSET); + sts.RemoveAll(); + + CFile f; + TCHAR path[MAX_PATH], fn[MAX_PATH]; + if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { + return E_FAIL; + } + + _tremove(fn); + + _tcscat_s(fn, _T(".ass")); + + if (!sts.SaveAs(fn, Subtitle::ASS, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { + return E_FAIL; + } + + int len = (int)f.GetLength(); + + SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); + ZeroMemory(psi, pmt->FormatLength()); + psi->dwOffset = sizeof(SUBTITLEINFO); + strcpy_s(psi->IsoLang, "eng"); + f.Read(pmt->pbFormat + psi->dwOffset, len); + f.Close(); + + _tremove(fn); + + return NOERROR; +} + +// +// CSubtitleSourceUSF +// + +CSubtitleSourceUSF::CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceUSF::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Subtitle); + pmt->SetSubtype(&MEDIASUBTYPE_USF); + pmt->SetFormatType(&FORMAT_SubtitleInfo); + SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); + ZeroMemory(psi, pmt->FormatLength()); + strcpy_s(psi->IsoLang, "eng"); + // TODO: ... + + return NOERROR; +} + +// +// CSubtitleSourcePreview +// + +CSubtitleSourcePreview::CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourcePreview::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Video); + pmt->SetSubtype(&MEDIASUBTYPE_RGB32); + pmt->SetFormatType(&FORMAT_VideoInfo); + VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); + ZeroMemory(pvih, pmt->FormatLength()); + pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); + pvih->bmiHeader.biWidth = _WIDTH; + pvih->bmiHeader.biHeight = _HEIGHT; + pvih->bmiHeader.biBitCount = 32; + pvih->bmiHeader.biCompression = BI_RGB; + pvih->bmiHeader.biPlanes = 1; + pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth * abs(pvih->bmiHeader.biHeight) * pvih->bmiHeader.biBitCount >> 3; + + return NOERROR; +} + +// +// CSubtitleSourceARGB +// + +CSubtitleSourceARGB::CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceARGB::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Video); + pmt->SetSubtype(&MEDIASUBTYPE_ARGB32); + pmt->SetFormatType(&FORMAT_VideoInfo); + VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); + ZeroMemory(pvih, pmt->FormatLength()); + pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); + // TODO: read w,h,fps from a config file or registry + pvih->bmiHeader.biWidth = _WIDTH; + pvih->bmiHeader.biHeight = _HEIGHT; + pvih->bmiHeader.biBitCount = 32; + pvih->bmiHeader.biCompression = BI_RGB; + pvih->bmiHeader.biPlanes = 1; + pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth * abs(pvih->bmiHeader.biHeight) * pvih->bmiHeader.biBitCount >> 3; + + return NOERROR; +} diff --git a/src/filters/source/SubtitleSource/SubtitleSource.def b/src/filters/source/SubtitleSource/SubtitleSource.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.def +++ b/src/filters/source/SubtitleSource/SubtitleSource.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/source/SubtitleSource/SubtitleSource.h b/src/filters/source/SubtitleSource/SubtitleSource.h index b8e7382a994..379ba8d7102 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.h +++ b/src/filters/source/SubtitleSource/SubtitleSource.h @@ -1,155 +1,155 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "../../../Subtitles/RTS.h" - -#define SubtitleSourceName L"MPC-HC Subtitle Source" - -class CSubtitleSource - : public CSource - , public IFileSourceFilter - , public IAMFilterMiscFlags -{ -protected: - CStringW m_fn; - -public: - CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid); - virtual ~CSubtitleSource(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IFileSourceFilter - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); - - // IAMFilterMiscFlags - STDMETHODIMP_(ULONG) GetMiscFlags(); - - virtual HRESULT GetMediaType(CMediaType* pmt) = 0; - - // CBaseFilter - STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); -}; - -class CSubtitleStream - : public CSourceStream - , public CSourceSeeking -{ - CCritSec m_cSharedState; - - int m_nPosition; - - BOOL m_bDiscontinuity, m_bFlushing; - - HRESULT OnThreadStartPlay(); - HRESULT OnThreadCreate(); - - void UpdateFromSeek(); - STDMETHODIMP SetRate(double dRate); - - HRESULT ChangeStart(); - HRESULT ChangeStop(); - HRESULT ChangeRate() { return S_OK; } - -protected: - CRenderedTextSubtitle m_rts; - -public: - CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr); - virtual ~CSubtitleStream(); - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT DecideBufferSize(IMemAllocator* pIMemAlloc, ALLOCATOR_PROPERTIES* pProperties); - HRESULT FillBuffer(IMediaSample* pSample); - HRESULT GetMediaType(CMediaType* pmt); - HRESULT CheckMediaType(const CMediaType* pmt); - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; - -class __declspec(uuid("E44CA3B5-A0FF-41A0-AF16-42429B1095EA")) - CSubtitleSourceASCII : public CSubtitleSource -{ -public: - CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("87864E0F-7073-4E39-B802-143DE0ED4964")) - CSubtitleSourceUTF8 : public CSubtitleSource -{ -public: - CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("18316B1A-5877-4CC4-85FD-EDE65CD489EC")) - CSubtitleSourceSSA : public CSubtitleSource -{ -public: - CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("416782BC-1D87-48C0-8F65-F113A5CB8E15")) - CSubtitleSourceASS : public CSubtitleSource -{ -public: - CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("D7215AFC-DFE6-483B-9AF3-6BBECFF14CF4")) - CSubtitleSourceUSF : public CSubtitleSource -{ -public: - CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("932E75D4-BBD4-4A0F-9071-6728FBDC4C98")) - CSubtitleSourcePreview : public CSubtitleSource -{ -public: - CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("CF0D7280-527D-415E-BA02-56017484D73E")) - CSubtitleSourceARGB : public CSubtitleSource -{ -public: - CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "../../../Subtitles/RTS.h" + +#define SubtitleSourceName L"MPC-HC Subtitle Source" + +class CSubtitleSource + : public CSource + , public IFileSourceFilter + , public IAMFilterMiscFlags +{ +protected: + CStringW m_fn; + +public: + CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid); + virtual ~CSubtitleSource(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IFileSourceFilter + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); + + // IAMFilterMiscFlags + STDMETHODIMP_(ULONG) GetMiscFlags(); + + virtual HRESULT GetMediaType(CMediaType* pmt) = 0; + + // CBaseFilter + STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); +}; + +class CSubtitleStream + : public CSourceStream + , public CSourceSeeking +{ + CCritSec m_cSharedState; + + int m_nPosition; + + BOOL m_bDiscontinuity, m_bFlushing; + + HRESULT OnThreadStartPlay(); + HRESULT OnThreadCreate(); + + void UpdateFromSeek(); + STDMETHODIMP SetRate(double dRate); + + HRESULT ChangeStart(); + HRESULT ChangeStop(); + HRESULT ChangeRate() { return S_OK; } + +protected: + CRenderedTextSubtitle m_rts; + +public: + CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr); + virtual ~CSubtitleStream(); + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT DecideBufferSize(IMemAllocator* pIMemAlloc, ALLOCATOR_PROPERTIES* pProperties); + HRESULT FillBuffer(IMediaSample* pSample); + HRESULT GetMediaType(CMediaType* pmt); + HRESULT CheckMediaType(const CMediaType* pmt); + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; + +class __declspec(uuid("E44CA3B5-A0FF-41A0-AF16-42429B1095EA")) + CSubtitleSourceASCII : public CSubtitleSource +{ +public: + CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("87864E0F-7073-4E39-B802-143DE0ED4964")) + CSubtitleSourceUTF8 : public CSubtitleSource +{ +public: + CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("18316B1A-5877-4CC4-85FD-EDE65CD489EC")) + CSubtitleSourceSSA : public CSubtitleSource +{ +public: + CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("416782BC-1D87-48C0-8F65-F113A5CB8E15")) + CSubtitleSourceASS : public CSubtitleSource +{ +public: + CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("D7215AFC-DFE6-483B-9AF3-6BBECFF14CF4")) + CSubtitleSourceUSF : public CSubtitleSource +{ +public: + CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("932E75D4-BBD4-4A0F-9071-6728FBDC4C98")) + CSubtitleSourcePreview : public CSubtitleSource +{ +public: + CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("CF0D7280-527D-415E-BA02-56017484D73E")) + CSubtitleSourceARGB : public CSubtitleSource +{ +public: + CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; diff --git a/src/filters/source/SubtitleSource/SubtitleSource.rc b/src/filters/source/SubtitleSource/SubtitleSource.rc index 47de809a7f9..5e2e430d87f 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.rc +++ b/src/filters/source/SubtitleSource/SubtitleSource.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "SubtitleSource Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "SubtitleSource Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "SubtitleSource.ax" - VALUE "ProductName", "SubtitleSource Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "SubtitleSource Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "SubtitleSource Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "SubtitleSource.ax" + VALUE "ProductName", "SubtitleSource Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/source/SubtitleSource/SubtitleSource.vcxproj b/src/filters/source/SubtitleSource/SubtitleSource.vcxproj index af365f1865e..3836a388d2b 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.vcxproj +++ b/src/filters/source/SubtitleSource/SubtitleSource.vcxproj @@ -1,133 +1,133 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {8F998497-9C51-4FAA-83E4-1D85B22CBA13} - SubtitleSource - MFCProj - SubtitleSource - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;..\..\..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - comsuppw.lib;Vfw32.lib;%(AdditionalDependencies) - SubtitleSource.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - Create - - - - - - - - - true - - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {d514ea4d-eafb-47a9-a437-a582ca571251} - - - {5e56335f-0fb1-4eea-b240-d8dc5e0608e4} - - - {da8461c4-7683-4360-9372-2a9e0f1795c2} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {8F998497-9C51-4FAA-83E4-1D85B22CBA13} + SubtitleSource + MFCProj + SubtitleSource + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;..\..\..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + comsuppw.lib;Vfw32.lib;%(AdditionalDependencies) + SubtitleSource.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + Create + + + + + + + + + true + + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {d514ea4d-eafb-47a9-a437-a582ca571251} + + + {5e56335f-0fb1-4eea-b240-d8dc5e0608e4} + + + {da8461c4-7683-4360-9372-2a9e0f1795c2} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/source/SubtitleSource/SubtitleSource.vcxproj.filters b/src/filters/source/SubtitleSource/SubtitleSource.vcxproj.filters index 1e69995e668..1b24192f8e1 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.vcxproj.filters +++ b/src/filters/source/SubtitleSource/SubtitleSource.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {02ec0f4b-6c0b-4d12-b1f0-0cbc16c2b813} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {dab25e34-5059-453a-8973-39482d61dbc4} - h;hpp;hxx;hm;inl;inc - - - {e6e3e6a0-c068-410d-a040-01813e3bd6aa} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {02ec0f4b-6c0b-4d12-b1f0-0cbc16c2b813} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {dab25e34-5059-453a-8973-39482d61dbc4} + h;hpp;hxx;hm;inl;inc + + + {e6e3e6a0-c068-410d-a040-01813e3bd6aa} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/source/SubtitleSource/resource.h b/src/filters/source/SubtitleSource/resource.h index a1c36076f0b..b56787c1e85 100644 --- a/src/filters/source/SubtitleSource/resource.h +++ b/src/filters/source/SubtitleSource/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by SubtitleSource.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SubtitleSource.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/source/SubtitleSource/stdafx.cpp b/src/filters/source/SubtitleSource/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/source/SubtitleSource/stdafx.cpp +++ b/src/filters/source/SubtitleSource/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/source/SubtitleSource/stdafx.h b/src/filters/source/SubtitleSource/stdafx.h index d8320f2c878..12bbe2db0a7 100644 --- a/src/filters/source/SubtitleSource/stdafx.h +++ b/src/filters/source/SubtitleSource/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/stdafx.cpp b/src/filters/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/stdafx.cpp +++ b/src/filters/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/stdafx.h b/src/filters/stdafx.h index 8ee094e9596..9499f547031 100644 --- a/src/filters/stdafx.h +++ b/src/filters/stdafx.h @@ -1,43 +1,43 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -namespace Gdiplus -{ - using std::min; - using std::max; -}; -#include - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +namespace Gdiplus +{ + using std::min; + using std::max; +}; +#include + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/switcher/AudioSwitcher/Audio.cpp b/src/filters/switcher/AudioSwitcher/Audio.cpp index 1313d82ea2f..cb2c99a103f 100644 --- a/src/filters/switcher/AudioSwitcher/Audio.cpp +++ b/src/filters/switcher/AudioSwitcher/Audio.cpp @@ -1,322 +1,322 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ -// originally from virtualdub - -#include "stdafx.h" -#include -#include -#include "Audio.h" - -static long audio_pointsample_8(void* dst, void* src, long accum, long samp_frac, long cnt) -{ - unsigned char* d = (unsigned char*)dst; - unsigned char* s = (unsigned char*)src; - - do { - *d++ = s[accum >> 19]; - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static long audio_pointsample_16(void* dst, void* src, long accum, long samp_frac, long cnt) -{ - unsigned short* d = (unsigned short*)dst; - unsigned short* s = (unsigned short*)src; - - do { - *d++ = s[accum >> 19]; - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static long audio_pointsample_32(void* dst, void* src, long accum, long samp_frac, long cnt) -{ - unsigned long* d = (unsigned long*)dst; - unsigned long* s = (unsigned long*)src; - - do { - *d++ = s[accum >> 19]; - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static long audio_downsample_mono8(void* dst, void* src, long* filter_bank, int filter_width, long accum, long samp_frac, long cnt) -{ - unsigned char* d = (unsigned char*)dst; - unsigned char* s = (unsigned char*)src; - - do { - long sum = 0; - int w; - long* fb_ptr; - unsigned char* s_ptr; - - w = filter_width; - fb_ptr = filter_bank + filter_width * ((accum >> 11) & 0xff); - s_ptr = s + (accum >> 19); - do { - sum += *fb_ptr++ * (int) * s_ptr++; - } while (--w); - - if (sum < 0) { - *d++ = 0; - } else if (sum > 0x3fffff) { - *d++ = 0xff; - } else { - *d++ = (unsigned char)((sum + 0x2000) >> 14); - } - - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static long audio_downsample_mono16(void* dst, void* src, long* filter_bank, int filter_width, long accum, long samp_frac, long cnt) -{ - signed short* d = (signed short*)dst; - signed short* s = (signed short*)src; - - do { - long sum = 0; - int w; - long* fb_ptr; - signed short* s_ptr; - - w = filter_width; - fb_ptr = filter_bank + filter_width * ((accum >> 11) & 0xff); - s_ptr = s + (accum >> 19); - do { - sum += *fb_ptr++ * (int) * s_ptr++; - } while (--w); - - if (sum < -0x20000000) { - *d++ = -0x8000; - } else if (sum > 0x1fffffff) { - *d++ = 0x7fff; - } else { - *d++ = (signed short)((sum + 0x2000) >> 14); - } - - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static int permute_index(int a, int b) -{ - return (b - (a >> 8) - 1) + (a & 255) * b; -} - -static void make_downsample_filter(long* filter_bank, int filter_width, long samp_frac) -{ - int i, j; - double filt_max; - double filtwidth_frac; - - filtwidth_frac = samp_frac / 2048.0; - - filter_bank[filter_width - 1] = 0; - - filt_max = (16384.0 * 524288.0) / samp_frac; - - for (i = 0; i < 128 * filter_width; i++) { - int y = 0; - double d = i / filtwidth_frac; - - if (d < 1.0) { - y = (int)(0.5 + filt_max * (1.0 - d)); - } - - filter_bank[permute_index(128 * filter_width + i, filter_width)] - = filter_bank[permute_index(128 * filter_width - i, filter_width)] - = y; - } - - // Normalize the filter to correct for integer roundoff errors - - for (i = 0; i < 256 * filter_width; i += filter_width) { - int v = 0; - for (j = 0; j < filter_width; j++) { - v += filter_bank[i + j]; - } - - //_RPT2(0,"error[%02x] = %04x\n", i/filter_width, 0x4000 - v); - - v = (0x4000 - v) / filter_width; - for (j = 0; j < filter_width; j++) { - filter_bank[i + j] += v; - } - } - - // _CrtCheckMemory(); -} - -AudioStreamResampler::AudioStreamResampler(int bps, long orig_rate, long new_rate, bool fHighQuality) - : ptsampleRout(audio_pointsample_16) - , dnsampleRout(audio_downsample_mono16) - , samp_frac(0x80000) - , accum(0) - , holdover(0) - , filter_bank(nullptr) - , filter_width(1) - , bps(bps) -{ - if (bps == 1) { - ptsampleRout = audio_pointsample_8; - dnsampleRout = audio_downsample_mono8; - } else if (bps >= 2) { - ptsampleRout = audio_pointsample_16; - dnsampleRout = audio_downsample_mono16; - } else { - return; - } - - // orig_rate > new_rate! - samp_frac = MulDiv(orig_rate, 0x80000, new_rate); - - // If this is a high-quality downsample, allocate memory for the filter bank - if (fHighQuality) { - if (samp_frac > 0x80000) { - // HQ downsample: allocate filter bank - - filter_width = ((samp_frac + 0x7ffff) >> 19) << 1 << 1; - - filter_bank = DEBUG_NEW long[filter_width * 256]; - if (!filter_bank) { - filter_width = 1; - return; - } - - make_downsample_filter(filter_bank, filter_width, samp_frac); - - // Clear lower samples - - memset(cbuffer, bps >= 2 ? 0 : 0x80, bps * filter_width); - - holdover = filter_width / 2; - } - } -} - -AudioStreamResampler::~AudioStreamResampler() -{ - delete [] filter_bank; -} - -long AudioStreamResampler::Downsample(void* input, long samplesIn, void* output, long samplesOut) -{ - long lActualSamples = 0; - - // Downsampling is even worse because we have overlap to the left and to the - // right of the interpolated point. - // - // We need (n/2) points to the left and (n/2-1) points to the right. - - while (samplesIn > 0 && samplesOut > 0) { - long srcSamples, dstSamples; - int nhold; - - // Figure out how many source samples we need. - // - // To do this, compute the highest fixed-point accumulator we'll reach. - // Truncate that, and add the filter width. Then subtract however many - // samples are sitting at the bottom of the buffer. - - srcSamples = (long)(((__int64)samp_frac * (samplesOut - 1) + accum) >> 19) + filter_width - holdover; - - // Don't exceed the buffer (BUFFER_SIZE - holdover). - - if (srcSamples > BUFFER_SIZE - holdover) { - srcSamples = BUFFER_SIZE - holdover; - } - - // Read into buffer. - - srcSamples = std::min(srcSamples, samplesIn); - if (!srcSamples) { - break; - } - - memcpy((char*)cbuffer + holdover * bps, (char*)input, srcSamples * bps); - input = (void*)((char*)input + srcSamples * bps); - - // Figure out how many destination samples we'll get out of what we - // read. We'll have (srcSamples+holdover) bytes, so the maximum - // fixed-pt accumulator we can hit is - // (srcSamples+holdover-filter_width)<<16 + 0xffff. - - dstSamples = (((__int64)(srcSamples + holdover - filter_width) << 19) + 0x7ffff - accum) / samp_frac + 1; - - if (dstSamples > samplesOut) { - dstSamples = samplesOut; - } - - if (dstSamples >= 1) { - if (filter_bank) { - accum = dnsampleRout(output, cbuffer, filter_bank, filter_width, accum, samp_frac, dstSamples); - } else { - accum = ptsampleRout(output, cbuffer, accum, samp_frac, dstSamples); - } - - output = (void*)((char*)output + bps * dstSamples); - lActualSamples += dstSamples; - samplesOut -= dstSamples; - } - - // We're "shifting" the new samples down to the bottom by discarding - // all the samples in the buffer, so adjust the fixed-pt accum - // accordingly. - - accum -= ((srcSamples + holdover) << 19); - - // Oops, did we need some of those? - // - // If accum=0, we need (n/2) samples back. accum>=0x10000 is fewer, - // accum<0 is more. - - nhold = - (accum >> 19); - - //ASSERT(nhold <= (filter_width / 2)); - - if (nhold > 0) { - memmove(cbuffer, (char*)cbuffer + bps * (srcSamples + holdover - nhold), bps * nhold); - holdover = nhold; - accum += nhold << 19; - } else { - holdover = 0; - } - - //ASSERT(accum >= 0); - } - - int Bytes = lActualSamples * bps; - UNREFERENCED_PARAMETER(Bytes); - - return lActualSamples; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ +// originally from virtualdub + +#include "stdafx.h" +#include +#include +#include "Audio.h" + +static long audio_pointsample_8(void* dst, void* src, long accum, long samp_frac, long cnt) +{ + unsigned char* d = (unsigned char*)dst; + unsigned char* s = (unsigned char*)src; + + do { + *d++ = s[accum >> 19]; + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static long audio_pointsample_16(void* dst, void* src, long accum, long samp_frac, long cnt) +{ + unsigned short* d = (unsigned short*)dst; + unsigned short* s = (unsigned short*)src; + + do { + *d++ = s[accum >> 19]; + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static long audio_pointsample_32(void* dst, void* src, long accum, long samp_frac, long cnt) +{ + unsigned long* d = (unsigned long*)dst; + unsigned long* s = (unsigned long*)src; + + do { + *d++ = s[accum >> 19]; + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static long audio_downsample_mono8(void* dst, void* src, long* filter_bank, int filter_width, long accum, long samp_frac, long cnt) +{ + unsigned char* d = (unsigned char*)dst; + unsigned char* s = (unsigned char*)src; + + do { + long sum = 0; + int w; + long* fb_ptr; + unsigned char* s_ptr; + + w = filter_width; + fb_ptr = filter_bank + filter_width * ((accum >> 11) & 0xff); + s_ptr = s + (accum >> 19); + do { + sum += *fb_ptr++ * (int) * s_ptr++; + } while (--w); + + if (sum < 0) { + *d++ = 0; + } else if (sum > 0x3fffff) { + *d++ = 0xff; + } else { + *d++ = (unsigned char)((sum + 0x2000) >> 14); + } + + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static long audio_downsample_mono16(void* dst, void* src, long* filter_bank, int filter_width, long accum, long samp_frac, long cnt) +{ + signed short* d = (signed short*)dst; + signed short* s = (signed short*)src; + + do { + long sum = 0; + int w; + long* fb_ptr; + signed short* s_ptr; + + w = filter_width; + fb_ptr = filter_bank + filter_width * ((accum >> 11) & 0xff); + s_ptr = s + (accum >> 19); + do { + sum += *fb_ptr++ * (int) * s_ptr++; + } while (--w); + + if (sum < -0x20000000) { + *d++ = -0x8000; + } else if (sum > 0x1fffffff) { + *d++ = 0x7fff; + } else { + *d++ = (signed short)((sum + 0x2000) >> 14); + } + + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static int permute_index(int a, int b) +{ + return (b - (a >> 8) - 1) + (a & 255) * b; +} + +static void make_downsample_filter(long* filter_bank, int filter_width, long samp_frac) +{ + int i, j; + double filt_max; + double filtwidth_frac; + + filtwidth_frac = samp_frac / 2048.0; + + filter_bank[filter_width - 1] = 0; + + filt_max = (16384.0 * 524288.0) / samp_frac; + + for (i = 0; i < 128 * filter_width; i++) { + int y = 0; + double d = i / filtwidth_frac; + + if (d < 1.0) { + y = (int)(0.5 + filt_max * (1.0 - d)); + } + + filter_bank[permute_index(128 * filter_width + i, filter_width)] + = filter_bank[permute_index(128 * filter_width - i, filter_width)] + = y; + } + + // Normalize the filter to correct for integer roundoff errors + + for (i = 0; i < 256 * filter_width; i += filter_width) { + int v = 0; + for (j = 0; j < filter_width; j++) { + v += filter_bank[i + j]; + } + + //_RPT2(0,"error[%02x] = %04x\n", i/filter_width, 0x4000 - v); + + v = (0x4000 - v) / filter_width; + for (j = 0; j < filter_width; j++) { + filter_bank[i + j] += v; + } + } + + // _CrtCheckMemory(); +} + +AudioStreamResampler::AudioStreamResampler(int bps, long orig_rate, long new_rate, bool fHighQuality) + : ptsampleRout(audio_pointsample_16) + , dnsampleRout(audio_downsample_mono16) + , samp_frac(0x80000) + , accum(0) + , holdover(0) + , filter_bank(nullptr) + , filter_width(1) + , bps(bps) +{ + if (bps == 1) { + ptsampleRout = audio_pointsample_8; + dnsampleRout = audio_downsample_mono8; + } else if (bps >= 2) { + ptsampleRout = audio_pointsample_16; + dnsampleRout = audio_downsample_mono16; + } else { + return; + } + + // orig_rate > new_rate! + samp_frac = MulDiv(orig_rate, 0x80000, new_rate); + + // If this is a high-quality downsample, allocate memory for the filter bank + if (fHighQuality) { + if (samp_frac > 0x80000) { + // HQ downsample: allocate filter bank + + filter_width = ((samp_frac + 0x7ffff) >> 19) << 1 << 1; + + filter_bank = DEBUG_NEW long[filter_width * 256]; + if (!filter_bank) { + filter_width = 1; + return; + } + + make_downsample_filter(filter_bank, filter_width, samp_frac); + + // Clear lower samples + + memset(cbuffer, bps >= 2 ? 0 : 0x80, bps * filter_width); + + holdover = filter_width / 2; + } + } +} + +AudioStreamResampler::~AudioStreamResampler() +{ + delete [] filter_bank; +} + +long AudioStreamResampler::Downsample(void* input, long samplesIn, void* output, long samplesOut) +{ + long lActualSamples = 0; + + // Downsampling is even worse because we have overlap to the left and to the + // right of the interpolated point. + // + // We need (n/2) points to the left and (n/2-1) points to the right. + + while (samplesIn > 0 && samplesOut > 0) { + long srcSamples, dstSamples; + int nhold; + + // Figure out how many source samples we need. + // + // To do this, compute the highest fixed-point accumulator we'll reach. + // Truncate that, and add the filter width. Then subtract however many + // samples are sitting at the bottom of the buffer. + + srcSamples = (long)(((__int64)samp_frac * (samplesOut - 1) + accum) >> 19) + filter_width - holdover; + + // Don't exceed the buffer (BUFFER_SIZE - holdover). + + if (srcSamples > BUFFER_SIZE - holdover) { + srcSamples = BUFFER_SIZE - holdover; + } + + // Read into buffer. + + srcSamples = std::min(srcSamples, samplesIn); + if (!srcSamples) { + break; + } + + memcpy((char*)cbuffer + holdover * bps, (char*)input, srcSamples * bps); + input = (void*)((char*)input + srcSamples * bps); + + // Figure out how many destination samples we'll get out of what we + // read. We'll have (srcSamples+holdover) bytes, so the maximum + // fixed-pt accumulator we can hit is + // (srcSamples+holdover-filter_width)<<16 + 0xffff. + + dstSamples = (((__int64)(srcSamples + holdover - filter_width) << 19) + 0x7ffff - accum) / samp_frac + 1; + + if (dstSamples > samplesOut) { + dstSamples = samplesOut; + } + + if (dstSamples >= 1) { + if (filter_bank) { + accum = dnsampleRout(output, cbuffer, filter_bank, filter_width, accum, samp_frac, dstSamples); + } else { + accum = ptsampleRout(output, cbuffer, accum, samp_frac, dstSamples); + } + + output = (void*)((char*)output + bps * dstSamples); + lActualSamples += dstSamples; + samplesOut -= dstSamples; + } + + // We're "shifting" the new samples down to the bottom by discarding + // all the samples in the buffer, so adjust the fixed-pt accum + // accordingly. + + accum -= ((srcSamples + holdover) << 19); + + // Oops, did we need some of those? + // + // If accum=0, we need (n/2) samples back. accum>=0x10000 is fewer, + // accum<0 is more. + + nhold = - (accum >> 19); + + //ASSERT(nhold <= (filter_width / 2)); + + if (nhold > 0) { + memmove(cbuffer, (char*)cbuffer + bps * (srcSamples + holdover - nhold), bps * nhold); + holdover = nhold; + accum += nhold << 19; + } else { + holdover = 0; + } + + //ASSERT(accum >= 0); + } + + int Bytes = lActualSamples * bps; + UNREFERENCED_PARAMETER(Bytes); + + return lActualSamples; +} diff --git a/src/filters/switcher/AudioSwitcher/Audio.h b/src/filters/switcher/AudioSwitcher/Audio.h index a9bc552c358..49185070a14 100644 --- a/src/filters/switcher/AudioSwitcher/Audio.h +++ b/src/filters/switcher/AudioSwitcher/Audio.h @@ -1,50 +1,50 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -typedef long(*AudioPointSampler)(void*, void*, long, long, long); -typedef long(*AudioDownSampler)(void*, void*, long*, int, long, long, long); - -class AudioStreamResampler -{ -private: - AudioPointSampler ptsampleRout; - AudioDownSampler dnsampleRout; - long samp_frac; - long accum; - int holdover; - long* filter_bank; - int filter_width; - - enum { BUFFER_SIZE = 512 }; - BYTE cbuffer[4 * BUFFER_SIZE]; - int bps; - -public: - AudioStreamResampler(int bps, long orig_rate, long new_rate, bool fHighQuality); - ~AudioStreamResampler(); - - AudioStreamResampler(const AudioStreamResampler&) = delete; - AudioStreamResampler& operator=(const AudioStreamResampler&) = delete; - - long Downsample(void* input, long samplesIn, void* output, long samplesOut); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +typedef long(*AudioPointSampler)(void*, void*, long, long, long); +typedef long(*AudioDownSampler)(void*, void*, long*, int, long, long, long); + +class AudioStreamResampler +{ +private: + AudioPointSampler ptsampleRout; + AudioDownSampler dnsampleRout; + long samp_frac; + long accum; + int holdover; + long* filter_bank; + int filter_width; + + enum { BUFFER_SIZE = 512 }; + BYTE cbuffer[4 * BUFFER_SIZE]; + int bps; + +public: + AudioStreamResampler(int bps, long orig_rate, long new_rate, bool fHighQuality); + ~AudioStreamResampler(); + + AudioStreamResampler(const AudioStreamResampler&) = delete; + AudioStreamResampler& operator=(const AudioStreamResampler&) = delete; + + long Downsample(void* input, long samplesIn, void* output, long samplesOut); +}; diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.cpp b/src/filters/switcher/AudioSwitcher/AudioSwitcher.cpp index 080e1ded4b4..fd92526d235 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.cpp +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.cpp @@ -1,755 +1,755 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include -#include "AudioSwitcher.h" -#include "Audio.h" -#include "../../../DSUtil/DSUtil.h" -#include "../../../DSUtil/AudioTools.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -#define NORMALIZATION_REGAIN_STEP 0.06 // +6%/s -#define NORMALIZATION_REGAIN_THRESHOLD 0.75 - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL} -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL} -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CAudioSwitcherFilter), AudioSwitcherName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CAudioSwitcherFilter -// - -CAudioSwitcherFilter::CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr) - : CStreamSwitcherFilter(lpunk, phr, __uuidof(this)) - , m_fCustomChannelMapping(false) - , m_fDownSampleTo441(false) - , m_rtAudioTimeShift(0) - , m_fNormalize(false) - , m_fNormalizeRecover(false) - , m_nMaxNormFactor(4.0) - , m_boostFactor(1.0) - , m_normalizeFactor(m_nMaxNormFactor) - , m_rtNextStart(0) - , m_rtNextStop(1) - , m_rtSegmentStart(0) -{ - ZeroMemory(m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); - - if (phr) { - if (FAILED(*phr)) { - return; - } else { - *phr = S_OK; - } - } -} - -STDMETHODIMP CAudioSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IAudioSwitcherFilter) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CAudioSwitcherFilter::CheckMediaType(const CMediaType* pmt) -{ - if (pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->pbFormat) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pmt->pbFormat; - WORD wBitsPerSample = wfe->wBitsPerSample; - WORD wFormatTag = wfe->wFormatTag; - if (wfe->nChannels > 2 && wFormatTag != WAVE_FORMAT_EXTENSIBLE) { - return VFW_E_INVALIDMEDIATYPE; // iviaudio tries to fool us - } - if (wfe->nSamplesPerSec == 0) { - ASSERT(false); - return VFW_E_INVALIDMEDIATYPE; - } - if (wBitsPerSample == 8 || wBitsPerSample == 16 || wBitsPerSample == 24 || wBitsPerSample == 32) { - if (wFormatTag == WAVE_FORMAT_PCM || wFormatTag == WAVE_FORMAT_IEEE_FLOAT || wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF || wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - return S_OK; - } - } - } - return VFW_E_TYPE_NOT_ACCEPTED; -} - -template -__forceinline void mix(DWORD mask, int ch, int bps, BYTE* src, BYTE* dst) -{ - U sum = 0; - - for (int i = 0, j = ch; i < j; i++) { - if (mask & (1 << i)) { - sum += *(T*)&src[bps * i]; - } - } - - if (sum < Umin) { - sum = Umin; - } else if (sum > Umax) { - sum = Umax; - } - - *(T*)dst = (T)sum; -} - -template<> -__forceinline void mix(DWORD mask, int ch, int bps, BYTE* src, BYTE* dst) -{ - INT64 sum = 0; - - for (int i = 0, j = ch; i < j; i++) { - if (mask & (1 << i)) { - int tmp; - memcpy((BYTE*)&tmp + 1, &src[bps * i], 3); - sum += tmp >> 8; - } - } - - sum = std::min(std::max(sum, INT24_MIN), INT24_MAX); - - memcpy(dst, (BYTE*)&sum, 3); -} - -template -__forceinline void mix4(DWORD mask, BYTE* src, BYTE* dst) -{ - U sum = 0; - int bps = sizeof T; - - if (mask & (1 << 0)) { - sum += *(T*)&src[bps * 0]; - } - if (mask & (1 << 1)) { - sum += *(T*)&src[bps * 1]; - } - if (mask & (1 << 2)) { - sum += *(T*)&src[bps * 2]; - } - if (mask & (1 << 3)) { - sum += *(T*)&src[bps * 3]; - } - - if (sum < Umin) { - sum = Umin; - } else if (sum > Umax) { - sum = Umax; - } - - *(T*)dst = (T)sum; -} - -template -T clamp(double s, T smin, T smax) -{ - if (s < -1.0) { - s = -1.0; - } else if (s > 1.0) { - s = 1.0; - } - T t = (T)(s * smax); - if (t < smin) { - t = smin; - } else if (t > smax) { - t = smax; - } - return t; -} - -HRESULT CAudioSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - CStreamSwitcherInputPin* pInPin = GetInputPin(); - CStreamSwitcherOutputPin* pOutPin = GetOutputPin(); - if (!pInPin || !pOutPin) { - return __super::Transform(pIn, pOut); - } - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; - WAVEFORMATEX* wfeout = (WAVEFORMATEX*)pOutPin->CurrentMediaType().pbFormat; - WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe; - - int bps = wfe->wBitsPerSample >> 3; - - int len = pIn->GetActualDataLength() / (bps * wfe->nChannels); - if (len < 0 || wfe->nSamplesPerSec == 0 || !wfeout) { - return S_FALSE; - } - int lenout = (UINT64)len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec; - - REFERENCE_TIME rtStart, rtStop; - if (SUCCEEDED(pIn->GetTime(&rtStart, &rtStop))) { - rtStart += m_rtAudioTimeShift; - rtStop += m_rtAudioTimeShift; - pOut->SetTime(&rtStart, &rtStop); - - m_rtNextStart = rtStart; - m_rtNextStop = rtStop; - } else { - pOut->SetTime(&m_rtNextStart, &m_rtNextStop); - } - - REFERENCE_TIME rtDur = 10000000i64 * len / wfe->nSamplesPerSec; - - m_rtNextStart += rtDur; - m_rtNextStop += rtDur; - - if (m_normalizeFactor < 1.0 && pIn->IsDiscontinuity() == S_OK) { - m_normalizeFactor = std::max(1.0, m_nMaxNormFactor * 0.5); - } - - WORD tag = wfe->wFormatTag; - bool fPCM = tag == WAVE_FORMAT_PCM || tag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM; - bool fFloat = tag == WAVE_FORMAT_IEEE_FLOAT || tag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - if (!fPCM && !fFloat) { - return __super::Transform(pIn, pOut); - } - - BYTE* pDataIn = nullptr; - BYTE* pDataOut = nullptr; - - HRESULT hr; - if (FAILED(hr = pIn->GetPointer(&pDataIn))) { - return hr; - } - if (FAILED(hr = pOut->GetPointer(&pDataOut))) { - return hr; - } - - if (!pDataIn || !pDataOut) { - return S_FALSE; - } - // len = 0 doesn't mean it's failed, return S_OK otherwise might screw the sound - if (len == 0) { - pOut->SetActualDataLength(0); - return S_OK; - } - - bool bDownSampleTo441 = (m_fDownSampleTo441 - && wfe->nSamplesPerSec > 44100 && wfeout->nSamplesPerSec == 44100 - && wfe->wBitsPerSample <= 16 && fPCM); - - if (bDownSampleTo441 && m_pResamplers.GetCount() < wfeout->nChannels) { - ASSERT(false); - m_pResamplers.RemoveAll(); - for (int i = 0; i < wfeout->nChannels; i++) { - CAutoPtr pResampler; - pResampler.Attach(DEBUG_NEW AudioStreamResampler(wfeout->wBitsPerSample >> 3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true)); - m_pResamplers.Add(pResampler); - } - } - - BYTE* pTmp = nullptr; - BYTE* pDst = nullptr; - if (bDownSampleTo441 && m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { - pDst = pTmp = DEBUG_NEW BYTE[size_t(len) * size_t(bps) * wfeout->nChannels]; - } else { - pDst = pDataOut; - } - - if (m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { - size_t channelsCount = m_chs[wfe->nChannels - 1].GetCount(); - ASSERT(channelsCount == 0 || wfeout->nChannels == channelsCount); - - int srcstep = bps * wfe->nChannels; - int dststep = bps * wfeout->nChannels; - int channels = wfe->nChannels; - - if (channelsCount > 0 && wfeout->nChannels == channelsCount) { - for (int i = 0; i < wfeout->nChannels; i++) { - DWORD mask = m_chs[wfe->nChannels - 1][i].Channel; - - BYTE* src = pDataIn; - BYTE* dst = &pDst[bps * i]; - - if (fPCM) { - if (wfe->wBitsPerSample == 8) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix(mask, channels, bps, src, dst); - } - } else if (wfe->wBitsPerSample == 16) { - if (wfe->nChannels != 4 || wfeout->nChannels != 4) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix(mask, channels, bps, src, dst); - } - } else { // most popular channels count - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix4(mask, src, dst); - } - } - } else if (wfe->wBitsPerSample == 24) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix(mask, channels, bps, src, dst); - } - } else if (wfe->wBitsPerSample == 32) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix(mask, channels, bps, src, dst); - } - } - } else if (fFloat) { - if (wfe->wBitsPerSample == 32) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix < float, double, -1, 1 > (mask, channels, bps, src, dst); - } - } else if (wfe->wBitsPerSample == 64) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix < double, double, -1, 1 > (mask, channels, bps, src, dst); - } - } - } - } - } else { - ZeroMemory(pDataOut, pOut->GetSize()); - } - } else { - HRESULT hr2; - if (S_OK != (hr2 = __super::Transform(pIn, pOut))) { - return hr2; - } - } - - if (bDownSampleTo441) { - if (BYTE* buff = DEBUG_NEW BYTE[len * bps]) { - for (int ch = 0; ch < wfeout->nChannels; ch++) { - ZeroMemory(buff, len * bps); - - for (int i = 0; i < len; i++) { - memcpy(buff + i * bps, (char*)pDst + (ch + i * wfeout->nChannels)*bps, bps); - } - - m_pResamplers[ch]->Downsample(buff, len, buff, lenout); - - for (int i = 0; i < lenout; i++) { - memcpy((char*)pDataOut + (ch + i * wfeout->nChannels)*bps, buff + i * bps, bps); - } - } - - delete [] buff; - } - - delete [] pTmp; - } - - if (m_fNormalize || m_boostFactor > 1) { - size_t samples = size_t(lenout) * wfeout->nChannels; - double sample_mul = 1.0; - - if (m_fNormalize) { - double sample_max = 0.0; - - // calculate max peak - if (fPCM) { - int32_t maxpeak = 0; - if (wfe->wBitsPerSample == 8) { - for (size_t i = 0; i < samples; i++) { - int32_t peak = abs((int8_t)(pDataOut[i] ^ 0x80)); - if (peak > maxpeak) { - maxpeak = peak; - } - } - sample_max = (double)maxpeak / INT8_MAX; - } else if (wfe->wBitsPerSample == 16) { - for (size_t i = 0; i < samples; i++) { - int32_t peak = abs(((int16_t*)pDataOut)[i]); - if (peak > maxpeak) { - maxpeak = peak; - } - } - sample_max = (double)maxpeak / INT16_MAX; - } else if (wfe->wBitsPerSample == 24) { - for (size_t i = 0; i < samples; i++) { - int32_t peak = 0; - BYTE* p = (BYTE*)(&peak); - p[1] = pDataOut[i * 3]; - p[2] = pDataOut[i * 3 + 1]; - p[3] = pDataOut[i * 3 + 2]; - peak = abs(peak); - if (peak > maxpeak) { - maxpeak = peak; - } - } - sample_max = (double)maxpeak / INT32_MAX; - } else if (wfe->wBitsPerSample == 32) { - for (size_t i = 0; i < samples; i++) { - int32_t peak = abs(((int32_t*)pDataOut)[i]); - if (peak > maxpeak) { - maxpeak = peak; - } - } - sample_max = (double)maxpeak / INT32_MAX; - } - } else if (fFloat) { - if (wfe->wBitsPerSample == 32) { - for (size_t i = 0; i < samples; i++) { - double sample = (double)abs(((float*)pDataOut)[i]); - if (sample > sample_max) { - sample_max = sample; - } - } - } else if (wfe->wBitsPerSample == 64) { - for (size_t i = 0; i < samples; i++) { - double sample = (double)abs(((double*)pDataOut)[i]); - if (sample > sample_max) { - sample_max = sample; - } - } - } - } - - double normFact = 1.0 / sample_max; - if (m_normalizeFactor > normFact) { - m_normalizeFactor = normFact; - } else { - if (m_fNormalizeRecover) { - // we don't regain if we are too close of the maximum - if (sample_max * m_normalizeFactor < NORMALIZATION_REGAIN_THRESHOLD) { - m_normalizeFactor += NORMALIZATION_REGAIN_STEP * rtDur / 10000000; // the step is per second so we weight it with the duration - } - } else if (m_normalizeFactor < 0.8 && normFact >= 1.0) { - // recover from overflow situation (audio glitch?) - m_normalizeFactor += NORMALIZATION_REGAIN_STEP * rtDur / 10000000; - } - } - - if (m_normalizeFactor > m_nMaxNormFactor) { - m_normalizeFactor = m_nMaxNormFactor; - } - - sample_mul = m_normalizeFactor; - } - - if (m_boostFactor > 1.0) { - sample_mul *= m_boostFactor; - } - - if (sample_mul != 1.0) { - if (fPCM) { - if (wfe->wBitsPerSample == 8) { - gain_uint8(sample_mul, samples, (uint8_t*)pDataOut); - } else if (wfe->wBitsPerSample == 16) { - gain_int16(sample_mul, samples, (int16_t*)pDataOut); - } else if (wfe->wBitsPerSample == 24) { - gain_int24(sample_mul, samples, pDataOut); - } else if (wfe->wBitsPerSample == 32) { - gain_int32(sample_mul, samples, (int32_t*)pDataOut); - } - } else if (fFloat) { - if (wfe->wBitsPerSample == 32) { - gain_float(sample_mul, samples, (float*)pDataOut); - } else if (wfe->wBitsPerSample == 64) { - gain_double(sample_mul, samples, (double*)pDataOut); - } - } - } - } - - pOut->SetActualDataLength(lenout * bps * wfeout->nChannels); - - return S_OK; -} - -CMediaType CAudioSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer) -{ - CStreamSwitcherInputPin* pInPin = GetInputPin(); - CStreamSwitcherOutputPin* pOutPin = GetOutputPin(); - if (!pInPin || !pOutPin || ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) { - return __super::CreateNewOutputMediaType(mt, cbBuffer); - } - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; - - if (m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { - m_chs[wfe->nChannels - 1].RemoveAll(); - - DWORD mask = DWORD((__int64(1) << wfe->nChannels) - 1); - for (int i = 0; i < AS_MAX_CHANNELS; i++) { - if (m_pSpeakerToChannelMap[wfe->nChannels - 1][i]&mask) { - ChMap cm = {1u << i, m_pSpeakerToChannelMap[wfe->nChannels - 1][i]}; - m_chs[wfe->nChannels - 1].Add(cm); - } - } - - if (!m_chs[wfe->nChannels - 1].IsEmpty()) { - mt.ReallocFormatBuffer(sizeof(WAVEFORMATEXTENSIBLE)); - WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)mt.pbFormat; - wfex->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - wfex->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wfex->Samples.wValidBitsPerSample = wfe->wBitsPerSample; - wfex->SubFormat = - wfe->wFormatTag == WAVE_FORMAT_PCM ? KSDATAFORMAT_SUBTYPE_PCM : - wfe->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : - wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? ((WAVEFORMATEXTENSIBLE*)wfe)->SubFormat : - KSDATAFORMAT_SUBTYPE_PCM; // can't happen - - wfex->dwChannelMask = 0; - for (size_t i = 0; i < m_chs[wfe->nChannels - 1].GetCount(); i++) { - wfex->dwChannelMask |= m_chs[wfe->nChannels - 1][i].Speaker; - } - - wfex->Format.nChannels = (WORD)m_chs[wfe->nChannels - 1].GetCount(); - wfex->Format.nBlockAlign = wfex->Format.nChannels * wfex->Format.wBitsPerSample >> 3; - wfex->Format.nAvgBytesPerSec = wfex->Format.nBlockAlign * wfex->Format.nSamplesPerSec; - } - } - - WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mt.pbFormat; - - if (m_fDownSampleTo441) { - if (wfeout->nSamplesPerSec > 44100 && wfeout->wBitsPerSample <= 16) { - wfeout->nSamplesPerSec = 44100; - wfeout->nAvgBytesPerSec = wfeout->nBlockAlign * wfeout->nSamplesPerSec; - } - } - - int bps = wfe->wBitsPerSample >> 3; - int len = cbBuffer / (bps * wfe->nChannels); - int lenout = (UINT64)len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec; - cbBuffer = lenout * bps * wfeout->nChannels; - - // mt.lSampleSize = (ULONG)max(mt.lSampleSize, wfe->nAvgBytesPerSec * rtLen / 10000000i64); - // mt.lSampleSize = (mt.lSampleSize + (wfe->nBlockAlign-1)) & ~(wfe->nBlockAlign-1); - - return mt; -} - -void CAudioSwitcherFilter::OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut) -{ - const WAVEFORMATEX* wfe = (WAVEFORMATEX*)mtIn.pbFormat; - const WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mtOut.pbFormat; - - m_pResamplers.RemoveAll(); - for (int i = 0; i < wfeout->nChannels; i++) { - CAutoPtr pResampler; - pResampler.Attach(DEBUG_NEW AudioStreamResampler(wfeout->wBitsPerSample >> 3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true)); - m_pResamplers.Add(pResampler); - } - - TRACE(_T("CAudioSwitcherFilter::OnNewOutputMediaType\n")); - m_normalizeFactor = m_nMaxNormFactor; -} - -HRESULT CAudioSwitcherFilter::DeliverEndFlush() -{ - TRACE(_T("CAudioSwitcherFilter::DeliverEndFlush\n")); - - return __super::DeliverEndFlush(); -} - -HRESULT CAudioSwitcherFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - TRACE(_T("CAudioSwitcherFilter::DeliverNewSegment\n")); - - if (m_fNormalizeRecover && m_normalizeFactor < m_nMaxNormFactor) { - // regain after large jump - if (tStart == 0LL || std::abs(tStart - m_rtSegmentStart - m_rtNextStart) >= 600000000LL) { - m_normalizeFactor = std::max(m_normalizeFactor, std::max(1.0, m_nMaxNormFactor * 0.5)); - } - } - m_rtSegmentStart = tStart; - - return __super::DeliverNewSegment(tStart, tStop, dRate); -} - -// IAudioSwitcherFilter - -STDMETHODIMP CAudioSwitcherFilter::GetInputSpeakerConfig(DWORD* pdwChannelMask) -{ - CheckPointer(pdwChannelMask, E_POINTER); - - *pdwChannelMask = 0; - - CStreamSwitcherInputPin* pInPin = GetInputPin(); - if (!pInPin || !pInPin->IsConnected()) { - return E_UNEXPECTED; - } - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; - - if (wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe; - *pdwChannelMask = wfex->dwChannelMask; - } else { - *pdwChannelMask = 0/*wfe->nChannels == 1 ? 4 : wfe->nChannels == 2 ? 3 : 0*/; - } - - return S_OK; -} - -STDMETHODIMP CAudioSwitcherFilter::GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) -{ - if (pfCustomChannelMapping) { - *pfCustomChannelMapping = m_fCustomChannelMapping; - } - memcpy(pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); - - return S_OK; -} - -STDMETHODIMP CAudioSwitcherFilter::SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) -{ - if (m_State == State_Stopped - || m_fCustomChannelMapping != fCustomChannelMapping - || memcmp(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap))) { - PauseGraph; - - CStreamSwitcherInputPin* pInput = GetInputPin(); - - SelectInput(nullptr); - - m_fCustomChannelMapping = fCustomChannelMapping; - memcpy(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); - - SelectInput(pInput); - - ResumeGraph; - } - - return S_OK; -} - -STDMETHODIMP_(int) CAudioSwitcherFilter::GetNumberOfInputChannels() -{ - CStreamSwitcherInputPin* pInPin = GetInputPin(); - return pInPin ? ((WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat)->nChannels : 0; -} - -STDMETHODIMP_(bool) CAudioSwitcherFilter::IsDownSamplingTo441Enabled() -{ - return m_fDownSampleTo441; -} - -STDMETHODIMP CAudioSwitcherFilter::EnableDownSamplingTo441(bool fEnable) -{ - if (m_fDownSampleTo441 != fEnable) { - PauseGraph; - m_fDownSampleTo441 = fEnable; - ResumeGraph; - } - - return S_OK; -} - -STDMETHODIMP_(REFERENCE_TIME) CAudioSwitcherFilter::GetAudioTimeShift() -{ - return m_rtAudioTimeShift; -} - -STDMETHODIMP CAudioSwitcherFilter::SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift) -{ - m_rtAudioTimeShift = rtAudioTimeShift; - return S_OK; -} - -// Deprecated -STDMETHODIMP CAudioSwitcherFilter::GetNormalizeBoost(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB) -{ - fNormalize = m_fNormalize; - fNormalizeRecover = m_fNormalizeRecover; - boost_dB = float(20.0 * log10(m_boostFactor)); - return S_OK; -} - -// Deprecated -STDMETHODIMP CAudioSwitcherFilter::SetNormalizeBoost(bool fNormalize, bool fNormalizeRecover, float boost_dB) -{ - if (m_fNormalize != fNormalize) { - m_normalizeFactor = m_nMaxNormFactor; - } - m_fNormalize = fNormalize; - m_fNormalizeRecover = fNormalizeRecover; - m_boostFactor = pow(10.0, boost_dB / 20.0); - return S_OK; -} - -STDMETHODIMP CAudioSwitcherFilter::GetNormalizeBoost2(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& boost) -{ - fNormalize = m_fNormalize; - nMaxNormFactor = UINT(100.0 * m_nMaxNormFactor + 0.5); - fNormalizeRecover = m_fNormalizeRecover; - boost = UINT(100.0 * m_boostFactor + 0.5) - 100; - return S_OK; -} - -STDMETHODIMP CAudioSwitcherFilter::SetNormalizeBoost2(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT boost) -{ - m_fNormalize = fNormalize; - m_nMaxNormFactor = nMaxNormFactor / 100.0; - m_fNormalizeRecover = fNormalizeRecover; - m_boostFactor = 1.0 + boost / 100.0; - if (m_fNormalize != fNormalize) { - m_normalizeFactor = m_nMaxNormFactor; - } - return S_OK; -} - -// IAMStreamSelect - -STDMETHODIMP CAudioSwitcherFilter::Enable(long lIndex, DWORD dwFlags) -{ - HRESULT hr = __super::Enable(lIndex, dwFlags); - if (S_OK == hr) { - m_normalizeFactor = m_nMaxNormFactor; - } - return hr; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include +#include "AudioSwitcher.h" +#include "Audio.h" +#include "../../../DSUtil/DSUtil.h" +#include "../../../DSUtil/AudioTools.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +#define NORMALIZATION_REGAIN_STEP 0.06 // +6%/s +#define NORMALIZATION_REGAIN_THRESHOLD 0.75 + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL} +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL} +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CAudioSwitcherFilter), AudioSwitcherName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CAudioSwitcherFilter +// + +CAudioSwitcherFilter::CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr) + : CStreamSwitcherFilter(lpunk, phr, __uuidof(this)) + , m_fCustomChannelMapping(false) + , m_fDownSampleTo441(false) + , m_rtAudioTimeShift(0) + , m_fNormalize(false) + , m_fNormalizeRecover(false) + , m_nMaxNormFactor(4.0) + , m_boostFactor(1.0) + , m_normalizeFactor(m_nMaxNormFactor) + , m_rtNextStart(0) + , m_rtNextStop(1) + , m_rtSegmentStart(0) +{ + ZeroMemory(m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); + + if (phr) { + if (FAILED(*phr)) { + return; + } else { + *phr = S_OK; + } + } +} + +STDMETHODIMP CAudioSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IAudioSwitcherFilter) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CAudioSwitcherFilter::CheckMediaType(const CMediaType* pmt) +{ + if (pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->pbFormat) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pmt->pbFormat; + WORD wBitsPerSample = wfe->wBitsPerSample; + WORD wFormatTag = wfe->wFormatTag; + if (wfe->nChannels > 2 && wFormatTag != WAVE_FORMAT_EXTENSIBLE) { + return VFW_E_INVALIDMEDIATYPE; // iviaudio tries to fool us + } + if (wfe->nSamplesPerSec == 0) { + ASSERT(false); + return VFW_E_INVALIDMEDIATYPE; + } + if (wBitsPerSample == 8 || wBitsPerSample == 16 || wBitsPerSample == 24 || wBitsPerSample == 32) { + if (wFormatTag == WAVE_FORMAT_PCM || wFormatTag == WAVE_FORMAT_IEEE_FLOAT || wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF || wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + return S_OK; + } + } + } + return VFW_E_TYPE_NOT_ACCEPTED; +} + +template +__forceinline void mix(DWORD mask, int ch, int bps, BYTE* src, BYTE* dst) +{ + U sum = 0; + + for (int i = 0, j = ch; i < j; i++) { + if (mask & (1 << i)) { + sum += *(T*)&src[bps * i]; + } + } + + if (sum < Umin) { + sum = Umin; + } else if (sum > Umax) { + sum = Umax; + } + + *(T*)dst = (T)sum; +} + +template<> +__forceinline void mix(DWORD mask, int ch, int bps, BYTE* src, BYTE* dst) +{ + INT64 sum = 0; + + for (int i = 0, j = ch; i < j; i++) { + if (mask & (1 << i)) { + int tmp; + memcpy((BYTE*)&tmp + 1, &src[bps * i], 3); + sum += tmp >> 8; + } + } + + sum = std::min(std::max(sum, INT24_MIN), INT24_MAX); + + memcpy(dst, (BYTE*)&sum, 3); +} + +template +__forceinline void mix4(DWORD mask, BYTE* src, BYTE* dst) +{ + U sum = 0; + int bps = sizeof T; + + if (mask & (1 << 0)) { + sum += *(T*)&src[bps * 0]; + } + if (mask & (1 << 1)) { + sum += *(T*)&src[bps * 1]; + } + if (mask & (1 << 2)) { + sum += *(T*)&src[bps * 2]; + } + if (mask & (1 << 3)) { + sum += *(T*)&src[bps * 3]; + } + + if (sum < Umin) { + sum = Umin; + } else if (sum > Umax) { + sum = Umax; + } + + *(T*)dst = (T)sum; +} + +template +T clamp(double s, T smin, T smax) +{ + if (s < -1.0) { + s = -1.0; + } else if (s > 1.0) { + s = 1.0; + } + T t = (T)(s * smax); + if (t < smin) { + t = smin; + } else if (t > smax) { + t = smax; + } + return t; +} + +HRESULT CAudioSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + CStreamSwitcherInputPin* pInPin = GetInputPin(); + CStreamSwitcherOutputPin* pOutPin = GetOutputPin(); + if (!pInPin || !pOutPin) { + return __super::Transform(pIn, pOut); + } + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; + WAVEFORMATEX* wfeout = (WAVEFORMATEX*)pOutPin->CurrentMediaType().pbFormat; + WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe; + + int bps = wfe->wBitsPerSample >> 3; + + int len = pIn->GetActualDataLength() / (bps * wfe->nChannels); + if (len < 0 || wfe->nSamplesPerSec == 0 || !wfeout) { + return S_FALSE; + } + int lenout = (UINT64)len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec; + + REFERENCE_TIME rtStart, rtStop; + if (SUCCEEDED(pIn->GetTime(&rtStart, &rtStop))) { + rtStart += m_rtAudioTimeShift; + rtStop += m_rtAudioTimeShift; + pOut->SetTime(&rtStart, &rtStop); + + m_rtNextStart = rtStart; + m_rtNextStop = rtStop; + } else { + pOut->SetTime(&m_rtNextStart, &m_rtNextStop); + } + + REFERENCE_TIME rtDur = 10000000i64 * len / wfe->nSamplesPerSec; + + m_rtNextStart += rtDur; + m_rtNextStop += rtDur; + + if (m_normalizeFactor < 1.0 && pIn->IsDiscontinuity() == S_OK) { + m_normalizeFactor = std::max(1.0, m_nMaxNormFactor * 0.5); + } + + WORD tag = wfe->wFormatTag; + bool fPCM = tag == WAVE_FORMAT_PCM || tag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM; + bool fFloat = tag == WAVE_FORMAT_IEEE_FLOAT || tag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + if (!fPCM && !fFloat) { + return __super::Transform(pIn, pOut); + } + + BYTE* pDataIn = nullptr; + BYTE* pDataOut = nullptr; + + HRESULT hr; + if (FAILED(hr = pIn->GetPointer(&pDataIn))) { + return hr; + } + if (FAILED(hr = pOut->GetPointer(&pDataOut))) { + return hr; + } + + if (!pDataIn || !pDataOut) { + return S_FALSE; + } + // len = 0 doesn't mean it's failed, return S_OK otherwise might screw the sound + if (len == 0) { + pOut->SetActualDataLength(0); + return S_OK; + } + + bool bDownSampleTo441 = (m_fDownSampleTo441 + && wfe->nSamplesPerSec > 44100 && wfeout->nSamplesPerSec == 44100 + && wfe->wBitsPerSample <= 16 && fPCM); + + if (bDownSampleTo441 && m_pResamplers.GetCount() < wfeout->nChannels) { + ASSERT(false); + m_pResamplers.RemoveAll(); + for (int i = 0; i < wfeout->nChannels; i++) { + CAutoPtr pResampler; + pResampler.Attach(DEBUG_NEW AudioStreamResampler(wfeout->wBitsPerSample >> 3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true)); + m_pResamplers.Add(pResampler); + } + } + + BYTE* pTmp = nullptr; + BYTE* pDst = nullptr; + if (bDownSampleTo441 && m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { + pDst = pTmp = DEBUG_NEW BYTE[size_t(len) * size_t(bps) * wfeout->nChannels]; + } else { + pDst = pDataOut; + } + + if (m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { + size_t channelsCount = m_chs[wfe->nChannels - 1].GetCount(); + ASSERT(channelsCount == 0 || wfeout->nChannels == channelsCount); + + int srcstep = bps * wfe->nChannels; + int dststep = bps * wfeout->nChannels; + int channels = wfe->nChannels; + + if (channelsCount > 0 && wfeout->nChannels == channelsCount) { + for (int i = 0; i < wfeout->nChannels; i++) { + DWORD mask = m_chs[wfe->nChannels - 1][i].Channel; + + BYTE* src = pDataIn; + BYTE* dst = &pDst[bps * i]; + + if (fPCM) { + if (wfe->wBitsPerSample == 8) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix(mask, channels, bps, src, dst); + } + } else if (wfe->wBitsPerSample == 16) { + if (wfe->nChannels != 4 || wfeout->nChannels != 4) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix(mask, channels, bps, src, dst); + } + } else { // most popular channels count + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix4(mask, src, dst); + } + } + } else if (wfe->wBitsPerSample == 24) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix(mask, channels, bps, src, dst); + } + } else if (wfe->wBitsPerSample == 32) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix(mask, channels, bps, src, dst); + } + } + } else if (fFloat) { + if (wfe->wBitsPerSample == 32) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix < float, double, -1, 1 > (mask, channels, bps, src, dst); + } + } else if (wfe->wBitsPerSample == 64) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix < double, double, -1, 1 > (mask, channels, bps, src, dst); + } + } + } + } + } else { + ZeroMemory(pDataOut, pOut->GetSize()); + } + } else { + HRESULT hr2; + if (S_OK != (hr2 = __super::Transform(pIn, pOut))) { + return hr2; + } + } + + if (bDownSampleTo441) { + if (BYTE* buff = DEBUG_NEW BYTE[len * bps]) { + for (int ch = 0; ch < wfeout->nChannels; ch++) { + ZeroMemory(buff, len * bps); + + for (int i = 0; i < len; i++) { + memcpy(buff + i * bps, (char*)pDst + (ch + i * wfeout->nChannels)*bps, bps); + } + + m_pResamplers[ch]->Downsample(buff, len, buff, lenout); + + for (int i = 0; i < lenout; i++) { + memcpy((char*)pDataOut + (ch + i * wfeout->nChannels)*bps, buff + i * bps, bps); + } + } + + delete [] buff; + } + + delete [] pTmp; + } + + if (m_fNormalize || m_boostFactor > 1) { + size_t samples = size_t(lenout) * wfeout->nChannels; + double sample_mul = 1.0; + + if (m_fNormalize) { + double sample_max = 0.0; + + // calculate max peak + if (fPCM) { + int32_t maxpeak = 0; + if (wfe->wBitsPerSample == 8) { + for (size_t i = 0; i < samples; i++) { + int32_t peak = abs((int8_t)(pDataOut[i] ^ 0x80)); + if (peak > maxpeak) { + maxpeak = peak; + } + } + sample_max = (double)maxpeak / INT8_MAX; + } else if (wfe->wBitsPerSample == 16) { + for (size_t i = 0; i < samples; i++) { + int32_t peak = abs(((int16_t*)pDataOut)[i]); + if (peak > maxpeak) { + maxpeak = peak; + } + } + sample_max = (double)maxpeak / INT16_MAX; + } else if (wfe->wBitsPerSample == 24) { + for (size_t i = 0; i < samples; i++) { + int32_t peak = 0; + BYTE* p = (BYTE*)(&peak); + p[1] = pDataOut[i * 3]; + p[2] = pDataOut[i * 3 + 1]; + p[3] = pDataOut[i * 3 + 2]; + peak = abs(peak); + if (peak > maxpeak) { + maxpeak = peak; + } + } + sample_max = (double)maxpeak / INT32_MAX; + } else if (wfe->wBitsPerSample == 32) { + for (size_t i = 0; i < samples; i++) { + int32_t peak = abs(((int32_t*)pDataOut)[i]); + if (peak > maxpeak) { + maxpeak = peak; + } + } + sample_max = (double)maxpeak / INT32_MAX; + } + } else if (fFloat) { + if (wfe->wBitsPerSample == 32) { + for (size_t i = 0; i < samples; i++) { + double sample = (double)abs(((float*)pDataOut)[i]); + if (sample > sample_max) { + sample_max = sample; + } + } + } else if (wfe->wBitsPerSample == 64) { + for (size_t i = 0; i < samples; i++) { + double sample = (double)abs(((double*)pDataOut)[i]); + if (sample > sample_max) { + sample_max = sample; + } + } + } + } + + double normFact = 1.0 / sample_max; + if (m_normalizeFactor > normFact) { + m_normalizeFactor = normFact; + } else { + if (m_fNormalizeRecover) { + // we don't regain if we are too close of the maximum + if (sample_max * m_normalizeFactor < NORMALIZATION_REGAIN_THRESHOLD) { + m_normalizeFactor += NORMALIZATION_REGAIN_STEP * rtDur / 10000000; // the step is per second so we weight it with the duration + } + } else if (m_normalizeFactor < 0.8 && normFact >= 1.0) { + // recover from overflow situation (audio glitch?) + m_normalizeFactor += NORMALIZATION_REGAIN_STEP * rtDur / 10000000; + } + } + + if (m_normalizeFactor > m_nMaxNormFactor) { + m_normalizeFactor = m_nMaxNormFactor; + } + + sample_mul = m_normalizeFactor; + } + + if (m_boostFactor > 1.0) { + sample_mul *= m_boostFactor; + } + + if (sample_mul != 1.0) { + if (fPCM) { + if (wfe->wBitsPerSample == 8) { + gain_uint8(sample_mul, samples, (uint8_t*)pDataOut); + } else if (wfe->wBitsPerSample == 16) { + gain_int16(sample_mul, samples, (int16_t*)pDataOut); + } else if (wfe->wBitsPerSample == 24) { + gain_int24(sample_mul, samples, pDataOut); + } else if (wfe->wBitsPerSample == 32) { + gain_int32(sample_mul, samples, (int32_t*)pDataOut); + } + } else if (fFloat) { + if (wfe->wBitsPerSample == 32) { + gain_float(sample_mul, samples, (float*)pDataOut); + } else if (wfe->wBitsPerSample == 64) { + gain_double(sample_mul, samples, (double*)pDataOut); + } + } + } + } + + pOut->SetActualDataLength(lenout * bps * wfeout->nChannels); + + return S_OK; +} + +CMediaType CAudioSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer) +{ + CStreamSwitcherInputPin* pInPin = GetInputPin(); + CStreamSwitcherOutputPin* pOutPin = GetOutputPin(); + if (!pInPin || !pOutPin || ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) { + return __super::CreateNewOutputMediaType(mt, cbBuffer); + } + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; + + if (m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { + m_chs[wfe->nChannels - 1].RemoveAll(); + + DWORD mask = DWORD((__int64(1) << wfe->nChannels) - 1); + for (int i = 0; i < AS_MAX_CHANNELS; i++) { + if (m_pSpeakerToChannelMap[wfe->nChannels - 1][i]&mask) { + ChMap cm = {1u << i, m_pSpeakerToChannelMap[wfe->nChannels - 1][i]}; + m_chs[wfe->nChannels - 1].Add(cm); + } + } + + if (!m_chs[wfe->nChannels - 1].IsEmpty()) { + mt.ReallocFormatBuffer(sizeof(WAVEFORMATEXTENSIBLE)); + WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)mt.pbFormat; + wfex->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + wfex->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfex->Samples.wValidBitsPerSample = wfe->wBitsPerSample; + wfex->SubFormat = + wfe->wFormatTag == WAVE_FORMAT_PCM ? KSDATAFORMAT_SUBTYPE_PCM : + wfe->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : + wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? ((WAVEFORMATEXTENSIBLE*)wfe)->SubFormat : + KSDATAFORMAT_SUBTYPE_PCM; // can't happen + + wfex->dwChannelMask = 0; + for (size_t i = 0; i < m_chs[wfe->nChannels - 1].GetCount(); i++) { + wfex->dwChannelMask |= m_chs[wfe->nChannels - 1][i].Speaker; + } + + wfex->Format.nChannels = (WORD)m_chs[wfe->nChannels - 1].GetCount(); + wfex->Format.nBlockAlign = wfex->Format.nChannels * wfex->Format.wBitsPerSample >> 3; + wfex->Format.nAvgBytesPerSec = wfex->Format.nBlockAlign * wfex->Format.nSamplesPerSec; + } + } + + WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mt.pbFormat; + + if (m_fDownSampleTo441) { + if (wfeout->nSamplesPerSec > 44100 && wfeout->wBitsPerSample <= 16) { + wfeout->nSamplesPerSec = 44100; + wfeout->nAvgBytesPerSec = wfeout->nBlockAlign * wfeout->nSamplesPerSec; + } + } + + int bps = wfe->wBitsPerSample >> 3; + int len = cbBuffer / (bps * wfe->nChannels); + int lenout = (UINT64)len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec; + cbBuffer = lenout * bps * wfeout->nChannels; + + // mt.lSampleSize = (ULONG)max(mt.lSampleSize, wfe->nAvgBytesPerSec * rtLen / 10000000i64); + // mt.lSampleSize = (mt.lSampleSize + (wfe->nBlockAlign-1)) & ~(wfe->nBlockAlign-1); + + return mt; +} + +void CAudioSwitcherFilter::OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut) +{ + const WAVEFORMATEX* wfe = (WAVEFORMATEX*)mtIn.pbFormat; + const WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mtOut.pbFormat; + + m_pResamplers.RemoveAll(); + for (int i = 0; i < wfeout->nChannels; i++) { + CAutoPtr pResampler; + pResampler.Attach(DEBUG_NEW AudioStreamResampler(wfeout->wBitsPerSample >> 3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true)); + m_pResamplers.Add(pResampler); + } + + TRACE(_T("CAudioSwitcherFilter::OnNewOutputMediaType\n")); + m_normalizeFactor = m_nMaxNormFactor; +} + +HRESULT CAudioSwitcherFilter::DeliverEndFlush() +{ + TRACE(_T("CAudioSwitcherFilter::DeliverEndFlush\n")); + + return __super::DeliverEndFlush(); +} + +HRESULT CAudioSwitcherFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + TRACE(_T("CAudioSwitcherFilter::DeliverNewSegment\n")); + + if (m_fNormalizeRecover && m_normalizeFactor < m_nMaxNormFactor) { + // regain after large jump + if (tStart == 0LL || std::abs(tStart - m_rtSegmentStart - m_rtNextStart) >= 600000000LL) { + m_normalizeFactor = std::max(m_normalizeFactor, std::max(1.0, m_nMaxNormFactor * 0.5)); + } + } + m_rtSegmentStart = tStart; + + return __super::DeliverNewSegment(tStart, tStop, dRate); +} + +// IAudioSwitcherFilter + +STDMETHODIMP CAudioSwitcherFilter::GetInputSpeakerConfig(DWORD* pdwChannelMask) +{ + CheckPointer(pdwChannelMask, E_POINTER); + + *pdwChannelMask = 0; + + CStreamSwitcherInputPin* pInPin = GetInputPin(); + if (!pInPin || !pInPin->IsConnected()) { + return E_UNEXPECTED; + } + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; + + if (wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe; + *pdwChannelMask = wfex->dwChannelMask; + } else { + *pdwChannelMask = 0/*wfe->nChannels == 1 ? 4 : wfe->nChannels == 2 ? 3 : 0*/; + } + + return S_OK; +} + +STDMETHODIMP CAudioSwitcherFilter::GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) +{ + if (pfCustomChannelMapping) { + *pfCustomChannelMapping = m_fCustomChannelMapping; + } + memcpy(pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); + + return S_OK; +} + +STDMETHODIMP CAudioSwitcherFilter::SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) +{ + if (m_State == State_Stopped + || m_fCustomChannelMapping != fCustomChannelMapping + || memcmp(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap))) { + PauseGraph; + + CStreamSwitcherInputPin* pInput = GetInputPin(); + + SelectInput(nullptr); + + m_fCustomChannelMapping = fCustomChannelMapping; + memcpy(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); + + SelectInput(pInput); + + ResumeGraph; + } + + return S_OK; +} + +STDMETHODIMP_(int) CAudioSwitcherFilter::GetNumberOfInputChannels() +{ + CStreamSwitcherInputPin* pInPin = GetInputPin(); + return pInPin ? ((WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat)->nChannels : 0; +} + +STDMETHODIMP_(bool) CAudioSwitcherFilter::IsDownSamplingTo441Enabled() +{ + return m_fDownSampleTo441; +} + +STDMETHODIMP CAudioSwitcherFilter::EnableDownSamplingTo441(bool fEnable) +{ + if (m_fDownSampleTo441 != fEnable) { + PauseGraph; + m_fDownSampleTo441 = fEnable; + ResumeGraph; + } + + return S_OK; +} + +STDMETHODIMP_(REFERENCE_TIME) CAudioSwitcherFilter::GetAudioTimeShift() +{ + return m_rtAudioTimeShift; +} + +STDMETHODIMP CAudioSwitcherFilter::SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift) +{ + m_rtAudioTimeShift = rtAudioTimeShift; + return S_OK; +} + +// Deprecated +STDMETHODIMP CAudioSwitcherFilter::GetNormalizeBoost(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB) +{ + fNormalize = m_fNormalize; + fNormalizeRecover = m_fNormalizeRecover; + boost_dB = float(20.0 * log10(m_boostFactor)); + return S_OK; +} + +// Deprecated +STDMETHODIMP CAudioSwitcherFilter::SetNormalizeBoost(bool fNormalize, bool fNormalizeRecover, float boost_dB) +{ + if (m_fNormalize != fNormalize) { + m_normalizeFactor = m_nMaxNormFactor; + } + m_fNormalize = fNormalize; + m_fNormalizeRecover = fNormalizeRecover; + m_boostFactor = pow(10.0, boost_dB / 20.0); + return S_OK; +} + +STDMETHODIMP CAudioSwitcherFilter::GetNormalizeBoost2(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& boost) +{ + fNormalize = m_fNormalize; + nMaxNormFactor = UINT(100.0 * m_nMaxNormFactor + 0.5); + fNormalizeRecover = m_fNormalizeRecover; + boost = UINT(100.0 * m_boostFactor + 0.5) - 100; + return S_OK; +} + +STDMETHODIMP CAudioSwitcherFilter::SetNormalizeBoost2(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT boost) +{ + m_fNormalize = fNormalize; + m_nMaxNormFactor = nMaxNormFactor / 100.0; + m_fNormalizeRecover = fNormalizeRecover; + m_boostFactor = 1.0 + boost / 100.0; + if (m_fNormalize != fNormalize) { + m_normalizeFactor = m_nMaxNormFactor; + } + return S_OK; +} + +// IAMStreamSelect + +STDMETHODIMP CAudioSwitcherFilter::Enable(long lIndex, DWORD dwFlags) +{ + HRESULT hr = __super::Enable(lIndex, dwFlags); + if (S_OK == hr) { + m_normalizeFactor = m_nMaxNormFactor; + } + return hr; +} diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.def b/src/filters/switcher/AudioSwitcher/AudioSwitcher.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.def +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.h b/src/filters/switcher/AudioSwitcher/AudioSwitcher.h index 9d6957c1898..b7a00918b76 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.h +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.h @@ -1,104 +1,104 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include "StreamSwitcher.h" - -#define AudioSwitcherName L"MPC-HC AudioSwitcher" -#define AS_MAX_CHANNELS 18 - - -interface __declspec(uuid("CEDB2890-53AE-4231-91A3-B0AAFCD1DBDE")) - IAudioSwitcherFilter : - public IUnknown -{ - STDMETHOD(GetInputSpeakerConfig)(DWORD* pdwChannelMask) PURE; - STDMETHOD(GetSpeakerConfig)(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) PURE; - STDMETHOD(SetSpeakerConfig)(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) PURE; - STDMETHOD_(int, GetNumberOfInputChannels)() PURE; - STDMETHOD_(bool, IsDownSamplingTo441Enabled)() PURE; - STDMETHOD(EnableDownSamplingTo441)(bool fEnable) PURE; - STDMETHOD_(REFERENCE_TIME, GetAudioTimeShift)() PURE; - STDMETHOD(SetAudioTimeShift)(REFERENCE_TIME rtAudioTimeShift) PURE; - // Deprecated - STDMETHOD(GetNormalizeBoost)(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB) PURE; - // Deprecated - STDMETHOD(SetNormalizeBoost)(bool fNormalize, bool fNormalizeRecover, float boost_dB) PURE; - STDMETHOD(GetNormalizeBoost2)(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& nBoost) PURE; - STDMETHOD(SetNormalizeBoost2)(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT nBoost) PURE; -}; - -class AudioStreamResampler; - -class __declspec(uuid("18C16B08-6497-420e-AD14-22D21C2CEAB7")) - CAudioSwitcherFilter : public CStreamSwitcherFilter, public IAudioSwitcherFilter -{ - struct ChMap { - DWORD Speaker, Channel; - }; - CAtlArray m_chs[AS_MAX_CHANNELS]; - - bool m_fCustomChannelMapping; - DWORD m_pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]; - bool m_fDownSampleTo441; - REFERENCE_TIME m_rtAudioTimeShift; - CAutoPtrArray m_pResamplers; - bool m_fNormalize, m_fNormalizeRecover; - double m_nMaxNormFactor, m_boostFactor; - double m_normalizeFactor; - - REFERENCE_TIME m_rtNextStart, m_rtNextStop; - REFERENCE_TIME m_rtSegmentStart; - -public: - CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - CMediaType CreateNewOutputMediaType(CMediaType mt, long& cbBuffer); - void OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut); - - HRESULT DeliverEndFlush(); - HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - - // IAudioSwitcherFilter - STDMETHODIMP GetInputSpeakerConfig(DWORD* pdwChannelMask); - STDMETHODIMP GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]); - STDMETHODIMP SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]); - STDMETHODIMP_(int) GetNumberOfInputChannels(); - STDMETHODIMP_(bool) IsDownSamplingTo441Enabled(); - STDMETHODIMP EnableDownSamplingTo441(bool fEnable); - STDMETHODIMP_(REFERENCE_TIME) GetAudioTimeShift(); - STDMETHODIMP SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift); - // Deprecated - STDMETHODIMP GetNormalizeBoost(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB); - // Deprecated - STDMETHODIMP SetNormalizeBoost(bool fNormalize, bool fNormalizeRecover, float boost_dB); - STDMETHODIMP GetNormalizeBoost2(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& nBoost); - STDMETHODIMP SetNormalizeBoost2(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT nBoost); - - // IAMStreamSelect - STDMETHODIMP Enable(long lIndex, DWORD dwFlags); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include "StreamSwitcher.h" + +#define AudioSwitcherName L"MPC-HC AudioSwitcher" +#define AS_MAX_CHANNELS 18 + + +interface __declspec(uuid("CEDB2890-53AE-4231-91A3-B0AAFCD1DBDE")) + IAudioSwitcherFilter : + public IUnknown +{ + STDMETHOD(GetInputSpeakerConfig)(DWORD* pdwChannelMask) PURE; + STDMETHOD(GetSpeakerConfig)(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) PURE; + STDMETHOD(SetSpeakerConfig)(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) PURE; + STDMETHOD_(int, GetNumberOfInputChannels)() PURE; + STDMETHOD_(bool, IsDownSamplingTo441Enabled)() PURE; + STDMETHOD(EnableDownSamplingTo441)(bool fEnable) PURE; + STDMETHOD_(REFERENCE_TIME, GetAudioTimeShift)() PURE; + STDMETHOD(SetAudioTimeShift)(REFERENCE_TIME rtAudioTimeShift) PURE; + // Deprecated + STDMETHOD(GetNormalizeBoost)(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB) PURE; + // Deprecated + STDMETHOD(SetNormalizeBoost)(bool fNormalize, bool fNormalizeRecover, float boost_dB) PURE; + STDMETHOD(GetNormalizeBoost2)(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& nBoost) PURE; + STDMETHOD(SetNormalizeBoost2)(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT nBoost) PURE; +}; + +class AudioStreamResampler; + +class __declspec(uuid("18C16B08-6497-420e-AD14-22D21C2CEAB7")) + CAudioSwitcherFilter : public CStreamSwitcherFilter, public IAudioSwitcherFilter +{ + struct ChMap { + DWORD Speaker, Channel; + }; + CAtlArray m_chs[AS_MAX_CHANNELS]; + + bool m_fCustomChannelMapping; + DWORD m_pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]; + bool m_fDownSampleTo441; + REFERENCE_TIME m_rtAudioTimeShift; + CAutoPtrArray m_pResamplers; + bool m_fNormalize, m_fNormalizeRecover; + double m_nMaxNormFactor, m_boostFactor; + double m_normalizeFactor; + + REFERENCE_TIME m_rtNextStart, m_rtNextStop; + REFERENCE_TIME m_rtSegmentStart; + +public: + CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + CMediaType CreateNewOutputMediaType(CMediaType mt, long& cbBuffer); + void OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut); + + HRESULT DeliverEndFlush(); + HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + // IAudioSwitcherFilter + STDMETHODIMP GetInputSpeakerConfig(DWORD* pdwChannelMask); + STDMETHODIMP GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]); + STDMETHODIMP SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]); + STDMETHODIMP_(int) GetNumberOfInputChannels(); + STDMETHODIMP_(bool) IsDownSamplingTo441Enabled(); + STDMETHODIMP EnableDownSamplingTo441(bool fEnable); + STDMETHODIMP_(REFERENCE_TIME) GetAudioTimeShift(); + STDMETHODIMP SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift); + // Deprecated + STDMETHODIMP GetNormalizeBoost(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB); + // Deprecated + STDMETHODIMP SetNormalizeBoost(bool fNormalize, bool fNormalizeRecover, float boost_dB); + STDMETHODIMP GetNormalizeBoost2(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& nBoost); + STDMETHODIMP SetNormalizeBoost2(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT nBoost); + + // IAMStreamSelect + STDMETHODIMP Enable(long lIndex, DWORD dwFlags); +}; diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.rc b/src/filters/switcher/AudioSwitcher/AudioSwitcher.rc index d9ae4e1f42a..b4c7b52f357 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.rc +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "AudioSwitcher" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "AudioSwitcher" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "AudioSwitcher.ax" - VALUE "ProductName", "AudioSwitcher" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "AudioSwitcher" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "AudioSwitcher" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "AudioSwitcher.ax" + VALUE "ProductName", "AudioSwitcher" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj b/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj index c3f3dde56c2..9df5e639df8 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj @@ -1,128 +1,128 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {D8DB3E7E-D50E-4EC3-A9B9-DAD18F5FE466} - AudioSwitcher - MFCProj - AudioSwitcher - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - AudioSwitcher.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - - Create - - - - - - - - - - - true - - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {D8DB3E7E-D50E-4EC3-A9B9-DAD18F5FE466} + AudioSwitcher + MFCProj + AudioSwitcher + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + AudioSwitcher.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + + Create + + + + + + + + + + + true + + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj.filters b/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj.filters index 0e4f0567c9d..689b8f22e10 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj.filters +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj.filters @@ -1,57 +1,57 @@ - - - - - {5d72cb26-7cb5-4089-8afe-a1675cca05bd} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {fad8eff1-05e1-4e43-b055-d246fd3761a6} - h;hpp;hxx;hm;inl;inc - - - {706cf01d-dbd5-4702-985f-1c65f75baa5e} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {5d72cb26-7cb5-4089-8afe-a1675cca05bd} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {fad8eff1-05e1-4e43-b055-d246fd3761a6} + h;hpp;hxx;hm;inl;inc + + + {706cf01d-dbd5-4702-985f-1c65f75baa5e} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/switcher/AudioSwitcher/StreamSwitcher.cpp b/src/filters/switcher/AudioSwitcher/StreamSwitcher.cpp index 2af29151f26..62c59c8eac6 100644 --- a/src/filters/switcher/AudioSwitcher/StreamSwitcher.cpp +++ b/src/filters/switcher/AudioSwitcher/StreamSwitcher.cpp @@ -1,1640 +1,1640 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "StreamSwitcher.h" -#include "../../../DSUtil/DSUtil.h" -#include "../../../DSUtil/PathUtils.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -#define BLOCKSTREAM - -// -// CStreamSwitcherPassThru -// - -CStreamSwitcherPassThru::CStreamSwitcherPassThru(LPUNKNOWN pUnk, HRESULT* phr, CStreamSwitcherFilter* pFilter) - : CMediaPosition(NAME("CStreamSwitcherPassThru"), pUnk) - , m_pFilter(pFilter) -{ -} - -STDMETHODIMP CStreamSwitcherPassThru::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = nullptr; - - return - QI(IMediaSeeking) - CMediaPosition::NonDelegatingQueryInterface(riid, ppv); -} - -template -HRESULT GetPeer(CStreamSwitcherFilter* pFilter, T** ppT) -{ - *ppT = nullptr; - - CBasePin* pPin = pFilter->GetInputPin(); - if (!pPin) { - return E_NOTIMPL; - } - - CComPtr pConnected; - if (FAILED(pPin->ConnectedTo(&pConnected))) { - return E_NOTIMPL; - } - - if (CComQIPtr pT = pConnected) { - *ppT = pT.Detach(); - return S_OK; - } - - return E_NOTIMPL; -} - - -#define CallPeerSeeking(call) \ - CComPtr pMS; \ - if (FAILED(GetPeer(m_pFilter, &pMS))) \ - return E_NOTIMPL; \ - return pMS->##call; - -#define CallPeer(call) \ - CComPtr pMP; \ - if (FAILED(GetPeer(m_pFilter, &pMP))) \ - return E_NOTIMPL; \ - return pMP->##call; - -#define CallPeerSeekingAll(call) \ - HRESULT hr = E_NOTIMPL; \ - POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); \ - while (pos) { \ - CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); \ - CComPtr pConnected; \ - if (FAILED(pPin->ConnectedTo(&pConnected))) \ - continue; \ - if (CComQIPtr pMS = pConnected) { \ - HRESULT hr2 = pMS->call; \ - if (pPin == m_pFilter->GetInputPin()) \ - hr = hr2; \ - } \ - } \ - return hr; - -#define CallPeerAll(call) \ - HRESULT hr = E_NOTIMPL; \ - POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); \ - while (pos) { \ - CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); \ - CComPtr pConnected; \ - if (FAILED(pPin->ConnectedTo(&pConnected))) \ - continue; \ - if (CComQIPtr pMP = pConnected) { \ - HRESULT hr2 = pMP->call; \ - if (pPin == m_pFilter->GetInputPin()) \ - hr = hr2; \ - } \ - } \ - return hr; - - -// IMediaSeeking - -STDMETHODIMP CStreamSwitcherPassThru::GetCapabilities(DWORD* pCaps) -{ - CallPeerSeeking(GetCapabilities(pCaps)); -} - -STDMETHODIMP CStreamSwitcherPassThru::CheckCapabilities(DWORD* pCaps) -{ - CallPeerSeeking(CheckCapabilities(pCaps)); -} - -STDMETHODIMP CStreamSwitcherPassThru::IsFormatSupported(const GUID* pFormat) -{ - CallPeerSeeking(IsFormatSupported(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::QueryPreferredFormat(GUID* pFormat) -{ - CallPeerSeeking(QueryPreferredFormat(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::SetTimeFormat(const GUID* pFormat) -{ - CallPeerSeeking(SetTimeFormat(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetTimeFormat(GUID* pFormat) -{ - CallPeerSeeking(GetTimeFormat(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::IsUsingTimeFormat(const GUID* pFormat) -{ - CallPeerSeeking(IsUsingTimeFormat(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - CallPeerSeeking(ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, LONGLONG* pStop, DWORD StopFlags) -{ - CallPeerSeekingAll(SetPositions(pCurrent, CurrentFlags, pStop, StopFlags)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - CallPeerSeeking(GetPositions(pCurrent, pStop)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetCurrentPosition(LONGLONG* pCurrent) -{ - CallPeerSeeking(GetCurrentPosition(pCurrent)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetStopPosition(LONGLONG* pStop) -{ - CallPeerSeeking(GetStopPosition(pStop)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetDuration(LONGLONG* pDuration) -{ - CallPeerSeeking(GetDuration(pDuration)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetPreroll(LONGLONG* pllPreroll) -{ - CallPeerSeeking(GetPreroll(pllPreroll)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - CallPeerSeeking(GetAvailable(pEarliest, pLatest)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetRate(double* pdRate) -{ - CallPeerSeeking(GetRate(pdRate)); -} - -STDMETHODIMP CStreamSwitcherPassThru::SetRate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - CallPeerSeekingAll(SetRate(dRate)); -} - -// IMediaPosition - -STDMETHODIMP CStreamSwitcherPassThru::get_Duration(REFTIME* plength) -{ - CallPeer(get_Duration(plength)); -} - -STDMETHODIMP CStreamSwitcherPassThru::get_CurrentPosition(REFTIME* pllTime) -{ - CallPeer(get_CurrentPosition(pllTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::put_CurrentPosition(REFTIME llTime) -{ - CallPeerAll(put_CurrentPosition(llTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::get_StopTime(REFTIME* pllTime) -{ - CallPeer(get_StopTime(pllTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::put_StopTime(REFTIME llTime) -{ - CallPeerAll(put_StopTime(llTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::get_PrerollTime(REFTIME* pllTime) -{ - CallPeer(get_PrerollTime(pllTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::put_PrerollTime(REFTIME llTime) -{ - CallPeerAll(put_PrerollTime(llTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::get_Rate(double* pdRate) -{ - CallPeer(get_Rate(pdRate)); -} - -STDMETHODIMP CStreamSwitcherPassThru::put_Rate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - CallPeerAll(put_Rate(dRate)); -} - -STDMETHODIMP CStreamSwitcherPassThru::CanSeekForward(LONG* pCanSeekForward) -{ - CallPeer(CanSeekForward(pCanSeekForward)); -} - -STDMETHODIMP CStreamSwitcherPassThru::CanSeekBackward(LONG* pCanSeekBackward) -{ - CallPeer(CanSeekBackward(pCanSeekBackward)); -} - -// -// CStreamSwitcherAllocator -// - -CStreamSwitcherAllocator::CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr) - : CMemAllocator(NAME("CStreamSwitcherAllocator"), nullptr, phr) - , m_pPin(pPin) - , m_fMediaTypeChanged(false) -{ - ASSERT(phr); - ASSERT(pPin); -} - -#ifdef _DEBUG -CStreamSwitcherAllocator::~CStreamSwitcherAllocator() -{ - ASSERT(m_bCommitted == FALSE); -} -#endif - -STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingAddRef() -{ - return m_pPin->m_pFilter->AddRef(); -} - -STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingRelease() -{ - return m_pPin->m_pFilter->Release(); -} - -STDMETHODIMP CStreamSwitcherAllocator::GetBuffer( - IMediaSample** ppBuffer, - REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, - DWORD dwFlags) -{ - HRESULT hr = VFW_E_NOT_COMMITTED; - - if (!m_bCommitted) { - return hr; - } - /* - TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() + %x\n"), this); - m_pPin->m_evBlock.Wait(); - TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() - %x\n"), this); - */ - if (m_fMediaTypeChanged) { - if (!m_pPin || !m_pPin->m_pFilter) { - return hr; - } - - CStreamSwitcherOutputPin* pOut = (static_cast(m_pPin->m_pFilter))->GetOutputPin(); - if (!pOut || !pOut->CurrentAllocator()) { - return hr; - } - - ALLOCATOR_PROPERTIES Properties, Actual; - if (FAILED(pOut->CurrentAllocator()->GetProperties(&Actual))) { - return hr; - } - if (FAILED(GetProperties(&Properties))) { - return hr; - } - - if (!m_bCommitted || Properties.cbBuffer < Actual.cbBuffer) { - Properties.cbBuffer = Actual.cbBuffer; - if (FAILED(Decommit())) { - return hr; - } - if (FAILED(SetProperties(&Properties, &Actual))) { - return hr; - } - if (FAILED(Commit())) { - return hr; - } - ASSERT(Actual.cbBuffer >= Properties.cbBuffer); - if (Actual.cbBuffer < Properties.cbBuffer) { - return hr; - } - } - } - - hr = CMemAllocator::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags); - - if (m_fMediaTypeChanged && SUCCEEDED(hr)) { - (*ppBuffer)->SetMediaType(&m_mt); - m_fMediaTypeChanged = false; - } - - return hr; -} - -void CStreamSwitcherAllocator::NotifyMediaType(const CMediaType& mt) -{ - CopyMediaType(&m_mt, &mt); - m_fMediaTypeChanged = true; -} - - -// -// CStreamSwitcherInputPin -// - -CStreamSwitcherInputPin::CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName) - : CBaseInputPin(NAME("CStreamSwitcherInputPin"), pFilter, &pFilter->m_csState, phr, pName) - , m_Allocator(this, phr) - , m_bSampleSkipped(FALSE) - , m_bQualityChanged(FALSE) - , m_bUsingOwnAllocator(FALSE) - , m_evBlock(TRUE) - , m_fCanBlock(false) - , m_hNotifyEvent(nullptr) - , m_bFirstSampleReceived(false) -{ - m_bCanReconnectWhenActive = true; -} - -class __declspec(uuid("138130AF-A79B-45D5-B4AA-87697457BA87")) - NeroAudioDecoder {}; - -STDMETHODIMP CStreamSwitcherInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IStreamSwitcherInputPin) - IsConnected() && GetCLSID(GetFilterFromPin(GetConnected())) == __uuidof(NeroAudioDecoder) && QI(IPinConnection) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IPinConnection - -STDMETHODIMP CStreamSwitcherInputPin::DynamicQueryAccept(const AM_MEDIA_TYPE* pmt) -{ - return QueryAccept(pmt); -} - -STDMETHODIMP CStreamSwitcherInputPin::NotifyEndOfStream(HANDLE hNotifyEvent) -{ - if (m_hNotifyEvent) { - SetEvent(m_hNotifyEvent); - } - m_hNotifyEvent = hNotifyEvent; - return S_OK; -} - -STDMETHODIMP CStreamSwitcherInputPin::IsEndPin() -{ - return S_OK; -} - -STDMETHODIMP CStreamSwitcherInputPin::DynamicDisconnect() -{ - CAutoLock cAutoLock(&m_csReceive); - Disconnect(); - return S_OK; -} - -// IStreamSwitcherInputPin - -STDMETHODIMP_(bool) CStreamSwitcherInputPin::IsActive() -{ - // TODO: lock onto something here - return (this == (static_cast(m_pFilter))->GetInputPin()); -} - -// - -HRESULT CStreamSwitcherInputPin::QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt) -{ - HRESULT hr = S_OK; - - CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); - - if (pOut && pOut->IsConnected()) { - if (CComPtr pPC = pOut->CurrentPinConnection()) { - hr = pPC->DynamicQueryAccept(pmt); - if (hr == S_OK) { - return S_OK; - } - } - - hr = pOut->GetConnected()->QueryAccept(pmt); - } - - return hr; -} - -void CStreamSwitcherInputPin::Block(bool fBlock) -{ - if (fBlock) { - m_evBlock.Reset(); - } else { - m_evBlock.Set(); - } -} - -HRESULT CStreamSwitcherInputPin::InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample) -{ - if (!pInSample || !ppOutSample) { - return E_POINTER; - } - - CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); - ASSERT(pOut->GetConnected()); - - CComPtr pOutSample; - - DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; - - if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { - dwFlags |= AM_GBF_NOTASYNCPOINT; - } - - HRESULT hr = pOut->GetDeliveryBuffer(&pOutSample, - (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) ? &m_SampleProps.tStart : nullptr, - (m_SampleProps.dwSampleFlags & AM_SAMPLE_STOPVALID) ? &m_SampleProps.tStop : nullptr, - dwFlags); - - if (FAILED(hr)) { - return hr; - } - - if (!pOutSample) { - return E_FAIL; - } - - if (CComQIPtr pOutSample2 = pOutSample) { - AM_SAMPLE2_PROPERTIES OutProps; - EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps))); - OutProps.dwTypeSpecificFlags = m_SampleProps.dwTypeSpecificFlags; - OutProps.dwSampleFlags = - (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | - (m_SampleProps.dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); - - OutProps.tStart = m_SampleProps.tStart; - OutProps.tStop = m_SampleProps.tStop; - OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); - - pOutSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps); - if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - m_bSampleSkipped = FALSE; - } - } else { - if (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) { - pOutSample->SetTime(&m_SampleProps.tStart, &m_SampleProps.tStop); - } - - if (m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { - pOutSample->SetSyncPoint(TRUE); - } - - if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - pOutSample->SetDiscontinuity(TRUE); - m_bSampleSkipped = FALSE; - } - - LONGLONG MediaStart, MediaEnd; - if (pInSample->GetMediaTime(&MediaStart, &MediaEnd) == NOERROR) { - pOutSample->SetMediaTime(&MediaStart, &MediaEnd); - } - } - - *ppOutSample = pOutSample.Detach(); - - return S_OK; -} - -// pure virtual - -HRESULT CStreamSwitcherInputPin::CheckMediaType(const CMediaType* pmt) -{ - return (static_cast(m_pFilter))->CheckMediaType(pmt); -} - -// virtual - -HRESULT CStreamSwitcherInputPin::CheckConnect(IPin* pPin) -{ - return (IPin*)(static_cast(m_pFilter))->GetOutputPin() == pPin - ? E_FAIL - : __super::CheckConnect(pPin); -} - -HRESULT CStreamSwitcherInputPin::CompleteConnect(IPin* pReceivePin) -{ - HRESULT hr = __super::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - (static_cast(m_pFilter))->CompleteConnect(PINDIR_INPUT, this, pReceivePin); - - m_fCanBlock = false; - bool fForkedSomewhere = false; - - CStringW streamName; - CStringW pinName; - - IPin* pPin = (IPin*)this; - IBaseFilter* pBF = (IBaseFilter*)m_pFilter; - - pPin = GetUpStreamPin(pBF, pPin); - if (pPin) { - pBF = GetFilterFromPin(pPin); - } - while (pPin && pBF) { - if (IsSplitter(pBF)) { - pinName = GetPinName(pPin); - } - - CLSID clsid = GetCLSID(pBF); - if (clsid == CLSID_AviSplitter || clsid == CLSID_OggSplitter) { - m_fCanBlock = true; - } - - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - fForkedSomewhere = fForkedSomewhere || nIn > 1 || nOut > 1; - - DWORD cStreams = 0; - CStringW streamSSName; - if (CComQIPtr pSSF = pBF) { - hr = pSSF->Count(&cStreams); - if (SUCCEEDED(hr)) { - for (int i = 0; i < (int)cStreams; i++) { - CComHeapPtr pszNameSS; - AM_MEDIA_TYPE* pmt = nullptr; - LCID lcid = 0; - - hr = pSSF->Info(i, &pmt, nullptr, &lcid, nullptr, &pszNameSS, nullptr, nullptr); - if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { - m_pSSF = pSSF; - DeleteMediaType(pmt); - streamSSName = pszNameSS; - break; - } - DeleteMediaType(pmt); - } - } - } - - if (CComQIPtr pFSF = pBF) { - CComHeapPtr fileName; - AM_MEDIA_TYPE mt; - - if (SUCCEEDED(pFSF->GetCurFile(&fileName, &mt)) && fileName) { - streamName = fileName; - if (streamName.Find(L"googlevideo.com") > 0 || (PathUtils::IsURL(streamName) && streamName.GetLength() > 50)) { //we don't like these URLs - streamName = streamSSName; - if (streamName.GetLength() <= 0) { - streamName = L"Online Audio Stream"; - } - } else { - streamName.Replace('\\', '/'); - CStringW fn = streamName.Mid(streamName.ReverseFind('/') + 1); - if (!fn.IsEmpty()) { - streamName = fn; - } - - // Haali & LAVFSplitter return only one "Audio" pin name, cause CMainFrame::OnInitMenuPopup lookup find the wrong popmenu, - // add space at the end to prevent this, internal filter never return "Audio" only. - if (!pinName.IsEmpty()) { - streamName = pinName + L" "; - } - } - - WCHAR* pName = DEBUG_NEW WCHAR[streamName.GetLength() + 1]; - if (pName) { - wcscpy_s(pName, streamName.GetLength() + 1, streamName); - if (m_pName) { - delete[] m_pName; - } - m_pName = pName; - if (cStreams == 1) { // Simple external track, no need to use the info from IAMStreamSelect - m_pSSF.Release(); - } - } - } - - break; - } - - pPin = GetFirstPin(pBF); - - pPin = GetUpStreamPin(pBF, pPin); - if (pPin) { - pBF = GetFilterFromPin(pPin); - } - } - - if (!fForkedSomewhere) { - m_fCanBlock = true; - } - - m_hNotifyEvent = nullptr; - - return S_OK; -} - -HRESULT CStreamSwitcherInputPin::Active() -{ - Block(!IsActive()); - - return __super::Active(); -} - -HRESULT CStreamSwitcherInputPin::Inactive() -{ - Block(false); - - return __super::Inactive(); -} - -// IPin - -STDMETHODIMP CStreamSwitcherInputPin::QueryAccept(const AM_MEDIA_TYPE* pmt) -{ - HRESULT hr = __super::QueryAccept(pmt); - if (S_OK != hr) { - return hr; - } - - return QueryAcceptDownstream(pmt); -} - -STDMETHODIMP CStreamSwitcherInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) -{ - // FIXME: this locked up once - // CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csReceive); - - HRESULT hr; - if (S_OK != (hr = QueryAcceptDownstream(pmt))) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - - if (m_Connected && m_Connected != pConnector) { - return VFW_E_ALREADY_CONNECTED; - } - - SAFE_RELEASE(m_Connected); - - return SUCCEEDED(__super::ReceiveConnection(pConnector, pmt)) ? S_OK : E_FAIL; -} - -STDMETHODIMP CStreamSwitcherInputPin::GetAllocator(IMemAllocator** ppAllocator) -{ - CheckPointer(ppAllocator, E_POINTER); - - if (m_pAllocator == nullptr) { - (m_pAllocator = &m_Allocator)->AddRef(); - } - - (*ppAllocator = m_pAllocator)->AddRef(); - - return NOERROR; -} - -STDMETHODIMP CStreamSwitcherInputPin::NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly) -{ - HRESULT hr = __super::NotifyAllocator(pAllocator, bReadOnly); - if (FAILED(hr)) { - return hr; - } - - m_bUsingOwnAllocator = (pAllocator == (IMemAllocator*)&m_Allocator); - - return S_OK; -} - -STDMETHODIMP CStreamSwitcherInputPin::BeginFlush() -{ - CAutoLock cAutoLock(&(static_cast(m_pFilter))->m_csState); - - HRESULT hr; - - CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); - - CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); - if (!IsConnected() || !pOut || !pOut->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - if (FAILED(hr = __super::BeginFlush())) { - return hr; - } - - return IsActive() ? pSSF->DeliverBeginFlush() : (Block(false), S_OK); -} - -STDMETHODIMP CStreamSwitcherInputPin::EndFlush() -{ - CAutoLock cAutoLock(&(static_cast(m_pFilter))->m_csState); - - HRESULT hr; - - CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); - - CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); - if (!IsConnected() || !pOut || !pOut->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - if (FAILED(hr = __super::EndFlush())) { - return hr; - } - - return IsActive() ? pSSF->DeliverEndFlush() : (Block(true), S_OK); -} - -STDMETHODIMP CStreamSwitcherInputPin::EndOfStream() -{ - CAutoLock cAutoLock(&m_csReceive); - - CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); - - CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); - if (!IsConnected() || !pOut || !pOut->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - if (m_hNotifyEvent) { - SetEvent(m_hNotifyEvent), m_hNotifyEvent = nullptr; - return S_OK; - } - - if (!m_bFirstSampleReceived) { - pSSF->Stop(); - } - return IsActive() ? pSSF->DeliverEndOfStream() : S_OK; -} - -// IMemInputPin - -STDMETHODIMP CStreamSwitcherInputPin::Receive(IMediaSample* pSample) -{ - m_bFirstSampleReceived = true; - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { - const CMediaType mt(*pmt); - DeleteMediaType(pmt), pmt = nullptr; - SetMediaType(&mt); - } - - // DAMN!!!!!! this doesn't work if the stream we are blocking - // shares the same thread with another stream, mpeg splitters - // are usually like that. Our nicely built up multithreaded - // strategy is useless because of this, ARRRRRRGHHHHHH. - -#ifdef BLOCKSTREAM - if (m_fCanBlock) { - m_evBlock.Wait(); - } -#endif - - if (!IsActive()) { -#ifdef BLOCKSTREAM - if (m_fCanBlock) { - return S_FALSE; - } -#endif - - TRACE(_T("&^$#@ : a stupid fix for this stupid problem\n")); - //Sleep(32); - return E_FAIL; // a stupid fix for this stupid problem - } - - CAutoLock cAutoLock(&m_csReceive); - - CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); - ASSERT(pOut->GetConnected()); - - HRESULT hr = __super::Receive(pSample); - if (S_OK != hr) { - return hr; - } - - if (m_SampleProps.dwStreamId != AM_STREAM_MEDIA) { - return pOut->Deliver(pSample); - } - - // - - ALLOCATOR_PROPERTIES props, actual; - m_pAllocator->GetProperties(&props); - IMemAllocator* cur_alloc = pOut->CurrentAllocator(); - if (!cur_alloc) { - ASSERT(false); - return E_FAIL; - } - cur_alloc->GetProperties(&actual); - - REFERENCE_TIME rtStart = 0, rtStop = 0; - if (S_OK == pSample->GetTime(&rtStart, &rtStop)) { - // - } - - long cbBuffer = pSample->GetActualDataLength(); - - CMediaType mtOut = m_mt; - mtOut = (static_cast(m_pFilter))->CreateNewOutputMediaType(mtOut, cbBuffer); - - bool fTypeChanged = false; - - if (mtOut != pOut->CurrentMediaType() || cbBuffer > actual.cbBuffer) { - fTypeChanged = true; - - m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED/*|AM_SAMPLE_DATADISCONTINUITY|AM_SAMPLE_TIMEDISCONTINUITY*/; - - if (props.cBuffers < 8 && mtOut.majortype == MEDIATYPE_Audio) { - props.cBuffers = 8; - } - - props.cbBuffer = cbBuffer; - - if (actual.cbAlign != props.cbAlign - || actual.cbPrefix != props.cbPrefix - || actual.cBuffers < props.cBuffers - || actual.cbBuffer < props.cbBuffer) { - pOut->DeliverBeginFlush(); - pOut->DeliverEndFlush(); - pOut->CurrentAllocator()->Decommit(); - pOut->CurrentAllocator()->SetProperties(&props, &actual); - pOut->CurrentAllocator()->Commit(); - } - } - - CComPtr pOutSample; - if (FAILED(InitializeOutputSample(pSample, &pOutSample))) { - return E_FAIL; - } - - pmt = nullptr; - if (SUCCEEDED(pOutSample->GetMediaType(&pmt)) && pmt) { - const CMediaType mt(*pmt); - DeleteMediaType(pmt), pmt = nullptr; - // TODO - ASSERT(0); - } - - if (fTypeChanged) { - pOut->SetMediaType(&mtOut); - (static_cast(m_pFilter))->OnNewOutputMediaType(m_mt, mtOut); - pOutSample->SetMediaType(&mtOut); - } - - // Transform - - hr = (static_cast(m_pFilter))->Transform(pSample, pOutSample); - - if (S_OK == hr) { - hr = pOut->Deliver(pOutSample); - m_bSampleSkipped = FALSE; - } else if (S_FALSE == hr) { - hr = S_OK; - pOutSample = nullptr; - m_bSampleSkipped = TRUE; - - if (!m_bQualityChanged) { - m_pFilter->NotifyEvent(EC_QUALITY_CHANGE, 0, 0); - m_bQualityChanged = TRUE; - } - } - - return hr; -} - -STDMETHODIMP CStreamSwitcherInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - if (!IsConnected() || !IsActive()) { - return S_OK; - } - - CAutoLock cAutoLock(&m_csReceive); - - CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); - - CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); - if (!pOut || !pOut->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - return pSSF->DeliverNewSegment(tStart, tStop, dRate); -} - -// -// CStreamSwitcherOutputPin -// - -CStreamSwitcherOutputPin::CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr) - : CBaseOutputPin(NAME("CStreamSwitcherOutputPin"), pFilter, &pFilter->m_csState, phr, L"Out") -{ - // m_bCanReconnectWhenActive = true; -} - -STDMETHODIMP CStreamSwitcherOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - ValidateReadWritePtr(ppv, sizeof(PVOID)); - *ppv = nullptr; - - if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { - if (m_pStreamSwitcherPassThru == nullptr) { - HRESULT hr = S_OK; - m_pStreamSwitcherPassThru = (IUnknown*)(INonDelegatingUnknown*) - DEBUG_NEW CStreamSwitcherPassThru(GetOwner(), &hr, static_cast(m_pFilter)); - - if (!m_pStreamSwitcherPassThru) { - return E_OUTOFMEMORY; - } - if (FAILED(hr)) { - return hr; - } - } - - return m_pStreamSwitcherPassThru->QueryInterface(riid, ppv); - } - /* - else if (riid == IID_IStreamBuilder) - { - return GetInterface((IStreamBuilder*)this, ppv); - } - */ - return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CStreamSwitcherOutputPin::QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt) -{ - HRESULT hr = S_FALSE; - - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - - if (pIn && pIn->IsConnected() && (pIn->IsUsingOwnAllocator() || pIn->CurrentMediaType() == *pmt)) { - if (CComQIPtr pPinTo = pIn->GetConnected()) { - if (S_OK != (hr = pPinTo->QueryAccept(pmt))) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } else { - return E_FAIL; - } - } - - return hr; -} - -// pure virtual - -HRESULT CStreamSwitcherOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - if (!pIn || !pIn->IsConnected()) { - return E_UNEXPECTED; - } - - CComPtr pAllocatorIn; - pIn->GetAllocator(&pAllocatorIn); - if (!pAllocatorIn) { - return E_UNEXPECTED; - } - - HRESULT hr; - if (FAILED(hr = pAllocatorIn->GetProperties(pProperties))) { - return hr; - } - - if (pProperties->cBuffers < 8 && pIn->CurrentMediaType().majortype == MEDIATYPE_Audio) { - pProperties->cBuffers = 8; - } - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -// virtual - -class __declspec(uuid("AEFA5024-215A-4FC7-97A4-1043C86FD0B8")) - MatrixMixer {}; - -HRESULT CStreamSwitcherOutputPin::CheckConnect(IPin* pPin) -{ - CComPtr pBF = GetFilterFromPin(pPin); - - return - IsAudioWaveRenderer(pBF) || GetCLSID(pBF) == __uuidof(MatrixMixer) - ? __super::CheckConnect(pPin) - : E_FAIL; - - // return CComQIPtr(pPin) ? CBaseOutputPin::CheckConnect(pPin) : E_NOINTERFACE; - // return CBaseOutputPin::CheckConnect(pPin); -} - -HRESULT CStreamSwitcherOutputPin::BreakConnect() -{ - m_pPinConnection = nullptr; - return __super::BreakConnect(); -} - -HRESULT CStreamSwitcherOutputPin::CompleteConnect(IPin* pReceivePin) -{ - m_pPinConnection = CComQIPtr(pReceivePin); - HRESULT hr = __super::CompleteConnect(pReceivePin); - - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - CMediaType mt; - if (SUCCEEDED(hr) && pIn && pIn->IsConnected() - && SUCCEEDED(pIn->GetConnected()->ConnectionMediaType(&mt)) && m_mt != mt) { - if (pIn->GetConnected()->QueryAccept(&m_mt) == S_OK) { - hr = m_pFilter->ReconnectPin(pIn->GetConnected(), &m_mt); - } else { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } - } - - return hr; -} - -HRESULT CStreamSwitcherOutputPin::CheckMediaType(const CMediaType* pmt) -{ - return (static_cast(m_pFilter))->CheckMediaType(pmt); -} - -HRESULT CStreamSwitcherOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - if (!pIn || !pIn->IsConnected()) { - return E_UNEXPECTED; - } - - CComPtr pEM; - if (FAILED(pIn->GetConnected()->EnumMediaTypes(&pEM))) { - return VFW_S_NO_MORE_ITEMS; - } - - if (iPosition > 0 && FAILED(pEM->Skip(iPosition))) { - return VFW_S_NO_MORE_ITEMS; - } - - AM_MEDIA_TYPE* tmp = nullptr; - if (S_OK != pEM->Next(1, &tmp, nullptr) || !tmp) { - return VFW_S_NO_MORE_ITEMS; - } - - CopyMediaType(pmt, tmp); - DeleteMediaType(tmp); - /* - if (iPosition < 0) return E_INVALIDARG; - if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; - - CopyMediaType(pmt, &pIn->CurrentMediaType()); - */ - return S_OK; -} - -// IPin - -STDMETHODIMP CStreamSwitcherOutputPin::QueryAccept(const AM_MEDIA_TYPE* pmt) -{ - HRESULT hr = __super::QueryAccept(pmt); - if (S_OK != hr) { - return hr; - } - - return QueryAcceptUpstream(pmt); -} - -// IQualityControl - -STDMETHODIMP CStreamSwitcherOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - if (!pIn || !pIn->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - return pIn->PassNotify(q); -} - -// IStreamBuilder - -STDMETHODIMP CStreamSwitcherOutputPin::Render(IPin* ppinOut, IGraphBuilder* pGraph) -{ - CComPtr pBF; - pBF.CoCreateInstance(CLSID_DSoundRender); - if (!pBF || FAILED(pGraph->AddFilter(pBF, L"Default DirectSound Device"))) { - return E_FAIL; - } - - if (FAILED(pGraph->ConnectDirect(ppinOut, GetFirstDisconnectedPin(pBF, PINDIR_INPUT), nullptr))) { - pGraph->RemoveFilter(pBF); - return E_FAIL; - } - - return S_OK; -} - -STDMETHODIMP CStreamSwitcherOutputPin::Backout(IPin* ppinOut, IGraphBuilder* pGraph) -{ - return S_OK; -} - -// -// CStreamSwitcherFilter -// - -CStreamSwitcherFilter::CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) - : CBaseFilter(NAME("CStreamSwitcherFilter"), lpunk, &m_csState, clsid) - , m_pInput(nullptr) - , m_pOutput(nullptr) -{ - if (phr) { - *phr = S_OK; - } - - HRESULT hr = S_OK; - - do { - CAutoPtr pInput; - CAutoPtr pOutput; - - hr = S_OK; - pInput.Attach(DEBUG_NEW CStreamSwitcherInputPin(this, &hr, L"Channel 1")); - if (!pInput || FAILED(hr)) { - break; - } - - hr = S_OK; - pOutput.Attach(DEBUG_NEW CStreamSwitcherOutputPin(this, &hr)); - if (!pOutput || FAILED(hr)) { - break; - } - - CAutoLock cAutoLock(&m_csPins); - - m_pInputs.AddHead(m_pInput = pInput.Detach()); - m_pOutput = pOutput.Detach(); - - return; - } while (false); - - if (phr) { - *phr = E_FAIL; - } -} - -CStreamSwitcherFilter::~CStreamSwitcherFilter() -{ - CAutoLock cAutoLock(&m_csPins); - - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - delete m_pInputs.GetNext(pos); - } - m_pInputs.RemoveAll(); - m_pInput = nullptr; - - delete m_pOutput; - m_pOutput = nullptr; -} - -STDMETHODIMP CStreamSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IAMStreamSelect) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// - -int CStreamSwitcherFilter::GetPinCount() -{ - CAutoLock cAutoLock(&m_csPins); - - return (1 + (int)m_pInputs.GetCount()); -} - -CBasePin* CStreamSwitcherFilter::GetPin(int n) -{ - CAutoLock cAutoLock(&m_csPins); - - if (n < 0 || n >= GetPinCount()) { - return nullptr; - } else if (n == 0) { - return m_pOutput; - } else { - return m_pInputs.GetAt(m_pInputs.FindIndex(n - 1)); - } -} - -int CStreamSwitcherFilter::GetConnectedInputPinCount() -{ - CAutoLock cAutoLock(&m_csPins); - - int nConnected = 0; - POSITION pos = m_pInputs.GetHeadPosition(); - - while (pos) { - if (m_pInputs.GetNext(pos)->IsConnected()) { - nConnected++; - } - } - - return nConnected; -} - -CStreamSwitcherInputPin* CStreamSwitcherFilter::GetConnectedInputPin(int n) -{ - if (n >= 0) { - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos); - if (pPin->IsConnected()) { - if (n == 0) { - return pPin; - } - n--; - } - } - } - - return nullptr; -} - -CStreamSwitcherInputPin* CStreamSwitcherFilter::GetInputPin() -{ - return m_pInput; -} - -CStreamSwitcherOutputPin* CStreamSwitcherFilter::GetOutputPin() -{ - return m_pOutput; -} - -// - -HRESULT CStreamSwitcherFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin) -{ - if (dir == PINDIR_INPUT) { - CAutoLock cAutoLock(&m_csPins); - - int nConnected = GetConnectedInputPinCount(); - - if (nConnected == 1) { - m_pInput = static_cast(pPin); - } - - if ((size_t)nConnected == m_pInputs.GetCount()) { - CStringW name; - name.Format(L"Channel %ld", ++m_PinVersion); - - HRESULT hr = S_OK; - CStreamSwitcherInputPin* pInputPin = DEBUG_NEW CStreamSwitcherInputPin(this, &hr, name); - if (!pInputPin || FAILED(hr)) { - delete pInputPin; - return E_FAIL; - } - m_pInputs.AddTail(pInputPin); - } - } - - return S_OK; -} - -// this should be very thread safe, I hope it is, it must be... :) - -void CStreamSwitcherFilter::SelectInput(CStreamSwitcherInputPin* pInput) -{ - // make sure no input thinks it is active - m_pInput = nullptr; - - // release blocked GetBuffer in our own allocator & block all Receive - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos); - pPin->Block(false); - // a few Receive calls can arrive here, but since m_pInput == nullptr neighter of them gets delivered - pPin->Block(true); - } - - // this will let waiting GetBuffer() calls go on inside our Receive() - if (m_pOutput) { - m_pOutput->DeliverBeginFlush(); - m_pOutput->DeliverEndFlush(); - } - - if (!pInput) { - return; - } - - // set new input - m_pInput = pInput; - - // let it go - m_pInput->Block(false); -} - -// - -HRESULT CStreamSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - BYTE* pDataIn = nullptr; - BYTE* pDataOut = nullptr; - - HRESULT hr; - if (FAILED(hr = pIn->GetPointer(&pDataIn))) { - return hr; - } - if (FAILED(hr = pOut->GetPointer(&pDataOut))) { - return hr; - } - - long len = pIn->GetActualDataLength(); - long size = pOut->GetSize(); - - if (!pDataIn || !pDataOut /*|| len > size || len <= 0*/) { - return S_FALSE; // FIXME - } - - memcpy(pDataOut, pDataIn, std::min(len, size)); - pOut->SetActualDataLength(std::min(len, size)); - - return S_OK; -} - -CMediaType CStreamSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer) -{ - return mt; -} - -HRESULT CStreamSwitcherFilter::DeliverEndOfStream() -{ - return m_pOutput ? m_pOutput->DeliverEndOfStream() : E_FAIL; -} - -HRESULT CStreamSwitcherFilter::DeliverBeginFlush() -{ - return m_pOutput ? m_pOutput->DeliverBeginFlush() : E_FAIL; -} - -HRESULT CStreamSwitcherFilter::DeliverEndFlush() -{ - return m_pOutput ? m_pOutput->DeliverEndFlush() : E_FAIL; -} - -HRESULT CStreamSwitcherFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - return m_pOutput ? m_pOutput->DeliverNewSegment(tStart, tStop, dRate) : E_FAIL; -} - -// IAMStreamSelect - -STDMETHODIMP CStreamSwitcherFilter::Count(DWORD* pcStreams) -{ - CheckPointer(pcStreams, E_POINTER); - - CAutoLock cAutoLock(&m_csPins); - - *pcStreams = 0; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CStreamSwitcherInputPin* pInputPin = m_pInputs.GetNext(pos); - - if (pInputPin->IsConnected()) { - if (CComPtr pSSF = pInputPin->GetStreamSelectionFilter()) { - DWORD cStreams = 0; - HRESULT hr = pSSF->Count(&cStreams); - if (SUCCEEDED(hr)) { - for (int i = 0; i < (int)cStreams; i++) { - AM_MEDIA_TYPE* pmt = nullptr; - hr = pSSF->Info(i, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { - (*pcStreams)++; - } - DeleteMediaType(pmt); - } - } - } else { - (*pcStreams)++; - } - } - } - - return S_OK; -} - -STDMETHODIMP CStreamSwitcherFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) -{ - CAutoLock cAutoLock(&m_csPins); - - IUnknown* pObject = nullptr; - bool bFound = false; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos && !bFound) { - CStreamSwitcherInputPin* pInputPin = m_pInputs.GetNext(pos); - - if (pInputPin->IsConnected()) { - if (CComPtr pSSF = pInputPin->GetStreamSelectionFilter()) { - DWORD cStreams = 0; - HRESULT hr = pSSF->Count(&cStreams); - if (SUCCEEDED(hr)) { - for (int i = 0; i < (int)cStreams; i++) { - AM_MEDIA_TYPE* pmt = nullptr; - DWORD dwFlags; - LPWSTR pszName = nullptr; - hr = pSSF->Info(i, &pmt, &dwFlags, plcid, nullptr, &pszName, nullptr, nullptr); - if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { - if (lIndex == 0) { - bFound = true; - pObject = pSSF; - - if (ppmt) { - *ppmt = pmt; - } else { - DeleteMediaType(pmt); - } - - if (pdwFlags) { - *pdwFlags = (m_pInput == pInputPin) ? dwFlags : 0; - } - - if (pdwGroup) { - *pdwGroup = 1; - } - - if (ppszName) { - *ppszName = pszName; - } else { - CoTaskMemFree(pszName); - } - - break; - } else { - lIndex--; - } - } - DeleteMediaType(pmt); - CoTaskMemFree(pszName); - } - } - } else if (lIndex == 0) { - bFound = true; - - if (ppmt) { - bool found = false; - CComPtr pPinUpstream; - if (SUCCEEDED(m_pInput->ConnectedTo(&pPinUpstream)) && pPinUpstream) { - // find audio input pin of upstream filter - if (CComQIPtr pBF = GetFilterFromPin(pPinUpstream)) { - BeginEnumPins(pBF, pEP, pPin) { - CMediaTypeEx mt; - PIN_DIRECTION dir; - if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (mt.majortype == MEDIATYPE_Audio) { - *ppmt = CreateMediaType(&mt); - found = true; - break; - } - } - } - EndEnumPins; - } - } - if (!found) { - *ppmt = CreateMediaType(&m_pInput->CurrentMediaType()); - } - } - - if (pdwFlags) { - *pdwFlags = (m_pInput == pInputPin) ? AMSTREAMSELECTINFO_EXCLUSIVE : 0; - } - - if (plcid) { - *plcid = 0; - } - - if (pdwGroup) { - *pdwGroup = 1; - } - - if (ppszName) { - *ppszName = (WCHAR*)CoTaskMemAlloc((wcslen(pInputPin->Name()) + 1) * sizeof(WCHAR)); - if (*ppszName) { - wcscpy_s(*ppszName, wcslen(pInputPin->Name()) + 1, pInputPin->Name()); - } - } - } else { - lIndex--; - } - } - } - - if (!bFound) { - return E_INVALIDARG; - } - - if (ppObject) { - *ppObject = pObject; - if (pObject) { - pObject->AddRef(); - } - } - - if (ppUnk) { - *ppUnk = nullptr; - } - - return S_OK; -} - -STDMETHODIMP CStreamSwitcherFilter::Enable(long lIndex, DWORD dwFlags) -{ - if (dwFlags != AMSTREAMSELECTENABLE_ENABLE) { - return E_NOTIMPL; - } - - PauseGraph; - - bool bFound = false; - int i = 0; - CStreamSwitcherInputPin* pNewInputPin = nullptr; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos && !bFound) { - pNewInputPin = m_pInputs.GetNext(pos); - - if (pNewInputPin->IsConnected()) { - if (CComPtr pSSF = pNewInputPin->GetStreamSelectionFilter()) { - DWORD cStreams = 0; - HRESULT hr = pSSF->Count(&cStreams); - if (SUCCEEDED(hr)) { - for (i = 0; i < (int)cStreams; i++) { - AM_MEDIA_TYPE* pmt = nullptr; - hr = pSSF->Info(i, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { - if (lIndex == 0) { - bFound = true; - DeleteMediaType(pmt); - break; - } else { - lIndex--; - } - } - DeleteMediaType(pmt); - } - } - } else if (lIndex == 0) { - bFound = true; - } else { - lIndex--; - } - } - } - - if (!bFound) { - return E_INVALIDARG; - } - - SelectInput(pNewInputPin); - - if (CComPtr pSSF = pNewInputPin->GetStreamSelectionFilter()) { - pSSF->Enable(i, dwFlags); - } - - ResumeGraph; - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "StreamSwitcher.h" +#include "../../../DSUtil/DSUtil.h" +#include "../../../DSUtil/PathUtils.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +#define BLOCKSTREAM + +// +// CStreamSwitcherPassThru +// + +CStreamSwitcherPassThru::CStreamSwitcherPassThru(LPUNKNOWN pUnk, HRESULT* phr, CStreamSwitcherFilter* pFilter) + : CMediaPosition(NAME("CStreamSwitcherPassThru"), pUnk) + , m_pFilter(pFilter) +{ +} + +STDMETHODIMP CStreamSwitcherPassThru::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = nullptr; + + return + QI(IMediaSeeking) + CMediaPosition::NonDelegatingQueryInterface(riid, ppv); +} + +template +HRESULT GetPeer(CStreamSwitcherFilter* pFilter, T** ppT) +{ + *ppT = nullptr; + + CBasePin* pPin = pFilter->GetInputPin(); + if (!pPin) { + return E_NOTIMPL; + } + + CComPtr pConnected; + if (FAILED(pPin->ConnectedTo(&pConnected))) { + return E_NOTIMPL; + } + + if (CComQIPtr pT = pConnected) { + *ppT = pT.Detach(); + return S_OK; + } + + return E_NOTIMPL; +} + + +#define CallPeerSeeking(call) \ + CComPtr pMS; \ + if (FAILED(GetPeer(m_pFilter, &pMS))) \ + return E_NOTIMPL; \ + return pMS->##call; + +#define CallPeer(call) \ + CComPtr pMP; \ + if (FAILED(GetPeer(m_pFilter, &pMP))) \ + return E_NOTIMPL; \ + return pMP->##call; + +#define CallPeerSeekingAll(call) \ + HRESULT hr = E_NOTIMPL; \ + POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); \ + while (pos) { \ + CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); \ + CComPtr pConnected; \ + if (FAILED(pPin->ConnectedTo(&pConnected))) \ + continue; \ + if (CComQIPtr pMS = pConnected) { \ + HRESULT hr2 = pMS->call; \ + if (pPin == m_pFilter->GetInputPin()) \ + hr = hr2; \ + } \ + } \ + return hr; + +#define CallPeerAll(call) \ + HRESULT hr = E_NOTIMPL; \ + POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); \ + while (pos) { \ + CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); \ + CComPtr pConnected; \ + if (FAILED(pPin->ConnectedTo(&pConnected))) \ + continue; \ + if (CComQIPtr pMP = pConnected) { \ + HRESULT hr2 = pMP->call; \ + if (pPin == m_pFilter->GetInputPin()) \ + hr = hr2; \ + } \ + } \ + return hr; + + +// IMediaSeeking + +STDMETHODIMP CStreamSwitcherPassThru::GetCapabilities(DWORD* pCaps) +{ + CallPeerSeeking(GetCapabilities(pCaps)); +} + +STDMETHODIMP CStreamSwitcherPassThru::CheckCapabilities(DWORD* pCaps) +{ + CallPeerSeeking(CheckCapabilities(pCaps)); +} + +STDMETHODIMP CStreamSwitcherPassThru::IsFormatSupported(const GUID* pFormat) +{ + CallPeerSeeking(IsFormatSupported(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::QueryPreferredFormat(GUID* pFormat) +{ + CallPeerSeeking(QueryPreferredFormat(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::SetTimeFormat(const GUID* pFormat) +{ + CallPeerSeeking(SetTimeFormat(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetTimeFormat(GUID* pFormat) +{ + CallPeerSeeking(GetTimeFormat(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::IsUsingTimeFormat(const GUID* pFormat) +{ + CallPeerSeeking(IsUsingTimeFormat(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + CallPeerSeeking(ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, LONGLONG* pStop, DWORD StopFlags) +{ + CallPeerSeekingAll(SetPositions(pCurrent, CurrentFlags, pStop, StopFlags)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + CallPeerSeeking(GetPositions(pCurrent, pStop)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetCurrentPosition(LONGLONG* pCurrent) +{ + CallPeerSeeking(GetCurrentPosition(pCurrent)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetStopPosition(LONGLONG* pStop) +{ + CallPeerSeeking(GetStopPosition(pStop)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetDuration(LONGLONG* pDuration) +{ + CallPeerSeeking(GetDuration(pDuration)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetPreroll(LONGLONG* pllPreroll) +{ + CallPeerSeeking(GetPreroll(pllPreroll)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + CallPeerSeeking(GetAvailable(pEarliest, pLatest)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetRate(double* pdRate) +{ + CallPeerSeeking(GetRate(pdRate)); +} + +STDMETHODIMP CStreamSwitcherPassThru::SetRate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + CallPeerSeekingAll(SetRate(dRate)); +} + +// IMediaPosition + +STDMETHODIMP CStreamSwitcherPassThru::get_Duration(REFTIME* plength) +{ + CallPeer(get_Duration(plength)); +} + +STDMETHODIMP CStreamSwitcherPassThru::get_CurrentPosition(REFTIME* pllTime) +{ + CallPeer(get_CurrentPosition(pllTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::put_CurrentPosition(REFTIME llTime) +{ + CallPeerAll(put_CurrentPosition(llTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::get_StopTime(REFTIME* pllTime) +{ + CallPeer(get_StopTime(pllTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::put_StopTime(REFTIME llTime) +{ + CallPeerAll(put_StopTime(llTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::get_PrerollTime(REFTIME* pllTime) +{ + CallPeer(get_PrerollTime(pllTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::put_PrerollTime(REFTIME llTime) +{ + CallPeerAll(put_PrerollTime(llTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::get_Rate(double* pdRate) +{ + CallPeer(get_Rate(pdRate)); +} + +STDMETHODIMP CStreamSwitcherPassThru::put_Rate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + CallPeerAll(put_Rate(dRate)); +} + +STDMETHODIMP CStreamSwitcherPassThru::CanSeekForward(LONG* pCanSeekForward) +{ + CallPeer(CanSeekForward(pCanSeekForward)); +} + +STDMETHODIMP CStreamSwitcherPassThru::CanSeekBackward(LONG* pCanSeekBackward) +{ + CallPeer(CanSeekBackward(pCanSeekBackward)); +} + +// +// CStreamSwitcherAllocator +// + +CStreamSwitcherAllocator::CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr) + : CMemAllocator(NAME("CStreamSwitcherAllocator"), nullptr, phr) + , m_pPin(pPin) + , m_fMediaTypeChanged(false) +{ + ASSERT(phr); + ASSERT(pPin); +} + +#ifdef _DEBUG +CStreamSwitcherAllocator::~CStreamSwitcherAllocator() +{ + ASSERT(m_bCommitted == FALSE); +} +#endif + +STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingAddRef() +{ + return m_pPin->m_pFilter->AddRef(); +} + +STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingRelease() +{ + return m_pPin->m_pFilter->Release(); +} + +STDMETHODIMP CStreamSwitcherAllocator::GetBuffer( + IMediaSample** ppBuffer, + REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, + DWORD dwFlags) +{ + HRESULT hr = VFW_E_NOT_COMMITTED; + + if (!m_bCommitted) { + return hr; + } + /* + TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() + %x\n"), this); + m_pPin->m_evBlock.Wait(); + TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() - %x\n"), this); + */ + if (m_fMediaTypeChanged) { + if (!m_pPin || !m_pPin->m_pFilter) { + return hr; + } + + CStreamSwitcherOutputPin* pOut = (static_cast(m_pPin->m_pFilter))->GetOutputPin(); + if (!pOut || !pOut->CurrentAllocator()) { + return hr; + } + + ALLOCATOR_PROPERTIES Properties, Actual; + if (FAILED(pOut->CurrentAllocator()->GetProperties(&Actual))) { + return hr; + } + if (FAILED(GetProperties(&Properties))) { + return hr; + } + + if (!m_bCommitted || Properties.cbBuffer < Actual.cbBuffer) { + Properties.cbBuffer = Actual.cbBuffer; + if (FAILED(Decommit())) { + return hr; + } + if (FAILED(SetProperties(&Properties, &Actual))) { + return hr; + } + if (FAILED(Commit())) { + return hr; + } + ASSERT(Actual.cbBuffer >= Properties.cbBuffer); + if (Actual.cbBuffer < Properties.cbBuffer) { + return hr; + } + } + } + + hr = CMemAllocator::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags); + + if (m_fMediaTypeChanged && SUCCEEDED(hr)) { + (*ppBuffer)->SetMediaType(&m_mt); + m_fMediaTypeChanged = false; + } + + return hr; +} + +void CStreamSwitcherAllocator::NotifyMediaType(const CMediaType& mt) +{ + CopyMediaType(&m_mt, &mt); + m_fMediaTypeChanged = true; +} + + +// +// CStreamSwitcherInputPin +// + +CStreamSwitcherInputPin::CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName) + : CBaseInputPin(NAME("CStreamSwitcherInputPin"), pFilter, &pFilter->m_csState, phr, pName) + , m_Allocator(this, phr) + , m_bSampleSkipped(FALSE) + , m_bQualityChanged(FALSE) + , m_bUsingOwnAllocator(FALSE) + , m_evBlock(TRUE) + , m_fCanBlock(false) + , m_hNotifyEvent(nullptr) + , m_bFirstSampleReceived(false) +{ + m_bCanReconnectWhenActive = true; +} + +class __declspec(uuid("138130AF-A79B-45D5-B4AA-87697457BA87")) + NeroAudioDecoder {}; + +STDMETHODIMP CStreamSwitcherInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IStreamSwitcherInputPin) + IsConnected() && GetCLSID(GetFilterFromPin(GetConnected())) == __uuidof(NeroAudioDecoder) && QI(IPinConnection) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IPinConnection + +STDMETHODIMP CStreamSwitcherInputPin::DynamicQueryAccept(const AM_MEDIA_TYPE* pmt) +{ + return QueryAccept(pmt); +} + +STDMETHODIMP CStreamSwitcherInputPin::NotifyEndOfStream(HANDLE hNotifyEvent) +{ + if (m_hNotifyEvent) { + SetEvent(m_hNotifyEvent); + } + m_hNotifyEvent = hNotifyEvent; + return S_OK; +} + +STDMETHODIMP CStreamSwitcherInputPin::IsEndPin() +{ + return S_OK; +} + +STDMETHODIMP CStreamSwitcherInputPin::DynamicDisconnect() +{ + CAutoLock cAutoLock(&m_csReceive); + Disconnect(); + return S_OK; +} + +// IStreamSwitcherInputPin + +STDMETHODIMP_(bool) CStreamSwitcherInputPin::IsActive() +{ + // TODO: lock onto something here + return (this == (static_cast(m_pFilter))->GetInputPin()); +} + +// + +HRESULT CStreamSwitcherInputPin::QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt) +{ + HRESULT hr = S_OK; + + CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); + + if (pOut && pOut->IsConnected()) { + if (CComPtr pPC = pOut->CurrentPinConnection()) { + hr = pPC->DynamicQueryAccept(pmt); + if (hr == S_OK) { + return S_OK; + } + } + + hr = pOut->GetConnected()->QueryAccept(pmt); + } + + return hr; +} + +void CStreamSwitcherInputPin::Block(bool fBlock) +{ + if (fBlock) { + m_evBlock.Reset(); + } else { + m_evBlock.Set(); + } +} + +HRESULT CStreamSwitcherInputPin::InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample) +{ + if (!pInSample || !ppOutSample) { + return E_POINTER; + } + + CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); + ASSERT(pOut->GetConnected()); + + CComPtr pOutSample; + + DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; + + if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { + dwFlags |= AM_GBF_NOTASYNCPOINT; + } + + HRESULT hr = pOut->GetDeliveryBuffer(&pOutSample, + (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) ? &m_SampleProps.tStart : nullptr, + (m_SampleProps.dwSampleFlags & AM_SAMPLE_STOPVALID) ? &m_SampleProps.tStop : nullptr, + dwFlags); + + if (FAILED(hr)) { + return hr; + } + + if (!pOutSample) { + return E_FAIL; + } + + if (CComQIPtr pOutSample2 = pOutSample) { + AM_SAMPLE2_PROPERTIES OutProps; + EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps))); + OutProps.dwTypeSpecificFlags = m_SampleProps.dwTypeSpecificFlags; + OutProps.dwSampleFlags = + (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | + (m_SampleProps.dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); + + OutProps.tStart = m_SampleProps.tStart; + OutProps.tStop = m_SampleProps.tStop; + OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); + + pOutSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps); + if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + m_bSampleSkipped = FALSE; + } + } else { + if (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) { + pOutSample->SetTime(&m_SampleProps.tStart, &m_SampleProps.tStop); + } + + if (m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { + pOutSample->SetSyncPoint(TRUE); + } + + if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + pOutSample->SetDiscontinuity(TRUE); + m_bSampleSkipped = FALSE; + } + + LONGLONG MediaStart, MediaEnd; + if (pInSample->GetMediaTime(&MediaStart, &MediaEnd) == NOERROR) { + pOutSample->SetMediaTime(&MediaStart, &MediaEnd); + } + } + + *ppOutSample = pOutSample.Detach(); + + return S_OK; +} + +// pure virtual + +HRESULT CStreamSwitcherInputPin::CheckMediaType(const CMediaType* pmt) +{ + return (static_cast(m_pFilter))->CheckMediaType(pmt); +} + +// virtual + +HRESULT CStreamSwitcherInputPin::CheckConnect(IPin* pPin) +{ + return (IPin*)(static_cast(m_pFilter))->GetOutputPin() == pPin + ? E_FAIL + : __super::CheckConnect(pPin); +} + +HRESULT CStreamSwitcherInputPin::CompleteConnect(IPin* pReceivePin) +{ + HRESULT hr = __super::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + (static_cast(m_pFilter))->CompleteConnect(PINDIR_INPUT, this, pReceivePin); + + m_fCanBlock = false; + bool fForkedSomewhere = false; + + CStringW streamName; + CStringW pinName; + + IPin* pPin = (IPin*)this; + IBaseFilter* pBF = (IBaseFilter*)m_pFilter; + + pPin = GetUpStreamPin(pBF, pPin); + if (pPin) { + pBF = GetFilterFromPin(pPin); + } + while (pPin && pBF) { + if (IsSplitter(pBF)) { + pinName = GetPinName(pPin); + } + + CLSID clsid = GetCLSID(pBF); + if (clsid == CLSID_AviSplitter || clsid == CLSID_OggSplitter) { + m_fCanBlock = true; + } + + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + fForkedSomewhere = fForkedSomewhere || nIn > 1 || nOut > 1; + + DWORD cStreams = 0; + CStringW streamSSName; + if (CComQIPtr pSSF = pBF) { + hr = pSSF->Count(&cStreams); + if (SUCCEEDED(hr)) { + for (int i = 0; i < (int)cStreams; i++) { + CComHeapPtr pszNameSS; + AM_MEDIA_TYPE* pmt = nullptr; + LCID lcid = 0; + + hr = pSSF->Info(i, &pmt, nullptr, &lcid, nullptr, &pszNameSS, nullptr, nullptr); + if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { + m_pSSF = pSSF; + DeleteMediaType(pmt); + streamSSName = pszNameSS; + break; + } + DeleteMediaType(pmt); + } + } + } + + if (CComQIPtr pFSF = pBF) { + CComHeapPtr fileName; + AM_MEDIA_TYPE mt; + + if (SUCCEEDED(pFSF->GetCurFile(&fileName, &mt)) && fileName) { + streamName = fileName; + if (streamName.Find(L"googlevideo.com") > 0 || (PathUtils::IsURL(streamName) && streamName.GetLength() > 50)) { //we don't like these URLs + streamName = streamSSName; + if (streamName.GetLength() <= 0) { + streamName = L"Online Audio Stream"; + } + } else { + streamName.Replace('\\', '/'); + CStringW fn = streamName.Mid(streamName.ReverseFind('/') + 1); + if (!fn.IsEmpty()) { + streamName = fn; + } + + // Haali & LAVFSplitter return only one "Audio" pin name, cause CMainFrame::OnInitMenuPopup lookup find the wrong popmenu, + // add space at the end to prevent this, internal filter never return "Audio" only. + if (!pinName.IsEmpty()) { + streamName = pinName + L" "; + } + } + + WCHAR* pName = DEBUG_NEW WCHAR[streamName.GetLength() + 1]; + if (pName) { + wcscpy_s(pName, streamName.GetLength() + 1, streamName); + if (m_pName) { + delete[] m_pName; + } + m_pName = pName; + if (cStreams == 1) { // Simple external track, no need to use the info from IAMStreamSelect + m_pSSF.Release(); + } + } + } + + break; + } + + pPin = GetFirstPin(pBF); + + pPin = GetUpStreamPin(pBF, pPin); + if (pPin) { + pBF = GetFilterFromPin(pPin); + } + } + + if (!fForkedSomewhere) { + m_fCanBlock = true; + } + + m_hNotifyEvent = nullptr; + + return S_OK; +} + +HRESULT CStreamSwitcherInputPin::Active() +{ + Block(!IsActive()); + + return __super::Active(); +} + +HRESULT CStreamSwitcherInputPin::Inactive() +{ + Block(false); + + return __super::Inactive(); +} + +// IPin + +STDMETHODIMP CStreamSwitcherInputPin::QueryAccept(const AM_MEDIA_TYPE* pmt) +{ + HRESULT hr = __super::QueryAccept(pmt); + if (S_OK != hr) { + return hr; + } + + return QueryAcceptDownstream(pmt); +} + +STDMETHODIMP CStreamSwitcherInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) +{ + // FIXME: this locked up once + // CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csReceive); + + HRESULT hr; + if (S_OK != (hr = QueryAcceptDownstream(pmt))) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + + if (m_Connected && m_Connected != pConnector) { + return VFW_E_ALREADY_CONNECTED; + } + + SAFE_RELEASE(m_Connected); + + return SUCCEEDED(__super::ReceiveConnection(pConnector, pmt)) ? S_OK : E_FAIL; +} + +STDMETHODIMP CStreamSwitcherInputPin::GetAllocator(IMemAllocator** ppAllocator) +{ + CheckPointer(ppAllocator, E_POINTER); + + if (m_pAllocator == nullptr) { + (m_pAllocator = &m_Allocator)->AddRef(); + } + + (*ppAllocator = m_pAllocator)->AddRef(); + + return NOERROR; +} + +STDMETHODIMP CStreamSwitcherInputPin::NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly) +{ + HRESULT hr = __super::NotifyAllocator(pAllocator, bReadOnly); + if (FAILED(hr)) { + return hr; + } + + m_bUsingOwnAllocator = (pAllocator == (IMemAllocator*)&m_Allocator); + + return S_OK; +} + +STDMETHODIMP CStreamSwitcherInputPin::BeginFlush() +{ + CAutoLock cAutoLock(&(static_cast(m_pFilter))->m_csState); + + HRESULT hr; + + CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); + + CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); + if (!IsConnected() || !pOut || !pOut->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + if (FAILED(hr = __super::BeginFlush())) { + return hr; + } + + return IsActive() ? pSSF->DeliverBeginFlush() : (Block(false), S_OK); +} + +STDMETHODIMP CStreamSwitcherInputPin::EndFlush() +{ + CAutoLock cAutoLock(&(static_cast(m_pFilter))->m_csState); + + HRESULT hr; + + CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); + + CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); + if (!IsConnected() || !pOut || !pOut->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + if (FAILED(hr = __super::EndFlush())) { + return hr; + } + + return IsActive() ? pSSF->DeliverEndFlush() : (Block(true), S_OK); +} + +STDMETHODIMP CStreamSwitcherInputPin::EndOfStream() +{ + CAutoLock cAutoLock(&m_csReceive); + + CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); + + CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); + if (!IsConnected() || !pOut || !pOut->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + if (m_hNotifyEvent) { + SetEvent(m_hNotifyEvent), m_hNotifyEvent = nullptr; + return S_OK; + } + + if (!m_bFirstSampleReceived) { + pSSF->Stop(); + } + return IsActive() ? pSSF->DeliverEndOfStream() : S_OK; +} + +// IMemInputPin + +STDMETHODIMP CStreamSwitcherInputPin::Receive(IMediaSample* pSample) +{ + m_bFirstSampleReceived = true; + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { + const CMediaType mt(*pmt); + DeleteMediaType(pmt), pmt = nullptr; + SetMediaType(&mt); + } + + // DAMN!!!!!! this doesn't work if the stream we are blocking + // shares the same thread with another stream, mpeg splitters + // are usually like that. Our nicely built up multithreaded + // strategy is useless because of this, ARRRRRRGHHHHHH. + +#ifdef BLOCKSTREAM + if (m_fCanBlock) { + m_evBlock.Wait(); + } +#endif + + if (!IsActive()) { +#ifdef BLOCKSTREAM + if (m_fCanBlock) { + return S_FALSE; + } +#endif + + TRACE(_T("&^$#@ : a stupid fix for this stupid problem\n")); + //Sleep(32); + return E_FAIL; // a stupid fix for this stupid problem + } + + CAutoLock cAutoLock(&m_csReceive); + + CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); + ASSERT(pOut->GetConnected()); + + HRESULT hr = __super::Receive(pSample); + if (S_OK != hr) { + return hr; + } + + if (m_SampleProps.dwStreamId != AM_STREAM_MEDIA) { + return pOut->Deliver(pSample); + } + + // + + ALLOCATOR_PROPERTIES props, actual; + m_pAllocator->GetProperties(&props); + IMemAllocator* cur_alloc = pOut->CurrentAllocator(); + if (!cur_alloc) { + ASSERT(false); + return E_FAIL; + } + cur_alloc->GetProperties(&actual); + + REFERENCE_TIME rtStart = 0, rtStop = 0; + if (S_OK == pSample->GetTime(&rtStart, &rtStop)) { + // + } + + long cbBuffer = pSample->GetActualDataLength(); + + CMediaType mtOut = m_mt; + mtOut = (static_cast(m_pFilter))->CreateNewOutputMediaType(mtOut, cbBuffer); + + bool fTypeChanged = false; + + if (mtOut != pOut->CurrentMediaType() || cbBuffer > actual.cbBuffer) { + fTypeChanged = true; + + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED/*|AM_SAMPLE_DATADISCONTINUITY|AM_SAMPLE_TIMEDISCONTINUITY*/; + + if (props.cBuffers < 8 && mtOut.majortype == MEDIATYPE_Audio) { + props.cBuffers = 8; + } + + props.cbBuffer = cbBuffer; + + if (actual.cbAlign != props.cbAlign + || actual.cbPrefix != props.cbPrefix + || actual.cBuffers < props.cBuffers + || actual.cbBuffer < props.cbBuffer) { + pOut->DeliverBeginFlush(); + pOut->DeliverEndFlush(); + pOut->CurrentAllocator()->Decommit(); + pOut->CurrentAllocator()->SetProperties(&props, &actual); + pOut->CurrentAllocator()->Commit(); + } + } + + CComPtr pOutSample; + if (FAILED(InitializeOutputSample(pSample, &pOutSample))) { + return E_FAIL; + } + + pmt = nullptr; + if (SUCCEEDED(pOutSample->GetMediaType(&pmt)) && pmt) { + const CMediaType mt(*pmt); + DeleteMediaType(pmt), pmt = nullptr; + // TODO + ASSERT(0); + } + + if (fTypeChanged) { + pOut->SetMediaType(&mtOut); + (static_cast(m_pFilter))->OnNewOutputMediaType(m_mt, mtOut); + pOutSample->SetMediaType(&mtOut); + } + + // Transform + + hr = (static_cast(m_pFilter))->Transform(pSample, pOutSample); + + if (S_OK == hr) { + hr = pOut->Deliver(pOutSample); + m_bSampleSkipped = FALSE; + } else if (S_FALSE == hr) { + hr = S_OK; + pOutSample = nullptr; + m_bSampleSkipped = TRUE; + + if (!m_bQualityChanged) { + m_pFilter->NotifyEvent(EC_QUALITY_CHANGE, 0, 0); + m_bQualityChanged = TRUE; + } + } + + return hr; +} + +STDMETHODIMP CStreamSwitcherInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + if (!IsConnected() || !IsActive()) { + return S_OK; + } + + CAutoLock cAutoLock(&m_csReceive); + + CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); + + CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); + if (!pOut || !pOut->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + return pSSF->DeliverNewSegment(tStart, tStop, dRate); +} + +// +// CStreamSwitcherOutputPin +// + +CStreamSwitcherOutputPin::CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr) + : CBaseOutputPin(NAME("CStreamSwitcherOutputPin"), pFilter, &pFilter->m_csState, phr, L"Out") +{ + // m_bCanReconnectWhenActive = true; +} + +STDMETHODIMP CStreamSwitcherOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + ValidateReadWritePtr(ppv, sizeof(PVOID)); + *ppv = nullptr; + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + if (m_pStreamSwitcherPassThru == nullptr) { + HRESULT hr = S_OK; + m_pStreamSwitcherPassThru = (IUnknown*)(INonDelegatingUnknown*) + DEBUG_NEW CStreamSwitcherPassThru(GetOwner(), &hr, static_cast(m_pFilter)); + + if (!m_pStreamSwitcherPassThru) { + return E_OUTOFMEMORY; + } + if (FAILED(hr)) { + return hr; + } + } + + return m_pStreamSwitcherPassThru->QueryInterface(riid, ppv); + } + /* + else if (riid == IID_IStreamBuilder) + { + return GetInterface((IStreamBuilder*)this, ppv); + } + */ + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CStreamSwitcherOutputPin::QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt) +{ + HRESULT hr = S_FALSE; + + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + + if (pIn && pIn->IsConnected() && (pIn->IsUsingOwnAllocator() || pIn->CurrentMediaType() == *pmt)) { + if (CComQIPtr pPinTo = pIn->GetConnected()) { + if (S_OK != (hr = pPinTo->QueryAccept(pmt))) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } else { + return E_FAIL; + } + } + + return hr; +} + +// pure virtual + +HRESULT CStreamSwitcherOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + if (!pIn || !pIn->IsConnected()) { + return E_UNEXPECTED; + } + + CComPtr pAllocatorIn; + pIn->GetAllocator(&pAllocatorIn); + if (!pAllocatorIn) { + return E_UNEXPECTED; + } + + HRESULT hr; + if (FAILED(hr = pAllocatorIn->GetProperties(pProperties))) { + return hr; + } + + if (pProperties->cBuffers < 8 && pIn->CurrentMediaType().majortype == MEDIATYPE_Audio) { + pProperties->cBuffers = 8; + } + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +// virtual + +class __declspec(uuid("AEFA5024-215A-4FC7-97A4-1043C86FD0B8")) + MatrixMixer {}; + +HRESULT CStreamSwitcherOutputPin::CheckConnect(IPin* pPin) +{ + CComPtr pBF = GetFilterFromPin(pPin); + + return + IsAudioWaveRenderer(pBF) || GetCLSID(pBF) == __uuidof(MatrixMixer) + ? __super::CheckConnect(pPin) + : E_FAIL; + + // return CComQIPtr(pPin) ? CBaseOutputPin::CheckConnect(pPin) : E_NOINTERFACE; + // return CBaseOutputPin::CheckConnect(pPin); +} + +HRESULT CStreamSwitcherOutputPin::BreakConnect() +{ + m_pPinConnection = nullptr; + return __super::BreakConnect(); +} + +HRESULT CStreamSwitcherOutputPin::CompleteConnect(IPin* pReceivePin) +{ + m_pPinConnection = CComQIPtr(pReceivePin); + HRESULT hr = __super::CompleteConnect(pReceivePin); + + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + CMediaType mt; + if (SUCCEEDED(hr) && pIn && pIn->IsConnected() + && SUCCEEDED(pIn->GetConnected()->ConnectionMediaType(&mt)) && m_mt != mt) { + if (pIn->GetConnected()->QueryAccept(&m_mt) == S_OK) { + hr = m_pFilter->ReconnectPin(pIn->GetConnected(), &m_mt); + } else { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + } + + return hr; +} + +HRESULT CStreamSwitcherOutputPin::CheckMediaType(const CMediaType* pmt) +{ + return (static_cast(m_pFilter))->CheckMediaType(pmt); +} + +HRESULT CStreamSwitcherOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + if (!pIn || !pIn->IsConnected()) { + return E_UNEXPECTED; + } + + CComPtr pEM; + if (FAILED(pIn->GetConnected()->EnumMediaTypes(&pEM))) { + return VFW_S_NO_MORE_ITEMS; + } + + if (iPosition > 0 && FAILED(pEM->Skip(iPosition))) { + return VFW_S_NO_MORE_ITEMS; + } + + AM_MEDIA_TYPE* tmp = nullptr; + if (S_OK != pEM->Next(1, &tmp, nullptr) || !tmp) { + return VFW_S_NO_MORE_ITEMS; + } + + CopyMediaType(pmt, tmp); + DeleteMediaType(tmp); + /* + if (iPosition < 0) return E_INVALIDARG; + if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; + + CopyMediaType(pmt, &pIn->CurrentMediaType()); + */ + return S_OK; +} + +// IPin + +STDMETHODIMP CStreamSwitcherOutputPin::QueryAccept(const AM_MEDIA_TYPE* pmt) +{ + HRESULT hr = __super::QueryAccept(pmt); + if (S_OK != hr) { + return hr; + } + + return QueryAcceptUpstream(pmt); +} + +// IQualityControl + +STDMETHODIMP CStreamSwitcherOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + if (!pIn || !pIn->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + return pIn->PassNotify(q); +} + +// IStreamBuilder + +STDMETHODIMP CStreamSwitcherOutputPin::Render(IPin* ppinOut, IGraphBuilder* pGraph) +{ + CComPtr pBF; + pBF.CoCreateInstance(CLSID_DSoundRender); + if (!pBF || FAILED(pGraph->AddFilter(pBF, L"Default DirectSound Device"))) { + return E_FAIL; + } + + if (FAILED(pGraph->ConnectDirect(ppinOut, GetFirstDisconnectedPin(pBF, PINDIR_INPUT), nullptr))) { + pGraph->RemoveFilter(pBF); + return E_FAIL; + } + + return S_OK; +} + +STDMETHODIMP CStreamSwitcherOutputPin::Backout(IPin* ppinOut, IGraphBuilder* pGraph) +{ + return S_OK; +} + +// +// CStreamSwitcherFilter +// + +CStreamSwitcherFilter::CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) + : CBaseFilter(NAME("CStreamSwitcherFilter"), lpunk, &m_csState, clsid) + , m_pInput(nullptr) + , m_pOutput(nullptr) +{ + if (phr) { + *phr = S_OK; + } + + HRESULT hr = S_OK; + + do { + CAutoPtr pInput; + CAutoPtr pOutput; + + hr = S_OK; + pInput.Attach(DEBUG_NEW CStreamSwitcherInputPin(this, &hr, L"Channel 1")); + if (!pInput || FAILED(hr)) { + break; + } + + hr = S_OK; + pOutput.Attach(DEBUG_NEW CStreamSwitcherOutputPin(this, &hr)); + if (!pOutput || FAILED(hr)) { + break; + } + + CAutoLock cAutoLock(&m_csPins); + + m_pInputs.AddHead(m_pInput = pInput.Detach()); + m_pOutput = pOutput.Detach(); + + return; + } while (false); + + if (phr) { + *phr = E_FAIL; + } +} + +CStreamSwitcherFilter::~CStreamSwitcherFilter() +{ + CAutoLock cAutoLock(&m_csPins); + + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + delete m_pInputs.GetNext(pos); + } + m_pInputs.RemoveAll(); + m_pInput = nullptr; + + delete m_pOutput; + m_pOutput = nullptr; +} + +STDMETHODIMP CStreamSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IAMStreamSelect) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// + +int CStreamSwitcherFilter::GetPinCount() +{ + CAutoLock cAutoLock(&m_csPins); + + return (1 + (int)m_pInputs.GetCount()); +} + +CBasePin* CStreamSwitcherFilter::GetPin(int n) +{ + CAutoLock cAutoLock(&m_csPins); + + if (n < 0 || n >= GetPinCount()) { + return nullptr; + } else if (n == 0) { + return m_pOutput; + } else { + return m_pInputs.GetAt(m_pInputs.FindIndex(n - 1)); + } +} + +int CStreamSwitcherFilter::GetConnectedInputPinCount() +{ + CAutoLock cAutoLock(&m_csPins); + + int nConnected = 0; + POSITION pos = m_pInputs.GetHeadPosition(); + + while (pos) { + if (m_pInputs.GetNext(pos)->IsConnected()) { + nConnected++; + } + } + + return nConnected; +} + +CStreamSwitcherInputPin* CStreamSwitcherFilter::GetConnectedInputPin(int n) +{ + if (n >= 0) { + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos); + if (pPin->IsConnected()) { + if (n == 0) { + return pPin; + } + n--; + } + } + } + + return nullptr; +} + +CStreamSwitcherInputPin* CStreamSwitcherFilter::GetInputPin() +{ + return m_pInput; +} + +CStreamSwitcherOutputPin* CStreamSwitcherFilter::GetOutputPin() +{ + return m_pOutput; +} + +// + +HRESULT CStreamSwitcherFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin) +{ + if (dir == PINDIR_INPUT) { + CAutoLock cAutoLock(&m_csPins); + + int nConnected = GetConnectedInputPinCount(); + + if (nConnected == 1) { + m_pInput = static_cast(pPin); + } + + if ((size_t)nConnected == m_pInputs.GetCount()) { + CStringW name; + name.Format(L"Channel %ld", ++m_PinVersion); + + HRESULT hr = S_OK; + CStreamSwitcherInputPin* pInputPin = DEBUG_NEW CStreamSwitcherInputPin(this, &hr, name); + if (!pInputPin || FAILED(hr)) { + delete pInputPin; + return E_FAIL; + } + m_pInputs.AddTail(pInputPin); + } + } + + return S_OK; +} + +// this should be very thread safe, I hope it is, it must be... :) + +void CStreamSwitcherFilter::SelectInput(CStreamSwitcherInputPin* pInput) +{ + // make sure no input thinks it is active + m_pInput = nullptr; + + // release blocked GetBuffer in our own allocator & block all Receive + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos); + pPin->Block(false); + // a few Receive calls can arrive here, but since m_pInput == nullptr neighter of them gets delivered + pPin->Block(true); + } + + // this will let waiting GetBuffer() calls go on inside our Receive() + if (m_pOutput) { + m_pOutput->DeliverBeginFlush(); + m_pOutput->DeliverEndFlush(); + } + + if (!pInput) { + return; + } + + // set new input + m_pInput = pInput; + + // let it go + m_pInput->Block(false); +} + +// + +HRESULT CStreamSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + BYTE* pDataIn = nullptr; + BYTE* pDataOut = nullptr; + + HRESULT hr; + if (FAILED(hr = pIn->GetPointer(&pDataIn))) { + return hr; + } + if (FAILED(hr = pOut->GetPointer(&pDataOut))) { + return hr; + } + + long len = pIn->GetActualDataLength(); + long size = pOut->GetSize(); + + if (!pDataIn || !pDataOut /*|| len > size || len <= 0*/) { + return S_FALSE; // FIXME + } + + memcpy(pDataOut, pDataIn, std::min(len, size)); + pOut->SetActualDataLength(std::min(len, size)); + + return S_OK; +} + +CMediaType CStreamSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer) +{ + return mt; +} + +HRESULT CStreamSwitcherFilter::DeliverEndOfStream() +{ + return m_pOutput ? m_pOutput->DeliverEndOfStream() : E_FAIL; +} + +HRESULT CStreamSwitcherFilter::DeliverBeginFlush() +{ + return m_pOutput ? m_pOutput->DeliverBeginFlush() : E_FAIL; +} + +HRESULT CStreamSwitcherFilter::DeliverEndFlush() +{ + return m_pOutput ? m_pOutput->DeliverEndFlush() : E_FAIL; +} + +HRESULT CStreamSwitcherFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + return m_pOutput ? m_pOutput->DeliverNewSegment(tStart, tStop, dRate) : E_FAIL; +} + +// IAMStreamSelect + +STDMETHODIMP CStreamSwitcherFilter::Count(DWORD* pcStreams) +{ + CheckPointer(pcStreams, E_POINTER); + + CAutoLock cAutoLock(&m_csPins); + + *pcStreams = 0; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CStreamSwitcherInputPin* pInputPin = m_pInputs.GetNext(pos); + + if (pInputPin->IsConnected()) { + if (CComPtr pSSF = pInputPin->GetStreamSelectionFilter()) { + DWORD cStreams = 0; + HRESULT hr = pSSF->Count(&cStreams); + if (SUCCEEDED(hr)) { + for (int i = 0; i < (int)cStreams; i++) { + AM_MEDIA_TYPE* pmt = nullptr; + hr = pSSF->Info(i, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { + (*pcStreams)++; + } + DeleteMediaType(pmt); + } + } + } else { + (*pcStreams)++; + } + } + } + + return S_OK; +} + +STDMETHODIMP CStreamSwitcherFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) +{ + CAutoLock cAutoLock(&m_csPins); + + IUnknown* pObject = nullptr; + bool bFound = false; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos && !bFound) { + CStreamSwitcherInputPin* pInputPin = m_pInputs.GetNext(pos); + + if (pInputPin->IsConnected()) { + if (CComPtr pSSF = pInputPin->GetStreamSelectionFilter()) { + DWORD cStreams = 0; + HRESULT hr = pSSF->Count(&cStreams); + if (SUCCEEDED(hr)) { + for (int i = 0; i < (int)cStreams; i++) { + AM_MEDIA_TYPE* pmt = nullptr; + DWORD dwFlags; + LPWSTR pszName = nullptr; + hr = pSSF->Info(i, &pmt, &dwFlags, plcid, nullptr, &pszName, nullptr, nullptr); + if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { + if (lIndex == 0) { + bFound = true; + pObject = pSSF; + + if (ppmt) { + *ppmt = pmt; + } else { + DeleteMediaType(pmt); + } + + if (pdwFlags) { + *pdwFlags = (m_pInput == pInputPin) ? dwFlags : 0; + } + + if (pdwGroup) { + *pdwGroup = 1; + } + + if (ppszName) { + *ppszName = pszName; + } else { + CoTaskMemFree(pszName); + } + + break; + } else { + lIndex--; + } + } + DeleteMediaType(pmt); + CoTaskMemFree(pszName); + } + } + } else if (lIndex == 0) { + bFound = true; + + if (ppmt) { + bool found = false; + CComPtr pPinUpstream; + if (SUCCEEDED(m_pInput->ConnectedTo(&pPinUpstream)) && pPinUpstream) { + // find audio input pin of upstream filter + if (CComQIPtr pBF = GetFilterFromPin(pPinUpstream)) { + BeginEnumPins(pBF, pEP, pPin) { + CMediaTypeEx mt; + PIN_DIRECTION dir; + if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (mt.majortype == MEDIATYPE_Audio) { + *ppmt = CreateMediaType(&mt); + found = true; + break; + } + } + } + EndEnumPins; + } + } + if (!found) { + *ppmt = CreateMediaType(&m_pInput->CurrentMediaType()); + } + } + + if (pdwFlags) { + *pdwFlags = (m_pInput == pInputPin) ? AMSTREAMSELECTINFO_EXCLUSIVE : 0; + } + + if (plcid) { + *plcid = 0; + } + + if (pdwGroup) { + *pdwGroup = 1; + } + + if (ppszName) { + *ppszName = (WCHAR*)CoTaskMemAlloc((wcslen(pInputPin->Name()) + 1) * sizeof(WCHAR)); + if (*ppszName) { + wcscpy_s(*ppszName, wcslen(pInputPin->Name()) + 1, pInputPin->Name()); + } + } + } else { + lIndex--; + } + } + } + + if (!bFound) { + return E_INVALIDARG; + } + + if (ppObject) { + *ppObject = pObject; + if (pObject) { + pObject->AddRef(); + } + } + + if (ppUnk) { + *ppUnk = nullptr; + } + + return S_OK; +} + +STDMETHODIMP CStreamSwitcherFilter::Enable(long lIndex, DWORD dwFlags) +{ + if (dwFlags != AMSTREAMSELECTENABLE_ENABLE) { + return E_NOTIMPL; + } + + PauseGraph; + + bool bFound = false; + int i = 0; + CStreamSwitcherInputPin* pNewInputPin = nullptr; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos && !bFound) { + pNewInputPin = m_pInputs.GetNext(pos); + + if (pNewInputPin->IsConnected()) { + if (CComPtr pSSF = pNewInputPin->GetStreamSelectionFilter()) { + DWORD cStreams = 0; + HRESULT hr = pSSF->Count(&cStreams); + if (SUCCEEDED(hr)) { + for (i = 0; i < (int)cStreams; i++) { + AM_MEDIA_TYPE* pmt = nullptr; + hr = pSSF->Info(i, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { + if (lIndex == 0) { + bFound = true; + DeleteMediaType(pmt); + break; + } else { + lIndex--; + } + } + DeleteMediaType(pmt); + } + } + } else if (lIndex == 0) { + bFound = true; + } else { + lIndex--; + } + } + } + + if (!bFound) { + return E_INVALIDARG; + } + + SelectInput(pNewInputPin); + + if (CComPtr pSSF = pNewInputPin->GetStreamSelectionFilter()) { + pSSF->Enable(i, dwFlags); + } + + ResumeGraph; + + return S_OK; +} diff --git a/src/filters/switcher/AudioSwitcher/StreamSwitcher.h b/src/filters/switcher/AudioSwitcher/StreamSwitcher.h index f2091c515a4..54cdfab6454 100644 --- a/src/filters/switcher/AudioSwitcher/StreamSwitcher.h +++ b/src/filters/switcher/AudioSwitcher/StreamSwitcher.h @@ -1,269 +1,269 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include - -class CStreamSwitcherFilter; - -class CStreamSwitcherPassThru : public IMediaSeeking, public CMediaPosition -{ -protected: - CStreamSwitcherFilter* m_pFilter; - -public: - CStreamSwitcherPassThru(LPUNKNOWN, HRESULT* phr, CStreamSwitcherFilter* pFilter); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IMediaSeeking methods - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, - LONGLONG* pStop, DWORD StopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - - // IMediaPosition properties - STDMETHODIMP get_Duration(REFTIME* plength); - STDMETHODIMP put_CurrentPosition(REFTIME llTime); - STDMETHODIMP get_StopTime(REFTIME* pllTime); - STDMETHODIMP put_StopTime(REFTIME llTime); - STDMETHODIMP get_PrerollTime(REFTIME* pllTime); - STDMETHODIMP put_PrerollTime(REFTIME llTime); - STDMETHODIMP get_Rate(double* pdRate); - STDMETHODIMP put_Rate(double dRate); - STDMETHODIMP get_CurrentPosition(REFTIME* pllTime); - STDMETHODIMP CanSeekForward(LONG* pCanSeekForward); - STDMETHODIMP CanSeekBackward(LONG* pCanSeekBackward); -}; - -class CStreamSwitcherInputPin; - -class CStreamSwitcherAllocator : public CMemAllocator -{ -protected: - CStreamSwitcherInputPin* m_pPin; - - CMediaType m_mt; - bool m_fMediaTypeChanged; - -public: - CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr); -#ifdef _DEBUG - ~CStreamSwitcherAllocator(); -#endif - - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - - STDMETHODIMP GetBuffer( - IMediaSample** ppBuffer, - REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, - DWORD dwFlags); - - void NotifyMediaType(const CMediaType& mt); -}; - -interface __declspec(uuid("DA395FA3-4A3E-4D85-805E-0BEFF53D4BCD")) - IStreamSwitcherInputPin : - public IUnknown -{ - STDMETHOD_(bool, IsActive)() PURE; -}; - -class CStreamSwitcherInputPin : public CBaseInputPin, public IPinConnection, public IStreamSwitcherInputPin -{ - friend class CStreamSwitcherAllocator; - - CStreamSwitcherAllocator m_Allocator; - - BOOL m_bSampleSkipped; - BOOL m_bQualityChanged; - BOOL m_bUsingOwnAllocator; - - CAMEvent m_evBlock; - bool m_fCanBlock; - bool m_bFirstSampleReceived; - HRESULT Active(); - HRESULT Inactive(); - - HRESULT QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt); - - HRESULT InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample); - - HANDLE m_hNotifyEvent; - - CComPtr m_pSSF; - -public: - CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - CMediaType& CurrentMediaType() { return m_mt; } - IMemAllocator* CurrentAllocator() { return m_pAllocator; } - - bool IsUsingOwnAllocator() { return m_bUsingOwnAllocator == TRUE; } - - void Block(bool fBlock); - - CCritSec m_csReceive; - - CComPtr GetStreamSelectionFilter() { return m_pSSF; } - - // pure virtual - HRESULT CheckMediaType(const CMediaType* pmt); - - // virtual - HRESULT CheckConnect(IPin* pPin); - HRESULT CompleteConnect(IPin* pReceivePin); - - // IPin - STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* pmt); - STDMETHODIMP ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator); - STDMETHODIMP NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - STDMETHODIMP EndOfStream(); - - // IMemInputPin - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - - // IPinConnection - STDMETHODIMP DynamicQueryAccept(const AM_MEDIA_TYPE* pmt); - STDMETHODIMP NotifyEndOfStream(HANDLE hNotifyEvent); - STDMETHODIMP IsEndPin(); - STDMETHODIMP DynamicDisconnect(); - - // IStreamSwitcherInputPin - STDMETHODIMP_(bool) IsActive(); -}; - -class CStreamSwitcherOutputPin : public CBaseOutputPin, public IStreamBuilder -{ - CComPtr m_pStreamSwitcherPassThru; - CComPtr m_pPinConnection; - - HRESULT QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt); - -public: - CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - CMediaType& CurrentMediaType() { return m_mt; } - IMemAllocator* CurrentAllocator() { return m_pAllocator; } - IPinConnection* CurrentPinConnection() { return m_pPinConnection; } - - // pure virtual - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - - // virtual - HRESULT CheckConnect(IPin* pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pReceivePin); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - - // IPin - STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* pmt); - - // IQualityControl - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); - - // IStreamBuilder - STDMETHODIMP Render(IPin* ppinOut, IGraphBuilder* pGraph); - STDMETHODIMP Backout(IPin* ppinOut, IGraphBuilder* pGraph); -}; - -class CStreamSwitcherFilter : public CBaseFilter, public IAMStreamSelect -{ - friend class CStreamSwitcherInputPin; - friend class CStreamSwitcherOutputPin; - friend class CStreamSwitcherPassThru; - - CAtlList m_pInputs; - CStreamSwitcherInputPin* m_pInput; - CStreamSwitcherOutputPin* m_pOutput; - - CCritSec m_csState, m_csPins; - - HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin); - -protected: - void SelectInput(CStreamSwitcherInputPin* pInput); - -public: - CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid); - virtual ~CStreamSwitcherFilter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - int GetPinCount(); - CBasePin* GetPin(int n); - - int GetConnectedInputPinCount(); - CStreamSwitcherInputPin* GetConnectedInputPin(int n); - CStreamSwitcherInputPin* GetInputPin(); - CStreamSwitcherOutputPin* GetOutputPin(); - - // override these - virtual HRESULT CheckMediaType(const CMediaType* pmt) = 0; - virtual HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - virtual CMediaType CreateNewOutputMediaType(CMediaType mt, long& cbBuffer); - virtual void OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut) {} - - // and maybe these - virtual HRESULT DeliverEndOfStream(); - virtual HRESULT DeliverBeginFlush(); - virtual HRESULT DeliverEndFlush(); - virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - - // IAMStreamSelect - STDMETHODIMP Count(DWORD* pcStreams); - STDMETHODIMP Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, - LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, - IUnknown** ppObject, IUnknown** ppUnk); - STDMETHODIMP Enable(long lIndex, DWORD dwFlags); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include + +class CStreamSwitcherFilter; + +class CStreamSwitcherPassThru : public IMediaSeeking, public CMediaPosition +{ +protected: + CStreamSwitcherFilter* m_pFilter; + +public: + CStreamSwitcherPassThru(LPUNKNOWN, HRESULT* phr, CStreamSwitcherFilter* pFilter); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IMediaSeeking methods + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, + LONGLONG* pStop, DWORD StopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + + // IMediaPosition properties + STDMETHODIMP get_Duration(REFTIME* plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(REFTIME* pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(REFTIME* pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(double* pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP get_CurrentPosition(REFTIME* pllTime); + STDMETHODIMP CanSeekForward(LONG* pCanSeekForward); + STDMETHODIMP CanSeekBackward(LONG* pCanSeekBackward); +}; + +class CStreamSwitcherInputPin; + +class CStreamSwitcherAllocator : public CMemAllocator +{ +protected: + CStreamSwitcherInputPin* m_pPin; + + CMediaType m_mt; + bool m_fMediaTypeChanged; + +public: + CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr); +#ifdef _DEBUG + ~CStreamSwitcherAllocator(); +#endif + + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + + STDMETHODIMP GetBuffer( + IMediaSample** ppBuffer, + REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, + DWORD dwFlags); + + void NotifyMediaType(const CMediaType& mt); +}; + +interface __declspec(uuid("DA395FA3-4A3E-4D85-805E-0BEFF53D4BCD")) + IStreamSwitcherInputPin : + public IUnknown +{ + STDMETHOD_(bool, IsActive)() PURE; +}; + +class CStreamSwitcherInputPin : public CBaseInputPin, public IPinConnection, public IStreamSwitcherInputPin +{ + friend class CStreamSwitcherAllocator; + + CStreamSwitcherAllocator m_Allocator; + + BOOL m_bSampleSkipped; + BOOL m_bQualityChanged; + BOOL m_bUsingOwnAllocator; + + CAMEvent m_evBlock; + bool m_fCanBlock; + bool m_bFirstSampleReceived; + HRESULT Active(); + HRESULT Inactive(); + + HRESULT QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt); + + HRESULT InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample); + + HANDLE m_hNotifyEvent; + + CComPtr m_pSSF; + +public: + CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + CMediaType& CurrentMediaType() { return m_mt; } + IMemAllocator* CurrentAllocator() { return m_pAllocator; } + + bool IsUsingOwnAllocator() { return m_bUsingOwnAllocator == TRUE; } + + void Block(bool fBlock); + + CCritSec m_csReceive; + + CComPtr GetStreamSelectionFilter() { return m_pSSF; } + + // pure virtual + HRESULT CheckMediaType(const CMediaType* pmt); + + // virtual + HRESULT CheckConnect(IPin* pPin); + HRESULT CompleteConnect(IPin* pReceivePin); + + // IPin + STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* pmt); + STDMETHODIMP ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator); + STDMETHODIMP NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + STDMETHODIMP EndOfStream(); + + // IMemInputPin + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + // IPinConnection + STDMETHODIMP DynamicQueryAccept(const AM_MEDIA_TYPE* pmt); + STDMETHODIMP NotifyEndOfStream(HANDLE hNotifyEvent); + STDMETHODIMP IsEndPin(); + STDMETHODIMP DynamicDisconnect(); + + // IStreamSwitcherInputPin + STDMETHODIMP_(bool) IsActive(); +}; + +class CStreamSwitcherOutputPin : public CBaseOutputPin, public IStreamBuilder +{ + CComPtr m_pStreamSwitcherPassThru; + CComPtr m_pPinConnection; + + HRESULT QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt); + +public: + CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + CMediaType& CurrentMediaType() { return m_mt; } + IMemAllocator* CurrentAllocator() { return m_pAllocator; } + IPinConnection* CurrentPinConnection() { return m_pPinConnection; } + + // pure virtual + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + + // virtual + HRESULT CheckConnect(IPin* pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pReceivePin); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + + // IPin + STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* pmt); + + // IQualityControl + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); + + // IStreamBuilder + STDMETHODIMP Render(IPin* ppinOut, IGraphBuilder* pGraph); + STDMETHODIMP Backout(IPin* ppinOut, IGraphBuilder* pGraph); +}; + +class CStreamSwitcherFilter : public CBaseFilter, public IAMStreamSelect +{ + friend class CStreamSwitcherInputPin; + friend class CStreamSwitcherOutputPin; + friend class CStreamSwitcherPassThru; + + CAtlList m_pInputs; + CStreamSwitcherInputPin* m_pInput; + CStreamSwitcherOutputPin* m_pOutput; + + CCritSec m_csState, m_csPins; + + HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin); + +protected: + void SelectInput(CStreamSwitcherInputPin* pInput); + +public: + CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid); + virtual ~CStreamSwitcherFilter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + int GetPinCount(); + CBasePin* GetPin(int n); + + int GetConnectedInputPinCount(); + CStreamSwitcherInputPin* GetConnectedInputPin(int n); + CStreamSwitcherInputPin* GetInputPin(); + CStreamSwitcherOutputPin* GetOutputPin(); + + // override these + virtual HRESULT CheckMediaType(const CMediaType* pmt) = 0; + virtual HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + virtual CMediaType CreateNewOutputMediaType(CMediaType mt, long& cbBuffer); + virtual void OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut) {} + + // and maybe these + virtual HRESULT DeliverEndOfStream(); + virtual HRESULT DeliverBeginFlush(); + virtual HRESULT DeliverEndFlush(); + virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + // IAMStreamSelect + STDMETHODIMP Count(DWORD* pcStreams); + STDMETHODIMP Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, + LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, + IUnknown** ppObject, IUnknown** ppUnk); + STDMETHODIMP Enable(long lIndex, DWORD dwFlags); +}; diff --git a/src/filters/switcher/AudioSwitcher/resource.h b/src/filters/switcher/AudioSwitcher/resource.h index 7eb4f1a1480..2b00562fdee 100644 --- a/src/filters/switcher/AudioSwitcher/resource.h +++ b/src/filters/switcher/AudioSwitcher/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by AudioSwitcher.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by AudioSwitcher.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/switcher/AudioSwitcher/stdafx.cpp b/src/filters/switcher/AudioSwitcher/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/switcher/AudioSwitcher/stdafx.cpp +++ b/src/filters/switcher/AudioSwitcher/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/switcher/AudioSwitcher/stdafx.h b/src/filters/switcher/AudioSwitcher/stdafx.h index 0406bee9e05..f0c534cd5b2 100644 --- a/src/filters/switcher/AudioSwitcher/stdafx.h +++ b/src/filters/switcher/AudioSwitcher/stdafx.h @@ -1,36 +1,36 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include - -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include + +#include diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.cpp b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.cpp index fd99fcda64b..3aad88550e7 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.cpp +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.cpp @@ -1,512 +1,512 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "AVI2AC3Filter.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DOLBY_AC3}, - {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DTS}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CAVI2AC3Filter), AVI2AC3FilterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CAVI2AC3Filter -// - -CAVI2AC3Filter::CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr) - : CTransformFilter(NAME("CAVI2AC3Filter"), lpunk, __uuidof(this)) -{ - if (phr) { - *phr = S_OK; - } -} - -CAVI2AC3Filter::~CAVI2AC3Filter() -{ -} - -HRESULT CAVI2AC3Filter::Transform(IMediaSample* pSample, IMediaSample* pOutSample) -{ - HRESULT hr; - - BYTE* pIn = nullptr; - if (FAILED(hr = pSample->GetPointer(&pIn))) { - return hr; - } - BYTE* pInOrg = pIn; - - long len = pSample->GetActualDataLength(); - if (len <= 0) { - return S_FALSE; - } - - BYTE* pOut = nullptr; - if (FAILED(hr = pOutSample->GetPointer(&pOut))) { - return hr; - } - BYTE* pOutOrg = pOut; - - long size = pOutSample->GetSize(); - - if ((CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) - && (CheckWAVEAC3(&m_pOutput->CurrentMediaType()) || CheckWAVEDTS(&m_pOutput->CurrentMediaType()))) { - if (*(DWORD*)pIn == 0xBA010000) { - pIn += 14; - } - - if (*(DWORD*)pIn == 0xBD010000) { - pIn += 8 + 1 + pIn[8] + 1 + 3; - } - - len -= long(pInOrg - pIn); - - if (size < len) { - return E_FAIL; - } - - memcpy(pOut, pIn, len); - pOut += len; - } else if ((CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) - && (CheckAC3(&m_pOutput->CurrentMediaType()) || CheckDTS(&m_pOutput->CurrentMediaType()))) { - if ((m_pOutput->CurrentMediaType().majortype == MEDIATYPE_DVD_ENCRYPTED_PACK - || m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES) - && (len + 12 + 3) >= 0x10000) { // damn, this can happen if the interleave time is too big - REFERENCE_TIME rtStart = 0, rtStop = 1; - bool fHasTime = (S_OK == pSample->GetTime(&rtStart, &rtStop)); - - bool fDiscontinuity = (S_OK == pOutSample->IsDiscontinuity()); - - long pos = 0; - while (pos < len) { - int curlen = std::min(len - pos, 2013l); - pos += 2013; - - CComPtr pNewOutSample; - hr = InitializeOutputSample(pSample, &pNewOutSample); - - if (fDiscontinuity) { - if (fHasTime) { - rtStop = rtStart + (rtStop - rtStart) * curlen / len; - pNewOutSample->SetTime(&rtStart, &rtStop); - } - - fDiscontinuity = false; - } else { - pNewOutSample->SetTime(nullptr, nullptr); - pNewOutSample->SetDiscontinuity(FALSE); - } - - BYTE* pNewOut = nullptr; - if (FAILED(hr = pNewOutSample->GetPointer(&pNewOut))) { - return hr; - } - BYTE* pNewOutOrg = pNewOut; - - long newSize = pNewOutSample->GetSize(); - - const GUID* majortype = &m_pOutput->CurrentMediaType().majortype; - const GUID* subtype = &m_pOutput->CurrentMediaType().subtype; - - if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { - if (newSize < curlen + 32 + 3) { - return E_FAIL; - } - - BYTE PESHeader[] = { - 0x00, 0x00, 0x01, 0xBA, // PES id - 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0) - 0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits) - }; - - memcpy(pNewOut, &PESHeader, sizeof(PESHeader)); - pNewOut += sizeof(PESHeader); - - majortype = &MEDIATYPE_MPEG2_PES; - } - - if (*majortype == MEDIATYPE_MPEG2_PES) { - if (newSize < curlen + 20 + 3) { - return E_FAIL; - } - - BYTE Private1Header[] = { - 0x00, 0x00, 0x01, 0xBD, // private stream 1 id - 0x07, 0xEC, // packet length (TODO: modify it later) - 0x81, 0x80, // marker, original, PTS - flags - 0x08, // packet data starting offset - 0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0) - 0xFF, 0xFF, 0xFF, // stuffing - 0x80, // stream id (0) - 0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back) - }; - - int packetlen = curlen + 12 + 3; - ASSERT(packetlen <= 0xffff); - Private1Header[4] = (packetlen >> 8) & 0xff; - Private1Header[5] = packetlen & 0xff; - - if (*subtype == MEDIASUBTYPE_DTS) { - Private1Header[17] += 8; - } - - if (*subtype == MEDIASUBTYPE_DOLBY_AC3) { - for (int i = 0; i < curlen; i++) { - if (*(DWORD*)&pIn[i] == 0x770B) { - i++; - Private1Header[19] = (i >> 8) & 0xff; - Private1Header[20] = i & 0xff; - break; - } - } - } else if (*subtype == MEDIASUBTYPE_DTS) { - for (int i = 0; i < curlen; i++) { - if (*(DWORD*)&pIn[i] == 0x0180FE7F) { - i++; - Private1Header[19] = (i >> 8) & 0xff; - Private1Header[20] = i & 0xff; - break; - } - } - } - - memcpy(pNewOut, &Private1Header, sizeof(Private1Header)); - pNewOut += sizeof(Private1Header); - - majortype = &MEDIATYPE_Audio; - } - - if (*majortype == MEDIATYPE_Audio) { - if (newSize < curlen) { - return E_FAIL; - } - memcpy(pNewOut, pIn, curlen); - pIn += curlen; - pNewOut += curlen; - } - - pNewOutSample->SetActualDataLength(long(pNewOut - pNewOutOrg)); - - m_pOutput->Deliver(pNewOutSample); - } - - return S_FALSE; - } else { // phew, we can do the easier way - const GUID* majortype = &m_pOutput->CurrentMediaType().majortype; - const GUID* subtype = &m_pOutput->CurrentMediaType().subtype; - - if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { - if (size < len + 32 + 3) { - return E_FAIL; - } - - BYTE PESHeader[] = { - 0x00, 0x00, 0x01, 0xBA, // PES id - 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0) - 0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits) - }; - - memcpy(pOut, &PESHeader, sizeof(PESHeader)); - pOut += sizeof(PESHeader); - - majortype = &MEDIATYPE_MPEG2_PES; - } - - if (*majortype == MEDIATYPE_MPEG2_PES) { - if (size < len + 20 + 3) { - return E_FAIL; - } - - BYTE Private1Header[] = { - 0x00, 0x00, 0x01, 0xBD, // private stream 1 id - 0x07, 0xEC, // packet length (TODO: modify it later) - 0x81, 0x80, // marker, original, PTS - flags - 0x08, // packet data starting offset - 0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0) - 0xFF, 0xFF, 0xFF, // stuffing - 0x80, // stream id (0) - 0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back) - }; - - int packetlen = len + 12 + 3; - ASSERT(packetlen <= 0xffff); - Private1Header[4] = (packetlen >> 8) & 0xff; - Private1Header[5] = packetlen & 0xff; - - if (*subtype == MEDIASUBTYPE_DTS) { - Private1Header[17] += 8; - } - - memcpy(pOut, &Private1Header, sizeof(Private1Header)); - pOut += sizeof(Private1Header); - - majortype = &MEDIATYPE_Audio; - } - - if (*majortype == MEDIATYPE_Audio) { - if (size < len) { - return E_FAIL; - } - - memcpy(pOut, pIn, len); - pIn += len; - pOut += len; - } - } - } else { - return E_FAIL; - } - - pOutSample->SetActualDataLength(int(pOut - pOutOrg)); - - return S_OK; -} - -bool CAVI2AC3Filter::CheckAC3(const CMediaType* pmt) -{ - return (pmt->majortype == MEDIATYPE_Audio - || pmt->majortype == MEDIATYPE_MPEG2_PES - || pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) - && pmt->subtype == MEDIASUBTYPE_DOLBY_AC3; -} - -bool CAVI2AC3Filter::CheckDTS(const CMediaType* pmt) -{ - return (pmt->majortype == MEDIATYPE_Audio - || pmt->majortype == MEDIATYPE_MPEG2_PES - || pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) - && pmt->subtype == MEDIASUBTYPE_DTS; -} - -bool CAVI2AC3Filter::CheckWAVEAC3(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Audio - && pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 - && pmt->formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3; -} - -bool CAVI2AC3Filter::CheckWAVEDTS(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Audio - && pmt->subtype == MEDIASUBTYPE_WAVE_DTS - && pmt->formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS; -} - -HRESULT CAVI2AC3Filter::CheckInputType(const CMediaType* mtIn) -{ - bool fWaveFormatEx = !!(mtIn->formattype == FORMAT_WaveFormatEx); - - return CheckAC3(mtIn) && fWaveFormatEx || CheckDTS(mtIn) && fWaveFormatEx - || CheckWAVEAC3(mtIn) || CheckWAVEDTS(mtIn) - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CAVI2AC3Filter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return CheckAC3(mtIn) && CheckWAVEAC3(mtOut) - || CheckWAVEAC3(mtIn) && CheckAC3(mtOut) - || CheckDTS(mtIn) && CheckWAVEDTS(mtOut) - || CheckWAVEDTS(mtIn) && CheckDTS(mtOut) - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CAVI2AC3Filter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - CComPtr pAllocatorIn; - m_pInput->GetAllocator(&pAllocatorIn); - if (!pAllocatorIn) { - return E_UNEXPECTED; - } - - pAllocatorIn->GetProperties(pProperties); - - pProperties->cBuffers = 2; - pProperties->cbBuffer = std::max(pProperties->cbBuffer, 1024l * 1024l); // this should be enough... - pProperties->cbAlign = 1; - pProperties->cbPrefix = 0; - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -HRESULT CAVI2AC3Filter::GetMediaType(int iPosition, CMediaType* pMediaType) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - const GUID& majortype = m_pInput->CurrentMediaType().majortype; - const GUID& subtype = m_pInput->CurrentMediaType().subtype; - UNREFERENCED_PARAMETER(majortype); - - if (CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) { - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - pMediaType->majortype = MEDIATYPE_Audio; - - pMediaType->formattype = FORMAT_WaveFormatEx; - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX)); - ZeroMemory(wfe, sizeof(WAVEFORMATEX)); - wfe->cbSize = sizeof(WAVEFORMATEX); - wfe->nAvgBytesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nAvgBytesPerSec; - wfe->nSamplesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nSamplesPerSec; - wfe->wBitsPerSample = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->wBitsPerSample; - wfe->nChannels = 2; - wfe->nBlockAlign = 1; - - if (subtype == MEDIASUBTYPE_DOLBY_AC3) { - pMediaType->subtype = MEDIASUBTYPE_WAVE_DOLBY_AC3; - wfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3; - } else if (subtype == MEDIASUBTYPE_DTS) { - pMediaType->subtype = MEDIASUBTYPE_WAVE_DTS; - wfe->wFormatTag = WAVE_FORMAT_DVD_DTS; - } else { - return E_INVALIDARG; - } - } else if (CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) { - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 4) { - return VFW_S_NO_MORE_ITEMS; - } - - if (subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3) { - pMediaType->subtype = MEDIASUBTYPE_DOLBY_AC3; - - pMediaType->formattype = FORMAT_WaveFormatEx; - DOLBYAC3WAVEFORMAT* wfe = (DOLBYAC3WAVEFORMAT*)pMediaType->AllocFormatBuffer(sizeof(DOLBYAC3WAVEFORMAT)); - ZeroMemory(wfe, sizeof(DOLBYAC3WAVEFORMAT)); - // unfortunately we can't tell what we are going to get in transform, - // so we just set the most common values and hope that the ac3 decoder - // is flexible enough (it is usually :) to find out these from the bitstream - wfe->wfx.cbSize = sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX); - wfe->wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3; - wfe->wfx.nSamplesPerSec = 48000; - wfe->wfx.nChannels = 6; - wfe->bBigEndian = TRUE; - } else if (subtype == MEDIASUBTYPE_WAVE_DTS) { - pMediaType->subtype = MEDIASUBTYPE_DTS; - - pMediaType->formattype = FORMAT_WaveFormatEx; - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX)); - ZeroMemory(wfe, sizeof(WAVEFORMATEX)); - // same case as with ac3, but this time we don't even know the structure - wfe->cbSize = sizeof(WAVEFORMATEX); - wfe->wFormatTag = WAVE_FORMAT_PCM; - wfe->nSamplesPerSec = 48000; - wfe->nChannels = 6; - } else { - return E_INVALIDARG; - } - - switch (iPosition) { - case 0: - pMediaType->majortype = MEDIATYPE_Audio; - break; - case 1: - pMediaType->ResetFormatBuffer(); - pMediaType->formattype = FORMAT_None; - // no break - case 2: - pMediaType->majortype = MEDIATYPE_MPEG2_PES; - break; - case 3: - pMediaType->ResetFormatBuffer(); - pMediaType->formattype = FORMAT_None; - // no break - case 4: - pMediaType->majortype = MEDIATYPE_DVD_ENCRYPTED_PACK; - break; - default: - ASSERT(FALSE); // Shouldn't happen - return E_INVALIDARG; - } - } else { - return VFW_S_NO_MORE_ITEMS; - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "AVI2AC3Filter.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DOLBY_AC3}, + {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DTS}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CAVI2AC3Filter), AVI2AC3FilterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CAVI2AC3Filter +// + +CAVI2AC3Filter::CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr) + : CTransformFilter(NAME("CAVI2AC3Filter"), lpunk, __uuidof(this)) +{ + if (phr) { + *phr = S_OK; + } +} + +CAVI2AC3Filter::~CAVI2AC3Filter() +{ +} + +HRESULT CAVI2AC3Filter::Transform(IMediaSample* pSample, IMediaSample* pOutSample) +{ + HRESULT hr; + + BYTE* pIn = nullptr; + if (FAILED(hr = pSample->GetPointer(&pIn))) { + return hr; + } + BYTE* pInOrg = pIn; + + long len = pSample->GetActualDataLength(); + if (len <= 0) { + return S_FALSE; + } + + BYTE* pOut = nullptr; + if (FAILED(hr = pOutSample->GetPointer(&pOut))) { + return hr; + } + BYTE* pOutOrg = pOut; + + long size = pOutSample->GetSize(); + + if ((CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) + && (CheckWAVEAC3(&m_pOutput->CurrentMediaType()) || CheckWAVEDTS(&m_pOutput->CurrentMediaType()))) { + if (*(DWORD*)pIn == 0xBA010000) { + pIn += 14; + } + + if (*(DWORD*)pIn == 0xBD010000) { + pIn += 8 + 1 + pIn[8] + 1 + 3; + } + + len -= long(pInOrg - pIn); + + if (size < len) { + return E_FAIL; + } + + memcpy(pOut, pIn, len); + pOut += len; + } else if ((CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) + && (CheckAC3(&m_pOutput->CurrentMediaType()) || CheckDTS(&m_pOutput->CurrentMediaType()))) { + if ((m_pOutput->CurrentMediaType().majortype == MEDIATYPE_DVD_ENCRYPTED_PACK + || m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES) + && (len + 12 + 3) >= 0x10000) { // damn, this can happen if the interleave time is too big + REFERENCE_TIME rtStart = 0, rtStop = 1; + bool fHasTime = (S_OK == pSample->GetTime(&rtStart, &rtStop)); + + bool fDiscontinuity = (S_OK == pOutSample->IsDiscontinuity()); + + long pos = 0; + while (pos < len) { + int curlen = std::min(len - pos, 2013l); + pos += 2013; + + CComPtr pNewOutSample; + hr = InitializeOutputSample(pSample, &pNewOutSample); + + if (fDiscontinuity) { + if (fHasTime) { + rtStop = rtStart + (rtStop - rtStart) * curlen / len; + pNewOutSample->SetTime(&rtStart, &rtStop); + } + + fDiscontinuity = false; + } else { + pNewOutSample->SetTime(nullptr, nullptr); + pNewOutSample->SetDiscontinuity(FALSE); + } + + BYTE* pNewOut = nullptr; + if (FAILED(hr = pNewOutSample->GetPointer(&pNewOut))) { + return hr; + } + BYTE* pNewOutOrg = pNewOut; + + long newSize = pNewOutSample->GetSize(); + + const GUID* majortype = &m_pOutput->CurrentMediaType().majortype; + const GUID* subtype = &m_pOutput->CurrentMediaType().subtype; + + if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { + if (newSize < curlen + 32 + 3) { + return E_FAIL; + } + + BYTE PESHeader[] = { + 0x00, 0x00, 0x01, 0xBA, // PES id + 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0) + 0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits) + }; + + memcpy(pNewOut, &PESHeader, sizeof(PESHeader)); + pNewOut += sizeof(PESHeader); + + majortype = &MEDIATYPE_MPEG2_PES; + } + + if (*majortype == MEDIATYPE_MPEG2_PES) { + if (newSize < curlen + 20 + 3) { + return E_FAIL; + } + + BYTE Private1Header[] = { + 0x00, 0x00, 0x01, 0xBD, // private stream 1 id + 0x07, 0xEC, // packet length (TODO: modify it later) + 0x81, 0x80, // marker, original, PTS - flags + 0x08, // packet data starting offset + 0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0) + 0xFF, 0xFF, 0xFF, // stuffing + 0x80, // stream id (0) + 0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back) + }; + + int packetlen = curlen + 12 + 3; + ASSERT(packetlen <= 0xffff); + Private1Header[4] = (packetlen >> 8) & 0xff; + Private1Header[5] = packetlen & 0xff; + + if (*subtype == MEDIASUBTYPE_DTS) { + Private1Header[17] += 8; + } + + if (*subtype == MEDIASUBTYPE_DOLBY_AC3) { + for (int i = 0; i < curlen; i++) { + if (*(DWORD*)&pIn[i] == 0x770B) { + i++; + Private1Header[19] = (i >> 8) & 0xff; + Private1Header[20] = i & 0xff; + break; + } + } + } else if (*subtype == MEDIASUBTYPE_DTS) { + for (int i = 0; i < curlen; i++) { + if (*(DWORD*)&pIn[i] == 0x0180FE7F) { + i++; + Private1Header[19] = (i >> 8) & 0xff; + Private1Header[20] = i & 0xff; + break; + } + } + } + + memcpy(pNewOut, &Private1Header, sizeof(Private1Header)); + pNewOut += sizeof(Private1Header); + + majortype = &MEDIATYPE_Audio; + } + + if (*majortype == MEDIATYPE_Audio) { + if (newSize < curlen) { + return E_FAIL; + } + memcpy(pNewOut, pIn, curlen); + pIn += curlen; + pNewOut += curlen; + } + + pNewOutSample->SetActualDataLength(long(pNewOut - pNewOutOrg)); + + m_pOutput->Deliver(pNewOutSample); + } + + return S_FALSE; + } else { // phew, we can do the easier way + const GUID* majortype = &m_pOutput->CurrentMediaType().majortype; + const GUID* subtype = &m_pOutput->CurrentMediaType().subtype; + + if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { + if (size < len + 32 + 3) { + return E_FAIL; + } + + BYTE PESHeader[] = { + 0x00, 0x00, 0x01, 0xBA, // PES id + 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0) + 0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits) + }; + + memcpy(pOut, &PESHeader, sizeof(PESHeader)); + pOut += sizeof(PESHeader); + + majortype = &MEDIATYPE_MPEG2_PES; + } + + if (*majortype == MEDIATYPE_MPEG2_PES) { + if (size < len + 20 + 3) { + return E_FAIL; + } + + BYTE Private1Header[] = { + 0x00, 0x00, 0x01, 0xBD, // private stream 1 id + 0x07, 0xEC, // packet length (TODO: modify it later) + 0x81, 0x80, // marker, original, PTS - flags + 0x08, // packet data starting offset + 0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0) + 0xFF, 0xFF, 0xFF, // stuffing + 0x80, // stream id (0) + 0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back) + }; + + int packetlen = len + 12 + 3; + ASSERT(packetlen <= 0xffff); + Private1Header[4] = (packetlen >> 8) & 0xff; + Private1Header[5] = packetlen & 0xff; + + if (*subtype == MEDIASUBTYPE_DTS) { + Private1Header[17] += 8; + } + + memcpy(pOut, &Private1Header, sizeof(Private1Header)); + pOut += sizeof(Private1Header); + + majortype = &MEDIATYPE_Audio; + } + + if (*majortype == MEDIATYPE_Audio) { + if (size < len) { + return E_FAIL; + } + + memcpy(pOut, pIn, len); + pIn += len; + pOut += len; + } + } + } else { + return E_FAIL; + } + + pOutSample->SetActualDataLength(int(pOut - pOutOrg)); + + return S_OK; +} + +bool CAVI2AC3Filter::CheckAC3(const CMediaType* pmt) +{ + return (pmt->majortype == MEDIATYPE_Audio + || pmt->majortype == MEDIATYPE_MPEG2_PES + || pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) + && pmt->subtype == MEDIASUBTYPE_DOLBY_AC3; +} + +bool CAVI2AC3Filter::CheckDTS(const CMediaType* pmt) +{ + return (pmt->majortype == MEDIATYPE_Audio + || pmt->majortype == MEDIATYPE_MPEG2_PES + || pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) + && pmt->subtype == MEDIASUBTYPE_DTS; +} + +bool CAVI2AC3Filter::CheckWAVEAC3(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Audio + && pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 + && pmt->formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3; +} + +bool CAVI2AC3Filter::CheckWAVEDTS(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Audio + && pmt->subtype == MEDIASUBTYPE_WAVE_DTS + && pmt->formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS; +} + +HRESULT CAVI2AC3Filter::CheckInputType(const CMediaType* mtIn) +{ + bool fWaveFormatEx = !!(mtIn->formattype == FORMAT_WaveFormatEx); + + return CheckAC3(mtIn) && fWaveFormatEx || CheckDTS(mtIn) && fWaveFormatEx + || CheckWAVEAC3(mtIn) || CheckWAVEDTS(mtIn) + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CAVI2AC3Filter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return CheckAC3(mtIn) && CheckWAVEAC3(mtOut) + || CheckWAVEAC3(mtIn) && CheckAC3(mtOut) + || CheckDTS(mtIn) && CheckWAVEDTS(mtOut) + || CheckWAVEDTS(mtIn) && CheckDTS(mtOut) + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CAVI2AC3Filter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + CComPtr pAllocatorIn; + m_pInput->GetAllocator(&pAllocatorIn); + if (!pAllocatorIn) { + return E_UNEXPECTED; + } + + pAllocatorIn->GetProperties(pProperties); + + pProperties->cBuffers = 2; + pProperties->cbBuffer = std::max(pProperties->cbBuffer, 1024l * 1024l); // this should be enough... + pProperties->cbAlign = 1; + pProperties->cbPrefix = 0; + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +HRESULT CAVI2AC3Filter::GetMediaType(int iPosition, CMediaType* pMediaType) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + const GUID& majortype = m_pInput->CurrentMediaType().majortype; + const GUID& subtype = m_pInput->CurrentMediaType().subtype; + UNREFERENCED_PARAMETER(majortype); + + if (CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) { + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + pMediaType->majortype = MEDIATYPE_Audio; + + pMediaType->formattype = FORMAT_WaveFormatEx; + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX)); + ZeroMemory(wfe, sizeof(WAVEFORMATEX)); + wfe->cbSize = sizeof(WAVEFORMATEX); + wfe->nAvgBytesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nAvgBytesPerSec; + wfe->nSamplesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nSamplesPerSec; + wfe->wBitsPerSample = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->wBitsPerSample; + wfe->nChannels = 2; + wfe->nBlockAlign = 1; + + if (subtype == MEDIASUBTYPE_DOLBY_AC3) { + pMediaType->subtype = MEDIASUBTYPE_WAVE_DOLBY_AC3; + wfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3; + } else if (subtype == MEDIASUBTYPE_DTS) { + pMediaType->subtype = MEDIASUBTYPE_WAVE_DTS; + wfe->wFormatTag = WAVE_FORMAT_DVD_DTS; + } else { + return E_INVALIDARG; + } + } else if (CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) { + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 4) { + return VFW_S_NO_MORE_ITEMS; + } + + if (subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3) { + pMediaType->subtype = MEDIASUBTYPE_DOLBY_AC3; + + pMediaType->formattype = FORMAT_WaveFormatEx; + DOLBYAC3WAVEFORMAT* wfe = (DOLBYAC3WAVEFORMAT*)pMediaType->AllocFormatBuffer(sizeof(DOLBYAC3WAVEFORMAT)); + ZeroMemory(wfe, sizeof(DOLBYAC3WAVEFORMAT)); + // unfortunately we can't tell what we are going to get in transform, + // so we just set the most common values and hope that the ac3 decoder + // is flexible enough (it is usually :) to find out these from the bitstream + wfe->wfx.cbSize = sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX); + wfe->wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3; + wfe->wfx.nSamplesPerSec = 48000; + wfe->wfx.nChannels = 6; + wfe->bBigEndian = TRUE; + } else if (subtype == MEDIASUBTYPE_WAVE_DTS) { + pMediaType->subtype = MEDIASUBTYPE_DTS; + + pMediaType->formattype = FORMAT_WaveFormatEx; + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX)); + ZeroMemory(wfe, sizeof(WAVEFORMATEX)); + // same case as with ac3, but this time we don't even know the structure + wfe->cbSize = sizeof(WAVEFORMATEX); + wfe->wFormatTag = WAVE_FORMAT_PCM; + wfe->nSamplesPerSec = 48000; + wfe->nChannels = 6; + } else { + return E_INVALIDARG; + } + + switch (iPosition) { + case 0: + pMediaType->majortype = MEDIATYPE_Audio; + break; + case 1: + pMediaType->ResetFormatBuffer(); + pMediaType->formattype = FORMAT_None; + // no break + case 2: + pMediaType->majortype = MEDIATYPE_MPEG2_PES; + break; + case 3: + pMediaType->ResetFormatBuffer(); + pMediaType->formattype = FORMAT_None; + // no break + case 4: + pMediaType->majortype = MEDIATYPE_DVD_ENCRYPTED_PACK; + break; + default: + ASSERT(FALSE); // Shouldn't happen + return E_INVALIDARG; + } + } else { + return VFW_S_NO_MORE_ITEMS; + } + + return S_OK; +} diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.def b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.def +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.h b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.h index 59a889845a3..421c7a4f3bc 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.h +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.h @@ -1,67 +1,67 @@ -/* - * (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 . - * - */ - -#pragma once - -#define AVI2AC3FilterName L"MPC-HC AVI<->AC3/DTS" - -/* AC3 audio - - wFormatTag WAVE_FORMAT_DOLBY_AC3 - nChannels 1 -6 channels valid - nSamplesPerSec 48000, 44100, 32000 - nAvgByesPerSec 4000 to 80000 - nBlockAlign 128 - 3840 - wBitsPerSample Up to 24 bits - (in the original) - -*/ - -typedef struct tagDOLBYAC3WAVEFORMAT { - WAVEFORMATEX wfx; - BYTE bBigEndian; // TRUE = Big Endian, FALSE little endian - BYTE bsid; - BYTE lfeon; - BYTE copyrightb; - BYTE nAuxBitsCode; // Aux bits per frame -} DOLBYAC3WAVEFORMAT; - -// -// CAVI2AC3Filter -// - -class __declspec(uuid("93230DD0-7B3C-4efb-AFBB-DC380FEC9E6B")) - CAVI2AC3Filter : public CTransformFilter -{ - bool CheckAC3(const CMediaType* pmt); - bool CheckDTS(const CMediaType* pmt); - bool CheckWAVEAC3(const CMediaType* pmt); - bool CheckWAVEDTS(const CMediaType* pmt); - -public: - CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr); - virtual ~CAVI2AC3Filter(); - - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); -}; +/* + * (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 . + * + */ + +#pragma once + +#define AVI2AC3FilterName L"MPC-HC AVI<->AC3/DTS" + +/* AC3 audio + + wFormatTag WAVE_FORMAT_DOLBY_AC3 + nChannels 1 -6 channels valid + nSamplesPerSec 48000, 44100, 32000 + nAvgByesPerSec 4000 to 80000 + nBlockAlign 128 - 3840 + wBitsPerSample Up to 24 bits - (in the original) + +*/ + +typedef struct tagDOLBYAC3WAVEFORMAT { + WAVEFORMATEX wfx; + BYTE bBigEndian; // TRUE = Big Endian, FALSE little endian + BYTE bsid; + BYTE lfeon; + BYTE copyrightb; + BYTE nAuxBitsCode; // Aux bits per frame +} DOLBYAC3WAVEFORMAT; + +// +// CAVI2AC3Filter +// + +class __declspec(uuid("93230DD0-7B3C-4efb-AFBB-DC380FEC9E6B")) + CAVI2AC3Filter : public CTransformFilter +{ + bool CheckAC3(const CMediaType* pmt); + bool CheckDTS(const CMediaType* pmt); + bool CheckWAVEAC3(const CMediaType* pmt); + bool CheckWAVEDTS(const CMediaType* pmt); + +public: + CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr); + virtual ~CAVI2AC3Filter(); + + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); +}; diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.rc b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.rc index f61dca6467c..00e54d563e1 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.rc +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "AVI <-> AC3/DTS Converter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "AVI2AC3Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "AVI2AC3Filter.ax" - VALUE "ProductName", "AVI2AC3Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "AVI <-> AC3/DTS Converter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "AVI2AC3Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "AVI2AC3Filter.ax" + VALUE "ProductName", "AVI2AC3Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj index c3ca52f5a34..36f594b9a94 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj @@ -1,114 +1,114 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {339A4575-E25B-45D6-94A1-D835891740B8} - AVI2AC3Filter - MFCProj - AVI2AC3Filter - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - AVI2AC3Filter.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {339A4575-E25B-45D6-94A1-D835891740B8} + AVI2AC3Filter + MFCProj + AVI2AC3Filter + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + AVI2AC3Filter.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj.filters b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj.filters index 801dac2147f..b865009bdf5 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj.filters +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {00cf5f87-ccb3-495d-aa71-5c96741443af} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {315d7e31-e679-4814-b1b1-291189683016} - h;hpp;hxx;hm;inl;inc - - - {f2e1cd40-0b89-445b-b583-0220959f7205} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {00cf5f87-ccb3-495d-aa71-5c96741443af} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {315d7e31-e679-4814-b1b1-291189683016} + h;hpp;hxx;hm;inl;inc + + + {f2e1cd40-0b89-445b-b583-0220959f7205} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/transform/AVI2AC3Filter/resource.h b/src/filters/transform/AVI2AC3Filter/resource.h index fba14bf5a69..e24ec65f345 100644 --- a/src/filters/transform/AVI2AC3Filter/resource.h +++ b/src/filters/transform/AVI2AC3Filter/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by AVI2AC3Filter.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by AVI2AC3Filter.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/transform/AVI2AC3Filter/stdafx.cpp b/src/filters/transform/AVI2AC3Filter/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/transform/AVI2AC3Filter/stdafx.cpp +++ b/src/filters/transform/AVI2AC3Filter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/transform/AVI2AC3Filter/stdafx.h b/src/filters/transform/AVI2AC3Filter/stdafx.h index d8320f2c878..12bbe2db0a7 100644 --- a/src/filters/transform/AVI2AC3Filter/stdafx.h +++ b/src/filters/transform/AVI2AC3Filter/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/transform/BufferFilter/BufferFilter.cpp b/src/filters/transform/BufferFilter/BufferFilter.cpp index 1ccb796508f..392f69e55ef 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.cpp +++ b/src/filters/transform/BufferFilter/BufferFilter.cpp @@ -1,372 +1,372 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "BufferFilter.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CBufferFilter), BufferFilterName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CBufferFilter -// - -CBufferFilter::CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr) - : CTransformFilter(NAME("CBufferFilter"), lpunk, __uuidof(this)) - , m_nSamplesToBuffer(2) -{ - HRESULT hr = S_OK; - - do { - m_pInput = DEBUG_NEW CTransformInputPin(NAME("Transform input pin"), this, &hr, L"In"); - if (!m_pInput) { - hr = E_OUTOFMEMORY; - } - if (FAILED(hr)) { - break; - } - - m_pOutput = DEBUG_NEW CBufferFilterOutputPin(this, &hr); - if (!m_pOutput) { - hr = E_OUTOFMEMORY; - } - if (FAILED(hr)) { - delete m_pInput; - m_pInput = nullptr; - break; - } - } while (false); - - if (phr) { - *phr = hr; - } -} - -CBufferFilter::~CBufferFilter() -{ -} - -STDMETHODIMP CBufferFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IBufferFilter) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IBufferFilter - -STDMETHODIMP CBufferFilter::SetBuffers(int nBuffers) -{ - if (!m_pOutput) { - return E_FAIL; - } - - if (m_pOutput->IsConnected()) { // TODO: allow "on-the-fly" changes - return VFW_E_ALREADY_CONNECTED; - } - - m_nSamplesToBuffer = nBuffers; - - return S_OK; -} - -STDMETHODIMP_(int) CBufferFilter::GetBuffers() -{ - return m_nSamplesToBuffer; -} - -STDMETHODIMP_(int) CBufferFilter::GetFreeBuffers() -{ - CBufferFilterOutputPin* pPin = static_cast(m_pOutput); - return (pPin && pPin->m_pOutputQueue ? (m_nSamplesToBuffer - pPin->m_pOutputQueue->GetQueueCount()) : 0); -} - -STDMETHODIMP CBufferFilter::SetPriority(DWORD dwPriority) -{ - CBufferFilterOutputPin* pPin = static_cast(m_pOutput); - return (pPin && pPin->m_pOutputQueue ? (pPin->m_pOutputQueue->SetPriority(dwPriority) ? S_OK : E_FAIL) : E_UNEXPECTED); -} - -// - -HRESULT CBufferFilter::Receive(IMediaSample* pSample) -{ - ASSERT(pSample); - CheckPointer(pSample, E_POINTER); - ASSERT(m_pOutput); - CheckPointer(m_pOutput, E_POINTER); - - /* Check for other streams and pass them on */ - AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps(); - if (pProps->dwStreamId != AM_STREAM_MEDIA) { - return m_pOutput->Deliver(pSample); - } - - HRESULT hr; - IMediaSample* pOutSample; - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - // Start timing the transform (if PERF is defined) - MSR_START(m_idTransform); - - // have the derived class transform the data - - hr = Transform(pSample, pOutSample); - - // Stop the clock and log it (if PERF is defined) - MSR_STOP(m_idTransform); - - if (FAILED(hr)) { - DbgLog((LOG_TRACE, 1, _T("Error from transform"))); - } else { - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pOutSample); - m_bSampleSkipped = FALSE; // last thing no longer dropped - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this cause because returning S_FALSE - // from Receive() means that this is the end of the stream and no more data should - // be sent. - if (S_FALSE == hr) { - - // Release the sample before calling notify to avoid - // deadlocks if the sample holds a lock on the system - // such as DirectDraw buffers do - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - NotifyEvent(EC_QUALITY_CHANGE, 0, 0); - m_bQualityChanged = TRUE; - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - - return hr; -} - -HRESULT CBufferFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - BYTE* pDataIn = nullptr; - BYTE* pDataOut = nullptr; - - long len = pIn->GetActualDataLength(); - long size = pOut->GetSize(); - - if (FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn || FAILED(pOut->GetPointer(&pDataOut)) || !pDataOut - || len > size || len <= 0) { - return S_FALSE; - } - - memcpy(pDataOut, pDataIn, std::min(len, size)); - - pOut->SetActualDataLength(std::min(len, size)); - - return S_OK; -} - -HRESULT CBufferFilter::CheckInputType(const CMediaType* mtIn) -{ - return S_OK; -} - -HRESULT CBufferFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return mtIn->MatchesPartial(mtOut) ? S_OK : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CBufferFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - CComPtr pAllocatorIn; - m_pInput->GetAllocator(&pAllocatorIn); - if (!pAllocatorIn) { - return E_UNEXPECTED; - } - - pAllocatorIn->GetProperties(pProperties); - - pProperties->cBuffers = std::max(m_nSamplesToBuffer, pProperties->cBuffers); - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -HRESULT CBufferFilter::GetMediaType(int iPosition, CMediaType* pMediaType) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - // TODO: offer all input types from upstream and allow reconnection at least in stopped state - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - CopyMediaType(pMediaType, &m_pInput->CurrentMediaType()); - - return S_OK; -} - -HRESULT CBufferFilter::StopStreaming() -{ - CBufferFilterOutputPin* pPin = static_cast(m_pOutput); - if (m_pInput && pPin && pPin->m_pOutputQueue) { - while (!m_pInput->IsFlushing() && pPin->m_pOutputQueue->GetQueueCount() > 0) { - Sleep(50); - } - } - - return __super::StopStreaming(); -} - -// -// CBufferFilterOutputPin -// - -CBufferFilterOutputPin::CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr) - : CTransformOutputPin(NAME("CBufferFilterOutputPin"), pFilter, phr, L"Out") -{ -} - -HRESULT CBufferFilterOutputPin::Active() -{ - CAutoLock lock_it(m_pLock); - - if (m_Connected && !m_pOutputQueue) { - HRESULT hr = NOERROR; - - m_pOutputQueue.Attach(DEBUG_NEW CBufferFilterOutputQueue(m_Connected, &hr)); - if (!m_pOutputQueue) { - hr = E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - m_pOutputQueue.Free(); - return hr; - } - } - - return __super::Active(); -} - -HRESULT CBufferFilterOutputPin::Inactive() -{ - CAutoLock lock_it(m_pLock); - m_pOutputQueue.Free(); - return __super::Inactive(); -} - -HRESULT CBufferFilterOutputPin::Deliver(IMediaSample* pMediaSample) -{ - if (!m_pOutputQueue) { - return NOERROR; - } - pMediaSample->AddRef(); - return m_pOutputQueue->Receive(pMediaSample); -} - -HRESULT CBufferFilterOutputPin::DeliverEndOfStream() -{ - CallQueue(EOS()); -} - -HRESULT CBufferFilterOutputPin::DeliverBeginFlush() -{ - CallQueue(BeginFlush()); -} - -HRESULT CBufferFilterOutputPin::DeliverEndFlush() -{ - CallQueue(EndFlush()); -} - -HRESULT CBufferFilterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - CallQueue(NewSegment(tStart, tStop, dRate)); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "BufferFilter.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CBufferFilter), BufferFilterName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CBufferFilter +// + +CBufferFilter::CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr) + : CTransformFilter(NAME("CBufferFilter"), lpunk, __uuidof(this)) + , m_nSamplesToBuffer(2) +{ + HRESULT hr = S_OK; + + do { + m_pInput = DEBUG_NEW CTransformInputPin(NAME("Transform input pin"), this, &hr, L"In"); + if (!m_pInput) { + hr = E_OUTOFMEMORY; + } + if (FAILED(hr)) { + break; + } + + m_pOutput = DEBUG_NEW CBufferFilterOutputPin(this, &hr); + if (!m_pOutput) { + hr = E_OUTOFMEMORY; + } + if (FAILED(hr)) { + delete m_pInput; + m_pInput = nullptr; + break; + } + } while (false); + + if (phr) { + *phr = hr; + } +} + +CBufferFilter::~CBufferFilter() +{ +} + +STDMETHODIMP CBufferFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IBufferFilter) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IBufferFilter + +STDMETHODIMP CBufferFilter::SetBuffers(int nBuffers) +{ + if (!m_pOutput) { + return E_FAIL; + } + + if (m_pOutput->IsConnected()) { // TODO: allow "on-the-fly" changes + return VFW_E_ALREADY_CONNECTED; + } + + m_nSamplesToBuffer = nBuffers; + + return S_OK; +} + +STDMETHODIMP_(int) CBufferFilter::GetBuffers() +{ + return m_nSamplesToBuffer; +} + +STDMETHODIMP_(int) CBufferFilter::GetFreeBuffers() +{ + CBufferFilterOutputPin* pPin = static_cast(m_pOutput); + return (pPin && pPin->m_pOutputQueue ? (m_nSamplesToBuffer - pPin->m_pOutputQueue->GetQueueCount()) : 0); +} + +STDMETHODIMP CBufferFilter::SetPriority(DWORD dwPriority) +{ + CBufferFilterOutputPin* pPin = static_cast(m_pOutput); + return (pPin && pPin->m_pOutputQueue ? (pPin->m_pOutputQueue->SetPriority(dwPriority) ? S_OK : E_FAIL) : E_UNEXPECTED); +} + +// + +HRESULT CBufferFilter::Receive(IMediaSample* pSample) +{ + ASSERT(pSample); + CheckPointer(pSample, E_POINTER); + ASSERT(m_pOutput); + CheckPointer(m_pOutput, E_POINTER); + + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->Deliver(pSample); + } + + HRESULT hr; + IMediaSample* pOutSample; + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + // Start timing the transform (if PERF is defined) + MSR_START(m_idTransform); + + // have the derived class transform the data + + hr = Transform(pSample, pOutSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransform); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE, 1, _T("Error from transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pOutSample); + m_bSampleSkipped = FALSE; // last thing no longer dropped + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // Release the sample before calling notify to avoid + // deadlocks if the sample holds a lock on the system + // such as DirectDraw buffers do + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE, 0, 0); + m_bQualityChanged = TRUE; + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + + return hr; +} + +HRESULT CBufferFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + BYTE* pDataIn = nullptr; + BYTE* pDataOut = nullptr; + + long len = pIn->GetActualDataLength(); + long size = pOut->GetSize(); + + if (FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn || FAILED(pOut->GetPointer(&pDataOut)) || !pDataOut + || len > size || len <= 0) { + return S_FALSE; + } + + memcpy(pDataOut, pDataIn, std::min(len, size)); + + pOut->SetActualDataLength(std::min(len, size)); + + return S_OK; +} + +HRESULT CBufferFilter::CheckInputType(const CMediaType* mtIn) +{ + return S_OK; +} + +HRESULT CBufferFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return mtIn->MatchesPartial(mtOut) ? S_OK : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CBufferFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + CComPtr pAllocatorIn; + m_pInput->GetAllocator(&pAllocatorIn); + if (!pAllocatorIn) { + return E_UNEXPECTED; + } + + pAllocatorIn->GetProperties(pProperties); + + pProperties->cBuffers = std::max(m_nSamplesToBuffer, pProperties->cBuffers); + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +HRESULT CBufferFilter::GetMediaType(int iPosition, CMediaType* pMediaType) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + // TODO: offer all input types from upstream and allow reconnection at least in stopped state + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + CopyMediaType(pMediaType, &m_pInput->CurrentMediaType()); + + return S_OK; +} + +HRESULT CBufferFilter::StopStreaming() +{ + CBufferFilterOutputPin* pPin = static_cast(m_pOutput); + if (m_pInput && pPin && pPin->m_pOutputQueue) { + while (!m_pInput->IsFlushing() && pPin->m_pOutputQueue->GetQueueCount() > 0) { + Sleep(50); + } + } + + return __super::StopStreaming(); +} + +// +// CBufferFilterOutputPin +// + +CBufferFilterOutputPin::CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr) + : CTransformOutputPin(NAME("CBufferFilterOutputPin"), pFilter, phr, L"Out") +{ +} + +HRESULT CBufferFilterOutputPin::Active() +{ + CAutoLock lock_it(m_pLock); + + if (m_Connected && !m_pOutputQueue) { + HRESULT hr = NOERROR; + + m_pOutputQueue.Attach(DEBUG_NEW CBufferFilterOutputQueue(m_Connected, &hr)); + if (!m_pOutputQueue) { + hr = E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + m_pOutputQueue.Free(); + return hr; + } + } + + return __super::Active(); +} + +HRESULT CBufferFilterOutputPin::Inactive() +{ + CAutoLock lock_it(m_pLock); + m_pOutputQueue.Free(); + return __super::Inactive(); +} + +HRESULT CBufferFilterOutputPin::Deliver(IMediaSample* pMediaSample) +{ + if (!m_pOutputQueue) { + return NOERROR; + } + pMediaSample->AddRef(); + return m_pOutputQueue->Receive(pMediaSample); +} + +HRESULT CBufferFilterOutputPin::DeliverEndOfStream() +{ + CallQueue(EOS()); +} + +HRESULT CBufferFilterOutputPin::DeliverBeginFlush() +{ + CallQueue(BeginFlush()); +} + +HRESULT CBufferFilterOutputPin::DeliverEndFlush() +{ + CallQueue(EndFlush()); +} + +HRESULT CBufferFilterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CallQueue(NewSegment(tStart, tStop, dRate)); +} diff --git a/src/filters/transform/BufferFilter/BufferFilter.def b/src/filters/transform/BufferFilter/BufferFilter.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.def +++ b/src/filters/transform/BufferFilter/BufferFilter.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/transform/BufferFilter/BufferFilter.h b/src/filters/transform/BufferFilter/BufferFilter.h index 3df9fbf125d..c253ed22d42 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.h +++ b/src/filters/transform/BufferFilter/BufferFilter.h @@ -1,99 +1,99 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include - -#define BufferFilterName L"MPC-HC Buffer Filter" - -interface __declspec(uuid("63EF0035-3FFE-4c41-9230-4346E028BE20")) - IBufferFilter : - public IUnknown -{ - STDMETHOD(SetBuffers)(int nBuffers) PURE; - STDMETHOD_(int, GetBuffers)() PURE; - STDMETHOD_(int, GetFreeBuffers)() PURE; - STDMETHOD(SetPriority)(DWORD dwPriority = THREAD_PRIORITY_NORMAL) PURE; -}; - -class __declspec(uuid("DA2B3D77-2F29-4fd2-AC99-DEE4A8A13BF0")) - CBufferFilter : public CTransformFilter, public IBufferFilter -{ - int m_nSamplesToBuffer; - -public: - CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr); - virtual ~CBufferFilter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IBufferFilter - STDMETHODIMP SetBuffers(int nBuffers); - STDMETHODIMP_(int) GetBuffers(); - STDMETHODIMP_(int) GetFreeBuffers(); - STDMETHODIMP SetPriority(DWORD dwPriority = THREAD_PRIORITY_NORMAL); - - HRESULT Receive(IMediaSample* pSample); - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); - HRESULT StopStreaming(); -}; - -class CBufferFilterOutputPin : public CTransformOutputPin -{ - class CBufferFilterOutputQueue : public COutputQueue - { - public: - CBufferFilterOutputQueue(IPin* pInputPin, HRESULT* phr, - DWORD dwPriority = THREAD_PRIORITY_NORMAL, - BOOL bAuto = FALSE, BOOL bQueue = TRUE, - LONG lBatchSize = 1, BOOL bBatchExact = FALSE, - LONG lListSize = DEFAULTCACHE, - bool bFlushingOpt = false) - : COutputQueue(pInputPin, phr, bAuto, bQueue, lBatchSize, bBatchExact, lListSize, dwPriority, bFlushingOpt) { - } - - int GetQueueCount() { return m_List ? m_List->GetCount() : -1; } - - bool SetPriority(DWORD dwPriority) { - return m_hThread ? !!::SetThreadPriority(m_hThread, dwPriority) : false; - } - }; - -public: - CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr); - - CAutoPtr m_pOutputQueue; - - HRESULT Active(); - HRESULT Inactive(); - - HRESULT Deliver(IMediaSample* pMediaSample); - HRESULT DeliverEndOfStream(); - HRESULT DeliverBeginFlush(); - HRESULT DeliverEndFlush(); - HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include + +#define BufferFilterName L"MPC-HC Buffer Filter" + +interface __declspec(uuid("63EF0035-3FFE-4c41-9230-4346E028BE20")) + IBufferFilter : + public IUnknown +{ + STDMETHOD(SetBuffers)(int nBuffers) PURE; + STDMETHOD_(int, GetBuffers)() PURE; + STDMETHOD_(int, GetFreeBuffers)() PURE; + STDMETHOD(SetPriority)(DWORD dwPriority = THREAD_PRIORITY_NORMAL) PURE; +}; + +class __declspec(uuid("DA2B3D77-2F29-4fd2-AC99-DEE4A8A13BF0")) + CBufferFilter : public CTransformFilter, public IBufferFilter +{ + int m_nSamplesToBuffer; + +public: + CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr); + virtual ~CBufferFilter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IBufferFilter + STDMETHODIMP SetBuffers(int nBuffers); + STDMETHODIMP_(int) GetBuffers(); + STDMETHODIMP_(int) GetFreeBuffers(); + STDMETHODIMP SetPriority(DWORD dwPriority = THREAD_PRIORITY_NORMAL); + + HRESULT Receive(IMediaSample* pSample); + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); + HRESULT StopStreaming(); +}; + +class CBufferFilterOutputPin : public CTransformOutputPin +{ + class CBufferFilterOutputQueue : public COutputQueue + { + public: + CBufferFilterOutputQueue(IPin* pInputPin, HRESULT* phr, + DWORD dwPriority = THREAD_PRIORITY_NORMAL, + BOOL bAuto = FALSE, BOOL bQueue = TRUE, + LONG lBatchSize = 1, BOOL bBatchExact = FALSE, + LONG lListSize = DEFAULTCACHE, + bool bFlushingOpt = false) + : COutputQueue(pInputPin, phr, bAuto, bQueue, lBatchSize, bBatchExact, lListSize, dwPriority, bFlushingOpt) { + } + + int GetQueueCount() { return m_List ? m_List->GetCount() : -1; } + + bool SetPriority(DWORD dwPriority) { + return m_hThread ? !!::SetThreadPriority(m_hThread, dwPriority) : false; + } + }; + +public: + CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr); + + CAutoPtr m_pOutputQueue; + + HRESULT Active(); + HRESULT Inactive(); + + HRESULT Deliver(IMediaSample* pMediaSample); + HRESULT DeliverEndOfStream(); + HRESULT DeliverBeginFlush(); + HRESULT DeliverEndFlush(); + HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); +}; diff --git a/src/filters/transform/BufferFilter/BufferFilter.rc b/src/filters/transform/BufferFilter/BufferFilter.rc index 28ab46df900..ca8b9de15cb 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.rc +++ b/src/filters/transform/BufferFilter/BufferFilter.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "BufferFilter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "BufferFilter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "BufferFilter.ax" - VALUE "ProductName", "BufferFilter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "BufferFilter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "BufferFilter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "BufferFilter.ax" + VALUE "ProductName", "BufferFilter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/transform/BufferFilter/BufferFilter.vcxproj b/src/filters/transform/BufferFilter/BufferFilter.vcxproj index e4b8547f330..87446141864 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.vcxproj +++ b/src/filters/transform/BufferFilter/BufferFilter.vcxproj @@ -1,114 +1,114 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {9DCFD02A-16A0-4766-BC18-66163E21929D} - BufferFilter - MFCProj - BufferFilter - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - BufferFilter.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {9DCFD02A-16A0-4766-BC18-66163E21929D} + BufferFilter + MFCProj + BufferFilter + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + BufferFilter.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/transform/BufferFilter/BufferFilter.vcxproj.filters b/src/filters/transform/BufferFilter/BufferFilter.vcxproj.filters index 06d3f156d68..00d84c07e07 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.vcxproj.filters +++ b/src/filters/transform/BufferFilter/BufferFilter.vcxproj.filters @@ -1,45 +1,45 @@ - - - - - {9b46af16-2931-44b3-981b-5a22b3ba715b} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {c2ac36f0-4a7c-472d-9399-044ccd8a0c19} - h;hpp;hxx;hm;inl;inc - - - {d1339141-4475-4353-a628-f09883acf731} - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {9b46af16-2931-44b3-981b-5a22b3ba715b} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2ac36f0-4a7c-472d-9399-044ccd8a0c19} + h;hpp;hxx;hm;inl;inc + + + {d1339141-4475-4353-a628-f09883acf731} + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/transform/BufferFilter/resource.h b/src/filters/transform/BufferFilter/resource.h index b51a6af76c2..f0a39ebf9c8 100644 --- a/src/filters/transform/BufferFilter/resource.h +++ b/src/filters/transform/BufferFilter/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by BufferFilter.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by BufferFilter.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/transform/BufferFilter/stdafx.cpp b/src/filters/transform/BufferFilter/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/transform/BufferFilter/stdafx.cpp +++ b/src/filters/transform/BufferFilter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/transform/BufferFilter/stdafx.h b/src/filters/transform/BufferFilter/stdafx.h index d8320f2c878..12bbe2db0a7 100644 --- a/src/filters/transform/BufferFilter/stdafx.h +++ b/src/filters/transform/BufferFilter/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.cpp b/src/filters/transform/DeCSSFilter/DeCSSFilter.cpp index a3e01c5a146..70bf82d6bd8 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.cpp +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.cpp @@ -1,259 +1,259 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "DeCSSFilter.h" -#include "../../../DeCSS/DeCSSInputPin.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -#include -#include "moreuuids.h" - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_NULL}, - {&MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CDeCSSFilter), DeCSSFilterName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CDeCSSFilter -// - -class CKsPSInputPin : public CDeCSSInputPin -{ -public: - CKsPSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName) - : CDeCSSInputPin(pObjectName, pFilter, phr, pName) { - } - - // IKsPropertySet - STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength) { - if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { - return pKsPS->Set(PropSet, Id, InstanceData, InstanceLength, PropertyData, DataLength); - } - return E_NOTIMPL; - } - STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG* pBytesReturned) { - if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { - return pKsPS->Get(PropSet, Id, InstanceData, InstanceLength, PropertyData, DataLength, pBytesReturned); - } - return E_NOTIMPL; - } - STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) { - if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { - return pKsPS->QuerySupported(PropSet, Id, pTypeSupport); - } - return E_NOTIMPL; - } -}; - -CDeCSSFilter::CDeCSSFilter(LPUNKNOWN lpunk, HRESULT* phr) - : CTransformFilter(NAME("CDeCSSFilter"), lpunk, __uuidof(this)) -{ - HRESULT hr; - if (!phr) { - phr = &hr; - } - *phr = S_OK; - - m_pInput = DEBUG_NEW CKsPSInputPin(NAME("CKsPSInputPin"), this, phr, L"In"); - if (!m_pInput) { - *phr = E_OUTOFMEMORY; - } - if (FAILED(*phr)) { - return; - } - - m_pOutput = DEBUG_NEW CTransformOutputPin(NAME("CTransformOutputPin"), this, phr, L"Out"); - if (!m_pOutput) { - *phr = E_OUTOFMEMORY; - } - if (FAILED(*phr)) { - delete m_pInput; - m_pInput = nullptr; - return; - } -} - -CDeCSSFilter::~CDeCSSFilter() -{ -} - -HRESULT CDeCSSFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - AM_MEDIA_TYPE* pmt; - if (SUCCEEDED(pIn->GetMediaType(&pmt)) && pmt) { - CMediaType mt = *pmt; - m_pInput->SetMediaType(&mt); - mt.majortype = m_pOutput->CurrentMediaType().majortype; - m_pOutput->SetMediaType(&mt); - pOut->SetMediaType(&mt); - DeleteMediaType(pmt); - } - - BYTE* pDataIn = nullptr; - BYTE* pDataOut = nullptr; - - HRESULT hr; - if (FAILED(hr = pIn->GetPointer(&pDataIn)) || FAILED(hr = pOut->GetPointer(&pDataOut))) { - return hr; - } - - long len = pIn->GetActualDataLength(); - long size = pOut->GetSize(); - - if (len == 0 || pDataIn == nullptr) { // format changes do not carry any data - pOut->SetActualDataLength(0); - return S_OK; - } - - if (m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES) { - if (*(DWORD*)pDataIn == 0xBA010000) { - len -= 14; - pDataIn += 14; - if (int stuffing = (pDataIn[-1] & 7)) { - len -= stuffing; - pDataIn += stuffing; - } - } - if (len <= 0) { - return S_FALSE; - } - if (*(DWORD*)pDataIn == 0xBB010000) { - len -= 4; - pDataIn += 4; - int hdrlen = ((pDataIn[0] << 8) | pDataIn[1]) + 2; - len -= hdrlen; - pDataIn += hdrlen; - } - if (len <= 0) { - return S_FALSE; - } - } - - if (!pDataIn || !pDataOut || len > size || len < 0) { - return S_FALSE; - } - - memcpy(pDataOut, pDataIn, std::min(len, size)); - pOut->SetActualDataLength(std::min(len, size)); - - return S_OK; -} - -HRESULT CDeCSSFilter::CheckInputType(const CMediaType* mtIn) -{ - return mtIn->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CDeCSSFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return SUCCEEDED(CheckInputType(mtIn)) - && mtOut->majortype == MEDIATYPE_MPEG2_PACK || mtOut->majortype == MEDIATYPE_MPEG2_PES - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CDeCSSFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - pProperties->cbAlign = 1; - pProperties->cBuffers = 1; - pProperties->cbBuffer = 2048; - pProperties->cbPrefix = 0; - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -HRESULT CDeCSSFilter::GetMediaType(int iPosition, CMediaType* pmt) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 1) { - return VFW_S_NO_MORE_ITEMS; - } - - CopyMediaType(pmt, &m_pInput->CurrentMediaType()); - if (iPosition == 0) { - pmt->majortype = MEDIATYPE_MPEG2_PACK; - } - if (iPosition == 1) { - pmt->majortype = MEDIATYPE_MPEG2_PES; - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "DeCSSFilter.h" +#include "../../../DeCSS/DeCSSInputPin.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +#include +#include "moreuuids.h" + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_NULL}, + {&MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CDeCSSFilter), DeCSSFilterName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CDeCSSFilter +// + +class CKsPSInputPin : public CDeCSSInputPin +{ +public: + CKsPSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName) + : CDeCSSInputPin(pObjectName, pFilter, phr, pName) { + } + + // IKsPropertySet + STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength) { + if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { + return pKsPS->Set(PropSet, Id, InstanceData, InstanceLength, PropertyData, DataLength); + } + return E_NOTIMPL; + } + STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG* pBytesReturned) { + if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { + return pKsPS->Get(PropSet, Id, InstanceData, InstanceLength, PropertyData, DataLength, pBytesReturned); + } + return E_NOTIMPL; + } + STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) { + if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { + return pKsPS->QuerySupported(PropSet, Id, pTypeSupport); + } + return E_NOTIMPL; + } +}; + +CDeCSSFilter::CDeCSSFilter(LPUNKNOWN lpunk, HRESULT* phr) + : CTransformFilter(NAME("CDeCSSFilter"), lpunk, __uuidof(this)) +{ + HRESULT hr; + if (!phr) { + phr = &hr; + } + *phr = S_OK; + + m_pInput = DEBUG_NEW CKsPSInputPin(NAME("CKsPSInputPin"), this, phr, L"In"); + if (!m_pInput) { + *phr = E_OUTOFMEMORY; + } + if (FAILED(*phr)) { + return; + } + + m_pOutput = DEBUG_NEW CTransformOutputPin(NAME("CTransformOutputPin"), this, phr, L"Out"); + if (!m_pOutput) { + *phr = E_OUTOFMEMORY; + } + if (FAILED(*phr)) { + delete m_pInput; + m_pInput = nullptr; + return; + } +} + +CDeCSSFilter::~CDeCSSFilter() +{ +} + +HRESULT CDeCSSFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + AM_MEDIA_TYPE* pmt; + if (SUCCEEDED(pIn->GetMediaType(&pmt)) && pmt) { + CMediaType mt = *pmt; + m_pInput->SetMediaType(&mt); + mt.majortype = m_pOutput->CurrentMediaType().majortype; + m_pOutput->SetMediaType(&mt); + pOut->SetMediaType(&mt); + DeleteMediaType(pmt); + } + + BYTE* pDataIn = nullptr; + BYTE* pDataOut = nullptr; + + HRESULT hr; + if (FAILED(hr = pIn->GetPointer(&pDataIn)) || FAILED(hr = pOut->GetPointer(&pDataOut))) { + return hr; + } + + long len = pIn->GetActualDataLength(); + long size = pOut->GetSize(); + + if (len == 0 || pDataIn == nullptr) { // format changes do not carry any data + pOut->SetActualDataLength(0); + return S_OK; + } + + if (m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES) { + if (*(DWORD*)pDataIn == 0xBA010000) { + len -= 14; + pDataIn += 14; + if (int stuffing = (pDataIn[-1] & 7)) { + len -= stuffing; + pDataIn += stuffing; + } + } + if (len <= 0) { + return S_FALSE; + } + if (*(DWORD*)pDataIn == 0xBB010000) { + len -= 4; + pDataIn += 4; + int hdrlen = ((pDataIn[0] << 8) | pDataIn[1]) + 2; + len -= hdrlen; + pDataIn += hdrlen; + } + if (len <= 0) { + return S_FALSE; + } + } + + if (!pDataIn || !pDataOut || len > size || len < 0) { + return S_FALSE; + } + + memcpy(pDataOut, pDataIn, std::min(len, size)); + pOut->SetActualDataLength(std::min(len, size)); + + return S_OK; +} + +HRESULT CDeCSSFilter::CheckInputType(const CMediaType* mtIn) +{ + return mtIn->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CDeCSSFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return SUCCEEDED(CheckInputType(mtIn)) + && mtOut->majortype == MEDIATYPE_MPEG2_PACK || mtOut->majortype == MEDIATYPE_MPEG2_PES + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CDeCSSFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + pProperties->cbAlign = 1; + pProperties->cBuffers = 1; + pProperties->cbBuffer = 2048; + pProperties->cbPrefix = 0; + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +HRESULT CDeCSSFilter::GetMediaType(int iPosition, CMediaType* pmt) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 1) { + return VFW_S_NO_MORE_ITEMS; + } + + CopyMediaType(pmt, &m_pInput->CurrentMediaType()); + if (iPosition == 0) { + pmt->majortype = MEDIATYPE_MPEG2_PACK; + } + if (iPosition == 1) { + pmt->majortype = MEDIATYPE_MPEG2_PES; + } + + return S_OK; +} diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.def b/src/filters/transform/DeCSSFilter/DeCSSFilter.def index 6492e5cd656..8b4dcdde858 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.def +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.h b/src/filters/transform/DeCSSFilter/DeCSSFilter.h index 0b800efc48a..ed1fd9f9848 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.h +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.h @@ -1,40 +1,40 @@ -/* - * (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 . - * - */ - -#pragma once - -#define DeCSSFilterName L"MPC-HC DeCSSFilter" - -class __declspec(uuid("7B3BD419-FE03-4820-BE94-A22A4F844895")) - CDeCSSFilter : public CTransformFilter -{ - friend class CKsPSInputPin; - -public: - CDeCSSFilter(LPUNKNOWN lpunk, HRESULT* phr); - virtual ~CDeCSSFilter(); - - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); -}; +/* + * (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 . + * + */ + +#pragma once + +#define DeCSSFilterName L"MPC-HC DeCSSFilter" + +class __declspec(uuid("7B3BD419-FE03-4820-BE94-A22A4F844895")) + CDeCSSFilter : public CTransformFilter +{ + friend class CKsPSInputPin; + +public: + CDeCSSFilter(LPUNKNOWN lpunk, HRESULT* phr); + virtual ~CDeCSSFilter(); + + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); +}; diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.rc b/src/filters/transform/DeCSSFilter/DeCSSFilter.rc index 152af2b3855..90940bdec22 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.rc +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "DeCSSFilter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "DeCSSFilter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "DeCSSFilter.ax" - VALUE "ProductName", "DeCSSFilter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "DeCSSFilter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "DeCSSFilter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "DeCSSFilter.ax" + VALUE "ProductName", "DeCSSFilter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj b/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj index 7b5f000b9e1..be71938ac84 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj @@ -1,117 +1,117 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {F6B06383-3FFD-403B-9867-4AA82A20AA83} - DeCSSFilter - MFCProj - DeCSSFilter - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - DeCSSFilter.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {1a2dfd1a-3c6c-44d1-909d-294af646b575} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {F6B06383-3FFD-403B-9867-4AA82A20AA83} + DeCSSFilter + MFCProj + DeCSSFilter + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + DeCSSFilter.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {1a2dfd1a-3c6c-44d1-909d-294af646b575} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj.filters b/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj.filters index f5eda45944c..da5ab1f53ea 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj.filters +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj.filters @@ -1,45 +1,45 @@ - - - - - {8b808ee2-0f72-4075-8ecb-82a22d4466ae} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {f3d45f80-2532-40ae-894e-b22166f99365} - h;hpp;hxx;hm;inl;inc - - - {21573b71-7374-4d8d-9e54-3e990fae2c15} - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {8b808ee2-0f72-4075-8ecb-82a22d4466ae} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {f3d45f80-2532-40ae-894e-b22166f99365} + h;hpp;hxx;hm;inl;inc + + + {21573b71-7374-4d8d-9e54-3e990fae2c15} + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/transform/DeCSSFilter/resource.h b/src/filters/transform/DeCSSFilter/resource.h index e745510abb1..a84767ddee6 100644 --- a/src/filters/transform/DeCSSFilter/resource.h +++ b/src/filters/transform/DeCSSFilter/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by DeCSSFilter.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DeCSSFilter.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/transform/DeCSSFilter/stdafx.cpp b/src/filters/transform/DeCSSFilter/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/filters/transform/DeCSSFilter/stdafx.cpp +++ b/src/filters/transform/DeCSSFilter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/transform/DeCSSFilter/stdafx.h b/src/filters/transform/DeCSSFilter/stdafx.h index d8320f2c878..12bbe2db0a7 100644 --- a/src/filters/transform/DeCSSFilter/stdafx.h +++ b/src/filters/transform/DeCSSFilter/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/transform/VSFilter/IDirectVobSub.h b/src/filters/transform/VSFilter/IDirectVobSub.h index 9d4a6f65305..dccd0880cf1 100644 --- a/src/filters/transform/VSFilter/IDirectVobSub.h +++ b/src/filters/transform/VSFilter/IDirectVobSub.h @@ -1,194 +1,194 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#pragma once - -#include "../../../Subtitles/STS.h" - -#ifdef __cplusplus -extern "C" { -#endif - -interface __declspec(uuid("EBE1FB08-3957-47ca-AF13-5827E5442E56")) - IDirectVobSub : - public IUnknown -{ - STDMETHOD(get_FileName)(THIS_ WCHAR* fn) PURE; // fn should point to a buffer allocated to at least the length of MAX_PATH (=260) - - STDMETHOD(put_FileName)(THIS_ WCHAR* fn) PURE; - - STDMETHOD(get_LanguageCount)(THIS_ int* nLangs) PURE; - - STDMETHOD(get_LanguageName)(THIS_ int iLanguage, WCHAR** ppName) PURE; // the returned *ppName is allocated with CoTaskMemAlloc - - STDMETHOD(get_SelectedLanguage)(THIS_ int* iSelected) PURE; - - STDMETHOD(put_SelectedLanguage)(THIS_ int iSelected) PURE; - - STDMETHOD(get_HideSubtitles)(THIS_ bool* fHideSubtitles) PURE; - - STDMETHOD(put_HideSubtitles)(THIS_ bool fHideSubtitles) PURE; - - // deprecated - STDMETHOD(get_PreBuffering)(THIS_ bool* fDoPreBuffering) PURE; - - // deprecated - STDMETHOD(put_PreBuffering)(THIS_ bool fDoPreBuffering) PURE; - - STDMETHOD(get_Placement)(THIS_ bool* fOverridePlacement, int* xperc, int* yperc) PURE; - - STDMETHOD(put_Placement)(THIS_ bool fOverridePlacement, int xperc, int yperc) PURE; - - STDMETHOD(get_VobSubSettings)(THIS_ bool* fBuffer, bool* fOnlyShowForcedSubs, bool* fPolygonize) PURE; - - STDMETHOD(put_VobSubSettings)(THIS_ bool fBuffer, bool fOnlyShowForcedSubs, bool fPolygonize) PURE; - - // depending on lflen, lf must point to LOGFONTA or LOGFONTW - STDMETHOD(get_TextSettings)(THIS_ void* lf, int lflen, COLORREF* color, bool* fShadow, bool* fOutline, bool* fAdvancedRenderer) PURE; - - STDMETHOD(put_TextSettings)(THIS_ void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer) PURE; - - STDMETHOD(get_Flip)(THIS_ bool* fPicture, bool* fSubtitles) PURE; - - STDMETHOD(put_Flip)(THIS_ bool fPicture, bool fSubtitles) PURE; - - STDMETHOD(get_OSD)(THIS_ bool* fOSD) PURE; - - STDMETHOD(put_OSD)(THIS_ bool fOSD) PURE; - - STDMETHOD(get_SaveFullPath)(THIS_ bool* fSaveFullPath) PURE; - - STDMETHOD(put_SaveFullPath)(THIS_ bool fSaveFullPath) PURE; - - STDMETHOD(get_SubtitleTiming)(THIS_ int* delay, int* speedmul, int* speeddiv) PURE; - - STDMETHOD(put_SubtitleTiming)(THIS_ int delay, int speedmul, int speeddiv) PURE; - - STDMETHOD(get_MediaFPS)(THIS_ bool* fEnabled, double* fps) PURE; - - STDMETHOD(put_MediaFPS)(THIS_ bool fEnabled, double fps) PURE; - - // no longer supported - - STDMETHOD(get_ColorFormat)(THIS_ int* iPosition) PURE; - - STDMETHOD(put_ColorFormat)(THIS_ int iPosition) PURE; - - - STDMETHOD(get_ZoomRect)(THIS_ NORMALIZEDRECT* rect) PURE; - - STDMETHOD(put_ZoomRect)(THIS_ NORMALIZEDRECT* rect) PURE; - - - STDMETHOD(UpdateRegistry)(THIS_) PURE; - - - STDMETHOD(HasConfigDialog)(THIS_ int iSelected) PURE; - - STDMETHOD(ShowConfigDialog)(THIS_ int iSelected, HWND hWndParent) PURE; // if available, this will popup a child dialog allowing the user to edit the style options - - - STDMETHOD(IsSubtitleReloaderLocked)(THIS_ bool* fLocked) PURE; - - STDMETHOD(LockSubtitleReloader)(THIS_ bool fLock) PURE; - - STDMETHOD(get_SubtitleReloader)(THIS_ bool* fDisabled) PURE; - - STDMETHOD(put_SubtitleReloader)(THIS_ bool fDisable) PURE; - - // horizontal: 0 - disabled, 1 - mod32 extension (width = (width + 31) & ~31) - // vertical: 0 - disabled, 1 - 16:9, 2 - 4:3, 0x80 - crop (use crop together with 16:9 or 4:3, eg 0x81 will crop to 16:9 if the picture was taller) - // resx2: 0 - disabled, 1 - enabled, 2 - depends on the original resolution - // resx2minw: resolution doubler will be used if width * height <= resx2minw * resx2minh (resx2minw * resx2minh equals to 384 * 288 by default) - STDMETHOD(get_ExtendPicture)(THIS_ int* horizontal, int* vertical, int* resx2, int* resx2minw, int* resx2minh) PURE; - - STDMETHOD(put_ExtendPicture)(THIS_ int horizontal, int vertical, int resx2, int resx2minw, int resx2minh) PURE; - - // level: 0 - when needed, 1 - always, 2 - disabled - STDMETHOD(get_LoadSettings)(THIS_ int* level, bool* fExternalLoad, bool* fWebLoad, bool* fEmbeddedLoad) PURE; - - STDMETHOD(put_LoadSettings)(THIS_ int level, bool fExternalLoad, bool fWebLoad, bool fEmbeddedLoad) PURE; - - STDMETHOD(get_SubPictToBuffer)(THIS_ unsigned int* uSubPictToBuffer) PURE; - - STDMETHOD(put_SubPictToBuffer)(THIS_ unsigned int uSubPictToBuffer) PURE; - - STDMETHOD(get_AnimWhenBuffering)(THIS_ bool* fAnimWhenBuffering) PURE; - - STDMETHOD(put_AnimWhenBuffering)(THIS_ bool fAnimWhenBuffering) PURE; -}; - -interface __declspec(uuid("FE6EC6A0-21CA-4970-9EF0-B296F7F38AF0")) - ISubClock : - public IUnknown -{ - STDMETHOD(SetTime)(REFERENCE_TIME rt) PURE; - STDMETHOD_(REFERENCE_TIME, GetTime)() PURE; -}; - -interface __declspec(uuid("0665B760-FBC1-46C3-A35F-E471527C96A4")) - ISubClock2 : - public ISubClock -{ - STDMETHOD(SetAvgTimePerFrame)(REFERENCE_TIME rt) PURE; - STDMETHOD(GetAvgTimePerFrame)(REFERENCE_TIME* prt) PURE; // return S_OK only if *prt was set and is valid -}; - -interface __declspec(uuid("AB52FC9C-2415-4dca-BC1C-8DCC2EAE8150")) - IDirectVobSub2 : - public IDirectVobSub -{ - STDMETHOD(AdviseSubClock)(THIS_ ISubClock* pSubClock) PURE; - - STDMETHOD_(bool, get_Forced)(THIS_) PURE; - - STDMETHOD(put_Forced)(THIS_ bool fForced) PURE; - - STDMETHOD(get_TextSettings)(THIS_ STSStyle* pDefStyle) PURE; - - STDMETHOD(put_TextSettings)(THIS_ STSStyle* pDefStyle) PURE; - - STDMETHOD(get_AspectRatioSettings)(THIS_ CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType) PURE; - - STDMETHOD(put_AspectRatioSettings)(THIS_ CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType) PURE; -}; - -interface __declspec(uuid("4484A031-713F-4893-8C24-4505C56E8915")) - IDirectVobSub3 : - public IDirectVobSub2 -{ - STDMETHOD_(bool, get_DisableSubtitleAnimation)(THIS_) PURE; - STDMETHOD(put_DisableSubtitleAnimation)(THIS_ bool bDisableSubtitleAnimation) PURE; - - STDMETHOD_(int, get_RenderAtWhenAnimationIsDisabled)(THIS_) PURE; - STDMETHOD(put_RenderAtWhenAnimationIsDisabled)(THIS_ int nRenderAtWhenAnimationIsDisabled) PURE; - - STDMETHOD_(int, get_AnimationRate)(THIS_) PURE; - STDMETHOD(put_AnimationRate)(THIS_ int nAnimationRate) PURE; - - STDMETHOD_(bool, get_AllowDroppingSubpic)(THIS_) PURE; - STDMETHOD(put_AllowDroppingSubpic)(THIS_ bool bAllowDroppingSubpic) PURE; -}; - - -#ifdef __cplusplus -} -#endif +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#pragma once + +#include "../../../Subtitles/STS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +interface __declspec(uuid("EBE1FB08-3957-47ca-AF13-5827E5442E56")) + IDirectVobSub : + public IUnknown +{ + STDMETHOD(get_FileName)(THIS_ WCHAR* fn) PURE; // fn should point to a buffer allocated to at least the length of MAX_PATH (=260) + + STDMETHOD(put_FileName)(THIS_ WCHAR* fn) PURE; + + STDMETHOD(get_LanguageCount)(THIS_ int* nLangs) PURE; + + STDMETHOD(get_LanguageName)(THIS_ int iLanguage, WCHAR** ppName) PURE; // the returned *ppName is allocated with CoTaskMemAlloc + + STDMETHOD(get_SelectedLanguage)(THIS_ int* iSelected) PURE; + + STDMETHOD(put_SelectedLanguage)(THIS_ int iSelected) PURE; + + STDMETHOD(get_HideSubtitles)(THIS_ bool* fHideSubtitles) PURE; + + STDMETHOD(put_HideSubtitles)(THIS_ bool fHideSubtitles) PURE; + + // deprecated + STDMETHOD(get_PreBuffering)(THIS_ bool* fDoPreBuffering) PURE; + + // deprecated + STDMETHOD(put_PreBuffering)(THIS_ bool fDoPreBuffering) PURE; + + STDMETHOD(get_Placement)(THIS_ bool* fOverridePlacement, int* xperc, int* yperc) PURE; + + STDMETHOD(put_Placement)(THIS_ bool fOverridePlacement, int xperc, int yperc) PURE; + + STDMETHOD(get_VobSubSettings)(THIS_ bool* fBuffer, bool* fOnlyShowForcedSubs, bool* fPolygonize) PURE; + + STDMETHOD(put_VobSubSettings)(THIS_ bool fBuffer, bool fOnlyShowForcedSubs, bool fPolygonize) PURE; + + // depending on lflen, lf must point to LOGFONTA or LOGFONTW + STDMETHOD(get_TextSettings)(THIS_ void* lf, int lflen, COLORREF* color, bool* fShadow, bool* fOutline, bool* fAdvancedRenderer) PURE; + + STDMETHOD(put_TextSettings)(THIS_ void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer) PURE; + + STDMETHOD(get_Flip)(THIS_ bool* fPicture, bool* fSubtitles) PURE; + + STDMETHOD(put_Flip)(THIS_ bool fPicture, bool fSubtitles) PURE; + + STDMETHOD(get_OSD)(THIS_ bool* fOSD) PURE; + + STDMETHOD(put_OSD)(THIS_ bool fOSD) PURE; + + STDMETHOD(get_SaveFullPath)(THIS_ bool* fSaveFullPath) PURE; + + STDMETHOD(put_SaveFullPath)(THIS_ bool fSaveFullPath) PURE; + + STDMETHOD(get_SubtitleTiming)(THIS_ int* delay, int* speedmul, int* speeddiv) PURE; + + STDMETHOD(put_SubtitleTiming)(THIS_ int delay, int speedmul, int speeddiv) PURE; + + STDMETHOD(get_MediaFPS)(THIS_ bool* fEnabled, double* fps) PURE; + + STDMETHOD(put_MediaFPS)(THIS_ bool fEnabled, double fps) PURE; + + // no longer supported + + STDMETHOD(get_ColorFormat)(THIS_ int* iPosition) PURE; + + STDMETHOD(put_ColorFormat)(THIS_ int iPosition) PURE; + + + STDMETHOD(get_ZoomRect)(THIS_ NORMALIZEDRECT* rect) PURE; + + STDMETHOD(put_ZoomRect)(THIS_ NORMALIZEDRECT* rect) PURE; + + + STDMETHOD(UpdateRegistry)(THIS_) PURE; + + + STDMETHOD(HasConfigDialog)(THIS_ int iSelected) PURE; + + STDMETHOD(ShowConfigDialog)(THIS_ int iSelected, HWND hWndParent) PURE; // if available, this will popup a child dialog allowing the user to edit the style options + + + STDMETHOD(IsSubtitleReloaderLocked)(THIS_ bool* fLocked) PURE; + + STDMETHOD(LockSubtitleReloader)(THIS_ bool fLock) PURE; + + STDMETHOD(get_SubtitleReloader)(THIS_ bool* fDisabled) PURE; + + STDMETHOD(put_SubtitleReloader)(THIS_ bool fDisable) PURE; + + // horizontal: 0 - disabled, 1 - mod32 extension (width = (width + 31) & ~31) + // vertical: 0 - disabled, 1 - 16:9, 2 - 4:3, 0x80 - crop (use crop together with 16:9 or 4:3, eg 0x81 will crop to 16:9 if the picture was taller) + // resx2: 0 - disabled, 1 - enabled, 2 - depends on the original resolution + // resx2minw: resolution doubler will be used if width * height <= resx2minw * resx2minh (resx2minw * resx2minh equals to 384 * 288 by default) + STDMETHOD(get_ExtendPicture)(THIS_ int* horizontal, int* vertical, int* resx2, int* resx2minw, int* resx2minh) PURE; + + STDMETHOD(put_ExtendPicture)(THIS_ int horizontal, int vertical, int resx2, int resx2minw, int resx2minh) PURE; + + // level: 0 - when needed, 1 - always, 2 - disabled + STDMETHOD(get_LoadSettings)(THIS_ int* level, bool* fExternalLoad, bool* fWebLoad, bool* fEmbeddedLoad) PURE; + + STDMETHOD(put_LoadSettings)(THIS_ int level, bool fExternalLoad, bool fWebLoad, bool fEmbeddedLoad) PURE; + + STDMETHOD(get_SubPictToBuffer)(THIS_ unsigned int* uSubPictToBuffer) PURE; + + STDMETHOD(put_SubPictToBuffer)(THIS_ unsigned int uSubPictToBuffer) PURE; + + STDMETHOD(get_AnimWhenBuffering)(THIS_ bool* fAnimWhenBuffering) PURE; + + STDMETHOD(put_AnimWhenBuffering)(THIS_ bool fAnimWhenBuffering) PURE; +}; + +interface __declspec(uuid("FE6EC6A0-21CA-4970-9EF0-B296F7F38AF0")) + ISubClock : + public IUnknown +{ + STDMETHOD(SetTime)(REFERENCE_TIME rt) PURE; + STDMETHOD_(REFERENCE_TIME, GetTime)() PURE; +}; + +interface __declspec(uuid("0665B760-FBC1-46C3-A35F-E471527C96A4")) + ISubClock2 : + public ISubClock +{ + STDMETHOD(SetAvgTimePerFrame)(REFERENCE_TIME rt) PURE; + STDMETHOD(GetAvgTimePerFrame)(REFERENCE_TIME* prt) PURE; // return S_OK only if *prt was set and is valid +}; + +interface __declspec(uuid("AB52FC9C-2415-4dca-BC1C-8DCC2EAE8150")) + IDirectVobSub2 : + public IDirectVobSub +{ + STDMETHOD(AdviseSubClock)(THIS_ ISubClock* pSubClock) PURE; + + STDMETHOD_(bool, get_Forced)(THIS_) PURE; + + STDMETHOD(put_Forced)(THIS_ bool fForced) PURE; + + STDMETHOD(get_TextSettings)(THIS_ STSStyle* pDefStyle) PURE; + + STDMETHOD(put_TextSettings)(THIS_ STSStyle* pDefStyle) PURE; + + STDMETHOD(get_AspectRatioSettings)(THIS_ CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType) PURE; + + STDMETHOD(put_AspectRatioSettings)(THIS_ CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType) PURE; +}; + +interface __declspec(uuid("4484A031-713F-4893-8C24-4505C56E8915")) + IDirectVobSub3 : + public IDirectVobSub2 +{ + STDMETHOD_(bool, get_DisableSubtitleAnimation)(THIS_) PURE; + STDMETHOD(put_DisableSubtitleAnimation)(THIS_ bool bDisableSubtitleAnimation) PURE; + + STDMETHOD_(int, get_RenderAtWhenAnimationIsDisabled)(THIS_) PURE; + STDMETHOD(put_RenderAtWhenAnimationIsDisabled)(THIS_ int nRenderAtWhenAnimationIsDisabled) PURE; + + STDMETHOD_(int, get_AnimationRate)(THIS_) PURE; + STDMETHOD(put_AnimationRate)(THIS_ int nAnimationRate) PURE; + + STDMETHOD_(bool, get_AllowDroppingSubpic)(THIS_) PURE; + STDMETHOD(put_AllowDroppingSubpic)(THIS_ bool bAllowDroppingSubpic) PURE; +}; + + +#ifdef __cplusplus +} +#endif diff --git a/src/mpc-hc/AboutDlg.cpp b/src/mpc-hc/AboutDlg.cpp index 2c31af5a483..bcce29e8329 100644 --- a/src/mpc-hc/AboutDlg.cpp +++ b/src/mpc-hc/AboutDlg.cpp @@ -1,340 +1,340 @@ -/* - * (C) 2012-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "AboutDlg.h" -#include "mpc-hc_config.h" -#ifndef MPCHC_LITE -#include "FGFilterLAV.h" -#endif -#include "mplayerc.h" -#include "FileVersionInfo.h" -#include "PathUtils.h" -#include "VersionInfo.h" -#include -#include "Monitors.h" - - -///////////////////////////////////////////////////////////////////////////// -// CAboutDlg dialog used for App About - -CAboutDlg::CAboutDlg() : CMPCThemeDialog(CAboutDlg::IDD, NULL) -{ - //{{AFX_DATA_INIT(CAboutDlg) - //}}AFX_DATA_INIT -} - -CAboutDlg::~CAboutDlg() -{ -} - -BOOL CAboutDlg::OnInitDialog() -{ - // Get the default text before it is overwritten by the call to __super::OnInitDialog() -#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)); - - m_appname = _T("MPC-HC"); - if (VersionInfo::Is64Bit()) { - m_appname += _T(" (64-bit)"); - } -#ifdef MPCHC_LITE - m_appname += _T(" (Lite)"); -#endif -#ifdef _DEBUG - m_appname += _T(" (Debug)"); -#endif - - m_homepage.Format(_T("%s"), WEBSITE_URL); - - m_strBuildNumber = VersionInfo::GetFullVersionString(); - - m_LAVFilters.Format(IDS_STRING_COLON, _T("LAV Filters")); -#ifndef MPCHC_LITE - CString LAVFiltersVersion = CFGFilterLAV::GetVersion(); - if (!LAVFiltersVersion.IsEmpty()) { - m_LAVFiltersVersion = LAVFiltersVersion; - } -#endif - - m_buildDate = VersionInfo::GetBuildDateString(); - -#pragma warning(push) -#pragma warning(disable: 4996) - OSVERSIONINFOEX osVersion = { sizeof(OSVERSIONINFOEX) }; - GetVersionEx(reinterpret_cast(&osVersion)); -#pragma warning(pop) - - if (osVersion.dwMajorVersion == 10 && osVersion.dwMinorVersion == 0) { - if (IsWindowsServer()) { - if (osVersion.dwBuildNumber > 20348) { - m_OSName = _T("Windows Server"); - } else if (osVersion.dwBuildNumber == 20348) { - m_OSName = _T("Windows Server 2022"); - } else if (osVersion.dwBuildNumber >= 19042) { - m_OSName = _T("Windows Server, version 20H2"); - } else if (osVersion.dwBuildNumber >= 19041) { - m_OSName = _T("Windows Server, version 2004"); - } else if (osVersion.dwBuildNumber >= 18363) { - m_OSName = _T("Windows Server, version 1909"); - } else if (osVersion.dwBuildNumber >= 18362) { - m_OSName = _T("Windows Server, version 1903"); - } else if (osVersion.dwBuildNumber >= 17763) { - m_OSName = _T("Windows Server 2019"); - } else { - m_OSName = _T("Windows Server 2016"); - } - } else { - if (osVersion.dwBuildNumber > 22631) { - m_OSName = _T("Windows 11"); - } else if (osVersion.dwBuildNumber == 22631) { - m_OSName = _T("Windows 11 (Build 23H2)"); - } else if (osVersion.dwBuildNumber >= 22621) { - m_OSName = _T("Windows 11 (Build 22H2)"); - } else if (osVersion.dwBuildNumber >= 22000) { - m_OSName = _T("Windows 11 (Build 21H2)"); - } else if (osVersion.dwBuildNumber >= 19046) { - m_OSName = _T("Windows 10"); - } else if (osVersion.dwBuildNumber == 19045) { - m_OSName = _T("Windows 10 (Build 22H2)"); - } else if (osVersion.dwBuildNumber == 19044) { - m_OSName = _T("Windows 10 (Build 21H2)"); - } else if (osVersion.dwBuildNumber == 19043) { - m_OSName = _T("Windows 10 (Build 21H1)"); - } else if (osVersion.dwBuildNumber == 19042) { - m_OSName = _T("Windows 10 (Build 20H2)"); - } else if (osVersion.dwBuildNumber == 19041) { - m_OSName = _T("Windows 10 (Build 2004)"); - } else if (osVersion.dwBuildNumber >= 18363) { - m_OSName = _T("Windows 10 (Build 1909)"); - } else if (osVersion.dwBuildNumber == 18362) { - m_OSName = _T("Windows 10 (Build 1903)"); - } else if (osVersion.dwBuildNumber >= 17763) { - m_OSName = _T("Windows 10 (Build 1809)"); - } else if (osVersion.dwBuildNumber >= 17134) { - m_OSName = _T("Windows 10 (Build 1803)"); - } else if (osVersion.dwBuildNumber >= 16299) { - m_OSName = _T("Windows 10 (Build 1709)"); - } else if (osVersion.dwBuildNumber >= 15063) { - m_OSName = _T("Windows 10 (Build 1703)"); - } else if (osVersion.dwBuildNumber >= 14393) { - m_OSName = _T("Windows 10 (Build 1607)"); - } else if (osVersion.dwBuildNumber >= 10586) { - m_OSName = _T("Windows 10 (Build 1511)"); - } else if (osVersion.dwBuildNumber >= 10240) { - m_OSName = _T("Windows 10 (Build 1507)"); - } else { - m_OSName = _T("Windows 10"); - } - } - } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 3) { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server 2012 R2"); - } else { - m_OSName = _T("Windows 8.1"); - } - } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 2) { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server 2012"); - } else { - m_OSName = _T("Windows 8"); - } - } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 1) { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server 2008 R2"); - } else { - m_OSName = _T("Windows 7"); - } - } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 0) { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server 2008"); - } else { - m_OSName = _T("Windows Vista"); - } - } else { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server"); - } else { - m_OSName = _T("Windows NT"); - } - } - if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion < 2 && osVersion.szCSDVersion[0]) { - m_OSName.AppendFormat(_T(" (%s)"), osVersion.szCSDVersion); - } - m_OSVersion.Format(_T("%1u.%1u.%u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber); - -#if !defined(_WIN64) - // 32-bit programs run on both 32-bit and 64-bit Windows - // so must sniff - BOOL f64 = FALSE; - if (IsWow64Process(GetCurrentProcess(), &f64) && f64) -#endif - { - m_OSVersion += _T(" (64-bit)"); - } - - UpdateData(FALSE); - - GetDlgItem(IDOK)->SetFocus(); - fulfillThemeReqs(); - - 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_HOMEPAGE_LINK, m_homepage); - DDX_Text(pDX, IDC_VERSION, m_strBuildNumber); - DDX_Text(pDX, IDC_STATIC5, m_LAVFilters); -#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, CMPCThemeDialog) - //{{AFX_MSG_MAP(CAboutDlg) - // No message handlers - //}}AFX_MSG_MAP - ON_NOTIFY(NM_CLICK, IDC_HOMEPAGE_LINK, OnHomepage) - 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::OnCopyToClipboard() -{ - CStringW info = m_appname + _T("\r\n"); - info += CString(_T('-'), m_appname.GetLength()) + _T("\r\n\r\n"); - info += _T("Build information:\r\n"); - info += _T(" Version: ") + m_strBuildNumber + _T("\r\n"); - info += _T(" Build date: ") + m_buildDate + _T("\r\n\r\n"); -#ifndef MPCHC_LITE - info += _T("LAV Filters:\r\n"); - info += _T(" LAV Splitter: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::SPLITTER) + _T("\r\n"); - info += _T(" LAV Video: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::VIDEO_DECODER) + _T("\r\n"); - info += _T(" LAV Audio: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::AUDIO_DECODER) + _T("\r\n"); - info += _T(" FFmpeg compiler: ") + VersionInfo::GetGCCVersion() + _T("\r\n\r\n"); -#endif - info += _T("Operating system:\r\n"); - info += _T(" Name: ") + m_OSName + _T("\r\n"); - info += _T(" Version: ") + m_OSVersion + _T("\r\n\r\n"); - - info += _T("Hardware:\r\n"); - - CRegKey key; - if (key.Open(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) { - ULONG nChars = 0; - if (key.QueryStringValue(_T("ProcessorNameString"), nullptr, &nChars) == ERROR_SUCCESS) { - CString cpuName; - if (key.QueryStringValue(_T("ProcessorNameString"), cpuName.GetBuffer(nChars), &nChars) == ERROR_SUCCESS) { - cpuName.ReleaseBuffer(nChars); - cpuName.Trim(); - info.AppendFormat(_T(" CPU: %s\r\n"), cpuName.GetString()); - } - } - } - - IDirect3D9* pD3D9 = Direct3DCreate9(D3D_SDK_VERSION); - if (pD3D9) { - for (UINT adapter = 0, adapterCount = pD3D9->GetAdapterCount(); adapter < adapterCount; adapter++) { - D3DADAPTER_IDENTIFIER9 adapterIdentifier; - if (pD3D9->GetAdapterIdentifier(adapter, 0, &adapterIdentifier) == D3D_OK) { - CString deviceName = adapterIdentifier.Description; - deviceName.Trim(); - - if (adapterCount > 1) { - info.AppendFormat(_T(" GPU%u: %s"), adapter + 1, deviceName.GetString()); - } else { - info.AppendFormat(_T(" GPU: %s"), deviceName.GetString()); - } - if (adapterIdentifier.DriverVersion.QuadPart) { - info.AppendFormat(_T(" (driver version: %s)"), - FileVersionInfo::FormatVersionString(adapterIdentifier.DriverVersion.LowPart, adapterIdentifier.DriverVersion.HighPart).GetString()); - } - info += _T("\r\n"); - } - } - pD3D9->Release(); - } - - auto &s = AfxGetAppSettings(); - CMonitors monitors; - - CStringW currentMonitorName; - monitors.GetNearestMonitor(AfxGetMainWnd()).GetName(currentMonitorName); - - CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); - - for (int i = 0; i < monitors.GetCount(); i++) { - CMonitor monitor = monitors.GetMonitor(i); - - if (monitor.IsMonitor()) { - CStringW displayName, deviceName; - monitor.GetNames(displayName, deviceName); - CStringW str = displayName; - - if (!deviceName.IsEmpty()) { - str.Append(L" - " + deviceName); - } - - int bpp = monitor.GetBitsPerPixel(); - CRect mr; - monitor.GetMonitorRect(mr); - int dpi = DpiHelper::GetDPIForMonitor(monitor); - CString dpis; - if (dpi > 0) { - dpis.Format(L" %i DPI", dpi); - } - str.AppendFormat(L" [%ix%i %i-bit%s]", mr.Width(), mr.Height(), bpp, dpis.GetString()); - if (displayName == currentMonitorName) { - str.AppendFormat(L" - [%s]", ResStr(IDS_FULLSCREENMONITOR_CURRENT).GetString()); - } - info.AppendFormat(L" Monitor: %s\r\n", str.GetString()); - } - } - info += _T("\r\nText:\r\n"); - double textScaleFactor = DpiHelper::GetTextScaleFactor(); - info.AppendFormat(L" Scale Factor: %f\r\n", textScaleFactor); - int cp = GetACP(); - info.AppendFormat(L" Ansi Codepage: %i\r\n", cp); - - CClipboard clipboard(this); - VERIFY(clipboard.SetText(info)); -} +/* + * (C) 2012-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "AboutDlg.h" +#include "mpc-hc_config.h" +#ifndef MPCHC_LITE +#include "FGFilterLAV.h" +#endif +#include "mplayerc.h" +#include "FileVersionInfo.h" +#include "PathUtils.h" +#include "VersionInfo.h" +#include +#include "Monitors.h" + + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +CAboutDlg::CAboutDlg() : CMPCThemeDialog(CAboutDlg::IDD, NULL) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +CAboutDlg::~CAboutDlg() +{ +} + +BOOL CAboutDlg::OnInitDialog() +{ + // Get the default text before it is overwritten by the call to __super::OnInitDialog() +#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)); + + m_appname = _T("MPC-HC"); + if (VersionInfo::Is64Bit()) { + m_appname += _T(" (64-bit)"); + } +#ifdef MPCHC_LITE + m_appname += _T(" (Lite)"); +#endif +#ifdef _DEBUG + m_appname += _T(" (Debug)"); +#endif + + m_homepage.Format(_T("%s"), WEBSITE_URL); + + m_strBuildNumber = VersionInfo::GetFullVersionString(); + + m_LAVFilters.Format(IDS_STRING_COLON, _T("LAV Filters")); +#ifndef MPCHC_LITE + CString LAVFiltersVersion = CFGFilterLAV::GetVersion(); + if (!LAVFiltersVersion.IsEmpty()) { + m_LAVFiltersVersion = LAVFiltersVersion; + } +#endif + + m_buildDate = VersionInfo::GetBuildDateString(); + +#pragma warning(push) +#pragma warning(disable: 4996) + OSVERSIONINFOEX osVersion = { sizeof(OSVERSIONINFOEX) }; + GetVersionEx(reinterpret_cast(&osVersion)); +#pragma warning(pop) + + if (osVersion.dwMajorVersion == 10 && osVersion.dwMinorVersion == 0) { + if (IsWindowsServer()) { + if (osVersion.dwBuildNumber > 20348) { + m_OSName = _T("Windows Server"); + } else if (osVersion.dwBuildNumber == 20348) { + m_OSName = _T("Windows Server 2022"); + } else if (osVersion.dwBuildNumber >= 19042) { + m_OSName = _T("Windows Server, version 20H2"); + } else if (osVersion.dwBuildNumber >= 19041) { + m_OSName = _T("Windows Server, version 2004"); + } else if (osVersion.dwBuildNumber >= 18363) { + m_OSName = _T("Windows Server, version 1909"); + } else if (osVersion.dwBuildNumber >= 18362) { + m_OSName = _T("Windows Server, version 1903"); + } else if (osVersion.dwBuildNumber >= 17763) { + m_OSName = _T("Windows Server 2019"); + } else { + m_OSName = _T("Windows Server 2016"); + } + } else { + if (osVersion.dwBuildNumber > 22631) { + m_OSName = _T("Windows 11"); + } else if (osVersion.dwBuildNumber == 22631) { + m_OSName = _T("Windows 11 (Build 23H2)"); + } else if (osVersion.dwBuildNumber >= 22621) { + m_OSName = _T("Windows 11 (Build 22H2)"); + } else if (osVersion.dwBuildNumber >= 22000) { + m_OSName = _T("Windows 11 (Build 21H2)"); + } else if (osVersion.dwBuildNumber >= 19046) { + m_OSName = _T("Windows 10"); + } else if (osVersion.dwBuildNumber == 19045) { + m_OSName = _T("Windows 10 (Build 22H2)"); + } else if (osVersion.dwBuildNumber == 19044) { + m_OSName = _T("Windows 10 (Build 21H2)"); + } else if (osVersion.dwBuildNumber == 19043) { + m_OSName = _T("Windows 10 (Build 21H1)"); + } else if (osVersion.dwBuildNumber == 19042) { + m_OSName = _T("Windows 10 (Build 20H2)"); + } else if (osVersion.dwBuildNumber == 19041) { + m_OSName = _T("Windows 10 (Build 2004)"); + } else if (osVersion.dwBuildNumber >= 18363) { + m_OSName = _T("Windows 10 (Build 1909)"); + } else if (osVersion.dwBuildNumber == 18362) { + m_OSName = _T("Windows 10 (Build 1903)"); + } else if (osVersion.dwBuildNumber >= 17763) { + m_OSName = _T("Windows 10 (Build 1809)"); + } else if (osVersion.dwBuildNumber >= 17134) { + m_OSName = _T("Windows 10 (Build 1803)"); + } else if (osVersion.dwBuildNumber >= 16299) { + m_OSName = _T("Windows 10 (Build 1709)"); + } else if (osVersion.dwBuildNumber >= 15063) { + m_OSName = _T("Windows 10 (Build 1703)"); + } else if (osVersion.dwBuildNumber >= 14393) { + m_OSName = _T("Windows 10 (Build 1607)"); + } else if (osVersion.dwBuildNumber >= 10586) { + m_OSName = _T("Windows 10 (Build 1511)"); + } else if (osVersion.dwBuildNumber >= 10240) { + m_OSName = _T("Windows 10 (Build 1507)"); + } else { + m_OSName = _T("Windows 10"); + } + } + } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 3) { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server 2012 R2"); + } else { + m_OSName = _T("Windows 8.1"); + } + } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 2) { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server 2012"); + } else { + m_OSName = _T("Windows 8"); + } + } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 1) { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server 2008 R2"); + } else { + m_OSName = _T("Windows 7"); + } + } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 0) { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server 2008"); + } else { + m_OSName = _T("Windows Vista"); + } + } else { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server"); + } else { + m_OSName = _T("Windows NT"); + } + } + if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion < 2 && osVersion.szCSDVersion[0]) { + m_OSName.AppendFormat(_T(" (%s)"), osVersion.szCSDVersion); + } + m_OSVersion.Format(_T("%1u.%1u.%u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber); + +#if !defined(_WIN64) + // 32-bit programs run on both 32-bit and 64-bit Windows + // so must sniff + BOOL f64 = FALSE; + if (IsWow64Process(GetCurrentProcess(), &f64) && f64) +#endif + { + m_OSVersion += _T(" (64-bit)"); + } + + UpdateData(FALSE); + + GetDlgItem(IDOK)->SetFocus(); + fulfillThemeReqs(); + + 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_HOMEPAGE_LINK, m_homepage); + DDX_Text(pDX, IDC_VERSION, m_strBuildNumber); + DDX_Text(pDX, IDC_STATIC5, m_LAVFilters); +#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, CMPCThemeDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP + ON_NOTIFY(NM_CLICK, IDC_HOMEPAGE_LINK, OnHomepage) + 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::OnCopyToClipboard() +{ + CStringW info = m_appname + _T("\r\n"); + info += CString(_T('-'), m_appname.GetLength()) + _T("\r\n\r\n"); + info += _T("Build information:\r\n"); + info += _T(" Version: ") + m_strBuildNumber + _T("\r\n"); + info += _T(" Build date: ") + m_buildDate + _T("\r\n\r\n"); +#ifndef MPCHC_LITE + info += _T("LAV Filters:\r\n"); + info += _T(" LAV Splitter: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::SPLITTER) + _T("\r\n"); + info += _T(" LAV Video: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::VIDEO_DECODER) + _T("\r\n"); + info += _T(" LAV Audio: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::AUDIO_DECODER) + _T("\r\n"); + info += _T(" FFmpeg compiler: ") + VersionInfo::GetGCCVersion() + _T("\r\n\r\n"); +#endif + info += _T("Operating system:\r\n"); + info += _T(" Name: ") + m_OSName + _T("\r\n"); + info += _T(" Version: ") + m_OSVersion + _T("\r\n\r\n"); + + info += _T("Hardware:\r\n"); + + CRegKey key; + if (key.Open(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) { + ULONG nChars = 0; + if (key.QueryStringValue(_T("ProcessorNameString"), nullptr, &nChars) == ERROR_SUCCESS) { + CString cpuName; + if (key.QueryStringValue(_T("ProcessorNameString"), cpuName.GetBuffer(nChars), &nChars) == ERROR_SUCCESS) { + cpuName.ReleaseBuffer(nChars); + cpuName.Trim(); + info.AppendFormat(_T(" CPU: %s\r\n"), cpuName.GetString()); + } + } + } + + IDirect3D9* pD3D9 = Direct3DCreate9(D3D_SDK_VERSION); + if (pD3D9) { + for (UINT adapter = 0, adapterCount = pD3D9->GetAdapterCount(); adapter < adapterCount; adapter++) { + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + if (pD3D9->GetAdapterIdentifier(adapter, 0, &adapterIdentifier) == D3D_OK) { + CString deviceName = adapterIdentifier.Description; + deviceName.Trim(); + + if (adapterCount > 1) { + info.AppendFormat(_T(" GPU%u: %s"), adapter + 1, deviceName.GetString()); + } else { + info.AppendFormat(_T(" GPU: %s"), deviceName.GetString()); + } + if (adapterIdentifier.DriverVersion.QuadPart) { + info.AppendFormat(_T(" (driver version: %s)"), + FileVersionInfo::FormatVersionString(adapterIdentifier.DriverVersion.LowPart, adapterIdentifier.DriverVersion.HighPart).GetString()); + } + info += _T("\r\n"); + } + } + pD3D9->Release(); + } + + auto &s = AfxGetAppSettings(); + CMonitors monitors; + + CStringW currentMonitorName; + monitors.GetNearestMonitor(AfxGetMainWnd()).GetName(currentMonitorName); + + CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); + + for (int i = 0; i < monitors.GetCount(); i++) { + CMonitor monitor = monitors.GetMonitor(i); + + if (monitor.IsMonitor()) { + CStringW displayName, deviceName; + monitor.GetNames(displayName, deviceName); + CStringW str = displayName; + + if (!deviceName.IsEmpty()) { + str.Append(L" - " + deviceName); + } + + int bpp = monitor.GetBitsPerPixel(); + CRect mr; + monitor.GetMonitorRect(mr); + int dpi = DpiHelper::GetDPIForMonitor(monitor); + CString dpis; + if (dpi > 0) { + dpis.Format(L" %i DPI", dpi); + } + str.AppendFormat(L" [%ix%i %i-bit%s]", mr.Width(), mr.Height(), bpp, dpis.GetString()); + if (displayName == currentMonitorName) { + str.AppendFormat(L" - [%s]", ResStr(IDS_FULLSCREENMONITOR_CURRENT).GetString()); + } + info.AppendFormat(L" Monitor: %s\r\n", str.GetString()); + } + } + info += _T("\r\nText:\r\n"); + double textScaleFactor = DpiHelper::GetTextScaleFactor(); + info.AppendFormat(L" Scale Factor: %f\r\n", textScaleFactor); + int cp = GetACP(); + info.AppendFormat(L" Ansi Codepage: %i\r\n", cp); + + CClipboard clipboard(this); + VERIFY(clipboard.SetText(info)); +} diff --git a/src/mpc-hc/AboutDlg.h b/src/mpc-hc/AboutDlg.h index 791da4c429b..f8e24d5c648 100644 --- a/src/mpc-hc/AboutDlg.h +++ b/src/mpc-hc/AboutDlg.h @@ -1,67 +1,67 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "resource.h" -#include "CMPCThemeDialog.h" - -class CAboutDlg : public CMPCThemeDialog -{ - CStatic m_icon; - - CString m_appname; - CString m_homepage; - - CString m_strBuildNumber; - CString m_LAVFilters; -#ifndef MPCHC_LITE - CString m_LAVFiltersVersion; -#endif - CString m_buildDate; - - CString m_OSName; - CString m_OSVersion; - -public: - CAboutDlg(); - virtual ~CAboutDlg(); - - virtual BOOL OnInitDialog(); - - // 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 - - // Implementation -protected: - //{{AFX_MSG(CAboutDlg) - afx_msg void OnCopyToClipboard(); - afx_msg void OnHomepage(NMHDR* pNMHDR, LRESULT* pResult); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; +/* + * (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 . + * + */ + +#pragma once + +#include "resource.h" +#include "CMPCThemeDialog.h" + +class CAboutDlg : public CMPCThemeDialog +{ + CStatic m_icon; + + CString m_appname; + CString m_homepage; + + CString m_strBuildNumber; + CString m_LAVFilters; +#ifndef MPCHC_LITE + CString m_LAVFiltersVersion; +#endif + CString m_buildDate; + + CString m_OSName; + CString m_OSVersion; + +public: + CAboutDlg(); + virtual ~CAboutDlg(); + + virtual BOOL OnInitDialog(); + + // 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 + + // Implementation +protected: + //{{AFX_MSG(CAboutDlg) + afx_msg void OnCopyToClipboard(); + afx_msg void OnHomepage(NMHDR* pNMHDR, LRESULT* pResult); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; diff --git a/src/mpc-hc/AppSettings.cpp b/src/mpc-hc/AppSettings.cpp index 608f1b982cb..6b6223d2562 100644 --- a/src/mpc-hc/AppSettings.cpp +++ b/src/mpc-hc/AppSettings.cpp @@ -1,3869 +1,3869 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "AppSettings.h" -#include "CrashReporter.h" -#include "FGFilter.h" -#include "FakeFilterMapper2.h" -#include "FileAssoc.h" -#include "ExceptionHandler.h" -#include "PathUtils.h" -#include "Translations.h" -#include "UpdateChecker.h" -#include "WinAPIUtils.h" -#include "moreuuids.h" -#include "mplayerc.h" -#include "../thirdparty/sanear/src/Factory.h" -#include -#include -#include -#include "date/date.h" -#include "PPageExternalFilters.h" -#include "../VideoRenderers/MPCVRAllocatorPresenter.h" -std::map CAppSettings::CommandIDToWMCMD; - -#pragma warning(push) -#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized -CAppSettings::CAppSettings() - : bInitialized(false) - , nCLSwitches(0) - , rtShift(0) - , rtStart(0) - , lDVDTitle(0) - , lDVDChapter(0) - , iMonitor(0) - , fShowDebugInfo(false) - , iAdminOption(0) - , fAllowMultipleInst(false) - , fTrayIcon(false) - , fShowOSD(true) - , fShowCurrentTimeInOSD(false) - , nOSDTransparency(64) - , nOSDBorder(1) - , fLimitWindowProportions(false) - , fSnapToDesktopEdges(false) - , fHideCDROMsSubMenu(false) - , dwPriority(NORMAL_PRIORITY_CLASS) - , iTitleBarTextStyle(1) - , fTitleBarTextTitle(false) - , fKeepHistory(true) - , iRecentFilesNumber(100) - , MRU(L"MediaHistory", iRecentFilesNumber) - , MRUDub(0, _T("Recent Dub List"), _T("Dub%d"), 20) - , fRememberDVDPos(false) - , fRememberFilePos(false) - , iRememberPosForLongerThan(5) - , bRememberPosForAudioFiles(true) - , bRememberExternalPlaylistPos(true) - , bRememberTrackSelection(true) - , bRememberPlaylistItems(true) - , fRememberWindowPos(false) - , fRememberWindowSize(false) - , rcLastWindowPos(CRect(100, 100, 500, 400)) - , fSavePnSZoom(false) - , dZoomX(1.0) - , dZoomY(1.0) - , fAssociatedWithIcons(true) - , hAccel(nullptr) - , fWinLirc(false) - , fUIce(false) - , fGlobalMedia(true) - , nLogoId(-1) - , fLogoExternal(false) - , fLogoColorProfileEnabled(false) - , fEnableWebServer(false) - , nWebServerPort(13579) - , nCmdlnWebServerPort(-1) - , fWebServerUseCompression(true) - , fWebServerLocalhostOnly(false) - , bWebUIEnablePreview(false) - , fWebServerPrintDebugInfo(false) - , nVolume(100) - , fMute(false) - , nBalance(0) - , nLoops(1) - , fLoopForever(false) - , eLoopMode(LoopMode::PLAYLIST) - , fRememberZoomLevel(true) - , nAutoFitFactorMin(75) - , nAutoFitFactorMax(75) - , iZoomLevel(1) - , fEnableWorkerThreadForOpening(true) - , fReportFailedPins(true) - , fAutoloadAudio(true) - , fBlockVSFilter(true) - , bBlockRDP(false) - , nVolumeStep(5) - , nSpeedStep(0) - , nDefaultToolbarSize(24) - , eAfterPlayback(AfterPlayback::DO_NOTHING) - , fUseDVDPath(false) - , idMenuLang(0) - , idAudioLang(0) - , idSubtitlesLang(0) - , fClosedCaptions(false) - , iDSVideoRendererType(VIDRNDT_DS_DEFAULT) - , fD3DFullscreen(false) - , fLaunchfullscreen(false) - , bHideFullscreenControls(true) - , eHideFullscreenControlsPolicy(HideFullscreenControlsPolicy::SHOW_WHEN_HOVERED) - , uHideFullscreenControlsDelay(0) - , bHideFullscreenDockedPanels(true) - , fExitFullScreenAtTheEnd(true) - , iDefaultCaptureDevice(0) - , iAnalogCountry(1) - , iBDAScanFreqStart(474000) - , iBDAScanFreqEnd(858000) - , iBDABandwidth(8) - , iBDASymbolRate(0) - , fBDAUseOffset(false) - , iBDAOffset(166) - , fBDAIgnoreEncryptedChannels(false) - , nDVBLastChannel(INT_ERROR) - , nDVBRebuildFilterGraph(DVB_REBUILD_FG_WHEN_SWITCHING) - , nDVBStopFilterGraph(DVB_STOP_FG_WHEN_SWITCHING) - , SrcFilters() - , TraFilters() - , fEnableAudioSwitcher(true) - , fAudioNormalize(false) - , nAudioMaxNormFactor(400) - , fAudioNormalizeRecover(true) - , nAudioBoost(0) - , fDownSampleTo441(false) - , fAudioTimeShift(false) - , iAudioTimeShift(0) - , fCustomChannelMapping(false) - , nSpeakerChannels(2) - , pSpeakerToChannelMap() - , fOverridePlacement(false) - , nHorPos(50) - , nVerPos(90) - , bSubtitleARCompensation(true) - , nSubDelayStep(500) - , bPreferDefaultForcedSubtitles(true) - , fPrioritizeExternalSubtitles(true) - , fDisableInternalSubtitles(true) - , bAllowOverridingExternalSplitterChoice(false) - , bAutoDownloadSubtitles(false) - , bAutoSaveDownloadedSubtitles(false) - , nAutoDownloadScoreMovies(0x16) - , nAutoDownloadScoreSeries(0x18) - , bAutoUploadSubtitles(false) - , bPreferHearingImpairedSubtitles(false) - , bMPCTheme(true) - , bWindows10DarkThemeActive(false) - , bWindows10AccentColorsEnabled(false) - , iModernSeekbarHeight(DEF_MODERN_SEEKBAR_HEIGHT) - , eModernThemeMode(CMPCTheme::ModernThemeMode::WINDOWSDEFAULT) - , iFullscreenDelay(MIN_FULLSCREEN_DELAY) - , iVerticalAlignVideo(verticalAlignVideoType::ALIGN_MIDDLE) - , nJumpDistS(DEFAULT_JUMPDISTANCE_1) - , nJumpDistM(DEFAULT_JUMPDISTANCE_2) - , nJumpDistL(DEFAULT_JUMPDISTANCE_3) - , bFastSeek(true) - , eFastSeekMethod(FASTSEEK_NEAREST_KEYFRAME) - , fShowChapters(true) - , bNotifySkype(false) - , fPreventMinimize(false) - , bUseEnhancedTaskBar(true) - , fLCDSupport(false) - , fSeekPreview(false) - , iSeekPreviewSize(15) - , fUseSearchInFolder(false) - , fUseSeekbarHover(true) - , nHoverPosition(TIME_TOOLTIP_ABOVE_SEEKBAR) - , nOSDSize(0) - , bHideWindowedMousePointer(true) - , iBrightness(0) - , iContrast(0) - , iHue(0) - , iSaturation(0) - , nUpdaterAutoCheck(-1) - , nUpdaterDelay(7) - , eCaptionMenuMode(MODE_SHOWCAPTIONMENU) - , fHideNavigation(false) - , nCS(CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR) - , language(LANGID(-1)) - , fEnableSubtitles(true) - , bSubtitleOverrideDefaultStyle(false) - , bSubtitleOverrideAllStyles(false) - , iDefaultVideoSize(DVS_FROMINSIDE) - , fKeepAspectRatio(true) - , fCompMonDeskARDiff(false) - , iOnTop(0) - , bFavRememberPos(true) - , bFavRelativeDrive(false) - , bFavRememberABMarks(false) - , iThumbRows(4) - , iThumbCols(4) - , iThumbWidth(1024) - , bSubSaveExternalStyleFile(false) - , bShufflePlaylistItems(false) - , bHidePlaylistFullScreen(false) - , nLastWindowType(SIZE_RESTORED) - , nLastUsedPage(0) - , fRemainingTime(false) - , bHighPrecisionTimer(false) - , bTimerShowPercentage(false) - , fLastFullScreen(false) - , fEnableEDLEditor(false) - , hMasterWnd(nullptr) - , bHideWindowedControls(false) - , nJpegQuality(90) - , bEnableCoverArt(true) - , nCoverArtSizeLimit(600) - , bEnableLogging(false) - , bUseLegacyToolbar(false) - , iLAVGPUDevice(DWORD_MAX) - , nCmdVolume(0) - , eSubtitleRenderer(SubtitleRenderer::INTERNAL) - , bUseYDL(true) - , iYDLMaxHeight(1440) - , iYDLVideoFormat(0) - , iYDLAudioFormat(0) - , bYDLAudioOnly(false) - , sYDLExePath(_T("")) - , sYDLCommandLine(_T("")) - , bSnapShotSubtitles(true) - , bSnapShotKeepVideoExtension(true) - , bEnableCrashReporter(true) - , nStreamPosPollerInterval(100) - , bShowLangInStatusbar(false) - , bShowFPSInStatusbar(false) - , bShowABMarksInStatusbar(false) - , bShowVideoInfoInStatusbar(true) - , bShowAudioFormatInStatusbar(true) -#if USE_LIBASS - , bRenderSSAUsingLibass(false) - , bRenderSRTUsingLibass(false) -#endif - , bAddLangCodeWhenSaveSubtitles(false) - , bUseTitleInRecentFileList(true) - , sYDLSubsPreference() - , bUseAutomaticCaptions(false) - , bLockNoPause(false) - , bPreventDisplaySleep(true) - , bUseSMTC(false) - , iReloadAfterLongPause(0) - , bOpenRecPanelWhenOpeningDevice(true) - , lastQuickOpenPath(L"") - , lastFileSaveCopyPath(L"") - , lastFileOpenDirPath(L"") - , externalPlayListPath(L"") - , iRedirectOpenToAppendThreshold(1000) - , bFullscreenSeparateControls(true) - , bAlwaysUseShortMenu(false) - , iStillVideoDuration(10) - , iMouseLeftUpDelay(0) - , bUseFreeType(false) - , bUseMediainfoLoadFileDuration(false) - , bCaptureDeinterlace(false) - , bPauseWhileDraggingSeekbar(true) - , bConfirmFileDelete(true) -{ - // Internal source filter -#if INTERNAL_SOURCEFILTER_AC3 - SrcFiltersKeys[SRC_AC3] = FilterKey(_T("SRC_AC3"), true); -#endif -#if INTERNAL_SOURCEFILTER_ASF - SrcFiltersKeys[SRC_ASF] = FilterKey(_T("SRC_ASF"), false); -#endif -#if INTERNAL_SOURCEFILTER_AVI - SrcFiltersKeys[SRC_AVI] = FilterKey(_T("SRC_AVI"), true); -#endif -#if INTERNAL_SOURCEFILTER_AVS - SrcFiltersKeys[SRC_AVS] = FilterKey(_T("SRC_AVS"), true); -#endif -#if INTERNAL_SOURCEFILTER_DTS - SrcFiltersKeys[SRC_DTS] = FilterKey(_T("SRC_DTS"), true); -#endif -#if INTERNAL_SOURCEFILTER_FLAC - SrcFiltersKeys[SRC_FLAC] = FilterKey(_T("SRC_FLAC"), true); -#endif -#if INTERNAL_SOURCEFILTER_FLIC - SrcFiltersKeys[SRC_FLIC] = FilterKey(_T("SRC_FLIC"), true); -#endif -#if INTERNAL_SOURCEFILTER_FLV - SrcFiltersKeys[SRC_FLV] = FilterKey(_T("SRC_FLV"), true); -#endif -#if INTERNAL_SOURCEFILTER_GIF - SrcFiltersKeys[SRC_GIF] = FilterKey(_T("SRC_GIF"), true); -#endif -#if INTERNAL_SOURCEFILTER_HTTP - SrcFiltersKeys[SRC_HTTP] = FilterKey(_T("SRC_HTTP"), true); -#endif -#if INTERNAL_SOURCEFILTER_MATROSKA - SrcFiltersKeys[SRC_MATROSKA] = FilterKey(_T("SRC_MATROSKA"), true); -#endif -#if INTERNAL_SOURCEFILTER_MISC - SrcFiltersKeys[SRC_MISC] = FilterKey(_T("SRC_MISC"), true); -#endif -#if INTERNAL_SOURCEFILTER_MMS - SrcFiltersKeys[SRC_MMS] = FilterKey(_T("SRC_MMS"), true); -#endif -#if INTERNAL_SOURCEFILTER_MP4 - SrcFiltersKeys[SRC_MP4] = FilterKey(_T("SRC_MP4"), true); -#endif -#if INTERNAL_SOURCEFILTER_MPEGAUDIO - SrcFiltersKeys[SRC_MPA] = FilterKey(_T("SRC_MPA"), true); -#endif -#if INTERNAL_SOURCEFILTER_MPEG - SrcFiltersKeys[SRC_MPEG] = FilterKey(_T("SRC_MPEG"), true); - SrcFiltersKeys[SRC_MPEGTS] = FilterKey(_T("SRC_MPEGTS"), true); -#endif -#if INTERNAL_SOURCEFILTER_OGG - SrcFiltersKeys[SRC_OGG] = FilterKey(_T("SRC_OGG"), true); -#endif -#if INTERNAL_SOURCEFILTER_REALMEDIA - SrcFiltersKeys[SRC_REALMEDIA] = FilterKey(_T("SRC_REALMEDIA"), true); -#endif -#if INTERNAL_SOURCEFILTER_RTMP - SrcFiltersKeys[SRC_RTMP] = FilterKey(_T("SRC_RTMP"), true); -#endif -#if INTERNAL_SOURCEFILTER_RTP - SrcFiltersKeys[SRC_RTP] = FilterKey(_T("SRC_RTP"), true); -#endif -#if INTERNAL_SOURCEFILTER_RTSP - SrcFiltersKeys[SRC_RTSP] = FilterKey(_T("SRC_RTSP"), true); -#endif -#if INTERNAL_SOURCEFILTER_RTSP - SrcFiltersKeys[SRC_UDP] = FilterKey(_T("SRC_UDP"), true); -#endif -#if INTERNAL_SOURCEFILTER_WTV - SrcFiltersKeys[SRC_WTV] = FilterKey(_T("SRC_WTV"), true); -#endif -#if INTERNAL_SOURCEFILTER_CDDA - SrcFiltersKeys[SRC_CDDA] = FilterKey(_T("SRC_CDDA"), true); -#endif -#if INTERNAL_SOURCEFILTER_CDXA - SrcFiltersKeys[SRC_CDXA] = FilterKey(_T("SRC_CDXA"), true); -#endif -#if INTERNAL_SOURCEFILTER_DSM - SrcFiltersKeys[SRC_DSM] = FilterKey(_T("SRC_DSM"), true); -#endif -#if INTERNAL_SOURCEFILTER_RFS - SrcFiltersKeys[SRC_RFS] = FilterKey(_T("SRC_RFS"), true); -#endif -#if INTERNAL_SOURCEFILTER_VTS - SrcFiltersKeys[SRC_VTS] = FilterKey(_T("SRC_VTS"), true); -#endif - - // Internal decoders -#if INTERNAL_DECODER_MPEG1 - TraFiltersKeys[TRA_MPEG1] = FilterKey(_T("TRA_MPEG1"), true); -#endif -#if INTERNAL_DECODER_MPEG2 - TraFiltersKeys[TRA_MPEG2] = FilterKey(_T("TRA_MPEG2"), true); -#endif -#if INTERNAL_DECODER_REALVIDEO - TraFiltersKeys[TRA_RV] = FilterKey(_T("TRA_RV"), true); -#endif -#if INTERNAL_DECODER_REALAUDIO - TraFiltersKeys[TRA_RA] = FilterKey(_T("TRA_RA"), true); -#endif -#if INTERNAL_DECODER_MPEGAUDIO - TraFiltersKeys[TRA_MPA] = FilterKey(_T("TRA_MPA"), true); -#endif -#if INTERNAL_DECODER_DTS - TraFiltersKeys[TRA_DTS] = FilterKey(_T("TRA_DTS"), true); -#endif -#if INTERNAL_DECODER_LPCM - TraFiltersKeys[TRA_LPCM] = FilterKey(_T("TRA_LPCM"), true); -#endif -#if INTERNAL_DECODER_AC3 - TraFiltersKeys[TRA_AC3] = FilterKey(_T("TRA_AC3"), true); -#endif -#if INTERNAL_DECODER_AAC - TraFiltersKeys[TRA_AAC] = FilterKey(_T("TRA_AAC"), true); -#endif -#if INTERNAL_DECODER_ALAC - TraFiltersKeys[TRA_ALAC] = FilterKey(_T("TRA_ALAC"), true); -#endif -#if INTERNAL_DECODER_ALS - TraFiltersKeys[TRA_ALS] = FilterKey(_T("TRA_ALS"), true); -#endif -#if INTERNAL_DECODER_PS2AUDIO - TraFiltersKeys[TRA_PS2AUD] = FilterKey(_T("TRA_PS2AUD"), true); -#endif -#if INTERNAL_DECODER_VORBIS - TraFiltersKeys[TRA_VORBIS] = FilterKey(_T("TRA_VORBIS"), true); -#endif -#if INTERNAL_DECODER_FLAC - TraFiltersKeys[TRA_FLAC] = FilterKey(_T("TRA_FLAC"), true); -#endif -#if INTERNAL_DECODER_NELLYMOSER - TraFiltersKeys[TRA_NELLY] = FilterKey(_T("TRA_NELLY"), true); -#endif -#if INTERNAL_DECODER_AMR - TraFiltersKeys[TRA_AMR] = FilterKey(_T("TRA_AMR"), true); -#endif -#if INTERNAL_DECODER_OPUS - TraFiltersKeys[TRA_OPUS] = FilterKey(_T("TRA_OPUS"), true); -#endif -#if INTERNAL_DECODER_WMA - TraFiltersKeys[TRA_WMA] = FilterKey(_T("TRA_WMA"), false); -#endif -#if INTERNAL_DECODER_WMAPRO - TraFiltersKeys[TRA_WMAPRO] = FilterKey(_T("TRA_WMAPRO"), false); -#endif -#if INTERNAL_DECODER_WMALL - TraFiltersKeys[TRA_WMALL] = FilterKey(_T("TRA_WMALL"), false); -#endif -#if INTERNAL_DECODER_G726 - TraFiltersKeys[TRA_G726] = FilterKey(_T("TRA_G726"), true); -#endif -#if INTERNAL_DECODER_G729 - TraFiltersKeys[TRA_G729] = FilterKey(_T("TRA_G729"), true); -#endif -#if INTERNAL_DECODER_OTHERAUDIO - TraFiltersKeys[TRA_OTHERAUDIO] = FilterKey(_T("TRA_OTHERAUDIO"), true); -#endif -#if INTERNAL_DECODER_PCM - TraFiltersKeys[TRA_PCM] = FilterKey(_T("TRA_PCM"), true); -#endif -#if INTERNAL_DECODER_H264 - TraFiltersKeys[TRA_H264] = FilterKey(_T("TRA_H264"), true); -#endif -#if INTERNAL_DECODER_HEVC - TraFiltersKeys[TRA_HEVC] = FilterKey(_T("TRA_HEVC"), true); -#endif -#if INTERNAL_DECODER_VVC - TraFiltersKeys[TRA_VVC] = FilterKey(_T("TRA_VVC"), true); -#endif -#if INTERNAL_DECODER_AV1 - TraFiltersKeys[TRA_AV1] = FilterKey(_T("TRA_AV1"), true); -#endif -#if INTERNAL_DECODER_VC1 - TraFiltersKeys[TRA_VC1] = FilterKey(_T("TRA_VC1"), true); -#endif -#if INTERNAL_DECODER_FLV - TraFiltersKeys[TRA_FLV4] = FilterKey(_T("TRA_FLV4"), true); -#endif -#if INTERNAL_DECODER_VP356 - TraFiltersKeys[TRA_VP356] = FilterKey(_T("TRA_VP356"), true); -#endif -#if INTERNAL_DECODER_VP8 - TraFiltersKeys[TRA_VP8] = FilterKey(_T("TRA_VP8"), true); -#endif -#if INTERNAL_DECODER_VP9 - TraFiltersKeys[TRA_VP9] = FilterKey(_T("TRA_VP9"), true); -#endif -#if INTERNAL_DECODER_XVID - TraFiltersKeys[TRA_XVID] = FilterKey(_T("TRA_XVID"), true); -#endif -#if INTERNAL_DECODER_DIVX - TraFiltersKeys[TRA_DIVX] = FilterKey(_T("TRA_DIVX"), true); -#endif -#if INTERNAL_DECODER_MSMPEG4 - TraFiltersKeys[TRA_MSMPEG4] = FilterKey(_T("TRA_MSMPEG4"), true); -#endif -#if INTERNAL_DECODER_WMV - TraFiltersKeys[TRA_WMV] = FilterKey(_T("TRA_WMV"), false); -#endif -#if INTERNAL_DECODER_SVQ - TraFiltersKeys[TRA_SVQ3] = FilterKey(_T("TRA_SVQ3"), true); -#endif -#if INTERNAL_DECODER_H263 - TraFiltersKeys[TRA_H263] = FilterKey(_T("TRA_H263"), true); -#endif -#if INTERNAL_DECODER_THEORA - TraFiltersKeys[TRA_THEORA] = FilterKey(_T("TRA_THEORA"), true); -#endif -#if INTERNAL_DECODER_AMVV - TraFiltersKeys[TRA_AMVV] = FilterKey(_T("TRA_AMVV"), true); -#endif -#if INTERNAL_DECODER_MJPEG - TraFiltersKeys[TRA_MJPEG] = FilterKey(_T("TRA_MJPEG"), true); -#endif -#if INTERNAL_DECODER_INDEO - TraFiltersKeys[TRA_INDEO] = FilterKey(_T("TRA_INDEO"), true); -#endif -#if INTERNAL_DECODER_SCREEN - TraFiltersKeys[TRA_SCREEN] = FilterKey(_T("TRA_SCREEN"), true); -#endif -#if INTERNAL_DECODER_FLIC - TraFiltersKeys[TRA_FLIC] = FilterKey(_T("TRA_FLIC"), true); -#endif -#if INTERNAL_DECODER_MSVIDEO - TraFiltersKeys[TRA_MSVIDEO] = FilterKey(_T("TRA_MSVIDEO"), true); -#endif -#if INTERNAL_DECODER_V210_V410 - TraFiltersKeys[TRA_V210_V410] = FilterKey(_T("TRA_V210_V410"), false); -#endif -#if INTERNAL_DECODER_PRORES - TraFiltersKeys[TRA_PRORES] = FilterKey(_T("TRA_PRORES"), true); -#endif -#if INTERNAL_DECODER_DNXHD - TraFiltersKeys[TRA_DNXHD] = FilterKey(_T("TRA_DNXHD"), true); -#endif -#if INTERNAL_DECODER_OTHERVIDEO - TraFiltersKeys[TRA_OTHERVIDEO] = FilterKey(_T("TRA_OTHERVIDEO"), true); -#endif - - ZeroMemory(&DVDPosition, sizeof(DVDPosition)); - - ENSURE(SUCCEEDED(SaneAudioRenderer::Factory::CreateSettings(&sanear))); - - // Mouse - nMouseLeftClick = ID_PLAY_PLAYPAUSE; - nMouseLeftDblClick = ID_VIEW_FULLSCREEN; - nMouseRightClick = ID_MENU_PLAYER_SHORT; - MouseMiddleClick = { 0, 0, 0, 0 }; - MouseX1Click = { ID_NAVIGATE_SKIPBACK, 0, 0, 0 }; - MouseX2Click = { ID_NAVIGATE_SKIPFORWARD, 0, 0, 0 }; - MouseWheelUp = { ID_VOLUME_UP, ID_PLAY_SEEKFORWARDLARGE, 0, ID_PLAY_SEEKFORWARDLARGE }; - MouseWheelDown = { ID_VOLUME_DOWN, ID_PLAY_SEEKBACKWARDLARGE, 0, ID_PLAY_SEEKBACKWARDLARGE }; - MouseWheelLeft = { 0, 0, 0, 0 }; - MouseWheelRight = { 0, 0, 0, 0 }; - bMouseLeftClickOpenRecent = false; - bMouseEasyMove = true; - -} -#pragma warning(pop) - -/* Note: the mouse commands in this list are no longer being used. Mouse binding are now stored elsewhere. - * They are included for backwards compatibility. - */ -static constexpr wmcmd_base default_wmcmds[] = { - { ID_FILE_OPENQUICK, 'Q', FCONTROL, IDS_MPLAYERC_0 }, - { ID_FILE_OPENMEDIA, 'O', FCONTROL, IDS_AG_OPEN_FILE }, - { ID_FILE_OPENDVDBD, 'D', FCONTROL, IDS_AG_OPEN_DVD }, - { ID_FILE_OPENDEVICE, 'V', FCONTROL, IDS_AG_OPEN_DEVICE }, - { ID_FILE_OPENDIRECTORY, 0, 0, IDS_AG_OPENDIRECTORY }, - { ID_FILE_REOPEN, 'E', FCONTROL, IDS_AG_REOPEN }, - { ID_FILE_RECYCLE, VK_DELETE, 0, IDS_FILE_RECYCLE }, - { ID_FILE_SAVE_COPY, 0, 0, IDS_AG_SAVE_COPY }, - { ID_FILE_SAVE_IMAGE, 'I', FALT, IDS_AG_SAVE_IMAGE }, - { ID_FILE_SAVE_IMAGE_AUTO, VK_F5, 0, IDS_MPLAYERC_6 }, - { ID_FILE_SAVE_THUMBNAILS, 0, 0, IDS_FILE_SAVE_THUMBNAILS }, - { ID_FILE_SUBTITLES_LOAD, 'L', FCONTROL, IDS_AG_LOAD_SUBTITLES }, - { ID_FILE_SUBTITLES_SAVE, 'S', FCONTROL, IDS_AG_SAVE_SUBTITLES }, - { ID_FILE_SUBTITLES_DOWNLOAD, 'D', 0, IDS_SUBTITLES_DOWNLOAD }, - { ID_FILE_CLOSE_AND_RESTORE, 'C', FCONTROL, IDS_AG_CLOSE }, - { ID_FILE_PROPERTIES, VK_F10, FSHIFT, IDS_AG_PROPERTIES }, - { ID_FILE_OPEN_LOCATION, VK_F10, FCONTROL | FSHIFT, IDS_AG_OPEN_FILE_LOCATION }, - { ID_FILE_EXIT, 'X', FALT, IDS_AG_EXIT }, - { ID_PLAY_PLAYPAUSE, VK_SPACE, 0, IDS_AG_PLAYPAUSE, APPCOMMAND_MEDIA_PLAY_PAUSE, wmcmd::LUP }, - { ID_PLAY_PLAY, 0, 0, IDS_AG_PLAY, APPCOMMAND_MEDIA_PLAY }, - { ID_PLAY_PAUSE, 0, 0, IDS_AG_PAUSE, APPCOMMAND_MEDIA_PAUSE }, - { ID_PLAY_STOP, VK_OEM_PERIOD, 0, IDS_AG_STOP, APPCOMMAND_MEDIA_STOP }, - { ID_PLAY_FRAMESTEP, VK_RIGHT, FCONTROL, IDS_AG_FRAMESTEP }, - { ID_PLAY_FRAMESTEP_BACK, VK_LEFT, FCONTROL, IDS_MPLAYERC_16 }, - { ID_NAVIGATE_GOTO, 'G', FCONTROL, IDS_AG_GO_TO }, - { ID_PLAY_INCRATE, VK_UP, FCONTROL, IDS_AG_INCREASE_RATE }, - { ID_PLAY_DECRATE, VK_DOWN, FCONTROL, IDS_AG_DECREASE_RATE }, - { ID_PLAY_RESETRATE, 'R', FCONTROL, IDS_AG_RESET_RATE }, - { ID_PLAY_INCAUDDELAY, VK_ADD, 0, IDS_MPLAYERC_21 }, - { ID_PLAY_DECAUDDELAY, VK_SUBTRACT, 0, IDS_MPLAYERC_22 }, - { ID_PLAY_SEEKFORWARDSMALL, 0, 0, IDS_MPLAYERC_23 }, - { ID_PLAY_SEEKBACKWARDSMALL, 0, 0, IDS_MPLAYERC_24 }, - { ID_PLAY_SEEKFORWARDMED, VK_RIGHT, 0, IDS_MPLAYERC_25 }, - { ID_PLAY_SEEKBACKWARDMED, VK_LEFT, 0, IDS_MPLAYERC_26 }, - { ID_PLAY_SEEKFORWARDLARGE, 0, 0, IDS_MPLAYERC_27, 0, wmcmd::WUP, FVIRTKEY | FCONTROL }, - { ID_PLAY_SEEKBACKWARDLARGE, 0, 0, IDS_MPLAYERC_28, 0, wmcmd::WDOWN, FVIRTKEY | FCONTROL }, - { ID_PLAY_SEEKKEYFORWARD, VK_RIGHT, FSHIFT, IDS_MPLAYERC_29 }, - { ID_PLAY_SEEKKEYBACKWARD, VK_LEFT, FSHIFT, IDS_MPLAYERC_30 }, - { ID_PLAY_SEEKSET, VK_HOME, 0, IDS_AG_SEEKSET }, - { ID_PLAY_REPEAT_FOREVER, 0, 0, IDS_PLAYLOOP_FOREVER }, - { ID_PLAY_REPEAT_ONEFILE, 0, 0, IDS_PLAYLOOPMODE_FILE }, - { ID_PLAY_REPEAT_WHOLEPLAYLIST, 0, 0, IDS_PLAYLOOPMODE_PLAYLIST }, - { ID_PLAY_REPEAT_AB, 0, 0, IDS_PLAYLOOPMODE_AB }, - { ID_PLAY_REPEAT_AB_MARK_A, VK_OEM_4, 0, IDS_PLAYLOOPMODE_AB_MARK_A }, - { ID_PLAY_REPEAT_AB_MARK_B, VK_OEM_6, 0, IDS_PLAYLOOPMODE_AB_MARK_B }, - { ID_NAVIGATE_SKIPFORWARD, VK_NEXT, 0, IDS_AG_NEXT, APPCOMMAND_MEDIA_NEXTTRACK, wmcmd::X2DOWN }, - { ID_NAVIGATE_SKIPBACK, VK_PRIOR, 0, IDS_AG_PREVIOUS, APPCOMMAND_MEDIA_PREVIOUSTRACK, wmcmd::X1DOWN }, - { ID_NAVIGATE_SKIPFORWARDFILE, VK_NEXT, FCONTROL, IDS_AG_NEXT_FILE }, - { ID_NAVIGATE_SKIPBACKFILE, VK_PRIOR, FCONTROL, IDS_AG_PREVIOUS_FILE }, - { ID_NAVIGATE_TUNERSCAN, 'T', FSHIFT, IDS_NAVIGATE_TUNERSCAN }, - { ID_FAVORITES_QUICKADDFAVORITE, 'Q', FSHIFT, IDS_FAVORITES_QUICKADDFAVORITE }, - { ID_FAVORITES_ORGANIZE, 0, 0, IDS_FAVORITES_ORGANIZE }, - { ID_VIEW_CAPTIONMENU, '0', FCONTROL, IDS_AG_TOGGLE_CAPTION }, - { ID_VIEW_SEEKER, '1', FCONTROL, IDS_AG_TOGGLE_SEEKER }, - { ID_VIEW_CONTROLS, '2', FCONTROL, IDS_AG_TOGGLE_CONTROLS }, - { ID_VIEW_INFORMATION, '3', FCONTROL, IDS_AG_TOGGLE_INFO }, - { ID_VIEW_STATISTICS, '4', FCONTROL, IDS_AG_TOGGLE_STATS }, - { ID_VIEW_STATUS, '5', FCONTROL, IDS_AG_TOGGLE_STATUS }, - { ID_VIEW_SUBRESYNC, '6', FCONTROL, IDS_AG_TOGGLE_SUBRESYNC }, - { ID_VIEW_PLAYLIST, '7', FCONTROL, IDS_AG_TOGGLE_PLAYLIST }, - { ID_VIEW_CAPTURE, '8', FCONTROL, IDS_AG_TOGGLE_CAPTURE }, - { ID_VIEW_NAVIGATION, '9', FCONTROL, IDS_AG_TOGGLE_NAVIGATION }, - { ID_VIEW_DEBUGSHADERS, 0, 0, IDS_AG_TOGGLE_DEBUGSHADERS }, - { ID_PRESIZE_SHADERS_TOGGLE, 'P', FCONTROL, IDS_PRESIZE_SHADERS_TOGGLE }, - { ID_POSTSIZE_SHADERS_TOGGLE, 'P', FCONTROL | FALT, IDS_POSTSIZE_SHADERS_TOGGLE }, - { ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE, 0, 0, IDS_AG_TOGGLE_DEFAULT_SUBTITLE_STYLE }, - { ID_VIEW_PRESETS_MINIMAL, '1', 0, IDS_AG_VIEW_MINIMAL }, - { ID_VIEW_PRESETS_COMPACT, '2', 0, IDS_AG_VIEW_COMPACT }, - { ID_VIEW_PRESETS_NORMAL, '3', 0, IDS_AG_VIEW_NORMAL }, - { ID_VIEW_FULLSCREEN, VK_RETURN, FALT, IDS_AG_FULLSCREEN, 0, wmcmd::LDBLCLK }, - { ID_VIEW_FULLSCREEN_SECONDARY, VK_F11, 0, IDS_MPLAYERC_39 }, - { ID_VIEW_ZOOM_25, VK_OEM_3, FALT, IDS_AG_ZOOM_25 }, /* VK_OEM_3 is `~ on US keyboards*/ - { ID_VIEW_ZOOM_50, '1', FALT, IDS_AG_ZOOM_50 }, - { ID_VIEW_ZOOM_100, '2', FALT, IDS_AG_ZOOM_100 }, - { ID_VIEW_ZOOM_200, '3', FALT, IDS_AG_ZOOM_200 }, - { ID_VIEW_ZOOM_AUTOFIT, '4', FALT, IDS_AG_ZOOM_AUTO_FIT }, - { ID_VIEW_ZOOM_AUTOFIT_LARGER, '5', FALT, IDS_AG_ZOOM_AUTO_FIT_LARGER }, - { ID_VIEW_ZOOM_ADD, 0, 0, IDS_AG_ZOOM_ADD }, - { ID_VIEW_ZOOM_SUB, 0, 0, IDS_AG_ZOOM_SUB }, - { ID_ASPECTRATIO_NEXT, 0, 0, IDS_AG_NEXT_AR_PRESET }, - { ID_VIEW_VF_HALF, 0, 0, IDS_AG_VIDFRM_HALF }, - { ID_VIEW_VF_NORMAL, 0, 0, IDS_AG_VIDFRM_NORMAL }, - { ID_VIEW_VF_DOUBLE, 0, 0, IDS_AG_VIDFRM_DOUBLE }, - { ID_VIEW_VF_STRETCH, 0, 0, IDS_AG_VIDFRM_STRETCH }, - { ID_VIEW_VF_FROMINSIDE, 0, 0, IDS_AG_VIDFRM_INSIDE }, - { ID_VIEW_VF_ZOOM1, 0, 0, IDS_AG_VIDFRM_ZOOM1 }, - { ID_VIEW_VF_ZOOM2, 0, 0, IDS_AG_VIDFRM_ZOOM2 }, - { ID_VIEW_VF_FROMOUTSIDE, 0, 0, IDS_AG_VIDFRM_OUTSIDE }, - { ID_VIEW_VF_SWITCHZOOM, 0, 0, IDS_AG_VIDFRM_SWITCHZOOM }, - { ID_ONTOP_ALWAYS, 'A', FCONTROL, IDS_AG_ALWAYS_ON_TOP }, - { ID_VIEW_RESET, VK_NUMPAD5, 0, IDS_AG_PNS_RESET }, - { ID_VIEW_INCSIZE, VK_NUMPAD9, 0, IDS_AG_PNS_INC_SIZE }, - { ID_VIEW_INCWIDTH, VK_NUMPAD6, 0, IDS_AG_PNS_INC_WIDTH }, - { ID_VIEW_INCHEIGHT, VK_NUMPAD8, 0, IDS_MPLAYERC_47 }, - { ID_VIEW_DECSIZE, VK_NUMPAD1, 0, IDS_AG_PNS_DEC_SIZE }, - { ID_VIEW_DECWIDTH, VK_NUMPAD4, 0, IDS_AG_PNS_DEC_WIDTH }, - { ID_VIEW_DECHEIGHT, VK_NUMPAD2, 0, IDS_MPLAYERC_50 }, - { ID_PANSCAN_CENTER, VK_NUMPAD5, FCONTROL, IDS_AG_PNS_CENTER }, - { ID_PANSCAN_MOVELEFT, VK_NUMPAD4, FCONTROL, IDS_AG_PNS_LEFT }, - { ID_PANSCAN_MOVERIGHT, VK_NUMPAD6, FCONTROL, IDS_AG_PNS_RIGHT }, - { ID_PANSCAN_MOVEUP, VK_NUMPAD8, FCONTROL, IDS_AG_PNS_UP }, - { ID_PANSCAN_MOVEDOWN, VK_NUMPAD2, FCONTROL, IDS_AG_PNS_DOWN }, - { ID_PANSCAN_MOVEUPLEFT, VK_NUMPAD7, FCONTROL, IDS_AG_PNS_UPLEFT }, - { ID_PANSCAN_MOVEUPRIGHT, VK_NUMPAD9, FCONTROL, IDS_AG_PNS_UPRIGHT }, - { ID_PANSCAN_MOVEDOWNLEFT, VK_NUMPAD1, FCONTROL, IDS_AG_PNS_DOWNLEFT }, - { ID_PANSCAN_MOVEDOWNRIGHT, VK_NUMPAD3, FCONTROL, IDS_MPLAYERC_59 }, - { ID_PANSCAN_ROTATEXP, VK_NUMPAD8, FALT, IDS_AG_PNS_ROTATEX_P }, - { ID_PANSCAN_ROTATEXM, VK_NUMPAD2, FALT, IDS_AG_PNS_ROTATEX_M }, - { ID_PANSCAN_ROTATEYP, VK_NUMPAD4, FALT, IDS_AG_PNS_ROTATEY_P }, - { ID_PANSCAN_ROTATEYM, VK_NUMPAD6, FALT, IDS_AG_PNS_ROTATEY_M }, - { ID_PANSCAN_ROTATEZP, VK_NUMPAD1, FALT, IDS_AG_PNS_ROTATEZ_P }, - { ID_PANSCAN_ROTATEZM, VK_NUMPAD3, FALT, IDS_AG_PNS_ROTATEZ_M }, - { ID_VOLUME_UP, VK_UP, 0, IDS_AG_VOLUME_UP, 0, wmcmd::WUP }, - { ID_VOLUME_DOWN, VK_DOWN, 0, IDS_AG_VOLUME_DOWN, 0, wmcmd::WDOWN }, - { ID_VOLUME_MUTE, 'M', FCONTROL, IDS_AG_VOLUME_MUTE, 0 }, - { ID_VOLUME_BOOST_INC, 0, 0, IDS_VOLUME_BOOST_INC }, - { ID_VOLUME_BOOST_DEC, 0, 0, IDS_VOLUME_BOOST_DEC }, - { ID_VOLUME_BOOST_MIN, 0, 0, IDS_VOLUME_BOOST_MIN }, - { ID_VOLUME_BOOST_MAX, 0, 0, IDS_VOLUME_BOOST_MAX }, - { ID_CUSTOM_CHANNEL_MAPPING, 0, 0, IDS_CUSTOM_CHANNEL_MAPPING }, - { ID_NORMALIZE, 0, 0, IDS_NORMALIZE }, - { ID_REGAIN_VOLUME, 0, 0, IDS_REGAIN_VOLUME }, - { ID_COLOR_BRIGHTNESS_INC, 0, 0, IDS_BRIGHTNESS_INC }, - { ID_COLOR_BRIGHTNESS_DEC, 0, 0, IDS_BRIGHTNESS_DEC }, - { ID_COLOR_CONTRAST_INC, 0, 0, IDS_CONTRAST_INC }, - { ID_COLOR_CONTRAST_DEC, 0, 0, IDS_CONTRAST_DEC }, - { ID_COLOR_HUE_INC, 0, 0, IDS_HUE_INC }, - { ID_COLOR_HUE_DEC, 0, 0, IDS_HUE_DEC }, - { ID_COLOR_SATURATION_INC, 0, 0, IDS_SATURATION_INC }, - { ID_COLOR_SATURATION_DEC, 0, 0, IDS_SATURATION_DEC }, - { ID_COLOR_RESET, 0, 0, IDS_RESET_COLOR }, - { ID_NAVIGATE_TITLEMENU, 'T', FALT, IDS_MPLAYERC_63 }, - { ID_NAVIGATE_ROOTMENU, 'R', FALT, IDS_AG_DVD_ROOT_MENU }, - { ID_NAVIGATE_SUBPICTUREMENU, 0, 0, IDS_MPLAYERC_65 }, - { ID_NAVIGATE_AUDIOMENU, 0, 0, IDS_MPLAYERC_66 }, - { ID_NAVIGATE_ANGLEMENU, 0, 0, IDS_MPLAYERC_67 }, - { ID_NAVIGATE_CHAPTERMENU, 0, 0, IDS_MPLAYERC_68 }, - { ID_NAVIGATE_MENU_LEFT, VK_LEFT, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_LEFT }, - { ID_NAVIGATE_MENU_RIGHT, VK_RIGHT, FCONTROL | FSHIFT, IDS_MPLAYERC_70 }, - { ID_NAVIGATE_MENU_UP, VK_UP, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_UP }, - { ID_NAVIGATE_MENU_DOWN, VK_DOWN, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_DOWN }, - { ID_NAVIGATE_MENU_ACTIVATE, 0, 0, IDS_MPLAYERC_73 }, - { ID_NAVIGATE_MENU_BACK, 0, 0, IDS_AG_DVD_MENU_BACK }, - { ID_NAVIGATE_MENU_LEAVE, 0, 0, IDS_MPLAYERC_75 }, - { ID_BOSS, 'B', 0, IDS_AG_BOSS_KEY }, - { ID_MENU_PLAYER_SHORT, VK_APPS, 0, IDS_MPLAYERC_77, 0, wmcmd::RUP }, - { ID_MENU_PLAYER_LONG, 0, 0, IDS_MPLAYERC_78 }, - { ID_MENU_FILTERS, 0, 0, IDS_AG_FILTERS_MENU }, - { ID_VIEW_OPTIONS, 'O', 0, IDS_AG_OPTIONS }, - { ID_STREAM_AUDIO_NEXT, 'A', 0, IDS_AG_NEXT_AUDIO }, - { ID_STREAM_AUDIO_PREV, 'A', FSHIFT, IDS_AG_PREV_AUDIO }, - { ID_STREAM_SUB_NEXT, 'S', 0, IDS_AG_NEXT_SUBTITLE }, - { ID_STREAM_SUB_PREV, 'S', FSHIFT, IDS_AG_PREV_SUBTITLE }, - { ID_STREAM_SUB_ONOFF, 'W', 0, IDS_MPLAYERC_85 }, - { ID_SUBTITLES_SUBITEM_START + 2, 0, 0, IDS_MPLAYERC_86 }, - { ID_DVD_ANGLE_NEXT, 0, 0, IDS_MPLAYERC_91 }, - { ID_DVD_ANGLE_PREV, 0, 0, IDS_MPLAYERC_92 }, - { ID_DVD_AUDIO_NEXT, 0, 0, IDS_MPLAYERC_93 }, - { ID_DVD_AUDIO_PREV, 0, 0, IDS_MPLAYERC_94 }, - { ID_DVD_SUB_NEXT, 0, 0, IDS_MPLAYERC_95 }, - { ID_DVD_SUB_PREV, 0, 0, IDS_MPLAYERC_96 }, - { ID_DVD_SUB_ONOFF, 0, 0, IDS_MPLAYERC_97 }, - { ID_VIEW_TEARING_TEST, 0, 0, IDS_AG_TEARING_TEST }, - { ID_VIEW_OSD_DISPLAY_TIME, 'I', FCONTROL, IDS_OSD_DISPLAY_CURRENT_TIME }, - { ID_VIEW_OSD_SHOW_FILENAME, 'N', 0, IDS_OSD_SHOW_FILENAME }, - { ID_SHADERS_PRESET_NEXT, 0, 0, IDS_AG_SHADERS_PRESET_NEXT }, - { ID_SHADERS_PRESET_PREV, 0, 0, IDS_AG_SHADERS_PRESET_PREV }, - { ID_D3DFULLSCREEN_TOGGLE, 0, 0, IDS_MPLAYERC_99 }, - { ID_GOTO_PREV_SUB, 'Y', 0, IDS_MPLAYERC_100 }, - { ID_GOTO_NEXT_SUB, 'U', 0, IDS_MPLAYERC_101 }, - { ID_SUBRESYNC_SHIFT_DOWN, VK_NEXT, FALT, IDS_MPLAYERC_102 }, - { ID_SUBRESYNC_SHIFT_UP, VK_PRIOR, FALT, IDS_MPLAYERC_103 }, - { ID_VIEW_DISPLAY_RENDERER_STATS, 'J', FCONTROL, IDS_OSD_DISPLAY_RENDERER_STATS }, - { ID_VIEW_RESET_RENDERER_STATS, 'R', FCONTROL | FALT, IDS_OSD_RESET_RENDERER_STATS }, - { ID_VIEW_VSYNC, 'V', 0, IDS_AG_VSYNC }, - { ID_VIEW_ENABLEFRAMETIMECORRECTION, 0, 0, IDS_AG_ENABLEFRAMETIMECORRECTION }, - { ID_VIEW_VSYNCACCURATE, 'V', FCONTROL | FALT, IDS_AG_VSYNCACCURATE }, - { ID_VIEW_VSYNCOFFSET_DECREASE, VK_UP, FCONTROL | FALT, IDS_AG_VSYNCOFFSET_DECREASE }, - { ID_VIEW_VSYNCOFFSET_INCREASE, VK_DOWN, FCONTROL | FALT, IDS_AG_VSYNCOFFSET_INCREASE }, - { ID_SUB_DELAY_DOWN, VK_F1, 0, IDS_MPLAYERC_104 }, - { ID_SUB_DELAY_UP, VK_F2, 0, IDS_MPLAYERC_105 }, - { ID_SUB_POS_DOWN, VK_SUBTRACT, FCONTROL | FSHIFT, IDS_SUB_POS_DOWN }, - { ID_SUB_POS_UP, VK_ADD, FCONTROL | FSHIFT, IDS_SUB_POS_UP }, - { ID_SUB_FONT_SIZE_DEC, VK_SUBTRACT, FCONTROL, IDS_SUB_FONT_SIZE_DEC }, - { ID_SUB_FONT_SIZE_INC, VK_ADD, FCONTROL, IDS_SUB_FONT_SIZE_INC }, - - { ID_AFTERPLAYBACK_DONOTHING, 0, 0, IDS_AFTERPLAYBACK_DONOTHING }, - { ID_AFTERPLAYBACK_PLAYNEXT, 0, 0, IDS_AFTERPLAYBACK_PLAYNEXT }, - { ID_AFTERPLAYBACK_MONITOROFF, 0, 0, IDS_AFTERPLAYBACK_MONITOROFF }, - { ID_AFTERPLAYBACK_EXIT, 0, 0, IDS_AFTERPLAYBACK_EXIT }, - { ID_AFTERPLAYBACK_STANDBY, 0, 0, IDS_AFTERPLAYBACK_STANDBY }, - { ID_AFTERPLAYBACK_HIBERNATE, 0, 0, IDS_AFTERPLAYBACK_HIBERNATE }, - { ID_AFTERPLAYBACK_SHUTDOWN, 0, 0, IDS_AFTERPLAYBACK_SHUTDOWN }, - { ID_AFTERPLAYBACK_LOGOFF, 0, 0, IDS_AFTERPLAYBACK_LOGOFF }, - { ID_AFTERPLAYBACK_LOCK, 0, 0, IDS_AFTERPLAYBACK_LOCK }, - - { ID_VIEW_EDITLISTEDITOR, 0, 0, IDS_AG_TOGGLE_EDITLISTEDITOR }, - { ID_EDL_IN, 0, 0, IDS_AG_EDL_IN }, - { ID_EDL_OUT, 0, 0, IDS_AG_EDL_OUT }, - { ID_EDL_NEWCLIP, 0, 0, IDS_AG_EDL_NEW_CLIP }, - { ID_EDL_SAVE, 0, 0, IDS_AG_EDL_SAVE }, - - { ID_PLAYLIST_TOGGLE_SHUFFLE, 0, 0, IDS_PLAYLIST_TOGGLE_SHUFFLE }, - { ID_AUDIOSHIFT_ONOFF, 0, 0, IDS_AUDIOSHIFT_ONOFF }, -}; - -void CAppSettings::CreateCommands() -{ - for (const auto& wc : default_wmcmds) { - wmcmd w = wmcmd(wc); - w.fVirt |= FVIRTKEY | FNOINVERT; - CommandIDToWMCMD[wc.cmd] = &wc; - wmcmds.AddTail(w); - } - ASSERT(wmcmds.GetCount() <= ACCEL_LIST_SIZE); -} - -CAppSettings::~CAppSettings() -{ - if (hAccel) { - DestroyAcceleratorTable(hAccel); - } -} - -bool CAppSettings::IsD3DFullscreen() const -{ - if (iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || iDSVideoRendererType == VIDRNDT_DS_SYNC) { - return fD3DFullscreen || (nCLSwitches & CLSW_D3DFULLSCREEN); - } else { - return false; - } -} - -bool CAppSettings::IsISRAutoLoadEnabled() const -{ - return eSubtitleRenderer == SubtitleRenderer::INTERNAL && - IsSubtitleRendererSupported(eSubtitleRenderer, iDSVideoRendererType); -} - -CAppSettings::SubtitleRenderer CAppSettings::GetSubtitleRenderer() const -{ - switch (eSubtitleRenderer) { - case SubtitleRenderer::INTERNAL: - return IsSubtitleRendererSupported(SubtitleRenderer::INTERNAL, iDSVideoRendererType) ? eSubtitleRenderer : SubtitleRenderer::VS_FILTER; - case SubtitleRenderer::XY_SUB_FILTER: - return IsSubtitleRendererSupported(SubtitleRenderer::XY_SUB_FILTER, iDSVideoRendererType) ? eSubtitleRenderer : SubtitleRenderer::VS_FILTER; - default: - return eSubtitleRenderer; - } -} - -bool CAppSettings::IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer) -{ - switch (eSubtitleRenderer) { - case SubtitleRenderer::INTERNAL: - return true; - case SubtitleRenderer::VS_FILTER: - return IsCLSIDRegistered(CLSID_VSFilter); - case SubtitleRenderer::XY_SUB_FILTER: - return IsCLSIDRegistered(CLSID_XySubFilter); - case SubtitleRenderer::NONE: - return true; - default: - ASSERT(FALSE); - return false; - } -} - -bool CAppSettings::IsSubtitleRendererSupported(SubtitleRenderer eSubtitleRenderer, int videoRenderer) -{ - switch (eSubtitleRenderer) { - case SubtitleRenderer::INTERNAL: - switch (videoRenderer) { - case VIDRNDT_DS_VMR9RENDERLESS: - case VIDRNDT_DS_EVR_CUSTOM: - case VIDRNDT_DS_DXR: - case VIDRNDT_DS_SYNC: - case VIDRNDT_DS_MADVR: - case VIDRNDT_DS_MPCVR: - return true; - } - break; - - case SubtitleRenderer::VS_FILTER: - return true; - - case SubtitleRenderer::XY_SUB_FILTER: - switch (videoRenderer) { - case VIDRNDT_DS_VMR9RENDERLESS: - case VIDRNDT_DS_EVR_CUSTOM: - case VIDRNDT_DS_SYNC: - case VIDRNDT_DS_MADVR: - case VIDRNDT_DS_MPCVR: - return true; - } - break; - case SubtitleRenderer::NONE: - return true; - - default: - ASSERT(FALSE); - } - - return false; -} - -bool CAppSettings::IsVideoRendererAvailable(int iVideoRendererType) -{ - switch (iVideoRendererType) { - case VIDRNDT_DS_DXR: - return IsCLSIDRegistered(CLSID_DXR); - case VIDRNDT_DS_EVR: - case VIDRNDT_DS_EVR_CUSTOM: - case VIDRNDT_DS_SYNC: - return IsCLSIDRegistered(CLSID_EnhancedVideoRenderer); - case VIDRNDT_DS_MADVR: - return IsCLSIDRegistered(CLSID_madVR); - case VIDRNDT_DS_MPCVR: - return IsCLSIDRegistered(CLSID_MPCVR) || DSObjects::CMPCVRAllocatorPresenter::HasInternalMPCVRFilter(); -#ifdef _WIN64 - case VIDRNDT_DS_OVERLAYMIXER: - return false; -#endif - default: - return true; - } -} - -bool CAppSettings::IsInitialized() const -{ - return bInitialized; -} - -CString CAppSettings::SelectedAudioRenderer() const -{ - CString strResult; - if (!AfxGetMyApp()->m_AudioRendererDisplayName_CL.IsEmpty()) { - strResult = AfxGetMyApp()->m_AudioRendererDisplayName_CL; - } else { - strResult = AfxGetAppSettings().strAudioRendererDisplayName; - } - - return strResult; -} - -void CAppSettings::ClearRecentFiles() { - MRU.RemoveAll(); - - for (int i = MRUDub.GetSize() - 1; i >= 0; i--) { - MRUDub.Remove(i); - } - MRUDub.WriteList(); - - // Empty the Windows "Recent" jump list - CComPtr pDests; - HRESULT hr = pDests.CoCreateInstance(CLSID_ApplicationDestinations, nullptr, CLSCTX_INPROC_SERVER); - if (SUCCEEDED(hr)) { - pDests->RemoveAllDestinations(); - } -} - -void CAppSettings::SaveSettings(bool write_full_history /* = false */) -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - if (!bInitialized) { - return; - } - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECAPTIONMENU, eCaptionMenuMode); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDENAVIGATION, fHideNavigation); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CONTROLSTATE, nCS); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTVIDEOFRAME, iDefaultVideoSize); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPASPECTRATIO, fKeepAspectRatio); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COMPMONDESKARDIFF, fCompMonDeskARDiff); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUME, nVolume); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BALANCE, nBalance); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUMESTEP, nVolumeStep); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPEEDSTEP, nSpeedStep); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MUTE, fMute); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPNUM, nLoops); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP, fLoopForever); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPMODE, static_cast(eLoopMode)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ZOOM, iZoomLevel); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, fAllowMultipleInst); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTSTYLE, iTitleBarTextStyle); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTTITLE, fTitleBarTextTitle); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ONTOP, iOnTop); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TRAYICON, fTrayIcon); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOZOOM, fRememberZoomLevel); - pApp->WriteProfileStringW(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR, NULL); //remove old form factor - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MIN, nAutoFitFactorMin); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MAX, nAutoFitFactorMax); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AFTER_PLAYBACK, static_cast(eAfterPlayback)); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS, bHideFullscreenControls)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_POLICY, - static_cast(eHideFullscreenControlsPolicy))); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_DELAY, uHideFullscreenControlsDelay)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_DOCKED_PANELS, bHideFullscreenDockedPanels)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_CONTROLS, bHideWindowedControls)); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_MOUSE_POINTER, bHideWindowedMousePointer)); - - // Auto-change fullscreen mode - SaveSettingsAutoChangeFullScreenMode(); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_EXITFULLSCREENATTHEEND, fExitFullScreenAtTheEnd); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWPOS, fRememberWindowPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWSIZE, fRememberWindowSize); - if (fRememberWindowSize || fRememberWindowPos) { - pApp->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_LASTWINDOWRECT, (BYTE*)&rcLastWindowPos, sizeof(rcLastWindowPos)); - } - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTWINDOWTYPE, nLastWindowType); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTFULLSCREEN, fLastFullScreen); - - if (fSavePnSZoom) { - CString str; - str.Format(_T("%.3f,%.3f"), dZoomX, dZoomY); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM, str); - } else { - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM, nullptr); - } - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPTODESKTOPEDGES, fSnapToDesktopEdges); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_X, sizeAspectRatio.cx); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_Y, sizeAspectRatio.cy); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPHISTORY, fKeepHistory); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RECENT_FILES_NUMBER, iRecentFilesNumber); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, iDSVideoRendererType); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHUFFLEPLAYLISTITEMS, bShufflePlaylistItems); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERPLAYLISTITEMS, bRememberPlaylistItems); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDEPLAYLISTFULLSCREEN, bHidePlaylistFullScreen); - pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERPOS, bFavRememberPos); - pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_RELATIVEDRIVE, bFavRelativeDrive); - pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERABMARKS, bFavRememberABMarks); - - UpdateRenderersData(true); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUDIORENDERERTYPE, CString(strAudioRendererDisplayName)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOLOADAUDIO, fAutoloadAudio); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER, CString(strSubtitlesLanguageOrder)); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER, CString(strAudiosLanguageOrder)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKVSFILTER, fBlockVSFilter); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKRDP, bBlockRDP); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWORKERTHREADFOROPENING, fEnableWorkerThreadForOpening); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REPORTFAILEDPINS, fReportFailedPins); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_DVDPATH, strDVDPath); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USEDVDPATH, fUseDVDPath); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MENULANG, idMenuLang); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOLANG, idAudioLang); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANG, idSubtitlesLang); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_OPENTYPELANGHINT, CString(strOpenTypeLangHint)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_FREETYPE, bUseFreeType); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_MEDIAINFO_LOAD_FILE_DURATION, bUseMediainfoLoadFileDuration); -#if USE_LIBASS - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSSAUSINGLIBASS, bRenderSSAUsingLibass); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSRTUSINGLIBASS, bRenderSRTUsingLibass); -#endif - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CLOSEDCAPTIONS, fClosedCaptions); - CString style; - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SPSTYLE, style <<= subtitlesDefStyle); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPOVERRIDEPLACEMENT, fOverridePlacement); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPHORPOS, nHorPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPVERPOS, nVerPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLEARCOMPENSATION, bSubtitleARCompensation); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBDELAYINTERVAL, nSubDelayStep); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLESUBTITLES, fEnableSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREFER_FORCED_DEFAULT_SUBTITLES, bPreferDefaultForcedSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITIZEEXTERNALSUBTITLES, fPrioritizeExternalSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLEINTERNALSUBTITLES, fDisableInternalSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_OVERRIDING_EXT_SPLITTER, bAllowOverridingExternalSplitterChoice); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLES, bAutoDownloadSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOSAVEDOWNLOADEDSUBTITLES, bAutoSaveDownloadedSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCOREMOVIES, nAutoDownloadScoreMovies); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCORESERIES, nAutoDownloadScoreSeries); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLESEXCLUDE, strAutoDownloadSubtitlesExclude); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOUPLOADSUBTITLES, bAutoUploadSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREFERHEARINGIMPAIREDSUBTITLES, bPreferHearingImpairedSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MPCTHEME, bMPCTheme); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNSEEKBARHEIGHT, iModernSeekbarHeight); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNTHEMEMODE, static_cast(eModernThemeMode)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_DELAY, iFullscreenDelay); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VERTICALALIGNVIDEO, static_cast(iVerticalAlignVideo)); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESPROVIDERS, strSubtitlesProviders); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLEPATHS, strSubtitlePaths); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_DEFAULT_STYLE, bSubtitleOverrideDefaultStyle); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_ALL_STYLES, bSubtitleOverrideAllStyles); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOSWITCHER, fEnableAudioSwitcher); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOTIMESHIFT, fAudioTimeShift); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOTIMESHIFT, iAudioTimeShift); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DOWNSAMPLETO441, fDownSampleTo441); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CUSTOMCHANNELMAPPING, fCustomChannelMapping); - pApp->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_SPEAKERTOCHANNELMAPPING, (BYTE*)pSpeakerToChannelMap, sizeof(pSpeakerToChannelMap)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZE, fAudioNormalize); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOMAXNORMFACTOR, nAudioMaxNormFactor); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZERECOVER, fAudioNormalizeRecover); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, nAudioBoost); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPEAKERCHANNELS, nSpeakerChannels); - - // Multi-monitor code - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITOR, CString(strFullScreenMonitorID)); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITORDEVICE, CString(strFullScreenMonitorDeviceName)); - - // Mouse - CStringW str; - str.Format(L"%u", nMouseLeftClick); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT, str); - str.Format(L"%u", nMouseLeftDblClick); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT_DBLCLICK, str); - str.Format(L"%u", nMouseRightClick); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_RIGHT, str); - str.Format(L"%u;%u;%u;%u", MouseMiddleClick.normal, MouseMiddleClick.ctrl, MouseMiddleClick.shift, MouseMiddleClick.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_MIDDLE, str); - str.Format(L"%u;%u;%u;%u", MouseX1Click.normal, MouseX1Click.ctrl, MouseX1Click.shift, MouseX1Click.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X1, str); - str.Format(L"%u;%u;%u;%u", MouseX2Click.normal, MouseX2Click.ctrl, MouseX2Click.shift, MouseX2Click.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X2, str); - str.Format(L"%u;%u;%u;%u", MouseWheelUp.normal, MouseWheelUp.ctrl, MouseWheelUp.shift, MouseWheelUp.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_UP, str); - str.Format(L"%u;%u;%u;%u", MouseWheelDown.normal, MouseWheelDown.ctrl, MouseWheelDown.shift, MouseWheelDown.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_DOWN, str); - str.Format(L"%u;%u;%u;%u", MouseWheelLeft.normal, MouseWheelLeft.ctrl, MouseWheelLeft.shift, MouseWheelLeft.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_LEFT, str); - str.Format(L"%u;%u;%u;%u", MouseWheelRight.normal, MouseWheelRight.ctrl, MouseWheelRight.shift, MouseWheelRight.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_RIGHT, str); - - - // Prevent Minimize when in Fullscreen mode on non default monitor - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_MINIMIZE, fPreventMinimize); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENHANCED_TASKBAR, bUseEnhancedTaskBar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEARCH_IN_FOLDER, fUseSearchInFolder); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TIME_TOOLTIP, fUseSeekbarHover); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_TOOLTIP_POSITION, nHoverPosition); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MPC_OSD_SIZE, nOSDSize); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_MPC_OSD_FONT, strOSDFont); - - // Associated types with icon or not... - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASSOCIATED_WITH_ICON, fAssociatedWithIcons); - // Last Open Dir - //pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_LAST_OPEN_DIR, strLastOpenDir); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_D3DFULLSCREEN, fD3DFullscreen); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_BRIGHTNESS, iBrightness); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_CONTRAST, iContrast); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_HUE, iHue); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_SATURATION, iSaturation); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOWOSD, fShowOSD); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CURRENT_TIME_OSD, fShowCurrentTimeInOSD); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_TRANSPARENCY, nOSDTransparency); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_BORDER, nOSDBorder); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEEDLEDITOR, fEnableEDLEditor); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LANGUAGE, language); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK, bFastSeek); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK_METHOD, eFastSeekMethod); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CHAPTERS, fShowChapters); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, fLCDSupport); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW, fSeekPreview); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW_SIZE, iSeekPreviewSize); - - - // Save analog capture settings - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, iDefaultCaptureDevice); - pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, strAnalogVideo); - pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, strAnalogAudio); - pApp->WriteProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, iAnalogCountry); - - // Save digital capture settings (BDA) - pApp->WriteProfileString(IDS_R_DVB, nullptr, nullptr); // Ensure the section is cleared before saving the new settings - - //pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER, strBDANetworkProvider); - pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER, strBDATuner); - pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER, strBDAReceiver); - //pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD, strBDAStandard); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, iBDAScanFreqStart); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, iBDAScanFreqEnd); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, iBDABandwidth); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SYMBOLRATE, iBDASymbolRate); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_USE_OFFSET, fBDAUseOffset); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_OFFSET, iBDAOffset); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_IGNORE_ENCRYPTED_CHANNELS, fBDAIgnoreEncryptedChannels); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, nDVBLastChannel); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, nDVBRebuildFilterGraph); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, nDVBStopFilterGraph); - - for (size_t i = 0; i < m_DVBChannels.size(); i++) { - CString numChannel; - numChannel.Format(_T("%Iu"), i); - pApp->WriteProfileString(IDS_R_DVB, numChannel, m_DVBChannels[i].ToString()); - } - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DVDPOS, fRememberDVDPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS, fRememberFilePos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSLONGER, iRememberPosForLongerThan); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSAUDIO, bRememberPosForAudioFiles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_PLAYLIST, bRememberExternalPlaylistPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_TRACK_SELECTION, bRememberTrackSelection); - - pApp->WriteProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, nullptr, nullptr); - for (INT_PTR i = 0, j = m_pnspresets.GetCount(); i < j; i++) { - CString str; - str.Format(_T("Preset%Id"), i); - pApp->WriteProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, str, m_pnspresets[i]); - } - - pApp->WriteProfileString(IDS_R_COMMANDS, nullptr, nullptr); - POSITION pos = wmcmds.GetHeadPosition(); - for (int i = 0; pos;) { - const wmcmd& wc = wmcmds.GetNext(pos); - if (wc.IsModified()) { - CString str; - str.Format(_T("CommandMod%d"), i); - // mouse and mouseVirt are written twice for backwards compatibility with old versions - CString str2; - str2.Format(_T("%hu %hx %hx \"%S\" %d %hhu %u %hhu %hhu %hhu"), - wc.cmd, (WORD)wc.fVirt, wc.key, wc.rmcmd.GetString(), - wc.rmrepcnt, wc.mouse, wc.appcmd, wc.mouse, wc.mouseVirt, wc.mouseVirt); - pApp->WriteProfileString(IDS_R_COMMANDS, str, str2); - i++; - } - } - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WINLIRC, fWinLirc); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WINLIRCADDR, strWinLircAddr); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UICE, fUIce); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_UICEADDR, strUIceAddr); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GLOBALMEDIA, fGlobalMedia); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTS, nJumpDistS); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTM, nJumpDistM); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTL, nJumpDistL); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LIMITWINDOWPROPORTIONS, fLimitWindowProportions); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTUSEDPAGE, nLastUsedPage); - - m_Formats.UpdateData(true); - - // Internal filters - for (int f = 0; f < SRC_LAST; f++) { - pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, SrcFiltersKeys[f].name, SrcFilters[f]); - } - for (int f = 0; f < TRA_LAST; f++) { - pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, TraFiltersKeys[f].name, TraFilters[f]); - } - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_LOGOFILE, strLogoFileName); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOID, nLogoId); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOEXT, fLogoExternal); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOCOLORPROFILE, fLogoColorProfileEnabled); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECDROMSSUBMENU, fHideCDROMsSubMenu); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITY, dwPriority); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LAUNCHFULLSCREEN, fLaunchfullscreen); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWEBSERVER, fEnableWebServer); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPORT, nWebServerPort); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERUSECOMPRESSION, fWebServerUseCompression); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERLOCALHOSTONLY, fWebServerLocalhostOnly); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBUI_ENABLE_PREVIEW, bWebUIEnablePreview); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPRINTDEBUGINFO, fWebServerPrintDebugInfo); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBROOT, strWebRoot); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBDEFINDEX, strWebDefIndex); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBSERVERCGI, strWebServerCGI); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTPATH, strSnapshotPath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTEXT, strSnapshotExt); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTSUBTITLES, bSnapShotSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTKEEPVIDEOEXTENSION, bSnapShotKeepVideoExtension); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBROWS, iThumbRows); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBCOLS, iThumbCols); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBWIDTH, iThumbWidth); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBSAVEEXTERNALSTYLEFILE, bSubSaveExternalStyleFile)); - { - // Save the list of extra (non-default) shader files - VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_EXTRA, m_ShadersExtraList.ToString())); - // Save shader selection - CString strPre, strPost; - m_Shaders.GetCurrentPreset().ToStrings(strPre, strPost); - VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_PRERESIZE, strPre)); - VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_POSTRESIZE, strPost)); - // Save shader presets - int i = 0; - CString iStr; - pApp->WriteProfileString(IDS_R_SHADER_PRESETS, nullptr, nullptr); - for (const auto& pair : m_Shaders.GetPresets()) { - iStr.Format(_T("%d"), i++); - pair.second.ToStrings(strPre, strPost); - VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, iStr, pair.first)); - VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_PRERESIZE + iStr, strPre)); - VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_POSTRESIZE + iStr, strPost)); - } - // Save selected preset name - CString name; - m_Shaders.GetCurrentPresetName(name); - VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_LASTPRESET, name)); - } - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADER, bToggleShader); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADERSSCREENSPACE, bToggleShaderScreenSpace); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMAINING_TIME, fRemainingTime); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIGH_PRECISION_TIMER, bHighPrecisionTimer); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIMER_SHOW_PERCENTAGE, bTimerShowPercentage); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_AUTO_CHECK, nUpdaterAutoCheck); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_DELAY, nUpdaterDelay); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_NOTIFY_SKYPE, bNotifySkype); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JPEG_QUALITY, nJpegQuality); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART, bEnableCoverArt); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART_SIZE_LIMIT, nCoverArtSizeLimit); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGGING, bEnableLogging); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_LEGACY_TOOLBAR, bUseLegacyToolbar); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, - static_cast(eSubtitleRenderer))); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTTOOLBARSIZE, nDefaultToolbarSize); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_POSITION, bSaveImagePosition); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_CURRENTTIME, bSaveImageCurrentTime); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_INACCURATE_FASTSEEK, bAllowInaccurateFastseek); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP_FOLDER_NEXT_FILE, bLoopFolderOnPlayNextFile); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOCK_NOPAUSE, bLockNoPause); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_DISPLAY_SLEEP, bPreventDisplaySleep); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_SMTC, bUseSMTC); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RELOAD_AFTER_LONG_PAUSE, iReloadAfterLongPause); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OPEN_REC_PANEL_WHEN_OPENING_DEVICE, bOpenRecPanelWhenOpeningDevice); - - { - CComHeapPtr pDeviceId; - BOOL bExclusive; - UINT32 uBufferDuration; - if (SUCCEEDED(sanear->GetOutputDevice(&pDeviceId, &bExclusive, &uBufferDuration))) { - pApp->WriteProfileString(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_ID, pDeviceId); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_EXCLUSIVE, bExclusive); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_BUFFER, uBufferDuration); - } - - BOOL bCrossfeedEnabled = sanear->GetCrossfeedEnabled(); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_ENABLED, bCrossfeedEnabled); - - UINT32 uCutoffFrequency, uCrossfeedLevel; - sanear->GetCrossfeedSettings(&uCutoffFrequency, &uCrossfeedLevel); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ, uCutoffFrequency); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, uCrossfeedLevel); - - BOOL bIgnoreSystemChannelMixer = sanear->GetIgnoreSystemChannelMixer(); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_IGNORE_SYSTEM_MIXER, bIgnoreSystemChannelMixer); - } - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_YDL, bUseYDL); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, iYDLMaxHeight); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_VIDEO_FORMAT, iYDLVideoFormat); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_FORMAT, iYDLAudioFormat); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, bYDLAudioOnly); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_EXEPATH, sYDLExePath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_COMMAND_LINE, sYDLCommandLine); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLE_CRASH_REPORTER, bEnableCrashReporter); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_REFRESH_INTERVAL, nStreamPosPollerInterval); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_LANG_STATUSBAR, bShowLangInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_FPS_STATUSBAR, bShowFPSInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_ABMARKS_STATUSBAR, bShowABMarksInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_VIDEOINFO_STATUSBAR, bShowVideoInfoInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_AUDIOFORMAT_STATUSBAR, bShowAudioFormatInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ADD_LANGCODE_WHEN_SAVE_SUBTITLES, bAddLangCodeWhenSaveSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TITLE_IN_RECENT_FILE_LIST, bUseTitleInRecentFileList); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_SUBS_PREFERENCE, sYDLSubsPreference); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_AUTOMATIC_CAPTIONS, bUseAutomaticCaptions); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_QUICKOPEN_PATH, lastQuickOpenPath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_FILESAVECOPY_PATH, lastFileSaveCopyPath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_FILEOPENDIR_PATH, lastFileOpenDirPath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_EXTERNAL_PLAYLIST_PATH, externalPlayListPath); - - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REDIRECT_OPEN_TO_APPEND_THRESHOLD, iRedirectOpenToAppendThreshold); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_SEPARATE_CONTROLS, bFullscreenSeparateControls); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALWAYS_USE_SHORT_MENU, bAlwaysUseShortMenu); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_STILL_VIDEO_DURATION, iStillVideoDuration); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MOUSE_LEFTUP_DELAY, iMouseLeftUpDelay); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CAPTURE_DEINTERLACE, bCaptureDeinterlace); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PAUSE_WHILE_DRAGGING_SEEKBAR, bPauseWhileDraggingSeekbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CONFIRM_FILE_DELETE, bConfirmFileDelete); - - if (fKeepHistory && write_full_history) { - MRU.SaveMediaHistory(); - } - - pApp->FlushProfile(); -} - -void CAppSettings::PurgeMediaHistory(size_t maxsize) { - CStringW section = L"MediaHistory"; - auto timeToHash = LoadHistoryHashes(section, L"LastUpdated"); - size_t entries = timeToHash.size(); - if (entries > maxsize) { - for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { - if (entries > maxsize) { - PurgeExpiredHash(section, iter->second); - entries--; - } else { - break; - } - } - } -} - -void CAppSettings::PurgePlaylistHistory(size_t maxsize) { - CStringW section = L"PlaylistHistory"; - auto timeToHash = LoadHistoryHashes(section, L"LastUpdated"); - size_t entries = timeToHash.size(); - if (entries > maxsize) { - for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { - if (entries > maxsize) { - PurgeExpiredHash(section, iter->second); - entries--; - } else { - break; - } - } - } -} - -std::multimap CAppSettings::LoadHistoryHashes(CStringW section, CStringW dateField) { - auto pApp = AfxGetMyApp(); - auto hashes = pApp->GetSectionSubKeys(section); - - std::multimap timeToHash; - for (auto const& hash : hashes) { - CStringW lastOpened, subSection; - subSection.Format(L"%s\\%s", section, static_cast(hash)); - lastOpened = pApp->GetProfileStringW(subSection, dateField, L"0000-00-00T00:00:00.0Z"); - if (!lastOpened.IsEmpty()) { - timeToHash.insert(std::pair(lastOpened, hash)); - } - } - return timeToHash; -} - -void CAppSettings::PurgeExpiredHash(CStringW section, CStringW hash) { - auto pApp = AfxGetMyApp(); - CStringW subSection; - subSection.Format(L"%s\\%s", section, static_cast(hash)); - pApp->WriteProfileString(subSection, nullptr, nullptr); -} - -void CAppSettings::LoadExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey /*= IDS_R_EXTERNAL_FILTERS*/) -{ - CWinApp* pApp = AfxGetApp(); - ASSERT(pApp); - - for (unsigned int i = 0; ; i++) { - CString key; - key.Format(_T("%s\\%04u"), baseKey, i); - - CAutoPtr f(DEBUG_NEW FilterOverride); - - f->fDisabled = !pApp->GetProfileInt(key, _T("Enabled"), FALSE); - - UINT j = pApp->GetProfileInt(key, _T("SourceType"), -1); - if (j == 0) { - f->type = FilterOverride::REGISTERED; - f->dispname = CStringW(pApp->GetProfileString(key, _T("DisplayName"))); - f->name = pApp->GetProfileString(key, _T("Name")); - CString clsid_str = pApp->GetProfileString(key, _T("CLSID")); - if (clsid_str.IsEmpty() && f->dispname.GetLength() == 88 && f->dispname.Left(1) == L"@") { - clsid_str = f->dispname.Right(38); - } - if (clsid_str.GetLength() == 38) { - f->clsid = GUIDFromCString(clsid_str); - } - } else if (j == 1) { - f->type = FilterOverride::EXTERNAL; - f->path = pApp->GetProfileString(key, _T("Path")); - f->name = pApp->GetProfileString(key, _T("Name")); - f->clsid = GUIDFromCString(pApp->GetProfileString(key, _T("CLSID"))); - } else { - pApp->WriteProfileString(key, nullptr, 0); - break; - } - - if (IgnoreExternalFilter(f->clsid)) { - continue; - } - - f->backup.RemoveAll(); - for (unsigned int k = 0; ; k++) { - CString val; - val.Format(_T("org%04u"), k); - CString guid = pApp->GetProfileString(key, val); - if (guid.IsEmpty()) { - break; - } - f->backup.AddTail(GUIDFromCString(guid)); - } - - f->guids.RemoveAll(); - for (unsigned int k = 0; ; k++) { - CString val; - val.Format(_T("mod%04u"), k); - CString guid = pApp->GetProfileString(key, val); - if (guid.IsEmpty()) { - break; - } - f->guids.AddTail(GUIDFromCString(guid)); - } - - f->iLoadType = (int)pApp->GetProfileInt(key, _T("LoadType"), -1); - if (f->iLoadType < 0) { - break; - } - - f->dwMerit = pApp->GetProfileInt(key, _T("Merit"), MERIT_DO_NOT_USE + 1); - - filters.AddTail(f); - } -} - -void CAppSettings::SaveExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey /*= IDS_R_EXTERNAL_FILTERS*/) -{ - // Saving External Filter settings takes a long time. Use only when really necessary. - CWinApp* pApp = AfxGetApp(); - ASSERT(pApp); - - // Remove the old keys - for (unsigned int i = 0; ; i++) { - CString key; - key.Format(_T("%s\\%04u"), baseKey, i); - int j = pApp->GetProfileInt(key, _T("Enabled"), -1); - pApp->WriteProfileString(key, nullptr, nullptr); - if (j < 0) { - break; - } - } - - unsigned int k = 0; - POSITION pos = filters.GetHeadPosition(); - while (pos) { - FilterOverride* f = filters.GetNext(pos); - - if (f->fTemporary) { - continue; - } - - CString key; - key.Format(_T("%s\\%04u"), baseKey, k); - - pApp->WriteProfileInt(key, _T("SourceType"), (int)f->type); - pApp->WriteProfileInt(key, _T("Enabled"), (int)!f->fDisabled); - pApp->WriteProfileString(key, _T("Name"), f->name); - pApp->WriteProfileString(key, _T("CLSID"), CStringFromGUID(f->clsid)); - if (f->type == FilterOverride::REGISTERED) { - pApp->WriteProfileString(key, _T("DisplayName"), CString(f->dispname)); - } else if (f->type == FilterOverride::EXTERNAL) { - pApp->WriteProfileString(key, _T("Path"), f->path); - } - POSITION pos2 = f->backup.GetHeadPosition(); - for (unsigned int i = 0; pos2; i++) { - CString val; - val.Format(_T("org%04u"), i); - pApp->WriteProfileString(key, val, CStringFromGUID(f->backup.GetNext(pos2))); - } - pos2 = f->guids.GetHeadPosition(); - for (unsigned int i = 0; pos2; i++) { - CString val; - val.Format(_T("mod%04u"), i); - pApp->WriteProfileString(key, val, CStringFromGUID(f->guids.GetNext(pos2))); - } - pApp->WriteProfileInt(key, _T("LoadType"), f->iLoadType); - pApp->WriteProfileInt(key, _T("Merit"), f->dwMerit); - - k++; - } -} - -void CAppSettings::SaveSettingsAutoChangeFullScreenMode() -{ - auto pApp = AfxGetMyApp(); - ASSERT(pApp); - - // Ensure the section is cleared before saving the new settings - for (size_t i = 0;; i++) { - CString section; - section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); - - // WriteProfileString doesn't return false when INI is used and the section doesn't exist - // so instead check for the a value inside that section - if (!pApp->HasProfileEntry(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED)) { - break; - } else { - VERIFY(pApp->WriteProfileString(section, nullptr, nullptr)); - } - } - pApp->WriteProfileString(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, nullptr, nullptr); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_ENABLE, autoChangeFSMode.bEnabled)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_APPLYDEFMODEATFSEXIT, autoChangeFSMode.bApplyDefaultModeAtFSExit)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_RESTORERESAFTEREXIT, autoChangeFSMode.bRestoreResAfterProgExit)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_DELAY, (int)autoChangeFSMode.uDelay)); - - for (size_t i = 0; i < autoChangeFSMode.modes.size(); i++) { - const auto& mode = autoChangeFSMode.modes[i]; - CString section; - section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); - - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED, mode.bChecked)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTART, std::lround(mode.dFrameRateStart * 1000000))); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTOP, std::lround(mode.dFrameRateStop * 1000000))); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_AUDIODELAY, mode.msAudioDelay)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_BPP, mode.dm.bpp)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FREQ, mode.dm.freq)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEX, mode.dm.size.cx)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEY, mode.dm.size.cy)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FLAGS, (int)mode.dm.dwDisplayFlags)); - } -} - -void CAppSettings::LoadSettings() -{ - CWinApp* pApp = AfxGetApp(); - ASSERT(pApp); - - UINT len; - BYTE* ptr = nullptr; - - if (bInitialized) { - return; - } - - // Set interface language first! - language = (LANGID)pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LANGUAGE, -1); - if (language == LANGID(-1)) { - language = Translations::SetDefaultLanguage(); - } else if (language != 0) { - if (language <= 23) { - // We must be updating from a really old version, use the default language - language = Translations::SetDefaultLanguage(); - } else if (!Translations::SetLanguage(language, false)) { - // In case of error, reset the language to English - language = 0; - } - } - - CreateCommands(); - - eCaptionMenuMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECAPTIONMENU, MODE_SHOWCAPTIONMENU)); - fHideNavigation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDENAVIGATION, FALSE); - nCS = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CONTROLSTATE, CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR); - iDefaultVideoSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTVIDEOFRAME, DVS_FROMINSIDE); - fKeepAspectRatio = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPASPECTRATIO, TRUE); - fCompMonDeskARDiff = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COMPMONDESKARDIFF, FALSE); - nVolume = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUME, 100); - nBalance = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BALANCE, 0); - fMute = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MUTE, FALSE); - nLoops = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPNUM, 1); - fLoopForever = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP, FALSE); - eLoopMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPMODE, static_cast(LoopMode::PLAYLIST))); - iZoomLevel = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ZOOM, 1); - iDSVideoRendererType = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, - IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS); - nVolumeStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUMESTEP, 5); - nSpeedStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPEEDSTEP, 0); - if (nSpeedStep > 75) { - nSpeedStep = 75; - } - - UpdateRenderersData(false); - - strAudioRendererDisplayName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIORENDERERTYPE); - fAutoloadAudio = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOLOADAUDIO, TRUE); - strSubtitlesLanguageOrder = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER); - strAudiosLanguageOrder = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER); - fBlockVSFilter = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKVSFILTER, TRUE); - bBlockRDP = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKRDP, FALSE); - fEnableWorkerThreadForOpening = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWORKERTHREADFOROPENING, TRUE); - fReportFailedPins = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REPORTFAILEDPINS, TRUE); - fAllowMultipleInst = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, FALSE); - iTitleBarTextStyle = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTSTYLE, 1); - fTitleBarTextTitle = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTTITLE, FALSE); - iOnTop = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ONTOP, 0); - fTrayIcon = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TRAYICON, FALSE); - fRememberZoomLevel = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOZOOM, TRUE); - int tAutoFitFactor = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR, 0); //if found, old fit factor will be default for min/max - nAutoFitFactorMin = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MIN, tAutoFitFactor ? tAutoFitFactor : DEF_MIN_AUTOFIT_SCALE_FACTOR); //otherwise default min to DEF_MIN_AUTOFIT_SCALE_FACTOR - nAutoFitFactorMax = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MAX, tAutoFitFactor ? tAutoFitFactor : DEF_MAX_AUTOFIT_SCALE_FACTOR); //otherwise default max to DEF_MAX_AUTOFIT_SCALE_FACTOR - nAutoFitFactorMin = std::max(std::min(nAutoFitFactorMin, nAutoFitFactorMax), MIN_AUTOFIT_SCALE_FACTOR); - nAutoFitFactorMax = std::min(std::max(nAutoFitFactorMin, nAutoFitFactorMax), MAX_AUTOFIT_SCALE_FACTOR); - - eAfterPlayback = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AFTER_PLAYBACK, 0)); - - bHideFullscreenControls = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS, TRUE); - eHideFullscreenControlsPolicy = - static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_POLICY, 1)); - uHideFullscreenControlsDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_DELAY, 0); - bHideFullscreenDockedPanels = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_DOCKED_PANELS, TRUE); - bHideWindowedControls = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_CONTROLS, FALSE); - - bHideWindowedMousePointer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_MOUSE_POINTER, TRUE); - - // Multi-monitor code - strFullScreenMonitorID = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITOR); - strFullScreenMonitorDeviceName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITORDEVICE); - - // Mouse - CStringW str; - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT); - swscanf_s(str, L"%u", &nMouseLeftClick); - if (nMouseLeftClick != 0 && nMouseLeftClick != ID_PLAY_PLAYPAUSE && nMouseLeftClick != ID_VIEW_FULLSCREEN) { - nMouseLeftClick = ID_PLAY_PLAYPAUSE; - } - - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT_DBLCLICK); - swscanf_s(str, L"%u", &nMouseLeftDblClick); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_RIGHT); - swscanf_s(str, L"%u", &nMouseRightClick); - - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_MIDDLE); - swscanf_s(str, L"%u;%u;%u;%u", &MouseMiddleClick.normal, &MouseMiddleClick.ctrl, &MouseMiddleClick.shift, &MouseMiddleClick.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X1); - swscanf_s(str, L"%u;%u;%u;%u", &MouseX1Click.normal, &MouseX1Click.ctrl, &MouseX1Click.shift, &MouseX1Click.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X2); - swscanf_s(str, L"%u;%u;%u;%u", &MouseX2Click.normal, &MouseX2Click.ctrl, &MouseX2Click.shift, &MouseX2Click.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_UP); - swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelUp.normal, &MouseWheelUp.ctrl, &MouseWheelUp.shift, &MouseWheelUp.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_DOWN); - swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelDown.normal, &MouseWheelDown.ctrl, &MouseWheelDown.shift, &MouseWheelDown.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_LEFT); - swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelLeft.normal, &MouseWheelLeft.ctrl, &MouseWheelLeft.shift, &MouseWheelLeft.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_RIGHT); - swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelRight.normal, &MouseWheelRight.ctrl, &MouseWheelRight.shift, &MouseWheelRight.rbtn); - - - // Prevent Minimize when in fullscreen mode on non default monitor - fPreventMinimize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_MINIMIZE, FALSE); - bUseEnhancedTaskBar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENHANCED_TASKBAR, TRUE); - fUseSearchInFolder = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEARCH_IN_FOLDER, TRUE); - fUseSeekbarHover = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TIME_TOOLTIP, TRUE); - nHoverPosition = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_TOOLTIP_POSITION, TIME_TOOLTIP_ABOVE_SEEKBAR); - nOSDSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MPC_OSD_SIZE, 18); - LOGFONT lf; - GetMessageFont(&lf); - strOSDFont = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_MPC_OSD_FONT, lf.lfFaceName); - if (strOSDFont.IsEmpty() || strOSDFont.GetLength() >= LF_FACESIZE) { - strOSDFont = lf.lfFaceName; - } - - // Associated types with icon or not... - fAssociatedWithIcons = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASSOCIATED_WITH_ICON, TRUE); - // Last Open Dir - //strLastOpenDir = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_LAST_OPEN_DIR, _T("C:\\")); - - fAudioTimeShift = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOTIMESHIFT, FALSE); - iAudioTimeShift = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOTIMESHIFT, 0); - - // Auto-change fullscreen mode - autoChangeFSMode.bEnabled = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_ENABLE, FALSE); - autoChangeFSMode.bApplyDefaultModeAtFSExit = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_APPLYDEFMODEATFSEXIT, FALSE); - autoChangeFSMode.bRestoreResAfterProgExit = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_RESTORERESAFTEREXIT, TRUE); - autoChangeFSMode.uDelay = pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_DELAY, 0); - - autoChangeFSMode.modes.clear(); - for (size_t i = 0;; i++) { - CString section; - section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); - - int iChecked = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED, INT_ERROR); - if (iChecked == INT_ERROR) { - break; - } - - double dFrameRateStart = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTART, 0) / 1000000.0; - double dFrameRateStop = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTOP, 0) / 1000000.0; - int msAudioDelay = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_AUDIODELAY, fAudioTimeShift ? iAudioTimeShift : 0); - DisplayMode dm; - dm.bValid = true; - dm.bpp = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_BPP, 0); - dm.freq = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FREQ, 0); - dm.size.cx = (LONG)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEX, 0); - dm.size.cy = (LONG)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEY, 0); - dm.dwDisplayFlags = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FLAGS, 0); - - autoChangeFSMode.modes.emplace_back(!!iChecked, dFrameRateStart, dFrameRateStop, msAudioDelay, std::move(dm)); - } - - fExitFullScreenAtTheEnd = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_EXITFULLSCREENATTHEEND, TRUE); - - fRememberWindowPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWPOS, FALSE); - fRememberWindowSize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWSIZE, FALSE); - str = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM); - if (_stscanf_s(str, _T("%lf,%lf"), &dZoomX, &dZoomY) == 2 && - dZoomX >= 0.196 && dZoomX <= 5.0 && - dZoomY >= 0.196 && dZoomY <= 5.0) { - fSavePnSZoom = true; - } else { - fSavePnSZoom = false; - dZoomX = 1.0; - dZoomY = 1.0; - } - fSnapToDesktopEdges = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPTODESKTOPEDGES, FALSE); - sizeAspectRatio.cx = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_X, 0); - sizeAspectRatio.cy = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_Y, 0); - - fKeepHistory = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPHISTORY, TRUE); - fileAssoc.SetNoRecentDocs(!fKeepHistory); - iRecentFilesNumber = std::max(0, (int)pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RECENT_FILES_NUMBER, 100)); - MRU.SetSize(iRecentFilesNumber); - - if (pApp->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_LASTWINDOWRECT, &ptr, &len)) { - if (len == sizeof(CRect)) { - memcpy(&rcLastWindowPos, ptr, sizeof(CRect)); - if (rcLastWindowPos.Width() < 250 || rcLastWindowPos.Height() < 80) { - rcLastWindowPos = CRect(100, 100, 500, 400); - } - } - delete[] ptr; - } - nLastWindowType = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTWINDOWTYPE, SIZE_RESTORED); - fLastFullScreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTFULLSCREEN, FALSE); - - bShufflePlaylistItems = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHUFFLEPLAYLISTITEMS, FALSE); - bRememberPlaylistItems = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERPLAYLISTITEMS, TRUE); - bHidePlaylistFullScreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDEPLAYLISTFULLSCREEN, FALSE); - bFavRememberPos = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERPOS, TRUE); - bFavRelativeDrive = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_RELATIVEDRIVE, FALSE); - bFavRememberABMarks = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERABMARKS, FALSE); - - strDVDPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_DVDPATH); - fUseDVDPath = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USEDVDPATH, FALSE); - idMenuLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MENULANG, 0); - idAudioLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOLANG, 0); - idSubtitlesLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANG, 0); -#if USE_LIBASS - bRenderSSAUsingLibass = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSSAUSINGLIBASS, FALSE); - bRenderSRTUsingLibass = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSRTUSINGLIBASS, FALSE); -#endif - CT2A tmpLangHint(pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_OPENTYPELANGHINT, _T(""))); - strOpenTypeLangHint = tmpLangHint; - bUseFreeType = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_FREETYPE, FALSE); - bUseMediainfoLoadFileDuration = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_MEDIAINFO_LOAD_FILE_DURATION, FALSE); - bCaptureDeinterlace = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CAPTURE_DEINTERLACE, FALSE); - bPauseWhileDraggingSeekbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PAUSE_WHILE_DRAGGING_SEEKBAR, TRUE); - bConfirmFileDelete = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CONFIRM_FILE_DELETE, TRUE); - - fClosedCaptions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CLOSEDCAPTIONS, FALSE); - { - CString temp = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SPSTYLE); - subtitlesDefStyle <<= temp; - if (temp.IsEmpty()) { // Position the text subtitles relative to the video frame by default - subtitlesDefStyle.relativeTo = STSStyle::AUTO; - } - } - fOverridePlacement = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPOVERRIDEPLACEMENT, FALSE); - nHorPos = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPHORPOS, 50); - nVerPos = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPVERPOS, 90); - bSubtitleARCompensation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLEARCOMPENSATION, TRUE); - nSubDelayStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBDELAYINTERVAL, 500); - if (nSubDelayStep < 10) { - nSubDelayStep = 500; - } - - fEnableSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLESUBTITLES, TRUE); - bPreferDefaultForcedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREFER_FORCED_DEFAULT_SUBTITLES, TRUE); - fPrioritizeExternalSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITIZEEXTERNALSUBTITLES, TRUE); - fDisableInternalSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLEINTERNALSUBTITLES, FALSE); - bAllowOverridingExternalSplitterChoice = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_OVERRIDING_EXT_SPLITTER, FALSE); - bAutoDownloadSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLES, FALSE); - bAutoSaveDownloadedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOSAVEDOWNLOADEDSUBTITLES, FALSE); - nAutoDownloadScoreMovies = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCOREMOVIES, 0x16); - nAutoDownloadScoreSeries = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCORESERIES, 0x18); - strAutoDownloadSubtitlesExclude = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLESEXCLUDE); - bAutoUploadSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOUPLOADSUBTITLES, FALSE); - bPreferHearingImpairedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREFERHEARINGIMPAIREDSUBTITLES, FALSE); - bMPCTheme = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MPCTHEME, TRUE); - if (IsWindows10OrGreater()) { - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"), KEY_READ)) { - DWORD useTheme = (DWORD)-1; - if (ERROR_SUCCESS == key.QueryDWORDValue(_T("AppsUseLightTheme"), useTheme)) { - if (0 == useTheme) { - bWindows10DarkThemeActive = true; - } - } - } - if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\DWM"), KEY_READ)) { - DWORD useColorPrevalence = (DWORD)-1; - if (ERROR_SUCCESS == key.QueryDWORDValue(_T("ColorPrevalence"), useColorPrevalence)) { - if (1 == useColorPrevalence) { - bWindows10AccentColorsEnabled = true; - } - } - } - } - iModernSeekbarHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNSEEKBARHEIGHT, DEF_MODERN_SEEKBAR_HEIGHT); - if (iModernSeekbarHeight < MIN_MODERN_SEEKBAR_HEIGHT || iModernSeekbarHeight > MAX_MODERN_SEEKBAR_HEIGHT) { - iModernSeekbarHeight = DEF_MODERN_SEEKBAR_HEIGHT; - } - - eModernThemeMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNTHEMEMODE, static_cast(CMPCTheme::ModernThemeMode::WINDOWSDEFAULT))); - - iFullscreenDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_DELAY, MIN_FULLSCREEN_DELAY); - if (iFullscreenDelay < MIN_FULLSCREEN_DELAY || iFullscreenDelay > MAX_FULLSCREEN_DELAY) { - iFullscreenDelay = MIN_FULLSCREEN_DELAY; - } - - int tVertAlign = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VERTICALALIGNVIDEO, static_cast(verticalAlignVideoType::ALIGN_MIDDLE)); - if (tVertAlign < static_cast(verticalAlignVideoType::ALIGN_MIDDLE) || tVertAlign > static_cast(verticalAlignVideoType::ALIGN_BOTTOM)) { - tVertAlign = static_cast(verticalAlignVideoType::ALIGN_MIDDLE); - } - iVerticalAlignVideo = static_cast(tVertAlign); - - strSubtitlesProviders = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESPROVIDERS, _T("<|OpenSubtitles2|||1|0|><|podnapisi|||1|0|><|Napisy24|||0|0|>")); - strSubtitlePaths = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLEPATHS, DEFAULT_SUBTITLE_PATHS); - bSubtitleOverrideDefaultStyle = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_DEFAULT_STYLE, FALSE); - bSubtitleOverrideAllStyles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_ALL_STYLES, FALSE); - - fEnableAudioSwitcher = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOSWITCHER, TRUE); - fDownSampleTo441 = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DOWNSAMPLETO441, FALSE); - fCustomChannelMapping = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CUSTOMCHANNELMAPPING, FALSE); - - BOOL bResult = pApp->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_SPEAKERTOCHANNELMAPPING, &ptr, &len); - if (bResult && len == sizeof(pSpeakerToChannelMap)) { - memcpy(pSpeakerToChannelMap, ptr, sizeof(pSpeakerToChannelMap)); - } else { - ZeroMemory(pSpeakerToChannelMap, sizeof(pSpeakerToChannelMap)); - for (int j = 0; j < 18; j++) { - for (int i = 0; i <= j; i++) { - pSpeakerToChannelMap[j][i] = 1 << i; - } - } - - pSpeakerToChannelMap[0][0] = 1 << 0; - pSpeakerToChannelMap[0][1] = 1 << 0; - - pSpeakerToChannelMap[3][0] = 1 << 0; - pSpeakerToChannelMap[3][1] = 1 << 1; - pSpeakerToChannelMap[3][2] = 0; - pSpeakerToChannelMap[3][3] = 0; - pSpeakerToChannelMap[3][4] = 1 << 2; - pSpeakerToChannelMap[3][5] = 1 << 3; - - pSpeakerToChannelMap[4][0] = 1 << 0; - pSpeakerToChannelMap[4][1] = 1 << 1; - pSpeakerToChannelMap[4][2] = 1 << 2; - pSpeakerToChannelMap[4][3] = 0; - pSpeakerToChannelMap[4][4] = 1 << 3; - pSpeakerToChannelMap[4][5] = 1 << 4; - } - if (bResult) { - delete [] ptr; - } - - fAudioNormalize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZE, FALSE); - nAudioMaxNormFactor = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOMAXNORMFACTOR, 400); - fAudioNormalizeRecover = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZERECOVER, TRUE); - nAudioBoost = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, 0); - - nSpeakerChannels = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPEAKERCHANNELS, 2); - - // External filters - LoadExternalFilters(m_filters); - - m_pnspresets.RemoveAll(); - - for (int i = 0; i < (ID_PANNSCAN_PRESETS_END - ID_PANNSCAN_PRESETS_START); i++) { - CString str2; - str2.Format(_T("Preset%d"), i); - str2 = pApp->GetProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, str2); - if (str2.IsEmpty()) { - break; - } - m_pnspresets.Add(str2); - } - - if (m_pnspresets.IsEmpty()) { - const double _4p3 = 4.0 / 3.0; - const double _16p9 = 16.0 / 9.0; - const double _185p1 = 1.85 / 1.0; - const double _235p1 = 2.35 / 1.0; - UNREFERENCED_PARAMETER(_185p1); - - CString str2; - str2.Format(IDS_SCALE_16_9, 0.5, 0.5, /*_4p3 / _4p3 =*/ 1.0, _16p9 / _4p3); - m_pnspresets.Add(str2); - str2.Format(IDS_SCALE_WIDESCREEN, 0.5, 0.5, _16p9 / _4p3, _16p9 / _4p3); - m_pnspresets.Add(str2); - str2.Format(IDS_SCALE_ULTRAWIDE, 0.5, 0.5, _235p1 / _4p3, _235p1 / _4p3); - m_pnspresets.Add(str2); - } - - for (int i = 0; i < wmcmds.GetCount(); i++) { - CString str2; - str2.Format(_T("CommandMod%d"), i); - str2 = pApp->GetProfileString(IDS_R_COMMANDS, str2); - if (str2.IsEmpty()) { - break; - } - - wmcmd tmp; - int n; - int fVirt = 0; - BYTE ignore; - if (5 > (n = _stscanf_s(str2, _T("%hu %x %hx %S %d %hhu %u %hhu %hhu %hhu"), - &tmp.cmd, &fVirt, &tmp.key, tmp.rmcmd.GetBuffer(128), 128, - &tmp.rmrepcnt, &tmp.mouse, &tmp.appcmd, &ignore, - &tmp.mouseVirt, &ignore))) { - break; - } - tmp.rmcmd.ReleaseBuffer(); - if (n >= 2) { - tmp.fVirt = (BYTE)fVirt; - } - if (POSITION pos = wmcmds.Find(tmp)) { - wmcmd& wc = wmcmds.GetAt(pos); - wc.cmd = tmp.cmd; - wc.fVirt = tmp.fVirt; - wc.key = tmp.key; - if (n >= 6) { - wc.mouse = tmp.mouse; - } - if (n >= 7) { - wc.appcmd = tmp.appcmd; - } - if (n >= 9) { - wc.mouseVirt = tmp.mouseVirt; - } - wc.rmcmd = tmp.rmcmd.Trim('\"'); - wc.rmrepcnt = tmp.rmrepcnt; - } - } - - CAtlArray pAccel; - pAccel.SetCount(ACCEL_LIST_SIZE); - int accel_count = 0; - POSITION pos = wmcmds.GetHeadPosition(); - for (int i = 0; pos; i++) { - ACCEL x = wmcmds.GetNext(pos); - if (x.key > 0) { - pAccel[accel_count] = x; - accel_count++; - } - } - hAccel = CreateAcceleratorTable(pAccel.GetData(), accel_count); - - strWinLircAddr = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WINLIRCADDR, _T("127.0.0.1:8765")); - fWinLirc = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WINLIRC, FALSE); - strUIceAddr = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_UICEADDR, _T("127.0.0.1:1234")); - fUIce = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UICE, FALSE); - fGlobalMedia = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_GLOBALMEDIA, TRUE); - - nJumpDistS = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTS, DEFAULT_JUMPDISTANCE_1); - nJumpDistM = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTM, DEFAULT_JUMPDISTANCE_2); - nJumpDistL = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTL, DEFAULT_JUMPDISTANCE_3); - fLimitWindowProportions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LIMITWINDOWPROPORTIONS, FALSE); - - m_Formats.UpdateData(false); - - // Internal filters - for (int f = 0; f < SRC_LAST; f++) { - SrcFilters[f] = !!pApp->GetProfileInt(IDS_R_INTERNAL_FILTERS, SrcFiltersKeys[f].name, SrcFiltersKeys[f].bDefault); - } - for (int f = 0; f < TRA_LAST; f++) { - TraFilters[f] = !!pApp->GetProfileInt(IDS_R_INTERNAL_FILTERS, TraFiltersKeys[f].name, TraFiltersKeys[f].bDefault); - } - - strLogoFileName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_LOGOFILE); - nLogoId = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOID, -1); - fLogoExternal = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOEXT, FALSE); - fLogoColorProfileEnabled = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOCOLORPROFILE, FALSE); - - fHideCDROMsSubMenu = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECDROMSSUBMENU, FALSE); - - dwPriority = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITY, NORMAL_PRIORITY_CLASS); - ::SetPriorityClass(::GetCurrentProcess(), dwPriority); - fLaunchfullscreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LAUNCHFULLSCREEN, FALSE); - - fEnableWebServer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWEBSERVER, FALSE); - nWebServerPort = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPORT, 13579); - fWebServerUseCompression = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERUSECOMPRESSION, TRUE); - fWebServerLocalhostOnly = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERLOCALHOSTONLY, FALSE); - bWebUIEnablePreview = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBUI_ENABLE_PREVIEW, FALSE); - fWebServerPrintDebugInfo = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPRINTDEBUGINFO, FALSE); - strWebRoot = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBROOT, _T("*./webroot")); - strWebDefIndex = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBDEFINDEX, _T("index.html;index.php")); - strWebServerCGI = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBSERVERCGI); - - CString MyPictures; - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), KEY_READ)) { - ULONG lenValue = 1024; - if (ERROR_SUCCESS == key.QueryStringValue(_T("My Pictures"), MyPictures.GetBuffer((int)lenValue), &lenValue)) { - MyPictures.ReleaseBufferSetLength((int)lenValue); - } else { - MyPictures.Empty(); - } - } - strSnapshotPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTPATH, MyPictures); - strSnapshotExt = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTEXT, _T(".jpg")); - bSnapShotSubtitles = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTSUBTITLES, TRUE); - bSnapShotKeepVideoExtension = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTKEEPVIDEOEXTENSION, TRUE); - - iThumbRows = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBROWS, 4); - iThumbCols = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBCOLS, 4); - iThumbWidth = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBWIDTH, 1024); - - bSubSaveExternalStyleFile = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBSAVEEXTERNALSTYLEFILE, FALSE); - nLastUsedPage = WORD(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTUSEDPAGE, 0)); - - { - // Load the list of extra (non-default) shader files - m_ShadersExtraList = ShaderList(pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_EXTRA)); - // Load shader selection - m_Shaders.SetCurrentPreset(ShaderPreset(pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_PRERESIZE), - pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_POSTRESIZE))); - // Load shader presets - ShaderSelection::ShaderPresetMap presets; - for (int i = 0;; i++) { - CString iStr; - iStr.Format(_T("%d"), i); - CString name = pApp->GetProfileString(IDS_R_SHADER_PRESETS, iStr); - if (name.IsEmpty()) { - break; - } - presets.emplace(name, ShaderPreset(pApp->GetProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_PRERESIZE + iStr), - pApp->GetProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_POSTRESIZE + iStr))); - } - m_Shaders.SetPresets(presets); - // Load last shader preset name - CString name = pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_LASTPRESET); - if (!name.IsEmpty()) { - m_Shaders.SetCurrentPreset(name); - } - } - - fD3DFullscreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_D3DFULLSCREEN, FALSE); - - iBrightness = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_BRIGHTNESS, 0); - iContrast = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_CONTRAST, 0); - iHue = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_HUE, 0); - iSaturation = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_SATURATION, 0); - - fShowOSD = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOWOSD, TRUE); - fShowCurrentTimeInOSD = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CURRENT_TIME_OSD, FALSE); - - nOSDTransparency = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_TRANSPARENCY, 64); - nOSDBorder = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_BORDER, 1); - - fEnableEDLEditor = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEEDLEDITOR, FALSE); - bFastSeek = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK, TRUE); - eFastSeekMethod = static_cast( - pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK_METHOD, FASTSEEK_NEAREST_KEYFRAME)); - fShowChapters = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CHAPTERS, TRUE); - - - fLCDSupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, FALSE); - - fSeekPreview = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW, FALSE); - iSeekPreviewSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW_SIZE, 15); - if (iSeekPreviewSize < 5) iSeekPreviewSize = 5; - if (iSeekPreviewSize > 40) iSeekPreviewSize = 40; - - // Save analog capture settings - iDefaultCaptureDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, 0); - strAnalogVideo = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, _T("dummy")); - strAnalogAudio = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, _T("dummy")); - iAnalogCountry = pApp->GetProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, 1); - - //strBDANetworkProvider = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER); - strBDATuner = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER); - strBDAReceiver = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER); - //sBDAStandard = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD); - iBDAScanFreqStart = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, 474000); - iBDAScanFreqEnd = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, 858000); - iBDABandwidth = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, 8); - iBDASymbolRate = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SYMBOLRATE, 0); - fBDAUseOffset = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_USE_OFFSET, FALSE); - iBDAOffset = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_OFFSET, 166); - fBDAIgnoreEncryptedChannels = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_IGNORE_ENCRYPTED_CHANNELS, FALSE); - nDVBLastChannel = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, INT_ERROR); - nDVBRebuildFilterGraph = (DVB_RebuildFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, DVB_STOP_FG_ALWAYS); - nDVBStopFilterGraph = (DVB_StopFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, DVB_STOP_FG_ALWAYS); - - for (int iChannel = 0; ; iChannel++) { - CString strTemp; - strTemp.Format(_T("%d"), iChannel); - CString strChannel = pApp->GetProfileString(IDS_R_DVB, strTemp); - if (strChannel.IsEmpty()) { - break; - } - try { - m_DVBChannels.emplace_back(strChannel); - } catch (CException* e) { - // The tokenisation can fail if the input string was invalid - TRACE(_T("Failed to parse a DVB channel from string \"%s\""), strChannel.GetString()); - ASSERT(FALSE); - e->Delete(); - } - } - - // playback positions for last played files - fRememberFilePos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS, FALSE); - iRememberPosForLongerThan = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSLONGER, 5); - bRememberPosForAudioFiles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSAUDIO, TRUE); - if (iRememberPosForLongerThan < 0) { - iRememberPosForLongerThan = 5; - } - bRememberExternalPlaylistPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_PLAYLIST, TRUE); - bRememberTrackSelection = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_TRACK_SELECTION, TRUE); - - // playback positions for last played DVDs - fRememberDVDPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DVDPOS, FALSE); - - bToggleShader = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADER, TRUE); - bToggleShaderScreenSpace = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADERSSCREENSPACE, TRUE); - - fRemainingTime = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMAINING_TIME, FALSE); - bHighPrecisionTimer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIGH_PRECISION_TIMER, FALSE); - bTimerShowPercentage = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIMER_SHOW_PERCENTAGE, FALSE); - - nUpdaterAutoCheck = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_AUTO_CHECK, AUTOUPDATE_UNKNOWN); - nUpdaterDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_DELAY, 7); - if (nUpdaterDelay < 1) { - nUpdaterDelay = 1; - } - - bNotifySkype = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_NOTIFY_SKYPE, FALSE); - - nJpegQuality = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JPEG_QUALITY, 90); - if (nJpegQuality < 20 || nJpegQuality > 100) { - nJpegQuality = 90; - } - - bEnableCoverArt = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART, TRUE); - nCoverArtSizeLimit = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART_SIZE_LIMIT, 600); - - bEnableLogging = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGGING, FALSE); - bUseLegacyToolbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_LEGACY_TOOLBAR, FALSE); - - eSubtitleRenderer = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, static_cast(SubtitleRenderer::INTERNAL))); - if (eSubtitleRenderer == SubtitleRenderer::RESERVED) { - eSubtitleRenderer = SubtitleRenderer::INTERNAL; - bRenderSSAUsingLibass = true; - } - - nDefaultToolbarSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTTOOLBARSIZE, 24); - - bSaveImagePosition = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_POSITION, TRUE); - bSaveImageCurrentTime = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_CURRENTTIME, FALSE); - - bAllowInaccurateFastseek = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_INACCURATE_FASTSEEK, TRUE); - bLoopFolderOnPlayNextFile = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP_FOLDER_NEXT_FILE, FALSE); - - bLockNoPause = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOCK_NOPAUSE, FALSE); - bPreventDisplaySleep = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_DISPLAY_SLEEP, TRUE); - bUseSMTC = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_SMTC, FALSE); - iReloadAfterLongPause = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RELOAD_AFTER_LONG_PAUSE, 0); - bOpenRecPanelWhenOpeningDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OPEN_REC_PANEL_WHEN_OPENING_DEVICE, TRUE); - - sanear->SetOutputDevice(pApp->GetProfileString(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_ID), - pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_EXCLUSIVE, FALSE), - pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_BUFFER, - SaneAudioRenderer::ISettings::OUTPUT_DEVICE_BUFFER_DEFAULT_MS)); - - sanear->SetCrossfeedEnabled(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_ENABLED, FALSE)); - - sanear->SetCrossfeedSettings(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ, - SaneAudioRenderer::ISettings::CROSSFEED_CUTOFF_FREQ_CMOY), - pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, - SaneAudioRenderer::ISettings::CROSSFEED_LEVEL_CMOY)); - - sanear->SetIgnoreSystemChannelMixer(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_IGNORE_SYSTEM_MIXER, TRUE)); - - bUseYDL = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_YDL, TRUE); - iYDLMaxHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, 1440); - iYDLVideoFormat = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_VIDEO_FORMAT, 0); - iYDLAudioFormat = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_FORMAT, 0); - bYDLAudioOnly = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, FALSE); - sYDLExePath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_EXEPATH, _T("")); - sYDLCommandLine = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_COMMAND_LINE, _T("")); - - bEnableCrashReporter = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLE_CRASH_REPORTER, TRUE); - - nStreamPosPollerInterval = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_REFRESH_INTERVAL, 100); - bShowLangInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_LANG_STATUSBAR, FALSE); - bShowFPSInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_FPS_STATUSBAR, FALSE); - bShowABMarksInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_ABMARKS_STATUSBAR, FALSE); - bShowVideoInfoInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_VIDEOINFO_STATUSBAR, TRUE); - bShowAudioFormatInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_AUDIOFORMAT_STATUSBAR, TRUE); - - bAddLangCodeWhenSaveSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ADD_LANGCODE_WHEN_SAVE_SUBTITLES, FALSE); - bUseTitleInRecentFileList = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TITLE_IN_RECENT_FILE_LIST, TRUE); - sYDLSubsPreference = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_SUBS_PREFERENCE, _T("")); - bUseAutomaticCaptions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_AUTOMATIC_CAPTIONS, FALSE); - - lastQuickOpenPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_QUICKOPEN_PATH, L""); - lastFileSaveCopyPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_FILESAVECOPY_PATH, L""); - lastFileOpenDirPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_FILEOPENDIR_PATH, L""); - externalPlayListPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_EXTERNAL_PLAYLIST_PATH, L""); - - iRedirectOpenToAppendThreshold = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REDIRECT_OPEN_TO_APPEND_THRESHOLD, 1000); - bFullscreenSeparateControls = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_SEPARATE_CONTROLS, TRUE); - bAlwaysUseShortMenu = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALWAYS_USE_SHORT_MENU, FALSE); - iStillVideoDuration = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_STILL_VIDEO_DURATION, 10); - iMouseLeftUpDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MOUSE_LEFTUP_DELAY, 0); - - if (bMPCTheme) { - CMPCTheme::InitializeColors(eModernThemeMode); - } - // GUI theme can be used now - static_cast(AfxGetApp())->m_bThemeLoaded = bMPCTheme; - - if (fLaunchfullscreen && slFiles.GetCount() > 0) { - nCLSwitches |= CLSW_FULLSCREEN; - } - - bInitialized = true; -} - -bool CAppSettings::GetAllowMultiInst() const -{ - return !!AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, FALSE); -} - -void CAppSettings::UpdateRenderersData(bool fSave) -{ - CWinApp* pApp = AfxGetApp(); - CRenderersSettings& r = m_RenderersSettings; - CRenderersSettings::CAdvRendererSettings& ars = r.m_AdvRendSets; - - if (fSave) { - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_APSURACEFUSAGE, r.iAPSurfaceUsage); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DX9_RESIZER, r.iDX9Resizer); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VMR9MIXERMODE, r.fVMR9MixerMode); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRAlternateVSync"), ars.bVMR9AlterativeVSync); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSyncOffset"), ars.iVMR9VSyncOffset); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSyncAccurate2"), ars.bVMR9VSyncAccurate); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFullscreenGUISupport"), ars.bVMR9FullscreenGUISupport); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSync"), ars.bVMR9VSync); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRDisableDesktopComposition"), ars.bVMRDisableDesktopComposition); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFullFloatingPointProcessing2"), ars.bVMR9FullFloatingPointProcessing); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRHalfFloatingPointProcessing"), ars.bVMR9HalfFloatingPointProcessing); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementEnable"), ars.bVMR9ColorManagementEnable); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementInput"), ars.iVMR9ColorManagementInput); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementAmbientLight"), ars.iVMR9ColorManagementAmbientLight); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementIntent"), ars.iVMR9ColorManagementIntent); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVROutputRange"), ars.iEVROutputRange); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVRHighColorRes"), ars.bEVRHighColorResolution); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVRForceInputHighColorRes"), ars.bEVRForceInputHighColorResolution); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVREnableFrameTimeCorrection"), ars.bEVREnableFrameTimeCorrection); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUBeforeVSync"), ars.bVMRFlushGPUBeforeVSync); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUAfterPresent"), ars.bVMRFlushGPUAfterPresent); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUWait"), ars.bVMRFlushGPUWait); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("DesktopSizeBackBuffer"), ars.bDesktopSizeBackBuffer); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeClock"), ars.bSynchronizeVideo); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeDisplay"), ars.bSynchronizeDisplay); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeNearest"), ars.bSynchronizeNearest); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("LineDelta"), ars.iLineDelta); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("ColumnDelta"), ars.iColumnDelta); - - pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("CycleDelta"), (LPBYTE) & (ars.fCycleDelta), sizeof(ars.fCycleDelta)); - pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("TargetSyncOffset"), (LPBYTE) & (ars.fTargetSyncOffset), sizeof(ars.fTargetSyncOffset)); - pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("ControlLimit"), (LPBYTE) & (ars.fControlLimit), sizeof(ars.fControlLimit)); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CACHESHADERS, ars.bCacheShaders); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("ResetDevice"), r.fResetDevice); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCSIZE, r.subPicQueueSettings.nSize); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESX, r.subPicQueueSettings.nMaxResX); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESY, r.subPicQueueSettings.nMaxResY); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, r.subPicQueueSettings.bDisableSubtitleAnimation); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDER_AT_WHEN_ANIM_DISABLED, r.subPicQueueSettings.nRenderAtWhenAnimationIsDisabled); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_ANIMATION_RATE, r.subPicQueueSettings.nAnimationRate); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_DROPPING_SUBPIC, r.subPicQueueSettings.bAllowDroppingSubpic); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_EVR_BUFFERS, r.iEvrBuffers); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_D3D9RENDERDEVICE, r.D3D9RenderDevice); - } else { - r.iAPSurfaceUsage = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_APSURACEFUSAGE, VIDRNDT_AP_TEXTURE3D); - r.iDX9Resizer = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DX9_RESIZER, 1); - r.fVMR9MixerMode = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VMR9MIXERMODE, TRUE); - - CRenderersSettings::CAdvRendererSettings DefaultSettings; - ars.bVMR9AlterativeVSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRAlternateVSync"), DefaultSettings.bVMR9AlterativeVSync); - ars.iVMR9VSyncOffset = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSyncOffset"), DefaultSettings.iVMR9VSyncOffset); - ars.bVMR9VSyncAccurate = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSyncAccurate2"), DefaultSettings.bVMR9VSyncAccurate); - ars.bVMR9FullscreenGUISupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFullscreenGUISupport"), DefaultSettings.bVMR9FullscreenGUISupport); - ars.bEVRHighColorResolution = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVRHighColorRes"), DefaultSettings.bEVRHighColorResolution); - ars.bEVRForceInputHighColorResolution = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVRForceInputHighColorRes"), DefaultSettings.bEVRForceInputHighColorResolution); - ars.bEVREnableFrameTimeCorrection = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVREnableFrameTimeCorrection"), DefaultSettings.bEVREnableFrameTimeCorrection); - ars.bVMR9VSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSync"), DefaultSettings.bVMR9VSync); - ars.bVMRDisableDesktopComposition = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRDisableDesktopComposition"), DefaultSettings.bVMRDisableDesktopComposition); - ars.bVMR9FullFloatingPointProcessing = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFullFloatingPointProcessing2"), DefaultSettings.bVMR9FullFloatingPointProcessing); - ars.bVMR9HalfFloatingPointProcessing = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRHalfFloatingPointProcessing"), DefaultSettings.bVMR9HalfFloatingPointProcessing); - - ars.bVMR9ColorManagementEnable = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementEnable"), DefaultSettings.bVMR9ColorManagementEnable); - ars.iVMR9ColorManagementInput = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementInput"), DefaultSettings.iVMR9ColorManagementInput); - ars.iVMR9ColorManagementAmbientLight = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementAmbientLight"), DefaultSettings.iVMR9ColorManagementAmbientLight); - ars.iVMR9ColorManagementIntent = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementIntent"), DefaultSettings.iVMR9ColorManagementIntent); - - ars.iEVROutputRange = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVROutputRange"), DefaultSettings.iEVROutputRange); - - ars.bVMRFlushGPUBeforeVSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUBeforeVSync"), DefaultSettings.bVMRFlushGPUBeforeVSync); - ars.bVMRFlushGPUAfterPresent = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUAfterPresent"), DefaultSettings.bVMRFlushGPUAfterPresent); - ars.bVMRFlushGPUWait = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUWait"), DefaultSettings.bVMRFlushGPUWait); - - ars.bDesktopSizeBackBuffer = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("DesktopSizeBackBuffer"), DefaultSettings.bDesktopSizeBackBuffer); - - ars.bSynchronizeVideo = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeClock"), DefaultSettings.bSynchronizeVideo); - ars.bSynchronizeDisplay = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeDisplay"), DefaultSettings.bSynchronizeDisplay); - ars.bSynchronizeNearest = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeNearest"), DefaultSettings.bSynchronizeNearest); - ars.iLineDelta = pApp->GetProfileInt(IDS_R_SETTINGS, _T("LineDelta"), DefaultSettings.iLineDelta); - ars.iColumnDelta = pApp->GetProfileInt(IDS_R_SETTINGS, _T("ColumnDelta"), DefaultSettings.iColumnDelta); - - double* dPtr; - UINT dSize; - if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("CycleDelta"), (LPBYTE*)&dPtr, &dSize)) { - ars.fCycleDelta = *dPtr; - delete [] dPtr; - } - - if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("TargetSyncOffset"), (LPBYTE*)&dPtr, &dSize)) { - ars.fTargetSyncOffset = *dPtr; - delete [] dPtr; - } - if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("ControlLimit"), (LPBYTE*)&dPtr, &dSize)) { - ars.fControlLimit = *dPtr; - delete [] dPtr; - } - - ars.bCacheShaders = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CACHESHADERS, DefaultSettings.bCacheShaders); - if (AfxGetMyApp()->GetAppSavePath(ars.sShaderCachePath)) { - ars.sShaderCachePath = PathUtils::CombinePaths(ars.sShaderCachePath, IDS_R_SHADER_CACHE); - } - - r.fResetDevice = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("ResetDevice"), FALSE); - - r.subPicQueueSettings.nSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCSIZE, 0); - r.subPicQueueSettings.nMaxResX = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESX, 2560); - r.subPicQueueSettings.nMaxResY = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESY, 1440); - if (r.subPicQueueSettings.nMaxResX < 600 || r.subPicQueueSettings.nMaxResY < 480) { - r.subPicQueueSettings.nMaxResX = 2560; - r.subPicQueueSettings.nMaxResY = 1440; - } - r.subPicQueueSettings.bDisableSubtitleAnimation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, FALSE); - r.subPicQueueSettings.nRenderAtWhenAnimationIsDisabled = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDER_AT_WHEN_ANIM_DISABLED, 50); - r.subPicQueueSettings.nAnimationRate = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_ANIMATION_RATE, 100); - r.subPicQueueSettings.bAllowDroppingSubpic = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_DROPPING_SUBPIC, TRUE); - - r.subPicVerticalShift = 0; - r.fontScaleOverride = 1.0; - - r.iEvrBuffers = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_EVR_BUFFERS, 5); - r.D3D9RenderDevice = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_D3D9RENDERDEVICE); - } -} - -__int64 CAppSettings::ConvertTimeToMSec(const CString& time) const -{ - __int64 Sec = 0; - __int64 mSec = 0; - __int64 mult = 1; - - int pos = time.GetLength() - 1; - if (pos < 3) { - return 0; - } - - while (pos >= 0) { - TCHAR ch = time[pos]; - if (ch == '.') { - mSec = Sec * 1000 / mult; - Sec = 0; - mult = 1; - } else if (ch == ':') { - mult = mult * 6 / 10; - } else if (ch >= '0' && ch <= '9') { - Sec += (ch - '0') * mult; - mult *= 10; - } else { - mSec = Sec = 0; - break; - } - pos--; - } - return Sec * 1000 + mSec; -} - -void CAppSettings::ExtractDVDStartPos(CString& strParam) -{ - int i = 0, j = 0; - for (CString token = strParam.Tokenize(_T("#"), i); - j < 3 && !token.IsEmpty(); - token = strParam.Tokenize(_T("#"), i), j++) { - switch (j) { - case 0: - lDVDTitle = token.IsEmpty() ? 0 : (ULONG)_wtol(token); - break; - case 1: - if (token.Find(':') > 0) { - UINT h = 0, m = 0, s = 0, f = 0; - int nRead = _stscanf_s(token, _T("%02u:%02u:%02u.%03u"), &h, &m, &s, &f); - if (nRead >= 3) { - DVDPosition.bHours = (BYTE)h; - DVDPosition.bMinutes = (BYTE)m; - DVDPosition.bSeconds = (BYTE)s; - DVDPosition.bFrames = (BYTE)f; - } - } else { - lDVDChapter = token.IsEmpty() ? 0 : (ULONG)_wtol(token); - } - break; - } - } -} - -CString CAppSettings::ParseFileName(CString const& param) -{ - if (param.Find(_T(":")) < 0 && param.Left(2) != L"\\\\") { - // Try to transform relative pathname into full pathname - CString fullPathName; - DWORD dwLen = GetFullPathName(param, 2048, fullPathName.GetBuffer(2048), nullptr); - if (dwLen > 0 && dwLen < 2048) { - fullPathName.ReleaseBuffer(dwLen); - - if (!fullPathName.IsEmpty() && PathUtils::Exists(fullPathName)) { - return fullPathName; - } - } - } else { - CString fullPathName = param; - ExtendMaxPathLengthIfNeeded(fullPathName); - return fullPathName; - } - - return param; -} - -void CAppSettings::ParseCommandLine(CAtlList& cmdln) -{ - UINT64 existingAfterPlaybackCL = nCLSwitches & CLSW_AFTERPLAYBACK_MASK; - nCLSwitches = 0; - slFiles.RemoveAll(); - slDubs.RemoveAll(); - slSubs.RemoveAll(); - slFilters.RemoveAll(); - rtStart = 0; - rtShift = 0; - lDVDTitle = 0; - lDVDChapter = 0; - ZeroMemory(&DVDPosition, sizeof(DVDPosition)); - iAdminOption = 0; - sizeFixedWindow.SetSize(0, 0); - fixedWindowPosition = NO_FIXED_POSITION; - iMonitor = 0; - strPnSPreset.Empty(); - - POSITION pos = cmdln.GetHeadPosition(); - while (pos) { - const CString& param = cmdln.GetNext(pos); - if (param.IsEmpty()) { - continue; - } - - if ((param[0] == '-' || param[0] == '/') && param.GetLength() > 1) { - CString sw = param.Mid(1).MakeLower(); - if (sw == _T("open")) { - nCLSwitches |= CLSW_OPEN; - } else if (sw == _T("play")) { - nCLSwitches |= CLSW_PLAY; - } else if (sw == _T("fullscreen")) { - nCLSwitches |= CLSW_FULLSCREEN; - } else if (sw == _T("minimized")) { - nCLSwitches |= CLSW_MINIMIZED; - } else if (sw == _T("new")) { - nCLSwitches |= CLSW_NEW; - } else if (sw == _T("help") || sw == _T("h") || sw == _T("?")) { - nCLSwitches |= CLSW_HELP; - } else if (sw == _T("dub") && pos) { - slDubs.AddTail(ParseFileName(cmdln.GetNext(pos))); - } else if (sw == _T("dubdelay") && pos) { - CString strFile = ParseFileName(cmdln.GetNext(pos)); - int nPos = strFile.Find(_T("DELAY")); - if (nPos != -1) { - rtShift = 10000i64 * _tstol(strFile.Mid(nPos + 6)); - } - slDubs.AddTail(strFile); - } else if (sw == _T("sub") && pos) { - slSubs.AddTail(ParseFileName(cmdln.GetNext(pos))); - } else if (sw == _T("filter") && pos) { - slFilters.AddTail(cmdln.GetNext(pos)); - } else if (sw == _T("dvd")) { - nCLSwitches |= CLSW_DVD; - } else if (sw == _T("dvdpos") && pos) { - ExtractDVDStartPos(cmdln.GetNext(pos)); - } else if (sw == _T("cd")) { - nCLSwitches |= CLSW_CD; - } else if (sw == _T("device")) { - nCLSwitches |= CLSW_DEVICE; - } else if (sw == _T("add")) { - nCLSwitches |= CLSW_ADD; - } else if (sw == _T("randomize")) { - nCLSwitches |= CLSW_RANDOMIZE; - } else if (sw == _T("volume") && pos) { - int setVolumeVal = _ttoi(cmdln.GetNext(pos)); - if (setVolumeVal >= 0 && setVolumeVal <= 100) { - nCmdVolume = setVolumeVal; - nCLSwitches |= CLSW_VOLUME; - } else { - nCLSwitches |= CLSW_UNRECOGNIZEDSWITCH; - } - } else if (sw == _T("regvid")) { - nCLSwitches |= CLSW_REGEXTVID; - } else if (sw == _T("regaud")) { - nCLSwitches |= CLSW_REGEXTAUD; - } else if (sw == _T("regpl")) { - nCLSwitches |= CLSW_REGEXTPL; - } else if (sw == _T("regall")) { - nCLSwitches |= (CLSW_REGEXTVID | CLSW_REGEXTAUD | CLSW_REGEXTPL); - } else if (sw == _T("unregall")) { - nCLSwitches |= CLSW_UNREGEXT; - } else if (sw == _T("unregvid")) { - nCLSwitches |= CLSW_UNREGEXT; /* keep for compatibility with old versions */ - } else if (sw == _T("unregaud")) { - nCLSwitches |= CLSW_UNREGEXT; /* keep for compatibility with old versions */ - } else if (sw == _T("iconsassoc")) { - nCLSwitches |= CLSW_ICONSASSOC; - } else if (sw == _T("start") && pos) { - rtStart = 10000i64 * _tcstol(cmdln.GetNext(pos), nullptr, 10); - nCLSwitches |= CLSW_STARTVALID; - } else if (sw == _T("startpos") && pos) { - rtStart = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); - nCLSwitches |= CLSW_STARTVALID; - } else if (sw == _T("nofocus")) { - nCLSwitches |= CLSW_NOFOCUS; - } else if (sw == _T("close")) { - nCLSwitches |= CLSW_CLOSE; - } else if (sw == _T("standby")) { - nCLSwitches |= CLSW_STANDBY; - } else if (sw == _T("hibernate")) { - nCLSwitches |= CLSW_HIBERNATE; - } else if (sw == _T("shutdown")) { - nCLSwitches |= CLSW_SHUTDOWN; - } else if (sw == _T("logoff")) { - nCLSwitches |= CLSW_LOGOFF; - } else if (sw == _T("lock")) { - nCLSwitches |= CLSW_LOCK; - } else if (sw == _T("d3dfs")) { - nCLSwitches |= CLSW_D3DFULLSCREEN; - } else if (sw == _T("adminoption") && pos) { - nCLSwitches |= CLSW_ADMINOPTION; - iAdminOption = _ttoi(cmdln.GetNext(pos)); - } else if (sw == _T("slave") && pos) { - nCLSwitches |= CLSW_SLAVE; - hMasterWnd = (HWND)IntToPtr(_ttoi(cmdln.GetNext(pos))); - } else if (sw == _T("fixedsize") && pos) { - CAtlList sl; - // Optional arguments for the main window's position - Explode(cmdln.GetNext(pos), sl, ',', 4); - if (sl.GetCount() == 4) { - fixedWindowPosition.SetPoint(_ttol(sl.GetAt(sl.FindIndex(2))), _ttol(sl.GetAt(sl.FindIndex(3))) ); - } - if (sl.GetCount() >= 2) { - sizeFixedWindow.SetSize(_ttol(sl.GetAt(sl.FindIndex(0))), _ttol(sl.GetAt(sl.FindIndex(1))) ); - if (sizeFixedWindow.cx > 0 && sizeFixedWindow.cy > 0) { - nCLSwitches |= CLSW_FIXEDSIZE; - } - } - } else if (sw == _T("viewpreset") && pos) { - int viewPreset = _ttoi(cmdln.GetNext(pos)); - switch (viewPreset) { - case 1: - nCLSwitches |= CLSW_PRESET1; - break; - case 2: - nCLSwitches |= CLSW_PRESET2; - break; - case 3: - nCLSwitches |= CLSW_PRESET3; - break; - default: - nCLSwitches |= CLSW_UNRECOGNIZEDSWITCH; - break; - } - } else if (sw == _T("monitor") && pos) { - iMonitor = _tcstol(cmdln.GetNext(pos), nullptr, 10); - nCLSwitches |= CLSW_MONITOR; - } else if (sw == _T("pns") && pos) { - strPnSPreset = cmdln.GetNext(pos); - } else if (sw == _T("webport") && pos) { - int tmpport = _tcstol(cmdln.GetNext(pos), nullptr, 10); - if (tmpport >= 0 && tmpport <= 65535) { - nCmdlnWebServerPort = tmpport; - } - } else if (sw == _T("debug")) { - fShowDebugInfo = true; - } else if (sw == _T("nocrashreporter")) { -#if USE_DRDUMP_CRASH_REPORTER - if (CrashReporter::IsEnabled()) { - CrashReporter::Disable(); - MPCExceptionHandler::Enable(); - } -#endif - } else if (sw == _T("audiorenderer") && pos) { - SetAudioRenderer(_ttoi(cmdln.GetNext(pos))); - } else if (sw == _T("shaderpreset") && pos) { - m_Shaders.SetCurrentPreset(cmdln.GetNext(pos)); - } else if (sw == _T("reset")) { - nCLSwitches |= CLSW_RESET; - } else if (sw == _T("mute")) { - nCLSwitches |= CLSW_MUTE; - } else if (sw == _T("monitoroff")) { - nCLSwitches |= CLSW_MONITOROFF; - } else if (sw == _T("playnext")) { - nCLSwitches |= CLSW_PLAYNEXT; - } else if (sw == _T("hwgpu") && pos) { - iLAVGPUDevice = _tcstol(cmdln.GetNext(pos), nullptr, 10); - } else if (sw == _T("configlavsplitter")) { - nCLSwitches |= CLSW_CONFIGLAVSPLITTER; - } else if (sw == _T("configlavaudio")) { - nCLSwitches |= CLSW_CONFIGLAVAUDIO; - } else if (sw == _T("configlavvideo")) { - nCLSwitches |= CLSW_CONFIGLAVVIDEO; - } else if (sw == L"ab_start" && pos) { - abRepeat.positionA = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); - } else if (sw == L"ab_end" && pos) { - abRepeat.positionB = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); - } else if (sw == L"thumbnails") { - nCLSwitches |= CLSW_THUMBNAILS | CLSW_NEW; - } else { - nCLSwitches |= CLSW_HELP | CLSW_UNRECOGNIZEDSWITCH; - } - } else { - if (param == _T("-")) { // Special case: standard input - slFiles.AddTail(_T("pipe://stdin")); - } else { - const_cast(param) = ParseFileName(param); - slFiles.AddTail(param); - } - } - } - - if (abRepeat.positionA && abRepeat.positionB && abRepeat.positionA >= abRepeat.positionB) { - abRepeat.positionA = 0; - abRepeat.positionB = 0; - } - if (abRepeat.positionA > rtStart || (abRepeat.positionB && abRepeat.positionB < rtStart)) { - rtStart = abRepeat.positionA; - nCLSwitches |= CLSW_STARTVALID; - } - - if (0 == (nCLSwitches & CLSW_AFTERPLAYBACK_MASK)) { //no changes to playback mask, so let's preserve existing - nCLSwitches |= existingAfterPlaybackCL; - } -} - -void CAppSettings::GetFav(favtype ft, CAtlList& sl) const -{ - sl.RemoveAll(); - - CString root; - - switch (ft) { - case FAV_FILE: - root = IDS_R_FAVFILES; - break; - case FAV_DVD: - root = IDS_R_FAVDVDS; - break; - case FAV_DEVICE: - root = IDS_R_FAVDEVICES; - break; - default: - return; - } - - for (int i = 0; ; i++) { - CString s; - s.Format(_T("Name%d"), i); - s = AfxGetApp()->GetProfileString(root, s); - if (s.IsEmpty()) { - break; - } - sl.AddTail(s); - } -} - -void CAppSettings::SetFav(favtype ft, CAtlList& sl) -{ - CString root; - - switch (ft) { - case FAV_FILE: - root = IDS_R_FAVFILES; - break; - case FAV_DVD: - root = IDS_R_FAVDVDS; - break; - case FAV_DEVICE: - root = IDS_R_FAVDEVICES; - break; - default: - return; - } - - AfxGetApp()->WriteProfileString(root, nullptr, nullptr); - - int i = 0; - POSITION pos = sl.GetHeadPosition(); - while (pos) { - CString s; - s.Format(_T("Name%d"), i++); - AfxGetApp()->WriteProfileString(root, s, sl.GetNext(pos)); - } -} - -void CAppSettings::AddFav(favtype ft, CString s) -{ - CAtlList sl; - GetFav(ft, sl); - if (sl.Find(s)) { - return; - } - sl.AddTail(s); - SetFav(ft, sl); -} - -CBDAChannel* CAppSettings::FindChannelByPref(int nPrefNumber) -{ - auto it = find_if(m_DVBChannels.begin(), m_DVBChannels.end(), [&](CBDAChannel const & channel) { - return channel.GetPrefNumber() == nPrefNumber; - }); - - return it != m_DVBChannels.end() ? &(*it) : nullptr; -} - -// Settings::CRecentFileAndURLList -CAppSettings::CRecentFileAndURLList::CRecentFileAndURLList(UINT nStart, LPCTSTR lpszSection, - LPCTSTR lpszEntryFormat, int nSize, - int nMaxDispLen) - : CRecentFileList(nStart, lpszSection, lpszEntryFormat, nSize, nMaxDispLen) -{ -} - -extern BOOL AFXAPI AfxComparePath(LPCTSTR lpszPath1, LPCTSTR lpszPath2); - -void CAppSettings::CRecentFileAndURLList::Add(LPCTSTR lpszPathName) -{ - ASSERT(m_arrNames != nullptr); - ASSERT(lpszPathName != nullptr); - ASSERT(AfxIsValidString(lpszPathName)); - - if (m_nSize <= 0 || CString(lpszPathName).MakeLower().Find(_T("@device:")) >= 0) { - return; - } - - CString pathName = lpszPathName; - - bool fURL = PathUtils::IsURL(pathName); - - // fully qualify the path name - if (!fURL) { - pathName = MakeFullPath(pathName); - } - - // update the MRU list, if an existing MRU string matches file name - int iMRU; - for (iMRU = 0; iMRU < m_nSize - 1; iMRU++) { - if ((fURL && !_tcscmp(m_arrNames[iMRU], pathName)) - || AfxComparePath(m_arrNames[iMRU], pathName)) { - break; // iMRU will point to matching entry - } - } - // move MRU strings before this one down - for (; iMRU > 0; iMRU--) { - ASSERT(iMRU > 0); - ASSERT(iMRU < m_nSize); - m_arrNames[iMRU] = m_arrNames[iMRU - 1]; - } - // place this one at the beginning - m_arrNames[0] = pathName; -} - -void CAppSettings::CRecentFileAndURLList::SetSize(int nSize) -{ - ENSURE_ARG(nSize >= 0); - - if (m_nSize != nSize) { - CString* arrNames = DEBUG_NEW CString[nSize]; - int nSizeToCopy = std::min(m_nSize, nSize); - for (int i = 0; i < nSizeToCopy; i++) { - arrNames[i] = m_arrNames[i]; - } - delete [] m_arrNames; - m_arrNames = arrNames; - m_nSize = nSize; - } -} - -#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) -CStringW getShortHash(PBYTE bytes, ULONG size) { - BCRYPT_ALG_HANDLE algHandle = nullptr; - BCRYPT_HASH_HANDLE hashHandle = nullptr; - - PBYTE hash = nullptr; - DWORD hashLen = 0; - DWORD cbResult = 0; - ULONG dwFlags = 0; - const int shortHashLen = 12; - - NTSTATUS stat; - CStringW shortHash = L""; - - stat = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_SHA1_ALGORITHM, nullptr, 0); - if (NT_SUCCESS(stat)) { - stat = BCryptGetProperty(algHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hashLen, sizeof(hashLen), &cbResult, dwFlags); - if (NT_SUCCESS(stat)) { - hash = (PBYTE)HeapAlloc(GetProcessHeap(), dwFlags, hashLen); - if (nullptr != hash) { - stat = BCryptCreateHash(algHandle, &hashHandle, nullptr, 0, nullptr, 0, dwFlags); - if (NT_SUCCESS(stat)) { - stat = BCryptHashData(hashHandle, bytes, size, dwFlags); - if (NT_SUCCESS(stat)) { - stat = BCryptFinishHash(hashHandle, hash, hashLen, 0); - if (NT_SUCCESS(stat)) { - DWORD hashStrLen = 0; - if (CryptBinaryToStringW(hash, hashLen, CRYPT_STRING_BASE64, nullptr, &hashStrLen) && hashStrLen > 0) { - CStringW longHash; - if (CryptBinaryToStringW(hash, hashLen, CRYPT_STRING_BASE64, longHash.GetBuffer(hashStrLen - 1), &hashStrLen)) { - longHash.ReleaseBuffer(hashStrLen); - shortHash = longHash.Left(shortHashLen); - } else { - longHash.ReleaseBuffer(); - } - } - } - } - } - } - } - } - - if (nullptr != hash) { - HeapFree(GetProcessHeap(), dwFlags, hash); - } - - if (nullptr != hashHandle) { - BCryptDestroyHash(hashHandle); - } - - if (nullptr != algHandle) { - BCryptCloseAlgorithmProvider(algHandle, dwFlags); - } - - return shortHash; -} - -CStringW getRFEHash(CStringW fn) { - fn.MakeLower(); - CStringW hash = getShortHash((PBYTE)fn.GetString(), fn.GetLength() * sizeof(WCHAR)); - if (hash.IsEmpty()) { - ASSERT(FALSE); - hash = fn.Right(30); - hash.Replace(L"\\", L"/"); - } - return hash; -} - -CStringW getRFEHash(ULONGLONG llDVDGuid) { - CStringW hash; - hash.Format(L"DVD%llu", llDVDGuid); - return hash; -} - -CStringW getRFEHash(RecentFileEntry &r) { - CStringW fn; - if (r.DVDPosition.llDVDGuid) { - return getRFEHash(r.DVDPosition.llDVDGuid); - } else { - fn = r.fns.GetHead(); - return getRFEHash(fn); - } -} - -/* -void CAppSettings::CRecentFileListWithMoreInfo::Remove(size_t nIndex) { - if (nIndex >= 0 && nIndex < rfe_array.GetCount()) { - auto pApp = AfxGetMyApp(); - CStringW& hash = rfe_array[nIndex].hash; - if (!hash.IsEmpty()) { - pApp->RemoveProfileKey(m_section, hash); - } - rfe_array.RemoveAt(nIndex); - rfe_array.FreeExtra(); - } - if (nIndex == 0 && rfe_array.GetCount() == 0) { - // list was cleared - current_rfe_hash.Empty(); - } -} -*/ - -void CAppSettings::CRecentFileListWithMoreInfo::Add(LPCTSTR fn) { - RecentFileEntry r; - LoadMediaHistoryEntryFN(fn, r); - Add(r, true); -} - -void CAppSettings::CRecentFileListWithMoreInfo::Add(LPCTSTR fn, ULONGLONG llDVDGuid) { - RecentFileEntry r; - LoadMediaHistoryEntryDVD(llDVDGuid, fn, r); - Add(r, true); -} - -bool CAppSettings::CRecentFileListWithMoreInfo::GetCurrentIndex(size_t& idx) { - for (int i = 0; i < rfe_array.GetCount(); i++) { - if (rfe_array[i].hash == current_rfe_hash) { - idx = i; - return true; - } - } - return false; -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentFilePosition(REFERENCE_TIME time, bool forcePersist /* = false */) { - size_t idx; - if (GetCurrentIndex(idx)) { - rfe_array[idx].filePosition = time; - if (forcePersist || std::abs(persistedFilePosition - time) > 300000000) { - WriteMediaHistoryEntry(rfe_array[idx]); - } - } -} - -REFERENCE_TIME CAppSettings::CRecentFileListWithMoreInfo::GetCurrentFilePosition() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].filePosition; - } - return 0; -} - -ABRepeat CAppSettings::CRecentFileListWithMoreInfo::GetCurrentABRepeat() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].abRepeat; - } - return ABRepeat(); -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentDVDTimecode(DVD_HMSF_TIMECODE* time) { - size_t idx; - if (GetCurrentIndex(idx)) { - DVD_POSITION* dvdPosition = &rfe_array[idx].DVDPosition; - if (dvdPosition) { - memcpy(&dvdPosition->timecode, (void*)time, sizeof(DVD_HMSF_TIMECODE)); - } - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentDVDTitle(DWORD title) { - size_t idx; - if (GetCurrentIndex(idx)) { - DVD_POSITION* dvdPosition = &rfe_array[idx].DVDPosition; - if (dvdPosition) { - dvdPosition->lTitle = title; - } - } -} - -DVD_POSITION CAppSettings::CRecentFileListWithMoreInfo::GetCurrentDVDPosition() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].DVDPosition; - } - return DVD_POSITION(); -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentAudioTrack(int audioIndex) { - size_t idx; - if (GetCurrentIndex(idx)) { - if (rfe_array[idx].AudioTrackIndex != audioIndex) { - rfe_array[idx].AudioTrackIndex = audioIndex; - WriteMediaHistoryAudioIndex(rfe_array[idx]); - } - } -} - -int CAppSettings::CRecentFileListWithMoreInfo::GetCurrentAudioTrack() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].AudioTrackIndex; - } - return -1; -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentSubtitleTrack(int subIndex) { - size_t idx; - if (GetCurrentIndex(idx)) { - if (rfe_array[idx].SubtitleTrackIndex != subIndex) { - rfe_array[idx].SubtitleTrackIndex = subIndex; - WriteMediaHistorySubtitleIndex(rfe_array[idx]); - } - } -} - -int CAppSettings::CRecentFileListWithMoreInfo::GetCurrentSubtitleTrack() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].SubtitleTrackIndex; - } - return -1; -} - -void CAppSettings::CRecentFileListWithMoreInfo::AddSubToCurrent(CStringW subpath) { - size_t idx; - if (GetCurrentIndex(idx)) { - bool found = rfe_array[idx].subs.Find(subpath); - if (!found) { - rfe_array[idx].subs.AddHead(subpath); - WriteMediaHistoryEntry(rfe_array[idx]); - } - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::SetCurrentTitle(CStringW title) { - size_t idx; - if (GetCurrentIndex(idx)) { - rfe_array[idx].title = title; - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentABRepeat(ABRepeat abRepeat) { - size_t idx; - if (GetCurrentIndex(idx)) { - rfe_array[idx].abRepeat = abRepeat; - WriteMediaHistoryEntry(rfe_array[idx]); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::WriteCurrentEntry() { - size_t idx; - if (!current_rfe_hash.IsEmpty() && GetCurrentIndex(idx)) { - WriteMediaHistoryEntry(rfe_array[idx]); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::Add(RecentFileEntry r, bool current_open) { - if (r.fns.GetCount() < 1) { - return; - } - if (CString(r.fns.GetHead()).MakeLower().Find(_T("@device:")) >= 0) { - return; - } - - if (r.hash.IsEmpty()) { - r.hash = getRFEHash(r); - } - for (size_t i = 0; i < rfe_array.GetCount(); i++) { - if (r.hash == rfe_array[i].hash) { - rfe_array.RemoveAt(i); //do not call Remove as it will purge reg key. we are just resorting - break; - } - } - WriteMediaHistoryEntry(r, true); - - rfe_array.InsertAt(0, r); - if (current_open) { - current_rfe_hash = r.hash; - persistedFilePosition = r.filePosition; - } - - // purge obsolete entry - if (rfe_array.GetCount() > m_maxSize) { - CStringW hash = rfe_array.GetAt(m_maxSize).hash; - if (!hash.IsEmpty()) { - CStringW subSection; - subSection.Format(L"%s\\%s", m_section, static_cast(hash)); - auto pApp = AfxGetMyApp(); - pApp->WriteProfileString(subSection, nullptr, nullptr); - } - rfe_array.SetCount(m_maxSize); - } - rfe_array.FreeExtra(); -} - -static void DeserializeHex(LPCTSTR strVal, BYTE* pBuffer, int nBufSize) { - long lRes; - - for (int i = 0; i < nBufSize; i++) { - _stscanf_s(strVal + (i * 2), _T("%02lx"), &lRes); - pBuffer[i] = (BYTE)lRes; - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::ReadLegacyMediaHistory(std::map& filenameToIndex) { - rfe_array.RemoveAll(); - auto pApp = AfxGetMyApp(); - LPCWSTR legacySection = L"Recent File List"; - int dvdCount = 0; - for (size_t i = 1; i <= m_maxSize; i++) { - CStringW t; - t.Format(_T("File%zu"), i); - CStringW fn = pApp->GetProfileStringW(legacySection, t); - if (fn.IsEmpty()) { - break; - } - t.Format(_T("Title%zu"), i); - CStringW title = pApp->GetProfileStringW(legacySection, t); - t.Format(_T("Cue%zu"), i); - CStringW cue = pApp->GetProfileStringW(legacySection, t); - RecentFileEntry r; - r.fns.AddTail(fn); - r.title = title; - r.cue = cue; - int k = 2; - for (;; k++) { - t.Format(_T("File%zu,%d"), i, k); - CStringW ft = pApp->GetProfileStringW(legacySection, t); - if (ft.IsEmpty()) break; - r.fns.AddTail(ft); - } - k = 1; - for (;; k++) { - t.Format(_T("Sub%zu,%d"), i, k); - CStringW st = pApp->GetProfileStringW(legacySection, t); - if (st.IsEmpty()) break; - r.subs.AddTail(st); - } - if (fn.Right(9) == L"\\VIDEO_TS") { //try to find the dvd position from index - CStringW strDVDPos; - strDVDPos.Format(_T("DVD Position %d"), dvdCount++); - CStringW strValue = pApp->GetProfileString(IDS_R_SETTINGS, strDVDPos, _T("")); - - if (!strValue.IsEmpty()) { - if (strValue.GetLength() / 2 == sizeof(DVD_POSITION)) { - DeserializeHex(strValue, (BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); - } - } - rfe_array.Add(r); - } else { - filenameToIndex[r.fns.GetHead()] = rfe_array.Add(r); - } - } - rfe_array.FreeExtra(); -} - -static CString SerializeHex(const BYTE* pBuffer, int nBufSize) { - CString strTemp; - CString strResult; - - for (int i = 0; i < nBufSize; i++) { - strTemp.Format(_T("%02x"), pBuffer[i]); - strResult += strTemp; - } - - return strResult; -} - -void CAppSettings::CRecentFileListWithMoreInfo::ReadLegacyMediaPosition(std::map& filenameToIndex) { - auto pApp = AfxGetMyApp(); - bool hasNextEntry = true; - CStringW strFilename; - CStringW strFilePos; - - for (int i = 0; i < 1000 && hasNextEntry; i++) { - strFilename.Format(_T("File Name %d"), i); - CStringW strFile = pApp->GetProfileString(IDS_R_SETTINGS, strFilename); - - if (strFile.IsEmpty()) { - hasNextEntry = false; - } else { - strFilePos.Format(_T("File Position %d"), i); - if (filenameToIndex.count(strFile)) { - size_t index = filenameToIndex[strFile]; - if (index < rfe_array.GetCount()) { - CStringW strValue = pApp->GetProfileString(IDS_R_SETTINGS, strFilePos); - rfe_array.GetAt(index).filePosition = _tstoi64(strValue); - } - } - // remove old values - pApp->WriteProfileString(IDS_R_SETTINGS, strFilename, nullptr); - pApp->WriteProfileString(IDS_R_SETTINGS, strFilePos, nullptr); - } - } -} - -bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntryFN(CStringW fn, RecentFileEntry& r) { - CStringW hash = getRFEHash(fn); - if (!LoadMediaHistoryEntry(hash, r)) { - r.hash = hash; - r.fns.AddHead(fn); //otherwise add a new entry - return false; - } - return true; -} - -bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntryDVD(ULONGLONG llDVDGuid, CStringW fn, RecentFileEntry& r) { - CStringW hash = getRFEHash(llDVDGuid); - if (!LoadMediaHistoryEntry(hash, r)) { - r.hash = hash; - r.fns.AddHead(fn); //otherwise add a new entry - r.DVDPosition.llDVDGuid = llDVDGuid; - return false; - } - return true; -} - -bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntry(CStringW hash, RecentFileEntry &r) { - auto pApp = AfxGetMyApp(); - CStringW fn, subSection, t; - - subSection.Format(L"%s\\%s", m_section, static_cast(hash)); - - fn = pApp->GetProfileStringW(subSection, L"Filename", L""); - if (fn.IsEmpty()) { - return false; - } - - DWORD filePosition = pApp->GetProfileIntW(subSection, L"FilePosition", 0); - CStringW dvdPosition = pApp->GetProfileStringW(subSection, L"DVDPosition", L""); - - r.hash = hash; - r.fns.AddHead(fn); - r.title = pApp->GetProfileStringW(subSection, L"Title", L""); - r.cue = pApp->GetProfileStringW(subSection, L"Cue", L""); - r.filePosition = filePosition * 10000LL; - if (!dvdPosition.IsEmpty()) { - if (dvdPosition.GetLength() / 2 == sizeof(DVD_POSITION)) { - DeserializeHex(dvdPosition, (BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); - } - } - r.abRepeat.positionA = pApp->GetProfileIntW(subSection, L"abRepeat.positionA", 0) * 10000LL; - r.abRepeat.positionB = pApp->GetProfileIntW(subSection, L"abRepeat.positionB", 0) * 10000LL; - r.abRepeat.dvdTitle = pApp->GetProfileIntW(subSection, L"abRepeat.dvdTitle", -1); - - int k = 2; - for (;; k++) { - t.Format(_T("Filename%03d"), k); - CStringW ft = pApp->GetProfileStringW(subSection, t); - if (ft.IsEmpty()) { - break; - } - r.fns.AddTail(ft); - } - k = 1; - for (;; k++) { - t.Format(_T("Sub%03d"), k); - CStringW st = pApp->GetProfileStringW(subSection, t); - if (st.IsEmpty()) { - break; - } - r.subs.AddTail(st); - } - - r.AudioTrackIndex = pApp->GetProfileIntW(subSection, L"AudioTrackIndex", -1); - r.SubtitleTrackIndex = pApp->GetProfileIntW(subSection, L"SubtitleTrackIndex", -1); - return true; -} - -void CAppSettings::CRecentFileListWithMoreInfo::ReadMediaHistory() { - auto pApp = AfxGetMyApp(); - - int lastAddedStored = pApp->GetProfileIntW(m_section, L"LastAdded", 0); - if (lastAddedStored != 0 && lastAddedStored == rfe_last_added || rfe_last_added == 1) { - return; - } - listModifySequence++; - - size_t maxsize = AfxGetAppSettings().fKeepHistory ? m_maxSize : 0; - - std::list hashes = pApp->GetSectionSubKeys(m_section); - - if (hashes.empty()) { - if (maxsize > 0) { - MigrateLegacyHistory(); - hashes = pApp->GetSectionSubKeys(m_section); - } else { - rfe_last_added = 1; - rfe_array.RemoveAll(); - return; - } - } - - auto timeToHash = CAppSettings::LoadHistoryHashes(m_section, L"LastOpened"); - - rfe_array.RemoveAll(); - int entries = 0; - for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { - bool purge_rfe = true; - CStringW hash = iter->second; - if (entries < maxsize) { - RecentFileEntry r; - r.lastOpened = iter->first; - if (LoadMediaHistoryEntry(hash, r)) { - rfe_array.Add(r); - purge_rfe = false; - entries++; - } - } - if (purge_rfe) { //purge entry - CAppSettings::PurgeExpiredHash(m_section, hash); - } - } - rfe_array.FreeExtra(); - - if (lastAddedStored == 0 && m_maxSize > 0) { - rfe_last_added = 1; // history read, but nothing new added yet - pApp->WriteProfileInt(m_section, L"LastAdded", rfe_last_added); - } else { - rfe_last_added = lastAddedStored; - } - - // The playlist history size is not managed elsewhere - CAppSettings::PurgePlaylistHistory(maxsize); -} - -void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistoryAudioIndex(RecentFileEntry& r) { - auto pApp = AfxGetMyApp(); - - if (r.hash.IsEmpty()) { - r.hash = getRFEHash(r.fns.GetHead()); - } - - CStringW subSection, t; - subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); - - if (r.AudioTrackIndex != -1) { - pApp->WriteProfileInt(subSection, L"AudioTrackIndex", int(r.AudioTrackIndex)); - } else { - pApp->WriteProfileStringW(subSection, L"AudioTrackIndex", nullptr); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistorySubtitleIndex(RecentFileEntry& r) { - auto pApp = AfxGetMyApp(); - - if (r.hash.IsEmpty()) { - r.hash = getRFEHash(r.fns.GetHead()); - } - - CStringW subSection, t; - subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); - - if (r.SubtitleTrackIndex != -1) { - pApp->WriteProfileInt(subSection, L"SubtitleTrackIndex", int(r.SubtitleTrackIndex)); - } else { - pApp->WriteProfileStringW(subSection, L"SubtitleTrackIndex", nullptr); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistoryEntry(RecentFileEntry& r, bool updateLastOpened /* = false */) { - auto pApp = AfxGetMyApp(); - - if (r.hash.IsEmpty()) { - r.hash = getRFEHash(r.fns.GetHead()); - } - - CStringW subSection, t; - subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); - - CString storedFilename = pApp->GetProfileStringW(subSection, L"Filename", L""); - bool isNewEntry = storedFilename.IsEmpty(); - if (isNewEntry || storedFilename != r.fns.GetHead()) { - pApp->WriteProfileStringW(subSection, L"Filename", r.fns.GetHead()); - } - - if (r.fns.GetCount() > 1) { - int k = 2; - POSITION p(r.fns.GetHeadPosition()); - r.fns.GetNext(p); - while (p != nullptr) { - CString fn = r.fns.GetNext(p); - t.Format(L"Filename%03d", k); - pApp->WriteProfileStringW(subSection, t, fn); - k++; - } - } - if (!r.title.IsEmpty()) { - t = L"Title"; - pApp->WriteProfileStringW(subSection, t, r.title); - } - if (!r.cue.IsEmpty()) { - t = L"Cue"; - pApp->WriteProfileStringW(subSection, t, r.cue); - } - if (r.subs.GetCount() > 0) { - int k = 1; - POSITION p(r.subs.GetHeadPosition()); - while (p != nullptr) { - CString fn = r.subs.GetNext(p); - t.Format(L"Sub%03d", k); - pApp->WriteProfileStringW(subSection, t, fn); - k++; - } - } - if (r.DVDPosition.llDVDGuid) { - t = L"DVDPosition"; - CStringW strValue = SerializeHex((BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); - pApp->WriteProfileStringW(subSection, t, strValue); - } else { - t = L"FilePosition"; - pApp->WriteProfileInt(subSection, t, int(r.filePosition / 10000LL)); - persistedFilePosition = r.filePosition; - } - if (r.abRepeat.positionA) { - pApp->WriteProfileInt(subSection, L"abRepeat.positionA", int(r.abRepeat.positionA / 10000LL)); - } else { - pApp->WriteProfileStringW(subSection, L"abRepeat.positionA", nullptr); - } - if (r.abRepeat.positionB) { - pApp->WriteProfileInt(subSection, L"abRepeat.positionB", int(r.abRepeat.positionB / 10000LL)); - } else { - pApp->WriteProfileStringW(subSection, L"abRepeat.positionB", nullptr); - } - if (r.abRepeat && r.abRepeat.dvdTitle != -1) { - pApp->WriteProfileInt(subSection, L"abRepeat.dvdTitle", int(r.abRepeat.dvdTitle)); - } else { - pApp->WriteProfileStringW(subSection, L"abRepeat.dvdTitle", nullptr); - } - - if (r.AudioTrackIndex != -1) { - pApp->WriteProfileInt(subSection, L"AudioTrackIndex", int(r.AudioTrackIndex)); - } else { - pApp->WriteProfileStringW(subSection, L"AudioTrackIndex", nullptr); - } - - if (r.SubtitleTrackIndex != -1) { - pApp->WriteProfileInt(subSection, L"SubtitleTrackIndex", int(r.SubtitleTrackIndex)); - } else { - pApp->WriteProfileStringW(subSection, L"SubtitleTrackIndex", nullptr); - } - - if (updateLastOpened || isNewEntry || r.lastOpened.IsEmpty()) { - auto now = std::chrono::system_clock::now(); - auto nowISO = date::format(L"%FT%TZ", date::floor(now)); - r.lastOpened = CStringW(nowISO.c_str()); - pApp->WriteProfileStringW(subSection, L"LastOpened", r.lastOpened); - if (isNewEntry) { - rfe_last_added = (int)std::chrono::time_point_cast(now).time_since_epoch().count(); - pApp->WriteProfileInt(m_section, L"LastAdded", rfe_last_added); - } - } - listModifySequence++; -} - -void CAppSettings::CRecentFileListWithMoreInfo::SaveMediaHistory() { - if (rfe_array.GetCount()) { - //go in reverse in case we are setting last opened when migrating history (makes last appear oldest) - for (size_t i = rfe_array.GetCount() - 1, j = 0; j < m_maxSize && j < rfe_array.GetCount(); i--, j++) { - auto& r = rfe_array.GetAt(i); - WriteMediaHistoryEntry(r); - } - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::MigrateLegacyHistory() { - auto pApp = AfxGetMyApp(); - std::map filenameToIndex; - ReadLegacyMediaHistory(filenameToIndex); - ReadLegacyMediaPosition(filenameToIndex); - SaveMediaHistory(); - LPCWSTR legacySection = L"Recent File List"; - pApp->WriteProfileString(legacySection, nullptr, nullptr); -} - -void CAppSettings::CRecentFileListWithMoreInfo::SetSize(size_t nSize) { - m_maxSize = nSize; - if (rfe_array.GetCount() > m_maxSize) { - rfe_array.SetCount(m_maxSize); - PurgeMediaHistory(m_maxSize); - PurgePlaylistHistory(m_maxSize); - // to force update of recent files menu - listModifySequence++; - } - rfe_array.FreeExtra(); - - if (nSize == 0) { - current_rfe_hash.Empty(); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::RemoveAll() { - SetSize(0); -} - -bool CAppSettings::IsVSFilterInstalled() -{ - return IsCLSIDRegistered(CLSID_VSFilter); -} - -void CAppSettings::UpdateSettings() -{ - auto pApp = AfxGetMyApp(); - ASSERT(pApp); - - UINT version = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_R_VERSION, 0); - if (version >= APPSETTINGS_VERSION) { - return; // Nothing to update - } - - // Use lambda expressions to copy data entries - auto copyInt = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { - if (pApp->HasProfileEntry(oldSection, oldEntry)) { - int old = pApp->GetProfileInt(oldSection, oldEntry, 0); - VERIFY(pApp->WriteProfileInt(newSection, newEntry, old)); - } - }; - auto copyStr = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { - if (pApp->HasProfileEntry(oldSection, oldEntry)) { - CString old = pApp->GetProfileString(oldSection, oldEntry); - VERIFY(pApp->WriteProfileString(newSection, newEntry, old)); - } - }; - auto copyBin = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { - UINT len; - BYTE* old; - if (pApp->GetProfileBinary(oldSection, oldEntry, &old, &len)) { - VERIFY(pApp->WriteProfileBinary(newSection, newEntry, old, len)); - delete [] old; - } - }; - - - // Migrate to the latest version, these cases should fall through - // so that all incremental updates are applied. - switch (version) { - case 0: { - UINT nAudioBoostTmp = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, -1); - if (nAudioBoostTmp == UINT(-1)) { - double dAudioBoost_dB = _tstof(pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, _T("0"))); - if (dAudioBoost_dB < 0 || dAudioBoost_dB > 10) { - dAudioBoost_dB = 0; - } - nAudioBoostTmp = UINT(100 * pow(10.0, dAudioBoost_dB / 20.0) + 0.5) - 100; - } - if (nAudioBoostTmp > 300) { // Max boost is 300% - nAudioBoostTmp = 300; - } - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, nAudioBoostTmp); - } - { - const CString section(_T("Settings")); - copyInt(section, _T("Remember DVD Pos"), section, _T("RememberDVDPos")); - copyInt(section, _T("Remember File Pos"), section, _T("RememberFilePos")); - copyInt(section, _T("Show OSD"), section, _T("ShowOSD")); - copyStr(section, _T("Shaders List"), section, _T("ShadersList")); - copyInt(section, _T("OSD_Size"), section, _T("OSDSize")); - copyStr(section, _T("OSD_Font"), section, _T("OSDFont")); - copyInt(section, _T("gotoluf"), section, _T("GoToLastUsed")); - copyInt(section, _T("fps"), section, _T("GoToFPS")); - } - { - // Copy DVB section - const CString oldSection(_T("DVB configuration")); - const CString newSection(_T("DVBConfiguration")); - //copyStr(oldSection, _T("BDANetworkProvider"), newSection, _T("BDANetworkProvider")); - copyStr(oldSection, _T("BDATuner"), newSection, _T("BDATuner")); - copyStr(oldSection, _T("BDAReceiver"), newSection, _T("BDAReceiver")); - copyInt(oldSection, _T("BDAScanFreqStart"), newSection, _T("BDAScanFreqStart")); - copyInt(oldSection, _T("BDAScanFreqEnd"), newSection, _T("BDAScanFreqEnd")); - copyInt(oldSection, _T("BDABandWidth"), newSection, _T("BDABandWidth")); - copyInt(oldSection, _T("BDAUseOffset"), newSection, _T("BDAUseOffset")); - copyInt(oldSection, _T("BDAOffset"), newSection, _T("BDAOffset")); - copyInt(oldSection, _T("BDAIgnoreEncryptedChannels"), newSection, _T("BDAIgnoreEncryptedChannels")); - copyInt(oldSection, _T("LastChannel"), newSection, _T("LastChannel")); - copyInt(oldSection, _T("RebuildFilterGraph"), newSection, _T("RebuildFilterGraph")); - copyInt(oldSection, _T("StopFilterGraph"), newSection, _T("StopFilterGraph")); - for (int iChannel = 0; ; iChannel++) { - CString strTemp, strChannel; - strTemp.Format(_T("%d"), iChannel); - if (!pApp->HasProfileEntry(oldSection, strTemp)) { - break; - } - strChannel = pApp->GetProfileString(oldSection, strTemp); - if (strChannel.IsEmpty()) { - break; - } - VERIFY(pApp->WriteProfileString(newSection, strTemp, strChannel)); - } - } - [[fallthrough]]; - case 1: { - // Internal decoding of WMV 1/2/3 is now disabled by default so we reinitialize its value - pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, _T("TRA_WMV"), FALSE); - } - [[fallthrough]]; - case 2: { - const CString section(_T("Settings")); - if (pApp->HasProfileEntry(section, _T("FullScreenCtrls")) && - pApp->HasProfileEntry(section, _T("FullScreenCtrlsTimeOut"))) { - bool bHide = true; - int nHidePolicy = 0; - int nTimeout = -1; - if (!pApp->GetProfileInt(section, _T("FullScreenCtrls"), 0)) { - // hide always - } else { - nTimeout = pApp->GetProfileInt(section, _T("FullScreenCtrlsTimeOut"), 0); - if (nTimeout < 0) { - // show always - bHide = false; - } else if (nTimeout == 0) { - // show when hovered - nHidePolicy = 1; - } else { - // show when mouse moved - nHidePolicy = 2; - } - } - VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControls"), bHide)); - if (nTimeout >= 0) { - VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControlsPolicy"), nHidePolicy)); - VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControlsDelay"), nTimeout * 1000)); - } - } - } - [[fallthrough]]; - case 3: { -#pragma pack(push, 1) - struct dispmode { - bool fValid; - CSize size; - int bpp, freq; - DWORD dmDisplayFlags; - }; - - struct fpsmode { - double vfr_from; - double vfr_to; - bool fChecked; - dispmode dmFSRes; - bool fIsData; - }; - - struct AChFR { - bool bEnabled; - fpsmode dmFullscreenRes[30]; - bool bApplyDefault; - }; //AutoChangeFullscrRes -#pragma pack(pop) - - LPBYTE ptr; - UINT len; - bool bSetDefault = true; - if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("FullscreenRes"), &ptr, &len)) { - if (len == sizeof(AChFR)) { - AChFR autoChangeFullscrRes; - memcpy(&autoChangeFullscrRes, ptr, sizeof(AChFR)); - - autoChangeFSMode.bEnabled = autoChangeFullscrRes.bEnabled; - autoChangeFSMode.bApplyDefaultModeAtFSExit = autoChangeFullscrRes.bApplyDefault; - - for (size_t i = 0; i < _countof(autoChangeFullscrRes.dmFullscreenRes); i++) { - const auto& modeOld = autoChangeFullscrRes.dmFullscreenRes[i]; - // The old settings could be corrupted quite easily so be careful when converting them - if (modeOld.fIsData - && modeOld.vfr_from >= 0.0 && modeOld.vfr_from <= 126.0 - && modeOld.vfr_to >= 0.0 && modeOld.vfr_to <= 126.0 - && modeOld.dmFSRes.fValid - && modeOld.dmFSRes.bpp == 32 - && modeOld.dmFSRes.size.cx >= 640 && modeOld.dmFSRes.size.cx < 10000 - && modeOld.dmFSRes.size.cy >= 380 && modeOld.dmFSRes.size.cy < 10000 - && modeOld.dmFSRes.freq > 0 && modeOld.dmFSRes.freq < 1000) { - DisplayMode dm; - dm.bValid = true; - dm.size = modeOld.dmFSRes.size; - dm.bpp = 32; - dm.freq = modeOld.dmFSRes.freq; - dm.dwDisplayFlags = modeOld.dmFSRes.dmDisplayFlags & DM_INTERLACED; - - autoChangeFSMode.modes.emplace_back(modeOld.fChecked, modeOld.vfr_from, modeOld.vfr_to, 0, std::move(dm)); - } - } - - bSetDefault = autoChangeFSMode.modes.empty() || autoChangeFSMode.modes[0].dFrameRateStart != 0.0 || autoChangeFSMode.modes[0].dFrameRateStop != 0.0; - } - delete [] ptr; - } - - if (bSetDefault) { - autoChangeFSMode.bEnabled = false; - autoChangeFSMode.bApplyDefaultModeAtFSExit = false; - autoChangeFSMode.modes.clear(); - } - autoChangeFSMode.bRestoreResAfterProgExit = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("RestoreResAfterExit"), TRUE); - autoChangeFSMode.uDelay = pApp->GetProfileInt(IDS_R_SETTINGS, _T("FullscreenResDelay"), 0); - - SaveSettingsAutoChangeFullScreenMode(); - } - [[fallthrough]]; - case 4: { - bool bDisableSubtitleAnimation = !pApp->GetProfileInt(IDS_R_SETTINGS, _T("SPCAllowAnimationWhenBuffering"), TRUE); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, bDisableSubtitleAnimation)); - } - [[fallthrough]]; - case 5: - copyInt(IDS_R_INTERNAL_FILTERS, _T("SRC_DTSAC3"), IDS_R_INTERNAL_FILTERS, _T("SRC_DTS")); - copyInt(IDS_R_INTERNAL_FILTERS, _T("SRC_DTSAC3"), IDS_R_INTERNAL_FILTERS, _T("SRC_AC3")); - [[fallthrough]]; - case 6: { - SubtitleRenderer subrenderer = SubtitleRenderer::INTERNAL; - if (!pApp->GetProfileInt(IDS_R_SETTINGS, _T("AutoloadSubtitles"), TRUE)) { - if (IsSubtitleRendererRegistered(SubtitleRenderer::VS_FILTER)) { - subrenderer = SubtitleRenderer::VS_FILTER; - } - if (IsSubtitleRendererRegistered(SubtitleRenderer::XY_SUB_FILTER)) { - int renderer = IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS; - renderer = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, renderer); - if (IsSubtitleRendererSupported(SubtitleRenderer::XY_SUB_FILTER, renderer)) { - subrenderer = SubtitleRenderer::XY_SUB_FILTER; - } - } - } - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, static_cast(subrenderer))); - } - [[fallthrough]]; - case 7: - // Update the settings after the removal of DirectX 7 renderers - switch (pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_DEFAULT)) { - case 3: // VIDRNDT_DS_VMR7WINDOWED - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_VMR9WINDOWED)); - break; - case 5: // VIDRNDT_DS_VMR7RENDERLESS - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_VMR9RENDERLESS)); - break; - } - [[fallthrough]]; - default: - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_R_VERSION, APPSETTINGS_VERSION); - } -} - -// RenderersSettings.h - -CRenderersData* GetRenderersData() { - return &AfxGetMyApp()->m_Renderers; -} - -CRenderersSettings& GetRenderersSettings() { - auto& s = AfxGetAppSettings(); - if (s.m_RenderersSettings.subPicQueueSettings.nSize > 0) { - // queue does not work properly with libass - if (s.bRenderSSAUsingLibass || s.bRenderSRTUsingLibass) { - s.m_RenderersSettings.subPicQueueSettings.nSize = 0; - } - } - return s.m_RenderersSettings; -} - -void CAppSettings::SavePlayListPosition(CStringW playlistPath, UINT position) { - auto pApp = AfxGetMyApp(); - ASSERT(pApp); - - auto hash = getRFEHash(playlistPath); - - CStringW subSection, t; - subSection.Format(L"%s\\%s", L"PlaylistHistory", static_cast(hash)); - pApp->WriteProfileInt(subSection, L"Position", position); - - auto now = std::chrono::system_clock::now(); - auto nowISO = date::format(L"%FT%TZ", date::floor(now)); - CStringW lastUpdated = CStringW(nowISO.c_str()); - pApp->WriteProfileStringW(subSection, L"LastUpdated", lastUpdated); -} - -UINT CAppSettings::GetSavedPlayListPosition(CStringW playlistPath) { - auto pApp = AfxGetMyApp(); - ASSERT(pApp); - - auto hash = getRFEHash(playlistPath); - - CStringW subSection, t; - subSection.Format(L"%s\\%s", L"PlaylistHistory", static_cast(hash)); - UINT position = pApp->GetProfileIntW(subSection, L"Position", -1); - if (position != (UINT)-1) { - return position; - } - return 0; -} - -// SubRendererSettings.h - -// Todo: move individual members of AppSettings into SubRendererSettings struct and use this function to get a reference to it -SubRendererSettings GetSubRendererSettings() { - const auto& s = AfxGetAppSettings(); - SubRendererSettings srs; - srs.defaultStyle = s.subtitlesDefStyle; - srs.overrideDefaultStyle = s.bSubtitleOverrideDefaultStyle || s.bSubtitleOverrideAllStyles; - srs.overrideAllStyles = s.bSubtitleOverrideAllStyles; -#if USE_LIBASS - srs.renderSSAUsingLibass = s.bRenderSSAUsingLibass; - srs.renderSRTUsingLibass = s.bRenderSRTUsingLibass; -#endif - OpenTypeLang::CStringAtoHintStr(srs.openTypeLangHint, s.strOpenTypeLangHint); - return srs; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "AppSettings.h" +#include "CrashReporter.h" +#include "FGFilter.h" +#include "FakeFilterMapper2.h" +#include "FileAssoc.h" +#include "ExceptionHandler.h" +#include "PathUtils.h" +#include "Translations.h" +#include "UpdateChecker.h" +#include "WinAPIUtils.h" +#include "moreuuids.h" +#include "mplayerc.h" +#include "../thirdparty/sanear/src/Factory.h" +#include +#include +#include +#include "date/date.h" +#include "PPageExternalFilters.h" +#include "../VideoRenderers/MPCVRAllocatorPresenter.h" +std::map CAppSettings::CommandIDToWMCMD; + +#pragma warning(push) +#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized +CAppSettings::CAppSettings() + : bInitialized(false) + , nCLSwitches(0) + , rtShift(0) + , rtStart(0) + , lDVDTitle(0) + , lDVDChapter(0) + , iMonitor(0) + , fShowDebugInfo(false) + , iAdminOption(0) + , fAllowMultipleInst(false) + , fTrayIcon(false) + , fShowOSD(true) + , fShowCurrentTimeInOSD(false) + , nOSDTransparency(64) + , nOSDBorder(1) + , fLimitWindowProportions(false) + , fSnapToDesktopEdges(false) + , fHideCDROMsSubMenu(false) + , dwPriority(NORMAL_PRIORITY_CLASS) + , iTitleBarTextStyle(1) + , fTitleBarTextTitle(false) + , fKeepHistory(true) + , iRecentFilesNumber(100) + , MRU(L"MediaHistory", iRecentFilesNumber) + , MRUDub(0, _T("Recent Dub List"), _T("Dub%d"), 20) + , fRememberDVDPos(false) + , fRememberFilePos(false) + , iRememberPosForLongerThan(5) + , bRememberPosForAudioFiles(true) + , bRememberExternalPlaylistPos(true) + , bRememberTrackSelection(true) + , bRememberPlaylistItems(true) + , fRememberWindowPos(false) + , fRememberWindowSize(false) + , rcLastWindowPos(CRect(100, 100, 500, 400)) + , fSavePnSZoom(false) + , dZoomX(1.0) + , dZoomY(1.0) + , fAssociatedWithIcons(true) + , hAccel(nullptr) + , fWinLirc(false) + , fUIce(false) + , fGlobalMedia(true) + , nLogoId(-1) + , fLogoExternal(false) + , fLogoColorProfileEnabled(false) + , fEnableWebServer(false) + , nWebServerPort(13579) + , nCmdlnWebServerPort(-1) + , fWebServerUseCompression(true) + , fWebServerLocalhostOnly(false) + , bWebUIEnablePreview(false) + , fWebServerPrintDebugInfo(false) + , nVolume(100) + , fMute(false) + , nBalance(0) + , nLoops(1) + , fLoopForever(false) + , eLoopMode(LoopMode::PLAYLIST) + , fRememberZoomLevel(true) + , nAutoFitFactorMin(75) + , nAutoFitFactorMax(75) + , iZoomLevel(1) + , fEnableWorkerThreadForOpening(true) + , fReportFailedPins(true) + , fAutoloadAudio(true) + , fBlockVSFilter(true) + , bBlockRDP(false) + , nVolumeStep(5) + , nSpeedStep(0) + , nDefaultToolbarSize(24) + , eAfterPlayback(AfterPlayback::DO_NOTHING) + , fUseDVDPath(false) + , idMenuLang(0) + , idAudioLang(0) + , idSubtitlesLang(0) + , fClosedCaptions(false) + , iDSVideoRendererType(VIDRNDT_DS_DEFAULT) + , fD3DFullscreen(false) + , fLaunchfullscreen(false) + , bHideFullscreenControls(true) + , eHideFullscreenControlsPolicy(HideFullscreenControlsPolicy::SHOW_WHEN_HOVERED) + , uHideFullscreenControlsDelay(0) + , bHideFullscreenDockedPanels(true) + , fExitFullScreenAtTheEnd(true) + , iDefaultCaptureDevice(0) + , iAnalogCountry(1) + , iBDAScanFreqStart(474000) + , iBDAScanFreqEnd(858000) + , iBDABandwidth(8) + , iBDASymbolRate(0) + , fBDAUseOffset(false) + , iBDAOffset(166) + , fBDAIgnoreEncryptedChannels(false) + , nDVBLastChannel(INT_ERROR) + , nDVBRebuildFilterGraph(DVB_REBUILD_FG_WHEN_SWITCHING) + , nDVBStopFilterGraph(DVB_STOP_FG_WHEN_SWITCHING) + , SrcFilters() + , TraFilters() + , fEnableAudioSwitcher(true) + , fAudioNormalize(false) + , nAudioMaxNormFactor(400) + , fAudioNormalizeRecover(true) + , nAudioBoost(0) + , fDownSampleTo441(false) + , fAudioTimeShift(false) + , iAudioTimeShift(0) + , fCustomChannelMapping(false) + , nSpeakerChannels(2) + , pSpeakerToChannelMap() + , fOverridePlacement(false) + , nHorPos(50) + , nVerPos(90) + , bSubtitleARCompensation(true) + , nSubDelayStep(500) + , bPreferDefaultForcedSubtitles(true) + , fPrioritizeExternalSubtitles(true) + , fDisableInternalSubtitles(true) + , bAllowOverridingExternalSplitterChoice(false) + , bAutoDownloadSubtitles(false) + , bAutoSaveDownloadedSubtitles(false) + , nAutoDownloadScoreMovies(0x16) + , nAutoDownloadScoreSeries(0x18) + , bAutoUploadSubtitles(false) + , bPreferHearingImpairedSubtitles(false) + , bMPCTheme(true) + , bWindows10DarkThemeActive(false) + , bWindows10AccentColorsEnabled(false) + , iModernSeekbarHeight(DEF_MODERN_SEEKBAR_HEIGHT) + , eModernThemeMode(CMPCTheme::ModernThemeMode::WINDOWSDEFAULT) + , iFullscreenDelay(MIN_FULLSCREEN_DELAY) + , iVerticalAlignVideo(verticalAlignVideoType::ALIGN_MIDDLE) + , nJumpDistS(DEFAULT_JUMPDISTANCE_1) + , nJumpDistM(DEFAULT_JUMPDISTANCE_2) + , nJumpDistL(DEFAULT_JUMPDISTANCE_3) + , bFastSeek(true) + , eFastSeekMethod(FASTSEEK_NEAREST_KEYFRAME) + , fShowChapters(true) + , bNotifySkype(false) + , fPreventMinimize(false) + , bUseEnhancedTaskBar(true) + , fLCDSupport(false) + , fSeekPreview(false) + , iSeekPreviewSize(15) + , fUseSearchInFolder(false) + , fUseSeekbarHover(true) + , nHoverPosition(TIME_TOOLTIP_ABOVE_SEEKBAR) + , nOSDSize(0) + , bHideWindowedMousePointer(true) + , iBrightness(0) + , iContrast(0) + , iHue(0) + , iSaturation(0) + , nUpdaterAutoCheck(-1) + , nUpdaterDelay(7) + , eCaptionMenuMode(MODE_SHOWCAPTIONMENU) + , fHideNavigation(false) + , nCS(CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR) + , language(LANGID(-1)) + , fEnableSubtitles(true) + , bSubtitleOverrideDefaultStyle(false) + , bSubtitleOverrideAllStyles(false) + , iDefaultVideoSize(DVS_FROMINSIDE) + , fKeepAspectRatio(true) + , fCompMonDeskARDiff(false) + , iOnTop(0) + , bFavRememberPos(true) + , bFavRelativeDrive(false) + , bFavRememberABMarks(false) + , iThumbRows(4) + , iThumbCols(4) + , iThumbWidth(1024) + , bSubSaveExternalStyleFile(false) + , bShufflePlaylistItems(false) + , bHidePlaylistFullScreen(false) + , nLastWindowType(SIZE_RESTORED) + , nLastUsedPage(0) + , fRemainingTime(false) + , bHighPrecisionTimer(false) + , bTimerShowPercentage(false) + , fLastFullScreen(false) + , fEnableEDLEditor(false) + , hMasterWnd(nullptr) + , bHideWindowedControls(false) + , nJpegQuality(90) + , bEnableCoverArt(true) + , nCoverArtSizeLimit(600) + , bEnableLogging(false) + , bUseLegacyToolbar(false) + , iLAVGPUDevice(DWORD_MAX) + , nCmdVolume(0) + , eSubtitleRenderer(SubtitleRenderer::INTERNAL) + , bUseYDL(true) + , iYDLMaxHeight(1440) + , iYDLVideoFormat(0) + , iYDLAudioFormat(0) + , bYDLAudioOnly(false) + , sYDLExePath(_T("")) + , sYDLCommandLine(_T("")) + , bSnapShotSubtitles(true) + , bSnapShotKeepVideoExtension(true) + , bEnableCrashReporter(true) + , nStreamPosPollerInterval(100) + , bShowLangInStatusbar(false) + , bShowFPSInStatusbar(false) + , bShowABMarksInStatusbar(false) + , bShowVideoInfoInStatusbar(true) + , bShowAudioFormatInStatusbar(true) +#if USE_LIBASS + , bRenderSSAUsingLibass(false) + , bRenderSRTUsingLibass(false) +#endif + , bAddLangCodeWhenSaveSubtitles(false) + , bUseTitleInRecentFileList(true) + , sYDLSubsPreference() + , bUseAutomaticCaptions(false) + , bLockNoPause(false) + , bPreventDisplaySleep(true) + , bUseSMTC(false) + , iReloadAfterLongPause(0) + , bOpenRecPanelWhenOpeningDevice(true) + , lastQuickOpenPath(L"") + , lastFileSaveCopyPath(L"") + , lastFileOpenDirPath(L"") + , externalPlayListPath(L"") + , iRedirectOpenToAppendThreshold(1000) + , bFullscreenSeparateControls(true) + , bAlwaysUseShortMenu(false) + , iStillVideoDuration(10) + , iMouseLeftUpDelay(0) + , bUseFreeType(false) + , bUseMediainfoLoadFileDuration(false) + , bCaptureDeinterlace(false) + , bPauseWhileDraggingSeekbar(true) + , bConfirmFileDelete(true) +{ + // Internal source filter +#if INTERNAL_SOURCEFILTER_AC3 + SrcFiltersKeys[SRC_AC3] = FilterKey(_T("SRC_AC3"), true); +#endif +#if INTERNAL_SOURCEFILTER_ASF + SrcFiltersKeys[SRC_ASF] = FilterKey(_T("SRC_ASF"), false); +#endif +#if INTERNAL_SOURCEFILTER_AVI + SrcFiltersKeys[SRC_AVI] = FilterKey(_T("SRC_AVI"), true); +#endif +#if INTERNAL_SOURCEFILTER_AVS + SrcFiltersKeys[SRC_AVS] = FilterKey(_T("SRC_AVS"), true); +#endif +#if INTERNAL_SOURCEFILTER_DTS + SrcFiltersKeys[SRC_DTS] = FilterKey(_T("SRC_DTS"), true); +#endif +#if INTERNAL_SOURCEFILTER_FLAC + SrcFiltersKeys[SRC_FLAC] = FilterKey(_T("SRC_FLAC"), true); +#endif +#if INTERNAL_SOURCEFILTER_FLIC + SrcFiltersKeys[SRC_FLIC] = FilterKey(_T("SRC_FLIC"), true); +#endif +#if INTERNAL_SOURCEFILTER_FLV + SrcFiltersKeys[SRC_FLV] = FilterKey(_T("SRC_FLV"), true); +#endif +#if INTERNAL_SOURCEFILTER_GIF + SrcFiltersKeys[SRC_GIF] = FilterKey(_T("SRC_GIF"), true); +#endif +#if INTERNAL_SOURCEFILTER_HTTP + SrcFiltersKeys[SRC_HTTP] = FilterKey(_T("SRC_HTTP"), true); +#endif +#if INTERNAL_SOURCEFILTER_MATROSKA + SrcFiltersKeys[SRC_MATROSKA] = FilterKey(_T("SRC_MATROSKA"), true); +#endif +#if INTERNAL_SOURCEFILTER_MISC + SrcFiltersKeys[SRC_MISC] = FilterKey(_T("SRC_MISC"), true); +#endif +#if INTERNAL_SOURCEFILTER_MMS + SrcFiltersKeys[SRC_MMS] = FilterKey(_T("SRC_MMS"), true); +#endif +#if INTERNAL_SOURCEFILTER_MP4 + SrcFiltersKeys[SRC_MP4] = FilterKey(_T("SRC_MP4"), true); +#endif +#if INTERNAL_SOURCEFILTER_MPEGAUDIO + SrcFiltersKeys[SRC_MPA] = FilterKey(_T("SRC_MPA"), true); +#endif +#if INTERNAL_SOURCEFILTER_MPEG + SrcFiltersKeys[SRC_MPEG] = FilterKey(_T("SRC_MPEG"), true); + SrcFiltersKeys[SRC_MPEGTS] = FilterKey(_T("SRC_MPEGTS"), true); +#endif +#if INTERNAL_SOURCEFILTER_OGG + SrcFiltersKeys[SRC_OGG] = FilterKey(_T("SRC_OGG"), true); +#endif +#if INTERNAL_SOURCEFILTER_REALMEDIA + SrcFiltersKeys[SRC_REALMEDIA] = FilterKey(_T("SRC_REALMEDIA"), true); +#endif +#if INTERNAL_SOURCEFILTER_RTMP + SrcFiltersKeys[SRC_RTMP] = FilterKey(_T("SRC_RTMP"), true); +#endif +#if INTERNAL_SOURCEFILTER_RTP + SrcFiltersKeys[SRC_RTP] = FilterKey(_T("SRC_RTP"), true); +#endif +#if INTERNAL_SOURCEFILTER_RTSP + SrcFiltersKeys[SRC_RTSP] = FilterKey(_T("SRC_RTSP"), true); +#endif +#if INTERNAL_SOURCEFILTER_RTSP + SrcFiltersKeys[SRC_UDP] = FilterKey(_T("SRC_UDP"), true); +#endif +#if INTERNAL_SOURCEFILTER_WTV + SrcFiltersKeys[SRC_WTV] = FilterKey(_T("SRC_WTV"), true); +#endif +#if INTERNAL_SOURCEFILTER_CDDA + SrcFiltersKeys[SRC_CDDA] = FilterKey(_T("SRC_CDDA"), true); +#endif +#if INTERNAL_SOURCEFILTER_CDXA + SrcFiltersKeys[SRC_CDXA] = FilterKey(_T("SRC_CDXA"), true); +#endif +#if INTERNAL_SOURCEFILTER_DSM + SrcFiltersKeys[SRC_DSM] = FilterKey(_T("SRC_DSM"), true); +#endif +#if INTERNAL_SOURCEFILTER_RFS + SrcFiltersKeys[SRC_RFS] = FilterKey(_T("SRC_RFS"), true); +#endif +#if INTERNAL_SOURCEFILTER_VTS + SrcFiltersKeys[SRC_VTS] = FilterKey(_T("SRC_VTS"), true); +#endif + + // Internal decoders +#if INTERNAL_DECODER_MPEG1 + TraFiltersKeys[TRA_MPEG1] = FilterKey(_T("TRA_MPEG1"), true); +#endif +#if INTERNAL_DECODER_MPEG2 + TraFiltersKeys[TRA_MPEG2] = FilterKey(_T("TRA_MPEG2"), true); +#endif +#if INTERNAL_DECODER_REALVIDEO + TraFiltersKeys[TRA_RV] = FilterKey(_T("TRA_RV"), true); +#endif +#if INTERNAL_DECODER_REALAUDIO + TraFiltersKeys[TRA_RA] = FilterKey(_T("TRA_RA"), true); +#endif +#if INTERNAL_DECODER_MPEGAUDIO + TraFiltersKeys[TRA_MPA] = FilterKey(_T("TRA_MPA"), true); +#endif +#if INTERNAL_DECODER_DTS + TraFiltersKeys[TRA_DTS] = FilterKey(_T("TRA_DTS"), true); +#endif +#if INTERNAL_DECODER_LPCM + TraFiltersKeys[TRA_LPCM] = FilterKey(_T("TRA_LPCM"), true); +#endif +#if INTERNAL_DECODER_AC3 + TraFiltersKeys[TRA_AC3] = FilterKey(_T("TRA_AC3"), true); +#endif +#if INTERNAL_DECODER_AAC + TraFiltersKeys[TRA_AAC] = FilterKey(_T("TRA_AAC"), true); +#endif +#if INTERNAL_DECODER_ALAC + TraFiltersKeys[TRA_ALAC] = FilterKey(_T("TRA_ALAC"), true); +#endif +#if INTERNAL_DECODER_ALS + TraFiltersKeys[TRA_ALS] = FilterKey(_T("TRA_ALS"), true); +#endif +#if INTERNAL_DECODER_PS2AUDIO + TraFiltersKeys[TRA_PS2AUD] = FilterKey(_T("TRA_PS2AUD"), true); +#endif +#if INTERNAL_DECODER_VORBIS + TraFiltersKeys[TRA_VORBIS] = FilterKey(_T("TRA_VORBIS"), true); +#endif +#if INTERNAL_DECODER_FLAC + TraFiltersKeys[TRA_FLAC] = FilterKey(_T("TRA_FLAC"), true); +#endif +#if INTERNAL_DECODER_NELLYMOSER + TraFiltersKeys[TRA_NELLY] = FilterKey(_T("TRA_NELLY"), true); +#endif +#if INTERNAL_DECODER_AMR + TraFiltersKeys[TRA_AMR] = FilterKey(_T("TRA_AMR"), true); +#endif +#if INTERNAL_DECODER_OPUS + TraFiltersKeys[TRA_OPUS] = FilterKey(_T("TRA_OPUS"), true); +#endif +#if INTERNAL_DECODER_WMA + TraFiltersKeys[TRA_WMA] = FilterKey(_T("TRA_WMA"), false); +#endif +#if INTERNAL_DECODER_WMAPRO + TraFiltersKeys[TRA_WMAPRO] = FilterKey(_T("TRA_WMAPRO"), false); +#endif +#if INTERNAL_DECODER_WMALL + TraFiltersKeys[TRA_WMALL] = FilterKey(_T("TRA_WMALL"), false); +#endif +#if INTERNAL_DECODER_G726 + TraFiltersKeys[TRA_G726] = FilterKey(_T("TRA_G726"), true); +#endif +#if INTERNAL_DECODER_G729 + TraFiltersKeys[TRA_G729] = FilterKey(_T("TRA_G729"), true); +#endif +#if INTERNAL_DECODER_OTHERAUDIO + TraFiltersKeys[TRA_OTHERAUDIO] = FilterKey(_T("TRA_OTHERAUDIO"), true); +#endif +#if INTERNAL_DECODER_PCM + TraFiltersKeys[TRA_PCM] = FilterKey(_T("TRA_PCM"), true); +#endif +#if INTERNAL_DECODER_H264 + TraFiltersKeys[TRA_H264] = FilterKey(_T("TRA_H264"), true); +#endif +#if INTERNAL_DECODER_HEVC + TraFiltersKeys[TRA_HEVC] = FilterKey(_T("TRA_HEVC"), true); +#endif +#if INTERNAL_DECODER_VVC + TraFiltersKeys[TRA_VVC] = FilterKey(_T("TRA_VVC"), true); +#endif +#if INTERNAL_DECODER_AV1 + TraFiltersKeys[TRA_AV1] = FilterKey(_T("TRA_AV1"), true); +#endif +#if INTERNAL_DECODER_VC1 + TraFiltersKeys[TRA_VC1] = FilterKey(_T("TRA_VC1"), true); +#endif +#if INTERNAL_DECODER_FLV + TraFiltersKeys[TRA_FLV4] = FilterKey(_T("TRA_FLV4"), true); +#endif +#if INTERNAL_DECODER_VP356 + TraFiltersKeys[TRA_VP356] = FilterKey(_T("TRA_VP356"), true); +#endif +#if INTERNAL_DECODER_VP8 + TraFiltersKeys[TRA_VP8] = FilterKey(_T("TRA_VP8"), true); +#endif +#if INTERNAL_DECODER_VP9 + TraFiltersKeys[TRA_VP9] = FilterKey(_T("TRA_VP9"), true); +#endif +#if INTERNAL_DECODER_XVID + TraFiltersKeys[TRA_XVID] = FilterKey(_T("TRA_XVID"), true); +#endif +#if INTERNAL_DECODER_DIVX + TraFiltersKeys[TRA_DIVX] = FilterKey(_T("TRA_DIVX"), true); +#endif +#if INTERNAL_DECODER_MSMPEG4 + TraFiltersKeys[TRA_MSMPEG4] = FilterKey(_T("TRA_MSMPEG4"), true); +#endif +#if INTERNAL_DECODER_WMV + TraFiltersKeys[TRA_WMV] = FilterKey(_T("TRA_WMV"), false); +#endif +#if INTERNAL_DECODER_SVQ + TraFiltersKeys[TRA_SVQ3] = FilterKey(_T("TRA_SVQ3"), true); +#endif +#if INTERNAL_DECODER_H263 + TraFiltersKeys[TRA_H263] = FilterKey(_T("TRA_H263"), true); +#endif +#if INTERNAL_DECODER_THEORA + TraFiltersKeys[TRA_THEORA] = FilterKey(_T("TRA_THEORA"), true); +#endif +#if INTERNAL_DECODER_AMVV + TraFiltersKeys[TRA_AMVV] = FilterKey(_T("TRA_AMVV"), true); +#endif +#if INTERNAL_DECODER_MJPEG + TraFiltersKeys[TRA_MJPEG] = FilterKey(_T("TRA_MJPEG"), true); +#endif +#if INTERNAL_DECODER_INDEO + TraFiltersKeys[TRA_INDEO] = FilterKey(_T("TRA_INDEO"), true); +#endif +#if INTERNAL_DECODER_SCREEN + TraFiltersKeys[TRA_SCREEN] = FilterKey(_T("TRA_SCREEN"), true); +#endif +#if INTERNAL_DECODER_FLIC + TraFiltersKeys[TRA_FLIC] = FilterKey(_T("TRA_FLIC"), true); +#endif +#if INTERNAL_DECODER_MSVIDEO + TraFiltersKeys[TRA_MSVIDEO] = FilterKey(_T("TRA_MSVIDEO"), true); +#endif +#if INTERNAL_DECODER_V210_V410 + TraFiltersKeys[TRA_V210_V410] = FilterKey(_T("TRA_V210_V410"), false); +#endif +#if INTERNAL_DECODER_PRORES + TraFiltersKeys[TRA_PRORES] = FilterKey(_T("TRA_PRORES"), true); +#endif +#if INTERNAL_DECODER_DNXHD + TraFiltersKeys[TRA_DNXHD] = FilterKey(_T("TRA_DNXHD"), true); +#endif +#if INTERNAL_DECODER_OTHERVIDEO + TraFiltersKeys[TRA_OTHERVIDEO] = FilterKey(_T("TRA_OTHERVIDEO"), true); +#endif + + ZeroMemory(&DVDPosition, sizeof(DVDPosition)); + + ENSURE(SUCCEEDED(SaneAudioRenderer::Factory::CreateSettings(&sanear))); + + // Mouse + nMouseLeftClick = ID_PLAY_PLAYPAUSE; + nMouseLeftDblClick = ID_VIEW_FULLSCREEN; + nMouseRightClick = ID_MENU_PLAYER_SHORT; + MouseMiddleClick = { 0, 0, 0, 0 }; + MouseX1Click = { ID_NAVIGATE_SKIPBACK, 0, 0, 0 }; + MouseX2Click = { ID_NAVIGATE_SKIPFORWARD, 0, 0, 0 }; + MouseWheelUp = { ID_VOLUME_UP, ID_PLAY_SEEKFORWARDLARGE, 0, ID_PLAY_SEEKFORWARDLARGE }; + MouseWheelDown = { ID_VOLUME_DOWN, ID_PLAY_SEEKBACKWARDLARGE, 0, ID_PLAY_SEEKBACKWARDLARGE }; + MouseWheelLeft = { 0, 0, 0, 0 }; + MouseWheelRight = { 0, 0, 0, 0 }; + bMouseLeftClickOpenRecent = false; + bMouseEasyMove = true; + +} +#pragma warning(pop) + +/* Note: the mouse commands in this list are no longer being used. Mouse binding are now stored elsewhere. + * They are included for backwards compatibility. + */ +static constexpr wmcmd_base default_wmcmds[] = { + { ID_FILE_OPENQUICK, 'Q', FCONTROL, IDS_MPLAYERC_0 }, + { ID_FILE_OPENMEDIA, 'O', FCONTROL, IDS_AG_OPEN_FILE }, + { ID_FILE_OPENDVDBD, 'D', FCONTROL, IDS_AG_OPEN_DVD }, + { ID_FILE_OPENDEVICE, 'V', FCONTROL, IDS_AG_OPEN_DEVICE }, + { ID_FILE_OPENDIRECTORY, 0, 0, IDS_AG_OPENDIRECTORY }, + { ID_FILE_REOPEN, 'E', FCONTROL, IDS_AG_REOPEN }, + { ID_FILE_RECYCLE, VK_DELETE, 0, IDS_FILE_RECYCLE }, + { ID_FILE_SAVE_COPY, 0, 0, IDS_AG_SAVE_COPY }, + { ID_FILE_SAVE_IMAGE, 'I', FALT, IDS_AG_SAVE_IMAGE }, + { ID_FILE_SAVE_IMAGE_AUTO, VK_F5, 0, IDS_MPLAYERC_6 }, + { ID_FILE_SAVE_THUMBNAILS, 0, 0, IDS_FILE_SAVE_THUMBNAILS }, + { ID_FILE_SUBTITLES_LOAD, 'L', FCONTROL, IDS_AG_LOAD_SUBTITLES }, + { ID_FILE_SUBTITLES_SAVE, 'S', FCONTROL, IDS_AG_SAVE_SUBTITLES }, + { ID_FILE_SUBTITLES_DOWNLOAD, 'D', 0, IDS_SUBTITLES_DOWNLOAD }, + { ID_FILE_CLOSE_AND_RESTORE, 'C', FCONTROL, IDS_AG_CLOSE }, + { ID_FILE_PROPERTIES, VK_F10, FSHIFT, IDS_AG_PROPERTIES }, + { ID_FILE_OPEN_LOCATION, VK_F10, FCONTROL | FSHIFT, IDS_AG_OPEN_FILE_LOCATION }, + { ID_FILE_EXIT, 'X', FALT, IDS_AG_EXIT }, + { ID_PLAY_PLAYPAUSE, VK_SPACE, 0, IDS_AG_PLAYPAUSE, APPCOMMAND_MEDIA_PLAY_PAUSE, wmcmd::LUP }, + { ID_PLAY_PLAY, 0, 0, IDS_AG_PLAY, APPCOMMAND_MEDIA_PLAY }, + { ID_PLAY_PAUSE, 0, 0, IDS_AG_PAUSE, APPCOMMAND_MEDIA_PAUSE }, + { ID_PLAY_STOP, VK_OEM_PERIOD, 0, IDS_AG_STOP, APPCOMMAND_MEDIA_STOP }, + { ID_PLAY_FRAMESTEP, VK_RIGHT, FCONTROL, IDS_AG_FRAMESTEP }, + { ID_PLAY_FRAMESTEP_BACK, VK_LEFT, FCONTROL, IDS_MPLAYERC_16 }, + { ID_NAVIGATE_GOTO, 'G', FCONTROL, IDS_AG_GO_TO }, + { ID_PLAY_INCRATE, VK_UP, FCONTROL, IDS_AG_INCREASE_RATE }, + { ID_PLAY_DECRATE, VK_DOWN, FCONTROL, IDS_AG_DECREASE_RATE }, + { ID_PLAY_RESETRATE, 'R', FCONTROL, IDS_AG_RESET_RATE }, + { ID_PLAY_INCAUDDELAY, VK_ADD, 0, IDS_MPLAYERC_21 }, + { ID_PLAY_DECAUDDELAY, VK_SUBTRACT, 0, IDS_MPLAYERC_22 }, + { ID_PLAY_SEEKFORWARDSMALL, 0, 0, IDS_MPLAYERC_23 }, + { ID_PLAY_SEEKBACKWARDSMALL, 0, 0, IDS_MPLAYERC_24 }, + { ID_PLAY_SEEKFORWARDMED, VK_RIGHT, 0, IDS_MPLAYERC_25 }, + { ID_PLAY_SEEKBACKWARDMED, VK_LEFT, 0, IDS_MPLAYERC_26 }, + { ID_PLAY_SEEKFORWARDLARGE, 0, 0, IDS_MPLAYERC_27, 0, wmcmd::WUP, FVIRTKEY | FCONTROL }, + { ID_PLAY_SEEKBACKWARDLARGE, 0, 0, IDS_MPLAYERC_28, 0, wmcmd::WDOWN, FVIRTKEY | FCONTROL }, + { ID_PLAY_SEEKKEYFORWARD, VK_RIGHT, FSHIFT, IDS_MPLAYERC_29 }, + { ID_PLAY_SEEKKEYBACKWARD, VK_LEFT, FSHIFT, IDS_MPLAYERC_30 }, + { ID_PLAY_SEEKSET, VK_HOME, 0, IDS_AG_SEEKSET }, + { ID_PLAY_REPEAT_FOREVER, 0, 0, IDS_PLAYLOOP_FOREVER }, + { ID_PLAY_REPEAT_ONEFILE, 0, 0, IDS_PLAYLOOPMODE_FILE }, + { ID_PLAY_REPEAT_WHOLEPLAYLIST, 0, 0, IDS_PLAYLOOPMODE_PLAYLIST }, + { ID_PLAY_REPEAT_AB, 0, 0, IDS_PLAYLOOPMODE_AB }, + { ID_PLAY_REPEAT_AB_MARK_A, VK_OEM_4, 0, IDS_PLAYLOOPMODE_AB_MARK_A }, + { ID_PLAY_REPEAT_AB_MARK_B, VK_OEM_6, 0, IDS_PLAYLOOPMODE_AB_MARK_B }, + { ID_NAVIGATE_SKIPFORWARD, VK_NEXT, 0, IDS_AG_NEXT, APPCOMMAND_MEDIA_NEXTTRACK, wmcmd::X2DOWN }, + { ID_NAVIGATE_SKIPBACK, VK_PRIOR, 0, IDS_AG_PREVIOUS, APPCOMMAND_MEDIA_PREVIOUSTRACK, wmcmd::X1DOWN }, + { ID_NAVIGATE_SKIPFORWARDFILE, VK_NEXT, FCONTROL, IDS_AG_NEXT_FILE }, + { ID_NAVIGATE_SKIPBACKFILE, VK_PRIOR, FCONTROL, IDS_AG_PREVIOUS_FILE }, + { ID_NAVIGATE_TUNERSCAN, 'T', FSHIFT, IDS_NAVIGATE_TUNERSCAN }, + { ID_FAVORITES_QUICKADDFAVORITE, 'Q', FSHIFT, IDS_FAVORITES_QUICKADDFAVORITE }, + { ID_FAVORITES_ORGANIZE, 0, 0, IDS_FAVORITES_ORGANIZE }, + { ID_VIEW_CAPTIONMENU, '0', FCONTROL, IDS_AG_TOGGLE_CAPTION }, + { ID_VIEW_SEEKER, '1', FCONTROL, IDS_AG_TOGGLE_SEEKER }, + { ID_VIEW_CONTROLS, '2', FCONTROL, IDS_AG_TOGGLE_CONTROLS }, + { ID_VIEW_INFORMATION, '3', FCONTROL, IDS_AG_TOGGLE_INFO }, + { ID_VIEW_STATISTICS, '4', FCONTROL, IDS_AG_TOGGLE_STATS }, + { ID_VIEW_STATUS, '5', FCONTROL, IDS_AG_TOGGLE_STATUS }, + { ID_VIEW_SUBRESYNC, '6', FCONTROL, IDS_AG_TOGGLE_SUBRESYNC }, + { ID_VIEW_PLAYLIST, '7', FCONTROL, IDS_AG_TOGGLE_PLAYLIST }, + { ID_VIEW_CAPTURE, '8', FCONTROL, IDS_AG_TOGGLE_CAPTURE }, + { ID_VIEW_NAVIGATION, '9', FCONTROL, IDS_AG_TOGGLE_NAVIGATION }, + { ID_VIEW_DEBUGSHADERS, 0, 0, IDS_AG_TOGGLE_DEBUGSHADERS }, + { ID_PRESIZE_SHADERS_TOGGLE, 'P', FCONTROL, IDS_PRESIZE_SHADERS_TOGGLE }, + { ID_POSTSIZE_SHADERS_TOGGLE, 'P', FCONTROL | FALT, IDS_POSTSIZE_SHADERS_TOGGLE }, + { ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE, 0, 0, IDS_AG_TOGGLE_DEFAULT_SUBTITLE_STYLE }, + { ID_VIEW_PRESETS_MINIMAL, '1', 0, IDS_AG_VIEW_MINIMAL }, + { ID_VIEW_PRESETS_COMPACT, '2', 0, IDS_AG_VIEW_COMPACT }, + { ID_VIEW_PRESETS_NORMAL, '3', 0, IDS_AG_VIEW_NORMAL }, + { ID_VIEW_FULLSCREEN, VK_RETURN, FALT, IDS_AG_FULLSCREEN, 0, wmcmd::LDBLCLK }, + { ID_VIEW_FULLSCREEN_SECONDARY, VK_F11, 0, IDS_MPLAYERC_39 }, + { ID_VIEW_ZOOM_25, VK_OEM_3, FALT, IDS_AG_ZOOM_25 }, /* VK_OEM_3 is `~ on US keyboards*/ + { ID_VIEW_ZOOM_50, '1', FALT, IDS_AG_ZOOM_50 }, + { ID_VIEW_ZOOM_100, '2', FALT, IDS_AG_ZOOM_100 }, + { ID_VIEW_ZOOM_200, '3', FALT, IDS_AG_ZOOM_200 }, + { ID_VIEW_ZOOM_AUTOFIT, '4', FALT, IDS_AG_ZOOM_AUTO_FIT }, + { ID_VIEW_ZOOM_AUTOFIT_LARGER, '5', FALT, IDS_AG_ZOOM_AUTO_FIT_LARGER }, + { ID_VIEW_ZOOM_ADD, 0, 0, IDS_AG_ZOOM_ADD }, + { ID_VIEW_ZOOM_SUB, 0, 0, IDS_AG_ZOOM_SUB }, + { ID_ASPECTRATIO_NEXT, 0, 0, IDS_AG_NEXT_AR_PRESET }, + { ID_VIEW_VF_HALF, 0, 0, IDS_AG_VIDFRM_HALF }, + { ID_VIEW_VF_NORMAL, 0, 0, IDS_AG_VIDFRM_NORMAL }, + { ID_VIEW_VF_DOUBLE, 0, 0, IDS_AG_VIDFRM_DOUBLE }, + { ID_VIEW_VF_STRETCH, 0, 0, IDS_AG_VIDFRM_STRETCH }, + { ID_VIEW_VF_FROMINSIDE, 0, 0, IDS_AG_VIDFRM_INSIDE }, + { ID_VIEW_VF_ZOOM1, 0, 0, IDS_AG_VIDFRM_ZOOM1 }, + { ID_VIEW_VF_ZOOM2, 0, 0, IDS_AG_VIDFRM_ZOOM2 }, + { ID_VIEW_VF_FROMOUTSIDE, 0, 0, IDS_AG_VIDFRM_OUTSIDE }, + { ID_VIEW_VF_SWITCHZOOM, 0, 0, IDS_AG_VIDFRM_SWITCHZOOM }, + { ID_ONTOP_ALWAYS, 'A', FCONTROL, IDS_AG_ALWAYS_ON_TOP }, + { ID_VIEW_RESET, VK_NUMPAD5, 0, IDS_AG_PNS_RESET }, + { ID_VIEW_INCSIZE, VK_NUMPAD9, 0, IDS_AG_PNS_INC_SIZE }, + { ID_VIEW_INCWIDTH, VK_NUMPAD6, 0, IDS_AG_PNS_INC_WIDTH }, + { ID_VIEW_INCHEIGHT, VK_NUMPAD8, 0, IDS_MPLAYERC_47 }, + { ID_VIEW_DECSIZE, VK_NUMPAD1, 0, IDS_AG_PNS_DEC_SIZE }, + { ID_VIEW_DECWIDTH, VK_NUMPAD4, 0, IDS_AG_PNS_DEC_WIDTH }, + { ID_VIEW_DECHEIGHT, VK_NUMPAD2, 0, IDS_MPLAYERC_50 }, + { ID_PANSCAN_CENTER, VK_NUMPAD5, FCONTROL, IDS_AG_PNS_CENTER }, + { ID_PANSCAN_MOVELEFT, VK_NUMPAD4, FCONTROL, IDS_AG_PNS_LEFT }, + { ID_PANSCAN_MOVERIGHT, VK_NUMPAD6, FCONTROL, IDS_AG_PNS_RIGHT }, + { ID_PANSCAN_MOVEUP, VK_NUMPAD8, FCONTROL, IDS_AG_PNS_UP }, + { ID_PANSCAN_MOVEDOWN, VK_NUMPAD2, FCONTROL, IDS_AG_PNS_DOWN }, + { ID_PANSCAN_MOVEUPLEFT, VK_NUMPAD7, FCONTROL, IDS_AG_PNS_UPLEFT }, + { ID_PANSCAN_MOVEUPRIGHT, VK_NUMPAD9, FCONTROL, IDS_AG_PNS_UPRIGHT }, + { ID_PANSCAN_MOVEDOWNLEFT, VK_NUMPAD1, FCONTROL, IDS_AG_PNS_DOWNLEFT }, + { ID_PANSCAN_MOVEDOWNRIGHT, VK_NUMPAD3, FCONTROL, IDS_MPLAYERC_59 }, + { ID_PANSCAN_ROTATEXP, VK_NUMPAD8, FALT, IDS_AG_PNS_ROTATEX_P }, + { ID_PANSCAN_ROTATEXM, VK_NUMPAD2, FALT, IDS_AG_PNS_ROTATEX_M }, + { ID_PANSCAN_ROTATEYP, VK_NUMPAD4, FALT, IDS_AG_PNS_ROTATEY_P }, + { ID_PANSCAN_ROTATEYM, VK_NUMPAD6, FALT, IDS_AG_PNS_ROTATEY_M }, + { ID_PANSCAN_ROTATEZP, VK_NUMPAD1, FALT, IDS_AG_PNS_ROTATEZ_P }, + { ID_PANSCAN_ROTATEZM, VK_NUMPAD3, FALT, IDS_AG_PNS_ROTATEZ_M }, + { ID_VOLUME_UP, VK_UP, 0, IDS_AG_VOLUME_UP, 0, wmcmd::WUP }, + { ID_VOLUME_DOWN, VK_DOWN, 0, IDS_AG_VOLUME_DOWN, 0, wmcmd::WDOWN }, + { ID_VOLUME_MUTE, 'M', FCONTROL, IDS_AG_VOLUME_MUTE, 0 }, + { ID_VOLUME_BOOST_INC, 0, 0, IDS_VOLUME_BOOST_INC }, + { ID_VOLUME_BOOST_DEC, 0, 0, IDS_VOLUME_BOOST_DEC }, + { ID_VOLUME_BOOST_MIN, 0, 0, IDS_VOLUME_BOOST_MIN }, + { ID_VOLUME_BOOST_MAX, 0, 0, IDS_VOLUME_BOOST_MAX }, + { ID_CUSTOM_CHANNEL_MAPPING, 0, 0, IDS_CUSTOM_CHANNEL_MAPPING }, + { ID_NORMALIZE, 0, 0, IDS_NORMALIZE }, + { ID_REGAIN_VOLUME, 0, 0, IDS_REGAIN_VOLUME }, + { ID_COLOR_BRIGHTNESS_INC, 0, 0, IDS_BRIGHTNESS_INC }, + { ID_COLOR_BRIGHTNESS_DEC, 0, 0, IDS_BRIGHTNESS_DEC }, + { ID_COLOR_CONTRAST_INC, 0, 0, IDS_CONTRAST_INC }, + { ID_COLOR_CONTRAST_DEC, 0, 0, IDS_CONTRAST_DEC }, + { ID_COLOR_HUE_INC, 0, 0, IDS_HUE_INC }, + { ID_COLOR_HUE_DEC, 0, 0, IDS_HUE_DEC }, + { ID_COLOR_SATURATION_INC, 0, 0, IDS_SATURATION_INC }, + { ID_COLOR_SATURATION_DEC, 0, 0, IDS_SATURATION_DEC }, + { ID_COLOR_RESET, 0, 0, IDS_RESET_COLOR }, + { ID_NAVIGATE_TITLEMENU, 'T', FALT, IDS_MPLAYERC_63 }, + { ID_NAVIGATE_ROOTMENU, 'R', FALT, IDS_AG_DVD_ROOT_MENU }, + { ID_NAVIGATE_SUBPICTUREMENU, 0, 0, IDS_MPLAYERC_65 }, + { ID_NAVIGATE_AUDIOMENU, 0, 0, IDS_MPLAYERC_66 }, + { ID_NAVIGATE_ANGLEMENU, 0, 0, IDS_MPLAYERC_67 }, + { ID_NAVIGATE_CHAPTERMENU, 0, 0, IDS_MPLAYERC_68 }, + { ID_NAVIGATE_MENU_LEFT, VK_LEFT, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_LEFT }, + { ID_NAVIGATE_MENU_RIGHT, VK_RIGHT, FCONTROL | FSHIFT, IDS_MPLAYERC_70 }, + { ID_NAVIGATE_MENU_UP, VK_UP, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_UP }, + { ID_NAVIGATE_MENU_DOWN, VK_DOWN, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_DOWN }, + { ID_NAVIGATE_MENU_ACTIVATE, 0, 0, IDS_MPLAYERC_73 }, + { ID_NAVIGATE_MENU_BACK, 0, 0, IDS_AG_DVD_MENU_BACK }, + { ID_NAVIGATE_MENU_LEAVE, 0, 0, IDS_MPLAYERC_75 }, + { ID_BOSS, 'B', 0, IDS_AG_BOSS_KEY }, + { ID_MENU_PLAYER_SHORT, VK_APPS, 0, IDS_MPLAYERC_77, 0, wmcmd::RUP }, + { ID_MENU_PLAYER_LONG, 0, 0, IDS_MPLAYERC_78 }, + { ID_MENU_FILTERS, 0, 0, IDS_AG_FILTERS_MENU }, + { ID_VIEW_OPTIONS, 'O', 0, IDS_AG_OPTIONS }, + { ID_STREAM_AUDIO_NEXT, 'A', 0, IDS_AG_NEXT_AUDIO }, + { ID_STREAM_AUDIO_PREV, 'A', FSHIFT, IDS_AG_PREV_AUDIO }, + { ID_STREAM_SUB_NEXT, 'S', 0, IDS_AG_NEXT_SUBTITLE }, + { ID_STREAM_SUB_PREV, 'S', FSHIFT, IDS_AG_PREV_SUBTITLE }, + { ID_STREAM_SUB_ONOFF, 'W', 0, IDS_MPLAYERC_85 }, + { ID_SUBTITLES_SUBITEM_START + 2, 0, 0, IDS_MPLAYERC_86 }, + { ID_DVD_ANGLE_NEXT, 0, 0, IDS_MPLAYERC_91 }, + { ID_DVD_ANGLE_PREV, 0, 0, IDS_MPLAYERC_92 }, + { ID_DVD_AUDIO_NEXT, 0, 0, IDS_MPLAYERC_93 }, + { ID_DVD_AUDIO_PREV, 0, 0, IDS_MPLAYERC_94 }, + { ID_DVD_SUB_NEXT, 0, 0, IDS_MPLAYERC_95 }, + { ID_DVD_SUB_PREV, 0, 0, IDS_MPLAYERC_96 }, + { ID_DVD_SUB_ONOFF, 0, 0, IDS_MPLAYERC_97 }, + { ID_VIEW_TEARING_TEST, 0, 0, IDS_AG_TEARING_TEST }, + { ID_VIEW_OSD_DISPLAY_TIME, 'I', FCONTROL, IDS_OSD_DISPLAY_CURRENT_TIME }, + { ID_VIEW_OSD_SHOW_FILENAME, 'N', 0, IDS_OSD_SHOW_FILENAME }, + { ID_SHADERS_PRESET_NEXT, 0, 0, IDS_AG_SHADERS_PRESET_NEXT }, + { ID_SHADERS_PRESET_PREV, 0, 0, IDS_AG_SHADERS_PRESET_PREV }, + { ID_D3DFULLSCREEN_TOGGLE, 0, 0, IDS_MPLAYERC_99 }, + { ID_GOTO_PREV_SUB, 'Y', 0, IDS_MPLAYERC_100 }, + { ID_GOTO_NEXT_SUB, 'U', 0, IDS_MPLAYERC_101 }, + { ID_SUBRESYNC_SHIFT_DOWN, VK_NEXT, FALT, IDS_MPLAYERC_102 }, + { ID_SUBRESYNC_SHIFT_UP, VK_PRIOR, FALT, IDS_MPLAYERC_103 }, + { ID_VIEW_DISPLAY_RENDERER_STATS, 'J', FCONTROL, IDS_OSD_DISPLAY_RENDERER_STATS }, + { ID_VIEW_RESET_RENDERER_STATS, 'R', FCONTROL | FALT, IDS_OSD_RESET_RENDERER_STATS }, + { ID_VIEW_VSYNC, 'V', 0, IDS_AG_VSYNC }, + { ID_VIEW_ENABLEFRAMETIMECORRECTION, 0, 0, IDS_AG_ENABLEFRAMETIMECORRECTION }, + { ID_VIEW_VSYNCACCURATE, 'V', FCONTROL | FALT, IDS_AG_VSYNCACCURATE }, + { ID_VIEW_VSYNCOFFSET_DECREASE, VK_UP, FCONTROL | FALT, IDS_AG_VSYNCOFFSET_DECREASE }, + { ID_VIEW_VSYNCOFFSET_INCREASE, VK_DOWN, FCONTROL | FALT, IDS_AG_VSYNCOFFSET_INCREASE }, + { ID_SUB_DELAY_DOWN, VK_F1, 0, IDS_MPLAYERC_104 }, + { ID_SUB_DELAY_UP, VK_F2, 0, IDS_MPLAYERC_105 }, + { ID_SUB_POS_DOWN, VK_SUBTRACT, FCONTROL | FSHIFT, IDS_SUB_POS_DOWN }, + { ID_SUB_POS_UP, VK_ADD, FCONTROL | FSHIFT, IDS_SUB_POS_UP }, + { ID_SUB_FONT_SIZE_DEC, VK_SUBTRACT, FCONTROL, IDS_SUB_FONT_SIZE_DEC }, + { ID_SUB_FONT_SIZE_INC, VK_ADD, FCONTROL, IDS_SUB_FONT_SIZE_INC }, + + { ID_AFTERPLAYBACK_DONOTHING, 0, 0, IDS_AFTERPLAYBACK_DONOTHING }, + { ID_AFTERPLAYBACK_PLAYNEXT, 0, 0, IDS_AFTERPLAYBACK_PLAYNEXT }, + { ID_AFTERPLAYBACK_MONITOROFF, 0, 0, IDS_AFTERPLAYBACK_MONITOROFF }, + { ID_AFTERPLAYBACK_EXIT, 0, 0, IDS_AFTERPLAYBACK_EXIT }, + { ID_AFTERPLAYBACK_STANDBY, 0, 0, IDS_AFTERPLAYBACK_STANDBY }, + { ID_AFTERPLAYBACK_HIBERNATE, 0, 0, IDS_AFTERPLAYBACK_HIBERNATE }, + { ID_AFTERPLAYBACK_SHUTDOWN, 0, 0, IDS_AFTERPLAYBACK_SHUTDOWN }, + { ID_AFTERPLAYBACK_LOGOFF, 0, 0, IDS_AFTERPLAYBACK_LOGOFF }, + { ID_AFTERPLAYBACK_LOCK, 0, 0, IDS_AFTERPLAYBACK_LOCK }, + + { ID_VIEW_EDITLISTEDITOR, 0, 0, IDS_AG_TOGGLE_EDITLISTEDITOR }, + { ID_EDL_IN, 0, 0, IDS_AG_EDL_IN }, + { ID_EDL_OUT, 0, 0, IDS_AG_EDL_OUT }, + { ID_EDL_NEWCLIP, 0, 0, IDS_AG_EDL_NEW_CLIP }, + { ID_EDL_SAVE, 0, 0, IDS_AG_EDL_SAVE }, + + { ID_PLAYLIST_TOGGLE_SHUFFLE, 0, 0, IDS_PLAYLIST_TOGGLE_SHUFFLE }, + { ID_AUDIOSHIFT_ONOFF, 0, 0, IDS_AUDIOSHIFT_ONOFF }, +}; + +void CAppSettings::CreateCommands() +{ + for (const auto& wc : default_wmcmds) { + wmcmd w = wmcmd(wc); + w.fVirt |= FVIRTKEY | FNOINVERT; + CommandIDToWMCMD[wc.cmd] = &wc; + wmcmds.AddTail(w); + } + ASSERT(wmcmds.GetCount() <= ACCEL_LIST_SIZE); +} + +CAppSettings::~CAppSettings() +{ + if (hAccel) { + DestroyAcceleratorTable(hAccel); + } +} + +bool CAppSettings::IsD3DFullscreen() const +{ + if (iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || iDSVideoRendererType == VIDRNDT_DS_SYNC) { + return fD3DFullscreen || (nCLSwitches & CLSW_D3DFULLSCREEN); + } else { + return false; + } +} + +bool CAppSettings::IsISRAutoLoadEnabled() const +{ + return eSubtitleRenderer == SubtitleRenderer::INTERNAL && + IsSubtitleRendererSupported(eSubtitleRenderer, iDSVideoRendererType); +} + +CAppSettings::SubtitleRenderer CAppSettings::GetSubtitleRenderer() const +{ + switch (eSubtitleRenderer) { + case SubtitleRenderer::INTERNAL: + return IsSubtitleRendererSupported(SubtitleRenderer::INTERNAL, iDSVideoRendererType) ? eSubtitleRenderer : SubtitleRenderer::VS_FILTER; + case SubtitleRenderer::XY_SUB_FILTER: + return IsSubtitleRendererSupported(SubtitleRenderer::XY_SUB_FILTER, iDSVideoRendererType) ? eSubtitleRenderer : SubtitleRenderer::VS_FILTER; + default: + return eSubtitleRenderer; + } +} + +bool CAppSettings::IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer) +{ + switch (eSubtitleRenderer) { + case SubtitleRenderer::INTERNAL: + return true; + case SubtitleRenderer::VS_FILTER: + return IsCLSIDRegistered(CLSID_VSFilter); + case SubtitleRenderer::XY_SUB_FILTER: + return IsCLSIDRegistered(CLSID_XySubFilter); + case SubtitleRenderer::NONE: + return true; + default: + ASSERT(FALSE); + return false; + } +} + +bool CAppSettings::IsSubtitleRendererSupported(SubtitleRenderer eSubtitleRenderer, int videoRenderer) +{ + switch (eSubtitleRenderer) { + case SubtitleRenderer::INTERNAL: + switch (videoRenderer) { + case VIDRNDT_DS_VMR9RENDERLESS: + case VIDRNDT_DS_EVR_CUSTOM: + case VIDRNDT_DS_DXR: + case VIDRNDT_DS_SYNC: + case VIDRNDT_DS_MADVR: + case VIDRNDT_DS_MPCVR: + return true; + } + break; + + case SubtitleRenderer::VS_FILTER: + return true; + + case SubtitleRenderer::XY_SUB_FILTER: + switch (videoRenderer) { + case VIDRNDT_DS_VMR9RENDERLESS: + case VIDRNDT_DS_EVR_CUSTOM: + case VIDRNDT_DS_SYNC: + case VIDRNDT_DS_MADVR: + case VIDRNDT_DS_MPCVR: + return true; + } + break; + case SubtitleRenderer::NONE: + return true; + + default: + ASSERT(FALSE); + } + + return false; +} + +bool CAppSettings::IsVideoRendererAvailable(int iVideoRendererType) +{ + switch (iVideoRendererType) { + case VIDRNDT_DS_DXR: + return IsCLSIDRegistered(CLSID_DXR); + case VIDRNDT_DS_EVR: + case VIDRNDT_DS_EVR_CUSTOM: + case VIDRNDT_DS_SYNC: + return IsCLSIDRegistered(CLSID_EnhancedVideoRenderer); + case VIDRNDT_DS_MADVR: + return IsCLSIDRegistered(CLSID_madVR); + case VIDRNDT_DS_MPCVR: + return IsCLSIDRegistered(CLSID_MPCVR) || DSObjects::CMPCVRAllocatorPresenter::HasInternalMPCVRFilter(); +#ifdef _WIN64 + case VIDRNDT_DS_OVERLAYMIXER: + return false; +#endif + default: + return true; + } +} + +bool CAppSettings::IsInitialized() const +{ + return bInitialized; +} + +CString CAppSettings::SelectedAudioRenderer() const +{ + CString strResult; + if (!AfxGetMyApp()->m_AudioRendererDisplayName_CL.IsEmpty()) { + strResult = AfxGetMyApp()->m_AudioRendererDisplayName_CL; + } else { + strResult = AfxGetAppSettings().strAudioRendererDisplayName; + } + + return strResult; +} + +void CAppSettings::ClearRecentFiles() { + MRU.RemoveAll(); + + for (int i = MRUDub.GetSize() - 1; i >= 0; i--) { + MRUDub.Remove(i); + } + MRUDub.WriteList(); + + // Empty the Windows "Recent" jump list + CComPtr pDests; + HRESULT hr = pDests.CoCreateInstance(CLSID_ApplicationDestinations, nullptr, CLSCTX_INPROC_SERVER); + if (SUCCEEDED(hr)) { + pDests->RemoveAllDestinations(); + } +} + +void CAppSettings::SaveSettings(bool write_full_history /* = false */) +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + if (!bInitialized) { + return; + } + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECAPTIONMENU, eCaptionMenuMode); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDENAVIGATION, fHideNavigation); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CONTROLSTATE, nCS); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTVIDEOFRAME, iDefaultVideoSize); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPASPECTRATIO, fKeepAspectRatio); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COMPMONDESKARDIFF, fCompMonDeskARDiff); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUME, nVolume); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BALANCE, nBalance); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUMESTEP, nVolumeStep); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPEEDSTEP, nSpeedStep); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MUTE, fMute); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPNUM, nLoops); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP, fLoopForever); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPMODE, static_cast(eLoopMode)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ZOOM, iZoomLevel); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, fAllowMultipleInst); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTSTYLE, iTitleBarTextStyle); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTTITLE, fTitleBarTextTitle); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ONTOP, iOnTop); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TRAYICON, fTrayIcon); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOZOOM, fRememberZoomLevel); + pApp->WriteProfileStringW(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR, NULL); //remove old form factor + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MIN, nAutoFitFactorMin); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MAX, nAutoFitFactorMax); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AFTER_PLAYBACK, static_cast(eAfterPlayback)); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS, bHideFullscreenControls)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_POLICY, + static_cast(eHideFullscreenControlsPolicy))); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_DELAY, uHideFullscreenControlsDelay)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_DOCKED_PANELS, bHideFullscreenDockedPanels)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_CONTROLS, bHideWindowedControls)); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_MOUSE_POINTER, bHideWindowedMousePointer)); + + // Auto-change fullscreen mode + SaveSettingsAutoChangeFullScreenMode(); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_EXITFULLSCREENATTHEEND, fExitFullScreenAtTheEnd); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWPOS, fRememberWindowPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWSIZE, fRememberWindowSize); + if (fRememberWindowSize || fRememberWindowPos) { + pApp->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_LASTWINDOWRECT, (BYTE*)&rcLastWindowPos, sizeof(rcLastWindowPos)); + } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTWINDOWTYPE, nLastWindowType); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTFULLSCREEN, fLastFullScreen); + + if (fSavePnSZoom) { + CString str; + str.Format(_T("%.3f,%.3f"), dZoomX, dZoomY); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM, str); + } else { + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM, nullptr); + } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPTODESKTOPEDGES, fSnapToDesktopEdges); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_X, sizeAspectRatio.cx); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_Y, sizeAspectRatio.cy); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPHISTORY, fKeepHistory); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RECENT_FILES_NUMBER, iRecentFilesNumber); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, iDSVideoRendererType); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHUFFLEPLAYLISTITEMS, bShufflePlaylistItems); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERPLAYLISTITEMS, bRememberPlaylistItems); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDEPLAYLISTFULLSCREEN, bHidePlaylistFullScreen); + pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERPOS, bFavRememberPos); + pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_RELATIVEDRIVE, bFavRelativeDrive); + pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERABMARKS, bFavRememberABMarks); + + UpdateRenderersData(true); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUDIORENDERERTYPE, CString(strAudioRendererDisplayName)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOLOADAUDIO, fAutoloadAudio); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER, CString(strSubtitlesLanguageOrder)); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER, CString(strAudiosLanguageOrder)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKVSFILTER, fBlockVSFilter); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKRDP, bBlockRDP); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWORKERTHREADFOROPENING, fEnableWorkerThreadForOpening); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REPORTFAILEDPINS, fReportFailedPins); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_DVDPATH, strDVDPath); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USEDVDPATH, fUseDVDPath); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MENULANG, idMenuLang); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOLANG, idAudioLang); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANG, idSubtitlesLang); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_OPENTYPELANGHINT, CString(strOpenTypeLangHint)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_FREETYPE, bUseFreeType); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_MEDIAINFO_LOAD_FILE_DURATION, bUseMediainfoLoadFileDuration); +#if USE_LIBASS + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSSAUSINGLIBASS, bRenderSSAUsingLibass); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSRTUSINGLIBASS, bRenderSRTUsingLibass); +#endif + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CLOSEDCAPTIONS, fClosedCaptions); + CString style; + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SPSTYLE, style <<= subtitlesDefStyle); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPOVERRIDEPLACEMENT, fOverridePlacement); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPHORPOS, nHorPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPVERPOS, nVerPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLEARCOMPENSATION, bSubtitleARCompensation); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBDELAYINTERVAL, nSubDelayStep); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLESUBTITLES, fEnableSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREFER_FORCED_DEFAULT_SUBTITLES, bPreferDefaultForcedSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITIZEEXTERNALSUBTITLES, fPrioritizeExternalSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLEINTERNALSUBTITLES, fDisableInternalSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_OVERRIDING_EXT_SPLITTER, bAllowOverridingExternalSplitterChoice); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLES, bAutoDownloadSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOSAVEDOWNLOADEDSUBTITLES, bAutoSaveDownloadedSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCOREMOVIES, nAutoDownloadScoreMovies); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCORESERIES, nAutoDownloadScoreSeries); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLESEXCLUDE, strAutoDownloadSubtitlesExclude); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOUPLOADSUBTITLES, bAutoUploadSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREFERHEARINGIMPAIREDSUBTITLES, bPreferHearingImpairedSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MPCTHEME, bMPCTheme); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNSEEKBARHEIGHT, iModernSeekbarHeight); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNTHEMEMODE, static_cast(eModernThemeMode)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_DELAY, iFullscreenDelay); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VERTICALALIGNVIDEO, static_cast(iVerticalAlignVideo)); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESPROVIDERS, strSubtitlesProviders); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLEPATHS, strSubtitlePaths); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_DEFAULT_STYLE, bSubtitleOverrideDefaultStyle); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_ALL_STYLES, bSubtitleOverrideAllStyles); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOSWITCHER, fEnableAudioSwitcher); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOTIMESHIFT, fAudioTimeShift); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOTIMESHIFT, iAudioTimeShift); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DOWNSAMPLETO441, fDownSampleTo441); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CUSTOMCHANNELMAPPING, fCustomChannelMapping); + pApp->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_SPEAKERTOCHANNELMAPPING, (BYTE*)pSpeakerToChannelMap, sizeof(pSpeakerToChannelMap)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZE, fAudioNormalize); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOMAXNORMFACTOR, nAudioMaxNormFactor); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZERECOVER, fAudioNormalizeRecover); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, nAudioBoost); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPEAKERCHANNELS, nSpeakerChannels); + + // Multi-monitor code + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITOR, CString(strFullScreenMonitorID)); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITORDEVICE, CString(strFullScreenMonitorDeviceName)); + + // Mouse + CStringW str; + str.Format(L"%u", nMouseLeftClick); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT, str); + str.Format(L"%u", nMouseLeftDblClick); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT_DBLCLICK, str); + str.Format(L"%u", nMouseRightClick); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_RIGHT, str); + str.Format(L"%u;%u;%u;%u", MouseMiddleClick.normal, MouseMiddleClick.ctrl, MouseMiddleClick.shift, MouseMiddleClick.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_MIDDLE, str); + str.Format(L"%u;%u;%u;%u", MouseX1Click.normal, MouseX1Click.ctrl, MouseX1Click.shift, MouseX1Click.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X1, str); + str.Format(L"%u;%u;%u;%u", MouseX2Click.normal, MouseX2Click.ctrl, MouseX2Click.shift, MouseX2Click.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X2, str); + str.Format(L"%u;%u;%u;%u", MouseWheelUp.normal, MouseWheelUp.ctrl, MouseWheelUp.shift, MouseWheelUp.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_UP, str); + str.Format(L"%u;%u;%u;%u", MouseWheelDown.normal, MouseWheelDown.ctrl, MouseWheelDown.shift, MouseWheelDown.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_DOWN, str); + str.Format(L"%u;%u;%u;%u", MouseWheelLeft.normal, MouseWheelLeft.ctrl, MouseWheelLeft.shift, MouseWheelLeft.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_LEFT, str); + str.Format(L"%u;%u;%u;%u", MouseWheelRight.normal, MouseWheelRight.ctrl, MouseWheelRight.shift, MouseWheelRight.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_RIGHT, str); + + + // Prevent Minimize when in Fullscreen mode on non default monitor + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_MINIMIZE, fPreventMinimize); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENHANCED_TASKBAR, bUseEnhancedTaskBar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEARCH_IN_FOLDER, fUseSearchInFolder); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TIME_TOOLTIP, fUseSeekbarHover); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_TOOLTIP_POSITION, nHoverPosition); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MPC_OSD_SIZE, nOSDSize); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_MPC_OSD_FONT, strOSDFont); + + // Associated types with icon or not... + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASSOCIATED_WITH_ICON, fAssociatedWithIcons); + // Last Open Dir + //pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_LAST_OPEN_DIR, strLastOpenDir); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_D3DFULLSCREEN, fD3DFullscreen); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_BRIGHTNESS, iBrightness); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_CONTRAST, iContrast); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_HUE, iHue); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_SATURATION, iSaturation); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOWOSD, fShowOSD); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CURRENT_TIME_OSD, fShowCurrentTimeInOSD); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_TRANSPARENCY, nOSDTransparency); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_BORDER, nOSDBorder); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEEDLEDITOR, fEnableEDLEditor); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LANGUAGE, language); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK, bFastSeek); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK_METHOD, eFastSeekMethod); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CHAPTERS, fShowChapters); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, fLCDSupport); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW, fSeekPreview); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW_SIZE, iSeekPreviewSize); + + + // Save analog capture settings + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, iDefaultCaptureDevice); + pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, strAnalogVideo); + pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, strAnalogAudio); + pApp->WriteProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, iAnalogCountry); + + // Save digital capture settings (BDA) + pApp->WriteProfileString(IDS_R_DVB, nullptr, nullptr); // Ensure the section is cleared before saving the new settings + + //pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER, strBDANetworkProvider); + pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER, strBDATuner); + pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER, strBDAReceiver); + //pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD, strBDAStandard); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, iBDAScanFreqStart); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, iBDAScanFreqEnd); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, iBDABandwidth); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SYMBOLRATE, iBDASymbolRate); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_USE_OFFSET, fBDAUseOffset); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_OFFSET, iBDAOffset); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_IGNORE_ENCRYPTED_CHANNELS, fBDAIgnoreEncryptedChannels); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, nDVBLastChannel); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, nDVBRebuildFilterGraph); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, nDVBStopFilterGraph); + + for (size_t i = 0; i < m_DVBChannels.size(); i++) { + CString numChannel; + numChannel.Format(_T("%Iu"), i); + pApp->WriteProfileString(IDS_R_DVB, numChannel, m_DVBChannels[i].ToString()); + } + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DVDPOS, fRememberDVDPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS, fRememberFilePos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSLONGER, iRememberPosForLongerThan); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSAUDIO, bRememberPosForAudioFiles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_PLAYLIST, bRememberExternalPlaylistPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_TRACK_SELECTION, bRememberTrackSelection); + + pApp->WriteProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, nullptr, nullptr); + for (INT_PTR i = 0, j = m_pnspresets.GetCount(); i < j; i++) { + CString str; + str.Format(_T("Preset%Id"), i); + pApp->WriteProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, str, m_pnspresets[i]); + } + + pApp->WriteProfileString(IDS_R_COMMANDS, nullptr, nullptr); + POSITION pos = wmcmds.GetHeadPosition(); + for (int i = 0; pos;) { + const wmcmd& wc = wmcmds.GetNext(pos); + if (wc.IsModified()) { + CString str; + str.Format(_T("CommandMod%d"), i); + // mouse and mouseVirt are written twice for backwards compatibility with old versions + CString str2; + str2.Format(_T("%hu %hx %hx \"%S\" %d %hhu %u %hhu %hhu %hhu"), + wc.cmd, (WORD)wc.fVirt, wc.key, wc.rmcmd.GetString(), + wc.rmrepcnt, wc.mouse, wc.appcmd, wc.mouse, wc.mouseVirt, wc.mouseVirt); + pApp->WriteProfileString(IDS_R_COMMANDS, str, str2); + i++; + } + } + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WINLIRC, fWinLirc); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WINLIRCADDR, strWinLircAddr); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UICE, fUIce); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_UICEADDR, strUIceAddr); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GLOBALMEDIA, fGlobalMedia); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTS, nJumpDistS); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTM, nJumpDistM); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTL, nJumpDistL); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LIMITWINDOWPROPORTIONS, fLimitWindowProportions); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTUSEDPAGE, nLastUsedPage); + + m_Formats.UpdateData(true); + + // Internal filters + for (int f = 0; f < SRC_LAST; f++) { + pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, SrcFiltersKeys[f].name, SrcFilters[f]); + } + for (int f = 0; f < TRA_LAST; f++) { + pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, TraFiltersKeys[f].name, TraFilters[f]); + } + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_LOGOFILE, strLogoFileName); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOID, nLogoId); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOEXT, fLogoExternal); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOCOLORPROFILE, fLogoColorProfileEnabled); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECDROMSSUBMENU, fHideCDROMsSubMenu); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITY, dwPriority); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LAUNCHFULLSCREEN, fLaunchfullscreen); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWEBSERVER, fEnableWebServer); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPORT, nWebServerPort); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERUSECOMPRESSION, fWebServerUseCompression); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERLOCALHOSTONLY, fWebServerLocalhostOnly); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBUI_ENABLE_PREVIEW, bWebUIEnablePreview); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPRINTDEBUGINFO, fWebServerPrintDebugInfo); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBROOT, strWebRoot); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBDEFINDEX, strWebDefIndex); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBSERVERCGI, strWebServerCGI); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTPATH, strSnapshotPath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTEXT, strSnapshotExt); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTSUBTITLES, bSnapShotSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTKEEPVIDEOEXTENSION, bSnapShotKeepVideoExtension); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBROWS, iThumbRows); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBCOLS, iThumbCols); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBWIDTH, iThumbWidth); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBSAVEEXTERNALSTYLEFILE, bSubSaveExternalStyleFile)); + { + // Save the list of extra (non-default) shader files + VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_EXTRA, m_ShadersExtraList.ToString())); + // Save shader selection + CString strPre, strPost; + m_Shaders.GetCurrentPreset().ToStrings(strPre, strPost); + VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_PRERESIZE, strPre)); + VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_POSTRESIZE, strPost)); + // Save shader presets + int i = 0; + CString iStr; + pApp->WriteProfileString(IDS_R_SHADER_PRESETS, nullptr, nullptr); + for (const auto& pair : m_Shaders.GetPresets()) { + iStr.Format(_T("%d"), i++); + pair.second.ToStrings(strPre, strPost); + VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, iStr, pair.first)); + VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_PRERESIZE + iStr, strPre)); + VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_POSTRESIZE + iStr, strPost)); + } + // Save selected preset name + CString name; + m_Shaders.GetCurrentPresetName(name); + VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_LASTPRESET, name)); + } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADER, bToggleShader); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADERSSCREENSPACE, bToggleShaderScreenSpace); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMAINING_TIME, fRemainingTime); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIGH_PRECISION_TIMER, bHighPrecisionTimer); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIMER_SHOW_PERCENTAGE, bTimerShowPercentage); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_AUTO_CHECK, nUpdaterAutoCheck); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_DELAY, nUpdaterDelay); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_NOTIFY_SKYPE, bNotifySkype); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JPEG_QUALITY, nJpegQuality); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART, bEnableCoverArt); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART_SIZE_LIMIT, nCoverArtSizeLimit); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGGING, bEnableLogging); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_LEGACY_TOOLBAR, bUseLegacyToolbar); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, + static_cast(eSubtitleRenderer))); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTTOOLBARSIZE, nDefaultToolbarSize); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_POSITION, bSaveImagePosition); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_CURRENTTIME, bSaveImageCurrentTime); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_INACCURATE_FASTSEEK, bAllowInaccurateFastseek); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP_FOLDER_NEXT_FILE, bLoopFolderOnPlayNextFile); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOCK_NOPAUSE, bLockNoPause); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_DISPLAY_SLEEP, bPreventDisplaySleep); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_SMTC, bUseSMTC); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RELOAD_AFTER_LONG_PAUSE, iReloadAfterLongPause); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OPEN_REC_PANEL_WHEN_OPENING_DEVICE, bOpenRecPanelWhenOpeningDevice); + + { + CComHeapPtr pDeviceId; + BOOL bExclusive; + UINT32 uBufferDuration; + if (SUCCEEDED(sanear->GetOutputDevice(&pDeviceId, &bExclusive, &uBufferDuration))) { + pApp->WriteProfileString(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_ID, pDeviceId); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_EXCLUSIVE, bExclusive); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_BUFFER, uBufferDuration); + } + + BOOL bCrossfeedEnabled = sanear->GetCrossfeedEnabled(); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_ENABLED, bCrossfeedEnabled); + + UINT32 uCutoffFrequency, uCrossfeedLevel; + sanear->GetCrossfeedSettings(&uCutoffFrequency, &uCrossfeedLevel); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ, uCutoffFrequency); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, uCrossfeedLevel); + + BOOL bIgnoreSystemChannelMixer = sanear->GetIgnoreSystemChannelMixer(); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_IGNORE_SYSTEM_MIXER, bIgnoreSystemChannelMixer); + } + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_YDL, bUseYDL); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, iYDLMaxHeight); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_VIDEO_FORMAT, iYDLVideoFormat); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_FORMAT, iYDLAudioFormat); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, bYDLAudioOnly); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_EXEPATH, sYDLExePath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_COMMAND_LINE, sYDLCommandLine); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLE_CRASH_REPORTER, bEnableCrashReporter); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_REFRESH_INTERVAL, nStreamPosPollerInterval); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_LANG_STATUSBAR, bShowLangInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_FPS_STATUSBAR, bShowFPSInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_ABMARKS_STATUSBAR, bShowABMarksInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_VIDEOINFO_STATUSBAR, bShowVideoInfoInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_AUDIOFORMAT_STATUSBAR, bShowAudioFormatInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ADD_LANGCODE_WHEN_SAVE_SUBTITLES, bAddLangCodeWhenSaveSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TITLE_IN_RECENT_FILE_LIST, bUseTitleInRecentFileList); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_SUBS_PREFERENCE, sYDLSubsPreference); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_AUTOMATIC_CAPTIONS, bUseAutomaticCaptions); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_QUICKOPEN_PATH, lastQuickOpenPath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_FILESAVECOPY_PATH, lastFileSaveCopyPath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_FILEOPENDIR_PATH, lastFileOpenDirPath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_EXTERNAL_PLAYLIST_PATH, externalPlayListPath); + + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REDIRECT_OPEN_TO_APPEND_THRESHOLD, iRedirectOpenToAppendThreshold); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_SEPARATE_CONTROLS, bFullscreenSeparateControls); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALWAYS_USE_SHORT_MENU, bAlwaysUseShortMenu); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_STILL_VIDEO_DURATION, iStillVideoDuration); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MOUSE_LEFTUP_DELAY, iMouseLeftUpDelay); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CAPTURE_DEINTERLACE, bCaptureDeinterlace); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PAUSE_WHILE_DRAGGING_SEEKBAR, bPauseWhileDraggingSeekbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CONFIRM_FILE_DELETE, bConfirmFileDelete); + + if (fKeepHistory && write_full_history) { + MRU.SaveMediaHistory(); + } + + pApp->FlushProfile(); +} + +void CAppSettings::PurgeMediaHistory(size_t maxsize) { + CStringW section = L"MediaHistory"; + auto timeToHash = LoadHistoryHashes(section, L"LastUpdated"); + size_t entries = timeToHash.size(); + if (entries > maxsize) { + for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { + if (entries > maxsize) { + PurgeExpiredHash(section, iter->second); + entries--; + } else { + break; + } + } + } +} + +void CAppSettings::PurgePlaylistHistory(size_t maxsize) { + CStringW section = L"PlaylistHistory"; + auto timeToHash = LoadHistoryHashes(section, L"LastUpdated"); + size_t entries = timeToHash.size(); + if (entries > maxsize) { + for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { + if (entries > maxsize) { + PurgeExpiredHash(section, iter->second); + entries--; + } else { + break; + } + } + } +} + +std::multimap CAppSettings::LoadHistoryHashes(CStringW section, CStringW dateField) { + auto pApp = AfxGetMyApp(); + auto hashes = pApp->GetSectionSubKeys(section); + + std::multimap timeToHash; + for (auto const& hash : hashes) { + CStringW lastOpened, subSection; + subSection.Format(L"%s\\%s", section, static_cast(hash)); + lastOpened = pApp->GetProfileStringW(subSection, dateField, L"0000-00-00T00:00:00.0Z"); + if (!lastOpened.IsEmpty()) { + timeToHash.insert(std::pair(lastOpened, hash)); + } + } + return timeToHash; +} + +void CAppSettings::PurgeExpiredHash(CStringW section, CStringW hash) { + auto pApp = AfxGetMyApp(); + CStringW subSection; + subSection.Format(L"%s\\%s", section, static_cast(hash)); + pApp->WriteProfileString(subSection, nullptr, nullptr); +} + +void CAppSettings::LoadExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey /*= IDS_R_EXTERNAL_FILTERS*/) +{ + CWinApp* pApp = AfxGetApp(); + ASSERT(pApp); + + for (unsigned int i = 0; ; i++) { + CString key; + key.Format(_T("%s\\%04u"), baseKey, i); + + CAutoPtr f(DEBUG_NEW FilterOverride); + + f->fDisabled = !pApp->GetProfileInt(key, _T("Enabled"), FALSE); + + UINT j = pApp->GetProfileInt(key, _T("SourceType"), -1); + if (j == 0) { + f->type = FilterOverride::REGISTERED; + f->dispname = CStringW(pApp->GetProfileString(key, _T("DisplayName"))); + f->name = pApp->GetProfileString(key, _T("Name")); + CString clsid_str = pApp->GetProfileString(key, _T("CLSID")); + if (clsid_str.IsEmpty() && f->dispname.GetLength() == 88 && f->dispname.Left(1) == L"@") { + clsid_str = f->dispname.Right(38); + } + if (clsid_str.GetLength() == 38) { + f->clsid = GUIDFromCString(clsid_str); + } + } else if (j == 1) { + f->type = FilterOverride::EXTERNAL; + f->path = pApp->GetProfileString(key, _T("Path")); + f->name = pApp->GetProfileString(key, _T("Name")); + f->clsid = GUIDFromCString(pApp->GetProfileString(key, _T("CLSID"))); + } else { + pApp->WriteProfileString(key, nullptr, 0); + break; + } + + if (IgnoreExternalFilter(f->clsid)) { + continue; + } + + f->backup.RemoveAll(); + for (unsigned int k = 0; ; k++) { + CString val; + val.Format(_T("org%04u"), k); + CString guid = pApp->GetProfileString(key, val); + if (guid.IsEmpty()) { + break; + } + f->backup.AddTail(GUIDFromCString(guid)); + } + + f->guids.RemoveAll(); + for (unsigned int k = 0; ; k++) { + CString val; + val.Format(_T("mod%04u"), k); + CString guid = pApp->GetProfileString(key, val); + if (guid.IsEmpty()) { + break; + } + f->guids.AddTail(GUIDFromCString(guid)); + } + + f->iLoadType = (int)pApp->GetProfileInt(key, _T("LoadType"), -1); + if (f->iLoadType < 0) { + break; + } + + f->dwMerit = pApp->GetProfileInt(key, _T("Merit"), MERIT_DO_NOT_USE + 1); + + filters.AddTail(f); + } +} + +void CAppSettings::SaveExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey /*= IDS_R_EXTERNAL_FILTERS*/) +{ + // Saving External Filter settings takes a long time. Use only when really necessary. + CWinApp* pApp = AfxGetApp(); + ASSERT(pApp); + + // Remove the old keys + for (unsigned int i = 0; ; i++) { + CString key; + key.Format(_T("%s\\%04u"), baseKey, i); + int j = pApp->GetProfileInt(key, _T("Enabled"), -1); + pApp->WriteProfileString(key, nullptr, nullptr); + if (j < 0) { + break; + } + } + + unsigned int k = 0; + POSITION pos = filters.GetHeadPosition(); + while (pos) { + FilterOverride* f = filters.GetNext(pos); + + if (f->fTemporary) { + continue; + } + + CString key; + key.Format(_T("%s\\%04u"), baseKey, k); + + pApp->WriteProfileInt(key, _T("SourceType"), (int)f->type); + pApp->WriteProfileInt(key, _T("Enabled"), (int)!f->fDisabled); + pApp->WriteProfileString(key, _T("Name"), f->name); + pApp->WriteProfileString(key, _T("CLSID"), CStringFromGUID(f->clsid)); + if (f->type == FilterOverride::REGISTERED) { + pApp->WriteProfileString(key, _T("DisplayName"), CString(f->dispname)); + } else if (f->type == FilterOverride::EXTERNAL) { + pApp->WriteProfileString(key, _T("Path"), f->path); + } + POSITION pos2 = f->backup.GetHeadPosition(); + for (unsigned int i = 0; pos2; i++) { + CString val; + val.Format(_T("org%04u"), i); + pApp->WriteProfileString(key, val, CStringFromGUID(f->backup.GetNext(pos2))); + } + pos2 = f->guids.GetHeadPosition(); + for (unsigned int i = 0; pos2; i++) { + CString val; + val.Format(_T("mod%04u"), i); + pApp->WriteProfileString(key, val, CStringFromGUID(f->guids.GetNext(pos2))); + } + pApp->WriteProfileInt(key, _T("LoadType"), f->iLoadType); + pApp->WriteProfileInt(key, _T("Merit"), f->dwMerit); + + k++; + } +} + +void CAppSettings::SaveSettingsAutoChangeFullScreenMode() +{ + auto pApp = AfxGetMyApp(); + ASSERT(pApp); + + // Ensure the section is cleared before saving the new settings + for (size_t i = 0;; i++) { + CString section; + section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); + + // WriteProfileString doesn't return false when INI is used and the section doesn't exist + // so instead check for the a value inside that section + if (!pApp->HasProfileEntry(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED)) { + break; + } else { + VERIFY(pApp->WriteProfileString(section, nullptr, nullptr)); + } + } + pApp->WriteProfileString(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, nullptr, nullptr); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_ENABLE, autoChangeFSMode.bEnabled)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_APPLYDEFMODEATFSEXIT, autoChangeFSMode.bApplyDefaultModeAtFSExit)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_RESTORERESAFTEREXIT, autoChangeFSMode.bRestoreResAfterProgExit)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_DELAY, (int)autoChangeFSMode.uDelay)); + + for (size_t i = 0; i < autoChangeFSMode.modes.size(); i++) { + const auto& mode = autoChangeFSMode.modes[i]; + CString section; + section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); + + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED, mode.bChecked)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTART, std::lround(mode.dFrameRateStart * 1000000))); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTOP, std::lround(mode.dFrameRateStop * 1000000))); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_AUDIODELAY, mode.msAudioDelay)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_BPP, mode.dm.bpp)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FREQ, mode.dm.freq)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEX, mode.dm.size.cx)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEY, mode.dm.size.cy)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FLAGS, (int)mode.dm.dwDisplayFlags)); + } +} + +void CAppSettings::LoadSettings() +{ + CWinApp* pApp = AfxGetApp(); + ASSERT(pApp); + + UINT len; + BYTE* ptr = nullptr; + + if (bInitialized) { + return; + } + + // Set interface language first! + language = (LANGID)pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LANGUAGE, -1); + if (language == LANGID(-1)) { + language = Translations::SetDefaultLanguage(); + } else if (language != 0) { + if (language <= 23) { + // We must be updating from a really old version, use the default language + language = Translations::SetDefaultLanguage(); + } else if (!Translations::SetLanguage(language, false)) { + // In case of error, reset the language to English + language = 0; + } + } + + CreateCommands(); + + eCaptionMenuMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECAPTIONMENU, MODE_SHOWCAPTIONMENU)); + fHideNavigation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDENAVIGATION, FALSE); + nCS = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CONTROLSTATE, CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR); + iDefaultVideoSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTVIDEOFRAME, DVS_FROMINSIDE); + fKeepAspectRatio = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPASPECTRATIO, TRUE); + fCompMonDeskARDiff = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COMPMONDESKARDIFF, FALSE); + nVolume = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUME, 100); + nBalance = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BALANCE, 0); + fMute = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MUTE, FALSE); + nLoops = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPNUM, 1); + fLoopForever = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP, FALSE); + eLoopMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPMODE, static_cast(LoopMode::PLAYLIST))); + iZoomLevel = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ZOOM, 1); + iDSVideoRendererType = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, + IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS); + nVolumeStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUMESTEP, 5); + nSpeedStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPEEDSTEP, 0); + if (nSpeedStep > 75) { + nSpeedStep = 75; + } + + UpdateRenderersData(false); + + strAudioRendererDisplayName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIORENDERERTYPE); + fAutoloadAudio = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOLOADAUDIO, TRUE); + strSubtitlesLanguageOrder = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER); + strAudiosLanguageOrder = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER); + fBlockVSFilter = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKVSFILTER, TRUE); + bBlockRDP = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKRDP, FALSE); + fEnableWorkerThreadForOpening = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWORKERTHREADFOROPENING, TRUE); + fReportFailedPins = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REPORTFAILEDPINS, TRUE); + fAllowMultipleInst = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, FALSE); + iTitleBarTextStyle = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTSTYLE, 1); + fTitleBarTextTitle = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTTITLE, FALSE); + iOnTop = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ONTOP, 0); + fTrayIcon = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TRAYICON, FALSE); + fRememberZoomLevel = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOZOOM, TRUE); + int tAutoFitFactor = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR, 0); //if found, old fit factor will be default for min/max + nAutoFitFactorMin = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MIN, tAutoFitFactor ? tAutoFitFactor : DEF_MIN_AUTOFIT_SCALE_FACTOR); //otherwise default min to DEF_MIN_AUTOFIT_SCALE_FACTOR + nAutoFitFactorMax = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MAX, tAutoFitFactor ? tAutoFitFactor : DEF_MAX_AUTOFIT_SCALE_FACTOR); //otherwise default max to DEF_MAX_AUTOFIT_SCALE_FACTOR + nAutoFitFactorMin = std::max(std::min(nAutoFitFactorMin, nAutoFitFactorMax), MIN_AUTOFIT_SCALE_FACTOR); + nAutoFitFactorMax = std::min(std::max(nAutoFitFactorMin, nAutoFitFactorMax), MAX_AUTOFIT_SCALE_FACTOR); + + eAfterPlayback = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AFTER_PLAYBACK, 0)); + + bHideFullscreenControls = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS, TRUE); + eHideFullscreenControlsPolicy = + static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_POLICY, 1)); + uHideFullscreenControlsDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_DELAY, 0); + bHideFullscreenDockedPanels = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_DOCKED_PANELS, TRUE); + bHideWindowedControls = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_CONTROLS, FALSE); + + bHideWindowedMousePointer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_MOUSE_POINTER, TRUE); + + // Multi-monitor code + strFullScreenMonitorID = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITOR); + strFullScreenMonitorDeviceName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITORDEVICE); + + // Mouse + CStringW str; + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT); + swscanf_s(str, L"%u", &nMouseLeftClick); + if (nMouseLeftClick != 0 && nMouseLeftClick != ID_PLAY_PLAYPAUSE && nMouseLeftClick != ID_VIEW_FULLSCREEN) { + nMouseLeftClick = ID_PLAY_PLAYPAUSE; + } + + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT_DBLCLICK); + swscanf_s(str, L"%u", &nMouseLeftDblClick); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_RIGHT); + swscanf_s(str, L"%u", &nMouseRightClick); + + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_MIDDLE); + swscanf_s(str, L"%u;%u;%u;%u", &MouseMiddleClick.normal, &MouseMiddleClick.ctrl, &MouseMiddleClick.shift, &MouseMiddleClick.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X1); + swscanf_s(str, L"%u;%u;%u;%u", &MouseX1Click.normal, &MouseX1Click.ctrl, &MouseX1Click.shift, &MouseX1Click.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X2); + swscanf_s(str, L"%u;%u;%u;%u", &MouseX2Click.normal, &MouseX2Click.ctrl, &MouseX2Click.shift, &MouseX2Click.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_UP); + swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelUp.normal, &MouseWheelUp.ctrl, &MouseWheelUp.shift, &MouseWheelUp.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_DOWN); + swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelDown.normal, &MouseWheelDown.ctrl, &MouseWheelDown.shift, &MouseWheelDown.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_LEFT); + swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelLeft.normal, &MouseWheelLeft.ctrl, &MouseWheelLeft.shift, &MouseWheelLeft.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_RIGHT); + swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelRight.normal, &MouseWheelRight.ctrl, &MouseWheelRight.shift, &MouseWheelRight.rbtn); + + + // Prevent Minimize when in fullscreen mode on non default monitor + fPreventMinimize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_MINIMIZE, FALSE); + bUseEnhancedTaskBar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENHANCED_TASKBAR, TRUE); + fUseSearchInFolder = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEARCH_IN_FOLDER, TRUE); + fUseSeekbarHover = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TIME_TOOLTIP, TRUE); + nHoverPosition = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_TOOLTIP_POSITION, TIME_TOOLTIP_ABOVE_SEEKBAR); + nOSDSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MPC_OSD_SIZE, 18); + LOGFONT lf; + GetMessageFont(&lf); + strOSDFont = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_MPC_OSD_FONT, lf.lfFaceName); + if (strOSDFont.IsEmpty() || strOSDFont.GetLength() >= LF_FACESIZE) { + strOSDFont = lf.lfFaceName; + } + + // Associated types with icon or not... + fAssociatedWithIcons = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASSOCIATED_WITH_ICON, TRUE); + // Last Open Dir + //strLastOpenDir = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_LAST_OPEN_DIR, _T("C:\\")); + + fAudioTimeShift = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOTIMESHIFT, FALSE); + iAudioTimeShift = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOTIMESHIFT, 0); + + // Auto-change fullscreen mode + autoChangeFSMode.bEnabled = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_ENABLE, FALSE); + autoChangeFSMode.bApplyDefaultModeAtFSExit = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_APPLYDEFMODEATFSEXIT, FALSE); + autoChangeFSMode.bRestoreResAfterProgExit = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_RESTORERESAFTEREXIT, TRUE); + autoChangeFSMode.uDelay = pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_DELAY, 0); + + autoChangeFSMode.modes.clear(); + for (size_t i = 0;; i++) { + CString section; + section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); + + int iChecked = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED, INT_ERROR); + if (iChecked == INT_ERROR) { + break; + } + + double dFrameRateStart = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTART, 0) / 1000000.0; + double dFrameRateStop = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTOP, 0) / 1000000.0; + int msAudioDelay = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_AUDIODELAY, fAudioTimeShift ? iAudioTimeShift : 0); + DisplayMode dm; + dm.bValid = true; + dm.bpp = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_BPP, 0); + dm.freq = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FREQ, 0); + dm.size.cx = (LONG)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEX, 0); + dm.size.cy = (LONG)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEY, 0); + dm.dwDisplayFlags = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FLAGS, 0); + + autoChangeFSMode.modes.emplace_back(!!iChecked, dFrameRateStart, dFrameRateStop, msAudioDelay, std::move(dm)); + } + + fExitFullScreenAtTheEnd = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_EXITFULLSCREENATTHEEND, TRUE); + + fRememberWindowPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWPOS, FALSE); + fRememberWindowSize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWSIZE, FALSE); + str = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM); + if (_stscanf_s(str, _T("%lf,%lf"), &dZoomX, &dZoomY) == 2 && + dZoomX >= 0.196 && dZoomX <= 5.0 && + dZoomY >= 0.196 && dZoomY <= 5.0) { + fSavePnSZoom = true; + } else { + fSavePnSZoom = false; + dZoomX = 1.0; + dZoomY = 1.0; + } + fSnapToDesktopEdges = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPTODESKTOPEDGES, FALSE); + sizeAspectRatio.cx = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_X, 0); + sizeAspectRatio.cy = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_Y, 0); + + fKeepHistory = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPHISTORY, TRUE); + fileAssoc.SetNoRecentDocs(!fKeepHistory); + iRecentFilesNumber = std::max(0, (int)pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RECENT_FILES_NUMBER, 100)); + MRU.SetSize(iRecentFilesNumber); + + if (pApp->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_LASTWINDOWRECT, &ptr, &len)) { + if (len == sizeof(CRect)) { + memcpy(&rcLastWindowPos, ptr, sizeof(CRect)); + if (rcLastWindowPos.Width() < 250 || rcLastWindowPos.Height() < 80) { + rcLastWindowPos = CRect(100, 100, 500, 400); + } + } + delete[] ptr; + } + nLastWindowType = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTWINDOWTYPE, SIZE_RESTORED); + fLastFullScreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTFULLSCREEN, FALSE); + + bShufflePlaylistItems = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHUFFLEPLAYLISTITEMS, FALSE); + bRememberPlaylistItems = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERPLAYLISTITEMS, TRUE); + bHidePlaylistFullScreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDEPLAYLISTFULLSCREEN, FALSE); + bFavRememberPos = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERPOS, TRUE); + bFavRelativeDrive = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_RELATIVEDRIVE, FALSE); + bFavRememberABMarks = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERABMARKS, FALSE); + + strDVDPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_DVDPATH); + fUseDVDPath = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USEDVDPATH, FALSE); + idMenuLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MENULANG, 0); + idAudioLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOLANG, 0); + idSubtitlesLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANG, 0); +#if USE_LIBASS + bRenderSSAUsingLibass = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSSAUSINGLIBASS, FALSE); + bRenderSRTUsingLibass = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSRTUSINGLIBASS, FALSE); +#endif + CT2A tmpLangHint(pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_OPENTYPELANGHINT, _T(""))); + strOpenTypeLangHint = tmpLangHint; + bUseFreeType = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_FREETYPE, FALSE); + bUseMediainfoLoadFileDuration = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_MEDIAINFO_LOAD_FILE_DURATION, FALSE); + bCaptureDeinterlace = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CAPTURE_DEINTERLACE, FALSE); + bPauseWhileDraggingSeekbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PAUSE_WHILE_DRAGGING_SEEKBAR, TRUE); + bConfirmFileDelete = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CONFIRM_FILE_DELETE, TRUE); + + fClosedCaptions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CLOSEDCAPTIONS, FALSE); + { + CString temp = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SPSTYLE); + subtitlesDefStyle <<= temp; + if (temp.IsEmpty()) { // Position the text subtitles relative to the video frame by default + subtitlesDefStyle.relativeTo = STSStyle::AUTO; + } + } + fOverridePlacement = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPOVERRIDEPLACEMENT, FALSE); + nHorPos = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPHORPOS, 50); + nVerPos = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPVERPOS, 90); + bSubtitleARCompensation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLEARCOMPENSATION, TRUE); + nSubDelayStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBDELAYINTERVAL, 500); + if (nSubDelayStep < 10) { + nSubDelayStep = 500; + } + + fEnableSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLESUBTITLES, TRUE); + bPreferDefaultForcedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREFER_FORCED_DEFAULT_SUBTITLES, TRUE); + fPrioritizeExternalSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITIZEEXTERNALSUBTITLES, TRUE); + fDisableInternalSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLEINTERNALSUBTITLES, FALSE); + bAllowOverridingExternalSplitterChoice = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_OVERRIDING_EXT_SPLITTER, FALSE); + bAutoDownloadSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLES, FALSE); + bAutoSaveDownloadedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOSAVEDOWNLOADEDSUBTITLES, FALSE); + nAutoDownloadScoreMovies = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCOREMOVIES, 0x16); + nAutoDownloadScoreSeries = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCORESERIES, 0x18); + strAutoDownloadSubtitlesExclude = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLESEXCLUDE); + bAutoUploadSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOUPLOADSUBTITLES, FALSE); + bPreferHearingImpairedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREFERHEARINGIMPAIREDSUBTITLES, FALSE); + bMPCTheme = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MPCTHEME, TRUE); + if (IsWindows10OrGreater()) { + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"), KEY_READ)) { + DWORD useTheme = (DWORD)-1; + if (ERROR_SUCCESS == key.QueryDWORDValue(_T("AppsUseLightTheme"), useTheme)) { + if (0 == useTheme) { + bWindows10DarkThemeActive = true; + } + } + } + if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\DWM"), KEY_READ)) { + DWORD useColorPrevalence = (DWORD)-1; + if (ERROR_SUCCESS == key.QueryDWORDValue(_T("ColorPrevalence"), useColorPrevalence)) { + if (1 == useColorPrevalence) { + bWindows10AccentColorsEnabled = true; + } + } + } + } + iModernSeekbarHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNSEEKBARHEIGHT, DEF_MODERN_SEEKBAR_HEIGHT); + if (iModernSeekbarHeight < MIN_MODERN_SEEKBAR_HEIGHT || iModernSeekbarHeight > MAX_MODERN_SEEKBAR_HEIGHT) { + iModernSeekbarHeight = DEF_MODERN_SEEKBAR_HEIGHT; + } + + eModernThemeMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNTHEMEMODE, static_cast(CMPCTheme::ModernThemeMode::WINDOWSDEFAULT))); + + iFullscreenDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_DELAY, MIN_FULLSCREEN_DELAY); + if (iFullscreenDelay < MIN_FULLSCREEN_DELAY || iFullscreenDelay > MAX_FULLSCREEN_DELAY) { + iFullscreenDelay = MIN_FULLSCREEN_DELAY; + } + + int tVertAlign = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VERTICALALIGNVIDEO, static_cast(verticalAlignVideoType::ALIGN_MIDDLE)); + if (tVertAlign < static_cast(verticalAlignVideoType::ALIGN_MIDDLE) || tVertAlign > static_cast(verticalAlignVideoType::ALIGN_BOTTOM)) { + tVertAlign = static_cast(verticalAlignVideoType::ALIGN_MIDDLE); + } + iVerticalAlignVideo = static_cast(tVertAlign); + + strSubtitlesProviders = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESPROVIDERS, _T("<|OpenSubtitles2|||1|0|><|podnapisi|||1|0|><|Napisy24|||0|0|>")); + strSubtitlePaths = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLEPATHS, DEFAULT_SUBTITLE_PATHS); + bSubtitleOverrideDefaultStyle = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_DEFAULT_STYLE, FALSE); + bSubtitleOverrideAllStyles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_ALL_STYLES, FALSE); + + fEnableAudioSwitcher = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOSWITCHER, TRUE); + fDownSampleTo441 = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DOWNSAMPLETO441, FALSE); + fCustomChannelMapping = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CUSTOMCHANNELMAPPING, FALSE); + + BOOL bResult = pApp->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_SPEAKERTOCHANNELMAPPING, &ptr, &len); + if (bResult && len == sizeof(pSpeakerToChannelMap)) { + memcpy(pSpeakerToChannelMap, ptr, sizeof(pSpeakerToChannelMap)); + } else { + ZeroMemory(pSpeakerToChannelMap, sizeof(pSpeakerToChannelMap)); + for (int j = 0; j < 18; j++) { + for (int i = 0; i <= j; i++) { + pSpeakerToChannelMap[j][i] = 1 << i; + } + } + + pSpeakerToChannelMap[0][0] = 1 << 0; + pSpeakerToChannelMap[0][1] = 1 << 0; + + pSpeakerToChannelMap[3][0] = 1 << 0; + pSpeakerToChannelMap[3][1] = 1 << 1; + pSpeakerToChannelMap[3][2] = 0; + pSpeakerToChannelMap[3][3] = 0; + pSpeakerToChannelMap[3][4] = 1 << 2; + pSpeakerToChannelMap[3][5] = 1 << 3; + + pSpeakerToChannelMap[4][0] = 1 << 0; + pSpeakerToChannelMap[4][1] = 1 << 1; + pSpeakerToChannelMap[4][2] = 1 << 2; + pSpeakerToChannelMap[4][3] = 0; + pSpeakerToChannelMap[4][4] = 1 << 3; + pSpeakerToChannelMap[4][5] = 1 << 4; + } + if (bResult) { + delete [] ptr; + } + + fAudioNormalize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZE, FALSE); + nAudioMaxNormFactor = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOMAXNORMFACTOR, 400); + fAudioNormalizeRecover = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZERECOVER, TRUE); + nAudioBoost = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, 0); + + nSpeakerChannels = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPEAKERCHANNELS, 2); + + // External filters + LoadExternalFilters(m_filters); + + m_pnspresets.RemoveAll(); + + for (int i = 0; i < (ID_PANNSCAN_PRESETS_END - ID_PANNSCAN_PRESETS_START); i++) { + CString str2; + str2.Format(_T("Preset%d"), i); + str2 = pApp->GetProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, str2); + if (str2.IsEmpty()) { + break; + } + m_pnspresets.Add(str2); + } + + if (m_pnspresets.IsEmpty()) { + const double _4p3 = 4.0 / 3.0; + const double _16p9 = 16.0 / 9.0; + const double _185p1 = 1.85 / 1.0; + const double _235p1 = 2.35 / 1.0; + UNREFERENCED_PARAMETER(_185p1); + + CString str2; + str2.Format(IDS_SCALE_16_9, 0.5, 0.5, /*_4p3 / _4p3 =*/ 1.0, _16p9 / _4p3); + m_pnspresets.Add(str2); + str2.Format(IDS_SCALE_WIDESCREEN, 0.5, 0.5, _16p9 / _4p3, _16p9 / _4p3); + m_pnspresets.Add(str2); + str2.Format(IDS_SCALE_ULTRAWIDE, 0.5, 0.5, _235p1 / _4p3, _235p1 / _4p3); + m_pnspresets.Add(str2); + } + + for (int i = 0; i < wmcmds.GetCount(); i++) { + CString str2; + str2.Format(_T("CommandMod%d"), i); + str2 = pApp->GetProfileString(IDS_R_COMMANDS, str2); + if (str2.IsEmpty()) { + break; + } + + wmcmd tmp; + int n; + int fVirt = 0; + BYTE ignore; + if (5 > (n = _stscanf_s(str2, _T("%hu %x %hx %S %d %hhu %u %hhu %hhu %hhu"), + &tmp.cmd, &fVirt, &tmp.key, tmp.rmcmd.GetBuffer(128), 128, + &tmp.rmrepcnt, &tmp.mouse, &tmp.appcmd, &ignore, + &tmp.mouseVirt, &ignore))) { + break; + } + tmp.rmcmd.ReleaseBuffer(); + if (n >= 2) { + tmp.fVirt = (BYTE)fVirt; + } + if (POSITION pos = wmcmds.Find(tmp)) { + wmcmd& wc = wmcmds.GetAt(pos); + wc.cmd = tmp.cmd; + wc.fVirt = tmp.fVirt; + wc.key = tmp.key; + if (n >= 6) { + wc.mouse = tmp.mouse; + } + if (n >= 7) { + wc.appcmd = tmp.appcmd; + } + if (n >= 9) { + wc.mouseVirt = tmp.mouseVirt; + } + wc.rmcmd = tmp.rmcmd.Trim('\"'); + wc.rmrepcnt = tmp.rmrepcnt; + } + } + + CAtlArray pAccel; + pAccel.SetCount(ACCEL_LIST_SIZE); + int accel_count = 0; + POSITION pos = wmcmds.GetHeadPosition(); + for (int i = 0; pos; i++) { + ACCEL x = wmcmds.GetNext(pos); + if (x.key > 0) { + pAccel[accel_count] = x; + accel_count++; + } + } + hAccel = CreateAcceleratorTable(pAccel.GetData(), accel_count); + + strWinLircAddr = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WINLIRCADDR, _T("127.0.0.1:8765")); + fWinLirc = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WINLIRC, FALSE); + strUIceAddr = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_UICEADDR, _T("127.0.0.1:1234")); + fUIce = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UICE, FALSE); + fGlobalMedia = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_GLOBALMEDIA, TRUE); + + nJumpDistS = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTS, DEFAULT_JUMPDISTANCE_1); + nJumpDistM = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTM, DEFAULT_JUMPDISTANCE_2); + nJumpDistL = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTL, DEFAULT_JUMPDISTANCE_3); + fLimitWindowProportions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LIMITWINDOWPROPORTIONS, FALSE); + + m_Formats.UpdateData(false); + + // Internal filters + for (int f = 0; f < SRC_LAST; f++) { + SrcFilters[f] = !!pApp->GetProfileInt(IDS_R_INTERNAL_FILTERS, SrcFiltersKeys[f].name, SrcFiltersKeys[f].bDefault); + } + for (int f = 0; f < TRA_LAST; f++) { + TraFilters[f] = !!pApp->GetProfileInt(IDS_R_INTERNAL_FILTERS, TraFiltersKeys[f].name, TraFiltersKeys[f].bDefault); + } + + strLogoFileName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_LOGOFILE); + nLogoId = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOID, -1); + fLogoExternal = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOEXT, FALSE); + fLogoColorProfileEnabled = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOCOLORPROFILE, FALSE); + + fHideCDROMsSubMenu = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECDROMSSUBMENU, FALSE); + + dwPriority = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITY, NORMAL_PRIORITY_CLASS); + ::SetPriorityClass(::GetCurrentProcess(), dwPriority); + fLaunchfullscreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LAUNCHFULLSCREEN, FALSE); + + fEnableWebServer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWEBSERVER, FALSE); + nWebServerPort = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPORT, 13579); + fWebServerUseCompression = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERUSECOMPRESSION, TRUE); + fWebServerLocalhostOnly = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERLOCALHOSTONLY, FALSE); + bWebUIEnablePreview = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBUI_ENABLE_PREVIEW, FALSE); + fWebServerPrintDebugInfo = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPRINTDEBUGINFO, FALSE); + strWebRoot = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBROOT, _T("*./webroot")); + strWebDefIndex = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBDEFINDEX, _T("index.html;index.php")); + strWebServerCGI = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBSERVERCGI); + + CString MyPictures; + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), KEY_READ)) { + ULONG lenValue = 1024; + if (ERROR_SUCCESS == key.QueryStringValue(_T("My Pictures"), MyPictures.GetBuffer((int)lenValue), &lenValue)) { + MyPictures.ReleaseBufferSetLength((int)lenValue); + } else { + MyPictures.Empty(); + } + } + strSnapshotPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTPATH, MyPictures); + strSnapshotExt = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTEXT, _T(".jpg")); + bSnapShotSubtitles = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTSUBTITLES, TRUE); + bSnapShotKeepVideoExtension = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTKEEPVIDEOEXTENSION, TRUE); + + iThumbRows = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBROWS, 4); + iThumbCols = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBCOLS, 4); + iThumbWidth = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBWIDTH, 1024); + + bSubSaveExternalStyleFile = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBSAVEEXTERNALSTYLEFILE, FALSE); + nLastUsedPage = WORD(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTUSEDPAGE, 0)); + + { + // Load the list of extra (non-default) shader files + m_ShadersExtraList = ShaderList(pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_EXTRA)); + // Load shader selection + m_Shaders.SetCurrentPreset(ShaderPreset(pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_PRERESIZE), + pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_POSTRESIZE))); + // Load shader presets + ShaderSelection::ShaderPresetMap presets; + for (int i = 0;; i++) { + CString iStr; + iStr.Format(_T("%d"), i); + CString name = pApp->GetProfileString(IDS_R_SHADER_PRESETS, iStr); + if (name.IsEmpty()) { + break; + } + presets.emplace(name, ShaderPreset(pApp->GetProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_PRERESIZE + iStr), + pApp->GetProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_POSTRESIZE + iStr))); + } + m_Shaders.SetPresets(presets); + // Load last shader preset name + CString name = pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_LASTPRESET); + if (!name.IsEmpty()) { + m_Shaders.SetCurrentPreset(name); + } + } + + fD3DFullscreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_D3DFULLSCREEN, FALSE); + + iBrightness = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_BRIGHTNESS, 0); + iContrast = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_CONTRAST, 0); + iHue = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_HUE, 0); + iSaturation = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_SATURATION, 0); + + fShowOSD = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOWOSD, TRUE); + fShowCurrentTimeInOSD = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CURRENT_TIME_OSD, FALSE); + + nOSDTransparency = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_TRANSPARENCY, 64); + nOSDBorder = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_BORDER, 1); + + fEnableEDLEditor = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEEDLEDITOR, FALSE); + bFastSeek = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK, TRUE); + eFastSeekMethod = static_cast( + pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK_METHOD, FASTSEEK_NEAREST_KEYFRAME)); + fShowChapters = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CHAPTERS, TRUE); + + + fLCDSupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, FALSE); + + fSeekPreview = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW, FALSE); + iSeekPreviewSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW_SIZE, 15); + if (iSeekPreviewSize < 5) iSeekPreviewSize = 5; + if (iSeekPreviewSize > 40) iSeekPreviewSize = 40; + + // Save analog capture settings + iDefaultCaptureDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, 0); + strAnalogVideo = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, _T("dummy")); + strAnalogAudio = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, _T("dummy")); + iAnalogCountry = pApp->GetProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, 1); + + //strBDANetworkProvider = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER); + strBDATuner = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER); + strBDAReceiver = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER); + //sBDAStandard = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD); + iBDAScanFreqStart = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, 474000); + iBDAScanFreqEnd = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, 858000); + iBDABandwidth = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, 8); + iBDASymbolRate = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SYMBOLRATE, 0); + fBDAUseOffset = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_USE_OFFSET, FALSE); + iBDAOffset = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_OFFSET, 166); + fBDAIgnoreEncryptedChannels = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_IGNORE_ENCRYPTED_CHANNELS, FALSE); + nDVBLastChannel = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, INT_ERROR); + nDVBRebuildFilterGraph = (DVB_RebuildFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, DVB_STOP_FG_ALWAYS); + nDVBStopFilterGraph = (DVB_StopFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, DVB_STOP_FG_ALWAYS); + + for (int iChannel = 0; ; iChannel++) { + CString strTemp; + strTemp.Format(_T("%d"), iChannel); + CString strChannel = pApp->GetProfileString(IDS_R_DVB, strTemp); + if (strChannel.IsEmpty()) { + break; + } + try { + m_DVBChannels.emplace_back(strChannel); + } catch (CException* e) { + // The tokenisation can fail if the input string was invalid + TRACE(_T("Failed to parse a DVB channel from string \"%s\""), strChannel.GetString()); + ASSERT(FALSE); + e->Delete(); + } + } + + // playback positions for last played files + fRememberFilePos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS, FALSE); + iRememberPosForLongerThan = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSLONGER, 5); + bRememberPosForAudioFiles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSAUDIO, TRUE); + if (iRememberPosForLongerThan < 0) { + iRememberPosForLongerThan = 5; + } + bRememberExternalPlaylistPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_PLAYLIST, TRUE); + bRememberTrackSelection = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_TRACK_SELECTION, TRUE); + + // playback positions for last played DVDs + fRememberDVDPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DVDPOS, FALSE); + + bToggleShader = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADER, TRUE); + bToggleShaderScreenSpace = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADERSSCREENSPACE, TRUE); + + fRemainingTime = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMAINING_TIME, FALSE); + bHighPrecisionTimer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIGH_PRECISION_TIMER, FALSE); + bTimerShowPercentage = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIMER_SHOW_PERCENTAGE, FALSE); + + nUpdaterAutoCheck = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_AUTO_CHECK, AUTOUPDATE_UNKNOWN); + nUpdaterDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_DELAY, 7); + if (nUpdaterDelay < 1) { + nUpdaterDelay = 1; + } + + bNotifySkype = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_NOTIFY_SKYPE, FALSE); + + nJpegQuality = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JPEG_QUALITY, 90); + if (nJpegQuality < 20 || nJpegQuality > 100) { + nJpegQuality = 90; + } + + bEnableCoverArt = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART, TRUE); + nCoverArtSizeLimit = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART_SIZE_LIMIT, 600); + + bEnableLogging = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGGING, FALSE); + bUseLegacyToolbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_LEGACY_TOOLBAR, FALSE); + + eSubtitleRenderer = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, static_cast(SubtitleRenderer::INTERNAL))); + if (eSubtitleRenderer == SubtitleRenderer::RESERVED) { + eSubtitleRenderer = SubtitleRenderer::INTERNAL; + bRenderSSAUsingLibass = true; + } + + nDefaultToolbarSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTTOOLBARSIZE, 24); + + bSaveImagePosition = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_POSITION, TRUE); + bSaveImageCurrentTime = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_CURRENTTIME, FALSE); + + bAllowInaccurateFastseek = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_INACCURATE_FASTSEEK, TRUE); + bLoopFolderOnPlayNextFile = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP_FOLDER_NEXT_FILE, FALSE); + + bLockNoPause = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOCK_NOPAUSE, FALSE); + bPreventDisplaySleep = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_DISPLAY_SLEEP, TRUE); + bUseSMTC = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_SMTC, FALSE); + iReloadAfterLongPause = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RELOAD_AFTER_LONG_PAUSE, 0); + bOpenRecPanelWhenOpeningDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OPEN_REC_PANEL_WHEN_OPENING_DEVICE, TRUE); + + sanear->SetOutputDevice(pApp->GetProfileString(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_ID), + pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_EXCLUSIVE, FALSE), + pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_BUFFER, + SaneAudioRenderer::ISettings::OUTPUT_DEVICE_BUFFER_DEFAULT_MS)); + + sanear->SetCrossfeedEnabled(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_ENABLED, FALSE)); + + sanear->SetCrossfeedSettings(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ, + SaneAudioRenderer::ISettings::CROSSFEED_CUTOFF_FREQ_CMOY), + pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, + SaneAudioRenderer::ISettings::CROSSFEED_LEVEL_CMOY)); + + sanear->SetIgnoreSystemChannelMixer(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_IGNORE_SYSTEM_MIXER, TRUE)); + + bUseYDL = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_YDL, TRUE); + iYDLMaxHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, 1440); + iYDLVideoFormat = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_VIDEO_FORMAT, 0); + iYDLAudioFormat = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_FORMAT, 0); + bYDLAudioOnly = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, FALSE); + sYDLExePath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_EXEPATH, _T("")); + sYDLCommandLine = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_COMMAND_LINE, _T("")); + + bEnableCrashReporter = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLE_CRASH_REPORTER, TRUE); + + nStreamPosPollerInterval = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_REFRESH_INTERVAL, 100); + bShowLangInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_LANG_STATUSBAR, FALSE); + bShowFPSInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_FPS_STATUSBAR, FALSE); + bShowABMarksInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_ABMARKS_STATUSBAR, FALSE); + bShowVideoInfoInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_VIDEOINFO_STATUSBAR, TRUE); + bShowAudioFormatInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_AUDIOFORMAT_STATUSBAR, TRUE); + + bAddLangCodeWhenSaveSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ADD_LANGCODE_WHEN_SAVE_SUBTITLES, FALSE); + bUseTitleInRecentFileList = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TITLE_IN_RECENT_FILE_LIST, TRUE); + sYDLSubsPreference = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_SUBS_PREFERENCE, _T("")); + bUseAutomaticCaptions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_AUTOMATIC_CAPTIONS, FALSE); + + lastQuickOpenPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_QUICKOPEN_PATH, L""); + lastFileSaveCopyPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_FILESAVECOPY_PATH, L""); + lastFileOpenDirPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_FILEOPENDIR_PATH, L""); + externalPlayListPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_EXTERNAL_PLAYLIST_PATH, L""); + + iRedirectOpenToAppendThreshold = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REDIRECT_OPEN_TO_APPEND_THRESHOLD, 1000); + bFullscreenSeparateControls = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_SEPARATE_CONTROLS, TRUE); + bAlwaysUseShortMenu = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALWAYS_USE_SHORT_MENU, FALSE); + iStillVideoDuration = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_STILL_VIDEO_DURATION, 10); + iMouseLeftUpDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MOUSE_LEFTUP_DELAY, 0); + + if (bMPCTheme) { + CMPCTheme::InitializeColors(eModernThemeMode); + } + // GUI theme can be used now + static_cast(AfxGetApp())->m_bThemeLoaded = bMPCTheme; + + if (fLaunchfullscreen && slFiles.GetCount() > 0) { + nCLSwitches |= CLSW_FULLSCREEN; + } + + bInitialized = true; +} + +bool CAppSettings::GetAllowMultiInst() const +{ + return !!AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, FALSE); +} + +void CAppSettings::UpdateRenderersData(bool fSave) +{ + CWinApp* pApp = AfxGetApp(); + CRenderersSettings& r = m_RenderersSettings; + CRenderersSettings::CAdvRendererSettings& ars = r.m_AdvRendSets; + + if (fSave) { + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_APSURACEFUSAGE, r.iAPSurfaceUsage); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DX9_RESIZER, r.iDX9Resizer); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VMR9MIXERMODE, r.fVMR9MixerMode); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRAlternateVSync"), ars.bVMR9AlterativeVSync); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSyncOffset"), ars.iVMR9VSyncOffset); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSyncAccurate2"), ars.bVMR9VSyncAccurate); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFullscreenGUISupport"), ars.bVMR9FullscreenGUISupport); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSync"), ars.bVMR9VSync); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRDisableDesktopComposition"), ars.bVMRDisableDesktopComposition); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFullFloatingPointProcessing2"), ars.bVMR9FullFloatingPointProcessing); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRHalfFloatingPointProcessing"), ars.bVMR9HalfFloatingPointProcessing); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementEnable"), ars.bVMR9ColorManagementEnable); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementInput"), ars.iVMR9ColorManagementInput); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementAmbientLight"), ars.iVMR9ColorManagementAmbientLight); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementIntent"), ars.iVMR9ColorManagementIntent); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVROutputRange"), ars.iEVROutputRange); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVRHighColorRes"), ars.bEVRHighColorResolution); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVRForceInputHighColorRes"), ars.bEVRForceInputHighColorResolution); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVREnableFrameTimeCorrection"), ars.bEVREnableFrameTimeCorrection); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUBeforeVSync"), ars.bVMRFlushGPUBeforeVSync); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUAfterPresent"), ars.bVMRFlushGPUAfterPresent); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUWait"), ars.bVMRFlushGPUWait); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("DesktopSizeBackBuffer"), ars.bDesktopSizeBackBuffer); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeClock"), ars.bSynchronizeVideo); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeDisplay"), ars.bSynchronizeDisplay); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeNearest"), ars.bSynchronizeNearest); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("LineDelta"), ars.iLineDelta); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("ColumnDelta"), ars.iColumnDelta); + + pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("CycleDelta"), (LPBYTE) & (ars.fCycleDelta), sizeof(ars.fCycleDelta)); + pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("TargetSyncOffset"), (LPBYTE) & (ars.fTargetSyncOffset), sizeof(ars.fTargetSyncOffset)); + pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("ControlLimit"), (LPBYTE) & (ars.fControlLimit), sizeof(ars.fControlLimit)); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CACHESHADERS, ars.bCacheShaders); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("ResetDevice"), r.fResetDevice); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCSIZE, r.subPicQueueSettings.nSize); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESX, r.subPicQueueSettings.nMaxResX); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESY, r.subPicQueueSettings.nMaxResY); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, r.subPicQueueSettings.bDisableSubtitleAnimation); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDER_AT_WHEN_ANIM_DISABLED, r.subPicQueueSettings.nRenderAtWhenAnimationIsDisabled); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_ANIMATION_RATE, r.subPicQueueSettings.nAnimationRate); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_DROPPING_SUBPIC, r.subPicQueueSettings.bAllowDroppingSubpic); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_EVR_BUFFERS, r.iEvrBuffers); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_D3D9RENDERDEVICE, r.D3D9RenderDevice); + } else { + r.iAPSurfaceUsage = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_APSURACEFUSAGE, VIDRNDT_AP_TEXTURE3D); + r.iDX9Resizer = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DX9_RESIZER, 1); + r.fVMR9MixerMode = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VMR9MIXERMODE, TRUE); + + CRenderersSettings::CAdvRendererSettings DefaultSettings; + ars.bVMR9AlterativeVSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRAlternateVSync"), DefaultSettings.bVMR9AlterativeVSync); + ars.iVMR9VSyncOffset = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSyncOffset"), DefaultSettings.iVMR9VSyncOffset); + ars.bVMR9VSyncAccurate = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSyncAccurate2"), DefaultSettings.bVMR9VSyncAccurate); + ars.bVMR9FullscreenGUISupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFullscreenGUISupport"), DefaultSettings.bVMR9FullscreenGUISupport); + ars.bEVRHighColorResolution = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVRHighColorRes"), DefaultSettings.bEVRHighColorResolution); + ars.bEVRForceInputHighColorResolution = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVRForceInputHighColorRes"), DefaultSettings.bEVRForceInputHighColorResolution); + ars.bEVREnableFrameTimeCorrection = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVREnableFrameTimeCorrection"), DefaultSettings.bEVREnableFrameTimeCorrection); + ars.bVMR9VSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSync"), DefaultSettings.bVMR9VSync); + ars.bVMRDisableDesktopComposition = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRDisableDesktopComposition"), DefaultSettings.bVMRDisableDesktopComposition); + ars.bVMR9FullFloatingPointProcessing = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFullFloatingPointProcessing2"), DefaultSettings.bVMR9FullFloatingPointProcessing); + ars.bVMR9HalfFloatingPointProcessing = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRHalfFloatingPointProcessing"), DefaultSettings.bVMR9HalfFloatingPointProcessing); + + ars.bVMR9ColorManagementEnable = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementEnable"), DefaultSettings.bVMR9ColorManagementEnable); + ars.iVMR9ColorManagementInput = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementInput"), DefaultSettings.iVMR9ColorManagementInput); + ars.iVMR9ColorManagementAmbientLight = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementAmbientLight"), DefaultSettings.iVMR9ColorManagementAmbientLight); + ars.iVMR9ColorManagementIntent = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementIntent"), DefaultSettings.iVMR9ColorManagementIntent); + + ars.iEVROutputRange = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVROutputRange"), DefaultSettings.iEVROutputRange); + + ars.bVMRFlushGPUBeforeVSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUBeforeVSync"), DefaultSettings.bVMRFlushGPUBeforeVSync); + ars.bVMRFlushGPUAfterPresent = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUAfterPresent"), DefaultSettings.bVMRFlushGPUAfterPresent); + ars.bVMRFlushGPUWait = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUWait"), DefaultSettings.bVMRFlushGPUWait); + + ars.bDesktopSizeBackBuffer = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("DesktopSizeBackBuffer"), DefaultSettings.bDesktopSizeBackBuffer); + + ars.bSynchronizeVideo = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeClock"), DefaultSettings.bSynchronizeVideo); + ars.bSynchronizeDisplay = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeDisplay"), DefaultSettings.bSynchronizeDisplay); + ars.bSynchronizeNearest = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeNearest"), DefaultSettings.bSynchronizeNearest); + ars.iLineDelta = pApp->GetProfileInt(IDS_R_SETTINGS, _T("LineDelta"), DefaultSettings.iLineDelta); + ars.iColumnDelta = pApp->GetProfileInt(IDS_R_SETTINGS, _T("ColumnDelta"), DefaultSettings.iColumnDelta); + + double* dPtr; + UINT dSize; + if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("CycleDelta"), (LPBYTE*)&dPtr, &dSize)) { + ars.fCycleDelta = *dPtr; + delete [] dPtr; + } + + if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("TargetSyncOffset"), (LPBYTE*)&dPtr, &dSize)) { + ars.fTargetSyncOffset = *dPtr; + delete [] dPtr; + } + if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("ControlLimit"), (LPBYTE*)&dPtr, &dSize)) { + ars.fControlLimit = *dPtr; + delete [] dPtr; + } + + ars.bCacheShaders = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CACHESHADERS, DefaultSettings.bCacheShaders); + if (AfxGetMyApp()->GetAppSavePath(ars.sShaderCachePath)) { + ars.sShaderCachePath = PathUtils::CombinePaths(ars.sShaderCachePath, IDS_R_SHADER_CACHE); + } + + r.fResetDevice = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("ResetDevice"), FALSE); + + r.subPicQueueSettings.nSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCSIZE, 0); + r.subPicQueueSettings.nMaxResX = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESX, 2560); + r.subPicQueueSettings.nMaxResY = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESY, 1440); + if (r.subPicQueueSettings.nMaxResX < 600 || r.subPicQueueSettings.nMaxResY < 480) { + r.subPicQueueSettings.nMaxResX = 2560; + r.subPicQueueSettings.nMaxResY = 1440; + } + r.subPicQueueSettings.bDisableSubtitleAnimation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, FALSE); + r.subPicQueueSettings.nRenderAtWhenAnimationIsDisabled = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDER_AT_WHEN_ANIM_DISABLED, 50); + r.subPicQueueSettings.nAnimationRate = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_ANIMATION_RATE, 100); + r.subPicQueueSettings.bAllowDroppingSubpic = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_DROPPING_SUBPIC, TRUE); + + r.subPicVerticalShift = 0; + r.fontScaleOverride = 1.0; + + r.iEvrBuffers = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_EVR_BUFFERS, 5); + r.D3D9RenderDevice = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_D3D9RENDERDEVICE); + } +} + +__int64 CAppSettings::ConvertTimeToMSec(const CString& time) const +{ + __int64 Sec = 0; + __int64 mSec = 0; + __int64 mult = 1; + + int pos = time.GetLength() - 1; + if (pos < 3) { + return 0; + } + + while (pos >= 0) { + TCHAR ch = time[pos]; + if (ch == '.') { + mSec = Sec * 1000 / mult; + Sec = 0; + mult = 1; + } else if (ch == ':') { + mult = mult * 6 / 10; + } else if (ch >= '0' && ch <= '9') { + Sec += (ch - '0') * mult; + mult *= 10; + } else { + mSec = Sec = 0; + break; + } + pos--; + } + return Sec * 1000 + mSec; +} + +void CAppSettings::ExtractDVDStartPos(CString& strParam) +{ + int i = 0, j = 0; + for (CString token = strParam.Tokenize(_T("#"), i); + j < 3 && !token.IsEmpty(); + token = strParam.Tokenize(_T("#"), i), j++) { + switch (j) { + case 0: + lDVDTitle = token.IsEmpty() ? 0 : (ULONG)_wtol(token); + break; + case 1: + if (token.Find(':') > 0) { + UINT h = 0, m = 0, s = 0, f = 0; + int nRead = _stscanf_s(token, _T("%02u:%02u:%02u.%03u"), &h, &m, &s, &f); + if (nRead >= 3) { + DVDPosition.bHours = (BYTE)h; + DVDPosition.bMinutes = (BYTE)m; + DVDPosition.bSeconds = (BYTE)s; + DVDPosition.bFrames = (BYTE)f; + } + } else { + lDVDChapter = token.IsEmpty() ? 0 : (ULONG)_wtol(token); + } + break; + } + } +} + +CString CAppSettings::ParseFileName(CString const& param) +{ + if (param.Find(_T(":")) < 0 && param.Left(2) != L"\\\\") { + // Try to transform relative pathname into full pathname + CString fullPathName; + DWORD dwLen = GetFullPathName(param, 2048, fullPathName.GetBuffer(2048), nullptr); + if (dwLen > 0 && dwLen < 2048) { + fullPathName.ReleaseBuffer(dwLen); + + if (!fullPathName.IsEmpty() && PathUtils::Exists(fullPathName)) { + return fullPathName; + } + } + } else { + CString fullPathName = param; + ExtendMaxPathLengthIfNeeded(fullPathName); + return fullPathName; + } + + return param; +} + +void CAppSettings::ParseCommandLine(CAtlList& cmdln) +{ + UINT64 existingAfterPlaybackCL = nCLSwitches & CLSW_AFTERPLAYBACK_MASK; + nCLSwitches = 0; + slFiles.RemoveAll(); + slDubs.RemoveAll(); + slSubs.RemoveAll(); + slFilters.RemoveAll(); + rtStart = 0; + rtShift = 0; + lDVDTitle = 0; + lDVDChapter = 0; + ZeroMemory(&DVDPosition, sizeof(DVDPosition)); + iAdminOption = 0; + sizeFixedWindow.SetSize(0, 0); + fixedWindowPosition = NO_FIXED_POSITION; + iMonitor = 0; + strPnSPreset.Empty(); + + POSITION pos = cmdln.GetHeadPosition(); + while (pos) { + const CString& param = cmdln.GetNext(pos); + if (param.IsEmpty()) { + continue; + } + + if ((param[0] == '-' || param[0] == '/') && param.GetLength() > 1) { + CString sw = param.Mid(1).MakeLower(); + if (sw == _T("open")) { + nCLSwitches |= CLSW_OPEN; + } else if (sw == _T("play")) { + nCLSwitches |= CLSW_PLAY; + } else if (sw == _T("fullscreen")) { + nCLSwitches |= CLSW_FULLSCREEN; + } else if (sw == _T("minimized")) { + nCLSwitches |= CLSW_MINIMIZED; + } else if (sw == _T("new")) { + nCLSwitches |= CLSW_NEW; + } else if (sw == _T("help") || sw == _T("h") || sw == _T("?")) { + nCLSwitches |= CLSW_HELP; + } else if (sw == _T("dub") && pos) { + slDubs.AddTail(ParseFileName(cmdln.GetNext(pos))); + } else if (sw == _T("dubdelay") && pos) { + CString strFile = ParseFileName(cmdln.GetNext(pos)); + int nPos = strFile.Find(_T("DELAY")); + if (nPos != -1) { + rtShift = 10000i64 * _tstol(strFile.Mid(nPos + 6)); + } + slDubs.AddTail(strFile); + } else if (sw == _T("sub") && pos) { + slSubs.AddTail(ParseFileName(cmdln.GetNext(pos))); + } else if (sw == _T("filter") && pos) { + slFilters.AddTail(cmdln.GetNext(pos)); + } else if (sw == _T("dvd")) { + nCLSwitches |= CLSW_DVD; + } else if (sw == _T("dvdpos") && pos) { + ExtractDVDStartPos(cmdln.GetNext(pos)); + } else if (sw == _T("cd")) { + nCLSwitches |= CLSW_CD; + } else if (sw == _T("device")) { + nCLSwitches |= CLSW_DEVICE; + } else if (sw == _T("add")) { + nCLSwitches |= CLSW_ADD; + } else if (sw == _T("randomize")) { + nCLSwitches |= CLSW_RANDOMIZE; + } else if (sw == _T("volume") && pos) { + int setVolumeVal = _ttoi(cmdln.GetNext(pos)); + if (setVolumeVal >= 0 && setVolumeVal <= 100) { + nCmdVolume = setVolumeVal; + nCLSwitches |= CLSW_VOLUME; + } else { + nCLSwitches |= CLSW_UNRECOGNIZEDSWITCH; + } + } else if (sw == _T("regvid")) { + nCLSwitches |= CLSW_REGEXTVID; + } else if (sw == _T("regaud")) { + nCLSwitches |= CLSW_REGEXTAUD; + } else if (sw == _T("regpl")) { + nCLSwitches |= CLSW_REGEXTPL; + } else if (sw == _T("regall")) { + nCLSwitches |= (CLSW_REGEXTVID | CLSW_REGEXTAUD | CLSW_REGEXTPL); + } else if (sw == _T("unregall")) { + nCLSwitches |= CLSW_UNREGEXT; + } else if (sw == _T("unregvid")) { + nCLSwitches |= CLSW_UNREGEXT; /* keep for compatibility with old versions */ + } else if (sw == _T("unregaud")) { + nCLSwitches |= CLSW_UNREGEXT; /* keep for compatibility with old versions */ + } else if (sw == _T("iconsassoc")) { + nCLSwitches |= CLSW_ICONSASSOC; + } else if (sw == _T("start") && pos) { + rtStart = 10000i64 * _tcstol(cmdln.GetNext(pos), nullptr, 10); + nCLSwitches |= CLSW_STARTVALID; + } else if (sw == _T("startpos") && pos) { + rtStart = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); + nCLSwitches |= CLSW_STARTVALID; + } else if (sw == _T("nofocus")) { + nCLSwitches |= CLSW_NOFOCUS; + } else if (sw == _T("close")) { + nCLSwitches |= CLSW_CLOSE; + } else if (sw == _T("standby")) { + nCLSwitches |= CLSW_STANDBY; + } else if (sw == _T("hibernate")) { + nCLSwitches |= CLSW_HIBERNATE; + } else if (sw == _T("shutdown")) { + nCLSwitches |= CLSW_SHUTDOWN; + } else if (sw == _T("logoff")) { + nCLSwitches |= CLSW_LOGOFF; + } else if (sw == _T("lock")) { + nCLSwitches |= CLSW_LOCK; + } else if (sw == _T("d3dfs")) { + nCLSwitches |= CLSW_D3DFULLSCREEN; + } else if (sw == _T("adminoption") && pos) { + nCLSwitches |= CLSW_ADMINOPTION; + iAdminOption = _ttoi(cmdln.GetNext(pos)); + } else if (sw == _T("slave") && pos) { + nCLSwitches |= CLSW_SLAVE; + hMasterWnd = (HWND)IntToPtr(_ttoi(cmdln.GetNext(pos))); + } else if (sw == _T("fixedsize") && pos) { + CAtlList sl; + // Optional arguments for the main window's position + Explode(cmdln.GetNext(pos), sl, ',', 4); + if (sl.GetCount() == 4) { + fixedWindowPosition.SetPoint(_ttol(sl.GetAt(sl.FindIndex(2))), _ttol(sl.GetAt(sl.FindIndex(3))) ); + } + if (sl.GetCount() >= 2) { + sizeFixedWindow.SetSize(_ttol(sl.GetAt(sl.FindIndex(0))), _ttol(sl.GetAt(sl.FindIndex(1))) ); + if (sizeFixedWindow.cx > 0 && sizeFixedWindow.cy > 0) { + nCLSwitches |= CLSW_FIXEDSIZE; + } + } + } else if (sw == _T("viewpreset") && pos) { + int viewPreset = _ttoi(cmdln.GetNext(pos)); + switch (viewPreset) { + case 1: + nCLSwitches |= CLSW_PRESET1; + break; + case 2: + nCLSwitches |= CLSW_PRESET2; + break; + case 3: + nCLSwitches |= CLSW_PRESET3; + break; + default: + nCLSwitches |= CLSW_UNRECOGNIZEDSWITCH; + break; + } + } else if (sw == _T("monitor") && pos) { + iMonitor = _tcstol(cmdln.GetNext(pos), nullptr, 10); + nCLSwitches |= CLSW_MONITOR; + } else if (sw == _T("pns") && pos) { + strPnSPreset = cmdln.GetNext(pos); + } else if (sw == _T("webport") && pos) { + int tmpport = _tcstol(cmdln.GetNext(pos), nullptr, 10); + if (tmpport >= 0 && tmpport <= 65535) { + nCmdlnWebServerPort = tmpport; + } + } else if (sw == _T("debug")) { + fShowDebugInfo = true; + } else if (sw == _T("nocrashreporter")) { +#if USE_DRDUMP_CRASH_REPORTER + if (CrashReporter::IsEnabled()) { + CrashReporter::Disable(); + MPCExceptionHandler::Enable(); + } +#endif + } else if (sw == _T("audiorenderer") && pos) { + SetAudioRenderer(_ttoi(cmdln.GetNext(pos))); + } else if (sw == _T("shaderpreset") && pos) { + m_Shaders.SetCurrentPreset(cmdln.GetNext(pos)); + } else if (sw == _T("reset")) { + nCLSwitches |= CLSW_RESET; + } else if (sw == _T("mute")) { + nCLSwitches |= CLSW_MUTE; + } else if (sw == _T("monitoroff")) { + nCLSwitches |= CLSW_MONITOROFF; + } else if (sw == _T("playnext")) { + nCLSwitches |= CLSW_PLAYNEXT; + } else if (sw == _T("hwgpu") && pos) { + iLAVGPUDevice = _tcstol(cmdln.GetNext(pos), nullptr, 10); + } else if (sw == _T("configlavsplitter")) { + nCLSwitches |= CLSW_CONFIGLAVSPLITTER; + } else if (sw == _T("configlavaudio")) { + nCLSwitches |= CLSW_CONFIGLAVAUDIO; + } else if (sw == _T("configlavvideo")) { + nCLSwitches |= CLSW_CONFIGLAVVIDEO; + } else if (sw == L"ab_start" && pos) { + abRepeat.positionA = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); + } else if (sw == L"ab_end" && pos) { + abRepeat.positionB = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); + } else if (sw == L"thumbnails") { + nCLSwitches |= CLSW_THUMBNAILS | CLSW_NEW; + } else { + nCLSwitches |= CLSW_HELP | CLSW_UNRECOGNIZEDSWITCH; + } + } else { + if (param == _T("-")) { // Special case: standard input + slFiles.AddTail(_T("pipe://stdin")); + } else { + const_cast(param) = ParseFileName(param); + slFiles.AddTail(param); + } + } + } + + if (abRepeat.positionA && abRepeat.positionB && abRepeat.positionA >= abRepeat.positionB) { + abRepeat.positionA = 0; + abRepeat.positionB = 0; + } + if (abRepeat.positionA > rtStart || (abRepeat.positionB && abRepeat.positionB < rtStart)) { + rtStart = abRepeat.positionA; + nCLSwitches |= CLSW_STARTVALID; + } + + if (0 == (nCLSwitches & CLSW_AFTERPLAYBACK_MASK)) { //no changes to playback mask, so let's preserve existing + nCLSwitches |= existingAfterPlaybackCL; + } +} + +void CAppSettings::GetFav(favtype ft, CAtlList& sl) const +{ + sl.RemoveAll(); + + CString root; + + switch (ft) { + case FAV_FILE: + root = IDS_R_FAVFILES; + break; + case FAV_DVD: + root = IDS_R_FAVDVDS; + break; + case FAV_DEVICE: + root = IDS_R_FAVDEVICES; + break; + default: + return; + } + + for (int i = 0; ; i++) { + CString s; + s.Format(_T("Name%d"), i); + s = AfxGetApp()->GetProfileString(root, s); + if (s.IsEmpty()) { + break; + } + sl.AddTail(s); + } +} + +void CAppSettings::SetFav(favtype ft, CAtlList& sl) +{ + CString root; + + switch (ft) { + case FAV_FILE: + root = IDS_R_FAVFILES; + break; + case FAV_DVD: + root = IDS_R_FAVDVDS; + break; + case FAV_DEVICE: + root = IDS_R_FAVDEVICES; + break; + default: + return; + } + + AfxGetApp()->WriteProfileString(root, nullptr, nullptr); + + int i = 0; + POSITION pos = sl.GetHeadPosition(); + while (pos) { + CString s; + s.Format(_T("Name%d"), i++); + AfxGetApp()->WriteProfileString(root, s, sl.GetNext(pos)); + } +} + +void CAppSettings::AddFav(favtype ft, CString s) +{ + CAtlList sl; + GetFav(ft, sl); + if (sl.Find(s)) { + return; + } + sl.AddTail(s); + SetFav(ft, sl); +} + +CBDAChannel* CAppSettings::FindChannelByPref(int nPrefNumber) +{ + auto it = find_if(m_DVBChannels.begin(), m_DVBChannels.end(), [&](CBDAChannel const & channel) { + return channel.GetPrefNumber() == nPrefNumber; + }); + + return it != m_DVBChannels.end() ? &(*it) : nullptr; +} + +// Settings::CRecentFileAndURLList +CAppSettings::CRecentFileAndURLList::CRecentFileAndURLList(UINT nStart, LPCTSTR lpszSection, + LPCTSTR lpszEntryFormat, int nSize, + int nMaxDispLen) + : CRecentFileList(nStart, lpszSection, lpszEntryFormat, nSize, nMaxDispLen) +{ +} + +extern BOOL AFXAPI AfxComparePath(LPCTSTR lpszPath1, LPCTSTR lpszPath2); + +void CAppSettings::CRecentFileAndURLList::Add(LPCTSTR lpszPathName) +{ + ASSERT(m_arrNames != nullptr); + ASSERT(lpszPathName != nullptr); + ASSERT(AfxIsValidString(lpszPathName)); + + if (m_nSize <= 0 || CString(lpszPathName).MakeLower().Find(_T("@device:")) >= 0) { + return; + } + + CString pathName = lpszPathName; + + bool fURL = PathUtils::IsURL(pathName); + + // fully qualify the path name + if (!fURL) { + pathName = MakeFullPath(pathName); + } + + // update the MRU list, if an existing MRU string matches file name + int iMRU; + for (iMRU = 0; iMRU < m_nSize - 1; iMRU++) { + if ((fURL && !_tcscmp(m_arrNames[iMRU], pathName)) + || AfxComparePath(m_arrNames[iMRU], pathName)) { + break; // iMRU will point to matching entry + } + } + // move MRU strings before this one down + for (; iMRU > 0; iMRU--) { + ASSERT(iMRU > 0); + ASSERT(iMRU < m_nSize); + m_arrNames[iMRU] = m_arrNames[iMRU - 1]; + } + // place this one at the beginning + m_arrNames[0] = pathName; +} + +void CAppSettings::CRecentFileAndURLList::SetSize(int nSize) +{ + ENSURE_ARG(nSize >= 0); + + if (m_nSize != nSize) { + CString* arrNames = DEBUG_NEW CString[nSize]; + int nSizeToCopy = std::min(m_nSize, nSize); + for (int i = 0; i < nSizeToCopy; i++) { + arrNames[i] = m_arrNames[i]; + } + delete [] m_arrNames; + m_arrNames = arrNames; + m_nSize = nSize; + } +} + +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +CStringW getShortHash(PBYTE bytes, ULONG size) { + BCRYPT_ALG_HANDLE algHandle = nullptr; + BCRYPT_HASH_HANDLE hashHandle = nullptr; + + PBYTE hash = nullptr; + DWORD hashLen = 0; + DWORD cbResult = 0; + ULONG dwFlags = 0; + const int shortHashLen = 12; + + NTSTATUS stat; + CStringW shortHash = L""; + + stat = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_SHA1_ALGORITHM, nullptr, 0); + if (NT_SUCCESS(stat)) { + stat = BCryptGetProperty(algHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hashLen, sizeof(hashLen), &cbResult, dwFlags); + if (NT_SUCCESS(stat)) { + hash = (PBYTE)HeapAlloc(GetProcessHeap(), dwFlags, hashLen); + if (nullptr != hash) { + stat = BCryptCreateHash(algHandle, &hashHandle, nullptr, 0, nullptr, 0, dwFlags); + if (NT_SUCCESS(stat)) { + stat = BCryptHashData(hashHandle, bytes, size, dwFlags); + if (NT_SUCCESS(stat)) { + stat = BCryptFinishHash(hashHandle, hash, hashLen, 0); + if (NT_SUCCESS(stat)) { + DWORD hashStrLen = 0; + if (CryptBinaryToStringW(hash, hashLen, CRYPT_STRING_BASE64, nullptr, &hashStrLen) && hashStrLen > 0) { + CStringW longHash; + if (CryptBinaryToStringW(hash, hashLen, CRYPT_STRING_BASE64, longHash.GetBuffer(hashStrLen - 1), &hashStrLen)) { + longHash.ReleaseBuffer(hashStrLen); + shortHash = longHash.Left(shortHashLen); + } else { + longHash.ReleaseBuffer(); + } + } + } + } + } + } + } + } + + if (nullptr != hash) { + HeapFree(GetProcessHeap(), dwFlags, hash); + } + + if (nullptr != hashHandle) { + BCryptDestroyHash(hashHandle); + } + + if (nullptr != algHandle) { + BCryptCloseAlgorithmProvider(algHandle, dwFlags); + } + + return shortHash; +} + +CStringW getRFEHash(CStringW fn) { + fn.MakeLower(); + CStringW hash = getShortHash((PBYTE)fn.GetString(), fn.GetLength() * sizeof(WCHAR)); + if (hash.IsEmpty()) { + ASSERT(FALSE); + hash = fn.Right(30); + hash.Replace(L"\\", L"/"); + } + return hash; +} + +CStringW getRFEHash(ULONGLONG llDVDGuid) { + CStringW hash; + hash.Format(L"DVD%llu", llDVDGuid); + return hash; +} + +CStringW getRFEHash(RecentFileEntry &r) { + CStringW fn; + if (r.DVDPosition.llDVDGuid) { + return getRFEHash(r.DVDPosition.llDVDGuid); + } else { + fn = r.fns.GetHead(); + return getRFEHash(fn); + } +} + +/* +void CAppSettings::CRecentFileListWithMoreInfo::Remove(size_t nIndex) { + if (nIndex >= 0 && nIndex < rfe_array.GetCount()) { + auto pApp = AfxGetMyApp(); + CStringW& hash = rfe_array[nIndex].hash; + if (!hash.IsEmpty()) { + pApp->RemoveProfileKey(m_section, hash); + } + rfe_array.RemoveAt(nIndex); + rfe_array.FreeExtra(); + } + if (nIndex == 0 && rfe_array.GetCount() == 0) { + // list was cleared + current_rfe_hash.Empty(); + } +} +*/ + +void CAppSettings::CRecentFileListWithMoreInfo::Add(LPCTSTR fn) { + RecentFileEntry r; + LoadMediaHistoryEntryFN(fn, r); + Add(r, true); +} + +void CAppSettings::CRecentFileListWithMoreInfo::Add(LPCTSTR fn, ULONGLONG llDVDGuid) { + RecentFileEntry r; + LoadMediaHistoryEntryDVD(llDVDGuid, fn, r); + Add(r, true); +} + +bool CAppSettings::CRecentFileListWithMoreInfo::GetCurrentIndex(size_t& idx) { + for (int i = 0; i < rfe_array.GetCount(); i++) { + if (rfe_array[i].hash == current_rfe_hash) { + idx = i; + return true; + } + } + return false; +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentFilePosition(REFERENCE_TIME time, bool forcePersist /* = false */) { + size_t idx; + if (GetCurrentIndex(idx)) { + rfe_array[idx].filePosition = time; + if (forcePersist || std::abs(persistedFilePosition - time) > 300000000) { + WriteMediaHistoryEntry(rfe_array[idx]); + } + } +} + +REFERENCE_TIME CAppSettings::CRecentFileListWithMoreInfo::GetCurrentFilePosition() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].filePosition; + } + return 0; +} + +ABRepeat CAppSettings::CRecentFileListWithMoreInfo::GetCurrentABRepeat() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].abRepeat; + } + return ABRepeat(); +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentDVDTimecode(DVD_HMSF_TIMECODE* time) { + size_t idx; + if (GetCurrentIndex(idx)) { + DVD_POSITION* dvdPosition = &rfe_array[idx].DVDPosition; + if (dvdPosition) { + memcpy(&dvdPosition->timecode, (void*)time, sizeof(DVD_HMSF_TIMECODE)); + } + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentDVDTitle(DWORD title) { + size_t idx; + if (GetCurrentIndex(idx)) { + DVD_POSITION* dvdPosition = &rfe_array[idx].DVDPosition; + if (dvdPosition) { + dvdPosition->lTitle = title; + } + } +} + +DVD_POSITION CAppSettings::CRecentFileListWithMoreInfo::GetCurrentDVDPosition() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].DVDPosition; + } + return DVD_POSITION(); +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentAudioTrack(int audioIndex) { + size_t idx; + if (GetCurrentIndex(idx)) { + if (rfe_array[idx].AudioTrackIndex != audioIndex) { + rfe_array[idx].AudioTrackIndex = audioIndex; + WriteMediaHistoryAudioIndex(rfe_array[idx]); + } + } +} + +int CAppSettings::CRecentFileListWithMoreInfo::GetCurrentAudioTrack() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].AudioTrackIndex; + } + return -1; +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentSubtitleTrack(int subIndex) { + size_t idx; + if (GetCurrentIndex(idx)) { + if (rfe_array[idx].SubtitleTrackIndex != subIndex) { + rfe_array[idx].SubtitleTrackIndex = subIndex; + WriteMediaHistorySubtitleIndex(rfe_array[idx]); + } + } +} + +int CAppSettings::CRecentFileListWithMoreInfo::GetCurrentSubtitleTrack() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].SubtitleTrackIndex; + } + return -1; +} + +void CAppSettings::CRecentFileListWithMoreInfo::AddSubToCurrent(CStringW subpath) { + size_t idx; + if (GetCurrentIndex(idx)) { + bool found = rfe_array[idx].subs.Find(subpath); + if (!found) { + rfe_array[idx].subs.AddHead(subpath); + WriteMediaHistoryEntry(rfe_array[idx]); + } + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::SetCurrentTitle(CStringW title) { + size_t idx; + if (GetCurrentIndex(idx)) { + rfe_array[idx].title = title; + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentABRepeat(ABRepeat abRepeat) { + size_t idx; + if (GetCurrentIndex(idx)) { + rfe_array[idx].abRepeat = abRepeat; + WriteMediaHistoryEntry(rfe_array[idx]); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::WriteCurrentEntry() { + size_t idx; + if (!current_rfe_hash.IsEmpty() && GetCurrentIndex(idx)) { + WriteMediaHistoryEntry(rfe_array[idx]); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::Add(RecentFileEntry r, bool current_open) { + if (r.fns.GetCount() < 1) { + return; + } + if (CString(r.fns.GetHead()).MakeLower().Find(_T("@device:")) >= 0) { + return; + } + + if (r.hash.IsEmpty()) { + r.hash = getRFEHash(r); + } + for (size_t i = 0; i < rfe_array.GetCount(); i++) { + if (r.hash == rfe_array[i].hash) { + rfe_array.RemoveAt(i); //do not call Remove as it will purge reg key. we are just resorting + break; + } + } + WriteMediaHistoryEntry(r, true); + + rfe_array.InsertAt(0, r); + if (current_open) { + current_rfe_hash = r.hash; + persistedFilePosition = r.filePosition; + } + + // purge obsolete entry + if (rfe_array.GetCount() > m_maxSize) { + CStringW hash = rfe_array.GetAt(m_maxSize).hash; + if (!hash.IsEmpty()) { + CStringW subSection; + subSection.Format(L"%s\\%s", m_section, static_cast(hash)); + auto pApp = AfxGetMyApp(); + pApp->WriteProfileString(subSection, nullptr, nullptr); + } + rfe_array.SetCount(m_maxSize); + } + rfe_array.FreeExtra(); +} + +static void DeserializeHex(LPCTSTR strVal, BYTE* pBuffer, int nBufSize) { + long lRes; + + for (int i = 0; i < nBufSize; i++) { + _stscanf_s(strVal + (i * 2), _T("%02lx"), &lRes); + pBuffer[i] = (BYTE)lRes; + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::ReadLegacyMediaHistory(std::map& filenameToIndex) { + rfe_array.RemoveAll(); + auto pApp = AfxGetMyApp(); + LPCWSTR legacySection = L"Recent File List"; + int dvdCount = 0; + for (size_t i = 1; i <= m_maxSize; i++) { + CStringW t; + t.Format(_T("File%zu"), i); + CStringW fn = pApp->GetProfileStringW(legacySection, t); + if (fn.IsEmpty()) { + break; + } + t.Format(_T("Title%zu"), i); + CStringW title = pApp->GetProfileStringW(legacySection, t); + t.Format(_T("Cue%zu"), i); + CStringW cue = pApp->GetProfileStringW(legacySection, t); + RecentFileEntry r; + r.fns.AddTail(fn); + r.title = title; + r.cue = cue; + int k = 2; + for (;; k++) { + t.Format(_T("File%zu,%d"), i, k); + CStringW ft = pApp->GetProfileStringW(legacySection, t); + if (ft.IsEmpty()) break; + r.fns.AddTail(ft); + } + k = 1; + for (;; k++) { + t.Format(_T("Sub%zu,%d"), i, k); + CStringW st = pApp->GetProfileStringW(legacySection, t); + if (st.IsEmpty()) break; + r.subs.AddTail(st); + } + if (fn.Right(9) == L"\\VIDEO_TS") { //try to find the dvd position from index + CStringW strDVDPos; + strDVDPos.Format(_T("DVD Position %d"), dvdCount++); + CStringW strValue = pApp->GetProfileString(IDS_R_SETTINGS, strDVDPos, _T("")); + + if (!strValue.IsEmpty()) { + if (strValue.GetLength() / 2 == sizeof(DVD_POSITION)) { + DeserializeHex(strValue, (BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); + } + } + rfe_array.Add(r); + } else { + filenameToIndex[r.fns.GetHead()] = rfe_array.Add(r); + } + } + rfe_array.FreeExtra(); +} + +static CString SerializeHex(const BYTE* pBuffer, int nBufSize) { + CString strTemp; + CString strResult; + + for (int i = 0; i < nBufSize; i++) { + strTemp.Format(_T("%02x"), pBuffer[i]); + strResult += strTemp; + } + + return strResult; +} + +void CAppSettings::CRecentFileListWithMoreInfo::ReadLegacyMediaPosition(std::map& filenameToIndex) { + auto pApp = AfxGetMyApp(); + bool hasNextEntry = true; + CStringW strFilename; + CStringW strFilePos; + + for (int i = 0; i < 1000 && hasNextEntry; i++) { + strFilename.Format(_T("File Name %d"), i); + CStringW strFile = pApp->GetProfileString(IDS_R_SETTINGS, strFilename); + + if (strFile.IsEmpty()) { + hasNextEntry = false; + } else { + strFilePos.Format(_T("File Position %d"), i); + if (filenameToIndex.count(strFile)) { + size_t index = filenameToIndex[strFile]; + if (index < rfe_array.GetCount()) { + CStringW strValue = pApp->GetProfileString(IDS_R_SETTINGS, strFilePos); + rfe_array.GetAt(index).filePosition = _tstoi64(strValue); + } + } + // remove old values + pApp->WriteProfileString(IDS_R_SETTINGS, strFilename, nullptr); + pApp->WriteProfileString(IDS_R_SETTINGS, strFilePos, nullptr); + } + } +} + +bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntryFN(CStringW fn, RecentFileEntry& r) { + CStringW hash = getRFEHash(fn); + if (!LoadMediaHistoryEntry(hash, r)) { + r.hash = hash; + r.fns.AddHead(fn); //otherwise add a new entry + return false; + } + return true; +} + +bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntryDVD(ULONGLONG llDVDGuid, CStringW fn, RecentFileEntry& r) { + CStringW hash = getRFEHash(llDVDGuid); + if (!LoadMediaHistoryEntry(hash, r)) { + r.hash = hash; + r.fns.AddHead(fn); //otherwise add a new entry + r.DVDPosition.llDVDGuid = llDVDGuid; + return false; + } + return true; +} + +bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntry(CStringW hash, RecentFileEntry &r) { + auto pApp = AfxGetMyApp(); + CStringW fn, subSection, t; + + subSection.Format(L"%s\\%s", m_section, static_cast(hash)); + + fn = pApp->GetProfileStringW(subSection, L"Filename", L""); + if (fn.IsEmpty()) { + return false; + } + + DWORD filePosition = pApp->GetProfileIntW(subSection, L"FilePosition", 0); + CStringW dvdPosition = pApp->GetProfileStringW(subSection, L"DVDPosition", L""); + + r.hash = hash; + r.fns.AddHead(fn); + r.title = pApp->GetProfileStringW(subSection, L"Title", L""); + r.cue = pApp->GetProfileStringW(subSection, L"Cue", L""); + r.filePosition = filePosition * 10000LL; + if (!dvdPosition.IsEmpty()) { + if (dvdPosition.GetLength() / 2 == sizeof(DVD_POSITION)) { + DeserializeHex(dvdPosition, (BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); + } + } + r.abRepeat.positionA = pApp->GetProfileIntW(subSection, L"abRepeat.positionA", 0) * 10000LL; + r.abRepeat.positionB = pApp->GetProfileIntW(subSection, L"abRepeat.positionB", 0) * 10000LL; + r.abRepeat.dvdTitle = pApp->GetProfileIntW(subSection, L"abRepeat.dvdTitle", -1); + + int k = 2; + for (;; k++) { + t.Format(_T("Filename%03d"), k); + CStringW ft = pApp->GetProfileStringW(subSection, t); + if (ft.IsEmpty()) { + break; + } + r.fns.AddTail(ft); + } + k = 1; + for (;; k++) { + t.Format(_T("Sub%03d"), k); + CStringW st = pApp->GetProfileStringW(subSection, t); + if (st.IsEmpty()) { + break; + } + r.subs.AddTail(st); + } + + r.AudioTrackIndex = pApp->GetProfileIntW(subSection, L"AudioTrackIndex", -1); + r.SubtitleTrackIndex = pApp->GetProfileIntW(subSection, L"SubtitleTrackIndex", -1); + return true; +} + +void CAppSettings::CRecentFileListWithMoreInfo::ReadMediaHistory() { + auto pApp = AfxGetMyApp(); + + int lastAddedStored = pApp->GetProfileIntW(m_section, L"LastAdded", 0); + if (lastAddedStored != 0 && lastAddedStored == rfe_last_added || rfe_last_added == 1) { + return; + } + listModifySequence++; + + size_t maxsize = AfxGetAppSettings().fKeepHistory ? m_maxSize : 0; + + std::list hashes = pApp->GetSectionSubKeys(m_section); + + if (hashes.empty()) { + if (maxsize > 0) { + MigrateLegacyHistory(); + hashes = pApp->GetSectionSubKeys(m_section); + } else { + rfe_last_added = 1; + rfe_array.RemoveAll(); + return; + } + } + + auto timeToHash = CAppSettings::LoadHistoryHashes(m_section, L"LastOpened"); + + rfe_array.RemoveAll(); + int entries = 0; + for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { + bool purge_rfe = true; + CStringW hash = iter->second; + if (entries < maxsize) { + RecentFileEntry r; + r.lastOpened = iter->first; + if (LoadMediaHistoryEntry(hash, r)) { + rfe_array.Add(r); + purge_rfe = false; + entries++; + } + } + if (purge_rfe) { //purge entry + CAppSettings::PurgeExpiredHash(m_section, hash); + } + } + rfe_array.FreeExtra(); + + if (lastAddedStored == 0 && m_maxSize > 0) { + rfe_last_added = 1; // history read, but nothing new added yet + pApp->WriteProfileInt(m_section, L"LastAdded", rfe_last_added); + } else { + rfe_last_added = lastAddedStored; + } + + // The playlist history size is not managed elsewhere + CAppSettings::PurgePlaylistHistory(maxsize); +} + +void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistoryAudioIndex(RecentFileEntry& r) { + auto pApp = AfxGetMyApp(); + + if (r.hash.IsEmpty()) { + r.hash = getRFEHash(r.fns.GetHead()); + } + + CStringW subSection, t; + subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); + + if (r.AudioTrackIndex != -1) { + pApp->WriteProfileInt(subSection, L"AudioTrackIndex", int(r.AudioTrackIndex)); + } else { + pApp->WriteProfileStringW(subSection, L"AudioTrackIndex", nullptr); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistorySubtitleIndex(RecentFileEntry& r) { + auto pApp = AfxGetMyApp(); + + if (r.hash.IsEmpty()) { + r.hash = getRFEHash(r.fns.GetHead()); + } + + CStringW subSection, t; + subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); + + if (r.SubtitleTrackIndex != -1) { + pApp->WriteProfileInt(subSection, L"SubtitleTrackIndex", int(r.SubtitleTrackIndex)); + } else { + pApp->WriteProfileStringW(subSection, L"SubtitleTrackIndex", nullptr); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistoryEntry(RecentFileEntry& r, bool updateLastOpened /* = false */) { + auto pApp = AfxGetMyApp(); + + if (r.hash.IsEmpty()) { + r.hash = getRFEHash(r.fns.GetHead()); + } + + CStringW subSection, t; + subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); + + CString storedFilename = pApp->GetProfileStringW(subSection, L"Filename", L""); + bool isNewEntry = storedFilename.IsEmpty(); + if (isNewEntry || storedFilename != r.fns.GetHead()) { + pApp->WriteProfileStringW(subSection, L"Filename", r.fns.GetHead()); + } + + if (r.fns.GetCount() > 1) { + int k = 2; + POSITION p(r.fns.GetHeadPosition()); + r.fns.GetNext(p); + while (p != nullptr) { + CString fn = r.fns.GetNext(p); + t.Format(L"Filename%03d", k); + pApp->WriteProfileStringW(subSection, t, fn); + k++; + } + } + if (!r.title.IsEmpty()) { + t = L"Title"; + pApp->WriteProfileStringW(subSection, t, r.title); + } + if (!r.cue.IsEmpty()) { + t = L"Cue"; + pApp->WriteProfileStringW(subSection, t, r.cue); + } + if (r.subs.GetCount() > 0) { + int k = 1; + POSITION p(r.subs.GetHeadPosition()); + while (p != nullptr) { + CString fn = r.subs.GetNext(p); + t.Format(L"Sub%03d", k); + pApp->WriteProfileStringW(subSection, t, fn); + k++; + } + } + if (r.DVDPosition.llDVDGuid) { + t = L"DVDPosition"; + CStringW strValue = SerializeHex((BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); + pApp->WriteProfileStringW(subSection, t, strValue); + } else { + t = L"FilePosition"; + pApp->WriteProfileInt(subSection, t, int(r.filePosition / 10000LL)); + persistedFilePosition = r.filePosition; + } + if (r.abRepeat.positionA) { + pApp->WriteProfileInt(subSection, L"abRepeat.positionA", int(r.abRepeat.positionA / 10000LL)); + } else { + pApp->WriteProfileStringW(subSection, L"abRepeat.positionA", nullptr); + } + if (r.abRepeat.positionB) { + pApp->WriteProfileInt(subSection, L"abRepeat.positionB", int(r.abRepeat.positionB / 10000LL)); + } else { + pApp->WriteProfileStringW(subSection, L"abRepeat.positionB", nullptr); + } + if (r.abRepeat && r.abRepeat.dvdTitle != -1) { + pApp->WriteProfileInt(subSection, L"abRepeat.dvdTitle", int(r.abRepeat.dvdTitle)); + } else { + pApp->WriteProfileStringW(subSection, L"abRepeat.dvdTitle", nullptr); + } + + if (r.AudioTrackIndex != -1) { + pApp->WriteProfileInt(subSection, L"AudioTrackIndex", int(r.AudioTrackIndex)); + } else { + pApp->WriteProfileStringW(subSection, L"AudioTrackIndex", nullptr); + } + + if (r.SubtitleTrackIndex != -1) { + pApp->WriteProfileInt(subSection, L"SubtitleTrackIndex", int(r.SubtitleTrackIndex)); + } else { + pApp->WriteProfileStringW(subSection, L"SubtitleTrackIndex", nullptr); + } + + if (updateLastOpened || isNewEntry || r.lastOpened.IsEmpty()) { + auto now = std::chrono::system_clock::now(); + auto nowISO = date::format(L"%FT%TZ", date::floor(now)); + r.lastOpened = CStringW(nowISO.c_str()); + pApp->WriteProfileStringW(subSection, L"LastOpened", r.lastOpened); + if (isNewEntry) { + rfe_last_added = (int)std::chrono::time_point_cast(now).time_since_epoch().count(); + pApp->WriteProfileInt(m_section, L"LastAdded", rfe_last_added); + } + } + listModifySequence++; +} + +void CAppSettings::CRecentFileListWithMoreInfo::SaveMediaHistory() { + if (rfe_array.GetCount()) { + //go in reverse in case we are setting last opened when migrating history (makes last appear oldest) + for (size_t i = rfe_array.GetCount() - 1, j = 0; j < m_maxSize && j < rfe_array.GetCount(); i--, j++) { + auto& r = rfe_array.GetAt(i); + WriteMediaHistoryEntry(r); + } + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::MigrateLegacyHistory() { + auto pApp = AfxGetMyApp(); + std::map filenameToIndex; + ReadLegacyMediaHistory(filenameToIndex); + ReadLegacyMediaPosition(filenameToIndex); + SaveMediaHistory(); + LPCWSTR legacySection = L"Recent File List"; + pApp->WriteProfileString(legacySection, nullptr, nullptr); +} + +void CAppSettings::CRecentFileListWithMoreInfo::SetSize(size_t nSize) { + m_maxSize = nSize; + if (rfe_array.GetCount() > m_maxSize) { + rfe_array.SetCount(m_maxSize); + PurgeMediaHistory(m_maxSize); + PurgePlaylistHistory(m_maxSize); + // to force update of recent files menu + listModifySequence++; + } + rfe_array.FreeExtra(); + + if (nSize == 0) { + current_rfe_hash.Empty(); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::RemoveAll() { + SetSize(0); +} + +bool CAppSettings::IsVSFilterInstalled() +{ + return IsCLSIDRegistered(CLSID_VSFilter); +} + +void CAppSettings::UpdateSettings() +{ + auto pApp = AfxGetMyApp(); + ASSERT(pApp); + + UINT version = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_R_VERSION, 0); + if (version >= APPSETTINGS_VERSION) { + return; // Nothing to update + } + + // Use lambda expressions to copy data entries + auto copyInt = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { + if (pApp->HasProfileEntry(oldSection, oldEntry)) { + int old = pApp->GetProfileInt(oldSection, oldEntry, 0); + VERIFY(pApp->WriteProfileInt(newSection, newEntry, old)); + } + }; + auto copyStr = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { + if (pApp->HasProfileEntry(oldSection, oldEntry)) { + CString old = pApp->GetProfileString(oldSection, oldEntry); + VERIFY(pApp->WriteProfileString(newSection, newEntry, old)); + } + }; + auto copyBin = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { + UINT len; + BYTE* old; + if (pApp->GetProfileBinary(oldSection, oldEntry, &old, &len)) { + VERIFY(pApp->WriteProfileBinary(newSection, newEntry, old, len)); + delete [] old; + } + }; + + + // Migrate to the latest version, these cases should fall through + // so that all incremental updates are applied. + switch (version) { + case 0: { + UINT nAudioBoostTmp = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, -1); + if (nAudioBoostTmp == UINT(-1)) { + double dAudioBoost_dB = _tstof(pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, _T("0"))); + if (dAudioBoost_dB < 0 || dAudioBoost_dB > 10) { + dAudioBoost_dB = 0; + } + nAudioBoostTmp = UINT(100 * pow(10.0, dAudioBoost_dB / 20.0) + 0.5) - 100; + } + if (nAudioBoostTmp > 300) { // Max boost is 300% + nAudioBoostTmp = 300; + } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, nAudioBoostTmp); + } + { + const CString section(_T("Settings")); + copyInt(section, _T("Remember DVD Pos"), section, _T("RememberDVDPos")); + copyInt(section, _T("Remember File Pos"), section, _T("RememberFilePos")); + copyInt(section, _T("Show OSD"), section, _T("ShowOSD")); + copyStr(section, _T("Shaders List"), section, _T("ShadersList")); + copyInt(section, _T("OSD_Size"), section, _T("OSDSize")); + copyStr(section, _T("OSD_Font"), section, _T("OSDFont")); + copyInt(section, _T("gotoluf"), section, _T("GoToLastUsed")); + copyInt(section, _T("fps"), section, _T("GoToFPS")); + } + { + // Copy DVB section + const CString oldSection(_T("DVB configuration")); + const CString newSection(_T("DVBConfiguration")); + //copyStr(oldSection, _T("BDANetworkProvider"), newSection, _T("BDANetworkProvider")); + copyStr(oldSection, _T("BDATuner"), newSection, _T("BDATuner")); + copyStr(oldSection, _T("BDAReceiver"), newSection, _T("BDAReceiver")); + copyInt(oldSection, _T("BDAScanFreqStart"), newSection, _T("BDAScanFreqStart")); + copyInt(oldSection, _T("BDAScanFreqEnd"), newSection, _T("BDAScanFreqEnd")); + copyInt(oldSection, _T("BDABandWidth"), newSection, _T("BDABandWidth")); + copyInt(oldSection, _T("BDAUseOffset"), newSection, _T("BDAUseOffset")); + copyInt(oldSection, _T("BDAOffset"), newSection, _T("BDAOffset")); + copyInt(oldSection, _T("BDAIgnoreEncryptedChannels"), newSection, _T("BDAIgnoreEncryptedChannels")); + copyInt(oldSection, _T("LastChannel"), newSection, _T("LastChannel")); + copyInt(oldSection, _T("RebuildFilterGraph"), newSection, _T("RebuildFilterGraph")); + copyInt(oldSection, _T("StopFilterGraph"), newSection, _T("StopFilterGraph")); + for (int iChannel = 0; ; iChannel++) { + CString strTemp, strChannel; + strTemp.Format(_T("%d"), iChannel); + if (!pApp->HasProfileEntry(oldSection, strTemp)) { + break; + } + strChannel = pApp->GetProfileString(oldSection, strTemp); + if (strChannel.IsEmpty()) { + break; + } + VERIFY(pApp->WriteProfileString(newSection, strTemp, strChannel)); + } + } + [[fallthrough]]; + case 1: { + // Internal decoding of WMV 1/2/3 is now disabled by default so we reinitialize its value + pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, _T("TRA_WMV"), FALSE); + } + [[fallthrough]]; + case 2: { + const CString section(_T("Settings")); + if (pApp->HasProfileEntry(section, _T("FullScreenCtrls")) && + pApp->HasProfileEntry(section, _T("FullScreenCtrlsTimeOut"))) { + bool bHide = true; + int nHidePolicy = 0; + int nTimeout = -1; + if (!pApp->GetProfileInt(section, _T("FullScreenCtrls"), 0)) { + // hide always + } else { + nTimeout = pApp->GetProfileInt(section, _T("FullScreenCtrlsTimeOut"), 0); + if (nTimeout < 0) { + // show always + bHide = false; + } else if (nTimeout == 0) { + // show when hovered + nHidePolicy = 1; + } else { + // show when mouse moved + nHidePolicy = 2; + } + } + VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControls"), bHide)); + if (nTimeout >= 0) { + VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControlsPolicy"), nHidePolicy)); + VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControlsDelay"), nTimeout * 1000)); + } + } + } + [[fallthrough]]; + case 3: { +#pragma pack(push, 1) + struct dispmode { + bool fValid; + CSize size; + int bpp, freq; + DWORD dmDisplayFlags; + }; + + struct fpsmode { + double vfr_from; + double vfr_to; + bool fChecked; + dispmode dmFSRes; + bool fIsData; + }; + + struct AChFR { + bool bEnabled; + fpsmode dmFullscreenRes[30]; + bool bApplyDefault; + }; //AutoChangeFullscrRes +#pragma pack(pop) + + LPBYTE ptr; + UINT len; + bool bSetDefault = true; + if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("FullscreenRes"), &ptr, &len)) { + if (len == sizeof(AChFR)) { + AChFR autoChangeFullscrRes; + memcpy(&autoChangeFullscrRes, ptr, sizeof(AChFR)); + + autoChangeFSMode.bEnabled = autoChangeFullscrRes.bEnabled; + autoChangeFSMode.bApplyDefaultModeAtFSExit = autoChangeFullscrRes.bApplyDefault; + + for (size_t i = 0; i < _countof(autoChangeFullscrRes.dmFullscreenRes); i++) { + const auto& modeOld = autoChangeFullscrRes.dmFullscreenRes[i]; + // The old settings could be corrupted quite easily so be careful when converting them + if (modeOld.fIsData + && modeOld.vfr_from >= 0.0 && modeOld.vfr_from <= 126.0 + && modeOld.vfr_to >= 0.0 && modeOld.vfr_to <= 126.0 + && modeOld.dmFSRes.fValid + && modeOld.dmFSRes.bpp == 32 + && modeOld.dmFSRes.size.cx >= 640 && modeOld.dmFSRes.size.cx < 10000 + && modeOld.dmFSRes.size.cy >= 380 && modeOld.dmFSRes.size.cy < 10000 + && modeOld.dmFSRes.freq > 0 && modeOld.dmFSRes.freq < 1000) { + DisplayMode dm; + dm.bValid = true; + dm.size = modeOld.dmFSRes.size; + dm.bpp = 32; + dm.freq = modeOld.dmFSRes.freq; + dm.dwDisplayFlags = modeOld.dmFSRes.dmDisplayFlags & DM_INTERLACED; + + autoChangeFSMode.modes.emplace_back(modeOld.fChecked, modeOld.vfr_from, modeOld.vfr_to, 0, std::move(dm)); + } + } + + bSetDefault = autoChangeFSMode.modes.empty() || autoChangeFSMode.modes[0].dFrameRateStart != 0.0 || autoChangeFSMode.modes[0].dFrameRateStop != 0.0; + } + delete [] ptr; + } + + if (bSetDefault) { + autoChangeFSMode.bEnabled = false; + autoChangeFSMode.bApplyDefaultModeAtFSExit = false; + autoChangeFSMode.modes.clear(); + } + autoChangeFSMode.bRestoreResAfterProgExit = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("RestoreResAfterExit"), TRUE); + autoChangeFSMode.uDelay = pApp->GetProfileInt(IDS_R_SETTINGS, _T("FullscreenResDelay"), 0); + + SaveSettingsAutoChangeFullScreenMode(); + } + [[fallthrough]]; + case 4: { + bool bDisableSubtitleAnimation = !pApp->GetProfileInt(IDS_R_SETTINGS, _T("SPCAllowAnimationWhenBuffering"), TRUE); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, bDisableSubtitleAnimation)); + } + [[fallthrough]]; + case 5: + copyInt(IDS_R_INTERNAL_FILTERS, _T("SRC_DTSAC3"), IDS_R_INTERNAL_FILTERS, _T("SRC_DTS")); + copyInt(IDS_R_INTERNAL_FILTERS, _T("SRC_DTSAC3"), IDS_R_INTERNAL_FILTERS, _T("SRC_AC3")); + [[fallthrough]]; + case 6: { + SubtitleRenderer subrenderer = SubtitleRenderer::INTERNAL; + if (!pApp->GetProfileInt(IDS_R_SETTINGS, _T("AutoloadSubtitles"), TRUE)) { + if (IsSubtitleRendererRegistered(SubtitleRenderer::VS_FILTER)) { + subrenderer = SubtitleRenderer::VS_FILTER; + } + if (IsSubtitleRendererRegistered(SubtitleRenderer::XY_SUB_FILTER)) { + int renderer = IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS; + renderer = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, renderer); + if (IsSubtitleRendererSupported(SubtitleRenderer::XY_SUB_FILTER, renderer)) { + subrenderer = SubtitleRenderer::XY_SUB_FILTER; + } + } + } + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, static_cast(subrenderer))); + } + [[fallthrough]]; + case 7: + // Update the settings after the removal of DirectX 7 renderers + switch (pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_DEFAULT)) { + case 3: // VIDRNDT_DS_VMR7WINDOWED + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_VMR9WINDOWED)); + break; + case 5: // VIDRNDT_DS_VMR7RENDERLESS + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_VMR9RENDERLESS)); + break; + } + [[fallthrough]]; + default: + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_R_VERSION, APPSETTINGS_VERSION); + } +} + +// RenderersSettings.h + +CRenderersData* GetRenderersData() { + return &AfxGetMyApp()->m_Renderers; +} + +CRenderersSettings& GetRenderersSettings() { + auto& s = AfxGetAppSettings(); + if (s.m_RenderersSettings.subPicQueueSettings.nSize > 0) { + // queue does not work properly with libass + if (s.bRenderSSAUsingLibass || s.bRenderSRTUsingLibass) { + s.m_RenderersSettings.subPicQueueSettings.nSize = 0; + } + } + return s.m_RenderersSettings; +} + +void CAppSettings::SavePlayListPosition(CStringW playlistPath, UINT position) { + auto pApp = AfxGetMyApp(); + ASSERT(pApp); + + auto hash = getRFEHash(playlistPath); + + CStringW subSection, t; + subSection.Format(L"%s\\%s", L"PlaylistHistory", static_cast(hash)); + pApp->WriteProfileInt(subSection, L"Position", position); + + auto now = std::chrono::system_clock::now(); + auto nowISO = date::format(L"%FT%TZ", date::floor(now)); + CStringW lastUpdated = CStringW(nowISO.c_str()); + pApp->WriteProfileStringW(subSection, L"LastUpdated", lastUpdated); +} + +UINT CAppSettings::GetSavedPlayListPosition(CStringW playlistPath) { + auto pApp = AfxGetMyApp(); + ASSERT(pApp); + + auto hash = getRFEHash(playlistPath); + + CStringW subSection, t; + subSection.Format(L"%s\\%s", L"PlaylistHistory", static_cast(hash)); + UINT position = pApp->GetProfileIntW(subSection, L"Position", -1); + if (position != (UINT)-1) { + return position; + } + return 0; +} + +// SubRendererSettings.h + +// Todo: move individual members of AppSettings into SubRendererSettings struct and use this function to get a reference to it +SubRendererSettings GetSubRendererSettings() { + const auto& s = AfxGetAppSettings(); + SubRendererSettings srs; + srs.defaultStyle = s.subtitlesDefStyle; + srs.overrideDefaultStyle = s.bSubtitleOverrideDefaultStyle || s.bSubtitleOverrideAllStyles; + srs.overrideAllStyles = s.bSubtitleOverrideAllStyles; +#if USE_LIBASS + srs.renderSSAUsingLibass = s.bRenderSSAUsingLibass; + srs.renderSRTUsingLibass = s.bRenderSRTUsingLibass; +#endif + OpenTypeLang::CStringAtoHintStr(srs.openTypeLangHint, s.strOpenTypeLangHint); + return srs; +} diff --git a/src/mpc-hc/AppSettings.h b/src/mpc-hc/AppSettings.h index 1ab8e4dc6d7..64efcac850b 100644 --- a/src/mpc-hc/AppSettings.h +++ b/src/mpc-hc/AppSettings.h @@ -1,1076 +1,1076 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#pragma once -#include "mpc-hc_config.h" -#include "../Subtitles/STS.h" -#include "../filters/switcher/AudioSwitcher/AudioSwitcher.h" -#include "../thirdparty/sanear/src/Interfaces.h" -#include "DVBChannel.h" -#include "FileAssoc.h" -#include "FilterEnum.h" -#include "MediaFormats.h" -#include "../filters/renderer/VideoRenderers/RenderersSettings.h" -#include "SettingsDefines.h" -#include "Shaders.h" -#include "../Subtitles/SubRendererSettings.h" -#include -#include -#include "CMPCTheme.h" - - -class FilterOverride; - -// flags for CAppSettings::nCS -enum { - CS_NONE = 0, - CS_SEEKBAR = 1, - CS_TOOLBAR = CS_SEEKBAR << 1, - CS_INFOBAR = CS_TOOLBAR << 1, - CS_STATSBAR = CS_INFOBAR << 1, - CS_STATUSBAR = CS_STATSBAR << 1, - CS_LAST = CS_STATUSBAR -}; - -enum : UINT64 { - CLSW_NONE = 0, - CLSW_OPEN = 1, - CLSW_PLAY = CLSW_OPEN << 1, - CLSW_CLOSE = CLSW_PLAY << 1, - CLSW_STANDBY = CLSW_CLOSE << 1, - CLSW_HIBERNATE = CLSW_STANDBY << 1, - CLSW_SHUTDOWN = CLSW_HIBERNATE << 1, - CLSW_LOGOFF = CLSW_SHUTDOWN << 1, - CLSW_LOCK = CLSW_LOGOFF << 1, - CLSW_MONITOROFF = CLSW_LOCK << 1, - CLSW_PLAYNEXT = CLSW_MONITOROFF << 1, - CLSW_DONOTHING = CLSW_PLAYNEXT << 1, - CLSW_AFTERPLAYBACK_MASK = CLSW_CLOSE | CLSW_STANDBY | CLSW_SHUTDOWN | CLSW_HIBERNATE | CLSW_LOGOFF | CLSW_LOCK | CLSW_MONITOROFF | CLSW_PLAYNEXT | CLSW_DONOTHING, - CLSW_FULLSCREEN = CLSW_DONOTHING << 1, - CLSW_NEW = CLSW_FULLSCREEN << 1, - CLSW_HELP = CLSW_NEW << 1, - CLSW_DVD = CLSW_HELP << 1, - CLSW_CD = CLSW_DVD << 1, - CLSW_DEVICE = CLSW_CD << 1, - CLSW_ADD = CLSW_DEVICE << 1, - CLSW_RANDOMIZE = CLSW_ADD << 1, - CLSW_MINIMIZED = CLSW_RANDOMIZE << 1, - CLSW_REGEXTVID = CLSW_MINIMIZED << 1, - CLSW_REGEXTAUD = CLSW_REGEXTVID << 1, - CLSW_REGEXTPL = CLSW_REGEXTAUD << 1, - CLSW_UNREGEXT = CLSW_REGEXTPL << 1, - CLSW_ICONSASSOC = CLSW_UNREGEXT << 1, - CLSW_STARTVALID = CLSW_ICONSASSOC << 1, - CLSW_NOFOCUS = CLSW_STARTVALID << 1, - CLSW_FIXEDSIZE = CLSW_NOFOCUS << 1, - CLSW_MONITOR = CLSW_FIXEDSIZE << 1, - CLSW_D3DFULLSCREEN = CLSW_MONITOR << 1, - CLSW_ADMINOPTION = CLSW_D3DFULLSCREEN << 1, - CLSW_SLAVE = CLSW_ADMINOPTION << 1, - CLSW_AUDIORENDERER = CLSW_SLAVE << 1, - CLSW_RESET = CLSW_AUDIORENDERER << 1, - CLSW_PRESET1 = CLSW_RESET << 1, - CLSW_PRESET2 = CLSW_PRESET1 << 1, - CLSW_PRESET3 = CLSW_PRESET2 << 1, - CLSW_CONFIGLAVSPLITTER = CLSW_PRESET3 << 1, - CLSW_CONFIGLAVAUDIO = CLSW_CONFIGLAVSPLITTER << 1, - CLSW_CONFIGLAVVIDEO = CLSW_CONFIGLAVAUDIO << 1, - CLSW_MUTE = CLSW_CONFIGLAVVIDEO << 1, - CLSW_VOLUME = CLSW_MUTE << 1, - CLSW_THUMBNAILS = CLSW_VOLUME << 1, - CLSW_UNRECOGNIZEDSWITCH = CLSW_THUMBNAILS << 1, // 47 -}; - -enum MpcCaptionState { - MODE_SHOWCAPTIONMENU, - MODE_HIDEMENU, - MODE_FRAMEONLY, - MODE_BORDERLESS, - MODE_COUNT -}; // flags for Caption & Menu Mode - -enum { - VIDRNDT_DS_DEFAULT = 0, - VIDRNDT_DS_OVERLAYMIXER = 2, - VIDRNDT_DS_VMR9WINDOWED = 4, - VIDRNDT_DS_VMR9RENDERLESS = 6, - VIDRNDT_DS_DXR = 7, - VIDRNDT_DS_NULL_COMP = 8, - VIDRNDT_DS_NULL_UNCOMP = 9, - VIDRNDT_DS_EVR = 10, - VIDRNDT_DS_EVR_CUSTOM = 11, - VIDRNDT_DS_MADVR = 12, - VIDRNDT_DS_SYNC = 13, - VIDRNDT_DS_MPCVR = 14, -}; - -// Enumeration for MCE remote control (careful : add 0x010000 for all keys!) -enum MCE_RAW_INPUT { - MCE_DETAILS = 0x010209, - MCE_GUIDE = 0x01008D, - MCE_TVJUMP = 0x010025, - MCE_STANDBY = 0x010082, - MCE_OEM1 = 0x010080, - MCE_OEM2 = 0x010081, - MCE_MYTV = 0x010046, - MCE_MYVIDEOS = 0x01004A, - MCE_MYPICTURES = 0x010049, - MCE_MYMUSIC = 0x010047, - MCE_RECORDEDTV = 0x010048, - MCE_DVDANGLE = 0x01004B, - MCE_DVDAUDIO = 0x01004C, - MCE_DVDMENU = 0x010024, - MCE_DVDSUBTITLE = 0x01004D, - MCE_RED = 0x01005B, - MCE_GREEN = 0x01005C, - MCE_YELLOW = 0x01005D, - MCE_BLUE = 0x01005E, - MCE_MEDIA_NEXTTRACK = 0x0100B5, - MCE_MEDIA_PREVIOUSTRACK = 0x0100B6 -}; - -#define AUDRNDT_NULL_COMP _T("Null Audio Renderer (Any)") -#define AUDRNDT_NULL_UNCOMP _T("Null Audio Renderer (Uncompressed)") -#define AUDRNDT_INTERNAL _T("Internal Audio Renderer") // Use this as device name for SaneAR -#define AUDRNDT_SANEAR _T("SaneAR Audio Renderer") // This only as title -#define AUDRNDT_MPC L"MPC Audio Renderer" - - -#define DEFAULT_SUBTITLE_PATHS _T(".;.\\subtitles;.\\subs") -#define DEFAULT_JUMPDISTANCE_1 1000 -#define DEFAULT_JUMPDISTANCE_2 5000 -#define DEFAULT_JUMPDISTANCE_3 20000 - -#define MIN_AUTOFIT_SCALE_FACTOR 25 -#define MAX_AUTOFIT_SCALE_FACTOR 100 -#define DEF_MIN_AUTOFIT_SCALE_FACTOR 40 -#define DEF_MAX_AUTOFIT_SCALE_FACTOR 80 - -#define NO_FIXED_POSITION CPoint(INT_MIN, INT_MIN) - -enum dvstype { - DVS_HALF, - DVS_NORMAL, - DVS_DOUBLE, - DVS_STRETCH, - DVS_FROMINSIDE, - DVS_FROMOUTSIDE, - DVS_ZOOM1, - DVS_ZOOM2 -}; - -enum favtype { - FAV_FILE, - FAV_DVD, - FAV_DEVICE -}; - -enum { - TIME_TOOLTIP_ABOVE_SEEKBAR, - TIME_TOOLTIP_BELOW_SEEKBAR -}; - -enum DVB_RebuildFilterGraph { - DVB_REBUILD_FG_NEVER = 0, - DVB_REBUILD_FG_WHEN_SWITCHING, - DVB_REBUILD_FG_ALWAYS -}; - -enum DVB_StopFilterGraph { - DVB_STOP_FG_NEVER = 0, - DVB_STOP_FG_WHEN_SWITCHING, - DVB_STOP_FG_ALWAYS -}; - -struct ShaderC { - CString label; - CString profile; - CString srcdata; - ULONGLONG length = 0; - FILETIME ftwrite = {0,0}; - - bool Match(LPCWSTR _label, const bool _bD3D11) const { - return (label.CompareNoCase(_label) == 0 && (_bD3D11 == (profile == "ps_4_0"))); - } -}; - -struct DisplayMode { - bool bValid = false; - CSize size; - int bpp = 0, freq = 0; - DWORD dwDisplayFlags = 0; - - bool operator == (const DisplayMode& dm) const { - return (bValid == dm.bValid && size == dm.size && bpp == dm.bpp && freq == dm.freq && dwDisplayFlags == dm.dwDisplayFlags); - }; - - bool operator < (const DisplayMode& dm) const { - bool bRet = false; - - // Ignore bValid when sorting - if (size.cx < dm.size.cx) { - bRet = true; - } else if (size.cx == dm.size.cx) { - if (size.cy < dm.size.cy) { - bRet = true; - } else if (size.cy == dm.size.cy) { - if (freq < dm.freq) { - bRet = true; - } else if (freq == dm.freq) { - if (bpp < dm.bpp) { - bRet = true; - } else if (bpp == dm.bpp) { - bRet = (dwDisplayFlags & DM_INTERLACED) && !(dm.dwDisplayFlags & DM_INTERLACED); - } - } - } - } - - return bRet; - }; -}; - -struct AutoChangeMode { - AutoChangeMode(bool _bChecked, double _dFrameRateStart, double _dFrameRateStop, int _msAudioDelay, DisplayMode _dm) - : bChecked(_bChecked) - , dFrameRateStart(_dFrameRateStart) - , dFrameRateStop(_dFrameRateStop) - , msAudioDelay(_msAudioDelay) - , dm(std::move(_dm)) { - } - - bool bChecked; - double dFrameRateStart; - double dFrameRateStop; - int msAudioDelay; - DisplayMode dm; -}; - -struct AutoChangeFullscreenMode { - bool bEnabled = false; - std::vector modes; - bool bApplyDefaultModeAtFSExit = false; - bool bRestoreResAfterProgExit = true; - unsigned uDelay = 0u; -}; - -#define ACCEL_LIST_SIZE 201 - -struct wmcmd_base : public ACCEL { - BYTE mouse; - BYTE mouseVirt; - DWORD dwname; - UINT appcmd; - - enum : BYTE { - NONE, - LDOWN, - LUP, - LDBLCLK, - MDOWN, - MUP, - MDBLCLK, - RDOWN, - RUP, - RDBLCLK, - X1DOWN, - X1UP, - X1DBLCLK, - X2DOWN, - X2UP, - X2DBLCLK, - WUP, - WDOWN, - WRIGHT, - WLEFT, - LAST - }; - - wmcmd_base() - : ACCEL( { - 0, 0, 0 - }) - , mouse(NONE) - , mouseVirt(0) - , dwname(0) - , appcmd(0) {} - - constexpr wmcmd_base(WORD _cmd, WORD _key, BYTE _fVirt, DWORD _dwname, UINT _appcmd = 0, BYTE _mouse = NONE, BYTE _mouseVirt = 0) - : ACCEL{ _fVirt, _key, _cmd } - , mouse(_mouse) - , mouseVirt(_mouseVirt) - , dwname(_dwname) - , appcmd(_appcmd) {} - - constexpr wmcmd_base(const wmcmd_base&) = default; - constexpr wmcmd_base(wmcmd_base&&) = default; - wmcmd_base& operator=(const wmcmd_base&) = default; - wmcmd_base& operator=(wmcmd_base&&) = default; -}; - -class wmcmd : public wmcmd_base -{ - const wmcmd_base* default_cmd = nullptr; - -public: - CStringA rmcmd; - int rmrepcnt = 5; - - wmcmd() = default; - wmcmd& operator=(const wmcmd&) = default; - wmcmd& operator=(wmcmd&&) = default; - - explicit wmcmd(const wmcmd_base& cmd) - : wmcmd_base(cmd) - , default_cmd(&cmd) - , rmrepcnt(5) { - } - - bool operator == (const wmcmd& wc) const { - return cmd > 0 && cmd == wc.cmd; - } - - CString GetName() const { - return ResStr(dwname); - } - - void Restore() { - ASSERT(default_cmd); - *static_cast(this) = *static_cast(default_cmd); - appcmd = default_cmd->appcmd; - mouse = default_cmd->mouse; - mouseVirt = default_cmd->mouseVirt; - rmcmd.Empty(); - rmrepcnt = 5; - } - - bool IsModified() const { - ASSERT(default_cmd); - return memcmp(static_cast(this), static_cast(default_cmd), sizeof(ACCEL)) || - appcmd != default_cmd->appcmd || - mouse != default_cmd->mouse || - mouseVirt != default_cmd->mouseVirt || - !rmcmd.IsEmpty() || - rmrepcnt != 5; - } -}; - -class CRemoteCtrlClient : public CAsyncSocket -{ -protected: - CCritSec m_csLock; - CWnd* m_pWnd; - enum { - DISCONNECTED, - CONNECTED, - CONNECTING - } m_nStatus; - CString m_addr; - - virtual void OnConnect(int nErrorCode); - virtual void OnClose(int nErrorCode); - virtual void OnReceive(int nErrorCode); - - virtual void OnCommand(CStringA str) = 0; - - void ExecuteCommand(CStringA cmd, int repcnt); - -public: - CRemoteCtrlClient(); - void SetHWND(HWND hWnd); - void Connect(CString addr); - void DisConnect(); - int GetStatus() const { - return m_nStatus; - } -}; - -class CWinLircClient : public CRemoteCtrlClient -{ -protected: - virtual void OnCommand(CStringA str); - -public: - CWinLircClient(); -}; - -class CUIceClient : public CRemoteCtrlClient -{ -protected: - virtual void OnCommand(CStringA str); - -public: - CUIceClient(); -}; - -#define APPSETTINGS_VERSION 8 - -struct DVD_POSITION { - ULONGLONG llDVDGuid = 0; - ULONG lTitle = 0; - DVD_HMSF_TIMECODE timecode = { 0 }; -}; - -struct ABRepeat { - ABRepeat() : positionA(0), positionB(0), dvdTitle(-1) {} - operator bool() const { return positionA || positionB; }; - REFERENCE_TIME positionA, positionB; - ULONG dvdTitle; //whatever title they saved last will be the only one we remember -}; - -class RecentFileEntry { -public: - RecentFileEntry() {} - void InitEntry(const RecentFileEntry& r) { - hash = r.hash; - cue = r.cue; - title = r.title; - lastOpened = r.lastOpened; - filePosition = r.filePosition; - DVDPosition = r.DVDPosition; - fns.RemoveAll(); - subs.RemoveAll(); - fns.AddHeadList(&r.fns); - subs.AddHeadList(&r.subs); - abRepeat = r.abRepeat; - AudioTrackIndex = r.AudioTrackIndex; - SubtitleTrackIndex = r.SubtitleTrackIndex; - } - RecentFileEntry(const RecentFileEntry &r) { - InitEntry(r); - } - - CStringW hash; - CString title; - CString lastOpened; - CAtlList fns; - CString cue; - CAtlList subs; - REFERENCE_TIME filePosition=0; - DVD_POSITION DVDPosition = {}; - ABRepeat abRepeat; - int AudioTrackIndex = -1; - int SubtitleTrackIndex = -1; - - void operator=(const RecentFileEntry &r) { - InitEntry(r); - } -}; - -class CAppSettings -{ - bool bInitialized = false; - - 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 - - void SetSize(int nSize); - }; - - class CRecentFileListWithMoreInfo - { - public: - CRecentFileListWithMoreInfo(LPCTSTR lpszSection, int nSize) - : m_section(lpszSection) - , m_maxSize(nSize) - , current_rfe_hash(L"") - {} - - CAtlArray rfe_array; - size_t m_maxSize; - LPCTSTR m_section; - REFERENCE_TIME persistedFilePosition = 0; - CString current_rfe_hash; - int rfe_last_added = 0; - int listModifySequence = 0; - - int GetSize() { - return (int)rfe_array.GetCount(); - } - - RecentFileEntry& operator[](size_t nIndex) { - ASSERT(nIndex >= 0 && nIndex < rfe_array.GetCount()); - return rfe_array[nIndex]; - } - - //void Remove(size_t nIndex); - void Add(LPCTSTR fn); - void Add(LPCTSTR fn, ULONGLONG llDVDGuid); - void Add(RecentFileEntry r, bool current_open = false); - bool GetCurrentIndex(size_t& idx); - void UpdateCurrentFilePosition(REFERENCE_TIME time, bool forcePersist = false); - REFERENCE_TIME GetCurrentFilePosition(); - ABRepeat GetCurrentABRepeat(); - void UpdateCurrentDVDTimecode(DVD_HMSF_TIMECODE *time); - void UpdateCurrentDVDTitle(DWORD title); - DVD_POSITION GetCurrentDVDPosition(); - void UpdateCurrentAudioTrack(int audioIndex); - int GetCurrentAudioTrack(); - void UpdateCurrentSubtitleTrack(int audioIndex); - int GetCurrentSubtitleTrack(); - void AddSubToCurrent(CStringW subpath); - void SetCurrentTitle(CStringW subpath); - void UpdateCurrentABRepeat(ABRepeat abRepeat); - void WriteCurrentEntry(); - void ReadMediaHistory(); - void WriteMediaHistoryAudioIndex(RecentFileEntry& r); - void WriteMediaHistorySubtitleIndex(RecentFileEntry& r); - void WriteMediaHistoryEntry(RecentFileEntry& r, bool updateLastOpened = false); - void SaveMediaHistory(); - void ReadLegacyMediaHistory(std::map &filenameToIndex); - void ReadLegacyMediaPosition(std::map &filenameToIndex); - bool LoadMediaHistoryEntryFN(CStringW fn, RecentFileEntry& r); - bool LoadMediaHistoryEntryDVD(ULONGLONG llDVDGuid, CStringW fn, RecentFileEntry& r); - bool LoadMediaHistoryEntry(CStringW hash, RecentFileEntry& r); - void MigrateLegacyHistory(); - void SetSize(size_t nSize); - void RemoveAll(); - }; - -public: - // cmdline params - UINT64 nCLSwitches; - CAtlList slFiles, slDubs, slSubs, slFilters; - static std::map CommandIDToWMCMD; - - // Initial position (used by command line flags) - REFERENCE_TIME rtShift; - REFERENCE_TIME rtStart; - ABRepeat abRepeat; - ULONG lDVDTitle; - ULONG lDVDChapter; - DVD_HMSF_TIMECODE DVDPosition; - - CSize sizeFixedWindow; - CPoint fixedWindowPosition; - bool HasFixedWindowSize() const { - return sizeFixedWindow.cx > 0 || sizeFixedWindow.cy > 0; - } - //int iFixedWidth, iFixedHeight; - int iMonitor; - - CString ParseFileName(CString const& param); - void ParseCommandLine(CAtlList& cmdln); - - // Added a Debug display to the screen (/debug option) - bool fShowDebugInfo; - int iAdminOption; - - - // Player - bool fAllowMultipleInst; - bool fTrayIcon; - bool fShowOSD; - bool fShowCurrentTimeInOSD; - int nOSDTransparency; - int nOSDBorder; - - bool fLimitWindowProportions; - bool fSnapToDesktopEdges; - bool fHideCDROMsSubMenu; - DWORD dwPriority; - int iTitleBarTextStyle; - bool fTitleBarTextTitle; - bool fKeepHistory; - int iRecentFilesNumber; - CRecentFileListWithMoreInfo MRU; - CRecentFileAndURLList MRUDub; - bool fRememberDVDPos; - bool fRememberFilePos; - int iRememberPosForLongerThan; - bool bRememberPosForAudioFiles; - bool bRememberExternalPlaylistPos; - bool bRememberTrackSelection; - bool bRememberPlaylistItems; - bool fRememberWindowPos; - CRect rcLastWindowPos; - bool fRememberWindowSize; - bool fSavePnSZoom; - double dZoomX; - double dZoomY; - - // Formats - CMediaFormats m_Formats; - bool fAssociatedWithIcons; - - // Keys - CList wmcmds; - HACCEL hAccel; - bool fWinLirc; - CString strWinLircAddr; - CWinLircClient WinLircClient; - bool fUIce; - CString strUIceAddr; - CUIceClient UIceClient; - bool fGlobalMedia; - - // Mouse - UINT nMouseLeftClick; - bool bMouseLeftClickOpenRecent; - UINT nMouseLeftDblClick; - bool bMouseEasyMove; - UINT nMouseRightClick; - struct MOUSE_ASSIGNMENT { - UINT normal; - UINT ctrl; - UINT shift; - UINT rbtn; - }; - MOUSE_ASSIGNMENT MouseMiddleClick; - MOUSE_ASSIGNMENT MouseX1Click; - MOUSE_ASSIGNMENT MouseX2Click; - MOUSE_ASSIGNMENT MouseWheelUp; - MOUSE_ASSIGNMENT MouseWheelDown; - MOUSE_ASSIGNMENT MouseWheelLeft; - MOUSE_ASSIGNMENT MouseWheelRight; - - // Logo - int nLogoId; - bool fLogoExternal; - BOOL fLogoColorProfileEnabled; - CString strLogoFileName; - - // Web Inteface - bool fEnableWebServer; - int nWebServerPort; - int nCmdlnWebServerPort; - bool fWebServerUseCompression; - bool fWebServerLocalhostOnly; - bool bWebUIEnablePreview; - bool fWebServerPrintDebugInfo; - CString strWebRoot, strWebDefIndex; - CString strWebServerCGI; - - // Playback - int nVolume; - bool fMute; - int nBalance; - int nLoops; - bool fLoopForever; - - enum class LoopMode { - FILE, - PLAYLIST - } eLoopMode; - - bool fRememberZoomLevel; - int nAutoFitFactorMin; - int nAutoFitFactorMax; - int iZoomLevel; - CStringW strAudiosLanguageOrder; - CStringW strSubtitlesLanguageOrder; - bool fEnableWorkerThreadForOpening; - bool fReportFailedPins; - bool fAutoloadAudio; - bool fBlockVSFilter; - bool bBlockRDP; - UINT nVolumeStep; - UINT nSpeedStep; - int nDefaultToolbarSize; - bool bSaveImagePosition; - bool bSaveImageCurrentTime; - bool bAllowInaccurateFastseek; - bool bLoopFolderOnPlayNextFile; - bool bLockNoPause; - bool bPreventDisplaySleep; - bool bUseSMTC; - int iReloadAfterLongPause; - bool bOpenRecPanelWhenOpeningDevice; - - enum class AfterPlayback { - DO_NOTHING, - PLAY_NEXT, - REWIND, - MONITOROFF, - CLOSE, - EXIT - } eAfterPlayback; - - // DVD - bool fUseDVDPath; - CString strDVDPath; - LCID idMenuLang, idAudioLang, idSubtitlesLang; - bool fClosedCaptions; - - // Output - CRenderersSettings m_RenderersSettings; - int iDSVideoRendererType; - - CStringW strAudioRendererDisplayName; - bool fD3DFullscreen; - - // Fullscreen - bool fLaunchfullscreen; - bool bHideFullscreenControls; - enum class HideFullscreenControlsPolicy { - SHOW_NEVER, - SHOW_WHEN_HOVERED, - SHOW_WHEN_CURSOR_MOVED, - } eHideFullscreenControlsPolicy; - unsigned uHideFullscreenControlsDelay; - bool bHideFullscreenDockedPanels; - bool fExitFullScreenAtTheEnd; - CStringW strFullScreenMonitorID; - CStringW strFullScreenMonitorDeviceName; - AutoChangeFullscreenMode autoChangeFSMode; - - // 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; - int iBDASymbolRate; - bool fBDAUseOffset; - int iBDAOffset; - bool fBDAIgnoreEncryptedChannels; - int nDVBLastChannel; - std::vector m_DVBChannels; - DVB_RebuildFilterGraph nDVBRebuildFilterGraph; - DVB_StopFilterGraph nDVBStopFilterGraph; - - // Internal Filters - bool SrcFilters[SRC_LAST + !SRC_LAST]; - bool TraFilters[TRA_LAST + !TRA_LAST]; - - // Audio Switcher - bool 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 m_filters; - - // Subtitles - bool fOverridePlacement; - int nHorPos, nVerPos; - bool bSubtitleARCompensation; - int nSubDelayStep; - - // Default Style - STSStyle subtitlesDefStyle; - - // Misc - bool bPreferDefaultForcedSubtitles; - bool fPrioritizeExternalSubtitles; - bool fDisableInternalSubtitles; - bool bAllowOverridingExternalSplitterChoice; - bool bAutoDownloadSubtitles; - bool bAutoSaveDownloadedSubtitles; - int nAutoDownloadScoreMovies; - int nAutoDownloadScoreSeries; - CString strAutoDownloadSubtitlesExclude; - bool bAutoUploadSubtitles; - bool bPreferHearingImpairedSubtitles; -#if USE_LIBASS - bool bRenderSSAUsingLibass; - bool bRenderSRTUsingLibass; -#endif - bool bMPCTheme; - bool bWindows10DarkThemeActive; - bool bWindows10AccentColorsEnabled; - int iModernSeekbarHeight; - - CMPCTheme::ModernThemeMode eModernThemeMode; - - int iFullscreenDelay; - - enum class verticalAlignVideoType { - ALIGN_MIDDLE, - ALIGN_TOP, - ALIGN_BOTTOM - } eVerticalAlignVideoType; - verticalAlignVideoType iVerticalAlignVideo; - - CString strSubtitlesProviders; - CString strSubtitlePaths; - - // Tweaks - int nJumpDistS; - int nJumpDistM; - int nJumpDistL; - bool bFastSeek; - enum { FASTSEEK_LATEST_KEYFRAME, FASTSEEK_NEAREST_KEYFRAME } eFastSeekMethod; - bool fShowChapters; - bool bNotifySkype; - bool fPreventMinimize; - bool bUseEnhancedTaskBar; - bool fLCDSupport; - bool fSeekPreview; - int iSeekPreviewSize; - bool fUseSearchInFolder; - bool fUseSeekbarHover; - int nHoverPosition; - CString strOSDFont; - int nOSDSize; - bool bHideWindowedMousePointer; - - // Miscellaneous - int iBrightness; - int iContrast; - int iHue; - int iSaturation; - int nUpdaterAutoCheck; - int nUpdaterDelay; - - // MENUS - // View - MpcCaptionState eCaptionMenuMode; - bool fHideNavigation; - UINT nCS; // Control state for toolbars - // Language - LANGID language; - // Subtitles menu - bool fEnableSubtitles; - bool bSubtitleOverrideDefaultStyle; - bool bSubtitleOverrideAllStyles; - // Video Frame - int iDefaultVideoSize; - bool fKeepAspectRatio; - bool fCompMonDeskARDiff; - // Pan&Scan - CString strPnSPreset; - CStringArray m_pnspresets; - // On top menu - int iOnTop; - - // WINDOWS - // Add Favorite - bool bFavRememberPos; - bool bFavRelativeDrive; - bool bFavRememberABMarks; - // Save Image... - CString strSnapshotPath, strSnapshotExt; - bool bSnapShotSubtitles; - bool bSnapShotKeepVideoExtension; - // Save Thumbnails... - int iThumbRows, iThumbCols, iThumbWidth; - // Save Subtitle - bool bSubSaveExternalStyleFile; - // Shaders - bool bToggleShader; - bool bToggleShaderScreenSpace; - ShaderList m_ShadersExtraList; - ShaderSelection m_Shaders; - // Playlist (contex menu) - bool bShufflePlaylistItems; - bool bHidePlaylistFullScreen; - - // OTHER STATES - //CStringW strLastOpenDir; - UINT nLastWindowType; - WORD nLastUsedPage; - bool fRemainingTime; - bool bHighPrecisionTimer; - bool bTimerShowPercentage; - bool fLastFullScreen; - - bool fEnableEDLEditor; - - HWND hMasterWnd; - - bool bHideWindowedControls; - - int nJpegQuality; - - bool bEnableCoverArt; - int nCoverArtSizeLimit; - - bool bEnableLogging; - bool bUseLegacyToolbar; - - bool IsD3DFullscreen() const; - CString SelectedAudioRenderer() const; - bool IsISRAutoLoadEnabled() const; - bool IsInitialized() const; - static bool IsVideoRendererAvailable(int iVideoRendererType); - - CFileAssoc fileAssoc; - - CComPtr sanear; - - DWORD iLAVGPUDevice; - unsigned nCmdVolume; - - enum class SubtitleRenderer { - INTERNAL, - VS_FILTER, - XY_SUB_FILTER, - RESERVED, // unused - NONE, - }; - - SubtitleRenderer GetSubtitleRenderer() const; - void SetSubtitleRenderer(SubtitleRenderer renderer) { - eSubtitleRenderer = renderer; - } - - static bool IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer); - - static bool IsSubtitleRendererSupported(SubtitleRenderer eSubtitleRenderer, int videoRenderer); - - CSize GetAspectRatioOverride() const { - ASSERT(fKeepAspectRatio && "Keep Aspect Ratio option have to be enabled if override value is used."); - return sizeAspectRatio; - }; - void SetAspectRatioOverride(const CSize& ar) { - sizeAspectRatio = ar; - } - - // YoutubeDL settings - bool bUseYDL; - int iYDLMaxHeight; - int iYDLVideoFormat; - int iYDLAudioFormat; - bool bYDLAudioOnly; - CString sYDLExePath; - CString sYDLCommandLine; - - bool bEnableCrashReporter; - - int nStreamPosPollerInterval; - bool bShowLangInStatusbar; - bool bShowFPSInStatusbar; - bool bShowABMarksInStatusbar; - bool bShowVideoInfoInStatusbar; - bool bShowAudioFormatInStatusbar; - - bool bAddLangCodeWhenSaveSubtitles; - bool bUseTitleInRecentFileList; - bool bUseSubsFromYDL; - CString sYDLSubsPreference; - bool bUseAutomaticCaptions; - bool bUseFreeType; - bool bUseMediainfoLoadFileDuration; - bool bPauseWhileDraggingSeekbar; - CStringA strOpenTypeLangHint; - - CStringW lastQuickOpenPath; - CStringW lastFileSaveCopyPath; - CStringW lastFileOpenDirPath; - CStringW externalPlayListPath; - - int iRedirectOpenToAppendThreshold; - bool bFullscreenSeparateControls; - bool bAlwaysUseShortMenu; - int iStillVideoDuration; - int iMouseLeftUpDelay; - - bool bCaptureDeinterlace; - bool bConfirmFileDelete; - -private: - struct FilterKey { - CString name; - bool bDefault; - - FilterKey() - : name() - , bDefault(false) { - } - - FilterKey(CString name, bool bDefault) - : name(name) - , bDefault(bDefault) { - } - }; - - FilterKey SrcFiltersKeys[SRC_LAST + !SRC_LAST]; - FilterKey TraFiltersKeys[TRA_LAST + !TRA_LAST]; - - __int64 ConvertTimeToMSec(const CString& time) const; - void ExtractDVDStartPos(CString& strParam); - - void CreateCommands(); - - void SaveExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS); - void LoadExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS); - void ConvertOldExternalFiltersList(); - - void SaveSettingsAutoChangeFullScreenMode(); - - void UpdateRenderersData(bool fSave); - - SubtitleRenderer eSubtitleRenderer; - CSize sizeAspectRatio; - -public: - CAppSettings(); - CAppSettings(const CAppSettings&) = delete; - ~CAppSettings(); - - CAppSettings& operator = (const CAppSettings&) = delete; - - void SaveSettings(bool write_full_history = false); - void ClearRecentFiles(); - static void PurgeMediaHistory(size_t maxsize = 0); - static void PurgePlaylistHistory(size_t maxsize = 0); - static std::multimap LoadHistoryHashes(CStringW section, CStringW dateField); - static void PurgeExpiredHash(CStringW section, CStringW hash); - void LoadSettings(); - void SaveExternalFilters() { - if (bInitialized) { - SaveExternalFilters(m_filters); - } - }; - void UpdateSettings(); - - void SavePlayListPosition(CStringW playlistPath, UINT position); - - UINT GetSavedPlayListPosition(CStringW playlistPath); - - void SetAsUninitialized() { - bInitialized = false; - }; - - void GetFav(favtype ft, CAtlList& sl) const; - void SetFav(favtype ft, CAtlList& sl); - void AddFav(favtype ft, CString s); - - CBDAChannel* FindChannelByPref(int nPrefNumber); - - bool GetAllowMultiInst() const; - - static bool IsVSFilterInstalled(); -}; - +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#pragma once +#include "mpc-hc_config.h" +#include "../Subtitles/STS.h" +#include "../filters/switcher/AudioSwitcher/AudioSwitcher.h" +#include "../thirdparty/sanear/src/Interfaces.h" +#include "DVBChannel.h" +#include "FileAssoc.h" +#include "FilterEnum.h" +#include "MediaFormats.h" +#include "../filters/renderer/VideoRenderers/RenderersSettings.h" +#include "SettingsDefines.h" +#include "Shaders.h" +#include "../Subtitles/SubRendererSettings.h" +#include +#include +#include "CMPCTheme.h" + + +class FilterOverride; + +// flags for CAppSettings::nCS +enum { + CS_NONE = 0, + CS_SEEKBAR = 1, + CS_TOOLBAR = CS_SEEKBAR << 1, + CS_INFOBAR = CS_TOOLBAR << 1, + CS_STATSBAR = CS_INFOBAR << 1, + CS_STATUSBAR = CS_STATSBAR << 1, + CS_LAST = CS_STATUSBAR +}; + +enum : UINT64 { + CLSW_NONE = 0, + CLSW_OPEN = 1, + CLSW_PLAY = CLSW_OPEN << 1, + CLSW_CLOSE = CLSW_PLAY << 1, + CLSW_STANDBY = CLSW_CLOSE << 1, + CLSW_HIBERNATE = CLSW_STANDBY << 1, + CLSW_SHUTDOWN = CLSW_HIBERNATE << 1, + CLSW_LOGOFF = CLSW_SHUTDOWN << 1, + CLSW_LOCK = CLSW_LOGOFF << 1, + CLSW_MONITOROFF = CLSW_LOCK << 1, + CLSW_PLAYNEXT = CLSW_MONITOROFF << 1, + CLSW_DONOTHING = CLSW_PLAYNEXT << 1, + CLSW_AFTERPLAYBACK_MASK = CLSW_CLOSE | CLSW_STANDBY | CLSW_SHUTDOWN | CLSW_HIBERNATE | CLSW_LOGOFF | CLSW_LOCK | CLSW_MONITOROFF | CLSW_PLAYNEXT | CLSW_DONOTHING, + CLSW_FULLSCREEN = CLSW_DONOTHING << 1, + CLSW_NEW = CLSW_FULLSCREEN << 1, + CLSW_HELP = CLSW_NEW << 1, + CLSW_DVD = CLSW_HELP << 1, + CLSW_CD = CLSW_DVD << 1, + CLSW_DEVICE = CLSW_CD << 1, + CLSW_ADD = CLSW_DEVICE << 1, + CLSW_RANDOMIZE = CLSW_ADD << 1, + CLSW_MINIMIZED = CLSW_RANDOMIZE << 1, + CLSW_REGEXTVID = CLSW_MINIMIZED << 1, + CLSW_REGEXTAUD = CLSW_REGEXTVID << 1, + CLSW_REGEXTPL = CLSW_REGEXTAUD << 1, + CLSW_UNREGEXT = CLSW_REGEXTPL << 1, + CLSW_ICONSASSOC = CLSW_UNREGEXT << 1, + CLSW_STARTVALID = CLSW_ICONSASSOC << 1, + CLSW_NOFOCUS = CLSW_STARTVALID << 1, + CLSW_FIXEDSIZE = CLSW_NOFOCUS << 1, + CLSW_MONITOR = CLSW_FIXEDSIZE << 1, + CLSW_D3DFULLSCREEN = CLSW_MONITOR << 1, + CLSW_ADMINOPTION = CLSW_D3DFULLSCREEN << 1, + CLSW_SLAVE = CLSW_ADMINOPTION << 1, + CLSW_AUDIORENDERER = CLSW_SLAVE << 1, + CLSW_RESET = CLSW_AUDIORENDERER << 1, + CLSW_PRESET1 = CLSW_RESET << 1, + CLSW_PRESET2 = CLSW_PRESET1 << 1, + CLSW_PRESET3 = CLSW_PRESET2 << 1, + CLSW_CONFIGLAVSPLITTER = CLSW_PRESET3 << 1, + CLSW_CONFIGLAVAUDIO = CLSW_CONFIGLAVSPLITTER << 1, + CLSW_CONFIGLAVVIDEO = CLSW_CONFIGLAVAUDIO << 1, + CLSW_MUTE = CLSW_CONFIGLAVVIDEO << 1, + CLSW_VOLUME = CLSW_MUTE << 1, + CLSW_THUMBNAILS = CLSW_VOLUME << 1, + CLSW_UNRECOGNIZEDSWITCH = CLSW_THUMBNAILS << 1, // 47 +}; + +enum MpcCaptionState { + MODE_SHOWCAPTIONMENU, + MODE_HIDEMENU, + MODE_FRAMEONLY, + MODE_BORDERLESS, + MODE_COUNT +}; // flags for Caption & Menu Mode + +enum { + VIDRNDT_DS_DEFAULT = 0, + VIDRNDT_DS_OVERLAYMIXER = 2, + VIDRNDT_DS_VMR9WINDOWED = 4, + VIDRNDT_DS_VMR9RENDERLESS = 6, + VIDRNDT_DS_DXR = 7, + VIDRNDT_DS_NULL_COMP = 8, + VIDRNDT_DS_NULL_UNCOMP = 9, + VIDRNDT_DS_EVR = 10, + VIDRNDT_DS_EVR_CUSTOM = 11, + VIDRNDT_DS_MADVR = 12, + VIDRNDT_DS_SYNC = 13, + VIDRNDT_DS_MPCVR = 14, +}; + +// Enumeration for MCE remote control (careful : add 0x010000 for all keys!) +enum MCE_RAW_INPUT { + MCE_DETAILS = 0x010209, + MCE_GUIDE = 0x01008D, + MCE_TVJUMP = 0x010025, + MCE_STANDBY = 0x010082, + MCE_OEM1 = 0x010080, + MCE_OEM2 = 0x010081, + MCE_MYTV = 0x010046, + MCE_MYVIDEOS = 0x01004A, + MCE_MYPICTURES = 0x010049, + MCE_MYMUSIC = 0x010047, + MCE_RECORDEDTV = 0x010048, + MCE_DVDANGLE = 0x01004B, + MCE_DVDAUDIO = 0x01004C, + MCE_DVDMENU = 0x010024, + MCE_DVDSUBTITLE = 0x01004D, + MCE_RED = 0x01005B, + MCE_GREEN = 0x01005C, + MCE_YELLOW = 0x01005D, + MCE_BLUE = 0x01005E, + MCE_MEDIA_NEXTTRACK = 0x0100B5, + MCE_MEDIA_PREVIOUSTRACK = 0x0100B6 +}; + +#define AUDRNDT_NULL_COMP _T("Null Audio Renderer (Any)") +#define AUDRNDT_NULL_UNCOMP _T("Null Audio Renderer (Uncompressed)") +#define AUDRNDT_INTERNAL _T("Internal Audio Renderer") // Use this as device name for SaneAR +#define AUDRNDT_SANEAR _T("SaneAR Audio Renderer") // This only as title +#define AUDRNDT_MPC L"MPC Audio Renderer" + + +#define DEFAULT_SUBTITLE_PATHS _T(".;.\\subtitles;.\\subs") +#define DEFAULT_JUMPDISTANCE_1 1000 +#define DEFAULT_JUMPDISTANCE_2 5000 +#define DEFAULT_JUMPDISTANCE_3 20000 + +#define MIN_AUTOFIT_SCALE_FACTOR 25 +#define MAX_AUTOFIT_SCALE_FACTOR 100 +#define DEF_MIN_AUTOFIT_SCALE_FACTOR 40 +#define DEF_MAX_AUTOFIT_SCALE_FACTOR 80 + +#define NO_FIXED_POSITION CPoint(INT_MIN, INT_MIN) + +enum dvstype { + DVS_HALF, + DVS_NORMAL, + DVS_DOUBLE, + DVS_STRETCH, + DVS_FROMINSIDE, + DVS_FROMOUTSIDE, + DVS_ZOOM1, + DVS_ZOOM2 +}; + +enum favtype { + FAV_FILE, + FAV_DVD, + FAV_DEVICE +}; + +enum { + TIME_TOOLTIP_ABOVE_SEEKBAR, + TIME_TOOLTIP_BELOW_SEEKBAR +}; + +enum DVB_RebuildFilterGraph { + DVB_REBUILD_FG_NEVER = 0, + DVB_REBUILD_FG_WHEN_SWITCHING, + DVB_REBUILD_FG_ALWAYS +}; + +enum DVB_StopFilterGraph { + DVB_STOP_FG_NEVER = 0, + DVB_STOP_FG_WHEN_SWITCHING, + DVB_STOP_FG_ALWAYS +}; + +struct ShaderC { + CString label; + CString profile; + CString srcdata; + ULONGLONG length = 0; + FILETIME ftwrite = {0,0}; + + bool Match(LPCWSTR _label, const bool _bD3D11) const { + return (label.CompareNoCase(_label) == 0 && (_bD3D11 == (profile == "ps_4_0"))); + } +}; + +struct DisplayMode { + bool bValid = false; + CSize size; + int bpp = 0, freq = 0; + DWORD dwDisplayFlags = 0; + + bool operator == (const DisplayMode& dm) const { + return (bValid == dm.bValid && size == dm.size && bpp == dm.bpp && freq == dm.freq && dwDisplayFlags == dm.dwDisplayFlags); + }; + + bool operator < (const DisplayMode& dm) const { + bool bRet = false; + + // Ignore bValid when sorting + if (size.cx < dm.size.cx) { + bRet = true; + } else if (size.cx == dm.size.cx) { + if (size.cy < dm.size.cy) { + bRet = true; + } else if (size.cy == dm.size.cy) { + if (freq < dm.freq) { + bRet = true; + } else if (freq == dm.freq) { + if (bpp < dm.bpp) { + bRet = true; + } else if (bpp == dm.bpp) { + bRet = (dwDisplayFlags & DM_INTERLACED) && !(dm.dwDisplayFlags & DM_INTERLACED); + } + } + } + } + + return bRet; + }; +}; + +struct AutoChangeMode { + AutoChangeMode(bool _bChecked, double _dFrameRateStart, double _dFrameRateStop, int _msAudioDelay, DisplayMode _dm) + : bChecked(_bChecked) + , dFrameRateStart(_dFrameRateStart) + , dFrameRateStop(_dFrameRateStop) + , msAudioDelay(_msAudioDelay) + , dm(std::move(_dm)) { + } + + bool bChecked; + double dFrameRateStart; + double dFrameRateStop; + int msAudioDelay; + DisplayMode dm; +}; + +struct AutoChangeFullscreenMode { + bool bEnabled = false; + std::vector modes; + bool bApplyDefaultModeAtFSExit = false; + bool bRestoreResAfterProgExit = true; + unsigned uDelay = 0u; +}; + +#define ACCEL_LIST_SIZE 201 + +struct wmcmd_base : public ACCEL { + BYTE mouse; + BYTE mouseVirt; + DWORD dwname; + UINT appcmd; + + enum : BYTE { + NONE, + LDOWN, + LUP, + LDBLCLK, + MDOWN, + MUP, + MDBLCLK, + RDOWN, + RUP, + RDBLCLK, + X1DOWN, + X1UP, + X1DBLCLK, + X2DOWN, + X2UP, + X2DBLCLK, + WUP, + WDOWN, + WRIGHT, + WLEFT, + LAST + }; + + wmcmd_base() + : ACCEL( { + 0, 0, 0 + }) + , mouse(NONE) + , mouseVirt(0) + , dwname(0) + , appcmd(0) {} + + constexpr wmcmd_base(WORD _cmd, WORD _key, BYTE _fVirt, DWORD _dwname, UINT _appcmd = 0, BYTE _mouse = NONE, BYTE _mouseVirt = 0) + : ACCEL{ _fVirt, _key, _cmd } + , mouse(_mouse) + , mouseVirt(_mouseVirt) + , dwname(_dwname) + , appcmd(_appcmd) {} + + constexpr wmcmd_base(const wmcmd_base&) = default; + constexpr wmcmd_base(wmcmd_base&&) = default; + wmcmd_base& operator=(const wmcmd_base&) = default; + wmcmd_base& operator=(wmcmd_base&&) = default; +}; + +class wmcmd : public wmcmd_base +{ + const wmcmd_base* default_cmd = nullptr; + +public: + CStringA rmcmd; + int rmrepcnt = 5; + + wmcmd() = default; + wmcmd& operator=(const wmcmd&) = default; + wmcmd& operator=(wmcmd&&) = default; + + explicit wmcmd(const wmcmd_base& cmd) + : wmcmd_base(cmd) + , default_cmd(&cmd) + , rmrepcnt(5) { + } + + bool operator == (const wmcmd& wc) const { + return cmd > 0 && cmd == wc.cmd; + } + + CString GetName() const { + return ResStr(dwname); + } + + void Restore() { + ASSERT(default_cmd); + *static_cast(this) = *static_cast(default_cmd); + appcmd = default_cmd->appcmd; + mouse = default_cmd->mouse; + mouseVirt = default_cmd->mouseVirt; + rmcmd.Empty(); + rmrepcnt = 5; + } + + bool IsModified() const { + ASSERT(default_cmd); + return memcmp(static_cast(this), static_cast(default_cmd), sizeof(ACCEL)) || + appcmd != default_cmd->appcmd || + mouse != default_cmd->mouse || + mouseVirt != default_cmd->mouseVirt || + !rmcmd.IsEmpty() || + rmrepcnt != 5; + } +}; + +class CRemoteCtrlClient : public CAsyncSocket +{ +protected: + CCritSec m_csLock; + CWnd* m_pWnd; + enum { + DISCONNECTED, + CONNECTED, + CONNECTING + } m_nStatus; + CString m_addr; + + virtual void OnConnect(int nErrorCode); + virtual void OnClose(int nErrorCode); + virtual void OnReceive(int nErrorCode); + + virtual void OnCommand(CStringA str) = 0; + + void ExecuteCommand(CStringA cmd, int repcnt); + +public: + CRemoteCtrlClient(); + void SetHWND(HWND hWnd); + void Connect(CString addr); + void DisConnect(); + int GetStatus() const { + return m_nStatus; + } +}; + +class CWinLircClient : public CRemoteCtrlClient +{ +protected: + virtual void OnCommand(CStringA str); + +public: + CWinLircClient(); +}; + +class CUIceClient : public CRemoteCtrlClient +{ +protected: + virtual void OnCommand(CStringA str); + +public: + CUIceClient(); +}; + +#define APPSETTINGS_VERSION 8 + +struct DVD_POSITION { + ULONGLONG llDVDGuid = 0; + ULONG lTitle = 0; + DVD_HMSF_TIMECODE timecode = { 0 }; +}; + +struct ABRepeat { + ABRepeat() : positionA(0), positionB(0), dvdTitle(-1) {} + operator bool() const { return positionA || positionB; }; + REFERENCE_TIME positionA, positionB; + ULONG dvdTitle; //whatever title they saved last will be the only one we remember +}; + +class RecentFileEntry { +public: + RecentFileEntry() {} + void InitEntry(const RecentFileEntry& r) { + hash = r.hash; + cue = r.cue; + title = r.title; + lastOpened = r.lastOpened; + filePosition = r.filePosition; + DVDPosition = r.DVDPosition; + fns.RemoveAll(); + subs.RemoveAll(); + fns.AddHeadList(&r.fns); + subs.AddHeadList(&r.subs); + abRepeat = r.abRepeat; + AudioTrackIndex = r.AudioTrackIndex; + SubtitleTrackIndex = r.SubtitleTrackIndex; + } + RecentFileEntry(const RecentFileEntry &r) { + InitEntry(r); + } + + CStringW hash; + CString title; + CString lastOpened; + CAtlList fns; + CString cue; + CAtlList subs; + REFERENCE_TIME filePosition=0; + DVD_POSITION DVDPosition = {}; + ABRepeat abRepeat; + int AudioTrackIndex = -1; + int SubtitleTrackIndex = -1; + + void operator=(const RecentFileEntry &r) { + InitEntry(r); + } +}; + +class CAppSettings +{ + bool bInitialized = false; + + 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 + + void SetSize(int nSize); + }; + + class CRecentFileListWithMoreInfo + { + public: + CRecentFileListWithMoreInfo(LPCTSTR lpszSection, int nSize) + : m_section(lpszSection) + , m_maxSize(nSize) + , current_rfe_hash(L"") + {} + + CAtlArray rfe_array; + size_t m_maxSize; + LPCTSTR m_section; + REFERENCE_TIME persistedFilePosition = 0; + CString current_rfe_hash; + int rfe_last_added = 0; + int listModifySequence = 0; + + int GetSize() { + return (int)rfe_array.GetCount(); + } + + RecentFileEntry& operator[](size_t nIndex) { + ASSERT(nIndex >= 0 && nIndex < rfe_array.GetCount()); + return rfe_array[nIndex]; + } + + //void Remove(size_t nIndex); + void Add(LPCTSTR fn); + void Add(LPCTSTR fn, ULONGLONG llDVDGuid); + void Add(RecentFileEntry r, bool current_open = false); + bool GetCurrentIndex(size_t& idx); + void UpdateCurrentFilePosition(REFERENCE_TIME time, bool forcePersist = false); + REFERENCE_TIME GetCurrentFilePosition(); + ABRepeat GetCurrentABRepeat(); + void UpdateCurrentDVDTimecode(DVD_HMSF_TIMECODE *time); + void UpdateCurrentDVDTitle(DWORD title); + DVD_POSITION GetCurrentDVDPosition(); + void UpdateCurrentAudioTrack(int audioIndex); + int GetCurrentAudioTrack(); + void UpdateCurrentSubtitleTrack(int audioIndex); + int GetCurrentSubtitleTrack(); + void AddSubToCurrent(CStringW subpath); + void SetCurrentTitle(CStringW subpath); + void UpdateCurrentABRepeat(ABRepeat abRepeat); + void WriteCurrentEntry(); + void ReadMediaHistory(); + void WriteMediaHistoryAudioIndex(RecentFileEntry& r); + void WriteMediaHistorySubtitleIndex(RecentFileEntry& r); + void WriteMediaHistoryEntry(RecentFileEntry& r, bool updateLastOpened = false); + void SaveMediaHistory(); + void ReadLegacyMediaHistory(std::map &filenameToIndex); + void ReadLegacyMediaPosition(std::map &filenameToIndex); + bool LoadMediaHistoryEntryFN(CStringW fn, RecentFileEntry& r); + bool LoadMediaHistoryEntryDVD(ULONGLONG llDVDGuid, CStringW fn, RecentFileEntry& r); + bool LoadMediaHistoryEntry(CStringW hash, RecentFileEntry& r); + void MigrateLegacyHistory(); + void SetSize(size_t nSize); + void RemoveAll(); + }; + +public: + // cmdline params + UINT64 nCLSwitches; + CAtlList slFiles, slDubs, slSubs, slFilters; + static std::map CommandIDToWMCMD; + + // Initial position (used by command line flags) + REFERENCE_TIME rtShift; + REFERENCE_TIME rtStart; + ABRepeat abRepeat; + ULONG lDVDTitle; + ULONG lDVDChapter; + DVD_HMSF_TIMECODE DVDPosition; + + CSize sizeFixedWindow; + CPoint fixedWindowPosition; + bool HasFixedWindowSize() const { + return sizeFixedWindow.cx > 0 || sizeFixedWindow.cy > 0; + } + //int iFixedWidth, iFixedHeight; + int iMonitor; + + CString ParseFileName(CString const& param); + void ParseCommandLine(CAtlList& cmdln); + + // Added a Debug display to the screen (/debug option) + bool fShowDebugInfo; + int iAdminOption; + + + // Player + bool fAllowMultipleInst; + bool fTrayIcon; + bool fShowOSD; + bool fShowCurrentTimeInOSD; + int nOSDTransparency; + int nOSDBorder; + + bool fLimitWindowProportions; + bool fSnapToDesktopEdges; + bool fHideCDROMsSubMenu; + DWORD dwPriority; + int iTitleBarTextStyle; + bool fTitleBarTextTitle; + bool fKeepHistory; + int iRecentFilesNumber; + CRecentFileListWithMoreInfo MRU; + CRecentFileAndURLList MRUDub; + bool fRememberDVDPos; + bool fRememberFilePos; + int iRememberPosForLongerThan; + bool bRememberPosForAudioFiles; + bool bRememberExternalPlaylistPos; + bool bRememberTrackSelection; + bool bRememberPlaylistItems; + bool fRememberWindowPos; + CRect rcLastWindowPos; + bool fRememberWindowSize; + bool fSavePnSZoom; + double dZoomX; + double dZoomY; + + // Formats + CMediaFormats m_Formats; + bool fAssociatedWithIcons; + + // Keys + CList wmcmds; + HACCEL hAccel; + bool fWinLirc; + CString strWinLircAddr; + CWinLircClient WinLircClient; + bool fUIce; + CString strUIceAddr; + CUIceClient UIceClient; + bool fGlobalMedia; + + // Mouse + UINT nMouseLeftClick; + bool bMouseLeftClickOpenRecent; + UINT nMouseLeftDblClick; + bool bMouseEasyMove; + UINT nMouseRightClick; + struct MOUSE_ASSIGNMENT { + UINT normal; + UINT ctrl; + UINT shift; + UINT rbtn; + }; + MOUSE_ASSIGNMENT MouseMiddleClick; + MOUSE_ASSIGNMENT MouseX1Click; + MOUSE_ASSIGNMENT MouseX2Click; + MOUSE_ASSIGNMENT MouseWheelUp; + MOUSE_ASSIGNMENT MouseWheelDown; + MOUSE_ASSIGNMENT MouseWheelLeft; + MOUSE_ASSIGNMENT MouseWheelRight; + + // Logo + int nLogoId; + bool fLogoExternal; + BOOL fLogoColorProfileEnabled; + CString strLogoFileName; + + // Web Inteface + bool fEnableWebServer; + int nWebServerPort; + int nCmdlnWebServerPort; + bool fWebServerUseCompression; + bool fWebServerLocalhostOnly; + bool bWebUIEnablePreview; + bool fWebServerPrintDebugInfo; + CString strWebRoot, strWebDefIndex; + CString strWebServerCGI; + + // Playback + int nVolume; + bool fMute; + int nBalance; + int nLoops; + bool fLoopForever; + + enum class LoopMode { + FILE, + PLAYLIST + } eLoopMode; + + bool fRememberZoomLevel; + int nAutoFitFactorMin; + int nAutoFitFactorMax; + int iZoomLevel; + CStringW strAudiosLanguageOrder; + CStringW strSubtitlesLanguageOrder; + bool fEnableWorkerThreadForOpening; + bool fReportFailedPins; + bool fAutoloadAudio; + bool fBlockVSFilter; + bool bBlockRDP; + UINT nVolumeStep; + UINT nSpeedStep; + int nDefaultToolbarSize; + bool bSaveImagePosition; + bool bSaveImageCurrentTime; + bool bAllowInaccurateFastseek; + bool bLoopFolderOnPlayNextFile; + bool bLockNoPause; + bool bPreventDisplaySleep; + bool bUseSMTC; + int iReloadAfterLongPause; + bool bOpenRecPanelWhenOpeningDevice; + + enum class AfterPlayback { + DO_NOTHING, + PLAY_NEXT, + REWIND, + MONITOROFF, + CLOSE, + EXIT + } eAfterPlayback; + + // DVD + bool fUseDVDPath; + CString strDVDPath; + LCID idMenuLang, idAudioLang, idSubtitlesLang; + bool fClosedCaptions; + + // Output + CRenderersSettings m_RenderersSettings; + int iDSVideoRendererType; + + CStringW strAudioRendererDisplayName; + bool fD3DFullscreen; + + // Fullscreen + bool fLaunchfullscreen; + bool bHideFullscreenControls; + enum class HideFullscreenControlsPolicy { + SHOW_NEVER, + SHOW_WHEN_HOVERED, + SHOW_WHEN_CURSOR_MOVED, + } eHideFullscreenControlsPolicy; + unsigned uHideFullscreenControlsDelay; + bool bHideFullscreenDockedPanels; + bool fExitFullScreenAtTheEnd; + CStringW strFullScreenMonitorID; + CStringW strFullScreenMonitorDeviceName; + AutoChangeFullscreenMode autoChangeFSMode; + + // 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; + int iBDASymbolRate; + bool fBDAUseOffset; + int iBDAOffset; + bool fBDAIgnoreEncryptedChannels; + int nDVBLastChannel; + std::vector m_DVBChannels; + DVB_RebuildFilterGraph nDVBRebuildFilterGraph; + DVB_StopFilterGraph nDVBStopFilterGraph; + + // Internal Filters + bool SrcFilters[SRC_LAST + !SRC_LAST]; + bool TraFilters[TRA_LAST + !TRA_LAST]; + + // Audio Switcher + bool 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 m_filters; + + // Subtitles + bool fOverridePlacement; + int nHorPos, nVerPos; + bool bSubtitleARCompensation; + int nSubDelayStep; + + // Default Style + STSStyle subtitlesDefStyle; + + // Misc + bool bPreferDefaultForcedSubtitles; + bool fPrioritizeExternalSubtitles; + bool fDisableInternalSubtitles; + bool bAllowOverridingExternalSplitterChoice; + bool bAutoDownloadSubtitles; + bool bAutoSaveDownloadedSubtitles; + int nAutoDownloadScoreMovies; + int nAutoDownloadScoreSeries; + CString strAutoDownloadSubtitlesExclude; + bool bAutoUploadSubtitles; + bool bPreferHearingImpairedSubtitles; +#if USE_LIBASS + bool bRenderSSAUsingLibass; + bool bRenderSRTUsingLibass; +#endif + bool bMPCTheme; + bool bWindows10DarkThemeActive; + bool bWindows10AccentColorsEnabled; + int iModernSeekbarHeight; + + CMPCTheme::ModernThemeMode eModernThemeMode; + + int iFullscreenDelay; + + enum class verticalAlignVideoType { + ALIGN_MIDDLE, + ALIGN_TOP, + ALIGN_BOTTOM + } eVerticalAlignVideoType; + verticalAlignVideoType iVerticalAlignVideo; + + CString strSubtitlesProviders; + CString strSubtitlePaths; + + // Tweaks + int nJumpDistS; + int nJumpDistM; + int nJumpDistL; + bool bFastSeek; + enum { FASTSEEK_LATEST_KEYFRAME, FASTSEEK_NEAREST_KEYFRAME } eFastSeekMethod; + bool fShowChapters; + bool bNotifySkype; + bool fPreventMinimize; + bool bUseEnhancedTaskBar; + bool fLCDSupport; + bool fSeekPreview; + int iSeekPreviewSize; + bool fUseSearchInFolder; + bool fUseSeekbarHover; + int nHoverPosition; + CString strOSDFont; + int nOSDSize; + bool bHideWindowedMousePointer; + + // Miscellaneous + int iBrightness; + int iContrast; + int iHue; + int iSaturation; + int nUpdaterAutoCheck; + int nUpdaterDelay; + + // MENUS + // View + MpcCaptionState eCaptionMenuMode; + bool fHideNavigation; + UINT nCS; // Control state for toolbars + // Language + LANGID language; + // Subtitles menu + bool fEnableSubtitles; + bool bSubtitleOverrideDefaultStyle; + bool bSubtitleOverrideAllStyles; + // Video Frame + int iDefaultVideoSize; + bool fKeepAspectRatio; + bool fCompMonDeskARDiff; + // Pan&Scan + CString strPnSPreset; + CStringArray m_pnspresets; + // On top menu + int iOnTop; + + // WINDOWS + // Add Favorite + bool bFavRememberPos; + bool bFavRelativeDrive; + bool bFavRememberABMarks; + // Save Image... + CString strSnapshotPath, strSnapshotExt; + bool bSnapShotSubtitles; + bool bSnapShotKeepVideoExtension; + // Save Thumbnails... + int iThumbRows, iThumbCols, iThumbWidth; + // Save Subtitle + bool bSubSaveExternalStyleFile; + // Shaders + bool bToggleShader; + bool bToggleShaderScreenSpace; + ShaderList m_ShadersExtraList; + ShaderSelection m_Shaders; + // Playlist (contex menu) + bool bShufflePlaylistItems; + bool bHidePlaylistFullScreen; + + // OTHER STATES + //CStringW strLastOpenDir; + UINT nLastWindowType; + WORD nLastUsedPage; + bool fRemainingTime; + bool bHighPrecisionTimer; + bool bTimerShowPercentage; + bool fLastFullScreen; + + bool fEnableEDLEditor; + + HWND hMasterWnd; + + bool bHideWindowedControls; + + int nJpegQuality; + + bool bEnableCoverArt; + int nCoverArtSizeLimit; + + bool bEnableLogging; + bool bUseLegacyToolbar; + + bool IsD3DFullscreen() const; + CString SelectedAudioRenderer() const; + bool IsISRAutoLoadEnabled() const; + bool IsInitialized() const; + static bool IsVideoRendererAvailable(int iVideoRendererType); + + CFileAssoc fileAssoc; + + CComPtr sanear; + + DWORD iLAVGPUDevice; + unsigned nCmdVolume; + + enum class SubtitleRenderer { + INTERNAL, + VS_FILTER, + XY_SUB_FILTER, + RESERVED, // unused + NONE, + }; + + SubtitleRenderer GetSubtitleRenderer() const; + void SetSubtitleRenderer(SubtitleRenderer renderer) { + eSubtitleRenderer = renderer; + } + + static bool IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer); + + static bool IsSubtitleRendererSupported(SubtitleRenderer eSubtitleRenderer, int videoRenderer); + + CSize GetAspectRatioOverride() const { + ASSERT(fKeepAspectRatio && "Keep Aspect Ratio option have to be enabled if override value is used."); + return sizeAspectRatio; + }; + void SetAspectRatioOverride(const CSize& ar) { + sizeAspectRatio = ar; + } + + // YoutubeDL settings + bool bUseYDL; + int iYDLMaxHeight; + int iYDLVideoFormat; + int iYDLAudioFormat; + bool bYDLAudioOnly; + CString sYDLExePath; + CString sYDLCommandLine; + + bool bEnableCrashReporter; + + int nStreamPosPollerInterval; + bool bShowLangInStatusbar; + bool bShowFPSInStatusbar; + bool bShowABMarksInStatusbar; + bool bShowVideoInfoInStatusbar; + bool bShowAudioFormatInStatusbar; + + bool bAddLangCodeWhenSaveSubtitles; + bool bUseTitleInRecentFileList; + bool bUseSubsFromYDL; + CString sYDLSubsPreference; + bool bUseAutomaticCaptions; + bool bUseFreeType; + bool bUseMediainfoLoadFileDuration; + bool bPauseWhileDraggingSeekbar; + CStringA strOpenTypeLangHint; + + CStringW lastQuickOpenPath; + CStringW lastFileSaveCopyPath; + CStringW lastFileOpenDirPath; + CStringW externalPlayListPath; + + int iRedirectOpenToAppendThreshold; + bool bFullscreenSeparateControls; + bool bAlwaysUseShortMenu; + int iStillVideoDuration; + int iMouseLeftUpDelay; + + bool bCaptureDeinterlace; + bool bConfirmFileDelete; + +private: + struct FilterKey { + CString name; + bool bDefault; + + FilterKey() + : name() + , bDefault(false) { + } + + FilterKey(CString name, bool bDefault) + : name(name) + , bDefault(bDefault) { + } + }; + + FilterKey SrcFiltersKeys[SRC_LAST + !SRC_LAST]; + FilterKey TraFiltersKeys[TRA_LAST + !TRA_LAST]; + + __int64 ConvertTimeToMSec(const CString& time) const; + void ExtractDVDStartPos(CString& strParam); + + void CreateCommands(); + + void SaveExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS); + void LoadExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS); + void ConvertOldExternalFiltersList(); + + void SaveSettingsAutoChangeFullScreenMode(); + + void UpdateRenderersData(bool fSave); + + SubtitleRenderer eSubtitleRenderer; + CSize sizeAspectRatio; + +public: + CAppSettings(); + CAppSettings(const CAppSettings&) = delete; + ~CAppSettings(); + + CAppSettings& operator = (const CAppSettings&) = delete; + + void SaveSettings(bool write_full_history = false); + void ClearRecentFiles(); + static void PurgeMediaHistory(size_t maxsize = 0); + static void PurgePlaylistHistory(size_t maxsize = 0); + static std::multimap LoadHistoryHashes(CStringW section, CStringW dateField); + static void PurgeExpiredHash(CStringW section, CStringW hash); + void LoadSettings(); + void SaveExternalFilters() { + if (bInitialized) { + SaveExternalFilters(m_filters); + } + }; + void UpdateSettings(); + + void SavePlayListPosition(CStringW playlistPath, UINT position); + + UINT GetSavedPlayListPosition(CStringW playlistPath); + + void SetAsUninitialized() { + bInitialized = false; + }; + + void GetFav(favtype ft, CAtlList& sl) const; + void SetFav(favtype ft, CAtlList& sl); + void AddFav(favtype ft, CString s); + + CBDAChannel* FindChannelByPref(int nPrefNumber); + + bool GetAllowMultiInst() const; + + static bool IsVSFilterInstalled(); +}; + diff --git a/src/mpc-hc/AuthDlg.cpp b/src/mpc-hc/AuthDlg.cpp index ddb06bd249f..f31ba0fbf36 100644 --- a/src/mpc-hc/AuthDlg.cpp +++ b/src/mpc-hc/AuthDlg.cpp @@ -1,92 +1,92 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "AuthDlg.h" - -// We need to dynamically link to the functions provided by CredUI.lib in order -// to be able to use the features available to the OS. -#include -#include "WinApiFunc.h" - -HRESULT PromptForCredentials(HWND hWnd, const CString& strCaptionText, const CString& strMessageText, CString& strDomain, CString& strUsername, CString& strPassword, BOOL* bSave) -{ - CREDUI_INFO info = { sizeof(info) }; - info.hwndParent = hWnd; - info.pszCaptionText = strCaptionText.Left(CREDUI_MAX_CAPTION_LENGTH); - info.pszMessageText = strMessageText.Left(CREDUI_MAX_MESSAGE_LENGTH); - - DWORD dwUsername = CREDUI_MAX_USERNAME_LENGTH + 1; - DWORD dwPassword = CREDUI_MAX_PASSWORD_LENGTH + 1; - DWORD dwDomain = CREDUI_MAX_GENERIC_TARGET_LENGTH + 1; - - // Define CredUI.dll functions for Windows Vista+ - const WinapiFunc - fnCredPackAuthenticationBufferW = { _T("CREDUI.DLL"), "CredPackAuthenticationBufferW" }; - - const WinapiFunc - fnCredUIPromptForWindowsCredentialsW = { _T("CREDUI.DLL"), "CredUIPromptForWindowsCredentialsW" }; - - const WinapiFunc - fnCredUnPackAuthenticationBufferW = { _T("CREDUI.DLL"), "CredUnPackAuthenticationBufferW" }; - - if (fnCredPackAuthenticationBufferW && fnCredUIPromptForWindowsCredentialsW && fnCredUnPackAuthenticationBufferW) { - PVOID pvInAuthBlob = nullptr; - ULONG cbInAuthBlob = 0; - PVOID pvAuthBlob = nullptr; - ULONG cbAuthBlob = 0; - ULONG ulAuthPackage = 0; - - // Call CredPackAuthenticationBufferW once to determine the size, in bytes, of the authentication buffer. - if (strUsername.GetLength()) { - BOOL bResult = fnCredPackAuthenticationBufferW(0, (LPTSTR)(LPCTSTR)strUsername, (LPTSTR)(LPCTSTR)strPassword, nullptr, &cbInAuthBlob); - if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - if ((pvInAuthBlob = CoTaskMemAlloc(cbInAuthBlob)) != nullptr) { - VERIFY(fnCredPackAuthenticationBufferW(0, (LPTSTR)(LPCTSTR)strUsername, (LPTSTR)(LPCTSTR)strPassword, (PBYTE)pvInAuthBlob, &cbInAuthBlob)); - } - } - } - const DWORD dwFlags = CREDUIWIN_GENERIC | CREDUIWIN_ENUMERATE_CURRENT_USER | (bSave ? CREDUIWIN_CHECKBOX : 0); - DWORD dwResult = fnCredUIPromptForWindowsCredentialsW(&info, 0, &ulAuthPackage, pvInAuthBlob, cbInAuthBlob, &pvAuthBlob, &cbAuthBlob, bSave, dwFlags); - if (dwResult == ERROR_SUCCESS) { - VERIFY(fnCredUnPackAuthenticationBufferW(0, pvAuthBlob, cbAuthBlob, strUsername.GetBufferSetLength(dwUsername), &dwUsername, strDomain.GetBufferSetLength(dwDomain), &dwDomain, strPassword.GetBufferSetLength(dwPassword), &dwPassword)); - strUsername.ReleaseBuffer(); - strPassword.ReleaseBuffer(); - strDomain.ReleaseBuffer(); - } - - // Delete the input authentication byte array. - if (pvInAuthBlob) { - SecureZeroMemory(pvInAuthBlob, cbInAuthBlob); - CoTaskMemFree(pvInAuthBlob); - pvInAuthBlob = nullptr; - } - // Delete the output authentication byte array. - if (pvAuthBlob) { - SecureZeroMemory(pvAuthBlob, cbAuthBlob); - CoTaskMemFree(pvAuthBlob); - pvAuthBlob = nullptr; - } - return dwResult; // ERROR_SUCCESS / ERROR_CANCELLED - } - - return ERROR_CALL_NOT_IMPLEMENTED; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "AuthDlg.h" + +// We need to dynamically link to the functions provided by CredUI.lib in order +// to be able to use the features available to the OS. +#include +#include "WinApiFunc.h" + +HRESULT PromptForCredentials(HWND hWnd, const CString& strCaptionText, const CString& strMessageText, CString& strDomain, CString& strUsername, CString& strPassword, BOOL* bSave) +{ + CREDUI_INFO info = { sizeof(info) }; + info.hwndParent = hWnd; + info.pszCaptionText = strCaptionText.Left(CREDUI_MAX_CAPTION_LENGTH); + info.pszMessageText = strMessageText.Left(CREDUI_MAX_MESSAGE_LENGTH); + + DWORD dwUsername = CREDUI_MAX_USERNAME_LENGTH + 1; + DWORD dwPassword = CREDUI_MAX_PASSWORD_LENGTH + 1; + DWORD dwDomain = CREDUI_MAX_GENERIC_TARGET_LENGTH + 1; + + // Define CredUI.dll functions for Windows Vista+ + const WinapiFunc + fnCredPackAuthenticationBufferW = { _T("CREDUI.DLL"), "CredPackAuthenticationBufferW" }; + + const WinapiFunc + fnCredUIPromptForWindowsCredentialsW = { _T("CREDUI.DLL"), "CredUIPromptForWindowsCredentialsW" }; + + const WinapiFunc + fnCredUnPackAuthenticationBufferW = { _T("CREDUI.DLL"), "CredUnPackAuthenticationBufferW" }; + + if (fnCredPackAuthenticationBufferW && fnCredUIPromptForWindowsCredentialsW && fnCredUnPackAuthenticationBufferW) { + PVOID pvInAuthBlob = nullptr; + ULONG cbInAuthBlob = 0; + PVOID pvAuthBlob = nullptr; + ULONG cbAuthBlob = 0; + ULONG ulAuthPackage = 0; + + // Call CredPackAuthenticationBufferW once to determine the size, in bytes, of the authentication buffer. + if (strUsername.GetLength()) { + BOOL bResult = fnCredPackAuthenticationBufferW(0, (LPTSTR)(LPCTSTR)strUsername, (LPTSTR)(LPCTSTR)strPassword, nullptr, &cbInAuthBlob); + if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + if ((pvInAuthBlob = CoTaskMemAlloc(cbInAuthBlob)) != nullptr) { + VERIFY(fnCredPackAuthenticationBufferW(0, (LPTSTR)(LPCTSTR)strUsername, (LPTSTR)(LPCTSTR)strPassword, (PBYTE)pvInAuthBlob, &cbInAuthBlob)); + } + } + } + const DWORD dwFlags = CREDUIWIN_GENERIC | CREDUIWIN_ENUMERATE_CURRENT_USER | (bSave ? CREDUIWIN_CHECKBOX : 0); + DWORD dwResult = fnCredUIPromptForWindowsCredentialsW(&info, 0, &ulAuthPackage, pvInAuthBlob, cbInAuthBlob, &pvAuthBlob, &cbAuthBlob, bSave, dwFlags); + if (dwResult == ERROR_SUCCESS) { + VERIFY(fnCredUnPackAuthenticationBufferW(0, pvAuthBlob, cbAuthBlob, strUsername.GetBufferSetLength(dwUsername), &dwUsername, strDomain.GetBufferSetLength(dwDomain), &dwDomain, strPassword.GetBufferSetLength(dwPassword), &dwPassword)); + strUsername.ReleaseBuffer(); + strPassword.ReleaseBuffer(); + strDomain.ReleaseBuffer(); + } + + // Delete the input authentication byte array. + if (pvInAuthBlob) { + SecureZeroMemory(pvInAuthBlob, cbInAuthBlob); + CoTaskMemFree(pvInAuthBlob); + pvInAuthBlob = nullptr; + } + // Delete the output authentication byte array. + if (pvAuthBlob) { + SecureZeroMemory(pvAuthBlob, cbAuthBlob); + CoTaskMemFree(pvAuthBlob); + pvAuthBlob = nullptr; + } + return dwResult; // ERROR_SUCCESS / ERROR_CANCELLED + } + + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/src/mpc-hc/AuthDlg.h b/src/mpc-hc/AuthDlg.h index 288c4bd384e..b440df5e63b 100644 --- a/src/mpc-hc/AuthDlg.h +++ b/src/mpc-hc/AuthDlg.h @@ -1,26 +1,26 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include - -HRESULT PromptForCredentials(HWND hWnd, const CString& strCaptionText, const CString& strMessageText, CString& strDomain, CString& strUsername, CString& strPassword, BOOL* bSave); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include + +HRESULT PromptForCredentials(HWND hWnd, const CString& strCaptionText, const CString& strMessageText, CString& strDomain, CString& strUsername, CString& strPassword, BOOL* bSave); diff --git a/src/mpc-hc/BaseGraph.cpp b/src/mpc-hc/BaseGraph.cpp index c5d117c7c20..f77ed1a0f99 100644 --- a/src/mpc-hc/BaseGraph.cpp +++ b/src/mpc-hc/BaseGraph.cpp @@ -1,909 +1,909 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "BaseGraph.h" -#include "DSUtil.h" - - -// -// CPlayerWindow -// - -BOOL CPlayerWindow::PreCreateWindow(CREATESTRUCT& cs) -{ - if (!CWnd::PreCreateWindow(cs)) { - return FALSE; - } - - cs.style &= ~WS_BORDER; - cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, - ::LoadCursor(nullptr, IDC_HAND), nullptr, nullptr); - - return TRUE; -} - -BEGIN_MESSAGE_MAP(CPlayerWindow, CWnd) - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -BOOL CPlayerWindow::OnEraseBkgnd(CDC* pDC) -{ - for (CWnd* pChild = GetWindow(GW_CHILD); pChild; pChild = pChild->GetNextWindow()) { - if (!pChild->IsWindowVisible()) { - continue; - } - - CRect r; - pChild->GetClientRect(&r); - pChild->MapWindowPoints(this, &r); - pDC->ExcludeClipRect(&r); - } - - CRect r; - GetClientRect(&r); - pDC->FillSolidRect(&r, 0); - - return TRUE; -} - -// -// CBaseGraph -// - -CBaseGraph::CBaseGraph() - : CUnknown(NAME("CBaseGraph"), nullptr) - , m_hNotifyWnd(0) - , m_lNotifyMsg(0) - , m_lNotifyInstData(0) -{ -} - -CBaseGraph::~CBaseGraph() -{ -} - -STDMETHODIMP CBaseGraph::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFilterGraph) - QI(IGraphBuilder) - QI(IFilterGraph2) - QI(IGraphBuilder2) - QI(IMediaControl) - QI(IMediaSeeking) - QI(IMediaEventEx) - QI(IVideoWindow) - QI(IBasicVideo) - QI(IBasicAudio) - QI(IAMOpenProgress) - QI(IGraphEngine) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CBaseGraph::ClearMessageQueue() -{ - while (!m_msgqueue.IsEmpty()) { - GMSG msg = m_msgqueue.RemoveHead(); - FreeEventParams(msg.m_lEventCode, msg.m_lParam1, msg.m_lParam2); - } -} - -void CBaseGraph::NotifyEvent(long lEventCode, LONG_PTR lParam1, LONG_PTR lParam2) -{ - if (!m_hNotifyWnd) { - return; - } - - GMSG msg; - msg.m_lEventCode = lEventCode; - msg.m_lParam1 = lParam1; - msg.m_lParam2 = lParam2; - m_msgqueue.AddTail(msg); - - PostMessage((HWND)m_hNotifyWnd, m_lNotifyMsg, (WPARAM)0, m_lNotifyInstData); -} - -// IDispatch -STDMETHODIMP CBaseGraph::GetTypeInfoCount(UINT* pctinfo) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) -{ - return E_NOTIMPL; -} - -// IFilterGraph -STDMETHODIMP CBaseGraph::AddFilter(IBaseFilter* pFilter, LPCWSTR pName) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RemoveFilter(IBaseFilter* pFilter) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::EnumFilters(IEnumFilters** ppEnum) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConnectDirect(IPin* ppinOut, IPin* ppinIn, const AM_MEDIA_TYPE* pmt) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Reconnect(IPin* ppin) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Disconnect(IPin* ppin) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetDefaultSyncSource() -{ - return E_NOTIMPL; -} - -// IGraphBuilder -STDMETHODIMP CBaseGraph::Connect(IPin* ppinOut, IPin* ppinIn) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Render(IPin* ppinOut) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - *ppFilter = nullptr; - return RenderFile(lpcwstrFileName, nullptr); -}//E_NOTIMPL;} - -STDMETHODIMP CBaseGraph::SetLogFile(DWORD_PTR hFile) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Abort() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ShouldOperationContinue() -{ - return E_NOTIMPL; -} - -// IFilterGraph2 -STDMETHODIMP CBaseGraph::AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext) -{ - return E_NOTIMPL; -} - -// IGraphBuilder2 -STDMETHODIMP CBaseGraph::IsPinDirection(IPin* pPin, PIN_DIRECTION dir) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::IsPinConnected(IPin* pPin) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConnectFilter(IBaseFilter* pBF, IPin* pPinIn) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConnectFilter(IPin* pPinOut, IBaseFilter* pBF) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::NukeDownstream(IUnknown* pUnk) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::FindInterface(REFIID iid, void** ppv, BOOL bRemove) -{ - return QueryInterface(iid, ppv); -} - -STDMETHODIMP CBaseGraph::AddToROT() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RemoveFromROT() -{ - return E_NOTIMPL; -} - -// IMediaControl -STDMETHODIMP CBaseGraph::Run() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Pause() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Stop() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetState(LONG msTimeout, OAFilterState* pfs) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RenderFile(BSTR strFilename) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::AddSourceFilter(BSTR strFilename, IDispatch** ppUnk) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_FilterCollection(IDispatch** ppUnk) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_RegFilterCollection(IDispatch** ppUnk) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::StopWhenReady() -{ - return Stop(); -} - -// IMediaEvent -STDMETHODIMP CBaseGraph::GetEventHandle(OAEVENT* hEvent) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetEvent(long* lEventCode, LONG_PTR* lParam1, LONG_PTR* lParam2, long msTimeout) -{ - if (m_msgqueue.IsEmpty()) { - return E_FAIL; - } - - GMSG msg = m_msgqueue.RemoveHead(); - if (lEventCode) { - *lEventCode = msg.m_lEventCode; - } - if (lParam1) { - *lParam1 = msg.m_lParam1; - } - if (lParam2) { - *lParam2 = msg.m_lParam2; - } - - return S_OK; -} - -STDMETHODIMP CBaseGraph::WaitForCompletion(long msTimeout, long* pEvCode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::CancelDefaultHandling(long lEvCode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RestoreDefaultHandling(long lEvCode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::FreeEventParams(long lEvCode, LONG_PTR lParam1, LONG_PTR lParam2) -{ - if (EC_BG_ERROR == lEvCode) { - if (lParam1) { - CoTaskMemFree((void*)lParam1); - } - } - - return S_OK; -} - -// IMediaEventEx -STDMETHODIMP CBaseGraph::SetNotifyWindow(OAHWND hwnd, long lMsg, LONG_PTR lInstanceData) -{ - m_hNotifyWnd = hwnd; - m_lNotifyMsg = lMsg; - m_lNotifyInstData = lInstanceData; - - if (!IsWindow((HWND)m_hNotifyWnd)) { - m_hNotifyWnd = 0; - return E_FAIL; - } - - return S_OK; -} - -STDMETHODIMP CBaseGraph::SetNotifyFlags(long lNoNotifyFlags) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetNotifyFlags(long* lplNoNotifyFlags) -{ - return E_NOTIMPL; -} - -// IMediaSeeking -STDMETHODIMP CBaseGraph::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetCurrentPos | AM_SEEKING_CanGetDuration; - - return S_OK; -} - -STDMETHODIMP CBaseGraph::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - if (*pCapabilities == 0) { - return S_OK; - } - - DWORD caps; - GetCapabilities(&caps); - - DWORD caps2 = caps & *pCapabilities; - - return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseGraph::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseGraph::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseGraph::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CBaseGraph::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CBaseGraph::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CBaseGraph::GetDuration(LONGLONG* pDuration) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetStopPosition(LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetCurrentPosition(LONGLONG* pCurrent) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetRate(double dRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetRate(double* pdRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetPreroll(LONGLONG* pllPreroll) -{ - return E_NOTIMPL; -} - -// IVideoWindow -STDMETHODIMP CBaseGraph::put_Caption(BSTR strCaption) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Caption(BSTR* strCaption) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_WindowStyle(long WindowStyle) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_WindowStyle(long* WindowStyle) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_WindowStyleEx(long WindowStyleEx) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_WindowStyleEx(long* WindowStyleEx) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_AutoShow(long AutoShow) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_AutoShow(long* AutoShow) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_WindowState(long WindowState) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_WindowState(long* WindowState) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_BackgroundPalette(long BackgroundPalette) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_BackgroundPalette(long* pBackgroundPalette) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Visible(long Visible) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Visible(long* pVisible) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Left(long Left) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Left(long* pLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Width(long Width) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Width(long* pWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Top(long Top) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Top(long* pTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Height(long Height) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Height(long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Owner(OAHWND Owner) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Owner(OAHWND* Owner) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_MessageDrain(OAHWND Drain) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_MessageDrain(OAHWND* Drain) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_BorderColor(long* Color) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_BorderColor(long Color) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_FullScreenMode(long* FullScreenMode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_FullScreenMode(long FullScreenMode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetWindowForeground(long Focus) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetWindowPosition(long Left, long Top, long Width, long Height) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetMinIdealImageSize(long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetMaxIdealImageSize(long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::HideCursor(long HideCursor) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::IsCursorHidden(long* CursorHidden) -{ - return E_NOTIMPL; -} - -// IBasicVideo -STDMETHODIMP CBaseGraph::get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_BitRate(long* pBitRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_BitErrorRate(long* pBitErrorRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_VideoWidth(long* pVideoWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_VideoHeight(long* pVideoHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_SourceLeft(long SourceLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_SourceLeft(long* pSourceLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_SourceWidth(long SourceWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_SourceWidth(long* pSourceWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_SourceTop(long SourceTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_SourceTop(long* pSourceTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_SourceHeight(long SourceHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_SourceHeight(long* pSourceHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_DestinationLeft(long DestinationLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_DestinationLeft(long* pDestinationLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_DestinationWidth(long DestinationWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_DestinationWidth(long* pDestinationWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_DestinationTop(long DestinationTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_DestinationTop(long* pDestinationTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_DestinationHeight(long DestinationHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_DestinationHeight(long* pDestinationHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetSourcePosition(long Left, long Top, long Width, long Height) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetDefaultSourcePosition() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetDestinationPosition(long Left, long Top, long Width, long Height) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetDefaultDestinationPosition() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetVideoSize(long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetCurrentImage(long* pBufferSize, long* pDIBImage) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::IsUsingDefaultSource() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::IsUsingDefaultDestination() -{ - return E_NOTIMPL; -} - -// IBasicAudio -STDMETHODIMP CBaseGraph::put_Volume(long lVolume) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Volume(long* plVolume) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Balance(long lBalance) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Balance(long* plBalance) -{ - return E_NOTIMPL; -} - -// IAMOpenProgress -STDMETHODIMP CBaseGraph::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::AbortOperation() -{ - return E_NOTIMPL; -} - -// IGraphEngine -STDMETHODIMP_(engine_t) CBaseGraph::GetEngine() -{ - return DirectShow; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "BaseGraph.h" +#include "DSUtil.h" + + +// +// CPlayerWindow +// + +BOOL CPlayerWindow::PreCreateWindow(CREATESTRUCT& cs) +{ + if (!CWnd::PreCreateWindow(cs)) { + return FALSE; + } + + cs.style &= ~WS_BORDER; + cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + ::LoadCursor(nullptr, IDC_HAND), nullptr, nullptr); + + return TRUE; +} + +BEGIN_MESSAGE_MAP(CPlayerWindow, CWnd) + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +BOOL CPlayerWindow::OnEraseBkgnd(CDC* pDC) +{ + for (CWnd* pChild = GetWindow(GW_CHILD); pChild; pChild = pChild->GetNextWindow()) { + if (!pChild->IsWindowVisible()) { + continue; + } + + CRect r; + pChild->GetClientRect(&r); + pChild->MapWindowPoints(this, &r); + pDC->ExcludeClipRect(&r); + } + + CRect r; + GetClientRect(&r); + pDC->FillSolidRect(&r, 0); + + return TRUE; +} + +// +// CBaseGraph +// + +CBaseGraph::CBaseGraph() + : CUnknown(NAME("CBaseGraph"), nullptr) + , m_hNotifyWnd(0) + , m_lNotifyMsg(0) + , m_lNotifyInstData(0) +{ +} + +CBaseGraph::~CBaseGraph() +{ +} + +STDMETHODIMP CBaseGraph::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFilterGraph) + QI(IGraphBuilder) + QI(IFilterGraph2) + QI(IGraphBuilder2) + QI(IMediaControl) + QI(IMediaSeeking) + QI(IMediaEventEx) + QI(IVideoWindow) + QI(IBasicVideo) + QI(IBasicAudio) + QI(IAMOpenProgress) + QI(IGraphEngine) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CBaseGraph::ClearMessageQueue() +{ + while (!m_msgqueue.IsEmpty()) { + GMSG msg = m_msgqueue.RemoveHead(); + FreeEventParams(msg.m_lEventCode, msg.m_lParam1, msg.m_lParam2); + } +} + +void CBaseGraph::NotifyEvent(long lEventCode, LONG_PTR lParam1, LONG_PTR lParam2) +{ + if (!m_hNotifyWnd) { + return; + } + + GMSG msg; + msg.m_lEventCode = lEventCode; + msg.m_lParam1 = lParam1; + msg.m_lParam2 = lParam2; + m_msgqueue.AddTail(msg); + + PostMessage((HWND)m_hNotifyWnd, m_lNotifyMsg, (WPARAM)0, m_lNotifyInstData); +} + +// IDispatch +STDMETHODIMP CBaseGraph::GetTypeInfoCount(UINT* pctinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + return E_NOTIMPL; +} + +// IFilterGraph +STDMETHODIMP CBaseGraph::AddFilter(IBaseFilter* pFilter, LPCWSTR pName) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RemoveFilter(IBaseFilter* pFilter) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::EnumFilters(IEnumFilters** ppEnum) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConnectDirect(IPin* ppinOut, IPin* ppinIn, const AM_MEDIA_TYPE* pmt) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Reconnect(IPin* ppin) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Disconnect(IPin* ppin) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetDefaultSyncSource() +{ + return E_NOTIMPL; +} + +// IGraphBuilder +STDMETHODIMP CBaseGraph::Connect(IPin* ppinOut, IPin* ppinIn) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Render(IPin* ppinOut) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + *ppFilter = nullptr; + return RenderFile(lpcwstrFileName, nullptr); +}//E_NOTIMPL;} + +STDMETHODIMP CBaseGraph::SetLogFile(DWORD_PTR hFile) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Abort() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ShouldOperationContinue() +{ + return E_NOTIMPL; +} + +// IFilterGraph2 +STDMETHODIMP CBaseGraph::AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext) +{ + return E_NOTIMPL; +} + +// IGraphBuilder2 +STDMETHODIMP CBaseGraph::IsPinDirection(IPin* pPin, PIN_DIRECTION dir) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::IsPinConnected(IPin* pPin) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConnectFilter(IBaseFilter* pBF, IPin* pPinIn) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConnectFilter(IPin* pPinOut, IBaseFilter* pBF) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::NukeDownstream(IUnknown* pUnk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::FindInterface(REFIID iid, void** ppv, BOOL bRemove) +{ + return QueryInterface(iid, ppv); +} + +STDMETHODIMP CBaseGraph::AddToROT() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RemoveFromROT() +{ + return E_NOTIMPL; +} + +// IMediaControl +STDMETHODIMP CBaseGraph::Run() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Pause() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Stop() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetState(LONG msTimeout, OAFilterState* pfs) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RenderFile(BSTR strFilename) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::AddSourceFilter(BSTR strFilename, IDispatch** ppUnk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_FilterCollection(IDispatch** ppUnk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_RegFilterCollection(IDispatch** ppUnk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::StopWhenReady() +{ + return Stop(); +} + +// IMediaEvent +STDMETHODIMP CBaseGraph::GetEventHandle(OAEVENT* hEvent) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetEvent(long* lEventCode, LONG_PTR* lParam1, LONG_PTR* lParam2, long msTimeout) +{ + if (m_msgqueue.IsEmpty()) { + return E_FAIL; + } + + GMSG msg = m_msgqueue.RemoveHead(); + if (lEventCode) { + *lEventCode = msg.m_lEventCode; + } + if (lParam1) { + *lParam1 = msg.m_lParam1; + } + if (lParam2) { + *lParam2 = msg.m_lParam2; + } + + return S_OK; +} + +STDMETHODIMP CBaseGraph::WaitForCompletion(long msTimeout, long* pEvCode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::CancelDefaultHandling(long lEvCode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RestoreDefaultHandling(long lEvCode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::FreeEventParams(long lEvCode, LONG_PTR lParam1, LONG_PTR lParam2) +{ + if (EC_BG_ERROR == lEvCode) { + if (lParam1) { + CoTaskMemFree((void*)lParam1); + } + } + + return S_OK; +} + +// IMediaEventEx +STDMETHODIMP CBaseGraph::SetNotifyWindow(OAHWND hwnd, long lMsg, LONG_PTR lInstanceData) +{ + m_hNotifyWnd = hwnd; + m_lNotifyMsg = lMsg; + m_lNotifyInstData = lInstanceData; + + if (!IsWindow((HWND)m_hNotifyWnd)) { + m_hNotifyWnd = 0; + return E_FAIL; + } + + return S_OK; +} + +STDMETHODIMP CBaseGraph::SetNotifyFlags(long lNoNotifyFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetNotifyFlags(long* lplNoNotifyFlags) +{ + return E_NOTIMPL; +} + +// IMediaSeeking +STDMETHODIMP CBaseGraph::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetCurrentPos | AM_SEEKING_CanGetDuration; + + return S_OK; +} + +STDMETHODIMP CBaseGraph::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + if (*pCapabilities == 0) { + return S_OK; + } + + DWORD caps; + GetCapabilities(&caps); + + DWORD caps2 = caps & *pCapabilities; + + return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseGraph::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseGraph::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseGraph::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CBaseGraph::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CBaseGraph::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CBaseGraph::GetDuration(LONGLONG* pDuration) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetStopPosition(LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetCurrentPosition(LONGLONG* pCurrent) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetRate(double dRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetRate(double* pdRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetPreroll(LONGLONG* pllPreroll) +{ + return E_NOTIMPL; +} + +// IVideoWindow +STDMETHODIMP CBaseGraph::put_Caption(BSTR strCaption) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Caption(BSTR* strCaption) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_WindowStyle(long WindowStyle) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_WindowStyle(long* WindowStyle) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_WindowStyleEx(long WindowStyleEx) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_WindowStyleEx(long* WindowStyleEx) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_AutoShow(long AutoShow) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_AutoShow(long* AutoShow) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_WindowState(long WindowState) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_WindowState(long* WindowState) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_BackgroundPalette(long BackgroundPalette) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_BackgroundPalette(long* pBackgroundPalette) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Visible(long Visible) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Visible(long* pVisible) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Left(long Left) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Left(long* pLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Width(long Width) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Width(long* pWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Top(long Top) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Top(long* pTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Height(long Height) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Height(long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Owner(OAHWND Owner) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Owner(OAHWND* Owner) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_MessageDrain(OAHWND Drain) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_MessageDrain(OAHWND* Drain) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_BorderColor(long* Color) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_BorderColor(long Color) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_FullScreenMode(long* FullScreenMode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_FullScreenMode(long FullScreenMode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetWindowForeground(long Focus) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetWindowPosition(long Left, long Top, long Width, long Height) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetMinIdealImageSize(long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetMaxIdealImageSize(long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::HideCursor(long HideCursor) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::IsCursorHidden(long* CursorHidden) +{ + return E_NOTIMPL; +} + +// IBasicVideo +STDMETHODIMP CBaseGraph::get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_BitRate(long* pBitRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_BitErrorRate(long* pBitErrorRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_VideoWidth(long* pVideoWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_VideoHeight(long* pVideoHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_SourceLeft(long SourceLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_SourceLeft(long* pSourceLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_SourceWidth(long SourceWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_SourceWidth(long* pSourceWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_SourceTop(long SourceTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_SourceTop(long* pSourceTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_SourceHeight(long SourceHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_SourceHeight(long* pSourceHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_DestinationLeft(long DestinationLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_DestinationLeft(long* pDestinationLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_DestinationWidth(long DestinationWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_DestinationWidth(long* pDestinationWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_DestinationTop(long DestinationTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_DestinationTop(long* pDestinationTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_DestinationHeight(long DestinationHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_DestinationHeight(long* pDestinationHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetSourcePosition(long Left, long Top, long Width, long Height) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetDefaultSourcePosition() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetDestinationPosition(long Left, long Top, long Width, long Height) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetDefaultDestinationPosition() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetVideoSize(long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetCurrentImage(long* pBufferSize, long* pDIBImage) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::IsUsingDefaultSource() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::IsUsingDefaultDestination() +{ + return E_NOTIMPL; +} + +// IBasicAudio +STDMETHODIMP CBaseGraph::put_Volume(long lVolume) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Volume(long* plVolume) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Balance(long lBalance) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Balance(long* plBalance) +{ + return E_NOTIMPL; +} + +// IAMOpenProgress +STDMETHODIMP CBaseGraph::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::AbortOperation() +{ + return E_NOTIMPL; +} + +// IGraphEngine +STDMETHODIMP_(engine_t) CBaseGraph::GetEngine() +{ + return DirectShow; +} diff --git a/src/mpc-hc/BaseGraph.h b/src/mpc-hc/BaseGraph.h index 1f388f0ecf7..0b76c68fdf9 100644 --- a/src/mpc-hc/BaseGraph.h +++ b/src/mpc-hc/BaseGraph.h @@ -1,261 +1,261 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include "IGraphBuilder2.h" - - -class CPlayerWindow : public CWnd -{ -public: - CPlayerWindow() {} - -protected: - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - DECLARE_MESSAGE_MAP() -}; - -enum engine_t { - DirectShow = 0, - ShockWave = 3 -}; - -interface __declspec(uuid("B110CDE5-6331-4118-8AAF-A870D6F7E2E4")) - IGraphEngine : - public IUnknown -{ - STDMETHOD_(engine_t, GetEngine)() PURE; -}; - -enum { - EC_BG_AUDIO_CHANGED = EC_USER + 1, - EC_BG_ERROR -}; - -class CBaseGraph - : public CUnknown - , public IGraphBuilder2 - , public IMediaControl - , public IMediaEventEx - , public IMediaSeeking - , public IVideoWindow - , public IBasicVideo - , public IBasicAudio - , public IAMOpenProgress - , public IGraphEngine -{ - OAHWND m_hNotifyWnd; - long m_lNotifyMsg; - LONG_PTR m_lNotifyInstData; - - struct GMSG { - long m_lEventCode; - LONG_PTR m_lParam1, m_lParam2; - }; - CList m_msgqueue; - -protected: - void ClearMessageQueue(); - -public: - CBaseGraph(); - virtual ~CBaseGraph(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - void NotifyEvent(long lEventCode, LONG_PTR lParam1 = 0, LONG_PTR lParam2 = 0); - -protected: - // IDispatch - STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); - STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo); - STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId); - STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr); - - // IFilterGraph - STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); - STDMETHODIMP RemoveFilter(IBaseFilter* pFilter); - STDMETHODIMP EnumFilters(IEnumFilters** ppEnum); - STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter); - STDMETHODIMP ConnectDirect(IPin* ppinOut, IPin* ppinIn, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP Reconnect(IPin* ppin); - STDMETHODIMP Disconnect(IPin* ppin); - STDMETHODIMP SetDefaultSyncSource(); - - // IGraphBuilder - STDMETHODIMP Connect(IPin* ppinOut, IPin* ppinIn); - STDMETHODIMP Render(IPin* ppinOut); - STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); - STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - STDMETHODIMP SetLogFile(DWORD_PTR hFile); - STDMETHODIMP Abort(); - STDMETHODIMP ShouldOperationContinue(); - - // IFilterGraph2 - STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext); - - // IGraphBuilder2 - STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir); - STDMETHODIMP IsPinConnected(IPin* pPin); - STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn); - STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF); - STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP NukeDownstream(IUnknown* pUnk); - STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove); - STDMETHODIMP AddToROT(); - STDMETHODIMP RemoveFromROT(); - - // IMediaControl - STDMETHODIMP Run(); - STDMETHODIMP Pause(); - STDMETHODIMP Stop(); - STDMETHODIMP GetState(LONG msTimeout, OAFilterState* pfs); - STDMETHODIMP RenderFile(BSTR strFilename); - STDMETHODIMP AddSourceFilter(BSTR strFilename, IDispatch** ppUnk); - STDMETHODIMP get_FilterCollection(IDispatch** ppUnk); - STDMETHODIMP get_RegFilterCollection(IDispatch** ppUnk); - STDMETHODIMP StopWhenReady(); - - // IMediaEvent - STDMETHODIMP GetEventHandle(OAEVENT* hEvent); - STDMETHODIMP GetEvent(long* lEventCode, LONG_PTR* lParam1, LONG_PTR* lParam2, long msTimeout); - STDMETHODIMP WaitForCompletion(long msTimeout, long* pEvCode); - STDMETHODIMP CancelDefaultHandling(long lEvCode); - STDMETHODIMP RestoreDefaultHandling(long lEvCode); - STDMETHODIMP FreeEventParams(long lEvCode, LONG_PTR lParam1, LONG_PTR lParam2); - - // IMediaEventEx - STDMETHODIMP SetNotifyWindow(OAHWND hwnd, long lMsg, LONG_PTR lInstanceData); - STDMETHODIMP SetNotifyFlags(long lNoNotifyFlags); - STDMETHODIMP GetNotifyFlags(long* lplNoNotifyFlags); - - // IMediaSeeking - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - - // IVideoWindow - STDMETHODIMP put_Caption(BSTR strCaption); - STDMETHODIMP get_Caption(BSTR* strCaption); - STDMETHODIMP put_WindowStyle(long WindowStyle); - STDMETHODIMP get_WindowStyle(long* WindowStyle); - STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); - STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx); - STDMETHODIMP put_AutoShow(long AutoShow); - STDMETHODIMP get_AutoShow(long* AutoShow); - STDMETHODIMP put_WindowState(long WindowState); - STDMETHODIMP get_WindowState(long* WindowState); - STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); - STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette); - STDMETHODIMP put_Visible(long Visible); - STDMETHODIMP get_Visible(long* pVisible); - STDMETHODIMP put_Left(long Left); - STDMETHODIMP get_Left(long* pLeft); - STDMETHODIMP put_Width(long Width); - STDMETHODIMP get_Width(long* pWidth); - STDMETHODIMP put_Top(long Top); - STDMETHODIMP get_Top(long* pTop); - STDMETHODIMP put_Height(long Height); - STDMETHODIMP get_Height(long* pHeight); - STDMETHODIMP put_Owner(OAHWND Owner); - STDMETHODIMP get_Owner(OAHWND* Owner); - STDMETHODIMP put_MessageDrain(OAHWND Drain); - STDMETHODIMP get_MessageDrain(OAHWND* Drain); - STDMETHODIMP get_BorderColor(long* Color); - STDMETHODIMP put_BorderColor(long Color); - STDMETHODIMP get_FullScreenMode(long* FullScreenMode); - STDMETHODIMP put_FullScreenMode(long FullScreenMode); - STDMETHODIMP SetWindowForeground(long Focus); - STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam); - STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height); - STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight); - STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight); - STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - STDMETHODIMP HideCursor(long HideCursor); - STDMETHODIMP IsCursorHidden(long* CursorHidden); - - // IBasicVideo - STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame); - STDMETHODIMP get_BitRate(long* pBitRate); - STDMETHODIMP get_BitErrorRate(long* pBitErrorRate); - STDMETHODIMP get_VideoWidth(long* pVideoWidth); - STDMETHODIMP get_VideoHeight(long* pVideoHeight); - STDMETHODIMP put_SourceLeft(long SourceLeft); - STDMETHODIMP get_SourceLeft(long* pSourceLeft); - STDMETHODIMP put_SourceWidth(long SourceWidth); - STDMETHODIMP get_SourceWidth(long* pSourceWidth); - STDMETHODIMP put_SourceTop(long SourceTop); - STDMETHODIMP get_SourceTop(long* pSourceTop); - STDMETHODIMP put_SourceHeight(long SourceHeight); - STDMETHODIMP get_SourceHeight(long* pSourceHeight); - STDMETHODIMP put_DestinationLeft(long DestinationLeft); - STDMETHODIMP get_DestinationLeft(long* pDestinationLeft); - STDMETHODIMP put_DestinationWidth(long DestinationWidth); - STDMETHODIMP get_DestinationWidth(long* pDestinationWidth); - STDMETHODIMP put_DestinationTop(long DestinationTop); - STDMETHODIMP get_DestinationTop(long* pDestinationTop); - STDMETHODIMP put_DestinationHeight(long DestinationHeight); - STDMETHODIMP get_DestinationHeight(long* pDestinationHeight); - STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height); - STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - STDMETHODIMP SetDefaultSourcePosition(); - STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height); - STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - STDMETHODIMP SetDefaultDestinationPosition(); - STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight); - STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette); - STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage); - STDMETHODIMP IsUsingDefaultSource(); - STDMETHODIMP IsUsingDefaultDestination(); - - // IBasicAudio - STDMETHODIMP put_Volume(long lVolume); - STDMETHODIMP get_Volume(long* plVolume); - STDMETHODIMP put_Balance(long lBalance); - STDMETHODIMP get_Balance(long* plBalance); - - // IAMOpenProgress - STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent); - STDMETHODIMP AbortOperation(); - - // IGraphEngine - STDMETHODIMP_(engine_t) GetEngine(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include "IGraphBuilder2.h" + + +class CPlayerWindow : public CWnd +{ +public: + CPlayerWindow() {} + +protected: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + DECLARE_MESSAGE_MAP() +}; + +enum engine_t { + DirectShow = 0, + ShockWave = 3 +}; + +interface __declspec(uuid("B110CDE5-6331-4118-8AAF-A870D6F7E2E4")) + IGraphEngine : + public IUnknown +{ + STDMETHOD_(engine_t, GetEngine)() PURE; +}; + +enum { + EC_BG_AUDIO_CHANGED = EC_USER + 1, + EC_BG_ERROR +}; + +class CBaseGraph + : public CUnknown + , public IGraphBuilder2 + , public IMediaControl + , public IMediaEventEx + , public IMediaSeeking + , public IVideoWindow + , public IBasicVideo + , public IBasicAudio + , public IAMOpenProgress + , public IGraphEngine +{ + OAHWND m_hNotifyWnd; + long m_lNotifyMsg; + LONG_PTR m_lNotifyInstData; + + struct GMSG { + long m_lEventCode; + LONG_PTR m_lParam1, m_lParam2; + }; + CList m_msgqueue; + +protected: + void ClearMessageQueue(); + +public: + CBaseGraph(); + virtual ~CBaseGraph(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + void NotifyEvent(long lEventCode, LONG_PTR lParam1 = 0, LONG_PTR lParam2 = 0); + +protected: + // IDispatch + STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); + STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo); + STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId); + STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr); + + // IFilterGraph + STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); + STDMETHODIMP RemoveFilter(IBaseFilter* pFilter); + STDMETHODIMP EnumFilters(IEnumFilters** ppEnum); + STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter); + STDMETHODIMP ConnectDirect(IPin* ppinOut, IPin* ppinIn, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP Reconnect(IPin* ppin); + STDMETHODIMP Disconnect(IPin* ppin); + STDMETHODIMP SetDefaultSyncSource(); + + // IGraphBuilder + STDMETHODIMP Connect(IPin* ppinOut, IPin* ppinIn); + STDMETHODIMP Render(IPin* ppinOut); + STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); + STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + STDMETHODIMP SetLogFile(DWORD_PTR hFile); + STDMETHODIMP Abort(); + STDMETHODIMP ShouldOperationContinue(); + + // IFilterGraph2 + STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext); + + // IGraphBuilder2 + STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir); + STDMETHODIMP IsPinConnected(IPin* pPin); + STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn); + STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF); + STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP NukeDownstream(IUnknown* pUnk); + STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove); + STDMETHODIMP AddToROT(); + STDMETHODIMP RemoveFromROT(); + + // IMediaControl + STDMETHODIMP Run(); + STDMETHODIMP Pause(); + STDMETHODIMP Stop(); + STDMETHODIMP GetState(LONG msTimeout, OAFilterState* pfs); + STDMETHODIMP RenderFile(BSTR strFilename); + STDMETHODIMP AddSourceFilter(BSTR strFilename, IDispatch** ppUnk); + STDMETHODIMP get_FilterCollection(IDispatch** ppUnk); + STDMETHODIMP get_RegFilterCollection(IDispatch** ppUnk); + STDMETHODIMP StopWhenReady(); + + // IMediaEvent + STDMETHODIMP GetEventHandle(OAEVENT* hEvent); + STDMETHODIMP GetEvent(long* lEventCode, LONG_PTR* lParam1, LONG_PTR* lParam2, long msTimeout); + STDMETHODIMP WaitForCompletion(long msTimeout, long* pEvCode); + STDMETHODIMP CancelDefaultHandling(long lEvCode); + STDMETHODIMP RestoreDefaultHandling(long lEvCode); + STDMETHODIMP FreeEventParams(long lEvCode, LONG_PTR lParam1, LONG_PTR lParam2); + + // IMediaEventEx + STDMETHODIMP SetNotifyWindow(OAHWND hwnd, long lMsg, LONG_PTR lInstanceData); + STDMETHODIMP SetNotifyFlags(long lNoNotifyFlags); + STDMETHODIMP GetNotifyFlags(long* lplNoNotifyFlags); + + // IMediaSeeking + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + + // IVideoWindow + STDMETHODIMP put_Caption(BSTR strCaption); + STDMETHODIMP get_Caption(BSTR* strCaption); + STDMETHODIMP put_WindowStyle(long WindowStyle); + STDMETHODIMP get_WindowStyle(long* WindowStyle); + STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); + STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx); + STDMETHODIMP put_AutoShow(long AutoShow); + STDMETHODIMP get_AutoShow(long* AutoShow); + STDMETHODIMP put_WindowState(long WindowState); + STDMETHODIMP get_WindowState(long* WindowState); + STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); + STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette); + STDMETHODIMP put_Visible(long Visible); + STDMETHODIMP get_Visible(long* pVisible); + STDMETHODIMP put_Left(long Left); + STDMETHODIMP get_Left(long* pLeft); + STDMETHODIMP put_Width(long Width); + STDMETHODIMP get_Width(long* pWidth); + STDMETHODIMP put_Top(long Top); + STDMETHODIMP get_Top(long* pTop); + STDMETHODIMP put_Height(long Height); + STDMETHODIMP get_Height(long* pHeight); + STDMETHODIMP put_Owner(OAHWND Owner); + STDMETHODIMP get_Owner(OAHWND* Owner); + STDMETHODIMP put_MessageDrain(OAHWND Drain); + STDMETHODIMP get_MessageDrain(OAHWND* Drain); + STDMETHODIMP get_BorderColor(long* Color); + STDMETHODIMP put_BorderColor(long Color); + STDMETHODIMP get_FullScreenMode(long* FullScreenMode); + STDMETHODIMP put_FullScreenMode(long FullScreenMode); + STDMETHODIMP SetWindowForeground(long Focus); + STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam); + STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height); + STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight); + STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight); + STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + STDMETHODIMP HideCursor(long HideCursor); + STDMETHODIMP IsCursorHidden(long* CursorHidden); + + // IBasicVideo + STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame); + STDMETHODIMP get_BitRate(long* pBitRate); + STDMETHODIMP get_BitErrorRate(long* pBitErrorRate); + STDMETHODIMP get_VideoWidth(long* pVideoWidth); + STDMETHODIMP get_VideoHeight(long* pVideoHeight); + STDMETHODIMP put_SourceLeft(long SourceLeft); + STDMETHODIMP get_SourceLeft(long* pSourceLeft); + STDMETHODIMP put_SourceWidth(long SourceWidth); + STDMETHODIMP get_SourceWidth(long* pSourceWidth); + STDMETHODIMP put_SourceTop(long SourceTop); + STDMETHODIMP get_SourceTop(long* pSourceTop); + STDMETHODIMP put_SourceHeight(long SourceHeight); + STDMETHODIMP get_SourceHeight(long* pSourceHeight); + STDMETHODIMP put_DestinationLeft(long DestinationLeft); + STDMETHODIMP get_DestinationLeft(long* pDestinationLeft); + STDMETHODIMP put_DestinationWidth(long DestinationWidth); + STDMETHODIMP get_DestinationWidth(long* pDestinationWidth); + STDMETHODIMP put_DestinationTop(long DestinationTop); + STDMETHODIMP get_DestinationTop(long* pDestinationTop); + STDMETHODIMP put_DestinationHeight(long DestinationHeight); + STDMETHODIMP get_DestinationHeight(long* pDestinationHeight); + STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height); + STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + STDMETHODIMP SetDefaultSourcePosition(); + STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height); + STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + STDMETHODIMP SetDefaultDestinationPosition(); + STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight); + STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette); + STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage); + STDMETHODIMP IsUsingDefaultSource(); + STDMETHODIMP IsUsingDefaultDestination(); + + // IBasicAudio + STDMETHODIMP put_Volume(long lVolume); + STDMETHODIMP get_Volume(long* plVolume); + STDMETHODIMP put_Balance(long lBalance); + STDMETHODIMP get_Balance(long* plBalance); + + // IAMOpenProgress + STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent); + STDMETHODIMP AbortOperation(); + + // IGraphEngine + STDMETHODIMP_(engine_t) GetEngine(); +}; diff --git a/src/mpc-hc/CMPCTheme.cpp b/src/mpc-hc/CMPCTheme.cpp index b4d7b0eee3d..7e60883e2c5 100755 --- a/src/mpc-hc/CMPCTheme.cpp +++ b/src/mpc-hc/CMPCTheme.cpp @@ -1,697 +1,697 @@ -#include "stdafx.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - -#define RGBGS(x) ((COLORREF)(((BYTE)(x)|((WORD)((BYTE)(x))<<8))|(((DWORD)(BYTE)(x))<<16))) - -const int CMPCTheme::GroupBoxTextIndent = 8; -bool CMPCTheme::drawThemedControls = false; -COLORREF CMPCTheme::CloseHoverColor = RGB(232, 17, 35); -COLORREF CMPCTheme::ClosePushColor = RGB(139, 10, 20); -COLORREF CMPCTheme::DebugColorRed = RGB(255, 0, 0); -COLORREF CMPCTheme::DebugColorYellow = RGB(255, 255, 0); -COLORREF CMPCTheme::DebugColorGreen = RGB(0, 255, 0); -COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedTextColor = RGB(255, 255, 255); -COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedBGColor = RGB(56, 56, 56); -COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedEditBorderColor = RGB(155, 155, 155); -COLORREF CMPCTheme::W10DarkThemeTitlebarBGColor = RGB(0, 0, 0); -COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveBGColor = RGB(43, 43, 43); -COLORREF CMPCTheme::W10DarkThemeTitlebarFGColor = RGB(255, 255, 255); -COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveFGColor = RGB(170, 170, 170); -COLORREF CMPCTheme::W10DarkThemeTitlebarIconPenColor = RGB(255, 255, 255); -COLORREF CMPCTheme::W10DarkThemeTitlebarControlHoverBGColor = RGB(43, 43, 43); -COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveControlHoverBGColor = RGB(65, 65, 65); -COLORREF CMPCTheme::W10DarkThemeTitlebarControlPushedBGColor = RGB(70, 70, 70); -COLORREF CMPCTheme::W10DarkThemeWindowBorderColor = RGB(57, 57, 57); - - - -COLORREF CMPCTheme::MenuBGColor; -COLORREF CMPCTheme::MenubarBGColor; -COLORREF CMPCTheme::WindowBGColor; -COLORREF CMPCTheme::ControlAreaBGColor; - -COLORREF CMPCTheme::ContentBGColor; -COLORREF CMPCTheme::ContentSelectedColor; -COLORREF CMPCTheme::PlayerBGColor; - -COLORREF CMPCTheme::HighLightColor; - -COLORREF CMPCTheme::MenuSelectedColor; -COLORREF CMPCTheme::MenubarSelectedBGColor; -COLORREF CMPCTheme::MenuSeparatorColor; -COLORREF CMPCTheme::MenuItemDisabledColor; -//COLORREF CMPCTheme::MenuItemUnfocusedColor; -COLORREF CMPCTheme::MainMenuBorderColor; - -COLORREF CMPCTheme::TextFGColor; -COLORREF CMPCTheme::TextFGColorFade; -COLORREF CMPCTheme::PropPageCaptionFGColor; -COLORREF CMPCTheme::ContentTextDisabledFGColorFade; -COLORREF CMPCTheme::ContentTextDisabledFGColorFade2; //even more faded, used for NA text on CListCtrl/audio switcher - -COLORREF CMPCTheme::SubmenuColor; - -COLORREF CMPCTheme::WindowBorderColorLight; -COLORREF CMPCTheme::WindowBorderColorDim; -COLORREF CMPCTheme::NoBorderColor; -COLORREF CMPCTheme::GripperPatternColor; //visual studio, since explorer has no grippers - -COLORREF CMPCTheme::ScrollBGColor; -COLORREF CMPCTheme::ScrollProgressColor; -COLORREF CMPCTheme::ScrollThumbColor; -COLORREF CMPCTheme::ScrollThumbHoverColor; -COLORREF CMPCTheme::ScrollThumbDragColor; -COLORREF CMPCTheme::ScrollButtonArrowColor; -COLORREF CMPCTheme::ScrollButtonArrowClickColor; -COLORREF CMPCTheme::ScrollButtonHoverColor; -COLORREF CMPCTheme::ScrollButtonClickColor; - -COLORREF CMPCTheme::InlineEditBorderColor; -COLORREF CMPCTheme::TooltipBorderColor; - -COLORREF CMPCTheme::GroupBoxBorderColor; - -COLORREF CMPCTheme::PlayerButtonHotColor; -COLORREF CMPCTheme::PlayerButtonCheckedColor; -COLORREF CMPCTheme::PlayerButtonClickedColor; -COLORREF CMPCTheme::PlayerButtonBorderColor; - -COLORREF CMPCTheme::ButtonBorderOuterColor; -COLORREF CMPCTheme::ButtonBorderInnerFocusedColor; -COLORREF CMPCTheme::ButtonBorderInnerColor; -COLORREF CMPCTheme::ButtonBorderSelectedKBFocusColor; -COLORREF CMPCTheme::ButtonBorderHoverKBFocusColor; -COLORREF CMPCTheme::ButtonBorderKBFocusColor; -COLORREF CMPCTheme::ButtonFillColor; -COLORREF CMPCTheme::ButtonFillHoverColor; -COLORREF CMPCTheme::ButtonFillSelectedColor; -COLORREF CMPCTheme::ButtonDisabledFGColor; - -COLORREF CMPCTheme::CheckboxBorderColor; -COLORREF CMPCTheme::CheckboxBGColor; -COLORREF CMPCTheme::CheckboxBorderHoverColor; -COLORREF CMPCTheme::CheckboxBGHoverColor; - -COLORREF CMPCTheme::ImageDisabledColor; - -COLORREF CMPCTheme::SliderChannelColor; - -COLORREF CMPCTheme::EditBorderColor; - -COLORREF CMPCTheme::TreeCtrlLineColor; -COLORREF CMPCTheme::TreeCtrlHoverColor; -COLORREF CMPCTheme::TreeCtrlFocusColor; - -COLORREF CMPCTheme::CheckColor; - -COLORREF CMPCTheme::ColumnHeaderHotColor; - -COLORREF CMPCTheme::StaticEtchedColor; - -COLORREF CMPCTheme::ListCtrlDisabledBGColor; -COLORREF CMPCTheme::ListCtrlGridColor; -COLORREF CMPCTheme::ListCtrlErrorColor; -COLORREF CMPCTheme::HeaderCtrlGridColor; -COLORREF CMPCTheme::AudioSwitcherGridColor; - -COLORREF CMPCTheme::TabCtrlBorderColor; -COLORREF CMPCTheme::TabCtrlInactiveColor; - - -COLORREF CMPCTheme::StatusBarBGColor; -COLORREF CMPCTheme::StatusBarSeparatorColor; - - -COLORREF CMPCTheme::ProgressBarBGColor; -COLORREF CMPCTheme::ProgressBarColor; - -COLORREF CMPCTheme::SubresyncFadeText1; -COLORREF CMPCTheme::SubresyncFadeText2; -COLORREF CMPCTheme::SubresyncActiveFadeText; -COLORREF CMPCTheme::SubresyncHLColor1; -COLORREF CMPCTheme::SubresyncHLColor2; -COLORREF CMPCTheme::SubresyncGridSepColor; - -COLORREF CMPCTheme::ActivePlayListItemColor; -COLORREF CMPCTheme::ActivePlayListItemHLColor; -COLORREF CMPCTheme::StaticLinkColor; - -COLORREF CMPCTheme::SeekbarCurrentPositionColor; -COLORREF CMPCTheme::SeekbarChapterColor; -COLORREF CMPCTheme::SeekbarABColor; - -wchar_t* const CMPCTheme::uiTextFont = L"Segoe UI"; -wchar_t* const CMPCTheme::uiStaticTextFont = L"Segoe UI Semilight"; -wchar_t* const CMPCTheme::uiSymbolFont = L"MS UI Gothic"; - - -const int CMPCTheme::gripPatternLong = 5; -const int CMPCTheme::gripPatternShort = 4; - - -const BYTE CMPCTheme::GripperBitsH[10] = { - 0x80, 0x00, - 0x00, 0x00, - 0x20, 0x00, - 0x00, 0x00, - 0x80, 0x00, -}; - -const BYTE CMPCTheme::GripperBitsV[8] = { - 0x88, 0x00, - 0x00, 0x00, - 0x20, 0x00, - 0x00, 0x00, -}; - -const COLORREF CMPCTheme::ComboboxArrowColor = RGB(200, 200, 200); -const COLORREF CMPCTheme::ComboboxArrowColorDisabled = RGB(100, 100, 100); - -const COLORREF CMPCTheme::HeaderCtrlSortArrowColor = RGB(200, 200, 200); - - -const BYTE CMPCTheme::CheckBits[14] = { - 0x02, 0x00, - 0x06, 0x00, - 0x8E, 0x00, - 0xDC, 0x00, - 0xF8, 0x00, - 0x70, 0x00, - 0x20, 0x00, -}; - -const int CMPCTheme::CheckWidth = 7; -const int CMPCTheme::CheckHeight = 7; - - -const UINT CMPCTheme::ThemeCheckBoxes[5] = { - IDB_DT_CB_96, - IDB_DT_CB_120, - IDB_DT_CB_144, - IDB_DT_CB_144, - IDB_DT_CB_192, -}; - -const UINT CMPCTheme::ThemeRadios[5] = { - IDB_DT_RADIO_96, - IDB_DT_RADIO_120, - IDB_DT_RADIO_144, - IDB_DT_RADIO_144, - IDB_DT_RADIO_192, -}; - -const UINT CMPCTheme::ThemeGrippers[5] = { - IDB_GRIPPER_96, - IDB_GRIPPER_120, - IDB_GRIPPER_144, - IDB_GRIPPER_168, - IDB_GRIPPER_192, -}; - -const std::vector CMPCTheme::minimizeIcon96({ - {2, 6, newPath}, - {11, 6, closePath}, -}); - -const std::vector CMPCTheme::minimizeIcon120({ - {3, 7, newPath}, - {14, 7, closePath}, -}); - -const std::vector CMPCTheme::minimizeIcon144({ - {4, 9, newPath}, - {18, 9, closePath}, -}); - -//same size as 144, but centered better -const std::vector CMPCTheme::minimizeIcon168({ - {2, 9, newPath}, - {16, 9, closePath}, -}); - -const std::vector CMPCTheme::minimizeIcon192({ - {5.5, 12.5, newPath}, - {23.5, 12.5, closePath}, -}); - -const std::vector CMPCTheme::restoreIcon96({ - {2, 4, newPath}, - {9, 4, linePath}, - {9, 11, linePath}, - {2, 11, linePath}, - {2, 4, linePath}, - {4, 4, newPath}, - {4, 2, linePath}, - {11, 2, linePath}, - {11, 9, linePath}, - {9, 9, linePath} -}); - -const std::vector CMPCTheme::restoreIcon120({ - {2, 4, newPath}, - {11, 4, linePath}, - {11, 13, linePath}, - {2, 13, linePath}, - {2, 4, linePath}, - {4, 4, newPath}, - {4, 2, linePath}, - {13, 2, linePath}, - {13, 11, linePath}, - {11, 11, linePath}, -}); - -const std::vector CMPCTheme::restoreIcon144({ - {2, 5, newPath}, - {13, 5, linePath}, - {13, 16, linePath}, - {2, 16, linePath}, - {2, 5, linePath}, - {5, 5, newPath}, - {5, 2, linePath}, - {16, 2, linePath}, - {16, 13, linePath}, - {13, 13, linePath}, -}); - -const std::vector CMPCTheme::restoreIcon168 = CMPCTheme::restoreIcon144; - -const std::vector CMPCTheme::restoreIcon192({ - { 3.5, 7.5, newPath}, - { 17.5, 7.5, linePath }, - { 17.5, 21.5, linePath }, - { 3.5, 21.5, linePath }, - { 3.5, 7.5, linePath }, - { 7.5, 7.5, newPath }, - { 7.5, 3.5, linePath }, - { 21.5, 3.5, linePath }, - { 21.5, 17.5, linePath }, - { 17.5, 17.5, linePath }, -}); - -const std::vector CMPCTheme::maximizeIcon96({ - {1, 1, newPath}, - {1, 10, linePath}, - {10, 10, linePath}, - {10, 1, linePath}, - {1, 1, linePath} -}); - -const std::vector CMPCTheme::maximizeIcon120({ - {2, 2, newPath}, - {2, 13, linePath}, - {13, 13, linePath}, - {13, 2, linePath}, - {2, 2, linePath}, -}); - -const std::vector CMPCTheme::maximizeIcon144({ - {2, 2, newPath}, - {2, 16, linePath}, - {16, 16, linePath}, - {16, 2, linePath}, - {2, 2, linePath}, -}); - -const std::vector CMPCTheme::maximizeIcon168 = CMPCTheme::maximizeIcon144; - -const std::vector CMPCTheme::maximizeIcon192({ - {3.5, 3.5, newPath}, - {3.5, 21.5, linePath}, - {21.5, 21.5, linePath}, - {21.5, 3.5, linePath}, - {3.5, 3.5, linePath}, -}); - -const std::vector CMPCTheme::closeIcon96({ - {1, 1, newPath}, - {10, 10, closePath}, - {1, 10, newPath}, - {10, 1, closePath} -}); - -const std::vector CMPCTheme::closeIcon120({ - {2, 2, newPath}, - {13, 13, linePath}, - {2, 13, newPath}, - {13, 2, linePath}, -}); - -const std::vector CMPCTheme::closeIcon144({ - {2, 2, newPath}, - {16, 16, linePath}, - {2, 16, newPath}, - {16, 2, linePath}, -}); - -const std::vector CMPCTheme::closeIcon168 = CMPCTheme::closeIcon144; - -const std::vector CMPCTheme::closeIcon192({ - {3.5, 3.5, newPath}, - {21.5, 21.5, linePath}, - {3.5, 21.5, newPath}, - {21.5, 3.5, linePath}, -}); - -//windows10 centers the icon "path" on the button, inside a frame -//sometimes this frame is centered, but at different dpis it's misaligned by 1-2 pixels -//we use the width/height of the frame to tweak the "center" position -const int CMPCTheme::W10TitlebarIconPathHeight[5] = { - 12, - 15, //should be 16, but to match windows 10 - 18, //should be 19 - 18, //should be 19 - 26, -}; - -const int CMPCTheme::W10TitlebarIconPathWidth[5] = { - 12, - 17, //should be 16, but to match windows 10 - 19, - 19, - 28, -}; - -const float CMPCTheme::W10TitlebarIconPathThickness[5] = { - 1, - 1, - 1, - 1, - 2, -}; - -const int CMPCTheme::W10TitlebarButtonWidth[5] = { - 45, - 58, - 69, - 80, - 91, -}; - -const int CMPCTheme::W10TitlebarButtonSpacing[5] = { - 1, - 1, - 2, - 1, //makes no sense, but spacing goes back to 1 - 2, -}; - -const int CMPCTheme::ToolbarIconPathDimension[5] = { - 7, - 9, - 11, - 12, - 14, -}; - -const int CMPCTheme::ToolbarHideButtonDimensions[5] = { - 11, - 14, - 17, - 20, - 22, -}; - -const int CMPCTheme::ToolbarGripperHeight[5] = { - 5, - 6, - 8, - 9, - 10, -}; - -const std::vector CMPCTheme::hideIcon96({ - {0, 0, newPath}, - {6, 6, linePath}, - {0, 6, newPath}, - {6, 0, linePath} -}); - -const std::vector CMPCTheme::hideIcon120({ - {0, 0, newPath}, - {8, 8, linePath}, - {0, 8, newPath}, - {8, 0, linePath}, -}); - -const std::vector CMPCTheme::hideIcon144({ - {0, 0, newPath}, - {10, 10, linePath}, - {0, 10, newPath}, - {10, 0, linePath}, -}); - -const std::vector CMPCTheme::hideIcon168({ - {0, 0, newPath}, - {11, 11, linePath}, - {0, 11, newPath}, - {11, 0, linePath}, -}); - -const std::vector CMPCTheme::hideIcon192({ - {0, 0, newPath}, - {13, 13, linePath}, - {0, 13, newPath}, - {13, 0, linePath}, -}); - - -void CMPCTheme::InitializeColors(ModernThemeMode themeMode) { - if (themeMode == ModernThemeMode::WINDOWSDEFAULT) { - if (AfxGetAppSettings().bWindows10DarkThemeActive) { - themeMode = ModernThemeMode::DARK; - } else { - themeMode = ModernThemeMode::LIGHT; - } - } - - if (themeMode == ModernThemeMode::DARK) { - drawThemedControls = true; - - MenuBGColor = RGB(43, 43, 43); - MenubarBGColor = RGB(43, 43, 43); - WindowBGColor = RGB(25, 25, 25); - ControlAreaBGColor = RGB(56, 56, 56); - - ContentBGColor = RGB(32, 32, 32); - ContentSelectedColor = RGB(119, 119, 119); - PlayerBGColor = RGB(32, 32, 32); - - HighLightColor = GetSysColor(COLOR_HIGHLIGHT); - - MenuSelectedColor = RGB(65, 65, 65); - MenubarSelectedBGColor = RGB(65, 65, 65); - MenuSeparatorColor = RGB(128, 128, 128); - MenuItemDisabledColor = RGB(109, 109, 109); - MainMenuBorderColor = RGB(32, 32, 32); - - TextFGColor = RGB(255, 255, 255); - PropPageCaptionFGColor = RGBGS(255); - TextFGColorFade = RGB(200, 200, 200); - ContentTextDisabledFGColorFade = RGB(109, 109, 109); - ContentTextDisabledFGColorFade2 = RGB(60, 60, 60); //even more faded, used for NA text on CListCtrl/audio switcher - - SubmenuColor = RGB(191, 191, 191); - - WindowBorderColorLight = RGB(99, 99, 99); - WindowBorderColorDim = RGB(43, 43, 43); - NoBorderColor = RGB(0, 0, 0); - GripperPatternColor = RGB(70, 70, 74); //visual studio dark, since explorer has no grippers - - ScrollBGColor = RGB(23, 23, 23); - ScrollProgressColor = RGB(60, 60, 60); - ScrollThumbColor = RGB(77, 77, 77); - ScrollThumbHoverColor = RGB(144, 144, 144); - ScrollThumbDragColor = RGB(183, 183, 183); - ScrollButtonArrowColor = RGB(103, 103, 103); - ScrollButtonArrowClickColor = RGBGS(103); - ScrollButtonHoverColor = RGB(55, 55, 55); - ScrollButtonClickColor = RGB(166, 166, 166); - - InlineEditBorderColor = RGB(255, 255, 255); - TooltipBorderColor = RGB(118, 118, 118); - - GroupBoxBorderColor = RGB(118, 118, 118); - - PlayerButtonHotColor = RGB(43, 43, 43); - PlayerButtonCheckedColor = RGB(66, 66, 66); - PlayerButtonClickedColor = RGB(55, 55, 55); - PlayerButtonBorderColor = RGB(0, 0, 0); - - ButtonBorderOuterColor = RGB(240, 240, 240); - ButtonBorderInnerFocusedColor = RGB(255, 255, 255); - ButtonBorderInnerColor = RGB(155, 155, 155); - ButtonBorderSelectedKBFocusColor = RGB(150, 150, 150); - ButtonBorderHoverKBFocusColor = RGB(181, 181, 181); - ButtonBorderKBFocusColor = RGB(195, 195, 195); - ButtonFillColor = RGB(51, 51, 51); - ButtonFillHoverColor = RGB(69, 69, 69); - ButtonFillSelectedColor = RGB(102, 102, 102); - ButtonDisabledFGColor = RGB(109, 109, 109); - - CheckboxBorderColor = RGB(137, 137, 137); - CheckboxBGColor = RGB(0, 0, 0); - CheckboxBorderHoverColor = RGB(121, 121, 121); - CheckboxBGHoverColor = RGB(8, 8, 8); - - ImageDisabledColor = RGB(109, 109, 109); - - SliderChannelColor = RGB(109, 109, 109); - - EditBorderColor = RGB(106, 106, 106); - - TreeCtrlLineColor = RGB(106, 106, 106); - TreeCtrlHoverColor = RGB(77, 77, 77); - TreeCtrlFocusColor = RGB(98, 98, 98); - - CheckColor = RGB(222, 222, 222); - - ColumnHeaderHotColor = RGB(67, 67, 67); - - StaticEtchedColor = RGB(65, 65, 65); - - ListCtrlDisabledBGColor = RGB(40, 40, 40); - ListCtrlGridColor = RGB(43, 43, 43); - ListCtrlErrorColor = RGB(242, 13, 13); - HeaderCtrlGridColor = RGB(99, 99, 99); - AudioSwitcherGridColor = RGB(99, 99, 99); - - TabCtrlBorderColor = RGB(99, 99, 99); - TabCtrlInactiveColor = RGB(40, 40, 40); - - - StatusBarBGColor = RGB(51, 51, 51); - StatusBarSeparatorColor = RGB(247, 247, 247); - - ProgressBarBGColor = RGB(0, 0, 0); - ProgressBarColor = RGB(75, 75, 75); - - SubresyncFadeText1 = RGB(190, 190, 190); - SubresyncFadeText2 = RGB(160, 160, 160); - SubresyncActiveFadeText = RGB(215, 215, 215); - SubresyncHLColor1 = RGB(100, 100, 100); - SubresyncHLColor2 = RGB(80, 80, 80); - SubresyncGridSepColor = RGB(220, 220, 220); - - ActivePlayListItemColor = RGB(38, 160, 218); - ActivePlayListItemHLColor = RGB(0, 40, 110); - StaticLinkColor = RGB(38, 160, 218); - - SeekbarCurrentPositionColor = RGB(38, 160, 218); - SeekbarChapterColor = RGB(100, 100, 100); - SeekbarABColor = RGB(242, 13, 13); - } else { - MenuBGColor = RGBGS(238); - MenubarBGColor = RGBGS(255); - WindowBGColor = RGBGS(255); - ControlAreaBGColor = RGBGS(240); - - ContentBGColor = RGBGS(255); - ContentSelectedColor = RGB(0, 120, 215); - PlayerBGColor = RGBGS(255); - - HighLightColor = GetSysColor(COLOR_HIGHLIGHT); - - MenuSelectedColor = RGBGS(255); - MenubarSelectedBGColor = RGBGS(238); - MenuSeparatorColor = RGBGS(145); - MenuItemDisabledColor = RGBGS(109); - MainMenuBorderColor = RGBGS(255); - - TextFGColor = RGBGS(0); - PropPageCaptionFGColor = RGBGS(245); - TextFGColorFade = RGBGS(109); - ContentTextDisabledFGColorFade = RGBGS(176); - ContentTextDisabledFGColorFade2 = RGBGS(224); //even more faded, used for NA text on CListCtrl/audio switcher - - SubmenuColor = RGBGS(0); - - WindowBorderColorLight = RGB(130, 135, 144); - WindowBorderColorDim = RGB(48, 56, 62); - NoBorderColor = RGBGS(0); - GripperPatternColor = RGB(153, 153, 153); //visual studio light, since explorer has no grippers - - ScrollBGColor = RGBGS(240); - ScrollProgressColor = RGB(130, 215, 146); - ScrollThumbColor = RGBGS(205); - ScrollThumbHoverColor = RGBGS(166); - ScrollThumbDragColor = RGBGS(119); - ScrollButtonArrowColor = RGBGS(96); - ScrollButtonArrowClickColor = RGBGS(255); - ScrollButtonHoverColor = RGBGS(218); - ScrollButtonClickColor = RGBGS(96); - - InlineEditBorderColor = RGBGS(0); - TooltipBorderColor = RGBGS(118); - - GroupBoxBorderColor = RGB(130, 135, 144); - - PlayerButtonHotColor = RGB(232, 239, 247); - PlayerButtonCheckedColor = RGB(205, 228, 252); - PlayerButtonClickedColor = RGB(201, 224, 247); - PlayerButtonBorderColor = RGB(98, 162, 228); - - - ButtonBorderOuterColor = RGBGS(173); - ButtonBorderInnerFocusedColor = RGB(0, 120, 215); - ButtonBorderInnerColor = RGBGS(173); - ButtonBorderSelectedKBFocusColor = RGB(60, 20, 7); - ButtonBorderHoverKBFocusColor = RGB(21, 1, 11); - ButtonBorderKBFocusColor = RGBGS(17); - ButtonFillColor = RGBGS(225); - ButtonFillHoverColor = RGB(229, 241, 251); - ButtonFillSelectedColor = RGB(204, 228, 247); - ButtonDisabledFGColor = RGBGS(204); - - CheckboxBorderColor = RGB(97, 121, 160); - CheckboxBGColor = RGBGS(255); - CheckboxBorderHoverColor = RGB(38, 160, 218); - CheckboxBGHoverColor = RGBGS(255); - - ImageDisabledColor = RGBGS(128); - - SliderChannelColor = RGBGS(128); - - EditBorderColor = RGB(106, 106, 106); - - TreeCtrlLineColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - TreeCtrlHoverColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - TreeCtrlFocusColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - CheckColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - ColumnHeaderHotColor = RGB(217, 235, 239); - - StaticEtchedColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - ListCtrlDisabledBGColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - ListCtrlGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - ListCtrlErrorColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - HeaderCtrlGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - AudioSwitcherGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - TabCtrlBorderColor = RGBGS(227); - TabCtrlInactiveColor = RGBGS(246); - - StatusBarBGColor = RGBGS(240); - StatusBarSeparatorColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - ProgressBarBGColor = RGBGS(255); - ProgressBarColor = RGB(130, 215, 146); - - SubresyncFadeText1 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncFadeText2 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncActiveFadeText = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncHLColor1 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncHLColor2 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncGridSepColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - ActivePlayListItemColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - ActivePlayListItemHLColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - StaticLinkColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - SeekbarCurrentPositionColor = RGB(38, 160, 218); - SeekbarChapterColor = RGB(100, 100, 100); - SeekbarABColor = RGB(242, 13, 13); - } -} +#include "stdafx.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + +#define RGBGS(x) ((COLORREF)(((BYTE)(x)|((WORD)((BYTE)(x))<<8))|(((DWORD)(BYTE)(x))<<16))) + +const int CMPCTheme::GroupBoxTextIndent = 8; +bool CMPCTheme::drawThemedControls = false; +COLORREF CMPCTheme::CloseHoverColor = RGB(232, 17, 35); +COLORREF CMPCTheme::ClosePushColor = RGB(139, 10, 20); +COLORREF CMPCTheme::DebugColorRed = RGB(255, 0, 0); +COLORREF CMPCTheme::DebugColorYellow = RGB(255, 255, 0); +COLORREF CMPCTheme::DebugColorGreen = RGB(0, 255, 0); +COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedTextColor = RGB(255, 255, 255); +COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedBGColor = RGB(56, 56, 56); +COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedEditBorderColor = RGB(155, 155, 155); +COLORREF CMPCTheme::W10DarkThemeTitlebarBGColor = RGB(0, 0, 0); +COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveBGColor = RGB(43, 43, 43); +COLORREF CMPCTheme::W10DarkThemeTitlebarFGColor = RGB(255, 255, 255); +COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveFGColor = RGB(170, 170, 170); +COLORREF CMPCTheme::W10DarkThemeTitlebarIconPenColor = RGB(255, 255, 255); +COLORREF CMPCTheme::W10DarkThemeTitlebarControlHoverBGColor = RGB(43, 43, 43); +COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveControlHoverBGColor = RGB(65, 65, 65); +COLORREF CMPCTheme::W10DarkThemeTitlebarControlPushedBGColor = RGB(70, 70, 70); +COLORREF CMPCTheme::W10DarkThemeWindowBorderColor = RGB(57, 57, 57); + + + +COLORREF CMPCTheme::MenuBGColor; +COLORREF CMPCTheme::MenubarBGColor; +COLORREF CMPCTheme::WindowBGColor; +COLORREF CMPCTheme::ControlAreaBGColor; + +COLORREF CMPCTheme::ContentBGColor; +COLORREF CMPCTheme::ContentSelectedColor; +COLORREF CMPCTheme::PlayerBGColor; + +COLORREF CMPCTheme::HighLightColor; + +COLORREF CMPCTheme::MenuSelectedColor; +COLORREF CMPCTheme::MenubarSelectedBGColor; +COLORREF CMPCTheme::MenuSeparatorColor; +COLORREF CMPCTheme::MenuItemDisabledColor; +//COLORREF CMPCTheme::MenuItemUnfocusedColor; +COLORREF CMPCTheme::MainMenuBorderColor; + +COLORREF CMPCTheme::TextFGColor; +COLORREF CMPCTheme::TextFGColorFade; +COLORREF CMPCTheme::PropPageCaptionFGColor; +COLORREF CMPCTheme::ContentTextDisabledFGColorFade; +COLORREF CMPCTheme::ContentTextDisabledFGColorFade2; //even more faded, used for NA text on CListCtrl/audio switcher + +COLORREF CMPCTheme::SubmenuColor; + +COLORREF CMPCTheme::WindowBorderColorLight; +COLORREF CMPCTheme::WindowBorderColorDim; +COLORREF CMPCTheme::NoBorderColor; +COLORREF CMPCTheme::GripperPatternColor; //visual studio, since explorer has no grippers + +COLORREF CMPCTheme::ScrollBGColor; +COLORREF CMPCTheme::ScrollProgressColor; +COLORREF CMPCTheme::ScrollThumbColor; +COLORREF CMPCTheme::ScrollThumbHoverColor; +COLORREF CMPCTheme::ScrollThumbDragColor; +COLORREF CMPCTheme::ScrollButtonArrowColor; +COLORREF CMPCTheme::ScrollButtonArrowClickColor; +COLORREF CMPCTheme::ScrollButtonHoverColor; +COLORREF CMPCTheme::ScrollButtonClickColor; + +COLORREF CMPCTheme::InlineEditBorderColor; +COLORREF CMPCTheme::TooltipBorderColor; + +COLORREF CMPCTheme::GroupBoxBorderColor; + +COLORREF CMPCTheme::PlayerButtonHotColor; +COLORREF CMPCTheme::PlayerButtonCheckedColor; +COLORREF CMPCTheme::PlayerButtonClickedColor; +COLORREF CMPCTheme::PlayerButtonBorderColor; + +COLORREF CMPCTheme::ButtonBorderOuterColor; +COLORREF CMPCTheme::ButtonBorderInnerFocusedColor; +COLORREF CMPCTheme::ButtonBorderInnerColor; +COLORREF CMPCTheme::ButtonBorderSelectedKBFocusColor; +COLORREF CMPCTheme::ButtonBorderHoverKBFocusColor; +COLORREF CMPCTheme::ButtonBorderKBFocusColor; +COLORREF CMPCTheme::ButtonFillColor; +COLORREF CMPCTheme::ButtonFillHoverColor; +COLORREF CMPCTheme::ButtonFillSelectedColor; +COLORREF CMPCTheme::ButtonDisabledFGColor; + +COLORREF CMPCTheme::CheckboxBorderColor; +COLORREF CMPCTheme::CheckboxBGColor; +COLORREF CMPCTheme::CheckboxBorderHoverColor; +COLORREF CMPCTheme::CheckboxBGHoverColor; + +COLORREF CMPCTheme::ImageDisabledColor; + +COLORREF CMPCTheme::SliderChannelColor; + +COLORREF CMPCTheme::EditBorderColor; + +COLORREF CMPCTheme::TreeCtrlLineColor; +COLORREF CMPCTheme::TreeCtrlHoverColor; +COLORREF CMPCTheme::TreeCtrlFocusColor; + +COLORREF CMPCTheme::CheckColor; + +COLORREF CMPCTheme::ColumnHeaderHotColor; + +COLORREF CMPCTheme::StaticEtchedColor; + +COLORREF CMPCTheme::ListCtrlDisabledBGColor; +COLORREF CMPCTheme::ListCtrlGridColor; +COLORREF CMPCTheme::ListCtrlErrorColor; +COLORREF CMPCTheme::HeaderCtrlGridColor; +COLORREF CMPCTheme::AudioSwitcherGridColor; + +COLORREF CMPCTheme::TabCtrlBorderColor; +COLORREF CMPCTheme::TabCtrlInactiveColor; + + +COLORREF CMPCTheme::StatusBarBGColor; +COLORREF CMPCTheme::StatusBarSeparatorColor; + + +COLORREF CMPCTheme::ProgressBarBGColor; +COLORREF CMPCTheme::ProgressBarColor; + +COLORREF CMPCTheme::SubresyncFadeText1; +COLORREF CMPCTheme::SubresyncFadeText2; +COLORREF CMPCTheme::SubresyncActiveFadeText; +COLORREF CMPCTheme::SubresyncHLColor1; +COLORREF CMPCTheme::SubresyncHLColor2; +COLORREF CMPCTheme::SubresyncGridSepColor; + +COLORREF CMPCTheme::ActivePlayListItemColor; +COLORREF CMPCTheme::ActivePlayListItemHLColor; +COLORREF CMPCTheme::StaticLinkColor; + +COLORREF CMPCTheme::SeekbarCurrentPositionColor; +COLORREF CMPCTheme::SeekbarChapterColor; +COLORREF CMPCTheme::SeekbarABColor; + +wchar_t* const CMPCTheme::uiTextFont = L"Segoe UI"; +wchar_t* const CMPCTheme::uiStaticTextFont = L"Segoe UI Semilight"; +wchar_t* const CMPCTheme::uiSymbolFont = L"MS UI Gothic"; + + +const int CMPCTheme::gripPatternLong = 5; +const int CMPCTheme::gripPatternShort = 4; + + +const BYTE CMPCTheme::GripperBitsH[10] = { + 0x80, 0x00, + 0x00, 0x00, + 0x20, 0x00, + 0x00, 0x00, + 0x80, 0x00, +}; + +const BYTE CMPCTheme::GripperBitsV[8] = { + 0x88, 0x00, + 0x00, 0x00, + 0x20, 0x00, + 0x00, 0x00, +}; + +const COLORREF CMPCTheme::ComboboxArrowColor = RGB(200, 200, 200); +const COLORREF CMPCTheme::ComboboxArrowColorDisabled = RGB(100, 100, 100); + +const COLORREF CMPCTheme::HeaderCtrlSortArrowColor = RGB(200, 200, 200); + + +const BYTE CMPCTheme::CheckBits[14] = { + 0x02, 0x00, + 0x06, 0x00, + 0x8E, 0x00, + 0xDC, 0x00, + 0xF8, 0x00, + 0x70, 0x00, + 0x20, 0x00, +}; + +const int CMPCTheme::CheckWidth = 7; +const int CMPCTheme::CheckHeight = 7; + + +const UINT CMPCTheme::ThemeCheckBoxes[5] = { + IDB_DT_CB_96, + IDB_DT_CB_120, + IDB_DT_CB_144, + IDB_DT_CB_144, + IDB_DT_CB_192, +}; + +const UINT CMPCTheme::ThemeRadios[5] = { + IDB_DT_RADIO_96, + IDB_DT_RADIO_120, + IDB_DT_RADIO_144, + IDB_DT_RADIO_144, + IDB_DT_RADIO_192, +}; + +const UINT CMPCTheme::ThemeGrippers[5] = { + IDB_GRIPPER_96, + IDB_GRIPPER_120, + IDB_GRIPPER_144, + IDB_GRIPPER_168, + IDB_GRIPPER_192, +}; + +const std::vector CMPCTheme::minimizeIcon96({ + {2, 6, newPath}, + {11, 6, closePath}, +}); + +const std::vector CMPCTheme::minimizeIcon120({ + {3, 7, newPath}, + {14, 7, closePath}, +}); + +const std::vector CMPCTheme::minimizeIcon144({ + {4, 9, newPath}, + {18, 9, closePath}, +}); + +//same size as 144, but centered better +const std::vector CMPCTheme::minimizeIcon168({ + {2, 9, newPath}, + {16, 9, closePath}, +}); + +const std::vector CMPCTheme::minimizeIcon192({ + {5.5, 12.5, newPath}, + {23.5, 12.5, closePath}, +}); + +const std::vector CMPCTheme::restoreIcon96({ + {2, 4, newPath}, + {9, 4, linePath}, + {9, 11, linePath}, + {2, 11, linePath}, + {2, 4, linePath}, + {4, 4, newPath}, + {4, 2, linePath}, + {11, 2, linePath}, + {11, 9, linePath}, + {9, 9, linePath} +}); + +const std::vector CMPCTheme::restoreIcon120({ + {2, 4, newPath}, + {11, 4, linePath}, + {11, 13, linePath}, + {2, 13, linePath}, + {2, 4, linePath}, + {4, 4, newPath}, + {4, 2, linePath}, + {13, 2, linePath}, + {13, 11, linePath}, + {11, 11, linePath}, +}); + +const std::vector CMPCTheme::restoreIcon144({ + {2, 5, newPath}, + {13, 5, linePath}, + {13, 16, linePath}, + {2, 16, linePath}, + {2, 5, linePath}, + {5, 5, newPath}, + {5, 2, linePath}, + {16, 2, linePath}, + {16, 13, linePath}, + {13, 13, linePath}, +}); + +const std::vector CMPCTheme::restoreIcon168 = CMPCTheme::restoreIcon144; + +const std::vector CMPCTheme::restoreIcon192({ + { 3.5, 7.5, newPath}, + { 17.5, 7.5, linePath }, + { 17.5, 21.5, linePath }, + { 3.5, 21.5, linePath }, + { 3.5, 7.5, linePath }, + { 7.5, 7.5, newPath }, + { 7.5, 3.5, linePath }, + { 21.5, 3.5, linePath }, + { 21.5, 17.5, linePath }, + { 17.5, 17.5, linePath }, +}); + +const std::vector CMPCTheme::maximizeIcon96({ + {1, 1, newPath}, + {1, 10, linePath}, + {10, 10, linePath}, + {10, 1, linePath}, + {1, 1, linePath} +}); + +const std::vector CMPCTheme::maximizeIcon120({ + {2, 2, newPath}, + {2, 13, linePath}, + {13, 13, linePath}, + {13, 2, linePath}, + {2, 2, linePath}, +}); + +const std::vector CMPCTheme::maximizeIcon144({ + {2, 2, newPath}, + {2, 16, linePath}, + {16, 16, linePath}, + {16, 2, linePath}, + {2, 2, linePath}, +}); + +const std::vector CMPCTheme::maximizeIcon168 = CMPCTheme::maximizeIcon144; + +const std::vector CMPCTheme::maximizeIcon192({ + {3.5, 3.5, newPath}, + {3.5, 21.5, linePath}, + {21.5, 21.5, linePath}, + {21.5, 3.5, linePath}, + {3.5, 3.5, linePath}, +}); + +const std::vector CMPCTheme::closeIcon96({ + {1, 1, newPath}, + {10, 10, closePath}, + {1, 10, newPath}, + {10, 1, closePath} +}); + +const std::vector CMPCTheme::closeIcon120({ + {2, 2, newPath}, + {13, 13, linePath}, + {2, 13, newPath}, + {13, 2, linePath}, +}); + +const std::vector CMPCTheme::closeIcon144({ + {2, 2, newPath}, + {16, 16, linePath}, + {2, 16, newPath}, + {16, 2, linePath}, +}); + +const std::vector CMPCTheme::closeIcon168 = CMPCTheme::closeIcon144; + +const std::vector CMPCTheme::closeIcon192({ + {3.5, 3.5, newPath}, + {21.5, 21.5, linePath}, + {3.5, 21.5, newPath}, + {21.5, 3.5, linePath}, +}); + +//windows10 centers the icon "path" on the button, inside a frame +//sometimes this frame is centered, but at different dpis it's misaligned by 1-2 pixels +//we use the width/height of the frame to tweak the "center" position +const int CMPCTheme::W10TitlebarIconPathHeight[5] = { + 12, + 15, //should be 16, but to match windows 10 + 18, //should be 19 + 18, //should be 19 + 26, +}; + +const int CMPCTheme::W10TitlebarIconPathWidth[5] = { + 12, + 17, //should be 16, but to match windows 10 + 19, + 19, + 28, +}; + +const float CMPCTheme::W10TitlebarIconPathThickness[5] = { + 1, + 1, + 1, + 1, + 2, +}; + +const int CMPCTheme::W10TitlebarButtonWidth[5] = { + 45, + 58, + 69, + 80, + 91, +}; + +const int CMPCTheme::W10TitlebarButtonSpacing[5] = { + 1, + 1, + 2, + 1, //makes no sense, but spacing goes back to 1 + 2, +}; + +const int CMPCTheme::ToolbarIconPathDimension[5] = { + 7, + 9, + 11, + 12, + 14, +}; + +const int CMPCTheme::ToolbarHideButtonDimensions[5] = { + 11, + 14, + 17, + 20, + 22, +}; + +const int CMPCTheme::ToolbarGripperHeight[5] = { + 5, + 6, + 8, + 9, + 10, +}; + +const std::vector CMPCTheme::hideIcon96({ + {0, 0, newPath}, + {6, 6, linePath}, + {0, 6, newPath}, + {6, 0, linePath} +}); + +const std::vector CMPCTheme::hideIcon120({ + {0, 0, newPath}, + {8, 8, linePath}, + {0, 8, newPath}, + {8, 0, linePath}, +}); + +const std::vector CMPCTheme::hideIcon144({ + {0, 0, newPath}, + {10, 10, linePath}, + {0, 10, newPath}, + {10, 0, linePath}, +}); + +const std::vector CMPCTheme::hideIcon168({ + {0, 0, newPath}, + {11, 11, linePath}, + {0, 11, newPath}, + {11, 0, linePath}, +}); + +const std::vector CMPCTheme::hideIcon192({ + {0, 0, newPath}, + {13, 13, linePath}, + {0, 13, newPath}, + {13, 0, linePath}, +}); + + +void CMPCTheme::InitializeColors(ModernThemeMode themeMode) { + if (themeMode == ModernThemeMode::WINDOWSDEFAULT) { + if (AfxGetAppSettings().bWindows10DarkThemeActive) { + themeMode = ModernThemeMode::DARK; + } else { + themeMode = ModernThemeMode::LIGHT; + } + } + + if (themeMode == ModernThemeMode::DARK) { + drawThemedControls = true; + + MenuBGColor = RGB(43, 43, 43); + MenubarBGColor = RGB(43, 43, 43); + WindowBGColor = RGB(25, 25, 25); + ControlAreaBGColor = RGB(56, 56, 56); + + ContentBGColor = RGB(32, 32, 32); + ContentSelectedColor = RGB(119, 119, 119); + PlayerBGColor = RGB(32, 32, 32); + + HighLightColor = GetSysColor(COLOR_HIGHLIGHT); + + MenuSelectedColor = RGB(65, 65, 65); + MenubarSelectedBGColor = RGB(65, 65, 65); + MenuSeparatorColor = RGB(128, 128, 128); + MenuItemDisabledColor = RGB(109, 109, 109); + MainMenuBorderColor = RGB(32, 32, 32); + + TextFGColor = RGB(255, 255, 255); + PropPageCaptionFGColor = RGBGS(255); + TextFGColorFade = RGB(200, 200, 200); + ContentTextDisabledFGColorFade = RGB(109, 109, 109); + ContentTextDisabledFGColorFade2 = RGB(60, 60, 60); //even more faded, used for NA text on CListCtrl/audio switcher + + SubmenuColor = RGB(191, 191, 191); + + WindowBorderColorLight = RGB(99, 99, 99); + WindowBorderColorDim = RGB(43, 43, 43); + NoBorderColor = RGB(0, 0, 0); + GripperPatternColor = RGB(70, 70, 74); //visual studio dark, since explorer has no grippers + + ScrollBGColor = RGB(23, 23, 23); + ScrollProgressColor = RGB(60, 60, 60); + ScrollThumbColor = RGB(77, 77, 77); + ScrollThumbHoverColor = RGB(144, 144, 144); + ScrollThumbDragColor = RGB(183, 183, 183); + ScrollButtonArrowColor = RGB(103, 103, 103); + ScrollButtonArrowClickColor = RGBGS(103); + ScrollButtonHoverColor = RGB(55, 55, 55); + ScrollButtonClickColor = RGB(166, 166, 166); + + InlineEditBorderColor = RGB(255, 255, 255); + TooltipBorderColor = RGB(118, 118, 118); + + GroupBoxBorderColor = RGB(118, 118, 118); + + PlayerButtonHotColor = RGB(43, 43, 43); + PlayerButtonCheckedColor = RGB(66, 66, 66); + PlayerButtonClickedColor = RGB(55, 55, 55); + PlayerButtonBorderColor = RGB(0, 0, 0); + + ButtonBorderOuterColor = RGB(240, 240, 240); + ButtonBorderInnerFocusedColor = RGB(255, 255, 255); + ButtonBorderInnerColor = RGB(155, 155, 155); + ButtonBorderSelectedKBFocusColor = RGB(150, 150, 150); + ButtonBorderHoverKBFocusColor = RGB(181, 181, 181); + ButtonBorderKBFocusColor = RGB(195, 195, 195); + ButtonFillColor = RGB(51, 51, 51); + ButtonFillHoverColor = RGB(69, 69, 69); + ButtonFillSelectedColor = RGB(102, 102, 102); + ButtonDisabledFGColor = RGB(109, 109, 109); + + CheckboxBorderColor = RGB(137, 137, 137); + CheckboxBGColor = RGB(0, 0, 0); + CheckboxBorderHoverColor = RGB(121, 121, 121); + CheckboxBGHoverColor = RGB(8, 8, 8); + + ImageDisabledColor = RGB(109, 109, 109); + + SliderChannelColor = RGB(109, 109, 109); + + EditBorderColor = RGB(106, 106, 106); + + TreeCtrlLineColor = RGB(106, 106, 106); + TreeCtrlHoverColor = RGB(77, 77, 77); + TreeCtrlFocusColor = RGB(98, 98, 98); + + CheckColor = RGB(222, 222, 222); + + ColumnHeaderHotColor = RGB(67, 67, 67); + + StaticEtchedColor = RGB(65, 65, 65); + + ListCtrlDisabledBGColor = RGB(40, 40, 40); + ListCtrlGridColor = RGB(43, 43, 43); + ListCtrlErrorColor = RGB(242, 13, 13); + HeaderCtrlGridColor = RGB(99, 99, 99); + AudioSwitcherGridColor = RGB(99, 99, 99); + + TabCtrlBorderColor = RGB(99, 99, 99); + TabCtrlInactiveColor = RGB(40, 40, 40); + + + StatusBarBGColor = RGB(51, 51, 51); + StatusBarSeparatorColor = RGB(247, 247, 247); + + ProgressBarBGColor = RGB(0, 0, 0); + ProgressBarColor = RGB(75, 75, 75); + + SubresyncFadeText1 = RGB(190, 190, 190); + SubresyncFadeText2 = RGB(160, 160, 160); + SubresyncActiveFadeText = RGB(215, 215, 215); + SubresyncHLColor1 = RGB(100, 100, 100); + SubresyncHLColor2 = RGB(80, 80, 80); + SubresyncGridSepColor = RGB(220, 220, 220); + + ActivePlayListItemColor = RGB(38, 160, 218); + ActivePlayListItemHLColor = RGB(0, 40, 110); + StaticLinkColor = RGB(38, 160, 218); + + SeekbarCurrentPositionColor = RGB(38, 160, 218); + SeekbarChapterColor = RGB(100, 100, 100); + SeekbarABColor = RGB(242, 13, 13); + } else { + MenuBGColor = RGBGS(238); + MenubarBGColor = RGBGS(255); + WindowBGColor = RGBGS(255); + ControlAreaBGColor = RGBGS(240); + + ContentBGColor = RGBGS(255); + ContentSelectedColor = RGB(0, 120, 215); + PlayerBGColor = RGBGS(255); + + HighLightColor = GetSysColor(COLOR_HIGHLIGHT); + + MenuSelectedColor = RGBGS(255); + MenubarSelectedBGColor = RGBGS(238); + MenuSeparatorColor = RGBGS(145); + MenuItemDisabledColor = RGBGS(109); + MainMenuBorderColor = RGBGS(255); + + TextFGColor = RGBGS(0); + PropPageCaptionFGColor = RGBGS(245); + TextFGColorFade = RGBGS(109); + ContentTextDisabledFGColorFade = RGBGS(176); + ContentTextDisabledFGColorFade2 = RGBGS(224); //even more faded, used for NA text on CListCtrl/audio switcher + + SubmenuColor = RGBGS(0); + + WindowBorderColorLight = RGB(130, 135, 144); + WindowBorderColorDim = RGB(48, 56, 62); + NoBorderColor = RGBGS(0); + GripperPatternColor = RGB(153, 153, 153); //visual studio light, since explorer has no grippers + + ScrollBGColor = RGBGS(240); + ScrollProgressColor = RGB(130, 215, 146); + ScrollThumbColor = RGBGS(205); + ScrollThumbHoverColor = RGBGS(166); + ScrollThumbDragColor = RGBGS(119); + ScrollButtonArrowColor = RGBGS(96); + ScrollButtonArrowClickColor = RGBGS(255); + ScrollButtonHoverColor = RGBGS(218); + ScrollButtonClickColor = RGBGS(96); + + InlineEditBorderColor = RGBGS(0); + TooltipBorderColor = RGBGS(118); + + GroupBoxBorderColor = RGB(130, 135, 144); + + PlayerButtonHotColor = RGB(232, 239, 247); + PlayerButtonCheckedColor = RGB(205, 228, 252); + PlayerButtonClickedColor = RGB(201, 224, 247); + PlayerButtonBorderColor = RGB(98, 162, 228); + + + ButtonBorderOuterColor = RGBGS(173); + ButtonBorderInnerFocusedColor = RGB(0, 120, 215); + ButtonBorderInnerColor = RGBGS(173); + ButtonBorderSelectedKBFocusColor = RGB(60, 20, 7); + ButtonBorderHoverKBFocusColor = RGB(21, 1, 11); + ButtonBorderKBFocusColor = RGBGS(17); + ButtonFillColor = RGBGS(225); + ButtonFillHoverColor = RGB(229, 241, 251); + ButtonFillSelectedColor = RGB(204, 228, 247); + ButtonDisabledFGColor = RGBGS(204); + + CheckboxBorderColor = RGB(97, 121, 160); + CheckboxBGColor = RGBGS(255); + CheckboxBorderHoverColor = RGB(38, 160, 218); + CheckboxBGHoverColor = RGBGS(255); + + ImageDisabledColor = RGBGS(128); + + SliderChannelColor = RGBGS(128); + + EditBorderColor = RGB(106, 106, 106); + + TreeCtrlLineColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + TreeCtrlHoverColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + TreeCtrlFocusColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + CheckColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + ColumnHeaderHotColor = RGB(217, 235, 239); + + StaticEtchedColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + ListCtrlDisabledBGColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + ListCtrlGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + ListCtrlErrorColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + HeaderCtrlGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + AudioSwitcherGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + TabCtrlBorderColor = RGBGS(227); + TabCtrlInactiveColor = RGBGS(246); + + StatusBarBGColor = RGBGS(240); + StatusBarSeparatorColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + ProgressBarBGColor = RGBGS(255); + ProgressBarColor = RGB(130, 215, 146); + + SubresyncFadeText1 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncFadeText2 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncActiveFadeText = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncHLColor1 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncHLColor2 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncGridSepColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + ActivePlayListItemColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + ActivePlayListItemHLColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + StaticLinkColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + SeekbarCurrentPositionColor = RGB(38, 160, 218); + SeekbarChapterColor = RGB(100, 100, 100); + SeekbarABColor = RGB(242, 13, 13); + } +} diff --git a/src/mpc-hc/CMPCTheme.h b/src/mpc-hc/CMPCTheme.h index 12c30b8a404..a94b0c70d02 100755 --- a/src/mpc-hc/CMPCTheme.h +++ b/src/mpc-hc/CMPCTheme.h @@ -1,195 +1,195 @@ -#pragma once - -class CMPCTheme -{ -public: - enum class ModernThemeMode { - DARK, - LIGHT, - WINDOWSDEFAULT - }; - - static COLORREF MenuBGColor; - static COLORREF MenubarBGColor; - static COLORREF WindowBGColor; //used in explorer for left nav - static COLORREF ControlAreaBGColor; //used in file open dialog for button / file selection bg - static COLORREF ContentBGColor; //used in explorer for bg of file list - static COLORREF ContentSelectedColor; //used in explorer for bg of file list - static COLORREF PlayerBGColor; - static COLORREF HighLightColor; - - static COLORREF MenuSelectedColor; - static COLORREF MenubarSelectedBGColor; - static COLORREF MenuItemDisabledColor; - static COLORREF MainMenuBorderColor; - static COLORREF MenuSeparatorColor; - - static COLORREF TextFGColor; - static COLORREF TextFGColorFade; - static COLORREF PropPageCaptionFGColor; - static COLORREF ContentTextDisabledFGColorFade; - static COLORREF ContentTextDisabledFGColorFade2; - static COLORREF SubmenuColor; - static COLORREF CloseHoverColor; - static COLORREF ClosePushColor; - static COLORREF CloseColor; - static COLORREF WindowBorderColorLight; - static COLORREF WindowBorderColorDim; - static COLORREF NoBorderColor; - static COLORREF GripperPatternColor; - - static COLORREF ScrollBGColor; - static COLORREF ScrollProgressColor; - static COLORREF ScrollThumbColor; - static COLORREF ScrollThumbHoverColor; - static COLORREF ScrollThumbDragColor; - static COLORREF ScrollButtonArrowColor; - static COLORREF ScrollButtonArrowClickColor; - static COLORREF ScrollButtonHoverColor; - static COLORREF ScrollButtonClickColor; - - static COLORREF InlineEditBorderColor; - static COLORREF TooltipBorderColor; - - static COLORREF GroupBoxBorderColor; - - static COLORREF DebugColorRed; - static COLORREF DebugColorYellow; - static COLORREF DebugColorGreen; - - static COLORREF PlayerButtonHotColor; - static COLORREF PlayerButtonCheckedColor; - static COLORREF PlayerButtonClickedColor; - static COLORREF PlayerButtonBorderColor; - - static COLORREF ButtonBorderOuterColor; - static COLORREF ButtonBorderInnerFocusedColor; - static COLORREF ButtonBorderInnerColor; - static COLORREF ButtonBorderSelectedKBFocusColor; - static COLORREF ButtonBorderHoverKBFocusColor; - static COLORREF ButtonBorderKBFocusColor; - static COLORREF ButtonFillColor; - static COLORREF ButtonFillHoverColor; - static COLORREF ButtonFillSelectedColor; - static COLORREF ButtonDisabledFGColor; - - static COLORREF CheckboxBorderColor; - static COLORREF CheckboxBGColor; - static COLORREF CheckboxBorderHoverColor; - static COLORREF CheckboxBGHoverColor; - - static COLORREF ImageDisabledColor; - - static COLORREF SliderChannelColor; - - static COLORREF EditBorderColor; - - static COLORREF TreeCtrlLineColor; - static COLORREF TreeCtrlHoverColor; - static COLORREF TreeCtrlFocusColor; - - static COLORREF CheckColor; - - static COLORREF ColumnHeaderHotColor; - - static COLORREF StaticEtchedColor; - - static COLORREF ListCtrlDisabledBGColor; - static COLORREF ListCtrlGridColor; - static COLORREF ListCtrlErrorColor; - static COLORREF HeaderCtrlGridColor; - static COLORREF AudioSwitcherGridColor; - - static COLORREF TabCtrlBorderColor; - static COLORREF TabCtrlInactiveColor; - - static COLORREF StatusBarBGColor; - static COLORREF StatusBarSeparatorColor; - static COLORREF StatusBarEditBorderColor; - - static COLORREF W10DarkThemeFileDialogInjectedTextColor; - static COLORREF W10DarkThemeFileDialogInjectedBGColor; - static COLORREF W10DarkThemeFileDialogInjectedEditBorderColor; - static COLORREF W10DarkThemeTitlebarBGColor; - static COLORREF W10DarkThemeTitlebarInactiveBGColor; - static COLORREF W10DarkThemeTitlebarFGColor; - static COLORREF W10DarkThemeTitlebarInactiveFGColor; - static COLORREF W10DarkThemeTitlebarIconPenColor; - static COLORREF W10DarkThemeTitlebarControlHoverBGColor; - static COLORREF W10DarkThemeTitlebarInactiveControlHoverBGColor; - static COLORREF W10DarkThemeTitlebarControlPushedBGColor; - static COLORREF W10DarkThemeWindowBorderColor; - - static COLORREF ProgressBarBGColor; - static COLORREF ProgressBarColor; - - static COLORREF SubresyncFadeText1; - static COLORREF SubresyncFadeText2; - static COLORREF SubresyncActiveFadeText; - static COLORREF SubresyncHLColor1; - static COLORREF SubresyncHLColor2; - static COLORREF SubresyncGridSepColor; - - static COLORREF ActivePlayListItemColor; - static COLORREF ActivePlayListItemHLColor; - static COLORREF StaticLinkColor; - static COLORREF SeekbarCurrentPositionColor; - static COLORREF SeekbarChapterColor; - static COLORREF SeekbarABColor; - - static const int GroupBoxTextIndent; - - - static const BYTE GripperBitsH[10]; - static const BYTE GripperBitsV[8]; - static const int gripPatternShort; - static const int gripPatternLong; - - static wchar_t* const uiTextFont; - static wchar_t* const uiStaticTextFont; - static wchar_t* const uiSymbolFont; - - - static const COLORREF ComboboxArrowColor; - static const COLORREF ComboboxArrowColorDisabled; - - static const COLORREF HeaderCtrlSortArrowColor; - - static const BYTE CheckBits[14]; - static const int CheckWidth; - static const int CheckHeight; - - const static UINT ThemeCheckBoxes[5]; - const static UINT ThemeRadios[5]; - const static UINT ThemeGrippers[5]; - - enum pathState { - linePath, - newPath, - closePath - }; - - struct pathPoint { - float x; - float y; - pathState state; - }; - static const std::vector minimizeIcon96, minimizeIcon120, minimizeIcon144, minimizeIcon168, minimizeIcon192; - static const std::vector maximizeIcon96, maximizeIcon120, maximizeIcon144, maximizeIcon168, maximizeIcon192; - static const std::vector restoreIcon96, restoreIcon120, restoreIcon144, restoreIcon168, restoreIcon192; - static const std::vector closeIcon96, closeIcon120, closeIcon144, closeIcon168, closeIcon192; - static const std::vector hideIcon96, hideIcon120, hideIcon144, hideIcon168, hideIcon192; - static const int CMPCTheme::W10TitlebarIconPathHeight[5]; - static const int CMPCTheme::W10TitlebarIconPathWidth[5]; - static const float CMPCTheme::W10TitlebarIconPathThickness[5]; - static const int CMPCTheme::W10TitlebarButtonWidth[5]; - static const int CMPCTheme::W10TitlebarButtonSpacing[5]; - static const int CMPCTheme::ToolbarIconPathDimension[5]; - static const int CMPCTheme::ToolbarGripperHeight[5]; - static const int CMPCTheme::ToolbarHideButtonDimensions[5]; - - - static bool drawThemedControls; - - static void InitializeColors(ModernThemeMode themeMode); -}; +#pragma once + +class CMPCTheme +{ +public: + enum class ModernThemeMode { + DARK, + LIGHT, + WINDOWSDEFAULT + }; + + static COLORREF MenuBGColor; + static COLORREF MenubarBGColor; + static COLORREF WindowBGColor; //used in explorer for left nav + static COLORREF ControlAreaBGColor; //used in file open dialog for button / file selection bg + static COLORREF ContentBGColor; //used in explorer for bg of file list + static COLORREF ContentSelectedColor; //used in explorer for bg of file list + static COLORREF PlayerBGColor; + static COLORREF HighLightColor; + + static COLORREF MenuSelectedColor; + static COLORREF MenubarSelectedBGColor; + static COLORREF MenuItemDisabledColor; + static COLORREF MainMenuBorderColor; + static COLORREF MenuSeparatorColor; + + static COLORREF TextFGColor; + static COLORREF TextFGColorFade; + static COLORREF PropPageCaptionFGColor; + static COLORREF ContentTextDisabledFGColorFade; + static COLORREF ContentTextDisabledFGColorFade2; + static COLORREF SubmenuColor; + static COLORREF CloseHoverColor; + static COLORREF ClosePushColor; + static COLORREF CloseColor; + static COLORREF WindowBorderColorLight; + static COLORREF WindowBorderColorDim; + static COLORREF NoBorderColor; + static COLORREF GripperPatternColor; + + static COLORREF ScrollBGColor; + static COLORREF ScrollProgressColor; + static COLORREF ScrollThumbColor; + static COLORREF ScrollThumbHoverColor; + static COLORREF ScrollThumbDragColor; + static COLORREF ScrollButtonArrowColor; + static COLORREF ScrollButtonArrowClickColor; + static COLORREF ScrollButtonHoverColor; + static COLORREF ScrollButtonClickColor; + + static COLORREF InlineEditBorderColor; + static COLORREF TooltipBorderColor; + + static COLORREF GroupBoxBorderColor; + + static COLORREF DebugColorRed; + static COLORREF DebugColorYellow; + static COLORREF DebugColorGreen; + + static COLORREF PlayerButtonHotColor; + static COLORREF PlayerButtonCheckedColor; + static COLORREF PlayerButtonClickedColor; + static COLORREF PlayerButtonBorderColor; + + static COLORREF ButtonBorderOuterColor; + static COLORREF ButtonBorderInnerFocusedColor; + static COLORREF ButtonBorderInnerColor; + static COLORREF ButtonBorderSelectedKBFocusColor; + static COLORREF ButtonBorderHoverKBFocusColor; + static COLORREF ButtonBorderKBFocusColor; + static COLORREF ButtonFillColor; + static COLORREF ButtonFillHoverColor; + static COLORREF ButtonFillSelectedColor; + static COLORREF ButtonDisabledFGColor; + + static COLORREF CheckboxBorderColor; + static COLORREF CheckboxBGColor; + static COLORREF CheckboxBorderHoverColor; + static COLORREF CheckboxBGHoverColor; + + static COLORREF ImageDisabledColor; + + static COLORREF SliderChannelColor; + + static COLORREF EditBorderColor; + + static COLORREF TreeCtrlLineColor; + static COLORREF TreeCtrlHoverColor; + static COLORREF TreeCtrlFocusColor; + + static COLORREF CheckColor; + + static COLORREF ColumnHeaderHotColor; + + static COLORREF StaticEtchedColor; + + static COLORREF ListCtrlDisabledBGColor; + static COLORREF ListCtrlGridColor; + static COLORREF ListCtrlErrorColor; + static COLORREF HeaderCtrlGridColor; + static COLORREF AudioSwitcherGridColor; + + static COLORREF TabCtrlBorderColor; + static COLORREF TabCtrlInactiveColor; + + static COLORREF StatusBarBGColor; + static COLORREF StatusBarSeparatorColor; + static COLORREF StatusBarEditBorderColor; + + static COLORREF W10DarkThemeFileDialogInjectedTextColor; + static COLORREF W10DarkThemeFileDialogInjectedBGColor; + static COLORREF W10DarkThemeFileDialogInjectedEditBorderColor; + static COLORREF W10DarkThemeTitlebarBGColor; + static COLORREF W10DarkThemeTitlebarInactiveBGColor; + static COLORREF W10DarkThemeTitlebarFGColor; + static COLORREF W10DarkThemeTitlebarInactiveFGColor; + static COLORREF W10DarkThemeTitlebarIconPenColor; + static COLORREF W10DarkThemeTitlebarControlHoverBGColor; + static COLORREF W10DarkThemeTitlebarInactiveControlHoverBGColor; + static COLORREF W10DarkThemeTitlebarControlPushedBGColor; + static COLORREF W10DarkThemeWindowBorderColor; + + static COLORREF ProgressBarBGColor; + static COLORREF ProgressBarColor; + + static COLORREF SubresyncFadeText1; + static COLORREF SubresyncFadeText2; + static COLORREF SubresyncActiveFadeText; + static COLORREF SubresyncHLColor1; + static COLORREF SubresyncHLColor2; + static COLORREF SubresyncGridSepColor; + + static COLORREF ActivePlayListItemColor; + static COLORREF ActivePlayListItemHLColor; + static COLORREF StaticLinkColor; + static COLORREF SeekbarCurrentPositionColor; + static COLORREF SeekbarChapterColor; + static COLORREF SeekbarABColor; + + static const int GroupBoxTextIndent; + + + static const BYTE GripperBitsH[10]; + static const BYTE GripperBitsV[8]; + static const int gripPatternShort; + static const int gripPatternLong; + + static wchar_t* const uiTextFont; + static wchar_t* const uiStaticTextFont; + static wchar_t* const uiSymbolFont; + + + static const COLORREF ComboboxArrowColor; + static const COLORREF ComboboxArrowColorDisabled; + + static const COLORREF HeaderCtrlSortArrowColor; + + static const BYTE CheckBits[14]; + static const int CheckWidth; + static const int CheckHeight; + + const static UINT ThemeCheckBoxes[5]; + const static UINT ThemeRadios[5]; + const static UINT ThemeGrippers[5]; + + enum pathState { + linePath, + newPath, + closePath + }; + + struct pathPoint { + float x; + float y; + pathState state; + }; + static const std::vector minimizeIcon96, minimizeIcon120, minimizeIcon144, minimizeIcon168, minimizeIcon192; + static const std::vector maximizeIcon96, maximizeIcon120, maximizeIcon144, maximizeIcon168, maximizeIcon192; + static const std::vector restoreIcon96, restoreIcon120, restoreIcon144, restoreIcon168, restoreIcon192; + static const std::vector closeIcon96, closeIcon120, closeIcon144, closeIcon168, closeIcon192; + static const std::vector hideIcon96, hideIcon120, hideIcon144, hideIcon168, hideIcon192; + static const int CMPCTheme::W10TitlebarIconPathHeight[5]; + static const int CMPCTheme::W10TitlebarIconPathWidth[5]; + static const float CMPCTheme::W10TitlebarIconPathThickness[5]; + static const int CMPCTheme::W10TitlebarButtonWidth[5]; + static const int CMPCTheme::W10TitlebarButtonSpacing[5]; + static const int CMPCTheme::ToolbarIconPathDimension[5]; + static const int CMPCTheme::ToolbarGripperHeight[5]; + static const int CMPCTheme::ToolbarHideButtonDimensions[5]; + + + static bool drawThemedControls; + + static void InitializeColors(ModernThemeMode themeMode); +}; diff --git a/src/mpc-hc/CMPCThemeButton.cpp b/src/mpc-hc/CMPCThemeButton.cpp index 94e1e1d314d..57c0116bcd4 100755 --- a/src/mpc-hc/CMPCThemeButton.cpp +++ b/src/mpc-hc/CMPCThemeButton.cpp @@ -1,191 +1,191 @@ -#include "stdafx.h" -#include "CMPCThemeButton.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -CMPCThemeButton::CMPCThemeButton() -{ - if (AppIsThemeLoaded()) { - m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT; //just setting this to get hovering working - } - drawShield = false; -} - -CMPCThemeButton::~CMPCThemeButton() -{ -} - -void CMPCThemeButton::PreSubclassWindow() //bypass CMFCButton impl since it will enable ownerdraw. also clear CS_DBLCLKS class style, due to mfcbutton requirements -{ - InitStyle(GetStyle()); - CButton::PreSubclassWindow(); - DWORD classStyle = ::GetClassLongPtr(m_hWnd, GCL_STYLE); - classStyle &= ~(CS_DBLCLKS); - ::SetClassLongPtr(m_hWnd, GCL_STYLE, classStyle); -} - -BOOL CMPCThemeButton::PreCreateWindow(CREATESTRUCT& cs) //bypass CMFCButton impl since it will enable ownerdraw. also clear CS_DBLCLKS class style, due to mfcbutton requirements -{ - InitStyle(cs.style); - if (!CButton::PreCreateWindow(cs)) { - return FALSE; - } - DWORD classStyle = ::GetClassLongPtr(m_hWnd, GCL_STYLE); - classStyle &= ~(CS_DBLCLKS); - ::SetClassLongPtr(m_hWnd, GCL_STYLE, classStyle); - return TRUE; -} - - -IMPLEMENT_DYNAMIC(CMPCThemeButton, CMFCButton) -BEGIN_MESSAGE_MAP(CMPCThemeButton, CMFCButton) - ON_WM_SETFONT() - ON_WM_GETFONT() - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeButton::OnNMCustomdraw) - ON_MESSAGE(BCM_SETSHIELD, &setShieldIcon) -END_MESSAGE_MAP() - -LRESULT CMPCThemeButton::setShieldIcon(WPARAM wParam, LPARAM lParam) -{ - drawShield = (BOOL)lParam; - return 1; //pass it along -} - -void CMPCThemeButton::drawButtonBase(CDC* pDC, CRect rect, CString strText, bool selected, bool highLighted, bool focused, bool disabled, bool thin, bool shield, HWND accelWindow) -{ - CBrush fb, fb2; - fb.CreateSolidBrush(CMPCTheme::ButtonBorderOuterColor); - - if (!thin) { //some small buttons look very ugly with the full border. make up our own solution - pDC->FrameRect(rect, &fb); - rect.DeflateRect(1, 1); - } - COLORREF bg = CMPCTheme::ButtonFillColor, dottedClr = CMPCTheme::ButtonBorderKBFocusColor; - - if (selected) {//mouse down - fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - bg = CMPCTheme::ButtonFillSelectedColor; - dottedClr = CMPCTheme::ButtonBorderSelectedKBFocusColor; - } else if (highLighted) { - fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - bg = CMPCTheme::ButtonFillHoverColor; - dottedClr = CMPCTheme::ButtonBorderHoverKBFocusColor; - } else if (focused) { - fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerFocusedColor); - } else { - fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - } - - pDC->FrameRect(rect, &fb2); - rect.DeflateRect(1, 1); - pDC->FillSolidRect(rect, bg); - - - if (focused) { - rect.DeflateRect(1, 1); - COLORREF oldTextFGColor = pDC->SetTextColor(dottedClr); - COLORREF oldBGColor = pDC->SetBkColor(bg); - CBrush* dotted = pDC->GetHalftoneBrush(); - pDC->FrameRect(rect, dotted); - DeleteObject(dotted); - pDC->SetTextColor(oldTextFGColor); - pDC->SetBkColor(oldBGColor); - } - - if (!strText.IsEmpty()) { - int nMode = pDC->SetBkMode(TRANSPARENT); - - COLORREF oldTextFGColor; - if (disabled) { - oldTextFGColor = pDC->SetTextColor(CMPCTheme::ButtonDisabledFGColor); - } else { - oldTextFGColor = pDC->SetTextColor(CMPCTheme::TextFGColor); - } - - UINT format = DT_CENTER | DT_VCENTER | DT_SINGLELINE; - if (shield) { - int iconsize = MulDiv(pDC->GetDeviceCaps(LOGPIXELSX), 1, 6); - int shieldY = rect.top + (rect.Height() - iconsize) / 2 + 1; - CRect centerRect = rect; - pDC->DrawTextW(strText, rect, format | DT_CALCRECT); - rect.top = centerRect.top; - rect.bottom = centerRect.bottom; - rect.OffsetRect((centerRect.Width() - rect.Width() + iconsize) / 2, 0); - int shieldX = rect.left - iconsize - 1; - HICON hShieldIcon = (HICON)LoadImage(0, IDI_SHIELD, IMAGE_ICON, iconsize, iconsize, LR_SHARED); - if (hShieldIcon) { - DrawIconEx(pDC->GetSafeHdc(), shieldX, shieldY, hShieldIcon, iconsize, iconsize, 0, NULL, DI_NORMAL); - } - } - - if (accelWindow && (::SendMessage(accelWindow, WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { - format |= DT_HIDEPREFIX; - } - pDC->DrawTextW(strText, rect, format); - - pDC->SetTextColor(oldTextFGColor); - pDC->SetBkMode(nMode); - } - fb.DeleteObject(); - fb2.DeleteObject(); -} - -#define max(a,b) (((a) > (b)) ? (a) : (b)) -void CMPCThemeButton::drawButton(HDC hdc, CRect rect, UINT state) -{ - CDC* pDC = CDC::FromHandle(hdc); - - CString strText; - GetWindowText(strText); - bool selected = ODS_SELECTED == (state & ODS_SELECTED); - bool focused = ODS_FOCUS == (state & ODS_FOCUS); - bool disabled = ODS_DISABLED == (state & ODS_DISABLED); - - BUTTON_IMAGELIST imgList; - GetImageList(&imgList); - CImageList* images = CImageList::FromHandlePermanent(imgList.himl); - //bool thin = (images != nullptr); //thin borders for image buttons - bool thin = true; - - - drawButtonBase(pDC, rect, strText, selected, IsHighlighted(), focused, disabled, thin, drawShield, m_hWnd); - - int imageIndex = 0; //Normal - if (disabled) { - imageIndex = 1; - } - - if (images != nullptr) { //assume centered - IMAGEINFO ii; - if (images->GetImageCount() <= imageIndex) { - imageIndex = 0; - } - images->GetImageInfo(imageIndex, &ii); - int width = ii.rcImage.right - ii.rcImage.left; - int height = ii.rcImage.bottom - ii.rcImage.top; - rect.DeflateRect((rect.Width() - width) / 2, max(0, (rect.Height() - height) / 2)); - images->Draw(pDC, imageIndex, rect.TopLeft(), ILD_NORMAL); - } -} - -void CMPCThemeButton::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); - *pResult = CDRF_DODEFAULT; - if (AppIsThemeLoaded()) { - if (pNMCD->dwDrawStage == CDDS_PREERASE) { - drawButton(pNMCD->hdc, pNMCD->rc, pNMCD->uItemState); - *pResult = CDRF_SKIPDEFAULT; - } - } -} -void CMPCThemeButton::OnSetFont(CFont* pFont, BOOL bRedraw) -{ - Default(); //bypass the MFCButton font impl since we don't always draw this button ourselves (classic mode) -} - -HFONT CMPCThemeButton::OnGetFont() -{ - return (HFONT)Default(); -} +#include "stdafx.h" +#include "CMPCThemeButton.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +CMPCThemeButton::CMPCThemeButton() +{ + if (AppIsThemeLoaded()) { + m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT; //just setting this to get hovering working + } + drawShield = false; +} + +CMPCThemeButton::~CMPCThemeButton() +{ +} + +void CMPCThemeButton::PreSubclassWindow() //bypass CMFCButton impl since it will enable ownerdraw. also clear CS_DBLCLKS class style, due to mfcbutton requirements +{ + InitStyle(GetStyle()); + CButton::PreSubclassWindow(); + DWORD classStyle = ::GetClassLongPtr(m_hWnd, GCL_STYLE); + classStyle &= ~(CS_DBLCLKS); + ::SetClassLongPtr(m_hWnd, GCL_STYLE, classStyle); +} + +BOOL CMPCThemeButton::PreCreateWindow(CREATESTRUCT& cs) //bypass CMFCButton impl since it will enable ownerdraw. also clear CS_DBLCLKS class style, due to mfcbutton requirements +{ + InitStyle(cs.style); + if (!CButton::PreCreateWindow(cs)) { + return FALSE; + } + DWORD classStyle = ::GetClassLongPtr(m_hWnd, GCL_STYLE); + classStyle &= ~(CS_DBLCLKS); + ::SetClassLongPtr(m_hWnd, GCL_STYLE, classStyle); + return TRUE; +} + + +IMPLEMENT_DYNAMIC(CMPCThemeButton, CMFCButton) +BEGIN_MESSAGE_MAP(CMPCThemeButton, CMFCButton) + ON_WM_SETFONT() + ON_WM_GETFONT() + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeButton::OnNMCustomdraw) + ON_MESSAGE(BCM_SETSHIELD, &setShieldIcon) +END_MESSAGE_MAP() + +LRESULT CMPCThemeButton::setShieldIcon(WPARAM wParam, LPARAM lParam) +{ + drawShield = (BOOL)lParam; + return 1; //pass it along +} + +void CMPCThemeButton::drawButtonBase(CDC* pDC, CRect rect, CString strText, bool selected, bool highLighted, bool focused, bool disabled, bool thin, bool shield, HWND accelWindow) +{ + CBrush fb, fb2; + fb.CreateSolidBrush(CMPCTheme::ButtonBorderOuterColor); + + if (!thin) { //some small buttons look very ugly with the full border. make up our own solution + pDC->FrameRect(rect, &fb); + rect.DeflateRect(1, 1); + } + COLORREF bg = CMPCTheme::ButtonFillColor, dottedClr = CMPCTheme::ButtonBorderKBFocusColor; + + if (selected) {//mouse down + fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + bg = CMPCTheme::ButtonFillSelectedColor; + dottedClr = CMPCTheme::ButtonBorderSelectedKBFocusColor; + } else if (highLighted) { + fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + bg = CMPCTheme::ButtonFillHoverColor; + dottedClr = CMPCTheme::ButtonBorderHoverKBFocusColor; + } else if (focused) { + fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerFocusedColor); + } else { + fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + } + + pDC->FrameRect(rect, &fb2); + rect.DeflateRect(1, 1); + pDC->FillSolidRect(rect, bg); + + + if (focused) { + rect.DeflateRect(1, 1); + COLORREF oldTextFGColor = pDC->SetTextColor(dottedClr); + COLORREF oldBGColor = pDC->SetBkColor(bg); + CBrush* dotted = pDC->GetHalftoneBrush(); + pDC->FrameRect(rect, dotted); + DeleteObject(dotted); + pDC->SetTextColor(oldTextFGColor); + pDC->SetBkColor(oldBGColor); + } + + if (!strText.IsEmpty()) { + int nMode = pDC->SetBkMode(TRANSPARENT); + + COLORREF oldTextFGColor; + if (disabled) { + oldTextFGColor = pDC->SetTextColor(CMPCTheme::ButtonDisabledFGColor); + } else { + oldTextFGColor = pDC->SetTextColor(CMPCTheme::TextFGColor); + } + + UINT format = DT_CENTER | DT_VCENTER | DT_SINGLELINE; + if (shield) { + int iconsize = MulDiv(pDC->GetDeviceCaps(LOGPIXELSX), 1, 6); + int shieldY = rect.top + (rect.Height() - iconsize) / 2 + 1; + CRect centerRect = rect; + pDC->DrawTextW(strText, rect, format | DT_CALCRECT); + rect.top = centerRect.top; + rect.bottom = centerRect.bottom; + rect.OffsetRect((centerRect.Width() - rect.Width() + iconsize) / 2, 0); + int shieldX = rect.left - iconsize - 1; + HICON hShieldIcon = (HICON)LoadImage(0, IDI_SHIELD, IMAGE_ICON, iconsize, iconsize, LR_SHARED); + if (hShieldIcon) { + DrawIconEx(pDC->GetSafeHdc(), shieldX, shieldY, hShieldIcon, iconsize, iconsize, 0, NULL, DI_NORMAL); + } + } + + if (accelWindow && (::SendMessage(accelWindow, WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { + format |= DT_HIDEPREFIX; + } + pDC->DrawTextW(strText, rect, format); + + pDC->SetTextColor(oldTextFGColor); + pDC->SetBkMode(nMode); + } + fb.DeleteObject(); + fb2.DeleteObject(); +} + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +void CMPCThemeButton::drawButton(HDC hdc, CRect rect, UINT state) +{ + CDC* pDC = CDC::FromHandle(hdc); + + CString strText; + GetWindowText(strText); + bool selected = ODS_SELECTED == (state & ODS_SELECTED); + bool focused = ODS_FOCUS == (state & ODS_FOCUS); + bool disabled = ODS_DISABLED == (state & ODS_DISABLED); + + BUTTON_IMAGELIST imgList; + GetImageList(&imgList); + CImageList* images = CImageList::FromHandlePermanent(imgList.himl); + //bool thin = (images != nullptr); //thin borders for image buttons + bool thin = true; + + + drawButtonBase(pDC, rect, strText, selected, IsHighlighted(), focused, disabled, thin, drawShield, m_hWnd); + + int imageIndex = 0; //Normal + if (disabled) { + imageIndex = 1; + } + + if (images != nullptr) { //assume centered + IMAGEINFO ii; + if (images->GetImageCount() <= imageIndex) { + imageIndex = 0; + } + images->GetImageInfo(imageIndex, &ii); + int width = ii.rcImage.right - ii.rcImage.left; + int height = ii.rcImage.bottom - ii.rcImage.top; + rect.DeflateRect((rect.Width() - width) / 2, max(0, (rect.Height() - height) / 2)); + images->Draw(pDC, imageIndex, rect.TopLeft(), ILD_NORMAL); + } +} + +void CMPCThemeButton::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); + *pResult = CDRF_DODEFAULT; + if (AppIsThemeLoaded()) { + if (pNMCD->dwDrawStage == CDDS_PREERASE) { + drawButton(pNMCD->hdc, pNMCD->rc, pNMCD->uItemState); + *pResult = CDRF_SKIPDEFAULT; + } + } +} +void CMPCThemeButton::OnSetFont(CFont* pFont, BOOL bRedraw) +{ + Default(); //bypass the MFCButton font impl since we don't always draw this button ourselves (classic mode) +} + +HFONT CMPCThemeButton::OnGetFont() +{ + return (HFONT)Default(); +} diff --git a/src/mpc-hc/CMPCThemeButton.h b/src/mpc-hc/CMPCThemeButton.h index c682ee420fc..42d68741871 100755 --- a/src/mpc-hc/CMPCThemeButton.h +++ b/src/mpc-hc/CMPCThemeButton.h @@ -1,22 +1,22 @@ -#pragma once - -class CMPCThemeButton : public CMFCButton -{ -protected: - void drawButton(HDC hdc, CRect rect, UINT state); - CFont font; - bool drawShield; -public: - CMPCThemeButton(); - virtual ~CMPCThemeButton(); - void PreSubclassWindow(); - BOOL PreCreateWindow(CREATESTRUCT& cs); - LRESULT setShieldIcon(WPARAM wParam, LPARAM lParam); - static void drawButtonBase(CDC* pDC, CRect rect, CString strText, bool selected, bool highLighted, bool focused, bool disabled, bool thin, bool shield, HWND accelWindow=nullptr); - DECLARE_DYNAMIC(CMPCThemeButton) - DECLARE_MESSAGE_MAP() - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnSetFont(CFont* pFont, BOOL bRedraw); - afx_msg HFONT OnGetFont(); -}; - +#pragma once + +class CMPCThemeButton : public CMFCButton +{ +protected: + void drawButton(HDC hdc, CRect rect, UINT state); + CFont font; + bool drawShield; +public: + CMPCThemeButton(); + virtual ~CMPCThemeButton(); + void PreSubclassWindow(); + BOOL PreCreateWindow(CREATESTRUCT& cs); + LRESULT setShieldIcon(WPARAM wParam, LPARAM lParam); + static void drawButtonBase(CDC* pDC, CRect rect, CString strText, bool selected, bool highLighted, bool focused, bool disabled, bool thin, bool shield, HWND accelWindow=nullptr); + DECLARE_DYNAMIC(CMPCThemeButton) + DECLARE_MESSAGE_MAP() + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnSetFont(CFont* pFont, BOOL bRedraw); + afx_msg HFONT OnGetFont(); +}; + diff --git a/src/mpc-hc/CMPCThemeCmdUIDialog.cpp b/src/mpc-hc/CMPCThemeCmdUIDialog.cpp index b7f1991a858..48a219e88a7 100755 --- a/src/mpc-hc/CMPCThemeCmdUIDialog.cpp +++ b/src/mpc-hc/CMPCThemeCmdUIDialog.cpp @@ -1,45 +1,45 @@ -#include "stdafx.h" -#include "CMPCThemeCmdUIDialog.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - - -CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog() -{ -} - -CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog(UINT nIDTemplate, CWnd* pParent): CCmdUIDialog(nIDTemplate, pParent) -{ -} - -CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent): CCmdUIDialog(lpszTemplateName, pParent) -{ -} - - -CMPCThemeCmdUIDialog::~CMPCThemeCmdUIDialog() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeCmdUIDialog, CCmdUIDialog) -BEGIN_MESSAGE_MAP(CMPCThemeCmdUIDialog, CCmdUIDialog) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - -BOOL CMPCThemeCmdUIDialog::OnInitDialog() -{ - BOOL ret = __super::OnInitDialog(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return ret; -} - - -HBRUSH CMPCThemeCmdUIDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppNeedsThemedControls()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} +#include "stdafx.h" +#include "CMPCThemeCmdUIDialog.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + + +CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog() +{ +} + +CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog(UINT nIDTemplate, CWnd* pParent): CCmdUIDialog(nIDTemplate, pParent) +{ +} + +CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent): CCmdUIDialog(lpszTemplateName, pParent) +{ +} + + +CMPCThemeCmdUIDialog::~CMPCThemeCmdUIDialog() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeCmdUIDialog, CCmdUIDialog) +BEGIN_MESSAGE_MAP(CMPCThemeCmdUIDialog, CCmdUIDialog) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + +BOOL CMPCThemeCmdUIDialog::OnInitDialog() +{ + BOOL ret = __super::OnInitDialog(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return ret; +} + + +HBRUSH CMPCThemeCmdUIDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppNeedsThemedControls()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} diff --git a/src/mpc-hc/CMPCThemeCmdUIDialog.h b/src/mpc-hc/CMPCThemeCmdUIDialog.h index 6ebe57a520b..52fd70ec466 100755 --- a/src/mpc-hc/CMPCThemeCmdUIDialog.h +++ b/src/mpc-hc/CMPCThemeCmdUIDialog.h @@ -1,21 +1,21 @@ -#pragma once -#include "..\CmdUI\CmdUI.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeGroupBox.h" -#include "CMPCThemeLinkCtrl.h" -#include "CMPCThemeUtil.h" -class CMPCThemeCmdUIDialog : public CCmdUIDialog, public CMPCThemeUtil -{ -public: - CMPCThemeCmdUIDialog(); - CMPCThemeCmdUIDialog(UINT nIDTemplate, CWnd* pParent = nullptr); - CMPCThemeCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); - virtual ~CMPCThemeCmdUIDialog(); - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - BOOL OnInitDialog(); - DECLARE_DYNAMIC(CMPCThemeCmdUIDialog) - DECLARE_MESSAGE_MAP() -public: - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -}; - +#pragma once +#include "..\CmdUI\CmdUI.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeGroupBox.h" +#include "CMPCThemeLinkCtrl.h" +#include "CMPCThemeUtil.h" +class CMPCThemeCmdUIDialog : public CCmdUIDialog, public CMPCThemeUtil +{ +public: + CMPCThemeCmdUIDialog(); + CMPCThemeCmdUIDialog(UINT nIDTemplate, CWnd* pParent = nullptr); + CMPCThemeCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); + virtual ~CMPCThemeCmdUIDialog(); + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + BOOL OnInitDialog(); + DECLARE_DYNAMIC(CMPCThemeCmdUIDialog) + DECLARE_MESSAGE_MAP() +public: + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +}; + diff --git a/src/mpc-hc/CMPCThemeComPropertyPage.cpp b/src/mpc-hc/CMPCThemeComPropertyPage.cpp index 305167fa436..3bb9608cc07 100755 --- a/src/mpc-hc/CMPCThemeComPropertyPage.cpp +++ b/src/mpc-hc/CMPCThemeComPropertyPage.cpp @@ -1,46 +1,46 @@ -#include "stdafx.h" -#include "CMPCThemeComPropertyPage.h" -#include "moreuuids.h" - -CLSID CMPCThemeComPropertyPage::dialogClsid = GUID_NULL; - -CMPCThemeComPropertyPage::CMPCThemeComPropertyPage(IPropertyPage* pPage) : CComPropertyPage(pPage) -{ - -} - -CMPCThemeComPropertyPage::~CMPCThemeComPropertyPage() -{ - dialogClsid = GUID_NULL; -} - -BOOL CMPCThemeComPropertyPage::OnInitDialog() -{ - __super::OnInitDialog(); - - if (dialogClsid == CLSID_MPCVR) { - fulfillThemeReqs(CMPCThemeUtil::SpecialThemeCases::ExternalPropertyPageWithDefaultButton); - } else if (dialogClsid == CLSID_Generic_WDM_FilterProxy) { - fulfillThemeReqs(CMPCThemeUtil::SpecialThemeCases::ExternalPropertyPageWithAnalogCaptureSliders); - } else { - fulfillThemeReqs(); - } - return 0; -} - -IMPLEMENT_DYNAMIC(CMPCThemeComPropertyPage, CComPropertyPage) -BEGIN_MESSAGE_MAP(CMPCThemeComPropertyPage, CComPropertyPage) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeComPropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} +#include "stdafx.h" +#include "CMPCThemeComPropertyPage.h" +#include "moreuuids.h" + +CLSID CMPCThemeComPropertyPage::dialogClsid = GUID_NULL; + +CMPCThemeComPropertyPage::CMPCThemeComPropertyPage(IPropertyPage* pPage) : CComPropertyPage(pPage) +{ + +} + +CMPCThemeComPropertyPage::~CMPCThemeComPropertyPage() +{ + dialogClsid = GUID_NULL; +} + +BOOL CMPCThemeComPropertyPage::OnInitDialog() +{ + __super::OnInitDialog(); + + if (dialogClsid == CLSID_MPCVR) { + fulfillThemeReqs(CMPCThemeUtil::SpecialThemeCases::ExternalPropertyPageWithDefaultButton); + } else if (dialogClsid == CLSID_Generic_WDM_FilterProxy) { + fulfillThemeReqs(CMPCThemeUtil::SpecialThemeCases::ExternalPropertyPageWithAnalogCaptureSliders); + } else { + fulfillThemeReqs(); + } + return 0; +} + +IMPLEMENT_DYNAMIC(CMPCThemeComPropertyPage, CComPropertyPage) +BEGIN_MESSAGE_MAP(CMPCThemeComPropertyPage, CComPropertyPage) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeComPropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} diff --git a/src/mpc-hc/CMPCThemeComPropertyPage.h b/src/mpc-hc/CMPCThemeComPropertyPage.h index 7106e3f5a9f..1ab69f42b86 100755 --- a/src/mpc-hc/CMPCThemeComPropertyPage.h +++ b/src/mpc-hc/CMPCThemeComPropertyPage.h @@ -1,21 +1,21 @@ -#pragma once -#include "ComPropertyPage.h" -#include "CMPCThemeUtil.h" -class CMPCThemeComPropertyPage : public CComPropertyPage, public CMPCThemeUtil -{ -public: - CMPCThemeComPropertyPage(IPropertyPage* pPage); - virtual ~CMPCThemeComPropertyPage(); - - - void fulfillThemeReqs(SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase) { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this, specialCase); }; - static void SetDialogType(CLSID clsid) { dialogClsid = clsid; }; - DECLARE_DYNAMIC(CMPCThemeComPropertyPage) - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - virtual BOOL OnInitDialog(); - static CLSID dialogClsid; -}; - +#pragma once +#include "ComPropertyPage.h" +#include "CMPCThemeUtil.h" +class CMPCThemeComPropertyPage : public CComPropertyPage, public CMPCThemeUtil +{ +public: + CMPCThemeComPropertyPage(IPropertyPage* pPage); + virtual ~CMPCThemeComPropertyPage(); + + + void fulfillThemeReqs(SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase) { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this, specialCase); }; + static void SetDialogType(CLSID clsid) { dialogClsid = clsid; }; + DECLARE_DYNAMIC(CMPCThemeComPropertyPage) + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + virtual BOOL OnInitDialog(); + static CLSID dialogClsid; +}; + diff --git a/src/mpc-hc/CMPCThemeComboBox.cpp b/src/mpc-hc/CMPCThemeComboBox.cpp index 72e807ca51a..5b6a42b22ee 100644 --- a/src/mpc-hc/CMPCThemeComboBox.cpp +++ b/src/mpc-hc/CMPCThemeComboBox.cpp @@ -1,300 +1,300 @@ -#include "stdafx.h" -#include "CMPCThemeComboBox.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#undef SubclassWindow - -IMPLEMENT_DYNAMIC(CMPCThemeComboBox, CComboBox) - -BEGIN_MESSAGE_MAP(CMPCThemeComboBox, CComboBox) - ON_WM_PAINT() - ON_WM_SETFOCUS() - ON_WM_MOUSEMOVE() - ON_WM_MOUSELEAVE() - ON_WM_LBUTTONUP() - ON_WM_LBUTTONDOWN() - ON_WM_CREATE() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -CMPCThemeComboBox::CMPCThemeComboBox() - :CComboBox(), - isHover(false), - hasThemedControls(false) -{ -} - -void CMPCThemeComboBox::doDraw(CDC& dc, CString strText, CRect rText, COLORREF bkColor, COLORREF fgColor, bool drawDotted) -{ - COLORREF crOldTextColor = dc.GetTextColor(); - COLORREF crOldBkColor = dc.GetBkColor(); - - dc.SetBkColor(bkColor); - dc.SetTextColor(fgColor); - - CRect textRect = rText; - //textRect.left += 3; - - CFont* font = GetFont(); - CFont* pOldFont = dc.SelectObject(font); - dc.DrawTextW(strText, &textRect, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); - dc.SelectObject(pOldFont); - - if (drawDotted) { - dc.SetTextColor(bkColor ^ 0xffffff); - CBrush* dotted = dc.GetHalftoneBrush(); - dc.FrameRect(rText, dotted); - DeleteObject(dotted); - } - - dc.SetTextColor(crOldTextColor); - dc.SetBkColor(crOldBkColor); -} - -CMPCThemeComboBox::~CMPCThemeComboBox() -{ -} - -void CMPCThemeComboBox::themeControls() -{ - if (AppNeedsThemedControls()) { - if (CMPCThemeUtil::canUseWin10DarkTheme() && !hasThemedControls) { - COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - if (GetComboBoxInfo(&info)) { - SetWindowTheme(info.hwndList, L"DarkMode_Explorer", NULL); - DWORD dropdownType = GetStyle() & 3; - if (CBS_DROPDOWN == dropdownType || CBS_SIMPLE == dropdownType) { - cbEdit.SubclassWindow(info.hwndItem); - } - - hasThemedControls = true; - } - } - } -} - -void CMPCThemeComboBox::PreSubclassWindow() -{ - themeControls(); -} - - -void CMPCThemeComboBox::drawComboArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect) -{ - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - Gdiplus::Color clr; - clr.SetFromCOLORREF(arrowClr); - - int dpi = dpiWindow.DPIX(); - float steps; - - if (dpi < 120) { - steps = 3.5; - } else if (dpi < 144) { - steps = 4; - } else if (dpi < 168) { - steps = 5; - } else if (dpi < 192) { - steps = 5; - } else { - steps = 6; - } - - int xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - int yPos = arrowRect.top + (arrowRect.Height() - (steps + 1)) / 2; - - Gdiplus::Graphics gfx(dc.m_hDC); - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x4); - Gdiplus::Pen pen(clr, 1); - for (int i = 0; i < 2; i++) { - Gdiplus::GraphicsPath path; - Gdiplus::PointF vertices[3]; - - vertices[0] = Gdiplus::PointF(xPos, yPos); - vertices[1] = Gdiplus::PointF(steps + xPos, yPos + steps); - vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos); - - path.AddLines(vertices, 3); - gfx.DrawPath(&pen, &path); - } -} - - -void CMPCThemeComboBox::OnPaint() -{ - if (AppNeedsThemedControls()) { - CPaintDC dc(this); - CRect r, rBorder, rText, rBG, rSelect, rDownArrow; - GetClientRect(r); - CString strText; - GetWindowText(strText); - - COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - GetComboBoxInfo(&info); - CWnd* pCBEdit = GetDlgItem(1001); - - CBrush fb; - bool isFocused, drawDotted = false; - - if (pCBEdit) { - CRect editRect; - pCBEdit->GetWindowRect(editRect); - ScreenToClient(editRect); - dc.ExcludeClipRect(editRect); - isFocused = (nullptr != info.hwndItem && ::GetFocus() == info.hwndItem); - if (isFocused) { - fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerFocusedColor); - } else { - fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - } - } else { - isFocused = (GetFocus() == this); - if (isFocused) { - drawDotted = true; - } - fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - } - - COLORREF bkColor, fgColor = CMPCTheme::TextFGColor, arrowColor = CMPCTheme::ComboboxArrowColor; - if ((nullptr != info.hwndList && ::IsWindowVisible(info.hwndList)) || info.stateButton == STATE_SYSTEM_PRESSED) { //always looks the same once the list is open - bkColor = CMPCTheme::ButtonFillSelectedColor; - drawDotted = false; - } else if (info.stateButton == 0 && isHover) { //not pressed and hovered - bkColor = CMPCTheme::ButtonFillHoverColor; - } else if (!IsWindowEnabled()) { - bkColor = CMPCTheme::ButtonFillColor; - fgColor = CMPCTheme::ButtonDisabledFGColor; - arrowColor = CMPCTheme::ComboboxArrowColorDisabled; - } else { - bkColor = CMPCTheme::ButtonFillColor; - } - - rBG = r; - rBG.DeflateRect(1, 1); - if (pCBEdit) { - CRect tB(info.rcButton); - dc.FillSolidRect(tB, bkColor); - rBG.right = info.rcButton.left - 1; - CMPCThemeUtil::drawParentDialogBGClr(this, &dc, rBG, true); - rBG.left = rBG.right; - rBG.right += 1; - dc.FillSolidRect(rBG, CMPCTheme::ButtonBorderInnerColor); - } else { - dc.FillSolidRect(rBG, bkColor); - rText = r; - rText.right = info.rcItem.right; - rText.DeflateRect(3, 3); - doDraw(dc, strText, rText, bkColor, fgColor, drawDotted); - } - - rDownArrow = info.rcButton; - drawComboArrow(dc, arrowColor, rDownArrow); - - rBorder = r; - dc.FrameRect(rBorder, &fb); - fb.DeleteObject(); - } else { - CComboBox::OnPaint(); - } -} - - -void CMPCThemeComboBox::OnSetFocus(CWnd* pOldWnd) -{ - CComboBox::OnSetFocus(pOldWnd); - //Invalidate(); -} - -void CMPCThemeComboBox::checkHover(UINT nFlags, CPoint point, bool invalidate) -{ - CRect r; - bool oldHover = isHover; - CPoint ptScreen = point; - ClientToScreen(&ptScreen); - - CWnd* pCBEdit = GetDlgItem(1001); - if (pCBEdit) { //we only hover on the button, because the edit covers most of the combobox (except one pixel, which we don't want to check, as it causes flicker) - COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - GetComboBoxInfo(&info); - r = info.rcButton; - } else { - GetClientRect(r); - } - - if (r.PtInRect(point) && WindowFromPoint(ptScreen)->GetSafeHwnd() == GetSafeHwnd()) { - isHover = true; - } else { - isHover = false; - } - if (isHover != oldHover && invalidate) { - Invalidate(); - } - -} - -void CMPCThemeComboBox::OnMouseMove(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point); - CComboBox::OnMouseMove(nFlags, point); -} - - -void CMPCThemeComboBox::OnMouseLeave() -{ - checkHover(0, CPoint(-1, -1)); - CComboBox::OnMouseLeave(); -} - - -void CMPCThemeComboBox::OnLButtonUp(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point, false); - CComboBox::OnLButtonUp(nFlags, point); -} - - -void CMPCThemeComboBox::OnLButtonDown(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point); - CComboBox::OnLButtonDown(nFlags, point); -} - - -int CMPCThemeComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (__super::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - themeControls(); - - return 0; -} - - -BOOL CMPCThemeComboBox::OnEraseBkgnd(CDC* pDC) { - return TRUE; -} - -int CMPCThemeComboBox::SetCurSel(int nSelect) { //note, this is NOT virtual, and only works for explicit subclass - int cur = GetCurSel(); - if (cur != nSelect) { - int ret = __super::SetCurSel(nSelect); - RedrawWindow(); - return ret; - } else { - return nSelect; - } -} - -void CMPCThemeComboBox::SelectByItemData(DWORD_PTR data) { - for (int i = 0; i < GetCount(); i++) { - if (GetItemData(i) == data) { - SetCurSel(i); //calls CMPCThemeComboBox::SetCurSel - break; - } - } -} +#include "stdafx.h" +#include "CMPCThemeComboBox.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#undef SubclassWindow + +IMPLEMENT_DYNAMIC(CMPCThemeComboBox, CComboBox) + +BEGIN_MESSAGE_MAP(CMPCThemeComboBox, CComboBox) + ON_WM_PAINT() + ON_WM_SETFOCUS() + ON_WM_MOUSEMOVE() + ON_WM_MOUSELEAVE() + ON_WM_LBUTTONUP() + ON_WM_LBUTTONDOWN() + ON_WM_CREATE() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +CMPCThemeComboBox::CMPCThemeComboBox() + :CComboBox(), + isHover(false), + hasThemedControls(false) +{ +} + +void CMPCThemeComboBox::doDraw(CDC& dc, CString strText, CRect rText, COLORREF bkColor, COLORREF fgColor, bool drawDotted) +{ + COLORREF crOldTextColor = dc.GetTextColor(); + COLORREF crOldBkColor = dc.GetBkColor(); + + dc.SetBkColor(bkColor); + dc.SetTextColor(fgColor); + + CRect textRect = rText; + //textRect.left += 3; + + CFont* font = GetFont(); + CFont* pOldFont = dc.SelectObject(font); + dc.DrawTextW(strText, &textRect, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); + dc.SelectObject(pOldFont); + + if (drawDotted) { + dc.SetTextColor(bkColor ^ 0xffffff); + CBrush* dotted = dc.GetHalftoneBrush(); + dc.FrameRect(rText, dotted); + DeleteObject(dotted); + } + + dc.SetTextColor(crOldTextColor); + dc.SetBkColor(crOldBkColor); +} + +CMPCThemeComboBox::~CMPCThemeComboBox() +{ +} + +void CMPCThemeComboBox::themeControls() +{ + if (AppNeedsThemedControls()) { + if (CMPCThemeUtil::canUseWin10DarkTheme() && !hasThemedControls) { + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; + if (GetComboBoxInfo(&info)) { + SetWindowTheme(info.hwndList, L"DarkMode_Explorer", NULL); + DWORD dropdownType = GetStyle() & 3; + if (CBS_DROPDOWN == dropdownType || CBS_SIMPLE == dropdownType) { + cbEdit.SubclassWindow(info.hwndItem); + } + + hasThemedControls = true; + } + } + } +} + +void CMPCThemeComboBox::PreSubclassWindow() +{ + themeControls(); +} + + +void CMPCThemeComboBox::drawComboArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect) +{ + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + Gdiplus::Color clr; + clr.SetFromCOLORREF(arrowClr); + + int dpi = dpiWindow.DPIX(); + float steps; + + if (dpi < 120) { + steps = 3.5; + } else if (dpi < 144) { + steps = 4; + } else if (dpi < 168) { + steps = 5; + } else if (dpi < 192) { + steps = 5; + } else { + steps = 6; + } + + int xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + int yPos = arrowRect.top + (arrowRect.Height() - (steps + 1)) / 2; + + Gdiplus::Graphics gfx(dc.m_hDC); + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x4); + Gdiplus::Pen pen(clr, 1); + for (int i = 0; i < 2; i++) { + Gdiplus::GraphicsPath path; + Gdiplus::PointF vertices[3]; + + vertices[0] = Gdiplus::PointF(xPos, yPos); + vertices[1] = Gdiplus::PointF(steps + xPos, yPos + steps); + vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos); + + path.AddLines(vertices, 3); + gfx.DrawPath(&pen, &path); + } +} + + +void CMPCThemeComboBox::OnPaint() +{ + if (AppNeedsThemedControls()) { + CPaintDC dc(this); + CRect r, rBorder, rText, rBG, rSelect, rDownArrow; + GetClientRect(r); + CString strText; + GetWindowText(strText); + + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; + GetComboBoxInfo(&info); + CWnd* pCBEdit = GetDlgItem(1001); + + CBrush fb; + bool isFocused, drawDotted = false; + + if (pCBEdit) { + CRect editRect; + pCBEdit->GetWindowRect(editRect); + ScreenToClient(editRect); + dc.ExcludeClipRect(editRect); + isFocused = (nullptr != info.hwndItem && ::GetFocus() == info.hwndItem); + if (isFocused) { + fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerFocusedColor); + } else { + fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + } + } else { + isFocused = (GetFocus() == this); + if (isFocused) { + drawDotted = true; + } + fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + } + + COLORREF bkColor, fgColor = CMPCTheme::TextFGColor, arrowColor = CMPCTheme::ComboboxArrowColor; + if ((nullptr != info.hwndList && ::IsWindowVisible(info.hwndList)) || info.stateButton == STATE_SYSTEM_PRESSED) { //always looks the same once the list is open + bkColor = CMPCTheme::ButtonFillSelectedColor; + drawDotted = false; + } else if (info.stateButton == 0 && isHover) { //not pressed and hovered + bkColor = CMPCTheme::ButtonFillHoverColor; + } else if (!IsWindowEnabled()) { + bkColor = CMPCTheme::ButtonFillColor; + fgColor = CMPCTheme::ButtonDisabledFGColor; + arrowColor = CMPCTheme::ComboboxArrowColorDisabled; + } else { + bkColor = CMPCTheme::ButtonFillColor; + } + + rBG = r; + rBG.DeflateRect(1, 1); + if (pCBEdit) { + CRect tB(info.rcButton); + dc.FillSolidRect(tB, bkColor); + rBG.right = info.rcButton.left - 1; + CMPCThemeUtil::drawParentDialogBGClr(this, &dc, rBG, true); + rBG.left = rBG.right; + rBG.right += 1; + dc.FillSolidRect(rBG, CMPCTheme::ButtonBorderInnerColor); + } else { + dc.FillSolidRect(rBG, bkColor); + rText = r; + rText.right = info.rcItem.right; + rText.DeflateRect(3, 3); + doDraw(dc, strText, rText, bkColor, fgColor, drawDotted); + } + + rDownArrow = info.rcButton; + drawComboArrow(dc, arrowColor, rDownArrow); + + rBorder = r; + dc.FrameRect(rBorder, &fb); + fb.DeleteObject(); + } else { + CComboBox::OnPaint(); + } +} + + +void CMPCThemeComboBox::OnSetFocus(CWnd* pOldWnd) +{ + CComboBox::OnSetFocus(pOldWnd); + //Invalidate(); +} + +void CMPCThemeComboBox::checkHover(UINT nFlags, CPoint point, bool invalidate) +{ + CRect r; + bool oldHover = isHover; + CPoint ptScreen = point; + ClientToScreen(&ptScreen); + + CWnd* pCBEdit = GetDlgItem(1001); + if (pCBEdit) { //we only hover on the button, because the edit covers most of the combobox (except one pixel, which we don't want to check, as it causes flicker) + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; + GetComboBoxInfo(&info); + r = info.rcButton; + } else { + GetClientRect(r); + } + + if (r.PtInRect(point) && WindowFromPoint(ptScreen)->GetSafeHwnd() == GetSafeHwnd()) { + isHover = true; + } else { + isHover = false; + } + if (isHover != oldHover && invalidate) { + Invalidate(); + } + +} + +void CMPCThemeComboBox::OnMouseMove(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point); + CComboBox::OnMouseMove(nFlags, point); +} + + +void CMPCThemeComboBox::OnMouseLeave() +{ + checkHover(0, CPoint(-1, -1)); + CComboBox::OnMouseLeave(); +} + + +void CMPCThemeComboBox::OnLButtonUp(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point, false); + CComboBox::OnLButtonUp(nFlags, point); +} + + +void CMPCThemeComboBox::OnLButtonDown(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point); + CComboBox::OnLButtonDown(nFlags, point); +} + + +int CMPCThemeComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (__super::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + themeControls(); + + return 0; +} + + +BOOL CMPCThemeComboBox::OnEraseBkgnd(CDC* pDC) { + return TRUE; +} + +int CMPCThemeComboBox::SetCurSel(int nSelect) { //note, this is NOT virtual, and only works for explicit subclass + int cur = GetCurSel(); + if (cur != nSelect) { + int ret = __super::SetCurSel(nSelect); + RedrawWindow(); + return ret; + } else { + return nSelect; + } +} + +void CMPCThemeComboBox::SelectByItemData(DWORD_PTR data) { + for (int i = 0; i < GetCount(); i++) { + if (GetItemData(i) == data) { + SetCurSel(i); //calls CMPCThemeComboBox::SetCurSel + break; + } + } +} diff --git a/src/mpc-hc/CMPCThemeComboBox.h b/src/mpc-hc/CMPCThemeComboBox.h index 6ffde8f3c98..67136b5ece9 100755 --- a/src/mpc-hc/CMPCThemeComboBox.h +++ b/src/mpc-hc/CMPCThemeComboBox.h @@ -1,33 +1,33 @@ -#pragma once -#include -#include "CMPCThemeEdit.h" -class CMPCThemeComboBox : - public CComboBox -{ - DECLARE_DYNAMIC(CMPCThemeComboBox) -private: - bool isHover; - bool hasThemedControls; - CBrush bgBrush; - CMPCThemeEdit cbEdit; -public: - CMPCThemeComboBox(); - void doDraw(CDC& dc, CString strText, CRect r, COLORREF bkColor, COLORREF fgColor, bool drawDotted); - virtual ~CMPCThemeComboBox(); - void themeControls(); - void PreSubclassWindow(); - void drawComboArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect); - void checkHover(UINT nFlags, CPoint point, bool invalidate = true); - int SetCurSel(int nSelect); - void SelectByItemData(DWORD_PTR data); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg void OnSetFocus(CWnd* pOldWnd); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; - +#pragma once +#include +#include "CMPCThemeEdit.h" +class CMPCThemeComboBox : + public CComboBox +{ + DECLARE_DYNAMIC(CMPCThemeComboBox) +private: + bool isHover; + bool hasThemedControls; + CBrush bgBrush; + CMPCThemeEdit cbEdit; +public: + CMPCThemeComboBox(); + void doDraw(CDC& dc, CString strText, CRect r, COLORREF bkColor, COLORREF fgColor, bool drawDotted); + virtual ~CMPCThemeComboBox(); + void themeControls(); + void PreSubclassWindow(); + void drawComboArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect); + void checkHover(UINT nFlags, CPoint point, bool invalidate = true); + int SetCurSel(int nSelect); + void SelectByItemData(DWORD_PTR data); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; + diff --git a/src/mpc-hc/CMPCThemeDialog.cpp b/src/mpc-hc/CMPCThemeDialog.cpp index 460cd01b730..cd70c757eb9 100755 --- a/src/mpc-hc/CMPCThemeDialog.cpp +++ b/src/mpc-hc/CMPCThemeDialog.cpp @@ -1,67 +1,67 @@ -#include "stdafx.h" -#include "CMPCThemeDialog.h" -#include "CMPCTheme.h" -#include "mplayerc.h" -#undef SubclassWindow - - -CMPCThemeDialog::CMPCThemeDialog(bool isDummy /* = false */) -{ - this->isDummy = isDummy; -} - -CMPCThemeDialog::CMPCThemeDialog(UINT nIDTemplate, CWnd* pParentWnd) : CDialog(nIDTemplate, pParentWnd) -{ -} - - -CMPCThemeDialog::~CMPCThemeDialog() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeDialog, CDialog) - -BEGIN_MESSAGE_MAP(CMPCThemeDialog, CDialog) - ON_COMMAND_EX(IDOK, OnOK_EX) - ON_WM_CTLCOLOR() - ON_WM_HSCROLL() -END_MESSAGE_MAP() - -BOOL CMPCThemeDialog::OnInitDialog() -{ - BOOL ret = __super::OnInitDialog(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return ret; -} - -HBRUSH CMPCThemeDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} -BOOL CMPCThemeDialog::PreTranslateMessage(MSG* pMsg) { - if (isDummy) { - return FALSE; - } else { - return CDialog::PreTranslateMessage(pMsg); - } -} - -void CMPCThemeDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { - __super::OnHScroll(nSBCode, nPos, pScrollBar); - if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase && nSBCode == TB_THUMBPOSITION) { - UpdateAnalogCaptureDeviceSlider(pScrollBar); - } -} - -BOOL CMPCThemeDialog::OnOK_EX(UINT nId) { - if (ToolbarCustomizeDialog == specialCase) { //the toolbar customize dialog has assigned 1==IDOK to the "add" button, which CDialog interprets as `EndDialog(IDOK)` - return FALSE; - } - __super::OnOK(); - return TRUE; -} +#include "stdafx.h" +#include "CMPCThemeDialog.h" +#include "CMPCTheme.h" +#include "mplayerc.h" +#undef SubclassWindow + + +CMPCThemeDialog::CMPCThemeDialog(bool isDummy /* = false */) +{ + this->isDummy = isDummy; +} + +CMPCThemeDialog::CMPCThemeDialog(UINT nIDTemplate, CWnd* pParentWnd) : CDialog(nIDTemplate, pParentWnd) +{ +} + + +CMPCThemeDialog::~CMPCThemeDialog() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeDialog, CDialog) + +BEGIN_MESSAGE_MAP(CMPCThemeDialog, CDialog) + ON_COMMAND_EX(IDOK, OnOK_EX) + ON_WM_CTLCOLOR() + ON_WM_HSCROLL() +END_MESSAGE_MAP() + +BOOL CMPCThemeDialog::OnInitDialog() +{ + BOOL ret = __super::OnInitDialog(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return ret; +} + +HBRUSH CMPCThemeDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} +BOOL CMPCThemeDialog::PreTranslateMessage(MSG* pMsg) { + if (isDummy) { + return FALSE; + } else { + return CDialog::PreTranslateMessage(pMsg); + } +} + +void CMPCThemeDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { + __super::OnHScroll(nSBCode, nPos, pScrollBar); + if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase && nSBCode == TB_THUMBPOSITION) { + UpdateAnalogCaptureDeviceSlider(pScrollBar); + } +} + +BOOL CMPCThemeDialog::OnOK_EX(UINT nId) { + if (ToolbarCustomizeDialog == specialCase) { //the toolbar customize dialog has assigned 1==IDOK to the "add" button, which CDialog interprets as `EndDialog(IDOK)` + return FALSE; + } + __super::OnOK(); + return TRUE; +} diff --git a/src/mpc-hc/CMPCThemeDialog.h b/src/mpc-hc/CMPCThemeDialog.h index bfaae9bfce1..fe1165883ee 100755 --- a/src/mpc-hc/CMPCThemeDialog.h +++ b/src/mpc-hc/CMPCThemeDialog.h @@ -1,29 +1,29 @@ -#pragma once -#include -#include "CMPCThemeButton.h" -#include "CMPCThemeGroupBox.h" -#include "CMPCThemeLinkCtrl.h" -#include "CMPCThemeUtil.h" - -class CMPCThemeDialog : - public CDialog, public CMPCThemeUtil -{ -public: - CMPCThemeDialog(bool isDummy = false); - explicit CMPCThemeDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); - virtual ~CMPCThemeDialog(); - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - BOOL OnInitDialog(); - void SetSpecialCase(CMPCThemeUtil::SpecialThemeCases specialCase) { this->specialCase = specialCase; } - DECLARE_DYNAMIC(CMPCThemeDialog) - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - BOOL PreTranslateMessage(MSG* pMsg); - virtual BOOL OnOK_EX(UINT nId); -private: - bool isDummy = false; - CMPCThemeUtil::SpecialThemeCases specialCase = NoSpecialCase; -public: - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); -}; - +#pragma once +#include +#include "CMPCThemeButton.h" +#include "CMPCThemeGroupBox.h" +#include "CMPCThemeLinkCtrl.h" +#include "CMPCThemeUtil.h" + +class CMPCThemeDialog : + public CDialog, public CMPCThemeUtil +{ +public: + CMPCThemeDialog(bool isDummy = false); + explicit CMPCThemeDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); + virtual ~CMPCThemeDialog(); + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + BOOL OnInitDialog(); + void SetSpecialCase(CMPCThemeUtil::SpecialThemeCases specialCase) { this->specialCase = specialCase; } + DECLARE_DYNAMIC(CMPCThemeDialog) + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL OnOK_EX(UINT nId); +private: + bool isDummy = false; + CMPCThemeUtil::SpecialThemeCases specialCase = NoSpecialCase; +public: + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); +}; + diff --git a/src/mpc-hc/CMPCThemeDockBar.cpp b/src/mpc-hc/CMPCThemeDockBar.cpp index 47a7eb33df2..2167166eba3 100755 --- a/src/mpc-hc/CMPCThemeDockBar.cpp +++ b/src/mpc-hc/CMPCThemeDockBar.cpp @@ -1,62 +1,62 @@ -#include "stdafx.h" -#include "CMPCThemeDockBar.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - -IMPLEMENT_DYNAMIC(CMPCThemeDockBar, CDockBar) -BEGIN_MESSAGE_MAP(CMPCThemeDockBar, CDockBar) - ON_WM_ERASEBKGND() - ON_WM_NCPAINT() -END_MESSAGE_MAP() - -CMPCThemeDockBar::CMPCThemeDockBar() -{ -} - - -CMPCThemeDockBar::~CMPCThemeDockBar() -{ -} - - -BOOL CMPCThemeDockBar::OnEraseBkgnd(CDC* pDC) -{ - if (!AppIsThemeLoaded()) { - return __super::OnEraseBkgnd(pDC); - } - - CBrush backBrush(CMPCTheme::WindowBGColor); - - CBrush* pOldBrush = pDC->SelectObject(&backBrush); - CRect rect; - pDC->GetClipBox(&rect); - - pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); - pDC->SelectObject(pOldBrush); - - return TRUE; -} - - -void CMPCThemeDockBar::OnNcPaint() -{ - if (!AppIsThemeLoaded()) { - __super::OnNcPaint(); - return; - } - - CWindowDC dc(this); // the HDC will be released by the destructor - - CRect rcClient, rcWindow; - GetClientRect(rcClient); - GetWindowRect(rcWindow); - ScreenToClient(rcWindow); - rcClient.OffsetRect(-rcWindow.TopLeft()); - rcWindow.OffsetRect(-rcWindow.TopLeft()); - - CRect rcDraw = rcWindow; - - dc.IntersectClipRect(rcWindow); - dc.ExcludeClipRect(rcClient); - dc.FillSolidRect(rcDraw, CMPCTheme::WindowBGColor); -} +#include "stdafx.h" +#include "CMPCThemeDockBar.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + +IMPLEMENT_DYNAMIC(CMPCThemeDockBar, CDockBar) +BEGIN_MESSAGE_MAP(CMPCThemeDockBar, CDockBar) + ON_WM_ERASEBKGND() + ON_WM_NCPAINT() +END_MESSAGE_MAP() + +CMPCThemeDockBar::CMPCThemeDockBar() +{ +} + + +CMPCThemeDockBar::~CMPCThemeDockBar() +{ +} + + +BOOL CMPCThemeDockBar::OnEraseBkgnd(CDC* pDC) +{ + if (!AppIsThemeLoaded()) { + return __super::OnEraseBkgnd(pDC); + } + + CBrush backBrush(CMPCTheme::WindowBGColor); + + CBrush* pOldBrush = pDC->SelectObject(&backBrush); + CRect rect; + pDC->GetClipBox(&rect); + + pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); + pDC->SelectObject(pOldBrush); + + return TRUE; +} + + +void CMPCThemeDockBar::OnNcPaint() +{ + if (!AppIsThemeLoaded()) { + __super::OnNcPaint(); + return; + } + + CWindowDC dc(this); // the HDC will be released by the destructor + + CRect rcClient, rcWindow; + GetClientRect(rcClient); + GetWindowRect(rcWindow); + ScreenToClient(rcWindow); + rcClient.OffsetRect(-rcWindow.TopLeft()); + rcWindow.OffsetRect(-rcWindow.TopLeft()); + + CRect rcDraw = rcWindow; + + dc.IntersectClipRect(rcWindow); + dc.ExcludeClipRect(rcClient); + dc.FillSolidRect(rcDraw, CMPCTheme::WindowBGColor); +} diff --git a/src/mpc-hc/CMPCThemeDockBar.h b/src/mpc-hc/CMPCThemeDockBar.h index eb9042abf45..b3a355f9287 100755 --- a/src/mpc-hc/CMPCThemeDockBar.h +++ b/src/mpc-hc/CMPCThemeDockBar.h @@ -1,15 +1,15 @@ -#pragma once -#include -class CMPCThemeDockBar : public CDockBar -{ - DECLARE_DYNAMIC(CMPCThemeDockBar) -public: - CMPCThemeDockBar(); - virtual ~CMPCThemeDockBar(); -protected: - DECLARE_MESSAGE_MAP() -public: - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnNcPaint(); -}; - +#pragma once +#include +class CMPCThemeDockBar : public CDockBar +{ + DECLARE_DYNAMIC(CMPCThemeDockBar) +public: + CMPCThemeDockBar(); + virtual ~CMPCThemeDockBar(); +protected: + DECLARE_MESSAGE_MAP() +public: + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnNcPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeEdit.cpp b/src/mpc-hc/CMPCThemeEdit.cpp index eb8df670002..615a7897402 100755 --- a/src/mpc-hc/CMPCThemeEdit.cpp +++ b/src/mpc-hc/CMPCThemeEdit.cpp @@ -1,437 +1,437 @@ -#include "stdafx.h" -#include "CMPCThemeEdit.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#include "CMPCThemeMenu.h" -#include - -std::unique_ptr editMenu; -CMPCThemeEdit::CMPCThemeEdit() -{ - buddy = nullptr; - themedSBHelper = nullptr; - isFileDialogChild = false; - //horizontal scrollbar broken for CEdit, we must theme ourselves - // if (!CMPCThemeUtil::canUseWin10DarkTheme()()) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - // } -} - -CMPCThemeEdit::~CMPCThemeEdit() -{ - if (nullptr != themedSBHelper) { - delete themedSBHelper; - } -} - -IMPLEMENT_DYNAMIC(CMPCThemeEdit, CEdit) -BEGIN_MESSAGE_MAP(CMPCThemeEdit, CEdit) - ON_WM_NCPAINT() - ON_WM_MOUSEWHEEL() - ON_WM_VSCROLL() - ON_WM_HSCROLL() - ON_WM_KEYDOWN() - ON_WM_WINDOWPOSCHANGED() - ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, ResizeSupport) - ON_MESSAGE(WM_CONTEXTMENU, OnContextMenu) - ON_WM_MEASUREITEM() -END_MESSAGE_MAP() - -void CMPCThemeEdit::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { - if (lpMeasureItemStruct->CtlType == ODT_MENU && editMenu) { - editMenu->MeasureItem(lpMeasureItemStruct); - return; - } - - CEdit::OnMeasureItem(nIDCtl, lpMeasureItemStruct); -} - -//on Edit class, cbWndExtra allocates space for a pointer, which points to this data -struct PRIVATEWNDDATA { - LONG_PTR ptr1; - DWORD D04, D08; - DWORD textLength; - DWORD D10; - DWORD startSelection, endSelection, cursorPosition; - DWORD DW1[5]; - LONG_PTR ptr2; - DWORD hwnd; //32-bit storage, even on 64-bit (HWND is wrong size) - DWORD DW2[7]; - DWORD parentHwnd; //32-bit storage, even on 64-bit (HWND is wrong size) - DWORD D3; - LONG_PTR ptr3; - DWORD D4; - DWORD flags; //EDIT control flags -}; - -//ContextMenu constants -#define ENABLE_UNICODE_CONTROL_CHARS 0x40000000 -#define IDS_OPEN_IME 0x1052 -#define IDS_CLOSE_IME 0x1053 -#define IDS_IME_RECONVERSION 0x1056 -#define ID_CONTEXT_MENU_IME 0x2711 -#define ID_CONTEXT_MENU_RECONVERSION 0x2713 -#define SCS_FEATURES_NEEDED (SCS_CAP_MAKEREAD | SCS_CAP_SETRECONVERTSTRING) -#define EDIT_CONTEXT_MENU 1 - -bool IsBidiLocale() { - DWORD layout; - //see https://web.archive.org/web/20131013052748/http://blogs.msdn.com/b/michkap/archive/2012/01/13/10256391.aspx - if (GetLocaleInfoW(GetUserDefaultUILanguage(), LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, (LPWSTR)&layout, 2)) { - if (layout == 1) { - return true; - } - } - return false; -} - -std::array UnicodeChars = { - 0x200D, //ZWJ -- Zero width &joiner - 0x200C, //ZWNJ -- Zero width &non-joiner - 0x200E, //RLM -- &Right-to-left mark - 0x200F, //LRM -- &Left-to-right mark - 0x202A, //LRE -- Start of left-to-right embedding - 0x202B, //RLE -- Start of right-to-left embedding - 0x202D, //LRO -- Start of left-to-right override - 0x202E, //RLO -- Start of right-to-left override - 0x202C, //PDF -- Pop directional formatting - 0x206E, //NADS -- National digit shapes substitution - 0x206F, //NODS -- Nominal (European) digit shapes - 0x206B, //ASS -- Activate symmetric swapping - 0x206A, //ISS -- Inhibit symmetric swapping - 0x206D, //AAFS -- Activate Arabic form shaping - 0x206C, //IAFS -- Inhibit Arabic form shaping - 0x001E, //RS -- Record Separator (Block separator) - 0x001F, //US -- Unit Separator (Segment separator) -}; - -void CMPCThemeEdit::SetCompWindowPos(HIMC himc, UINT start) { - COMPOSITIONFORM cf = { CFS_POINT, PosFromChar(start), {0} }; - ImmSetCompositionWindow(himc, &cf); -} - -LRESULT CMPCThemeEdit::OnContextMenu(WPARAM wParam, LPARAM lParam) { - if (AppIsThemeLoaded()) { - if (GetFocus() != this) { - SetFocus(); - } - HMODULE g_hinst = GetModuleHandleW(L"comctl32.dll"); - if (g_hinst) { - HMENU menu = LoadMenuW(g_hinst, (LPCWSTR)EDIT_CONTEXT_MENU); - if (menu) { - HMENU popup = GetSubMenu(menu, 0); - if (popup) { - CPoint pt; - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - - DWORD rtlStyle = WS_EX_RTLREADING | WS_EX_RIGHT; - bool isRTL = (GetExStyle() & rtlStyle); - - bool supportUnicodeControl = false, showControlChars = false; - PRIVATEWNDDATA *pwd = (PRIVATEWNDDATA *)GetWindowLongPtrW(m_hWnd, 0); - if (pwd && pwd->hwnd == static_cast((LONG_PTR)m_hWnd)) { //sanity check - supportUnicodeControl = true; - showControlChars = (pwd->flags & ENABLE_UNICODE_CONTROL_CHARS); - } - - if (pt.x == -1 && pt.y == -1) { //VK_APPS - CRect rc; - GetClientRect(&rc); - - pt.x = rc.left + (rc.right - rc.left) / 2; - pt.y = rc.top + (rc.bottom - rc.top) / 2; - ClientToScreen(&pt); - } - - UINT start = HIWORD(GetSel()); - UINT end = LOWORD(GetSel()); - DWORD style = GetStyle(); - bool isPasswordField = (style & ES_PASSWORD); - CStringW str; - GetWindowTextW(str); - - - if (end < start) { - std::swap(end, start); - } - int selectionLength = end - start; - - editMenu = std::make_unique(); - editMenu->setOSMenu(true); - editMenu->Attach(popup); - editMenu->EnableMenuItem(EM_UNDO, MF_BYCOMMAND | (CanUndo() && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); - editMenu->EnableMenuItem(WM_CUT, MF_BYCOMMAND | (selectionLength && !isPasswordField && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); - editMenu->EnableMenuItem(WM_COPY, MF_BYCOMMAND | (selectionLength && !isPasswordField ? MF_ENABLED : MF_GRAYED)); - editMenu->EnableMenuItem(WM_PASTE, MF_BYCOMMAND | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); - editMenu->EnableMenuItem(WM_CLEAR, MF_BYCOMMAND | (selectionLength && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); //delete - editMenu->EnableMenuItem(EM_SETSEL, MF_BYCOMMAND | (start || (end != str.GetLength()) ? MF_ENABLED : MF_GRAYED)); //select all - editMenu->EnableMenuItem(WM_APP, MF_BYCOMMAND | MF_ENABLED); //RTL - editMenu->CheckMenuItem(WM_APP, MF_BYCOMMAND | (isRTL ? MF_CHECKED : MF_UNCHECKED)); - - if (supportUnicodeControl) { - editMenu->EnableMenuItem(WM_APP + 1, MF_BYCOMMAND | MF_ENABLED); //show unicode control chars - editMenu->CheckMenuItem(WM_APP + 1, MF_BYCOMMAND | (showControlChars ? MF_CHECKED : MF_UNCHECKED)); - } - - //enable all unicode char inserts - for (UINT idx = WM_APP + 0x2; idx <= WM_APP + 0x13; idx++) { - editMenu->EnableMenuItem(idx, MF_BYCOMMAND | MF_ENABLED); - } - - HIMC himc = nullptr; - HKL hkl = GetKeyboardLayout(NULL); - if (ImmIsIME(hkl)) { - himc = ImmGetContext(this->m_hWnd); - if (himc) { - bool checked = false, enabled = true; - MENUITEMINFOW mii = { sizeof(MENUITEMINFOW) }; - mii.fMask = MIIM_ID | MIIM_STRING; - mii.wID = ID_CONTEXT_MENU_IME; - CStringW miS; - bool strLoaded; - - if (::ImmGetOpenStatus(himc)) { - strLoaded = miS.LoadStringW(g_hinst, IDS_CLOSE_IME); - } else { - strLoaded = miS.LoadStringW(g_hinst, IDS_OPEN_IME); - } - - if (strLoaded) { - mii.dwTypeData = (LPWSTR)miS.GetString(); - mii.cch = (UINT)wcslen(mii.dwTypeData); - - editMenu->InsertMenuItemW(editMenu->GetMenuItemCount(), &mii); - } - - strLoaded = miS.LoadStringW(g_hinst, IDS_IME_RECONVERSION); - if (strLoaded) { - mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE; - mii.dwTypeData = (LPWSTR)miS.GetString(); - mii.cch = (UINT)wcslen(mii.dwTypeData); - mii.wID = ID_CONTEXT_MENU_RECONVERSION; - bool supportsReconversion = (ImmGetProperty(hkl, IGP_SETCOMPSTR) & SCS_FEATURES_NEEDED) == SCS_FEATURES_NEEDED; - if (!supportsReconversion || !selectionLength || isPasswordField) { - mii.fState = MFS_DISABLED; - } else { - mii.fState = MFS_ENABLED; - } - editMenu->InsertMenuItemW(editMenu->GetMenuItemCount(), &mii); - } - } - } - editMenu->fulfillThemeReqs(); - - UINT cmd = editMenu->TrackPopupMenu((IsBidiLocale() ? TPM_LAYOUTRTL : TPM_LEFTALIGN) | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, pt.x, pt.y, this); - - switch (cmd) { - case EM_UNDO: - case WM_CUT: - case WM_COPY: - case WM_PASTE: - case WM_CLEAR: - SendMessageW(cmd, 0, 0); - break; - case EM_SETSEL: - SendMessageW(EM_SETSEL, 0, -1); - break; - case WM_APP: //RTL - ModifyStyleEx(isRTL ? rtlStyle : 0, isRTL ? 0 : rtlStyle); - break; - case WM_APP + 1: //show unicode control chars - if (pwd) { - pwd->flags ^= ENABLE_UNICODE_CONTROL_CHARS; - Invalidate(); - } - break; - case ID_CONTEXT_MENU_IME: //IME - if (himc) { - ImmSetOpenStatus(himc, !ImmGetOpenStatus(himc)); - } - break; - case ID_CONTEXT_MENU_RECONVERSION: - if (himc) { - CStringW selected; - selected = str.Mid(start, end - start); - const size_t text_memory_byte = sizeof(wchar_t) * (selected.GetLength() + 1); - const size_t memory_block_size = sizeof(RECONVERTSTRING) + text_memory_byte; - std::unique_ptr memory_block{ new (std::nothrow) BYTE[memory_block_size] }; - if (memory_block) { - SetCompWindowPos(himc, start); - RECONVERTSTRING* reconv{ reinterpret_cast(memory_block.get()) }; - reconv->dwSize = (DWORD)memory_block_size; - reconv->dwVersion = 0; - reconv->dwStrLen = selected.GetLength(); - reconv->dwStrOffset = sizeof(RECONVERTSTRING); - reconv->dwCompStrLen = selected.GetLength(); - reconv->dwCompStrOffset = 0; - reconv->dwTargetStrLen = selected.GetLength(); - reconv->dwTargetStrOffset = reconv->dwCompStrOffset; - wchar_t* text{ reinterpret_cast(memory_block.get() + sizeof(RECONVERTSTRING)) }; - memcpy_s(text, text_memory_byte, selected.GetBuffer(), text_memory_byte); - ImmSetCompositionStringW(himc, SCS_QUERYRECONVERTSTRING, (LPVOID)memory_block.get(), (DWORD)memory_block_size, nullptr, 0); - ImmSetCompositionStringW(himc, SCS_SETRECONVERTSTRING, (LPVOID)memory_block.get(), (DWORD)memory_block_size, nullptr, 0); - } - } - default: - int idx = cmd - (WM_APP + 0x2); - if (idx >= 0 && idx < UnicodeChars.size()) { - SendMessageW(WM_CHAR, UnicodeChars[idx], 0); break; //US -- Unit Separator (Segment separator) - } - break; - } - - if (himc) { - ::ImmReleaseContext(this->m_hWnd, himc); - } - editMenu.reset(); - return 0; - } - } - } - } - return Default(); -} - -bool CMPCThemeEdit::IsScrollable() { - return 0 != (GetStyle() & (WS_VSCROLL | WS_HSCROLL)); -} - -//this message is sent by resizablelib -//we prevent clipping for multi-line edits due to using regions which conflict with resizablelib clipping -LRESULT CMPCThemeEdit::ResizeSupport(WPARAM wParam, LPARAM lParam) { - if (AppNeedsThemedControls() && IsScrollable()) { - if (wParam == RSZSUP_QUERYPROPERTIES) { - LPRESIZEPROPERTIES props = (LPRESIZEPROPERTIES)lParam; - props->bAskClipping = false; - props->bCachedLikesClipping = false; - return TRUE; - } - } - return FALSE; -} - -void CMPCThemeEdit::OnWindowPosChanged(WINDOWPOS* lpwndpos) { - if (AppNeedsThemedControls()) { - if (themedSBHelper && IsScrollable()) { - themedSBHelper->OnWindowPosChanged(); - } - } - return __super::OnWindowPosChanged(lpwndpos); -} - -void CMPCThemeEdit::PreSubclassWindow() -{ - if (AppIsThemeLoaded()) { - CRect r; - GetClientRect(r); - r.DeflateRect(2, 2); //some default padding for those spaceless fonts - SetRect(r); - if (CMPCThemeUtil::canUseWin10DarkTheme()) { - SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); - } else { - SetWindowTheme(GetSafeHwnd(), L"", NULL); - } - } else { - __super::PreSubclassWindow(); - } -} - - - -void CMPCThemeEdit::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - if (IsScrollable()) { //scrollable edit will be treated like a window, not a field - if (nullptr != themedSBHelper) { - themedSBHelper->themedNcPaintWithSB(); - } else { - CMPCThemeScrollBarHelper::themedNcPaint(this, this); - } - } else { - CWindowDC dc(this); - - CRect rect; - GetWindowRect(&rect); - rect.OffsetRect(-rect.left, -rect.top); - - //note: rc file with style "NOT WS_BORDER" will remove the default of WS_EX_CLIENTEDGE from EDITTEXT - //WS_BORDER itself is not typically present - auto stEx = GetExStyle(); - if (0 != (GetStyle() & WS_BORDER) || 0 != (GetExStyle() & WS_EX_CLIENTEDGE)) { - CBrush brush; - if (isFileDialogChild) {//special case for edits injected to file dialog - brush.CreateSolidBrush(CMPCTheme::W10DarkThemeFileDialogInjectedEditBorderColor); - } else { - brush.CreateSolidBrush(CMPCTheme::EditBorderColor); - } - - dc.FrameRect(&rect, &brush); - brush.DeleteObject(); - } - - //added code to draw the inner rect for the border. we shrunk the draw rect for border spacing earlier - //normally, the bg of the dialog is sufficient, but in the case of ResizableDialog, it clips the anchored - //windows, which leaves unpainted area just inside our border - rect.DeflateRect(1, 1); - CMPCThemeUtil::drawParentDialogBGClr(this, &dc, rect, false); - - if (nullptr != buddy) { - buddy->Invalidate(); - } - } - - } else { - __super::OnNcPaint(); - } -} - -void CMPCThemeEdit::SetFixedWidthFont(CFont& f) -{ - if (AppIsThemeLoaded()) { - CWindowDC dc(this); - if (CMPCThemeUtil::getFixedFont(font, &dc, this)) { - SetFont(&font); - } else { - SetFont(&f); - } - } else { - SetFont(&f); - } -} - -BOOL CMPCThemeEdit::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) -{ - __super::OnMouseWheel(nFlags, zDelta, pt); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - ScreenToClient(&pt); - return TRUE; -} - -void CMPCThemeEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - __super::OnVScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - -void CMPCThemeEdit::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - __super::OnHScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - - -void CMPCThemeEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - __super::OnKeyDown(nChar, nRepCnt, nFlags); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} +#include "stdafx.h" +#include "CMPCThemeEdit.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#include "CMPCThemeMenu.h" +#include + +std::unique_ptr editMenu; +CMPCThemeEdit::CMPCThemeEdit() +{ + buddy = nullptr; + themedSBHelper = nullptr; + isFileDialogChild = false; + //horizontal scrollbar broken for CEdit, we must theme ourselves + // if (!CMPCThemeUtil::canUseWin10DarkTheme()()) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + // } +} + +CMPCThemeEdit::~CMPCThemeEdit() +{ + if (nullptr != themedSBHelper) { + delete themedSBHelper; + } +} + +IMPLEMENT_DYNAMIC(CMPCThemeEdit, CEdit) +BEGIN_MESSAGE_MAP(CMPCThemeEdit, CEdit) + ON_WM_NCPAINT() + ON_WM_MOUSEWHEEL() + ON_WM_VSCROLL() + ON_WM_HSCROLL() + ON_WM_KEYDOWN() + ON_WM_WINDOWPOSCHANGED() + ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, ResizeSupport) + ON_MESSAGE(WM_CONTEXTMENU, OnContextMenu) + ON_WM_MEASUREITEM() +END_MESSAGE_MAP() + +void CMPCThemeEdit::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { + if (lpMeasureItemStruct->CtlType == ODT_MENU && editMenu) { + editMenu->MeasureItem(lpMeasureItemStruct); + return; + } + + CEdit::OnMeasureItem(nIDCtl, lpMeasureItemStruct); +} + +//on Edit class, cbWndExtra allocates space for a pointer, which points to this data +struct PRIVATEWNDDATA { + LONG_PTR ptr1; + DWORD D04, D08; + DWORD textLength; + DWORD D10; + DWORD startSelection, endSelection, cursorPosition; + DWORD DW1[5]; + LONG_PTR ptr2; + DWORD hwnd; //32-bit storage, even on 64-bit (HWND is wrong size) + DWORD DW2[7]; + DWORD parentHwnd; //32-bit storage, even on 64-bit (HWND is wrong size) + DWORD D3; + LONG_PTR ptr3; + DWORD D4; + DWORD flags; //EDIT control flags +}; + +//ContextMenu constants +#define ENABLE_UNICODE_CONTROL_CHARS 0x40000000 +#define IDS_OPEN_IME 0x1052 +#define IDS_CLOSE_IME 0x1053 +#define IDS_IME_RECONVERSION 0x1056 +#define ID_CONTEXT_MENU_IME 0x2711 +#define ID_CONTEXT_MENU_RECONVERSION 0x2713 +#define SCS_FEATURES_NEEDED (SCS_CAP_MAKEREAD | SCS_CAP_SETRECONVERTSTRING) +#define EDIT_CONTEXT_MENU 1 + +bool IsBidiLocale() { + DWORD layout; + //see https://web.archive.org/web/20131013052748/http://blogs.msdn.com/b/michkap/archive/2012/01/13/10256391.aspx + if (GetLocaleInfoW(GetUserDefaultUILanguage(), LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, (LPWSTR)&layout, 2)) { + if (layout == 1) { + return true; + } + } + return false; +} + +std::array UnicodeChars = { + 0x200D, //ZWJ -- Zero width &joiner + 0x200C, //ZWNJ -- Zero width &non-joiner + 0x200E, //RLM -- &Right-to-left mark + 0x200F, //LRM -- &Left-to-right mark + 0x202A, //LRE -- Start of left-to-right embedding + 0x202B, //RLE -- Start of right-to-left embedding + 0x202D, //LRO -- Start of left-to-right override + 0x202E, //RLO -- Start of right-to-left override + 0x202C, //PDF -- Pop directional formatting + 0x206E, //NADS -- National digit shapes substitution + 0x206F, //NODS -- Nominal (European) digit shapes + 0x206B, //ASS -- Activate symmetric swapping + 0x206A, //ISS -- Inhibit symmetric swapping + 0x206D, //AAFS -- Activate Arabic form shaping + 0x206C, //IAFS -- Inhibit Arabic form shaping + 0x001E, //RS -- Record Separator (Block separator) + 0x001F, //US -- Unit Separator (Segment separator) +}; + +void CMPCThemeEdit::SetCompWindowPos(HIMC himc, UINT start) { + COMPOSITIONFORM cf = { CFS_POINT, PosFromChar(start), {0} }; + ImmSetCompositionWindow(himc, &cf); +} + +LRESULT CMPCThemeEdit::OnContextMenu(WPARAM wParam, LPARAM lParam) { + if (AppIsThemeLoaded()) { + if (GetFocus() != this) { + SetFocus(); + } + HMODULE g_hinst = GetModuleHandleW(L"comctl32.dll"); + if (g_hinst) { + HMENU menu = LoadMenuW(g_hinst, (LPCWSTR)EDIT_CONTEXT_MENU); + if (menu) { + HMENU popup = GetSubMenu(menu, 0); + if (popup) { + CPoint pt; + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + + DWORD rtlStyle = WS_EX_RTLREADING | WS_EX_RIGHT; + bool isRTL = (GetExStyle() & rtlStyle); + + bool supportUnicodeControl = false, showControlChars = false; + PRIVATEWNDDATA *pwd = (PRIVATEWNDDATA *)GetWindowLongPtrW(m_hWnd, 0); + if (pwd && pwd->hwnd == static_cast((LONG_PTR)m_hWnd)) { //sanity check + supportUnicodeControl = true; + showControlChars = (pwd->flags & ENABLE_UNICODE_CONTROL_CHARS); + } + + if (pt.x == -1 && pt.y == -1) { //VK_APPS + CRect rc; + GetClientRect(&rc); + + pt.x = rc.left + (rc.right - rc.left) / 2; + pt.y = rc.top + (rc.bottom - rc.top) / 2; + ClientToScreen(&pt); + } + + UINT start = HIWORD(GetSel()); + UINT end = LOWORD(GetSel()); + DWORD style = GetStyle(); + bool isPasswordField = (style & ES_PASSWORD); + CStringW str; + GetWindowTextW(str); + + + if (end < start) { + std::swap(end, start); + } + int selectionLength = end - start; + + editMenu = std::make_unique(); + editMenu->setOSMenu(true); + editMenu->Attach(popup); + editMenu->EnableMenuItem(EM_UNDO, MF_BYCOMMAND | (CanUndo() && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); + editMenu->EnableMenuItem(WM_CUT, MF_BYCOMMAND | (selectionLength && !isPasswordField && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); + editMenu->EnableMenuItem(WM_COPY, MF_BYCOMMAND | (selectionLength && !isPasswordField ? MF_ENABLED : MF_GRAYED)); + editMenu->EnableMenuItem(WM_PASTE, MF_BYCOMMAND | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); + editMenu->EnableMenuItem(WM_CLEAR, MF_BYCOMMAND | (selectionLength && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); //delete + editMenu->EnableMenuItem(EM_SETSEL, MF_BYCOMMAND | (start || (end != str.GetLength()) ? MF_ENABLED : MF_GRAYED)); //select all + editMenu->EnableMenuItem(WM_APP, MF_BYCOMMAND | MF_ENABLED); //RTL + editMenu->CheckMenuItem(WM_APP, MF_BYCOMMAND | (isRTL ? MF_CHECKED : MF_UNCHECKED)); + + if (supportUnicodeControl) { + editMenu->EnableMenuItem(WM_APP + 1, MF_BYCOMMAND | MF_ENABLED); //show unicode control chars + editMenu->CheckMenuItem(WM_APP + 1, MF_BYCOMMAND | (showControlChars ? MF_CHECKED : MF_UNCHECKED)); + } + + //enable all unicode char inserts + for (UINT idx = WM_APP + 0x2; idx <= WM_APP + 0x13; idx++) { + editMenu->EnableMenuItem(idx, MF_BYCOMMAND | MF_ENABLED); + } + + HIMC himc = nullptr; + HKL hkl = GetKeyboardLayout(NULL); + if (ImmIsIME(hkl)) { + himc = ImmGetContext(this->m_hWnd); + if (himc) { + bool checked = false, enabled = true; + MENUITEMINFOW mii = { sizeof(MENUITEMINFOW) }; + mii.fMask = MIIM_ID | MIIM_STRING; + mii.wID = ID_CONTEXT_MENU_IME; + CStringW miS; + bool strLoaded; + + if (::ImmGetOpenStatus(himc)) { + strLoaded = miS.LoadStringW(g_hinst, IDS_CLOSE_IME); + } else { + strLoaded = miS.LoadStringW(g_hinst, IDS_OPEN_IME); + } + + if (strLoaded) { + mii.dwTypeData = (LPWSTR)miS.GetString(); + mii.cch = (UINT)wcslen(mii.dwTypeData); + + editMenu->InsertMenuItemW(editMenu->GetMenuItemCount(), &mii); + } + + strLoaded = miS.LoadStringW(g_hinst, IDS_IME_RECONVERSION); + if (strLoaded) { + mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE; + mii.dwTypeData = (LPWSTR)miS.GetString(); + mii.cch = (UINT)wcslen(mii.dwTypeData); + mii.wID = ID_CONTEXT_MENU_RECONVERSION; + bool supportsReconversion = (ImmGetProperty(hkl, IGP_SETCOMPSTR) & SCS_FEATURES_NEEDED) == SCS_FEATURES_NEEDED; + if (!supportsReconversion || !selectionLength || isPasswordField) { + mii.fState = MFS_DISABLED; + } else { + mii.fState = MFS_ENABLED; + } + editMenu->InsertMenuItemW(editMenu->GetMenuItemCount(), &mii); + } + } + } + editMenu->fulfillThemeReqs(); + + UINT cmd = editMenu->TrackPopupMenu((IsBidiLocale() ? TPM_LAYOUTRTL : TPM_LEFTALIGN) | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, pt.x, pt.y, this); + + switch (cmd) { + case EM_UNDO: + case WM_CUT: + case WM_COPY: + case WM_PASTE: + case WM_CLEAR: + SendMessageW(cmd, 0, 0); + break; + case EM_SETSEL: + SendMessageW(EM_SETSEL, 0, -1); + break; + case WM_APP: //RTL + ModifyStyleEx(isRTL ? rtlStyle : 0, isRTL ? 0 : rtlStyle); + break; + case WM_APP + 1: //show unicode control chars + if (pwd) { + pwd->flags ^= ENABLE_UNICODE_CONTROL_CHARS; + Invalidate(); + } + break; + case ID_CONTEXT_MENU_IME: //IME + if (himc) { + ImmSetOpenStatus(himc, !ImmGetOpenStatus(himc)); + } + break; + case ID_CONTEXT_MENU_RECONVERSION: + if (himc) { + CStringW selected; + selected = str.Mid(start, end - start); + const size_t text_memory_byte = sizeof(wchar_t) * (selected.GetLength() + 1); + const size_t memory_block_size = sizeof(RECONVERTSTRING) + text_memory_byte; + std::unique_ptr memory_block{ new (std::nothrow) BYTE[memory_block_size] }; + if (memory_block) { + SetCompWindowPos(himc, start); + RECONVERTSTRING* reconv{ reinterpret_cast(memory_block.get()) }; + reconv->dwSize = (DWORD)memory_block_size; + reconv->dwVersion = 0; + reconv->dwStrLen = selected.GetLength(); + reconv->dwStrOffset = sizeof(RECONVERTSTRING); + reconv->dwCompStrLen = selected.GetLength(); + reconv->dwCompStrOffset = 0; + reconv->dwTargetStrLen = selected.GetLength(); + reconv->dwTargetStrOffset = reconv->dwCompStrOffset; + wchar_t* text{ reinterpret_cast(memory_block.get() + sizeof(RECONVERTSTRING)) }; + memcpy_s(text, text_memory_byte, selected.GetBuffer(), text_memory_byte); + ImmSetCompositionStringW(himc, SCS_QUERYRECONVERTSTRING, (LPVOID)memory_block.get(), (DWORD)memory_block_size, nullptr, 0); + ImmSetCompositionStringW(himc, SCS_SETRECONVERTSTRING, (LPVOID)memory_block.get(), (DWORD)memory_block_size, nullptr, 0); + } + } + default: + int idx = cmd - (WM_APP + 0x2); + if (idx >= 0 && idx < UnicodeChars.size()) { + SendMessageW(WM_CHAR, UnicodeChars[idx], 0); break; //US -- Unit Separator (Segment separator) + } + break; + } + + if (himc) { + ::ImmReleaseContext(this->m_hWnd, himc); + } + editMenu.reset(); + return 0; + } + } + } + } + return Default(); +} + +bool CMPCThemeEdit::IsScrollable() { + return 0 != (GetStyle() & (WS_VSCROLL | WS_HSCROLL)); +} + +//this message is sent by resizablelib +//we prevent clipping for multi-line edits due to using regions which conflict with resizablelib clipping +LRESULT CMPCThemeEdit::ResizeSupport(WPARAM wParam, LPARAM lParam) { + if (AppNeedsThemedControls() && IsScrollable()) { + if (wParam == RSZSUP_QUERYPROPERTIES) { + LPRESIZEPROPERTIES props = (LPRESIZEPROPERTIES)lParam; + props->bAskClipping = false; + props->bCachedLikesClipping = false; + return TRUE; + } + } + return FALSE; +} + +void CMPCThemeEdit::OnWindowPosChanged(WINDOWPOS* lpwndpos) { + if (AppNeedsThemedControls()) { + if (themedSBHelper && IsScrollable()) { + themedSBHelper->OnWindowPosChanged(); + } + } + return __super::OnWindowPosChanged(lpwndpos); +} + +void CMPCThemeEdit::PreSubclassWindow() +{ + if (AppIsThemeLoaded()) { + CRect r; + GetClientRect(r); + r.DeflateRect(2, 2); //some default padding for those spaceless fonts + SetRect(r); + if (CMPCThemeUtil::canUseWin10DarkTheme()) { + SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); + } else { + SetWindowTheme(GetSafeHwnd(), L"", NULL); + } + } else { + __super::PreSubclassWindow(); + } +} + + + +void CMPCThemeEdit::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + if (IsScrollable()) { //scrollable edit will be treated like a window, not a field + if (nullptr != themedSBHelper) { + themedSBHelper->themedNcPaintWithSB(); + } else { + CMPCThemeScrollBarHelper::themedNcPaint(this, this); + } + } else { + CWindowDC dc(this); + + CRect rect; + GetWindowRect(&rect); + rect.OffsetRect(-rect.left, -rect.top); + + //note: rc file with style "NOT WS_BORDER" will remove the default of WS_EX_CLIENTEDGE from EDITTEXT + //WS_BORDER itself is not typically present + auto stEx = GetExStyle(); + if (0 != (GetStyle() & WS_BORDER) || 0 != (GetExStyle() & WS_EX_CLIENTEDGE)) { + CBrush brush; + if (isFileDialogChild) {//special case for edits injected to file dialog + brush.CreateSolidBrush(CMPCTheme::W10DarkThemeFileDialogInjectedEditBorderColor); + } else { + brush.CreateSolidBrush(CMPCTheme::EditBorderColor); + } + + dc.FrameRect(&rect, &brush); + brush.DeleteObject(); + } + + //added code to draw the inner rect for the border. we shrunk the draw rect for border spacing earlier + //normally, the bg of the dialog is sufficient, but in the case of ResizableDialog, it clips the anchored + //windows, which leaves unpainted area just inside our border + rect.DeflateRect(1, 1); + CMPCThemeUtil::drawParentDialogBGClr(this, &dc, rect, false); + + if (nullptr != buddy) { + buddy->Invalidate(); + } + } + + } else { + __super::OnNcPaint(); + } +} + +void CMPCThemeEdit::SetFixedWidthFont(CFont& f) +{ + if (AppIsThemeLoaded()) { + CWindowDC dc(this); + if (CMPCThemeUtil::getFixedFont(font, &dc, this)) { + SetFont(&font); + } else { + SetFont(&f); + } + } else { + SetFont(&f); + } +} + +BOOL CMPCThemeEdit::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + __super::OnMouseWheel(nFlags, zDelta, pt); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + ScreenToClient(&pt); + return TRUE; +} + +void CMPCThemeEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + __super::OnVScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + +void CMPCThemeEdit::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + __super::OnHScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + + +void CMPCThemeEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + __super::OnKeyDown(nChar, nRepCnt, nFlags); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} diff --git a/src/mpc-hc/CMPCThemeEdit.h b/src/mpc-hc/CMPCThemeEdit.h index 2c72cfbc8e2..5b19b63b7c4 100755 --- a/src/mpc-hc/CMPCThemeEdit.h +++ b/src/mpc-hc/CMPCThemeEdit.h @@ -1,39 +1,39 @@ -#pragma once -#include -#include "CMPCThemeScrollBarHelper.h" -#include - -class CMPCThemeEdit : public CEdit - , public CMPCThemeScrollable -{ -public: - DECLARE_DYNAMIC(CMPCThemeEdit) - CMPCThemeEdit(); - virtual ~CMPCThemeEdit(); - void PreSubclassWindow(); - void setBuddy(CWnd* buddyWindow) { this->buddy = buddyWindow; }; - void setFileDialogChild(bool set) { isFileDialogChild = set; }; - void SetFixedWidthFont(CFont& f); - bool IsScrollable(); -protected: - CWnd* buddy; - CMPCThemeScrollBarHelper* themedSBHelper; - CFont font; - bool isFileDialogChild; - void SetCompWindowPos(HIMC himc, UINT start); - - DECLARE_MESSAGE_MAP() - - afx_msg LRESULT ResizeSupport(WPARAM wParam, LPARAM lParam); - afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); - afx_msg void OnNcPaint(); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); -public: - afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); - afx_msg LRESULT OnContextMenu(WPARAM wParam, LPARAM lParam); - afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); -}; - - +#pragma once +#include +#include "CMPCThemeScrollBarHelper.h" +#include + +class CMPCThemeEdit : public CEdit + , public CMPCThemeScrollable +{ +public: + DECLARE_DYNAMIC(CMPCThemeEdit) + CMPCThemeEdit(); + virtual ~CMPCThemeEdit(); + void PreSubclassWindow(); + void setBuddy(CWnd* buddyWindow) { this->buddy = buddyWindow; }; + void setFileDialogChild(bool set) { isFileDialogChild = set; }; + void SetFixedWidthFont(CFont& f); + bool IsScrollable(); +protected: + CWnd* buddy; + CMPCThemeScrollBarHelper* themedSBHelper; + CFont font; + bool isFileDialogChild; + void SetCompWindowPos(HIMC himc, UINT start); + + DECLARE_MESSAGE_MAP() + + afx_msg LRESULT ResizeSupport(WPARAM wParam, LPARAM lParam); + afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); + afx_msg void OnNcPaint(); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); +public: + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg LRESULT OnContextMenu(WPARAM wParam, LPARAM lParam); + afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); +}; + + diff --git a/src/mpc-hc/CMPCThemeFrameUtil.cpp b/src/mpc-hc/CMPCThemeFrameUtil.cpp index 685379185b8..6818e0322b2 100644 --- a/src/mpc-hc/CMPCThemeFrameUtil.cpp +++ b/src/mpc-hc/CMPCThemeFrameUtil.cpp @@ -1,7 +1,7 @@ -#include "stdafx.h" -#include "CMPCThemeFrameUtil.h" - -CMPCThemeFrameUtil::CMPCThemeFrameUtil(CWnd* _self) -{ - self = _self; -} +#include "stdafx.h" +#include "CMPCThemeFrameUtil.h" + +CMPCThemeFrameUtil::CMPCThemeFrameUtil(CWnd* _self) +{ + self = _self; +} diff --git a/src/mpc-hc/CMPCThemeFrameUtil.h b/src/mpc-hc/CMPCThemeFrameUtil.h index 177a4b54a28..4b2aa15f13c 100644 --- a/src/mpc-hc/CMPCThemeFrameUtil.h +++ b/src/mpc-hc/CMPCThemeFrameUtil.h @@ -1,14 +1,14 @@ -#pragma once -#include "stdafx.h" -#include "CMPCTheme.h" -class CMPCThemeFrameUtil -{ - -public: - CWnd* self; - CMPCThemeFrameUtil(CWnd* self); - bool IsWindowForeground() { return self == self->GetActiveWindow(); }; - bool IsWindowZoomed() { return self->IsZoomed(); }; - BOOL PostWindowMessage(UINT Msg, WPARAM wParam, LPARAM lParam) { return self->PostMessage(Msg, wParam, lParam); }; -}; - +#pragma once +#include "stdafx.h" +#include "CMPCTheme.h" +class CMPCThemeFrameUtil +{ + +public: + CWnd* self; + CMPCThemeFrameUtil(CWnd* self); + bool IsWindowForeground() { return self == self->GetActiveWindow(); }; + bool IsWindowZoomed() { return self->IsZoomed(); }; + BOOL PostWindowMessage(UINT Msg, WPARAM wParam, LPARAM lParam) { return self->PostMessage(Msg, wParam, lParam); }; +}; + diff --git a/src/mpc-hc/CMPCThemeFrameWnd.cpp b/src/mpc-hc/CMPCThemeFrameWnd.cpp index 9df3e3ff8cc..04b256dc5d1 100644 --- a/src/mpc-hc/CMPCThemeFrameWnd.cpp +++ b/src/mpc-hc/CMPCThemeFrameWnd.cpp @@ -1,450 +1,450 @@ -//deprecated in favor of setWindowCompositionAttribute--undocumented Windows 10 API - -#include "stdafx.h" -#include "VersionHelpersInternal.h" -#include "CMPCThemeFrameWnd.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#include "SVGImage.h" -#include -#include <../src/mfc/oleimpl2.h> - -IMPLEMENT_DYNAMIC(CMPCThemeFrameWnd, CFrameWnd) - -BEGIN_MESSAGE_MAP(CMPCThemeFrameWnd, CFrameWnd) - ON_WM_CREATE() - ON_WM_ACTIVATE() - ON_WM_PAINT() - ON_WM_NCCALCSIZE() - ON_WM_SHOWWINDOW() - ON_WM_NCHITTEST() - ON_WM_NCMOUSELEAVE() -END_MESSAGE_MAP() - -CMPCThemeFrameWnd::CMPCThemeFrameWnd(): - CMPCThemeFrameUtil(this), - minimizeButton(SC_MINIMIZE), - maximizeButton(SC_MAXIMIZE), - closeButton(SC_CLOSE), - currentFrameState(frameNormal), - titleBarInfo( -{ - 0 -}), -drawCustomFrame(false), -titlebarHeight(30) //sane default, should be updated as soon as created -{ -} - -CMPCThemeFrameWnd::~CMPCThemeFrameWnd() -{ - if (closeButton.m_hWnd) { - closeButton.DestroyWindow(); - } - if (minimizeButton.m_hWnd) { - minimizeButton.DestroyWindow(); - } - if (maximizeButton.m_hWnd) { - maximizeButton.DestroyWindow(); - } -} - -LRESULT CMPCThemeFrameWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (drawCustomFrame) { - if (uMsg == WM_WINDOWPOSCHANGING && - (WS_THICKFRAME) == (GetStyle() & (WS_THICKFRAME | WS_CAPTION)) && - currentFrameState != frameThemedTopBorder) { - WINDOWPOS* wp = (WINDOWPOS*)lParam; - if (nullptr != wp) { - wp->flags |= SWP_NOREDRAW; //prevents corruption of the border when disabling caption - } - } - } - return __super::WindowProc(uMsg, wParam, lParam); -} - -void CMPCThemeFrameWnd::RecalcLayout(BOOL bNotify) -{ - if (drawCustomFrame) { - recalcTitleBar(); - int clientTop = 0; - if (currentFrameState == frameThemedCaption) { - CRect titleBarRect = getTitleBarRect(); - clientTop = titleBarRect.bottom; - if (GetMenuBarState() == AFX_MBS_VISIBLE) { - clientTop += GetSystemMetrics(SM_CYMENU); - } - - CRect sysMenuIconRect = getSysMenuIconRect(); - CRect closeRect, maximizeRect, minimizeRect; - GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); - - if (IsWindow(closeButton.m_hWnd)) { - closeButton.MoveWindow(closeRect, TRUE); - closeButton.ShowWindow(SW_SHOW); - } - if (IsWindow(minimizeButton.m_hWnd)) { - minimizeButton.MoveWindow(minimizeRect, TRUE); - minimizeButton.ShowWindow(SW_SHOW); - } - if (IsWindow(maximizeButton.m_hWnd)) { - maximizeButton.MoveWindow(maximizeRect, TRUE); - maximizeButton.ShowWindow(SW_SHOW); - } - } else { - m_rectBorder.top = borders.top; - if (IsWindow(closeButton.m_hWnd)) { - closeButton.ShowWindow(SW_HIDE); - } - if (IsWindow(minimizeButton.m_hWnd)) { - minimizeButton.ShowWindow(SW_HIDE); - } - if (IsWindow(maximizeButton.m_hWnd)) { - maximizeButton.ShowWindow(SW_HIDE); - } - } - - //begin standard CFrameWnd::RecalcLayout code - if (m_bInRecalcLayout) { - return; - } - - m_bInRecalcLayout = TRUE; - // clear idle flags for recalc layout if called elsewhere - if (m_nIdleFlags & idleNotify) { - bNotify = TRUE; - } - m_nIdleFlags &= ~(idleLayout | idleNotify); - - // call the layout hook -- OLE support uses this hook - if (bNotify && m_pNotifyHook != NULL) { - m_pNotifyHook->OnRecalcLayout(); - } - - // reposition all the child windows (regardless of ID) - if (GetStyle() & FWS_SNAPTOBARS) { - CRect rect(0, 0, 32767, 32767); - RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, - &rect, &rect, FALSE); - RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, - &m_rectBorder, &rect, TRUE); - CalcWindowRect(&rect); - SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); - } else { - //begin mpc-hc code to to position inside virtual client rect - CRect cr; - GetClientRect(cr); - cr.top = clientTop; - //end mpc-hc code to to position inside virtual client rect - RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder, &cr /* mpc-hc, pass virtual client rect */); - } - m_bInRecalcLayout = FALSE; - //end CFrameWnd::RecalcLayout code - - - Invalidate(TRUE); - RedrawWindow(); - } else { - __super::RecalcLayout(bNotify); - } -} - -void CMPCThemeFrameWnd::SetMenuBarVisibility(DWORD dwStyle) -{ - __super::SetMenuBarVisibility(dwStyle); - if (currentFrameState == frameThemedCaption && 0 != (dwStyle & AFX_MBS_VISIBLE)) { - Invalidate(); - DrawMenuBar(); - } -} - -BOOL CMPCThemeFrameWnd::SetMenuBarState(DWORD dwState) -{ - BOOL ret = __super::SetMenuBarState(dwState); - if (ret && currentFrameState == frameThemedCaption) { - RecalcLayout(); - DrawMenuBar(); - } - return ret; -} - -CRect CMPCThemeFrameWnd::getTitleBarRect() -{ - CRect cr; - GetClientRect(cr); - CRect wr; - GetClientRect(wr); - - if (IsZoomed()) { - cr.top += borders.top + 1; //invisible area when maximized - cr.bottom = cr.top + titlebarHeight; - } else { - cr.top += 1; //border - cr.bottom = cr.top + titlebarHeight; - } - return cr; -} - -CRect CMPCThemeFrameWnd::getSysMenuIconRect() -{ - CRect sysMenuIconRect, cr; - cr = getTitleBarRect(); - - DpiHelper dpiWindow; - dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); - int iconsize = MulDiv(dpiWindow.DPIX(), 1, 6); - sysMenuIconRect.top = cr.top + (cr.Height() - iconsize) / 2 + 1; - sysMenuIconRect.bottom = sysMenuIconRect.top + iconsize; - sysMenuIconRect.left = (dpiWindow.ScaleX(30) - iconsize) / 2 + 1; - sysMenuIconRect.right = sysMenuIconRect.left + iconsize; - return sysMenuIconRect; -} - -bool CMPCThemeFrameWnd::checkFrame(LONG style) -{ - frameState oldState = currentFrameState; - currentFrameState = frameNormal; - if (drawCustomFrame) { - if ((WS_THICKFRAME | WS_CAPTION) == (style & (WS_THICKFRAME | WS_CAPTION))) { - currentFrameState = frameThemedCaption; - } else if ((WS_THICKFRAME) == (style & (WS_THICKFRAME | WS_CAPTION))) { - currentFrameState = frameThemedTopBorder; - } - } - return (oldState == currentFrameState); -} - -int CMPCThemeFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (drawCustomFrame) { - int res = CWnd::OnCreate(lpCreateStruct); - - if (res == -1) { - return -1; - } - - RECT r = { 0, 0, 0, 0 }; - - closeButton.Create(_T("Close Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1001); - closeButton.setParentFrame(this); - - minimizeButton.Create(_T("Minimize Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1002); - minimizeButton.setParentFrame(this); - - maximizeButton.Create(_T("Maximize Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1003); - maximizeButton.setParentFrame(this); - - return res; - } else { - return __super::OnCreate(lpCreateStruct); - } -} - -void CMPCThemeFrameWnd::GetIconRects(CRect titlebarRect, CRect& closeRect, CRect& maximizeRect, CRect& minimizeRect) -{ - DpiHelper dpi; - dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); - - int closeRightX; - if (IsZoomed()) { - closeRightX = titlebarRect.right - 2; - } else { - closeRightX = titlebarRect.right; - } - - int iconHeight; - if (IsZoomed()) { //works at 96dpi, 120dpi, 144dpi, 168dpi, 192dpi - iconHeight = titlebarRect.Height() - 2; - } else { - iconHeight = titlebarRect.Height() - 1; - } - int buttonWidth = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarButtonWidth); - int buttonSpacing = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarButtonSpacing); - CRect buttonDimRect(0, 0, buttonWidth, iconHeight); - closeRect = CRect(closeRightX - buttonDimRect.Width(), titlebarRect.top, closeRightX, titlebarRect.top + buttonDimRect.Height()); - maximizeRect = CRect(closeRect.left - buttonSpacing - buttonDimRect.Width(), titlebarRect.top, closeRect.left - buttonSpacing, titlebarRect.top + buttonDimRect.Height()); - minimizeRect = CRect(maximizeRect.left - buttonSpacing - buttonDimRect.Width(), titlebarRect.top, maximizeRect.left - buttonSpacing, titlebarRect.top + buttonDimRect.Height()); -} - -void CMPCThemeFrameWnd::OnPaint() -{ - if (currentFrameState != frameNormal) { - CRect closeRect, maximizeRect, minimizeRect; - CRect titleBarRect = getTitleBarRect(); - GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); - - CPaintDC dc(this); - - CDC dcMem; - CBitmap bmMem; - CRect memRect = { 0, 0, titleBarRect.right, titleBarRect.bottom }; - CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, memRect); - - CRect topBorderRect = { titleBarRect.left, titleBarRect.top - 1, titleBarRect.right, titleBarRect.top }; - dcMem.FillSolidRect(topBorderRect, CMPCTheme::W10DarkThemeWindowBorderColor); - - COLORREF titleBarColor; - if (IsWindowForeground()) { - titleBarColor = CMPCTheme::W10DarkThemeTitlebarBGColor; - } else { - titleBarColor = CMPCTheme::W10DarkThemeTitlebarInactiveBGColor; - } - - - dcMem.FillSolidRect(titleBarRect, titleBarColor); - - if (currentFrameState == frameThemedCaption) { - - CFont f; - CMPCThemeUtil::getFontByType(f, this, CMPCThemeUtil::CaptionFont); - dcMem.SelectObject(f); - - CRect captionRect = titleBarRect; - DpiHelper dpi; - dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); - - CRect sysMenuIconRect = getSysMenuIconRect(); - int sysIconDim = sysMenuIconRect.Width(); - - captionRect.left += sysMenuIconRect.right + dpi.ScaleX(4); - captionRect.right = minimizeRect.left - dpi.ScaleX(4); - - CFont font; - CMPCThemeUtil::getFontByType(font, this, CMPCThemeUtil::CaptionFont); - dcMem.SetBkColor(titleBarColor); - dcMem.SetTextColor(CMPCTheme::W10DarkThemeTitlebarFGColor); - CString windowText; - GetWindowText(windowText); - dcMem.DrawTextW(windowText, captionRect, DT_LEFT | DT_WORD_ELLIPSIS | DT_VCENTER | DT_SINGLELINE); - - HICON icon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(m_nIDHelp), IMAGE_ICON, sysIconDim, sysIconDim, LR_SHARED); - ::DrawIconEx(dcMem.m_hDC, sysMenuIconRect.left, sysMenuIconRect.top, icon, 0, 0, 0, nullptr, DI_NORMAL); - } - - CMPCThemeUtil::flushMemDC(&dc, dcMem, memRect); - - if (m_pCtrlCont != NULL) { - m_pCtrlCont->OnPaint(&dc); - } - Default(); - } else { - Default(); - } - -} - -void CMPCThemeFrameWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) -{ - if (AppIsThemeLoaded() && IsWindows10OrGreater() && !AfxGetAppSettings().bWindows10AccentColorsEnabled) { - drawCustomFrame = true; - } else { - drawCustomFrame = false; - } - - if (drawCustomFrame) { - if (currentFrameState != frameNormal) { - if (bCalcValidRects) { - if (currentFrameState == frameThemedCaption) { - lpncsp->rgrc[0].left += borders.left + 1; - lpncsp->rgrc[0].right -= borders.right + 1; - lpncsp->rgrc[0].bottom -= borders.bottom + 1; - } else { - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - lpncsp->rgrc[0].top -= 6; - } - } else { - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - } - } else { - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - } - recalcFrame(); //framechanged--if necessary we recalculate everything; if done internally this should be a no-op - } else { - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - } -} - -void CMPCThemeFrameWnd::recalcFrame() -{ - if (!checkFrame(GetStyle())) { - borders = { 0, 0, 0, 0 }; - UINT style = GetStyle(); - if (0 != (style & WS_THICKFRAME)) { - AdjustWindowRectEx(&borders, style & ~WS_CAPTION, FALSE, NULL); - borders.left = abs(borders.left); - borders.top = abs(borders.top); - } else if (0 != (style & WS_BORDER)) { - borders = { 1, 1, 1, 1 }; - } - SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); - } -} - -void CMPCThemeFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) -{ - if (drawCustomFrame) { - if (titleBarInfo.cbSize == 0) { //only check this once, as it can be wrong later - titleBarInfo = { sizeof(TITLEBARINFO) }; - GetTitleBarInfo(&titleBarInfo); - } - recalcFrame(); - CWnd::OnActivate(nState, pWndOther, bMinimized); - Invalidate(TRUE); - } else { - __super::OnActivate(nState, pWndOther, bMinimized); - } -} - -LRESULT CMPCThemeFrameWnd::OnNcHitTest(CPoint point) -{ - if (currentFrameState == frameThemedCaption) { - LRESULT result = 0; - - result = CWnd::OnNcHitTest(point); - if (result == HTCLIENT) { - ScreenToClient(&point); - if (point.y < borders.top) { - return HTTOP; - } else if (point.y < titlebarHeight) { - CRect sysMenuIconRect = getSysMenuIconRect(); - CRect closeRect, maximizeRect, minimizeRect; - CRect titleBarRect = getTitleBarRect(); - GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); - - if (sysMenuIconRect.PtInRect(point)) { - return HTSYSMENU; - } else if (closeRect.PtInRect(point) || minimizeRect.PtInRect(point) || maximizeRect.PtInRect(point)) { - return HTNOWHERE; - } else { - return HTCAPTION; - } - } else if (point.y < titlebarHeight + GetSystemMetrics(SM_CYMENU)) { - return HTMENU; - } - } - return result; - } else { - return __super::OnNcHitTest(point); - } -} - -void CMPCThemeFrameWnd::OnNcMouseLeave() -{ - if (currentFrameState == frameThemedCaption) { - CWnd::OnNcMouseLeave(); - } else { - __super::OnNcMouseLeave(); - } -} - -void CMPCThemeFrameWnd::recalcTitleBar() -{ - titlebarHeight = CRect(titleBarInfo.rcTitleBar).Height() + borders.top; - if (IsZoomed()) { - titlebarHeight -= borders.top; - } -} - +//deprecated in favor of setWindowCompositionAttribute--undocumented Windows 10 API + +#include "stdafx.h" +#include "VersionHelpersInternal.h" +#include "CMPCThemeFrameWnd.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#include "SVGImage.h" +#include +#include <../src/mfc/oleimpl2.h> + +IMPLEMENT_DYNAMIC(CMPCThemeFrameWnd, CFrameWnd) + +BEGIN_MESSAGE_MAP(CMPCThemeFrameWnd, CFrameWnd) + ON_WM_CREATE() + ON_WM_ACTIVATE() + ON_WM_PAINT() + ON_WM_NCCALCSIZE() + ON_WM_SHOWWINDOW() + ON_WM_NCHITTEST() + ON_WM_NCMOUSELEAVE() +END_MESSAGE_MAP() + +CMPCThemeFrameWnd::CMPCThemeFrameWnd(): + CMPCThemeFrameUtil(this), + minimizeButton(SC_MINIMIZE), + maximizeButton(SC_MAXIMIZE), + closeButton(SC_CLOSE), + currentFrameState(frameNormal), + titleBarInfo( +{ + 0 +}), +drawCustomFrame(false), +titlebarHeight(30) //sane default, should be updated as soon as created +{ +} + +CMPCThemeFrameWnd::~CMPCThemeFrameWnd() +{ + if (closeButton.m_hWnd) { + closeButton.DestroyWindow(); + } + if (minimizeButton.m_hWnd) { + minimizeButton.DestroyWindow(); + } + if (maximizeButton.m_hWnd) { + maximizeButton.DestroyWindow(); + } +} + +LRESULT CMPCThemeFrameWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (drawCustomFrame) { + if (uMsg == WM_WINDOWPOSCHANGING && + (WS_THICKFRAME) == (GetStyle() & (WS_THICKFRAME | WS_CAPTION)) && + currentFrameState != frameThemedTopBorder) { + WINDOWPOS* wp = (WINDOWPOS*)lParam; + if (nullptr != wp) { + wp->flags |= SWP_NOREDRAW; //prevents corruption of the border when disabling caption + } + } + } + return __super::WindowProc(uMsg, wParam, lParam); +} + +void CMPCThemeFrameWnd::RecalcLayout(BOOL bNotify) +{ + if (drawCustomFrame) { + recalcTitleBar(); + int clientTop = 0; + if (currentFrameState == frameThemedCaption) { + CRect titleBarRect = getTitleBarRect(); + clientTop = titleBarRect.bottom; + if (GetMenuBarState() == AFX_MBS_VISIBLE) { + clientTop += GetSystemMetrics(SM_CYMENU); + } + + CRect sysMenuIconRect = getSysMenuIconRect(); + CRect closeRect, maximizeRect, minimizeRect; + GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); + + if (IsWindow(closeButton.m_hWnd)) { + closeButton.MoveWindow(closeRect, TRUE); + closeButton.ShowWindow(SW_SHOW); + } + if (IsWindow(minimizeButton.m_hWnd)) { + minimizeButton.MoveWindow(minimizeRect, TRUE); + minimizeButton.ShowWindow(SW_SHOW); + } + if (IsWindow(maximizeButton.m_hWnd)) { + maximizeButton.MoveWindow(maximizeRect, TRUE); + maximizeButton.ShowWindow(SW_SHOW); + } + } else { + m_rectBorder.top = borders.top; + if (IsWindow(closeButton.m_hWnd)) { + closeButton.ShowWindow(SW_HIDE); + } + if (IsWindow(minimizeButton.m_hWnd)) { + minimizeButton.ShowWindow(SW_HIDE); + } + if (IsWindow(maximizeButton.m_hWnd)) { + maximizeButton.ShowWindow(SW_HIDE); + } + } + + //begin standard CFrameWnd::RecalcLayout code + if (m_bInRecalcLayout) { + return; + } + + m_bInRecalcLayout = TRUE; + // clear idle flags for recalc layout if called elsewhere + if (m_nIdleFlags & idleNotify) { + bNotify = TRUE; + } + m_nIdleFlags &= ~(idleLayout | idleNotify); + + // call the layout hook -- OLE support uses this hook + if (bNotify && m_pNotifyHook != NULL) { + m_pNotifyHook->OnRecalcLayout(); + } + + // reposition all the child windows (regardless of ID) + if (GetStyle() & FWS_SNAPTOBARS) { + CRect rect(0, 0, 32767, 32767); + RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, + &rect, &rect, FALSE); + RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, + &m_rectBorder, &rect, TRUE); + CalcWindowRect(&rect); + SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); + } else { + //begin mpc-hc code to to position inside virtual client rect + CRect cr; + GetClientRect(cr); + cr.top = clientTop; + //end mpc-hc code to to position inside virtual client rect + RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder, &cr /* mpc-hc, pass virtual client rect */); + } + m_bInRecalcLayout = FALSE; + //end CFrameWnd::RecalcLayout code + + + Invalidate(TRUE); + RedrawWindow(); + } else { + __super::RecalcLayout(bNotify); + } +} + +void CMPCThemeFrameWnd::SetMenuBarVisibility(DWORD dwStyle) +{ + __super::SetMenuBarVisibility(dwStyle); + if (currentFrameState == frameThemedCaption && 0 != (dwStyle & AFX_MBS_VISIBLE)) { + Invalidate(); + DrawMenuBar(); + } +} + +BOOL CMPCThemeFrameWnd::SetMenuBarState(DWORD dwState) +{ + BOOL ret = __super::SetMenuBarState(dwState); + if (ret && currentFrameState == frameThemedCaption) { + RecalcLayout(); + DrawMenuBar(); + } + return ret; +} + +CRect CMPCThemeFrameWnd::getTitleBarRect() +{ + CRect cr; + GetClientRect(cr); + CRect wr; + GetClientRect(wr); + + if (IsZoomed()) { + cr.top += borders.top + 1; //invisible area when maximized + cr.bottom = cr.top + titlebarHeight; + } else { + cr.top += 1; //border + cr.bottom = cr.top + titlebarHeight; + } + return cr; +} + +CRect CMPCThemeFrameWnd::getSysMenuIconRect() +{ + CRect sysMenuIconRect, cr; + cr = getTitleBarRect(); + + DpiHelper dpiWindow; + dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); + int iconsize = MulDiv(dpiWindow.DPIX(), 1, 6); + sysMenuIconRect.top = cr.top + (cr.Height() - iconsize) / 2 + 1; + sysMenuIconRect.bottom = sysMenuIconRect.top + iconsize; + sysMenuIconRect.left = (dpiWindow.ScaleX(30) - iconsize) / 2 + 1; + sysMenuIconRect.right = sysMenuIconRect.left + iconsize; + return sysMenuIconRect; +} + +bool CMPCThemeFrameWnd::checkFrame(LONG style) +{ + frameState oldState = currentFrameState; + currentFrameState = frameNormal; + if (drawCustomFrame) { + if ((WS_THICKFRAME | WS_CAPTION) == (style & (WS_THICKFRAME | WS_CAPTION))) { + currentFrameState = frameThemedCaption; + } else if ((WS_THICKFRAME) == (style & (WS_THICKFRAME | WS_CAPTION))) { + currentFrameState = frameThemedTopBorder; + } + } + return (oldState == currentFrameState); +} + +int CMPCThemeFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (drawCustomFrame) { + int res = CWnd::OnCreate(lpCreateStruct); + + if (res == -1) { + return -1; + } + + RECT r = { 0, 0, 0, 0 }; + + closeButton.Create(_T("Close Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1001); + closeButton.setParentFrame(this); + + minimizeButton.Create(_T("Minimize Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1002); + minimizeButton.setParentFrame(this); + + maximizeButton.Create(_T("Maximize Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1003); + maximizeButton.setParentFrame(this); + + return res; + } else { + return __super::OnCreate(lpCreateStruct); + } +} + +void CMPCThemeFrameWnd::GetIconRects(CRect titlebarRect, CRect& closeRect, CRect& maximizeRect, CRect& minimizeRect) +{ + DpiHelper dpi; + dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); + + int closeRightX; + if (IsZoomed()) { + closeRightX = titlebarRect.right - 2; + } else { + closeRightX = titlebarRect.right; + } + + int iconHeight; + if (IsZoomed()) { //works at 96dpi, 120dpi, 144dpi, 168dpi, 192dpi + iconHeight = titlebarRect.Height() - 2; + } else { + iconHeight = titlebarRect.Height() - 1; + } + int buttonWidth = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarButtonWidth); + int buttonSpacing = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarButtonSpacing); + CRect buttonDimRect(0, 0, buttonWidth, iconHeight); + closeRect = CRect(closeRightX - buttonDimRect.Width(), titlebarRect.top, closeRightX, titlebarRect.top + buttonDimRect.Height()); + maximizeRect = CRect(closeRect.left - buttonSpacing - buttonDimRect.Width(), titlebarRect.top, closeRect.left - buttonSpacing, titlebarRect.top + buttonDimRect.Height()); + minimizeRect = CRect(maximizeRect.left - buttonSpacing - buttonDimRect.Width(), titlebarRect.top, maximizeRect.left - buttonSpacing, titlebarRect.top + buttonDimRect.Height()); +} + +void CMPCThemeFrameWnd::OnPaint() +{ + if (currentFrameState != frameNormal) { + CRect closeRect, maximizeRect, minimizeRect; + CRect titleBarRect = getTitleBarRect(); + GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); + + CPaintDC dc(this); + + CDC dcMem; + CBitmap bmMem; + CRect memRect = { 0, 0, titleBarRect.right, titleBarRect.bottom }; + CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, memRect); + + CRect topBorderRect = { titleBarRect.left, titleBarRect.top - 1, titleBarRect.right, titleBarRect.top }; + dcMem.FillSolidRect(topBorderRect, CMPCTheme::W10DarkThemeWindowBorderColor); + + COLORREF titleBarColor; + if (IsWindowForeground()) { + titleBarColor = CMPCTheme::W10DarkThemeTitlebarBGColor; + } else { + titleBarColor = CMPCTheme::W10DarkThemeTitlebarInactiveBGColor; + } + + + dcMem.FillSolidRect(titleBarRect, titleBarColor); + + if (currentFrameState == frameThemedCaption) { + + CFont f; + CMPCThemeUtil::getFontByType(f, this, CMPCThemeUtil::CaptionFont); + dcMem.SelectObject(f); + + CRect captionRect = titleBarRect; + DpiHelper dpi; + dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); + + CRect sysMenuIconRect = getSysMenuIconRect(); + int sysIconDim = sysMenuIconRect.Width(); + + captionRect.left += sysMenuIconRect.right + dpi.ScaleX(4); + captionRect.right = minimizeRect.left - dpi.ScaleX(4); + + CFont font; + CMPCThemeUtil::getFontByType(font, this, CMPCThemeUtil::CaptionFont); + dcMem.SetBkColor(titleBarColor); + dcMem.SetTextColor(CMPCTheme::W10DarkThemeTitlebarFGColor); + CString windowText; + GetWindowText(windowText); + dcMem.DrawTextW(windowText, captionRect, DT_LEFT | DT_WORD_ELLIPSIS | DT_VCENTER | DT_SINGLELINE); + + HICON icon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(m_nIDHelp), IMAGE_ICON, sysIconDim, sysIconDim, LR_SHARED); + ::DrawIconEx(dcMem.m_hDC, sysMenuIconRect.left, sysMenuIconRect.top, icon, 0, 0, 0, nullptr, DI_NORMAL); + } + + CMPCThemeUtil::flushMemDC(&dc, dcMem, memRect); + + if (m_pCtrlCont != NULL) { + m_pCtrlCont->OnPaint(&dc); + } + Default(); + } else { + Default(); + } + +} + +void CMPCThemeFrameWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) +{ + if (AppIsThemeLoaded() && IsWindows10OrGreater() && !AfxGetAppSettings().bWindows10AccentColorsEnabled) { + drawCustomFrame = true; + } else { + drawCustomFrame = false; + } + + if (drawCustomFrame) { + if (currentFrameState != frameNormal) { + if (bCalcValidRects) { + if (currentFrameState == frameThemedCaption) { + lpncsp->rgrc[0].left += borders.left + 1; + lpncsp->rgrc[0].right -= borders.right + 1; + lpncsp->rgrc[0].bottom -= borders.bottom + 1; + } else { + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + lpncsp->rgrc[0].top -= 6; + } + } else { + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + } + } else { + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + } + recalcFrame(); //framechanged--if necessary we recalculate everything; if done internally this should be a no-op + } else { + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + } +} + +void CMPCThemeFrameWnd::recalcFrame() +{ + if (!checkFrame(GetStyle())) { + borders = { 0, 0, 0, 0 }; + UINT style = GetStyle(); + if (0 != (style & WS_THICKFRAME)) { + AdjustWindowRectEx(&borders, style & ~WS_CAPTION, FALSE, NULL); + borders.left = abs(borders.left); + borders.top = abs(borders.top); + } else if (0 != (style & WS_BORDER)) { + borders = { 1, 1, 1, 1 }; + } + SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + } +} + +void CMPCThemeFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) +{ + if (drawCustomFrame) { + if (titleBarInfo.cbSize == 0) { //only check this once, as it can be wrong later + titleBarInfo = { sizeof(TITLEBARINFO) }; + GetTitleBarInfo(&titleBarInfo); + } + recalcFrame(); + CWnd::OnActivate(nState, pWndOther, bMinimized); + Invalidate(TRUE); + } else { + __super::OnActivate(nState, pWndOther, bMinimized); + } +} + +LRESULT CMPCThemeFrameWnd::OnNcHitTest(CPoint point) +{ + if (currentFrameState == frameThemedCaption) { + LRESULT result = 0; + + result = CWnd::OnNcHitTest(point); + if (result == HTCLIENT) { + ScreenToClient(&point); + if (point.y < borders.top) { + return HTTOP; + } else if (point.y < titlebarHeight) { + CRect sysMenuIconRect = getSysMenuIconRect(); + CRect closeRect, maximizeRect, minimizeRect; + CRect titleBarRect = getTitleBarRect(); + GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); + + if (sysMenuIconRect.PtInRect(point)) { + return HTSYSMENU; + } else if (closeRect.PtInRect(point) || minimizeRect.PtInRect(point) || maximizeRect.PtInRect(point)) { + return HTNOWHERE; + } else { + return HTCAPTION; + } + } else if (point.y < titlebarHeight + GetSystemMetrics(SM_CYMENU)) { + return HTMENU; + } + } + return result; + } else { + return __super::OnNcHitTest(point); + } +} + +void CMPCThemeFrameWnd::OnNcMouseLeave() +{ + if (currentFrameState == frameThemedCaption) { + CWnd::OnNcMouseLeave(); + } else { + __super::OnNcMouseLeave(); + } +} + +void CMPCThemeFrameWnd::recalcTitleBar() +{ + titlebarHeight = CRect(titleBarInfo.rcTitleBar).Height() + borders.top; + if (IsZoomed()) { + titlebarHeight -= borders.top; + } +} + diff --git a/src/mpc-hc/CMPCThemeFrameWnd.h b/src/mpc-hc/CMPCThemeFrameWnd.h index ebe50a48747..e6a47a44acc 100644 --- a/src/mpc-hc/CMPCThemeFrameWnd.h +++ b/src/mpc-hc/CMPCThemeFrameWnd.h @@ -1,49 +1,49 @@ -#pragma once -#include -#include "CMPCTheme.h" -#include "CMPCThemeFrameUtil.h" -#include "CMPCThemeTitleBarControlButton.h" - -class CMPCThemeFrameWnd : - public CFrameWnd, - public CMPCThemeFrameUtil -{ -public: - CMPCThemeFrameWnd(); -protected: - DECLARE_DYNAMIC(CMPCThemeFrameWnd) -public: - virtual ~CMPCThemeFrameWnd(); - LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); - virtual void RecalcLayout(BOOL bNotify = TRUE); - virtual void SetMenuBarVisibility(DWORD dwStyle); - BOOL SetMenuBarState(DWORD dwState); - CRect getTitleBarRect(); - CRect getSysMenuIconRect(); -protected: - CRect borders; - int titlebarHeight; - void recalcTitleBar(); - CMPCThemeTitleBarControlButton minimizeButton, maximizeButton, closeButton; - void GetIconRects(CRect titlebarRect, CRect& closeRect, CRect& maximizeRect, CRect& minimizeRect); - bool checkFrame(LONG style); - void recalcFrame(); - enum frameState { - frameNormal, - frameThemedCaption, - frameThemedTopBorder, - }; -private: - TITLEBARINFO titleBarInfo; - frameState currentFrameState; - bool drawCustomFrame; -public: - DECLARE_MESSAGE_MAP() - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); - afx_msg void OnPaint(); - afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg void OnNcMouseLeave(); -}; - +#pragma once +#include +#include "CMPCTheme.h" +#include "CMPCThemeFrameUtil.h" +#include "CMPCThemeTitleBarControlButton.h" + +class CMPCThemeFrameWnd : + public CFrameWnd, + public CMPCThemeFrameUtil +{ +public: + CMPCThemeFrameWnd(); +protected: + DECLARE_DYNAMIC(CMPCThemeFrameWnd) +public: + virtual ~CMPCThemeFrameWnd(); + LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + virtual void RecalcLayout(BOOL bNotify = TRUE); + virtual void SetMenuBarVisibility(DWORD dwStyle); + BOOL SetMenuBarState(DWORD dwState); + CRect getTitleBarRect(); + CRect getSysMenuIconRect(); +protected: + CRect borders; + int titlebarHeight; + void recalcTitleBar(); + CMPCThemeTitleBarControlButton minimizeButton, maximizeButton, closeButton; + void GetIconRects(CRect titlebarRect, CRect& closeRect, CRect& maximizeRect, CRect& minimizeRect); + bool checkFrame(LONG style); + void recalcFrame(); + enum frameState { + frameNormal, + frameThemedCaption, + frameThemedTopBorder, + }; +private: + TITLEBARINFO titleBarInfo; + frameState currentFrameState; + bool drawCustomFrame; +public: + DECLARE_MESSAGE_MAP() + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); + afx_msg void OnPaint(); + afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg void OnNcMouseLeave(); +}; + diff --git a/src/mpc-hc/CMPCThemeGroupBox.cpp b/src/mpc-hc/CMPCThemeGroupBox.cpp index 60af3e65c99..b8f58744eb5 100644 --- a/src/mpc-hc/CMPCThemeGroupBox.cpp +++ b/src/mpc-hc/CMPCThemeGroupBox.cpp @@ -1,106 +1,106 @@ -#include "stdafx.h" -#include "CMPCThemeGroupBox.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -IMPLEMENT_DYNAMIC(CMPCThemeGroupBox, CStatic) - -CMPCThemeGroupBox::CMPCThemeGroupBox() - :manuallySetFont(nullptr) -{ - -} - - -CMPCThemeGroupBox::~CMPCThemeGroupBox() -{ -} - -BEGIN_MESSAGE_MAP(CMPCThemeGroupBox, CStatic) - ON_WM_PAINT() - ON_WM_ENABLE() - ON_MESSAGE(WM_SETFONT, OnSetFont) - ON_MESSAGE(WM_GETFONT, OnGetFont) -END_MESSAGE_MAP() - - -void CMPCThemeGroupBox::OnPaint() -{ - if (AppNeedsThemedControls()) { - - CPaintDC dc(this); - - CRect r, rborder, rtext; - GetClientRect(r); - HDC hDC = ::GetDC(NULL); - CString text; - GetWindowText(text); - - CFont* font = GetFont(); - - CSize cs = CMPCThemeUtil::GetTextSize(_T("W"), hDC, font); - ::ReleaseDC(NULL, hDC); - - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::GroupBoxBorderColor); - rborder = r; - rborder.top += cs.cy / 2; - dc.FrameRect(rborder, &fb); - - if (!text.IsEmpty()) { - COLORREF oldClr; - //see https://stackoverflow.com/questions/26481189/how-to-make-the-group-box-text-to-be-disabled-when-group-box-is-disabled - //even if common controls doesn't always honor disabled group boxes, we can in the themed version - if (IsWindowEnabled()) { - oldClr = dc.SetTextColor(CMPCTheme::TextFGColor); - } else { - oldClr = dc.SetTextColor(CMPCTheme::ContentTextDisabledFGColorFade); - } - COLORREF oldBkClr = dc.SetBkColor(CMPCTheme::WindowBGColor); - CFont* pOldFont = dc.SelectObject(font); - - rtext = r; - rtext.left += CMPCTheme::GroupBoxTextIndent; - - text += _T(" "); //seems to be the default behavior - dc.DrawTextW(text, rtext, DT_TOP | DT_LEFT | DT_SINGLELINE | DT_EDITCONTROL); // DT_NOPREFIX not needed - - dc.SelectObject(pOldFont); - dc.SetTextColor(oldClr); - dc.SetBkColor(oldBkClr); - } - fb.DeleteObject(); - ::ReleaseDC(NULL, hDC); - } else { - __super::OnPaint(); - } -} - -void CMPCThemeGroupBox::OnEnable(BOOL bEnable) { - if (AppNeedsThemedControls()) { - SetRedraw(FALSE); - __super::OnEnable(bEnable); - SetRedraw(TRUE); - Invalidate(); //WM_PAINT not handled when enabling/disabling - RedrawWindow(); - } else { - __super::OnEnable(bEnable); - } -} - -LRESULT CMPCThemeGroupBox::OnSetFont(WPARAM wParam, LPARAM lParam) { - manuallySetFont = (HFONT)wParam; - if ((BOOL)lParam) { - Invalidate(); - } - return 0; -} - -LRESULT CMPCThemeGroupBox::OnGetFont(WPARAM wParam, LPARAM lParam) { - if (manuallySetFont) { - return (LRESULT)manuallySetFont; - } else { - return (LRESULT)Default(); - } -} +#include "stdafx.h" +#include "CMPCThemeGroupBox.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +IMPLEMENT_DYNAMIC(CMPCThemeGroupBox, CStatic) + +CMPCThemeGroupBox::CMPCThemeGroupBox() + :manuallySetFont(nullptr) +{ + +} + + +CMPCThemeGroupBox::~CMPCThemeGroupBox() +{ +} + +BEGIN_MESSAGE_MAP(CMPCThemeGroupBox, CStatic) + ON_WM_PAINT() + ON_WM_ENABLE() + ON_MESSAGE(WM_SETFONT, OnSetFont) + ON_MESSAGE(WM_GETFONT, OnGetFont) +END_MESSAGE_MAP() + + +void CMPCThemeGroupBox::OnPaint() +{ + if (AppNeedsThemedControls()) { + + CPaintDC dc(this); + + CRect r, rborder, rtext; + GetClientRect(r); + HDC hDC = ::GetDC(NULL); + CString text; + GetWindowText(text); + + CFont* font = GetFont(); + + CSize cs = CMPCThemeUtil::GetTextSize(_T("W"), hDC, font); + ::ReleaseDC(NULL, hDC); + + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::GroupBoxBorderColor); + rborder = r; + rborder.top += cs.cy / 2; + dc.FrameRect(rborder, &fb); + + if (!text.IsEmpty()) { + COLORREF oldClr; + //see https://stackoverflow.com/questions/26481189/how-to-make-the-group-box-text-to-be-disabled-when-group-box-is-disabled + //even if common controls doesn't always honor disabled group boxes, we can in the themed version + if (IsWindowEnabled()) { + oldClr = dc.SetTextColor(CMPCTheme::TextFGColor); + } else { + oldClr = dc.SetTextColor(CMPCTheme::ContentTextDisabledFGColorFade); + } + COLORREF oldBkClr = dc.SetBkColor(CMPCTheme::WindowBGColor); + CFont* pOldFont = dc.SelectObject(font); + + rtext = r; + rtext.left += CMPCTheme::GroupBoxTextIndent; + + text += _T(" "); //seems to be the default behavior + dc.DrawTextW(text, rtext, DT_TOP | DT_LEFT | DT_SINGLELINE | DT_EDITCONTROL); // DT_NOPREFIX not needed + + dc.SelectObject(pOldFont); + dc.SetTextColor(oldClr); + dc.SetBkColor(oldBkClr); + } + fb.DeleteObject(); + ::ReleaseDC(NULL, hDC); + } else { + __super::OnPaint(); + } +} + +void CMPCThemeGroupBox::OnEnable(BOOL bEnable) { + if (AppNeedsThemedControls()) { + SetRedraw(FALSE); + __super::OnEnable(bEnable); + SetRedraw(TRUE); + Invalidate(); //WM_PAINT not handled when enabling/disabling + RedrawWindow(); + } else { + __super::OnEnable(bEnable); + } +} + +LRESULT CMPCThemeGroupBox::OnSetFont(WPARAM wParam, LPARAM lParam) { + manuallySetFont = (HFONT)wParam; + if ((BOOL)lParam) { + Invalidate(); + } + return 0; +} + +LRESULT CMPCThemeGroupBox::OnGetFont(WPARAM wParam, LPARAM lParam) { + if (manuallySetFont) { + return (LRESULT)manuallySetFont; + } else { + return (LRESULT)Default(); + } +} diff --git a/src/mpc-hc/CMPCThemeGroupBox.h b/src/mpc-hc/CMPCThemeGroupBox.h index cee7657b01c..14759011dff 100755 --- a/src/mpc-hc/CMPCThemeGroupBox.h +++ b/src/mpc-hc/CMPCThemeGroupBox.h @@ -1,18 +1,18 @@ -#pragma once -#include -class CMPCThemeGroupBox : public CStatic -{ - DECLARE_DYNAMIC(CMPCThemeGroupBox) -public: - CMPCThemeGroupBox(); - virtual ~CMPCThemeGroupBox(); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg void OnEnable(BOOL bEnable); - //CStatic does not implement WM_SETFONT. Needed for manually created GroupBox - afx_msg LRESULT OnSetFont(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnGetFont(WPARAM wParam, LPARAM lParam); -protected: - HFONT manuallySetFont; -}; - +#pragma once +#include +class CMPCThemeGroupBox : public CStatic +{ + DECLARE_DYNAMIC(CMPCThemeGroupBox) +public: + CMPCThemeGroupBox(); + virtual ~CMPCThemeGroupBox(); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg void OnEnable(BOOL bEnable); + //CStatic does not implement WM_SETFONT. Needed for manually created GroupBox + afx_msg LRESULT OnSetFont(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnGetFont(WPARAM wParam, LPARAM lParam); +protected: + HFONT manuallySetFont; +}; + diff --git a/src/mpc-hc/CMPCThemeHeaderCtrl.cpp b/src/mpc-hc/CMPCThemeHeaderCtrl.cpp index 60fee2c0431..4c93f79dfe7 100755 --- a/src/mpc-hc/CMPCThemeHeaderCtrl.cpp +++ b/src/mpc-hc/CMPCThemeHeaderCtrl.cpp @@ -1,272 +1,272 @@ -#include "stdafx.h" -#include "CMPCThemeHeaderCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "DpiHelper.h" -#include "mplayerc.h" - -CMPCThemeHeaderCtrl::CMPCThemeHeaderCtrl() -{ - hotItem = -2; -} - - -CMPCThemeHeaderCtrl::~CMPCThemeHeaderCtrl() -{ -} -BEGIN_MESSAGE_MAP(CMPCThemeHeaderCtrl, CHeaderCtrl) - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeHeaderCtrl::OnNMCustomdraw) - ON_NOTIFY(HDN_TRACKA, 0, &CMPCThemeHeaderCtrl::OnHdnTrack) - ON_NOTIFY(HDN_TRACKW, 0, &CMPCThemeHeaderCtrl::OnHdnTrack) - ON_WM_MOUSEMOVE() - ON_WM_MOUSELEAVE() - ON_WM_PAINT() -END_MESSAGE_MAP() - -void CMPCThemeHeaderCtrl::drawSortArrow(CDC* dc, COLORREF arrowClr, CRect arrowRect, bool ascending) -{ - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - Gdiplus::Color clr; - clr.SetFromCOLORREF(arrowClr); - - int dpi = dpiWindow.DPIX(); - float steps; - - if (dpi < 120) { - steps = 3.5; - } else if (dpi < 144) { - steps = 4; - } else if (dpi < 168) { - steps = 5; - } else if (dpi < 192) { - steps = 5; - } else { - steps = 6; - } - - int xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - int yPos = arrowRect.top; - - Gdiplus::Graphics gfx(dc->m_hDC); - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x4); - Gdiplus::Pen pen(clr, 1); - for (int i = 0; i < 2; i++) { - Gdiplus::GraphicsPath path; - Gdiplus::PointF vertices[3]; - - if (ascending) { - vertices[0] = Gdiplus::PointF(xPos, yPos); - vertices[1] = Gdiplus::PointF(steps + xPos, yPos + steps); - vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos); - } else { - vertices[0] = Gdiplus::PointF(xPos, yPos + steps); - vertices[1] = Gdiplus::PointF(steps + xPos, yPos); - vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos + steps); - } - - path.AddLines(vertices, 3); - gfx.DrawPath(&pen, &path); - } -} - -void CMPCThemeHeaderCtrl::drawItem(int nItem, CRect rText, CDC* pDC) -{ - - COLORREF textColor = CMPCTheme::TextFGColor; - COLORREF bgColor = CMPCTheme::ContentBGColor; - - COLORREF oldTextColor = pDC->GetTextColor(); - COLORREF oldBkColor = pDC->GetBkColor(); - - CRect rGrid; - rGrid = rText; - - - rGrid.top -= 1; - rGrid.bottom -= 1; - - CPoint ptCursor; - ::GetCursorPos(&ptCursor); - ScreenToClient(&ptCursor); - checkHot(ptCursor); - - if (nItem == hotItem) { - bgColor = CMPCTheme::ColumnHeaderHotColor; - } - pDC->FillSolidRect(rGrid, bgColor); - - CPen gridPen, *oldPen; - gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::HeaderCtrlGridColor); - oldPen = pDC->SelectObject(&gridPen); - if (nItem != 0) { - //we will draw left border, which lines up with grid. this differs from native widget - //which draws the right border which consequently does not line up with the grid (ugly) - //we only draw the left border starting from the second column - pDC->MoveTo(rGrid.left, rGrid.top); - pDC->LineTo(rGrid.left, rGrid.bottom); - } else { - pDC->MoveTo(rGrid.left, rGrid.bottom); - } - pDC->LineTo(rGrid.BottomRight()); - //pDC->LineTo(rGrid.right, rGrid.top); - pDC->SelectObject(oldPen); - - if (nItem != -1) { - HDITEM hditem = { 0 }; - hditem.mask = HDI_FORMAT | HDI_TEXT | HDI_STATE; - const int c_cchBuffer = 1024; - TCHAR lpBuffer[c_cchBuffer]; - hditem.pszText = lpBuffer; - hditem.cchTextMax = c_cchBuffer; - - GetItem(nItem, &hditem); - int align = hditem.fmt & HDF_JUSTIFYMASK; - UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX; - if (align == HDF_CENTER) { - textFormat |= DT_CENTER; - } else if (align == HDF_LEFT) { - textFormat |= DT_LEFT; - rText.left += 6; - } else { - textFormat |= DT_RIGHT; - rText.right -= 6; - } - CString text = hditem.pszText; - pDC->SetTextColor(textColor); - pDC->SetBkColor(bgColor); - - CMPCThemeUtil::DrawBufferedText(pDC, text, rText, textFormat); - if (hditem.fmt & HDF_SORTUP) { - drawSortArrow(pDC, CMPCTheme::HeaderCtrlSortArrowColor, rText, true); - } else if (hditem.fmt & HDF_SORTDOWN) { - drawSortArrow(pDC, CMPCTheme::HeaderCtrlSortArrowColor, rText, false); - } - } - - pDC->SetTextColor(oldTextColor); - pDC->SetBkColor(oldBkColor); - gridPen.DeleteObject(); -} - -/* custom draw doesn't handle empty areas! code is no longer used in favor of OnPaint() */ -void CMPCThemeHeaderCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); - - *pResult = CDRF_DODEFAULT; - if (AppIsThemeLoaded()) { - if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT) { - *pResult = CDRF_NOTIFYITEMDRAW; - } else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { - int nItem = pLVCD->nmcd.dwItemSpec; - CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); - CRect rText; - GetItemRect(nItem, rText); - - drawItem(nItem, rText, pDC); - *pResult = CDRF_SKIPDEFAULT; - } - } -} - - -void CMPCThemeHeaderCtrl::OnHdnTrack(NMHDR* pNMHDR, LRESULT* pResult) -{ - // LPNMHEADER phdr = reinterpret_cast(pNMHDR); - *pResult = 0; -} - -void CMPCThemeHeaderCtrl::checkHot(CPoint point) -{ - HDHITTESTINFO hdHitTestInfo; - hdHitTestInfo.pt = point; - - int prevHotItem = hotItem; - hotItem = (int)SendMessage(HDM_HITTEST, 0, (LPARAM)&hdHitTestInfo); - - if ((hdHitTestInfo.flags & HHT_ONHEADER) == 0) { - hotItem = -2; - } - if (hotItem != prevHotItem) { - RedrawWindow(); - } -} - - -void CMPCThemeHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - if ((nFlags & MK_LBUTTON) == 0) { - checkHot(point); - } - - __super::OnMouseMove(nFlags, point); -} - -void CMPCThemeHeaderCtrl::OnMouseLeave() -{ - if (hotItem >= 0) { - hotItem = -1; - RedrawWindow(); - } - __super::OnMouseLeave(); -} - - -#define max(a,b) (((a) > (b)) ? (a) : (b)) -void CMPCThemeHeaderCtrl::OnPaint() -{ - if (GetStyle() & HDS_FILTERBAR) { - Default(); - return; - } - - CPaintDC dc(this); // device context for painting - CMemDC memDC(dc, this); - CDC* pDC = &memDC.GetDC(); - CFont* font = GetFont(); - CFont* pOldFont = pDC->SelectObject(font); - - CRect rectClip; - dc.GetClipBox(rectClip); - - CRect rect; - GetClientRect(rect); - - CRect rectItem; - int nCount = GetItemCount(); - - int xMax = 0; - - for (int i = 0; i < nCount; i++) { - CPoint ptCursor; - ::GetCursorPos(&ptCursor); - ScreenToClient(&ptCursor); - - GetItemRect(i, rectItem); - - CRgn rgnClip; - rgnClip.CreateRectRgnIndirect(&rectItem); - pDC->SelectClipRgn(&rgnClip); - - // Draw item: - drawItem(i, rectItem, pDC); - - pDC->SelectClipRgn(NULL); - - xMax = max(xMax, rectItem.right); - } - - // Draw "tail border": - if (nCount == 0) { - rectItem = rect; - rectItem.right++; - } else { - rectItem.left = xMax; - rectItem.right = rect.right + 1; - } - - drawItem(-1, rectItem, pDC); - pDC->SelectObject(pOldFont); -} +#include "stdafx.h" +#include "CMPCThemeHeaderCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "DpiHelper.h" +#include "mplayerc.h" + +CMPCThemeHeaderCtrl::CMPCThemeHeaderCtrl() +{ + hotItem = -2; +} + + +CMPCThemeHeaderCtrl::~CMPCThemeHeaderCtrl() +{ +} +BEGIN_MESSAGE_MAP(CMPCThemeHeaderCtrl, CHeaderCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeHeaderCtrl::OnNMCustomdraw) + ON_NOTIFY(HDN_TRACKA, 0, &CMPCThemeHeaderCtrl::OnHdnTrack) + ON_NOTIFY(HDN_TRACKW, 0, &CMPCThemeHeaderCtrl::OnHdnTrack) + ON_WM_MOUSEMOVE() + ON_WM_MOUSELEAVE() + ON_WM_PAINT() +END_MESSAGE_MAP() + +void CMPCThemeHeaderCtrl::drawSortArrow(CDC* dc, COLORREF arrowClr, CRect arrowRect, bool ascending) +{ + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + Gdiplus::Color clr; + clr.SetFromCOLORREF(arrowClr); + + int dpi = dpiWindow.DPIX(); + float steps; + + if (dpi < 120) { + steps = 3.5; + } else if (dpi < 144) { + steps = 4; + } else if (dpi < 168) { + steps = 5; + } else if (dpi < 192) { + steps = 5; + } else { + steps = 6; + } + + int xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + int yPos = arrowRect.top; + + Gdiplus::Graphics gfx(dc->m_hDC); + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x4); + Gdiplus::Pen pen(clr, 1); + for (int i = 0; i < 2; i++) { + Gdiplus::GraphicsPath path; + Gdiplus::PointF vertices[3]; + + if (ascending) { + vertices[0] = Gdiplus::PointF(xPos, yPos); + vertices[1] = Gdiplus::PointF(steps + xPos, yPos + steps); + vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos); + } else { + vertices[0] = Gdiplus::PointF(xPos, yPos + steps); + vertices[1] = Gdiplus::PointF(steps + xPos, yPos); + vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos + steps); + } + + path.AddLines(vertices, 3); + gfx.DrawPath(&pen, &path); + } +} + +void CMPCThemeHeaderCtrl::drawItem(int nItem, CRect rText, CDC* pDC) +{ + + COLORREF textColor = CMPCTheme::TextFGColor; + COLORREF bgColor = CMPCTheme::ContentBGColor; + + COLORREF oldTextColor = pDC->GetTextColor(); + COLORREF oldBkColor = pDC->GetBkColor(); + + CRect rGrid; + rGrid = rText; + + + rGrid.top -= 1; + rGrid.bottom -= 1; + + CPoint ptCursor; + ::GetCursorPos(&ptCursor); + ScreenToClient(&ptCursor); + checkHot(ptCursor); + + if (nItem == hotItem) { + bgColor = CMPCTheme::ColumnHeaderHotColor; + } + pDC->FillSolidRect(rGrid, bgColor); + + CPen gridPen, *oldPen; + gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::HeaderCtrlGridColor); + oldPen = pDC->SelectObject(&gridPen); + if (nItem != 0) { + //we will draw left border, which lines up with grid. this differs from native widget + //which draws the right border which consequently does not line up with the grid (ugly) + //we only draw the left border starting from the second column + pDC->MoveTo(rGrid.left, rGrid.top); + pDC->LineTo(rGrid.left, rGrid.bottom); + } else { + pDC->MoveTo(rGrid.left, rGrid.bottom); + } + pDC->LineTo(rGrid.BottomRight()); + //pDC->LineTo(rGrid.right, rGrid.top); + pDC->SelectObject(oldPen); + + if (nItem != -1) { + HDITEM hditem = { 0 }; + hditem.mask = HDI_FORMAT | HDI_TEXT | HDI_STATE; + const int c_cchBuffer = 1024; + TCHAR lpBuffer[c_cchBuffer]; + hditem.pszText = lpBuffer; + hditem.cchTextMax = c_cchBuffer; + + GetItem(nItem, &hditem); + int align = hditem.fmt & HDF_JUSTIFYMASK; + UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX; + if (align == HDF_CENTER) { + textFormat |= DT_CENTER; + } else if (align == HDF_LEFT) { + textFormat |= DT_LEFT; + rText.left += 6; + } else { + textFormat |= DT_RIGHT; + rText.right -= 6; + } + CString text = hditem.pszText; + pDC->SetTextColor(textColor); + pDC->SetBkColor(bgColor); + + CMPCThemeUtil::DrawBufferedText(pDC, text, rText, textFormat); + if (hditem.fmt & HDF_SORTUP) { + drawSortArrow(pDC, CMPCTheme::HeaderCtrlSortArrowColor, rText, true); + } else if (hditem.fmt & HDF_SORTDOWN) { + drawSortArrow(pDC, CMPCTheme::HeaderCtrlSortArrowColor, rText, false); + } + } + + pDC->SetTextColor(oldTextColor); + pDC->SetBkColor(oldBkColor); + gridPen.DeleteObject(); +} + +/* custom draw doesn't handle empty areas! code is no longer used in favor of OnPaint() */ +void CMPCThemeHeaderCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); + + *pResult = CDRF_DODEFAULT; + if (AppIsThemeLoaded()) { + if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT) { + *pResult = CDRF_NOTIFYITEMDRAW; + } else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { + int nItem = pLVCD->nmcd.dwItemSpec; + CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); + CRect rText; + GetItemRect(nItem, rText); + + drawItem(nItem, rText, pDC); + *pResult = CDRF_SKIPDEFAULT; + } + } +} + + +void CMPCThemeHeaderCtrl::OnHdnTrack(NMHDR* pNMHDR, LRESULT* pResult) +{ + // LPNMHEADER phdr = reinterpret_cast(pNMHDR); + *pResult = 0; +} + +void CMPCThemeHeaderCtrl::checkHot(CPoint point) +{ + HDHITTESTINFO hdHitTestInfo; + hdHitTestInfo.pt = point; + + int prevHotItem = hotItem; + hotItem = (int)SendMessage(HDM_HITTEST, 0, (LPARAM)&hdHitTestInfo); + + if ((hdHitTestInfo.flags & HHT_ONHEADER) == 0) { + hotItem = -2; + } + if (hotItem != prevHotItem) { + RedrawWindow(); + } +} + + +void CMPCThemeHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + if ((nFlags & MK_LBUTTON) == 0) { + checkHot(point); + } + + __super::OnMouseMove(nFlags, point); +} + +void CMPCThemeHeaderCtrl::OnMouseLeave() +{ + if (hotItem >= 0) { + hotItem = -1; + RedrawWindow(); + } + __super::OnMouseLeave(); +} + + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +void CMPCThemeHeaderCtrl::OnPaint() +{ + if (GetStyle() & HDS_FILTERBAR) { + Default(); + return; + } + + CPaintDC dc(this); // device context for painting + CMemDC memDC(dc, this); + CDC* pDC = &memDC.GetDC(); + CFont* font = GetFont(); + CFont* pOldFont = pDC->SelectObject(font); + + CRect rectClip; + dc.GetClipBox(rectClip); + + CRect rect; + GetClientRect(rect); + + CRect rectItem; + int nCount = GetItemCount(); + + int xMax = 0; + + for (int i = 0; i < nCount; i++) { + CPoint ptCursor; + ::GetCursorPos(&ptCursor); + ScreenToClient(&ptCursor); + + GetItemRect(i, rectItem); + + CRgn rgnClip; + rgnClip.CreateRectRgnIndirect(&rectItem); + pDC->SelectClipRgn(&rgnClip); + + // Draw item: + drawItem(i, rectItem, pDC); + + pDC->SelectClipRgn(NULL); + + xMax = max(xMax, rectItem.right); + } + + // Draw "tail border": + if (nCount == 0) { + rectItem = rect; + rectItem.right++; + } else { + rectItem.left = xMax; + rectItem.right = rect.right + 1; + } + + drawItem(-1, rectItem, pDC); + pDC->SelectObject(pOldFont); +} diff --git a/src/mpc-hc/CMPCThemeHeaderCtrl.h b/src/mpc-hc/CMPCThemeHeaderCtrl.h index b58daf4d243..839200f735d 100755 --- a/src/mpc-hc/CMPCThemeHeaderCtrl.h +++ b/src/mpc-hc/CMPCThemeHeaderCtrl.h @@ -1,21 +1,21 @@ -#pragma once -#include -class CMPCThemeHeaderCtrl : - public CHeaderCtrl -{ -protected: - int hotItem; - void checkHot(CPoint point); - void drawSortArrow(CDC* dc, COLORREF arrowClr, CRect arrowRect, bool ascending); - void drawItem(int nItem, CRect rText, CDC* pDC); -public: - CMPCThemeHeaderCtrl(); - virtual ~CMPCThemeHeaderCtrl(); - DECLARE_MESSAGE_MAP() - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnHdnTrack(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg void OnPaint(); -}; - +#pragma once +#include +class CMPCThemeHeaderCtrl : + public CHeaderCtrl +{ +protected: + int hotItem; + void checkHot(CPoint point); + void drawSortArrow(CDC* dc, COLORREF arrowClr, CRect arrowRect, bool ascending); + void drawItem(int nItem, CRect rText, CDC* pDC); +public: + CMPCThemeHeaderCtrl(); + virtual ~CMPCThemeHeaderCtrl(); + DECLARE_MESSAGE_MAP() + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnHdnTrack(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeInlineEdit.cpp b/src/mpc-hc/CMPCThemeInlineEdit.cpp index 3f4fe0f61b4..5c38d90de48 100755 --- a/src/mpc-hc/CMPCThemeInlineEdit.cpp +++ b/src/mpc-hc/CMPCThemeInlineEdit.cpp @@ -1,69 +1,69 @@ -#include "stdafx.h" -#include "CMPCThemeInlineEdit.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - -CMPCThemeInlineEdit::CMPCThemeInlineEdit(): - overrideX(0) - ,overrideMaxWidth(-1) - ,offsetEnabled(false) -{ - m_brBkgnd.CreateSolidBrush(CMPCTheme::ContentBGColor); -} - - -CMPCThemeInlineEdit::~CMPCThemeInlineEdit() -{ - m_brBkgnd.DeleteObject(); -} -void CMPCThemeInlineEdit::setOverridePos(int x, int maxWidth) { - overrideX = x; - overrideMaxWidth = maxWidth; - offsetEnabled = true; -} -BEGIN_MESSAGE_MAP(CMPCThemeInlineEdit, CEdit) - ON_WM_CTLCOLOR_REFLECT() - ON_WM_WINDOWPOSCHANGED() - ON_WM_PAINT() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeInlineEdit::CtlColor(CDC* pDC, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::ContentBGColor); - return m_brBkgnd; - } else { - return NULL; - } -} - - -void CMPCThemeInlineEdit::OnWindowPosChanged(WINDOWPOS* lpwndpos) { - if (offsetEnabled && overrideX != lpwndpos->x) { - lpwndpos->cx = overrideMaxWidth == -1 ? lpwndpos->cx : std::min(lpwndpos->cx, overrideMaxWidth); - SetWindowPos(nullptr, overrideX, lpwndpos->y, lpwndpos->cx, lpwndpos->cy, SWP_NOZORDER); - } - CEdit::OnWindowPosChanged(lpwndpos); -} - -void CMPCThemeInlineEdit::OnPaint() { - if (AppIsThemeLoaded()) { - CPaintDC dc(this); - - CRect rect; - GetClientRect(&rect); - - CBrush brush; - brush.CreateSolidBrush(CMPCTheme::InlineEditBorderColor); - dc.FrameRect(&rect, &brush); - brush.DeleteObject(); - - rect.DeflateRect(1, 1); - CBrush bgBrush(CMPCTheme::ContentBGColor); - dc.FrameRect(rect, &bgBrush); - } else { - __super::OnPaint(); - } -} +#include "stdafx.h" +#include "CMPCThemeInlineEdit.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + +CMPCThemeInlineEdit::CMPCThemeInlineEdit(): + overrideX(0) + ,overrideMaxWidth(-1) + ,offsetEnabled(false) +{ + m_brBkgnd.CreateSolidBrush(CMPCTheme::ContentBGColor); +} + + +CMPCThemeInlineEdit::~CMPCThemeInlineEdit() +{ + m_brBkgnd.DeleteObject(); +} +void CMPCThemeInlineEdit::setOverridePos(int x, int maxWidth) { + overrideX = x; + overrideMaxWidth = maxWidth; + offsetEnabled = true; +} +BEGIN_MESSAGE_MAP(CMPCThemeInlineEdit, CEdit) + ON_WM_CTLCOLOR_REFLECT() + ON_WM_WINDOWPOSCHANGED() + ON_WM_PAINT() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeInlineEdit::CtlColor(CDC* pDC, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::ContentBGColor); + return m_brBkgnd; + } else { + return NULL; + } +} + + +void CMPCThemeInlineEdit::OnWindowPosChanged(WINDOWPOS* lpwndpos) { + if (offsetEnabled && overrideX != lpwndpos->x) { + lpwndpos->cx = overrideMaxWidth == -1 ? lpwndpos->cx : std::min(lpwndpos->cx, overrideMaxWidth); + SetWindowPos(nullptr, overrideX, lpwndpos->y, lpwndpos->cx, lpwndpos->cy, SWP_NOZORDER); + } + CEdit::OnWindowPosChanged(lpwndpos); +} + +void CMPCThemeInlineEdit::OnPaint() { + if (AppIsThemeLoaded()) { + CPaintDC dc(this); + + CRect rect; + GetClientRect(&rect); + + CBrush brush; + brush.CreateSolidBrush(CMPCTheme::InlineEditBorderColor); + dc.FrameRect(&rect, &brush); + brush.DeleteObject(); + + rect.DeflateRect(1, 1); + CBrush bgBrush(CMPCTheme::ContentBGColor); + dc.FrameRect(rect, &bgBrush); + } else { + __super::OnPaint(); + } +} diff --git a/src/mpc-hc/CMPCThemeInlineEdit.h b/src/mpc-hc/CMPCThemeInlineEdit.h index fcbb1e07038..fafd97c2f14 100755 --- a/src/mpc-hc/CMPCThemeInlineEdit.h +++ b/src/mpc-hc/CMPCThemeInlineEdit.h @@ -1,21 +1,21 @@ -#pragma once -#include -class CMPCThemeInlineEdit : - public CEdit -{ -public: - CMPCThemeInlineEdit(); - virtual ~CMPCThemeInlineEdit(); - CBrush m_brBkgnd; - void setOverridePos(int x, int maxWidth); - DECLARE_MESSAGE_MAP() - afx_msg void OnNcPaint(); - afx_msg HBRUSH CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/); - afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); -private: - int overrideX, overrideMaxWidth; - bool offsetEnabled; -public: - afx_msg void OnPaint(); -}; - +#pragma once +#include +class CMPCThemeInlineEdit : + public CEdit +{ +public: + CMPCThemeInlineEdit(); + virtual ~CMPCThemeInlineEdit(); + CBrush m_brBkgnd; + void setOverridePos(int x, int maxWidth); + DECLARE_MESSAGE_MAP() + afx_msg void OnNcPaint(); + afx_msg HBRUSH CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/); + afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); +private: + int overrideX, overrideMaxWidth; + bool offsetEnabled; +public: + afx_msg void OnPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeLinkCtrl.cpp b/src/mpc-hc/CMPCThemeLinkCtrl.cpp index bfec5d15c84..cf5a9c13264 100755 --- a/src/mpc-hc/CMPCThemeLinkCtrl.cpp +++ b/src/mpc-hc/CMPCThemeLinkCtrl.cpp @@ -1,35 +1,35 @@ -#include "stdafx.h" -#include "CMPCThemeLinkCtrl.h" -#include "CMPCTheme.h" - - -CMPCThemeLinkCtrl::CMPCThemeLinkCtrl() -{ - -} - - -CMPCThemeLinkCtrl::~CMPCThemeLinkCtrl() -{ -} -BEGIN_MESSAGE_MAP(CMPCThemeLinkCtrl, CLinkCtrl) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeLinkCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH hbr = CLinkCtrl::OnCtlColor(pDC, pWnd, nCtlColor); - - pDC->SetTextColor(CMPCTheme::TextFGColor); - return hbr; -} - -void CMPCThemeLinkCtrl::PreSubclassWindow() -{ - LITEM item = { 0 }; - item.mask = LIF_ITEMINDEX | LIF_STATE; - item.state = LIS_DEFAULTCOLORS; - item.stateMask = LIS_DEFAULTCOLORS; - SetItem(&item); -} +#include "stdafx.h" +#include "CMPCThemeLinkCtrl.h" +#include "CMPCTheme.h" + + +CMPCThemeLinkCtrl::CMPCThemeLinkCtrl() +{ + +} + + +CMPCThemeLinkCtrl::~CMPCThemeLinkCtrl() +{ +} +BEGIN_MESSAGE_MAP(CMPCThemeLinkCtrl, CLinkCtrl) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeLinkCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH hbr = CLinkCtrl::OnCtlColor(pDC, pWnd, nCtlColor); + + pDC->SetTextColor(CMPCTheme::TextFGColor); + return hbr; +} + +void CMPCThemeLinkCtrl::PreSubclassWindow() +{ + LITEM item = { 0 }; + item.mask = LIF_ITEMINDEX | LIF_STATE; + item.state = LIS_DEFAULTCOLORS; + item.stateMask = LIS_DEFAULTCOLORS; + SetItem(&item); +} diff --git a/src/mpc-hc/CMPCThemeLinkCtrl.h b/src/mpc-hc/CMPCThemeLinkCtrl.h index 087c7cce02b..99bfb3c1848 100755 --- a/src/mpc-hc/CMPCThemeLinkCtrl.h +++ b/src/mpc-hc/CMPCThemeLinkCtrl.h @@ -1,13 +1,13 @@ -#pragma once -#include -class CMPCThemeLinkCtrl : - public CLinkCtrl -{ -public: - CMPCThemeLinkCtrl(); - virtual ~CMPCThemeLinkCtrl(); - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - virtual void PreSubclassWindow(); -}; - +#pragma once +#include +class CMPCThemeLinkCtrl : + public CLinkCtrl +{ +public: + CMPCThemeLinkCtrl(); + virtual ~CMPCThemeLinkCtrl(); + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + virtual void PreSubclassWindow(); +}; + diff --git a/src/mpc-hc/CMPCThemeListBox.cpp b/src/mpc-hc/CMPCThemeListBox.cpp index a636d54c9d9..e4f8b2d5a8b 100755 --- a/src/mpc-hc/CMPCThemeListBox.cpp +++ b/src/mpc-hc/CMPCThemeListBox.cpp @@ -1,224 +1,224 @@ -#include "stdafx.h" -#include "CMPCThemeListBox.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -IMPLEMENT_DYNAMIC(CMPCThemeListBox, CListBox) - -CMPCThemeListBox::CMPCThemeListBox() - :customizeToolBar(nullptr) -{ - themedToolTipCid = (UINT_PTR) - 1; - themedSBHelper = nullptr; - if (!CMPCThemeUtil::canUseWin10DarkTheme()) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - } -} - - -CMPCThemeListBox::~CMPCThemeListBox() -{ - if (nullptr != themedSBHelper) { - delete themedSBHelper; - } -} - -BEGIN_MESSAGE_MAP(CMPCThemeListBox, CListBox) - ON_WM_NCPAINT() - ON_WM_MOUSEWHEEL() - ON_WM_TIMER() - ON_WM_VSCROLL() - ON_CONTROL_REFLECT_EX(LBN_SELCHANGE, &CMPCThemeListBox::OnLbnSelchange) - ON_WM_MOUSEMOVE() - ON_WM_SIZE() -END_MESSAGE_MAP() - - -void CMPCThemeListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CDC dc; - if (lpDrawItemStruct->itemID == -1) { - return; - } - dc.Attach(lpDrawItemStruct->hDC); - - int buttonID = (int16_t)LOWORD(lpDrawItemStruct->itemData); - - CRect rc(lpDrawItemStruct->rcItem); - - COLORREF crOldTextColor = dc.GetTextColor(); - COLORREF crOldBkColor = dc.GetBkColor(); - - if ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED)) { - dc.SetTextColor(CMPCTheme::TextFGColor); - dc.SetBkColor(CMPCTheme::ContentSelectedColor); - dc.FillSolidRect(&rc, CMPCTheme::ContentSelectedColor); - } else { - dc.SetTextColor(CMPCTheme::TextFGColor); - dc.SetBkColor(CMPCTheme::ContentBGColor); - dc.FillSolidRect(&rc, CMPCTheme::ContentBGColor); - } - - if (customizeToolBar) { - if (buttonID != -1) { - auto list = customizeToolBar->GetToolBarCtrl().GetImageList(); - IMAGEINFO ii; - list->GetImageInfo(buttonID, &ii); - CRect rci(ii.rcImage); - int border = (rc.Height() - rci.Height()) / 2; - border = border < 0 ? 0 : border; - list->Draw(&dc, buttonID, rc.TopLeft() + CPoint(border, border), ILD_NORMAL); - } - rc.left += rc.Height(); - } - - rc.left += 3; - - CString strText; - GetText(lpDrawItemStruct->itemID, strText); - - CFont* font = GetFont(); - CFont* pOldFont = dc.SelectObject(font); - dc.DrawTextW(strText, strText.GetLength(), &rc, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); - - dc.SetTextColor(crOldTextColor); - dc.SetBkColor(crOldBkColor); - dc.SelectObject(pOldFont); - - dc.Detach(); -} - - -void CMPCThemeListBox::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->themedNcPaintWithSB(); - } else { - CMPCThemeScrollBarHelper::themedNcPaint(this, this); - } - } else { - __super::OnNcPaint(); - } -} - -BOOL CMPCThemeListBox::PreTranslateMessage(MSG* pMsg) -{ - if (AppNeedsThemedControls()) { - themedToolTip.RelayEvent(pMsg); - } - return CListBox::PreTranslateMessage(pMsg); -} - -void CMPCThemeListBox::PreSubclassWindow() -{ - CListBox::PreSubclassWindow(); - if (AppNeedsThemedControls()) { - if (CMPCThemeUtil::canUseWin10DarkTheme()) { - SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); - } else { - SetWindowTheme(GetSafeHwnd(), L"", NULL); - } - if (nullptr == themedToolTip.m_hWnd) { - themedToolTip.Create(this, TTS_ALWAYSTIP); - } - themedToolTip.enableFlickerHelper(); - } -} - - -BOOL CMPCThemeListBox::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) -{ - CListBox::OnMouseWheel(nFlags, zDelta, pt); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - ScreenToClient(&pt); - updateToolTip(pt); - return TRUE; -} - -void CMPCThemeListBox::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - CListBox::OnVScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - -BOOL CMPCThemeListBox::OnLbnSelchange() -{ - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - return FALSE; //allow non-reflection handling -} - - -void CMPCThemeListBox::updateToolTip(CPoint point) -{ - if (AppNeedsThemedControls() && nullptr != themedToolTip) { - TOOLINFO ti = { 0 }; - UINT_PTR tid = OnToolHitTest(point, &ti); - //OnToolHitTest returns -1 on failure but doesn't update uId to match - - if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool - if (themedToolTip.GetToolCount() > 0) { - themedToolTip.DelTool(this); - themedToolTip.Activate(FALSE); - } - themedToolTipCid = (UINT_PTR) - 1; - } - - if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { - - themedToolTipCid = ti.uId; - - CRect cr; - GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate - - themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); - themedToolTip.Activate(TRUE); - } - } -} - - -void CMPCThemeListBox::OnMouseMove(UINT nFlags, CPoint point) -{ - updateToolTip(point); -} - -void CMPCThemeListBox::setIntegralHeight() -{ - CWindowDC dc(this); - CFont* font = GetFont(); - CFont* pOldFont = dc.SelectObject(font); - CRect r(0, 0, 99, 99); - CString test = _T("W"); - dc.DrawText(test, test.GetLength(), &r, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); - SetItemHeight(0, r.Height()); - - dc.SelectObject(pOldFont); -} - -void CMPCThemeListBox::OnSize(UINT nType, int cx, int cy) -{ - CListBox::OnSize(nType, cx, cy); -} - -void CMPCThemeListBox::EnsureVisible(int index) { - CRect r; - GetClientRect(&r); - int lbHeight = r.Height(); - - int height=0; - for (int i = index; i >= 0; i--) { - height += GetItemHeight(i); - if (height > lbHeight) { - SetTopIndex(i + 1); - return; - } - } -} +#include "stdafx.h" +#include "CMPCThemeListBox.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +IMPLEMENT_DYNAMIC(CMPCThemeListBox, CListBox) + +CMPCThemeListBox::CMPCThemeListBox() + :customizeToolBar(nullptr) +{ + themedToolTipCid = (UINT_PTR) - 1; + themedSBHelper = nullptr; + if (!CMPCThemeUtil::canUseWin10DarkTheme()) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + } +} + + +CMPCThemeListBox::~CMPCThemeListBox() +{ + if (nullptr != themedSBHelper) { + delete themedSBHelper; + } +} + +BEGIN_MESSAGE_MAP(CMPCThemeListBox, CListBox) + ON_WM_NCPAINT() + ON_WM_MOUSEWHEEL() + ON_WM_TIMER() + ON_WM_VSCROLL() + ON_CONTROL_REFLECT_EX(LBN_SELCHANGE, &CMPCThemeListBox::OnLbnSelchange) + ON_WM_MOUSEMOVE() + ON_WM_SIZE() +END_MESSAGE_MAP() + + +void CMPCThemeListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC dc; + if (lpDrawItemStruct->itemID == -1) { + return; + } + dc.Attach(lpDrawItemStruct->hDC); + + int buttonID = (int16_t)LOWORD(lpDrawItemStruct->itemData); + + CRect rc(lpDrawItemStruct->rcItem); + + COLORREF crOldTextColor = dc.GetTextColor(); + COLORREF crOldBkColor = dc.GetBkColor(); + + if ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED)) { + dc.SetTextColor(CMPCTheme::TextFGColor); + dc.SetBkColor(CMPCTheme::ContentSelectedColor); + dc.FillSolidRect(&rc, CMPCTheme::ContentSelectedColor); + } else { + dc.SetTextColor(CMPCTheme::TextFGColor); + dc.SetBkColor(CMPCTheme::ContentBGColor); + dc.FillSolidRect(&rc, CMPCTheme::ContentBGColor); + } + + if (customizeToolBar) { + if (buttonID != -1) { + auto list = customizeToolBar->GetToolBarCtrl().GetImageList(); + IMAGEINFO ii; + list->GetImageInfo(buttonID, &ii); + CRect rci(ii.rcImage); + int border = (rc.Height() - rci.Height()) / 2; + border = border < 0 ? 0 : border; + list->Draw(&dc, buttonID, rc.TopLeft() + CPoint(border, border), ILD_NORMAL); + } + rc.left += rc.Height(); + } + + rc.left += 3; + + CString strText; + GetText(lpDrawItemStruct->itemID, strText); + + CFont* font = GetFont(); + CFont* pOldFont = dc.SelectObject(font); + dc.DrawTextW(strText, strText.GetLength(), &rc, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); + + dc.SetTextColor(crOldTextColor); + dc.SetBkColor(crOldBkColor); + dc.SelectObject(pOldFont); + + dc.Detach(); +} + + +void CMPCThemeListBox::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->themedNcPaintWithSB(); + } else { + CMPCThemeScrollBarHelper::themedNcPaint(this, this); + } + } else { + __super::OnNcPaint(); + } +} + +BOOL CMPCThemeListBox::PreTranslateMessage(MSG* pMsg) +{ + if (AppNeedsThemedControls()) { + themedToolTip.RelayEvent(pMsg); + } + return CListBox::PreTranslateMessage(pMsg); +} + +void CMPCThemeListBox::PreSubclassWindow() +{ + CListBox::PreSubclassWindow(); + if (AppNeedsThemedControls()) { + if (CMPCThemeUtil::canUseWin10DarkTheme()) { + SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); + } else { + SetWindowTheme(GetSafeHwnd(), L"", NULL); + } + if (nullptr == themedToolTip.m_hWnd) { + themedToolTip.Create(this, TTS_ALWAYSTIP); + } + themedToolTip.enableFlickerHelper(); + } +} + + +BOOL CMPCThemeListBox::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + CListBox::OnMouseWheel(nFlags, zDelta, pt); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + ScreenToClient(&pt); + updateToolTip(pt); + return TRUE; +} + +void CMPCThemeListBox::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + CListBox::OnVScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + +BOOL CMPCThemeListBox::OnLbnSelchange() +{ + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + return FALSE; //allow non-reflection handling +} + + +void CMPCThemeListBox::updateToolTip(CPoint point) +{ + if (AppNeedsThemedControls() && nullptr != themedToolTip) { + TOOLINFO ti = { 0 }; + UINT_PTR tid = OnToolHitTest(point, &ti); + //OnToolHitTest returns -1 on failure but doesn't update uId to match + + if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool + if (themedToolTip.GetToolCount() > 0) { + themedToolTip.DelTool(this); + themedToolTip.Activate(FALSE); + } + themedToolTipCid = (UINT_PTR) - 1; + } + + if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { + + themedToolTipCid = ti.uId; + + CRect cr; + GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate + + themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); + themedToolTip.Activate(TRUE); + } + } +} + + +void CMPCThemeListBox::OnMouseMove(UINT nFlags, CPoint point) +{ + updateToolTip(point); +} + +void CMPCThemeListBox::setIntegralHeight() +{ + CWindowDC dc(this); + CFont* font = GetFont(); + CFont* pOldFont = dc.SelectObject(font); + CRect r(0, 0, 99, 99); + CString test = _T("W"); + dc.DrawText(test, test.GetLength(), &r, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); + SetItemHeight(0, r.Height()); + + dc.SelectObject(pOldFont); +} + +void CMPCThemeListBox::OnSize(UINT nType, int cx, int cy) +{ + CListBox::OnSize(nType, cx, cy); +} + +void CMPCThemeListBox::EnsureVisible(int index) { + CRect r; + GetClientRect(&r); + int lbHeight = r.Height(); + + int height=0; + for (int i = index; i >= 0; i--) { + height += GetItemHeight(i); + if (height > lbHeight) { + SetTopIndex(i + 1); + return; + } + } +} diff --git a/src/mpc-hc/CMPCThemeListBox.h b/src/mpc-hc/CMPCThemeListBox.h index ad38d24013d..f5f74e88d06 100755 --- a/src/mpc-hc/CMPCThemeListBox.h +++ b/src/mpc-hc/CMPCThemeListBox.h @@ -1,37 +1,37 @@ -#pragma once -#include -#include "CMPCThemeScrollBar.h" -#include "CMPCThemeToolTipCtrl.h" -#include "CMPCThemeScrollBarHelper.h" - -class CMPCThemeListBox : - public CListBox, public CMPCThemeScrollable -{ - DECLARE_DYNAMIC(CMPCThemeListBox) -private: - CMPCThemeScrollBar vertSB; - CMPCThemeToolTipCtrl themedToolTip; - UINT_PTR themedToolTipCid; - CMPCThemeScrollBarHelper* themedSBHelper; - CToolBar* customizeToolBar; -protected: - virtual void PreSubclassWindow(); -public: - CMPCThemeListBox(); - virtual ~CMPCThemeListBox(); - virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); - BOOL PreTranslateMessage(MSG* pMsg); - DECLARE_MESSAGE_MAP() - afx_msg void OnNcPaint(); -public: - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg BOOL OnLbnSelchange(); - void updateToolTip(CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - void setIntegralHeight(); - afx_msg void OnSize(UINT nType, int cx, int cy); - void EnsureVisible(int index); - void SetCustomizeToolbar(CToolBar* tb) { customizeToolBar = tb; }; -}; - +#pragma once +#include +#include "CMPCThemeScrollBar.h" +#include "CMPCThemeToolTipCtrl.h" +#include "CMPCThemeScrollBarHelper.h" + +class CMPCThemeListBox : + public CListBox, public CMPCThemeScrollable +{ + DECLARE_DYNAMIC(CMPCThemeListBox) +private: + CMPCThemeScrollBar vertSB; + CMPCThemeToolTipCtrl themedToolTip; + UINT_PTR themedToolTipCid; + CMPCThemeScrollBarHelper* themedSBHelper; + CToolBar* customizeToolBar; +protected: + virtual void PreSubclassWindow(); +public: + CMPCThemeListBox(); + virtual ~CMPCThemeListBox(); + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + BOOL PreTranslateMessage(MSG* pMsg); + DECLARE_MESSAGE_MAP() + afx_msg void OnNcPaint(); +public: + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg BOOL OnLbnSelchange(); + void updateToolTip(CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + void setIntegralHeight(); + afx_msg void OnSize(UINT nType, int cx, int cy); + void EnsureVisible(int index); + void SetCustomizeToolbar(CToolBar* tb) { customizeToolBar = tb; }; +}; + diff --git a/src/mpc-hc/CMPCThemeMaskedEdit.cpp b/src/mpc-hc/CMPCThemeMaskedEdit.cpp index e3159e3ae43..900372e6691 100755 --- a/src/mpc-hc/CMPCThemeMaskedEdit.cpp +++ b/src/mpc-hc/CMPCThemeMaskedEdit.cpp @@ -1,51 +1,51 @@ -#include "stdafx.h" -#include "CMPCThemeMaskedEdit.h" -#include "mplayerc.h" -#include "CMPCTheme.h" - -CMPCThemeMaskedEdit::CMPCThemeMaskedEdit() -{ -} - - -CMPCThemeMaskedEdit::~CMPCThemeMaskedEdit() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeMaskedEdit, CMFCMaskedEdit) -BEGIN_MESSAGE_MAP(CMPCThemeMaskedEdit, CMFCMaskedEdit) - ON_WM_NCPAINT() -END_MESSAGE_MAP() - - -void CMPCThemeMaskedEdit::PreSubclassWindow() -{ - if (AppIsThemeLoaded()) { - ModifyStyleEx(WS_EX_CLIENTEDGE, WS_EX_STATICEDGE, SWP_FRAMECHANGED); - CRect r; - GetClientRect(r); - r.DeflateRect(2, 2); //some default padding for those spaceless fonts - SetRect(r); - } else { - __super::PreSubclassWindow(); - } -} - -void CMPCThemeMaskedEdit::OnNcPaint() -{ - if (AppIsThemeLoaded()) { - CWindowDC dc(this); - - CRect rect; - GetWindowRect(&rect); - rect.OffsetRect(-rect.left, -rect.top); - - CBrush brush; - brush.CreateSolidBrush(CMPCTheme::EditBorderColor); - - dc.FrameRect(&rect, &brush); - brush.DeleteObject(); - } else { - __super::OnNcPaint(); - } -} +#include "stdafx.h" +#include "CMPCThemeMaskedEdit.h" +#include "mplayerc.h" +#include "CMPCTheme.h" + +CMPCThemeMaskedEdit::CMPCThemeMaskedEdit() +{ +} + + +CMPCThemeMaskedEdit::~CMPCThemeMaskedEdit() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeMaskedEdit, CMFCMaskedEdit) +BEGIN_MESSAGE_MAP(CMPCThemeMaskedEdit, CMFCMaskedEdit) + ON_WM_NCPAINT() +END_MESSAGE_MAP() + + +void CMPCThemeMaskedEdit::PreSubclassWindow() +{ + if (AppIsThemeLoaded()) { + ModifyStyleEx(WS_EX_CLIENTEDGE, WS_EX_STATICEDGE, SWP_FRAMECHANGED); + CRect r; + GetClientRect(r); + r.DeflateRect(2, 2); //some default padding for those spaceless fonts + SetRect(r); + } else { + __super::PreSubclassWindow(); + } +} + +void CMPCThemeMaskedEdit::OnNcPaint() +{ + if (AppIsThemeLoaded()) { + CWindowDC dc(this); + + CRect rect; + GetWindowRect(&rect); + rect.OffsetRect(-rect.left, -rect.top); + + CBrush brush; + brush.CreateSolidBrush(CMPCTheme::EditBorderColor); + + dc.FrameRect(&rect, &brush); + brush.DeleteObject(); + } else { + __super::OnNcPaint(); + } +} diff --git a/src/mpc-hc/CMPCThemeMaskedEdit.h b/src/mpc-hc/CMPCThemeMaskedEdit.h index 51349205ba7..bc33027e8f8 100755 --- a/src/mpc-hc/CMPCThemeMaskedEdit.h +++ b/src/mpc-hc/CMPCThemeMaskedEdit.h @@ -1,18 +1,18 @@ -#pragma once -#include -class CMPCThemeMaskedEdit : - public CMFCMaskedEdit -{ - DECLARE_DYNAMIC(CMPCThemeMaskedEdit) -public: - CMPCThemeMaskedEdit(); - virtual ~CMPCThemeMaskedEdit(); - void PreSubclassWindow(); -protected: - CFont font; - - DECLARE_MESSAGE_MAP() - afx_msg void OnNcPaint(); - -}; - +#pragma once +#include +class CMPCThemeMaskedEdit : + public CMFCMaskedEdit +{ + DECLARE_DYNAMIC(CMPCThemeMaskedEdit) +public: + CMPCThemeMaskedEdit(); + virtual ~CMPCThemeMaskedEdit(); + void PreSubclassWindow(); +protected: + CFont font; + + DECLARE_MESSAGE_MAP() + afx_msg void OnNcPaint(); + +}; + diff --git a/src/mpc-hc/CMPCThemeMenu.cpp b/src/mpc-hc/CMPCThemeMenu.cpp index ffabac9d16e..c58daa13b48 100644 --- a/src/mpc-hc/CMPCThemeMenu.cpp +++ b/src/mpc-hc/CMPCThemeMenu.cpp @@ -1,590 +1,590 @@ -#include "stdafx.h" -#include "CMPCThemeMenu.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include -#include "AppSettings.h" -#include "PPageAccelTbl.h" -#include "mplayerc.h" - -std::map CMPCThemeMenu::subMenuIDs; -HBRUSH CMPCThemeMenu::bgBrush = 0; -HBRUSH CMPCThemeMenu::bgMenubarBrush = 0; -CFont CMPCThemeMenu::font; -CFont CMPCThemeMenu::symbolFont; -CFont CMPCThemeMenu::bulletFont; -CFont CMPCThemeMenu::checkFont; -bool CMPCThemeMenu::hasDimensions = false; -int CMPCThemeMenu::subMenuPadding; -int CMPCThemeMenu::iconSpacing; -int CMPCThemeMenu::iconPadding; -int CMPCThemeMenu::rowPadding; -int CMPCThemeMenu::separatorPadding; -int CMPCThemeMenu::separatorHeight; -int CMPCThemeMenu::postTextSpacing; -int CMPCThemeMenu::accelSpacing; -CCritSec CMPCThemeMenu::resourceLock; -std::mutex CMPCThemeMenu::submenuMutex; - -IMPLEMENT_DYNAMIC(CMPCThemeMenu, CMenu); -CMPCThemeMenu::CMPCThemeMenu() -{ -} - -CMPCThemeMenu::~CMPCThemeMenu() -{ - { - std::lock_guard guard(submenuMutex); - std::map::iterator itr = subMenuIDs.begin(); - while (itr != subMenuIDs.end()) { - if (itr->second == this) { - itr = subMenuIDs.erase(itr); - } else { - ++itr; - } - } - } - - for (u_int i = 0; i < allocatedItems.size(); i++) { - delete allocatedItems[i]; - } - for (u_int i = 0; i < allocatedMenus.size(); i++) { - allocatedMenus[i]->Detach(); - delete allocatedMenus[i]; - } -} - -void CMPCThemeMenu::initDimensions() -{ - if (!hasDimensions) { - DpiHelper dpi = DpiHelper(); - dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); - - subMenuPadding = dpi.ScaleX(20); - iconSpacing = dpi.ScaleX(22); - iconPadding = dpi.ScaleX(10); - rowPadding = dpi.ScaleY(4) + 3; //windows 10 explorer has paddings of 7,8,9,9,11--this yields 7,8,9,10,11 - separatorPadding = dpi.ScaleX(8); - separatorHeight = dpi.ScaleX(7); - postTextSpacing = dpi.ScaleX(20); - accelSpacing = dpi.ScaleX(30); - { - CAutoLock cAutoLock(&resourceLock); - if (font.m_hObject) { - font.DeleteObject(); - } - CMPCThemeUtil::getFontByType(font, AfxGetMainWnd(), CMPCThemeUtil::MenuFont); - if (symbolFont.m_hObject) { - symbolFont.DeleteObject(); - } - CMPCThemeUtil::getFontByFace(symbolFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 14, FW_BOLD); - if (bulletFont.m_hObject) { - bulletFont.DeleteObject(); - } - CMPCThemeUtil::getFontByFace(bulletFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 6, FW_REGULAR); - if (checkFont.m_hObject) { - checkFont.DeleteObject(); - } - CMPCThemeUtil::getFontByFace(checkFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 10, FW_REGULAR); - } - hasDimensions = true; - } -} - -UINT CMPCThemeMenu::findID(UINT& nPos, bool byCommand) -{ - int iMaxItems = GetMenuItemCount(); - - UINT nID; - if (byCommand) { - nID = nPos; - bool found = false; - for (int j = 0; j < iMaxItems; j++) { - if (nID == GetMenuItemID(j)) { - nPos = j; - found = true; - break; - } - } - if (!found) { - return (UINT) - 1; - } - } else { - nID = GetMenuItemID(nPos); - if (nID == 0xFFFFFFFF) { //submenu, have to find the old-fashioned way - MENUITEMINFO mii = { sizeof(mii) }; - mii.fMask = MIIM_ID; - GetMenuItemInfo(nPos, &mii, TRUE); - nID = mii.wID; - } - } - return nID; -} - -void CMPCThemeMenu::cleanupItem(UINT nPosition, UINT nFlags) -{ - if (AppIsThemeLoaded()) { - MENUITEMINFO tInfo = { sizeof(MENUITEMINFO) }; - tInfo.fMask = MIIM_DATA; - GetMenuItemInfo(nPosition, &tInfo, 0 != (nFlags & MF_BYPOSITION)); - MenuObject* pObject = (MenuObject*)tInfo.dwItemData; - if (std::find(allocatedItems.begin(), allocatedItems.end(), pObject) != allocatedItems.end()) { - allocatedItems.erase(std::remove(allocatedItems.begin(), allocatedItems.end(), pObject), allocatedItems.end()); - delete pObject; - } - } -} - -BOOL CMPCThemeMenu::DeleteMenu(UINT nPosition, UINT nFlags) -{ - cleanupItem(nPosition, nFlags); - return CMenu::DeleteMenu(nPosition, nFlags); -} - -BOOL CMPCThemeMenu::RemoveMenu(UINT nPosition, UINT nFlags) -{ - cleanupItem(nPosition, nFlags); - if (nFlags & MF_BYPOSITION) { - CMenu *t = GetSubMenu(nPosition); - if (t) { - t->Detach(); - if (std::find(allocatedMenus.begin(), allocatedMenus.end(), t) != allocatedMenus.end()) { - allocatedMenus.erase(std::remove(allocatedMenus.begin(), allocatedMenus.end(), t), allocatedMenus.end()); - delete t; - } - } - } - return CMenu::RemoveMenu(nPosition, nFlags); -} - -BOOL CMPCThemeMenu::SetThemedMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos) { - bool rebuildData = false; - bool isMenuBar = false; - if (AppIsThemeLoaded()) { - MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; - mii.fMask = MIIM_DATA; - CMenu::GetMenuItemInfo(uItem, &mii, fByPos); - rebuildData = (0 != (lpMenuItemInfo->fMask & (MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING))); - if (mii.dwItemData && rebuildData) { - MenuObject* tm = (MenuObject*)mii.dwItemData; - isMenuBar = tm->isMenubar; - lpMenuItemInfo->fMask |= MIIM_DATA; - lpMenuItemInfo->dwItemData = 0; - cleanupItem(uItem, fByPos ? MF_BYPOSITION : MF_BYCOMMAND); - } - } - - BOOL ret = CMenu::SetMenuItemInfo(uItem, lpMenuItemInfo, fByPos); - - if (rebuildData) { - fulfillThemeReqsItem((UINT)uItem, !fByPos, isMenuBar); - } - return ret; -} - -BOOL CMPCThemeMenu::SetThemedMenuItemInfo(CMenu* menu, UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos) { - if (menu) { - if (AppIsThemeLoaded()) { - CMPCThemeMenu *tMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, menu); - if (nullptr != tMenu) { - return tMenu->SetThemedMenuItemInfo(uItem, lpMenuItemInfo, fByPos); - } - } else { - return menu->SetMenuItemInfo(uItem, lpMenuItemInfo, fByPos); - } - } - return 0; -} - -BOOL CMPCThemeMenu::AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, LPCTSTR lpszNewItem) -{ - BOOL ret = CMenu::AppendMenu(nFlags, nIDNewItem, lpszNewItem); - UINT numItems = GetMenuItemCount(); - if (numItems > 0) { - //this guarantees we will find the item just inserted, in case id is not unique (0) - fulfillThemeReqsItem(numItems - 1); - } - return ret; -} - -void CMPCThemeMenu::fulfillThemeReqs(bool isMenubar) -{ - if (AppIsThemeLoaded()) { - MENUINFO oldInfo = { sizeof(MENUINFO) }; - oldInfo.fMask = MIM_STYLE; - GetMenuInfo(&oldInfo); - - MENUINFO MenuInfo = { 0 }; - MenuInfo.cbSize = sizeof(MENUINFO); - MenuInfo.fMask = MIM_BACKGROUND | MIM_STYLE | MIM_APPLYTOSUBMENUS; - MenuInfo.dwStyle = oldInfo.dwStyle; - if (!bgBrush) { - bgBrush = ::CreateSolidBrush(CMPCTheme::MenuBGColor); - } - if (!bgMenubarBrush) { - bgMenubarBrush = ::CreateSolidBrush(CMPCTheme::MenubarBGColor); - } - if (isMenubar) { - MenuInfo.hbrBack = bgMenubarBrush; - } else { - MenuInfo.hbrBack = bgBrush; - } - SetMenuInfo(&MenuInfo); - - int iMaxItems = GetMenuItemCount(); - for (int i = 0; i < iMaxItems; i++) { - CString nameHolder; - MenuObject* pObject = DEBUG_NEW MenuObject; - allocatedItems.push_back(pObject); - pObject->m_hIcon = NULL; - pObject->isMenubar = isMenubar; - if (i == 0) { - pObject->isFirstMenuInMenuBar = true; - } - - GetMenuString(i, pObject->m_strCaption, MF_BYPOSITION); - - UINT nID = GetMenuItemID(i); - if (!isOSMenu) { - pObject->m_strAccel = CPPageAccelTbl::MakeAccelShortcutLabel(nID); - } - - subMenuIDs[nID] = this; - - MENUITEMINFO tInfo; - ZeroMemory(&tInfo, sizeof(MENUITEMINFO)); - tInfo.fMask = MIIM_FTYPE; - tInfo.cbSize = sizeof(MENUITEMINFO); - GetMenuItemInfo(i, &tInfo, true); - - if (tInfo.fType & MFT_SEPARATOR) { - pObject->isSeparator = true; - } - - MENUITEMINFO mInfo; - ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); - - mInfo.fMask = MIIM_FTYPE | MIIM_DATA; - mInfo.fType = MFT_OWNERDRAW | tInfo.fType; - mInfo.cbSize = sizeof(MENUITEMINFO); - mInfo.dwItemData = (ULONG_PTR)pObject; - CMenu::SetMenuItemInfo(i, &mInfo, true); - - CMenu* t = GetSubMenu(i); - if (nullptr != t) { - CMPCThemeMenu* pSubMenu; - pSubMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, t); - if (!pSubMenu) { - pSubMenu = DEBUG_NEW CMPCThemeMenu; - pSubMenu->setOSMenu(isOSMenu); - allocatedMenus.push_back(pSubMenu); - pSubMenu->Attach(t->Detach()); - } - pSubMenu->fulfillThemeReqs(); - } - } - } -} - -void CMPCThemeMenu::fulfillThemeReqsItem(UINT i, bool byCommand, bool isMenuBar) -{ - if (AppIsThemeLoaded()) { - MENUITEMINFO tInfo = { sizeof(MENUITEMINFO) }; - tInfo.fMask = MIIM_DATA | MIIM_FTYPE; - GetMenuItemInfo(i, &tInfo, !byCommand); - if (NULL == tInfo.dwItemData) { - CString nameHolder; - MenuObject* pObject = DEBUG_NEW MenuObject; - allocatedItems.push_back(pObject); - pObject->m_hIcon = NULL; - pObject->isMenubar = isMenuBar; - - UINT posOrCmd = byCommand ? MF_BYCOMMAND : MF_BYPOSITION; - - GetMenuString(i, pObject->m_strCaption, posOrCmd); - - UINT nPos = i; - UINT nID = findID(nPos, byCommand); - if (nID == -1) { - return; - } - - pObject->m_strAccel = CPPageAccelTbl::MakeAccelShortcutLabel(nID); - - subMenuIDs[nID] = this; - - if (tInfo.fType & MFT_SEPARATOR) { - pObject->isSeparator = true; - } - - MENUITEMINFO mInfo; - ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); - - mInfo.fMask = MIIM_FTYPE | MIIM_DATA; - mInfo.fType = MFT_OWNERDRAW | tInfo.fType; - mInfo.cbSize = sizeof(MENUITEMINFO); - mInfo.dwItemData = (ULONG_PTR)pObject; - CMenu::SetMenuItemInfo(nPos, &mInfo, true); - - CMenu* t = GetSubMenu(nPos); - if (nullptr != t) { - CMPCThemeMenu* pSubMenu; - pSubMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, t); - if (!pSubMenu) { - pSubMenu = DEBUG_NEW CMPCThemeMenu; - pSubMenu->setOSMenu(isOSMenu); - allocatedMenus.push_back(pSubMenu); - pSubMenu->Attach(t->Detach()); - } - pSubMenu->fulfillThemeReqs(); - } - } - } -} - -void CMPCThemeMenu::fulfillThemeReqsItem(CMenu* parent, UINT i, bool byCommand) -{ - CMPCThemeMenu* t; - if ((t = DYNAMIC_DOWNCAST(CMPCThemeMenu, parent)) != nullptr) { - t->fulfillThemeReqsItem(i, byCommand); - } -} - -UINT CMPCThemeMenu::getPosFromID(CMenu* parent, UINT nID) -{ - int iMaxItems = parent->GetMenuItemCount(); - for (int j = 0; j < iMaxItems; j++) { - if (nID == parent->GetMenuItemID(j)) { - return j; - } - } - return (UINT) - 1; -} - -CMPCThemeMenu* CMPCThemeMenu::getParentMenu(UINT itemID) -{ - if (subMenuIDs.count(itemID) == 1) { - CMPCThemeMenu* m = subMenuIDs.at(itemID); - /* // checks if submenu for overriding of onmeasureitem (win32 limitation). - // but mpc-hc doesn't set up some submenus until later - // which is too late for measureitem to take place - // so we return all items for measuring - MENUITEMINFO mInfo; - ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); - mInfo.fMask = MIIM_SUBMENU; - mInfo.cbSize = sizeof(MENUITEMINFO); - m->GetMenuItemInfo(itemID, &mInfo); - if (mInfo.hSubMenu) // */ - return m; - } - - return nullptr; -} - -void CMPCThemeMenu::GetRects(RECT rcItem, CRect& rectFull, CRect& rectM, CRect& rectIcon, CRect& rectText, CRect& rectArrow) -{ - rectFull.CopyRect(&rcItem); - rectM = rectFull; - rectIcon.SetRect(rectM.left, rectM.top, rectM.left + iconSpacing, rectM.bottom); - rectText.SetRect(rectM.left + iconSpacing + iconPadding, rectM.top, rectM.right - subMenuPadding, rectM.bottom); - rectArrow.SetRect(rectM.right - subMenuPadding, rectM.top, rectM.right, rectM.bottom); -} - -void CMPCThemeMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CAutoLock cAutoLock(&resourceLock); //make sure our resources are protected - if (font.m_hObject) { - MenuObject* menuObject = (MenuObject*)lpDrawItemStruct->itemData; - - MENUITEMINFO mInfo = { sizeof(MENUITEMINFO) }; - - mInfo.fMask = MIIM_FTYPE | MIIM_SUBMENU; - if (lpDrawItemStruct->itemID) { - GetMenuItemInfo(lpDrawItemStruct->itemID, &mInfo); - } else { - //itemID=0 is default for anything inserted without specifying ID (separator). - //result can be finding the first separator rather than a valid item with id=0 - MENUITEMINFO byDataInfo = { sizeof(MENUITEMINFO) }; - byDataInfo.fMask = MIIM_DATA | MIIM_ID; - for (int a = 0; a < GetMenuItemCount(); a++) { - GetMenuItemInfo((UINT)a, &byDataInfo, true); - if (byDataInfo.wID == 0 && byDataInfo.dwItemData == lpDrawItemStruct->itemData) { - GetMenuItemInfo((UINT)a, &mInfo, true); - break; - } - } - } - - CRect rectFull; - CRect rectM; - CRect rectIcon; - CRect rectText; - CRect rectArrow; - - GetRects(lpDrawItemStruct->rcItem, rectFull, rectM, rectIcon, rectText, rectArrow); - - UINT captionAlign = DT_LEFT; - - COLORREF ArrowColor = CMPCTheme::SubmenuColor; - COLORREF TextFGColor; - COLORREF TextBGColor; - COLORREF TextSelectColor; - - if (menuObject->isMenubar) { - TextBGColor = CMPCTheme::MenubarBGColor; - TextSelectColor = CMPCTheme::MenubarSelectedBGColor; - } else { - TextBGColor = CMPCTheme::MenuBGColor; - TextSelectColor = CMPCTheme::MenuSelectedColor; - } - - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - - if ((lpDrawItemStruct->itemState & ODS_DISABLED)) { - TextFGColor = CMPCTheme::MenuItemDisabledColor; - ArrowColor = CMPCTheme::MenuItemDisabledColor; - } else if (menuObject->isMenubar && GetForegroundWindow() != AfxGetMainWnd()->m_hWnd) { - TextFGColor = CMPCTheme::TextFGColorFade; - } else { - TextFGColor = CMPCTheme::TextFGColor; - } - - int oldBKMode = pDC->SetBkMode(TRANSPARENT); - pDC->FillSolidRect(&rectM, TextBGColor); - - if (menuObject->isMenubar) { - if (menuObject->isFirstMenuInMenuBar) { //clean up white borders - CRect wndSize; - ::GetClientRect(AfxGetMainWnd()->m_hWnd, &wndSize); - - CRect rectBorder(rectM.left, rectM.bottom, rectM.left + wndSize.Width(), rectM.bottom + 1); - pDC->FillSolidRect(&rectBorder, CMPCTheme::MainMenuBorderColor); - ExcludeClipRect(lpDrawItemStruct->hDC, rectBorder.left, rectBorder.top, rectBorder.right, rectBorder.bottom); - } - rectM = rectFull; - rectText = rectFull; - captionAlign = DT_CENTER; - } - - if (mInfo.fType & MFT_SEPARATOR) { - int centerOffset = (separatorHeight - 1) / 2; - CRect rectSeparator(rectM.left + separatorPadding, rectM.top + centerOffset, rectM.right - separatorPadding, rectM.top + centerOffset + 1); - pDC->FillSolidRect(&rectSeparator, CMPCTheme::MenuSeparatorColor); - } else { - COLORREF oldTextFGColor = pDC->SetTextColor(TextFGColor); - - CFont* pOldFont = pDC->GetCurrentFont(); - pDC->SelectObject(&font); - if ((lpDrawItemStruct->itemState & (ODS_SELECTED | ODS_HOTLIGHT)) && (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) { - pDC->FillSolidRect(&rectM, TextSelectColor); - } - CString left, right; - GetStrings(menuObject, left, right); - - UINT accelStyle = 0; - if (lpDrawItemStruct->itemState & ODS_NOACCEL) { //removing single &s before drawtext - accelStyle = DT_HIDEPREFIX; - } - pDC->DrawTextW(left, rectText, DT_VCENTER | captionAlign | DT_SINGLELINE | accelStyle); - - if (!menuObject->isMenubar) { - - if (right.GetLength() > 0) { - pDC->DrawTextW(right, rectText, DT_VCENTER | DT_RIGHT | DT_SINGLELINE | accelStyle); - } - - if (mInfo.hSubMenu) { - pDC->SelectObject(&symbolFont); - pDC->SetTextColor(ArrowColor); - pDC->DrawTextW(TEXT(">"), rectArrow, DT_VCENTER | DT_CENTER | DT_SINGLELINE); - } - - if (lpDrawItemStruct->itemState & ODS_CHECKED) { - CString check; - if (mInfo.fType & MFT_RADIOCHECK) { - check = TEXT("\u25CF"); //bullet - pDC->SelectObject(&bulletFont); - } else { - check = TEXT("\u2714"); //checkmark - pDC->SelectObject(&checkFont); - } - pDC->SetTextColor(TextFGColor); - pDC->DrawTextW(check, rectIcon, DT_VCENTER | DT_CENTER | DT_SINGLELINE); - } - } - - pDC->SetBkMode(oldBKMode); - pDC->SetTextColor(oldTextFGColor); - pDC->SelectObject(pOldFont); - } - ExcludeClipRect(lpDrawItemStruct->hDC, rectFull.left, rectFull.top, rectFull.right, rectFull.bottom); - } -} - -void CMPCThemeMenu::GetStrings(MenuObject* mo, CString& left, CString& right) -{ - if (mo->m_strAccel.GetLength() > 0) { - left = mo->m_strCaption; - right = mo->m_strAccel; - } else { - CString text = mo->m_strCaption; - if (!AfxExtractSubString(left, text, 0, _T('\t'))) { - left = _T(""); - } - if (!AfxExtractSubString(right, text, 1, _T('\t'))) { - right = _T(""); - } - } -} - -void CMPCThemeMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) -{ - initDimensions(); //should happen before drawitem - CAutoLock cAutoLock(&resourceLock); //make sure our resources are protected - - HWND mainWnd = AfxGetMainWnd()->GetSafeHwnd(); - HDC hDC = ::GetDC(mainWnd); - MenuObject* mo = (MenuObject*)lpMeasureItemStruct->itemData; - - if (mo->isSeparator) { - lpMeasureItemStruct->itemWidth = 0; - lpMeasureItemStruct->itemHeight = separatorHeight; - } else if (hDC) { - CSize height = CMPCThemeUtil::GetTextSize(_T("W"), hDC, &font); - if (mo->isMenubar) { - CSize cs = CMPCThemeUtil::GetTextSize(mo->m_strCaption, hDC, &font); - lpMeasureItemStruct->itemWidth = cs.cx; - lpMeasureItemStruct->itemHeight = height.cy + rowPadding; - } else { - CString left, right; - GetStrings(mo, left, right); - CSize cs = CMPCThemeUtil::GetTextSize(left, hDC, &font); - lpMeasureItemStruct->itemHeight = height.cy + rowPadding; - lpMeasureItemStruct->itemWidth = iconSpacing + postTextSpacing + subMenuPadding + cs.cx; - if (right.GetLength() > 0) { - CSize csAccel = CMPCThemeUtil::GetTextSize(right, hDC, &font); - lpMeasureItemStruct->itemWidth += accelSpacing + csAccel.cx; - } - } - } - ::ReleaseDC(mainWnd, hDC); -} - -CMPCThemeMenu* CMPCThemeMenu::GetSubMenu(int nPos) -{ - return (CMPCThemeMenu*) CMenu::GetSubMenu(nPos); -} - -void CMPCThemeMenu::updateItem(CCmdUI* pCmdUI) -{ - CMenu* cm = pCmdUI->m_pMenu; - - if (DYNAMIC_DOWNCAST(CMPCThemeMenu, cm)) { - MENUITEMINFO mInfo = { sizeof(MENUITEMINFO) }; - mInfo.fMask = MIIM_DATA; - VERIFY(cm->GetMenuItemInfo(pCmdUI->m_nID, &mInfo)); - - MenuObject* menuObject = (MenuObject*)mInfo.dwItemData; - cm->GetMenuString(pCmdUI->m_nID, menuObject->m_strCaption, MF_BYCOMMAND); - } -} +#include "stdafx.h" +#include "CMPCThemeMenu.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include +#include "AppSettings.h" +#include "PPageAccelTbl.h" +#include "mplayerc.h" + +std::map CMPCThemeMenu::subMenuIDs; +HBRUSH CMPCThemeMenu::bgBrush = 0; +HBRUSH CMPCThemeMenu::bgMenubarBrush = 0; +CFont CMPCThemeMenu::font; +CFont CMPCThemeMenu::symbolFont; +CFont CMPCThemeMenu::bulletFont; +CFont CMPCThemeMenu::checkFont; +bool CMPCThemeMenu::hasDimensions = false; +int CMPCThemeMenu::subMenuPadding; +int CMPCThemeMenu::iconSpacing; +int CMPCThemeMenu::iconPadding; +int CMPCThemeMenu::rowPadding; +int CMPCThemeMenu::separatorPadding; +int CMPCThemeMenu::separatorHeight; +int CMPCThemeMenu::postTextSpacing; +int CMPCThemeMenu::accelSpacing; +CCritSec CMPCThemeMenu::resourceLock; +std::mutex CMPCThemeMenu::submenuMutex; + +IMPLEMENT_DYNAMIC(CMPCThemeMenu, CMenu); +CMPCThemeMenu::CMPCThemeMenu() +{ +} + +CMPCThemeMenu::~CMPCThemeMenu() +{ + { + std::lock_guard guard(submenuMutex); + std::map::iterator itr = subMenuIDs.begin(); + while (itr != subMenuIDs.end()) { + if (itr->second == this) { + itr = subMenuIDs.erase(itr); + } else { + ++itr; + } + } + } + + for (u_int i = 0; i < allocatedItems.size(); i++) { + delete allocatedItems[i]; + } + for (u_int i = 0; i < allocatedMenus.size(); i++) { + allocatedMenus[i]->Detach(); + delete allocatedMenus[i]; + } +} + +void CMPCThemeMenu::initDimensions() +{ + if (!hasDimensions) { + DpiHelper dpi = DpiHelper(); + dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); + + subMenuPadding = dpi.ScaleX(20); + iconSpacing = dpi.ScaleX(22); + iconPadding = dpi.ScaleX(10); + rowPadding = dpi.ScaleY(4) + 3; //windows 10 explorer has paddings of 7,8,9,9,11--this yields 7,8,9,10,11 + separatorPadding = dpi.ScaleX(8); + separatorHeight = dpi.ScaleX(7); + postTextSpacing = dpi.ScaleX(20); + accelSpacing = dpi.ScaleX(30); + { + CAutoLock cAutoLock(&resourceLock); + if (font.m_hObject) { + font.DeleteObject(); + } + CMPCThemeUtil::getFontByType(font, AfxGetMainWnd(), CMPCThemeUtil::MenuFont); + if (symbolFont.m_hObject) { + symbolFont.DeleteObject(); + } + CMPCThemeUtil::getFontByFace(symbolFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 14, FW_BOLD); + if (bulletFont.m_hObject) { + bulletFont.DeleteObject(); + } + CMPCThemeUtil::getFontByFace(bulletFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 6, FW_REGULAR); + if (checkFont.m_hObject) { + checkFont.DeleteObject(); + } + CMPCThemeUtil::getFontByFace(checkFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 10, FW_REGULAR); + } + hasDimensions = true; + } +} + +UINT CMPCThemeMenu::findID(UINT& nPos, bool byCommand) +{ + int iMaxItems = GetMenuItemCount(); + + UINT nID; + if (byCommand) { + nID = nPos; + bool found = false; + for (int j = 0; j < iMaxItems; j++) { + if (nID == GetMenuItemID(j)) { + nPos = j; + found = true; + break; + } + } + if (!found) { + return (UINT) - 1; + } + } else { + nID = GetMenuItemID(nPos); + if (nID == 0xFFFFFFFF) { //submenu, have to find the old-fashioned way + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_ID; + GetMenuItemInfo(nPos, &mii, TRUE); + nID = mii.wID; + } + } + return nID; +} + +void CMPCThemeMenu::cleanupItem(UINT nPosition, UINT nFlags) +{ + if (AppIsThemeLoaded()) { + MENUITEMINFO tInfo = { sizeof(MENUITEMINFO) }; + tInfo.fMask = MIIM_DATA; + GetMenuItemInfo(nPosition, &tInfo, 0 != (nFlags & MF_BYPOSITION)); + MenuObject* pObject = (MenuObject*)tInfo.dwItemData; + if (std::find(allocatedItems.begin(), allocatedItems.end(), pObject) != allocatedItems.end()) { + allocatedItems.erase(std::remove(allocatedItems.begin(), allocatedItems.end(), pObject), allocatedItems.end()); + delete pObject; + } + } +} + +BOOL CMPCThemeMenu::DeleteMenu(UINT nPosition, UINT nFlags) +{ + cleanupItem(nPosition, nFlags); + return CMenu::DeleteMenu(nPosition, nFlags); +} + +BOOL CMPCThemeMenu::RemoveMenu(UINT nPosition, UINT nFlags) +{ + cleanupItem(nPosition, nFlags); + if (nFlags & MF_BYPOSITION) { + CMenu *t = GetSubMenu(nPosition); + if (t) { + t->Detach(); + if (std::find(allocatedMenus.begin(), allocatedMenus.end(), t) != allocatedMenus.end()) { + allocatedMenus.erase(std::remove(allocatedMenus.begin(), allocatedMenus.end(), t), allocatedMenus.end()); + delete t; + } + } + } + return CMenu::RemoveMenu(nPosition, nFlags); +} + +BOOL CMPCThemeMenu::SetThemedMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos) { + bool rebuildData = false; + bool isMenuBar = false; + if (AppIsThemeLoaded()) { + MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; + mii.fMask = MIIM_DATA; + CMenu::GetMenuItemInfo(uItem, &mii, fByPos); + rebuildData = (0 != (lpMenuItemInfo->fMask & (MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING))); + if (mii.dwItemData && rebuildData) { + MenuObject* tm = (MenuObject*)mii.dwItemData; + isMenuBar = tm->isMenubar; + lpMenuItemInfo->fMask |= MIIM_DATA; + lpMenuItemInfo->dwItemData = 0; + cleanupItem(uItem, fByPos ? MF_BYPOSITION : MF_BYCOMMAND); + } + } + + BOOL ret = CMenu::SetMenuItemInfo(uItem, lpMenuItemInfo, fByPos); + + if (rebuildData) { + fulfillThemeReqsItem((UINT)uItem, !fByPos, isMenuBar); + } + return ret; +} + +BOOL CMPCThemeMenu::SetThemedMenuItemInfo(CMenu* menu, UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos) { + if (menu) { + if (AppIsThemeLoaded()) { + CMPCThemeMenu *tMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, menu); + if (nullptr != tMenu) { + return tMenu->SetThemedMenuItemInfo(uItem, lpMenuItemInfo, fByPos); + } + } else { + return menu->SetMenuItemInfo(uItem, lpMenuItemInfo, fByPos); + } + } + return 0; +} + +BOOL CMPCThemeMenu::AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, LPCTSTR lpszNewItem) +{ + BOOL ret = CMenu::AppendMenu(nFlags, nIDNewItem, lpszNewItem); + UINT numItems = GetMenuItemCount(); + if (numItems > 0) { + //this guarantees we will find the item just inserted, in case id is not unique (0) + fulfillThemeReqsItem(numItems - 1); + } + return ret; +} + +void CMPCThemeMenu::fulfillThemeReqs(bool isMenubar) +{ + if (AppIsThemeLoaded()) { + MENUINFO oldInfo = { sizeof(MENUINFO) }; + oldInfo.fMask = MIM_STYLE; + GetMenuInfo(&oldInfo); + + MENUINFO MenuInfo = { 0 }; + MenuInfo.cbSize = sizeof(MENUINFO); + MenuInfo.fMask = MIM_BACKGROUND | MIM_STYLE | MIM_APPLYTOSUBMENUS; + MenuInfo.dwStyle = oldInfo.dwStyle; + if (!bgBrush) { + bgBrush = ::CreateSolidBrush(CMPCTheme::MenuBGColor); + } + if (!bgMenubarBrush) { + bgMenubarBrush = ::CreateSolidBrush(CMPCTheme::MenubarBGColor); + } + if (isMenubar) { + MenuInfo.hbrBack = bgMenubarBrush; + } else { + MenuInfo.hbrBack = bgBrush; + } + SetMenuInfo(&MenuInfo); + + int iMaxItems = GetMenuItemCount(); + for (int i = 0; i < iMaxItems; i++) { + CString nameHolder; + MenuObject* pObject = DEBUG_NEW MenuObject; + allocatedItems.push_back(pObject); + pObject->m_hIcon = NULL; + pObject->isMenubar = isMenubar; + if (i == 0) { + pObject->isFirstMenuInMenuBar = true; + } + + GetMenuString(i, pObject->m_strCaption, MF_BYPOSITION); + + UINT nID = GetMenuItemID(i); + if (!isOSMenu) { + pObject->m_strAccel = CPPageAccelTbl::MakeAccelShortcutLabel(nID); + } + + subMenuIDs[nID] = this; + + MENUITEMINFO tInfo; + ZeroMemory(&tInfo, sizeof(MENUITEMINFO)); + tInfo.fMask = MIIM_FTYPE; + tInfo.cbSize = sizeof(MENUITEMINFO); + GetMenuItemInfo(i, &tInfo, true); + + if (tInfo.fType & MFT_SEPARATOR) { + pObject->isSeparator = true; + } + + MENUITEMINFO mInfo; + ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); + + mInfo.fMask = MIIM_FTYPE | MIIM_DATA; + mInfo.fType = MFT_OWNERDRAW | tInfo.fType; + mInfo.cbSize = sizeof(MENUITEMINFO); + mInfo.dwItemData = (ULONG_PTR)pObject; + CMenu::SetMenuItemInfo(i, &mInfo, true); + + CMenu* t = GetSubMenu(i); + if (nullptr != t) { + CMPCThemeMenu* pSubMenu; + pSubMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, t); + if (!pSubMenu) { + pSubMenu = DEBUG_NEW CMPCThemeMenu; + pSubMenu->setOSMenu(isOSMenu); + allocatedMenus.push_back(pSubMenu); + pSubMenu->Attach(t->Detach()); + } + pSubMenu->fulfillThemeReqs(); + } + } + } +} + +void CMPCThemeMenu::fulfillThemeReqsItem(UINT i, bool byCommand, bool isMenuBar) +{ + if (AppIsThemeLoaded()) { + MENUITEMINFO tInfo = { sizeof(MENUITEMINFO) }; + tInfo.fMask = MIIM_DATA | MIIM_FTYPE; + GetMenuItemInfo(i, &tInfo, !byCommand); + if (NULL == tInfo.dwItemData) { + CString nameHolder; + MenuObject* pObject = DEBUG_NEW MenuObject; + allocatedItems.push_back(pObject); + pObject->m_hIcon = NULL; + pObject->isMenubar = isMenuBar; + + UINT posOrCmd = byCommand ? MF_BYCOMMAND : MF_BYPOSITION; + + GetMenuString(i, pObject->m_strCaption, posOrCmd); + + UINT nPos = i; + UINT nID = findID(nPos, byCommand); + if (nID == -1) { + return; + } + + pObject->m_strAccel = CPPageAccelTbl::MakeAccelShortcutLabel(nID); + + subMenuIDs[nID] = this; + + if (tInfo.fType & MFT_SEPARATOR) { + pObject->isSeparator = true; + } + + MENUITEMINFO mInfo; + ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); + + mInfo.fMask = MIIM_FTYPE | MIIM_DATA; + mInfo.fType = MFT_OWNERDRAW | tInfo.fType; + mInfo.cbSize = sizeof(MENUITEMINFO); + mInfo.dwItemData = (ULONG_PTR)pObject; + CMenu::SetMenuItemInfo(nPos, &mInfo, true); + + CMenu* t = GetSubMenu(nPos); + if (nullptr != t) { + CMPCThemeMenu* pSubMenu; + pSubMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, t); + if (!pSubMenu) { + pSubMenu = DEBUG_NEW CMPCThemeMenu; + pSubMenu->setOSMenu(isOSMenu); + allocatedMenus.push_back(pSubMenu); + pSubMenu->Attach(t->Detach()); + } + pSubMenu->fulfillThemeReqs(); + } + } + } +} + +void CMPCThemeMenu::fulfillThemeReqsItem(CMenu* parent, UINT i, bool byCommand) +{ + CMPCThemeMenu* t; + if ((t = DYNAMIC_DOWNCAST(CMPCThemeMenu, parent)) != nullptr) { + t->fulfillThemeReqsItem(i, byCommand); + } +} + +UINT CMPCThemeMenu::getPosFromID(CMenu* parent, UINT nID) +{ + int iMaxItems = parent->GetMenuItemCount(); + for (int j = 0; j < iMaxItems; j++) { + if (nID == parent->GetMenuItemID(j)) { + return j; + } + } + return (UINT) - 1; +} + +CMPCThemeMenu* CMPCThemeMenu::getParentMenu(UINT itemID) +{ + if (subMenuIDs.count(itemID) == 1) { + CMPCThemeMenu* m = subMenuIDs.at(itemID); + /* // checks if submenu for overriding of onmeasureitem (win32 limitation). + // but mpc-hc doesn't set up some submenus until later + // which is too late for measureitem to take place + // so we return all items for measuring + MENUITEMINFO mInfo; + ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); + mInfo.fMask = MIIM_SUBMENU; + mInfo.cbSize = sizeof(MENUITEMINFO); + m->GetMenuItemInfo(itemID, &mInfo); + if (mInfo.hSubMenu) // */ + return m; + } + + return nullptr; +} + +void CMPCThemeMenu::GetRects(RECT rcItem, CRect& rectFull, CRect& rectM, CRect& rectIcon, CRect& rectText, CRect& rectArrow) +{ + rectFull.CopyRect(&rcItem); + rectM = rectFull; + rectIcon.SetRect(rectM.left, rectM.top, rectM.left + iconSpacing, rectM.bottom); + rectText.SetRect(rectM.left + iconSpacing + iconPadding, rectM.top, rectM.right - subMenuPadding, rectM.bottom); + rectArrow.SetRect(rectM.right - subMenuPadding, rectM.top, rectM.right, rectM.bottom); +} + +void CMPCThemeMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CAutoLock cAutoLock(&resourceLock); //make sure our resources are protected + if (font.m_hObject) { + MenuObject* menuObject = (MenuObject*)lpDrawItemStruct->itemData; + + MENUITEMINFO mInfo = { sizeof(MENUITEMINFO) }; + + mInfo.fMask = MIIM_FTYPE | MIIM_SUBMENU; + if (lpDrawItemStruct->itemID) { + GetMenuItemInfo(lpDrawItemStruct->itemID, &mInfo); + } else { + //itemID=0 is default for anything inserted without specifying ID (separator). + //result can be finding the first separator rather than a valid item with id=0 + MENUITEMINFO byDataInfo = { sizeof(MENUITEMINFO) }; + byDataInfo.fMask = MIIM_DATA | MIIM_ID; + for (int a = 0; a < GetMenuItemCount(); a++) { + GetMenuItemInfo((UINT)a, &byDataInfo, true); + if (byDataInfo.wID == 0 && byDataInfo.dwItemData == lpDrawItemStruct->itemData) { + GetMenuItemInfo((UINT)a, &mInfo, true); + break; + } + } + } + + CRect rectFull; + CRect rectM; + CRect rectIcon; + CRect rectText; + CRect rectArrow; + + GetRects(lpDrawItemStruct->rcItem, rectFull, rectM, rectIcon, rectText, rectArrow); + + UINT captionAlign = DT_LEFT; + + COLORREF ArrowColor = CMPCTheme::SubmenuColor; + COLORREF TextFGColor; + COLORREF TextBGColor; + COLORREF TextSelectColor; + + if (menuObject->isMenubar) { + TextBGColor = CMPCTheme::MenubarBGColor; + TextSelectColor = CMPCTheme::MenubarSelectedBGColor; + } else { + TextBGColor = CMPCTheme::MenuBGColor; + TextSelectColor = CMPCTheme::MenuSelectedColor; + } + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + + if ((lpDrawItemStruct->itemState & ODS_DISABLED)) { + TextFGColor = CMPCTheme::MenuItemDisabledColor; + ArrowColor = CMPCTheme::MenuItemDisabledColor; + } else if (menuObject->isMenubar && GetForegroundWindow() != AfxGetMainWnd()->m_hWnd) { + TextFGColor = CMPCTheme::TextFGColorFade; + } else { + TextFGColor = CMPCTheme::TextFGColor; + } + + int oldBKMode = pDC->SetBkMode(TRANSPARENT); + pDC->FillSolidRect(&rectM, TextBGColor); + + if (menuObject->isMenubar) { + if (menuObject->isFirstMenuInMenuBar) { //clean up white borders + CRect wndSize; + ::GetClientRect(AfxGetMainWnd()->m_hWnd, &wndSize); + + CRect rectBorder(rectM.left, rectM.bottom, rectM.left + wndSize.Width(), rectM.bottom + 1); + pDC->FillSolidRect(&rectBorder, CMPCTheme::MainMenuBorderColor); + ExcludeClipRect(lpDrawItemStruct->hDC, rectBorder.left, rectBorder.top, rectBorder.right, rectBorder.bottom); + } + rectM = rectFull; + rectText = rectFull; + captionAlign = DT_CENTER; + } + + if (mInfo.fType & MFT_SEPARATOR) { + int centerOffset = (separatorHeight - 1) / 2; + CRect rectSeparator(rectM.left + separatorPadding, rectM.top + centerOffset, rectM.right - separatorPadding, rectM.top + centerOffset + 1); + pDC->FillSolidRect(&rectSeparator, CMPCTheme::MenuSeparatorColor); + } else { + COLORREF oldTextFGColor = pDC->SetTextColor(TextFGColor); + + CFont* pOldFont = pDC->GetCurrentFont(); + pDC->SelectObject(&font); + if ((lpDrawItemStruct->itemState & (ODS_SELECTED | ODS_HOTLIGHT)) && (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) { + pDC->FillSolidRect(&rectM, TextSelectColor); + } + CString left, right; + GetStrings(menuObject, left, right); + + UINT accelStyle = 0; + if (lpDrawItemStruct->itemState & ODS_NOACCEL) { //removing single &s before drawtext + accelStyle = DT_HIDEPREFIX; + } + pDC->DrawTextW(left, rectText, DT_VCENTER | captionAlign | DT_SINGLELINE | accelStyle); + + if (!menuObject->isMenubar) { + + if (right.GetLength() > 0) { + pDC->DrawTextW(right, rectText, DT_VCENTER | DT_RIGHT | DT_SINGLELINE | accelStyle); + } + + if (mInfo.hSubMenu) { + pDC->SelectObject(&symbolFont); + pDC->SetTextColor(ArrowColor); + pDC->DrawTextW(TEXT(">"), rectArrow, DT_VCENTER | DT_CENTER | DT_SINGLELINE); + } + + if (lpDrawItemStruct->itemState & ODS_CHECKED) { + CString check; + if (mInfo.fType & MFT_RADIOCHECK) { + check = TEXT("\u25CF"); //bullet + pDC->SelectObject(&bulletFont); + } else { + check = TEXT("\u2714"); //checkmark + pDC->SelectObject(&checkFont); + } + pDC->SetTextColor(TextFGColor); + pDC->DrawTextW(check, rectIcon, DT_VCENTER | DT_CENTER | DT_SINGLELINE); + } + } + + pDC->SetBkMode(oldBKMode); + pDC->SetTextColor(oldTextFGColor); + pDC->SelectObject(pOldFont); + } + ExcludeClipRect(lpDrawItemStruct->hDC, rectFull.left, rectFull.top, rectFull.right, rectFull.bottom); + } +} + +void CMPCThemeMenu::GetStrings(MenuObject* mo, CString& left, CString& right) +{ + if (mo->m_strAccel.GetLength() > 0) { + left = mo->m_strCaption; + right = mo->m_strAccel; + } else { + CString text = mo->m_strCaption; + if (!AfxExtractSubString(left, text, 0, _T('\t'))) { + left = _T(""); + } + if (!AfxExtractSubString(right, text, 1, _T('\t'))) { + right = _T(""); + } + } +} + +void CMPCThemeMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) +{ + initDimensions(); //should happen before drawitem + CAutoLock cAutoLock(&resourceLock); //make sure our resources are protected + + HWND mainWnd = AfxGetMainWnd()->GetSafeHwnd(); + HDC hDC = ::GetDC(mainWnd); + MenuObject* mo = (MenuObject*)lpMeasureItemStruct->itemData; + + if (mo->isSeparator) { + lpMeasureItemStruct->itemWidth = 0; + lpMeasureItemStruct->itemHeight = separatorHeight; + } else if (hDC) { + CSize height = CMPCThemeUtil::GetTextSize(_T("W"), hDC, &font); + if (mo->isMenubar) { + CSize cs = CMPCThemeUtil::GetTextSize(mo->m_strCaption, hDC, &font); + lpMeasureItemStruct->itemWidth = cs.cx; + lpMeasureItemStruct->itemHeight = height.cy + rowPadding; + } else { + CString left, right; + GetStrings(mo, left, right); + CSize cs = CMPCThemeUtil::GetTextSize(left, hDC, &font); + lpMeasureItemStruct->itemHeight = height.cy + rowPadding; + lpMeasureItemStruct->itemWidth = iconSpacing + postTextSpacing + subMenuPadding + cs.cx; + if (right.GetLength() > 0) { + CSize csAccel = CMPCThemeUtil::GetTextSize(right, hDC, &font); + lpMeasureItemStruct->itemWidth += accelSpacing + csAccel.cx; + } + } + } + ::ReleaseDC(mainWnd, hDC); +} + +CMPCThemeMenu* CMPCThemeMenu::GetSubMenu(int nPos) +{ + return (CMPCThemeMenu*) CMenu::GetSubMenu(nPos); +} + +void CMPCThemeMenu::updateItem(CCmdUI* pCmdUI) +{ + CMenu* cm = pCmdUI->m_pMenu; + + if (DYNAMIC_DOWNCAST(CMPCThemeMenu, cm)) { + MENUITEMINFO mInfo = { sizeof(MENUITEMINFO) }; + mInfo.fMask = MIIM_DATA; + VERIFY(cm->GetMenuItemInfo(pCmdUI->m_nID, &mInfo)); + + MenuObject* menuObject = (MenuObject*)mInfo.dwItemData; + cm->GetMenuString(pCmdUI->m_nID, menuObject->m_strCaption, MF_BYCOMMAND); + } +} diff --git a/src/mpc-hc/CMPCThemeMenu.h b/src/mpc-hc/CMPCThemeMenu.h index ecc97f4573b..28125ab9e83 100644 --- a/src/mpc-hc/CMPCThemeMenu.h +++ b/src/mpc-hc/CMPCThemeMenu.h @@ -1,63 +1,63 @@ -#pragma once -#include - -struct MenuObject { - HICON m_hIcon; - CString m_strCaption; - CString m_strAccel; - bool isMenubar = false; - bool isSeparator = false; - bool isFirstMenuInMenuBar = false; -}; - - - -class CMPCThemeMenu : public CMenu -{ - DECLARE_DYNAMIC(CMPCThemeMenu) -public: - CMPCThemeMenu(); - virtual ~CMPCThemeMenu(); - - void fulfillThemeReqs(bool menubar = false); - void fulfillThemeReqsItem(UINT i, bool byCommand = false, bool isMenuBar = false); - static void fulfillThemeReqsItem(CMenu* parent, UINT i, bool byCommand = false); - static UINT getPosFromID(CMenu* parent, UINT nID); - static CMPCThemeMenu* getParentMenu(UINT itemID); - virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); - void GetStrings(MenuObject* mo, CString& left, CString& right); - virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); - virtual BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL); - virtual BOOL DeleteMenu(UINT nPosition, UINT nFlags); - virtual BOOL RemoveMenu(UINT nPosition, UINT nFlags); - virtual BOOL SetThemedMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE); - static BOOL SetThemedMenuItemInfo(CMenu *menu, UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE); - CMPCThemeMenu* GetSubMenu(int nPos); - static void updateItem(CCmdUI* pCmdUI); - static void clearDimensions() { hasDimensions = false; }; - void setOSMenu(bool isOSMenu) { this->isOSMenu = isOSMenu; }; -protected: - static std::map subMenuIDs; - std::vector allocatedItems; - std::vector allocatedMenus; - void initDimensions(); - UINT findID(UINT& i, bool byCommand); - void cleanupItem(UINT nPosition, UINT nFlags); - bool isOSMenu = false; - - void GetRects(RECT rcItem, CRect& rectFull, CRect& rectM, CRect& rectIcon, CRect& rectText, CRect& rectArrow); - static bool hasDimensions; - static int subMenuPadding; - static int iconSpacing; - static int iconPadding; - static int rowPadding; - static int separatorPadding; - static int separatorHeight; - static int postTextSpacing; - static int accelSpacing; - static HBRUSH bgBrush, bgMenubarBrush; - static CFont font, symbolFont, bulletFont, checkFont; - static CCritSec resourceLock; - static std::mutex submenuMutex; -}; - +#pragma once +#include + +struct MenuObject { + HICON m_hIcon; + CString m_strCaption; + CString m_strAccel; + bool isMenubar = false; + bool isSeparator = false; + bool isFirstMenuInMenuBar = false; +}; + + + +class CMPCThemeMenu : public CMenu +{ + DECLARE_DYNAMIC(CMPCThemeMenu) +public: + CMPCThemeMenu(); + virtual ~CMPCThemeMenu(); + + void fulfillThemeReqs(bool menubar = false); + void fulfillThemeReqsItem(UINT i, bool byCommand = false, bool isMenuBar = false); + static void fulfillThemeReqsItem(CMenu* parent, UINT i, bool byCommand = false); + static UINT getPosFromID(CMenu* parent, UINT nID); + static CMPCThemeMenu* getParentMenu(UINT itemID); + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + void GetStrings(MenuObject* mo, CString& left, CString& right); + virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); + virtual BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL); + virtual BOOL DeleteMenu(UINT nPosition, UINT nFlags); + virtual BOOL RemoveMenu(UINT nPosition, UINT nFlags); + virtual BOOL SetThemedMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE); + static BOOL SetThemedMenuItemInfo(CMenu *menu, UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE); + CMPCThemeMenu* GetSubMenu(int nPos); + static void updateItem(CCmdUI* pCmdUI); + static void clearDimensions() { hasDimensions = false; }; + void setOSMenu(bool isOSMenu) { this->isOSMenu = isOSMenu; }; +protected: + static std::map subMenuIDs; + std::vector allocatedItems; + std::vector allocatedMenus; + void initDimensions(); + UINT findID(UINT& i, bool byCommand); + void cleanupItem(UINT nPosition, UINT nFlags); + bool isOSMenu = false; + + void GetRects(RECT rcItem, CRect& rectFull, CRect& rectM, CRect& rectIcon, CRect& rectText, CRect& rectArrow); + static bool hasDimensions; + static int subMenuPadding; + static int iconSpacing; + static int iconPadding; + static int rowPadding; + static int separatorPadding; + static int separatorHeight; + static int postTextSpacing; + static int accelSpacing; + static HBRUSH bgBrush, bgMenubarBrush; + static CFont font, symbolFont, bulletFont, checkFont; + static CCritSec resourceLock; + static std::mutex submenuMutex; +}; + diff --git a/src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp b/src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp index a58289d99f5..9b62367301b 100644 --- a/src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp +++ b/src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp @@ -1,21 +1,21 @@ -#include "stdafx.h" -#include "CMPCThemeMiniDockFrameWnd.h" -#include "CMPCThemeUtil.h" - -IMPLEMENT_DYNCREATE(CMPCThemeMiniDockFrameWnd, CMiniDockFrameWnd) - -BEGIN_MESSAGE_MAP(CMPCThemeMiniDockFrameWnd, CMiniDockFrameWnd) - ON_WM_CREATE() -END_MESSAGE_MAP() - - -int CMPCThemeMiniDockFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (CMiniDockFrameWnd::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - CMPCThemeUtil::enableWindows10DarkFrame(this); - - return 0; -} +#include "stdafx.h" +#include "CMPCThemeMiniDockFrameWnd.h" +#include "CMPCThemeUtil.h" + +IMPLEMENT_DYNCREATE(CMPCThemeMiniDockFrameWnd, CMiniDockFrameWnd) + +BEGIN_MESSAGE_MAP(CMPCThemeMiniDockFrameWnd, CMiniDockFrameWnd) + ON_WM_CREATE() +END_MESSAGE_MAP() + + +int CMPCThemeMiniDockFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CMiniDockFrameWnd::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + CMPCThemeUtil::enableWindows10DarkFrame(this); + + return 0; +} diff --git a/src/mpc-hc/CMPCThemeMiniDockFrameWnd.h b/src/mpc-hc/CMPCThemeMiniDockFrameWnd.h index 5dde75a7aad..b2a5ceed78f 100644 --- a/src/mpc-hc/CMPCThemeMiniDockFrameWnd.h +++ b/src/mpc-hc/CMPCThemeMiniDockFrameWnd.h @@ -1,12 +1,12 @@ -#pragma once -#include - -class CMPCThemeMiniDockFrameWnd: - CMiniDockFrameWnd -{ - DECLARE_DYNCREATE(CMPCThemeMiniDockFrameWnd) -public: - DECLARE_MESSAGE_MAP() - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); -}; - +#pragma once +#include + +class CMPCThemeMiniDockFrameWnd: + CMiniDockFrameWnd +{ + DECLARE_DYNCREATE(CMPCThemeMiniDockFrameWnd) +public: + DECLARE_MESSAGE_MAP() + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); +}; + diff --git a/src/mpc-hc/CMPCThemeMsgBox.cpp b/src/mpc-hc/CMPCThemeMsgBox.cpp index e44fd7082b5..8f77e241f0c 100755 --- a/src/mpc-hc/CMPCThemeMsgBox.cpp +++ b/src/mpc-hc/CMPCThemeMsgBox.cpp @@ -1,82 +1,82 @@ -#include "stdafx.h" -#include "CMPCThemeMsgBox.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - - -CMPCThemeMsgBox::CMPCThemeMsgBox(CWnd* pParent, CString strMessage, CString strTitle, UINT nStyle, UINT nHelp) - : CMessageBoxDialog(pParent, strMessage, strTitle, nStyle, nHelp) -{ -} - -CMPCThemeMsgBox::CMPCThemeMsgBox(CWnd* pParent, UINT nMessageID, UINT nTitleID, UINT nStyle, UINT nHelp) - : CMessageBoxDialog(pParent, nMessageID, nTitleID, nStyle, nHelp) -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeMsgBox, CMessageBoxDialog) - -CMPCThemeMsgBox::~CMPCThemeMsgBox() -{ -} - -BOOL CMPCThemeMsgBox::OnInitDialog() -{ - BOOL ret = __super::OnInitDialog(); - fulfillThemeReqs(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return ret; -} - -BEGIN_MESSAGE_MAP(CMPCThemeMsgBox, CMessageBoxDialog) - ON_WM_CTLCOLOR() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeMsgBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} - - -BOOL CMPCThemeMsgBox::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - CRect rect, messageArea, buttonArea; - GetClientRect(&rect); - messageArea = rect; - buttonArea = rect; - messageArea.bottom = buttonAreaY; - buttonArea.top = buttonAreaY; - pDC->FillSolidRect(messageArea, CMPCTheme::WindowBGColor); - pDC->FillSolidRect(buttonArea, CMPCTheme::StatusBarBGColor); - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} - -BOOL CMPCThemeMsgBox::MessageBoxW(CWnd* parent, LPCWSTR lpText) -{ - return CMPCThemeMsgBox::MessageBox(parent, lpText, NULL, MB_OK); -} - -BOOL CMPCThemeMsgBox::MessageBoxW(CWnd* parent, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) -{ - if (AppNeedsThemedControls()) { - CMPCThemeMsgBox dlgMessage(parent, lpText, lpCaption, uType, NULL); - return (BOOL)dlgMessage.DoModal(); - } else { - if (parent) { - return parent->MessageBoxW(lpText, lpCaption, uType); - } else { - return ::MessageBoxW(NULL, lpText, lpCaption, uType); - } - } -} +#include "stdafx.h" +#include "CMPCThemeMsgBox.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + + +CMPCThemeMsgBox::CMPCThemeMsgBox(CWnd* pParent, CString strMessage, CString strTitle, UINT nStyle, UINT nHelp) + : CMessageBoxDialog(pParent, strMessage, strTitle, nStyle, nHelp) +{ +} + +CMPCThemeMsgBox::CMPCThemeMsgBox(CWnd* pParent, UINT nMessageID, UINT nTitleID, UINT nStyle, UINT nHelp) + : CMessageBoxDialog(pParent, nMessageID, nTitleID, nStyle, nHelp) +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeMsgBox, CMessageBoxDialog) + +CMPCThemeMsgBox::~CMPCThemeMsgBox() +{ +} + +BOOL CMPCThemeMsgBox::OnInitDialog() +{ + BOOL ret = __super::OnInitDialog(); + fulfillThemeReqs(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return ret; +} + +BEGIN_MESSAGE_MAP(CMPCThemeMsgBox, CMessageBoxDialog) + ON_WM_CTLCOLOR() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeMsgBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} + + +BOOL CMPCThemeMsgBox::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + CRect rect, messageArea, buttonArea; + GetClientRect(&rect); + messageArea = rect; + buttonArea = rect; + messageArea.bottom = buttonAreaY; + buttonArea.top = buttonAreaY; + pDC->FillSolidRect(messageArea, CMPCTheme::WindowBGColor); + pDC->FillSolidRect(buttonArea, CMPCTheme::StatusBarBGColor); + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} + +BOOL CMPCThemeMsgBox::MessageBoxW(CWnd* parent, LPCWSTR lpText) +{ + return CMPCThemeMsgBox::MessageBox(parent, lpText, NULL, MB_OK); +} + +BOOL CMPCThemeMsgBox::MessageBoxW(CWnd* parent, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) +{ + if (AppNeedsThemedControls()) { + CMPCThemeMsgBox dlgMessage(parent, lpText, lpCaption, uType, NULL); + return (BOOL)dlgMessage.DoModal(); + } else { + if (parent) { + return parent->MessageBoxW(lpText, lpCaption, uType); + } else { + return ::MessageBoxW(NULL, lpText, lpCaption, uType); + } + } +} diff --git a/src/mpc-hc/CMPCThemeMsgBox.h b/src/mpc-hc/CMPCThemeMsgBox.h index 195fdee320c..0fda73e97c0 100755 --- a/src/mpc-hc/CMPCThemeMsgBox.h +++ b/src/mpc-hc/CMPCThemeMsgBox.h @@ -1,20 +1,20 @@ -#pragma once -#include "MessageBoxDialog/MessageBoxDialog.h" -#include "CMPCThemeUtil.h" - -class CMPCThemeMsgBox : public CMessageBoxDialog, public CMPCThemeUtil -{ -public: - CMPCThemeMsgBox(CWnd* pParent, CString strMessage, CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0); - CMPCThemeMsgBox(CWnd* pParent, UINT nMessageID, UINT nTitleID = 0, UINT nStyle = MB_OK, UINT nHelp = 0); - DECLARE_DYNAMIC(CMPCThemeMsgBox) - virtual ~CMPCThemeMsgBox(); - BOOL OnInitDialog(); - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - static BOOL MessageBoxW(CWnd* parent, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); - static BOOL MessageBoxW(CWnd* parent, LPCWSTR lpText); - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; - +#pragma once +#include "MessageBoxDialog/MessageBoxDialog.h" +#include "CMPCThemeUtil.h" + +class CMPCThemeMsgBox : public CMessageBoxDialog, public CMPCThemeUtil +{ +public: + CMPCThemeMsgBox(CWnd* pParent, CString strMessage, CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0); + CMPCThemeMsgBox(CWnd* pParent, UINT nMessageID, UINT nTitleID = 0, UINT nStyle = MB_OK, UINT nHelp = 0); + DECLARE_DYNAMIC(CMPCThemeMsgBox) + virtual ~CMPCThemeMsgBox(); + BOOL OnInitDialog(); + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + static BOOL MessageBoxW(CWnd* parent, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); + static BOOL MessageBoxW(CWnd* parent, LPCWSTR lpText); + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; + diff --git a/src/mpc-hc/CMPCThemePPageBase.cpp b/src/mpc-hc/CMPCThemePPageBase.cpp index 4f2f95430af..48caf8c829d 100755 --- a/src/mpc-hc/CMPCThemePPageBase.cpp +++ b/src/mpc-hc/CMPCThemePPageBase.cpp @@ -1,89 +1,89 @@ -#include "stdafx.h" -#include "CMPCThemePPageBase.h" -#include "CMPCTheme.h" -#include "ImageGrayer.h" -#include "mplayerc.h" - -IMPLEMENT_DYNAMIC(CMPCThemePPageBase, CPPageBase) - -CMPCThemePPageBase::CMPCThemePPageBase(UINT nIDTemplate, UINT nIDCaption) - : CPPageBase(nIDTemplate, nIDCaption) -{ -} - - -CMPCThemePPageBase::~CMPCThemePPageBase() -{ -} - -BOOL CMPCThemePPageBase::OnInitDialog() -{ - __super::OnInitDialog(); - fulfillThemeReqs(); - return 0; -} - -void CMPCThemePPageBase::SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle) -{ - if (AppIsThemeLoaded()) { - if (!m_buttonIcons.count(iconDef)) { - CImage img, imgEnabled, imgDisabled; - if (iconDef.svgTargetWidth) { - SVGImage::LoadIconDef(iconDef, img); - } else { - img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); - } - - ImageGrayer::UpdateColor(img, imgEnabled, false, colorStyle); - ImageGrayer::UpdateColor(img, imgDisabled, true, colorStyle); - - CImageList& imageList = m_buttonIcons[iconDef]; - imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 2, 0); - imageList.Add(CBitmap::FromHandle(imgEnabled), nullptr); - imageList.Add(CBitmap::FromHandle(imgDisabled), nullptr); - } - - BUTTON_IMAGELIST buttonImageList; - buttonImageList.himl = m_buttonIcons[iconDef]; - buttonImageList.margin = { 0, 0, 0, 0 }; - buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; - static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); - } else { - CPPageBase::SetButtonIcon(nIDButton, iconDef); - } -} - - -BEGIN_MESSAGE_MAP(CMPCThemePPageBase, CPPageBase) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemePPageBase::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} - -BOOL CMPCThemePPageBase::PreTranslateMessage(MSG* pMsg) { - RelayThemedDialogTooltip(pMsg); - return __super::PreTranslateMessage(pMsg); -} - -CPPageBase* CMPCThemePPageBase::FindSiblingPage(CRuntimeClass* pClass) { - CPropertySheet* parent = (CPropertySheet*)GetParent(); - int count = parent->GetPageCount(); - for (int i = 0; i < count; i++) { - CPropertyPage* page = parent->GetPage(i); - CPPageBase *pb = (CPPageBase*)AfxDynamicDownCast(pClass, page); - if (::IsWindow(pb->GetSafeHwnd())) { - return pb; - } - } - return nullptr; -} +#include "stdafx.h" +#include "CMPCThemePPageBase.h" +#include "CMPCTheme.h" +#include "ImageGrayer.h" +#include "mplayerc.h" + +IMPLEMENT_DYNAMIC(CMPCThemePPageBase, CPPageBase) + +CMPCThemePPageBase::CMPCThemePPageBase(UINT nIDTemplate, UINT nIDCaption) + : CPPageBase(nIDTemplate, nIDCaption) +{ +} + + +CMPCThemePPageBase::~CMPCThemePPageBase() +{ +} + +BOOL CMPCThemePPageBase::OnInitDialog() +{ + __super::OnInitDialog(); + fulfillThemeReqs(); + return 0; +} + +void CMPCThemePPageBase::SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle) +{ + if (AppIsThemeLoaded()) { + if (!m_buttonIcons.count(iconDef)) { + CImage img, imgEnabled, imgDisabled; + if (iconDef.svgTargetWidth) { + SVGImage::LoadIconDef(iconDef, img); + } else { + img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); + } + + ImageGrayer::UpdateColor(img, imgEnabled, false, colorStyle); + ImageGrayer::UpdateColor(img, imgDisabled, true, colorStyle); + + CImageList& imageList = m_buttonIcons[iconDef]; + imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 2, 0); + imageList.Add(CBitmap::FromHandle(imgEnabled), nullptr); + imageList.Add(CBitmap::FromHandle(imgDisabled), nullptr); + } + + BUTTON_IMAGELIST buttonImageList; + buttonImageList.himl = m_buttonIcons[iconDef]; + buttonImageList.margin = { 0, 0, 0, 0 }; + buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; + static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); + } else { + CPPageBase::SetButtonIcon(nIDButton, iconDef); + } +} + + +BEGIN_MESSAGE_MAP(CMPCThemePPageBase, CPPageBase) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemePPageBase::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} + +BOOL CMPCThemePPageBase::PreTranslateMessage(MSG* pMsg) { + RelayThemedDialogTooltip(pMsg); + return __super::PreTranslateMessage(pMsg); +} + +CPPageBase* CMPCThemePPageBase::FindSiblingPage(CRuntimeClass* pClass) { + CPropertySheet* parent = (CPropertySheet*)GetParent(); + int count = parent->GetPageCount(); + for (int i = 0; i < count; i++) { + CPropertyPage* page = parent->GetPage(i); + CPPageBase *pb = (CPPageBase*)AfxDynamicDownCast(pClass, page); + if (::IsWindow(pb->GetSafeHwnd())) { + return pb; + } + } + return nullptr; +} diff --git a/src/mpc-hc/CMPCThemePPageBase.h b/src/mpc-hc/CMPCThemePPageBase.h index 28d0cd2c917..a7daab3c3f7 100755 --- a/src/mpc-hc/CMPCThemePPageBase.h +++ b/src/mpc-hc/CMPCThemePPageBase.h @@ -1,24 +1,24 @@ -#pragma once -#include "PPageBase.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeUtil.h" -#include "ImageGrayer.h" -class CMPCThemePPageBase : - public CPPageBase, public CMPCThemeUtil -{ - DECLARE_DYNAMIC(CMPCThemePPageBase) -public: - CMPCThemePPageBase(UINT nIDTemplate, UINT nIDCaption); - virtual ~CMPCThemePPageBase(); - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - virtual BOOL OnInitDialog(); - virtual void AdjustDynamicWidgets() {}; - void SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle = ImageGrayer::mpcMono); - BOOL PreTranslateMessage(MSG* pMsg); - CPPageBase* FindSiblingPage(CRuntimeClass* pClass); -}; - +#pragma once +#include "PPageBase.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeUtil.h" +#include "ImageGrayer.h" +class CMPCThemePPageBase : + public CPPageBase, public CMPCThemeUtil +{ + DECLARE_DYNAMIC(CMPCThemePPageBase) +public: + CMPCThemePPageBase(UINT nIDTemplate, UINT nIDCaption); + virtual ~CMPCThemePPageBase(); + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + virtual BOOL OnInitDialog(); + virtual void AdjustDynamicWidgets() {}; + void SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle = ImageGrayer::mpcMono); + BOOL PreTranslateMessage(MSG* pMsg); + CPPageBase* FindSiblingPage(CRuntimeClass* pClass); +}; + diff --git a/src/mpc-hc/CMPCThemePlayerBar.cpp b/src/mpc-hc/CMPCThemePlayerBar.cpp index 00f3fb3f0bd..b23a8448f91 100755 --- a/src/mpc-hc/CMPCThemePlayerBar.cpp +++ b/src/mpc-hc/CMPCThemePlayerBar.cpp @@ -1,141 +1,141 @@ -#include "stdafx.h" -#include "CMPCThemePlayerBar.h" -#include "mplayerc.h" -#include "CMPCTheme.h" -#include "MainFrm.h" - -CMPCThemePlayerBar::CMPCThemePlayerBar(CMainFrame* pMainFrame) - :m_pMainFrame(pMainFrame) -{ - InitializeSize(); -} - -CMPCThemePlayerBar::~CMPCThemePlayerBar() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemePlayerBar, CPlayerBar) - -BEGIN_MESSAGE_MAP(CMPCThemePlayerBar, CPlayerBar) - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -void CMPCThemePlayerBar::InitializeSize() { - auto& dpi = m_pMainFrame->m_dpi; - int buttonDim = CMPCThemeUtil::getConstantByDPI(m_pMainFrame, CMPCTheme::ToolbarHideButtonDimensions); - m_cyGripper = buttonDim + dpi.ScaleX(2); - m_biHide.SetDpiSize(CSize(buttonDim, buttonDim)); -} - -BOOL CMPCThemePlayerBar::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - CRect rect; - pDC->GetClipBox(&rect); - pDC->FillSolidRect(rect.left, rect.top, rect.Width(), rect.Height(), CMPCTheme::WindowBGColor); - - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} - -void CMPCThemePlayerBar::paintHideButton(CDC* pDC, CSCBButton b) //derived from CSCBButton::Paint -{ - CRect rc = b.GetRect(); - - if (b.bPushed) { - pDC->FillSolidRect(rc, CMPCTheme::ClosePushColor); - } else if (b.bRaised) { - pDC->FillSolidRect(rc, CMPCTheme::CloseHoverColor); - } - - auto& dpi = m_pMainFrame->m_dpi; - - CMPCThemeUtil::drawToolbarHideButton(pDC, this, rc, CMPCThemeUtil::getIconPathByDPI(m_pMainFrame, TOOLBAR_HIDE_ICON), dpi.ScaleFactorX(), true, b.bPushed||b.bRaised); -} - -void CMPCThemePlayerBar::NcCalcClient(LPRECT pRc, UINT nDockBarID) { //derived from CSizingControlBarG::NcCalcClient to support DPI changes - CRect rcBar(pRc); // save the bar rect - - // subtract edges - baseCSizingControlBarG::NcCalcClient(pRc, nDockBarID); - - if (!HasGripper()) - return; - - CRect rc(pRc); // the client rect as calculated by the base class - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ClientToScreen(rcBar); - GetParent()->ClientToScreen(rc); - - BOOL bHorz = (nDockBarID == AFX_IDW_DOCKBAR_TOP) || - (nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); - - if (bHorz) - rc.DeflateRect(m_cyGripper, 0, 0, 0); - else - rc.DeflateRect(0, m_cyGripper, 0, 0); - - auto& dpi = m_pMainFrame->m_dpi; - - // set position for the "x" (hide bar) button - CPoint ptOrgBtn; - if (bHorz) - ptOrgBtn = CPoint(rc.left - dpi.ScaleX(13), rc.top); - else - ptOrgBtn = CPoint(rc.right - dpi.ScaleX(12), rc.top - dpi.ScaleY(13)); - - m_biHide.Move(ptOrgBtn - rcBar.TopLeft()); - - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ScreenToClient(&rc); - - *pRc = rc; - -} - -void CMPCThemePlayerBar::NcPaintGripper(CDC* pDC, CRect rcClient) //derived from CSizingControlBarG base implementation -{ - if (!AppIsThemeLoaded()) { - __super::NcPaintGripper(pDC, rcClient); - return; - } - - if (!HasGripper()) { - return; - } - - CRect gripper = rcClient; - CRect rcbtn = m_biHide.GetRect(); - BOOL bHorz = IsHorzDocked(); - CBitmap patternBMP; - - gripper.DeflateRect(1, 1); - int gripperHeight = CMPCThemeUtil::getConstantByDPI(m_pMainFrame, CMPCTheme::ToolbarGripperHeight); - - if (bHorz) { // gripper at left - gripper.left = rcbtn.left + (rcbtn.Width() - gripperHeight) / 2; - gripper.top = rcbtn.bottom + 3; - } else { // gripper at top - gripper.top = rcbtn.top + (rcbtn.Height() - gripperHeight) / 2; - gripper.right = rcbtn.left - 3; - } - CMPCThemeUtil::drawGripper(this, m_pMainFrame, gripper, pDC, bHorz); - - paintHideButton(pDC, m_biHide); -} - -void CMPCThemePlayerBar::mpc_fillNcBG(CDC* mdc, CRect rcDraw) -{ - if (AppIsThemeLoaded()) { - if (IsFloating()) { - rcDraw.DeflateRect(1, 1); - } - mdc->FillSolidRect(rcDraw, CMPCTheme::WindowBGColor); - } else { - __super::mpc_fillNcBG(mdc, rcDraw); - } -} +#include "stdafx.h" +#include "CMPCThemePlayerBar.h" +#include "mplayerc.h" +#include "CMPCTheme.h" +#include "MainFrm.h" + +CMPCThemePlayerBar::CMPCThemePlayerBar(CMainFrame* pMainFrame) + :m_pMainFrame(pMainFrame) +{ + InitializeSize(); +} + +CMPCThemePlayerBar::~CMPCThemePlayerBar() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemePlayerBar, CPlayerBar) + +BEGIN_MESSAGE_MAP(CMPCThemePlayerBar, CPlayerBar) + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +void CMPCThemePlayerBar::InitializeSize() { + auto& dpi = m_pMainFrame->m_dpi; + int buttonDim = CMPCThemeUtil::getConstantByDPI(m_pMainFrame, CMPCTheme::ToolbarHideButtonDimensions); + m_cyGripper = buttonDim + dpi.ScaleX(2); + m_biHide.SetDpiSize(CSize(buttonDim, buttonDim)); +} + +BOOL CMPCThemePlayerBar::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + CRect rect; + pDC->GetClipBox(&rect); + pDC->FillSolidRect(rect.left, rect.top, rect.Width(), rect.Height(), CMPCTheme::WindowBGColor); + + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} + +void CMPCThemePlayerBar::paintHideButton(CDC* pDC, CSCBButton b) //derived from CSCBButton::Paint +{ + CRect rc = b.GetRect(); + + if (b.bPushed) { + pDC->FillSolidRect(rc, CMPCTheme::ClosePushColor); + } else if (b.bRaised) { + pDC->FillSolidRect(rc, CMPCTheme::CloseHoverColor); + } + + auto& dpi = m_pMainFrame->m_dpi; + + CMPCThemeUtil::drawToolbarHideButton(pDC, this, rc, CMPCThemeUtil::getIconPathByDPI(m_pMainFrame, TOOLBAR_HIDE_ICON), dpi.ScaleFactorX(), true, b.bPushed||b.bRaised); +} + +void CMPCThemePlayerBar::NcCalcClient(LPRECT pRc, UINT nDockBarID) { //derived from CSizingControlBarG::NcCalcClient to support DPI changes + CRect rcBar(pRc); // save the bar rect + + // subtract edges + baseCSizingControlBarG::NcCalcClient(pRc, nDockBarID); + + if (!HasGripper()) + return; + + CRect rc(pRc); // the client rect as calculated by the base class + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ClientToScreen(rcBar); + GetParent()->ClientToScreen(rc); + + BOOL bHorz = (nDockBarID == AFX_IDW_DOCKBAR_TOP) || + (nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); + + if (bHorz) + rc.DeflateRect(m_cyGripper, 0, 0, 0); + else + rc.DeflateRect(0, m_cyGripper, 0, 0); + + auto& dpi = m_pMainFrame->m_dpi; + + // set position for the "x" (hide bar) button + CPoint ptOrgBtn; + if (bHorz) + ptOrgBtn = CPoint(rc.left - dpi.ScaleX(13), rc.top); + else + ptOrgBtn = CPoint(rc.right - dpi.ScaleX(12), rc.top - dpi.ScaleY(13)); + + m_biHide.Move(ptOrgBtn - rcBar.TopLeft()); + + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ScreenToClient(&rc); + + *pRc = rc; + +} + +void CMPCThemePlayerBar::NcPaintGripper(CDC* pDC, CRect rcClient) //derived from CSizingControlBarG base implementation +{ + if (!AppIsThemeLoaded()) { + __super::NcPaintGripper(pDC, rcClient); + return; + } + + if (!HasGripper()) { + return; + } + + CRect gripper = rcClient; + CRect rcbtn = m_biHide.GetRect(); + BOOL bHorz = IsHorzDocked(); + CBitmap patternBMP; + + gripper.DeflateRect(1, 1); + int gripperHeight = CMPCThemeUtil::getConstantByDPI(m_pMainFrame, CMPCTheme::ToolbarGripperHeight); + + if (bHorz) { // gripper at left + gripper.left = rcbtn.left + (rcbtn.Width() - gripperHeight) / 2; + gripper.top = rcbtn.bottom + 3; + } else { // gripper at top + gripper.top = rcbtn.top + (rcbtn.Height() - gripperHeight) / 2; + gripper.right = rcbtn.left - 3; + } + CMPCThemeUtil::drawGripper(this, m_pMainFrame, gripper, pDC, bHorz); + + paintHideButton(pDC, m_biHide); +} + +void CMPCThemePlayerBar::mpc_fillNcBG(CDC* mdc, CRect rcDraw) +{ + if (AppIsThemeLoaded()) { + if (IsFloating()) { + rcDraw.DeflateRect(1, 1); + } + mdc->FillSolidRect(rcDraw, CMPCTheme::WindowBGColor); + } else { + __super::mpc_fillNcBG(mdc, rcDraw); + } +} diff --git a/src/mpc-hc/CMPCThemePlayerBar.h b/src/mpc-hc/CMPCThemePlayerBar.h index 2ce7ea6261f..2e08d7a0698 100755 --- a/src/mpc-hc/CMPCThemePlayerBar.h +++ b/src/mpc-hc/CMPCThemePlayerBar.h @@ -1,22 +1,22 @@ -#pragma once -#include "PlayerBar.h" - -class CMainFrame; -class CMPCThemePlayerBar : public CPlayerBar -{ -public: - CMPCThemePlayerBar(CMainFrame* pMainFrame); - virtual ~CMPCThemePlayerBar(); - DECLARE_DYNAMIC(CMPCThemePlayerBar) - - void NcPaintGripper(CDC* pDC, CRect rcClient); - void mpc_fillNcBG(CDC* mdc, CRect rcDraw); - DECLARE_MESSAGE_MAP() - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - void InitializeSize(); - void paintHideButton(CDC* pDC, CSCBButton b); - virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); -protected: - CMainFrame* m_pMainFrame; -}; - +#pragma once +#include "PlayerBar.h" + +class CMainFrame; +class CMPCThemePlayerBar : public CPlayerBar +{ +public: + CMPCThemePlayerBar(CMainFrame* pMainFrame); + virtual ~CMPCThemePlayerBar(); + DECLARE_DYNAMIC(CMPCThemePlayerBar) + + void NcPaintGripper(CDC* pDC, CRect rcClient); + void mpc_fillNcBG(CDC* mdc, CRect rcDraw); + DECLARE_MESSAGE_MAP() + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + void InitializeSize(); + void paintHideButton(CDC* pDC, CSCBButton b); + virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); +protected: + CMainFrame* m_pMainFrame; +}; + diff --git a/src/mpc-hc/CMPCThemePlayerListCtrl.cpp b/src/mpc-hc/CMPCThemePlayerListCtrl.cpp index 4d18569a186..a4991af900c 100755 --- a/src/mpc-hc/CMPCThemePlayerListCtrl.cpp +++ b/src/mpc-hc/CMPCThemePlayerListCtrl.cpp @@ -1,633 +1,633 @@ -#include "stdafx.h" -#include "CMPCThemePlayerListCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#undef SubclassWindow - -CMPCThemePlayerListCtrl::CMPCThemePlayerListCtrl() : CListCtrl() -{ - themeGridLines = false; - fullRowSelect = false; - themedSBHelper = nullptr; - hasCheckedColors = false; - hasCBImages = false; - customThemeInterface = nullptr; - if (!CMPCThemeUtil::canUseWin10DarkTheme()) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - } -} - - -CMPCThemePlayerListCtrl::~CMPCThemePlayerListCtrl() -{ - if (nullptr != themedSBHelper) { - delete themedSBHelper; - } -} - - -void CMPCThemePlayerListCtrl::PreSubclassWindow() -{ - if (!AppNeedsThemedControls()) { - EnableToolTips(TRUE); - } else { - if (CMPCThemeUtil::canUseWin10DarkTheme()) { - SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); - } else { - SetWindowTheme(GetSafeHwnd(), L"", NULL); - } - CToolTipCtrl* t = GetToolTips(); - if (nullptr != t) { - lvsToolTip.SubclassWindow(t->m_hWnd); - } - subclassHeader(); - } - CListCtrl::PreSubclassWindow(); -} - -IMPLEMENT_DYNAMIC(CMPCThemePlayerListCtrl, CListCtrl) - -BEGIN_MESSAGE_MAP(CMPCThemePlayerListCtrl, CListCtrl) - ON_WM_NCPAINT() - ON_WM_CREATE() - ON_NOTIFY_REFLECT_EX(LVN_ENDSCROLL, OnLvnEndScroll) - ON_WM_MOUSEMOVE() - ON_WM_MOUSEWHEEL() - ON_WM_NCCALCSIZE() - ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, OnCustomDraw) - ON_WM_ERASEBKGND() - ON_WM_CTLCOLOR() - ON_NOTIFY_EX(HDN_ENDTRACKA, 0, &OnHdnEndtrack) - ON_NOTIFY_EX(HDN_ENDTRACKW, 0, &OnHdnEndtrack) - ON_NOTIFY_REFLECT_EX(LVN_ITEMCHANGED, &OnLvnItemchanged) - ON_MESSAGE(PLAYER_PLAYLIST_UPDATE_SCROLLBAR, OnDelayed_UpdateScrollbar) - ON_WM_WINDOWPOSCHANGED() -END_MESSAGE_MAP() - -void CMPCThemePlayerListCtrl::OnWindowPosChanged(WINDOWPOS* lpwndpos) { - if (AppNeedsThemedControls()) { - if (themedSBHelper && 0 != (GetStyle() & (WS_VSCROLL | WS_HSCROLL))) { - themedSBHelper->OnWindowPosChanged(); - } - } - return __super::OnWindowPosChanged(lpwndpos); -} - - -void CMPCThemePlayerListCtrl::subclassHeader() -{ - CHeaderCtrl* t = GetHeaderCtrl(); - if (nullptr != t && IsWindow(t->m_hWnd) && themedHdrCtrl.m_hWnd == NULL) { - themedHdrCtrl.SubclassWindow(t->GetSafeHwnd()); - } -} - -void CMPCThemePlayerListCtrl::setAdditionalStyles(DWORD styles) -{ - if (AppNeedsThemedControls()) { - DWORD stylesToAdd = styles, stylesToRemove = 0; - if (styles & LVS_EX_GRIDLINES) { - stylesToAdd &= ~LVS_EX_GRIDLINES; - stylesToRemove |= LVS_EX_GRIDLINES; - themeGridLines = true; - } - if (styles & LVS_EX_FULLROWSELECT) { - //we need these to remain, or else other columns may not get refreshed on a selection change. - //no regressions observed yet, but unclear why we removed this style for custom draw previously - //error was observed with playersubresyncbar - // stylesToAdd &= ~LVS_EX_FULLROWSELECT; - // stylesToRemove |= LVS_EX_FULLROWSELECT; - fullRowSelect = true; - } - if (styles & LVS_EX_DOUBLEBUFFER) { //we will buffer ourselves - stylesToAdd &= ~LVS_EX_DOUBLEBUFFER; - stylesToRemove |= LVS_EX_DOUBLEBUFFER; - } - SetExtendedStyle((GetExtendedStyle() | stylesToAdd) & ~stylesToRemove); - } else { - SetExtendedStyle(GetExtendedStyle() | styles); - } -} - -void CMPCThemePlayerListCtrl::setHasCBImages(bool on) -{ - hasCBImages = on; -} - -void CMPCThemePlayerListCtrl::setItemTextWithDefaultFlag(int nItem, int nSubItem, LPCTSTR lpszText, bool flagged) -{ - SetItemText(nItem, nSubItem, lpszText); - setFlaggedItem(nItem, flagged); -} - -void CMPCThemePlayerListCtrl::setFlaggedItem(int iItem, bool flagged) -{ - flaggedItems[iItem] = flagged; -} - -bool CMPCThemePlayerListCtrl::getFlaggedItem(int iItem) -{ - auto it = flaggedItems.find(iItem); - if (it != flaggedItems.end()) { - return it->second; - } else { - return false; - } -} - -void CMPCThemePlayerListCtrl::DoDPIChanged() -{ - if (listMPCThemeFontBold.m_hObject) { - listMPCThemeFontBold.DeleteObject(); - } - -} - - -BOOL CMPCThemePlayerListCtrl::PreTranslateMessage(MSG* pMsg) -{ - if (AppNeedsThemedControls()) { - if (!IsWindow(themedToolTip.m_hWnd)) { - themedToolTip.Create(this, TTS_ALWAYSTIP); - themedToolTip.enableFlickerHelper(); - } - if (IsWindow(themedToolTip.m_hWnd)) { - themedToolTip.RelayEvent(pMsg); - } - } - return __super::PreTranslateMessage(pMsg); -} - -void CMPCThemePlayerListCtrl::setCheckedColors(COLORREF checkedBG, COLORREF checkedText, COLORREF uncheckedText) -{ - checkedBGClr = checkedBG; - checkedTextClr = checkedText; - uncheckedTextClr = uncheckedText; - hasCheckedColors = true; -} - -void CMPCThemePlayerListCtrl::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->themedNcPaintWithSB(); - } else { - CMPCThemeScrollBarHelper::themedNcPaint(this, this); - } - } else { - __super::OnNcPaint(); - } -} - - -int CMPCThemePlayerListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (__super::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - if (AppNeedsThemedControls()) { - SetBkColor(CMPCTheme::ContentBGColor); - subclassHeader(); - } - - return 0; -} - -BOOL CMPCThemePlayerListCtrl::OnLvnEndScroll(NMHDR* pNMHDR, LRESULT* pResult) -{ - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - *pResult = 0; - } - return FALSE; -} - -void CMPCThemePlayerListCtrl::updateSB() -{ - if (nullptr != themedSBHelper) { - themedSBHelper->hideNativeScrollBars(); - } -} - -void CMPCThemePlayerListCtrl::updateScrollInfo(bool invalidate /*=false*/) -{ - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(invalidate); - } -} - -LRESULT CMPCThemePlayerListCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (AppNeedsThemedControls() && nullptr != themedSBHelper) { - if (themedSBHelper->WindowProc(this, message, wParam, lParam)) { - return 1; - } - } - return __super::WindowProc(message, wParam, lParam); -} - -void CMPCThemePlayerListCtrl::updateToolTip(CPoint point) -{ - if (AppNeedsThemedControls() && nullptr != themedToolTip) { - TOOLINFO ti = { 0 }; - UINT_PTR tid = OnToolHitTest(point, &ti); - //OnToolHitTest returns -1 on failure but doesn't update uId to match - - if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool - if (themedToolTip.GetToolCount() > 0) { - themedToolTip.DelTool(this); - themedToolTip.Activate(FALSE); - } - themedToolTipCid = (UINT_PTR) - 1; - } - - if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { - - themedToolTipCid = ti.uId; - - CRect cr; - GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate - - themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); - themedToolTip.Activate(TRUE); - } - } -} - -void CMPCThemePlayerListCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - __super::OnMouseMove(nFlags, point); - updateToolTip(point); -} - - -BOOL CMPCThemePlayerListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) -{ - BOOL ret = __super::OnMouseWheel(nFlags, zDelta, pt); - ScreenToClient(&pt); - updateToolTip(pt); - return ret; -} - - -void CMPCThemePlayerListCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) -{ - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - if (AppNeedsThemedControls()) { - if (GetStyle() & WS_HSCROLL && nullptr == themedSBHelper) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - } - ::PostMessage(m_hWnd, PLAYER_PLAYLIST_UPDATE_SCROLLBAR, (WPARAM)0, (LPARAM)TRUE); - } -} - -void CMPCThemePlayerListCtrl::drawItem(CDC* pDC, int nItem, int nSubItem) -{ - if (IsItemVisible(nItem)) { - - CRect rect, rRow, rIcon, rText, rTextBG, rectDC, rClient; - GetClientRect(rClient); - GetItemRect(nItem, rRow, LVIR_BOUNDS); - GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rText); - GetSubItemRect(nItem, nSubItem, LVIR_ICON, rIcon); - GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect); - DWORD dwStyle = GetStyle() & LVS_TYPEMASK; - - if (0 == nSubItem) { //getsubitemrect gives whole row for 0/LVIR_BOUNDS. but LVIR_LABEL is limited to text bounds. MSDN undocumented behavior - rect.right = rText.right; - } - - //issubitemvisible - if (rClient.left <= rect.right && rClient.right >= rect.left && rClient.top <= rect.bottom && rClient.bottom >= rect.top) { - COLORREF textColor = CMPCTheme::TextFGColor; - COLORREF bgColor = CMPCTheme::ContentBGColor; - COLORREF selectedBGColor = CMPCTheme::ContentSelectedColor; - - COLORREF oldTextColor = pDC->GetTextColor(); - COLORREF oldBkColor = pDC->GetBkColor(); - - CString text = GetItemText(nItem, nSubItem); - if (nullptr != customThemeInterface) { //subclasses can override colors here - bool overrideSelectedBG = false; - customThemeInterface->GetCustomTextColors(nItem, nSubItem, textColor, bgColor, overrideSelectedBG); - if (overrideSelectedBG) { - selectedBGColor = bgColor; - } - } - - pDC->SetTextColor(textColor); - pDC->SetBkColor(bgColor); - - rectDC = rRow; - CDC dcMem; - CBitmap bmMem; - CMPCThemeUtil::initMemDC(pDC, dcMem, bmMem, rectDC); - rect.OffsetRect(-rectDC.TopLeft()); - rText.OffsetRect(-rectDC.TopLeft()); - rIcon.OffsetRect(-rectDC.TopLeft()); - rRow.OffsetRect(-rectDC.TopLeft()); - - if (!IsWindowEnabled() && 0 == nSubItem) { //no gridlines, bg for full row - dcMem.FillSolidRect(rRow, CMPCTheme::ListCtrlDisabledBGColor); - } else { - dcMem.FillSolidRect(rect, CMPCTheme::ContentBGColor); //no flicker because we have a memory dc - } - - rTextBG = rText; - CHeaderCtrl* hdrCtrl = GetHeaderCtrl(); - int align = DT_LEFT; - if (nullptr != hdrCtrl) { - HDITEM hditem = { 0 }; - hditem.mask = HDI_FORMAT; - hdrCtrl->GetItem(nSubItem, &hditem); - align = hditem.fmt & HDF_JUSTIFYMASK; - } - UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX; - if (align == HDF_CENTER) { - textFormat |= DT_CENTER; - } else if (align == HDF_LEFT) { - textFormat |= DT_LEFT; - if (nSubItem == 0) {//less indent for first column - rText.left += 2; - } else { - rText.left += 6; - } - } else { - textFormat |= DT_RIGHT; - rText.right -= 6; - } - - bool isChecked = false; - int contentLeft = rText.left; - if (rIcon.Width() > 0) { - LVITEM lvi = { 0 }; - lvi.iItem = nItem; - lvi.iSubItem = 0; - lvi.mask = LVIF_IMAGE; - GetItem(&lvi); - - if (nSubItem == 0) { - contentLeft = rIcon.left; - if (hasCBImages) { //draw manually to match theme - rIcon.DeflateRect(0, 0, 1, 0); - if (rIcon.Height() > rIcon.Width()) { - rIcon.DeflateRect(0, (rIcon.Height() - rIcon.Width()) / 2); //as tall as wide - } - - CMPCThemeUtil::drawCheckBox(GetParent(), lvi.iImage, false, false, rIcon, &dcMem); - } else { - if (dwStyle == LVS_ICON) { - } else if (dwStyle == LVS_SMALLICON || dwStyle == LVS_LIST || dwStyle == LVS_REPORT) { - CImageList* ilist = GetImageList(LVSIL_SMALL); - int cx, cy; - ImageList_GetIconSize(ilist->m_hImageList, &cx, &cy); - rIcon.top += (rIcon.Height() - cy) / 2; - ilist->Draw(&dcMem, lvi.iImage, rIcon.TopLeft(), ILD_TRANSPARENT); - } - } - if (align == HDF_LEFT) { - rText.left += 2; //more ident after image - } - } - } - if (0 != (GetExtendedStyle() & LVS_EX_CHECKBOXES) && INDEXTOSTATEIMAGEMASK(0) != GetItemState(nItem, LVIS_STATEIMAGEMASK)) { - isChecked = (TRUE == GetCheck(nItem)); - if (nSubItem == 0) { - int cbSize = GetSystemMetrics(SM_CXMENUCHECK); - int cbYMargin = (rect.Height() - cbSize - 1) / 2; - int cbXMargin = (contentLeft - rect.left - cbSize) / 2; - CRect rcb = { rect.left + cbXMargin, rect.top + cbYMargin, rect.left + cbXMargin + cbSize, rect.top + cbYMargin + cbSize }; - CMPCThemeUtil::drawCheckBox(GetParent(), isChecked, false, true, rcb, &dcMem); - } - } - - if (IsWindowEnabled()) { - bool selected = false; - if (GetItemState(nItem, LVIS_SELECTED) == LVIS_SELECTED && (nSubItem == 0 || fullRowSelect) && (GetStyle() & LVS_SHOWSELALWAYS || GetFocus() == this)) { - bgColor = selectedBGColor; - if (LVS_REPORT != dwStyle) { //in list mode we don't fill the "whole" column - CRect tmp = rText; - dcMem.DrawTextW(text, tmp, textFormat | DT_CALCRECT); //end of string - rTextBG.right = tmp.right + (rText.left - rTextBG.left); //end of string plus same indent from the left side - } - selected = true; - } else if (hasCheckedColors) { - if (isChecked && checkedBGClr != -1) { - bgColor = checkedBGClr; - } - if (isChecked && checkedTextClr != -1) { - dcMem.SetTextColor(checkedTextClr); - } - if (!isChecked && uncheckedTextClr != -1) { - dcMem.SetTextColor(uncheckedTextClr); - } - } - dcMem.FillSolidRect(rTextBG, bgColor); - - if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { - CRect rGrid = rect; - rGrid.bottom -= 1; - CPen gridPenV, gridPenH, *oldPen; - if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { - COLORREF horzGridColor, vertGridColor; - customThemeInterface->GetCustomGridColors(nItem, horzGridColor, vertGridColor); - gridPenV.CreatePen(PS_SOLID, 1, vertGridColor); - gridPenH.CreatePen(PS_SOLID, 1, horzGridColor); - } else { - gridPenV.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); - gridPenH.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); - } - - oldPen = dcMem.SelectObject(&gridPenV); - if (nSubItem != 0) { - dcMem.MoveTo(rGrid.TopLeft()); - dcMem.LineTo(rGrid.left, rGrid.bottom); - } else { - dcMem.MoveTo(rGrid.left, rGrid.bottom); - } - - dcMem.SelectObject(&gridPenH); - dcMem.LineTo(rGrid.BottomRight()); - - dcMem.SelectObject(&gridPenV); - dcMem.LineTo(rGrid.right, rGrid.top); - - dcMem.SelectObject(oldPen); - gridPenV.DeleteObject(); - gridPenH.DeleteObject(); - } else if (selected) { - CBrush borderBG; - borderBG.CreateSolidBrush(CMPCTheme::ListCtrlDisabledBGColor); - dcMem.FrameRect(rTextBG, &borderBG); - borderBG.DeleteObject(); - } - } - - if (getFlaggedItem(nItem)) { //could be a setting, but flagged items are bold for now - if (!listMPCThemeFontBold.m_hObject) { - listMPCThemeFont = GetFont(); - LOGFONT lf; - listMPCThemeFont->GetLogFont(&lf); - lf.lfWeight = FW_BOLD; - listMPCThemeFontBold.CreateFontIndirect(&lf); - } - - dcMem.SelectObject(listMPCThemeFontBold); - } - dcMem.DrawTextW(text, rText, textFormat); - CMPCThemeUtil::flushMemDC(pDC, dcMem, rectDC); - pDC->SetTextColor(oldTextColor); - pDC->SetBkColor(oldBkColor); - } - } -} - -BOOL CMPCThemePlayerListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - if (AppNeedsThemedControls()) { - NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); - - *pResult = CDRF_DODEFAULT; - if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT) { - if (nullptr != customThemeInterface) { - customThemeInterface->DoCustomPrePaint(); - } - *pResult = CDRF_NOTIFYITEMDRAW; - } else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { - DWORD dwStyle = GetStyle() & LVS_TYPEMASK; - if (LVS_REPORT == dwStyle) { - *pResult = CDRF_NOTIFYSUBITEMDRAW; - } else { - int nItem = static_cast(pLVCD->nmcd.dwItemSpec); - CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); - drawItem(pDC, nItem, 0); - *pResult = CDRF_SKIPDEFAULT; - } - } else if (pLVCD->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM)) { - if (GetStyle() & LVS_OWNERDRAWFIXED) { - //found that for ownerdraw routines, we can end up here and draw both ways on hover/tooltip. this should prevent it - *pResult = CDRF_DODEFAULT; - } else { - int nItem = static_cast(pLVCD->nmcd.dwItemSpec); - if (IsItemVisible(nItem)) { - int nSubItem = pLVCD->iSubItem; - CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); - drawItem(pDC, nItem, nSubItem); - } - *pResult = CDRF_SKIPDEFAULT; - } - } - return TRUE; - } - return FALSE; -} - - -BOOL CMPCThemePlayerListCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppNeedsThemedControls()) { - CRect r; - GetClientRect(r); - int dcState = pDC->SaveDC(); - for (int y = 0; y < GetItemCount(); y++) { - CRect clip; - GetItemRect(y, clip, LVIR_BOUNDS); - pDC->ExcludeClipRect(clip); - } - pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); - - if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { - - CPen gridPen, *oldPen; - gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); - oldPen = pDC->SelectObject(&gridPen); - - if (GetItemCount() > 0) { - CRect gr; - for (int x = 0; x < themedHdrCtrl.GetItemCount(); x++) { - themedHdrCtrl.GetItemRect(x, gr); - pDC->MoveTo(gr.right, r.top); - pDC->LineTo(gr.right, r.bottom); - } - gr.bottom = 0; - for (int y = 0; y < GetItemCount() || gr.bottom < r.bottom; y++) { - if (y >= GetItemCount()) { - gr.OffsetRect(0, gr.Height()); - } else { - GetItemRect(y, gr, LVIR_BOUNDS); - } - { - CPen horzPen; - pDC->MoveTo(r.left, gr.bottom - 1); - if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { - COLORREF horzGridColor, tmp; - customThemeInterface->GetCustomGridColors(y, horzGridColor, tmp); - horzPen.CreatePen(PS_SOLID, 1, horzGridColor); - pDC->SelectObject(&horzPen); - pDC->LineTo(r.right, gr.bottom - 1); - pDC->SelectObject(&gridPen); - horzPen.DeleteObject(); - } else { - pDC->LineTo(r.right, gr.bottom - 1); - } - } - } - } - pDC->SelectObject(oldPen); - gridPen.DeleteObject(); - } - pDC->RestoreDC(dcState); - } else { - return __super::OnEraseBkgnd(pDC); - } - return TRUE; -} - - -HBRUSH CMPCThemePlayerListCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} - - -BOOL CMPCThemePlayerListCtrl::OnHdnEndtrack(UINT id, NMHDR* pNMHDR, LRESULT* pResult) -{ - // LPNMHEADER phdr = reinterpret_cast(pNMHDR); - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - } - *pResult = 0; - - //we don't want to prevent this event from being processed - //it's used when "show windows contents while dragging" is false, - //to draw the outline of the resized column - return FALSE; -} - -LRESULT CMPCThemePlayerListCtrl::OnDelayed_UpdateScrollbar(WPARAM, LPARAM invalidate) -{ - updateScrollInfo((bool)invalidate); - return 0; -} - -BOOL CMPCThemePlayerListCtrl::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) -{ - //LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); - if (AppNeedsThemedControls()) { - ::PostMessage(m_hWnd, PLAYER_PLAYLIST_UPDATE_SCROLLBAR, (WPARAM)0, (LPARAM)0); - } - *pResult = 0; - return FALSE; -} +#include "stdafx.h" +#include "CMPCThemePlayerListCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#undef SubclassWindow + +CMPCThemePlayerListCtrl::CMPCThemePlayerListCtrl() : CListCtrl() +{ + themeGridLines = false; + fullRowSelect = false; + themedSBHelper = nullptr; + hasCheckedColors = false; + hasCBImages = false; + customThemeInterface = nullptr; + if (!CMPCThemeUtil::canUseWin10DarkTheme()) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + } +} + + +CMPCThemePlayerListCtrl::~CMPCThemePlayerListCtrl() +{ + if (nullptr != themedSBHelper) { + delete themedSBHelper; + } +} + + +void CMPCThemePlayerListCtrl::PreSubclassWindow() +{ + if (!AppNeedsThemedControls()) { + EnableToolTips(TRUE); + } else { + if (CMPCThemeUtil::canUseWin10DarkTheme()) { + SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); + } else { + SetWindowTheme(GetSafeHwnd(), L"", NULL); + } + CToolTipCtrl* t = GetToolTips(); + if (nullptr != t) { + lvsToolTip.SubclassWindow(t->m_hWnd); + } + subclassHeader(); + } + CListCtrl::PreSubclassWindow(); +} + +IMPLEMENT_DYNAMIC(CMPCThemePlayerListCtrl, CListCtrl) + +BEGIN_MESSAGE_MAP(CMPCThemePlayerListCtrl, CListCtrl) + ON_WM_NCPAINT() + ON_WM_CREATE() + ON_NOTIFY_REFLECT_EX(LVN_ENDSCROLL, OnLvnEndScroll) + ON_WM_MOUSEMOVE() + ON_WM_MOUSEWHEEL() + ON_WM_NCCALCSIZE() + ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, OnCustomDraw) + ON_WM_ERASEBKGND() + ON_WM_CTLCOLOR() + ON_NOTIFY_EX(HDN_ENDTRACKA, 0, &OnHdnEndtrack) + ON_NOTIFY_EX(HDN_ENDTRACKW, 0, &OnHdnEndtrack) + ON_NOTIFY_REFLECT_EX(LVN_ITEMCHANGED, &OnLvnItemchanged) + ON_MESSAGE(PLAYER_PLAYLIST_UPDATE_SCROLLBAR, OnDelayed_UpdateScrollbar) + ON_WM_WINDOWPOSCHANGED() +END_MESSAGE_MAP() + +void CMPCThemePlayerListCtrl::OnWindowPosChanged(WINDOWPOS* lpwndpos) { + if (AppNeedsThemedControls()) { + if (themedSBHelper && 0 != (GetStyle() & (WS_VSCROLL | WS_HSCROLL))) { + themedSBHelper->OnWindowPosChanged(); + } + } + return __super::OnWindowPosChanged(lpwndpos); +} + + +void CMPCThemePlayerListCtrl::subclassHeader() +{ + CHeaderCtrl* t = GetHeaderCtrl(); + if (nullptr != t && IsWindow(t->m_hWnd) && themedHdrCtrl.m_hWnd == NULL) { + themedHdrCtrl.SubclassWindow(t->GetSafeHwnd()); + } +} + +void CMPCThemePlayerListCtrl::setAdditionalStyles(DWORD styles) +{ + if (AppNeedsThemedControls()) { + DWORD stylesToAdd = styles, stylesToRemove = 0; + if (styles & LVS_EX_GRIDLINES) { + stylesToAdd &= ~LVS_EX_GRIDLINES; + stylesToRemove |= LVS_EX_GRIDLINES; + themeGridLines = true; + } + if (styles & LVS_EX_FULLROWSELECT) { + //we need these to remain, or else other columns may not get refreshed on a selection change. + //no regressions observed yet, but unclear why we removed this style for custom draw previously + //error was observed with playersubresyncbar + // stylesToAdd &= ~LVS_EX_FULLROWSELECT; + // stylesToRemove |= LVS_EX_FULLROWSELECT; + fullRowSelect = true; + } + if (styles & LVS_EX_DOUBLEBUFFER) { //we will buffer ourselves + stylesToAdd &= ~LVS_EX_DOUBLEBUFFER; + stylesToRemove |= LVS_EX_DOUBLEBUFFER; + } + SetExtendedStyle((GetExtendedStyle() | stylesToAdd) & ~stylesToRemove); + } else { + SetExtendedStyle(GetExtendedStyle() | styles); + } +} + +void CMPCThemePlayerListCtrl::setHasCBImages(bool on) +{ + hasCBImages = on; +} + +void CMPCThemePlayerListCtrl::setItemTextWithDefaultFlag(int nItem, int nSubItem, LPCTSTR lpszText, bool flagged) +{ + SetItemText(nItem, nSubItem, lpszText); + setFlaggedItem(nItem, flagged); +} + +void CMPCThemePlayerListCtrl::setFlaggedItem(int iItem, bool flagged) +{ + flaggedItems[iItem] = flagged; +} + +bool CMPCThemePlayerListCtrl::getFlaggedItem(int iItem) +{ + auto it = flaggedItems.find(iItem); + if (it != flaggedItems.end()) { + return it->second; + } else { + return false; + } +} + +void CMPCThemePlayerListCtrl::DoDPIChanged() +{ + if (listMPCThemeFontBold.m_hObject) { + listMPCThemeFontBold.DeleteObject(); + } + +} + + +BOOL CMPCThemePlayerListCtrl::PreTranslateMessage(MSG* pMsg) +{ + if (AppNeedsThemedControls()) { + if (!IsWindow(themedToolTip.m_hWnd)) { + themedToolTip.Create(this, TTS_ALWAYSTIP); + themedToolTip.enableFlickerHelper(); + } + if (IsWindow(themedToolTip.m_hWnd)) { + themedToolTip.RelayEvent(pMsg); + } + } + return __super::PreTranslateMessage(pMsg); +} + +void CMPCThemePlayerListCtrl::setCheckedColors(COLORREF checkedBG, COLORREF checkedText, COLORREF uncheckedText) +{ + checkedBGClr = checkedBG; + checkedTextClr = checkedText; + uncheckedTextClr = uncheckedText; + hasCheckedColors = true; +} + +void CMPCThemePlayerListCtrl::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->themedNcPaintWithSB(); + } else { + CMPCThemeScrollBarHelper::themedNcPaint(this, this); + } + } else { + __super::OnNcPaint(); + } +} + + +int CMPCThemePlayerListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (__super::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + if (AppNeedsThemedControls()) { + SetBkColor(CMPCTheme::ContentBGColor); + subclassHeader(); + } + + return 0; +} + +BOOL CMPCThemePlayerListCtrl::OnLvnEndScroll(NMHDR* pNMHDR, LRESULT* pResult) +{ + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + *pResult = 0; + } + return FALSE; +} + +void CMPCThemePlayerListCtrl::updateSB() +{ + if (nullptr != themedSBHelper) { + themedSBHelper->hideNativeScrollBars(); + } +} + +void CMPCThemePlayerListCtrl::updateScrollInfo(bool invalidate /*=false*/) +{ + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(invalidate); + } +} + +LRESULT CMPCThemePlayerListCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (AppNeedsThemedControls() && nullptr != themedSBHelper) { + if (themedSBHelper->WindowProc(this, message, wParam, lParam)) { + return 1; + } + } + return __super::WindowProc(message, wParam, lParam); +} + +void CMPCThemePlayerListCtrl::updateToolTip(CPoint point) +{ + if (AppNeedsThemedControls() && nullptr != themedToolTip) { + TOOLINFO ti = { 0 }; + UINT_PTR tid = OnToolHitTest(point, &ti); + //OnToolHitTest returns -1 on failure but doesn't update uId to match + + if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool + if (themedToolTip.GetToolCount() > 0) { + themedToolTip.DelTool(this); + themedToolTip.Activate(FALSE); + } + themedToolTipCid = (UINT_PTR) - 1; + } + + if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { + + themedToolTipCid = ti.uId; + + CRect cr; + GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate + + themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); + themedToolTip.Activate(TRUE); + } + } +} + +void CMPCThemePlayerListCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + __super::OnMouseMove(nFlags, point); + updateToolTip(point); +} + + +BOOL CMPCThemePlayerListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + BOOL ret = __super::OnMouseWheel(nFlags, zDelta, pt); + ScreenToClient(&pt); + updateToolTip(pt); + return ret; +} + + +void CMPCThemePlayerListCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) +{ + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + if (AppNeedsThemedControls()) { + if (GetStyle() & WS_HSCROLL && nullptr == themedSBHelper) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + } + ::PostMessage(m_hWnd, PLAYER_PLAYLIST_UPDATE_SCROLLBAR, (WPARAM)0, (LPARAM)TRUE); + } +} + +void CMPCThemePlayerListCtrl::drawItem(CDC* pDC, int nItem, int nSubItem) +{ + if (IsItemVisible(nItem)) { + + CRect rect, rRow, rIcon, rText, rTextBG, rectDC, rClient; + GetClientRect(rClient); + GetItemRect(nItem, rRow, LVIR_BOUNDS); + GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rText); + GetSubItemRect(nItem, nSubItem, LVIR_ICON, rIcon); + GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect); + DWORD dwStyle = GetStyle() & LVS_TYPEMASK; + + if (0 == nSubItem) { //getsubitemrect gives whole row for 0/LVIR_BOUNDS. but LVIR_LABEL is limited to text bounds. MSDN undocumented behavior + rect.right = rText.right; + } + + //issubitemvisible + if (rClient.left <= rect.right && rClient.right >= rect.left && rClient.top <= rect.bottom && rClient.bottom >= rect.top) { + COLORREF textColor = CMPCTheme::TextFGColor; + COLORREF bgColor = CMPCTheme::ContentBGColor; + COLORREF selectedBGColor = CMPCTheme::ContentSelectedColor; + + COLORREF oldTextColor = pDC->GetTextColor(); + COLORREF oldBkColor = pDC->GetBkColor(); + + CString text = GetItemText(nItem, nSubItem); + if (nullptr != customThemeInterface) { //subclasses can override colors here + bool overrideSelectedBG = false; + customThemeInterface->GetCustomTextColors(nItem, nSubItem, textColor, bgColor, overrideSelectedBG); + if (overrideSelectedBG) { + selectedBGColor = bgColor; + } + } + + pDC->SetTextColor(textColor); + pDC->SetBkColor(bgColor); + + rectDC = rRow; + CDC dcMem; + CBitmap bmMem; + CMPCThemeUtil::initMemDC(pDC, dcMem, bmMem, rectDC); + rect.OffsetRect(-rectDC.TopLeft()); + rText.OffsetRect(-rectDC.TopLeft()); + rIcon.OffsetRect(-rectDC.TopLeft()); + rRow.OffsetRect(-rectDC.TopLeft()); + + if (!IsWindowEnabled() && 0 == nSubItem) { //no gridlines, bg for full row + dcMem.FillSolidRect(rRow, CMPCTheme::ListCtrlDisabledBGColor); + } else { + dcMem.FillSolidRect(rect, CMPCTheme::ContentBGColor); //no flicker because we have a memory dc + } + + rTextBG = rText; + CHeaderCtrl* hdrCtrl = GetHeaderCtrl(); + int align = DT_LEFT; + if (nullptr != hdrCtrl) { + HDITEM hditem = { 0 }; + hditem.mask = HDI_FORMAT; + hdrCtrl->GetItem(nSubItem, &hditem); + align = hditem.fmt & HDF_JUSTIFYMASK; + } + UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX; + if (align == HDF_CENTER) { + textFormat |= DT_CENTER; + } else if (align == HDF_LEFT) { + textFormat |= DT_LEFT; + if (nSubItem == 0) {//less indent for first column + rText.left += 2; + } else { + rText.left += 6; + } + } else { + textFormat |= DT_RIGHT; + rText.right -= 6; + } + + bool isChecked = false; + int contentLeft = rText.left; + if (rIcon.Width() > 0) { + LVITEM lvi = { 0 }; + lvi.iItem = nItem; + lvi.iSubItem = 0; + lvi.mask = LVIF_IMAGE; + GetItem(&lvi); + + if (nSubItem == 0) { + contentLeft = rIcon.left; + if (hasCBImages) { //draw manually to match theme + rIcon.DeflateRect(0, 0, 1, 0); + if (rIcon.Height() > rIcon.Width()) { + rIcon.DeflateRect(0, (rIcon.Height() - rIcon.Width()) / 2); //as tall as wide + } + + CMPCThemeUtil::drawCheckBox(GetParent(), lvi.iImage, false, false, rIcon, &dcMem); + } else { + if (dwStyle == LVS_ICON) { + } else if (dwStyle == LVS_SMALLICON || dwStyle == LVS_LIST || dwStyle == LVS_REPORT) { + CImageList* ilist = GetImageList(LVSIL_SMALL); + int cx, cy; + ImageList_GetIconSize(ilist->m_hImageList, &cx, &cy); + rIcon.top += (rIcon.Height() - cy) / 2; + ilist->Draw(&dcMem, lvi.iImage, rIcon.TopLeft(), ILD_TRANSPARENT); + } + } + if (align == HDF_LEFT) { + rText.left += 2; //more ident after image + } + } + } + if (0 != (GetExtendedStyle() & LVS_EX_CHECKBOXES) && INDEXTOSTATEIMAGEMASK(0) != GetItemState(nItem, LVIS_STATEIMAGEMASK)) { + isChecked = (TRUE == GetCheck(nItem)); + if (nSubItem == 0) { + int cbSize = GetSystemMetrics(SM_CXMENUCHECK); + int cbYMargin = (rect.Height() - cbSize - 1) / 2; + int cbXMargin = (contentLeft - rect.left - cbSize) / 2; + CRect rcb = { rect.left + cbXMargin, rect.top + cbYMargin, rect.left + cbXMargin + cbSize, rect.top + cbYMargin + cbSize }; + CMPCThemeUtil::drawCheckBox(GetParent(), isChecked, false, true, rcb, &dcMem); + } + } + + if (IsWindowEnabled()) { + bool selected = false; + if (GetItemState(nItem, LVIS_SELECTED) == LVIS_SELECTED && (nSubItem == 0 || fullRowSelect) && (GetStyle() & LVS_SHOWSELALWAYS || GetFocus() == this)) { + bgColor = selectedBGColor; + if (LVS_REPORT != dwStyle) { //in list mode we don't fill the "whole" column + CRect tmp = rText; + dcMem.DrawTextW(text, tmp, textFormat | DT_CALCRECT); //end of string + rTextBG.right = tmp.right + (rText.left - rTextBG.left); //end of string plus same indent from the left side + } + selected = true; + } else if (hasCheckedColors) { + if (isChecked && checkedBGClr != -1) { + bgColor = checkedBGClr; + } + if (isChecked && checkedTextClr != -1) { + dcMem.SetTextColor(checkedTextClr); + } + if (!isChecked && uncheckedTextClr != -1) { + dcMem.SetTextColor(uncheckedTextClr); + } + } + dcMem.FillSolidRect(rTextBG, bgColor); + + if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { + CRect rGrid = rect; + rGrid.bottom -= 1; + CPen gridPenV, gridPenH, *oldPen; + if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { + COLORREF horzGridColor, vertGridColor; + customThemeInterface->GetCustomGridColors(nItem, horzGridColor, vertGridColor); + gridPenV.CreatePen(PS_SOLID, 1, vertGridColor); + gridPenH.CreatePen(PS_SOLID, 1, horzGridColor); + } else { + gridPenV.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); + gridPenH.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); + } + + oldPen = dcMem.SelectObject(&gridPenV); + if (nSubItem != 0) { + dcMem.MoveTo(rGrid.TopLeft()); + dcMem.LineTo(rGrid.left, rGrid.bottom); + } else { + dcMem.MoveTo(rGrid.left, rGrid.bottom); + } + + dcMem.SelectObject(&gridPenH); + dcMem.LineTo(rGrid.BottomRight()); + + dcMem.SelectObject(&gridPenV); + dcMem.LineTo(rGrid.right, rGrid.top); + + dcMem.SelectObject(oldPen); + gridPenV.DeleteObject(); + gridPenH.DeleteObject(); + } else if (selected) { + CBrush borderBG; + borderBG.CreateSolidBrush(CMPCTheme::ListCtrlDisabledBGColor); + dcMem.FrameRect(rTextBG, &borderBG); + borderBG.DeleteObject(); + } + } + + if (getFlaggedItem(nItem)) { //could be a setting, but flagged items are bold for now + if (!listMPCThemeFontBold.m_hObject) { + listMPCThemeFont = GetFont(); + LOGFONT lf; + listMPCThemeFont->GetLogFont(&lf); + lf.lfWeight = FW_BOLD; + listMPCThemeFontBold.CreateFontIndirect(&lf); + } + + dcMem.SelectObject(listMPCThemeFontBold); + } + dcMem.DrawTextW(text, rText, textFormat); + CMPCThemeUtil::flushMemDC(pDC, dcMem, rectDC); + pDC->SetTextColor(oldTextColor); + pDC->SetBkColor(oldBkColor); + } + } +} + +BOOL CMPCThemePlayerListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + if (AppNeedsThemedControls()) { + NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); + + *pResult = CDRF_DODEFAULT; + if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT) { + if (nullptr != customThemeInterface) { + customThemeInterface->DoCustomPrePaint(); + } + *pResult = CDRF_NOTIFYITEMDRAW; + } else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { + DWORD dwStyle = GetStyle() & LVS_TYPEMASK; + if (LVS_REPORT == dwStyle) { + *pResult = CDRF_NOTIFYSUBITEMDRAW; + } else { + int nItem = static_cast(pLVCD->nmcd.dwItemSpec); + CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); + drawItem(pDC, nItem, 0); + *pResult = CDRF_SKIPDEFAULT; + } + } else if (pLVCD->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM)) { + if (GetStyle() & LVS_OWNERDRAWFIXED) { + //found that for ownerdraw routines, we can end up here and draw both ways on hover/tooltip. this should prevent it + *pResult = CDRF_DODEFAULT; + } else { + int nItem = static_cast(pLVCD->nmcd.dwItemSpec); + if (IsItemVisible(nItem)) { + int nSubItem = pLVCD->iSubItem; + CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); + drawItem(pDC, nItem, nSubItem); + } + *pResult = CDRF_SKIPDEFAULT; + } + } + return TRUE; + } + return FALSE; +} + + +BOOL CMPCThemePlayerListCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppNeedsThemedControls()) { + CRect r; + GetClientRect(r); + int dcState = pDC->SaveDC(); + for (int y = 0; y < GetItemCount(); y++) { + CRect clip; + GetItemRect(y, clip, LVIR_BOUNDS); + pDC->ExcludeClipRect(clip); + } + pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); + + if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { + + CPen gridPen, *oldPen; + gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); + oldPen = pDC->SelectObject(&gridPen); + + if (GetItemCount() > 0) { + CRect gr; + for (int x = 0; x < themedHdrCtrl.GetItemCount(); x++) { + themedHdrCtrl.GetItemRect(x, gr); + pDC->MoveTo(gr.right, r.top); + pDC->LineTo(gr.right, r.bottom); + } + gr.bottom = 0; + for (int y = 0; y < GetItemCount() || gr.bottom < r.bottom; y++) { + if (y >= GetItemCount()) { + gr.OffsetRect(0, gr.Height()); + } else { + GetItemRect(y, gr, LVIR_BOUNDS); + } + { + CPen horzPen; + pDC->MoveTo(r.left, gr.bottom - 1); + if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { + COLORREF horzGridColor, tmp; + customThemeInterface->GetCustomGridColors(y, horzGridColor, tmp); + horzPen.CreatePen(PS_SOLID, 1, horzGridColor); + pDC->SelectObject(&horzPen); + pDC->LineTo(r.right, gr.bottom - 1); + pDC->SelectObject(&gridPen); + horzPen.DeleteObject(); + } else { + pDC->LineTo(r.right, gr.bottom - 1); + } + } + } + } + pDC->SelectObject(oldPen); + gridPen.DeleteObject(); + } + pDC->RestoreDC(dcState); + } else { + return __super::OnEraseBkgnd(pDC); + } + return TRUE; +} + + +HBRUSH CMPCThemePlayerListCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} + + +BOOL CMPCThemePlayerListCtrl::OnHdnEndtrack(UINT id, NMHDR* pNMHDR, LRESULT* pResult) +{ + // LPNMHEADER phdr = reinterpret_cast(pNMHDR); + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + } + *pResult = 0; + + //we don't want to prevent this event from being processed + //it's used when "show windows contents while dragging" is false, + //to draw the outline of the resized column + return FALSE; +} + +LRESULT CMPCThemePlayerListCtrl::OnDelayed_UpdateScrollbar(WPARAM, LPARAM invalidate) +{ + updateScrollInfo((bool)invalidate); + return 0; +} + +BOOL CMPCThemePlayerListCtrl::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + //LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); + if (AppNeedsThemedControls()) { + ::PostMessage(m_hWnd, PLAYER_PLAYLIST_UPDATE_SCROLLBAR, (WPARAM)0, (LPARAM)0); + } + *pResult = 0; + return FALSE; +} diff --git a/src/mpc-hc/CMPCThemePlayerListCtrl.h b/src/mpc-hc/CMPCThemePlayerListCtrl.h index 0624e60a36d..a59fb3c9aa5 100755 --- a/src/mpc-hc/CMPCThemePlayerListCtrl.h +++ b/src/mpc-hc/CMPCThemePlayerListCtrl.h @@ -1,74 +1,74 @@ -#pragma once -#include "CMPCThemeScrollBarHelper.h" -#include "CMPCThemeToolTipCtrl.h" -#include "CMPCThemeUtil.h" -#include "CMPCThemeHeaderCtrl.h" - -//undocumented state changes for LVS_EX_CHECKBOXES -#define LVIS_UNCHECKED 0x1000 -#define LVIS_CHECKED 0x2000 - -class CMPCThemeListCtrlCustomInterface -{ -public: - virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) = 0; - virtual void DoCustomPrePaint() = 0; - virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) = 0; - virtual bool UseCustomGrid() { return true; }; -}; - -class CMPCThemePlayerListCtrl : public CListCtrl, CMPCThemeUtil, CMPCThemeScrollable -{ -public: - CMPCThemePlayerListCtrl(); - virtual ~CMPCThemePlayerListCtrl(); - DECLARE_DYNAMIC(CMPCThemePlayerListCtrl) - - void updateSB(); - void updateScrollInfo(bool invalidate = false); - LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - void updateToolTip(CPoint point); - virtual BOOL PreTranslateMessage(MSG* pMsg); - void setCheckedColors(COLORREF checkedBG, COLORREF checkedText, COLORREF uncheckedText); - void subclassHeader(); - void setAdditionalStyles(DWORD styles); - void setHasCBImages(bool on); - void setItemTextWithDefaultFlag(int nItem, int nSubItem, LPCTSTR lpszText, bool flagged); - void setFlaggedItem(int iItem, bool flagged); - bool getFlaggedItem(int iItem); - void setColorInterface(CMPCThemeListCtrlCustomInterface* iface) { customThemeInterface = iface; }; - void DoDPIChanged(); - - DECLARE_MESSAGE_MAP() - afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); - afx_msg void OnNcPaint(); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg BOOL OnLvnEndScroll(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); - afx_msg BOOL OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - CMPCThemeScrollBarHelper* themedSBHelper; - CMPCThemeToolTipCtrl themedToolTip, lvsToolTip; - UINT_PTR themedToolTipCid; - COLORREF checkedBGClr, checkedTextClr, uncheckedTextClr; - std::map flaggedItems; - bool hasCheckedColors; - bool hasCBImages; - bool themeGridLines; - bool fullRowSelect; - CMPCThemeHeaderCtrl themedHdrCtrl; - CFont* listMPCThemeFont, listMPCThemeFontBold; - CMPCThemeListCtrlCustomInterface* customThemeInterface; - void drawItem(CDC* pDC, int nItem, int nSubItem); - virtual void PreSubclassWindow(); -public: - void doDefault() { Default(); }; - afx_msg BOOL OnHdnEndtrack(UINT id, NMHDR* pNMHDR, LRESULT* pResult); - afx_msg LRESULT OnDelayed_UpdateScrollbar(WPARAM, LPARAM); - afx_msg BOOL OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); -}; - +#pragma once +#include "CMPCThemeScrollBarHelper.h" +#include "CMPCThemeToolTipCtrl.h" +#include "CMPCThemeUtil.h" +#include "CMPCThemeHeaderCtrl.h" + +//undocumented state changes for LVS_EX_CHECKBOXES +#define LVIS_UNCHECKED 0x1000 +#define LVIS_CHECKED 0x2000 + +class CMPCThemeListCtrlCustomInterface +{ +public: + virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) = 0; + virtual void DoCustomPrePaint() = 0; + virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) = 0; + virtual bool UseCustomGrid() { return true; }; +}; + +class CMPCThemePlayerListCtrl : public CListCtrl, CMPCThemeUtil, CMPCThemeScrollable +{ +public: + CMPCThemePlayerListCtrl(); + virtual ~CMPCThemePlayerListCtrl(); + DECLARE_DYNAMIC(CMPCThemePlayerListCtrl) + + void updateSB(); + void updateScrollInfo(bool invalidate = false); + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + void updateToolTip(CPoint point); + virtual BOOL PreTranslateMessage(MSG* pMsg); + void setCheckedColors(COLORREF checkedBG, COLORREF checkedText, COLORREF uncheckedText); + void subclassHeader(); + void setAdditionalStyles(DWORD styles); + void setHasCBImages(bool on); + void setItemTextWithDefaultFlag(int nItem, int nSubItem, LPCTSTR lpszText, bool flagged); + void setFlaggedItem(int iItem, bool flagged); + bool getFlaggedItem(int iItem); + void setColorInterface(CMPCThemeListCtrlCustomInterface* iface) { customThemeInterface = iface; }; + void DoDPIChanged(); + + DECLARE_MESSAGE_MAP() + afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); + afx_msg void OnNcPaint(); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg BOOL OnLvnEndScroll(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); + afx_msg BOOL OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + CMPCThemeScrollBarHelper* themedSBHelper; + CMPCThemeToolTipCtrl themedToolTip, lvsToolTip; + UINT_PTR themedToolTipCid; + COLORREF checkedBGClr, checkedTextClr, uncheckedTextClr; + std::map flaggedItems; + bool hasCheckedColors; + bool hasCBImages; + bool themeGridLines; + bool fullRowSelect; + CMPCThemeHeaderCtrl themedHdrCtrl; + CFont* listMPCThemeFont, listMPCThemeFontBold; + CMPCThemeListCtrlCustomInterface* customThemeInterface; + void drawItem(CDC* pDC, int nItem, int nSubItem); + virtual void PreSubclassWindow(); +public: + void doDefault() { Default(); }; + afx_msg BOOL OnHdnEndtrack(UINT id, NMHDR* pNMHDR, LRESULT* pResult); + afx_msg LRESULT OnDelayed_UpdateScrollbar(WPARAM, LPARAM); + afx_msg BOOL OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); +}; + diff --git a/src/mpc-hc/CMPCThemePropPageFrame.cpp b/src/mpc-hc/CMPCThemePropPageFrame.cpp index b4534b508f9..ac05e806341 100755 --- a/src/mpc-hc/CMPCThemePropPageFrame.cpp +++ b/src/mpc-hc/CMPCThemePropPageFrame.cpp @@ -1,98 +1,98 @@ -#include "stdafx.h" -#include "CMPCThemePropPageFrame.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "TreePropSheet/PropPageFrameDefault.h" -#include "../DSUtil/WinAPIUtils.h" - -CBrush CMPCThemePropPageFrame::mpcThemeBorderBrush; - -CMPCThemePropPageFrame::CMPCThemePropPageFrame() : CPropPageFrameDefault() -{ - if (nullptr == mpcThemeBorderBrush.m_hObject) { - mpcThemeBorderBrush.CreateSolidBrush(CMPCTheme::WindowBorderColorLight); - } -} - - -CMPCThemePropPageFrame::~CMPCThemePropPageFrame() -{ -} - -BEGIN_MESSAGE_MAP(CMPCThemePropPageFrame, CPropPageFrameDefault) - ON_WM_PAINT() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - - -BOOL CMPCThemePropPageFrame::Create(DWORD dwWindowStyle, const RECT& rect, CWnd* pwndParent, UINT nID) -{ - return CWnd::Create( - AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), 0), - _T("MPCTheme Page Frame"), - dwWindowStyle, rect, pwndParent, nID); -} - -CWnd* CMPCThemePropPageFrame::GetWnd() -{ - return static_cast(this); -} - -void CMPCThemePropPageFrame::DrawCaption(CDC* pDC, CRect rect, LPCTSTR lpszCaption, HICON hIcon) -{ - COLORREF clrLeft = CMPCTheme::ContentSelectedColor; - COLORREF clrRight = CMPCTheme::ContentBGColor; - FillGradientRectH(pDC, rect, clrLeft, clrRight); - - rect.left += 2; - - COLORREF clrPrev = pDC->SetTextColor(CMPCTheme::PropPageCaptionFGColor); - int nBkStyle = pDC->SetBkMode(TRANSPARENT); - - LOGFONT lf; - GetMessageFont(&lf); - lf.lfHeight = static_cast(-.8f * rect.Height()); - lf.lfWeight = FW_BOLD; - CFont f; - f.CreateFontIndirectW(&lf); - CFont* oldFont = pDC->SelectObject(&f); - - TEXTMETRIC GDIMetrics; - GetTextMetricsW(pDC->GetSafeHdc(), &GDIMetrics); - while (GDIMetrics.tmHeight > rect.Height() && abs(lf.lfHeight) > 10) { - pDC->SelectObject(oldFont); - f.DeleteObject(); - lf.lfHeight++; - f.CreateFontIndirectW(&lf); - pDC->SelectObject(&f); - GetTextMetricsW(pDC->GetSafeHdc(), &GDIMetrics); - } - - - rect.top -= GDIMetrics.tmDescent - 1; - - pDC->DrawTextW(lpszCaption, rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); // DT_NOPREFIX not needed - - pDC->SetTextColor(clrPrev); - pDC->SelectObject(oldFont); - pDC->SetBkMode(nBkStyle); -} - -void CMPCThemePropPageFrame::OnPaint() -{ - CPaintDC dc(this); - Draw(&dc); -} - -BOOL CMPCThemePropPageFrame::OnEraseBkgnd(CDC* pDC) -{ - bool ret = CMPCThemeUtil::MPCThemeEraseBkgnd(pDC, this, CTLCOLOR_DLG); - if (ret) { - CRect rect; - GetClientRect(rect); - pDC->FrameRect(rect, &mpcThemeBorderBrush); - return ret; - } else { - return __super::OnEraseBkgnd(pDC); - } -} +#include "stdafx.h" +#include "CMPCThemePropPageFrame.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "TreePropSheet/PropPageFrameDefault.h" +#include "../DSUtil/WinAPIUtils.h" + +CBrush CMPCThemePropPageFrame::mpcThemeBorderBrush; + +CMPCThemePropPageFrame::CMPCThemePropPageFrame() : CPropPageFrameDefault() +{ + if (nullptr == mpcThemeBorderBrush.m_hObject) { + mpcThemeBorderBrush.CreateSolidBrush(CMPCTheme::WindowBorderColorLight); + } +} + + +CMPCThemePropPageFrame::~CMPCThemePropPageFrame() +{ +} + +BEGIN_MESSAGE_MAP(CMPCThemePropPageFrame, CPropPageFrameDefault) + ON_WM_PAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + +BOOL CMPCThemePropPageFrame::Create(DWORD dwWindowStyle, const RECT& rect, CWnd* pwndParent, UINT nID) +{ + return CWnd::Create( + AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), 0), + _T("MPCTheme Page Frame"), + dwWindowStyle, rect, pwndParent, nID); +} + +CWnd* CMPCThemePropPageFrame::GetWnd() +{ + return static_cast(this); +} + +void CMPCThemePropPageFrame::DrawCaption(CDC* pDC, CRect rect, LPCTSTR lpszCaption, HICON hIcon) +{ + COLORREF clrLeft = CMPCTheme::ContentSelectedColor; + COLORREF clrRight = CMPCTheme::ContentBGColor; + FillGradientRectH(pDC, rect, clrLeft, clrRight); + + rect.left += 2; + + COLORREF clrPrev = pDC->SetTextColor(CMPCTheme::PropPageCaptionFGColor); + int nBkStyle = pDC->SetBkMode(TRANSPARENT); + + LOGFONT lf; + GetMessageFont(&lf); + lf.lfHeight = static_cast(-.8f * rect.Height()); + lf.lfWeight = FW_BOLD; + CFont f; + f.CreateFontIndirectW(&lf); + CFont* oldFont = pDC->SelectObject(&f); + + TEXTMETRIC GDIMetrics; + GetTextMetricsW(pDC->GetSafeHdc(), &GDIMetrics); + while (GDIMetrics.tmHeight > rect.Height() && abs(lf.lfHeight) > 10) { + pDC->SelectObject(oldFont); + f.DeleteObject(); + lf.lfHeight++; + f.CreateFontIndirectW(&lf); + pDC->SelectObject(&f); + GetTextMetricsW(pDC->GetSafeHdc(), &GDIMetrics); + } + + + rect.top -= GDIMetrics.tmDescent - 1; + + pDC->DrawTextW(lpszCaption, rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); // DT_NOPREFIX not needed + + pDC->SetTextColor(clrPrev); + pDC->SelectObject(oldFont); + pDC->SetBkMode(nBkStyle); +} + +void CMPCThemePropPageFrame::OnPaint() +{ + CPaintDC dc(this); + Draw(&dc); +} + +BOOL CMPCThemePropPageFrame::OnEraseBkgnd(CDC* pDC) +{ + bool ret = CMPCThemeUtil::MPCThemeEraseBkgnd(pDC, this, CTLCOLOR_DLG); + if (ret) { + CRect rect; + GetClientRect(rect); + pDC->FrameRect(rect, &mpcThemeBorderBrush); + return ret; + } else { + return __super::OnEraseBkgnd(pDC); + } +} diff --git a/src/mpc-hc/CMPCThemePropPageFrame.h b/src/mpc-hc/CMPCThemePropPageFrame.h index 0c5c659727e..875a53b5317 100755 --- a/src/mpc-hc/CMPCThemePropPageFrame.h +++ b/src/mpc-hc/CMPCThemePropPageFrame.h @@ -1,19 +1,19 @@ -#pragma once -#include "TreePropSheet/PropPageFrameDefault.h" -class CMPCThemePropPageFrame : public TreePropSheet::CPropPageFrameDefault -{ -public: - CMPCThemePropPageFrame(); - virtual ~CMPCThemePropPageFrame(); - virtual BOOL Create(DWORD dwWindowStyle, const RECT& rect, CWnd* pwndParent, UINT nID); - virtual CWnd* GetWnd(); - - virtual void DrawCaption(CDC* pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); - - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - DECLARE_MESSAGE_MAP() -protected: - static CBrush mpcThemeBorderBrush; -}; - +#pragma once +#include "TreePropSheet/PropPageFrameDefault.h" +class CMPCThemePropPageFrame : public TreePropSheet::CPropPageFrameDefault +{ +public: + CMPCThemePropPageFrame(); + virtual ~CMPCThemePropPageFrame(); + virtual BOOL Create(DWORD dwWindowStyle, const RECT& rect, CWnd* pwndParent, UINT nID); + virtual CWnd* GetWnd(); + + virtual void DrawCaption(CDC* pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); + + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + DECLARE_MESSAGE_MAP() +protected: + static CBrush mpcThemeBorderBrush; +}; + diff --git a/src/mpc-hc/CMPCThemePropertyPage.cpp b/src/mpc-hc/CMPCThemePropertyPage.cpp index 2166286c9c5..286ec5ab1ba 100755 --- a/src/mpc-hc/CMPCThemePropertyPage.cpp +++ b/src/mpc-hc/CMPCThemePropertyPage.cpp @@ -1,36 +1,36 @@ -#include "stdafx.h" -#include "CMPCThemePropertyPage.h" - -CMPCThemePropertyPage::CMPCThemePropertyPage(UINT nIDTemplate, UINT nIDCaption) - : CPropertyPage(nIDTemplate, nIDCaption) -{ - -} - -CMPCThemePropertyPage::~CMPCThemePropertyPage() -{ -} - -BOOL CMPCThemePropertyPage::OnInitDialog() -{ - __super::OnInitDialog(); - fulfillThemeReqs(); - return 0; -} - -IMPLEMENT_DYNAMIC(CMPCThemePropertyPage, CPropertyPage) -BEGIN_MESSAGE_MAP(CMPCThemePropertyPage, CPropertyPage) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemePropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} +#include "stdafx.h" +#include "CMPCThemePropertyPage.h" + +CMPCThemePropertyPage::CMPCThemePropertyPage(UINT nIDTemplate, UINT nIDCaption) + : CPropertyPage(nIDTemplate, nIDCaption) +{ + +} + +CMPCThemePropertyPage::~CMPCThemePropertyPage() +{ +} + +BOOL CMPCThemePropertyPage::OnInitDialog() +{ + __super::OnInitDialog(); + fulfillThemeReqs(); + return 0; +} + +IMPLEMENT_DYNAMIC(CMPCThemePropertyPage, CPropertyPage) +BEGIN_MESSAGE_MAP(CMPCThemePropertyPage, CPropertyPage) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemePropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} diff --git a/src/mpc-hc/CMPCThemePropertyPage.h b/src/mpc-hc/CMPCThemePropertyPage.h index 3b81ce021e5..08ed45b2122 100755 --- a/src/mpc-hc/CMPCThemePropertyPage.h +++ b/src/mpc-hc/CMPCThemePropertyPage.h @@ -1,19 +1,19 @@ -#pragma once -#include "CMPCThemeUtil.h" -class CMPCThemePropertyPage : public CPropertyPage, public CMPCThemeUtil -{ -public: - CMPCThemePropertyPage(UINT nIDTemplate, UINT nIDCaption); - virtual ~CMPCThemePropertyPage(); - - - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - DECLARE_DYNAMIC(CMPCThemePropertyPage) - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - virtual BOOL OnInitDialog(); - -}; - +#pragma once +#include "CMPCThemeUtil.h" +class CMPCThemePropertyPage : public CPropertyPage, public CMPCThemeUtil +{ +public: + CMPCThemePropertyPage(UINT nIDTemplate, UINT nIDCaption); + virtual ~CMPCThemePropertyPage(); + + + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + DECLARE_DYNAMIC(CMPCThemePropertyPage) + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + virtual BOOL OnInitDialog(); + +}; + diff --git a/src/mpc-hc/CMPCThemePropertySheet.cpp b/src/mpc-hc/CMPCThemePropertySheet.cpp index 17b77a65219..84e1ec0ad3d 100755 --- a/src/mpc-hc/CMPCThemePropertySheet.cpp +++ b/src/mpc-hc/CMPCThemePropertySheet.cpp @@ -1,66 +1,66 @@ -#include "stdafx.h" -#include "CMPCThemePropertySheet.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - - -CMPCThemePropertySheet::CMPCThemePropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) - : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) - ,isModal(false) -{ -} - -CMPCThemePropertySheet::CMPCThemePropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) - : CPropertySheet(pszCaption, pParentWnd, iSelectPage) - ,isModal(false) -{ -} - -CMPCThemePropertySheet::~CMPCThemePropertySheet() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemePropertySheet, CPropertySheet) -BEGIN_MESSAGE_MAP(CMPCThemePropertySheet, CPropertySheet) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - -BOOL CMPCThemePropertySheet::OnInitDialog() -{ - BOOL bResult = __super::OnInitDialog(); - fulfillThemeReqs(); - return bResult; -} - -void CMPCThemePropertySheet::fulfillThemeReqs() -{ - if (AppNeedsThemedControls()) { - CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); - if (isModal) { //propsheets not normally modal, but if so... - CMPCThemeUtil::enableWindows10DarkFrame(this); - } - } -} - -HBRUSH CMPCThemePropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppNeedsThemedControls()) { - LRESULT lResult; - if (pWnd->SendChildNotifyLastMsg(&lResult)) { - return (HBRUSH)lResult; - } - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::ControlAreaBGColor); - return controlAreaBrush; - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} - -INT_PTR CMPCThemePropertySheet::DoModal() { - isModal = true; - PreDoModalRTL(&m_psh); - return __super::DoModal(); -} +#include "stdafx.h" +#include "CMPCThemePropertySheet.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + + +CMPCThemePropertySheet::CMPCThemePropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) + : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) + ,isModal(false) +{ +} + +CMPCThemePropertySheet::CMPCThemePropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) + : CPropertySheet(pszCaption, pParentWnd, iSelectPage) + ,isModal(false) +{ +} + +CMPCThemePropertySheet::~CMPCThemePropertySheet() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemePropertySheet, CPropertySheet) +BEGIN_MESSAGE_MAP(CMPCThemePropertySheet, CPropertySheet) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + +BOOL CMPCThemePropertySheet::OnInitDialog() +{ + BOOL bResult = __super::OnInitDialog(); + fulfillThemeReqs(); + return bResult; +} + +void CMPCThemePropertySheet::fulfillThemeReqs() +{ + if (AppNeedsThemedControls()) { + CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); + if (isModal) { //propsheets not normally modal, but if so... + CMPCThemeUtil::enableWindows10DarkFrame(this); + } + } +} + +HBRUSH CMPCThemePropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppNeedsThemedControls()) { + LRESULT lResult; + if (pWnd->SendChildNotifyLastMsg(&lResult)) { + return (HBRUSH)lResult; + } + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::ControlAreaBGColor); + return controlAreaBrush; + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} + +INT_PTR CMPCThemePropertySheet::DoModal() { + isModal = true; + PreDoModalRTL(&m_psh); + return __super::DoModal(); +} diff --git a/src/mpc-hc/CMPCThemePropertySheet.h b/src/mpc-hc/CMPCThemePropertySheet.h index 432a9268613..8da67ed9ef4 100755 --- a/src/mpc-hc/CMPCThemePropertySheet.h +++ b/src/mpc-hc/CMPCThemePropertySheet.h @@ -1,25 +1,25 @@ -#pragma once -#include -#include "CMPCThemeUtil.h" - - -class CMPCThemePropertySheet : - public CPropertySheet - , public CMPCThemeUtil -{ - DECLARE_DYNAMIC(CMPCThemePropertySheet) - -public: - CMPCThemePropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); - CMPCThemePropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); - virtual ~CMPCThemePropertySheet(); - - virtual BOOL OnInitDialog(); - void fulfillThemeReqs(); - virtual INT_PTR DoModal(); //override to handle RTL without using SetWindowLongPtr - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - bool isModal; -}; - +#pragma once +#include +#include "CMPCThemeUtil.h" + + +class CMPCThemePropertySheet : + public CPropertySheet + , public CMPCThemeUtil +{ + DECLARE_DYNAMIC(CMPCThemePropertySheet) + +public: + CMPCThemePropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + CMPCThemePropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + virtual ~CMPCThemePropertySheet(); + + virtual BOOL OnInitDialog(); + void fulfillThemeReqs(); + virtual INT_PTR DoModal(); //override to handle RTL without using SetWindowLongPtr + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + bool isModal; +}; + diff --git a/src/mpc-hc/CMPCThemeRadioOrCheck.cpp b/src/mpc-hc/CMPCThemeRadioOrCheck.cpp index dd571c28061..8a41f971b17 100755 --- a/src/mpc-hc/CMPCThemeRadioOrCheck.cpp +++ b/src/mpc-hc/CMPCThemeRadioOrCheck.cpp @@ -1,274 +1,274 @@ -#include "stdafx.h" -#include "CMPCThemeRadioOrCheck.h" -#include "CMPCTheme.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeUtil.h" -#include "VersionHelpersInternal.h" -#include "DpiHelper.h" -#include "mplayerc.h" - -CMPCThemeRadioOrCheck::CMPCThemeRadioOrCheck() -{ - isHover = false; - buttonType = RadioOrCheck::unknownType; - isFileDialogChild = false; - buttonStyle = 0; - isAuto = false; -} - - -CMPCThemeRadioOrCheck::~CMPCThemeRadioOrCheck() -{ -} - -void CMPCThemeRadioOrCheck::PreSubclassWindow() -{ - DWORD winButtonType = (GetButtonStyle() & BS_TYPEMASK); - - if (BS_RADIOBUTTON == winButtonType || BS_AUTORADIOBUTTON == winButtonType) { - buttonType = radioType; - isAuto = BS_AUTORADIOBUTTON == winButtonType; - } else if (BS_3STATE == winButtonType || BS_AUTO3STATE == winButtonType) { - buttonType = threeStateType; - isAuto = BS_AUTO3STATE == winButtonType; - } else if (BS_CHECKBOX == winButtonType || BS_AUTOCHECKBOX == winButtonType) { - buttonType = checkType; - isAuto = BS_AUTOCHECKBOX == winButtonType; - } - ASSERT(buttonType != unknownType); - - buttonStyle = GetWindowLongPtr(GetSafeHwnd(), GWL_STYLE); - CButton::PreSubclassWindow(); -} - -IMPLEMENT_DYNAMIC(CMPCThemeRadioOrCheck, CButton) -BEGIN_MESSAGE_MAP(CMPCThemeRadioOrCheck, CButton) - ON_WM_MOUSEMOVE() - ON_WM_MOUSELEAVE() - ON_WM_PAINT() - ON_WM_ENABLE() - ON_WM_ERASEBKGND() - ON_WM_UPDATEUISTATE() -END_MESSAGE_MAP() - - -void CMPCThemeRadioOrCheck::OnPaint() -{ - if (AppIsThemeLoaded() && CMPCTheme::drawThemedControls) { - CPaintDC dc(this); - CRect rectItem; - GetClientRect(rectItem); - - COLORREF oldBkColor = dc.GetBkColor(); - COLORREF oldTextColor = dc.GetTextColor(); - - bool isDisabled = !IsWindowEnabled(); - bool isFocused = (GetFocus() == this); - - LRESULT checkState = SendMessage(BM_GETCHECK); - - CString sTitle; - GetWindowText(sTitle); - - - if (0 != (buttonStyle & BS_PUSHLIKE)) { - CFont* oFont, *font = GetFont(); - oFont = dc.SelectObject(font); - CMPCThemeButton::drawButtonBase(&dc, rectItem, sTitle, checkState != BST_UNCHECKED, isHover, isFocused, checkState == BST_INDETERMINATE, false, false, m_hWnd); - dc.SelectObject(oFont); - } else { - CRect rectCheck; - int cbWidth; - int cbHeight; - if (IsWindows8OrGreater()) { - DpiHelper dpiWindow; - dpiWindow.Override(this->GetSafeHwnd()); - cbWidth = dpiWindow.GetSystemMetricsDPI(SM_CXMENUCHECK); - cbHeight = dpiWindow.GetSystemMetricsDPI(SM_CYMENUCHECK); - } else { - cbWidth = ::GetSystemMetrics(SM_CXMENUCHECK); - cbHeight = ::GetSystemMetrics(SM_CYMENUCHECK); - } - - if (buttonStyle & BS_LEFTTEXT) { - rectCheck.left = rectItem.right - cbWidth; - rectCheck.right = rectCheck.left + cbWidth; - rectItem.right = rectCheck.left - 2; - } else { - rectCheck.left = rectItem.left; - rectCheck.right = rectCheck.left + cbWidth; - rectItem.left = rectCheck.right + 2; - } - - rectCheck.top = (rectItem.Height() - cbHeight) / 2; - rectCheck.bottom = rectCheck.top + cbHeight; - - if (buttonType == checkType) { - CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc); - } else if (buttonType == threeStateType) { - CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc); - } else if (buttonType == radioType) { - CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc, true); - } - - if (!sTitle.IsEmpty()) { - CRect centerRect = rectItem; - CFont* pOldFont, *font = GetFont(); - pOldFont = dc.SelectObject(font); - - UINT uFormat = 0; - if (buttonStyle & BS_MULTILINE) { - uFormat |= DT_WORDBREAK; - } else { - uFormat |= DT_SINGLELINE; - } - - if (buttonStyle & BS_VCENTER) { - uFormat |= DT_VCENTER; - } - - if ((buttonStyle & BS_CENTER) == BS_CENTER) { - uFormat |= DT_CENTER; - dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed - rectItem.OffsetRect((centerRect.Width() - rectItem.Width()) / 2, - (centerRect.Height() - rectItem.Height()) / 2); - } else if ((buttonStyle & BS_RIGHT) == BS_RIGHT) { - uFormat |= DT_RIGHT; - dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed - rectItem.OffsetRect(centerRect.Width() - rectItem.Width(), - (centerRect.Height() - rectItem.Height()) / 2); - } else { // if ((buttonStyle & BS_LEFT) == BS_LEFT) { - uFormat |= DT_LEFT; - dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed - rectItem.OffsetRect(0, (centerRect.Height() - rectItem.Height()) / 2); - } - - if (isFileDialogChild) { - CMPCThemeUtil::getCtlColorFileDialog(dc.GetSafeHdc(), CTLCOLOR_BTN); - } else { - dc.SetBkColor(CMPCTheme::WindowBGColor); - } - - CRect focusRect = rectItem; - focusRect.InflateRect(0, 0); - if (buttonStyle & BS_MULTILINE) { //needed to clear old select for multi-line - HBRUSH hb = CMPCThemeUtil::getParentDialogBGClr(this, &dc); - CBrush cb; - cb.Attach(hb); - dc.FrameRect(focusRect, &cb); - cb.Detach(); - } - - if (isDisabled) { - dc.SetTextColor(CMPCTheme::ButtonDisabledFGColor); - dc.DrawTextW(sTitle, -1, &rectItem, uFormat); // DT_NOPREFIX not needed - } else { - dc.SetTextColor(CMPCTheme::TextFGColor); - dc.DrawTextW(sTitle, -1, &rectItem, uFormat); // DT_NOPREFIX not needed - } - dc.SelectObject(pOldFont); - - if (isFocused) { - dc.SetTextColor(CMPCTheme::ButtonBorderKBFocusColor); //no example of this in explorer, but white seems too harsh - CBrush* dotted = dc.GetHalftoneBrush(); - dc.FrameRect(focusRect, dotted); - DeleteObject(dotted); - } - - } - } - - dc.SetBkColor(oldBkColor); - dc.SetTextColor(oldTextColor); - } else { - CButton::OnPaint(); - } -} - -void CMPCThemeRadioOrCheck::OnSetFocus(CWnd* pOldWnd) -{ - CButton::OnSetFocus(pOldWnd); - Invalidate(); -} - -void CMPCThemeRadioOrCheck::checkHover(UINT nFlags, CPoint point, bool invalidate) -{ - CRect r; - GetClientRect(r); - bool oldHover = isHover; - CPoint ptScreen = point; - ClientToScreen(&ptScreen); - - if (r.PtInRect(point) && WindowFromPoint(ptScreen)->GetSafeHwnd() == GetSafeHwnd()) { - isHover = true; - } else { - isHover = false; - } - if (isHover != oldHover && invalidate) { - Invalidate(); - } - -} - -void CMPCThemeRadioOrCheck::OnMouseMove(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point); - CButton::OnMouseMove(nFlags, point); -} - - -void CMPCThemeRadioOrCheck::OnMouseLeave() -{ - checkHover(0, CPoint(-1, -1)); - CButton::OnMouseLeave(); -} - - -void CMPCThemeRadioOrCheck::OnLButtonUp(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point, false); - CButton::OnLButtonUp(nFlags, point); -} - - -void CMPCThemeRadioOrCheck::OnLButtonDown(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point); - CButton::OnLButtonDown(nFlags, point); -} - - - -void CMPCThemeRadioOrCheck::OnEnable(BOOL bEnable) -{ - if (AppIsThemeLoaded()) { - SetRedraw(FALSE); - __super::OnEnable(bEnable); - SetRedraw(TRUE); - Invalidate(); //WM_PAINT not handled when enabling/disabling - } else { - __super::OnEnable(bEnable); - } -} - - -BOOL CMPCThemeRadioOrCheck::OnEraseBkgnd(CDC* pDC) -{ - CRect r; - GetClientRect(r); - if (isFileDialogChild) { - HBRUSH hBrush = CMPCThemeUtil::getCtlColorFileDialog(pDC->GetSafeHdc(), CTLCOLOR_BTN); - ::FillRect(pDC->GetSafeHdc(), r, hBrush); - } else { - CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); - } - return TRUE; -} - - -void CMPCThemeRadioOrCheck::OnUpdateUIState(UINT nAction, UINT nUIElement) { - if (nUIElement & UISF_HIDEACCEL) { - Invalidate(); - } - return __super::OnUpdateUIState(nAction, nUIElement); -} +#include "stdafx.h" +#include "CMPCThemeRadioOrCheck.h" +#include "CMPCTheme.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeUtil.h" +#include "VersionHelpersInternal.h" +#include "DpiHelper.h" +#include "mplayerc.h" + +CMPCThemeRadioOrCheck::CMPCThemeRadioOrCheck() +{ + isHover = false; + buttonType = RadioOrCheck::unknownType; + isFileDialogChild = false; + buttonStyle = 0; + isAuto = false; +} + + +CMPCThemeRadioOrCheck::~CMPCThemeRadioOrCheck() +{ +} + +void CMPCThemeRadioOrCheck::PreSubclassWindow() +{ + DWORD winButtonType = (GetButtonStyle() & BS_TYPEMASK); + + if (BS_RADIOBUTTON == winButtonType || BS_AUTORADIOBUTTON == winButtonType) { + buttonType = radioType; + isAuto = BS_AUTORADIOBUTTON == winButtonType; + } else if (BS_3STATE == winButtonType || BS_AUTO3STATE == winButtonType) { + buttonType = threeStateType; + isAuto = BS_AUTO3STATE == winButtonType; + } else if (BS_CHECKBOX == winButtonType || BS_AUTOCHECKBOX == winButtonType) { + buttonType = checkType; + isAuto = BS_AUTOCHECKBOX == winButtonType; + } + ASSERT(buttonType != unknownType); + + buttonStyle = GetWindowLongPtr(GetSafeHwnd(), GWL_STYLE); + CButton::PreSubclassWindow(); +} + +IMPLEMENT_DYNAMIC(CMPCThemeRadioOrCheck, CButton) +BEGIN_MESSAGE_MAP(CMPCThemeRadioOrCheck, CButton) + ON_WM_MOUSEMOVE() + ON_WM_MOUSELEAVE() + ON_WM_PAINT() + ON_WM_ENABLE() + ON_WM_ERASEBKGND() + ON_WM_UPDATEUISTATE() +END_MESSAGE_MAP() + + +void CMPCThemeRadioOrCheck::OnPaint() +{ + if (AppIsThemeLoaded() && CMPCTheme::drawThemedControls) { + CPaintDC dc(this); + CRect rectItem; + GetClientRect(rectItem); + + COLORREF oldBkColor = dc.GetBkColor(); + COLORREF oldTextColor = dc.GetTextColor(); + + bool isDisabled = !IsWindowEnabled(); + bool isFocused = (GetFocus() == this); + + LRESULT checkState = SendMessage(BM_GETCHECK); + + CString sTitle; + GetWindowText(sTitle); + + + if (0 != (buttonStyle & BS_PUSHLIKE)) { + CFont* oFont, *font = GetFont(); + oFont = dc.SelectObject(font); + CMPCThemeButton::drawButtonBase(&dc, rectItem, sTitle, checkState != BST_UNCHECKED, isHover, isFocused, checkState == BST_INDETERMINATE, false, false, m_hWnd); + dc.SelectObject(oFont); + } else { + CRect rectCheck; + int cbWidth; + int cbHeight; + if (IsWindows8OrGreater()) { + DpiHelper dpiWindow; + dpiWindow.Override(this->GetSafeHwnd()); + cbWidth = dpiWindow.GetSystemMetricsDPI(SM_CXMENUCHECK); + cbHeight = dpiWindow.GetSystemMetricsDPI(SM_CYMENUCHECK); + } else { + cbWidth = ::GetSystemMetrics(SM_CXMENUCHECK); + cbHeight = ::GetSystemMetrics(SM_CYMENUCHECK); + } + + if (buttonStyle & BS_LEFTTEXT) { + rectCheck.left = rectItem.right - cbWidth; + rectCheck.right = rectCheck.left + cbWidth; + rectItem.right = rectCheck.left - 2; + } else { + rectCheck.left = rectItem.left; + rectCheck.right = rectCheck.left + cbWidth; + rectItem.left = rectCheck.right + 2; + } + + rectCheck.top = (rectItem.Height() - cbHeight) / 2; + rectCheck.bottom = rectCheck.top + cbHeight; + + if (buttonType == checkType) { + CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc); + } else if (buttonType == threeStateType) { + CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc); + } else if (buttonType == radioType) { + CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc, true); + } + + if (!sTitle.IsEmpty()) { + CRect centerRect = rectItem; + CFont* pOldFont, *font = GetFont(); + pOldFont = dc.SelectObject(font); + + UINT uFormat = 0; + if (buttonStyle & BS_MULTILINE) { + uFormat |= DT_WORDBREAK; + } else { + uFormat |= DT_SINGLELINE; + } + + if (buttonStyle & BS_VCENTER) { + uFormat |= DT_VCENTER; + } + + if ((buttonStyle & BS_CENTER) == BS_CENTER) { + uFormat |= DT_CENTER; + dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed + rectItem.OffsetRect((centerRect.Width() - rectItem.Width()) / 2, + (centerRect.Height() - rectItem.Height()) / 2); + } else if ((buttonStyle & BS_RIGHT) == BS_RIGHT) { + uFormat |= DT_RIGHT; + dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed + rectItem.OffsetRect(centerRect.Width() - rectItem.Width(), + (centerRect.Height() - rectItem.Height()) / 2); + } else { // if ((buttonStyle & BS_LEFT) == BS_LEFT) { + uFormat |= DT_LEFT; + dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed + rectItem.OffsetRect(0, (centerRect.Height() - rectItem.Height()) / 2); + } + + if (isFileDialogChild) { + CMPCThemeUtil::getCtlColorFileDialog(dc.GetSafeHdc(), CTLCOLOR_BTN); + } else { + dc.SetBkColor(CMPCTheme::WindowBGColor); + } + + CRect focusRect = rectItem; + focusRect.InflateRect(0, 0); + if (buttonStyle & BS_MULTILINE) { //needed to clear old select for multi-line + HBRUSH hb = CMPCThemeUtil::getParentDialogBGClr(this, &dc); + CBrush cb; + cb.Attach(hb); + dc.FrameRect(focusRect, &cb); + cb.Detach(); + } + + if (isDisabled) { + dc.SetTextColor(CMPCTheme::ButtonDisabledFGColor); + dc.DrawTextW(sTitle, -1, &rectItem, uFormat); // DT_NOPREFIX not needed + } else { + dc.SetTextColor(CMPCTheme::TextFGColor); + dc.DrawTextW(sTitle, -1, &rectItem, uFormat); // DT_NOPREFIX not needed + } + dc.SelectObject(pOldFont); + + if (isFocused) { + dc.SetTextColor(CMPCTheme::ButtonBorderKBFocusColor); //no example of this in explorer, but white seems too harsh + CBrush* dotted = dc.GetHalftoneBrush(); + dc.FrameRect(focusRect, dotted); + DeleteObject(dotted); + } + + } + } + + dc.SetBkColor(oldBkColor); + dc.SetTextColor(oldTextColor); + } else { + CButton::OnPaint(); + } +} + +void CMPCThemeRadioOrCheck::OnSetFocus(CWnd* pOldWnd) +{ + CButton::OnSetFocus(pOldWnd); + Invalidate(); +} + +void CMPCThemeRadioOrCheck::checkHover(UINT nFlags, CPoint point, bool invalidate) +{ + CRect r; + GetClientRect(r); + bool oldHover = isHover; + CPoint ptScreen = point; + ClientToScreen(&ptScreen); + + if (r.PtInRect(point) && WindowFromPoint(ptScreen)->GetSafeHwnd() == GetSafeHwnd()) { + isHover = true; + } else { + isHover = false; + } + if (isHover != oldHover && invalidate) { + Invalidate(); + } + +} + +void CMPCThemeRadioOrCheck::OnMouseMove(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point); + CButton::OnMouseMove(nFlags, point); +} + + +void CMPCThemeRadioOrCheck::OnMouseLeave() +{ + checkHover(0, CPoint(-1, -1)); + CButton::OnMouseLeave(); +} + + +void CMPCThemeRadioOrCheck::OnLButtonUp(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point, false); + CButton::OnLButtonUp(nFlags, point); +} + + +void CMPCThemeRadioOrCheck::OnLButtonDown(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point); + CButton::OnLButtonDown(nFlags, point); +} + + + +void CMPCThemeRadioOrCheck::OnEnable(BOOL bEnable) +{ + if (AppIsThemeLoaded()) { + SetRedraw(FALSE); + __super::OnEnable(bEnable); + SetRedraw(TRUE); + Invalidate(); //WM_PAINT not handled when enabling/disabling + } else { + __super::OnEnable(bEnable); + } +} + + +BOOL CMPCThemeRadioOrCheck::OnEraseBkgnd(CDC* pDC) +{ + CRect r; + GetClientRect(r); + if (isFileDialogChild) { + HBRUSH hBrush = CMPCThemeUtil::getCtlColorFileDialog(pDC->GetSafeHdc(), CTLCOLOR_BTN); + ::FillRect(pDC->GetSafeHdc(), r, hBrush); + } else { + CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); + } + return TRUE; +} + + +void CMPCThemeRadioOrCheck::OnUpdateUIState(UINT nAction, UINT nUIElement) { + if (nUIElement & UISF_HIDEACCEL) { + Invalidate(); + } + return __super::OnUpdateUIState(nAction, nUIElement); +} diff --git a/src/mpc-hc/CMPCThemeRadioOrCheck.h b/src/mpc-hc/CMPCThemeRadioOrCheck.h index 6918b79f926..c4d2ac6cd46 100755 --- a/src/mpc-hc/CMPCThemeRadioOrCheck.h +++ b/src/mpc-hc/CMPCThemeRadioOrCheck.h @@ -1,38 +1,38 @@ -#pragma once -#include -class CMPCThemeRadioOrCheck : public CButton -{ -public: - CMPCThemeRadioOrCheck(); - virtual ~CMPCThemeRadioOrCheck(); - void PreSubclassWindow(); -private: - bool isHover; - BOOL isAuto; - CBrush bgBrush; - DWORD buttonStyle; - enum RadioOrCheck { - radioType, - checkType, - threeStateType, - unknownType - }; - RadioOrCheck buttonType; -protected: - bool isFileDialogChild; - DECLARE_DYNAMIC(CMPCThemeRadioOrCheck) - DECLARE_MESSAGE_MAP() - afx_msg void OnSetFocus(CWnd* pOldWnd); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - void checkHover(UINT nFlags, CPoint point, bool invalidate = true); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); -public: - afx_msg void OnPaint(); - afx_msg void OnEnable(BOOL bEnable); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - void setFileDialogChild(bool set) { isFileDialogChild = set; }; - afx_msg void OnUpdateUIState(UINT nAction, UINT nUIElement); -}; - +#pragma once +#include +class CMPCThemeRadioOrCheck : public CButton +{ +public: + CMPCThemeRadioOrCheck(); + virtual ~CMPCThemeRadioOrCheck(); + void PreSubclassWindow(); +private: + bool isHover; + BOOL isAuto; + CBrush bgBrush; + DWORD buttonStyle; + enum RadioOrCheck { + radioType, + checkType, + threeStateType, + unknownType + }; + RadioOrCheck buttonType; +protected: + bool isFileDialogChild; + DECLARE_DYNAMIC(CMPCThemeRadioOrCheck) + DECLARE_MESSAGE_MAP() + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + void checkHover(UINT nFlags, CPoint point, bool invalidate = true); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); +public: + afx_msg void OnPaint(); + afx_msg void OnEnable(BOOL bEnable); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + void setFileDialogChild(bool set) { isFileDialogChild = set; }; + afx_msg void OnUpdateUIState(UINT nAction, UINT nUIElement); +}; + diff --git a/src/mpc-hc/CMPCThemeResizableDialog.cpp b/src/mpc-hc/CMPCThemeResizableDialog.cpp index 170438e8704..5138288f3bd 100755 --- a/src/mpc-hc/CMPCThemeResizableDialog.cpp +++ b/src/mpc-hc/CMPCThemeResizableDialog.cpp @@ -1,51 +1,51 @@ -#include "stdafx.h" -#include "CMPCThemeResizableDialog.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - -CMPCThemeResizableDialog::CMPCThemeResizableDialog() -{ -} - -CMPCThemeResizableDialog::CMPCThemeResizableDialog(UINT nIDTemplate, CWnd* pParent): CResizableDialog(nIDTemplate, pParent) -{ -} - -CMPCThemeResizableDialog::CMPCThemeResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParent): CResizableDialog(lpszTemplateName, pParent) -{ -} - - -CMPCThemeResizableDialog::~CMPCThemeResizableDialog() -{ -} - -BOOL CMPCThemeResizableDialog::OnInitDialog() { - BOOL ret = CResizableDialog::OnInitDialog(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return ret; -} - -void CMPCThemeResizableDialog::fulfillThemeReqs() -{ - if (AppNeedsThemedControls()) { - CMPCThemeUtil::enableWindows10DarkFrame(this); - SetSizeGripBkMode(TRANSPARENT); //fix for gripper in mpc theme - CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); - } -} - -BEGIN_MESSAGE_MAP(CMPCThemeResizableDialog, CResizableDialog) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeResizableDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} +#include "stdafx.h" +#include "CMPCThemeResizableDialog.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + +CMPCThemeResizableDialog::CMPCThemeResizableDialog() +{ +} + +CMPCThemeResizableDialog::CMPCThemeResizableDialog(UINT nIDTemplate, CWnd* pParent): CResizableDialog(nIDTemplate, pParent) +{ +} + +CMPCThemeResizableDialog::CMPCThemeResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParent): CResizableDialog(lpszTemplateName, pParent) +{ +} + + +CMPCThemeResizableDialog::~CMPCThemeResizableDialog() +{ +} + +BOOL CMPCThemeResizableDialog::OnInitDialog() { + BOOL ret = CResizableDialog::OnInitDialog(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return ret; +} + +void CMPCThemeResizableDialog::fulfillThemeReqs() +{ + if (AppNeedsThemedControls()) { + CMPCThemeUtil::enableWindows10DarkFrame(this); + SetSizeGripBkMode(TRANSPARENT); //fix for gripper in mpc theme + CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); + } +} + +BEGIN_MESSAGE_MAP(CMPCThemeResizableDialog, CResizableDialog) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeResizableDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} diff --git a/src/mpc-hc/CMPCThemeResizableDialog.h b/src/mpc-hc/CMPCThemeResizableDialog.h index 712990f542e..96e304c9898 100755 --- a/src/mpc-hc/CMPCThemeResizableDialog.h +++ b/src/mpc-hc/CMPCThemeResizableDialog.h @@ -1,19 +1,19 @@ -#pragma once -#include "CMPCThemeButton.h" -#include "CMPCThemeGroupBox.h" -#include "CMPCThemeLinkCtrl.h" -#include "CMPCThemeUtil.h" -class CMPCThemeResizableDialog : public CResizableDialog, public CMPCThemeUtil -{ -public: - CMPCThemeResizableDialog(); - CMPCThemeResizableDialog(UINT nIDTemplate, CWnd* pParent = nullptr); - CMPCThemeResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); - virtual ~CMPCThemeResizableDialog(); - BOOL OnInitDialog(); - void fulfillThemeReqs(); - DECLARE_MESSAGE_MAP() -public: - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -}; - +#pragma once +#include "CMPCThemeButton.h" +#include "CMPCThemeGroupBox.h" +#include "CMPCThemeLinkCtrl.h" +#include "CMPCThemeUtil.h" +class CMPCThemeResizableDialog : public CResizableDialog, public CMPCThemeUtil +{ +public: + CMPCThemeResizableDialog(); + CMPCThemeResizableDialog(UINT nIDTemplate, CWnd* pParent = nullptr); + CMPCThemeResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); + virtual ~CMPCThemeResizableDialog(); + BOOL OnInitDialog(); + void fulfillThemeReqs(); + DECLARE_MESSAGE_MAP() +public: + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +}; + diff --git a/src/mpc-hc/CMPCThemeScrollBar.cpp b/src/mpc-hc/CMPCThemeScrollBar.cpp index 56abb7f19d6..064eb055751 100755 --- a/src/mpc-hc/CMPCThemeScrollBar.cpp +++ b/src/mpc-hc/CMPCThemeScrollBar.cpp @@ -1,280 +1,280 @@ -#include "stdafx.h" -#include "DpiHelper.h" -#include "CMPCThemeScrollBar.h" -#include "CMPCTheme.h" -#include "CMPCThemeListBox.h" -#include "CMPCThemeEdit.h" - -IMPLEMENT_DYNAMIC(CMPCThemeScrollBar, CXeScrollBarBase) - -BEGIN_MESSAGE_MAP(CMPCThemeScrollBar, CXeScrollBarBase) - // ON_WM_MOUSEWHEEL() -END_MESSAGE_MAP() - -CMPCThemeScrollBar::CMPCThemeScrollBar(): - haveInitScrollInfo(false) - , disableNoScroll(false) -{ -} - - -CMPCThemeScrollBar::~CMPCThemeScrollBar() -{ -} - -void CMPCThemeScrollBar::drawSBArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation) -{ - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - Gdiplus::Graphics gfx(dc.m_hDC); - Gdiplus::Color clr; - clr.SetFromCOLORREF(arrowClr); - - int dpi = dpiWindow.DPIX(); - - int xPos; - int yPos; - int xsign, ysign; - int rows, steps; - - if (dpi < 120) { - rows = 3; - steps = 3; - } else if (dpi < 144) { - rows = 3; - steps = 4; - } else if (dpi < 168) { - rows = 4; - steps = 5; - } else if (dpi < 192) { - rows = 4; - steps = 5; - } else { - rows = 4; - steps = 5; - } - - float shortDim = steps + rows; - int indent; - switch (orientation) { - case arrowLeft: - indent = ceil((arrowRect.Width() - shortDim) / 2); - xPos = arrowRect.right - indent - 1; //left and right arrows are pegged to the inside edge - yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; - xsign = -1; - ysign = 1; - break; - case arrowRight: - indent = ceil((arrowRect.Width() - shortDim) / 2); - yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; - xPos = arrowRect.left + indent; //left and right arrows are pegged to the inside edge - xsign = 1; - ysign = 1; - break; - case arrowTop: - xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - indent = ceil((arrowRect.Height() - shortDim) / 2); - yPos = arrowRect.top + indent + shortDim - 1; //top and bottom arrows are pegged to the top edge - xsign = 1; - ysign = -1; - break; - case arrowBottom: - default: - xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - indent = ceil((arrowRect.Height() - shortDim) / 2); - yPos = arrowRect.top + indent; //top and bottom arrows are pegged to the top edge - xsign = 1; - ysign = 1; - break; - } - - gfx.SetSmoothingMode(Gdiplus::SmoothingModeNone); - Gdiplus::Pen pen(clr, 1); - for (int i = 0; i < rows; i++) { - if (orientation == arrowLeft || orientation == arrowRight) { - gfx.DrawLine(&pen, xPos + i * xsign, yPos, xPos + (steps + i) * xsign, steps * ysign + yPos); - gfx.DrawLine(&pen, xPos + (steps + i) * xsign, steps * ysign + yPos, xPos + i * xsign, (steps * 2) * ysign + yPos); - } else { - gfx.DrawLine(&pen, xPos, yPos + i * ysign, steps * xsign + xPos, yPos + (steps + i) * ysign); - gfx.DrawLine(&pen, steps * xsign + xPos, yPos + (steps + i) * ysign, (steps * 2) * xsign + xPos, yPos + i * ysign); - } - } - -} - - -void CMPCThemeScrollBar::DrawScrollBar(CDC* pDC) -{ - CRect rcC; - GetClientRect(&rcC); - - // Draw to memory DC - CDC dcMem; - dcMem.CreateCompatibleDC(pDC); - CBitmap bmMem; - bmMem.CreateCompatibleBitmap(pDC, rcC.Width(), rcC.Height()); - CBitmap* pOldBm = dcMem.SelectObject(&bmMem); - - - CBrush brushBG(CMPCTheme::ScrollBGColor); - dcMem.FillRect(rcC, &brushBG); - - CBrush brushChannel(CMPCTheme::ScrollBGColor); - - XSB_EDRAWELEM eState; - const CRect* prcElem = 0; - stXSB_AREA stArea; - - for (int nElem = eTLbutton; nElem <= eThumb; nElem++) { - stArea.eArea = (eXSB_AREA)nElem; - - prcElem = GetUIelementDrawState(stArea.eArea, eState); - if (!prcElem || eState == eNotDrawn) { // Rect empty or area not drawn? - continue; - } - - CRect butRect = prcElem; - if (m_bHorizontal) { - butRect.top += 1; - butRect.bottom -= 1; - } else { - butRect.left += 1; - butRect.right -= 1; - } - - - if (stArea.IsButton()) { - CBrush brushButton; - COLORREF buttonClr = RGB(0, 0, 0); - COLORREF buttonFGClr = CMPCTheme::ScrollButtonArrowColor; - switch (eState) { - case eDisabled: - //no example found of disabled dark scrollbar, but when disabled, button bg = scroll bg - //(see notepad for example of disabled non-dark--bg color matches disabled button) - buttonClr = CMPCTheme::ScrollBGColor; - break; - case eNormal: - buttonClr = CMPCTheme::ScrollBGColor; - break; - case eDown: - buttonClr = CMPCTheme::ScrollButtonClickColor; - buttonFGClr = CMPCTheme::ScrollButtonArrowClickColor; - break; - case eHot: - buttonClr = CMPCTheme::ScrollButtonHoverColor; - break; - default: - ASSERT(FALSE); // Unknown state! - } - brushButton.CreateSolidBrush(buttonClr); - dcMem.FillRect(butRect, &brushButton); - brushButton.DeleteObject(); - - if (m_bHorizontal) { - if (nElem == eTLbutton) { //top or left - drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowLeft); - } else { - drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowRight); - } - } else { - if (nElem == eTLbutton) { //top or left - drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowTop); - } else { - drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowBottom); - } - } - - } else if (stArea.IsChannel()) { - if (m_bHorizontal) { - dcMem.FillRect(prcElem, &brushChannel); - } else { - dcMem.FillRect(prcElem, &brushChannel); - } - } else { // Is thumb - CBrush brushThumb; - switch (eState) { - case eDisabled: - //no example found of disabled dark scrollbar, but when disabled, we will hide the thumb entirely. put bg color here for now - brushThumb.CreateSolidBrush(CMPCTheme::ScrollBGColor); - break; - case eNormal: - brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbColor); - break; - case eDown: - brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbDragColor); - break; - case eHot: - brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbHoverColor); - break; - default: - ASSERT(FALSE); // Unknown state! - } - dcMem.FillRect(butRect, &brushThumb); - brushThumb.DeleteObject(); - } - } - - pDC->BitBlt(0, 0, rcC.Width(), rcC.Height(), &dcMem, 0, 0, SRCCOPY); - - dcMem.SelectObject(pOldBm); - bmMem.DeleteObject(); -} - -void CMPCThemeScrollBar::SendScrollMsg(WORD wSBcode, WORD wHiWPARAM /*= 0*/) -{ - ASSERT(::IsWindow(m_hWnd)); - if (nullptr != m_scrollWindow && ::IsWindow(m_scrollWindow->m_hWnd)) { - if (SB_ENDSCROLL != wSBcode) { - m_scrollWindow->SendMessage((m_bHorizontal) ? WM_HSCROLL : WM_VSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); - } - } else if (nullptr != m_pParent && ::IsWindow(m_pParent->m_hWnd)) { - m_pParent->SendMessage((m_bHorizontal) ? WM_HSCROLL : WM_VSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); - } -} - -void CMPCThemeScrollBar::setScrollWindow(CWnd* window) -{ - this->m_scrollWindow = window; - if (DYNAMIC_DOWNCAST(CMPCThemeEdit, window)) { - disableNoScroll = true; - } else if (DYNAMIC_DOWNCAST(CMPCThemeListBox, window)) { - disableNoScroll = 0 != (window->GetStyle() & LBS_DISABLENOSCROLL); - } -} - -void CMPCThemeScrollBar::updateScrollInfo() -{ - if (GetStyle() & WS_VISIBLE) { - SCROLLINFO si = { 0 }, siSelf = { 0 }; - si.cbSize = sizeof(SCROLLINFO); - si.fMask = SIF_ALL; - m_scrollWindow->GetScrollInfo(m_bHorizontal ? SB_HORZ : SB_VERT, &si); - siSelf.cbSize = sizeof(SCROLLINFO); - siSelf.fMask = SIF_ALL; - GetScrollInfo(&siSelf); - if (si.nMax != siSelf.nMax || si.nMin != siSelf.nMin || si.nPos != siSelf.nPos || si.nPage != siSelf.nPage || !haveInitScrollInfo) { - if (disableNoScroll) { - si.fMask |= SIF_DISABLENOSCROLL; - } - SetScrollInfo(&si); - haveInitScrollInfo = true; - } - } -} - -BOOL CMPCThemeScrollBar::PreTranslateMessage(MSG* pMsg) -{ - switch (pMsg->message) { - case WM_MOUSEWHEEL: - //windows with integrated scrollbars handle mousewheel messages themselves - //we have to send it manually since our parent is not the scrollwindow - if (nullptr != m_scrollWindow && ::IsWindow(m_scrollWindow->m_hWnd)) { - m_scrollWindow->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam); - return TRUE; - } - break; - } - return __super::PreTranslateMessage(pMsg); -} - +#include "stdafx.h" +#include "DpiHelper.h" +#include "CMPCThemeScrollBar.h" +#include "CMPCTheme.h" +#include "CMPCThemeListBox.h" +#include "CMPCThemeEdit.h" + +IMPLEMENT_DYNAMIC(CMPCThemeScrollBar, CXeScrollBarBase) + +BEGIN_MESSAGE_MAP(CMPCThemeScrollBar, CXeScrollBarBase) + // ON_WM_MOUSEWHEEL() +END_MESSAGE_MAP() + +CMPCThemeScrollBar::CMPCThemeScrollBar(): + haveInitScrollInfo(false) + , disableNoScroll(false) +{ +} + + +CMPCThemeScrollBar::~CMPCThemeScrollBar() +{ +} + +void CMPCThemeScrollBar::drawSBArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation) +{ + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + Gdiplus::Graphics gfx(dc.m_hDC); + Gdiplus::Color clr; + clr.SetFromCOLORREF(arrowClr); + + int dpi = dpiWindow.DPIX(); + + int xPos; + int yPos; + int xsign, ysign; + int rows, steps; + + if (dpi < 120) { + rows = 3; + steps = 3; + } else if (dpi < 144) { + rows = 3; + steps = 4; + } else if (dpi < 168) { + rows = 4; + steps = 5; + } else if (dpi < 192) { + rows = 4; + steps = 5; + } else { + rows = 4; + steps = 5; + } + + float shortDim = steps + rows; + int indent; + switch (orientation) { + case arrowLeft: + indent = ceil((arrowRect.Width() - shortDim) / 2); + xPos = arrowRect.right - indent - 1; //left and right arrows are pegged to the inside edge + yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; + xsign = -1; + ysign = 1; + break; + case arrowRight: + indent = ceil((arrowRect.Width() - shortDim) / 2); + yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; + xPos = arrowRect.left + indent; //left and right arrows are pegged to the inside edge + xsign = 1; + ysign = 1; + break; + case arrowTop: + xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + indent = ceil((arrowRect.Height() - shortDim) / 2); + yPos = arrowRect.top + indent + shortDim - 1; //top and bottom arrows are pegged to the top edge + xsign = 1; + ysign = -1; + break; + case arrowBottom: + default: + xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + indent = ceil((arrowRect.Height() - shortDim) / 2); + yPos = arrowRect.top + indent; //top and bottom arrows are pegged to the top edge + xsign = 1; + ysign = 1; + break; + } + + gfx.SetSmoothingMode(Gdiplus::SmoothingModeNone); + Gdiplus::Pen pen(clr, 1); + for (int i = 0; i < rows; i++) { + if (orientation == arrowLeft || orientation == arrowRight) { + gfx.DrawLine(&pen, xPos + i * xsign, yPos, xPos + (steps + i) * xsign, steps * ysign + yPos); + gfx.DrawLine(&pen, xPos + (steps + i) * xsign, steps * ysign + yPos, xPos + i * xsign, (steps * 2) * ysign + yPos); + } else { + gfx.DrawLine(&pen, xPos, yPos + i * ysign, steps * xsign + xPos, yPos + (steps + i) * ysign); + gfx.DrawLine(&pen, steps * xsign + xPos, yPos + (steps + i) * ysign, (steps * 2) * xsign + xPos, yPos + i * ysign); + } + } + +} + + +void CMPCThemeScrollBar::DrawScrollBar(CDC* pDC) +{ + CRect rcC; + GetClientRect(&rcC); + + // Draw to memory DC + CDC dcMem; + dcMem.CreateCompatibleDC(pDC); + CBitmap bmMem; + bmMem.CreateCompatibleBitmap(pDC, rcC.Width(), rcC.Height()); + CBitmap* pOldBm = dcMem.SelectObject(&bmMem); + + + CBrush brushBG(CMPCTheme::ScrollBGColor); + dcMem.FillRect(rcC, &brushBG); + + CBrush brushChannel(CMPCTheme::ScrollBGColor); + + XSB_EDRAWELEM eState; + const CRect* prcElem = 0; + stXSB_AREA stArea; + + for (int nElem = eTLbutton; nElem <= eThumb; nElem++) { + stArea.eArea = (eXSB_AREA)nElem; + + prcElem = GetUIelementDrawState(stArea.eArea, eState); + if (!prcElem || eState == eNotDrawn) { // Rect empty or area not drawn? + continue; + } + + CRect butRect = prcElem; + if (m_bHorizontal) { + butRect.top += 1; + butRect.bottom -= 1; + } else { + butRect.left += 1; + butRect.right -= 1; + } + + + if (stArea.IsButton()) { + CBrush brushButton; + COLORREF buttonClr = RGB(0, 0, 0); + COLORREF buttonFGClr = CMPCTheme::ScrollButtonArrowColor; + switch (eState) { + case eDisabled: + //no example found of disabled dark scrollbar, but when disabled, button bg = scroll bg + //(see notepad for example of disabled non-dark--bg color matches disabled button) + buttonClr = CMPCTheme::ScrollBGColor; + break; + case eNormal: + buttonClr = CMPCTheme::ScrollBGColor; + break; + case eDown: + buttonClr = CMPCTheme::ScrollButtonClickColor; + buttonFGClr = CMPCTheme::ScrollButtonArrowClickColor; + break; + case eHot: + buttonClr = CMPCTheme::ScrollButtonHoverColor; + break; + default: + ASSERT(FALSE); // Unknown state! + } + brushButton.CreateSolidBrush(buttonClr); + dcMem.FillRect(butRect, &brushButton); + brushButton.DeleteObject(); + + if (m_bHorizontal) { + if (nElem == eTLbutton) { //top or left + drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowLeft); + } else { + drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowRight); + } + } else { + if (nElem == eTLbutton) { //top or left + drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowTop); + } else { + drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowBottom); + } + } + + } else if (stArea.IsChannel()) { + if (m_bHorizontal) { + dcMem.FillRect(prcElem, &brushChannel); + } else { + dcMem.FillRect(prcElem, &brushChannel); + } + } else { // Is thumb + CBrush brushThumb; + switch (eState) { + case eDisabled: + //no example found of disabled dark scrollbar, but when disabled, we will hide the thumb entirely. put bg color here for now + brushThumb.CreateSolidBrush(CMPCTheme::ScrollBGColor); + break; + case eNormal: + brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbColor); + break; + case eDown: + brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbDragColor); + break; + case eHot: + brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbHoverColor); + break; + default: + ASSERT(FALSE); // Unknown state! + } + dcMem.FillRect(butRect, &brushThumb); + brushThumb.DeleteObject(); + } + } + + pDC->BitBlt(0, 0, rcC.Width(), rcC.Height(), &dcMem, 0, 0, SRCCOPY); + + dcMem.SelectObject(pOldBm); + bmMem.DeleteObject(); +} + +void CMPCThemeScrollBar::SendScrollMsg(WORD wSBcode, WORD wHiWPARAM /*= 0*/) +{ + ASSERT(::IsWindow(m_hWnd)); + if (nullptr != m_scrollWindow && ::IsWindow(m_scrollWindow->m_hWnd)) { + if (SB_ENDSCROLL != wSBcode) { + m_scrollWindow->SendMessage((m_bHorizontal) ? WM_HSCROLL : WM_VSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); + } + } else if (nullptr != m_pParent && ::IsWindow(m_pParent->m_hWnd)) { + m_pParent->SendMessage((m_bHorizontal) ? WM_HSCROLL : WM_VSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); + } +} + +void CMPCThemeScrollBar::setScrollWindow(CWnd* window) +{ + this->m_scrollWindow = window; + if (DYNAMIC_DOWNCAST(CMPCThemeEdit, window)) { + disableNoScroll = true; + } else if (DYNAMIC_DOWNCAST(CMPCThemeListBox, window)) { + disableNoScroll = 0 != (window->GetStyle() & LBS_DISABLENOSCROLL); + } +} + +void CMPCThemeScrollBar::updateScrollInfo() +{ + if (GetStyle() & WS_VISIBLE) { + SCROLLINFO si = { 0 }, siSelf = { 0 }; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_ALL; + m_scrollWindow->GetScrollInfo(m_bHorizontal ? SB_HORZ : SB_VERT, &si); + siSelf.cbSize = sizeof(SCROLLINFO); + siSelf.fMask = SIF_ALL; + GetScrollInfo(&siSelf); + if (si.nMax != siSelf.nMax || si.nMin != siSelf.nMin || si.nPos != siSelf.nPos || si.nPage != siSelf.nPage || !haveInitScrollInfo) { + if (disableNoScroll) { + si.fMask |= SIF_DISABLENOSCROLL; + } + SetScrollInfo(&si); + haveInitScrollInfo = true; + } + } +} + +BOOL CMPCThemeScrollBar::PreTranslateMessage(MSG* pMsg) +{ + switch (pMsg->message) { + case WM_MOUSEWHEEL: + //windows with integrated scrollbars handle mousewheel messages themselves + //we have to send it manually since our parent is not the scrollwindow + if (nullptr != m_scrollWindow && ::IsWindow(m_scrollWindow->m_hWnd)) { + m_scrollWindow->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam); + return TRUE; + } + break; + } + return __super::PreTranslateMessage(pMsg); +} + diff --git a/src/mpc-hc/CMPCThemeScrollBar.h b/src/mpc-hc/CMPCThemeScrollBar.h index 8c2502b27be..077b114479a 100755 --- a/src/mpc-hc/CMPCThemeScrollBar.h +++ b/src/mpc-hc/CMPCThemeScrollBar.h @@ -1,31 +1,31 @@ -#pragma once -#include -#include "XeScrollBar/XeScrollBarBase.h" - -class CMPCThemeScrollBar : public CXeScrollBarBase -{ - DECLARE_DYNAMIC(CMPCThemeScrollBar) -public: - CMPCThemeScrollBar(); - virtual ~CMPCThemeScrollBar(); - enum arrowOrientation { - arrowLeft, - arrowRight, - arrowTop, - arrowBottom - }; - void DrawScrollBar(CDC* pDC); - virtual void SendScrollMsg(WORD wSBcode, WORD wHiWPARAM); - void setScrollWindow(CWnd* window); - void updateScrollInfo(); - BOOL PreTranslateMessage(MSG* pMsg); - void updateScrollInfo(int nPos); -protected: - CWnd* m_scrollWindow; //real parent is window we overlay the SB - DECLARE_MESSAGE_MAP() - UINT scrollLines; - bool haveInitScrollInfo; - bool disableNoScroll; - void drawSBArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation); -}; - +#pragma once +#include +#include "XeScrollBar/XeScrollBarBase.h" + +class CMPCThemeScrollBar : public CXeScrollBarBase +{ + DECLARE_DYNAMIC(CMPCThemeScrollBar) +public: + CMPCThemeScrollBar(); + virtual ~CMPCThemeScrollBar(); + enum arrowOrientation { + arrowLeft, + arrowRight, + arrowTop, + arrowBottom + }; + void DrawScrollBar(CDC* pDC); + virtual void SendScrollMsg(WORD wSBcode, WORD wHiWPARAM); + void setScrollWindow(CWnd* window); + void updateScrollInfo(); + BOOL PreTranslateMessage(MSG* pMsg); + void updateScrollInfo(int nPos); +protected: + CWnd* m_scrollWindow; //real parent is window we overlay the SB + DECLARE_MESSAGE_MAP() + UINT scrollLines; + bool haveInitScrollInfo; + bool disableNoScroll; + void drawSBArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation); +}; + diff --git a/src/mpc-hc/CMPCThemeScrollBarHelper.cpp b/src/mpc-hc/CMPCThemeScrollBarHelper.cpp index 2adeaa9f8f3..6ba4fda95b8 100644 --- a/src/mpc-hc/CMPCThemeScrollBarHelper.cpp +++ b/src/mpc-hc/CMPCThemeScrollBarHelper.cpp @@ -1,348 +1,348 @@ -#include "stdafx.h" -#include "CMPCThemeScrollBarHelper.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" - -CMPCThemeScrollBarHelper::CMPCThemeScrollBarHelper(CWnd* scrollWindow) - :helperInfo(nullptr) - ,setWindowRegionActive(false) -{ - window = scrollWindow; - pParent = nullptr; -} - - -CMPCThemeScrollBarHelper::~CMPCThemeScrollBarHelper() -{ -} - -void CMPCThemeScrollBarHelper::createThemedScrollBars() -{ - pParent = window->GetParent(); - ScrollBarHelperInfo i(window); - if (nullptr != pParent && IsWindow(pParent->m_hWnd)) { - if (i.canVSB && !IsWindow(vertSB.m_hWnd)) { - VERIFY(vertSB.Create(SBS_VERT | WS_CHILD | - WS_VISIBLE, CRect(0, 0, 0, 0), pParent, 0)); - vertSB.setScrollWindow(window); //we want messages from this SB - } - - if (i.canHSB && !IsWindow(horzSB.m_hWnd)) { - VERIFY(horzSB.Create(SBS_HORZ | WS_CHILD | - WS_VISIBLE, CRect(0, 0, 0, 0), pParent, 0)); - horzSB.setScrollWindow(window); //we want messages from this SB - } - } - hideNativeScrollBars(); -} - -void CMPCThemeScrollBarHelper::OnWindowPosChanged() { - { - std::lock_guard lck(helperMutex); - //this is to prevent recursive calls to OnWindowPos due to SetWindowRgn - if (!setWindowRegionActive) { - hideNativeScrollBars(); - } - } -} - -void CMPCThemeScrollBarHelper::setWindowRegionExclusive(HRGN h) { - { - std::lock_guard lck(helperMutex); - setWindowRegionActive = true; - } - window->SetWindowRgn(h, false); - { - std::lock_guard lck(helperMutex); - setWindowRegionActive = false; - } -} - -void CMPCThemeScrollBarHelper::hideNativeScrollBars() -{ - - if (!CMPCThemeUtil::IsWindowVisibleAndRendered(window)) { - return; - } - - bool windowChanged = helperInfo.UpdateHelperInfo(window); - - ScrollBarHelperInfo& i = helperInfo; - CRect wr = i.wr; - CRect horzRect, vertRect; - bool needsRegion = false; - - if (IsWindow(vertSB.m_hWnd)) { - if (i.canVSB) { - int width = i.sbThickness, height = wr.bottom - wr.top - 2 * i.borderThickness - (i.canHSB ? i.sbThickness : 0); - needsRegion = true; - - vertRect = CRect(CPoint(i.wrOnParent.right - width - i.borderThickness, i.wrOnParent.top + i.borderThickness), CSize(width, height)); - vertSB.MoveWindow(vertRect); - vertSB.ShowWindow(SW_SHOW); - updateScrollInfo(); - } else { - if (vertSB.IsWindowVisible()) { - CRect sbWR; - vertSB.GetWindowRect(sbWR); - vertSB.ShowWindow(SW_HIDE); - window->ScreenToClient(sbWR); - window->RedrawWindow(sbWR, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); - } - } - } - - if (IsWindow(horzSB.m_hWnd)) { - if (i.canHSB) { - int height = i.sbThickness, width = wr.right - wr.left - 2 * i.borderThickness - (i.canVSB ? i.sbThickness : 0); - needsRegion = true; - - horzRect = CRect(CPoint(i.wrOnParent.left + i.borderThickness, i.wrOnParent.bottom - height - i.borderThickness), CSize(width, height)); - horzSB.MoveWindow(horzRect); - horzSB.ShowWindow(SW_SHOW); - updateScrollInfo(); - } else { - if (horzSB.IsWindowVisible()) { - CRect sbWR; - horzSB.GetWindowRect(sbWR); - horzSB.ShowWindow(SW_HIDE); - window->ScreenToClient(sbWR); - window->RedrawWindow(sbWR, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); - } - } - } - if (needsRegion) { - if (windowChanged) { - HRGN contentRgn = CreateRectRgn(wr.left, wr.top, wr.right, wr.bottom); - if (!vertRect.IsRectEmpty()) { - ::MapWindowPoints(pParent->GetSafeHwnd(), window->GetSafeHwnd(), (LPPOINT)&vertRect, 2); - vertRect += helperInfo.clientOffset; - HRGN vertRgn = CreateRectRgnIndirect(vertRect); - CombineRgn(contentRgn, contentRgn, vertRgn, RGN_DIFF); - } - if (!horzRect.IsRectEmpty()) { - ::MapWindowPoints(pParent->GetSafeHwnd(), window->GetSafeHwnd(), (LPPOINT)&horzRect, 2); - horzRect += helperInfo.clientOffset; - HRGN horzRgn = CreateRectRgnIndirect(horzRect); - CombineRgn(contentRgn, contentRgn, horzRgn, RGN_DIFF); - } - setWindowRegionExclusive(contentRgn); - } - } else { - setWindowRegionExclusive(NULL); - } -} - -void CMPCThemeScrollBarHelper::updateScrollInfo(bool invalidate /*=false*/) -{ - if (IsWindow(vertSB.m_hWnd)) { - vertSB.updateScrollInfo(); - if (invalidate) { - vertSB.Invalidate(); - } - } - if (IsWindow(horzSB.m_hWnd)) { - horzSB.updateScrollInfo(); - if (invalidate) { - horzSB.Invalidate(); - } - } -} - - -//clistctrl does not seem to scroll when receiving thumb messages, so we handle them here -//this will allow the scrollbar to update as well -//inspired by flyhigh https://www.codeproject.com/Articles/14724/Replace-a-Window-s-Internal-Scrollbar-with-a-custo -//changed to avoid glitchy redraws and only update the scrollbar that has been changed -bool CMPCThemeScrollBarHelper::WindowProc(CListCtrl* list, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_VSCROLL || message == WM_HSCROLL) { - WORD sbCode = LOWORD(wParam); - if (sbCode == SB_THUMBTRACK || sbCode == SB_THUMBPOSITION) { - SCROLLINFO siv = { 0 }; - siv.cbSize = sizeof(SCROLLINFO); - siv.fMask = SIF_ALL; - SCROLLINFO sih = siv; - int nPos = HIWORD(wParam); - CRect rcClient; - list->GetClientRect(&rcClient); - - SIZE sizeAll; - SIZE size = { 0, 0 }; - if (WM_VSCROLL == message) { - list->GetScrollInfo(SB_VERT, &siv); - if (siv.nPage == 0) { - sizeAll.cy = rcClient.bottom; - } else { - sizeAll.cy = rcClient.bottom * (siv.nMax + 1) / siv.nPage; - } - size.cy = sizeAll.cy * (nPos - siv.nPos) / (siv.nMax + 1); - } else { - list->GetScrollInfo(SB_HORZ, &sih); - if (sih.nPage == 0) { - sizeAll.cx = rcClient.right; - } else { - sizeAll.cx = rcClient.right * (sih.nMax + 1) / sih.nPage; - } - size.cx = sizeAll.cx * (nPos - sih.nPos) / (sih.nMax + 1); - } - //adipose: this code is needed to prevent listctrl glitchy drawing. - //scroll sends a cascade of redraws which are untenable during a thumb drag - //only one redraw per scroll call this way - if (nullptr != pParent && IsWindow(pParent->m_hWnd)) { - pParent->SetRedraw(FALSE); - list->Scroll(size); - pParent->SetRedraw(); - list->Invalidate(); - CHeaderCtrl* hdrCtrl = list->GetHeaderCtrl(); - if (nullptr != hdrCtrl) { - hdrCtrl->Invalidate(); - } - } - return true; //processed - } - } - return false; -} - -bool CMPCThemeScrollBarHelper::WindowProc(CTreeCtrl* tree, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_VSCROLL || message == WM_HSCROLL) { - WORD sbCode = LOWORD(wParam); - if (sbCode == SB_THUMBTRACK || sbCode == SB_THUMBPOSITION) { - SCROLLINFO siv = { 0 }; - siv.cbSize = sizeof(SCROLLINFO); - siv.fMask = SIF_ALL; - SCROLLINFO sih = siv; - int nPos = HIWORD(wParam); - CRect rcClient; - tree->GetClientRect(&rcClient); - tree->GetScrollInfo(SB_VERT, &siv); - tree->GetScrollInfo(SB_HORZ, &sih); - - WPARAM wp = (WPARAM) - 1; - int lines = 0; - if (WM_VSCROLL == message) { - wp = nPos < siv.nPos ? SB_LINEUP : SB_LINEDOWN; - lines = abs(nPos - siv.nPos); - } else { - wp = nPos < sih.nPos ? SB_LINELEFT : SB_LINERIGHT; - lines = abs(nPos - sih.nPos); - } - - if (-1 != wp && nullptr != pParent && IsWindow(pParent->m_hWnd)) { - pParent->SetRedraw(FALSE); - while (lines-- > 0) { - tree->SendMessage(message, wp, 0); - } - pParent->SetRedraw(); - tree->Invalidate(); - } - return true; //processed - } - } - return false; -} - -void CMPCThemeScrollBarHelper::themedNcPaintWithSB() -{ - createThemedScrollBars(); - doNcPaint(window); -} - -void CMPCThemeScrollBarHelper::themedNcPaint(CWnd* window, CMPCThemeScrollable* swindow) -{ - if (window->GetStyle() & WS_HSCROLL) { - SCROLLBARINFO sbHorz = { sizeof(SCROLLBARINFO) }; - if (window->GetScrollBarInfo(OBJID_HSCROLL, &sbHorz)) { - if (0 == (sbHorz.rgstate[0] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_UNAVAILABLE))) { - swindow->doDefault(); //required to get the horz sb buttons to draw in listctrl - } - } - } - - doNcPaint(window); - if (window->GetStyle() & WS_VSCROLL) { - window->SetScrollPos(SB_VERT, window->GetScrollPos(SB_VERT), TRUE); - } -} - -ScrollBarHelperInfo::ScrollBarHelperInfo(CWnd* w): - wr(), corner(), wrOnParent() - ,sbThickness(0), borderThickness(0) - ,canVSB(false), canHSB(false), needsSBCorner(false) -{ - if (w && w->m_hWnd && IsWindow(w->m_hWnd)) { - w->GetWindowRect(wr); - - wrOnParent = wr; - CWnd* pParent = w->GetParent(); - if (nullptr != pParent) { - pParent->ScreenToClient(wrOnParent); - } - - wr.OffsetRect(-wr.left, -wr.top); - - sbThickness = GetSystemMetrics(SM_CXVSCROLL); - clientOffset = CMPCThemeUtil::GetRegionOffset(w); - borderThickness = clientOffset.x; - - auto style = w->GetStyle(); - //we have to draw vertical scrollbar because ncpaint is overridden to handle horizontal scrollbar - //windows dark theme horizontal scrollbar is broken - //exceptions: SB simply disappears if window is less than border thickness - canVSB = 0 != (style & WS_VSCROLL) && sbThickness < wr.Width() - borderThickness * 2; - canHSB = 0 != (style & WS_HSCROLL) && sbThickness < wr.Height() - borderThickness * 2; - needsSBCorner = (style & (WS_VSCROLL | WS_HSCROLL)) == (WS_VSCROLL | WS_HSCROLL) && canVSB && canHSB; - corner = { wr.right - sbThickness - borderThickness, wr.bottom - sbThickness - borderThickness, wr.right - borderThickness, wr.bottom - borderThickness }; - } -} - -bool ScrollBarHelperInfo::UpdateHelperInfo(CWnd* w) { - ScrollBarHelperInfo tmp(w); - if (tmp == *this) { - return false; - } - *this = tmp; - return true; -} - -bool ScrollBarHelperInfo::operator==(ScrollBarHelperInfo& other) { - return other.borderThickness == borderThickness && other.sbThickness == sbThickness //dimensions - && other.wr == wr && other.wrOnParent == wrOnParent && other.corner == corner //rects - && other.clientOffset == clientOffset - && other.canHSB == canHSB && other.canVSB == canVSB && other.needsSBCorner == needsSBCorner //bools - ; -} - -void CMPCThemeScrollBarHelper::doNcPaint(CWnd* window) -{ - HRGN currentRgn = CreateRectRgn(0, 0, 0, 0); - int rType = window->GetWindowRgn(currentRgn); - window->SetWindowRgn(NULL, false); - - CWindowDC dc(window); - int oldDC = dc.SaveDC(); - - CRect clip; - ScrollBarHelperInfo i(window); - - CRect &wr = i.wr; - - clip = wr; //client rect is insufficient to clip scrollbars - clip.DeflateRect(i.borderThickness, i.borderThickness); - dc.ExcludeClipRect(clip); - CBrush brush(CMPCTheme::WindowBorderColorLight); //color used for column sep in explorer - dc.FillSolidRect(wr, CMPCTheme::ContentBGColor); - dc.FrameRect(wr, &brush); - - dc.RestoreDC(oldDC); - if (i.needsSBCorner) { - dc.FillSolidRect(i.corner, CMPCTheme::ContentBGColor); - } - - if (rType == COMPLEXREGION || rType == SIMPLEREGION) { - window->SetWindowRgn(currentRgn, false); - } -} - +#include "stdafx.h" +#include "CMPCThemeScrollBarHelper.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" + +CMPCThemeScrollBarHelper::CMPCThemeScrollBarHelper(CWnd* scrollWindow) + :helperInfo(nullptr) + ,setWindowRegionActive(false) +{ + window = scrollWindow; + pParent = nullptr; +} + + +CMPCThemeScrollBarHelper::~CMPCThemeScrollBarHelper() +{ +} + +void CMPCThemeScrollBarHelper::createThemedScrollBars() +{ + pParent = window->GetParent(); + ScrollBarHelperInfo i(window); + if (nullptr != pParent && IsWindow(pParent->m_hWnd)) { + if (i.canVSB && !IsWindow(vertSB.m_hWnd)) { + VERIFY(vertSB.Create(SBS_VERT | WS_CHILD | + WS_VISIBLE, CRect(0, 0, 0, 0), pParent, 0)); + vertSB.setScrollWindow(window); //we want messages from this SB + } + + if (i.canHSB && !IsWindow(horzSB.m_hWnd)) { + VERIFY(horzSB.Create(SBS_HORZ | WS_CHILD | + WS_VISIBLE, CRect(0, 0, 0, 0), pParent, 0)); + horzSB.setScrollWindow(window); //we want messages from this SB + } + } + hideNativeScrollBars(); +} + +void CMPCThemeScrollBarHelper::OnWindowPosChanged() { + { + std::lock_guard lck(helperMutex); + //this is to prevent recursive calls to OnWindowPos due to SetWindowRgn + if (!setWindowRegionActive) { + hideNativeScrollBars(); + } + } +} + +void CMPCThemeScrollBarHelper::setWindowRegionExclusive(HRGN h) { + { + std::lock_guard lck(helperMutex); + setWindowRegionActive = true; + } + window->SetWindowRgn(h, false); + { + std::lock_guard lck(helperMutex); + setWindowRegionActive = false; + } +} + +void CMPCThemeScrollBarHelper::hideNativeScrollBars() +{ + + if (!CMPCThemeUtil::IsWindowVisibleAndRendered(window)) { + return; + } + + bool windowChanged = helperInfo.UpdateHelperInfo(window); + + ScrollBarHelperInfo& i = helperInfo; + CRect wr = i.wr; + CRect horzRect, vertRect; + bool needsRegion = false; + + if (IsWindow(vertSB.m_hWnd)) { + if (i.canVSB) { + int width = i.sbThickness, height = wr.bottom - wr.top - 2 * i.borderThickness - (i.canHSB ? i.sbThickness : 0); + needsRegion = true; + + vertRect = CRect(CPoint(i.wrOnParent.right - width - i.borderThickness, i.wrOnParent.top + i.borderThickness), CSize(width, height)); + vertSB.MoveWindow(vertRect); + vertSB.ShowWindow(SW_SHOW); + updateScrollInfo(); + } else { + if (vertSB.IsWindowVisible()) { + CRect sbWR; + vertSB.GetWindowRect(sbWR); + vertSB.ShowWindow(SW_HIDE); + window->ScreenToClient(sbWR); + window->RedrawWindow(sbWR, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + } + } + } + + if (IsWindow(horzSB.m_hWnd)) { + if (i.canHSB) { + int height = i.sbThickness, width = wr.right - wr.left - 2 * i.borderThickness - (i.canVSB ? i.sbThickness : 0); + needsRegion = true; + + horzRect = CRect(CPoint(i.wrOnParent.left + i.borderThickness, i.wrOnParent.bottom - height - i.borderThickness), CSize(width, height)); + horzSB.MoveWindow(horzRect); + horzSB.ShowWindow(SW_SHOW); + updateScrollInfo(); + } else { + if (horzSB.IsWindowVisible()) { + CRect sbWR; + horzSB.GetWindowRect(sbWR); + horzSB.ShowWindow(SW_HIDE); + window->ScreenToClient(sbWR); + window->RedrawWindow(sbWR, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + } + } + } + if (needsRegion) { + if (windowChanged) { + HRGN contentRgn = CreateRectRgn(wr.left, wr.top, wr.right, wr.bottom); + if (!vertRect.IsRectEmpty()) { + ::MapWindowPoints(pParent->GetSafeHwnd(), window->GetSafeHwnd(), (LPPOINT)&vertRect, 2); + vertRect += helperInfo.clientOffset; + HRGN vertRgn = CreateRectRgnIndirect(vertRect); + CombineRgn(contentRgn, contentRgn, vertRgn, RGN_DIFF); + } + if (!horzRect.IsRectEmpty()) { + ::MapWindowPoints(pParent->GetSafeHwnd(), window->GetSafeHwnd(), (LPPOINT)&horzRect, 2); + horzRect += helperInfo.clientOffset; + HRGN horzRgn = CreateRectRgnIndirect(horzRect); + CombineRgn(contentRgn, contentRgn, horzRgn, RGN_DIFF); + } + setWindowRegionExclusive(contentRgn); + } + } else { + setWindowRegionExclusive(NULL); + } +} + +void CMPCThemeScrollBarHelper::updateScrollInfo(bool invalidate /*=false*/) +{ + if (IsWindow(vertSB.m_hWnd)) { + vertSB.updateScrollInfo(); + if (invalidate) { + vertSB.Invalidate(); + } + } + if (IsWindow(horzSB.m_hWnd)) { + horzSB.updateScrollInfo(); + if (invalidate) { + horzSB.Invalidate(); + } + } +} + + +//clistctrl does not seem to scroll when receiving thumb messages, so we handle them here +//this will allow the scrollbar to update as well +//inspired by flyhigh https://www.codeproject.com/Articles/14724/Replace-a-Window-s-Internal-Scrollbar-with-a-custo +//changed to avoid glitchy redraws and only update the scrollbar that has been changed +bool CMPCThemeScrollBarHelper::WindowProc(CListCtrl* list, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_VSCROLL || message == WM_HSCROLL) { + WORD sbCode = LOWORD(wParam); + if (sbCode == SB_THUMBTRACK || sbCode == SB_THUMBPOSITION) { + SCROLLINFO siv = { 0 }; + siv.cbSize = sizeof(SCROLLINFO); + siv.fMask = SIF_ALL; + SCROLLINFO sih = siv; + int nPos = HIWORD(wParam); + CRect rcClient; + list->GetClientRect(&rcClient); + + SIZE sizeAll; + SIZE size = { 0, 0 }; + if (WM_VSCROLL == message) { + list->GetScrollInfo(SB_VERT, &siv); + if (siv.nPage == 0) { + sizeAll.cy = rcClient.bottom; + } else { + sizeAll.cy = rcClient.bottom * (siv.nMax + 1) / siv.nPage; + } + size.cy = sizeAll.cy * (nPos - siv.nPos) / (siv.nMax + 1); + } else { + list->GetScrollInfo(SB_HORZ, &sih); + if (sih.nPage == 0) { + sizeAll.cx = rcClient.right; + } else { + sizeAll.cx = rcClient.right * (sih.nMax + 1) / sih.nPage; + } + size.cx = sizeAll.cx * (nPos - sih.nPos) / (sih.nMax + 1); + } + //adipose: this code is needed to prevent listctrl glitchy drawing. + //scroll sends a cascade of redraws which are untenable during a thumb drag + //only one redraw per scroll call this way + if (nullptr != pParent && IsWindow(pParent->m_hWnd)) { + pParent->SetRedraw(FALSE); + list->Scroll(size); + pParent->SetRedraw(); + list->Invalidate(); + CHeaderCtrl* hdrCtrl = list->GetHeaderCtrl(); + if (nullptr != hdrCtrl) { + hdrCtrl->Invalidate(); + } + } + return true; //processed + } + } + return false; +} + +bool CMPCThemeScrollBarHelper::WindowProc(CTreeCtrl* tree, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_VSCROLL || message == WM_HSCROLL) { + WORD sbCode = LOWORD(wParam); + if (sbCode == SB_THUMBTRACK || sbCode == SB_THUMBPOSITION) { + SCROLLINFO siv = { 0 }; + siv.cbSize = sizeof(SCROLLINFO); + siv.fMask = SIF_ALL; + SCROLLINFO sih = siv; + int nPos = HIWORD(wParam); + CRect rcClient; + tree->GetClientRect(&rcClient); + tree->GetScrollInfo(SB_VERT, &siv); + tree->GetScrollInfo(SB_HORZ, &sih); + + WPARAM wp = (WPARAM) - 1; + int lines = 0; + if (WM_VSCROLL == message) { + wp = nPos < siv.nPos ? SB_LINEUP : SB_LINEDOWN; + lines = abs(nPos - siv.nPos); + } else { + wp = nPos < sih.nPos ? SB_LINELEFT : SB_LINERIGHT; + lines = abs(nPos - sih.nPos); + } + + if (-1 != wp && nullptr != pParent && IsWindow(pParent->m_hWnd)) { + pParent->SetRedraw(FALSE); + while (lines-- > 0) { + tree->SendMessage(message, wp, 0); + } + pParent->SetRedraw(); + tree->Invalidate(); + } + return true; //processed + } + } + return false; +} + +void CMPCThemeScrollBarHelper::themedNcPaintWithSB() +{ + createThemedScrollBars(); + doNcPaint(window); +} + +void CMPCThemeScrollBarHelper::themedNcPaint(CWnd* window, CMPCThemeScrollable* swindow) +{ + if (window->GetStyle() & WS_HSCROLL) { + SCROLLBARINFO sbHorz = { sizeof(SCROLLBARINFO) }; + if (window->GetScrollBarInfo(OBJID_HSCROLL, &sbHorz)) { + if (0 == (sbHorz.rgstate[0] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_UNAVAILABLE))) { + swindow->doDefault(); //required to get the horz sb buttons to draw in listctrl + } + } + } + + doNcPaint(window); + if (window->GetStyle() & WS_VSCROLL) { + window->SetScrollPos(SB_VERT, window->GetScrollPos(SB_VERT), TRUE); + } +} + +ScrollBarHelperInfo::ScrollBarHelperInfo(CWnd* w): + wr(), corner(), wrOnParent() + ,sbThickness(0), borderThickness(0) + ,canVSB(false), canHSB(false), needsSBCorner(false) +{ + if (w && w->m_hWnd && IsWindow(w->m_hWnd)) { + w->GetWindowRect(wr); + + wrOnParent = wr; + CWnd* pParent = w->GetParent(); + if (nullptr != pParent) { + pParent->ScreenToClient(wrOnParent); + } + + wr.OffsetRect(-wr.left, -wr.top); + + sbThickness = GetSystemMetrics(SM_CXVSCROLL); + clientOffset = CMPCThemeUtil::GetRegionOffset(w); + borderThickness = clientOffset.x; + + auto style = w->GetStyle(); + //we have to draw vertical scrollbar because ncpaint is overridden to handle horizontal scrollbar + //windows dark theme horizontal scrollbar is broken + //exceptions: SB simply disappears if window is less than border thickness + canVSB = 0 != (style & WS_VSCROLL) && sbThickness < wr.Width() - borderThickness * 2; + canHSB = 0 != (style & WS_HSCROLL) && sbThickness < wr.Height() - borderThickness * 2; + needsSBCorner = (style & (WS_VSCROLL | WS_HSCROLL)) == (WS_VSCROLL | WS_HSCROLL) && canVSB && canHSB; + corner = { wr.right - sbThickness - borderThickness, wr.bottom - sbThickness - borderThickness, wr.right - borderThickness, wr.bottom - borderThickness }; + } +} + +bool ScrollBarHelperInfo::UpdateHelperInfo(CWnd* w) { + ScrollBarHelperInfo tmp(w); + if (tmp == *this) { + return false; + } + *this = tmp; + return true; +} + +bool ScrollBarHelperInfo::operator==(ScrollBarHelperInfo& other) { + return other.borderThickness == borderThickness && other.sbThickness == sbThickness //dimensions + && other.wr == wr && other.wrOnParent == wrOnParent && other.corner == corner //rects + && other.clientOffset == clientOffset + && other.canHSB == canHSB && other.canVSB == canVSB && other.needsSBCorner == needsSBCorner //bools + ; +} + +void CMPCThemeScrollBarHelper::doNcPaint(CWnd* window) +{ + HRGN currentRgn = CreateRectRgn(0, 0, 0, 0); + int rType = window->GetWindowRgn(currentRgn); + window->SetWindowRgn(NULL, false); + + CWindowDC dc(window); + int oldDC = dc.SaveDC(); + + CRect clip; + ScrollBarHelperInfo i(window); + + CRect &wr = i.wr; + + clip = wr; //client rect is insufficient to clip scrollbars + clip.DeflateRect(i.borderThickness, i.borderThickness); + dc.ExcludeClipRect(clip); + CBrush brush(CMPCTheme::WindowBorderColorLight); //color used for column sep in explorer + dc.FillSolidRect(wr, CMPCTheme::ContentBGColor); + dc.FrameRect(wr, &brush); + + dc.RestoreDC(oldDC); + if (i.needsSBCorner) { + dc.FillSolidRect(i.corner, CMPCTheme::ContentBGColor); + } + + if (rType == COMPLEXREGION || rType == SIMPLEREGION) { + window->SetWindowRgn(currentRgn, false); + } +} + diff --git a/src/mpc-hc/CMPCThemeScrollBarHelper.h b/src/mpc-hc/CMPCThemeScrollBarHelper.h index 44619bcec7b..282b0ece944 100755 --- a/src/mpc-hc/CMPCThemeScrollBarHelper.h +++ b/src/mpc-hc/CMPCThemeScrollBarHelper.h @@ -1,51 +1,51 @@ -#pragma once -#include "CMPCThemeScrollBar.h" -#include -class CMPCThemeTreeCtrl; - -class CMPCThemeScrollable -{ -public: - CMPCThemeScrollable() {}; - ~CMPCThemeScrollable() {}; - virtual void doDefault() {}; -}; - -class ScrollBarHelperInfo { -public: - ScrollBarHelperInfo(CWnd* w); - bool UpdateHelperInfo(CWnd* w); - bool operator==(ScrollBarHelperInfo& lhs); - bool operator!=(ScrollBarHelperInfo& lhs) { return !operator==(lhs); } - CRect wr, corner, wrOnParent; - CPoint clientOffset; - int sbThickness; - int borderThickness; - bool canVSB; - bool canHSB; - bool needsSBCorner; -}; - -class CMPCThemeScrollBarHelper -{ -protected: - CWnd* window, *pParent; - CMPCThemeScrollBar vertSB, horzSB; - ScrollBarHelperInfo helperInfo; - std::recursive_mutex helperMutex; - bool setWindowRegionActive; - static void doNcPaint(CWnd* window); -public: - CMPCThemeScrollBarHelper(CWnd* scrollWindow); - ~CMPCThemeScrollBarHelper(); - void createThemedScrollBars(); - void OnWindowPosChanged(); - void setWindowRegionExclusive(HRGN h); - void hideNativeScrollBars(); - void updateScrollInfo(bool invalidate = false); - bool WindowProc(CListCtrl* list, UINT message, WPARAM wParam, LPARAM lParam); - bool WindowProc(CTreeCtrl* tree, UINT message, WPARAM wParam, LPARAM lParam); - void themedNcPaintWithSB(); - static void themedNcPaint(CWnd* window, CMPCThemeScrollable* swindow); -}; - +#pragma once +#include "CMPCThemeScrollBar.h" +#include +class CMPCThemeTreeCtrl; + +class CMPCThemeScrollable +{ +public: + CMPCThemeScrollable() {}; + ~CMPCThemeScrollable() {}; + virtual void doDefault() {}; +}; + +class ScrollBarHelperInfo { +public: + ScrollBarHelperInfo(CWnd* w); + bool UpdateHelperInfo(CWnd* w); + bool operator==(ScrollBarHelperInfo& lhs); + bool operator!=(ScrollBarHelperInfo& lhs) { return !operator==(lhs); } + CRect wr, corner, wrOnParent; + CPoint clientOffset; + int sbThickness; + int borderThickness; + bool canVSB; + bool canHSB; + bool needsSBCorner; +}; + +class CMPCThemeScrollBarHelper +{ +protected: + CWnd* window, *pParent; + CMPCThemeScrollBar vertSB, horzSB; + ScrollBarHelperInfo helperInfo; + std::recursive_mutex helperMutex; + bool setWindowRegionActive; + static void doNcPaint(CWnd* window); +public: + CMPCThemeScrollBarHelper(CWnd* scrollWindow); + ~CMPCThemeScrollBarHelper(); + void createThemedScrollBars(); + void OnWindowPosChanged(); + void setWindowRegionExclusive(HRGN h); + void hideNativeScrollBars(); + void updateScrollInfo(bool invalidate = false); + bool WindowProc(CListCtrl* list, UINT message, WPARAM wParam, LPARAM lParam); + bool WindowProc(CTreeCtrl* tree, UINT message, WPARAM wParam, LPARAM lParam); + void themedNcPaintWithSB(); + static void themedNcPaint(CWnd* window, CMPCThemeScrollable* swindow); +}; + diff --git a/src/mpc-hc/CMPCThemeSliderCtrl.cpp b/src/mpc-hc/CMPCThemeSliderCtrl.cpp index 7e214c239a8..080ad31522f 100755 --- a/src/mpc-hc/CMPCThemeSliderCtrl.cpp +++ b/src/mpc-hc/CMPCThemeSliderCtrl.cpp @@ -1,201 +1,201 @@ -#include "stdafx.h" -#include "CMPCThemeSliderCtrl.h" -#include "CMPCTheme.h" -#include "mplayerc.h" -#undef SubclassWindow - -CMPCThemeSliderCtrl::CMPCThemeSliderCtrl() - : m_bDrag(false), m_bHover(false), lockToZero(false) -{ - -} - - -CMPCThemeSliderCtrl::~CMPCThemeSliderCtrl() -{ -} - -void CMPCThemeSliderCtrl::PreSubclassWindow() -{ - if (AppIsThemeLoaded()) { - CToolTipCtrl* pTip = GetToolTips(); - if (nullptr != pTip) { - themedToolTip.SubclassWindow(pTip->m_hWnd); - } - } -} - -IMPLEMENT_DYNAMIC(CMPCThemeSliderCtrl, CSliderCtrl) - -BEGIN_MESSAGE_MAP(CMPCThemeSliderCtrl, CSliderCtrl) - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeSliderCtrl::OnNMCustomdraw) - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONUP() - ON_WM_MOUSELEAVE() - ON_WM_MOUSEWHEEL() -END_MESSAGE_MAP() - - -void CMPCThemeSliderCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); - LRESULT lr = CDRF_DODEFAULT; - - if (AppIsThemeLoaded()) { - switch (pNMCD->dwDrawStage) { - case CDDS_PREPAINT: - lr = CDRF_NOTIFYITEMDRAW; - break; - - case CDDS_ITEMPREPAINT: - - if (pNMCD->dwItemSpec == TBCD_CHANNEL) { - CDC dc; - dc.Attach(pNMCD->hdc); - - CRect rect; - GetClientRect(rect); - dc.FillSolidRect(&rect, CMPCTheme::WindowBGColor); - - CRect channelRect; - GetChannelRect(channelRect); - CRect thumbRect; - GetThumbRect(thumbRect); - - CRect r; - if (TBS_VERT == (GetStyle() & TBS_VERT)) { - channelRect = CRect(channelRect.top, channelRect.left, channelRect.bottom, channelRect.right); //for vertical, channelrect returns 90deg rotated dimensions - channelRect.NormalizeRect(); - CopyRect(&pNMCD->rc, CRect(thumbRect.left + 2, channelRect.top, thumbRect.right - 3, channelRect.bottom - 2)); - CopyRect(r, &pNMCD->rc); - r.DeflateRect(6, 0, 6, 0); - } - else { - CopyRect(&pNMCD->rc, CRect(channelRect.left, thumbRect.top + 2, channelRect.right - 2, thumbRect.bottom - 3)); - CopyRect(r, &pNMCD->rc); - r.DeflateRect(0, 6, 0, 6); - } - - - dc.FillSolidRect(r, CMPCTheme::SliderChannelColor); - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - - dc.Detach(); - lr = CDRF_SKIPDEFAULT; - } else if (pNMCD->dwItemSpec == TBCD_THUMB) { - CDC dc; - dc.Attach(pNMCD->hdc); - pNMCD->rc.bottom--; - CRect r(pNMCD->rc); - r.DeflateRect(0, 0, 1, 0); - - CBrush fb; - if (m_bDrag) { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbDragColor); - } else if (m_bHover) { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbHoverColor); - } else { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbColor); - } - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - - dc.Detach(); - lr = CDRF_SKIPDEFAULT; - } - - break; - }; - } - - *pResult = lr; -} - -void CMPCThemeSliderCtrl::invalidateThumb() -{ - int max = GetRangeMax(); - SetRangeMax(max, TRUE); -} - - -void CMPCThemeSliderCtrl::checkHover(CPoint point) -{ - CRect thumbRect; - GetThumbRect(thumbRect); - bool oldHover = m_bHover; - m_bHover = false; - if (thumbRect.PtInRect(point)) { - m_bHover = true; - } - - if (m_bHover != oldHover) { - invalidateThumb(); - } -} - -void CMPCThemeSliderCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - checkHover(point); - CSliderCtrl::OnMouseMove(nFlags, point); -} - - -void CMPCThemeSliderCtrl::OnLButtonUp(UINT nFlags, CPoint point) -{ - m_bDrag = false; - invalidateThumb(); - checkHover(point); - CSliderCtrl::OnLButtonUp(nFlags, point); -} - - -void CMPCThemeSliderCtrl::OnMouseLeave() -{ - checkHover(CPoint(-1, -1)); - CSliderCtrl::OnMouseLeave(); -} - - -void CMPCThemeSliderCtrl::SendScrollMsg(WORD wSBcode, WORD wHiWPARAM /*= 0*/) { - ASSERT(::IsWindow(m_hWnd)); - CWnd* m_pParent = GetParent(); - if (m_pParent && ::IsWindow(m_pParent->m_hWnd)) { - bool isVert = GetStyle() & TBS_VERT; - m_pParent->SendMessage(isVert ? WM_VSCROLL : WM_HSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); - } -} - -BOOL CMPCThemeSliderCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { - if (lockToZero) { - WORD wSBcode = 0xFFFF; - int dir = 1; - if (zDelta >= WHEEL_DELTA) { - wSBcode = SB_LINEUP; - } else if (zDelta <= -WHEEL_DELTA) { - wSBcode = SB_LINEDOWN; - dir = -1; - zDelta = -zDelta; - } - if (wSBcode != 0xFFFF) { - int scrollIncrememt = (GetRangeMax() - GetRangeMin()) / 50; - do { - SendScrollMsg(wSBcode); - int curPos = GetPos(); - int newPos = curPos + dir * scrollIncrememt; - if (abs(newPos) < abs(scrollIncrememt) && SGN(newPos) != SGN(curPos)) { //we crossed zero and are in between +/- scrollIncrement - newPos = 0; - } - SetPos(newPos); - } while ((zDelta -= WHEEL_DELTA) >= WHEEL_DELTA); - SendScrollMsg(SB_ENDSCROLL); - } - - return 1; // Message was processed. (was 0, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 1 if scrolling enabled - } else { - return CSliderCtrl::OnMouseWheel(nFlags, zDelta, pt); - } -} +#include "stdafx.h" +#include "CMPCThemeSliderCtrl.h" +#include "CMPCTheme.h" +#include "mplayerc.h" +#undef SubclassWindow + +CMPCThemeSliderCtrl::CMPCThemeSliderCtrl() + : m_bDrag(false), m_bHover(false), lockToZero(false) +{ + +} + + +CMPCThemeSliderCtrl::~CMPCThemeSliderCtrl() +{ +} + +void CMPCThemeSliderCtrl::PreSubclassWindow() +{ + if (AppIsThemeLoaded()) { + CToolTipCtrl* pTip = GetToolTips(); + if (nullptr != pTip) { + themedToolTip.SubclassWindow(pTip->m_hWnd); + } + } +} + +IMPLEMENT_DYNAMIC(CMPCThemeSliderCtrl, CSliderCtrl) + +BEGIN_MESSAGE_MAP(CMPCThemeSliderCtrl, CSliderCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeSliderCtrl::OnNMCustomdraw) + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONUP() + ON_WM_MOUSELEAVE() + ON_WM_MOUSEWHEEL() +END_MESSAGE_MAP() + + +void CMPCThemeSliderCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); + LRESULT lr = CDRF_DODEFAULT; + + if (AppIsThemeLoaded()) { + switch (pNMCD->dwDrawStage) { + case CDDS_PREPAINT: + lr = CDRF_NOTIFYITEMDRAW; + break; + + case CDDS_ITEMPREPAINT: + + if (pNMCD->dwItemSpec == TBCD_CHANNEL) { + CDC dc; + dc.Attach(pNMCD->hdc); + + CRect rect; + GetClientRect(rect); + dc.FillSolidRect(&rect, CMPCTheme::WindowBGColor); + + CRect channelRect; + GetChannelRect(channelRect); + CRect thumbRect; + GetThumbRect(thumbRect); + + CRect r; + if (TBS_VERT == (GetStyle() & TBS_VERT)) { + channelRect = CRect(channelRect.top, channelRect.left, channelRect.bottom, channelRect.right); //for vertical, channelrect returns 90deg rotated dimensions + channelRect.NormalizeRect(); + CopyRect(&pNMCD->rc, CRect(thumbRect.left + 2, channelRect.top, thumbRect.right - 3, channelRect.bottom - 2)); + CopyRect(r, &pNMCD->rc); + r.DeflateRect(6, 0, 6, 0); + } + else { + CopyRect(&pNMCD->rc, CRect(channelRect.left, thumbRect.top + 2, channelRect.right - 2, thumbRect.bottom - 3)); + CopyRect(r, &pNMCD->rc); + r.DeflateRect(0, 6, 0, 6); + } + + + dc.FillSolidRect(r, CMPCTheme::SliderChannelColor); + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + + dc.Detach(); + lr = CDRF_SKIPDEFAULT; + } else if (pNMCD->dwItemSpec == TBCD_THUMB) { + CDC dc; + dc.Attach(pNMCD->hdc); + pNMCD->rc.bottom--; + CRect r(pNMCD->rc); + r.DeflateRect(0, 0, 1, 0); + + CBrush fb; + if (m_bDrag) { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbDragColor); + } else if (m_bHover) { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbHoverColor); + } else { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbColor); + } + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + + dc.Detach(); + lr = CDRF_SKIPDEFAULT; + } + + break; + }; + } + + *pResult = lr; +} + +void CMPCThemeSliderCtrl::invalidateThumb() +{ + int max = GetRangeMax(); + SetRangeMax(max, TRUE); +} + + +void CMPCThemeSliderCtrl::checkHover(CPoint point) +{ + CRect thumbRect; + GetThumbRect(thumbRect); + bool oldHover = m_bHover; + m_bHover = false; + if (thumbRect.PtInRect(point)) { + m_bHover = true; + } + + if (m_bHover != oldHover) { + invalidateThumb(); + } +} + +void CMPCThemeSliderCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + checkHover(point); + CSliderCtrl::OnMouseMove(nFlags, point); +} + + +void CMPCThemeSliderCtrl::OnLButtonUp(UINT nFlags, CPoint point) +{ + m_bDrag = false; + invalidateThumb(); + checkHover(point); + CSliderCtrl::OnLButtonUp(nFlags, point); +} + + +void CMPCThemeSliderCtrl::OnMouseLeave() +{ + checkHover(CPoint(-1, -1)); + CSliderCtrl::OnMouseLeave(); +} + + +void CMPCThemeSliderCtrl::SendScrollMsg(WORD wSBcode, WORD wHiWPARAM /*= 0*/) { + ASSERT(::IsWindow(m_hWnd)); + CWnd* m_pParent = GetParent(); + if (m_pParent && ::IsWindow(m_pParent->m_hWnd)) { + bool isVert = GetStyle() & TBS_VERT; + m_pParent->SendMessage(isVert ? WM_VSCROLL : WM_HSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); + } +} + +BOOL CMPCThemeSliderCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { + if (lockToZero) { + WORD wSBcode = 0xFFFF; + int dir = 1; + if (zDelta >= WHEEL_DELTA) { + wSBcode = SB_LINEUP; + } else if (zDelta <= -WHEEL_DELTA) { + wSBcode = SB_LINEDOWN; + dir = -1; + zDelta = -zDelta; + } + if (wSBcode != 0xFFFF) { + int scrollIncrememt = (GetRangeMax() - GetRangeMin()) / 50; + do { + SendScrollMsg(wSBcode); + int curPos = GetPos(); + int newPos = curPos + dir * scrollIncrememt; + if (abs(newPos) < abs(scrollIncrememt) && SGN(newPos) != SGN(curPos)) { //we crossed zero and are in between +/- scrollIncrement + newPos = 0; + } + SetPos(newPos); + } while ((zDelta -= WHEEL_DELTA) >= WHEEL_DELTA); + SendScrollMsg(SB_ENDSCROLL); + } + + return 1; // Message was processed. (was 0, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 1 if scrolling enabled + } else { + return CSliderCtrl::OnMouseWheel(nFlags, zDelta, pt); + } +} diff --git a/src/mpc-hc/CMPCThemeSliderCtrl.h b/src/mpc-hc/CMPCThemeSliderCtrl.h index 31b0165fceb..0f5db77a87c 100755 --- a/src/mpc-hc/CMPCThemeSliderCtrl.h +++ b/src/mpc-hc/CMPCThemeSliderCtrl.h @@ -1,28 +1,28 @@ -#pragma once -#include -#include "CMPCThemeToolTipCtrl.h" - -class CMPCThemeSliderCtrl : public CSliderCtrl -{ -public: - CMPCThemeSliderCtrl(); - virtual ~CMPCThemeSliderCtrl(); - virtual void PreSubclassWindow(); - DECLARE_DYNAMIC(CMPCThemeSliderCtrl) - DECLARE_MESSAGE_MAP() -protected: - CBrush bgBrush; - bool m_bDrag, m_bHover, lockToZero; - CMPCThemeToolTipCtrl themedToolTip; -public: - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - void invalidateThumb(); - void checkHover(CPoint point); - void SendScrollMsg(WORD wSBcode, WORD wHiWPARAM = 0); - void SetLockToZero(bool enable = true) { lockToZero = enable; }; - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); -}; - +#pragma once +#include +#include "CMPCThemeToolTipCtrl.h" + +class CMPCThemeSliderCtrl : public CSliderCtrl +{ +public: + CMPCThemeSliderCtrl(); + virtual ~CMPCThemeSliderCtrl(); + virtual void PreSubclassWindow(); + DECLARE_DYNAMIC(CMPCThemeSliderCtrl) + DECLARE_MESSAGE_MAP() +protected: + CBrush bgBrush; + bool m_bDrag, m_bHover, lockToZero; + CMPCThemeToolTipCtrl themedToolTip; +public: + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + void invalidateThumb(); + void checkHover(CPoint point); + void SendScrollMsg(WORD wSBcode, WORD wHiWPARAM = 0); + void SetLockToZero(bool enable = true) { lockToZero = enable; }; + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); +}; + diff --git a/src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp b/src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp index 493e121b276..dec930635c2 100755 --- a/src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp +++ b/src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp @@ -1,236 +1,236 @@ -#include "stdafx.h" -#include "DpiHelper.h" -#include "CMPCThemeSpinButtonCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeEdit.h" -#include "mplayerc.h" - -CMPCThemeSpinButtonCtrl::CMPCThemeSpinButtonCtrl() -{ -} - - -CMPCThemeSpinButtonCtrl::~CMPCThemeSpinButtonCtrl() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeSpinButtonCtrl, CSpinButtonCtrl) -BEGIN_MESSAGE_MAP(CMPCThemeSpinButtonCtrl, CSpinButtonCtrl) - ON_WM_PAINT() - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONDOWN() - ON_WM_LBUTTONUP() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - - -void CMPCThemeSpinButtonCtrl::drawSpinArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation) -{ - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - Gdiplus::Graphics gfx(dc.m_hDC); - Gdiplus::Color clr; - clr.SetFromCOLORREF(arrowClr); - - int dpi = dpiWindow.DPIX(); - float steps; - - if (dpi < 120) { - steps = 2; - } else if (dpi < 144) { - steps = 3; - } else if (dpi < 168) { - steps = 4; - } else if (dpi < 192) { - steps = 4; - } else { - steps = 4.5; - } - - int xPos; - int yPos; - int xsign, ysign; - switch (orientation) { - case arrowLeft: - xPos = arrowRect.right - (arrowRect.Width() - (steps)) / 2; - yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; - xsign = -1; - ysign = 1; - break; - case arrowRight: - xPos = arrowRect.left + (arrowRect.Width() - (steps + 1)) / 2; - yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; - xsign = 1; - ysign = 1; - break; - case arrowTop: - xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - yPos = arrowRect.bottom - (arrowRect.Height() - (steps)) / 2; - xsign = 1; - ysign = -1; - break; - case arrowBottom: - default: - xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - yPos = arrowRect.top + (arrowRect.Height() - (steps + 1)) / 2; - xsign = 1; - ysign = 1; - break; - } - - Gdiplus::PointF vertices[3]; - - if (orientation == arrowLeft || orientation == arrowRight) { - vertices[0] = Gdiplus::PointF(xPos, yPos); - vertices[1] = Gdiplus::PointF(xPos + steps * xsign, yPos + steps * ysign); - vertices[2] = Gdiplus::PointF(xPos, yPos + steps * 2 * ysign); - } else { - vertices[0] = Gdiplus::PointF(xPos, yPos); - vertices[1] = Gdiplus::PointF(xPos + steps * xsign, yPos + steps * ysign); - vertices[2] = Gdiplus::PointF(xPos + steps * 2 * xsign, yPos); - } - - Gdiplus::Pen pen(clr, 1); - - if (floor(steps) != steps) { - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - } else { - gfx.SetSmoothingMode(Gdiplus::SmoothingModeNone); - } - - gfx.DrawPolygon(&pen, vertices, 3); - - Gdiplus::SolidBrush brush(clr); - gfx.FillPolygon(&brush, vertices, 3); -} - -void CMPCThemeSpinButtonCtrl::OnPaint() -{ - if (AppIsThemeLoaded()) { - CWnd* buddy = GetBuddy(); - bool hasBuddy = false; - CMPCThemeEdit* buddyEdit; - if (nullptr != buddy && nullptr != (buddyEdit = DYNAMIC_DOWNCAST(CMPCThemeEdit, buddy))) { - buddyEdit->setBuddy(this); //we need to know about the buddy spin ctrl to clip it in ncpaint :-/ - hasBuddy = true; - } - - CPaintDC dc(this); - CRect rectItem; - GetClientRect(rectItem); - - COLORREF bgClr = CMPCTheme::ContentBGColor; - - - CBrush borderBrush(CMPCTheme::EditBorderColor); - CBrush butBorderBrush(CMPCTheme::ButtonBorderInnerColor); - - dc.FillSolidRect(rectItem, bgClr); - - bool horz = 0 != (GetStyle() & UDS_HORZ); - if (horz) { - if (hasBuddy) { - dc.ExcludeClipRect(1, 0, rectItem.Width() - 1, 1); //don't get top edge of rect - dc.FrameRect(rectItem, &borderBrush); - } - } else { - if (hasBuddy) { - dc.ExcludeClipRect(0, 1, 1, rectItem.Height() - 1); //don't get left edge of rect - dc.FrameRect(rectItem, &borderBrush); - } - } - - int buddySpacing = hasBuddy ? 1 : 0; - for (int firstOrSecond = 0; firstOrSecond < 2; firstOrSecond++) { - CRect butRect = rectItem; - if (horz) { - butRect.DeflateRect(1, 1, 1, 1 + buddySpacing); - if (0 == firstOrSecond) {//left or top - butRect.right -= butRect.Width() / 2; - } else { - butRect.left += butRect.Width() / 2; - } - butRect.DeflateRect(1, 0); - } else { - butRect.DeflateRect(1, 1, 1 + buddySpacing, 1); - if (0 == firstOrSecond) {//left or top - butRect.bottom -= butRect.Height() / 2; - } else { - butRect.top += butRect.Height() / 2; - } - butRect.DeflateRect(0, 1); - } - - - if (butRect.PtInRect(downPos)) { - bgClr = CMPCTheme::ButtonFillSelectedColor; - } else { - bgClr = CMPCTheme::ButtonFillColor; - } - - dc.FillSolidRect(butRect, bgClr); - dc.FrameRect(butRect, &butBorderBrush); - - COLORREF arrowColor; - if (IsWindowEnabled()) { - arrowColor = CMPCTheme::TextFGColor; - } else { - arrowColor = CMPCTheme::ButtonDisabledFGColor; - } - - if (horz) { - if (0 == firstOrSecond) { //left - drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowLeft); - } else { - drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowRight); - } - } else { - if (0 == firstOrSecond) { //top - drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowTop); - } else { - drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowBottom); - } - } - } - - } else { - __super::OnPaint(); - } - -} - - -void CMPCThemeSpinButtonCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - CSpinButtonCtrl::OnMouseMove(nFlags, point); - if (MK_LBUTTON & nFlags) { - downPos = point; - } else { - downPos = CPoint(-1, -1); - } -} - - -void CMPCThemeSpinButtonCtrl::OnLButtonDown(UINT nFlags, CPoint point) -{ - CSpinButtonCtrl::OnLButtonDown(nFlags, point); - downPos = point; -} - - -void CMPCThemeSpinButtonCtrl::OnLButtonUp(UINT nFlags, CPoint point) -{ - CSpinButtonCtrl::OnLButtonUp(nFlags, point); - downPos = CPoint(-1, -1); -} - - -BOOL CMPCThemeSpinButtonCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} +#include "stdafx.h" +#include "DpiHelper.h" +#include "CMPCThemeSpinButtonCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeEdit.h" +#include "mplayerc.h" + +CMPCThemeSpinButtonCtrl::CMPCThemeSpinButtonCtrl() +{ +} + + +CMPCThemeSpinButtonCtrl::~CMPCThemeSpinButtonCtrl() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeSpinButtonCtrl, CSpinButtonCtrl) +BEGIN_MESSAGE_MAP(CMPCThemeSpinButtonCtrl, CSpinButtonCtrl) + ON_WM_PAINT() + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + +void CMPCThemeSpinButtonCtrl::drawSpinArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation) +{ + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + Gdiplus::Graphics gfx(dc.m_hDC); + Gdiplus::Color clr; + clr.SetFromCOLORREF(arrowClr); + + int dpi = dpiWindow.DPIX(); + float steps; + + if (dpi < 120) { + steps = 2; + } else if (dpi < 144) { + steps = 3; + } else if (dpi < 168) { + steps = 4; + } else if (dpi < 192) { + steps = 4; + } else { + steps = 4.5; + } + + int xPos; + int yPos; + int xsign, ysign; + switch (orientation) { + case arrowLeft: + xPos = arrowRect.right - (arrowRect.Width() - (steps)) / 2; + yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; + xsign = -1; + ysign = 1; + break; + case arrowRight: + xPos = arrowRect.left + (arrowRect.Width() - (steps + 1)) / 2; + yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; + xsign = 1; + ysign = 1; + break; + case arrowTop: + xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + yPos = arrowRect.bottom - (arrowRect.Height() - (steps)) / 2; + xsign = 1; + ysign = -1; + break; + case arrowBottom: + default: + xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + yPos = arrowRect.top + (arrowRect.Height() - (steps + 1)) / 2; + xsign = 1; + ysign = 1; + break; + } + + Gdiplus::PointF vertices[3]; + + if (orientation == arrowLeft || orientation == arrowRight) { + vertices[0] = Gdiplus::PointF(xPos, yPos); + vertices[1] = Gdiplus::PointF(xPos + steps * xsign, yPos + steps * ysign); + vertices[2] = Gdiplus::PointF(xPos, yPos + steps * 2 * ysign); + } else { + vertices[0] = Gdiplus::PointF(xPos, yPos); + vertices[1] = Gdiplus::PointF(xPos + steps * xsign, yPos + steps * ysign); + vertices[2] = Gdiplus::PointF(xPos + steps * 2 * xsign, yPos); + } + + Gdiplus::Pen pen(clr, 1); + + if (floor(steps) != steps) { + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); + } else { + gfx.SetSmoothingMode(Gdiplus::SmoothingModeNone); + } + + gfx.DrawPolygon(&pen, vertices, 3); + + Gdiplus::SolidBrush brush(clr); + gfx.FillPolygon(&brush, vertices, 3); +} + +void CMPCThemeSpinButtonCtrl::OnPaint() +{ + if (AppIsThemeLoaded()) { + CWnd* buddy = GetBuddy(); + bool hasBuddy = false; + CMPCThemeEdit* buddyEdit; + if (nullptr != buddy && nullptr != (buddyEdit = DYNAMIC_DOWNCAST(CMPCThemeEdit, buddy))) { + buddyEdit->setBuddy(this); //we need to know about the buddy spin ctrl to clip it in ncpaint :-/ + hasBuddy = true; + } + + CPaintDC dc(this); + CRect rectItem; + GetClientRect(rectItem); + + COLORREF bgClr = CMPCTheme::ContentBGColor; + + + CBrush borderBrush(CMPCTheme::EditBorderColor); + CBrush butBorderBrush(CMPCTheme::ButtonBorderInnerColor); + + dc.FillSolidRect(rectItem, bgClr); + + bool horz = 0 != (GetStyle() & UDS_HORZ); + if (horz) { + if (hasBuddy) { + dc.ExcludeClipRect(1, 0, rectItem.Width() - 1, 1); //don't get top edge of rect + dc.FrameRect(rectItem, &borderBrush); + } + } else { + if (hasBuddy) { + dc.ExcludeClipRect(0, 1, 1, rectItem.Height() - 1); //don't get left edge of rect + dc.FrameRect(rectItem, &borderBrush); + } + } + + int buddySpacing = hasBuddy ? 1 : 0; + for (int firstOrSecond = 0; firstOrSecond < 2; firstOrSecond++) { + CRect butRect = rectItem; + if (horz) { + butRect.DeflateRect(1, 1, 1, 1 + buddySpacing); + if (0 == firstOrSecond) {//left or top + butRect.right -= butRect.Width() / 2; + } else { + butRect.left += butRect.Width() / 2; + } + butRect.DeflateRect(1, 0); + } else { + butRect.DeflateRect(1, 1, 1 + buddySpacing, 1); + if (0 == firstOrSecond) {//left or top + butRect.bottom -= butRect.Height() / 2; + } else { + butRect.top += butRect.Height() / 2; + } + butRect.DeflateRect(0, 1); + } + + + if (butRect.PtInRect(downPos)) { + bgClr = CMPCTheme::ButtonFillSelectedColor; + } else { + bgClr = CMPCTheme::ButtonFillColor; + } + + dc.FillSolidRect(butRect, bgClr); + dc.FrameRect(butRect, &butBorderBrush); + + COLORREF arrowColor; + if (IsWindowEnabled()) { + arrowColor = CMPCTheme::TextFGColor; + } else { + arrowColor = CMPCTheme::ButtonDisabledFGColor; + } + + if (horz) { + if (0 == firstOrSecond) { //left + drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowLeft); + } else { + drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowRight); + } + } else { + if (0 == firstOrSecond) { //top + drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowTop); + } else { + drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowBottom); + } + } + } + + } else { + __super::OnPaint(); + } + +} + + +void CMPCThemeSpinButtonCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + CSpinButtonCtrl::OnMouseMove(nFlags, point); + if (MK_LBUTTON & nFlags) { + downPos = point; + } else { + downPos = CPoint(-1, -1); + } +} + + +void CMPCThemeSpinButtonCtrl::OnLButtonDown(UINT nFlags, CPoint point) +{ + CSpinButtonCtrl::OnLButtonDown(nFlags, point); + downPos = point; +} + + +void CMPCThemeSpinButtonCtrl::OnLButtonUp(UINT nFlags, CPoint point) +{ + CSpinButtonCtrl::OnLButtonUp(nFlags, point); + downPos = CPoint(-1, -1); +} + + +BOOL CMPCThemeSpinButtonCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} diff --git a/src/mpc-hc/CMPCThemeSpinButtonCtrl.h b/src/mpc-hc/CMPCThemeSpinButtonCtrl.h index 8abdfda0ed0..b1835d58b82 100755 --- a/src/mpc-hc/CMPCThemeSpinButtonCtrl.h +++ b/src/mpc-hc/CMPCThemeSpinButtonCtrl.h @@ -1,27 +1,27 @@ -#pragma once -#include -class CMPCThemeSpinButtonCtrl : public CSpinButtonCtrl -{ -public: - CMPCThemeSpinButtonCtrl(); - virtual ~CMPCThemeSpinButtonCtrl(); - DECLARE_DYNAMIC(CMPCThemeSpinButtonCtrl) - enum arrowOrientation { - arrowLeft, - arrowRight, - arrowTop, - arrowBottom - }; - - - DECLARE_MESSAGE_MAP() - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -protected: - CPoint downPos; - void drawSpinArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation); - void OnPaint(); -}; - +#pragma once +#include +class CMPCThemeSpinButtonCtrl : public CSpinButtonCtrl +{ +public: + CMPCThemeSpinButtonCtrl(); + virtual ~CMPCThemeSpinButtonCtrl(); + DECLARE_DYNAMIC(CMPCThemeSpinButtonCtrl) + enum arrowOrientation { + arrowLeft, + arrowRight, + arrowTop, + arrowBottom + }; + + + DECLARE_MESSAGE_MAP() + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +protected: + CPoint downPos; + void drawSpinArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation); + void OnPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeStatic.cpp b/src/mpc-hc/CMPCThemeStatic.cpp index cd81363d984..d332ded6bb5 100755 --- a/src/mpc-hc/CMPCThemeStatic.cpp +++ b/src/mpc-hc/CMPCThemeStatic.cpp @@ -1,179 +1,179 @@ -#include "stdafx.h" -#include "CMPCThemeStatic.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -CMPCThemeStatic::CMPCThemeStatic() -{ - isFileDialogChild = false; -} - - -CMPCThemeStatic::~CMPCThemeStatic() -{ -} -IMPLEMENT_DYNAMIC(CMPCThemeStatic, CStatic) -BEGIN_MESSAGE_MAP(CMPCThemeStatic, CStatic) - ON_WM_PAINT() - ON_WM_NCPAINT() - ON_WM_ENABLE() - ON_WM_ERASEBKGND() - ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, ResizeSupport) -END_MESSAGE_MAP() - -//this message is sent by resizablelib -//we prevent clipping for statics as they don't get redrawn correctly after erasing -LRESULT CMPCThemeStatic::ResizeSupport(WPARAM wParam, LPARAM lParam) { - if (AppNeedsThemedControls()) { - if (wParam == RSZSUP_QUERYPROPERTIES) { - LPRESIZEPROPERTIES props = (LPRESIZEPROPERTIES)lParam; - props->bAskClipping = false; - props->bCachedLikesClipping = false; - return TRUE; - } - } - return FALSE; -} - -void CMPCThemeStatic::OnPaint() -{ - if (AppNeedsThemedControls()) { - CPaintDC dc(this); - - CString sTitle; - GetWindowText(sTitle); - CRect rectItem; - GetClientRect(rectItem); - dc.SetBkMode(TRANSPARENT); - - COLORREF oldBkColor = dc.GetBkColor(); - COLORREF oldTextColor = dc.GetTextColor(); - - bool isDisabled = !IsWindowEnabled(); - UINT style = GetStyle(); - - if (!sTitle.IsEmpty()) { - bool canWrap = sTitle.Find(_T("\n")) != -1; - - CFont* font = GetFont(); - CFont* pOldFont = dc.SelectObject(font); - - UINT uFormat = 0; - if (style & SS_LEFTNOWORDWRAP) { - if (!canWrap) { - uFormat |= DT_SINGLELINE; - } - } else { - uFormat |= DT_WORDBREAK; - } - - if (0 != (style & SS_CENTERIMAGE) && !canWrap) { - //If the static control contains a single line of text, the text is centered vertically in the client area of the control. msdn - uFormat |= DT_SINGLELINE; - uFormat |= DT_VCENTER; - } else { - uFormat |= DT_TOP; - } - - if ((style & SS_CENTER) == SS_CENTER) { - uFormat |= DT_CENTER; - } else if ((style & SS_RIGHT) == SS_RIGHT) { - uFormat |= DT_RIGHT; - } else { // if ((style & SS_LEFT) == SS_LEFT || (style & SS_LEFTNOWORDWRAP) == SS_LEFTNOWORDWRAP) { - uFormat |= DT_LEFT; - } - - UINT ellipsisStyle = (style & SS_ELLIPSISMASK); - if (ellipsisStyle == SS_PATHELLIPSIS) { - uFormat |= DT_PATH_ELLIPSIS; - } else if (ellipsisStyle == SS_ENDELLIPSIS) { - uFormat |= DT_END_ELLIPSIS; - } else if (ellipsisStyle == SS_WORDELLIPSIS) { - uFormat |= DT_WORD_ELLIPSIS; - } - - if ((SendMessage(WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { - uFormat |= DT_HIDEPREFIX; - } - - dc.SetBkColor(CMPCTheme::WindowBGColor); - if (isDisabled) { - dc.SetTextColor(CMPCTheme::ButtonDisabledFGColor); - dc.DrawTextW(sTitle, -1, &rectItem, uFormat); - } else { - dc.SetTextColor(CMPCTheme::TextFGColor); - dc.DrawTextW(sTitle, -1, &rectItem, uFormat); - } - dc.SelectObject(pOldFont); - dc.SetBkColor(oldBkColor); - dc.SetTextColor(oldTextColor); - } - } else { - __super::OnPaint(); - } -} - - -void CMPCThemeStatic::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - CDC* pDC = GetWindowDC(); - - CRect rect; - GetWindowRect(&rect); - rect.OffsetRect(-rect.left, -rect.top); - DWORD type = GetStyle() & SS_TYPEMASK; - - if (SS_ETCHEDHORZ == type || SS_ETCHEDVERT == type) { //etched lines assumed - rect.DeflateRect(0, 0, 1, 1); //make it thinner - CBrush brush(CMPCTheme::StaticEtchedColor); - pDC->FillSolidRect(rect, CMPCTheme::StaticEtchedColor); - } else if (SS_ETCHEDFRAME == type) { //etched border - CBrush brush(CMPCTheme::StaticEtchedColor); - pDC->FrameRect(rect, &brush); - } else { //not supported yet - } - - ReleaseDC(pDC); - } else { - CStatic::OnNcPaint(); - } -} - -void CMPCThemeStatic::OnEnable(BOOL bEnable) -{ - if (AppNeedsThemedControls()) { - SetRedraw(FALSE); - __super::OnEnable(bEnable); - SetRedraw(TRUE); - CWnd* parent = GetParent(); - if (nullptr != parent) { - CRect wr; - GetWindowRect(wr); - parent->ScreenToClient(wr); - parent->InvalidateRect(wr, TRUE); - } else { - Invalidate(); - } - } else { - __super::OnEnable(bEnable); - } -} - -BOOL CMPCThemeStatic::OnEraseBkgnd(CDC* pDC) -{ - if (AppNeedsThemedControls()) { - CRect r; - GetClientRect(r); - if (isFileDialogChild) { - HBRUSH hBrush = CMPCThemeUtil::getCtlColorFileDialog(pDC->GetSafeHdc(), CTLCOLOR_STATIC); - ::FillRect(pDC->GetSafeHdc(), r, hBrush); - } else { - CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); - } - return TRUE; - } else { - return CStatic::OnEraseBkgnd(pDC); - } -} +#include "stdafx.h" +#include "CMPCThemeStatic.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +CMPCThemeStatic::CMPCThemeStatic() +{ + isFileDialogChild = false; +} + + +CMPCThemeStatic::~CMPCThemeStatic() +{ +} +IMPLEMENT_DYNAMIC(CMPCThemeStatic, CStatic) +BEGIN_MESSAGE_MAP(CMPCThemeStatic, CStatic) + ON_WM_PAINT() + ON_WM_NCPAINT() + ON_WM_ENABLE() + ON_WM_ERASEBKGND() + ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, ResizeSupport) +END_MESSAGE_MAP() + +//this message is sent by resizablelib +//we prevent clipping for statics as they don't get redrawn correctly after erasing +LRESULT CMPCThemeStatic::ResizeSupport(WPARAM wParam, LPARAM lParam) { + if (AppNeedsThemedControls()) { + if (wParam == RSZSUP_QUERYPROPERTIES) { + LPRESIZEPROPERTIES props = (LPRESIZEPROPERTIES)lParam; + props->bAskClipping = false; + props->bCachedLikesClipping = false; + return TRUE; + } + } + return FALSE; +} + +void CMPCThemeStatic::OnPaint() +{ + if (AppNeedsThemedControls()) { + CPaintDC dc(this); + + CString sTitle; + GetWindowText(sTitle); + CRect rectItem; + GetClientRect(rectItem); + dc.SetBkMode(TRANSPARENT); + + COLORREF oldBkColor = dc.GetBkColor(); + COLORREF oldTextColor = dc.GetTextColor(); + + bool isDisabled = !IsWindowEnabled(); + UINT style = GetStyle(); + + if (!sTitle.IsEmpty()) { + bool canWrap = sTitle.Find(_T("\n")) != -1; + + CFont* font = GetFont(); + CFont* pOldFont = dc.SelectObject(font); + + UINT uFormat = 0; + if (style & SS_LEFTNOWORDWRAP) { + if (!canWrap) { + uFormat |= DT_SINGLELINE; + } + } else { + uFormat |= DT_WORDBREAK; + } + + if (0 != (style & SS_CENTERIMAGE) && !canWrap) { + //If the static control contains a single line of text, the text is centered vertically in the client area of the control. msdn + uFormat |= DT_SINGLELINE; + uFormat |= DT_VCENTER; + } else { + uFormat |= DT_TOP; + } + + if ((style & SS_CENTER) == SS_CENTER) { + uFormat |= DT_CENTER; + } else if ((style & SS_RIGHT) == SS_RIGHT) { + uFormat |= DT_RIGHT; + } else { // if ((style & SS_LEFT) == SS_LEFT || (style & SS_LEFTNOWORDWRAP) == SS_LEFTNOWORDWRAP) { + uFormat |= DT_LEFT; + } + + UINT ellipsisStyle = (style & SS_ELLIPSISMASK); + if (ellipsisStyle == SS_PATHELLIPSIS) { + uFormat |= DT_PATH_ELLIPSIS; + } else if (ellipsisStyle == SS_ENDELLIPSIS) { + uFormat |= DT_END_ELLIPSIS; + } else if (ellipsisStyle == SS_WORDELLIPSIS) { + uFormat |= DT_WORD_ELLIPSIS; + } + + if ((SendMessage(WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { + uFormat |= DT_HIDEPREFIX; + } + + dc.SetBkColor(CMPCTheme::WindowBGColor); + if (isDisabled) { + dc.SetTextColor(CMPCTheme::ButtonDisabledFGColor); + dc.DrawTextW(sTitle, -1, &rectItem, uFormat); + } else { + dc.SetTextColor(CMPCTheme::TextFGColor); + dc.DrawTextW(sTitle, -1, &rectItem, uFormat); + } + dc.SelectObject(pOldFont); + dc.SetBkColor(oldBkColor); + dc.SetTextColor(oldTextColor); + } + } else { + __super::OnPaint(); + } +} + + +void CMPCThemeStatic::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + CDC* pDC = GetWindowDC(); + + CRect rect; + GetWindowRect(&rect); + rect.OffsetRect(-rect.left, -rect.top); + DWORD type = GetStyle() & SS_TYPEMASK; + + if (SS_ETCHEDHORZ == type || SS_ETCHEDVERT == type) { //etched lines assumed + rect.DeflateRect(0, 0, 1, 1); //make it thinner + CBrush brush(CMPCTheme::StaticEtchedColor); + pDC->FillSolidRect(rect, CMPCTheme::StaticEtchedColor); + } else if (SS_ETCHEDFRAME == type) { //etched border + CBrush brush(CMPCTheme::StaticEtchedColor); + pDC->FrameRect(rect, &brush); + } else { //not supported yet + } + + ReleaseDC(pDC); + } else { + CStatic::OnNcPaint(); + } +} + +void CMPCThemeStatic::OnEnable(BOOL bEnable) +{ + if (AppNeedsThemedControls()) { + SetRedraw(FALSE); + __super::OnEnable(bEnable); + SetRedraw(TRUE); + CWnd* parent = GetParent(); + if (nullptr != parent) { + CRect wr; + GetWindowRect(wr); + parent->ScreenToClient(wr); + parent->InvalidateRect(wr, TRUE); + } else { + Invalidate(); + } + } else { + __super::OnEnable(bEnable); + } +} + +BOOL CMPCThemeStatic::OnEraseBkgnd(CDC* pDC) +{ + if (AppNeedsThemedControls()) { + CRect r; + GetClientRect(r); + if (isFileDialogChild) { + HBRUSH hBrush = CMPCThemeUtil::getCtlColorFileDialog(pDC->GetSafeHdc(), CTLCOLOR_STATIC); + ::FillRect(pDC->GetSafeHdc(), r, hBrush); + } else { + CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); + } + return TRUE; + } else { + return CStatic::OnEraseBkgnd(pDC); + } +} diff --git a/src/mpc-hc/CMPCThemeStatic.h b/src/mpc-hc/CMPCThemeStatic.h index 0a01379d536..1f9ff71a127 100755 --- a/src/mpc-hc/CMPCThemeStatic.h +++ b/src/mpc-hc/CMPCThemeStatic.h @@ -1,21 +1,21 @@ -#pragma once -#include -class CMPCThemeStatic : - public CStatic -{ - DECLARE_DYNAMIC(CMPCThemeStatic) -public: - - CMPCThemeStatic(); - virtual ~CMPCThemeStatic(); - void setFileDialogChild(bool set) { isFileDialogChild = set; }; - DECLARE_MESSAGE_MAP() - afx_msg LRESULT ResizeSupport(WPARAM wParam, LPARAM lParam); - afx_msg void OnPaint(); - afx_msg void OnNcPaint(); - afx_msg void OnEnable(BOOL bEnable); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -protected: - bool isFileDialogChild; -}; - +#pragma once +#include +class CMPCThemeStatic : + public CStatic +{ + DECLARE_DYNAMIC(CMPCThemeStatic) +public: + + CMPCThemeStatic(); + virtual ~CMPCThemeStatic(); + void setFileDialogChild(bool set) { isFileDialogChild = set; }; + DECLARE_MESSAGE_MAP() + afx_msg LRESULT ResizeSupport(WPARAM wParam, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg void OnNcPaint(); + afx_msg void OnEnable(BOOL bEnable); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +protected: + bool isFileDialogChild; +}; + diff --git a/src/mpc-hc/CMPCThemeStaticLink.cpp b/src/mpc-hc/CMPCThemeStaticLink.cpp index 6106a5306da..1ed69ca9c4f 100755 --- a/src/mpc-hc/CMPCThemeStaticLink.cpp +++ b/src/mpc-hc/CMPCThemeStaticLink.cpp @@ -1,99 +1,99 @@ -#include "stdafx.h" -#include "CMPCThemeStaticLink.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -CMPCThemeStaticLink::CMPCThemeStaticLink(LPCTSTR lpText, bool bDeleteOnDestroy) : CStaticLink(lpText, bDeleteOnDestroy) -{ -} - -CMPCThemeStaticLink::~CMPCThemeStaticLink() -{ -} - - -IMPLEMENT_DYNAMIC(CMPCThemeStaticLink, CStaticLink) - -BEGIN_MESSAGE_MAP(CMPCThemeStaticLink, CStaticLink) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_WM_CTLCOLOR_REFLECT() - ON_WM_ENABLE() -END_MESSAGE_MAP() - - - -void CMPCThemeStaticLink::OnPaint() -{ - if (AppIsThemeLoaded()) { //only reason for custom paint is disabled statics do not honor ctlcolor and draw greyed text which looks terrible on other bgs - CPaintDC dc(this); // device context for painting - COLORREF oldBkClr = dc.GetBkColor(); - COLORREF oldTextClr = dc.GetTextColor(); - int oldBkMode = dc.GetBkMode(); - - dc.SetBkMode(TRANSPARENT); - - CRect r; - - CString text; - GetWindowText(text); - DWORD format = 0; - DWORD style = GetStyle(); - if (style & SS_RIGHT) { - format |= DT_RIGHT; - } else if (style & SS_CENTER) { - format |= DT_CENTER; - } //else DT_LEFT is default - - if (style & SS_CENTERIMAGE) { //applies to text, too - format |= DT_VCENTER; - } - - if ((SendMessage(WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { - format |= DT_HIDEPREFIX; - } - - if (!IsWindowEnabled()) { - dc.SetTextColor(CMPCTheme::ContentTextDisabledFGColorFade); - } else { - dc.SetTextColor(CMPCTheme::StaticLinkColor); - } - CFont* font = GetFont(); - CFont* oldFont = dc.SelectObject(font); - dc.DrawTextW(text, r, format | DT_CALCRECT); - CMPCThemeUtil::drawParentDialogBGClr(this, &dc, r); - dc.DrawTextW(text, r, format); - - dc.SelectObject(oldFont); - dc.SetBkColor(oldBkClr); - dc.SetTextColor(oldTextClr); - dc.SetBkMode(oldBkMode); - } else { - __super::OnPaint(); - } -} - - -HBRUSH CMPCThemeStaticLink::CtlColor(CDC* pDC, UINT nCtlColor) //avoid overridden cstaticlink ctlcolor -{ - if (AppIsThemeLoaded()) { - return NULL; - } else { - return __super::CtlColor(pDC, nCtlColor); - } -} - - -void CMPCThemeStaticLink::OnEnable(BOOL bEnable) -{ - if (AppIsThemeLoaded()) { - SetRedraw(FALSE); - __super::OnEnable(bEnable); - SetRedraw(TRUE); - Invalidate(); //WM_PAINT not handled when enabling/disabling - RedrawWindow(); - } else { - __super::OnEnable(bEnable); - } -} +#include "stdafx.h" +#include "CMPCThemeStaticLink.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +CMPCThemeStaticLink::CMPCThemeStaticLink(LPCTSTR lpText, bool bDeleteOnDestroy) : CStaticLink(lpText, bDeleteOnDestroy) +{ +} + +CMPCThemeStaticLink::~CMPCThemeStaticLink() +{ +} + + +IMPLEMENT_DYNAMIC(CMPCThemeStaticLink, CStaticLink) + +BEGIN_MESSAGE_MAP(CMPCThemeStaticLink, CStaticLink) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_CTLCOLOR_REFLECT() + ON_WM_ENABLE() +END_MESSAGE_MAP() + + + +void CMPCThemeStaticLink::OnPaint() +{ + if (AppIsThemeLoaded()) { //only reason for custom paint is disabled statics do not honor ctlcolor and draw greyed text which looks terrible on other bgs + CPaintDC dc(this); // device context for painting + COLORREF oldBkClr = dc.GetBkColor(); + COLORREF oldTextClr = dc.GetTextColor(); + int oldBkMode = dc.GetBkMode(); + + dc.SetBkMode(TRANSPARENT); + + CRect r; + + CString text; + GetWindowText(text); + DWORD format = 0; + DWORD style = GetStyle(); + if (style & SS_RIGHT) { + format |= DT_RIGHT; + } else if (style & SS_CENTER) { + format |= DT_CENTER; + } //else DT_LEFT is default + + if (style & SS_CENTERIMAGE) { //applies to text, too + format |= DT_VCENTER; + } + + if ((SendMessage(WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { + format |= DT_HIDEPREFIX; + } + + if (!IsWindowEnabled()) { + dc.SetTextColor(CMPCTheme::ContentTextDisabledFGColorFade); + } else { + dc.SetTextColor(CMPCTheme::StaticLinkColor); + } + CFont* font = GetFont(); + CFont* oldFont = dc.SelectObject(font); + dc.DrawTextW(text, r, format | DT_CALCRECT); + CMPCThemeUtil::drawParentDialogBGClr(this, &dc, r); + dc.DrawTextW(text, r, format); + + dc.SelectObject(oldFont); + dc.SetBkColor(oldBkClr); + dc.SetTextColor(oldTextClr); + dc.SetBkMode(oldBkMode); + } else { + __super::OnPaint(); + } +} + + +HBRUSH CMPCThemeStaticLink::CtlColor(CDC* pDC, UINT nCtlColor) //avoid overridden cstaticlink ctlcolor +{ + if (AppIsThemeLoaded()) { + return NULL; + } else { + return __super::CtlColor(pDC, nCtlColor); + } +} + + +void CMPCThemeStaticLink::OnEnable(BOOL bEnable) +{ + if (AppIsThemeLoaded()) { + SetRedraw(FALSE); + __super::OnEnable(bEnable); + SetRedraw(TRUE); + Invalidate(); //WM_PAINT not handled when enabling/disabling + RedrawWindow(); + } else { + __super::OnEnable(bEnable); + } +} diff --git a/src/mpc-hc/CMPCThemeStaticLink.h b/src/mpc-hc/CMPCThemeStaticLink.h index 5d5bbe6cea5..fd8f6a2fcee 100755 --- a/src/mpc-hc/CMPCThemeStaticLink.h +++ b/src/mpc-hc/CMPCThemeStaticLink.h @@ -1,18 +1,18 @@ -#pragma once -#include "StaticLink.h" -#include "CMPCThemeUtil.h" -class CMPCThemeStaticLink : - public CStaticLink, public CMPCThemeUtil -{ -protected: - CBrush bgBrush; -public: - DECLARE_DYNAMIC(CMPCThemeStaticLink) - CMPCThemeStaticLink(LPCTSTR lpText = nullptr, bool bDeleteOnDestroy = false); - virtual ~CMPCThemeStaticLink(); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor); - afx_msg void OnEnable(BOOL bEnable); -}; - +#pragma once +#include "StaticLink.h" +#include "CMPCThemeUtil.h" +class CMPCThemeStaticLink : + public CStaticLink, public CMPCThemeUtil +{ +protected: + CBrush bgBrush; +public: + DECLARE_DYNAMIC(CMPCThemeStaticLink) + CMPCThemeStaticLink(LPCTSTR lpText = nullptr, bool bDeleteOnDestroy = false); + virtual ~CMPCThemeStaticLink(); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor); + afx_msg void OnEnable(BOOL bEnable); +}; + diff --git a/src/mpc-hc/CMPCThemeStatusBar.cpp b/src/mpc-hc/CMPCThemeStatusBar.cpp index 6b6412bcb69..63a2bdba787 100755 --- a/src/mpc-hc/CMPCThemeStatusBar.cpp +++ b/src/mpc-hc/CMPCThemeStatusBar.cpp @@ -1,123 +1,123 @@ -#include "stdafx.h" -#include "CMPCThemeStatusBar.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -CMPCThemeStatusBar::CMPCThemeStatusBar() -{ -} - - -CMPCThemeStatusBar::~CMPCThemeStatusBar() -{ -} - -void CMPCThemeStatusBar::PreSubclassWindow() -{ - if (AppIsThemeLoaded()) { - ModifyStyleEx(WS_BORDER, WS_EX_STATICEDGE, 0); - } else { - __super::PreSubclassWindow(); - } -} - - -BEGIN_MESSAGE_MAP(CMPCThemeStatusBar, CStatusBar) - ON_WM_NCPAINT() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -void CMPCThemeStatusBar::SetText(LPCTSTR lpszText, int nPane, int nType) -{ - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - - if (AppIsThemeLoaded()) { - ctrl.SetText(_T(""), nPane, SBT_OWNERDRAW); - texts[nPane] = lpszText; - Invalidate(); - } else { - ctrl.SetText(lpszText, nPane, nType); - } -} - -BOOL CMPCThemeStatusBar::SetParts(int nParts, int* pWidths) -{ - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - numParts = nParts; - return ctrl.SetParts(nParts, pWidths); -} - -int CMPCThemeStatusBar::GetParts(int nParts, int* pParts) -{ - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - return ctrl.GetParts(nParts, pParts); -} - -BOOL CMPCThemeStatusBar::GetRect(int nPane, LPRECT lpRect) -{ - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - return ctrl.GetRect(nPane, lpRect); -} - - -void CMPCThemeStatusBar::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CDC dc; - dc.Attach(lpDrawItemStruct->hDC); - CRect rect(&lpDrawItemStruct->rcItem); - int item = lpDrawItemStruct->itemID; - dc.SetBkColor(CMPCTheme::StatusBarBGColor); - dc.SetTextColor(CMPCTheme::TextFGColor); - CFont font; - if (CMPCThemeUtil::getFontByType(font, this, CMPCThemeUtil::MessageFont)) { - dc.SelectObject(&font); - } - dc.FillSolidRect(rect, CMPCTheme::StatusBarBGColor); - rect.left += 4; - dc.DrawTextW(texts[item], rect, DT_NOPREFIX); - if (item < numParts - 1) { //draw a separator - CRect separator(rect.right, rect.top, rect.right + 1, rect.bottom); - dc.OffsetClipRgn(1, 0); //separator is 1 pixel beyond our rect - dc.FillSolidRect(separator, CMPCTheme::StatusBarSeparatorColor); - } - dc.Detach(); -} - - -void CMPCThemeStatusBar::OnNcPaint() -{ - if (!AppIsThemeLoaded()) { - return __super::OnNcPaint(); - } else { - CWindowDC dc(this); - - CRect rcWindow; - GetWindowRect(rcWindow); - ScreenToClient(rcWindow); - rcWindow.OffsetRect(-rcWindow.TopLeft()); - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - - int nHorz, nVert, nSpacing; - GetStatusBarCtrl().GetBorders(nHorz, nVert, nSpacing); - for (int item = 0; item < numParts; item++) { //don't touch the status bar elements; they are painted in DrawItem - CRect rc; - if (GetRect(item, rc)) { - rc.DeflateRect(1, 1, item < numParts - 1 ? 0 : 1, 1); //the rects provided to DrawItem exclude the border - dc.ExcludeClipRect(rc); - } - } - dc.FillSolidRect(rcWindow, CMPCTheme::StatusBarBGColor); - dc.SelectClipRgn(nullptr); - } -} - - -BOOL CMPCThemeStatusBar::OnEraseBkgnd(CDC* pDC) -{ - if (!AppIsThemeLoaded()) { - return __super::OnEraseBkgnd(pDC); - } else { - return TRUE; - } -} +#include "stdafx.h" +#include "CMPCThemeStatusBar.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +CMPCThemeStatusBar::CMPCThemeStatusBar() +{ +} + + +CMPCThemeStatusBar::~CMPCThemeStatusBar() +{ +} + +void CMPCThemeStatusBar::PreSubclassWindow() +{ + if (AppIsThemeLoaded()) { + ModifyStyleEx(WS_BORDER, WS_EX_STATICEDGE, 0); + } else { + __super::PreSubclassWindow(); + } +} + + +BEGIN_MESSAGE_MAP(CMPCThemeStatusBar, CStatusBar) + ON_WM_NCPAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +void CMPCThemeStatusBar::SetText(LPCTSTR lpszText, int nPane, int nType) +{ + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + + if (AppIsThemeLoaded()) { + ctrl.SetText(_T(""), nPane, SBT_OWNERDRAW); + texts[nPane] = lpszText; + Invalidate(); + } else { + ctrl.SetText(lpszText, nPane, nType); + } +} + +BOOL CMPCThemeStatusBar::SetParts(int nParts, int* pWidths) +{ + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + numParts = nParts; + return ctrl.SetParts(nParts, pWidths); +} + +int CMPCThemeStatusBar::GetParts(int nParts, int* pParts) +{ + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + return ctrl.GetParts(nParts, pParts); +} + +BOOL CMPCThemeStatusBar::GetRect(int nPane, LPRECT lpRect) +{ + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + return ctrl.GetRect(nPane, lpRect); +} + + +void CMPCThemeStatusBar::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC dc; + dc.Attach(lpDrawItemStruct->hDC); + CRect rect(&lpDrawItemStruct->rcItem); + int item = lpDrawItemStruct->itemID; + dc.SetBkColor(CMPCTheme::StatusBarBGColor); + dc.SetTextColor(CMPCTheme::TextFGColor); + CFont font; + if (CMPCThemeUtil::getFontByType(font, this, CMPCThemeUtil::MessageFont)) { + dc.SelectObject(&font); + } + dc.FillSolidRect(rect, CMPCTheme::StatusBarBGColor); + rect.left += 4; + dc.DrawTextW(texts[item], rect, DT_NOPREFIX); + if (item < numParts - 1) { //draw a separator + CRect separator(rect.right, rect.top, rect.right + 1, rect.bottom); + dc.OffsetClipRgn(1, 0); //separator is 1 pixel beyond our rect + dc.FillSolidRect(separator, CMPCTheme::StatusBarSeparatorColor); + } + dc.Detach(); +} + + +void CMPCThemeStatusBar::OnNcPaint() +{ + if (!AppIsThemeLoaded()) { + return __super::OnNcPaint(); + } else { + CWindowDC dc(this); + + CRect rcWindow; + GetWindowRect(rcWindow); + ScreenToClient(rcWindow); + rcWindow.OffsetRect(-rcWindow.TopLeft()); + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + + int nHorz, nVert, nSpacing; + GetStatusBarCtrl().GetBorders(nHorz, nVert, nSpacing); + for (int item = 0; item < numParts; item++) { //don't touch the status bar elements; they are painted in DrawItem + CRect rc; + if (GetRect(item, rc)) { + rc.DeflateRect(1, 1, item < numParts - 1 ? 0 : 1, 1); //the rects provided to DrawItem exclude the border + dc.ExcludeClipRect(rc); + } + } + dc.FillSolidRect(rcWindow, CMPCTheme::StatusBarBGColor); + dc.SelectClipRgn(nullptr); + } +} + + +BOOL CMPCThemeStatusBar::OnEraseBkgnd(CDC* pDC) +{ + if (!AppIsThemeLoaded()) { + return __super::OnEraseBkgnd(pDC); + } else { + return TRUE; + } +} diff --git a/src/mpc-hc/CMPCThemeStatusBar.h b/src/mpc-hc/CMPCThemeStatusBar.h index 1a5fa1d1a8c..7a2806fae53 100755 --- a/src/mpc-hc/CMPCThemeStatusBar.h +++ b/src/mpc-hc/CMPCThemeStatusBar.h @@ -1,23 +1,23 @@ -#pragma once -#include -class CMPCThemeStatusBar : - public CStatusBar -{ -public: - CMPCThemeStatusBar(); - virtual ~CMPCThemeStatusBar(); - void PreSubclassWindow(); - void SetText(LPCTSTR lpszText, int nPane, int nType); - BOOL SetParts(int nParts, int* pWidths); - int GetParts(int nParts, int* pParts); - BOOL GetRect(int nPane, LPRECT lpRect); - void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); - DECLARE_MESSAGE_MAP() -protected: - std::map texts; - int numParts; -public: - afx_msg void OnNcPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; - +#pragma once +#include +class CMPCThemeStatusBar : + public CStatusBar +{ +public: + CMPCThemeStatusBar(); + virtual ~CMPCThemeStatusBar(); + void PreSubclassWindow(); + void SetText(LPCTSTR lpszText, int nPane, int nType); + BOOL SetParts(int nParts, int* pWidths); + int GetParts(int nParts, int* pParts); + BOOL GetRect(int nPane, LPRECT lpRect); + void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + DECLARE_MESSAGE_MAP() +protected: + std::map texts; + int numParts; +public: + afx_msg void OnNcPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; + diff --git a/src/mpc-hc/CMPCThemeTabCtrl.cpp b/src/mpc-hc/CMPCThemeTabCtrl.cpp index b82a32654a3..f8f7f3fe4c0 100755 --- a/src/mpc-hc/CMPCThemeTabCtrl.cpp +++ b/src/mpc-hc/CMPCThemeTabCtrl.cpp @@ -1,200 +1,200 @@ -#include "stdafx.h" -#include "CMPCThemeTabCtrl.h" -#include "mplayerc.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" - - -CMPCThemeTabCtrl::CMPCThemeTabCtrl(): CTabCtrl() -{ -} - -CMPCThemeTabCtrl::~CMPCThemeTabCtrl() -{ -} - -void CMPCThemeTabCtrl::PreSubclassWindow() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeTabCtrl, CTabCtrl) -BEGIN_MESSAGE_MAP(CMPCThemeTabCtrl, CTabCtrl) - ON_WM_CTLCOLOR() - ON_WM_ERASEBKGND() - ON_WM_PAINT() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeTabCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} - -void CMPCThemeTabCtrl::doDrawItem(int nItem, CRect rText, bool isSelected, CDC* pDC) -{ - if (nItem != -1) { - TCITEM tcitem = { 0 }; - tcitem.mask = TCIF_TEXT | TCIF_STATE; - const int c_cchBuffer = 1024; - TCHAR lpBuffer[c_cchBuffer]; - tcitem.pszText = lpBuffer; - tcitem.cchTextMax = c_cchBuffer; - - GetItem(nItem, &tcitem); - - COLORREF oldTextColor = pDC->GetTextColor(); - COLORREF oldBkColor = pDC->GetBkColor(); - - COLORREF textColor = CMPCTheme::TextFGColor; - COLORREF bgColor; - - CRect rBorder; - rBorder = rText; - - int leftY, rightY; - if (!isSelected) { - bgColor = CMPCTheme::TabCtrlInactiveColor; - rightY = rBorder.bottom; - } else { - bgColor = CMPCTheme::WindowBGColor; - rightY = rBorder.bottom - 1; - } - - if (nItem != 0) { - leftY = rBorder.bottom - 2; //starts above the horizontal border - } else { - leftY = rBorder.bottom - 1; //starts on the border to connect with the main border - } - - pDC->FillSolidRect(rBorder, bgColor); - - CPen borderPen, *oldPen; - borderPen.CreatePen(PS_SOLID, 1, CMPCTheme::TabCtrlBorderColor); - oldPen = pDC->SelectObject(&borderPen); - pDC->MoveTo(rBorder.left, leftY); - pDC->LineTo(rBorder.left, rBorder.top); - pDC->LineTo(rBorder.right, rBorder.top); - pDC->LineTo(rBorder.right, rightY); //non-inclusive - - pDC->SelectObject(oldPen); - borderPen.DeleteObject(); - - CPoint ptCursor; - ::GetCursorPos(&ptCursor); - ScreenToClient(&ptCursor); - - UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS; - textFormat |= DT_LEFT; - rText.left += 6; - - CString text = tcitem.pszText; - pDC->SetTextColor(textColor); - pDC->SetBkColor(bgColor); - - CMPCThemeUtil::DrawBufferedText(pDC, text, rText, textFormat); - - pDC->SetTextColor(oldTextColor); - pDC->SetBkColor(oldBkColor); - } - -} - -void CMPCThemeTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CDC dc; - dc.Attach(lpDrawItemStruct->hDC); - doDrawItem(lpDrawItemStruct->itemID, lpDrawItemStruct->rcItem, 0 != (lpDrawItemStruct->itemState & ODS_SELECTED), &dc); - dc.Detach(); -} - -BOOL CMPCThemeTabCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - CRect r; - GetClientRect(r); - CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); - } - return TRUE; -} - -void CMPCThemeTabCtrl::OnPaint() -{ - if (AppIsThemeLoaded()) { - CPaintDC dc(this); // device context for painting - int oldDC = dc.SaveDC(); - CRect rClient, rContent, rectDC; - GetClientRect(rClient); - rectDC = rClient; - - CDC dcMem; - CBitmap bmMem; - CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, rectDC); - rClient.OffsetRect(-rectDC.TopLeft()); - - dcMem.SelectObject(GetFont()); - - DRAWITEMSTRUCT dItemStruct; - dItemStruct.CtlType = ODT_TAB; - dItemStruct.CtlID = GetDlgCtrlID(); - dItemStruct.hwndItem = GetSafeHwnd(); - dItemStruct.hDC = dcMem.GetSafeHdc(); - dItemStruct.itemAction = ODA_DRAWENTIRE; - dItemStruct.rcItem = rClient; - - rContent = dItemStruct.rcItem; - AdjustRect(FALSE, rContent); - dItemStruct.rcItem.top = rContent.top - 2; - - COLORREF oldTextColor = dcMem.GetTextColor(); - COLORREF oldBkColor = dcMem.GetBkColor(); - - CBrush contentFrameBrush; - contentFrameBrush.CreateSolidBrush(CMPCTheme::TabCtrlBorderColor); - rContent.InflateRect(1, 1); - dcMem.FrameRect(rContent, &CMPCThemeUtil::windowBrush); - rContent.InflateRect(1, 1); - dcMem.FrameRect(rContent, &contentFrameBrush); - contentBrush.DeleteObject(); - - dcMem.SetTextColor(oldTextColor); - dcMem.SetBkColor(oldBkColor); - - - int nTab = GetItemCount(); - int nSel = GetCurSel(); - - if (!nTab) { - return; - } - - while (nTab--) { - if (nTab != nSel) { - dItemStruct.itemID = nTab; - dItemStruct.itemState = 0; - - VERIFY(GetItemRect(nTab, &dItemStruct.rcItem)); - DrawItem(&dItemStruct); - } - } - - dItemStruct.itemID = nSel; - dItemStruct.itemState = ODS_SELECTED; - - VERIFY(GetItemRect(nSel, &dItemStruct.rcItem)); - - dItemStruct.rcItem.bottom += 2; - dItemStruct.rcItem.top -= 2; - DrawItem(&dItemStruct); - - CMPCThemeUtil::flushMemDC(&dc, dcMem, rectDC); - dc.RestoreDC(oldDC); - } else { - __super::OnPaint(); - } -} - +#include "stdafx.h" +#include "CMPCThemeTabCtrl.h" +#include "mplayerc.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" + + +CMPCThemeTabCtrl::CMPCThemeTabCtrl(): CTabCtrl() +{ +} + +CMPCThemeTabCtrl::~CMPCThemeTabCtrl() +{ +} + +void CMPCThemeTabCtrl::PreSubclassWindow() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeTabCtrl, CTabCtrl) +BEGIN_MESSAGE_MAP(CMPCThemeTabCtrl, CTabCtrl) + ON_WM_CTLCOLOR() + ON_WM_ERASEBKGND() + ON_WM_PAINT() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeTabCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} + +void CMPCThemeTabCtrl::doDrawItem(int nItem, CRect rText, bool isSelected, CDC* pDC) +{ + if (nItem != -1) { + TCITEM tcitem = { 0 }; + tcitem.mask = TCIF_TEXT | TCIF_STATE; + const int c_cchBuffer = 1024; + TCHAR lpBuffer[c_cchBuffer]; + tcitem.pszText = lpBuffer; + tcitem.cchTextMax = c_cchBuffer; + + GetItem(nItem, &tcitem); + + COLORREF oldTextColor = pDC->GetTextColor(); + COLORREF oldBkColor = pDC->GetBkColor(); + + COLORREF textColor = CMPCTheme::TextFGColor; + COLORREF bgColor; + + CRect rBorder; + rBorder = rText; + + int leftY, rightY; + if (!isSelected) { + bgColor = CMPCTheme::TabCtrlInactiveColor; + rightY = rBorder.bottom; + } else { + bgColor = CMPCTheme::WindowBGColor; + rightY = rBorder.bottom - 1; + } + + if (nItem != 0) { + leftY = rBorder.bottom - 2; //starts above the horizontal border + } else { + leftY = rBorder.bottom - 1; //starts on the border to connect with the main border + } + + pDC->FillSolidRect(rBorder, bgColor); + + CPen borderPen, *oldPen; + borderPen.CreatePen(PS_SOLID, 1, CMPCTheme::TabCtrlBorderColor); + oldPen = pDC->SelectObject(&borderPen); + pDC->MoveTo(rBorder.left, leftY); + pDC->LineTo(rBorder.left, rBorder.top); + pDC->LineTo(rBorder.right, rBorder.top); + pDC->LineTo(rBorder.right, rightY); //non-inclusive + + pDC->SelectObject(oldPen); + borderPen.DeleteObject(); + + CPoint ptCursor; + ::GetCursorPos(&ptCursor); + ScreenToClient(&ptCursor); + + UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS; + textFormat |= DT_LEFT; + rText.left += 6; + + CString text = tcitem.pszText; + pDC->SetTextColor(textColor); + pDC->SetBkColor(bgColor); + + CMPCThemeUtil::DrawBufferedText(pDC, text, rText, textFormat); + + pDC->SetTextColor(oldTextColor); + pDC->SetBkColor(oldBkColor); + } + +} + +void CMPCThemeTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC dc; + dc.Attach(lpDrawItemStruct->hDC); + doDrawItem(lpDrawItemStruct->itemID, lpDrawItemStruct->rcItem, 0 != (lpDrawItemStruct->itemState & ODS_SELECTED), &dc); + dc.Detach(); +} + +BOOL CMPCThemeTabCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + CRect r; + GetClientRect(r); + CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); + } + return TRUE; +} + +void CMPCThemeTabCtrl::OnPaint() +{ + if (AppIsThemeLoaded()) { + CPaintDC dc(this); // device context for painting + int oldDC = dc.SaveDC(); + CRect rClient, rContent, rectDC; + GetClientRect(rClient); + rectDC = rClient; + + CDC dcMem; + CBitmap bmMem; + CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, rectDC); + rClient.OffsetRect(-rectDC.TopLeft()); + + dcMem.SelectObject(GetFont()); + + DRAWITEMSTRUCT dItemStruct; + dItemStruct.CtlType = ODT_TAB; + dItemStruct.CtlID = GetDlgCtrlID(); + dItemStruct.hwndItem = GetSafeHwnd(); + dItemStruct.hDC = dcMem.GetSafeHdc(); + dItemStruct.itemAction = ODA_DRAWENTIRE; + dItemStruct.rcItem = rClient; + + rContent = dItemStruct.rcItem; + AdjustRect(FALSE, rContent); + dItemStruct.rcItem.top = rContent.top - 2; + + COLORREF oldTextColor = dcMem.GetTextColor(); + COLORREF oldBkColor = dcMem.GetBkColor(); + + CBrush contentFrameBrush; + contentFrameBrush.CreateSolidBrush(CMPCTheme::TabCtrlBorderColor); + rContent.InflateRect(1, 1); + dcMem.FrameRect(rContent, &CMPCThemeUtil::windowBrush); + rContent.InflateRect(1, 1); + dcMem.FrameRect(rContent, &contentFrameBrush); + contentBrush.DeleteObject(); + + dcMem.SetTextColor(oldTextColor); + dcMem.SetBkColor(oldBkColor); + + + int nTab = GetItemCount(); + int nSel = GetCurSel(); + + if (!nTab) { + return; + } + + while (nTab--) { + if (nTab != nSel) { + dItemStruct.itemID = nTab; + dItemStruct.itemState = 0; + + VERIFY(GetItemRect(nTab, &dItemStruct.rcItem)); + DrawItem(&dItemStruct); + } + } + + dItemStruct.itemID = nSel; + dItemStruct.itemState = ODS_SELECTED; + + VERIFY(GetItemRect(nSel, &dItemStruct.rcItem)); + + dItemStruct.rcItem.bottom += 2; + dItemStruct.rcItem.top -= 2; + DrawItem(&dItemStruct); + + CMPCThemeUtil::flushMemDC(&dc, dcMem, rectDC); + dc.RestoreDC(oldDC); + } else { + __super::OnPaint(); + } +} + diff --git a/src/mpc-hc/CMPCThemeTabCtrl.h b/src/mpc-hc/CMPCThemeTabCtrl.h index 771c9482a62..a3b3f64f5df 100755 --- a/src/mpc-hc/CMPCThemeTabCtrl.h +++ b/src/mpc-hc/CMPCThemeTabCtrl.h @@ -1,21 +1,21 @@ -#pragma once -#include "stdafx.h" -#include "CMPCThemeUtil.h" - -class CMPCThemeTabCtrl : public CTabCtrl, public CMPCThemeUtil -{ -public: - CMPCThemeTabCtrl(); - virtual ~CMPCThemeTabCtrl(); - void PreSubclassWindow(); - DECLARE_DYNAMIC(CMPCThemeTabCtrl) - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - void doDrawItem(int nItem, CRect rText, bool isSelected, CDC* pDC); - void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); -public: - BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnPaint(); -}; - +#pragma once +#include "stdafx.h" +#include "CMPCThemeUtil.h" + +class CMPCThemeTabCtrl : public CTabCtrl, public CMPCThemeUtil +{ +public: + CMPCThemeTabCtrl(); + virtual ~CMPCThemeTabCtrl(); + void PreSubclassWindow(); + DECLARE_DYNAMIC(CMPCThemeTabCtrl) + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + void doDrawItem(int nItem, CRect rText, bool isSelected, CDC* pDC); + void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); +public: + BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeTitleBarControlButton.cpp b/src/mpc-hc/CMPCThemeTitleBarControlButton.cpp index 938f4b05100..d467305514f 100644 --- a/src/mpc-hc/CMPCThemeTitleBarControlButton.cpp +++ b/src/mpc-hc/CMPCThemeTitleBarControlButton.cpp @@ -1,133 +1,133 @@ -#include "stdafx.h" -#include "mplayerc.h" -#include "CMPCThemeTitleBarControlButton.h" -#include "CMPCThemeUtil.h" - -BEGIN_MESSAGE_MAP(CMPCThemeTitleBarControlButton, CMFCButton) - ON_WM_PAINT() - ON_CONTROL_REFLECT(BN_CLICKED, &CMPCThemeTitleBarControlButton::OnBnClicked) -END_MESSAGE_MAP() - -CMPCThemeTitleBarControlButton::CMPCThemeTitleBarControlButton(WPARAM _buttonType) : CMFCButton() - , parent(nullptr) -{ - this->buttonType = _buttonType; - switch (buttonType) { - case SC_CLOSE: - hoverColor = CMPCTheme::CloseHoverColor; - pushedColor = CMPCTheme::ClosePushColor; - hoverInactiveColor = CMPCTheme::CloseHoverColor; - break; - case SC_MINIMIZE: - case SC_MAXIMIZE: - default: - hoverColor = CMPCTheme::W10DarkThemeTitlebarControlHoverBGColor; - pushedColor = CMPCTheme::W10DarkThemeTitlebarControlPushedBGColor; - hoverInactiveColor = CMPCTheme::W10DarkThemeTitlebarInactiveControlHoverBGColor; - break; - } -} - - -void CMPCThemeTitleBarControlButton::setParentFrame(CMPCThemeFrameUtil* _parent) -{ - this->parent = _parent; -} - -WPARAM CMPCThemeTitleBarControlButton::getButtonType() -{ - if (buttonType == SC_MAXIMIZE && parent->IsWindowZoomed()) { - return SC_RESTORE; - } - return buttonType; -} - -void CMPCThemeTitleBarControlButton::drawTitleBarButton(CDC* pDC, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias) -{ - int iconWidth = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarIconPathWidth); - int iconHeight = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarIconPathHeight); - float penThickness = CMPCThemeUtil::getConstantFByDPI(this, CMPCTheme::W10TitlebarIconPathThickness); - CRect pathRect = { - iconRect.left + (iconRect.Width() - iconWidth) / 2, - iconRect.top + (iconRect.Height() - iconHeight) / 2, - iconWidth, - iconHeight - }; - - Gdiplus::Graphics gfx(pDC->m_hDC); - if (antiAlias) { - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x8); - } - Gdiplus::Color lineClr; - lineClr.SetFromCOLORREF(CMPCTheme::W10DarkThemeTitlebarIconPenColor); - Gdiplus::Pen iPen(lineClr, penThickness); - if (penThickness >= 2) { - iPen.SetLineCap(Gdiplus::LineCapSquare, Gdiplus::LineCapSquare, Gdiplus::DashCapFlat); - } - Gdiplus::REAL lastX = 0, lastY = 0; - for (u_int i = 0; i < icon.size(); i++) { - CMPCTheme::pathPoint p = icon[i]; - Gdiplus::REAL x = (Gdiplus::REAL)(pathRect.left + p.x); - Gdiplus::REAL y = (Gdiplus::REAL)(pathRect.top + p.y); - if (p.state == CMPCTheme::newPath) { - lastX = x; - lastY = y; - } else if ((p.state == CMPCTheme::linePath || p.state == CMPCTheme::closePath) && i > 0) { - gfx.DrawLine(&iPen, lastX, lastY, x, y); - if (antiAlias && penThickness < 2) { - gfx.DrawLine(&iPen, lastX, lastY, x, y); //draw again to brighten the AA diagonals - } - lastX = x; - lastY = y; - } - } -} - - -void CMPCThemeTitleBarControlButton::OnPaint() -{ - CPaintDC dc(this); // device context for painting - CRect cr; - GetClientRect(cr); - if (IsPushed()) { - dc.FillSolidRect(cr, pushedColor); - } else if (IsHighlighted()) { - if (parent->IsWindowForeground()) { - dc.FillSolidRect(cr, hoverColor); - } else { - dc.FillSolidRect(cr, hoverInactiveColor); - } - } else { - if (nullptr != parent) { - COLORREF tbColor; - if (parent->IsWindowForeground()) { - tbColor = CMPCTheme::W10DarkThemeTitlebarBGColor; - } else { - tbColor = CMPCTheme::W10DarkThemeTitlebarInactiveBGColor; - } - dc.FillSolidRect(cr, tbColor); - } - } - DpiHelper dpiWindow; - dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); - drawTitleBarButton(&dc, cr, CMPCThemeUtil::getIconPathByDPI(this), dpiWindow.ScaleFactorX(), true); -} - -void CMPCThemeTitleBarControlButton::OnBnClicked() -{ - switch (buttonType) { - case SC_CLOSE: - parent->PostWindowMessage(WM_CLOSE, 0, 0); - break; - case SC_MINIMIZE: - parent->PostWindowMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); - break; - case SC_MAXIMIZE: - if (parent->IsWindowZoomed()) { - parent->PostWindowMessage(WM_SYSCOMMAND, SC_RESTORE, 0); - } else { - parent->PostWindowMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); - } - break; - } -} +#include "stdafx.h" +#include "mplayerc.h" +#include "CMPCThemeTitleBarControlButton.h" +#include "CMPCThemeUtil.h" + +BEGIN_MESSAGE_MAP(CMPCThemeTitleBarControlButton, CMFCButton) + ON_WM_PAINT() + ON_CONTROL_REFLECT(BN_CLICKED, &CMPCThemeTitleBarControlButton::OnBnClicked) +END_MESSAGE_MAP() + +CMPCThemeTitleBarControlButton::CMPCThemeTitleBarControlButton(WPARAM _buttonType) : CMFCButton() + , parent(nullptr) +{ + this->buttonType = _buttonType; + switch (buttonType) { + case SC_CLOSE: + hoverColor = CMPCTheme::CloseHoverColor; + pushedColor = CMPCTheme::ClosePushColor; + hoverInactiveColor = CMPCTheme::CloseHoverColor; + break; + case SC_MINIMIZE: + case SC_MAXIMIZE: + default: + hoverColor = CMPCTheme::W10DarkThemeTitlebarControlHoverBGColor; + pushedColor = CMPCTheme::W10DarkThemeTitlebarControlPushedBGColor; + hoverInactiveColor = CMPCTheme::W10DarkThemeTitlebarInactiveControlHoverBGColor; + break; + } +} + + +void CMPCThemeTitleBarControlButton::setParentFrame(CMPCThemeFrameUtil* _parent) +{ + this->parent = _parent; +} + +WPARAM CMPCThemeTitleBarControlButton::getButtonType() +{ + if (buttonType == SC_MAXIMIZE && parent->IsWindowZoomed()) { + return SC_RESTORE; + } + return buttonType; +} + +void CMPCThemeTitleBarControlButton::drawTitleBarButton(CDC* pDC, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias) +{ + int iconWidth = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarIconPathWidth); + int iconHeight = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarIconPathHeight); + float penThickness = CMPCThemeUtil::getConstantFByDPI(this, CMPCTheme::W10TitlebarIconPathThickness); + CRect pathRect = { + iconRect.left + (iconRect.Width() - iconWidth) / 2, + iconRect.top + (iconRect.Height() - iconHeight) / 2, + iconWidth, + iconHeight + }; + + Gdiplus::Graphics gfx(pDC->m_hDC); + if (antiAlias) { + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x8); + } + Gdiplus::Color lineClr; + lineClr.SetFromCOLORREF(CMPCTheme::W10DarkThemeTitlebarIconPenColor); + Gdiplus::Pen iPen(lineClr, penThickness); + if (penThickness >= 2) { + iPen.SetLineCap(Gdiplus::LineCapSquare, Gdiplus::LineCapSquare, Gdiplus::DashCapFlat); + } + Gdiplus::REAL lastX = 0, lastY = 0; + for (u_int i = 0; i < icon.size(); i++) { + CMPCTheme::pathPoint p = icon[i]; + Gdiplus::REAL x = (Gdiplus::REAL)(pathRect.left + p.x); + Gdiplus::REAL y = (Gdiplus::REAL)(pathRect.top + p.y); + if (p.state == CMPCTheme::newPath) { + lastX = x; + lastY = y; + } else if ((p.state == CMPCTheme::linePath || p.state == CMPCTheme::closePath) && i > 0) { + gfx.DrawLine(&iPen, lastX, lastY, x, y); + if (antiAlias && penThickness < 2) { + gfx.DrawLine(&iPen, lastX, lastY, x, y); //draw again to brighten the AA diagonals + } + lastX = x; + lastY = y; + } + } +} + + +void CMPCThemeTitleBarControlButton::OnPaint() +{ + CPaintDC dc(this); // device context for painting + CRect cr; + GetClientRect(cr); + if (IsPushed()) { + dc.FillSolidRect(cr, pushedColor); + } else if (IsHighlighted()) { + if (parent->IsWindowForeground()) { + dc.FillSolidRect(cr, hoverColor); + } else { + dc.FillSolidRect(cr, hoverInactiveColor); + } + } else { + if (nullptr != parent) { + COLORREF tbColor; + if (parent->IsWindowForeground()) { + tbColor = CMPCTheme::W10DarkThemeTitlebarBGColor; + } else { + tbColor = CMPCTheme::W10DarkThemeTitlebarInactiveBGColor; + } + dc.FillSolidRect(cr, tbColor); + } + } + DpiHelper dpiWindow; + dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); + drawTitleBarButton(&dc, cr, CMPCThemeUtil::getIconPathByDPI(this), dpiWindow.ScaleFactorX(), true); +} + +void CMPCThemeTitleBarControlButton::OnBnClicked() +{ + switch (buttonType) { + case SC_CLOSE: + parent->PostWindowMessage(WM_CLOSE, 0, 0); + break; + case SC_MINIMIZE: + parent->PostWindowMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); + break; + case SC_MAXIMIZE: + if (parent->IsWindowZoomed()) { + parent->PostWindowMessage(WM_SYSCOMMAND, SC_RESTORE, 0); + } else { + parent->PostWindowMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); + } + break; + } +} diff --git a/src/mpc-hc/CMPCThemeTitleBarControlButton.h b/src/mpc-hc/CMPCThemeTitleBarControlButton.h index 1ab7b472b55..39fcaaf39c6 100644 --- a/src/mpc-hc/CMPCThemeTitleBarControlButton.h +++ b/src/mpc-hc/CMPCThemeTitleBarControlButton.h @@ -1,21 +1,21 @@ -#pragma once -#include "CMPCThemeFrameUtil.h" - -class CMPCThemeTitleBarControlButton : - public CMFCButton -{ -public: - CMPCThemeTitleBarControlButton(WPARAM _buttonType); - void setParentFrame(CMPCThemeFrameUtil* parent); - WPARAM getButtonType(); -protected: - void drawTitleBarButton(CDC* pDC, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias = false); - WPARAM buttonType; - COLORREF hoverColor, pushedColor, hoverInactiveColor; - CMPCThemeFrameUtil* parent; -public: - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg void OnBnClicked(); -}; - +#pragma once +#include "CMPCThemeFrameUtil.h" + +class CMPCThemeTitleBarControlButton : + public CMFCButton +{ +public: + CMPCThemeTitleBarControlButton(WPARAM _buttonType); + void setParentFrame(CMPCThemeFrameUtil* parent); + WPARAM getButtonType(); +protected: + void drawTitleBarButton(CDC* pDC, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias = false); + WPARAM buttonType; + COLORREF hoverColor, pushedColor, hoverInactiveColor; + CMPCThemeFrameUtil* parent; +public: + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg void OnBnClicked(); +}; + diff --git a/src/mpc-hc/CMPCThemeToolTipCtrl.cpp b/src/mpc-hc/CMPCThemeToolTipCtrl.cpp index 1ff7bf3eddc..22cf808b07b 100644 --- a/src/mpc-hc/CMPCThemeToolTipCtrl.cpp +++ b/src/mpc-hc/CMPCThemeToolTipCtrl.cpp @@ -1,263 +1,263 @@ -#include "stdafx.h" -#include "CMPCThemeToolTipCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include -#include "mplayerc.h" - - -CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrl() -{ - this->useFlickerHelper = false; - this->helper = nullptr; - BOOL notBasicMode; - DwmIsCompositionEnabled(¬BasicMode); - basicMode = !notBasicMode; -} - - -CMPCThemeToolTipCtrl::~CMPCThemeToolTipCtrl() -{ - if (nullptr != helper) { - helper->DestroyWindow(); - delete helper; - } -} - -void CMPCThemeToolTipCtrl::enableFlickerHelper() -{ - if (IsAppThemed() && IsThemeActive() && !basicMode) { //in classic/basic mode, the helper gets wiped out by the fade, so we disable it - this->useFlickerHelper = true; - } -} - -IMPLEMENT_DYNAMIC(CMPCThemeToolTipCtrl, CToolTipCtrl) -BEGIN_MESSAGE_MAP(CMPCThemeToolTipCtrl, CToolTipCtrl) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_WM_CREATE() - ON_WM_MOVE() - ON_WM_SHOWWINDOW() - ON_WM_SIZE() - ON_WM_WINDOWPOSCHANGING() -END_MESSAGE_MAP() - -void CMPCThemeToolTipCtrl::drawText(CDC& dc, CMPCThemeToolTipCtrl* tt, CRect& rect, bool calcRect) -{ - CFont* font = tt->GetFont(); - CFont* pOldFont = dc.SelectObject(font); - - CString text; - tt->GetWindowText(text); - int maxWidth = tt->GetMaxTipWidth(); - int calcStyle = 0; - if (calcRect) { - calcStyle = DT_CALCRECT; - } - rect.DeflateRect(6, 2); - if (maxWidth == -1) { - if (calcRect) { - dc.DrawTextW(text, rect, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | calcStyle); - } else { - dc.DrawTextW(text, rect, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_NOPREFIX); - } - } else { - dc.DrawTextW(text, rect, DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | calcStyle); - } - rect.InflateRect(6, 2); //when calculating, put it back - if (!calcStyle) { - tt->lastDrawRect = rect; - } - - dc.SelectObject(pOldFont); -} - -void CMPCThemeToolTipCtrl::paintTT(CDC& dc, CMPCThemeToolTipCtrl* tt) -{ - CRect r; - tt->GetClientRect(r); - - dc.FillSolidRect(r, CMPCTheme::MenuBGColor); - - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::TooltipBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - COLORREF oldClr = dc.SetTextColor(CMPCTheme::TextFGColor); - drawText(dc, tt, r, false); - dc.SetTextColor(oldClr); -} - -void CMPCThemeToolTipCtrl::OnPaint() -{ - if (AppIsThemeLoaded()) { - CPaintDC dc(this); - if (useFlickerHelper) { //helper will paint - return; - } - paintTT(dc, this); - } else { - __super::OnPaint(); - } -} - - -BOOL CMPCThemeToolTipCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} - - -int CMPCThemeToolTipCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (CToolTipCtrl::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - if (AppIsThemeLoaded()) { - makeHelper(); - } - return 0; -} - -void CMPCThemeToolTipCtrl::makeHelper() -{ - if (!useFlickerHelper) { - return; - } - - if (nullptr != helper) { - delete helper; - helper = nullptr; - } - CRect r; - GetClientRect(r); - if (r.Size() == CSize(0, 0)) { - return; - } - ClientToScreen(r); - - helper = DEBUG_NEW CMPCThemeToolTipCtrlHelper(this); - //do it the long way since no menu for parent - helper->CreateEx(NULL, AfxRegisterWndClass(0), NULL, WS_POPUP | WS_DISABLED, - r.left, r.top, r.right - r.left, r.bottom - r.top, - GetParent()->GetSafeHwnd(), NULL, NULL); - helper->Invalidate(); - helper->ShowWindow(SW_SHOWNOACTIVATE); -} - -void CMPCThemeToolTipCtrl::RedrawIfVisible() { - if (::IsWindow(m_hWnd) && IsWindowVisible()) { - CWindowDC dc(this); - CRect wr; - drawText(dc, this, wr, true); - if (wr != lastDrawRect) { - Update(); - } else { - RedrawWindow(); - } - } -} - -BEGIN_MESSAGE_MAP(CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper, CWnd) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_WM_NCCALCSIZE() -END_MESSAGE_MAP() - - -CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::CMPCThemeToolTipCtrlHelper(CMPCThemeToolTipCtrl* tt) -{ - this->tt = tt; -} - -CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::~CMPCThemeToolTipCtrlHelper() -{ - DestroyWindow(); -} - -void CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::OnPaint() -{ - CPaintDC dc(this); - CMPCThemeToolTipCtrl::paintTT(dc, tt); -} - - -BOOL CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::OnEraseBkgnd(CDC* pDC) -{ - return TRUE; -} - -void CMPCThemeToolTipCtrl::OnMove(int x, int y) -{ - CToolTipCtrl::OnMove(x, y); - if (AppIsThemeLoaded()) { - makeHelper(); - } -} - - -void CMPCThemeToolTipCtrl::OnShowWindow(BOOL bShow, UINT nStatus) -{ - - CToolTipCtrl::OnShowWindow(bShow, nStatus); - if (AppIsThemeLoaded()) { - if (!bShow) { - if (helper != nullptr) { - delete helper; - helper = nullptr; - } - } - } -} - -void CMPCThemeToolTipCtrl::OnSize(UINT nType, int cx, int cy) -{ - CToolTipCtrl::OnSize(nType, cx, cy); - if (AppIsThemeLoaded()) { - makeHelper(); - } -} - - -void CMPCThemeToolTipCtrl::OnWindowPosChanging(WINDOWPOS* lpwndpos) -{ - CToolTipCtrl::OnWindowPosChanging(lpwndpos); - if (AppIsThemeLoaded()) { - //hack to make it fit if fonts differ from parent. can be manually avoided - //if the parent widget is set to same font (see CMPCThemePlayerListCtrl using MessageFont now) - CString text; - GetWindowText(text); - if (text.GetLength() > 0 && GetMaxTipWidth() == -1) { - CWindowDC dc(this); - - CRect cr; - drawText(dc, this, cr, true);//calculate crect required to fit the text - - lpwndpos->cx = cr.Width(); - lpwndpos->cy = cr.Height(); - } - } -} - -//tooltip rules for how to hover on parent window -//by default tooltipctrl will simply hover at the mouse position, -//unlike the tooltips created with EnableTooltips which center below the window -//(in all cases tested-slider, combobox, edit) -void CMPCThemeToolTipCtrl::SetHoverPosition(CWnd* parent) { - if (IsWindow(parent->GetSafeHwnd())) { - CRect parentRect, ttRect; - parent->GetWindowRect(parentRect); - GetWindowRect(ttRect); - int centerOffset = (parentRect.left + parentRect.right - ttRect.left - ttRect.right) / 2; - ttRect.right += centerOffset; - ttRect.left += centerOffset; - ttRect.bottom += (parentRect.bottom - ttRect.top); - ttRect.top = parentRect.bottom; - MoveWindow(ttRect); - } -} +#include "stdafx.h" +#include "CMPCThemeToolTipCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include +#include "mplayerc.h" + + +CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrl() +{ + this->useFlickerHelper = false; + this->helper = nullptr; + BOOL notBasicMode; + DwmIsCompositionEnabled(¬BasicMode); + basicMode = !notBasicMode; +} + + +CMPCThemeToolTipCtrl::~CMPCThemeToolTipCtrl() +{ + if (nullptr != helper) { + helper->DestroyWindow(); + delete helper; + } +} + +void CMPCThemeToolTipCtrl::enableFlickerHelper() +{ + if (IsAppThemed() && IsThemeActive() && !basicMode) { //in classic/basic mode, the helper gets wiped out by the fade, so we disable it + this->useFlickerHelper = true; + } +} + +IMPLEMENT_DYNAMIC(CMPCThemeToolTipCtrl, CToolTipCtrl) +BEGIN_MESSAGE_MAP(CMPCThemeToolTipCtrl, CToolTipCtrl) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_CREATE() + ON_WM_MOVE() + ON_WM_SHOWWINDOW() + ON_WM_SIZE() + ON_WM_WINDOWPOSCHANGING() +END_MESSAGE_MAP() + +void CMPCThemeToolTipCtrl::drawText(CDC& dc, CMPCThemeToolTipCtrl* tt, CRect& rect, bool calcRect) +{ + CFont* font = tt->GetFont(); + CFont* pOldFont = dc.SelectObject(font); + + CString text; + tt->GetWindowText(text); + int maxWidth = tt->GetMaxTipWidth(); + int calcStyle = 0; + if (calcRect) { + calcStyle = DT_CALCRECT; + } + rect.DeflateRect(6, 2); + if (maxWidth == -1) { + if (calcRect) { + dc.DrawTextW(text, rect, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | calcStyle); + } else { + dc.DrawTextW(text, rect, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_NOPREFIX); + } + } else { + dc.DrawTextW(text, rect, DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | calcStyle); + } + rect.InflateRect(6, 2); //when calculating, put it back + if (!calcStyle) { + tt->lastDrawRect = rect; + } + + dc.SelectObject(pOldFont); +} + +void CMPCThemeToolTipCtrl::paintTT(CDC& dc, CMPCThemeToolTipCtrl* tt) +{ + CRect r; + tt->GetClientRect(r); + + dc.FillSolidRect(r, CMPCTheme::MenuBGColor); + + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::TooltipBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + COLORREF oldClr = dc.SetTextColor(CMPCTheme::TextFGColor); + drawText(dc, tt, r, false); + dc.SetTextColor(oldClr); +} + +void CMPCThemeToolTipCtrl::OnPaint() +{ + if (AppIsThemeLoaded()) { + CPaintDC dc(this); + if (useFlickerHelper) { //helper will paint + return; + } + paintTT(dc, this); + } else { + __super::OnPaint(); + } +} + + +BOOL CMPCThemeToolTipCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} + + +int CMPCThemeToolTipCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CToolTipCtrl::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + if (AppIsThemeLoaded()) { + makeHelper(); + } + return 0; +} + +void CMPCThemeToolTipCtrl::makeHelper() +{ + if (!useFlickerHelper) { + return; + } + + if (nullptr != helper) { + delete helper; + helper = nullptr; + } + CRect r; + GetClientRect(r); + if (r.Size() == CSize(0, 0)) { + return; + } + ClientToScreen(r); + + helper = DEBUG_NEW CMPCThemeToolTipCtrlHelper(this); + //do it the long way since no menu for parent + helper->CreateEx(NULL, AfxRegisterWndClass(0), NULL, WS_POPUP | WS_DISABLED, + r.left, r.top, r.right - r.left, r.bottom - r.top, + GetParent()->GetSafeHwnd(), NULL, NULL); + helper->Invalidate(); + helper->ShowWindow(SW_SHOWNOACTIVATE); +} + +void CMPCThemeToolTipCtrl::RedrawIfVisible() { + if (::IsWindow(m_hWnd) && IsWindowVisible()) { + CWindowDC dc(this); + CRect wr; + drawText(dc, this, wr, true); + if (wr != lastDrawRect) { + Update(); + } else { + RedrawWindow(); + } + } +} + +BEGIN_MESSAGE_MAP(CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper, CWnd) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_NCCALCSIZE() +END_MESSAGE_MAP() + + +CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::CMPCThemeToolTipCtrlHelper(CMPCThemeToolTipCtrl* tt) +{ + this->tt = tt; +} + +CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::~CMPCThemeToolTipCtrlHelper() +{ + DestroyWindow(); +} + +void CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::OnPaint() +{ + CPaintDC dc(this); + CMPCThemeToolTipCtrl::paintTT(dc, tt); +} + + +BOOL CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::OnEraseBkgnd(CDC* pDC) +{ + return TRUE; +} + +void CMPCThemeToolTipCtrl::OnMove(int x, int y) +{ + CToolTipCtrl::OnMove(x, y); + if (AppIsThemeLoaded()) { + makeHelper(); + } +} + + +void CMPCThemeToolTipCtrl::OnShowWindow(BOOL bShow, UINT nStatus) +{ + + CToolTipCtrl::OnShowWindow(bShow, nStatus); + if (AppIsThemeLoaded()) { + if (!bShow) { + if (helper != nullptr) { + delete helper; + helper = nullptr; + } + } + } +} + +void CMPCThemeToolTipCtrl::OnSize(UINT nType, int cx, int cy) +{ + CToolTipCtrl::OnSize(nType, cx, cy); + if (AppIsThemeLoaded()) { + makeHelper(); + } +} + + +void CMPCThemeToolTipCtrl::OnWindowPosChanging(WINDOWPOS* lpwndpos) +{ + CToolTipCtrl::OnWindowPosChanging(lpwndpos); + if (AppIsThemeLoaded()) { + //hack to make it fit if fonts differ from parent. can be manually avoided + //if the parent widget is set to same font (see CMPCThemePlayerListCtrl using MessageFont now) + CString text; + GetWindowText(text); + if (text.GetLength() > 0 && GetMaxTipWidth() == -1) { + CWindowDC dc(this); + + CRect cr; + drawText(dc, this, cr, true);//calculate crect required to fit the text + + lpwndpos->cx = cr.Width(); + lpwndpos->cy = cr.Height(); + } + } +} + +//tooltip rules for how to hover on parent window +//by default tooltipctrl will simply hover at the mouse position, +//unlike the tooltips created with EnableTooltips which center below the window +//(in all cases tested-slider, combobox, edit) +void CMPCThemeToolTipCtrl::SetHoverPosition(CWnd* parent) { + if (IsWindow(parent->GetSafeHwnd())) { + CRect parentRect, ttRect; + parent->GetWindowRect(parentRect); + GetWindowRect(ttRect); + int centerOffset = (parentRect.left + parentRect.right - ttRect.left - ttRect.right) / 2; + ttRect.right += centerOffset; + ttRect.left += centerOffset; + ttRect.bottom += (parentRect.bottom - ttRect.top); + ttRect.top = parentRect.bottom; + MoveWindow(ttRect); + } +} diff --git a/src/mpc-hc/CMPCThemeToolTipCtrl.h b/src/mpc-hc/CMPCThemeToolTipCtrl.h index 4280e3e479b..0df2cd05b43 100755 --- a/src/mpc-hc/CMPCThemeToolTipCtrl.h +++ b/src/mpc-hc/CMPCThemeToolTipCtrl.h @@ -1,45 +1,45 @@ -#pragma once -#include - -class CMPCThemeToolTipCtrl; - - -class CMPCThemeToolTipCtrl : public CToolTipCtrl -{ - class CMPCThemeToolTipCtrlHelper : public CWnd - { - private: - CMPCThemeToolTipCtrl* tt; - public: - CMPCThemeToolTipCtrlHelper(CMPCThemeToolTipCtrl* tt); - virtual ~CMPCThemeToolTipCtrlHelper(); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - }; - - - DECLARE_DYNAMIC(CMPCThemeToolTipCtrl) -private: - bool useFlickerHelper, basicMode; - CMPCThemeToolTipCtrlHelper* helper; - void makeHelper(); - CRect lastDrawRect; -public: - CMPCThemeToolTipCtrl(); - virtual ~CMPCThemeToolTipCtrl(); - void enableFlickerHelper(); - static void drawText(CDC& dc, CMPCThemeToolTipCtrl* tt, CRect& rect, bool calcRect = false); - static void paintTT(CDC& dc, CMPCThemeToolTipCtrl* tt); - void SetHoverPosition(CWnd* parent); - void RedrawIfVisible(); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnMove(int x, int y); - afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); -}; - +#pragma once +#include + +class CMPCThemeToolTipCtrl; + + +class CMPCThemeToolTipCtrl : public CToolTipCtrl +{ + class CMPCThemeToolTipCtrlHelper : public CWnd + { + private: + CMPCThemeToolTipCtrl* tt; + public: + CMPCThemeToolTipCtrlHelper(CMPCThemeToolTipCtrl* tt); + virtual ~CMPCThemeToolTipCtrlHelper(); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + }; + + + DECLARE_DYNAMIC(CMPCThemeToolTipCtrl) +private: + bool useFlickerHelper, basicMode; + CMPCThemeToolTipCtrlHelper* helper; + void makeHelper(); + CRect lastDrawRect; +public: + CMPCThemeToolTipCtrl(); + virtual ~CMPCThemeToolTipCtrl(); + void enableFlickerHelper(); + static void drawText(CDC& dc, CMPCThemeToolTipCtrl* tt, CRect& rect, bool calcRect = false); + static void paintTT(CDC& dc, CMPCThemeToolTipCtrl* tt); + void SetHoverPosition(CWnd* parent); + void RedrawIfVisible(); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnMove(int x, int y); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); +}; + diff --git a/src/mpc-hc/CMPCThemeTreeCtrl.cpp b/src/mpc-hc/CMPCThemeTreeCtrl.cpp index 7b297093007..21fcebf5c8e 100755 --- a/src/mpc-hc/CMPCThemeTreeCtrl.cpp +++ b/src/mpc-hc/CMPCThemeTreeCtrl.cpp @@ -1,244 +1,244 @@ -#include "stdafx.h" -#include "CMPCThemeTreeCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#undef SubclassWindow - - -CMPCThemeTreeCtrl::CMPCThemeTreeCtrl(): - themedSBHelper(nullptr), - themedToolTipCid((UINT_PTR) - 1) -{ - if (AppNeedsThemedControls()) { - m_brBkgnd.CreateSolidBrush(CMPCTheme::InlineEditBorderColor); - if (!CMPCThemeUtil::canUseWin10DarkTheme()) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - } - } - -} - -CMPCThemeTreeCtrl::~CMPCThemeTreeCtrl() -{ - if (nullptr != themedSBHelper) { - delete themedSBHelper; - } - m_brBkgnd.DeleteObject(); -} - -BOOL CMPCThemeTreeCtrl::PreCreateWindow(CREATESTRUCT& cs) -{ - if (AppNeedsThemedControls()) { - cs.dwExStyle |= WS_EX_CLIENTEDGE; - } - return __super::PreCreateWindow(cs); -} - -void CMPCThemeTreeCtrl::fulfillThemeReqs() -{ - if (AppNeedsThemedControls()) { - if (CMPCThemeUtil::canUseWin10DarkTheme()) { - SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); - } else { - SetWindowTheme(GetSafeHwnd(), L"", NULL); - } - SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); //necessary to prevent significant flicker - - SetLineColor(CMPCTheme::TreeCtrlLineColor); - if (nullptr == tvsTooltip.m_hWnd) { - CToolTipCtrl* t = GetToolTips(); - if (nullptr != t) { - tvsTooltip.SubclassWindow(t->m_hWnd); - } - } - } else { - //adipose--enabling this cuts down on a very minor flicker in classic mode; - //the duplicate line above is necessary due to a non-default bg. - //treat as a separate line of code to be clear that this one is "optional" while the other is not - SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); //optional - } -} - -BEGIN_MESSAGE_MAP(CMPCThemeTreeCtrl, CTreeCtrl) - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeTreeCtrl::OnNMCustomdraw) - ON_WM_ERASEBKGND() - ON_WM_DRAWITEM() - ON_WM_NCPAINT() - ON_WM_MOUSEMOVE() - ON_WM_MOUSEWHEEL() - ON_WM_VSCROLL() - ON_WM_HSCROLL() -END_MESSAGE_MAP() -IMPLEMENT_DYNAMIC(CMPCThemeTreeCtrl, CTreeCtrl) - -BOOL CMPCThemeTreeCtrl::PreTranslateMessage(MSG* pMsg) -{ - if (AppNeedsThemedControls()) { - if (!IsWindow(themedToolTip.m_hWnd)) { - themedToolTip.Create(this, TTS_ALWAYSTIP); - themedToolTip.enableFlickerHelper(); - } - if (IsWindow(themedToolTip.m_hWnd)) { - themedToolTip.RelayEvent(pMsg); - } - } - return __super::PreTranslateMessage(pMsg); -} - -void CMPCThemeTreeCtrl::updateToolTip(CPoint point) -{ - if (AppNeedsThemedControls() && nullptr != themedToolTip) { - TOOLINFO ti = { 0 }; - UINT_PTR tid = OnToolHitTest(point, &ti); - //OnToolHitTest returns -1 on failure but doesn't update uId to match - - if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool - if (themedToolTip.GetToolCount() > 0) { - themedToolTip.DelTool(this); - themedToolTip.Activate(FALSE); - } - themedToolTipCid = (UINT_PTR) - 1; - } - - if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { - - themedToolTipCid = ti.uId; - - CRect cr; - GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate - - themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); - themedToolTip.Activate(TRUE); - } - } -} - -void CMPCThemeTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - __super::OnMouseMove(nFlags, point); - updateToolTip(point); -} - -void CMPCThemeTreeCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); - NMTVCUSTOMDRAW* pstCD = reinterpret_cast(pNMHDR); - *pResult = CDRF_DODEFAULT; - - if (AppNeedsThemedControls()) { - - bool isFocus, isHot; - switch (pNMCD->dwDrawStage) { - case CDDS_PREPAINT: { - *pResult = CDRF_NOTIFYITEMDRAW; - CDC dc; - dc.Attach(pNMCD->hdc); - dc.FillSolidRect(&pNMCD->rc, CMPCTheme::ContentBGColor); - //doEraseBkgnd(&dc); - dc.Detach(); - break; - } - case CDDS_ITEMPREPAINT: - isFocus = 0 != (pNMCD->uItemState & CDIS_FOCUS); - isHot = 0 != (pNMCD->uItemState & CDIS_HOT); - - //regular theme is a bit ugly but better than Explorer theme. we clear the focus states to control the highlight ourselves - if (!CMPCThemeUtil::canUseWin10DarkTheme()) { - pNMCD->uItemState &= ~(CDIS_FOCUS | CDIS_HOT | CDIS_SELECTED); - } - - if (isFocus) { - pstCD->clrTextBk = CMPCTheme::TreeCtrlFocusColor; - } else if (isHot) { - pstCD->clrTextBk = CMPCTheme::TreeCtrlHoverColor; - } else { - pstCD->clrTextBk = CMPCTheme::ContentBGColor; - } - if (0 == (pNMCD->uItemState & CDIS_DISABLED) && IsWindowEnabled()) { - pstCD->clrText = CMPCTheme::TextFGColor; - } else { - pstCD->clrText = CMPCTheme::ButtonDisabledFGColor; - } - *pResult = CDRF_DODEFAULT; - break; - default: - pResult = CDRF_DODEFAULT; - break; - } - } else { - __super::OnPaint(); - } -} - -void CMPCThemeTreeCtrl::doEraseBkgnd(CDC* pDC) -{ - CRect r; - GetWindowRect(r); - r.OffsetRect(-r.left, -r.top); - pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); -} - -BOOL CMPCThemeTreeCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppNeedsThemedControls()) { - //doEraseBkgnd(pDC); //we do this in the custom draw prepaint step now, to allow double buffering to work - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} - - -void CMPCThemeTreeCtrl::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->themedNcPaintWithSB(); - } else { - CMPCThemeScrollBarHelper::themedNcPaint(this, this); - } - } else { - __super::OnNcPaint(); - } -} - -//no end scroll notification for treectrl, so handle mousewheel, v and h scrolls :-/ -BOOL CMPCThemeTreeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) -{ - BOOL ret = __super::OnMouseWheel(nFlags, zDelta, pt); - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - ScreenToClient(&pt); - updateToolTip(pt); - } - return ret; -} - -void CMPCThemeTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - __super::OnVScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - -void CMPCThemeTreeCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - __super::OnHScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - -LRESULT CMPCThemeTreeCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (AppNeedsThemedControls() && nullptr != themedSBHelper) { - if (themedSBHelper->WindowProc(this, message, wParam, lParam)) { - return 1; - } - } - return __super::WindowProc(message, wParam, lParam); -} +#include "stdafx.h" +#include "CMPCThemeTreeCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#undef SubclassWindow + + +CMPCThemeTreeCtrl::CMPCThemeTreeCtrl(): + themedSBHelper(nullptr), + themedToolTipCid((UINT_PTR) - 1) +{ + if (AppNeedsThemedControls()) { + m_brBkgnd.CreateSolidBrush(CMPCTheme::InlineEditBorderColor); + if (!CMPCThemeUtil::canUseWin10DarkTheme()) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + } + } + +} + +CMPCThemeTreeCtrl::~CMPCThemeTreeCtrl() +{ + if (nullptr != themedSBHelper) { + delete themedSBHelper; + } + m_brBkgnd.DeleteObject(); +} + +BOOL CMPCThemeTreeCtrl::PreCreateWindow(CREATESTRUCT& cs) +{ + if (AppNeedsThemedControls()) { + cs.dwExStyle |= WS_EX_CLIENTEDGE; + } + return __super::PreCreateWindow(cs); +} + +void CMPCThemeTreeCtrl::fulfillThemeReqs() +{ + if (AppNeedsThemedControls()) { + if (CMPCThemeUtil::canUseWin10DarkTheme()) { + SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); + } else { + SetWindowTheme(GetSafeHwnd(), L"", NULL); + } + SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); //necessary to prevent significant flicker + + SetLineColor(CMPCTheme::TreeCtrlLineColor); + if (nullptr == tvsTooltip.m_hWnd) { + CToolTipCtrl* t = GetToolTips(); + if (nullptr != t) { + tvsTooltip.SubclassWindow(t->m_hWnd); + } + } + } else { + //adipose--enabling this cuts down on a very minor flicker in classic mode; + //the duplicate line above is necessary due to a non-default bg. + //treat as a separate line of code to be clear that this one is "optional" while the other is not + SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); //optional + } +} + +BEGIN_MESSAGE_MAP(CMPCThemeTreeCtrl, CTreeCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeTreeCtrl::OnNMCustomdraw) + ON_WM_ERASEBKGND() + ON_WM_DRAWITEM() + ON_WM_NCPAINT() + ON_WM_MOUSEMOVE() + ON_WM_MOUSEWHEEL() + ON_WM_VSCROLL() + ON_WM_HSCROLL() +END_MESSAGE_MAP() +IMPLEMENT_DYNAMIC(CMPCThemeTreeCtrl, CTreeCtrl) + +BOOL CMPCThemeTreeCtrl::PreTranslateMessage(MSG* pMsg) +{ + if (AppNeedsThemedControls()) { + if (!IsWindow(themedToolTip.m_hWnd)) { + themedToolTip.Create(this, TTS_ALWAYSTIP); + themedToolTip.enableFlickerHelper(); + } + if (IsWindow(themedToolTip.m_hWnd)) { + themedToolTip.RelayEvent(pMsg); + } + } + return __super::PreTranslateMessage(pMsg); +} + +void CMPCThemeTreeCtrl::updateToolTip(CPoint point) +{ + if (AppNeedsThemedControls() && nullptr != themedToolTip) { + TOOLINFO ti = { 0 }; + UINT_PTR tid = OnToolHitTest(point, &ti); + //OnToolHitTest returns -1 on failure but doesn't update uId to match + + if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool + if (themedToolTip.GetToolCount() > 0) { + themedToolTip.DelTool(this); + themedToolTip.Activate(FALSE); + } + themedToolTipCid = (UINT_PTR) - 1; + } + + if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { + + themedToolTipCid = ti.uId; + + CRect cr; + GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate + + themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); + themedToolTip.Activate(TRUE); + } + } +} + +void CMPCThemeTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + __super::OnMouseMove(nFlags, point); + updateToolTip(point); +} + +void CMPCThemeTreeCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); + NMTVCUSTOMDRAW* pstCD = reinterpret_cast(pNMHDR); + *pResult = CDRF_DODEFAULT; + + if (AppNeedsThemedControls()) { + + bool isFocus, isHot; + switch (pNMCD->dwDrawStage) { + case CDDS_PREPAINT: { + *pResult = CDRF_NOTIFYITEMDRAW; + CDC dc; + dc.Attach(pNMCD->hdc); + dc.FillSolidRect(&pNMCD->rc, CMPCTheme::ContentBGColor); + //doEraseBkgnd(&dc); + dc.Detach(); + break; + } + case CDDS_ITEMPREPAINT: + isFocus = 0 != (pNMCD->uItemState & CDIS_FOCUS); + isHot = 0 != (pNMCD->uItemState & CDIS_HOT); + + //regular theme is a bit ugly but better than Explorer theme. we clear the focus states to control the highlight ourselves + if (!CMPCThemeUtil::canUseWin10DarkTheme()) { + pNMCD->uItemState &= ~(CDIS_FOCUS | CDIS_HOT | CDIS_SELECTED); + } + + if (isFocus) { + pstCD->clrTextBk = CMPCTheme::TreeCtrlFocusColor; + } else if (isHot) { + pstCD->clrTextBk = CMPCTheme::TreeCtrlHoverColor; + } else { + pstCD->clrTextBk = CMPCTheme::ContentBGColor; + } + if (0 == (pNMCD->uItemState & CDIS_DISABLED) && IsWindowEnabled()) { + pstCD->clrText = CMPCTheme::TextFGColor; + } else { + pstCD->clrText = CMPCTheme::ButtonDisabledFGColor; + } + *pResult = CDRF_DODEFAULT; + break; + default: + pResult = CDRF_DODEFAULT; + break; + } + } else { + __super::OnPaint(); + } +} + +void CMPCThemeTreeCtrl::doEraseBkgnd(CDC* pDC) +{ + CRect r; + GetWindowRect(r); + r.OffsetRect(-r.left, -r.top); + pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); +} + +BOOL CMPCThemeTreeCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppNeedsThemedControls()) { + //doEraseBkgnd(pDC); //we do this in the custom draw prepaint step now, to allow double buffering to work + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} + + +void CMPCThemeTreeCtrl::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->themedNcPaintWithSB(); + } else { + CMPCThemeScrollBarHelper::themedNcPaint(this, this); + } + } else { + __super::OnNcPaint(); + } +} + +//no end scroll notification for treectrl, so handle mousewheel, v and h scrolls :-/ +BOOL CMPCThemeTreeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + BOOL ret = __super::OnMouseWheel(nFlags, zDelta, pt); + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + ScreenToClient(&pt); + updateToolTip(pt); + } + return ret; +} + +void CMPCThemeTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + __super::OnVScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + +void CMPCThemeTreeCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + __super::OnHScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + +LRESULT CMPCThemeTreeCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (AppNeedsThemedControls() && nullptr != themedSBHelper) { + if (themedSBHelper->WindowProc(this, message, wParam, lParam)) { + return 1; + } + } + return __super::WindowProc(message, wParam, lParam); +} diff --git a/src/mpc-hc/CMPCThemeTreeCtrl.h b/src/mpc-hc/CMPCThemeTreeCtrl.h index 5ce6368db6a..48527e1ef2f 100755 --- a/src/mpc-hc/CMPCThemeTreeCtrl.h +++ b/src/mpc-hc/CMPCThemeTreeCtrl.h @@ -1,36 +1,36 @@ -#pragma once -#include -#include "CMPCThemeScrollBarHelper.h" -#include "CMPCThemeToolTipCtrl.h" - -class CMPCThemeTreeCtrl : public CTreeCtrl - , public CMPCThemeScrollable -{ -public: - CMPCThemeTreeCtrl(); - virtual ~CMPCThemeTreeCtrl(); - BOOL PreCreateWindow(CREATESTRUCT& cs); - void fulfillThemeReqs(); - LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - void updateToolTip(CPoint point); - BOOL PreTranslateMessage(MSG* pMsg); - DECLARE_DYNAMIC(CMPCThemeTreeCtrl) - DECLARE_MESSAGE_MAP() - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnNcPaint(); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); -protected: - CBrush m_brBkgnd; - CFont font; - CMPCThemeScrollBarHelper* themedSBHelper; - CMPCThemeToolTipCtrl themedToolTip, tvsTooltip; - UINT_PTR themedToolTipCid; - void doEraseBkgnd(CDC* pDC); -public: - void doDefault() { Default(); } - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); -}; - +#pragma once +#include +#include "CMPCThemeScrollBarHelper.h" +#include "CMPCThemeToolTipCtrl.h" + +class CMPCThemeTreeCtrl : public CTreeCtrl + , public CMPCThemeScrollable +{ +public: + CMPCThemeTreeCtrl(); + virtual ~CMPCThemeTreeCtrl(); + BOOL PreCreateWindow(CREATESTRUCT& cs); + void fulfillThemeReqs(); + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + void updateToolTip(CPoint point); + BOOL PreTranslateMessage(MSG* pMsg); + DECLARE_DYNAMIC(CMPCThemeTreeCtrl) + DECLARE_MESSAGE_MAP() + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnNcPaint(); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); +protected: + CBrush m_brBkgnd; + CFont font; + CMPCThemeScrollBarHelper* themedSBHelper; + CMPCThemeToolTipCtrl themedToolTip, tvsTooltip; + UINT_PTR themedToolTipCid; + void doEraseBkgnd(CDC* pDC); +public: + void doDefault() { Default(); } + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); +}; + diff --git a/src/mpc-hc/CMPCThemeUtil.cpp b/src/mpc-hc/CMPCThemeUtil.cpp index 53259dabff7..530d79f1b1f 100755 --- a/src/mpc-hc/CMPCThemeUtil.cpp +++ b/src/mpc-hc/CMPCThemeUtil.cpp @@ -1,1301 +1,1301 @@ -#include "stdafx.h" -#include "CMPCThemeUtil.h" -#include "CMPCTheme.h" -#include "mplayerc.h" -#include "MainFrm.h" -#include "CMPCThemeStatic.h" -#include "CMPCThemeDialog.h" -#include "CMPCThemeSliderCtrl.h" -#include "CMPCThemeTabCtrl.h" -#include "VersionHelpersInternal.h" -#include "CMPCThemeTitleBarControlButton.h" -#include "CMPCThemeInternalPropertyPageWnd.h" -#include "CMPCThemeWin10Api.h" -#include "Translations.h" -#include "ImageGrayer.h" -#include "CMPCThemePropPageButton.h" -#undef SubclassWindow - -CBrush CMPCThemeUtil::contentBrush; -CBrush CMPCThemeUtil::windowBrush; -CBrush CMPCThemeUtil::controlAreaBrush; -CBrush CMPCThemeUtil::W10DarkThemeFileDialogInjectedBGBrush; -NONCLIENTMETRICS CMPCThemeUtil::nonClientMetrics = { 0 }; -bool CMPCThemeUtil::metricsNeedCalculation = true; - -CMPCThemeUtil::CMPCThemeUtil(): - themedDialogToolTipParent(nullptr) -{ -} - -CMPCThemeUtil::~CMPCThemeUtil() -{ - for (u_int i = 0; i < allocatedWindows.size(); i++) { - delete allocatedWindows[i]; - } -} - -void CMPCThemeUtil::subClassTBCustomizeDialog(CWnd* wnd, CToolBar* customizeToolBar) -{ - CWnd* c = CWnd::FromHandle(themableDialogHandle); - CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(); - pObject->SetSpecialCase(ToolbarCustomizeDialog); - makeThemed(pObject, c); - fulfillThemeReqs(c, ToolbarCustomizeDialog, customizeToolBar); - - ::RedrawWindow(themableDialogHandle, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_ERASE); - - if (AfxGetAppSettings().bWindows10DarkThemeActive) { - enableWindows10DarkFrame(pObject); - //force titlebar redraw - c->SendMessage(WM_NCACTIVATE, FALSE); - c->SendMessage(WM_NCACTIVATE, TRUE); - } -} - -void CMPCThemeUtil::fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase /* = 0 */, CWnd* otherWindow /* = nullptr */) -{ - if (AppIsThemeLoaded()) { - - initHelperObjects(); - - CWnd* pChild = wnd->GetWindow(GW_CHILD); - while (pChild) { - LRESULT lRes = pChild->SendMessage(WM_GETDLGCODE, 0, 0); - CWnd* tChild = pChild; - pChild = pChild->GetNextWindow(); //increment before any unsubclassing - CString runtimeClass = tChild->GetRuntimeClass()->m_lpszClassName; - TCHAR windowClass[MAX_PATH]; - ::GetClassName(tChild->GetSafeHwnd(), windowClass, _countof(windowClass)); - DWORD style = tChild->GetStyle(); - DWORD buttonType = (style & BS_TYPEMASK); - DWORD staticStyle = (style & SS_TYPEMASK); - CString windowTitle; - - if (tChild->m_hWnd) { - tChild->GetWindowText(windowTitle); - } - bool canSubclass = (CWnd::FromHandlePermanent(tChild->GetSafeHwnd()) == NULL); //refuse to subclass if already subclassed. in this case the member class should be updated rather than dynamically subclassing - - if (canSubclass) { - if (DLGC_BUTTON == (lRes & DLGC_BUTTON)) { - if (DLGC_DEFPUSHBUTTON == (lRes & DLGC_DEFPUSHBUTTON) || DLGC_UNDEFPUSHBUTTON == (lRes & DLGC_UNDEFPUSHBUTTON)) { - CMPCThemeButton* pObject; - if (specialCase == ExternalPropertyPageWithDefaultButton && windowTitle == "Default" && AppNeedsThemedControls()) { - pObject = DEBUG_NEW CMPCThemePropPageButton(); - } else { - pObject = DEBUG_NEW CMPCThemeButton(); - } - makeThemed(pObject, tChild); - } else if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX)) { - CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); - makeThemed(pObject, tChild); - } else if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_3STATE || buttonType == BS_AUTO3STATE)) { - CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); - makeThemed(pObject, tChild); - } else if (DLGC_RADIOBUTTON == (lRes & DLGC_RADIOBUTTON) && (buttonType == BS_RADIOBUTTON || buttonType == BS_AUTORADIOBUTTON)) { - CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); - makeThemed(pObject, tChild); - } else { //what other buttons? - // int a = 1; - } - } else if (0 == _tcsicmp(windowClass, WC_SCROLLBAR)) { - } else if (0 == _tcsicmp(windowClass, WC_BUTTON) && buttonType == BS_GROUPBOX) { - CMPCThemeGroupBox* pObject = DEBUG_NEW CMPCThemeGroupBox(); - makeThemed(pObject, tChild); - SetWindowTheme(tChild->GetSafeHwnd(), L"", L""); - } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_ICON == staticStyle) { //don't touch icons for now - } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_BITMAP == staticStyle) { //don't touch BITMAPS for now - } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_OWNERDRAW == staticStyle) { //don't touch OWNERDRAW for now - } else if (0 == _tcsicmp(windowClass, WC_STATIC) && (staticStyle < SS_OWNERDRAW || SS_ETCHEDHORZ == staticStyle || SS_ETCHEDVERT == staticStyle || SS_ETCHEDFRAME == staticStyle)) { - LITEM li = { 0 }; - li.mask = LIF_ITEMINDEX | LIF_ITEMID; - if (::SendMessage(tChild->GetSafeHwnd(), LM_GETITEM, 0, (LPARAM)& li)) { //we appear to have a linkctrl - CMPCThemeLinkCtrl* pObject = DEBUG_NEW CMPCThemeLinkCtrl(); - makeThemed(pObject, tChild); - } else { - CMPCThemeStatic* pObject = DEBUG_NEW CMPCThemeStatic(); - if (0 == (style & SS_LEFTNOWORDWRAP) && 0 == windowTitle.Left(20).Compare(_T("Select which output "))) { - //this is a hack for LAVFilters to avoid wrapping the statics - //FIXME by upstreaming a change to dialog layout of lavfilters, or by developing a dynamic re-layout engine - CRect wr; - tChild->GetWindowRect(wr); - wnd->ScreenToClient(wr); - wr.right += 5; - tChild->MoveWindow(wr); - } - makeThemed(pObject, tChild); - if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase && 0x416 == GetDlgCtrlID(tChild->m_hWnd)) { - CStringW str; - pObject->GetWindowTextW(str); - str.Replace(L" \r\n ", L"\r\n"); //this prevents double-wrapping due to the space wrapping before the carriage return - pObject->SetWindowTextW(str); - pObject->ModifyStyle(0, TBS_DOWNISLEFT); - } - } - } else if (0 == _tcsicmp(windowClass, WC_EDIT)) { - CMPCThemeEdit* pObject = DEBUG_NEW CMPCThemeEdit(); - makeThemed(pObject, tChild); - } else if (0 == _tcsicmp(windowClass, UPDOWN_CLASS)) { - CMPCThemeSpinButtonCtrl* pObject = DEBUG_NEW CMPCThemeSpinButtonCtrl(); - makeThemed(pObject, tChild); - } else if (0 == _tcsicmp(windowClass, _T("#32770"))) { //dialog class - CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(windowTitle == ""); - pObject->SetSpecialCase(specialCase); - makeThemed(pObject, tChild); - } else if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { - CMPCThemeComboBox* pObject = DEBUG_NEW CMPCThemeComboBox(); - makeThemed(pObject, tChild); - } else if (0 == _tcsicmp(windowClass, WC_LISTBOX)) { - CMPCThemeListBox* pObject = DEBUG_NEW CMPCThemeListBox(); - makeThemed(pObject, tChild); - if (specialCase == ToolbarCustomizeDialog) { - pObject->SetCustomizeToolbar ((CToolBar*)otherWindow); - } - } else if (0 == _tcsicmp(windowClass, TRACKBAR_CLASS)) { - CMPCThemeSliderCtrl* pObject = DEBUG_NEW CMPCThemeSliderCtrl(); - makeThemed(pObject, tChild); - if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase) { - pObject->ModifyStyle(0, TBS_DOWNISLEFT); - } - } else if (0 == _tcsicmp(windowClass, WC_TABCONTROL)) { - CMPCThemeTabCtrl* pObject = DEBUG_NEW CMPCThemeTabCtrl(); - makeThemed(pObject, tChild); - } else if (windowTitle == _T("CInternalPropertyPageWnd")) { //only seems to be needed for windows from external filters? - CMPCThemeInternalPropertyPageWnd* pObject = DEBUG_NEW CMPCThemeInternalPropertyPageWnd(); - makeThemed(pObject, tChild); - } - } - if (0 == _tcsicmp(windowClass, _T("#32770"))) { //dialog class - fulfillThemeReqs(tChild, specialCase); - } else if (windowTitle == _T("CInternalPropertyPageWnd")) { //internal window encompassing property pages - fulfillThemeReqs(tChild); - } - } - } -} - -void CMPCThemeUtil::initHelperObjects() -{ - if (contentBrush.m_hObject == nullptr) { - contentBrush.CreateSolidBrush(CMPCTheme::ContentBGColor); - } - if (windowBrush.m_hObject == nullptr) { - windowBrush.CreateSolidBrush(CMPCTheme::WindowBGColor); - } - if (controlAreaBrush.m_hObject == nullptr) { - controlAreaBrush.CreateSolidBrush(CMPCTheme::ControlAreaBGColor); - } - if (W10DarkThemeFileDialogInjectedBGBrush.m_hObject == nullptr) { - W10DarkThemeFileDialogInjectedBGBrush.CreateSolidBrush(CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); - } -} - -void CMPCThemeUtil::makeThemed(CWnd* pObject, CWnd* tChild) -{ - allocatedWindows.push_back(pObject); - pObject->SubclassWindow(tChild->GetSafeHwnd()); -} - -void CMPCThemeUtil::EnableThemedDialogTooltips(CDialog* wnd) -{ - if (AppIsThemeLoaded()) { - if (themedDialogToolTip.m_hWnd) { - themedDialogToolTip.DestroyWindow(); - } - themedDialogToolTipParent = wnd; - themedDialogToolTip.Create(wnd, TTS_NOPREFIX | TTS_ALWAYSTIP); - themedDialogToolTip.Activate(TRUE); - themedDialogToolTip.SetDelayTime(TTDT_AUTOPOP, 10000); - //enable tooltips for all child windows - CWnd* pChild = wnd->GetWindow(GW_CHILD); - while (pChild) { - themedDialogToolTip.AddTool(pChild, LPSTR_TEXTCALLBACK); - pChild = pChild->GetNextWindow(); - } - } else { - wnd->EnableToolTips(TRUE); - } -} - -void CMPCThemeUtil::RedrawDialogTooltipIfVisible() { - if (AppIsThemeLoaded() && themedDialogToolTip.m_hWnd) { - themedDialogToolTip.RedrawIfVisible(); - } else { - AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState(); - CToolTipCtrl* pToolTip = pModuleThreadState->m_pToolTip; - if (pToolTip && ::IsWindow(pToolTip->m_hWnd) && pToolTip->IsWindowVisible()) { - pToolTip->Update(); - } - } -} - -void CMPCThemeUtil::PlaceThemedDialogTooltip(UINT_PTR nID) -{ - if (AppIsThemeLoaded() && IsWindow(themedDialogToolTip)) { - if (::IsWindow(themedDialogToolTipParent->GetSafeHwnd())) { - CWnd* controlWnd = themedDialogToolTipParent->GetDlgItem(nID); - themedDialogToolTip.SetHoverPosition(controlWnd); - } - } -} - -void CMPCThemeUtil::RelayThemedDialogTooltip(MSG* pMsg) -{ - if (AppIsThemeLoaded() && IsWindow(themedDialogToolTip)) { - themedDialogToolTip.RelayEvent(pMsg); - } -} - -LRESULT CALLBACK wndProcFileDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - WNDPROC wndProcSink = NULL; - wndProcSink = (WNDPROC)GetProp(hWnd, _T("WNDPROC_SINK")); - if (!wndProcSink) { - return 0; - } - if (WM_CTLCOLOREDIT == uMsg) { - return (LRESULT)CMPCThemeUtil::getCtlColorFileDialog((HDC)wParam, CTLCOLOR_EDIT); - } - return ::CallWindowProc(wndProcSink, hWnd, uMsg, wParam, lParam); -} - -void CMPCThemeUtil::subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass) { - if (0 == wcsicmp(childWindowClass, WC_STATIC)) { - CWnd* c = CWnd::FromHandle(widget); - c->UnsubclassWindow(); - CMPCThemeStatic* pObject = DEBUG_NEW CMPCThemeStatic(); - pObject->setFileDialogChild(true); - allocatedWindows.push_back(pObject); - pObject->SubclassWindow(widget); - } else if (0 == wcsicmp(childWindowClass, WC_BUTTON)) { - CWnd* c = CWnd::FromHandle(widget); - DWORD style = c->GetStyle(); - DWORD buttonType = (style & BS_TYPEMASK); - if (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX) { - c->UnsubclassWindow(); - CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); - pObject->setFileDialogChild(true); - allocatedWindows.push_back(pObject); - pObject->SubclassWindow(widget); - } - } else if (0 == wcsicmp(childWindowClass, WC_EDIT)) { - CWnd* c = CWnd::FromHandle(widget); - c->UnsubclassWindow(); - CMPCThemeEdit* pObject = DEBUG_NEW CMPCThemeEdit(); - pObject->setFileDialogChild(true); - allocatedWindows.push_back(pObject); - pObject->SubclassWindow(widget); - if (nullptr == GetProp(parent, _T("WNDPROC_SINK"))) { - LONG_PTR wndProcOld = ::SetWindowLongPtr(parent, GWLP_WNDPROC, (LONG_PTR)wndProcFileDialog); - SetProp(parent, _T("WNDPROC_SINK"), (HANDLE)wndProcOld); - } - } -} - -void CMPCThemeUtil::subClassFileDialog(CWnd* wnd) { - if (AfxGetAppSettings().bWindows10DarkThemeActive) { - initHelperObjects(); - - HWND duiview = ::FindWindowExW(themableDialogHandle, NULL, L"DUIViewWndClassName", NULL); - HWND duihwnd = ::FindWindowExW(duiview, NULL, L"DirectUIHWND", NULL); - - if (duihwnd) { //we found the FileDialog - if (dialogProminentControlStringID) { //if this is set, we assume there is a single prominent control (note, it's in the filedialog main window) - subClassFileDialogRecurse(wnd, themableDialogHandle, ProminentControlIDWidget); - } else { - subClassFileDialogRecurse(wnd, duihwnd, RecurseSinkWidgets); - } - themableDialogHandle = nullptr; - ::RedrawWindow(duiview, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); - } - } -} - -void CMPCThemeUtil::subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType) { - HWND pChild = ::GetWindow(hWnd, GW_CHILD); - while (pChild) { - WCHAR childWindowClass[MAX_PATH]; - ::GetClassName(pChild, childWindowClass, _countof(childWindowClass)); - if (searchType == RecurseSinkWidgets) { - if (0 == wcsicmp(childWindowClass, L"FloatNotifySink")) { //children are the injected controls - subClassFileDialogRecurse(wnd, pChild, ThemeAllChildren); //recurse and theme all children of sink - } - } else if (searchType == ThemeAllChildren) { - subClassFileDialogWidgets(pChild, hWnd, childWindowClass); - } else if (searchType == ProminentControlIDWidget){ - WCHAR str[MAX_PATH]; - ::GetWindowText(pChild, str, _countof(str)); - if (0 == wcsicmp(str, ResStr(dialogProminentControlStringID))) { - subClassFileDialogWidgets(pChild, hWnd, childWindowClass); - return; - } - } - pChild = ::GetNextWindow(pChild, GW_HWNDNEXT); - } -} - -void CMPCThemeUtil::redrawAllThemedWidgets() { - for (auto w : allocatedWindows) { - w->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); - } -} - -AFX_STATIC DLGITEMTEMPLATE* AFXAPI _AfxFindNextDlgItem(DLGITEMTEMPLATE* pItem, BOOL bDialogEx); -AFX_STATIC DLGITEMTEMPLATE* AFXAPI _AfxFindFirstDlgItem(const DLGTEMPLATE* pTemplate); - -AFX_STATIC inline BOOL IsDialogEx(const DLGTEMPLATE* pTemplate) -{ - return ((_DialogSplitHelper::DLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF; -} - -static inline WORD& DlgTemplateItemCount(DLGTEMPLATE* pTemplate) -{ - if (IsDialogEx(pTemplate)) { - return reinterpret_cast<_DialogSplitHelper::DLGTEMPLATEEX*>(pTemplate)->cDlgItems; - } else { - return pTemplate->cdit; - } -} - -static inline const WORD& DlgTemplateItemCount(const DLGTEMPLATE* pTemplate) -{ - if (IsDialogEx(pTemplate)) { - return reinterpret_cast(pTemplate)->cDlgItems; - } else { - return pTemplate->cdit; - } -} - -bool CMPCThemeUtil::ModifyTemplates(CPropertySheet* sheet, CRuntimeClass* pageClass, DWORD id, DWORD addStyle, DWORD removeStyle) -{ - if (AppIsThemeLoaded()) { - PROPSHEETHEADER m_psh = sheet->m_psh; - for (int i = 0; i < sheet->GetPageCount(); i++) { - CPropertyPage* pPage = sheet->GetPage(i); - if (nullptr == AfxDynamicDownCast(pageClass, pPage)) { - continue; - } - PROPSHEETPAGE* tpsp = &pPage->m_psp; - - const DLGTEMPLATE* pTemplate; - if (tpsp->dwFlags & PSP_DLGINDIRECT) { - pTemplate = tpsp->pResource; - } else { - HRSRC hResource = ::FindResource(tpsp->hInstance, tpsp->pszTemplate, RT_DIALOG); - if (hResource == NULL) { - return false; - } - HGLOBAL hTemplate = LoadResource(tpsp->hInstance, hResource); - if (hTemplate == NULL) { - return false; - } - pTemplate = (LPCDLGTEMPLATE)LockResource(hTemplate); - if (pTemplate == NULL) { - return false; - } - } - - if (afxOccManager != NULL) { - DLGITEMTEMPLATE* pItem = _AfxFindFirstDlgItem(pTemplate); - DLGITEMTEMPLATE* pNextItem; - BOOL bDialogEx = IsDialogEx(pTemplate); - - int iItem, iItems = DlgTemplateItemCount(pTemplate); - - for (iItem = 0; iItem < iItems; iItem++) { - pNextItem = _AfxFindNextDlgItem(pItem, bDialogEx); - DWORD dwOldProtect, tp; - if (bDialogEx) { - _DialogSplitHelper::DLGITEMTEMPLATEEX* pItemEx = (_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem; - if (pItemEx->id == id) { - if (VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), PAGE_READWRITE, &dwOldProtect)) { - pItemEx->style |= addStyle; - pItemEx->style &= ~removeStyle; - VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), dwOldProtect, &tp); - } - } - } else { - if (pItem->id == id) { - if (VirtualProtect(&pItem->style, sizeof(pItem->style), PAGE_READWRITE, &dwOldProtect)) { - pItem->style |= addStyle; - pItem->style &= ~removeStyle; - VirtualProtect(&pItem->style, sizeof(pItem->style), dwOldProtect, &tp); - } - } - } - pItem = pNextItem; - } - } - } - } - return true; -} - -void CMPCThemeUtil::enableFileDialogHook() -{ - CMainFrame* pMainFrame = AfxGetMainFrame(); - pMainFrame->enableFileDialogHook(this); -} - -HBRUSH CMPCThemeUtil::getCtlColorFileDialog(HDC hDC, UINT nCtlColor) -{ - initHelperObjects(); - if (CTLCOLOR_EDIT == nCtlColor) { - ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); - ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); - return W10DarkThemeFileDialogInjectedBGBrush; - } else if (CTLCOLOR_STATIC == nCtlColor) { - ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); - ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); - return W10DarkThemeFileDialogInjectedBGBrush; - } else if (CTLCOLOR_BTN == nCtlColor) { - ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); - ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); - return W10DarkThemeFileDialogInjectedBGBrush; - } else { - return NULL; - } -} - -HBRUSH CMPCThemeUtil::getCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - initHelperObjects(); - LRESULT lResult; - if (pWnd->SendChildNotifyLastMsg(&lResult)) { - return (HBRUSH)lResult; - } - if (CTLCOLOR_LISTBOX == nCtlColor) { - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::ContentBGColor); - return contentBrush; - } else { - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::WindowBGColor); - return windowBrush; - } - } - return nullptr; -} - -bool CMPCThemeUtil::MPCThemeEraseBkgnd(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - CRect rect; - pWnd->GetClientRect(rect); - if (CTLCOLOR_DLG == nCtlColor) { //only supported "class" for now - pDC->FillSolidRect(rect, CMPCTheme::WindowBGColor); - } else { - return false; - } - return true; - } else { - return false; - } -} - -bool CMPCThemeUtil::getFontByFace(CFont& font, CWnd* wnd, wchar_t* fontName, int size, LONG weight) -{ - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - - if (!wnd) { - wnd = AfxGetMainWnd(); - } - - DpiHelper dpiWindow; - - dpiWindow.Override(wnd->GetSafeHwnd()); - lf.lfHeight = -MulDiv(size, dpiWindow.DPIY(), 72); - - lf.lfQuality = CLEARTYPE_QUALITY; - - //lf.lfQuality = ANTIALIASED_QUALITY; - lf.lfWeight = weight; - wcsncpy_s(lf.lfFaceName, fontName, LF_FACESIZE); - - return font.CreateFontIndirect(&lf); -} - -bool CMPCThemeUtil::getFixedFont(CFont& font, CDC* pDC, CWnd* wnd) -{ - if (!wnd) { - wnd = AfxGetMainWnd(); - } - - DpiHelper dpiWindow; - dpiWindow.Override(wnd->GetSafeHwnd()); - - LOGFONT tlf; - memset(&tlf, 0, sizeof(LOGFONT)); - tlf.lfHeight = -MulDiv(10, dpiWindow.DPIY(), 72); - tlf.lfQuality = CLEARTYPE_QUALITY; - tlf.lfWeight = FW_REGULAR; - wcsncpy_s(tlf.lfFaceName, _T("Consolas"), LF_FACESIZE); - return font.CreateFontIndirect(&tlf); -} - -bool CMPCThemeUtil::getFontByType(CFont& font, CWnd* wnd, int type, bool underline, bool bold) -{ - /* adipose: works poorly for dialogs as they cannot be scaled to fit zoomed fonts, only use for menus and status bars*/ - GetMetrics(); - - if (!wnd) { - wnd = AfxGetMainWnd(); - } - - //metrics will have the right fonts for the main window, but current window may be on another screen - DpiHelper dpiWindow, dpiMain; - dpiWindow.Override(wnd->GetSafeHwnd()); - dpiMain.Override(AfxGetMainWnd()->GetSafeHwnd()); - - LOGFONT* lf; - if (type == CaptionFont) { - lf = &nonClientMetrics.lfCaptionFont; - } else if (type == SmallCaptionFont) { - lf = &nonClientMetrics.lfSmCaptionFont; - } else if (type == MenuFont) { - lf = &nonClientMetrics.lfMenuFont; - } else if (type == StatusFont) { - lf = &nonClientMetrics.lfStatusFont; - } else if (type == MessageFont || type == DialogFont) { - lf = &nonClientMetrics.lfMessageFont; -#if 0 - } else if (type == DialogFont) { //hack for compatibility with MS SHell Dlg (8) used in dialogs - DpiHelper dpiWindow; - dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); - - LOGFONT tlf; - memset(&tlf, 0, sizeof(LOGFONT)); - tlf.lfHeight = -MulDiv(8, dpiWindow.DPIY(), 72); - tlf.lfQuality = CLEARTYPE_QUALITY; - tlf.lfWeight = FW_REGULAR; - wcsncpy_s(tlf.lfFaceName, m.lfMessageFont.lfFaceName, LF_FACESIZE); - //wcsncpy_s(tlf.lfFaceName, _T("MS Shell Dlg"), LF_FACESIZE); - lf = &tlf; -#endif - } else { - lf = &nonClientMetrics.lfMessageFont; - } - - int newHeight = MulDiv(lf->lfHeight, dpiWindow.DPIY(), dpiMain.DPIY()); - if (underline || bold || newHeight != lf->lfHeight) { - LOGFONT tlf; - memset(&tlf, 0, sizeof(LOGFONT)); - tlf.lfHeight = newHeight; - tlf.lfQuality = lf->lfQuality; - tlf.lfWeight = lf->lfWeight; - wcsncpy_s(tlf.lfFaceName, lf->lfFaceName, LF_FACESIZE); - tlf.lfUnderline = underline; - if (bold) { - tlf.lfWeight = FW_BOLD; - } - return font.CreateFontIndirect(&tlf); - } else { - return font.CreateFontIndirect(lf); - } -} - -CSize CMPCThemeUtil::GetTextSize(CString str, CDC* pDC, CFont* font) -{ - CFont* pOldFont = pDC->SelectObject(font); - - CRect r = { 0, 0, 0, 0 }; - pDC->DrawTextW(str, r, DT_SINGLELINE | DT_CALCRECT); - CSize cs = r.Size(); - pDC->SelectObject(pOldFont); - return cs; -} - -CSize CMPCThemeUtil::GetTextSize(CString str, HDC hDC, CFont* font) -{ - CDC* pDC = CDC::FromHandle(hDC); - return GetTextSize(str, pDC, font); -} - -CSize CMPCThemeUtil::GetTextSize(CString str, HDC hDC, CWnd *wnd, int type) -{ - CDC* pDC = CDC::FromHandle(hDC); - CFont font; - getFontByType(font, wnd, type); - - return GetTextSize(str, pDC, &font); -} - -CSize CMPCThemeUtil::GetTextSizeDiff(CString str, HDC hDC, CWnd* wnd, int type, CFont* curFont) -{ - CSize cs = GetTextSize(str, hDC, wnd, type); - CDC* cDC = CDC::FromHandle(hDC); - CFont* pOldFont = cDC->SelectObject(curFont); - CSize curCs = cDC->GetTextExtent(str); - cDC->SelectObject(pOldFont); - - return cs - curCs; -} - -void CMPCThemeUtil::GetMetrics(bool reset /* = false */) -{ - NONCLIENTMETRICS *m = &nonClientMetrics; - if (m->cbSize == 0 || metricsNeedCalculation || reset) { - m->cbSize = sizeof(NONCLIENTMETRICS); - ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), m, 0); - if (AfxGetMainWnd() == nullptr) {//this used to happen when CPreView::OnCreate was calling ScaleFont, should no longer occur - return; //we can do nothing more if main window not found yet, and metricsNeedCalculation will remain set - } - - DpiHelper dpi, dpiWindow; - dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); - - //getclientmetrics is ignorant of per window DPI - if (dpi.ScaleFactorY() != dpiWindow.ScaleFactorY()) { - m->lfCaptionFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfCaptionFont.lfHeight); - m->lfSmCaptionFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfSmCaptionFont.lfHeight); - m->lfMenuFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfMenuFont.lfHeight); - m->lfStatusFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfStatusFont.lfHeight); - m->lfMessageFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfMessageFont.lfHeight); - } - metricsNeedCalculation = false; - } -} - -void CMPCThemeUtil::initMemDC(CDC* pDC, CDC& dcMem, CBitmap& bmMem, CRect rect) -{ - dcMem.CreateCompatibleDC(pDC); - dcMem.SetBkColor(pDC->GetBkColor()); - dcMem.SetTextColor(pDC->GetTextColor()); - dcMem.SetBkMode(pDC->GetBkMode()); - dcMem.SelectObject(pDC->GetCurrentFont()); - - bmMem.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); - dcMem.SelectObject(&bmMem); - dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect.left, rect.top, SRCCOPY); -} - -void CMPCThemeUtil::flushMemDC(CDC* pDC, CDC& dcMem, CRect rect) -{ - pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); -} - - -void CMPCThemeUtil::DrawBufferedText(CDC* pDC, CString text, CRect rect, UINT format) -{ - CDC dcMem; - dcMem.CreateCompatibleDC(pDC); - dcMem.SetBkColor(pDC->GetBkColor()); - dcMem.SetTextColor(pDC->GetTextColor()); - dcMem.SetBkMode(pDC->GetBkMode()); - dcMem.SelectObject(pDC->GetCurrentFont()); - - CBitmap bmMem; - bmMem.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); - dcMem.SelectObject(&bmMem); - dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect.left, rect.top, SRCCOPY); - - CRect tr = rect; - tr.OffsetRect(-tr.left, -tr.top); - dcMem.DrawTextW(text, tr, format); - - pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); -} - -void CMPCThemeUtil::Draw2BitTransparent(CDC& dc, int left, int top, int width, int height, CBitmap& bmp, COLORREF fgColor) -{ - COLORREF crOldTextColor = dc.GetTextColor(); - COLORREF crOldBkColor = dc.GetBkColor(); - - CDC dcBMP; - dcBMP.CreateCompatibleDC(&dc); - - dcBMP.SelectObject(bmp); - dc.BitBlt(left, top, width, height, &dcBMP, 0, 0, SRCINVERT); //SRCINVERT works to create mask from 2-bit image. same result as bitblt with text=0 and bk=0xffffff - dc.SetBkColor(fgColor); //paint: foreground color (1 in 2 bit) - dc.SetTextColor(RGB(0, 0, 0)); //paint: black where transparent - dc.BitBlt(left, top, width, height, &dcBMP, 0, 0, SRCPAINT); - - dc.SetTextColor(crOldTextColor); - dc.SetBkColor(crOldBkColor); -} - -#if 0 -void CMPCThemeUtil::dbg(CString text, ...) -{ - va_list args; - va_start(args, text); - CString output; - output.FormatV(text, args); - OutputDebugString(output); - OutputDebugString(_T("\n")); - va_end(args); -} -#endif - -float CMPCThemeUtil::getConstantFByDPI(CWnd* window, const float* constants) -{ - int index; - DpiHelper dpiWindow; - dpiWindow.Override(window->GetSafeHwnd()); - int dpi = dpiWindow.DPIX(); - - if (dpi < 120) { - index = 0; - } else if (dpi < 144) { - index = 1; - } else if (dpi < 168) { - index = 2; - } else if (dpi < 192) { - index = 3; - } else { - index = 4; - } - - return constants[index]; -} - -int CMPCThemeUtil::getConstantByDPI(CWnd* window, const int* constants) -{ - int index; - DpiHelper dpiWindow; - dpiWindow.Override(window->GetSafeHwnd()); - int dpi = dpiWindow.DPIX(); - - if (dpi < 120) { - index = 0; - } else if (dpi < 144) { - index = 1; - } else if (dpi < 168) { - index = 2; - } else if (dpi < 192) { - index = 3; - } else { - index = 4; - } - - return constants[index]; -} - -UINT CMPCThemeUtil::getResourceByDPI(CWnd* window, CDC* pDC, const UINT* resources) -{ - int index; - //int dpi = pDC->GetDeviceCaps(LOGPIXELSX); - DpiHelper dpiWindow; - dpiWindow.Override(window->GetSafeHwnd()); - int dpi = dpiWindow.DPIX(); - - if (dpi < 120) { - index = 0; - } else if (dpi < 144) { - index = 1; - } else if (dpi < 168) { - index = 2; - } else if (dpi < 192) { - index = 3; - } else { - index = 4; - } - - return resources[index]; -} - -const std::vector CMPCThemeUtil::getIconPathByDPI(CWnd* wnd, WPARAM buttonType) { - DpiHelper dpiWindow; - dpiWindow.Override(wnd->GetSafeHwnd()); - - int dpi = dpiWindow.DPIX(); - switch (buttonType) { - case SC_MINIMIZE: - if (dpi < 120) { - return CMPCTheme::minimizeIcon96; - } else if (dpi < 144) { - return CMPCTheme::minimizeIcon120; - } else if (dpi < 168) { - return CMPCTheme::minimizeIcon144; - } else if (dpi < 192) { - return CMPCTheme::minimizeIcon168; - } else { - return CMPCTheme::minimizeIcon192; - } - case SC_RESTORE: - if (dpi < 120) { - return CMPCTheme::restoreIcon96; - } else if (dpi < 144) { - return CMPCTheme::restoreIcon120; - } else if (dpi < 168) { - return CMPCTheme::restoreIcon144; - } else if (dpi < 192) { - return CMPCTheme::restoreIcon168; - } else { - return CMPCTheme::restoreIcon192; - } - case SC_MAXIMIZE: - if (dpi < 120) { - return CMPCTheme::maximizeIcon96; - } else if (dpi < 144) { - return CMPCTheme::maximizeIcon120; - } else if (dpi < 168) { - return CMPCTheme::maximizeIcon144; - } else if (dpi < 192) { - return CMPCTheme::maximizeIcon168; - } else { - return CMPCTheme::maximizeIcon192; - } - case TOOLBAR_HIDE_ICON: - if (dpi < 120) { - return CMPCTheme::hideIcon96; - } else if (dpi < 144) { - return CMPCTheme::hideIcon120; - } else if (dpi < 168) { - return CMPCTheme::hideIcon144; - } else if (dpi < 192) { - return CMPCTheme::hideIcon168; - } else { - return CMPCTheme::hideIcon192; - } - case SC_CLOSE: - default: - if (dpi < 120) { - return CMPCTheme::closeIcon96; - } else if (dpi < 144) { - return CMPCTheme::closeIcon120; - } else if (dpi < 168) { - return CMPCTheme::closeIcon144; - } else if (dpi < 192) { - return CMPCTheme::closeIcon168; - } else { - return CMPCTheme::closeIcon192; - } - } -} - -//MapDialogRect deficiencies: -// 1. Caches results for windows even after they receive a DPI change -// 2. for templateless dialogs (e.g., MessageBoxDialog.cpp), the caching requires a reboot to fix -// 3. Does not honor selected font -// 4. For PropSheet, always uses "MS Shell Dlg" no matter what the sheet has selected in the .rc -void CMPCThemeUtil::MapDialogRect2(CDialog* wnd, CRect& r) { - CDC* pDC; - if (wnd && (pDC = wnd->GetDC())) { - CFont msgFont; - if (!getFontByType(msgFont, wnd, CMPCThemeUtil::MessageFont)) { - //if (!getFontByFace(msgFont, wnd, L"MS Shell Dlg", 9)){ - return; - } - - CFont* oldFont = pDC->SelectObject(&msgFont); - - //average character dimensions: https://web.archive.org/web/20131208002908/http://support.microsoft.com/kb/125681 - TEXTMETRICW tm; - SIZE size; - pDC->GetTextMetricsW(&tm); - GetTextExtentPoint32W(pDC->GetSafeHdc(), L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size); - pDC->SelectObject(oldFont); - int avgWidth = (size.cx / 26 + 1) / 2; - int avgHeight = (WORD)tm.tmHeight; - - //MapDialogRect definition: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapdialogrect - r.left = MulDiv(r.left, avgWidth, 4); - r.right = MulDiv(r.right, avgWidth, 4); - r.top = MulDiv(r.top, avgHeight, 8); - r.bottom = MulDiv(r.bottom, avgHeight, 8); - } -} - -const std::vector CMPCThemeUtil::getIconPathByDPI(CMPCThemeTitleBarControlButton* button) -{ - return getIconPathByDPI(button, button->getButtonType()); -} - -void CMPCThemeUtil::drawToolbarHideButton(CDC* pDC, CWnd* window, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias, bool hover) { - int iconWidth = CMPCThemeUtil::getConstantByDPI(window, CMPCTheme::ToolbarIconPathDimension); - int iconHeight = iconWidth; - float penThickness = 1; - CPoint ul(iconRect.left + (iconRect.Width() - iconWidth) / 2, iconRect.top + (iconRect.Height() - iconHeight) / 2); - CRect pathRect = { - ul.x, - ul.y, - ul.x + iconWidth, - ul.y + iconHeight - }; - - Gdiplus::Graphics gfx(pDC->m_hDC); - if (antiAlias) { - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x8); - } - Gdiplus::Color lineClr; - - if (hover) { //draw like a win10 icon - lineClr.SetFromCOLORREF(CMPCTheme::W10DarkThemeTitlebarIconPenColor); - } else { //draw in fg color as there is no button bg - lineClr.SetFromCOLORREF(CMPCTheme::TextFGColor); - } - Gdiplus::Pen iPen(lineClr, penThickness); - if (penThickness >= 2) { - iPen.SetLineCap(Gdiplus::LineCapSquare, Gdiplus::LineCapSquare, Gdiplus::DashCapFlat); - } - Gdiplus::REAL lastX = 0, lastY = 0; - for (u_int i = 0; i < icon.size(); i++) { - CMPCTheme::pathPoint p = icon[i]; - Gdiplus::REAL x = (Gdiplus::REAL)(pathRect.left + p.x); - Gdiplus::REAL y = (Gdiplus::REAL)(pathRect.top + p.y); - if (p.state == CMPCTheme::newPath) { - lastX = x; - lastY = y; - } else if ((p.state == CMPCTheme::linePath || p.state == CMPCTheme::closePath) && i > 0) { - gfx.DrawLine(&iPen, lastX, lastY, x, y); - if (antiAlias && penThickness < 2) { - gfx.DrawLine(&iPen, lastX, lastY, x, y); //draw again to brighten the AA diagonals - } - lastX = x; - lastY = y; - } - } -} - -void CMPCThemeUtil::drawGripper(CWnd* window, CWnd* dpiRefWnd, CRect rectGripper, CDC* pDC, bool rot90) { - CPngImage image; - image.Load(getResourceByDPI(dpiRefWnd, pDC, CMPCTheme::ThemeGrippers), AfxGetInstanceHandle()); - CImage gripperTemplate, gripperColorized; - gripperTemplate.Attach((HBITMAP)image.Detach()); - ImageGrayer::Colorize(gripperTemplate, gripperColorized, CMPCTheme::GripperPatternColor, CMPCTheme::WindowBGColor, rot90); - - CDC mDC; - mDC.CreateCompatibleDC(pDC); - mDC.SelectObject(gripperColorized); - - CDC dcMem; - CBitmap bmMem; - initMemDC(pDC, dcMem, bmMem, rectGripper); - if (rot90) { - for (int a = 0; a < rectGripper.Height(); a += gripperColorized.GetHeight()) { - dcMem.BitBlt(0, a, gripperColorized.GetWidth(), gripperColorized.GetHeight(), &mDC, 0, 0, SRCCOPY); - } - } else { - for (int a = 0; a < rectGripper.Width(); a += gripperColorized.GetWidth()) { - dcMem.BitBlt(a, 0, gripperColorized.GetWidth(), gripperColorized.GetHeight(), &mDC, 0, 0, SRCCOPY); - } - } - flushMemDC(pDC, dcMem, rectGripper); -} - - -void CMPCThemeUtil::drawCheckBox(CWnd* window, UINT checkState, bool isHover, bool useSystemSize, CRect rectCheck, CDC* pDC, bool isRadio) -{ - COLORREF borderClr, bgClr; - COLORREF oldBkClr = pDC->GetBkColor(), oldTextClr = pDC->GetTextColor(); - if (isHover) { - borderClr = CMPCTheme::CheckboxBorderHoverColor; - bgClr = CMPCTheme::CheckboxBGHoverColor; - } else { - borderClr = CMPCTheme::CheckboxBorderColor; - bgClr = CMPCTheme::CheckboxBGColor; - } - - if (useSystemSize) { - CPngImage image; - image.Load(getResourceByDPI(window, pDC, isRadio ? CMPCTheme::ThemeRadios : CMPCTheme::ThemeCheckBoxes), AfxGetInstanceHandle()); - BITMAP bm; - image.GetBitmap(&bm); - int size = bm.bmHeight; - - CDC mDC; - mDC.CreateCompatibleDC(pDC); - mDC.SelectObject(image); - int index; - if (isRadio) { - index = RadioRegular; - if (checkState) { - index += 1; - } - if (isHover) { - index += 2; - } - } else { - index = CheckBoxRegular; - if (isHover) { - index += 1; - } - } - CRect drawRect(0, 0, size, size); - //drawRect.OffsetRect(rectCheck.left + (rectCheck.Width() - size) / 2, rectCheck.top + (rectCheck.Height() - size) / 2); - drawRect.OffsetRect(rectCheck.left, rectCheck.top + (rectCheck.Height() - size) / 2); - - if (!isRadio && checkState != BST_CHECKED) { //we can draw this w/o BMPs - CBrush brush(borderClr); - pDC->FrameRect(drawRect, &brush); - drawRect.DeflateRect(1, 1); - pDC->FillSolidRect(drawRect, bgClr); - if (checkState == BST_INDETERMINATE) { - drawRect.DeflateRect(2, 2); - pDC->FillSolidRect(drawRect, CMPCTheme::CheckColor); - } - } else { - int left = index * size; - pDC->BitBlt(drawRect.left, drawRect.top, drawRect.Width(), drawRect.Height(), &mDC, left, 0, SRCCOPY); - } - } else { - CBrush brush(borderClr); - pDC->FrameRect(rectCheck, &brush); - rectCheck.DeflateRect(1, 1); - pDC->FillSolidRect(rectCheck, bgClr); - if (BST_CHECKED == checkState) { - CBitmap checkBMP; - CDC dcCheckBMP; - dcCheckBMP.CreateCompatibleDC(pDC); - - int left, top, width, height; - width = CMPCTheme::CheckWidth; - height = CMPCTheme::CheckHeight; - left = rectCheck.left + (rectCheck.Width() - width) / 2; - top = rectCheck.top + (rectCheck.Height() - height) / 2; - checkBMP.CreateBitmap(width, height, 1, 1, CMPCTheme::CheckBits); - dcCheckBMP.SelectObject(&checkBMP); - - pDC->SetBkColor(CMPCTheme::CheckColor); - pDC->SetTextColor(bgClr); - pDC->BitBlt(left, top, width, height, &dcCheckBMP, 0, 0, SRCCOPY); - } else if (BST_INDETERMINATE == checkState) { - rectCheck.DeflateRect(2, 2); - pDC->FillSolidRect(rectCheck, CMPCTheme::CheckColor); - } - } - pDC->SetBkColor(oldBkClr); - pDC->SetTextColor(oldTextClr); -} - -bool CMPCThemeUtil::canUseWin10DarkTheme() -{ - if (AppNeedsThemedControls()) { - // return false; //FIXME. return false to test behavior for OS < Win10 1809 - RTL_OSVERSIONINFOW osvi = GetRealOSVersion(); - bool ret = (osvi.dwMajorVersion = 10 && osvi.dwMajorVersion >= 0 && osvi.dwBuildNumber >= 17763); //dark theme first available in win 10 1809 - return ret; - } - return false; -} - -UINT CMPCThemeUtil::defaultLogo() -{ - return IDF_LOGO4; -} - -struct AFX_CTLCOLOR { - HWND hWnd; - HDC hDC; - UINT nCtlType; -}; - -HBRUSH CMPCThemeUtil::getParentDialogBGClr(CWnd* wnd, CDC* pDC) { - WPARAM w = (WPARAM)pDC; - AFX_CTLCOLOR ctl; - ctl.hWnd = wnd->GetSafeHwnd(); - ctl.nCtlType = CTLCOLOR_DLG; - ctl.hDC = pDC->GetSafeHdc(); - CWnd* parent = wnd->GetParent(); - if (nullptr == parent) { - parent = wnd; - } - HBRUSH bg = (HBRUSH)parent->SendMessage(WM_CTLCOLORDLG, w, (LPARAM)&ctl); - return bg; -} - -void CMPCThemeUtil::drawParentDialogBGClr(CWnd* wnd, CDC* pDC, CRect r, bool fill) -{ - CBrush brush; - HBRUSH bg = getParentDialogBGClr(wnd, pDC); - brush.Attach(bg); - if (fill) { - pDC->FillRect(r, &brush); - } else { - pDC->FrameRect(r, &brush); - } - brush.Detach(); -} - -void CMPCThemeUtil::fulfillThemeReqs(CProgressCtrl* ctl) -{ - if (AppIsThemeLoaded()) { - SetWindowTheme(ctl->GetSafeHwnd(), _T(""), _T("")); - ctl->SetBarColor(CMPCTheme::ProgressBarColor); - ctl->SetBkColor(CMPCTheme::ProgressBarBGColor); - } - ctl->UpdateWindow(); -} - -void CMPCThemeUtil::enableWindows10DarkFrame(CWnd* window) -{ - if (canUseWin10DarkTheme()) { - HMODULE hUser = GetModuleHandleA("user32.dll"); - if (hUser) { - pfnSetWindowCompositionAttribute setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(hUser, "SetWindowCompositionAttribute"); - if (setWindowCompositionAttribute) { - ACCENT_POLICY accent = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 }; - WINDOWCOMPOSITIONATTRIBDATA data; - data.Attrib = WCA_USEDARKMODECOLORS; - data.pvData = &accent; - data.cbData = sizeof(accent); - setWindowCompositionAttribute(window->GetSafeHwnd(), &data); - } - } - } -} - -int CALLBACK PropSheetCallBackRTL(HWND hWnd, UINT message, LPARAM lParam) { - switch (message) { - case PSCB_PRECREATE: - { - //arabic or hebrew - if (Translations::IsLangRTL(AfxGetAppSettings().language)) { - LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam; - lpTemplate->dwExtendedStyle |= WS_EX_LAYOUTRTL; - } - } - break; - } - return 0; -} - -void CMPCThemeUtil::PreDoModalRTL(LPPROPSHEETHEADERW m_psh) { - //see RTLWindowsLayoutCbtFilterHook and Translations::SetLanguage. - //We handle here to avoid Windows 11 bug with SetWindowLongPtr - m_psh->dwFlags |= PSH_USECALLBACK; - m_psh->pfnCallback = PropSheetCallBackRTL; -} - -//Regions are relative to upper left of WINDOW rect (not client) -CPoint CMPCThemeUtil::GetRegionOffset(CWnd* window) { - CRect twr, tcr; - window->GetWindowRect(twr); - window->GetClientRect(tcr); - ::MapWindowPoints(window->GetSafeHwnd(), nullptr, (LPPOINT)&tcr, 2); - CPoint offset = tcr.TopLeft() - twr.TopLeft(); - return offset; -} - -void CMPCThemeUtil::AdjustDynamicWidgetPair(CWnd* window, int leftWidget, int rightWidget, WidgetPairType lType, WidgetPairType rType) { - if (window && IsWindow(window->m_hWnd)) { - DpiHelper dpiWindow; - dpiWindow.Override(window->GetSafeHwnd()); - LONG dynamicSpace = dpiWindow.ScaleX(5); - - - - CWnd* leftW = window->GetDlgItem(leftWidget); - CWnd* rightW = window->GetDlgItem(rightWidget); - - WidgetPairType ll = lType; - WidgetPairType rr = rType; - - if (true || lType == WidgetPairAuto) { - LRESULT lRes = leftW->SendMessage(WM_GETDLGCODE, 0, 0); - DWORD buttonType = (leftW->GetStyle() & BS_TYPEMASK); - - if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX)) { - lType = WidgetPairCheckBox; - } else { //we only support checkbox or text on the left, just assume it's text now - lType = WidgetPairText; - } - } - - if (true || rType == WidgetPairAuto) { - TCHAR windowClass[MAX_PATH]; - ::GetClassName(rightW->GetSafeHwnd(), windowClass, _countof(windowClass)); - - if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { - rType = WidgetPairCombo; - } else { //we only support combo or edit on the right, just assume it's edit now - rType = WidgetPairEdit; - } - } - - if (leftW && rightW && IsWindow(leftW->m_hWnd) && IsWindow(rightW->m_hWnd)) { - CRect l, r; - LONG leftWantsRight, rightWantsLeft; - - leftW->GetWindowRect(l); - leftW->GetOwner()->ScreenToClient(l); - rightW->GetWindowRect(r); - rightW->GetOwner()->ScreenToClient(r); - CDC* lpDC = leftW->GetDC(); - CFont* pFont = leftW->GetFont(); - leftWantsRight = l.right; - rightWantsLeft = r.left; - { - int left = l.left; - if (lType == WidgetPairCheckBox) { - left += dpiWindow.GetSystemMetricsDPI(SM_CXMENUCHECK) + 2; - } - - CFont* pOldFont = lpDC->SelectObject(pFont); - TEXTMETRIC tm; - lpDC->GetTextMetricsW(&tm); - - CString str; - leftW->GetWindowTextW(str); - CSize szText = lpDC->GetTextExtent(str); - lpDC->SelectObject(pOldFont); - - leftWantsRight = left + szText.cx + tm.tmAveCharWidth; - leftW->ReleaseDC(lpDC); - } - - { - if (rType == WidgetPairCombo) { - //int wantWidth = (int)::SendMessage(rightW->m_hWnd, CB_GETDROPPEDWIDTH, 0, 0); - CComboBox *cb = DYNAMIC_DOWNCAST(CComboBox, rightW); - if (cb) { - int wantWidth = CorrectComboListWidth(*cb); - if (wantWidth != CB_ERR) { - rightWantsLeft = r.right - wantWidth - GetSystemMetrics(SM_CXVSCROLL); - } - } - } - } - CRect cl = l, cr = r; - if (leftWantsRight > rightWantsLeft - dynamicSpace //overlaps; we will assume defaults are best - || (leftWantsRight < l.right && rightWantsLeft > r.left) // there is no need to resize - || (lType == WidgetPairText && DT_RIGHT == (leftW->GetStyle() & DT_RIGHT)) ) //right aligned text not supported, as the right edge is fixed - { - //do nothing - } else { - l.right = leftWantsRight; - //if necessary space would shrink the right widget, instead get as close to original size as possible - //this minimizes noticeable layout changes - r.left = std::min(rightWantsLeft, std::max(l.right + dynamicSpace, r.left)); - } - if ((lType == WidgetPairText || lType == WidgetPairCheckBox) && (rType == WidgetPairCombo || rType == WidgetPairEdit)) { - l.top = r.top; - l.bottom += r.Height() - l.Height(); - leftW->ModifyStyle(0, SS_CENTERIMAGE); - } - - if (l != cl) { - leftW->MoveWindow(l); - } - if (r != cr) { - rightW->MoveWindow(r); - } - } - } -} - -void CMPCThemeUtil::UpdateAnalogCaptureDeviceSlider(CScrollBar* pScrollBar) { - if (pScrollBar && ::IsWindow(pScrollBar->m_hWnd)) { - if (CSliderCtrl* slider = DYNAMIC_DOWNCAST(CSliderCtrl, pScrollBar)) { - slider->SendMessage(WM_KEYUP, VK_LEFT, 1); //does not move the slider, only forces current position to be registered - } - } -} - -bool CMPCThemeUtil::IsWindowVisibleAndRendered(CWnd* window) { - if (!window || !IsWindow(window->m_hWnd) || !window->IsWindowVisible()) { - return false; - } else { - CRect r; - HDC hdc = GetWindowDC(window->m_hWnd); - GetClipBox(hdc, &r); - if (r.IsRectEmpty()) { - return false; - } - } - return true; -} +#include "stdafx.h" +#include "CMPCThemeUtil.h" +#include "CMPCTheme.h" +#include "mplayerc.h" +#include "MainFrm.h" +#include "CMPCThemeStatic.h" +#include "CMPCThemeDialog.h" +#include "CMPCThemeSliderCtrl.h" +#include "CMPCThemeTabCtrl.h" +#include "VersionHelpersInternal.h" +#include "CMPCThemeTitleBarControlButton.h" +#include "CMPCThemeInternalPropertyPageWnd.h" +#include "CMPCThemeWin10Api.h" +#include "Translations.h" +#include "ImageGrayer.h" +#include "CMPCThemePropPageButton.h" +#undef SubclassWindow + +CBrush CMPCThemeUtil::contentBrush; +CBrush CMPCThemeUtil::windowBrush; +CBrush CMPCThemeUtil::controlAreaBrush; +CBrush CMPCThemeUtil::W10DarkThemeFileDialogInjectedBGBrush; +NONCLIENTMETRICS CMPCThemeUtil::nonClientMetrics = { 0 }; +bool CMPCThemeUtil::metricsNeedCalculation = true; + +CMPCThemeUtil::CMPCThemeUtil(): + themedDialogToolTipParent(nullptr) +{ +} + +CMPCThemeUtil::~CMPCThemeUtil() +{ + for (u_int i = 0; i < allocatedWindows.size(); i++) { + delete allocatedWindows[i]; + } +} + +void CMPCThemeUtil::subClassTBCustomizeDialog(CWnd* wnd, CToolBar* customizeToolBar) +{ + CWnd* c = CWnd::FromHandle(themableDialogHandle); + CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(); + pObject->SetSpecialCase(ToolbarCustomizeDialog); + makeThemed(pObject, c); + fulfillThemeReqs(c, ToolbarCustomizeDialog, customizeToolBar); + + ::RedrawWindow(themableDialogHandle, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_ERASE); + + if (AfxGetAppSettings().bWindows10DarkThemeActive) { + enableWindows10DarkFrame(pObject); + //force titlebar redraw + c->SendMessage(WM_NCACTIVATE, FALSE); + c->SendMessage(WM_NCACTIVATE, TRUE); + } +} + +void CMPCThemeUtil::fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase /* = 0 */, CWnd* otherWindow /* = nullptr */) +{ + if (AppIsThemeLoaded()) { + + initHelperObjects(); + + CWnd* pChild = wnd->GetWindow(GW_CHILD); + while (pChild) { + LRESULT lRes = pChild->SendMessage(WM_GETDLGCODE, 0, 0); + CWnd* tChild = pChild; + pChild = pChild->GetNextWindow(); //increment before any unsubclassing + CString runtimeClass = tChild->GetRuntimeClass()->m_lpszClassName; + TCHAR windowClass[MAX_PATH]; + ::GetClassName(tChild->GetSafeHwnd(), windowClass, _countof(windowClass)); + DWORD style = tChild->GetStyle(); + DWORD buttonType = (style & BS_TYPEMASK); + DWORD staticStyle = (style & SS_TYPEMASK); + CString windowTitle; + + if (tChild->m_hWnd) { + tChild->GetWindowText(windowTitle); + } + bool canSubclass = (CWnd::FromHandlePermanent(tChild->GetSafeHwnd()) == NULL); //refuse to subclass if already subclassed. in this case the member class should be updated rather than dynamically subclassing + + if (canSubclass) { + if (DLGC_BUTTON == (lRes & DLGC_BUTTON)) { + if (DLGC_DEFPUSHBUTTON == (lRes & DLGC_DEFPUSHBUTTON) || DLGC_UNDEFPUSHBUTTON == (lRes & DLGC_UNDEFPUSHBUTTON)) { + CMPCThemeButton* pObject; + if (specialCase == ExternalPropertyPageWithDefaultButton && windowTitle == "Default" && AppNeedsThemedControls()) { + pObject = DEBUG_NEW CMPCThemePropPageButton(); + } else { + pObject = DEBUG_NEW CMPCThemeButton(); + } + makeThemed(pObject, tChild); + } else if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX)) { + CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); + makeThemed(pObject, tChild); + } else if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_3STATE || buttonType == BS_AUTO3STATE)) { + CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); + makeThemed(pObject, tChild); + } else if (DLGC_RADIOBUTTON == (lRes & DLGC_RADIOBUTTON) && (buttonType == BS_RADIOBUTTON || buttonType == BS_AUTORADIOBUTTON)) { + CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); + makeThemed(pObject, tChild); + } else { //what other buttons? + // int a = 1; + } + } else if (0 == _tcsicmp(windowClass, WC_SCROLLBAR)) { + } else if (0 == _tcsicmp(windowClass, WC_BUTTON) && buttonType == BS_GROUPBOX) { + CMPCThemeGroupBox* pObject = DEBUG_NEW CMPCThemeGroupBox(); + makeThemed(pObject, tChild); + SetWindowTheme(tChild->GetSafeHwnd(), L"", L""); + } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_ICON == staticStyle) { //don't touch icons for now + } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_BITMAP == staticStyle) { //don't touch BITMAPS for now + } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_OWNERDRAW == staticStyle) { //don't touch OWNERDRAW for now + } else if (0 == _tcsicmp(windowClass, WC_STATIC) && (staticStyle < SS_OWNERDRAW || SS_ETCHEDHORZ == staticStyle || SS_ETCHEDVERT == staticStyle || SS_ETCHEDFRAME == staticStyle)) { + LITEM li = { 0 }; + li.mask = LIF_ITEMINDEX | LIF_ITEMID; + if (::SendMessage(tChild->GetSafeHwnd(), LM_GETITEM, 0, (LPARAM)& li)) { //we appear to have a linkctrl + CMPCThemeLinkCtrl* pObject = DEBUG_NEW CMPCThemeLinkCtrl(); + makeThemed(pObject, tChild); + } else { + CMPCThemeStatic* pObject = DEBUG_NEW CMPCThemeStatic(); + if (0 == (style & SS_LEFTNOWORDWRAP) && 0 == windowTitle.Left(20).Compare(_T("Select which output "))) { + //this is a hack for LAVFilters to avoid wrapping the statics + //FIXME by upstreaming a change to dialog layout of lavfilters, or by developing a dynamic re-layout engine + CRect wr; + tChild->GetWindowRect(wr); + wnd->ScreenToClient(wr); + wr.right += 5; + tChild->MoveWindow(wr); + } + makeThemed(pObject, tChild); + if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase && 0x416 == GetDlgCtrlID(tChild->m_hWnd)) { + CStringW str; + pObject->GetWindowTextW(str); + str.Replace(L" \r\n ", L"\r\n"); //this prevents double-wrapping due to the space wrapping before the carriage return + pObject->SetWindowTextW(str); + pObject->ModifyStyle(0, TBS_DOWNISLEFT); + } + } + } else if (0 == _tcsicmp(windowClass, WC_EDIT)) { + CMPCThemeEdit* pObject = DEBUG_NEW CMPCThemeEdit(); + makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, UPDOWN_CLASS)) { + CMPCThemeSpinButtonCtrl* pObject = DEBUG_NEW CMPCThemeSpinButtonCtrl(); + makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, _T("#32770"))) { //dialog class + CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(windowTitle == ""); + pObject->SetSpecialCase(specialCase); + makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { + CMPCThemeComboBox* pObject = DEBUG_NEW CMPCThemeComboBox(); + makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, WC_LISTBOX)) { + CMPCThemeListBox* pObject = DEBUG_NEW CMPCThemeListBox(); + makeThemed(pObject, tChild); + if (specialCase == ToolbarCustomizeDialog) { + pObject->SetCustomizeToolbar ((CToolBar*)otherWindow); + } + } else if (0 == _tcsicmp(windowClass, TRACKBAR_CLASS)) { + CMPCThemeSliderCtrl* pObject = DEBUG_NEW CMPCThemeSliderCtrl(); + makeThemed(pObject, tChild); + if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase) { + pObject->ModifyStyle(0, TBS_DOWNISLEFT); + } + } else if (0 == _tcsicmp(windowClass, WC_TABCONTROL)) { + CMPCThemeTabCtrl* pObject = DEBUG_NEW CMPCThemeTabCtrl(); + makeThemed(pObject, tChild); + } else if (windowTitle == _T("CInternalPropertyPageWnd")) { //only seems to be needed for windows from external filters? + CMPCThemeInternalPropertyPageWnd* pObject = DEBUG_NEW CMPCThemeInternalPropertyPageWnd(); + makeThemed(pObject, tChild); + } + } + if (0 == _tcsicmp(windowClass, _T("#32770"))) { //dialog class + fulfillThemeReqs(tChild, specialCase); + } else if (windowTitle == _T("CInternalPropertyPageWnd")) { //internal window encompassing property pages + fulfillThemeReqs(tChild); + } + } + } +} + +void CMPCThemeUtil::initHelperObjects() +{ + if (contentBrush.m_hObject == nullptr) { + contentBrush.CreateSolidBrush(CMPCTheme::ContentBGColor); + } + if (windowBrush.m_hObject == nullptr) { + windowBrush.CreateSolidBrush(CMPCTheme::WindowBGColor); + } + if (controlAreaBrush.m_hObject == nullptr) { + controlAreaBrush.CreateSolidBrush(CMPCTheme::ControlAreaBGColor); + } + if (W10DarkThemeFileDialogInjectedBGBrush.m_hObject == nullptr) { + W10DarkThemeFileDialogInjectedBGBrush.CreateSolidBrush(CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); + } +} + +void CMPCThemeUtil::makeThemed(CWnd* pObject, CWnd* tChild) +{ + allocatedWindows.push_back(pObject); + pObject->SubclassWindow(tChild->GetSafeHwnd()); +} + +void CMPCThemeUtil::EnableThemedDialogTooltips(CDialog* wnd) +{ + if (AppIsThemeLoaded()) { + if (themedDialogToolTip.m_hWnd) { + themedDialogToolTip.DestroyWindow(); + } + themedDialogToolTipParent = wnd; + themedDialogToolTip.Create(wnd, TTS_NOPREFIX | TTS_ALWAYSTIP); + themedDialogToolTip.Activate(TRUE); + themedDialogToolTip.SetDelayTime(TTDT_AUTOPOP, 10000); + //enable tooltips for all child windows + CWnd* pChild = wnd->GetWindow(GW_CHILD); + while (pChild) { + themedDialogToolTip.AddTool(pChild, LPSTR_TEXTCALLBACK); + pChild = pChild->GetNextWindow(); + } + } else { + wnd->EnableToolTips(TRUE); + } +} + +void CMPCThemeUtil::RedrawDialogTooltipIfVisible() { + if (AppIsThemeLoaded() && themedDialogToolTip.m_hWnd) { + themedDialogToolTip.RedrawIfVisible(); + } else { + AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState(); + CToolTipCtrl* pToolTip = pModuleThreadState->m_pToolTip; + if (pToolTip && ::IsWindow(pToolTip->m_hWnd) && pToolTip->IsWindowVisible()) { + pToolTip->Update(); + } + } +} + +void CMPCThemeUtil::PlaceThemedDialogTooltip(UINT_PTR nID) +{ + if (AppIsThemeLoaded() && IsWindow(themedDialogToolTip)) { + if (::IsWindow(themedDialogToolTipParent->GetSafeHwnd())) { + CWnd* controlWnd = themedDialogToolTipParent->GetDlgItem(nID); + themedDialogToolTip.SetHoverPosition(controlWnd); + } + } +} + +void CMPCThemeUtil::RelayThemedDialogTooltip(MSG* pMsg) +{ + if (AppIsThemeLoaded() && IsWindow(themedDialogToolTip)) { + themedDialogToolTip.RelayEvent(pMsg); + } +} + +LRESULT CALLBACK wndProcFileDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC wndProcSink = NULL; + wndProcSink = (WNDPROC)GetProp(hWnd, _T("WNDPROC_SINK")); + if (!wndProcSink) { + return 0; + } + if (WM_CTLCOLOREDIT == uMsg) { + return (LRESULT)CMPCThemeUtil::getCtlColorFileDialog((HDC)wParam, CTLCOLOR_EDIT); + } + return ::CallWindowProc(wndProcSink, hWnd, uMsg, wParam, lParam); +} + +void CMPCThemeUtil::subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass) { + if (0 == wcsicmp(childWindowClass, WC_STATIC)) { + CWnd* c = CWnd::FromHandle(widget); + c->UnsubclassWindow(); + CMPCThemeStatic* pObject = DEBUG_NEW CMPCThemeStatic(); + pObject->setFileDialogChild(true); + allocatedWindows.push_back(pObject); + pObject->SubclassWindow(widget); + } else if (0 == wcsicmp(childWindowClass, WC_BUTTON)) { + CWnd* c = CWnd::FromHandle(widget); + DWORD style = c->GetStyle(); + DWORD buttonType = (style & BS_TYPEMASK); + if (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX) { + c->UnsubclassWindow(); + CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); + pObject->setFileDialogChild(true); + allocatedWindows.push_back(pObject); + pObject->SubclassWindow(widget); + } + } else if (0 == wcsicmp(childWindowClass, WC_EDIT)) { + CWnd* c = CWnd::FromHandle(widget); + c->UnsubclassWindow(); + CMPCThemeEdit* pObject = DEBUG_NEW CMPCThemeEdit(); + pObject->setFileDialogChild(true); + allocatedWindows.push_back(pObject); + pObject->SubclassWindow(widget); + if (nullptr == GetProp(parent, _T("WNDPROC_SINK"))) { + LONG_PTR wndProcOld = ::SetWindowLongPtr(parent, GWLP_WNDPROC, (LONG_PTR)wndProcFileDialog); + SetProp(parent, _T("WNDPROC_SINK"), (HANDLE)wndProcOld); + } + } +} + +void CMPCThemeUtil::subClassFileDialog(CWnd* wnd) { + if (AfxGetAppSettings().bWindows10DarkThemeActive) { + initHelperObjects(); + + HWND duiview = ::FindWindowExW(themableDialogHandle, NULL, L"DUIViewWndClassName", NULL); + HWND duihwnd = ::FindWindowExW(duiview, NULL, L"DirectUIHWND", NULL); + + if (duihwnd) { //we found the FileDialog + if (dialogProminentControlStringID) { //if this is set, we assume there is a single prominent control (note, it's in the filedialog main window) + subClassFileDialogRecurse(wnd, themableDialogHandle, ProminentControlIDWidget); + } else { + subClassFileDialogRecurse(wnd, duihwnd, RecurseSinkWidgets); + } + themableDialogHandle = nullptr; + ::RedrawWindow(duiview, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + } + } +} + +void CMPCThemeUtil::subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType) { + HWND pChild = ::GetWindow(hWnd, GW_CHILD); + while (pChild) { + WCHAR childWindowClass[MAX_PATH]; + ::GetClassName(pChild, childWindowClass, _countof(childWindowClass)); + if (searchType == RecurseSinkWidgets) { + if (0 == wcsicmp(childWindowClass, L"FloatNotifySink")) { //children are the injected controls + subClassFileDialogRecurse(wnd, pChild, ThemeAllChildren); //recurse and theme all children of sink + } + } else if (searchType == ThemeAllChildren) { + subClassFileDialogWidgets(pChild, hWnd, childWindowClass); + } else if (searchType == ProminentControlIDWidget){ + WCHAR str[MAX_PATH]; + ::GetWindowText(pChild, str, _countof(str)); + if (0 == wcsicmp(str, ResStr(dialogProminentControlStringID))) { + subClassFileDialogWidgets(pChild, hWnd, childWindowClass); + return; + } + } + pChild = ::GetNextWindow(pChild, GW_HWNDNEXT); + } +} + +void CMPCThemeUtil::redrawAllThemedWidgets() { + for (auto w : allocatedWindows) { + w->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } +} + +AFX_STATIC DLGITEMTEMPLATE* AFXAPI _AfxFindNextDlgItem(DLGITEMTEMPLATE* pItem, BOOL bDialogEx); +AFX_STATIC DLGITEMTEMPLATE* AFXAPI _AfxFindFirstDlgItem(const DLGTEMPLATE* pTemplate); + +AFX_STATIC inline BOOL IsDialogEx(const DLGTEMPLATE* pTemplate) +{ + return ((_DialogSplitHelper::DLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF; +} + +static inline WORD& DlgTemplateItemCount(DLGTEMPLATE* pTemplate) +{ + if (IsDialogEx(pTemplate)) { + return reinterpret_cast<_DialogSplitHelper::DLGTEMPLATEEX*>(pTemplate)->cDlgItems; + } else { + return pTemplate->cdit; + } +} + +static inline const WORD& DlgTemplateItemCount(const DLGTEMPLATE* pTemplate) +{ + if (IsDialogEx(pTemplate)) { + return reinterpret_cast(pTemplate)->cDlgItems; + } else { + return pTemplate->cdit; + } +} + +bool CMPCThemeUtil::ModifyTemplates(CPropertySheet* sheet, CRuntimeClass* pageClass, DWORD id, DWORD addStyle, DWORD removeStyle) +{ + if (AppIsThemeLoaded()) { + PROPSHEETHEADER m_psh = sheet->m_psh; + for (int i = 0; i < sheet->GetPageCount(); i++) { + CPropertyPage* pPage = sheet->GetPage(i); + if (nullptr == AfxDynamicDownCast(pageClass, pPage)) { + continue; + } + PROPSHEETPAGE* tpsp = &pPage->m_psp; + + const DLGTEMPLATE* pTemplate; + if (tpsp->dwFlags & PSP_DLGINDIRECT) { + pTemplate = tpsp->pResource; + } else { + HRSRC hResource = ::FindResource(tpsp->hInstance, tpsp->pszTemplate, RT_DIALOG); + if (hResource == NULL) { + return false; + } + HGLOBAL hTemplate = LoadResource(tpsp->hInstance, hResource); + if (hTemplate == NULL) { + return false; + } + pTemplate = (LPCDLGTEMPLATE)LockResource(hTemplate); + if (pTemplate == NULL) { + return false; + } + } + + if (afxOccManager != NULL) { + DLGITEMTEMPLATE* pItem = _AfxFindFirstDlgItem(pTemplate); + DLGITEMTEMPLATE* pNextItem; + BOOL bDialogEx = IsDialogEx(pTemplate); + + int iItem, iItems = DlgTemplateItemCount(pTemplate); + + for (iItem = 0; iItem < iItems; iItem++) { + pNextItem = _AfxFindNextDlgItem(pItem, bDialogEx); + DWORD dwOldProtect, tp; + if (bDialogEx) { + _DialogSplitHelper::DLGITEMTEMPLATEEX* pItemEx = (_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem; + if (pItemEx->id == id) { + if (VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), PAGE_READWRITE, &dwOldProtect)) { + pItemEx->style |= addStyle; + pItemEx->style &= ~removeStyle; + VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), dwOldProtect, &tp); + } + } + } else { + if (pItem->id == id) { + if (VirtualProtect(&pItem->style, sizeof(pItem->style), PAGE_READWRITE, &dwOldProtect)) { + pItem->style |= addStyle; + pItem->style &= ~removeStyle; + VirtualProtect(&pItem->style, sizeof(pItem->style), dwOldProtect, &tp); + } + } + } + pItem = pNextItem; + } + } + } + } + return true; +} + +void CMPCThemeUtil::enableFileDialogHook() +{ + CMainFrame* pMainFrame = AfxGetMainFrame(); + pMainFrame->enableFileDialogHook(this); +} + +HBRUSH CMPCThemeUtil::getCtlColorFileDialog(HDC hDC, UINT nCtlColor) +{ + initHelperObjects(); + if (CTLCOLOR_EDIT == nCtlColor) { + ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); + ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); + return W10DarkThemeFileDialogInjectedBGBrush; + } else if (CTLCOLOR_STATIC == nCtlColor) { + ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); + ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); + return W10DarkThemeFileDialogInjectedBGBrush; + } else if (CTLCOLOR_BTN == nCtlColor) { + ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); + ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); + return W10DarkThemeFileDialogInjectedBGBrush; + } else { + return NULL; + } +} + +HBRUSH CMPCThemeUtil::getCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + initHelperObjects(); + LRESULT lResult; + if (pWnd->SendChildNotifyLastMsg(&lResult)) { + return (HBRUSH)lResult; + } + if (CTLCOLOR_LISTBOX == nCtlColor) { + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::ContentBGColor); + return contentBrush; + } else { + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::WindowBGColor); + return windowBrush; + } + } + return nullptr; +} + +bool CMPCThemeUtil::MPCThemeEraseBkgnd(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + CRect rect; + pWnd->GetClientRect(rect); + if (CTLCOLOR_DLG == nCtlColor) { //only supported "class" for now + pDC->FillSolidRect(rect, CMPCTheme::WindowBGColor); + } else { + return false; + } + return true; + } else { + return false; + } +} + +bool CMPCThemeUtil::getFontByFace(CFont& font, CWnd* wnd, wchar_t* fontName, int size, LONG weight) +{ + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + + if (!wnd) { + wnd = AfxGetMainWnd(); + } + + DpiHelper dpiWindow; + + dpiWindow.Override(wnd->GetSafeHwnd()); + lf.lfHeight = -MulDiv(size, dpiWindow.DPIY(), 72); + + lf.lfQuality = CLEARTYPE_QUALITY; + + //lf.lfQuality = ANTIALIASED_QUALITY; + lf.lfWeight = weight; + wcsncpy_s(lf.lfFaceName, fontName, LF_FACESIZE); + + return font.CreateFontIndirect(&lf); +} + +bool CMPCThemeUtil::getFixedFont(CFont& font, CDC* pDC, CWnd* wnd) +{ + if (!wnd) { + wnd = AfxGetMainWnd(); + } + + DpiHelper dpiWindow; + dpiWindow.Override(wnd->GetSafeHwnd()); + + LOGFONT tlf; + memset(&tlf, 0, sizeof(LOGFONT)); + tlf.lfHeight = -MulDiv(10, dpiWindow.DPIY(), 72); + tlf.lfQuality = CLEARTYPE_QUALITY; + tlf.lfWeight = FW_REGULAR; + wcsncpy_s(tlf.lfFaceName, _T("Consolas"), LF_FACESIZE); + return font.CreateFontIndirect(&tlf); +} + +bool CMPCThemeUtil::getFontByType(CFont& font, CWnd* wnd, int type, bool underline, bool bold) +{ + /* adipose: works poorly for dialogs as they cannot be scaled to fit zoomed fonts, only use for menus and status bars*/ + GetMetrics(); + + if (!wnd) { + wnd = AfxGetMainWnd(); + } + + //metrics will have the right fonts for the main window, but current window may be on another screen + DpiHelper dpiWindow, dpiMain; + dpiWindow.Override(wnd->GetSafeHwnd()); + dpiMain.Override(AfxGetMainWnd()->GetSafeHwnd()); + + LOGFONT* lf; + if (type == CaptionFont) { + lf = &nonClientMetrics.lfCaptionFont; + } else if (type == SmallCaptionFont) { + lf = &nonClientMetrics.lfSmCaptionFont; + } else if (type == MenuFont) { + lf = &nonClientMetrics.lfMenuFont; + } else if (type == StatusFont) { + lf = &nonClientMetrics.lfStatusFont; + } else if (type == MessageFont || type == DialogFont) { + lf = &nonClientMetrics.lfMessageFont; +#if 0 + } else if (type == DialogFont) { //hack for compatibility with MS SHell Dlg (8) used in dialogs + DpiHelper dpiWindow; + dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); + + LOGFONT tlf; + memset(&tlf, 0, sizeof(LOGFONT)); + tlf.lfHeight = -MulDiv(8, dpiWindow.DPIY(), 72); + tlf.lfQuality = CLEARTYPE_QUALITY; + tlf.lfWeight = FW_REGULAR; + wcsncpy_s(tlf.lfFaceName, m.lfMessageFont.lfFaceName, LF_FACESIZE); + //wcsncpy_s(tlf.lfFaceName, _T("MS Shell Dlg"), LF_FACESIZE); + lf = &tlf; +#endif + } else { + lf = &nonClientMetrics.lfMessageFont; + } + + int newHeight = MulDiv(lf->lfHeight, dpiWindow.DPIY(), dpiMain.DPIY()); + if (underline || bold || newHeight != lf->lfHeight) { + LOGFONT tlf; + memset(&tlf, 0, sizeof(LOGFONT)); + tlf.lfHeight = newHeight; + tlf.lfQuality = lf->lfQuality; + tlf.lfWeight = lf->lfWeight; + wcsncpy_s(tlf.lfFaceName, lf->lfFaceName, LF_FACESIZE); + tlf.lfUnderline = underline; + if (bold) { + tlf.lfWeight = FW_BOLD; + } + return font.CreateFontIndirect(&tlf); + } else { + return font.CreateFontIndirect(lf); + } +} + +CSize CMPCThemeUtil::GetTextSize(CString str, CDC* pDC, CFont* font) +{ + CFont* pOldFont = pDC->SelectObject(font); + + CRect r = { 0, 0, 0, 0 }; + pDC->DrawTextW(str, r, DT_SINGLELINE | DT_CALCRECT); + CSize cs = r.Size(); + pDC->SelectObject(pOldFont); + return cs; +} + +CSize CMPCThemeUtil::GetTextSize(CString str, HDC hDC, CFont* font) +{ + CDC* pDC = CDC::FromHandle(hDC); + return GetTextSize(str, pDC, font); +} + +CSize CMPCThemeUtil::GetTextSize(CString str, HDC hDC, CWnd *wnd, int type) +{ + CDC* pDC = CDC::FromHandle(hDC); + CFont font; + getFontByType(font, wnd, type); + + return GetTextSize(str, pDC, &font); +} + +CSize CMPCThemeUtil::GetTextSizeDiff(CString str, HDC hDC, CWnd* wnd, int type, CFont* curFont) +{ + CSize cs = GetTextSize(str, hDC, wnd, type); + CDC* cDC = CDC::FromHandle(hDC); + CFont* pOldFont = cDC->SelectObject(curFont); + CSize curCs = cDC->GetTextExtent(str); + cDC->SelectObject(pOldFont); + + return cs - curCs; +} + +void CMPCThemeUtil::GetMetrics(bool reset /* = false */) +{ + NONCLIENTMETRICS *m = &nonClientMetrics; + if (m->cbSize == 0 || metricsNeedCalculation || reset) { + m->cbSize = sizeof(NONCLIENTMETRICS); + ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), m, 0); + if (AfxGetMainWnd() == nullptr) {//this used to happen when CPreView::OnCreate was calling ScaleFont, should no longer occur + return; //we can do nothing more if main window not found yet, and metricsNeedCalculation will remain set + } + + DpiHelper dpi, dpiWindow; + dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); + + //getclientmetrics is ignorant of per window DPI + if (dpi.ScaleFactorY() != dpiWindow.ScaleFactorY()) { + m->lfCaptionFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfCaptionFont.lfHeight); + m->lfSmCaptionFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfSmCaptionFont.lfHeight); + m->lfMenuFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfMenuFont.lfHeight); + m->lfStatusFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfStatusFont.lfHeight); + m->lfMessageFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfMessageFont.lfHeight); + } + metricsNeedCalculation = false; + } +} + +void CMPCThemeUtil::initMemDC(CDC* pDC, CDC& dcMem, CBitmap& bmMem, CRect rect) +{ + dcMem.CreateCompatibleDC(pDC); + dcMem.SetBkColor(pDC->GetBkColor()); + dcMem.SetTextColor(pDC->GetTextColor()); + dcMem.SetBkMode(pDC->GetBkMode()); + dcMem.SelectObject(pDC->GetCurrentFont()); + + bmMem.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); + dcMem.SelectObject(&bmMem); + dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect.left, rect.top, SRCCOPY); +} + +void CMPCThemeUtil::flushMemDC(CDC* pDC, CDC& dcMem, CRect rect) +{ + pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); +} + + +void CMPCThemeUtil::DrawBufferedText(CDC* pDC, CString text, CRect rect, UINT format) +{ + CDC dcMem; + dcMem.CreateCompatibleDC(pDC); + dcMem.SetBkColor(pDC->GetBkColor()); + dcMem.SetTextColor(pDC->GetTextColor()); + dcMem.SetBkMode(pDC->GetBkMode()); + dcMem.SelectObject(pDC->GetCurrentFont()); + + CBitmap bmMem; + bmMem.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); + dcMem.SelectObject(&bmMem); + dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect.left, rect.top, SRCCOPY); + + CRect tr = rect; + tr.OffsetRect(-tr.left, -tr.top); + dcMem.DrawTextW(text, tr, format); + + pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); +} + +void CMPCThemeUtil::Draw2BitTransparent(CDC& dc, int left, int top, int width, int height, CBitmap& bmp, COLORREF fgColor) +{ + COLORREF crOldTextColor = dc.GetTextColor(); + COLORREF crOldBkColor = dc.GetBkColor(); + + CDC dcBMP; + dcBMP.CreateCompatibleDC(&dc); + + dcBMP.SelectObject(bmp); + dc.BitBlt(left, top, width, height, &dcBMP, 0, 0, SRCINVERT); //SRCINVERT works to create mask from 2-bit image. same result as bitblt with text=0 and bk=0xffffff + dc.SetBkColor(fgColor); //paint: foreground color (1 in 2 bit) + dc.SetTextColor(RGB(0, 0, 0)); //paint: black where transparent + dc.BitBlt(left, top, width, height, &dcBMP, 0, 0, SRCPAINT); + + dc.SetTextColor(crOldTextColor); + dc.SetBkColor(crOldBkColor); +} + +#if 0 +void CMPCThemeUtil::dbg(CString text, ...) +{ + va_list args; + va_start(args, text); + CString output; + output.FormatV(text, args); + OutputDebugString(output); + OutputDebugString(_T("\n")); + va_end(args); +} +#endif + +float CMPCThemeUtil::getConstantFByDPI(CWnd* window, const float* constants) +{ + int index; + DpiHelper dpiWindow; + dpiWindow.Override(window->GetSafeHwnd()); + int dpi = dpiWindow.DPIX(); + + if (dpi < 120) { + index = 0; + } else if (dpi < 144) { + index = 1; + } else if (dpi < 168) { + index = 2; + } else if (dpi < 192) { + index = 3; + } else { + index = 4; + } + + return constants[index]; +} + +int CMPCThemeUtil::getConstantByDPI(CWnd* window, const int* constants) +{ + int index; + DpiHelper dpiWindow; + dpiWindow.Override(window->GetSafeHwnd()); + int dpi = dpiWindow.DPIX(); + + if (dpi < 120) { + index = 0; + } else if (dpi < 144) { + index = 1; + } else if (dpi < 168) { + index = 2; + } else if (dpi < 192) { + index = 3; + } else { + index = 4; + } + + return constants[index]; +} + +UINT CMPCThemeUtil::getResourceByDPI(CWnd* window, CDC* pDC, const UINT* resources) +{ + int index; + //int dpi = pDC->GetDeviceCaps(LOGPIXELSX); + DpiHelper dpiWindow; + dpiWindow.Override(window->GetSafeHwnd()); + int dpi = dpiWindow.DPIX(); + + if (dpi < 120) { + index = 0; + } else if (dpi < 144) { + index = 1; + } else if (dpi < 168) { + index = 2; + } else if (dpi < 192) { + index = 3; + } else { + index = 4; + } + + return resources[index]; +} + +const std::vector CMPCThemeUtil::getIconPathByDPI(CWnd* wnd, WPARAM buttonType) { + DpiHelper dpiWindow; + dpiWindow.Override(wnd->GetSafeHwnd()); + + int dpi = dpiWindow.DPIX(); + switch (buttonType) { + case SC_MINIMIZE: + if (dpi < 120) { + return CMPCTheme::minimizeIcon96; + } else if (dpi < 144) { + return CMPCTheme::minimizeIcon120; + } else if (dpi < 168) { + return CMPCTheme::minimizeIcon144; + } else if (dpi < 192) { + return CMPCTheme::minimizeIcon168; + } else { + return CMPCTheme::minimizeIcon192; + } + case SC_RESTORE: + if (dpi < 120) { + return CMPCTheme::restoreIcon96; + } else if (dpi < 144) { + return CMPCTheme::restoreIcon120; + } else if (dpi < 168) { + return CMPCTheme::restoreIcon144; + } else if (dpi < 192) { + return CMPCTheme::restoreIcon168; + } else { + return CMPCTheme::restoreIcon192; + } + case SC_MAXIMIZE: + if (dpi < 120) { + return CMPCTheme::maximizeIcon96; + } else if (dpi < 144) { + return CMPCTheme::maximizeIcon120; + } else if (dpi < 168) { + return CMPCTheme::maximizeIcon144; + } else if (dpi < 192) { + return CMPCTheme::maximizeIcon168; + } else { + return CMPCTheme::maximizeIcon192; + } + case TOOLBAR_HIDE_ICON: + if (dpi < 120) { + return CMPCTheme::hideIcon96; + } else if (dpi < 144) { + return CMPCTheme::hideIcon120; + } else if (dpi < 168) { + return CMPCTheme::hideIcon144; + } else if (dpi < 192) { + return CMPCTheme::hideIcon168; + } else { + return CMPCTheme::hideIcon192; + } + case SC_CLOSE: + default: + if (dpi < 120) { + return CMPCTheme::closeIcon96; + } else if (dpi < 144) { + return CMPCTheme::closeIcon120; + } else if (dpi < 168) { + return CMPCTheme::closeIcon144; + } else if (dpi < 192) { + return CMPCTheme::closeIcon168; + } else { + return CMPCTheme::closeIcon192; + } + } +} + +//MapDialogRect deficiencies: +// 1. Caches results for windows even after they receive a DPI change +// 2. for templateless dialogs (e.g., MessageBoxDialog.cpp), the caching requires a reboot to fix +// 3. Does not honor selected font +// 4. For PropSheet, always uses "MS Shell Dlg" no matter what the sheet has selected in the .rc +void CMPCThemeUtil::MapDialogRect2(CDialog* wnd, CRect& r) { + CDC* pDC; + if (wnd && (pDC = wnd->GetDC())) { + CFont msgFont; + if (!getFontByType(msgFont, wnd, CMPCThemeUtil::MessageFont)) { + //if (!getFontByFace(msgFont, wnd, L"MS Shell Dlg", 9)){ + return; + } + + CFont* oldFont = pDC->SelectObject(&msgFont); + + //average character dimensions: https://web.archive.org/web/20131208002908/http://support.microsoft.com/kb/125681 + TEXTMETRICW tm; + SIZE size; + pDC->GetTextMetricsW(&tm); + GetTextExtentPoint32W(pDC->GetSafeHdc(), L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size); + pDC->SelectObject(oldFont); + int avgWidth = (size.cx / 26 + 1) / 2; + int avgHeight = (WORD)tm.tmHeight; + + //MapDialogRect definition: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapdialogrect + r.left = MulDiv(r.left, avgWidth, 4); + r.right = MulDiv(r.right, avgWidth, 4); + r.top = MulDiv(r.top, avgHeight, 8); + r.bottom = MulDiv(r.bottom, avgHeight, 8); + } +} + +const std::vector CMPCThemeUtil::getIconPathByDPI(CMPCThemeTitleBarControlButton* button) +{ + return getIconPathByDPI(button, button->getButtonType()); +} + +void CMPCThemeUtil::drawToolbarHideButton(CDC* pDC, CWnd* window, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias, bool hover) { + int iconWidth = CMPCThemeUtil::getConstantByDPI(window, CMPCTheme::ToolbarIconPathDimension); + int iconHeight = iconWidth; + float penThickness = 1; + CPoint ul(iconRect.left + (iconRect.Width() - iconWidth) / 2, iconRect.top + (iconRect.Height() - iconHeight) / 2); + CRect pathRect = { + ul.x, + ul.y, + ul.x + iconWidth, + ul.y + iconHeight + }; + + Gdiplus::Graphics gfx(pDC->m_hDC); + if (antiAlias) { + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x8); + } + Gdiplus::Color lineClr; + + if (hover) { //draw like a win10 icon + lineClr.SetFromCOLORREF(CMPCTheme::W10DarkThemeTitlebarIconPenColor); + } else { //draw in fg color as there is no button bg + lineClr.SetFromCOLORREF(CMPCTheme::TextFGColor); + } + Gdiplus::Pen iPen(lineClr, penThickness); + if (penThickness >= 2) { + iPen.SetLineCap(Gdiplus::LineCapSquare, Gdiplus::LineCapSquare, Gdiplus::DashCapFlat); + } + Gdiplus::REAL lastX = 0, lastY = 0; + for (u_int i = 0; i < icon.size(); i++) { + CMPCTheme::pathPoint p = icon[i]; + Gdiplus::REAL x = (Gdiplus::REAL)(pathRect.left + p.x); + Gdiplus::REAL y = (Gdiplus::REAL)(pathRect.top + p.y); + if (p.state == CMPCTheme::newPath) { + lastX = x; + lastY = y; + } else if ((p.state == CMPCTheme::linePath || p.state == CMPCTheme::closePath) && i > 0) { + gfx.DrawLine(&iPen, lastX, lastY, x, y); + if (antiAlias && penThickness < 2) { + gfx.DrawLine(&iPen, lastX, lastY, x, y); //draw again to brighten the AA diagonals + } + lastX = x; + lastY = y; + } + } +} + +void CMPCThemeUtil::drawGripper(CWnd* window, CWnd* dpiRefWnd, CRect rectGripper, CDC* pDC, bool rot90) { + CPngImage image; + image.Load(getResourceByDPI(dpiRefWnd, pDC, CMPCTheme::ThemeGrippers), AfxGetInstanceHandle()); + CImage gripperTemplate, gripperColorized; + gripperTemplate.Attach((HBITMAP)image.Detach()); + ImageGrayer::Colorize(gripperTemplate, gripperColorized, CMPCTheme::GripperPatternColor, CMPCTheme::WindowBGColor, rot90); + + CDC mDC; + mDC.CreateCompatibleDC(pDC); + mDC.SelectObject(gripperColorized); + + CDC dcMem; + CBitmap bmMem; + initMemDC(pDC, dcMem, bmMem, rectGripper); + if (rot90) { + for (int a = 0; a < rectGripper.Height(); a += gripperColorized.GetHeight()) { + dcMem.BitBlt(0, a, gripperColorized.GetWidth(), gripperColorized.GetHeight(), &mDC, 0, 0, SRCCOPY); + } + } else { + for (int a = 0; a < rectGripper.Width(); a += gripperColorized.GetWidth()) { + dcMem.BitBlt(a, 0, gripperColorized.GetWidth(), gripperColorized.GetHeight(), &mDC, 0, 0, SRCCOPY); + } + } + flushMemDC(pDC, dcMem, rectGripper); +} + + +void CMPCThemeUtil::drawCheckBox(CWnd* window, UINT checkState, bool isHover, bool useSystemSize, CRect rectCheck, CDC* pDC, bool isRadio) +{ + COLORREF borderClr, bgClr; + COLORREF oldBkClr = pDC->GetBkColor(), oldTextClr = pDC->GetTextColor(); + if (isHover) { + borderClr = CMPCTheme::CheckboxBorderHoverColor; + bgClr = CMPCTheme::CheckboxBGHoverColor; + } else { + borderClr = CMPCTheme::CheckboxBorderColor; + bgClr = CMPCTheme::CheckboxBGColor; + } + + if (useSystemSize) { + CPngImage image; + image.Load(getResourceByDPI(window, pDC, isRadio ? CMPCTheme::ThemeRadios : CMPCTheme::ThemeCheckBoxes), AfxGetInstanceHandle()); + BITMAP bm; + image.GetBitmap(&bm); + int size = bm.bmHeight; + + CDC mDC; + mDC.CreateCompatibleDC(pDC); + mDC.SelectObject(image); + int index; + if (isRadio) { + index = RadioRegular; + if (checkState) { + index += 1; + } + if (isHover) { + index += 2; + } + } else { + index = CheckBoxRegular; + if (isHover) { + index += 1; + } + } + CRect drawRect(0, 0, size, size); + //drawRect.OffsetRect(rectCheck.left + (rectCheck.Width() - size) / 2, rectCheck.top + (rectCheck.Height() - size) / 2); + drawRect.OffsetRect(rectCheck.left, rectCheck.top + (rectCheck.Height() - size) / 2); + + if (!isRadio && checkState != BST_CHECKED) { //we can draw this w/o BMPs + CBrush brush(borderClr); + pDC->FrameRect(drawRect, &brush); + drawRect.DeflateRect(1, 1); + pDC->FillSolidRect(drawRect, bgClr); + if (checkState == BST_INDETERMINATE) { + drawRect.DeflateRect(2, 2); + pDC->FillSolidRect(drawRect, CMPCTheme::CheckColor); + } + } else { + int left = index * size; + pDC->BitBlt(drawRect.left, drawRect.top, drawRect.Width(), drawRect.Height(), &mDC, left, 0, SRCCOPY); + } + } else { + CBrush brush(borderClr); + pDC->FrameRect(rectCheck, &brush); + rectCheck.DeflateRect(1, 1); + pDC->FillSolidRect(rectCheck, bgClr); + if (BST_CHECKED == checkState) { + CBitmap checkBMP; + CDC dcCheckBMP; + dcCheckBMP.CreateCompatibleDC(pDC); + + int left, top, width, height; + width = CMPCTheme::CheckWidth; + height = CMPCTheme::CheckHeight; + left = rectCheck.left + (rectCheck.Width() - width) / 2; + top = rectCheck.top + (rectCheck.Height() - height) / 2; + checkBMP.CreateBitmap(width, height, 1, 1, CMPCTheme::CheckBits); + dcCheckBMP.SelectObject(&checkBMP); + + pDC->SetBkColor(CMPCTheme::CheckColor); + pDC->SetTextColor(bgClr); + pDC->BitBlt(left, top, width, height, &dcCheckBMP, 0, 0, SRCCOPY); + } else if (BST_INDETERMINATE == checkState) { + rectCheck.DeflateRect(2, 2); + pDC->FillSolidRect(rectCheck, CMPCTheme::CheckColor); + } + } + pDC->SetBkColor(oldBkClr); + pDC->SetTextColor(oldTextClr); +} + +bool CMPCThemeUtil::canUseWin10DarkTheme() +{ + if (AppNeedsThemedControls()) { + // return false; //FIXME. return false to test behavior for OS < Win10 1809 + RTL_OSVERSIONINFOW osvi = GetRealOSVersion(); + bool ret = (osvi.dwMajorVersion = 10 && osvi.dwMajorVersion >= 0 && osvi.dwBuildNumber >= 17763); //dark theme first available in win 10 1809 + return ret; + } + return false; +} + +UINT CMPCThemeUtil::defaultLogo() +{ + return IDF_LOGO4; +} + +struct AFX_CTLCOLOR { + HWND hWnd; + HDC hDC; + UINT nCtlType; +}; + +HBRUSH CMPCThemeUtil::getParentDialogBGClr(CWnd* wnd, CDC* pDC) { + WPARAM w = (WPARAM)pDC; + AFX_CTLCOLOR ctl; + ctl.hWnd = wnd->GetSafeHwnd(); + ctl.nCtlType = CTLCOLOR_DLG; + ctl.hDC = pDC->GetSafeHdc(); + CWnd* parent = wnd->GetParent(); + if (nullptr == parent) { + parent = wnd; + } + HBRUSH bg = (HBRUSH)parent->SendMessage(WM_CTLCOLORDLG, w, (LPARAM)&ctl); + return bg; +} + +void CMPCThemeUtil::drawParentDialogBGClr(CWnd* wnd, CDC* pDC, CRect r, bool fill) +{ + CBrush brush; + HBRUSH bg = getParentDialogBGClr(wnd, pDC); + brush.Attach(bg); + if (fill) { + pDC->FillRect(r, &brush); + } else { + pDC->FrameRect(r, &brush); + } + brush.Detach(); +} + +void CMPCThemeUtil::fulfillThemeReqs(CProgressCtrl* ctl) +{ + if (AppIsThemeLoaded()) { + SetWindowTheme(ctl->GetSafeHwnd(), _T(""), _T("")); + ctl->SetBarColor(CMPCTheme::ProgressBarColor); + ctl->SetBkColor(CMPCTheme::ProgressBarBGColor); + } + ctl->UpdateWindow(); +} + +void CMPCThemeUtil::enableWindows10DarkFrame(CWnd* window) +{ + if (canUseWin10DarkTheme()) { + HMODULE hUser = GetModuleHandleA("user32.dll"); + if (hUser) { + pfnSetWindowCompositionAttribute setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(hUser, "SetWindowCompositionAttribute"); + if (setWindowCompositionAttribute) { + ACCENT_POLICY accent = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 }; + WINDOWCOMPOSITIONATTRIBDATA data; + data.Attrib = WCA_USEDARKMODECOLORS; + data.pvData = &accent; + data.cbData = sizeof(accent); + setWindowCompositionAttribute(window->GetSafeHwnd(), &data); + } + } + } +} + +int CALLBACK PropSheetCallBackRTL(HWND hWnd, UINT message, LPARAM lParam) { + switch (message) { + case PSCB_PRECREATE: + { + //arabic or hebrew + if (Translations::IsLangRTL(AfxGetAppSettings().language)) { + LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam; + lpTemplate->dwExtendedStyle |= WS_EX_LAYOUTRTL; + } + } + break; + } + return 0; +} + +void CMPCThemeUtil::PreDoModalRTL(LPPROPSHEETHEADERW m_psh) { + //see RTLWindowsLayoutCbtFilterHook and Translations::SetLanguage. + //We handle here to avoid Windows 11 bug with SetWindowLongPtr + m_psh->dwFlags |= PSH_USECALLBACK; + m_psh->pfnCallback = PropSheetCallBackRTL; +} + +//Regions are relative to upper left of WINDOW rect (not client) +CPoint CMPCThemeUtil::GetRegionOffset(CWnd* window) { + CRect twr, tcr; + window->GetWindowRect(twr); + window->GetClientRect(tcr); + ::MapWindowPoints(window->GetSafeHwnd(), nullptr, (LPPOINT)&tcr, 2); + CPoint offset = tcr.TopLeft() - twr.TopLeft(); + return offset; +} + +void CMPCThemeUtil::AdjustDynamicWidgetPair(CWnd* window, int leftWidget, int rightWidget, WidgetPairType lType, WidgetPairType rType) { + if (window && IsWindow(window->m_hWnd)) { + DpiHelper dpiWindow; + dpiWindow.Override(window->GetSafeHwnd()); + LONG dynamicSpace = dpiWindow.ScaleX(5); + + + + CWnd* leftW = window->GetDlgItem(leftWidget); + CWnd* rightW = window->GetDlgItem(rightWidget); + + WidgetPairType ll = lType; + WidgetPairType rr = rType; + + if (true || lType == WidgetPairAuto) { + LRESULT lRes = leftW->SendMessage(WM_GETDLGCODE, 0, 0); + DWORD buttonType = (leftW->GetStyle() & BS_TYPEMASK); + + if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX)) { + lType = WidgetPairCheckBox; + } else { //we only support checkbox or text on the left, just assume it's text now + lType = WidgetPairText; + } + } + + if (true || rType == WidgetPairAuto) { + TCHAR windowClass[MAX_PATH]; + ::GetClassName(rightW->GetSafeHwnd(), windowClass, _countof(windowClass)); + + if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { + rType = WidgetPairCombo; + } else { //we only support combo or edit on the right, just assume it's edit now + rType = WidgetPairEdit; + } + } + + if (leftW && rightW && IsWindow(leftW->m_hWnd) && IsWindow(rightW->m_hWnd)) { + CRect l, r; + LONG leftWantsRight, rightWantsLeft; + + leftW->GetWindowRect(l); + leftW->GetOwner()->ScreenToClient(l); + rightW->GetWindowRect(r); + rightW->GetOwner()->ScreenToClient(r); + CDC* lpDC = leftW->GetDC(); + CFont* pFont = leftW->GetFont(); + leftWantsRight = l.right; + rightWantsLeft = r.left; + { + int left = l.left; + if (lType == WidgetPairCheckBox) { + left += dpiWindow.GetSystemMetricsDPI(SM_CXMENUCHECK) + 2; + } + + CFont* pOldFont = lpDC->SelectObject(pFont); + TEXTMETRIC tm; + lpDC->GetTextMetricsW(&tm); + + CString str; + leftW->GetWindowTextW(str); + CSize szText = lpDC->GetTextExtent(str); + lpDC->SelectObject(pOldFont); + + leftWantsRight = left + szText.cx + tm.tmAveCharWidth; + leftW->ReleaseDC(lpDC); + } + + { + if (rType == WidgetPairCombo) { + //int wantWidth = (int)::SendMessage(rightW->m_hWnd, CB_GETDROPPEDWIDTH, 0, 0); + CComboBox *cb = DYNAMIC_DOWNCAST(CComboBox, rightW); + if (cb) { + int wantWidth = CorrectComboListWidth(*cb); + if (wantWidth != CB_ERR) { + rightWantsLeft = r.right - wantWidth - GetSystemMetrics(SM_CXVSCROLL); + } + } + } + } + CRect cl = l, cr = r; + if (leftWantsRight > rightWantsLeft - dynamicSpace //overlaps; we will assume defaults are best + || (leftWantsRight < l.right && rightWantsLeft > r.left) // there is no need to resize + || (lType == WidgetPairText && DT_RIGHT == (leftW->GetStyle() & DT_RIGHT)) ) //right aligned text not supported, as the right edge is fixed + { + //do nothing + } else { + l.right = leftWantsRight; + //if necessary space would shrink the right widget, instead get as close to original size as possible + //this minimizes noticeable layout changes + r.left = std::min(rightWantsLeft, std::max(l.right + dynamicSpace, r.left)); + } + if ((lType == WidgetPairText || lType == WidgetPairCheckBox) && (rType == WidgetPairCombo || rType == WidgetPairEdit)) { + l.top = r.top; + l.bottom += r.Height() - l.Height(); + leftW->ModifyStyle(0, SS_CENTERIMAGE); + } + + if (l != cl) { + leftW->MoveWindow(l); + } + if (r != cr) { + rightW->MoveWindow(r); + } + } + } +} + +void CMPCThemeUtil::UpdateAnalogCaptureDeviceSlider(CScrollBar* pScrollBar) { + if (pScrollBar && ::IsWindow(pScrollBar->m_hWnd)) { + if (CSliderCtrl* slider = DYNAMIC_DOWNCAST(CSliderCtrl, pScrollBar)) { + slider->SendMessage(WM_KEYUP, VK_LEFT, 1); //does not move the slider, only forces current position to be registered + } + } +} + +bool CMPCThemeUtil::IsWindowVisibleAndRendered(CWnd* window) { + if (!window || !IsWindow(window->m_hWnd) || !window->IsWindowVisible()) { + return false; + } else { + CRect r; + HDC hdc = GetWindowDC(window->m_hWnd); + GetClipBox(hdc, &r); + if (r.IsRectEmpty()) { + return false; + } + } + return true; +} diff --git a/src/mpc-hc/CMPCThemeUtil.h b/src/mpc-hc/CMPCThemeUtil.h index cfd45d5fe1a..ae83776a717 100644 --- a/src/mpc-hc/CMPCThemeUtil.h +++ b/src/mpc-hc/CMPCThemeUtil.h @@ -1,135 +1,135 @@ -#pragma once -#include -#include -#include -#include -#include "CMPCTheme.h" -#include "CMPCThemeToolTipCtrl.h" - -#define TOOLBAR_HIDE_ICON 0xF900 - -class CMPCThemeTitleBarControlButton; -int CALLBACK PropSheetCallBackRTL(HWND hWnd, UINT message, LPARAM lParam); - -class CMPCThemeUtil -{ -public: - enum SpecialThemeCases { - NoSpecialCase = 0, - ExternalPropertyPageWithDefaultButton, - ExternalPropertyPageWithAnalogCaptureSliders, - ToolbarCustomizeDialog - }; - - enum WidgetPairType { - WidgetPairAuto = 0 - , WidgetPairCheckBox - , WidgetPairCombo - , WidgetPairText - , WidgetPairEdit - }; - - CMPCThemeUtil(); - virtual ~CMPCThemeUtil(); - - static bool ModifyTemplates(CPropertySheet* sheet, CRuntimeClass* pageClass, DWORD id, DWORD addStyle, DWORD removeStyle = 0); - - - static HBRUSH getCtlColorFileDialog(HDC hDC, UINT nCtlColor); - static HBRUSH getCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - static bool MPCThemeEraseBkgnd(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - - enum FileDialogWidgetSearch { - RecurseSinkWidgets - ,ThemeAllChildren - ,ProminentControlIDWidget - }; - - HWND themableDialogHandle = nullptr; - void enableFileDialogHook(); - void subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType); - void subClassFileDialog(CWnd* wnd); - void subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass); - void redrawAllThemedWidgets(); - void subClassTBCustomizeDialog(CWnd* wnd, CToolBar* tb); -protected: - int dialogProminentControlStringID = 0; - - static CBrush contentBrush, windowBrush, controlAreaBrush, W10DarkThemeFileDialogInjectedBGBrush; - static NONCLIENTMETRICS nonClientMetrics; - std::vector allocatedWindows; - - void fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase, CWnd* otherWindow = nullptr); - static void initHelperObjects(); - void makeThemed(CWnd* pObject, CWnd* tChild); - - //replaces tooltip from EnableTooltips() - CMPCThemeToolTipCtrl themedDialogToolTip; - CDialog* themedDialogToolTipParent; - void EnableThemedDialogTooltips(CDialog* wnd); - void PlaceThemedDialogTooltip(UINT_PTR nID); - void RelayThemedDialogTooltip(MSG* pMsg); - void RedrawDialogTooltipIfVisible(); - static bool metricsNeedCalculation; -public: - static bool getFontByFace(CFont& font, CWnd *wnd, wchar_t* fontName, int size, LONG weight = FW_REGULAR); - static bool getFixedFont(CFont& font, CDC* pDC, CWnd* wnd); - static bool getFontByType(CFont& font, CWnd* wnd, int type, bool underline = false, bool bold = false); - enum fontType { - CaptionFont, - SmallCaptionFont, - MenuFont, - StatusFont, - MessageFont, - DialogFont, - }; - - static CSize GetTextSize(CString str, HDC hDC, CFont* font); - static CSize GetTextSize(CString str, CDC* pDC, CFont* font); - static CSize GetTextSize(CString str, HDC hDC, CWnd* wnd, int type); - static CSize GetTextSizeDiff(CString str, HDC hDC, CWnd* wnd, int type, CFont* curFont); - - - static void GetMetrics(bool reset = false); - static void initMemDC(CDC* pDC, CDC& dcMem, CBitmap& bmMem, CRect rect); - static void flushMemDC(CDC* pDC, CDC& dcMem, CRect rect); - static void DrawBufferedText(CDC* pDC, CString text, CRect rect, UINT format); - static void Draw2BitTransparent(CDC& dc, int left, int top, int width, int height, CBitmap& bmp, COLORREF fgColor); - static void dbg(CString text, ...); - static float getConstantFByDPI(CWnd* window, const float* constants); - static int getConstantByDPI(CWnd* window, const int* constants); - static UINT getResourceByDPI(CWnd* window, CDC* pDC, const UINT* resources); - static void MapDialogRect2(CDialog* wnd, CRect& r); - static const std::vector getIconPathByDPI(CMPCThemeTitleBarControlButton* button); - static const std::vector getIconPathByDPI(CWnd* wnd, WPARAM buttonType); - static void drawCheckBox(CWnd* window, UINT checkState, bool isHover, bool useSystemSize, CRect rectCheck, CDC* pDC, bool isRadio = false); - static void drawGripper(CWnd* window, CWnd* dpiRefWnd, CRect rectGripper, CDC* pDC, bool rot90); - static void drawToolbarHideButton(CDC* pDC, CWnd* window, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias, bool hover); - static bool canUseWin10DarkTheme(); - static UINT defaultLogo(); - static HBRUSH getParentDialogBGClr(CWnd* wnd, CDC* pDC); - static void drawParentDialogBGClr(CWnd* wnd, CDC* pDC, CRect r, bool fill = true); - static void fulfillThemeReqs(CProgressCtrl* ctl); - static void enableWindows10DarkFrame(CWnd* window); - static void AdjustDynamicWidgetPair(CWnd* window, int left, int right, WidgetPairType lType = WidgetPairAuto, WidgetPairType rType = WidgetPairAuto); - static void UpdateAnalogCaptureDeviceSlider(CScrollBar* pScrollBar); - static bool IsWindowVisibleAndRendered(CWnd* window); - - void PreDoModalRTL(LPPROPSHEETHEADERW m_psh); - - static CPoint GetRegionOffset(CWnd* window); - - enum CheckBoxStyle { - CheckBoxRegular = 0, - CheckBoxHover = 1, - }; - - enum RadioStyle { - RadioRegular = 0, - RadioRegularSet = 1, - RadioHover = 2, - RadioHoverSet = 3 - }; -}; - - +#pragma once +#include +#include +#include +#include +#include "CMPCTheme.h" +#include "CMPCThemeToolTipCtrl.h" + +#define TOOLBAR_HIDE_ICON 0xF900 + +class CMPCThemeTitleBarControlButton; +int CALLBACK PropSheetCallBackRTL(HWND hWnd, UINT message, LPARAM lParam); + +class CMPCThemeUtil +{ +public: + enum SpecialThemeCases { + NoSpecialCase = 0, + ExternalPropertyPageWithDefaultButton, + ExternalPropertyPageWithAnalogCaptureSliders, + ToolbarCustomizeDialog + }; + + enum WidgetPairType { + WidgetPairAuto = 0 + , WidgetPairCheckBox + , WidgetPairCombo + , WidgetPairText + , WidgetPairEdit + }; + + CMPCThemeUtil(); + virtual ~CMPCThemeUtil(); + + static bool ModifyTemplates(CPropertySheet* sheet, CRuntimeClass* pageClass, DWORD id, DWORD addStyle, DWORD removeStyle = 0); + + + static HBRUSH getCtlColorFileDialog(HDC hDC, UINT nCtlColor); + static HBRUSH getCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + static bool MPCThemeEraseBkgnd(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + + enum FileDialogWidgetSearch { + RecurseSinkWidgets + ,ThemeAllChildren + ,ProminentControlIDWidget + }; + + HWND themableDialogHandle = nullptr; + void enableFileDialogHook(); + void subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType); + void subClassFileDialog(CWnd* wnd); + void subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass); + void redrawAllThemedWidgets(); + void subClassTBCustomizeDialog(CWnd* wnd, CToolBar* tb); +protected: + int dialogProminentControlStringID = 0; + + static CBrush contentBrush, windowBrush, controlAreaBrush, W10DarkThemeFileDialogInjectedBGBrush; + static NONCLIENTMETRICS nonClientMetrics; + std::vector allocatedWindows; + + void fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase, CWnd* otherWindow = nullptr); + static void initHelperObjects(); + void makeThemed(CWnd* pObject, CWnd* tChild); + + //replaces tooltip from EnableTooltips() + CMPCThemeToolTipCtrl themedDialogToolTip; + CDialog* themedDialogToolTipParent; + void EnableThemedDialogTooltips(CDialog* wnd); + void PlaceThemedDialogTooltip(UINT_PTR nID); + void RelayThemedDialogTooltip(MSG* pMsg); + void RedrawDialogTooltipIfVisible(); + static bool metricsNeedCalculation; +public: + static bool getFontByFace(CFont& font, CWnd *wnd, wchar_t* fontName, int size, LONG weight = FW_REGULAR); + static bool getFixedFont(CFont& font, CDC* pDC, CWnd* wnd); + static bool getFontByType(CFont& font, CWnd* wnd, int type, bool underline = false, bool bold = false); + enum fontType { + CaptionFont, + SmallCaptionFont, + MenuFont, + StatusFont, + MessageFont, + DialogFont, + }; + + static CSize GetTextSize(CString str, HDC hDC, CFont* font); + static CSize GetTextSize(CString str, CDC* pDC, CFont* font); + static CSize GetTextSize(CString str, HDC hDC, CWnd* wnd, int type); + static CSize GetTextSizeDiff(CString str, HDC hDC, CWnd* wnd, int type, CFont* curFont); + + + static void GetMetrics(bool reset = false); + static void initMemDC(CDC* pDC, CDC& dcMem, CBitmap& bmMem, CRect rect); + static void flushMemDC(CDC* pDC, CDC& dcMem, CRect rect); + static void DrawBufferedText(CDC* pDC, CString text, CRect rect, UINT format); + static void Draw2BitTransparent(CDC& dc, int left, int top, int width, int height, CBitmap& bmp, COLORREF fgColor); + static void dbg(CString text, ...); + static float getConstantFByDPI(CWnd* window, const float* constants); + static int getConstantByDPI(CWnd* window, const int* constants); + static UINT getResourceByDPI(CWnd* window, CDC* pDC, const UINT* resources); + static void MapDialogRect2(CDialog* wnd, CRect& r); + static const std::vector getIconPathByDPI(CMPCThemeTitleBarControlButton* button); + static const std::vector getIconPathByDPI(CWnd* wnd, WPARAM buttonType); + static void drawCheckBox(CWnd* window, UINT checkState, bool isHover, bool useSystemSize, CRect rectCheck, CDC* pDC, bool isRadio = false); + static void drawGripper(CWnd* window, CWnd* dpiRefWnd, CRect rectGripper, CDC* pDC, bool rot90); + static void drawToolbarHideButton(CDC* pDC, CWnd* window, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias, bool hover); + static bool canUseWin10DarkTheme(); + static UINT defaultLogo(); + static HBRUSH getParentDialogBGClr(CWnd* wnd, CDC* pDC); + static void drawParentDialogBGClr(CWnd* wnd, CDC* pDC, CRect r, bool fill = true); + static void fulfillThemeReqs(CProgressCtrl* ctl); + static void enableWindows10DarkFrame(CWnd* window); + static void AdjustDynamicWidgetPair(CWnd* window, int left, int right, WidgetPairType lType = WidgetPairAuto, WidgetPairType rType = WidgetPairAuto); + static void UpdateAnalogCaptureDeviceSlider(CScrollBar* pScrollBar); + static bool IsWindowVisibleAndRendered(CWnd* window); + + void PreDoModalRTL(LPPROPSHEETHEADERW m_psh); + + static CPoint GetRegionOffset(CWnd* window); + + enum CheckBoxStyle { + CheckBoxRegular = 0, + CheckBoxHover = 1, + }; + + enum RadioStyle { + RadioRegular = 0, + RadioRegularSet = 1, + RadioHover = 2, + RadioHoverSet = 3 + }; +}; + + diff --git a/src/mpc-hc/CMPCThemeWin10Api.h b/src/mpc-hc/CMPCThemeWin10Api.h index 6a925ef9ae3..bc8f008835b 100644 --- a/src/mpc-hc/CMPCThemeWin10Api.h +++ b/src/mpc-hc/CMPCThemeWin10Api.h @@ -1,60 +1,60 @@ -#pragma once - -typedef enum _WINDOWCOMPOSITIONATTRIB { - WCA_UNDEFINED = 0, - WCA_NCRENDERING_ENABLED = 1, - WCA_NCRENDERING_POLICY = 2, - WCA_TRANSITIONS_FORCEDISABLED = 3, - WCA_ALLOW_NCPAINT = 4, - WCA_CAPTION_BUTTON_BOUNDS = 5, - WCA_NONCLIENT_RTL_LAYOUT = 6, - WCA_FORCE_ICONIC_REPRESENTATION = 7, - WCA_EXTENDED_FRAME_BOUNDS = 8, - WCA_HAS_ICONIC_BITMAP = 9, - WCA_THEME_ATTRIBUTES = 10, - WCA_NCRENDERING_EXILED = 11, - WCA_NCADORNMENTINFO = 12, - WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, - WCA_VIDEO_OVERLAY_ACTIVE = 14, - WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, - WCA_DISALLOW_PEEK = 16, - WCA_CLOAK = 17, - WCA_CLOAKED = 18, - WCA_ACCENT_POLICY = 19, - WCA_FREEZE_REPRESENTATION = 20, - WCA_EVER_UNCLOAKED = 21, - WCA_VISUAL_OWNER = 22, - WCA_HOLOGRAPHIC = 23, - WCA_EXCLUDED_FROM_DDA = 24, - WCA_PASSIVEUPDATEMODE = 25, - WCA_USEDARKMODECOLORS = 26, - WCA_LAST = 27 -} WINDOWCOMPOSITIONATTRIB; - -typedef struct _WINDOWCOMPOSITIONATTRIBDATA { - WINDOWCOMPOSITIONATTRIB Attrib; - PVOID pvData; - SIZE_T cbData; -} WINDOWCOMPOSITIONATTRIBDATA; - -typedef enum _ACCENT_STATE { - ACCENT_DISABLED = 0, - ACCENT_ENABLE_GRADIENT = 1, - ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, - ACCENT_ENABLE_BLURBEHIND = 3, - ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803 - ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809 - ACCENT_INVALID_STATE = 6 -} ACCENT_STATE; - -typedef struct _ACCENT_POLICY { - ACCENT_STATE AccentState; - DWORD AccentFlags; - DWORD GradientColor; - DWORD AnimationId; -} ACCENT_POLICY; - -typedef BOOL(WINAPI* pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); - -typedef BOOL(WINAPI* pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); - +#pragma once + +typedef enum _WINDOWCOMPOSITIONATTRIB { + WCA_UNDEFINED = 0, + WCA_NCRENDERING_ENABLED = 1, + WCA_NCRENDERING_POLICY = 2, + WCA_TRANSITIONS_FORCEDISABLED = 3, + WCA_ALLOW_NCPAINT = 4, + WCA_CAPTION_BUTTON_BOUNDS = 5, + WCA_NONCLIENT_RTL_LAYOUT = 6, + WCA_FORCE_ICONIC_REPRESENTATION = 7, + WCA_EXTENDED_FRAME_BOUNDS = 8, + WCA_HAS_ICONIC_BITMAP = 9, + WCA_THEME_ATTRIBUTES = 10, + WCA_NCRENDERING_EXILED = 11, + WCA_NCADORNMENTINFO = 12, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, + WCA_VIDEO_OVERLAY_ACTIVE = 14, + WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, + WCA_DISALLOW_PEEK = 16, + WCA_CLOAK = 17, + WCA_CLOAKED = 18, + WCA_ACCENT_POLICY = 19, + WCA_FREEZE_REPRESENTATION = 20, + WCA_EVER_UNCLOAKED = 21, + WCA_VISUAL_OWNER = 22, + WCA_HOLOGRAPHIC = 23, + WCA_EXCLUDED_FROM_DDA = 24, + WCA_PASSIVEUPDATEMODE = 25, + WCA_USEDARKMODECOLORS = 26, + WCA_LAST = 27 +} WINDOWCOMPOSITIONATTRIB; + +typedef struct _WINDOWCOMPOSITIONATTRIBDATA { + WINDOWCOMPOSITIONATTRIB Attrib; + PVOID pvData; + SIZE_T cbData; +} WINDOWCOMPOSITIONATTRIBDATA; + +typedef enum _ACCENT_STATE { + ACCENT_DISABLED = 0, + ACCENT_ENABLE_GRADIENT = 1, + ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, + ACCENT_ENABLE_BLURBEHIND = 3, + ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803 + ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809 + ACCENT_INVALID_STATE = 6 +} ACCENT_STATE; + +typedef struct _ACCENT_POLICY { + ACCENT_STATE AccentState; + DWORD AccentFlags; + DWORD GradientColor; + DWORD AnimationId; +} ACCENT_POLICY; + +typedef BOOL(WINAPI* pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); + +typedef BOOL(WINAPI* pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); + diff --git a/src/mpc-hc/CShockwaveFlash.cpp b/src/mpc-hc/CShockwaveFlash.cpp index 538799df1dc..aa1286d45e3 100644 --- a/src/mpc-hc/CShockwaveFlash.cpp +++ b/src/mpc-hc/CShockwaveFlash.cpp @@ -1,29 +1,29 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "CShockwaveFlash.h" - - -///////////////////////////////////////////////////////////////////////////// -// CShockwaveFlash - -IMPLEMENT_DYNCREATE(CShockwaveFlash, CWnd) +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "CShockwaveFlash.h" + + +///////////////////////////////////////////////////////////////////////////// +// CShockwaveFlash + +IMPLEMENT_DYNCREATE(CShockwaveFlash, CWnd) diff --git a/src/mpc-hc/CShockwaveFlash.h b/src/mpc-hc/CShockwaveFlash.h index ed89145c230..4864542430b 100644 --- a/src/mpc-hc/CShockwaveFlash.h +++ b/src/mpc-hc/CShockwaveFlash.h @@ -1,383 +1,383 @@ -/* - * (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 . - * - */ - -#pragma once - -///////////////////////////////////////////////////////////////////////////// -// CShockwaveFlash - -class CShockwaveFlash : public CWnd -{ -protected: - DECLARE_DYNCREATE(CShockwaveFlash) -public: - CLSID const& GetClsid() { - static CLSID const clsid - = { 0xD27CDB6E, 0xAE6D, 0x11CF, { 0x96, 0xB8, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } }; - return clsid; - } - virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, - const RECT& rect, CWnd* pParentWnd, UINT nID, - CCreateContext* pContext = nullptr) { - return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); - } - - BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, - UINT nID, CFile* pPersist = nullptr, BOOL bStorage = FALSE, - BSTR bstrLicKey = nullptr) { - return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID, - pPersist, bStorage, bstrLicKey); - } - - // Attributes -public: - - // Operations -public: - - long get_ReadyState() { - long result; - InvokeHelper(DISPID_READYSTATE, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - long get_TotalFrames() { - long result; - InvokeHelper(0x7c, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - BOOL get_Playing() { - BOOL result; - InvokeHelper(0x7d, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_Playing(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x7d, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_Quality() { - long result; - InvokeHelper(0x69, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_Quality(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x69, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_ScaleMode() { - long result; - InvokeHelper(0x78, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_ScaleMode(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x78, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_AlignMode() { - long result; - InvokeHelper(0x79, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_AlignMode(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x79, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_BackgroundColor() { - long result; - InvokeHelper(0x7b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_BackgroundColor(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x7b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - BOOL get_Loop() { - BOOL result; - InvokeHelper(0x6a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_Loop(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x6a, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_Movie() { - CString result; - InvokeHelper(0x66, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_Movie(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x66, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_FrameNum() { - long result; - InvokeHelper(0x6b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_FrameNum(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x6b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - void SetZoomRect(long left, long top, long right, long bottom) { - static BYTE parms[] = VTS_I4 VTS_I4 VTS_I4 VTS_I4; - InvokeHelper(0x6d, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, left, top, right, bottom); - } - void Zoom(long factor) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x76, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, factor); - } - void Pan(long x, long y, long mode) { - static BYTE parms[] = VTS_I4 VTS_I4 VTS_I4; - InvokeHelper(0x77, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, x, y, mode); - } - void Play() { - InvokeHelper(0x70, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void Stop() { - InvokeHelper(0x71, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void Back() { - InvokeHelper(0x72, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void Forward() { - InvokeHelper(0x73, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void Rewind() { - InvokeHelper(0x74, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void StopPlay() { - InvokeHelper(0x7e, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void GotoFrame(long FrameNum) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x7f, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, FrameNum); - } - long CurrentFrame() { - long result; - InvokeHelper(0x80, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); - return result; - } - BOOL IsPlaying() { - BOOL result; - InvokeHelper(0x81, DISPATCH_METHOD, VT_BOOL, (void*)&result, nullptr); - return result; - } - long PercentLoaded() { - long result; - InvokeHelper(0x82, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); - return result; - } - BOOL FrameLoaded(long FrameNum) { - BOOL result; - static BYTE parms[] = VTS_I4; - InvokeHelper(0x83, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms, FrameNum); - return result; - } - long FlashVersion() { - long result; - InvokeHelper(0x84, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); - return result; - } - CString get_WMode() { - CString result; - InvokeHelper(0x85, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_WMode(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x85, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_SAlign() { - CString result; - InvokeHelper(0x86, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_SAlign(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x86, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - BOOL get_Menu() { - BOOL result; - InvokeHelper(0x87, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_Menu(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x87, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_Base() { - CString result; - InvokeHelper(0x88, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_Base(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x88, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_Scale() { - CString result; - InvokeHelper(0x89, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_Scale(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x89, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - BOOL get_DeviceFont() { - BOOL result; - InvokeHelper(0x8a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_DeviceFont(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x8a, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - BOOL get_EmbedMovie() { - BOOL result; - InvokeHelper(0x8b, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_EmbedMovie(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x8b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_BGColor() { - CString result; - InvokeHelper(0x8c, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_BGColor(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x8c, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_Quality2() { - CString result; - InvokeHelper(0x8d, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_Quality2(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x8d, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - void LoadMovie(long layer, LPCTSTR url) { - static BYTE parms[] = VTS_I4 VTS_BSTR; - InvokeHelper(0x8e, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, layer, url); - } - void TGotoFrame(LPCTSTR target, long FrameNum) { - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0x8f, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, FrameNum); - } - void TGotoLabel(LPCTSTR target, LPCTSTR label) { - static BYTE parms[] = VTS_BSTR VTS_BSTR; - InvokeHelper(0x90, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, label); - } - long TCurrentFrame(LPCTSTR target) { - long result; - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x91, DISPATCH_METHOD, VT_I4, (void*)&result, parms, target); - return result; - } - CString TCurrentLabel(LPCTSTR target) { - CString result; - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x92, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, target); - return result; - } - void TPlay(LPCTSTR target) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x93, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target); - } - void TStopPlay(LPCTSTR target) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x94, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target); - } - void SetVariable(LPCTSTR name, LPCTSTR value) { - static BYTE parms[] = VTS_BSTR VTS_BSTR; - InvokeHelper(0x97, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, name, value); - } - CString GetVariable(LPCTSTR name) { - CString result; - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x98, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, name); - return result; - } - void TSetProperty(LPCTSTR target, long property, LPCTSTR value) { - static BYTE parms[] = VTS_BSTR VTS_I4 VTS_BSTR; - InvokeHelper(0x99, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, property, value); - } - CString TGetProperty(LPCTSTR target, long property) { - CString result; - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0x9a, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, target, property); - return result; - } - void TCallFrame(LPCTSTR target, long FrameNum) { - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0x9b, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, FrameNum); - } - void TCallLabel(LPCTSTR target, LPCTSTR label) { - static BYTE parms[] = VTS_BSTR VTS_BSTR; - InvokeHelper(0x9c, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, label); - } - void TSetPropertyNum(LPCTSTR target, long property, double value) { - static BYTE parms[] = VTS_BSTR VTS_I4 VTS_R8; - InvokeHelper(0x9d, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, property, value); - } - double TGetPropertyNum(LPCTSTR target, long property) { - double result; - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0x9e, DISPATCH_METHOD, VT_R8, (void*)&result, parms, target, property); - return result; - } - double TGetPropertyAsNumber(LPCTSTR target, long property) { - double result; - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0xac, DISPATCH_METHOD, VT_R8, (void*)&result, parms, target, property); - return result; - } - CString get_SWRemote() { - CString result; - InvokeHelper(0x9f, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_SWRemote(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x9f, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_FlashVars() { - CString result; - InvokeHelper(0xaa, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_FlashVars(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0xaa, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_AllowScriptAccess() { - CString result; - InvokeHelper(0xab, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_AllowScriptAccess(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0xab, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - -}; +/* + * (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 . + * + */ + +#pragma once + +///////////////////////////////////////////////////////////////////////////// +// CShockwaveFlash + +class CShockwaveFlash : public CWnd +{ +protected: + DECLARE_DYNCREATE(CShockwaveFlash) +public: + CLSID const& GetClsid() { + static CLSID const clsid + = { 0xD27CDB6E, 0xAE6D, 0x11CF, { 0x96, 0xB8, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } }; + return clsid; + } + virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, UINT nID, + CCreateContext* pContext = nullptr) { + return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); + } + + BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, + UINT nID, CFile* pPersist = nullptr, BOOL bStorage = FALSE, + BSTR bstrLicKey = nullptr) { + return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID, + pPersist, bStorage, bstrLicKey); + } + + // Attributes +public: + + // Operations +public: + + long get_ReadyState() { + long result; + InvokeHelper(DISPID_READYSTATE, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + long get_TotalFrames() { + long result; + InvokeHelper(0x7c, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + BOOL get_Playing() { + BOOL result; + InvokeHelper(0x7d, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_Playing(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x7d, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_Quality() { + long result; + InvokeHelper(0x69, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_Quality(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x69, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_ScaleMode() { + long result; + InvokeHelper(0x78, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_ScaleMode(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x78, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_AlignMode() { + long result; + InvokeHelper(0x79, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_AlignMode(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x79, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_BackgroundColor() { + long result; + InvokeHelper(0x7b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_BackgroundColor(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x7b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + BOOL get_Loop() { + BOOL result; + InvokeHelper(0x6a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_Loop(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x6a, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_Movie() { + CString result; + InvokeHelper(0x66, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_Movie(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x66, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_FrameNum() { + long result; + InvokeHelper(0x6b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_FrameNum(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x6b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + void SetZoomRect(long left, long top, long right, long bottom) { + static BYTE parms[] = VTS_I4 VTS_I4 VTS_I4 VTS_I4; + InvokeHelper(0x6d, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, left, top, right, bottom); + } + void Zoom(long factor) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x76, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, factor); + } + void Pan(long x, long y, long mode) { + static BYTE parms[] = VTS_I4 VTS_I4 VTS_I4; + InvokeHelper(0x77, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, x, y, mode); + } + void Play() { + InvokeHelper(0x70, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void Stop() { + InvokeHelper(0x71, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void Back() { + InvokeHelper(0x72, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void Forward() { + InvokeHelper(0x73, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void Rewind() { + InvokeHelper(0x74, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void StopPlay() { + InvokeHelper(0x7e, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void GotoFrame(long FrameNum) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x7f, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, FrameNum); + } + long CurrentFrame() { + long result; + InvokeHelper(0x80, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); + return result; + } + BOOL IsPlaying() { + BOOL result; + InvokeHelper(0x81, DISPATCH_METHOD, VT_BOOL, (void*)&result, nullptr); + return result; + } + long PercentLoaded() { + long result; + InvokeHelper(0x82, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); + return result; + } + BOOL FrameLoaded(long FrameNum) { + BOOL result; + static BYTE parms[] = VTS_I4; + InvokeHelper(0x83, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms, FrameNum); + return result; + } + long FlashVersion() { + long result; + InvokeHelper(0x84, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); + return result; + } + CString get_WMode() { + CString result; + InvokeHelper(0x85, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_WMode(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x85, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_SAlign() { + CString result; + InvokeHelper(0x86, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_SAlign(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x86, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + BOOL get_Menu() { + BOOL result; + InvokeHelper(0x87, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_Menu(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x87, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_Base() { + CString result; + InvokeHelper(0x88, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_Base(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x88, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_Scale() { + CString result; + InvokeHelper(0x89, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_Scale(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x89, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + BOOL get_DeviceFont() { + BOOL result; + InvokeHelper(0x8a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_DeviceFont(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x8a, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + BOOL get_EmbedMovie() { + BOOL result; + InvokeHelper(0x8b, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_EmbedMovie(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x8b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_BGColor() { + CString result; + InvokeHelper(0x8c, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_BGColor(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x8c, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_Quality2() { + CString result; + InvokeHelper(0x8d, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_Quality2(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x8d, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + void LoadMovie(long layer, LPCTSTR url) { + static BYTE parms[] = VTS_I4 VTS_BSTR; + InvokeHelper(0x8e, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, layer, url); + } + void TGotoFrame(LPCTSTR target, long FrameNum) { + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0x8f, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, FrameNum); + } + void TGotoLabel(LPCTSTR target, LPCTSTR label) { + static BYTE parms[] = VTS_BSTR VTS_BSTR; + InvokeHelper(0x90, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, label); + } + long TCurrentFrame(LPCTSTR target) { + long result; + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x91, DISPATCH_METHOD, VT_I4, (void*)&result, parms, target); + return result; + } + CString TCurrentLabel(LPCTSTR target) { + CString result; + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x92, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, target); + return result; + } + void TPlay(LPCTSTR target) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x93, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target); + } + void TStopPlay(LPCTSTR target) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x94, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target); + } + void SetVariable(LPCTSTR name, LPCTSTR value) { + static BYTE parms[] = VTS_BSTR VTS_BSTR; + InvokeHelper(0x97, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, name, value); + } + CString GetVariable(LPCTSTR name) { + CString result; + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x98, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, name); + return result; + } + void TSetProperty(LPCTSTR target, long property, LPCTSTR value) { + static BYTE parms[] = VTS_BSTR VTS_I4 VTS_BSTR; + InvokeHelper(0x99, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, property, value); + } + CString TGetProperty(LPCTSTR target, long property) { + CString result; + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0x9a, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, target, property); + return result; + } + void TCallFrame(LPCTSTR target, long FrameNum) { + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0x9b, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, FrameNum); + } + void TCallLabel(LPCTSTR target, LPCTSTR label) { + static BYTE parms[] = VTS_BSTR VTS_BSTR; + InvokeHelper(0x9c, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, label); + } + void TSetPropertyNum(LPCTSTR target, long property, double value) { + static BYTE parms[] = VTS_BSTR VTS_I4 VTS_R8; + InvokeHelper(0x9d, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, property, value); + } + double TGetPropertyNum(LPCTSTR target, long property) { + double result; + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0x9e, DISPATCH_METHOD, VT_R8, (void*)&result, parms, target, property); + return result; + } + double TGetPropertyAsNumber(LPCTSTR target, long property) { + double result; + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0xac, DISPATCH_METHOD, VT_R8, (void*)&result, parms, target, property); + return result; + } + CString get_SWRemote() { + CString result; + InvokeHelper(0x9f, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_SWRemote(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x9f, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_FlashVars() { + CString result; + InvokeHelper(0xaa, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_FlashVars(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0xaa, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_AllowScriptAccess() { + CString result; + InvokeHelper(0xab, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_AllowScriptAccess(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0xab, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + +}; diff --git a/src/mpc-hc/ChildView.cpp b/src/mpc-hc/ChildView.cpp index dad9e948cf3..0e30405f295 100644 --- a/src/mpc-hc/ChildView.cpp +++ b/src/mpc-hc/ChildView.cpp @@ -1,207 +1,207 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "ChildView.h" -#include "MainFrm.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "ColorProfileUtil.h" - -CChildView::CChildView(CMainFrame* pMainFrame) - : CMouseWndWithArtView(pMainFrame) - , m_bSwitchingFullscreen(false) - , m_bFirstMedia(true) -{ - GetEventd().Connect(m_eventc, { - MpcEvent::SWITCHING_TO_FULLSCREEN, - MpcEvent::SWITCHED_TO_FULLSCREEN, - MpcEvent::SWITCHING_FROM_FULLSCREEN, - MpcEvent::SWITCHED_FROM_FULLSCREEN, - MpcEvent::MEDIA_LOADED, - }, std::bind(&CChildView::EventCallback, this, std::placeholders::_1)); -} - -CChildView::~CChildView() -{ -} - -void CChildView::EventCallback(MpcEvent ev) -{ - switch (ev) { - case MpcEvent::SWITCHING_TO_FULLSCREEN: - case MpcEvent::SWITCHING_FROM_FULLSCREEN: - m_bSwitchingFullscreen = true; - break; - case MpcEvent::SWITCHED_TO_FULLSCREEN: - case MpcEvent::SWITCHED_FROM_FULLSCREEN: - m_bSwitchingFullscreen = false; - break; - case MpcEvent::MEDIA_LOADED: - m_bFirstMedia = false; - break; - default: - ASSERT(FALSE); - } -} - -BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) -{ - if (!CWnd::PreCreateWindow(cs)) { - return FALSE; - } - - cs.style &= ~WS_BORDER; - cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, - ::LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), nullptr); - - return TRUE; -} - -BOOL CChildView::PreTranslateMessage(MSG* pMsg) -{ - // filter interactive video controls mouse messages - if (pMsg->hwnd != m_hWnd && - pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST && - m_pMainFrame->IsInteractiveVideo()) { - switch (pMsg->message) { - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - // let them through, interactive video controls will handle those - break; - case WM_MOUSEMOVE: { - // duplicate those - CPoint point(pMsg->lParam); - ::MapWindowPoints(pMsg->hwnd, m_hWnd, &point, 1); - VERIFY(PostMessage(pMsg->message, pMsg->wParam, MAKELPARAM(point.x, point.y))); - break; - } - default: { - // and handle others in this class - CPoint point(pMsg->lParam); - ::MapWindowPoints(pMsg->hwnd, m_hWnd, &point, 1); - pMsg->lParam = MAKELPARAM(point.x, point.y); - pMsg->hwnd = m_hWnd; - } - } - } - return CWnd::PreTranslateMessage(pMsg); -} - -IMPLEMENT_DYNAMIC(CChildView, CMouseWnd) - -BEGIN_MESSAGE_MAP(CChildView, CMouseWnd) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_WM_SIZE() - ON_WM_NCHITTEST() - ON_WM_NCLBUTTONDOWN() -END_MESSAGE_MAP() - -void CChildView::OnPaint() -{ - CPaintDC dc(this); - m_pMainFrame->RepaintVideo(); -} - -void CChildView::OnSize(UINT nType, int cx, int cy) -{ - __super::OnSize(nType, cx, cy); - if (!m_bSwitchingFullscreen) { - m_pMainFrame->MoveVideoWindow(); - } - m_pMainFrame->UpdateThumbnailClip(); -} - -LRESULT CChildView::OnNcHitTest(CPoint point) -{ - LRESULT ret = CWnd::OnNcHitTest(point); - if (!m_pMainFrame->IsFullScreenMainFrame() && m_pMainFrame->IsFrameLessWindow()) { - CRect rcFrame; - GetWindowRect(&rcFrame); - CRect rcClient(rcFrame); - rcClient.InflateRect(-GetSystemMetrics(SM_CXSIZEFRAME), -GetSystemMetrics(SM_CYSIZEFRAME)); - - if (rcFrame.PtInRect(point)) { - if (point.x > rcClient.right) { - if (point.y < rcClient.top) { - ret = HTTOPRIGHT; - } else if (point.y > rcClient.bottom) { - ret = HTBOTTOMRIGHT; - } else { - ret = HTRIGHT; - } - } else if (point.x < rcClient.left) { - if (point.y < rcClient.top) { - ret = HTTOPLEFT; - } else if (point.y > rcClient.bottom) { - ret = HTBOTTOMLEFT; - } else { - ret = HTLEFT; - } - } else if (point.y < rcClient.top) { - ret = HTTOP; - } else if (point.y > rcClient.bottom) { - ret = HTBOTTOM; - } - } - } - return ret; -} - -void CChildView::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - BYTE flag = 0; - switch (nHitTest) { - case HTTOP: - flag = WMSZ_TOP; - break; - case HTTOPLEFT: - flag = WMSZ_TOPLEFT; - break; - case HTTOPRIGHT: - flag = WMSZ_TOPRIGHT; - break; - case HTLEFT: - flag = WMSZ_LEFT; - break; - case HTRIGHT: - flag = WMSZ_RIGHT; - break; - case HTBOTTOM: - flag = WMSZ_BOTTOM; - break; - case HTBOTTOMLEFT: - flag = WMSZ_BOTTOMLEFT; - break; - case HTBOTTOMRIGHT: - flag = WMSZ_BOTTOMRIGHT; - break; - } - if (flag) { - m_pMainFrame->SendMessage(WM_SYSCOMMAND, SC_SIZE | flag, MAKELPARAM(point.x, point.y)); - } -} - -BOOL CChildView::OnEraseBkgnd(CDC* pDC) { - return __super::OnEraseBkgnd(pDC); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "ChildView.h" +#include "MainFrm.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "ColorProfileUtil.h" + +CChildView::CChildView(CMainFrame* pMainFrame) + : CMouseWndWithArtView(pMainFrame) + , m_bSwitchingFullscreen(false) + , m_bFirstMedia(true) +{ + GetEventd().Connect(m_eventc, { + MpcEvent::SWITCHING_TO_FULLSCREEN, + MpcEvent::SWITCHED_TO_FULLSCREEN, + MpcEvent::SWITCHING_FROM_FULLSCREEN, + MpcEvent::SWITCHED_FROM_FULLSCREEN, + MpcEvent::MEDIA_LOADED, + }, std::bind(&CChildView::EventCallback, this, std::placeholders::_1)); +} + +CChildView::~CChildView() +{ +} + +void CChildView::EventCallback(MpcEvent ev) +{ + switch (ev) { + case MpcEvent::SWITCHING_TO_FULLSCREEN: + case MpcEvent::SWITCHING_FROM_FULLSCREEN: + m_bSwitchingFullscreen = true; + break; + case MpcEvent::SWITCHED_TO_FULLSCREEN: + case MpcEvent::SWITCHED_FROM_FULLSCREEN: + m_bSwitchingFullscreen = false; + break; + case MpcEvent::MEDIA_LOADED: + m_bFirstMedia = false; + break; + default: + ASSERT(FALSE); + } +} + +BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) +{ + if (!CWnd::PreCreateWindow(cs)) { + return FALSE; + } + + cs.style &= ~WS_BORDER; + cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + ::LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), nullptr); + + return TRUE; +} + +BOOL CChildView::PreTranslateMessage(MSG* pMsg) +{ + // filter interactive video controls mouse messages + if (pMsg->hwnd != m_hWnd && + pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST && + m_pMainFrame->IsInteractiveVideo()) { + switch (pMsg->message) { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + // let them through, interactive video controls will handle those + break; + case WM_MOUSEMOVE: { + // duplicate those + CPoint point(pMsg->lParam); + ::MapWindowPoints(pMsg->hwnd, m_hWnd, &point, 1); + VERIFY(PostMessage(pMsg->message, pMsg->wParam, MAKELPARAM(point.x, point.y))); + break; + } + default: { + // and handle others in this class + CPoint point(pMsg->lParam); + ::MapWindowPoints(pMsg->hwnd, m_hWnd, &point, 1); + pMsg->lParam = MAKELPARAM(point.x, point.y); + pMsg->hwnd = m_hWnd; + } + } + } + return CWnd::PreTranslateMessage(pMsg); +} + +IMPLEMENT_DYNAMIC(CChildView, CMouseWnd) + +BEGIN_MESSAGE_MAP(CChildView, CMouseWnd) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_SIZE() + ON_WM_NCHITTEST() + ON_WM_NCLBUTTONDOWN() +END_MESSAGE_MAP() + +void CChildView::OnPaint() +{ + CPaintDC dc(this); + m_pMainFrame->RepaintVideo(); +} + +void CChildView::OnSize(UINT nType, int cx, int cy) +{ + __super::OnSize(nType, cx, cy); + if (!m_bSwitchingFullscreen) { + m_pMainFrame->MoveVideoWindow(); + } + m_pMainFrame->UpdateThumbnailClip(); +} + +LRESULT CChildView::OnNcHitTest(CPoint point) +{ + LRESULT ret = CWnd::OnNcHitTest(point); + if (!m_pMainFrame->IsFullScreenMainFrame() && m_pMainFrame->IsFrameLessWindow()) { + CRect rcFrame; + GetWindowRect(&rcFrame); + CRect rcClient(rcFrame); + rcClient.InflateRect(-GetSystemMetrics(SM_CXSIZEFRAME), -GetSystemMetrics(SM_CYSIZEFRAME)); + + if (rcFrame.PtInRect(point)) { + if (point.x > rcClient.right) { + if (point.y < rcClient.top) { + ret = HTTOPRIGHT; + } else if (point.y > rcClient.bottom) { + ret = HTBOTTOMRIGHT; + } else { + ret = HTRIGHT; + } + } else if (point.x < rcClient.left) { + if (point.y < rcClient.top) { + ret = HTTOPLEFT; + } else if (point.y > rcClient.bottom) { + ret = HTBOTTOMLEFT; + } else { + ret = HTLEFT; + } + } else if (point.y < rcClient.top) { + ret = HTTOP; + } else if (point.y > rcClient.bottom) { + ret = HTBOTTOM; + } + } + } + return ret; +} + +void CChildView::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + BYTE flag = 0; + switch (nHitTest) { + case HTTOP: + flag = WMSZ_TOP; + break; + case HTTOPLEFT: + flag = WMSZ_TOPLEFT; + break; + case HTTOPRIGHT: + flag = WMSZ_TOPRIGHT; + break; + case HTLEFT: + flag = WMSZ_LEFT; + break; + case HTRIGHT: + flag = WMSZ_RIGHT; + break; + case HTBOTTOM: + flag = WMSZ_BOTTOM; + break; + case HTBOTTOMLEFT: + flag = WMSZ_BOTTOMLEFT; + break; + case HTBOTTOMRIGHT: + flag = WMSZ_BOTTOMRIGHT; + break; + } + if (flag) { + m_pMainFrame->SendMessage(WM_SYSCOMMAND, SC_SIZE | flag, MAKELPARAM(point.x, point.y)); + } +} + +BOOL CChildView::OnEraseBkgnd(CDC* pDC) { + return __super::OnEraseBkgnd(pDC); +} diff --git a/src/mpc-hc/ChildView.h b/src/mpc-hc/ChildView.h index 577a70f885a..e01a81c629b 100644 --- a/src/mpc-hc/ChildView.h +++ b/src/mpc-hc/ChildView.h @@ -1,53 +1,53 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include "MouseWndWithArtView.h" - -class CChildView : public CMouseWndWithArtView -{ - bool m_bSwitchingFullscreen; - bool m_bFirstMedia; - - EventClient m_eventc; - - void EventCallback(MpcEvent ev); - -public: - CChildView(CMainFrame* pMainFrm); - virtual ~CChildView(); - - DECLARE_DYNAMIC(CChildView) - -protected: - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - virtual BOOL PreTranslateMessage(MSG* pMsg); - - DECLARE_MESSAGE_MAP() - - afx_msg void OnPaint(); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); -public: - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include "MouseWndWithArtView.h" + +class CChildView : public CMouseWndWithArtView +{ + bool m_bSwitchingFullscreen; + bool m_bFirstMedia; + + EventClient m_eventc; + + void EventCallback(MpcEvent ev); + +public: + CChildView(CMainFrame* pMainFrm); + virtual ~CChildView(); + + DECLARE_DYNAMIC(CChildView) + +protected: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnPaint(); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); +public: + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; diff --git a/src/mpc-hc/ColorButton.cpp b/src/mpc-hc/ColorButton.cpp index 997f539cc97..d3697608bc5 100644 --- a/src/mpc-hc/ColorButton.cpp +++ b/src/mpc-hc/ColorButton.cpp @@ -1,96 +1,96 @@ -/* - * (C) 2014 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "ColorButton.h" -#include "CMPCTheme.h" - -CColorButton::CColorButton() -{ - Initialize(); -} - -void CColorButton::SetColor(COLORREF color) -{ - if (m_color != color) { - m_color = color; - Invalidate(); - } -} - -void CColorButton::Initialize() -{ - if (m_bInitialized) { - m_penInside.DeleteObject(); - m_penBorder.DeleteObject(); - m_penBorderFocus.DeleteObject(); - } else { - m_bInitialized = true; - } - - if (AppIsThemeLoaded()) { - VERIFY(m_penInside.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::NoBorderColor)); - VERIFY(m_penBorder.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::ButtonBorderOuterColor)); - VERIFY(m_penBorderFocus.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::ButtonBorderInnerFocusedColor)); - } else { - VERIFY(m_penInside.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_BTNFACE))); - VERIFY(m_penBorder.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_BTNSHADOW))); - VERIFY(m_penBorderFocus.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_HIGHLIGHT))); - } -} - -void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - if (pDC) { - CRect rect; - GetClientRect(rect); - CPen& borderPen = (lpDrawItemStruct->itemState & ODS_FOCUS) ? m_penBorderFocus : m_penBorder; - CPen* pOldPen = pDC->SelectObject(&borderPen); - pDC->Rectangle(rect); - pDC->SelectObject(&m_penInside); - rect.DeflateRect(1, 1); - pDC->Rectangle(rect); - rect.DeflateRect(1, 1); - pDC->FillSolidRect(rect, m_color); - pDC->SelectObject(pOldPen); - } else { - ASSERT(FALSE); - } -} - -BEGIN_MESSAGE_MAP(CColorButton, CButton) - ON_WM_SETCURSOR() -END_MESSAGE_MAP() - -BOOL CColorButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) -{ - UNREFERENCED_PARAMETER(pWnd); - UNREFERENCED_PARAMETER(nHitTest); - UNREFERENCED_PARAMETER(message); - - if (IsWindowEnabled()) { - ::SetCursor(m_cursor); - return TRUE; - } - - return FALSE; -} +/* + * (C) 2014 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "ColorButton.h" +#include "CMPCTheme.h" + +CColorButton::CColorButton() +{ + Initialize(); +} + +void CColorButton::SetColor(COLORREF color) +{ + if (m_color != color) { + m_color = color; + Invalidate(); + } +} + +void CColorButton::Initialize() +{ + if (m_bInitialized) { + m_penInside.DeleteObject(); + m_penBorder.DeleteObject(); + m_penBorderFocus.DeleteObject(); + } else { + m_bInitialized = true; + } + + if (AppIsThemeLoaded()) { + VERIFY(m_penInside.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::NoBorderColor)); + VERIFY(m_penBorder.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::ButtonBorderOuterColor)); + VERIFY(m_penBorderFocus.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::ButtonBorderInnerFocusedColor)); + } else { + VERIFY(m_penInside.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_BTNFACE))); + VERIFY(m_penBorder.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_BTNSHADOW))); + VERIFY(m_penBorderFocus.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_HIGHLIGHT))); + } +} + +void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + if (pDC) { + CRect rect; + GetClientRect(rect); + CPen& borderPen = (lpDrawItemStruct->itemState & ODS_FOCUS) ? m_penBorderFocus : m_penBorder; + CPen* pOldPen = pDC->SelectObject(&borderPen); + pDC->Rectangle(rect); + pDC->SelectObject(&m_penInside); + rect.DeflateRect(1, 1); + pDC->Rectangle(rect); + rect.DeflateRect(1, 1); + pDC->FillSolidRect(rect, m_color); + pDC->SelectObject(pOldPen); + } else { + ASSERT(FALSE); + } +} + +BEGIN_MESSAGE_MAP(CColorButton, CButton) + ON_WM_SETCURSOR() +END_MESSAGE_MAP() + +BOOL CColorButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + UNREFERENCED_PARAMETER(pWnd); + UNREFERENCED_PARAMETER(nHitTest); + UNREFERENCED_PARAMETER(message); + + if (IsWindowEnabled()) { + ::SetCursor(m_cursor); + return TRUE; + } + + return FALSE; +} diff --git a/src/mpc-hc/ComPropertyPage.cpp b/src/mpc-hc/ComPropertyPage.cpp index 7ff8b3f3435..20f8962562b 100644 --- a/src/mpc-hc/ComPropertyPage.cpp +++ b/src/mpc-hc/ComPropertyPage.cpp @@ -1,104 +1,104 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "ComPropertyPage.h" -#include "ComPropertySheet.h" - - -// CComPropertyPage dialog - -IMPLEMENT_DYNAMIC(CComPropertyPage, CPropertyPage) -CComPropertyPage::CComPropertyPage(IPropertyPage* pPage) - : CPropertyPage(CComPropertyPage::IDD), m_pPage(pPage) -{ - PROPPAGEINFO ppi; - m_pPage->GetPageInfo(&ppi); - m_pPSP->pszTitle = (m_strCaption = ppi.pszTitle); - m_psp.dwFlags |= PSP_USETITLE; -} - -CComPropertyPage::~CComPropertyPage() -{ -} - -void CComPropertyPage::DoDataExchange(CDataExchange* pDX) -{ - CPropertyPage::DoDataExchange(pDX); -} - -BOOL CComPropertyPage::OnInitDialog() -{ - CPropertyPage::OnInitDialog(); - - CRect r; - PROPPAGEINFO ppi; - m_pPage->GetPageInfo(&ppi); - r = CRect(CPoint(0, 0), ppi.size); - m_pPage->Activate(m_hWnd, r, FALSE); - m_pPage->Show(SW_SHOW); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CComPropertyPage::OnDestroy() -{ - CPropertyPage::OnDestroy(); - m_pPage->Deactivate(); -} - -BOOL CComPropertyPage::OnSetActive() -{ - SetModified(S_OK == m_pPage->IsPageDirty()); - - CWnd* pParent = GetParent(); - if (pParent->IsKindOf(RUNTIME_CLASS(CComPropertySheet))) { - CComPropertySheet* pSheet = static_cast(pParent); - pSheet->OnActivated(this); - } - - return CPropertyPage::OnSetActive(); -} - -BOOL CComPropertyPage::OnKillActive() -{ - SetModified(FALSE); - return CPropertyPage::OnKillActive(); -} - - -BEGIN_MESSAGE_MAP(CComPropertyPage, CPropertyPage) - ON_WM_DESTROY() -END_MESSAGE_MAP() - - -// CComPropertyPage message handlers - -void CComPropertyPage::OnOK() -{ - if (S_OK == m_pPage->IsPageDirty()) { - m_pPage->Apply(); - } - SetModified(FALSE); - CPropertyPage::OnOK(); -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "ComPropertyPage.h" +#include "ComPropertySheet.h" + + +// CComPropertyPage dialog + +IMPLEMENT_DYNAMIC(CComPropertyPage, CPropertyPage) +CComPropertyPage::CComPropertyPage(IPropertyPage* pPage) + : CPropertyPage(CComPropertyPage::IDD), m_pPage(pPage) +{ + PROPPAGEINFO ppi; + m_pPage->GetPageInfo(&ppi); + m_pPSP->pszTitle = (m_strCaption = ppi.pszTitle); + m_psp.dwFlags |= PSP_USETITLE; +} + +CComPropertyPage::~CComPropertyPage() +{ +} + +void CComPropertyPage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); +} + +BOOL CComPropertyPage::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + + CRect r; + PROPPAGEINFO ppi; + m_pPage->GetPageInfo(&ppi); + r = CRect(CPoint(0, 0), ppi.size); + m_pPage->Activate(m_hWnd, r, FALSE); + m_pPage->Show(SW_SHOW); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CComPropertyPage::OnDestroy() +{ + CPropertyPage::OnDestroy(); + m_pPage->Deactivate(); +} + +BOOL CComPropertyPage::OnSetActive() +{ + SetModified(S_OK == m_pPage->IsPageDirty()); + + CWnd* pParent = GetParent(); + if (pParent->IsKindOf(RUNTIME_CLASS(CComPropertySheet))) { + CComPropertySheet* pSheet = static_cast(pParent); + pSheet->OnActivated(this); + } + + return CPropertyPage::OnSetActive(); +} + +BOOL CComPropertyPage::OnKillActive() +{ + SetModified(FALSE); + return CPropertyPage::OnKillActive(); +} + + +BEGIN_MESSAGE_MAP(CComPropertyPage, CPropertyPage) + ON_WM_DESTROY() +END_MESSAGE_MAP() + + +// CComPropertyPage message handlers + +void CComPropertyPage::OnOK() +{ + if (S_OK == m_pPage->IsPageDirty()) { + m_pPage->Apply(); + } + SetModified(FALSE); + CPropertyPage::OnOK(); +} diff --git a/src/mpc-hc/ComPropertyPage.h b/src/mpc-hc/ComPropertyPage.h index ead6c4e228c..6eb4e9a3d76 100644 --- a/src/mpc-hc/ComPropertyPage.h +++ b/src/mpc-hc/ComPropertyPage.h @@ -1,52 +1,52 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "resource.h" - -// CComPropertyPage dialog - -class CComPropertyPage : public CPropertyPage -{ - DECLARE_DYNAMIC(CComPropertyPage) - - CComPtr m_pPage; - -public: - CComPropertyPage(IPropertyPage* pPage); - virtual ~CComPropertyPage(); - - // Dialog Data - enum { IDD = IDD_COMPROPERTYPAGE }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnSetActive(); - virtual BOOL OnKillActive(); - - DECLARE_MESSAGE_MAP() - -public: - virtual BOOL OnInitDialog(); - afx_msg void OnDestroy(); - virtual void OnOK(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "resource.h" + +// CComPropertyPage dialog + +class CComPropertyPage : public CPropertyPage +{ + DECLARE_DYNAMIC(CComPropertyPage) + + CComPtr m_pPage; + +public: + CComPropertyPage(IPropertyPage* pPage); + virtual ~CComPropertyPage(); + + // Dialog Data + enum { IDD = IDD_COMPROPERTYPAGE }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnSetActive(); + virtual BOOL OnKillActive(); + + DECLARE_MESSAGE_MAP() + +public: + virtual BOOL OnInitDialog(); + afx_msg void OnDestroy(); + virtual void OnOK(); +}; diff --git a/src/mpc-hc/ComPropertySheet.cpp b/src/mpc-hc/ComPropertySheet.cpp index 7af7e7a4239..4c6b262ff3b 100644 --- a/src/mpc-hc/ComPropertySheet.cpp +++ b/src/mpc-hc/ComPropertySheet.cpp @@ -1,287 +1,287 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "ComPropertySheet.h" -#include "DSUtil.h" -#include "../filters/InternalPropertyPage.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" - -// CComPropertyPageSite - -class CComPropertyPageSite : public CUnknown, public IPropertyPageSite -{ - IComPropertyPageDirty* m_pPPD; - -public: - CComPropertyPageSite(IComPropertyPageDirty* pPPD) : CUnknown(NAME("CComPropertyPageSite"), nullptr), m_pPPD(pPPD) {} - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(IPropertyPageSite) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IPropertyPageSite - STDMETHODIMP OnStatusChange(DWORD flags) { - if (m_pPPD) { - if (flags & PROPPAGESTATUS_DIRTY) { - m_pPPD->OnSetDirty(true); - } - if (flags & PROPPAGESTATUS_CLEAN) { - m_pPPD->OnSetDirty(false); - } - } - return S_OK; - } - STDMETHODIMP GetLocaleID(LCID* pLocaleID) { - CheckPointer(pLocaleID, E_POINTER); - *pLocaleID = ::GetUserDefaultLCID(); - return S_OK; - } - STDMETHODIMP GetPageContainer(IUnknown** ppUnk) { - return E_NOTIMPL; - } - STDMETHODIMP TranslateAccelerator(LPMSG pMsg) { - return E_NOTIMPL; - } -}; - -// CComPropertySheet - -IMPLEMENT_DYNAMIC(CComPropertySheet, CPropertySheet) -CComPropertySheet::CComPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) - : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) -{ - m_pSite = DEBUG_NEW CComPropertyPageSite(this); - m_size.SetSize(0, 0); -} - -CComPropertySheet::CComPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) - : CPropertySheet(pszCaption, pParentWnd, iSelectPage) -{ - m_pSite = DEBUG_NEW CComPropertyPageSite(this); - m_size.SetSize(0, 0); -} - -CComPropertySheet::~CComPropertySheet() -{ -} - -int CComPropertySheet::AddPages(ISpecifyPropertyPages* pSPP, bool internalfilter /*= false*/, ULONG uIgnorePage /*= -1*/) -{ - if (!pSPP) { - return 0; - } - - CAUUID caGUID; - caGUID.pElems = nullptr; - if (FAILED(pSPP->GetPages(&caGUID)) || caGUID.pElems == nullptr) { - return 0; - } - - IUnknown* lpUnk = nullptr; - if (FAILED(pSPP->QueryInterface(&lpUnk))) { - return 0; - } - - m_spp.AddTail(pSPP); - - CComQIPtr pSPP2 = pSPP; - CComQIPtr pPersist = pSPP; - - ULONG nPages = 0; - for (ULONG i = 0; i < caGUID.cElems; i++) { - CComPtr pPage; - - HRESULT hr = E_FAIL; - - if (pSPP2) { - hr = pSPP2->CreatePage(caGUID.pElems[i], &pPage); - } - - if (FAILED(hr) && internalfilter && !pPage && pPersist) { - hr = LoadExternalPropertyPage(pPersist, caGUID.pElems[i], &pPage); - } - - if (FAILED(hr) && !pPage) { - hr = pPage.CoCreateInstance(caGUID.pElems[i]); - } - - if (FAILED(hr) && !internalfilter && !pPage && pPersist) { - hr = LoadExternalPropertyPage(pPersist, caGUID.pElems[i], &pPage); - } - - if (SUCCEEDED(hr) && i != uIgnorePage) { - if (AddPage(pPage, lpUnk)) { - nPages++; - } - } - } - - CoTaskMemFree(caGUID.pElems); - lpUnk->Release(); - - return nPages; -} - -bool CComPropertySheet::AddPage(IPropertyPage* pPage, IUnknown* pUnk) -{ - if (!pPage || !pUnk) { - return false; - } - - pPage->SetPageSite(m_pSite); - pPage->SetObjects(1, &pUnk); - PROPPAGEINFO ppi; - pPage->GetPageInfo(&ppi); - m_size.cx = std::max(m_size.cx, ppi.size.cx); - m_size.cy = std::max(m_size.cy, ppi.size.cy); - CAutoPtr p(DEBUG_NEW CMPCThemeComPropertyPage(pPage)); - __super::AddPage(p); - m_pages.AddTail(p); - - return true; -} - -void CComPropertySheet::OnActivated(CPropertyPage* pPage) -{ - if (!pPage) { - return; - } - - CRect bounds(30000, 30000, -30000, -30000); - - CRect wr, cr; - GetWindowRect(wr); - GetClientRect(cr); - CSize ws = wr.Size(); - - CRect twr, tcr; - CTabCtrl* pTC = (CTabCtrl*)GetDlgItem(AFX_IDC_TAB_CONTROL); - pTC->GetWindowRect(twr); - pTC->GetClientRect(tcr); - CSize tws = twr.Size(); - - if (CWnd* pChild = pPage->GetWindow(GW_CHILD)) { - pChild->ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0); - pChild->ModifyStyleEx(WS_EX_DLGMODALFRAME, WS_EX_CONTROLPARENT); - - for (CWnd* pGrandChild = pChild->GetWindow(GW_CHILD); pGrandChild; pGrandChild = pGrandChild->GetNextWindow()) { - if (!(pGrandChild->GetStyle()&WS_VISIBLE)) { - continue; - } - - CRect r; - pGrandChild->GetWindowRect(&r); - pChild->ScreenToClient(r); - bounds |= r; - } - } - - bounds |= CRect(0, 0, 0, 0); - bounds.SetRect(0, 0, bounds.right + std::max(bounds.left, 4l), bounds.bottom + std::max(bounds.top, 4l)); - - CRect r = CRect(CPoint(0, 0), bounds.Size()); - pTC->AdjustRect(TRUE, r); - r.SetRect(twr.TopLeft(), twr.TopLeft() + r.Size()); - ScreenToClient(r); - pTC->MoveWindow(r); - pTC->ModifyStyle(TCS_MULTILINE, TCS_SINGLELINE); - - CSize diff = r.Size() - tws; - - if (!bounds.IsRectEmpty()) { - if (CWnd* pChild = pPage->GetWindow(GW_CHILD)) { - pChild->MoveWindow(bounds); - } - CRect r2 = twr; - pTC->AdjustRect(FALSE, r2); - ScreenToClient(r2); - pPage->MoveWindow(CRect(r2.TopLeft(), bounds.Size())); - } - - int _afxPropSheetButtons[] = { IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP }; - for (int i = 0; i < _countof(_afxPropSheetButtons); i++) { - if (CWnd* pWnd = GetDlgItem(_afxPropSheetButtons[i])) { - pWnd->GetWindowRect(r); - ScreenToClient(r); - pWnd->MoveWindow(CRect(r.TopLeft() + diff, r.Size())); - } - } - - MoveWindow(CRect(wr.TopLeft(), ws + diff)); - - Invalidate(); -} - - -BEGIN_MESSAGE_MAP(CComPropertySheet, CPropertySheet) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -// CComPropertySheet message handlers - -BOOL CComPropertySheet::OnInitDialog() -{ - BOOL bResult = (BOOL)Default();//CPropertySheet::OnInitDialog(); - - if (!(GetStyle() & WS_CHILD)) { - CenterWindow(); - } - - fulfillThemeReqs(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return bResult; -} - -void CComPropertySheet::fulfillThemeReqs() -{ - if (AppNeedsThemedControls()) { - CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); - } -} - -HBRUSH CComPropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppNeedsThemedControls()) { - LRESULT lResult; - if (pWnd->SendChildNotifyLastMsg(&lResult)) { - return (HBRUSH)lResult; - } - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::ControlAreaBGColor); - return controlAreaBrush; - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} - - -INT_PTR CComPropertySheet::DoModal() { - PreDoModalRTL(&m_psh); - return __super::DoModal(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "ComPropertySheet.h" +#include "DSUtil.h" +#include "../filters/InternalPropertyPage.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" + +// CComPropertyPageSite + +class CComPropertyPageSite : public CUnknown, public IPropertyPageSite +{ + IComPropertyPageDirty* m_pPPD; + +public: + CComPropertyPageSite(IComPropertyPageDirty* pPPD) : CUnknown(NAME("CComPropertyPageSite"), nullptr), m_pPPD(pPPD) {} + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(IPropertyPageSite) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IPropertyPageSite + STDMETHODIMP OnStatusChange(DWORD flags) { + if (m_pPPD) { + if (flags & PROPPAGESTATUS_DIRTY) { + m_pPPD->OnSetDirty(true); + } + if (flags & PROPPAGESTATUS_CLEAN) { + m_pPPD->OnSetDirty(false); + } + } + return S_OK; + } + STDMETHODIMP GetLocaleID(LCID* pLocaleID) { + CheckPointer(pLocaleID, E_POINTER); + *pLocaleID = ::GetUserDefaultLCID(); + return S_OK; + } + STDMETHODIMP GetPageContainer(IUnknown** ppUnk) { + return E_NOTIMPL; + } + STDMETHODIMP TranslateAccelerator(LPMSG pMsg) { + return E_NOTIMPL; + } +}; + +// CComPropertySheet + +IMPLEMENT_DYNAMIC(CComPropertySheet, CPropertySheet) +CComPropertySheet::CComPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) + : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) +{ + m_pSite = DEBUG_NEW CComPropertyPageSite(this); + m_size.SetSize(0, 0); +} + +CComPropertySheet::CComPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) + : CPropertySheet(pszCaption, pParentWnd, iSelectPage) +{ + m_pSite = DEBUG_NEW CComPropertyPageSite(this); + m_size.SetSize(0, 0); +} + +CComPropertySheet::~CComPropertySheet() +{ +} + +int CComPropertySheet::AddPages(ISpecifyPropertyPages* pSPP, bool internalfilter /*= false*/, ULONG uIgnorePage /*= -1*/) +{ + if (!pSPP) { + return 0; + } + + CAUUID caGUID; + caGUID.pElems = nullptr; + if (FAILED(pSPP->GetPages(&caGUID)) || caGUID.pElems == nullptr) { + return 0; + } + + IUnknown* lpUnk = nullptr; + if (FAILED(pSPP->QueryInterface(&lpUnk))) { + return 0; + } + + m_spp.AddTail(pSPP); + + CComQIPtr pSPP2 = pSPP; + CComQIPtr pPersist = pSPP; + + ULONG nPages = 0; + for (ULONG i = 0; i < caGUID.cElems; i++) { + CComPtr pPage; + + HRESULT hr = E_FAIL; + + if (pSPP2) { + hr = pSPP2->CreatePage(caGUID.pElems[i], &pPage); + } + + if (FAILED(hr) && internalfilter && !pPage && pPersist) { + hr = LoadExternalPropertyPage(pPersist, caGUID.pElems[i], &pPage); + } + + if (FAILED(hr) && !pPage) { + hr = pPage.CoCreateInstance(caGUID.pElems[i]); + } + + if (FAILED(hr) && !internalfilter && !pPage && pPersist) { + hr = LoadExternalPropertyPage(pPersist, caGUID.pElems[i], &pPage); + } + + if (SUCCEEDED(hr) && i != uIgnorePage) { + if (AddPage(pPage, lpUnk)) { + nPages++; + } + } + } + + CoTaskMemFree(caGUID.pElems); + lpUnk->Release(); + + return nPages; +} + +bool CComPropertySheet::AddPage(IPropertyPage* pPage, IUnknown* pUnk) +{ + if (!pPage || !pUnk) { + return false; + } + + pPage->SetPageSite(m_pSite); + pPage->SetObjects(1, &pUnk); + PROPPAGEINFO ppi; + pPage->GetPageInfo(&ppi); + m_size.cx = std::max(m_size.cx, ppi.size.cx); + m_size.cy = std::max(m_size.cy, ppi.size.cy); + CAutoPtr p(DEBUG_NEW CMPCThemeComPropertyPage(pPage)); + __super::AddPage(p); + m_pages.AddTail(p); + + return true; +} + +void CComPropertySheet::OnActivated(CPropertyPage* pPage) +{ + if (!pPage) { + return; + } + + CRect bounds(30000, 30000, -30000, -30000); + + CRect wr, cr; + GetWindowRect(wr); + GetClientRect(cr); + CSize ws = wr.Size(); + + CRect twr, tcr; + CTabCtrl* pTC = (CTabCtrl*)GetDlgItem(AFX_IDC_TAB_CONTROL); + pTC->GetWindowRect(twr); + pTC->GetClientRect(tcr); + CSize tws = twr.Size(); + + if (CWnd* pChild = pPage->GetWindow(GW_CHILD)) { + pChild->ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0); + pChild->ModifyStyleEx(WS_EX_DLGMODALFRAME, WS_EX_CONTROLPARENT); + + for (CWnd* pGrandChild = pChild->GetWindow(GW_CHILD); pGrandChild; pGrandChild = pGrandChild->GetNextWindow()) { + if (!(pGrandChild->GetStyle()&WS_VISIBLE)) { + continue; + } + + CRect r; + pGrandChild->GetWindowRect(&r); + pChild->ScreenToClient(r); + bounds |= r; + } + } + + bounds |= CRect(0, 0, 0, 0); + bounds.SetRect(0, 0, bounds.right + std::max(bounds.left, 4l), bounds.bottom + std::max(bounds.top, 4l)); + + CRect r = CRect(CPoint(0, 0), bounds.Size()); + pTC->AdjustRect(TRUE, r); + r.SetRect(twr.TopLeft(), twr.TopLeft() + r.Size()); + ScreenToClient(r); + pTC->MoveWindow(r); + pTC->ModifyStyle(TCS_MULTILINE, TCS_SINGLELINE); + + CSize diff = r.Size() - tws; + + if (!bounds.IsRectEmpty()) { + if (CWnd* pChild = pPage->GetWindow(GW_CHILD)) { + pChild->MoveWindow(bounds); + } + CRect r2 = twr; + pTC->AdjustRect(FALSE, r2); + ScreenToClient(r2); + pPage->MoveWindow(CRect(r2.TopLeft(), bounds.Size())); + } + + int _afxPropSheetButtons[] = { IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP }; + for (int i = 0; i < _countof(_afxPropSheetButtons); i++) { + if (CWnd* pWnd = GetDlgItem(_afxPropSheetButtons[i])) { + pWnd->GetWindowRect(r); + ScreenToClient(r); + pWnd->MoveWindow(CRect(r.TopLeft() + diff, r.Size())); + } + } + + MoveWindow(CRect(wr.TopLeft(), ws + diff)); + + Invalidate(); +} + + +BEGIN_MESSAGE_MAP(CComPropertySheet, CPropertySheet) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +// CComPropertySheet message handlers + +BOOL CComPropertySheet::OnInitDialog() +{ + BOOL bResult = (BOOL)Default();//CPropertySheet::OnInitDialog(); + + if (!(GetStyle() & WS_CHILD)) { + CenterWindow(); + } + + fulfillThemeReqs(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return bResult; +} + +void CComPropertySheet::fulfillThemeReqs() +{ + if (AppNeedsThemedControls()) { + CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); + } +} + +HBRUSH CComPropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppNeedsThemedControls()) { + LRESULT lResult; + if (pWnd->SendChildNotifyLastMsg(&lResult)) { + return (HBRUSH)lResult; + } + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::ControlAreaBGColor); + return controlAreaBrush; + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} + + +INT_PTR CComPropertySheet::DoModal() { + PreDoModalRTL(&m_psh); + return __super::DoModal(); +} diff --git a/src/mpc-hc/ComPropertySheet.h b/src/mpc-hc/ComPropertySheet.h index 027deee5c0d..a01be194f2a 100644 --- a/src/mpc-hc/ComPropertySheet.h +++ b/src/mpc-hc/ComPropertySheet.h @@ -1,70 +1,70 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include "CMPCThemeComPropertyPage.h" -#include "CMPCThemeUtil.h" - -interface IComPropertyPageDirty -{ - virtual void OnSetDirty(bool fDirty) = 0; -}; - -// CComPropertySheet - -class CComPropertySheet : public CPropertySheet - , public IComPropertyPageDirty - , public CMPCThemeUtil -{ - DECLARE_DYNAMIC(CComPropertySheet) - - CComPtr m_pSite; - CInterfaceList m_spp; - CAutoPtrList m_pages; - CSize m_size; - -public: - CComPropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); - CComPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); - virtual ~CComPropertySheet(); - - int AddPages(ISpecifyPropertyPages* pSPP, bool internalfilter = false, ULONG uIgnorePage = ULONG(-1)); - bool AddPage(IPropertyPage* pPage, IUnknown* pUnk); - - void OnActivated(CPropertyPage* pPage); - - // IComPropertyPageDirty - void OnSetDirty(bool fDirty) { - if (CPropertyPage* p = GetActivePage()) { - p->SetModified(fDirty); - } - } - - virtual BOOL OnInitDialog(); - void fulfillThemeReqs(); - virtual INT_PTR DoModal(); //override to handle RTL without using SetWindowLongPtr - - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - -protected: - DECLARE_MESSAGE_MAP() -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include "CMPCThemeComPropertyPage.h" +#include "CMPCThemeUtil.h" + +interface IComPropertyPageDirty +{ + virtual void OnSetDirty(bool fDirty) = 0; +}; + +// CComPropertySheet + +class CComPropertySheet : public CPropertySheet + , public IComPropertyPageDirty + , public CMPCThemeUtil +{ + DECLARE_DYNAMIC(CComPropertySheet) + + CComPtr m_pSite; + CInterfaceList m_spp; + CAutoPtrList m_pages; + CSize m_size; + +public: + CComPropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + CComPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + virtual ~CComPropertySheet(); + + int AddPages(ISpecifyPropertyPages* pSPP, bool internalfilter = false, ULONG uIgnorePage = ULONG(-1)); + bool AddPage(IPropertyPage* pPage, IUnknown* pUnk); + + void OnActivated(CPropertyPage* pPage); + + // IComPropertyPageDirty + void OnSetDirty(bool fDirty) { + if (CPropertyPage* p = GetActivePage()) { + p->SetModified(fDirty); + } + } + + virtual BOOL OnInitDialog(); + void fulfillThemeReqs(); + virtual INT_PTR DoModal(); //override to handle RTL without using SetWindowLongPtr + + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + +protected: + DECLARE_MESSAGE_MAP() +}; diff --git a/src/mpc-hc/DVBChannel.cpp b/src/mpc-hc/DVBChannel.cpp index ffc4a8a4837..98bfc1db8b1 100644 --- a/src/mpc-hc/DVBChannel.cpp +++ b/src/mpc-hc/DVBChannel.cpp @@ -1,310 +1,310 @@ -/* - * (C) 2009-2017 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 . - * - */ - - -#include "stdafx.h" -#include "DVBChannel.h" -#include "ISOLang.h" -#include "mplayerc.h" - - -LCID BDAStreamInfo::GetLCID() const -{ - return ISOLang::ISO6392ToLcid(CStringA(sLanguage)); -}; - -CBDAChannel::CBDAChannel(CString strChannel) -{ - FromString(strChannel); -} - -void CBDAChannel::FromString(CString strValue) -{ - int i = 0; - - int nVersion = _tstol(strValue.Tokenize(_T("|"), i)); - // We don't try to parse versions newer than the one we support - if (nVersion > FORMAT_VERSION_CURRENT) { - AfxThrowInvalidArgException(); - } - - m_strName = strValue.Tokenize(_T("|"), i); - m_ulFrequency = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulBandwidth = (nVersion > FORMAT_VERSION_4) ? _tstol(strValue.Tokenize(_T("|"), i)) - : AfxGetAppSettings().iBDABandwidth * 1000; - m_ulSymbolRate = (nVersion > FORMAT_VERSION_5) ? _tstol(strValue.Tokenize(_T("|"), i)) - : AfxGetAppSettings().iBDASymbolRate; - m_nPrefNumber = _tstol(strValue.Tokenize(_T("|"), i)); - m_nOriginNumber = _tstol(strValue.Tokenize(_T("|"), i)); - if (nVersion > FORMAT_VERSION_0) { - m_bEncrypted = !!_tstol(strValue.Tokenize(_T("|"), i)); - } - if (nVersion > FORMAT_VERSION_1) { - m_bNowNextFlag = !!_tstol(strValue.Tokenize(_T("|"), i)); - } - m_ulONID = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulTSID = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulSID = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulPMT = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulPCR = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulVideoPID = _tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoType = (BDA_STREAM_TYPE) _tstol(strValue.Tokenize(_T("|"), i)); - m_nAudioCount = _tstol(strValue.Tokenize(_T("|"), i)); - if (nVersion > FORMAT_VERSION_1) { - m_nDefaultAudio = _tstol(strValue.Tokenize(_T("|"), i)); - } - m_nSubtitleCount = _tstol(strValue.Tokenize(_T("|"), i)); - if (nVersion > FORMAT_VERSION_2) { - m_nDefaultSubtitle = _tstol(strValue.Tokenize(_T("|"), i)); - } - - for (int j = 0; j < m_nAudioCount; j++) { - m_Audios[j].ulPID = _tstol(strValue.Tokenize(_T("|"), i)); - m_Audios[j].nType = (BDA_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_Audios[j].nPesType = (PES_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_Audios[j].sLanguage = strValue.Tokenize(_T("|"), i); - } - - for (int j = 0; j < m_nSubtitleCount; j++) { - m_Subtitles[j].ulPID = _tstol(strValue.Tokenize(_T("|"), i)); - m_Subtitles[j].nType = (BDA_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_Subtitles[j].nPesType = (PES_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_Subtitles[j].sLanguage = strValue.Tokenize(_T("|"), i); - } - - if (nVersion > FORMAT_VERSION_3) { - m_nVideoFps = (BDA_FPS_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoChroma = (BDA_CHROMA_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoWidth = _tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoHeight = _tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoAR = (BDA_AspectRatio_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - } -} - -CString CBDAChannel::ToString() const -{ - auto substituteEmpty = [](const CString & lang) -> CString { - if (lang.IsEmpty()) - { - return _T(" "); - } - return lang; - }; - - CString strValue; - strValue.AppendFormat(_T("%d|%s|%lu|%lu|%lu|%d|%d|%d|%d|%lu|%lu|%lu|%lu|%lu|%lu|%d|%d|%d|%d|%d"), - FORMAT_VERSION_CURRENT, - m_strName.GetString(), - m_ulFrequency, - m_ulBandwidth, - m_ulSymbolRate, - m_nPrefNumber, - m_nOriginNumber, - m_bEncrypted, - m_bNowNextFlag, - m_ulONID, - m_ulTSID, - m_ulSID, - m_ulPMT, - m_ulPCR, - m_ulVideoPID, - m_nVideoType, - m_nAudioCount, - m_nDefaultAudio, - m_nSubtitleCount, - m_nDefaultSubtitle); - - for (int i = 0; i < m_nAudioCount; i++) { - strValue.AppendFormat(_T("|%lu|%d|%d|%s"), m_Audios[i].ulPID, m_Audios[i].nType, m_Audios[i].nPesType, substituteEmpty(m_Audios[i].sLanguage).GetString()); - } - - for (int i = 0; i < m_nSubtitleCount; i++) { - strValue.AppendFormat(_T("|%lu|%d|%d|%s"), m_Subtitles[i].ulPID, m_Subtitles[i].nType, m_Subtitles[i].nPesType, substituteEmpty(m_Subtitles[i].sLanguage).GetString()); - } - - strValue.AppendFormat(_T("|%d|%d|%lu|%lu|%d"), - m_nVideoFps, - m_nVideoChroma, - m_nVideoWidth, - m_nVideoHeight, - m_nVideoAR); - - return strValue; -} - -CStringA CBDAChannel::ToJSON() const -{ - CStringA jsonChannel; - jsonChannel.Format("{ \"index\" : %d, \"name\" : \"%s\" }", - m_nPrefNumber, - EscapeJSONString(UTF16To8(m_strName)).GetString()); - return jsonChannel; -} - -void CBDAChannel::AddStreamInfo(ULONG ulPID, BDA_STREAM_TYPE nType, PES_STREAM_TYPE nPesType, LPCTSTR strLanguage) -{ - switch (nType) { - case BDA_MPV: - case BDA_H264: - case BDA_HEVC: - m_ulVideoPID = ulPID; - m_nVideoType = nType; - break; - case BDA_MPA: - case BDA_AC3: - case BDA_EAC3: - case BDA_ADTS: - case BDA_LATM: - if (m_nAudioCount < BDA_MAX_AUDIO) { - m_Audios[m_nAudioCount].ulPID = ulPID; - m_Audios[m_nAudioCount].nType = nType; - m_Audios[m_nAudioCount].nPesType = nPesType; - m_Audios[m_nAudioCount].sLanguage = strLanguage; - m_nAudioCount++; - } - break; - case BDA_SUBTITLE: - if (m_nSubtitleCount < BDA_MAX_SUBTITLE) { - m_Subtitles[m_nSubtitleCount].ulPID = ulPID; - m_Subtitles[m_nSubtitleCount].nType = nType; - m_Subtitles[m_nSubtitleCount].nPesType = nPesType; - m_Subtitles[m_nSubtitleCount].sLanguage = strLanguage; - m_nSubtitleCount++; - } - break; - } -} - -REFERENCE_TIME CBDAChannel::GetAvgTimePerFrame() -{ - REFERENCE_TIME Value; - switch (m_nVideoFps) { - case BDA_FPS_23_976: - Value = 417084; - break; - case BDA_FPS_24_0: - Value = 416667; - break; - case BDA_FPS_25_0: - Value = 400000; - break; - case BDA_FPS_29_97: - Value = 333667; - break; - case BDA_FPS_30_0: - Value = 333333; - break; - case BDA_FPS_50_0: - Value = 200000; - break; - case BDA_FPS_59_94: - Value = 166834; - break; - case BDA_FPS_60_0: - Value = 166667; - break; - default: - Value = 0; - break; - } - return Value; -} - -CString CBDAChannel::GetVideoFpsDesc() -{ - CString strValue; - switch (m_nVideoFps) { - case BDA_FPS_23_976: - strValue = _T("23.976"); - break; - case BDA_FPS_24_0: - strValue = _T("24.000"); - break; - case BDA_FPS_25_0: - strValue = _T("25.000"); - break; - case BDA_FPS_29_97: - strValue = _T("29.970"); - break; - case BDA_FPS_30_0: - strValue = _T("30.000"); - break; - case BDA_FPS_50_0: - strValue = _T("50.000"); - break; - case BDA_FPS_59_94: - strValue = _T("59.940"); - break; - case BDA_FPS_60_0: - strValue = _T("60.000"); - break; - default: - strValue = _T(" -"); - break; - } - return strValue; - -} - -DWORD CBDAChannel::GetVideoARx() -{ - DWORD Value; - switch (GetVideoAR()) { - case BDA_AR_1: - Value = 1; - break; - case BDA_AR_3_4: - Value = 4; - break; - case BDA_AR_9_16: - Value = 16; - break; - case BDA_AR_1_2_21: - Value = 221; - break; - default: - Value = 0; - break; - } - return Value; -} - -DWORD CBDAChannel::GetVideoARy() -{ - DWORD Value; - switch (GetVideoAR()) { - case BDA_AR_1: - Value = 1; - break; - case BDA_AR_3_4: - Value = 3; - break; - case BDA_AR_9_16: - Value = 9; - break; - case BDA_AR_1_2_21: - Value = 100; - break; - default: - Value = 0; - break; - } - return Value; -} +/* + * (C) 2009-2017 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 . + * + */ + + +#include "stdafx.h" +#include "DVBChannel.h" +#include "ISOLang.h" +#include "mplayerc.h" + + +LCID BDAStreamInfo::GetLCID() const +{ + return ISOLang::ISO6392ToLcid(CStringA(sLanguage)); +}; + +CBDAChannel::CBDAChannel(CString strChannel) +{ + FromString(strChannel); +} + +void CBDAChannel::FromString(CString strValue) +{ + int i = 0; + + int nVersion = _tstol(strValue.Tokenize(_T("|"), i)); + // We don't try to parse versions newer than the one we support + if (nVersion > FORMAT_VERSION_CURRENT) { + AfxThrowInvalidArgException(); + } + + m_strName = strValue.Tokenize(_T("|"), i); + m_ulFrequency = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulBandwidth = (nVersion > FORMAT_VERSION_4) ? _tstol(strValue.Tokenize(_T("|"), i)) + : AfxGetAppSettings().iBDABandwidth * 1000; + m_ulSymbolRate = (nVersion > FORMAT_VERSION_5) ? _tstol(strValue.Tokenize(_T("|"), i)) + : AfxGetAppSettings().iBDASymbolRate; + m_nPrefNumber = _tstol(strValue.Tokenize(_T("|"), i)); + m_nOriginNumber = _tstol(strValue.Tokenize(_T("|"), i)); + if (nVersion > FORMAT_VERSION_0) { + m_bEncrypted = !!_tstol(strValue.Tokenize(_T("|"), i)); + } + if (nVersion > FORMAT_VERSION_1) { + m_bNowNextFlag = !!_tstol(strValue.Tokenize(_T("|"), i)); + } + m_ulONID = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulTSID = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulSID = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulPMT = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulPCR = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulVideoPID = _tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoType = (BDA_STREAM_TYPE) _tstol(strValue.Tokenize(_T("|"), i)); + m_nAudioCount = _tstol(strValue.Tokenize(_T("|"), i)); + if (nVersion > FORMAT_VERSION_1) { + m_nDefaultAudio = _tstol(strValue.Tokenize(_T("|"), i)); + } + m_nSubtitleCount = _tstol(strValue.Tokenize(_T("|"), i)); + if (nVersion > FORMAT_VERSION_2) { + m_nDefaultSubtitle = _tstol(strValue.Tokenize(_T("|"), i)); + } + + for (int j = 0; j < m_nAudioCount; j++) { + m_Audios[j].ulPID = _tstol(strValue.Tokenize(_T("|"), i)); + m_Audios[j].nType = (BDA_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_Audios[j].nPesType = (PES_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_Audios[j].sLanguage = strValue.Tokenize(_T("|"), i); + } + + for (int j = 0; j < m_nSubtitleCount; j++) { + m_Subtitles[j].ulPID = _tstol(strValue.Tokenize(_T("|"), i)); + m_Subtitles[j].nType = (BDA_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_Subtitles[j].nPesType = (PES_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_Subtitles[j].sLanguage = strValue.Tokenize(_T("|"), i); + } + + if (nVersion > FORMAT_VERSION_3) { + m_nVideoFps = (BDA_FPS_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoChroma = (BDA_CHROMA_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoWidth = _tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoHeight = _tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoAR = (BDA_AspectRatio_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + } +} + +CString CBDAChannel::ToString() const +{ + auto substituteEmpty = [](const CString & lang) -> CString { + if (lang.IsEmpty()) + { + return _T(" "); + } + return lang; + }; + + CString strValue; + strValue.AppendFormat(_T("%d|%s|%lu|%lu|%lu|%d|%d|%d|%d|%lu|%lu|%lu|%lu|%lu|%lu|%d|%d|%d|%d|%d"), + FORMAT_VERSION_CURRENT, + m_strName.GetString(), + m_ulFrequency, + m_ulBandwidth, + m_ulSymbolRate, + m_nPrefNumber, + m_nOriginNumber, + m_bEncrypted, + m_bNowNextFlag, + m_ulONID, + m_ulTSID, + m_ulSID, + m_ulPMT, + m_ulPCR, + m_ulVideoPID, + m_nVideoType, + m_nAudioCount, + m_nDefaultAudio, + m_nSubtitleCount, + m_nDefaultSubtitle); + + for (int i = 0; i < m_nAudioCount; i++) { + strValue.AppendFormat(_T("|%lu|%d|%d|%s"), m_Audios[i].ulPID, m_Audios[i].nType, m_Audios[i].nPesType, substituteEmpty(m_Audios[i].sLanguage).GetString()); + } + + for (int i = 0; i < m_nSubtitleCount; i++) { + strValue.AppendFormat(_T("|%lu|%d|%d|%s"), m_Subtitles[i].ulPID, m_Subtitles[i].nType, m_Subtitles[i].nPesType, substituteEmpty(m_Subtitles[i].sLanguage).GetString()); + } + + strValue.AppendFormat(_T("|%d|%d|%lu|%lu|%d"), + m_nVideoFps, + m_nVideoChroma, + m_nVideoWidth, + m_nVideoHeight, + m_nVideoAR); + + return strValue; +} + +CStringA CBDAChannel::ToJSON() const +{ + CStringA jsonChannel; + jsonChannel.Format("{ \"index\" : %d, \"name\" : \"%s\" }", + m_nPrefNumber, + EscapeJSONString(UTF16To8(m_strName)).GetString()); + return jsonChannel; +} + +void CBDAChannel::AddStreamInfo(ULONG ulPID, BDA_STREAM_TYPE nType, PES_STREAM_TYPE nPesType, LPCTSTR strLanguage) +{ + switch (nType) { + case BDA_MPV: + case BDA_H264: + case BDA_HEVC: + m_ulVideoPID = ulPID; + m_nVideoType = nType; + break; + case BDA_MPA: + case BDA_AC3: + case BDA_EAC3: + case BDA_ADTS: + case BDA_LATM: + if (m_nAudioCount < BDA_MAX_AUDIO) { + m_Audios[m_nAudioCount].ulPID = ulPID; + m_Audios[m_nAudioCount].nType = nType; + m_Audios[m_nAudioCount].nPesType = nPesType; + m_Audios[m_nAudioCount].sLanguage = strLanguage; + m_nAudioCount++; + } + break; + case BDA_SUBTITLE: + if (m_nSubtitleCount < BDA_MAX_SUBTITLE) { + m_Subtitles[m_nSubtitleCount].ulPID = ulPID; + m_Subtitles[m_nSubtitleCount].nType = nType; + m_Subtitles[m_nSubtitleCount].nPesType = nPesType; + m_Subtitles[m_nSubtitleCount].sLanguage = strLanguage; + m_nSubtitleCount++; + } + break; + } +} + +REFERENCE_TIME CBDAChannel::GetAvgTimePerFrame() +{ + REFERENCE_TIME Value; + switch (m_nVideoFps) { + case BDA_FPS_23_976: + Value = 417084; + break; + case BDA_FPS_24_0: + Value = 416667; + break; + case BDA_FPS_25_0: + Value = 400000; + break; + case BDA_FPS_29_97: + Value = 333667; + break; + case BDA_FPS_30_0: + Value = 333333; + break; + case BDA_FPS_50_0: + Value = 200000; + break; + case BDA_FPS_59_94: + Value = 166834; + break; + case BDA_FPS_60_0: + Value = 166667; + break; + default: + Value = 0; + break; + } + return Value; +} + +CString CBDAChannel::GetVideoFpsDesc() +{ + CString strValue; + switch (m_nVideoFps) { + case BDA_FPS_23_976: + strValue = _T("23.976"); + break; + case BDA_FPS_24_0: + strValue = _T("24.000"); + break; + case BDA_FPS_25_0: + strValue = _T("25.000"); + break; + case BDA_FPS_29_97: + strValue = _T("29.970"); + break; + case BDA_FPS_30_0: + strValue = _T("30.000"); + break; + case BDA_FPS_50_0: + strValue = _T("50.000"); + break; + case BDA_FPS_59_94: + strValue = _T("59.940"); + break; + case BDA_FPS_60_0: + strValue = _T("60.000"); + break; + default: + strValue = _T(" -"); + break; + } + return strValue; + +} + +DWORD CBDAChannel::GetVideoARx() +{ + DWORD Value; + switch (GetVideoAR()) { + case BDA_AR_1: + Value = 1; + break; + case BDA_AR_3_4: + Value = 4; + break; + case BDA_AR_9_16: + Value = 16; + break; + case BDA_AR_1_2_21: + Value = 221; + break; + default: + Value = 0; + break; + } + return Value; +} + +DWORD CBDAChannel::GetVideoARy() +{ + DWORD Value; + switch (GetVideoAR()) { + case BDA_AR_1: + Value = 1; + break; + case BDA_AR_3_4: + Value = 3; + break; + case BDA_AR_9_16: + Value = 9; + break; + case BDA_AR_1_2_21: + Value = 100; + break; + default: + Value = 0; + break; + } + return Value; +} diff --git a/src/mpc-hc/DVBChannel.h b/src/mpc-hc/DVBChannel.h index af89625e92a..d6866e34d8b 100644 --- a/src/mpc-hc/DVBChannel.h +++ b/src/mpc-hc/DVBChannel.h @@ -1,221 +1,221 @@ -/* - * (C) 2009-2016 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 . - * - */ - -#pragma once - -#include -#include - -#define FORMAT_VERSION_0 0 -#define FORMAT_VERSION_1 1 -#define FORMAT_VERSION_2 2 -#define FORMAT_VERSION_3 3 -#define FORMAT_VERSION_4 4 -#define FORMAT_VERSION_5 5 -#define FORMAT_VERSION_CURRENT 6 - -#define BDA_MAX_AUDIO 10 -#define BDA_MAX_SUBTITLE 10 - -struct EventDescriptor { - CString eventName; - CString eventDesc; - time_t startTime = 0; - time_t duration = 0; - CString strStartTime; - CString strEndTime; - std::vector> extendedDescriptorsItems; - CString extendedDescriptorsText; - int parentalRating = -1; - CString content; -}; - -enum BDA_STREAM_TYPE { - BDA_MPV = 0x00, - BDA_H264 = 0x01, - BDA_MPA = 0x02, - BDA_AC3 = 0x03, - BDA_EAC3 = 0x04, - BDA_HEVC = 0x05, - BDA_ADTS = 0x10, - BDA_LATM = 0x11, - BDA_PSI = 0x80, - BDA_TIF = 0x81, - BDA_EPG = 0x82, - BDA_SUB = 0x83, - BDA_SUBTITLE = 0xFE, - BDA_UNKNOWN = 0xFF -}; - -enum BDA_CHROMA_TYPE { - BDA_Chroma_NONE = 0x00, - BDA_Chroma_4_2_0 = 0x01, - BDA_Chroma_4_2_2 = 0x02, - BDA_Chroma_4_4_4 = 0x03 -}; - -enum BDA_FPS_TYPE { - BDA_FPS_NONE = 0x00, - BDA_FPS_23_976 = 0x01, - BDA_FPS_24_0 = 0x02, - BDA_FPS_25_0 = 0x03, - BDA_FPS_29_97 = 0x04, - BDA_FPS_30_0 = 0x05, - BDA_FPS_50_0 = 0x06, - BDA_FPS_59_94 = 0x07, - BDA_FPS_60_0 = 0x08 -}; - -enum BDA_AspectRatio_TYPE { - BDA_AR_NULL = 0x00, - BDA_AR_1 = 0x01, - BDA_AR_3_4 = 0x02, - BDA_AR_9_16 = 0x03, - BDA_AR_1_2_21 = 0x04 -}; - -struct BDAStreamInfo { - ULONG ulPID = 0; - BDA_STREAM_TYPE nType = BDA_UNKNOWN; - PES_STREAM_TYPE nPesType = INVALID; - CString sLanguage; - - LCID GetLCID() const; -}; - -class CBDAChannel -{ -public: - CBDAChannel() = default; - CBDAChannel(CString strChannel); - ~CBDAChannel() = default; - - CString ToString() const; - /** - * @brief Output a JSON representation of a BDA channel. - * @note The object contains two elements : "index", which corresponds to - * @c m_nPrefNumber, and "name", which contains @c m_strName. - * @returns A string representing a JSON object containing the - * aforementioned elements. - */ - CStringA ToJSON() const; - - LPCTSTR GetName() const { return m_strName; }; - ULONG GetFrequency() const { return m_ulFrequency; }; - ULONG GetBandwidth() const { return m_ulBandwidth; } - ULONG GetSymbolRate() const { return m_ulSymbolRate; } - int GetPrefNumber() const { return m_nPrefNumber; }; - int GetOriginNumber() const { return m_nOriginNumber; }; - ULONG GetONID() const { return m_ulONID; }; - ULONG GetTSID() const { return m_ulTSID; }; - ULONG GetSID() const { return m_ulSID; }; - ULONG GetPMT() const { return m_ulPMT; }; - ULONG GetPCR() const { return m_ulPCR; }; - ULONG GetVideoPID() const { return m_ulVideoPID; }; - BDA_FPS_TYPE GetVideoFps() const { return m_nVideoFps; } - CString GetVideoFpsDesc(); - BDA_CHROMA_TYPE GetVideoChroma() const { return m_nVideoChroma; } - ULONG GetVideoWidth() const {return m_nVideoWidth; } - ULONG GetVideoHeight() const {return m_nVideoHeight; } - BDA_AspectRatio_TYPE GetVideoAR() {return m_nVideoAR; } - DWORD GetVideoARx(); - DWORD GetVideoARy(); - BDA_STREAM_TYPE GetVideoType() const { return m_nVideoType; } - ULONG GetDefaultAudioPID() const { return m_Audios[GetDefaultAudio()].ulPID; }; - BDA_STREAM_TYPE GetDefaultAudioType() const { return m_Audios[GetDefaultAudio()].nType; } - ULONG GetDefaultSubtitlePID() const { return m_Subtitles[GetDefaultSubtitle()].ulPID; }; - int GetAudioCount() const { return m_nAudioCount; }; - int GetDefaultAudio() const { return m_nDefaultAudio; }; - int GetSubtitleCount() const { return m_nSubtitleCount; }; - int GetDefaultSubtitle() const { return m_nDefaultSubtitle; }; - BDAStreamInfo* GetAudio(int nIndex) { return &m_Audios[nIndex]; }; - const BDAStreamInfo* GetAudio(int nIndex) const { return &m_Audios[nIndex]; }; - BDAStreamInfo* GetSubtitle(int nIndex) { return &m_Subtitles[nIndex]; }; - const BDAStreamInfo* GetSubtitle(int nIndex) const { return &m_Subtitles[nIndex]; }; - bool HasName() const { return !m_strName.IsEmpty(); }; - bool IsEncrypted() const { return m_bEncrypted; }; - bool GetNowNextFlag() const { return m_bNowNextFlag; }; - REFERENCE_TIME GetAvgTimePerFrame(); - - void SetName(LPCTSTR Value) { m_strName = Value; }; - void SetFrequency(ULONG Value) { m_ulFrequency = Value; }; - void SetBandwidth(ULONG ulBandwidth) { m_ulBandwidth = ulBandwidth; } - void SetSymbolRate(ULONG ulSymbolRate) { m_ulSymbolRate = ulSymbolRate; } - void SetPrefNumber(int Value) { m_nPrefNumber = Value; }; - void SetOriginNumber(int Value) { m_nOriginNumber = Value; }; - void SetEncrypted(bool Value) { m_bEncrypted = Value; }; - void SetNowNextFlag(bool Value) { m_bNowNextFlag = Value; }; - void SetONID(ULONG Value) { m_ulONID = Value; }; - void SetTSID(ULONG Value) { m_ulTSID = Value; }; - void SetSID(ULONG Value) { m_ulSID = Value; }; - void SetPMT(ULONG Value) { m_ulPMT = Value; }; - void SetPCR(ULONG Value) { m_ulPCR = Value; }; - void SetVideoPID(ULONG Value) { m_ulVideoPID = Value; }; - void SetVideoFps(BDA_FPS_TYPE Value) { m_nVideoFps = Value; }; - void SetVideoChroma(BDA_CHROMA_TYPE Value) { m_nVideoChroma = Value; }; - void SetVideoWidth(ULONG Value) { m_nVideoWidth = Value; }; - void SetVideoHeight(ULONG Value) { m_nVideoHeight = Value; }; - void SetVideoAR(BDA_AspectRatio_TYPE Value) { m_nVideoAR = Value; }; - void SetDefaultAudio(int Value) { m_nDefaultAudio = Value; } - void SetDefaultSubtitle(int Value) { m_nDefaultSubtitle = Value; } - - void AddStreamInfo(ULONG ulPID, BDA_STREAM_TYPE nType, PES_STREAM_TYPE nPesType, LPCTSTR strLanguage); - - bool operator < (CBDAChannel const& channel) const { - int aOriginNumber = GetOriginNumber(); - int bOriginNumber = channel.GetOriginNumber(); - return (aOriginNumber == 0 && bOriginNumber == 0) ? GetPrefNumber() < channel.GetPrefNumber() : (aOriginNumber == 0 || bOriginNumber == 0) ? bOriginNumber == 0 : aOriginNumber < bOriginNumber; - } - - // Returns true for channels with the same place, doesn't necessarily need to be equal (i.e if internal streams were updated) - bool operator==(CBDAChannel const& channel) const { - return GetPMT() == channel.GetPMT() && GetFrequency() == channel.GetFrequency(); - } - -private: - CString m_strName; - ULONG m_ulFrequency = 0; - ULONG m_ulBandwidth = 0; - ULONG m_ulSymbolRate = 0; - int m_nPrefNumber = 0; - int m_nOriginNumber = 0; - bool m_bEncrypted = false; - bool m_bNowNextFlag = false; - ULONG m_ulONID = 0; - ULONG m_ulTSID = 0; - ULONG m_ulSID = 0; - ULONG m_ulPMT = 0; - ULONG m_ulPCR = 0; - ULONG m_ulVideoPID = 0; - BDA_STREAM_TYPE m_nVideoType = BDA_MPV; - BDA_FPS_TYPE m_nVideoFps = BDA_FPS_25_0; - BDA_CHROMA_TYPE m_nVideoChroma = BDA_Chroma_4_2_0; - ULONG m_nVideoWidth = 0; - ULONG m_nVideoHeight = 0; - BDA_AspectRatio_TYPE m_nVideoAR = BDA_AR_NULL; - int m_nAudioCount = 0; - int m_nDefaultAudio = 0; - int m_nSubtitleCount = 0; - int m_nDefaultSubtitle = -1; - std::array m_Audios; - std::array m_Subtitles; - - void FromString(CString strValue); -}; +/* + * (C) 2009-2016 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 . + * + */ + +#pragma once + +#include +#include + +#define FORMAT_VERSION_0 0 +#define FORMAT_VERSION_1 1 +#define FORMAT_VERSION_2 2 +#define FORMAT_VERSION_3 3 +#define FORMAT_VERSION_4 4 +#define FORMAT_VERSION_5 5 +#define FORMAT_VERSION_CURRENT 6 + +#define BDA_MAX_AUDIO 10 +#define BDA_MAX_SUBTITLE 10 + +struct EventDescriptor { + CString eventName; + CString eventDesc; + time_t startTime = 0; + time_t duration = 0; + CString strStartTime; + CString strEndTime; + std::vector> extendedDescriptorsItems; + CString extendedDescriptorsText; + int parentalRating = -1; + CString content; +}; + +enum BDA_STREAM_TYPE { + BDA_MPV = 0x00, + BDA_H264 = 0x01, + BDA_MPA = 0x02, + BDA_AC3 = 0x03, + BDA_EAC3 = 0x04, + BDA_HEVC = 0x05, + BDA_ADTS = 0x10, + BDA_LATM = 0x11, + BDA_PSI = 0x80, + BDA_TIF = 0x81, + BDA_EPG = 0x82, + BDA_SUB = 0x83, + BDA_SUBTITLE = 0xFE, + BDA_UNKNOWN = 0xFF +}; + +enum BDA_CHROMA_TYPE { + BDA_Chroma_NONE = 0x00, + BDA_Chroma_4_2_0 = 0x01, + BDA_Chroma_4_2_2 = 0x02, + BDA_Chroma_4_4_4 = 0x03 +}; + +enum BDA_FPS_TYPE { + BDA_FPS_NONE = 0x00, + BDA_FPS_23_976 = 0x01, + BDA_FPS_24_0 = 0x02, + BDA_FPS_25_0 = 0x03, + BDA_FPS_29_97 = 0x04, + BDA_FPS_30_0 = 0x05, + BDA_FPS_50_0 = 0x06, + BDA_FPS_59_94 = 0x07, + BDA_FPS_60_0 = 0x08 +}; + +enum BDA_AspectRatio_TYPE { + BDA_AR_NULL = 0x00, + BDA_AR_1 = 0x01, + BDA_AR_3_4 = 0x02, + BDA_AR_9_16 = 0x03, + BDA_AR_1_2_21 = 0x04 +}; + +struct BDAStreamInfo { + ULONG ulPID = 0; + BDA_STREAM_TYPE nType = BDA_UNKNOWN; + PES_STREAM_TYPE nPesType = INVALID; + CString sLanguage; + + LCID GetLCID() const; +}; + +class CBDAChannel +{ +public: + CBDAChannel() = default; + CBDAChannel(CString strChannel); + ~CBDAChannel() = default; + + CString ToString() const; + /** + * @brief Output a JSON representation of a BDA channel. + * @note The object contains two elements : "index", which corresponds to + * @c m_nPrefNumber, and "name", which contains @c m_strName. + * @returns A string representing a JSON object containing the + * aforementioned elements. + */ + CStringA ToJSON() const; + + LPCTSTR GetName() const { return m_strName; }; + ULONG GetFrequency() const { return m_ulFrequency; }; + ULONG GetBandwidth() const { return m_ulBandwidth; } + ULONG GetSymbolRate() const { return m_ulSymbolRate; } + int GetPrefNumber() const { return m_nPrefNumber; }; + int GetOriginNumber() const { return m_nOriginNumber; }; + ULONG GetONID() const { return m_ulONID; }; + ULONG GetTSID() const { return m_ulTSID; }; + ULONG GetSID() const { return m_ulSID; }; + ULONG GetPMT() const { return m_ulPMT; }; + ULONG GetPCR() const { return m_ulPCR; }; + ULONG GetVideoPID() const { return m_ulVideoPID; }; + BDA_FPS_TYPE GetVideoFps() const { return m_nVideoFps; } + CString GetVideoFpsDesc(); + BDA_CHROMA_TYPE GetVideoChroma() const { return m_nVideoChroma; } + ULONG GetVideoWidth() const {return m_nVideoWidth; } + ULONG GetVideoHeight() const {return m_nVideoHeight; } + BDA_AspectRatio_TYPE GetVideoAR() {return m_nVideoAR; } + DWORD GetVideoARx(); + DWORD GetVideoARy(); + BDA_STREAM_TYPE GetVideoType() const { return m_nVideoType; } + ULONG GetDefaultAudioPID() const { return m_Audios[GetDefaultAudio()].ulPID; }; + BDA_STREAM_TYPE GetDefaultAudioType() const { return m_Audios[GetDefaultAudio()].nType; } + ULONG GetDefaultSubtitlePID() const { return m_Subtitles[GetDefaultSubtitle()].ulPID; }; + int GetAudioCount() const { return m_nAudioCount; }; + int GetDefaultAudio() const { return m_nDefaultAudio; }; + int GetSubtitleCount() const { return m_nSubtitleCount; }; + int GetDefaultSubtitle() const { return m_nDefaultSubtitle; }; + BDAStreamInfo* GetAudio(int nIndex) { return &m_Audios[nIndex]; }; + const BDAStreamInfo* GetAudio(int nIndex) const { return &m_Audios[nIndex]; }; + BDAStreamInfo* GetSubtitle(int nIndex) { return &m_Subtitles[nIndex]; }; + const BDAStreamInfo* GetSubtitle(int nIndex) const { return &m_Subtitles[nIndex]; }; + bool HasName() const { return !m_strName.IsEmpty(); }; + bool IsEncrypted() const { return m_bEncrypted; }; + bool GetNowNextFlag() const { return m_bNowNextFlag; }; + REFERENCE_TIME GetAvgTimePerFrame(); + + void SetName(LPCTSTR Value) { m_strName = Value; }; + void SetFrequency(ULONG Value) { m_ulFrequency = Value; }; + void SetBandwidth(ULONG ulBandwidth) { m_ulBandwidth = ulBandwidth; } + void SetSymbolRate(ULONG ulSymbolRate) { m_ulSymbolRate = ulSymbolRate; } + void SetPrefNumber(int Value) { m_nPrefNumber = Value; }; + void SetOriginNumber(int Value) { m_nOriginNumber = Value; }; + void SetEncrypted(bool Value) { m_bEncrypted = Value; }; + void SetNowNextFlag(bool Value) { m_bNowNextFlag = Value; }; + void SetONID(ULONG Value) { m_ulONID = Value; }; + void SetTSID(ULONG Value) { m_ulTSID = Value; }; + void SetSID(ULONG Value) { m_ulSID = Value; }; + void SetPMT(ULONG Value) { m_ulPMT = Value; }; + void SetPCR(ULONG Value) { m_ulPCR = Value; }; + void SetVideoPID(ULONG Value) { m_ulVideoPID = Value; }; + void SetVideoFps(BDA_FPS_TYPE Value) { m_nVideoFps = Value; }; + void SetVideoChroma(BDA_CHROMA_TYPE Value) { m_nVideoChroma = Value; }; + void SetVideoWidth(ULONG Value) { m_nVideoWidth = Value; }; + void SetVideoHeight(ULONG Value) { m_nVideoHeight = Value; }; + void SetVideoAR(BDA_AspectRatio_TYPE Value) { m_nVideoAR = Value; }; + void SetDefaultAudio(int Value) { m_nDefaultAudio = Value; } + void SetDefaultSubtitle(int Value) { m_nDefaultSubtitle = Value; } + + void AddStreamInfo(ULONG ulPID, BDA_STREAM_TYPE nType, PES_STREAM_TYPE nPesType, LPCTSTR strLanguage); + + bool operator < (CBDAChannel const& channel) const { + int aOriginNumber = GetOriginNumber(); + int bOriginNumber = channel.GetOriginNumber(); + return (aOriginNumber == 0 && bOriginNumber == 0) ? GetPrefNumber() < channel.GetPrefNumber() : (aOriginNumber == 0 || bOriginNumber == 0) ? bOriginNumber == 0 : aOriginNumber < bOriginNumber; + } + + // Returns true for channels with the same place, doesn't necessarily need to be equal (i.e if internal streams were updated) + bool operator==(CBDAChannel const& channel) const { + return GetPMT() == channel.GetPMT() && GetFrequency() == channel.GetFrequency(); + } + +private: + CString m_strName; + ULONG m_ulFrequency = 0; + ULONG m_ulBandwidth = 0; + ULONG m_ulSymbolRate = 0; + int m_nPrefNumber = 0; + int m_nOriginNumber = 0; + bool m_bEncrypted = false; + bool m_bNowNextFlag = false; + ULONG m_ulONID = 0; + ULONG m_ulTSID = 0; + ULONG m_ulSID = 0; + ULONG m_ulPMT = 0; + ULONG m_ulPCR = 0; + ULONG m_ulVideoPID = 0; + BDA_STREAM_TYPE m_nVideoType = BDA_MPV; + BDA_FPS_TYPE m_nVideoFps = BDA_FPS_25_0; + BDA_CHROMA_TYPE m_nVideoChroma = BDA_Chroma_4_2_0; + ULONG m_nVideoWidth = 0; + ULONG m_nVideoHeight = 0; + BDA_AspectRatio_TYPE m_nVideoAR = BDA_AR_NULL; + int m_nAudioCount = 0; + int m_nDefaultAudio = 0; + int m_nSubtitleCount = 0; + int m_nDefaultSubtitle = -1; + std::array m_Audios; + std::array m_Subtitles; + + void FromString(CString strValue); +}; diff --git a/src/mpc-hc/DeinterlacerFilter.cpp b/src/mpc-hc/DeinterlacerFilter.cpp index 615ae25ca71..938e542f624 100644 --- a/src/mpc-hc/DeinterlacerFilter.cpp +++ b/src/mpc-hc/DeinterlacerFilter.cpp @@ -1,170 +1,170 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#include "stdafx.h" -#include "DeinterlacerFilter.h" -#include "MediaTypes.h" -#include "moreuuids.h" - - -CDeinterlacerFilter::CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr) - : CTransformFilter(NAME("CDeinterlacerFilter"), punk, __uuidof(CDeinterlacerFilter)) -{ - if (phr) { - *phr = S_OK; - } -} - -HRESULT CDeinterlacerFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin) -{ - return GetCLSID(pPin) == __uuidof(*this) ? E_FAIL : S_OK; -} - -HRESULT CDeinterlacerFilter::CheckInputType(const CMediaType* mtIn) -{ - if (mtIn->majortype != MEDIATYPE_Video) { - return E_FAIL; - } - if (mtIn->formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mtIn->pbFormat; - if (!(vih2->dwInterlaceFlags & AMINTERLACE_IsInterlaced)) { - return E_FAIL; - } - } - - BITMAPINFOHEADER bih; - if (!ExtractBIH(mtIn, &bih) || bih.biWidth == 0 || bih.biHeight <= 288) { - return E_FAIL; - } - - return mtIn->subtype == MEDIASUBTYPE_YUY2 || mtIn->subtype == MEDIASUBTYPE_UYVY - || mtIn->subtype == MEDIASUBTYPE_I420 || mtIn->subtype == MEDIASUBTYPE_YV12 || mtIn->subtype == MEDIASUBTYPE_IYUV - ? S_OK - : E_FAIL; -} - -HRESULT CDeinterlacerFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return mtIn->subtype == mtOut->subtype ? S_OK : E_FAIL; -} - -HRESULT CDeinterlacerFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - HRESULT hr; - - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pOut->GetMediaType(&pmt)) && pmt) { - CMediaType mt = *pmt; - m_pOutput->SetMediaType(&mt); - DeleteMediaType(pmt); - } - - BYTE* pDataIn = nullptr; - if (FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn) { - return S_FALSE; - } - - BYTE* pDataOut = nullptr; - if (FAILED(hr = pOut->GetPointer(&pDataOut)) || !pDataOut) { - return hr; - } - - const CMediaType& mtIn = m_pInput->CurrentMediaType(); - const CMediaType& mtOut = m_pOutput->CurrentMediaType(); - - BITMAPINFOHEADER bihIn, bihOut; - ExtractBIH(&mtIn, &bihIn); - ExtractBIH(&mtOut, &bihOut); - - bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3; - bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3; - bool fFlip = fInputFlipped != fOutputFlipped; - - int bppIn = !(bihIn.biBitCount & 7) ? bihIn.biBitCount : 8; - int bppOut = !(bihOut.biBitCount & 7) ? bihOut.biBitCount : 8; - int pitchIn = bihIn.biWidth * bppIn >> 3; - int pitchOut = bihOut.biWidth * bppOut >> 3; - - if (fFlip) { - pitchOut = -pitchOut; - } - - if (mtIn.subtype == MEDIASUBTYPE_YUY2 || mtIn.subtype == MEDIASUBTYPE_UYVY) { - DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); - } else if (mtIn.subtype == MEDIASUBTYPE_I420 || mtIn.subtype == MEDIASUBTYPE_YV12 || mtIn.subtype == MEDIASUBTYPE_IYUV) { - DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); - - int sizeIn = bihIn.biHeight * pitchIn, sizeOut = abs(bihOut.biHeight) * pitchOut; - pitchIn /= 2; - pitchOut /= 2; - bihIn.biHeight /= 2; - pDataIn += sizeIn; - pDataOut += sizeOut; - DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); - - pDataIn += sizeIn / 4; - pDataOut += sizeOut / 4; - DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); - } - - return S_OK; -} - -HRESULT CDeinterlacerFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - BITMAPINFOHEADER bih; - ExtractBIH(&m_pOutput->CurrentMediaType(), &bih); - - pProperties->cBuffers = 1; - pProperties->cbBuffer = bih.biSizeImage; - pProperties->cbAlign = 1; - pProperties->cbPrefix = 0; - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR; -} - -HRESULT CDeinterlacerFilter::GetMediaType(int iPosition, CMediaType* pmt) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - *pmt = m_pInput->CurrentMediaType(); - CorrectMediaType(pmt); - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#include "stdafx.h" +#include "DeinterlacerFilter.h" +#include "MediaTypes.h" +#include "moreuuids.h" + + +CDeinterlacerFilter::CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr) + : CTransformFilter(NAME("CDeinterlacerFilter"), punk, __uuidof(CDeinterlacerFilter)) +{ + if (phr) { + *phr = S_OK; + } +} + +HRESULT CDeinterlacerFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin) +{ + return GetCLSID(pPin) == __uuidof(*this) ? E_FAIL : S_OK; +} + +HRESULT CDeinterlacerFilter::CheckInputType(const CMediaType* mtIn) +{ + if (mtIn->majortype != MEDIATYPE_Video) { + return E_FAIL; + } + if (mtIn->formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mtIn->pbFormat; + if (!(vih2->dwInterlaceFlags & AMINTERLACE_IsInterlaced)) { + return E_FAIL; + } + } + + BITMAPINFOHEADER bih; + if (!ExtractBIH(mtIn, &bih) || bih.biWidth == 0 || bih.biHeight <= 288) { + return E_FAIL; + } + + return mtIn->subtype == MEDIASUBTYPE_YUY2 || mtIn->subtype == MEDIASUBTYPE_UYVY + || mtIn->subtype == MEDIASUBTYPE_I420 || mtIn->subtype == MEDIASUBTYPE_YV12 || mtIn->subtype == MEDIASUBTYPE_IYUV + ? S_OK + : E_FAIL; +} + +HRESULT CDeinterlacerFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return mtIn->subtype == mtOut->subtype ? S_OK : E_FAIL; +} + +HRESULT CDeinterlacerFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + HRESULT hr; + + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pOut->GetMediaType(&pmt)) && pmt) { + CMediaType mt = *pmt; + m_pOutput->SetMediaType(&mt); + DeleteMediaType(pmt); + } + + BYTE* pDataIn = nullptr; + if (FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn) { + return S_FALSE; + } + + BYTE* pDataOut = nullptr; + if (FAILED(hr = pOut->GetPointer(&pDataOut)) || !pDataOut) { + return hr; + } + + const CMediaType& mtIn = m_pInput->CurrentMediaType(); + const CMediaType& mtOut = m_pOutput->CurrentMediaType(); + + BITMAPINFOHEADER bihIn, bihOut; + ExtractBIH(&mtIn, &bihIn); + ExtractBIH(&mtOut, &bihOut); + + bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3; + bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3; + bool fFlip = fInputFlipped != fOutputFlipped; + + int bppIn = !(bihIn.biBitCount & 7) ? bihIn.biBitCount : 8; + int bppOut = !(bihOut.biBitCount & 7) ? bihOut.biBitCount : 8; + int pitchIn = bihIn.biWidth * bppIn >> 3; + int pitchOut = bihOut.biWidth * bppOut >> 3; + + if (fFlip) { + pitchOut = -pitchOut; + } + + if (mtIn.subtype == MEDIASUBTYPE_YUY2 || mtIn.subtype == MEDIASUBTYPE_UYVY) { + DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); + } else if (mtIn.subtype == MEDIASUBTYPE_I420 || mtIn.subtype == MEDIASUBTYPE_YV12 || mtIn.subtype == MEDIASUBTYPE_IYUV) { + DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); + + int sizeIn = bihIn.biHeight * pitchIn, sizeOut = abs(bihOut.biHeight) * pitchOut; + pitchIn /= 2; + pitchOut /= 2; + bihIn.biHeight /= 2; + pDataIn += sizeIn; + pDataOut += sizeOut; + DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); + + pDataIn += sizeIn / 4; + pDataOut += sizeOut / 4; + DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); + } + + return S_OK; +} + +HRESULT CDeinterlacerFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + BITMAPINFOHEADER bih; + ExtractBIH(&m_pOutput->CurrentMediaType(), &bih); + + pProperties->cBuffers = 1; + pProperties->cbBuffer = bih.biSizeImage; + pProperties->cbAlign = 1; + pProperties->cbPrefix = 0; + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR; +} + +HRESULT CDeinterlacerFilter::GetMediaType(int iPosition, CMediaType* pmt) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + *pmt = m_pInput->CurrentMediaType(); + CorrectMediaType(pmt); + return S_OK; +} diff --git a/src/mpc-hc/DeinterlacerFilter.h b/src/mpc-hc/DeinterlacerFilter.h index 30ed0d6bccf..74b76012f3d 100644 --- a/src/mpc-hc/DeinterlacerFilter.h +++ b/src/mpc-hc/DeinterlacerFilter.h @@ -1,37 +1,37 @@ -/* - * (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 . - * - */ - -#pragma once - -class __declspec(uuid("96F3E0BE-1BA4-4E79-973D-191FE425C86B")) - CDeinterlacerFilter : public CTransformFilter -{ -protected: - HRESULT CheckConnect(PIN_DIRECTION dir, IPin* pPin); - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - -public: - CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr); -}; +/* + * (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 . + * + */ + +#pragma once + +class __declspec(uuid("96F3E0BE-1BA4-4E79-973D-191FE425C86B")) + CDeinterlacerFilter : public CTransformFilter +{ +protected: + HRESULT CheckConnect(PIN_DIRECTION dir, IPin* pPin); + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + +public: + CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr); +}; diff --git a/src/mpc-hc/EditListEditor.cpp b/src/mpc-hc/EditListEditor.cpp index c88eda78a7b..4ebc48a1ad9 100644 --- a/src/mpc-hc/EditListEditor.cpp +++ b/src/mpc-hc/EditListEditor.cpp @@ -1,662 +1,662 @@ -/* - * (C) 2009-2018 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 . - * - */ - -#include "stdafx.h" -#include "resource.h" -#include "EditListEditor.h" -#include "DSUtil.h" - - -CClip::CClip() - : m_rtIn(_I64_MIN) - , m_rtOut(_I64_MIN) -{ -} - -CClip::~CClip() -{ -} - -void CClip::SetIn(LPCTSTR strVal) -{ - m_rtIn = StringToReftime(strVal); -} - -void CClip::SetOut(LPCTSTR strVal) -{ - m_rtOut = StringToReftime(strVal); -} - -void CClip::SetIn(REFERENCE_TIME rtVal) -{ - m_rtIn = rtVal; - if (m_rtIn > m_rtOut) { - m_rtOut = _I64_MIN; - } -}; - -void CClip::SetOut(REFERENCE_TIME rtVal) -{ - m_rtOut = rtVal; - if (m_rtIn > m_rtOut) { - m_rtIn = _I64_MIN; - } -}; - -CString CClip::GetIn() const -{ - return m_rtIn == _I64_MIN ? CString() : ReftimeToString(m_rtIn); -} - -CString CClip::GetOut() const -{ - return m_rtOut == _I64_MIN ? CString() : ReftimeToString(m_rtOut); -} - -IMPLEMENT_DYNAMIC(CEditListEditor, CPlayerBar) -CEditListEditor::CEditListEditor() - : m_curPos(nullptr) - , m_bDragging(FALSE) - , m_nDragIndex(-1) - , m_nDropIndex(-1) - , m_pDragImage(nullptr) - , m_bFileOpen(false) -{ -} - -CEditListEditor::~CEditListEditor() -{ - SaveEditListToFile(); -} - -BEGIN_MESSAGE_MAP(CEditListEditor, CPlayerBar) - ON_WM_SIZE() - ON_NOTIFY(LVN_ITEMCHANGED, IDC_EDITLIST, OnLvnItemchanged) - ON_NOTIFY(LVN_KEYDOWN, IDC_EDITLIST, OnLvnKeyDown) - ON_WM_DRAWITEM() - ON_NOTIFY(LVN_BEGINDRAG, IDC_EDITLIST, OnBeginDrag) - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONUP() - ON_WM_TIMER() - ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_EDITLIST, OnBeginlabeleditList) - ON_NOTIFY(LVN_DOLABELEDIT, IDC_EDITLIST, OnDolabeleditList) - ON_NOTIFY(LVN_ENDLABELEDIT, IDC_EDITLIST, OnEndlabeleditList) -END_MESSAGE_MAP() - -BOOL CEditListEditor::Create(CWnd* pParentWnd, UINT defDockBarID) -{ - if (!__super::Create(ResStr(IDS_EDIT_LIST_EDITOR), pParentWnd, ID_VIEW_EDITLISTEDITOR, defDockBarID, _T("Edit List Editor"))) { - return FALSE; - } - - m_stUsers.Create(_T("User :"), WS_VISIBLE | WS_CHILD, CRect(5, 5, 100, 21), this, 0); - m_cbUsers.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(90, 0, 260, 21), this, 0); - FillCombo(_T("Users.txt"), m_cbUsers, false); - - m_stHotFolders.Create(_T("Hot folder :"), WS_VISIBLE | WS_CHILD, CRect(5, 35, 100, 51), this, 0); - m_cbHotFolders.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(90, 30, 260, 21), this, 0); - FillCombo(_T("HotFolders.txt"), m_cbHotFolders, true); - - m_list.CreateEx( - WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP - | LVS_OWNERDRAWFIXED - | LVS_REPORT | LVS_SINGLESEL | LVS_AUTOARRANGE | LVS_NOSORTHEADER, - CRect(0, 0, 100, 100), this, IDC_EDITLIST); - - m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); - - m_list.InsertColumn(COL_IN, _T("Nb."), LVCFMT_LEFT, 35); - m_list.InsertColumn(COL_IN, _T("In"), LVCFMT_LEFT, 100); - m_list.InsertColumn(COL_OUT, _T("Out"), LVCFMT_LEFT, 100); - m_list.InsertColumn(COL_NAME, _T("Name"), LVCFMT_LEFT, 150); - - m_fakeImageList.Create(1, 16, ILC_COLOR4, 10, 10); - m_list.SetImageList(&m_fakeImageList, LVSIL_SMALL); - - return TRUE; -} - -void CEditListEditor::ReloadTranslatableResources() -{ - SetWindowText(ResStr(IDS_EDIT_LIST_EDITOR)); -} - -void CEditListEditor::OnSize(UINT nType, int cx, int cy) -{ - __super::OnSize(nType, cx, cy); - - ResizeListColumn(); -} - -void CEditListEditor::ResizeListColumn() -{ - if (::IsWindow(m_list.m_hWnd)) { - CRect r; - GetClientRect(r); - r.DeflateRect(2, 2); - - r.top += 60; - m_list.SetRedraw(FALSE); - m_list.MoveWindow(r); - m_list.GetClientRect(r); - m_list.SetRedraw(TRUE); - } -} - -void CEditListEditor::SaveEditListToFile() -{ - if ((m_bFileOpen || !m_editList.IsEmpty()) && !m_strFileName.IsEmpty()) { - CStdioFile editListFile; - if (editListFile.Open(m_strFileName, CFile::modeCreate | CFile::modeWrite)) { - CString strLine; - int nIndex; - CString strUser; - CString strHotFolders; - - nIndex = m_cbUsers.GetCurSel(); - if (nIndex >= 0) { - m_cbUsers.GetLBText(nIndex, strUser); - } - - nIndex = m_cbHotFolders.GetCurSel(); - if (nIndex >= 0) { - m_cbHotFolders.GetLBText(nIndex, strHotFolders); - } - - POSITION pos = m_editList.GetHeadPosition(); - for (int i = 0; pos; i++, m_editList.GetNext(pos)) { - CClip& CurClip = m_editList.GetAt(pos); - - if (CurClip.HaveIn() && CurClip.HaveOut()) { - strLine.Format(_T("%s\t%s\t%s\t%s\t%s\n"), CurClip.GetIn().GetString(), CurClip.GetOut().GetString(), CurClip.GetName().GetString(), strUser.GetString(), strHotFolders.GetString()); - editListFile.WriteString(strLine); - } - } - - editListFile.Close(); - } - } -} - -void CEditListEditor::CloseFile() -{ - SaveEditListToFile(); - m_editList.RemoveAll(); - m_list.DeleteAllItems(); - m_curPos = nullptr; - m_strFileName.Empty(); - m_bFileOpen = false; - m_cbHotFolders.SetCurSel(0); -} - -void CEditListEditor::OpenFile(LPCTSTR lpFileName) -{ - CString strLine; - CStdioFile editListFile; - CString strUser; - CString strHotFolders; - - CloseFile(); - m_strFileName.Format(_T("%s.edl"), lpFileName); - - if (editListFile.Open(m_strFileName, CFile::modeRead)) { - m_bFileOpen = true; - while (editListFile.ReadString(strLine)) { - //int nPos = 0; - CString strIn; // = strLine.Tokenize(_T(" \t"), nPos); - CString strOut; // = strLine.Tokenize(_T(" \t"), nPos); - CString strName; // = strLine.Tokenize(_T(" \t"), nPos); - - AfxExtractSubString(strIn, strLine, 0, _T('\t')); - AfxExtractSubString(strOut, strLine, 1, _T('\t')); - AfxExtractSubString(strName, strLine, 2, _T('\t')); - if (strUser.IsEmpty()) { - AfxExtractSubString(strUser, strLine, 3, _T('\t')); - SelectCombo(strUser, m_cbUsers); - } - if (strHotFolders.IsEmpty()) { - AfxExtractSubString(strHotFolders, strLine, 4, _T('\t')); - SelectCombo(strHotFolders, m_cbHotFolders); - } - - if (!strIn.IsEmpty() && !strOut.IsEmpty()) { - CClip NewClip; - NewClip.SetIn(strIn); - NewClip.SetOut(strOut); - NewClip.SetName(strName); - - InsertClip(nullptr, NewClip); - } - } - - editListFile.Close(); - } else { - m_bFileOpen = false; - } - - if (m_nameList.IsEmpty()) { - CStdioFile nameFile; - CString str; - if (nameFile.Open(_T("EditListNames.txt"), CFile::modeRead)) { - while (nameFile.ReadString(str)) { - m_nameList.Add(str); - } - nameFile.Close(); - } - } -} - -void CEditListEditor::SetIn(REFERENCE_TIME rtIn) -{ - if (m_curPos) { - CClip& curClip = m_editList.GetAt(m_curPos); - - curClip.SetIn(rtIn); - m_list.Invalidate(); - } -} - -void CEditListEditor::SetOut(REFERENCE_TIME rtOut) -{ - if (m_curPos) { - CClip& curClip = m_editList.GetAt(m_curPos); - - curClip.SetOut(rtOut); - m_list.Invalidate(); - } -} - -void CEditListEditor::NewClip(REFERENCE_TIME rtVal) -{ - CClip newClip; - newClip.SetIn(rtVal); - - if (m_curPos) { - CClip& curClip = m_editList.GetAt(m_curPos); - - if (curClip.HaveIn()) { - if (!curClip.HaveOut()) { - curClip.SetOut(rtVal); - } - } - } - m_curPos = InsertClip(m_curPos, newClip); - m_list.Invalidate(); -} - -void CEditListEditor::Save() -{ - SaveEditListToFile(); -} - -POSITION CEditListEditor::InsertClip(POSITION pos, CClip& newClip) -{ - LVITEM lv; - POSITION newClipPos; - - if (pos == nullptr) { - newClipPos = m_editList.AddTail(newClip); - } else { - newClipPos = m_editList.InsertAfter(pos, newClip); - } - - lv.mask = LVIF_STATE | LVIF_TEXT; - lv.iItem = FindIndex(pos); - lv.iSubItem = 0; - lv.pszText = const_cast(_T("")); - lv.state = m_list.GetItemCount() == 0 ? LVIS_SELECTED : 0; - m_list.InsertItem(&lv); - - return newClipPos; -} - -int CEditListEditor::FindIndex(const POSITION pos) const -{ - int iItem = 0; - POSITION curPos = m_editList.GetHeadPosition(); - while (curPos && curPos != pos) { - m_editList.GetNext(curPos); - iItem++; - } - return iItem; -} - -int CEditListEditor::FindNameIndex(LPCTSTR strName) const -{ - int nResult = -1; - - for (int i = 0; i < m_nameList.GetCount(); i++) { - const CString& curName = m_nameList.GetAt(i); - - if (curName == strName) { - nResult = i; - break; - } - } - - return nResult; -} - -void CEditListEditor::FillCombo(LPCTSTR strFileName, CComboBox& combo, bool bAllowNull) -{ - CStdioFile nameFile; - CString str; - if (nameFile.Open(strFileName, CFile::modeRead)) { - if (bAllowNull) { - combo.AddString(_T("")); - } - - while (nameFile.ReadString(str)) { - combo.AddString(str); - } - nameFile.Close(); - } -} - -void CEditListEditor::SelectCombo(LPCTSTR strValue, CComboBox& combo) -{ - for (int i = 0; i < combo.GetCount(); i++) { - CString strTemp; - combo.GetLBText(i, strTemp); - if (strTemp == strValue) { - combo.SetCurSel(i); - break; - } - } -} - -void CEditListEditor::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - if (nIDCtl != IDC_EDITLIST) { - return; - } - - int nItem = lpDrawItemStruct->itemID; - CRect rcItem = lpDrawItemStruct->rcItem; - POSITION pos = m_editList.FindIndex(nItem); - - if (pos) { - bool fSelected = (pos == m_curPos); - UNREFERENCED_PARAMETER(fSelected); - CClip& curClip = m_editList.GetAt(pos); - CString strTemp; - - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - - if (!!m_list.GetItemState(nItem, LVIS_SELECTED)) { - FillRect(pDC->m_hDC, rcItem, CBrush(0xf1dacc)); - FrameRect(pDC->m_hDC, rcItem, CBrush(0xc56a31)); - } else { - FillRect(pDC->m_hDC, rcItem, CBrush(GetSysColor(COLOR_WINDOW))); - } - - COLORREF textcolor = RGB(0, 0, 0); - if (!curClip.HaveIn() || !curClip.HaveOut()) { - textcolor = RGB(255, 0, 0); - } - - for (int i = 0; i < COL_MAX; i++) { - m_list.GetSubItemRect(nItem, i, LVIR_LABEL, rcItem); - pDC->SetTextColor(textcolor); - switch (i) { - case COL_INDEX: - strTemp.Format(_T("%d"), nItem + 1); - pDC->DrawText(strTemp, rcItem, DT_CENTER | DT_VCENTER); - break; - case COL_IN: - pDC->DrawText(curClip.GetIn(), rcItem, DT_CENTER | DT_VCENTER); - break; - case COL_OUT: - pDC->DrawText(curClip.GetOut(), rcItem, DT_CENTER | DT_VCENTER); - break; - case COL_NAME: - pDC->DrawText(curClip.GetName(), rcItem, DT_LEFT | DT_VCENTER); - break; - } - } - } -} - -void CEditListEditor::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); - - if (pNMLV->iItem >= 0) { - m_curPos = m_editList.FindIndex(pNMLV->iItem); - } -} - -void CEditListEditor::OnLvnKeyDown(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMLVKEYDOWN pLVKeyDown = reinterpret_cast(pNMHDR); - - *pResult = FALSE; - - if (pLVKeyDown->wVKey == VK_DELETE) { - POSITION pos = m_list.GetFirstSelectedItemPosition(); - POSITION clipPos; - int nItem = -1; - while (pos) { - nItem = m_list.GetNextSelectedItem(pos); - clipPos = m_editList.FindIndex(nItem); - if (clipPos) { - m_editList.RemoveAt(clipPos); - } - m_list.DeleteItem(nItem); - } - if (nItem != -1) { - m_list.SetItemState(std::min(nItem, m_list.GetItemCount() - 1), LVIS_SELECTED, LVIS_SELECTED); - } - m_list.Invalidate(); - } -} - -void CEditListEditor::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) -{ - ModifyStyle(WS_EX_ACCEPTFILES, 0); - - m_nDragIndex = ((LPNMLISTVIEW)pNMHDR)->iItem; - - CPoint p(0, 0); - m_pDragImage = m_list.CreateDragImageEx(&p); - - CPoint p2 = ((LPNMLISTVIEW)pNMHDR)->ptAction; - - m_pDragImage->BeginDrag(0, p2 - p); - m_pDragImage->DragEnter(GetDesktopWindow(), ((LPNMLISTVIEW)pNMHDR)->ptAction); - - m_bDragging = TRUE; - m_nDropIndex = -1; - - SetCapture(); -} - -void CEditListEditor::OnMouseMove(UINT nFlags, CPoint point) -{ - if (m_bDragging) { - m_ptDropPoint = point; - ClientToScreen(&m_ptDropPoint); - - m_pDragImage->DragMove(m_ptDropPoint); - m_pDragImage->DragShowNolock(FALSE); - - WindowFromPoint(m_ptDropPoint)->ScreenToClient(&m_ptDropPoint); - - m_pDragImage->DragShowNolock(TRUE); - - { - int iOverItem = m_list.HitTest(m_ptDropPoint); - int iTopItem = m_list.GetTopIndex(); - int iBottomItem = m_list.GetBottomIndex(); - - if (iOverItem == iTopItem && iTopItem != 0) { // top of list - SetTimer(1, 100, nullptr); - } else { - KillTimer(1); - } - - if (iOverItem >= iBottomItem && iBottomItem != (m_list.GetItemCount() - 1)) { // bottom of list - SetTimer(2, 100, nullptr); - } else { - KillTimer(2); - } - } - } - - __super::OnMouseMove(nFlags, point); -} - -void CEditListEditor::OnTimer(UINT_PTR nIDEvent) -{ - int iTopItem = m_list.GetTopIndex(); - int iBottomItem = iTopItem + m_list.GetCountPerPage() - 1; - - if (m_bDragging) { - m_pDragImage->DragShowNolock(FALSE); - - if (nIDEvent == 1) { - m_list.EnsureVisible(iTopItem - 1, false); - m_list.UpdateWindow(); - if (m_list.GetTopIndex() == 0) { - KillTimer(1); - } - } else if (nIDEvent == 2) { - m_list.EnsureVisible(iBottomItem + 1, false); - m_list.UpdateWindow(); - if (m_list.GetBottomIndex() == (m_list.GetItemCount() - 1)) { - KillTimer(2); - } - } - - m_pDragImage->DragShowNolock(TRUE); - } - - __super::OnTimer(nIDEvent); -} - -void CEditListEditor::OnLButtonUp(UINT nFlags, CPoint point) -{ - if (m_bDragging) { - ::ReleaseCapture(); - - m_bDragging = FALSE; - m_pDragImage->DragLeave(GetDesktopWindow()); - m_pDragImage->EndDrag(); - - delete m_pDragImage; - m_pDragImage = nullptr; - - KillTimer(1); - KillTimer(2); - - CPoint pt(point); - ClientToScreen(&pt); - - if (WindowFromPoint(pt) == &m_list) { - DropItemOnList(); - } - } - - ModifyStyle(0, WS_EX_ACCEPTFILES); - - __super::OnLButtonUp(nFlags, point); -} - -void CEditListEditor::DropItemOnList() -{ - m_ptDropPoint.y -= 10; - m_nDropIndex = m_list.HitTest(CPoint(10, m_ptDropPoint.y)); - - POSITION dragPos = m_editList.FindIndex(m_nDragIndex); - POSITION dropPos = m_editList.FindIndex(m_nDropIndex); - if (dragPos && dropPos) { - CClip& dragClip = m_editList.GetAt(dragPos); - m_editList.InsertAfter(dropPos, dragClip); - m_editList.RemoveAt(dragPos); - m_list.Invalidate(); - } -} - -void CEditListEditor::OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (pItem->iItem < 0) { - return; - } - - if (pItem->iSubItem == COL_NAME) { - *pResult = TRUE; - } -} - -void CEditListEditor::OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (pItem->iItem < 0) { - return; - } - - if (m_curPos && pItem->iSubItem == COL_NAME) { - CClip& curClip = m_editList.GetAt(m_curPos); - int nSel = FindNameIndex(curClip.GetName()); - - CAtlList sl; - for (int i = 0; i < m_nameList.GetCount(); i++) { - sl.AddTail(m_nameList.GetAt(i)); - } - m_list.ShowInPlaceComboBox(pItem->iItem, pItem->iSubItem, sl, nSel, true); - - *pResult = TRUE; - } -} - -void CEditListEditor::OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (!m_list.m_fInPlaceDirty) { - return; - } - - if (pItem->iItem < 0) { - return; - } - - CString& curName = m_nameList.GetAt(pItem->lParam); - - if (m_curPos && pItem->iSubItem == COL_NAME) { - CClip& curClip = m_editList.GetAt(m_curPos); - curClip.SetName(curName); - - *pResult = TRUE; - } -} +/* + * (C) 2009-2018 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 . + * + */ + +#include "stdafx.h" +#include "resource.h" +#include "EditListEditor.h" +#include "DSUtil.h" + + +CClip::CClip() + : m_rtIn(_I64_MIN) + , m_rtOut(_I64_MIN) +{ +} + +CClip::~CClip() +{ +} + +void CClip::SetIn(LPCTSTR strVal) +{ + m_rtIn = StringToReftime(strVal); +} + +void CClip::SetOut(LPCTSTR strVal) +{ + m_rtOut = StringToReftime(strVal); +} + +void CClip::SetIn(REFERENCE_TIME rtVal) +{ + m_rtIn = rtVal; + if (m_rtIn > m_rtOut) { + m_rtOut = _I64_MIN; + } +}; + +void CClip::SetOut(REFERENCE_TIME rtVal) +{ + m_rtOut = rtVal; + if (m_rtIn > m_rtOut) { + m_rtIn = _I64_MIN; + } +}; + +CString CClip::GetIn() const +{ + return m_rtIn == _I64_MIN ? CString() : ReftimeToString(m_rtIn); +} + +CString CClip::GetOut() const +{ + return m_rtOut == _I64_MIN ? CString() : ReftimeToString(m_rtOut); +} + +IMPLEMENT_DYNAMIC(CEditListEditor, CPlayerBar) +CEditListEditor::CEditListEditor() + : m_curPos(nullptr) + , m_bDragging(FALSE) + , m_nDragIndex(-1) + , m_nDropIndex(-1) + , m_pDragImage(nullptr) + , m_bFileOpen(false) +{ +} + +CEditListEditor::~CEditListEditor() +{ + SaveEditListToFile(); +} + +BEGIN_MESSAGE_MAP(CEditListEditor, CPlayerBar) + ON_WM_SIZE() + ON_NOTIFY(LVN_ITEMCHANGED, IDC_EDITLIST, OnLvnItemchanged) + ON_NOTIFY(LVN_KEYDOWN, IDC_EDITLIST, OnLvnKeyDown) + ON_WM_DRAWITEM() + ON_NOTIFY(LVN_BEGINDRAG, IDC_EDITLIST, OnBeginDrag) + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONUP() + ON_WM_TIMER() + ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_EDITLIST, OnBeginlabeleditList) + ON_NOTIFY(LVN_DOLABELEDIT, IDC_EDITLIST, OnDolabeleditList) + ON_NOTIFY(LVN_ENDLABELEDIT, IDC_EDITLIST, OnEndlabeleditList) +END_MESSAGE_MAP() + +BOOL CEditListEditor::Create(CWnd* pParentWnd, UINT defDockBarID) +{ + if (!__super::Create(ResStr(IDS_EDIT_LIST_EDITOR), pParentWnd, ID_VIEW_EDITLISTEDITOR, defDockBarID, _T("Edit List Editor"))) { + return FALSE; + } + + m_stUsers.Create(_T("User :"), WS_VISIBLE | WS_CHILD, CRect(5, 5, 100, 21), this, 0); + m_cbUsers.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(90, 0, 260, 21), this, 0); + FillCombo(_T("Users.txt"), m_cbUsers, false); + + m_stHotFolders.Create(_T("Hot folder :"), WS_VISIBLE | WS_CHILD, CRect(5, 35, 100, 51), this, 0); + m_cbHotFolders.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(90, 30, 260, 21), this, 0); + FillCombo(_T("HotFolders.txt"), m_cbHotFolders, true); + + m_list.CreateEx( + WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP + | LVS_OWNERDRAWFIXED + | LVS_REPORT | LVS_SINGLESEL | LVS_AUTOARRANGE | LVS_NOSORTHEADER, + CRect(0, 0, 100, 100), this, IDC_EDITLIST); + + m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); + + m_list.InsertColumn(COL_IN, _T("Nb."), LVCFMT_LEFT, 35); + m_list.InsertColumn(COL_IN, _T("In"), LVCFMT_LEFT, 100); + m_list.InsertColumn(COL_OUT, _T("Out"), LVCFMT_LEFT, 100); + m_list.InsertColumn(COL_NAME, _T("Name"), LVCFMT_LEFT, 150); + + m_fakeImageList.Create(1, 16, ILC_COLOR4, 10, 10); + m_list.SetImageList(&m_fakeImageList, LVSIL_SMALL); + + return TRUE; +} + +void CEditListEditor::ReloadTranslatableResources() +{ + SetWindowText(ResStr(IDS_EDIT_LIST_EDITOR)); +} + +void CEditListEditor::OnSize(UINT nType, int cx, int cy) +{ + __super::OnSize(nType, cx, cy); + + ResizeListColumn(); +} + +void CEditListEditor::ResizeListColumn() +{ + if (::IsWindow(m_list.m_hWnd)) { + CRect r; + GetClientRect(r); + r.DeflateRect(2, 2); + + r.top += 60; + m_list.SetRedraw(FALSE); + m_list.MoveWindow(r); + m_list.GetClientRect(r); + m_list.SetRedraw(TRUE); + } +} + +void CEditListEditor::SaveEditListToFile() +{ + if ((m_bFileOpen || !m_editList.IsEmpty()) && !m_strFileName.IsEmpty()) { + CStdioFile editListFile; + if (editListFile.Open(m_strFileName, CFile::modeCreate | CFile::modeWrite)) { + CString strLine; + int nIndex; + CString strUser; + CString strHotFolders; + + nIndex = m_cbUsers.GetCurSel(); + if (nIndex >= 0) { + m_cbUsers.GetLBText(nIndex, strUser); + } + + nIndex = m_cbHotFolders.GetCurSel(); + if (nIndex >= 0) { + m_cbHotFolders.GetLBText(nIndex, strHotFolders); + } + + POSITION pos = m_editList.GetHeadPosition(); + for (int i = 0; pos; i++, m_editList.GetNext(pos)) { + CClip& CurClip = m_editList.GetAt(pos); + + if (CurClip.HaveIn() && CurClip.HaveOut()) { + strLine.Format(_T("%s\t%s\t%s\t%s\t%s\n"), CurClip.GetIn().GetString(), CurClip.GetOut().GetString(), CurClip.GetName().GetString(), strUser.GetString(), strHotFolders.GetString()); + editListFile.WriteString(strLine); + } + } + + editListFile.Close(); + } + } +} + +void CEditListEditor::CloseFile() +{ + SaveEditListToFile(); + m_editList.RemoveAll(); + m_list.DeleteAllItems(); + m_curPos = nullptr; + m_strFileName.Empty(); + m_bFileOpen = false; + m_cbHotFolders.SetCurSel(0); +} + +void CEditListEditor::OpenFile(LPCTSTR lpFileName) +{ + CString strLine; + CStdioFile editListFile; + CString strUser; + CString strHotFolders; + + CloseFile(); + m_strFileName.Format(_T("%s.edl"), lpFileName); + + if (editListFile.Open(m_strFileName, CFile::modeRead)) { + m_bFileOpen = true; + while (editListFile.ReadString(strLine)) { + //int nPos = 0; + CString strIn; // = strLine.Tokenize(_T(" \t"), nPos); + CString strOut; // = strLine.Tokenize(_T(" \t"), nPos); + CString strName; // = strLine.Tokenize(_T(" \t"), nPos); + + AfxExtractSubString(strIn, strLine, 0, _T('\t')); + AfxExtractSubString(strOut, strLine, 1, _T('\t')); + AfxExtractSubString(strName, strLine, 2, _T('\t')); + if (strUser.IsEmpty()) { + AfxExtractSubString(strUser, strLine, 3, _T('\t')); + SelectCombo(strUser, m_cbUsers); + } + if (strHotFolders.IsEmpty()) { + AfxExtractSubString(strHotFolders, strLine, 4, _T('\t')); + SelectCombo(strHotFolders, m_cbHotFolders); + } + + if (!strIn.IsEmpty() && !strOut.IsEmpty()) { + CClip NewClip; + NewClip.SetIn(strIn); + NewClip.SetOut(strOut); + NewClip.SetName(strName); + + InsertClip(nullptr, NewClip); + } + } + + editListFile.Close(); + } else { + m_bFileOpen = false; + } + + if (m_nameList.IsEmpty()) { + CStdioFile nameFile; + CString str; + if (nameFile.Open(_T("EditListNames.txt"), CFile::modeRead)) { + while (nameFile.ReadString(str)) { + m_nameList.Add(str); + } + nameFile.Close(); + } + } +} + +void CEditListEditor::SetIn(REFERENCE_TIME rtIn) +{ + if (m_curPos) { + CClip& curClip = m_editList.GetAt(m_curPos); + + curClip.SetIn(rtIn); + m_list.Invalidate(); + } +} + +void CEditListEditor::SetOut(REFERENCE_TIME rtOut) +{ + if (m_curPos) { + CClip& curClip = m_editList.GetAt(m_curPos); + + curClip.SetOut(rtOut); + m_list.Invalidate(); + } +} + +void CEditListEditor::NewClip(REFERENCE_TIME rtVal) +{ + CClip newClip; + newClip.SetIn(rtVal); + + if (m_curPos) { + CClip& curClip = m_editList.GetAt(m_curPos); + + if (curClip.HaveIn()) { + if (!curClip.HaveOut()) { + curClip.SetOut(rtVal); + } + } + } + m_curPos = InsertClip(m_curPos, newClip); + m_list.Invalidate(); +} + +void CEditListEditor::Save() +{ + SaveEditListToFile(); +} + +POSITION CEditListEditor::InsertClip(POSITION pos, CClip& newClip) +{ + LVITEM lv; + POSITION newClipPos; + + if (pos == nullptr) { + newClipPos = m_editList.AddTail(newClip); + } else { + newClipPos = m_editList.InsertAfter(pos, newClip); + } + + lv.mask = LVIF_STATE | LVIF_TEXT; + lv.iItem = FindIndex(pos); + lv.iSubItem = 0; + lv.pszText = const_cast(_T("")); + lv.state = m_list.GetItemCount() == 0 ? LVIS_SELECTED : 0; + m_list.InsertItem(&lv); + + return newClipPos; +} + +int CEditListEditor::FindIndex(const POSITION pos) const +{ + int iItem = 0; + POSITION curPos = m_editList.GetHeadPosition(); + while (curPos && curPos != pos) { + m_editList.GetNext(curPos); + iItem++; + } + return iItem; +} + +int CEditListEditor::FindNameIndex(LPCTSTR strName) const +{ + int nResult = -1; + + for (int i = 0; i < m_nameList.GetCount(); i++) { + const CString& curName = m_nameList.GetAt(i); + + if (curName == strName) { + nResult = i; + break; + } + } + + return nResult; +} + +void CEditListEditor::FillCombo(LPCTSTR strFileName, CComboBox& combo, bool bAllowNull) +{ + CStdioFile nameFile; + CString str; + if (nameFile.Open(strFileName, CFile::modeRead)) { + if (bAllowNull) { + combo.AddString(_T("")); + } + + while (nameFile.ReadString(str)) { + combo.AddString(str); + } + nameFile.Close(); + } +} + +void CEditListEditor::SelectCombo(LPCTSTR strValue, CComboBox& combo) +{ + for (int i = 0; i < combo.GetCount(); i++) { + CString strTemp; + combo.GetLBText(i, strTemp); + if (strTemp == strValue) { + combo.SetCurSel(i); + break; + } + } +} + +void CEditListEditor::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (nIDCtl != IDC_EDITLIST) { + return; + } + + int nItem = lpDrawItemStruct->itemID; + CRect rcItem = lpDrawItemStruct->rcItem; + POSITION pos = m_editList.FindIndex(nItem); + + if (pos) { + bool fSelected = (pos == m_curPos); + UNREFERENCED_PARAMETER(fSelected); + CClip& curClip = m_editList.GetAt(pos); + CString strTemp; + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + + if (!!m_list.GetItemState(nItem, LVIS_SELECTED)) { + FillRect(pDC->m_hDC, rcItem, CBrush(0xf1dacc)); + FrameRect(pDC->m_hDC, rcItem, CBrush(0xc56a31)); + } else { + FillRect(pDC->m_hDC, rcItem, CBrush(GetSysColor(COLOR_WINDOW))); + } + + COLORREF textcolor = RGB(0, 0, 0); + if (!curClip.HaveIn() || !curClip.HaveOut()) { + textcolor = RGB(255, 0, 0); + } + + for (int i = 0; i < COL_MAX; i++) { + m_list.GetSubItemRect(nItem, i, LVIR_LABEL, rcItem); + pDC->SetTextColor(textcolor); + switch (i) { + case COL_INDEX: + strTemp.Format(_T("%d"), nItem + 1); + pDC->DrawText(strTemp, rcItem, DT_CENTER | DT_VCENTER); + break; + case COL_IN: + pDC->DrawText(curClip.GetIn(), rcItem, DT_CENTER | DT_VCENTER); + break; + case COL_OUT: + pDC->DrawText(curClip.GetOut(), rcItem, DT_CENTER | DT_VCENTER); + break; + case COL_NAME: + pDC->DrawText(curClip.GetName(), rcItem, DT_LEFT | DT_VCENTER); + break; + } + } + } +} + +void CEditListEditor::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); + + if (pNMLV->iItem >= 0) { + m_curPos = m_editList.FindIndex(pNMLV->iItem); + } +} + +void CEditListEditor::OnLvnKeyDown(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLVKEYDOWN pLVKeyDown = reinterpret_cast(pNMHDR); + + *pResult = FALSE; + + if (pLVKeyDown->wVKey == VK_DELETE) { + POSITION pos = m_list.GetFirstSelectedItemPosition(); + POSITION clipPos; + int nItem = -1; + while (pos) { + nItem = m_list.GetNextSelectedItem(pos); + clipPos = m_editList.FindIndex(nItem); + if (clipPos) { + m_editList.RemoveAt(clipPos); + } + m_list.DeleteItem(nItem); + } + if (nItem != -1) { + m_list.SetItemState(std::min(nItem, m_list.GetItemCount() - 1), LVIS_SELECTED, LVIS_SELECTED); + } + m_list.Invalidate(); + } +} + +void CEditListEditor::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) +{ + ModifyStyle(WS_EX_ACCEPTFILES, 0); + + m_nDragIndex = ((LPNMLISTVIEW)pNMHDR)->iItem; + + CPoint p(0, 0); + m_pDragImage = m_list.CreateDragImageEx(&p); + + CPoint p2 = ((LPNMLISTVIEW)pNMHDR)->ptAction; + + m_pDragImage->BeginDrag(0, p2 - p); + m_pDragImage->DragEnter(GetDesktopWindow(), ((LPNMLISTVIEW)pNMHDR)->ptAction); + + m_bDragging = TRUE; + m_nDropIndex = -1; + + SetCapture(); +} + +void CEditListEditor::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_bDragging) { + m_ptDropPoint = point; + ClientToScreen(&m_ptDropPoint); + + m_pDragImage->DragMove(m_ptDropPoint); + m_pDragImage->DragShowNolock(FALSE); + + WindowFromPoint(m_ptDropPoint)->ScreenToClient(&m_ptDropPoint); + + m_pDragImage->DragShowNolock(TRUE); + + { + int iOverItem = m_list.HitTest(m_ptDropPoint); + int iTopItem = m_list.GetTopIndex(); + int iBottomItem = m_list.GetBottomIndex(); + + if (iOverItem == iTopItem && iTopItem != 0) { // top of list + SetTimer(1, 100, nullptr); + } else { + KillTimer(1); + } + + if (iOverItem >= iBottomItem && iBottomItem != (m_list.GetItemCount() - 1)) { // bottom of list + SetTimer(2, 100, nullptr); + } else { + KillTimer(2); + } + } + } + + __super::OnMouseMove(nFlags, point); +} + +void CEditListEditor::OnTimer(UINT_PTR nIDEvent) +{ + int iTopItem = m_list.GetTopIndex(); + int iBottomItem = iTopItem + m_list.GetCountPerPage() - 1; + + if (m_bDragging) { + m_pDragImage->DragShowNolock(FALSE); + + if (nIDEvent == 1) { + m_list.EnsureVisible(iTopItem - 1, false); + m_list.UpdateWindow(); + if (m_list.GetTopIndex() == 0) { + KillTimer(1); + } + } else if (nIDEvent == 2) { + m_list.EnsureVisible(iBottomItem + 1, false); + m_list.UpdateWindow(); + if (m_list.GetBottomIndex() == (m_list.GetItemCount() - 1)) { + KillTimer(2); + } + } + + m_pDragImage->DragShowNolock(TRUE); + } + + __super::OnTimer(nIDEvent); +} + +void CEditListEditor::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (m_bDragging) { + ::ReleaseCapture(); + + m_bDragging = FALSE; + m_pDragImage->DragLeave(GetDesktopWindow()); + m_pDragImage->EndDrag(); + + delete m_pDragImage; + m_pDragImage = nullptr; + + KillTimer(1); + KillTimer(2); + + CPoint pt(point); + ClientToScreen(&pt); + + if (WindowFromPoint(pt) == &m_list) { + DropItemOnList(); + } + } + + ModifyStyle(0, WS_EX_ACCEPTFILES); + + __super::OnLButtonUp(nFlags, point); +} + +void CEditListEditor::DropItemOnList() +{ + m_ptDropPoint.y -= 10; + m_nDropIndex = m_list.HitTest(CPoint(10, m_ptDropPoint.y)); + + POSITION dragPos = m_editList.FindIndex(m_nDragIndex); + POSITION dropPos = m_editList.FindIndex(m_nDropIndex); + if (dragPos && dropPos) { + CClip& dragClip = m_editList.GetAt(dragPos); + m_editList.InsertAfter(dropPos, dragClip); + m_editList.RemoveAt(dragPos); + m_list.Invalidate(); + } +} + +void CEditListEditor::OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (pItem->iItem < 0) { + return; + } + + if (pItem->iSubItem == COL_NAME) { + *pResult = TRUE; + } +} + +void CEditListEditor::OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (pItem->iItem < 0) { + return; + } + + if (m_curPos && pItem->iSubItem == COL_NAME) { + CClip& curClip = m_editList.GetAt(m_curPos); + int nSel = FindNameIndex(curClip.GetName()); + + CAtlList sl; + for (int i = 0; i < m_nameList.GetCount(); i++) { + sl.AddTail(m_nameList.GetAt(i)); + } + m_list.ShowInPlaceComboBox(pItem->iItem, pItem->iSubItem, sl, nSel, true); + + *pResult = TRUE; + } +} + +void CEditListEditor::OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (!m_list.m_fInPlaceDirty) { + return; + } + + if (pItem->iItem < 0) { + return; + } + + CString& curName = m_nameList.GetAt(pItem->lParam); + + if (m_curPos && pItem->iSubItem == COL_NAME) { + CClip& curClip = m_editList.GetAt(m_curPos); + curClip.SetName(curName); + + *pResult = TRUE; + } +} diff --git a/src/mpc-hc/EditListEditor.h b/src/mpc-hc/EditListEditor.h index 26c3b40dc01..261698cb890 100644 --- a/src/mpc-hc/EditListEditor.h +++ b/src/mpc-hc/EditListEditor.h @@ -1,121 +1,121 @@ -/* - * (C) 2009-2014 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 . - * - */ - -#pragma once - -#include "PlayerBar.h" -#include "PlayerListCtrl.h" - - -class CClip -{ -private: - REFERENCE_TIME m_rtIn; - REFERENCE_TIME m_rtOut; - CString m_strName; - -public: - CClip(); - ~CClip(); - - bool HaveIn() const { return m_rtIn != _I64_MIN; }; - bool HaveOut() const { return m_rtOut != _I64_MIN; }; - - void SetIn(LPCTSTR strVal); - void SetOut(LPCTSTR strVal); - void SetIn(REFERENCE_TIME rtVal); - void SetOut(REFERENCE_TIME rtVal); - void SetName(LPCTSTR strName) { m_strName = strName; }; - - CString GetIn() const; - CString GetOut() const; - CString GetName() const { return m_strName; }; -}; - -class CEditListEditor : public CPlayerBar -{ - DECLARE_DYNAMIC(CEditListEditor) - -private: - enum { - COL_INDEX, - COL_IN, - COL_OUT, - COL_NAME, - COL_MAX - }; - - CPlayerListCtrl m_list; - CStatic m_stUsers; - CComboBox m_cbUsers; - CStatic m_stHotFolders; - CComboBox m_cbHotFolders; - CImageList m_fakeImageList; - POSITION m_curPos; - BOOL m_bDragging; - int m_nDragIndex; - int m_nDropIndex; - CPoint m_ptDropPoint; - CImageList* m_pDragImage; - - CString m_strFileName; - bool m_bFileOpen; - CList m_editList; - CArray m_nameList; - - void SaveEditListToFile(); - void ResizeListColumn(); - POSITION InsertClip(POSITION pos, CClip& newClip); - void DropItemOnList(); - int FindIndex(const POSITION pos) const; - int FindNameIndex(LPCTSTR strName) const; - void FillCombo(LPCTSTR strFileName, CComboBox& combo, bool bAllowNull); - void SelectCombo(LPCTSTR strValue, CComboBox& combo); - -public: - CEditListEditor(); - ~CEditListEditor(); - - BOOL Create(CWnd* pParentWnd, UINT defDockBarID); - - virtual void ReloadTranslatableResources(); - - void CloseFile(); - void OpenFile(LPCTSTR lpFileName); - void SetIn(REFERENCE_TIME rtIn); - void SetOut(REFERENCE_TIME rtOut); - void NewClip(REFERENCE_TIME rtVal); - void Save(); - -protected: - DECLARE_MESSAGE_MAP() - - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnLvnKeyDown(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); - afx_msg void OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnTimer(UINT_PTR nIDEvent); - afx_msg void OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult); -}; +/* + * (C) 2009-2014 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 . + * + */ + +#pragma once + +#include "PlayerBar.h" +#include "PlayerListCtrl.h" + + +class CClip +{ +private: + REFERENCE_TIME m_rtIn; + REFERENCE_TIME m_rtOut; + CString m_strName; + +public: + CClip(); + ~CClip(); + + bool HaveIn() const { return m_rtIn != _I64_MIN; }; + bool HaveOut() const { return m_rtOut != _I64_MIN; }; + + void SetIn(LPCTSTR strVal); + void SetOut(LPCTSTR strVal); + void SetIn(REFERENCE_TIME rtVal); + void SetOut(REFERENCE_TIME rtVal); + void SetName(LPCTSTR strName) { m_strName = strName; }; + + CString GetIn() const; + CString GetOut() const; + CString GetName() const { return m_strName; }; +}; + +class CEditListEditor : public CPlayerBar +{ + DECLARE_DYNAMIC(CEditListEditor) + +private: + enum { + COL_INDEX, + COL_IN, + COL_OUT, + COL_NAME, + COL_MAX + }; + + CPlayerListCtrl m_list; + CStatic m_stUsers; + CComboBox m_cbUsers; + CStatic m_stHotFolders; + CComboBox m_cbHotFolders; + CImageList m_fakeImageList; + POSITION m_curPos; + BOOL m_bDragging; + int m_nDragIndex; + int m_nDropIndex; + CPoint m_ptDropPoint; + CImageList* m_pDragImage; + + CString m_strFileName; + bool m_bFileOpen; + CList m_editList; + CArray m_nameList; + + void SaveEditListToFile(); + void ResizeListColumn(); + POSITION InsertClip(POSITION pos, CClip& newClip); + void DropItemOnList(); + int FindIndex(const POSITION pos) const; + int FindNameIndex(LPCTSTR strName) const; + void FillCombo(LPCTSTR strFileName, CComboBox& combo, bool bAllowNull); + void SelectCombo(LPCTSTR strValue, CComboBox& combo); + +public: + CEditListEditor(); + ~CEditListEditor(); + + BOOL Create(CWnd* pParentWnd, UINT defDockBarID); + + virtual void ReloadTranslatableResources(); + + void CloseFile(); + void OpenFile(LPCTSTR lpFileName); + void SetIn(REFERENCE_TIME rtIn); + void SetOut(REFERENCE_TIME rtOut); + void NewClip(REFERENCE_TIME rtVal); + void Save(); + +protected: + DECLARE_MESSAGE_MAP() + + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnLvnKeyDown(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); + afx_msg void OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnTimer(UINT_PTR nIDEvent); + afx_msg void OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult); +}; diff --git a/src/mpc-hc/EditWithButton.cpp b/src/mpc-hc/EditWithButton.cpp index 64c038672b7..e31c5ba79c6 100644 --- a/src/mpc-hc/EditWithButton.cpp +++ b/src/mpc-hc/EditWithButton.cpp @@ -1,363 +1,363 @@ -#include "stdafx.h" -#include "EditWithButton.h" - -#define WM_EDITWITHBUTTON_RECALCNCSIZE (WM_USER + 200) // arbitrary number. hopefully no conflicts - - -// CEditWithButton_Base --------------------------------------------------------------------------- - -CEditWithButton_Base::CEditWithButton_Base() - : m_TopBorder(0) - , m_BottomBorder(0) - , m_LeftBorder(0) - , m_RightBorder(0) - , m_ButtonWidth(1) - , m_IsButtonPressed(false) - , m_IsMouseActive(false) - , m_IsButtonHot(false) -{ -} - -BEGIN_MESSAGE_MAP(CEditWithButton_Base, CEdit) - ON_WM_NCCALCSIZE() - ON_WM_NCPAINT() - ON_WM_NCLBUTTONDOWN() - ON_WM_MOUSEMOVE() - ON_WM_NCMOUSEMOVE() - ON_WM_NCMOUSELEAVE() - ON_WM_LBUTTONUP() - ON_WM_NCHITTEST() - ON_MESSAGE(WM_EDITWITHBUTTON_RECALCNCSIZE, OnRecalcNcSize) - ON_WM_NCDESTROY() - ON_WM_ENABLE() - ON_MESSAGE(EM_SETREADONLY, OnSetReadOnly) -END_MESSAGE_MAP() - -CRect CEditWithButton_Base::GetButtonRect(const CRect& rectWindow) const -{ - CRect rectButton(rectWindow); - rectButton.top += m_TopBorder; - rectButton.bottom -= m_BottomBorder; - rectButton.right -= m_RightBorder; - rectButton.left = rectButton.right - m_ButtonWidth; - - // take into account any scrollbars in the edit control - if (rectButton.right > rectButton.left) { - rectButton.OffsetRect(m_RightBorder - m_LeftBorder, 0); - } - - return rectButton; -} - -int CEditWithButton_Base::GetButtonThemeState() const -{ - if (GetStyle() & (ES_READONLY | WS_DISABLED)) { - return PBS_DISABLED; - } else if (m_IsButtonPressed) { - return PBS_PRESSED; - } else if (m_IsButtonHot) { - return PBS_HOT; - } else { - return PBS_NORMAL; - } -} - -void CEditWithButton_Base::DrawButton(CRect rectButton) -{ - CWindowDC dc(this); - - HTHEME hButtonTheme = OpenThemeData(m_hWnd, _T("Button")); - if (hButtonTheme) { - int ButtonState = GetButtonThemeState(); - - // If necessary, first fill with the edit control's background color. - if (IsThemeBackgroundPartiallyTransparent(hButtonTheme, BP_PUSHBUTTON, ButtonState)) { - HTHEME hEditTheme = OpenThemeDataEx(m_hWnd, _T("Edit"), OTD_NONCLIENT); - - COLORREF BgColor = GetThemeSysColor(hEditTheme, (GetStyle() & (ES_READONLY | WS_DISABLED)) ? COLOR_3DFACE : COLOR_WINDOW); - dc.FillSolidRect(rectButton, BgColor); - - CloseThemeData(hEditTheme); - } - - DrawThemeBackground(hButtonTheme, dc, BP_PUSHBUTTON, ButtonState, rectButton, nullptr); - - DrawButtonContent(dc, rectButton, hButtonTheme); - - CloseThemeData(hButtonTheme); - } else { - UINT uState = DFCS_BUTTONPUSH; - if (GetStyle() & (ES_READONLY | WS_DISABLED)) { - uState |= DFCS_INACTIVE; - } else if (m_IsButtonPressed) { - uState |= DFCS_PUSHED; - } - dc.DrawFrameControl(rectButton, DFC_BUTTON, uState); - - // If the button is in a pressed state, then contents should move slightly as part of the "push" effect. - if (m_IsButtonPressed) { - rectButton.OffsetRect(1, 1); - } - - DrawButtonContent(dc, rectButton, nullptr); - } -} - -void CEditWithButton_Base::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) -{ - CRect rectOld = lpncsp->rgrc[0]; - - // Let the default processing setup space of the usual screen elements (borders, etc) - CEdit::OnNcCalcSize(bCalcValidRects, lpncsp); - - // Store the current size of the borders, so we know where to put the button - m_TopBorder = lpncsp->rgrc[0].top - rectOld.top; - m_BottomBorder = rectOld.bottom - lpncsp->rgrc[0].bottom; - m_LeftBorder = lpncsp->rgrc[0].left - rectOld.left; - m_RightBorder = rectOld.right - lpncsp->rgrc[0].right; - - m_ButtonWidth = CalculateButtonWidth(); - - // Deflate the right side, making room for our button - lpncsp->rgrc[0].right -= m_ButtonWidth; -} - -void CEditWithButton_Base::OnNcPaint() -{ - // Allow default processing - CEdit::OnNcPaint(); - - CRect rectWindow; - GetWindowRect(rectWindow); - // Adjust coords to start at 0,0 - rectWindow.OffsetRect(-rectWindow.TopLeft()); - - CRect rectButton = GetButtonRect(rectWindow); - - DrawButton(rectButton); -} - -void CEditWithButton_Base::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - if (!(GetStyle() & (ES_READONLY | WS_DISABLED))) { - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - if (rectButton.PtInRect(point)) { - SetCapture(); - - m_IsButtonPressed = true; - m_IsMouseActive = true; - - // Redraw the button to reflect the change - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - } - } - - CEdit::OnNcLButtonDown(nHitTest, point); -} - -void CEditWithButton_Base::OnMouseMove(UINT nFlags, CPoint point) -{ - if (m_IsMouseActive) { - ClientToScreen(&point); - - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - bool OldState = m_IsButtonPressed; - - m_IsButtonPressed = rectButton.PtInRect(point) != FALSE; - - // If the button state has changed, redraw it to reflect the change - if (OldState != m_IsButtonPressed) { - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - } - } - - CEdit::OnMouseMove(nFlags, point); -} - -void CEditWithButton_Base::OnNcMouseMove(UINT nHitTest, CPoint point) -{ - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - bool OldState = m_IsButtonHot; - m_IsButtonHot = rectButton.PtInRect(point) != FALSE; - // If the button state has changed, redraw it to reflect the change - if (OldState != m_IsButtonHot) { - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - // If the state has changed to hot, register to get the WM_NCMOUSELEAVE notification. - if (m_IsButtonHot) { - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(tme); - tme.dwFlags = TME_LEAVE | TME_NONCLIENT; - tme.hwndTrack = m_hWnd; - tme.dwHoverTime = HOVER_DEFAULT; - _TrackMouseEvent(&tme); - } - } - - CEdit::OnNcMouseMove(nHitTest, point); -} - -void CEditWithButton_Base::OnNcMouseLeave() -{ - CPoint point; - GetCursorPos(&point); - - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - // We may get this message either when the mouse actually leaves the client area - // or when the user clicks the mouse on the button. So we must check whether or - // not the cursor has actually left the button area. If so, then update the hot - // state and prompt a redraw of the button. - if (!rectButton.PtInRect(point)) { - m_IsButtonHot = false; - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - } - - CEdit::OnNcMouseLeave(); -} - -void CEditWithButton_Base::OnLButtonUp(UINT nFlags, CPoint point) -{ - if (m_IsMouseActive) { - ReleaseCapture(); - - ClientToScreen(&point); - - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - // Reset the button to a "normal" state. - m_IsButtonHot = false; - m_IsButtonPressed = false; - m_IsMouseActive = false; - - // Redraw the button to reflect the changes. - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - // Run the on-click logic if appropriate. - if (rectButton.PtInRect(point)) { - OnLeftClick(); - } - } - - CEdit::OnLButtonUp(nFlags, point); -} - -LRESULT CEditWithButton_Base::OnNcHitTest(CPoint point) -{ - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - if (rectButton.PtInRect(point)) { - return HTBORDER; - } - - return CEdit::OnNcHitTest(point); -} - -void CEditWithButton_Base::PreSubclassWindow() -{ - CEdit::PreSubclassWindow(); - - // Because our WindowProc is not yet in place, we need to post a message - PostMessage(WM_EDITWITHBUTTON_RECALCNCSIZE); -} - -LRESULT CEditWithButton_Base::OnRecalcNcSize(WPARAM wParam, LPARAM lParam) -{ - // Prompt a WM_NCCALCSIZE to be issued - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - return 0; -} - -void CEditWithButton_Base::OnEnable(BOOL bEnable) -{ - // Let all the default handling happen. - CEdit::OnEnable(bEnable); - - // Prompt the button area to redraw. - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); -} - -LRESULT CEditWithButton_Base::OnSetReadOnly(WPARAM wParam, LPARAM lParam) -{ - // Let all the default handling happen. - LRESULT r = DefWindowProc(EM_SETREADONLY, wParam, lParam); - - // Prompt the button area to redraw. - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - return r; -} - -void CEditWithButton_Base::OnLeftClick() -{ - PostMessage(EDIT_BUTTON_LEFTCLICKED); -} - - - -// CEditWithButton -------------------------------------------------------------------------------- - -CEditWithButton::CEditWithButton(LPCTSTR pszButtonText) - : m_ButtonText(pszButtonText) -{ -} - -CString CEditWithButton::GetButtonText() const -{ - return m_ButtonText; -} - -void CEditWithButton::SetButtonText(LPCTSTR buttonText) -{ - m_ButtonText = buttonText; - - // If this is a live window, then prompt the button area to redraw. - if (IsWindow(m_hWnd)) { - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - } -} - -void CEditWithButton::DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme) -{ - CFont* pOldFont = dc.SelectObject(GetFont()); - - if (hButtonTheme) { - DrawThemeText(hButtonTheme, dc.m_hDC, BP_PUSHBUTTON, GetButtonThemeState(), - m_ButtonText, m_ButtonText.GetLength(), - DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, rectButton); - } else { - if (GetStyle() & (ES_READONLY | WS_DISABLED)) { - dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); - } - - dc.SetBkMode(TRANSPARENT); - dc.DrawText(m_ButtonText, m_ButtonText.GetLength(), - rectButton, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } - - dc.SelectObject(pOldFont); -} - -int CEditWithButton::CalculateButtonWidth() -{ - CWindowDC dc(this); - return dc.GetTextExtent(' ' + m_ButtonText + ' ').cx; - // Note: For readability, we need some space between the text and the side borders of the button. - // A simple way to accomplish this is to pad the string with spaces when calculating the width. -} +#include "stdafx.h" +#include "EditWithButton.h" + +#define WM_EDITWITHBUTTON_RECALCNCSIZE (WM_USER + 200) // arbitrary number. hopefully no conflicts + + +// CEditWithButton_Base --------------------------------------------------------------------------- + +CEditWithButton_Base::CEditWithButton_Base() + : m_TopBorder(0) + , m_BottomBorder(0) + , m_LeftBorder(0) + , m_RightBorder(0) + , m_ButtonWidth(1) + , m_IsButtonPressed(false) + , m_IsMouseActive(false) + , m_IsButtonHot(false) +{ +} + +BEGIN_MESSAGE_MAP(CEditWithButton_Base, CEdit) + ON_WM_NCCALCSIZE() + ON_WM_NCPAINT() + ON_WM_NCLBUTTONDOWN() + ON_WM_MOUSEMOVE() + ON_WM_NCMOUSEMOVE() + ON_WM_NCMOUSELEAVE() + ON_WM_LBUTTONUP() + ON_WM_NCHITTEST() + ON_MESSAGE(WM_EDITWITHBUTTON_RECALCNCSIZE, OnRecalcNcSize) + ON_WM_NCDESTROY() + ON_WM_ENABLE() + ON_MESSAGE(EM_SETREADONLY, OnSetReadOnly) +END_MESSAGE_MAP() + +CRect CEditWithButton_Base::GetButtonRect(const CRect& rectWindow) const +{ + CRect rectButton(rectWindow); + rectButton.top += m_TopBorder; + rectButton.bottom -= m_BottomBorder; + rectButton.right -= m_RightBorder; + rectButton.left = rectButton.right - m_ButtonWidth; + + // take into account any scrollbars in the edit control + if (rectButton.right > rectButton.left) { + rectButton.OffsetRect(m_RightBorder - m_LeftBorder, 0); + } + + return rectButton; +} + +int CEditWithButton_Base::GetButtonThemeState() const +{ + if (GetStyle() & (ES_READONLY | WS_DISABLED)) { + return PBS_DISABLED; + } else if (m_IsButtonPressed) { + return PBS_PRESSED; + } else if (m_IsButtonHot) { + return PBS_HOT; + } else { + return PBS_NORMAL; + } +} + +void CEditWithButton_Base::DrawButton(CRect rectButton) +{ + CWindowDC dc(this); + + HTHEME hButtonTheme = OpenThemeData(m_hWnd, _T("Button")); + if (hButtonTheme) { + int ButtonState = GetButtonThemeState(); + + // If necessary, first fill with the edit control's background color. + if (IsThemeBackgroundPartiallyTransparent(hButtonTheme, BP_PUSHBUTTON, ButtonState)) { + HTHEME hEditTheme = OpenThemeDataEx(m_hWnd, _T("Edit"), OTD_NONCLIENT); + + COLORREF BgColor = GetThemeSysColor(hEditTheme, (GetStyle() & (ES_READONLY | WS_DISABLED)) ? COLOR_3DFACE : COLOR_WINDOW); + dc.FillSolidRect(rectButton, BgColor); + + CloseThemeData(hEditTheme); + } + + DrawThemeBackground(hButtonTheme, dc, BP_PUSHBUTTON, ButtonState, rectButton, nullptr); + + DrawButtonContent(dc, rectButton, hButtonTheme); + + CloseThemeData(hButtonTheme); + } else { + UINT uState = DFCS_BUTTONPUSH; + if (GetStyle() & (ES_READONLY | WS_DISABLED)) { + uState |= DFCS_INACTIVE; + } else if (m_IsButtonPressed) { + uState |= DFCS_PUSHED; + } + dc.DrawFrameControl(rectButton, DFC_BUTTON, uState); + + // If the button is in a pressed state, then contents should move slightly as part of the "push" effect. + if (m_IsButtonPressed) { + rectButton.OffsetRect(1, 1); + } + + DrawButtonContent(dc, rectButton, nullptr); + } +} + +void CEditWithButton_Base::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) +{ + CRect rectOld = lpncsp->rgrc[0]; + + // Let the default processing setup space of the usual screen elements (borders, etc) + CEdit::OnNcCalcSize(bCalcValidRects, lpncsp); + + // Store the current size of the borders, so we know where to put the button + m_TopBorder = lpncsp->rgrc[0].top - rectOld.top; + m_BottomBorder = rectOld.bottom - lpncsp->rgrc[0].bottom; + m_LeftBorder = lpncsp->rgrc[0].left - rectOld.left; + m_RightBorder = rectOld.right - lpncsp->rgrc[0].right; + + m_ButtonWidth = CalculateButtonWidth(); + + // Deflate the right side, making room for our button + lpncsp->rgrc[0].right -= m_ButtonWidth; +} + +void CEditWithButton_Base::OnNcPaint() +{ + // Allow default processing + CEdit::OnNcPaint(); + + CRect rectWindow; + GetWindowRect(rectWindow); + // Adjust coords to start at 0,0 + rectWindow.OffsetRect(-rectWindow.TopLeft()); + + CRect rectButton = GetButtonRect(rectWindow); + + DrawButton(rectButton); +} + +void CEditWithButton_Base::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + if (!(GetStyle() & (ES_READONLY | WS_DISABLED))) { + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + if (rectButton.PtInRect(point)) { + SetCapture(); + + m_IsButtonPressed = true; + m_IsMouseActive = true; + + // Redraw the button to reflect the change + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + CEdit::OnNcLButtonDown(nHitTest, point); +} + +void CEditWithButton_Base::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_IsMouseActive) { + ClientToScreen(&point); + + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + bool OldState = m_IsButtonPressed; + + m_IsButtonPressed = rectButton.PtInRect(point) != FALSE; + + // If the button state has changed, redraw it to reflect the change + if (OldState != m_IsButtonPressed) { + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + CEdit::OnMouseMove(nFlags, point); +} + +void CEditWithButton_Base::OnNcMouseMove(UINT nHitTest, CPoint point) +{ + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + bool OldState = m_IsButtonHot; + m_IsButtonHot = rectButton.PtInRect(point) != FALSE; + // If the button state has changed, redraw it to reflect the change + if (OldState != m_IsButtonHot) { + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + // If the state has changed to hot, register to get the WM_NCMOUSELEAVE notification. + if (m_IsButtonHot) { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE | TME_NONCLIENT; + tme.hwndTrack = m_hWnd; + tme.dwHoverTime = HOVER_DEFAULT; + _TrackMouseEvent(&tme); + } + } + + CEdit::OnNcMouseMove(nHitTest, point); +} + +void CEditWithButton_Base::OnNcMouseLeave() +{ + CPoint point; + GetCursorPos(&point); + + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + // We may get this message either when the mouse actually leaves the client area + // or when the user clicks the mouse on the button. So we must check whether or + // not the cursor has actually left the button area. If so, then update the hot + // state and prompt a redraw of the button. + if (!rectButton.PtInRect(point)) { + m_IsButtonHot = false; + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } + + CEdit::OnNcMouseLeave(); +} + +void CEditWithButton_Base::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (m_IsMouseActive) { + ReleaseCapture(); + + ClientToScreen(&point); + + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + // Reset the button to a "normal" state. + m_IsButtonHot = false; + m_IsButtonPressed = false; + m_IsMouseActive = false; + + // Redraw the button to reflect the changes. + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + // Run the on-click logic if appropriate. + if (rectButton.PtInRect(point)) { + OnLeftClick(); + } + } + + CEdit::OnLButtonUp(nFlags, point); +} + +LRESULT CEditWithButton_Base::OnNcHitTest(CPoint point) +{ + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + if (rectButton.PtInRect(point)) { + return HTBORDER; + } + + return CEdit::OnNcHitTest(point); +} + +void CEditWithButton_Base::PreSubclassWindow() +{ + CEdit::PreSubclassWindow(); + + // Because our WindowProc is not yet in place, we need to post a message + PostMessage(WM_EDITWITHBUTTON_RECALCNCSIZE); +} + +LRESULT CEditWithButton_Base::OnRecalcNcSize(WPARAM wParam, LPARAM lParam) +{ + // Prompt a WM_NCCALCSIZE to be issued + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + return 0; +} + +void CEditWithButton_Base::OnEnable(BOOL bEnable) +{ + // Let all the default handling happen. + CEdit::OnEnable(bEnable); + + // Prompt the button area to redraw. + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); +} + +LRESULT CEditWithButton_Base::OnSetReadOnly(WPARAM wParam, LPARAM lParam) +{ + // Let all the default handling happen. + LRESULT r = DefWindowProc(EM_SETREADONLY, wParam, lParam); + + // Prompt the button area to redraw. + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + return r; +} + +void CEditWithButton_Base::OnLeftClick() +{ + PostMessage(EDIT_BUTTON_LEFTCLICKED); +} + + + +// CEditWithButton -------------------------------------------------------------------------------- + +CEditWithButton::CEditWithButton(LPCTSTR pszButtonText) + : m_ButtonText(pszButtonText) +{ +} + +CString CEditWithButton::GetButtonText() const +{ + return m_ButtonText; +} + +void CEditWithButton::SetButtonText(LPCTSTR buttonText) +{ + m_ButtonText = buttonText; + + // If this is a live window, then prompt the button area to redraw. + if (IsWindow(m_hWnd)) { + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } +} + +void CEditWithButton::DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme) +{ + CFont* pOldFont = dc.SelectObject(GetFont()); + + if (hButtonTheme) { + DrawThemeText(hButtonTheme, dc.m_hDC, BP_PUSHBUTTON, GetButtonThemeState(), + m_ButtonText, m_ButtonText.GetLength(), + DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, rectButton); + } else { + if (GetStyle() & (ES_READONLY | WS_DISABLED)) { + dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); + } + + dc.SetBkMode(TRANSPARENT); + dc.DrawText(m_ButtonText, m_ButtonText.GetLength(), + rectButton, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + + dc.SelectObject(pOldFont); +} + +int CEditWithButton::CalculateButtonWidth() +{ + CWindowDC dc(this); + return dc.GetTextExtent(' ' + m_ButtonText + ' ').cx; + // Note: For readability, we need some space between the text and the side borders of the button. + // A simple way to accomplish this is to pad the string with spaces when calculating the width. +} diff --git a/src/mpc-hc/EditWithButton.h b/src/mpc-hc/EditWithButton.h index 9ef99cbf689..7582a58ac37 100644 --- a/src/mpc-hc/EditWithButton.h +++ b/src/mpc-hc/EditWithButton.h @@ -1,113 +1,113 @@ -/* - Edit With Button - - This class acts mostly like a normal Edit Box except that it provides a button to the right - side of the control. Clicking the button invokes the virutal OnLeftClick method. If that - has not been overridden in a derived classes then it sends the EDIT_BUTTON_LEFTCLICKED - message to the parent window. - - CEditWithButton_Base contains most of the code to make this work but cannot be instantiated - itself. A derived class must override DrawButtonContent and CalculateButtonWidth to determine - what is actually drawn for the button. - - CEditWithButton is a derived class that handles the simplest form of a button where a plain - text string is displayed on the button. - - Other classes could be derived to draw other kinds of buttons. -*/ -#pragma once - -#include -#include "UxTheme.h" - - -// May be sent to the parent window when the edit control's button is clicked. -// wParam will be set to the ID of the control that sent the message. -#define EDIT_BUTTON_LEFTCLICKED (WM_APP + 842) // arbitrary number, change if necessary - - -// CEditWithButton_Base --------------------------------------------------------------------------- -// This is the base class from which others derive to implement specific kinds of buttons. -class CEditWithButton_Base : public CEdit -{ -public: - CEditWithButton_Base(); - - // Called when a left click is detected. The default implementation will send a - // EDIT_BUTTON_LEFTCLICKED message to the parent window. Derived classes - // could override this to handle the event themselves, and so are not required - // to call this base implementation. - virtual void OnLeftClick(); - -protected: - afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); - afx_msg void OnNcPaint(); - afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point); - afx_msg void OnNcMouseLeave(); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg LRESULT OnNcHitTest(CPoint point); - virtual void PreSubclassWindow(); - afx_msg LRESULT OnRecalcNcSize(WPARAM wParam, LPARAM lParam); - afx_msg void OnEnable(BOOL bEnable); - afx_msg LRESULT OnSetReadOnly(WPARAM wParam, LPARAM lParam); - DECLARE_MESSAGE_MAP() - - // Given the rectangle of the control window, this returns the rect that the button will occupy. - CRect GetButtonRect(const CRect& rectWindow) const; - - // Translates the current button state in a value that could be used by DrawThemeBackground. - int GetButtonThemeState() const; - - // Called when the button needs to be drawn. - // The default implementation draws the button frame, adjusts the rect if - // the button is pressed, and then calls DrawButtonContent to render the - // contents of the button. - virtual void DrawButton(CRect rectButton); - - // Called when the button contents (anything inside the button's border) needs to - // be drawn. The rect will have already been adjusted if the button is pressed. - // The content must be drawn using the given device context within the given rect. - virtual void DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme) = 0; - - // Called when the button's width needs to be (re)calculated. - // This must return the width in pixels. - virtual int CalculateButtonWidth() = 0; - -private: - - int m_TopBorder; - int m_BottomBorder; - int m_LeftBorder; - int m_RightBorder; - - int m_ButtonWidth; // stores the button's width in pixels (so that we don't have to re-calculate it) - - bool m_IsButtonPressed; - bool m_IsMouseActive; - - bool m_IsButtonHot; -}; - - -// CEditWithButton -------------------------------------------------------------------------------- -// This implements a button containing plain text. -class CEditWithButton : public CEditWithButton_Base -{ -public: - // The given text will be displayed in the button. - explicit CEditWithButton(LPCTSTR pszButtonText = _T("...")); - - // Gets/Sets the button text. - CString GetButtonText() const; - void SetButtonText(LPCTSTR buttonText); - -private: - - virtual void DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme); - - virtual int CalculateButtonWidth(); - - CString m_ButtonText; -}; +/* + Edit With Button + + This class acts mostly like a normal Edit Box except that it provides a button to the right + side of the control. Clicking the button invokes the virutal OnLeftClick method. If that + has not been overridden in a derived classes then it sends the EDIT_BUTTON_LEFTCLICKED + message to the parent window. + + CEditWithButton_Base contains most of the code to make this work but cannot be instantiated + itself. A derived class must override DrawButtonContent and CalculateButtonWidth to determine + what is actually drawn for the button. + + CEditWithButton is a derived class that handles the simplest form of a button where a plain + text string is displayed on the button. + + Other classes could be derived to draw other kinds of buttons. +*/ +#pragma once + +#include +#include "UxTheme.h" + + +// May be sent to the parent window when the edit control's button is clicked. +// wParam will be set to the ID of the control that sent the message. +#define EDIT_BUTTON_LEFTCLICKED (WM_APP + 842) // arbitrary number, change if necessary + + +// CEditWithButton_Base --------------------------------------------------------------------------- +// This is the base class from which others derive to implement specific kinds of buttons. +class CEditWithButton_Base : public CEdit +{ +public: + CEditWithButton_Base(); + + // Called when a left click is detected. The default implementation will send a + // EDIT_BUTTON_LEFTCLICKED message to the parent window. Derived classes + // could override this to handle the event themselves, and so are not required + // to call this base implementation. + virtual void OnLeftClick(); + +protected: + afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); + afx_msg void OnNcPaint(); + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point); + afx_msg void OnNcMouseLeave(); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg LRESULT OnNcHitTest(CPoint point); + virtual void PreSubclassWindow(); + afx_msg LRESULT OnRecalcNcSize(WPARAM wParam, LPARAM lParam); + afx_msg void OnEnable(BOOL bEnable); + afx_msg LRESULT OnSetReadOnly(WPARAM wParam, LPARAM lParam); + DECLARE_MESSAGE_MAP() + + // Given the rectangle of the control window, this returns the rect that the button will occupy. + CRect GetButtonRect(const CRect& rectWindow) const; + + // Translates the current button state in a value that could be used by DrawThemeBackground. + int GetButtonThemeState() const; + + // Called when the button needs to be drawn. + // The default implementation draws the button frame, adjusts the rect if + // the button is pressed, and then calls DrawButtonContent to render the + // contents of the button. + virtual void DrawButton(CRect rectButton); + + // Called when the button contents (anything inside the button's border) needs to + // be drawn. The rect will have already been adjusted if the button is pressed. + // The content must be drawn using the given device context within the given rect. + virtual void DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme) = 0; + + // Called when the button's width needs to be (re)calculated. + // This must return the width in pixels. + virtual int CalculateButtonWidth() = 0; + +private: + + int m_TopBorder; + int m_BottomBorder; + int m_LeftBorder; + int m_RightBorder; + + int m_ButtonWidth; // stores the button's width in pixels (so that we don't have to re-calculate it) + + bool m_IsButtonPressed; + bool m_IsMouseActive; + + bool m_IsButtonHot; +}; + + +// CEditWithButton -------------------------------------------------------------------------------- +// This implements a button containing plain text. +class CEditWithButton : public CEditWithButton_Base +{ +public: + // The given text will be displayed in the button. + explicit CEditWithButton(LPCTSTR pszButtonText = _T("...")); + + // Gets/Sets the button text. + CString GetButtonText() const; + void SetButtonText(LPCTSTR buttonText); + +private: + + virtual void DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme); + + virtual int CalculateButtonWidth(); + + CString m_ButtonText; +}; diff --git a/src/mpc-hc/ExceptionHandler.cpp b/src/mpc-hc/ExceptionHandler.cpp index 1760e9837a4..bb1aaf3c655 100644 --- a/src/mpc-hc/ExceptionHandler.cpp +++ b/src/mpc-hc/ExceptionHandler.cpp @@ -1,213 +1,213 @@ -/* - * (C) 2017 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 . - * - */ - -#include "stdafx.h" -#include "ExceptionHandler.h" -#include -#include -#include -#include "mplayerc.h" - -#ifndef _DEBUG - -LPCWSTR GetExceptionName(DWORD code) -{ - switch (code) { - case EXCEPTION_ACCESS_VIOLATION: - return _T("ACCESS VIOLATION"); - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - return _T("ARRAY BOUNDS EXCEEDED"); - case EXCEPTION_BREAKPOINT: - return _T("BREAKPOINT"); - case EXCEPTION_DATATYPE_MISALIGNMENT: - return _T("DATATYPE MISALIGNMENT"); - case EXCEPTION_FLT_DENORMAL_OPERAND: - return _T("FLT DENORMAL OPERAND"); - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - return _T("FLT DIVIDE BY ZERO"); - case EXCEPTION_FLT_INEXACT_RESULT: - return _T("FLT INEXACT RESULT"); - case EXCEPTION_FLT_INVALID_OPERATION: - return _T("FLT INVALID OPERATION"); - case EXCEPTION_FLT_OVERFLOW: - return _T("FLT OVERFLOW"); - case EXCEPTION_FLT_STACK_CHECK: - return _T("FLT STACK CHECK"); - case EXCEPTION_FLT_UNDERFLOW: - return _T("FLT UNDERFLOW"); - case EXCEPTION_GUARD_PAGE: - return _T("GUARD PAGE"); - case EXCEPTION_ILLEGAL_INSTRUCTION: - return _T("ILLEGAL_INSTRUCTION"); - case EXCEPTION_IN_PAGE_ERROR: - return _T("IN PAGE ERROR"); - case EXCEPTION_INT_DIVIDE_BY_ZERO: - return _T("INT DIVIDE BY ZERO"); - case EXCEPTION_INT_OVERFLOW: - return _T("INT OVERFLOW"); - case EXCEPTION_INVALID_DISPOSITION: - return _T("INVALID DISPOSITION"); - case EXCEPTION_INVALID_HANDLE: - return _T("INVALID HANDLE"); - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - return _T("NONCONTINUABLE EXCEPTION"); - case EXCEPTION_PRIV_INSTRUCTION: - return _T("PRIV INSTRUCTION"); - case EXCEPTION_SINGLE_STEP: - return _T("SINGLE STEP"); - case EXCEPTION_STACK_OVERFLOW: - return _T("STACK OVERFLOW"); - case 0xE06D7363: - return _T("UNDEFINED C++ EXCEPTION"); - default: - return _T("[UNKNOWN]"); - } -} - -HMODULE GetExceptionModule(LPVOID address, LPWSTR moduleName) -{ - HMODULE moduleList[1024]; - DWORD sizeNeeded = 0; - if (!EnumProcessModules(GetCurrentProcess(), moduleList, sizeof(moduleList), &sizeNeeded) || sizeNeeded > sizeof(moduleList)) { - return nullptr; - } - - int curModule = -1; - for (DWORD i = 0; i < (sizeNeeded / sizeof(HMODULE)); ++i) { - if (moduleList[i] < address) { - if (curModule == -1) { - curModule = i; - } else { - if (moduleList[curModule] < moduleList[i]) { - curModule = i; - } - } - } - } - - if (curModule == -1) { - return nullptr; - } - - if (!GetModuleFileName(moduleList[curModule], moduleName, MAX_PATH)) { - return nullptr; - } - - return moduleList[curModule]; -} - -void HandleCommonException(LPEXCEPTION_POINTERS exceptionInfo) -{ - wchar_t message[MAX_PATH + 255]; - wchar_t module[MAX_PATH]; - const wchar_t* moduleName = GetExceptionModule(exceptionInfo->ExceptionRecord->ExceptionAddress, module) ? module : _T("[UNKNOWN]"); - - const uintptr_t codeBase = uintptr_t(GetModuleHandle(nullptr)); - const uintptr_t offset = uintptr_t(exceptionInfo->ExceptionRecord->ExceptionAddress) - codeBase; - - swprintf_s(message, _countof(message), _T(\ - "An error has occurred. MPC-HC will close now.\n\n"\ - "Exception:\n%s\n\n"\ - "Crashing module:\n%s\n"\ - "Offset: 0x%" PRIXPTR ", Codebase: 0x%" PRIXPTR "\n\n"), - GetExceptionName(exceptionInfo->ExceptionRecord->ExceptionCode), - moduleName, - offset, - codeBase); - - MessageBox(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), message, _T("Unexpected error"), MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_SYSTEMMODAL); -} - -void HandleAccessViolation(LPEXCEPTION_POINTERS exceptionInfo) -{ - wchar_t message[MAX_PATH + 255]; - wchar_t module[MAX_PATH]; - const wchar_t* moduleName = GetExceptionModule(exceptionInfo->ExceptionRecord->ExceptionAddress, module) ? module : _T("[UNKNOWN]"); - - const uintptr_t codeBase = uintptr_t(GetModuleHandle(nullptr)); - const uintptr_t offset = uintptr_t(exceptionInfo->ExceptionRecord->ExceptionAddress) - codeBase; - - const wchar_t* accessType; - switch (exceptionInfo->ExceptionRecord->ExceptionInformation[0]) { - case 0: - accessType = _T("read"); - break; - case 1: - accessType = _T("write"); - break; - case 2: - accessType = _T("execute"); - break; - default: - accessType = _T("[UNKNOWN]"); - break; - } - - swprintf_s(message, _countof(message), _T(\ - "An error has occurred. MPC-HC will close now.\n\n"\ - "Exception:\n%s\n\n"\ - "Crashing module:\n%s\n"\ - "Offset: 0x%" PRIXPTR ", Codebase: 0x%" PRIXPTR "\n"\ - "The thread %lu tried to %s memory at address 0x%" PRIXPTR "\n\n"), - GetExceptionName(exceptionInfo->ExceptionRecord->ExceptionCode), - moduleName, - offset, - codeBase, - GetCurrentThreadId(), - accessType, - exceptionInfo->ExceptionRecord->ExceptionInformation[1]); - - MessageBox(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), message, _T("Unexpected error"), MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_SYSTEMMODAL); -} - -LONG WINAPI UnhandledException(LPEXCEPTION_POINTERS exceptionInfo) -{ -#if 1 - if (AfxGetMyApp()->m_fClosingState) { - return EXCEPTION_EXECUTE_HANDLER; - } -#endif - - switch (exceptionInfo->ExceptionRecord->ExceptionCode) { - case EXCEPTION_ACCESS_VIOLATION: - HandleAccessViolation(exceptionInfo); - break; - default: - HandleCommonException(exceptionInfo); - break; - } - - return EXCEPTION_EXECUTE_HANDLER; -} -#endif - -void MPCExceptionHandler::Enable() -{ -#ifndef _DEBUG - SetUnhandledExceptionFilter(UnhandledException); -#endif -}; - -void MPCExceptionHandler::Disable() -{ -#ifndef _DEBUG - SetUnhandledExceptionFilter(nullptr); -#endif -}; +/* + * (C) 2017 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 . + * + */ + +#include "stdafx.h" +#include "ExceptionHandler.h" +#include +#include +#include +#include "mplayerc.h" + +#ifndef _DEBUG + +LPCWSTR GetExceptionName(DWORD code) +{ + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + return _T("ACCESS VIOLATION"); + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return _T("ARRAY BOUNDS EXCEEDED"); + case EXCEPTION_BREAKPOINT: + return _T("BREAKPOINT"); + case EXCEPTION_DATATYPE_MISALIGNMENT: + return _T("DATATYPE MISALIGNMENT"); + case EXCEPTION_FLT_DENORMAL_OPERAND: + return _T("FLT DENORMAL OPERAND"); + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return _T("FLT DIVIDE BY ZERO"); + case EXCEPTION_FLT_INEXACT_RESULT: + return _T("FLT INEXACT RESULT"); + case EXCEPTION_FLT_INVALID_OPERATION: + return _T("FLT INVALID OPERATION"); + case EXCEPTION_FLT_OVERFLOW: + return _T("FLT OVERFLOW"); + case EXCEPTION_FLT_STACK_CHECK: + return _T("FLT STACK CHECK"); + case EXCEPTION_FLT_UNDERFLOW: + return _T("FLT UNDERFLOW"); + case EXCEPTION_GUARD_PAGE: + return _T("GUARD PAGE"); + case EXCEPTION_ILLEGAL_INSTRUCTION: + return _T("ILLEGAL_INSTRUCTION"); + case EXCEPTION_IN_PAGE_ERROR: + return _T("IN PAGE ERROR"); + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return _T("INT DIVIDE BY ZERO"); + case EXCEPTION_INT_OVERFLOW: + return _T("INT OVERFLOW"); + case EXCEPTION_INVALID_DISPOSITION: + return _T("INVALID DISPOSITION"); + case EXCEPTION_INVALID_HANDLE: + return _T("INVALID HANDLE"); + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return _T("NONCONTINUABLE EXCEPTION"); + case EXCEPTION_PRIV_INSTRUCTION: + return _T("PRIV INSTRUCTION"); + case EXCEPTION_SINGLE_STEP: + return _T("SINGLE STEP"); + case EXCEPTION_STACK_OVERFLOW: + return _T("STACK OVERFLOW"); + case 0xE06D7363: + return _T("UNDEFINED C++ EXCEPTION"); + default: + return _T("[UNKNOWN]"); + } +} + +HMODULE GetExceptionModule(LPVOID address, LPWSTR moduleName) +{ + HMODULE moduleList[1024]; + DWORD sizeNeeded = 0; + if (!EnumProcessModules(GetCurrentProcess(), moduleList, sizeof(moduleList), &sizeNeeded) || sizeNeeded > sizeof(moduleList)) { + return nullptr; + } + + int curModule = -1; + for (DWORD i = 0; i < (sizeNeeded / sizeof(HMODULE)); ++i) { + if (moduleList[i] < address) { + if (curModule == -1) { + curModule = i; + } else { + if (moduleList[curModule] < moduleList[i]) { + curModule = i; + } + } + } + } + + if (curModule == -1) { + return nullptr; + } + + if (!GetModuleFileName(moduleList[curModule], moduleName, MAX_PATH)) { + return nullptr; + } + + return moduleList[curModule]; +} + +void HandleCommonException(LPEXCEPTION_POINTERS exceptionInfo) +{ + wchar_t message[MAX_PATH + 255]; + wchar_t module[MAX_PATH]; + const wchar_t* moduleName = GetExceptionModule(exceptionInfo->ExceptionRecord->ExceptionAddress, module) ? module : _T("[UNKNOWN]"); + + const uintptr_t codeBase = uintptr_t(GetModuleHandle(nullptr)); + const uintptr_t offset = uintptr_t(exceptionInfo->ExceptionRecord->ExceptionAddress) - codeBase; + + swprintf_s(message, _countof(message), _T(\ + "An error has occurred. MPC-HC will close now.\n\n"\ + "Exception:\n%s\n\n"\ + "Crashing module:\n%s\n"\ + "Offset: 0x%" PRIXPTR ", Codebase: 0x%" PRIXPTR "\n\n"), + GetExceptionName(exceptionInfo->ExceptionRecord->ExceptionCode), + moduleName, + offset, + codeBase); + + MessageBox(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), message, _T("Unexpected error"), MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_SYSTEMMODAL); +} + +void HandleAccessViolation(LPEXCEPTION_POINTERS exceptionInfo) +{ + wchar_t message[MAX_PATH + 255]; + wchar_t module[MAX_PATH]; + const wchar_t* moduleName = GetExceptionModule(exceptionInfo->ExceptionRecord->ExceptionAddress, module) ? module : _T("[UNKNOWN]"); + + const uintptr_t codeBase = uintptr_t(GetModuleHandle(nullptr)); + const uintptr_t offset = uintptr_t(exceptionInfo->ExceptionRecord->ExceptionAddress) - codeBase; + + const wchar_t* accessType; + switch (exceptionInfo->ExceptionRecord->ExceptionInformation[0]) { + case 0: + accessType = _T("read"); + break; + case 1: + accessType = _T("write"); + break; + case 2: + accessType = _T("execute"); + break; + default: + accessType = _T("[UNKNOWN]"); + break; + } + + swprintf_s(message, _countof(message), _T(\ + "An error has occurred. MPC-HC will close now.\n\n"\ + "Exception:\n%s\n\n"\ + "Crashing module:\n%s\n"\ + "Offset: 0x%" PRIXPTR ", Codebase: 0x%" PRIXPTR "\n"\ + "The thread %lu tried to %s memory at address 0x%" PRIXPTR "\n\n"), + GetExceptionName(exceptionInfo->ExceptionRecord->ExceptionCode), + moduleName, + offset, + codeBase, + GetCurrentThreadId(), + accessType, + exceptionInfo->ExceptionRecord->ExceptionInformation[1]); + + MessageBox(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), message, _T("Unexpected error"), MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_SYSTEMMODAL); +} + +LONG WINAPI UnhandledException(LPEXCEPTION_POINTERS exceptionInfo) +{ +#if 1 + if (AfxGetMyApp()->m_fClosingState) { + return EXCEPTION_EXECUTE_HANDLER; + } +#endif + + switch (exceptionInfo->ExceptionRecord->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + HandleAccessViolation(exceptionInfo); + break; + default: + HandleCommonException(exceptionInfo); + break; + } + + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +void MPCExceptionHandler::Enable() +{ +#ifndef _DEBUG + SetUnhandledExceptionFilter(UnhandledException); +#endif +}; + +void MPCExceptionHandler::Disable() +{ +#ifndef _DEBUG + SetUnhandledExceptionFilter(nullptr); +#endif +}; diff --git a/src/mpc-hc/ExceptionHandler.h b/src/mpc-hc/ExceptionHandler.h index b776997f267..e1094b74576 100644 --- a/src/mpc-hc/ExceptionHandler.h +++ b/src/mpc-hc/ExceptionHandler.h @@ -1,27 +1,27 @@ -/* - * (C) 2017 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 . - * - */ - -#pragma once - -namespace MPCExceptionHandler -{ - void Enable(); - void Disable(); -}; +/* + * (C) 2017 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 . + * + */ + +#pragma once + +namespace MPCExceptionHandler +{ + void Enable(); + void Disable(); +}; diff --git a/src/mpc-hc/FGFilter.cpp b/src/mpc-hc/FGFilter.cpp index 72ab9ba32e0..8954c933044 100644 --- a/src/mpc-hc/FGFilter.cpp +++ b/src/mpc-hc/FGFilter.cpp @@ -1,778 +1,778 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "FGFilter.h" -#include "MainFrm.h" -#include "DSUtil.h" -#include "IPinHook.h" // For the NVIDIA driver bug work-around -#include "uuids.h" -#include "moreuuids.h" -#include - -#include -#include "AllocatorCommon.h" -#include "SyncAllocatorPresenter.h" - -#define LOG_FILTER_INSERT 0 - -#if !TRACE_GRAPH_BUILD -#undef TRACE -#define TRACE(...) -#endif - -// -// CFGFilter -// - -CFGFilter::CFGFilter(const CLSID& clsid, CStringW name, UINT64 merit) - : m_clsid(clsid) - , m_name(name) -{ - m_merit.val = merit; -} - -CFGFilter::~CFGFilter() -{ -} - -const CAtlList& CFGFilter::GetTypes() const -{ - return m_types; -} - -void CFGFilter::SetTypes(const CAtlList& types) -{ - m_types.RemoveAll(); - m_types.AddTailList(&types); -} - -void CFGFilter::AddType(const GUID& majortype, const GUID& subtype) -{ - m_types.AddTail(majortype); - m_types.AddTail(subtype); -} - -bool CFGFilter::CheckTypes(const CAtlArray& types, bool fExactMatch) -{ - POSITION pos = m_types.GetHeadPosition(); - while (pos) { - const GUID& majortype = m_types.GetNext(pos); - if (!pos) { - ASSERT(0); - break; - } - const GUID& subtype = m_types.GetNext(pos); - - for (int i = 0, len = types.GetCount() & ~1; i < len; i += 2) { - if (fExactMatch) { - if (majortype == types[i] && majortype != GUID_NULL - && subtype == types[i + 1] && subtype != GUID_NULL) { - return true; - } - } else { - if ((majortype == GUID_NULL || types[i] == GUID_NULL || majortype == types[i]) - && (subtype == GUID_NULL || types[i + 1] == GUID_NULL || subtype == types[i + 1])) { - return true; - } - } - } - } - - return false; -} - -// -// CFGFilterRegistry -// - -CFGFilterRegistry::CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit) - : CFGFilter(GUID_NULL, L"", merit) - , m_pMoniker(pMoniker) -{ - if (!m_pMoniker) { - return; - } - - CComHeapPtr str; - if (FAILED(m_pMoniker->GetDisplayName(0, 0, &str))) { - return; - } - m_DisplayName = m_name = str; - - QueryProperties(); - - if (merit != MERIT64_DO_USE) { - m_merit.val = merit; - } -} - -CFGFilterRegistry::CFGFilterRegistry(CStringW DisplayName, UINT64 merit) - : CFGFilter(GUID_NULL, L"", merit) - , m_DisplayName(DisplayName) -{ - if (m_DisplayName.IsEmpty()) { - return; - } - - CComPtr pBC; - CreateBindCtx(0, &pBC); - - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBC, CComBSTR(m_DisplayName), &chEaten, &m_pMoniker)) { - return; - } - - QueryProperties(); - - if (merit != MERIT64_DO_USE) { - m_merit.val = merit; - } -} - -void CFGFilterRegistry::QueryProperties() -{ - ASSERT(m_pMoniker); - CComPtr pPB; - if (SUCCEEDED(m_pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)))) { - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - m_name = var.bstrVal; - var.Clear(); - } - - if (SUCCEEDED(pPB->Read(_T("CLSID"), &var, nullptr))) { - CLSIDFromString(var.bstrVal, &m_clsid); - var.Clear(); - } - - if (SUCCEEDED(pPB->Read(_T("FilterData"), &var, nullptr))) { - BSTR* pstr; - if (SUCCEEDED(SafeArrayAccessData(var.parray, (void**)&pstr))) { - ExtractFilterData((BYTE*)pstr, var.parray->cbElements * (var.parray->rgsabound[0].cElements)); - SafeArrayUnaccessData(var.parray); - } - - var.Clear(); - } - } -} - -CFGFilterRegistry::CFGFilterRegistry(const CLSID& clsid, UINT64 merit) - : CFGFilter(clsid, L"", merit) -{ - if (m_clsid == GUID_NULL) { - return; - } - - CString guid = CStringFromGUID(m_clsid); - - CRegKey key; - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + guid, KEY_READ)) { - ULONG nChars = 0; - if (ERROR_SUCCESS == key.QueryStringValue(nullptr, nullptr, &nChars)) { - CString name; - if (ERROR_SUCCESS == key.QueryStringValue(nullptr, name.GetBuffer(nChars), &nChars)) { - name.ReleaseBuffer(nChars); - m_name = name; - } - } - - key.Close(); - } - - CRegKey catkey; - - if (ERROR_SUCCESS == catkey.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance"), KEY_READ)) { - if (ERROR_SUCCESS != key.Open(catkey, guid, KEY_READ)) { - // illiminable pack uses the name of the filter and not the clsid, have to enum all keys to find it... - - FILETIME ft; - TCHAR buff[256]; - DWORD len = _countof(buff); - for (DWORD i = 0; ERROR_SUCCESS == catkey.EnumKey(i, buff, &len, &ft); i++, len = _countof(buff)) { - if (ERROR_SUCCESS == key.Open(catkey, buff, KEY_READ)) { - TCHAR clsidString[256]; - len = _countof(clsidString); - if (ERROR_SUCCESS == key.QueryStringValue(_T("CLSID"), clsidString, &len) - && GUIDFromCString(clsidString) == m_clsid) { - break; - } - - key.Close(); - } - } - } - - if (key) { - ULONG nChars = 0; - if (ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), nullptr, &nChars)) { - CString name; - if (ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), name.GetBuffer(nChars), &nChars)) { - name.ReleaseBuffer(nChars); - m_name = name; - } - } - - ULONG nBytes = 0; - if (ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), nullptr, &nBytes)) { - CAutoVectorPtr buff; - if (buff.Allocate(nBytes) && ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), buff, &nBytes)) { - ExtractFilterData(buff, nBytes); - } - } - - key.Close(); - } - } - - if (merit != MERIT64_DO_USE) { - m_merit.val = merit; - } -} - -HRESULT CFGFilterRegistry::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - CheckPointer(ppBF, E_POINTER); - - HRESULT hr = E_FAIL; - - if (m_pMoniker) { - if (SUCCEEDED(hr = m_pMoniker->BindToObject(0, 0, IID_PPV_ARGS(ppBF)))) { - m_clsid = ::GetCLSID(*ppBF); - } - } else if (m_clsid != GUID_NULL) { - CComQIPtr pBF; - - if (FAILED(pBF.CoCreateInstance(m_clsid))) { - return E_FAIL; - } - - *ppBF = pBF.Detach(); - - hr = S_OK; - } - - return hr; -}; - -interface __declspec(uuid("97f7c4d4-547b-4a5f-8332-536430ad2e4d")) - IAMFilterData : - public IUnknown -{ - STDMETHOD(ParseFilterData)(BYTE* rgbFilterData, ULONG cb, BYTE** prgbRegFilter2) PURE; - STDMETHOD(CreateFilterData)(REGFILTER2* prf2, BYTE** prgbFilterData, ULONG* pcb) PURE; -}; - -void CFGFilterRegistry::ExtractFilterData(BYTE* p, UINT len) -{ - CComPtr pFD; - BYTE* ptr = nullptr; - - if (SUCCEEDED(pFD.CoCreateInstance(CLSID_FilterMapper2)) - && SUCCEEDED(pFD->ParseFilterData(p, len, (BYTE**)&ptr))) { - REGFILTER2* prf = (REGFILTER2*) * (WPARAM*)ptr; // this is f*cked up - - m_merit.mid = prf->dwMerit; - - if (prf->dwVersion == 1) { - for (UINT i = 0; i < prf->cPins; i++) { - if (prf->rgPins[i].bOutput) { - continue; - } - - for (UINT j = 0; j < prf->rgPins[i].nMediaTypes; j++) { - if (!prf->rgPins[i].lpMediaType[j].clsMajorType || !prf->rgPins[i].lpMediaType[j].clsMinorType) { - break; - } - - const REGPINTYPES& rpt = prf->rgPins[i].lpMediaType[j]; - AddType(*rpt.clsMajorType, *rpt.clsMinorType); - } - } - } else if (prf->dwVersion == 2) { - for (UINT i = 0; i < prf->cPins2; i++) { - if (prf->rgPins2[i].dwFlags & REG_PINFLAG_B_OUTPUT) { - continue; - } - - for (UINT j = 0; j < prf->rgPins2[i].nMediaTypes; j++) { - if (!prf->rgPins2[i].lpMediaType[j].clsMajorType || !prf->rgPins2[i].lpMediaType[j].clsMinorType) { - break; - } - - const REGPINTYPES& rpt = prf->rgPins2[i].lpMediaType[j]; - AddType(*rpt.clsMajorType, *rpt.clsMinorType); - } - } - } - - CoTaskMemFree(prf); - } else { - BYTE* base = p; - -#define ChkLen(size) if (p - base + size > (int)len) return; - - ChkLen(4) - if (*(DWORD*)p != 0x00000002) { - return; // only version 2 supported, no samples found for 1 - } - p += 4; - - ChkLen(4) - m_merit.mid = *(DWORD*)p; - p += 4; - - m_types.RemoveAll(); - - ChkLen(8) - DWORD nPins = *(DWORD*)p; - p += 8; - while (nPins-- > 0) { - ChkLen(1) - BYTE n = *p - 0x30; - p++; - UNREFERENCED_PARAMETER(n); - - ChkLen(2) - WORD pi = *(WORD*)p; - p += 2; - ASSERT(pi == 'ip'); - UNREFERENCED_PARAMETER(pi); - - ChkLen(1) - BYTE x33 = *p; - p++; - ASSERT(x33 == 0x33); - UNREFERENCED_PARAMETER(x33); - - ChkLen(8) - bool fOutput = !!(*p & REG_PINFLAG_B_OUTPUT); - p += 8; - - ChkLen(12) - DWORD nTypes = *(DWORD*)p; - p += 12; - while (nTypes-- > 0) { - ChkLen(1) - n = *p - 0x30; - p++; - UNREFERENCED_PARAMETER(n); - - ChkLen(2) - WORD ty = *(WORD*)p; - p += 2; - ASSERT(ty == 'yt'); - UNREFERENCED_PARAMETER(ty); - - ChkLen(5) - x33 = *p; - p++; - ASSERT(x33 == 0x33); - UNREFERENCED_PARAMETER(x33); - p += 4; - - ChkLen(8) - if (*(DWORD*)p < (DWORD)(p - base + 8) || *(DWORD*)p >= len - || *(DWORD*)(p + 4) < (DWORD)(p - base + 8) || *(DWORD*)(p + 4) >= len) { - p += 8; - continue; - } - - GUID majortype, subtype; - memcpy(&majortype, &base[*(DWORD*)p], sizeof(GUID)); - p += 4; - if (!fOutput) { - AddType(majortype, subtype); - } - } - } - -#undef ChkLen - } -} - -// -// CFGFilterFile -// - -CFGFilterFile::CFGFilterFile(const CLSID& clsid, CString path, CStringW name, UINT64 merit) - : CFGFilter(clsid, name, merit) - , m_path(path) - , m_hInst(nullptr) -{ -} - -HRESULT CFGFilterFile::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - CheckPointer(ppBF, E_POINTER); - - return LoadExternalFilter(m_path, m_clsid, ppBF); -} - -// -// CFGFilterVideoRenderer -// - -CFGFilterVideoRenderer::CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name, UINT64 merit, bool preview) - : CFGFilter(clsid, name, merit) - , m_hWnd(hWnd) - , m_bHasHookReceiveConnection(false) - , m_bIsPreview(preview) -{ - bool mpcvr = (clsid == CLSID_MPCVR || clsid == CLSID_MPCVRAllocatorPresenter); - bool madvr = (clsid == CLSID_madVR || clsid == CLSID_madVRAllocatorPresenter); - bool evr = (clsid == CLSID_EnhancedVideoRenderer || clsid == CLSID_EVRAllocatorPresenter || clsid == CLSID_SyncAllocatorPresenter); - - // List is based on filter registration data from madVR. - // ToDo: Some subtypes might only work with madVR. Figure out which ones and add them conditionally for extra efficiency. - - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV12); // 0 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_NV12); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yv12); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_nv12); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM1); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM3); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM4); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_NV21); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_IYUV); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_I420); // 10 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUY2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuy2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YVYU); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYVY); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_uyvy); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_cyuv); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYNV); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYNY); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_HDYC); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_uyv1); // 20 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_2Vu1); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_VDTZ); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUV2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuv2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_2vuy); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_2Vuy); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuvu); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuvs); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV16); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_I422); // 30 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y422); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_V422); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y42B); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P422); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUNV); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_VYUY); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVUI); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_AYUV); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV24); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_I444); // 40 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v308); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v408); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB24); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB32); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_24BG); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_BGRA); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ABGR); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGBA); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB0); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_0RGB); // 50 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_b48r); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RBA64); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_64RBA); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_b64a); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P010); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P210); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y210); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v210); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y410); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v410); // 60 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P016); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P216); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y216); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v216); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y416); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v416); // 66 - - if (mpcvr) { - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y8); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y16); - } - - if (mpcvr || evr) { - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ARGB32); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_A2R10G10B10); - } -} - -CFGFilterVideoRenderer::~CFGFilterVideoRenderer() -{ - if (m_bHasHookReceiveConnection) { - UnhookReceiveConnection(); - } -} - -HRESULT CFGFilterVideoRenderer::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - TRACE(_T("--> CFGFilterVideoRenderer::Create on thread: %lu\n"), GetCurrentThreadId()); - CheckPointer(ppBF, E_POINTER); - - HRESULT hr; - CComPtr pCAP; - - auto isD3DFullScreenMode = []() { - auto pMainFrame = dynamic_cast(AfxGetApp()->m_pMainWnd); - ASSERT(pMainFrame); - return pMainFrame && pMainFrame->IsD3DFullScreenMode(); - }; - - if (m_clsid == CLSID_EVRAllocatorPresenter) { - CheckNoLog(CreateEVR(m_clsid, m_hWnd, !m_bIsPreview && isD3DFullScreenMode(), &pCAP, m_bIsPreview)); - } else if (m_clsid == CLSID_SyncAllocatorPresenter) { - CheckNoLog(CreateSyncRenderer(m_clsid, m_hWnd, isD3DFullScreenMode(), &pCAP)); - } else if (m_clsid == CLSID_MPCVRAllocatorPresenter || m_clsid == CLSID_madVRAllocatorPresenter || - m_clsid == CLSID_VMR9AllocatorPresenter || m_clsid == CLSID_DXRAllocatorPresenter) { - CheckNoLog(CreateAP9(m_clsid, m_hWnd, isD3DFullScreenMode(), &pCAP)); - } else { - CComPtr pBF; - CheckNoLog(pBF.CoCreateInstance(m_clsid)); - - if (m_clsid == CLSID_EnhancedVideoRenderer) { - CComQIPtr pConfig = pBF; - pConfig->SetNumberOfStreams(m_bIsPreview ? 1 : 3); - - if (CComQIPtr pMFGS = pBF) { - CComPtr pMFVDC; - if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVDC)))) { - pMFVDC->SetVideoWindow(m_hWnd); - if (m_bIsPreview) { - pMFVDC->SetRenderingPrefs(MFVideoRenderPrefs_DoNotRepaintOnStop); - } - } - } - } else if (m_clsid == CLSID_VideoMixingRenderer9) { - if (m_bIsPreview) { - CComQIPtr pConfig = pBF; - - if (pConfig) { - pConfig->SetRenderingMode(VMR9Mode_Windowless); - CComQIPtr pControl = pBF; - if (pControl) { - pControl->SetVideoClippingWindow(m_hWnd); - } - } - } - } - - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pMPC = pPin) { - pUnks.AddTail(pMPC); - break; - } - } - EndEnumPins; - - *ppBF = pBF.Detach(); - } - - if (pCAP) { - CComPtr pRenderer; - CheckNoLog(pCAP->CreateRenderer(&pRenderer)); - - *ppBF = CComQIPtr(pRenderer).Detach(); - - if (m_clsid == CLSID_MPCVRAllocatorPresenter) { - auto pMainFrame = (CMainFrame*)(AfxGetApp()->m_pMainWnd); - if (pMainFrame && pMainFrame->HasDedicatedFSVideoWindow()) { - if (CComQIPtr pD3DFSC = *ppBF) { - pD3DFSC->SetD3DFullscreen(true); - } - } - // renderer supports calling IVideoWindow::put_Owner before the pins are connected - if (CComQIPtr pVW = *ppBF) { - VERIFY(SUCCEEDED(pVW->put_Owner((OAHWND)m_hWnd))); - } - } else if (m_clsid == CLSID_madVRAllocatorPresenter) { - if (CComQIPtr pMVRSR = pCAP) { - VERIFY(SUCCEEDED(pMVRSR->DisableSubclassing())); - } - // renderer supports calling IVideoWindow::put_Owner before the pins are connected - if (CComQIPtr pVW = *ppBF) { - VERIFY(SUCCEEDED(pVW->put_Owner((OAHWND)m_hWnd))); - } - } - - pUnks.AddTail(pCAP); - if (CComQIPtr pCAP2 = pCAP) { - pUnks.AddTail(pCAP2); - } - if (CComQIPtr pCAP3 = pCAP) { - pUnks.AddTail(pCAP3); - } - } - - CheckPointer(*ppBF, E_FAIL); - - if (!m_bIsPreview && (m_clsid == CLSID_EnhancedVideoRenderer || m_clsid == CLSID_EVRAllocatorPresenter || m_clsid == CLSID_SyncAllocatorPresenter || m_clsid == CLSID_VMR9AllocatorPresenter)) { - m_bHasHookReceiveConnection = HookReceiveConnection(*ppBF); - } - - return hr; -} - -// -// CFGFilterList -// - -CFGFilterList::CFGFilterList() -{ -} - -CFGFilterList::~CFGFilterList() -{ - RemoveAll(); -} - -void CFGFilterList::RemoveAll() -{ - while (!m_filters.IsEmpty()) { - const filter_t& f = m_filters.RemoveHead(); - if (f.autodelete) { - delete f.pFGF; - } - } - - m_sortedfilters.RemoveAll(); -} - -void CFGFilterList::Insert(CFGFilter* pFGF, int group, bool exactmatch, bool autodelete) -{ - bool bInsert = true; - -#if DEBUG & LOG_FILTER_INSERT - bool do_log = pFGF->GetMerit() != MERIT64_DO_NOT_USE; - if (do_log) { - TRACE(_T("FGM: Inserting %d %d %016I64x %s\n"), group, exactmatch, pFGF->GetMerit(), - pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()).GetString() : CString(pFGF->GetName()).GetString()); - } -#endif - - CLSID insert_clsid = pFGF->GetCLSID(); - - POSITION pos = m_filters.GetHeadPosition(); - while (pos) { - filter_t& f = m_filters.GetNext(pos); - - if (pFGF == f.pFGF) { - bInsert = false; -#if DEBUG & LOG_FILTER_INSERT - if (do_log) { - TRACE(_T("FGM: ^ duplicate (exact)\n")); - } -#endif - break; - } - - // Filters are inserted in this order: - // 1) Internal filters - // 2) Renderers - // 3) Overrides - // 4) Registry - - if (insert_clsid != GUID_NULL && insert_clsid == f.pFGF->GetCLSID()) { - // Exact same filter if name also identical. Name is different for the internal filters, and those should be handled as different filters. - // Blacklisted filters can have empty name. - if (f.pFGF->GetMerit() == MERIT64_DO_NOT_USE || pFGF->GetName() == f.pFGF->GetName()) { - bInsert = false; -#if DEBUG & LOG_FILTER_INSERT - if (do_log) { - TRACE(_T("FGM: ^ duplicate\n")); - } -#endif - break; - } - } - - if (group != f.group) { - continue; - } - - CFGFilterRegistry* pFGFR = dynamic_cast(pFGF); - if (pFGFR && pFGFR->GetMoniker()) { - CFGFilterRegistry* pFGFR2 = dynamic_cast(f.pFGF); - if (pFGFR2 && pFGFR2->GetMoniker() && S_OK == pFGFR->GetMoniker()->IsEqual(pFGFR2->GetMoniker())) { - bInsert = false; -#if DEBUG & LOG_FILTER_INSERT - if (do_log) { - TRACE(_T("FGM: ^ duplicate (moniker)\n")); - } -#endif - break; - } - } - } - - if (bInsert) { - filter_t f = {(int)m_filters.GetCount(), pFGF, group, exactmatch, autodelete}; - m_filters.AddTail(f); - - m_sortedfilters.RemoveAll(); - } else if (autodelete) { - delete pFGF; - } -} - -POSITION CFGFilterList::GetHeadPosition() -{ - if (m_sortedfilters.IsEmpty()) { - CAtlArray sort; - sort.SetCount(m_filters.GetCount()); - POSITION pos = m_filters.GetHeadPosition(); - for (int i = 0; pos; i++) { - sort[i] = m_filters.GetNext(pos); - } - std::sort(sort.GetData(), sort.GetData() + sort.GetCount()); - for (size_t i = 0; i < sort.GetCount(); i++) { - if (sort[i].pFGF->GetMerit() >= MERIT64_DO_USE) { - m_sortedfilters.AddTail(sort[i].pFGF); - } - } - -#ifdef _DEBUG - TRACE(_T("FGM: Sorting filters\n")); - pos = m_sortedfilters.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_sortedfilters.GetNext(pos); - TRACE(_T("FGM: - %016I64x '%s'\n"), pFGF->GetMerit(), pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()).GetString() : CString(pFGF->GetName()).GetString()); - } -#endif - } - - return m_sortedfilters.GetHeadPosition(); -} - -CFGFilter* CFGFilterList::GetNext(POSITION& pos) -{ - return m_sortedfilters.GetNext(pos); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "FGFilter.h" +#include "MainFrm.h" +#include "DSUtil.h" +#include "IPinHook.h" // For the NVIDIA driver bug work-around +#include "uuids.h" +#include "moreuuids.h" +#include + +#include +#include "AllocatorCommon.h" +#include "SyncAllocatorPresenter.h" + +#define LOG_FILTER_INSERT 0 + +#if !TRACE_GRAPH_BUILD +#undef TRACE +#define TRACE(...) +#endif + +// +// CFGFilter +// + +CFGFilter::CFGFilter(const CLSID& clsid, CStringW name, UINT64 merit) + : m_clsid(clsid) + , m_name(name) +{ + m_merit.val = merit; +} + +CFGFilter::~CFGFilter() +{ +} + +const CAtlList& CFGFilter::GetTypes() const +{ + return m_types; +} + +void CFGFilter::SetTypes(const CAtlList& types) +{ + m_types.RemoveAll(); + m_types.AddTailList(&types); +} + +void CFGFilter::AddType(const GUID& majortype, const GUID& subtype) +{ + m_types.AddTail(majortype); + m_types.AddTail(subtype); +} + +bool CFGFilter::CheckTypes(const CAtlArray& types, bool fExactMatch) +{ + POSITION pos = m_types.GetHeadPosition(); + while (pos) { + const GUID& majortype = m_types.GetNext(pos); + if (!pos) { + ASSERT(0); + break; + } + const GUID& subtype = m_types.GetNext(pos); + + for (int i = 0, len = types.GetCount() & ~1; i < len; i += 2) { + if (fExactMatch) { + if (majortype == types[i] && majortype != GUID_NULL + && subtype == types[i + 1] && subtype != GUID_NULL) { + return true; + } + } else { + if ((majortype == GUID_NULL || types[i] == GUID_NULL || majortype == types[i]) + && (subtype == GUID_NULL || types[i + 1] == GUID_NULL || subtype == types[i + 1])) { + return true; + } + } + } + } + + return false; +} + +// +// CFGFilterRegistry +// + +CFGFilterRegistry::CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit) + : CFGFilter(GUID_NULL, L"", merit) + , m_pMoniker(pMoniker) +{ + if (!m_pMoniker) { + return; + } + + CComHeapPtr str; + if (FAILED(m_pMoniker->GetDisplayName(0, 0, &str))) { + return; + } + m_DisplayName = m_name = str; + + QueryProperties(); + + if (merit != MERIT64_DO_USE) { + m_merit.val = merit; + } +} + +CFGFilterRegistry::CFGFilterRegistry(CStringW DisplayName, UINT64 merit) + : CFGFilter(GUID_NULL, L"", merit) + , m_DisplayName(DisplayName) +{ + if (m_DisplayName.IsEmpty()) { + return; + } + + CComPtr pBC; + CreateBindCtx(0, &pBC); + + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBC, CComBSTR(m_DisplayName), &chEaten, &m_pMoniker)) { + return; + } + + QueryProperties(); + + if (merit != MERIT64_DO_USE) { + m_merit.val = merit; + } +} + +void CFGFilterRegistry::QueryProperties() +{ + ASSERT(m_pMoniker); + CComPtr pPB; + if (SUCCEEDED(m_pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)))) { + CComVariant var; + if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + m_name = var.bstrVal; + var.Clear(); + } + + if (SUCCEEDED(pPB->Read(_T("CLSID"), &var, nullptr))) { + CLSIDFromString(var.bstrVal, &m_clsid); + var.Clear(); + } + + if (SUCCEEDED(pPB->Read(_T("FilterData"), &var, nullptr))) { + BSTR* pstr; + if (SUCCEEDED(SafeArrayAccessData(var.parray, (void**)&pstr))) { + ExtractFilterData((BYTE*)pstr, var.parray->cbElements * (var.parray->rgsabound[0].cElements)); + SafeArrayUnaccessData(var.parray); + } + + var.Clear(); + } + } +} + +CFGFilterRegistry::CFGFilterRegistry(const CLSID& clsid, UINT64 merit) + : CFGFilter(clsid, L"", merit) +{ + if (m_clsid == GUID_NULL) { + return; + } + + CString guid = CStringFromGUID(m_clsid); + + CRegKey key; + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + guid, KEY_READ)) { + ULONG nChars = 0; + if (ERROR_SUCCESS == key.QueryStringValue(nullptr, nullptr, &nChars)) { + CString name; + if (ERROR_SUCCESS == key.QueryStringValue(nullptr, name.GetBuffer(nChars), &nChars)) { + name.ReleaseBuffer(nChars); + m_name = name; + } + } + + key.Close(); + } + + CRegKey catkey; + + if (ERROR_SUCCESS == catkey.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance"), KEY_READ)) { + if (ERROR_SUCCESS != key.Open(catkey, guid, KEY_READ)) { + // illiminable pack uses the name of the filter and not the clsid, have to enum all keys to find it... + + FILETIME ft; + TCHAR buff[256]; + DWORD len = _countof(buff); + for (DWORD i = 0; ERROR_SUCCESS == catkey.EnumKey(i, buff, &len, &ft); i++, len = _countof(buff)) { + if (ERROR_SUCCESS == key.Open(catkey, buff, KEY_READ)) { + TCHAR clsidString[256]; + len = _countof(clsidString); + if (ERROR_SUCCESS == key.QueryStringValue(_T("CLSID"), clsidString, &len) + && GUIDFromCString(clsidString) == m_clsid) { + break; + } + + key.Close(); + } + } + } + + if (key) { + ULONG nChars = 0; + if (ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), nullptr, &nChars)) { + CString name; + if (ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), name.GetBuffer(nChars), &nChars)) { + name.ReleaseBuffer(nChars); + m_name = name; + } + } + + ULONG nBytes = 0; + if (ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), nullptr, &nBytes)) { + CAutoVectorPtr buff; + if (buff.Allocate(nBytes) && ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), buff, &nBytes)) { + ExtractFilterData(buff, nBytes); + } + } + + key.Close(); + } + } + + if (merit != MERIT64_DO_USE) { + m_merit.val = merit; + } +} + +HRESULT CFGFilterRegistry::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + CheckPointer(ppBF, E_POINTER); + + HRESULT hr = E_FAIL; + + if (m_pMoniker) { + if (SUCCEEDED(hr = m_pMoniker->BindToObject(0, 0, IID_PPV_ARGS(ppBF)))) { + m_clsid = ::GetCLSID(*ppBF); + } + } else if (m_clsid != GUID_NULL) { + CComQIPtr pBF; + + if (FAILED(pBF.CoCreateInstance(m_clsid))) { + return E_FAIL; + } + + *ppBF = pBF.Detach(); + + hr = S_OK; + } + + return hr; +}; + +interface __declspec(uuid("97f7c4d4-547b-4a5f-8332-536430ad2e4d")) + IAMFilterData : + public IUnknown +{ + STDMETHOD(ParseFilterData)(BYTE* rgbFilterData, ULONG cb, BYTE** prgbRegFilter2) PURE; + STDMETHOD(CreateFilterData)(REGFILTER2* prf2, BYTE** prgbFilterData, ULONG* pcb) PURE; +}; + +void CFGFilterRegistry::ExtractFilterData(BYTE* p, UINT len) +{ + CComPtr pFD; + BYTE* ptr = nullptr; + + if (SUCCEEDED(pFD.CoCreateInstance(CLSID_FilterMapper2)) + && SUCCEEDED(pFD->ParseFilterData(p, len, (BYTE**)&ptr))) { + REGFILTER2* prf = (REGFILTER2*) * (WPARAM*)ptr; // this is f*cked up + + m_merit.mid = prf->dwMerit; + + if (prf->dwVersion == 1) { + for (UINT i = 0; i < prf->cPins; i++) { + if (prf->rgPins[i].bOutput) { + continue; + } + + for (UINT j = 0; j < prf->rgPins[i].nMediaTypes; j++) { + if (!prf->rgPins[i].lpMediaType[j].clsMajorType || !prf->rgPins[i].lpMediaType[j].clsMinorType) { + break; + } + + const REGPINTYPES& rpt = prf->rgPins[i].lpMediaType[j]; + AddType(*rpt.clsMajorType, *rpt.clsMinorType); + } + } + } else if (prf->dwVersion == 2) { + for (UINT i = 0; i < prf->cPins2; i++) { + if (prf->rgPins2[i].dwFlags & REG_PINFLAG_B_OUTPUT) { + continue; + } + + for (UINT j = 0; j < prf->rgPins2[i].nMediaTypes; j++) { + if (!prf->rgPins2[i].lpMediaType[j].clsMajorType || !prf->rgPins2[i].lpMediaType[j].clsMinorType) { + break; + } + + const REGPINTYPES& rpt = prf->rgPins2[i].lpMediaType[j]; + AddType(*rpt.clsMajorType, *rpt.clsMinorType); + } + } + } + + CoTaskMemFree(prf); + } else { + BYTE* base = p; + +#define ChkLen(size) if (p - base + size > (int)len) return; + + ChkLen(4) + if (*(DWORD*)p != 0x00000002) { + return; // only version 2 supported, no samples found for 1 + } + p += 4; + + ChkLen(4) + m_merit.mid = *(DWORD*)p; + p += 4; + + m_types.RemoveAll(); + + ChkLen(8) + DWORD nPins = *(DWORD*)p; + p += 8; + while (nPins-- > 0) { + ChkLen(1) + BYTE n = *p - 0x30; + p++; + UNREFERENCED_PARAMETER(n); + + ChkLen(2) + WORD pi = *(WORD*)p; + p += 2; + ASSERT(pi == 'ip'); + UNREFERENCED_PARAMETER(pi); + + ChkLen(1) + BYTE x33 = *p; + p++; + ASSERT(x33 == 0x33); + UNREFERENCED_PARAMETER(x33); + + ChkLen(8) + bool fOutput = !!(*p & REG_PINFLAG_B_OUTPUT); + p += 8; + + ChkLen(12) + DWORD nTypes = *(DWORD*)p; + p += 12; + while (nTypes-- > 0) { + ChkLen(1) + n = *p - 0x30; + p++; + UNREFERENCED_PARAMETER(n); + + ChkLen(2) + WORD ty = *(WORD*)p; + p += 2; + ASSERT(ty == 'yt'); + UNREFERENCED_PARAMETER(ty); + + ChkLen(5) + x33 = *p; + p++; + ASSERT(x33 == 0x33); + UNREFERENCED_PARAMETER(x33); + p += 4; + + ChkLen(8) + if (*(DWORD*)p < (DWORD)(p - base + 8) || *(DWORD*)p >= len + || *(DWORD*)(p + 4) < (DWORD)(p - base + 8) || *(DWORD*)(p + 4) >= len) { + p += 8; + continue; + } + + GUID majortype, subtype; + memcpy(&majortype, &base[*(DWORD*)p], sizeof(GUID)); + p += 4; + if (!fOutput) { + AddType(majortype, subtype); + } + } + } + +#undef ChkLen + } +} + +// +// CFGFilterFile +// + +CFGFilterFile::CFGFilterFile(const CLSID& clsid, CString path, CStringW name, UINT64 merit) + : CFGFilter(clsid, name, merit) + , m_path(path) + , m_hInst(nullptr) +{ +} + +HRESULT CFGFilterFile::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + CheckPointer(ppBF, E_POINTER); + + return LoadExternalFilter(m_path, m_clsid, ppBF); +} + +// +// CFGFilterVideoRenderer +// + +CFGFilterVideoRenderer::CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name, UINT64 merit, bool preview) + : CFGFilter(clsid, name, merit) + , m_hWnd(hWnd) + , m_bHasHookReceiveConnection(false) + , m_bIsPreview(preview) +{ + bool mpcvr = (clsid == CLSID_MPCVR || clsid == CLSID_MPCVRAllocatorPresenter); + bool madvr = (clsid == CLSID_madVR || clsid == CLSID_madVRAllocatorPresenter); + bool evr = (clsid == CLSID_EnhancedVideoRenderer || clsid == CLSID_EVRAllocatorPresenter || clsid == CLSID_SyncAllocatorPresenter); + + // List is based on filter registration data from madVR. + // ToDo: Some subtypes might only work with madVR. Figure out which ones and add them conditionally for extra efficiency. + + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV12); // 0 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_NV12); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yv12); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_nv12); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM1); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM3); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM4); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_NV21); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_IYUV); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_I420); // 10 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUY2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuy2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YVYU); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYVY); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_uyvy); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_cyuv); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYNV); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYNY); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_HDYC); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_uyv1); // 20 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_2Vu1); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_VDTZ); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUV2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuv2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_2vuy); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_2Vuy); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuvu); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuvs); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV16); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_I422); // 30 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y422); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_V422); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y42B); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P422); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUNV); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_VYUY); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVUI); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_AYUV); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV24); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_I444); // 40 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v308); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v408); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB24); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB32); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_24BG); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_BGRA); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ABGR); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGBA); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB0); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_0RGB); // 50 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_b48r); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RBA64); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_64RBA); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_b64a); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P010); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P210); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y210); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v210); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y410); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v410); // 60 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P016); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P216); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y216); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v216); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y416); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v416); // 66 + + if (mpcvr) { + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y8); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y16); + } + + if (mpcvr || evr) { + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ARGB32); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_A2R10G10B10); + } +} + +CFGFilterVideoRenderer::~CFGFilterVideoRenderer() +{ + if (m_bHasHookReceiveConnection) { + UnhookReceiveConnection(); + } +} + +HRESULT CFGFilterVideoRenderer::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + TRACE(_T("--> CFGFilterVideoRenderer::Create on thread: %lu\n"), GetCurrentThreadId()); + CheckPointer(ppBF, E_POINTER); + + HRESULT hr; + CComPtr pCAP; + + auto isD3DFullScreenMode = []() { + auto pMainFrame = dynamic_cast(AfxGetApp()->m_pMainWnd); + ASSERT(pMainFrame); + return pMainFrame && pMainFrame->IsD3DFullScreenMode(); + }; + + if (m_clsid == CLSID_EVRAllocatorPresenter) { + CheckNoLog(CreateEVR(m_clsid, m_hWnd, !m_bIsPreview && isD3DFullScreenMode(), &pCAP, m_bIsPreview)); + } else if (m_clsid == CLSID_SyncAllocatorPresenter) { + CheckNoLog(CreateSyncRenderer(m_clsid, m_hWnd, isD3DFullScreenMode(), &pCAP)); + } else if (m_clsid == CLSID_MPCVRAllocatorPresenter || m_clsid == CLSID_madVRAllocatorPresenter || + m_clsid == CLSID_VMR9AllocatorPresenter || m_clsid == CLSID_DXRAllocatorPresenter) { + CheckNoLog(CreateAP9(m_clsid, m_hWnd, isD3DFullScreenMode(), &pCAP)); + } else { + CComPtr pBF; + CheckNoLog(pBF.CoCreateInstance(m_clsid)); + + if (m_clsid == CLSID_EnhancedVideoRenderer) { + CComQIPtr pConfig = pBF; + pConfig->SetNumberOfStreams(m_bIsPreview ? 1 : 3); + + if (CComQIPtr pMFGS = pBF) { + CComPtr pMFVDC; + if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVDC)))) { + pMFVDC->SetVideoWindow(m_hWnd); + if (m_bIsPreview) { + pMFVDC->SetRenderingPrefs(MFVideoRenderPrefs_DoNotRepaintOnStop); + } + } + } + } else if (m_clsid == CLSID_VideoMixingRenderer9) { + if (m_bIsPreview) { + CComQIPtr pConfig = pBF; + + if (pConfig) { + pConfig->SetRenderingMode(VMR9Mode_Windowless); + CComQIPtr pControl = pBF; + if (pControl) { + pControl->SetVideoClippingWindow(m_hWnd); + } + } + } + } + + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pMPC = pPin) { + pUnks.AddTail(pMPC); + break; + } + } + EndEnumPins; + + *ppBF = pBF.Detach(); + } + + if (pCAP) { + CComPtr pRenderer; + CheckNoLog(pCAP->CreateRenderer(&pRenderer)); + + *ppBF = CComQIPtr(pRenderer).Detach(); + + if (m_clsid == CLSID_MPCVRAllocatorPresenter) { + auto pMainFrame = (CMainFrame*)(AfxGetApp()->m_pMainWnd); + if (pMainFrame && pMainFrame->HasDedicatedFSVideoWindow()) { + if (CComQIPtr pD3DFSC = *ppBF) { + pD3DFSC->SetD3DFullscreen(true); + } + } + // renderer supports calling IVideoWindow::put_Owner before the pins are connected + if (CComQIPtr pVW = *ppBF) { + VERIFY(SUCCEEDED(pVW->put_Owner((OAHWND)m_hWnd))); + } + } else if (m_clsid == CLSID_madVRAllocatorPresenter) { + if (CComQIPtr pMVRSR = pCAP) { + VERIFY(SUCCEEDED(pMVRSR->DisableSubclassing())); + } + // renderer supports calling IVideoWindow::put_Owner before the pins are connected + if (CComQIPtr pVW = *ppBF) { + VERIFY(SUCCEEDED(pVW->put_Owner((OAHWND)m_hWnd))); + } + } + + pUnks.AddTail(pCAP); + if (CComQIPtr pCAP2 = pCAP) { + pUnks.AddTail(pCAP2); + } + if (CComQIPtr pCAP3 = pCAP) { + pUnks.AddTail(pCAP3); + } + } + + CheckPointer(*ppBF, E_FAIL); + + if (!m_bIsPreview && (m_clsid == CLSID_EnhancedVideoRenderer || m_clsid == CLSID_EVRAllocatorPresenter || m_clsid == CLSID_SyncAllocatorPresenter || m_clsid == CLSID_VMR9AllocatorPresenter)) { + m_bHasHookReceiveConnection = HookReceiveConnection(*ppBF); + } + + return hr; +} + +// +// CFGFilterList +// + +CFGFilterList::CFGFilterList() +{ +} + +CFGFilterList::~CFGFilterList() +{ + RemoveAll(); +} + +void CFGFilterList::RemoveAll() +{ + while (!m_filters.IsEmpty()) { + const filter_t& f = m_filters.RemoveHead(); + if (f.autodelete) { + delete f.pFGF; + } + } + + m_sortedfilters.RemoveAll(); +} + +void CFGFilterList::Insert(CFGFilter* pFGF, int group, bool exactmatch, bool autodelete) +{ + bool bInsert = true; + +#if DEBUG & LOG_FILTER_INSERT + bool do_log = pFGF->GetMerit() != MERIT64_DO_NOT_USE; + if (do_log) { + TRACE(_T("FGM: Inserting %d %d %016I64x %s\n"), group, exactmatch, pFGF->GetMerit(), + pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()).GetString() : CString(pFGF->GetName()).GetString()); + } +#endif + + CLSID insert_clsid = pFGF->GetCLSID(); + + POSITION pos = m_filters.GetHeadPosition(); + while (pos) { + filter_t& f = m_filters.GetNext(pos); + + if (pFGF == f.pFGF) { + bInsert = false; +#if DEBUG & LOG_FILTER_INSERT + if (do_log) { + TRACE(_T("FGM: ^ duplicate (exact)\n")); + } +#endif + break; + } + + // Filters are inserted in this order: + // 1) Internal filters + // 2) Renderers + // 3) Overrides + // 4) Registry + + if (insert_clsid != GUID_NULL && insert_clsid == f.pFGF->GetCLSID()) { + // Exact same filter if name also identical. Name is different for the internal filters, and those should be handled as different filters. + // Blacklisted filters can have empty name. + if (f.pFGF->GetMerit() == MERIT64_DO_NOT_USE || pFGF->GetName() == f.pFGF->GetName()) { + bInsert = false; +#if DEBUG & LOG_FILTER_INSERT + if (do_log) { + TRACE(_T("FGM: ^ duplicate\n")); + } +#endif + break; + } + } + + if (group != f.group) { + continue; + } + + CFGFilterRegistry* pFGFR = dynamic_cast(pFGF); + if (pFGFR && pFGFR->GetMoniker()) { + CFGFilterRegistry* pFGFR2 = dynamic_cast(f.pFGF); + if (pFGFR2 && pFGFR2->GetMoniker() && S_OK == pFGFR->GetMoniker()->IsEqual(pFGFR2->GetMoniker())) { + bInsert = false; +#if DEBUG & LOG_FILTER_INSERT + if (do_log) { + TRACE(_T("FGM: ^ duplicate (moniker)\n")); + } +#endif + break; + } + } + } + + if (bInsert) { + filter_t f = {(int)m_filters.GetCount(), pFGF, group, exactmatch, autodelete}; + m_filters.AddTail(f); + + m_sortedfilters.RemoveAll(); + } else if (autodelete) { + delete pFGF; + } +} + +POSITION CFGFilterList::GetHeadPosition() +{ + if (m_sortedfilters.IsEmpty()) { + CAtlArray sort; + sort.SetCount(m_filters.GetCount()); + POSITION pos = m_filters.GetHeadPosition(); + for (int i = 0; pos; i++) { + sort[i] = m_filters.GetNext(pos); + } + std::sort(sort.GetData(), sort.GetData() + sort.GetCount()); + for (size_t i = 0; i < sort.GetCount(); i++) { + if (sort[i].pFGF->GetMerit() >= MERIT64_DO_USE) { + m_sortedfilters.AddTail(sort[i].pFGF); + } + } + +#ifdef _DEBUG + TRACE(_T("FGM: Sorting filters\n")); + pos = m_sortedfilters.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_sortedfilters.GetNext(pos); + TRACE(_T("FGM: - %016I64x '%s'\n"), pFGF->GetMerit(), pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()).GetString() : CString(pFGF->GetName()).GetString()); + } +#endif + } + + return m_sortedfilters.GetHeadPosition(); +} + +CFGFilter* CFGFilterList::GetNext(POSITION& pos) +{ + return m_sortedfilters.GetNext(pos); +} diff --git a/src/mpc-hc/FGFilter.h b/src/mpc-hc/FGFilter.h index 0d34d1dd95a..772326e88af 100644 --- a/src/mpc-hc/FGFilter.h +++ b/src/mpc-hc/FGFilter.h @@ -1,193 +1,193 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015, 2017 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 . - * - */ - -#pragma once - -#define MERIT64(merit) (((UINT64)(merit)) << 16) -#define MERIT64_DO_NOT_USE MERIT64(MERIT_DO_NOT_USE) -#define MERIT64_DO_USE MERIT64(MERIT_DO_NOT_USE + 1) -#define MERIT64_UNLIKELY (MERIT64(MERIT_UNLIKELY)) -#define MERIT64_NORMAL (MERIT64(MERIT_NORMAL)) -#define MERIT64_PREFERRED (MERIT64(MERIT_PREFERRED)) -#define MERIT64_ABOVE_DSHOW (MERIT64(1) << 32) - -#define LowMeritSuffix L" (low merit)" -#define LowMerit(x) (CStringW(x) + LowMeritSuffix) - - -class CFGFilter -{ -protected: - CLSID m_clsid; - CStringW m_name; - struct { - union { - UINT64 val; - struct { - UINT64 low: 16, mid: 32, high: 16; - }; - }; - } m_merit; - CAtlList m_types; - -public: - CFGFilter(const CLSID& clsid, CStringW name = L"", UINT64 merit = MERIT64_DO_USE); - virtual ~CFGFilter(); - - CLSID GetCLSID() const { return m_clsid; } - CStringW GetName() const { return m_name; } - UINT64 GetMerit() const { return m_merit.val; } - DWORD GetMeritForDirectShow() const { return m_merit.mid; } - const CAtlList& GetTypes() const; - void SetTypes(const CAtlList& types); - void AddType(const GUID& majortype, const GUID& subtype); - bool CheckTypes(const CAtlArray& types, bool fExactMatch); - - CAtlList m_protocols, m_extensions, m_chkbytes; // TODO: subtype? - - virtual HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks) = 0; -}; - -class CFGFilterRegistry : public CFGFilter -{ -protected: - CStringW m_DisplayName; - CComPtr m_pMoniker; - - void ExtractFilterData(BYTE* p, UINT len); - -public: - CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit = MERIT64_DO_USE); - CFGFilterRegistry(CStringW DisplayName, UINT64 merit = MERIT64_DO_USE); - CFGFilterRegistry(const CLSID& clsid, UINT64 merit = MERIT64_DO_USE); - - CStringW GetDisplayName() { return m_DisplayName; } - IMoniker* GetMoniker() { return m_pMoniker; } - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); -private: - void QueryProperties(); -}; - -template -class CFGFilterInternal : public CFGFilter -{ -public: - CFGFilterInternal(CStringW name = L"", UINT64 merit = MERIT64_DO_USE) : CFGFilter(__uuidof(T), name, merit) {} - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks) { - CheckPointer(ppBF, E_POINTER); - - HRESULT hr = S_OK; - CComPtr pBF = DEBUG_NEW T(nullptr, &hr); - if (FAILED(hr)) { - return hr; - } - - *ppBF = pBF.Detach(); - - return hr; - } -}; - -class CFGFilterFile : public CFGFilter -{ -protected: - CString m_path; - HINSTANCE m_hInst; - -public: - CFGFilterFile(const CLSID& clsid, CString path, CStringW name = L"", UINT64 merit = MERIT64_DO_USE); - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); -}; - -class CFGFilterVideoRenderer : public CFGFilter -{ -protected: - HWND m_hWnd; - bool m_bHasHookReceiveConnection; - bool m_bIsPreview; - -public: - CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name = L"", UINT64 merit = MERIT64_DO_USE, bool preview = false); - virtual ~CFGFilterVideoRenderer(); - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); -}; - -class CFGFilterList -{ - struct filter_t { - int index; - CFGFilter* pFGF; - int group; - bool exactmatch, autodelete; - - bool operator <(const filter_t& rhs) const { - if (group != rhs.group) { - return group < rhs.group; - } - - if (pFGF->GetMerit() != rhs.pFGF->GetMerit()) { - return pFGF->GetMerit() > rhs.pFGF->GetMerit(); - } - - if (pFGF->GetCLSID() == rhs.pFGF->GetCLSID()) { - CFGFilterFile* fgfa = dynamic_cast(pFGF); - CFGFilterFile* fgfb = dynamic_cast(rhs.pFGF); - - if (fgfa && !fgfb) { - return true; - } - if (!fgfa && fgfb) { - return false; - } - } - - if (exactmatch && !rhs.exactmatch) { - return true; - } - if (!exactmatch && rhs.exactmatch) { - return false; - } - - if (index != rhs.index) { - return index < rhs.index; - } - - return false; - } - }; - CAtlList m_filters; - CAtlList m_sortedfilters; - -public: - CFGFilterList(); - virtual ~CFGFilterList(); - - bool IsEmpty() { return m_filters.IsEmpty(); } - void RemoveAll(); - void Insert(CFGFilter* pFGF, int group, bool exactmatch = false, bool autodelete = true); - - POSITION GetHeadPosition(); - CFGFilter* GetNext(POSITION& pos); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015, 2017 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 . + * + */ + +#pragma once + +#define MERIT64(merit) (((UINT64)(merit)) << 16) +#define MERIT64_DO_NOT_USE MERIT64(MERIT_DO_NOT_USE) +#define MERIT64_DO_USE MERIT64(MERIT_DO_NOT_USE + 1) +#define MERIT64_UNLIKELY (MERIT64(MERIT_UNLIKELY)) +#define MERIT64_NORMAL (MERIT64(MERIT_NORMAL)) +#define MERIT64_PREFERRED (MERIT64(MERIT_PREFERRED)) +#define MERIT64_ABOVE_DSHOW (MERIT64(1) << 32) + +#define LowMeritSuffix L" (low merit)" +#define LowMerit(x) (CStringW(x) + LowMeritSuffix) + + +class CFGFilter +{ +protected: + CLSID m_clsid; + CStringW m_name; + struct { + union { + UINT64 val; + struct { + UINT64 low: 16, mid: 32, high: 16; + }; + }; + } m_merit; + CAtlList m_types; + +public: + CFGFilter(const CLSID& clsid, CStringW name = L"", UINT64 merit = MERIT64_DO_USE); + virtual ~CFGFilter(); + + CLSID GetCLSID() const { return m_clsid; } + CStringW GetName() const { return m_name; } + UINT64 GetMerit() const { return m_merit.val; } + DWORD GetMeritForDirectShow() const { return m_merit.mid; } + const CAtlList& GetTypes() const; + void SetTypes(const CAtlList& types); + void AddType(const GUID& majortype, const GUID& subtype); + bool CheckTypes(const CAtlArray& types, bool fExactMatch); + + CAtlList m_protocols, m_extensions, m_chkbytes; // TODO: subtype? + + virtual HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks) = 0; +}; + +class CFGFilterRegistry : public CFGFilter +{ +protected: + CStringW m_DisplayName; + CComPtr m_pMoniker; + + void ExtractFilterData(BYTE* p, UINT len); + +public: + CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit = MERIT64_DO_USE); + CFGFilterRegistry(CStringW DisplayName, UINT64 merit = MERIT64_DO_USE); + CFGFilterRegistry(const CLSID& clsid, UINT64 merit = MERIT64_DO_USE); + + CStringW GetDisplayName() { return m_DisplayName; } + IMoniker* GetMoniker() { return m_pMoniker; } + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); +private: + void QueryProperties(); +}; + +template +class CFGFilterInternal : public CFGFilter +{ +public: + CFGFilterInternal(CStringW name = L"", UINT64 merit = MERIT64_DO_USE) : CFGFilter(__uuidof(T), name, merit) {} + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks) { + CheckPointer(ppBF, E_POINTER); + + HRESULT hr = S_OK; + CComPtr pBF = DEBUG_NEW T(nullptr, &hr); + if (FAILED(hr)) { + return hr; + } + + *ppBF = pBF.Detach(); + + return hr; + } +}; + +class CFGFilterFile : public CFGFilter +{ +protected: + CString m_path; + HINSTANCE m_hInst; + +public: + CFGFilterFile(const CLSID& clsid, CString path, CStringW name = L"", UINT64 merit = MERIT64_DO_USE); + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); +}; + +class CFGFilterVideoRenderer : public CFGFilter +{ +protected: + HWND m_hWnd; + bool m_bHasHookReceiveConnection; + bool m_bIsPreview; + +public: + CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name = L"", UINT64 merit = MERIT64_DO_USE, bool preview = false); + virtual ~CFGFilterVideoRenderer(); + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); +}; + +class CFGFilterList +{ + struct filter_t { + int index; + CFGFilter* pFGF; + int group; + bool exactmatch, autodelete; + + bool operator <(const filter_t& rhs) const { + if (group != rhs.group) { + return group < rhs.group; + } + + if (pFGF->GetMerit() != rhs.pFGF->GetMerit()) { + return pFGF->GetMerit() > rhs.pFGF->GetMerit(); + } + + if (pFGF->GetCLSID() == rhs.pFGF->GetCLSID()) { + CFGFilterFile* fgfa = dynamic_cast(pFGF); + CFGFilterFile* fgfb = dynamic_cast(rhs.pFGF); + + if (fgfa && !fgfb) { + return true; + } + if (!fgfa && fgfb) { + return false; + } + } + + if (exactmatch && !rhs.exactmatch) { + return true; + } + if (!exactmatch && rhs.exactmatch) { + return false; + } + + if (index != rhs.index) { + return index < rhs.index; + } + + return false; + } + }; + CAtlList m_filters; + CAtlList m_sortedfilters; + +public: + CFGFilterList(); + virtual ~CFGFilterList(); + + bool IsEmpty() { return m_filters.IsEmpty(); } + void RemoveAll(); + void Insert(CFGFilter* pFGF, int group, bool exactmatch = false, bool autodelete = true); + + POSITION GetHeadPosition(); + CFGFilter* GetNext(POSITION& pos); +}; diff --git a/src/mpc-hc/FGFilterLAV.cpp b/src/mpc-hc/FGFilterLAV.cpp index d8967a6592f..0be53d61dfa 100644 --- a/src/mpc-hc/FGFilterLAV.cpp +++ b/src/mpc-hc/FGFilterLAV.cpp @@ -1,1274 +1,1274 @@ -/* - * (C) 2013-2018 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "PathUtils.h" -#include "../filters/InternalPropertyPage.h" -#include "../filters/PinInfoWnd.h" -#include - -#include -#include "FGFilterLAV.h" - -#define LAV_FILTERS_VERSION(major, minor, rev, commit) ((QWORD)(major) << 48 | (QWORD)(minor) << 32 | (QWORD)(rev) << 16 | (QWORD)(commit)) - -#ifndef _WIN64 -#define LAVFILTERS_DIR _T("LAVFilters\\") -#else -#define LAVFILTERS_DIR _T("LAVFilters64\\") -#endif - -// -// CFGFilterLAV -// - -CList CFGFilterLAV::s_instances; -QWORD CFGFilterLAV::lav_version = 0; - -CFGFilterLAV::CFGFilterLAV(const CLSID& clsid, CString path, CStringW name, bool bAddLowMeritSuffix, UINT64 merit, bool bIsPreview) - : isPreview(bIsPreview) - , CFGFilterFile(clsid, path, name + (bAddLowMeritSuffix ? LowMeritSuffix : L""), merit) -{ -} - -CString CFGFilterLAV::GetFilterPath(LAVFILTER_TYPE filterType) -{ - // Default path - CString filterPath = PathUtils::CombinePaths(PathUtils::GetProgramPath(), LAVFILTERS_DIR); - CLSID filterCLSID; - - switch (filterType) { - case SPLITTER: - case SPLITTER_SOURCE: - filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVSplitterBase::filename); - filterCLSID = GUID_LAVSplitter; - break; - case VIDEO_DECODER: - filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVVideo::filename); - filterCLSID = GUID_LAVVideo; - break; - case AUDIO_DECODER: - filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVAudio::filename); - filterCLSID = GUID_LAVAudio; - break; - default: - ASSERT(FALSE); // This should never happen - break; - } - -#if ENABLE_LOAD_EXTERNAL_LAVF_AS_INTERNAL - // Check that the filter's version is correct - if (!CheckVersion(filterPath)) { - // If not, check if a registered version of the filter is available. - filterPath = ::GetFilterPath(filterCLSID); - // and if it can be used - if (!CheckVersion(filterPath)) { - filterPath = _T(""); - } - } -#endif - - return filterPath; -} - -bool CFGFilterLAV::CheckVersion(CString filterPath) -{ - QWORD fversion = FileVersionInfo::GetFileVersionNum(filterPath); - if (fversion >= 0 && (lav_version == 0 || lav_version > fversion)) { - lav_version = fversion; - } - - return fversion >= LAV_FILTERS_VERSION(0, 68, 0, 0); -} - -CString CFGFilterLAV::GetVersion(LAVFILTER_TYPE filterType /*= INVALID*/) -{ - CStringList paths; - - if (filterType == INVALID) { - paths.AddTail(GetFilterPath(SPLITTER)); - paths.AddTail(GetFilterPath(VIDEO_DECODER)); - paths.AddTail(GetFilterPath(AUDIO_DECODER)); - } else { - paths.AddTail(GetFilterPath(filterType)); - } - - QWORD uiVersionMin = UINT64_MAX; - QWORD uiVersionMax = 0ui64; - CString strVersionMin, strVersionMax; - POSITION pos = paths.GetHeadPosition(); - while (pos) { - CString& path = paths.GetNext(pos); - - QWORD version = FileVersionInfo::GetFileVersionNum(path); - if (version) { - if (version < uiVersionMin) { - uiVersionMin = version; - strVersionMin = FileVersionInfo::FormatVersionString(version); - } - if (version > uiVersionMax) { - uiVersionMax = version; - strVersionMax = FileVersionInfo::FormatVersionString(version); - } - } - } - - CString version; - if (uiVersionMin != UINT64_MAX) { - version = strVersionMin; - if (uiVersionMax != uiVersionMin) { - version.AppendFormat(_T(" - %s"), strVersionMax.GetString()); - } - } - - return version; -} - -CFGFilterLAV* CFGFilterLAV::CreateFilter(LAVFILTER_TYPE filterType, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) -{ - CFGFilterLAV* filter = nullptr; - - CString filterPath = GetFilterPath(filterType); - - switch (filterType) { - case SPLITTER: - filter = DEBUG_NEW CFGFilterLAVSplitter(filterPath, merit, bAddLowMeritSuffix, bIsPreview); - break; - case SPLITTER_SOURCE: - filter = DEBUG_NEW CFGFilterLAVSplitterSource(filterPath, merit, bAddLowMeritSuffix, bIsPreview); - break; - case VIDEO_DECODER: - filter = DEBUG_NEW CFGFilterLAVVideo(filterPath, merit, bAddLowMeritSuffix, bIsPreview); - break; - case AUDIO_DECODER: - filter = DEBUG_NEW CFGFilterLAVAudio(filterPath, merit, bAddLowMeritSuffix, bIsPreview); - break; - default: - ASSERT(FALSE); // This should never happen - break; - } - - return filter; -} - -CFGFilterLAV* CFGFilterLAV::CreateFilterPreview(LAVFILTER_TYPE filterType, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/) { - CFGFilterLAV* filter = CreateFilter(filterType, merit, bAddLowMeritSuffix, true); - - return filter; -} - - -bool CFGFilterLAV::IsInternalInstance(IBaseFilter* pBF, LAVFILTER_TYPE* pLAVFilterType /*= nullptr*/) -{ - bool bIsInternalInstance = (s_instances.Find(pBF) != nullptr); - - if (bIsInternalInstance && pLAVFilterType) { - CLSID clsid; - *pLAVFilterType = INVALID; - - if (SUCCEEDED(pBF->GetClassID(&clsid))) { - if (clsid == GUID_LAVSplitter) { - *pLAVFilterType = SPLITTER; - } else if (clsid == GUID_LAVSplitterSource) { - *pLAVFilterType = SPLITTER_SOURCE; - } else if (clsid == GUID_LAVVideo) { - *pLAVFilterType = VIDEO_DECODER; - } else if (clsid == GUID_LAVAudio) { - *pLAVFilterType = AUDIO_DECODER; - } - } - } - - return bIsInternalInstance; -} - -HRESULT CFGFilterLAV::PropertyPageCallback(IBaseFilter* pBF) -{ - CheckPointer(pBF, E_POINTER); - - CComPropertySheet ps(IDS_PROPSHEET_PROPERTIES, AfxGetMyApp()->GetMainWnd()); - - // Find out which internal filter we are opening the property page for - CFGFilterLAV::LAVFILTER_TYPE LAVFilterType = CFGFilterLAV::INVALID; - if (!CFGFilterLAV::IsInternalInstance(pBF, &LAVFilterType)) { - return E_UNEXPECTED; - } - - HRESULT hr = E_FAIL; - if (CComQIPtr pSPP = pBF) { - ps.AddPages(pSPP, (LAVFilterType != CFGFilterLAV::AUDIO_DECODER) ? 1 : 2); - } - - CComPtr pPP = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr); - ps.AddPage(pPP, pBF); - - if (ps.GetPageCount() > 1) { - ps.DoModal(); - - if (CComQIPtr pLAVFSettings = pBF) { - CFGFilterLAVSplitterBase::Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get current settings from LAVSplitter - settings.SaveSettings(); // Save them to the registry/ini - } - } else if (CComQIPtr pLAVVideoSettings = pBF) { - CFGFilterLAVVideo::Settings settings; - if (settings.GetSettings(pLAVVideoSettings)) { // Get current settings from LAVVideo - settings.SaveSettings(); // Save them to the registry/ini - } - } else if (CComQIPtr pLAVAudioSettings = pBF) { - CFGFilterLAVAudio::Settings settings; - if (settings.GetSettings(pLAVAudioSettings)) { // Get current settings from LAVAudio - settings.SaveSettings(); // Save them to the registry/ini - } - } - - hr = S_OK; - } - - return hr; -} - -// -// CFGFilterLAVSplitterBase -// - -const CString CFGFilterLAVSplitterBase::filename = _T("LAVSplitter.ax"); - -CFGFilterLAVSplitterBase::CFGFilterLAVSplitterBase(CString path, const CLSID& clsid, CStringW name, bool bAddLowMeritSuffix, UINT64 merit, bool bIsPreview) - : CFGFilterLAV(clsid, path, name, bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -HRESULT CFGFilterLAVSplitterBase::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - HRESULT hr = __super::Create(ppBF, pUnks); - - if (SUCCEEDED(hr)) { - if (!CheckVersion(m_path)) { - hr = E_FAIL; - } else if (CComQIPtr pLAVFSettings = *ppBF) { - // Take control over LAVSplitter's settings, the settings are reseted to default values - hr = pLAVFSettings->SetRuntimeConfig(TRUE); - - if (SUCCEEDED(hr)) { - if (isPreview) { - pLAVFSettings->SetMaxQueueMemSize(20); - pLAVFSettings->SetMaxQueueSize(50); - pLAVFSettings->SetSubstreamsEnabled(false); - pLAVFSettings->SetSubtitleMode(LAVSubtitleMode_NoSubs); - } else { - Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVSplitter - settings.LoadSettings(); // Load our current settings from registry/ini - settings.SetSettings(pLAVFSettings); // Set our settings in LAVSplitter - } - } - - SetEnabledDisabledFormats(pLAVFSettings); - - // Keep track of LAVFilters instances in runtime mode - s_instances.AddTail(*ppBF); - } - } else { - hr = E_NOINTERFACE; - } - } - - return hr; -} - -void CFGFilterLAVSplitterBase::SetEnabledDisabledFormats(CComQIPtr pLAVFSettings) -{ - // "*" is a special case and means all formats are enabled - if (m_enabledFormats.IsEmpty() || m_enabledFormats.GetHead() != "*") { - // We turn off all formats by default to ensure that we won't hijack other filters - LPSTR* formats; - UINT nFormats; - if (SUCCEEDED(pLAVFSettings->GetFormats(&formats, &nFormats))) { - for (UINT i = 0; i < nFormats; i++) { - pLAVFSettings->SetFormatEnabled(formats[i], FALSE); - // Free the memory immediately since we won't need it later - CoTaskMemFree(formats[i]); - } - CoTaskMemFree(formats); - } - // We turn on only the formats specified explicitly - POSITION pos = m_enabledFormats.GetHeadPosition(); - while (pos) { - const CStringA& format = m_enabledFormats.GetNext(pos); - pLAVFSettings->SetFormatEnabled(format, TRUE); - } - } - - // Explicitly disabled formats - POSITION pos = m_disabledFormats.GetHeadPosition(); - while (pos) { - const CStringA& format = m_disabledFormats.GetNext(pos); - pLAVFSettings->SetFormatEnabled(format, FALSE); - } -} - -void CFGFilterLAVSplitterBase::ShowPropertyPages(CWnd* pParendWnd) -{ - CFGFilterLAV::ShowPropertyPages(pParendWnd); -} - -void CFGFilterLAVSplitterBase::Settings::LoadSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("TrayIcon"), bTrayIcon); - - prefAudioLangs = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefAudioLangs"), prefAudioLangs.c_str()); - prefSubLangs = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefSubLangs"), prefSubLangs.c_str()); - subtitleAdvanced = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleAdvanced"), subtitleAdvanced.c_str()); - - subtitleMode = (LAVSubtitleMode)pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleMode"), subtitleMode); - - bPGSForcedStream = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSForcedStream"), bPGSForcedStream); - - bPGSOnlyForced = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSOnlyForced"), bPGSOnlyForced); - - iVC1Mode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("vc1TimestampMode"), iVC1Mode); - - bSubstreams = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("substreams"), bSubstreams); - - bMatroskaExternalSegments = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("MatroskaExternalSegments"), bMatroskaExternalSegments); - - bStreamSwitchReselectSubs = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchReselectSubs"), bStreamSwitchReselectSubs); - - bStreamSwitchRemoveAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchRemoveAudio"), bStreamSwitchRemoveAudio); - - bPreferHighQualityAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PreferHighQualityAudio"), bPreferHighQualityAudio); - - bImpairedAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("ImpairedAudio"), bImpairedAudio); - - dwQueueMaxMemSize = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxSize"), dwQueueMaxMemSize); - - dwQueueMaxPackets = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxPackets"), dwQueueMaxPackets); - - dwNetworkAnalysisDuration = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("NetworkAnalysisDuration"), dwNetworkAnalysisDuration); -} - -void CFGFilterLAVSplitterBase::Settings::SaveSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("TrayIcon"), bTrayIcon); - - pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefAudioLangs"), prefAudioLangs.c_str()); - pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefSubLangs"), prefSubLangs.c_str()); - pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleAdvanced"), subtitleAdvanced.c_str()); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleMode"), subtitleMode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSForcedStream"), bPGSForcedStream); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSOnlyForced"), bPGSOnlyForced); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("vc1TimestampMode"), iVC1Mode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("substreams"), bSubstreams); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("MatroskaExternalSegments"), bMatroskaExternalSegments); - - if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchReselectSubs"), bStreamSwitchReselectSubs); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchRemoveAudio"), bStreamSwitchRemoveAudio); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PreferHighQualityAudio"), bPreferHighQualityAudio); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("ImpairedAudio"), bImpairedAudio); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxSize"), dwQueueMaxMemSize); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxPackets"), dwQueueMaxPackets); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("NetworkAnalysisDuration"), dwNetworkAnalysisDuration); -} - -bool CFGFilterLAVSplitterBase::Settings::GetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - bTrayIcon = pLAVFSettings->GetTrayIcon(); - - HRESULT hr; - LPWSTR lpwstr = nullptr; - hr = pLAVFSettings->GetPreferredLanguages(&lpwstr); - if (SUCCEEDED(hr) && lpwstr) { - prefAudioLangs = lpwstr; - CoTaskMemFree(lpwstr); - } - lpwstr = nullptr; - hr = pLAVFSettings->GetPreferredSubtitleLanguages(&lpwstr); - if (SUCCEEDED(hr) && lpwstr) { - prefSubLangs = lpwstr; - CoTaskMemFree(lpwstr); - } - lpwstr = nullptr; - hr = pLAVFSettings->GetAdvancedSubtitleConfig(&lpwstr); - if (SUCCEEDED(hr) && lpwstr) { - subtitleAdvanced = lpwstr; - CoTaskMemFree(lpwstr); - } - - subtitleMode = pLAVFSettings->GetSubtitleMode(); - - bPGSForcedStream = pLAVFSettings->GetPGSForcedStream(); - - bPGSOnlyForced = pLAVFSettings->GetPGSOnlyForced(); - - iVC1Mode = pLAVFSettings->GetVC1TimestampMode(); - - bSubstreams = pLAVFSettings->GetSubstreamsEnabled(); - - bMatroskaExternalSegments = pLAVFSettings->GetLoadMatroskaExternalSegments(); - - if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { - bStreamSwitchReselectSubs = pLAVFSettings->GetStreamSwitchReselectSubtitles(); - } else { - bStreamSwitchReselectSubs = FALSE; - } - - bStreamSwitchRemoveAudio = pLAVFSettings->GetStreamSwitchRemoveAudio(); - - bImpairedAudio = pLAVFSettings->GetUseAudioForHearingVisuallyImpaired(); - - bPreferHighQualityAudio = pLAVFSettings->GetPreferHighQualityAudioStreams(); - - dwQueueMaxMemSize = pLAVFSettings->GetMaxQueueMemSize(); - - dwQueueMaxPackets = pLAVFSettings->GetMaxQueueSize(); - - dwNetworkAnalysisDuration = pLAVFSettings->GetNetworkStreamAnalysisDuration(); - - return true; -} - -bool CFGFilterLAVSplitterBase::Settings::SetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - pLAVFSettings->SetTrayIcon(bTrayIcon); - - pLAVFSettings->SetPreferredLanguages(prefAudioLangs.c_str()); - pLAVFSettings->SetPreferredSubtitleLanguages(prefSubLangs.c_str()); - pLAVFSettings->SetAdvancedSubtitleConfig(subtitleAdvanced.c_str()); - - pLAVFSettings->SetSubtitleMode(subtitleMode); - - pLAVFSettings->SetPGSForcedStream(bPGSForcedStream); - - pLAVFSettings->SetPGSOnlyForced(bPGSOnlyForced); - - pLAVFSettings->SetVC1TimestampMode(iVC1Mode); - - pLAVFSettings->SetSubstreamsEnabled(bSubstreams); - - pLAVFSettings->SetLoadMatroskaExternalSegments(bMatroskaExternalSegments); - - if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { - pLAVFSettings->SetStreamSwitchReselectSubtitles(bStreamSwitchReselectSubs); - } - - pLAVFSettings->SetStreamSwitchRemoveAudio(bStreamSwitchRemoveAudio); - - pLAVFSettings->SetUseAudioForHearingVisuallyImpaired(bImpairedAudio); - - pLAVFSettings->SetPreferHighQualityAudioStreams(bPreferHighQualityAudio); - - pLAVFSettings->SetMaxQueueMemSize(dwQueueMaxMemSize); - - pLAVFSettings->SetMaxQueueSize(dwQueueMaxPackets); - - pLAVFSettings->SetNetworkStreamAnalysisDuration(dwNetworkAnalysisDuration); - - // Custom interface available only in patched build, will be removed after it's upstreamed - if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { - pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); - } - - return true; -} - -// -// CFGFilterLAVSplitter -// - -CFGFilterLAVSplitter::CFGFilterLAVSplitter(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) - : CFGFilterLAVSplitterBase(path, GUID_LAVSplitter, L"LAV Splitter (internal)", bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -// -// CFGFilterLAVSplitterSource -// - -CFGFilterLAVSplitterSource::CFGFilterLAVSplitterSource(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) - : CFGFilterLAVSplitterBase(path, GUID_LAVSplitterSource, L"LAV Splitter Source (internal)", bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -// -// CFGFilterLAVVideo -// - -const CString CFGFilterLAVVideo::filename = _T("LAVVideo.ax"); - -CFGFilterLAVVideo::CFGFilterLAVVideo(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) - : CFGFilterLAV(GUID_LAVVideo, path, L"LAV Video Decoder (internal)", bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -HRESULT CFGFilterLAVVideo::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - HRESULT hr = __super::Create(ppBF, pUnks); - - if (SUCCEEDED(hr)) { - if (!CheckVersion(m_path)) { - hr = E_FAIL; - } else if (CComQIPtr pLAVFSettings = *ppBF) { - // Take control over LAVVideo's settings, the settings are reseted to default values - hr = pLAVFSettings->SetRuntimeConfig(TRUE); - - if (SUCCEEDED(hr)) { - if (isPreview) { - pLAVFSettings->SetNumThreads(2); - pLAVFSettings->SetPixelFormat(LAVOutPixFmt_P010, false); - pLAVFSettings->SetPixelFormat(LAVOutPixFmt_P016, false); - } else { - Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVVideo - settings.LoadSettings(); // Load our current settings from registry/ini - settings.SetSettings(pLAVFSettings); // Set our settings in LAVVideo - } - } - // Keep track of LAVFilters instances in runtime mode - s_instances.AddTail(*ppBF); - } - } else { - hr = E_NOINTERFACE; - } - } - - return hr; -} - -void CFGFilterLAVVideo::ShowPropertyPages(CWnd* pParendWnd) -{ - CFGFilterLAV::ShowPropertyPages(pParendWnd); -} - -LPCTSTR CFGFilterLAVVideo::GetUserFriendlyDecoderName(const LPCWSTR decoderName) -{ - static constexpr std::pair userFriendlyDecoderNames[] = { - std::make_pair(L"avcodec", _T("FFmpeg")), - std::make_pair(L"dxva2n", _T("DXVA2 Native")), - std::make_pair(L"dxva2cb", _T("DXVA2 Copy-back")), - std::make_pair(L"dxva2cb direct", _T("DXVA2 Copy-back (Direct)")), - std::make_pair(L"cuvid", _T("NVIDIA CUVID")), - std::make_pair(L"quicksync", _T("Intel QuickSync")), - std::make_pair(L"d3d11 cb direct", _T("D3D11 Copy-back (Direct)")), - std::make_pair(L"d3d11 cb", _T("D3D11 Copy-back")), - std::make_pair(L"d3d11 native", _T("D3D11 Native")), - std::make_pair(L"msdk mvc hw", _T("Intel H.264 (MVC 3D)")), - }; - - for (const auto& name : userFriendlyDecoderNames) { - if (wcscmp(decoderName, name.first) == 0) { - return name.second; - } - } - - return decoderName; -} - -static LPCTSTR pixFmtSettingsMap[LAVOutPixFmt_NB] = { - _T("yv12"), _T("nv12"), _T("yuy2"), _T("uyvy"), _T("ayuv"), _T("p010"), _T("p210"), _T("y410"), - _T("p016"), _T("p216"), _T("y416"), _T("rgb32"), _T("rgb24"), _T("v210"), _T("v410"), _T("yv16"), - _T("yv24"), _T("rgb48") -}; - -# define PCIV_INTEL 0x8086 -# define PCIV_AMD 0x1002 -# define PCIV_NVIDIA 0x10de -# define PCIV_QUALCOMM 0x4351 -# define PCIV_MICROSOFT 0x1414 - -bool GetGPUDetailsD3D9(DWORD* vendorid, DWORD* deviceid, DWORD* pixelshaderversion) { - bool result = false; - try { - IDirect3D9Ex* pD3D = nullptr; - HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D); - if (hr == D3D_OK && pD3D) { - UINT count = pD3D->GetAdapterCount(); - if (count > 0) { - D3DCAPS9 caps; - hr = pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); - if (hr == D3D_OK) { - *pixelshaderversion = caps.PixelShaderVersion & 0xFFFF; - } - D3DADAPTER_IDENTIFIER9 aid9; - hr = pD3D->GetAdapterIdentifier(0, 0, &aid9); - if (hr == D3D_OK) { - *vendorid = aid9.VendorId; - *deviceid = aid9.DeviceId; - result = true; - } - } - pD3D->Release(); - } - } catch (...) { - } - return result; -} - -#if 0 -#include - -bool SupportsD3D11VA() -{ - bool result = false; - try { - ID3D11Device* pDevice = nullptr; - ID3D11DeviceContext* pContext = nullptr; - D3D_FEATURE_LEVEL fl_available; - D3D_FEATURE_LEVEL fl_list[] = { D3D_FEATURE_LEVEL_11_1 }; - HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, fl_list, _countof(fl_list), D3D11_SDK_VERSION, &pDevice, &fl_available, &pContext); - if (hr == S_OK) { - if (fl_available >= D3D_FEATURE_LEVEL_11_1) { - result = true; - } - } - } catch (...) { - } - return result; -} -#endif - -// GPUs which have (slow) partial acceleration of HEVC -bool IntelHEVCBlacklist(DWORD deviceid) { - bool result = false; - - switch (deviceid) { - case 0x0412: // Haswell - case 0x0416: - case 0x041a: - case 0x041e: - case 0x0a16: - case 0x0a1e: - case 0x0a26: - case 0x0a2e: - case 0x0c02: - case 0x0c06: - case 0x0c12: - case 0x0c16: - case 0x0c22: - case 0x0c26: - case 0x0d06: - case 0x0d16: - case 0x0d22: - case 0x0d26: - case 0x1612: // Broadwell - case 0x1616: - case 0x161a: - case 0x161b: - case 0x161d: - case 0x161e: - case 0x1622: - case 0x1626: - case 0x162a: - case 0x162b: - case 0x162d: - case 0x162e: - result = true; - } - - return result; -} - -void CFGFilterLAVVideo::Settings::LoadSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("TrayIcon"), bTrayIcon); - - dwStreamAR = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("StreamAR"), dwStreamAR); - - dwNumThreads = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("NumThreads"), dwNumThreads); - - dwDeintFieldOrder = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintFieldOrder"), dwDeintFieldOrder); - - deintMode = (LAVDeintMode)pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintMode"), deintMode); - - dwRGBRange = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("RGBRange"), dwRGBRange); - - dwSWDeintMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintMode"), dwSWDeintMode); - - dwSWDeintOutput = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintOutput"), dwSWDeintOutput); - - dwDitherMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DitherMode"), dwDitherMode); - - for (int i = 0; i < LAVOutPixFmt_NB; ++i) { - bPixFmts[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_OUTPUTFORMAT, pixFmtSettingsMap[i], bPixFmts[i]); - } - - dwHWAccel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), -1); - if (dwHWAccel == DWORD(-1)) { - // Detect GPU and decide if HWA should be used - // ToDo: if MPCVR is used as renderer, check registry if it uses D3D11 and then use D3D11 decoding (if supported) - dwHWAccel = HWAccel_None; - DWORD vendorid = 0; - DWORD deviceid = 0; - DWORD pixelshaderversion = 0; - if (GetGPUDetailsD3D9(&vendorid, &deviceid, &pixelshaderversion)) { - if (pixelshaderversion >= 0x300) { - if (vendorid == PCIV_NVIDIA || vendorid == PCIV_INTEL || vendorid == PCIV_AMD || vendorid == PCIV_QUALCOMM) { - dwHWAccel = HWAccel_DXVA2Native; - if (vendorid == PCIV_INTEL && IntelHEVCBlacklist(deviceid)) { - bHWFormats[HWCodec_HEVC] = false; - } - } - } - } - } - - bHWFormats[HWCodec_H264] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264"), bHWFormats[HWCodec_H264]); - bHWFormats[HWCodec_VC1] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vc1"), bHWFormats[HWCodec_VC1]); - bHWFormats[HWCodec_MPEG2] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg2"), bHWFormats[HWCodec_MPEG2]); - bHWFormats[HWCodec_MPEG4] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg4"), bHWFormats[HWCodec_MPEG4]); - bHWFormats[HWCodec_MPEG2DVD] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("dvd"), bHWFormats[HWCodec_MPEG2DVD]); - bHWFormats[HWCodec_HEVC] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("hevc"), bHWFormats[HWCodec_HEVC]); - bHWFormats[HWCodec_VP9] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vp9"), bHWFormats[HWCodec_VP9]); - bHWFormats[HWCodec_H264MVC] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264mvc"), bHWFormats[HWCodec_H264MVC]); - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 1, 87)) { - bHWFormats[HWCodec_AV1] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("av1"), bHWFormats[HWCodec_AV1]); - } - - dwHWAccelResFlags = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWResFlags"), dwHWAccelResFlags); - - dwHWDeintMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintMode"), dwHWDeintMode); - - dwHWDeintOutput = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintOutput"), dwHWDeintOutput); - - if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { - dwHWAccelDeviceDXVA2 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2"), dwHWAccelDeviceDXVA2); - dwHWAccelDeviceDXVA2Desc = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2Desc"), dwHWAccelDeviceDXVA2Desc); - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { - dwHWAccelDeviceD3D11 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11"), dwHWAccelDeviceD3D11); - dwHWAccelDeviceD3D11Desc = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11Desc"), dwHWAccelDeviceD3D11Desc); - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { - bHWAccelCUVIDXVA = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelCUVIDXVA"), bHWAccelCUVIDXVA); - } -} - -void CFGFilterLAVVideo::Settings::SaveSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("TrayIcon"), bTrayIcon); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("StreamAR"), dwStreamAR); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("NumThreads"), dwNumThreads); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintFieldOrder"), dwDeintFieldOrder); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintMode"), deintMode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("RGBRange"), dwRGBRange); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintMode"), dwSWDeintMode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintOutput"), dwSWDeintOutput); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DitherMode"), dwDitherMode); - - for (int i = 0; i < LAVOutPixFmt_NB; ++i) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_OUTPUTFORMAT, pixFmtSettingsMap[i], bPixFmts[i]); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), dwHWAccel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264"), bHWFormats[HWCodec_H264]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vc1"), bHWFormats[HWCodec_VC1]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg2"), bHWFormats[HWCodec_MPEG2]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg4"), bHWFormats[HWCodec_MPEG4]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("dvd"), bHWFormats[HWCodec_MPEG2DVD]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("hevc"), bHWFormats[HWCodec_HEVC]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vp9"), bHWFormats[HWCodec_VP9]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264mvc"), bHWFormats[HWCodec_H264MVC]); - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 1, 87)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("av1"), bHWFormats[HWCodec_AV1]); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWResFlags"), dwHWAccelResFlags); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintMode"), dwHWDeintMode); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintOutput"), dwHWDeintOutput); - - if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2"), dwHWAccelDeviceDXVA2); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2Desc"), dwHWAccelDeviceDXVA2Desc); - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11"), dwHWAccelDeviceD3D11); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11Desc"), dwHWAccelDeviceD3D11Desc); - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelCUVIDXVA"), bHWAccelCUVIDXVA); - } -} - -bool CFGFilterLAVVideo::Settings::GetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - bTrayIcon = pLAVFSettings->GetTrayIcon(); - - dwStreamAR = pLAVFSettings->GetStreamAR(); - - dwNumThreads = pLAVFSettings->GetNumThreads(); - - dwDeintFieldOrder = pLAVFSettings->GetDeintFieldOrder(); - - deintMode = pLAVFSettings->GetDeinterlacingMode(); - - dwRGBRange = pLAVFSettings->GetRGBOutputRange(); - - dwSWDeintMode = pLAVFSettings->GetSWDeintMode(); - - dwSWDeintOutput = pLAVFSettings->GetSWDeintOutput(); - - dwDitherMode = pLAVFSettings->GetDitherMode(); - - for (int i = 0; i < LAVOutPixFmt_NB; ++i) { - bPixFmts[i] = pLAVFSettings->GetPixelFormat((LAVOutPixFmts)i); - } - - dwHWAccel = pLAVFSettings->GetHWAccel(); - - for (int i = 0; i < HWCodec_NB; ++i) { - bHWFormats[i] = pLAVFSettings->GetHWAccelCodec((LAVVideoHWCodec)i); - } - - dwHWAccelResFlags = pLAVFSettings->GetHWAccelResolutionFlags(); - - dwHWDeintMode = pLAVFSettings->GetHWAccelDeintMode(); - - dwHWDeintOutput = pLAVFSettings->GetHWAccelDeintOutput(); - - if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { - dwHWAccelDeviceDXVA2 = pLAVFSettings->GetHWAccelDeviceIndex(HWAccel_DXVA2CopyBack, &dwHWAccelDeviceDXVA2Desc); - } else { - dwHWAccelDeviceDXVA2 = LAVHWACCEL_DEVICE_DEFAULT; - dwHWAccelDeviceDXVA2Desc = 0; - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { - dwHWAccelDeviceD3D11 = pLAVFSettings->GetHWAccelDeviceIndex(HWAccel_D3D11, &dwHWAccelDeviceD3D11Desc); - } else { - dwHWAccelDeviceD3D11 = LAVHWACCEL_DEVICE_DEFAULT; - dwHWAccelDeviceD3D11Desc = 0; - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { - bHWAccelCUVIDXVA = pLAVFSettings->GetHWAccelDeintHQ(); - } else { - bHWAccelCUVIDXVA = TRUE; - } - - return true; -} - -bool CFGFilterLAVVideo::Settings::SetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - pLAVFSettings->SetTrayIcon(bTrayIcon); - - pLAVFSettings->SetStreamAR(dwStreamAR); - - pLAVFSettings->SetNumThreads(dwNumThreads); - - pLAVFSettings->SetDeintFieldOrder((LAVDeintFieldOrder)dwDeintFieldOrder); - - pLAVFSettings->SetDeinterlacingMode(deintMode); - - pLAVFSettings->SetRGBOutputRange(dwRGBRange); - - pLAVFSettings->SetSWDeintMode((LAVSWDeintModes)dwSWDeintMode); - - pLAVFSettings->SetSWDeintOutput((LAVDeintOutput)dwSWDeintOutput); - - pLAVFSettings->SetDitherMode((LAVDitherMode)dwDitherMode); - - for (int i = 0; i < LAVOutPixFmt_NB; ++i) { - pLAVFSettings->SetPixelFormat((LAVOutPixFmts)i, bPixFmts[i]); - } - - pLAVFSettings->SetHWAccel((LAVHWAccel)dwHWAccel); - - for (int i = 0; i < HWCodec_NB; ++i) { - pLAVFSettings->SetHWAccelCodec((LAVVideoHWCodec)i, bHWFormats[i]); - } - - pLAVFSettings->SetHWAccelResolutionFlags(dwHWAccelResFlags); - - pLAVFSettings->SetHWAccelDeintMode((LAVHWDeintModes)dwHWDeintMode); - - pLAVFSettings->SetHWAccelDeintOutput((LAVDeintOutput)dwHWDeintOutput); - - if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { - pLAVFSettings->SetHWAccelDeviceIndex(HWAccel_DXVA2CopyBack, dwHWAccelDeviceDXVA2, dwHWAccelDeviceDXVA2Desc); - } - if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { - pLAVFSettings->SetHWAccelDeviceIndex(HWAccel_D3D11, dwHWAccelDeviceD3D11, dwHWAccelDeviceD3D11Desc); - } - if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { - pLAVFSettings->SetHWAccelDeintHQ(bHWAccelCUVIDXVA); - } - - // Force RV1/2 and v210/v410 enabled, the user can control it from our own options - pLAVFSettings->SetFormatConfiguration(Codec_RV12, TRUE); - pLAVFSettings->SetFormatConfiguration(Codec_v210, TRUE); - // Enable Cinepack and QPEG so that they can be used in low-merit mode - pLAVFSettings->SetFormatConfiguration(Codec_Cinepak, TRUE); - pLAVFSettings->SetFormatConfiguration(Codec_QPEG, TRUE); - - // Custom interface available only in patched build, will be removed after it's upstreamed - if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { - pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); - } - - if (AfxGetAppSettings().iLAVGPUDevice != DWORD_MAX) { - pLAVFSettings->SetGPUDeviceIndex(AfxGetAppSettings().iLAVGPUDevice); - } - - return true; -} - - -// -// CFGFilterLAVAudio -// - -const CString CFGFilterLAVAudio::filename = _T("LAVAudio.ax"); - -CFGFilterLAVAudio::CFGFilterLAVAudio(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) - : CFGFilterLAV(GUID_LAVAudio, path, L"LAV Audio Decoder (internal)", bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -HRESULT CFGFilterLAVAudio::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - HRESULT hr = __super::Create(ppBF, pUnks); - - if (SUCCEEDED(hr)) { - if (!CheckVersion(m_path)) { - hr = E_FAIL; - } else if (CComQIPtr pLAVFSettings = *ppBF) { - // Take control over LAVAudio's settings, the settings are reseted to default values - hr = pLAVFSettings->SetRuntimeConfig(TRUE); - - if (SUCCEEDED(hr)) { - if (!isPreview) { - Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVAudio - settings.LoadSettings(); // Load our current settings from registry/ini - settings.SetSettings(pLAVFSettings); // Set our settings in LAVAudio - } - } - // Keep track of LAVFilters instances in runtime mode - s_instances.AddTail(*ppBF); - } - } else { - hr = E_NOINTERFACE; - } - } - - return hr; -} - -void CFGFilterLAVAudio::ShowPropertyPages(CWnd* pParendWnd) -{ - CFGFilterLAV::ShowPropertyPages(pParendWnd); -} - -static LPCTSTR bitstreamingCodecs[Bitstream_NB] = { - _T("ac3"), _T("eac3"), _T("truehd"), _T("dts"), _T("dtshd") -}; - -static LPCTSTR sampleFormats[SampleFormat_Bitstream] = { - _T("s16"), _T("s24"), _T("s32"), _T("u8"), _T("fp32") -}; - -void CFGFilterLAVAudio::Settings::LoadSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("TrayIcon"), bTrayIcon); - - bDRCEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCEnabled"), bDRCEnabled); - - iDRCLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCLevel"), iDRCLevel); - - bDTSHDFraming = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DTSHDFraming"), bDTSHDFraming); - - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { - bBitstreamingFallback = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("BitstreamingFallback"), bBitstreamingFallback); - } - - bAutoAVSync = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AutoAVSync"), bAutoAVSync); - - bExpandMono = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("ExpandMono"), bExpandMono); - - bExpand61 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Expand61"), bExpand61); - - bOutputStandardLayout = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("OutputStandardLayout"), bOutputStandardLayout); - - bOutput51Legacy = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Output51Legacy"), bOutput51Legacy); - - bMixingEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Mixing"), bMixingEnabled); - - dwMixingLayout = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLayout"), dwMixingLayout); - - dwMixingFlags = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingFlags"), dwMixingFlags); - - dwMixingMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingMode"), dwMixingMode); - - dwMixingCenterLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingCenterLevel"), dwMixingCenterLevel); - - dwMixingSurroundLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingSurroundLevel"), dwMixingSurroundLevel); - - dwMixingLFELevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLFELevel"), dwMixingLFELevel); - - bAudioDelayEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelayEnabled"), bAudioDelayEnabled); - - iAudioDelay = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelay"), iAudioDelay); - - for (int i = 0; i < Bitstream_NB; ++i) { - CString key = CString(_T("Bitstreaming_")) + bitstreamingCodecs[i]; - bBitstream[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bBitstream[i]); - } - - for (int i = 0; i < SampleFormat_Bitstream; ++i) { - CString key = CString(_T("SampleFormat_")) + sampleFormats[i]; - bSampleFormats[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bSampleFormats[i]); - } - - bSampleConvertDither = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("SampleConvertDither"), bSampleConvertDither); -} - -void CFGFilterLAVAudio::Settings::SaveSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("TrayIcon"), bTrayIcon); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCEnabled"), bDRCEnabled); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCLevel"), iDRCLevel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DTSHDFraming"), bDTSHDFraming); - - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("BitstreamingFallback"), bBitstreamingFallback); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AutoAVSync"), bAutoAVSync); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("ExpandMono"), bExpandMono); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Expand61"), bExpand61); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("OutputStandardLayout"), bOutputStandardLayout); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Output51Legacy"), bOutput51Legacy); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Mixing"), bMixingEnabled); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLayout"), dwMixingLayout); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingFlags"), dwMixingFlags); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingMode"), dwMixingMode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingCenterLevel"), dwMixingCenterLevel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingSurroundLevel"), dwMixingSurroundLevel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLFELevel"), dwMixingLFELevel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelayEnabled"), bAudioDelayEnabled); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelay"), iAudioDelay); - - for (int i = 0; i < Bitstream_NB; ++i) { - CString key = CString(_T("Bitstreaming_")) + bitstreamingCodecs[i]; - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bBitstream[i]); - } - - for (int i = 0; i < SampleFormat_Bitstream; ++i) { - CString key = CString(_T("SampleFormat_")) + sampleFormats[i]; - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bSampleFormats[i]); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("SampleConvertDither"), bSampleConvertDither); -} - -bool CFGFilterLAVAudio::Settings::GetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - bTrayIcon = pLAVFSettings->GetTrayIcon(); - - pLAVFSettings->GetDRC(&bDRCEnabled, &iDRCLevel); - - bDTSHDFraming = pLAVFSettings->GetDTSHDFraming(); - - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { - bBitstreamingFallback = pLAVFSettings->GetBitstreamingFallback(); - } else { - bBitstreamingFallback = FALSE; - } - - bAutoAVSync = pLAVFSettings->GetAutoAVSync(); - - bExpandMono = pLAVFSettings->GetExpandMono(); - - bExpand61 = pLAVFSettings->GetExpand61(); - - bOutputStandardLayout = pLAVFSettings->GetOutputStandardLayout(); - - bOutput51Legacy = pLAVFSettings->GetOutput51LegacyLayout(); - - bMixingEnabled = pLAVFSettings->GetMixingEnabled(); - - dwMixingLayout = pLAVFSettings->GetMixingLayout(); - - dwMixingFlags = pLAVFSettings->GetMixingFlags(); - - dwMixingMode = pLAVFSettings->GetMixingMode(); - - pLAVFSettings->GetMixingLevels(&dwMixingCenterLevel, &dwMixingSurroundLevel, &dwMixingLFELevel); - - pLAVFSettings->GetAudioDelay(&bAudioDelayEnabled, &iAudioDelay); - - for (int i = 0; i < Bitstream_NB; ++i) { - bBitstream[i] = pLAVFSettings->GetBitstreamConfig((LAVBitstreamCodec)i); - } - - for (int i = 0; i < SampleFormat_Bitstream; ++i) { - bSampleFormats[i] = pLAVFSettings->GetSampleFormat((LAVAudioSampleFormat)i); - } - - bSampleConvertDither = pLAVFSettings->GetSampleConvertDithering(); - - return true; -} - -bool CFGFilterLAVAudio::Settings::SetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - pLAVFSettings->SetTrayIcon(bTrayIcon); - - pLAVFSettings->SetDRC(bDRCEnabled, iDRCLevel); - - pLAVFSettings->SetDTSHDFraming(bDTSHDFraming); - - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { - pLAVFSettings->SetBitstreamingFallback(bBitstreamingFallback); - } - - pLAVFSettings->SetAutoAVSync(bAutoAVSync); - - pLAVFSettings->SetExpandMono(bExpandMono); - - pLAVFSettings->SetExpand61(bExpand61); - - pLAVFSettings->SetOutputStandardLayout(bOutputStandardLayout); - - pLAVFSettings->SetOutput51LegacyLayout(bOutput51Legacy); - - pLAVFSettings->SetMixingEnabled(bMixingEnabled); - - pLAVFSettings->SetMixingLayout(dwMixingLayout); - - pLAVFSettings->SetMixingFlags(dwMixingFlags); - - pLAVFSettings->SetMixingMode((LAVAudioMixingMode)dwMixingMode); - - pLAVFSettings->SetMixingLevels(dwMixingCenterLevel, dwMixingSurroundLevel, dwMixingLFELevel); - - pLAVFSettings->SetAudioDelay(bAudioDelayEnabled, iAudioDelay); - - for (int i = 0; i < Bitstream_NB; ++i) { - pLAVFSettings->SetBitstreamConfig((LAVBitstreamCodec)i, bBitstream[i]); - } - - for (int i = 0; i < SampleFormat_Bitstream; ++i) { - pLAVFSettings->SetSampleFormat((LAVAudioSampleFormat)i, bSampleFormats[i]); - } - - pLAVFSettings->SetSampleConvertDithering(bSampleConvertDither); - - // The internal LAV Audio Decoder will not be registered to handle WMA formats - // since the system decoder is preferred. However we can still enable those - // formats internally so that they are used in low-merit mode. - pLAVFSettings->SetFormatConfiguration(Codec_WMA2, TRUE); - pLAVFSettings->SetFormatConfiguration(Codec_WMAPRO, TRUE); - pLAVFSettings->SetFormatConfiguration(Codec_WMALL, TRUE); - - // Custom interface available only in patched build, will be removed after it's upstreamed - if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { - pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); - } - - return true; -} +/* + * (C) 2013-2018 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "PathUtils.h" +#include "../filters/InternalPropertyPage.h" +#include "../filters/PinInfoWnd.h" +#include + +#include +#include "FGFilterLAV.h" + +#define LAV_FILTERS_VERSION(major, minor, rev, commit) ((QWORD)(major) << 48 | (QWORD)(minor) << 32 | (QWORD)(rev) << 16 | (QWORD)(commit)) + +#ifndef _WIN64 +#define LAVFILTERS_DIR _T("LAVFilters\\") +#else +#define LAVFILTERS_DIR _T("LAVFilters64\\") +#endif + +// +// CFGFilterLAV +// + +CList CFGFilterLAV::s_instances; +QWORD CFGFilterLAV::lav_version = 0; + +CFGFilterLAV::CFGFilterLAV(const CLSID& clsid, CString path, CStringW name, bool bAddLowMeritSuffix, UINT64 merit, bool bIsPreview) + : isPreview(bIsPreview) + , CFGFilterFile(clsid, path, name + (bAddLowMeritSuffix ? LowMeritSuffix : L""), merit) +{ +} + +CString CFGFilterLAV::GetFilterPath(LAVFILTER_TYPE filterType) +{ + // Default path + CString filterPath = PathUtils::CombinePaths(PathUtils::GetProgramPath(), LAVFILTERS_DIR); + CLSID filterCLSID; + + switch (filterType) { + case SPLITTER: + case SPLITTER_SOURCE: + filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVSplitterBase::filename); + filterCLSID = GUID_LAVSplitter; + break; + case VIDEO_DECODER: + filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVVideo::filename); + filterCLSID = GUID_LAVVideo; + break; + case AUDIO_DECODER: + filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVAudio::filename); + filterCLSID = GUID_LAVAudio; + break; + default: + ASSERT(FALSE); // This should never happen + break; + } + +#if ENABLE_LOAD_EXTERNAL_LAVF_AS_INTERNAL + // Check that the filter's version is correct + if (!CheckVersion(filterPath)) { + // If not, check if a registered version of the filter is available. + filterPath = ::GetFilterPath(filterCLSID); + // and if it can be used + if (!CheckVersion(filterPath)) { + filterPath = _T(""); + } + } +#endif + + return filterPath; +} + +bool CFGFilterLAV::CheckVersion(CString filterPath) +{ + QWORD fversion = FileVersionInfo::GetFileVersionNum(filterPath); + if (fversion >= 0 && (lav_version == 0 || lav_version > fversion)) { + lav_version = fversion; + } + + return fversion >= LAV_FILTERS_VERSION(0, 68, 0, 0); +} + +CString CFGFilterLAV::GetVersion(LAVFILTER_TYPE filterType /*= INVALID*/) +{ + CStringList paths; + + if (filterType == INVALID) { + paths.AddTail(GetFilterPath(SPLITTER)); + paths.AddTail(GetFilterPath(VIDEO_DECODER)); + paths.AddTail(GetFilterPath(AUDIO_DECODER)); + } else { + paths.AddTail(GetFilterPath(filterType)); + } + + QWORD uiVersionMin = UINT64_MAX; + QWORD uiVersionMax = 0ui64; + CString strVersionMin, strVersionMax; + POSITION pos = paths.GetHeadPosition(); + while (pos) { + CString& path = paths.GetNext(pos); + + QWORD version = FileVersionInfo::GetFileVersionNum(path); + if (version) { + if (version < uiVersionMin) { + uiVersionMin = version; + strVersionMin = FileVersionInfo::FormatVersionString(version); + } + if (version > uiVersionMax) { + uiVersionMax = version; + strVersionMax = FileVersionInfo::FormatVersionString(version); + } + } + } + + CString version; + if (uiVersionMin != UINT64_MAX) { + version = strVersionMin; + if (uiVersionMax != uiVersionMin) { + version.AppendFormat(_T(" - %s"), strVersionMax.GetString()); + } + } + + return version; +} + +CFGFilterLAV* CFGFilterLAV::CreateFilter(LAVFILTER_TYPE filterType, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) +{ + CFGFilterLAV* filter = nullptr; + + CString filterPath = GetFilterPath(filterType); + + switch (filterType) { + case SPLITTER: + filter = DEBUG_NEW CFGFilterLAVSplitter(filterPath, merit, bAddLowMeritSuffix, bIsPreview); + break; + case SPLITTER_SOURCE: + filter = DEBUG_NEW CFGFilterLAVSplitterSource(filterPath, merit, bAddLowMeritSuffix, bIsPreview); + break; + case VIDEO_DECODER: + filter = DEBUG_NEW CFGFilterLAVVideo(filterPath, merit, bAddLowMeritSuffix, bIsPreview); + break; + case AUDIO_DECODER: + filter = DEBUG_NEW CFGFilterLAVAudio(filterPath, merit, bAddLowMeritSuffix, bIsPreview); + break; + default: + ASSERT(FALSE); // This should never happen + break; + } + + return filter; +} + +CFGFilterLAV* CFGFilterLAV::CreateFilterPreview(LAVFILTER_TYPE filterType, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/) { + CFGFilterLAV* filter = CreateFilter(filterType, merit, bAddLowMeritSuffix, true); + + return filter; +} + + +bool CFGFilterLAV::IsInternalInstance(IBaseFilter* pBF, LAVFILTER_TYPE* pLAVFilterType /*= nullptr*/) +{ + bool bIsInternalInstance = (s_instances.Find(pBF) != nullptr); + + if (bIsInternalInstance && pLAVFilterType) { + CLSID clsid; + *pLAVFilterType = INVALID; + + if (SUCCEEDED(pBF->GetClassID(&clsid))) { + if (clsid == GUID_LAVSplitter) { + *pLAVFilterType = SPLITTER; + } else if (clsid == GUID_LAVSplitterSource) { + *pLAVFilterType = SPLITTER_SOURCE; + } else if (clsid == GUID_LAVVideo) { + *pLAVFilterType = VIDEO_DECODER; + } else if (clsid == GUID_LAVAudio) { + *pLAVFilterType = AUDIO_DECODER; + } + } + } + + return bIsInternalInstance; +} + +HRESULT CFGFilterLAV::PropertyPageCallback(IBaseFilter* pBF) +{ + CheckPointer(pBF, E_POINTER); + + CComPropertySheet ps(IDS_PROPSHEET_PROPERTIES, AfxGetMyApp()->GetMainWnd()); + + // Find out which internal filter we are opening the property page for + CFGFilterLAV::LAVFILTER_TYPE LAVFilterType = CFGFilterLAV::INVALID; + if (!CFGFilterLAV::IsInternalInstance(pBF, &LAVFilterType)) { + return E_UNEXPECTED; + } + + HRESULT hr = E_FAIL; + if (CComQIPtr pSPP = pBF) { + ps.AddPages(pSPP, (LAVFilterType != CFGFilterLAV::AUDIO_DECODER) ? 1 : 2); + } + + CComPtr pPP = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr); + ps.AddPage(pPP, pBF); + + if (ps.GetPageCount() > 1) { + ps.DoModal(); + + if (CComQIPtr pLAVFSettings = pBF) { + CFGFilterLAVSplitterBase::Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get current settings from LAVSplitter + settings.SaveSettings(); // Save them to the registry/ini + } + } else if (CComQIPtr pLAVVideoSettings = pBF) { + CFGFilterLAVVideo::Settings settings; + if (settings.GetSettings(pLAVVideoSettings)) { // Get current settings from LAVVideo + settings.SaveSettings(); // Save them to the registry/ini + } + } else if (CComQIPtr pLAVAudioSettings = pBF) { + CFGFilterLAVAudio::Settings settings; + if (settings.GetSettings(pLAVAudioSettings)) { // Get current settings from LAVAudio + settings.SaveSettings(); // Save them to the registry/ini + } + } + + hr = S_OK; + } + + return hr; +} + +// +// CFGFilterLAVSplitterBase +// + +const CString CFGFilterLAVSplitterBase::filename = _T("LAVSplitter.ax"); + +CFGFilterLAVSplitterBase::CFGFilterLAVSplitterBase(CString path, const CLSID& clsid, CStringW name, bool bAddLowMeritSuffix, UINT64 merit, bool bIsPreview) + : CFGFilterLAV(clsid, path, name, bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +HRESULT CFGFilterLAVSplitterBase::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + HRESULT hr = __super::Create(ppBF, pUnks); + + if (SUCCEEDED(hr)) { + if (!CheckVersion(m_path)) { + hr = E_FAIL; + } else if (CComQIPtr pLAVFSettings = *ppBF) { + // Take control over LAVSplitter's settings, the settings are reseted to default values + hr = pLAVFSettings->SetRuntimeConfig(TRUE); + + if (SUCCEEDED(hr)) { + if (isPreview) { + pLAVFSettings->SetMaxQueueMemSize(20); + pLAVFSettings->SetMaxQueueSize(50); + pLAVFSettings->SetSubstreamsEnabled(false); + pLAVFSettings->SetSubtitleMode(LAVSubtitleMode_NoSubs); + } else { + Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVSplitter + settings.LoadSettings(); // Load our current settings from registry/ini + settings.SetSettings(pLAVFSettings); // Set our settings in LAVSplitter + } + } + + SetEnabledDisabledFormats(pLAVFSettings); + + // Keep track of LAVFilters instances in runtime mode + s_instances.AddTail(*ppBF); + } + } else { + hr = E_NOINTERFACE; + } + } + + return hr; +} + +void CFGFilterLAVSplitterBase::SetEnabledDisabledFormats(CComQIPtr pLAVFSettings) +{ + // "*" is a special case and means all formats are enabled + if (m_enabledFormats.IsEmpty() || m_enabledFormats.GetHead() != "*") { + // We turn off all formats by default to ensure that we won't hijack other filters + LPSTR* formats; + UINT nFormats; + if (SUCCEEDED(pLAVFSettings->GetFormats(&formats, &nFormats))) { + for (UINT i = 0; i < nFormats; i++) { + pLAVFSettings->SetFormatEnabled(formats[i], FALSE); + // Free the memory immediately since we won't need it later + CoTaskMemFree(formats[i]); + } + CoTaskMemFree(formats); + } + // We turn on only the formats specified explicitly + POSITION pos = m_enabledFormats.GetHeadPosition(); + while (pos) { + const CStringA& format = m_enabledFormats.GetNext(pos); + pLAVFSettings->SetFormatEnabled(format, TRUE); + } + } + + // Explicitly disabled formats + POSITION pos = m_disabledFormats.GetHeadPosition(); + while (pos) { + const CStringA& format = m_disabledFormats.GetNext(pos); + pLAVFSettings->SetFormatEnabled(format, FALSE); + } +} + +void CFGFilterLAVSplitterBase::ShowPropertyPages(CWnd* pParendWnd) +{ + CFGFilterLAV::ShowPropertyPages(pParendWnd); +} + +void CFGFilterLAVSplitterBase::Settings::LoadSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("TrayIcon"), bTrayIcon); + + prefAudioLangs = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefAudioLangs"), prefAudioLangs.c_str()); + prefSubLangs = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefSubLangs"), prefSubLangs.c_str()); + subtitleAdvanced = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleAdvanced"), subtitleAdvanced.c_str()); + + subtitleMode = (LAVSubtitleMode)pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleMode"), subtitleMode); + + bPGSForcedStream = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSForcedStream"), bPGSForcedStream); + + bPGSOnlyForced = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSOnlyForced"), bPGSOnlyForced); + + iVC1Mode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("vc1TimestampMode"), iVC1Mode); + + bSubstreams = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("substreams"), bSubstreams); + + bMatroskaExternalSegments = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("MatroskaExternalSegments"), bMatroskaExternalSegments); + + bStreamSwitchReselectSubs = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchReselectSubs"), bStreamSwitchReselectSubs); + + bStreamSwitchRemoveAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchRemoveAudio"), bStreamSwitchRemoveAudio); + + bPreferHighQualityAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PreferHighQualityAudio"), bPreferHighQualityAudio); + + bImpairedAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("ImpairedAudio"), bImpairedAudio); + + dwQueueMaxMemSize = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxSize"), dwQueueMaxMemSize); + + dwQueueMaxPackets = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxPackets"), dwQueueMaxPackets); + + dwNetworkAnalysisDuration = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("NetworkAnalysisDuration"), dwNetworkAnalysisDuration); +} + +void CFGFilterLAVSplitterBase::Settings::SaveSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("TrayIcon"), bTrayIcon); + + pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefAudioLangs"), prefAudioLangs.c_str()); + pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefSubLangs"), prefSubLangs.c_str()); + pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleAdvanced"), subtitleAdvanced.c_str()); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleMode"), subtitleMode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSForcedStream"), bPGSForcedStream); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSOnlyForced"), bPGSOnlyForced); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("vc1TimestampMode"), iVC1Mode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("substreams"), bSubstreams); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("MatroskaExternalSegments"), bMatroskaExternalSegments); + + if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchReselectSubs"), bStreamSwitchReselectSubs); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchRemoveAudio"), bStreamSwitchRemoveAudio); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PreferHighQualityAudio"), bPreferHighQualityAudio); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("ImpairedAudio"), bImpairedAudio); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxSize"), dwQueueMaxMemSize); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxPackets"), dwQueueMaxPackets); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("NetworkAnalysisDuration"), dwNetworkAnalysisDuration); +} + +bool CFGFilterLAVSplitterBase::Settings::GetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + bTrayIcon = pLAVFSettings->GetTrayIcon(); + + HRESULT hr; + LPWSTR lpwstr = nullptr; + hr = pLAVFSettings->GetPreferredLanguages(&lpwstr); + if (SUCCEEDED(hr) && lpwstr) { + prefAudioLangs = lpwstr; + CoTaskMemFree(lpwstr); + } + lpwstr = nullptr; + hr = pLAVFSettings->GetPreferredSubtitleLanguages(&lpwstr); + if (SUCCEEDED(hr) && lpwstr) { + prefSubLangs = lpwstr; + CoTaskMemFree(lpwstr); + } + lpwstr = nullptr; + hr = pLAVFSettings->GetAdvancedSubtitleConfig(&lpwstr); + if (SUCCEEDED(hr) && lpwstr) { + subtitleAdvanced = lpwstr; + CoTaskMemFree(lpwstr); + } + + subtitleMode = pLAVFSettings->GetSubtitleMode(); + + bPGSForcedStream = pLAVFSettings->GetPGSForcedStream(); + + bPGSOnlyForced = pLAVFSettings->GetPGSOnlyForced(); + + iVC1Mode = pLAVFSettings->GetVC1TimestampMode(); + + bSubstreams = pLAVFSettings->GetSubstreamsEnabled(); + + bMatroskaExternalSegments = pLAVFSettings->GetLoadMatroskaExternalSegments(); + + if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { + bStreamSwitchReselectSubs = pLAVFSettings->GetStreamSwitchReselectSubtitles(); + } else { + bStreamSwitchReselectSubs = FALSE; + } + + bStreamSwitchRemoveAudio = pLAVFSettings->GetStreamSwitchRemoveAudio(); + + bImpairedAudio = pLAVFSettings->GetUseAudioForHearingVisuallyImpaired(); + + bPreferHighQualityAudio = pLAVFSettings->GetPreferHighQualityAudioStreams(); + + dwQueueMaxMemSize = pLAVFSettings->GetMaxQueueMemSize(); + + dwQueueMaxPackets = pLAVFSettings->GetMaxQueueSize(); + + dwNetworkAnalysisDuration = pLAVFSettings->GetNetworkStreamAnalysisDuration(); + + return true; +} + +bool CFGFilterLAVSplitterBase::Settings::SetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + pLAVFSettings->SetTrayIcon(bTrayIcon); + + pLAVFSettings->SetPreferredLanguages(prefAudioLangs.c_str()); + pLAVFSettings->SetPreferredSubtitleLanguages(prefSubLangs.c_str()); + pLAVFSettings->SetAdvancedSubtitleConfig(subtitleAdvanced.c_str()); + + pLAVFSettings->SetSubtitleMode(subtitleMode); + + pLAVFSettings->SetPGSForcedStream(bPGSForcedStream); + + pLAVFSettings->SetPGSOnlyForced(bPGSOnlyForced); + + pLAVFSettings->SetVC1TimestampMode(iVC1Mode); + + pLAVFSettings->SetSubstreamsEnabled(bSubstreams); + + pLAVFSettings->SetLoadMatroskaExternalSegments(bMatroskaExternalSegments); + + if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { + pLAVFSettings->SetStreamSwitchReselectSubtitles(bStreamSwitchReselectSubs); + } + + pLAVFSettings->SetStreamSwitchRemoveAudio(bStreamSwitchRemoveAudio); + + pLAVFSettings->SetUseAudioForHearingVisuallyImpaired(bImpairedAudio); + + pLAVFSettings->SetPreferHighQualityAudioStreams(bPreferHighQualityAudio); + + pLAVFSettings->SetMaxQueueMemSize(dwQueueMaxMemSize); + + pLAVFSettings->SetMaxQueueSize(dwQueueMaxPackets); + + pLAVFSettings->SetNetworkStreamAnalysisDuration(dwNetworkAnalysisDuration); + + // Custom interface available only in patched build, will be removed after it's upstreamed + if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { + pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); + } + + return true; +} + +// +// CFGFilterLAVSplitter +// + +CFGFilterLAVSplitter::CFGFilterLAVSplitter(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) + : CFGFilterLAVSplitterBase(path, GUID_LAVSplitter, L"LAV Splitter (internal)", bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +// +// CFGFilterLAVSplitterSource +// + +CFGFilterLAVSplitterSource::CFGFilterLAVSplitterSource(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) + : CFGFilterLAVSplitterBase(path, GUID_LAVSplitterSource, L"LAV Splitter Source (internal)", bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +// +// CFGFilterLAVVideo +// + +const CString CFGFilterLAVVideo::filename = _T("LAVVideo.ax"); + +CFGFilterLAVVideo::CFGFilterLAVVideo(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) + : CFGFilterLAV(GUID_LAVVideo, path, L"LAV Video Decoder (internal)", bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +HRESULT CFGFilterLAVVideo::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + HRESULT hr = __super::Create(ppBF, pUnks); + + if (SUCCEEDED(hr)) { + if (!CheckVersion(m_path)) { + hr = E_FAIL; + } else if (CComQIPtr pLAVFSettings = *ppBF) { + // Take control over LAVVideo's settings, the settings are reseted to default values + hr = pLAVFSettings->SetRuntimeConfig(TRUE); + + if (SUCCEEDED(hr)) { + if (isPreview) { + pLAVFSettings->SetNumThreads(2); + pLAVFSettings->SetPixelFormat(LAVOutPixFmt_P010, false); + pLAVFSettings->SetPixelFormat(LAVOutPixFmt_P016, false); + } else { + Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVVideo + settings.LoadSettings(); // Load our current settings from registry/ini + settings.SetSettings(pLAVFSettings); // Set our settings in LAVVideo + } + } + // Keep track of LAVFilters instances in runtime mode + s_instances.AddTail(*ppBF); + } + } else { + hr = E_NOINTERFACE; + } + } + + return hr; +} + +void CFGFilterLAVVideo::ShowPropertyPages(CWnd* pParendWnd) +{ + CFGFilterLAV::ShowPropertyPages(pParendWnd); +} + +LPCTSTR CFGFilterLAVVideo::GetUserFriendlyDecoderName(const LPCWSTR decoderName) +{ + static constexpr std::pair userFriendlyDecoderNames[] = { + std::make_pair(L"avcodec", _T("FFmpeg")), + std::make_pair(L"dxva2n", _T("DXVA2 Native")), + std::make_pair(L"dxva2cb", _T("DXVA2 Copy-back")), + std::make_pair(L"dxva2cb direct", _T("DXVA2 Copy-back (Direct)")), + std::make_pair(L"cuvid", _T("NVIDIA CUVID")), + std::make_pair(L"quicksync", _T("Intel QuickSync")), + std::make_pair(L"d3d11 cb direct", _T("D3D11 Copy-back (Direct)")), + std::make_pair(L"d3d11 cb", _T("D3D11 Copy-back")), + std::make_pair(L"d3d11 native", _T("D3D11 Native")), + std::make_pair(L"msdk mvc hw", _T("Intel H.264 (MVC 3D)")), + }; + + for (const auto& name : userFriendlyDecoderNames) { + if (wcscmp(decoderName, name.first) == 0) { + return name.second; + } + } + + return decoderName; +} + +static LPCTSTR pixFmtSettingsMap[LAVOutPixFmt_NB] = { + _T("yv12"), _T("nv12"), _T("yuy2"), _T("uyvy"), _T("ayuv"), _T("p010"), _T("p210"), _T("y410"), + _T("p016"), _T("p216"), _T("y416"), _T("rgb32"), _T("rgb24"), _T("v210"), _T("v410"), _T("yv16"), + _T("yv24"), _T("rgb48") +}; + +# define PCIV_INTEL 0x8086 +# define PCIV_AMD 0x1002 +# define PCIV_NVIDIA 0x10de +# define PCIV_QUALCOMM 0x4351 +# define PCIV_MICROSOFT 0x1414 + +bool GetGPUDetailsD3D9(DWORD* vendorid, DWORD* deviceid, DWORD* pixelshaderversion) { + bool result = false; + try { + IDirect3D9Ex* pD3D = nullptr; + HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D); + if (hr == D3D_OK && pD3D) { + UINT count = pD3D->GetAdapterCount(); + if (count > 0) { + D3DCAPS9 caps; + hr = pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); + if (hr == D3D_OK) { + *pixelshaderversion = caps.PixelShaderVersion & 0xFFFF; + } + D3DADAPTER_IDENTIFIER9 aid9; + hr = pD3D->GetAdapterIdentifier(0, 0, &aid9); + if (hr == D3D_OK) { + *vendorid = aid9.VendorId; + *deviceid = aid9.DeviceId; + result = true; + } + } + pD3D->Release(); + } + } catch (...) { + } + return result; +} + +#if 0 +#include + +bool SupportsD3D11VA() +{ + bool result = false; + try { + ID3D11Device* pDevice = nullptr; + ID3D11DeviceContext* pContext = nullptr; + D3D_FEATURE_LEVEL fl_available; + D3D_FEATURE_LEVEL fl_list[] = { D3D_FEATURE_LEVEL_11_1 }; + HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, fl_list, _countof(fl_list), D3D11_SDK_VERSION, &pDevice, &fl_available, &pContext); + if (hr == S_OK) { + if (fl_available >= D3D_FEATURE_LEVEL_11_1) { + result = true; + } + } + } catch (...) { + } + return result; +} +#endif + +// GPUs which have (slow) partial acceleration of HEVC +bool IntelHEVCBlacklist(DWORD deviceid) { + bool result = false; + + switch (deviceid) { + case 0x0412: // Haswell + case 0x0416: + case 0x041a: + case 0x041e: + case 0x0a16: + case 0x0a1e: + case 0x0a26: + case 0x0a2e: + case 0x0c02: + case 0x0c06: + case 0x0c12: + case 0x0c16: + case 0x0c22: + case 0x0c26: + case 0x0d06: + case 0x0d16: + case 0x0d22: + case 0x0d26: + case 0x1612: // Broadwell + case 0x1616: + case 0x161a: + case 0x161b: + case 0x161d: + case 0x161e: + case 0x1622: + case 0x1626: + case 0x162a: + case 0x162b: + case 0x162d: + case 0x162e: + result = true; + } + + return result; +} + +void CFGFilterLAVVideo::Settings::LoadSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("TrayIcon"), bTrayIcon); + + dwStreamAR = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("StreamAR"), dwStreamAR); + + dwNumThreads = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("NumThreads"), dwNumThreads); + + dwDeintFieldOrder = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintFieldOrder"), dwDeintFieldOrder); + + deintMode = (LAVDeintMode)pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintMode"), deintMode); + + dwRGBRange = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("RGBRange"), dwRGBRange); + + dwSWDeintMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintMode"), dwSWDeintMode); + + dwSWDeintOutput = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintOutput"), dwSWDeintOutput); + + dwDitherMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DitherMode"), dwDitherMode); + + for (int i = 0; i < LAVOutPixFmt_NB; ++i) { + bPixFmts[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_OUTPUTFORMAT, pixFmtSettingsMap[i], bPixFmts[i]); + } + + dwHWAccel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), -1); + if (dwHWAccel == DWORD(-1)) { + // Detect GPU and decide if HWA should be used + // ToDo: if MPCVR is used as renderer, check registry if it uses D3D11 and then use D3D11 decoding (if supported) + dwHWAccel = HWAccel_None; + DWORD vendorid = 0; + DWORD deviceid = 0; + DWORD pixelshaderversion = 0; + if (GetGPUDetailsD3D9(&vendorid, &deviceid, &pixelshaderversion)) { + if (pixelshaderversion >= 0x300) { + if (vendorid == PCIV_NVIDIA || vendorid == PCIV_INTEL || vendorid == PCIV_AMD || vendorid == PCIV_QUALCOMM) { + dwHWAccel = HWAccel_DXVA2Native; + if (vendorid == PCIV_INTEL && IntelHEVCBlacklist(deviceid)) { + bHWFormats[HWCodec_HEVC] = false; + } + } + } + } + } + + bHWFormats[HWCodec_H264] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264"), bHWFormats[HWCodec_H264]); + bHWFormats[HWCodec_VC1] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vc1"), bHWFormats[HWCodec_VC1]); + bHWFormats[HWCodec_MPEG2] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg2"), bHWFormats[HWCodec_MPEG2]); + bHWFormats[HWCodec_MPEG4] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg4"), bHWFormats[HWCodec_MPEG4]); + bHWFormats[HWCodec_MPEG2DVD] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("dvd"), bHWFormats[HWCodec_MPEG2DVD]); + bHWFormats[HWCodec_HEVC] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("hevc"), bHWFormats[HWCodec_HEVC]); + bHWFormats[HWCodec_VP9] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vp9"), bHWFormats[HWCodec_VP9]); + bHWFormats[HWCodec_H264MVC] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264mvc"), bHWFormats[HWCodec_H264MVC]); + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 1, 87)) { + bHWFormats[HWCodec_AV1] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("av1"), bHWFormats[HWCodec_AV1]); + } + + dwHWAccelResFlags = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWResFlags"), dwHWAccelResFlags); + + dwHWDeintMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintMode"), dwHWDeintMode); + + dwHWDeintOutput = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintOutput"), dwHWDeintOutput); + + if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { + dwHWAccelDeviceDXVA2 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2"), dwHWAccelDeviceDXVA2); + dwHWAccelDeviceDXVA2Desc = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2Desc"), dwHWAccelDeviceDXVA2Desc); + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { + dwHWAccelDeviceD3D11 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11"), dwHWAccelDeviceD3D11); + dwHWAccelDeviceD3D11Desc = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11Desc"), dwHWAccelDeviceD3D11Desc); + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { + bHWAccelCUVIDXVA = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelCUVIDXVA"), bHWAccelCUVIDXVA); + } +} + +void CFGFilterLAVVideo::Settings::SaveSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("TrayIcon"), bTrayIcon); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("StreamAR"), dwStreamAR); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("NumThreads"), dwNumThreads); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintFieldOrder"), dwDeintFieldOrder); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintMode"), deintMode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("RGBRange"), dwRGBRange); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintMode"), dwSWDeintMode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintOutput"), dwSWDeintOutput); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DitherMode"), dwDitherMode); + + for (int i = 0; i < LAVOutPixFmt_NB; ++i) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_OUTPUTFORMAT, pixFmtSettingsMap[i], bPixFmts[i]); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), dwHWAccel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264"), bHWFormats[HWCodec_H264]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vc1"), bHWFormats[HWCodec_VC1]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg2"), bHWFormats[HWCodec_MPEG2]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg4"), bHWFormats[HWCodec_MPEG4]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("dvd"), bHWFormats[HWCodec_MPEG2DVD]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("hevc"), bHWFormats[HWCodec_HEVC]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vp9"), bHWFormats[HWCodec_VP9]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264mvc"), bHWFormats[HWCodec_H264MVC]); + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 1, 87)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("av1"), bHWFormats[HWCodec_AV1]); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWResFlags"), dwHWAccelResFlags); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintMode"), dwHWDeintMode); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintOutput"), dwHWDeintOutput); + + if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2"), dwHWAccelDeviceDXVA2); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2Desc"), dwHWAccelDeviceDXVA2Desc); + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11"), dwHWAccelDeviceD3D11); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11Desc"), dwHWAccelDeviceD3D11Desc); + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelCUVIDXVA"), bHWAccelCUVIDXVA); + } +} + +bool CFGFilterLAVVideo::Settings::GetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + bTrayIcon = pLAVFSettings->GetTrayIcon(); + + dwStreamAR = pLAVFSettings->GetStreamAR(); + + dwNumThreads = pLAVFSettings->GetNumThreads(); + + dwDeintFieldOrder = pLAVFSettings->GetDeintFieldOrder(); + + deintMode = pLAVFSettings->GetDeinterlacingMode(); + + dwRGBRange = pLAVFSettings->GetRGBOutputRange(); + + dwSWDeintMode = pLAVFSettings->GetSWDeintMode(); + + dwSWDeintOutput = pLAVFSettings->GetSWDeintOutput(); + + dwDitherMode = pLAVFSettings->GetDitherMode(); + + for (int i = 0; i < LAVOutPixFmt_NB; ++i) { + bPixFmts[i] = pLAVFSettings->GetPixelFormat((LAVOutPixFmts)i); + } + + dwHWAccel = pLAVFSettings->GetHWAccel(); + + for (int i = 0; i < HWCodec_NB; ++i) { + bHWFormats[i] = pLAVFSettings->GetHWAccelCodec((LAVVideoHWCodec)i); + } + + dwHWAccelResFlags = pLAVFSettings->GetHWAccelResolutionFlags(); + + dwHWDeintMode = pLAVFSettings->GetHWAccelDeintMode(); + + dwHWDeintOutput = pLAVFSettings->GetHWAccelDeintOutput(); + + if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { + dwHWAccelDeviceDXVA2 = pLAVFSettings->GetHWAccelDeviceIndex(HWAccel_DXVA2CopyBack, &dwHWAccelDeviceDXVA2Desc); + } else { + dwHWAccelDeviceDXVA2 = LAVHWACCEL_DEVICE_DEFAULT; + dwHWAccelDeviceDXVA2Desc = 0; + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { + dwHWAccelDeviceD3D11 = pLAVFSettings->GetHWAccelDeviceIndex(HWAccel_D3D11, &dwHWAccelDeviceD3D11Desc); + } else { + dwHWAccelDeviceD3D11 = LAVHWACCEL_DEVICE_DEFAULT; + dwHWAccelDeviceD3D11Desc = 0; + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { + bHWAccelCUVIDXVA = pLAVFSettings->GetHWAccelDeintHQ(); + } else { + bHWAccelCUVIDXVA = TRUE; + } + + return true; +} + +bool CFGFilterLAVVideo::Settings::SetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + pLAVFSettings->SetTrayIcon(bTrayIcon); + + pLAVFSettings->SetStreamAR(dwStreamAR); + + pLAVFSettings->SetNumThreads(dwNumThreads); + + pLAVFSettings->SetDeintFieldOrder((LAVDeintFieldOrder)dwDeintFieldOrder); + + pLAVFSettings->SetDeinterlacingMode(deintMode); + + pLAVFSettings->SetRGBOutputRange(dwRGBRange); + + pLAVFSettings->SetSWDeintMode((LAVSWDeintModes)dwSWDeintMode); + + pLAVFSettings->SetSWDeintOutput((LAVDeintOutput)dwSWDeintOutput); + + pLAVFSettings->SetDitherMode((LAVDitherMode)dwDitherMode); + + for (int i = 0; i < LAVOutPixFmt_NB; ++i) { + pLAVFSettings->SetPixelFormat((LAVOutPixFmts)i, bPixFmts[i]); + } + + pLAVFSettings->SetHWAccel((LAVHWAccel)dwHWAccel); + + for (int i = 0; i < HWCodec_NB; ++i) { + pLAVFSettings->SetHWAccelCodec((LAVVideoHWCodec)i, bHWFormats[i]); + } + + pLAVFSettings->SetHWAccelResolutionFlags(dwHWAccelResFlags); + + pLAVFSettings->SetHWAccelDeintMode((LAVHWDeintModes)dwHWDeintMode); + + pLAVFSettings->SetHWAccelDeintOutput((LAVDeintOutput)dwHWDeintOutput); + + if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { + pLAVFSettings->SetHWAccelDeviceIndex(HWAccel_DXVA2CopyBack, dwHWAccelDeviceDXVA2, dwHWAccelDeviceDXVA2Desc); + } + if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { + pLAVFSettings->SetHWAccelDeviceIndex(HWAccel_D3D11, dwHWAccelDeviceD3D11, dwHWAccelDeviceD3D11Desc); + } + if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { + pLAVFSettings->SetHWAccelDeintHQ(bHWAccelCUVIDXVA); + } + + // Force RV1/2 and v210/v410 enabled, the user can control it from our own options + pLAVFSettings->SetFormatConfiguration(Codec_RV12, TRUE); + pLAVFSettings->SetFormatConfiguration(Codec_v210, TRUE); + // Enable Cinepack and QPEG so that they can be used in low-merit mode + pLAVFSettings->SetFormatConfiguration(Codec_Cinepak, TRUE); + pLAVFSettings->SetFormatConfiguration(Codec_QPEG, TRUE); + + // Custom interface available only in patched build, will be removed after it's upstreamed + if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { + pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); + } + + if (AfxGetAppSettings().iLAVGPUDevice != DWORD_MAX) { + pLAVFSettings->SetGPUDeviceIndex(AfxGetAppSettings().iLAVGPUDevice); + } + + return true; +} + + +// +// CFGFilterLAVAudio +// + +const CString CFGFilterLAVAudio::filename = _T("LAVAudio.ax"); + +CFGFilterLAVAudio::CFGFilterLAVAudio(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) + : CFGFilterLAV(GUID_LAVAudio, path, L"LAV Audio Decoder (internal)", bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +HRESULT CFGFilterLAVAudio::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + HRESULT hr = __super::Create(ppBF, pUnks); + + if (SUCCEEDED(hr)) { + if (!CheckVersion(m_path)) { + hr = E_FAIL; + } else if (CComQIPtr pLAVFSettings = *ppBF) { + // Take control over LAVAudio's settings, the settings are reseted to default values + hr = pLAVFSettings->SetRuntimeConfig(TRUE); + + if (SUCCEEDED(hr)) { + if (!isPreview) { + Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVAudio + settings.LoadSettings(); // Load our current settings from registry/ini + settings.SetSettings(pLAVFSettings); // Set our settings in LAVAudio + } + } + // Keep track of LAVFilters instances in runtime mode + s_instances.AddTail(*ppBF); + } + } else { + hr = E_NOINTERFACE; + } + } + + return hr; +} + +void CFGFilterLAVAudio::ShowPropertyPages(CWnd* pParendWnd) +{ + CFGFilterLAV::ShowPropertyPages(pParendWnd); +} + +static LPCTSTR bitstreamingCodecs[Bitstream_NB] = { + _T("ac3"), _T("eac3"), _T("truehd"), _T("dts"), _T("dtshd") +}; + +static LPCTSTR sampleFormats[SampleFormat_Bitstream] = { + _T("s16"), _T("s24"), _T("s32"), _T("u8"), _T("fp32") +}; + +void CFGFilterLAVAudio::Settings::LoadSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("TrayIcon"), bTrayIcon); + + bDRCEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCEnabled"), bDRCEnabled); + + iDRCLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCLevel"), iDRCLevel); + + bDTSHDFraming = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DTSHDFraming"), bDTSHDFraming); + + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { + bBitstreamingFallback = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("BitstreamingFallback"), bBitstreamingFallback); + } + + bAutoAVSync = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AutoAVSync"), bAutoAVSync); + + bExpandMono = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("ExpandMono"), bExpandMono); + + bExpand61 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Expand61"), bExpand61); + + bOutputStandardLayout = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("OutputStandardLayout"), bOutputStandardLayout); + + bOutput51Legacy = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Output51Legacy"), bOutput51Legacy); + + bMixingEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Mixing"), bMixingEnabled); + + dwMixingLayout = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLayout"), dwMixingLayout); + + dwMixingFlags = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingFlags"), dwMixingFlags); + + dwMixingMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingMode"), dwMixingMode); + + dwMixingCenterLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingCenterLevel"), dwMixingCenterLevel); + + dwMixingSurroundLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingSurroundLevel"), dwMixingSurroundLevel); + + dwMixingLFELevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLFELevel"), dwMixingLFELevel); + + bAudioDelayEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelayEnabled"), bAudioDelayEnabled); + + iAudioDelay = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelay"), iAudioDelay); + + for (int i = 0; i < Bitstream_NB; ++i) { + CString key = CString(_T("Bitstreaming_")) + bitstreamingCodecs[i]; + bBitstream[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bBitstream[i]); + } + + for (int i = 0; i < SampleFormat_Bitstream; ++i) { + CString key = CString(_T("SampleFormat_")) + sampleFormats[i]; + bSampleFormats[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bSampleFormats[i]); + } + + bSampleConvertDither = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("SampleConvertDither"), bSampleConvertDither); +} + +void CFGFilterLAVAudio::Settings::SaveSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("TrayIcon"), bTrayIcon); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCEnabled"), bDRCEnabled); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCLevel"), iDRCLevel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DTSHDFraming"), bDTSHDFraming); + + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("BitstreamingFallback"), bBitstreamingFallback); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AutoAVSync"), bAutoAVSync); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("ExpandMono"), bExpandMono); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Expand61"), bExpand61); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("OutputStandardLayout"), bOutputStandardLayout); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Output51Legacy"), bOutput51Legacy); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Mixing"), bMixingEnabled); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLayout"), dwMixingLayout); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingFlags"), dwMixingFlags); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingMode"), dwMixingMode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingCenterLevel"), dwMixingCenterLevel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingSurroundLevel"), dwMixingSurroundLevel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLFELevel"), dwMixingLFELevel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelayEnabled"), bAudioDelayEnabled); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelay"), iAudioDelay); + + for (int i = 0; i < Bitstream_NB; ++i) { + CString key = CString(_T("Bitstreaming_")) + bitstreamingCodecs[i]; + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bBitstream[i]); + } + + for (int i = 0; i < SampleFormat_Bitstream; ++i) { + CString key = CString(_T("SampleFormat_")) + sampleFormats[i]; + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bSampleFormats[i]); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("SampleConvertDither"), bSampleConvertDither); +} + +bool CFGFilterLAVAudio::Settings::GetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + bTrayIcon = pLAVFSettings->GetTrayIcon(); + + pLAVFSettings->GetDRC(&bDRCEnabled, &iDRCLevel); + + bDTSHDFraming = pLAVFSettings->GetDTSHDFraming(); + + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { + bBitstreamingFallback = pLAVFSettings->GetBitstreamingFallback(); + } else { + bBitstreamingFallback = FALSE; + } + + bAutoAVSync = pLAVFSettings->GetAutoAVSync(); + + bExpandMono = pLAVFSettings->GetExpandMono(); + + bExpand61 = pLAVFSettings->GetExpand61(); + + bOutputStandardLayout = pLAVFSettings->GetOutputStandardLayout(); + + bOutput51Legacy = pLAVFSettings->GetOutput51LegacyLayout(); + + bMixingEnabled = pLAVFSettings->GetMixingEnabled(); + + dwMixingLayout = pLAVFSettings->GetMixingLayout(); + + dwMixingFlags = pLAVFSettings->GetMixingFlags(); + + dwMixingMode = pLAVFSettings->GetMixingMode(); + + pLAVFSettings->GetMixingLevels(&dwMixingCenterLevel, &dwMixingSurroundLevel, &dwMixingLFELevel); + + pLAVFSettings->GetAudioDelay(&bAudioDelayEnabled, &iAudioDelay); + + for (int i = 0; i < Bitstream_NB; ++i) { + bBitstream[i] = pLAVFSettings->GetBitstreamConfig((LAVBitstreamCodec)i); + } + + for (int i = 0; i < SampleFormat_Bitstream; ++i) { + bSampleFormats[i] = pLAVFSettings->GetSampleFormat((LAVAudioSampleFormat)i); + } + + bSampleConvertDither = pLAVFSettings->GetSampleConvertDithering(); + + return true; +} + +bool CFGFilterLAVAudio::Settings::SetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + pLAVFSettings->SetTrayIcon(bTrayIcon); + + pLAVFSettings->SetDRC(bDRCEnabled, iDRCLevel); + + pLAVFSettings->SetDTSHDFraming(bDTSHDFraming); + + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { + pLAVFSettings->SetBitstreamingFallback(bBitstreamingFallback); + } + + pLAVFSettings->SetAutoAVSync(bAutoAVSync); + + pLAVFSettings->SetExpandMono(bExpandMono); + + pLAVFSettings->SetExpand61(bExpand61); + + pLAVFSettings->SetOutputStandardLayout(bOutputStandardLayout); + + pLAVFSettings->SetOutput51LegacyLayout(bOutput51Legacy); + + pLAVFSettings->SetMixingEnabled(bMixingEnabled); + + pLAVFSettings->SetMixingLayout(dwMixingLayout); + + pLAVFSettings->SetMixingFlags(dwMixingFlags); + + pLAVFSettings->SetMixingMode((LAVAudioMixingMode)dwMixingMode); + + pLAVFSettings->SetMixingLevels(dwMixingCenterLevel, dwMixingSurroundLevel, dwMixingLFELevel); + + pLAVFSettings->SetAudioDelay(bAudioDelayEnabled, iAudioDelay); + + for (int i = 0; i < Bitstream_NB; ++i) { + pLAVFSettings->SetBitstreamConfig((LAVBitstreamCodec)i, bBitstream[i]); + } + + for (int i = 0; i < SampleFormat_Bitstream; ++i) { + pLAVFSettings->SetSampleFormat((LAVAudioSampleFormat)i, bSampleFormats[i]); + } + + pLAVFSettings->SetSampleConvertDithering(bSampleConvertDither); + + // The internal LAV Audio Decoder will not be registered to handle WMA formats + // since the system decoder is preferred. However we can still enable those + // formats internally so that they are used in low-merit mode. + pLAVFSettings->SetFormatConfiguration(Codec_WMA2, TRUE); + pLAVFSettings->SetFormatConfiguration(Codec_WMAPRO, TRUE); + pLAVFSettings->SetFormatConfiguration(Codec_WMALL, TRUE); + + // Custom interface available only in patched build, will be removed after it's upstreamed + if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { + pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); + } + + return true; +} diff --git a/src/mpc-hc/FGManager.cpp b/src/mpc-hc/FGManager.cpp index 5a6dcfba1c7..79d8f2169ae 100644 --- a/src/mpc-hc/FGManager.cpp +++ b/src/mpc-hc/FGManager.cpp @@ -1,3044 +1,3044 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "FGManager.h" -#include "../DeCSS/VobFile.h" -#include "../filters/Filters.h" -#include "AllocatorCommon.h" -#include "DeinterlacerFilter.h" -#include "FakeFilterMapper2.h" -#include "FileVersionInfo.h" -#include "IPinHook.h" -#include "NullRenderers.h" -#include "PathUtils.h" -#include "SyncAllocatorPresenter.h" -#include "mplayerc.h" -#include "sanear/src/Factory.h" -#include "../src/thirdparty/MpcAudioRenderer/MpcAudioRenderer.h" -#include "DSUtil.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "../src/thirdparty/LAVFilters/src/include/IURLSourceFilterLAV.h" - -#include -#include "moreuuids.h" -#include - -#if !TRACE_GRAPH_BUILD -#undef TRACE -#define TRACE(...) -#endif - -// -// CFGManager -// - -class CNullAudioRenderer; - -CFGManager::CFGManager(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) - : CUnknown(pName, pUnk) - , m_dwRegister(0) - , m_hWnd(hWnd) - , m_bIsPreview(IsPreview) - , m_bPreviewSupportsRotation(false) - , m_ignoreVideo(false) - , m_bIsCapture(false) - , m_source() - , m_transform() - , m_override() - , m_deadends() - , m_aborted(false) - , m_useragent() - , m_referrer() -{ - m_pUnkInner.CoCreateInstance(CLSID_FilterGraph, GetOwner()); - m_pFM.CoCreateInstance(CLSID_FilterMapper2); -} - -CFGManager::~CFGManager() -{ - CAutoLock cAutoLock(this); - while (!m_source.IsEmpty()) { - delete m_source.RemoveHead(); - } - while (!m_transform.IsEmpty()) { - delete m_transform.RemoveHead(); - } - while (!m_override.IsEmpty()) { - delete m_override.RemoveHead(); - } - m_pUnks.RemoveAll(); - m_pUnkInner.Release(); -} - -STDMETHODIMP CFGManager::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFilterGraph) - QI(IGraphBuilder) - QI(IFilterGraph2) - QI(IGraphBuilder2) - QI(IGraphBuilderDeadEnd) - (m_pUnkInner && riid != IID_IUnknown && SUCCEEDED(m_pUnkInner->QueryInterface(riid, ppv))) ? S_OK : - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// - -void CFGManager::CStreamPath::Append(IBaseFilter* pBF, IPin* pPin) -{ - path_t p; - p.clsid = GetCLSID(pBF); - p.filter = GetFilterName(pBF); - p.pin = GetPinName(pPin); - AddTail(p); -} - -bool CFGManager::CStreamPath::Compare(const CStreamPath& path) -{ - POSITION pos1 = GetHeadPosition(); - POSITION pos2 = path.GetHeadPosition(); - - while (pos1 && pos2) { - const path_t& p1 = GetNext(pos1); - const path_t& p2 = path.GetNext(pos2); - - if (p1.filter != p2.filter) { - return true; - } else if (p1.pin != p2.pin) { - return false; - } - } - - return true; -} - -// - -bool CFGManager::CheckBytes(HANDLE hFile, CString chkbytes) -{ - CAtlList sl; - Explode(chkbytes, sl, ','); - - if (sl.GetCount() < 4) { - return false; - } - - ASSERT(!(sl.GetCount() & 3)); - - LARGE_INTEGER size = {0, 0}; - GetFileSizeEx(hFile, &size); - - while (sl.GetCount() >= 4) { - CString offsetstr = sl.RemoveHead(); - CString cbstr = sl.RemoveHead(); - CString maskstr = sl.RemoveHead(); - CString valstr = sl.RemoveHead(); - - long cb = _ttol(cbstr); - - if (offsetstr.IsEmpty() || cbstr.IsEmpty() - || valstr.IsEmpty() || (valstr.GetLength() & 1) - || cb * 2 != valstr.GetLength()) { - return false; - } - - LARGE_INTEGER offset; - offset.QuadPart = _ttoi64(offsetstr); - if (offset.QuadPart < 0) { - offset.QuadPart = size.QuadPart - offset.QuadPart; - } - SetFilePointerEx(hFile, offset, &offset, FILE_BEGIN); - - // LAME - while (maskstr.GetLength() < valstr.GetLength()) { - maskstr += _T('F'); - } - - CAtlArray mask, val; - CStringToBin(maskstr, mask); - CStringToBin(valstr, val); - - for (size_t i = 0; i < val.GetCount(); i++) { - BYTE b; - DWORD r; - if (!ReadFile(hFile, &b, 1, &r, nullptr) || (b & mask[i]) != val[i]) { - return false; - } - } - } - - return sl.IsEmpty(); -} - -CFGFilter* LookupFilterRegistry(const GUID& guid, CAtlList& list, UINT64 fallback_merit = MERIT64_DO_USE) -{ - POSITION pos = list.GetHeadPosition(); - CFGFilter* pFilter = nullptr; - while (pos) { - CFGFilter* pFGF = list.GetNext(pos); - if (pFGF->GetCLSID() == guid) { - pFilter = pFGF; - break; - } - } - if (pFilter) { - return DEBUG_NEW CFGFilterRegistry(guid, pFilter->GetMerit()); - } else { - return DEBUG_NEW CFGFilterRegistry(guid, fallback_merit); - } -} - -HRESULT CFGManager::EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl) -{ - // TODO: use overrides - - CheckPointer(lpcwstrFileName, E_POINTER); - - fl.RemoveAll(); - - CStringW fn = CStringW(lpcwstrFileName).TrimLeft(); - CStringW cfn = fn; - if (cfn.Left(4) == "\\\\?\\") { - cfn = cfn.Mid(4); - } - CStringW protocol = cfn.Left(cfn.Find(':') + 1).TrimRight(':').MakeLower(); - CStringW ext = CPathW(fn).GetExtension().MakeLower(); - - HANDLE hFile = INVALID_HANDLE_VALUE; - - if (protocol.GetLength() <= 1 || protocol == L"file") { - hFile = CreateFile(CString(fn), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)nullptr); - - // In case of audio CDs with extra content, the audio tracks - // cannot be accessed directly so we have to try opening it - if (hFile == INVALID_HANDLE_VALUE && ext != L".cda") { - return VFW_E_NOT_FOUND; - } - } - - if (hFile == INVALID_HANDLE_VALUE) { - // internal / protocol - - POSITION pos = m_source.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_source.GetNext(pos); - if (pFGF->m_protocols.Find(CString(protocol))) { - fl.Insert(pFGF, 0, false, false); - } - } - } else { - // internal / check bytes - - POSITION pos = m_source.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_source.GetNext(pos); - - POSITION pos2 = pFGF->m_chkbytes.GetHeadPosition(); - while (pos2) { - if (CheckBytes(hFile, pFGF->m_chkbytes.GetNext(pos2))) { - fl.Insert(pFGF, 1, false, false); - break; - } - } - } - } - - if (!ext.IsEmpty()) { - // internal / file extension - - POSITION pos = m_source.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_source.GetNext(pos); - if (pFGF->m_extensions.Find(CString(ext))) { - fl.Insert(pFGF, 2, false, false); - } - } - } - - { - // internal / the rest - - POSITION pos = m_source.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_source.GetNext(pos); - if (pFGF->m_protocols.IsEmpty() && pFGF->m_chkbytes.IsEmpty() && pFGF->m_extensions.IsEmpty()) { - fl.Insert(pFGF, 3, false, false); - } - } - } - - TCHAR buff[256]; - ULONG len; - - if (hFile == INVALID_HANDLE_VALUE) { - // protocol - - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, CString(protocol), KEY_READ)) { - CRegKey exts; - if (ERROR_SUCCESS == exts.Open(key, _T("Extensions"), KEY_READ)) { - len = _countof(buff); - if (ERROR_SUCCESS == exts.QueryStringValue(CString(ext), buff, &len)) { - fl.Insert(LookupFilterRegistry(GUIDFromCString(buff), m_override), 4); - } - } - - len = _countof(buff); - if (ERROR_SUCCESS == key.QueryStringValue(_T("Source Filter"), buff, &len)) { - fl.Insert(LookupFilterRegistry(GUIDFromCString(buff), m_override), 5); - } - } - - fl.Insert(DEBUG_NEW CFGFilterRegistry(CLSID_URLReader), 6); - } else { - // check bytes - - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Media Type"), KEY_READ)) { - FILETIME ft; - len = _countof(buff); - for (DWORD i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len, &ft); i++, len = _countof(buff)) { - GUID majortype; - if (FAILED(GUIDFromCString(buff, majortype))) { - continue; - } - - CRegKey majorkey; - if (ERROR_SUCCESS == majorkey.Open(key, buff, KEY_READ)) { - len = _countof(buff); - for (DWORD j = 0; ERROR_SUCCESS == majorkey.EnumKey(j, buff, &len, &ft); j++, len = _countof(buff)) { - GUID subtype; - if (FAILED(GUIDFromCString(buff, subtype))) { - continue; - } - - CRegKey subkey; - if (ERROR_SUCCESS == subkey.Open(majorkey, buff, KEY_READ)) { - len = _countof(buff); - if (ERROR_SUCCESS != subkey.QueryStringValue(_T("Source Filter"), buff, &len)) { - continue; - } - - GUID clsid = GUIDFromCString(buff); - TCHAR buff2[256]; - ULONG len2; - - len = _countof(buff); - len2 = sizeof(buff2); - for (DWORD k = 0, type; - clsid != GUID_NULL && ERROR_SUCCESS == RegEnumValue(subkey, k, buff2, &len2, 0, &type, (BYTE*)buff, &len); - k++, len = _countof(buff), len2 = sizeof(buff2)) { - if (CheckBytes(hFile, CString(buff))) { - CFGFilter* pFGF = LookupFilterRegistry(clsid, m_override); - pFGF->AddType(majortype, subtype); - if (pFGF->GetMerit() >= MERIT64_ABOVE_DSHOW) { - fl.Insert(pFGF, 7); - } else { - fl.Insert(pFGF, 9); - } - break; - } - } - } - } - } - } - } - } - - if (!ext.IsEmpty()) { - // file extension - - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Media Type\\Extensions\\") + CString(ext), KEY_READ)) { - len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - LONG ret = key.QueryStringValue(_T("Source Filter"), buff, &len); // QueryStringValue can return ERROR_INVALID_DATA on bogus strings (radlight mpc v1003, fixed in v1004) - if (ERROR_SUCCESS == ret || ERROR_INVALID_DATA == ret && GUIDFromCString(buff) != GUID_NULL) { - GUID clsid = GUIDFromCString(buff); - GUID majortype = GUID_NULL; - GUID subtype = GUID_NULL; - - len = _countof(buff); - if (ERROR_SUCCESS == key.QueryStringValue(_T("Media Type"), buff, &len)) { - majortype = GUIDFromCString(buff); - } - - len = _countof(buff); - if (ERROR_SUCCESS == key.QueryStringValue(_T("Subtype"), buff, &len)) { - subtype = GUIDFromCString(buff); - } - - CFGFilter* pFGF = LookupFilterRegistry(clsid, m_override); - pFGF->AddType(majortype, subtype); - fl.Insert(pFGF, 7); - } - } - - // preferred external filters - if (ext == L".avs" || ext == L".vpy") { - POSITION pos = m_override.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_override.GetNext(pos); - if (pFGF->GetMerit() >= MERIT64_ABOVE_DSHOW) { - if (pFGF->GetCLSID() == GUIDFromCString(L"{7D3BBD5A-880D-4A30-A2D1-7B8C2741AFEF}")) { // MPC Script Source - if (ext == L".avs" || ext == L".vpy") { - fl.Insert(pFGF, 0, false, false); - } - } - } - } - } - } - - if (hFile != INVALID_HANDLE_VALUE) { - CloseHandle(hFile); - - CFGFilter* pFGF = LookupFilterRegistry(CLSID_AsyncReader, m_override); - pFGF->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_NULL); - fl.Insert(pFGF, 9); - } - - return S_OK; -} - -HRESULT CFGManager::AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF) -{ - CLSID clsid = pFGF->GetCLSID(); - TRACE(_T("FGM: AddSourceFilter trying '%s'\n"), CStringFromGUID(clsid).GetString()); - - CheckPointer(lpcwstrFileName, E_POINTER); - CheckPointer(ppBF, E_POINTER); - - ASSERT(*ppBF == nullptr); - - HRESULT hr; - - CComPtr pBF; - CInterfaceList pUnks; - if (FAILED(hr = pFGF->Create(&pBF, pUnks))) { - return hr; - } - - CComQIPtr pFSF = pBF; - if (!pFSF) { - return E_NOINTERFACE; - } - - if (clsid == __uuidof(CRARFileSource) && m_entryRFS.GetLength() > 0) { - CComPtr rfs = static_cast(pBF.p); - std::wstring preselectedRarFileEntry(m_entryRFS.GetBuffer()); - rfs->SetPreselectedRarFileEntry(preselectedRarFileEntry); - } - - if (FAILED(hr = AddFilter(pBF, lpcwstrFilterName))) { - return hr; - } - - const AM_MEDIA_TYPE* pmt = nullptr; - if (clsid == GUID_LAVSplitterSource) { - CComQIPtr pSFL = pBF; - if (pSFL && (!m_useragent.IsEmpty() || !m_referrer.IsEmpty())) { - // ToDo: set strings - hr = pSFL->LoadURL(lpcwstrFileName, m_useragent, m_referrer); - if (FAILED(hr)) { - RemoveFilter(pBF); - return hr; - } - } else { - hr = pFSF->Load(lpcwstrFileName, pmt); - if (FAILED(hr)) { - RemoveFilter(pBF); - return hr; - } - } - } else { - CMediaType mt; - const CAtlList& types = pFGF->GetTypes(); - if (types.GetCount() == 2 && (types.GetHead() != GUID_NULL || types.GetTail() != GUID_NULL)) { - mt.majortype = types.GetHead(); - mt.subtype = types.GetTail(); - pmt = &mt; - } - - hr = pFSF->Load(lpcwstrFileName, pmt); - if (FAILED(hr) || m_aborted) { // sometimes looping with AviSynth - RemoveFilter(pBF); - return m_aborted ? E_ABORT : hr; - } - - BeginEnumMediaTypes(GetFirstPin(pBF, PINDIR_OUTPUT), pEMT, pmt2) { - static const GUID guid1 = - { 0x640999A0, 0xA946, 0x11D0, { 0xA5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // ASX file Parser - static const GUID guid2 = - { 0x640999A1, 0xA946, 0x11D0, { 0xA5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // ASX v.2 file Parser - static const GUID guid3 = - { 0xD51BD5AE, 0x7548, 0x11CF, { 0xA5, 0x20, 0x00, 0x80, 0xC7, 0x7E, 0xF5, 0x8A } }; // XML Playlist - - if (pmt2->subtype == guid1 || pmt2->subtype == guid2 || pmt2->subtype == guid3) { - RemoveFilter(pBF); - pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_NetShowSource); - hr = AddSourceFilter(pFGF, lpcwstrFileName, lpcwstrFilterName, ppBF); - delete pFGF; - return hr; - } - } - EndEnumMediaTypes(pmt2); - } - - *ppBF = pBF.Detach(); - - m_pUnks.AddTailList(&pUnks); - - return S_OK; -} - -// IFilterGraph - -STDMETHODIMP CFGManager::AddFilter(IBaseFilter* pFilter, LPCWSTR pName) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (FAILED(hr = CComQIPtr(m_pUnkInner)->AddFilter(pFilter, pName))) { - return hr; - } - - // TODO - hr = pFilter->JoinFilterGraph(nullptr, nullptr); - hr = pFilter->JoinFilterGraph(this, pName); - - return hr; -} - -STDMETHODIMP CFGManager::RemoveFilter(IBaseFilter* pFilter) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->RemoveFilter(pFilter); -} - -STDMETHODIMP CFGManager::EnumFilters(IEnumFilters** ppEnum) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - // Not locking here fixes a deadlock involving ReClock - //CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->EnumFilters(ppEnum); -} - -STDMETHODIMP CFGManager::FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->FindFilterByName(pName, ppFilter); -} - -STDMETHODIMP CFGManager::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - CComPtr pBF = GetFilterFromPin(pPinIn); - CLSID clsid = GetCLSID(pBF); - - // TODO: GetUpStreamFilter goes up on the first input pin only - for (CComPtr pBFUS = GetFilterFromPin(pPinOut); pBFUS; pBFUS = GetUpStreamFilter(pBFUS)) { - if (pBFUS == pBF) { - return VFW_E_CIRCULAR_GRAPH; - } - if (clsid != CLSID_Proxy && GetCLSID(pBFUS) == clsid) { - return VFW_E_CANNOT_CONNECT; - } - } - - return CComQIPtr(m_pUnkInner)->ConnectDirect(pPinOut, pPinIn, pmt); -} - -STDMETHODIMP CFGManager::Reconnect(IPin* ppin) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->Reconnect(ppin); -} - -STDMETHODIMP CFGManager::Disconnect(IPin* ppin) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->Disconnect(ppin); -} - -STDMETHODIMP CFGManager::SetDefaultSyncSource() -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->SetDefaultSyncSource(); -} - -// IGraphBuilder - -STDMETHODIMP CFGManager::Connect(IPin* pPinOut, IPin* pPinIn) -{ - return Connect(pPinOut, pPinIn, true); -} - -HRESULT CFGManager::Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPinOut, E_POINTER); - - if (m_aborted) { - return E_ABORT; - } - - HRESULT hr; - - if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT) - || pPinIn && S_OK != IsPinDirection(pPinIn, PINDIR_INPUT)) { - return VFW_E_INVALID_DIRECTION; - } - - if (S_OK == IsPinConnected(pPinOut) - || pPinIn && S_OK == IsPinConnected(pPinIn)) { - return VFW_E_ALREADY_CONNECTED; - } - - bool fDeadEnd = true; - - if (pPinIn) { - // 1. Try a direct connection between the filters, with no intermediate filters - - if (SUCCEEDED(hr = ConnectDirect(pPinOut, pPinIn, nullptr))) { - return hr; - } - } else { - // 1. Use IStreamBuilder - - if (CComQIPtr pSB = pPinOut) { - if (SUCCEEDED(hr = pSB->Render(pPinOut, this))) { - return hr; - } - - pSB->Backout(pPinOut, this); - } - } - - // 2. Try cached filters - - CComPtr pFilterPinIn = nullptr; - if (pPinIn) { - pFilterPinIn = GetFilterFromPin(pPinIn); - } - - if (CComQIPtr pGC = (IGraphBuilder2*)this) { - BeginEnumCachedFilters(pGC, pEF, pBF) { - if (pFilterPinIn && pFilterPinIn == pBF) { - continue; - } - - hr = pGC->RemoveFilterFromCache(pBF); - - // does RemoveFilterFromCache call AddFilter like AddFilterToCache calls RemoveFilter ? - - if (SUCCEEDED(hr = ConnectFilterDirect(pPinOut, pBF, nullptr))) { - if (!IsStreamEnd(pBF)) { - fDeadEnd = false; - } - - if (SUCCEEDED(hr = ConnectFilter(pBF, pPinIn))) { - return hr; - } - } - - hr = pGC->AddFilterToCache(pBF); - } - EndEnumCachedFilters; - } - - // 3. Try filters in the graph - - CComPtr pFilterPinOut = GetFilterFromPin(pPinOut); - CLSID clsid_pinout = GetCLSID(pFilterPinOut); - - { - CInterfaceList pBFs; - - BeginEnumFilters(this, pEF, pBF) { - if (pFilterPinIn && pFilterPinIn == pBF || pFilterPinOut == pBF) { - continue; - } - - // HACK: ffdshow - audio capture filter - if (clsid_pinout == GUIDFromCString(_T("{04FE9017-F873-410E-871E-AB91661A4EF7}")) - && GetCLSID(pBF) == GUIDFromCString(_T("{E30629D2-27E5-11CE-875D-00608CB78066}"))) { - continue; - } - - pBFs.AddTail(pBF); - } - EndEnumFilters; - - POSITION pos = pBFs.GetHeadPosition(); - while (pos) { - IBaseFilter* pBF = pBFs.GetNext(pos); - - if (SUCCEEDED(hr = ConnectFilterDirect(pPinOut, pBF, nullptr))) { - if (!IsStreamEnd(pBF)) { - fDeadEnd = false; - } - - if (SUCCEEDED(hr = ConnectFilter(pBF, pPinIn))) { - return hr; - } - } - - EXECUTE_ASSERT(SUCCEEDED(Disconnect(pPinOut))); - } - } - - // 4. Look up filters in the registry - - { - // workaround for Cyberlink video decoder, which can have an unwanted output pin - if (clsid_pinout == GUIDFromCString(_T("{F8FC6C1F-DE81-41A8-90FF-0316FDD439FD}"))) { - CPinInfo infoPinOut; - if (SUCCEEDED(pPinOut->QueryPinInfo(&infoPinOut))) { - if (CString(infoPinOut.achName) == L"~Encode Out") { - // ignore this pin - return S_OK; - } - } - } - - CFGFilterList fl; - - CAtlArray types; - ExtractMediaTypes(pPinOut, types); - - POSITION pos = m_transform.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_transform.GetNext(pos); - if (pFGF->GetMerit() < MERIT64_DO_USE || pFGF->CheckTypes(types, false)) { - fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true), false); - } - } - - pos = m_override.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_override.GetNext(pos); - if (pFGF->GetMerit() < MERIT64_DO_USE || pFGF->CheckTypes(types, false)) { - fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true), false); - } - } - - CComPtr pEM; - if (!types.IsEmpty() - && SUCCEEDED(m_pFM->EnumMatchingFilters( - &pEM, 0, FALSE, MERIT_DO_NOT_USE + 1, - TRUE, (DWORD)types.GetCount() / 2, types.GetData(), nullptr, nullptr, FALSE, - !!pPinIn, 0, nullptr, nullptr, nullptr))) { - for (CComPtr pMoniker; S_OK == pEM->Next(1, &pMoniker, nullptr); pMoniker = nullptr) { - CFGFilterRegistry* pFGF = DEBUG_NEW CFGFilterRegistry(pMoniker); - fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true)); - } - } - - // let's check whether the madVR allocator presenter is in our list - // it should be if madVR is selected as the video renderer - CFGFilter* pMadVRAllocatorPresenter = nullptr; - pos = fl.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = fl.GetNext(pos); - if (pFGF->GetCLSID() == CLSID_madVRAllocatorPresenter) { - // found it! - pMadVRAllocatorPresenter = pFGF; - break; - } - } - - pos = fl.GetHeadPosition(); - while (pos) { - if (m_aborted) { - return E_ABORT; - } - - CFGFilter* pFGF = fl.GetNext(pos); - - // avoid pointless connection attempts - CLSID candidate = pFGF->GetCLSID(); - if (clsid_pinout == candidate) { - continue; - } else if (candidate == CLSID_VSFilter) { - if (clsid_pinout == GUID_LAVAudio || clsid_pinout == __uuidof(CAudioSwitcherFilter)) { - continue; - } - } else if (candidate == CLSID_RDPDShowRedirectionFilter) { - if (clsid_pinout == __uuidof(CAudioSwitcherFilter)) { - continue; - } - } else if (candidate == GUID_LAVAudio) { - if (clsid_pinout == __uuidof(CAudioSwitcherFilter)) { - continue; - } - } - -#if 0 - // Checks if madVR is already in the graph to avoid two instances at the same time - CComPtr pBFmadVR; - FindFilterByName(_T("madVR"), &pBFmadVR); - if (pBFmadVR && (pFGF->GetName() == _T("madVR"))) { - continue; - } -#endif - - if (pMadVRAllocatorPresenter && (pFGF->GetCLSID() == CLSID_madVR)) { - // the pure madVR filter was selected (without the allocator presenter) - // subtitles, OSD etc don't work correctly without the allocator presenter - // so we prefer the allocator presenter over the pure filter - pFGF = pMadVRAllocatorPresenter; - } - - CString filtername = pFGF->GetName().GetString(); - if (filtername.IsEmpty()) { - filtername = CLSIDToString(candidate); - } - TRACE(_T("FGM: Connecting '%s'\n"), filtername); - - CComPtr pBF; - CInterfaceList pUnks; - if (FAILED(pFGF->Create(&pBF, pUnks))) { - TRACE(_T("FGM: Filter creation failed\n")); - if (!m_bIsCapture) { - // Check if selected video renderer fails to load - CLSID filter = pFGF->GetCLSID(); - if (filter == CLSID_MPCVRAllocatorPresenter || filter == CLSID_madVRAllocatorPresenter || filter == CLSID_DXRAllocatorPresenter) { - if (IDYES == AfxMessageBox(_T("The selected video renderer has failed to load.\n\nThe player will now fallback to using a basic video renderer, which has reduced performance and quality. Subtitles may also fail to load.\n\nDo you want to change settings to use the default video renderer (EVR-CP/VMR9)? (player restart required)"), MB_ICONEXCLAMATION | MB_YESNO, 0)) { - CAppSettings& s = AfxGetAppSettings(); - s.iDSVideoRendererType = IsCLSIDRegistered(CLSID_EnhancedVideoRenderer) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS; - } - } else if (filter == CLSID_EVRAllocatorPresenter || filter == CLSID_VMR9AllocatorPresenter) { - if (IDYES == AfxMessageBox(_T("The selected video renderer has failed to load.\n\nThis problem is often caused by a bug in the graphics driver. Or you may be using a generic driver which has limited capabilities. It is recommended to update the graphics driver to solve this problem. A proper driver is required for optimal video playback performance and quality.\n\nThe player will now fallback to using a basic video renderer, which has reduced performance and quality. Subtitles may also fail to load.\n\nYou can select a different renderer here:\nOptions > playback > Output\n\nDo you want to use the basic video renderer by default?"), MB_ICONEXCLAMATION | MB_YESNO, 0)) { - CAppSettings& s = AfxGetAppSettings(); - s.iDSVideoRendererType = IsCLSIDRegistered(CLSID_EnhancedVideoRenderer) ? VIDRNDT_DS_EVR : VIDRNDT_DS_VMR9WINDOWED; - s.SetSubtitleRenderer(CAppSettings::SubtitleRenderer::VS_FILTER); - // Disable DXVA in internal video decoder - CMPlayerCApp* pApp = AfxGetMyApp(); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), 0); - } - } - } - continue; - } - - if (FAILED(hr = AddFilter(pBF, pFGF->GetName()))) { - TRACE(_T("FGM: Adding the filter failed\n")); - pUnks.RemoveAll(); - pBF.Release(); - continue; - } - - hr = ConnectFilterDirect(pPinOut, pBF, nullptr); - /* - if (FAILED(hr)) - { - if (types.GetCount() >= 2 && types[0] == MEDIATYPE_Stream && types[1] != GUID_NULL) - { - CMediaType mt; - - mt.majortype = types[0]; - mt.subtype = types[1]; - mt.formattype = FORMAT_None; - if (FAILED(hr)) hr = ConnectFilterDirect(pPinOut, pBF, &mt); - - mt.formattype = GUID_NULL; - if (FAILED(hr)) hr = ConnectFilterDirect(pPinOut, pBF, &mt); - } - } - */ - if (SUCCEEDED(hr)) { - TRACE(_T("FGM: Filter connected to %s\n"), CLSIDToString(clsid_pinout)); - if (!IsStreamEnd(pBF)) { - fDeadEnd = false; - } - - if (m_aborted) { - return E_ABORT; - } - - if (bContinueRender) { - hr = ConnectFilter(pBF, pPinIn); - } - - if (SUCCEEDED(hr)) { - m_pUnks.AddTailList(&pUnks); - - // maybe the application should do this... - - POSITION posInterface = pUnks.GetHeadPosition(); - while (posInterface) { - if (CComQIPtr pMPC = pUnks.GetNext(posInterface)) { - pMPC->SetAspectRatioMode(AM_ARMODE_STRETCHED); - } - } - - if (CComQIPtr pARC = pBF) { - pARC->SetAspectRatioMode(VMR_ARMODE_NONE); - } - - if (CComQIPtr pARC = pBF) { - pARC->SetAspectRatioMode(VMR_ARMODE_NONE); - } - - if (CComQIPtr pMC = pBF) { - m_pUnks.AddTail(pMC); - } - - if (CComQIPtr pMB = pBF) { - m_pUnks.AddTail(pMB); - } - - if (CComQIPtr pMFVMB = pBF) { - m_pUnks.AddTail(pMFVMB); - } - - if (CComQIPtr pMFGS = pBF) { - CComPtr pMFVDC; - CComPtr pMFMB; - CComPtr pMFVP; - - if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVDC)))) { - m_pUnks.AddTail(pMFVDC); - } - - if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&pMFMB)))) { - m_pUnks.AddTail(pMFMB); - } - - if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&pMFVP)))) { - m_pUnks.AddTail(pMFVP); - } - } - - return hr; - } - } - - TRACE(_T("FGM: Failed to connect to %s\n"), CLSIDToString(clsid_pinout)); - CPinInfo infoPinOut; - if (SUCCEEDED(pPinOut->QueryPinInfo(&infoPinOut))) { - TRACE(_T("FGM: Output pin name: %s\n"), infoPinOut.achName); - } - EXECUTE_ASSERT(SUCCEEDED(RemoveFilter(pBF))); - pUnks.RemoveAll(); - pBF.Release(); - } - } - - if (fDeadEnd) { - CAutoPtr psde(DEBUG_NEW CStreamDeadEnd()); - psde->AddTailList(&m_streampath); - int skip = 0; - BeginEnumMediaTypes(pPinOut, pEM, pmt) { - if (pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_NULL) { - skip++; - } - psde->mts.AddTail(CMediaType(*pmt)); - } - EndEnumMediaTypes(pmt); - if (skip < (int)psde->mts.GetCount()) { - m_deadends.Add(psde); - } - } - - return pPinIn ? VFW_E_CANNOT_CONNECT : VFW_E_CANNOT_RENDER; -} - -STDMETHODIMP CFGManager::Render(IPin* pPinOut) -{ - CAutoLock cAutoLock(this); - - return RenderEx(pPinOut, 0, nullptr); -} - -HRESULT CFGManager::RenderRFSFileEntry(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList, CStringW entryRFS){ - this->m_entryRFS = entryRFS; - return RenderFile(lpcwstrFileName, lpcwstrPlayList); -} - -CUnknown* WINAPI CFGManager::GetMpcAudioRendererInstance(LPUNKNOWN lpunk, HRESULT* phr) { - return CreateInstance(lpunk, phr); -} - -STDMETHODIMP CFGManager::RenderFile(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList) -{ - TRACE(_T("CFGManager::RenderFile on thread: %lu\n"), GetCurrentThreadId()); - CAutoLock cAutoLock(this); - - m_streampath.RemoveAll(); - m_deadends.RemoveAll(); - - HRESULT hr; - HRESULT hrRFS = S_OK; - - CFGFilterList fl; - if (FAILED(hr = EnumSourceFilters(lpcwstrFileName, fl))) { - return hr; - } - - CAutoPtrArray deadends; - - hr = VFW_E_CANNOT_RENDER; - - POSITION pos = fl.GetHeadPosition(); - while (pos) { - CComPtr pBF; - CFGFilter* pFG = fl.GetNext(pos); - - if (SUCCEEDED(hr = AddSourceFilter(pFG, lpcwstrFileName, pFG->GetName(), &pBF))) { - m_streampath.RemoveAll(); - m_deadends.RemoveAll(); - - if (m_ignoreVideo) { - CFGFilter* pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_COMP), MERIT64_ABOVE_DSHOW + 3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } - - if (SUCCEEDED(hr = ConnectFilter(pBF, nullptr))) { - // insert null video renderer on next RenderFile call which is used for audio dubs - m_ignoreVideo = True; - TRACE(_T("CFGManager::RenderFile complete\n")); - return hr; - } - - NukeDownstream(pBF); - RemoveFilter(pBF); - - deadends.Append(m_deadends); - - if (hr == E_ABORT) { - break; - } - } else if (pFG->GetCLSID() == __uuidof(CRARFileSource) && HRESULT_FACILITY(hr) == FACILITY_ITF) { - hrRFS = hr; - } - } - - m_deadends.Copy(deadends); - - // If RFS was part of the graph, return its error code instead of the last error code. - // TODO: Improve filter error reporting to graph manager. - return hrRFS != S_OK ? hrRFS : hr; -} - -STDMETHODIMP CFGManager::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - CFGFilterList fl; - - if (FAILED(hr = EnumSourceFilters(lpcwstrFileName, fl))) { - return hr; - } - - POSITION pos = fl.GetHeadPosition(); - while (pos) { - if (SUCCEEDED(hr = AddSourceFilter(fl.GetNext(pos), lpcwstrFileName, lpcwstrFilterName, ppFilter))) { - return hr; - } - } - - return VFW_E_CANNOT_LOAD_SOURCE_FILTER; -} - -STDMETHODIMP CFGManager::SetLogFile(DWORD_PTR hFile) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->SetLogFile(hFile); -} - -STDMETHODIMP CFGManager::Abort() -{ - if (!m_pUnkInner) { - ASSERT(false); - return E_UNEXPECTED; - } - - // When a filter (renderer) in the child thread (the graph thread) calls CreateWindow() - // then that call triggers an implicit call of SendMessage to the main window. - // This is a blocking call, meaning main thread must be able to process that window message. - // So we can not request a lock here when called from main thread since that would result in a deadlock. - //CAutoLock cAutoLock(this); - - m_aborted = true; - - return CComQIPtr(m_pUnkInner)->Abort(); -} - -STDMETHODIMP CFGManager::ShouldOperationContinue() -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->ShouldOperationContinue(); -} - -// IFilterGraph2 - -STDMETHODIMP CFGManager::AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->AddSourceFilterForMoniker(pMoniker, pCtx, lpcwstrFilterName, ppFilter); -} - -STDMETHODIMP CFGManager::ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->ReconnectEx(ppin, pmt); -} - -STDMETHODIMP CFGManager::RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext) -{ - CAutoLock cAutoLock(this); - - m_streampath.RemoveAll(); - m_deadends.RemoveAll(); - - if (!pPinOut || dwFlags > AM_RENDEREX_RENDERTOEXISTINGRENDERERS || pvContext) { - return E_INVALIDARG; - } - - if (dwFlags & AM_RENDEREX_RENDERTOEXISTINGRENDERERS) { - CInterfaceList pBFs; - - BeginEnumFilters(this, pEF, pBF) { - if (CComQIPtr pAMMF = pBF) { - if (pAMMF->GetMiscFlags() & AM_FILTER_MISC_FLAGS_IS_RENDERER) { - pBFs.AddTail(pBF); - } - } else { - BeginEnumPins(pBF, pEP, pPin) { - CComPtr pPinIn; - DWORD size = 1; - if (SUCCEEDED(pPin->QueryInternalConnections(&pPinIn, &size)) && size == 0) { - pBFs.AddTail(pBF); - break; - } - } - EndEnumPins; - } - } - EndEnumFilters; - - while (!pBFs.IsEmpty()) { - HRESULT hr; - if (SUCCEEDED(hr = ConnectFilter(pPinOut, pBFs.RemoveHead()))) { - return hr; - } - } - - return VFW_E_CANNOT_RENDER; - } - - return Connect(pPinOut, (IPin*)nullptr); -} - -// IGraphBuilder2 - -STDMETHODIMP CFGManager::IsPinDirection(IPin* pPin, PIN_DIRECTION dir1) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPin, E_POINTER); - - PIN_DIRECTION dir2; - if (FAILED(pPin->QueryDirection(&dir2))) { - return E_FAIL; - } - - return dir1 == dir2 ? S_OK : S_FALSE; -} - -STDMETHODIMP CFGManager::IsPinConnected(IPin* pPin) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPin, E_POINTER); - - CComPtr pPinTo; - return SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo ? S_OK : S_FALSE; -} - -STDMETHODIMP CFGManager::ConnectFilter(IBaseFilter* pBF, IPin* pPinIn) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pBF, E_POINTER); - - if (m_aborted) { - return E_ABORT; - } - - if (pPinIn && S_OK != IsPinDirection(pPinIn, PINDIR_INPUT)) { - return VFW_E_INVALID_DIRECTION; - } - - int nTotal = 0, nRendered = 0; - - const CAppSettings& s = AfxGetAppSettings(); - - BeginEnumPins(pBF, pEP, pPin) { - if (S_OK == IsPinDirection(pPin, PINDIR_OUTPUT) - && S_OK != IsPinConnected(pPin) - && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { - - CLSID clsid; - pBF->GetClassID(&clsid); - // Disable DVD subtitle mixing in EVR (CP) and Sync Renderer for Microsoft DTV-DVD Video Decoder, it corrupts DVD playback. - if (clsid == CLSID_CMPEG2VidDecoderDS) { - if (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { - if (GetPinName(pPin)[0] == '~') { - continue; - } - } - } - // No multiple pin for Internal MPEG2 Software Decoder, NVIDIA PureVideo Decoder, Sonic Cinemaster VideoDecoder - else if (clsid == CLSID_CMpeg2DecFilter - || clsid == CLSID_NvidiaVideoDecoder - || clsid == CLSID_SonicCinemasterVideoDecoder) { - if (GetPinName(pPin)[0] == '~') { - continue; - } - //TODO: enable multiple pins for the renderer, if the video decoder supports DXVA - } - - m_streampath.Append(pBF, pPin); - - HRESULT hr = Connect(pPin, pPinIn); - - if (SUCCEEDED(hr)) { - for (int i = (int)m_deadends.GetCount() - 1; i >= 0; i--) { - if (m_deadends.GetAt(i)->Compare(m_streampath)) { - m_deadends.RemoveAt(i); - } - } - nRendered++; - } - - nTotal++; - - m_streampath.RemoveTail(); - - if (SUCCEEDED(hr) && pPinIn) { - return S_OK; - } - } - } - EndEnumPins; - - return - nRendered == nTotal ? (nRendered > 0 ? S_OK : S_FALSE) : - nRendered > 0 ? VFW_S_PARTIAL_RENDER : - VFW_E_CANNOT_RENDER; -} - -STDMETHODIMP CFGManager::ConnectFilter(IPin* pPinOut, IBaseFilter* pBF) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPinOut, E_POINTER); - CheckPointer(pBF, E_POINTER); - - if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT)) { - return VFW_E_INVALID_DIRECTION; - } - - const CAppSettings& s = AfxGetAppSettings(); - - BeginEnumPins(pBF, pEP, pPin) { - if (S_OK == IsPinDirection(pPin, PINDIR_INPUT) - && S_OK != IsPinConnected(pPin) - && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { - HRESULT hr = Connect(pPinOut, pPin); - if (SUCCEEDED(hr)) { - return hr; - } - } - } - EndEnumPins; - - return VFW_E_CANNOT_CONNECT; -} - -STDMETHODIMP CFGManager::ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPinOut, E_POINTER); - CheckPointer(pBF, E_POINTER); - - if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT)) { - return VFW_E_INVALID_DIRECTION; - } - - const CAppSettings& s = AfxGetAppSettings(); - - BeginEnumPins(pBF, pEP, pPin) { - if (S_OK == IsPinDirection(pPin, PINDIR_INPUT) - && S_OK != IsPinConnected(pPin) - && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { - HRESULT hr = ConnectDirect(pPinOut, pPin, pmt); - if (SUCCEEDED(hr)) { - return hr; - } - } - } - EndEnumPins; - - return VFW_E_CANNOT_CONNECT; -} - -STDMETHODIMP CFGManager::NukeDownstream(IUnknown* pUnk) -{ - CAutoLock cAutoLock(this); - - if (CComQIPtr pBF = pUnk) { - BeginEnumPins(pBF, pEP, pPin) { - NukeDownstream(pPin); - } - EndEnumPins; - } else if (CComQIPtr pPin = pUnk) { - CComPtr pPinTo; - if (S_OK == IsPinDirection(pPin, PINDIR_OUTPUT) - && SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { - if (pBF = GetFilterFromPin(pPinTo)) { - if (GetCLSID(pBF) == CLSID_EnhancedVideoRenderer) { - // GetFilterFromPin() returns pointer to the Base EVR, - // but we need to remove Outer EVR from the graph. - CComPtr pOuterEVR; - if (SUCCEEDED(pBF->QueryInterface(&pOuterEVR))) { - pBF = pOuterEVR; - } - } - NukeDownstream(pBF); - Disconnect(pPinTo); - Disconnect(pPin); - RemoveFilter(pBF); - } - } - } else { - return E_INVALIDARG; - } - - return S_OK; -} - -STDMETHODIMP CFGManager::FindInterface(REFIID iid, void** ppv, BOOL bRemove) -{ - CAutoLock cAutoLock(this); - - CheckPointer(ppv, E_POINTER); - - for (POSITION pos = m_pUnks.GetHeadPosition(); pos; m_pUnks.GetNext(pos)) { - if (SUCCEEDED(m_pUnks.GetAt(pos)->QueryInterface(iid, ppv))) { - if (bRemove) { - m_pUnks.RemoveAt(pos); - } - return S_OK; - } - } - - return E_NOINTERFACE; -} - -STDMETHODIMP CFGManager::AddToROT() -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (m_dwRegister) { - return S_FALSE; - } - - CComPtr pROT; - CComPtr pMoniker; - WCHAR wsz[256]; - swprintf_s(wsz, _countof(wsz), L"FilterGraph %08p pid %08x (MPC-HC)", this, GetCurrentProcessId()); - if (SUCCEEDED(hr = GetRunningObjectTable(0, &pROT)) - && SUCCEEDED(hr = CreateItemMoniker(L"!", wsz, &pMoniker))) { - hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, (IGraphBuilder2*)this, pMoniker, &m_dwRegister); - } - - return hr; -} - -STDMETHODIMP CFGManager::RemoveFromROT() -{ - if (!m_dwRegister) { - return S_FALSE; - } - - //CAutoLock cAutoLock(this); - - HRESULT hr; - CComPtr pROT; - if (SUCCEEDED(hr = GetRunningObjectTable(0, &pROT)) - && SUCCEEDED(hr = pROT->Revoke(m_dwRegister))) { - m_dwRegister = 0; - } - - return hr; -} - -// IGraphBuilderDeadEnd - -STDMETHODIMP_(size_t) CFGManager::GetCount() -{ - CAutoLock cAutoLock(this); - - return m_deadends.GetCount(); -} - -STDMETHODIMP CFGManager::GetDeadEnd(int iIndex, CAtlList& path, CAtlList& mts) -{ - CAutoLock cAutoLock(this); - - if (iIndex < 0 || iIndex >= (int)m_deadends.GetCount()) { - return E_FAIL; - } - - path.RemoveAll(); - mts.RemoveAll(); - - POSITION pos = m_deadends[iIndex]->GetHeadPosition(); - while (pos) { - const path_t& p = m_deadends[iIndex]->GetNext(pos); - - CStringW str; - str.Format(L"%s::%s", p.filter.GetString(), p.pin.GetString()); - path.AddTail(str); - } - - mts.AddTailList(&m_deadends[iIndex]->mts); - - return S_OK; -} - -// -// Custom Filter Injection -// - -void CFGManagerCustom::InsertLAVSplitterSource(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* src = s.SrcFilters; - - CFGFilterLAV* filter; - if (IsPreview) { - filter = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER_SOURCE); - } else { - filter = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER_SOURCE); - } - CAutoPtr pFGLAVSplitterSource(static_cast (filter)); - -#if INTERNAL_SOURCEFILTER_AVI - if (src[SRC_AVI] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,41564920")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,41564958")); - pFGLAVSplitterSource->AddEnabledFormat("avi"); - } -#endif - -#if INTERNAL_SOURCEFILTER_AVS - if (src[SRC_AVS] || IsPreview) { - pFGLAVSplitterSource->m_extensions.AddTail(_T(".avs")); - pFGLAVSplitterSource->AddEnabledFormat("avisynth"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MP4 - if (src[SRC_MP4] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,66747970")); // ftyp - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,6d6f6f76")); // moov - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,6d646174")); // mdat - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,736b6970")); // skip - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,12,ffffffff00000000ffffffff,77696465027fe3706d646174")); // wide ? mdat - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("3,3,,000001")); // raw mpeg4 video - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mov")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mp4")); - pFGLAVSplitterSource->AddEnabledFormat("mp4"); - } -#endif - -#if INTERNAL_SOURCEFILTER_FLV - if (src[SRC_FLV] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,464C5601")); // FLV (v1) - pFGLAVSplitterSource->AddEnabledFormat("flv"); - } -#endif - -#if INTERNAL_SOURCEFILTER_GIF - if (src[SRC_GIF] && !IsPreview) { - pFGLAVSplitterSource->m_extensions.AddTail(_T(".gif")); - pFGLAVSplitterSource->AddEnabledFormat("gif"); - } -#endif - -#if INTERNAL_SOURCEFILTER_ASF - if (src[SRC_ASF] || IsPreview) { - pFGLAVSplitterSource->m_extensions.AddTail(_T(".wmv")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".asf")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dvr-ms")); - pFGLAVSplitterSource->AddEnabledFormat("asf"); - } -#endif - -#if INTERNAL_SOURCEFILTER_WTV - if (src[SRC_WTV] || IsPreview) { - pFGLAVSplitterSource->m_extensions.AddTail(_T(".wtv")); - pFGLAVSplitterSource->AddEnabledFormat("wtv"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MATROSKA - if (src[SRC_MATROSKA] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,1A45DFA3")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mkv")); - pFGLAVSplitterSource->AddEnabledFormat("matroska"); - } -#endif - -#if INTERNAL_SOURCEFILTER_REALMEDIA - if (src[SRC_REALMEDIA] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,2E524D46")); - pFGLAVSplitterSource->AddEnabledFormat("rm"); - } -#endif - -#if INTERNAL_SOURCEFILTER_FLIC - if (src[SRC_FLIC] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,2,,11AF")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,2,,12AF")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".fli")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".flc")); - pFGLAVSplitterSource->AddEnabledFormat("flic"); - } -#endif - -#if INTERNAL_SOURCEFILTER_FLAC - if (src[SRC_FLAC] && !IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,664C6143")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".flac")); - pFGLAVSplitterSource->AddEnabledFormat("flac"); - } -#endif - -#if INTERNAL_SOURCEFILTER_OGG - if (src[SRC_OGG] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4F676753")); - pFGLAVSplitterSource->AddEnabledFormat("ogg"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MPEG - if (src[SRC_MPEG] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,16,FFFFFFFFF100010001800001FFFFFFFF,000001BA2100010001800001000001BB")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,5,FFFFFFFFC0,000001BA40")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,54467263,1660,1,,47")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,8,fffffc00ffe00000,4156000055000000")); - pFGLAVSplitterSource->AddEnabledFormat("mpeg"); - pFGLAVSplitterSource->AddEnabledFormat("mpegraw"); - } - if (src[SRC_MPEGTS] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,1,,47,188,1,,47,376,1,,47")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,1,,47,196,1,,47,388,1,,47")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".ts")); // for some broken .ts - pFGLAVSplitterSource->AddEnabledFormat("mpegts"); - } - if (src[SRC_MPEG] || src[SRC_MPEGTS] || IsPreview) { - // for Blu-ray playback - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,494E4458")); // INDX (index.bdmv) - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4D4F424A")); // MOBJ (MovieObject.bdmv) - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4D504C53")); // MPLS - } -#endif - -#if INTERNAL_SOURCEFILTER_AC3 - if (src[SRC_AC3] && !IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,2,,0B77")); // AC3, E-AC3 - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,F8726FBB")); // MLP - pFGLAVSplitterSource->m_extensions.AddTail(_T(".ac3")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".eac3")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mlp")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".truehd")); - pFGLAVSplitterSource->AddEnabledFormat("ac3"); - pFGLAVSplitterSource->AddEnabledFormat("eac3"); - pFGLAVSplitterSource->AddEnabledFormat("mlp"); - pFGLAVSplitterSource->AddEnabledFormat("truehd"); - } -#endif - -#if INTERNAL_SOURCEFILTER_DTS - if (src[SRC_DTS] && !IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,7FFE8001")); // DTS - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,fE7f0180")); // DTS LE - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,8,,57415645666D7420"));// RIFFxxxxWAVEfmt_ for DTSWAV - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dts")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dtshd")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dtsma")); - pFGLAVSplitterSource->AddEnabledFormat("dts"); - pFGLAVSplitterSource->AddEnabledFormat("dtshd"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MPEGAUDIO - if (src[SRC_MPA] && !IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,2,FFE0,FFE0")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,10,FFFFFF00000080808080,49443300000000000000")); - pFGLAVSplitterSource->AddEnabledFormat("mp3"); - } -#endif - -#if INTERNAL_SOURCEFILTER_HTTP - if (src[SRC_HTTP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("http")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("https")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("icyx")); - pFGLAVSplitterSource->AddEnabledFormat("http"); - pFGLAVSplitterSource->AddEnabledFormat("dash"); - pFGLAVSplitterSource->AddEnabledFormat("hls"); - } -#endif - -#if INTERNAL_SOURCEFILTER_RTSP - if (src[SRC_RTSP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtsp")); - // Add transport protocol specific RTSP URL handlers - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspu")); // UDP - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspm")); // UDP multicast - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspt")); // TCP - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtsph")); // HTTP - pFGLAVSplitterSource->AddEnabledFormat("rtsp"); - } -#endif - -#if INTERNAL_SOURCEFILTER_UDP - if (src[SRC_UDP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("udp")); - pFGLAVSplitterSource->AddEnabledFormat("udp"); - } -#endif - -#if INTERNAL_SOURCEFILTER_RTP - if (src[SRC_RTP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtp")); - pFGLAVSplitterSource->AddEnabledFormat("rtp"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MMS - if (src[SRC_MMS] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("mms")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("mmsh")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("mmst")); - pFGLAVSplitterSource->AddEnabledFormat("mms"); - } -#endif - -#if INTERNAL_SOURCEFILTER_RTMP - if (src[SRC_RTMP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtmp")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtmpt")); - pFGLAVSplitterSource->AddEnabledFormat("live_flv"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MISC - // ToDo: split into separate options - if (src[SRC_MISC] || IsPreview) { - // video - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dv")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dhav")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".m3u8")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".y4m")); - pFGLAVSplitterSource->AddEnabledFormat("dv"); - pFGLAVSplitterSource->AddEnabledFormat("dhav"); - pFGLAVSplitterSource->AddEnabledFormat("y4m"); - } - if (src[SRC_MISC] && !IsPreview) { - // raw video - pFGLAVSplitterSource->m_extensions.AddTail(_T(".264")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".265")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".h264")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".h265")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".av1")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".m4v")); - pFGLAVSplitterSource->AddEnabledFormat("av1"); - pFGLAVSplitterSource->AddEnabledFormat("m4v"); - pFGLAVSplitterSource->AddEnabledFormat("rawvideo"); - // audio - pFGLAVSplitterSource->m_extensions.AddTail(_T(".amr")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".ape")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mpc")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".w64")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".wav")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".wv")); - pFGLAVSplitterSource->AddEnabledFormat("amr"); - pFGLAVSplitterSource->AddEnabledFormat("ape"); - pFGLAVSplitterSource->AddEnabledFormat("mpc"); - pFGLAVSplitterSource->AddEnabledFormat("mpc8"); - pFGLAVSplitterSource->AddEnabledFormat("w64"); - pFGLAVSplitterSource->AddEnabledFormat("wav"); - pFGLAVSplitterSource->AddEnabledFormat("wv"); - } -#endif - - // Always register the pipe protocol to allow handling standard input - pFGLAVSplitterSource->m_protocols.AddTail(_T("pipe")); - - // Add LAV Source Filter if needed - if (!pFGLAVSplitterSource->m_extensions.IsEmpty() - || !pFGLAVSplitterSource->m_chkbytes.IsEmpty() - || !pFGLAVSplitterSource->m_protocols.IsEmpty()) { - m_source.AddTail(pFGLAVSplitterSource.Detach()); - } -} - -void CFGManagerCustom::InsertLAVSplitter(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* src = s.SrcFilters; - - CFGFilterLAV* filterHM, * filterLM; - if (IsPreview) { - filterHM = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER, MERIT64_ABOVE_DSHOW); - filterLM = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER, MERIT64_DO_USE, true); - } else { - filterHM = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER, MERIT64_ABOVE_DSHOW); - filterLM = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER, MERIT64_DO_USE, true); - } - CAutoPtr pFGLAVSplitter(static_cast(filterHM)); - CAutoPtr pFGLAVSplitterLM(static_cast(filterLM)); - -#if INTERNAL_SOURCEFILTER_MATROSKA - if (src[SRC_MATROSKA] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Matroska); - pFGLAVSplitter->AddEnabledFormat("matroska"); - } -#endif - -#if INTERNAL_SOURCEFILTER_REALMEDIA - if (src[SRC_REALMEDIA] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_RealMedia); - pFGLAVSplitter->AddEnabledFormat("rm"); - } -#endif - -#if INTERNAL_SOURCEFILTER_AVI - if (src[SRC_AVI] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Avi); - pFGLAVSplitter->AddEnabledFormat("avi"); - } -#endif - -#if INTERNAL_SOURCEFILTER_AVS - if (src[SRC_AVS] || IsPreview) { - pFGLAVSplitter->AddEnabledFormat("avisynth"); - } -#endif - -#if INTERNAL_SOURCEFILTER_OGG - if (src[SRC_OGG] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Ogg); - pFGLAVSplitter->AddEnabledFormat("ogg"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MPEG - if (src[SRC_MPEG] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1System); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PROGRAM); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PVA); - pFGLAVSplitter->AddEnabledFormat("mpeg"); - pFGLAVSplitter->AddEnabledFormat("mpegraw"); - } - if (src[SRC_MPEGTS] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_TRANSPORT); - pFGLAVSplitter->AddEnabledFormat("mpegts"); - } -#endif - -#if INTERNAL_SOURCEFILTER_AC3 - if (src[SRC_AC3] && !IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_AC3); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_TRUEHD); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_DDPLUS); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MLP); - pFGLAVSplitter->AddEnabledFormat("ac3"); - pFGLAVSplitter->AddEnabledFormat("eac3"); - } -#endif - -#if INTERNAL_SOURCEFILTER_DTS - if (src[SRC_DTS] && !IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DTS); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DTS_HD); - pFGLAVSplitter->AddEnabledFormat("dts"); - pFGLAVSplitter->AddEnabledFormat("dtshd"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MPEGAUDIO - if (src[SRC_MPA] && !IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio); - pFGLAVSplitter->AddEnabledFormat("mp3"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MP4 - if (src[SRC_MP4] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MP4); - pFGLAVSplitter->AddEnabledFormat("mp4"); - } -#endif - -#if INTERNAL_SOURCEFILTER_FLV - if (src[SRC_FLV] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_FLV); - pFGLAVSplitter->AddEnabledFormat("flv"); - } -#endif - -#if INTERNAL_SOURCEFILTER_ASF - if (src[SRC_ASF] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_ASF); - pFGLAVSplitter->AddEnabledFormat("asf"); - } -#endif - - // Add LAV Splitter if needed - if (!pFGLAVSplitter->GetTypes().IsEmpty()) { - m_transform.AddTail(pFGLAVSplitter.Detach()); - } - - if (!IsPreview && pFGLAVSplitterLM) { - // Add low merit LAV Splitter - pFGLAVSplitterLM->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_NULL); - pFGLAVSplitterLM->AddEnabledFormat("*"); - // Explicitly disable all common subtitles format - pFGLAVSplitterLM->AddDisabledFormat("aqtitle"); - pFGLAVSplitterLM->AddDisabledFormat("ass"); - pFGLAVSplitterLM->AddDisabledFormat("dvbsub"); - pFGLAVSplitterLM->AddDisabledFormat("dvbtxt"); - pFGLAVSplitterLM->AddDisabledFormat("jacosub"); - pFGLAVSplitterLM->AddDisabledFormat("lrc"); - pFGLAVSplitterLM->AddDisabledFormat("microdvd"); - pFGLAVSplitterLM->AddDisabledFormat("mpl2"); - pFGLAVSplitterLM->AddDisabledFormat("mpsub"); - pFGLAVSplitterLM->AddDisabledFormat("realtext"); - pFGLAVSplitterLM->AddDisabledFormat("sami"); - pFGLAVSplitterLM->AddDisabledFormat("srt"); - pFGLAVSplitterLM->AddDisabledFormat("stl"); - pFGLAVSplitterLM->AddDisabledFormat("subviewer"); - pFGLAVSplitterLM->AddDisabledFormat("subviewer1"); - pFGLAVSplitterLM->AddDisabledFormat("sup"); - pFGLAVSplitterLM->AddDisabledFormat("vobsub"); - pFGLAVSplitterLM->AddDisabledFormat("vplayer"); - pFGLAVSplitterLM->AddDisabledFormat("webvtt"); - m_transform.AddTail(pFGLAVSplitterLM.Detach()); - } -} - -void CFGManagerCustom::InsertOtherInternalSourcefilters(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* src = s.SrcFilters; - CFGFilter* pFGF; - -#if INTERNAL_SOURCEFILTER_RFS - if (src[SRC_RFS] || IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_chkbytes.AddTail(_T("0,7,,526172211A0700")); // rar4 signature - pFGF->m_chkbytes.AddTail(_T("0,8,,526172211A070100")); // rar5 signature - pFGF->m_extensions.AddTail(_T(".rar")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_CDDA - if (src[SRC_CDDA] && !IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_extensions.AddTail(_T(".cda")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_CDXA - if (src[SRC_CDXA] || IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,43445841")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_VTS - if (src[SRC_VTS] || IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_chkbytes.AddTail(_T("0,12,,445644564944454F2D565453")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_DSM - if (src[SRC_DSM] || IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_chkbytes.AddTail(_T("0,4,,44534D53")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_DSM - if (src[SRC_DSM]) { - pFGF = DEBUG_NEW CFGFilterInternal(DSMSplitterName, MERIT64_ABOVE_DSHOW); - } else { - pFGF = DEBUG_NEW CFGFilterInternal(LowMerit(DSMSplitterName), MERIT64_DO_USE); - } - pFGF->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DirectShowMedia); - pFGF->AddType(MEDIATYPE_Stream, GUID_NULL); - m_transform.AddTail(pFGF); -#endif -} - -void CFGManagerCustom::InsertLAVVideo(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* tra = s.TraFilters; - CFGFilter* pFGF; - - CAutoPtr pFGLAVVideo (IsPreview ? CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::VIDEO_DECODER, MERIT64_ABOVE_DSHOW) : CFGFilterLAV::CreateFilter(CFGFilterLAV::VIDEO_DECODER, MERIT64_ABOVE_DSHOW)); - CAutoPtr pFGLAVVideoLM(IsPreview ? CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::VIDEO_DECODER, MERIT64_DO_USE, true) : CFGFilterLAV::CreateFilter(CFGFilterLAV::VIDEO_DECODER, MERIT64_DO_USE, true)); - -#if INTERNAL_DECODER_MPEG1 - pFGF = IsPreview || tra[TRA_MPEG1] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Packet); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Payload); -#endif -#if INTERNAL_DECODER_FLV - pFGF = IsPreview || tra[TRA_FLV4] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLV1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_flv1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLV4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_flv4); -#endif -#if INTERNAL_DECODER_VP356 - pFGF = IsPreview || tra[TRA_VP356] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP30); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP31); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP40); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP50); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp50); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP60); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp60); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP61); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp61); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP62); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp62); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP6F); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp6f); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP6A); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp6a); -#endif -#if INTERNAL_DECODER_H264 - pFGF = IsPreview || tra[TRA_H264] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_X264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_x264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VSSH); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vssh); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DAVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_davc); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_PAVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_pavc); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_avc1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264_bis); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CCV1); -#endif -#if INTERNAL_DECODER_HEVC - pFGF = IsPreview || tra[TRA_HEVC] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HEVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HM10); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H265); -#endif -#if INTERNAL_DECODER_VVC - pFGF = IsPreview || tra[TRA_VVC] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VVC1); -#endif -#if INTERNAL_DECODER_AV1 - pFGF = IsPreview || tra[TRA_AV1] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AV01); -#endif -#if INTERNAL_DECODER_VC1 - pFGF = IsPreview || tra[TRA_VC1] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wvc1); -#endif -#if INTERNAL_DECODER_XVID - pFGF = IsPreview || tra[TRA_XVID] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_XVID); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_xvid); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_XVIX); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_xvix); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP4V); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp4v); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_M4S2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_m4s2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP4S); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp4s); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IV1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3iv1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IV2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3iv2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IVX); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3ivx); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_BLZ0); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_blz0); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DM4V); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dm4v); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DXGM); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dxgm); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_fmp4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HDX4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_hdx4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_LMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_lmp4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NDIG); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ndig); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_RMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_rmp4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_smp4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SEDG); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_sedg); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_UMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ump4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WV1F); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wv1f); -#endif -#if INTERNAL_DECODER_DIVX - pFGF = IsPreview || tra[TRA_DIVX] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIVX); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_divx); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DX50); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dx50); -#endif -#if INTERNAL_DECODER_WMV - pFGF = IsPreview || tra[TRA_WMV] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_2VMW); -#endif -#if INTERNAL_DECODER_MSMPEG4 - pFGF = IsPreview || tra[TRA_MSMPEG4] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DVX3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dvx3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP43); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp43); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_COL1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_col1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV5); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div5); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV6); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div6); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AP41); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap41); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mpg3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP42); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp42); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mpg4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP41); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp41); -#endif -#if INTERNAL_DECODER_SVQ - pFGF = IsPreview || tra[TRA_SVQ3] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SVQ3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SVQ1); -#endif -#if INTERNAL_DECODER_H263 - pFGF = IsPreview || tra[TRA_H263] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H263); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h263); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_S263); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_s263); -#endif -#if INTERNAL_DECODER_THEORA - pFGF = IsPreview || tra[TRA_THEORA] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_THEORA); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_theora); -#endif -#if INTERNAL_DECODER_AMVV - pFGF = IsPreview || tra[TRA_AMVV] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AMVV); -#endif -#if INTERNAL_DECODER_VP8 - pFGF = IsPreview || tra[TRA_VP8] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP80); -#endif -#if INTERNAL_DECODER_VP9 - pFGF = IsPreview || tra[TRA_VP9] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP90); -#endif -#if INTERNAL_DECODER_MJPEG - pFGF = IsPreview || tra[TRA_MJPEG] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPG); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_QTJpeg); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPA); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPB); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVRn); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_LJPG); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_JPGL); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJLS); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPA); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPB); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SP5X); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SP54); -#endif -#if INTERNAL_DECODER_INDEO - pFGF = IsPreview || tra[TRA_INDEO] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV31); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV32); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV41); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV50); -#endif -#if INTERNAL_DECODER_SCREEN - pFGF = IsPreview || tra[TRA_SCREEN] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_TSCC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_TSC2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VMNC); -#endif -#if INTERNAL_DECODER_FLIC - pFGF = IsPreview || tra[TRA_FLIC] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLIC); -#endif -#if INTERNAL_DECODER_MSVIDEO - pFGF = IsPreview || tra[TRA_MSVIDEO] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CRAM); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WHAM); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MSVC); -#endif -#if INTERNAL_DECODER_V210_V410 - pFGF = IsPreview || tra[TRA_V210_V410] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_v210); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_v410); -#endif -#if INTERNAL_DECODER_MPEG2 - pFGF = IsPreview || tra[TRA_MPEG2] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG2); -#endif -#if INTERNAL_DECODER_PRORES - pFGF = IsPreview || tra[TRA_PRORES] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apch); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apcn); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apcs); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apco); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap4h); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap4x); -#endif -#if INTERNAL_DECODER_DNXHD - pFGF = IsPreview || tra[TRA_DNXHD] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVdn); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVdh); -#endif -#if INTERNAL_DECODER_OTHERVIDEO - pFGF = IsPreview || tra[TRA_OTHERVIDEO] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CFHD); -#endif - - // Add LAV Video if needed - if (!pFGLAVVideo->GetTypes().IsEmpty()) { - m_transform.AddTail(pFGLAVVideo.Detach()); - } - - // Add low merit LAV video - pFGLAVVideoLM->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGLAVVideoLM.Detach()); -} - -void CFGManagerCustom::InsertLAVAudio() -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* tra = s.TraFilters; - CFGFilter* pFGF; - - CAutoPtr pFGLAVAudio(CFGFilterLAV::CreateFilter(CFGFilterLAV::AUDIO_DECODER, MERIT64_ABOVE_DSHOW)); - CAutoPtr pFGLAVAudioLM(CFGFilterLAV::CreateFilter(CFGFilterLAV::AUDIO_DECODER, MERIT64_DO_USE, true)); - -#if INTERNAL_DECODER_MPEGAUDIO - pFGF = tra[TRA_MPA] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MP3); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1AudioPayload); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Payload); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Packet); - - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG2_AUDIO); -#endif - -#if INTERNAL_DECODER_AMR - pFGF = tra[TRA_AMR] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_SAMR); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AMR); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_SAWB); -#endif - -#if INTERNAL_DECODER_LPCM - pFGF = tra[TRA_LPCM] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_HDMV_LPCM_AUDIO); -#endif - -#if INTERNAL_DECODER_AC3 - pFGF = tra[TRA_AC3] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WAVE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_TRUEHD); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_DDPLUS); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MLP); -#endif - -#if INTERNAL_DECODER_DTS - pFGF = tra[TRA_DTS] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DTS_HD); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WAVE_DTS); -#endif - -#if INTERNAL_DECODER_AAC - pFGF = tra[TRA_AAC] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_AAC); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_AAC); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AAC); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_LATM_AAC); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AAC_ADTS); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MP4A); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MP4A); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MP4A); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_mp4a); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_mp4a); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_mp4a); -#endif - -#if INTERNAL_DECODER_PS2AUDIO - pFGF = tra[TRA_PS2AUD] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_PS2_PCM); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_PS2_PCM); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PS2_PCM); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_PS2_ADPCM); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_PS2_ADPCM); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PS2_ADPCM); -#endif - -#if INTERNAL_DECODER_VORBIS - pFGF = tra[TRA_VORBIS] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_Vorbis2); -#endif - -#if INTERNAL_DECODER_FLAC - pFGF = tra[TRA_FLAC] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_FLAC_FRAMED); -#endif - -#if INTERNAL_DECODER_NELLYMOSER - pFGF = tra[TRA_NELLY] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NELLYMOSER); -#endif - -#if INTERNAL_DECODER_ALAC - pFGF = tra[TRA_ALAC] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ALAC); -#endif - -#if INTERNAL_DECODER_ALS - pFGF = tra[TRA_ALS] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ALS); -#endif - -#if INTERNAL_DECODER_OPUS - pFGF = tra[TRA_OPUS] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_OPUS); -#endif - -#if INTERNAL_DECODER_WMA - pFGF = tra[TRA_WMA] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MSAUDIO1); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO2); -#endif - -#if INTERNAL_DECODER_WMAPRO - pFGF = tra[TRA_WMAPRO] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO3); -#endif - -#if INTERNAL_DECODER_WMALL - pFGF = tra[TRA_WMALL] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO_LOSSLESS); -#endif - -#if INTERNAL_DECODER_PCM - pFGF = tra[TRA_PCM] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_NONE); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_RAW); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_TWOS); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_SOWT); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_IN24); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_IN32); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_FL32); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_FL64); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IEEE_FLOAT); // only for 64-bit float PCM - /* todo: this should not depend on PCM */ - #if INTERNAL_DECODER_ADPCM - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMA4); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ADPCM_SWF); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ADPCM_AMV); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMA_WAV); - #endif -#endif - -#if INTERNAL_DECODER_G726 - pFGF = tra[TRA_G726] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_G726); -#endif - -#if INTERNAL_DECODER_G729 - pFGF = tra[TRA_G729] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_G729); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_729A); -#endif - -#if INTERNAL_DECODER_OTHERAUDIO - pFGF = tra[TRA_OTHERAUDIO] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMC); -#endif - - // Add LAV Audio if needed - if (!pFGLAVAudio->GetTypes().IsEmpty()) { - m_transform.AddTail(pFGLAVAudio.Detach()); - } - - // Add low merit LAV Audio - pFGLAVAudioLM->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGLAVAudioLM.Detach()); -} - -void CFGManagerCustom::InsertBlockedFilters() -{ - // "Subtitle Mixer" makes an access violation around the - // 11-12th media type when enumerating them on its output. - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{00A95963-3BE5-48C0-AD9F-3356D67EA09D}")), MERIT64_DO_NOT_USE)); - - // DiracSplitter.ax is crashing MPC-HC when opening invalid files... - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{09E7F58E-71A1-419D-B0A0-E524AE1454A9}")), MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{5899CFB9-948F-4869-A999-5544ECB38BA5}")), MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{F78CF248-180E-4713-B107-B13F7B5C31E1}")), MERIT64_DO_NOT_USE)); - - // ISCR suxx - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}")), MERIT64_DO_NOT_USE)); - - // Samsung's "mpeg-4 demultiplexor" can even open matroska files, amazing... - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{99EC0C72-4D1B-411B-AB1F-D561EE049D94}")), MERIT64_DO_NOT_USE)); - - // LG Video Renderer (lgvid.ax) just crashes when trying to connect it - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{9F711C60-0668-11D0-94D4-0000C02BA972}")), MERIT64_DO_NOT_USE)); - - // palm demuxer crashes (even crashes graphedit when dropping an .ac3 onto it) - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{BE2CF8A7-08CE-4A2C-9A25-FD726A999196}")), MERIT64_DO_NOT_USE)); - - // mainconcept color space converter - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{272D77A0-A852-4851-ADA4-9091FEAD4C86}")), MERIT64_DO_NOT_USE)); - - // mainconcept mp4 demuxer - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{2A55FF12-1657-41D7-9D2D-A2CDC6978FF2}")), MERIT64_DO_NOT_USE)); - - // Accusoft PICVideo M-JPEG Codec - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{4C4CD9E1-F876-11D2-962F-00500471FDDC}")), MERIT64_DO_NOT_USE)); - - // SolveigMM MP4 Demultiplexer (smm_mp4demuxer.ax) - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{5F19B8FE-BA79-4183-B3CF-FEE4E8F801E4}")), MERIT64_DO_NOT_USE)); - - // Morgan's Stream Switcher (mmswitch.ax) - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_MorganStreamSwitcher, MERIT64_DO_NOT_USE)); - - if (AfxGetAppSettings().bBlockRDP) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_RDPDShowRedirectionFilter, MERIT64_DO_NOT_USE)); - } - - // DCDSPFilter (early versions crash mpc) - { - CRegKey key; - - TCHAR buff[256]; - ULONG len = sizeof(buff); - ZeroMemory(buff, sizeof(buff)); - - CString clsid = _T("{B38C58A0-1809-11D6-A458-EDAE78F1DF12}"); - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + clsid + _T("\\InprocServer32"), KEY_READ) - && ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len) - && FileVersionInfo::GetFileVersionNum(buff) < 0x0001000000030000ui64) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(clsid), MERIT64_DO_NOT_USE)); - } - } -} - -void CFGManagerCustom::InsertSubtitleFilters(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - CFGFilter* pFGF; - - // Null text renderer - pFGF = DEBUG_NEW CFGFilterInternal(L"NullTextRenderer", IsPreview ? MERIT64_ABOVE_DSHOW : MERIT64_DO_USE); - pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_ScriptCommand, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_Subtitle, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DVD_SUBPICTURE); - pFGF->AddType(MEDIATYPE_NULL, MEDIASUBTYPE_CVD_SUBPICTURE); - pFGF->AddType(MEDIATYPE_NULL, MEDIASUBTYPE_SVCD_SUBPICTURE); - m_transform.AddTail(pFGF); - - if (IsPreview) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - } else { - // Insert preferred subtitle renderer and block others - switch (s.GetSubtitleRenderer()) { - case CAppSettings::SubtitleRenderer::INTERNAL: - if (s.fBlockVSFilter) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); - } - if (s.fBlockVSFilter || IsCLSIDRegistered(CLSID_VSFilter)) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); - } - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - break; - case CAppSettings::SubtitleRenderer::VS_FILTER: - pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_ABOVE_DSHOW); - if (pFGF) { - pFGF->AddType(MEDIASUBTYPE_NULL, MEDIASUBTYPE_NULL); - m_override.AddTail(pFGF); - } - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - break; - case CAppSettings::SubtitleRenderer::XY_SUB_FILTER: - pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_ABOVE_DSHOW); - if (pFGF) { - pFGF->AddType(MEDIASUBTYPE_NULL, MEDIASUBTYPE_NULL); - m_override.AddTail(pFGF); - } - pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_ABOVE_DSHOW); - if (pFGF) { - pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_Subtitle, MEDIASUBTYPE_NULL); - m_override.AddTail(pFGF); - } - if (s.fBlockVSFilter) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); - } - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - break; - case CAppSettings::SubtitleRenderer::NONE: - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - break; - } - } -} - -void CFGManagerCustom::InsertBroadcomDecoder() -{ - CFGFilter* pFGF = DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{2DE1D17E-46B1-42A8-9AEC-E20E80D9B1A9}")), MERIT64_ABOVE_DSHOW); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_X264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_x264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VSSH); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vssh); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DAVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_davc); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_PAVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_pavc); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_avc1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264_bis); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CCV1); - - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wvc1); - - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO); - m_transform.AddHead(pFGF); -} - -// -// CFGManagerCustom -// - -CFGManagerCustom::CFGManagerCustom(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) - : CFGManager(pName, pUnk, hWnd, IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - - bool bOverrideBroadcom = false; - CFGFilter* pFGF; - m_source; - - const bool* src = s.SrcFilters; - const bool* tra = s.TraFilters; - - // Reset LAVFilters internal instances - CFGFilterLAV::ResetInternalInstances(); - - // Add internal filters - InsertLAVSplitterSource(IsPreview); - InsertLAVSplitter(IsPreview); - InsertOtherInternalSourcefilters(IsPreview); -#if HAS_VIDEO_DECODERS - InsertLAVVideo(IsPreview); -#endif -#if HAS_AUDIO_DECODERS - if (!IsPreview) { - InsertLAVAudio(); - } -#endif - InsertSubtitleFilters(IsPreview); - - // Blocked filters - InsertBlockedFilters(); - if (m_bIsPreview) { - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_RDPDShowRedirectionFilter, MERIT64_DO_NOT_USE)); - } - - // Overrides - WORD merit_low = 1; - POSITION pos = s.m_filters.GetTailPosition(); - while (pos) { - FilterOverride* fo = s.m_filters.GetPrev(pos); - - if (!fo->fDisabled && fo->name == _T("Broadcom Video Decoder")) { - bOverrideBroadcom = true; - } - if (fo->fDisabled || fo->type == FilterOverride::EXTERNAL && !PathUtils::Exists(MakeFullPath(fo->path))) { - continue; - } - - ULONGLONG merit = - fo->iLoadType == FilterOverride::BLOCK ? MERIT64_DO_NOT_USE : - fo->iLoadType == FilterOverride::PREFERRED ? (IsPreview ? MERIT64_DO_USE : MERIT64_ABOVE_DSHOW) : - MERIT64(fo->dwMerit); - - merit += merit_low++; - - pFGF = nullptr; - if (fo->type == FilterOverride::REGISTERED) { - pFGF = DEBUG_NEW CFGFilterRegistry(fo->dispname, merit); - } else if (fo->type == FilterOverride::EXTERNAL) { - pFGF = DEBUG_NEW CFGFilterFile(fo->clsid, fo->path, CStringW(fo->name), merit); - } - if (pFGF) { - pFGF->SetTypes(fo->guids); - m_override.AddTail(pFGF); - } - } - - /* Use Broadcom decoder (if installed) for VC-1, H.264 and MPEG-2 */ - if (!IsPreview && !bOverrideBroadcom) { - // ToDo: maybe remove support for this old filter? - InsertBroadcomDecoder(); - } -} - -STDMETHODIMP CFGManagerCustom::AddFilter(IBaseFilter* pBF, LPCWSTR pName) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (FAILED(hr = __super::AddFilter(pBF, pName))) { - return hr; - } - - CAppSettings& s = AfxGetAppSettings(); - - if (GetCLSID(pBF) == CLSID_DMOWrapperFilter) { - if (CComQIPtr pPB = pBF) { - CComVariant var(true); - pPB->Write(_T("_HIRESOUTPUT"), &var); - } - } - - if (CComQIPtr pASF = pBF) { - pASF->EnableDownSamplingTo441(s.fDownSampleTo441); - pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); - pASF->SetAudioTimeShift(s.fAudioTimeShift ? 10000i64 * s.iAudioTimeShift : 0); - pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); - } - - return hr; -} - -// -// CFGManagerPlayer -// - -CFGManagerPlayer::CFGManagerPlayer(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) - : CFGManagerCustom(pName, pUnk, hWnd, IsPreview) - , m_hWnd(hWnd) -{ - TRACE(_T("CFGManagerPlayer::CFGManagerPlayer on thread: %lu\n"), GetCurrentThreadId()); - CFGFilter* pFGF; - - const CAppSettings& s = AfxGetAppSettings(); - - /* value is chosen so that it is higher than standard renderers, but lower than important intermediate filters like VSFilter */ - UINT64 renderer_merit = MERIT64(0x800001) + 0x100; - - // Switchers - - if (s.fEnableAudioSwitcher && !m_bIsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(L"Audio Switcher", renderer_merit + 0x100); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } - - // Renderers - if (!m_bIsPreview) { - switch (s.iDSVideoRendererType) { - case VIDRNDT_DS_DEFAULT: - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VideoRendererDefault, MERIT64(0x800001))); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VideoMixingRenderer9, MERIT64(0x200003))); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_EnhancedVideoRenderer, MERIT64(0x200002))); - break; - case VIDRNDT_DS_OVERLAYMIXER: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_OverlayMixer, StrRes(IDS_PPAGE_OUTPUT_OVERLAYMIXER), renderer_merit)); - break; - case VIDRNDT_DS_VMR9WINDOWED: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VideoMixingRenderer9, StrRes(IDS_PPAGE_OUTPUT_VMR9WINDOWED), renderer_merit)); - break; - case VIDRNDT_DS_VMR9RENDERLESS: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VMR9AllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_VMR9RENDERLESS), renderer_merit)); - break; - case VIDRNDT_DS_EVR: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, StrRes(IDS_PPAGE_OUTPUT_EVR), renderer_merit)); - break; - case VIDRNDT_DS_EVR_CUSTOM: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_EVR_CUSTOM), renderer_merit)); - break; - case VIDRNDT_DS_DXR: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_DXRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_DXR), renderer_merit)); - break; - case VIDRNDT_DS_MADVR: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_madVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_MADVR), renderer_merit)); - break; - case VIDRNDT_DS_SYNC: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_SyncAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_SYNC), renderer_merit)); - break; - case VIDRNDT_DS_MPCVR: - if (!m_bIsCapture) { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_MPCVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_MPCVR), renderer_merit)); - } else { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, StrRes(IDS_PPAGE_OUTPUT_EVR), renderer_merit)); - } - break; - case VIDRNDT_DS_NULL_COMP: - pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_COMP), MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - break; - case VIDRNDT_DS_NULL_UNCOMP: - pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_UNCOMP), MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - break; - } - } else { - bool preview_evrcp = (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) || (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) || (s.iDSVideoRendererType == VIDRNDT_DS_MADVR) || (s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); - if (preview_evrcp && CAppSettings::IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM)) { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EVRAllocatorPresenter, L"EVRCP - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); - m_bPreviewSupportsRotation = true; - } else if (CAppSettings::IsVideoRendererAvailable(VIDRNDT_DS_EVR)) { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, L"EVR - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); - } else { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VideoMixingRenderer9, L"VMR9 - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); - } - } - - if (!m_bIsPreview) { - CString SelAudioRenderer = s.SelectedAudioRenderer(); - if (SelAudioRenderer == AUDRNDT_NULL_COMP) { - pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_COMP, MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - // DVD stuff - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); - m_transform.AddTail(pFGF); - } else if (SelAudioRenderer == AUDRNDT_NULL_UNCOMP) { - pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_UNCOMP, MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } else if (SelAudioRenderer == AUDRNDT_INTERNAL) { - struct SaneAudioRendererFilter : CFGFilter { - SaneAudioRendererFilter(CStringW name, UINT64 merit) : - CFGFilter(SaneAudioRenderer::Factory::GetFilterGuid(), name, merit) {} - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList&) override { - return SaneAudioRenderer::Factory::CreateFilter(AfxGetAppSettings().sanear, ppBF); - } - }; - pFGF = DEBUG_NEW SaneAudioRendererFilter(AUDRNDT_SANEAR, renderer_merit + 0x50); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } else if (SelAudioRenderer == AUDRNDT_MPC) { - pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_MPC, renderer_merit); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IEEE_FLOAT); - m_transform.AddTail(pFGF); - } else if (!SelAudioRenderer.IsEmpty()) { - pFGF = DEBUG_NEW CFGFilterRegistry(SelAudioRenderer, renderer_merit); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } - } else { - pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_COMP, MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - // DVD stuff - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); - m_transform.AddTail(pFGF); - } -} - -STDMETHODIMP CFGManagerPlayer::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) -{ - CAutoLock cAutoLock(this); - - CLSID pin_clsid = GetCLSID(pPinOut); - if (pin_clsid == CLSID_MPEG2Demultiplexer) { - CComQIPtr pMS = pPinOut; - REFERENCE_TIME rtDur = 0; - if (!pMS || FAILED(pMS->GetDuration(&rtDur)) || rtDur <= 0) { - return E_FAIL; - } - } else if (pin_clsid == CLSID_StillVideo || pin_clsid == CLSID_MPCImageSource) { - CComQIPtr pMS = pPinOut; - if (pMS) { - const CAppSettings& s = AfxGetAppSettings(); - if (s.iStillVideoDuration > 0) { - REFERENCE_TIME rtCur = 0; - REFERENCE_TIME rtDur = 0; - REFERENCE_TIME rtDurOverride = s.iStillVideoDuration * 10000000LL; - pMS->GetDuration(&rtDur); - if (rtDur == 0 || rtDur >= 10 * 3600 * 10000000LL) { - rtDur = rtDurOverride; - } else if (rtDur < rtDurOverride) { - rtDur = (rtDurOverride / rtDur) * rtDur; - } - // always call SetPositions() to prevent infinite repeat by the source filter - pMS->SetPositions(&rtCur, AM_SEEKING_AbsolutePositioning, &rtDur, AM_SEEKING_AbsolutePositioning); - } - } - } - - return __super::ConnectDirect(pPinOut, pPinIn, pmt); -} - -// -// CFGManagerDVD -// - -CFGManagerDVD::CFGManagerDVD(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) - : CFGManagerPlayer(pName, pUnk, hWnd, IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - - // elecard's decoder isn't suited for dvd playback (atm) - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{F50B3F13-19C4-11CF-AA9A-02608C9BABA2}")), MERIT64_DO_NOT_USE)); -} - -class CResetDVD : public CDVDSession -{ -public: - CResetDVD(LPCTSTR path) { - if (Open(path)) { - if (BeginSession()) { - Authenticate(); /*GetDiscKey();*/ - EndSession(); - } - Close(); - } - } -}; - -STDMETHODIMP CFGManagerDVD::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - CComPtr pBF; - if (FAILED(hr = AddSourceFilter(lpcwstrFile, lpcwstrFile, &pBF))) { - return hr; - } - - return ConnectFilter(pBF, nullptr); -} - -STDMETHODIMP CFGManagerDVD::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - CAutoLock cAutoLock(this); - - CheckPointer(lpcwstrFileName, E_POINTER); - CheckPointer(ppFilter, E_POINTER); - - CStringW fn = CStringW(lpcwstrFileName).TrimLeft(); - - GUID clsid = CLSID_DVDNavigator; - - CComPtr pBF; - if (FAILED(pBF.CoCreateInstance(clsid)) - || FAILED(AddFilter(pBF, L"DVD Navigator"))) { - return VFW_E_CANNOT_LOAD_SOURCE_FILTER; - } - - CComQIPtr pDVDC; - CComQIPtr pDVDI; - - if (!((pDVDC = pBF) && (pDVDI = pBF))) { - return E_NOINTERFACE; - } - - WCHAR buff[MAX_PATH]; - ULONG len; - if ((!fn.IsEmpty() - && FAILED(pDVDC->SetDVDDirectory(fn)) - && FAILED(pDVDC->SetDVDDirectory(fn + L"VIDEO_TS")) - && FAILED(pDVDC->SetDVDDirectory(fn + L"\\VIDEO_TS"))) - || FAILED(pDVDI->GetDVDDirectory(buff, _countof(buff), &len)) || len == 0) { - return E_INVALIDARG; - } - - pDVDC->SetOption(DVD_ResetOnStop, FALSE); - pDVDC->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); - - if (clsid == CLSID_DVDNavigator) { - CResetDVD(CString(buff)); - } - - *ppFilter = pBF.Detach(); - - return S_OK; -} - -// -// CFGManagerCapture -// - -CFGManagerCapture::CFGManagerCapture(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd) - : CFGManagerPlayer(pName, pUnk, hWnd) -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (s.bCaptureDeinterlace) { - // set merit higher than our video renderers - CFGFilter* pFGF = DEBUG_NEW CFGFilterInternal(L"Deinterlacer", MERIT64(0x800001) + 0x200); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } - - m_bIsCapture = True; -} - -// -// CFGManagerMuxer -// - -CFGManagerMuxer::CFGManagerMuxer(LPCTSTR pName, LPUNKNOWN pUnk) - : CFGManagerCustom(pName, pUnk) -{ - m_source.AddTail(DEBUG_NEW CFGFilterInternal()); -} - -// -// CFGAggregator -// - -CFGAggregator::CFGAggregator(const CLSID& clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT& hr) - : CUnknown(pName, pUnk) -{ - hr = m_pUnkInner.CoCreateInstance(clsid, GetOwner()); -} - -CFGAggregator::~CFGAggregator() -{ - m_pUnkInner.Release(); -} - -STDMETHODIMP CFGAggregator::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - m_pUnkInner && (riid != IID_IUnknown && SUCCEEDED(m_pUnkInner->QueryInterface(riid, ppv))) ? S_OK : - __super::NonDelegatingQueryInterface(riid, ppv); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "FGManager.h" +#include "../DeCSS/VobFile.h" +#include "../filters/Filters.h" +#include "AllocatorCommon.h" +#include "DeinterlacerFilter.h" +#include "FakeFilterMapper2.h" +#include "FileVersionInfo.h" +#include "IPinHook.h" +#include "NullRenderers.h" +#include "PathUtils.h" +#include "SyncAllocatorPresenter.h" +#include "mplayerc.h" +#include "sanear/src/Factory.h" +#include "../src/thirdparty/MpcAudioRenderer/MpcAudioRenderer.h" +#include "DSUtil.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "../src/thirdparty/LAVFilters/src/include/IURLSourceFilterLAV.h" + +#include +#include "moreuuids.h" +#include + +#if !TRACE_GRAPH_BUILD +#undef TRACE +#define TRACE(...) +#endif + +// +// CFGManager +// + +class CNullAudioRenderer; + +CFGManager::CFGManager(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) + : CUnknown(pName, pUnk) + , m_dwRegister(0) + , m_hWnd(hWnd) + , m_bIsPreview(IsPreview) + , m_bPreviewSupportsRotation(false) + , m_ignoreVideo(false) + , m_bIsCapture(false) + , m_source() + , m_transform() + , m_override() + , m_deadends() + , m_aborted(false) + , m_useragent() + , m_referrer() +{ + m_pUnkInner.CoCreateInstance(CLSID_FilterGraph, GetOwner()); + m_pFM.CoCreateInstance(CLSID_FilterMapper2); +} + +CFGManager::~CFGManager() +{ + CAutoLock cAutoLock(this); + while (!m_source.IsEmpty()) { + delete m_source.RemoveHead(); + } + while (!m_transform.IsEmpty()) { + delete m_transform.RemoveHead(); + } + while (!m_override.IsEmpty()) { + delete m_override.RemoveHead(); + } + m_pUnks.RemoveAll(); + m_pUnkInner.Release(); +} + +STDMETHODIMP CFGManager::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFilterGraph) + QI(IGraphBuilder) + QI(IFilterGraph2) + QI(IGraphBuilder2) + QI(IGraphBuilderDeadEnd) + (m_pUnkInner && riid != IID_IUnknown && SUCCEEDED(m_pUnkInner->QueryInterface(riid, ppv))) ? S_OK : + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// + +void CFGManager::CStreamPath::Append(IBaseFilter* pBF, IPin* pPin) +{ + path_t p; + p.clsid = GetCLSID(pBF); + p.filter = GetFilterName(pBF); + p.pin = GetPinName(pPin); + AddTail(p); +} + +bool CFGManager::CStreamPath::Compare(const CStreamPath& path) +{ + POSITION pos1 = GetHeadPosition(); + POSITION pos2 = path.GetHeadPosition(); + + while (pos1 && pos2) { + const path_t& p1 = GetNext(pos1); + const path_t& p2 = path.GetNext(pos2); + + if (p1.filter != p2.filter) { + return true; + } else if (p1.pin != p2.pin) { + return false; + } + } + + return true; +} + +// + +bool CFGManager::CheckBytes(HANDLE hFile, CString chkbytes) +{ + CAtlList sl; + Explode(chkbytes, sl, ','); + + if (sl.GetCount() < 4) { + return false; + } + + ASSERT(!(sl.GetCount() & 3)); + + LARGE_INTEGER size = {0, 0}; + GetFileSizeEx(hFile, &size); + + while (sl.GetCount() >= 4) { + CString offsetstr = sl.RemoveHead(); + CString cbstr = sl.RemoveHead(); + CString maskstr = sl.RemoveHead(); + CString valstr = sl.RemoveHead(); + + long cb = _ttol(cbstr); + + if (offsetstr.IsEmpty() || cbstr.IsEmpty() + || valstr.IsEmpty() || (valstr.GetLength() & 1) + || cb * 2 != valstr.GetLength()) { + return false; + } + + LARGE_INTEGER offset; + offset.QuadPart = _ttoi64(offsetstr); + if (offset.QuadPart < 0) { + offset.QuadPart = size.QuadPart - offset.QuadPart; + } + SetFilePointerEx(hFile, offset, &offset, FILE_BEGIN); + + // LAME + while (maskstr.GetLength() < valstr.GetLength()) { + maskstr += _T('F'); + } + + CAtlArray mask, val; + CStringToBin(maskstr, mask); + CStringToBin(valstr, val); + + for (size_t i = 0; i < val.GetCount(); i++) { + BYTE b; + DWORD r; + if (!ReadFile(hFile, &b, 1, &r, nullptr) || (b & mask[i]) != val[i]) { + return false; + } + } + } + + return sl.IsEmpty(); +} + +CFGFilter* LookupFilterRegistry(const GUID& guid, CAtlList& list, UINT64 fallback_merit = MERIT64_DO_USE) +{ + POSITION pos = list.GetHeadPosition(); + CFGFilter* pFilter = nullptr; + while (pos) { + CFGFilter* pFGF = list.GetNext(pos); + if (pFGF->GetCLSID() == guid) { + pFilter = pFGF; + break; + } + } + if (pFilter) { + return DEBUG_NEW CFGFilterRegistry(guid, pFilter->GetMerit()); + } else { + return DEBUG_NEW CFGFilterRegistry(guid, fallback_merit); + } +} + +HRESULT CFGManager::EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl) +{ + // TODO: use overrides + + CheckPointer(lpcwstrFileName, E_POINTER); + + fl.RemoveAll(); + + CStringW fn = CStringW(lpcwstrFileName).TrimLeft(); + CStringW cfn = fn; + if (cfn.Left(4) == "\\\\?\\") { + cfn = cfn.Mid(4); + } + CStringW protocol = cfn.Left(cfn.Find(':') + 1).TrimRight(':').MakeLower(); + CStringW ext = CPathW(fn).GetExtension().MakeLower(); + + HANDLE hFile = INVALID_HANDLE_VALUE; + + if (protocol.GetLength() <= 1 || protocol == L"file") { + hFile = CreateFile(CString(fn), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)nullptr); + + // In case of audio CDs with extra content, the audio tracks + // cannot be accessed directly so we have to try opening it + if (hFile == INVALID_HANDLE_VALUE && ext != L".cda") { + return VFW_E_NOT_FOUND; + } + } + + if (hFile == INVALID_HANDLE_VALUE) { + // internal / protocol + + POSITION pos = m_source.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_source.GetNext(pos); + if (pFGF->m_protocols.Find(CString(protocol))) { + fl.Insert(pFGF, 0, false, false); + } + } + } else { + // internal / check bytes + + POSITION pos = m_source.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_source.GetNext(pos); + + POSITION pos2 = pFGF->m_chkbytes.GetHeadPosition(); + while (pos2) { + if (CheckBytes(hFile, pFGF->m_chkbytes.GetNext(pos2))) { + fl.Insert(pFGF, 1, false, false); + break; + } + } + } + } + + if (!ext.IsEmpty()) { + // internal / file extension + + POSITION pos = m_source.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_source.GetNext(pos); + if (pFGF->m_extensions.Find(CString(ext))) { + fl.Insert(pFGF, 2, false, false); + } + } + } + + { + // internal / the rest + + POSITION pos = m_source.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_source.GetNext(pos); + if (pFGF->m_protocols.IsEmpty() && pFGF->m_chkbytes.IsEmpty() && pFGF->m_extensions.IsEmpty()) { + fl.Insert(pFGF, 3, false, false); + } + } + } + + TCHAR buff[256]; + ULONG len; + + if (hFile == INVALID_HANDLE_VALUE) { + // protocol + + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, CString(protocol), KEY_READ)) { + CRegKey exts; + if (ERROR_SUCCESS == exts.Open(key, _T("Extensions"), KEY_READ)) { + len = _countof(buff); + if (ERROR_SUCCESS == exts.QueryStringValue(CString(ext), buff, &len)) { + fl.Insert(LookupFilterRegistry(GUIDFromCString(buff), m_override), 4); + } + } + + len = _countof(buff); + if (ERROR_SUCCESS == key.QueryStringValue(_T("Source Filter"), buff, &len)) { + fl.Insert(LookupFilterRegistry(GUIDFromCString(buff), m_override), 5); + } + } + + fl.Insert(DEBUG_NEW CFGFilterRegistry(CLSID_URLReader), 6); + } else { + // check bytes + + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Media Type"), KEY_READ)) { + FILETIME ft; + len = _countof(buff); + for (DWORD i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len, &ft); i++, len = _countof(buff)) { + GUID majortype; + if (FAILED(GUIDFromCString(buff, majortype))) { + continue; + } + + CRegKey majorkey; + if (ERROR_SUCCESS == majorkey.Open(key, buff, KEY_READ)) { + len = _countof(buff); + for (DWORD j = 0; ERROR_SUCCESS == majorkey.EnumKey(j, buff, &len, &ft); j++, len = _countof(buff)) { + GUID subtype; + if (FAILED(GUIDFromCString(buff, subtype))) { + continue; + } + + CRegKey subkey; + if (ERROR_SUCCESS == subkey.Open(majorkey, buff, KEY_READ)) { + len = _countof(buff); + if (ERROR_SUCCESS != subkey.QueryStringValue(_T("Source Filter"), buff, &len)) { + continue; + } + + GUID clsid = GUIDFromCString(buff); + TCHAR buff2[256]; + ULONG len2; + + len = _countof(buff); + len2 = sizeof(buff2); + for (DWORD k = 0, type; + clsid != GUID_NULL && ERROR_SUCCESS == RegEnumValue(subkey, k, buff2, &len2, 0, &type, (BYTE*)buff, &len); + k++, len = _countof(buff), len2 = sizeof(buff2)) { + if (CheckBytes(hFile, CString(buff))) { + CFGFilter* pFGF = LookupFilterRegistry(clsid, m_override); + pFGF->AddType(majortype, subtype); + if (pFGF->GetMerit() >= MERIT64_ABOVE_DSHOW) { + fl.Insert(pFGF, 7); + } else { + fl.Insert(pFGF, 9); + } + break; + } + } + } + } + } + } + } + } + + if (!ext.IsEmpty()) { + // file extension + + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Media Type\\Extensions\\") + CString(ext), KEY_READ)) { + len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + LONG ret = key.QueryStringValue(_T("Source Filter"), buff, &len); // QueryStringValue can return ERROR_INVALID_DATA on bogus strings (radlight mpc v1003, fixed in v1004) + if (ERROR_SUCCESS == ret || ERROR_INVALID_DATA == ret && GUIDFromCString(buff) != GUID_NULL) { + GUID clsid = GUIDFromCString(buff); + GUID majortype = GUID_NULL; + GUID subtype = GUID_NULL; + + len = _countof(buff); + if (ERROR_SUCCESS == key.QueryStringValue(_T("Media Type"), buff, &len)) { + majortype = GUIDFromCString(buff); + } + + len = _countof(buff); + if (ERROR_SUCCESS == key.QueryStringValue(_T("Subtype"), buff, &len)) { + subtype = GUIDFromCString(buff); + } + + CFGFilter* pFGF = LookupFilterRegistry(clsid, m_override); + pFGF->AddType(majortype, subtype); + fl.Insert(pFGF, 7); + } + } + + // preferred external filters + if (ext == L".avs" || ext == L".vpy") { + POSITION pos = m_override.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_override.GetNext(pos); + if (pFGF->GetMerit() >= MERIT64_ABOVE_DSHOW) { + if (pFGF->GetCLSID() == GUIDFromCString(L"{7D3BBD5A-880D-4A30-A2D1-7B8C2741AFEF}")) { // MPC Script Source + if (ext == L".avs" || ext == L".vpy") { + fl.Insert(pFGF, 0, false, false); + } + } + } + } + } + } + + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle(hFile); + + CFGFilter* pFGF = LookupFilterRegistry(CLSID_AsyncReader, m_override); + pFGF->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_NULL); + fl.Insert(pFGF, 9); + } + + return S_OK; +} + +HRESULT CFGManager::AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF) +{ + CLSID clsid = pFGF->GetCLSID(); + TRACE(_T("FGM: AddSourceFilter trying '%s'\n"), CStringFromGUID(clsid).GetString()); + + CheckPointer(lpcwstrFileName, E_POINTER); + CheckPointer(ppBF, E_POINTER); + + ASSERT(*ppBF == nullptr); + + HRESULT hr; + + CComPtr pBF; + CInterfaceList pUnks; + if (FAILED(hr = pFGF->Create(&pBF, pUnks))) { + return hr; + } + + CComQIPtr pFSF = pBF; + if (!pFSF) { + return E_NOINTERFACE; + } + + if (clsid == __uuidof(CRARFileSource) && m_entryRFS.GetLength() > 0) { + CComPtr rfs = static_cast(pBF.p); + std::wstring preselectedRarFileEntry(m_entryRFS.GetBuffer()); + rfs->SetPreselectedRarFileEntry(preselectedRarFileEntry); + } + + if (FAILED(hr = AddFilter(pBF, lpcwstrFilterName))) { + return hr; + } + + const AM_MEDIA_TYPE* pmt = nullptr; + if (clsid == GUID_LAVSplitterSource) { + CComQIPtr pSFL = pBF; + if (pSFL && (!m_useragent.IsEmpty() || !m_referrer.IsEmpty())) { + // ToDo: set strings + hr = pSFL->LoadURL(lpcwstrFileName, m_useragent, m_referrer); + if (FAILED(hr)) { + RemoveFilter(pBF); + return hr; + } + } else { + hr = pFSF->Load(lpcwstrFileName, pmt); + if (FAILED(hr)) { + RemoveFilter(pBF); + return hr; + } + } + } else { + CMediaType mt; + const CAtlList& types = pFGF->GetTypes(); + if (types.GetCount() == 2 && (types.GetHead() != GUID_NULL || types.GetTail() != GUID_NULL)) { + mt.majortype = types.GetHead(); + mt.subtype = types.GetTail(); + pmt = &mt; + } + + hr = pFSF->Load(lpcwstrFileName, pmt); + if (FAILED(hr) || m_aborted) { // sometimes looping with AviSynth + RemoveFilter(pBF); + return m_aborted ? E_ABORT : hr; + } + + BeginEnumMediaTypes(GetFirstPin(pBF, PINDIR_OUTPUT), pEMT, pmt2) { + static const GUID guid1 = + { 0x640999A0, 0xA946, 0x11D0, { 0xA5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // ASX file Parser + static const GUID guid2 = + { 0x640999A1, 0xA946, 0x11D0, { 0xA5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // ASX v.2 file Parser + static const GUID guid3 = + { 0xD51BD5AE, 0x7548, 0x11CF, { 0xA5, 0x20, 0x00, 0x80, 0xC7, 0x7E, 0xF5, 0x8A } }; // XML Playlist + + if (pmt2->subtype == guid1 || pmt2->subtype == guid2 || pmt2->subtype == guid3) { + RemoveFilter(pBF); + pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_NetShowSource); + hr = AddSourceFilter(pFGF, lpcwstrFileName, lpcwstrFilterName, ppBF); + delete pFGF; + return hr; + } + } + EndEnumMediaTypes(pmt2); + } + + *ppBF = pBF.Detach(); + + m_pUnks.AddTailList(&pUnks); + + return S_OK; +} + +// IFilterGraph + +STDMETHODIMP CFGManager::AddFilter(IBaseFilter* pFilter, LPCWSTR pName) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (FAILED(hr = CComQIPtr(m_pUnkInner)->AddFilter(pFilter, pName))) { + return hr; + } + + // TODO + hr = pFilter->JoinFilterGraph(nullptr, nullptr); + hr = pFilter->JoinFilterGraph(this, pName); + + return hr; +} + +STDMETHODIMP CFGManager::RemoveFilter(IBaseFilter* pFilter) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->RemoveFilter(pFilter); +} + +STDMETHODIMP CFGManager::EnumFilters(IEnumFilters** ppEnum) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + // Not locking here fixes a deadlock involving ReClock + //CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->EnumFilters(ppEnum); +} + +STDMETHODIMP CFGManager::FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->FindFilterByName(pName, ppFilter); +} + +STDMETHODIMP CFGManager::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + CComPtr pBF = GetFilterFromPin(pPinIn); + CLSID clsid = GetCLSID(pBF); + + // TODO: GetUpStreamFilter goes up on the first input pin only + for (CComPtr pBFUS = GetFilterFromPin(pPinOut); pBFUS; pBFUS = GetUpStreamFilter(pBFUS)) { + if (pBFUS == pBF) { + return VFW_E_CIRCULAR_GRAPH; + } + if (clsid != CLSID_Proxy && GetCLSID(pBFUS) == clsid) { + return VFW_E_CANNOT_CONNECT; + } + } + + return CComQIPtr(m_pUnkInner)->ConnectDirect(pPinOut, pPinIn, pmt); +} + +STDMETHODIMP CFGManager::Reconnect(IPin* ppin) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->Reconnect(ppin); +} + +STDMETHODIMP CFGManager::Disconnect(IPin* ppin) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->Disconnect(ppin); +} + +STDMETHODIMP CFGManager::SetDefaultSyncSource() +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->SetDefaultSyncSource(); +} + +// IGraphBuilder + +STDMETHODIMP CFGManager::Connect(IPin* pPinOut, IPin* pPinIn) +{ + return Connect(pPinOut, pPinIn, true); +} + +HRESULT CFGManager::Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPinOut, E_POINTER); + + if (m_aborted) { + return E_ABORT; + } + + HRESULT hr; + + if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT) + || pPinIn && S_OK != IsPinDirection(pPinIn, PINDIR_INPUT)) { + return VFW_E_INVALID_DIRECTION; + } + + if (S_OK == IsPinConnected(pPinOut) + || pPinIn && S_OK == IsPinConnected(pPinIn)) { + return VFW_E_ALREADY_CONNECTED; + } + + bool fDeadEnd = true; + + if (pPinIn) { + // 1. Try a direct connection between the filters, with no intermediate filters + + if (SUCCEEDED(hr = ConnectDirect(pPinOut, pPinIn, nullptr))) { + return hr; + } + } else { + // 1. Use IStreamBuilder + + if (CComQIPtr pSB = pPinOut) { + if (SUCCEEDED(hr = pSB->Render(pPinOut, this))) { + return hr; + } + + pSB->Backout(pPinOut, this); + } + } + + // 2. Try cached filters + + CComPtr pFilterPinIn = nullptr; + if (pPinIn) { + pFilterPinIn = GetFilterFromPin(pPinIn); + } + + if (CComQIPtr pGC = (IGraphBuilder2*)this) { + BeginEnumCachedFilters(pGC, pEF, pBF) { + if (pFilterPinIn && pFilterPinIn == pBF) { + continue; + } + + hr = pGC->RemoveFilterFromCache(pBF); + + // does RemoveFilterFromCache call AddFilter like AddFilterToCache calls RemoveFilter ? + + if (SUCCEEDED(hr = ConnectFilterDirect(pPinOut, pBF, nullptr))) { + if (!IsStreamEnd(pBF)) { + fDeadEnd = false; + } + + if (SUCCEEDED(hr = ConnectFilter(pBF, pPinIn))) { + return hr; + } + } + + hr = pGC->AddFilterToCache(pBF); + } + EndEnumCachedFilters; + } + + // 3. Try filters in the graph + + CComPtr pFilterPinOut = GetFilterFromPin(pPinOut); + CLSID clsid_pinout = GetCLSID(pFilterPinOut); + + { + CInterfaceList pBFs; + + BeginEnumFilters(this, pEF, pBF) { + if (pFilterPinIn && pFilterPinIn == pBF || pFilterPinOut == pBF) { + continue; + } + + // HACK: ffdshow - audio capture filter + if (clsid_pinout == GUIDFromCString(_T("{04FE9017-F873-410E-871E-AB91661A4EF7}")) + && GetCLSID(pBF) == GUIDFromCString(_T("{E30629D2-27E5-11CE-875D-00608CB78066}"))) { + continue; + } + + pBFs.AddTail(pBF); + } + EndEnumFilters; + + POSITION pos = pBFs.GetHeadPosition(); + while (pos) { + IBaseFilter* pBF = pBFs.GetNext(pos); + + if (SUCCEEDED(hr = ConnectFilterDirect(pPinOut, pBF, nullptr))) { + if (!IsStreamEnd(pBF)) { + fDeadEnd = false; + } + + if (SUCCEEDED(hr = ConnectFilter(pBF, pPinIn))) { + return hr; + } + } + + EXECUTE_ASSERT(SUCCEEDED(Disconnect(pPinOut))); + } + } + + // 4. Look up filters in the registry + + { + // workaround for Cyberlink video decoder, which can have an unwanted output pin + if (clsid_pinout == GUIDFromCString(_T("{F8FC6C1F-DE81-41A8-90FF-0316FDD439FD}"))) { + CPinInfo infoPinOut; + if (SUCCEEDED(pPinOut->QueryPinInfo(&infoPinOut))) { + if (CString(infoPinOut.achName) == L"~Encode Out") { + // ignore this pin + return S_OK; + } + } + } + + CFGFilterList fl; + + CAtlArray types; + ExtractMediaTypes(pPinOut, types); + + POSITION pos = m_transform.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_transform.GetNext(pos); + if (pFGF->GetMerit() < MERIT64_DO_USE || pFGF->CheckTypes(types, false)) { + fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true), false); + } + } + + pos = m_override.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_override.GetNext(pos); + if (pFGF->GetMerit() < MERIT64_DO_USE || pFGF->CheckTypes(types, false)) { + fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true), false); + } + } + + CComPtr pEM; + if (!types.IsEmpty() + && SUCCEEDED(m_pFM->EnumMatchingFilters( + &pEM, 0, FALSE, MERIT_DO_NOT_USE + 1, + TRUE, (DWORD)types.GetCount() / 2, types.GetData(), nullptr, nullptr, FALSE, + !!pPinIn, 0, nullptr, nullptr, nullptr))) { + for (CComPtr pMoniker; S_OK == pEM->Next(1, &pMoniker, nullptr); pMoniker = nullptr) { + CFGFilterRegistry* pFGF = DEBUG_NEW CFGFilterRegistry(pMoniker); + fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true)); + } + } + + // let's check whether the madVR allocator presenter is in our list + // it should be if madVR is selected as the video renderer + CFGFilter* pMadVRAllocatorPresenter = nullptr; + pos = fl.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = fl.GetNext(pos); + if (pFGF->GetCLSID() == CLSID_madVRAllocatorPresenter) { + // found it! + pMadVRAllocatorPresenter = pFGF; + break; + } + } + + pos = fl.GetHeadPosition(); + while (pos) { + if (m_aborted) { + return E_ABORT; + } + + CFGFilter* pFGF = fl.GetNext(pos); + + // avoid pointless connection attempts + CLSID candidate = pFGF->GetCLSID(); + if (clsid_pinout == candidate) { + continue; + } else if (candidate == CLSID_VSFilter) { + if (clsid_pinout == GUID_LAVAudio || clsid_pinout == __uuidof(CAudioSwitcherFilter)) { + continue; + } + } else if (candidate == CLSID_RDPDShowRedirectionFilter) { + if (clsid_pinout == __uuidof(CAudioSwitcherFilter)) { + continue; + } + } else if (candidate == GUID_LAVAudio) { + if (clsid_pinout == __uuidof(CAudioSwitcherFilter)) { + continue; + } + } + +#if 0 + // Checks if madVR is already in the graph to avoid two instances at the same time + CComPtr pBFmadVR; + FindFilterByName(_T("madVR"), &pBFmadVR); + if (pBFmadVR && (pFGF->GetName() == _T("madVR"))) { + continue; + } +#endif + + if (pMadVRAllocatorPresenter && (pFGF->GetCLSID() == CLSID_madVR)) { + // the pure madVR filter was selected (without the allocator presenter) + // subtitles, OSD etc don't work correctly without the allocator presenter + // so we prefer the allocator presenter over the pure filter + pFGF = pMadVRAllocatorPresenter; + } + + CString filtername = pFGF->GetName().GetString(); + if (filtername.IsEmpty()) { + filtername = CLSIDToString(candidate); + } + TRACE(_T("FGM: Connecting '%s'\n"), filtername); + + CComPtr pBF; + CInterfaceList pUnks; + if (FAILED(pFGF->Create(&pBF, pUnks))) { + TRACE(_T("FGM: Filter creation failed\n")); + if (!m_bIsCapture) { + // Check if selected video renderer fails to load + CLSID filter = pFGF->GetCLSID(); + if (filter == CLSID_MPCVRAllocatorPresenter || filter == CLSID_madVRAllocatorPresenter || filter == CLSID_DXRAllocatorPresenter) { + if (IDYES == AfxMessageBox(_T("The selected video renderer has failed to load.\n\nThe player will now fallback to using a basic video renderer, which has reduced performance and quality. Subtitles may also fail to load.\n\nDo you want to change settings to use the default video renderer (EVR-CP/VMR9)? (player restart required)"), MB_ICONEXCLAMATION | MB_YESNO, 0)) { + CAppSettings& s = AfxGetAppSettings(); + s.iDSVideoRendererType = IsCLSIDRegistered(CLSID_EnhancedVideoRenderer) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS; + } + } else if (filter == CLSID_EVRAllocatorPresenter || filter == CLSID_VMR9AllocatorPresenter) { + if (IDYES == AfxMessageBox(_T("The selected video renderer has failed to load.\n\nThis problem is often caused by a bug in the graphics driver. Or you may be using a generic driver which has limited capabilities. It is recommended to update the graphics driver to solve this problem. A proper driver is required for optimal video playback performance and quality.\n\nThe player will now fallback to using a basic video renderer, which has reduced performance and quality. Subtitles may also fail to load.\n\nYou can select a different renderer here:\nOptions > playback > Output\n\nDo you want to use the basic video renderer by default?"), MB_ICONEXCLAMATION | MB_YESNO, 0)) { + CAppSettings& s = AfxGetAppSettings(); + s.iDSVideoRendererType = IsCLSIDRegistered(CLSID_EnhancedVideoRenderer) ? VIDRNDT_DS_EVR : VIDRNDT_DS_VMR9WINDOWED; + s.SetSubtitleRenderer(CAppSettings::SubtitleRenderer::VS_FILTER); + // Disable DXVA in internal video decoder + CMPlayerCApp* pApp = AfxGetMyApp(); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), 0); + } + } + } + continue; + } + + if (FAILED(hr = AddFilter(pBF, pFGF->GetName()))) { + TRACE(_T("FGM: Adding the filter failed\n")); + pUnks.RemoveAll(); + pBF.Release(); + continue; + } + + hr = ConnectFilterDirect(pPinOut, pBF, nullptr); + /* + if (FAILED(hr)) + { + if (types.GetCount() >= 2 && types[0] == MEDIATYPE_Stream && types[1] != GUID_NULL) + { + CMediaType mt; + + mt.majortype = types[0]; + mt.subtype = types[1]; + mt.formattype = FORMAT_None; + if (FAILED(hr)) hr = ConnectFilterDirect(pPinOut, pBF, &mt); + + mt.formattype = GUID_NULL; + if (FAILED(hr)) hr = ConnectFilterDirect(pPinOut, pBF, &mt); + } + } + */ + if (SUCCEEDED(hr)) { + TRACE(_T("FGM: Filter connected to %s\n"), CLSIDToString(clsid_pinout)); + if (!IsStreamEnd(pBF)) { + fDeadEnd = false; + } + + if (m_aborted) { + return E_ABORT; + } + + if (bContinueRender) { + hr = ConnectFilter(pBF, pPinIn); + } + + if (SUCCEEDED(hr)) { + m_pUnks.AddTailList(&pUnks); + + // maybe the application should do this... + + POSITION posInterface = pUnks.GetHeadPosition(); + while (posInterface) { + if (CComQIPtr pMPC = pUnks.GetNext(posInterface)) { + pMPC->SetAspectRatioMode(AM_ARMODE_STRETCHED); + } + } + + if (CComQIPtr pARC = pBF) { + pARC->SetAspectRatioMode(VMR_ARMODE_NONE); + } + + if (CComQIPtr pARC = pBF) { + pARC->SetAspectRatioMode(VMR_ARMODE_NONE); + } + + if (CComQIPtr pMC = pBF) { + m_pUnks.AddTail(pMC); + } + + if (CComQIPtr pMB = pBF) { + m_pUnks.AddTail(pMB); + } + + if (CComQIPtr pMFVMB = pBF) { + m_pUnks.AddTail(pMFVMB); + } + + if (CComQIPtr pMFGS = pBF) { + CComPtr pMFVDC; + CComPtr pMFMB; + CComPtr pMFVP; + + if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVDC)))) { + m_pUnks.AddTail(pMFVDC); + } + + if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&pMFMB)))) { + m_pUnks.AddTail(pMFMB); + } + + if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&pMFVP)))) { + m_pUnks.AddTail(pMFVP); + } + } + + return hr; + } + } + + TRACE(_T("FGM: Failed to connect to %s\n"), CLSIDToString(clsid_pinout)); + CPinInfo infoPinOut; + if (SUCCEEDED(pPinOut->QueryPinInfo(&infoPinOut))) { + TRACE(_T("FGM: Output pin name: %s\n"), infoPinOut.achName); + } + EXECUTE_ASSERT(SUCCEEDED(RemoveFilter(pBF))); + pUnks.RemoveAll(); + pBF.Release(); + } + } + + if (fDeadEnd) { + CAutoPtr psde(DEBUG_NEW CStreamDeadEnd()); + psde->AddTailList(&m_streampath); + int skip = 0; + BeginEnumMediaTypes(pPinOut, pEM, pmt) { + if (pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_NULL) { + skip++; + } + psde->mts.AddTail(CMediaType(*pmt)); + } + EndEnumMediaTypes(pmt); + if (skip < (int)psde->mts.GetCount()) { + m_deadends.Add(psde); + } + } + + return pPinIn ? VFW_E_CANNOT_CONNECT : VFW_E_CANNOT_RENDER; +} + +STDMETHODIMP CFGManager::Render(IPin* pPinOut) +{ + CAutoLock cAutoLock(this); + + return RenderEx(pPinOut, 0, nullptr); +} + +HRESULT CFGManager::RenderRFSFileEntry(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList, CStringW entryRFS){ + this->m_entryRFS = entryRFS; + return RenderFile(lpcwstrFileName, lpcwstrPlayList); +} + +CUnknown* WINAPI CFGManager::GetMpcAudioRendererInstance(LPUNKNOWN lpunk, HRESULT* phr) { + return CreateInstance(lpunk, phr); +} + +STDMETHODIMP CFGManager::RenderFile(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList) +{ + TRACE(_T("CFGManager::RenderFile on thread: %lu\n"), GetCurrentThreadId()); + CAutoLock cAutoLock(this); + + m_streampath.RemoveAll(); + m_deadends.RemoveAll(); + + HRESULT hr; + HRESULT hrRFS = S_OK; + + CFGFilterList fl; + if (FAILED(hr = EnumSourceFilters(lpcwstrFileName, fl))) { + return hr; + } + + CAutoPtrArray deadends; + + hr = VFW_E_CANNOT_RENDER; + + POSITION pos = fl.GetHeadPosition(); + while (pos) { + CComPtr pBF; + CFGFilter* pFG = fl.GetNext(pos); + + if (SUCCEEDED(hr = AddSourceFilter(pFG, lpcwstrFileName, pFG->GetName(), &pBF))) { + m_streampath.RemoveAll(); + m_deadends.RemoveAll(); + + if (m_ignoreVideo) { + CFGFilter* pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_COMP), MERIT64_ABOVE_DSHOW + 3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } + + if (SUCCEEDED(hr = ConnectFilter(pBF, nullptr))) { + // insert null video renderer on next RenderFile call which is used for audio dubs + m_ignoreVideo = True; + TRACE(_T("CFGManager::RenderFile complete\n")); + return hr; + } + + NukeDownstream(pBF); + RemoveFilter(pBF); + + deadends.Append(m_deadends); + + if (hr == E_ABORT) { + break; + } + } else if (pFG->GetCLSID() == __uuidof(CRARFileSource) && HRESULT_FACILITY(hr) == FACILITY_ITF) { + hrRFS = hr; + } + } + + m_deadends.Copy(deadends); + + // If RFS was part of the graph, return its error code instead of the last error code. + // TODO: Improve filter error reporting to graph manager. + return hrRFS != S_OK ? hrRFS : hr; +} + +STDMETHODIMP CFGManager::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + CFGFilterList fl; + + if (FAILED(hr = EnumSourceFilters(lpcwstrFileName, fl))) { + return hr; + } + + POSITION pos = fl.GetHeadPosition(); + while (pos) { + if (SUCCEEDED(hr = AddSourceFilter(fl.GetNext(pos), lpcwstrFileName, lpcwstrFilterName, ppFilter))) { + return hr; + } + } + + return VFW_E_CANNOT_LOAD_SOURCE_FILTER; +} + +STDMETHODIMP CFGManager::SetLogFile(DWORD_PTR hFile) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->SetLogFile(hFile); +} + +STDMETHODIMP CFGManager::Abort() +{ + if (!m_pUnkInner) { + ASSERT(false); + return E_UNEXPECTED; + } + + // When a filter (renderer) in the child thread (the graph thread) calls CreateWindow() + // then that call triggers an implicit call of SendMessage to the main window. + // This is a blocking call, meaning main thread must be able to process that window message. + // So we can not request a lock here when called from main thread since that would result in a deadlock. + //CAutoLock cAutoLock(this); + + m_aborted = true; + + return CComQIPtr(m_pUnkInner)->Abort(); +} + +STDMETHODIMP CFGManager::ShouldOperationContinue() +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->ShouldOperationContinue(); +} + +// IFilterGraph2 + +STDMETHODIMP CFGManager::AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->AddSourceFilterForMoniker(pMoniker, pCtx, lpcwstrFilterName, ppFilter); +} + +STDMETHODIMP CFGManager::ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->ReconnectEx(ppin, pmt); +} + +STDMETHODIMP CFGManager::RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext) +{ + CAutoLock cAutoLock(this); + + m_streampath.RemoveAll(); + m_deadends.RemoveAll(); + + if (!pPinOut || dwFlags > AM_RENDEREX_RENDERTOEXISTINGRENDERERS || pvContext) { + return E_INVALIDARG; + } + + if (dwFlags & AM_RENDEREX_RENDERTOEXISTINGRENDERERS) { + CInterfaceList pBFs; + + BeginEnumFilters(this, pEF, pBF) { + if (CComQIPtr pAMMF = pBF) { + if (pAMMF->GetMiscFlags() & AM_FILTER_MISC_FLAGS_IS_RENDERER) { + pBFs.AddTail(pBF); + } + } else { + BeginEnumPins(pBF, pEP, pPin) { + CComPtr pPinIn; + DWORD size = 1; + if (SUCCEEDED(pPin->QueryInternalConnections(&pPinIn, &size)) && size == 0) { + pBFs.AddTail(pBF); + break; + } + } + EndEnumPins; + } + } + EndEnumFilters; + + while (!pBFs.IsEmpty()) { + HRESULT hr; + if (SUCCEEDED(hr = ConnectFilter(pPinOut, pBFs.RemoveHead()))) { + return hr; + } + } + + return VFW_E_CANNOT_RENDER; + } + + return Connect(pPinOut, (IPin*)nullptr); +} + +// IGraphBuilder2 + +STDMETHODIMP CFGManager::IsPinDirection(IPin* pPin, PIN_DIRECTION dir1) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPin, E_POINTER); + + PIN_DIRECTION dir2; + if (FAILED(pPin->QueryDirection(&dir2))) { + return E_FAIL; + } + + return dir1 == dir2 ? S_OK : S_FALSE; +} + +STDMETHODIMP CFGManager::IsPinConnected(IPin* pPin) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPin, E_POINTER); + + CComPtr pPinTo; + return SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo ? S_OK : S_FALSE; +} + +STDMETHODIMP CFGManager::ConnectFilter(IBaseFilter* pBF, IPin* pPinIn) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pBF, E_POINTER); + + if (m_aborted) { + return E_ABORT; + } + + if (pPinIn && S_OK != IsPinDirection(pPinIn, PINDIR_INPUT)) { + return VFW_E_INVALID_DIRECTION; + } + + int nTotal = 0, nRendered = 0; + + const CAppSettings& s = AfxGetAppSettings(); + + BeginEnumPins(pBF, pEP, pPin) { + if (S_OK == IsPinDirection(pPin, PINDIR_OUTPUT) + && S_OK != IsPinConnected(pPin) + && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { + + CLSID clsid; + pBF->GetClassID(&clsid); + // Disable DVD subtitle mixing in EVR (CP) and Sync Renderer for Microsoft DTV-DVD Video Decoder, it corrupts DVD playback. + if (clsid == CLSID_CMPEG2VidDecoderDS) { + if (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { + if (GetPinName(pPin)[0] == '~') { + continue; + } + } + } + // No multiple pin for Internal MPEG2 Software Decoder, NVIDIA PureVideo Decoder, Sonic Cinemaster VideoDecoder + else if (clsid == CLSID_CMpeg2DecFilter + || clsid == CLSID_NvidiaVideoDecoder + || clsid == CLSID_SonicCinemasterVideoDecoder) { + if (GetPinName(pPin)[0] == '~') { + continue; + } + //TODO: enable multiple pins for the renderer, if the video decoder supports DXVA + } + + m_streampath.Append(pBF, pPin); + + HRESULT hr = Connect(pPin, pPinIn); + + if (SUCCEEDED(hr)) { + for (int i = (int)m_deadends.GetCount() - 1; i >= 0; i--) { + if (m_deadends.GetAt(i)->Compare(m_streampath)) { + m_deadends.RemoveAt(i); + } + } + nRendered++; + } + + nTotal++; + + m_streampath.RemoveTail(); + + if (SUCCEEDED(hr) && pPinIn) { + return S_OK; + } + } + } + EndEnumPins; + + return + nRendered == nTotal ? (nRendered > 0 ? S_OK : S_FALSE) : + nRendered > 0 ? VFW_S_PARTIAL_RENDER : + VFW_E_CANNOT_RENDER; +} + +STDMETHODIMP CFGManager::ConnectFilter(IPin* pPinOut, IBaseFilter* pBF) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPinOut, E_POINTER); + CheckPointer(pBF, E_POINTER); + + if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT)) { + return VFW_E_INVALID_DIRECTION; + } + + const CAppSettings& s = AfxGetAppSettings(); + + BeginEnumPins(pBF, pEP, pPin) { + if (S_OK == IsPinDirection(pPin, PINDIR_INPUT) + && S_OK != IsPinConnected(pPin) + && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { + HRESULT hr = Connect(pPinOut, pPin); + if (SUCCEEDED(hr)) { + return hr; + } + } + } + EndEnumPins; + + return VFW_E_CANNOT_CONNECT; +} + +STDMETHODIMP CFGManager::ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPinOut, E_POINTER); + CheckPointer(pBF, E_POINTER); + + if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT)) { + return VFW_E_INVALID_DIRECTION; + } + + const CAppSettings& s = AfxGetAppSettings(); + + BeginEnumPins(pBF, pEP, pPin) { + if (S_OK == IsPinDirection(pPin, PINDIR_INPUT) + && S_OK != IsPinConnected(pPin) + && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { + HRESULT hr = ConnectDirect(pPinOut, pPin, pmt); + if (SUCCEEDED(hr)) { + return hr; + } + } + } + EndEnumPins; + + return VFW_E_CANNOT_CONNECT; +} + +STDMETHODIMP CFGManager::NukeDownstream(IUnknown* pUnk) +{ + CAutoLock cAutoLock(this); + + if (CComQIPtr pBF = pUnk) { + BeginEnumPins(pBF, pEP, pPin) { + NukeDownstream(pPin); + } + EndEnumPins; + } else if (CComQIPtr pPin = pUnk) { + CComPtr pPinTo; + if (S_OK == IsPinDirection(pPin, PINDIR_OUTPUT) + && SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { + if (pBF = GetFilterFromPin(pPinTo)) { + if (GetCLSID(pBF) == CLSID_EnhancedVideoRenderer) { + // GetFilterFromPin() returns pointer to the Base EVR, + // but we need to remove Outer EVR from the graph. + CComPtr pOuterEVR; + if (SUCCEEDED(pBF->QueryInterface(&pOuterEVR))) { + pBF = pOuterEVR; + } + } + NukeDownstream(pBF); + Disconnect(pPinTo); + Disconnect(pPin); + RemoveFilter(pBF); + } + } + } else { + return E_INVALIDARG; + } + + return S_OK; +} + +STDMETHODIMP CFGManager::FindInterface(REFIID iid, void** ppv, BOOL bRemove) +{ + CAutoLock cAutoLock(this); + + CheckPointer(ppv, E_POINTER); + + for (POSITION pos = m_pUnks.GetHeadPosition(); pos; m_pUnks.GetNext(pos)) { + if (SUCCEEDED(m_pUnks.GetAt(pos)->QueryInterface(iid, ppv))) { + if (bRemove) { + m_pUnks.RemoveAt(pos); + } + return S_OK; + } + } + + return E_NOINTERFACE; +} + +STDMETHODIMP CFGManager::AddToROT() +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (m_dwRegister) { + return S_FALSE; + } + + CComPtr pROT; + CComPtr pMoniker; + WCHAR wsz[256]; + swprintf_s(wsz, _countof(wsz), L"FilterGraph %08p pid %08x (MPC-HC)", this, GetCurrentProcessId()); + if (SUCCEEDED(hr = GetRunningObjectTable(0, &pROT)) + && SUCCEEDED(hr = CreateItemMoniker(L"!", wsz, &pMoniker))) { + hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, (IGraphBuilder2*)this, pMoniker, &m_dwRegister); + } + + return hr; +} + +STDMETHODIMP CFGManager::RemoveFromROT() +{ + if (!m_dwRegister) { + return S_FALSE; + } + + //CAutoLock cAutoLock(this); + + HRESULT hr; + CComPtr pROT; + if (SUCCEEDED(hr = GetRunningObjectTable(0, &pROT)) + && SUCCEEDED(hr = pROT->Revoke(m_dwRegister))) { + m_dwRegister = 0; + } + + return hr; +} + +// IGraphBuilderDeadEnd + +STDMETHODIMP_(size_t) CFGManager::GetCount() +{ + CAutoLock cAutoLock(this); + + return m_deadends.GetCount(); +} + +STDMETHODIMP CFGManager::GetDeadEnd(int iIndex, CAtlList& path, CAtlList& mts) +{ + CAutoLock cAutoLock(this); + + if (iIndex < 0 || iIndex >= (int)m_deadends.GetCount()) { + return E_FAIL; + } + + path.RemoveAll(); + mts.RemoveAll(); + + POSITION pos = m_deadends[iIndex]->GetHeadPosition(); + while (pos) { + const path_t& p = m_deadends[iIndex]->GetNext(pos); + + CStringW str; + str.Format(L"%s::%s", p.filter.GetString(), p.pin.GetString()); + path.AddTail(str); + } + + mts.AddTailList(&m_deadends[iIndex]->mts); + + return S_OK; +} + +// +// Custom Filter Injection +// + +void CFGManagerCustom::InsertLAVSplitterSource(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* src = s.SrcFilters; + + CFGFilterLAV* filter; + if (IsPreview) { + filter = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER_SOURCE); + } else { + filter = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER_SOURCE); + } + CAutoPtr pFGLAVSplitterSource(static_cast (filter)); + +#if INTERNAL_SOURCEFILTER_AVI + if (src[SRC_AVI] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,41564920")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,41564958")); + pFGLAVSplitterSource->AddEnabledFormat("avi"); + } +#endif + +#if INTERNAL_SOURCEFILTER_AVS + if (src[SRC_AVS] || IsPreview) { + pFGLAVSplitterSource->m_extensions.AddTail(_T(".avs")); + pFGLAVSplitterSource->AddEnabledFormat("avisynth"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MP4 + if (src[SRC_MP4] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,66747970")); // ftyp + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,6d6f6f76")); // moov + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,6d646174")); // mdat + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,736b6970")); // skip + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,12,ffffffff00000000ffffffff,77696465027fe3706d646174")); // wide ? mdat + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("3,3,,000001")); // raw mpeg4 video + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mov")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mp4")); + pFGLAVSplitterSource->AddEnabledFormat("mp4"); + } +#endif + +#if INTERNAL_SOURCEFILTER_FLV + if (src[SRC_FLV] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,464C5601")); // FLV (v1) + pFGLAVSplitterSource->AddEnabledFormat("flv"); + } +#endif + +#if INTERNAL_SOURCEFILTER_GIF + if (src[SRC_GIF] && !IsPreview) { + pFGLAVSplitterSource->m_extensions.AddTail(_T(".gif")); + pFGLAVSplitterSource->AddEnabledFormat("gif"); + } +#endif + +#if INTERNAL_SOURCEFILTER_ASF + if (src[SRC_ASF] || IsPreview) { + pFGLAVSplitterSource->m_extensions.AddTail(_T(".wmv")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".asf")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dvr-ms")); + pFGLAVSplitterSource->AddEnabledFormat("asf"); + } +#endif + +#if INTERNAL_SOURCEFILTER_WTV + if (src[SRC_WTV] || IsPreview) { + pFGLAVSplitterSource->m_extensions.AddTail(_T(".wtv")); + pFGLAVSplitterSource->AddEnabledFormat("wtv"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MATROSKA + if (src[SRC_MATROSKA] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,1A45DFA3")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mkv")); + pFGLAVSplitterSource->AddEnabledFormat("matroska"); + } +#endif + +#if INTERNAL_SOURCEFILTER_REALMEDIA + if (src[SRC_REALMEDIA] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,2E524D46")); + pFGLAVSplitterSource->AddEnabledFormat("rm"); + } +#endif + +#if INTERNAL_SOURCEFILTER_FLIC + if (src[SRC_FLIC] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,2,,11AF")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,2,,12AF")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".fli")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".flc")); + pFGLAVSplitterSource->AddEnabledFormat("flic"); + } +#endif + +#if INTERNAL_SOURCEFILTER_FLAC + if (src[SRC_FLAC] && !IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,664C6143")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".flac")); + pFGLAVSplitterSource->AddEnabledFormat("flac"); + } +#endif + +#if INTERNAL_SOURCEFILTER_OGG + if (src[SRC_OGG] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4F676753")); + pFGLAVSplitterSource->AddEnabledFormat("ogg"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MPEG + if (src[SRC_MPEG] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,16,FFFFFFFFF100010001800001FFFFFFFF,000001BA2100010001800001000001BB")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,5,FFFFFFFFC0,000001BA40")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,54467263,1660,1,,47")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,8,fffffc00ffe00000,4156000055000000")); + pFGLAVSplitterSource->AddEnabledFormat("mpeg"); + pFGLAVSplitterSource->AddEnabledFormat("mpegraw"); + } + if (src[SRC_MPEGTS] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,1,,47,188,1,,47,376,1,,47")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,1,,47,196,1,,47,388,1,,47")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".ts")); // for some broken .ts + pFGLAVSplitterSource->AddEnabledFormat("mpegts"); + } + if (src[SRC_MPEG] || src[SRC_MPEGTS] || IsPreview) { + // for Blu-ray playback + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,494E4458")); // INDX (index.bdmv) + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4D4F424A")); // MOBJ (MovieObject.bdmv) + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4D504C53")); // MPLS + } +#endif + +#if INTERNAL_SOURCEFILTER_AC3 + if (src[SRC_AC3] && !IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,2,,0B77")); // AC3, E-AC3 + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,F8726FBB")); // MLP + pFGLAVSplitterSource->m_extensions.AddTail(_T(".ac3")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".eac3")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mlp")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".truehd")); + pFGLAVSplitterSource->AddEnabledFormat("ac3"); + pFGLAVSplitterSource->AddEnabledFormat("eac3"); + pFGLAVSplitterSource->AddEnabledFormat("mlp"); + pFGLAVSplitterSource->AddEnabledFormat("truehd"); + } +#endif + +#if INTERNAL_SOURCEFILTER_DTS + if (src[SRC_DTS] && !IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,7FFE8001")); // DTS + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,fE7f0180")); // DTS LE + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,8,,57415645666D7420"));// RIFFxxxxWAVEfmt_ for DTSWAV + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dts")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dtshd")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dtsma")); + pFGLAVSplitterSource->AddEnabledFormat("dts"); + pFGLAVSplitterSource->AddEnabledFormat("dtshd"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MPEGAUDIO + if (src[SRC_MPA] && !IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,2,FFE0,FFE0")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,10,FFFFFF00000080808080,49443300000000000000")); + pFGLAVSplitterSource->AddEnabledFormat("mp3"); + } +#endif + +#if INTERNAL_SOURCEFILTER_HTTP + if (src[SRC_HTTP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("http")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("https")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("icyx")); + pFGLAVSplitterSource->AddEnabledFormat("http"); + pFGLAVSplitterSource->AddEnabledFormat("dash"); + pFGLAVSplitterSource->AddEnabledFormat("hls"); + } +#endif + +#if INTERNAL_SOURCEFILTER_RTSP + if (src[SRC_RTSP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtsp")); + // Add transport protocol specific RTSP URL handlers + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspu")); // UDP + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspm")); // UDP multicast + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspt")); // TCP + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtsph")); // HTTP + pFGLAVSplitterSource->AddEnabledFormat("rtsp"); + } +#endif + +#if INTERNAL_SOURCEFILTER_UDP + if (src[SRC_UDP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("udp")); + pFGLAVSplitterSource->AddEnabledFormat("udp"); + } +#endif + +#if INTERNAL_SOURCEFILTER_RTP + if (src[SRC_RTP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtp")); + pFGLAVSplitterSource->AddEnabledFormat("rtp"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MMS + if (src[SRC_MMS] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("mms")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("mmsh")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("mmst")); + pFGLAVSplitterSource->AddEnabledFormat("mms"); + } +#endif + +#if INTERNAL_SOURCEFILTER_RTMP + if (src[SRC_RTMP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtmp")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtmpt")); + pFGLAVSplitterSource->AddEnabledFormat("live_flv"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MISC + // ToDo: split into separate options + if (src[SRC_MISC] || IsPreview) { + // video + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dv")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dhav")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".m3u8")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".y4m")); + pFGLAVSplitterSource->AddEnabledFormat("dv"); + pFGLAVSplitterSource->AddEnabledFormat("dhav"); + pFGLAVSplitterSource->AddEnabledFormat("y4m"); + } + if (src[SRC_MISC] && !IsPreview) { + // raw video + pFGLAVSplitterSource->m_extensions.AddTail(_T(".264")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".265")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".h264")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".h265")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".av1")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".m4v")); + pFGLAVSplitterSource->AddEnabledFormat("av1"); + pFGLAVSplitterSource->AddEnabledFormat("m4v"); + pFGLAVSplitterSource->AddEnabledFormat("rawvideo"); + // audio + pFGLAVSplitterSource->m_extensions.AddTail(_T(".amr")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".ape")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mpc")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".w64")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".wav")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".wv")); + pFGLAVSplitterSource->AddEnabledFormat("amr"); + pFGLAVSplitterSource->AddEnabledFormat("ape"); + pFGLAVSplitterSource->AddEnabledFormat("mpc"); + pFGLAVSplitterSource->AddEnabledFormat("mpc8"); + pFGLAVSplitterSource->AddEnabledFormat("w64"); + pFGLAVSplitterSource->AddEnabledFormat("wav"); + pFGLAVSplitterSource->AddEnabledFormat("wv"); + } +#endif + + // Always register the pipe protocol to allow handling standard input + pFGLAVSplitterSource->m_protocols.AddTail(_T("pipe")); + + // Add LAV Source Filter if needed + if (!pFGLAVSplitterSource->m_extensions.IsEmpty() + || !pFGLAVSplitterSource->m_chkbytes.IsEmpty() + || !pFGLAVSplitterSource->m_protocols.IsEmpty()) { + m_source.AddTail(pFGLAVSplitterSource.Detach()); + } +} + +void CFGManagerCustom::InsertLAVSplitter(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* src = s.SrcFilters; + + CFGFilterLAV* filterHM, * filterLM; + if (IsPreview) { + filterHM = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER, MERIT64_ABOVE_DSHOW); + filterLM = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER, MERIT64_DO_USE, true); + } else { + filterHM = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER, MERIT64_ABOVE_DSHOW); + filterLM = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER, MERIT64_DO_USE, true); + } + CAutoPtr pFGLAVSplitter(static_cast(filterHM)); + CAutoPtr pFGLAVSplitterLM(static_cast(filterLM)); + +#if INTERNAL_SOURCEFILTER_MATROSKA + if (src[SRC_MATROSKA] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Matroska); + pFGLAVSplitter->AddEnabledFormat("matroska"); + } +#endif + +#if INTERNAL_SOURCEFILTER_REALMEDIA + if (src[SRC_REALMEDIA] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_RealMedia); + pFGLAVSplitter->AddEnabledFormat("rm"); + } +#endif + +#if INTERNAL_SOURCEFILTER_AVI + if (src[SRC_AVI] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Avi); + pFGLAVSplitter->AddEnabledFormat("avi"); + } +#endif + +#if INTERNAL_SOURCEFILTER_AVS + if (src[SRC_AVS] || IsPreview) { + pFGLAVSplitter->AddEnabledFormat("avisynth"); + } +#endif + +#if INTERNAL_SOURCEFILTER_OGG + if (src[SRC_OGG] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Ogg); + pFGLAVSplitter->AddEnabledFormat("ogg"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MPEG + if (src[SRC_MPEG] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1System); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PROGRAM); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PVA); + pFGLAVSplitter->AddEnabledFormat("mpeg"); + pFGLAVSplitter->AddEnabledFormat("mpegraw"); + } + if (src[SRC_MPEGTS] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_TRANSPORT); + pFGLAVSplitter->AddEnabledFormat("mpegts"); + } +#endif + +#if INTERNAL_SOURCEFILTER_AC3 + if (src[SRC_AC3] && !IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_AC3); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_TRUEHD); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_DDPLUS); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MLP); + pFGLAVSplitter->AddEnabledFormat("ac3"); + pFGLAVSplitter->AddEnabledFormat("eac3"); + } +#endif + +#if INTERNAL_SOURCEFILTER_DTS + if (src[SRC_DTS] && !IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DTS); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DTS_HD); + pFGLAVSplitter->AddEnabledFormat("dts"); + pFGLAVSplitter->AddEnabledFormat("dtshd"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MPEGAUDIO + if (src[SRC_MPA] && !IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio); + pFGLAVSplitter->AddEnabledFormat("mp3"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MP4 + if (src[SRC_MP4] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MP4); + pFGLAVSplitter->AddEnabledFormat("mp4"); + } +#endif + +#if INTERNAL_SOURCEFILTER_FLV + if (src[SRC_FLV] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_FLV); + pFGLAVSplitter->AddEnabledFormat("flv"); + } +#endif + +#if INTERNAL_SOURCEFILTER_ASF + if (src[SRC_ASF] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_ASF); + pFGLAVSplitter->AddEnabledFormat("asf"); + } +#endif + + // Add LAV Splitter if needed + if (!pFGLAVSplitter->GetTypes().IsEmpty()) { + m_transform.AddTail(pFGLAVSplitter.Detach()); + } + + if (!IsPreview && pFGLAVSplitterLM) { + // Add low merit LAV Splitter + pFGLAVSplitterLM->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_NULL); + pFGLAVSplitterLM->AddEnabledFormat("*"); + // Explicitly disable all common subtitles format + pFGLAVSplitterLM->AddDisabledFormat("aqtitle"); + pFGLAVSplitterLM->AddDisabledFormat("ass"); + pFGLAVSplitterLM->AddDisabledFormat("dvbsub"); + pFGLAVSplitterLM->AddDisabledFormat("dvbtxt"); + pFGLAVSplitterLM->AddDisabledFormat("jacosub"); + pFGLAVSplitterLM->AddDisabledFormat("lrc"); + pFGLAVSplitterLM->AddDisabledFormat("microdvd"); + pFGLAVSplitterLM->AddDisabledFormat("mpl2"); + pFGLAVSplitterLM->AddDisabledFormat("mpsub"); + pFGLAVSplitterLM->AddDisabledFormat("realtext"); + pFGLAVSplitterLM->AddDisabledFormat("sami"); + pFGLAVSplitterLM->AddDisabledFormat("srt"); + pFGLAVSplitterLM->AddDisabledFormat("stl"); + pFGLAVSplitterLM->AddDisabledFormat("subviewer"); + pFGLAVSplitterLM->AddDisabledFormat("subviewer1"); + pFGLAVSplitterLM->AddDisabledFormat("sup"); + pFGLAVSplitterLM->AddDisabledFormat("vobsub"); + pFGLAVSplitterLM->AddDisabledFormat("vplayer"); + pFGLAVSplitterLM->AddDisabledFormat("webvtt"); + m_transform.AddTail(pFGLAVSplitterLM.Detach()); + } +} + +void CFGManagerCustom::InsertOtherInternalSourcefilters(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* src = s.SrcFilters; + CFGFilter* pFGF; + +#if INTERNAL_SOURCEFILTER_RFS + if (src[SRC_RFS] || IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_chkbytes.AddTail(_T("0,7,,526172211A0700")); // rar4 signature + pFGF->m_chkbytes.AddTail(_T("0,8,,526172211A070100")); // rar5 signature + pFGF->m_extensions.AddTail(_T(".rar")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_CDDA + if (src[SRC_CDDA] && !IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_extensions.AddTail(_T(".cda")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_CDXA + if (src[SRC_CDXA] || IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,43445841")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_VTS + if (src[SRC_VTS] || IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_chkbytes.AddTail(_T("0,12,,445644564944454F2D565453")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_DSM + if (src[SRC_DSM] || IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_chkbytes.AddTail(_T("0,4,,44534D53")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_DSM + if (src[SRC_DSM]) { + pFGF = DEBUG_NEW CFGFilterInternal(DSMSplitterName, MERIT64_ABOVE_DSHOW); + } else { + pFGF = DEBUG_NEW CFGFilterInternal(LowMerit(DSMSplitterName), MERIT64_DO_USE); + } + pFGF->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DirectShowMedia); + pFGF->AddType(MEDIATYPE_Stream, GUID_NULL); + m_transform.AddTail(pFGF); +#endif +} + +void CFGManagerCustom::InsertLAVVideo(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* tra = s.TraFilters; + CFGFilter* pFGF; + + CAutoPtr pFGLAVVideo (IsPreview ? CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::VIDEO_DECODER, MERIT64_ABOVE_DSHOW) : CFGFilterLAV::CreateFilter(CFGFilterLAV::VIDEO_DECODER, MERIT64_ABOVE_DSHOW)); + CAutoPtr pFGLAVVideoLM(IsPreview ? CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::VIDEO_DECODER, MERIT64_DO_USE, true) : CFGFilterLAV::CreateFilter(CFGFilterLAV::VIDEO_DECODER, MERIT64_DO_USE, true)); + +#if INTERNAL_DECODER_MPEG1 + pFGF = IsPreview || tra[TRA_MPEG1] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Packet); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Payload); +#endif +#if INTERNAL_DECODER_FLV + pFGF = IsPreview || tra[TRA_FLV4] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLV1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_flv1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLV4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_flv4); +#endif +#if INTERNAL_DECODER_VP356 + pFGF = IsPreview || tra[TRA_VP356] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP30); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP31); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP40); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP50); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp50); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP60); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp60); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP61); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp61); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP62); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp62); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP6F); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp6f); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP6A); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp6a); +#endif +#if INTERNAL_DECODER_H264 + pFGF = IsPreview || tra[TRA_H264] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_X264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_x264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VSSH); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vssh); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DAVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_davc); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_PAVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_pavc); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_avc1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264_bis); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CCV1); +#endif +#if INTERNAL_DECODER_HEVC + pFGF = IsPreview || tra[TRA_HEVC] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HEVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HM10); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H265); +#endif +#if INTERNAL_DECODER_VVC + pFGF = IsPreview || tra[TRA_VVC] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VVC1); +#endif +#if INTERNAL_DECODER_AV1 + pFGF = IsPreview || tra[TRA_AV1] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AV01); +#endif +#if INTERNAL_DECODER_VC1 + pFGF = IsPreview || tra[TRA_VC1] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wvc1); +#endif +#if INTERNAL_DECODER_XVID + pFGF = IsPreview || tra[TRA_XVID] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_XVID); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_xvid); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_XVIX); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_xvix); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP4V); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp4v); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_M4S2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_m4s2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP4S); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp4s); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IV1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3iv1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IV2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3iv2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IVX); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3ivx); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_BLZ0); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_blz0); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DM4V); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dm4v); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DXGM); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dxgm); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_fmp4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HDX4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_hdx4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_LMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_lmp4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NDIG); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ndig); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_RMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_rmp4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_smp4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SEDG); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_sedg); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_UMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ump4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WV1F); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wv1f); +#endif +#if INTERNAL_DECODER_DIVX + pFGF = IsPreview || tra[TRA_DIVX] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIVX); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_divx); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DX50); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dx50); +#endif +#if INTERNAL_DECODER_WMV + pFGF = IsPreview || tra[TRA_WMV] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_2VMW); +#endif +#if INTERNAL_DECODER_MSMPEG4 + pFGF = IsPreview || tra[TRA_MSMPEG4] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DVX3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dvx3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP43); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp43); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_COL1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_col1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV5); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div5); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV6); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div6); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AP41); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap41); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mpg3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP42); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp42); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mpg4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP41); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp41); +#endif +#if INTERNAL_DECODER_SVQ + pFGF = IsPreview || tra[TRA_SVQ3] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SVQ3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SVQ1); +#endif +#if INTERNAL_DECODER_H263 + pFGF = IsPreview || tra[TRA_H263] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H263); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h263); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_S263); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_s263); +#endif +#if INTERNAL_DECODER_THEORA + pFGF = IsPreview || tra[TRA_THEORA] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_THEORA); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_theora); +#endif +#if INTERNAL_DECODER_AMVV + pFGF = IsPreview || tra[TRA_AMVV] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AMVV); +#endif +#if INTERNAL_DECODER_VP8 + pFGF = IsPreview || tra[TRA_VP8] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP80); +#endif +#if INTERNAL_DECODER_VP9 + pFGF = IsPreview || tra[TRA_VP9] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP90); +#endif +#if INTERNAL_DECODER_MJPEG + pFGF = IsPreview || tra[TRA_MJPEG] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPG); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_QTJpeg); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPA); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPB); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVRn); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_LJPG); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_JPGL); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJLS); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPA); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPB); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SP5X); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SP54); +#endif +#if INTERNAL_DECODER_INDEO + pFGF = IsPreview || tra[TRA_INDEO] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV31); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV32); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV41); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV50); +#endif +#if INTERNAL_DECODER_SCREEN + pFGF = IsPreview || tra[TRA_SCREEN] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_TSCC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_TSC2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VMNC); +#endif +#if INTERNAL_DECODER_FLIC + pFGF = IsPreview || tra[TRA_FLIC] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLIC); +#endif +#if INTERNAL_DECODER_MSVIDEO + pFGF = IsPreview || tra[TRA_MSVIDEO] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CRAM); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WHAM); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MSVC); +#endif +#if INTERNAL_DECODER_V210_V410 + pFGF = IsPreview || tra[TRA_V210_V410] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_v210); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_v410); +#endif +#if INTERNAL_DECODER_MPEG2 + pFGF = IsPreview || tra[TRA_MPEG2] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG2); +#endif +#if INTERNAL_DECODER_PRORES + pFGF = IsPreview || tra[TRA_PRORES] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apch); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apcn); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apcs); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apco); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap4h); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap4x); +#endif +#if INTERNAL_DECODER_DNXHD + pFGF = IsPreview || tra[TRA_DNXHD] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVdn); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVdh); +#endif +#if INTERNAL_DECODER_OTHERVIDEO + pFGF = IsPreview || tra[TRA_OTHERVIDEO] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CFHD); +#endif + + // Add LAV Video if needed + if (!pFGLAVVideo->GetTypes().IsEmpty()) { + m_transform.AddTail(pFGLAVVideo.Detach()); + } + + // Add low merit LAV video + pFGLAVVideoLM->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGLAVVideoLM.Detach()); +} + +void CFGManagerCustom::InsertLAVAudio() +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* tra = s.TraFilters; + CFGFilter* pFGF; + + CAutoPtr pFGLAVAudio(CFGFilterLAV::CreateFilter(CFGFilterLAV::AUDIO_DECODER, MERIT64_ABOVE_DSHOW)); + CAutoPtr pFGLAVAudioLM(CFGFilterLAV::CreateFilter(CFGFilterLAV::AUDIO_DECODER, MERIT64_DO_USE, true)); + +#if INTERNAL_DECODER_MPEGAUDIO + pFGF = tra[TRA_MPA] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MP3); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1AudioPayload); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Payload); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Packet); + + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG2_AUDIO); +#endif + +#if INTERNAL_DECODER_AMR + pFGF = tra[TRA_AMR] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_SAMR); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AMR); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_SAWB); +#endif + +#if INTERNAL_DECODER_LPCM + pFGF = tra[TRA_LPCM] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_HDMV_LPCM_AUDIO); +#endif + +#if INTERNAL_DECODER_AC3 + pFGF = tra[TRA_AC3] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WAVE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_TRUEHD); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_DDPLUS); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MLP); +#endif + +#if INTERNAL_DECODER_DTS + pFGF = tra[TRA_DTS] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DTS_HD); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WAVE_DTS); +#endif + +#if INTERNAL_DECODER_AAC + pFGF = tra[TRA_AAC] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_AAC); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_AAC); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AAC); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_LATM_AAC); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AAC_ADTS); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MP4A); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MP4A); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MP4A); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_mp4a); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_mp4a); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_mp4a); +#endif + +#if INTERNAL_DECODER_PS2AUDIO + pFGF = tra[TRA_PS2AUD] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_PS2_PCM); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_PS2_PCM); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PS2_PCM); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_PS2_ADPCM); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_PS2_ADPCM); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PS2_ADPCM); +#endif + +#if INTERNAL_DECODER_VORBIS + pFGF = tra[TRA_VORBIS] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_Vorbis2); +#endif + +#if INTERNAL_DECODER_FLAC + pFGF = tra[TRA_FLAC] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_FLAC_FRAMED); +#endif + +#if INTERNAL_DECODER_NELLYMOSER + pFGF = tra[TRA_NELLY] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NELLYMOSER); +#endif + +#if INTERNAL_DECODER_ALAC + pFGF = tra[TRA_ALAC] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ALAC); +#endif + +#if INTERNAL_DECODER_ALS + pFGF = tra[TRA_ALS] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ALS); +#endif + +#if INTERNAL_DECODER_OPUS + pFGF = tra[TRA_OPUS] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_OPUS); +#endif + +#if INTERNAL_DECODER_WMA + pFGF = tra[TRA_WMA] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MSAUDIO1); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO2); +#endif + +#if INTERNAL_DECODER_WMAPRO + pFGF = tra[TRA_WMAPRO] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO3); +#endif + +#if INTERNAL_DECODER_WMALL + pFGF = tra[TRA_WMALL] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO_LOSSLESS); +#endif + +#if INTERNAL_DECODER_PCM + pFGF = tra[TRA_PCM] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_NONE); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_RAW); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_TWOS); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_SOWT); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_IN24); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_IN32); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_FL32); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_FL64); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IEEE_FLOAT); // only for 64-bit float PCM + /* todo: this should not depend on PCM */ + #if INTERNAL_DECODER_ADPCM + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMA4); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ADPCM_SWF); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ADPCM_AMV); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMA_WAV); + #endif +#endif + +#if INTERNAL_DECODER_G726 + pFGF = tra[TRA_G726] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_G726); +#endif + +#if INTERNAL_DECODER_G729 + pFGF = tra[TRA_G729] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_G729); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_729A); +#endif + +#if INTERNAL_DECODER_OTHERAUDIO + pFGF = tra[TRA_OTHERAUDIO] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMC); +#endif + + // Add LAV Audio if needed + if (!pFGLAVAudio->GetTypes().IsEmpty()) { + m_transform.AddTail(pFGLAVAudio.Detach()); + } + + // Add low merit LAV Audio + pFGLAVAudioLM->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGLAVAudioLM.Detach()); +} + +void CFGManagerCustom::InsertBlockedFilters() +{ + // "Subtitle Mixer" makes an access violation around the + // 11-12th media type when enumerating them on its output. + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{00A95963-3BE5-48C0-AD9F-3356D67EA09D}")), MERIT64_DO_NOT_USE)); + + // DiracSplitter.ax is crashing MPC-HC when opening invalid files... + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{09E7F58E-71A1-419D-B0A0-E524AE1454A9}")), MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{5899CFB9-948F-4869-A999-5544ECB38BA5}")), MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{F78CF248-180E-4713-B107-B13F7B5C31E1}")), MERIT64_DO_NOT_USE)); + + // ISCR suxx + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}")), MERIT64_DO_NOT_USE)); + + // Samsung's "mpeg-4 demultiplexor" can even open matroska files, amazing... + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{99EC0C72-4D1B-411B-AB1F-D561EE049D94}")), MERIT64_DO_NOT_USE)); + + // LG Video Renderer (lgvid.ax) just crashes when trying to connect it + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{9F711C60-0668-11D0-94D4-0000C02BA972}")), MERIT64_DO_NOT_USE)); + + // palm demuxer crashes (even crashes graphedit when dropping an .ac3 onto it) + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{BE2CF8A7-08CE-4A2C-9A25-FD726A999196}")), MERIT64_DO_NOT_USE)); + + // mainconcept color space converter + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{272D77A0-A852-4851-ADA4-9091FEAD4C86}")), MERIT64_DO_NOT_USE)); + + // mainconcept mp4 demuxer + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{2A55FF12-1657-41D7-9D2D-A2CDC6978FF2}")), MERIT64_DO_NOT_USE)); + + // Accusoft PICVideo M-JPEG Codec + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{4C4CD9E1-F876-11D2-962F-00500471FDDC}")), MERIT64_DO_NOT_USE)); + + // SolveigMM MP4 Demultiplexer (smm_mp4demuxer.ax) + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{5F19B8FE-BA79-4183-B3CF-FEE4E8F801E4}")), MERIT64_DO_NOT_USE)); + + // Morgan's Stream Switcher (mmswitch.ax) + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_MorganStreamSwitcher, MERIT64_DO_NOT_USE)); + + if (AfxGetAppSettings().bBlockRDP) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_RDPDShowRedirectionFilter, MERIT64_DO_NOT_USE)); + } + + // DCDSPFilter (early versions crash mpc) + { + CRegKey key; + + TCHAR buff[256]; + ULONG len = sizeof(buff); + ZeroMemory(buff, sizeof(buff)); + + CString clsid = _T("{B38C58A0-1809-11D6-A458-EDAE78F1DF12}"); + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + clsid + _T("\\InprocServer32"), KEY_READ) + && ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len) + && FileVersionInfo::GetFileVersionNum(buff) < 0x0001000000030000ui64) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(clsid), MERIT64_DO_NOT_USE)); + } + } +} + +void CFGManagerCustom::InsertSubtitleFilters(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + CFGFilter* pFGF; + + // Null text renderer + pFGF = DEBUG_NEW CFGFilterInternal(L"NullTextRenderer", IsPreview ? MERIT64_ABOVE_DSHOW : MERIT64_DO_USE); + pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_ScriptCommand, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_Subtitle, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DVD_SUBPICTURE); + pFGF->AddType(MEDIATYPE_NULL, MEDIASUBTYPE_CVD_SUBPICTURE); + pFGF->AddType(MEDIATYPE_NULL, MEDIASUBTYPE_SVCD_SUBPICTURE); + m_transform.AddTail(pFGF); + + if (IsPreview) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + } else { + // Insert preferred subtitle renderer and block others + switch (s.GetSubtitleRenderer()) { + case CAppSettings::SubtitleRenderer::INTERNAL: + if (s.fBlockVSFilter) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); + } + if (s.fBlockVSFilter || IsCLSIDRegistered(CLSID_VSFilter)) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); + } + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + break; + case CAppSettings::SubtitleRenderer::VS_FILTER: + pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_ABOVE_DSHOW); + if (pFGF) { + pFGF->AddType(MEDIASUBTYPE_NULL, MEDIASUBTYPE_NULL); + m_override.AddTail(pFGF); + } + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + break; + case CAppSettings::SubtitleRenderer::XY_SUB_FILTER: + pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_ABOVE_DSHOW); + if (pFGF) { + pFGF->AddType(MEDIASUBTYPE_NULL, MEDIASUBTYPE_NULL); + m_override.AddTail(pFGF); + } + pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_ABOVE_DSHOW); + if (pFGF) { + pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_Subtitle, MEDIASUBTYPE_NULL); + m_override.AddTail(pFGF); + } + if (s.fBlockVSFilter) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); + } + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + break; + case CAppSettings::SubtitleRenderer::NONE: + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + break; + } + } +} + +void CFGManagerCustom::InsertBroadcomDecoder() +{ + CFGFilter* pFGF = DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{2DE1D17E-46B1-42A8-9AEC-E20E80D9B1A9}")), MERIT64_ABOVE_DSHOW); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_X264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_x264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VSSH); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vssh); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DAVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_davc); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_PAVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_pavc); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_avc1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264_bis); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CCV1); + + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wvc1); + + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO); + m_transform.AddHead(pFGF); +} + +// +// CFGManagerCustom +// + +CFGManagerCustom::CFGManagerCustom(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) + : CFGManager(pName, pUnk, hWnd, IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + + bool bOverrideBroadcom = false; + CFGFilter* pFGF; + m_source; + + const bool* src = s.SrcFilters; + const bool* tra = s.TraFilters; + + // Reset LAVFilters internal instances + CFGFilterLAV::ResetInternalInstances(); + + // Add internal filters + InsertLAVSplitterSource(IsPreview); + InsertLAVSplitter(IsPreview); + InsertOtherInternalSourcefilters(IsPreview); +#if HAS_VIDEO_DECODERS + InsertLAVVideo(IsPreview); +#endif +#if HAS_AUDIO_DECODERS + if (!IsPreview) { + InsertLAVAudio(); + } +#endif + InsertSubtitleFilters(IsPreview); + + // Blocked filters + InsertBlockedFilters(); + if (m_bIsPreview) { + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_RDPDShowRedirectionFilter, MERIT64_DO_NOT_USE)); + } + + // Overrides + WORD merit_low = 1; + POSITION pos = s.m_filters.GetTailPosition(); + while (pos) { + FilterOverride* fo = s.m_filters.GetPrev(pos); + + if (!fo->fDisabled && fo->name == _T("Broadcom Video Decoder")) { + bOverrideBroadcom = true; + } + if (fo->fDisabled || fo->type == FilterOverride::EXTERNAL && !PathUtils::Exists(MakeFullPath(fo->path))) { + continue; + } + + ULONGLONG merit = + fo->iLoadType == FilterOverride::BLOCK ? MERIT64_DO_NOT_USE : + fo->iLoadType == FilterOverride::PREFERRED ? (IsPreview ? MERIT64_DO_USE : MERIT64_ABOVE_DSHOW) : + MERIT64(fo->dwMerit); + + merit += merit_low++; + + pFGF = nullptr; + if (fo->type == FilterOverride::REGISTERED) { + pFGF = DEBUG_NEW CFGFilterRegistry(fo->dispname, merit); + } else if (fo->type == FilterOverride::EXTERNAL) { + pFGF = DEBUG_NEW CFGFilterFile(fo->clsid, fo->path, CStringW(fo->name), merit); + } + if (pFGF) { + pFGF->SetTypes(fo->guids); + m_override.AddTail(pFGF); + } + } + + /* Use Broadcom decoder (if installed) for VC-1, H.264 and MPEG-2 */ + if (!IsPreview && !bOverrideBroadcom) { + // ToDo: maybe remove support for this old filter? + InsertBroadcomDecoder(); + } +} + +STDMETHODIMP CFGManagerCustom::AddFilter(IBaseFilter* pBF, LPCWSTR pName) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (FAILED(hr = __super::AddFilter(pBF, pName))) { + return hr; + } + + CAppSettings& s = AfxGetAppSettings(); + + if (GetCLSID(pBF) == CLSID_DMOWrapperFilter) { + if (CComQIPtr pPB = pBF) { + CComVariant var(true); + pPB->Write(_T("_HIRESOUTPUT"), &var); + } + } + + if (CComQIPtr pASF = pBF) { + pASF->EnableDownSamplingTo441(s.fDownSampleTo441); + pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); + pASF->SetAudioTimeShift(s.fAudioTimeShift ? 10000i64 * s.iAudioTimeShift : 0); + pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); + } + + return hr; +} + +// +// CFGManagerPlayer +// + +CFGManagerPlayer::CFGManagerPlayer(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) + : CFGManagerCustom(pName, pUnk, hWnd, IsPreview) + , m_hWnd(hWnd) +{ + TRACE(_T("CFGManagerPlayer::CFGManagerPlayer on thread: %lu\n"), GetCurrentThreadId()); + CFGFilter* pFGF; + + const CAppSettings& s = AfxGetAppSettings(); + + /* value is chosen so that it is higher than standard renderers, but lower than important intermediate filters like VSFilter */ + UINT64 renderer_merit = MERIT64(0x800001) + 0x100; + + // Switchers + + if (s.fEnableAudioSwitcher && !m_bIsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(L"Audio Switcher", renderer_merit + 0x100); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } + + // Renderers + if (!m_bIsPreview) { + switch (s.iDSVideoRendererType) { + case VIDRNDT_DS_DEFAULT: + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VideoRendererDefault, MERIT64(0x800001))); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VideoMixingRenderer9, MERIT64(0x200003))); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_EnhancedVideoRenderer, MERIT64(0x200002))); + break; + case VIDRNDT_DS_OVERLAYMIXER: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_OverlayMixer, StrRes(IDS_PPAGE_OUTPUT_OVERLAYMIXER), renderer_merit)); + break; + case VIDRNDT_DS_VMR9WINDOWED: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VideoMixingRenderer9, StrRes(IDS_PPAGE_OUTPUT_VMR9WINDOWED), renderer_merit)); + break; + case VIDRNDT_DS_VMR9RENDERLESS: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VMR9AllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_VMR9RENDERLESS), renderer_merit)); + break; + case VIDRNDT_DS_EVR: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, StrRes(IDS_PPAGE_OUTPUT_EVR), renderer_merit)); + break; + case VIDRNDT_DS_EVR_CUSTOM: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_EVR_CUSTOM), renderer_merit)); + break; + case VIDRNDT_DS_DXR: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_DXRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_DXR), renderer_merit)); + break; + case VIDRNDT_DS_MADVR: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_madVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_MADVR), renderer_merit)); + break; + case VIDRNDT_DS_SYNC: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_SyncAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_SYNC), renderer_merit)); + break; + case VIDRNDT_DS_MPCVR: + if (!m_bIsCapture) { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_MPCVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_MPCVR), renderer_merit)); + } else { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, StrRes(IDS_PPAGE_OUTPUT_EVR), renderer_merit)); + } + break; + case VIDRNDT_DS_NULL_COMP: + pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_COMP), MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + break; + case VIDRNDT_DS_NULL_UNCOMP: + pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_UNCOMP), MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + break; + } + } else { + bool preview_evrcp = (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) || (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) || (s.iDSVideoRendererType == VIDRNDT_DS_MADVR) || (s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); + if (preview_evrcp && CAppSettings::IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM)) { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EVRAllocatorPresenter, L"EVRCP - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); + m_bPreviewSupportsRotation = true; + } else if (CAppSettings::IsVideoRendererAvailable(VIDRNDT_DS_EVR)) { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, L"EVR - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); + } else { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VideoMixingRenderer9, L"VMR9 - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); + } + } + + if (!m_bIsPreview) { + CString SelAudioRenderer = s.SelectedAudioRenderer(); + if (SelAudioRenderer == AUDRNDT_NULL_COMP) { + pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_COMP, MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + // DVD stuff + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); + m_transform.AddTail(pFGF); + } else if (SelAudioRenderer == AUDRNDT_NULL_UNCOMP) { + pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_UNCOMP, MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } else if (SelAudioRenderer == AUDRNDT_INTERNAL) { + struct SaneAudioRendererFilter : CFGFilter { + SaneAudioRendererFilter(CStringW name, UINT64 merit) : + CFGFilter(SaneAudioRenderer::Factory::GetFilterGuid(), name, merit) {} + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList&) override { + return SaneAudioRenderer::Factory::CreateFilter(AfxGetAppSettings().sanear, ppBF); + } + }; + pFGF = DEBUG_NEW SaneAudioRendererFilter(AUDRNDT_SANEAR, renderer_merit + 0x50); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } else if (SelAudioRenderer == AUDRNDT_MPC) { + pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_MPC, renderer_merit); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IEEE_FLOAT); + m_transform.AddTail(pFGF); + } else if (!SelAudioRenderer.IsEmpty()) { + pFGF = DEBUG_NEW CFGFilterRegistry(SelAudioRenderer, renderer_merit); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } + } else { + pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_COMP, MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + // DVD stuff + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); + m_transform.AddTail(pFGF); + } +} + +STDMETHODIMP CFGManagerPlayer::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) +{ + CAutoLock cAutoLock(this); + + CLSID pin_clsid = GetCLSID(pPinOut); + if (pin_clsid == CLSID_MPEG2Demultiplexer) { + CComQIPtr pMS = pPinOut; + REFERENCE_TIME rtDur = 0; + if (!pMS || FAILED(pMS->GetDuration(&rtDur)) || rtDur <= 0) { + return E_FAIL; + } + } else if (pin_clsid == CLSID_StillVideo || pin_clsid == CLSID_MPCImageSource) { + CComQIPtr pMS = pPinOut; + if (pMS) { + const CAppSettings& s = AfxGetAppSettings(); + if (s.iStillVideoDuration > 0) { + REFERENCE_TIME rtCur = 0; + REFERENCE_TIME rtDur = 0; + REFERENCE_TIME rtDurOverride = s.iStillVideoDuration * 10000000LL; + pMS->GetDuration(&rtDur); + if (rtDur == 0 || rtDur >= 10 * 3600 * 10000000LL) { + rtDur = rtDurOverride; + } else if (rtDur < rtDurOverride) { + rtDur = (rtDurOverride / rtDur) * rtDur; + } + // always call SetPositions() to prevent infinite repeat by the source filter + pMS->SetPositions(&rtCur, AM_SEEKING_AbsolutePositioning, &rtDur, AM_SEEKING_AbsolutePositioning); + } + } + } + + return __super::ConnectDirect(pPinOut, pPinIn, pmt); +} + +// +// CFGManagerDVD +// + +CFGManagerDVD::CFGManagerDVD(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) + : CFGManagerPlayer(pName, pUnk, hWnd, IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + + // elecard's decoder isn't suited for dvd playback (atm) + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{F50B3F13-19C4-11CF-AA9A-02608C9BABA2}")), MERIT64_DO_NOT_USE)); +} + +class CResetDVD : public CDVDSession +{ +public: + CResetDVD(LPCTSTR path) { + if (Open(path)) { + if (BeginSession()) { + Authenticate(); /*GetDiscKey();*/ + EndSession(); + } + Close(); + } + } +}; + +STDMETHODIMP CFGManagerDVD::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + CComPtr pBF; + if (FAILED(hr = AddSourceFilter(lpcwstrFile, lpcwstrFile, &pBF))) { + return hr; + } + + return ConnectFilter(pBF, nullptr); +} + +STDMETHODIMP CFGManagerDVD::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + CAutoLock cAutoLock(this); + + CheckPointer(lpcwstrFileName, E_POINTER); + CheckPointer(ppFilter, E_POINTER); + + CStringW fn = CStringW(lpcwstrFileName).TrimLeft(); + + GUID clsid = CLSID_DVDNavigator; + + CComPtr pBF; + if (FAILED(pBF.CoCreateInstance(clsid)) + || FAILED(AddFilter(pBF, L"DVD Navigator"))) { + return VFW_E_CANNOT_LOAD_SOURCE_FILTER; + } + + CComQIPtr pDVDC; + CComQIPtr pDVDI; + + if (!((pDVDC = pBF) && (pDVDI = pBF))) { + return E_NOINTERFACE; + } + + WCHAR buff[MAX_PATH]; + ULONG len; + if ((!fn.IsEmpty() + && FAILED(pDVDC->SetDVDDirectory(fn)) + && FAILED(pDVDC->SetDVDDirectory(fn + L"VIDEO_TS")) + && FAILED(pDVDC->SetDVDDirectory(fn + L"\\VIDEO_TS"))) + || FAILED(pDVDI->GetDVDDirectory(buff, _countof(buff), &len)) || len == 0) { + return E_INVALIDARG; + } + + pDVDC->SetOption(DVD_ResetOnStop, FALSE); + pDVDC->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); + + if (clsid == CLSID_DVDNavigator) { + CResetDVD(CString(buff)); + } + + *ppFilter = pBF.Detach(); + + return S_OK; +} + +// +// CFGManagerCapture +// + +CFGManagerCapture::CFGManagerCapture(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd) + : CFGManagerPlayer(pName, pUnk, hWnd) +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (s.bCaptureDeinterlace) { + // set merit higher than our video renderers + CFGFilter* pFGF = DEBUG_NEW CFGFilterInternal(L"Deinterlacer", MERIT64(0x800001) + 0x200); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } + + m_bIsCapture = True; +} + +// +// CFGManagerMuxer +// + +CFGManagerMuxer::CFGManagerMuxer(LPCTSTR pName, LPUNKNOWN pUnk) + : CFGManagerCustom(pName, pUnk) +{ + m_source.AddTail(DEBUG_NEW CFGFilterInternal()); +} + +// +// CFGAggregator +// + +CFGAggregator::CFGAggregator(const CLSID& clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT& hr) + : CUnknown(pName, pUnk) +{ + hr = m_pUnkInner.CoCreateInstance(clsid, GetOwner()); +} + +CFGAggregator::~CFGAggregator() +{ + m_pUnkInner.Release(); +} + +STDMETHODIMP CFGAggregator::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + m_pUnkInner && (riid != IID_IUnknown && SUCCEEDED(m_pUnkInner->QueryInterface(riid, ppv))) ? S_OK : + __super::NonDelegatingQueryInterface(riid, ppv); +} diff --git a/src/mpc-hc/FGManager.h b/src/mpc-hc/FGManager.h index 2d91169a485..1ec16f5d63e 100644 --- a/src/mpc-hc/FGManager.h +++ b/src/mpc-hc/FGManager.h @@ -1,212 +1,212 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "FGFilter.h" -#include "FGFilterLAV.h" -#include "IGraphBuilder2.h" - -class CFGManager - : public CUnknown - , public IGraphBuilder2 - , public IGraphBuilderDeadEnd - , public CCritSec -{ -public: - struct path_t { - CLSID clsid; - CString filter, pin; - }; - - class CStreamPath : public CAtlList - { - public: - void Append(IBaseFilter* pBF, IPin* pPin); - bool Compare(const CStreamPath& path); - }; - - class CStreamDeadEnd : public CStreamPath - { - public: - CAtlList mts; - }; - -private: - CComPtr m_pUnkInner; - DWORD m_dwRegister; - - bool m_aborted; - - CStreamPath m_streampath; - CAutoPtrArray m_deadends; - -protected: - CComPtr m_pFM; - CInterfaceList m_pUnks; - CAtlList m_source, m_transform, m_override; - - BOOL m_ignoreVideo; - - CString m_useragent; - CString m_referrer; - - static bool CheckBytes(HANDLE hFile, CString chkbytes); - - HRESULT EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl); - HRESULT AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF); - HRESULT Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender); - - // IFilterGraph - - STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); - STDMETHODIMP RemoveFilter(IBaseFilter* pFilter); - STDMETHODIMP EnumFilters(IEnumFilters** ppEnum); - STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter); - STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP Reconnect(IPin* ppin); - STDMETHODIMP Disconnect(IPin* ppin); - STDMETHODIMP SetDefaultSyncSource(); - - // IGraphBuilder - - STDMETHODIMP Connect(IPin* pPinOut, IPin* pPinIn); - STDMETHODIMP Render(IPin* pPinOut); - STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); - STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - STDMETHODIMP SetLogFile(DWORD_PTR hFile); - STDMETHODIMP Abort(); - STDMETHODIMP ShouldOperationContinue(); - - // IFilterGraph2 - - STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext); - - // IGraphBuilder2 - - STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir); - STDMETHODIMP IsPinConnected(IPin* pPin); - STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn); - STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF); - STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP NukeDownstream(IUnknown* pUnk); - STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove); - STDMETHODIMP AddToROT(); - STDMETHODIMP RemoveFromROT(); - - // IGraphBuilderDeadEnd - - STDMETHODIMP_(size_t) GetCount(); - STDMETHODIMP GetDeadEnd(int iIndex, CAtlList& path, CAtlList& mts); - - // - HWND m_hWnd; - bool m_bIsPreview,m_bPreviewSupportsRotation; - CStringW m_entryRFS; - bool m_bIsCapture; - -public: - CFGManager(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd = 0, bool IsPreview = false); - virtual ~CFGManager(); - HRESULT RenderRFSFileEntry(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList, CStringW entryRFS); - bool PreviewSupportsRotation() { return m_bPreviewSupportsRotation; } - static CUnknown* WINAPI GetMpcAudioRendererInstance(LPUNKNOWN lpunk, HRESULT* phr); - - void SetUserAgent(CString ua) { m_useragent = ua; }; - void SetReferrer(CString ref) { m_referrer = ref; }; - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); -}; - -class CFGManagerCustom : public CFGManager -{ -public: - // IFilterGraph - - STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); - - void InsertLAVSplitterSource(bool IsPreview = false); - void InsertLAVSplitter(bool IsPreview = false); - void InsertLAVVideo(bool IsPreview = false); - void InsertLAVAudio(); - void InsertOtherInternalSourcefilters(bool IsPreview = false); - void InsertSubtitleFilters(bool IsPreview = false); - void InsertBlockedFilters(); - void InsertBroadcomDecoder(); - -public: - CFGManagerCustom(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd = 0, bool IsPreview = false); -}; - -class CFGManagerPlayer : public CFGManagerCustom -{ -protected: - HWND m_hWnd; - - // IFilterGraph - - STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); - -public: - CFGManagerPlayer(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview = false); -}; - -class CFGManagerDVD : public CFGManagerPlayer -{ -protected: - // IGraphBuilder - - STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); - STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - -public: - CFGManagerDVD(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview = false); -}; - -class CFGManagerCapture : public CFGManagerPlayer -{ -public: - CFGManagerCapture(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd); -}; - -class CFGManagerMuxer : public CFGManagerCustom -{ -public: - CFGManagerMuxer(LPCTSTR pName, LPUNKNOWN pUnk); -}; - -// - -class CFGAggregator : public CUnknown -{ -protected: - CComPtr m_pUnkInner; - -public: - CFGAggregator(const CLSID& clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT& hr); - virtual ~CFGAggregator(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "FGFilter.h" +#include "FGFilterLAV.h" +#include "IGraphBuilder2.h" + +class CFGManager + : public CUnknown + , public IGraphBuilder2 + , public IGraphBuilderDeadEnd + , public CCritSec +{ +public: + struct path_t { + CLSID clsid; + CString filter, pin; + }; + + class CStreamPath : public CAtlList + { + public: + void Append(IBaseFilter* pBF, IPin* pPin); + bool Compare(const CStreamPath& path); + }; + + class CStreamDeadEnd : public CStreamPath + { + public: + CAtlList mts; + }; + +private: + CComPtr m_pUnkInner; + DWORD m_dwRegister; + + bool m_aborted; + + CStreamPath m_streampath; + CAutoPtrArray m_deadends; + +protected: + CComPtr m_pFM; + CInterfaceList m_pUnks; + CAtlList m_source, m_transform, m_override; + + BOOL m_ignoreVideo; + + CString m_useragent; + CString m_referrer; + + static bool CheckBytes(HANDLE hFile, CString chkbytes); + + HRESULT EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl); + HRESULT AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF); + HRESULT Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender); + + // IFilterGraph + + STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); + STDMETHODIMP RemoveFilter(IBaseFilter* pFilter); + STDMETHODIMP EnumFilters(IEnumFilters** ppEnum); + STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter); + STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP Reconnect(IPin* ppin); + STDMETHODIMP Disconnect(IPin* ppin); + STDMETHODIMP SetDefaultSyncSource(); + + // IGraphBuilder + + STDMETHODIMP Connect(IPin* pPinOut, IPin* pPinIn); + STDMETHODIMP Render(IPin* pPinOut); + STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); + STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + STDMETHODIMP SetLogFile(DWORD_PTR hFile); + STDMETHODIMP Abort(); + STDMETHODIMP ShouldOperationContinue(); + + // IFilterGraph2 + + STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext); + + // IGraphBuilder2 + + STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir); + STDMETHODIMP IsPinConnected(IPin* pPin); + STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn); + STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF); + STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP NukeDownstream(IUnknown* pUnk); + STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove); + STDMETHODIMP AddToROT(); + STDMETHODIMP RemoveFromROT(); + + // IGraphBuilderDeadEnd + + STDMETHODIMP_(size_t) GetCount(); + STDMETHODIMP GetDeadEnd(int iIndex, CAtlList& path, CAtlList& mts); + + // + HWND m_hWnd; + bool m_bIsPreview,m_bPreviewSupportsRotation; + CStringW m_entryRFS; + bool m_bIsCapture; + +public: + CFGManager(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd = 0, bool IsPreview = false); + virtual ~CFGManager(); + HRESULT RenderRFSFileEntry(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList, CStringW entryRFS); + bool PreviewSupportsRotation() { return m_bPreviewSupportsRotation; } + static CUnknown* WINAPI GetMpcAudioRendererInstance(LPUNKNOWN lpunk, HRESULT* phr); + + void SetUserAgent(CString ua) { m_useragent = ua; }; + void SetReferrer(CString ref) { m_referrer = ref; }; + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); +}; + +class CFGManagerCustom : public CFGManager +{ +public: + // IFilterGraph + + STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); + + void InsertLAVSplitterSource(bool IsPreview = false); + void InsertLAVSplitter(bool IsPreview = false); + void InsertLAVVideo(bool IsPreview = false); + void InsertLAVAudio(); + void InsertOtherInternalSourcefilters(bool IsPreview = false); + void InsertSubtitleFilters(bool IsPreview = false); + void InsertBlockedFilters(); + void InsertBroadcomDecoder(); + +public: + CFGManagerCustom(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd = 0, bool IsPreview = false); +}; + +class CFGManagerPlayer : public CFGManagerCustom +{ +protected: + HWND m_hWnd; + + // IFilterGraph + + STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); + +public: + CFGManagerPlayer(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview = false); +}; + +class CFGManagerDVD : public CFGManagerPlayer +{ +protected: + // IGraphBuilder + + STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); + STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + +public: + CFGManagerDVD(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview = false); +}; + +class CFGManagerCapture : public CFGManagerPlayer +{ +public: + CFGManagerCapture(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd); +}; + +class CFGManagerMuxer : public CFGManagerCustom +{ +public: + CFGManagerMuxer(LPCTSTR pName, LPUNKNOWN pUnk); +}; + +// + +class CFGAggregator : public CUnknown +{ +protected: + CComPtr m_pUnkInner; + +public: + CFGAggregator(const CLSID& clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT& hr); + virtual ~CFGAggregator(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); +}; diff --git a/src/mpc-hc/FGManagerBDA.cpp b/src/mpc-hc/FGManagerBDA.cpp index 2f848165b29..6214d4f8679 100644 --- a/src/mpc-hc/FGManagerBDA.cpp +++ b/src/mpc-hc/FGManagerBDA.cpp @@ -1,1456 +1,1456 @@ -/* - * (C) 2009-2017 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 . - * - */ - -#include "stdafx.h" -#include "FGManagerBDA.h" -#include "Mpeg2SectionData.h" -#include "MainFrm.h" -#include "Logger.h" -#include -#include -#include -#include -#include -#include - -#define LOG(...) MPCHC_LOG(BDA, __VA_ARGS__) -#define CheckAndLogBDA(x, msg) hr = ##x; if (FAILED(hr)) { LOG(msg _T(": 0x%08x\n"), hr); return hr; } -#define CheckAndLogBDANoRet(x, msg) hr = ##x; if (FAILED(hr)) { LOG(msg _T(": 0x%08x\n"), hr); } - -/// Format, Video MPEG2 -static VIDEOINFOHEADER2 sMpv_fmt = { - {0, 0, 720, 576}, // rcSource - {0, 0, 0, 0}, // rcTarget - 0, // dwBitRate - 0, // dwBitErrorRate - 400000, // AvgTimePerFrame - 0, // dwInterlaceFlags - 0, // dwCopyProtectFlags - 0, // dwPictAspectRatioX - 0, // dwPictAspectRatioY - {0}, // dwControlFlag & dwReserved1 - 0, // dwReserved2 - { - // bmiHeader - sizeof(BITMAPINFOHEADER), // biSize - 720, // biWidth - 576, // biHeight - 0, // biPlanes - 0, // biBitCount - 0 // biCompression - } - // implicitly sets the others fields to 0 -}; - -/// Media type, Video MPEG2 -static const AM_MEDIA_TYPE mt_Mpv = { - MEDIATYPE_Video, // majortype - MEDIASUBTYPE_MPEG2_VIDEO, // subtype - FALSE, // bFixedSizeSamples - TRUE, // bTemporalCompression - 0, // lSampleSize - FORMAT_VideoInfo2, // formattype - nullptr, // pUnk - sizeof(sMpv_fmt), // cbFormat - (LPBYTE)& sMpv_fmt // pbFormat -}; - -/// Format, Video H264 -static VIDEOINFOHEADER2 vih2_H264 = { - {0, 0, 0, 0}, // rcSource - {0, 0, 0, 0}, // rcTarget - 0, // dwBitRate, - 0, // dwBitErrorRate - 0, // AvgTimePerFrame - 0, // dwInterlaceFlags - 0, // dwCopyProtectFlags - 0, // dwPictAspectRatioX - 0, // dwPictAspectRatioY - {0}, // dwControlFlag & dwReserved1 - 0, // dwReserved2 - { - // bmiHeader - sizeof(BITMAPINFOHEADER), // biSize - 720, // biWidth - 576, // biHeight - 1, // biPlanes - 0, // biBitCount - MAKEFOURCC('h', '2', '6', '4') // biCompression - } - // implicitly sets the others fields to 0 -}; - -/// Media type, Video H264 -static const AM_MEDIA_TYPE mt_H264 = { - MEDIATYPE_Video, // majortype - MEDIASUBTYPE_H264, // subtype - FALSE, // bFixedSizeSamples - TRUE, // bTemporalCompression - 0, // lSampleSize - FORMAT_VideoInfo2, // formattype - nullptr, // pUnk - sizeof(vih2_H264), // cbFormat - (LPBYTE)& vih2_H264 // pbFormat -}; - -/// Format, Video HEVC -static VIDEOINFOHEADER2 vih2_HEVC = { - {0, 0, 0, 0}, // rcSource - {0, 0, 0, 0}, // rcTarget - 0, // dwBitRate, - 0, // dwBitErrorRate - 0, // AvgTimePerFrame - 0, // dwInterlaceFlags - 0, // dwCopyProtectFlags - 0, // dwPictAspectRatioX - 0, // dwPictAspectRatioY - {0}, // dwControlFlag & dwReserved1 - 0, // dwReserved2 - { - // bmiHeader - sizeof(BITMAPINFOHEADER), // biSize - 720, // biWidth - 576, // biHeight - 1, // biPlanes - 0, // biBitCount - MAKEFOURCC('H', 'E', 'V', 'C') // biCompression - } - // implicitly sets the others fields to 0 -}; - -/// Media type, Video HEVC -static const AM_MEDIA_TYPE mt_HEVC = { - MEDIATYPE_Video, // majortype - MEDIASUBTYPE_HEVC, // subtype - FALSE, // bFixedSizeSamples - TRUE, // bTemporalCompression - 0, // lSampleSize - FORMAT_VideoInfo2, // formattype - nullptr, // pUnk - sizeof(vih2_HEVC), // cbFormat - (LPBYTE)& vih2_HEVC // pbFormat -}; - -// Format, Audio MPEG2 -static BYTE MPEG2AudioFormat[] = { - 0x50, 0x00, //wFormatTag - 0x02, 0x00, //nChannels - 0x80, 0xbb, 0x00, 0x00, //nSamplesPerSec - 0x00, 0x7d, 0x00, 0x00, //nAvgBytesPerSec - 0x01, 0x00, //nBlockAlign - 0x00, 0x00, //wBitsPerSample - 0x16, 0x00, //cbSize - 0x02, 0x00, //wValidBitsPerSample - 0x00, 0xe8, //wSamplesPerBlock - 0x03, 0x00, //wReserved - 0x01, 0x00, 0x01, 0x00, //dwChannelMask - 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// Format, Audio (E)AC3 -static BYTE AC3AudioFormat[] = { - 0x00, 0x20, //wFormatTag - 0x06, 0x00, //nChannels - 0x80, 0xBB, 0x00, 0x00, //nSamplesPerSec - 0xC0, 0x5D, 0x00, 0x00, //nAvgBytesPerSec - 0x00, 0x03, //nBlockAlign - 0x00, 0x00, //wBitsPerSample - 0x00, 0x00 //cbSize -}; - -// Format, Audio AAC -static BYTE AACAudioFormat[] = { - 0xFF, 0x00, //wFormatTag - 0x02, 0x00, //nChannels - 0x80, 0xBB, 0x00, 0x00, //nSamplesPerSec - 0xCE, 0x3E, 0x00, 0x00, //nAvgBytesPerSec - 0xAE, 0x02, //nBlockAlign - 0x00, 0x00, //wBitsPerSample - 0x02, 0x00, //cbSize - 0x11, 0x90 -}; - -/// Media type, Audio MPEG2 -static const AM_MEDIA_TYPE mt_Mpa = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_MPEG2_AUDIO, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(MPEG2AudioFormat), // cbFormat - MPEG2AudioFormat // pbFormat -}; - -/// Media type, Audio AC3 -static const AM_MEDIA_TYPE mt_Ac3 = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_DOLBY_AC3, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(AC3AudioFormat), // cbFormat - AC3AudioFormat, // pbFormat -}; - -/// Media type, Audio EAC3 -static const AM_MEDIA_TYPE mt_Eac3 = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_DOLBY_DDPLUS, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(AC3AudioFormat), // cbFormat - AC3AudioFormat, // pbFormat -}; - -/// Media type, Audio AAC ADTS -static const AM_MEDIA_TYPE mt_adts = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_MPEG_ADTS_AAC, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(AACAudioFormat), // cbFormat - AACAudioFormat, // pbFormat -}; - -/// Media type, Audio AAC LATM -static const AM_MEDIA_TYPE mt_latm = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_LATM_AAC, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(AACAudioFormat), // cbFormat - AACAudioFormat, // pbFormat -}; - -/// Media type, PSI -static const AM_MEDIA_TYPE mt_Psi = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_MPEG2DATA, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr // pbFormat -}; - -/// Media type, TIF -static const AM_MEDIA_TYPE mt_DVB_Tif = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_DVB_SI, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr // pbFormat -}; - -/// Media type, EPG -static const AM_MEDIA_TYPE mt_DVB_Epg = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_DVB_SI, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr, // pbFormat -}; - -/// Media type, TIF -static const AM_MEDIA_TYPE mt_ATSC_Tif = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_ATSC_SI, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr // pbFormat -}; - -/// Media type, EPG -static const AM_MEDIA_TYPE mt_ATSC_Epg = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_ATSC_SI, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr, // pbFormat -}; - -static const SUBTITLEINFO SubFormat = { 0, "", L"" }; - -/// Media type, subtitle -static const AM_MEDIA_TYPE mt_Subtitle = { - MEDIATYPE_Subtitle, // majortype - MEDIASUBTYPE_DVB_SUBTITLES, // subtype - FALSE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - sizeof(SubFormat), // cbFormat - (LPBYTE)& SubFormat // pbFormat -}; - -/// CLSID for TIF -// FC772AB0-0C7F-11D3-8FF2-00A0C9224CF4 -static const CLSID CLSID_BDA_MPEG2_TIF = -{0xFC772AB0, 0x0C7F, 0x11D3, {0x8F, 0xF2, 0x00, 0xA0, 0xC9, 0x22, 0x4C, 0xF4}}; - -CFGManagerBDA::CFGManagerBDA(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd) - : CFGManagerPlayer(pName, pUnk, hWnd) -{ - LOG(_T("---------------------------------------------------------------->")); - LOG(_T("Starting session...")); - - CAppSettings& s = AfxGetAppSettings(); - m_nDVBRebuildFilterGraph = s.nDVBRebuildFilterGraph; - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - - if (pChannel) { - if (pChannel->GetVideoType() == BDA_H264) { - UpdateMediaType(&vih2_H264, pChannel); - } else if (pChannel->GetVideoType() == BDA_HEVC) { - UpdateMediaType(&vih2_HEVC, pChannel); - } else if (pChannel->GetVideoType() == BDA_MPV) { - UpdateMediaType(&sMpv_fmt, pChannel); - } - } - - tunerIsATSC = false; - BeginEnumSysDev(KSCATEGORY_BDA_NETWORK_TUNER, pMoniker) { - CComHeapPtr strName; - if (SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName)) ) { - if (s.strBDATuner == CString(strName)) { - CComPtr pPB; - pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)); - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - CString fName = CString(var.bstrVal); - if (fName.Find(_T("ATSC")) > -1) { //hack to identify an ATSC tuner. better solution might be to check the tuner capabilities, but this should be good enough - tunerIsATSC = true; - } - } - } - } - } - EndEnumSysDev; - - m_DVBStreams[BDA_MPV] = CDVBStream(L"mpv", &mt_Mpv); - m_DVBStreams[BDA_H264] = CDVBStream(L"h264", &mt_H264); - m_DVBStreams[BDA_HEVC] = CDVBStream(L"HEVC", &mt_HEVC); - m_DVBStreams[BDA_MPA] = CDVBStream(L"mpa", &mt_Mpa); - m_DVBStreams[BDA_AC3] = CDVBStream(L"ac3", &mt_Ac3); - m_DVBStreams[BDA_EAC3] = CDVBStream(L"eac3", &mt_Eac3); - m_DVBStreams[BDA_ADTS] = CDVBStream(L"adts", &mt_adts); - m_DVBStreams[BDA_LATM] = CDVBStream(L"latm", &mt_latm); - m_DVBStreams[BDA_PSI] = CDVBStream(L"psi", &mt_Psi, true, MEDIA_MPEG2_PSI); - if (tunerIsATSC) { - m_DVBStreams[BDA_TIF] = CDVBStream(L"tif", &mt_ATSC_Tif, true); - m_DVBStreams[BDA_EPG] = CDVBStream(L"epg", &mt_ATSC_Epg); - } else { - m_DVBStreams[BDA_TIF] = CDVBStream(L"tif", &mt_DVB_Tif, true); - m_DVBStreams[BDA_EPG] = CDVBStream(L"epg", &mt_DVB_Epg); - } - m_DVBStreams[BDA_SUB] = CDVBStream(L"sub", &mt_Subtitle/*, false, MEDIA_TRANSPORT_PAYLOAD*/); - - if (pChannel) { - m_nCurVideoType = pChannel->GetVideoType(); - m_nCurAudioType = pChannel->GetDefaultAudioType(); - } else { - m_nCurVideoType = BDA_MPV; - m_nCurAudioType = BDA_MPA; - } - m_fHideWindow = false; - - // Blacklist some unsupported filters (AddHead must be used to ensure higher priority): - // - audio switcher - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(__uuidof(CAudioSwitcherFilter), MERIT64_DO_NOT_USE)); - // - internal video decoder and ffdshow DXVA video decoder (cf ticket #730) - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_MPCVideoDecoder, MERIT64_DO_NOT_USE)); - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_FFDShowDXVADecoder, MERIT64_DO_NOT_USE)); - // - Microsoft DTV-DVD Audio Decoder - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_MSDVTDVDAudioDecoder, MERIT64_DO_NOT_USE)); - // - ACM Wrapper - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_ACMWrapper, MERIT64_DO_NOT_USE)); - // - ReClock - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_ReClock, MERIT64_DO_NOT_USE)); - - LOG(_T("CFGManagerBDA object created.")); -} - -CFGManagerBDA::~CFGManagerBDA() -{ - m_DVBStreams.RemoveAll(); - LOG(_T("CFGManagerBDA object destroyed.")); - LOG(_T("<----------------------------------------------------------------\n\n")); -} - -HRESULT CFGManagerBDA::CreateKSFilterFN(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& FriendlyName) { - HRESULT hr = VFW_E_NOT_FOUND; - BeginEnumSysDev(KSCategory, pMoniker) { - CComPtr pPB; - CComVariant var; - if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB))) && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - CStringW fName = CStringW(var.bstrVal); - if (fName != FriendlyName) { - continue; - } - - hr = pMoniker->BindToObject(nullptr, nullptr, IID_PPV_ARGS(ppBF)); - if (SUCCEEDED(hr)) { - hr = AddFilter(*ppBF, fName); - } - break; - } - } - EndEnumSysDev; - - return hr; -} - - -HRESULT CFGManagerBDA::CreateKSFilter(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& DisplayName) -{ - HRESULT hr = VFW_E_NOT_FOUND; - BeginEnumSysDev(KSCategory, pMoniker) { - CComPtr pPB; - CComVariant var; - CComHeapPtr strName; - if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB))) && - SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName)) && - SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - CStringW Name = strName; - if (Name != DisplayName) { - continue; - } - - hr = pMoniker->BindToObject(nullptr, nullptr, IID_PPV_ARGS(ppBF)); - if (SUCCEEDED(hr)) { - hr = AddFilter(*ppBF, CStringW(var.bstrVal)); - } - break; - } - } - EndEnumSysDev; - - return hr; -} - -HRESULT CFGManagerBDA::SearchIBDATopology(const CComPtr& pTuner, REFIID iid, CComPtr& pUnk) -{ - CComQIPtr pTop(pTuner); - CheckPointer(pTop, E_NOINTERFACE); - - ULONG NodeTypes = 0; - ULONG NodeType[32]; - - HRESULT hr = pTop->GetNodeTypes(&NodeTypes, _countof(NodeType), NodeType); - - if (FAILED(hr)) { - return hr; - } - - for (ULONG i = 0; i < NodeTypes; i++) { - ULONG nInterfaces; - GUID aInterface[32]; - - hr = pTop->GetNodeInterfaces(NodeType[i], &nInterfaces, _countof(aInterface), aInterface); - - if (FAILED(hr)) { - continue; - } - - for (ULONG j = 0; j < nInterfaces; j++) { - if (aInterface[j] == iid) { - return pTop->GetControlNode(0, 1, NodeType[i], &pUnk); - } - } - } - - return FAILED(hr) ? hr : E_NOINTERFACE; -} - -HRESULT CFGManagerBDA::ConnectFilters(IBaseFilter* pOutFilter, IBaseFilter* pInFilter) -{ - HRESULT hr = VFW_E_CANNOT_CONNECT; - BeginEnumPins(pOutFilter, pEP, pOutPin) { - if (S_OK == IsPinDirection(pOutPin, PINDIR_OUTPUT) - && S_OK != IsPinConnected(pOutPin)) { - BeginEnumPins(pInFilter, pEP2, pInPin) { - if (S_OK == IsPinDirection(pInPin, PINDIR_INPUT) - && S_OK != IsPinConnected(pInPin)) { - hr = this->ConnectDirect(pOutPin, pInPin, nullptr); - -#if 0 && defined(_DEBUG) // Disabled by default because it can be verbose - CPinInfo infoPinIn, infoPinOut; - infoPinIn.achName[0] = infoPinOut.achName[0] = L'\0'; - CFilterInfo infoFilterIn, infoFilterOut; - infoFilterIn.achName[0] = infoFilterOut.achName[0] = L'\0'; - - pInPin->QueryPinInfo(&infoPinIn); - if (infoPinIn.pFilter) { - infoPinIn.pFilter->QueryFilterInfo(&infoFilterIn); - } - pOutPin->QueryPinInfo(&infoPinOut); - if (infoPinOut.pFilter) { - infoPinOut.pFilter->QueryFilterInfo(&infoFilterOut); - } - - TRACE(_T("%s - %s => %s - %s (hr=0x%08x)\n"), infoFilterOut.achName, infoPinOut.achName, infoFilterIn.achName, infoPinIn.achName, hr); -#endif - - if (SUCCEEDED(hr)) { - return hr; - } - } - } - EndEnumPins; - } - } - EndEnumPins; - - return hr; -} - -STDMETHODIMP CFGManagerBDA::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) -{ - HRESULT hr; - const CAppSettings& s = AfxGetAppSettings(); - CComPtr pNetwork; - CComPtr pTuner; - CComPtr pReceiver; - - LOG(_T("Creating BDA filters...")); - CheckAndLogBDA(CreateKSFilterFN(&pNetwork, KSCATEGORY_BDA_NETWORK_PROVIDER, _T("Microsoft Network Provider")), _T("Network provider creation")); - if (FAILED(hr = CreateKSFilter(&pTuner, KSCATEGORY_BDA_NETWORK_TUNER, s.strBDATuner))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CREATE_TUNER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Network tuner creation: 0x%08x\n"), hr); - LOG(_T("Network tuner creation: 0x%08x"), hr); - return hr; - } - - if (FAILED(hr = ConnectFilters(pNetwork, pTuner))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CONNECT_TUNER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Network <-> Tuner: 0x%08x\n"), hr); - LOG(_T("Network <-> Tuner: 0x%08x"), hr); - return hr; - } - m_pBDAControl = pTuner; - - if (FAILED(hr = SearchIBDATopology(pTuner, m_pBDAFreq))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, _T("IBDA_FrequencyFilter topology failed."), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - LOG(_T("IBDA_FrequencyFilter topology failed.")); - return hr; - } - m_pBDATunerStats = m_pBDAFreq; - if (FAILED(hr = SearchIBDATopology(pTuner, m_pBDADemodulator))) { - TRACE(_T("BDA: IBDA_DigitalDemodulator topology failed: 0x%08x\n"), hr); - LOG(_T("IBDA_DigitalDemodulator topology failed. Result 0x%08x"), hr); - } - m_pBDADemodStats = m_pBDADemodulator; - - if (!m_pBDATunerStats || !m_pBDADemodStats) { - if (m_pBDATunerStats) { - TRACE(_T("BDA: no statistics interface on the demodulator node --> using the statistics from the RF node only\n")); - LOG(_T("No statistics interface on the demodulator node --> using the statistics from the RF node only.")); - m_pBDADemodStats = m_pBDATunerStats; - } else if (m_pBDADemodStats) { - TRACE(_T("BDA: no statistics interface on the RF node --> using the statistics from the demodulator node only\n")); - LOG(_T("No statistics interface on the RF node --> using the statistics from the demodulator node only.")); - m_pBDATunerStats = m_pBDADemodStats; - } else { // if (!m_pBDATunerStats && !m_pBDADemodStats) - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, _T("No statistics interface available."), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Not statistics interface available\n")); - LOG(_T("Not statistics interface available.")); - return E_NOINTERFACE; - } - } - - if (SUCCEEDED(hr = SearchIBDATopology(pTuner, m_pBDAAutoDemulate))) { - if (SUCCEEDED(hr = m_pBDAAutoDemulate->put_AutoDemodulate())) { - LOG(_T("Auto Demulate is on.")); - } else { - LOG(_T("Auto Demulate could not be switched: 0x%08x."), hr); - } - } else { - LOG(_T("AutoDemulate topology not found.")); - TRACE(_T("BDA: AutoDemulate topology not found: 0x%08x\n"), hr); - } - - if (FAILED(hr = m_pDemux.CoCreateInstance(CLSID_MPEG2Demultiplexer, nullptr, CLSCTX_INPROC_SERVER))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_DEMULTIPLEXER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Microsoft demux creation: 0x%08x\n"), hr); - return hr; - } - CheckNoLog(AddFilter(m_pDemux, _T("MPEG-2 Demultiplexer"))); - if (FAILED(ConnectFilters(pTuner, m_pDemux))) { // Separate receiver is required - if (FAILED(hr = CreateKSFilter(&pReceiver, KSCATEGORY_BDA_RECEIVER_COMPONENT, s.strBDAReceiver))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CREATE_RECEIVER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Receiver creation: 0x%08x\n"), hr); - return hr; - } - if (FAILED(hr = ConnectFilters(pTuner, pReceiver))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CONNECT_TUNER_REC), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Tuner <-> Receiver: 0x%08x\n"), hr); - return hr; - } - if (FAILED(ConnectFilters(pReceiver, m_pDemux))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_DEMULTIPLEXER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Receiver <-> Demux: 0x%08x\n"), hr); - return hr; - } - LOG(_T("Network -> Tuner -> Receiver connected.")); - - } else { // The selected filter is performing both tuner and receiver functions - LOG(_T("Network -> Receiver connected.")); - } - - CheckNoLog(CreateMicrosoftDemux(m_pDemux)); - -#ifdef _DEBUG - LOG(_T("Filter list:")); - BeginEnumFilters(this, pEF, pBF) { - LOG(_T(" ") + GetFilterName(pBF)); - } - EndEnumFilters; - LOG(_T("Filter list end.\n")); -#endif - - return hr; -} - -STDMETHODIMP CFGManagerBDA::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) -{ - // Bypass CFGManagerPlayer limitation (IMediaSeeking for Mpeg2 demux) - return CFGManagerCustom::ConnectDirect(pPinOut, pPinIn, pmt); -} - -STDMETHODIMP CFGManagerBDA::SetChannel(int nChannelPrefNumber) -{ - HRESULT hr = E_INVALIDARG; - CAppSettings& s = AfxGetAppSettings(); - - CBDAChannel* pChannel = s.FindChannelByPref(nChannelPrefNumber); - LOG(_T("Start SetChannel %d."), nChannelPrefNumber); - if (pChannel) { - if (!((m_nCurAudioType == BDA_UNKNOWN) ^ (pChannel->GetDefaultAudioType() == BDA_UNKNOWN)) && - ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_NEVER) || - ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_WHEN_SWITCHING) && (m_nCurVideoType == pChannel->GetVideoType())) || - ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_ALWAYS) && (s.nDVBLastChannel == nChannelPrefNumber)))) { - hr = SetChannelInternal(pChannel); - } else { - s.nDVBLastChannel = nChannelPrefNumber; - return S_FALSE; - } - - if (SUCCEEDED(hr)) { - s.nDVBLastChannel = nChannelPrefNumber; - m_nCurVideoType = pChannel->GetVideoType(); - m_nCurAudioType = pChannel->GetDefaultAudioType(); - LOG(_T("SetChannel %d successful.\n"), nChannelPrefNumber); - } else { - LOG(_T("SetChannel %d failed. Result: 0x%08x.\n"), nChannelPrefNumber, hr); - } - } - return hr; -} - -STDMETHODIMP CFGManagerBDA::SetAudio(int nAudioIndex) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CFGManagerBDA::SetFrequency(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) -{ - HRESULT hr; - LOG(_T("Frequency %lu, Bandwidth %lu, SymbolRate %lu"), ulFrequency, ulBandwidth, ulSymbolRate); - CheckPointer(m_pBDAControl, E_FAIL); - CheckPointer(m_pBDAFreq, E_FAIL); - - CheckAndLogBDA(m_pBDAControl->StartChanges(), _T(" SetFrequency StartChanges")); - if (ulSymbolRate != 0) { - CheckAndLogBDANoRet(m_pBDADemodulator->put_SymbolRate(&ulSymbolRate), _T(" SetFrequency put_SymbolRate")); - } - CheckAndLogBDANoRet(m_pBDAFreq->put_FrequencyMultiplier(1000), _T(" SetFrequency put_FrequencyMultiplier")); - CheckAndLogBDANoRet(m_pBDAFreq->put_Bandwidth(ulBandwidth / 1000), _T(" SetFrequency put_Bandwidth")); - CheckAndLogBDA(m_pBDAFreq->put_Frequency(ulFrequency), _T(" SetFrequency put_Frequency")); - CheckAndLogBDA(m_pBDAControl->CheckChanges(), _T(" SetFrequency CheckChanges")); - CheckAndLogBDA(m_pBDAControl->CommitChanges(), _T(" SetFrequency CommitChanges")); - - int i = 50; - ULONG pState = BDA_CHANGES_PENDING; - while (SUCCEEDED(hr = m_pBDAControl->GetChangeState(&pState)) && pState == BDA_CHANGES_PENDING && i-- > 0) { - LOG(_T("changes pending, waiting for tuner...")); - Sleep(50); - } - - if (SUCCEEDED(hr)) { - if (pState == BDA_CHANGES_PENDING) { - LOG(_T("changes pending (timeout error----)")); - hr = VFW_E_TIMEOUT; - } else { - LOG(_T("Frequency changed: %lu / %lu."), ulFrequency, ulBandwidth); -#ifdef _DEBUG - BOOLEAN bPresent; - BOOLEAN bLocked; - LONG lDbStrength; - LONG lPercentQuality; - - if (SUCCEEDED(GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { - LOG(_T("Signal stats: Strength %ld dB, Quality %ld%%"), lDbStrength, lPercentQuality); - } -#endif - } - } else { - LOG(_T("Frequency change failed. Result: 0x%08x."), hr); - } - - return hr; -} - -HRESULT CFGManagerBDA::ClearMaps() -{ - HRESULT hr = S_OK; - - if (m_DVBStreams[BDA_MPV].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_MPV].Unmap(m_DVBStreams[BDA_MPV].GetMappedPID())); - } - if (m_DVBStreams[BDA_H264].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_H264].Unmap(m_DVBStreams[BDA_H264].GetMappedPID())); - } - if (m_DVBStreams[BDA_HEVC].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_HEVC].Unmap(m_DVBStreams[BDA_HEVC].GetMappedPID())); - } - if (m_DVBStreams[BDA_MPA].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_MPA].Unmap(m_DVBStreams[BDA_MPA].GetMappedPID())); - } - if (m_DVBStreams[BDA_AC3].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_AC3].Unmap(m_DVBStreams[BDA_AC3].GetMappedPID())); - } - if (m_DVBStreams[BDA_EAC3].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_EAC3].Unmap(m_DVBStreams[BDA_EAC3].GetMappedPID())); - } - if (m_DVBStreams[BDA_ADTS].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_ADTS].Unmap(m_DVBStreams[BDA_ADTS].GetMappedPID())); - } - if (m_DVBStreams[BDA_LATM].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_LATM].Unmap(m_DVBStreams[BDA_LATM].GetMappedPID())); - } - if (m_DVBStreams[BDA_SUB].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_SUB].Unmap(m_DVBStreams[BDA_SUB].GetMappedPID())); - } - - return hr; -} - -STDMETHODIMP CFGManagerBDA::Scan(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd) -{ - HRESULT hr = S_OK; - - if (ulFrequency == 0 || ulBandwidth == 0) { - ClearMaps(); - } else { - CMpeg2DataParser Parser(m_DVBStreams[BDA_PSI].GetFilter()); - - LOG(_T("Scanning frequency %u.........."), ulFrequency); - - if (tunerIsATSC) { - enum DVB_SI vctType; - if (FAILED(hr = Parser.ParseMGT(vctType)) || SI_undef == vctType) { //try to read MGT to determine type of ATSC - vctType = TID_CVCT; - } - hr = Parser.ParseVCT(ulFrequency, ulBandwidth, ulSymbolRate, vctType); //ATSC - LOG(L"ParseVCT failed. Result: 0x%08x.", hr); - } else { - hr = Parser.ParseSDT(ulFrequency, ulBandwidth, ulSymbolRate); //DVB - LOG(L"ParseSDT failed. Result: 0x%08x.", hr); - } - if (!FAILED(hr)) { - if (FAILED(hr = Parser.ParsePAT())) { - LOG(_T("ParsePAT failed. Result: 0x%08x."), hr); - } else if (FAILED(hr = Parser.ParseNIT())) { - LOG(_T("ParseNIT failed. Result: 0x%08x."), hr); - } - } - - POSITION pos = Parser.Channels.GetStartPosition(); - while (pos) { - CBDAChannel& Channel = Parser.Channels.GetNextValue(pos); - if (Channel.HasName()) { - ::SendMessage(hWnd, WM_TUNER_NEW_CHANNEL, 0, (LPARAM)(LPCTSTR)Channel.ToString()); - } - } - LOG(_T("Scanning frequency %u done."), ulFrequency); - } - - return hr; -} - -STDMETHODIMP CFGManagerBDA::GetStats(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality) -{ - HRESULT hr = S_OK; - CheckPointer(m_pBDATunerStats, E_UNEXPECTED); - CheckPointer(m_pBDADemodStats, E_UNEXPECTED); - - if (FAILED(hr = m_pBDATunerStats->get_SignalPresent(&bPresent)) && FAILED(hr = m_pBDADemodStats->get_SignalPresent(&bPresent))) { - return hr; - } - if (FAILED(hr = m_pBDADemodStats->get_SignalLocked(&bLocked)) && FAILED(hr = m_pBDATunerStats->get_SignalLocked(&bLocked))) { - return hr; - } - if (FAILED(hr = m_pBDATunerStats->get_SignalStrength(&lDbStrength)) && FAILED(hr = m_pBDADemodStats->get_SignalStrength(&lDbStrength))) { - return hr; - } - if (FAILED(hr = m_pBDADemodStats->get_SignalQuality(&lPercentQuality)) && FAILED(hr = m_pBDATunerStats->get_SignalQuality(&lPercentQuality))) { - return hr; - } - - return hr; -} - -// IAMStreamSelect -STDMETHODIMP CFGManagerBDA::Count(DWORD* pcStreams) -{ - CheckPointer(pcStreams, E_POINTER); - CAppSettings& s = AfxGetAppSettings(); - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - - *pcStreams = 0; - - if (pChannel) { - int Streams = pChannel->GetAudioCount() + pChannel->GetSubtitleCount(); - *pcStreams = pChannel->GetSubtitleCount() ? Streams + 1 : Streams; - } - - return S_OK; -} - -STDMETHODIMP CFGManagerBDA::Enable(long lIndex, DWORD dwFlags) -{ - HRESULT hr = E_INVALIDARG; - CAppSettings& s = AfxGetAppSettings(); - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - - if (pChannel) { - if (lIndex >= 0 && lIndex < pChannel->GetAudioCount()) { - BDAStreamInfo* pStreamInfo = pChannel->GetAudio(lIndex); - if (pStreamInfo) { - CDVBStream* pStream = &m_DVBStreams[pStreamInfo->nType]; - if (pStream) { - if (pStream->GetMappedPID()) { - pStream->Unmap(pStream->GetMappedPID()); - } - FILTER_STATE nState = GetState(); - if (m_nCurAudioType != pStreamInfo->nType) { - if ((s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS) && (GetState() != State_Stopped)) { - ChangeState(State_Stopped); - } - SwitchStream(m_nCurAudioType, pStreamInfo->nType); - m_nCurAudioType = pStreamInfo->nType; - CheckNoLog(Flush(m_nCurVideoType, m_nCurAudioType)); - } - pStream->Map(pStreamInfo->ulPID); - ChangeState((FILTER_STATE)nState); - - hr = S_OK; - } else { - ASSERT(FALSE); - } - } else { - ASSERT(FALSE); - } - } else if (lIndex > 0 && lIndex < pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { - BDAStreamInfo* pStreamInfo = pChannel->GetSubtitle(lIndex - pChannel->GetAudioCount()); - - if (pStreamInfo) { - m_DVBStreams[BDA_SUB].Map(pStreamInfo->ulPID); - hr = S_OK; - } - } else if (lIndex > 0 && m_DVBStreams[BDA_SUB].GetMappedPID() && lIndex == pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { - m_DVBStreams[BDA_SUB].Unmap(m_DVBStreams[BDA_SUB].GetMappedPID()); - hr = S_OK; - } - } else { - ASSERT(FALSE); - } - - return hr; -} - -STDMETHODIMP CFGManagerBDA::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) -{ - HRESULT hr = E_INVALIDARG; - CAppSettings& s = AfxGetAppSettings(); - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - BDAStreamInfo* pStreamInfo = nullptr; - CDVBStream* pStream = nullptr; - CDVBStream* pCurrentStream = nullptr; - - if (pChannel) { - if (lIndex >= 0 && lIndex < pChannel->GetAudioCount()) { - pCurrentStream = &m_DVBStreams[m_nCurAudioType]; - pStreamInfo = pChannel->GetAudio(lIndex); - if (pStreamInfo) { - pStream = &m_DVBStreams[pStreamInfo->nType]; - } - if (pdwGroup) { - *pdwGroup = 1; // Audio group - } - } else if (lIndex > 0 && lIndex < pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { - pCurrentStream = &m_DVBStreams[BDA_SUB]; - pStreamInfo = pChannel->GetSubtitle(lIndex - pChannel->GetAudioCount()); - if (pStreamInfo) { - pStream = &m_DVBStreams[pStreamInfo->nType]; - } - if (pdwGroup) { - *pdwGroup = 2; // Subtitle group - } - } else if (lIndex > 0 && lIndex == pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { - pCurrentStream = &m_DVBStreams[BDA_SUB]; - - if (pCurrentStream) { - if (pdwFlags) { - *pdwFlags = (!pCurrentStream->GetMappedPID()) ? AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE : 0; - } - if (plcid) { - *plcid = (LCID)LCID_NOSUBTITLES; - } - if (pdwGroup) { - *pdwGroup = 2; // Subtitle group - } - if (ppszName) { - CStringW str; - str = _T("No subtitles"); - - *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); - if (*ppszName == nullptr) { - return E_OUTOFMEMORY; - } - wcscpy_s(*ppszName, str.GetLength() + 1, str); - } - } - - return S_OK; - } - - if (pStreamInfo && pStream && pCurrentStream) { - if (ppmt) { - const AM_MEDIA_TYPE* pMT = pStream->GetMediaType(); - if (pMT) { - *ppmt = CreateMediaType(pMT); - } else { - *ppmt = nullptr; - return E_FAIL; - } - } - if (pdwFlags) { - *pdwFlags = (pCurrentStream->GetMappedPID() == pStreamInfo->ulPID) ? AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE : 0; - } - if (plcid) { - *plcid = pStreamInfo->GetLCID(); - } - if (ppObject) { - *ppObject = nullptr; - } - if (ppUnk) { - *ppUnk = nullptr; - } - if (ppszName) { - CStringW str; - - str = StreamTypeToName(pStreamInfo->nPesType); - - if (!pStreamInfo->sLanguage.IsEmpty() && pStreamInfo->GetLCID() == 0) { - // Try to convert language code even if LCID was not found. - str += _T(" [") + ISOLang::ISO6392ToLanguage(CStringA(pStreamInfo->sLanguage)) + _T("]"); - } - - *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); - if (*ppszName == nullptr) { - return E_OUTOFMEMORY; - } - wcscpy_s(*ppszName, str.GetLength() + 1, str); - } - - hr = S_OK; - } - } - - return hr; -} - -STDMETHODIMP CFGManagerBDA::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IBDATuner) - QI(IAMStreamSelect) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CFGManagerBDA::CreateMicrosoftDemux(CComPtr& pMpeg2Demux) -{ - CComPtr pDemux; - HRESULT hr; - bool bAudioMPA = false; - bool bAudioAC3 = false; - bool bAudioEAC3 = false; - bool bAudioADTS = false; - bool bAudioLATM = false; - - CheckNoLog(pMpeg2Demux->QueryInterface(IID_PPV_ARGS(&pDemux))); - - LOG(_T("Receiver -> Demux connected.")); - CAppSettings& s = AfxGetAppSettings(); - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - if (pChannel && (m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_ALWAYS)) { - for (int i = 0; i < pChannel->GetAudioCount(); i++) { - switch ((pChannel->GetAudio(i))->nType) { - case BDA_MPA: - bAudioMPA = true; - break; - case BDA_AC3: - bAudioAC3 = true; - break; - case BDA_EAC3: - bAudioEAC3 = true; - break; - case BDA_ADTS: - bAudioADTS = true; - break; - case BDA_LATM: - bAudioLATM = true; - break; - } - } - } else { // All the possible audio filters will be present in the filter graph - bAudioMPA = true; - bAudioAC3 = true; - bAudioEAC3 = true; - bAudioADTS = true; - bAudioLATM = true; - } - - POSITION pos = m_DVBStreams.GetStartPosition(); - while (pos) { - CComPtr pPin; - BDA_STREAM_TYPE nType = m_DVBStreams.GetNextKey(pos); - CDVBStream& Stream = m_DVBStreams[nType]; - - switch (nType) { - case BDA_TIF: - case BDA_PSI: - if (!Stream.GetFindExisting() || - (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { - CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); - } - CheckNoLog(Connect(pPin, nullptr, false)); - Stream.SetPin(pPin); - LOG(_T("Filter connected to Demux for media type %d."), nType); - break; - - case BDA_MPV: - case BDA_H264: - case BDA_HEVC: - if ((nType == m_nCurVideoType) || (m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_NEVER)) { - if (!Stream.GetFindExisting() || - (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { - CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); - } - if (m_nCurVideoType == nType) { - CheckNoLog(Connect(pPin, nullptr, true)); - Stream.SetPin(pPin); - LOG(_T("Graph completed for stream type %d."), nType); - } else { - CheckNoLog(Connect(pPin, nullptr, false)); - Stream.SetPin(pPin); - LOG(_T("Filter connected to Demux for media type %d."), nType); - } - } - break; - - case BDA_MPA: - case BDA_AC3: - case BDA_EAC3: - case BDA_ADTS: - case BDA_LATM: - if ((bAudioMPA && (nType == BDA_MPA)) || (bAudioAC3 && (nType == BDA_AC3)) || - (bAudioEAC3 && (nType == BDA_EAC3)) || (bAudioADTS && (nType == BDA_ADTS)) || (bAudioLATM && (nType == BDA_LATM))) { - if (!Stream.GetFindExisting() || - (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { - CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); - } - if (m_nCurAudioType == nType) { - CheckNoLog(Connect(pPin, nullptr, true)); - Stream.SetPin(pPin); - LOG(_T("Graph completed for stream type %d."), nType); - } else { - CheckNoLog(Connect(pPin, nullptr, false)); - Stream.SetPin(pPin); - LOG(_T("Filter connected to Demux for media type %d."), nType); - } - } - break; - - case BDA_SUB: - if (!Stream.GetFindExisting() || - (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { - CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); - } - CheckNoLog(Connect(pPin, nullptr, false)); - CComPtr pPinTo; - pPin->ConnectedTo(&pPinTo); - CMainFrame* pMainFrame = dynamic_cast(AfxGetApp()->GetMainWnd()); - if (pMainFrame && SUCCEEDED(hr = pMainFrame->InsertTextPassThruFilter(pMpeg2Demux, pPin, pPinTo))) { - Stream.SetPin(pPin); - LOG(_T("Filter connected to Demux for media type %d."), nType); - } else { - LOG(_T("DVB_SUB Filter connection failed. Error 0x%08x."), hr); - } - break; - } - } - - LOG(_T("CreateMicrosoftDemux succeeded.\n")); - - return hr; -} - -HRESULT CFGManagerBDA::SetChannelInternal(CBDAChannel* pChannel) -{ - HRESULT hr = E_ABORT; - bool bRadioToTV = false; - const CAppSettings& s = AfxGetAppSettings(); - ClearMaps(); - - if (s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS && GetState() != State_Stopped) { - ChangeState(State_Stopped); - } - - if (pChannel->GetVideoPID() != 0) { - CComPtr pDemux; - m_pDemux->QueryInterface(IID_PPV_ARGS(&pDemux)); - - if (pChannel->GetVideoType() == BDA_H264) { - UpdateMediaType(&vih2_H264, pChannel); - hr = pDemux->SetOutputPinMediaType(const_cast(L"h264"), const_cast(&mt_H264)); - } else if (pChannel->GetVideoType() == BDA_HEVC) { - UpdateMediaType(&vih2_HEVC, pChannel); - hr = pDemux->SetOutputPinMediaType(const_cast(L"HEVC"), const_cast(&mt_HEVC)); - } else { - UpdateMediaType(&sMpv_fmt, pChannel); - hr = pDemux->SetOutputPinMediaType(const_cast(L"mpv"), const_cast(&mt_Mpv)); - } - if (m_nCurVideoType != pChannel->GetVideoType() || GetState() == State_Stopped) { - if (s.nDVBStopFilterGraph == DVB_STOP_FG_WHEN_SWITCHING && GetState() != State_Stopped) { - ChangeState(State_Stopped); - } - if (FAILED(hr = SwitchStream(m_nCurVideoType, pChannel->GetVideoType()))) { - LOG(_T("Video switchStream failed. Result: 0x%08x"), hr); - return hr; - } - } - - if (m_fHideWindow) { - bRadioToTV = true; - } - } else { - m_fHideWindow = true; - } - - if (m_nCurAudioType != pChannel->GetDefaultAudioType()) { - if (FAILED(hr = SwitchStream(m_nCurAudioType, pChannel->GetDefaultAudioType()))) { - LOG(_T("Audio switchStream failed. Result: 0x%08x"), hr); - return hr; - } - } - - if (GetState() == State_Stopped) { - CheckNoLog(ChangeState(State_Running)); - } - - CheckNoLog(SetFrequency(pChannel->GetFrequency(), pChannel->GetBandwidth(), pChannel->GetSymbolRate())); - - CheckNoLog(Flush(pChannel->GetVideoType(), pChannel->GetDefaultAudioType())); - - if (pChannel->GetVideoPID() != 0) { - CheckNoLog(m_DVBStreams[pChannel->GetVideoType()].Map(pChannel->GetVideoPID())); - } - - CheckNoLog(m_DVBStreams[pChannel->GetDefaultAudioType()].Map(pChannel->GetDefaultAudioPID())); - - if (pChannel->GetSubtitleCount() > 0 && pChannel->GetDefaultSubtitle() != -1 && pChannel->GetDefaultSubtitle() != pChannel->GetSubtitleCount()) { - CheckNoLog(m_DVBStreams[BDA_SUB].Map(pChannel->GetDefaultSubtitlePID())); - } - LOG(_T("Stream maps:")); - LOG(_T("Mapped PID MPEG-2: %u, Mapped PID H.264: %u, Mapped PID HEVC: %u."), - m_DVBStreams[BDA_MPV].GetMappedPID(), m_DVBStreams[BDA_H264].GetMappedPID(), m_DVBStreams[BDA_HEVC].GetMappedPID()); - LOG(_T("Mapped PID MPA: %u, Mapped PID AC3: %u, Mapped PID EAC3: %u, Mapped PID AAC-ADTS: %u, Mapped PID AAC-LATM: %u.") - , m_DVBStreams[BDA_MPA].GetMappedPID(), m_DVBStreams[BDA_AC3].GetMappedPID(), m_DVBStreams[BDA_EAC3].GetMappedPID(), m_DVBStreams[BDA_ADTS].GetMappedPID(), m_DVBStreams[BDA_LATM].GetMappedPID()); - LOG(_T("Mapped PID Subtitles: %u."), m_DVBStreams[BDA_SUB].GetMappedPID()); - - if (bRadioToTV) { - m_fHideWindow = false; - Sleep(1800); - } - - if (CMainFrame* pMainFrame = AfxGetMainFrame()) { - pMainFrame->HideVideoWindow(m_fHideWindow); - } - - return hr; -} - -HRESULT CFGManagerBDA::Flush(BDA_STREAM_TYPE nVideoType, BDA_STREAM_TYPE nAudioType) -{ - HRESULT hr = S_OK; - - CComPtr pFilterSub = m_DVBStreams[BDA_SUB].GetFilter(); - if (pFilterSub) { - CComPtr pSubPinIn = GetFirstPin(pFilterSub, PINDIR_INPUT); - hr = pSubPinIn->BeginFlush(); - hr = pSubPinIn->EndFlush(); - hr = pSubPinIn->NewSegment(0, MAXLONG, 1); - } - CComPtr pFilterAudio = m_DVBStreams[nAudioType].GetFilter(); - if (pFilterAudio) { - CComPtr pAudPinIn = GetFirstPin(pFilterAudio, PINDIR_INPUT); - hr = pAudPinIn->BeginFlush(); - hr = pAudPinIn->EndFlush(); - hr = pAudPinIn->NewSegment(0, MAXLONG, 1); - } - CComPtr pFilterVideo = m_DVBStreams[nVideoType].GetFilter(); - if (pFilterVideo) { - CComPtr pVidPinIn = GetFirstPin(pFilterVideo, PINDIR_INPUT); - hr = pVidPinIn->BeginFlush(); - hr = pVidPinIn->EndFlush(); - hr = pVidPinIn->NewSegment(0, MAXLONG, 1); - } - - return hr; -} - -HRESULT CFGManagerBDA::SwitchStream(BDA_STREAM_TYPE nOldType, BDA_STREAM_TYPE nNewType) -{ - HRESULT hr = S_OK; - CComPtr pFGOld = m_DVBStreams[nOldType].GetFilter(); - CComPtr pFGNew = m_DVBStreams[nNewType].GetFilter(); - CComPtr pOldOut = GetFirstPin(pFGOld, PINDIR_OUTPUT); - CComPtr pInPin; - if (pOldOut && pFGNew) { - pOldOut->ConnectedTo(&pInPin); - if (!pInPin) { - ASSERT(false); - return E_UNEXPECTED; - } - CComPtr pNewOut = GetFirstPin(pFGNew, PINDIR_OUTPUT); - CComPtr pNewOutDynamic; - - if (nNewType != BDA_MPV && nNewType != BDA_H264 && nNewType != BDA_HEVC && GetState() != State_Stopped) { - CComPtr pDemux; - m_pDemux->QueryInterface(IID_PPV_ARGS(&pDemux)); - - switch (nNewType) { - case BDA_MPA: - hr = pDemux->SetOutputPinMediaType(const_cast(L"mpa"), const_cast(&mt_Mpa)); - break; - case BDA_AC3: - hr = pDemux->SetOutputPinMediaType(const_cast(L"ac3"), const_cast(&mt_Ac3)); - break; - case BDA_EAC3: - hr = pDemux->SetOutputPinMediaType(const_cast(L"eac3"), const_cast(&mt_Eac3)); - break; - case BDA_ADTS: - hr = pDemux->SetOutputPinMediaType(const_cast(L"adts"), const_cast(&mt_latm)); - break; - case BDA_LATM: - hr = pDemux->SetOutputPinMediaType(const_cast(L"latm"), const_cast(&mt_latm)); - break; - } - } - - CComPtr pOldOutDynamic; - pOldOut->QueryInterface(IID_PPV_ARGS(&pOldOutDynamic)); - CComPtr pInPinDynamic; - pInPin->QueryInterface(IID_PPV_ARGS(&pInPinDynamic)); - CComPtr pOldOutControl; - if ((GetState() != State_Stopped) && pInPinDynamic && pOldOutDynamic) { // Try dynamic switch - pOldOut->QueryInterface(IID_PPV_ARGS(&pOldOutControl)); - pOldOutControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, nullptr); - CComPtr pGraph; - QueryInterface(IID_PPV_ARGS(&pGraph)); - hr = pGraph->Reconnect(pNewOut, pInPin, nullptr, nullptr, nullptr, AM_GRAPH_CONFIG_RECONNECT_DIRECTCONNECT); - pOldOutControl->Block(0, nullptr); - } else { // Dynamic pins not supported - LOG(_T("Dynamic pin interface not supported.")); - hr = Disconnect(pOldOut); - if (FAILED(hr) && (GetState() != State_Stopped)) { - ChangeState(State_Stopped); - hr = Disconnect(pOldOut); - } - if (SUCCEEDED(hr)) { - hr = Disconnect(pInPin); - if (FAILED(hr) && (GetState() != State_Stopped)) { - ChangeState(State_Stopped); - hr = Disconnect(pInPin); - } - } - if (SUCCEEDED(hr)) { - hr = ConnectDirect(pNewOut, pInPin, nullptr); - if (FAILED(hr) && (GetState() != State_Stopped)) { - ChangeState(State_Stopped); - hr = ConnectDirect(pNewOut, pInPin, nullptr); - } - if (FAILED(hr)) { - hr = E_UNEXPECTED; - } - } - } - } else { - hr = E_POINTER; - ASSERT(FALSE); - } - - LOG(_T("SwitchStream - Stream type: %d. Result: 0x%08x"), nNewType, hr); - - return hr; -} - -void CFGManagerBDA::UpdateMediaType(VIDEOINFOHEADER2* NewVideoHeader, CBDAChannel* pChannel) -{ - NewVideoHeader->AvgTimePerFrame = pChannel->GetAvgTimePerFrame(); - if ((pChannel->GetVideoFps() == BDA_FPS_25_0) || - (pChannel->GetVideoFps() == BDA_FPS_29_97) || - (pChannel->GetVideoFps() == BDA_FPS_30_0)) { - NewVideoHeader->dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_DisplayModeBobOrWeave; - } else { - NewVideoHeader->dwInterlaceFlags = 0; - } - if ((pChannel->GetVideoARx() != 0) && (pChannel->GetVideoARy() != 0)) { - NewVideoHeader->dwPictAspectRatioX = pChannel->GetVideoARx(); - NewVideoHeader->dwPictAspectRatioY = pChannel->GetVideoARy(); - } else { - NewVideoHeader->dwPictAspectRatioX = 16; - NewVideoHeader->dwPictAspectRatioY = 9; - } - - if (pChannel->GetVideoHeight()) { - NewVideoHeader->bmiHeader.biHeight = pChannel->GetVideoHeight(); - NewVideoHeader->bmiHeader.biWidth = pChannel->GetVideoWidth(); - } else { - NewVideoHeader->bmiHeader.biHeight = 576; - NewVideoHeader->bmiHeader.biWidth = 720; - } - - if (NewVideoHeader->dwPictAspectRatioX && NewVideoHeader->dwPictAspectRatioY) { - NewVideoHeader->bmiHeader.biWidth = (LONG)(NewVideoHeader->bmiHeader.biHeight * NewVideoHeader->dwPictAspectRatioX / NewVideoHeader->dwPictAspectRatioY); - } - - NewVideoHeader->rcSource.top = 0; - NewVideoHeader->rcSource.left = 0; - NewVideoHeader->rcSource.right = NewVideoHeader->bmiHeader.biWidth; - NewVideoHeader->rcSource.bottom = NewVideoHeader->bmiHeader.biHeight; - NewVideoHeader->rcTarget.top = 0; - NewVideoHeader->rcTarget.left = 0; - NewVideoHeader->rcTarget.right = 0; - NewVideoHeader->rcTarget.bottom = 0; -} - -HRESULT CFGManagerBDA::UpdatePSI(const CBDAChannel* pChannel, EventDescriptor& NowNext) -{ - HRESULT hr = S_FALSE; - CMpeg2DataParser Parser(m_DVBStreams[BDA_PSI].GetFilter()); - - if (pChannel->GetNowNextFlag()) { - hr = Parser.ParseEIT(pChannel->GetSID(), NowNext); - } - - return hr; -} - -HRESULT CFGManagerBDA::ChangeState(FILTER_STATE nRequested) -{ - HRESULT hr = S_OK; - OAFilterState nState = nRequested + 1; - - CComPtr pMC; - QueryInterface(IID_PPV_ARGS(&pMC)); - pMC->GetState(500, &nState); - if (nState != nRequested) { - CMainFrame* pMainFrame = AfxGetMainFrame(); - switch (nRequested) { - case State_Stopped: { - if (pMainFrame) { - pMainFrame->KillTimersStop(); - } - hr = pMC->Stop(); - LOG(_T("IMediaControl stop: 0x%08x."), hr); - return hr; - } - case State_Paused: { - LOG(_T("IMediaControl pause.")); - return pMC->Pause(); - } - case State_Running: { - if (SUCCEEDED(hr = pMC->Run()) && SUCCEEDED(hr = pMC->GetState(500, &nState)) && nState == State_Running && pMainFrame) { - pMainFrame->SetTimersPlay(); - } - LOG(_T("IMediaControl play: 0x%08x."), hr); - return hr; - } - } - } - return hr; -} - -FILTER_STATE CFGManagerBDA::GetState() -{ - CComPtr pMC; - OAFilterState nState; - QueryInterface(IID_PPV_ARGS(&pMC)); - pMC->GetState(500, &nState); - - return (FILTER_STATE) nState; -} +/* + * (C) 2009-2017 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 . + * + */ + +#include "stdafx.h" +#include "FGManagerBDA.h" +#include "Mpeg2SectionData.h" +#include "MainFrm.h" +#include "Logger.h" +#include +#include +#include +#include +#include +#include + +#define LOG(...) MPCHC_LOG(BDA, __VA_ARGS__) +#define CheckAndLogBDA(x, msg) hr = ##x; if (FAILED(hr)) { LOG(msg _T(": 0x%08x\n"), hr); return hr; } +#define CheckAndLogBDANoRet(x, msg) hr = ##x; if (FAILED(hr)) { LOG(msg _T(": 0x%08x\n"), hr); } + +/// Format, Video MPEG2 +static VIDEOINFOHEADER2 sMpv_fmt = { + {0, 0, 720, 576}, // rcSource + {0, 0, 0, 0}, // rcTarget + 0, // dwBitRate + 0, // dwBitErrorRate + 400000, // AvgTimePerFrame + 0, // dwInterlaceFlags + 0, // dwCopyProtectFlags + 0, // dwPictAspectRatioX + 0, // dwPictAspectRatioY + {0}, // dwControlFlag & dwReserved1 + 0, // dwReserved2 + { + // bmiHeader + sizeof(BITMAPINFOHEADER), // biSize + 720, // biWidth + 576, // biHeight + 0, // biPlanes + 0, // biBitCount + 0 // biCompression + } + // implicitly sets the others fields to 0 +}; + +/// Media type, Video MPEG2 +static const AM_MEDIA_TYPE mt_Mpv = { + MEDIATYPE_Video, // majortype + MEDIASUBTYPE_MPEG2_VIDEO, // subtype + FALSE, // bFixedSizeSamples + TRUE, // bTemporalCompression + 0, // lSampleSize + FORMAT_VideoInfo2, // formattype + nullptr, // pUnk + sizeof(sMpv_fmt), // cbFormat + (LPBYTE)& sMpv_fmt // pbFormat +}; + +/// Format, Video H264 +static VIDEOINFOHEADER2 vih2_H264 = { + {0, 0, 0, 0}, // rcSource + {0, 0, 0, 0}, // rcTarget + 0, // dwBitRate, + 0, // dwBitErrorRate + 0, // AvgTimePerFrame + 0, // dwInterlaceFlags + 0, // dwCopyProtectFlags + 0, // dwPictAspectRatioX + 0, // dwPictAspectRatioY + {0}, // dwControlFlag & dwReserved1 + 0, // dwReserved2 + { + // bmiHeader + sizeof(BITMAPINFOHEADER), // biSize + 720, // biWidth + 576, // biHeight + 1, // biPlanes + 0, // biBitCount + MAKEFOURCC('h', '2', '6', '4') // biCompression + } + // implicitly sets the others fields to 0 +}; + +/// Media type, Video H264 +static const AM_MEDIA_TYPE mt_H264 = { + MEDIATYPE_Video, // majortype + MEDIASUBTYPE_H264, // subtype + FALSE, // bFixedSizeSamples + TRUE, // bTemporalCompression + 0, // lSampleSize + FORMAT_VideoInfo2, // formattype + nullptr, // pUnk + sizeof(vih2_H264), // cbFormat + (LPBYTE)& vih2_H264 // pbFormat +}; + +/// Format, Video HEVC +static VIDEOINFOHEADER2 vih2_HEVC = { + {0, 0, 0, 0}, // rcSource + {0, 0, 0, 0}, // rcTarget + 0, // dwBitRate, + 0, // dwBitErrorRate + 0, // AvgTimePerFrame + 0, // dwInterlaceFlags + 0, // dwCopyProtectFlags + 0, // dwPictAspectRatioX + 0, // dwPictAspectRatioY + {0}, // dwControlFlag & dwReserved1 + 0, // dwReserved2 + { + // bmiHeader + sizeof(BITMAPINFOHEADER), // biSize + 720, // biWidth + 576, // biHeight + 1, // biPlanes + 0, // biBitCount + MAKEFOURCC('H', 'E', 'V', 'C') // biCompression + } + // implicitly sets the others fields to 0 +}; + +/// Media type, Video HEVC +static const AM_MEDIA_TYPE mt_HEVC = { + MEDIATYPE_Video, // majortype + MEDIASUBTYPE_HEVC, // subtype + FALSE, // bFixedSizeSamples + TRUE, // bTemporalCompression + 0, // lSampleSize + FORMAT_VideoInfo2, // formattype + nullptr, // pUnk + sizeof(vih2_HEVC), // cbFormat + (LPBYTE)& vih2_HEVC // pbFormat +}; + +// Format, Audio MPEG2 +static BYTE MPEG2AudioFormat[] = { + 0x50, 0x00, //wFormatTag + 0x02, 0x00, //nChannels + 0x80, 0xbb, 0x00, 0x00, //nSamplesPerSec + 0x00, 0x7d, 0x00, 0x00, //nAvgBytesPerSec + 0x01, 0x00, //nBlockAlign + 0x00, 0x00, //wBitsPerSample + 0x16, 0x00, //cbSize + 0x02, 0x00, //wValidBitsPerSample + 0x00, 0xe8, //wSamplesPerBlock + 0x03, 0x00, //wReserved + 0x01, 0x00, 0x01, 0x00, //dwChannelMask + 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Format, Audio (E)AC3 +static BYTE AC3AudioFormat[] = { + 0x00, 0x20, //wFormatTag + 0x06, 0x00, //nChannels + 0x80, 0xBB, 0x00, 0x00, //nSamplesPerSec + 0xC0, 0x5D, 0x00, 0x00, //nAvgBytesPerSec + 0x00, 0x03, //nBlockAlign + 0x00, 0x00, //wBitsPerSample + 0x00, 0x00 //cbSize +}; + +// Format, Audio AAC +static BYTE AACAudioFormat[] = { + 0xFF, 0x00, //wFormatTag + 0x02, 0x00, //nChannels + 0x80, 0xBB, 0x00, 0x00, //nSamplesPerSec + 0xCE, 0x3E, 0x00, 0x00, //nAvgBytesPerSec + 0xAE, 0x02, //nBlockAlign + 0x00, 0x00, //wBitsPerSample + 0x02, 0x00, //cbSize + 0x11, 0x90 +}; + +/// Media type, Audio MPEG2 +static const AM_MEDIA_TYPE mt_Mpa = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_MPEG2_AUDIO, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(MPEG2AudioFormat), // cbFormat + MPEG2AudioFormat // pbFormat +}; + +/// Media type, Audio AC3 +static const AM_MEDIA_TYPE mt_Ac3 = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_DOLBY_AC3, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(AC3AudioFormat), // cbFormat + AC3AudioFormat, // pbFormat +}; + +/// Media type, Audio EAC3 +static const AM_MEDIA_TYPE mt_Eac3 = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_DOLBY_DDPLUS, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(AC3AudioFormat), // cbFormat + AC3AudioFormat, // pbFormat +}; + +/// Media type, Audio AAC ADTS +static const AM_MEDIA_TYPE mt_adts = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_MPEG_ADTS_AAC, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(AACAudioFormat), // cbFormat + AACAudioFormat, // pbFormat +}; + +/// Media type, Audio AAC LATM +static const AM_MEDIA_TYPE mt_latm = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_LATM_AAC, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(AACAudioFormat), // cbFormat + AACAudioFormat, // pbFormat +}; + +/// Media type, PSI +static const AM_MEDIA_TYPE mt_Psi = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_MPEG2DATA, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr // pbFormat +}; + +/// Media type, TIF +static const AM_MEDIA_TYPE mt_DVB_Tif = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_DVB_SI, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr // pbFormat +}; + +/// Media type, EPG +static const AM_MEDIA_TYPE mt_DVB_Epg = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_DVB_SI, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr, // pbFormat +}; + +/// Media type, TIF +static const AM_MEDIA_TYPE mt_ATSC_Tif = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_ATSC_SI, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr // pbFormat +}; + +/// Media type, EPG +static const AM_MEDIA_TYPE mt_ATSC_Epg = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_ATSC_SI, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr, // pbFormat +}; + +static const SUBTITLEINFO SubFormat = { 0, "", L"" }; + +/// Media type, subtitle +static const AM_MEDIA_TYPE mt_Subtitle = { + MEDIATYPE_Subtitle, // majortype + MEDIASUBTYPE_DVB_SUBTITLES, // subtype + FALSE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + sizeof(SubFormat), // cbFormat + (LPBYTE)& SubFormat // pbFormat +}; + +/// CLSID for TIF +// FC772AB0-0C7F-11D3-8FF2-00A0C9224CF4 +static const CLSID CLSID_BDA_MPEG2_TIF = +{0xFC772AB0, 0x0C7F, 0x11D3, {0x8F, 0xF2, 0x00, 0xA0, 0xC9, 0x22, 0x4C, 0xF4}}; + +CFGManagerBDA::CFGManagerBDA(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd) + : CFGManagerPlayer(pName, pUnk, hWnd) +{ + LOG(_T("---------------------------------------------------------------->")); + LOG(_T("Starting session...")); + + CAppSettings& s = AfxGetAppSettings(); + m_nDVBRebuildFilterGraph = s.nDVBRebuildFilterGraph; + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + + if (pChannel) { + if (pChannel->GetVideoType() == BDA_H264) { + UpdateMediaType(&vih2_H264, pChannel); + } else if (pChannel->GetVideoType() == BDA_HEVC) { + UpdateMediaType(&vih2_HEVC, pChannel); + } else if (pChannel->GetVideoType() == BDA_MPV) { + UpdateMediaType(&sMpv_fmt, pChannel); + } + } + + tunerIsATSC = false; + BeginEnumSysDev(KSCATEGORY_BDA_NETWORK_TUNER, pMoniker) { + CComHeapPtr strName; + if (SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName)) ) { + if (s.strBDATuner == CString(strName)) { + CComPtr pPB; + pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)); + CComVariant var; + if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + CString fName = CString(var.bstrVal); + if (fName.Find(_T("ATSC")) > -1) { //hack to identify an ATSC tuner. better solution might be to check the tuner capabilities, but this should be good enough + tunerIsATSC = true; + } + } + } + } + } + EndEnumSysDev; + + m_DVBStreams[BDA_MPV] = CDVBStream(L"mpv", &mt_Mpv); + m_DVBStreams[BDA_H264] = CDVBStream(L"h264", &mt_H264); + m_DVBStreams[BDA_HEVC] = CDVBStream(L"HEVC", &mt_HEVC); + m_DVBStreams[BDA_MPA] = CDVBStream(L"mpa", &mt_Mpa); + m_DVBStreams[BDA_AC3] = CDVBStream(L"ac3", &mt_Ac3); + m_DVBStreams[BDA_EAC3] = CDVBStream(L"eac3", &mt_Eac3); + m_DVBStreams[BDA_ADTS] = CDVBStream(L"adts", &mt_adts); + m_DVBStreams[BDA_LATM] = CDVBStream(L"latm", &mt_latm); + m_DVBStreams[BDA_PSI] = CDVBStream(L"psi", &mt_Psi, true, MEDIA_MPEG2_PSI); + if (tunerIsATSC) { + m_DVBStreams[BDA_TIF] = CDVBStream(L"tif", &mt_ATSC_Tif, true); + m_DVBStreams[BDA_EPG] = CDVBStream(L"epg", &mt_ATSC_Epg); + } else { + m_DVBStreams[BDA_TIF] = CDVBStream(L"tif", &mt_DVB_Tif, true); + m_DVBStreams[BDA_EPG] = CDVBStream(L"epg", &mt_DVB_Epg); + } + m_DVBStreams[BDA_SUB] = CDVBStream(L"sub", &mt_Subtitle/*, false, MEDIA_TRANSPORT_PAYLOAD*/); + + if (pChannel) { + m_nCurVideoType = pChannel->GetVideoType(); + m_nCurAudioType = pChannel->GetDefaultAudioType(); + } else { + m_nCurVideoType = BDA_MPV; + m_nCurAudioType = BDA_MPA; + } + m_fHideWindow = false; + + // Blacklist some unsupported filters (AddHead must be used to ensure higher priority): + // - audio switcher + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(__uuidof(CAudioSwitcherFilter), MERIT64_DO_NOT_USE)); + // - internal video decoder and ffdshow DXVA video decoder (cf ticket #730) + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_MPCVideoDecoder, MERIT64_DO_NOT_USE)); + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_FFDShowDXVADecoder, MERIT64_DO_NOT_USE)); + // - Microsoft DTV-DVD Audio Decoder + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_MSDVTDVDAudioDecoder, MERIT64_DO_NOT_USE)); + // - ACM Wrapper + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_ACMWrapper, MERIT64_DO_NOT_USE)); + // - ReClock + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_ReClock, MERIT64_DO_NOT_USE)); + + LOG(_T("CFGManagerBDA object created.")); +} + +CFGManagerBDA::~CFGManagerBDA() +{ + m_DVBStreams.RemoveAll(); + LOG(_T("CFGManagerBDA object destroyed.")); + LOG(_T("<----------------------------------------------------------------\n\n")); +} + +HRESULT CFGManagerBDA::CreateKSFilterFN(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& FriendlyName) { + HRESULT hr = VFW_E_NOT_FOUND; + BeginEnumSysDev(KSCategory, pMoniker) { + CComPtr pPB; + CComVariant var; + if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB))) && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + CStringW fName = CStringW(var.bstrVal); + if (fName != FriendlyName) { + continue; + } + + hr = pMoniker->BindToObject(nullptr, nullptr, IID_PPV_ARGS(ppBF)); + if (SUCCEEDED(hr)) { + hr = AddFilter(*ppBF, fName); + } + break; + } + } + EndEnumSysDev; + + return hr; +} + + +HRESULT CFGManagerBDA::CreateKSFilter(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& DisplayName) +{ + HRESULT hr = VFW_E_NOT_FOUND; + BeginEnumSysDev(KSCategory, pMoniker) { + CComPtr pPB; + CComVariant var; + CComHeapPtr strName; + if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB))) && + SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName)) && + SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + CStringW Name = strName; + if (Name != DisplayName) { + continue; + } + + hr = pMoniker->BindToObject(nullptr, nullptr, IID_PPV_ARGS(ppBF)); + if (SUCCEEDED(hr)) { + hr = AddFilter(*ppBF, CStringW(var.bstrVal)); + } + break; + } + } + EndEnumSysDev; + + return hr; +} + +HRESULT CFGManagerBDA::SearchIBDATopology(const CComPtr& pTuner, REFIID iid, CComPtr& pUnk) +{ + CComQIPtr pTop(pTuner); + CheckPointer(pTop, E_NOINTERFACE); + + ULONG NodeTypes = 0; + ULONG NodeType[32]; + + HRESULT hr = pTop->GetNodeTypes(&NodeTypes, _countof(NodeType), NodeType); + + if (FAILED(hr)) { + return hr; + } + + for (ULONG i = 0; i < NodeTypes; i++) { + ULONG nInterfaces; + GUID aInterface[32]; + + hr = pTop->GetNodeInterfaces(NodeType[i], &nInterfaces, _countof(aInterface), aInterface); + + if (FAILED(hr)) { + continue; + } + + for (ULONG j = 0; j < nInterfaces; j++) { + if (aInterface[j] == iid) { + return pTop->GetControlNode(0, 1, NodeType[i], &pUnk); + } + } + } + + return FAILED(hr) ? hr : E_NOINTERFACE; +} + +HRESULT CFGManagerBDA::ConnectFilters(IBaseFilter* pOutFilter, IBaseFilter* pInFilter) +{ + HRESULT hr = VFW_E_CANNOT_CONNECT; + BeginEnumPins(pOutFilter, pEP, pOutPin) { + if (S_OK == IsPinDirection(pOutPin, PINDIR_OUTPUT) + && S_OK != IsPinConnected(pOutPin)) { + BeginEnumPins(pInFilter, pEP2, pInPin) { + if (S_OK == IsPinDirection(pInPin, PINDIR_INPUT) + && S_OK != IsPinConnected(pInPin)) { + hr = this->ConnectDirect(pOutPin, pInPin, nullptr); + +#if 0 && defined(_DEBUG) // Disabled by default because it can be verbose + CPinInfo infoPinIn, infoPinOut; + infoPinIn.achName[0] = infoPinOut.achName[0] = L'\0'; + CFilterInfo infoFilterIn, infoFilterOut; + infoFilterIn.achName[0] = infoFilterOut.achName[0] = L'\0'; + + pInPin->QueryPinInfo(&infoPinIn); + if (infoPinIn.pFilter) { + infoPinIn.pFilter->QueryFilterInfo(&infoFilterIn); + } + pOutPin->QueryPinInfo(&infoPinOut); + if (infoPinOut.pFilter) { + infoPinOut.pFilter->QueryFilterInfo(&infoFilterOut); + } + + TRACE(_T("%s - %s => %s - %s (hr=0x%08x)\n"), infoFilterOut.achName, infoPinOut.achName, infoFilterIn.achName, infoPinIn.achName, hr); +#endif + + if (SUCCEEDED(hr)) { + return hr; + } + } + } + EndEnumPins; + } + } + EndEnumPins; + + return hr; +} + +STDMETHODIMP CFGManagerBDA::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) +{ + HRESULT hr; + const CAppSettings& s = AfxGetAppSettings(); + CComPtr pNetwork; + CComPtr pTuner; + CComPtr pReceiver; + + LOG(_T("Creating BDA filters...")); + CheckAndLogBDA(CreateKSFilterFN(&pNetwork, KSCATEGORY_BDA_NETWORK_PROVIDER, _T("Microsoft Network Provider")), _T("Network provider creation")); + if (FAILED(hr = CreateKSFilter(&pTuner, KSCATEGORY_BDA_NETWORK_TUNER, s.strBDATuner))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CREATE_TUNER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Network tuner creation: 0x%08x\n"), hr); + LOG(_T("Network tuner creation: 0x%08x"), hr); + return hr; + } + + if (FAILED(hr = ConnectFilters(pNetwork, pTuner))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CONNECT_TUNER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Network <-> Tuner: 0x%08x\n"), hr); + LOG(_T("Network <-> Tuner: 0x%08x"), hr); + return hr; + } + m_pBDAControl = pTuner; + + if (FAILED(hr = SearchIBDATopology(pTuner, m_pBDAFreq))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, _T("IBDA_FrequencyFilter topology failed."), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + LOG(_T("IBDA_FrequencyFilter topology failed.")); + return hr; + } + m_pBDATunerStats = m_pBDAFreq; + if (FAILED(hr = SearchIBDATopology(pTuner, m_pBDADemodulator))) { + TRACE(_T("BDA: IBDA_DigitalDemodulator topology failed: 0x%08x\n"), hr); + LOG(_T("IBDA_DigitalDemodulator topology failed. Result 0x%08x"), hr); + } + m_pBDADemodStats = m_pBDADemodulator; + + if (!m_pBDATunerStats || !m_pBDADemodStats) { + if (m_pBDATunerStats) { + TRACE(_T("BDA: no statistics interface on the demodulator node --> using the statistics from the RF node only\n")); + LOG(_T("No statistics interface on the demodulator node --> using the statistics from the RF node only.")); + m_pBDADemodStats = m_pBDATunerStats; + } else if (m_pBDADemodStats) { + TRACE(_T("BDA: no statistics interface on the RF node --> using the statistics from the demodulator node only\n")); + LOG(_T("No statistics interface on the RF node --> using the statistics from the demodulator node only.")); + m_pBDATunerStats = m_pBDADemodStats; + } else { // if (!m_pBDATunerStats && !m_pBDADemodStats) + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, _T("No statistics interface available."), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Not statistics interface available\n")); + LOG(_T("Not statistics interface available.")); + return E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr = SearchIBDATopology(pTuner, m_pBDAAutoDemulate))) { + if (SUCCEEDED(hr = m_pBDAAutoDemulate->put_AutoDemodulate())) { + LOG(_T("Auto Demulate is on.")); + } else { + LOG(_T("Auto Demulate could not be switched: 0x%08x."), hr); + } + } else { + LOG(_T("AutoDemulate topology not found.")); + TRACE(_T("BDA: AutoDemulate topology not found: 0x%08x\n"), hr); + } + + if (FAILED(hr = m_pDemux.CoCreateInstance(CLSID_MPEG2Demultiplexer, nullptr, CLSCTX_INPROC_SERVER))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_DEMULTIPLEXER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Microsoft demux creation: 0x%08x\n"), hr); + return hr; + } + CheckNoLog(AddFilter(m_pDemux, _T("MPEG-2 Demultiplexer"))); + if (FAILED(ConnectFilters(pTuner, m_pDemux))) { // Separate receiver is required + if (FAILED(hr = CreateKSFilter(&pReceiver, KSCATEGORY_BDA_RECEIVER_COMPONENT, s.strBDAReceiver))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CREATE_RECEIVER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Receiver creation: 0x%08x\n"), hr); + return hr; + } + if (FAILED(hr = ConnectFilters(pTuner, pReceiver))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CONNECT_TUNER_REC), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Tuner <-> Receiver: 0x%08x\n"), hr); + return hr; + } + if (FAILED(ConnectFilters(pReceiver, m_pDemux))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_DEMULTIPLEXER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Receiver <-> Demux: 0x%08x\n"), hr); + return hr; + } + LOG(_T("Network -> Tuner -> Receiver connected.")); + + } else { // The selected filter is performing both tuner and receiver functions + LOG(_T("Network -> Receiver connected.")); + } + + CheckNoLog(CreateMicrosoftDemux(m_pDemux)); + +#ifdef _DEBUG + LOG(_T("Filter list:")); + BeginEnumFilters(this, pEF, pBF) { + LOG(_T(" ") + GetFilterName(pBF)); + } + EndEnumFilters; + LOG(_T("Filter list end.\n")); +#endif + + return hr; +} + +STDMETHODIMP CFGManagerBDA::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) +{ + // Bypass CFGManagerPlayer limitation (IMediaSeeking for Mpeg2 demux) + return CFGManagerCustom::ConnectDirect(pPinOut, pPinIn, pmt); +} + +STDMETHODIMP CFGManagerBDA::SetChannel(int nChannelPrefNumber) +{ + HRESULT hr = E_INVALIDARG; + CAppSettings& s = AfxGetAppSettings(); + + CBDAChannel* pChannel = s.FindChannelByPref(nChannelPrefNumber); + LOG(_T("Start SetChannel %d."), nChannelPrefNumber); + if (pChannel) { + if (!((m_nCurAudioType == BDA_UNKNOWN) ^ (pChannel->GetDefaultAudioType() == BDA_UNKNOWN)) && + ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_NEVER) || + ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_WHEN_SWITCHING) && (m_nCurVideoType == pChannel->GetVideoType())) || + ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_ALWAYS) && (s.nDVBLastChannel == nChannelPrefNumber)))) { + hr = SetChannelInternal(pChannel); + } else { + s.nDVBLastChannel = nChannelPrefNumber; + return S_FALSE; + } + + if (SUCCEEDED(hr)) { + s.nDVBLastChannel = nChannelPrefNumber; + m_nCurVideoType = pChannel->GetVideoType(); + m_nCurAudioType = pChannel->GetDefaultAudioType(); + LOG(_T("SetChannel %d successful.\n"), nChannelPrefNumber); + } else { + LOG(_T("SetChannel %d failed. Result: 0x%08x.\n"), nChannelPrefNumber, hr); + } + } + return hr; +} + +STDMETHODIMP CFGManagerBDA::SetAudio(int nAudioIndex) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CFGManagerBDA::SetFrequency(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) +{ + HRESULT hr; + LOG(_T("Frequency %lu, Bandwidth %lu, SymbolRate %lu"), ulFrequency, ulBandwidth, ulSymbolRate); + CheckPointer(m_pBDAControl, E_FAIL); + CheckPointer(m_pBDAFreq, E_FAIL); + + CheckAndLogBDA(m_pBDAControl->StartChanges(), _T(" SetFrequency StartChanges")); + if (ulSymbolRate != 0) { + CheckAndLogBDANoRet(m_pBDADemodulator->put_SymbolRate(&ulSymbolRate), _T(" SetFrequency put_SymbolRate")); + } + CheckAndLogBDANoRet(m_pBDAFreq->put_FrequencyMultiplier(1000), _T(" SetFrequency put_FrequencyMultiplier")); + CheckAndLogBDANoRet(m_pBDAFreq->put_Bandwidth(ulBandwidth / 1000), _T(" SetFrequency put_Bandwidth")); + CheckAndLogBDA(m_pBDAFreq->put_Frequency(ulFrequency), _T(" SetFrequency put_Frequency")); + CheckAndLogBDA(m_pBDAControl->CheckChanges(), _T(" SetFrequency CheckChanges")); + CheckAndLogBDA(m_pBDAControl->CommitChanges(), _T(" SetFrequency CommitChanges")); + + int i = 50; + ULONG pState = BDA_CHANGES_PENDING; + while (SUCCEEDED(hr = m_pBDAControl->GetChangeState(&pState)) && pState == BDA_CHANGES_PENDING && i-- > 0) { + LOG(_T("changes pending, waiting for tuner...")); + Sleep(50); + } + + if (SUCCEEDED(hr)) { + if (pState == BDA_CHANGES_PENDING) { + LOG(_T("changes pending (timeout error----)")); + hr = VFW_E_TIMEOUT; + } else { + LOG(_T("Frequency changed: %lu / %lu."), ulFrequency, ulBandwidth); +#ifdef _DEBUG + BOOLEAN bPresent; + BOOLEAN bLocked; + LONG lDbStrength; + LONG lPercentQuality; + + if (SUCCEEDED(GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { + LOG(_T("Signal stats: Strength %ld dB, Quality %ld%%"), lDbStrength, lPercentQuality); + } +#endif + } + } else { + LOG(_T("Frequency change failed. Result: 0x%08x."), hr); + } + + return hr; +} + +HRESULT CFGManagerBDA::ClearMaps() +{ + HRESULT hr = S_OK; + + if (m_DVBStreams[BDA_MPV].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_MPV].Unmap(m_DVBStreams[BDA_MPV].GetMappedPID())); + } + if (m_DVBStreams[BDA_H264].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_H264].Unmap(m_DVBStreams[BDA_H264].GetMappedPID())); + } + if (m_DVBStreams[BDA_HEVC].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_HEVC].Unmap(m_DVBStreams[BDA_HEVC].GetMappedPID())); + } + if (m_DVBStreams[BDA_MPA].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_MPA].Unmap(m_DVBStreams[BDA_MPA].GetMappedPID())); + } + if (m_DVBStreams[BDA_AC3].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_AC3].Unmap(m_DVBStreams[BDA_AC3].GetMappedPID())); + } + if (m_DVBStreams[BDA_EAC3].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_EAC3].Unmap(m_DVBStreams[BDA_EAC3].GetMappedPID())); + } + if (m_DVBStreams[BDA_ADTS].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_ADTS].Unmap(m_DVBStreams[BDA_ADTS].GetMappedPID())); + } + if (m_DVBStreams[BDA_LATM].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_LATM].Unmap(m_DVBStreams[BDA_LATM].GetMappedPID())); + } + if (m_DVBStreams[BDA_SUB].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_SUB].Unmap(m_DVBStreams[BDA_SUB].GetMappedPID())); + } + + return hr; +} + +STDMETHODIMP CFGManagerBDA::Scan(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd) +{ + HRESULT hr = S_OK; + + if (ulFrequency == 0 || ulBandwidth == 0) { + ClearMaps(); + } else { + CMpeg2DataParser Parser(m_DVBStreams[BDA_PSI].GetFilter()); + + LOG(_T("Scanning frequency %u.........."), ulFrequency); + + if (tunerIsATSC) { + enum DVB_SI vctType; + if (FAILED(hr = Parser.ParseMGT(vctType)) || SI_undef == vctType) { //try to read MGT to determine type of ATSC + vctType = TID_CVCT; + } + hr = Parser.ParseVCT(ulFrequency, ulBandwidth, ulSymbolRate, vctType); //ATSC + LOG(L"ParseVCT failed. Result: 0x%08x.", hr); + } else { + hr = Parser.ParseSDT(ulFrequency, ulBandwidth, ulSymbolRate); //DVB + LOG(L"ParseSDT failed. Result: 0x%08x.", hr); + } + if (!FAILED(hr)) { + if (FAILED(hr = Parser.ParsePAT())) { + LOG(_T("ParsePAT failed. Result: 0x%08x."), hr); + } else if (FAILED(hr = Parser.ParseNIT())) { + LOG(_T("ParseNIT failed. Result: 0x%08x."), hr); + } + } + + POSITION pos = Parser.Channels.GetStartPosition(); + while (pos) { + CBDAChannel& Channel = Parser.Channels.GetNextValue(pos); + if (Channel.HasName()) { + ::SendMessage(hWnd, WM_TUNER_NEW_CHANNEL, 0, (LPARAM)(LPCTSTR)Channel.ToString()); + } + } + LOG(_T("Scanning frequency %u done."), ulFrequency); + } + + return hr; +} + +STDMETHODIMP CFGManagerBDA::GetStats(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality) +{ + HRESULT hr = S_OK; + CheckPointer(m_pBDATunerStats, E_UNEXPECTED); + CheckPointer(m_pBDADemodStats, E_UNEXPECTED); + + if (FAILED(hr = m_pBDATunerStats->get_SignalPresent(&bPresent)) && FAILED(hr = m_pBDADemodStats->get_SignalPresent(&bPresent))) { + return hr; + } + if (FAILED(hr = m_pBDADemodStats->get_SignalLocked(&bLocked)) && FAILED(hr = m_pBDATunerStats->get_SignalLocked(&bLocked))) { + return hr; + } + if (FAILED(hr = m_pBDATunerStats->get_SignalStrength(&lDbStrength)) && FAILED(hr = m_pBDADemodStats->get_SignalStrength(&lDbStrength))) { + return hr; + } + if (FAILED(hr = m_pBDADemodStats->get_SignalQuality(&lPercentQuality)) && FAILED(hr = m_pBDATunerStats->get_SignalQuality(&lPercentQuality))) { + return hr; + } + + return hr; +} + +// IAMStreamSelect +STDMETHODIMP CFGManagerBDA::Count(DWORD* pcStreams) +{ + CheckPointer(pcStreams, E_POINTER); + CAppSettings& s = AfxGetAppSettings(); + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + + *pcStreams = 0; + + if (pChannel) { + int Streams = pChannel->GetAudioCount() + pChannel->GetSubtitleCount(); + *pcStreams = pChannel->GetSubtitleCount() ? Streams + 1 : Streams; + } + + return S_OK; +} + +STDMETHODIMP CFGManagerBDA::Enable(long lIndex, DWORD dwFlags) +{ + HRESULT hr = E_INVALIDARG; + CAppSettings& s = AfxGetAppSettings(); + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + + if (pChannel) { + if (lIndex >= 0 && lIndex < pChannel->GetAudioCount()) { + BDAStreamInfo* pStreamInfo = pChannel->GetAudio(lIndex); + if (pStreamInfo) { + CDVBStream* pStream = &m_DVBStreams[pStreamInfo->nType]; + if (pStream) { + if (pStream->GetMappedPID()) { + pStream->Unmap(pStream->GetMappedPID()); + } + FILTER_STATE nState = GetState(); + if (m_nCurAudioType != pStreamInfo->nType) { + if ((s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS) && (GetState() != State_Stopped)) { + ChangeState(State_Stopped); + } + SwitchStream(m_nCurAudioType, pStreamInfo->nType); + m_nCurAudioType = pStreamInfo->nType; + CheckNoLog(Flush(m_nCurVideoType, m_nCurAudioType)); + } + pStream->Map(pStreamInfo->ulPID); + ChangeState((FILTER_STATE)nState); + + hr = S_OK; + } else { + ASSERT(FALSE); + } + } else { + ASSERT(FALSE); + } + } else if (lIndex > 0 && lIndex < pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { + BDAStreamInfo* pStreamInfo = pChannel->GetSubtitle(lIndex - pChannel->GetAudioCount()); + + if (pStreamInfo) { + m_DVBStreams[BDA_SUB].Map(pStreamInfo->ulPID); + hr = S_OK; + } + } else if (lIndex > 0 && m_DVBStreams[BDA_SUB].GetMappedPID() && lIndex == pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { + m_DVBStreams[BDA_SUB].Unmap(m_DVBStreams[BDA_SUB].GetMappedPID()); + hr = S_OK; + } + } else { + ASSERT(FALSE); + } + + return hr; +} + +STDMETHODIMP CFGManagerBDA::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) +{ + HRESULT hr = E_INVALIDARG; + CAppSettings& s = AfxGetAppSettings(); + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + BDAStreamInfo* pStreamInfo = nullptr; + CDVBStream* pStream = nullptr; + CDVBStream* pCurrentStream = nullptr; + + if (pChannel) { + if (lIndex >= 0 && lIndex < pChannel->GetAudioCount()) { + pCurrentStream = &m_DVBStreams[m_nCurAudioType]; + pStreamInfo = pChannel->GetAudio(lIndex); + if (pStreamInfo) { + pStream = &m_DVBStreams[pStreamInfo->nType]; + } + if (pdwGroup) { + *pdwGroup = 1; // Audio group + } + } else if (lIndex > 0 && lIndex < pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { + pCurrentStream = &m_DVBStreams[BDA_SUB]; + pStreamInfo = pChannel->GetSubtitle(lIndex - pChannel->GetAudioCount()); + if (pStreamInfo) { + pStream = &m_DVBStreams[pStreamInfo->nType]; + } + if (pdwGroup) { + *pdwGroup = 2; // Subtitle group + } + } else if (lIndex > 0 && lIndex == pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { + pCurrentStream = &m_DVBStreams[BDA_SUB]; + + if (pCurrentStream) { + if (pdwFlags) { + *pdwFlags = (!pCurrentStream->GetMappedPID()) ? AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE : 0; + } + if (plcid) { + *plcid = (LCID)LCID_NOSUBTITLES; + } + if (pdwGroup) { + *pdwGroup = 2; // Subtitle group + } + if (ppszName) { + CStringW str; + str = _T("No subtitles"); + + *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); + if (*ppszName == nullptr) { + return E_OUTOFMEMORY; + } + wcscpy_s(*ppszName, str.GetLength() + 1, str); + } + } + + return S_OK; + } + + if (pStreamInfo && pStream && pCurrentStream) { + if (ppmt) { + const AM_MEDIA_TYPE* pMT = pStream->GetMediaType(); + if (pMT) { + *ppmt = CreateMediaType(pMT); + } else { + *ppmt = nullptr; + return E_FAIL; + } + } + if (pdwFlags) { + *pdwFlags = (pCurrentStream->GetMappedPID() == pStreamInfo->ulPID) ? AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE : 0; + } + if (plcid) { + *plcid = pStreamInfo->GetLCID(); + } + if (ppObject) { + *ppObject = nullptr; + } + if (ppUnk) { + *ppUnk = nullptr; + } + if (ppszName) { + CStringW str; + + str = StreamTypeToName(pStreamInfo->nPesType); + + if (!pStreamInfo->sLanguage.IsEmpty() && pStreamInfo->GetLCID() == 0) { + // Try to convert language code even if LCID was not found. + str += _T(" [") + ISOLang::ISO6392ToLanguage(CStringA(pStreamInfo->sLanguage)) + _T("]"); + } + + *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); + if (*ppszName == nullptr) { + return E_OUTOFMEMORY; + } + wcscpy_s(*ppszName, str.GetLength() + 1, str); + } + + hr = S_OK; + } + } + + return hr; +} + +STDMETHODIMP CFGManagerBDA::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IBDATuner) + QI(IAMStreamSelect) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CFGManagerBDA::CreateMicrosoftDemux(CComPtr& pMpeg2Demux) +{ + CComPtr pDemux; + HRESULT hr; + bool bAudioMPA = false; + bool bAudioAC3 = false; + bool bAudioEAC3 = false; + bool bAudioADTS = false; + bool bAudioLATM = false; + + CheckNoLog(pMpeg2Demux->QueryInterface(IID_PPV_ARGS(&pDemux))); + + LOG(_T("Receiver -> Demux connected.")); + CAppSettings& s = AfxGetAppSettings(); + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + if (pChannel && (m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_ALWAYS)) { + for (int i = 0; i < pChannel->GetAudioCount(); i++) { + switch ((pChannel->GetAudio(i))->nType) { + case BDA_MPA: + bAudioMPA = true; + break; + case BDA_AC3: + bAudioAC3 = true; + break; + case BDA_EAC3: + bAudioEAC3 = true; + break; + case BDA_ADTS: + bAudioADTS = true; + break; + case BDA_LATM: + bAudioLATM = true; + break; + } + } + } else { // All the possible audio filters will be present in the filter graph + bAudioMPA = true; + bAudioAC3 = true; + bAudioEAC3 = true; + bAudioADTS = true; + bAudioLATM = true; + } + + POSITION pos = m_DVBStreams.GetStartPosition(); + while (pos) { + CComPtr pPin; + BDA_STREAM_TYPE nType = m_DVBStreams.GetNextKey(pos); + CDVBStream& Stream = m_DVBStreams[nType]; + + switch (nType) { + case BDA_TIF: + case BDA_PSI: + if (!Stream.GetFindExisting() || + (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { + CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); + } + CheckNoLog(Connect(pPin, nullptr, false)); + Stream.SetPin(pPin); + LOG(_T("Filter connected to Demux for media type %d."), nType); + break; + + case BDA_MPV: + case BDA_H264: + case BDA_HEVC: + if ((nType == m_nCurVideoType) || (m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_NEVER)) { + if (!Stream.GetFindExisting() || + (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { + CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); + } + if (m_nCurVideoType == nType) { + CheckNoLog(Connect(pPin, nullptr, true)); + Stream.SetPin(pPin); + LOG(_T("Graph completed for stream type %d."), nType); + } else { + CheckNoLog(Connect(pPin, nullptr, false)); + Stream.SetPin(pPin); + LOG(_T("Filter connected to Demux for media type %d."), nType); + } + } + break; + + case BDA_MPA: + case BDA_AC3: + case BDA_EAC3: + case BDA_ADTS: + case BDA_LATM: + if ((bAudioMPA && (nType == BDA_MPA)) || (bAudioAC3 && (nType == BDA_AC3)) || + (bAudioEAC3 && (nType == BDA_EAC3)) || (bAudioADTS && (nType == BDA_ADTS)) || (bAudioLATM && (nType == BDA_LATM))) { + if (!Stream.GetFindExisting() || + (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { + CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); + } + if (m_nCurAudioType == nType) { + CheckNoLog(Connect(pPin, nullptr, true)); + Stream.SetPin(pPin); + LOG(_T("Graph completed for stream type %d."), nType); + } else { + CheckNoLog(Connect(pPin, nullptr, false)); + Stream.SetPin(pPin); + LOG(_T("Filter connected to Demux for media type %d."), nType); + } + } + break; + + case BDA_SUB: + if (!Stream.GetFindExisting() || + (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { + CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); + } + CheckNoLog(Connect(pPin, nullptr, false)); + CComPtr pPinTo; + pPin->ConnectedTo(&pPinTo); + CMainFrame* pMainFrame = dynamic_cast(AfxGetApp()->GetMainWnd()); + if (pMainFrame && SUCCEEDED(hr = pMainFrame->InsertTextPassThruFilter(pMpeg2Demux, pPin, pPinTo))) { + Stream.SetPin(pPin); + LOG(_T("Filter connected to Demux for media type %d."), nType); + } else { + LOG(_T("DVB_SUB Filter connection failed. Error 0x%08x."), hr); + } + break; + } + } + + LOG(_T("CreateMicrosoftDemux succeeded.\n")); + + return hr; +} + +HRESULT CFGManagerBDA::SetChannelInternal(CBDAChannel* pChannel) +{ + HRESULT hr = E_ABORT; + bool bRadioToTV = false; + const CAppSettings& s = AfxGetAppSettings(); + ClearMaps(); + + if (s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS && GetState() != State_Stopped) { + ChangeState(State_Stopped); + } + + if (pChannel->GetVideoPID() != 0) { + CComPtr pDemux; + m_pDemux->QueryInterface(IID_PPV_ARGS(&pDemux)); + + if (pChannel->GetVideoType() == BDA_H264) { + UpdateMediaType(&vih2_H264, pChannel); + hr = pDemux->SetOutputPinMediaType(const_cast(L"h264"), const_cast(&mt_H264)); + } else if (pChannel->GetVideoType() == BDA_HEVC) { + UpdateMediaType(&vih2_HEVC, pChannel); + hr = pDemux->SetOutputPinMediaType(const_cast(L"HEVC"), const_cast(&mt_HEVC)); + } else { + UpdateMediaType(&sMpv_fmt, pChannel); + hr = pDemux->SetOutputPinMediaType(const_cast(L"mpv"), const_cast(&mt_Mpv)); + } + if (m_nCurVideoType != pChannel->GetVideoType() || GetState() == State_Stopped) { + if (s.nDVBStopFilterGraph == DVB_STOP_FG_WHEN_SWITCHING && GetState() != State_Stopped) { + ChangeState(State_Stopped); + } + if (FAILED(hr = SwitchStream(m_nCurVideoType, pChannel->GetVideoType()))) { + LOG(_T("Video switchStream failed. Result: 0x%08x"), hr); + return hr; + } + } + + if (m_fHideWindow) { + bRadioToTV = true; + } + } else { + m_fHideWindow = true; + } + + if (m_nCurAudioType != pChannel->GetDefaultAudioType()) { + if (FAILED(hr = SwitchStream(m_nCurAudioType, pChannel->GetDefaultAudioType()))) { + LOG(_T("Audio switchStream failed. Result: 0x%08x"), hr); + return hr; + } + } + + if (GetState() == State_Stopped) { + CheckNoLog(ChangeState(State_Running)); + } + + CheckNoLog(SetFrequency(pChannel->GetFrequency(), pChannel->GetBandwidth(), pChannel->GetSymbolRate())); + + CheckNoLog(Flush(pChannel->GetVideoType(), pChannel->GetDefaultAudioType())); + + if (pChannel->GetVideoPID() != 0) { + CheckNoLog(m_DVBStreams[pChannel->GetVideoType()].Map(pChannel->GetVideoPID())); + } + + CheckNoLog(m_DVBStreams[pChannel->GetDefaultAudioType()].Map(pChannel->GetDefaultAudioPID())); + + if (pChannel->GetSubtitleCount() > 0 && pChannel->GetDefaultSubtitle() != -1 && pChannel->GetDefaultSubtitle() != pChannel->GetSubtitleCount()) { + CheckNoLog(m_DVBStreams[BDA_SUB].Map(pChannel->GetDefaultSubtitlePID())); + } + LOG(_T("Stream maps:")); + LOG(_T("Mapped PID MPEG-2: %u, Mapped PID H.264: %u, Mapped PID HEVC: %u."), + m_DVBStreams[BDA_MPV].GetMappedPID(), m_DVBStreams[BDA_H264].GetMappedPID(), m_DVBStreams[BDA_HEVC].GetMappedPID()); + LOG(_T("Mapped PID MPA: %u, Mapped PID AC3: %u, Mapped PID EAC3: %u, Mapped PID AAC-ADTS: %u, Mapped PID AAC-LATM: %u.") + , m_DVBStreams[BDA_MPA].GetMappedPID(), m_DVBStreams[BDA_AC3].GetMappedPID(), m_DVBStreams[BDA_EAC3].GetMappedPID(), m_DVBStreams[BDA_ADTS].GetMappedPID(), m_DVBStreams[BDA_LATM].GetMappedPID()); + LOG(_T("Mapped PID Subtitles: %u."), m_DVBStreams[BDA_SUB].GetMappedPID()); + + if (bRadioToTV) { + m_fHideWindow = false; + Sleep(1800); + } + + if (CMainFrame* pMainFrame = AfxGetMainFrame()) { + pMainFrame->HideVideoWindow(m_fHideWindow); + } + + return hr; +} + +HRESULT CFGManagerBDA::Flush(BDA_STREAM_TYPE nVideoType, BDA_STREAM_TYPE nAudioType) +{ + HRESULT hr = S_OK; + + CComPtr pFilterSub = m_DVBStreams[BDA_SUB].GetFilter(); + if (pFilterSub) { + CComPtr pSubPinIn = GetFirstPin(pFilterSub, PINDIR_INPUT); + hr = pSubPinIn->BeginFlush(); + hr = pSubPinIn->EndFlush(); + hr = pSubPinIn->NewSegment(0, MAXLONG, 1); + } + CComPtr pFilterAudio = m_DVBStreams[nAudioType].GetFilter(); + if (pFilterAudio) { + CComPtr pAudPinIn = GetFirstPin(pFilterAudio, PINDIR_INPUT); + hr = pAudPinIn->BeginFlush(); + hr = pAudPinIn->EndFlush(); + hr = pAudPinIn->NewSegment(0, MAXLONG, 1); + } + CComPtr pFilterVideo = m_DVBStreams[nVideoType].GetFilter(); + if (pFilterVideo) { + CComPtr pVidPinIn = GetFirstPin(pFilterVideo, PINDIR_INPUT); + hr = pVidPinIn->BeginFlush(); + hr = pVidPinIn->EndFlush(); + hr = pVidPinIn->NewSegment(0, MAXLONG, 1); + } + + return hr; +} + +HRESULT CFGManagerBDA::SwitchStream(BDA_STREAM_TYPE nOldType, BDA_STREAM_TYPE nNewType) +{ + HRESULT hr = S_OK; + CComPtr pFGOld = m_DVBStreams[nOldType].GetFilter(); + CComPtr pFGNew = m_DVBStreams[nNewType].GetFilter(); + CComPtr pOldOut = GetFirstPin(pFGOld, PINDIR_OUTPUT); + CComPtr pInPin; + if (pOldOut && pFGNew) { + pOldOut->ConnectedTo(&pInPin); + if (!pInPin) { + ASSERT(false); + return E_UNEXPECTED; + } + CComPtr pNewOut = GetFirstPin(pFGNew, PINDIR_OUTPUT); + CComPtr pNewOutDynamic; + + if (nNewType != BDA_MPV && nNewType != BDA_H264 && nNewType != BDA_HEVC && GetState() != State_Stopped) { + CComPtr pDemux; + m_pDemux->QueryInterface(IID_PPV_ARGS(&pDemux)); + + switch (nNewType) { + case BDA_MPA: + hr = pDemux->SetOutputPinMediaType(const_cast(L"mpa"), const_cast(&mt_Mpa)); + break; + case BDA_AC3: + hr = pDemux->SetOutputPinMediaType(const_cast(L"ac3"), const_cast(&mt_Ac3)); + break; + case BDA_EAC3: + hr = pDemux->SetOutputPinMediaType(const_cast(L"eac3"), const_cast(&mt_Eac3)); + break; + case BDA_ADTS: + hr = pDemux->SetOutputPinMediaType(const_cast(L"adts"), const_cast(&mt_latm)); + break; + case BDA_LATM: + hr = pDemux->SetOutputPinMediaType(const_cast(L"latm"), const_cast(&mt_latm)); + break; + } + } + + CComPtr pOldOutDynamic; + pOldOut->QueryInterface(IID_PPV_ARGS(&pOldOutDynamic)); + CComPtr pInPinDynamic; + pInPin->QueryInterface(IID_PPV_ARGS(&pInPinDynamic)); + CComPtr pOldOutControl; + if ((GetState() != State_Stopped) && pInPinDynamic && pOldOutDynamic) { // Try dynamic switch + pOldOut->QueryInterface(IID_PPV_ARGS(&pOldOutControl)); + pOldOutControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, nullptr); + CComPtr pGraph; + QueryInterface(IID_PPV_ARGS(&pGraph)); + hr = pGraph->Reconnect(pNewOut, pInPin, nullptr, nullptr, nullptr, AM_GRAPH_CONFIG_RECONNECT_DIRECTCONNECT); + pOldOutControl->Block(0, nullptr); + } else { // Dynamic pins not supported + LOG(_T("Dynamic pin interface not supported.")); + hr = Disconnect(pOldOut); + if (FAILED(hr) && (GetState() != State_Stopped)) { + ChangeState(State_Stopped); + hr = Disconnect(pOldOut); + } + if (SUCCEEDED(hr)) { + hr = Disconnect(pInPin); + if (FAILED(hr) && (GetState() != State_Stopped)) { + ChangeState(State_Stopped); + hr = Disconnect(pInPin); + } + } + if (SUCCEEDED(hr)) { + hr = ConnectDirect(pNewOut, pInPin, nullptr); + if (FAILED(hr) && (GetState() != State_Stopped)) { + ChangeState(State_Stopped); + hr = ConnectDirect(pNewOut, pInPin, nullptr); + } + if (FAILED(hr)) { + hr = E_UNEXPECTED; + } + } + } + } else { + hr = E_POINTER; + ASSERT(FALSE); + } + + LOG(_T("SwitchStream - Stream type: %d. Result: 0x%08x"), nNewType, hr); + + return hr; +} + +void CFGManagerBDA::UpdateMediaType(VIDEOINFOHEADER2* NewVideoHeader, CBDAChannel* pChannel) +{ + NewVideoHeader->AvgTimePerFrame = pChannel->GetAvgTimePerFrame(); + if ((pChannel->GetVideoFps() == BDA_FPS_25_0) || + (pChannel->GetVideoFps() == BDA_FPS_29_97) || + (pChannel->GetVideoFps() == BDA_FPS_30_0)) { + NewVideoHeader->dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_DisplayModeBobOrWeave; + } else { + NewVideoHeader->dwInterlaceFlags = 0; + } + if ((pChannel->GetVideoARx() != 0) && (pChannel->GetVideoARy() != 0)) { + NewVideoHeader->dwPictAspectRatioX = pChannel->GetVideoARx(); + NewVideoHeader->dwPictAspectRatioY = pChannel->GetVideoARy(); + } else { + NewVideoHeader->dwPictAspectRatioX = 16; + NewVideoHeader->dwPictAspectRatioY = 9; + } + + if (pChannel->GetVideoHeight()) { + NewVideoHeader->bmiHeader.biHeight = pChannel->GetVideoHeight(); + NewVideoHeader->bmiHeader.biWidth = pChannel->GetVideoWidth(); + } else { + NewVideoHeader->bmiHeader.biHeight = 576; + NewVideoHeader->bmiHeader.biWidth = 720; + } + + if (NewVideoHeader->dwPictAspectRatioX && NewVideoHeader->dwPictAspectRatioY) { + NewVideoHeader->bmiHeader.biWidth = (LONG)(NewVideoHeader->bmiHeader.biHeight * NewVideoHeader->dwPictAspectRatioX / NewVideoHeader->dwPictAspectRatioY); + } + + NewVideoHeader->rcSource.top = 0; + NewVideoHeader->rcSource.left = 0; + NewVideoHeader->rcSource.right = NewVideoHeader->bmiHeader.biWidth; + NewVideoHeader->rcSource.bottom = NewVideoHeader->bmiHeader.biHeight; + NewVideoHeader->rcTarget.top = 0; + NewVideoHeader->rcTarget.left = 0; + NewVideoHeader->rcTarget.right = 0; + NewVideoHeader->rcTarget.bottom = 0; +} + +HRESULT CFGManagerBDA::UpdatePSI(const CBDAChannel* pChannel, EventDescriptor& NowNext) +{ + HRESULT hr = S_FALSE; + CMpeg2DataParser Parser(m_DVBStreams[BDA_PSI].GetFilter()); + + if (pChannel->GetNowNextFlag()) { + hr = Parser.ParseEIT(pChannel->GetSID(), NowNext); + } + + return hr; +} + +HRESULT CFGManagerBDA::ChangeState(FILTER_STATE nRequested) +{ + HRESULT hr = S_OK; + OAFilterState nState = nRequested + 1; + + CComPtr pMC; + QueryInterface(IID_PPV_ARGS(&pMC)); + pMC->GetState(500, &nState); + if (nState != nRequested) { + CMainFrame* pMainFrame = AfxGetMainFrame(); + switch (nRequested) { + case State_Stopped: { + if (pMainFrame) { + pMainFrame->KillTimersStop(); + } + hr = pMC->Stop(); + LOG(_T("IMediaControl stop: 0x%08x."), hr); + return hr; + } + case State_Paused: { + LOG(_T("IMediaControl pause.")); + return pMC->Pause(); + } + case State_Running: { + if (SUCCEEDED(hr = pMC->Run()) && SUCCEEDED(hr = pMC->GetState(500, &nState)) && nState == State_Running && pMainFrame) { + pMainFrame->SetTimersPlay(); + } + LOG(_T("IMediaControl play: 0x%08x."), hr); + return hr; + } + } + } + return hr; +} + +FILTER_STATE CFGManagerBDA::GetState() +{ + CComPtr pMC; + OAFilterState nState; + QueryInterface(IID_PPV_ARGS(&pMC)); + pMC->GetState(500, &nState); + + return (FILTER_STATE) nState; +} diff --git a/src/mpc-hc/FGManagerBDA.h b/src/mpc-hc/FGManagerBDA.h index e05895de459..b0000e1e8a4 100644 --- a/src/mpc-hc/FGManagerBDA.h +++ b/src/mpc-hc/FGManagerBDA.h @@ -1,178 +1,178 @@ -/* - * (C) 2009-2017 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 . - * - */ - -#pragma once - -#include "FGManager.h" -#include "DVBChannel.h" -#include - -enum DVB_RebuildFilterGraph; -typedef struct tagVIDEOINFOHEADER2 VIDEOINFOHEADER2; - -class CDVBStream -{ -public: - CDVBStream() - : m_pmt(0) - , m_bFindExisting(false) - , m_Name(L"") - , m_nMsc(MEDIA_TRANSPORT_PACKET) - , m_ulMappedPID(0) { - } - - CDVBStream(LPCWSTR strName, const AM_MEDIA_TYPE* pmt, bool bFindExisting = false, MEDIA_SAMPLE_CONTENT nMsc = MEDIA_ELEMENTARY_STREAM) - : m_pmt(pmt) - , m_bFindExisting(bFindExisting) - , m_Name(strName) - , m_nMsc(nMsc) - , m_ulMappedPID(0) { - } - - LPCWSTR GetName() const { return m_Name; }; - const AM_MEDIA_TYPE* GetMediaType() { return m_pmt; }; - bool GetFindExisting() const { return m_bFindExisting; }; - IBaseFilter* GetFilter() { return m_pFilter; }; - - void SetPin(IPin* pPin) { - CComPtr pPinOut; - PIN_INFO PinInfo; - - m_pMap = pPin; - if (m_pMap && - SUCCEEDED(pPin->ConnectedTo(&pPinOut)) && - SUCCEEDED(pPinOut->QueryPinInfo(&PinInfo))) { - m_pFilter.Attach(PinInfo.pFilter); - } - } - - HRESULT Map(ULONG ulPID) { - CheckPointer(m_pMap, E_UNEXPECTED); - ClearMaps(); - m_ulMappedPID = ulPID; - return m_pMap->MapPID(1, &ulPID, m_nMsc); - } - - HRESULT Unmap(ULONG ulPID) { - CheckPointer(m_pMap, E_UNEXPECTED); - m_ulMappedPID = 0; - return m_pMap->UnmapPID(1, &ulPID); - } - - ULONG GetMappedPID() const { return m_ulMappedPID; } - -private: - CComQIPtr m_pMap; - CComPtr m_pFilter; - const AM_MEDIA_TYPE* m_pmt; - bool m_bFindExisting; - LPCWSTR m_Name; - MEDIA_SAMPLE_CONTENT m_nMsc; - ULONG m_ulMappedPID; - - void ClearMaps() { - CComPtr pEnumMap; - - if (SUCCEEDED(m_pMap->EnumPIDMap(&pEnumMap))) { - PID_MAP maps[8]; - ULONG nbPids = 0; - ZeroMemory(maps, sizeof(maps)); - - if (pEnumMap->Next(_countof(maps), maps, &nbPids) == S_OK) { - for (ULONG i = 0; i < nbPids; i++) { - ULONG pid = maps[i].ulPID; - - m_pMap->UnmapPID(1, &pid); - } - } - } - } -}; - -class CFGManagerBDA : public CFGManagerPlayer, IBDATuner, IAMStreamSelect -{ -public: - CFGManagerBDA(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd); - ~CFGManagerBDA(); - - // IGraphBuilder - STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); - - // IFilterGraph - STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); - - // IBDATuner - STDMETHODIMP SetChannel(int nChannelPrefNumber); - STDMETHODIMP SetAudio(int nAudioIndex); - STDMETHODIMP SetFrequency(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate); - STDMETHODIMP Scan(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd); - STDMETHODIMP GetStats(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality); - - // IAMStreamSelect - STDMETHODIMP Count(DWORD* pcStreams); - STDMETHODIMP Enable(long lIndex, DWORD dwFlags); - STDMETHODIMP Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - STDMETHODIMP UpdatePSI(const CBDAChannel* pChannel, EventDescriptor& NowNext); - -private: - - CComQIPtr m_pBDAControl; - CComPtr m_pBDAFreq; - CComQIPtr m_pBDATunerStats; - CComPtr m_pBDADemodulator; - CComQIPtr m_pBDADemodStats; - CComPtr m_pBDAAutoDemulate; - DVB_RebuildFilterGraph m_nDVBRebuildFilterGraph; - CAtlMap m_DVBStreams; - bool tunerIsATSC; - - BDA_STREAM_TYPE m_nCurVideoType; - BDA_STREAM_TYPE m_nCurAudioType; - bool m_fHideWindow; - CComPtr m_pDemux; - - HRESULT CreateKSFilter(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& DisplayName); - HRESULT CreateKSFilterFN(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& FriendlyName); - HRESULT ConnectFilters(IBaseFilter* pOutFiter, IBaseFilter* pInFilter); - HRESULT CreateMicrosoftDemux(CComPtr& pMpeg2Demux); - HRESULT SetChannelInternal(CBDAChannel* pChannel); - HRESULT SwitchStream(BDA_STREAM_TYPE nOldType, BDA_STREAM_TYPE nNewType); - HRESULT ChangeState(FILTER_STATE nRequested); - HRESULT ClearMaps(); - FILTER_STATE GetState(); - void UpdateMediaType(VIDEOINFOHEADER2* NewVideoHeader, CBDAChannel* pChannel); - HRESULT Flush(BDA_STREAM_TYPE nVideoType, BDA_STREAM_TYPE nAudioType); - - template - HRESULT SearchIBDATopology(const CComPtr& pTuner, CComPtr& pItf) { - CComPtr pUnk; - HRESULT hr = SearchIBDATopology(pTuner, __uuidof(ITF), pUnk); - - if (SUCCEEDED(hr)) { - hr = pUnk.QueryInterface(&pItf); - } - return !pItf ? E_NOINTERFACE : hr; - } - - HRESULT SearchIBDATopology(const CComPtr& pTuner, REFIID iid, CComPtr& pUnk); -}; +/* + * (C) 2009-2017 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 . + * + */ + +#pragma once + +#include "FGManager.h" +#include "DVBChannel.h" +#include + +enum DVB_RebuildFilterGraph; +typedef struct tagVIDEOINFOHEADER2 VIDEOINFOHEADER2; + +class CDVBStream +{ +public: + CDVBStream() + : m_pmt(0) + , m_bFindExisting(false) + , m_Name(L"") + , m_nMsc(MEDIA_TRANSPORT_PACKET) + , m_ulMappedPID(0) { + } + + CDVBStream(LPCWSTR strName, const AM_MEDIA_TYPE* pmt, bool bFindExisting = false, MEDIA_SAMPLE_CONTENT nMsc = MEDIA_ELEMENTARY_STREAM) + : m_pmt(pmt) + , m_bFindExisting(bFindExisting) + , m_Name(strName) + , m_nMsc(nMsc) + , m_ulMappedPID(0) { + } + + LPCWSTR GetName() const { return m_Name; }; + const AM_MEDIA_TYPE* GetMediaType() { return m_pmt; }; + bool GetFindExisting() const { return m_bFindExisting; }; + IBaseFilter* GetFilter() { return m_pFilter; }; + + void SetPin(IPin* pPin) { + CComPtr pPinOut; + PIN_INFO PinInfo; + + m_pMap = pPin; + if (m_pMap && + SUCCEEDED(pPin->ConnectedTo(&pPinOut)) && + SUCCEEDED(pPinOut->QueryPinInfo(&PinInfo))) { + m_pFilter.Attach(PinInfo.pFilter); + } + } + + HRESULT Map(ULONG ulPID) { + CheckPointer(m_pMap, E_UNEXPECTED); + ClearMaps(); + m_ulMappedPID = ulPID; + return m_pMap->MapPID(1, &ulPID, m_nMsc); + } + + HRESULT Unmap(ULONG ulPID) { + CheckPointer(m_pMap, E_UNEXPECTED); + m_ulMappedPID = 0; + return m_pMap->UnmapPID(1, &ulPID); + } + + ULONG GetMappedPID() const { return m_ulMappedPID; } + +private: + CComQIPtr m_pMap; + CComPtr m_pFilter; + const AM_MEDIA_TYPE* m_pmt; + bool m_bFindExisting; + LPCWSTR m_Name; + MEDIA_SAMPLE_CONTENT m_nMsc; + ULONG m_ulMappedPID; + + void ClearMaps() { + CComPtr pEnumMap; + + if (SUCCEEDED(m_pMap->EnumPIDMap(&pEnumMap))) { + PID_MAP maps[8]; + ULONG nbPids = 0; + ZeroMemory(maps, sizeof(maps)); + + if (pEnumMap->Next(_countof(maps), maps, &nbPids) == S_OK) { + for (ULONG i = 0; i < nbPids; i++) { + ULONG pid = maps[i].ulPID; + + m_pMap->UnmapPID(1, &pid); + } + } + } + } +}; + +class CFGManagerBDA : public CFGManagerPlayer, IBDATuner, IAMStreamSelect +{ +public: + CFGManagerBDA(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd); + ~CFGManagerBDA(); + + // IGraphBuilder + STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); + + // IFilterGraph + STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); + + // IBDATuner + STDMETHODIMP SetChannel(int nChannelPrefNumber); + STDMETHODIMP SetAudio(int nAudioIndex); + STDMETHODIMP SetFrequency(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate); + STDMETHODIMP Scan(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd); + STDMETHODIMP GetStats(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality); + + // IAMStreamSelect + STDMETHODIMP Count(DWORD* pcStreams); + STDMETHODIMP Enable(long lIndex, DWORD dwFlags); + STDMETHODIMP Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + STDMETHODIMP UpdatePSI(const CBDAChannel* pChannel, EventDescriptor& NowNext); + +private: + + CComQIPtr m_pBDAControl; + CComPtr m_pBDAFreq; + CComQIPtr m_pBDATunerStats; + CComPtr m_pBDADemodulator; + CComQIPtr m_pBDADemodStats; + CComPtr m_pBDAAutoDemulate; + DVB_RebuildFilterGraph m_nDVBRebuildFilterGraph; + CAtlMap m_DVBStreams; + bool tunerIsATSC; + + BDA_STREAM_TYPE m_nCurVideoType; + BDA_STREAM_TYPE m_nCurAudioType; + bool m_fHideWindow; + CComPtr m_pDemux; + + HRESULT CreateKSFilter(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& DisplayName); + HRESULT CreateKSFilterFN(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& FriendlyName); + HRESULT ConnectFilters(IBaseFilter* pOutFiter, IBaseFilter* pInFilter); + HRESULT CreateMicrosoftDemux(CComPtr& pMpeg2Demux); + HRESULT SetChannelInternal(CBDAChannel* pChannel); + HRESULT SwitchStream(BDA_STREAM_TYPE nOldType, BDA_STREAM_TYPE nNewType); + HRESULT ChangeState(FILTER_STATE nRequested); + HRESULT ClearMaps(); + FILTER_STATE GetState(); + void UpdateMediaType(VIDEOINFOHEADER2* NewVideoHeader, CBDAChannel* pChannel); + HRESULT Flush(BDA_STREAM_TYPE nVideoType, BDA_STREAM_TYPE nAudioType); + + template + HRESULT SearchIBDATopology(const CComPtr& pTuner, CComPtr& pItf) { + CComPtr pUnk; + HRESULT hr = SearchIBDATopology(pTuner, __uuidof(ITF), pUnk); + + if (SUCCEEDED(hr)) { + hr = pUnk.QueryInterface(&pItf); + } + return !pItf ? E_NOINTERFACE : hr; + } + + HRESULT SearchIBDATopology(const CComPtr& pTuner, REFIID iid, CComPtr& pUnk); +}; diff --git a/src/mpc-hc/FakeFilterMapper2.cpp b/src/mpc-hc/FakeFilterMapper2.cpp index f2065a39851..a197be23763 100644 --- a/src/mpc-hc/FakeFilterMapper2.cpp +++ b/src/mpc-hc/FakeFilterMapper2.cpp @@ -1,718 +1,718 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "FakeFilterMapper2.h" -#include "MacrovisionKicker.h" -#include "DSUtil.h" - -#include "MhookHelper.h" - - -HRESULT(__stdcall* Real_CoCreateInstance)(CONST IID& a0, - LPUNKNOWN a1, - DWORD a2, - CONST IID& a3, - LPVOID* a4) - = CoCreateInstance; - -LONG(WINAPI* Real_RegCreateKeyExA)(HKEY a0, - LPCSTR a1, - DWORD a2, - LPSTR a3, - DWORD a4, - REGSAM a5, - LPSECURITY_ATTRIBUTES a6, - PHKEY a7, - LPDWORD a8) - = RegCreateKeyExA; - -LONG(WINAPI* Real_RegCreateKeyExW)(HKEY a0, - LPCWSTR a1, - DWORD a2, - LPWSTR a3, - DWORD a4, - REGSAM a5, - LPSECURITY_ATTRIBUTES a6, - PHKEY a7, - LPDWORD a8) - = RegCreateKeyExW; - -LONG(WINAPI* Real_RegDeleteKeyA)(HKEY a0, - LPCSTR a1) - = RegDeleteKeyA; - -LONG(WINAPI* Real_RegDeleteKeyW)(HKEY a0, - LPCWSTR a1) - = RegDeleteKeyW; - -LONG(WINAPI* Real_RegDeleteValueA)(HKEY a0, - LPCSTR a1) - = RegDeleteValueA; - - -LONG(WINAPI* Real_RegDeleteValueW)(HKEY a0, - LPCWSTR a1) - = RegDeleteValueW; - -LONG(WINAPI* Real_RegEnumKeyExA)(HKEY a0, - DWORD a1, - LPSTR a2, - LPDWORD a3, - LPDWORD a4, - LPSTR a5, - LPDWORD a6, - struct _FILETIME* a7) - = RegEnumKeyExA; - -LONG(WINAPI* Real_RegEnumKeyExW)(HKEY a0, - DWORD a1, - LPWSTR a2, - LPDWORD a3, - LPDWORD a4, - LPWSTR a5, - LPDWORD a6, - struct _FILETIME* a7) - = RegEnumKeyExW; - -LONG(WINAPI* Real_RegEnumValueA)(HKEY a0, - DWORD a1, - LPSTR a2, - LPDWORD a3, - LPDWORD a4, - LPDWORD a5, - LPBYTE a6, - LPDWORD a7) - = RegEnumValueA; - -LONG(WINAPI* Real_RegEnumValueW)(HKEY a0, - DWORD a1, - LPWSTR a2, - LPDWORD a3, - LPDWORD a4, - LPDWORD a5, - LPBYTE a6, - LPDWORD a7) - = RegEnumValueW; - -LONG(WINAPI* Real_RegOpenKeyExA)(HKEY a0, - LPCSTR a1, - DWORD a2, - REGSAM a3, - PHKEY a4) - = RegOpenKeyExA; - -LONG(WINAPI* Real_RegOpenKeyExW)(HKEY a0, - LPCWSTR a1, - DWORD a2, - REGSAM a3, - PHKEY a4) - = RegOpenKeyExW; - -LONG(WINAPI* Real_RegQueryInfoKeyA)(HKEY a0, - LPSTR a1, - LPDWORD a2, - LPDWORD a3, - LPDWORD a4, - LPDWORD a5, - LPDWORD a6, - LPDWORD a7, - LPDWORD a8, - LPDWORD a9, - LPDWORD a10, - struct _FILETIME* a11) - = RegQueryInfoKeyA; - -LONG(WINAPI* Real_RegQueryInfoKeyW)(HKEY a0, - LPWSTR a1, - LPDWORD a2, - LPDWORD a3, - LPDWORD a4, - LPDWORD a5, - LPDWORD a6, - LPDWORD a7, - LPDWORD a8, - LPDWORD a9, - LPDWORD a10, - struct _FILETIME* a11) - = RegQueryInfoKeyW; - -LONG(WINAPI* Real_RegQueryValueExA)(HKEY a0, - LPCSTR a1, - LPDWORD a2, - LPDWORD a3, - LPBYTE a4, - LPDWORD a5) - = RegQueryValueExA; - -LONG(WINAPI* Real_RegQueryValueExW)(HKEY a0, - LPCWSTR a1, - LPDWORD a2, - LPDWORD a3, - LPBYTE a4, - LPDWORD a5) - = RegQueryValueExW; - -LONG(WINAPI* Real_RegSetValueExA)(HKEY a0, - LPCSTR a1, - DWORD a2, - DWORD a3, - const BYTE* a4, - DWORD a5) - = RegSetValueExA; - -LONG(WINAPI* Real_RegSetValueExW)(HKEY a0, - LPCWSTR a1, - DWORD a2, - DWORD a3, - const BYTE* a4, - DWORD a5) - = RegSetValueExW; - - -LONG(WINAPI* Real_RegCloseKey)(HKEY a0) - = RegCloseKey; - -LONG(WINAPI* Real_RegFlushKey)(HKEY a0) - = RegFlushKey; - -LONG(WINAPI* Real_RegCreateKeyA)(HKEY a0, LPCSTR a1, PHKEY a2) - = RegCreateKeyA; - -LONG(WINAPI* Real_RegCreateKeyW)(HKEY a0, LPCWSTR a1, PHKEY a2) - = RegCreateKeyW; - -LONG(WINAPI* Real_RegOpenKeyA)(HKEY a0, LPCSTR a1, PHKEY a2) - = RegOpenKeyA; - -LONG(WINAPI* Real_RegOpenKeyW)(HKEY a0, LPCWSTR a1, PHKEY a2) - = RegOpenKeyW; - -LONG(WINAPI* Real_RegQueryValueA)(HKEY a0, LPCSTR a1, LPSTR a2, PLONG a3) - = RegQueryValueA; - -LONG(WINAPI* Real_RegQueryValueW)(HKEY a0, LPCWSTR a1, LPWSTR a2, PLONG a3) - = RegQueryValueW; - -LONG(WINAPI* Real_RegSetValueW)(HKEY a0, LPCWSTR a1, DWORD a2, LPCWSTR a3, DWORD a4) - = RegSetValueW; - -LONG(WINAPI* Real_RegSetValueA)(HKEY a0, LPCSTR a1, DWORD a2, LPCSTR a3, DWORD a4) - = RegSetValueA; - - - -HRESULT WINAPI Mine_CoCreateInstance(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, - IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID FAR* ppv) -{ - if (CFilterMapper2::s_pFilterMapper2) { - CheckPointer(ppv, E_POINTER); - - if (rclsid == CLSID_FilterMapper) { - ASSERT(FALSE); - return REGDB_E_CLASSNOTREG; // sorry... - } - - if (rclsid == CLSID_FilterMapper2) { - if (pUnkOuter) { - return CLASS_E_NOAGGREGATION; - } - - if (riid == __uuidof(IUnknown)) { - CFilterMapper2::s_pFilterMapper2->AddRef(); - *ppv = (IUnknown*)CFilterMapper2::s_pFilterMapper2; - return S_OK; - } else if (riid == __uuidof(IFilterMapper2)) { - CFilterMapper2::s_pFilterMapper2->AddRef(); - *ppv = (IFilterMapper2*)CFilterMapper2::s_pFilterMapper2; - return S_OK; - } else { - return E_NOINTERFACE; - } - } - } - /* else - { - if (rclsid == CLSID_FilterMapper2) - { - CFilterMapper2* pFM2 = DEBUG_NEW CFilterMapper2(true, false, pUnkOuter); - CComPtr pUnk = (IUnknown*)pFM2; - return pUnk->QueryInterface(riid, ppv); - } - } - */ - if (!pUnkOuter) - if (rclsid == CLSID_VideoMixingRenderer || rclsid == CLSID_VideoMixingRenderer9 - || rclsid == CLSID_VideoRenderer || rclsid == CLSID_VideoRendererDefault - || rclsid == CLSID_OverlayMixer) { // || rclsid == CLSID_OverlayMixer2 - where is this declared?) - CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; - CComPtr pInner; - - if (SUCCEEDED(Real_CoCreateInstance(rclsid, pUnk, dwClsContext, IID_PPV_ARGS(&pInner)))) { - pMK->SetInner(pInner); - return pUnk->QueryInterface(riid, ppv); - } - } - - return Real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); -} - -#define FAKEHKEY (HKEY)0x12345678 - -LONG WINAPI Mine_RegCloseKey(HKEY a0) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_SUCCESS; - } - return Real_RegCloseKey(a0); -} - -LONG WINAPI Mine_RegFlushKey(HKEY a0) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_SUCCESS; - } - return Real_RegFlushKey(a0); -} - -LONG WINAPI Mine_RegCreateKeyA(HKEY a0, LPCSTR a1, PHKEY a2) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a2 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegCreateKeyA(a0, a1, a2); -} - -LONG WINAPI Mine_RegCreateKeyW(HKEY a0, LPCWSTR a1, PHKEY a2) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a2 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegCreateKeyW(a0, a1, a2); -} - -LONG WINAPI Mine_RegCreateKeyExA(HKEY a0, LPCSTR a1, DWORD a2, LPSTR a3, DWORD a4, REGSAM a5, LPSECURITY_ATTRIBUTES a6, PHKEY a7, LPDWORD a8) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a7 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegCreateKeyExA(a0, a1, a2, a3, a4, a5, a6, a7, a8); -} - -LONG WINAPI Mine_RegCreateKeyExW(HKEY a0, LPCWSTR a1, DWORD a2, LPWSTR a3, DWORD a4, REGSAM a5, LPSECURITY_ATTRIBUTES a6, PHKEY a7, LPDWORD a8) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a7 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegCreateKeyExW(a0, a1, a2, a3, a4, a5, a6, a7, a8); -} - -LONG WINAPI Mine_RegDeleteKeyA(HKEY a0, LPCSTR a1) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegDeleteKeyA(a0, a1); -} - -LONG WINAPI Mine_RegDeleteKeyW(HKEY a0, LPCWSTR a1) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegDeleteKeyW(a0, a1); -} - -LONG WINAPI Mine_RegDeleteValueA(HKEY a0, LPCSTR a1) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegDeleteValueA(a0, a1); -} - -LONG WINAPI Mine_RegDeleteValueW(HKEY a0, LPCWSTR a1) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegDeleteValueW(a0, a1); -} - -LONG WINAPI Mine_RegEnumKeyExA(HKEY a0, DWORD a1, LPSTR a2, LPDWORD a3, LPDWORD a4, LPSTR a5, LPDWORD a6, struct _FILETIME* a7) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_NO_MORE_ITEMS; - } - return Real_RegEnumKeyExA(a0, a1, a2, a3, a4, a5, a6, a7); -} - -LONG WINAPI Mine_RegEnumKeyExW(HKEY a0, DWORD a1, LPWSTR a2, LPDWORD a3, LPDWORD a4, LPWSTR a5, LPDWORD a6, struct _FILETIME* a7) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_NO_MORE_ITEMS; - } - return Real_RegEnumKeyExW(a0, a1, a2, a3, a4, a5, a6, a7); -} - -LONG WINAPI Mine_RegEnumValueA(HKEY a0, DWORD a1, LPSTR a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPBYTE a6, LPDWORD a7) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_NO_MORE_ITEMS; - } - return Real_RegEnumValueA(a0, a1, a2, a3, a4, a5, a6, a7); -} - -LONG WINAPI Mine_RegEnumValueW(HKEY a0, DWORD a1, LPWSTR a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPBYTE a6, LPDWORD a7) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_NO_MORE_ITEMS; - } - return Real_RegEnumValueW(a0, a1, a2, a3, a4, a5, a6, a7); -} - -LONG WINAPI Mine_RegOpenKeyA(HKEY a0, LPCSTR a1, PHKEY a2) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a2 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegOpenKeyA(a0, a1, a2); -} - -LONG WINAPI Mine_RegOpenKeyW(HKEY a0, LPCWSTR a1, PHKEY a2) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a2 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegOpenKeyW(a0, a1, a2); -} - -LONG WINAPI Mine_RegOpenKeyExA(HKEY a0, LPCSTR a1, DWORD a2, REGSAM a3, PHKEY a4) -{ - if (CFilterMapper2::s_pFilterMapper2 && (a3 & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { - *a4 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegOpenKeyExA(a0, a1, a2, a3, a4); -} - -LONG WINAPI Mine_RegOpenKeyExW(HKEY a0, LPCWSTR a1, DWORD a2, REGSAM a3, PHKEY a4) -{ - if (CFilterMapper2::s_pFilterMapper2 && (a3 & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { - *a4 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegOpenKeyExW(a0, a1, a2, a3, a4); -} - -LONG WINAPI Mine_RegQueryInfoKeyA(HKEY a0, LPSTR a1, LPDWORD a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPDWORD a6, LPDWORD a7, LPDWORD a8, LPDWORD a9, LPDWORD a10, struct _FILETIME* a11) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_INVALID_HANDLE; - } - return Real_RegQueryInfoKeyA(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); -} - -LONG WINAPI Mine_RegQueryInfoKeyW(HKEY a0, LPWSTR a1, LPDWORD a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPDWORD a6, LPDWORD a7, LPDWORD a8, LPDWORD a9, LPDWORD a10, struct _FILETIME* a11) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_INVALID_HANDLE; - } - return Real_RegQueryInfoKeyW(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); -} - -LONG WINAPI Mine_RegQueryValueA(HKEY a0, LPCSTR a1, LPSTR a2, PLONG a3) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - *a3 = 0; - return ERROR_SUCCESS; - } - return Real_RegQueryValueA(a0, a1, a2, a3); -} - -LONG WINAPI Mine_RegQueryValueW(HKEY a0, LPCWSTR a1, LPWSTR a2, PLONG a3) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - *a3 = 0; - return ERROR_SUCCESS; - } - return Real_RegQueryValueW(a0, a1, a2, a3); -} - -LONG WINAPI Mine_RegQueryValueExA(HKEY a0, LPCSTR a1, LPDWORD a2, LPDWORD a3, LPBYTE a4, LPDWORD a5) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - *a5 = 0; - return ERROR_SUCCESS; - } - return Real_RegQueryValueExA(a0, a1, a2, a3, a4, a5); -} - -LONG WINAPI Mine_RegQueryValueExW(HKEY a0, LPCWSTR a1, LPDWORD a2, LPDWORD a3, LPBYTE a4, LPDWORD a5) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - *a5 = 0; - return ERROR_SUCCESS; - } - return Real_RegQueryValueExW(a0, a1, a2, a3, a4, a5); -} - -LONG WINAPI Mine_RegSetValueA(HKEY a0, LPCSTR a1, DWORD a2, LPCSTR a3, DWORD a4) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegSetValueA(a0, a1, a2, a3, a4); -} - -LONG WINAPI Mine_RegSetValueW(HKEY a0, LPCWSTR a1, DWORD a2, LPCWSTR a3, DWORD a4) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegSetValueW(a0, a1, a2, a3, a4); -} - -LONG WINAPI Mine_RegSetValueExA(HKEY a0, LPCSTR a1, DWORD a2, DWORD a3, const BYTE* a4, DWORD a5) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegSetValueExA(a0, a1, a2, a3, a4, a5); -} - -LONG WINAPI Mine_RegSetValueExW(HKEY a0, LPCWSTR a1, DWORD a2, DWORD a3, const BYTE* a4, DWORD a5) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegSetValueExW(a0, a1, a2, a3, a4, a5); -} - -// -// CFilterMapper2 -// - -IFilterMapper2* CFilterMapper2::s_pFilterMapper2 = nullptr; - -bool CFilterMapper2::s_bInitialized = false; - -void CFilterMapper2::Init() -{ - if (!s_bInitialized) { - // In case of error, we don't report the failure immediately since the hooks might not be needed - s_bInitialized = Mhook_SetHookEx(&Real_CoCreateInstance, Mine_CoCreateInstance) - && Mhook_SetHookEx(&Real_RegCloseKey, Mine_RegCloseKey) - && Mhook_SetHookEx(&Real_RegFlushKey, Mine_RegFlushKey) - && Mhook_SetHookEx(&Real_RegCreateKeyA, Mine_RegCreateKeyA) - && Mhook_SetHookEx(&Real_RegCreateKeyW, Mine_RegCreateKeyW) - && Mhook_SetHookEx(&Real_RegCreateKeyExA, Mine_RegCreateKeyExA) - && Mhook_SetHookEx(&Real_RegCreateKeyExW, Mine_RegCreateKeyExW) - && Mhook_SetHookEx(&Real_RegDeleteKeyA, Mine_RegDeleteKeyA) - && Mhook_SetHookEx(&Real_RegDeleteKeyW, Mine_RegDeleteKeyW) - && Mhook_SetHookEx(&Real_RegDeleteValueA, Mine_RegDeleteValueA) - && Mhook_SetHookEx(&Real_RegDeleteValueW, Mine_RegDeleteValueW) - && Mhook_SetHookEx(&Real_RegEnumKeyExA, Mine_RegEnumKeyExA) - && Mhook_SetHookEx(&Real_RegEnumKeyExW, Mine_RegEnumKeyExW) - && Mhook_SetHookEx(&Real_RegEnumValueA, Mine_RegEnumValueA) - && Mhook_SetHookEx(&Real_RegEnumValueW, Mine_RegEnumValueW) - && Mhook_SetHookEx(&Real_RegOpenKeyA, Mine_RegOpenKeyA) - && Mhook_SetHookEx(&Real_RegOpenKeyW, Mine_RegOpenKeyW) - && Mhook_SetHookEx(&Real_RegOpenKeyExA, Mine_RegOpenKeyExA) - && Mhook_SetHookEx(&Real_RegOpenKeyExW, Mine_RegOpenKeyExW) - && Mhook_SetHookEx(&Real_RegQueryInfoKeyA, Mine_RegQueryInfoKeyA) - && Mhook_SetHookEx(&Real_RegQueryInfoKeyW, Mine_RegQueryInfoKeyW) - && Mhook_SetHookEx(&Real_RegQueryValueA, Mine_RegQueryValueA) - && Mhook_SetHookEx(&Real_RegQueryValueW, Mine_RegQueryValueW) - && Mhook_SetHookEx(&Real_RegQueryValueExA, Mine_RegQueryValueExA) - && Mhook_SetHookEx(&Real_RegQueryValueExW, Mine_RegQueryValueExW) - && Mhook_SetHookEx(&Real_RegSetValueA, Mine_RegSetValueA) - && Mhook_SetHookEx(&Real_RegSetValueW, Mine_RegSetValueW) - && Mhook_SetHookEx(&Real_RegSetValueExA, Mine_RegSetValueExA) - && Mhook_SetHookEx(&Real_RegSetValueExW, Mine_RegSetValueExW); - s_bInitialized &= MH_EnableHook(MH_ALL_HOOKS) == MH_OK; - } -} - -CFilterMapper2::CFilterMapper2(bool bRefCounted, bool bAllowUnreg /*= false*/, LPUNKNOWN pUnkOuter /*= nullptr*/) - : CUnknown(NAME("CFilterMapper2"), pUnkOuter) - , m_bRefCounted(bRefCounted) - , m_bAllowUnreg(bAllowUnreg) -{ - m_cRef = bRefCounted ? 0 : 1; - - // We can't call Init() if more than one thread is running due to a custom optimization - // we use for mhook. Instead we ensure that the hooks were properly set up at startup - ENSURE(s_bInitialized); - - HRESULT hr = Real_CoCreateInstance(CLSID_FilterMapper2, (IUnknown*)(INonDelegatingUnknown*)this, - CLSCTX_ALL, IID_PPV_ARGS(&m_pFM2)); - if (FAILED(hr) || !m_pFM2) { - ASSERT(FALSE); - } -} - -CFilterMapper2::~CFilterMapper2() -{ - POSITION pos = m_filters.GetHeadPosition(); - while (pos) { - delete m_filters.GetNext(pos); - } -} - -STDMETHODIMP CFilterMapper2::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - if (riid == __uuidof(IFilterMapper2)) { - return GetInterface((IFilterMapper2*)this, ppv); - } - - HRESULT hr = m_pFM2 ? m_pFM2->QueryInterface(riid, ppv) : E_NOINTERFACE; - - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CFilterMapper2::Register(CString path) -{ - // Load filter - if (HMODULE h = LoadLibraryEx(path, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH)) { - typedef HRESULT(__stdcall * PDllRegisterServer)(); - if (PDllRegisterServer fpDllRegisterServer = (PDllRegisterServer)GetProcAddress(h, "DllRegisterServer")) { - ASSERT(!CFilterMapper2::s_pFilterMapper2); - - CFilterMapper2::s_pFilterMapper2 = this; - m_path = path; - fpDllRegisterServer(); - m_path.Empty(); - CFilterMapper2::s_pFilterMapper2 = nullptr; - } - - FreeLibrary(h); - } -} - -// IFilterMapper2 - -STDMETHODIMP CFilterMapper2::CreateCategory(REFCLSID clsidCategory, DWORD dwCategoryMerit, LPCWSTR Description) -{ - if (!m_path.IsEmpty()) { - return S_OK; - } else if (CComQIPtr pFM2 = m_pFM2) { - return pFM2->CreateCategory(clsidCategory, dwCategoryMerit, Description); - } - - return E_NOTIMPL; -} - -STDMETHODIMP CFilterMapper2::UnregisterFilter(const CLSID* pclsidCategory, const OLECHAR* szInstance, REFCLSID Filter) -{ - if (!m_path.IsEmpty()) { - return S_OK; - } else if (CComQIPtr pFM2 = m_pFM2) { - return m_bAllowUnreg ? pFM2->UnregisterFilter(pclsidCategory, szInstance, Filter) : S_OK; - } - - return E_NOTIMPL; -} - -STDMETHODIMP CFilterMapper2::RegisterFilter(REFCLSID clsidFilter, LPCWSTR Name, IMoniker** ppMoniker, const CLSID* pclsidCategory, const OLECHAR* szInstance, const REGFILTER2* prf2) -{ - if (!m_path.IsEmpty()) { - if (FilterOverride* f = DEBUG_NEW FilterOverride) { - f->fDisabled = false; - f->type = FilterOverride::EXTERNAL; - f->path = m_path; - f->name = CStringW(Name); - f->clsid = clsidFilter; - f->iLoadType = FilterOverride::MERIT; - f->dwMerit = prf2->dwMerit; - - if (prf2->dwVersion == 1) { - for (ULONG i = 0; i < prf2->cPins; i++) { - const REGFILTERPINS& rgPin = prf2->rgPins[i]; - if (rgPin.bOutput) { - continue; - } - - for (UINT j = 0; j < rgPin.nMediaTypes; j++) { - if (!rgPin.lpMediaType[j].clsMajorType || !rgPin.lpMediaType[j].clsMinorType) { - break; - } - f->guids.AddTail(*rgPin.lpMediaType[j].clsMajorType); - f->guids.AddTail(*rgPin.lpMediaType[j].clsMinorType); - } - } - } else if (prf2->dwVersion == 2) { - for (ULONG i = 0; i < prf2->cPins2; i++) { - const REGFILTERPINS2& rgPin = prf2->rgPins2[i]; - if (rgPin.dwFlags & REG_PINFLAG_B_OUTPUT) { - continue; - } - - for (UINT j = 0; j < rgPin.nMediaTypes; j++) { - if (!rgPin.lpMediaType[j].clsMajorType || !rgPin.lpMediaType[j].clsMinorType) { - break; - } - f->guids.AddTail(*rgPin.lpMediaType[j].clsMajorType); - f->guids.AddTail(*rgPin.lpMediaType[j].clsMinorType); - } - } - } - - f->backup.AddTailList(&f->guids); - - m_filters.AddTail(f); - } - - return S_OK; - } else if (CComQIPtr pFM2 = m_pFM2) { - return pFM2->RegisterFilter(clsidFilter, Name, ppMoniker, pclsidCategory, szInstance, prf2); - } - - return E_NOTIMPL; -} - -STDMETHODIMP CFilterMapper2::EnumMatchingFilters(IEnumMoniker** ppEnum, DWORD dwFlags, BOOL bExactMatch, DWORD dwMerit, - BOOL bInputNeeded, DWORD cInputTypes, const GUID* pInputTypes, const REGPINMEDIUM* pMedIn, const CLSID* pPinCategoryIn, BOOL bRender, - BOOL bOutputNeeded, DWORD cOutputTypes, const GUID* pOutputTypes, const REGPINMEDIUM* pMedOut, const CLSID* pPinCategoryOut) -{ - if (CComQIPtr pFM2 = m_pFM2) { - return pFM2->EnumMatchingFilters(ppEnum, dwFlags, bExactMatch, dwMerit, - bInputNeeded, cInputTypes, pInputTypes, pMedIn, pPinCategoryIn, bRender, - bOutputNeeded, cOutputTypes, pOutputTypes, pMedOut, pPinCategoryOut); - } - - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "FakeFilterMapper2.h" +#include "MacrovisionKicker.h" +#include "DSUtil.h" + +#include "MhookHelper.h" + + +HRESULT(__stdcall* Real_CoCreateInstance)(CONST IID& a0, + LPUNKNOWN a1, + DWORD a2, + CONST IID& a3, + LPVOID* a4) + = CoCreateInstance; + +LONG(WINAPI* Real_RegCreateKeyExA)(HKEY a0, + LPCSTR a1, + DWORD a2, + LPSTR a3, + DWORD a4, + REGSAM a5, + LPSECURITY_ATTRIBUTES a6, + PHKEY a7, + LPDWORD a8) + = RegCreateKeyExA; + +LONG(WINAPI* Real_RegCreateKeyExW)(HKEY a0, + LPCWSTR a1, + DWORD a2, + LPWSTR a3, + DWORD a4, + REGSAM a5, + LPSECURITY_ATTRIBUTES a6, + PHKEY a7, + LPDWORD a8) + = RegCreateKeyExW; + +LONG(WINAPI* Real_RegDeleteKeyA)(HKEY a0, + LPCSTR a1) + = RegDeleteKeyA; + +LONG(WINAPI* Real_RegDeleteKeyW)(HKEY a0, + LPCWSTR a1) + = RegDeleteKeyW; + +LONG(WINAPI* Real_RegDeleteValueA)(HKEY a0, + LPCSTR a1) + = RegDeleteValueA; + + +LONG(WINAPI* Real_RegDeleteValueW)(HKEY a0, + LPCWSTR a1) + = RegDeleteValueW; + +LONG(WINAPI* Real_RegEnumKeyExA)(HKEY a0, + DWORD a1, + LPSTR a2, + LPDWORD a3, + LPDWORD a4, + LPSTR a5, + LPDWORD a6, + struct _FILETIME* a7) + = RegEnumKeyExA; + +LONG(WINAPI* Real_RegEnumKeyExW)(HKEY a0, + DWORD a1, + LPWSTR a2, + LPDWORD a3, + LPDWORD a4, + LPWSTR a5, + LPDWORD a6, + struct _FILETIME* a7) + = RegEnumKeyExW; + +LONG(WINAPI* Real_RegEnumValueA)(HKEY a0, + DWORD a1, + LPSTR a2, + LPDWORD a3, + LPDWORD a4, + LPDWORD a5, + LPBYTE a6, + LPDWORD a7) + = RegEnumValueA; + +LONG(WINAPI* Real_RegEnumValueW)(HKEY a0, + DWORD a1, + LPWSTR a2, + LPDWORD a3, + LPDWORD a4, + LPDWORD a5, + LPBYTE a6, + LPDWORD a7) + = RegEnumValueW; + +LONG(WINAPI* Real_RegOpenKeyExA)(HKEY a0, + LPCSTR a1, + DWORD a2, + REGSAM a3, + PHKEY a4) + = RegOpenKeyExA; + +LONG(WINAPI* Real_RegOpenKeyExW)(HKEY a0, + LPCWSTR a1, + DWORD a2, + REGSAM a3, + PHKEY a4) + = RegOpenKeyExW; + +LONG(WINAPI* Real_RegQueryInfoKeyA)(HKEY a0, + LPSTR a1, + LPDWORD a2, + LPDWORD a3, + LPDWORD a4, + LPDWORD a5, + LPDWORD a6, + LPDWORD a7, + LPDWORD a8, + LPDWORD a9, + LPDWORD a10, + struct _FILETIME* a11) + = RegQueryInfoKeyA; + +LONG(WINAPI* Real_RegQueryInfoKeyW)(HKEY a0, + LPWSTR a1, + LPDWORD a2, + LPDWORD a3, + LPDWORD a4, + LPDWORD a5, + LPDWORD a6, + LPDWORD a7, + LPDWORD a8, + LPDWORD a9, + LPDWORD a10, + struct _FILETIME* a11) + = RegQueryInfoKeyW; + +LONG(WINAPI* Real_RegQueryValueExA)(HKEY a0, + LPCSTR a1, + LPDWORD a2, + LPDWORD a3, + LPBYTE a4, + LPDWORD a5) + = RegQueryValueExA; + +LONG(WINAPI* Real_RegQueryValueExW)(HKEY a0, + LPCWSTR a1, + LPDWORD a2, + LPDWORD a3, + LPBYTE a4, + LPDWORD a5) + = RegQueryValueExW; + +LONG(WINAPI* Real_RegSetValueExA)(HKEY a0, + LPCSTR a1, + DWORD a2, + DWORD a3, + const BYTE* a4, + DWORD a5) + = RegSetValueExA; + +LONG(WINAPI* Real_RegSetValueExW)(HKEY a0, + LPCWSTR a1, + DWORD a2, + DWORD a3, + const BYTE* a4, + DWORD a5) + = RegSetValueExW; + + +LONG(WINAPI* Real_RegCloseKey)(HKEY a0) + = RegCloseKey; + +LONG(WINAPI* Real_RegFlushKey)(HKEY a0) + = RegFlushKey; + +LONG(WINAPI* Real_RegCreateKeyA)(HKEY a0, LPCSTR a1, PHKEY a2) + = RegCreateKeyA; + +LONG(WINAPI* Real_RegCreateKeyW)(HKEY a0, LPCWSTR a1, PHKEY a2) + = RegCreateKeyW; + +LONG(WINAPI* Real_RegOpenKeyA)(HKEY a0, LPCSTR a1, PHKEY a2) + = RegOpenKeyA; + +LONG(WINAPI* Real_RegOpenKeyW)(HKEY a0, LPCWSTR a1, PHKEY a2) + = RegOpenKeyW; + +LONG(WINAPI* Real_RegQueryValueA)(HKEY a0, LPCSTR a1, LPSTR a2, PLONG a3) + = RegQueryValueA; + +LONG(WINAPI* Real_RegQueryValueW)(HKEY a0, LPCWSTR a1, LPWSTR a2, PLONG a3) + = RegQueryValueW; + +LONG(WINAPI* Real_RegSetValueW)(HKEY a0, LPCWSTR a1, DWORD a2, LPCWSTR a3, DWORD a4) + = RegSetValueW; + +LONG(WINAPI* Real_RegSetValueA)(HKEY a0, LPCSTR a1, DWORD a2, LPCSTR a3, DWORD a4) + = RegSetValueA; + + + +HRESULT WINAPI Mine_CoCreateInstance(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, + IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID FAR* ppv) +{ + if (CFilterMapper2::s_pFilterMapper2) { + CheckPointer(ppv, E_POINTER); + + if (rclsid == CLSID_FilterMapper) { + ASSERT(FALSE); + return REGDB_E_CLASSNOTREG; // sorry... + } + + if (rclsid == CLSID_FilterMapper2) { + if (pUnkOuter) { + return CLASS_E_NOAGGREGATION; + } + + if (riid == __uuidof(IUnknown)) { + CFilterMapper2::s_pFilterMapper2->AddRef(); + *ppv = (IUnknown*)CFilterMapper2::s_pFilterMapper2; + return S_OK; + } else if (riid == __uuidof(IFilterMapper2)) { + CFilterMapper2::s_pFilterMapper2->AddRef(); + *ppv = (IFilterMapper2*)CFilterMapper2::s_pFilterMapper2; + return S_OK; + } else { + return E_NOINTERFACE; + } + } + } + /* else + { + if (rclsid == CLSID_FilterMapper2) + { + CFilterMapper2* pFM2 = DEBUG_NEW CFilterMapper2(true, false, pUnkOuter); + CComPtr pUnk = (IUnknown*)pFM2; + return pUnk->QueryInterface(riid, ppv); + } + } + */ + if (!pUnkOuter) + if (rclsid == CLSID_VideoMixingRenderer || rclsid == CLSID_VideoMixingRenderer9 + || rclsid == CLSID_VideoRenderer || rclsid == CLSID_VideoRendererDefault + || rclsid == CLSID_OverlayMixer) { // || rclsid == CLSID_OverlayMixer2 - where is this declared?) + CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; + CComPtr pInner; + + if (SUCCEEDED(Real_CoCreateInstance(rclsid, pUnk, dwClsContext, IID_PPV_ARGS(&pInner)))) { + pMK->SetInner(pInner); + return pUnk->QueryInterface(riid, ppv); + } + } + + return Real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); +} + +#define FAKEHKEY (HKEY)0x12345678 + +LONG WINAPI Mine_RegCloseKey(HKEY a0) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_SUCCESS; + } + return Real_RegCloseKey(a0); +} + +LONG WINAPI Mine_RegFlushKey(HKEY a0) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_SUCCESS; + } + return Real_RegFlushKey(a0); +} + +LONG WINAPI Mine_RegCreateKeyA(HKEY a0, LPCSTR a1, PHKEY a2) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a2 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegCreateKeyA(a0, a1, a2); +} + +LONG WINAPI Mine_RegCreateKeyW(HKEY a0, LPCWSTR a1, PHKEY a2) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a2 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegCreateKeyW(a0, a1, a2); +} + +LONG WINAPI Mine_RegCreateKeyExA(HKEY a0, LPCSTR a1, DWORD a2, LPSTR a3, DWORD a4, REGSAM a5, LPSECURITY_ATTRIBUTES a6, PHKEY a7, LPDWORD a8) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a7 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegCreateKeyExA(a0, a1, a2, a3, a4, a5, a6, a7, a8); +} + +LONG WINAPI Mine_RegCreateKeyExW(HKEY a0, LPCWSTR a1, DWORD a2, LPWSTR a3, DWORD a4, REGSAM a5, LPSECURITY_ATTRIBUTES a6, PHKEY a7, LPDWORD a8) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a7 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegCreateKeyExW(a0, a1, a2, a3, a4, a5, a6, a7, a8); +} + +LONG WINAPI Mine_RegDeleteKeyA(HKEY a0, LPCSTR a1) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegDeleteKeyA(a0, a1); +} + +LONG WINAPI Mine_RegDeleteKeyW(HKEY a0, LPCWSTR a1) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegDeleteKeyW(a0, a1); +} + +LONG WINAPI Mine_RegDeleteValueA(HKEY a0, LPCSTR a1) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegDeleteValueA(a0, a1); +} + +LONG WINAPI Mine_RegDeleteValueW(HKEY a0, LPCWSTR a1) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegDeleteValueW(a0, a1); +} + +LONG WINAPI Mine_RegEnumKeyExA(HKEY a0, DWORD a1, LPSTR a2, LPDWORD a3, LPDWORD a4, LPSTR a5, LPDWORD a6, struct _FILETIME* a7) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_NO_MORE_ITEMS; + } + return Real_RegEnumKeyExA(a0, a1, a2, a3, a4, a5, a6, a7); +} + +LONG WINAPI Mine_RegEnumKeyExW(HKEY a0, DWORD a1, LPWSTR a2, LPDWORD a3, LPDWORD a4, LPWSTR a5, LPDWORD a6, struct _FILETIME* a7) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_NO_MORE_ITEMS; + } + return Real_RegEnumKeyExW(a0, a1, a2, a3, a4, a5, a6, a7); +} + +LONG WINAPI Mine_RegEnumValueA(HKEY a0, DWORD a1, LPSTR a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPBYTE a6, LPDWORD a7) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_NO_MORE_ITEMS; + } + return Real_RegEnumValueA(a0, a1, a2, a3, a4, a5, a6, a7); +} + +LONG WINAPI Mine_RegEnumValueW(HKEY a0, DWORD a1, LPWSTR a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPBYTE a6, LPDWORD a7) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_NO_MORE_ITEMS; + } + return Real_RegEnumValueW(a0, a1, a2, a3, a4, a5, a6, a7); +} + +LONG WINAPI Mine_RegOpenKeyA(HKEY a0, LPCSTR a1, PHKEY a2) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a2 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegOpenKeyA(a0, a1, a2); +} + +LONG WINAPI Mine_RegOpenKeyW(HKEY a0, LPCWSTR a1, PHKEY a2) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a2 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegOpenKeyW(a0, a1, a2); +} + +LONG WINAPI Mine_RegOpenKeyExA(HKEY a0, LPCSTR a1, DWORD a2, REGSAM a3, PHKEY a4) +{ + if (CFilterMapper2::s_pFilterMapper2 && (a3 & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { + *a4 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegOpenKeyExA(a0, a1, a2, a3, a4); +} + +LONG WINAPI Mine_RegOpenKeyExW(HKEY a0, LPCWSTR a1, DWORD a2, REGSAM a3, PHKEY a4) +{ + if (CFilterMapper2::s_pFilterMapper2 && (a3 & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { + *a4 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegOpenKeyExW(a0, a1, a2, a3, a4); +} + +LONG WINAPI Mine_RegQueryInfoKeyA(HKEY a0, LPSTR a1, LPDWORD a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPDWORD a6, LPDWORD a7, LPDWORD a8, LPDWORD a9, LPDWORD a10, struct _FILETIME* a11) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_INVALID_HANDLE; + } + return Real_RegQueryInfoKeyA(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); +} + +LONG WINAPI Mine_RegQueryInfoKeyW(HKEY a0, LPWSTR a1, LPDWORD a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPDWORD a6, LPDWORD a7, LPDWORD a8, LPDWORD a9, LPDWORD a10, struct _FILETIME* a11) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_INVALID_HANDLE; + } + return Real_RegQueryInfoKeyW(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); +} + +LONG WINAPI Mine_RegQueryValueA(HKEY a0, LPCSTR a1, LPSTR a2, PLONG a3) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + *a3 = 0; + return ERROR_SUCCESS; + } + return Real_RegQueryValueA(a0, a1, a2, a3); +} + +LONG WINAPI Mine_RegQueryValueW(HKEY a0, LPCWSTR a1, LPWSTR a2, PLONG a3) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + *a3 = 0; + return ERROR_SUCCESS; + } + return Real_RegQueryValueW(a0, a1, a2, a3); +} + +LONG WINAPI Mine_RegQueryValueExA(HKEY a0, LPCSTR a1, LPDWORD a2, LPDWORD a3, LPBYTE a4, LPDWORD a5) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + *a5 = 0; + return ERROR_SUCCESS; + } + return Real_RegQueryValueExA(a0, a1, a2, a3, a4, a5); +} + +LONG WINAPI Mine_RegQueryValueExW(HKEY a0, LPCWSTR a1, LPDWORD a2, LPDWORD a3, LPBYTE a4, LPDWORD a5) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + *a5 = 0; + return ERROR_SUCCESS; + } + return Real_RegQueryValueExW(a0, a1, a2, a3, a4, a5); +} + +LONG WINAPI Mine_RegSetValueA(HKEY a0, LPCSTR a1, DWORD a2, LPCSTR a3, DWORD a4) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegSetValueA(a0, a1, a2, a3, a4); +} + +LONG WINAPI Mine_RegSetValueW(HKEY a0, LPCWSTR a1, DWORD a2, LPCWSTR a3, DWORD a4) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegSetValueW(a0, a1, a2, a3, a4); +} + +LONG WINAPI Mine_RegSetValueExA(HKEY a0, LPCSTR a1, DWORD a2, DWORD a3, const BYTE* a4, DWORD a5) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegSetValueExA(a0, a1, a2, a3, a4, a5); +} + +LONG WINAPI Mine_RegSetValueExW(HKEY a0, LPCWSTR a1, DWORD a2, DWORD a3, const BYTE* a4, DWORD a5) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegSetValueExW(a0, a1, a2, a3, a4, a5); +} + +// +// CFilterMapper2 +// + +IFilterMapper2* CFilterMapper2::s_pFilterMapper2 = nullptr; + +bool CFilterMapper2::s_bInitialized = false; + +void CFilterMapper2::Init() +{ + if (!s_bInitialized) { + // In case of error, we don't report the failure immediately since the hooks might not be needed + s_bInitialized = Mhook_SetHookEx(&Real_CoCreateInstance, Mine_CoCreateInstance) + && Mhook_SetHookEx(&Real_RegCloseKey, Mine_RegCloseKey) + && Mhook_SetHookEx(&Real_RegFlushKey, Mine_RegFlushKey) + && Mhook_SetHookEx(&Real_RegCreateKeyA, Mine_RegCreateKeyA) + && Mhook_SetHookEx(&Real_RegCreateKeyW, Mine_RegCreateKeyW) + && Mhook_SetHookEx(&Real_RegCreateKeyExA, Mine_RegCreateKeyExA) + && Mhook_SetHookEx(&Real_RegCreateKeyExW, Mine_RegCreateKeyExW) + && Mhook_SetHookEx(&Real_RegDeleteKeyA, Mine_RegDeleteKeyA) + && Mhook_SetHookEx(&Real_RegDeleteKeyW, Mine_RegDeleteKeyW) + && Mhook_SetHookEx(&Real_RegDeleteValueA, Mine_RegDeleteValueA) + && Mhook_SetHookEx(&Real_RegDeleteValueW, Mine_RegDeleteValueW) + && Mhook_SetHookEx(&Real_RegEnumKeyExA, Mine_RegEnumKeyExA) + && Mhook_SetHookEx(&Real_RegEnumKeyExW, Mine_RegEnumKeyExW) + && Mhook_SetHookEx(&Real_RegEnumValueA, Mine_RegEnumValueA) + && Mhook_SetHookEx(&Real_RegEnumValueW, Mine_RegEnumValueW) + && Mhook_SetHookEx(&Real_RegOpenKeyA, Mine_RegOpenKeyA) + && Mhook_SetHookEx(&Real_RegOpenKeyW, Mine_RegOpenKeyW) + && Mhook_SetHookEx(&Real_RegOpenKeyExA, Mine_RegOpenKeyExA) + && Mhook_SetHookEx(&Real_RegOpenKeyExW, Mine_RegOpenKeyExW) + && Mhook_SetHookEx(&Real_RegQueryInfoKeyA, Mine_RegQueryInfoKeyA) + && Mhook_SetHookEx(&Real_RegQueryInfoKeyW, Mine_RegQueryInfoKeyW) + && Mhook_SetHookEx(&Real_RegQueryValueA, Mine_RegQueryValueA) + && Mhook_SetHookEx(&Real_RegQueryValueW, Mine_RegQueryValueW) + && Mhook_SetHookEx(&Real_RegQueryValueExA, Mine_RegQueryValueExA) + && Mhook_SetHookEx(&Real_RegQueryValueExW, Mine_RegQueryValueExW) + && Mhook_SetHookEx(&Real_RegSetValueA, Mine_RegSetValueA) + && Mhook_SetHookEx(&Real_RegSetValueW, Mine_RegSetValueW) + && Mhook_SetHookEx(&Real_RegSetValueExA, Mine_RegSetValueExA) + && Mhook_SetHookEx(&Real_RegSetValueExW, Mine_RegSetValueExW); + s_bInitialized &= MH_EnableHook(MH_ALL_HOOKS) == MH_OK; + } +} + +CFilterMapper2::CFilterMapper2(bool bRefCounted, bool bAllowUnreg /*= false*/, LPUNKNOWN pUnkOuter /*= nullptr*/) + : CUnknown(NAME("CFilterMapper2"), pUnkOuter) + , m_bRefCounted(bRefCounted) + , m_bAllowUnreg(bAllowUnreg) +{ + m_cRef = bRefCounted ? 0 : 1; + + // We can't call Init() if more than one thread is running due to a custom optimization + // we use for mhook. Instead we ensure that the hooks were properly set up at startup + ENSURE(s_bInitialized); + + HRESULT hr = Real_CoCreateInstance(CLSID_FilterMapper2, (IUnknown*)(INonDelegatingUnknown*)this, + CLSCTX_ALL, IID_PPV_ARGS(&m_pFM2)); + if (FAILED(hr) || !m_pFM2) { + ASSERT(FALSE); + } +} + +CFilterMapper2::~CFilterMapper2() +{ + POSITION pos = m_filters.GetHeadPosition(); + while (pos) { + delete m_filters.GetNext(pos); + } +} + +STDMETHODIMP CFilterMapper2::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + if (riid == __uuidof(IFilterMapper2)) { + return GetInterface((IFilterMapper2*)this, ppv); + } + + HRESULT hr = m_pFM2 ? m_pFM2->QueryInterface(riid, ppv) : E_NOINTERFACE; + + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CFilterMapper2::Register(CString path) +{ + // Load filter + if (HMODULE h = LoadLibraryEx(path, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH)) { + typedef HRESULT(__stdcall * PDllRegisterServer)(); + if (PDllRegisterServer fpDllRegisterServer = (PDllRegisterServer)GetProcAddress(h, "DllRegisterServer")) { + ASSERT(!CFilterMapper2::s_pFilterMapper2); + + CFilterMapper2::s_pFilterMapper2 = this; + m_path = path; + fpDllRegisterServer(); + m_path.Empty(); + CFilterMapper2::s_pFilterMapper2 = nullptr; + } + + FreeLibrary(h); + } +} + +// IFilterMapper2 + +STDMETHODIMP CFilterMapper2::CreateCategory(REFCLSID clsidCategory, DWORD dwCategoryMerit, LPCWSTR Description) +{ + if (!m_path.IsEmpty()) { + return S_OK; + } else if (CComQIPtr pFM2 = m_pFM2) { + return pFM2->CreateCategory(clsidCategory, dwCategoryMerit, Description); + } + + return E_NOTIMPL; +} + +STDMETHODIMP CFilterMapper2::UnregisterFilter(const CLSID* pclsidCategory, const OLECHAR* szInstance, REFCLSID Filter) +{ + if (!m_path.IsEmpty()) { + return S_OK; + } else if (CComQIPtr pFM2 = m_pFM2) { + return m_bAllowUnreg ? pFM2->UnregisterFilter(pclsidCategory, szInstance, Filter) : S_OK; + } + + return E_NOTIMPL; +} + +STDMETHODIMP CFilterMapper2::RegisterFilter(REFCLSID clsidFilter, LPCWSTR Name, IMoniker** ppMoniker, const CLSID* pclsidCategory, const OLECHAR* szInstance, const REGFILTER2* prf2) +{ + if (!m_path.IsEmpty()) { + if (FilterOverride* f = DEBUG_NEW FilterOverride) { + f->fDisabled = false; + f->type = FilterOverride::EXTERNAL; + f->path = m_path; + f->name = CStringW(Name); + f->clsid = clsidFilter; + f->iLoadType = FilterOverride::MERIT; + f->dwMerit = prf2->dwMerit; + + if (prf2->dwVersion == 1) { + for (ULONG i = 0; i < prf2->cPins; i++) { + const REGFILTERPINS& rgPin = prf2->rgPins[i]; + if (rgPin.bOutput) { + continue; + } + + for (UINT j = 0; j < rgPin.nMediaTypes; j++) { + if (!rgPin.lpMediaType[j].clsMajorType || !rgPin.lpMediaType[j].clsMinorType) { + break; + } + f->guids.AddTail(*rgPin.lpMediaType[j].clsMajorType); + f->guids.AddTail(*rgPin.lpMediaType[j].clsMinorType); + } + } + } else if (prf2->dwVersion == 2) { + for (ULONG i = 0; i < prf2->cPins2; i++) { + const REGFILTERPINS2& rgPin = prf2->rgPins2[i]; + if (rgPin.dwFlags & REG_PINFLAG_B_OUTPUT) { + continue; + } + + for (UINT j = 0; j < rgPin.nMediaTypes; j++) { + if (!rgPin.lpMediaType[j].clsMajorType || !rgPin.lpMediaType[j].clsMinorType) { + break; + } + f->guids.AddTail(*rgPin.lpMediaType[j].clsMajorType); + f->guids.AddTail(*rgPin.lpMediaType[j].clsMinorType); + } + } + } + + f->backup.AddTailList(&f->guids); + + m_filters.AddTail(f); + } + + return S_OK; + } else if (CComQIPtr pFM2 = m_pFM2) { + return pFM2->RegisterFilter(clsidFilter, Name, ppMoniker, pclsidCategory, szInstance, prf2); + } + + return E_NOTIMPL; +} + +STDMETHODIMP CFilterMapper2::EnumMatchingFilters(IEnumMoniker** ppEnum, DWORD dwFlags, BOOL bExactMatch, DWORD dwMerit, + BOOL bInputNeeded, DWORD cInputTypes, const GUID* pInputTypes, const REGPINMEDIUM* pMedIn, const CLSID* pPinCategoryIn, BOOL bRender, + BOOL bOutputNeeded, DWORD cOutputTypes, const GUID* pOutputTypes, const REGPINMEDIUM* pMedOut, const CLSID* pPinCategoryOut) +{ + if (CComQIPtr pFM2 = m_pFM2) { + return pFM2->EnumMatchingFilters(ppEnum, dwFlags, bExactMatch, dwMerit, + bInputNeeded, cInputTypes, pInputTypes, pMedIn, pPinCategoryIn, bRender, + bOutputNeeded, cOutputTypes, pOutputTypes, pMedOut, pPinCategoryOut); + } + + return E_NOTIMPL; +} diff --git a/src/mpc-hc/FakeFilterMapper2.h b/src/mpc-hc/FakeFilterMapper2.h index 70f8e2a86ed..642d96d202b 100644 --- a/src/mpc-hc/FakeFilterMapper2.h +++ b/src/mpc-hc/FakeFilterMapper2.h @@ -1,99 +1,99 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include - - -class FilterOverride -{ -public: - bool fDisabled, fTemporary; - enum { REGISTERED, EXTERNAL } type; - // REGISTERED - CStringW dispname; - // EXTERNAL - CString path, name; - CLSID clsid; - // props - CAtlList guids, backup; - enum { PREFERRED, BLOCK, MERIT }; - int iLoadType; - DWORD dwMerit; - - FilterOverride() - : fDisabled(false) - , fTemporary(false) - , type(EXTERNAL) - , clsid(GUID_NULL) - , iLoadType(0) - , dwMerit(0) { - } - FilterOverride(FilterOverride* f) { - fDisabled = f->fDisabled; - fTemporary = f->fTemporary; - type = f->type; - dispname = f->dispname; - path = f->path; - name = f->name; - clsid = f->clsid; - guids.AddTailList(&f->guids); - backup.AddTailList(&f->backup); - iLoadType = f->iLoadType; - dwMerit = f->dwMerit; - } -}; - -class CFilterMapper2 : protected CUnknown, public IFilterMapper2 -{ - static bool s_bInitialized; - - CComPtr m_pFM2; - CString m_path; - - bool m_bRefCounted, m_bAllowUnreg; - -protected: - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IFilterMapper2 - - STDMETHODIMP CreateCategory(REFCLSID clsidCategory, DWORD dwCategoryMerit, LPCWSTR Description); - STDMETHODIMP UnregisterFilter(const CLSID* pclsidCategory, const OLECHAR* szInstance, REFCLSID Filter); - STDMETHODIMP RegisterFilter(REFCLSID clsidFilter, LPCWSTR Name, IMoniker** ppMoniker, const CLSID* pclsidCategory, const OLECHAR* szInstance, const REGFILTER2* prf2); - STDMETHODIMP EnumMatchingFilters(IEnumMoniker** ppEnum, DWORD dwFlags, BOOL bExactMatch, DWORD dwMerit, - BOOL bInputNeeded, DWORD cInputTypes, const GUID* pInputTypes, const REGPINMEDIUM* pMedIn, const CLSID* pPinCategoryIn, BOOL bRender, - BOOL bOutputNeeded, DWORD cOutputTypes, const GUID* pOutputTypes, const REGPINMEDIUM* pMedOut, const CLSID* pPinCategoryOut); - -public: - CFilterMapper2(bool bRefCounted, bool bAllowUnreg = false, LPUNKNOWN pUnkOuter = nullptr); - virtual ~CFilterMapper2(); - - void SetInner(IUnknown* pUnk) { m_pFM2 = pUnk; } - - static void Init(); - - static IFilterMapper2* s_pFilterMapper2; - CList m_filters; - void Register(CString path); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include + + +class FilterOverride +{ +public: + bool fDisabled, fTemporary; + enum { REGISTERED, EXTERNAL } type; + // REGISTERED + CStringW dispname; + // EXTERNAL + CString path, name; + CLSID clsid; + // props + CAtlList guids, backup; + enum { PREFERRED, BLOCK, MERIT }; + int iLoadType; + DWORD dwMerit; + + FilterOverride() + : fDisabled(false) + , fTemporary(false) + , type(EXTERNAL) + , clsid(GUID_NULL) + , iLoadType(0) + , dwMerit(0) { + } + FilterOverride(FilterOverride* f) { + fDisabled = f->fDisabled; + fTemporary = f->fTemporary; + type = f->type; + dispname = f->dispname; + path = f->path; + name = f->name; + clsid = f->clsid; + guids.AddTailList(&f->guids); + backup.AddTailList(&f->backup); + iLoadType = f->iLoadType; + dwMerit = f->dwMerit; + } +}; + +class CFilterMapper2 : protected CUnknown, public IFilterMapper2 +{ + static bool s_bInitialized; + + CComPtr m_pFM2; + CString m_path; + + bool m_bRefCounted, m_bAllowUnreg; + +protected: + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IFilterMapper2 + + STDMETHODIMP CreateCategory(REFCLSID clsidCategory, DWORD dwCategoryMerit, LPCWSTR Description); + STDMETHODIMP UnregisterFilter(const CLSID* pclsidCategory, const OLECHAR* szInstance, REFCLSID Filter); + STDMETHODIMP RegisterFilter(REFCLSID clsidFilter, LPCWSTR Name, IMoniker** ppMoniker, const CLSID* pclsidCategory, const OLECHAR* szInstance, const REGFILTER2* prf2); + STDMETHODIMP EnumMatchingFilters(IEnumMoniker** ppEnum, DWORD dwFlags, BOOL bExactMatch, DWORD dwMerit, + BOOL bInputNeeded, DWORD cInputTypes, const GUID* pInputTypes, const REGPINMEDIUM* pMedIn, const CLSID* pPinCategoryIn, BOOL bRender, + BOOL bOutputNeeded, DWORD cOutputTypes, const GUID* pOutputTypes, const REGPINMEDIUM* pMedOut, const CLSID* pPinCategoryOut); + +public: + CFilterMapper2(bool bRefCounted, bool bAllowUnreg = false, LPUNKNOWN pUnkOuter = nullptr); + virtual ~CFilterMapper2(); + + void SetInner(IUnknown* pUnk) { m_pFM2 = pUnk; } + + static void Init(); + + static IFilterMapper2* s_pFilterMapper2; + CList m_filters; + void Register(CString path); +}; diff --git a/src/mpc-hc/FavoriteAddDlg.cpp b/src/mpc-hc/FavoriteAddDlg.cpp index 06d1c4903e2..60ddc27227d 100644 --- a/src/mpc-hc/FavoriteAddDlg.cpp +++ b/src/mpc-hc/FavoriteAddDlg.cpp @@ -1,125 +1,125 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "FavoriteAddDlg.h" -#include "SettingsDefines.h" -#include "AppSettings.h" - -// CFavoriteAddDlg dialog - -CFavoriteAddDlg::CFavoriteAddDlg(CString shortname, CString fullname, - BOOL bEnableABMarks /*=FALSE*/, CWnd* pParent /*=nullptr*/) - : CMPCThemeResizableDialog(CFavoriteAddDlg::IDD, pParent) - , m_shortname(shortname) - , m_fullname(fullname) - , m_bEnableABMarks(bEnableABMarks) - , m_bRememberPos(TRUE) - , m_bRememberABMarks(FALSE) - , m_bRelativeDrive(FALSE) -{ -} - -CFavoriteAddDlg::~CFavoriteAddDlg() -{ -} - -void CFavoriteAddDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO1, m_namectrl); - DDX_CBString(pDX, IDC_COMBO1, m_name); - DDX_Check(pDX, IDC_CHECK1, m_bRememberPos); - DDX_Check(pDX, IDC_CHECK2, m_bRelativeDrive); - DDX_Check(pDX, IDC_CHECK3, m_bRememberABMarks); - fulfillThemeReqs(); -} - -BOOL CFavoriteAddDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - if (!m_shortname.IsEmpty()) { - m_namectrl.AddString(m_shortname); - } - - if (!m_fullname.IsEmpty()) { - m_namectrl.AddString(m_fullname); - } - - ::CorrectComboListWidth(m_namectrl); - - const CAppSettings& s = AfxGetAppSettings(); - - m_bRememberPos = s.bFavRememberPos; - m_bRelativeDrive = s.bFavRelativeDrive; - - if (m_bEnableABMarks) { - m_bRememberABMarks = s.bFavRememberABMarks; - } - GetDlgItem(IDC_CHECK3)->EnableWindow(m_bEnableABMarks); - - UpdateData(FALSE); // Update UI - - m_namectrl.SetCurSel(0); - - AddAnchor(IDC_COMBO1, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDOK, BOTTOM_RIGHT); - AddAnchor(IDCANCEL, BOTTOM_RIGHT); - - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - - -BEGIN_MESSAGE_MAP(CFavoriteAddDlg, CMPCThemeResizableDialog) - ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOk) -END_MESSAGE_MAP() - - -// CFavoriteAddDlg message handlers - -void CFavoriteAddDlg::OnUpdateOk(CCmdUI* pCmdUI) -{ - UpdateData(); // Retrieve UI values - - pCmdUI->Enable(!m_name.IsEmpty()); -} - -void CFavoriteAddDlg::OnOK() -{ - UpdateData(); // Retrieve UI values - - // Remember settings - CAppSettings& s = AfxGetAppSettings(); - - s.bFavRememberPos = !!m_bRememberPos; - s.bFavRelativeDrive = !!m_bRelativeDrive; - - if (m_bEnableABMarks) { - s.bFavRememberABMarks = !!m_bRememberABMarks; - } - - __super::OnOK(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "FavoriteAddDlg.h" +#include "SettingsDefines.h" +#include "AppSettings.h" + +// CFavoriteAddDlg dialog + +CFavoriteAddDlg::CFavoriteAddDlg(CString shortname, CString fullname, + BOOL bEnableABMarks /*=FALSE*/, CWnd* pParent /*=nullptr*/) + : CMPCThemeResizableDialog(CFavoriteAddDlg::IDD, pParent) + , m_shortname(shortname) + , m_fullname(fullname) + , m_bEnableABMarks(bEnableABMarks) + , m_bRememberPos(TRUE) + , m_bRememberABMarks(FALSE) + , m_bRelativeDrive(FALSE) +{ +} + +CFavoriteAddDlg::~CFavoriteAddDlg() +{ +} + +void CFavoriteAddDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO1, m_namectrl); + DDX_CBString(pDX, IDC_COMBO1, m_name); + DDX_Check(pDX, IDC_CHECK1, m_bRememberPos); + DDX_Check(pDX, IDC_CHECK2, m_bRelativeDrive); + DDX_Check(pDX, IDC_CHECK3, m_bRememberABMarks); + fulfillThemeReqs(); +} + +BOOL CFavoriteAddDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + if (!m_shortname.IsEmpty()) { + m_namectrl.AddString(m_shortname); + } + + if (!m_fullname.IsEmpty()) { + m_namectrl.AddString(m_fullname); + } + + ::CorrectComboListWidth(m_namectrl); + + const CAppSettings& s = AfxGetAppSettings(); + + m_bRememberPos = s.bFavRememberPos; + m_bRelativeDrive = s.bFavRelativeDrive; + + if (m_bEnableABMarks) { + m_bRememberABMarks = s.bFavRememberABMarks; + } + GetDlgItem(IDC_CHECK3)->EnableWindow(m_bEnableABMarks); + + UpdateData(FALSE); // Update UI + + m_namectrl.SetCurSel(0); + + AddAnchor(IDC_COMBO1, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDOK, BOTTOM_RIGHT); + AddAnchor(IDCANCEL, BOTTOM_RIGHT); + + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + + +BEGIN_MESSAGE_MAP(CFavoriteAddDlg, CMPCThemeResizableDialog) + ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOk) +END_MESSAGE_MAP() + + +// CFavoriteAddDlg message handlers + +void CFavoriteAddDlg::OnUpdateOk(CCmdUI* pCmdUI) +{ + UpdateData(); // Retrieve UI values + + pCmdUI->Enable(!m_name.IsEmpty()); +} + +void CFavoriteAddDlg::OnOK() +{ + UpdateData(); // Retrieve UI values + + // Remember settings + CAppSettings& s = AfxGetAppSettings(); + + s.bFavRememberPos = !!m_bRememberPos; + s.bFavRelativeDrive = !!m_bRelativeDrive; + + if (m_bEnableABMarks) { + s.bFavRememberABMarks = !!m_bRememberABMarks; + } + + __super::OnOK(); +} diff --git a/src/mpc-hc/FavoriteAddDlg.h b/src/mpc-hc/FavoriteAddDlg.h index f83c98bf48b..4dfea3e8a28 100644 --- a/src/mpc-hc/FavoriteAddDlg.h +++ b/src/mpc-hc/FavoriteAddDlg.h @@ -1,54 +1,54 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "CMPCThemeResizableDialog.h" -#include "CMPCThemeComboBox.h" - -// CFavoriteAddDlg dialog - -class CFavoriteAddDlg : public CMPCThemeResizableDialog -{ -public: - CFavoriteAddDlg(CString shortname, CString fullname, BOOL bEnableABMarks = FALSE, CWnd* pParent = nullptr); // standard constructor - virtual ~CFavoriteAddDlg(); - - // Dialog Data - enum { IDD = IDD_FAVADD }; - - CString m_name; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual void OnOK(); - afx_msg void OnUpdateOk(CCmdUI* pCmdUI); - DECLARE_MESSAGE_MAP() - -private: - CMPCThemeComboBox m_namectrl; - CString m_shortname, m_fullname; - BOOL m_bEnableABMarks; - BOOL m_bRememberPos; - BOOL m_bRememberABMarks; - BOOL m_bRelativeDrive; -}; +/* + * (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 . + * + */ + +#pragma once + +#include "CMPCThemeResizableDialog.h" +#include "CMPCThemeComboBox.h" + +// CFavoriteAddDlg dialog + +class CFavoriteAddDlg : public CMPCThemeResizableDialog +{ +public: + CFavoriteAddDlg(CString shortname, CString fullname, BOOL bEnableABMarks = FALSE, CWnd* pParent = nullptr); // standard constructor + virtual ~CFavoriteAddDlg(); + + // Dialog Data + enum { IDD = IDD_FAVADD }; + + CString m_name; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual void OnOK(); + afx_msg void OnUpdateOk(CCmdUI* pCmdUI); + DECLARE_MESSAGE_MAP() + +private: + CMPCThemeComboBox m_namectrl; + CString m_shortname, m_fullname; + BOOL m_bEnableABMarks; + BOOL m_bRememberPos; + BOOL m_bRememberABMarks; + BOOL m_bRelativeDrive; +}; diff --git a/src/mpc-hc/FavoriteOrganizeDlg.cpp b/src/mpc-hc/FavoriteOrganizeDlg.cpp index 8165f9a5f98..ddaecb8bdab 100644 --- a/src/mpc-hc/FavoriteOrganizeDlg.cpp +++ b/src/mpc-hc/FavoriteOrganizeDlg.cpp @@ -1,532 +1,532 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "FavoriteOrganizeDlg.h" -#include "mplayerc.h" -#include "MainFrm.h" -#include "CMPCTheme.h" -#undef SubclassWindow - -// CFavoriteOrganizeDlg dialog - -//IMPLEMENT_DYNAMIC(CFavoriteOrganizeDlg, CMPCThemeResizableDialog) -CFavoriteOrganizeDlg::CFavoriteOrganizeDlg(CWnd* pParent /*=nullptr*/) - : CModelessResizableDialog(CFavoriteOrganizeDlg::IDD, pParent) -{ -} - -CFavoriteOrganizeDlg::~CFavoriteOrganizeDlg() -{ -} - -void CFavoriteOrganizeDlg::SetupList(bool fSave) -{ - - int i = m_tab.GetCurSel(); - - if (fSave) { - CAtlList sl; - - for (int j = 0; j < m_list.GetItemCount(); j++) { - CAtlList args; - ExplodeEsc(m_sl[i].GetAt((POSITION)m_list.GetItemData(j)), args, _T(';')); - args.RemoveHead(); - args.AddHead(m_list.GetItemText(j, 0)); - sl.AddTail(ImplodeEsc(args, _T(';'))); - } - m_sl[i].RemoveAll(); - m_sl[i].AddTailList(&sl); - SetupList(false); //reload the list to invalide the old itemdata - } else { - m_list.SetRedraw(FALSE); - m_list.DeleteAllItems(); - - for(POSITION pos = m_sl[i].GetHeadPosition(), tmp; pos; ) { - tmp = pos; - - FileFavorite ff; - VERIFY(FileFavorite::TryParse(m_sl[i].GetNext(pos), ff)); - - int n = m_list.InsertItem(m_list.GetItemCount(), ff.Name); - m_list.SetItemData(n, (DWORD_PTR)tmp); - - CString str = ff.ToString(); - if (!str.IsEmpty()) { - m_list.SetItemText(n, 1, str); - } - } - - UpdateColumnsSizes(); - m_list.SetRedraw(TRUE); - m_list.RedrawWindow(0, 0, RDW_INVALIDATE); - } -} - -void CFavoriteOrganizeDlg::UpdateColumnsSizes() -{ - CRect r; - m_list.GetClientRect(r); - m_list.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER); - if (firstSize) { - m_list.SetColumnWidth(1, LVSCW_AUTOSIZE); //this is needed to calculate the min width, but don't keep resetting it or you get flicker - firstSize = false; - minSizeTime = m_list.GetColumnWidth(1); - } - m_list.SetColumnWidth(1, std::max(minSizeTime, r.Width() - m_list.GetColumnWidth(0))); -} - -void CFavoriteOrganizeDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Control(pDX, IDC_TAB1, m_tab); - DDX_Control(pDX, IDC_LIST2, m_list); -} - - -BEGIN_MESSAGE_MAP(CFavoriteOrganizeDlg, CModelessResizableDialog) - ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnTcnSelchangeTab1) - ON_WM_DRAWITEM() - ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST2, OnLvnItemchangedList2) - ON_BN_CLICKED(IDC_BUTTON1, OnRenameBnClicked) - ON_UPDATE_COMMAND_UI(IDC_BUTTON1, OnUpdateRenameBn) - ON_BN_CLICKED(IDC_BUTTON2, OnDeleteBnClicked) - ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateDeleteBn) - ON_BN_CLICKED(IDC_BUTTON3, OnUpBnClicked) - ON_UPDATE_COMMAND_UI(IDC_BUTTON3, OnUpdateUpBn) - ON_BN_CLICKED(IDC_BUTTON4, OnDownBnClicked) - ON_UPDATE_COMMAND_UI(IDC_BUTTON4, OnUpdateDownBn) - ON_NOTIFY(TCN_SELCHANGING, IDC_TAB1, OnTcnSelchangingTab1) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_WM_ACTIVATE() - ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST2, OnLvnEndlabeleditList2) - ON_NOTIFY(NM_DBLCLK, IDC_LIST2, OnPlayFavorite) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST2, OnKeyPressed) - ON_NOTIFY(LVN_GETINFOTIP, IDC_LIST2, OnLvnGetInfoTipList) - ON_WM_SIZE() -END_MESSAGE_MAP() - -void CFavoriteOrganizeDlg::OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult) { - CWnd::UpdateDialogControls(this, TRUE); //needed for modeless dialog due to no idle pump -} -// CFavoriteOrganizeDlg message handlers - -BOOL CFavoriteOrganizeDlg::OnInitDialog() -{ - __super::OnInitDialog(); - if (GetExStyle() & WS_EX_TOPMOST) { - if (auto tt = m_list.GetToolTips()) { //when dialog is topmost, tooltips appear behind the dialog? - tt->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOMOVE); - } - } - firstSize = true; - minSizeTime = 0; - m_tab.InsertItem(0, ResStr(IDS_FAVFILES)); - m_tab.InsertItem(1, ResStr(IDS_FAVDVDS)); - // m_tab.InsertItem(2, ResStr(IDS_FAVDEVICES)); - m_tab.SetCurSel(0); - - m_list.InsertColumn(0, _T("")); - m_list.InsertColumn(1, _T("")); - m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_INFOTIP); - m_list.setAdditionalStyles(LVS_EX_FULLROWSELECT); - - LoadList(); - - AddAnchor(IDC_TAB1, TOP_LEFT, BOTTOM_RIGHT); - AddAnchor(IDC_LIST2, TOP_LEFT, BOTTOM_RIGHT); - AddAnchor(IDC_BUTTON1, TOP_RIGHT); - AddAnchor(IDC_BUTTON2, TOP_RIGHT); - AddAnchor(IDC_BUTTON3, TOP_RIGHT); - AddAnchor(IDC_BUTTON4, TOP_RIGHT); - AddAnchor(IDOK, BOTTOM_RIGHT); - EnableSaveRestore(IDS_R_DLG_ORGANIZE_FAV); - fulfillThemeReqs(); - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CFavoriteOrganizeDlg::LoadList() { - const CAppSettings& s = AfxGetAppSettings(); - s.GetFav(FAV_FILE, m_sl[0]); - s.GetFav(FAV_DVD, m_sl[1]); - s.GetFav(FAV_DEVICE, m_sl[2]); - - SetupList(false); -} - -BOOL CFavoriteOrganizeDlg::PreTranslateMessage(MSG* pMsg) -{ - // Inhibit default handling for the Enter key when the list has the focus and an item is selected. - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN - && pMsg->hwnd == m_list.GetSafeHwnd() && m_list.GetSelectedCount() > 0) { - return FALSE; - } - - return __super::PreTranslateMessage(pMsg); -} - -void CFavoriteOrganizeDlg::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult) -{ - SetupList(false); - - m_list.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - - *pResult = 0; -} - -void CFavoriteOrganizeDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - if (nIDCtl != IDC_LIST2) { - return; - } - - int nItem = lpDrawItemStruct->itemID; - if (m_list.IsItemVisible(nItem)) { - CEdit* pEdit = m_list.GetEditControl(); - - CRect rcItem = lpDrawItemStruct->rcItem; - CRect rText, rTime, rectDC, rHighlight; - - m_list.GetSubItemRect(nItem, 0, LVIR_LABEL, rText); - rText.left += 2; //magic number for column 0 - m_list.GetSubItemRect(nItem, 1, LVIR_LABEL, rTime); - rTime.right -= 6; //magic number for column >0, from right - rectDC = rcItem; - rHighlight = rcItem; - rHighlight.left = rText.left; - rHighlight.right = rTime.right; - - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - int savedDC = pDC->SaveDC(); - bool isSelected = !!m_list.GetItemState(nItem, LVIS_SELECTED); - bool isEdited = pEdit && ::IsWindow(pEdit->m_hWnd) && isSelected; - - CDC dcMem; - CBitmap bmMem; - CMPCThemeUtil::initMemDC(pDC, dcMem, bmMem, rectDC); - rcItem.OffsetRect(-rectDC.TopLeft()); - rText.OffsetRect(-rectDC.TopLeft()); - rTime.OffsetRect(-rectDC.TopLeft()); - rHighlight.OffsetRect(-rectDC.TopLeft()); - - if (AppIsThemeLoaded()) { - dcMem.FillSolidRect(rcItem, CMPCTheme::ContentBGColor); - } else { - dcMem.FillSolidRect(rcItem, GetSysColor(COLOR_WINDOW)); - } - - if (isSelected) { - if (AppIsThemeLoaded()) { - dcMem.FillSolidRect(rHighlight, CMPCTheme::ContentSelectedColor); - } else { - CBrush b2; - dcMem.FillSolidRect(rHighlight, 0xf1dacc); - b2.CreateSolidBrush(0xc56a31); - dcMem.FrameRect(rHighlight, &b2); - b2.DeleteObject(); - } - } - - COLORREF textcolor; - if (AppIsThemeLoaded()) { - textcolor = CMPCTheme::TextFGColor; - } else { - textcolor = 0; - } - dcMem.SetTextColor(textcolor); - - CString str; - - if (!isEdited) { - str = m_list.GetItemText(nItem, 0); - dcMem.DrawTextW(str, rText, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX); - } - str = m_list.GetItemText(nItem, 1); - if (!str.IsEmpty()) { - dcMem.DrawTextW(str, rTime, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_RIGHT | DT_NOPREFIX); - } - if (isEdited) { //added to reduce flicker while editing. - CRect r; - pEdit->GetWindowRect(r); - m_list.ScreenToClient(r); - pDC->ExcludeClipRect(r); - } - CMPCThemeUtil::flushMemDC(pDC, dcMem, rectDC); - pDC->RestoreDC(savedDC); - } -} - -void CFavoriteOrganizeDlg::OnRenameBnClicked() -{ - if (POSITION pos = m_list.GetFirstSelectedItemPosition()) { - m_list.SetFocus(); - m_list.EditLabel(m_list.GetNextSelectedItem(pos)); - } -} - -void CFavoriteOrganizeDlg::OnUpdateRenameBn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_list.GetSelectedCount() == 1); -} - -void CFavoriteOrganizeDlg::OnLvnEndlabeleditList2(NMHDR* pNMHDR, LRESULT* pResult) -{ - NMLVDISPINFO* pDispInfo = reinterpret_cast(pNMHDR); - if (pDispInfo->item.iItem >= 0 && pDispInfo->item.pszText) { - m_list.SetItemText(pDispInfo->item.iItem, 0, pDispInfo->item.pszText); - } - UpdateColumnsSizes(); - - *pResult = 0; -} - -void CFavoriteOrganizeDlg::PlayFavorite(int nItem) -{ - switch (m_tab.GetCurSel()) { - case 0: // Files - ((CMainFrame*)GetParentFrame())->PlayFavoriteFile(m_sl[0].GetAt((POSITION)m_list.GetItemData(nItem))); - break; - case 1: // DVDs - ((CMainFrame*)GetParentFrame())->PlayFavoriteDVD(m_sl[1].GetAt((POSITION)m_list.GetItemData(nItem))); - break; - case 2: // Devices - break; - } -} - -void CFavoriteOrganizeDlg::OnPlayFavorite(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMITEMACTIVATE pItemActivate = reinterpret_cast(pNMHDR); - - if (pItemActivate->iItem >= 0) { - PlayFavorite(pItemActivate->iItem); - } -} - -void CFavoriteOrganizeDlg::OnKeyPressed(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR; - - switch (pLVKeyDow->wVKey) { - case VK_DELETE: - case VK_BACK: - OnDeleteBnClicked(); - *pResult = 1; - break; - case VK_RETURN: - if (POSITION pos = m_list.GetFirstSelectedItemPosition()) { - int nItem = m_list.GetNextSelectedItem(pos); - if (nItem >= 0 && nItem < m_list.GetItemCount()) { - PlayFavorite(nItem); - } - } - *pResult = 1; - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) { // If the high-order bit is 1, the key is down; otherwise, it is up. - m_list.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED); - } - *pResult = 1; - break; - case 'I': - if (GetKeyState(VK_CONTROL) < 0) { // If the high-order bit is 1, the key is down; otherwise, it is up. - for (int nItem = 0; nItem < m_list.GetItemCount(); nItem++) { - m_list.SetItemState(nItem, ~m_list.GetItemState(nItem, LVIS_SELECTED), LVIS_SELECTED); - } - } - *pResult = 1; - break; - - case 'C': - if (GetKeyState(VK_CONTROL) < 0) { - if(m_tab.GetCurSel() == 0) { // Files - CopyToClipboard(); - } - } - *pResult = 1; - break; - default: - *pResult = 0; - } -} - -void CFavoriteOrganizeDlg::OnDeleteBnClicked() -{ - POSITION pos; - int nItem = -1; - - while ((pos = m_list.GetFirstSelectedItemPosition()) != nullptr) { - nItem = m_list.GetNextSelectedItem(pos); - if (nItem < 0 || nItem >= m_list.GetItemCount()) { - return; - } - - m_list.DeleteItem(nItem); - } - - nItem = std::min(nItem, m_list.GetItemCount() - 1); - m_list.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED); -} - -void CFavoriteOrganizeDlg::OnUpdateDeleteBn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_list.GetSelectedCount() > 0); -} - -void CFavoriteOrganizeDlg::MoveItem(int nItem, int offset) -{ - DWORD_PTR data = m_list.GetItemData(nItem); - CString strName = m_list.GetItemText(nItem, 0); - CString strPos = m_list.GetItemText(nItem, 1); - - m_list.DeleteItem(nItem); - - nItem += offset; - - m_list.InsertItem(nItem, strName); - m_list.SetItemData(nItem, data); - m_list.SetItemText(nItem, 1, strPos); - m_list.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED); -} - -void CFavoriteOrganizeDlg::OnUpBnClicked() -{ - POSITION pos = m_list.GetFirstSelectedItemPosition(); - - while (pos) { - int nItem = m_list.GetNextSelectedItem(pos); - if (nItem <= 0 || nItem >= m_list.GetItemCount()) { - return; - } - - MoveItem(nItem, -1); - } -} - -void CFavoriteOrganizeDlg::OnUpdateUpBn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_list.GetSelectedCount() > 0 && !m_list.GetItemState(0, LVIS_SELECTED)); -} - -void CFavoriteOrganizeDlg::OnDownBnClicked() -{ - CArray selectedItems; - POSITION pos = m_list.GetFirstSelectedItemPosition(); - - while (pos) { - int nItem = m_list.GetNextSelectedItem(pos); - if (nItem < 0 || nItem >= m_list.GetItemCount() - 1) { - return; - } - - selectedItems.Add(nItem); - } - - for (INT_PTR i = selectedItems.GetSize() - 1; i >= 0; i--) { - MoveItem(selectedItems[i], +1); - } -} - -void CFavoriteOrganizeDlg::OnUpdateDownBn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_list.GetSelectedCount() > 0 && !m_list.GetItemState(m_list.GetItemCount() - 1, LVIS_SELECTED)); -} - -void CFavoriteOrganizeDlg::OnTcnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult) -{ - SetupList(true); - - *pResult = 0; -} - -void CFavoriteOrganizeDlg::OnBnClickedOk() -{ - SetupList(true); - - CAppSettings& s = AfxGetAppSettings(); - s.SetFav(FAV_FILE, m_sl[0]); - s.SetFav(FAV_DVD, m_sl[1]); - s.SetFav(FAV_DEVICE, m_sl[2]); - - OnOK(); -} - -void CFavoriteOrganizeDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) -{ - __super::OnActivate(nState, pWndOther, bMinimized); - - if (nState == WA_ACTIVE) { - m_list.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - } -} - -void CFavoriteOrganizeDlg::OnSize(UINT nType, int cx, int cy) -{ - __super::OnSize(nType, cx, cy); - - if (IsWindow(m_list)) { - UpdateColumnsSizes(); //on first size, we need to call this, or it doesn't use the full window until a rename/resize - } -} - -void CFavoriteOrganizeDlg::OnLvnGetInfoTipList(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast(pNMHDR); - - CAtlList args; - ExplodeEsc(m_sl[m_tab.GetCurSel()].GetAt((POSITION)m_list.GetItemData(pGetInfoTip->iItem)), args, _T(';')); - CString path = args.RemoveTail(); - // Relative to drive value is always third. If less args are available that means it is not included. - int rootLength = (args.GetCount() == 3 && args.RemoveTail() != _T("0")) ? CPath(path).SkipRoot() : 0; - - StringCchCopyW(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path.Mid(rootLength)); - - *pResult = 0; -} - - -void CFavoriteOrganizeDlg::CopyToClipboard() -{ - CAtlList* pSL = &m_sl[m_tab.GetCurSel()]; - - // Iterate through selected items - CString favorites; - for(POSITION pos = m_list.GetFirstSelectedItemPosition(); pos; ) { - int iItem = m_list.GetNextSelectedItem(pos); - const CString& fav = pSL->GetAt((POSITION)m_list.GetItemData(iItem)); - CAtlList args; - ((CMainFrame*)GetParentFrame())->ParseFavoriteFile(fav, args); - - CString path = args.GetHead().Trim(); - if (!path.IsEmpty()) { - favorites.Append(path); - favorites.Append(_T("\r\n")); - } - } - - if (!favorites.IsEmpty()) { - CClipboard clipboard(this); - VERIFY(clipboard.SetText(favorites)); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "FavoriteOrganizeDlg.h" +#include "mplayerc.h" +#include "MainFrm.h" +#include "CMPCTheme.h" +#undef SubclassWindow + +// CFavoriteOrganizeDlg dialog + +//IMPLEMENT_DYNAMIC(CFavoriteOrganizeDlg, CMPCThemeResizableDialog) +CFavoriteOrganizeDlg::CFavoriteOrganizeDlg(CWnd* pParent /*=nullptr*/) + : CModelessResizableDialog(CFavoriteOrganizeDlg::IDD, pParent) +{ +} + +CFavoriteOrganizeDlg::~CFavoriteOrganizeDlg() +{ +} + +void CFavoriteOrganizeDlg::SetupList(bool fSave) +{ + + int i = m_tab.GetCurSel(); + + if (fSave) { + CAtlList sl; + + for (int j = 0; j < m_list.GetItemCount(); j++) { + CAtlList args; + ExplodeEsc(m_sl[i].GetAt((POSITION)m_list.GetItemData(j)), args, _T(';')); + args.RemoveHead(); + args.AddHead(m_list.GetItemText(j, 0)); + sl.AddTail(ImplodeEsc(args, _T(';'))); + } + m_sl[i].RemoveAll(); + m_sl[i].AddTailList(&sl); + SetupList(false); //reload the list to invalide the old itemdata + } else { + m_list.SetRedraw(FALSE); + m_list.DeleteAllItems(); + + for(POSITION pos = m_sl[i].GetHeadPosition(), tmp; pos; ) { + tmp = pos; + + FileFavorite ff; + VERIFY(FileFavorite::TryParse(m_sl[i].GetNext(pos), ff)); + + int n = m_list.InsertItem(m_list.GetItemCount(), ff.Name); + m_list.SetItemData(n, (DWORD_PTR)tmp); + + CString str = ff.ToString(); + if (!str.IsEmpty()) { + m_list.SetItemText(n, 1, str); + } + } + + UpdateColumnsSizes(); + m_list.SetRedraw(TRUE); + m_list.RedrawWindow(0, 0, RDW_INVALIDATE); + } +} + +void CFavoriteOrganizeDlg::UpdateColumnsSizes() +{ + CRect r; + m_list.GetClientRect(r); + m_list.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER); + if (firstSize) { + m_list.SetColumnWidth(1, LVSCW_AUTOSIZE); //this is needed to calculate the min width, but don't keep resetting it or you get flicker + firstSize = false; + minSizeTime = m_list.GetColumnWidth(1); + } + m_list.SetColumnWidth(1, std::max(minSizeTime, r.Width() - m_list.GetColumnWidth(0))); +} + +void CFavoriteOrganizeDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDC_TAB1, m_tab); + DDX_Control(pDX, IDC_LIST2, m_list); +} + + +BEGIN_MESSAGE_MAP(CFavoriteOrganizeDlg, CModelessResizableDialog) + ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnTcnSelchangeTab1) + ON_WM_DRAWITEM() + ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST2, OnLvnItemchangedList2) + ON_BN_CLICKED(IDC_BUTTON1, OnRenameBnClicked) + ON_UPDATE_COMMAND_UI(IDC_BUTTON1, OnUpdateRenameBn) + ON_BN_CLICKED(IDC_BUTTON2, OnDeleteBnClicked) + ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateDeleteBn) + ON_BN_CLICKED(IDC_BUTTON3, OnUpBnClicked) + ON_UPDATE_COMMAND_UI(IDC_BUTTON3, OnUpdateUpBn) + ON_BN_CLICKED(IDC_BUTTON4, OnDownBnClicked) + ON_UPDATE_COMMAND_UI(IDC_BUTTON4, OnUpdateDownBn) + ON_NOTIFY(TCN_SELCHANGING, IDC_TAB1, OnTcnSelchangingTab1) + ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_WM_ACTIVATE() + ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST2, OnLvnEndlabeleditList2) + ON_NOTIFY(NM_DBLCLK, IDC_LIST2, OnPlayFavorite) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST2, OnKeyPressed) + ON_NOTIFY(LVN_GETINFOTIP, IDC_LIST2, OnLvnGetInfoTipList) + ON_WM_SIZE() +END_MESSAGE_MAP() + +void CFavoriteOrganizeDlg::OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult) { + CWnd::UpdateDialogControls(this, TRUE); //needed for modeless dialog due to no idle pump +} +// CFavoriteOrganizeDlg message handlers + +BOOL CFavoriteOrganizeDlg::OnInitDialog() +{ + __super::OnInitDialog(); + if (GetExStyle() & WS_EX_TOPMOST) { + if (auto tt = m_list.GetToolTips()) { //when dialog is topmost, tooltips appear behind the dialog? + tt->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOMOVE); + } + } + firstSize = true; + minSizeTime = 0; + m_tab.InsertItem(0, ResStr(IDS_FAVFILES)); + m_tab.InsertItem(1, ResStr(IDS_FAVDVDS)); + // m_tab.InsertItem(2, ResStr(IDS_FAVDEVICES)); + m_tab.SetCurSel(0); + + m_list.InsertColumn(0, _T("")); + m_list.InsertColumn(1, _T("")); + m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_INFOTIP); + m_list.setAdditionalStyles(LVS_EX_FULLROWSELECT); + + LoadList(); + + AddAnchor(IDC_TAB1, TOP_LEFT, BOTTOM_RIGHT); + AddAnchor(IDC_LIST2, TOP_LEFT, BOTTOM_RIGHT); + AddAnchor(IDC_BUTTON1, TOP_RIGHT); + AddAnchor(IDC_BUTTON2, TOP_RIGHT); + AddAnchor(IDC_BUTTON3, TOP_RIGHT); + AddAnchor(IDC_BUTTON4, TOP_RIGHT); + AddAnchor(IDOK, BOTTOM_RIGHT); + EnableSaveRestore(IDS_R_DLG_ORGANIZE_FAV); + fulfillThemeReqs(); + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CFavoriteOrganizeDlg::LoadList() { + const CAppSettings& s = AfxGetAppSettings(); + s.GetFav(FAV_FILE, m_sl[0]); + s.GetFav(FAV_DVD, m_sl[1]); + s.GetFav(FAV_DEVICE, m_sl[2]); + + SetupList(false); +} + +BOOL CFavoriteOrganizeDlg::PreTranslateMessage(MSG* pMsg) +{ + // Inhibit default handling for the Enter key when the list has the focus and an item is selected. + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN + && pMsg->hwnd == m_list.GetSafeHwnd() && m_list.GetSelectedCount() > 0) { + return FALSE; + } + + return __super::PreTranslateMessage(pMsg); +} + +void CFavoriteOrganizeDlg::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult) +{ + SetupList(false); + + m_list.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + + *pResult = 0; +} + +void CFavoriteOrganizeDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (nIDCtl != IDC_LIST2) { + return; + } + + int nItem = lpDrawItemStruct->itemID; + if (m_list.IsItemVisible(nItem)) { + CEdit* pEdit = m_list.GetEditControl(); + + CRect rcItem = lpDrawItemStruct->rcItem; + CRect rText, rTime, rectDC, rHighlight; + + m_list.GetSubItemRect(nItem, 0, LVIR_LABEL, rText); + rText.left += 2; //magic number for column 0 + m_list.GetSubItemRect(nItem, 1, LVIR_LABEL, rTime); + rTime.right -= 6; //magic number for column >0, from right + rectDC = rcItem; + rHighlight = rcItem; + rHighlight.left = rText.left; + rHighlight.right = rTime.right; + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + int savedDC = pDC->SaveDC(); + bool isSelected = !!m_list.GetItemState(nItem, LVIS_SELECTED); + bool isEdited = pEdit && ::IsWindow(pEdit->m_hWnd) && isSelected; + + CDC dcMem; + CBitmap bmMem; + CMPCThemeUtil::initMemDC(pDC, dcMem, bmMem, rectDC); + rcItem.OffsetRect(-rectDC.TopLeft()); + rText.OffsetRect(-rectDC.TopLeft()); + rTime.OffsetRect(-rectDC.TopLeft()); + rHighlight.OffsetRect(-rectDC.TopLeft()); + + if (AppIsThemeLoaded()) { + dcMem.FillSolidRect(rcItem, CMPCTheme::ContentBGColor); + } else { + dcMem.FillSolidRect(rcItem, GetSysColor(COLOR_WINDOW)); + } + + if (isSelected) { + if (AppIsThemeLoaded()) { + dcMem.FillSolidRect(rHighlight, CMPCTheme::ContentSelectedColor); + } else { + CBrush b2; + dcMem.FillSolidRect(rHighlight, 0xf1dacc); + b2.CreateSolidBrush(0xc56a31); + dcMem.FrameRect(rHighlight, &b2); + b2.DeleteObject(); + } + } + + COLORREF textcolor; + if (AppIsThemeLoaded()) { + textcolor = CMPCTheme::TextFGColor; + } else { + textcolor = 0; + } + dcMem.SetTextColor(textcolor); + + CString str; + + if (!isEdited) { + str = m_list.GetItemText(nItem, 0); + dcMem.DrawTextW(str, rText, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX); + } + str = m_list.GetItemText(nItem, 1); + if (!str.IsEmpty()) { + dcMem.DrawTextW(str, rTime, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_RIGHT | DT_NOPREFIX); + } + if (isEdited) { //added to reduce flicker while editing. + CRect r; + pEdit->GetWindowRect(r); + m_list.ScreenToClient(r); + pDC->ExcludeClipRect(r); + } + CMPCThemeUtil::flushMemDC(pDC, dcMem, rectDC); + pDC->RestoreDC(savedDC); + } +} + +void CFavoriteOrganizeDlg::OnRenameBnClicked() +{ + if (POSITION pos = m_list.GetFirstSelectedItemPosition()) { + m_list.SetFocus(); + m_list.EditLabel(m_list.GetNextSelectedItem(pos)); + } +} + +void CFavoriteOrganizeDlg::OnUpdateRenameBn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_list.GetSelectedCount() == 1); +} + +void CFavoriteOrganizeDlg::OnLvnEndlabeleditList2(NMHDR* pNMHDR, LRESULT* pResult) +{ + NMLVDISPINFO* pDispInfo = reinterpret_cast(pNMHDR); + if (pDispInfo->item.iItem >= 0 && pDispInfo->item.pszText) { + m_list.SetItemText(pDispInfo->item.iItem, 0, pDispInfo->item.pszText); + } + UpdateColumnsSizes(); + + *pResult = 0; +} + +void CFavoriteOrganizeDlg::PlayFavorite(int nItem) +{ + switch (m_tab.GetCurSel()) { + case 0: // Files + ((CMainFrame*)GetParentFrame())->PlayFavoriteFile(m_sl[0].GetAt((POSITION)m_list.GetItemData(nItem))); + break; + case 1: // DVDs + ((CMainFrame*)GetParentFrame())->PlayFavoriteDVD(m_sl[1].GetAt((POSITION)m_list.GetItemData(nItem))); + break; + case 2: // Devices + break; + } +} + +void CFavoriteOrganizeDlg::OnPlayFavorite(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMITEMACTIVATE pItemActivate = reinterpret_cast(pNMHDR); + + if (pItemActivate->iItem >= 0) { + PlayFavorite(pItemActivate->iItem); + } +} + +void CFavoriteOrganizeDlg::OnKeyPressed(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR; + + switch (pLVKeyDow->wVKey) { + case VK_DELETE: + case VK_BACK: + OnDeleteBnClicked(); + *pResult = 1; + break; + case VK_RETURN: + if (POSITION pos = m_list.GetFirstSelectedItemPosition()) { + int nItem = m_list.GetNextSelectedItem(pos); + if (nItem >= 0 && nItem < m_list.GetItemCount()) { + PlayFavorite(nItem); + } + } + *pResult = 1; + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) { // If the high-order bit is 1, the key is down; otherwise, it is up. + m_list.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED); + } + *pResult = 1; + break; + case 'I': + if (GetKeyState(VK_CONTROL) < 0) { // If the high-order bit is 1, the key is down; otherwise, it is up. + for (int nItem = 0; nItem < m_list.GetItemCount(); nItem++) { + m_list.SetItemState(nItem, ~m_list.GetItemState(nItem, LVIS_SELECTED), LVIS_SELECTED); + } + } + *pResult = 1; + break; + + case 'C': + if (GetKeyState(VK_CONTROL) < 0) { + if(m_tab.GetCurSel() == 0) { // Files + CopyToClipboard(); + } + } + *pResult = 1; + break; + default: + *pResult = 0; + } +} + +void CFavoriteOrganizeDlg::OnDeleteBnClicked() +{ + POSITION pos; + int nItem = -1; + + while ((pos = m_list.GetFirstSelectedItemPosition()) != nullptr) { + nItem = m_list.GetNextSelectedItem(pos); + if (nItem < 0 || nItem >= m_list.GetItemCount()) { + return; + } + + m_list.DeleteItem(nItem); + } + + nItem = std::min(nItem, m_list.GetItemCount() - 1); + m_list.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED); +} + +void CFavoriteOrganizeDlg::OnUpdateDeleteBn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_list.GetSelectedCount() > 0); +} + +void CFavoriteOrganizeDlg::MoveItem(int nItem, int offset) +{ + DWORD_PTR data = m_list.GetItemData(nItem); + CString strName = m_list.GetItemText(nItem, 0); + CString strPos = m_list.GetItemText(nItem, 1); + + m_list.DeleteItem(nItem); + + nItem += offset; + + m_list.InsertItem(nItem, strName); + m_list.SetItemData(nItem, data); + m_list.SetItemText(nItem, 1, strPos); + m_list.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED); +} + +void CFavoriteOrganizeDlg::OnUpBnClicked() +{ + POSITION pos = m_list.GetFirstSelectedItemPosition(); + + while (pos) { + int nItem = m_list.GetNextSelectedItem(pos); + if (nItem <= 0 || nItem >= m_list.GetItemCount()) { + return; + } + + MoveItem(nItem, -1); + } +} + +void CFavoriteOrganizeDlg::OnUpdateUpBn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_list.GetSelectedCount() > 0 && !m_list.GetItemState(0, LVIS_SELECTED)); +} + +void CFavoriteOrganizeDlg::OnDownBnClicked() +{ + CArray selectedItems; + POSITION pos = m_list.GetFirstSelectedItemPosition(); + + while (pos) { + int nItem = m_list.GetNextSelectedItem(pos); + if (nItem < 0 || nItem >= m_list.GetItemCount() - 1) { + return; + } + + selectedItems.Add(nItem); + } + + for (INT_PTR i = selectedItems.GetSize() - 1; i >= 0; i--) { + MoveItem(selectedItems[i], +1); + } +} + +void CFavoriteOrganizeDlg::OnUpdateDownBn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_list.GetSelectedCount() > 0 && !m_list.GetItemState(m_list.GetItemCount() - 1, LVIS_SELECTED)); +} + +void CFavoriteOrganizeDlg::OnTcnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult) +{ + SetupList(true); + + *pResult = 0; +} + +void CFavoriteOrganizeDlg::OnBnClickedOk() +{ + SetupList(true); + + CAppSettings& s = AfxGetAppSettings(); + s.SetFav(FAV_FILE, m_sl[0]); + s.SetFav(FAV_DVD, m_sl[1]); + s.SetFav(FAV_DEVICE, m_sl[2]); + + OnOK(); +} + +void CFavoriteOrganizeDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) +{ + __super::OnActivate(nState, pWndOther, bMinimized); + + if (nState == WA_ACTIVE) { + m_list.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } +} + +void CFavoriteOrganizeDlg::OnSize(UINT nType, int cx, int cy) +{ + __super::OnSize(nType, cx, cy); + + if (IsWindow(m_list)) { + UpdateColumnsSizes(); //on first size, we need to call this, or it doesn't use the full window until a rename/resize + } +} + +void CFavoriteOrganizeDlg::OnLvnGetInfoTipList(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast(pNMHDR); + + CAtlList args; + ExplodeEsc(m_sl[m_tab.GetCurSel()].GetAt((POSITION)m_list.GetItemData(pGetInfoTip->iItem)), args, _T(';')); + CString path = args.RemoveTail(); + // Relative to drive value is always third. If less args are available that means it is not included. + int rootLength = (args.GetCount() == 3 && args.RemoveTail() != _T("0")) ? CPath(path).SkipRoot() : 0; + + StringCchCopyW(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path.Mid(rootLength)); + + *pResult = 0; +} + + +void CFavoriteOrganizeDlg::CopyToClipboard() +{ + CAtlList* pSL = &m_sl[m_tab.GetCurSel()]; + + // Iterate through selected items + CString favorites; + for(POSITION pos = m_list.GetFirstSelectedItemPosition(); pos; ) { + int iItem = m_list.GetNextSelectedItem(pos); + const CString& fav = pSL->GetAt((POSITION)m_list.GetItemData(iItem)); + CAtlList args; + ((CMainFrame*)GetParentFrame())->ParseFavoriteFile(fav, args); + + CString path = args.GetHead().Trim(); + if (!path.IsEmpty()) { + favorites.Append(path); + favorites.Append(_T("\r\n")); + } + } + + if (!favorites.IsEmpty()) { + CClipboard clipboard(this); + VERIFY(clipboard.SetText(favorites)); + } +} diff --git a/src/mpc-hc/FavoriteOrganizeDlg.h b/src/mpc-hc/FavoriteOrganizeDlg.h index 00ea165aa33..b1235794cd7 100644 --- a/src/mpc-hc/FavoriteOrganizeDlg.h +++ b/src/mpc-hc/FavoriteOrganizeDlg.h @@ -1,84 +1,84 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "ModelessResizableDialog.h" -#include "CMPCThemeTabCtrl.h" -#include "CMPCThemePlayerListCtrl.h" - -// CFavoriteOrganizeDlg dialog - -class CFavoriteOrganizeDlg : public CModelessResizableDialog -{ - // DECLARE_DYNAMIC(CFavoriteOrganizeDlg) - -private: - CAtlList m_sl[3]; - -public: - CFavoriteOrganizeDlg(CWnd* pParent = nullptr); // standard constructor - virtual ~CFavoriteOrganizeDlg(); - - virtual BOOL PreTranslateMessage(MSG* pMsg); - - // Dialog Data - enum { IDD = IDD_FAVORGANIZE }; - - CMPCThemeTabCtrl m_tab; - CMPCThemePlayerListCtrl m_list; - bool firstSize=false; - int minSizeTime = 0; - void LoadList(); - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - - void SetupList(bool fSave); - - void UpdateColumnsSizes(); - void MoveItem(int nItem, int offset); - void PlayFavorite(int nItem); - void CopyToClipboard(); - - DECLARE_MESSAGE_MAP() -public: - afx_msg void OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); - afx_msg void OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnRenameBnClicked(); - afx_msg void OnUpdateRenameBn(CCmdUI* pCmdUI); - afx_msg void OnDeleteBnClicked(); - afx_msg void OnUpdateDeleteBn(CCmdUI* pCmdUI); - afx_msg void OnUpBnClicked(); - afx_msg void OnUpdateUpBn(CCmdUI* pCmdUI); - afx_msg void OnDownBnClicked(); - afx_msg void OnUpdateDownBn(CCmdUI* pCmdUI); - afx_msg void OnTcnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnBnClickedOk(); - afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); - afx_msg void OnLvnEndlabeleditList2(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnPlayFavorite(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnKeyPressed(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnLvnGetInfoTipList(NMHDR* pNMHDR, LRESULT* pResult); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "ModelessResizableDialog.h" +#include "CMPCThemeTabCtrl.h" +#include "CMPCThemePlayerListCtrl.h" + +// CFavoriteOrganizeDlg dialog + +class CFavoriteOrganizeDlg : public CModelessResizableDialog +{ + // DECLARE_DYNAMIC(CFavoriteOrganizeDlg) + +private: + CAtlList m_sl[3]; + +public: + CFavoriteOrganizeDlg(CWnd* pParent = nullptr); // standard constructor + virtual ~CFavoriteOrganizeDlg(); + + virtual BOOL PreTranslateMessage(MSG* pMsg); + + // Dialog Data + enum { IDD = IDD_FAVORGANIZE }; + + CMPCThemeTabCtrl m_tab; + CMPCThemePlayerListCtrl m_list; + bool firstSize=false; + int minSizeTime = 0; + void LoadList(); + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + + void SetupList(bool fSave); + + void UpdateColumnsSizes(); + void MoveItem(int nItem, int offset); + void PlayFavorite(int nItem); + void CopyToClipboard(); + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); + afx_msg void OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnRenameBnClicked(); + afx_msg void OnUpdateRenameBn(CCmdUI* pCmdUI); + afx_msg void OnDeleteBnClicked(); + afx_msg void OnUpdateDeleteBn(CCmdUI* pCmdUI); + afx_msg void OnUpBnClicked(); + afx_msg void OnUpdateUpBn(CCmdUI* pCmdUI); + afx_msg void OnDownBnClicked(); + afx_msg void OnUpdateDownBn(CCmdUI* pCmdUI); + afx_msg void OnTcnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnBnClickedOk(); + afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); + afx_msg void OnLvnEndlabeleditList2(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnPlayFavorite(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnKeyPressed(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnLvnGetInfoTipList(NMHDR* pNMHDR, LRESULT* pResult); +}; diff --git a/src/mpc-hc/FileAssoc.cpp b/src/mpc-hc/FileAssoc.cpp index 77fe30ee093..b09c5713db9 100644 --- a/src/mpc-hc/FileAssoc.cpp +++ b/src/mpc-hc/FileAssoc.cpp @@ -1,744 +1,744 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include -#include "mplayerc.h" -#include "FileAssoc.h" -#include "resource.h" -#include "PathUtils.h" - - -// TODO: change this along with the root key for settings and the mutex name to -// avoid possible risks of conflict with the old MPC (non HC version). -#ifdef _WIN64 -#define PROGID _T("mplayerc64") -#else -#define PROGID _T("mplayerc") -#endif // _WIN64 - -CFileAssoc::IconLib::IconLib(GetIconIndexFunc fnGetIconIndex, GetIconLibVersionFunc fnGetIconLibVersion, HMODULE hLib) - : m_fnGetIconIndex(fnGetIconIndex) - , m_fnGetIconLibVersion(fnGetIconLibVersion) - , m_hLib(hLib) -{ - ASSERT(fnGetIconIndex && fnGetIconLibVersion && hLib); -} - -CFileAssoc::IconLib::~IconLib() -{ - VERIFY(FreeLibrary(m_hLib)); -} - -int CFileAssoc::IconLib::GetIconIndex(const CString& str) const -{ - return m_fnGetIconIndex(str); -} - -UINT CFileAssoc::IconLib::GetVersion() const -{ - return m_fnGetIconLibVersion(); -} - -void CFileAssoc::IconLib::SaveVersion() const -{ - AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ICON_LIB_VERSION, m_fnGetIconLibVersion()); -} - -CFileAssoc::CFileAssoc() - : m_iconLibPath(PathUtils::CombinePaths(PathUtils::GetProgramPath(), _T("mpciconlib.dll"))) - , m_strRegisteredAppName(_T("Media Player Classic")) - , m_strOldAssocKey(_T("PreviousRegistration")) - , m_strRegisteredAppKey(_T("Software\\Clients\\Media\\Media Player Classic\\Capabilities")) - , m_strRegAppFileAssocKey(_T("Software\\Clients\\Media\\Media Player Classic\\Capabilities\\FileAssociations")) - , m_strOpenCommand(_T("\"") + PathUtils::GetProgramPath(true) + _T("\" \"%1\"")) - , m_strEnqueueCommand(_T("\"") + PathUtils::GetProgramPath(true) + _T("\" /add \"%1\"")) - , m_bNoRecentDocs(false) - , m_checkIconsAssocInactiveEvent(TRUE, TRUE) // initially set, manual reset -{ - // Default manager (requires at least Vista) - VERIFY(CoCreateInstance(CLSID_ApplicationAssociationRegistration, nullptr, - CLSCTX_INPROC, IID_PPV_ARGS(&m_pAAR)) != CO_E_NOTINITIALIZED); - - m_handlers[0] = { _T("VideoFiles"), _T(" %1"), IDS_AUTOPLAY_PLAYVIDEO }; - m_handlers[1] = { _T("MusicFiles"), _T(" %1"), IDS_AUTOPLAY_PLAYMUSIC }; - m_handlers[2] = { _T("CDAudio"), _T(" %1 /cd"), IDS_AUTOPLAY_PLAYAUDIOCD }; - m_handlers[3] = { _T("DVDMovie"), _T(" %1 /dvd"), IDS_AUTOPLAY_PLAYDVDMOVIE }; -} - -CFileAssoc::~CFileAssoc() -{ - HANDLE hEvent = m_checkIconsAssocInactiveEvent; - DWORD dwEvent; - VERIFY(CoWaitForMultipleHandles(0, INFINITE, 1, &hEvent, &dwEvent) == S_OK); -} - -std::shared_ptr CFileAssoc::GetIconLib() const -{ - std::shared_ptr ret; - if (HMODULE hLib = LoadLibrary(m_iconLibPath)) { - auto fnGetIconIndex = reinterpret_cast(GetProcAddress(hLib, "GetIconIndex")); - auto fnGetIconLibVersion = reinterpret_cast(GetProcAddress(hLib, "GetIconLibVersion")); - if (fnGetIconIndex && fnGetIconLibVersion) { - ret = std::make_shared(fnGetIconIndex, fnGetIconLibVersion, hLib); - } else { - VERIFY(FreeLibrary(hLib)); - } - } - return ret; -} - -void CFileAssoc::SetNoRecentDocs(bool bNoRecentDocs, bool bUpdateAssocs /*= false*/) -{ - if (bNoRecentDocs == m_bNoRecentDocs) { - bUpdateAssocs = false; - } else { - m_bNoRecentDocs = bNoRecentDocs; - } - - CAtlList exts; - if (bUpdateAssocs && GetAssociatedExtensionsFromRegistry(exts)) { - CRegKey key; - POSITION pos = exts.GetHeadPosition(); - while (pos) { - const CString& ext = exts.GetNext(pos); - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, PROGID + ext)) { - if (m_bNoRecentDocs) { - key.SetStringValue(_T("NoRecentDocs"), _T("")); - } else { - key.DeleteValue(_T("NoRecentDocs")); - } - } - } - } -} - -bool CFileAssoc::RegisterApp() -{ - bool success = false; - - if (m_pAAR) { - CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); - - // Register MPC-HC for the windows "Default application" manager - CRegKey key; - - if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\RegisteredApplications"))) { - key.SetStringValue(_T("Media Player Classic"), m_strRegisteredAppKey); - - if (ERROR_SUCCESS == key.Create(HKEY_LOCAL_MACHINE, m_strRegisteredAppKey)) { - // ==>> TODO icon !!! - key.SetStringValue(_T("ApplicationDescription"), ResStr(IDS_APP_DESCRIPTION), REG_EXPAND_SZ); - key.SetStringValue(_T("ApplicationIcon"), appIcon, REG_EXPAND_SZ); - key.SetStringValue(_T("ApplicationName"), ResStr(IDR_MAINFRAME), REG_EXPAND_SZ); - - success = true; - } - } - } - - return success; -} - -bool CFileAssoc::Register(CString ext, CString strLabel, bool bRegister, bool bAddEnqueueContextMenu, bool bAssociatedWithIcon) -{ - CRegKey key; - CString strProgID = PROGID + ext; - - if (!bRegister) { - // On Windows 8, an app can't set itself as the default handler for a format - if (!IsWindows8OrGreater() && bRegister != IsRegistered(ext)) { - SetFileAssociation(ext, strProgID, bRegister); - } - - key.Attach(HKEY_CLASSES_ROOT); - key.RecurseDeleteKey(strProgID); - - if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, m_strRegAppFileAssocKey)) { - key.DeleteValue(ext); - } - - return true; - } else { - // Create ProgID for this file type - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID) - || ERROR_SUCCESS != key.SetStringValue(nullptr, strLabel)) { - return false; - } - - if (m_bNoRecentDocs) { - key.SetStringValue(_T("NoRecentDocs"), _T("")); - } else { - key.DeleteValue(_T("NoRecentDocs")); - } - - CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); - - // Add to playlist option - if (bAddEnqueueContextMenu) { - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, ResStr(IDS_ADD_TO_PLAYLIST)) - || ERROR_SUCCESS != key.SetStringValue(_T("Icon"), appIcon) - || ERROR_SUCCESS != key.SetStringValue(_T("MultiSelectModel"), _T("Player")) - || ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue\\command")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, m_strEnqueueCommand)) { - return false; - } - } else { - key.Close(); - key.Attach(HKEY_CLASSES_ROOT); - key.RecurseDeleteKey(strProgID + _T("\\shell\\enqueue")); - } - - // Play option - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open"))) { - return false; - } - if (ERROR_SUCCESS != key.SetStringValue(nullptr, ResStr(IDS_OPEN_WITH_MPC)) - || ERROR_SUCCESS != key.SetStringValue(_T("MultiSelectModel"), _T("Player")) - || ERROR_SUCCESS != key.SetStringValue(_T("Icon"), appIcon)) { - return false; - } - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open\\command")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, m_strOpenCommand)) { - return false; - } - - if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, m_strRegAppFileAssocKey) - || key.SetStringValue(ext, strProgID)) { - return false; - } - - if (bAssociatedWithIcon) { - if (auto iconLib = GetIconLib()) { - int iconIndex = iconLib->GetIconIndex(ext); - - /* icon_index value -1 means no icon was found in the iconlib for the file extension */ - if (iconIndex >= 0 && ExtractIcon(AfxGetApp()->m_hInstance, m_iconLibPath, iconIndex)) { - appIcon.Format(_T("\"%s\",%d"), m_iconLibPath.GetString(), iconIndex); - } - } - - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\DefaultIcon")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, appIcon)) { - return false; - } - } else { - key.Close(); - key.Attach(HKEY_CLASSES_ROOT); - key.RecurseDeleteKey(strProgID + _T("\\DefaultIcon")); - } - - // On Windows 8, an app can't set itself as the default handler for a format - if (!IsWindows8OrGreater() && bRegister != IsRegistered(ext)) { - SetFileAssociation(ext, strProgID, bRegister); - } - - return true; - } -} - -bool CFileAssoc::SetFileAssociation(CString strExt, CString strProgID, bool bRegister) -{ - CString extOldReg; - CRegKey key; - HRESULT hr = S_OK; - TCHAR buff[MAX_PATH]; - ULONG len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - - if (m_pAAR) { - // The Windows 7 way - CString strNewApp; - if (bRegister) { - // Create non existing file type - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strExt)) { - return false; - } - - CComHeapPtr pszCurrentAssociation; - // Save the application currently associated - if (SUCCEEDED(m_pAAR->QueryCurrentDefault(strExt, AT_FILEEXTENSION, AL_EFFECTIVE, &pszCurrentAssociation))) { - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID)) { - return false; - } - - key.SetStringValue(m_strOldAssocKey, pszCurrentAssociation); - } - strNewApp = m_strRegisteredAppName; - } else { - if (ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, strProgID)) { - return false; - } - - if (ERROR_SUCCESS == key.QueryStringValue(m_strOldAssocKey, buff, &len)) { - strNewApp = buff; - } - } - - hr = m_pAAR->SetAppAsDefault(strNewApp, strExt, AT_FILEEXTENSION); - } - - return SUCCEEDED(hr); -} - -bool CFileAssoc::IsRegistered(CString ext) const -{ - BOOL bIsDefault = FALSE; - CString strProgID = PROGID + ext; - - if (IsWindows8OrGreater()) { - bIsDefault = TRUE; // Check only if MPC-HC is registered as able to handle that format, not if it's the default. - } else if (m_pAAR) { - m_pAAR->QueryAppIsDefault(ext, AT_FILEEXTENSION, AL_EFFECTIVE, m_strRegisteredAppName, &bIsDefault); - } - - // Check if association is for this instance of MPC-HC - if (bIsDefault) { - CRegKey key; - TCHAR buff[MAX_PATH]; - ULONG len = _countof(buff); - - bIsDefault = FALSE; - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open\\command"), KEY_READ)) { - if (ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len)) { - bIsDefault = (m_strOpenCommand.CompareNoCase(CString(buff)) == 0); - } - } - } - - return !!bIsDefault; -} - -bool CFileAssoc::HasEnqueueContextMenuEntry(CString strExt) const -{ - CRegKey key; - CString strProgID = PROGID + strExt; - - return (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue"), KEY_READ)); -} - -bool CFileAssoc::Register(const CMediaFormatCategory& mfc, bool bRegister, bool bAddEnqueueContextMenu, bool bAssociatedWithIcon) -{ - if (!mfc.IsAssociable()) { - ASSERT(FALSE); - return false; - } - - CAtlList exts; - ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); - - CString strLabel = mfc.GetDescription(); - bool res = true; - - POSITION pos = exts.GetHeadPosition(); - while (pos) { - res &= Register(exts.GetNext(pos), strLabel, bRegister, bAddEnqueueContextMenu, bAssociatedWithIcon); - } - - return res; -} - -CFileAssoc::reg_state_t CFileAssoc::IsRegistered(const CMediaFormatCategory& mfc) const -{ - CAtlList exts; - ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); - - size_t cnt = 0; - - POSITION pos = exts.GetHeadPosition(); - while (pos) { - if (CFileAssoc::IsRegistered(exts.GetNext(pos))) { - cnt++; - } - } - - reg_state_t res; - if (cnt == 0) { - res = NOT_REGISTERED; - } else if (cnt == exts.GetCount()) { - res = ALL_REGISTERED; - } else { - res = SOME_REGISTERED; - } - - return res; -} - -CFileAssoc::reg_state_t CFileAssoc::HasAnyEnqueueContextMenuEntries(const CMediaFormatCategory& mfc) const -{ - CAtlList exts; - ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); - - size_t cnt = 0; - - POSITION pos = exts.GetHeadPosition(); - while (pos) { - if (CFileAssoc::HasEnqueueContextMenuEntry(exts.GetNext(pos))) { - cnt++; - } - } - - reg_state_t res; - if (cnt == 0) { - res = NOT_REGISTERED; - } else if (cnt == exts.GetCount()) { - res = ALL_REGISTERED; - } else { - res = SOME_REGISTERED; - } - - return res; -} - -bool CFileAssoc::RegisterFolderContextMenuEntries(bool bRegister) -{ - CRegKey key; - bool success; - - if (bRegister) { - success = false; - - CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); - - if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".enqueue"))) { - key.SetStringValue(nullptr, ResStr(IDS_ADD_TO_PLAYLIST)); - key.SetStringValue(_T("Icon"), appIcon); - - if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".enqueue\\command"))) { - key.SetStringValue(nullptr, m_strEnqueueCommand); - success = true; - } - } - - if (success && ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play"))) { - success = false; - - key.SetStringValue(nullptr, ResStr(IDS_OPEN_WITH_MPC)); - key.SetStringValue(_T("Icon"), appIcon); - - if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play\\command"))) { - key.SetStringValue(nullptr, m_strOpenCommand); - success = true; - } - } - - } else { - key.Attach(HKEY_CLASSES_ROOT); - success = (ERROR_SUCCESS == key.RecurseDeleteKey(_T("Directory\\shell\\") PROGID _T(".enqueue"))); - success &= (ERROR_SUCCESS == key.RecurseDeleteKey(_T("Directory\\shell\\") PROGID _T(".play"))); - } - - return success; -} - -bool CFileAssoc::AreRegisteredFolderContextMenuEntries() const -{ - CRegKey key; - TCHAR buff[MAX_PATH]; - ULONG len = _countof(buff); - bool registered = false; - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play\\command"), KEY_READ)) { - if (ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len)) { - registered = (m_strOpenCommand.CompareNoCase(CString(buff)) == 0); - } - } - - return registered; -} - -bool CFileAssoc::RegisterAutoPlay(autoplay_t ap, bool bRegister) -{ - CString exe = PathUtils::GetProgramPath(true); - - size_t i = (size_t)ap; - if (i >= m_handlers.size()) { - return false; - } - - CRegKey key; - - if (bRegister) { - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, _T("MediaPlayerClassic.Autorun"))) { - return false; - } - key.Close(); - - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, - _T("MediaPlayerClassic.Autorun\\Shell\\Play") + m_handlers[i].verb + _T("\\Command"))) { - return false; - } - key.SetStringValue(nullptr, _T("\"") + exe + _T("\"") + m_handlers[i].cmd); - key.Close(); - - if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\Handlers\\MPCPlay") + m_handlers[i].verb + _T("OnArrival"))) { - return false; - } - key.SetStringValue(_T("Action"), ResStr(m_handlers[i].action)); - key.SetStringValue(_T("Provider"), _T("Media Player Classic")); - key.SetStringValue(_T("InvokeProgID"), _T("MediaPlayerClassic.Autorun")); - key.SetStringValue(_T("InvokeVerb"), _T("Play") + m_handlers[i].verb); - key.SetStringValue(_T("DefaultIcon"), exe + _T(",0")); - key.Close(); - - if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"))) { - return false; - } - key.SetStringValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival"), _T("")); - key.Close(); - } else { - if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"))) { - return false; - } - key.DeleteValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival")); - key.Close(); - } - - return true; -} - -bool CFileAssoc::IsAutoPlayRegistered(autoplay_t ap) const -{ - ULONG len; - TCHAR buff[MAX_PATH]; - CString exe = PathUtils::GetProgramPath(true); - - size_t i = (size_t)ap; - if (i >= m_handlers.size()) { - return false; - } - - CRegKey key; - - if (ERROR_SUCCESS != key.Open(HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"), - KEY_READ)) { - return false; - } - len = _countof(buff); - if (ERROR_SUCCESS != key.QueryStringValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival"), buff, &len)) { - return false; - } - key.Close(); - - if (ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, - _T("MediaPlayerClassic.Autorun\\Shell\\Play") + m_handlers[i].verb + _T("\\Command"), - KEY_READ)) { - return false; - } - len = _countof(buff); - if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len)) { - return false; - } - if (_tcsnicmp(_T("\"") + exe, buff, exe.GetLength() + 1)) { - return false; - } - key.Close(); - - return true; -} - -bool CFileAssoc::GetAssociatedExtensions(const CMediaFormats& mf, CAtlList& exts) const -{ - exts.RemoveAll(); - - CAtlList mfcExts; - for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { - ExplodeMin(mf[i].GetExtsWithPeriod(), mfcExts, _T(' ')); - - POSITION pos = mfcExts.GetHeadPosition(); - while (pos) { - const CString ext = mfcExts.GetNext(pos); - if (IsRegistered(ext)) { - exts.AddTail(ext); - } - } - } - - return !exts.IsEmpty(); -} - -bool CFileAssoc::GetAssociatedExtensionsFromRegistry(CAtlList& exts) const -{ - exts.RemoveAll(); - - CRegKey rkHKCR(HKEY_CLASSES_ROOT); - LONG ret; - DWORD i = 0; - CString keyName, ext; - DWORD len = MAX_PATH; - - while ((ret = rkHKCR.EnumKey(i, keyName.GetBuffer(len), &len)) != ERROR_NO_MORE_ITEMS) { - if (ret == ERROR_SUCCESS) { - keyName.ReleaseBuffer(len); - - if (keyName.Find(PROGID) == 0) { - ext = keyName.Mid(_countof(PROGID) - 1); - - if (IsRegistered(ext)) { - exts.AddTail(ext); - } - } - - i++; - len = MAX_PATH; - } - } - - return !exts.IsEmpty(); -} - -bool CFileAssoc::ReAssocIcons(const CAtlList& exts) -{ - auto iconLib = GetIconLib(); - if (!iconLib) { - return false; - } - iconLib->SaveVersion(); - - const CString progPath = PathUtils::GetProgramPath(true); - - CRegKey key; - - POSITION pos = exts.GetHeadPosition(); - while (pos) { - const CString ext = exts.GetNext(pos); - const CString strProgID = PROGID + ext; - CString appIcon; - - int iconIndex = iconLib->GetIconIndex(ext); - - /* icon_index value -1 means no icon was found in the iconlib for the file extension */ - if (iconIndex >= 0 && ExtractIcon(AfxGetApp()->m_hInstance, m_iconLibPath, iconIndex)) { - appIcon.Format(_T("\"%s\",%d"), m_iconLibPath.GetString(), iconIndex); - } - - /* no icon was found for the file extension, so use MPC-HC's icon */ - if (appIcon.IsEmpty()) { - appIcon = _T("\"") + progPath + _T("\",0"); - } - - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\DefaultIcon")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, appIcon)) { - return false; - } - - key.Close(); - } - - return true; -} - -static HRESULT CALLBACK TaskDialogCallbackProc(HWND hwnd, UINT uNotification, WPARAM wParam, LPARAM lParam, LONG_PTR dwRefData) -{ - if (TDN_CREATED == uNotification) { - SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); - } - - return S_OK; -} - -void CFileAssoc::CheckIconsAssocThread() -{ - UINT nLastVersion = AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ICON_LIB_VERSION, 0); - - if (auto iconLib = GetIconLib()) { - UINT nCurrentVersion = iconLib->GetVersion(); - - CAtlList registeredExts; - - if (nCurrentVersion != nLastVersion && GetAssociatedExtensionsFromRegistry(registeredExts)) { - iconLib->SaveVersion(); - if (!IsUserAnAdmin()) { - TASKDIALOGCONFIG config; - ZeroMemory(&config, sizeof(TASKDIALOGCONFIG)); - config.cbSize = sizeof(config); - config.hInstance = AfxGetInstanceHandle(); - config.hwndParent = AfxGetApp()->GetMainWnd()->GetSafeHwnd(); - config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; - config.pszMainIcon = TD_SHIELD_ICON; - config.pszWindowTitle = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_TITLE); - config.pszMainInstruction = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_INSTR); - config.pszContent = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_CONTENT); - config.pfCallback = TaskDialogCallbackProc; - - typedef HRESULT(_stdcall * pfTaskDialogIndirect)(const TASKDIALOGCONFIG*, int*, int*, BOOL*); - - HMODULE hModule = ::LoadLibrary(_T("comctl32.dll")); - if (hModule) { - pfTaskDialogIndirect TaskDialogIndirect = (pfTaskDialogIndirect)(::GetProcAddress(hModule, "TaskDialogIndirect")); - - if (TaskDialogIndirect) { - int nButtonPressed = 0; - TaskDialogIndirect(&config, &nButtonPressed, nullptr, nullptr); - - if (IDYES == nButtonPressed) { - AfxGetMyApp()->RunAsAdministrator(PathUtils::GetProgramPath(true), _T("/iconsassoc"), true); - } - } - - ::FreeLibrary(hModule); - } - } else { - ReAssocIcons(registeredExts); - - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); - } - } - } - - m_checkIconsAssocInactiveEvent.Set(); -} - -void CFileAssoc::CheckIconsAssoc() -{ - std::lock_guard lock(m_checkIconsAssocMutex); - HANDLE hEvent = m_checkIconsAssocInactiveEvent; - DWORD dwEvent; - VERIFY(CoWaitForMultipleHandles(0, INFINITE, 1, &hEvent, &dwEvent) == S_OK); - m_checkIconsAssocInactiveEvent.Reset(); - try { - std::thread([this] { CheckIconsAssocThread(); }).detach(); - } catch (...) {} -} - -bool CFileAssoc::ShowWindowsAssocDialog() const -{ - IApplicationAssociationRegistrationUI* pAARUI; - HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI, - nullptr, - CLSCTX_INPROC, - IID_PPV_ARGS(&pAARUI)); - - bool success = (SUCCEEDED(hr) && pAARUI != nullptr); - - if (success) { - pAARUI->LaunchAdvancedAssociationUI(m_strRegisteredAppName); - pAARUI->Release(); - } - - return success; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include +#include "mplayerc.h" +#include "FileAssoc.h" +#include "resource.h" +#include "PathUtils.h" + + +// TODO: change this along with the root key for settings and the mutex name to +// avoid possible risks of conflict with the old MPC (non HC version). +#ifdef _WIN64 +#define PROGID _T("mplayerc64") +#else +#define PROGID _T("mplayerc") +#endif // _WIN64 + +CFileAssoc::IconLib::IconLib(GetIconIndexFunc fnGetIconIndex, GetIconLibVersionFunc fnGetIconLibVersion, HMODULE hLib) + : m_fnGetIconIndex(fnGetIconIndex) + , m_fnGetIconLibVersion(fnGetIconLibVersion) + , m_hLib(hLib) +{ + ASSERT(fnGetIconIndex && fnGetIconLibVersion && hLib); +} + +CFileAssoc::IconLib::~IconLib() +{ + VERIFY(FreeLibrary(m_hLib)); +} + +int CFileAssoc::IconLib::GetIconIndex(const CString& str) const +{ + return m_fnGetIconIndex(str); +} + +UINT CFileAssoc::IconLib::GetVersion() const +{ + return m_fnGetIconLibVersion(); +} + +void CFileAssoc::IconLib::SaveVersion() const +{ + AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ICON_LIB_VERSION, m_fnGetIconLibVersion()); +} + +CFileAssoc::CFileAssoc() + : m_iconLibPath(PathUtils::CombinePaths(PathUtils::GetProgramPath(), _T("mpciconlib.dll"))) + , m_strRegisteredAppName(_T("Media Player Classic")) + , m_strOldAssocKey(_T("PreviousRegistration")) + , m_strRegisteredAppKey(_T("Software\\Clients\\Media\\Media Player Classic\\Capabilities")) + , m_strRegAppFileAssocKey(_T("Software\\Clients\\Media\\Media Player Classic\\Capabilities\\FileAssociations")) + , m_strOpenCommand(_T("\"") + PathUtils::GetProgramPath(true) + _T("\" \"%1\"")) + , m_strEnqueueCommand(_T("\"") + PathUtils::GetProgramPath(true) + _T("\" /add \"%1\"")) + , m_bNoRecentDocs(false) + , m_checkIconsAssocInactiveEvent(TRUE, TRUE) // initially set, manual reset +{ + // Default manager (requires at least Vista) + VERIFY(CoCreateInstance(CLSID_ApplicationAssociationRegistration, nullptr, + CLSCTX_INPROC, IID_PPV_ARGS(&m_pAAR)) != CO_E_NOTINITIALIZED); + + m_handlers[0] = { _T("VideoFiles"), _T(" %1"), IDS_AUTOPLAY_PLAYVIDEO }; + m_handlers[1] = { _T("MusicFiles"), _T(" %1"), IDS_AUTOPLAY_PLAYMUSIC }; + m_handlers[2] = { _T("CDAudio"), _T(" %1 /cd"), IDS_AUTOPLAY_PLAYAUDIOCD }; + m_handlers[3] = { _T("DVDMovie"), _T(" %1 /dvd"), IDS_AUTOPLAY_PLAYDVDMOVIE }; +} + +CFileAssoc::~CFileAssoc() +{ + HANDLE hEvent = m_checkIconsAssocInactiveEvent; + DWORD dwEvent; + VERIFY(CoWaitForMultipleHandles(0, INFINITE, 1, &hEvent, &dwEvent) == S_OK); +} + +std::shared_ptr CFileAssoc::GetIconLib() const +{ + std::shared_ptr ret; + if (HMODULE hLib = LoadLibrary(m_iconLibPath)) { + auto fnGetIconIndex = reinterpret_cast(GetProcAddress(hLib, "GetIconIndex")); + auto fnGetIconLibVersion = reinterpret_cast(GetProcAddress(hLib, "GetIconLibVersion")); + if (fnGetIconIndex && fnGetIconLibVersion) { + ret = std::make_shared(fnGetIconIndex, fnGetIconLibVersion, hLib); + } else { + VERIFY(FreeLibrary(hLib)); + } + } + return ret; +} + +void CFileAssoc::SetNoRecentDocs(bool bNoRecentDocs, bool bUpdateAssocs /*= false*/) +{ + if (bNoRecentDocs == m_bNoRecentDocs) { + bUpdateAssocs = false; + } else { + m_bNoRecentDocs = bNoRecentDocs; + } + + CAtlList exts; + if (bUpdateAssocs && GetAssociatedExtensionsFromRegistry(exts)) { + CRegKey key; + POSITION pos = exts.GetHeadPosition(); + while (pos) { + const CString& ext = exts.GetNext(pos); + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, PROGID + ext)) { + if (m_bNoRecentDocs) { + key.SetStringValue(_T("NoRecentDocs"), _T("")); + } else { + key.DeleteValue(_T("NoRecentDocs")); + } + } + } + } +} + +bool CFileAssoc::RegisterApp() +{ + bool success = false; + + if (m_pAAR) { + CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); + + // Register MPC-HC for the windows "Default application" manager + CRegKey key; + + if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\RegisteredApplications"))) { + key.SetStringValue(_T("Media Player Classic"), m_strRegisteredAppKey); + + if (ERROR_SUCCESS == key.Create(HKEY_LOCAL_MACHINE, m_strRegisteredAppKey)) { + // ==>> TODO icon !!! + key.SetStringValue(_T("ApplicationDescription"), ResStr(IDS_APP_DESCRIPTION), REG_EXPAND_SZ); + key.SetStringValue(_T("ApplicationIcon"), appIcon, REG_EXPAND_SZ); + key.SetStringValue(_T("ApplicationName"), ResStr(IDR_MAINFRAME), REG_EXPAND_SZ); + + success = true; + } + } + } + + return success; +} + +bool CFileAssoc::Register(CString ext, CString strLabel, bool bRegister, bool bAddEnqueueContextMenu, bool bAssociatedWithIcon) +{ + CRegKey key; + CString strProgID = PROGID + ext; + + if (!bRegister) { + // On Windows 8, an app can't set itself as the default handler for a format + if (!IsWindows8OrGreater() && bRegister != IsRegistered(ext)) { + SetFileAssociation(ext, strProgID, bRegister); + } + + key.Attach(HKEY_CLASSES_ROOT); + key.RecurseDeleteKey(strProgID); + + if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, m_strRegAppFileAssocKey)) { + key.DeleteValue(ext); + } + + return true; + } else { + // Create ProgID for this file type + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID) + || ERROR_SUCCESS != key.SetStringValue(nullptr, strLabel)) { + return false; + } + + if (m_bNoRecentDocs) { + key.SetStringValue(_T("NoRecentDocs"), _T("")); + } else { + key.DeleteValue(_T("NoRecentDocs")); + } + + CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); + + // Add to playlist option + if (bAddEnqueueContextMenu) { + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, ResStr(IDS_ADD_TO_PLAYLIST)) + || ERROR_SUCCESS != key.SetStringValue(_T("Icon"), appIcon) + || ERROR_SUCCESS != key.SetStringValue(_T("MultiSelectModel"), _T("Player")) + || ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue\\command")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, m_strEnqueueCommand)) { + return false; + } + } else { + key.Close(); + key.Attach(HKEY_CLASSES_ROOT); + key.RecurseDeleteKey(strProgID + _T("\\shell\\enqueue")); + } + + // Play option + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open"))) { + return false; + } + if (ERROR_SUCCESS != key.SetStringValue(nullptr, ResStr(IDS_OPEN_WITH_MPC)) + || ERROR_SUCCESS != key.SetStringValue(_T("MultiSelectModel"), _T("Player")) + || ERROR_SUCCESS != key.SetStringValue(_T("Icon"), appIcon)) { + return false; + } + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open\\command")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, m_strOpenCommand)) { + return false; + } + + if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, m_strRegAppFileAssocKey) + || key.SetStringValue(ext, strProgID)) { + return false; + } + + if (bAssociatedWithIcon) { + if (auto iconLib = GetIconLib()) { + int iconIndex = iconLib->GetIconIndex(ext); + + /* icon_index value -1 means no icon was found in the iconlib for the file extension */ + if (iconIndex >= 0 && ExtractIcon(AfxGetApp()->m_hInstance, m_iconLibPath, iconIndex)) { + appIcon.Format(_T("\"%s\",%d"), m_iconLibPath.GetString(), iconIndex); + } + } + + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\DefaultIcon")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, appIcon)) { + return false; + } + } else { + key.Close(); + key.Attach(HKEY_CLASSES_ROOT); + key.RecurseDeleteKey(strProgID + _T("\\DefaultIcon")); + } + + // On Windows 8, an app can't set itself as the default handler for a format + if (!IsWindows8OrGreater() && bRegister != IsRegistered(ext)) { + SetFileAssociation(ext, strProgID, bRegister); + } + + return true; + } +} + +bool CFileAssoc::SetFileAssociation(CString strExt, CString strProgID, bool bRegister) +{ + CString extOldReg; + CRegKey key; + HRESULT hr = S_OK; + TCHAR buff[MAX_PATH]; + ULONG len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + + if (m_pAAR) { + // The Windows 7 way + CString strNewApp; + if (bRegister) { + // Create non existing file type + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strExt)) { + return false; + } + + CComHeapPtr pszCurrentAssociation; + // Save the application currently associated + if (SUCCEEDED(m_pAAR->QueryCurrentDefault(strExt, AT_FILEEXTENSION, AL_EFFECTIVE, &pszCurrentAssociation))) { + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID)) { + return false; + } + + key.SetStringValue(m_strOldAssocKey, pszCurrentAssociation); + } + strNewApp = m_strRegisteredAppName; + } else { + if (ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, strProgID)) { + return false; + } + + if (ERROR_SUCCESS == key.QueryStringValue(m_strOldAssocKey, buff, &len)) { + strNewApp = buff; + } + } + + hr = m_pAAR->SetAppAsDefault(strNewApp, strExt, AT_FILEEXTENSION); + } + + return SUCCEEDED(hr); +} + +bool CFileAssoc::IsRegistered(CString ext) const +{ + BOOL bIsDefault = FALSE; + CString strProgID = PROGID + ext; + + if (IsWindows8OrGreater()) { + bIsDefault = TRUE; // Check only if MPC-HC is registered as able to handle that format, not if it's the default. + } else if (m_pAAR) { + m_pAAR->QueryAppIsDefault(ext, AT_FILEEXTENSION, AL_EFFECTIVE, m_strRegisteredAppName, &bIsDefault); + } + + // Check if association is for this instance of MPC-HC + if (bIsDefault) { + CRegKey key; + TCHAR buff[MAX_PATH]; + ULONG len = _countof(buff); + + bIsDefault = FALSE; + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open\\command"), KEY_READ)) { + if (ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len)) { + bIsDefault = (m_strOpenCommand.CompareNoCase(CString(buff)) == 0); + } + } + } + + return !!bIsDefault; +} + +bool CFileAssoc::HasEnqueueContextMenuEntry(CString strExt) const +{ + CRegKey key; + CString strProgID = PROGID + strExt; + + return (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue"), KEY_READ)); +} + +bool CFileAssoc::Register(const CMediaFormatCategory& mfc, bool bRegister, bool bAddEnqueueContextMenu, bool bAssociatedWithIcon) +{ + if (!mfc.IsAssociable()) { + ASSERT(FALSE); + return false; + } + + CAtlList exts; + ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); + + CString strLabel = mfc.GetDescription(); + bool res = true; + + POSITION pos = exts.GetHeadPosition(); + while (pos) { + res &= Register(exts.GetNext(pos), strLabel, bRegister, bAddEnqueueContextMenu, bAssociatedWithIcon); + } + + return res; +} + +CFileAssoc::reg_state_t CFileAssoc::IsRegistered(const CMediaFormatCategory& mfc) const +{ + CAtlList exts; + ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); + + size_t cnt = 0; + + POSITION pos = exts.GetHeadPosition(); + while (pos) { + if (CFileAssoc::IsRegistered(exts.GetNext(pos))) { + cnt++; + } + } + + reg_state_t res; + if (cnt == 0) { + res = NOT_REGISTERED; + } else if (cnt == exts.GetCount()) { + res = ALL_REGISTERED; + } else { + res = SOME_REGISTERED; + } + + return res; +} + +CFileAssoc::reg_state_t CFileAssoc::HasAnyEnqueueContextMenuEntries(const CMediaFormatCategory& mfc) const +{ + CAtlList exts; + ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); + + size_t cnt = 0; + + POSITION pos = exts.GetHeadPosition(); + while (pos) { + if (CFileAssoc::HasEnqueueContextMenuEntry(exts.GetNext(pos))) { + cnt++; + } + } + + reg_state_t res; + if (cnt == 0) { + res = NOT_REGISTERED; + } else if (cnt == exts.GetCount()) { + res = ALL_REGISTERED; + } else { + res = SOME_REGISTERED; + } + + return res; +} + +bool CFileAssoc::RegisterFolderContextMenuEntries(bool bRegister) +{ + CRegKey key; + bool success; + + if (bRegister) { + success = false; + + CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); + + if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".enqueue"))) { + key.SetStringValue(nullptr, ResStr(IDS_ADD_TO_PLAYLIST)); + key.SetStringValue(_T("Icon"), appIcon); + + if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".enqueue\\command"))) { + key.SetStringValue(nullptr, m_strEnqueueCommand); + success = true; + } + } + + if (success && ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play"))) { + success = false; + + key.SetStringValue(nullptr, ResStr(IDS_OPEN_WITH_MPC)); + key.SetStringValue(_T("Icon"), appIcon); + + if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play\\command"))) { + key.SetStringValue(nullptr, m_strOpenCommand); + success = true; + } + } + + } else { + key.Attach(HKEY_CLASSES_ROOT); + success = (ERROR_SUCCESS == key.RecurseDeleteKey(_T("Directory\\shell\\") PROGID _T(".enqueue"))); + success &= (ERROR_SUCCESS == key.RecurseDeleteKey(_T("Directory\\shell\\") PROGID _T(".play"))); + } + + return success; +} + +bool CFileAssoc::AreRegisteredFolderContextMenuEntries() const +{ + CRegKey key; + TCHAR buff[MAX_PATH]; + ULONG len = _countof(buff); + bool registered = false; + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play\\command"), KEY_READ)) { + if (ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len)) { + registered = (m_strOpenCommand.CompareNoCase(CString(buff)) == 0); + } + } + + return registered; +} + +bool CFileAssoc::RegisterAutoPlay(autoplay_t ap, bool bRegister) +{ + CString exe = PathUtils::GetProgramPath(true); + + size_t i = (size_t)ap; + if (i >= m_handlers.size()) { + return false; + } + + CRegKey key; + + if (bRegister) { + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, _T("MediaPlayerClassic.Autorun"))) { + return false; + } + key.Close(); + + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, + _T("MediaPlayerClassic.Autorun\\Shell\\Play") + m_handlers[i].verb + _T("\\Command"))) { + return false; + } + key.SetStringValue(nullptr, _T("\"") + exe + _T("\"") + m_handlers[i].cmd); + key.Close(); + + if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\Handlers\\MPCPlay") + m_handlers[i].verb + _T("OnArrival"))) { + return false; + } + key.SetStringValue(_T("Action"), ResStr(m_handlers[i].action)); + key.SetStringValue(_T("Provider"), _T("Media Player Classic")); + key.SetStringValue(_T("InvokeProgID"), _T("MediaPlayerClassic.Autorun")); + key.SetStringValue(_T("InvokeVerb"), _T("Play") + m_handlers[i].verb); + key.SetStringValue(_T("DefaultIcon"), exe + _T(",0")); + key.Close(); + + if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"))) { + return false; + } + key.SetStringValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival"), _T("")); + key.Close(); + } else { + if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"))) { + return false; + } + key.DeleteValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival")); + key.Close(); + } + + return true; +} + +bool CFileAssoc::IsAutoPlayRegistered(autoplay_t ap) const +{ + ULONG len; + TCHAR buff[MAX_PATH]; + CString exe = PathUtils::GetProgramPath(true); + + size_t i = (size_t)ap; + if (i >= m_handlers.size()) { + return false; + } + + CRegKey key; + + if (ERROR_SUCCESS != key.Open(HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"), + KEY_READ)) { + return false; + } + len = _countof(buff); + if (ERROR_SUCCESS != key.QueryStringValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival"), buff, &len)) { + return false; + } + key.Close(); + + if (ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, + _T("MediaPlayerClassic.Autorun\\Shell\\Play") + m_handlers[i].verb + _T("\\Command"), + KEY_READ)) { + return false; + } + len = _countof(buff); + if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len)) { + return false; + } + if (_tcsnicmp(_T("\"") + exe, buff, exe.GetLength() + 1)) { + return false; + } + key.Close(); + + return true; +} + +bool CFileAssoc::GetAssociatedExtensions(const CMediaFormats& mf, CAtlList& exts) const +{ + exts.RemoveAll(); + + CAtlList mfcExts; + for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { + ExplodeMin(mf[i].GetExtsWithPeriod(), mfcExts, _T(' ')); + + POSITION pos = mfcExts.GetHeadPosition(); + while (pos) { + const CString ext = mfcExts.GetNext(pos); + if (IsRegistered(ext)) { + exts.AddTail(ext); + } + } + } + + return !exts.IsEmpty(); +} + +bool CFileAssoc::GetAssociatedExtensionsFromRegistry(CAtlList& exts) const +{ + exts.RemoveAll(); + + CRegKey rkHKCR(HKEY_CLASSES_ROOT); + LONG ret; + DWORD i = 0; + CString keyName, ext; + DWORD len = MAX_PATH; + + while ((ret = rkHKCR.EnumKey(i, keyName.GetBuffer(len), &len)) != ERROR_NO_MORE_ITEMS) { + if (ret == ERROR_SUCCESS) { + keyName.ReleaseBuffer(len); + + if (keyName.Find(PROGID) == 0) { + ext = keyName.Mid(_countof(PROGID) - 1); + + if (IsRegistered(ext)) { + exts.AddTail(ext); + } + } + + i++; + len = MAX_PATH; + } + } + + return !exts.IsEmpty(); +} + +bool CFileAssoc::ReAssocIcons(const CAtlList& exts) +{ + auto iconLib = GetIconLib(); + if (!iconLib) { + return false; + } + iconLib->SaveVersion(); + + const CString progPath = PathUtils::GetProgramPath(true); + + CRegKey key; + + POSITION pos = exts.GetHeadPosition(); + while (pos) { + const CString ext = exts.GetNext(pos); + const CString strProgID = PROGID + ext; + CString appIcon; + + int iconIndex = iconLib->GetIconIndex(ext); + + /* icon_index value -1 means no icon was found in the iconlib for the file extension */ + if (iconIndex >= 0 && ExtractIcon(AfxGetApp()->m_hInstance, m_iconLibPath, iconIndex)) { + appIcon.Format(_T("\"%s\",%d"), m_iconLibPath.GetString(), iconIndex); + } + + /* no icon was found for the file extension, so use MPC-HC's icon */ + if (appIcon.IsEmpty()) { + appIcon = _T("\"") + progPath + _T("\",0"); + } + + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\DefaultIcon")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, appIcon)) { + return false; + } + + key.Close(); + } + + return true; +} + +static HRESULT CALLBACK TaskDialogCallbackProc(HWND hwnd, UINT uNotification, WPARAM wParam, LPARAM lParam, LONG_PTR dwRefData) +{ + if (TDN_CREATED == uNotification) { + SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); + } + + return S_OK; +} + +void CFileAssoc::CheckIconsAssocThread() +{ + UINT nLastVersion = AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ICON_LIB_VERSION, 0); + + if (auto iconLib = GetIconLib()) { + UINT nCurrentVersion = iconLib->GetVersion(); + + CAtlList registeredExts; + + if (nCurrentVersion != nLastVersion && GetAssociatedExtensionsFromRegistry(registeredExts)) { + iconLib->SaveVersion(); + if (!IsUserAnAdmin()) { + TASKDIALOGCONFIG config; + ZeroMemory(&config, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(config); + config.hInstance = AfxGetInstanceHandle(); + config.hwndParent = AfxGetApp()->GetMainWnd()->GetSafeHwnd(); + config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; + config.pszMainIcon = TD_SHIELD_ICON; + config.pszWindowTitle = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_TITLE); + config.pszMainInstruction = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_INSTR); + config.pszContent = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_CONTENT); + config.pfCallback = TaskDialogCallbackProc; + + typedef HRESULT(_stdcall * pfTaskDialogIndirect)(const TASKDIALOGCONFIG*, int*, int*, BOOL*); + + HMODULE hModule = ::LoadLibrary(_T("comctl32.dll")); + if (hModule) { + pfTaskDialogIndirect TaskDialogIndirect = (pfTaskDialogIndirect)(::GetProcAddress(hModule, "TaskDialogIndirect")); + + if (TaskDialogIndirect) { + int nButtonPressed = 0; + TaskDialogIndirect(&config, &nButtonPressed, nullptr, nullptr); + + if (IDYES == nButtonPressed) { + AfxGetMyApp()->RunAsAdministrator(PathUtils::GetProgramPath(true), _T("/iconsassoc"), true); + } + } + + ::FreeLibrary(hModule); + } + } else { + ReAssocIcons(registeredExts); + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + } + } + } + + m_checkIconsAssocInactiveEvent.Set(); +} + +void CFileAssoc::CheckIconsAssoc() +{ + std::lock_guard lock(m_checkIconsAssocMutex); + HANDLE hEvent = m_checkIconsAssocInactiveEvent; + DWORD dwEvent; + VERIFY(CoWaitForMultipleHandles(0, INFINITE, 1, &hEvent, &dwEvent) == S_OK); + m_checkIconsAssocInactiveEvent.Reset(); + try { + std::thread([this] { CheckIconsAssocThread(); }).detach(); + } catch (...) {} +} + +bool CFileAssoc::ShowWindowsAssocDialog() const +{ + IApplicationAssociationRegistrationUI* pAARUI; + HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI, + nullptr, + CLSCTX_INPROC, + IID_PPV_ARGS(&pAARUI)); + + bool success = (SUCCEEDED(hr) && pAARUI != nullptr); + + if (success) { + pAARUI->LaunchAdvancedAssociationUI(m_strRegisteredAppName); + pAARUI->Release(); + } + + return success; +} diff --git a/src/mpc-hc/FileAssoc.h b/src/mpc-hc/FileAssoc.h index 3657bb724b0..0e6038ae2ef 100644 --- a/src/mpc-hc/FileAssoc.h +++ b/src/mpc-hc/FileAssoc.h @@ -1,136 +1,136 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#pragma once - -#include "MediaFormats.h" -#include - -#include -#include -#include -#include - -class CFileAssoc -{ -public: - enum reg_state_t { - NOT_REGISTERED, - SOME_REGISTERED, - ALL_REGISTERED - }; - enum autoplay_t { - AP_VIDEO, - AP_MUSIC, - AP_AUDIOCD, - AP_DVDMOVIE - }; - - class IconLib - { - public: - typedef int(*GetIconIndexFunc)(LPCTSTR); - typedef UINT(*GetIconLibVersionFunc)(); - - IconLib() = delete; - IconLib(const IconLib&) = delete; - IconLib& operator=(const IconLib&) = delete; - IconLib(GetIconIndexFunc fnGetIconIndex, GetIconLibVersionFunc fnGetIconLibVersion, HMODULE hLib); - ~IconLib(); - - int GetIconIndex(const CString& str) const; - UINT GetVersion() const; - void SaveVersion() const; - - protected: - const GetIconIndexFunc m_fnGetIconIndex; - const GetIconLibVersionFunc m_fnGetIconLibVersion; - const HMODULE m_hLib; - }; - - CFileAssoc(); - CFileAssoc(const CFileAssoc&) = delete; - CFileAssoc& operator=(const CFileAssoc&) = delete; - ~CFileAssoc(); - - std::shared_ptr GetIconLib() const; - - void SetNoRecentDocs(bool bNoRecentDocs, bool bUpdateAssocs = false); - - bool RegisterApp(); - - bool Register(CString ext, CString strLabel, bool bRegister, bool bRegisterContextMenuEntries, bool bAssociatedWithIcon); - bool IsRegistered(CString ext) const; - bool HasEnqueueContextMenuEntry(CString strExt) const; - - bool Register(const CMediaFormatCategory& mfc, bool bRegister, bool bRegisterContextMenuEntries, bool bAssociatedWithIcon); - reg_state_t IsRegistered(const CMediaFormatCategory& mfc) const; - reg_state_t HasAnyEnqueueContextMenuEntries(const CMediaFormatCategory& mfc) const; - - bool RegisterFolderContextMenuEntries(bool bRegister); - bool AreRegisteredFolderContextMenuEntries() const; - - bool RegisterAutoPlay(autoplay_t ap, bool bRegister); - bool IsAutoPlayRegistered(autoplay_t ap) const; - - bool GetAssociatedExtensions(const CMediaFormats& mf, CAtlList& exts) const; - bool GetAssociatedExtensionsFromRegistry(CAtlList& exts) const; - - bool ReAssocIcons(const CAtlList& exts); - - void CheckIconsAssoc(); - - bool ShowWindowsAssocDialog() const; - -protected: - struct Handler { - CString verb; - CString cmd; - UINT action; - - Handler() - : action(0) {} - Handler(const CString& verb, const CString& cmd, UINT action) - : verb(verb), cmd(cmd), action(action) {} - }; - - bool SetFileAssociation(CString strExt, CString strProgID, bool bRegister); - - void CheckIconsAssocThread(); - - const CString m_iconLibPath; - const CString m_strRegisteredAppName; - const CString m_strOldAssocKey; - const CString m_strRegisteredAppKey; - const CString m_strRegAppFileAssocKey; - - const CString m_strOpenCommand; - const CString m_strEnqueueCommand; - - bool m_bNoRecentDocs; - - CComPtr m_pAAR; - - std::mutex m_checkIconsAssocMutex; - ATL::CEvent m_checkIconsAssocInactiveEvent; - - std::array m_handlers; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#pragma once + +#include "MediaFormats.h" +#include + +#include +#include +#include +#include + +class CFileAssoc +{ +public: + enum reg_state_t { + NOT_REGISTERED, + SOME_REGISTERED, + ALL_REGISTERED + }; + enum autoplay_t { + AP_VIDEO, + AP_MUSIC, + AP_AUDIOCD, + AP_DVDMOVIE + }; + + class IconLib + { + public: + typedef int(*GetIconIndexFunc)(LPCTSTR); + typedef UINT(*GetIconLibVersionFunc)(); + + IconLib() = delete; + IconLib(const IconLib&) = delete; + IconLib& operator=(const IconLib&) = delete; + IconLib(GetIconIndexFunc fnGetIconIndex, GetIconLibVersionFunc fnGetIconLibVersion, HMODULE hLib); + ~IconLib(); + + int GetIconIndex(const CString& str) const; + UINT GetVersion() const; + void SaveVersion() const; + + protected: + const GetIconIndexFunc m_fnGetIconIndex; + const GetIconLibVersionFunc m_fnGetIconLibVersion; + const HMODULE m_hLib; + }; + + CFileAssoc(); + CFileAssoc(const CFileAssoc&) = delete; + CFileAssoc& operator=(const CFileAssoc&) = delete; + ~CFileAssoc(); + + std::shared_ptr GetIconLib() const; + + void SetNoRecentDocs(bool bNoRecentDocs, bool bUpdateAssocs = false); + + bool RegisterApp(); + + bool Register(CString ext, CString strLabel, bool bRegister, bool bRegisterContextMenuEntries, bool bAssociatedWithIcon); + bool IsRegistered(CString ext) const; + bool HasEnqueueContextMenuEntry(CString strExt) const; + + bool Register(const CMediaFormatCategory& mfc, bool bRegister, bool bRegisterContextMenuEntries, bool bAssociatedWithIcon); + reg_state_t IsRegistered(const CMediaFormatCategory& mfc) const; + reg_state_t HasAnyEnqueueContextMenuEntries(const CMediaFormatCategory& mfc) const; + + bool RegisterFolderContextMenuEntries(bool bRegister); + bool AreRegisteredFolderContextMenuEntries() const; + + bool RegisterAutoPlay(autoplay_t ap, bool bRegister); + bool IsAutoPlayRegistered(autoplay_t ap) const; + + bool GetAssociatedExtensions(const CMediaFormats& mf, CAtlList& exts) const; + bool GetAssociatedExtensionsFromRegistry(CAtlList& exts) const; + + bool ReAssocIcons(const CAtlList& exts); + + void CheckIconsAssoc(); + + bool ShowWindowsAssocDialog() const; + +protected: + struct Handler { + CString verb; + CString cmd; + UINT action; + + Handler() + : action(0) {} + Handler(const CString& verb, const CString& cmd, UINT action) + : verb(verb), cmd(cmd), action(action) {} + }; + + bool SetFileAssociation(CString strExt, CString strProgID, bool bRegister); + + void CheckIconsAssocThread(); + + const CString m_iconLibPath; + const CString m_strRegisteredAppName; + const CString m_strOldAssocKey; + const CString m_strRegisteredAppKey; + const CString m_strRegAppFileAssocKey; + + const CString m_strOpenCommand; + const CString m_strEnqueueCommand; + + bool m_bNoRecentDocs; + + CComPtr m_pAAR; + + std::mutex m_checkIconsAssocMutex; + ATL::CEvent m_checkIconsAssocInactiveEvent; + + std::array m_handlers; +}; diff --git a/src/mpc-hc/FilterEnum.h b/src/mpc-hc/FilterEnum.h index 5aedddc7250..081fb1d1940 100644 --- a/src/mpc-hc/FilterEnum.h +++ b/src/mpc-hc/FilterEnum.h @@ -1,274 +1,274 @@ -/* - * (C) 2010-2015, 2017 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 . - * - */ - -#pragma once - -#include "InternalFiltersConfig.h" - - -enum { - SOURCE_FILTER, - AUDIO_DECODER, - VIDEO_DECODER, - FILTER_TYPE_NB -}; - -enum SOURCE_FILTER { -#if INTERNAL_SOURCEFILTER_AC3 - SRC_AC3, -#endif -#if INTERNAL_SOURCEFILTER_ASF - SRC_ASF, -#endif -#if INTERNAL_SOURCEFILTER_AVI - SRC_AVI, -#endif -#if INTERNAL_SOURCEFILTER_AVS - SRC_AVS, -#endif -#if INTERNAL_SOURCEFILTER_DTS - SRC_DTS, -#endif -#if INTERNAL_SOURCEFILTER_FLAC - SRC_FLAC, -#endif -#if INTERNAL_SOURCEFILTER_FLIC - SRC_FLIC, -#endif -#if INTERNAL_SOURCEFILTER_FLV - SRC_FLV, -#endif -#if INTERNAL_SOURCEFILTER_GIF - SRC_GIF, -#endif -#if INTERNAL_SOURCEFILTER_HTTP - SRC_HTTP, -#endif -#if INTERNAL_SOURCEFILTER_MATROSKA - SRC_MATROSKA, -#endif -#if INTERNAL_SOURCEFILTER_MISC - SRC_MISC, -#endif -#if INTERNAL_SOURCEFILTER_MMS - SRC_MMS, -#endif -#if INTERNAL_SOURCEFILTER_MP4 - SRC_MP4, -#endif -#if INTERNAL_SOURCEFILTER_MPEGAUDIO - SRC_MPA, -#endif -#if INTERNAL_SOURCEFILTER_MPEG - SRC_MPEG, - SRC_MPEGTS, -#endif -#if INTERNAL_SOURCEFILTER_OGG - SRC_OGG, -#endif -#if INTERNAL_SOURCEFILTER_REALMEDIA - SRC_REALMEDIA, -#endif -#if INTERNAL_SOURCEFILTER_RTMP - SRC_RTMP, -#endif -#if INTERNAL_SOURCEFILTER_RTP - SRC_RTP, -#endif -#if INTERNAL_SOURCEFILTER_RTSP - SRC_RTSP, -#endif -#if INTERNAL_SOURCEFILTER_UDP - SRC_UDP, -#endif -#if INTERNAL_SOURCEFILTER_WTV - SRC_WTV, -#endif -#if INTERNAL_SOURCEFILTER_CDDA - SRC_CDDA, -#endif -#if INTERNAL_SOURCEFILTER_CDXA - SRC_CDXA, -#endif -#if INTERNAL_SOURCEFILTER_DSM - SRC_DSM, -#endif -#if INTERNAL_SOURCEFILTER_RFS - SRC_RFS, -#endif -#if INTERNAL_SOURCEFILTER_VTS - SRC_VTS, -#endif - SRC_LAST -}; - -enum DECODER { -#if INTERNAL_DECODER_MPEG1 - TRA_MPEG1, -#endif -#if INTERNAL_DECODER_MPEG2 - TRA_MPEG2, -#endif -#if INTERNAL_DECODER_REALVIDEO - TRA_RV, -#endif -#if INTERNAL_DECODER_REALAUDIO - TRA_RA, -#endif -#if INTERNAL_DECODER_MPEGAUDIO - TRA_MPA, -#endif -#if INTERNAL_DECODER_DTS - TRA_DTS, -#endif -#if INTERNAL_DECODER_LPCM - TRA_LPCM, -#endif -#if INTERNAL_DECODER_AC3 - TRA_AC3, -#endif -#if INTERNAL_DECODER_AAC - TRA_AAC, -#endif -#if INTERNAL_DECODER_ALAC - TRA_ALAC, -#endif -#if INTERNAL_DECODER_ALS - TRA_ALS, -#endif -#if INTERNAL_DECODER_PS2AUDIO - TRA_PS2AUD, -#endif -#if INTERNAL_DECODER_VORBIS - TRA_VORBIS, -#endif -#if INTERNAL_DECODER_FLAC - TRA_FLAC, -#endif -#if INTERNAL_DECODER_NELLYMOSER - TRA_NELLY, -#endif -#if INTERNAL_DECODER_AMR - TRA_AMR, -#endif -#if INTERNAL_DECODER_OPUS - TRA_OPUS, -#endif -#if INTERNAL_DECODER_WMA - TRA_WMA, -#endif -#if INTERNAL_DECODER_WMAPRO - TRA_WMAPRO, -#endif -#if INTERNAL_DECODER_WMALL - TRA_WMALL, -#endif -#if INTERNAL_DECODER_G726 - TRA_G726, -#endif -#if INTERNAL_DECODER_G729 - TRA_G729, -#endif -#if INTERNAL_DECODER_OTHERAUDIO - TRA_OTHERAUDIO, -#endif -#if INTERNAL_DECODER_PCM - TRA_PCM, -#endif -#if INTERNAL_DECODER_H264 - TRA_H264, -#endif -#if INTERNAL_DECODER_HEVC - TRA_HEVC, -#endif -#if INTERNAL_DECODER_VVC - TRA_VVC, -#endif -#if INTERNAL_DECODER_AV1 - TRA_AV1, -#endif -#if INTERNAL_DECODER_VC1 - TRA_VC1, -#endif -#if INTERNAL_DECODER_FLV - TRA_FLV4, -#endif -#if INTERNAL_DECODER_VP356 - TRA_VP356, -#endif -#if INTERNAL_DECODER_VP8 - TRA_VP8, -#endif -#if INTERNAL_DECODER_VP9 - TRA_VP9, -#endif -#if INTERNAL_DECODER_XVID - TRA_XVID, -#endif -#if INTERNAL_DECODER_DIVX - TRA_DIVX, -#endif -#if INTERNAL_DECODER_MSMPEG4 - TRA_MSMPEG4, -#endif -#if INTERNAL_DECODER_WMV - TRA_WMV, -#endif -#if INTERNAL_DECODER_SVQ - TRA_SVQ3, -#endif -#if INTERNAL_DECODER_H263 - TRA_H263, -#endif -#if INTERNAL_DECODER_THEORA - TRA_THEORA, -#endif -#if INTERNAL_DECODER_AMVV - TRA_AMVV, -#endif -#if INTERNAL_DECODER_MJPEG - TRA_MJPEG, -#endif -#if INTERNAL_DECODER_INDEO - TRA_INDEO, -#endif -#if INTERNAL_DECODER_SCREEN - TRA_SCREEN, -#endif -#if INTERNAL_DECODER_FLIC - TRA_FLIC, -#endif -#if INTERNAL_DECODER_MSVIDEO - TRA_MSVIDEO, -#endif -#if INTERNAL_DECODER_V210_V410 - TRA_V210_V410, -#endif -#if INTERNAL_DECODER_PRORES - TRA_PRORES, -#endif -#if INTERNAL_DECODER_DNXHD - TRA_DNXHD, -#endif -#if INTERNAL_DECODER_OTHERVIDEO - TRA_OTHERVIDEO, -#endif - TRA_LAST -}; +/* + * (C) 2010-2015, 2017 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 . + * + */ + +#pragma once + +#include "InternalFiltersConfig.h" + + +enum { + SOURCE_FILTER, + AUDIO_DECODER, + VIDEO_DECODER, + FILTER_TYPE_NB +}; + +enum SOURCE_FILTER { +#if INTERNAL_SOURCEFILTER_AC3 + SRC_AC3, +#endif +#if INTERNAL_SOURCEFILTER_ASF + SRC_ASF, +#endif +#if INTERNAL_SOURCEFILTER_AVI + SRC_AVI, +#endif +#if INTERNAL_SOURCEFILTER_AVS + SRC_AVS, +#endif +#if INTERNAL_SOURCEFILTER_DTS + SRC_DTS, +#endif +#if INTERNAL_SOURCEFILTER_FLAC + SRC_FLAC, +#endif +#if INTERNAL_SOURCEFILTER_FLIC + SRC_FLIC, +#endif +#if INTERNAL_SOURCEFILTER_FLV + SRC_FLV, +#endif +#if INTERNAL_SOURCEFILTER_GIF + SRC_GIF, +#endif +#if INTERNAL_SOURCEFILTER_HTTP + SRC_HTTP, +#endif +#if INTERNAL_SOURCEFILTER_MATROSKA + SRC_MATROSKA, +#endif +#if INTERNAL_SOURCEFILTER_MISC + SRC_MISC, +#endif +#if INTERNAL_SOURCEFILTER_MMS + SRC_MMS, +#endif +#if INTERNAL_SOURCEFILTER_MP4 + SRC_MP4, +#endif +#if INTERNAL_SOURCEFILTER_MPEGAUDIO + SRC_MPA, +#endif +#if INTERNAL_SOURCEFILTER_MPEG + SRC_MPEG, + SRC_MPEGTS, +#endif +#if INTERNAL_SOURCEFILTER_OGG + SRC_OGG, +#endif +#if INTERNAL_SOURCEFILTER_REALMEDIA + SRC_REALMEDIA, +#endif +#if INTERNAL_SOURCEFILTER_RTMP + SRC_RTMP, +#endif +#if INTERNAL_SOURCEFILTER_RTP + SRC_RTP, +#endif +#if INTERNAL_SOURCEFILTER_RTSP + SRC_RTSP, +#endif +#if INTERNAL_SOURCEFILTER_UDP + SRC_UDP, +#endif +#if INTERNAL_SOURCEFILTER_WTV + SRC_WTV, +#endif +#if INTERNAL_SOURCEFILTER_CDDA + SRC_CDDA, +#endif +#if INTERNAL_SOURCEFILTER_CDXA + SRC_CDXA, +#endif +#if INTERNAL_SOURCEFILTER_DSM + SRC_DSM, +#endif +#if INTERNAL_SOURCEFILTER_RFS + SRC_RFS, +#endif +#if INTERNAL_SOURCEFILTER_VTS + SRC_VTS, +#endif + SRC_LAST +}; + +enum DECODER { +#if INTERNAL_DECODER_MPEG1 + TRA_MPEG1, +#endif +#if INTERNAL_DECODER_MPEG2 + TRA_MPEG2, +#endif +#if INTERNAL_DECODER_REALVIDEO + TRA_RV, +#endif +#if INTERNAL_DECODER_REALAUDIO + TRA_RA, +#endif +#if INTERNAL_DECODER_MPEGAUDIO + TRA_MPA, +#endif +#if INTERNAL_DECODER_DTS + TRA_DTS, +#endif +#if INTERNAL_DECODER_LPCM + TRA_LPCM, +#endif +#if INTERNAL_DECODER_AC3 + TRA_AC3, +#endif +#if INTERNAL_DECODER_AAC + TRA_AAC, +#endif +#if INTERNAL_DECODER_ALAC + TRA_ALAC, +#endif +#if INTERNAL_DECODER_ALS + TRA_ALS, +#endif +#if INTERNAL_DECODER_PS2AUDIO + TRA_PS2AUD, +#endif +#if INTERNAL_DECODER_VORBIS + TRA_VORBIS, +#endif +#if INTERNAL_DECODER_FLAC + TRA_FLAC, +#endif +#if INTERNAL_DECODER_NELLYMOSER + TRA_NELLY, +#endif +#if INTERNAL_DECODER_AMR + TRA_AMR, +#endif +#if INTERNAL_DECODER_OPUS + TRA_OPUS, +#endif +#if INTERNAL_DECODER_WMA + TRA_WMA, +#endif +#if INTERNAL_DECODER_WMAPRO + TRA_WMAPRO, +#endif +#if INTERNAL_DECODER_WMALL + TRA_WMALL, +#endif +#if INTERNAL_DECODER_G726 + TRA_G726, +#endif +#if INTERNAL_DECODER_G729 + TRA_G729, +#endif +#if INTERNAL_DECODER_OTHERAUDIO + TRA_OTHERAUDIO, +#endif +#if INTERNAL_DECODER_PCM + TRA_PCM, +#endif +#if INTERNAL_DECODER_H264 + TRA_H264, +#endif +#if INTERNAL_DECODER_HEVC + TRA_HEVC, +#endif +#if INTERNAL_DECODER_VVC + TRA_VVC, +#endif +#if INTERNAL_DECODER_AV1 + TRA_AV1, +#endif +#if INTERNAL_DECODER_VC1 + TRA_VC1, +#endif +#if INTERNAL_DECODER_FLV + TRA_FLV4, +#endif +#if INTERNAL_DECODER_VP356 + TRA_VP356, +#endif +#if INTERNAL_DECODER_VP8 + TRA_VP8, +#endif +#if INTERNAL_DECODER_VP9 + TRA_VP9, +#endif +#if INTERNAL_DECODER_XVID + TRA_XVID, +#endif +#if INTERNAL_DECODER_DIVX + TRA_DIVX, +#endif +#if INTERNAL_DECODER_MSMPEG4 + TRA_MSMPEG4, +#endif +#if INTERNAL_DECODER_WMV + TRA_WMV, +#endif +#if INTERNAL_DECODER_SVQ + TRA_SVQ3, +#endif +#if INTERNAL_DECODER_H263 + TRA_H263, +#endif +#if INTERNAL_DECODER_THEORA + TRA_THEORA, +#endif +#if INTERNAL_DECODER_AMVV + TRA_AMVV, +#endif +#if INTERNAL_DECODER_MJPEG + TRA_MJPEG, +#endif +#if INTERNAL_DECODER_INDEO + TRA_INDEO, +#endif +#if INTERNAL_DECODER_SCREEN + TRA_SCREEN, +#endif +#if INTERNAL_DECODER_FLIC + TRA_FLIC, +#endif +#if INTERNAL_DECODER_MSVIDEO + TRA_MSVIDEO, +#endif +#if INTERNAL_DECODER_V210_V410 + TRA_V210_V410, +#endif +#if INTERNAL_DECODER_PRORES + TRA_PRORES, +#endif +#if INTERNAL_DECODER_DNXHD + TRA_DNXHD, +#endif +#if INTERNAL_DECODER_OTHERVIDEO + TRA_OTHERVIDEO, +#endif + TRA_LAST +}; diff --git a/src/mpc-hc/FloatEdit.cpp b/src/mpc-hc/FloatEdit.cpp index af98e790891..b94e2bd4331 100644 --- a/src/mpc-hc/FloatEdit.cpp +++ b/src/mpc-hc/FloatEdit.cpp @@ -1,181 +1,181 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015 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 . - * - */ - -#include "stdafx.h" -#include "FloatEdit.h" - - -// CFloatEdit - -IMPLEMENT_DYNAMIC(CMPCThemeFloatEdit, CMPCThemeEdit) - -bool CMPCThemeFloatEdit::GetFloat(float& f) -{ - CString s; - GetWindowText(s); - return (_stscanf_s(s, _T("%f"), &f) == 1); -} - -double CMPCThemeFloatEdit::operator = (double d) -{ - CString s; - s.Format(_T("%.4f"), d); - SetWindowText(s); - return d; -} - -CMPCThemeFloatEdit::operator double() -{ - CString s; - GetWindowText(s); - float flt; - if (swscanf_s(s, L"%f", &flt) != 1) { - flt = 0.0f; - } - flt = std::clamp(flt, m_lower, m_upper); - - return flt; -} - -void CMPCThemeFloatEdit::SetRange(float fLower, float fUpper) -{ - ASSERT(fLower < fUpper); - m_lower = fLower; - m_upper = fUpper; -} - -BEGIN_MESSAGE_MAP(CMPCThemeFloatEdit, CMPCThemeEdit) - ON_WM_CHAR() -END_MESSAGE_MAP() - -void CMPCThemeFloatEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - if (!(nChar >= '0' && nChar <= '9' || nChar == '.' || nChar == '\b' || nChar == '-')) { - return; - } - - if (nChar == '-' && m_lower >= 0) { - return; - } - - CString str; - GetWindowText(str); - - if (nChar == '.' && (str.Find('.') >= 0 || str.IsEmpty())) { - return; - } - - int nStartChar, nEndChar; - GetSel(nStartChar, nEndChar); - - if (nChar == '\b' && nStartChar <= 0) { - return; - } - - CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); -} - -// CIntEdit - -IMPLEMENT_DYNAMIC(CMPCThemeIntEdit, CMPCThemeEdit) - -BEGIN_MESSAGE_MAP(CMPCThemeIntEdit, CMPCThemeEdit) - ON_WM_CHAR() -END_MESSAGE_MAP() - -void CMPCThemeIntEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - if (!(nChar >= '0' && nChar <= '9' || nChar == '-' || nChar == '\b')) { - return; - } - - int nStartChar, nEndChar; - GetSel(nStartChar, nEndChar); - - if (nChar == '-' && nEndChar == 0) { - CString str; - GetWindowText(str); - if (!str.IsEmpty() && str[0] == '-') { - return; - } - } - - if (nChar == '-' && nStartChar != 0) { - return; - } - - CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); -} - -// CHexEdit - -IMPLEMENT_DYNAMIC(CMPCThemeHexEdit, CMPCThemeEdit) - -bool CMPCThemeHexEdit::GetDWORD(DWORD& dw) -{ - CString s; - GetWindowText(s); - return (_stscanf_s(s, _T("%lx"), &dw) == 1); -} - -DWORD CMPCThemeHexEdit::operator = (DWORD dw) -{ - CString s; - s.Format(_T("%08lx"), dw); - SetWindowText(s); - return dw; -} - -CMPCThemeHexEdit::operator DWORD() -{ - CString s; - GetWindowText(s); - DWORD dw; - return (_stscanf_s(s, _T("%lx"), &dw) == 1 ? dw : 0); -} - -BEGIN_MESSAGE_MAP(CMPCThemeHexEdit, CMPCThemeEdit) - ON_WM_CHAR() -END_MESSAGE_MAP() - -void CMPCThemeHexEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - if (!(nChar >= 'A' && nChar <= 'F' || nChar >= 'a' && nChar <= 'f' - || nChar >= '0' && nChar <= '9' || nChar == '\b')) { - return; - } - - CString str; - GetWindowText(str); - - int nStartChar, nEndChar; - GetSel(nStartChar, nEndChar); - - if (nChar == '\b' && nStartChar <= 0) { - return; - } - - if (nChar != '\b' && nEndChar - nStartChar == 0 && str.GetLength() >= 8) { - return; - } - - CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015 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 . + * + */ + +#include "stdafx.h" +#include "FloatEdit.h" + + +// CFloatEdit + +IMPLEMENT_DYNAMIC(CMPCThemeFloatEdit, CMPCThemeEdit) + +bool CMPCThemeFloatEdit::GetFloat(float& f) +{ + CString s; + GetWindowText(s); + return (_stscanf_s(s, _T("%f"), &f) == 1); +} + +double CMPCThemeFloatEdit::operator = (double d) +{ + CString s; + s.Format(_T("%.4f"), d); + SetWindowText(s); + return d; +} + +CMPCThemeFloatEdit::operator double() +{ + CString s; + GetWindowText(s); + float flt; + if (swscanf_s(s, L"%f", &flt) != 1) { + flt = 0.0f; + } + flt = std::clamp(flt, m_lower, m_upper); + + return flt; +} + +void CMPCThemeFloatEdit::SetRange(float fLower, float fUpper) +{ + ASSERT(fLower < fUpper); + m_lower = fLower; + m_upper = fUpper; +} + +BEGIN_MESSAGE_MAP(CMPCThemeFloatEdit, CMPCThemeEdit) + ON_WM_CHAR() +END_MESSAGE_MAP() + +void CMPCThemeFloatEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (!(nChar >= '0' && nChar <= '9' || nChar == '.' || nChar == '\b' || nChar == '-')) { + return; + } + + if (nChar == '-' && m_lower >= 0) { + return; + } + + CString str; + GetWindowText(str); + + if (nChar == '.' && (str.Find('.') >= 0 || str.IsEmpty())) { + return; + } + + int nStartChar, nEndChar; + GetSel(nStartChar, nEndChar); + + if (nChar == '\b' && nStartChar <= 0) { + return; + } + + CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); +} + +// CIntEdit + +IMPLEMENT_DYNAMIC(CMPCThemeIntEdit, CMPCThemeEdit) + +BEGIN_MESSAGE_MAP(CMPCThemeIntEdit, CMPCThemeEdit) + ON_WM_CHAR() +END_MESSAGE_MAP() + +void CMPCThemeIntEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (!(nChar >= '0' && nChar <= '9' || nChar == '-' || nChar == '\b')) { + return; + } + + int nStartChar, nEndChar; + GetSel(nStartChar, nEndChar); + + if (nChar == '-' && nEndChar == 0) { + CString str; + GetWindowText(str); + if (!str.IsEmpty() && str[0] == '-') { + return; + } + } + + if (nChar == '-' && nStartChar != 0) { + return; + } + + CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); +} + +// CHexEdit + +IMPLEMENT_DYNAMIC(CMPCThemeHexEdit, CMPCThemeEdit) + +bool CMPCThemeHexEdit::GetDWORD(DWORD& dw) +{ + CString s; + GetWindowText(s); + return (_stscanf_s(s, _T("%lx"), &dw) == 1); +} + +DWORD CMPCThemeHexEdit::operator = (DWORD dw) +{ + CString s; + s.Format(_T("%08lx"), dw); + SetWindowText(s); + return dw; +} + +CMPCThemeHexEdit::operator DWORD() +{ + CString s; + GetWindowText(s); + DWORD dw; + return (_stscanf_s(s, _T("%lx"), &dw) == 1 ? dw : 0); +} + +BEGIN_MESSAGE_MAP(CMPCThemeHexEdit, CMPCThemeEdit) + ON_WM_CHAR() +END_MESSAGE_MAP() + +void CMPCThemeHexEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (!(nChar >= 'A' && nChar <= 'F' || nChar >= 'a' && nChar <= 'f' + || nChar >= '0' && nChar <= '9' || nChar == '\b')) { + return; + } + + CString str; + GetWindowText(str); + + int nStartChar, nEndChar; + GetSel(nStartChar, nEndChar); + + if (nChar == '\b' && nStartChar <= 0) { + return; + } + + if (nChar != '\b' && nEndChar - nStartChar == 0 && str.GetLength() >= 8) { + return; + } + + CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); +} diff --git a/src/mpc-hc/FloatEdit.h b/src/mpc-hc/FloatEdit.h index 6c41f4adaf7..706fc66893a 100644 --- a/src/mpc-hc/FloatEdit.h +++ b/src/mpc-hc/FloatEdit.h @@ -1,70 +1,70 @@ -/* - * (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 . - * - */ - -#pragma once -#include "CMPCThemeEdit.h" -// CFloatEdit - -class CMPCThemeFloatEdit : public CMPCThemeEdit -{ - float m_lower = -1000000000.0f; - float m_upper = 1000000000.0f; - -public: - bool GetFloat(float& f); - double operator = (double d); - operator double(); - void SetRange(float fLower, float fUpper); - - DECLARE_DYNAMIC(CMPCThemeFloatEdit) - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); -}; - -// CIntEdit - -class CMPCThemeIntEdit : public CMPCThemeEdit -{ -public: - DECLARE_DYNAMIC(CMPCThemeIntEdit) - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); -}; - -// CHexEdit - -class CMPCThemeHexEdit : public CMPCThemeEdit -{ -public: - bool GetDWORD(DWORD& dw); - DWORD operator = (DWORD dw); - operator DWORD(); - - DECLARE_DYNAMIC(CMPCThemeHexEdit) - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); -}; +/* + * (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 . + * + */ + +#pragma once +#include "CMPCThemeEdit.h" +// CFloatEdit + +class CMPCThemeFloatEdit : public CMPCThemeEdit +{ + float m_lower = -1000000000.0f; + float m_upper = 1000000000.0f; + +public: + bool GetFloat(float& f); + double operator = (double d); + operator double(); + void SetRange(float fLower, float fUpper); + + DECLARE_DYNAMIC(CMPCThemeFloatEdit) + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); +}; + +// CIntEdit + +class CMPCThemeIntEdit : public CMPCThemeEdit +{ +public: + DECLARE_DYNAMIC(CMPCThemeIntEdit) + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); +}; + +// CHexEdit + +class CMPCThemeHexEdit : public CMPCThemeEdit +{ +public: + bool GetDWORD(DWORD& dw); + DWORD operator = (DWORD dw); + operator DWORD(); + + DECLARE_DYNAMIC(CMPCThemeHexEdit) + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); +}; diff --git a/src/mpc-hc/FullscreenWnd.cpp b/src/mpc-hc/FullscreenWnd.cpp index c1942088c9d..d5f6b02ddf5 100644 --- a/src/mpc-hc/FullscreenWnd.cpp +++ b/src/mpc-hc/FullscreenWnd.cpp @@ -1,103 +1,103 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "FullscreenWnd.h" -#include "MainFrm.h" - -IMPLEMENT_DYNAMIC(CFullscreenWnd, CMouseWndWithArtView) -CFullscreenWnd::CFullscreenWnd(CMainFrame* pMainFrame) - : CMouseWndWithArtView(pMainFrame, true) - , m_pMainFrame(pMainFrame) -{ -} - -bool CFullscreenWnd::IsWindow() const -{ - return !!m_hWnd; -} - -BOOL CFullscreenWnd::PreTranslateMessage(MSG* pMsg) -{ - switch (pMsg->message) { - case WM_KEYDOWN: - case WM_KEYUP: - m_pMainFrame->PostMessage(pMsg->message, pMsg->wParam, pMsg->lParam); - return TRUE; - } - - return __super::PreTranslateMessage(pMsg); -} - -BOOL CFullscreenWnd::PreCreateWindow(CREATESTRUCT& cs) -{ - cs.style &= ~WS_BORDER; - cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_NOCLOSE, - ::LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), nullptr); - - return __super::PreCreateWindow(cs); -} - -LRESULT CFullscreenWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ -#if 0 - if (message == WM_NCACTIVATE && LOWORD(wParam) == WA_INACTIVE && m_pMainFrame->IsD3DFullScreenMode()) { - return m_pMainFrame->m_pFullscreenWnd == this; - } -#endif - - return __super::WindowProc(message, wParam, lParam); -} - -BEGIN_MESSAGE_MAP(CFullscreenWnd, CMouseWnd) - ON_WM_ERASEBKGND() - ON_WM_DESTROY() -END_MESSAGE_MAP() - -BOOL CFullscreenWnd::OnEraseBkgnd(CDC* pDC) -{ - if (m_pMainFrame->m_fAudioOnly) { - return __super::OnEraseBkgnd(pDC); - } - else { - CRect r; - GetClientRect(r); - pDC->FillSolidRect(r, 0); - return FALSE; - } -} - -void CFullscreenWnd::OnDestroy() -{ - __super::OnDestroy(); - - CWnd* pMainWnd = AfxGetApp()->GetMainWnd(); - if (pMainWnd) { - pMainWnd->SetActiveWindow(); - } -} - -void CFullscreenWnd::SetCursor(LPCWSTR lpCursorName) { - m_hCursor = ::LoadCursorW(nullptr, lpCursorName); - m_bCursorVisible = true; - PostMessageW(WM_SETCURSOR, 0, 0); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "FullscreenWnd.h" +#include "MainFrm.h" + +IMPLEMENT_DYNAMIC(CFullscreenWnd, CMouseWndWithArtView) +CFullscreenWnd::CFullscreenWnd(CMainFrame* pMainFrame) + : CMouseWndWithArtView(pMainFrame, true) + , m_pMainFrame(pMainFrame) +{ +} + +bool CFullscreenWnd::IsWindow() const +{ + return !!m_hWnd; +} + +BOOL CFullscreenWnd::PreTranslateMessage(MSG* pMsg) +{ + switch (pMsg->message) { + case WM_KEYDOWN: + case WM_KEYUP: + m_pMainFrame->PostMessage(pMsg->message, pMsg->wParam, pMsg->lParam); + return TRUE; + } + + return __super::PreTranslateMessage(pMsg); +} + +BOOL CFullscreenWnd::PreCreateWindow(CREATESTRUCT& cs) +{ + cs.style &= ~WS_BORDER; + cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_NOCLOSE, + ::LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), nullptr); + + return __super::PreCreateWindow(cs); +} + +LRESULT CFullscreenWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ +#if 0 + if (message == WM_NCACTIVATE && LOWORD(wParam) == WA_INACTIVE && m_pMainFrame->IsD3DFullScreenMode()) { + return m_pMainFrame->m_pFullscreenWnd == this; + } +#endif + + return __super::WindowProc(message, wParam, lParam); +} + +BEGIN_MESSAGE_MAP(CFullscreenWnd, CMouseWnd) + ON_WM_ERASEBKGND() + ON_WM_DESTROY() +END_MESSAGE_MAP() + +BOOL CFullscreenWnd::OnEraseBkgnd(CDC* pDC) +{ + if (m_pMainFrame->m_fAudioOnly) { + return __super::OnEraseBkgnd(pDC); + } + else { + CRect r; + GetClientRect(r); + pDC->FillSolidRect(r, 0); + return FALSE; + } +} + +void CFullscreenWnd::OnDestroy() +{ + __super::OnDestroy(); + + CWnd* pMainWnd = AfxGetApp()->GetMainWnd(); + if (pMainWnd) { + pMainWnd->SetActiveWindow(); + } +} + +void CFullscreenWnd::SetCursor(LPCWSTR lpCursorName) { + m_hCursor = ::LoadCursorW(nullptr, lpCursorName); + m_bCursorVisible = true; + PostMessageW(WM_SETCURSOR, 0, 0); +} diff --git a/src/mpc-hc/FullscreenWnd.h b/src/mpc-hc/FullscreenWnd.h index 36a57f67813..0e13a9a2c0f 100644 --- a/src/mpc-hc/FullscreenWnd.h +++ b/src/mpc-hc/FullscreenWnd.h @@ -1,51 +1,51 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015 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 . - * - */ - -#pragma once - -#include "MouseWndWithArtView.h" - -class CMainFrame; - -class CFullscreenWnd final : public CMouseWndWithArtView -{ - DECLARE_DYNAMIC(CFullscreenWnd) - - explicit CFullscreenWnd(CMainFrame* pMainFrame); - bool IsWindow() const; - void SetCursor(LPCWSTR lpCursorName); - -private: - CMainFrame* m_pMainFrame; - HCURSOR m_hCursor; - bool m_bCursorVisible = false; - bool m_bTrackingMouseLeave = false; - -protected: - BOOL PreCreateWindow(CREATESTRUCT& cs) override; - BOOL PreTranslateMessage(MSG* pMsg) override; - LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam) override; - - DECLARE_MESSAGE_MAP() - - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnDestroy(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015 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 . + * + */ + +#pragma once + +#include "MouseWndWithArtView.h" + +class CMainFrame; + +class CFullscreenWnd final : public CMouseWndWithArtView +{ + DECLARE_DYNAMIC(CFullscreenWnd) + + explicit CFullscreenWnd(CMainFrame* pMainFrame); + bool IsWindow() const; + void SetCursor(LPCWSTR lpCursorName); + +private: + CMainFrame* m_pMainFrame; + HCURSOR m_hCursor; + bool m_bCursorVisible = false; + bool m_bTrackingMouseLeave = false; + +protected: + BOOL PreCreateWindow(CREATESTRUCT& cs) override; + BOOL PreTranslateMessage(MSG* pMsg) override; + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam) override; + + DECLARE_MESSAGE_MAP() + + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnDestroy(); +}; diff --git a/src/mpc-hc/GoToDlg.cpp b/src/mpc-hc/GoToDlg.cpp index 65cf1027aa3..506d175bca3 100644 --- a/src/mpc-hc/GoToDlg.cpp +++ b/src/mpc-hc/GoToDlg.cpp @@ -1,195 +1,195 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "GoToDlg.h" -#include "SettingsDefines.h" -#include - -// CGoToDlg dialog - -IMPLEMENT_DYNAMIC(CGoToDlg, CMPCThemeDialog) -CGoToDlg::CGoToDlg(REFERENCE_TIME time, REFERENCE_TIME maxTime, double fps, CWnd* pParent /*=nullptr*/) - : CMPCThemeDialog(CGoToDlg::IDD, pParent) - , m_time(time) - , m_maxTime(maxTime) - , m_fps(fps) -{ - if (m_fps == 0) { - CString str = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_GOTO_FPS, _T("0")); - float fps2; - if (_stscanf_s(str, _T("%f"), &fps2) == 1) { - m_fps = fps2; - } - } -} - -CGoToDlg::~CGoToDlg() -{ -} - -void CGoToDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - DDX_Text(pDX, IDC_EDIT1, m_timestr); - DDX_Text(pDX, IDC_EDIT2, m_framestr); - DDX_Control(pDX, IDC_EDIT1, m_timeedit); - DDX_Control(pDX, IDC_EDIT2, m_frameedit); - fulfillThemeReqs(); -} - -BOOL CGoToDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - bool showHours = (m_maxTime >= 3600 * 1000 * 10000i64); - - if (showHours) { - m_timeedit.EnableMask(_T("DD DD DD DDD"), _T("__:__:__.___"), L'0', _T("0123456789")); - } else { - m_timeedit.EnableMask(_T("DD DD DDD"), _T("__:__.___"), L'0', _T("0123456789")); - } - m_timeedit.EnableGetMaskedCharsOnly(false); - m_timeedit.EnableSelectByGroup(false); - - int time = (int)(m_time / 10000); - if (time >= 0) { - if (showHours) { - m_timestr.Format(_T("%02d:%02d:%02d.%03d"), - (time / (1000 * 60 * 60)) % 60, - (time / (1000 * 60)) % 60, - (time / 1000) % 60, time % 1000); - } else { - m_timestr.Format(_T("%02d:%02d.%03d"), - (time / (1000 * 60)) % 60, - (time / 1000) % 60, - time % 1000); - } - - if (m_fps > 0) { - m_framestr.Format(_T("%d, %.3f"), (int)(m_fps * m_time / 10000000 + 1.5), m_fps); - } - - UpdateData(FALSE); - - switch (AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_TIME)) { - default: - case TYPE_TIME: - m_timeedit.SetFocus(); - m_timeedit.SetSel(0, 0); - break; - case TYPE_FRAME: - m_frameedit.SetFocus(); - m_frameedit.SetSel(0, m_framestr.Find(',')); - break; - } - - } - - return FALSE; - - // return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - - -BEGIN_MESSAGE_MAP(CGoToDlg, CMPCThemeDialog) - ON_BN_CLICKED(IDC_OK1, OnParseTimeCode) - ON_BN_CLICKED(IDC_OK2, OnParseFrameCode) -END_MESSAGE_MAP() - - -// CGoToDlg message handlers - -void CGoToDlg::OnParseTimeCode() -{ - UpdateData(); - - AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_TIME); - - unsigned int hh = 0; - unsigned int mm = 0; - float ss = 0.0f; - WCHAR c; // extra character to ensure the end of string was reached - - if (((swscanf_s(m_timestr, L"%f%c", &ss, &c, 1) == 1) // ss[.ms] - || (swscanf_s(m_timestr, L"%u:%f%c", &mm, &ss, &c, 1) == 2 && ss < 60.0f) // mm:ss[.ms] - || (swscanf_s(m_timestr, L"%u:%u:%f%c", &hh, &mm, &ss, &c, 1) == 3 && mm < 60 && ss < 60.0f)) // hh:mm:ss[.ms] - && ss >= 0.0f) { - - int time = (int)(1000.0f * ((hh * 60 + mm) * 60 + ss) + 0.5f); - m_time = time * 10000i64; - - OnOK(); - } else { - AfxMessageBox(IDS_GOTO_ERROR_PARSING_TIME, MB_ICONEXCLAMATION | MB_OK, 0); - } -} - -void CGoToDlg::OnParseFrameCode() -{ - UpdateData(); - - AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_FRAME); - - int frame; - float fps; - WCHAR c1; // delimiter character - WCHAR c2; // extra character to ensure the end of string was reached - - int result = swscanf_s(m_framestr, L"%d%c%f%c", &frame, &c1, 1, &fps, &c2, 1); - if (result == 1) { - m_time = frame < 2 ? 0LL : (REFERENCE_TIME)ceil(10000000.0 * (frame - 1) / m_fps); - OnOK(); - } else if (result == 3 && c1 == L',') { - m_time = frame < 2 ? 0LL : (REFERENCE_TIME)ceil(10000000.0 * (frame - 1) / fps); - OnOK(); - } else if (result == 0 || c1 != L',') { - AfxMessageBox(IDS_GOTO_ERROR_PARSING_TEXT, MB_ICONEXCLAMATION | MB_OK, 0); - } else { - AfxMessageBox(IDS_GOTO_ERROR_PARSING_FPS, MB_ICONEXCLAMATION | MB_OK, 0); - } -} - -void CGoToDlg::OnOK() -{ - if (m_time > m_maxTime) { - AfxMessageBox(IDS_GOTO_ERROR_INVALID_TIME, MB_ICONEXCLAMATION | MB_OK, 0); - } else { - __super::OnOK(); - } -} - -BOOL CGoToDlg::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { - if (*GetFocus() == m_timeedit) { - OnParseTimeCode(); - } else if (*GetFocus() == m_frameedit) { - OnParseFrameCode(); - } - - return TRUE; - } - - return __super::PreTranslateMessage(pMsg); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "GoToDlg.h" +#include "SettingsDefines.h" +#include + +// CGoToDlg dialog + +IMPLEMENT_DYNAMIC(CGoToDlg, CMPCThemeDialog) +CGoToDlg::CGoToDlg(REFERENCE_TIME time, REFERENCE_TIME maxTime, double fps, CWnd* pParent /*=nullptr*/) + : CMPCThemeDialog(CGoToDlg::IDD, pParent) + , m_time(time) + , m_maxTime(maxTime) + , m_fps(fps) +{ + if (m_fps == 0) { + CString str = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_GOTO_FPS, _T("0")); + float fps2; + if (_stscanf_s(str, _T("%f"), &fps2) == 1) { + m_fps = fps2; + } + } +} + +CGoToDlg::~CGoToDlg() +{ +} + +void CGoToDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_EDIT1, m_timestr); + DDX_Text(pDX, IDC_EDIT2, m_framestr); + DDX_Control(pDX, IDC_EDIT1, m_timeedit); + DDX_Control(pDX, IDC_EDIT2, m_frameedit); + fulfillThemeReqs(); +} + +BOOL CGoToDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + bool showHours = (m_maxTime >= 3600 * 1000 * 10000i64); + + if (showHours) { + m_timeedit.EnableMask(_T("DD DD DD DDD"), _T("__:__:__.___"), L'0', _T("0123456789")); + } else { + m_timeedit.EnableMask(_T("DD DD DDD"), _T("__:__.___"), L'0', _T("0123456789")); + } + m_timeedit.EnableGetMaskedCharsOnly(false); + m_timeedit.EnableSelectByGroup(false); + + int time = (int)(m_time / 10000); + if (time >= 0) { + if (showHours) { + m_timestr.Format(_T("%02d:%02d:%02d.%03d"), + (time / (1000 * 60 * 60)) % 60, + (time / (1000 * 60)) % 60, + (time / 1000) % 60, time % 1000); + } else { + m_timestr.Format(_T("%02d:%02d.%03d"), + (time / (1000 * 60)) % 60, + (time / 1000) % 60, + time % 1000); + } + + if (m_fps > 0) { + m_framestr.Format(_T("%d, %.3f"), (int)(m_fps * m_time / 10000000 + 1.5), m_fps); + } + + UpdateData(FALSE); + + switch (AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_TIME)) { + default: + case TYPE_TIME: + m_timeedit.SetFocus(); + m_timeedit.SetSel(0, 0); + break; + case TYPE_FRAME: + m_frameedit.SetFocus(); + m_frameedit.SetSel(0, m_framestr.Find(',')); + break; + } + + } + + return FALSE; + + // return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + + +BEGIN_MESSAGE_MAP(CGoToDlg, CMPCThemeDialog) + ON_BN_CLICKED(IDC_OK1, OnParseTimeCode) + ON_BN_CLICKED(IDC_OK2, OnParseFrameCode) +END_MESSAGE_MAP() + + +// CGoToDlg message handlers + +void CGoToDlg::OnParseTimeCode() +{ + UpdateData(); + + AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_TIME); + + unsigned int hh = 0; + unsigned int mm = 0; + float ss = 0.0f; + WCHAR c; // extra character to ensure the end of string was reached + + if (((swscanf_s(m_timestr, L"%f%c", &ss, &c, 1) == 1) // ss[.ms] + || (swscanf_s(m_timestr, L"%u:%f%c", &mm, &ss, &c, 1) == 2 && ss < 60.0f) // mm:ss[.ms] + || (swscanf_s(m_timestr, L"%u:%u:%f%c", &hh, &mm, &ss, &c, 1) == 3 && mm < 60 && ss < 60.0f)) // hh:mm:ss[.ms] + && ss >= 0.0f) { + + int time = (int)(1000.0f * ((hh * 60 + mm) * 60 + ss) + 0.5f); + m_time = time * 10000i64; + + OnOK(); + } else { + AfxMessageBox(IDS_GOTO_ERROR_PARSING_TIME, MB_ICONEXCLAMATION | MB_OK, 0); + } +} + +void CGoToDlg::OnParseFrameCode() +{ + UpdateData(); + + AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_FRAME); + + int frame; + float fps; + WCHAR c1; // delimiter character + WCHAR c2; // extra character to ensure the end of string was reached + + int result = swscanf_s(m_framestr, L"%d%c%f%c", &frame, &c1, 1, &fps, &c2, 1); + if (result == 1) { + m_time = frame < 2 ? 0LL : (REFERENCE_TIME)ceil(10000000.0 * (frame - 1) / m_fps); + OnOK(); + } else if (result == 3 && c1 == L',') { + m_time = frame < 2 ? 0LL : (REFERENCE_TIME)ceil(10000000.0 * (frame - 1) / fps); + OnOK(); + } else if (result == 0 || c1 != L',') { + AfxMessageBox(IDS_GOTO_ERROR_PARSING_TEXT, MB_ICONEXCLAMATION | MB_OK, 0); + } else { + AfxMessageBox(IDS_GOTO_ERROR_PARSING_FPS, MB_ICONEXCLAMATION | MB_OK, 0); + } +} + +void CGoToDlg::OnOK() +{ + if (m_time > m_maxTime) { + AfxMessageBox(IDS_GOTO_ERROR_INVALID_TIME, MB_ICONEXCLAMATION | MB_OK, 0); + } else { + __super::OnOK(); + } +} + +BOOL CGoToDlg::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { + if (*GetFocus() == m_timeedit) { + OnParseTimeCode(); + } else if (*GetFocus() == m_frameedit) { + OnParseFrameCode(); + } + + return TRUE; + } + + return __super::PreTranslateMessage(pMsg); +} diff --git a/src/mpc-hc/GoToDlg.h b/src/mpc-hc/GoToDlg.h index e1d482e59bb..bd66aaa638c 100644 --- a/src/mpc-hc/GoToDlg.h +++ b/src/mpc-hc/GoToDlg.h @@ -1,67 +1,67 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include -#include "resource.h" -#include "CMPCThemeDialog.h" -#include "CMPCThemeEdit.h" -#include "CMPCThemeMaskedEdit.h" - - -// CGoToDlg dialog - -class CGoToDlg : public CMPCThemeDialog -{ - DECLARE_DYNAMIC(CGoToDlg) - - enum { TYPE_TIME, TYPE_FRAME }; - -public: - CGoToDlg(REFERENCE_TIME time = -1, REFERENCE_TIME maxTime = -1, double fps = 0, CWnd* pParent = nullptr); // standard constructor - virtual ~CGoToDlg(); - - CString m_timestr; - CString m_framestr; - CMPCThemeMaskedEdit m_timeedit; - CMPCThemeEdit m_frameedit; - - REFERENCE_TIME m_time; - REFERENCE_TIME m_maxTime; - double m_fps; - - // Dialog Data - enum { IDD = IDD_GOTO_DLG }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual BOOL PreTranslateMessage(MSG* pMsg); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnParseTimeCode(); - afx_msg void OnParseFrameCode(); - virtual void OnOK(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include +#include "resource.h" +#include "CMPCThemeDialog.h" +#include "CMPCThemeEdit.h" +#include "CMPCThemeMaskedEdit.h" + + +// CGoToDlg dialog + +class CGoToDlg : public CMPCThemeDialog +{ + DECLARE_DYNAMIC(CGoToDlg) + + enum { TYPE_TIME, TYPE_FRAME }; + +public: + CGoToDlg(REFERENCE_TIME time = -1, REFERENCE_TIME maxTime = -1, double fps = 0, CWnd* pParent = nullptr); // standard constructor + virtual ~CGoToDlg(); + + CString m_timestr; + CString m_framestr; + CMPCThemeMaskedEdit m_timeedit; + CMPCThemeEdit m_frameedit; + + REFERENCE_TIME m_time; + REFERENCE_TIME m_maxTime; + double m_fps; + + // Dialog Data + enum { IDD = IDD_GOTO_DLG }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnParseTimeCode(); + afx_msg void OnParseFrameCode(); + virtual void OnOK(); +}; diff --git a/src/mpc-hc/GraphThread.cpp b/src/mpc-hc/GraphThread.cpp index 97a8110bb94..3933001e422 100644 --- a/src/mpc-hc/GraphThread.cpp +++ b/src/mpc-hc/GraphThread.cpp @@ -1,107 +1,107 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "MainFrm.h" -#include "GraphThread.h" -#include - -IMPLEMENT_DYNCREATE(CGraphThread, CWinThread) - -BOOL CGraphThread::InitInstance() -{ - SetThreadName(DWORD(-1), "GraphThread"); - AfxSocketInit(); - return SUCCEEDED(CoInitialize(nullptr)) ? TRUE : FALSE; -} - -int CGraphThread::ExitInstance() -{ - CoUninitialize(); - return __super::ExitInstance(); -} - -BEGIN_MESSAGE_MAP(CGraphThread, CWinThread) - ON_THREAD_MESSAGE(TM_CLOSE, OnClose) - ON_THREAD_MESSAGE(TM_DISPLAY_CHANGE, OnDisplayChange) - ON_THREAD_MESSAGE(TM_EXIT, OnExit) - ON_THREAD_MESSAGE(TM_OPEN, OnOpen) - ON_THREAD_MESSAGE(TM_RESET, OnReset) - ON_THREAD_MESSAGE(TM_TUNER_SCAN, OnTunerScan) -END_MESSAGE_MAP() - -void CGraphThread::OnClose(WPARAM wParam, LPARAM lParam) -{ - ASSERT(m_pMainFrame); - ASSERT(WaitForSingleObject(m_pMainFrame->m_evClosePrivateFinished, 0) == WAIT_TIMEOUT); - if (m_pMainFrame->GetLoadState() == MLS::CLOSING) { - m_pMainFrame->CloseMediaPrivate(); - } - VERIFY(m_pMainFrame->m_evClosePrivateFinished.Set()); -} - -void CGraphThread::OnDisplayChange(WPARAM wParam, LPARAM lParam) -{ - if (m_pMainFrame) { - m_pMainFrame->DisplayChange(); - } - if (CAMEvent* e = (CAMEvent*)lParam) { - e->Set(); - } -} - -void CGraphThread::OnExit(WPARAM wParam, LPARAM lParam) -{ - PostQuitMessage(0); - if (CAMEvent* e = (CAMEvent*)lParam) { - e->Set(); - } -} - -void CGraphThread::OnOpen(WPARAM wParam, LPARAM lParam) -{ - TRACE(_T("--> CGraphThread::OnOpen on thread: %lu\n"), GetCurrentThreadId()); - ASSERT(m_pMainFrame); - ASSERT(WaitForSingleObject(m_pMainFrame->m_evOpenPrivateFinished, 0) == WAIT_TIMEOUT); - if (m_pMainFrame->GetLoadState() == MLS::LOADING) { - CAutoPtr pOMD((OpenMediaData*)lParam); - m_pMainFrame->OpenMediaPrivate(pOMD); - } - VERIFY(m_pMainFrame->m_evOpenPrivateFinished.Set()); -} - -void CGraphThread::OnReset(WPARAM wParam, LPARAM lParam) -{ - if (m_pMainFrame) { - m_pMainFrame->ResetDevice(); - } - if (CAMEvent* e = (CAMEvent*)lParam) { - e->Set(); - } -} - -void CGraphThread::OnTunerScan(WPARAM wParam, LPARAM lParam) -{ - if (m_pMainFrame) { - CAutoPtr pTSD((TunerScanData*)lParam); - m_pMainFrame->DoTunerScan(pTSD); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "MainFrm.h" +#include "GraphThread.h" +#include + +IMPLEMENT_DYNCREATE(CGraphThread, CWinThread) + +BOOL CGraphThread::InitInstance() +{ + SetThreadName(DWORD(-1), "GraphThread"); + AfxSocketInit(); + return SUCCEEDED(CoInitialize(nullptr)) ? TRUE : FALSE; +} + +int CGraphThread::ExitInstance() +{ + CoUninitialize(); + return __super::ExitInstance(); +} + +BEGIN_MESSAGE_MAP(CGraphThread, CWinThread) + ON_THREAD_MESSAGE(TM_CLOSE, OnClose) + ON_THREAD_MESSAGE(TM_DISPLAY_CHANGE, OnDisplayChange) + ON_THREAD_MESSAGE(TM_EXIT, OnExit) + ON_THREAD_MESSAGE(TM_OPEN, OnOpen) + ON_THREAD_MESSAGE(TM_RESET, OnReset) + ON_THREAD_MESSAGE(TM_TUNER_SCAN, OnTunerScan) +END_MESSAGE_MAP() + +void CGraphThread::OnClose(WPARAM wParam, LPARAM lParam) +{ + ASSERT(m_pMainFrame); + ASSERT(WaitForSingleObject(m_pMainFrame->m_evClosePrivateFinished, 0) == WAIT_TIMEOUT); + if (m_pMainFrame->GetLoadState() == MLS::CLOSING) { + m_pMainFrame->CloseMediaPrivate(); + } + VERIFY(m_pMainFrame->m_evClosePrivateFinished.Set()); +} + +void CGraphThread::OnDisplayChange(WPARAM wParam, LPARAM lParam) +{ + if (m_pMainFrame) { + m_pMainFrame->DisplayChange(); + } + if (CAMEvent* e = (CAMEvent*)lParam) { + e->Set(); + } +} + +void CGraphThread::OnExit(WPARAM wParam, LPARAM lParam) +{ + PostQuitMessage(0); + if (CAMEvent* e = (CAMEvent*)lParam) { + e->Set(); + } +} + +void CGraphThread::OnOpen(WPARAM wParam, LPARAM lParam) +{ + TRACE(_T("--> CGraphThread::OnOpen on thread: %lu\n"), GetCurrentThreadId()); + ASSERT(m_pMainFrame); + ASSERT(WaitForSingleObject(m_pMainFrame->m_evOpenPrivateFinished, 0) == WAIT_TIMEOUT); + if (m_pMainFrame->GetLoadState() == MLS::LOADING) { + CAutoPtr pOMD((OpenMediaData*)lParam); + m_pMainFrame->OpenMediaPrivate(pOMD); + } + VERIFY(m_pMainFrame->m_evOpenPrivateFinished.Set()); +} + +void CGraphThread::OnReset(WPARAM wParam, LPARAM lParam) +{ + if (m_pMainFrame) { + m_pMainFrame->ResetDevice(); + } + if (CAMEvent* e = (CAMEvent*)lParam) { + e->Set(); + } +} + +void CGraphThread::OnTunerScan(WPARAM wParam, LPARAM lParam) +{ + if (m_pMainFrame) { + CAutoPtr pTSD((TunerScanData*)lParam); + m_pMainFrame->DoTunerScan(pTSD); + } +} diff --git a/src/mpc-hc/GraphThread.h b/src/mpc-hc/GraphThread.h index 4c87e3dcb1e..e8a2e49656a 100644 --- a/src/mpc-hc/GraphThread.h +++ b/src/mpc-hc/GraphThread.h @@ -1,56 +1,56 @@ -/* - * (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 . - * - */ - -#pragma once - -class CMainFrame; - -class CGraphThread : public CWinThread -{ - DECLARE_DYNCREATE(CGraphThread); -public: - CGraphThread() : m_pMainFrame(nullptr) {} - - BOOL InitInstance(); - int ExitInstance(); - void SetMainFrame(CMainFrame* pMainFrame) { m_pMainFrame = pMainFrame; } - - enum { - TM_EXIT = WM_APP, - TM_OPEN, - TM_CLOSE, - TM_RESET, - TM_TUNER_SCAN, - TM_DISPLAY_CHANGE - }; - -protected: - DECLARE_MESSAGE_MAP() - afx_msg void OnClose(WPARAM wParam, LPARAM lParam); - afx_msg void OnDisplayChange(WPARAM wParam, LPARAM lParam); - afx_msg void OnExit(WPARAM wParam, LPARAM lParam); - afx_msg void OnOpen(WPARAM wParam, LPARAM lParam); - afx_msg void OnReset(WPARAM wParam, LPARAM lParam); - afx_msg void OnTunerScan(WPARAM wParam, LPARAM lParam); - -private: - CMainFrame* m_pMainFrame; -}; +/* + * (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 . + * + */ + +#pragma once + +class CMainFrame; + +class CGraphThread : public CWinThread +{ + DECLARE_DYNCREATE(CGraphThread); +public: + CGraphThread() : m_pMainFrame(nullptr) {} + + BOOL InitInstance(); + int ExitInstance(); + void SetMainFrame(CMainFrame* pMainFrame) { m_pMainFrame = pMainFrame; } + + enum { + TM_EXIT = WM_APP, + TM_OPEN, + TM_CLOSE, + TM_RESET, + TM_TUNER_SCAN, + TM_DISPLAY_CHANGE + }; + +protected: + DECLARE_MESSAGE_MAP() + afx_msg void OnClose(WPARAM wParam, LPARAM lParam); + afx_msg void OnDisplayChange(WPARAM wParam, LPARAM lParam); + afx_msg void OnExit(WPARAM wParam, LPARAM lParam); + afx_msg void OnOpen(WPARAM wParam, LPARAM lParam); + afx_msg void OnReset(WPARAM wParam, LPARAM lParam); + afx_msg void OnTunerScan(WPARAM wParam, LPARAM lParam); + +private: + CMainFrame* m_pMainFrame; +}; diff --git a/src/mpc-hc/IGraphBuilder2.h b/src/mpc-hc/IGraphBuilder2.h index 7429af50b02..1f335a2da0b 100644 --- a/src/mpc-hc/IGraphBuilder2.h +++ b/src/mpc-hc/IGraphBuilder2.h @@ -1,61 +1,61 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016-2017 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 . - * - */ - -#pragma once - -class CMediaType; - -interface __declspec(uuid("165BE9D6-0929-4363-9BA3-580D735AA0F6")) - IGraphBuilder2 : - public IFilterGraph2 -{ - STDMETHOD(IsPinDirection)(IPin* pPin, PIN_DIRECTION dir) PURE; - STDMETHOD(IsPinConnected)(IPin* pPin) PURE; - STDMETHOD(ConnectFilter)(IBaseFilter* pBF, IPin* pPinIn) PURE; - STDMETHOD(ConnectFilter)(IPin* pPinOut, IBaseFilter* pBF) PURE; - STDMETHOD(ConnectFilterDirect)(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) PURE; - STDMETHOD(NukeDownstream)(IUnknown* pUnk) PURE; - STDMETHOD(FindInterface)(REFIID iid, void** ppv, BOOL bRemove) PURE; - STDMETHOD(AddToROT)() PURE; - STDMETHOD(RemoveFromROT)() PURE; -}; - -// private use only -interface __declspec(uuid("43CDA93D-6A4E-4A07-BD3E-49D161073EE7")) - IGraphBuilderDeadEnd : - public IUnknown -{ - STDMETHOD_(size_t, GetCount)() PURE; - STDMETHOD(GetDeadEnd)(int iIndex, CAtlList& path, CAtlList& mts) PURE; -}; - -// private use only -interface __declspec(uuid("546E72B3-66A1-4A58-A99B-56530B3E2FFF")) - IBDATuner : - public IUnknown -{ - STDMETHOD(SetChannel)(int nChannelPrefNumber) PURE; - STDMETHOD(SetAudio)(int nAudioIndex) PURE; - STDMETHOD(SetFrequency)(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) PURE; - STDMETHOD(Scan)(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd) PURE; - STDMETHOD(GetStats)(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality) PURE; - STDMETHOD(UpdatePSI)(const class CBDAChannel* pChannel, struct EventDescriptor& NowNext) PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016-2017 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 . + * + */ + +#pragma once + +class CMediaType; + +interface __declspec(uuid("165BE9D6-0929-4363-9BA3-580D735AA0F6")) + IGraphBuilder2 : + public IFilterGraph2 +{ + STDMETHOD(IsPinDirection)(IPin* pPin, PIN_DIRECTION dir) PURE; + STDMETHOD(IsPinConnected)(IPin* pPin) PURE; + STDMETHOD(ConnectFilter)(IBaseFilter* pBF, IPin* pPinIn) PURE; + STDMETHOD(ConnectFilter)(IPin* pPinOut, IBaseFilter* pBF) PURE; + STDMETHOD(ConnectFilterDirect)(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) PURE; + STDMETHOD(NukeDownstream)(IUnknown* pUnk) PURE; + STDMETHOD(FindInterface)(REFIID iid, void** ppv, BOOL bRemove) PURE; + STDMETHOD(AddToROT)() PURE; + STDMETHOD(RemoveFromROT)() PURE; +}; + +// private use only +interface __declspec(uuid("43CDA93D-6A4E-4A07-BD3E-49D161073EE7")) + IGraphBuilderDeadEnd : + public IUnknown +{ + STDMETHOD_(size_t, GetCount)() PURE; + STDMETHOD(GetDeadEnd)(int iIndex, CAtlList& path, CAtlList& mts) PURE; +}; + +// private use only +interface __declspec(uuid("546E72B3-66A1-4A58-A99B-56530B3E2FFF")) + IBDATuner : + public IUnknown +{ + STDMETHOD(SetChannel)(int nChannelPrefNumber) PURE; + STDMETHOD(SetAudio)(int nAudioIndex) PURE; + STDMETHOD(SetFrequency)(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) PURE; + STDMETHOD(Scan)(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd) PURE; + STDMETHOD(GetStats)(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality) PURE; + STDMETHOD(UpdatePSI)(const class CBDAChannel* pChannel, struct EventDescriptor& NowNext) PURE; +}; diff --git a/src/mpc-hc/Ifo.cpp b/src/mpc-hc/Ifo.cpp index d01363558a2..9f8dfb80a9a 100644 --- a/src/mpc-hc/Ifo.cpp +++ b/src/mpc-hc/Ifo.cpp @@ -1,282 +1,282 @@ -/* - * (C) 2008-2014 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 . - * - */ - -#include "stdafx.h" -#include "Ifo.h" - - -#ifdef WORDS_BIGENDIAN -#define bswap_16(x) (x) -#define bswap_32(x) (x) -#define bswap_64(x) (x) -#else - -// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. -#define bswap_16(x) \ - ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) - -// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. -#define bswap_32(x) \ - ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ - (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) - -#define bswap_64(x) \ - (__extension__ \ - ({ union { __extension__ unsigned long long int __ll; \ - unsigned long int __l[2]; } __w, __r; \ - __w.__ll = (x); \ - __r.__l[0] = bswap_32 (__w.__l[1]); \ - __r.__l[1] = bswap_32 (__w.__l[0]); \ - __r.__ll; })) -#endif - -#ifdef WORDS_BIGENDIAN -#define be2me_16(x) (x) -#define be2me_32(x) (x) -#define be2me_64(x) (x) -#define le2me_16(x) bswap_16(x) -#define le2me_32(x) bswap_32(x) -#define le2me_64(x) bswap_64(x) -#else -#define be2me_16(x) bswap_16(x) -#define be2me_32(x) bswap_32(x) -#define be2me_64(x) bswap_64(x) -#define le2me_16(x) (x) -#define le2me_32(x) (x) -#define le2me_64(x) (x) -#endif - -#define DVD_VIDEO_LB_LEN 2048 -#define IFO_HDR_LEN 8 -#define LU_SUB_LEN 8 - -extern HANDLE(__stdcall* Real_CreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - - -uint32_t get4bytes(const BYTE* buf) -{ - return be2me_32(*((uint32_t*)buf)); -} - - -// VMG files -#define OFF_VMGM_PGCI_UT(buf) get4bytes (buf + 0xC8) - -// VTS files -#define OFF_VTSM_PGCI_UT(buf) get4bytes (buf + 0xD0) -#define OFF_VTS_PGCIT(buf) get4bytes (buf + 0xCC) - - -CIfo::CIfo() - : m_pBuffer(nullptr) - , m_dwSize(0) - , m_pPGCI(nullptr) - , m_pPGCIT(nullptr) -{ -} - -CIfo::~CIfo() -{ - delete [] m_pBuffer; -} - -int CIfo::GetMiscPGCI(CIfo::ifo_hdr_t* hdr, int title, uint8_t** ptr) -{ - pgci_sub_t* pgci_sub; - - *ptr = (uint8_t*) hdr; - *ptr += IFO_HDR_LEN; - pgci_sub = (pgci_sub_t*) *ptr + title; - - *ptr = (uint8_t*) hdr + be2me_32(pgci_sub->start); - - return 0; -} - -void CIfo::RemovePgciUOPs(uint8_t* ptr) -{ - ifo_hdr_t* hdr = (ifo_hdr_t*) ptr; - uint16_t num; - int i; - - ptr += IFO_HDR_LEN; - num = be2me_16(hdr->num); - - for (i = 1; i <= num; i++) { - lu_sub_t* lu_sub = (lu_sub_t*) ptr; - UNREFERENCED_PARAMETER(lu_sub); - - ptr += LU_SUB_LEN; - } - - for (i = 0; i < be2me_16(hdr->num); i++) { - uint8_t* ptr2; - - if (GetMiscPGCI(hdr, i, &ptr2) >= 0) { - pgc_t* pgc = (pgc_t*) ptr2; - pgc->prohibited_ops = 0; - } - } -} - -CIfo::pgc_t* CIfo::GetFirstPGC() -{ - if (m_pBuffer) { - return (pgc_t*)(m_pBuffer + 0x0400); - } else { - return nullptr; - } -} - -CIfo::pgc_t* CIfo::GetPGCI(const int title, const ifo_hdr_t* hdr) -{ - CIfo::pgci_sub_t* pgci_sub; - uint8_t* ptr; - - ptr = (uint8_t*) hdr; - ptr += IFO_HDR_LEN; - - pgci_sub = (pgci_sub_t*) ptr + title; - - ptr = (uint8_t*) hdr + be2me_32(pgci_sub->start); - - /* jdw */ - if (ptr >= ((uint8_t*) hdr + be2me_32(hdr->len))) { - return nullptr; - } - /* /jdw */ - - return (pgc_t*) ptr; -} - -bool CIfo::IsVTS() -{ - if (m_dwSize < 12 || (strncmp((char*)m_pBuffer, "DVDVIDEO-VTS", 12) != 0)) { - return false; - } - - return true; -} - -bool CIfo::IsVMG() -{ - if (m_dwSize < 12 || (strncmp((char*)m_pBuffer, "DVDVIDEO-VMG", 12) != 0)) { - return false; - } - - return true; -} - -bool CIfo::OpenFile(LPCTSTR strFile) -{ - bool bRet = false; - - HANDLE hFile = Real_CreateFileW(strFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile != INVALID_HANDLE_VALUE) { - LARGE_INTEGER size; - // min size of the ifo file comes from dvd sector size, - // max size we allow is 8 MB (taken with reserve), - // also the file size must a multiple of dvd sector size - if (GetFileSizeEx(hFile, &size) && (size.QuadPart >= DVD_VIDEO_LB_LEN) && - (size.QuadPart <= 0x800000) && !(size.QuadPart % DVD_VIDEO_LB_LEN)) { - ASSERT(!m_pBuffer); - m_pBuffer = DEBUG_NEW BYTE [(size_t)size.QuadPart]; - if (ReadFile(hFile, m_pBuffer, (DWORD)size.QuadPart, &m_dwSize, nullptr)) { - ASSERT(!m_pPGCI); - ASSERT(!m_pPGCIT); - uint32_t sector, sectorCount = (uint32_t)size.QuadPart / DVD_VIDEO_LB_LEN; - if (IsVTS()) { - sector = OFF_VTSM_PGCI_UT(m_pBuffer); - if (sector && (sector < sectorCount)) { - m_pPGCI = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); - } else { - TRACE(_T("IFO: Missing or invalid VTSM_PGCI_UT sector\n")); - } - sector = OFF_VTS_PGCIT(m_pBuffer); - if (sector && (sector < sectorCount)) { - m_pPGCIT = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); - } else { - TRACE(_T("IFO: Missing or invalid VTS_PGCI sector\n")); - } - } else if (IsVMG()) { - sector = OFF_VMGM_PGCI_UT(m_pBuffer); - if (sector && (sector < sectorCount)) { - m_pPGCI = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); - } else { - TRACE(_T("IFO: Missing or invalid VTSM_PGCI_UT sector\n")); - } - } - bRet = (m_pPGCI != nullptr); - } - } - CloseHandle(hFile); - } else { - ASSERT(FALSE); - } - - return bRet; -} - -bool CIfo::RemoveUOPs() -{ - pgc_t* pgc; - - if (m_pPGCI) { - pgc = GetFirstPGC(); - pgc->prohibited_ops = 0; - - for (int i = 0; i < be2me_16(m_pPGCI->num); i++) { - pgc = GetPGCI(i, m_pPGCI); - if (pgc) { - RemovePgciUOPs((uint8_t*)pgc); - } - } - } - if (m_pPGCIT) { - for (int i = 0; i < be2me_16(m_pPGCIT->num); i++) { - pgc = GetPGCI(i, m_pPGCIT); - if (pgc) { - pgc->prohibited_ops = 0; - } - } - } - return true; -} - -bool CIfo::SaveFile(LPCTSTR strFile) -{ - bool bRet = false; - - if (m_pBuffer) { - HANDLE hFile = Real_CreateFileW(strFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile != INVALID_HANDLE_VALUE) { - DWORD written; - if (WriteFile(hFile, m_pBuffer, m_dwSize, &written, nullptr)) { - bRet = true; - } - CloseHandle(hFile); - } - } - - ASSERT(bRet); - - return bRet; -} +/* + * (C) 2008-2014 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 . + * + */ + +#include "stdafx.h" +#include "Ifo.h" + + +#ifdef WORDS_BIGENDIAN +#define bswap_16(x) (x) +#define bswap_32(x) (x) +#define bswap_64(x) (x) +#else + +// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. +#define bswap_16(x) \ + ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) + +// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. +#define bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define bswap_64(x) \ + (__extension__ \ + ({ union { __extension__ unsigned long long int __ll; \ + unsigned long int __l[2]; } __w, __r; \ + __w.__ll = (x); \ + __r.__l[0] = bswap_32 (__w.__l[1]); \ + __r.__l[1] = bswap_32 (__w.__l[0]); \ + __r.__ll; })) +#endif + +#ifdef WORDS_BIGENDIAN +#define be2me_16(x) (x) +#define be2me_32(x) (x) +#define be2me_64(x) (x) +#define le2me_16(x) bswap_16(x) +#define le2me_32(x) bswap_32(x) +#define le2me_64(x) bswap_64(x) +#else +#define be2me_16(x) bswap_16(x) +#define be2me_32(x) bswap_32(x) +#define be2me_64(x) bswap_64(x) +#define le2me_16(x) (x) +#define le2me_32(x) (x) +#define le2me_64(x) (x) +#endif + +#define DVD_VIDEO_LB_LEN 2048 +#define IFO_HDR_LEN 8 +#define LU_SUB_LEN 8 + +extern HANDLE(__stdcall* Real_CreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + + +uint32_t get4bytes(const BYTE* buf) +{ + return be2me_32(*((uint32_t*)buf)); +} + + +// VMG files +#define OFF_VMGM_PGCI_UT(buf) get4bytes (buf + 0xC8) + +// VTS files +#define OFF_VTSM_PGCI_UT(buf) get4bytes (buf + 0xD0) +#define OFF_VTS_PGCIT(buf) get4bytes (buf + 0xCC) + + +CIfo::CIfo() + : m_pBuffer(nullptr) + , m_dwSize(0) + , m_pPGCI(nullptr) + , m_pPGCIT(nullptr) +{ +} + +CIfo::~CIfo() +{ + delete [] m_pBuffer; +} + +int CIfo::GetMiscPGCI(CIfo::ifo_hdr_t* hdr, int title, uint8_t** ptr) +{ + pgci_sub_t* pgci_sub; + + *ptr = (uint8_t*) hdr; + *ptr += IFO_HDR_LEN; + pgci_sub = (pgci_sub_t*) *ptr + title; + + *ptr = (uint8_t*) hdr + be2me_32(pgci_sub->start); + + return 0; +} + +void CIfo::RemovePgciUOPs(uint8_t* ptr) +{ + ifo_hdr_t* hdr = (ifo_hdr_t*) ptr; + uint16_t num; + int i; + + ptr += IFO_HDR_LEN; + num = be2me_16(hdr->num); + + for (i = 1; i <= num; i++) { + lu_sub_t* lu_sub = (lu_sub_t*) ptr; + UNREFERENCED_PARAMETER(lu_sub); + + ptr += LU_SUB_LEN; + } + + for (i = 0; i < be2me_16(hdr->num); i++) { + uint8_t* ptr2; + + if (GetMiscPGCI(hdr, i, &ptr2) >= 0) { + pgc_t* pgc = (pgc_t*) ptr2; + pgc->prohibited_ops = 0; + } + } +} + +CIfo::pgc_t* CIfo::GetFirstPGC() +{ + if (m_pBuffer) { + return (pgc_t*)(m_pBuffer + 0x0400); + } else { + return nullptr; + } +} + +CIfo::pgc_t* CIfo::GetPGCI(const int title, const ifo_hdr_t* hdr) +{ + CIfo::pgci_sub_t* pgci_sub; + uint8_t* ptr; + + ptr = (uint8_t*) hdr; + ptr += IFO_HDR_LEN; + + pgci_sub = (pgci_sub_t*) ptr + title; + + ptr = (uint8_t*) hdr + be2me_32(pgci_sub->start); + + /* jdw */ + if (ptr >= ((uint8_t*) hdr + be2me_32(hdr->len))) { + return nullptr; + } + /* /jdw */ + + return (pgc_t*) ptr; +} + +bool CIfo::IsVTS() +{ + if (m_dwSize < 12 || (strncmp((char*)m_pBuffer, "DVDVIDEO-VTS", 12) != 0)) { + return false; + } + + return true; +} + +bool CIfo::IsVMG() +{ + if (m_dwSize < 12 || (strncmp((char*)m_pBuffer, "DVDVIDEO-VMG", 12) != 0)) { + return false; + } + + return true; +} + +bool CIfo::OpenFile(LPCTSTR strFile) +{ + bool bRet = false; + + HANDLE hFile = Real_CreateFileW(strFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile != INVALID_HANDLE_VALUE) { + LARGE_INTEGER size; + // min size of the ifo file comes from dvd sector size, + // max size we allow is 8 MB (taken with reserve), + // also the file size must a multiple of dvd sector size + if (GetFileSizeEx(hFile, &size) && (size.QuadPart >= DVD_VIDEO_LB_LEN) && + (size.QuadPart <= 0x800000) && !(size.QuadPart % DVD_VIDEO_LB_LEN)) { + ASSERT(!m_pBuffer); + m_pBuffer = DEBUG_NEW BYTE [(size_t)size.QuadPart]; + if (ReadFile(hFile, m_pBuffer, (DWORD)size.QuadPart, &m_dwSize, nullptr)) { + ASSERT(!m_pPGCI); + ASSERT(!m_pPGCIT); + uint32_t sector, sectorCount = (uint32_t)size.QuadPart / DVD_VIDEO_LB_LEN; + if (IsVTS()) { + sector = OFF_VTSM_PGCI_UT(m_pBuffer); + if (sector && (sector < sectorCount)) { + m_pPGCI = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); + } else { + TRACE(_T("IFO: Missing or invalid VTSM_PGCI_UT sector\n")); + } + sector = OFF_VTS_PGCIT(m_pBuffer); + if (sector && (sector < sectorCount)) { + m_pPGCIT = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); + } else { + TRACE(_T("IFO: Missing or invalid VTS_PGCI sector\n")); + } + } else if (IsVMG()) { + sector = OFF_VMGM_PGCI_UT(m_pBuffer); + if (sector && (sector < sectorCount)) { + m_pPGCI = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); + } else { + TRACE(_T("IFO: Missing or invalid VTSM_PGCI_UT sector\n")); + } + } + bRet = (m_pPGCI != nullptr); + } + } + CloseHandle(hFile); + } else { + ASSERT(FALSE); + } + + return bRet; +} + +bool CIfo::RemoveUOPs() +{ + pgc_t* pgc; + + if (m_pPGCI) { + pgc = GetFirstPGC(); + pgc->prohibited_ops = 0; + + for (int i = 0; i < be2me_16(m_pPGCI->num); i++) { + pgc = GetPGCI(i, m_pPGCI); + if (pgc) { + RemovePgciUOPs((uint8_t*)pgc); + } + } + } + if (m_pPGCIT) { + for (int i = 0; i < be2me_16(m_pPGCIT->num); i++) { + pgc = GetPGCI(i, m_pPGCIT); + if (pgc) { + pgc->prohibited_ops = 0; + } + } + } + return true; +} + +bool CIfo::SaveFile(LPCTSTR strFile) +{ + bool bRet = false; + + if (m_pBuffer) { + HANDLE hFile = Real_CreateFileW(strFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile != INVALID_HANDLE_VALUE) { + DWORD written; + if (WriteFile(hFile, m_pBuffer, m_dwSize, &written, nullptr)) { + bRet = true; + } + CloseHandle(hFile); + } + } + + ASSERT(bRet); + + return bRet; +} diff --git a/src/mpc-hc/Ifo.h b/src/mpc-hc/Ifo.h index 86e63a53262..fe9b5c51ee9 100644 --- a/src/mpc-hc/Ifo.h +++ b/src/mpc-hc/Ifo.h @@ -1,186 +1,186 @@ -/* - * (C) 2008-2013, 2016 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 . - * - */ - -#pragma once - -#include - -#pragma pack(push, 1) - - -class CIfo -{ -public: - CIfo(); - ~CIfo(); - - bool OpenFile(LPCTSTR strFile); - bool SaveFile(LPCTSTR strFile); - bool RemoveUOPs(); - -private: - - struct pgci_sub_t { - uint16_t id : 16; // Language - uint16_t : 16; // don't know - uint32_t start : 32; // Start of unit - }; - - struct dvd_time_t { - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t frame_u; // The two high bits are the frame rate. - }; - - typedef uint8_t command_data_t[8]; -#define COMMAND_DATA_SIZE 8 - - struct pgc_command_tbl_t { // PGC Command Table - uint16_t nr_of_pre; - uint16_t nr_of_post; - uint16_t nr_of_cell; - uint16_t tbl_len; - command_data_t* pre_commands; - command_data_t* post_commands; - command_data_t* cell_commands; - }; -#define PGC_COMMAND_TBL_SIZE 8 - - typedef uint8_t pgc_program_map_t; - - struct ifo_pgci_caddr_t { // Cell Playback Information - uint8_t chain_info : 8; // 0x5e 0xde(2 angles, no overlay), 0x5f 0x9f 0x9f 0xdf(4 angles overlay), 0x2 0xa 0x8(1 angle) - uint8_t foo; // parental control ?? - uint8_t still_time; - uint8_t cell_cmd; - - dvd_time_t playback_time; - uint32_t vobu_start; // 1st vobu start - uint32_t ilvu_end; - uint32_t vobu_last_start; - uint32_t vobu_last_end; - }; - - struct ifo_pgc_cpos_t { // Cell Position Information - uint16_t vob_id : 16; // Video Object Identifier - uint8_t foo : 8; // Unknown - uint8_t cell_id : 8; // Cell Identifier - }; - -#ifndef CLUT_T -#define CLUT_T - - struct clut_t { // CLUT == Color LookUp Table - uint8_t foo : 8; // UNKNOWN: 0x00? - uint8_t y : 8; - uint8_t cr : 8; - uint8_t cb : 8; - }; -#endif - - struct audio_status_t { // Audio Status -#if BYTE_ORDER == BIG_ENDIAN - uint8_t available : 1; - uint8_t link : 7; -#else - uint8_t link : 7; - uint8_t available : 1; -#endif - uint8_t foo : 8; // UNKNOWN - }; - - - struct subp_status_t { // Subpicture status -#if BYTE_ORDER == BIG_ENDIAN - uint8_t available : 1; - uint8_t format4_3 : 7; -#else - uint8_t format4_3 : 7; - uint8_t available : 1; -#endif - uint8_t wide : 8; - uint8_t letter : 8; - uint8_t pan : 8; - }; - - - struct pgc_t { // Program Chain Information - uint16_t zero_1; - uint8_t nr_of_programs; - uint8_t nr_of_cells; - dvd_time_t playback_time; - uint32_t prohibited_ops; // New type? - audio_status_t audio_status[8]; - subp_status_t subp_status[32]; - uint16_t next_pgc_nr; - uint16_t prev_pgc_nr; - uint16_t goup_pgc_nr; - uint8_t still_time; - uint8_t pg_playback_mode; - clut_t clut[16]; - uint16_t pgc_command_tbl_offset; - uint16_t pgc_program_map_offset; - uint16_t cell_playback_tbl_offset; - uint16_t cell_position_tbl_offset; - pgc_command_tbl_t* pgc_command_tbl; - pgc_program_map_t* pgc_program_map; - ifo_pgci_caddr_t* cell_playback_tbl; - ifo_pgc_cpos_t* cell_position_tbl; - }; -#define PGC_SIZE 236 - - struct ifo_hdr_t { - uint16_t num : 16; // number of entries - uint16_t : 16; // UNKNOWN - uint32_t len : 32; // length of table - }; - - struct lu_sub_t { -#if BYTE_ORDER == BIG_ENDIAN - uint16_t foo1 : 4; // don't know - uint8_t menu_id : 4; // 0=off, 3=root, 4=spu, - // 5=audio, 6=angle, 7=ptt -#else - uint8_t menu_id : 4; // 0=off, 3=root, 4=spu, - // 5=audio, 6=angle, 7=ptt - uint16_t foo1 : 4; // don't know -#endif - uint16_t foo2 : 8; // don't know - uint16_t bar : 16; // don't know - uint32_t start : 32; // Start of unit - }; - - - BYTE* m_pBuffer; - DWORD m_dwSize; - - ifo_hdr_t* m_pPGCI; - ifo_hdr_t* m_pPGCIT; - - bool IsVTS(); - bool IsVMG(); - - pgc_t* GetFirstPGC(); - pgc_t* GetPGCI(const int title, const ifo_hdr_t* hdr); - int GetMiscPGCI(ifo_hdr_t* hdr, int title, uint8_t** ptr); - void RemovePgciUOPs(uint8_t* ptr); -}; -#pragma pack(pop) +/* + * (C) 2008-2013, 2016 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 . + * + */ + +#pragma once + +#include + +#pragma pack(push, 1) + + +class CIfo +{ +public: + CIfo(); + ~CIfo(); + + bool OpenFile(LPCTSTR strFile); + bool SaveFile(LPCTSTR strFile); + bool RemoveUOPs(); + +private: + + struct pgci_sub_t { + uint16_t id : 16; // Language + uint16_t : 16; // don't know + uint32_t start : 32; // Start of unit + }; + + struct dvd_time_t { + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t frame_u; // The two high bits are the frame rate. + }; + + typedef uint8_t command_data_t[8]; +#define COMMAND_DATA_SIZE 8 + + struct pgc_command_tbl_t { // PGC Command Table + uint16_t nr_of_pre; + uint16_t nr_of_post; + uint16_t nr_of_cell; + uint16_t tbl_len; + command_data_t* pre_commands; + command_data_t* post_commands; + command_data_t* cell_commands; + }; +#define PGC_COMMAND_TBL_SIZE 8 + + typedef uint8_t pgc_program_map_t; + + struct ifo_pgci_caddr_t { // Cell Playback Information + uint8_t chain_info : 8; // 0x5e 0xde(2 angles, no overlay), 0x5f 0x9f 0x9f 0xdf(4 angles overlay), 0x2 0xa 0x8(1 angle) + uint8_t foo; // parental control ?? + uint8_t still_time; + uint8_t cell_cmd; + + dvd_time_t playback_time; + uint32_t vobu_start; // 1st vobu start + uint32_t ilvu_end; + uint32_t vobu_last_start; + uint32_t vobu_last_end; + }; + + struct ifo_pgc_cpos_t { // Cell Position Information + uint16_t vob_id : 16; // Video Object Identifier + uint8_t foo : 8; // Unknown + uint8_t cell_id : 8; // Cell Identifier + }; + +#ifndef CLUT_T +#define CLUT_T + + struct clut_t { // CLUT == Color LookUp Table + uint8_t foo : 8; // UNKNOWN: 0x00? + uint8_t y : 8; + uint8_t cr : 8; + uint8_t cb : 8; + }; +#endif + + struct audio_status_t { // Audio Status +#if BYTE_ORDER == BIG_ENDIAN + uint8_t available : 1; + uint8_t link : 7; +#else + uint8_t link : 7; + uint8_t available : 1; +#endif + uint8_t foo : 8; // UNKNOWN + }; + + + struct subp_status_t { // Subpicture status +#if BYTE_ORDER == BIG_ENDIAN + uint8_t available : 1; + uint8_t format4_3 : 7; +#else + uint8_t format4_3 : 7; + uint8_t available : 1; +#endif + uint8_t wide : 8; + uint8_t letter : 8; + uint8_t pan : 8; + }; + + + struct pgc_t { // Program Chain Information + uint16_t zero_1; + uint8_t nr_of_programs; + uint8_t nr_of_cells; + dvd_time_t playback_time; + uint32_t prohibited_ops; // New type? + audio_status_t audio_status[8]; + subp_status_t subp_status[32]; + uint16_t next_pgc_nr; + uint16_t prev_pgc_nr; + uint16_t goup_pgc_nr; + uint8_t still_time; + uint8_t pg_playback_mode; + clut_t clut[16]; + uint16_t pgc_command_tbl_offset; + uint16_t pgc_program_map_offset; + uint16_t cell_playback_tbl_offset; + uint16_t cell_position_tbl_offset; + pgc_command_tbl_t* pgc_command_tbl; + pgc_program_map_t* pgc_program_map; + ifo_pgci_caddr_t* cell_playback_tbl; + ifo_pgc_cpos_t* cell_position_tbl; + }; +#define PGC_SIZE 236 + + struct ifo_hdr_t { + uint16_t num : 16; // number of entries + uint16_t : 16; // UNKNOWN + uint32_t len : 32; // length of table + }; + + struct lu_sub_t { +#if BYTE_ORDER == BIG_ENDIAN + uint16_t foo1 : 4; // don't know + uint8_t menu_id : 4; // 0=off, 3=root, 4=spu, + // 5=audio, 6=angle, 7=ptt +#else + uint8_t menu_id : 4; // 0=off, 3=root, 4=spu, + // 5=audio, 6=angle, 7=ptt + uint16_t foo1 : 4; // don't know +#endif + uint16_t foo2 : 8; // don't know + uint16_t bar : 16; // don't know + uint32_t start : 32; // Start of unit + }; + + + BYTE* m_pBuffer; + DWORD m_dwSize; + + ifo_hdr_t* m_pPGCI; + ifo_hdr_t* m_pPGCIT; + + bool IsVTS(); + bool IsVMG(); + + pgc_t* GetFirstPGC(); + pgc_t* GetPGCI(const int title, const ifo_hdr_t* hdr); + int GetMiscPGCI(ifo_hdr_t* hdr, int title, uint8_t** ptr); + void RemovePgciUOPs(uint8_t* ptr); +}; +#pragma pack(pop) diff --git a/src/mpc-hc/ImageGrayer.cpp b/src/mpc-hc/ImageGrayer.cpp index a858ac58448..35bbeb0f1ae 100644 --- a/src/mpc-hc/ImageGrayer.cpp +++ b/src/mpc-hc/ImageGrayer.cpp @@ -1,304 +1,304 @@ -/* -* (C) 2016 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 . -* -*/ - -#include "stdafx.h" -#include "ImageGrayer.h" -#include "CMPCTheme.h" - -struct HLS { - double H, L, S; - - HLS(const RGBQUAD& rgb) { - double R = rgb.rgbRed / 255.0; - double G = rgb.rgbGreen / 255.0; - double B = rgb.rgbBlue / 255.0; - double max = std::max({ R, G, B }); - double min = std::min({ R, G, B }); - - L = (max + min) / 2.0; - - if (max == min) { - S = H = 0.0; - } else { - double d = max - min; - - S = (L < 0.5) ? (d / (max + min)) : (d / (2.0 - max - min)); - - if (R == max) { - H = (G - B) / d; - } else if (G == max) { - H = 2.0 + (B - R) / d; - } else { // if (B == max) - H = 4.0 + (R - G) / d; - } - H /= 6.0; - if (H < 0.0) { - H += 1.0; - } - } - } - - RGBQUAD toRGBQUAD() { - RGBQUAD rgb; - rgb.rgbReserved = 255; - - if (S == 0.0) { - rgb.rgbRed = rgb.rgbGreen = rgb.rgbBlue = BYTE(L * 255); - } else { - auto hue2rgb = [](double p, double q, double h) { - if (h < 0.0) { - h += 1.0; - } else if (h > 1.0) { - h -= 1.0; - } - - if (h < 1.0 / 6.0) { - return p + (q - p) * 6.0 * h; - } else if (h < 0.5) { - return q; - } else if (h < 2.0 / 3.0) { - return p + (q - p) * (2.0 / 3.0 - h) * 6.0; - } - return p; - }; - - double q = (L < 0.5) ? (L * (1 + S)) : (L + S - L * S); - double p = 2 * L - q; - - rgb.rgbRed = BYTE(hue2rgb(p, q, H + 1.0 / 3.0) * 255); - rgb.rgbGreen = BYTE(hue2rgb(p, q, H) * 255); - rgb.rgbBlue = BYTE(hue2rgb(p, q, H - 1.0 / 3.0) * 255); - } - - return rgb; - } -}; - -bool ImageGrayer::Gray(const CImage& imgSource, CImage& imgDest, float brightness) -{ - // Only support 32-bit image for now - if (imgSource.GetBPP() != 32) { - return false; - } - - imgDest.Destroy(); - if (!imgDest.Create(imgSource.GetWidth(), imgSource.GetHeight(), imgSource.GetBPP())) { - return false; - } - BOOL bCopied = imgSource.BitBlt(imgDest.GetDC(), 0, 0); - imgDest.ReleaseDC(); - if (!bCopied) { - return false; - } - - auto adjustBrightness = [](BYTE c, double p) { - int cAdjusted; - if (c == 0 && p > 1.0) { - cAdjusted = std::lround((p - 1.0) * 255); - } else { - cAdjusted = std::lround(c * p); - } - - return BYTE(std::min(cAdjusted, 255)); - }; - - BYTE* bits = static_cast(imgDest.GetBits()); - for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < imgDest.GetWidth(); x++) { - HLS hls(p[x]); - hls.S = 0.0; // Make the color gray - - RGBQUAD rgb = hls.toRGBQUAD(); - - p[x].rgbRed = BYTE(adjustBrightness(rgb.rgbRed, 1.5 * brightness) * p[x].rgbReserved / 255); - p[x].rgbGreen = BYTE(adjustBrightness(rgb.rgbGreen, 1.5 * brightness) * p[x].rgbReserved / 255); - p[x].rgbBlue = BYTE(adjustBrightness(rgb.rgbBlue, 1.5 * brightness) * p[x].rgbReserved / 255); - } - } - - return true; -} - -bool ImageGrayer::UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle) -{ - // Force to 32-bit - CImage img32; - CImage const* imgSrc; - if (imgSource.GetBPP() != 32) { - if (!img32.Create(imgSource.GetWidth(), imgSource.GetHeight(), 32, CImage::createAlphaChannel)) { - return false; - } - - HDC const iDC = img32.GetDC(); - BOOL const bbResult = imgSource.BitBlt(iDC, 0, 0, SRCCOPY); - img32.ReleaseDC(); - - if (!bbResult) { - return false; - } - - BYTE* bits = static_cast(img32.GetBits()); - for (int y = 0; y < img32.GetHeight(); y++, bits += img32.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < img32.GetWidth(); x++) { - HLS hls(p[x]); - p[x].rgbReserved = 255; - } - } - imgSrc = &img32; - } else { - imgSrc = &imgSource; - } - - if (colorStyle == ImageGrayer::classicGrayscale) { - return Gray(imgSource, imgDest); - } else if (colorStyle == ImageGrayer::mpcGrayDisabled) { - if (disabled) { - return Gray(imgSource, imgDest, 0.5f); - } else { - imgDest = imgSource; - } - } else { //mpcMono - imgDest.Destroy(); - - if (!imgDest.Create(imgSrc->GetWidth(), imgSrc->GetHeight(), imgSrc->GetBPP())) { - return false; - } - BOOL bCopied = imgSrc->BitBlt(imgDest.GetDC(), 0, 0); - imgDest.ReleaseDC(); - if (!bCopied) { - return false; - } - - RGBQUAD newColor; - COLORREF themeColor; - - if (disabled) { - themeColor = CMPCTheme::ImageDisabledColor; - } else { - themeColor = CMPCTheme::TextFGColorFade; - } - newColor.rgbRed = GetRValue(themeColor); - newColor.rgbGreen = GetGValue(themeColor); - newColor.rgbBlue = GetBValue(themeColor); - newColor.rgbReserved = 0; - - - - BYTE* bits = static_cast(imgDest.GetBits()); - for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < imgDest.GetWidth(); x++) { - HLS hls(p[x]); - - RGBQUAD rgb = hls.toRGBQUAD(); - - if (p[x].rgbReserved != 0) { //ignore the transparent bits - p[x].rgbRed = newColor.rgbRed; - p[x].rgbBlue = newColor.rgbBlue; - p[x].rgbGreen = newColor.rgbGreen; - } - } - } - } - - return true; -} - -bool ImageGrayer::Colorize(const CImage& imgSrc, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90) { - // Force to 32-bit - if (imgSrc.GetBPP() != 32) { - return false; - } - - imgDest.Destroy(); - - int width = imgSrc.GetWidth(); - int height = imgSrc.GetHeight(); - - if (!imgDest.Create(width, height, imgSrc.GetBPP())) { - return false; - } - BOOL bCopied = imgSrc.BitBlt(imgDest.GetDC(), 0, 0); - imgDest.ReleaseDC(); - if (!bCopied) { - return false; - } - - RGBQUAD fgColor, bgColor; - fgColor.rgbRed = GetRValue(fg); - fgColor.rgbGreen = GetGValue(fg); - fgColor.rgbBlue = GetBValue(fg); - fgColor.rgbReserved = 0; - - bgColor.rgbRed = GetRValue(bg); - bgColor.rgbGreen = GetGValue(bg); - bgColor.rgbBlue = GetBValue(bg); - bgColor.rgbReserved = 0; - - - BYTE* bits = static_cast(imgDest.GetBits()); - for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < imgDest.GetWidth(); x++) { - HLS hls(p[x]); - - RGBQUAD rgb = hls.toRGBQUAD(); - - if (p[x].rgbReserved != 0) { //ignore the transparent bits - p[x].rgbRed = BYTE(fgColor.rgbRed * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbRed / 255); - p[x].rgbBlue = BYTE(fgColor.rgbBlue * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbBlue / 255); - p[x].rgbGreen = BYTE(fgColor.rgbGreen * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbGreen / 255); - } else { - p[x].rgbRed = bgColor.rgbRed; - p[x].rgbBlue = bgColor.rgbBlue; - p[x].rgbGreen = bgColor.rgbGreen; - } - p[x].rgbReserved = 255; - } - } - - if (rot90) { - Gdiplus::Bitmap* gdiPlusBitmap = Gdiplus::Bitmap::FromHBITMAP(imgDest.Detach(), 0); - gdiPlusBitmap->RotateFlip(Gdiplus::Rotate90FlipNone); - HBITMAP hbmp; - gdiPlusBitmap->GetHBITMAP(Gdiplus::Color::White, &hbmp); - imgDest.Attach(hbmp); - } - - return true; -} - -void ImageGrayer::PreMultiplyAlpha(CImage& imgSource) { - BYTE* bits = static_cast(imgSource.GetBits()); - for (int y = 0; y < imgSource.GetHeight(); y++, bits += imgSource.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < imgSource.GetWidth(); x++) { - HLS hls(p[x]); - - RGBQUAD rgb = hls.toRGBQUAD(); - - p[x].rgbRed = static_cast(round((float)p[x].rgbRed * p[x].rgbReserved / 255.0f)); - p[x].rgbBlue = static_cast(round((float)p[x].rgbBlue * p[x].rgbReserved / 255.0f)); - p[x].rgbGreen = static_cast(round((float)p[x].rgbGreen * p[x].rgbReserved / 255.0f)); - } - } -} +/* +* (C) 2016 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 . +* +*/ + +#include "stdafx.h" +#include "ImageGrayer.h" +#include "CMPCTheme.h" + +struct HLS { + double H, L, S; + + HLS(const RGBQUAD& rgb) { + double R = rgb.rgbRed / 255.0; + double G = rgb.rgbGreen / 255.0; + double B = rgb.rgbBlue / 255.0; + double max = std::max({ R, G, B }); + double min = std::min({ R, G, B }); + + L = (max + min) / 2.0; + + if (max == min) { + S = H = 0.0; + } else { + double d = max - min; + + S = (L < 0.5) ? (d / (max + min)) : (d / (2.0 - max - min)); + + if (R == max) { + H = (G - B) / d; + } else if (G == max) { + H = 2.0 + (B - R) / d; + } else { // if (B == max) + H = 4.0 + (R - G) / d; + } + H /= 6.0; + if (H < 0.0) { + H += 1.0; + } + } + } + + RGBQUAD toRGBQUAD() { + RGBQUAD rgb; + rgb.rgbReserved = 255; + + if (S == 0.0) { + rgb.rgbRed = rgb.rgbGreen = rgb.rgbBlue = BYTE(L * 255); + } else { + auto hue2rgb = [](double p, double q, double h) { + if (h < 0.0) { + h += 1.0; + } else if (h > 1.0) { + h -= 1.0; + } + + if (h < 1.0 / 6.0) { + return p + (q - p) * 6.0 * h; + } else if (h < 0.5) { + return q; + } else if (h < 2.0 / 3.0) { + return p + (q - p) * (2.0 / 3.0 - h) * 6.0; + } + return p; + }; + + double q = (L < 0.5) ? (L * (1 + S)) : (L + S - L * S); + double p = 2 * L - q; + + rgb.rgbRed = BYTE(hue2rgb(p, q, H + 1.0 / 3.0) * 255); + rgb.rgbGreen = BYTE(hue2rgb(p, q, H) * 255); + rgb.rgbBlue = BYTE(hue2rgb(p, q, H - 1.0 / 3.0) * 255); + } + + return rgb; + } +}; + +bool ImageGrayer::Gray(const CImage& imgSource, CImage& imgDest, float brightness) +{ + // Only support 32-bit image for now + if (imgSource.GetBPP() != 32) { + return false; + } + + imgDest.Destroy(); + if (!imgDest.Create(imgSource.GetWidth(), imgSource.GetHeight(), imgSource.GetBPP())) { + return false; + } + BOOL bCopied = imgSource.BitBlt(imgDest.GetDC(), 0, 0); + imgDest.ReleaseDC(); + if (!bCopied) { + return false; + } + + auto adjustBrightness = [](BYTE c, double p) { + int cAdjusted; + if (c == 0 && p > 1.0) { + cAdjusted = std::lround((p - 1.0) * 255); + } else { + cAdjusted = std::lround(c * p); + } + + return BYTE(std::min(cAdjusted, 255)); + }; + + BYTE* bits = static_cast(imgDest.GetBits()); + for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgDest.GetWidth(); x++) { + HLS hls(p[x]); + hls.S = 0.0; // Make the color gray + + RGBQUAD rgb = hls.toRGBQUAD(); + + p[x].rgbRed = BYTE(adjustBrightness(rgb.rgbRed, 1.5 * brightness) * p[x].rgbReserved / 255); + p[x].rgbGreen = BYTE(adjustBrightness(rgb.rgbGreen, 1.5 * brightness) * p[x].rgbReserved / 255); + p[x].rgbBlue = BYTE(adjustBrightness(rgb.rgbBlue, 1.5 * brightness) * p[x].rgbReserved / 255); + } + } + + return true; +} + +bool ImageGrayer::UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle) +{ + // Force to 32-bit + CImage img32; + CImage const* imgSrc; + if (imgSource.GetBPP() != 32) { + if (!img32.Create(imgSource.GetWidth(), imgSource.GetHeight(), 32, CImage::createAlphaChannel)) { + return false; + } + + HDC const iDC = img32.GetDC(); + BOOL const bbResult = imgSource.BitBlt(iDC, 0, 0, SRCCOPY); + img32.ReleaseDC(); + + if (!bbResult) { + return false; + } + + BYTE* bits = static_cast(img32.GetBits()); + for (int y = 0; y < img32.GetHeight(); y++, bits += img32.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < img32.GetWidth(); x++) { + HLS hls(p[x]); + p[x].rgbReserved = 255; + } + } + imgSrc = &img32; + } else { + imgSrc = &imgSource; + } + + if (colorStyle == ImageGrayer::classicGrayscale) { + return Gray(imgSource, imgDest); + } else if (colorStyle == ImageGrayer::mpcGrayDisabled) { + if (disabled) { + return Gray(imgSource, imgDest, 0.5f); + } else { + imgDest = imgSource; + } + } else { //mpcMono + imgDest.Destroy(); + + if (!imgDest.Create(imgSrc->GetWidth(), imgSrc->GetHeight(), imgSrc->GetBPP())) { + return false; + } + BOOL bCopied = imgSrc->BitBlt(imgDest.GetDC(), 0, 0); + imgDest.ReleaseDC(); + if (!bCopied) { + return false; + } + + RGBQUAD newColor; + COLORREF themeColor; + + if (disabled) { + themeColor = CMPCTheme::ImageDisabledColor; + } else { + themeColor = CMPCTheme::TextFGColorFade; + } + newColor.rgbRed = GetRValue(themeColor); + newColor.rgbGreen = GetGValue(themeColor); + newColor.rgbBlue = GetBValue(themeColor); + newColor.rgbReserved = 0; + + + + BYTE* bits = static_cast(imgDest.GetBits()); + for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgDest.GetWidth(); x++) { + HLS hls(p[x]); + + RGBQUAD rgb = hls.toRGBQUAD(); + + if (p[x].rgbReserved != 0) { //ignore the transparent bits + p[x].rgbRed = newColor.rgbRed; + p[x].rgbBlue = newColor.rgbBlue; + p[x].rgbGreen = newColor.rgbGreen; + } + } + } + } + + return true; +} + +bool ImageGrayer::Colorize(const CImage& imgSrc, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90) { + // Force to 32-bit + if (imgSrc.GetBPP() != 32) { + return false; + } + + imgDest.Destroy(); + + int width = imgSrc.GetWidth(); + int height = imgSrc.GetHeight(); + + if (!imgDest.Create(width, height, imgSrc.GetBPP())) { + return false; + } + BOOL bCopied = imgSrc.BitBlt(imgDest.GetDC(), 0, 0); + imgDest.ReleaseDC(); + if (!bCopied) { + return false; + } + + RGBQUAD fgColor, bgColor; + fgColor.rgbRed = GetRValue(fg); + fgColor.rgbGreen = GetGValue(fg); + fgColor.rgbBlue = GetBValue(fg); + fgColor.rgbReserved = 0; + + bgColor.rgbRed = GetRValue(bg); + bgColor.rgbGreen = GetGValue(bg); + bgColor.rgbBlue = GetBValue(bg); + bgColor.rgbReserved = 0; + + + BYTE* bits = static_cast(imgDest.GetBits()); + for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgDest.GetWidth(); x++) { + HLS hls(p[x]); + + RGBQUAD rgb = hls.toRGBQUAD(); + + if (p[x].rgbReserved != 0) { //ignore the transparent bits + p[x].rgbRed = BYTE(fgColor.rgbRed * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbRed / 255); + p[x].rgbBlue = BYTE(fgColor.rgbBlue * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbBlue / 255); + p[x].rgbGreen = BYTE(fgColor.rgbGreen * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbGreen / 255); + } else { + p[x].rgbRed = bgColor.rgbRed; + p[x].rgbBlue = bgColor.rgbBlue; + p[x].rgbGreen = bgColor.rgbGreen; + } + p[x].rgbReserved = 255; + } + } + + if (rot90) { + Gdiplus::Bitmap* gdiPlusBitmap = Gdiplus::Bitmap::FromHBITMAP(imgDest.Detach(), 0); + gdiPlusBitmap->RotateFlip(Gdiplus::Rotate90FlipNone); + HBITMAP hbmp; + gdiPlusBitmap->GetHBITMAP(Gdiplus::Color::White, &hbmp); + imgDest.Attach(hbmp); + } + + return true; +} + +void ImageGrayer::PreMultiplyAlpha(CImage& imgSource) { + BYTE* bits = static_cast(imgSource.GetBits()); + for (int y = 0; y < imgSource.GetHeight(); y++, bits += imgSource.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgSource.GetWidth(); x++) { + HLS hls(p[x]); + + RGBQUAD rgb = hls.toRGBQUAD(); + + p[x].rgbRed = static_cast(round((float)p[x].rgbRed * p[x].rgbReserved / 255.0f)); + p[x].rgbBlue = static_cast(round((float)p[x].rgbBlue * p[x].rgbReserved / 255.0f)); + p[x].rgbGreen = static_cast(round((float)p[x].rgbGreen * p[x].rgbReserved / 255.0f)); + } + } +} diff --git a/src/mpc-hc/ImageGrayer.h b/src/mpc-hc/ImageGrayer.h index 0ef54dbe4d3..44d643bcaf9 100644 --- a/src/mpc-hc/ImageGrayer.h +++ b/src/mpc-hc/ImageGrayer.h @@ -1,35 +1,35 @@ -/* -* (C) 2016 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 . -* -*/ - -#pragma once - -namespace ImageGrayer -{ - enum mpcColorStyle { - classicGrayscale, - mpcMono, - mpcGrayDisabled, - }; - - bool Gray(const CImage& imgSource, CImage& imgDest, float brightness = 1.0f); - bool UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle); - bool Colorize(const CImage& imgSource, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90); - void PreMultiplyAlpha(CImage& imgSource); -} +/* +* (C) 2016 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 . +* +*/ + +#pragma once + +namespace ImageGrayer +{ + enum mpcColorStyle { + classicGrayscale, + mpcMono, + mpcGrayDisabled, + }; + + bool Gray(const CImage& imgSource, CImage& imgDest, float brightness = 1.0f); + bool UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle); + bool Colorize(const CImage& imgSource, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90); + void PreMultiplyAlpha(CImage& imgSource); +} diff --git a/src/mpc-hc/InternalFiltersConfig.h b/src/mpc-hc/InternalFiltersConfig.h index 0065fa8891b..1aae33a1906 100644 --- a/src/mpc-hc/InternalFiltersConfig.h +++ b/src/mpc-hc/InternalFiltersConfig.h @@ -1,124 +1,124 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -// For configuring which internal filters are included into the build. - -#pragma once - -#if defined(MPCHC_LITE) -#define INTERNAL_FILTERS_OTHER 0 -#else -#define INTERNAL_FILTERS_OTHER 1 -#endif -#define INTERNAL_FILTERS_LAV USE_LAVFILTERS - -// Internal source filters -#define INTERNAL_SOURCEFILTER_AC3 INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_ASF INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_AVI INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_AVS INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_DTS INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_FLAC INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_FLIC INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_FLV INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_GIF INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_HTTP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MATROSKA INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MISC INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MMS INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MP4 INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MPEG INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MPEGAUDIO INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_OGG INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_REALMEDIA INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_RTMP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_RTP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_RTSP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_UDP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_WTV INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_CDDA INTERNAL_FILTERS_OTHER -#define INTERNAL_SOURCEFILTER_CDXA INTERNAL_FILTERS_OTHER -#define INTERNAL_SOURCEFILTER_DSM INTERNAL_FILTERS_OTHER -#define INTERNAL_SOURCEFILTER_RFS INTERNAL_FILTERS_OTHER -#define INTERNAL_SOURCEFILTER_VTS INTERNAL_FILTERS_OTHER - -// Internal audio decoders -#define INTERNAL_DECODER_LPCM INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_PS2AUDIO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_REALAUDIO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_PCM INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AC3 INTERNAL_FILTERS_LAV /* also E-AC3, TrueHD, MLP */ -#define INTERNAL_DECODER_DTS INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AAC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_ALAC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_ALS INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MPEGAUDIO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VORBIS INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_NELLYMOSER INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AMR INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_ADPCM INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_FLAC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_OPUS INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_WMA INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_WMAPRO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_WMALL INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_G726 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_G729 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_OTHERAUDIO INTERNAL_FILTERS_LAV - -// Internal video decoders -#define INTERNAL_DECODER_MPEG1 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MPEG2 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_REALVIDEO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_H264 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_HEVC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VVC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AV1 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VC1 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_FLV INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VP356 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_DIVX INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_XVID INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_WMV INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MSMPEG4 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_SVQ INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_H263 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_THEORA INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AMVV INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VP8 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VP9 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MJPEG INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_INDEO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_SCREEN INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_FLIC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MSVIDEO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_V210_V410 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_PRORES INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_DNXHD INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_OTHERVIDEO INTERNAL_FILTERS_LAV - - -// Groups -#define HAS_SOURCEFILTERS (INTERNAL_FILTERS_LAV || INTERNAL_FILTERS_OTHER) - -#define HAS_AUDIO_DECODERS INTERNAL_FILTERS_LAV - -#define HAS_VIDEO_DECODERS INTERNAL_FILTERS_LAV +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +// For configuring which internal filters are included into the build. + +#pragma once + +#if defined(MPCHC_LITE) +#define INTERNAL_FILTERS_OTHER 0 +#else +#define INTERNAL_FILTERS_OTHER 1 +#endif +#define INTERNAL_FILTERS_LAV USE_LAVFILTERS + +// Internal source filters +#define INTERNAL_SOURCEFILTER_AC3 INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_ASF INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_AVI INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_AVS INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_DTS INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_FLAC INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_FLIC INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_FLV INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_GIF INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_HTTP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MATROSKA INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MISC INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MMS INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MP4 INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MPEG INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MPEGAUDIO INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_OGG INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_REALMEDIA INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_RTMP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_RTP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_RTSP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_UDP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_WTV INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_CDDA INTERNAL_FILTERS_OTHER +#define INTERNAL_SOURCEFILTER_CDXA INTERNAL_FILTERS_OTHER +#define INTERNAL_SOURCEFILTER_DSM INTERNAL_FILTERS_OTHER +#define INTERNAL_SOURCEFILTER_RFS INTERNAL_FILTERS_OTHER +#define INTERNAL_SOURCEFILTER_VTS INTERNAL_FILTERS_OTHER + +// Internal audio decoders +#define INTERNAL_DECODER_LPCM INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_PS2AUDIO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_REALAUDIO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_PCM INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AC3 INTERNAL_FILTERS_LAV /* also E-AC3, TrueHD, MLP */ +#define INTERNAL_DECODER_DTS INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AAC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_ALAC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_ALS INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MPEGAUDIO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VORBIS INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_NELLYMOSER INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AMR INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_ADPCM INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_FLAC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_OPUS INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_WMA INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_WMAPRO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_WMALL INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_G726 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_G729 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_OTHERAUDIO INTERNAL_FILTERS_LAV + +// Internal video decoders +#define INTERNAL_DECODER_MPEG1 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MPEG2 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_REALVIDEO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_H264 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_HEVC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VVC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AV1 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VC1 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_FLV INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VP356 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_DIVX INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_XVID INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_WMV INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MSMPEG4 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_SVQ INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_H263 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_THEORA INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AMVV INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VP8 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VP9 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MJPEG INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_INDEO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_SCREEN INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_FLIC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MSVIDEO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_V210_V410 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_PRORES INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_DNXHD INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_OTHERVIDEO INTERNAL_FILTERS_LAV + + +// Groups +#define HAS_SOURCEFILTERS (INTERNAL_FILTERS_LAV || INTERNAL_FILTERS_OTHER) + +#define HAS_AUDIO_DECODERS INTERNAL_FILTERS_LAV + +#define HAS_VIDEO_DECODERS INTERNAL_FILTERS_LAV diff --git a/src/mpc-hc/KeyProvider.cpp b/src/mpc-hc/KeyProvider.cpp index 3031fbe1bfc..b40246cf675 100644 --- a/src/mpc-hc/KeyProvider.cpp +++ b/src/mpc-hc/KeyProvider.cpp @@ -1,57 +1,57 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "KeyProvider.h" -#include "DSUtil.h" - - -CKeyProvider::CKeyProvider() - : CUnknown(NAME("CKeyProvider"), nullptr) -{ -} - -CKeyProvider::~CKeyProvider() -{ -} - -STDMETHODIMP CKeyProvider::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IServiceProvider) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CKeyProvider::QueryService(REFIID siid, REFIID riid, void** ppv) -{ - /* - if (siid == __uuidof(IWMReader) && riid == IID_IUnknown) - { - CComPtr punkCert; - HRESULT hr = WMCreateCertificate(&punkCert); - if (SUCCEEDED(hr)) - *ppv = (void*)punkCert.Detach(); - return hr; - } - */ - - return E_NOINTERFACE; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "KeyProvider.h" +#include "DSUtil.h" + + +CKeyProvider::CKeyProvider() + : CUnknown(NAME("CKeyProvider"), nullptr) +{ +} + +CKeyProvider::~CKeyProvider() +{ +} + +STDMETHODIMP CKeyProvider::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IServiceProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CKeyProvider::QueryService(REFIID siid, REFIID riid, void** ppv) +{ + /* + if (siid == __uuidof(IWMReader) && riid == IID_IUnknown) + { + CComPtr punkCert; + HRESULT hr = WMCreateCertificate(&punkCert); + if (SUCCEEDED(hr)) + *ppv = (void*)punkCert.Detach(); + return hr; + } + */ + + return E_NOINTERFACE; +} diff --git a/src/mpc-hc/KeyProvider.h b/src/mpc-hc/KeyProvider.h index 38fd82c43c5..7217b3f85e1 100644 --- a/src/mpc-hc/KeyProvider.h +++ b/src/mpc-hc/KeyProvider.h @@ -1,42 +1,42 @@ -/* - * (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 . - * - */ - -#pragma once - -#include - - -// Declare and implement a key provider class derived from IServiceProvider. - -class CKeyProvider - : public CUnknown - , public IServiceProvider -{ -public: - CKeyProvider(); - ~CKeyProvider(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IServiceProvider - STDMETHODIMP QueryService(REFIID siid, REFIID riid, void** ppv); -}; +/* + * (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 . + * + */ + +#pragma once + +#include + + +// Declare and implement a key provider class derived from IServiceProvider. + +class CKeyProvider + : public CUnknown + , public IServiceProvider +{ +public: + CKeyProvider(); + ~CKeyProvider(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IServiceProvider + STDMETHODIMP QueryService(REFIID siid, REFIID riid, void** ppv); +}; diff --git a/src/mpc-hc/LcdSupport.cpp b/src/mpc-hc/LcdSupport.cpp index 445a90c92cb..e74ffdb704c 100644 --- a/src/mpc-hc/LcdSupport.cpp +++ b/src/mpc-hc/LcdSupport.cpp @@ -1,761 +1,761 @@ -/* - * (C) 2006-2013, 2015 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include -#include // _beginthread, _endthread -#include -#include - -#include "LcdSupport.h" -#include "LCDUI/LCDUI.h" - -#include "mplayerc.h" - -#define LCD_APP_NAME "MPC-HC" -#define LCD_UPD_TIMER 40 - - -void LCD_UpdateThread(void* Control) -{ - CMPC_Lcd* ctrl = static_cast(Control); - wchar_t str[40]; - __time64_t ltime; - __time64_t otime = 0; - struct tm thetime; - _locale_t locale = _create_locale(LC_TIME, ""); - - while (ctrl->Thread_Loop) { - EnterCriticalSection(&ctrl->cs); - if (_time64(<ime) != otime) { // Retrieve the time - otime = ltime; - _localtime64_s(&thetime, <ime); - - // Format the current time structure into a string - // using %#x is the long date representation, - // appropriate to the current locale - if (_wcsftime_l(str, _countof(str), _T("%F"), (const struct tm*)&thetime, locale) && - (ltime > ctrl->nThread_tTimeout || ltime < otime)) { // message displayed, no update until timeout - ctrl->m_MonoPage.m_Text[0].SetText(str); - ctrl->m_ColorPage.m_Text[0].SetText(str); - } - - if (_wcsftime_l(str, _countof(str), _T("%X"), (const struct tm*)&thetime, locale)) { - ctrl->m_MonoPage.m_Text[1].SetText(str); - ctrl->m_ColorPage.m_Text[1].SetText(str); - } - } - ctrl->m_Connection.Update(); - LeaveCriticalSection(&ctrl->cs); - Sleep(LCD_UPD_TIMER); - } - - _free_locale(locale); - _endthread(); -} - -/****************************************************************************************************** - ****************************************** CLCDMyProgressBar ****************************************/ - -void CLCDMyProgressBar::OnDraw(CLCDGfxBase& rGfx) -{ - // draw the border - RECT r = { 0, 0, GetWidth(), GetHeight() }; - - FrameRect(rGfx.GetHDC(), &r, m_hBrush); - - // draw the progress - switch (m_eMyStyle) { - case STYLE_CURSOR: { - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)1, (float)(GetWidth() - m_nCursorWidth - 1), - m_fPos); - r.left = nCursorPos; - r.right = r.left + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - } - break; - case STYLE_FILLED_H: - case STYLE_FILLED_V: { - int nBar = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - 0.0f, (m_eMyStyle == STYLE_FILLED_H ? (float)GetWidth() : (float)GetHeight()) - 4, - m_fPos); - r.left = r.left + 2; - r.bottom = r.bottom - 2; - if (m_eMyStyle == STYLE_FILLED_H) { - r.right = nBar + 2; - r.top = r.top + 2; - } else { - r.right = r.right - 2; - r.top = r.bottom - nBar; - } - - FillRect(rGfx.GetHDC(), &r, m_hBrush); - } - break; - case STYLE_DASHED_CURSOR: { - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)1, (float)(GetWidth() - m_nCursorWidth - 1), - m_fPos); - r.left = nCursorPos; - r.right = r.left + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), m_hPen); - - ::MoveToEx(rGfx.GetHDC(), 0, (r.bottom - r.top) / 2, nullptr); - ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top) / 2); - ::SelectObject(rGfx.GetHDC(), hOldPen); - } - break; - default: - break; - } -} - -void CLCDMyProgressBar::SetProgressStyle(ePROGRESS_STYLE eStyle) -{ - m_eStyle = eStyle; - - //Convert and update the new Style type - switch (eStyle) { - case CLCDProgressBar::STYLE_CURSOR: - m_eMyStyle = STYLE_CURSOR; - break; - case CLCDProgressBar::STYLE_FILLED: - m_eMyStyle = STYLE_FILLED_H; - break; - case CLCDProgressBar::STYLE_DASHED_CURSOR: - m_eMyStyle = STYLE_DASHED_CURSOR; - break; - default: - break; - } -} - -void CLCDMyProgressBar::SetProgressStyle(eMY_PROGRESS_STYLE eMyStyle) -{ - m_eMyStyle = eMyStyle; - - //Convert and update the old Style type - switch (eMyStyle) { - case STYLE_CURSOR: - m_eStyle = CLCDProgressBar::STYLE_CURSOR; - break; - case STYLE_FILLED_V: - case STYLE_FILLED_H: - m_eStyle = CLCDProgressBar::STYLE_FILLED; - break; - case STYLE_DASHED_CURSOR: - m_eStyle = CLCDProgressBar::STYLE_DASHED_CURSOR; - break; - default: - break; - } -} - -/****************************************************************************************************** - ****************************************** CLCDMyMonoPage ****************************************/ -CLCDMyMonoPage::CLCDMyMonoPage() -{ - Initialize(); -} - -CLCDMyMonoPage::~CLCDMyMonoPage() -{ - DeleteObject(hBmp[PS_PLAY]); - DeleteObject(hBmp[PS_PAUSE]); - DeleteObject(hBmp[PS_STOP]); -} - -HRESULT CLCDMyMonoPage::Initialize() -{ - LOGFONT lf; - HFONT hFont; - unsigned int x, y; - - // max dimensions: 160 x 43 - x = 10; - y = 0; - - BYTE bPause[] = {0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF - }; - - BYTE bStop[] = {0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00 - }; - - BYTE bPlay[] = {0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F - }; - - hBmp[PS_PLAY] = CreateBitmap(56, 7, 1, 1, bPlay); - hBmp[PS_PAUSE] = CreateBitmap(14, 7, 1, 1, bPause); - hBmp[PS_STOP] = CreateBitmap(8, 7, 1, 1, bStop); - - // Initialize the text control (media) - m_Text1.Initialize(); - m_Text1.SetOrigin(x, y); - m_Text1.SetSize(160 - x, 13); - m_Text1.SetAlignment(DT_CENTER); - m_Text1.SetWordWrap(false); - m_Text1.SetText(_T("")); - m_Text1.SetStartDelay(5000); - m_Text1.SetEndDelay(2000); - m_Text1.EnableRepeat(true); - m_Text1.SetScrollDirection(SCROLL_HORZ); - m_Text1.SetSpeed(24); - - // Initialize the progressbar control (media progress) - y += 15; - m_ProgBar[1].Initialize(); - m_ProgBar[1].SetOrigin(x + 10, y); - m_ProgBar[1].SetSize(160 - x - 10, 7); - m_ProgBar[1].SetPos(0); - m_ProgBar[1].SetRange(0, 100); - m_ProgBar[1].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_H); - - // gfx - m_PlayState.Initialize(); - m_PlayState.SetOrigin(x, y); - m_PlayState.SetSize(7, 7); - m_PlayState.SetBitmap(hBmp[PS_PLAY]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(300); - m_PlayState.SetAlpha(false); - m_PlayState.SetZoomLevel(1); - - // Initialize the text control (time / mpc messages) - y += 6; - m_Text[0].Initialize(); - m_Text[0].SetOrigin(x, y); - m_Text[0].SetSize(160 - x, /*13*/25); - m_Text[0].SetAlignment(DT_CENTER); - m_Text[0].SetWordWrap(false); - m_Text[0].SetText(_T("")); - m_Text[0].SetFontPointSize(7); - hFont = m_Text[0].GetFont(); - GetObject(hFont, sizeof(LOGFONT), &lf); - wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); - m_Text[0].SetFont(lf); - - y += 10; - m_Text[1].Initialize(); - m_Text[1].SetOrigin(x, y); - m_Text[1].SetSize(160 - x, /*13*/25); - m_Text[1].SetAlignment(DT_CENTER); - m_Text[1].SetWordWrap(false); - m_Text[1].SetText(_T("")); - m_Text[1].SetFontPointSize(7); - hFont = m_Text[1].GetFont(); - GetObject(hFont, sizeof(LOGFONT), &lf); - wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); - m_Text[1].SetFont(lf); - - // Initialize the progressbar control (volume) - m_ProgBar[0].Initialize(); - m_ProgBar[0].SetOrigin(0, 0); - m_ProgBar[0].SetSize(7, 43); - m_ProgBar[0].SetPos(0); - m_ProgBar[0].SetRange(0, 100); - m_ProgBar[0].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_V); - - AddObject(&m_Text1); - AddObject(&m_Text[0]); - AddObject(&m_Text[1]); - AddObject(&m_ProgBar[0]); - AddObject(&m_ProgBar[1]); - AddObject(&m_PlayState); - - return CLCDPage::Initialize(); -} - -void CLCDMyMonoPage::OnLCDButtonUp(int nButton) -{ - switch (nButton) { - case LGLCDBUTTON_BUTTON0: { - /*LOGFONT lf; - HFONT hFont = m_Text1.GetFont(); - - GetObject(hFont, sizeof(LOGFONT), &lf); - - CFontDialog cfd(&lf); - if (cfd.DoModal() == IDOK) - { - cfd.GetCurrentFont(&lf); - m_Text1.SetFont(lf); - }*/ - break; - } - case LGLCDBUTTON_BUTTON1: - break; - case LGLCDBUTTON_BUTTON2: - break; - case LGLCDBUTTON_BUTTON3: - break; - default: - break; - } -} - -/* update play state bitmap */ -void CLCDMyMonoPage::SetPlayState(PlayState ps) -{ - switch (ps) { - case PS_PLAY: - m_PlayState.SetBitmap(hBmp[PS_PLAY]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(300); - break; - - case PS_PAUSE: - m_PlayState.SetBitmap(hBmp[PS_PAUSE]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(800); - break; - - case PS_STOP: - m_ProgBar[1].SetPos(0); - m_PlayState.SetBitmap(hBmp[PS_STOP]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(5000); // dummy, only one picture - break; - - default: - break; - } -} - -/****************************************************************************************************** - ****************************************** CLCDMyColorPage ****************************************/ -CLCDMyColorPage::CLCDMyColorPage() -{ - Initialize(); -} - -CLCDMyColorPage::~CLCDMyColorPage() -{ - DeleteObject(hBmp[PS_PLAY]); - DeleteObject(hBmp[PS_PAUSE]); - DeleteObject(hBmp[PS_STOP]); -} - -HRESULT CLCDMyColorPage::Initialize() -{ - LOGFONT lf; - HFONT hFont; - unsigned int x, y; - - // max dimensions: 320 x 240 - x = 20; - y = 0; - - BYTE bPause[] = {0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF - }; - - BYTE bStop[] = {0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00 - }; - - BYTE bPlay[] = {0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F - }; - - hBmp[PS_PLAY] = CreateBitmap(56, 7, 1, 1, bPlay); - hBmp[PS_PAUSE] = CreateBitmap(14, 7, 1, 1, bPause); - hBmp[PS_STOP] = CreateBitmap(8, 7, 1, 1, bStop); - - - // Initialize the text control (media) - m_Text1.Initialize(); - m_Text1.SetOrigin(x, y); - m_Text1.SetSize(320 - x, 26); - m_Text1.SetAlignment(DT_CENTER | DT_VCENTER); - m_Text1.SetWordWrap(false); - m_Text1.SetText(_T("")); - m_Text1.SetFontPointSize(16); - m_Text1.SetStartDelay(5000); - m_Text1.SetEndDelay(2000); - m_Text1.EnableRepeat(true); - m_Text1.SetScrollDirection(SCROLL_HORZ); - m_Text1.SetSpeed(24); - - // Initialize the progressbar control (media progress) - y += 30; - m_ProgBar[1].Initialize(); - m_ProgBar[1].SetOrigin(x + 20, y); - m_ProgBar[1].SetSize(320 - x - 20, 14); - m_ProgBar[1].SetPos(0); - m_ProgBar[1].SetRange(0, 100); - m_ProgBar[1].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_H); - - // gfx - m_PlayState.Initialize(); - m_PlayState.SetOrigin(x, y); - m_PlayState.SetSize(14, 14); - m_PlayState.SetBitmap(hBmp[PS_PLAY]); - m_PlayState.ResetUpdate(); - m_PlayState.SetZoomLevel(2); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(300); - m_PlayState.SetAlpha(false); - m_PlayState.GetSize(); - - // Initialize the text control (time / mpc messages) - y += 14; - m_Text[0].Initialize(); - m_Text[0].SetOrigin(x, y); - m_Text[0].SetSize(320 - x, /*13*/50); - m_Text[0].SetAlignment(DT_CENTER); - m_Text[0].SetWordWrap(false); - m_Text[0].SetText(_T("")); - m_Text[0].SetFontPointSize(14); - hFont = m_Text[0].GetFont(); - GetObject(hFont, sizeof(LOGFONT), &lf); - wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); - m_Text[0].SetFont(lf); - - y += 22; - m_Text[1].Initialize(); - m_Text[1].SetOrigin(x, y); - m_Text[1].SetSize(320 - x, /*13*/50); - m_Text[1].SetAlignment(DT_CENTER); - m_Text[1].SetWordWrap(false); - m_Text[1].SetText(_T("")); - m_Text[1].SetFontPointSize(14); - hFont = m_Text[1].GetFont(); - GetObject(hFont, sizeof(LOGFONT), &lf); - wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); - m_Text[1].SetFont(lf); - - // Initialize the progressbar control (volume) - m_ProgBar[0].Initialize(); - m_ProgBar[0].SetOrigin(0, 0); - m_ProgBar[0].SetSize(14, 86); - m_ProgBar[0].SetPos(0); - m_ProgBar[0].SetRange(0, 100); - m_ProgBar[0].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_V); - - AddObject(&m_Text1); - AddObject(&m_Text[0]); - AddObject(&m_Text[1]); - AddObject(&m_ProgBar[0]); - AddObject(&m_ProgBar[1]); - AddObject(&m_PlayState); - - return CLCDPage::Initialize(); -} - -void CLCDMyColorPage::OnLCDButtonUp(int nButton) -{ - switch (nButton) { - case LGLCDBUTTON_BUTTON0: { - /*LOGFONT lf; - HFONT hFont = m_Text1.GetFont(); - - GetObject(hFont, sizeof(LOGFONT), &lf); - - CFontDialog cfd(&lf); - if (cfd.DoModal() == IDOK) - { - cfd.GetCurrentFont(&lf); - m_Text1.SetFont(lf); - }*/ - break; - } - case LGLCDBUTTON_BUTTON1: - break; - case LGLCDBUTTON_BUTTON2: - break; - case LGLCDBUTTON_BUTTON3: - break; - default: - break; - } -} - -/* update play state bitmap */ -void CLCDMyColorPage::SetPlayState(PlayState ps) -{ - switch (ps) { - case PS_PLAY: - m_PlayState.SetBitmap(hBmp[PS_PLAY]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(300); - break; - - case PS_PAUSE: - m_PlayState.SetBitmap(hBmp[PS_PAUSE]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(800); - break; - - case PS_STOP: - m_ProgBar[1].SetPos(0); - m_PlayState.SetBitmap(hBmp[PS_STOP]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(5000); // dummy, only one picture - break; - - default: - break; - } -} - -/****************************************************************************************************** - ********************************************** CMPC_Lcd *********************************************/ - -/* attach to an available lcd */ -CMPC_Lcd::CMPC_Lcd() - : hLCD_UpdateThread(nullptr) - , m_nMediaStart(0) - , m_nMediaStop(0) - , m_nVolumeStart(0) - , m_nVolumeStop(100) - , m_MonoOutput(nullptr) - , m_ColorOutput(nullptr) - , Thread_Loop(false) - , nThread_tTimeout(0) -{ - InitializeCriticalSection(&cs); - - // lcd init - ZeroMemory(&m_ConnCtx, sizeof(m_ConnCtx)); - - m_ConnCtx.appFriendlyName = _T(LCD_APP_NAME); - m_ConnCtx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BW | LGLCD_APPLET_CAP_QVGA; - m_ConnCtx.isAutostartable = FALSE; - m_ConnCtx.isPersistent = FALSE; - m_ConnCtx.onConfigure.configCallback = nullptr; // we don't have a configuration screen - m_ConnCtx.onConfigure.configContext = nullptr; - m_ConnCtx.onNotify.notificationCallback = nullptr; - m_ConnCtx.onNotify.notifyContext = nullptr; - m_ConnCtx.connection = LGLCD_INVALID_CONNECTION; // the "connection" member will be returned upon return - - const CAppSettings& s = AfxGetAppSettings(); - if (!s.fLCDSupport) { - return; - } - - if (FALSE == m_Connection.Initialize(m_ConnCtx)) { - //_tperror(_T("Initialize")); - return; - } - - m_MonoOutput = m_Connection.MonoOutput(); - m_MonoOutput->ShowPage(&m_MonoPage); - - m_ColorOutput = m_Connection.ColorOutput(); - m_ColorOutput->ShowPage(&m_ColorPage); - - SetAsForeground(TRUE); - - m_Connection.Update(); - - if (m_Connection.IsConnected()) { - Thread_Loop = true; - SetPlayState(PS_STOP); - hLCD_UpdateThread = (HANDLE) _beginthread(LCD_UpdateThread, 512 /* stack */, (void*) this /* arg */); - } -} - -/* detach from lcd */ -CMPC_Lcd::~CMPC_Lcd() -{ - if (m_Connection.IsConnected()) { - Thread_Loop = false; - WaitForSingleObject(hLCD_UpdateThread, LCD_UPD_TIMER * 2 /* timeout */); - hLCD_UpdateThread = nullptr; - } - - DeleteCriticalSection(&cs); - - m_Connection.Shutdown(); -} - -/* update title name */ -void CMPC_Lcd::SetMediaTitle(const TCHAR* text) -{ - EnterCriticalSection(&cs); - m_MonoPage.m_Text1.SetText(text); - m_MonoPage.m_ProgBar[1].SetPos(0); - m_ColorPage.m_Text1.SetText(text); - m_ColorPage.m_ProgBar[1].SetPos(0); - LeaveCriticalSection(&cs); -} - -/* set volume min/max */ -void CMPC_Lcd::SetVolumeRange(__int64 nStart, __int64 nStop) -{ - //handle 64bit integers LCDUI only supports int for Range - //Since it also supports floats for position, - //This will always work in percentage - m_nVolumeStart = nStart; - m_nVolumeStop = nStop; -} - -/* update volume */ -void CMPC_Lcd::SetVolume(__int64 nVol) -{ - //handle 64bit integers LCDUI only supports int for Range - //Since it also supports floats for position, - //This will always work in percentage - float fVol; - if (m_nVolumeStart != m_nVolumeStop) { - fVol = float(nVol - m_nVolumeStart) * 100.0f / float(m_nVolumeStop - m_nVolumeStart); - } else { - fVol = 0.0f; - ASSERT(FALSE); // This isn't supposed to happen - } - - EnterCriticalSection(&cs); - m_MonoPage.m_ProgBar[0].SetPos(fVol); - m_ColorPage.m_ProgBar[0].SetPos(fVol); - LeaveCriticalSection(&cs); -} - -/* set media min/max */ -void CMPC_Lcd::SetMediaRange(__int64 nStart, __int64 nStop) -{ - //handle 64bit integers LCDUI only supports int for Range - //Since it also supports floats for position, - //This will always work in percentage - m_nMediaStart = nStart; - m_nMediaStop = nStop; -} - -/* update media position */ -void CMPC_Lcd::SetMediaPos(__int64 nPos) -{ - //handle 64bit integers LCDUI only supports int for Range - //Since it also supports floats for position, - //This will always work in percentage - float fPos; - if (m_nMediaStart != m_nMediaStop) { - fPos = float(nPos - m_nMediaStart) * 100.0f / float(m_nMediaStop - m_nMediaStart); - } else { // The duration might be unknown - fPos = 0.0f; - } - - EnterCriticalSection(&cs); - m_MonoPage.m_ProgBar[1].SetPos(fPos); - m_ColorPage.m_ProgBar[1].SetPos(fPos); - LeaveCriticalSection(&cs); -} - -/* update status message (displayed for nTimeOut milliseconds) */ -void CMPC_Lcd::SetStatusMessage(const TCHAR* text, int nTimeOut) -{ - if (!m_Connection.IsConnected()) { - return; - } - - __time64_t ltime; - _time64(<ime); - if ((nTimeOut /= 1000) < 1) { - nTimeOut = 1; - } - - EnterCriticalSection(&cs); - nThread_tTimeout = ltime + nTimeOut; - m_MonoPage.m_Text[0].SetText(text); - m_ColorPage.m_Text[0].SetText(text); - LeaveCriticalSection(&cs); -} - -/* update play state bitmap */ -void CMPC_Lcd::SetPlayState(CMPC_Lcd::PlayState ps) -{ - if (!m_Connection.IsConnected()) { - return; - } - - EnterCriticalSection(&cs); - switch (ps) { - case PS_PLAY: - SetAsForeground(true); - break; - case PS_PAUSE: - break; - case PS_STOP: - SetAsForeground(false); - break; - default: - break; - } - - m_MonoPage.SetPlayState((CLCDMyMonoPage::PlayState)ps); - m_ColorPage.SetPlayState((CLCDMyColorPage::PlayState)ps); - - LeaveCriticalSection(&cs); -} - -HRESULT CMPC_Lcd::SetAsForeground(BOOL setAsForeground) -{ - if (nullptr != m_Connection.MonoOutput()) { - m_Connection.MonoOutput()->SetAsForeground(setAsForeground); - } - - if (nullptr != m_Connection.ColorOutput()) { - m_Connection.ColorOutput()->SetAsForeground(setAsForeground); - } - - return S_OK; -} +/* + * (C) 2006-2013, 2015 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include +#include // _beginthread, _endthread +#include +#include + +#include "LcdSupport.h" +#include "LCDUI/LCDUI.h" + +#include "mplayerc.h" + +#define LCD_APP_NAME "MPC-HC" +#define LCD_UPD_TIMER 40 + + +void LCD_UpdateThread(void* Control) +{ + CMPC_Lcd* ctrl = static_cast(Control); + wchar_t str[40]; + __time64_t ltime; + __time64_t otime = 0; + struct tm thetime; + _locale_t locale = _create_locale(LC_TIME, ""); + + while (ctrl->Thread_Loop) { + EnterCriticalSection(&ctrl->cs); + if (_time64(<ime) != otime) { // Retrieve the time + otime = ltime; + _localtime64_s(&thetime, <ime); + + // Format the current time structure into a string + // using %#x is the long date representation, + // appropriate to the current locale + if (_wcsftime_l(str, _countof(str), _T("%F"), (const struct tm*)&thetime, locale) && + (ltime > ctrl->nThread_tTimeout || ltime < otime)) { // message displayed, no update until timeout + ctrl->m_MonoPage.m_Text[0].SetText(str); + ctrl->m_ColorPage.m_Text[0].SetText(str); + } + + if (_wcsftime_l(str, _countof(str), _T("%X"), (const struct tm*)&thetime, locale)) { + ctrl->m_MonoPage.m_Text[1].SetText(str); + ctrl->m_ColorPage.m_Text[1].SetText(str); + } + } + ctrl->m_Connection.Update(); + LeaveCriticalSection(&ctrl->cs); + Sleep(LCD_UPD_TIMER); + } + + _free_locale(locale); + _endthread(); +} + +/****************************************************************************************************** + ****************************************** CLCDMyProgressBar ****************************************/ + +void CLCDMyProgressBar::OnDraw(CLCDGfxBase& rGfx) +{ + // draw the border + RECT r = { 0, 0, GetWidth(), GetHeight() }; + + FrameRect(rGfx.GetHDC(), &r, m_hBrush); + + // draw the progress + switch (m_eMyStyle) { + case STYLE_CURSOR: { + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)1, (float)(GetWidth() - m_nCursorWidth - 1), + m_fPos); + r.left = nCursorPos; + r.right = r.left + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + } + break; + case STYLE_FILLED_H: + case STYLE_FILLED_V: { + int nBar = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + 0.0f, (m_eMyStyle == STYLE_FILLED_H ? (float)GetWidth() : (float)GetHeight()) - 4, + m_fPos); + r.left = r.left + 2; + r.bottom = r.bottom - 2; + if (m_eMyStyle == STYLE_FILLED_H) { + r.right = nBar + 2; + r.top = r.top + 2; + } else { + r.right = r.right - 2; + r.top = r.bottom - nBar; + } + + FillRect(rGfx.GetHDC(), &r, m_hBrush); + } + break; + case STYLE_DASHED_CURSOR: { + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)1, (float)(GetWidth() - m_nCursorWidth - 1), + m_fPos); + r.left = nCursorPos; + r.right = r.left + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), m_hPen); + + ::MoveToEx(rGfx.GetHDC(), 0, (r.bottom - r.top) / 2, nullptr); + ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top) / 2); + ::SelectObject(rGfx.GetHDC(), hOldPen); + } + break; + default: + break; + } +} + +void CLCDMyProgressBar::SetProgressStyle(ePROGRESS_STYLE eStyle) +{ + m_eStyle = eStyle; + + //Convert and update the new Style type + switch (eStyle) { + case CLCDProgressBar::STYLE_CURSOR: + m_eMyStyle = STYLE_CURSOR; + break; + case CLCDProgressBar::STYLE_FILLED: + m_eMyStyle = STYLE_FILLED_H; + break; + case CLCDProgressBar::STYLE_DASHED_CURSOR: + m_eMyStyle = STYLE_DASHED_CURSOR; + break; + default: + break; + } +} + +void CLCDMyProgressBar::SetProgressStyle(eMY_PROGRESS_STYLE eMyStyle) +{ + m_eMyStyle = eMyStyle; + + //Convert and update the old Style type + switch (eMyStyle) { + case STYLE_CURSOR: + m_eStyle = CLCDProgressBar::STYLE_CURSOR; + break; + case STYLE_FILLED_V: + case STYLE_FILLED_H: + m_eStyle = CLCDProgressBar::STYLE_FILLED; + break; + case STYLE_DASHED_CURSOR: + m_eStyle = CLCDProgressBar::STYLE_DASHED_CURSOR; + break; + default: + break; + } +} + +/****************************************************************************************************** + ****************************************** CLCDMyMonoPage ****************************************/ +CLCDMyMonoPage::CLCDMyMonoPage() +{ + Initialize(); +} + +CLCDMyMonoPage::~CLCDMyMonoPage() +{ + DeleteObject(hBmp[PS_PLAY]); + DeleteObject(hBmp[PS_PAUSE]); + DeleteObject(hBmp[PS_STOP]); +} + +HRESULT CLCDMyMonoPage::Initialize() +{ + LOGFONT lf; + HFONT hFont; + unsigned int x, y; + + // max dimensions: 160 x 43 + x = 10; + y = 0; + + BYTE bPause[] = {0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF + }; + + BYTE bStop[] = {0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 + }; + + BYTE bPlay[] = {0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F + }; + + hBmp[PS_PLAY] = CreateBitmap(56, 7, 1, 1, bPlay); + hBmp[PS_PAUSE] = CreateBitmap(14, 7, 1, 1, bPause); + hBmp[PS_STOP] = CreateBitmap(8, 7, 1, 1, bStop); + + // Initialize the text control (media) + m_Text1.Initialize(); + m_Text1.SetOrigin(x, y); + m_Text1.SetSize(160 - x, 13); + m_Text1.SetAlignment(DT_CENTER); + m_Text1.SetWordWrap(false); + m_Text1.SetText(_T("")); + m_Text1.SetStartDelay(5000); + m_Text1.SetEndDelay(2000); + m_Text1.EnableRepeat(true); + m_Text1.SetScrollDirection(SCROLL_HORZ); + m_Text1.SetSpeed(24); + + // Initialize the progressbar control (media progress) + y += 15; + m_ProgBar[1].Initialize(); + m_ProgBar[1].SetOrigin(x + 10, y); + m_ProgBar[1].SetSize(160 - x - 10, 7); + m_ProgBar[1].SetPos(0); + m_ProgBar[1].SetRange(0, 100); + m_ProgBar[1].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_H); + + // gfx + m_PlayState.Initialize(); + m_PlayState.SetOrigin(x, y); + m_PlayState.SetSize(7, 7); + m_PlayState.SetBitmap(hBmp[PS_PLAY]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(300); + m_PlayState.SetAlpha(false); + m_PlayState.SetZoomLevel(1); + + // Initialize the text control (time / mpc messages) + y += 6; + m_Text[0].Initialize(); + m_Text[0].SetOrigin(x, y); + m_Text[0].SetSize(160 - x, /*13*/25); + m_Text[0].SetAlignment(DT_CENTER); + m_Text[0].SetWordWrap(false); + m_Text[0].SetText(_T("")); + m_Text[0].SetFontPointSize(7); + hFont = m_Text[0].GetFont(); + GetObject(hFont, sizeof(LOGFONT), &lf); + wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); + m_Text[0].SetFont(lf); + + y += 10; + m_Text[1].Initialize(); + m_Text[1].SetOrigin(x, y); + m_Text[1].SetSize(160 - x, /*13*/25); + m_Text[1].SetAlignment(DT_CENTER); + m_Text[1].SetWordWrap(false); + m_Text[1].SetText(_T("")); + m_Text[1].SetFontPointSize(7); + hFont = m_Text[1].GetFont(); + GetObject(hFont, sizeof(LOGFONT), &lf); + wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); + m_Text[1].SetFont(lf); + + // Initialize the progressbar control (volume) + m_ProgBar[0].Initialize(); + m_ProgBar[0].SetOrigin(0, 0); + m_ProgBar[0].SetSize(7, 43); + m_ProgBar[0].SetPos(0); + m_ProgBar[0].SetRange(0, 100); + m_ProgBar[0].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_V); + + AddObject(&m_Text1); + AddObject(&m_Text[0]); + AddObject(&m_Text[1]); + AddObject(&m_ProgBar[0]); + AddObject(&m_ProgBar[1]); + AddObject(&m_PlayState); + + return CLCDPage::Initialize(); +} + +void CLCDMyMonoPage::OnLCDButtonUp(int nButton) +{ + switch (nButton) { + case LGLCDBUTTON_BUTTON0: { + /*LOGFONT lf; + HFONT hFont = m_Text1.GetFont(); + + GetObject(hFont, sizeof(LOGFONT), &lf); + + CFontDialog cfd(&lf); + if (cfd.DoModal() == IDOK) + { + cfd.GetCurrentFont(&lf); + m_Text1.SetFont(lf); + }*/ + break; + } + case LGLCDBUTTON_BUTTON1: + break; + case LGLCDBUTTON_BUTTON2: + break; + case LGLCDBUTTON_BUTTON3: + break; + default: + break; + } +} + +/* update play state bitmap */ +void CLCDMyMonoPage::SetPlayState(PlayState ps) +{ + switch (ps) { + case PS_PLAY: + m_PlayState.SetBitmap(hBmp[PS_PLAY]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(300); + break; + + case PS_PAUSE: + m_PlayState.SetBitmap(hBmp[PS_PAUSE]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(800); + break; + + case PS_STOP: + m_ProgBar[1].SetPos(0); + m_PlayState.SetBitmap(hBmp[PS_STOP]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(5000); // dummy, only one picture + break; + + default: + break; + } +} + +/****************************************************************************************************** + ****************************************** CLCDMyColorPage ****************************************/ +CLCDMyColorPage::CLCDMyColorPage() +{ + Initialize(); +} + +CLCDMyColorPage::~CLCDMyColorPage() +{ + DeleteObject(hBmp[PS_PLAY]); + DeleteObject(hBmp[PS_PAUSE]); + DeleteObject(hBmp[PS_STOP]); +} + +HRESULT CLCDMyColorPage::Initialize() +{ + LOGFONT lf; + HFONT hFont; + unsigned int x, y; + + // max dimensions: 320 x 240 + x = 20; + y = 0; + + BYTE bPause[] = {0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF + }; + + BYTE bStop[] = {0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 + }; + + BYTE bPlay[] = {0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F + }; + + hBmp[PS_PLAY] = CreateBitmap(56, 7, 1, 1, bPlay); + hBmp[PS_PAUSE] = CreateBitmap(14, 7, 1, 1, bPause); + hBmp[PS_STOP] = CreateBitmap(8, 7, 1, 1, bStop); + + + // Initialize the text control (media) + m_Text1.Initialize(); + m_Text1.SetOrigin(x, y); + m_Text1.SetSize(320 - x, 26); + m_Text1.SetAlignment(DT_CENTER | DT_VCENTER); + m_Text1.SetWordWrap(false); + m_Text1.SetText(_T("")); + m_Text1.SetFontPointSize(16); + m_Text1.SetStartDelay(5000); + m_Text1.SetEndDelay(2000); + m_Text1.EnableRepeat(true); + m_Text1.SetScrollDirection(SCROLL_HORZ); + m_Text1.SetSpeed(24); + + // Initialize the progressbar control (media progress) + y += 30; + m_ProgBar[1].Initialize(); + m_ProgBar[1].SetOrigin(x + 20, y); + m_ProgBar[1].SetSize(320 - x - 20, 14); + m_ProgBar[1].SetPos(0); + m_ProgBar[1].SetRange(0, 100); + m_ProgBar[1].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_H); + + // gfx + m_PlayState.Initialize(); + m_PlayState.SetOrigin(x, y); + m_PlayState.SetSize(14, 14); + m_PlayState.SetBitmap(hBmp[PS_PLAY]); + m_PlayState.ResetUpdate(); + m_PlayState.SetZoomLevel(2); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(300); + m_PlayState.SetAlpha(false); + m_PlayState.GetSize(); + + // Initialize the text control (time / mpc messages) + y += 14; + m_Text[0].Initialize(); + m_Text[0].SetOrigin(x, y); + m_Text[0].SetSize(320 - x, /*13*/50); + m_Text[0].SetAlignment(DT_CENTER); + m_Text[0].SetWordWrap(false); + m_Text[0].SetText(_T("")); + m_Text[0].SetFontPointSize(14); + hFont = m_Text[0].GetFont(); + GetObject(hFont, sizeof(LOGFONT), &lf); + wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); + m_Text[0].SetFont(lf); + + y += 22; + m_Text[1].Initialize(); + m_Text[1].SetOrigin(x, y); + m_Text[1].SetSize(320 - x, /*13*/50); + m_Text[1].SetAlignment(DT_CENTER); + m_Text[1].SetWordWrap(false); + m_Text[1].SetText(_T("")); + m_Text[1].SetFontPointSize(14); + hFont = m_Text[1].GetFont(); + GetObject(hFont, sizeof(LOGFONT), &lf); + wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); + m_Text[1].SetFont(lf); + + // Initialize the progressbar control (volume) + m_ProgBar[0].Initialize(); + m_ProgBar[0].SetOrigin(0, 0); + m_ProgBar[0].SetSize(14, 86); + m_ProgBar[0].SetPos(0); + m_ProgBar[0].SetRange(0, 100); + m_ProgBar[0].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_V); + + AddObject(&m_Text1); + AddObject(&m_Text[0]); + AddObject(&m_Text[1]); + AddObject(&m_ProgBar[0]); + AddObject(&m_ProgBar[1]); + AddObject(&m_PlayState); + + return CLCDPage::Initialize(); +} + +void CLCDMyColorPage::OnLCDButtonUp(int nButton) +{ + switch (nButton) { + case LGLCDBUTTON_BUTTON0: { + /*LOGFONT lf; + HFONT hFont = m_Text1.GetFont(); + + GetObject(hFont, sizeof(LOGFONT), &lf); + + CFontDialog cfd(&lf); + if (cfd.DoModal() == IDOK) + { + cfd.GetCurrentFont(&lf); + m_Text1.SetFont(lf); + }*/ + break; + } + case LGLCDBUTTON_BUTTON1: + break; + case LGLCDBUTTON_BUTTON2: + break; + case LGLCDBUTTON_BUTTON3: + break; + default: + break; + } +} + +/* update play state bitmap */ +void CLCDMyColorPage::SetPlayState(PlayState ps) +{ + switch (ps) { + case PS_PLAY: + m_PlayState.SetBitmap(hBmp[PS_PLAY]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(300); + break; + + case PS_PAUSE: + m_PlayState.SetBitmap(hBmp[PS_PAUSE]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(800); + break; + + case PS_STOP: + m_ProgBar[1].SetPos(0); + m_PlayState.SetBitmap(hBmp[PS_STOP]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(5000); // dummy, only one picture + break; + + default: + break; + } +} + +/****************************************************************************************************** + ********************************************** CMPC_Lcd *********************************************/ + +/* attach to an available lcd */ +CMPC_Lcd::CMPC_Lcd() + : hLCD_UpdateThread(nullptr) + , m_nMediaStart(0) + , m_nMediaStop(0) + , m_nVolumeStart(0) + , m_nVolumeStop(100) + , m_MonoOutput(nullptr) + , m_ColorOutput(nullptr) + , Thread_Loop(false) + , nThread_tTimeout(0) +{ + InitializeCriticalSection(&cs); + + // lcd init + ZeroMemory(&m_ConnCtx, sizeof(m_ConnCtx)); + + m_ConnCtx.appFriendlyName = _T(LCD_APP_NAME); + m_ConnCtx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BW | LGLCD_APPLET_CAP_QVGA; + m_ConnCtx.isAutostartable = FALSE; + m_ConnCtx.isPersistent = FALSE; + m_ConnCtx.onConfigure.configCallback = nullptr; // we don't have a configuration screen + m_ConnCtx.onConfigure.configContext = nullptr; + m_ConnCtx.onNotify.notificationCallback = nullptr; + m_ConnCtx.onNotify.notifyContext = nullptr; + m_ConnCtx.connection = LGLCD_INVALID_CONNECTION; // the "connection" member will be returned upon return + + const CAppSettings& s = AfxGetAppSettings(); + if (!s.fLCDSupport) { + return; + } + + if (FALSE == m_Connection.Initialize(m_ConnCtx)) { + //_tperror(_T("Initialize")); + return; + } + + m_MonoOutput = m_Connection.MonoOutput(); + m_MonoOutput->ShowPage(&m_MonoPage); + + m_ColorOutput = m_Connection.ColorOutput(); + m_ColorOutput->ShowPage(&m_ColorPage); + + SetAsForeground(TRUE); + + m_Connection.Update(); + + if (m_Connection.IsConnected()) { + Thread_Loop = true; + SetPlayState(PS_STOP); + hLCD_UpdateThread = (HANDLE) _beginthread(LCD_UpdateThread, 512 /* stack */, (void*) this /* arg */); + } +} + +/* detach from lcd */ +CMPC_Lcd::~CMPC_Lcd() +{ + if (m_Connection.IsConnected()) { + Thread_Loop = false; + WaitForSingleObject(hLCD_UpdateThread, LCD_UPD_TIMER * 2 /* timeout */); + hLCD_UpdateThread = nullptr; + } + + DeleteCriticalSection(&cs); + + m_Connection.Shutdown(); +} + +/* update title name */ +void CMPC_Lcd::SetMediaTitle(const TCHAR* text) +{ + EnterCriticalSection(&cs); + m_MonoPage.m_Text1.SetText(text); + m_MonoPage.m_ProgBar[1].SetPos(0); + m_ColorPage.m_Text1.SetText(text); + m_ColorPage.m_ProgBar[1].SetPos(0); + LeaveCriticalSection(&cs); +} + +/* set volume min/max */ +void CMPC_Lcd::SetVolumeRange(__int64 nStart, __int64 nStop) +{ + //handle 64bit integers LCDUI only supports int for Range + //Since it also supports floats for position, + //This will always work in percentage + m_nVolumeStart = nStart; + m_nVolumeStop = nStop; +} + +/* update volume */ +void CMPC_Lcd::SetVolume(__int64 nVol) +{ + //handle 64bit integers LCDUI only supports int for Range + //Since it also supports floats for position, + //This will always work in percentage + float fVol; + if (m_nVolumeStart != m_nVolumeStop) { + fVol = float(nVol - m_nVolumeStart) * 100.0f / float(m_nVolumeStop - m_nVolumeStart); + } else { + fVol = 0.0f; + ASSERT(FALSE); // This isn't supposed to happen + } + + EnterCriticalSection(&cs); + m_MonoPage.m_ProgBar[0].SetPos(fVol); + m_ColorPage.m_ProgBar[0].SetPos(fVol); + LeaveCriticalSection(&cs); +} + +/* set media min/max */ +void CMPC_Lcd::SetMediaRange(__int64 nStart, __int64 nStop) +{ + //handle 64bit integers LCDUI only supports int for Range + //Since it also supports floats for position, + //This will always work in percentage + m_nMediaStart = nStart; + m_nMediaStop = nStop; +} + +/* update media position */ +void CMPC_Lcd::SetMediaPos(__int64 nPos) +{ + //handle 64bit integers LCDUI only supports int for Range + //Since it also supports floats for position, + //This will always work in percentage + float fPos; + if (m_nMediaStart != m_nMediaStop) { + fPos = float(nPos - m_nMediaStart) * 100.0f / float(m_nMediaStop - m_nMediaStart); + } else { // The duration might be unknown + fPos = 0.0f; + } + + EnterCriticalSection(&cs); + m_MonoPage.m_ProgBar[1].SetPos(fPos); + m_ColorPage.m_ProgBar[1].SetPos(fPos); + LeaveCriticalSection(&cs); +} + +/* update status message (displayed for nTimeOut milliseconds) */ +void CMPC_Lcd::SetStatusMessage(const TCHAR* text, int nTimeOut) +{ + if (!m_Connection.IsConnected()) { + return; + } + + __time64_t ltime; + _time64(<ime); + if ((nTimeOut /= 1000) < 1) { + nTimeOut = 1; + } + + EnterCriticalSection(&cs); + nThread_tTimeout = ltime + nTimeOut; + m_MonoPage.m_Text[0].SetText(text); + m_ColorPage.m_Text[0].SetText(text); + LeaveCriticalSection(&cs); +} + +/* update play state bitmap */ +void CMPC_Lcd::SetPlayState(CMPC_Lcd::PlayState ps) +{ + if (!m_Connection.IsConnected()) { + return; + } + + EnterCriticalSection(&cs); + switch (ps) { + case PS_PLAY: + SetAsForeground(true); + break; + case PS_PAUSE: + break; + case PS_STOP: + SetAsForeground(false); + break; + default: + break; + } + + m_MonoPage.SetPlayState((CLCDMyMonoPage::PlayState)ps); + m_ColorPage.SetPlayState((CLCDMyColorPage::PlayState)ps); + + LeaveCriticalSection(&cs); +} + +HRESULT CMPC_Lcd::SetAsForeground(BOOL setAsForeground) +{ + if (nullptr != m_Connection.MonoOutput()) { + m_Connection.MonoOutput()->SetAsForeground(setAsForeground); + } + + if (nullptr != m_Connection.ColorOutput()) { + m_Connection.ColorOutput()->SetAsForeground(setAsForeground); + } + + return S_OK; +} diff --git a/src/mpc-hc/LcdSupport.h b/src/mpc-hc/LcdSupport.h index c66ab24371a..f7906cd6e72 100644 --- a/src/mpc-hc/LcdSupport.h +++ b/src/mpc-hc/LcdSupport.h @@ -1,136 +1,136 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2016 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 . - * - */ - -#pragma once - -#include "lglcd/lglcd.h" -#include "LCDUI/LCDUI.h" - -class CLCDMyProgressBar : public CLCDProgressBar -{ -public: - enum eMY_PROGRESS_STYLE { - STYLE_FILLED_H, - STYLE_CURSOR, - STYLE_DASHED_CURSOR, - STYLE_FILLED_V - }; - - virtual void OnDraw(CLCDGfxBase& rGfx); - virtual void SetProgressStyle(ePROGRESS_STYLE eStyle); - virtual void SetProgressStyle(eMY_PROGRESS_STYLE eMyStyle); - -protected: - eMY_PROGRESS_STYLE m_eMyStyle; -}; - -class CLCDMyMonoPage : public CLCDPage -{ -public: - enum PlayState { - PS_PLAY = 0, - PS_PAUSE = 1, - PS_STOP = 2, - PS_UNUSED = 3 - }; - - virtual HRESULT Initialize(); - virtual void OnLCDButtonUp(int nButton); - void SetPlayState(PlayState ps); - - CLCDMyMonoPage(); - ~CLCDMyMonoPage(); - - CLCDScrollingText m_Text1; - CLCDText m_Text[2]; - CLCDMyProgressBar m_ProgBar[2]; - CLCDAnimatedBitmap m_PlayState; -private: - HBITMAP hBmp[PS_UNUSED]; -}; - -class CLCDMyColorPage : public CLCDPage -{ -public: - enum PlayState { - PS_PLAY = 0, - PS_PAUSE = 1, - PS_STOP = 2, - PS_UNUSED = 3 - }; - - virtual HRESULT Initialize(); - virtual void OnLCDButtonUp(int nButton); - void SetPlayState(PlayState ps); - - CLCDMyColorPage(); - ~CLCDMyColorPage(); - - CLCDScrollingText m_Text1; - CLCDText m_Text[2]; - CLCDMyProgressBar m_ProgBar[2]; - CLCDAnimatedBitmap m_PlayState; -private: - HBITMAP hBmp[PS_UNUSED]; -}; - -class CMPC_Lcd -{ -public: - enum PlayState { - PS_PLAY = 0, - PS_PAUSE = 1, - PS_STOP = 2, - PS_UNUSED = 3 - }; - -private: - lgLcdConnectContextEx m_ConnCtx; - HANDLE hLCD_UpdateThread; - - __int64 m_nMediaStart; - __int64 m_nMediaStop; - __int64 m_nVolumeStart; - __int64 m_nVolumeStop; - - HRESULT SetAsForeground(BOOL setAsForeground); - -public: - CLCDConnection m_Connection; - CLCDOutput* m_MonoOutput; - CLCDOutput* m_ColorOutput; - CLCDMyMonoPage m_MonoPage; - CLCDMyColorPage m_ColorPage; - bool Thread_Loop; - __time64_t nThread_tTimeout; - CRITICAL_SECTION cs; - - CMPC_Lcd(); - ~CMPC_Lcd(); - - void SetMediaTitle(const TCHAR* text); - void SetMediaRange(__int64 nStart, __int64 nStop); - void SetMediaPos(__int64 nPos); - void SetVolumeRange(__int64 nStart, __int64 nStop); - void SetVolume(__int64 nVol); - void SetStatusMessage(const TCHAR* text, int nTimeOut); - void SetPlayState(PlayState ps); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2016 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 . + * + */ + +#pragma once + +#include "lglcd/lglcd.h" +#include "LCDUI/LCDUI.h" + +class CLCDMyProgressBar : public CLCDProgressBar +{ +public: + enum eMY_PROGRESS_STYLE { + STYLE_FILLED_H, + STYLE_CURSOR, + STYLE_DASHED_CURSOR, + STYLE_FILLED_V + }; + + virtual void OnDraw(CLCDGfxBase& rGfx); + virtual void SetProgressStyle(ePROGRESS_STYLE eStyle); + virtual void SetProgressStyle(eMY_PROGRESS_STYLE eMyStyle); + +protected: + eMY_PROGRESS_STYLE m_eMyStyle; +}; + +class CLCDMyMonoPage : public CLCDPage +{ +public: + enum PlayState { + PS_PLAY = 0, + PS_PAUSE = 1, + PS_STOP = 2, + PS_UNUSED = 3 + }; + + virtual HRESULT Initialize(); + virtual void OnLCDButtonUp(int nButton); + void SetPlayState(PlayState ps); + + CLCDMyMonoPage(); + ~CLCDMyMonoPage(); + + CLCDScrollingText m_Text1; + CLCDText m_Text[2]; + CLCDMyProgressBar m_ProgBar[2]; + CLCDAnimatedBitmap m_PlayState; +private: + HBITMAP hBmp[PS_UNUSED]; +}; + +class CLCDMyColorPage : public CLCDPage +{ +public: + enum PlayState { + PS_PLAY = 0, + PS_PAUSE = 1, + PS_STOP = 2, + PS_UNUSED = 3 + }; + + virtual HRESULT Initialize(); + virtual void OnLCDButtonUp(int nButton); + void SetPlayState(PlayState ps); + + CLCDMyColorPage(); + ~CLCDMyColorPage(); + + CLCDScrollingText m_Text1; + CLCDText m_Text[2]; + CLCDMyProgressBar m_ProgBar[2]; + CLCDAnimatedBitmap m_PlayState; +private: + HBITMAP hBmp[PS_UNUSED]; +}; + +class CMPC_Lcd +{ +public: + enum PlayState { + PS_PLAY = 0, + PS_PAUSE = 1, + PS_STOP = 2, + PS_UNUSED = 3 + }; + +private: + lgLcdConnectContextEx m_ConnCtx; + HANDLE hLCD_UpdateThread; + + __int64 m_nMediaStart; + __int64 m_nMediaStop; + __int64 m_nVolumeStart; + __int64 m_nVolumeStop; + + HRESULT SetAsForeground(BOOL setAsForeground); + +public: + CLCDConnection m_Connection; + CLCDOutput* m_MonoOutput; + CLCDOutput* m_ColorOutput; + CLCDMyMonoPage m_MonoPage; + CLCDMyColorPage m_ColorPage; + bool Thread_Loop; + __time64_t nThread_tTimeout; + CRITICAL_SECTION cs; + + CMPC_Lcd(); + ~CMPC_Lcd(); + + void SetMediaTitle(const TCHAR* text); + void SetMediaRange(__int64 nStart, __int64 nStop); + void SetMediaPos(__int64 nPos); + void SetVolumeRange(__int64 nStart, __int64 nStop); + void SetVolume(__int64 nVol); + void SetStatusMessage(const TCHAR* text, int nTimeOut); + void SetPlayState(PlayState ps); +}; diff --git a/src/mpc-hc/MPCPngImage.cpp b/src/mpc-hc/MPCPngImage.cpp index f8c34078b9a..ca2fea78fcb 100644 --- a/src/mpc-hc/MPCPngImage.cpp +++ b/src/mpc-hc/MPCPngImage.cpp @@ -1,114 +1,114 @@ -#include "stdafx.h" -#include "MPCPngImage.h" - - -////////////////////////////////////////////////////////////////////// -// CPngImage - -CImage* CMPCPngImage::m_pImage; - -////////////////////////////////////////////////////////////////////// -// Operations -////////////////////////////////////////////////////////////////////// - -BOOL CMPCPngImage::Load(UINT uiResID, HINSTANCE hinstRes) -{ - return Load(MAKEINTRESOURCE(uiResID), hinstRes); -} - -BOOL CMPCPngImage::Load(LPCTSTR lpszResourceName, HINSTANCE hinstRes) -{ - if (hinstRes == nullptr) { - hinstRes = AfxFindResourceHandle(lpszResourceName, _T("PNG")); - } - - HRSRC hRsrc = ::FindResource(hinstRes, lpszResourceName, _T("PNG")); - if (hRsrc == nullptr) { - // Fallback to the instance handle - hinstRes = AfxGetInstanceHandle(); - hRsrc = ::FindResource(hinstRes, lpszResourceName, _T("PNG")); - if (hRsrc == nullptr) { - return FALSE; - } - } - - HGLOBAL hGlobal = LoadResource(hinstRes, hRsrc); - if (hGlobal == nullptr) { - return FALSE; - } - - LPVOID lpBuffer = ::LockResource(hGlobal); - if (lpBuffer == nullptr) { - FreeResource(hGlobal); - return FALSE; - } - - BOOL bRes = LoadFromBuffer((LPBYTE) lpBuffer, (UINT) ::SizeofResource(hinstRes, hRsrc)); - - UnlockResource(hGlobal); - FreeResource(hGlobal); - - return bRes; -} -//******************************************************************************* -BOOL CMPCPngImage::LoadFromFile(LPCTSTR lpszPath) -{ - BOOL bRes = FALSE; - - if (m_pImage == nullptr) { - m_pImage = DEBUG_NEW CImage; - ENSURE(m_pImage != nullptr); - } - - if (m_pImage->Load(lpszPath) == S_OK) { - bRes = Attach(m_pImage->Detach()); - } - - return bRes; -} -//******************************************************************************* -BOOL CMPCPngImage::LoadFromBuffer(const LPBYTE lpBuffer, UINT uiSize) -{ - ASSERT(lpBuffer != nullptr); - - HGLOBAL hRes = ::GlobalAlloc(GMEM_MOVEABLE, uiSize); - if (hRes == nullptr) { - return FALSE; - } - - IStream* pStream = nullptr; - LPVOID lpResBuffer = ::GlobalLock(hRes); - ASSERT(lpResBuffer != nullptr); - - memcpy(lpResBuffer, lpBuffer, uiSize); - - HRESULT hResult = ::CreateStreamOnHGlobal(hRes, TRUE, &pStream); - - if (hResult != S_OK) { - ::GlobalUnlock(hRes); - ::GlobalFree(hRes); - return FALSE; - } - - if (m_pImage == nullptr) { - m_pImage = DEBUG_NEW CImage; - ENSURE(m_pImage != nullptr); - } - - m_pImage->Load(pStream); - pStream->Release(); //should free hRes due to fDeleteOnRelease=TRUE above - - BOOL bRes = Attach(m_pImage->Detach()); - - return bRes; -} - -CSize CMPCPngImage::GetSize() -{ - CSize size; - BITMAP bm; - if (GetBitmap(&bm)) { - size.SetSize(bm.bmWidth, bm.bmHeight); - } - return size; -} +#include "stdafx.h" +#include "MPCPngImage.h" + + +////////////////////////////////////////////////////////////////////// +// CPngImage + +CImage* CMPCPngImage::m_pImage; + +////////////////////////////////////////////////////////////////////// +// Operations +////////////////////////////////////////////////////////////////////// + +BOOL CMPCPngImage::Load(UINT uiResID, HINSTANCE hinstRes) +{ + return Load(MAKEINTRESOURCE(uiResID), hinstRes); +} + +BOOL CMPCPngImage::Load(LPCTSTR lpszResourceName, HINSTANCE hinstRes) +{ + if (hinstRes == nullptr) { + hinstRes = AfxFindResourceHandle(lpszResourceName, _T("PNG")); + } + + HRSRC hRsrc = ::FindResource(hinstRes, lpszResourceName, _T("PNG")); + if (hRsrc == nullptr) { + // Fallback to the instance handle + hinstRes = AfxGetInstanceHandle(); + hRsrc = ::FindResource(hinstRes, lpszResourceName, _T("PNG")); + if (hRsrc == nullptr) { + return FALSE; + } + } + + HGLOBAL hGlobal = LoadResource(hinstRes, hRsrc); + if (hGlobal == nullptr) { + return FALSE; + } + + LPVOID lpBuffer = ::LockResource(hGlobal); + if (lpBuffer == nullptr) { + FreeResource(hGlobal); + return FALSE; + } + + BOOL bRes = LoadFromBuffer((LPBYTE) lpBuffer, (UINT) ::SizeofResource(hinstRes, hRsrc)); + + UnlockResource(hGlobal); + FreeResource(hGlobal); + + return bRes; +} +//******************************************************************************* +BOOL CMPCPngImage::LoadFromFile(LPCTSTR lpszPath) +{ + BOOL bRes = FALSE; + + if (m_pImage == nullptr) { + m_pImage = DEBUG_NEW CImage; + ENSURE(m_pImage != nullptr); + } + + if (m_pImage->Load(lpszPath) == S_OK) { + bRes = Attach(m_pImage->Detach()); + } + + return bRes; +} +//******************************************************************************* +BOOL CMPCPngImage::LoadFromBuffer(const LPBYTE lpBuffer, UINT uiSize) +{ + ASSERT(lpBuffer != nullptr); + + HGLOBAL hRes = ::GlobalAlloc(GMEM_MOVEABLE, uiSize); + if (hRes == nullptr) { + return FALSE; + } + + IStream* pStream = nullptr; + LPVOID lpResBuffer = ::GlobalLock(hRes); + ASSERT(lpResBuffer != nullptr); + + memcpy(lpResBuffer, lpBuffer, uiSize); + + HRESULT hResult = ::CreateStreamOnHGlobal(hRes, TRUE, &pStream); + + if (hResult != S_OK) { + ::GlobalUnlock(hRes); + ::GlobalFree(hRes); + return FALSE; + } + + if (m_pImage == nullptr) { + m_pImage = DEBUG_NEW CImage; + ENSURE(m_pImage != nullptr); + } + + m_pImage->Load(pStream); + pStream->Release(); //should free hRes due to fDeleteOnRelease=TRUE above + + BOOL bRes = Attach(m_pImage->Detach()); + + return bRes; +} + +CSize CMPCPngImage::GetSize() +{ + CSize size; + BITMAP bm; + if (GetBitmap(&bm)) { + size.SetSize(bm.bmWidth, bm.bmHeight); + } + return size; +} diff --git a/src/mpc-hc/MPCPngImage.h b/src/mpc-hc/MPCPngImage.h index 47448a7ff4a..9c041a74c4c 100644 --- a/src/mpc-hc/MPCPngImage.h +++ b/src/mpc-hc/MPCPngImage.h @@ -1,29 +1,29 @@ -#pragma once - -#include - -class CMPCPngImage : public CBitmap -{ - // Construction/Destruction -public: - CMPCPngImage() = default; - virtual ~CMPCPngImage() = default; - - // Attributes: -protected: - static ATL::CImage* m_pImage; - - // Operations: -public: - BOOL Load(UINT uiResID, HINSTANCE hinstRes = nullptr); - BOOL Load(LPCTSTR lpszResourceName, HINSTANCE hinstRes = nullptr); - - BOOL LoadFromFile(LPCTSTR lpszPath); - BOOL LoadFromBuffer(const LPBYTE lpBuffer, UINT uiSize); - - CSize GetSize(); - - static void __stdcall CleanUp() { - SAFE_DELETE(m_pImage); - } -}; +#pragma once + +#include + +class CMPCPngImage : public CBitmap +{ + // Construction/Destruction +public: + CMPCPngImage() = default; + virtual ~CMPCPngImage() = default; + + // Attributes: +protected: + static ATL::CImage* m_pImage; + + // Operations: +public: + BOOL Load(UINT uiResID, HINSTANCE hinstRes = nullptr); + BOOL Load(LPCTSTR lpszResourceName, HINSTANCE hinstRes = nullptr); + + BOOL LoadFromFile(LPCTSTR lpszPath); + BOOL LoadFromBuffer(const LPBYTE lpBuffer, UINT uiSize); + + CSize GetSize(); + + static void __stdcall CleanUp() { + SAFE_DELETE(m_pImage); + } +}; diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index 7f96c4c48bb..e4237fc5863 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -1,22182 +1,22182 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "MainFrm.h" -#include "mplayerc.h" -#include "version.h" - -#include "GraphThread.h" -#include "FGFilterLAV.h" -#include "FGManager.h" -#include "FGManagerBDA.h" -#include "ShockwaveGraph.h" -#include "TextPassThruFilter.h" -#include "FakeFilterMapper2.h" - -#include "FavoriteAddDlg.h" -#include "GoToDlg.h" -#include "MediaTypesDlg.h" -#include "OpenFileDlg.h" -#include "PnSPresetsDlg.h" -#include "SaveDlg.h" -#include "SaveImageDialog.h" -#include "SaveSubtitlesFileDialog.h" -#include "SaveThumbnailsDialog.h" -#include "OpenDirHelper.h" -#include "OpenDlg.h" -#include "TunerScanDlg.h" - -#include "ComPropertySheet.h" -#include "PPageAccelTbl.h" -#include "PPageAudioSwitcher.h" -#include "PPageFileInfoSheet.h" -#include "PPageSheet.h" -#include "PPageSubStyle.h" -#include "PPageSubtitles.h" - -#include "CoverArt.h" -#include "CrashReporter.h" -#include "KeyProvider.h" -#include "SkypeMoodMsgHandler.h" -#include "Translations.h" -#include "UpdateChecker.h" -#include "WebServer.h" -#include -#include -#include - -#include "../DeCSS/VobFile.h" -#include "../Subtitles/PGSSub.h" -#include "../Subtitles/RLECodedSubtitle.h" -#include "../Subtitles/RTS.h" -#include "../Subtitles/STS.h" -#include - -#include "../filters/InternalPropertyPage.h" -#include "../filters/PinInfoWnd.h" -#include "../filters/renderer/SyncClock/SyncClock.h" -#include "../filters/transform/BufferFilter/BufferFilter.h" - -#include -#include -#include -#include - -#include "FullscreenWnd.h" -#include "Monitors.h" - -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "YoutubeDL.h" -#include "CMPCThemeMenu.h" -#include "CMPCThemeDockBar.h" -#include "CMPCThemeMiniDockFrameWnd.h" -#include "RarEntrySelectorDialog.h" -#include "FileHandle.h" -#include "MPCFolderPickerDialog.h" - -#include "stb/stb_image.h" -#include "stb/stb_image_resize2.h" - -#include -#undef SubclassWindow - -// IID_IAMLine21Decoder -DECLARE_INTERFACE_IID_(IAMLine21Decoder_2, IAMLine21Decoder, "6E8D4A21-310C-11d0-B79A-00AA003767A7") {}; - -#define MIN_LOGO_WIDTH 400 -#define MIN_LOGO_HEIGHT 150 - -#define PREV_CHAP_THRESHOLD 2 - -static UINT s_uTaskbarRestart = RegisterWindowMessage(_T("TaskbarCreated")); -static UINT WM_NOTIFYICON = RegisterWindowMessage(_T("MYWM_NOTIFYICON")); -static UINT s_uTBBC = RegisterWindowMessage(_T("TaskbarButtonCreated")); - -CMainFrame::PlaybackRateMap CMainFrame::filePlaybackRates = { - { ID_PLAY_PLAYBACKRATE_025, .25f}, - { ID_PLAY_PLAYBACKRATE_050, .50f}, - { ID_PLAY_PLAYBACKRATE_075, .75f}, - { ID_PLAY_PLAYBACKRATE_090, .90f}, - { ID_PLAY_PLAYBACKRATE_100, 1.00f}, - { ID_PLAY_PLAYBACKRATE_110, 1.10f}, - { ID_PLAY_PLAYBACKRATE_125, 1.25f}, - { ID_PLAY_PLAYBACKRATE_150, 1.50f}, - { ID_PLAY_PLAYBACKRATE_200, 2.00f}, - { ID_PLAY_PLAYBACKRATE_300, 3.00f}, - { ID_PLAY_PLAYBACKRATE_400, 4.00f}, - { ID_PLAY_PLAYBACKRATE_600, 6.00f}, - { ID_PLAY_PLAYBACKRATE_800, 8.00f}, -}; - -CMainFrame::PlaybackRateMap CMainFrame::dvdPlaybackRates = { - { ID_PLAY_PLAYBACKRATE_025, .25f}, - { ID_PLAY_PLAYBACKRATE_050, .50f}, - { ID_PLAY_PLAYBACKRATE_100, 1.00f}, - { ID_PLAY_PLAYBACKRATE_200, 2.00f}, - { ID_PLAY_PLAYBACKRATE_400, 4.00f}, - { ID_PLAY_PLAYBACKRATE_800, 8.00f}, -}; - - -static bool EnsureDirectory(CString directory) -{ - int ret = SHCreateDirectoryEx(nullptr, directory, nullptr); - bool result = ret == ERROR_SUCCESS || ret == ERROR_ALREADY_EXISTS; - if (!result) { - AfxMessageBox(_T("Cannot create directory: ") + directory, MB_ICONEXCLAMATION | MB_OK); - } - return result; -} - -class CSubClock : public CUnknown, public ISubClock -{ - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(ISubClock) - CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - - REFERENCE_TIME m_rt; - -public: - CSubClock() : CUnknown(NAME("CSubClock"), nullptr) { - m_rt = 0; - } - - DECLARE_IUNKNOWN; - - // ISubClock - STDMETHODIMP SetTime(REFERENCE_TIME rt) { - m_rt = rt; - return S_OK; - } - STDMETHODIMP_(REFERENCE_TIME) GetTime() { - return m_rt; - } -}; - -bool FileFavorite::TryParse(const CString& fav, FileFavorite& ff) -{ - CAtlList parts; - return TryParse(fav, ff, parts); -} - -bool FileFavorite::TryParse(const CString& fav, FileFavorite& ff, CAtlList& parts) -{ - ExplodeEsc(fav, parts, _T(';')); - if (parts.IsEmpty()) { - return false; - } - - ff.Name = parts.RemoveHead(); - - if (!parts.IsEmpty()) { - // Start position and optional A-B marks "pos[:A:B]" - auto startPos = parts.RemoveHead(); - _stscanf_s(startPos, _T("%I64d:%I64d:%I64d"), &ff.Start, &ff.MarkA, &ff.MarkB); - ff.Start = std::max(ff.Start, 0ll); // Sanitize - } - if (!parts.IsEmpty()) { - _stscanf_s(parts.RemoveHead(), _T("%d"), &ff.RelativeDrive); - } - return true; -} - -CString FileFavorite::ToString() const -{ - CString str; - if (RelativeDrive) { - str = _T("[RD]"); - } - if (Start > 0) { // Start position - str.AppendFormat(_T("[%s]"), ReftimeToString2(Start).GetString()); - } - if (MarkA > 0 || MarkB > 0) { // A-B marks (only characters to save space) - CString abMarks; - if (MarkA > 0) { - abMarks = _T("A"); - } - if (MarkB > 0) { - abMarks.Append(_T("-B")); - } - str.AppendFormat(_T("[%s]"), abMarks.GetString()); - } - return str; -} - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame - -IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd) - -BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) - ON_WM_NCCREATE() - ON_WM_CREATE() - ON_WM_DESTROY() - ON_WM_CLOSE() - ON_WM_MEASUREITEM() - - ON_MESSAGE(WM_MPCVR_SWITCH_FULLSCREEN, OnMPCVRSwitchFullscreen) - - ON_REGISTERED_MESSAGE(s_uTaskbarRestart, OnTaskBarRestart) - ON_REGISTERED_MESSAGE(WM_NOTIFYICON, OnNotifyIcon) - - ON_REGISTERED_MESSAGE(s_uTBBC, OnTaskBarThumbnailsCreate) - - ON_REGISTERED_MESSAGE(SkypeMoodMsgHandler::uSkypeControlAPIAttach, OnSkypeAttach) - - ON_WM_SETFOCUS() - ON_WM_GETMINMAXINFO() - ON_WM_MOVE() - ON_WM_ENTERSIZEMOVE() - ON_WM_MOVING() - ON_WM_SIZE() - ON_WM_SIZING() - ON_WM_EXITSIZEMOVE() - ON_MESSAGE_VOID(WM_DISPLAYCHANGE, OnDisplayChange) - ON_WM_WINDOWPOSCHANGING() - - ON_MESSAGE(WM_DPICHANGED, OnDpiChanged) - - ON_WM_SYSCOMMAND() - ON_WM_ACTIVATEAPP() - ON_MESSAGE(WM_APPCOMMAND, OnAppCommand) - ON_WM_INPUT() - ON_MESSAGE(WM_HOTKEY, OnHotKey) - - ON_WM_TIMER() - - ON_MESSAGE(WM_GRAPHNOTIFY, OnGraphNotify) - ON_MESSAGE(WM_RESET_DEVICE, OnResetDevice) - ON_MESSAGE(WM_REARRANGERENDERLESS, OnRepaintRenderLess) - - ON_MESSAGE_VOID(WM_SAVESETTINGS, SaveAppSettings) - - ON_WM_NCHITTEST() - - ON_WM_HSCROLL() - - ON_WM_INITMENU() - ON_WM_INITMENUPOPUP() - ON_WM_UNINITMENUPOPUP() - - ON_WM_ENTERMENULOOP() - - ON_WM_QUERYENDSESSION() - ON_WM_ENDSESSION() - - ON_COMMAND(ID_MENU_PLAYER_SHORT, OnMenuPlayerShort) - ON_COMMAND(ID_MENU_PLAYER_LONG, OnMenuPlayerLong) - ON_COMMAND(ID_MENU_FILTERS, OnMenuFilters) - - ON_UPDATE_COMMAND_UI(IDC_PLAYERSTATUS, OnUpdatePlayerStatus) - - ON_MESSAGE(WM_POSTOPEN, OnFilePostOpenmedia) - ON_MESSAGE(WM_OPENFAILED, OnOpenMediaFailed) - ON_MESSAGE(WM_DVB_EIT_DATA_READY, OnCurrentChannelInfoUpdated) - - ON_COMMAND(ID_BOSS, OnBossKey) - - ON_COMMAND_RANGE(ID_STREAM_AUDIO_NEXT, ID_STREAM_AUDIO_PREV, OnStreamAudio) - ON_COMMAND_RANGE(ID_STREAM_SUB_NEXT, ID_STREAM_SUB_PREV, OnStreamSub) - ON_COMMAND(ID_AUDIOSHIFT_ONOFF, OnAudioShiftOnOff) - ON_COMMAND(ID_STREAM_SUB_ONOFF, OnStreamSubOnOff) - ON_COMMAND_RANGE(ID_DVD_ANGLE_NEXT, ID_DVD_ANGLE_PREV, OnDvdAngle) - ON_COMMAND_RANGE(ID_DVD_AUDIO_NEXT, ID_DVD_AUDIO_PREV, OnDvdAudio) - ON_COMMAND_RANGE(ID_DVD_SUB_NEXT, ID_DVD_SUB_PREV, OnDvdSub) - ON_COMMAND(ID_DVD_SUB_ONOFF, OnDvdSubOnOff) - - ON_COMMAND(ID_FILE_OPENQUICK, OnFileOpenQuick) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENMEDIA, OnUpdateFileOpen) - ON_COMMAND(ID_FILE_OPENMEDIA, OnFileOpenmedia) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENMEDIA, OnUpdateFileOpen) - ON_WM_COPYDATA() - ON_COMMAND(ID_FILE_OPENDVDBD, OnFileOpendvd) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENDVDBD, OnUpdateFileOpen) - ON_COMMAND(ID_FILE_OPENDEVICE, OnFileOpendevice) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENDEVICE, OnUpdateFileOpen) - ON_COMMAND_RANGE(ID_FILE_OPEN_OPTICAL_DISK_START, ID_FILE_OPEN_OPTICAL_DISK_END, OnFileOpenOpticalDisk) - ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_OPEN_OPTICAL_DISK_START, ID_FILE_OPEN_OPTICAL_DISK_END, OnUpdateFileOpen) - ON_COMMAND(ID_FILE_REOPEN, OnFileReopen) - ON_COMMAND(ID_FILE_RECYCLE, OnFileRecycle) - ON_COMMAND(ID_FILE_SAVE_COPY, OnFileSaveAs) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_COPY, OnUpdateFileSaveAs) - ON_COMMAND(ID_FILE_SAVE_IMAGE, OnFileSaveImage) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_IMAGE, OnUpdateFileSaveImage) - ON_COMMAND(ID_FILE_SAVE_IMAGE_AUTO, OnFileSaveImageAuto) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_IMAGE_AUTO, OnUpdateFileSaveImage) - ON_COMMAND(ID_CMDLINE_SAVE_THUMBNAILS, OnCmdLineSaveThumbnails) - ON_COMMAND(ID_FILE_SAVE_THUMBNAILS, OnFileSaveThumbnails) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_THUMBNAILS, OnUpdateFileSaveThumbnails) - ON_COMMAND(ID_FILE_SUBTITLES_LOAD, OnFileSubtitlesLoad) - ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_LOAD, OnUpdateFileSubtitlesLoad) - ON_COMMAND(ID_FILE_SUBTITLES_SAVE, OnFileSubtitlesSave) - ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_SAVE, OnUpdateFileSubtitlesSave) - //ON_COMMAND(ID_FILE_SUBTITLES_UPLOAD, OnFileSubtitlesUpload) - //ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_UPLOAD, OnUpdateFileSubtitlesUpload) - ON_COMMAND(ID_FILE_SUBTITLES_DOWNLOAD, OnFileSubtitlesDownload) - ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_DOWNLOAD, OnUpdateFileSubtitlesDownload) - ON_COMMAND(ID_FILE_PROPERTIES, OnFileProperties) - ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateFileProperties) - ON_COMMAND(ID_FILE_OPEN_LOCATION, OnFileOpenLocation) - ON_UPDATE_COMMAND_UI(ID_FILE_OPEN_LOCATION, OnUpdateFileProperties) - ON_COMMAND(ID_FILE_CLOSE_AND_RESTORE, OnFileCloseAndRestore) - ON_UPDATE_COMMAND_UI(ID_FILE_CLOSE_AND_RESTORE, OnUpdateFileClose) - ON_COMMAND(ID_FILE_CLOSEMEDIA, OnFileCloseMedia) - ON_UPDATE_COMMAND_UI(ID_FILE_CLOSEMEDIA, OnUpdateFileClose) - - ON_COMMAND(ID_VIEW_CAPTIONMENU, OnViewCaptionmenu) - ON_UPDATE_COMMAND_UI(ID_VIEW_CAPTIONMENU, OnUpdateViewCaptionmenu) - ON_COMMAND_RANGE(ID_VIEW_SEEKER, ID_VIEW_STATUS, OnViewControlBar) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_SEEKER, ID_VIEW_STATUS, OnUpdateViewControlBar) - ON_COMMAND(ID_VIEW_SUBRESYNC, OnViewSubresync) - ON_UPDATE_COMMAND_UI(ID_VIEW_SUBRESYNC, OnUpdateViewSubresync) - ON_COMMAND(ID_VIEW_PLAYLIST, OnViewPlaylist) - ON_UPDATE_COMMAND_UI(ID_VIEW_PLAYLIST, OnUpdateViewPlaylist) - ON_COMMAND(ID_PLAYLIST_TOGGLE_SHUFFLE, OnPlaylistToggleShuffle) - ON_COMMAND(ID_VIEW_EDITLISTEDITOR, OnViewEditListEditor) - ON_COMMAND(ID_EDL_IN, OnEDLIn) - ON_UPDATE_COMMAND_UI(ID_EDL_IN, OnUpdateEDLIn) - ON_COMMAND(ID_EDL_OUT, OnEDLOut) - ON_UPDATE_COMMAND_UI(ID_EDL_OUT, OnUpdateEDLOut) - ON_COMMAND(ID_EDL_NEWCLIP, OnEDLNewClip) - ON_UPDATE_COMMAND_UI(ID_EDL_NEWCLIP, OnUpdateEDLNewClip) - ON_COMMAND(ID_EDL_SAVE, OnEDLSave) - ON_UPDATE_COMMAND_UI(ID_EDL_SAVE, OnUpdateEDLSave) - ON_COMMAND(ID_VIEW_CAPTURE, OnViewCapture) - ON_UPDATE_COMMAND_UI(ID_VIEW_CAPTURE, OnUpdateViewCapture) - ON_COMMAND(ID_VIEW_DEBUGSHADERS, OnViewDebugShaders) - ON_UPDATE_COMMAND_UI(ID_VIEW_DEBUGSHADERS, OnUpdateViewDebugShaders) - ON_COMMAND(ID_VIEW_PRESETS_MINIMAL, OnViewMinimal) - ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_MINIMAL, OnUpdateViewMinimal) - ON_COMMAND(ID_VIEW_PRESETS_COMPACT, OnViewCompact) - ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_COMPACT, OnUpdateViewCompact) - ON_COMMAND(ID_VIEW_PRESETS_NORMAL, OnViewNormal) - ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_NORMAL, OnUpdateViewNormal) - ON_COMMAND(ID_VIEW_FULLSCREEN, OnViewFullscreen) - ON_COMMAND(ID_VIEW_FULLSCREEN_SECONDARY, OnViewFullscreenSecondary) - ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCREEN, OnUpdateViewFullscreen) - ON_COMMAND_RANGE(ID_VIEW_ZOOM_50, ID_VIEW_ZOOM_200, OnViewZoom) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_50, ID_VIEW_ZOOM_200, OnUpdateViewZoom) - ON_COMMAND_RANGE(ID_VIEW_ZOOM_25, ID_VIEW_ZOOM_25, OnViewZoom) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_25, ID_VIEW_ZOOM_25, OnUpdateViewZoom) - ON_COMMAND(ID_VIEW_ZOOM_AUTOFIT, OnViewZoomAutoFit) - ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_AUTOFIT, OnUpdateViewZoom) - ON_COMMAND(ID_VIEW_ZOOM_AUTOFIT_LARGER, OnViewZoomAutoFitLarger) - ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_AUTOFIT_LARGER, OnUpdateViewZoom) - ON_COMMAND_RANGE(ID_VIEW_ZOOM_SUB, ID_VIEW_ZOOM_ADD, OnViewModifySize) - ON_COMMAND_RANGE(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, OnViewDefaultVideoFrame) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, OnUpdateViewDefaultVideoFrame) - ON_COMMAND(ID_VIEW_VF_SWITCHZOOM, OnViewSwitchVideoFrame) - ON_COMMAND(ID_VIEW_VF_COMPMONDESKARDIFF, OnViewCompMonDeskARDiff) - ON_UPDATE_COMMAND_UI(ID_VIEW_VF_COMPMONDESKARDIFF, OnUpdateViewCompMonDeskARDiff) - ON_COMMAND_RANGE(ID_VIEW_RESET, ID_PANSCAN_CENTER, OnViewPanNScan) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_RESET, ID_PANSCAN_CENTER, OnUpdateViewPanNScan) - ON_COMMAND_RANGE(ID_PANNSCAN_PRESETS_START, ID_PANNSCAN_PRESETS_END, OnViewPanNScanPresets) - ON_UPDATE_COMMAND_UI_RANGE(ID_PANNSCAN_PRESETS_START, ID_PANNSCAN_PRESETS_END, OnUpdateViewPanNScanPresets) - ON_COMMAND_RANGE(ID_PANSCAN_ROTATEXP, ID_PANSCAN_ROTATEZM, OnViewRotate) - ON_UPDATE_COMMAND_UI_RANGE(ID_PANSCAN_ROTATEXP, ID_PANSCAN_ROTATEZM, OnUpdateViewRotate) - ON_COMMAND_RANGE(ID_PANSCAN_ROTATEZ270, ID_PANSCAN_ROTATEZ270, OnViewRotate) - ON_UPDATE_COMMAND_UI_RANGE(ID_PANSCAN_ROTATEZ270, ID_PANSCAN_ROTATEZ270, OnUpdateViewRotate) - ON_COMMAND_RANGE(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, OnViewAspectRatio) - ON_UPDATE_COMMAND_UI_RANGE(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, OnUpdateViewAspectRatio) - ON_COMMAND(ID_ASPECTRATIO_NEXT, OnViewAspectRatioNext) - ON_COMMAND_RANGE(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, OnViewOntop) - ON_UPDATE_COMMAND_UI_RANGE(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, OnUpdateViewOntop) - ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions) - - // Casimir666 - ON_UPDATE_COMMAND_UI(ID_VIEW_TEARING_TEST, OnUpdateViewTearingTest) - ON_COMMAND(ID_VIEW_TEARING_TEST, OnViewTearingTest) - ON_UPDATE_COMMAND_UI(ID_VIEW_DISPLAY_RENDERER_STATS, OnUpdateViewDisplayRendererStats) - ON_COMMAND(ID_VIEW_RESET_RENDERER_STATS, OnViewResetRendererStats) - ON_COMMAND(ID_VIEW_DISPLAY_RENDERER_STATS, OnViewDisplayRendererStats) - ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCREENGUISUPPORT, OnUpdateViewFullscreenGUISupport) - ON_UPDATE_COMMAND_UI(ID_VIEW_HIGHCOLORRESOLUTION, OnUpdateViewHighColorResolution) - ON_UPDATE_COMMAND_UI(ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION, OnUpdateViewForceInputHighColorResolution) - ON_UPDATE_COMMAND_UI(ID_VIEW_FULLFLOATINGPOINTPROCESSING, OnUpdateViewFullFloatingPointProcessing) - ON_UPDATE_COMMAND_UI(ID_VIEW_HALFFLOATINGPOINTPROCESSING, OnUpdateViewHalfFloatingPointProcessing) - ON_UPDATE_COMMAND_UI(ID_VIEW_ENABLEFRAMETIMECORRECTION, OnUpdateViewEnableFrameTimeCorrection) - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNC, OnUpdateViewVSync) - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET, OnUpdateViewVSyncOffset) - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCACCURATE, OnUpdateViewVSyncAccurate) - - ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZEVIDEO, OnUpdateViewSynchronizeVideo) - ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZEDISPLAY, OnUpdateViewSynchronizeDisplay) - ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZENEAREST, OnUpdateViewSynchronizeNearest) - - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_ENABLE, OnUpdateViewColorManagementEnable) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_AUTO, OnUpdateViewColorManagementInput) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_HDTV, OnUpdateViewColorManagementInput) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_SDTV_NTSC, OnUpdateViewColorManagementInput) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_SDTV_PAL, OnUpdateViewColorManagementInput) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_BRIGHT, OnUpdateViewColorManagementAmbientLight) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_DIM, OnUpdateViewColorManagementAmbientLight) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_DARK, OnUpdateViewColorManagementAmbientLight) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_PERCEPTUAL, OnUpdateViewColorManagementIntent) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC, OnUpdateViewColorManagementIntent) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_SATURATION, OnUpdateViewColorManagementIntent) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC, OnUpdateViewColorManagementIntent) - - ON_UPDATE_COMMAND_UI(ID_VIEW_EVROUTPUTRANGE_0_255, OnUpdateViewEVROutputRange) - ON_UPDATE_COMMAND_UI(ID_VIEW_EVROUTPUTRANGE_16_235, OnUpdateViewEVROutputRange) - - ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_BEFOREVSYNC, OnUpdateViewFlushGPU) - ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_AFTERPRESENT, OnUpdateViewFlushGPU) - ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_WAIT, OnUpdateViewFlushGPU) - - ON_UPDATE_COMMAND_UI(ID_VIEW_D3DFULLSCREEN, OnUpdateViewD3DFullscreen) - ON_UPDATE_COMMAND_UI(ID_VIEW_DISABLEDESKTOPCOMPOSITION, OnUpdateViewDisableDesktopComposition) - ON_UPDATE_COMMAND_UI(ID_VIEW_ALTERNATIVEVSYNC, OnUpdateViewAlternativeVSync) - - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET_INCREASE, OnUpdateViewVSyncOffsetIncrease) - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET_DECREASE, OnUpdateViewVSyncOffsetDecrease) - ON_COMMAND(ID_VIEW_FULLSCREENGUISUPPORT, OnViewFullscreenGUISupport) - ON_COMMAND(ID_VIEW_HIGHCOLORRESOLUTION, OnViewHighColorResolution) - ON_COMMAND(ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION, OnViewForceInputHighColorResolution) - ON_COMMAND(ID_VIEW_FULLFLOATINGPOINTPROCESSING, OnViewFullFloatingPointProcessing) - ON_COMMAND(ID_VIEW_HALFFLOATINGPOINTPROCESSING, OnViewHalfFloatingPointProcessing) - ON_COMMAND(ID_VIEW_ENABLEFRAMETIMECORRECTION, OnViewEnableFrameTimeCorrection) - ON_COMMAND(ID_VIEW_VSYNC, OnViewVSync) - ON_COMMAND(ID_VIEW_VSYNCACCURATE, OnViewVSyncAccurate) - - ON_COMMAND(ID_VIEW_SYNCHRONIZEVIDEO, OnViewSynchronizeVideo) - ON_COMMAND(ID_VIEW_SYNCHRONIZEDISPLAY, OnViewSynchronizeDisplay) - ON_COMMAND(ID_VIEW_SYNCHRONIZENEAREST, OnViewSynchronizeNearest) - - ON_COMMAND(ID_VIEW_CM_ENABLE, OnViewColorManagementEnable) - ON_COMMAND(ID_VIEW_CM_INPUT_AUTO, OnViewColorManagementInputAuto) - ON_COMMAND(ID_VIEW_CM_INPUT_HDTV, OnViewColorManagementInputHDTV) - ON_COMMAND(ID_VIEW_CM_INPUT_SDTV_NTSC, OnViewColorManagementInputSDTV_NTSC) - ON_COMMAND(ID_VIEW_CM_INPUT_SDTV_PAL, OnViewColorManagementInputSDTV_PAL) - ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_BRIGHT, OnViewColorManagementAmbientLightBright) - ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_DIM, OnViewColorManagementAmbientLightDim) - ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_DARK, OnViewColorManagementAmbientLightDark) - ON_COMMAND(ID_VIEW_CM_INTENT_PERCEPTUAL, OnViewColorManagementIntentPerceptual) - ON_COMMAND(ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC, OnViewColorManagementIntentRelativeColorimetric) - ON_COMMAND(ID_VIEW_CM_INTENT_SATURATION, OnViewColorManagementIntentSaturation) - ON_COMMAND(ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC, OnViewColorManagementIntentAbsoluteColorimetric) - - ON_COMMAND(ID_VIEW_EVROUTPUTRANGE_0_255, OnViewEVROutputRange_0_255) - ON_COMMAND(ID_VIEW_EVROUTPUTRANGE_16_235, OnViewEVROutputRange_16_235) - - ON_COMMAND(ID_VIEW_FLUSHGPU_BEFOREVSYNC, OnViewFlushGPUBeforeVSync) - ON_COMMAND(ID_VIEW_FLUSHGPU_AFTERPRESENT, OnViewFlushGPUAfterVSync) - ON_COMMAND(ID_VIEW_FLUSHGPU_WAIT, OnViewFlushGPUWait) - - ON_COMMAND(ID_VIEW_D3DFULLSCREEN, OnViewD3DFullScreen) - ON_COMMAND(ID_VIEW_DISABLEDESKTOPCOMPOSITION, OnViewDisableDesktopComposition) - ON_COMMAND(ID_VIEW_ALTERNATIVEVSYNC, OnViewAlternativeVSync) - ON_COMMAND(ID_VIEW_RESET_DEFAULT, OnViewResetDefault) - ON_COMMAND(ID_VIEW_RESET_OPTIMAL, OnViewResetOptimal) - - ON_COMMAND(ID_VIEW_VSYNCOFFSET_INCREASE, OnViewVSyncOffsetIncrease) - ON_COMMAND(ID_VIEW_VSYNCOFFSET_DECREASE, OnViewVSyncOffsetDecrease) - ON_UPDATE_COMMAND_UI(ID_PRESIZE_SHADERS_TOGGLE, OnUpdateShaderToggle1) - ON_COMMAND(ID_PRESIZE_SHADERS_TOGGLE, OnShaderToggle1) - ON_UPDATE_COMMAND_UI(ID_POSTSIZE_SHADERS_TOGGLE, OnUpdateShaderToggle2) - ON_COMMAND(ID_POSTSIZE_SHADERS_TOGGLE, OnShaderToggle2) - ON_UPDATE_COMMAND_UI(ID_VIEW_OSD_DISPLAY_TIME, OnUpdateViewOSDDisplayTime) - ON_COMMAND(ID_VIEW_OSD_DISPLAY_TIME, OnViewOSDDisplayTime) - ON_UPDATE_COMMAND_UI(ID_VIEW_OSD_SHOW_FILENAME, OnUpdateViewOSDShowFileName) - ON_COMMAND(ID_VIEW_OSD_SHOW_FILENAME, OnViewOSDShowFileName) - ON_COMMAND(ID_D3DFULLSCREEN_TOGGLE, OnD3DFullscreenToggle) - ON_COMMAND_RANGE(ID_GOTO_PREV_SUB, ID_GOTO_NEXT_SUB, OnGotoSubtitle) - ON_COMMAND_RANGE(ID_SUBRESYNC_SHIFT_DOWN, ID_SUBRESYNC_SHIFT_UP, OnSubresyncShiftSub) - ON_COMMAND_RANGE(ID_SUB_DELAY_DOWN, ID_SUB_DELAY_UP, OnSubtitleDelay) - ON_COMMAND_RANGE(ID_SUB_POS_DOWN, ID_SUB_POS_UP, OnSubtitlePos) - ON_COMMAND_RANGE(ID_SUB_FONT_SIZE_DEC, ID_SUB_FONT_SIZE_INC, OnSubtitleFontSize) - - ON_COMMAND(ID_PLAY_PLAY, OnPlayPlay) - ON_COMMAND(ID_PLAY_PAUSE, OnPlayPause) - ON_COMMAND(ID_PLAY_PLAYPAUSE, OnPlayPlaypause) - ON_COMMAND(ID_PLAY_STOP, OnPlayStop) - ON_UPDATE_COMMAND_UI(ID_PLAY_PLAY, OnUpdatePlayPauseStop) - ON_UPDATE_COMMAND_UI(ID_PLAY_PAUSE, OnUpdatePlayPauseStop) - ON_UPDATE_COMMAND_UI(ID_PLAY_PLAYPAUSE, OnUpdatePlayPauseStop) - ON_UPDATE_COMMAND_UI(ID_PLAY_STOP, OnUpdatePlayPauseStop) - ON_COMMAND_RANGE(ID_PLAY_FRAMESTEP, ID_PLAY_FRAMESTEP_BACK, OnPlayFramestep) - ON_UPDATE_COMMAND_UI(ID_PLAY_FRAMESTEP, OnUpdatePlayFramestep) - ON_COMMAND_RANGE(ID_PLAY_SEEKBACKWARDSMALL, ID_PLAY_SEEKFORWARDLARGE, OnPlaySeek) - ON_COMMAND(ID_PLAY_SEEKSET, OnPlaySeekSet) - ON_COMMAND_RANGE(ID_PLAY_SEEKKEYBACKWARD, ID_PLAY_SEEKKEYFORWARD, OnPlaySeekKey) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_SEEKBACKWARDSMALL, ID_PLAY_SEEKFORWARDLARGE, OnUpdatePlaySeek) - ON_UPDATE_COMMAND_UI(ID_PLAY_SEEKSET, OnUpdatePlaySeek) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_SEEKKEYBACKWARD, ID_PLAY_SEEKKEYFORWARD, OnUpdatePlaySeek) - ON_COMMAND_RANGE(ID_PLAY_DECRATE, ID_PLAY_INCRATE, OnPlayChangeRate) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_DECRATE, ID_PLAY_INCRATE, OnUpdatePlayChangeRate) - ON_COMMAND_RANGE(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, OnPlayChangeRate) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, OnUpdatePlayChangeRate) - ON_COMMAND(ID_PLAY_RESETRATE, OnPlayResetRate) - ON_UPDATE_COMMAND_UI(ID_PLAY_RESETRATE, OnUpdatePlayResetRate) - ON_COMMAND_RANGE(ID_PLAY_INCAUDDELAY, ID_PLAY_DECAUDDELAY, OnPlayChangeAudDelay) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_INCAUDDELAY, ID_PLAY_DECAUDDELAY, OnUpdatePlayChangeAudDelay) - ON_COMMAND(ID_FILTERS_COPY_TO_CLIPBOARD, OnPlayFiltersCopyToClipboard) - ON_COMMAND_RANGE(ID_FILTERS_SUBITEM_START, ID_FILTERS_SUBITEM_END, OnPlayFilters) - ON_UPDATE_COMMAND_UI_RANGE(ID_FILTERS_SUBITEM_START, ID_FILTERS_SUBITEM_END, OnUpdatePlayFilters) - ON_COMMAND(ID_SHADERS_SELECT, OnPlayShadersSelect) - ON_COMMAND(ID_SHADERS_PRESET_NEXT, OnPlayShadersPresetNext) - ON_COMMAND(ID_SHADERS_PRESET_PREV, OnPlayShadersPresetPrev) - ON_COMMAND_RANGE(ID_SHADERS_PRESETS_START, ID_SHADERS_PRESETS_END, OnPlayShadersPresets) - ON_COMMAND_RANGE(ID_AUDIO_SUBITEM_START, ID_AUDIO_SUBITEM_END, OnPlayAudio) - ON_COMMAND_RANGE(ID_SUBTITLES_SUBITEM_START, ID_SUBTITLES_SUBITEM_END, OnPlaySubtitles) - ON_COMMAND(ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE, OnSubtitlesDefaultStyle) - ON_COMMAND_RANGE(ID_VIDEO_STREAMS_SUBITEM_START, ID_VIDEO_STREAMS_SUBITEM_END, OnPlayVideoStreams) - ON_COMMAND_RANGE(ID_FILTERSTREAMS_SUBITEM_START, ID_FILTERSTREAMS_SUBITEM_END, OnPlayFiltersStreams) - ON_COMMAND_RANGE(ID_VOLUME_UP, ID_VOLUME_MUTE, OnPlayVolume) - ON_COMMAND_RANGE(ID_VOLUME_BOOST_INC, ID_VOLUME_BOOST_MAX, OnPlayVolumeBoost) - ON_UPDATE_COMMAND_UI_RANGE(ID_VOLUME_BOOST_INC, ID_VOLUME_BOOST_MAX, OnUpdatePlayVolumeBoost) - ON_COMMAND(ID_CUSTOM_CHANNEL_MAPPING, OnCustomChannelMapping) - ON_UPDATE_COMMAND_UI(ID_CUSTOM_CHANNEL_MAPPING, OnUpdateCustomChannelMapping) - ON_COMMAND_RANGE(ID_NORMALIZE, ID_REGAIN_VOLUME, OnNormalizeRegainVolume) - ON_UPDATE_COMMAND_UI_RANGE(ID_NORMALIZE, ID_REGAIN_VOLUME, OnUpdateNormalizeRegainVolume) - ON_COMMAND_RANGE(ID_COLOR_BRIGHTNESS_INC, ID_COLOR_RESET, OnPlayColor) - ON_UPDATE_COMMAND_UI_RANGE(ID_AFTERPLAYBACK_EXIT, ID_AFTERPLAYBACK_MONITOROFF, OnUpdateAfterplayback) - ON_COMMAND_RANGE(ID_AFTERPLAYBACK_EXIT, ID_AFTERPLAYBACK_MONITOROFF, OnAfterplayback) - ON_UPDATE_COMMAND_UI_RANGE(ID_AFTERPLAYBACK_PLAYNEXT, ID_AFTERPLAYBACK_DONOTHING, OnUpdateAfterplayback) - ON_COMMAND_RANGE(ID_AFTERPLAYBACK_PLAYNEXT, ID_AFTERPLAYBACK_DONOTHING, OnAfterplayback) - ON_COMMAND_RANGE(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, OnPlayRepeat) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, OnUpdatePlayRepeat) - ON_COMMAND_RANGE(ID_PLAY_REPEAT_AB, ID_PLAY_REPEAT_AB_MARK_B, OnABRepeat) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_REPEAT_AB, ID_PLAY_REPEAT_AB_MARK_B, OnUpdateABRepeat) - ON_COMMAND(ID_PLAY_REPEAT_FOREVER, OnPlayRepeatForever) - ON_UPDATE_COMMAND_UI(ID_PLAY_REPEAT_FOREVER, OnUpdatePlayRepeatForever) - - ON_COMMAND_RANGE(ID_NAVIGATE_SKIPBACK, ID_NAVIGATE_SKIPFORWARD, OnNavigateSkip) - ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_SKIPBACK, ID_NAVIGATE_SKIPFORWARD, OnUpdateNavigateSkip) - ON_COMMAND_RANGE(ID_NAVIGATE_SKIPBACKFILE, ID_NAVIGATE_SKIPFORWARDFILE, OnNavigateSkipFile) - ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_SKIPBACKFILE, ID_NAVIGATE_SKIPFORWARDFILE, OnUpdateNavigateSkipFile) - ON_COMMAND(ID_NAVIGATE_GOTO, OnNavigateGoto) - ON_UPDATE_COMMAND_UI(ID_NAVIGATE_GOTO, OnUpdateNavigateGoto) - ON_COMMAND_RANGE(ID_NAVIGATE_TITLEMENU, ID_NAVIGATE_CHAPTERMENU, OnNavigateMenu) - ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_TITLEMENU, ID_NAVIGATE_CHAPTERMENU, OnUpdateNavigateMenu) - ON_COMMAND_RANGE(ID_NAVIGATE_JUMPTO_SUBITEM_START, ID_NAVIGATE_JUMPTO_SUBITEM_END, OnNavigateJumpTo) - ON_COMMAND_RANGE(ID_NAVIGATE_MENU_LEFT, ID_NAVIGATE_MENU_LEAVE, OnNavigateMenuItem) - ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_MENU_LEFT, ID_NAVIGATE_MENU_LEAVE, OnUpdateNavigateMenuItem) - - ON_COMMAND(ID_NAVIGATE_TUNERSCAN, OnTunerScan) - ON_UPDATE_COMMAND_UI(ID_NAVIGATE_TUNERSCAN, OnUpdateTunerScan) - - ON_COMMAND(ID_FAVORITES_ADD, OnFavoritesAdd) - ON_UPDATE_COMMAND_UI(ID_FAVORITES_ADD, OnUpdateFavoritesAdd) - ON_COMMAND(ID_FAVORITES_QUICKADDFAVORITE, OnFavoritesQuickAddFavorite) - ON_COMMAND(ID_FAVORITES_ORGANIZE, OnFavoritesOrganize) - ON_UPDATE_COMMAND_UI(ID_FAVORITES_ORGANIZE, OnUpdateFavoritesOrganize) - ON_COMMAND_RANGE(ID_FAVORITES_FILE_START, ID_FAVORITES_FILE_END, OnFavoritesFile) - ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_FILE_START, ID_FAVORITES_FILE_END, OnUpdateFavoritesFile) - ON_COMMAND_RANGE(ID_FAVORITES_DVD_START, ID_FAVORITES_DVD_END, OnFavoritesDVD) - ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_DVD_START, ID_FAVORITES_DVD_END, OnUpdateFavoritesDVD) - ON_COMMAND_RANGE(ID_FAVORITES_DEVICE_START, ID_FAVORITES_DEVICE_END, OnFavoritesDevice) - ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_DEVICE_START, ID_FAVORITES_DEVICE_END, OnUpdateFavoritesDevice) - - ON_COMMAND(ID_RECENT_FILES_CLEAR, OnRecentFileClear) - ON_UPDATE_COMMAND_UI(ID_RECENT_FILES_CLEAR, OnUpdateRecentFileClear) - ON_COMMAND_RANGE(ID_RECENT_FILE_START, ID_RECENT_FILE_END, OnRecentFile) - ON_UPDATE_COMMAND_UI_RANGE(ID_RECENT_FILE_START, ID_RECENT_FILE_END, OnUpdateRecentFile) - - ON_COMMAND(ID_HELP_HOMEPAGE, OnHelpHomepage) - ON_COMMAND(ID_HELP_CHECKFORUPDATE, OnHelpCheckForUpdate) - ON_COMMAND(ID_HELP_TOOLBARIMAGES, OnHelpToolbarImages) - ON_COMMAND(ID_HELP_DONATE, OnHelpDonate) - - // Open Dir incl. SubDir - ON_COMMAND(ID_FILE_OPENDIRECTORY, OnFileOpendirectory) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENDIRECTORY, OnUpdateFileOpen) - ON_WM_POWERBROADCAST() - - // Navigation panel - ON_COMMAND(ID_VIEW_NAVIGATION, OnViewNavigation) - ON_UPDATE_COMMAND_UI(ID_VIEW_NAVIGATION, OnUpdateViewNavigation) - - ON_WM_WTSSESSION_CHANGE() - - ON_MESSAGE(WM_LOADSUBTITLES, OnLoadSubtitles) - ON_MESSAGE(WM_GETSUBTITLES, OnGetSubtitles) - ON_WM_DRAWITEM() - ON_WM_SETTINGCHANGE() - ON_WM_MOUSEHWHEEL() -END_MESSAGE_MAP() - -#ifdef _DEBUG -const TCHAR* GetEventString(LONG evCode) -{ -#define UNPACK_VALUE(VALUE) case VALUE: return _T(#VALUE); - switch (evCode) { - // System-defined event codes - UNPACK_VALUE(EC_COMPLETE); - UNPACK_VALUE(EC_USERABORT); - UNPACK_VALUE(EC_ERRORABORT); - //UNPACK_VALUE(EC_TIME); - UNPACK_VALUE(EC_REPAINT); - UNPACK_VALUE(EC_STREAM_ERROR_STOPPED); - UNPACK_VALUE(EC_STREAM_ERROR_STILLPLAYING); - UNPACK_VALUE(EC_ERROR_STILLPLAYING); - UNPACK_VALUE(EC_PALETTE_CHANGED); - UNPACK_VALUE(EC_VIDEO_SIZE_CHANGED); - UNPACK_VALUE(EC_QUALITY_CHANGE); - UNPACK_VALUE(EC_SHUTTING_DOWN); - UNPACK_VALUE(EC_CLOCK_CHANGED); - UNPACK_VALUE(EC_PAUSED); - UNPACK_VALUE(EC_OPENING_FILE); - UNPACK_VALUE(EC_BUFFERING_DATA); - UNPACK_VALUE(EC_FULLSCREEN_LOST); - UNPACK_VALUE(EC_ACTIVATE); - UNPACK_VALUE(EC_NEED_RESTART); - UNPACK_VALUE(EC_WINDOW_DESTROYED); - UNPACK_VALUE(EC_DISPLAY_CHANGED); - UNPACK_VALUE(EC_STARVATION); - UNPACK_VALUE(EC_OLE_EVENT); - UNPACK_VALUE(EC_NOTIFY_WINDOW); - UNPACK_VALUE(EC_STREAM_CONTROL_STOPPED); - UNPACK_VALUE(EC_STREAM_CONTROL_STARTED); - UNPACK_VALUE(EC_END_OF_SEGMENT); - UNPACK_VALUE(EC_SEGMENT_STARTED); - UNPACK_VALUE(EC_LENGTH_CHANGED); - UNPACK_VALUE(EC_DEVICE_LOST); - UNPACK_VALUE(EC_SAMPLE_NEEDED); - UNPACK_VALUE(EC_PROCESSING_LATENCY); - UNPACK_VALUE(EC_SAMPLE_LATENCY); - UNPACK_VALUE(EC_SCRUB_TIME); - UNPACK_VALUE(EC_STEP_COMPLETE); - UNPACK_VALUE(EC_TIMECODE_AVAILABLE); - UNPACK_VALUE(EC_EXTDEVICE_MODE_CHANGE); - UNPACK_VALUE(EC_STATE_CHANGE); - UNPACK_VALUE(EC_GRAPH_CHANGED); - UNPACK_VALUE(EC_CLOCK_UNSET); - UNPACK_VALUE(EC_VMR_RENDERDEVICE_SET); - UNPACK_VALUE(EC_VMR_SURFACE_FLIPPED); - UNPACK_VALUE(EC_VMR_RECONNECTION_FAILED); - UNPACK_VALUE(EC_PREPROCESS_COMPLETE); - UNPACK_VALUE(EC_CODECAPI_EVENT); - UNPACK_VALUE(EC_WMT_INDEX_EVENT); - UNPACK_VALUE(EC_WMT_EVENT); - UNPACK_VALUE(EC_BUILT); - UNPACK_VALUE(EC_UNBUILT); - UNPACK_VALUE(EC_SKIP_FRAMES); - UNPACK_VALUE(EC_PLEASE_REOPEN); - UNPACK_VALUE(EC_STATUS); - UNPACK_VALUE(EC_MARKER_HIT); - UNPACK_VALUE(EC_LOADSTATUS); - UNPACK_VALUE(EC_FILE_CLOSED); - UNPACK_VALUE(EC_ERRORABORTEX); - //UNPACK_VALUE(EC_NEW_PIN); - //UNPACK_VALUE(EC_RENDER_FINISHED); - UNPACK_VALUE(EC_EOS_SOON); - UNPACK_VALUE(EC_CONTENTPROPERTY_CHANGED); - UNPACK_VALUE(EC_BANDWIDTHCHANGE); - UNPACK_VALUE(EC_VIDEOFRAMEREADY); - // DVD-Video event codes - UNPACK_VALUE(EC_DVD_DOMAIN_CHANGE); - UNPACK_VALUE(EC_DVD_TITLE_CHANGE); - UNPACK_VALUE(EC_DVD_CHAPTER_START); - UNPACK_VALUE(EC_DVD_AUDIO_STREAM_CHANGE); - UNPACK_VALUE(EC_DVD_SUBPICTURE_STREAM_CHANGE); - UNPACK_VALUE(EC_DVD_ANGLE_CHANGE); - UNPACK_VALUE(EC_DVD_BUTTON_CHANGE); - UNPACK_VALUE(EC_DVD_VALID_UOPS_CHANGE); - UNPACK_VALUE(EC_DVD_STILL_ON); - UNPACK_VALUE(EC_DVD_STILL_OFF); - UNPACK_VALUE(EC_DVD_CURRENT_TIME); - UNPACK_VALUE(EC_DVD_ERROR); - UNPACK_VALUE(EC_DVD_WARNING); - UNPACK_VALUE(EC_DVD_CHAPTER_AUTOSTOP); - UNPACK_VALUE(EC_DVD_NO_FP_PGC); - UNPACK_VALUE(EC_DVD_PLAYBACK_RATE_CHANGE); - UNPACK_VALUE(EC_DVD_PARENTAL_LEVEL_CHANGE); - UNPACK_VALUE(EC_DVD_PLAYBACK_STOPPED); - UNPACK_VALUE(EC_DVD_ANGLES_AVAILABLE); - UNPACK_VALUE(EC_DVD_PLAYPERIOD_AUTOSTOP); - UNPACK_VALUE(EC_DVD_BUTTON_AUTO_ACTIVATED); - UNPACK_VALUE(EC_DVD_CMD_START); - UNPACK_VALUE(EC_DVD_CMD_END); - UNPACK_VALUE(EC_DVD_DISC_EJECTED); - UNPACK_VALUE(EC_DVD_DISC_INSERTED); - UNPACK_VALUE(EC_DVD_CURRENT_HMSF_TIME); - UNPACK_VALUE(EC_DVD_KARAOKE_MODE); - UNPACK_VALUE(EC_DVD_PROGRAM_CELL_CHANGE); - UNPACK_VALUE(EC_DVD_TITLE_SET_CHANGE); - UNPACK_VALUE(EC_DVD_PROGRAM_CHAIN_CHANGE); - UNPACK_VALUE(EC_DVD_VOBU_Offset); - UNPACK_VALUE(EC_DVD_VOBU_Timestamp); - UNPACK_VALUE(EC_DVD_GPRM_Change); - UNPACK_VALUE(EC_DVD_SPRM_Change); - UNPACK_VALUE(EC_DVD_BeginNavigationCommands); - UNPACK_VALUE(EC_DVD_NavigationCommand); - // Sound device error event codes - UNPACK_VALUE(EC_SNDDEV_IN_ERROR); - UNPACK_VALUE(EC_SNDDEV_OUT_ERROR); - // Custom event codes - UNPACK_VALUE(EC_BG_AUDIO_CHANGED); - UNPACK_VALUE(EC_BG_ERROR); - }; -#undef UNPACK_VALUE - return _T("UNKNOWN"); -} -#endif - -void CMainFrame::EventCallback(MpcEvent ev) -{ - const auto& s = AfxGetAppSettings(); - switch (ev) { - case MpcEvent::SHADER_SELECTION_CHANGED: - case MpcEvent::SHADER_PRERESIZE_SELECTION_CHANGED: - case MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED: - SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); - break; - case MpcEvent::DISPLAY_MODE_AUTOCHANGING: - if (GetLoadState() == MLS::LOADED && GetMediaState() == State_Running && s.autoChangeFSMode.uDelay) { - // pause if the mode is being changed during playback - OnPlayPause(); - m_bPausedForAutochangeMonitorMode = true; - } - break; - case MpcEvent::DISPLAY_MODE_AUTOCHANGED: - if (GetLoadState() == MLS::LOADED) { - if (m_bPausedForAutochangeMonitorMode && s.autoChangeFSMode.uDelay) { - // delay play if was paused due to mode change - ASSERT(GetMediaState() != State_Stopped); - const unsigned uModeChangeDelay = s.autoChangeFSMode.uDelay * 1000; - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, - std::bind(&CMainFrame::OnPlayPlay, this), uModeChangeDelay); - } else if (m_bDelaySetOutputRect) { - ASSERT(GetMediaState() == State_Stopped); - // tell OnFilePostOpenmedia() to delay entering play or paused state - m_bOpeningInAutochangedMonitorMode = true; - } - } - break; - case MpcEvent::CHANGING_UI_LANGUAGE: - UpdateUILanguage(); - break; - case MpcEvent::STREAM_POS_UPDATE_REQUEST: - OnTimer(TIMER_STREAMPOSPOLLER); - OnTimer(TIMER_STREAMPOSPOLLER2); - break; - default: - ASSERT(FALSE); - } -} - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame construction/destruction - -CMainFrame::CMainFrame() - : m_timerHider(this, TIMER_HIDER, 200) - , m_timerOneTime(this, TIMER_ONETIME_START, TIMER_ONETIME_END - TIMER_ONETIME_START + 1) - , m_bUsingDXVA(false) - , m_HWAccelType(nullptr) - , m_posFirstExtSub(nullptr) - , m_bDelaySetOutputRect(false) - , m_nJumpToSubMenusCount(0) - , m_nLoops(0) - , m_nLastSkipDirection(0) - , m_fCustomGraph(false) - , m_fShockwaveGraph(false) - , m_fFrameSteppingActive(false) - , m_nStepForwardCount(0) - , m_rtStepForwardStart(0) - , m_nVolumeBeforeFrameStepping(0) - , m_fEndOfStream(false) - , m_dwLastPause(0) - , m_dwReloadPos(0) - , m_iReloadAudioIdx(-1) - , m_iReloadSubIdx(-1) - , m_bRememberFilePos(false) - , m_dwLastRun(0) - , m_bBuffering(false) - , m_fLiveWM(false) - , m_rtDurationOverride(-1) - , m_iPlaybackMode(PM_NONE) - , m_lCurrentChapter(0) - , m_lChapterStartTime(0xFFFFFFFF) - , m_eMediaLoadState(MLS::CLOSED) - , m_CachedFilterState(-1) - , m_bSettingUpMenus(false) - , m_bOpenMediaActive(false) - , m_OpenMediaFailedCount(0) - , m_fFullScreen(false) - , m_bFullScreenWindowIsD3D(false) - , m_bFullScreenWindowIsOnSeparateDisplay(false) - , m_bNeedZoomAfterFullscreenExit(false) - , m_fStartInD3DFullscreen(false) - , m_fStartInFullscreenSeparate(false) - , m_pLastBar(nullptr) - , m_bFirstPlay(false) - , m_bOpeningInAutochangedMonitorMode(false) - , m_bPausedForAutochangeMonitorMode(false) - , m_fAudioOnly(true) - , m_iDVDDomain(DVD_DOMAIN_Stop) - , m_iDVDTitle(0) - , m_bDVDStillOn(false) - , m_dSpeedRate(1.0) - , m_ZoomX(1.0) - , m_ZoomY(1.0) - , m_PosX(0.5) - , m_PosY(0.5) - , m_AngleX(0) - , m_AngleY(0) - , m_AngleZ(0) - , m_iDefRotation(0) - , m_pGraphThread(nullptr) - , m_bOpenedThroughThread(false) - , m_evOpenPrivateFinished(FALSE, TRUE) - , m_evClosePrivateFinished(FALSE, TRUE) - , m_fOpeningAborted(false) - , m_bWasSnapped(false) - , m_wndSubtitlesDownloadDialog(this) - //, m_wndSubtitlesUploadDialog(this) - , m_wndFavoriteOrganizeDialog(this) - , m_bTrayIcon(false) - , m_fCapturing(false) - , m_controls(this) - , m_wndView(this) - , m_wndSeekBar(this) - , m_wndToolBar(this) - , m_wndInfoBar(this) - , m_wndStatsBar(this) - , m_wndStatusBar(this) - , m_wndSubresyncBar(this) - , m_wndPlaylistBar(this) - , m_wndPreView(this) - , m_wndCaptureBar(this) - , m_wndNavigationBar(this) - , m_pVideoWnd(nullptr) - , m_pOSDWnd(nullptr) - , m_pDedicatedFSVideoWnd(nullptr) - , m_OSD(this) - , m_nCurSubtitle(-1) - , m_lSubtitleShift(0) - , m_rtCurSubPos(0) - , m_bScanDlgOpened(false) - , m_bStopTunerScan(false) - , m_bLockedZoomVideoWindow(false) - , m_nLockedZoomVideoWindow(0) - , m_pActiveContextMenu(nullptr) - , m_pActiveSystemMenu(nullptr) - , m_bAltDownClean(false) - , m_bShowingFloatingMenubar(false) - , m_bAllowWindowZoom(false) - , m_dLastVideoScaleFactor(0) - , m_bExtOnTop(false) - , m_bIsBDPlay(false) - , m_bHasBDMeta(false) - , watchingDialog(themableDialogTypes::None) - , dialogHookHelper(nullptr) - , delayingFullScreen(false) - , restoringWindowRect(false) - , mediaTypesErrorDlg(nullptr) - , m_iStreamPosPollerInterval(100) - , currentAudioLang(_T("")) - , currentSubLang(_T("")) - , m_bToggleShader(false) - , m_bToggleShaderScreenSpace(false) - , m_MPLSPlaylist() - , m_sydlLastProcessURL() - , m_bUseSeekPreview(false) - , queuedSeek({0,0,false}) - , lastSeekStart(0) - , lastSeekFinish(0) - , defaultVideoAngle(0) - , m_media_trans_control() - , recentFilesMenuFromMRUSequence(-1) -{ - // Don't let CFrameWnd handle automatically the state of the menu items. - // This means that menu items without handlers won't be automatically - // disabled but it avoids some unwanted cases where programmatically - // disabled menu items are always re-enabled by CFrameWnd. - m_bAutoMenuEnable = FALSE; - - EventRouter::EventSelection receives; - receives.insert(MpcEvent::SHADER_SELECTION_CHANGED); - receives.insert(MpcEvent::SHADER_PRERESIZE_SELECTION_CHANGED); - receives.insert(MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED); - receives.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGING); - receives.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGED); - receives.insert(MpcEvent::CHANGING_UI_LANGUAGE); - receives.insert(MpcEvent::STREAM_POS_UPDATE_REQUEST); - EventRouter::EventSelection fires; - fires.insert(MpcEvent::SWITCHING_TO_FULLSCREEN); - fires.insert(MpcEvent::SWITCHED_TO_FULLSCREEN); - fires.insert(MpcEvent::SWITCHING_FROM_FULLSCREEN); - fires.insert(MpcEvent::SWITCHED_FROM_FULLSCREEN); - fires.insert(MpcEvent::SWITCHING_TO_FULLSCREEN_D3D); - fires.insert(MpcEvent::SWITCHED_TO_FULLSCREEN_D3D); - fires.insert(MpcEvent::MEDIA_LOADED); - fires.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGING); - fires.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGED); - fires.insert(MpcEvent::CONTEXT_MENU_POPUP_INITIALIZED); - fires.insert(MpcEvent::CONTEXT_MENU_POPUP_UNINITIALIZED); - fires.insert(MpcEvent::SYSTEM_MENU_POPUP_INITIALIZED); - fires.insert(MpcEvent::SYSTEM_MENU_POPUP_UNINITIALIZED); - fires.insert(MpcEvent::DPI_CHANGED); - GetEventd().Connect(m_eventc, receives, std::bind(&CMainFrame::EventCallback, this, std::placeholders::_1), fires); -} - -CMainFrame::~CMainFrame() -{ - if (defaultMPCThemeMenu != nullptr) { - delete defaultMPCThemeMenu; - } -} - -int CMainFrame::OnNcCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (IsWindows10OrGreater()) { - // Tell Windows to automatically handle scaling of non-client areas - // such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10 - const WinapiFunc - fnEnableNonClientDpiScaling = { _T("User32.dll"), "EnableNonClientDpiScaling" }; - - if (fnEnableNonClientDpiScaling) { - fnEnableNonClientDpiScaling(m_hWnd); - } - } - - return __super::OnNcCreate(lpCreateStruct); -} - -int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (__super::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - CMPCThemeUtil::enableWindows10DarkFrame(this); - - if (IsWindows8Point1OrGreater()) { - m_dpi.Override(m_hWnd); - } - - const WinapiFunc - fnChangeWindowMessageFilterEx = { _T("user32.dll"), "ChangeWindowMessageFilterEx" }; - - // allow taskbar messages through UIPI - if (fnChangeWindowMessageFilterEx) { - VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, s_uTaskbarRestart, MSGFLT_ALLOW, nullptr)); - VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, s_uTBBC, MSGFLT_ALLOW, nullptr)); - VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, WM_COMMAND, MSGFLT_ALLOW, nullptr)); - } - - VERIFY(m_popupMenu.LoadMenu(IDR_POPUP)); - VERIFY(m_mainPopupMenu.LoadMenu(IDR_POPUPMAIN)); - CreateDynamicMenus(); - - // 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); - - const CAppSettings& s = AfxGetAppSettings(); - - // Create OSD Window - CreateOSDBar(); - - // Create Preview Window - if (s.fSeekPreview) { - if (m_wndPreView.CreateEx(0, AfxRegisterWndClass(0), nullptr, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CRect(0, 0, 160, 109), this, 0)) { - m_wndPreView.ShowWindow(SW_HIDE); - m_wndPreView.SetRelativeSize(AfxGetAppSettings().iSeekPreviewSize); - } else { - TRACE(_T("Failed to create Preview Window")); - } - } - - // 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 - } - - m_pDedicatedFSVideoWnd = DEBUG_NEW CFullscreenWnd(this); - - m_controls.m_toolbars[CMainFrameControls::Toolbar::SEEKBAR] = &m_wndSeekBar; - m_controls.m_toolbars[CMainFrameControls::Toolbar::CONTROLS] = &m_wndToolBar; - m_controls.m_toolbars[CMainFrameControls::Toolbar::INFO] = &m_wndInfoBar; - m_controls.m_toolbars[CMainFrameControls::Toolbar::STATS] = &m_wndStatsBar; - m_controls.m_toolbars[CMainFrameControls::Toolbar::STATUS] = &m_wndStatusBar; - - // dockable bars - - EnableDocking(CBRS_ALIGN_ANY); - - bResult = m_wndSubresyncBar.Create(this, AFX_IDW_DOCKBAR_TOP, &m_csSubLock); - if (bResult) { - m_wndSubresyncBar.SetBarStyle(m_wndSubresyncBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndSubresyncBar.EnableDocking(CBRS_ALIGN_ANY); - m_wndSubresyncBar.SetHeight(200); - m_controls.m_panels[CMainFrameControls::Panel::SUBRESYNC] = &m_wndSubresyncBar; - } - bResult = bResult && m_wndPlaylistBar.Create(this, AFX_IDW_DOCKBAR_RIGHT); - if (bResult) { - m_wndPlaylistBar.SetBarStyle(m_wndPlaylistBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndPlaylistBar.EnableDocking(CBRS_ALIGN_ANY); - m_wndPlaylistBar.SetWidth(300); - m_controls.m_panels[CMainFrameControls::Panel::PLAYLIST] = &m_wndPlaylistBar; - //m_wndPlaylistBar.LoadPlaylist(GetRecentFile()); //adipose 2019-11-12; do this later after activating the frame - } - bResult = bResult && m_wndEditListEditor.Create(this, AFX_IDW_DOCKBAR_RIGHT); - if (bResult) { - m_wndEditListEditor.SetBarStyle(m_wndEditListEditor.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndEditListEditor.EnableDocking(CBRS_ALIGN_ANY); - m_controls.m_panels[CMainFrameControls::Panel::EDL] = &m_wndEditListEditor; - m_wndEditListEditor.SetHeight(100); - } - bResult = bResult && m_wndCaptureBar.Create(this, AFX_IDW_DOCKBAR_LEFT); - if (bResult) { - m_wndCaptureBar.SetBarStyle(m_wndCaptureBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndCaptureBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); - m_controls.m_panels[CMainFrameControls::Panel::CAPTURE] = &m_wndCaptureBar; - } - bResult = bResult && m_wndNavigationBar.Create(this, AFX_IDW_DOCKBAR_LEFT); - if (bResult) { - m_wndNavigationBar.SetBarStyle(m_wndNavigationBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndNavigationBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); - m_controls.m_panels[CMainFrameControls::Panel::NAVIGATION] = &m_wndNavigationBar; - } - if (!bResult) { - TRACE(_T("Failed to create all dockable bars\n")); - return -1; - } - - // Hide all controls initially - for (const auto& pair : m_controls.m_toolbars) { - pair.second->ShowWindow(SW_HIDE); - } - for (const auto& pair : m_controls.m_panels) { - pair.second->ShowWindow(SW_HIDE); - } - - m_dropTarget.Register(this); - - SetAlwaysOnTop(s.iOnTop); - - ShowTrayIcon(s.fTrayIcon); - - m_Lcd.SetVolumeRange(0, 100); - m_Lcd.SetVolume(std::max(1, s.nVolume)); - - m_pGraphThread = (CGraphThread*)AfxBeginThread(RUNTIME_CLASS(CGraphThread)); - - if (m_pGraphThread) { - m_pGraphThread->SetMainFrame(this); - } - - m_pSubtitlesProviders = std::make_unique(this); - m_wndSubtitlesDownloadDialog.Create(m_wndSubtitlesDownloadDialog.IDD, this, false); - //m_wndSubtitlesUploadDialog.Create(m_wndSubtitlesUploadDialog.IDD, this); - m_wndFavoriteOrganizeDialog.Create(m_wndFavoriteOrganizeDialog.IDD, this, false); - - if (s.nCmdlnWebServerPort != 0) { - if (s.nCmdlnWebServerPort > 0) { - StartWebServer(s.nCmdlnWebServerPort); - } else if (s.fEnableWebServer) { - StartWebServer(s.nWebServerPort); - } - } - - m_bToggleShader = s.bToggleShader; - m_bToggleShaderScreenSpace = s.bToggleShaderScreenSpace; - OpenSetupWindowTitle(true); - - WTSRegisterSessionNotification(); - - UpdateSkypeHandler(); - - m_popupMenu.fulfillThemeReqs(); - m_mainPopupMenu.fulfillThemeReqs(); - - if (s.bUseSMTC) { - m_media_trans_control.Init(this); - } - - return 0; -} - -void CMainFrame::CreateOSDBar() { - if (SUCCEEDED(m_OSD.Create(&m_wndView))) { - m_pOSDWnd = &m_wndView; - } -} - -bool CMainFrame::OSDBarSetPos() { - if (!m_OSD || !(::IsWindow(m_OSD.GetSafeHwnd())) || m_OSD.GetOSDType() != OSD_TYPE_GDI) { - return false; - } - const CAppSettings& s = AfxGetAppSettings(); - - if (s.iDSVideoRendererType == VIDRNDT_DS_MADVR || !m_wndView.IsWindowVisible()) { - if (m_OSD.IsWindowVisible()) { - m_OSD.ShowWindow(SW_HIDE); - } - return false; - } - - CRect r_wndView; - m_wndView.GetWindowRect(&r_wndView); - - int pos = 0; - - CRect MainWndRect; - m_wndView.GetWindowRect(&MainWndRect); - MainWndRect.right -= pos; - m_OSD.SetWndRect(MainWndRect); - if (m_OSD.IsWindowVisible()) { - ::PostMessageW(m_OSD.m_hWnd, WM_OSD_DRAW, WPARAM(0), LPARAM(0)); - } - - return false; -} - -void CMainFrame::DestroyOSDBar() { - if (m_OSD) { - m_OSD.Stop(); - m_OSD.DestroyWindow(); - } -} - -void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) -{ - if (lpMeasureItemStruct->CtlType == ODT_MENU) { - if (CMPCThemeMenu* cm = CMPCThemeMenu::getParentMenu(lpMeasureItemStruct->itemID)) { - cm->MeasureItem(lpMeasureItemStruct); - return; - } - } - - CFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct); -} - -void CMainFrame::OnDestroy() -{ - WTSUnRegisterSessionNotification(); - ShowTrayIcon(false); - m_dropTarget.Revoke(); - - if (m_pDebugShaders && IsWindow(m_pDebugShaders->m_hWnd)) { - VERIFY(m_pDebugShaders->DestroyWindow()); - } - - if (m_pGraphThread) { - CAMMsgEvent e; - m_pGraphThread->PostThreadMessage(CGraphThread::TM_EXIT, (WPARAM)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_ERROR); - } - } - - if (m_pDedicatedFSVideoWnd) { - if (m_pDedicatedFSVideoWnd->IsWindow()) { - m_pDedicatedFSVideoWnd->DestroyWindow(); - } - delete m_pDedicatedFSVideoWnd; - } - - m_wndPreView.DestroyWindow(); - - __super::OnDestroy(); -} - -void CMainFrame::OnClose() -{ - CAppSettings& s = AfxGetAppSettings(); - - s.bToggleShader = m_bToggleShader; - s.bToggleShaderScreenSpace = m_bToggleShaderScreenSpace; - s.dZoomX = m_ZoomX; - s.dZoomY = m_ZoomY; - - m_wndPlaylistBar.SavePlaylist(); - - m_controls.SaveState(); - - m_OSD.OnHide(); - - ShowWindow(SW_HIDE); - - if (GetLoadState() == MLS::LOADED || GetLoadState() == MLS::LOADING) { - CloseMedia(); - } - - m_wndPlaylistBar.ClearExternalPlaylistIfInvalid(); - - 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 - - AfxGetMyApp()->SetClosingState(); - - __super::OnClose(); -} - -LPCTSTR CMainFrame::GetRecentFile() const -{ - auto& MRU = AfxGetAppSettings().MRU; - MRU.ReadMediaHistory(); - for (int i = 0; i < MRU.GetSize(); i++) { - if (MRU[i].fns.GetCount() > 0 && !MRU[i].fns.GetHead().IsEmpty()) { - return MRU[i].fns.GetHead(); - } - } - return nullptr; -} - -LRESULT CMainFrame::OnTaskBarRestart(WPARAM, LPARAM) -{ - m_bTrayIcon = false; - ShowTrayIcon(AfxGetAppSettings().fTrayIcon); - return 0; -} - -LRESULT CMainFrame::OnNotifyIcon(WPARAM wParam, LPARAM lParam) -{ - if (HIWORD(lParam) != IDR_MAINFRAME) { - return -1; - } - - switch (LOWORD(lParam)) { - case WM_LBUTTONDOWN: - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - CreateThumbnailToolbar(); - MoveVideoWindow(); - SetForegroundWindow(); - break; - case WM_LBUTTONDBLCLK: - PostMessage(WM_COMMAND, ID_FILE_OPENMEDIA); - break; - case WM_RBUTTONDOWN: - case WM_CONTEXTMENU: { - SetForegroundWindow(); - m_mainPopupMenu.GetSubMenu(0)->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NOANIMATION, - GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam), GetModalParent()); - PostMessage(WM_NULL); - break; - } - case WM_MBUTTONDOWN: { - OnPlayPlaypause(); - break; - } - case WM_MOUSEMOVE: { - CString str; - GetWindowText(str); - SetTrayTip(str); - break; - } - default: - break; - } - - return 0; -} - -LRESULT CMainFrame::OnTaskBarThumbnailsCreate(WPARAM, LPARAM) -{ - return CreateThumbnailToolbar(); -} - -LRESULT CMainFrame::OnSkypeAttach(WPARAM wParam, LPARAM lParam) -{ - return m_pSkypeMoodMsgHandler ? m_pSkypeMoodMsgHandler->HandleAttach(wParam, lParam) : FALSE; -} - -void CMainFrame::ShowTrayIcon(bool bShow) -{ - NOTIFYICONDATA nid = { sizeof(nid), m_hWnd, IDR_MAINFRAME }; - - if (bShow) { - if (!m_bTrayIcon) { - nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; - nid.uCallbackMessage = WM_NOTIFYICON; - nid.uVersion = NOTIFYICON_VERSION_4; - nid.hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); - StringCchCopy(nid.szTip, _countof(nid.szTip), _T("MPC-HC")); - if (Shell_NotifyIcon(NIM_ADD, &nid) && Shell_NotifyIcon(NIM_SETVERSION, &nid)) { - m_bTrayIcon = true; - } - } - } else { - if (m_bTrayIcon) { - Shell_NotifyIcon(NIM_DELETE, &nid); - m_bTrayIcon = false; - if (IsIconic()) { - // if the window was minimized to tray - show it - ShowWindow(SW_RESTORE); - } - } - } -} - -void CMainFrame::SetTrayTip(const CString& str) -{ - NOTIFYICONDATA tnid; - tnid.cbSize = sizeof(NOTIFYICONDATA); - tnid.hWnd = m_hWnd; - tnid.uID = IDR_MAINFRAME; - tnid.uFlags = NIF_TIP | NIF_SHOWTIP; - StringCchCopy(tnid.szTip, _countof(tnid.szTip), str); - Shell_NotifyIcon(NIM_MODIFY, &tnid); -} - -BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) -{ - if (!__super::PreCreateWindow(cs)) { - return FALSE; - } - - cs.dwExStyle &= ~WS_EX_CLIENTEDGE; - cs.lpszClass = MPC_WND_CLASS_NAME; //AfxRegisterWndClass(nullptr); - - return TRUE; -} - -BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message == WM_KEYDOWN) { - if (pMsg->wParam == VK_ESCAPE) { - bool fEscapeNotAssigned = !AssignedToCmd(VK_ESCAPE); - - if (fEscapeNotAssigned) { - if (IsFullScreenMode()) { - OnViewFullscreen(); - if (GetLoadState() == MLS::LOADED) { - PostMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - return TRUE; - } else if (IsCaptionHidden()) { - PostMessage(WM_COMMAND, ID_VIEW_PRESETS_NORMAL); - return TRUE; - } - } - } else if (pMsg->wParam == VK_LEFT && m_pAMTuner) { - PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACK); - return TRUE; - } else if (pMsg->wParam == VK_RIGHT && m_pAMTuner) { - PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); - return TRUE; - } - } - - if ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_F10 && - m_dwMenuBarState == AFX_MBS_VISIBLE) { - // mfc doesn't hide menubar on f10, but we want to - VERIFY(SetMenuBarState(AFX_MBS_HIDDEN)); - return FALSE; - } - - if (pMsg->message == WM_KEYDOWN) { - m_bAltDownClean = false; - } - if (pMsg->message == WM_SYSKEYDOWN) { - m_bAltDownClean = (pMsg->wParam == VK_MENU); - } - if ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_MENU && - m_dwMenuBarState == AFX_MBS_HIDDEN) { - // mfc shows menubar when Ctrl->Alt->K is released in reverse order, but we don't want to - if (m_bAltDownClean) { - VERIFY(SetMenuBarState(AFX_MBS_VISIBLE)); - return FALSE; - } - return TRUE; - } - - // for compatibility with KatMouse and the like - if (pMsg->message == WM_MOUSEWHEEL && pMsg->hwnd == m_hWnd) { - pMsg->hwnd = m_wndView.m_hWnd; - return FALSE; - } - - return __super::PreTranslateMessage(pMsg); -} - -void CMainFrame::RecalcLayout(BOOL bNotify) -{ - __super::RecalcLayout(bNotify); - - CRect r; - GetWindowRect(&r); - MINMAXINFO mmi; - ZeroMemory(&mmi, sizeof(mmi)); - OnGetMinMaxInfo(&mmi); - const POINT& min = mmi.ptMinTrackSize; - if (r.Height() < min.y || r.Width() < min.x) { - r |= CRect(r.TopLeft(), CSize(min)); - MoveWindow(r); - } - OSDBarSetPos(); -} - -void CMainFrame::EnableDocking(DWORD dwDockStyle) -{ - ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY | CBRS_FLOAT_MULTI)) == 0); - - m_pFloatingFrameClass = RUNTIME_CLASS(CMPCThemeMiniDockFrameWnd); - for (int i = 0; i < 4; i++) { - if (dwDockBarMap[i][1] & dwDockStyle & CBRS_ALIGN_ANY) { - CMPCThemeDockBar* pDock = (CMPCThemeDockBar*)GetControlBar(dwDockBarMap[i][0]); - if (pDock == NULL) { - pDock = DEBUG_NEW CMPCThemeDockBar; - if (!pDock->Create(this, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD | WS_VISIBLE | - dwDockBarMap[i][1], dwDockBarMap[i][0])) { - AfxThrowResourceException(); - } - } - } - } -} - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame diagnostics - -#ifdef _DEBUG -void CMainFrame::AssertValid() const -{ - __super::AssertValid(); -} - -void CMainFrame::Dump(CDumpContext& dc) const -{ - __super::Dump(dc); -} - -#endif //_DEBUG - -typedef HIMC(WINAPI* pfnImmAssociateContext)(HWND, HIMC); -void dynImmAssociateContext(HWND hWnd, HIMC himc) { - HMODULE hImm32; - pfnImmAssociateContext pImmAssociateContext; - - hImm32 = LoadLibrary(_T("imm32.dll")); - if (NULL == hImm32) return; // No East Asian support - pImmAssociateContext = (pfnImmAssociateContext)GetProcAddress(hImm32, "ImmAssociateContext"); - if (NULL == pImmAssociateContext) { - FreeLibrary(hImm32); - return; - } - pImmAssociateContext(hWnd, himc); - FreeLibrary(hImm32); -} - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame message handlers -void CMainFrame::OnSetFocus(CWnd* pOldWnd) -{ - // forward focus to the view window - if (IsWindow(m_wndView.m_hWnd)) { - m_wndView.SetFocus(); - dynImmAssociateContext(m_wndView.m_hWnd, NULL); - } else { - dynImmAssociateContext(m_hWnd, NULL); - } -} - -BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) -{ - // let the view have first crack at the command - if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { - return TRUE; - } - - for (const auto& pair : m_controls.m_toolbars) { - if (pair.second->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { - return TRUE; - } - } - - for (const auto& pair : m_controls.m_panels) { - if (pair.second->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { - return TRUE; - } - } - - // otherwise, do default handling - return __super::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); -} - -void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI) -{ - auto setLarger = [](long & a, long b) { - a = std::max(a, b); - }; - - const long saneSize = 110; - const bool bMenuVisible = GetMenuBarVisibility() == AFX_MBV_KEEPVISIBLE || m_bShowingFloatingMenubar; - - // Begin with docked controls - lpMMI->ptMinTrackSize = CPoint(m_controls.GetDockZonesMinSize(saneSize)); - - if (bMenuVisible) { - // Ensure that menubar will fit horizontally - MENUBARINFO mbi = { sizeof(mbi) }; - GetMenuBarInfo(OBJID_MENU, 0, &mbi); - long x = GetSystemMetrics(SM_CYMENU) / 2; // free space after menu - CRect rect; - for (int i = 0; GetMenuItemRect(m_hWnd, mbi.hMenu, i, &rect); i++) { - x += rect.Width(); - } - setLarger(lpMMI->ptMinTrackSize.x, x); - } - - if (IsWindow(m_wndToolBar) && m_controls.ControlChecked(CMainFrameControls::Toolbar::CONTROLS)) { - // Ensure that Controls toolbar will fit - setLarger(lpMMI->ptMinTrackSize.x, m_wndToolBar.GetMinWidth()); - } - - // Ensure that window decorations will fit - CRect decorationsRect; - VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), bMenuVisible, GetWindowExStyle(m_hWnd))); - lpMMI->ptMinTrackSize.x += decorationsRect.Width(); - lpMMI->ptMinTrackSize.y += decorationsRect.Height(); - - // Final fence - setLarger(lpMMI->ptMinTrackSize.x, GetSystemMetrics(SM_CXMIN)); - setLarger(lpMMI->ptMinTrackSize.y, GetSystemMetrics(SM_CYMIN)); - - lpMMI->ptMaxTrackSize.x = GetSystemMetrics(SM_CXVIRTUALSCREEN) + decorationsRect.Width(); - lpMMI->ptMaxTrackSize.y = GetSystemMetrics(SM_CYVIRTUALSCREEN) - + ((GetStyle() & WS_THICKFRAME) ? GetSystemMetrics(SM_CYSIZEFRAME) : 0); - - OSDBarSetPos(); -} - -void CMainFrame::OnMove(int x, int y) -{ - __super::OnMove(x, y); - - if (m_bWasSnapped && IsZoomed()) { - m_bWasSnapped = false; - } - - WINDOWPLACEMENT wp; - GetWindowPlacement(&wp); - if (!m_bNeedZoomAfterFullscreenExit && !m_fFullScreen && IsWindowVisible() && wp.flags != WPF_RESTORETOMAXIMIZED && wp.showCmd != SW_SHOWMINIMIZED) { - GetWindowRect(AfxGetAppSettings().rcLastWindowPos); - } - - OSDBarSetPos(); -} - -void CMainFrame::OnEnterSizeMove() -{ - if (m_bWasSnapped) { - VERIFY(GetCursorPos(&m_snapStartPoint)); - GetWindowRect(m_snapStartRect); - } -} - -void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect) -{ - if (AfxGetAppSettings().fSnapToDesktopEdges) { - const CSize threshold(m_dpi.ScaleX(16), m_dpi.ScaleY(16)); - - CRect rect(pRect); - - CRect windowRect; - GetWindowRect(windowRect); - - if (windowRect.Size() != rect.Size()) { - // aero snap - return; - } - - CPoint point; - VERIFY(GetCursorPos(&point)); - - if (m_bWasSnapped) { - rect.MoveToXY(point - m_snapStartPoint + m_snapStartRect.TopLeft()); - } - - CRect areaRect; - CMonitors::GetNearestMonitor(this).GetWorkAreaRect(areaRect); - const CRect invisibleBorderSize = GetInvisibleBorderSize(); - areaRect.InflateRect(invisibleBorderSize); - - bool bSnapping = false; - - if (std::abs(rect.left - areaRect.left) < threshold.cx) { - bSnapping = true; - rect.MoveToX(areaRect.left); - } else if (std::abs(rect.right - areaRect.right) < threshold.cx) { - bSnapping = true; - rect.MoveToX(areaRect.right - rect.Width()); - } - if (std::abs(rect.top - areaRect.top) < threshold.cy) { - bSnapping = true; - rect.MoveToY(areaRect.top); - } else if (std::abs(rect.bottom - areaRect.bottom) < threshold.cy) { - bSnapping = true; - rect.MoveToY(areaRect.bottom - rect.Height()); - } - - if (!m_bWasSnapped && bSnapping) { - m_snapStartPoint = point; - m_snapStartRect = pRect; - } - - *pRect = rect; - - m_bWasSnapped = bSnapping; - } else { - m_bWasSnapped = false; - } - - __super::OnMoving(fwSide, pRect); - OSDBarSetPos(); -} - -void CMainFrame::OnSize(UINT nType, int cx, int cy) -{ - if (m_bTrayIcon && nType == SIZE_MINIMIZED) { - ShowWindow(SW_HIDE); - } else { - __super::OnSize(nType, cx, cy); - if (!m_bNeedZoomAfterFullscreenExit && IsWindowVisible() && !m_fFullScreen) { - CAppSettings& s = AfxGetAppSettings(); - if (nType != SIZE_MAXIMIZED && nType != SIZE_MINIMIZED) { - GetWindowRect(s.rcLastWindowPos); - } - s.nLastWindowType = nType; - } - } - if (nType != SIZE_MINIMIZED) { - OSDBarSetPos(); - } -} - -void CMainFrame::OnSizing(UINT nSide, LPRECT lpRect) -{ - __super::OnSizing(nSide, lpRect); - - if (m_fFullScreen) { - return; - } - - bool bCtrl = GetKeyState(VK_CONTROL) < 0; - OnSizingFixWndToVideo(nSide, lpRect, bCtrl); - OnSizingSnapToScreen(nSide, lpRect, bCtrl); -} - -void CMainFrame::OnSizingFixWndToVideo(UINT nSide, LPRECT lpRect, bool bCtrl) -{ - const auto& s = AfxGetAppSettings(); - - if (GetLoadState() != MLS::LOADED || s.iDefaultVideoSize == DVS_STRETCH || - bCtrl == s.fLimitWindowProportions || IsAeroSnapped() || (m_fAudioOnly && !m_wndView.IsCustomImgLoaded())) { - return; - } - - CSize videoSize = m_fAudioOnly ? m_wndView.GetLogoSize() : GetVideoSize(); - if (videoSize.cx == 0 || videoSize.cy == 0) { - return; - } - - CRect currentWindowRect, currentViewRect; - GetWindowRect(currentWindowRect); - m_wndView.GetWindowRect(currentViewRect); - CSize controlsSize(currentWindowRect.Width() - currentViewRect.Width(), - currentWindowRect.Height() - currentViewRect.Height()); - - const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); - const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); - if (bPanelsOnVideo) { - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetVisibleDockZones(uTop, uLeft, uRight, uBottom); - if (!bToolbarsOnVideo) { - uBottom -= m_controls.GetVisibleToolbarsHeight(); - } - controlsSize.cx -= uLeft + uRight; - controlsSize.cy -= uTop + uBottom; - } else if (bToolbarsOnVideo) { - controlsSize.cy -= m_controls.GetVisibleToolbarsHeight(); - } - - CSize newWindowSize(lpRect->right - lpRect->left, lpRect->bottom - lpRect->top); - - newWindowSize -= controlsSize; - - switch (nSide) { - case WMSZ_TOP: - case WMSZ_BOTTOM: - newWindowSize.cx = long(newWindowSize.cy * videoSize.cx / (double)videoSize.cy + 0.5); - newWindowSize.cy = long(newWindowSize.cx * videoSize.cy / (double)videoSize.cx + 0.5); - break; - case WMSZ_TOPLEFT: - case WMSZ_TOPRIGHT: - case WMSZ_BOTTOMLEFT: - case WMSZ_BOTTOMRIGHT: - case WMSZ_LEFT: - case WMSZ_RIGHT: - newWindowSize.cy = long(newWindowSize.cx * videoSize.cy / (double)videoSize.cx + 0.5); - newWindowSize.cx = long(newWindowSize.cy * videoSize.cx / (double)videoSize.cy + 0.5); - break; - } - - newWindowSize += controlsSize; - - switch (nSide) { - case WMSZ_TOPLEFT: - lpRect->left = lpRect->right - newWindowSize.cx; - lpRect->top = lpRect->bottom - newWindowSize.cy; - break; - case WMSZ_TOP: - case WMSZ_TOPRIGHT: - lpRect->right = lpRect->left + newWindowSize.cx; - lpRect->top = lpRect->bottom - newWindowSize.cy; - break; - case WMSZ_RIGHT: - case WMSZ_BOTTOM: - case WMSZ_BOTTOMRIGHT: - lpRect->right = lpRect->left + newWindowSize.cx; - lpRect->bottom = lpRect->top + newWindowSize.cy; - break; - case WMSZ_LEFT: - case WMSZ_BOTTOMLEFT: - lpRect->left = lpRect->right - newWindowSize.cx; - lpRect->bottom = lpRect->top + newWindowSize.cy; - break; - } - OSDBarSetPos(); -} - -void CMainFrame::OnSizingSnapToScreen(UINT nSide, LPRECT lpRect, bool bCtrl /*= false*/) -{ - const auto& s = AfxGetAppSettings(); - if (!s.fSnapToDesktopEdges) - return; - - CRect areaRect; - CMonitors::GetNearestMonitor(this).GetWorkAreaRect(areaRect); - const CRect invisibleBorderSize = GetInvisibleBorderSize(); - areaRect.InflateRect(invisibleBorderSize); - - CRect& rect = *reinterpret_cast(lpRect); - const CSize threshold(m_dpi.ScaleX(16), m_dpi.ScaleY(16)); - const auto SnapTo = [](LONG& val, LONG to, LONG threshold) { - return (std::abs(val - to) < threshold && val != to) ? (val = to, true) : false; - }; - - CSize videoSize = GetVideoSize(); - - if (bCtrl == s.fLimitWindowProportions || videoSize.cx == 0 || videoSize.cy == 0) { - SnapTo(rect.left, areaRect.left, threshold.cx); - SnapTo(rect.top, areaRect.top, threshold.cy); - SnapTo(rect.right, areaRect.right, threshold.cx); - SnapTo(rect.bottom, areaRect.bottom, threshold.cy); - return; - } - - const CRect rectOrig(rect); - switch (nSide) { - case WMSZ_TOPLEFT: - if (SnapTo(rect.left, areaRect.left, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_LEFT, &rect); - rect.OffsetRect(0, rectOrig.bottom - rect.bottom); - if (rect.top < areaRect.top && SnapTo(rect.top, areaRect.top, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_TOP, &rect); - rect.OffsetRect(rectOrig.right - rect.right, 0); - } - } else if (SnapTo(rect.top, areaRect.top, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_TOP, &rect); - rect.OffsetRect(rectOrig.right - rect.right, 0); - if (rect.left < areaRect.left && SnapTo(rect.left, areaRect.left, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_LEFT, &rect); - rect.OffsetRect(0, rectOrig.bottom - rect.bottom); - } - } - break; - case WMSZ_TOP: - case WMSZ_TOPRIGHT: - if (SnapTo(rect.right, areaRect.right, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); - rect.OffsetRect(0, rectOrig.bottom - rect.bottom); - if (rect.top < areaRect.top && SnapTo(rect.top, areaRect.top, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_TOP, &rect); - rect.OffsetRect(rectOrig.left - rect.left, 0); - } - } - else if (SnapTo(rect.top, areaRect.top, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_TOP, &rect); - rect.OffsetRect(rectOrig.left - rect.left, 0); - if (areaRect.right < rect.right && SnapTo(rect.right, areaRect.right, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); - rect.OffsetRect(0, rectOrig.bottom - rect.bottom); - } - } - break; - case WMSZ_RIGHT: - case WMSZ_BOTTOM: - case WMSZ_BOTTOMRIGHT: - if (SnapTo(rect.right, areaRect.right, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); - if (areaRect.bottom < rect.bottom && SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); - } - } else if (SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); - if (areaRect.right < rect.right && SnapTo(rect.right, areaRect.right, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); - } - } - break; - case WMSZ_LEFT: - case WMSZ_BOTTOMLEFT: - if (SnapTo(rect.left, areaRect.left, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_LEFT, &rect); - if (areaRect.bottom < rect.bottom && SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); - rect.OffsetRect(rectOrig.right - rect.right, 0); - } - } else if (SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); - rect.OffsetRect(rectOrig.right - rect.right, 0); - if (rect.left < areaRect.left && SnapTo(rect.left, areaRect.left, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_LEFT, &rect); - } - } - break; - } -} - -void CMainFrame::OnExitSizeMove() -{ - if (m_wndView.Dragging()) { - // HACK: windowed (not renderless) video renderers may not produce WM_MOUSEMOVE message here - UpdateControlState(CMainFrame::UPDATE_CHILDVIEW_CURSOR_HACK); - } -} - -void CMainFrame::OnDisplayChange() // untested, not sure if it's working... -{ - TRACE(_T("*** CMainFrame::OnDisplayChange()\n")); - - if (GetLoadState() == MLS::LOADED) { - if (m_pGraphThread) { - CAMMsgEvent e; - m_pGraphThread->PostThreadMessage(CGraphThread::TM_DISPLAY_CHANGE, (WPARAM)0, (LPARAM)&e); - e.WaitMsg(); - } else { - DisplayChange(); - } - } - - if (HasDedicatedFSVideoWindow()) { - MONITORINFO MonitorInfo; - HMONITOR hMonitor; - - ZeroMemory(&MonitorInfo, sizeof(MonitorInfo)); - MonitorInfo.cbSize = sizeof(MonitorInfo); - - hMonitor = MonitorFromWindow(m_pDedicatedFSVideoWnd->m_hWnd, 0); - if (GetMonitorInfo(hMonitor, &MonitorInfo)) { - CRect MonitorRect = CRect(MonitorInfo.rcMonitor); - m_pDedicatedFSVideoWnd->SetWindowPos(nullptr, - MonitorRect.left, - MonitorRect.top, - MonitorRect.Width(), - MonitorRect.Height(), - SWP_NOZORDER); - MoveVideoWindow(); - } - } -} - -void CMainFrame::OnWindowPosChanging(WINDOWPOS* lpwndpos) -{ - if (!(lpwndpos->flags & SWP_NOMOVE) && IsFullScreenMainFrame()) { - HMONITOR hm = MonitorFromPoint(CPoint(lpwndpos->x, lpwndpos->y), MONITOR_DEFAULTTONULL); - MONITORINFO mi = { sizeof(mi) }; - if (GetMonitorInfo(hm, &mi)) { - lpwndpos->flags &= ~SWP_NOSIZE; - lpwndpos->cx = mi.rcMonitor.right - mi.rcMonitor.left; - lpwndpos->cy = mi.rcMonitor.bottom - mi.rcMonitor.top; - lpwndpos->x = mi.rcMonitor.left; - lpwndpos->y = mi.rcMonitor.top; - } - } - __super::OnWindowPosChanging(lpwndpos); -} - -LRESULT CMainFrame::OnDpiChanged(WPARAM wParam, LPARAM lParam) -{ - m_dpi.Override(LOWORD(wParam), HIWORD(wParam)); - m_eventc.FireEvent(MpcEvent::DPI_CHANGED); - CMPCThemeUtil::GetMetrics(true); //force reset metrics used by util class - CMPCThemeMenu::clearDimensions(); - ReloadMenus(); - if (!restoringWindowRect) { //do not adjust for DPI if restoring saved window position - MoveWindow(reinterpret_cast(lParam)); - } - RecalcLayout(); - m_wndPreView.ScaleFont(); - return 0; -} - -void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) -{ - // Only stop screensaver if video playing; allow for audio only - if ((GetMediaState() == State_Running && !m_fEndOfStream && !m_fAudioOnly) - && (((nID & 0xFFF0) == SC_SCREENSAVE) || ((nID & 0xFFF0) == SC_MONITORPOWER))) { - TRACE(_T("SC_SCREENSAVE, nID = %u, lParam = %d\n"), nID, lParam); - return; - } - - __super::OnSysCommand(nID, lParam); -} - -void CMainFrame::OnActivateApp(BOOL bActive, DWORD dwThreadID) -{ - __super::OnActivateApp(bActive, dwThreadID); - - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW); - - if (IsFullScreenMainFrame()) { - if (bActive) { - // keep the fullscreen window on top while it's active, - // we don't want notification pop-ups to cover it - SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } else { - // don't keep the fullscreen window on top when it's not active, - // we want to be able to switch to other windows nicely - struct { - void operator()() const { - CMainFrame* pMainFrame = AfxGetMainFrame(); - if (!pMainFrame || !pMainFrame->m_fFullScreen || pMainFrame->WindowExpectedOnTop() || pMainFrame->m_bExtOnTop) { - return; - } - // place our window under the new active window - // when we can't determine that window, we try later - if (CWnd* pActiveWnd = GetForegroundWindow()) { - bool bMoved = false; - if (CWnd* pActiveRootWnd = pActiveWnd->GetAncestor(GA_ROOT)) { - const DWORD dwStyle = pActiveRootWnd->GetStyle(); - const DWORD dwExStyle = pActiveRootWnd->GetExStyle(); - if (!(dwStyle & WS_CHILD) && !(dwStyle & WS_POPUP) && !(dwExStyle & WS_EX_TOPMOST)) { - if (CWnd* pLastWnd = GetDesktopWindow()->GetTopWindow()) { - while (CWnd* pWnd = pLastWnd->GetNextWindow(GW_HWNDNEXT)) { - if (*pLastWnd == *pActiveRootWnd) { - pMainFrame->SetWindowPos( - pWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - bMoved = true; - break; - } - pLastWnd = pWnd; - } - } else { - ASSERT(FALSE); - } - } - } - if (!bMoved) { - pMainFrame->SetWindowPos( - &wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } - } else { - pMainFrame->m_timerOneTime.Subscribe( - TimerOneTimeSubscriber::PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW, *this, 1); - } - } - } placeUnder; - placeUnder(); - } - } -} - -LRESULT CMainFrame::OnAppCommand(WPARAM wParam, LPARAM lParam) -{ - UINT cmd = GET_APPCOMMAND_LPARAM(lParam); - UINT uDevice = GET_DEVICE_LPARAM(lParam); - - if (uDevice != FAPPCOMMAND_OEM && cmd != 0 - || cmd == APPCOMMAND_MEDIA_PLAY - || cmd == APPCOMMAND_MEDIA_PAUSE - || cmd == APPCOMMAND_MEDIA_CHANNEL_UP - || cmd == APPCOMMAND_MEDIA_CHANNEL_DOWN - || cmd == APPCOMMAND_MEDIA_RECORD - || cmd == APPCOMMAND_MEDIA_FAST_FORWARD - || cmd == APPCOMMAND_MEDIA_REWIND) { - const CAppSettings& s = AfxGetAppSettings(); - - BOOL fRet = FALSE; - - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - if (wc.appcmd == cmd && TRUE == SendMessage(WM_COMMAND, wc.cmd)) { - fRet = TRUE; - } - } - - if (fRet) { - return TRUE; - } - } - - return Default(); -} - -void CMainFrame::OnRawInput(UINT nInputcode, HRAWINPUT hRawInput) -{ - const CAppSettings& s = AfxGetAppSettings(); - UINT nMceCmd = AfxGetMyApp()->GetRemoteControlCode(nInputcode, hRawInput); - - switch (nMceCmd) { - case MCE_DETAILS: - case MCE_GUIDE: - case MCE_TVJUMP: - case MCE_STANDBY: - case MCE_OEM1: - case MCE_OEM2: - case MCE_MYTV: - case MCE_MYVIDEOS: - case MCE_MYPICTURES: - case MCE_MYMUSIC: - case MCE_RECORDEDTV: - case MCE_DVDANGLE: - case MCE_DVDAUDIO: - case MCE_DVDMENU: - case MCE_DVDSUBTITLE: - case MCE_RED: - case MCE_GREEN: - case MCE_YELLOW: - case MCE_BLUE: - case MCE_MEDIA_NEXTTRACK: - case MCE_MEDIA_PREVIOUSTRACK: - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - if (wc.appcmd == nMceCmd) { - SendMessage(WM_COMMAND, wc.cmd); - break; - } - } - break; - } -} - -LRESULT CMainFrame::OnHotKey(WPARAM wParam, LPARAM lParam) -{ - if (wParam == 0) { - ASSERT(false); - return FALSE; - } - - const CAppSettings& s = AfxGetAppSettings(); - BOOL fRet = FALSE; - - if (GetActiveWindow() == this || s.fGlobalMedia == TRUE) { - POSITION pos = s.wmcmds.GetHeadPosition(); - - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - if (wc.appcmd == wParam && TRUE == SendMessage(WM_COMMAND, wc.cmd)) { - fRet = TRUE; - } - } - } - - return fRet; -} - -bool g_bNoDuration = false; -bool g_bExternalSubtitleTime = false; -bool g_bExternalSubtitle = false; -double g_dRate = 1.0; - -void CMainFrame::OnTimer(UINT_PTR nIDEvent) -{ - switch (nIDEvent) { - case TIMER_WINDOW_FULLSCREEN: - if (AfxGetAppSettings().iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 - BOOL setEnabled = FALSE; - ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); - } - KillTimer(TIMER_WINDOW_FULLSCREEN); - delayingFullScreen = false; - break; - case TIMER_STREAMPOSPOLLER: - if (GetLoadState() == MLS::LOADED) { - REFERENCE_TIME rtNow = 0, rtDur = 0; - switch (GetPlaybackMode()) { - case PM_FILE: - g_bExternalSubtitleTime = false; - if (m_pGB && m_pMS) { - m_pMS->GetCurrentPosition(&rtNow); - if (!m_pGB || !m_pMS) return; // can happen very rarely due to race condition - m_pMS->GetDuration(&rtDur); - - if ((abRepeat.positionA && rtNow < abRepeat.positionA || abRepeat.positionB && rtNow >= abRepeat.positionB) && GetMediaState() != State_Stopped) { - PerformABRepeat(); - return; - } - - auto* pMRU = &AfxGetAppSettings().MRU; - if (m_bRememberFilePos && !m_fEndOfStream) { - pMRU->UpdateCurrentFilePosition(rtNow); - } - - // Casimir666 : autosave subtitle sync after play - if (m_nCurSubtitle >= 0 && m_rtCurSubPos != rtNow) { - if (m_lSubtitleShift) { - 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; - } - - m_wndStatusBar.SetStatusTimer(rtNow, rtDur, IsSubresyncBarVisible(), GetTimeFormat()); - } - break; - case PM_DVD: - 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 ? 30 / 1.001 - : 25.0; - - rtNow = HMSF2RT(Location.TimeCode, fps); - - if (abRepeat.positionB && rtNow >= abRepeat.positionB && GetMediaState() != State_Stopped) { - PerformABRepeat(); - return; - } - - DVD_HMSF_TIMECODE tcDur; - ULONG ulFlags; - if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { - rtDur = HMSF2RT(tcDur, fps); - } - if (m_pSubClock) { - m_pSubClock->SetTime(rtNow); - } - } - } - m_wndStatusBar.SetStatusTimer(rtNow, rtDur, IsSubresyncBarVisible(), GetTimeFormat()); - break; - case PM_ANALOG_CAPTURE: - g_bExternalSubtitleTime = true; - if (m_fCapturing) { - if (m_wndCaptureBar.m_capdlg.m_pMux) { - CComQIPtr pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux; - if (!pMuxMS || FAILED(pMuxMS->GetCurrentPosition(&rtNow))) { - if (m_pMS) { - m_pMS->GetCurrentPosition(&rtNow); - } - } - } - if (m_rtDurationOverride >= 0) { - rtDur = m_rtDurationOverride; - } - } - break; - case PM_DIGITAL_CAPTURE: - g_bExternalSubtitleTime = true; - m_pMS->GetCurrentPosition(&rtNow); - break; - default: - ASSERT(FALSE); - break; - } - - g_bNoDuration = rtDur <= 0; - m_wndSeekBar.Enable(!g_bNoDuration); - m_wndSeekBar.SetRange(0, rtDur); - m_wndSeekBar.SetPos(rtNow); - m_OSD.SetRange(rtDur); - m_OSD.SetPos(rtNow); - m_Lcd.SetMediaRange(0, rtDur); - m_Lcd.SetMediaPos(rtNow); - - if (m_pCAP) { - if (g_bExternalSubtitleTime) { - m_pCAP->SetTime(rtNow); - } - m_wndSubresyncBar.SetTime(rtNow); - m_wndSubresyncBar.SetFPS(m_pCAP->GetFPS()); - } - if (g_bExternalSubtitleTime && (m_iStreamPosPollerInterval > 40)) { - AdjustStreamPosPoller(true); - } - } - break; - case TIMER_STREAMPOSPOLLER2: - if (GetLoadState() == MLS::LOADED) { - switch (GetPlaybackMode()) { - case PM_FILE: - // no break - case PM_DVD: - if (AfxGetAppSettings().fShowCurrentTimeInOSD && m_OSD.CanShowMessage()) { - m_OSD.DisplayTime(m_wndStatusBar.GetStatusTimer()); - } - break; - case PM_DIGITAL_CAPTURE: { - EventDescriptor& NowNext = m_pDVBState->NowNext; - time_t tNow; - time(&tNow); - if (NowNext.duration > 0 && tNow >= NowNext.startTime && tNow <= NowNext.startTime + NowNext.duration) { - REFERENCE_TIME rtNow = REFERENCE_TIME(tNow - NowNext.startTime) * 10000000; - REFERENCE_TIME rtDur = REFERENCE_TIME(NowNext.duration) * 10000000; - m_wndStatusBar.SetStatusTimer(rtNow, rtDur, false, TIME_FORMAT_MEDIA_TIME); - if (AfxGetAppSettings().fShowCurrentTimeInOSD && m_OSD.CanShowMessage()) { - m_OSD.DisplayTime(m_wndStatusBar.GetStatusTimer()); - } - } else { - m_wndStatusBar.SetStatusTimer(ResStr(IDS_CAPTURE_LIVE)); - } - } - break; - case PM_ANALOG_CAPTURE: - if (!m_fCapturing) { - CString str(StrRes(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))) { - str.AppendFormat(_T(" (ch%ld)"), lChannel); - } - m_wndStatusBar.SetStatusTimer(str); - } - break; - default: - ASSERT(FALSE); - break; - } - } - break; - case TIMER_STATS: { - const CAppSettings& s = AfxGetAppSettings(); - if (m_wndStatsBar.IsVisible()) { - CString rate; - rate.Format(_T("%.3fx"), m_dSpeedRate); - if (m_pQP) { - CString info; - int tmp, tmp1; - - if (SUCCEEDED(m_pQP->get_AvgFrameRate(&tmp))) { // We hang here due to a lock that never gets released. - info.Format(_T("%d.%02d (%s)"), tmp / 100, tmp % 100, rate.GetString()); - } else { - info = _T("-"); - } - m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMERATE), info); - - if (SUCCEEDED(m_pQP->get_AvgSyncOffset(&tmp)) - && SUCCEEDED(m_pQP->get_DevSyncOffset(&tmp1))) { - info.Format(IDS_STATSBAR_SYNC_OFFSET_FORMAT, tmp, tmp1); - } else { - info = _T("-"); - } - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SYNC_OFFSET), info); - - if (SUCCEEDED(m_pQP->get_FramesDrawn(&tmp)) - && SUCCEEDED(m_pQP->get_FramesDroppedInRenderer(&tmp1))) { - info.Format(IDS_MAINFRM_6, tmp, tmp1); - } else { - info = _T("-"); - } - m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMES), info); - - if (SUCCEEDED(m_pQP->get_Jitter(&tmp))) { - info.Format(_T("%d ms"), tmp); - } else { - info = _T("-"); - } - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_JITTER), info); - } else { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_PLAYBACK_RATE), rate); - } - - if (m_pBI) { - CString sInfo; - - for (int i = 0, j = m_pBI->GetCount(); i < j; i++) { - int samples, size; - if (S_OK == m_pBI->GetStatus(i, samples, size) && (i < 2 || size > 0)) { // third pin is usually subs - sInfo.AppendFormat(_T("[P%d] %03d samples / %d KB "), i, samples, size / 1024); - } - } - - if (!sInfo.IsEmpty()) { - //sInfo.AppendFormat(_T("(p%lu)"), m_pBI->GetPriority()); - m_wndStatsBar.SetLine(StrRes(IDS_AG_BUFFERS), sInfo); - } - } - - { - // IBitRateInfo - CString sInfo; - BeginEnumFilters(m_pGB, pEF, pBF) { - unsigned i = 0; - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pBRI = pPin) { - DWORD nAvg = pBRI->GetAverageBitRate() / 1000; - - if (nAvg > 0) { - sInfo.AppendFormat(_T("[P%u] %lu/%lu kb/s "), i, nAvg, pBRI->GetCurrentBitRate() / 1000); - } - } - i++; - } - EndEnumPins; - - if (!sInfo.IsEmpty()) { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_BITRATE), sInfo + ResStr(IDS_STATSBAR_BITRATE_AVG_CUR)); - sInfo.Empty(); - } - } - EndEnumFilters; - } - } - - if (GetPlaybackMode() == PM_DVD) { // we also use this timer to update the info panel for DVD playback - ULONG ulAvailable, ulCurrent; - - // Location - - CString Location(_T('-')); - - 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(StrRes(IDS_INFOBAR_LOCATION), Location); - - // Video - - CString Video(_T('-')); - - 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_statusbarVideoSize.Format(_T("%dx%d"), VATR.ulSourceResolutionX, VATR.ulSourceResolutionY); - m_statusbarVideoFormat = VATR.Compression == DVD_VideoCompression_MPEG1 ? L"MPG1" : VATR.Compression == DVD_VideoCompression_MPEG2 ? L"MPG2" : L""; - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_VIDEO), Video); - - // Audio - - CString Audio(_T('-')); - - DVD_AudioAttributes AATR; - - if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulAvailable, &ulCurrent)) - && SUCCEEDED(m_pDVDI->GetAudioAttributes(ulCurrent, &AATR))) { - CString lang; - if (AATR.Language) { - GetLocaleString(AATR.Language, LOCALE_SENGLANGUAGE, lang); - currentAudioLang = lang; - } else { - lang.Format(IDS_AG_UNKNOWN, ulCurrent + 1); - currentAudioLang.Empty(); - } - - 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); - m_statusbarAudioFormat.Format(L"%s %dch", format, AATR.bNumberOfChannels); - - Audio.Format(IDS_MAINFRM_11, - lang.GetString(), - format.GetString(), - AATR.dwFrequency, - AATR.bQuantization, - AATR.bNumberOfChannels, - ResStr(AATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString()); - - m_wndStatusBar.SetStatusBitmap( - AATR.bNumberOfChannels == 1 ? IDB_AUDIOTYPE_MONO - : AATR.bNumberOfChannels >= 2 ? IDB_AUDIOTYPE_STEREO - : IDB_AUDIOTYPE_NOAUDIO); - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUDIO), Audio); - - // Subtitles - - CString Subtitles(_T('-')); - - BOOL bIsDisabled; - DVD_SubpictureAttributes SATR; - - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulAvailable, &ulCurrent, &bIsDisabled)) - && SUCCEEDED(m_pDVDI->GetSubpictureAttributes(ulCurrent, &SATR))) { - CString lang; - GetLocaleString(SATR.Language, LOCALE_SENGLANGUAGE, lang); - - 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.GetString()); - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_SUBTITLES), Subtitles); - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - if (m_pDVBState->bActive) { - CComQIPtr pTun = m_pGB; - BOOLEAN bPresent, bLocked; - LONG lDbStrength, lPercentQuality; - CString Signal; - - if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { - Signal.Format(IDS_STATSBAR_SIGNAL_FORMAT, (int)lDbStrength, lPercentQuality); - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), Signal); - } - } else { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), _T("-")); - } - } else if (GetPlaybackMode() == PM_FILE) { - OpenSetupInfoBar(false); - if (s.iTitleBarTextStyle == 1 && s.fTitleBarTextTitle) { - OpenSetupWindowTitle(); - } - MediaTransportControlSetMedia(); - SendNowPlayingToSkype(); - SendNowPlayingToApi(false); - } - - if (m_CachedFilterState == State_Running && !m_fAudioOnly) { - if (s.bPreventDisplaySleep) { - BOOL fActive = FALSE; - if (SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fActive, 0) && fActive) { - SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, nullptr, SPIF_SENDWININICHANGE); - SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, fActive, nullptr, SPIF_SENDWININICHANGE); - } - - // prevent screensaver activate, monitor sleep/turn off after playback - SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); - } - } - } - break; - case TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS: { - if (GetPlaybackMode() == PM_NONE) { - if (UnloadUnusedExternalObjects()) { - KillTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS); - } - } - } - break; - case TIMER_HIDER: - m_timerHider.NotifySubscribers(); - break; - case TIMER_DELAYEDSEEK: - KillTimer(TIMER_DELAYEDSEEK); - if (queuedSeek.seekTime > 0) { - SeekTo(queuedSeek.rtPos, queuedSeek.bShowOSD); - } - break; - default: - if (nIDEvent >= TIMER_ONETIME_START && nIDEvent <= TIMER_ONETIME_END) { - m_timerOneTime.NotifySubscribers(nIDEvent); - } else { - ASSERT(FALSE); - } - } - - __super::OnTimer(nIDEvent); -} - -void CMainFrame::DoAfterPlaybackEvent() -{ - CAppSettings& s = AfxGetAppSettings(); - bool bExitFullScreen = false; - bool bNoMoreMedia = false; - - if (s.nCLSwitches & CLSW_DONOTHING) { - // Do nothing - } else if (s.nCLSwitches & CLSW_CLOSE) { - SendMessage(WM_COMMAND, ID_FILE_EXIT); - } else if (s.nCLSwitches & CLSW_MONITOROFF) { - m_fEndOfStream = true; - bExitFullScreen = true; - SetThreadExecutionState(ES_CONTINUOUS); - SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, 2); - } else if (s.nCLSwitches & CLSW_STANDBY) { - SetPrivilege(SE_SHUTDOWN_NAME); - SetSystemPowerState(TRUE, FALSE); - SendMessage(WM_COMMAND, ID_FILE_EXIT); // Recheck if this is still needed after switching to new toolset and SetSuspendState() - } else if (s.nCLSwitches & CLSW_HIBERNATE) { - SetPrivilege(SE_SHUTDOWN_NAME); - SetSystemPowerState(FALSE, FALSE); - SendMessage(WM_COMMAND, ID_FILE_EXIT); - } else if (s.nCLSwitches & CLSW_SHUTDOWN) { - SetPrivilege(SE_SHUTDOWN_NAME); - InitiateSystemShutdownEx(nullptr, nullptr, 0, TRUE, FALSE, - SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE | SHTDN_REASON_FLAG_PLANNED); - SendMessage(WM_COMMAND, ID_FILE_EXIT); - } else if (s.nCLSwitches & CLSW_LOGOFF) { - SetPrivilege(SE_SHUTDOWN_NAME); - ExitWindowsEx(EWX_LOGOFF | EWX_FORCEIFHUNG, 0); - SendMessage(WM_COMMAND, ID_FILE_EXIT); - } else if (s.nCLSwitches & CLSW_LOCK) { - m_fEndOfStream = true; - bExitFullScreen = true; - LockWorkStation(); - } else if (s.nCLSwitches & CLSW_PLAYNEXT) { - if (!SearchInDir(true, (s.fLoopForever || m_nLoops < s.nLoops || s.bLoopFolderOnPlayNextFile))) { - m_fEndOfStream = true; - bExitFullScreen = true; - bNoMoreMedia = true; - } - } else { - // remembered after playback events - switch (s.eAfterPlayback) { - case CAppSettings::AfterPlayback::PLAY_NEXT: - if (m_wndPlaylistBar.GetCount() < 2) { // ignore global PLAY_NEXT in case of a playlist - if (!SearchInDir(true, s.bLoopFolderOnPlayNextFile)) { - SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); - } - } - break; - case CAppSettings::AfterPlayback::REWIND: - bExitFullScreen = true; - if (m_wndPlaylistBar.GetCount() > 1) { - s.nCLSwitches |= CLSW_OPEN; - PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); - } else { - SendMessage(WM_COMMAND, ID_PLAY_STOP); - } - break; - case CAppSettings::AfterPlayback::MONITOROFF: - m_fEndOfStream = true; - bExitFullScreen = true; - SetThreadExecutionState(ES_CONTINUOUS); - SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, 2); - break; - case CAppSettings::AfterPlayback::CLOSE: - SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); - break; - case CAppSettings::AfterPlayback::EXIT: - SendMessage(WM_COMMAND, ID_FILE_EXIT); - break; - default: - m_fEndOfStream = true; - bExitFullScreen = true; - break; - } - } - - if (AfxGetMyApp()->m_fClosingState) { - return; - } - - if (m_fEndOfStream) { - m_OSD.EnableShowMessage(false); - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - m_OSD.EnableShowMessage(); - if (bNoMoreMedia) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_NO_MORE_MEDIA)); - } - } - - if (bExitFullScreen && (IsFullScreenMode()) && s.fExitFullScreenAtTheEnd) { - OnViewFullscreen(); - } -} - -void CMainFrame::OnUpdateABRepeat(CCmdUI* pCmdUI) { - bool canABRepeat = GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD; - bool abRepeatActive = static_cast(abRepeat); - - switch (pCmdUI->m_nID) { - case ID_PLAY_REPEAT_AB: - pCmdUI->Enable(canABRepeat && abRepeatActive); - break; - case ID_PLAY_REPEAT_AB_MARK_A: - if (pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuItem(ID_PLAY_REPEAT_AB_MARK_A, MF_BYCOMMAND | (abRepeat.positionA ? MF_CHECKED : MF_UNCHECKED)); - } - pCmdUI->Enable(canABRepeat); - break; - case ID_PLAY_REPEAT_AB_MARK_B: - if (pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuItem(ID_PLAY_REPEAT_AB_MARK_B, MF_BYCOMMAND | (abRepeat.positionB ? MF_CHECKED : MF_UNCHECKED)); - } - pCmdUI->Enable(canABRepeat); - break; - default: - ASSERT(FALSE); - return; - } -} - - -void CMainFrame::OnABRepeat(UINT nID) { - switch (nID) { - case ID_PLAY_REPEAT_AB: - if (abRepeat) { //only support disabling from the menu - DisableABRepeat(); - } - break; - case ID_PLAY_REPEAT_AB_MARK_A: - case ID_PLAY_REPEAT_AB_MARK_B: - REFERENCE_TIME rtDur = 0; - int playmode = GetPlaybackMode(); - - bool havePos = false; - REFERENCE_TIME pos = 0; - - if (playmode == PM_FILE && m_pMS) { - m_pMS->GetDuration(&rtDur); - havePos = SUCCEEDED(m_pMS->GetCurrentPosition(&pos)); - } else if (playmode == PM_DVD && 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 ? 30 / 1.001 - : 25.0; - DVD_HMSF_TIMECODE tcDur; - ULONG ulFlags; - if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { - rtDur = HMSF2RT(tcDur, fps); - } - havePos = true; - pos = HMSF2RT(Location.TimeCode, fps); - abRepeat.dvdTitle = m_iDVDTitle; //we only support one title. so if they clear or set, we will remember the current title - } - } else { - return; - } - - if (nID == ID_PLAY_REPEAT_AB_MARK_A) { - if (abRepeat.positionA) { - abRepeat.positionA = 0; - } else if (havePos) { - abRepeat.positionA = pos; - if (abRepeat.positionA < rtDur) { - if (abRepeat.positionB && abRepeat.positionA >= abRepeat.positionB) { - abRepeat.positionB = 0; - } - } else { - abRepeat.positionA = 0; - } - } - } else if (nID == ID_PLAY_REPEAT_AB_MARK_B) { - if (abRepeat.positionB) { - abRepeat.positionB = 0; - } else if (havePos) { - abRepeat.positionB = pos; - if (abRepeat.positionB > 0 && abRepeat.positionB > abRepeat.positionA && rtDur >= abRepeat.positionB) { - if (GetMediaState() == State_Running) { - PerformABRepeat(); //we just set loop point B, so we need to repeat right now - } - } else { - abRepeat.positionB = 0; - } - } - } - - auto pMRU = &AfxGetAppSettings().MRU; - pMRU->UpdateCurrentABRepeat(abRepeat); - - m_wndSeekBar.Invalidate(); - break; - } -} - -void CMainFrame::PerformABRepeat() { - DoSeekTo(abRepeat.positionA, false); - - if (GetMediaState() == State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } -} - -void CMainFrame::DisableABRepeat() { - abRepeat = ABRepeat(); - - auto* pMRU = &AfxGetAppSettings().MRU; - pMRU->UpdateCurrentABRepeat(abRepeat); - - m_wndSeekBar.Invalidate(); -} - -bool CMainFrame::CheckABRepeat(REFERENCE_TIME& aPos, REFERENCE_TIME& bPos) { - if (GetPlaybackMode() == PM_FILE || (GetPlaybackMode() == PM_DVD && m_iDVDTitle == abRepeat.dvdTitle)) { - if (abRepeat) { - aPos = abRepeat.positionA; - bPos = abRepeat.positionB; - return true; - } - } - return false; -} - - -// -// graph event EC_COMPLETE handler -// -void CMainFrame::GraphEventComplete() -{ - CAppSettings& s = AfxGetAppSettings(); - - auto* pMRU = &s.MRU; - - - if (m_bRememberFilePos) { - pMRU->UpdateCurrentFilePosition(0, true); - } - - bool bBreak = false; - if (m_wndPlaylistBar.IsAtEnd() || s.eLoopMode == CAppSettings::LoopMode::FILE) { - ++m_nLoops; - bBreak = !!(s.nCLSwitches & CLSW_AFTERPLAYBACK_MASK); - } - - if (abRepeat) { - PerformABRepeat(); - } else if (s.fLoopForever || m_nLoops < s.nLoops) { - if (bBreak) { - DoAfterPlaybackEvent(); - } else if ((m_wndPlaylistBar.GetCount() > 1) && (s.eLoopMode == CAppSettings::LoopMode::PLAYLIST)) { - int nLoops = m_nLoops; - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARDFILE); - m_nLoops = nLoops; - } else { - if (GetMediaState() == State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } else if (m_pMS) { - REFERENCE_TIME rtDur = 0; - if ((m_pMS->GetDuration(&rtDur) == S_OK) && (rtDur >= 1000000LL) || !IsImageFile(lastOpenFile)) { // repeating still image is pointless and can cause player UI to freeze - REFERENCE_TIME rtPos = 0; - m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - if (GetMediaState() == State_Paused) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - } - } - } - } else { - DoAfterPlaybackEvent(); - } -} - -// -// our WM_GRAPHNOTIFY handler -// - -LRESULT CMainFrame::OnGraphNotify(WPARAM wParam, LPARAM lParam) -{ - CAppSettings& s = AfxGetAppSettings(); - HRESULT hr = S_OK; - - LONG evCode = 0; - LONG_PTR evParam1, evParam2; - while (!AfxGetMyApp()->m_fClosingState && m_pME && SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) { -#ifdef _DEBUG - if (evCode != EC_DVD_CURRENT_HMSF_TIME) { - TRACE(_T("--> CMainFrame::OnGraphNotify on thread: %lu; event: 0x%08x (%ws)\n"), GetCurrentThreadId(), evCode, GetEventString(evCode)); - } -#endif - CString str; - if (m_fCustomGraph) { - if (EC_BG_ERROR == evCode) { - str = CString((char*)evParam1); - } - } - hr = m_pME->FreeEventParams(evCode, evParam1, evParam2); - - switch (evCode) { - case EC_PAUSED: - if (GetLoadState() == MLS::LOADED) { - UpdateCachedMediaState(); - } - if (m_audioTrackCount > 1 && GetLoadState() == MLS::LOADED) { - CheckSelectedAudioStream(); - } - break; - case EC_COMPLETE: - UpdateCachedMediaState(); - GraphEventComplete(); - break; - case EC_ERRORABORT: - UpdateCachedMediaState(); - TRACE(_T("\thr = %08x\n"), (HRESULT)evParam1); - break; - case EC_BUFFERING_DATA: - TRACE(_T("\tBuffering data = %s\n"), evParam1 ? _T("true") : _T("false")); - m_bBuffering = !!evParam1; - break; - case EC_STEP_COMPLETE: - if (m_fFrameSteppingActive) { - m_nStepForwardCount++; - } - UpdateCachedMediaState(); - break; - case EC_DEVICE_LOST: - UpdateCachedMediaState(); - if (evParam2 == 0) { - // Device lost - if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - CComQIPtr pBF = (IUnknown*)evParam1; - if (!m_pVidCap && m_pVidCap == pBF || !m_pAudCap && m_pAudCap == pBF) { - SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); - } - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); - } - } - break; - case EC_DVD_TITLE_CHANGE: { - if (GetPlaybackMode() == PM_FILE) { - SetupChapters(); - } else if (GetPlaybackMode() == PM_DVD) { - m_iDVDTitle = (DWORD)evParam1; - - if (m_iDVDDomain == DVD_DOMAIN_Title) { - CString Domain; - Domain.Format(IDS_AG_TITLE, m_iDVDTitle); - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), Domain); - } - - SetupDVDChapters(); - } - } - break; - case EC_DVD_DOMAIN_CHANGE: { - m_iDVDDomain = (DVD_DOMAIN)evParam1; - - OpenDVDData* pDVDData = dynamic_cast(m_lastOMD.m_p); - ASSERT(pDVDData); - - CString Domain(_T('-')); - - switch (m_iDVDDomain) { - case DVD_DOMAIN_FirstPlay: - ULONGLONG llDVDGuid; - - Domain = _T("First Play"); - - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDiscID(nullptr, &llDVDGuid))) { - m_fValidDVDOpen = true; - - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("DVD Title: %lu"), s.lDVDTitle); - } - - if (s.lDVDTitle != 0) { - // Set command line position - hr = m_pDVDC->PlayTitle(s.lDVDTitle, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayTitle: 0x%08X"), hr); - m_OSD.DebugMessage(_T("DVD Chapter: %lu"), s.lDVDChapter); - } - - if (s.lDVDChapter > 1) { - hr = m_pDVDC->PlayChapterInTitle(s.lDVDTitle, s.lDVDChapter, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayChapterInTitle: 0x%08X"), hr); - } - } else { - // Trick: skip trailers with some DVDs - hr = m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("Resume: 0x%08X"), hr); - } - - // If the resume call succeeded, then we skip PlayChapterInTitle - // and PlayAtTimeInTitle. - if (hr == S_OK) { - // This might fail if the Title is not available yet? - hr = m_pDVDC->PlayAtTime(&s.DVDPosition, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayAtTime: 0x%08X"), hr); - } - } else { - if (s.fShowDebugInfo) - m_OSD.DebugMessage(_T("Timecode requested: %02d:%02d:%02d.%03d"), - s.DVDPosition.bHours, s.DVDPosition.bMinutes, - s.DVDPosition.bSeconds, s.DVDPosition.bFrames); - - // Always play chapter 1 (for now, until something else dumb happens) - hr = m_pDVDC->PlayChapterInTitle(s.lDVDTitle, 1, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayChapterInTitle: 0x%08X"), hr); - } - - // This might fail if the Title is not available yet? - hr = m_pDVDC->PlayAtTime(&s.DVDPosition, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayAtTime: 0x%08X"), hr); - } - - if (hr != S_OK) { - hr = m_pDVDC->PlayAtTimeInTitle(s.lDVDTitle, &s.DVDPosition, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayAtTimeInTitle: 0x%08X"), hr); - } - } - } // Resume - - hr = m_pDVDC->PlayAtTime(&s.DVDPosition, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayAtTime: %d"), hr); - } - } - - m_iDVDTitle = s.lDVDTitle; - s.lDVDTitle = 0; - s.lDVDChapter = 0; - } else if (pDVDData && pDVDData->pDvdState) { - // Set position from favorite - VERIFY(SUCCEEDED(m_pDVDC->SetState(pDVDData->pDvdState, DVD_CMD_FLAG_Block, nullptr))); - // We don't want to restore the position from the favorite - // if the playback is reinitialized so we clear the saved state - pDVDData->pDvdState.Release(); - } else if (s.fKeepHistory && s.fRememberDVDPos && s.MRU.GetCurrentDVDPosition().llDVDGuid) { - // Set last remembered position (if found...) - DVD_POSITION dvdPosition = s.MRU.GetCurrentDVDPosition(); - - hr = m_pDVDC->PlayTitle(dvdPosition.lTitle, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - TRACE(_T("Failed to set remembered DVD title index, hr = 0x%08X"), hr); - } else { - m_iDVDTitle = dvdPosition.lTitle; - - if (dvdPosition.timecode.bSeconds > 0 || dvdPosition.timecode.bMinutes > 0 || dvdPosition.timecode.bHours > 0 || dvdPosition.timecode.bFrames > 0) { -#if 0 - hr = m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - TRACE(_T("Failed to set remembered DVD resume flags, hr = 0x%08X"), hr); - } -#endif -#if 0 - hr = m_pDVDC->PlayAtTimeInTitle(dvdPosition.lTitle, &dvdPosition.timecode, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); -#else - hr = m_pDVDC->PlayAtTime(&dvdPosition.timecode, DVD_CMD_FLAG_Flush, nullptr); -#endif - } - - ABRepeat tmp = s.MRU.GetCurrentABRepeat(); - if (tmp.dvdTitle == m_iDVDTitle) { - abRepeat = tmp; - m_wndSeekBar.Invalidate(); - } - } - } - - if (s.fRememberZoomLevel && !IsFullScreenMode() && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { // Hack to the normal initial zoom for DVD + DXVA ... - ZoomVideoWindow(); - } - } - break; - case DVD_DOMAIN_VideoManagerMenu: - Domain = _T("Video Manager Menu"); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - break; - case DVD_DOMAIN_VideoTitleSetMenu: - Domain = _T("Video Title Set Menu"); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - break; - case DVD_DOMAIN_Title: - Domain.Format(IDS_AG_TITLE, m_iDVDTitle); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - if (s.fKeepHistory && s.fRememberDVDPos) { - s.MRU.UpdateCurrentDVDTitle(m_iDVDTitle); - } - if (!m_fValidDVDOpen && m_pDVDC) { - m_fValidDVDOpen = true; - m_pDVDC->ShowMenu(DVD_MENU_Title, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - } - break; - case DVD_DOMAIN_Stop: - Domain.LoadString(IDS_AG_STOP); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - break; - default: - Domain = _T("-"); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - break; - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), Domain); - - if (GetPlaybackMode() == PM_FILE) { - SetupChapters(); - } else if (GetPlaybackMode() == PM_DVD) { - SetupDVDChapters(); - } - -#if 0 // UOPs debug traces - if (hr == VFW_E_DVD_OPERATION_INHIBITED) { - ULONG UOPfields = 0; - pDVDI->GetCurrentUOPS(&UOPfields); - CString message; - message.Format(_T("UOP bitfield: 0x%08X; domain: %s"), UOPfields, Domain); - m_OSD.DisplayMessage(OSD_TOPLEFT, message); - } else { - m_OSD.DisplayMessage(OSD_TOPRIGHT, Domain); - } -#endif - - MoveVideoWindow(); // AR might have changed - } - break; - case EC_DVD_CURRENT_HMSF_TIME: { - s.MRU.UpdateCurrentDVDTimecode((DVD_HMSF_TIMECODE*)&evParam1); - } - break; - case EC_DVD_ERROR: { - TRACE(_T("\t%I64d %Id\n"), evParam1, evParam2); - - UINT err; - - switch (evParam1) { - case DVD_ERROR_Unexpected: - default: - err = IDS_MAINFRM_16; - break; - case DVD_ERROR_CopyProtectFail: - err = IDS_MAINFRM_17; - break; - case DVD_ERROR_InvalidDVD1_0Disc: - err = IDS_MAINFRM_18; - break; - case DVD_ERROR_InvalidDiscRegion: - err = IDS_MAINFRM_19; - break; - case DVD_ERROR_LowParentalLevel: - err = IDS_MAINFRM_20; - break; - case DVD_ERROR_MacrovisionFail: - err = IDS_MAINFRM_21; - break; - case DVD_ERROR_IncompatibleSystemAndDecoderRegions: - err = IDS_MAINFRM_22; - break; - case DVD_ERROR_IncompatibleDiscAndDecoderRegions: - err = IDS_MAINFRM_23; - break; - } - - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - - m_closingmsg.LoadString(err); - } - break; - case EC_DVD_WARNING: - TRACE(_T("\t%Id %Id\n"), evParam1, evParam2); - break; - case EC_VIDEO_SIZE_CHANGED: { - CSize size((DWORD)evParam1); - TRACE(_T("\t%ldx%ld\n"), size.cx, size.cy); - const bool bWasAudioOnly = m_fAudioOnly; - m_fAudioOnly = (size.cx <= 0 || size.cy <= 0); - OnVideoSizeChanged(bWasAudioOnly); - } - break; - case EC_LENGTH_CHANGED: { - REFERENCE_TIME rtDur = 0; - m_pMS->GetDuration(&rtDur); - m_wndPlaylistBar.SetCurTime(rtDur); - OnTimer(TIMER_STREAMPOSPOLLER); - OnTimer(TIMER_STREAMPOSPOLLER2); - LoadKeyFrames(); - if (GetPlaybackMode() == PM_FILE) { - SetupChapters(); - } else if (GetPlaybackMode() == PM_DVD) { - SetupDVDChapters(); - } - } - break; - case EC_BG_AUDIO_CHANGED: - if (m_fCustomGraph) { - int nAudioChannels = (int)evParam1; - - m_wndStatusBar.SetStatusBitmap(nAudioChannels == 1 ? IDB_AUDIOTYPE_MONO - : nAudioChannels >= 2 ? IDB_AUDIOTYPE_STEREO - : IDB_AUDIOTYPE_NOAUDIO); - } - break; - case EC_BG_ERROR: - if (m_fCustomGraph) { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - m_closingmsg = !str.IsEmpty() ? str : CString(_T("Unspecified graph error")); - m_wndPlaylistBar.SetCurValid(false); - return hr; - } - break; - case EC_DVD_PLAYBACK_RATE_CHANGE: - if (m_fCustomGraph && s.autoChangeFSMode.bEnabled && - (IsFullScreenMode()) && m_iDVDDomain == DVD_DOMAIN_Title) { - AutoChangeMonitorMode(); - } - break; - case EC_CLOCK_CHANGED: - if (m_pBA && !m_fFrameSteppingActive) { - m_pBA->put_Volume(m_wndToolBar.Volume); - } - break; - case 0xfa17: - // madVR changed graph state - UpdateCachedMediaState(); - break; - case EC_DVD_STILL_ON: - m_bDVDStillOn = true; - break; - case EC_DVD_STILL_OFF: - m_bDVDStillOn = false; - break; - case EC_DVD_BUTTON_CHANGE: - case EC_DVD_SUBPICTURE_STREAM_CHANGE: - case EC_DVD_AUDIO_STREAM_CHANGE: - case EC_DVD_ANGLE_CHANGE: - case EC_DVD_VALID_UOPS_CHANGE: - case EC_DVD_CHAPTER_START: - // no action required - break; - default: - UpdateCachedMediaState(); - TRACE(_T("Unhandled graph event\n")); - } - } - - return hr; -} - -LRESULT CMainFrame::OnResetDevice(WPARAM wParam, LPARAM lParam) -{ - m_OSD.HideMessage(true); - - OAFilterState fs = GetMediaState(); - if (fs == State_Running) { - if (!IsPlaybackCaptureMode()) { - MediaControlPause(true); - } else { - MediaControlStop(true); // Capture mode doesn't support pause - } - } - - if (m_bOpenedThroughThread) { - CAMMsgEvent e; - m_pGraphThread->PostThreadMessage(CGraphThread::TM_RESET, (WPARAM)0, (LPARAM)&e); - e.WaitMsg(); - } else { - ResetDevice(); - } - - if (fs == State_Running && m_pMC) { - MediaControlRun(); - - // When restarting DVB capture, we need to set again the channel. - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - SetChannel(AfxGetAppSettings().nDVBLastChannel); - } - } - } - - if (m_OSD.CanShowMessage()) { - m_OSD.HideMessage(false); - } - - return S_OK; -} - -LRESULT CMainFrame::OnRepaintRenderLess(WPARAM wParam, LPARAM lParam) -{ - MoveVideoWindow(); - return TRUE; -} - -void CMainFrame::SaveAppSettings() -{ - MSG msg; - if (!PeekMessage(&msg, m_hWnd, WM_SAVESETTINGS, WM_SAVESETTINGS, PM_NOREMOVE | PM_NOYIELD)) { - AfxGetAppSettings().SaveSettings(); - } -} - -LRESULT CMainFrame::OnNcHitTest(CPoint point) -{ - LRESULT nHitTest = __super::OnNcHitTest(point); - return ((IsCaptionHidden()) && nHitTest == HTCLIENT) ? HTCAPTION : nHitTest; -} - -void CMainFrame::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - // pScrollBar is null when making horizontal scroll with pen tablet - if (!pScrollBar) return; - - if (pScrollBar->IsKindOf(RUNTIME_CLASS(CVolumeCtrl))) { - OnPlayVolume(0); - } else if (pScrollBar->IsKindOf(RUNTIME_CLASS(CPlayerSeekBar)) && GetLoadState() == MLS::LOADED) { - SeekTo(m_wndSeekBar.GetPos()); - } else if (*pScrollBar == *m_pVideoWnd) { - SeekTo(m_OSD.GetPos()); - } - - __super::OnHScroll(nSBCode, nPos, pScrollBar); -} - -void CMainFrame::RestoreFocus() { - CWnd* curFocus = GetFocus(); - if (curFocus && curFocus != this) { - SetFocus(); - } -} - -void CMainFrame::OnInitMenu(CMenu* pMenu) -{ - __super::OnInitMenu(pMenu); - RestoreFocus(); - - const UINT uiMenuCount = pMenu->GetMenuItemCount(); - if (uiMenuCount == -1) { - return; - } - - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - - for (UINT i = 0; i < uiMenuCount; ++i) { -#ifdef _DEBUG - CString str; - pMenu->GetMenuString(i, str, MF_BYPOSITION); - str.Remove('&'); -#endif - UINT itemID = pMenu->GetMenuItemID(i); - if (itemID == 0xFFFFFFFF) { - mii.fMask = MIIM_ID; - pMenu->GetMenuItemInfo(i, &mii, TRUE); - itemID = mii.wID; - } - - CMPCThemeMenu* pSubMenu = nullptr; - - if (itemID == ID_FAVORITES) { - SetupFavoritesSubMenu(); - pSubMenu = &m_favoritesMenu; - }/*else if (itemID == ID_RECENT_FILES) { - SetupRecentFilesSubMenu(); - pSubMenu = &m_recentFilesMenu; - }*/ - - if (pSubMenu) { - mii.fMask = MIIM_STATE | MIIM_SUBMENU; - mii.fState = (pSubMenu->GetMenuItemCount()) > 0 ? MFS_ENABLED : MFS_DISABLED; - mii.hSubMenu = *pSubMenu; - VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pMenu, i, &mii, TRUE)); - pSubMenu->fulfillThemeReqs(); - } - } -} - -void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) { - __super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu); - - if (bSysMenu) { - m_pActiveSystemMenu = pPopupMenu; - m_eventc.FireEvent(MpcEvent::SYSTEM_MENU_POPUP_INITIALIZED); - return; - } - - UINT uiMenuCount = pPopupMenu->GetMenuItemCount(); - if (uiMenuCount == -1) { - return; - } - - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - - for (UINT i = 0; i < uiMenuCount; ++i) { -#ifdef _DEBUG - CString str; - pPopupMenu->GetMenuString(i, str, MF_BYPOSITION); - str.Remove('&'); -#endif - UINT firstSubItemID = 0; - CMenu* sm = pPopupMenu->GetSubMenu(i); - if (sm) { - firstSubItemID = sm->GetMenuItemID(0); - } - - if (firstSubItemID == ID_NAVIGATE_SKIPBACK) { // is "Navigate" submenu { - UINT fState = (GetLoadState() == MLS::LOADED - && (1/*GetPlaybackMode() == PM_DVD *//*|| (GetPlaybackMode() == PM_FILE && !m_PlayList.IsEmpty())*/)) - ? MF_ENABLED - : MF_GRAYED; - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - if (firstSubItemID == ID_VIEW_VF_HALF // is "Video Frame" submenu - || firstSubItemID == ID_VIEW_INCSIZE // is "Pan&Scan" submenu - || firstSubItemID == ID_ASPECTRATIO_START // is "Override Aspect Ratio" submenu - || firstSubItemID == ID_VIEW_ZOOM_25) { // is "Zoom" submenu - UINT fState = (GetLoadState() == MLS::LOADED && !m_fAudioOnly) - ? MF_ENABLED - : MF_GRAYED; - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - - // "File -> Subtitles" submenu - if (firstSubItemID == ID_FILE_SUBTITLES_LOAD) { - UINT fState = (GetLoadState() == MLS::LOADED && !m_fAudioOnly && m_pCAP) - ? MF_ENABLED - : MF_GRAYED; - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - - // renderer settings - if (firstSubItemID == ID_VIEW_TEARING_TEST) { - UINT fState = MF_GRAYED; - const CAppSettings& s = AfxGetAppSettings(); - if (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC || s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS) { - fState = MF_ENABLED; - } - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - - UINT itemID = pPopupMenu->GetMenuItemID(i); - if (itemID == 0xFFFFFFFF) { - mii.fMask = MIIM_ID; - VERIFY(pPopupMenu->GetMenuItemInfo(i, &mii, TRUE)); - itemID = mii.wID; - } - CMPCThemeMenu* pSubMenu = nullptr; - - // debug shaders - if (itemID == ID_VIEW_DEBUGSHADERS) { - UINT fState = MF_GRAYED; - if (GetLoadState() == MLS::LOADED && !m_fAudioOnly && m_pCAP2) { - fState = MF_ENABLED; - } - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - - if (itemID == ID_FILE_OPENDISC) { - SetupOpenCDSubMenu(); - pSubMenu = &m_openCDsMenu; - } else if (itemID == ID_FILTERS) { - SetupFiltersSubMenu(); - pSubMenu = &m_filtersMenu; - } else if (itemID == ID_AUDIOS) { - SetupAudioSubMenu(); - pSubMenu = &m_audiosMenu; - } else if (itemID == ID_SUBTITLES) { - SetupSubtitlesSubMenu(); - pSubMenu = &m_subtitlesMenu; - } else if (itemID == ID_VIDEO_STREAMS) { - CString menuStr; - menuStr.LoadString(GetPlaybackMode() == PM_DVD ? IDS_MENU_VIDEO_ANGLE : IDS_MENU_VIDEO_STREAM); - - mii.fMask = MIIM_STRING; - mii.dwTypeData = (LPTSTR)(LPCTSTR)menuStr; - VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pPopupMenu, i, &mii, TRUE)); - - SetupVideoStreamsSubMenu(); - pSubMenu = &m_videoStreamsMenu; - } else if (itemID == ID_NAVIGATE_GOTO) { - // ID_NAVIGATE_GOTO is just a marker we use to insert the appropriate submenus - SetupJumpToSubMenus(pPopupMenu, i + 1); - uiMenuCount = pPopupMenu->GetMenuItemCount(); //SetupJumpToSubMenus could actually reduce the menu count! - } else if (itemID == ID_FAVORITES) { - SetupFavoritesSubMenu(); - pSubMenu = &m_favoritesMenu; - } else if (itemID == ID_RECENT_FILES) { - SetupRecentFilesSubMenu(); - pSubMenu = &m_recentFilesMenu; - } else if (itemID == ID_SHADERS) { - if (SetupShadersSubMenu()) { - pPopupMenu->EnableMenuItem(ID_SHADERS, MF_BYPOSITION | MF_ENABLED); - } else { - pPopupMenu->EnableMenuItem(ID_SHADERS, MF_BYPOSITION | MF_GRAYED); - } - pSubMenu = &m_shadersMenu; - } - - if (pSubMenu) { - mii.fMask = MIIM_STATE | MIIM_SUBMENU; - mii.fState = (pSubMenu->GetMenuItemCount() > 0) ? MF_ENABLED : MF_GRAYED; - mii.hSubMenu = *pSubMenu; - VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pPopupMenu, i, &mii, TRUE)); - pSubMenu->fulfillThemeReqs(); - } - } - - uiMenuCount = pPopupMenu->GetMenuItemCount(); - if (uiMenuCount == -1) { - return; - } - - if (!AppIsThemeLoaded()) { //themed menus draw accelerators already, no need to append - for (UINT i = 0; i < uiMenuCount; ++i) { - UINT nID = pPopupMenu->GetMenuItemID(i); - if (nID == ID_SEPARATOR || nID == -1 - || nID >= ID_FAVORITES_FILE_START && nID <= ID_FAVORITES_FILE_END - || nID >= ID_RECENT_FILE_START && nID <= ID_RECENT_FILE_END - || nID >= ID_SUBTITLES_SUBITEM_START && nID <= ID_SUBTITLES_SUBITEM_END - || nID >= ID_NAVIGATE_JUMPTO_SUBITEM_START && nID <= ID_NAVIGATE_JUMPTO_SUBITEM_END) { - continue; - } - - CString str; - pPopupMenu->GetMenuString(i, str, MF_BYPOSITION); - int k = str.Find('\t'); - if (k > 0) { - str = str.Left(k); - } - - CString key = CPPageAccelTbl::MakeAccelShortcutLabel(nID); - if (key.IsEmpty() && k < 0) { - continue; - } - str += _T("\t") + key; - - // BUG(?): this disables menu item update ui calls for some reason... - //pPopupMenu->ModifyMenu(i, MF_BYPOSITION|MF_STRING, nID, str); - - // this works fine - mii.fMask = MIIM_STRING; - mii.dwTypeData = (LPTSTR)(LPCTSTR)str; - VERIFY(pPopupMenu->SetMenuItemInfo(i, &mii, TRUE)); - } - } - - uiMenuCount = pPopupMenu->GetMenuItemCount(); - if (uiMenuCount == -1) { - return; - } - - bool fPnSPresets = false; - - for (UINT i = 0; i < uiMenuCount; ++i) { - UINT nID = pPopupMenu->GetMenuItemID(i); - - if (nID >= ID_PANNSCAN_PRESETS_START && nID < ID_PANNSCAN_PRESETS_END) { - do { - nID = pPopupMenu->GetMenuItemID(i); - VERIFY(pPopupMenu->DeleteMenu(i, MF_BYPOSITION)); - uiMenuCount--; - } while (i < uiMenuCount && nID >= ID_PANNSCAN_PRESETS_START && nID < ID_PANNSCAN_PRESETS_END); - - nID = pPopupMenu->GetMenuItemID(i); - } - - if (nID == ID_VIEW_RESET) { - fPnSPresets = true; - } - } - - if (fPnSPresets) { - bool usetheme = AppIsThemeLoaded(); - const CAppSettings& s = AfxGetAppSettings(); - INT_PTR i = 0, j = s.m_pnspresets.GetCount(); - for (; i < j; i++) { - int k = 0; - CString label = s.m_pnspresets[i].Tokenize(_T(","), k); - VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND, ID_PANNSCAN_PRESETS_START + i, label)); - CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, (UINT)(ID_PANNSCAN_PRESETS_START + i), true); - } - //if (j > 0) - { - VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND, ID_PANNSCAN_PRESETS_START + i, ResStr(IDS_PANSCAN_EDIT))); - VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND | MF_SEPARATOR)); - if (usetheme) { - CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, (UINT)(ID_PANNSCAN_PRESETS_START + i), true); - UINT pos = CMPCThemeMenu::getPosFromID(pPopupMenu, ID_VIEW_RESET); //separator is inserted right before view_reset - CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, pos - 1); - } - } - } - - if (m_pActiveContextMenu == pPopupMenu) { - m_eventc.FireEvent(MpcEvent::CONTEXT_MENU_POPUP_INITIALIZED); - } -} - -void CMainFrame::OnUnInitMenuPopup(CMenu* pPopupMenu, UINT nFlags) -{ - __super::OnUnInitMenuPopup(pPopupMenu, nFlags); - if (m_pActiveContextMenu == pPopupMenu) { - m_pActiveContextMenu = nullptr; - m_eventc.FireEvent(MpcEvent::CONTEXT_MENU_POPUP_UNINITIALIZED); - } else if (m_pActiveSystemMenu == pPopupMenu) { - m_pActiveSystemMenu = nullptr; - SendMessage(WM_CANCELMODE); // unfocus main menu if system menu was entered with alt+space - m_eventc.FireEvent(MpcEvent::SYSTEM_MENU_POPUP_UNINITIALIZED); - } -} - -void CMainFrame::OnEnterMenuLoop(BOOL bIsTrackPopupMenu) -{ - if (!bIsTrackPopupMenu && !m_pActiveSystemMenu && GetMenuBarState() == AFX_MBS_HIDDEN) { - // mfc has problems synchronizing menu visibility with modal loop in certain situations - ASSERT(!m_pActiveContextMenu); - VERIFY(SetMenuBarState(AFX_MBS_VISIBLE)); - } - __super::OnEnterMenuLoop(bIsTrackPopupMenu); -} - -BOOL CMainFrame::OnQueryEndSession() -{ - return TRUE; -} - -void CMainFrame::OnEndSession(BOOL bEnding) -{ - // do nothing for now -} - -BOOL CMainFrame::OnMenu(CMenu* pMenu) -{ - if (!pMenu) { - return FALSE; - } - - CPoint point; - GetCursorPos(&point); - - // Do not show popup menu in D3D fullscreen it has several adverse effects. - if (IsD3DFullScreenMode()) { - CWnd* pWnd = WindowFromPoint(point); - if (pWnd && *pWnd == *m_pDedicatedFSVideoWnd) { - return FALSE; - } - } - - if (AfxGetMyApp()->m_fClosingState) { - return FALSE; //prevent crash when player closes with context menu open - } - - m_pActiveContextMenu = pMenu; - - pMenu->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NOANIMATION, point.x, point.y, this); - - return TRUE; -} - -void CMainFrame::OnMenuPlayerShort() -{ - if (!AfxGetAppSettings().bAlwaysUseShortMenu && (IsMenuHidden() || IsD3DFullScreenMode())) { - OnMenu(m_mainPopupMenu.GetSubMenu(0)); - } else { - OnMenu(m_popupMenu.GetSubMenu(0)); - } -} - -void CMainFrame::OnMenuPlayerLong() -{ - OnMenu(m_mainPopupMenu.GetSubMenu(0)); -} - -void CMainFrame::OnMenuFilters() -{ - SetupFiltersSubMenu(); - OnMenu(&m_filtersMenu); -} - -void CMainFrame::OnUpdatePlayerStatus(CCmdUI* pCmdUI) -{ - if (GetLoadState() == MLS::LOADING) { - m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_OPENING)); - if (AfxGetAppSettings().bUseEnhancedTaskBar && m_pTaskbarList) { - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_INDETERMINATE); - } - } else if (GetLoadState() == MLS::LOADED) { - if (!m_tempstatus_msg.IsEmpty()) { - m_wndStatusBar.SetStatusMessage(m_tempstatus_msg); - return; - } - CString msg; - if (m_fCapturing) { - msg.LoadString(IDS_CONTROLS_CAPTURING); - - if (m_pAMDF) { - long lDropped = 0; - m_pAMDF->GetNumDropped(&lDropped); - long lNotDropped = 0; - m_pAMDF->GetNumNotDropped(&lNotDropped); - - if ((lDropped + lNotDropped) > 0) { - msg.AppendFormat(IDS_MAINFRM_37, lDropped + lNotDropped, lDropped); - } - } - - CComPtr pPin; - if (m_pCGB && SUCCEEDED(m_pCGB->FindPin(m_wndCaptureBar.m_capdlg.m_pDst, PINDIR_INPUT, nullptr, nullptr, FALSE, 0, &pPin))) { - LONGLONG size = 0; - if (CComQIPtr pStream = pPin) { - pStream->Commit(STGC_DEFAULT); - - WIN32_FIND_DATA findFileData; - HANDLE h = FindFirstFile(m_wndCaptureBar.m_capdlg.m_file, &findFileData); - if (h != INVALID_HANDLE_VALUE) { - size = ((LONGLONG)findFileData.nFileSizeHigh << 32) | findFileData.nFileSizeLow; - - if (size < 1024i64 * 1024) { - msg.AppendFormat(IDS_MAINFRM_38, size / 1024); - } else { //if (size < 1024i64*1024*1024) - msg.AppendFormat(IDS_MAINFRM_39, size / 1024 / 1024); - } - - FindClose(h); - } - } - - ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes, TotalNumberOfFreeBytes; - if (GetDiskFreeSpaceEx( - m_wndCaptureBar.m_capdlg.m_file.Left(m_wndCaptureBar.m_capdlg.m_file.ReverseFind('\\') + 1), - &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) { - if (FreeBytesAvailable.QuadPart < 1024i64 * 1024) { - msg.AppendFormat(IDS_MAINFRM_40, FreeBytesAvailable.QuadPart / 1024); - } else { //if (FreeBytesAvailable.QuadPart < 1024i64*1024*1024) - msg.AppendFormat(IDS_MAINFRM_41, FreeBytesAvailable.QuadPart / 1024 / 1024); - } - } - - if (m_wndCaptureBar.m_capdlg.m_pMux) { - __int64 pos = 0; - CComQIPtr pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux; - if (pMuxMS && SUCCEEDED(pMuxMS->GetCurrentPosition(&pos)) && pos > 0) { - double bytepersec = 10000000.0 * size / pos; - if (bytepersec > 0) { - m_rtDurationOverride = REFERENCE_TIME(10000000.0 * (FreeBytesAvailable.QuadPart + size) / bytepersec); - } - } - } - - if (m_wndCaptureBar.m_capdlg.m_pVidBuffer - || m_wndCaptureBar.m_capdlg.m_pAudBuffer) { - int nFreeVidBuffers = 0, nFreeAudBuffers = 0; - if (CComQIPtr pVB = m_wndCaptureBar.m_capdlg.m_pVidBuffer) { - nFreeVidBuffers = pVB->GetFreeBuffers(); - } - if (CComQIPtr pAB = m_wndCaptureBar.m_capdlg.m_pAudBuffer) { - nFreeAudBuffers = pAB->GetFreeBuffers(); - } - - msg.AppendFormat(IDS_MAINFRM_42, nFreeVidBuffers, nFreeAudBuffers); - } - } - } else if (m_bBuffering) { - if (m_pAMNS) { - long BufferingProgress = 0; - if (SUCCEEDED(m_pAMNS->get_BufferingProgress(&BufferingProgress)) && BufferingProgress > 0) { - msg.Format(IDS_CONTROLS_BUFFERING, BufferingProgress); - - __int64 start = 0, stop = 0; - m_wndSeekBar.GetRange(start, stop); - m_fLiveWM = (stop == start); - } - } - } else if (m_pAMOP) { - LONGLONG t = 0, c = 0; - if (SUCCEEDED(m_pAMOP->QueryProgress(&t, &c)) && t > 0 && c < t) { - msg.Format(IDS_CONTROLS_BUFFERING, c * 100 / t); - } else { - m_pAMOP.Release(); - } - } - - if (msg.IsEmpty()) { - int msg_id = 0; - switch (m_CachedFilterState) { - case State_Stopped: - msg_id = IDS_CONTROLS_STOPPED; - break; - case State_Paused: - msg_id = IDS_CONTROLS_PAUSED; - break; - case State_Running: - msg_id = IDS_CONTROLS_PLAYING; - break; - } - if (m_fFrameSteppingActive) { - msg_id = IDS_CONTROLS_PAUSED; - } - if (msg_id) { - msg.LoadString(msg_id); - - if (m_bUsingDXVA && (msg_id == IDS_CONTROLS_PAUSED || msg_id == IDS_CONTROLS_PLAYING)) { - msg.AppendFormat(_T(" %s"), ResStr(IDS_HW_INDICATOR).GetString()); - } - } - - auto& s = AfxGetAppSettings(); - - CString videoinfo; - CString fpsinfo; - CStringW audioinfo; - if (s.bShowVideoInfoInStatusbar && (!m_statusbarVideoFormat.IsEmpty() || !m_statusbarVideoSize.IsEmpty())) { - if(!m_statusbarVideoFormat.IsEmpty()) { - videoinfo.Append(m_statusbarVideoFormat); - } - if(!m_statusbarVideoSize.IsEmpty()) { - if(!m_statusbarVideoFormat.IsEmpty()) { - videoinfo.AppendChar(_T(' ')); - } - videoinfo.Append(m_statusbarVideoSize); - } - } - if (s.bShowFPSInStatusbar && m_pCAP) { - if (m_dSpeedRate != 1.0) { - fpsinfo.Format(_T("%.2lf fps (%.2lfx)"), m_pCAP->GetFPS(), m_dSpeedRate); - } else { - fpsinfo.Format(_T("%.2lf fps"), m_pCAP->GetFPS()); - } - } - - if (s.bShowAudioFormatInStatusbar && !m_statusbarAudioFormat.IsEmpty()) { - audioinfo = m_statusbarAudioFormat; - } - - if (!videoinfo.IsEmpty() || !fpsinfo.IsEmpty()) { - CStringW tinfo = L""; - AppendWithDelimiter(tinfo, videoinfo); - AppendWithDelimiter(tinfo, fpsinfo); - msg.Append(L"\u2001[" + tinfo + L"]"); - } - - if (!audioinfo.IsEmpty()) { - msg.Append(L"\u2001[" + audioinfo); - if (s.bShowLangInStatusbar && !currentAudioLang.IsEmpty()) { - msg.Append(L" " + currentAudioLang); - } - msg.Append(L"]"); - } - - if (s.bShowLangInStatusbar) { - bool showaudiolang = audioinfo.IsEmpty() && !currentAudioLang.IsEmpty(); - if (showaudiolang || !currentSubLang.IsEmpty()) { - msg.Append(_T("\u2001[")); - if (showaudiolang) { - msg.Append(L"AUD: " + currentAudioLang); - } - if (!currentSubLang.IsEmpty()) { - if (showaudiolang) { - msg.Append(_T(", ")); - } - msg.Append(L"SUB: " + currentSubLang); - } - msg.Append(_T("]")); - } - } - if (s.bShowABMarksInStatusbar) { - if (abRepeat) { - REFERENCE_TIME actualB = abRepeat.positionB; - if (actualB == 0) { - REFERENCE_TIME start = 0; - m_wndSeekBar.GetRange(start, actualB); - } - bool showhours = (actualB >= 35995000000) || (abRepeat.positionA >= 35995000000); - CString timeMarkA = showhours ? ReftimeToString2(abRepeat.positionA) : ReftimeToString3(abRepeat.positionA); - CString timeMarkB = showhours ? ReftimeToString2(actualB) : ReftimeToString3(actualB); - msg.AppendFormat(_T("\u2001[A-B %s > %s]"), timeMarkA.GetString(), timeMarkB.GetString()); - } - } - } - - m_wndStatusBar.SetStatusMessage(msg); - } else if (GetLoadState() == MLS::CLOSING) { - m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_CLOSING)); - if (AfxGetAppSettings().bUseEnhancedTaskBar && m_pTaskbarList) { - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_INDETERMINATE); - } - } else { - m_wndStatusBar.SetStatusMessage(m_closingmsg); - } -} - -LRESULT CMainFrame::OnFilePostOpenmedia(WPARAM wParam, LPARAM lParam) -{ - if (!m_pGB) { - ASSERT(FALSE); - return 1; - } - ASSERT(GetLoadState() == MLS::LOADING); - - auto& s = AfxGetAppSettings(); - - // from this on - m_bOpenMediaActive = false; - m_OpenMediaFailedCount = 0; - m_bSettingUpMenus = true; - - SetLoadState(MLS::LOADED); - ASSERT(GetMediaStateDirect() == State_Stopped); - - // destroy invisible top-level d3dfs window if there is no video renderer - if (HasDedicatedFSVideoWindow() && !m_pMFVDC && !m_pVMRWC && !m_pVW) { - m_pDedicatedFSVideoWnd->DestroyWindow(); - if (s.IsD3DFullscreen()) { - m_fStartInD3DFullscreen = true; - } else { - m_fStartInFullscreenSeparate = true; - } - } - - // auto-change monitor mode if requested - if (s.autoChangeFSMode.bEnabled && IsFullScreenMode()) { - AutoChangeMonitorMode(); - // make sure the fullscreen window is positioned properly after the mode change, - // OnWindowPosChanging() will take care of that - if (m_bOpeningInAutochangedMonitorMode && m_fFullScreen) { - CRect rect; - GetWindowRect(rect); - MoveWindow(rect); - } - } - - // set shader selection - if (m_pCAP || m_pCAP2) { - SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); - } - - // load keyframes for fast-seek - if (wParam == PM_FILE) { - LoadKeyFrames(); - } - - // remember OpenMediaData for later use - m_lastOMD.Free(); - m_lastOMD.Attach((OpenMediaData*)lParam); - if (!m_lastOMD->title) { - ASSERT(false); - m_lastOMD->title = L""; - } - - // the media opened successfully, we don't want to jump trough it anymore - UINT lastSkipDirection = m_nLastSkipDirection; - m_nLastSkipDirection = 0; - - // let the EDL do its magic - if (s.fEnableEDLEditor && !m_lastOMD->title.IsEmpty()) { - m_wndEditListEditor.OpenFile(m_lastOMD->title); - } - - // initiate Capture panel with the new media - if (auto pDeviceData = dynamic_cast(m_lastOMD.m_p)) { - m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput); - m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel); - m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput); - } - - // current playlist item was loaded successfully - m_wndPlaylistBar.SetCurValid(true); - - // set item duration in the playlist - // TODO: GetDuration() should be refactored out of this place, to some aggregating class - REFERENCE_TIME rtDur = 0; - if (m_pMS && m_pMS->GetDuration(&rtDur) == S_OK) { - m_wndPlaylistBar.SetCurTime(rtDur); - } - - // process /pns command-line arg, then discard it - ApplyPanNScanPresetString(); - - // initiate toolbars with the new media - OpenSetupInfoBar(); - OpenSetupStatsBar(); - OpenSetupStatusBar(); - OpenSetupCaptureBar(); - - // Load cover-art - if (m_fAudioOnly || HasDedicatedFSVideoWindow()) { - UpdateControlState(CMainFrame::UPDATE_LOGO); - } - - if (s.bOpenRecPanelWhenOpeningDevice) { - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - // show navigation panel when it's available and not disabled - if (!s.fHideNavigation) { - m_wndNavigationBar.m_navdlg.UpdateElementList(); - if (!m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); - } - else { - ASSERT(FALSE); - } - } - } - else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - // show capture bar - if (!m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)) { - m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); - } - else { - ASSERT(FALSE); - } - } - } - - // we don't want to wait until timers initialize the seekbar and the time counter - OnTimer(TIMER_STREAMPOSPOLLER); - OnTimer(TIMER_STREAMPOSPOLLER2); - - if (m_AngleX != 0 || m_AngleY != 0 || m_AngleZ != 0) { - PerformFlipRotate(); - } - - bool go_fullscreen = s.fLaunchfullscreen && !m_fAudioOnly && !IsFullScreenMode() && lastSkipDirection == 0 && !(s.nCLSwitches & CLSW_THUMBNAILS); - - // auto-zoom if requested - if (IsWindowVisible() && s.fRememberZoomLevel && !IsFullScreenMode() && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { - if (go_fullscreen) { - m_bNeedZoomAfterFullscreenExit = true; - } - ZoomVideoWindow(ZOOM_DEFAULT_LEVEL, go_fullscreen); - } - - if (go_fullscreen) { - OnViewFullscreen(); - } - - // Add temporary flag to allow EC_VIDEO_SIZE_CHANGED event to stabilize window size - // for 5 seconds since playback starts - m_bAllowWindowZoom = true; - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::AUTOFIT_TIMEOUT, [this] - { m_bAllowWindowZoom = false; }, 5000); - - // update control bar areas and paint bypassing the message queue - RecalcLayout(); - UpdateWindow(); - - // the window is repositioned and repainted, video renderer rect is ready to be set - - // OnPlayPlay()/OnPlayPause() will take care of that - m_bDelaySetOutputRect = false; - - if (s.nCLSwitches & CLSW_THUMBNAILS) { - MoveVideoWindow(false, true); - MediaControlPause(true); - SendMessageW(WM_COMMAND, ID_CMDLINE_SAVE_THUMBNAILS); - m_bSettingUpMenus = false; - m_bRememberFilePos = false; - SendMessageW(WM_COMMAND, ID_FILE_EXIT); - return 0; - } - - MediaTransportControlSetMedia(); - - // start playback if requested - m_bFirstPlay = true; - const auto uModeChangeDelay = s.autoChangeFSMode.uDelay * 1000; - if (!(s.nCLSwitches & CLSW_OPEN) && (s.nLoops > 0)) { - if (m_bOpeningInAutochangedMonitorMode && uModeChangeDelay) { - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, - std::bind(&CMainFrame::OnPlayPlay, this), uModeChangeDelay); - } else { - OnPlayPlay(); - } - } else { - // OnUpdatePlayPauseStop() will decide if we can pause the media - if (m_bOpeningInAutochangedMonitorMode && uModeChangeDelay) { - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, - [this] { OnCommand(ID_PLAY_PAUSE, 0); }, uModeChangeDelay); - } else { - OnCommand(ID_PLAY_PAUSE, 0); - } - } - s.nCLSwitches &= ~CLSW_OPEN; - - // Ensure the dynamically added menu items are updated - SetupFiltersSubMenu(); - SetupAudioSubMenu(); - SetupSubtitlesSubMenu(); - SetupVideoStreamsSubMenu(); - SetupJumpToSubMenus(); - SetupRecentFilesSubMenu(); - - // notify listeners - if (GetPlaybackMode() != PM_DIGITAL_CAPTURE) { - SendNowPlayingToSkype(); - SendNowPlayingToApi(); - } - - if (CanPreviewUse() && m_wndSeekBar.IsVisible()) { - CPoint point; - GetCursorPos(&point); - - CRect rect; - m_wndSeekBar.GetWindowRect(&rect); - if (rect.PtInRect(point)) { - m_wndSeekBar.PreviewWindowShow(point); - } - } - - m_bSettingUpMenus = false; - - return 0; -} - -LRESULT CMainFrame::OnOpenMediaFailed(WPARAM wParam, LPARAM lParam) -{ - ASSERT(GetLoadState() == MLS::LOADING); - SetLoadState(MLS::FAILING); - - ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); - const auto& s = AfxGetAppSettings(); - - m_lastOMD.Free(); - m_lastOMD.Attach((OpenMediaData*)lParam); - if (!m_lastOMD->title) { - ASSERT(false); - m_lastOMD->title = L""; - } - - bool bOpenNextInPlaylist = false; - bool bAfterPlaybackEvent = false; - - m_bOpenMediaActive = false; - m_OpenMediaFailedCount++; - - m_dwReloadPos = 0; - reloadABRepeat = ABRepeat(); - m_iReloadAudioIdx = -1; - m_iReloadSubIdx = -1; - - if (wParam == PM_FILE && m_OpenMediaFailedCount < 5) { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli) && pli.m_bYoutubeDL && m_sydlLastProcessURL != pli.m_ydlSourceURL) { - OpenCurPlaylistItem(0, true); // Try to reprocess if failed first time. - return 0; - } - if (m_wndPlaylistBar.GetCount() == 1) { - if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { - bOpenNextInPlaylist = SearchInDir(false, s.bLoopFolderOnPlayNextFile); - if (!bOpenNextInPlaylist) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_FIRST_IN_FOLDER)); - } - } else if (m_nLastSkipDirection == ID_NAVIGATE_SKIPFORWARD) { - bOpenNextInPlaylist = SearchInDir(true, s.bLoopFolderOnPlayNextFile); - if (!bOpenNextInPlaylist) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_LAST_IN_FOLDER)); - } - } - } else { - m_wndPlaylistBar.SetCurValid(false); - - if (m_wndPlaylistBar.IsAtEnd()) { - m_nLoops++; - } - - if (s.fLoopForever || m_nLoops < s.nLoops) { - if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { - bOpenNextInPlaylist = m_wndPlaylistBar.SetPrev(); - } else { - bOpenNextInPlaylist = m_wndPlaylistBar.SetNext(); - } - } else { - bAfterPlaybackEvent = true; - } - } - } - - CloseMedia(bOpenNextInPlaylist); - - if (m_OpenMediaFailedCount >= 5) { - m_wndPlaylistBar.SetCurValid(false); - if (m_wndPlaylistBar.IsAtEnd()) { - m_nLoops++; - } - if (s.fLoopForever || m_nLoops < s.nLoops) { - if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { - m_wndPlaylistBar.SetPrev(); - } else { - m_wndPlaylistBar.SetNext(); - } - } - m_OpenMediaFailedCount = 0; - } - else if (bOpenNextInPlaylist) { - OpenCurPlaylistItem(); - } - else if (bAfterPlaybackEvent) { - DoAfterPlaybackEvent(); - } - - return 0; -} - -void CMainFrame::OnFilePostClosemedia(bool bNextIsQueued/* = false*/) -{ - SetPlaybackMode(PM_NONE); - SetLoadState(MLS::CLOSED); - - m_bOpenMediaActive = false; - - abRepeat = ABRepeat(); - m_kfs.clear(); - - m_nCurSubtitle = -1; - m_lSubtitleShift = 0; - - CAppSettings& s = AfxGetAppSettings(); - if (!s.fSavePnSZoom) { - m_AngleX = m_AngleY = m_AngleZ = 0; - m_ZoomX = m_ZoomY = 1.0; - m_PosX = m_PosY = 0.5; - } - - if (m_closingmsg.IsEmpty()) { - m_closingmsg.LoadString(IDS_CONTROLS_CLOSED); - } - - m_wndView.SetVideoRect(); - m_wndSeekBar.Enable(false); - m_wndSeekBar.SetRange(0, 0); - m_wndSeekBar.SetPos(0); - m_wndSeekBar.RemoveChapters(); - m_wndInfoBar.RemoveAllLines(); - m_wndStatsBar.RemoveAllLines(); - m_wndStatusBar.Clear(); - m_wndStatusBar.ShowTimer(false); - currentAudioLang.Empty(); - currentSubLang.Empty(); - m_OSD.SetRange(0); - m_OSD.SetPos(0); - m_Lcd.SetMediaRange(0, 0); - m_Lcd.SetMediaPos(0); - m_statusbarVideoFormat.Empty(); - m_statusbarVideoSize.Empty(); - - m_VidDispName.Empty(); - m_AudDispName.Empty(); - m_HWAccelType = L""; - - if (!bNextIsQueued) { - UpdateControlState(CMainFrame::UPDATE_LOGO); - RecalcLayout(); - } - - if (s.fEnableEDLEditor) { - m_wndEditListEditor.CloseFile(); - } - - if (m_controls.ControlChecked(CMainFrameControls::Panel::SUBRESYNC)) { - m_controls.ToggleControl(CMainFrameControls::Panel::SUBRESYNC); - } - - if (m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)) { - m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); - } - m_wndCaptureBar.m_capdlg.SetupVideoControls(_T(""), nullptr, nullptr, nullptr); - m_wndCaptureBar.m_capdlg.SetupAudioControls(_T(""), nullptr, CInterfaceArray()); - - if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); - } - - if (!bNextIsQueued) { - OpenSetupWindowTitle(true); - } - - SetAlwaysOnTop(s.iOnTop); - - SendNowPlayingToSkype(); - - // try to release external objects - UnloadUnusedExternalObjects(); - SetTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS, 60000, nullptr); - - if (HasDedicatedFSVideoWindow()) { - if (IsD3DFullScreenMode()) { - m_fStartInD3DFullscreen = true; - } else { - m_fStartInFullscreenSeparate = true; - } - if (!bNextIsQueued) { - m_pDedicatedFSVideoWnd->DestroyWindow(); - } - } - - UpdateWindow(); // redraw -} - -void CMainFrame::OnBossKey() -{ - // Disable animation - ANIMATIONINFO AnimationInfo; - AnimationInfo.cbSize = sizeof(ANIMATIONINFO); - ::SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - int m_WindowAnimationType = AnimationInfo.iMinAnimate; - AnimationInfo.iMinAnimate = 0; - ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - if (IsFullScreenMode()) { - SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN); - } - SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, -1); - - // Enable animation - AnimationInfo.iMinAnimate = m_WindowAnimationType; - ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); -} - -void CMainFrame::OnStreamAudio(UINT nID) -{ - nID -= ID_STREAM_AUDIO_NEXT; - - if (GetLoadState() != MLS::LOADED) { - return; - } - - DWORD cStreams = 0; - if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 1) { - for (DWORD i = 0; i < cStreams; i++) { - DWORD dwFlags = 0; - DWORD dwGroup = 0; - if (FAILED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { - return; - } - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - long stream_index = (i + (nID == 0 ? 1 : cStreams - 1)) % cStreams; - if (SUCCEEDED(m_pAudioSwitcherSS->Enable(stream_index, AMSTREAMSELECTENABLE_ENABLE))) { - LCID lcid = 0; - CComHeapPtr pszName; - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(m_pAudioSwitcherSS->Info(stream_index, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) { - m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pszName), lcid, 1)); - UpdateSelectedAudioStreamInfo(stream_index, pmt, lcid); - DeleteMediaType(pmt); - } - } - break; - } - } - } else if (GetPlaybackMode() == PM_FILE) { - OnStreamSelect(nID == 0, 1); - } else if (GetPlaybackMode() == PM_DVD) { - SendMessage(WM_COMMAND, ID_DVD_AUDIO_NEXT + nID); - } - - if (m_pBA && !m_fFrameSteppingActive) { - m_pBA->put_Volume(m_wndToolBar.Volume); - } -} - -void CMainFrame::OnStreamSub(UINT nID) -{ - nID -= ID_STREAM_SUB_NEXT; - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (!m_pSubStreams.IsEmpty()) { - AfxGetAppSettings().fEnableSubtitles = true; - SetSubtitle(nID == 0 ? 1 : -1, true, true); - SetFocus(); - } else if (GetPlaybackMode() == PM_FILE) { - OnStreamSelect(nID == 0, 2); - } else if (GetPlaybackMode() == PM_DVD) { - SendMessage(WM_COMMAND, ID_DVD_SUB_NEXT + nID); - } -} - -void CMainFrame::OnStreamSubOnOff() -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pCAP && !m_pSubStreams.IsEmpty() || m_pDVS) { - ToggleSubtitleOnOff(true); - SetFocus(); - } else if (GetPlaybackMode() == PM_DVD) { - SendMessage(WM_COMMAND, ID_DVD_SUB_ONOFF); - } -} - -void CMainFrame::OnDvdAngle(UINT nID) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pDVDI && m_pDVDC) { - ULONG ulAnglesAvailable, ulCurrentAngle; - if (SUCCEEDED(m_pDVDI->GetCurrentAngle(&ulAnglesAvailable, &ulCurrentAngle)) && ulAnglesAvailable > 1) { - ulCurrentAngle += (nID == ID_DVD_ANGLE_NEXT) ? 1 : -1; - if (ulCurrentAngle > ulAnglesAvailable) { - ulCurrentAngle = 1; - } else if (ulCurrentAngle < 1) { - ulCurrentAngle = ulAnglesAvailable; - } - m_pDVDC->SelectAngle(ulCurrentAngle, DVD_CMD_FLAG_Block, nullptr); - - CString osdMessage; - osdMessage.Format(IDS_AG_ANGLE, ulCurrentAngle); - m_OSD.DisplayMessage(OSD_TOPLEFT, osdMessage); - } - } -} - -void CMainFrame::OnDvdAudio(UINT nID) -{ - nID -= ID_DVD_AUDIO_NEXT; - - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pDVDI && m_pDVDC) { - ULONG nStreamsAvailable, nCurrentStream; - if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&nStreamsAvailable, &nCurrentStream)) && nStreamsAvailable > 1) { - DVD_AudioAttributes AATR; - UINT nNextStream = (nCurrentStream + (nID == 0 ? 1 : nStreamsAvailable - 1)) % nStreamsAvailable; - - HRESULT hr = m_pDVDC->SelectAudioStream(nNextStream, DVD_CMD_FLAG_Block, nullptr); - if (SUCCEEDED(m_pDVDI->GetAudioAttributes(nNextStream, &AATR))) { - CString lang; - CString strMessage; - if (AATR.Language) { - GetLocaleString(AATR.Language, LOCALE_SENGLANGUAGE, lang); - currentAudioLang = lang; - } else { - lang.Format(IDS_AG_UNKNOWN, nNextStream + 1); - currentAudioLang.Empty(); - } - - CString format = GetDVDAudioFormatName(AATR); - CString str; - - if (!format.IsEmpty()) { - str.Format(IDS_MAINFRM_11, - lang.GetString(), - format.GetString(), - AATR.dwFrequency, - AATR.bQuantization, - AATR.bNumberOfChannels, - ResStr(AATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString()); - if (FAILED(hr)) { - str += _T(" [") + ResStr(IDS_AG_ERROR) + _T("] "); - } - strMessage.Format(IDS_AUDIO_STREAM, str.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, strMessage); - } - } - } - } -} - -void CMainFrame::OnDvdSub(UINT nID) -{ - nID -= ID_DVD_SUB_NEXT; - - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pDVDI && m_pDVDC) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) - && ulStreamsAvailable > 1) { - //UINT nNextStream = (ulCurrentStream+(nID==0?1:ulStreamsAvailable-1))%ulStreamsAvailable; - int nNextStream; - - if (!bIsDisabled) { - nNextStream = ulCurrentStream + (nID == 0 ? 1 : -1); - } else { - nNextStream = (nID == 0 ? 0 : ulStreamsAvailable - 1); - } - - if (!bIsDisabled && ((nNextStream < 0) || ((ULONG)nNextStream >= ulStreamsAvailable))) { - m_pDVDC->SetSubpictureState(FALSE, DVD_CMD_FLAG_Block, nullptr); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_SUBTITLE_STREAM_OFF)); - } else { - HRESULT hr = m_pDVDC->SelectSubpictureStream(nNextStream, DVD_CMD_FLAG_Block, nullptr); - - DVD_SubpictureAttributes SATR; - m_pDVDC->SetSubpictureState(TRUE, DVD_CMD_FLAG_Block, nullptr); - if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(nNextStream, &SATR))) { - CString lang; - CString strMessage; - GetLocaleString(SATR.Language, LOCALE_SENGLANGUAGE, lang); - - if (FAILED(hr)) { - lang += _T(" [") + ResStr(IDS_AG_ERROR) + _T("] "); - } - strMessage.Format(IDS_SUBTITLE_STREAM, lang.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, strMessage); - } - } - } - } -} - -void CMainFrame::OnDvdSubOnOff() -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pDVDI && m_pDVDC) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { - m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); - } - } -} - -// -// menu item handlers -// - -// file - -INT_PTR CMainFrame::DoFileDialogWithLastFolder(CFileDialog& fd, CStringW& lastPath) { - if (!lastPath.IsEmpty()) { - fd.m_ofn.lpstrInitialDir = lastPath; - } - INT_PTR ret = fd.DoModal(); - if (ret == IDOK) { - lastPath = GetFolderOnly(fd.m_ofn.lpstrFile); - } - return ret; -} - - -void CMainFrame::OnFileOpenQuick() -{ - if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar)) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - CString filter; - CAtlArray mask; - s.m_Formats.GetFilter(filter, mask); - - DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_ALLOWMULTISELECT | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - if (!s.fKeepHistory) { - dwFlags |= OFN_DONTADDTORECENT; - } - - COpenFileDlg fd(mask, true, nullptr, nullptr, dwFlags, filter, GetModalParent()); - if (DoFileDialogWithLastFolder(fd, s.lastQuickOpenPath) != IDOK) { - return; - } - - CAtlList fns; - - POSITION pos = fd.GetStartPosition(); - while (pos) { - fns.AddTail(fd.GetNextPathName(pos)); - } - - bool fMultipleFiles = false; - - if (fns.GetCount() > 1 - || fns.GetCount() == 1 - && (fns.GetHead()[fns.GetHead().GetLength() - 1] == '\\' - || fns.GetHead()[fns.GetHead().GetLength() - 1] == '*')) { - fMultipleFiles = true; - } - - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - SetForegroundWindow(); - - if (fns.GetCount() == 1) { - if (OpenBD(fns.GetHead())) { - return; - } - } - - m_wndPlaylistBar.Open(fns, fMultipleFiles); - - OpenCurPlaylistItem(); -} - -void CMainFrame::OnFileOpenmedia() -{ - if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar) || IsD3DFullScreenMode()) { - return; - } - - static COpenDlg dlg; - if (IsWindow(dlg.GetSafeHwnd()) && dlg.IsWindowVisible()) { - dlg.SetForegroundWindow(); - return; - } - if (dlg.DoModal() != IDOK || dlg.GetFileNames().IsEmpty()) { - return; - } - - if (!dlg.GetAppendToPlaylist()) { - CloseMediaBeforeOpen(); - } - - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - SetForegroundWindow(); - - CAtlList filenames; - - if (CanSendToYoutubeDL(dlg.GetFileNames().GetHead())) { - if (ProcessYoutubeDLURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist())) { - if (!dlg.GetAppendToPlaylist()) { - OpenCurPlaylistItem(); - } - return; - } else if (IsOnYDLWhitelist(dlg.GetFileNames().GetHead())) { - // don't bother trying to open this website URL directly - return; - } - } - - filenames.AddHeadList(&dlg.GetFileNames()); - - if (!dlg.HasMultipleFiles()) { - if (OpenBD(filenames.GetHead())) { - return; - } - } - - if (dlg.GetAppendToPlaylist()) { - m_wndPlaylistBar.Append(filenames, dlg.HasMultipleFiles()); - } else { - m_wndPlaylistBar.Open(filenames, dlg.HasMultipleFiles()); - - OpenCurPlaylistItem(); - } -} - -LRESULT CMainFrame::OnMPCVRSwitchFullscreen(WPARAM wParam, LPARAM lParam) -{ - const auto& s = AfxGetAppSettings(); - m_bIsMPCVRExclusiveMode = static_cast(wParam); - - m_OSD.Stop(); - if (m_bIsMPCVRExclusiveMode) { - TRACE(L"MPCVR exclusive full screen\n"); - bool excl_mode_controls = IsFullScreenMainFrame(); - if (excl_mode_controls && m_wndPlaylistBar.IsVisible()) { - m_wndPlaylistBar.SetHiddenDueToFullscreen(true); - } - if (s.fShowOSD || s.fShowDebugInfo) { - if (m_pVMB || m_pMFVMB) { - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, excl_mode_controls); - } - } - } else { - if (s.fShowOSD || s.fShowDebugInfo) { - m_OSD.Start(m_pOSDWnd); - OSDBarSetPos(); - } - if (m_wndPlaylistBar.IsHiddenDueToFullscreen()) { - m_wndPlaylistBar.SetHiddenDueToFullscreen(false); - } - } - - return 0; -} - -void CMainFrame::OnUpdateFileOpen(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() != MLS::LOADING); -} - -BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) -{ - if (AfxGetMyApp()->m_fClosingState) { - return FALSE; - } - - CAppSettings& s = AfxGetAppSettings(); - - if (m_pSkypeMoodMsgHandler && m_pSkypeMoodMsgHandler->HandleMessage(pWnd->GetSafeHwnd(), pCDS)) { - return TRUE; - } else if (pCDS->dwData != 0x6ABE51 || pCDS->cbData < sizeof(DWORD)) { - if (s.hMasterWnd) { - ProcessAPICommand(pCDS); - return TRUE; - } else { - return FALSE; - } - } - - if (m_bScanDlgOpened) { - return FALSE; - } - - DWORD len = *((DWORD*)pCDS->lpData); - TCHAR* pBuff = (TCHAR*)((DWORD*)pCDS->lpData + 1); - TCHAR* pBuffEnd = (TCHAR*)((BYTE*)pBuff + pCDS->cbData - sizeof(DWORD)); - - CAtlList cmdln; - - while (len-- > 0 && pBuff < pBuffEnd) { - CString str(pBuff); - pBuff += str.GetLength() + 1; - - cmdln.AddTail(str); - } - - s.ParseCommandLine(cmdln); - - if (s.nCLSwitches & CLSW_SLAVE) { - SendAPICommand(CMD_CONNECT, L"%d", PtrToInt(GetSafeHwnd())); - s.nCLSwitches &= ~CLSW_SLAVE; - } - - POSITION pos = s.slFilters.GetHeadPosition(); - while (pos) { - CString fullpath = MakeFullPath(s.slFilters.GetNext(pos)); - - CPath tmp(fullpath); - tmp.RemoveFileSpec(); - tmp.AddBackslash(); - CString path = tmp; - - WIN32_FIND_DATA fd; - ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); - HANDLE hFind = FindFirstFile(fullpath, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - continue; - } - - CFilterMapper2 fm2(false); - fm2.Register(path + fd.cFileName); - while (!fm2.m_filters.IsEmpty()) { - if (FilterOverride* f = fm2.m_filters.RemoveTail()) { - f->fTemporary = true; - - bool fFound = false; - - POSITION pos2 = s.m_filters.GetHeadPosition(); - while (pos2) { - FilterOverride* f2 = s.m_filters.GetNext(pos2); - if (f2->type == FilterOverride::EXTERNAL && !f2->path.CompareNoCase(f->path)) { - fFound = true; - break; - } - } - - if (!fFound) { - CAutoPtr p(f); - s.m_filters.AddHead(p); - } - } - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - } - - bool fSetForegroundWindow = false; - - auto applyRandomizeSwitch = [&]() { - if (s.nCLSwitches & CLSW_RANDOMIZE) { - m_wndPlaylistBar.Randomize(); - s.nCLSwitches &= ~CLSW_RANDOMIZE; - } - }; - - if ((s.nCLSwitches & CLSW_DVD) && !s.slFiles.IsEmpty()) { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - fSetForegroundWindow = true; - - CAutoPtr p(DEBUG_NEW OpenDVDData()); - if (p) { - p->path = s.slFiles.GetHead(); - p->subs.AddTailList(&s.slSubs); - } - OpenMedia(p); - s.nCLSwitches &= ~CLSW_DVD; - } else if (s.nCLSwitches & CLSW_CD) { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - fSetForegroundWindow = true; - - CAtlList sl; - - if (!s.slFiles.IsEmpty()) { - GetOpticalDiskType(s.slFiles.GetHead()[0], sl); - } else { - CString dir; - dir.ReleaseBufferSetLength(GetCurrentDirectory(2048, dir.GetBuffer(2048))); - - GetOpticalDiskType(dir[0], sl); - - for (TCHAR drive = _T('A'); sl.IsEmpty() && drive <= _T('Z'); drive++) { - GetOpticalDiskType(drive, sl); - } - } - - m_wndPlaylistBar.Open(sl, true); - applyRandomizeSwitch(); - OpenCurPlaylistItem(); - s.nCLSwitches &= ~CLSW_CD; - } else if (s.nCLSwitches & CLSW_DEVICE) { - SendMessage(WM_COMMAND, ID_FILE_OPENDEVICE); - s.nCLSwitches &= ~CLSW_DEVICE; - } else if (!s.slFiles.IsEmpty()) { - CAtlList sl; - sl.AddTailList(&s.slFiles); - - PathUtils::ParseDirs(sl); - - bool fMulti = sl.GetCount() > 1; - - if (!fMulti) { - sl.AddTailList(&s.slDubs); - } - - if (OpenBD(s.slFiles.GetHead())) { - // Nothing more to do - } else if (!fMulti && CPath(s.slFiles.GetHead() + _T("\\VIDEO_TS")).IsDirectory()) { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - fSetForegroundWindow = true; - - CAutoPtr p(DEBUG_NEW OpenDVDData()); - if (p) { - p->path = s.slFiles.GetHead(); - p->subs.AddTailList(&s.slSubs); - } - OpenMedia(p); - } else { - ULONGLONG tcnow = GetTickCount64(); - if (m_dwLastRun && ((tcnow - m_dwLastRun) < s.iRedirectOpenToAppendThreshold)) { - s.nCLSwitches |= CLSW_ADD; - } - m_dwLastRun = tcnow; - - if ((s.nCLSwitches & CLSW_ADD) && !IsPlaylistEmpty()) { - POSITION pos2 = sl.GetHeadPosition(); - while (pos2) { - CString fn = sl.GetNext(pos2); - if (!CanSendToYoutubeDL(fn) || !ProcessYoutubeDLURL(fn, true)) { - CAtlList sl2; - sl2.AddHead(fn); - m_wndPlaylistBar.Append(sl2, false, &s.slSubs); - } - } - - applyRandomizeSwitch(); - - if (s.nCLSwitches & (CLSW_OPEN | CLSW_PLAY)) { - m_wndPlaylistBar.SetLast(); - OpenCurPlaylistItem(); - } - } else { - //SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - fSetForegroundWindow = true; - - if (fMulti || sl.GetCount() == 1) { - bool first = true; - POSITION pos2 = sl.GetHeadPosition(); - while (pos2) { - CString fn = sl.GetNext(pos2); - if (!CanSendToYoutubeDL(fn) || !ProcessYoutubeDLURL(fn, !first, false)) { - CAtlList sl2; - sl2.AddHead(fn); - if (first) { - m_wndPlaylistBar.Open(sl2, false, &s.slSubs); - } else { - m_wndPlaylistBar.Append(sl2, false, &s.slSubs); - } - } - first = false; - } - } else { - // video + dub - m_wndPlaylistBar.Open(sl, false, &s.slSubs); - } - - applyRandomizeSwitch(); - if (sl.GetCount() != 1 || !IsPlaylistFile(sl.GetHead())) { //playlists already set first pos (or saved pos) - m_wndPlaylistBar.SetFirst(); - } - OpenCurPlaylistItem((s.nCLSwitches & CLSW_STARTVALID) ? s.rtStart : 0, false, s.abRepeat); - - s.nCLSwitches &= ~CLSW_STARTVALID; - s.rtStart = 0; - } - s.nCLSwitches &= ~CLSW_ADD; - } - } else if ((s.nCLSwitches & CLSW_PLAY) && !IsPlaylistEmpty()) { - OpenCurPlaylistItem(); - } else { - applyRandomizeSwitch(); - } - - if (s.nCLSwitches & CLSW_PRESET1) { - SendMessage(WM_COMMAND, ID_VIEW_PRESETS_MINIMAL); - s.nCLSwitches &= ~CLSW_PRESET1; - } else if (s.nCLSwitches & CLSW_PRESET2) { - SendMessage(WM_COMMAND, ID_VIEW_PRESETS_COMPACT); - s.nCLSwitches &= ~CLSW_PRESET2; - } else if (s.nCLSwitches & CLSW_PRESET3) { - SendMessage(WM_COMMAND, ID_VIEW_PRESETS_NORMAL); - s.nCLSwitches &= ~CLSW_PRESET3; - } - if (s.nCLSwitches & CLSW_VOLUME) { - if (IsMuted()) { - SendMessage(WM_COMMAND, ID_VOLUME_MUTE); - } - m_wndToolBar.SetVolume(s.nCmdVolume); - s.nCLSwitches &= ~CLSW_VOLUME; - } - if (s.nCLSwitches & CLSW_MUTE) { - if (!IsMuted()) { - SendMessage(WM_COMMAND, ID_VOLUME_MUTE); - } - s.nCLSwitches &= ~CLSW_MUTE; - } - - if (fSetForegroundWindow && !(s.nCLSwitches & CLSW_NOFOCUS)) { - SetForegroundWindow(); - } - - return TRUE; -} - -int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) -{ - switch (uMsg) { - case BFFM_INITIALIZED: { - //Initial directory is set here - const CAppSettings& s = AfxGetAppSettings(); - if (!s.strDVDPath.IsEmpty()) { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)s.strDVDPath); - } - break; - } - default: - break; - } - return 0; -} - -void CMainFrame::OpenDVDOrBD(CStringW path) { - if (!path.IsEmpty()) { - AfxGetAppSettings().strDVDPath = path; - if (!OpenBD(path)) { - CAutoPtr p(DEBUG_NEW OpenDVDData()); - p->path = path; - p->path.Replace(_T('/'), _T('\\')); - p->path = ForceTrailingSlash(p->path); - - OpenMedia(p); - } - } -} - -void CMainFrame::OnFileOpendvd() -{ - if ((GetLoadState() == MLS::LOADING) || IsD3DFullScreenMode()) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - CString strTitle(StrRes(IDS_MAINFRM_46)); - CString path; - - if (s.fUseDVDPath && !s.strDVDPath.IsEmpty()) { - path = s.strDVDPath; - } else { - //strDVDPath is actually used as a default to open without the dialog, - //but since it is always updated to the last path chosen, - //we can use it as the default for the dialog, too - CFolderPickerDialog fd(ForceTrailingSlash(s.strDVDPath), FOS_PATHMUSTEXIST, GetModalParent()); - fd.m_ofn.lpstrTitle = strTitle; - - if (fd.DoModal() == IDOK) { - path = fd.GetPathName(); //getfolderpath() does not work correctly for CFolderPickerDialog - } else { - return; - } - } - OpenDVDOrBD(path); -} - -void CMainFrame::OnFileOpendevice() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (GetLoadState() == MLS::LOADING) { - return; - } - - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - SetForegroundWindow(); - - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - - m_wndPlaylistBar.Empty(); - - if (s.iDefaultCaptureDevice == 0 && s.strAnalogVideo == L"dummy" && s.strAnalogAudio == L"dummy") { - // device not configured yet, open settings - ShowOptions(IDD_PPAGECAPTURE); - return; - } - - CAutoPtr p(DEBUG_NEW OpenDeviceData()); - if (p) { - p->DisplayName[0] = s.strAnalogVideo; - p->DisplayName[1] = s.strAnalogAudio; - } - OpenMedia(p); -} - -void CMainFrame::OnFileOpenOpticalDisk(UINT nID) -{ - nID -= ID_FILE_OPEN_OPTICAL_DISK_START; - - nID++; - for (TCHAR drive = _T('A'); drive <= _T('Z'); drive++) { - CAtlList sl; - - OpticalDiskType_t discType = GetOpticalDiskType(drive, sl); - switch (discType) { - case OpticalDisk_Audio: - case OpticalDisk_VideoCD: - case OpticalDisk_DVDVideo: - case OpticalDisk_BD: - nID--; - break; - default: - break; - } - - if (nID == 0) { - if (OpticalDisk_BD == discType || OpticalDisk_DVDVideo == discType) { - OpenDVDOrBD(CStringW(drive) + L":\\"); - } else { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - SetForegroundWindow(); - - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - - m_wndPlaylistBar.Open(sl, true); - OpenCurPlaylistItem(); - } - break; - } - } -} - -void CMainFrame::OnFileRecycle() -{ - // check if a file is playing - if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_FILE) { - return; - } - - OAFilterState fs = GetMediaState(); - if (fs == State_Running) { - MediaControlPause(true); - } - - m_wndPlaylistBar.DeleteFileInPlaylist(m_wndPlaylistBar.m_pl.GetPos()); -} - -void CMainFrame::OnFileReopen() -{ - if (!m_LastOpenBDPath.IsEmpty() && OpenBD(m_LastOpenBDPath)) { - return; - } - - // save playback position - if (GetLoadState() == MLS::LOADED) { - if (m_bRememberFilePos && !m_fEndOfStream && m_dwReloadPos == 0 && m_pMS) { - auto& s = AfxGetAppSettings(); - REFERENCE_TIME rtNow = 0; - m_pMS->GetCurrentPosition(&rtNow); - m_dwReloadPos = rtNow; - s.MRU.UpdateCurrentFilePosition(rtNow, true); - } - reloadABRepeat = abRepeat; - } - - OpenCurPlaylistItem(0, true); -} - -DROPEFFECT CMainFrame::OnDropAccept(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) -{ - ClientToScreen(&point); - if (CMouse::CursorOnRootWindow(point, *this)) { - UpdateControlState(UPDATE_CONTROLS_VISIBILITY); - return (dwKeyState & MK_CONTROL) ? (DROPEFFECT_COPY | DROPEFFECT_APPEND) - : (DROPEFFECT_MOVE | DROPEFFECT_LINK | DROPEFFECT_COPY); - } - - return DROPEFFECT_NONE; -} - -bool CMainFrame::IsImageFile(CStringW fn) { - CPath path(fn); - CStringW ext(path.GetExtension()); - return IsImageFileExt(ext); -} - -bool CMainFrame::IsImageFileExt(CStringW ext) { - ext.MakeLower(); - return ( - ext == _T(".jpg") || ext == _T(".jpeg") || ext == _T(".png") || ext == _T(".gif") || ext == _T(".bmp") - || ext == _T(".tiff") || ext == _T(".jpe") || ext == _T(".tga") || ext == _T(".heic") || ext == _T(".avif") - ); -} - -bool CMainFrame::IsPlaylistFile(CStringW fn) { - CPath path(fn); - CStringW ext(path.GetExtension()); - return IsPlaylistFileExt(ext); -} - -bool CMainFrame::IsPlaylistFileExt(CStringW ext) { - return (ext == _T(".m3u") || ext == _T(".m3u8") || ext == _T(".mpcpl") || ext == _T(".pls") || ext == _T(".cue") || ext == _T(".asx")); -} - -bool CMainFrame::IsAudioOrVideoFileExt(CStringW ext) { - return IsPlayableFormatExt(ext); -} - -bool CMainFrame::IsAudioFileExt(CStringW ext) { - const CMediaFormats& mf = AfxGetAppSettings().m_Formats; - ext.MakeLower(); - return mf.FindExt(ext, true); -} - -bool CMainFrame::IsPlayableFormatExt(CStringW ext) { - const CMediaFormats& mf = AfxGetAppSettings().m_Formats; - ext.MakeLower(); - return mf.FindExt(ext); -} - -bool CMainFrame::CanSkipToExt(CStringW ext, CStringW curExt) -{ - if (IsImageFileExt(curExt)) { - return IsImageFileExt(ext); - } else { - return IsPlayableFormatExt(ext); - } -} - -BOOL IsSubtitleExtension(CString ext) -{ - return (ext == _T(".srt") || ext == _T(".ssa") || ext == _T(".ass") || ext == _T(".idx") || ext == _T(".sub") || ext == _T(".webvtt") || ext == _T(".vtt") || ext == _T(".sup") || ext == _T(".smi") || ext == _T(".psb") || ext == _T(".usf") || ext == _T(".xss") || ext == _T(".rt")|| ext == _T(".txt")); -} - -BOOL IsSubtitleFilename(CString filename) -{ - CString ext = CPath(filename).GetExtension().MakeLower(); - return IsSubtitleExtension(ext); -} - -bool CMainFrame::IsAudioFilename(CString filename) -{ - CString ext = CPath(filename).GetExtension(); - return IsAudioFileExt(ext); -} - -void CMainFrame::OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) -{ - SetForegroundWindow(); - - if (slFiles.IsEmpty()) { - return; - } - - if (slFiles.GetCount() == 1 && OpenBD(slFiles.GetHead())) { - return; - } - - PathUtils::ParseDirs(slFiles); - - bool bAppend = !!(dropEffect & DROPEFFECT_APPEND); - - // Check for subtitle files - SubtitleInput subInputSelected; - CString subfile; - BOOL onlysubs = true; - BOOL subloaded = false; - BOOL canLoadSub = !bAppend && !m_fAudioOnly && GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode(); - BOOL canLoadSubISR = canLoadSub && m_pCAP && (!m_pDVS || AfxGetAppSettings().IsISRAutoLoadEnabled()); - POSITION pos = slFiles.GetHeadPosition(); - while (pos) { - SubtitleInput subInput; - POSITION curpos = pos; - subfile = slFiles.GetNext(pos); - if (IsSubtitleFilename(subfile)) { - // remove subtitle file from list - slFiles.RemoveAt(curpos); - // try to load it - if (onlysubs && canLoadSub) { - if (canLoadSubISR && LoadSubtitle(subfile, &subInput, False)) { - if (!subInputSelected.pSubStream) { - // first one - subInputSelected = subInput; - } - subloaded = true; - } else if (m_pDVS && slFiles.IsEmpty()) { - if (SUCCEEDED(m_pDVS->put_FileName((LPWSTR)(LPCWSTR)subfile))) { - m_pDVS->put_SelectedLanguage(0); - m_pDVS->put_HideSubtitles(true); - m_pDVS->put_HideSubtitles(false); - subloaded = true; - } - } - } - } - else { - onlysubs = false; - } - } - - if (onlysubs) { - if (subInputSelected.pSubStream) { - AfxGetAppSettings().fEnableSubtitles = true; - SetSubtitle(subInputSelected); - } - if (subloaded) { - CPath fn(subfile); - fn.StripPath(); - CString statusmsg(static_cast(fn)); - SendStatusMessage(statusmsg + ResStr(IDS_SUB_LOADED_SUCCESS), 3000); - } else { - SendStatusMessage(_T("Failed to load subtitle file"), 3000); - } - return; - } - - // load http url with youtube-dl, if available - if (CanSendToYoutubeDL(slFiles.GetHead())) { - CloseMediaBeforeOpen(); - if (ProcessYoutubeDLURL(slFiles.GetHead(), bAppend)) { - if (!bAppend) { - OpenCurPlaylistItem(); - } - return; - } else if (IsOnYDLWhitelist(slFiles.GetHead())) { - // don't bother trying to open this website URL directly - return; - } - } - - // add remaining items - if (bAppend) { - m_wndPlaylistBar.Append(slFiles, true); - } else { - m_wndPlaylistBar.Open(slFiles, true); - OpenCurPlaylistItem(); - } -} - -void CMainFrame::OnFileSaveAs() -{ - CString in, out, ext; - CAppSettings& s = AfxGetAppSettings(); - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - in = pli.m_fns.GetHead(); - } else { - return; - } - - if (pli.m_bYoutubeDL || PathUtils::IsURL(in)) { - // URL - if (pli.m_bYoutubeDL) { - out = _T("%(title)s.%(ext)s"); - } else { - out = _T("choose_a_filename"); - } - } else { - out = PathUtils::StripPathOrUrl(in); - ext = CPath(out).GetExtension().MakeLower(); - if (ext == _T(".cda")) { - out = out.Left(out.GetLength() - 4) + _T(".wav"); - } else if (ext == _T(".ifo")) { - out = out.Left(out.GetLength() - 4) + _T(".vob"); - } - } - - if (!pli.m_bYoutubeDL || pli.m_ydlSourceURL.IsEmpty() || (AfxGetAppSettings().sYDLCommandLine.Find(_T("-o ")) < 0)) { - CFileDialog fd(FALSE, 0, out, - OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR, - ResStr(IDS_ALL_FILES_FILTER), GetModalParent(), 0); - if (DoFileDialogWithLastFolder(fd, s.lastFileSaveCopyPath) != IDOK || !in.CompareNoCase(fd.GetPathName())) { - return; - } else { - out = fd.GetPathName(); - } - } - - if (pli.m_bYoutubeDL && !pli.m_ydlSourceURL.IsEmpty()) { - DownloadWithYoutubeDL(pli.m_ydlSourceURL, out); - return; - } - - CPath p(out); - if (!ext.IsEmpty()) { - p.AddExtension(ext); - } - - OAFilterState fs = State_Stopped; - if (m_pMC) { - m_pMC->GetState(0, &fs); - if (fs == State_Running) { - MediaControlPause(true); - } - } - - CSaveDlg dlg(in, p); - dlg.DoModal(); - - if (m_pMC && fs == State_Running) { - MediaControlRun(); - } -} - -void CMainFrame::OnUpdateFileSaveAs(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_FILE); -} - -bool CMainFrame::GetDIB(BYTE** ppData, long& size, bool fSilent) -{ - if (!ppData) { - return false; - } - if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { - return false; - } - OAFilterState fs = GetMediaState(); - if (fs != State_Paused && fs != State_Running) { - return false; - } - - *ppData = nullptr; - size = 0; - - if (fs == State_Running && !m_pCAP) { - MediaControlPause(true); // wait for completion - } - - HRESULT hr = S_OK; - CString errmsg; - - do { - if (m_pCAP) { - hr = m_pCAP->GetDIB(nullptr, (DWORD*)&size); - if (FAILED(hr)) { - errmsg.Format(IDS_GETDIB_FAILED, hr); - break; - } - - *ppData = DEBUG_NEW BYTE[size]; - if (!(*ppData)) { - return false; - } - - hr = m_pCAP->GetDIB(*ppData, (DWORD*)&size); - if (FAILED(hr)) { - errmsg.Format(IDS_GETDIB_FAILED, hr); - break; - } - } else if (m_pMFVDC) { - // Capture with EVR - BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER)}; - BYTE* pDib; - DWORD dwSize; - REFERENCE_TIME rtImage = 0; - hr = m_pMFVDC->GetCurrentImage(&bih, &pDib, &dwSize, &rtImage); - if (FAILED(hr) || dwSize == 0) { - errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); - break; - } - - size = (long)dwSize + sizeof(BITMAPINFOHEADER); - *ppData = DEBUG_NEW BYTE[size]; - if (!(*ppData)) { - return false; - } - memcpy_s(*ppData, size, &bih, sizeof(BITMAPINFOHEADER)); - memcpy_s(*ppData + sizeof(BITMAPINFOHEADER), size - sizeof(BITMAPINFOHEADER), pDib, dwSize); - CoTaskMemFree(pDib); - } else { - hr = m_pBV->GetCurrentImage(&size, nullptr); - if (FAILED(hr) || size == 0) { - errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); - break; - } - - *ppData = DEBUG_NEW BYTE[size]; - if (!(*ppData)) { - return false; - } - - hr = m_pBV->GetCurrentImage(&size, (long*)*ppData); - if (FAILED(hr)) { - errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); - break; - } - } - } while (0); - - if (!fSilent) { - if (!errmsg.IsEmpty()) { - AfxMessageBox(errmsg, MB_OK); - } - } - - if (fs == State_Running && GetMediaState() != State_Running) { - MediaControlRun(); - } - - if (FAILED(hr)) { - SAFE_DELETE_ARRAY(*ppData); - return false; - } - - return true; -} - -void CMainFrame::SaveDIB(LPCTSTR fn, BYTE* pData, long size) -{ - CPath path(fn); - - PBITMAPINFO bi = reinterpret_cast(pData); - PBITMAPINFOHEADER bih = &bi->bmiHeader; - int bpp = bih->biBitCount; - - if (bpp != 16 && bpp != 24 && bpp != 32) { - AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); - return; - } - int w = bih->biWidth; - int h = abs(bih->biHeight); - int srcpitch = w * (bpp >> 3); - int dstpitch = (w * 3 + 3) / 4 * 4; // round w * 3 to next multiple of 4 - - BYTE* p = DEBUG_NEW BYTE[dstpitch * h]; - - const BYTE* src = pData + sizeof(*bih); - - BitBltFromRGBToRGB(w, h, p, dstpitch, 24, (BYTE*)src + srcpitch * (h - 1), -srcpitch, bpp); - - { - Gdiplus::GdiplusStartupInput gdiplusStartupInput; - ULONG_PTR gdiplusToken; - Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); - - Gdiplus::Bitmap* bm = new Gdiplus::Bitmap(w, h, dstpitch, PixelFormat24bppRGB, p); - - UINT num; // number of image encoders - UINT arraySize; // size, in bytes, of the image encoder array - - // How many encoders are there? - // How big (in bytes) is the array of all ImageCodecInfo objects? - Gdiplus::GetImageEncodersSize(&num, &arraySize); - - // Create a buffer large enough to hold the array of ImageCodecInfo - // objects that will be returned by GetImageEncoders. - Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)DEBUG_NEW BYTE[arraySize]; - - // GetImageEncoders creates an array of ImageCodecInfo objects - // and copies that array into a previously allocated buffer. - // The third argument, imageCodecInfos, is a pointer to that buffer. - Gdiplus::GetImageEncoders(num, arraySize, pImageCodecInfo); - - Gdiplus::EncoderParameters* pEncoderParameters = nullptr; - - // Find the mime type based on the extension - CString ext(path.GetExtension()); - CStringW mime; - if (ext == _T(".jpg")) { - mime = L"image/jpeg"; - - // Set the encoder parameter for jpeg quality - pEncoderParameters = DEBUG_NEW Gdiplus::EncoderParameters; - ULONG quality = AfxGetAppSettings().nJpegQuality; - - pEncoderParameters->Count = 1; - pEncoderParameters->Parameter[0].Guid = Gdiplus::EncoderQuality; - pEncoderParameters->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong; - pEncoderParameters->Parameter[0].NumberOfValues = 1; - pEncoderParameters->Parameter[0].Value = &quality; - } else if (ext == _T(".bmp")) { - mime = L"image/bmp"; - } else { - mime = L"image/png"; - } - - // Get the encoder clsid - CLSID encoderClsid = CLSID_NULL; - for (UINT i = 0; i < num && encoderClsid == CLSID_NULL; i++) { - if (wcscmp(pImageCodecInfo[i].MimeType, mime) == 0) { - encoderClsid = pImageCodecInfo[i].Clsid; - } - } - - Gdiplus::Status s = bm->Save(fn, &encoderClsid, pEncoderParameters); - - // All GDI+ objects must be destroyed before GdiplusShutdown is called - delete bm; - delete [] pImageCodecInfo; - delete pEncoderParameters; - Gdiplus::GdiplusShutdown(gdiplusToken); - delete [] p; - - if (s != Gdiplus::Ok) { - AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); - return; - } - } - - path.m_strPath.Replace(_T("\\\\"), _T("\\")); - - SendStatusMessage(m_wndStatusBar.PreparePathStatusMessage(path), 3000); -} - -HRESULT GetBasicVideoFrame(IBasicVideo* pBasicVideo, std::vector& dib) { - // IBasicVideo::GetCurrentImage() gives the original frame - - long size; - - HRESULT hr = pBasicVideo->GetCurrentImage(&size, nullptr); - if (FAILED(hr)) { - return hr; - } - if (size <= 0) { - return E_ABORT; - } - - dib.resize(size); - - hr = pBasicVideo->GetCurrentImage(&size, (long*)dib.data()); - if (FAILED(hr)) { - dib.clear(); - } - - return hr; -} - -HRESULT GetVideoDisplayControlFrame(IMFVideoDisplayControl* pVideoDisplayControl, std::vector& dib) { - // IMFVideoDisplayControl::GetCurrentImage() gives the displayed frame - - BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER) }; - BYTE* pDib; - DWORD size; - REFERENCE_TIME rtImage = 0; - - HRESULT hr = pVideoDisplayControl->GetCurrentImage(&bih, &pDib, &size, &rtImage); - if (S_OK != hr) { - return hr; - } - if (size == 0) { - return E_ABORT; - } - - dib.resize(sizeof(BITMAPINFOHEADER) + size); - - memcpy(dib.data(), &bih, sizeof(BITMAPINFOHEADER)); - memcpy(dib.data() + sizeof(BITMAPINFOHEADER), pDib, size); - CoTaskMemFree(pDib); - - return hr; -} - -HRESULT GetMadVRFrameGrabberFrame(IMadVRFrameGrabber* pMadVRFrameGrabber, std::vector& dib, bool displayed) { - LPVOID dibImage = nullptr; - HRESULT hr; - - if (displayed) { - hr = pMadVRFrameGrabber->GrabFrame(ZOOM_PLAYBACK_SIZE, 0, 0, 0, 0, 0, &dibImage, 0); - } else { - hr = pMadVRFrameGrabber->GrabFrame(ZOOM_ENCODED_SIZE, 0, 0, 0, 0, 0, &dibImage, 0); - } - - if (S_OK != hr) { - return hr; - } - if (!dibImage) { - return E_ABORT; - } - - const BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)dibImage; - - dib.resize(sizeof(BITMAPINFOHEADER) + bih->biSizeImage); - memcpy(dib.data(), dibImage, sizeof(BITMAPINFOHEADER) + bih->biSizeImage); - LocalFree(dibImage); - - return hr; -} - -HRESULT CMainFrame::GetDisplayedImage(std::vector& dib, CString& errmsg) { - errmsg.Empty(); - HRESULT hr; - - if (m_pCAP) { - LPVOID dibImage = nullptr; - hr = m_pCAP->GetDisplayedImage(&dibImage); - - if (S_OK == hr && dibImage) { - const BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)dibImage; - dib.resize(sizeof(BITMAPINFOHEADER) + bih->biSizeImage); - memcpy(dib.data(), dibImage, sizeof(BITMAPINFOHEADER) + bih->biSizeImage); - LocalFree(dibImage); - } - } - else if (m_pMFVDC) { - hr = GetVideoDisplayControlFrame(m_pMFVDC, dib); - } else if (m_pMVRFG) { - hr = GetMadVRFrameGrabberFrame(m_pMVRFG, dib, true); - } else { - hr = E_NOINTERFACE; - } - - if (FAILED(hr)) { - errmsg.Format(L"CMainFrame::GetCurrentImage() failed, 0x%08x", hr); - } - - return hr; -} - -HRESULT CMainFrame::GetCurrentFrame(std::vector& dib, CString& errmsg) { - HRESULT hr = S_OK; - errmsg.Empty(); - - OAFilterState fs = GetMediaState(); - if (m_eMediaLoadState != MLS::LOADED || m_fAudioOnly || (fs != State_Paused && fs != State_Running)) { - return E_ABORT; - } - - if (fs == State_Running && !m_pCAP) { - MediaControlPause(true); //wait for completion - } - - if (m_pCAP) { - DWORD size; - hr = m_pCAP->GetDIB(nullptr, &size); - - if (S_OK == hr) { - dib.resize(size); - hr = m_pCAP->GetDIB(dib.data(), &size); - } - - if (FAILED(hr)) { - errmsg.Format(L"ISubPicAllocatorPresenter3::GetDIB() failed, 0x%08x", hr); - } - } else if (m_pBV) { - hr = GetBasicVideoFrame(m_pBV, dib); - - if (hr == E_NOINTERFACE && m_pMFVDC) { - // hmm, EVR is not able to give the original frame, giving the displayed image - hr = GetDisplayedImage(dib, errmsg); - } else if (FAILED(hr)) { - errmsg.Format(L"IBasicVideo::GetCurrentImage() failed, 0x%08x", hr); - } - } else { - hr = E_POINTER; - errmsg.Format(L"Interface not found!"); - } - - if (fs == State_Running && GetMediaState() != State_Running) { - MediaControlRun(); - } - - return hr; -} - -HRESULT CMainFrame::GetOriginalFrame(std::vector& dib, CString& errmsg) { - HRESULT hr = S_OK; - errmsg.Empty(); - - if (m_pMVRFG) { - hr = GetMadVRFrameGrabberFrame(m_pMVRFG, dib, false); - if (FAILED(hr)) { - errmsg.Format(L"IMadVRFrameGrabber::GrabFrame() failed, 0x%08x", hr); - } - } else { - hr = GetCurrentFrame(dib, errmsg); - } - - return hr; -} - -HRESULT CMainFrame::RenderCurrentSubtitles(BYTE* pData) { - ASSERT(m_pCAP && AfxGetAppSettings().bSnapShotSubtitles && !m_pMVRFG && AfxGetAppSettings().fEnableSubtitles && AfxGetAppSettings().IsISRAutoLoadEnabled()); - CheckPointer(pData, E_FAIL); - HRESULT hr = S_FALSE; - - if (CComQIPtr pSubPicProvider = m_pCurrentSubInput.pSubStream) { - const PBITMAPINFOHEADER bih = (PBITMAPINFOHEADER)pData; - const int width = bih->biWidth; - const int height = bih->biHeight; - - REFERENCE_TIME rtNow = 0; - m_pMS->GetCurrentPosition(&rtNow); - - int delay = m_pCAP->GetSubtitleDelay(); - if (delay != 0) { - if (delay > 0 && delay * 10000LL > rtNow) { - return S_FALSE; - } else { - rtNow -= delay * 10000LL; - } - } - - int subWidth = width; - int subHeight = height; - bool needsResize = false; - if (CPGSSub* pgsSub = dynamic_cast(pSubPicProvider.p)) { - CSize sz; - if (SUCCEEDED(pgsSub->GetPresentationSegmentTextureSize(rtNow, sz))) { - subWidth = sz.cx; - subHeight = sz.cy; - needsResize = true; - } - } - - SubPicDesc spdRender; - - spdRender.type = MSP_RGB32; - spdRender.w = subWidth; - spdRender.h = abs(subHeight); - spdRender.bpp = 32; - spdRender.pitch = subWidth * 4; - spdRender.vidrect = { 0, 0, width, height }; - spdRender.bits = DEBUG_NEW BYTE[spdRender.pitch * spdRender.h]; - - CComPtr pSubPicAllocator = DEBUG_NEW CMemSubPicAllocator(spdRender.type, CSize(spdRender.w, spdRender.h)); - - CMemSubPic memSubPic(spdRender, pSubPicAllocator); - memSubPic.SetInverseAlpha(false); - memSubPic.ClearDirtyRect(); - - RECT bbox = {}; - hr = pSubPicProvider->Render(spdRender, rtNow, m_pCAP->GetFPS(), bbox); - if (needsResize) { - memSubPic.UnlockARGB(); - } - - if (S_OK == hr) { - SubPicDesc spdTarget; - spdTarget.type = MSP_RGB32; - spdTarget.w = width; - spdTarget.h = height; - spdTarget.bpp = 32; - spdTarget.pitch = -width * 4; - spdTarget.vidrect = { 0, 0, width, height }; - spdTarget.bits = (BYTE*)(bih + 1) + (width * 4) * (height - 1); - - hr = memSubPic.AlphaBlt(&spdRender.vidrect, &spdTarget.vidrect, &spdTarget); - } - } - - return hr; -} - -void CMainFrame::SaveImage(LPCWSTR fn, bool displayed, bool includeSubtitles) { - std::vector dib; - CString errmsg; - HRESULT hr; - if (displayed) { - hr = GetDisplayedImage(dib, errmsg); - } else { - hr = GetCurrentFrame(dib, errmsg); - if (includeSubtitles && m_pCAP && hr == S_OK) { - RenderCurrentSubtitles(dib.data()); - } - } - - if (hr == S_OK) { - SaveDIB(fn, dib.data(), (long)dib.size()); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_IMAGE_SAVED), 3000); - } else { - m_OSD.DisplayMessage(OSD_TOPLEFT, errmsg, 3000); - } -} - -void CMainFrame::SaveThumbnails(LPCTSTR fn) -{ - if (!m_pMC || !m_pMS || GetPlaybackMode() != PM_FILE /*&& GetPlaybackMode() != PM_DVD*/) { - return; - } - - REFERENCE_TIME rtPos = GetPos(); - REFERENCE_TIME rtDur = GetDur(); - - if (rtDur <= 0) { - AfxMessageBox(IDS_THUMBNAILS_NO_DURATION, MB_ICONWARNING | MB_OK, 0); - return; - } - - OAFilterState filterState = UpdateCachedMediaState(); - bool bWasStopped = (filterState == State_Stopped); - if (filterState != State_Paused) { - OnPlayPause(); - } - - CSize szVideoARCorrected, szVideo, szAR; - - if (m_pCAP) { - szVideo = m_pCAP->GetVideoSize(false); - szAR = m_pCAP->GetVideoSize(true); - } else if (m_pMFVDC) { - VERIFY(SUCCEEDED(m_pMFVDC->GetNativeVideoSize(&szVideo, &szAR))); - } else { - VERIFY(SUCCEEDED(m_pBV->GetVideoSize(&szVideo.cx, &szVideo.cy))); - - CComQIPtr pBV2 = m_pBV; - long lARx = 0, lARy = 0; - if (pBV2 && SUCCEEDED(pBV2->GetPreferredAspectRatio(&lARx, &lARy)) && lARx > 0 && lARy > 0) { - szAR.SetSize(lARx, lARy); - } - } - - if (szVideo.cx <= 0 || szVideo.cy <= 0) { - AfxMessageBox(IDS_THUMBNAILS_NO_FRAME_SIZE, MB_ICONWARNING | MB_OK, 0); - return; - } - - // with the overlay mixer IBasicVideo2 won't tell the new AR when changed dynamically - DVD_VideoAttributes VATR; - if (GetPlaybackMode() == PM_DVD && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { - szAR.SetSize(VATR.ulAspectX, VATR.ulAspectY); - } - - szVideoARCorrected = (szAR.cx <= 0 || szAR.cy <= 0) ? szVideo : CSize(MulDiv(szVideo.cy, szAR.cx, szAR.cy), szVideo.cy); - - const CAppSettings& s = AfxGetAppSettings(); - - int cols = std::clamp(s.iThumbCols, 1, 16); - int rows = std::clamp(s.iThumbRows, 1, 40); - - const int margin = 5; - int width = std::clamp(s.iThumbWidth, 256, 3840); - float fontscale = width / 1280.0; - int fontsize = fontscale * 16; - const int infoheight = 4 * fontsize + 6 + 2 * margin; - int height = width * szVideoARCorrected.cy / szVideoARCorrected.cx * rows / cols + infoheight; - - int dibsize = sizeof(BITMAPINFOHEADER) + width * height * 4; - - CAutoVectorPtr dib; - if (!dib.Allocate(dibsize)) { - AfxMessageBox(IDS_OUT_OF_MEMORY, MB_ICONWARNING | MB_OK, 0); - return; - } - - BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)(BYTE*)dib; - ZeroMemory(bih, sizeof(BITMAPINFOHEADER)); - bih->biSize = sizeof(BITMAPINFOHEADER); - bih->biWidth = width; - bih->biHeight = height; - bih->biPlanes = 1; - bih->biBitCount = 32; - bih->biCompression = BI_RGB; - bih->biSizeImage = width * height * 4; - memsetd(bih + 1, 0xffffff, bih->biSizeImage); - - SubPicDesc spd; - spd.w = width; - spd.h = height; - spd.bpp = 32; - spd.pitch = -width * 4; - spd.vidrect = CRect(0, 0, width, height); - spd.bits = (BYTE*)(bih + 1) + (width * 4) * (height - 1); - - bool darktheme = s.bMPCTheme && s.eModernThemeMode == CMPCTheme::ModernThemeMode::DARK; - - int gradientBase = 0xe0; - if (darktheme) { - gradientBase = 0x00; - } - // Paint the background - { - BYTE* p = (BYTE*)spd.bits; - for (int y = 0; y < spd.h; y++, p += spd.pitch) { - for (int x = 0; x < spd.w; x++) { - ((DWORD*)p)[x] = 0x010101 * (gradientBase + 0x08 * y / spd.h + 0x18 * (spd.w - x) / spd.w); - } - } - } - - CCritSec csSubLock; - RECT bbox; - CSize szThumbnail((width - margin * 2) / cols - margin * 2, (height - margin * 2 - infoheight) / rows - margin * 2); - // Ensure the thumbnails aren't ridiculously small so that the time indication can at least fit - if (szThumbnail.cx < 60 || szThumbnail.cy < 20) { - AfxMessageBox(IDS_THUMBNAIL_TOO_SMALL, MB_ICONWARNING | MB_OK, 0); - return; - } - - m_nVolumeBeforeFrameStepping = m_wndToolBar.Volume; - if (m_pBA) { - m_pBA->put_Volume(-10000); - } - - // Draw the thumbnails - std::unique_ptr thumb(new(std::nothrow) BYTE[szThumbnail.cx * szThumbnail.cy * 4]); - if (!thumb) { - return; - } - - int pics = cols * rows; - REFERENCE_TIME rtInterval = rtDur / (pics + 1LL); - for (int i = 1; i <= pics; i++) { - REFERENCE_TIME rt = rtInterval * i; - // use a keyframe if close to target time - if (rtInterval >= 100000000LL) { - REFERENCE_TIME rtMaxDiff = std::min(100000000LL, rtInterval / 10); // no more than 10 sec - rt = GetClosestKeyFrame(rt, rtMaxDiff, rtMaxDiff); - } - - DoSeekTo(rt, false); - UpdateWindow(); - - HRESULT hr = m_pFS ? m_pFS->Step(1, nullptr) : E_FAIL; - if (FAILED(hr)) { - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - AfxMessageBox(IDS_FRAME_STEP_ERROR_RENDERER, MB_ICONEXCLAMATION | MB_OK, 0); - return; - } - - bool abortloop = false; - HANDLE hGraphEvent = nullptr; - m_pME->GetEventHandle((OAEVENT*)&hGraphEvent); - while (hGraphEvent) { - DWORD res = WaitForSingleObject(hGraphEvent, 5000); - if (res == WAIT_OBJECT_0) { - LONG evCode = 0; - LONG_PTR evParam1, evParam2; - while (m_pME && SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) { - m_pME->FreeEventParams(evCode, evParam1, evParam2); - if (EC_STEP_COMPLETE == evCode) { - hGraphEvent = nullptr; - } - } - } else { - hGraphEvent = nullptr; - if (res == WAIT_TIMEOUT) { - // Likely a seek failure has occurred. For example due to an incomplete file. - REFERENCE_TIME rtCur = 0; - m_pMS->GetCurrentPosition(&rtCur); - if (rtCur >= rtDur) { - abortloop = true; - } - } - } - } - - if (abortloop) { - break; - } - - int col = (i - 1) % cols; - int row = (i - 1) / cols; - - CPoint p(2 * margin + col * (szThumbnail.cx + 2 * margin), infoheight + 2 * margin + row * (szThumbnail.cy + 2 * margin)); - CRect r(p, szThumbnail); - - CRenderedTextSubtitle rts(&csSubLock); - rts.m_SubRendererSettings.renderSSAUsingLibass = false; - rts.m_SubRendererSettings.overrideDefaultStyle = false; - rts.m_SubRendererSettings.overrideAllStyles = false; - rts.CreateDefaultStyle(0); - rts.m_storageRes = rts.m_playRes = CSize(width, height); - STSStyle* style = DEBUG_NEW STSStyle(); - style->fontName = L"Calibri"; - style->marginRect.SetRectEmpty(); - rts.AddStyle(_T("thumbs"), style); - - DVD_HMSF_TIMECODE hmsf = RT2HMS_r(rt); - CStringW str; - if (!darktheme) { - str.Format(L"{\\an7\\1c&Hffffff&\\4a&Hb0&\\bord1\\shad4\\be1}{\\p1}m %d %d l %d %d %d %d %d %d{\\p}", - r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom); - rts.Add(str, true, MS2RT(0), MS2RT(1), _T("thumbs")); // Thumbnail background - } - str.Format(L"{\\an3\\1c&Hffffff&\\3c&H000000&\\alpha&H80&\\fs%d\\b1\\bord2\\shad0\\pos(%d,%d)}%02u:%02u:%02u", - fontsize, r.right - 5, r.bottom - 3, hmsf.bHours, hmsf.bMinutes, hmsf.bSeconds); - rts.Add(str, true, MS2RT(1), MS2RT(2), _T("thumbs")); // Thumbnail time - - rts.Render(spd, 0, 25, bbox); // Draw the thumbnail background/time - - BYTE* pData = nullptr; - long size = 0; - if (!GetDIB(&pData, size)) { - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - return; - } - - BITMAPINFO* bi = (BITMAPINFO*)pData; - - if (bi->bmiHeader.biBitCount != 32) { - CString strTemp; - strTemp.Format(IDS_THUMBNAILS_INVALID_FORMAT, bi->bmiHeader.biBitCount); - AfxMessageBox(strTemp); - delete [] pData; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - return; - } - - int sw = bi->bmiHeader.biWidth; - int sh = abs(bi->bmiHeader.biHeight); - int sp = sw * 4; - const BYTE* src = pData + sizeof(bi->bmiHeader); - - stbir_resize(src, sw, sh, sp, thumb.get(), szThumbnail.cx, szThumbnail.cy, szThumbnail.cx * 4, STBIR_RGBA_PM, STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT); - - BYTE* dst = spd.bits + spd.pitch * r.top + r.left * 4; - - const BYTE* tsrc = thumb.get(); - int tsrcPitch = szThumbnail.cx * 4; - if (bi->bmiHeader.biHeight >= 0) { - tsrc += tsrcPitch * (szThumbnail.cy - 1); - tsrcPitch = -tsrcPitch; - } - for (int y = 0; y < szThumbnail.cy; y++, dst += spd.pitch, tsrc += tsrcPitch) { - memcpy(dst, tsrc, abs(tsrcPitch)); - } - - rts.Render(spd, 10000, 25, bbox); // Draw the thumbnail time - - delete [] pData; - } - - // Draw the file information - { - CRenderedTextSubtitle rts(&csSubLock); - rts.m_SubRendererSettings.renderSSAUsingLibass = false; - rts.m_SubRendererSettings.overrideDefaultStyle = false; - rts.m_SubRendererSettings.overrideAllStyles = false; - rts.CreateDefaultStyle(0); - rts.m_storageRes = rts.m_playRes = CSize(width, height); - STSStyle* style = DEBUG_NEW STSStyle(); - // Use System UI font. - CFont tempFont; - CMPCThemeUtil::getFontByType(tempFont, nullptr, CMPCThemeUtil::MessageFont); - LOGFONT lf; - if (tempFont.GetLogFont(&lf)) { - CString fontName(lf.lfFaceName); - style->fontName = fontName; - } - style->marginRect.SetRect(margin * 2, margin * 2, margin * 2, height - infoheight - margin); - rts.AddStyle(_T("thumbs"), style); - - CStringW str; - str.Format(L"{\\an9\\fs%d\\b1\\bord0\\shad0\\1c&Hffffff&}%s", infoheight - 2 * margin, L"MPC-HC"); - if (darktheme) { - str.Replace(L"\\1c&Hffffff", L"\\1c&Hc8c8c8"); - } - rts.Add(str, true, 0, 1, _T("thumbs"), _T(""), _T(""), CRect(0, 0, 0, 0), -1); - - DVD_HMSF_TIMECODE hmsf = RT2HMS_r(rtDur); - - CString title; - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_bYoutubeDL && pli.m_label && !pli.m_label.IsEmpty()) { - title = pli.m_label; - } else { - title = GetFileName(); - } - - CStringW fs; - CString curfile = m_wndPlaylistBar.GetCurFileName(); - if (!PathUtils::IsURL(curfile)) { - ExtendMaxPathLengthIfNeeded(curfile, true); - WIN32_FIND_DATA wfd; - HANDLE hFind = FindFirstFile(curfile, &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); - fs.Format(IDS_THUMBNAILS_INFO_FILESIZE, szFileSize, FormatNumber(szByteSize).GetString()); - } - } - - CStringW ar; - if (szAR.cx > 0 && szAR.cy > 0 && szAR.cx != szVideo.cx && szAR.cy != szVideo.cy) { - ar.Format(L"(%ld:%ld)", szAR.cx, szAR.cy); - } - CStringW fmt = ResStr(IDS_THUMBNAILS_INFO_HEADER); - if (darktheme) { - fmt.Replace(L"\\1c&H000000", L"\\1c&Hc8c8c8"); - } - str.Format(fmt, fontsize, - title.GetString(), fs.GetString(), szVideo.cx, szVideo.cy, ar.GetString(), hmsf.bHours, hmsf.bMinutes, hmsf.bSeconds); - rts.Add(str, true, 0, 1, _T("thumbs")); - - rts.Render(spd, 0, 25, bbox); - } - - SaveDIB(fn, (BYTE*)dib, dibsize); - - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - - if (bWasStopped) { - OnPlayStop(); - } else { - DoSeekTo(rtPos, false); - } - - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_THUMBS_SAVED), 3000); -} - -CString CMainFrame::MakeSnapshotFileName(BOOL thumbnails) -{ - CAppSettings& s = AfxGetAppSettings(); - CString prefix; - CString fn; - - ASSERT(!thumbnails || GetPlaybackMode() == PM_FILE); - - auto videoFn = GetFileName(); - auto fullName = m_wndPlaylistBar.GetCurFileName(true); - bool needsExtensionRemoval = !s.bSnapShotKeepVideoExtension; - if (IsPlaylistFile(videoFn)) { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - videoFn = pli.m_label; - needsExtensionRemoval = false; - } - } else if (needsExtensionRemoval && PathUtils::IsURL(fullName)){ - auto title = getBestTitle(); - if (!title.IsEmpty()) { - videoFn = title; - needsExtensionRemoval = false; - } - } - - - if (needsExtensionRemoval) { - int nPos = videoFn.ReverseFind('.'); - if (nPos != -1) { - videoFn = videoFn.Left(nPos); - } - } - - bool saveImagePosition, saveImageCurrentTime; - - if (m_wndSeekBar.HasDuration()) { - saveImagePosition = s.bSaveImagePosition; - saveImageCurrentTime = s.bSaveImageCurrentTime; - } else { - saveImagePosition = false; - saveImageCurrentTime = true; - } - - if (GetPlaybackMode() == PM_FILE) { - if (thumbnails) { - prefix.Format(_T("%s_thumbs"), videoFn.GetString()); - } else { - if (saveImagePosition) { - prefix.Format(_T("%s_snapshot_%s"), videoFn.GetString(), GetVidPos().GetString()); - } else { - prefix.Format(_T("%s_snapshot"), videoFn.GetString()); - } - } - } else if (GetPlaybackMode() == PM_DVD) { - if (saveImagePosition) { - prefix.Format(_T("dvd_snapshot_%s"), GetVidPos().GetString()); - } else { - prefix = _T("dvd_snapshot"); - } - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - prefix.Format(_T("%s_snapshot"), m_pDVBState->sChannelName.GetString()); - } else { - prefix = _T("snapshot"); - } - - if (!thumbnails && saveImageCurrentTime) { - CTime t = CTime::GetCurrentTime(); - fn.Format(_T("%s_[%s]%s"), PathUtils::FilterInvalidCharsFromFileName(prefix).GetString(), t.Format(_T("%Y.%m.%d_%H.%M.%S")).GetString(), s.strSnapshotExt.GetString()); - } else { - fn.Format(_T("%s%s"), PathUtils::FilterInvalidCharsFromFileName(prefix).GetString(), s.strSnapshotExt.GetString()); - } - return fn; -} - -BOOL CMainFrame::IsRendererCompatibleWithSaveImage() -{ - BOOL result = TRUE; - const CAppSettings& s = AfxGetAppSettings(); - - if (m_fShockwaveGraph) { - AfxMessageBox(IDS_SCREENSHOT_ERROR_SHOCKWAVE, MB_ICONEXCLAMATION | MB_OK, 0); - result = FALSE; - } else if (s.iDSVideoRendererType == VIDRNDT_DS_OVERLAYMIXER) { - AfxMessageBox(IDS_SCREENSHOT_ERROR_OVERLAY, MB_ICONEXCLAMATION | MB_OK, 0); - result = FALSE; - } - - return result; -} - -CString CMainFrame::GetVidPos() const -{ - CString posstr = _T(""); - if ((GetPlaybackMode() == PM_FILE) || (GetPlaybackMode() == PM_DVD)) { - __int64 start, stop, pos; - m_wndSeekBar.GetRange(start, stop); - pos = m_wndSeekBar.GetPos(); - - DVD_HMSF_TIMECODE tcNow = RT2HMSF(pos); - DVD_HMSF_TIMECODE tcDur = RT2HMSF(stop); - - if (tcDur.bHours > 0 || tcNow.bHours > 0) { - posstr.Format(_T("%02u.%02u.%02u.%03u"), tcNow.bHours, tcNow.bMinutes, tcNow.bSeconds, (pos / 10000) % 1000); - } else { - posstr.Format(_T("%02u.%02u.%03u"), tcNow.bMinutes, tcNow.bSeconds, (pos / 10000) % 1000); - } - } - - return posstr; -} - -void CMainFrame::OnFileSaveImage() -{ - CAppSettings& s = AfxGetAppSettings(); - - /* Check if a compatible renderer is being used */ - if (!IsRendererCompatibleWithSaveImage()) { - return; - } - - CPath psrc(s.strSnapshotPath); - psrc.Combine(s.strSnapshotPath.GetString(), MakeSnapshotFileName(FALSE)); - - bool subtitleOptionSupported = !m_pMVRFG && s.fEnableSubtitles && s.IsISRAutoLoadEnabled(); - - CSaveImageDialog fd(s.nJpegQuality, s.strSnapshotExt, (LPCTSTR)psrc, - _T("BMP - Windows Bitmap (*.bmp)|*.bmp|JPG - JPEG Image (*.jpg)|*.jpg|PNG - Portable Network Graphics (*.png)|*.png||"), GetModalParent(), subtitleOptionSupported); - - if (s.strSnapshotExt == _T(".bmp")) { - fd.m_pOFN->nFilterIndex = 1; - } else if (s.strSnapshotExt == _T(".jpg")) { - fd.m_pOFN->nFilterIndex = 2; - } else if (s.strSnapshotExt == _T(".png")) { - fd.m_pOFN->nFilterIndex = 3; - } - - if (fd.DoModal() != IDOK) { - return; - } - - if (fd.m_pOFN->nFilterIndex == 1) { - s.strSnapshotExt = _T(".bmp"); - } else if (fd.m_pOFN->nFilterIndex == 2) { - s.strSnapshotExt = _T(".jpg"); - s.nJpegQuality = fd.m_nJpegQuality; - } else { - fd.m_pOFN->nFilterIndex = 3; - s.strSnapshotExt = _T(".png"); - } - - CPath pdst(fd.GetPathName()); - CString ext(pdst.GetExtension().MakeLower()); - if (ext != s.strSnapshotExt) { - if (ext == _T(".bmp") || ext == _T(".jpg") || ext == _T(".png")) { - ext = s.strSnapshotExt; - } else { - ext += s.strSnapshotExt; - } - pdst.RenameExtension(ext); - } - CString path = (LPCTSTR)pdst; - pdst.RemoveFileSpec(); - s.strSnapshotPath = (LPCTSTR)pdst; - - bool includeSubtitles = subtitleOptionSupported && s.bSnapShotSubtitles; - - SaveImage(path, false, includeSubtitles); -} - -void CMainFrame::OnFileSaveImageAuto() -{ - const CAppSettings& s = AfxGetAppSettings(); - - // If path doesn't exist, Save Image instead - if (!PathUtils::IsDir(s.strSnapshotPath)) { - AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); - OnFileSaveImage(); - return; - } - - /* Check if a compatible renderer is being used */ - if (!IsRendererCompatibleWithSaveImage()) { - return; - } - - bool includeSubtitles = s.bSnapShotSubtitles && !m_pMVRFG && s.fEnableSubtitles && s.IsISRAutoLoadEnabled(); - - CString fn; - fn.Format(_T("%s\\%s"), s.strSnapshotPath.GetString(), MakeSnapshotFileName(FALSE).GetString()); - SaveImage(fn.GetString(), false, includeSubtitles); -} - -void CMainFrame::OnUpdateFileSaveImage(CCmdUI* pCmdUI) -{ - OAFilterState fs = GetMediaState(); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (fs == State_Paused || fs == State_Running)); -} - -void CMainFrame::OnCmdLineSaveThumbnails() -{ - CAppSettings& s = AfxGetAppSettings(); - - /* Check if a compatible renderer is being used */ - if (!IsRendererCompatibleWithSaveImage()) { - return; - } - - CPlaylistItem pli; - if (!m_wndPlaylistBar.GetCur(pli, true)) { - return; - } - - CPath psrc(m_wndPlaylistBar.GetCurFileName(true)); - psrc.RemoveFileSpec(); - psrc.Combine(psrc, MakeSnapshotFileName(TRUE)); - - s.iThumbRows = std::clamp(s.iThumbRows, 1, 40); - s.iThumbCols = std::clamp(s.iThumbCols, 1, 16); - s.iThumbWidth = std::clamp(s.iThumbWidth, 256, 3840); - - CString path = (LPCTSTR)psrc; - - SaveThumbnails(path); - -} - -void CMainFrame::OnFileSaveThumbnails() -{ - CAppSettings& s = AfxGetAppSettings(); - - /* Check if a compatible renderer is being used */ - if (!IsRendererCompatibleWithSaveImage()) { - return; - } - - CPath psrc(s.strSnapshotPath); - psrc.Combine(s.strSnapshotPath, MakeSnapshotFileName(TRUE)); - - CSaveThumbnailsDialog fd(s.nJpegQuality, s.iThumbRows, s.iThumbCols, s.iThumbWidth, s.strSnapshotExt, (LPCTSTR)psrc, - _T("BMP - Windows Bitmap (*.bmp)|*.bmp|JPG - JPEG Image (*.jpg)|*.jpg|PNG - Portable Network Graphics (*.png)|*.png||"), GetModalParent()); - - if (s.strSnapshotExt == _T(".bmp")) { - fd.m_pOFN->nFilterIndex = 1; - } else if (s.strSnapshotExt == _T(".jpg")) { - fd.m_pOFN->nFilterIndex = 2; - } else if (s.strSnapshotExt == _T(".png")) { - fd.m_pOFN->nFilterIndex = 3; - } - - if (fd.DoModal() != IDOK) { - return; - } - - if (fd.m_pOFN->nFilterIndex == 1) { - s.strSnapshotExt = _T(".bmp"); - } else if (fd.m_pOFN->nFilterIndex == 2) { - s.strSnapshotExt = _T(".jpg"); - s.nJpegQuality = fd.m_nJpegQuality; - } else { - fd.m_pOFN->nFilterIndex = 3; - s.strSnapshotExt = _T(".png"); - } - - s.iThumbRows = std::clamp(fd.m_rows, 1, 40); - s.iThumbCols = std::clamp(fd.m_cols, 1, 16); - s.iThumbWidth = std::clamp(fd.m_width, 256, 3840); - - CPath pdst(fd.GetPathName()); - CString ext(pdst.GetExtension().MakeLower()); - if (ext != s.strSnapshotExt) { - if (ext == _T(".bmp") || ext == _T(".jpg") || ext == _T(".png")) { - ext = s.strSnapshotExt; - } else { - ext += s.strSnapshotExt; - } - pdst.RenameExtension(ext); - } - CString path = (LPCTSTR)pdst; - pdst.RemoveFileSpec(); - s.strSnapshotPath = (LPCTSTR)pdst; - - SaveThumbnails(path); -} - -void CMainFrame::OnUpdateFileSaveThumbnails(CCmdUI* pCmdUI) -{ - OAFilterState fs = GetMediaState(); - UNREFERENCED_PARAMETER(fs); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (GetPlaybackMode() == PM_FILE /*|| GetPlaybackMode() == PM_DVD*/)); -} - -void CMainFrame::OnFileSubtitlesLoad() -{ - if (!m_pCAP && !m_pDVS) { - AfxMessageBox(IDS_CANNOT_LOAD_SUB, MB_ICONINFORMATION | MB_OK, 0); - return; - } - - DWORD dwFlags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_NOCHANGEDIR; - if (!AfxGetAppSettings().fKeepHistory) { - dwFlags |= OFN_DONTADDTORECENT; - } - CString filters; - filters.Format(_T("%s|*.srt;*.sub;*.ssa;*.ass;*.smi;*.psb;*.txt;*.idx;*.usf;*.xss;*.rt;*.sup;*.webvtt;*.vtt|%s"), - ResStr(IDS_SUBTITLE_FILES_FILTER).GetString(), ResStr(IDS_ALL_FILES_FILTER).GetString()); - - CFileDialog fd(TRUE, nullptr, nullptr, dwFlags, filters, GetModalParent()); - - OPENFILENAME& ofn = fd.GetOFN(); - // Provide a buffer big enough to hold 16 paths (which should be more than enough) - const int nBufferSize = 16 * (MAX_PATH + 1) + 1; - CString filenames; - ofn.lpstrFile = filenames.GetBuffer(nBufferSize); - ofn.nMaxFile = nBufferSize; - // Set the current file directory as default folder - CString curfile = m_wndPlaylistBar.GetCurFileName(); - if (!PathUtils::IsURL(curfile)) { - CPath defaultDir(curfile); - defaultDir.RemoveFileSpec(); - if (!defaultDir.m_strPath.IsEmpty()) { - ofn.lpstrInitialDir = defaultDir.m_strPath; - } - } - - if (fd.DoModal() == IDOK) { - bool bFirstFile = true; - POSITION pos = fd.GetStartPosition(); - while (pos) { - CString subfile = fd.GetNextPathName(pos); - if (m_pDVS) { - if (SUCCEEDED(m_pDVS->put_FileName((LPWSTR)(LPCWSTR)subfile))) { - m_pDVS->put_SelectedLanguage(0); - m_pDVS->put_HideSubtitles(true); - m_pDVS->put_HideSubtitles(false); - break; - } - } else { - SubtitleInput subInput; - if (LoadSubtitle(subfile, &subInput) && bFirstFile) { - bFirstFile = false; - // Use the subtitles file that was just added - AfxGetAppSettings().fEnableSubtitles = true; - SetSubtitle(subInput); - } - } - } - } -} - -void CMainFrame::OnUpdateFileSubtitlesLoad(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(!m_fAudioOnly && (m_pCAP || m_pDVS) && GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode()); -} - -void CMainFrame::SubtitlesSave(const TCHAR* directory, bool silent) -{ - if (lastOpenFile.IsEmpty()) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - - int i = 0; - SubtitleInput* pSubInput = GetSubtitleInput(i, true); - if (!pSubInput) { - return; - } - - CLSID clsid; - if (FAILED(pSubInput->pSubStream->GetClassID(&clsid))) { - return; - } - - CString suggestedFileName; - if (PathUtils::IsURL(lastOpenFile)) { - if (silent) { - return; - } - suggestedFileName = _T("subtitle"); - } else { - CPath path(lastOpenFile); - path.RemoveExtension(); - suggestedFileName = CString(path); - } - - if (directory && *directory) { - CPath suggestedPath(suggestedFileName); - int pos = suggestedPath.FindFileName(); - CString fileName = suggestedPath.m_strPath.Mid(pos); - CPath dirPath(directory); - if (dirPath.IsRelative()) { - dirPath = CPath(suggestedPath.m_strPath.Left(pos)) += dirPath; - } - if (EnsureDirectory(dirPath)) { - suggestedFileName = CString(dirPath += fileName); - } - else if (silent) { - return; - } - } - - bool isSaved = false; - if (clsid == __uuidof(CVobSubFile)) { - CVobSubFile* pVSF = (CVobSubFile*)(ISubStream*)pSubInput->pSubStream; - - // remember to set lpszDefExt to the first extension in the filter so that the save dialog autocompletes the extension - // and tracks attempts to overwrite in a graceful manner - if (silent) { - isSaved = pVSF->Save(suggestedFileName + _T(".idx"), m_pCAP->GetSubtitleDelay()); - } else { - CSaveSubtitlesFileDialog fd(m_pCAP->GetSubtitleDelay(), _T("idx"), suggestedFileName, - _T("VobSub (*.idx, *.sub)|*.idx;*.sub||"), GetModalParent()); - - if (fd.DoModal() == IDOK) { - CAutoLock cAutoLock(&m_csSubLock); - isSaved = pVSF->Save(fd.GetPathName(), fd.GetDelay()); - } - } - } - else if (clsid == __uuidof(CRenderedTextSubtitle)) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; - - if (s.bAddLangCodeWhenSaveSubtitles && pRTS->m_lcid && pRTS->m_lcid != LCID(-1)) { - CString str; - GetLocaleString(pRTS->m_lcid, LOCALE_SISO639LANGNAME, str); - suggestedFileName += _T('.') + str; - - if (pRTS->m_eHearingImpaired == Subtitle::HI_YES) { - suggestedFileName += _T(".hi"); - } - } - - // same thing as in the case of CVobSubFile above for lpszDefExt - if (silent) { - Subtitle::SubType type; - switch (pRTS->m_subtitleType) - { - case Subtitle::ASS: - case Subtitle::SSA: - case Subtitle::VTT: - type = Subtitle::ASS; - break; - default: - type = Subtitle::SRT; - } - - isSaved = pRTS->SaveAs( - suggestedFileName, type, m_pCAP->GetFPS(), m_pCAP->GetSubtitleDelay(), - CTextFile::DEFAULT_ENCODING, s.bSubSaveExternalStyleFile); - } else { - const std::vector types = { - Subtitle::SRT, - Subtitle::SUB, - Subtitle::SMI, - Subtitle::PSB, - Subtitle::SSA, - Subtitle::ASS - }; - - CString filter; - filter += _T("SubRip (*.srt)|*.srt|"); //1 = default - filter += _T("MicroDVD (*.sub)|*.sub|"); //2 - filter += _T("SAMI (*.smi)|*.smi|"); //3 - filter += _T("PowerDivX (*.psb)|*.psb|"); //4 - filter += _T("SubStation Alpha (*.ssa)|*.ssa|"); //5 - filter += _T("Advanced SubStation Alpha (*.ass)|*.ass|"); //6 - filter += _T("|"); - - CSaveSubtitlesFileDialog fd(pRTS->m_encoding, m_pCAP->GetSubtitleDelay(), s.bSubSaveExternalStyleFile, - _T("srt"), suggestedFileName, filter, types, GetModalParent()); - - if (pRTS->m_subtitleType == Subtitle::SSA || pRTS->m_subtitleType == Subtitle::ASS) { - fd.m_ofn.nFilterIndex = 6; //nFilterIndex is 1-based - } - - if (fd.DoModal() == IDOK) { - CAutoLock cAutoLock(&m_csSubLock); - s.bSubSaveExternalStyleFile = fd.GetSaveExternalStyleFile(); - isSaved = pRTS->SaveAs(fd.GetPathName(), types[fd.m_ofn.nFilterIndex - 1], m_pCAP->GetFPS(), fd.GetDelay(), fd.GetEncoding(), fd.GetSaveExternalStyleFile()); - } - } - } - else { - AfxMessageBox(_T("This operation is not supported.\r\nThe selected subtitles cannot be saved."), MB_ICONEXCLAMATION | MB_OK); - } - - if (isSaved && s.fKeepHistory) { - auto subPath = pSubInput->pSubStream->GetPath(); - if (!subPath.IsEmpty()) { - s.MRU.AddSubToCurrent(subPath); - } - } -} - -void CMainFrame::OnUpdateFileSubtitlesSave(CCmdUI* pCmdUI) -{ - bool bEnable = false; - - if (!m_pCurrentSubInput.pSourceFilter) { - if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { - bEnable = !pRTS->IsEmpty(); - } else if (dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { - bEnable = true; - } - } - - pCmdUI->Enable(bEnable); -} - -#if 0 -void CMainFrame::OnFileSubtitlesUpload() -{ - m_wndSubtitlesUploadDialog.ShowWindow(SW_SHOW); -} - -void CMainFrame::OnUpdateFileSubtitlesUpload(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(!m_pSubStreams.IsEmpty() && s.fEnableSubtitles); -} -#endif - -void CMainFrame::OnFileSubtitlesDownload() -{ - if (!m_fAudioOnly) { - if (m_pCAP && AfxGetAppSettings().IsISRAutoLoadEnabled()) { - m_wndSubtitlesDownloadDialog.ShowWindow(SW_SHOW); - } else { - AfxMessageBox(_T("Downloading subtitles only works when using the internal subtitle renderer."), MB_ICONINFORMATION | MB_OK, 0); - } - } -} - -void CMainFrame::OnUpdateFileSubtitlesDownload(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode() && m_pCAP && !m_fAudioOnly); -} - -void CMainFrame::OnFileProperties() -{ - CString fn; - CString ydlsrc; - if (m_pDVBState) { - fn = m_pDVBState->sChannelName; - } else { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - fn = pli.m_fns.GetHead(); - if (pli.m_bYoutubeDL) { - ydlsrc = pli.m_ydlSourceURL; - } - } - } - - ASSERT(!fn.IsEmpty()); - - CPPageFileInfoSheet fileinfo(fn, ydlsrc, this, GetModalParent()); - fileinfo.DoModal(); -} - -void CMainFrame::OnUpdateFileProperties(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() != PM_ANALOG_CAPTURE); -} - -void CMainFrame::OnFileOpenLocation() { - CString filePath = m_wndPlaylistBar.GetCurFileName(); - if (!PathUtils::IsURL(filePath)) { - ExploreToFile(filePath); - } -} - -void CMainFrame::OnFileCloseMedia() -{ - CloseMedia(); -} - -void CMainFrame::OnUpdateViewTearingTest(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC); - - pCmdUI->Enable(supported && GetLoadState() == MLS::LOADED && !m_fAudioOnly); - pCmdUI->SetCheck(supported && AfxGetMyApp()->m_Renderers.m_bTearingTest); -} - -void CMainFrame::OnViewTearingTest() -{ - AfxGetMyApp()->m_Renderers.m_bTearingTest = !AfxGetMyApp()->m_Renderers.m_bTearingTest; -} - -void CMainFrame::OnUpdateViewDisplayRendererStats(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); - - pCmdUI->Enable(supported && GetLoadState() == MLS::LOADED && !m_fAudioOnly); - pCmdUI->SetCheck(supported && AfxGetMyApp()->m_Renderers.m_iDisplayStats > 0); -} - -void CMainFrame::OnViewResetRendererStats() -{ - AfxGetMyApp()->m_Renderers.m_bResetStats = true; // Reset by "consumer" -} - -void CMainFrame::OnViewDisplayRendererStats() -{ - const CAppSettings& s = AfxGetAppSettings(); - bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); - - if (supported) { - if (m_pCAP3) { - m_pCAP3->ToggleStats(); - return; - } - - if (!AfxGetMyApp()->m_Renderers.m_iDisplayStats) { - AfxGetMyApp()->m_Renderers.m_bResetStats = true; // to reset statistics on first call ... - } - - ++AfxGetMyApp()->m_Renderers.m_iDisplayStats; - if (AfxGetMyApp()->m_Renderers.m_iDisplayStats > 3) { - AfxGetMyApp()->m_Renderers.m_iDisplayStats = 0; - } - RepaintVideo(); - } -} - -void CMainFrame::OnUpdateViewVSync(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(!supported || r.m_AdvRendSets.bVMR9VSync); -} - -void CMainFrame::OnUpdateViewVSyncOffset(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D - && r.m_AdvRendSets.bVMR9AlterativeVSync); - - pCmdUI->Enable(supported); - CString Temp; - Temp.Format(L"%d", r.m_AdvRendSets.iVMR9VSyncOffset); - pCmdUI->SetText(Temp); - CMPCThemeMenu::updateItem(pCmdUI); -} - -void CMainFrame::OnUpdateViewVSyncAccurate(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9VSyncAccurate); -} - -void CMainFrame::OnUpdateViewSynchronizeVideo(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_SYNC) && GetPlaybackMode() == PM_NONE); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeVideo); -} - -void CMainFrame::OnUpdateViewSynchronizeDisplay(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_SYNC) && GetPlaybackMode() == PM_NONE); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeDisplay); -} - -void CMainFrame::OnUpdateViewSynchronizeNearest(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_SYNC); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeNearest); -} - -void CMainFrame::OnUpdateViewColorManagementEnable(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9ColorManagementEnable); -} - -void CMainFrame::OnUpdateViewColorManagementInput(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support - && r.m_AdvRendSets.bVMR9ColorManagementEnable; - - pCmdUI->Enable(supported); - - switch (pCmdUI->m_nID) { - case ID_VIEW_CM_INPUT_AUTO: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_UNKNOWN); - break; - - case ID_VIEW_CM_INPUT_HDTV: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_HDTV); - break; - - case ID_VIEW_CM_INPUT_SDTV_NTSC: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_SDTV_NTSC); - break; - - case ID_VIEW_CM_INPUT_SDTV_PAL: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_SDTV_PAL); - break; - } -} - -void CMainFrame::OnUpdateViewColorManagementAmbientLight(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support && - r.m_AdvRendSets.bVMR9ColorManagementEnable; - - pCmdUI->Enable(supported); - - switch (pCmdUI->m_nID) { - case ID_VIEW_CM_AMBIENTLIGHT_BRIGHT: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_BRIGHT); - break; - case ID_VIEW_CM_AMBIENTLIGHT_DIM: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_DIM); - break; - case ID_VIEW_CM_AMBIENTLIGHT_DARK: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_DARK); - break; - } -} - -void CMainFrame::OnUpdateViewColorManagementIntent(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support - && r.m_AdvRendSets.bVMR9ColorManagementEnable; - - pCmdUI->Enable(supported); - - switch (pCmdUI->m_nID) { - case ID_VIEW_CM_INTENT_PERCEPTUAL: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_PERCEPTUAL); - break; - case ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC); - break; - case ID_VIEW_CM_INTENT_SATURATION: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_SATURATION); - break; - case ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC); - break; - } -} - -void CMainFrame::OnUpdateViewEVROutputRange(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - - if (pCmdUI->m_nID == ID_VIEW_EVROUTPUTRANGE_0_255) { - pCmdUI->SetCheck(r.m_AdvRendSets.iEVROutputRange == 0); - } else if (pCmdUI->m_nID == ID_VIEW_EVROUTPUTRANGE_16_235) { - pCmdUI->SetCheck(r.m_AdvRendSets.iEVROutputRange == 1); - } -} - -void CMainFrame::OnUpdateViewFlushGPU(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - - if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_BEFOREVSYNC) { - pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUBeforeVSync); - } else if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_AFTERPRESENT) { - pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUAfterPresent); - } else if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_WAIT) { - pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUWait); - } - -} - -void CMainFrame::OnUpdateViewD3DFullscreen(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(s.fD3DFullscreen); -} - -void CMainFrame::OnUpdateViewDisableDesktopComposition(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D - && !IsWindows8OrGreater()); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(supported && r.m_AdvRendSets.bVMRDisableDesktopComposition); -} - -void CMainFrame::OnUpdateViewAlternativeVSync(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9AlterativeVSync); -} - -void CMainFrame::OnUpdateViewFullscreenGUISupport(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9FullscreenGUISupport); -} - -void CMainFrame::OnUpdateViewHighColorResolution(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_b10bitSupport; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bEVRHighColorResolution); -} - -void CMainFrame::OnUpdateViewForceInputHighColorResolution(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_b10bitSupport; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bEVRForceInputHighColorResolution); -} - -void CMainFrame::OnUpdateViewFullFloatingPointProcessing(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP32Support; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9FullFloatingPointProcessing); -} - -void CMainFrame::OnUpdateViewHalfFloatingPointProcessing(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing); -} - -void CMainFrame::OnUpdateViewEnableFrameTimeCorrection(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bEVREnableFrameTimeCorrection); -} - -void CMainFrame::OnUpdateViewVSyncOffsetIncrease(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || (((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && r.m_AdvRendSets.bVMR9AlterativeVSync); - - pCmdUI->Enable(supported); -} - -void CMainFrame::OnUpdateViewVSyncOffsetDecrease(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || (((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && r.m_AdvRendSets.bVMR9AlterativeVSync); - - pCmdUI->Enable(supported); -} - -void CMainFrame::OnViewVSync() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9VSync = !r.m_AdvRendSets.bVMR9VSync; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9VSync - ? IDS_OSD_RS_VSYNC_ON : IDS_OSD_RS_VSYNC_OFF)); -} - -void CMainFrame::OnViewVSyncAccurate() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9VSyncAccurate = !r.m_AdvRendSets.bVMR9VSyncAccurate; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9VSyncAccurate - ? IDS_OSD_RS_ACCURATE_VSYNC_ON : IDS_OSD_RS_ACCURATE_VSYNC_OFF)); -} - -void CMainFrame::OnViewSynchronizeVideo() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bSynchronizeVideo = !r.m_AdvRendSets.bSynchronizeVideo; - if (r.m_AdvRendSets.bSynchronizeVideo) { - r.m_AdvRendSets.bSynchronizeDisplay = false; - r.m_AdvRendSets.bSynchronizeNearest = false; - r.m_AdvRendSets.bVMR9VSync = false; - r.m_AdvRendSets.bVMR9VSyncAccurate = false; - r.m_AdvRendSets.bVMR9AlterativeVSync = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeVideo - ? IDS_OSD_RS_SYNC_TO_DISPLAY_ON : IDS_OSD_RS_SYNC_TO_DISPLAY_ON)); -} - -void CMainFrame::OnViewSynchronizeDisplay() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bSynchronizeDisplay = !r.m_AdvRendSets.bSynchronizeDisplay; - if (r.m_AdvRendSets.bSynchronizeDisplay) { - r.m_AdvRendSets.bSynchronizeVideo = false; - r.m_AdvRendSets.bSynchronizeNearest = false; - r.m_AdvRendSets.bVMR9VSync = false; - r.m_AdvRendSets.bVMR9VSyncAccurate = false; - r.m_AdvRendSets.bVMR9AlterativeVSync = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeDisplay - ? IDS_OSD_RS_SYNC_TO_VIDEO_ON : IDS_OSD_RS_SYNC_TO_VIDEO_ON)); -} - -void CMainFrame::OnViewSynchronizeNearest() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bSynchronizeNearest = !r.m_AdvRendSets.bSynchronizeNearest; - if (r.m_AdvRendSets.bSynchronizeNearest) { - r.m_AdvRendSets.bSynchronizeVideo = false; - r.m_AdvRendSets.bSynchronizeDisplay = false; - r.m_AdvRendSets.bVMR9VSync = false; - r.m_AdvRendSets.bVMR9VSyncAccurate = false; - r.m_AdvRendSets.bVMR9AlterativeVSync = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeNearest - ? IDS_OSD_RS_PRESENT_NEAREST_ON : IDS_OSD_RS_PRESENT_NEAREST_OFF)); -} - -void CMainFrame::OnViewColorManagementEnable() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9ColorManagementEnable = !r.m_AdvRendSets.bVMR9ColorManagementEnable; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9ColorManagementEnable - ? IDS_OSD_RS_COLOR_MANAGEMENT_ON : IDS_OSD_RS_COLOR_MANAGEMENT_OFF)); -} - -void CMainFrame::OnViewColorManagementInputAuto() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_AUTO)); -} - -void CMainFrame::OnViewColorManagementInputHDTV() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_HDTV; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_HDTV)); -} - -void CMainFrame::OnViewColorManagementInputSDTV_NTSC() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_SDTV_NTSC; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_SD_NTSC)); -} - -void CMainFrame::OnViewColorManagementInputSDTV_PAL() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_SDTV_PAL; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_SD_PAL)); -} - -void CMainFrame::OnViewColorManagementAmbientLightBright() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_BRIGHT)); -} - -void CMainFrame::OnViewColorManagementAmbientLightDim() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_DIM; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_DIM)); -} - -void CMainFrame::OnViewColorManagementAmbientLightDark() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_DARK; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_DARK)); -} - -void CMainFrame::OnViewColorManagementIntentPerceptual() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_PERCEPT)); -} - -void CMainFrame::OnViewColorManagementIntentRelativeColorimetric() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_RELATIVE)); -} - -void CMainFrame::OnViewColorManagementIntentSaturation() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_SATURATION; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_SATUR)); -} - -void CMainFrame::OnViewColorManagementIntentAbsoluteColorimetric() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_ABSOLUTE)); -} - -void CMainFrame::OnViewEVROutputRange_0_255() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iEVROutputRange = 0; - CString strOSD; - strOSD.Format(IDS_OSD_RS_OUTPUT_RANGE, _T("0 - 255")); - m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); -} - -void CMainFrame::OnViewEVROutputRange_16_235() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iEVROutputRange = 1; - CString strOSD; - strOSD.Format(IDS_OSD_RS_OUTPUT_RANGE, _T("16 - 235")); - m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); -} - -void CMainFrame::OnViewFlushGPUBeforeVSync() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMRFlushGPUBeforeVSync = !r.m_AdvRendSets.bVMRFlushGPUBeforeVSync; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUBeforeVSync - ? IDS_OSD_RS_FLUSH_BEF_VSYNC_ON : IDS_OSD_RS_FLUSH_BEF_VSYNC_OFF)); -} - -void CMainFrame::OnViewFlushGPUAfterVSync() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMRFlushGPUAfterPresent = !r.m_AdvRendSets.bVMRFlushGPUAfterPresent; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUAfterPresent - ? IDS_OSD_RS_FLUSH_AFT_PRES_ON : IDS_OSD_RS_FLUSH_AFT_PRES_OFF)); -} - -void CMainFrame::OnViewFlushGPUWait() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMRFlushGPUWait = !r.m_AdvRendSets.bVMRFlushGPUWait; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUWait - ? IDS_OSD_RS_WAIT_ON : IDS_OSD_RS_WAIT_OFF)); -} - -void CMainFrame::OnViewD3DFullScreen() -{ - CAppSettings& r = AfxGetAppSettings(); - r.fD3DFullscreen = !r.fD3DFullscreen; - r.SaveSettings(); - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.fD3DFullscreen - ? IDS_OSD_RS_D3D_FULLSCREEN_ON : IDS_OSD_RS_D3D_FULLSCREEN_OFF)); -} - -void CMainFrame::OnViewDisableDesktopComposition() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMRDisableDesktopComposition = !r.m_AdvRendSets.bVMRDisableDesktopComposition; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRDisableDesktopComposition - ? IDS_OSD_RS_NO_DESKTOP_COMP_ON : IDS_OSD_RS_NO_DESKTOP_COMP_OFF)); -} - -void CMainFrame::OnViewAlternativeVSync() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9AlterativeVSync = !r.m_AdvRendSets.bVMR9AlterativeVSync; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9AlterativeVSync - ? IDS_OSD_RS_ALT_VSYNC_ON : IDS_OSD_RS_ALT_VSYNC_OFF)); -} - -void CMainFrame::OnViewResetDefault() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.SetDefault(); - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_RESET_DEFAULT)); -} - -void CMainFrame::OnViewResetOptimal() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.SetOptimal(); - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_RESET_OPTIMAL)); -} - -void CMainFrame::OnViewFullscreenGUISupport() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9FullscreenGUISupport = !r.m_AdvRendSets.bVMR9FullscreenGUISupport; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9FullscreenGUISupport - ? IDS_OSD_RS_D3D_FS_GUI_SUPP_ON : IDS_OSD_RS_D3D_FS_GUI_SUPP_OFF)); -} - -void CMainFrame::OnViewHighColorResolution() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bEVRHighColorResolution = !r.m_AdvRendSets.bEVRHighColorResolution; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVRHighColorResolution - ? IDS_OSD_RS_10BIT_RBG_OUT_ON : IDS_OSD_RS_10BIT_RBG_OUT_OFF)); -} - -void CMainFrame::OnViewForceInputHighColorResolution() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bEVRForceInputHighColorResolution = !r.m_AdvRendSets.bEVRForceInputHighColorResolution; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVRForceInputHighColorResolution - ? IDS_OSD_RS_10BIT_RBG_IN_ON : IDS_OSD_RS_10BIT_RBG_IN_OFF)); -} - -void CMainFrame::OnViewFullFloatingPointProcessing() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - if (!r.m_AdvRendSets.bVMR9FullFloatingPointProcessing) { - if (AfxMessageBox(_T("WARNING: Full Floating Point processing can sometimes cause problems. With some videos it can cause the player to freeze, crash, or display corrupted video. This happens mostly with Intel GPUs.\n\nAre you really sure that you want to enable this setting?"), MB_YESNO) == IDNO) { - return; - } - } - r.m_AdvRendSets.bVMR9FullFloatingPointProcessing = !r.m_AdvRendSets.bVMR9FullFloatingPointProcessing; - if (r.m_AdvRendSets.bVMR9FullFloatingPointProcessing) { - r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9FullFloatingPointProcessing - ? IDS_OSD_RS_FULL_FP_PROCESS_ON : IDS_OSD_RS_FULL_FP_PROCESS_OFF)); -} - -void CMainFrame::OnViewHalfFloatingPointProcessing() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing = !r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing; - if (r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing) { - r.m_AdvRendSets.bVMR9FullFloatingPointProcessing = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing - ? IDS_OSD_RS_HALF_FP_PROCESS_ON : IDS_OSD_RS_HALF_FP_PROCESS_OFF)); -} - -void CMainFrame::OnViewEnableFrameTimeCorrection() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bEVREnableFrameTimeCorrection = !r.m_AdvRendSets.bEVREnableFrameTimeCorrection; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVREnableFrameTimeCorrection - ? IDS_OSD_RS_FT_CORRECTION_ON : IDS_OSD_RS_FT_CORRECTION_OFF)); -} - -void CMainFrame::OnViewVSyncOffsetIncrease() -{ - CAppSettings& s = AfxGetAppSettings(); - CRenderersSettings& r = s.m_RenderersSettings; - CString strOSD; - if (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { - r.m_AdvRendSets.fTargetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset - 0.5; // Yeah, it should be a "-" - strOSD.Format(IDS_OSD_RS_TARGET_VSYNC_OFFSET, r.m_AdvRendSets.fTargetSyncOffset); - } else { - ++r.m_AdvRendSets.iVMR9VSyncOffset; - strOSD.Format(IDS_OSD_RS_VSYNC_OFFSET, r.m_AdvRendSets.iVMR9VSyncOffset); - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); -} - -void CMainFrame::OnViewVSyncOffsetDecrease() -{ - CAppSettings& s = AfxGetAppSettings(); - CRenderersSettings& r = s.m_RenderersSettings; - CString strOSD; - if (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { - r.m_AdvRendSets.fTargetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset + 0.5; - strOSD.Format(IDS_OSD_RS_TARGET_VSYNC_OFFSET, r.m_AdvRendSets.fTargetSyncOffset); - } else { - --r.m_AdvRendSets.iVMR9VSyncOffset; - strOSD.Format(IDS_OSD_RS_VSYNC_OFFSET, r.m_AdvRendSets.iVMR9VSyncOffset); - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); -} - -void CMainFrame::OnUpdateViewOSDDisplayTime(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(s.fShowOSD && GetLoadState() != MLS::CLOSED); - pCmdUI->SetCheck(AfxGetAppSettings().fShowCurrentTimeInOSD); -} - -void CMainFrame::OnViewOSDDisplayTime() -{ - auto &showTime = AfxGetAppSettings().fShowCurrentTimeInOSD; - showTime = !showTime; - - if (!showTime) { - m_OSD.ClearTime(); - } - - OnTimer(TIMER_STREAMPOSPOLLER2); -} - -void CMainFrame::OnUpdateViewOSDShowFileName(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(s.fShowOSD && GetLoadState() != MLS::CLOSED); -} - -void CMainFrame::OnViewOSDShowFileName() -{ - CString strOSD; - switch (GetPlaybackMode()) { - case PM_FILE: - strOSD = GetFileName(); - break; - case PM_DVD: - strOSD = _T("DVD"); - if (m_pDVDI) { - CString path; - ULONG len = 0; - if (SUCCEEDED(m_pDVDI->GetDVDDirectory(path.GetBuffer(MAX_PATH), MAX_PATH, &len)) && len) { - path.ReleaseBuffer(); - if (path.Find(_T("\\VIDEO_TS")) == 2) { - strOSD.AppendFormat(_T(" - %s"), GetDriveLabel(CPath(path)).GetString()); - } else { - strOSD.AppendFormat(_T(" - %s"), path.GetString()); - } - } - } - break; - case PM_ANALOG_CAPTURE: - strOSD = GetCaptureTitle(); - break; - case PM_DIGITAL_CAPTURE: - UpdateCurrentChannelInfo(true, false); - break; - default: // Shouldn't happen - ASSERT(FALSE); - return; - } - if (!strOSD.IsEmpty()) { - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD); - } -} - -void CMainFrame::OnUpdateShaderToggle1(CCmdUI* pCmdUI) -{ - if (AfxGetAppSettings().m_Shaders.GetCurrentPreset().GetPreResize().empty()) { - pCmdUI->Enable(FALSE); - pCmdUI->SetCheck (0); - } else { - pCmdUI->Enable(TRUE); - pCmdUI->SetCheck (m_bToggleShader); - } -} - -void CMainFrame::OnUpdateShaderToggle2(CCmdUI* pCmdUI) -{ - CAppSettings& s = AfxGetAppSettings(); - - if (s.m_Shaders.GetCurrentPreset().GetPostResize().empty()) { - pCmdUI->Enable(FALSE); - pCmdUI->SetCheck(0); - } else { - pCmdUI->Enable(TRUE); - pCmdUI->SetCheck(m_bToggleShaderScreenSpace); - } -} - -void CMainFrame::OnShaderToggle1() -{ - m_bToggleShader = !m_bToggleShader; - SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); - if (m_bToggleShader) { - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_PRESIZE_SHADERS_ENABLED)); - } else { - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_PRESIZE_SHADERS_DISABLED)); - } - - if (m_pCAP) { - RepaintVideo(); - } -} - -void CMainFrame::OnShaderToggle2() -{ - m_bToggleShaderScreenSpace = !m_bToggleShaderScreenSpace; - SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); - if (m_bToggleShaderScreenSpace) { - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_POSTSIZE_SHADERS_ENABLED)); - } else { - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_POSTSIZE_SHADERS_DISABLED)); - } - - if (m_pCAP) { - RepaintVideo(); - } -} - -void CMainFrame::OnD3DFullscreenToggle() -{ - CAppSettings& s = AfxGetAppSettings(); - CString strMsg; - - s.fD3DFullscreen = !s.fD3DFullscreen; - strMsg.LoadString(s.fD3DFullscreen ? IDS_OSD_RS_D3D_FULLSCREEN_ON : IDS_OSD_RS_D3D_FULLSCREEN_OFF); - if (GetLoadState() == MLS::CLOSED) { - m_closingmsg = strMsg; - } else { - m_OSD.DisplayMessage(OSD_TOPRIGHT, strMsg); - } -} - -void CMainFrame::OnFileCloseAndRestore() -{ - if (GetLoadState() == MLS::LOADED && IsFullScreenMode()) { - // exit fullscreen - OnViewFullscreen(); - } - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - RestoreDefaultWindowRect(); -} - -void CMainFrame::OnUpdateFileClose(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED || GetLoadState() == MLS::LOADING); -} - -// view - -void CMainFrame::SetCaptionState(MpcCaptionState eState) -{ - auto& s = AfxGetAppSettings(); - - if (eState == s.eCaptionMenuMode) { - return; - } - - const auto eOldState = s.eCaptionMenuMode; - s.eCaptionMenuMode = eState; - - if (IsFullScreenMainFrame()) { - return; - } - - DWORD dwRemove = 0, dwAdd = 0; - DWORD dwMenuFlags = GetMenuBarVisibility(); - - CRect windowRect; - - const bool bZoomed = !!IsZoomed(); - - if (!bZoomed) { - GetWindowRect(&windowRect); - CRect decorationsRect; - VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), dwMenuFlags == AFX_MBV_KEEPVISIBLE, GetWindowExStyle(m_hWnd))); - windowRect.bottom -= decorationsRect.bottom; - windowRect.right -= decorationsRect.right; - windowRect.top -= decorationsRect.top; - windowRect.left -= decorationsRect.left; - } - - const int base = MpcCaptionState::MODE_COUNT; - for (int i = eOldState; i != eState; i = (i + 1) % base) { - switch (static_cast(i)) { - case MpcCaptionState::MODE_BORDERLESS: - dwMenuFlags = AFX_MBV_KEEPVISIBLE; - dwAdd |= (WS_CAPTION | WS_THICKFRAME); - dwRemove &= ~(WS_CAPTION | WS_THICKFRAME); - break; - case MpcCaptionState::MODE_SHOWCAPTIONMENU: - dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; - break; - case MpcCaptionState::MODE_HIDEMENU: - dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; - dwAdd &= ~WS_CAPTION; - dwRemove |= WS_CAPTION; - break; - case MpcCaptionState::MODE_FRAMEONLY: - dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; - dwAdd &= ~WS_THICKFRAME; - dwRemove |= WS_THICKFRAME; - break; - default: - ASSERT(FALSE); - } - } - - UINT uFlags = SWP_NOZORDER; - if (dwRemove != dwAdd) { - uFlags |= SWP_FRAMECHANGED; - VERIFY(SetWindowLong(m_hWnd, GWL_STYLE, (GetWindowLong(m_hWnd, GWL_STYLE) | dwAdd) & ~dwRemove)); - } - - SetMenuBarVisibility(dwMenuFlags); - if (bZoomed) { - CMonitors::GetNearestMonitor(this).GetWorkAreaRect(windowRect); - } else { - VERIFY(AdjustWindowRectEx(windowRect, GetWindowStyle(m_hWnd), dwMenuFlags == AFX_MBV_KEEPVISIBLE, GetWindowExStyle(m_hWnd))); - } - - VERIFY(SetWindowPos(nullptr, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), uFlags)); - OSDBarSetPos(); -} - -void CMainFrame::OnViewCaptionmenu() -{ - const auto& s = AfxGetAppSettings(); - SetCaptionState(static_cast((s.eCaptionMenuMode + 1) % MpcCaptionState::MODE_COUNT)); -} - -void CMainFrame::OnUpdateViewCaptionmenu(CCmdUI* pCmdUI) -{ - const auto& s = AfxGetAppSettings(); - const UINT next[] = { IDS_VIEW_HIDEMENU, IDS_VIEW_FRAMEONLY, IDS_VIEW_BORDERLESS, IDS_VIEW_CAPTIONMENU }; - pCmdUI->SetText(ResStr(next[s.eCaptionMenuMode % MpcCaptionState::MODE_COUNT])); - CMPCThemeMenu::updateItem(pCmdUI); -} - -void CMainFrame::OnViewControlBar(UINT nID) -{ - nID -= ID_VIEW_SEEKER; - m_controls.ToggleControl(static_cast(nID)); -} - -void CMainFrame::OnUpdateViewControlBar(CCmdUI* pCmdUI) -{ - const UINT nID = pCmdUI->m_nID - ID_VIEW_SEEKER; - pCmdUI->SetCheck(m_controls.ControlChecked(static_cast(nID))); - if (pCmdUI->m_nID == ID_VIEW_SEEKER) { - pCmdUI->Enable(!IsPlaybackCaptureMode()); - } -} - -void CMainFrame::OnViewSubresync() -{ - m_controls.ToggleControl(CMainFrameControls::Panel::SUBRESYNC); - AdjustStreamPosPoller(true); -} - -void CMainFrame::OnUpdateViewSubresync(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::SUBRESYNC)); - bool enabled = m_pCAP && m_pCurrentSubInput.pSubStream && !IsPlaybackCaptureMode(); - if (enabled) { - CLSID clsid; - m_pCurrentSubInput.pSubStream->GetClassID(&clsid); - if (clsid == __uuidof(CRenderedTextSubtitle)) { -#if USE_LIBASS - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; - enabled = !pRTS->m_LibassContext.IsLibassActive(); -#endif - } else { - enabled = false; - } - } - pCmdUI->Enable(enabled); -} - -void CMainFrame::OnViewPlaylist() -{ - m_controls.ToggleControl(CMainFrameControls::Panel::PLAYLIST); - m_wndPlaylistBar.SetHiddenDueToFullscreen(false); -} - -void CMainFrame::OnUpdateViewPlaylist(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)); -} - -void CMainFrame::OnPlaylistToggleShuffle() { - CAppSettings& s = AfxGetAppSettings(); - s.bShufflePlaylistItems = !s.bShufflePlaylistItems; - m_wndPlaylistBar.m_pl.SetShuffle(s.bShufflePlaylistItems); -} - -void CMainFrame::OnViewEditListEditor() -{ - CAppSettings& s = AfxGetAppSettings(); - - if (s.fEnableEDLEditor || (AfxMessageBox(IDS_MB_SHOW_EDL_EDITOR, MB_ICONQUESTION | MB_YESNO, 0) == IDYES)) { - s.fEnableEDLEditor = true; - m_controls.ToggleControl(CMainFrameControls::Panel::EDL); - } -} - -void CMainFrame::OnEDLIn() -{ - if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { - REFERENCE_TIME rt; - - m_pMS->GetCurrentPosition(&rt); - m_wndEditListEditor.SetIn(rt); - } -} - -void CMainFrame::OnUpdateEDLIn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); -} - -void CMainFrame::OnEDLOut() -{ - if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { - REFERENCE_TIME rt; - - m_pMS->GetCurrentPosition(&rt); - m_wndEditListEditor.SetOut(rt); - } -} - -void CMainFrame::OnUpdateEDLOut(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); -} - -void CMainFrame::OnEDLNewClip() -{ - if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { - REFERENCE_TIME rt; - - m_pMS->GetCurrentPosition(&rt); - m_wndEditListEditor.NewClip(rt); - } -} - -void CMainFrame::OnUpdateEDLNewClip(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); -} - -void CMainFrame::OnEDLSave() -{ - if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { - m_wndEditListEditor.Save(); - } -} - -void CMainFrame::OnUpdateEDLSave(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); -} - -// Navigation menu -void CMainFrame::OnViewNavigation() -{ - const bool bHiding = m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION); - m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); - if (!bHiding) { - m_wndNavigationBar.m_navdlg.UpdateElementList(); - } - AfxGetAppSettings().fHideNavigation = bHiding; -} - -void CMainFrame::OnUpdateViewNavigation(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_DIGITAL_CAPTURE); -} - -void CMainFrame::OnViewCapture() -{ - m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); -} - -void CMainFrame::OnUpdateViewCapture(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_ANALOG_CAPTURE); -} - -void CMainFrame::OnViewDebugShaders() -{ - auto& dlg = m_pDebugShaders; - if (dlg && !dlg->m_hWnd) { - // something has destroyed the dialog and we didn't know about it - dlg = nullptr; - } - if (!dlg) { - // dialog doesn't exist - create and show it - dlg = std::make_unique(); - dlg->ShowWindow(SW_SHOW); - } else if (dlg->IsWindowVisible()) { - if (dlg->IsIconic()) { - // dialog is visible but iconic - restore it - VERIFY(dlg->ShowWindow(SW_RESTORE)); - } else { - // dialog is visible and not iconic - destroy it - VERIFY(dlg->DestroyWindow()); - ASSERT(!dlg->m_hWnd); - dlg = nullptr; - } - } else { - // dialog is not visible - show it - VERIFY(!dlg->ShowWindow(SW_SHOW)); - } -} - -void CMainFrame::OnUpdateViewDebugShaders(CCmdUI* pCmdUI) -{ - const auto& dlg = m_pDebugShaders; - pCmdUI->SetCheck(dlg && dlg->m_hWnd && dlg->IsWindowVisible()); -} - -void CMainFrame::OnViewMinimal() -{ - SetCaptionState(MODE_BORDERLESS); - m_controls.SetToolbarsSelection(CS_NONE, true); -} - -void CMainFrame::OnUpdateViewMinimal(CCmdUI* pCmdUI) -{ -} - -void CMainFrame::OnViewCompact() -{ - SetCaptionState(MODE_FRAMEONLY); - m_controls.SetToolbarsSelection(CS_SEEKBAR, true); -} - -void CMainFrame::OnUpdateViewCompact(CCmdUI* pCmdUI) -{ -} - -void CMainFrame::OnViewNormal() -{ - SetCaptionState(MODE_SHOWCAPTIONMENU); - m_controls.SetToolbarsSelection(CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR, true); -} - -void CMainFrame::OnUpdateViewNormal(CCmdUI* pCmdUI) -{ -} - -void CMainFrame::OnViewFullscreen() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (IsD3DFullScreenMode() || (s.IsD3DFullscreen() && !m_fFullScreen && !m_fAudioOnly && m_pD3DFSC && m_pMFVDC)) { - ToggleD3DFullscreen(true); - } else { - ToggleFullscreen(true, true); - } -} - -void CMainFrame::OnViewFullscreenSecondary() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (IsD3DFullScreenMode() || (s.IsD3DFullscreen() && !m_fFullScreen && !m_fAudioOnly && m_pD3DFSC && m_pMFVDC)) { - ToggleD3DFullscreen(false); - } else { - ToggleFullscreen(true, false); - } -} - -void CMainFrame::OnUpdateViewFullscreen(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED || m_fFullScreen); - pCmdUI->SetCheck(m_fFullScreen); -} - -void CMainFrame::OnViewZoom(UINT nID) -{ - double scale = (nID == ID_VIEW_ZOOM_25) ? 0.25 : (nID == ID_VIEW_ZOOM_50) ? 0.5 : (nID == ID_VIEW_ZOOM_200) ? 2.0 : 1.0; - - ZoomVideoWindow(scale); - - CString strODSMessage; - strODSMessage.Format(IDS_OSD_ZOOM, scale * 100); - m_OSD.DisplayMessage(OSD_TOPLEFT, strODSMessage, 3000); -} - -void CMainFrame::OnUpdateViewZoom(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly); -} - -void CMainFrame::OnViewZoomAutoFit() -{ - ZoomVideoWindow(ZOOM_AUTOFIT); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_ZOOM_AUTO), 3000); -} - -void CMainFrame::OnViewZoomAutoFitLarger() -{ - ZoomVideoWindow(ZOOM_AUTOFIT_LARGER); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_ZOOM_AUTO_LARGER), 3000); -} - -void CMainFrame::OnViewModifySize(UINT nID) { - if (m_fFullScreen || !m_pVideoWnd || IsZoomed() || IsIconic() || GetLoadState() != MLS::LOADED) { - return; - } - - enum resizeMethod { - autoChoose - , byHeight - , byWidth - } usedMethod; - - const CAppSettings& s = AfxGetAppSettings(); - MINMAXINFO mmi; - CSize videoSize = GetVideoOrArtSize(mmi); - int minWidth = (int)mmi.ptMinTrackSize.x; - - int mult = (nID == ID_VIEW_ZOOM_ADD ? 1 : ID_VIEW_ZOOM_SUB ? -1 : 0); - - double videoRatio = double(videoSize.cy) / double(videoSize.cx); - - CRect videoRect, workRect, maxRect; - videoRect = m_pVideoWnd->GetVideoRect(); - double videoRectRatio = double(videoRect.Height()) / double(videoRect.Width()); - bool previouslyProportional = IsNearlyEqual(videoRectRatio, videoRatio, 0.01); - - GetWorkAreaRect(workRect); - maxRect = GetZoomWindowRect(CSize(INT_MAX, INT_MAX), true); - - CRect rect, zoomRect; - GetWindowRect(&rect); - CSize targetSize; - - auto calculateZoomWindowRect = [&](resizeMethod useMethod = autoChoose, CSize forceDimension = {0,0}) { - int newWidth = videoRect.Width(); - int newHeight = videoRect.Height(); - - if (useMethod == autoChoose) { - if (double(videoRect.Height()) / videoRect.Width() + 0.01f < videoRatio) { //wider than aspect ratio, so use height instead - useMethod = byHeight; - int growPixels = int(.02f * workRect.Height()); - newHeight = videoRect.Height() + growPixels * mult; - } else { - useMethod = byWidth; - int growPixels = int(.02f * workRect.Width()); - newWidth = std::max(videoRect.Width() + growPixels * mult, minWidth); - } - } else if (useMethod == byHeight) { - newHeight = forceDimension.cy + videoRect.Height() - rect.Height(); - } else { - newWidth = forceDimension.cx + videoRect.Width() - rect.Width(); - } - - if (useMethod == byHeight) { - double newRatio = double(newHeight) / double(videoRect.Width()); - if (s.fLimitWindowProportions || previouslyProportional || SGN(newRatio - videoRatio) != SGN(videoRectRatio - videoRatio)) { - newWidth = std::max(int(ceil(newHeight / videoRatio)), minWidth); - if (mult == 1) { - newWidth = std::max(newWidth, videoRect.Width()); - } - } - } else { - double newRatio = double(videoRect.Height()) / double(newWidth); - if (s.fLimitWindowProportions || previouslyProportional || SGN(newRatio - videoRatio) != SGN(videoRectRatio - videoRatio)) { - newHeight = int(ceil(newWidth * videoRatio)); - if (mult == 1) { - newHeight = std::max(newHeight, videoRect.Height()); - } - } - } - targetSize = rect.Size() + CSize(newWidth - videoRect.Width(), newHeight - videoRect.Height()); - usedMethod = useMethod; - return GetZoomWindowRect(targetSize, true); - }; - - zoomRect = calculateZoomWindowRect(); - - CRect newRect, work; - newRect = CRect(rect.TopLeft(), targetSize); //this will be our default - - //if old rect was constrained to a single monitor, we zoom incrementally - if (GetWorkAreaRect(work) && work.PtInRect(rect.TopLeft()) && work.PtInRect(rect.BottomRight()-CSize(1,1)) - && ((zoomRect.Height() != rect.Height() && usedMethod == byHeight) || (zoomRect.Width() != rect.Width() && usedMethod == byWidth))) { - - if (zoomRect.Width() != targetSize.cx && zoomRect.Width() == maxRect.Width()) { //we appear to have been constrained by Screen Width - if (maxRect.Width() != rect.Width()) { //if it wasn't already filling the monitor horizonally, we will do that now - newRect = calculateZoomWindowRect(byWidth, maxRect.Size()); - } - } else if (zoomRect.Height() != targetSize.cy && zoomRect.Height() == maxRect.Height()) { //we appear to have been constrained by Screen Height - if (maxRect.Height() != rect.Height()) { //if it wasn't already filling the monitor vertically, we will do that now - newRect = calculateZoomWindowRect(byHeight, maxRect.Size()); - } - } else { - newRect = zoomRect; - } - } - - MoveWindow(newRect); -} - -void CMainFrame::OnViewDefaultVideoFrame(UINT nID) -{ - AfxGetAppSettings().iDefaultVideoSize = nID - ID_VIEW_VF_HALF; - m_ZoomX = m_ZoomY = 1; - m_PosX = m_PosY = 0.5; - MoveVideoWindow(); -} - -void CMainFrame::OnUpdateViewDefaultVideoFrame(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && s.iDSVideoRendererType != VIDRNDT_DS_EVR); - - int dvs = pCmdUI->m_nID - ID_VIEW_VF_HALF; - if (s.iDefaultVideoSize == dvs && pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, pCmdUI->m_nID, MF_BYCOMMAND); - } -} - -void CMainFrame::OnViewSwitchVideoFrame() -{ - CAppSettings& s = AfxGetAppSettings(); - - int vs = s.iDefaultVideoSize; - if (vs <= DVS_DOUBLE || vs == DVS_FROMOUTSIDE) { - vs = DVS_STRETCH; - } else if (vs == DVS_FROMINSIDE) { - vs = DVS_ZOOM1; - } else if (vs == DVS_ZOOM2) { - vs = DVS_FROMOUTSIDE; - } else { - vs++; - } - switch (vs) { // TODO: Read messages from resource file - case DVS_STRETCH: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_STRETCH_TO_WINDOW)); - break; - case DVS_FROMINSIDE: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_TOUCH_WINDOW_FROM_INSIDE)); - break; - case DVS_ZOOM1: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_ZOOM1)); - break; - case DVS_ZOOM2: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_ZOOM2)); - break; - case DVS_FROMOUTSIDE: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_TOUCH_WINDOW_FROM_OUTSIDE)); - break; - } - s.iDefaultVideoSize = vs; - m_ZoomX = m_ZoomY = 1; - m_PosX = m_PosY = 0.5; - MoveVideoWindow(); -} - -void CMainFrame::OnViewCompMonDeskARDiff() -{ - CAppSettings& s = AfxGetAppSettings(); - - s.fCompMonDeskARDiff = !s.fCompMonDeskARDiff; - OnVideoSizeChanged(); -} - -void CMainFrame::OnUpdateViewCompMonDeskARDiff(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - - pCmdUI->Enable(GetLoadState() == MLS::LOADED - && !m_fAudioOnly - && s.iDSVideoRendererType != VIDRNDT_DS_EVR - // This doesn't work with madVR due to the fact that it positions video itself. - // And it has exactly the same option built in. - && s.iDSVideoRendererType != VIDRNDT_DS_MADVR); - pCmdUI->SetCheck(s.fCompMonDeskARDiff); -} - -void CMainFrame::OnViewPanNScan(UINT nID) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - int x = 0, y = 0; - int dx = 0, dy = 0; - - switch (nID) { - case ID_VIEW_RESET: - // Subtitle overrides - ResetSubtitlePosAndSize(true); - // Pan&Scan - m_ZoomX = m_ZoomY = 1.0; - m_PosX = m_PosY = 0.5; - m_AngleX = m_AngleY = m_AngleZ = 0; - PerformFlipRotate(); - break; - case ID_VIEW_INCSIZE: - x = y = 1; - break; - case ID_VIEW_DECSIZE: - x = y = -1; - break; - case ID_VIEW_INCWIDTH: - x = 1; - break; - case ID_VIEW_DECWIDTH: - x = -1; - break; - case ID_VIEW_INCHEIGHT: - y = 1; - break; - case ID_VIEW_DECHEIGHT: - y = -1; - break; - case ID_PANSCAN_CENTER: - m_PosX = m_PosY = 0.5; - break; - case ID_PANSCAN_MOVELEFT: - dx = -1; - break; - case ID_PANSCAN_MOVERIGHT: - dx = 1; - break; - case ID_PANSCAN_MOVEUP: - dy = -1; - break; - case ID_PANSCAN_MOVEDOWN: - dy = 1; - break; - case ID_PANSCAN_MOVEUPLEFT: - dx = dy = -1; - break; - case ID_PANSCAN_MOVEUPRIGHT: - dx = 1; - dy = -1; - break; - case ID_PANSCAN_MOVEDOWNLEFT: - dx = -1; - dy = 1; - break; - case ID_PANSCAN_MOVEDOWNRIGHT: - dx = dy = 1; - break; - default: - break; - } - - if (x > 0 && m_ZoomX < 5.0) { - m_ZoomX = std::min(m_ZoomX * 1.02, 5.0); - } else if (x < 0 && m_ZoomX > 0.2) { - m_ZoomX = std::max(m_ZoomX / 1.02, 0.2); - } - - if (y > 0 && m_ZoomY < 5.0) { - m_ZoomY = std::min(m_ZoomY * 1.02, 5.0); - } else if (y < 0 && m_ZoomY > 0.2) { - m_ZoomY = std::max(m_ZoomY / 1.02, 0.2); - } - - if (dx < 0 && m_PosX > -0.5) { - m_PosX = std::max(m_PosX - 0.005 * m_ZoomX, -0.5); - } else if (dx > 0 && m_PosX < 1.5) { - m_PosX = std::min(m_PosX + 0.005 * m_ZoomX, 1.5); - } - - if (dy < 0 && m_PosY > -0.5) { - m_PosY = std::max(m_PosY - 0.005 * m_ZoomY, -0.5); - } else if (dy > 0 && m_PosY < 1.5) { - m_PosY = std::min(m_PosY + 0.005 * m_ZoomY, 1.5); - } - - MoveVideoWindow(true); -} - -void CMainFrame::OnUpdateViewPanNScan(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && AfxGetAppSettings().iDSVideoRendererType != VIDRNDT_DS_EVR); -} - -void CMainFrame::ApplyPanNScanPresetString() -{ - auto& s = AfxGetAppSettings(); - - if (s.strPnSPreset.IsEmpty()) - return; - - if (s.strPnSPreset.Find(',') != -1) { // try to set raw values - if (_stscanf_s(s.strPnSPreset, _T("%lf,%lf,%lf,%lf"), &m_PosX, &m_PosY, &m_ZoomX, &m_ZoomY) == 4) { - ValidatePanNScanParameters(); - MoveVideoWindow(); - } - } else { // try to set named preset - for (int i = 0; i < s.m_pnspresets.GetCount(); i++) { - int j = 0; - CString str = s.m_pnspresets[i]; - CString label = str.Tokenize(_T(","), j); - if (s.strPnSPreset == label) { - OnViewPanNScanPresets(i + ID_PANNSCAN_PRESETS_START); - } - } - } - - s.strPnSPreset.Empty(); -} - -void CMainFrame::OnViewPanNScanPresets(UINT nID) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - - nID -= ID_PANNSCAN_PRESETS_START; - - if ((INT_PTR)nID == s.m_pnspresets.GetCount()) { - CPnSPresetsDlg dlg; - dlg.m_pnspresets.Copy(s.m_pnspresets); - if (dlg.DoModal() == IDOK) { - s.m_pnspresets.Copy(dlg.m_pnspresets); - s.SaveSettings(); - } - return; - } - - m_PosX = 0.5; - m_PosY = 0.5; - m_ZoomX = 1.0; - m_ZoomY = 1.0; - - CString str = s.m_pnspresets[nID]; - - int i = 0, j = 0; - for (CString token = str.Tokenize(_T(","), i); !token.IsEmpty(); token = str.Tokenize(_T(","), i), j++) { - float f = 0; - if (_stscanf_s(token, _T("%f"), &f) != 1) { - continue; - } - - switch (j) { - case 0: - break; - case 1: - m_PosX = f; - break; - case 2: - m_PosY = f; - break; - case 3: - m_ZoomX = f; - break; - case 4: - m_ZoomY = f; - break; - default: - break; - } - } - - if (j != 5) { - return; - } - - ValidatePanNScanParameters(); - - MoveVideoWindow(true); -} - -void CMainFrame::ValidatePanNScanParameters() -{ - m_PosX = std::min(std::max(m_PosX, -0.5), 1.5); - m_PosY = std::min(std::max(m_PosY, -0.5), 1.5); - m_ZoomX = std::min(std::max(m_ZoomX, 0.2), 5.0); - m_ZoomY = std::min(std::max(m_ZoomY, 0.2), 5.0); -} - -void CMainFrame::OnUpdateViewPanNScanPresets(CCmdUI* pCmdUI) -{ - int nID = pCmdUI->m_nID - ID_PANNSCAN_PRESETS_START; - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && nID >= 0 && nID <= s.m_pnspresets.GetCount() && s.iDSVideoRendererType != VIDRNDT_DS_EVR); -} - -int nearest90(int angle) { - return int(float(angle) / 90 + 0.5) * 90; -} - -bool CMainFrame::PerformFlipRotate() -{ - HRESULT hr = E_NOTIMPL; - // Note: m_AngleZ is counterclockwise, so value 270 means rotated 90 degrees clockwise - if (m_pCAP3) { - bool isFlip = m_AngleX == 180; - bool isMirror = m_AngleY == 180; - int rotation = (360 - m_AngleZ + m_iDefRotation) % 360; - if (m_pMVRS) { - // MadVR: does not support mirror, instead of flip we rotate 180 degrees - hr = m_pCAP3->SetRotation(isFlip ? (rotation + 180) % 360 : rotation); - } else { - // MPCVR: instead of flip, we mirror plus rotate 180 degrees - hr = m_pCAP3->SetRotation(isFlip ? (rotation + 180) % 360 : rotation); - if (SUCCEEDED(hr)) { - // SetFlip actually mirrors instead of doing vertical flip - hr = m_pCAP3->SetFlip(isFlip || isMirror); - } - } - } else if (m_pCAP) { - // EVR-CP behavior for custom angles is ignored when choosing video size and zoom - // We get better results if we treat the closest 90 as the standard rotation, and custom rotate the remainder (<45deg) - int z = m_AngleZ; - if (m_pCAP2) { - int nZ = nearest90(z); - z = (z - nZ + 360) % 360; - Vector defAngle = Vector(0, 0, Vector::DegToRad((nZ - m_iDefRotation + 360) % 360)); - m_pCAP2->SetDefaultVideoAngle(defAngle); - } - - hr = m_pCAP->SetVideoAngle(Vector(Vector::DegToRad(m_AngleX), Vector::DegToRad(m_AngleY), Vector::DegToRad(z))); - } - - if (FAILED(hr)) { - m_AngleX = m_AngleY = m_AngleZ = 0; - return false; - } - if (m_pCAP2_preview) { //we support rotating preview - PreviewWindowHide(); - m_wndPreView.SetWindowSize(); - SetPreviewVideoPosition(); - //adipose: using defaultvideoangle instead of videoangle, as some oddity with AR shows up when using normal rotate with EVRCP. - //Since we only need to support 4 angles, this will work, but it *should* work with SetVideoAngle... - - hr = m_pCAP2_preview->SetDefaultVideoAngle(Vector(Vector::DegToRad(nearest90(m_AngleX)), Vector::DegToRad(nearest90(m_AngleY)), Vector::DegToRad(defaultVideoAngle + nearest90(m_AngleZ)))); - } - - return true; -} - -void CMainFrame::OnViewRotate(UINT nID) -{ - switch (nID) { - case ID_PANSCAN_ROTATEXP: - if (!m_pCAP3) { - m_AngleX += 2; - break; - } - [[fallthrough]]; // fall through for m_pCAP3 - case ID_PANSCAN_ROTATEXM: - if (m_AngleX >= 180) { - m_AngleX = 0; - } else { - m_AngleX = 180; - } - break; - case ID_PANSCAN_ROTATEYP: - if (!m_pCAP3) { - m_AngleY += 2; - break; - } - [[fallthrough]]; - case ID_PANSCAN_ROTATEYM: - if (m_AngleY >= 180) { - m_AngleY = 0; - } else { - m_AngleY = 180; - } - break; - case ID_PANSCAN_ROTATEZM: - if (m_AngleZ == 0 || m_AngleZ > 270) { - m_AngleZ = 270; - } else if (m_AngleZ > 180) { - m_AngleZ = 180; - } else if (m_AngleZ > 90) { - m_AngleZ = 90; - } else if (m_AngleZ > 0) { - m_AngleZ = 0; - } - break; - case ID_PANSCAN_ROTATEZP: - if (!m_pCAP3) { - m_AngleZ += 2; - break; - } - [[fallthrough]]; - case ID_PANSCAN_ROTATEZ270: - if (m_AngleZ < 90) { - m_AngleZ = 90; - } else if (m_AngleZ >= 270) { - m_AngleZ = 0; - } else if (m_AngleZ >= 180) { - m_AngleZ = 270; - } else if (m_AngleZ >= 90) { - m_AngleZ = 180; - } - break; - default: - return; - } - - m_AngleX %= 360; - m_AngleY %= 360; - if (m_AngleX == 180 && m_AngleY == 180) { - m_AngleX = m_AngleY = 0; - m_AngleZ += 180; - } - m_AngleZ %= 360; - - ASSERT(m_AngleX >= 0); - ASSERT(m_AngleY >= 0); - ASSERT(m_AngleZ >= 0); - - if (PerformFlipRotate()) { - // FIXME: do proper resizing of the window after rotate - if (!m_pMVRC) { - MoveVideoWindow(); - } - - CString info; - info.Format(_T("x: %d, y: %d, z: %d"), m_AngleX, m_AngleY, m_AngleZ); - SendStatusMessage(info, 3000); - } -} - -void CMainFrame::OnUpdateViewRotate(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (m_pCAP || m_pCAP3)); -} - -// FIXME -const static SIZE s_ar[] = {{0, 0}, {4, 3}, {5, 4}, {16, 9}, {235, 100}, {185, 100}}; - -void CMainFrame::OnViewAspectRatio(UINT nID) -{ - auto& s = AfxGetAppSettings(); - - CString info; - if (nID == ID_ASPECTRATIO_SAR) { - s.fKeepAspectRatio = false; - info.LoadString(IDS_ASPECT_RATIO_SAR); - } else { - s.fKeepAspectRatio = true; - CSize ar = s_ar[nID - ID_ASPECTRATIO_START]; - s.SetAspectRatioOverride(ar); - if (ar.cx && ar.cy) { - info.Format(IDS_MAINFRM_68, ar.cx, ar.cy); - } else { - info.LoadString(IDS_MAINFRM_69); - } - } - - SendStatusMessage(info, 3000); - m_OSD.DisplayMessage(OSD_TOPLEFT, info, 3000); - - OnVideoSizeChanged(); -} - -void CMainFrame::OnUpdateViewAspectRatio(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - - bool bSelected; - if (pCmdUI->m_nID == ID_ASPECTRATIO_SAR) { - bSelected = s.fKeepAspectRatio == false; - } else { - bSelected = s.fKeepAspectRatio == true && s.GetAspectRatioOverride() == s_ar[pCmdUI->m_nID - ID_ASPECTRATIO_START]; - } - if (bSelected && pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, pCmdUI->m_nID, MF_BYCOMMAND); - } - - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && s.iDSVideoRendererType != VIDRNDT_DS_EVR); -} - -void CMainFrame::OnViewAspectRatioNext() -{ - static_assert(ID_ASPECTRATIO_SAR - ID_ASPECTRATIO_START == _countof(s_ar) && ID_ASPECTRATIO_SAR == ID_ASPECTRATIO_END, - "ID_ASPECTRATIO_SAR needs to be last item in the menu."); - - const auto& s = AfxGetAppSettings(); - UINT nID = ID_ASPECTRATIO_START; - if (s.fKeepAspectRatio) { - const CSize ar = s.GetAspectRatioOverride(); - for (int i = 0; i < _countof(s_ar); i++) { - if (ar == s_ar[i]) { - nID += (i + 1) % ((ID_ASPECTRATIO_END - ID_ASPECTRATIO_START) + 1); - break; - } - } - } - - OnViewAspectRatio(nID); -} - -void CMainFrame::OnViewOntop(UINT nID) -{ - nID -= ID_ONTOP_DEFAULT; - if (AfxGetAppSettings().iOnTop == (int)nID) { - nID = !nID; - } - SetAlwaysOnTop(nID); -} - -void CMainFrame::OnUpdateViewOntop(CCmdUI* pCmdUI) -{ - int onTop = pCmdUI->m_nID - ID_ONTOP_DEFAULT; - if (AfxGetAppSettings().iOnTop == onTop && pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, pCmdUI->m_nID, MF_BYCOMMAND); - } -} - -void CMainFrame::OnViewOptions() -{ - ShowOptions(); -} - -// play - -void CMainFrame::OnPlayPlay() -{ - const CAppSettings& s = AfxGetAppSettings(); - - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); - m_bOpeningInAutochangedMonitorMode = false; - m_bPausedForAutochangeMonitorMode = false; - - if (GetLoadState() == MLS::CLOSED) { - m_bFirstPlay = false; - OpenCurPlaylistItem(); - return; - } - - if (GetLoadState() == MLS::LOADING) { - return; - } - - if (GetLoadState() == MLS::LOADED) { - // If playback was previously stopped or ended, we need to reset the window size - bool bVideoWndNeedReset = GetMediaState() == State_Stopped || m_fEndOfStream; - - KillTimersStop(); - - if (GetPlaybackMode() == PM_FILE) { - if (m_fEndOfStream) { - SendMessage(WM_COMMAND, ID_PLAY_STOP); - } else { - if (!m_fAudioOnly && m_dwLastPause && m_wndSeekBar.HasDuration() && s.iReloadAfterLongPause >= 0) { - // after long pause or hibernation, reload video file to avoid playback issues on some systems (with buggy drivers) - // in case of hibernate, m_dwLastPause equals 1 - if (m_dwLastPause == 1 || s.iReloadAfterLongPause > 0 && (GetTickCount64() - m_dwLastPause >= s.iReloadAfterLongPause * 60 * 1000)) { - m_dwReloadPos = m_wndSeekBar.GetPos(); - reloadABRepeat = abRepeat; - m_iReloadAudioIdx = GetCurrentAudioTrackIdx(); - m_iReloadSubIdx = GetCurrentSubtitleTrackIdx(); - OnFileReopen(); - return; - } - } - } - if (m_pMS) { - if (FAILED(m_pMS->SetRate(m_dSpeedRate))) { - m_dSpeedRate = 1.0; - } - } - } else if (GetPlaybackMode() == PM_DVD) { - m_dSpeedRate = 1.0; - m_pDVDC->PlayForwards(m_dSpeedRate, DVD_CMD_FLAG_Block, nullptr); - m_pDVDC->Pause(FALSE); - } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - MediaControlStop(); // audio preview won't be in sync if we run it from paused state - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - bVideoWndNeedReset = false; // SetChannel deals with MoveVideoWindow - SetChannel(s.nDVBLastChannel); - } else { - ASSERT(FALSE); - } - } else { - ASSERT(FALSE); - } - - if (bVideoWndNeedReset) { - MoveVideoWindow(false, true); - } - - if (m_fFrameSteppingActive) { - m_pFS->CancelStep(); - m_fFrameSteppingActive = false; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } else { - if (m_pBA) { - m_pBA->put_Volume(m_wndToolBar.Volume); - } - } - m_nStepForwardCount = 0; - - // Restart playback - MediaControlRun(); - - SetAlwaysOnTop(s.iOnTop); - - SetTimersPlay(); - } - - m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_PLAYING), 3000); - SetPlayState(PS_PLAY); - - OnTimer(TIMER_STREAMPOSPOLLER); - - SetupEVRColorControl(); // can be configured when streaming begins - - if (m_OSD.CanShowMessage()) { - CString strOSD; - CString strPlay(StrRes(ID_PLAY_PLAY)); - int i = strPlay.Find(_T("\n")); - if (i > 0) { - strPlay.Delete(i, strPlay.GetLength() - i); - } - - if (m_bFirstPlay) { - if (GetPlaybackMode() == PM_FILE) { - if (!m_LastOpenBDPath.IsEmpty()) { - strOSD.LoadString(IDS_PLAY_BD); - } else { - strOSD = GetFileName(); - CPlaylistItem pli; - if (!strOSD.IsEmpty() && (!m_wndPlaylistBar.GetCur(pli) || !pli.m_bYoutubeDL)) { - strOSD.TrimRight('/'); - strOSD.Replace('\\', '/'); - strOSD = strOSD.Mid(strOSD.ReverseFind('/') + 1); - } - } - } else if (GetPlaybackMode() == PM_DVD) { - strOSD.LoadString(IDS_PLAY_DVD); - } - } - - if (strOSD.IsEmpty()) { - strOSD = strPlay; - } - if (GetPlaybackMode() != PM_DIGITAL_CAPTURE) { - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - } - } - - m_bFirstPlay = false; -} - -void CMainFrame::OnPlayPause() -{ - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); - m_bOpeningInAutochangedMonitorMode = false; - - if (GetLoadState() == MLS::LOADED && GetMediaState() == State_Stopped) { - MoveVideoWindow(false, true); - } - - if (GetLoadState() == MLS::LOADED) { - if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD || GetPlaybackMode() == PM_ANALOG_CAPTURE) { - if (m_fFrameSteppingActive) { - m_pFS->CancelStep(); - m_fFrameSteppingActive = false; - m_nStepForwardCount = 0; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } - MediaControlPause(true); - } else { - ASSERT(FALSE); - } - - KillTimer(TIMER_STATS); - SetAlwaysOnTop(AfxGetAppSettings().iOnTop); - } - - CString strOSD(StrRes(ID_PLAY_PAUSE)); - int i = strOSD.Find(_T("\n")); - if (i > 0) { - strOSD.Delete(i, strOSD.GetLength() - i); - } - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_PAUSED), 3000); - SetPlayState(PS_PAUSE); -} - -void CMainFrame::OnPlayPlaypause() -{ - if (GetLoadState() == MLS::LOADED) { - OAFilterState fs = GetMediaState(); - if (fs == State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } else if (fs == State_Stopped || fs == State_Paused) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - } else if (GetLoadState() == MLS::CLOSED && !IsPlaylistEmpty()) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } -} - -void CMainFrame::OnApiPause() -{ - OAFilterState fs = GetMediaState(); - if (fs == State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } -} -void CMainFrame::OnApiPlay() -{ - OAFilterState fs = GetMediaState(); - if (fs == State_Stopped || fs == State_Paused) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } -} - -void CMainFrame::OnPlayStop() -{ - OnPlayStop(false); -} - -void CMainFrame::OnPlayStop(bool is_closing) -{ - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); - m_bOpeningInAutochangedMonitorMode = false; - m_bPausedForAutochangeMonitorMode = false; - - KillTimersStop(); - - m_wndSeekBar.SetPos(0); - if (GetLoadState() == MLS::LOADED) { - if (GetPlaybackMode() == PM_FILE) { - if (!is_closing) { - LONGLONG pos = 0; - m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - MediaControlStop(true); - if (m_bUseSeekPreview) { - MediaControlStopPreview(); - } - - if (m_pAMNS && m_pFSF) { - // After pause or stop the netshow url source filter won't continue - // on the next play command, unless we cheat it by setting the file name again. - WCHAR* pFN = nullptr; - AM_MEDIA_TYPE mt; - if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { - m_pFSF->Load(pFN, nullptr); - CoTaskMemFree(pFN); - } - } - } else if (GetPlaybackMode() == PM_DVD) { - m_pDVDC->SetOption(DVD_ResetOnStop, TRUE); - MediaControlStop(true); - m_pDVDC->SetOption(DVD_ResetOnStop, FALSE); - - if (m_bUseSeekPreview && m_pDVDC_preview) { - m_pDVDC_preview->SetOption(DVD_ResetOnStop, TRUE); - MediaControlStopPreview(); - m_pDVDC_preview->SetOption(DVD_ResetOnStop, FALSE); - } - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - MediaControlStop(true); - m_pDVBState->bActive = false; - OpenSetupWindowTitle(); - m_wndStatusBar.SetStatusTimer(StrRes(IDS_CAPTURE_LIVE)); - } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - MediaControlStop(true); - } - - m_dSpeedRate = 1.0; - - if (m_fFrameSteppingActive) { - m_pFS->CancelStep(); - m_fFrameSteppingActive = false; - m_nStepForwardCount = 0; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } - m_nStepForwardCount = 0; - } else if (GetLoadState() == MLS::CLOSING) { - MediaControlStop(true); - } - - m_nLoops = 0; - - if (m_hWnd) { - MoveVideoWindow(); - - if (!is_closing && GetLoadState() == MLS::LOADED) { - __int64 start, stop; - m_wndSeekBar.GetRange(start, stop); - if (!IsPlaybackCaptureMode()) { - m_wndStatusBar.SetStatusTimer(m_wndSeekBar.GetPos(), stop, IsSubresyncBarVisible(), GetTimeFormat()); - } - - SetAlwaysOnTop(AfxGetAppSettings().iOnTop); - } - } - - if (!is_closing && !m_fEndOfStream && GetLoadState() == MLS::LOADED) { - CString strOSD(StrRes(ID_PLAY_STOP)); - int i = strOSD.Find(_T("\n")); - if (i > 0) { - strOSD.Delete(i, strOSD.GetLength() - i); - } - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_STOPPED), 3000); - } else { - m_fEndOfStream = false; - } - - SetPlayState(PS_STOP); -} - -void CMainFrame::OnUpdatePlayPauseStop(CCmdUI* pCmdUI) -{ - bool fEnable = false; - bool fCheck = false; - - if (GetLoadState() == MLS::LOADED) { - OAFilterState fs = m_fFrameSteppingActive ? State_Paused : GetMediaState(); - - fCheck = pCmdUI->m_nID == ID_PLAY_PLAY && fs == State_Running || - pCmdUI->m_nID == ID_PLAY_PAUSE && fs == State_Paused || - pCmdUI->m_nID == ID_PLAY_STOP && fs == State_Stopped || - pCmdUI->m_nID == ID_PLAY_PLAYPAUSE && (fs == State_Paused || fs == State_Running); - - if (fs >= 0) { - if (GetPlaybackMode() == PM_FILE || IsPlaybackCaptureMode()) { - fEnable = true; - - if (m_fCapturing) { - fEnable = false; - } else if (m_fLiveWM && pCmdUI->m_nID == ID_PLAY_PAUSE) { - fEnable = false; - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE && pCmdUI->m_nID == ID_PLAY_PAUSE) { - fEnable = false; // Disable pause for digital capture mode to avoid accidental playback stop. We don't support time shifting yet. - } - } else if (GetPlaybackMode() == PM_DVD) { - fEnable = m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu - && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu; - - if (fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE) { - fEnable = false; - } - } - } - } else if (GetLoadState() == MLS::CLOSED) { - fEnable = (pCmdUI->m_nID == ID_PLAY_PLAY || pCmdUI->m_nID == ID_PLAY_PLAYPAUSE) && !IsPlaylistEmpty(); - } - - pCmdUI->SetCheck(fCheck); - pCmdUI->Enable(fEnable); -} - -void CMainFrame::OnPlayFramestep(UINT nID) -{ - if (!m_pFS && !m_pMS) { - return; - } - - KillTimerDelayedSeek(); - - m_OSD.EnableShowMessage(false); - - if (m_CachedFilterState == State_Paused) { - // Double check the state, because graph may have silently gone into a running state after performing a framestep - if (UpdateCachedMediaState() != State_Paused) { - MediaControlPause(true); - } - } else { - KillTimer(TIMER_STATS); - MediaControlPause(true); - } - - if (nID == ID_PLAY_FRAMESTEP && m_pFS) { - // To support framestep back, store the initial position when - // stepping forward - if (m_nStepForwardCount == 0) { - if (GetPlaybackMode() == PM_DVD) { - OnTimer(TIMER_STREAMPOSPOLLER); - m_rtStepForwardStart = m_wndSeekBar.GetPos(); - } else { - m_pMS->GetCurrentPosition(&m_rtStepForwardStart); - } - } - - if (!m_fFrameSteppingActive) { - m_fFrameSteppingActive = true; - m_nVolumeBeforeFrameStepping = m_wndToolBar.Volume; - if (m_pBA) { - m_pBA->put_Volume(-10000); - } - } - - HRESULT hr = m_pFS->Step(1, nullptr); - if (FAILED(hr)) { - TRACE(_T("Frame step failed.\n")); - m_fFrameSteppingActive = false; - m_nStepForwardCount = 0; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } - } else if (m_pMS && (m_nStepForwardCount == 0) && (S_OK == m_pMS->IsFormatSupported(&TIME_FORMAT_FRAME))) { - if (SUCCEEDED(m_pMS->SetTimeFormat(&TIME_FORMAT_FRAME))) { - REFERENCE_TIME rtCurPos; - - if (SUCCEEDED(m_pMS->GetCurrentPosition(&rtCurPos))) { - rtCurPos += (nID == ID_PLAY_FRAMESTEP) ? 1 : -1; - - m_pMS->SetPositions(&rtCurPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - m_pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME); - } - } else { // nID == ID_PLAY_FRAMESTEP_BACK - const REFERENCE_TIME rtAvgTimePerFrame = std::llround(GetAvgTimePerFrame() * 10000000LL); - REFERENCE_TIME rtCurPos = 0; - - if (m_nStepForwardCount) { // Exit of framestep forward, calculate current position - m_pFS->CancelStep(); - rtCurPos = m_rtStepForwardStart + m_nStepForwardCount * rtAvgTimePerFrame; - m_nStepForwardCount = 0; - rtCurPos -= rtAvgTimePerFrame; - } else if (GetPlaybackMode() == PM_DVD) { - // IMediaSeeking doesn't work properly with DVD Navigator - // Unfortunately, IDvdInfo2::GetCurrentLocation is inaccurate as well and only updates position approx. once per 500ms - // Due to inaccurate start position value, framestep backwards simply doesn't work well with DVDs. - // Seeking has same accuracy problem. Best we can do is jump back 500ms to at least get to a different frame. - OnTimer(TIMER_STREAMPOSPOLLER); - rtCurPos = m_wndSeekBar.GetPos(); - rtCurPos -= 5000000LL; - } else { - m_pMS->GetCurrentPosition(&rtCurPos); - rtCurPos -= rtAvgTimePerFrame; - } - - DoSeekTo(rtCurPos, false); - } - m_OSD.EnableShowMessage(); -} - -void CMainFrame::OnUpdatePlayFramestep(CCmdUI* pCmdUI) -{ - bool fEnable = false; - - if (pCmdUI->m_nID == ID_PLAY_FRAMESTEP) { - if (!m_fAudioOnly && !m_fLiveWM && GetLoadState() == MLS::LOADED && (GetPlaybackMode() == PM_FILE || (GetPlaybackMode() == PM_DVD && m_iDVDDomain == DVD_DOMAIN_Title))) { - if (m_pFS || m_pMS && (S_OK == m_pMS->IsFormatSupported(&TIME_FORMAT_FRAME))) { - fEnable = true; - } - } - } - pCmdUI->Enable(fEnable); -} - -void CMainFrame::OnPlaySeek(UINT nID) -{ - const auto& s = AfxGetAppSettings(); - - REFERENCE_TIME rtJumpDiff = - nID == ID_PLAY_SEEKBACKWARDSMALL ? -10000i64 * s.nJumpDistS : - nID == ID_PLAY_SEEKFORWARDSMALL ? +10000i64 * s.nJumpDistS : - nID == ID_PLAY_SEEKBACKWARDMED ? -10000i64 * s.nJumpDistM : - nID == ID_PLAY_SEEKFORWARDMED ? +10000i64 * s.nJumpDistM : - nID == ID_PLAY_SEEKBACKWARDLARGE ? -10000i64 * s.nJumpDistL : - nID == ID_PLAY_SEEKFORWARDLARGE ? +10000i64 * s.nJumpDistL : - 0; - - if (rtJumpDiff == 0) { - ASSERT(FALSE); - return; - } - - if (m_fShockwaveGraph) { - // HACK: the custom graph should support frame based seeking instead - rtJumpDiff /= 10000i64 * 100; - } - - const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); - REFERENCE_TIME rtSeekTo = rtPos + rtJumpDiff; - if (rtSeekTo < 0) { - rtSeekTo = 0; - } - - if (s.bFastSeek && !m_kfs.empty()) { - REFERENCE_TIME rtMaxForwardDiff; - REFERENCE_TIME rtMaxBackwardDiff; - if (s.bAllowInaccurateFastseek && (s.nJumpDistS >= 5000 || (nID != ID_PLAY_SEEKBACKWARDSMALL) && (nID != ID_PLAY_SEEKFORWARDSMALL))) { - if (rtJumpDiff > 0) { - rtMaxForwardDiff = 200000000LL; - rtMaxBackwardDiff = rtJumpDiff / 2; - } else { - rtMaxForwardDiff = -rtJumpDiff / 2; - rtMaxBackwardDiff = 200000000LL; - } - } else { - rtMaxForwardDiff = rtMaxBackwardDiff = std::min(100000000LL, abs(rtJumpDiff) * 3 / 10); - } - rtSeekTo = GetClosestKeyFrame(rtSeekTo, rtMaxForwardDiff, rtMaxBackwardDiff); - } - - SeekTo(rtSeekTo); -} - -void CMainFrame::OnPlaySeekSet() -{ - const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); - REFERENCE_TIME rtStart, rtStop; - m_wndSeekBar.GetRange(rtStart, rtStop); - - if (abRepeat.positionA > rtStart && abRepeat.positionA < rtStop) { - rtStart = abRepeat.positionA; - } - if (rtPos != rtStart) { - SeekTo(rtStart, false); - } -} - -void CMainFrame::AdjustStreamPosPoller(bool restart) -{ - int current_value = m_iStreamPosPollerInterval; - - if (g_bExternalSubtitleTime || IsSubresyncBarVisible()) { - m_iStreamPosPollerInterval = 40; - } else { - m_iStreamPosPollerInterval = AfxGetAppSettings().nStreamPosPollerInterval; - } - - if (restart && current_value != m_iStreamPosPollerInterval) { - if (KillTimer(TIMER_STREAMPOSPOLLER)) { - SetTimer(TIMER_STREAMPOSPOLLER, m_iStreamPosPollerInterval, nullptr); - } - } -} - -void CMainFrame::SetTimersPlay() -{ - AdjustStreamPosPoller(false); - - SetTimer(TIMER_STREAMPOSPOLLER, m_iStreamPosPollerInterval, nullptr); - SetTimer(TIMER_STREAMPOSPOLLER2, 500, nullptr); - SetTimer(TIMER_STATS, 1000, nullptr); -} - -void CMainFrame::KillTimerDelayedSeek() -{ - KillTimer(TIMER_DELAYEDSEEK); - queuedSeek = { 0, 0, false }; -} - -void CMainFrame::KillTimersStop() -{ - KillTimerDelayedSeek(); - KillTimer(TIMER_STREAMPOSPOLLER2); - KillTimer(TIMER_STREAMPOSPOLLER); - KillTimer(TIMER_STATS); - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DVBINFO_UPDATE); -} - -void CMainFrame::OnPlaySeekKey(UINT nID) -{ - if (!m_kfs.empty()) { - bool bSeekingForward = (nID == ID_PLAY_SEEKKEYFORWARD); - const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); - REFERENCE_TIME rtKeyframe; - REFERENCE_TIME rtTarget; - REFERENCE_TIME rtMin; - REFERENCE_TIME rtMax; - if (bSeekingForward) { - rtMin = rtPos + 10000LL; // at least one millisecond later - rtMax = GetDur(); - rtTarget = rtMin; - } else { - rtMin = 0; - if (GetMediaState() == State_Paused) { - rtMax = rtPos - 10000LL; - } else { - rtMax = rtPos - 5000000LL; - } - rtTarget = rtMax; - } - - if (GetKeyFrame(rtTarget, rtMin, rtMax, false, rtKeyframe)) { - SeekTo(rtKeyframe); - } - } -} - -void CMainFrame::OnUpdatePlaySeek(CCmdUI* pCmdUI) -{ - bool fEnable = false; - - if (GetLoadState() == MLS::LOADED) { - fEnable = true; - if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { - fEnable = false; - } else if (IsPlaybackCaptureMode()) { - fEnable = false; - } - } - - pCmdUI->Enable(fEnable); -} - -void CMainFrame::SetPlayingRate(double rate) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - HRESULT hr = E_FAIL; - if (GetPlaybackMode() == PM_FILE) { - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - if (m_pMS) { - hr = m_pMS->SetRate(rate); - } - } else if (GetPlaybackMode() == PM_DVD) { - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - if (rate > 0) { - hr = m_pDVDC->PlayForwards(rate, DVD_CMD_FLAG_Block, nullptr); - } else { - hr = m_pDVDC->PlayBackwards(-rate, DVD_CMD_FLAG_Block, nullptr); - } - } - if (SUCCEEDED(hr)) { - m_dSpeedRate = rate; - CString strODSMessage; - strODSMessage.Format(IDS_OSD_SPEED, rate); - m_OSD.DisplayMessage(OSD_TOPRIGHT, strODSMessage); - } -} - -void CMainFrame::OnPlayChangeRate(UINT nID) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (GetPlaybackMode() == PM_FILE) { - const CAppSettings& s = AfxGetAppSettings(); - double dSpeedStep = s.nSpeedStep / 100.0; - - if (nID == ID_PLAY_INCRATE) { - if (s.nSpeedStep > 0) { - if (m_dSpeedRate <= 0.05) { - double newrate = 1.0 - (95 / s.nSpeedStep) * dSpeedStep; - SetPlayingRate(newrate > 0.05 ? newrate : newrate + dSpeedStep); - } else { - SetPlayingRate(std::max(0.05, m_dSpeedRate + dSpeedStep)); - } - } else { - SetPlayingRate(std::max(0.0625, m_dSpeedRate * 2.0)); - } - } else if (nID == ID_PLAY_DECRATE) { - if (s.nSpeedStep > 0) { - SetPlayingRate(std::max(0.05, m_dSpeedRate - dSpeedStep)); - } else { - SetPlayingRate(std::max(0.0625, m_dSpeedRate / 2.0)); - } - } else if (nID > ID_PLAY_PLAYBACKRATE_START && nID < ID_PLAY_PLAYBACKRATE_END) { - if (filePlaybackRates.count(nID) != 0) { - SetPlayingRate(filePlaybackRates[nID]); - } else if (nID == ID_PLAY_PLAYBACKRATE_FPS24 || nID == ID_PLAY_PLAYBACKRATE_FPS25) { - if (m_pCAP) { - float target = (nID == ID_PLAY_PLAYBACKRATE_FPS24 ? 24.0f : 25.0f); - SetPlayingRate(target / m_pCAP->GetFPS()); - } - } - } - } else if (GetPlaybackMode() == PM_DVD) { - if (nID == ID_PLAY_INCRATE) { - if (m_dSpeedRate > 0) { - SetPlayingRate(m_dSpeedRate * 2.0); - } else if (m_dSpeedRate >= -1) { - SetPlayingRate(1); - } else { - SetPlayingRate(m_dSpeedRate / 2.0); - } - } else if (nID == ID_PLAY_DECRATE) { - if (m_dSpeedRate < 0) { - SetPlayingRate(m_dSpeedRate * 2.0); - } else if (m_dSpeedRate <= 1) { - SetPlayingRate(-1); - } else { - SetPlayingRate(m_dSpeedRate / 2.0); - } - } else if (nID > ID_PLAY_PLAYBACKRATE_START && nID < ID_PLAY_PLAYBACKRATE_END) { - if (dvdPlaybackRates.count(nID) != 0) { - SetPlayingRate(dvdPlaybackRates[nID]); - } - } - } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - - long lChannelMin = 0, lChannelMax = 0; - m_pAMTuner->ChannelMinMax(&lChannelMin, &lChannelMax); - long lChannel = 0, lVivSub = 0, lAudSub = 0; - m_pAMTuner->get_Channel(&lChannel, &lVivSub, &lAudSub); - - long lFreqOrg = 0, lFreqNew = -1; - m_pAMTuner->get_VideoFrequency(&lFreqOrg); - - //long lSignalStrength; - do { - if (nID == ID_PLAY_DECRATE) { - lChannel--; - } else if (nID == ID_PLAY_INCRATE) { - lChannel++; - } - - //if (lChannel < lChannelMin) lChannel = lChannelMax; - //if (lChannel > lChannelMax) lChannel = lChannelMin; - - if (lChannel < lChannelMin || lChannel > lChannelMax) { - break; - } - - if (FAILED(m_pAMTuner->put_Channel(lChannel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT))) { - break; - } - - long flFoundSignal; - m_pAMTuner->AutoTune(lChannel, &flFoundSignal); - - m_pAMTuner->get_VideoFrequency(&lFreqNew); - } while (FALSE); - /*SUCCEEDED(m_pAMTuner->SignalPresent(&lSignalStrength)) - && (lSignalStrength != AMTUNER_SIGNALPRESENT || lFreqNew == lFreqOrg));*/ - } else { - ASSERT(FALSE); - } -} - -void CMainFrame::OnUpdatePlayChangeRate(CCmdUI* pCmdUI) -{ - bool fEnable = false; - - if (GetLoadState() == MLS::LOADED) { - if (pCmdUI->m_nID > ID_PLAY_PLAYBACKRATE_START && pCmdUI->m_nID < ID_PLAY_PLAYBACKRATE_END && pCmdUI->m_pMenu) { - fEnable = false; - if (GetPlaybackMode() == PM_FILE) { - if (filePlaybackRates.count(pCmdUI->m_nID) != 0) { - fEnable = true; - if (filePlaybackRates[pCmdUI->m_nID] == m_dSpeedRate) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); - } - } else if (pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS24 || pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS25) { - fEnable = true; - if (m_pCAP) { - float target = (pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS24 ? 24.0f : 25.0f); - if (target / m_pCAP->GetFPS() == m_dSpeedRate) { - bool found = false; - for (auto const& [key, rate] : filePlaybackRates) { //make sure it wasn't a standard rate already - if (rate == m_dSpeedRate) { - found = true; - } - } - if (!found) { //must have used fps, as it didn't match a standard rate - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); - } - } - } - } - } else if (GetPlaybackMode() == PM_DVD) { - if (dvdPlaybackRates.count(pCmdUI->m_nID) != 0) { - fEnable = true; - if (dvdPlaybackRates[pCmdUI->m_nID] == m_dSpeedRate) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); - } - } - } - } else { - bool fInc = pCmdUI->m_nID == ID_PLAY_INCRATE; - - fEnable = true; - if (fInc && m_dSpeedRate >= 128.0) { - fEnable = false; - } else if (!fInc && GetPlaybackMode() == PM_FILE && m_dSpeedRate <= 0.05) { - fEnable = false; - } else if (!fInc && GetPlaybackMode() == PM_DVD && m_dSpeedRate <= -128.0) { - fEnable = false; - } else if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { - fEnable = false; - } else if (m_fShockwaveGraph) { - fEnable = false; - } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE && (!m_wndCaptureBar.m_capdlg.IsTunerActive() || m_fCapturing)) { - fEnable = false; - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - fEnable = false; - } else if (m_fLiveWM) { - fEnable = false; - } - } - } - - pCmdUI->Enable(fEnable); -} - -void CMainFrame::OnPlayResetRate() -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - HRESULT hr = E_FAIL; - - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - - if (GetPlaybackMode() == PM_FILE) { - hr = m_pMS->SetRate(1.0); - } else if (GetPlaybackMode() == PM_DVD) { - hr = m_pDVDC->PlayForwards(1.0, DVD_CMD_FLAG_Block, nullptr); - } - - if (SUCCEEDED(hr)) { - m_dSpeedRate = 1.0; - - CString strODSMessage; - strODSMessage.Format(IDS_OSD_SPEED, m_dSpeedRate); - m_OSD.DisplayMessage(OSD_TOPRIGHT, strODSMessage); - } -} - -void CMainFrame::OnUpdatePlayResetRate(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED); -} - -void CMainFrame::SetAudioDelay(REFERENCE_TIME rtShift) -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - pASF->SetAudioTimeShift(rtShift); - - if (GetLoadState() == MLS::LOADED) { - CString str; - str.Format(IDS_MAINFRM_70, rtShift / 10000); - SendStatusMessage(str, 3000); - m_OSD.DisplayMessage(OSD_TOPLEFT, str); - } - } -} - -void CMainFrame::SetSubtitleDelay(int delay_ms, bool relative) -{ - if (!m_pCAP && !m_pDVS) { - if (GetLoadState() == MLS::LOADED) { - SendStatusMessage(L"Delay is not supported by current subtitle renderer", 3000); - } - return; - } - - if (m_pDVS) { - int currentDelay, speedMul, speedDiv; - if (FAILED(m_pDVS->get_SubtitleTiming(¤tDelay, &speedMul, &speedDiv))) { - return; - } - if (relative) { - delay_ms += currentDelay; - } - - VERIFY(SUCCEEDED(m_pDVS->put_SubtitleTiming(delay_ms, speedMul, speedDiv))); - } - else { - ASSERT(m_pCAP != nullptr); - if (m_pSubStreams.IsEmpty()) { - SendStatusMessage(StrRes(IDS_SUBTITLES_ERROR), 3000); - return; - } - if (relative) { - delay_ms += m_pCAP->GetSubtitleDelay(); - } - - m_pCAP->SetSubtitleDelay(delay_ms); - } - - CString strSubDelay; - strSubDelay.Format(IDS_MAINFRM_139, delay_ms); - SendStatusMessage(strSubDelay, 3000); - m_OSD.DisplayMessage(OSD_TOPLEFT, strSubDelay); -} - -void CMainFrame::OnPlayChangeAudDelay(UINT nID) -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - REFERENCE_TIME rtShift = pASF->GetAudioTimeShift(); - rtShift += - nID == ID_PLAY_INCAUDDELAY ? 100000 : - nID == ID_PLAY_DECAUDDELAY ? -100000 : - 0; - - SetAudioDelay(rtShift); - } -} - -void CMainFrame::OnUpdatePlayChangeAudDelay(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(!!m_pGB /*&& !!FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)*/); -} - -void CMainFrame::OnPlayFiltersCopyToClipboard() -{ - // Don't translate that output since it's mostly for debugging purpose - CString filtersList = _T("Filters currently loaded:\r\n"); - // Skip the first two entries since they are the "Copy to clipboard" menu entry and a separator - for (int i = 2, count = m_filtersMenu.GetMenuItemCount(); i < count; i++) { - CString filterName; - m_filtersMenu.GetMenuString(i, filterName, MF_BYPOSITION); - filtersList.AppendFormat(_T(" - %s\r\n"), filterName.GetString()); - } - - CClipboard clipboard(this); - VERIFY(clipboard.SetText(filtersList)); -} - -bool CMainFrame::FilterSettingsByClassID(CLSID clsid, CWnd* parent) -{ - for (int a = 0; a < m_pparray.GetCount(); a++) { - CComQIPtr pBF2 = m_pparray[a]; - if (pBF2) { - CLSID tclsid; - pBF2->GetClassID(&tclsid); - if (tclsid == clsid) { - FilterSettings(m_pparray[a], parent); - return true; - } - } - } - return false; -} - -void CMainFrame::FilterSettings(CComPtr pUnk, CWnd* parent) { - CComPropertySheet ps(IDS_PROPSHEET_PROPERTIES); - - CComQIPtr pBF = pUnk; - CLSID clsid = GetCLSID(pBF); - CFGFilterLAV::LAVFILTER_TYPE LAVFilterType = CFGFilterLAV::INVALID; - bool bIsInternalLAV = CFGFilterLAV::IsInternalInstance(pBF, &LAVFilterType); - - if (CComQIPtr pSPP = pUnk) { - ULONG uIgnoredPage = ULONG(-1); - // If we are dealing with an internal filter, we want to ignore the "Formats" page. - if (bIsInternalLAV) { - uIgnoredPage = (LAVFilterType != CFGFilterLAV::AUDIO_DECODER) ? 1 : 2; - } - bool bIsInternalFilter = bIsInternalLAV || clsid == CLSID_MPCVR; - ps.AddPages(pSPP, bIsInternalFilter, uIgnoredPage); - } - - HRESULT hr; - CComPtr pPP = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr); - ps.AddPage(pPP, pBF); - - if (ps.GetPageCount() > 0) { - CMPCThemeComPropertyPage::SetDialogType(clsid); - ps.DoModal(); - OpenSetupStatusBar(); - - if (bIsInternalLAV) { - if (CComQIPtr pLAVFSettings = pBF) { - CFGFilterLAVSplitterBase::Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get current settings from LAVSplitter - settings.SaveSettings(); // Save them to the registry/ini - } - } else if (CComQIPtr pLAVVideoSettings = pBF) { - CFGFilterLAVVideo::Settings settings; - if (settings.GetSettings(pLAVVideoSettings)) { // Get current settings from LAVVideo - settings.SaveSettings(); // Save them to the registry/ini - } - } else if (CComQIPtr pLAVAudioSettings = pBF) { - CFGFilterLAVAudio::Settings settings; - if (settings.GetSettings(pLAVAudioSettings)) { // Get current settings from LAVAudio - settings.SaveSettings(); // Save them to the registry/ini - } - } - } - } -} - -void CMainFrame::OnPlayFilters(UINT nID) -{ - //ShowPPage(m_spparray[nID - ID_FILTERS_SUBITEM_START], m_hWnd); - - CComPtr pUnk = m_pparray[nID - ID_FILTERS_SUBITEM_START]; - - FilterSettings(pUnk, GetModalParent()); -} - -void CMainFrame::OnUpdatePlayFilters(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(!m_fCapturing); -} - -void CMainFrame::OnPlayShadersSelect() -{ - ShowOptions(IDD_PPAGESHADERS); -} - -void CMainFrame::OnPlayShadersPresetNext() -{ - auto& s = AfxGetAppSettings(); - if (s.m_Shaders.NextPreset()) { - CString name; - if (s.m_Shaders.GetCurrentPresetName(name)) { - CString msg; - msg.Format(IDS_OSD_SHADERS_PRESET, name.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, msg); - } - } -} - -void CMainFrame::OnPlayShadersPresetPrev() -{ - auto& s = AfxGetAppSettings(); - if (s.m_Shaders.PrevPreset()) { - CString name; - if (s.m_Shaders.GetCurrentPresetName(name)) { - CString msg; - msg.Format(IDS_OSD_SHADERS_PRESET, name.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, msg); - } - } -} - -void CMainFrame::OnPlayShadersPresets(UINT nID) -{ - ASSERT((nID >= ID_SHADERS_PRESETS_START) && (nID <= ID_SHADERS_PRESETS_END)); - auto& s = AfxGetAppSettings(); - int num = (int)nID - ID_SHADERS_PRESETS_START; - auto presets = s.m_Shaders.GetPresets(); - ASSERT(num < (int)presets.size()); - for (const auto& pair : presets) { - if (num-- == 0) { - s.m_Shaders.SetCurrentPreset(pair.first); - break; - } - } -} - -int CMainFrame::UpdateSelectedAudioStreamInfo(int index, AM_MEDIA_TYPE* pmt, LCID lcid) { - int nChannels = 0; - if (index >= 0) { - m_loadedAudioTrackIndex = index; - AfxGetAppSettings().MRU.UpdateCurrentAudioTrack(index); - } - if (pmt) { - m_statusbarAudioFormat = GetShortAudioNameFromMediaType(pmt); - AppendWithDelimiter(m_statusbarAudioFormat, GetChannelStrFromMediaType(pmt, nChannels)); - } else { - m_statusbarAudioFormat.Empty(); - } - if (lcid > 0) { - GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentAudioLang); - } else { - currentAudioLang.Empty(); - } - return nChannels; -} - -int CMainFrame::GetSelectedSubtitleTrackIndex() { - int subIdx = 0; - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - CComQIPtr pSSF = subInput.pSourceFilter; - if (pSSF) { - DWORD cStreams; - if (SUCCEEDED(pSSF->Count(&cStreams))) { - for (long j = 0; j < (long)cStreams; j++) { - DWORD dwFlags, dwGroup; - if (SUCCEEDED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 2) { - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - return subIdx; - } - subIdx++; - } - } - } - } - } else { - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - return subIdx; - } else { - subIdx += subInput.pSubStream->GetStreamCount(); - } - } - } - return 0; -} - -bool CMainFrame::IsValidSubtitleStream(int i) { - if (GetSubtitleInput(i) != nullptr) { - return true; - } - - return false; -} - -// Called from GraphThread -void CMainFrame::OnPlayAudio(UINT nID) -{ - int i = (int)nID - ID_AUDIO_SUBITEM_START; - - DWORD cStreams = 0; - - if (GetPlaybackMode() == PM_DVD) { - m_pDVDC->SelectAudioStream(i, DVD_CMD_FLAG_Block, nullptr); - LCID lcid = 0; - if (SUCCEEDED(m_pDVDI->GetAudioLanguage(i, &lcid)) && lcid != 0) { - GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentAudioLang); - } else { - currentAudioLang.Empty(); - } - } else if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { - if (i == 0) { - ShowOptions(CPPageAudioSwitcher::IDD); - } else { - LONG sidx = i - 1; - if (m_iReloadAudioIdx >= 0) { - if (m_iReloadAudioIdx < cStreams) { - sidx = m_iReloadAudioIdx; - } - m_iReloadAudioIdx = -1; - } - if (sidx >= cStreams) { //invalid stream? - return; - } - if (SUCCEEDED(m_pAudioSwitcherSS->Enable(sidx, AMSTREAMSELECTENABLE_ENABLE))) { - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(m_pAudioSwitcherSS->Info(sidx, &pmt, nullptr, &lcid, nullptr, nullptr, nullptr, nullptr))) { - UpdateSelectedAudioStreamInfo(sidx, pmt, lcid); - DeleteMediaType(pmt); - } else { - UpdateSelectedAudioStreamInfo(sidx, nullptr, -1); - } - } - } - } else if (GetPlaybackMode() == PM_FILE) { - OnNavStreamSelectSubMenu(i, 1); - AfxGetAppSettings().MRU.UpdateCurrentAudioTrack(i); - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - if (CBDAChannel* pChannel = m_pDVBState->pChannel) { - OnNavStreamSelectSubMenu(i, 1); - pChannel->SetDefaultAudio(i); - } - } -} - -void CMainFrame::OnSubtitlesDefaultStyle() -{ - CAppSettings& s = AfxGetAppSettings(); - if (!m_pSubStreams.IsEmpty()) { - s.bSubtitleOverrideDefaultStyle = !s.bSubtitleOverrideDefaultStyle; - UpdateSubtitleRenderingParameters(); - RepaintVideo(); - } -} - -void CMainFrame::OnPlaySubtitles(UINT nID) -{ - CAppSettings& s = AfxGetAppSettings(); - int i = (int)nID - ID_SUBTITLES_SUBITEM_START; - - if (GetPlaybackMode() == PM_DVD) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) - && ulStreamsAvailable) { - if (i == 0) { - m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); - } else if (i <= int(ulStreamsAvailable)) { - m_pDVDC->SelectSubpictureStream(i - 1, DVD_CMD_FLAG_Block, nullptr); - m_pDVDC->SetSubpictureState(TRUE, DVD_CMD_FLAG_Block, nullptr); - } - i -= ulStreamsAvailable + 1; - } - } - - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - if (CBDAChannel* pChannel = m_pDVBState->pChannel) { - OnNavStreamSelectSubMenu(i, 2); - pChannel->SetDefaultSubtitle(i); - SetSubtitle(i); - } - } else if (!m_pSubStreams.IsEmpty()) { - // Currently the subtitles menu contains 6 items apart from the actual subtitles list when the ISR is used - i -= 6; - - if (i == -6) { - // options - ShowOptions(CPPageSubtitles::IDD); - } else if (i == -5) { - // styles - int j = 0; - SubtitleInput* pSubInput = GetSubtitleInput(j, true); - CLSID clsid; - - if (pSubInput && SUCCEEDED(pSubInput->pSubStream->GetClassID(&clsid))) { - if (clsid == __uuidof(CRenderedTextSubtitle)) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; - - CAutoPtrArray pages; - CAtlArray styles; - - POSITION pos = pRTS->m_styles.GetStartPosition(); - for (int k = 0; pos; k++) { - CString styleName; - STSStyle* style; - pRTS->m_styles.GetNextAssoc(pos, styleName, style); - - CAutoPtr page(DEBUG_NEW CPPageSubStyle(/*isStyleDialog = */ true)); - if (style->hasAnsiStyleName) { - styleName = ToUnicode(styleName, pRTS->GetCharSet(style->charSet)); - } - page->InitStyle(styleName, *style); - pages.Add(page); - styles.Add(style); - } - - CMPCThemePropertySheet dlg(IDS_SUBTITLES_STYLES_CAPTION, GetModalParent()); - for (size_t l = 0; l < pages.GetCount(); l++) { - dlg.AddPage(pages[l]); - } - - if (dlg.DoModal() == IDOK) { - { - CAutoLock cAutoLock(&m_csSubLock); - bool defaultStyleChanged = false, otherStyleChanged = false; - - for (size_t l = 0; l < pages.GetCount(); l++) { - STSStyle tmpStyle = *styles[l]; - pages[l]->GetStyle(*styles[l]); - if (pages[l]->GetStyleName() == L"Default") { - if (*styles[l] != s.subtitlesDefStyle) { - pRTS->m_bUsingPlayerDefaultStyle = false; - pRTS->SetDefaultStyle(*styles[l]); - defaultStyleChanged = true; - } - } else if (tmpStyle != *styles[l]) { - otherStyleChanged = true; - } - } - if (otherStyleChanged || defaultStyleChanged) { - if (!defaultStyleChanged) { //it will already have triggered SetStyleChanged() internally - pRTS->SetStyleChanged(); - } - pRTS->Deinit(); - InvalidateSubtitle(); - RepaintVideo(); - m_wndSubresyncBar.ReloadSubtitle(); - } - } - } - } - } - } else if (i == -4) { - // reload - ReloadSubtitle(); - } else if (i == -3) { - // hide - ToggleSubtitleOnOff(); - } else if (i == -2) { - // override default style - s.bSubtitleOverrideDefaultStyle = !s.bSubtitleOverrideDefaultStyle; - UpdateSubtitleRenderingParameters(); - RepaintVideo(); - } else if (i == -1) { - // override all styles - s.bSubtitleOverrideAllStyles = !s.bSubtitleOverrideAllStyles; - UpdateSubtitleRenderingParameters(); - RepaintVideo(); - } else if (i >= 0) { - // this is an actual item from the subtitles list - s.fEnableSubtitles = true; - SetSubtitle(i); - } - } else if (GetPlaybackMode() == PM_FILE) { - OnNavStreamSelectSubMenu(i, 2); - } -} - -void CMainFrame::OnPlayVideoStreams(UINT nID) -{ - nID -= ID_VIDEO_STREAMS_SUBITEM_START; - - if (GetPlaybackMode() == PM_FILE) { - OnNavStreamSelectSubMenu(nID, 0); - } else if (GetPlaybackMode() == PM_DVD) { - m_pDVDC->SelectAngle(nID + 1, DVD_CMD_FLAG_Block, nullptr); - - CString osdMessage; - osdMessage.Format(IDS_AG_ANGLE, nID + 1); - m_OSD.DisplayMessage(OSD_TOPLEFT, osdMessage); - } -} - -void CMainFrame::OnPlayFiltersStreams(UINT nID) -{ - nID -= ID_FILTERSTREAMS_SUBITEM_START; - CComPtr pAMSS = m_ssarray[nID]; - UINT i = nID; - - while (i > 0 && pAMSS == m_ssarray[i - 1]) { - i--; - } - - if (FAILED(pAMSS->Enable(nID - i, AMSTREAMSELECTENABLE_ENABLE))) { - MessageBeep(UINT_MAX); - } - - OpenSetupStatusBar(); -} - -void CMainFrame::OnPlayVolume(UINT nID) -{ - if (GetLoadState() == MLS::LOADED) { - CString strVolume; - m_pBA->put_Volume(m_wndToolBar.Volume); - - //strVolume.Format (L"Vol : %d dB", m_wndToolBar.Volume / 100); - if (m_wndToolBar.Volume == -10000) { - strVolume.Format(IDS_VOLUME_OSD, 0); - } else { - strVolume.Format(IDS_VOLUME_OSD, m_wndToolBar.m_volctrl.GetPos()); - } - m_OSD.DisplayMessage(OSD_TOPLEFT, strVolume); - //SendStatusMessage(strVolume, 3000); // Now the volume is displayed in three places at once. - } - - m_Lcd.SetVolume((m_wndToolBar.Volume > -10000 ? m_wndToolBar.m_volctrl.GetPos() : 1)); -} - -void CMainFrame::OnPlayVolumeBoost(UINT nID) -{ - CAppSettings& s = AfxGetAppSettings(); - - switch (nID) { - case ID_VOLUME_BOOST_INC: - s.nAudioBoost += s.nVolumeStep; - if (s.nAudioBoost > 300) { - s.nAudioBoost = 300; - } - break; - case ID_VOLUME_BOOST_DEC: - if (s.nAudioBoost > s.nVolumeStep) { - s.nAudioBoost -= s.nVolumeStep; - } else { - s.nAudioBoost = 0; - } - break; - case ID_VOLUME_BOOST_MIN: - s.nAudioBoost = 0; - break; - case ID_VOLUME_BOOST_MAX: - s.nAudioBoost = 300; - break; - } - - SetVolumeBoost(s.nAudioBoost); -} - -void CMainFrame::SetVolumeBoost(UINT nAudioBoost) -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - bool fNormalize, fNormalizeRecover; - UINT nMaxNormFactor, nBoost; - pASF->GetNormalizeBoost2(fNormalize, nMaxNormFactor, fNormalizeRecover, nBoost); - - CString strBoost; - strBoost.Format(IDS_BOOST_OSD, nAudioBoost); - pASF->SetNormalizeBoost2(fNormalize, nMaxNormFactor, fNormalizeRecover, nAudioBoost); - m_OSD.DisplayMessage(OSD_TOPLEFT, strBoost); - } -} - -void CMainFrame::OnUpdatePlayVolumeBoost(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(); -} - -void CMainFrame::OnCustomChannelMapping() -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - CAppSettings& s = AfxGetAppSettings(); - s.fCustomChannelMapping = !s.fCustomChannelMapping; - pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(s.fCustomChannelMapping ? IDS_OSD_CUSTOM_CH_MAPPING_ON : IDS_OSD_CUSTOM_CH_MAPPING_OFF)); - } -} - -void CMainFrame::OnUpdateCustomChannelMapping(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(s.fEnableAudioSwitcher); -} - -void CMainFrame::OnNormalizeRegainVolume(UINT nID) -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - CAppSettings& s = AfxGetAppSettings(); - WORD osdMessage = 0; - - switch (nID) { - case ID_NORMALIZE: - s.fAudioNormalize = !s.fAudioNormalize; - osdMessage = s.fAudioNormalize ? IDS_OSD_NORMALIZE_ON : IDS_OSD_NORMALIZE_OFF; - break; - case ID_REGAIN_VOLUME: - s.fAudioNormalizeRecover = !s.fAudioNormalizeRecover; - osdMessage = s.fAudioNormalizeRecover ? IDS_OSD_REGAIN_VOLUME_ON : IDS_OSD_REGAIN_VOLUME_OFF; - break; - } - - pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMessage)); - } -} - -void CMainFrame::OnUpdateNormalizeRegainVolume(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(s.fEnableAudioSwitcher); -} - -void CMainFrame::OnPlayColor(UINT nID) -{ - if (m_pVMRMC || m_pMFVP) { - CAppSettings& s = AfxGetAppSettings(); - //ColorRanges* crs = AfxGetMyApp()->ColorControls; - int& brightness = s.iBrightness; - int& contrast = s.iContrast; - int& hue = s.iHue; - int& saturation = s.iSaturation; - CString tmp, str; - switch (nID) { - case ID_COLOR_BRIGHTNESS_INC: - brightness += 2; - [[fallthrough]]; - case ID_COLOR_BRIGHTNESS_DEC: - brightness -= 1; - SetColorControl(ProcAmp_Brightness, brightness, contrast, hue, saturation); - tmp.Format(brightness ? _T("%+d") : _T("%d"), brightness); - str.Format(IDS_OSD_BRIGHTNESS, tmp.GetString()); - break; - case ID_COLOR_CONTRAST_INC: - contrast += 2; - [[fallthrough]]; - case ID_COLOR_CONTRAST_DEC: - contrast -= 1; - SetColorControl(ProcAmp_Contrast, brightness, contrast, hue, saturation); - tmp.Format(contrast ? _T("%+d") : _T("%d"), contrast); - str.Format(IDS_OSD_CONTRAST, tmp.GetString()); - break; - case ID_COLOR_HUE_INC: - hue += 2; - [[fallthrough]]; - case ID_COLOR_HUE_DEC: - hue -= 1; - SetColorControl(ProcAmp_Hue, brightness, contrast, hue, saturation); - tmp.Format(hue ? _T("%+d") : _T("%d"), hue); - str.Format(IDS_OSD_HUE, tmp.GetString()); - break; - case ID_COLOR_SATURATION_INC: - saturation += 2; - [[fallthrough]]; - case ID_COLOR_SATURATION_DEC: - saturation -= 1; - SetColorControl(ProcAmp_Saturation, brightness, contrast, hue, saturation); - tmp.Format(saturation ? _T("%+d") : _T("%d"), saturation); - str.Format(IDS_OSD_SATURATION, tmp.GetString()); - break; - case ID_COLOR_RESET: - brightness = AfxGetMyApp()->GetColorControl(ProcAmp_Brightness)->DefaultValue; - contrast = AfxGetMyApp()->GetColorControl(ProcAmp_Contrast)->DefaultValue; - hue = AfxGetMyApp()->GetColorControl(ProcAmp_Hue)->DefaultValue; - saturation = AfxGetMyApp()->GetColorControl(ProcAmp_Saturation)->DefaultValue; - SetColorControl(ProcAmp_All, brightness, contrast, hue, saturation); - str.LoadString(IDS_OSD_RESET_COLOR); - break; - } - m_OSD.DisplayMessage(OSD_TOPLEFT, str); - } else { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_NO_COLORCONTROL)); - } -} - -void CMainFrame::OnAfterplayback(UINT nID) -{ - CAppSettings& s = AfxGetAppSettings(); - WORD osdMsg = 0; - bool bDisable = false; - - auto toggleOption = [&](UINT64 nID) { - bDisable = !!(s.nCLSwitches & nID); - s.nCLSwitches &= ~CLSW_AFTERPLAYBACK_MASK | nID; - s.nCLSwitches ^= nID; - }; - - switch (nID) { - case ID_AFTERPLAYBACK_EXIT: - toggleOption(CLSW_CLOSE); - osdMsg = IDS_AFTERPLAYBACK_EXIT; - break; - case ID_AFTERPLAYBACK_STANDBY: - toggleOption(CLSW_STANDBY); - osdMsg = IDS_AFTERPLAYBACK_STANDBY; - break; - case ID_AFTERPLAYBACK_HIBERNATE: - toggleOption(CLSW_HIBERNATE); - osdMsg = IDS_AFTERPLAYBACK_HIBERNATE; - break; - case ID_AFTERPLAYBACK_SHUTDOWN: - toggleOption(CLSW_SHUTDOWN); - osdMsg = IDS_AFTERPLAYBACK_SHUTDOWN; - break; - case ID_AFTERPLAYBACK_LOGOFF: - toggleOption(CLSW_LOGOFF); - osdMsg = IDS_AFTERPLAYBACK_LOGOFF; - break; - case ID_AFTERPLAYBACK_LOCK: - toggleOption(CLSW_LOCK); - osdMsg = IDS_AFTERPLAYBACK_LOCK; - break; - case ID_AFTERPLAYBACK_MONITOROFF: - toggleOption(CLSW_MONITOROFF); - osdMsg = IDS_AFTERPLAYBACK_MONITOROFF; - break; - case ID_AFTERPLAYBACK_PLAYNEXT: - toggleOption(CLSW_PLAYNEXT); - osdMsg = IDS_AFTERPLAYBACK_PLAYNEXT; - break; - case ID_AFTERPLAYBACK_DONOTHING: - toggleOption(CLSW_DONOTHING); - osdMsg = IDS_AFTERPLAYBACK_DONOTHING; - break; - } - if (bDisable) { - switch (s.eAfterPlayback) { - case CAppSettings::AfterPlayback::PLAY_NEXT: - osdMsg = IDS_AFTERPLAYBACK_PLAYNEXT; - break; - case CAppSettings::AfterPlayback::REWIND: - osdMsg = IDS_AFTERPLAYBACK_REWIND; - break; - case CAppSettings::AfterPlayback::MONITOROFF: - osdMsg = IDS_AFTERPLAYBACK_MONITOROFF; - break; - case CAppSettings::AfterPlayback::CLOSE: - osdMsg = IDS_AFTERPLAYBACK_CLOSE; - break; - case CAppSettings::AfterPlayback::EXIT: - osdMsg = IDS_AFTERPLAYBACK_EXIT; - break; - default: - ASSERT(FALSE); - [[fallthrough]]; - case CAppSettings::AfterPlayback::DO_NOTHING: - osdMsg = IDS_AFTERPLAYBACK_DONOTHING; - break; - } - } - - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMsg)); -} - -void CMainFrame::OnUpdateAfterplayback(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - bool bChecked; - bool bRadio = false; - - switch (pCmdUI->m_nID) { - case ID_AFTERPLAYBACK_EXIT: - bChecked = !!(s.nCLSwitches & CLSW_CLOSE); - bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::EXIT; - break; - case ID_AFTERPLAYBACK_STANDBY: - bChecked = !!(s.nCLSwitches & CLSW_STANDBY); - break; - case ID_AFTERPLAYBACK_HIBERNATE: - bChecked = !!(s.nCLSwitches & CLSW_HIBERNATE); - break; - case ID_AFTERPLAYBACK_SHUTDOWN: - bChecked = !!(s.nCLSwitches & CLSW_SHUTDOWN); - break; - case ID_AFTERPLAYBACK_LOGOFF: - bChecked = !!(s.nCLSwitches & CLSW_LOGOFF); - break; - case ID_AFTERPLAYBACK_LOCK: - bChecked = !!(s.nCLSwitches & CLSW_LOCK); - break; - case ID_AFTERPLAYBACK_MONITOROFF: - bChecked = !!(s.nCLSwitches & CLSW_MONITOROFF); - bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::MONITOROFF; - break; - case ID_AFTERPLAYBACK_PLAYNEXT: - bChecked = !!(s.nCLSwitches & CLSW_PLAYNEXT); - bRadio = (s.eAfterPlayback == CAppSettings::AfterPlayback::PLAY_NEXT) && (m_wndPlaylistBar.GetCount() < 2); - break; - case ID_AFTERPLAYBACK_DONOTHING: - bChecked = !!(s.nCLSwitches & CLSW_DONOTHING); - bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::DO_NOTHING; - break; - default: - ASSERT(FALSE); - return; - } - - if (IsMenu(*pCmdUI->m_pMenu)) { - MENUITEMINFO mii, cii; - ZeroMemory(&cii, sizeof(MENUITEMINFO)); - cii.cbSize = sizeof(cii); - cii.fMask = MIIM_FTYPE; - pCmdUI->m_pMenu->GetMenuItemInfo(pCmdUI->m_nID, &cii); - - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_FTYPE | MIIM_STATE; - mii.fType = (bRadio ? MFT_RADIOCHECK : 0) | (cii.fType & MFT_OWNERDRAW); //preserve owner draw flag - mii.fState = (bRadio ? MFS_DISABLED : 0) | (bChecked || bRadio ? MFS_CHECKED : 0); - VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pCmdUI->m_pMenu, pCmdUI->m_nID, &mii)); - } -} - -void CMainFrame::OnPlayRepeat(UINT nID) -{ - CAppSettings& s = AfxGetAppSettings(); - WORD osdMsg = 0; - - switch (nID) { - case ID_PLAY_REPEAT_ONEFILE: - s.eLoopMode = CAppSettings::LoopMode::FILE; - osdMsg = IDS_PLAYLOOPMODE_FILE; - break; - case ID_PLAY_REPEAT_WHOLEPLAYLIST: - s.eLoopMode = CAppSettings::LoopMode::PLAYLIST; - osdMsg = IDS_PLAYLOOPMODE_PLAYLIST; - break; - default: - ASSERT(FALSE); - return; - } - - m_nLoops = 0; - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMsg)); -} - -void CMainFrame::OnUpdatePlayRepeat(CCmdUI* pCmdUI) -{ - CAppSettings::LoopMode loopmode; - - switch (pCmdUI->m_nID) { - case ID_PLAY_REPEAT_ONEFILE: - loopmode = CAppSettings::LoopMode::FILE; - break; - case ID_PLAY_REPEAT_WHOLEPLAYLIST: - loopmode = CAppSettings::LoopMode::PLAYLIST; - break; - default: - ASSERT(FALSE); - return; - } - if (AfxGetAppSettings().eLoopMode == loopmode && pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, pCmdUI->m_nID, MF_BYCOMMAND); - } -} - -void CMainFrame::OnPlayRepeatForever() -{ - CAppSettings& s = AfxGetAppSettings(); - - s.fLoopForever = !s.fLoopForever; - - m_nLoops = 0; - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(s.fLoopForever ? IDS_PLAYLOOP_FOREVER_ON : IDS_PLAYLOOP_FOREVER_OFF)); -} - -void CMainFrame::OnUpdatePlayRepeatForever(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(AfxGetAppSettings().fLoopForever); -} - -bool CMainFrame::SeekToFileChapter(int iChapter, bool bRelative /*= false*/) -{ - if (GetPlaybackMode() != PM_FILE || !m_pCB) { - return false; - } - - bool ret = false; - - if (DWORD nChapters = m_pCB->ChapGetCount()) { - REFERENCE_TIME rt; - - if (bRelative) { - if (m_pMS && SUCCEEDED(m_pMS->GetCurrentPosition(&rt))) { - if (iChapter < 0) { - // Add a small threshold to jump back at least that amount of time - // This is needed when rt is near start of current chapter - rt -= PREV_CHAP_THRESHOLD * 10000000; - iChapter = 0; - iChapter = m_pCB->ChapLookupPrevious(&rt, nullptr); - // seek to start if there is no previous chapter - if (iChapter == -1 && rt >= 0) { - REFERENCE_TIME rtStart, rtStop; - m_wndSeekBar.GetRange(rtStart, rtStop); - DoSeekTo(rtStart, false); - return true; - } - } else { - iChapter = m_pCB->ChapLookupNext(&rt, nullptr); - } - } else { - return false; - } - } - - CComBSTR name; - REFERENCE_TIME rtStart, rtStop; - m_wndSeekBar.GetRange(rtStart, rtStop); - if (iChapter >= 0 && DWORD(iChapter) < nChapters && SUCCEEDED(m_pCB->ChapGet(iChapter, &rt, &name)) && rt < rtStop) { - DoSeekTo(rt, false); - SendStatusMessage(ResStr(IDS_AG_CHAPTER2) + CString(name), 3000); - ret = true; - - REFERENCE_TIME rtDur; - if (m_pMS && SUCCEEDED(m_pMS->GetDuration(&rtDur))) { - const CAppSettings& s = AfxGetAppSettings(); - CString strOSD; - REFERENCE_TIME rtShow = rt; - if (s.fRemainingTime) { - strOSD.Append(_T("-")); - rtShow = rtDur - rt; - } - if (rtDur >= 36005000000LL) { // At least 1 hour (rounded) - strOSD.AppendFormat(_T("%s / %s "), ReftimeToString2(rtShow).GetString(), ReftimeToString2(rtDur).GetString()); - } else { - strOSD.AppendFormat(_T("%s / %s "), ReftimeToString3(rtShow).GetString(), ReftimeToString3(rtDur).GetString()); - } - strOSD.AppendFormat(_T("\"%s\" (%d/%u)"), static_cast(name), iChapter + 1, nChapters); - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - } - } - } - - return ret; -} - -bool CMainFrame::SeekToDVDChapter(int iChapter, bool bRelative /*= false*/) -{ - if (GetPlaybackMode() != PM_DVD) { - return false; - } - - ULONG ulNumOfVolumes, ulVolume; - DVD_DISC_SIDE Side; - ULONG ulNumOfTitles = 0; - CheckNoLogBool(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles)); - - DVD_PLAYBACK_LOCATION2 Location; - ULONG ulNumOfChapters = 0; - ULONG uTitle = 0, uChapter = 0; - if (bRelative) { - CheckNoLogBool(m_pDVDI->GetCurrentLocation(&Location)); - - CheckNoLogBool(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters)); - - uTitle = Location.TitleNum; - uChapter = Location.ChapterNum; - - if (iChapter < 0) { - ULONG tsec = (Location.TimeCode.bHours * 3600) - + (Location.TimeCode.bMinutes * 60) - + (Location.TimeCode.bSeconds); - ULONG diff = 0; - if (m_lChapterStartTime != 0xFFFFFFFF && tsec > m_lChapterStartTime) { - diff = tsec - m_lChapterStartTime; - } - // Go the previous chapter only if more than PREV_CHAP_THRESHOLD seconds - // have passed since the beginning of the current chapter else restart it - if (diff <= PREV_CHAP_THRESHOLD) { - // If we are at the first chapter of a volume that isn't the first - // one, we skip to the last chapter of the previous volume. - if (uChapter == 1 && uTitle > 1) { - uTitle--; - CheckNoLogBool(m_pDVDI->GetNumberOfChapters(uTitle, &uChapter)); - } else if (uChapter > 1) { - uChapter--; - } - } - } else { - // If we are at the last chapter of a volume that isn't the last - // one, we skip to the first chapter of the next volume. - if (uChapter == ulNumOfChapters && uTitle < ulNumOfTitles) { - uTitle++; - uChapter = 1; - } else if (uChapter < ulNumOfChapters) { - uChapter++; - } - } - } else if (iChapter > 0) { - uChapter = ULONG(iChapter); - if (uChapter <= ulNumOfTitles) { - uTitle = uChapter; - uChapter = 1; - } else { - CheckNoLogBool(m_pDVDI->GetCurrentLocation(&Location)); - uTitle = Location.TitleNum; - uChapter -= ulNumOfTitles; - } - } - - if (uTitle && uChapter - && SUCCEEDED(m_pDVDC->PlayChapterInTitle(uTitle, uChapter, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr))) { - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location)) - && SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters))) { - CString strTitle; - strTitle.Format(IDS_AG_TITLE2, Location.TitleNum, ulNumOfTitles); - __int64 start, stop; - m_wndSeekBar.GetRange(start, stop); - - CString strOSD; - if (stop > 0) { - const CAppSettings& s = AfxGetAppSettings(); - - DVD_HMSF_TIMECODE currentHMSF = s.fRemainingTime ? RT2HMS_r(stop - HMSF2RT(Location.TimeCode)) : Location.TimeCode; - DVD_HMSF_TIMECODE stopHMSF = RT2HMS_r(stop); - strOSD.Format(_T("%s%s/%s %s, %s%02u/%02lu"), - s.fRemainingTime ? _T("- ") : _T(""), DVDtimeToString(currentHMSF, stopHMSF.bHours > 0).GetString(), DVDtimeToString(stopHMSF).GetString(), - strTitle.GetString(), ResStr(IDS_AG_CHAPTER2).GetString(), Location.ChapterNum, ulNumOfChapters); - } else { - strOSD.Format(_T("%s, %s%02u/%02lu"), strTitle.GetString(), ResStr(IDS_AG_CHAPTER2).GetString(), Location.ChapterNum, ulNumOfChapters); - } - - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - } - - return true; - } - - return false; -} - -// navigate -void CMainFrame::OnNavigateSkip(UINT nID) -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (GetPlaybackMode() == PM_FILE || CanSkipFromClosedFile()) { - m_nLastSkipDirection = nID; - - if (!SeekToFileChapter((nID == ID_NAVIGATE_SKIPBACK) ? -1 : 1, true)) { - if (nID == ID_NAVIGATE_SKIPBACK) { - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACKFILE); - } else if (nID == ID_NAVIGATE_SKIPFORWARD) { - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARDFILE); - } - } - } else if (GetPlaybackMode() == PM_DVD) { - m_dSpeedRate = 1.0; - - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - - SeekToDVDChapter((nID == ID_NAVIGATE_SKIPBACK) ? -1 : 1, true); - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - int nCurrentChannel = s.nDVBLastChannel; - - if (nID == ID_NAVIGATE_SKIPBACK) { - if (SUCCEEDED(SetChannel(nCurrentChannel - 1))) { - if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_wndNavigationBar.m_navdlg.UpdatePos(nCurrentChannel - 1); - } - } - } else if (nID == ID_NAVIGATE_SKIPFORWARD) { - if (SUCCEEDED(SetChannel(nCurrentChannel + 1))) { - if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_wndNavigationBar.m_navdlg.UpdatePos(nCurrentChannel + 1); - } - } - } - } - } -} - -bool CMainFrame::CanSkipFromClosedFile() { - if (GetPlaybackMode() == PM_NONE && AfxGetAppSettings().fUseSearchInFolder) { - if (m_wndPlaylistBar.GetCount() == 1) { - CPlaylistItem pli; - return m_wndPlaylistBar.GetCur(pli, true) && !PathUtils::IsURL(pli.m_fns.GetHead()); - } else if (m_wndPlaylistBar.GetCount() == 0 && !lastOpenFile.IsEmpty()) { - return !PathUtils::IsURL(lastOpenFile); - } - } - return false; -} - -void CMainFrame::OnUpdateNavigateSkip(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - - pCmdUI->Enable( - (GetLoadState() == MLS::LOADED - && ((GetPlaybackMode() == PM_DVD - && m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu - && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu) - || (GetPlaybackMode() == PM_FILE && s.fUseSearchInFolder) - || (GetPlaybackMode() == PM_FILE && !s.fUseSearchInFolder && (m_wndPlaylistBar.GetCount() > 1 || m_pCB->ChapGetCount() > 1)) - || (GetPlaybackMode() == PM_DIGITAL_CAPTURE && !m_pDVBState->bSetChannelActive))) - || (GetLoadState() == MLS::CLOSED && CanSkipFromClosedFile()) //to support skipping from broken file - ); -} - -void CMainFrame::OnNavigateSkipFile(UINT nID) -{ - if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_ANALOG_CAPTURE || CanSkipFromClosedFile()) { - if (m_wndPlaylistBar.GetCount() == 1 || CanSkipFromClosedFile()) { - CAppSettings& s = AfxGetAppSettings(); - if (GetPlaybackMode() == PM_ANALOG_CAPTURE || !s.fUseSearchInFolder) { - SendMessage(WM_COMMAND, ID_PLAY_STOP); // do not remove this, unless you want a circular call with OnPlayPlay() - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } else { - if (nID == ID_NAVIGATE_SKIPBACKFILE) { - if (!SearchInDir(false, s.bLoopFolderOnPlayNextFile)) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_FIRST_IN_FOLDER)); - } - } else if (nID == ID_NAVIGATE_SKIPFORWARDFILE) { - if (!SearchInDir(true, s.bLoopFolderOnPlayNextFile)) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_LAST_IN_FOLDER)); - } - } - } - } else { - if (nID == ID_NAVIGATE_SKIPBACKFILE) { - m_wndPlaylistBar.SetPrev(); - } else if (nID == ID_NAVIGATE_SKIPFORWARDFILE) { - m_wndPlaylistBar.SetNext(); - } - - OpenCurPlaylistItem(); - } - } -} - -void CMainFrame::OnUpdateNavigateSkipFile(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable( - (GetLoadState() == MLS::LOADED - && ((GetPlaybackMode() == PM_FILE && (m_wndPlaylistBar.GetCount() > 1 || s.fUseSearchInFolder)) - || (GetPlaybackMode() == PM_ANALOG_CAPTURE && !m_fCapturing && m_wndPlaylistBar.GetCount() > 1))) - || (GetLoadState() == MLS::CLOSED && CanSkipFromClosedFile()) - ); -} - -void CMainFrame::OnNavigateGoto() -{ - if ((GetLoadState() != MLS::LOADED) || IsD3DFullScreenMode()) { - return; - } - - const REFTIME atpf = GetAvgTimePerFrame(); - - REFERENCE_TIME start, dur = -1; - m_wndSeekBar.GetRange(start, dur); - CGoToDlg dlg(m_wndSeekBar.GetPos(), dur, atpf > 0.0 ? (1.0 / atpf) : 0.0); - if (IDOK != dlg.DoModal() || dlg.m_time < 0) { - return; - } - - DoSeekTo(dlg.m_time); -} - -void CMainFrame::OnUpdateNavigateGoto(CCmdUI* pCmdUI) -{ - bool fEnable = false; - - if (GetLoadState() == MLS::LOADED) { - fEnable = true; - if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { - fEnable = false; - } else if (IsPlaybackCaptureMode()) { - fEnable = false; - } - } - - pCmdUI->Enable(fEnable); -} - -void CMainFrame::OnNavigateMenu(UINT nID) -{ - nID -= ID_NAVIGATE_TITLEMENU; - - if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_DVD) { - return; - } - - m_dSpeedRate = 1.0; - - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - - m_pDVDC->ShowMenu((DVD_MENU_ID)(nID + 2), DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); -} - -void CMainFrame::OnUpdateNavigateMenu(CCmdUI* pCmdUI) -{ - UINT nID = pCmdUI->m_nID - ID_NAVIGATE_TITLEMENU; - ULONG ulUOPs; - - if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_DVD - || FAILED(m_pDVDI->GetCurrentUOPS(&ulUOPs))) { - pCmdUI->Enable(FALSE); - return; - } - - pCmdUI->Enable(!(ulUOPs & (UOP_FLAG_ShowMenu_Title << nID))); -} - -void CMainFrame::OnNavigateJumpTo(UINT nID) -{ - if (nID < ID_NAVIGATE_JUMPTO_SUBITEM_START) { - return; - } - - const CAppSettings& s = AfxGetAppSettings(); - - if (GetPlaybackMode() == PM_FILE) { - int id = nID - ID_NAVIGATE_JUMPTO_SUBITEM_START; - - if (id < (int)m_MPLSPlaylist.size() && m_MPLSPlaylist.size() > 1) { - int idx = 0; - for (auto &Item : m_MPLSPlaylist) { - if (idx == id) { - m_bIsBDPlay = true; - m_wndPlaylistBar.Empty(); - CAtlList sl; - sl.AddTail(CString(Item.m_strFileName)); - m_wndPlaylistBar.Append(sl, false); - OpenCurPlaylistItem(); - return; - } - idx++; - } - } - - if (m_MPLSPlaylist.size() > 1) { - id -= (int)m_MPLSPlaylist.size(); - } - - if (m_pCB->ChapGetCount() > 1) { - if (SeekToFileChapter(id)) { - return; - } - - id -= m_pCB->ChapGetCount(); - } - - if (id >= 0 && id < m_wndPlaylistBar.GetCount() && m_wndPlaylistBar.GetSelIdx() != id) { - m_wndPlaylistBar.SetSelIdx(id); - OpenCurPlaylistItem(); - } - } else if (GetPlaybackMode() == PM_DVD) { - SeekToDVDChapter(nID - ID_NAVIGATE_JUMPTO_SUBITEM_START + 1); - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - int nChannel = nID - ID_NAVIGATE_JUMPTO_SUBITEM_START; - - if (s.nDVBLastChannel != nChannel) { - if (SUCCEEDED(SetChannel(nChannel))) { - if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_wndNavigationBar.m_navdlg.UpdatePos(nChannel); - } - } - } - } - } -} - -void CMainFrame::OnNavigateMenuItem(UINT nID) -{ - nID -= ID_NAVIGATE_MENU_LEFT; - - if (GetPlaybackMode() == PM_DVD) { - switch (nID) { - case 0: - m_pDVDC->SelectRelativeButton(DVD_Relative_Left); - break; - case 1: - m_pDVDC->SelectRelativeButton(DVD_Relative_Right); - break; - case 2: - m_pDVDC->SelectRelativeButton(DVD_Relative_Upper); - break; - case 3: - m_pDVDC->SelectRelativeButton(DVD_Relative_Lower); - break; - case 4: - if (m_iDVDDomain == DVD_DOMAIN_Title || m_iDVDDomain == DVD_DOMAIN_VideoTitleSetMenu || m_iDVDDomain == DVD_DOMAIN_VideoManagerMenu) { - m_pDVDC->ActivateButton(); - } else { - OnPlayPlay(); - } - break; - case 5: - m_pDVDC->ReturnFromSubmenu(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - break; - case 6: - m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - break; - default: - break; - } - } else if (GetPlaybackMode() == PM_FILE) { - OnPlayPlay(); - } -} - -void CMainFrame::OnUpdateNavigateMenuItem(CCmdUI* pCmdUI) -{ - pCmdUI->Enable((GetLoadState() == MLS::LOADED) && ((GetPlaybackMode() == PM_DVD) || (GetPlaybackMode() == PM_FILE))); -} - -void CMainFrame::OnTunerScan() -{ - m_bScanDlgOpened = true; - CTunerScanDlg dlg(this); - dlg.DoModal(); - m_bScanDlgOpened = false; -} - -void CMainFrame::OnUpdateTunerScan(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_DIGITAL_CAPTURE); -} - -// favorites - -class CDVDStateStream : public CUnknown, public IStream -{ - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(IStream) - CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - - size_t m_pos; - -public: - CDVDStateStream() : CUnknown(NAME("CDVDStateStream"), nullptr) { - m_pos = 0; - } - - DECLARE_IUNKNOWN; - - CAtlArray m_data; - - // ISequentialStream - STDMETHODIMP Read(void* pv, ULONG cb, ULONG* pcbRead) { - size_t cbRead = std::min(m_data.GetCount() - m_pos, size_t(cb)); - cbRead = std::max(cbRead, size_t(0)); - if (cbRead) { - memcpy(pv, &m_data[m_pos], cbRead); - } - if (pcbRead) { - *pcbRead = (ULONG)cbRead; - } - m_pos += cbRead; - return S_OK; - } - STDMETHODIMP Write(const void* pv, ULONG cb, ULONG* pcbWritten) { - BYTE* p = (BYTE*)pv; - ULONG cbWritten = (ULONG) - 1; - while (++cbWritten < cb) { - m_data.Add(*p++); - } - if (pcbWritten) { - *pcbWritten = cbWritten; - } - return S_OK; - } - - // IStream - STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { - return E_NOTIMPL; - } - - STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize) { - return E_NOTIMPL; - } - - STDMETHODIMP CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { - return E_NOTIMPL; - } - - STDMETHODIMP Commit(DWORD grfCommitFlags) { - return E_NOTIMPL; - } - - STDMETHODIMP Revert() { - return E_NOTIMPL; - } - - STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { - return E_NOTIMPL; - } - - STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { - return E_NOTIMPL; - } - - STDMETHODIMP Stat(STATSTG* pstatstg, DWORD grfStatFlag) { - return E_NOTIMPL; - } - - STDMETHODIMP Clone(IStream** ppstm) { - return E_NOTIMPL; - } -}; - -void CMainFrame::AddFavorite(bool fDisplayMessage, bool fShowDialog) -{ - CAppSettings& s = AfxGetAppSettings(); - CAtlList args; - WORD osdMsg = 0; - const TCHAR sep = _T(';'); - - if (GetPlaybackMode() == PM_FILE) { - bool is_BD = false; - CString fn = m_wndPlaylistBar.GetCurFileNameTitle(); - if (fn.IsEmpty()) { - if (m_pFSF) { - CComHeapPtr pFN; - AM_MEDIA_TYPE mt; - if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { - fn = CStringW(pFN); - } - } - if (fn.IsEmpty()) { - return; - } - is_BD = true; - } - - CString desc = GetFileName(); - - // Name - CString name; - if (fShowDialog) { - BOOL bEnableABMarks = static_cast(abRepeat); - CFavoriteAddDlg dlg(desc, fn, bEnableABMarks); - if (dlg.DoModal() != IDOK) { - return; - } - name = dlg.m_name; - } else { - name = desc; - } - args.AddTail(name); - - // RememberPos - CString posStr = _T("0"); - if (s.bFavRememberPos) { - posStr.Format(_T("%I64d"), GetPos()); - } - // RememberABMarks - if (s.bFavRememberABMarks && abRepeat) { - posStr.AppendFormat(_T(":%I64d:%I64d"), abRepeat.positionA, abRepeat.positionB); - } - args.AddTail(posStr); - - // RelativeDrive - CString relativeDrive; - relativeDrive.Format(_T("%d"), s.bFavRelativeDrive); - - args.AddTail(relativeDrive); - - // Paths - if (is_BD) { - args.AddTail(fn); - } else { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli)) { - if (pli.m_bYoutubeDL) { - args.AddTail(pli.m_ydlSourceURL); - } else { - POSITION pos = pli.m_fns.GetHeadPosition(); - while (pos) { - args.AddTail(pli.m_fns.GetNext(pos)); - } - } - } - } - - CString str = ImplodeEsc(args, sep); - s.AddFav(FAV_FILE, str); - osdMsg = IDS_FILE_FAV_ADDED; - } else if (GetPlaybackMode() == PM_DVD) { - WCHAR path[MAX_PATH]; - ULONG len = 0; - if (SUCCEEDED(m_pDVDI->GetDVDDirectory(path, MAX_PATH, &len))) { - CString fn = path; - fn.TrimRight(_T("/\\")); - - DVD_PLAYBACK_LOCATION2 Location; - CString desc; - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location))) { - desc.Format(_T("%s - T%02u C%02u - %02u:%02u:%02u"), fn.GetString(), Location.TitleNum, Location.ChapterNum, - Location.TimeCode.bHours, Location.TimeCode.bMinutes, Location.TimeCode.bSeconds); - } else { - desc = fn; - } - // Name - CString name; - if (fShowDialog) { - CFavoriteAddDlg dlg(fn, desc); - if (dlg.DoModal() != IDOK) { - return; - } - name = dlg.m_name; - } else { - name = s.bFavRememberPos ? desc : fn; - } - args.AddTail(name); - - // RememberPos - CString pos(_T("0")); - if (s.bFavRememberPos) { - CDVDStateStream stream; - stream.AddRef(); - - CComPtr pStateData; - CComQIPtr pPersistStream; - if (SUCCEEDED(m_pDVDI->GetState(&pStateData)) - && (pPersistStream = pStateData) - && SUCCEEDED(OleSaveToStream(pPersistStream, (IStream*)&stream))) { - pos = BinToCString(stream.m_data.GetData(), stream.m_data.GetCount()); - } - } - - args.AddTail(pos); - - // Paths - args.AddTail(fn); - - CString str = ImplodeEsc(args, sep); - s.AddFav(FAV_DVD, str); - osdMsg = IDS_DVD_FAV_ADDED; - } - } // TODO: PM_ANALOG_CAPTURE and PM_DIGITAL_CAPTURE - - if (fDisplayMessage && osdMsg) { - CString osdMsgStr(StrRes(osdMsg)); - SendStatusMessage(osdMsgStr, 3000); - m_OSD.DisplayMessage(OSD_TOPLEFT, osdMsgStr, 3000); - } - if (::IsWindow(m_wndFavoriteOrganizeDialog.m_hWnd)) { - m_wndFavoriteOrganizeDialog.LoadList(); - } -} - -void CMainFrame::OnFavoritesAdd() -{ - AddFavorite(); -} - -void CMainFrame::OnUpdateFavoritesAdd(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD); -} - -void CMainFrame::OnFavoritesQuickAddFavorite() -{ - AddFavorite(true, false); -} - -void CMainFrame::OnFavoritesOrganize() -{ - m_wndFavoriteOrganizeDialog.ShowWindow(SW_SHOW); -} - -void CMainFrame::OnUpdateFavoritesOrganize(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - CAtlList sl; - s.GetFav(FAV_FILE, sl); - bool enable = !sl.IsEmpty(); - - if (!enable) { - s.GetFav(FAV_DVD, sl); - enable = !sl.IsEmpty(); - } - - pCmdUI->Enable(enable); -} - -void CMainFrame::OnRecentFileClear() -{ - if (IDYES != AfxMessageBox(IDS_RECENT_FILES_QUESTION, MB_ICONQUESTION | MB_YESNO, 0)) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - s.ClearRecentFiles(); -} - -void CMainFrame::OnUpdateRecentFileClear(CCmdUI* pCmdUI) -{ - // TODO: Add your command update UI handler code here -} - -void CMainFrame::OnFavoritesFile(UINT nID) -{ - nID -= ID_FAVORITES_FILE_START; - CAtlList sl; - AfxGetAppSettings().GetFav(FAV_FILE, sl); - - if (POSITION pos = sl.FindIndex(nID)) { - PlayFavoriteFile(sl.GetAt(pos)); - } -} - -void CMainFrame::PlayFavoriteFile(const CString& fav) -{ - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - - CAtlList args; - REFERENCE_TIME rtStart = 0; - FileFavorite ff = ParseFavoriteFile(fav, args, &rtStart); - - auto firstFile = args.GetHead(); - if (!m_wndPlaylistBar.SelectFileInPlaylist(firstFile) && - (!CanSendToYoutubeDL(firstFile) || - !ProcessYoutubeDLURL(firstFile, false))) { - m_wndPlaylistBar.Open(args, false); - } - - m_wndPlaylistBar.SetCurLabel(ff.Name); - - if (GetPlaybackMode() == PM_FILE && args.GetHead() == m_lastOMD->title) { - m_pMS->SetPositions(&rtStart, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - OnPlayPlay(); - } else { - OpenCurPlaylistItem(rtStart); - } - -} - -FileFavorite CMainFrame::ParseFavoriteFile(const CString& fav, CAtlList& args, REFERENCE_TIME* prtStart) -{ - FileFavorite ff; - VERIFY(FileFavorite::TryParse(fav, ff, args)); - - abRepeat.positionA = ff.MarkA; - abRepeat.positionB = ff.MarkB; - - // Start at mark A (if set) - ff.Start = std::max(ff.Start, abRepeat.positionA); - - if (prtStart) { - *prtStart = ff.Start; - } - - // NOTE: This is just for the favorites but we could add a global settings that - // does this always when on. Could be useful when using removable devices. - // All you have to do then is plug in your 500 gb drive, full with movies and/or music, - // start MPC-HC (from the 500 gb drive) with a preloaded playlist and press play. - if (ff.RelativeDrive) { - // Get the drive MPC-HC is on and apply it to the path list - CString exePath = PathUtils::GetProgramPath(true); - - CPath exeDrive(exePath); - - if (exeDrive.StripToRoot()) { - POSITION pos = args.GetHeadPosition(); - - while (pos != nullptr) { - CString& stringPath = args.GetNext(pos); // Note the reference (!) - CPath path(stringPath); - - int rootLength = path.SkipRoot(); - - if (path.StripToRoot()) { - if (_tcsicmp(exeDrive, path) != 0) { // Do we need to replace the drive letter ? - // Replace drive letter - CString newPath(exeDrive); - - newPath += stringPath.Mid(rootLength); - - stringPath = newPath; // Note: Changes args.GetHead() - } - } - } - } - } - return ff; -} - -void CMainFrame::OnUpdateFavoritesFile(CCmdUI* pCmdUI) -{ - //UINT nID = pCmdUI->m_nID - ID_FAVORITES_FILE_START; -} - -void CMainFrame::OnRecentFile(UINT nID) -{ - CAtlList fns; - auto& MRU = AfxGetAppSettings().MRU; - RecentFileEntry r; - - // find corresponding item in MRU list, we can't directly use string from menu because it may have been shortened - nID -= ID_RECENT_FILE_START; - if (nID < MRU.GetSize()) { - r = MRU[nID]; - fns.AddHeadList(&r.fns); - } else { - ASSERT(false); - return; - } - - CloseMediaBeforeOpen(); - - if (fns.GetCount() == 1 && CanSendToYoutubeDL(r.fns.GetHead())) { - if (ProcessYoutubeDLURL(fns.GetHead(), false)) { - OpenCurPlaylistItem(); - return; - } else if (IsOnYDLWhitelist(fns.GetHead())) { - // don't bother trying to open this website URL directly - return; - } - } - - CAtlList subs; - subs.AddHeadList(&r.subs); - - if (!m_wndPlaylistBar.SelectFileInPlaylist(fns.GetHead())) { - m_wndPlaylistBar.Open(fns, false, &subs, r.title, _T(""), r.cue); - } - else { - m_wndPlaylistBar.ReplaceCurrentItem(fns, &subs, r.title, _T(""), r.cue); - } - - OpenCurPlaylistItem(); -} - -void CMainFrame::OnUpdateRecentFile(CCmdUI* pCmdUI) -{ - //UINT nID = pCmdUI->m_nID - ID_RECENT_FILE_START; -} - -void CMainFrame::OnFavoritesDVD(UINT nID) -{ - nID -= ID_FAVORITES_DVD_START; - - CAtlList sl; - AfxGetAppSettings().GetFav(FAV_DVD, sl); - - if (POSITION pos = sl.FindIndex(nID)) { - PlayFavoriteDVD(sl.GetAt(pos)); - } -} - -void CMainFrame::PlayFavoriteDVD(CString fav) -{ - CAtlList args; - CString fn; - CDVDStateStream stream; - - stream.AddRef(); - - ExplodeEsc(fav, args, _T(';'), 3); - args.RemoveHeadNoReturn(); // desc / name - CString state = args.RemoveHead(); // state - if (state != _T("0")) { - CStringToBin(state, stream.m_data); - } - fn = args.RemoveHead(); // path - - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - - CComPtr pDvdState; - HRESULT hr = OleLoadFromStream((IStream*)&stream, IID_PPV_ARGS(&pDvdState)); - UNREFERENCED_PARAMETER(hr); - - CAutoPtr p(DEBUG_NEW OpenDVDData()); - if (p) { - p->path = fn; - p->pDvdState = pDvdState; - } - OpenMedia(p); -} - -void CMainFrame::OnUpdateFavoritesDVD(CCmdUI* pCmdUI) -{ - //UINT nID = pCmdUI->m_nID - ID_FAVORITES_DVD_START; -} - -void CMainFrame::OnFavoritesDevice(UINT nID) -{ - //nID -= ID_FAVORITES_DEVICE_START; -} - -void CMainFrame::OnUpdateFavoritesDevice(CCmdUI* pCmdUI) -{ - //UINT nID = pCmdUI->m_nID - ID_FAVORITES_DEVICE_START; -} - -// help - -void CMainFrame::OnHelpHomepage() -{ - ShellExecute(m_hWnd, _T("open"), WEBSITE_URL, nullptr, nullptr, SW_SHOWDEFAULT); -} - -void CMainFrame::OnHelpCheckForUpdate() -{ - UpdateChecker::CheckForUpdate(); -} - -void CMainFrame::OnHelpToolbarImages() -{ - ShellExecute(m_hWnd, _T("open"), _T("https://github.com/clsid2/mpc-hc/issues/382"), nullptr, nullptr, SW_SHOWDEFAULT); -} - -void CMainFrame::OnHelpDonate() -{ - ShellExecute(m_hWnd, _T("open"), _T("https://github.com/clsid2/mpc-hc/issues/383"), nullptr, nullptr, SW_SHOWDEFAULT); -} - -////////////////////////////////// - -static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - CAtlArray* ml = (CAtlArray*)dwData; - ml->Add(hMonitor); - return TRUE; -} - -void CMainFrame::SetDefaultWindowRect(int iMonitor) -{ - const CAppSettings& s = AfxGetAppSettings(); - CRect rcLastWindowPos = s.rcLastWindowPos; - - if (s.eCaptionMenuMode != MODE_SHOWCAPTIONMENU) { - if (s.eCaptionMenuMode == MODE_FRAMEONLY) { - ModifyStyle(WS_CAPTION, 0, SWP_NOZORDER); - } else if (s.eCaptionMenuMode == MODE_BORDERLESS) { - ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0, SWP_NOZORDER); - } - SetMenuBarVisibility(AFX_MBV_DISPLAYONFOCUS); - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - } - - CMonitors monitors; - CMonitor monitor; - if (iMonitor > 0 && iMonitor <= monitors.GetCount()) { - monitor = monitors.GetMonitor(iMonitor - 1); - } else { - monitor = CMonitors::GetNearestMonitor(this); - } - - CSize windowSize; - bool tRememberPos = s.fRememberWindowPos; - MINMAXINFO mmi; - OnGetMinMaxInfo(&mmi); - - if (s.HasFixedWindowSize()) { - windowSize = CSize(std::max(s.sizeFixedWindow.cx, mmi.ptMinTrackSize.x), std::max(s.sizeFixedWindow.cy, mmi.ptMinTrackSize.y)); - if (s.fixedWindowPosition != NO_FIXED_POSITION) { - tRememberPos = true; - CRect monitorRect; - monitor.GetWorkAreaRect(&monitorRect); - monitorRect += s.fixedWindowPosition; - rcLastWindowPos.MoveToXY(monitorRect.left, monitorRect.top); - } - } else if (s.fRememberWindowSize) { - windowSize = rcLastWindowPos.Size(); - } else { - CRect windowRect; - GetWindowRect(&windowRect); - CRect clientRect; - GetClientRect(&clientRect); - - CSize logoSize = m_wndView.GetLogoSize(); - logoSize.cx = std::max(logoSize.cx, m_dpi.ScaleX(MIN_LOGO_WIDTH)); - logoSize.cy = std::max(logoSize.cy, m_dpi.ScaleY(MIN_LOGO_HEIGHT)); - - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); - - windowSize.cx = windowRect.Width() - clientRect.Width() + logoSize.cx + uLeft + uRight; - windowSize.cy = windowRect.Height() - clientRect.Height() + logoSize.cy + uTop + uBottom; - } - - bool bRestoredWindowPosition = false; - if (tRememberPos) { - CRect windowRect(rcLastWindowPos.TopLeft(), windowSize); - if ((!iMonitor && CMonitors::IsOnScreen(windowRect)) - || (iMonitor && monitor.IsOnMonitor(windowRect))) { - restoringWindowRect = true; - MoveWindow(windowRect); - restoringWindowRect = false; - bRestoredWindowPosition = true; - } - } - - if (!bRestoredWindowPosition) { - CRect windowRect(0, 0, std::max(windowSize.cx, mmi.ptMinTrackSize.x), std::max(windowSize.cy, mmi.ptMinTrackSize.y)); - monitor.CenterRectToMonitor(windowRect, TRUE); - SetWindowPos(nullptr, windowRect.left, windowRect.top, windowSize.cx, windowSize.cy, SWP_NOZORDER | SWP_NOACTIVATE); - } - - if (s.fSavePnSZoom) { - m_ZoomX = s.dZoomX; - m_ZoomY = s.dZoomY; - } -} - -void CMainFrame::SetDefaultFullscreenState() -{ - CAppSettings& s = AfxGetAppSettings(); - - bool clGoFullscreen = !(s.nCLSwitches & (CLSW_ADD | CLSW_THUMBNAILS)) && (s.nCLSwitches & CLSW_FULLSCREEN); - - if (clGoFullscreen && !s.slFiles.IsEmpty()) { - // ignore fullscreen if all files are audio - clGoFullscreen = false; - const CMediaFormats& mf = AfxGetAppSettings().m_Formats; - POSITION pos = s.slFiles.GetHeadPosition(); - while (pos) { - CString fpath = s.slFiles.GetNext(pos); - CString ext = fpath.Mid(fpath.ReverseFind('.') + 1); - if (!mf.FindExt(ext, true)) { - clGoFullscreen = true; - break; - } - } - } - - if (clGoFullscreen) { - if (s.IsD3DFullscreen()) { - m_fStartInD3DFullscreen = true; - } else { - bool launchingFullscreenSeparateControls = false; - if (s.bFullscreenSeparateControls) { - CMonitors monitors; - CMonitor currentMonitor = monitors.GetNearestMonitor(this); - CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); - if (fullscreenMonitor.IsMonitor()) { - launchingFullscreenSeparateControls = fullscreenMonitor != currentMonitor; - } - } - - if (launchingFullscreenSeparateControls) { - m_fStartInFullscreenSeparate = true; - } else { - ToggleFullscreen(true, true); - m_bNeedZoomAfterFullscreenExit = true; - } - } - s.nCLSwitches &= ~CLSW_FULLSCREEN; - } else if (s.fRememberWindowSize && s.fRememberWindowPos && !m_fFullScreen && s.fLastFullScreen) { - // Casimir666 : if fullscreen was on, put it on back - if (s.IsD3DFullscreen()) { - m_fStartInD3DFullscreen = true; - } else { - ToggleFullscreen(true, true); - m_bNeedZoomAfterFullscreenExit = true; - } - } -} - -void CMainFrame::RestoreDefaultWindowRect() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (!m_fFullScreen && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { - CSize windowSize; - - if (s.HasFixedWindowSize()) { - windowSize = s.sizeFixedWindow; - } else if (s.fRememberWindowSize) { - windowSize = s.rcLastWindowPos.Size(); - } else { - CRect windowRect; - GetWindowRect(&windowRect); - CRect clientRect; - GetClientRect(&clientRect); - - CSize logoSize = m_wndView.GetLogoSize(); - logoSize.cx = std::max(logoSize.cx, m_dpi.ScaleX(MIN_LOGO_WIDTH)); - logoSize.cy = std::max(logoSize.cy, m_dpi.ScaleY(MIN_LOGO_HEIGHT)); - - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); - - windowSize.cx = windowRect.Width() - clientRect.Width() + logoSize.cx + uLeft + uRight; - windowSize.cy = windowRect.Height() - clientRect.Height() + logoSize.cy + uTop + uBottom; - } - - if (s.fRememberWindowPos) { - MoveWindow(CRect(s.rcLastWindowPos.TopLeft(), windowSize)); - } else { - SetWindowPos(nullptr, 0, 0, windowSize.cx, windowSize.cy, SWP_NOMOVE | SWP_NOZORDER); - CenterWindow(); - } - } -} - -CRect CMainFrame::GetInvisibleBorderSize() const -{ - CRect invisibleBorders; - - if (IsWindows10OrGreater()) { - static const WinapiFunc - fnDwmGetWindowAttribute = { _T("Dwmapi.dll"), "DwmGetWindowAttribute" }; - - if (fnDwmGetWindowAttribute) { - if (SUCCEEDED(fnDwmGetWindowAttribute(GetSafeHwnd(), DWMWA_EXTENDED_FRAME_BOUNDS, &invisibleBorders, sizeof(RECT)))) { - CRect windowRect; - GetWindowRect(windowRect); - - invisibleBorders.TopLeft() = invisibleBorders.TopLeft() - windowRect.TopLeft(); - invisibleBorders.BottomRight() = windowRect.BottomRight() - invisibleBorders.BottomRight(); - } else { - ASSERT(false); - } - } - } - - return invisibleBorders; -} - -OAFilterState CMainFrame::GetMediaStateDirect() const -{ - OAFilterState ret = -1; - if (m_eMediaLoadState == MLS::LOADED) { - m_pMC->GetState(0, &ret); - } - return ret; -} - -OAFilterState CMainFrame::GetMediaState() const -{ - OAFilterState ret = -1; - if (m_eMediaLoadState == MLS::LOADED) { - if (m_CachedFilterState != -1) { - #if DEBUG & 0 - ret = GetMediaStateDirect(); - ASSERT(ret == m_CachedFilterState || m_fFrameSteppingActive); - #endif - return m_CachedFilterState; - } else { - m_pMC->GetState(0, &ret); - } - } - return ret; -} - -OAFilterState CMainFrame::UpdateCachedMediaState() -{ - m_CachedFilterState = GetMediaStateDirect(); - return m_CachedFilterState; -} - -bool CMainFrame::MediaControlRun(bool waitforcompletion) -{ - m_dwLastPause = 0; - if (m_pMC) { - m_CachedFilterState = State_Running; - if (FAILED(m_pMC->Run())) { - // still in transition to running state - if (waitforcompletion) { - m_CachedFilterState = -1; - m_pMC->GetState(0, &m_CachedFilterState); - ASSERT(m_CachedFilterState == State_Running); - } - }; - MediaTransportControlUpdateState(State_Running); - return true; - } - return false; -} - -bool CMainFrame::MediaControlPause(bool waitforcompletion) -{ - m_dwLastPause = GetTickCount64(); - if (m_pMC) { - m_CachedFilterState = State_Paused; - if (FAILED(m_pMC->Pause())) { - // still in transition to paused state - if (waitforcompletion) { - m_CachedFilterState = -1; - m_pMC->GetState(0, &m_CachedFilterState); - ASSERT(m_CachedFilterState == State_Paused); - } - } - MediaTransportControlUpdateState(State_Paused); - return true; - } - return false; -} - -bool CMainFrame::MediaControlStop(bool waitforcompletion) -{ - m_dwLastPause = 0; - if (m_pMC) { - m_pMC->GetState(0, &m_CachedFilterState); - if (m_CachedFilterState != State_Stopped) { - if (FAILED(m_pMC->Stop())) { - ASSERT(FALSE); - m_CachedFilterState = -1; - return false; - } - if (waitforcompletion) { - m_CachedFilterState = -1; - m_pMC->GetState(0, &m_CachedFilterState); - ASSERT(m_CachedFilterState == State_Stopped); - } else { - m_CachedFilterState = State_Stopped; - } - } - MediaTransportControlUpdateState(State_Stopped); - return true; - } - return false; -} - -bool CMainFrame::MediaControlStopPreview() -{ - if (m_pMC_preview) { - OAFilterState fs = -1; - m_pMC_preview->GetState(0, &fs); - if (fs != State_Stopped) { - if (FAILED(m_pMC_preview->Stop())) { - ASSERT(FALSE); - return false; - } - m_pMC_preview->GetState(0, &fs); - ASSERT(fs == State_Stopped); - } - return true; - } - return false; -} - -void CMainFrame::SetPlaybackMode(int iNewStatus) -{ - m_iPlaybackMode = iNewStatus; -} - -CSize CMainFrame::GetVideoSizeWithRotation(bool forPreview) const -{ - CSize ret = GetVideoSize(); - if (forPreview && m_pGB_preview) { - CFGManagerPlayer* fgmPreview = static_cast(m_pGB_preview.p); - if (fgmPreview && !fgmPreview->PreviewSupportsRotation()) { - //preview cannot rotate, so we need to reverse any default rotation that swapped x/y - int rotation = ((360 - m_iDefRotation) % 360) / 90; - if (rotation == 1 || rotation == 3) { - std::swap(ret.cx, ret.cy); - } - return ret; - } - } - - if (m_pCAP && !m_pCAP3) { //videosize does not consider manual rotation - int rotation = ((360 - nearest90(m_AngleZ)) % 360) / 90; //do not add in m_iDefRotation - if (rotation == 1 || rotation == 3) { //90 degrees - std::swap(ret.cx, ret.cy); - } - } - return ret; -} - -CSize CMainFrame::GetVideoSize() const -{ - CSize ret; - if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { - return ret; - } - - const CAppSettings& s = AfxGetAppSettings(); - CSize videoSize, preferedAR; - - if (m_pCAP) { - videoSize = m_pCAP->GetVideoSize(false); - preferedAR = m_pCAP->GetVideoSize(s.fKeepAspectRatio); - } else if (m_pMFVDC) { - m_pMFVDC->GetNativeVideoSize(&videoSize, &preferedAR); // TODO : check AR !! - } else if (m_pBV) { - m_pBV->GetVideoSize(&videoSize.cx, &videoSize.cy); - - long arx = 0, ary = 0; - CComQIPtr pBV2 = m_pBV; - // FIXME: It can hang here, for few seconds (CPU goes to 100%), after the window have been moving over to another screen, - // due to GetPreferredAspectRatio, if it happens before CAudioSwitcherFilter::DeliverEndFlush, it seems. - if (pBV2 && SUCCEEDED(pBV2->GetPreferredAspectRatio(&arx, &ary)) && arx > 0 && ary > 0) { - preferedAR.SetSize(arx, ary); - } - } - if (preferedAR.cx <= 0 || preferedAR.cy <= 0) { //due to IBasicVideo2 not being found, this could still be zero for .swf - preferedAR.SetSize(videoSize.cx, videoSize.cy); - } - - if (videoSize.cx <= 0 || videoSize.cy <= 0) { - return ret; - } - - if (s.fKeepAspectRatio) { - CSize overrideAR = s.GetAspectRatioOverride(); - DVD_VideoAttributes VATR; - if ((!overrideAR.cx || !overrideAR.cy) && GetPlaybackMode() == PM_DVD - && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { - overrideAR.SetSize(VATR.ulAspectX, VATR.ulAspectY); - } - if (overrideAR.cx > 0 && overrideAR.cy > 0) { - if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", double(overrideAR.cx) / overrideAR.cy))) { - ret = m_pCAP->GetVideoSize(false); - } else { - ret = CSize(MulDiv(videoSize.cy, overrideAR.cx, overrideAR.cy), videoSize.cy); - } - } else { - if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", 0.0))) { - ret = m_pCAP->GetVideoSize(false); - } else { - ret = CSize(MulDiv(videoSize.cy, preferedAR.cx, preferedAR.cy), videoSize.cy); - } - } - } else { - CSize originalVideoSize(0, 1); - if (m_pMVRI) { - m_pMVRI->GetSize("originalVideoSize", &originalVideoSize); - } - if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", - double(originalVideoSize.cx) / originalVideoSize.cy))) { - ret = m_pCAP->GetVideoSize(false); - } else { - ret = videoSize; - } - } - - if (s.fCompMonDeskARDiff - && s.iDSVideoRendererType != VIDRNDT_DS_EVR - && s.iDSVideoRendererType != VIDRNDT_DS_MADVR) - if (HDC hDC = ::GetDC(nullptr)) { - int _HORZSIZE = GetDeviceCaps(hDC, HORZSIZE); - int _VERTSIZE = GetDeviceCaps(hDC, VERTSIZE); - int _HORZRES = GetDeviceCaps(hDC, HORZRES); - int _VERTRES = GetDeviceCaps(hDC, VERTRES); - - if (_HORZSIZE > 0 && _VERTSIZE > 0 && _HORZRES > 0 && _VERTRES > 0) { - double a = 1.0 * _HORZSIZE / _VERTSIZE; - double b = 1.0 * _HORZRES / _VERTRES; - - if (b < a) { - ret.cy = (DWORD)(1.0 * ret.cy * a / b); - } else if (a < b) { - ret.cx = (DWORD)(1.0 * ret.cx * b / a); - } - } - - ::ReleaseDC(nullptr, hDC); - } - - return ret; -} - -void CMainFrame::HidePlaylistFullScreen(bool force /* = false */) -{ - if (force || m_fFullScreen) { - CAppSettings& s = AfxGetAppSettings(); - if (s.bHidePlaylistFullScreen && m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)) { - m_wndPlaylistBar.SetHiddenDueToFullscreen(true); - ShowControlBar(&m_wndPlaylistBar, FALSE, FALSE); - } - } -} - -void CMainFrame::ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo) -{ - if (IsD3DFullScreenMode()) { - ASSERT(FALSE); - return; - } - - CAppSettings& s = AfxGetAppSettings(); - - if (delayingFullScreen) { - return; //swallow request if we are in the delay period - } - - CMonitors monitors; - CMonitor defaultMonitor = monitors.GetPrimaryMonitor(); - CMonitor currentMonitor = monitors.GetNearestMonitor(this); - CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); - if (!fullscreenMonitor.IsMonitor()) { - fullscreenMonitor = currentMonitor; - } - bool fullScreenSeparate = s.bFullscreenSeparateControls && (m_pMFVDC || m_pVMRWC || m_pVW) && fullscreenMonitor.IsMonitor() && fullscreenMonitor != currentMonitor && (s.nCS & (CS_SEEKBAR | CS_TOOLBAR)); - - const CWnd* pInsertAfter = nullptr; - CRect windowRect; - DWORD dwRemove = 0, dwAdd = 0; - - if (!fullScreenSeparate && s.iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 - BOOL setEnabled = TRUE; - ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); - } - - bool restart_osd = false; - if (!m_pMVTO) { - m_OSD.Stop(); - restart_osd = s.fShowOSD || s.fShowDebugInfo; - } - - if (fullScreenSeparate) { - if (m_fFullScreen) { - m_fFullScreen = false; - } else { - if (!m_bNeedZoomAfterFullscreenExit && !s.HasFixedWindowSize()) { - // adjust control window size to minimal - m_bNeedZoomAfterFullscreenExit = true; - ZoomVideoWindow(ZOOM_DEFAULT_LEVEL, true); - } - m_fFullScreen = true; - } - s.fLastFullScreen = false; //not really, just fullScreenSecondMonitor - - if (m_fFullScreen) { - m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN); - - // Set the fullscreen display mode - if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo) { - AutoChangeMonitorMode(); - } - - CreateFullScreenWindow(false); - if (m_pD3DFSC && s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { - m_pD3DFSC->SetD3DFullscreen(true); - } - // Assign the windowed video frame and pass it to the relevant classes. - m_pVideoWnd = m_pDedicatedFSVideoWnd; - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } else if (m_pVMRWC) { - m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); - } - if (m_pVW) { - m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); - m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); - } - m_wndView.Invalidate(); - } else { - m_eventc.FireEvent(MpcEvent::SWITCHING_FROM_FULLSCREEN); - - if (m_pD3DFSC && s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { - m_pD3DFSC->SetD3DFullscreen(false); - } - m_pVideoWnd = &m_wndView; - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } else if (m_pVMRWC) { - m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); - } - if (m_pVW) { - m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); - m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); - } - if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { - SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift - } - - // Destroy the Fullscreen window and zoom the windowed video frame - m_pDedicatedFSVideoWnd->DestroyWindow(); - if (m_bNeedZoomAfterFullscreenExit) { - m_bNeedZoomAfterFullscreenExit = false; - if (s.fRememberZoomLevel) { - ZoomVideoWindow(); - } - } - } - MoveVideoWindow(); - - if (s.bHideWindowedControls) { - m_controls.UpdateToolbarsVisibility(); - } - } else { - m_fFullScreen = !m_fFullScreen; - s.fLastFullScreen = m_fFullScreen; - - if (m_fFullScreen) { - SetCursor(nullptr); // prevents cursor flickering when our window is not under the cursor - - m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN); - - HidePlaylistFullScreen(true); - - GetWindowRect(&m_lastWindowRect); - - if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo && GetPlaybackMode() != PM_NONE) { - AutoChangeMonitorMode(); - } - - dwRemove |= WS_CAPTION | WS_THICKFRAME; - if (s.fPreventMinimize && fullscreenMonitor != defaultMonitor) { - dwRemove |= WS_MINIMIZEBOX; - } - - m_bExtOnTop = !s.iOnTop && (GetExStyle() & WS_EX_TOPMOST); - pInsertAfter = &wndTopMost; - - if (fToNearest) { - fullscreenMonitor.GetMonitorRect(windowRect); - } else { - GetDesktopWindow()->GetWindowRect(windowRect); - } - } else { - m_eventc.FireEvent(MpcEvent::SWITCHING_FROM_FULLSCREEN); - - if (m_pVideoWnd != &m_wndView) { - m_pVideoWnd = &m_wndView; - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } else if (m_pVMRWC) { - m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); - } - if (m_pVW) { - m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); - m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); - } - } - m_pDedicatedFSVideoWnd->DestroyWindow(); - - if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { - SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift - } - - windowRect = m_lastWindowRect; - if (!monitors.IsOnScreen(windowRect)) { - currentMonitor.CenterRectToMonitor(windowRect, TRUE); - } - - dwAdd |= WS_MINIMIZEBOX; - if (s.eCaptionMenuMode != MODE_BORDERLESS) { - dwAdd |= WS_THICKFRAME; - if (s.eCaptionMenuMode != MODE_FRAMEONLY) { - dwAdd |= WS_CAPTION; - } - } - - if (m_wndPlaylistBar.IsHiddenDueToFullscreen() && !m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)) { - if (s.bHideWindowedControls) { - m_wndPlaylistBar.SetHiddenDueToFullscreen(false, true); - } else { - m_wndPlaylistBar.SetHiddenDueToFullscreen(false); - m_controls.ToggleControl(CMainFrameControls::Panel::PLAYLIST); - } - } - - // If MPC-HC wasn't previously set "on top" by an external tool, - // we restore the current internal on top state. (1/2) - if (!m_bExtOnTop) { - pInsertAfter = &wndNoTopMost; - } - } - - bool bZoomVideoWindow = false; - if (m_bNeedZoomAfterFullscreenExit && !m_fFullScreen) { - bZoomVideoWindow = s.fRememberZoomLevel; - m_bNeedZoomAfterFullscreenExit = false; - } - - ModifyStyle(dwRemove, dwAdd, SWP_NOZORDER); - SetWindowPos(pInsertAfter, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), - SWP_NOSENDCHANGING | SWP_FRAMECHANGED); - - // If MPC-HC wasn't previously set "on top" by an external tool, - // we restore the current internal on top state. (2/2) - if (!m_fFullScreen && !m_bExtOnTop) { - SetAlwaysOnTop(s.iOnTop); - } - - SetMenuBarVisibility((!m_fFullScreen && s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) - ? AFX_MBV_KEEPVISIBLE : AFX_MBV_DISPLAYONFOCUS); - - UpdateControlState(UPDATE_CONTROLS_VISIBILITY); - - if (bZoomVideoWindow) { - ZoomVideoWindow(); - } - MoveVideoWindow(); - } - - if (restart_osd) { - if (m_fFullScreen && m_pCAP3 && m_pMFVMB) { // MPCVR - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); - } else { - m_OSD.Start(m_pOSDWnd); - OSDBarSetPos(); - } - } - - if (m_fFullScreen) { - m_eventc.FireEvent(MpcEvent::SWITCHED_TO_FULLSCREEN); - } else { - m_eventc.FireEvent(MpcEvent::SWITCHED_FROM_FULLSCREEN); - } - - if (!fullScreenSeparate && s.iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 - UINT_PTR timerID = 0; - timerID = SetTimer(TIMER_WINDOW_FULLSCREEN, s.iFullscreenDelay, nullptr); - if (0 == timerID) { - BOOL setEnabled = FALSE; - ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); - } else { - delayingFullScreen = true; - } - RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE); - } -} - -void CMainFrame::ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo) -{ - if (m_pD3DFSC && m_pMFVDC) { - CAppSettings& s = AfxGetAppSettings(); - - bool bIsFullscreen = false; - m_pD3DFSC->GetD3DFullscreen(&bIsFullscreen); - s.fLastFullScreen = !bIsFullscreen; - - m_OSD.Stop(); - - if (bIsFullscreen) { - // Turn off D3D Fullscreen - m_pD3DFSC->SetD3DFullscreen(false); - - // Assign the windowed video frame and pass it to the relevant classes. - m_pVideoWnd = &m_wndView; - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - - if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { - SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift - } - - // Destroy the D3D Fullscreen window and zoom the windowed video frame - m_pDedicatedFSVideoWnd->DestroyWindow(); - if (m_bNeedZoomAfterFullscreenExit) { - if (s.fRememberZoomLevel) { - ZoomVideoWindow(); - } - m_bNeedZoomAfterFullscreenExit = false; - } - - if (s.fShowOSD) { - m_OSD.Start(m_pOSDWnd); - } - MoveVideoWindow(); - RecalcLayout(); - } else { - // Set the fullscreen display mode - if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo) { - AutoChangeMonitorMode(); - } - - // Create a new D3D Fullscreen window - CreateFullScreenWindow(); - - m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN_D3D); - - // Assign the windowed video frame and pass it to the relevant classes. - m_pVideoWnd = m_pDedicatedFSVideoWnd; - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - m_wndView.Invalidate(); - - MoveVideoWindow(); - - // Turn on D3D Fullscreen - m_pD3DFSC->SetD3DFullscreen(true); - - if (s.fShowOSD || s.fShowDebugInfo) { - if (m_pVMB || m_pMFVMB) { - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); - } - } - - m_eventc.FireEvent(MpcEvent::SWITCHED_TO_FULLSCREEN_D3D); - } - } else { - ASSERT(false); - } -} - -bool CMainFrame::GetCurDispMode(const CString& displayName, DisplayMode& dm) -{ - return GetDispMode(displayName, ENUM_CURRENT_SETTINGS, dm); -} - -bool CMainFrame::GetDispMode(CString displayName, int i, DisplayMode& dm) -{ - if (displayName == _T("Current") || displayName.IsEmpty()) { - CMonitor monitor = CMonitors::GetNearestMonitor(AfxGetApp()->m_pMainWnd); - monitor.GetName(displayName); - } - - DEVMODE devmode; - devmode.dmSize = sizeof(DEVMODE); - devmode.dmDriverExtra = 0; - - dm.bValid = !!EnumDisplaySettingsExW(displayName, i, &devmode, EDS_RAWMODE); - - if (dm.bValid) { - dm.size = CSize(devmode.dmPelsWidth, devmode.dmPelsHeight); - dm.bpp = devmode.dmBitsPerPel; - dm.freq = devmode.dmDisplayFrequency; - dm.dwDisplayFlags = devmode.dmDisplayFlags; - } - - return dm.bValid; -} - -void CMainFrame::SetDispMode(CString displayName, const DisplayMode& dm, int msAudioDelay) -{ - DisplayMode dmCurrent; - if (!GetCurDispMode(displayName, dmCurrent)) { - return; - } - - CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); - if (dm.size == dmCurrent.size && dm.bpp == dmCurrent.bpp && dm.freq == dmCurrent.freq) { - if (pASF) { - pASF->SetAudioTimeShift(msAudioDelay * 10000i64); - } - return; - } - - DEVMODE dmScreenSettings; - ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings)); - dmScreenSettings.dmSize = sizeof(dmScreenSettings); - dmScreenSettings.dmPelsWidth = dm.size.cx; - dmScreenSettings.dmPelsHeight = dm.size.cy; - dmScreenSettings.dmBitsPerPel = dm.bpp; - dmScreenSettings.dmDisplayFrequency = dm.freq; - dmScreenSettings.dmDisplayFlags = dm.dwDisplayFlags; - dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; - - if (displayName == _T("Current") || displayName.IsEmpty()) { - CMonitor monitor = CMonitors::GetNearestMonitor(AfxGetApp()->m_pMainWnd); - monitor.GetName(displayName); - } - - const auto& s = AfxGetAppSettings(); - LONG ret; - - m_eventc.FireEvent(MpcEvent::DISPLAY_MODE_AUTOCHANGING); - if (AfxGetAppSettings().autoChangeFSMode.bRestoreResAfterProgExit) { - ret = ChangeDisplaySettingsExW(displayName, &dmScreenSettings, nullptr, CDS_FULLSCREEN, nullptr); - } else { - ret = ChangeDisplaySettingsExW(displayName, &dmScreenSettings, nullptr, 0, nullptr); - } - m_eventc.FireEvent(MpcEvent::DISPLAY_MODE_AUTOCHANGED); - - msAudioDelay = ret == DISP_CHANGE_SUCCESSFUL ? msAudioDelay : (s.fAudioTimeShift ? s.iAudioTimeShift : 0); - if (pASF) { - pASF->SetAudioTimeShift(msAudioDelay * 10000i64); - } -} - -void CMainFrame::AutoChangeMonitorMode() -{ - const CAppSettings& s = AfxGetAppSettings(); - if (s.autoChangeFSMode.modes.empty()) { - return; - } - - double dMediaFPS = 0.0; - - if (GetPlaybackMode() == PM_FILE) { - REFERENCE_TIME m_rtTimePerFrame = 1; - // if ExtractAvgTimePerFrame isn't executed then MediaFPS=10000000.0, - // (int)(MediaFPS + 0.5)=10000000 and SetDispMode is executed to Default. - BeginEnumFilters(m_pGB, pEF, pBF) { - BeginEnumPins(pBF, pEP, pPin) { - CMediaTypeEx mt; - PIN_DIRECTION dir; - if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_OUTPUT && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame)) { - if (m_rtTimePerFrame == 0) { - m_rtTimePerFrame = 1; - } - } - } - } - EndEnumPins; - } - EndEnumFilters; - dMediaFPS = 10000000.0 / m_rtTimePerFrame; - } else if (GetPlaybackMode() == PM_DVD) { - DVD_PLAYBACK_LOCATION2 Location; - if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) { - dMediaFPS = 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; - } - } - - for (const auto& mode : s.autoChangeFSMode.modes) { - if (mode.bChecked && dMediaFPS >= mode.dFrameRateStart && dMediaFPS <= mode.dFrameRateStop) { - SetDispMode(s.strFullScreenMonitorID, mode.dm, mode.msAudioDelay); - return; - } - } - SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift -} - -void CMainFrame::MoveVideoWindow(bool fShowStats/* = false*/, bool bSetStoppedVideoRect/* = false*/) -{ - m_dLastVideoScaleFactor = 0; - m_lastVideoSize.SetSize(0, 0); - - if (!m_bDelaySetOutputRect && GetLoadState() == MLS::LOADED && !m_fAudioOnly && IsWindowVisible()) { - CRect windowRect(0, 0, 0, 0); - CRect videoRect(0, 0, 0, 0); - - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->GetClientRect(windowRect); - } else { - m_wndView.GetClientRect(windowRect); - } - - const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); - const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); - if (bPanelsOnVideo) { - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetVisibleDockZones(uTop, uLeft, uRight, uBottom); - if (!bToolbarsOnVideo) { - uBottom -= m_controls.GetVisibleToolbarsHeight(); - } - windowRect.InflateRect(uLeft, uTop, uRight, uBottom); - } else if (bToolbarsOnVideo) { - windowRect.bottom += m_controls.GetVisibleToolbarsHeight(); - } - - int nCompensateForMenubar = m_bShowingFloatingMenubar && !IsD3DFullScreenMode() ? GetSystemMetrics(SM_CYMENU) : 0; - windowRect.bottom += nCompensateForMenubar; - - OAFilterState fs = GetMediaState(); - if (fs != State_Stopped || bSetStoppedVideoRect || m_fShockwaveGraph) { - const CSize szVideo = GetVideoSize(); - - m_dLastVideoScaleFactor = std::min((double)windowRect.Size().cx / szVideo.cx, - (double)windowRect.Size().cy / szVideo.cy); - m_lastVideoSize = szVideo; - - const double dVideoAR = double(szVideo.cx) / szVideo.cy; - - // because we don't have a way to get .swf size reliably, - // other modes don't make sense - const dvstype iDefaultVideoSize = m_fShockwaveGraph ? DVS_STRETCH : - static_cast(AfxGetAppSettings().iDefaultVideoSize); - - const double dWRWidth = windowRect.Width(); - const double dWRHeight = windowRect.Height(); - - double dVRWidth = dWRHeight * dVideoAR; - double dVRHeight; - - double madVRZoomFactor = 1.0; - - switch (iDefaultVideoSize) { - case DVS_HALF: - dVRWidth = szVideo.cx * 0.5; - dVRHeight = szVideo.cy * 0.5; - break; - case DVS_NORMAL: - dVRWidth = szVideo.cx; - dVRHeight = szVideo.cy; - break; - case DVS_DOUBLE: - dVRWidth = szVideo.cx * 2.0; - dVRHeight = szVideo.cy * 2.0; - break; - case DVS_STRETCH: - dVRWidth = dWRWidth; - dVRHeight = dWRHeight; - break; - default: - ASSERT(FALSE); - [[fallthrough]]; // Fallback to "Touch Window From Inside" if settings were corrupted. - case DVS_FROMINSIDE: - if (dWRWidth < dVRWidth) { - dVRWidth = dWRWidth; - dVRHeight = dVRWidth / dVideoAR; - } else { - dVRHeight = dWRHeight; - } - break; - case DVS_FROMOUTSIDE: - if (dWRWidth > dVRWidth) { - dVRWidth = dWRWidth; - dVRHeight = dVRWidth / dVideoAR; - } else { - dVRHeight = dWRHeight; - } - break; - case DVS_ZOOM1: - case DVS_ZOOM2: { - double scale = iDefaultVideoSize == DVS_ZOOM1 ? 1.0 / 3.0 : 2.0 / 3.0; - double minw = std::min(dWRWidth, dVRWidth); - double zoomValue = (std::max(dWRWidth, dVRWidth) - minw) * scale; - madVRZoomFactor = (minw + zoomValue) / minw; - dVRWidth = minw + zoomValue; - dVRHeight = dVRWidth / dVideoAR; - break; - } - } - - // Scale video frame - double dScaledVRWidth = m_ZoomX * dVRWidth; - double dScaledVRHeight = m_ZoomY * dVRHeight; - - auto vertAlign = AfxGetAppSettings().iVerticalAlignVideo; - double vertAlignOffset = 0; - if (vertAlign == CAppSettings::verticalAlignVideoType::ALIGN_TOP) { - vertAlignOffset = -(dWRHeight - dScaledVRHeight) / 2; - } else if (vertAlign == CAppSettings::verticalAlignVideoType::ALIGN_BOTTOM) { - vertAlignOffset = (dWRHeight - dScaledVRHeight) / 2; - } - - // Position video frame - // left and top parts are allowed to be negative - videoRect.left = lround(m_PosX * (dWRWidth * 3.0 - dScaledVRWidth) - dWRWidth); - videoRect.top = lround(m_PosY * (dWRHeight * 3.0 - dScaledVRHeight) - dWRHeight + vertAlignOffset); - // right and bottom parts are always at picture center or beyond, so never negative - videoRect.right = lround(videoRect.left + dScaledVRWidth); - videoRect.bottom = lround(videoRect.top + dScaledVRHeight); - - ASSERT(videoRect.Width() == lround(dScaledVRWidth)); - ASSERT(videoRect.Height() == lround(dScaledVRHeight)); - - if (m_pMVRC) { - static constexpr const LPCWSTR madVRModesMap[] = { - L"50%", - L"100%", - L"200%", - L"stretch", - L"touchInside", - L"touchOutside", - L"touchInside", - L"touchInside" - }; - - // workaround for rotated video with MadVR - bool swapxy = ((m_iDefRotation + m_AngleZ) / 90) & 1; - double mvr_ZoomX = swapxy ? m_ZoomY : m_ZoomX; - double mvr_ZoomY = swapxy ? m_ZoomX : m_ZoomY; - double mvr_PosX = swapxy ? m_PosY : m_PosX; - double mvr_PosY = swapxy ? m_PosX : m_PosY; - - m_pMVRC->SendCommandString("setZoomMode", const_cast(madVRModesMap[iDefaultVideoSize])); - m_pMVRC->SendCommandDouble("setZoomFactorX", madVRZoomFactor * mvr_ZoomX); - m_pMVRC->SendCommandDouble("setZoomFactorY", madVRZoomFactor * mvr_ZoomY); - m_pMVRC->SendCommandDouble("setZoomOffsetX", 2 * mvr_PosX - 1.0); - m_pMVRC->SendCommandDouble("setZoomOffsetY", 2 * mvr_PosY - 1.0); - } - - if (fShowStats) { - CString info; - info.Format(_T("Pos %.3f %.3f, Zoom %.3f %.3f, AR %.3f"), m_PosX, m_PosY, m_ZoomX, m_ZoomY, double(videoRect.Width()) / videoRect.Height()); - SendStatusMessage(info, 3000); - } - } else if (m_pMVRC) { - m_pMVRC->SendCommandString("setZoomMode", const_cast(L"autoDetect")); - } - - windowRect.top -= nCompensateForMenubar; - windowRect.bottom -= nCompensateForMenubar; - - if (m_pCAP) { - m_pCAP->SetPosition(windowRect, videoRect); - UpdateSubtitleRenderingParameters(); - } else { - if (m_pBV) { - m_pBV->SetDefaultSourcePosition(); - m_pBV->SetDestinationPosition(videoRect.left, videoRect.top, videoRect.Width(), videoRect.Height()); - } - if (m_pVW) { - m_pVW->SetWindowPosition(windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height()); - } - - if (m_pMFVDC) { - m_pMFVDC->SetVideoPosition(nullptr, &windowRect); - } - } - - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->SetVideoRect(&windowRect); - } else { - m_wndView.SetVideoRect(&windowRect); - } - } else { - m_wndView.SetVideoRect(); - } -} - -void CMainFrame::SetPreviewVideoPosition() { - if (m_bUseSeekPreview) { - CPoint point; - GetCursorPos(&point); - m_wndSeekBar.ScreenToClient(&point); - m_wndSeekBar.UpdateToolTipPosition(point); - - CRect wr; - m_wndPreView.GetVideoRect(&wr); - - const CSize ws(wr.Size()); - int w = ws.cx; - int h = ws.cy; - - const CSize arxy(GetVideoSizeWithRotation()); - { - const int dh = ws.cy; - const int dw = MulDiv(dh, arxy.cx, arxy.cy); - - int minw = dw; - int maxw = dw; - if (ws.cx < dw) { - minw = ws.cx; - } else if (ws.cx > dw) { - maxw = ws.cx; - } - - const float scale = 1 / 3.0f; - w = int(minw + (maxw - minw) * scale); - h = MulDiv(w, arxy.cy, arxy.cx); - } - - const CPoint pos(int(m_PosX * (wr.Width() * 3 - w) - wr.Width()), int(m_PosY * (wr.Height() * 3 - h) - wr.Height())); - const CRect vr(pos, CSize(w, h)); - - if (m_pMFVDC_preview) { - m_pMFVDC_preview->SetVideoPosition(nullptr, wr); - m_pMFVDC_preview->SetAspectRatioMode(MFVideoARMode_PreservePicture); - } - if (m_pVMR9C_preview) { - m_pVMR9C_preview->SetVideoPosition(nullptr, wr); - m_pVMR9C_preview->SetAspectRatioMode(VMR9ARMode_LetterBox); - } - if (m_pCAP2_preview) { - m_pCAP2_preview->SetPosition(wr, wr); - } - - if (m_pBV_preview) { - m_pBV_preview->SetDefaultSourcePosition(); - m_pBV_preview->SetDestinationPosition(vr.left, vr.top, vr.Width(), vr.Height()); - } - if (m_pVW_preview) { - m_pVW_preview->SetWindowPosition(wr.left, wr.top, wr.Width(), wr.Height()); - } - } -} - -void CMainFrame::HideVideoWindow(bool fHide) -{ - CRect wr; - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->GetClientRect(&wr); - } else if (!m_fFullScreen) { - m_wndView.GetClientRect(&wr); - } else { - GetWindowRect(&wr); - - // this code is needed to work in fullscreen on secondary monitor - CRect r; - m_wndView.GetWindowRect(&r); - wr -= r.TopLeft(); - } - - if (m_pCAP) { - if (fHide) { - CRect vr = CRect(0, 0, 0, 0); - m_pCAP->SetPosition(vr, vr); // hide - } else { - m_pCAP->SetPosition(wr, wr); // show - } - } - m_bLockedZoomVideoWindow = fHide; -} - -CSize CMainFrame::GetVideoOrArtSize(MINMAXINFO& mmi) -{ - const auto& s = AfxGetAppSettings(); - CSize videoSize; - OnGetMinMaxInfo(&mmi); - - if (m_fAudioOnly) { - videoSize = m_wndView.GetLogoSize(); - - if (videoSize.cx > videoSize.cy) { - if (videoSize.cx > s.nCoverArtSizeLimit) { - videoSize.cy = MulDiv(videoSize.cy, s.nCoverArtSizeLimit, videoSize.cx); - videoSize.cx = s.nCoverArtSizeLimit; - } - } else { - if (videoSize.cy > s.nCoverArtSizeLimit) { - videoSize.cx = MulDiv(videoSize.cx, s.nCoverArtSizeLimit, videoSize.cy); - videoSize.cy = s.nCoverArtSizeLimit; - } - } - } else { - videoSize = GetVideoSize(); - } - return videoSize; -} - -CSize CMainFrame::GetZoomWindowSize(double dScale, bool ignore_video_size) -{ - CSize ret; - - if (dScale >= 0.0 && GetLoadState() == MLS::LOADED) { - const auto& s = AfxGetAppSettings(); - MINMAXINFO mmi; - CSize videoSize = GetVideoOrArtSize(mmi); - - if (ignore_video_size || videoSize.cx <= 1 || videoSize.cy <= 1) { - videoSize.SetSize(0, 0); - } - if (videoSize.cx == 0 || m_fAudioOnly && videoSize.cy < 300) { - CRect windowRect; - GetWindowRect(windowRect); - if (windowRect.Height() < 420 && windowRect.Width() < 3800) { - // keep existing width, since it probably was intentionally made wider by user - mmi.ptMinTrackSize.x = std::max(windowRect.Width(), mmi.ptMinTrackSize.x); - if (m_fAudioOnly) { - // also keep existing height - videoSize.SetSize(0, 0); - mmi.ptMinTrackSize.y = std::max(windowRect.Height(), mmi.ptMinTrackSize.y); - } - } - - } - - CSize videoTargetSize = videoSize; - - CSize controlsSize; - const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); - const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); - if (!bPanelsOnVideo) { - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); - if (bToolbarsOnVideo) { - uBottom -= m_controls.GetToolbarsHeight(); - } - controlsSize.cx = uLeft + uRight; - controlsSize.cy = uTop + uBottom; - } else if (!bToolbarsOnVideo) { - controlsSize.cy = m_controls.GetToolbarsHeight(); - } - - CRect decorationsRect; - VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU, - GetWindowExStyle(m_hWnd))); - - CRect workRect; - CMonitors::GetNearestMonitor(this).GetWorkAreaRect(workRect); - - if (workRect.Width() && workRect.Height()) { - // account for invisible borders on Windows 10 by allowing - // the window to go out of screen a bit - if (IsWindows10OrGreater()) { - workRect.InflateRect(GetInvisibleBorderSize()); - } - - if (videoSize.cx > 0) { - // don't go larger than the current monitor working area and prevent black bars in this case - CSize videoSpaceSize = workRect.Size() - controlsSize - decorationsRect.Size(); - - // Do not adjust window size for video frame aspect ratio when video size is independent from window size - const bool bAdjustWindowAR = !(s.iDefaultVideoSize == DVS_HALF || s.iDefaultVideoSize == DVS_NORMAL || s.iDefaultVideoSize == DVS_DOUBLE); - const double videoAR = videoSize.cx / (double)videoSize.cy; - - videoTargetSize = CSize(int(videoSize.cx * dScale + 0.5), int(videoSize.cy * dScale + 0.5)); - - if (videoTargetSize.cx > videoSpaceSize.cx) { - videoTargetSize.cx = videoSpaceSize.cx; - if (bAdjustWindowAR) { - videoTargetSize.cy = std::lround(videoSpaceSize.cx / videoAR); - } - } - - if (videoTargetSize.cy > videoSpaceSize.cy) { - videoTargetSize.cy = videoSpaceSize.cy; - if (bAdjustWindowAR) { - videoTargetSize.cx = std::lround(videoSpaceSize.cy * videoAR); - } - } - } - } else { - ASSERT(FALSE); - } - - ret = videoTargetSize + controlsSize + decorationsRect.Size(); - ret.cx = std::max(ret.cx, mmi.ptMinTrackSize.x); - ret.cy = std::max(ret.cy, mmi.ptMinTrackSize.y); - } else { - ASSERT(FALSE); - } - - return ret; -} - -bool CMainFrame::GetWorkAreaRect(CRect& work) { - MONITORINFO mi = { sizeof(mi) }; - if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { - work = mi.rcWork; - // account for invisible borders on Windows 10 by allowing - // the window to go out of screen a bit - if (IsWindows10OrGreater()) { - work.InflateRect(GetInvisibleBorderSize()); - } - return true; - } - return false; -} - -CRect CMainFrame::GetZoomWindowRect(const CSize& size, bool ignoreSavedPosition /*= false*/) -{ - const auto& s = AfxGetAppSettings(); - CRect ret; - GetWindowRect(ret); - - CRect rcWork; - if (GetWorkAreaRect(rcWork)) { - CSize windowSize(size); - - // don't go larger than the current monitor working area - windowSize.cx = std::min(windowSize.cx, rcWork.Width()); - windowSize.cy = std::min(windowSize.cy, rcWork.Height()); - - // retain snapping or try not to be move the center of the window - // if we don't remember its position - if (m_bWasSnapped && ret.left == rcWork.left) { - // do nothing - } else if (m_bWasSnapped && ret.right == rcWork.right) { - ret.left = ret.right - windowSize.cx; - } else if (!s.fRememberWindowPos || ignoreSavedPosition) { - ret.left += (ret.right - ret.left) / 2 - windowSize.cx / 2; - } - if (m_bWasSnapped && ret.top == rcWork.top) { - // do nothing - } else if (m_bWasSnapped && ret.bottom == rcWork.bottom) { - ret.top = ret.bottom - windowSize.cy; - } else if (!s.fRememberWindowPos || ignoreSavedPosition) { - ret.top += (ret.bottom - ret.top) / 2 - windowSize.cy / 2; - } - - ret.right = ret.left + windowSize.cx; - ret.bottom = ret.top + windowSize.cy; - - // don't go beyond the current monitor working area - if (ret.right > rcWork.right) { - ret.OffsetRect(rcWork.right - ret.right, 0); - } - if (ret.left < rcWork.left) { - ret.OffsetRect(rcWork.left - ret.left, 0); - } - if (ret.bottom > rcWork.bottom) { - ret.OffsetRect(0, rcWork.bottom - ret.bottom); - } - if (ret.top < rcWork.top) { - ret.OffsetRect(0, rcWork.top - ret.top); - } - } else { - ASSERT(FALSE); - } - - return ret; -} - -void CMainFrame::ZoomVideoWindow(double dScale/* = ZOOM_DEFAULT_LEVEL*/, bool ignore_video_size /*= false*/) -{ - const auto& s = AfxGetAppSettings(); - - if ((GetLoadState() != MLS::LOADED) || - (m_nLockedZoomVideoWindow > 0) || m_bLockedZoomVideoWindow) { - if (m_nLockedZoomVideoWindow > 0) { - m_nLockedZoomVideoWindow--; - } - return; - } - - // Leave fullscreen when changing the zoom level - if (IsFullScreenMode()) { - OnViewFullscreen(); - } - - if (!s.HasFixedWindowSize()) { - ShowWindow(SW_SHOWNOACTIVATE); - if (dScale == (double)ZOOM_DEFAULT_LEVEL) { - if (s.fRememberWindowSize) { - return; // ignore default auto-zoom setting - } - dScale = - s.iZoomLevel == -1 ? 0.25 : - s.iZoomLevel == 0 ? 0.5 : - s.iZoomLevel == 1 ? 1.0 : - s.iZoomLevel == 2 ? 2.0 : - s.iZoomLevel == 3 ? GetZoomAutoFitScale() : -// s.iZoomLevel == 4 ? GetZoomAutoFitScale(true) : - 1.0; - } else if (dScale == (double)ZOOM_AUTOFIT) { - dScale = GetZoomAutoFitScale(); - } else if (dScale <= 0.0) { - ASSERT(FALSE); - return; - } - MoveWindow(GetZoomWindowRect(GetZoomWindowSize(dScale, ignore_video_size), !s.fRememberWindowPos)); - } -} - -double CMainFrame::GetZoomAutoFitScale() -{ - if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { - return 1.0; - } - - const CAppSettings& s = AfxGetAppSettings(); - - CSize arxy = GetVideoSize(); - - // get the work area - MONITORINFO mi; - mi.cbSize = sizeof(MONITORINFO); - HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); - GetMonitorInfo(hMonitor, &mi); - RECT& wa = mi.rcWork; - - DWORD style = GetStyle(); - CSize decorationsSize(0, 0); - - if (style & WS_CAPTION) { - // caption - decorationsSize.cy += GetSystemMetrics(SM_CYCAPTION); - // menu - if (s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) { - decorationsSize.cy += GetSystemMetrics(SM_CYMENU); - } - } - - if (style & WS_THICKFRAME) { - // vertical borders - decorationsSize.cx += 2 * ::GetSystemMetrics(SM_CXSIZEFRAME); - // horizontal borders - decorationsSize.cy += 2 * ::GetSystemMetrics(SM_CYSIZEFRAME); - - // account for invisible borders on Windows 10 - if (IsWindows10OrGreater()) { - RECT invisibleBorders = GetInvisibleBorderSize(); - - decorationsSize.cx -= (invisibleBorders.left + invisibleBorders.right); - decorationsSize.cy -= (invisibleBorders.top + invisibleBorders.bottom); - } - - if (!(style & WS_CAPTION)) { - decorationsSize.cx -= 2; - decorationsSize.cy -= 2; - } - } - - const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); - const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); - if (!bPanelsOnVideo) { - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); - if (bToolbarsOnVideo) { - uBottom -= m_controls.GetVisibleToolbarsHeight(); - } - decorationsSize.cx += uLeft + uRight; - decorationsSize.cy += uTop + uBottom; - } else if (!bToolbarsOnVideo) { - decorationsSize.cy -= m_controls.GetVisibleToolbarsHeight(); - } - - LONG width = wa.right - wa.left; - LONG height = wa.bottom - wa.top; - - double sxMin = ((double)width * s.nAutoFitFactorMin / 100 - decorationsSize.cx) / arxy.cx; - double syMin = ((double)height * s.nAutoFitFactorMin / 100 - decorationsSize.cy) / arxy.cy; - sxMin = std::min(sxMin, syMin); - // Take movie aspect ratio into consideration - // The scaling is computed so that the height is an integer value - syMin = floor(arxy.cy * floor(arxy.cx * sxMin + 0.5) / arxy.cx + 0.5) / arxy.cy; - - double sxMax = ((double)width * s.nAutoFitFactorMax / 100 - decorationsSize.cx) / arxy.cx; - double syMax = ((double)height * s.nAutoFitFactorMax / 100 - decorationsSize.cy) / arxy.cy; - sxMax = std::min(sxMax, syMax); - // Take movie aspect ratio into consideration - // The scaling is computed so that the height is an integer value - syMax = floor(arxy.cy * floor(arxy.cx * sxMax + 0.5) / arxy.cx + 0.5) / arxy.cy; - - - if (syMin < 0.0 || syMax < 0.0) { - ASSERT(FALSE); - syMin = 0.0; - syMax = 0.0; - } - - if (syMin > 1.0) { - return syMin; - } - if (syMax < 1.0) { - return syMax; - } - return 1.0; - -} - -void CMainFrame::RepaintVideo(const bool bForceRepaint/* = false*/) -{ - if (!m_bDelaySetOutputRect && (m_pCAP || m_pMFVDC)) { - OAFilterState fs = GetMediaState(); - if (fs == State_Paused || fs == State_Stopped || bForceRepaint || (m_bDVDStillOn && GetPlaybackMode() == PM_DVD)) { - if (m_pCAP) { - m_pCAP->Paint(false); - } else if (m_pMFVDC) { - m_pMFVDC->RepaintVideo(); - } - } - } -} - -ShaderC* CMainFrame::GetShader(CString path, bool bD3D11) -{ - ShaderC* pShader = nullptr; - - CString shadersDir = ShaderList::GetShadersDir(); - CString shadersDir11 = ShaderList::GetShadersDir11(); - CString tPath = path; - tPath.Replace(shadersDir, shadersDir11); - - //if the shader exists in the Shaders11 folder, use that one - if (bD3D11 && ::PathFileExistsW(tPath)) { - path = tPath; - } - - for (auto& shader : m_ShaderCache) { - if (shader.Match(path, bD3D11)) { - pShader = &shader; - break; - } - } - - if (!pShader) { - if (::PathFileExistsW(path)) { - CStdioFile file; - if (file.Open(path, CFile::modeRead | CFile::shareDenyWrite | CFile::typeText)) { - ShaderC shader; - shader.label = path; - - CString str; - file.ReadString(str); // read first string - if (str.Left(25) == L"// $MinimumShaderProfile:") { - shader.profile = str.Mid(25).Trim(); // shader version property - } else { - file.SeekToBegin(); - } - - if (shader.profile == L"ps_4_0" && !bD3D11 || shader.profile == L"ps_5_0") { - ASSERT(false); - return nullptr; - } else if (bD3D11) { - shader.profile = L"ps_4_0"; - } else if (shader.profile == L"ps_3_sw") { - shader.profile = L"ps_3_0"; - } else if (shader.profile != L"ps_2_0" - && shader.profile != L"ps_2_a" - && shader.profile != L"ps_2_b" - && shader.profile != L"ps_3_0") { - shader.profile = L"ps_3_0"; - } - - while (file.ReadString(str)) { - shader.srcdata += str + L"\n"; - } - - shader.length = file.GetLength(); - - FILETIME ftCreate, ftAccess, ftWrite; - if (GetFileTime(file.m_hFile, &ftCreate, &ftAccess, &ftWrite)) { - shader.ftwrite = ftWrite; - } - - file.Close(); - - m_ShaderCache.push_back(shader); - pShader = &m_ShaderCache.back(); - } - } - } - - return pShader; -} - -bool CMainFrame::SaveShaderFile(ShaderC* shader) -{ - CString path; - if (AfxGetMyApp()->GetAppSavePath(path)) { - path.AppendFormat(L"Shaders\\%s.hlsl", static_cast(shader->label)); - - CStdioFile file; - if (file.Open(path, CFile::modeWrite | CFile::shareExclusive | CFile::typeText)) { - file.SetLength(0); - - CString str; - str.Format(L"// $MinimumShaderProfile: %s\n", static_cast(shader->profile)); - file.WriteString(static_cast(str)); - - file.WriteString(static_cast(shader->srcdata)); - file.Close(); - - // delete out-of-date data from the cache - for (auto it = m_ShaderCache.begin(), end = m_ShaderCache.end(); it != end; ++it) { - if (it->Match(shader->label, false)) { - m_ShaderCache.erase(it); - break; - } - } - - return true; - } - } - return false; -} - -bool CMainFrame::DeleteShaderFile(LPCWSTR label) -{ - CString path; - if (AfxGetMyApp()->GetAppSavePath(path)) { - path.AppendFormat(L"Shaders\\%s.hlsl", label); - - if (!::PathFileExistsW(path) || ::DeleteFileW(path)) { - // if the file is missing or deleted successfully, then remove it from the cache - for (auto it = m_ShaderCache.begin(), end = m_ShaderCache.end(); it != end; ++it) { - if (it->Match(label, false)) { - m_ShaderCache.erase(it); - return true; - } - } - } - } - - return false; -} - -void CMainFrame::TidyShaderCache() -{ - CString appsavepath; - if (!AfxGetMyApp()->GetAppSavePath(appsavepath)) { - return; - } - - for (auto it = m_ShaderCache.cbegin(); it != m_ShaderCache.cend(); ) { - CString path(appsavepath); - path += L"Shaders\\"; - path += (*it).label + L".hlsl"; - - CFile file; - if (file.Open(path, CFile::modeRead | CFile::modeCreate | CFile::shareDenyNone)) { - ULONGLONG length = file.GetLength(); - FILETIME ftCreate = {}, ftAccess = {}, ftWrite = {}; - GetFileTime(file.m_hFile, &ftCreate, &ftAccess, &ftWrite); - - file.Close(); - - if ((*it).length == length && CompareFileTime(&(*it).ftwrite, &ftWrite) == 0) { - it++; - continue; // actual shader - } - } - - m_ShaderCache.erase(it++); // outdated shader - } -} - -void CMainFrame::SetShaders(bool bSetPreResize/* = true*/, bool bSetPostResize/* = true*/) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - const auto& s = AfxGetAppSettings(); - bool preFailed = false, postFailed = false; - - if (m_pCAP3) { //interfaces for madVR and MPC-VR - TidyShaderCache(); - const int PShaderMode = m_pCAP3->GetPixelShaderMode(); - if (PShaderMode != 9 && PShaderMode != 11) { - return; - } - - m_pCAP3->ClearPixelShaders(TARGET_FRAME); - m_pCAP3->ClearPixelShaders(TARGET_SCREEN); - int shadercount = 0; - if (bSetPreResize) { - int preTarget; - if (s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { //for now MPC-VR does not support pre-size shaders - preTarget = TARGET_SCREEN; - } else { - preTarget = TARGET_FRAME; - } - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { - ShaderC* pShader = GetShader(shader.filePath, PShaderMode == 11); - if (pShader) { - shadercount++; - CStringW label; - label.Format(L"Shader%d", shadercount); - CStringA profile = pShader->profile; - CStringA srcdata = pShader->srcdata; - if (FAILED(m_pCAP3->AddPixelShader(preTarget, label, profile, srcdata))) { - preFailed = true; - m_pCAP3->ClearPixelShaders(preTarget); - break; - } - } - } - } - if (bSetPostResize) { - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize().ExpandMultiPassShaderList()) { - ShaderC* pShader = GetShader(shader.filePath, PShaderMode == 11); - if (pShader) { - shadercount++; - CStringW label; - label.Format(L"Shader%d", shadercount); - CStringA profile = pShader->profile; - CStringA srcdata = pShader->srcdata; - if (FAILED(m_pCAP3->AddPixelShader(TARGET_SCREEN, label, profile, srcdata))) { - postFailed = true; - m_pCAP3->ClearPixelShaders(TARGET_SCREEN); - break; - } - } - } - } - } else if (m_pCAP2) { - // When pTarget parameter of ISubPicAllocatorPresenter2::SetPixelShader2() is nullptr, - // internal video renderers select maximum available profile and madVR (the only external renderer that - // supports shader part of ISubPicAllocatorPresenter2 interface) seems to ignore it altogether. - m_pCAP2->SetPixelShader2(nullptr, nullptr, false); - if (bSetPreResize) { - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { - if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, false))) { - preFailed = true; - m_pCAP2->SetPixelShader2(nullptr, nullptr, false); - break; - } - } - } - m_pCAP2->SetPixelShader2(nullptr, nullptr, true); - if (bSetPostResize) { - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize().ExpandMultiPassShaderList()) { - if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, true))) { - postFailed = true; - m_pCAP2->SetPixelShader2(nullptr, nullptr, true); - break; - } - } - } - } else if (m_pCAP) { - // shouldn't happen, all known renderers that support ISubPicAllocatorPresenter interface - // support ISubPicAllocatorPresenter2 as well, and it takes priority - ASSERT(FALSE); - m_pCAP->SetPixelShader(nullptr, nullptr); - if (bSetPreResize) { - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { - if (FAILED(m_pCAP->SetPixelShader(shader.GetCode(), nullptr))) { - preFailed = true; - m_pCAP->SetPixelShader(nullptr, nullptr); - break; - } - } - } - postFailed = !s.m_Shaders.GetCurrentPreset().GetPostResize().empty(); - } - - CString errMsg; - if (preFailed && postFailed) { - VERIFY(errMsg.LoadString(IDS_MAINFRM_BOTH_SHADERS_FAILED)); - } else if (preFailed) { - VERIFY(errMsg.LoadString(IDS_MAINFRM_PRE_SHADERS_FAILED)); - } else if (postFailed) { - VERIFY(errMsg.LoadString(IDS_MAINFRM_POST_SHADERS_FAILED)); - } else { - return; - } - SendStatusMessage(errMsg, 3000); -} - -void CMainFrame::SetBalance(int balance) -{ - int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channel - int balance_dB; - if (balance > -100 && balance < 100) { - balance_dB = sign * (int)(100 * 20 * log10(1 - abs(balance) / 100.0f)); - } else { - balance_dB = sign * (-10000); // -10000: only left, 10000: only right - } - - if (GetLoadState() == MLS::LOADED) { - CString strBalance, strBalanceOSD; - - m_pBA->put_Balance(balance_dB); - - if (balance == 0) { - strBalance.LoadString(IDS_BALANCE); - } else if (balance < 0) { - strBalance.Format(IDS_BALANCE_L, -balance); - } else { //if (m_nBalance > 0) - strBalance.Format(IDS_BALANCE_R, balance); - } - - strBalanceOSD.Format(IDS_BALANCE_OSD, strBalance.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, strBalanceOSD); - } -} - -// -// Open/Close -// - -bool PathIsOnOpticalDisc(CString path) -{ - if (path.GetLength() >= 3 && path[1] == L':' && path[2] == L'\\') { - CString drive = path.Left(3); - UINT type = GetDriveType(drive); - return type == DRIVE_CDROM && !IsDriveVirtual(drive); - } - return false; -} - -// Called from GraphThread -void CMainFrame::OpenCreateGraphObject(OpenMediaData* pOMD) -{ - ASSERT(m_pGB == nullptr); - - m_fCustomGraph = false; - m_fShockwaveGraph = false; - - const CAppSettings& s = AfxGetAppSettings(); - - m_pGB_preview = nullptr; - m_bUseSeekPreview = s.fUseSeekbarHover && s.fSeekPreview && m_wndPreView && ::IsWindow(m_wndPreView.m_hWnd) && !(s.nCLSwitches & CLSW_THUMBNAILS); - if (m_bUseSeekPreview) { -#if 1 - if (auto pOpenDVDData = dynamic_cast(pOMD)) { - // preview does not always work good with DVD even when loaded from hdd - m_bUseSeekPreview = false; - } else -#endif - if (OpenFileData* pFileData = dynamic_cast(pOMD)) { - CString fn = pFileData->fns.GetHead(); - if (fn.IsEmpty()) { - m_bUseSeekPreview = false; - } else { - CString ext = CPath(fn).GetExtension().MakeLower(); - if (((fn.Find(L"://") >= 0) || IsAudioFileExt(ext) || ext == L".avs" || PathIsOnOpticalDisc(fn))) { - // disable seek preview for: streaming data, audio files, files on optical disc - m_bUseSeekPreview = false; - } - } - } - } - - if (auto pOpenFileData = dynamic_cast(pOMD)) { - engine_t engine = s.m_Formats.GetEngine(pOpenFileData->fns.GetHead()); - - HRESULT hr = E_FAIL; - CComPtr pUnk; - - if (engine == ShockWave) { - pUnk = (IUnknown*)(INonDelegatingUnknown*)DEBUG_NEW DSObjects::CShockwaveGraph(m_pVideoWnd->m_hWnd, hr); - if (!pUnk) { - throw (UINT)IDS_AG_OUT_OF_MEMORY; - } - - if (SUCCEEDED(hr)) { - m_pGB = CComQIPtr(pUnk); - } - if (FAILED(hr) || !m_pGB) { - throw (UINT)IDS_MAINFRM_77; - } - m_fShockwaveGraph = true; - } - - m_fCustomGraph = m_fShockwaveGraph; - - if (!m_fCustomGraph) { - CFGManagerPlayer* fgm = DEBUG_NEW CFGManagerPlayer(_T("CFGManagerPlayer"), nullptr, m_pVideoWnd->m_hWnd); - if (!pOpenFileData->useragent.IsEmpty()) { - fgm->SetUserAgent(pOpenFileData->useragent); - } - if (!pOpenFileData->referrer.IsEmpty()) { - fgm->SetReferrer(pOpenFileData->referrer); - } - m_pGB = fgm; - - if (m_pGB && m_bUseSeekPreview) { - // build graph for preview - m_pGB_preview = DEBUG_NEW CFGManagerPlayer(L"CFGManagerPlayer", nullptr, m_wndPreView.GetVideoHWND(), true); - } - } - } else if (auto pOpenDVDData = dynamic_cast(pOMD)) { - m_pGB = DEBUG_NEW CFGManagerDVD(_T("CFGManagerDVD"), nullptr, m_pVideoWnd->m_hWnd); - - if (m_bUseSeekPreview) { - if (!PathIsOnOpticalDisc(pOpenDVDData->path)) { - m_pGB_preview = DEBUG_NEW CFGManagerDVD(L"CFGManagerDVD", nullptr, m_wndPreView.GetVideoHWND(), true); - } - } - } else if (auto pOpenDeviceData = dynamic_cast(pOMD)) { - if (s.iDefaultCaptureDevice == 1) { - m_pGB = DEBUG_NEW CFGManagerBDA(_T("CFGManagerBDA"), nullptr, m_pVideoWnd->m_hWnd); - } else { - m_pGB = DEBUG_NEW CFGManagerCapture(_T("CFGManagerCapture"), nullptr, m_pVideoWnd->m_hWnd); - } - } - - if (!m_pGB) { - throw (UINT)IDS_MAINFRM_80; - } - - if (!m_pGB_preview) { - m_bUseSeekPreview = false; - } - - m_pGB->AddToROT(); - - m_pMC = m_pGB; - m_pME = m_pGB; - m_pMS = m_pGB; // general - m_pVW = m_pGB; - m_pBV = m_pGB; // video - m_pBA = m_pGB; // audio - m_pFS = m_pGB; - - if (m_bUseSeekPreview) { - m_pGB_preview->AddToROT(); - - m_pMC_preview = m_pGB_preview; - //m_pME_preview = m_pGB_preview; - m_pMS_preview = m_pGB_preview; // general - m_pVW_preview = m_pGB_preview; - m_pBV_preview = m_pGB_preview; - //m_pFS_preview = m_pGB_preview; - } - - if (!(m_pMC && m_pME && m_pMS) - || !(m_pVW && m_pBV) - || !(m_pBA)) { - throw (UINT)IDS_GRAPH_INTERFACES_ERROR; - } - - if (FAILED(m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0))) { - throw (UINT)IDS_GRAPH_TARGET_WND_ERROR; - } - - m_pProv = (IUnknown*)DEBUG_NEW CKeyProvider(); - - if (CComQIPtr pObjectWithSite = m_pGB) { - pObjectWithSite->SetSite(m_pProv); - } - - m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); -} - -CWnd* CMainFrame::GetModalParent() -{ - const CAppSettings& s = AfxGetAppSettings(); - CWnd* pParentWnd = this; - if (HasDedicatedFSVideoWindow() && s.m_RenderersSettings.m_AdvRendSets.bVMR9FullscreenGUISupport) { - pParentWnd = m_pDedicatedFSVideoWnd; - } - return pParentWnd; -} - -void CMainFrame::ShowMediaTypesDialog() { - if (!m_fOpeningAborted) { - CAutoLock lck(&lockModalDialog); - CComQIPtr pGBDE = m_pGB; - if (pGBDE && pGBDE->GetCount()) { - mediaTypesErrorDlg = DEBUG_NEW CMediaTypesDlg(pGBDE, GetModalParent()); - mediaTypesErrorDlg->DoModal(); - delete mediaTypesErrorDlg; - mediaTypesErrorDlg = nullptr; - } - } -} - -void CMainFrame::ReleasePreviewGraph() -{ - if (m_pGB_preview) { - m_pCAP2_preview.Release(); - m_pMFVP_preview.Release(); - m_pMFVDC_preview.Release(); - m_pVMR9C_preview.Release(); - - //m_pFS_preview.Release(); - m_pMS_preview.Release(); - m_pBV_preview.Release(); - m_pVW_preview.Release(); - //m_pME_preview.Release(); - m_pMC_preview.Release(); - - if (m_pDVDC_preview) { - m_pDVDC_preview.Release(); - m_pDVDI_preview.Release(); - } - - m_pGB_preview->RemoveFromROT(); - m_pGB_preview.Release(); - } -} - -HRESULT CMainFrame::PreviewWindowHide() { - HRESULT hr = S_OK; - - if (!m_bUseSeekPreview) { - return E_FAIL; - } - - if (m_wndPreView.IsWindowVisible()) { - // Disable animation - ANIMATIONINFO AnimationInfo; - AnimationInfo.cbSize = sizeof(ANIMATIONINFO); - ::SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - int WindowAnimationType = AnimationInfo.iMinAnimate; - AnimationInfo.iMinAnimate = 0; - ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - - m_wndPreView.ShowWindow(SW_HIDE); - - // Enable animation - AnimationInfo.iMinAnimate = WindowAnimationType; - ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - - if (m_pGB_preview && m_pMC_preview) { - m_pMC_preview->Pause(); - } - } - - return hr; -} - -HRESULT CMainFrame::PreviewWindowShow(REFERENCE_TIME rtCur2) { - if (!CanPreviewUse()) { - return E_FAIL; - } - - HRESULT hr = S_OK; - if (GetPlaybackMode() == PM_DVD && m_pDVDC_preview) { - DVD_PLAYBACK_LOCATION2 Loc, Loc2; - double fps = 0; - - hr = m_pDVDI->GetCurrentLocation(&Loc); - if (FAILED(hr)) { - return hr; - } - - hr = m_pDVDI_preview->GetCurrentLocation(&Loc2); - - fps = Loc.TimeCodeFlags == DVD_TC_FLAG_25fps ? 25.0 - : Loc.TimeCodeFlags == DVD_TC_FLAG_30fps ? 30.0 - : Loc.TimeCodeFlags == DVD_TC_FLAG_DropFrame ? 29.97 - : 25.0; - - DVD_HMSF_TIMECODE dvdTo = RT2HMSF(rtCur2, fps); - - if (FAILED(hr) || (Loc.TitleNum != Loc2.TitleNum)) { - hr = m_pDVDC_preview->PlayTitle(Loc.TitleNum, DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - return hr; - } - m_pDVDC_preview->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (SUCCEEDED(hr)) { - hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - return hr; - } - } else { - hr = m_pDVDC_preview->PlayChapterInTitle(Loc.TitleNum, 1, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - hr = m_pDVDC_preview->PlayAtTimeInTitle(Loc.TitleNum, &dvdTo, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - return hr; - } - } - } - } else { - hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - return hr; - } - } - - m_pDVDI_preview->GetCurrentLocation(&Loc2); - - m_pMC_preview->Run(); - Sleep(10); - m_pMC_preview->Pause(); - } else if (GetPlaybackMode() == PM_FILE && m_pMS_preview) { - hr = m_pMS_preview->SetPositions(&rtCur2, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } else { - return E_FAIL; - } - - if (FAILED(hr)) { - return hr; - } - - /* - if (GetPlaybackMode() == PM_FILE) { - hr = pFS2 ? pFS2->Step(2, nullptr) : E_FAIL; - if (SUCCEEDED(hr)) { - Sleep(10); - } - } - */ - - if (!m_wndPreView.IsWindowVisible()) { - m_wndPreView.SetRelativeSize(AfxGetAppSettings().iSeekPreviewSize); - m_wndPreView.ShowWindow(SW_SHOWNOACTIVATE); - m_wndPreView.SetWindowSize(); - } - - return hr; -} - -HRESULT CMainFrame::HandleMultipleEntryRar(CStringW fn) { - CRFSList file_list(true); //true = clears itself on destruction - int num_files, num_ok_files; - - CRARFileSource::ScanArchive(fn.GetBuffer(), &file_list, &num_files, &num_ok_files); - if (num_ok_files > 1) { - RarEntrySelectorDialog entrySelector(&file_list, GetModalParent()); - if (IDOK == entrySelector.DoModal()) { - CStringW entryName = entrySelector.GetCurrentEntry(); - if (entryName.GetLength() > 0) { - CComPtr fgm = static_cast(m_pGB.p); - return fgm->RenderRFSFileEntry(fn, nullptr, entryName); - } - } - return RFS_E_ABORT; //we found multiple entries but no entry selected. - } - return E_NOTIMPL; //not a multi-entry rar -} - -// Called from GraphThread -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; - } - if (bMainFile) { - // store info, this is used for skipping to next/previous file - pOFD->title = fn; - lastOpenFile = fn; - } - - CString ext = GetFileExt(fn); - if (ext == ".mpls") { - CString fnn = PathUtils::StripPathOrUrl(fn); - CString tempath(fn); - tempath.Replace(fnn, _T("")); - tempath.Replace(_T("BDMV\\PLAYLIST\\"), _T("")); - CHdmvClipInfo clipinfo; - m_bHasBDMeta = clipinfo.ReadMeta(tempath, m_BDMeta); - } - - HRESULT hr; - HRESULT rarHR = E_NOTIMPL; -#if INTERNAL_SOURCEFILTER_RFS - if (s.SrcFilters[SRC_RFS] && !PathUtils::IsURL(fn)) { - CString ext = CPath(fn).GetExtension().MakeLower(); - if (ext == L".rar") { - rarHR = HandleMultipleEntryRar(fn); - } - } -#endif - - if (E_NOTIMPL == rarHR) { - hr = m_pGB->RenderFile(fn, nullptr); - } else { - hr = rarHR; - } - - if (FAILED(hr)) { - if (bMainFile) { - if (m_pME) { - m_pME->SetNotifyWindow(NULL, 0, 0); - } - - if (s.fReportFailedPins) { - ShowMediaTypesDialog(); - } - - 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; - } - } - - if (bMainFile) { - bool bIsVideo = false; - bool isRFS = false; - CStringW entryRFS; - - // Check for supported interfaces - BeginEnumFilters(m_pGB, pEF, pBF); - bool fsf = false; - CLSID clsid = GetCLSID(pBF); - // IFileSourceFilter - if (!m_pFSF) { - m_pFSF = pBF; - if (m_pFSF) { - fsf = true; - if (!m_pAMNS) { - m_pAMNS = pBF; - } - if (!m_pSplitterSS) { - m_pSplitterSS = pBF; - } - if (m_bUseSeekPreview) { - if (clsid == CLSID_StillVideo || clsid == CLSID_MPCImageSource) { - m_bUseSeekPreview = false; - } else if (clsid == __uuidof(CRARFileSource)) { - WCHAR* pFN = nullptr; - AM_MEDIA_TYPE mt; - if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { - isRFS = true; - entryRFS = pFN; - CoTaskMemFree(pFN); - } - } - } - } - } - // IAMStreamSelect / IDirectVobSub - if (!fsf) { - if (clsid == __uuidof(CAudioSwitcherFilter)) { - m_pAudioSwitcherSS = pBF; - } else { - if (clsid == GUID_LAVSplitter) { - m_pSplitterSS = pBF; - } else { - if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { - m_pDVS = pBF; - m_pDVS2 = pBF; - } else { - if (clsid != CLSID_MPCBEAudioRenderer) { - if (CComQIPtr pTest = pBF) { - if (!m_pOtherSS[0]) { - m_pOtherSS[0] = pBF; - } else if (!m_pOtherSS[1]) { - m_pOtherSS[1] = pBF; - } else { - ASSERT(false); - } - } - } - } - } - } - } - // Others - if (!m_pLN21) { - m_pLN21 = pBF; - } - if (!m_pKFI) { - m_pKFI = pBF; - } - if (!m_pAMOP) { - m_pAMOP = pBF; - } - if (!m_pAMMC[0]) { - m_pAMMC[0] = pBF; - } else if (!m_pAMMC[1]) { - m_pAMMC[1] = pBF; - } - if (m_bUseSeekPreview && !bIsVideo && IsVideoRenderer(pBF)) { - bIsVideo = true; - } - EndEnumFilters; - - ASSERT(m_pFSF); - - if (!bIsVideo) { - m_bUseSeekPreview = false; - } - if (m_bUseSeekPreview && IsImageFile(fn)) { - // don't use preview for images - m_bUseSeekPreview = false; - } - - if (m_bUseSeekPreview) { - HRESULT previewHR; - if (isRFS) { - CComPtr fgm = static_cast(m_pGB_preview.p); - previewHR = fgm->RenderRFSFileEntry(fn, nullptr, entryRFS); - } else { - previewHR = m_pGB_preview->RenderFile(fn, nullptr); - } - - if (FAILED(previewHR)) { - m_bUseSeekPreview = false; - ReleasePreviewGraph(); - } - } - } else { // Audio DUB - // Check for supported interfaces - BeginEnumFilters(m_pGB, pEF, pBF); - CLSID clsid = GetCLSID(pBF); - if (clsid == GUID_LAVSplitter || clsid == GUID_LAVSplitterSource) { - m_pSplitterDubSS = pBF; - if (m_pSplitterSS && m_pSplitterSS == m_pSplitterDubSS) { - m_pSplitterDubSS.Release(); - } - } else if (clsid == __uuidof(CAudioSwitcherFilter)) { - if (!m_pAudioSwitcherSS) { - m_pAudioSwitcherSS = pBF; - } - } - EndEnumFilters; - } - - // We don't keep track of piped inputs since that hardly makes any sense - if (s.fKeepHistory && fn.Find(_T("pipe:")) != 0 && pOFD->bAddToRecent) { - if (bMainFile) { - auto* pMRU = &s.MRU; - RecentFileEntry r; - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - if (pli.m_bYoutubeDL && !pli.m_ydlSourceURL.IsEmpty()) { - pMRU->LoadMediaHistoryEntryFN(pli.m_ydlSourceURL, r); - } else { - pMRU->LoadMediaHistoryEntryFN(fn, r); - if (pli.m_fns.GetCount() > r.fns.GetCount()) { - r.fns.RemoveAll(); - r.fns.AddHeadList(&pli.m_fns); - } - SHAddToRecentDocs(SHARD_PATH, fn); - } - if (pli.m_cue) { - r.cue = pli.m_cue_filename; - } - if (pli.m_subs.GetCount() > r.subs.GetCount()) { - r.subs.RemoveAll(); - r.subs.AddHeadList(&pli.m_subs); - } - - if (pli.m_label.IsEmpty()) { - CString title; - for (const auto& pAMMC : m_pAMMC) { - if (pAMMC) { - CComBSTR bstr; - if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { - title = bstr.m_str; - title.Trim(); - break; - } - } - } - if (title.GetLength() >= 10 && !IsNameSimilar(title, PathUtils::StripPathOrUrl(fn))) { - r.title = title; - } - } else { - if (pli.m_bYoutubeDL || !IsNameSimilar(pli.m_label, PathUtils::StripPathOrUrl(fn))) { - if (!pli.m_bYoutubeDL || fn == pli.m_ydlSourceURL) { - r.title = pli.m_label; - } else { - CString videoName(pli.m_label); - int m = LastIndexOfCString(videoName, _T(" (")); - if (m > 0) { - videoName = pli.m_label.Left(m); - } - r.title = videoName; - } - } - } - } else { - ASSERT(false); - r.fns.AddHead(fn); - } - - pMRU->Add(r, true); - CStringW playListName; - if (s.bRememberExternalPlaylistPos && m_wndPlaylistBar.IsExternalPlayListActive(playListName)) { - s.SavePlayListPosition(playListName, m_wndPlaylistBar.GetSelIdx()); - } - } - else { - CPlaylistItem pli; - if (!m_wndPlaylistBar.GetCur(pli) || !pli.m_bYoutubeDL) { - CRecentFileList* pMRUDub = &s.MRUDub; - pMRUDub->ReadList(); - pMRUDub->Add(fn); - pMRUDub->WriteList(); - } - } - } - - bMainFile = false; - - if (m_fCustomGraph) { - break; - } - } - - if (s.fReportFailedPins) { - ShowMediaTypesDialog(); - } - - SetupChapters(); - - SetPlaybackMode(PM_FILE); -} - -void CMainFrame::SetupExternalChapters() -{ - // .XCHP (eXternal CHaPters) file format: - // - UTF-8 text file. - // - Located in same folder as the audio/video file, and has same base filename. - // - It will override chapter metadata that is embedded in the file. - // - Each line defines a chapter: timecode, optionally followed by a space and chapter title. - // - Timecode must be in this format: HH:MM:SS,ddd - - CString fn = m_wndPlaylistBar.GetCurFileName(true); - if (fn.IsEmpty() || PathUtils::IsURL(fn)) { - return; - } - - CPath cp(fn); - cp.RenameExtension(_T(".xchp")); - if (!cp.FileExists()) { - return; - } - fn = cp.m_strPath; - - CTextFile f(CTextFile::UTF8); - f.SetFallbackEncoding(CTextFile::ANSI); - - CString str; - if (!f.Open(fn) || !f.ReadString(str)) { - return; - } - - f.Seek(0, CFile::SeekPosition::begin); - - while (f.ReadString(str)) { - REFERENCE_TIME rt = 0; - CString name = ""; - - if (str.GetLength() > 11) { - int lHour = 0; - int lMinute = 0; - int lSecond = 0; - int lMillisec = 0; - if (_stscanf_s(str.Left(12), _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { - rt = ((((lHour * 60) + lMinute) * 60 + lSecond) * MILLISECONDS + lMillisec) * (UNITS / MILLISECONDS); - if (str.GetLength() > 12) { - name = str.Mid(12); - name.Trim(); - } - m_pCB->ChapAppend(rt, name); - } else { - break; - } - } else { - break; - } - } - m_pCB->ChapSort(); -} - -void CMainFrame::SetupChapters() -{ - // Release the old chapter bag and create a new one. - // Due to smart pointers the old chapter bag won't - // be deleted until all classes release it. - m_pCB.Release(); - m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); - - SetupExternalChapters(); - if (m_pCB->ChapGetCount() > 0) { - UpdateSeekbarChapterBag(); - return; - } - - // ToDo: add global pointer list for IDSMChapterBag - CInterfaceList pBFs; - BeginEnumFilters(m_pGB, pEF, pBF); - pBFs.AddTail(pBF); - EndEnumFilters; - - POSITION pos; - - pos = pBFs.GetHeadPosition(); - while (pos && !m_pCB->ChapGetCount()) { - IBaseFilter* pBF = pBFs.GetNext(pos); - - CComQIPtr pCB = pBF; - if (!pCB) { - continue; - } - - for (DWORD i = 0, cnt = pCB->ChapGetCount(); i < cnt; i++) { - REFERENCE_TIME rt; - CComBSTR name; - if (SUCCEEDED(pCB->ChapGet(i, &rt, &name))) { - m_pCB->ChapAppend(rt, name); - } - } - } - - pos = pBFs.GetHeadPosition(); - while (pos && !m_pCB->ChapGetCount()) { - IBaseFilter* pBF = pBFs.GetNext(pos); - - CComQIPtr pCI = pBF; - if (!pCI) { - continue; - } - - CHAR iso6391[3]; - ::GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, iso6391, 3); - CStringA iso6392 = ISOLang::ISO6391To6392(iso6391); - if (iso6392.GetLength() < 3) { - iso6392 = "eng"; - } - - UINT cnt = pCI->GetChapterCount(CHAPTER_ROOT_ID); - for (UINT i = 1; i <= cnt; i++) { - UINT cid = pCI->GetChapterId(CHAPTER_ROOT_ID, i); - - ChapterElement ce; - if (pCI->GetChapterInfo(cid, &ce)) { - char pl[3] = {iso6392[0], iso6392[1], iso6392[2]}; - char cc[] = " "; - CComBSTR name; - name.Attach(pCI->GetChapterStringInfo(cid, pl, cc)); - m_pCB->ChapAppend(ce.rtStart, name); - } - } - } - - pos = pBFs.GetHeadPosition(); - while (pos && !m_pCB->ChapGetCount()) { - IBaseFilter* pBF = pBFs.GetNext(pos); - - CComQIPtr pES = pBF; - if (!pES) { - continue; - } - - long MarkerCount = 0; - if (SUCCEEDED(pES->get_MarkerCount(&MarkerCount))) { - for (long i = 1; i <= MarkerCount; i++) { - double MarkerTime = 0; - if (SUCCEEDED(pES->GetMarkerTime(i, &MarkerTime))) { - CStringW name; - name.Format(IDS_AG_CHAPTER, i); - - CComBSTR bstr; - if (S_OK == pES->GetMarkerName(i, &bstr)) { - name = bstr; - } - - m_pCB->ChapAppend(REFERENCE_TIME(MarkerTime * 10000000), name); - } - } - } - } - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_cue) { - SetupCueChapters(pli.m_cue_filename); - } - - UpdateSeekbarChapterBag(); -} - -void CMainFrame::SetupCueChapters(CString fn) { - CString str; - int cue_index(-1); - - CPlaylistItem pli; - if (!m_wndPlaylistBar.GetCur(pli, true)) { - ASSERT(false); - return; - } - - CWebTextFile f(CTextFile::UTF8); - f.SetFallbackEncoding(CTextFile::ANSI); - if (!f.Open(fn) || !f.ReadString(str)) { - return; - } - f.Seek(0, CFile::SeekPosition::begin); - - CString base; - bool isurl = PathUtils::IsURL(fn); - if (isurl) { - int p = fn.Find(_T('?')); - if (p > 0) { - fn = fn.Left(p); - } - p = fn.ReverseFind(_T('/')); - if (p > 0) { - base = fn.Left(p + 1); - } - } - else { - CPath basefilepath(fn); - basefilepath.RemoveFileSpec(); - basefilepath.AddBackslash(); - base = basefilepath.m_strPath; - } - - CString title; - CString performer; - CAtlList trackl; - CueTrackMeta track; - int trackID(0); - - while (f.ReadString(str)) { - str.Trim(); - if (cue_index == -1 && str.Left(5) == _T("TITLE")) { - title = str.Mid(6).Trim(_T("\"")); - } - else if (cue_index == -1 && str.Left(9) == _T("PERFORMER")) { - performer = str.Mid(10).Trim(_T("\"")); - } - else if (str.Left(4) == _T("FILE")) { - if (str.Right(4) == _T("WAVE") || str.Right(3) == _T("MP3") || str.Right(4) == _T("AIFF")) { // We just support audio file. - cue_index++; - } - } - else if (cue_index >= 0) { - if (str.Left(5) == _T("TRACK") && str.Right(5) == _T("AUDIO")) { - CT2CA tmp(str.Mid(6, str.GetLength() - 12)); - const char* tmp2(tmp); - sscanf_s(tmp2, "%d", &trackID); - if (track.trackID != 0) { - trackl.AddTail(track); - track = CueTrackMeta(); - } - track.trackID = trackID; - } - else if (str.Left(5) == _T("TITLE")) { - track.title = str.Mid(6).Trim(_T("\"")); - } - else if (str.Left(9) == _T("PERFORMER")) { - track.performer = str.Mid(10).Trim(_T("\"")); - } - else if (str.Left(5) == _T("INDEX")) { - CT2CA tmp(str.Mid(6)); - const char* tmp2(tmp); - int i1(0), m(0), s(0), ms(0); - sscanf_s(tmp2, "%d %d:%d:%d", &i1, &m, &s, &ms); - if (i1 != 0) track.time = 10000i64 * ((m * 60 + s) * 1000 + ms); - } - } - } - - if (track.trackID != 0) { - trackl.AddTail(track); - } - - if ((cue_index == 0 && trackl.GetCount() == 1) || cue_index > 1) pli.m_cue = false; // avoid unnecessary parsing of cue again later - - if (trackl.GetCount() >= 1) { - POSITION p = trackl.GetHeadPosition(); - bool b(true); - do { - if (p == trackl.GetTailPosition()) b = false; - CueTrackMeta c(trackl.GetNext(p)); - if (cue_index == 0 || (cue_index > 0 && c.trackID == (pli.m_cue_index + 1))) { - CString label; - if (c.trackID != 0 && !c.title.IsEmpty()) { - label = c.title; - if (!c.performer.IsEmpty()) { - label += (_T(" - ") + c.performer); - } - else if (!performer.IsEmpty()) { - label += (_T(" - ") + performer); - } - } - REFERENCE_TIME time(c.time); - if (cue_index > 0) time = 0; // We don't support gap. - m_pCB->ChapAppend(time, label); - } - } while (b); - } -} - -void CMainFrame::SetupDVDChapters() -{ - // Release the old chapter bag and create a new one. - // Due to smart pointers the old chapter bag won't - // be deleted until all classes release it. - m_pCB.Release(); - m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); - - WCHAR buff[MAX_PATH]; - ULONG len, ulNumOfChapters; - DVD_PLAYBACK_LOCATION2 loc; - - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDVDDirectory(buff, _countof(buff), &len)) - && SUCCEEDED(m_pDVDI->GetCurrentLocation(&loc)) - && SUCCEEDED(m_pDVDI->GetNumberOfChapters(loc.TitleNum, &ulNumOfChapters))) { - CString path; - path.Format(L"%s\\video_ts.IFO", buff); - ULONG VTSN, TTN; - - if (CVobFile::GetTitleInfo(path, loc.TitleNum, VTSN, TTN)) { - path.Format(L"%s\\VTS_%02lu_0.IFO", buff, VTSN); - CAtlList files; - - CVobFile vob; - if (vob.Open(path, files, TTN, false)) { - int iChaptersCount = vob.GetChaptersCount(); - if (ulNumOfChapters == (ULONG)iChaptersCount) { - for (int i = 0; i < iChaptersCount; i++) { - REFERENCE_TIME rt = vob.GetChapterOffset(i); - - CStringW str; - str.Format(IDS_AG_CHAPTER, i + 1); - - m_pCB->ChapAppend(rt, str); - } - } else { - // Parser failed! - ASSERT(FALSE); - } - vob.Close(); - } - } - } - - m_pCB->ChapSort(); - - UpdateSeekbarChapterBag(); -} - -// Called from GraphThread -void CMainFrame::OpenDVD(OpenDVDData* pODD) -{ - lastOpenFile.Empty(); - - HRESULT hr = m_pGB->RenderFile(CStringW(pODD->path), nullptr); - - CAppSettings& s = AfxGetAppSettings(); - - if (s.fReportFailedPins) { - ShowMediaTypesDialog(); - } - - if (SUCCEEDED(hr) && m_bUseSeekPreview) { - if (FAILED(hr = m_pGB_preview->RenderFile(pODD->path, nullptr))) { - m_bUseSeekPreview = false; - } - } - - // Check for supported interfaces - BeginEnumFilters(m_pGB, pEF, pBF) - CLSID clsid = GetCLSID(pBF); - // DVD stuff - if (!m_pDVDC) { - m_pDVDC = pBF; - } - if (!m_pDVDI) { - m_pDVDI = pBF; - } - // IAMStreamSelect filters / IDirectVobSub - if (clsid == __uuidof(CAudioSwitcherFilter)) { - m_pAudioSwitcherSS = pBF; - } else { - if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { - m_pDVS = pBF; - m_pDVS2 = pBF; - } else { - if (clsid != CLSID_MPCBEAudioRenderer) { - if (CComQIPtr pTest = pBF) { - if (!m_pOtherSS[0]) { - m_pOtherSS[0] = pBF; - } else if (!m_pOtherSS[1]) { - m_pOtherSS[1] = pBF; - } else { - ASSERT(false); - } - } - } - } - } - // Others - if (!m_pLN21) { - m_pLN21 = pBF; - } - EndEnumFilters; - - ASSERT(m_pDVDC); - ASSERT(m_pDVDI); - - if (m_bUseSeekPreview) { - BeginEnumFilters(m_pGB_preview, pEF, pBF) { - if ((m_pDVDC_preview = pBF) && (m_pDVDI_preview = pBF)) { - break; - } - } - EndEnumFilters; - } - - if (hr == E_INVALIDARG) { - throw (UINT)IDS_MAINFRM_93; - } else if (hr == VFW_E_CANNOT_RENDER) { - throw (UINT)IDS_DVD_NAV_ALL_PINS_ERROR; - } else if (hr == VFW_S_PARTIAL_RENDER) { - throw (UINT)IDS_DVD_NAV_SOME_PINS_ERROR; - } else if (hr == E_NOINTERFACE || !m_pDVDC || !m_pDVDI) { - throw (UINT)IDS_DVD_INTERFACES_ERROR; - } else if (hr == VFW_E_CANNOT_LOAD_SOURCE_FILTER) { - throw (UINT)IDS_MAINFRM_94; - } else if (FAILED(hr)) { - throw (UINT)IDS_AG_FAILED; - } - - WCHAR buff[MAX_PATH]; - ULONG len = 0; - if (SUCCEEDED(hr = m_pDVDI->GetDVDDirectory(buff, _countof(buff), &len))) { - pODD->title = CString(CStringW(buff)).TrimRight(_T("\\")); - } - - if (s.fKeepHistory) { - ULONGLONG llDVDGuid; - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDiscID(nullptr, &llDVDGuid))) { - auto* pMRU = &s.MRU; - pMRU->Add(pODD->title, llDVDGuid); - } - SHAddToRecentDocs(SHARD_PATH, pODD->title); - } - - // TODO: resetdvd - m_pDVDC->SetOption(DVD_ResetOnStop, FALSE); - m_pDVDC->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); - - if (m_bUseSeekPreview && m_pDVDC_preview) { - m_pDVDC_preview->SetOption(DVD_ResetOnStop, FALSE); - m_pDVDC_preview->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); - } - - if (s.idMenuLang) { - m_pDVDC->SelectDefaultMenuLanguage(s.idMenuLang); - } - if (s.idAudioLang) { - m_pDVDC->SelectDefaultAudioLanguage(s.idAudioLang, DVD_AUD_EXT_NotSpecified); - } - if (s.idSubtitlesLang) { - m_pDVDC->SelectDefaultSubpictureLanguage(s.idSubtitlesLang, DVD_SP_EXT_NotSpecified); - } - - m_iDVDDomain = DVD_DOMAIN_Stop; - - SetPlaybackMode(PM_DVD); -} - -// Called from GraphThread -HRESULT CMainFrame::OpenBDAGraph() -{ - lastOpenFile.Empty(); - - HRESULT hr = m_pGB->RenderFile(L"", L""); - if (SUCCEEDED(hr)) { - SetPlaybackMode(PM_DIGITAL_CAPTURE); - m_pDVBState = std::make_unique(); - - // Check for supported interfaces - BeginEnumFilters(m_pGB, pEF, pBF); - bool fsf = false; - CLSID clsid = GetCLSID(pBF); - // IFileSourceFilter - if (!m_pFSF) { - m_pFSF = pBF; - if (m_pFSF) { - fsf = true; - if (!m_pAMNS) { - m_pAMNS = pBF; - } - } - } - // IAMStreamSelect / IDirectVobSub - if (!fsf) { - if (clsid == __uuidof(CAudioSwitcherFilter)) { - m_pAudioSwitcherSS = pBF; - } else { - if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { - m_pDVS = pBF; - m_pDVS2 = pBF; - } - } - } - // Others - if (!m_pLN21) { - m_pLN21 = pBF; - } - if (!m_pAMMC[0]) { - m_pAMMC[0] = pBF; - } else if (!m_pAMMC[1]) { - m_pAMMC[1] = pBF; - } - EndEnumFilters; - - ASSERT(m_pFSF); - - // BDA graph builder implements IAMStreamSelect - m_pSplitterSS = m_pGB; - } - return hr; -} - -// Called from GraphThread -void CMainFrame::OpenCapture(OpenDeviceData* pODD) -{ - lastOpenFile.Empty(); - - m_wndCaptureBar.InitControls(); - - CStringW vidfrname, audfrname; - CComPtr pVidCapTmp, pAudCapTmp; - - m_VidDispName = pODD->DisplayName[0]; - - if (!m_VidDispName.IsEmpty()) { - if (!CreateFilter(m_VidDispName, &pVidCapTmp, vidfrname)) { - throw (UINT)IDS_MAINFRM_96; - } - } - - m_AudDispName = pODD->DisplayName[1]; - - if (!m_AudDispName.IsEmpty()) { - if (!CreateFilter(m_AudDispName, &pAudCapTmp, audfrname)) { - throw (UINT)IDS_MAINFRM_96; - } - } - - if (!pVidCapTmp && !pAudCapTmp) { - throw (UINT)IDS_MAINFRM_98; - } - - m_pCGB = nullptr; - m_pVidCap = nullptr; - m_pAudCap = nullptr; - - if (FAILED(m_pCGB.CoCreateInstance(CLSID_CaptureGraphBuilder2))) { - throw (UINT)IDS_MAINFRM_99; - } - - HRESULT hr; - - m_pCGB->SetFiltergraph(m_pGB); - - if (pVidCapTmp) { - if (FAILED(hr = m_pGB->AddFilter(pVidCapTmp, vidfrname))) { - throw (UINT)IDS_CAPTURE_ERROR_VID_FILTER; - } - - m_pVidCap = pVidCapTmp; - - if (!pAudCapTmp) { - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap))) - && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); - } - - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Interleaved, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev))) - && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); - } - - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pVidCap, IID_PPV_ARGS(&m_pAMASC))) - && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pVidCap, IID_PPV_ARGS(&m_pAMASC)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap")); - } else { - m_pAudCap = m_pVidCap; - } - } else { - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); - } - - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); - } - } - - if (FAILED(m_pCGB->FindInterface(&LOOK_UPSTREAM_ONLY, nullptr, m_pVidCap, IID_PPV_ARGS(&m_pAMXBar)))) { - TRACE(_T("Warning: No IAMCrossbar interface was found\n")); - } - - if (FAILED(m_pCGB->FindInterface(&LOOK_UPSTREAM_ONLY, nullptr, m_pVidCap, IID_PPV_ARGS(&m_pAMTuner)))) { - TRACE(_T("Warning: No IAMTVTuner interface was found\n")); - } - // TODO: init m_pAMXBar - - if (m_pAMTuner) { // load saved channel - m_pAMTuner->put_CountryCode(AfxGetApp()->GetProfileInt(_T("Capture"), _T("Country"), 1)); - - int vchannel = pODD->vchannel; - if (vchannel < 0) { - vchannel = AfxGetApp()->GetProfileInt(_T("Capture\\") + CString(m_VidDispName), _T("Channel"), -1); - } - if (vchannel >= 0) { - OAFilterState fs = State_Stopped; - m_pMC->GetState(0, &fs); - if (fs == State_Running) { - MediaControlPause(true); - } - m_pAMTuner->put_Channel(vchannel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT); - if (fs == State_Running) { - MediaControlRun(); - } - } - } - } - - if (pAudCapTmp) { - if (FAILED(hr = m_pGB->AddFilter(pAudCapTmp, CStringW(audfrname)))) { - throw (UINT)IDS_CAPTURE_ERROR_AUD_FILTER; - } - - m_pAudCap = pAudCapTmp; - - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pAudCap, IID_PPV_ARGS(&m_pAMASC))) - && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pAudCap, IID_PPV_ARGS(&m_pAMASC)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap")); - } - } - - if (!(m_pVidCap || m_pAudCap)) { - throw (UINT)IDS_MAINFRM_108; - } - - pODD->title.LoadString(IDS_CAPTURE_LIVE); - - SetPlaybackMode(PM_ANALOG_CAPTURE); -} - -// Called from GraphThread -void CMainFrame::OpenCustomizeGraph() -{ - if (GetPlaybackMode() != PM_FILE && GetPlaybackMode() != PM_DVD) { - return; - } - - CleanGraph(); - - if (GetPlaybackMode() == PM_FILE) { - if (m_pCAP && AfxGetAppSettings().IsISRAutoLoadEnabled()) { - AddTextPassThruFilter(); - } - } - - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - if (r.m_AdvRendSets.bSynchronizeVideo && s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { - HRESULT hr = S_OK; - m_pRefClock = DEBUG_NEW CSyncClockFilter(nullptr, &hr); - - if (SUCCEEDED(hr) && SUCCEEDED(m_pGB->AddFilter(m_pRefClock, L"SyncClock Filter"))) { - CComQIPtr refClock = m_pRefClock; - CComQIPtr mediaFilter = m_pGB; - - if (refClock && mediaFilter) { - VERIFY(SUCCEEDED(mediaFilter->SetSyncSource(refClock))); - mediaFilter = nullptr; - refClock = nullptr; - - VERIFY(SUCCEEDED(m_pRefClock->QueryInterface(IID_PPV_ARGS(&m_pSyncClock)))); - CComQIPtr pAdviser = m_pCAP; - if (pAdviser) { - VERIFY(SUCCEEDED(pAdviser->AdviseSyncClock(m_pSyncClock))); - } - } - } - } - - if (GetPlaybackMode() == PM_DVD) { - if (m_pDVS2) { - if (!m_pSubClock) { - m_pSubClock = DEBUG_NEW CSubClock; - } - m_pDVS2->AdviseSubClock(m_pSubClock); - } - } - - CleanGraph(); -} - -// Called from GraphThread -void CMainFrame::OpenSetupVideo() -{ - m_fAudioOnly = true; - - CSize vs; - - if (m_pMFVDC) { // EVR - m_fAudioOnly = false; - m_pMFVDC->GetNativeVideoSize(&vs, nullptr); - } else if (m_pCAP) { - vs = m_pCAP->GetVideoSize(false); - m_fAudioOnly = (vs.cx <= 0 || vs.cy <= 0); - } else { - if (CComQIPtr pBV = m_pGB) { - pBV->GetVideoSize(&vs.cx, &vs.cy); - - if (vs.cx > 0 && vs.cy > 0) { - m_fAudioOnly = false; - } - } - if (m_fAudioOnly && m_pVW) { - long lVisible; - if (SUCCEEDED(m_pVW->get_Visible(&lVisible))) { - m_pVW->get_Width(&vs.cx); - m_pVW->get_Height(&vs.cy); - if (vs.cx > 0 && vs.cy > 0) { - m_fAudioOnly = false; - } - } - } - } - - if (m_fShockwaveGraph) { - m_fAudioOnly = false; - } - - 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_pVideoWnd->m_hWnd); - - for (CWnd* pWnd = m_pVideoWnd->GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) { - // 1. lets WM_SETCURSOR through (not needed as of now) - // 2. allows CMouse::CursorOnWindow() to work with m_pVideoWnd - pWnd->EnableWindow(FALSE); - } - - if (m_bUseSeekPreview) { - m_pVW_preview->put_Owner((OAHWND)m_wndPreView.GetVideoHWND()); - m_pVW_preview->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); - } - - if (m_fAudioOnly) { - if (HasDedicatedFSVideoWindow() && !AfxGetAppSettings().bFullscreenSeparateControls) { //DedicateFSWindow allowed for audio - m_pDedicatedFSVideoWnd->DestroyWindow(); - } - } else { - m_statusbarVideoSize.Format(_T("%dx%d"), vs.cx, vs.cy); - UpdateDXVAStatus(); - } -} - -// Called from GraphThread -void CMainFrame::OpenSetupAudio() -{ - m_pBA->put_Volume(m_wndToolBar.Volume); - - // FIXME - int balance = AfxGetAppSettings().nBalance; - - int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channel - if (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); -} - -void CMainFrame::OpenSetupCaptureBar() -{ - if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - if (m_pVidCap && m_pAMVSCCap) { - CComQIPtr pVfwCD = m_pVidCap; - - if (!m_pAMXBar && pVfwCD) { - m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, m_pAMVSCCap, pVfwCD); - } else { - m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, m_pAMVSCCap, m_pAMXBar, m_pAMTuner); - } - } - - if (m_pAudCap && m_pAMASC) { - CInterfaceArray pAMAIM; - - BeginEnumPins(m_pAudCap, pEP, pPin) { - if (CComQIPtr pAIM = pPin) { - pAMAIM.Add(pAIM); - } - } - EndEnumPins; - - m_wndCaptureBar.m_capdlg.SetupAudioControls(m_AudDispName, m_pAMASC, pAMAIM); - } - - BuildGraphVideoAudio( - m_wndCaptureBar.m_capdlg.m_fVidPreview, false, - m_wndCaptureBar.m_capdlg.m_fAudPreview, false); - } -} - -void CMainFrame::OpenSetupInfoBar(bool bClear /*= true*/) -{ - bool bRecalcLayout = false; - - if (bClear) { - m_wndInfoBar.RemoveAllLines(); - } - - if (GetPlaybackMode() == PM_FILE) { - CComBSTR bstr; - CString title, author, copyright, rating, description; - if (m_pAMMC[0]) { - for (const auto& pAMMC : m_pAMMC) { - if (pAMMC) { - if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { - title = bstr.m_str; - title.Trim(); - } - bstr.Empty(); - if (SUCCEEDED(pAMMC->get_AuthorName(&bstr)) && bstr.Length()) { - author = bstr.m_str; - } - bstr.Empty(); - if (SUCCEEDED(pAMMC->get_Copyright(&bstr)) && bstr.Length()) { - copyright = bstr.m_str; - } - bstr.Empty(); - if (SUCCEEDED(pAMMC->get_Rating(&bstr)) && bstr.Length()) { - rating = bstr.m_str; - } - bstr.Empty(); - if (SUCCEEDED(pAMMC->get_Description(&bstr)) && bstr.Length()) { - description = bstr.m_str; - } - bstr.Empty(); - } - } - } - - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TITLE), title); - UpdateChapterInInfoBar(); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUTHOR), author); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_COPYRIGHT), copyright); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_RATING), rating); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); - } else if (GetPlaybackMode() == PM_DVD) { - CString info(_T('-')); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), info); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_LOCATION), info); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_VIDEO), info); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUDIO), info); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_SUBTITLES), info); - } - - if (bRecalcLayout) { - RecalcLayout(); - } -} - -void CMainFrame::UpdateChapterInInfoBar() -{ - CString chapter; - if (m_pCB) { - DWORD dwChapCount = m_pCB->ChapGetCount(); - if (dwChapCount) { - REFERENCE_TIME rtNow; - m_pMS->GetCurrentPosition(&rtNow); - - if (m_pCB) { - CComBSTR bstr; - long currentChap = m_pCB->ChapLookup(&rtNow, &bstr); - if (bstr.Length()) { - chapter.Format(_T("%s (%ld/%lu)"), bstr.m_str, std::max(0l, currentChap + 1l), dwChapCount); - } else { - chapter.Format(_T("%ld/%lu"), currentChap + 1, dwChapCount); - } - } - } - } - if (m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CHAPTER), chapter)) { - RecalcLayout(); - } -} - -void CMainFrame::OpenSetupStatsBar() -{ - m_wndStatsBar.RemoveAllLines(); - - if (GetLoadState() == MLS::LOADED) { - CString info(_T('-')); - bool bFoundIBitRateInfo = false; - - BeginEnumFilters(m_pGB, pEF, pBF) { - if (!m_pQP) { - m_pQP = pBF; - } - if (!m_pBI) { - m_pBI = pBF; - } - if (!bFoundIBitRateInfo) { - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pBRI = pPin) { - bFoundIBitRateInfo = true; - break; - } - } - EndEnumPins; - } - if (m_pQP && m_pBI && bFoundIBitRateInfo) { - break; - } - } - EndEnumFilters; - - if (m_pQP) { - m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMERATE), info); - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SYNC_OFFSET), info); - m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMES), info); - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_JITTER), info); - } else { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_PLAYBACK_RATE), info); - } - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), info); - } - if (m_pBI) { - m_wndStatsBar.SetLine(StrRes(IDS_AG_BUFFERS), info); - } - if (bFoundIBitRateInfo) { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_BITRATE), info); - } - } -} - -void CMainFrame::CheckSelectedAudioStream() -{ - int nChannels = 0; - int audiostreamcount = 0; - UINT audiobitmapid = IDB_AUDIOTYPE_NOAUDIO; - m_loadedAudioTrackIndex = -1; - - if (m_pAudioSwitcherSS) { - DWORD cStreams = 0; - if (SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { - LCID lcid = 0; - DWORD dwFlags, dwGroup; - AM_MEDIA_TYPE* pmt = nullptr; - for (DWORD i = 0; i < cStreams; i++) { - if (SUCCEEDED(m_pAudioSwitcherSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 1) { - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - m_loadedAudioTrackIndex = audiostreamcount; - nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - audiostreamcount++; - } - DeleteMediaType(pmt); - } - } - } - } - if (audiostreamcount == 0 && m_pSplitterSS) { - DWORD cStreams = 0; - if (SUCCEEDED(m_pSplitterSS->Count(&cStreams)) && cStreams > 0) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - for (DWORD i = 0; i < cStreams; i++) { - if (SUCCEEDED(m_pSplitterSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 1) { - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - m_loadedAudioTrackIndex = audiostreamcount; - nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - audiostreamcount++; - } - DeleteMediaType(pmt); - } - } - } - } - if (audiostreamcount == 0 && m_pSplitterDubSS) { - DWORD cStreams = 0; - if (SUCCEEDED(m_pSplitterDubSS->Count(&cStreams)) && cStreams > 0) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - for (DWORD i = 0; i < cStreams; i++) { - if (SUCCEEDED(m_pSplitterDubSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 1) { - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - m_loadedAudioTrackIndex = audiostreamcount; - nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - audiostreamcount++; - } - DeleteMediaType(pmt); - } - } - } - } - if (audiostreamcount == 0 && !m_pAudioSwitcherSS) { // Fallback - BeginEnumFilters(m_pGB, pEF, pBF) { - CComQIPtr pBA = pBF; // implemented by audio renderers - bool notrenderer = false; - - BeginEnumPins(pBF, pEP, pPin) { - if (S_OK == m_pGB->IsPinDirection(pPin, PINDIR_INPUT) && S_OK == m_pGB->IsPinConnected(pPin)) { - AM_MEDIA_TYPE mt; - if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (mt.majortype == MEDIATYPE_Audio) { - notrenderer = !pBA; - audiostreamcount = 1; - nChannels = UpdateSelectedAudioStreamInfo(-1, &mt, -1); - break; - } else if (mt.majortype == MEDIATYPE_Midi) { - notrenderer = true; - audiostreamcount = 1; - nChannels = UpdateSelectedAudioStreamInfo(-1, &mt, -1); - break; - } - } - } - } - EndEnumPins; - - if (nChannels > 0 && notrenderer) { // prefer audio decoder above renderer - break; - } - } - EndEnumFilters; - } - - if (audiostreamcount == 0) { - m_loadedAudioTrackIndex = -1; - UpdateSelectedAudioStreamInfo(-1, nullptr, -1); - } - - if (nChannels >= 2) { - audiobitmapid = IDB_AUDIOTYPE_STEREO; - } else if (nChannels == 1) { - audiobitmapid = IDB_AUDIOTYPE_MONO; - } - m_wndStatusBar.SetStatusBitmap(audiobitmapid); -} - -void CMainFrame::OpenSetupStatusBar() -{ - m_wndStatusBar.ShowTimer(true); - - if (!m_fCustomGraph) { - CString fcc; - // Find video output pin of the source filter or splitter - BeginEnumFilters(m_pGB, pEF, pBF) { - CLSID clsid = GetCLSID(pBF); - bool splitter = (clsid == GUID_LAVSplitterSource || clsid == GUID_LAVSplitter); - // only process filters that might be splitters - if (splitter || clsid != __uuidof(CAudioSwitcherFilter) && clsid != GUID_LAVVideo && clsid != GUID_LAVAudio) { - int input_pins = 0; - BeginEnumPins(pBF, pEP, pPin) { - PIN_DIRECTION dir; - CMediaTypeEx mt; - if (SUCCEEDED(pPin->QueryDirection(&dir)) && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (dir == PINDIR_OUTPUT) { - if (mt.majortype == MEDIATYPE_Video) { - GetVideoFormatNameFromMediaType(mt.subtype, fcc); - if (splitter) { - break; - } - } - } else { - input_pins++; - splitter = (mt.majortype == MEDIATYPE_Stream); - } - } - } - EndEnumPins; - - if ((input_pins == 0 || splitter) && !fcc.IsEmpty()) { - break; - } - } - } - EndEnumFilters; - - if (!fcc.IsEmpty()) { - m_statusbarVideoFormat = fcc; - } - - CheckSelectedAudioStream(); - } -} - -// Called from GraphThread -void CMainFrame::OpenSetupWindowTitle(bool reset /*= false*/) -{ - CString title(StrRes(IDR_MAINFRAME)); -#ifdef MPCHC_LITE - title += _T(" Lite"); -#endif - - CAppSettings& s = AfxGetAppSettings(); - - int i = s.iTitleBarTextStyle; - - if (!reset && (i == 0 || i == 1)) { - // There is no path in capture mode - if (IsPlaybackCaptureMode()) { - title = GetCaptureTitle(); - } else if (i == 1) { // Show filename or title - if (GetPlaybackMode() == PM_FILE) { - title = getBestTitle(s.fTitleBarTextTitle); - bool has_title = !title.IsEmpty(); - - CStringW fn = GetFileName(); - - if (has_title && !IsNameSimilar(title, fn)) s.MRU.SetCurrentTitle(title); - - if (!has_title) { - title = fn; - } - } else if (GetPlaybackMode() == PM_DVD) { - title = _T("DVD"); - CString path; - ULONG len = 0; - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDVDDirectory(path.GetBufferSetLength(MAX_PATH), MAX_PATH, &len)) && len) { - path.ReleaseBuffer(); - if (path.Find(_T("\\VIDEO_TS")) == 2) { - title.AppendFormat(_T(" - %s"), GetDriveLabel(CPath(path)).GetString()); - } - } - } - } else { // Show full path - if (GetPlaybackMode() == PM_FILE) { - title = m_wndPlaylistBar.GetCurFileNameTitle(); - } else if (GetPlaybackMode() == PM_DVD) { - title = _T("DVD"); - ULONG len = 0; - if (m_pDVDI) { - VERIFY(SUCCEEDED(m_pDVDI->GetDVDDirectory(title.GetBufferSetLength(MAX_PATH), MAX_PATH, &len))); - title.ReleaseBuffer(); - } - } - } - } - - SetWindowText(title); - m_Lcd.SetMediaTitle(title); -} - -// Called from GraphThread -int CMainFrame::SetupAudioStreams() -{ - bool bIsSplitter = false; - int desiredTrackIndex = m_loadedAudioTrackIndex; - m_loadedAudioTrackIndex = -1; - m_audioTrackCount = 0; - - CComQIPtr pSS = m_pAudioSwitcherSS; - if (!pSS) { - bIsSplitter = true; - pSS = m_pSplitterSS; - } - - DWORD cStreams = 0; - if (pSS && SUCCEEDED(pSS->Count(&cStreams))) { - if (cStreams > 1) { - const CAppSettings& s = AfxGetAppSettings(); - - CAtlArray langs; - int tPos = 0; - CString lang = s.strAudiosLanguageOrder.Tokenize(_T(",; "), tPos); - while (tPos != -1) { - lang.MakeLower(); - langs.Add(lang); - // Try to match the full language if possible - lang = ISOLang::ISO639XToLanguage(CStringA(lang)); - if (!lang.IsEmpty()) { - langs.Add(lang.MakeLower()); - } - lang = s.strAudiosLanguageOrder.Tokenize(_T(",; "), tPos); - } - - int selected = -1, id = 0; - int maxrating = -1; - for (DWORD i = 0; i < cStreams; i++) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - WCHAR* pName = nullptr; - CComPtr pObject; - if (FAILED(pSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pName, &pObject, nullptr))) { - continue; - } - CString name(pName); - CoTaskMemFree(pName); - - if (dwGroup != 1) { - ASSERT(bIsSplitter); - continue; - } - - m_audioTrackCount++; - - int rating = 0; - // If the track is controlled by a splitter and isn't selected at splitter level - if (!(dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE))) { - bool bSkipTrack; - - // If the splitter is the internal LAV Splitter and no language preferences - // have been set at splitter level, we can override its choice safely - CComQIPtr pBF = bIsSplitter ? pSS : reinterpret_cast(pObject.p); - if (pBF && CFGFilterLAV::IsInternalInstance(pBF)) { - bSkipTrack = false; - if (CComQIPtr pLAVFSettings = pBF) { - LPWSTR langPrefs = nullptr; - if (SUCCEEDED(pLAVFSettings->GetPreferredLanguages(&langPrefs)) && langPrefs && wcslen(langPrefs)) { - bSkipTrack = true; - } - CoTaskMemFree(langPrefs); - } - } else { - bSkipTrack = !s.bAllowOverridingExternalSplitterChoice; - } - - if (bSkipTrack) { - id++; - continue; - } - } else if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - // Give selected track a slightly higher rating - rating += 1; - // Get details of currently selected track - m_loadedAudioTrackIndex = m_audioTrackCount - 1; - UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - - DeleteMediaType(pmt); - - name.Trim(); - name.MakeLower(); - - for (size_t j = 0; j < langs.GetCount(); j++) { - int num = _tstoi(langs[j]) - 1; - if (num >= 0) { // this is track number - if (id != num) { - continue; // not matched - } - } else { // this is lang string - int len = langs[j].GetLength(); - if (name.Left(len) != langs[j] && name.Find(_T("[") + langs[j]) < 0) { - continue; // not matched - } - } - rating += 16 * int(langs.GetCount() - j); - break; - } - if (name.Find(_T("[default,forced]")) != -1) { // for LAV Splitter - rating += 4 + 2; - } - if (name.Find(_T("[forced]")) != -1) { - rating += 4; - } - if (name.Find(_T("[default]")) != -1) { - rating += 2; - } - - if (rating > maxrating) { - maxrating = rating; - selected = id; - } - - id++; - } - - if (desiredTrackIndex >= 0 && desiredTrackIndex < m_audioTrackCount) { - selected = desiredTrackIndex; - } - return m_audioTrackCount > 1 ? selected + !bIsSplitter : -1; - } else if (cStreams == 1) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pSS->Info(0, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 1 && (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE))) { - m_loadedAudioTrackIndex = 0; - m_audioTrackCount = 1; - UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - DeleteMediaType(pmt); - return -1; // no need to select a specific track - } - } - } - - return -1; -} - -bool MatchSubtrackWithISOLang(CString& tname, const ISOLangT& l) -{ - int p; - - if (!l.iso6392.IsEmpty()) { - p = tname.Find(_T("[") + l.iso6392 + _T("]")); - if (p > 0) { - return true; - } - p = tname.Find(_T(".") + l.iso6392 + _T(".")); - if (p > 0) { - return true; - } - } - - if (!l.iso6391.IsEmpty()) { - p = tname.Find(_T("[") + l.iso6391 + _T("]")); - if (p > 0) { - return true; - } - p = tname.Find(_T(".") + l.iso6391 + _T(".")); - if (p > 0) { - return true; - } - p = tname.Find(_T("[") + l.iso6391 + _T("-]")); // truncated BCP47 - if (p > 0) { - return true; - } - } - - if (!l.name.IsEmpty()) { - if (l.name == _T("off")) { - return tname.Find(_T("no subtitles")) >= 0; - } - - std::list langlist; - int tPos = 0; - CString lang = l.name.Tokenize(_T(";"), tPos); - while (tPos != -1) { - lang.MakeLower().TrimLeft(); - langlist.emplace_back(lang); - lang = l.name.Tokenize(_T(";"), tPos); - } - - for (auto& substr : langlist) { - p = tname.Find(_T("\t") + substr); - if (p > 0) { - return true; - } - p = tname.Find(_T(".") + substr + _T(".")); - if (p > 0) { - return true; - } - p = tname.Find(_T("[") + substr + _T("]")); - if (p > 0) { - return true; - } - p = tname.Find(substr); - if (p == 0 || p == 3 && tname.Left(3) == _T("s: ")) { // at begin of trackname - return true; - } - } - } - - return false; -} - -// Called from GraphThread -int CMainFrame::SetupSubtitleStreams() -{ - const CAppSettings& s = AfxGetAppSettings(); - - int selected = -1; - - if (!m_pSubStreams.IsEmpty()) { - bool is_external = false; - bool externalPriority = false; - bool has_off_lang = false; - std::list> langs; - int tPos = 0; - CString lang = s.strSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); - while (tPos != -1) { - lang.MakeLower(); - ISOLangT l = ISOLangT(lang, L"", L"", 0); - - if (lang == _T("off")) { - has_off_lang = true; - } else if (lang.Find(L'-') == 2) { - // BCP 47 - } else { - l = ISOLang::ISO639XToISOLang(CStringA(lang)); - if (l.name.IsEmpty()) { // not an ISO code - l.name = lang; - } else { - l.name.MakeLower(); - } - } - - langs.emplace_back(l); - - lang = s.strSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); - } - - int i = 0; - int subcount = m_pSubStreams.GetSize(); - int maxrating = 0; - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - if (m_posFirstExtSub == pos) { - is_external = true; - externalPriority = s.fPrioritizeExternalSubtitles; - } - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - CComPtr pSubStream = subInput.pSubStream; - CComQIPtr pSSF = subInput.pSourceFilter; - - bool bAllowOverridingSplitterChoice; - // If the internal LAV Splitter has its own language preferences set, we choose not to override its choice - if (pSSF && CFGFilterLAV::IsInternalInstance(subInput.pSourceFilter)) { - bAllowOverridingSplitterChoice = true; - if (CComQIPtr pLAVFSettings = subInput.pSourceFilter) { - CComHeapPtr pLangPrefs; - LAVSubtitleMode subtitleMode = pLAVFSettings->GetSubtitleMode(); - if ((((subtitleMode == LAVSubtitleMode_Default && SUCCEEDED(pLAVFSettings->GetPreferredSubtitleLanguages(&pLangPrefs))) - || (subtitleMode == LAVSubtitleMode_Advanced && SUCCEEDED(pLAVFSettings->GetAdvancedSubtitleConfig(&pLangPrefs)))) - && pLangPrefs && wcslen(pLangPrefs)) - || subtitleMode == LAVSubtitleMode_ForcedOnly || subtitleMode == LAVSubtitleMode_NoSubs) { - bAllowOverridingSplitterChoice = false; - } - } - } else { - bAllowOverridingSplitterChoice = s.bAllowOverridingExternalSplitterChoice; - } - - int count = 0; - if (pSSF) { - DWORD cStreams; - if (SUCCEEDED(pSSF->Count(&cStreams))) { - count = (int)cStreams; - } - } else { - count = pSubStream->GetStreamCount(); - } - - for (int j = 0; j < count; j++) { - CComHeapPtr pName; - LCID lcid = 0; - int rating = 0; - if (pSSF) { - DWORD dwFlags, dwGroup = 2; - pSSF->Info(j, nullptr, &dwFlags, &lcid, &dwGroup, &pName, nullptr, nullptr); - if (dwGroup != 2) { // If the track isn't a subtitle track, we skip it - continue; - } else if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - // Give slightly higher priority to the track selected by splitter so that - // we won't override selected track in case all have the same rating. - rating += 1; - } else if (!bAllowOverridingSplitterChoice) { - // If we aren't allowed to modify the splitter choice and the current - // track isn't already selected at splitter level we need to skip it. - i++; - continue; - } - } else { - pSubStream->GetStreamInfo(j, &pName, &lcid); - } - CString name(pName); - name.Trim(); - name.MakeLower(); - - size_t k = 0; - for (const auto& l : langs) { - int num = _tstoi(l.name) - 1; - if (num >= 0) { // this is track number - if (i != num) { - k++; - continue; // not matched - } - } else { // this is lang string - if (lcid == 0 || lcid == LCID(-1) || lcid != l.lcid) { - // no LCID match, analyze track name for language match - if (!MatchSubtrackWithISOLang(name, l)) { - k++; - continue; // not matched - } - } - // LCID match - } - rating += 16 * int(langs.size() - k); - break; - } - - if (is_external) { - if (rating > 0) { - if (externalPriority) { - rating += 16 * int(langs.size() + 1); - } - } else { - if (langs.size() == 0 || name.Find(_T("\t")) == -1) { - // no preferred language or unknown sub language - if (externalPriority) { - rating += 16 * int(langs.size() + 1); - } else { - rating = 1; - } - } - } - } else { - if (s.bPreferDefaultForcedSubtitles) { - if (name.Find(_T("[default,forced]")) != -1) { // for LAV Splitter - rating += 4 + 2; - } - if (name.Find(_T("[forced]")) != -1) { - rating += 2; - } - if (name.Find(_T("[default]")) != -1) { - rating += 4; - } - } -#if 0 - if (rating == 0 && bAllowOverridingSplitterChoice && langs.size() == 0) { - // use first embedded track as fallback if there is no preferred language - rating = 1; - } -#endif - } - - if (rating > maxrating) { - maxrating = rating; - selected = i; - } - i++; - } - } - } - - if (s.IsISRAutoLoadEnabled() && !m_fAudioOnly) { - if (s.bAutoDownloadSubtitles && m_pSubStreams.IsEmpty()) { - m_pSubtitlesProviders->Search(TRUE); - } else if (m_wndSubtitlesDownloadDialog.IsWindowVisible()) { - m_pSubtitlesProviders->Search(FALSE); - } - } - - return selected; -} - -bool CMainFrame::OpenMediaPrivate(CAutoPtr pOMD) -{ - ASSERT(GetLoadState() == MLS::LOADING); - auto& s = AfxGetAppSettings(); - - m_fValidDVDOpen = false; - m_iDefRotation = 0; - - OpenFileData* pFileData = dynamic_cast(pOMD.m_p); - OpenDVDData* pDVDData = dynamic_cast(pOMD.m_p); - OpenDeviceData* pDeviceData = dynamic_cast(pOMD.m_p); - ASSERT(pFileData || pDVDData || pDeviceData); - - m_pCAP3 = nullptr; - m_pCAP2 = nullptr; - m_pCAP = nullptr; - m_pVMRWC = nullptr; - m_pVMRMC = nullptr; - m_pMFVDC = nullptr; - m_pVMB = nullptr; - m_pMFVMB = nullptr; - m_pMFVP = nullptr; - m_pMVRC = nullptr; - m_pMVRI = nullptr; - m_pMVRS = nullptr; - m_pMVRSR = nullptr; - m_pMVRFG = nullptr; - m_pMVTO = nullptr; - m_pD3DFSC = nullptr; - m_pLN21 = nullptr; - m_pCAP2_preview = nullptr; - m_pMFVDC_preview = nullptr; - m_pMFVP_preview = nullptr; - m_pVMR9C_preview = nullptr; - -#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[%u]:\n"), index); - TRACE(_T("\t%ws\n"), path.GetString()); // %ws - wide character string always - index++; - } - } - // Debug trace code - End -#endif - - CString err; - try { - auto checkAborted = [&]() { - if (m_fOpeningAborted) { - throw (UINT)IDS_AG_ABORTED; - } - }; - - OpenCreateGraphObject(pOMD); - checkAborted(); - - if (pFileData) { - OpenFile(pFileData); - } else if (pDVDData) { - 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; - } - - if (!m_pGB) { - throw (UINT)IDS_MAINFRM_88; - } - - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP2), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP3), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRWC), FALSE); // might have IVMRMixerBitmap9, but not IVMRWindowlessControl9 - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRMC), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMB), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVMB), TRUE); - - m_pMVRC = m_pCAP; - m_pMVRI = m_pCAP; - m_pMVRS = m_pCAP; - m_pMVRSR = m_pCAP; - m_pMVRFG = m_pCAP; - m_pMVTO = m_pCAP; - m_pD3DFSC = m_pCAP; - - checkAborted(); - - SetupVMR9ColorControl(); - checkAborted(); - - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVDC), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVP), TRUE); - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } - - // COMMENTED OUT: does not work at this location, need to choose the correct mode (IMFVideoProcessor::SetVideoProcessorMode) - //SetupEVRColorControl(); - - if (m_bUseSeekPreview) { - m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pMFVDC_preview), TRUE); - m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pMFVP_preview), TRUE); - m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pVMR9C_preview), TRUE); - m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pCAP2_preview), TRUE); - - RECT wr; - m_wndPreView.GetVideoRect(&wr); - if (m_pMFVDC_preview) { - m_pMFVDC_preview->SetVideoWindow(m_wndPreView.GetVideoHWND()); - m_pMFVDC_preview->SetVideoPosition(nullptr, &wr); - } - if (m_pCAP2_preview) { - m_pCAP2_preview->SetPosition(wr, wr); - } - } - - if (m_pLN21) { - m_pLN21->SetServiceState(s.fClosedCaptions ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off); - } - - checkAborted(); - - OpenCustomizeGraph(); - checkAborted(); - - OpenSetupVideo(); - checkAborted(); - - if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is used - m_OSD.Stop(); - - if (m_pMVTO) { - m_OSD.Start(m_pVideoWnd, m_pMVTO); - } else if (m_fFullScreen && !m_fAudioOnly && m_pCAP3) { // MPCVR - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); - } else if (!m_fAudioOnly && IsD3DFullScreenMode() && (m_pVMB || m_pMFVMB)) { - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); - } else { - m_OSD.Start(m_pOSDWnd); - } - } - - OpenSetupAudio(); - checkAborted(); - - if (GetPlaybackMode() == PM_FILE && pFileData) { - const CString& fn = pFileData->fns.GetHead(); - // Don't try to save file position if source isn't seekable - REFERENCE_TIME rtPos = 0; - REFERENCE_TIME rtDur = 0; - m_loadedAudioTrackIndex = -1; - m_loadedSubtitleTrackIndex = -1; - - if (m_pMS) { - m_pMS->GetDuration(&rtDur); - } - - m_bRememberFilePos = s.fKeepHistory && s.fRememberFilePos && rtDur > (s.iRememberPosForLongerThan * 10000000i64 * 60i64) && (s.bRememberPosForAudioFiles || !m_fAudioOnly); - - // Set start time but seek only after all files are loaded - if (pFileData->rtStart > 0) { // Check if an explicit start time was given - rtPos = pFileData->rtStart; - } - if (pFileData->abRepeat) { // Check if an explicit a/b repeat time was given - abRepeat = pFileData->abRepeat; - } - - if (m_dwReloadPos > 0) { - if (m_dwReloadPos < rtDur) { - rtPos = m_dwReloadPos; - } - m_dwReloadPos = 0; - } - if (reloadABRepeat) { - abRepeat = reloadABRepeat; - reloadABRepeat = ABRepeat(); - } - - auto* pMRU = &AfxGetAppSettings().MRU; - if (pMRU->rfe_array.GetCount()) { - if (!rtPos && m_bRememberFilePos) { - rtPos = pMRU->GetCurrentFilePosition(); - if (rtPos >= rtDur || rtDur - rtPos < 50000000LL) { - rtPos = 0; - } - } - if (!abRepeat && s.fKeepHistory && s.fRememberFilePos) { - abRepeat = pMRU->GetCurrentABRepeat(); - } - if (s.fKeepHistory && s.bRememberTrackSelection) { - if (m_loadedAudioTrackIndex == -1) { - m_loadedAudioTrackIndex = pMRU->GetCurrentAudioTrack(); - } - if (m_loadedSubtitleTrackIndex == -1) { - m_loadedSubtitleTrackIndex = pMRU->GetCurrentSubtitleTrack(); - } - } - } - - if (abRepeat && abRepeat.positionB > 0) { - // validate - if (abRepeat.positionB > rtDur || abRepeat.positionA >= abRepeat.positionB) { - abRepeat = ABRepeat(); - } - } - if (abRepeat) { - m_wndSeekBar.Invalidate(); - } - - if (rtPos && rtDur) { - m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - - defaultVideoAngle = 0; - if (m_pFSF && (m_pCAP2 || m_pCAP3)) { - CComQIPtr pBF = m_pFSF; - if (GetCLSID(pBF) == GUID_LAVSplitter || GetCLSID(pBF) == GUID_LAVSplitterSource) { - if (CComQIPtr pPB = pBF) { - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("rotation"), &var, nullptr)) && var.vt == VT_BSTR) { - int rotatevalue = _wtoi(var.bstrVal); - if (rotatevalue == 90 || rotatevalue == 180 || rotatevalue == 270) { - m_iDefRotation = rotatevalue; - if (m_pCAP3) { - m_pCAP3->SetRotation(rotatevalue); - } else { - m_pCAP2->SetDefaultVideoAngle(Vector(0, 0, Vector::DegToRad(360 - rotatevalue))); - } - if (m_pCAP2_preview) { - defaultVideoAngle = 360 - rotatevalue; - m_pCAP2_preview->SetDefaultVideoAngle(Vector(0, 0, Vector::DegToRad(defaultVideoAngle))); - } - } - } - var.Clear(); - } - } - } - } - checkAborted(); - - if (m_pCAP && s.IsISRAutoLoadEnabled() && !m_fAudioOnly) { - if (s.fDisableInternalSubtitles) { - m_pSubStreams.RemoveAll(); // Needs to be replaced with code that checks for forced subtitles. - } - m_posFirstExtSub = nullptr; - if (!pOMD->subs.IsEmpty()) { - POSITION pos = pOMD->subs.GetHeadPosition(); - while (pos) { - LoadSubtitle(pOMD->subs.GetNext(pos), nullptr, true); - } - } - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli) && pli.m_bYoutubeDL && !s.sYDLSubsPreference.IsEmpty()) { - POSITION pos2 = pli.m_ydl_subs.GetHeadPosition(); - while (pos2) { - CYoutubeDLInstance::YDLSubInfo ydlsub = pli.m_ydl_subs.GetNext(pos2); - if (!ydlsub.isAutomaticCaptions || s.bUseAutomaticCaptions) { - LoadSubtitle(ydlsub); - } - } - } - } - checkAborted(); - - OpenSetupWindowTitle(); - checkAborted(); - - int audstm; // offset in audio track menu, AudioSwitcher adds an "Options" entry above the audio tracks - audstm = SetupAudioStreams(); - if (audstm >= 0) { - OnPlayAudio(ID_AUDIO_SUBITEM_START + audstm); - } - checkAborted(); - - int substm; - if (m_loadedSubtitleTrackIndex >= 0 && IsValidSubtitleStream(m_loadedSubtitleTrackIndex)) { - substm = m_loadedSubtitleTrackIndex; - } else { - substm = SetupSubtitleStreams(); - } - if (substm >= 0) { - SetSubtitle(substm); - } - checkAborted(); - - // apply /dubdelay command-line switch - // TODO: that command-line switch probably needs revision - if (s.rtShift != 0) { - SetAudioDelay(s.rtShift); - s.rtShift = 0; - } - } catch (LPCTSTR msg) { - err = msg; - } catch (CString& msg) { - err = msg; - } catch (UINT msg) { - err.LoadString(msg); - } - - if (m_bUseSeekPreview && m_pMC_preview) { - m_pMC_preview->Pause(); - } - - m_closingmsg = err; - - auto getMessageArgs = [&]() { - WPARAM wp = pFileData ? PM_FILE : pDVDData ? PM_DVD : pDeviceData ? (s.iDefaultCaptureDevice == 1 ? PM_DIGITAL_CAPTURE : PM_ANALOG_CAPTURE) : PM_NONE; - ASSERT(wp != PM_NONE); - LPARAM lp = (LPARAM)pOMD.Detach(); - ASSERT(lp); - return std::make_pair(wp, lp); - }; - if (err.IsEmpty()) { - auto args = getMessageArgs(); - if (!m_bOpenedThroughThread) { - ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); - OnFilePostOpenmedia(args.first, args.second); - } else { - PostMessage(WM_POSTOPEN, args.first, args.second); - } - } else if (!m_fOpeningAborted) { - auto args = getMessageArgs(); - if (!m_bOpenedThroughThread) { - ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); - OnOpenMediaFailed(args.first, args.second); - } else { - PostMessage(WM_OPENFAILED, args.first, args.second); - } - } - - return err.IsEmpty(); -} - -void CMainFrame::CloseMediaPrivate() -{ - ASSERT(GetLoadState() == MLS::CLOSING); - - MediaControlStop(true); // needed for StreamBufferSource, because m_iMediaLoadState is always MLS::CLOSED // TODO: fix the opening for such media - m_CachedFilterState = -1; - - m_fLiveWM = false; - m_fEndOfStream = false; - m_bBuffering = false; - m_rtDurationOverride = -1; - m_bUsingDXVA = false; - m_audioTrackCount = 0; - if (m_pDVBState) { - m_pDVBState->Join(); - m_pDVBState = nullptr; - } - m_pCB.Release(); - - { - CAutoLock cAutoLock(&m_csSubLock); - m_pCurrentSubInput = SubtitleInput(nullptr); - m_pSubStreams.RemoveAll(); - m_ExternalSubstreams.clear(); - } - m_pSubClock.Release(); - - if (m_pVW && !m_pMVRS) { - m_pVW->put_Owner(NULL); - } - - m_bIsMPCVRExclusiveMode = false; - - // IMPORTANT: IVMRSurfaceAllocatorNotify/IVMRSurfaceAllocatorNotify9 has to be released before the VMR/VMR9, otherwise it will crash in Release() - m_OSD.Stop(); - m_pMVRFG.Release(); - m_pMVRSR.Release(); - m_pMVRS.Release(); - m_pMVRC.Release(); - m_pMVRI.Release(); - m_pMVTO.Release(); - m_pD3DFSC.Release(); - m_pCAP3.Release(); - m_pCAP2.Release(); - m_pCAP.Release(); - m_pVMRWC.Release(); - m_pVMRMC.Release(); - m_pVMB.Release(); - m_pMFVMB.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(); - m_pFSF.Release(); - m_pKFI.Release(); - m_pAMNS.Release(); - m_pDVS.Release(); - m_pDVS2.Release(); - for (auto& pAMMC : m_pAMMC) { - pAMMC.Release(); - } - m_pAudioSwitcherSS.Release(); - m_pSplitterSS.Release(); - m_pSplitterDubSS.Release(); - for (auto& pSS : m_pOtherSS) { - pSS.Release(); - } - - if (m_pGB) { - m_pGB->RemoveFromROT(); - m_pGB.Release(); - } - - if (m_pGB_preview) { - TRACE(_T("Stopping preview graph\n")); - MediaControlStopPreview(); - TRACE(_T("Releasing preview graph\n")); - ReleasePreviewGraph(); - } - - m_pProv.Release(); - - m_fCustomGraph = m_fShockwaveGraph = false; - - m_lastOMD.Free(); - - m_FontInstaller.UninstallFonts(); -} - -bool CMainFrame::WildcardFileSearch(CString searchstr, std::set& results, bool recurse_dirs) -{ - ExtendMaxPathLengthIfNeeded(searchstr); - - CString path = searchstr; - path.Replace('/', '\\'); - int p = path.ReverseFind('\\'); - if (p < 0) return false; - path = path.Left(p + 1); - - WIN32_FIND_DATA findData; - ZeroMemory(&findData, sizeof(WIN32_FIND_DATA)); - HANDLE h = FindFirstFile(searchstr, &findData); - if (h != INVALID_HANDLE_VALUE) { - CString search_ext = searchstr.Mid(searchstr.ReverseFind('.')).MakeLower(); - bool other_ext = (search_ext != _T(".*")); - CStringW curExt = CPath(m_wndPlaylistBar.GetCurFileName()).GetExtension().MakeLower(); - - do { - CString filename = findData.cFileName; - - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if (recurse_dirs && search_ext == L".*" && filename != L"." && filename != L"..") { - WildcardFileSearch(path + filename + L"\\*.*", results, true); - } - continue; - } - - CString ext = filename.Mid(filename.ReverseFind('.')).MakeLower(); - - if (CanSkipToExt(ext, curExt)) { - /* playlist and cue files should be ignored when searching dir for playable files */ - if (!IsPlaylistFileExt(ext)) { - results.insert(path + filename); - } - } else if (other_ext && search_ext == ext) { - results.insert(path + filename); - if (ext == _T(".rar")) { - break; - } - } - } while (FindNextFile(h, &findData)); - - FindClose(h); - } - - return results.size() > 0; -} - -bool CMainFrame::SearchInDir(bool bDirForward, bool bLoop /*= false*/) -{ - ASSERT(GetPlaybackMode() == PM_FILE || CanSkipFromClosedFile()); - - CString filename; - - auto pFileData = dynamic_cast(m_lastOMD.m_p); - if (!pFileData || !pFileData->title || pFileData->title.IsEmpty()) { - if (CanSkipFromClosedFile()) { - if (m_wndPlaylistBar.GetCount() == 1) { - filename = m_wndPlaylistBar.m_pl.GetHead().m_fns.GetHead(); - } else { - filename = lastOpenFile; - } - } else { - ASSERT(FALSE); - return false; - } - } else { - filename = pFileData->title; - } - - if (PathUtils::IsURL(filename)) { - return false; - } - - int p = filename.ReverseFind(_T('\\')); - if (p < 0) { - return false; - } - CString filemask = filename.Left(p + 1) + _T("*.*"); - std::set filelist; - if (!WildcardFileSearch(filemask, filelist, false)) { - return false; - } - - // We make sure that the currently opened file is added to the list - // even if it's of an unknown format. - auto current = filelist.insert(filename).first; - - if (filelist.size() < 2 && CPath(filename).FileExists()) { - return false; - } - - if (bDirForward) { - current++; - if (current == filelist.end()) { - if (bLoop) { - current = filelist.begin(); - } else { - return false; - } - } - } else { - if (current == filelist.begin()) { - if (bLoop) { - current = filelist.end(); - } else { - return false; - } - } - current--; - } - - CAtlList sl; - sl.AddHead(*current); - m_wndPlaylistBar.Open(sl, false); - OpenCurPlaylistItem(); - - return true; -} - -void CMainFrame::DoTunerScan(TunerScanData* pTSD) -{ - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - bool wasStopped = false; - if (GetMediaState() == State_Stopped) { - SetChannel(-1); - MediaControlRun(); - wasStopped = true; - } - - BOOLEAN bPresent; - BOOLEAN bLocked; - LONG lDbStrength = 0; - LONG lPercentQuality = 0; - int nOffset = pTSD->Offset ? 3 : 1; - LONG lOffsets[3] = {0, pTSD->Offset, -pTSD->Offset}; - m_bStopTunerScan = false; - pTun->Scan(0, 0, 0, NULL); // Clear maps - - for (ULONG ulFrequency = pTSD->FrequencyStart; ulFrequency <= pTSD->FrequencyStop; ulFrequency += pTSD->Bandwidth) { - bool bSucceeded = false; - for (int nOffsetPos = 0; nOffsetPos < nOffset && !bSucceeded; nOffsetPos++) { - if (SUCCEEDED(pTun->SetFrequency(ulFrequency + lOffsets[nOffsetPos], pTSD->Bandwidth, pTSD->SymbolRate))) { - Sleep(200); // Let the tuner some time to detect the signal - if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { - ::SendMessage(pTSD->Hwnd, WM_TUNER_STATS, lDbStrength, lPercentQuality); - pTun->Scan(ulFrequency + lOffsets[nOffsetPos], pTSD->Bandwidth, pTSD->SymbolRate, pTSD->Hwnd); - bSucceeded = true; - } - } - } - - int nProgress = MulDiv(ulFrequency - pTSD->FrequencyStart, 100, pTSD->FrequencyStop - pTSD->FrequencyStart); - ::SendMessage(pTSD->Hwnd, WM_TUNER_SCAN_PROGRESS, nProgress, 0); - ::SendMessage(pTSD->Hwnd, WM_TUNER_STATS, lDbStrength, lPercentQuality); - - if (m_bStopTunerScan) { - break; - } - } - - ::SendMessage(pTSD->Hwnd, WM_TUNER_SCAN_END, 0, 0); - if (wasStopped) { - SetChannel(AfxGetAppSettings().nDVBLastChannel); - MediaControlStop(); - } - } - } -} - -// Skype - -void CMainFrame::SendNowPlayingToSkype() -{ - if (!m_pSkypeMoodMsgHandler) { - return; - } - - CString msg; - - if (GetLoadState() == MLS::LOADED) { - CString title, author; - - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_TITLE), title); - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); - - if (title.IsEmpty()) { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - CString label = !pli.m_label.IsEmpty() ? pli.m_label : pli.m_fns.GetHead(); - - if (GetPlaybackMode() == PM_FILE) { - CString fn = label; - if (!pli.m_bYoutubeDL && PathUtils::IsURL(fn)) { - int i = fn.Find('?'); - if (i >= 0) { - fn = fn.Left(i); - } - } - CPath path(fn); - path.StripPath(); - path.MakePretty(); - path.RemoveExtension(); - title = (LPCTSTR)path; - author.Empty(); - } else if (IsPlaybackCaptureMode()) { - title = GetCaptureTitle(); - author.Empty(); - } else if (GetPlaybackMode() == PM_DVD) { - title = _T("DVD"); - author.Empty(); - } - } - } - - if (!author.IsEmpty()) { - msg.Format(_T("%s - %s"), author.GetString(), title.GetString()); - } else { - msg = title; - } - } - - m_pSkypeMoodMsgHandler->SendMoodMessage(msg); -} - -// dynamic menus - -void CMainFrame::CreateDynamicMenus() -{ - VERIFY(m_openCDsMenu.CreatePopupMenu()); - VERIFY(m_filtersMenu.CreatePopupMenu()); - VERIFY(m_subtitlesMenu.CreatePopupMenu()); - VERIFY(m_audiosMenu.CreatePopupMenu()); - VERIFY(m_videoStreamsMenu.CreatePopupMenu()); - VERIFY(m_chaptersMenu.CreatePopupMenu()); - VERIFY(m_titlesMenu.CreatePopupMenu()); - VERIFY(m_playlistMenu.CreatePopupMenu()); - VERIFY(m_BDPlaylistMenu.CreatePopupMenu()); - VERIFY(m_channelsMenu.CreatePopupMenu()); - VERIFY(m_favoritesMenu.CreatePopupMenu()); - VERIFY(m_shadersMenu.CreatePopupMenu()); - VERIFY(m_recentFilesMenu.CreatePopupMenu()); -} - -void CMainFrame::DestroyDynamicMenus() -{ - VERIFY(m_openCDsMenu.DestroyMenu()); - VERIFY(m_filtersMenu.DestroyMenu()); - VERIFY(m_subtitlesMenu.DestroyMenu()); - VERIFY(m_audiosMenu.DestroyMenu()); - VERIFY(m_videoStreamsMenu.DestroyMenu()); - VERIFY(m_chaptersMenu.DestroyMenu()); - VERIFY(m_titlesMenu.DestroyMenu()); - VERIFY(m_playlistMenu.DestroyMenu()); - VERIFY(m_BDPlaylistMenu.DestroyMenu()); - VERIFY(m_channelsMenu.DestroyMenu()); - VERIFY(m_favoritesMenu.DestroyMenu()); - VERIFY(m_shadersMenu.DestroyMenu()); - VERIFY(m_recentFilesMenu.DestroyMenu()); - m_nJumpToSubMenusCount = 0; -} - -void CMainFrame::SetupOpenCDSubMenu() -{ - CMenu& subMenu = m_openCDsMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (GetLoadState() == MLS::LOADING || AfxGetAppSettings().fHideCDROMsSubMenu) { - return; - } - - UINT id = ID_FILE_OPEN_OPTICAL_DISK_START; - for (TCHAR drive = _T('A'); drive <= _T('Z'); drive++) { - CAtlList files; - OpticalDiskType_t opticalDiskType = GetOpticalDiskType(drive, files); - - if (opticalDiskType != OpticalDisk_NotFound && opticalDiskType != OpticalDisk_Unknown) { - CString label = GetDriveLabel(drive); - if (label.IsEmpty()) { - switch (opticalDiskType) { - case OpticalDisk_Audio: - label = _T("Audio CD"); - break; - case OpticalDisk_VideoCD: - label = _T("(S)VCD"); - break; - case OpticalDisk_DVDVideo: - label = _T("DVD Video"); - break; - case OpticalDisk_BD: - label = _T("Blu-ray Disc"); - break; - default: - ASSERT(FALSE); - break; - } - } - - CString str; - str.Format(_T("%s (%c:)"), label.GetString(), drive); - - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, str)); - } - } -} - -void CMainFrame::SetupFiltersSubMenu() -{ - CMPCThemeMenu& subMenu = m_filtersMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - m_pparray.RemoveAll(); - m_ssarray.RemoveAll(); - - if (GetLoadState() == MLS::LOADED) { - UINT idf = 1; //used as an id, so make non-zero to start - UINT ids = ID_FILTERS_SUBITEM_START; - UINT idl = ID_FILTERSTREAMS_SUBITEM_START; - - BeginEnumFilters(m_pGB, pEF, pBF) { - CString filterName(GetFilterName(pBF)); - if (filterName.GetLength() >= 43) { - filterName = filterName.Left(40) + _T("..."); - } - - CLSID clsid = GetCLSID(pBF); - if (clsid == CLSID_AVIDec) { - CComPtr pPin = GetFirstPin(pBF); - AM_MEDIA_TYPE mt; - if (pPin && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - DWORD c = ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression; - switch (c) { - case BI_RGB: - filterName += _T(" (RGB)"); - break; - case BI_RLE4: - filterName += _T(" (RLE4)"); - break; - case BI_RLE8: - filterName += _T(" (RLE8)"); - break; - case BI_BITFIELDS: - filterName += _T(" (BITF)"); - break; - default: - filterName.AppendFormat(_T(" (%c%c%c%c)"), - (TCHAR)((c >> 0) & 0xff), - (TCHAR)((c >> 8) & 0xff), - (TCHAR)((c >> 16) & 0xff), - (TCHAR)((c >> 24) & 0xff)); - break; - } - } - } else if (clsid == CLSID_ACMWrapper) { - CComPtr pPin = GetFirstPin(pBF); - AM_MEDIA_TYPE mt; - if (pPin && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - WORD c = ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag; - filterName.AppendFormat(_T(" (0x%04x)"), (int)c); - } - } else if (clsid == __uuidof(CTextPassThruFilter) - || clsid == __uuidof(CNullTextRenderer) - || clsid == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) { // ISCR - // hide these - continue; - } - - CMenu internalSubMenu; - VERIFY(internalSubMenu.CreatePopupMenu()); - - int nPPages = 0; - - CComQIPtr pSPP = pBF; - - m_pparray.Add(pBF); - VERIFY(internalSubMenu.AppendMenu(MF_STRING | MF_ENABLED, ids, ResStr(IDS_MAINFRM_116))); - - nPPages++; - - BeginEnumPins(pBF, pEP, pPin) { - CString pinName = GetPinName(pPin); - pinName.Replace(_T("&"), _T("&&")); - - if (pSPP = pPin) { - CAUUID caGUID; - caGUID.pElems = nullptr; - if (SUCCEEDED(pSPP->GetPages(&caGUID)) && caGUID.cElems > 0) { - m_pparray.Add(pPin); - VERIFY(internalSubMenu.AppendMenu(MF_STRING | MF_ENABLED, ids + nPPages, pinName + ResStr(IDS_MAINFRM_117))); - - if (caGUID.pElems) { - CoTaskMemFree(caGUID.pElems); - } - - nPPages++; - } - } - } - EndEnumPins; - - CComQIPtr pSS = pBF; - DWORD nStreams = 0; - if (pSS && SUCCEEDED(pSS->Count(&nStreams))) { - DWORD flags = DWORD_MAX; - DWORD group = DWORD_MAX; - DWORD prevgroup = DWORD_MAX; - LCID lcid = 0; - WCHAR* wname = nullptr; - UINT uMenuFlags; - - if (nStreams > 0 && nPPages > 0) { - VERIFY(internalSubMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - } - - UINT idlstart = idl; - UINT selectedInGroup = 0; - - for (DWORD i = 0; i < nStreams; i++) { - m_ssarray.Add(pSS); - - flags = group = 0; - wname = nullptr; - if (FAILED(pSS->Info(i, nullptr, &flags, &lcid, &group, &wname, nullptr, nullptr))) { - continue; - } - - if (group != prevgroup && idl > idlstart) { - if (selectedInGroup) { - VERIFY(internalSubMenu.CheckMenuRadioItem(idlstart, idl - 1, selectedInGroup, MF_BYCOMMAND)); - selectedInGroup = 0; - } - VERIFY(internalSubMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - idlstart = idl; - } - prevgroup = group; - - uMenuFlags = MF_STRING | MF_ENABLED; - if (flags & AMSTREAMSELECTINFO_EXCLUSIVE) { - selectedInGroup = idl; - } else if (flags & AMSTREAMSELECTINFO_ENABLED) { - uMenuFlags |= MF_CHECKED; - } - - CString streamName; - if (!wname) { - streamName.LoadString(IDS_AG_UNKNOWN_STREAM); - streamName.AppendFormat(_T(" %lu"), i + 1); - } else { - streamName = wname; - streamName.Replace(_T("&"), _T("&&")); - CoTaskMemFree(wname); - } - - VERIFY(internalSubMenu.AppendMenu(uMenuFlags, idl++, streamName)); - } - if (selectedInGroup) { - VERIFY(internalSubMenu.CheckMenuRadioItem(idlstart, idl - 1, selectedInGroup, MF_BYCOMMAND)); - } - - if (nStreams == 0) { - pSS.Release(); - } - } - - if (nPPages == 1 && !pSS) { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ids, filterName)); - } else { - if (nPPages > 0 || pSS) { - UINT nFlags = MF_STRING | MF_POPUP | ((pSPP || pSS) ? MF_ENABLED : MF_GRAYED); - VERIFY(subMenu.AppendMenu(nFlags, (UINT_PTR)internalSubMenu.Detach(), filterName)); - } else { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_GRAYED, idf, filterName)); - } - } - - ids += nPPages; - idf++; - } - EndEnumFilters; - - if (subMenu.GetMenuItemCount() > 0) { - VERIFY(subMenu.InsertMenu(0, MF_STRING | MF_ENABLED | MF_BYPOSITION, ID_FILTERS_COPY_TO_CLIPBOARD, ResStr(IDS_FILTERS_COPY_TO_CLIPBOARD))); - VERIFY(subMenu.InsertMenu(1, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); - } - subMenu.fulfillThemeReqs(); - } -} - -void CMainFrame::SetupAudioSubMenu() -{ - CMenu& subMenu = m_audiosMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (GetLoadState() != MLS::LOADED) { - return; - } - - UINT id = ID_AUDIO_SUBITEM_START; - - DWORD cStreams = 0; - - if (GetPlaybackMode() == PM_DVD) { - currentAudioLang = _T(""); - ULONG ulStreamsAvailable, ulCurrentStream; - if (FAILED(m_pDVDI->GetCurrentAudio(&ulStreamsAvailable, &ulCurrentStream))) { - return; - } - - LCID DefLanguage; - DVD_AUDIO_LANG_EXT ext; - if (FAILED(m_pDVDI->GetDefaultAudioLanguage(&DefLanguage, &ext))) { - return; - } - - for (ULONG i = 0; i < ulStreamsAvailable; i++) { - LCID Language; - if (FAILED(m_pDVDI->GetAudioLanguage(i, &Language))) { - continue; - } - - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (Language == DefLanguage) { - flags |= MF_DEFAULT; - } - if (i == ulCurrentStream) { - flags |= MF_CHECKED; - if (Language) { - GetLocaleString(Language, LOCALE_SISO639LANGNAME2, currentAudioLang); - } - } - - CString str; - if (Language) { - GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); - } else { - str.Format(IDS_AG_UNKNOWN, i + 1); - } - - DVD_AudioAttributes ATR; - if (SUCCEEDED(m_pDVDI->GetAudioAttributes(i, &ATR))) { - switch (ATR.LanguageExtension) { - case DVD_AUD_EXT_NotSpecified: - default: - break; - case DVD_AUD_EXT_Captions: - str += _T(" (Captions)"); - break; - case DVD_AUD_EXT_VisuallyImpaired: - str += _T(" (Visually Impaired)"); - break; - case DVD_AUD_EXT_DirectorComments1: - str.AppendFormat(IDS_MAINFRM_121); - break; - case DVD_AUD_EXT_DirectorComments2: - str.AppendFormat(IDS_MAINFRM_122); - break; - } - - CString format = GetDVDAudioFormatName(ATR); - - if (!format.IsEmpty()) { - str.Format(IDS_MAINFRM_11, - CString(str).GetString(), - format.GetString(), - ATR.dwFrequency, - ATR.bQuantization, - ATR.bNumberOfChannels, - ResStr(ATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString() - ); - } - } - - VERIFY(AppendMenuEx(subMenu, flags, id++, str)); - } - } - // If available use the audio switcher for everything but DVDs - else if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_OPTIONS))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - - long iSel = 0; - - for (long i = 0; i < (long)cStreams; i++) { - DWORD dwFlags; - WCHAR* pName = nullptr; - if (FAILED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, nullptr, &pName, nullptr, nullptr))) { - break; - } - if (dwFlags) { - iSel = i; - } - - CString name(pName); - name.Replace(_T("&"), _T("&&")); - - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); - - CoTaskMemFree(pName); - } - VERIFY(subMenu.CheckMenuRadioItem(2, 2 + cStreams - 1, 2 + iSel, MF_BYPOSITION)); - } else if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - SetupNavStreamSelectSubMenu(subMenu, id, 1); - } -} - -void CMainFrame::SetupSubtitlesSubMenu() -{ - CMenu& subMenu = m_subtitlesMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { - return; - } - - UINT id = ID_SUBTITLES_SUBITEM_START; - - // DVD subtitles in DVD mode are never handled by the internal subtitles renderer - // but it is still possible to load external subtitles so we keep that if block - // separated from the rest - if (GetPlaybackMode() == PM_DVD) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) - && ulStreamsAvailable > 0) { - LCID DefLanguage; - DVD_SUBPICTURE_LANG_EXT ext; - if (FAILED(m_pDVDI->GetDefaultSubpictureLanguage(&DefLanguage, &ext))) { - return; - } - - VERIFY(subMenu.AppendMenu(MF_STRING | (bIsDisabled ? 0 : MF_CHECKED), id++, ResStr(IDS_DVD_SUBTITLES_ENABLE))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - - for (ULONG i = 0; i < ulStreamsAvailable; i++) { - LCID Language; - if (FAILED(m_pDVDI->GetSubpictureLanguage(i, &Language))) { - continue; - } - - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (Language == DefLanguage) { - flags |= MF_DEFAULT; - } - if (i == ulCurrentStream) { - flags |= MF_CHECKED; - } - - CString str; - if (Language) { - GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); - } else { - str.Format(IDS_AG_UNKNOWN, i + 1); - } - - DVD_SubpictureAttributes ATR; - if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(i, &ATR))) { - switch (ATR.LanguageExtension) { - case DVD_SP_EXT_NotSpecified: - default: - break; - case DVD_SP_EXT_Caption_Normal: - str += _T(""); - break; - case DVD_SP_EXT_Caption_Big: - str += _T(" (Big)"); - break; - case DVD_SP_EXT_Caption_Children: - str += _T(" (Children)"); - break; - case DVD_SP_EXT_CC_Normal: - str += _T(" (CC)"); - break; - case DVD_SP_EXT_CC_Big: - str += _T(" (CC Big)"); - break; - case DVD_SP_EXT_CC_Children: - str += _T(" (CC Children)"); - break; - case DVD_SP_EXT_Forced: - str += _T(" (Forced)"); - break; - case DVD_SP_EXT_DirectorComments_Normal: - str += _T(" (Director Comments)"); - break; - case DVD_SP_EXT_DirectorComments_Big: - str += _T(" (Director Comments, Big)"); - break; - case DVD_SP_EXT_DirectorComments_Children: - str += _T(" (Director Comments, Children)"); - break; - } - } - - VERIFY(AppendMenuEx(subMenu, flags, id++, str)); - } - } - } - - POSITION pos = m_pSubStreams.GetHeadPosition(); - - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - DWORD selected = SetupNavStreamSelectSubMenu(subMenu, id, 2); - if (selected != -1) { - SetSubtitle(selected - ID_SUBTITLES_SUBITEM_START); - } - } else if (pos) { // Internal subtitles renderer - int nItemsBeforeStart = id - ID_SUBTITLES_SUBITEM_START; - if (nItemsBeforeStart > 0) { - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - nItemsBeforeStart += 2; // Separators - } - - // Build the static menu's items - bool bTextSubtitles = false; - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_OPTIONS))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_STYLES))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_RELOAD))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_HIDE))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUB_OVERRIDE_DEFAULT_STYLE))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUB_OVERRIDE_ALL_STYLES))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - - // Build the dynamic menu's items - int i = 0, iSelected = -1; - while (pos) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - - if (CComQIPtr pSSF = subInput.pSourceFilter) { - DWORD cStreams; - if (FAILED(pSSF->Count(&cStreams))) { - continue; - } - - for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { - DWORD dwFlags, dwGroup; - CComHeapPtr pszName; - LCID lcid = 0; - if (FAILED(pSSF->Info(j, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - if (dwGroup != 2) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream - && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - iSelected = i; - } - - CString name(pszName); - /* - CString lcname = CString(name).MakeLower(); - if (lcname.Find(_T(" off")) >= 0) { - name.LoadString(IDS_AG_DISABLED); - } - */ - if (lcid != 0 && name.Find(L'\t') < 0) { - CString lcidstr; - GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); - name.Append(_T("\t") + lcidstr); - } - - name.Replace(_T("&"), _T("&&")); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); - i++; - } - } else { - CComPtr pSubStream = subInput.pSubStream; - if (!pSubStream) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - iSelected = i + pSubStream->GetStream(); - } - - for (int j = 0, cnt = pSubStream->GetStreamCount(); j < cnt; j++) { - CComHeapPtr pName; - LCID lcid = 0; - if (SUCCEEDED(pSubStream->GetStreamInfo(j, &pName, &lcid))) { - CString name(pName); - if (lcid != 0 && name.Find(L'\t') < 0) { - CString lcidstr; - GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); - name.Append(_T("\t") + lcidstr); - } - - name.Replace(_T("&"), _T("&&")); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); - } else { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_AG_UNKNOWN_STREAM))); - } - i++; - } - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - CLSID clsid; - if (SUCCEEDED(subInput.pSubStream->GetClassID(&clsid)) - && clsid == __uuidof(CRenderedTextSubtitle)) { - bTextSubtitles = true; - } - } - - // TODO: find a better way to group these entries - /*if (pos && m_pSubStreams.GetAt(pos).subStream) { - CLSID cur, next; - pSubStream->GetClassID(&cur); - m_pSubStreams.GetAt(pos).subStream->GetClassID(&next); - - if (cur != next) { - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - } - }*/ - } - - // Set the menu's items' state - const CAppSettings& s = AfxGetAppSettings(); - // Style - if (!bTextSubtitles) { - subMenu.EnableMenuItem(nItemsBeforeStart + 1, MF_BYPOSITION | MF_GRAYED); - } - // Hide - if (!s.fEnableSubtitles) { - subMenu.CheckMenuItem(nItemsBeforeStart + 4, MF_BYPOSITION | MF_CHECKED); - } - // Style overrides - if (!bTextSubtitles) { - subMenu.EnableMenuItem(nItemsBeforeStart + 5, MF_BYPOSITION | MF_GRAYED); - subMenu.EnableMenuItem(nItemsBeforeStart + 6, MF_BYPOSITION | MF_GRAYED); - } - if (s.bSubtitleOverrideDefaultStyle) { - subMenu.CheckMenuItem(nItemsBeforeStart + 5, MF_BYPOSITION | MF_CHECKED); - } - if (s.bSubtitleOverrideAllStyles) { - subMenu.CheckMenuItem(nItemsBeforeStart + 6, MF_BYPOSITION | MF_CHECKED); - } - if (iSelected >= 0) { - VERIFY(subMenu.CheckMenuRadioItem(nItemsBeforeStart + 8, nItemsBeforeStart + 8 + i - 1, nItemsBeforeStart + 8 + iSelected, MF_BYPOSITION)); - } - } else if (GetPlaybackMode() == PM_FILE) { - SetupNavStreamSelectSubMenu(subMenu, id, 2); - } -} - -void CMainFrame::SetupVideoStreamsSubMenu() -{ - CMenu& subMenu = m_videoStreamsMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (GetLoadState() != MLS::LOADED) { - return; - } - - UINT id = ID_VIDEO_STREAMS_SUBITEM_START; - - if (GetPlaybackMode() == PM_FILE) { - SetupNavStreamSelectSubMenu(subMenu, id, 0); - } else if (GetPlaybackMode() == PM_DVD) { - ULONG ulStreamsAvailable, ulCurrentStream; - if (FAILED(m_pDVDI->GetCurrentAngle(&ulStreamsAvailable, &ulCurrentStream))) { - return; - } - - if (ulStreamsAvailable < 2) { - return; // one choice is not a choice... - } - - for (ULONG i = 1; i <= ulStreamsAvailable; i++) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (i == ulCurrentStream) { - flags |= MF_CHECKED; - } - - CString str; - str.Format(IDS_AG_ANGLE, i); - - VERIFY(subMenu.AppendMenu(flags, id++, str)); - } - } -} - -void CMainFrame::SetupJumpToSubMenus(CMenu* parentMenu /*= nullptr*/, int iInsertPos /*= -1*/) -{ - const CAppSettings& s = AfxGetAppSettings(); - auto emptyMenu = [&](CMPCThemeMenu & menu) { - while (menu.RemoveMenu(0, MF_BYPOSITION)); - }; - - // Empty the submenus - emptyMenu(m_chaptersMenu); - emptyMenu(m_titlesMenu); - emptyMenu(m_playlistMenu); - emptyMenu(m_BDPlaylistMenu); - emptyMenu(m_channelsMenu); - // Remove the submenus from the "Navigate" menu - if (parentMenu && iInsertPos >= 0) { - for (; m_nJumpToSubMenusCount > 0; m_nJumpToSubMenusCount--) { - VERIFY(parentMenu->RemoveMenu(iInsertPos, MF_BYPOSITION)); - } - } - - if (GetLoadState() != MLS::LOADED) { - return; - } - - UINT id = ID_NAVIGATE_JUMPTO_SUBITEM_START, idStart, idSelected; - - auto menuStartRadioSection = [&]() { - idStart = id; - idSelected = UINT_ERROR; - }; - auto menuEndRadioSection = [&](CMenu & menu) { - if (idSelected != UINT_ERROR) { - VERIFY(menu.CheckMenuRadioItem(idStart, id - 1, idSelected, - idStart >= ID_NAVIGATE_JUMPTO_SUBITEM_START ? MF_BYCOMMAND : MF_BYPOSITION)); - } - }; - auto addSubMenuIfPossible = [&](CString subMenuName, CMenu & subMenu) { - if (parentMenu && iInsertPos >= 0) { - if (parentMenu->InsertMenu(iInsertPos + m_nJumpToSubMenusCount, MF_POPUP | MF_BYPOSITION, - (UINT_PTR)(HMENU)subMenu, subMenuName)) { - CMPCThemeMenu::fulfillThemeReqsItem(parentMenu, iInsertPos + m_nJumpToSubMenusCount); - m_nJumpToSubMenusCount++; - } else { - ASSERT(FALSE); - } - } - }; - - if (GetPlaybackMode() == PM_FILE) { - if (m_MPLSPlaylist.size() > 1) { - menuStartRadioSection(); - for (auto& Item : m_MPLSPlaylist) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - CString time = _T("[") + ReftimeToString2(Item.Duration()) + _T("]"); - CString name = PathUtils::StripPathOrUrl(Item.m_strFileName); - - if (name == m_wndPlaylistBar.m_pl.GetHead().GetLabel()) { - idSelected = id; - } - - name.Replace(_T("&"), _T("&&")); - VERIFY(m_BDPlaylistMenu.AppendMenu(flags, id++, name + '\t' + time)); - } - menuEndRadioSection(m_BDPlaylistMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_BD_PLAYLISTS), m_BDPlaylistMenu); - } - - //SetupChapters(); - if (m_pCB && m_pCB->ChapGetCount() > 1) { - REFERENCE_TIME rt = GetPos(); - DWORD j = m_pCB->ChapLookup(&rt, nullptr); - menuStartRadioSection(); - for (DWORD i = 0; i < m_pCB->ChapGetCount(); i++, id++) { - rt = 0; - CComBSTR bstr; - if (FAILED(m_pCB->ChapGet(i, &rt, &bstr))) { - continue; - } - - CString time = _T("[") + ReftimeToString2(rt) + _T("]"); - - CString name = CString(bstr); - name.Replace(_T("&"), _T("&&")); - name.Replace(_T("\t"), _T(" ")); - - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (i == j) { - idSelected = id; - } - - VERIFY(m_chaptersMenu.AppendMenu(flags, id, name + '\t' + time)); - } - menuEndRadioSection(m_chaptersMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHAPTERS), m_chaptersMenu); - } - - if (m_wndPlaylistBar.GetCount() > 1) { - menuStartRadioSection(); - POSITION pos = m_wndPlaylistBar.m_pl.GetHeadPosition(); - while (pos && id < ID_NAVIGATE_JUMPTO_SUBITEM_START + 128) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (pos == m_wndPlaylistBar.m_pl.GetPos()) { - idSelected = id; - } - CPlaylistItem& pli = m_wndPlaylistBar.m_pl.GetNext(pos); - CString name = pli.GetLabel(); - name.Replace(_T("&"), _T("&&")); - VERIFY(m_playlistMenu.AppendMenu(flags, id++, name)); - } - menuEndRadioSection(m_playlistMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_PLAYLIST), m_playlistMenu); - } - } else if (GetPlaybackMode() == PM_DVD) { - ULONG ulNumOfVolumes, ulVolume, ulNumOfTitles, ulNumOfChapters, ulUOPs; - DVD_DISC_SIDE Side; - DVD_PLAYBACK_LOCATION2 Location; - - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location)) - && SUCCEEDED(m_pDVDI->GetCurrentUOPS(&ulUOPs)) - && SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters)) - && SUCCEEDED(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles))) { - menuStartRadioSection(); - for (ULONG i = 1; i <= ulNumOfTitles; i++) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (i == Location.TitleNum) { - idSelected = id; - } - if (ulUOPs & UOP_FLAG_Play_Title) { - flags |= MF_GRAYED; - } - - CString str; - str.Format(IDS_AG_TITLE, i); - - VERIFY(m_titlesMenu.AppendMenu(flags, id++, str)); - } - menuEndRadioSection(m_titlesMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_TITLES), m_titlesMenu); - - menuStartRadioSection(); - for (ULONG i = 1; i <= ulNumOfChapters; i++) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (i == Location.ChapterNum) { - idSelected = id; - } - if (ulUOPs & UOP_FLAG_Play_Chapter) { - flags |= MF_GRAYED; - } - - CString str; - str.Format(IDS_AG_CHAPTER, i); - - VERIFY(m_chaptersMenu.AppendMenu(flags, id++, str)); - } - menuEndRadioSection(m_chaptersMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHAPTERS), m_chaptersMenu); - } - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - menuStartRadioSection(); - for (const auto& channel : s.m_DVBChannels) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - - if (channel.GetPrefNumber() == s.nDVBLastChannel) { - idSelected = id; - } - VERIFY(m_channelsMenu.AppendMenu(flags, ID_NAVIGATE_JUMPTO_SUBITEM_START + channel.GetPrefNumber(), channel.GetName())); - id++; - } - menuEndRadioSection(m_channelsMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHANNELS), m_channelsMenu); - } -} - -DWORD CMainFrame::SetupNavStreamSelectSubMenu(CMenu& subMenu, UINT id, DWORD dwSelGroup) -{ - bool bAddSeparator = false; - DWORD selected = -1; - bool streams_found = false; - - auto addStreamSelectFilter = [&](CComPtr pSS) { - DWORD cStreams; - if (!pSS || FAILED(pSS->Count(&cStreams))) { - return; - } - - bool bAdded = false; - for (DWORD i = 0; i < cStreams; i++) { - DWORD dwFlags, dwGroup; - CComHeapPtr pszName; - LCID lcid = 0; - if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - if (dwGroup != dwSelGroup) { - continue; - } - - CString name(pszName); - /* - CString lcname = CString(name).MakeLower(); - if (dwGroup == 2 && lcname.Find(_T(" off")) >= 0) { - name.LoadString(IDS_AG_DISABLED); - } - */ - if (dwGroup == 2 && lcid != 0 && name.Find(L'\t') < 0) { - CString lcidstr; - GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); - name.Append(_T("\t") + lcidstr); - } - - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (dwFlags) { - flags |= MF_CHECKED; - selected = id; - } - - if (bAddSeparator) { - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - bAddSeparator = false; - } - bAdded = true; - - name.Replace(_T("&"), _T("&&")); - VERIFY(subMenu.AppendMenu(flags, id++, name)); - } - - if (bAdded) { - bAddSeparator = true; - streams_found = true; - } - }; - - if (m_pSplitterSS) { - addStreamSelectFilter(m_pSplitterSS); - } - if (!streams_found && m_pOtherSS[0]) { - addStreamSelectFilter(m_pOtherSS[0]); - } - if (!streams_found && m_pOtherSS[1]) { - addStreamSelectFilter(m_pOtherSS[1]); - } - - return selected; -} - -void CMainFrame::OnNavStreamSelectSubMenu(UINT id, DWORD dwSelGroup) -{ - bool streams_found = false; - - auto processStreamSelectFilter = [&](CComPtr pSS) { - bool bSelected = false; - - DWORD cStreams; - if (SUCCEEDED(pSS->Count(&cStreams))) { - for (int i = 0, j = cStreams; i < j; i++) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - CComHeapPtr pszName; - - if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - if (dwGroup != dwSelGroup) { - continue; - } - - streams_found = true; - - if (id == 0) { - pSS->Enable(i, AMSTREAMSELECTENABLE_ENABLE); - bSelected = true; - break; - } - - id--; - } - } - - return bSelected; - }; - - if (m_pSplitterSS) { - if (processStreamSelectFilter(m_pSplitterSS)) return; - } - if (!streams_found && m_pOtherSS[0]) { - if (processStreamSelectFilter(m_pOtherSS[0])) return; - } - if (!streams_found && m_pOtherSS[1]) { - if (processStreamSelectFilter(m_pOtherSS[1])) return; - } -} - -void CMainFrame::OnStreamSelect(bool bForward, DWORD dwSelGroup) -{ - ASSERT(dwSelGroup == 1 || dwSelGroup == 2); - bool streams_found = false; - - auto processStreamSelectFilter = [&](CComPtr pSS) { - DWORD cStreams; - if (FAILED(pSS->Count(&cStreams))) { - return false; - } - - std::vector> streams; - size_t currentSel = SIZE_MAX; - for (DWORD i = 0; i < cStreams; i++) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - CComHeapPtr pszName; - - if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - if (dwGroup != dwSelGroup) { - continue; - } - - streams_found = true; - - if (dwFlags) { - currentSel = streams.size(); - } - streams.emplace_back(i, (int)streams.size(), lcid, CString(pszName)); - } - - size_t count = streams.size(); - if (count && currentSel != SIZE_MAX) { - size_t requested = (bForward ? currentSel + 1 : currentSel - 1) % count; - DWORD id; - int trackindex; - LCID lcid = 0; - CString name; - std::tie(id, trackindex, lcid, name) = streams.at(requested); - if (SUCCEEDED(pSS->Enable(id, AMSTREAMSELECTENABLE_ENABLE))) { - if (dwSelGroup == 1 || AfxGetAppSettings().fEnableSubtitles) { - m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(name, lcid, dwSelGroup)); - } - if (dwSelGroup == 1) { - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pSS->Info(id, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr))) { - UpdateSelectedAudioStreamInfo(trackindex, pmt, lcid); - DeleteMediaType(pmt); - } - } else { - if (lcid && AfxGetAppSettings().fEnableSubtitles) { - GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentSubLang); - } else { - currentSubLang.Empty(); - } - } - } - return true; - } - return false; - }; - - if (m_pSplitterSS) { - if (processStreamSelectFilter(m_pSplitterSS)) return; - } - if (!streams_found && m_pOtherSS[0]) { - if (processStreamSelectFilter(m_pOtherSS[0])) return; - } - if (!streams_found && m_pOtherSS[1]) { - if (processStreamSelectFilter(m_pOtherSS[1])) return; - } -} - -CString CMainFrame::GetStreamOSDString(CString name, LCID lcid, DWORD dwSelGroup) -{ - name.Replace(_T("\t"), _T(" - ")); - CString sLcid; - if (lcid && lcid != LCID(-1)) { - GetLocaleString(lcid, LOCALE_SENGLANGUAGE, sLcid); - } - if (!sLcid.IsEmpty() && CString(name).MakeLower().Find(CString(sLcid).MakeLower()) < 0) { - name += _T(" (") + sLcid + _T(")"); - } - CString strMessage; - if (dwSelGroup == 1) { - int n = 0; - if (name.Find(_T("A:")) == 0) { - n = 2; - } - strMessage.Format(IDS_AUDIO_STREAM, name.Mid(n).Trim().GetString()); - } else if (dwSelGroup == 2) { - int n = 0; - if (name.Find(_T("S:")) == 0) { - n = 2; - } - strMessage.Format(IDS_SUBTITLE_STREAM, name.Mid(n).Trim().GetString()); - } - return strMessage; -} - -void CMainFrame::SetupRecentFilesSubMenu() -{ - auto& s = AfxGetAppSettings(); - auto& MRU = s.MRU; - MRU.ReadMediaHistory(); - - if (MRU.listModifySequence == recentFilesMenuFromMRUSequence) { - return; - } - recentFilesMenuFromMRUSequence = MRU.listModifySequence; - - CMenu& subMenu = m_recentFilesMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (!s.fKeepHistory) { - return; - } - - if (MRU.GetSize() > 0) { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_RECENT_FILES_CLEAR, ResStr(IDS_RECENT_FILES_CLEAR))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - UINT id = ID_RECENT_FILE_START; - for (int i = 0; i < MRU.GetSize(); i++) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (!MRU[i].fns.IsEmpty() && !MRU[i].fns.GetHead().IsEmpty()) { - CString p = MRU[i].cue.IsEmpty() ? MRU[i].fns.GetHead() : MRU[i].cue; - if (s.bUseTitleInRecentFileList && !MRU[i].title.IsEmpty()) { - CString title(MRU[i].title); - if (title.GetLength() > 100) { - title = title.Left(40) + _T("~~~") + title.Right(57); - } - int targetlen = 150 - title.GetLength(); - if (PathUtils::IsURL(p)) { - if (title.Right(1) == L')') { - // probably already contains shorturl - p = title; - } else { - CString shorturl = ShortenURL(p, targetlen, true); - p.Format(_T("%s (%s)"), static_cast(title), static_cast(shorturl)); - } - } else { - CString fn = PathUtils::StripPathOrUrl(p); - if (fn.GetLength() > targetlen) { // If file name is too long, cut middle part. - int l = fn.GetLength(); - fn.Format(_T("%s~~~%s"), static_cast(fn.Left(l / 2 - 2 + (l % 2))), static_cast(fn.Right(l / 2 - 1))); - } - p.Format(_T("%s (%s)"), static_cast(title), static_cast(fn)); - } - } - else { - if (PathUtils::IsURL(p)) { - p = ShortenURL(p, 150); - } - if (p.GetLength() > 150) { - p.Format(_T("%s~~~%s"), static_cast(p.Left(60)), static_cast(p.Right(87))); - } - } - p.Replace(_T("&"), _T("&&")); - VERIFY(subMenu.AppendMenu(flags, id, p)); - } else { - ASSERT(false); - } - id++; - } - } -} - -void CMainFrame::SetupFavoritesSubMenu() -{ - CMenu& subMenu = m_favoritesMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - const CAppSettings& s = AfxGetAppSettings(); - - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_FAVORITES_ADD, ResStr(IDS_FAVORITES_ADD))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_FAVORITES_ORGANIZE, ResStr(IDS_FAVORITES_ORGANIZE))); - - UINT nLastGroupStart = subMenu.GetMenuItemCount(); - UINT id = ID_FAVORITES_FILE_START; - CAtlList favs; - AfxGetAppSettings().GetFav(FAV_FILE, favs); - POSITION pos = favs.GetHeadPosition(); - - while (pos) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - - CString f_str = favs.GetNext(pos); - f_str.Replace(_T("&"), _T("&&")); - f_str.Replace(_T("\t"), _T(" ")); - - FileFavorite ff; - VERIFY(FileFavorite::TryParse(f_str, ff)); - - f_str = ff.Name; - - CString str = ff.ToString(); - if (!str.IsEmpty()) { - f_str.AppendFormat(_T("\t%s"), str.GetString()); - } - - if (!f_str.IsEmpty()) { - VERIFY(subMenu.AppendMenu(flags, id, f_str)); - } - - id++; - if (id > ID_FAVORITES_FILE_END) { - break; - } - } - - if (id > ID_FAVORITES_FILE_START) { - VERIFY(subMenu.InsertMenu(nLastGroupStart, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); - } - - nLastGroupStart = subMenu.GetMenuItemCount(); - - id = ID_FAVORITES_DVD_START; - s.GetFav(FAV_DVD, favs); - pos = favs.GetHeadPosition(); - - while (pos) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - - CString str = favs.GetNext(pos); - str.Replace(_T("&"), _T("&&")); - - CAtlList sl; - ExplodeEsc(str, sl, _T(';'), 2); - - str = sl.RemoveHead(); - - if (!sl.IsEmpty()) { - // TODO - } - - if (!str.IsEmpty()) { - VERIFY(subMenu.AppendMenu(flags, id, str)); - } - - id++; - if (id > ID_FAVORITES_DVD_END) { - break; - } - } - - if (id > ID_FAVORITES_DVD_START) { - VERIFY(subMenu.InsertMenu(nLastGroupStart, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); - } - - nLastGroupStart = subMenu.GetMenuItemCount(); - - id = ID_FAVORITES_DEVICE_START; - - s.GetFav(FAV_DEVICE, favs); - - pos = favs.GetHeadPosition(); - while (pos) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - - CString str = favs.GetNext(pos); - str.Replace(_T("&"), _T("&&")); - - CAtlList sl; - ExplodeEsc(str, sl, _T(';'), 2); - - str = sl.RemoveHead(); - - if (!str.IsEmpty()) { - VERIFY(subMenu.AppendMenu(flags, id, str)); - } - - id++; - if (id > ID_FAVORITES_DEVICE_END) { - break; - } - } -} - -bool CMainFrame::SetupShadersSubMenu() -{ - const auto& s = AfxGetAppSettings(); - - CMenu& subMenu = m_shadersMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (!(s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS || s.iDSVideoRendererType == VIDRNDT_DS_MADVR || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR)) { - return false; - } - - subMenu.AppendMenu(MF_BYCOMMAND | MF_STRING | MF_ENABLED, ID_PRESIZE_SHADERS_TOGGLE, ResStr(IDS_PRESIZE_SHADERS_TOGGLE)); - subMenu.AppendMenu(MF_BYCOMMAND | MF_STRING | MF_ENABLED, ID_POSTSIZE_SHADERS_TOGGLE, ResStr(IDS_POSTSIZE_SHADERS_TOGGLE)); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_SHADERS_SELECT, ResStr(IDS_SHADERS_SELECT))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_VIEW_DEBUGSHADERS, ResStr(IDS_SHADERS_DEBUG))); - - auto presets = s.m_Shaders.GetPresets(); - if (!presets.empty()) { - CString current; - bool selected = s.m_Shaders.GetCurrentPresetName(current); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - UINT nID = ID_SHADERS_PRESETS_START; - for (const auto& pair : presets) { - if (nID > ID_SHADERS_PRESETS_END) { - // too many presets - ASSERT(FALSE); - break; - } - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, nID, pair.first)); - if (selected && pair.first == current) { - VERIFY(subMenu.CheckMenuRadioItem(nID, nID, nID, MF_BYCOMMAND)); - selected = false; - } - nID++; - } - } - return true; -} - -///////////// - -void CMainFrame::SetAlwaysOnTop(int iOnTop) -{ - CAppSettings& s = AfxGetAppSettings(); - - if (!IsFullScreenMode()) { - const CWnd* pInsertAfter = nullptr; - - if (iOnTop == 0) { - // We only want to disable "On Top" once so that - // we don't interfere with other window manager - if (s.iOnTop || !alwaysOnTopZOrderInitialized) { - pInsertAfter = &wndNoTopMost; - alwaysOnTopZOrderInitialized = true; - } - } else if (iOnTop == 1) { - pInsertAfter = &wndTopMost; - } else if (iOnTop == 2) { - pInsertAfter = (GetMediaState() == State_Running) ? &wndTopMost : &wndNoTopMost; - } else { // if (iOnTop == 3) - pInsertAfter = (GetMediaState() == State_Running && !m_fAudioOnly) ? &wndTopMost : &wndNoTopMost; - } - - if (pInsertAfter) { - SetWindowPos(pInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } - } - - s.iOnTop = iOnTop; -} - -bool CMainFrame::WindowExpectedOnTop() { - return (AfxGetAppSettings().iOnTop == 1 || - (AfxGetAppSettings().iOnTop == 2 && GetMediaState() == State_Running) || - (AfxGetAppSettings().iOnTop == 3 && GetMediaState() == State_Running && !m_fAudioOnly)); -} - -void CMainFrame::AddTextPassThruFilter() -{ - BeginEnumFilters(m_pGB, pEF, pBF) { - if (!IsSplitter(pBF)) { - continue; - } - - BeginEnumPins(pBF, pEP, pPin) { - CComPtr pPinTo; - AM_MEDIA_TYPE mt; - if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo - && SUCCEEDED(pPin->ConnectionMediaType(&mt)) - && (mt.majortype == MEDIATYPE_Text || mt.majortype == MEDIATYPE_Subtitle)) { - InsertTextPassThruFilter(pBF, pPin, pPinTo); - } - } - EndEnumPins; - } - EndEnumFilters; -} - -HRESULT CMainFrame::InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinTo) -{ - HRESULT hr; - CComQIPtr pTPTF = DEBUG_NEW CTextPassThruFilter(this); - CStringW name; - name.Format(L"TextPassThru%p", static_cast(pTPTF)); - if (FAILED(hr = m_pGB->AddFilter(pTPTF, name))) { - return hr; - } - - OAFilterState fs = GetMediaState(); - if (fs == State_Running || fs == State_Paused) { - MediaControlStop(true); - } - - hr = pPinTo->Disconnect(); - hr = pPin->Disconnect(); - - if (FAILED(hr = m_pGB->ConnectDirect(pPin, GetFirstPin(pTPTF, PINDIR_INPUT), nullptr)) - || FAILED(hr = m_pGB->ConnectDirect(GetFirstPin(pTPTF, PINDIR_OUTPUT), pPinTo, nullptr))) { - hr = m_pGB->ConnectDirect(pPin, pPinTo, nullptr); - } else { - SubtitleInput subInput(CComQIPtr(pTPTF), pBF); - m_pSubStreams.AddTail(subInput); - } - - if (fs == State_Running) { - MediaControlRun(); - } else if (fs == State_Paused) { - MediaControlPause(); - } - - return hr; -} - -bool CMainFrame::LoadSubtitle(CString fn, SubtitleInput* pSubInput /*= nullptr*/, bool bAutoLoad /*= false*/) -{ - CAppSettings& s = AfxGetAppSettings(); - CComQIPtr pSubStream; - - if (!s.IsISRAutoLoadEnabled() && (FindFilter(CLSID_VSFilter, m_pGB) || FindFilter(CLSID_XySubFilter, m_pGB))) { - // Prevent ISR from loading if VSFilter is already in graph. - // TODO: Support VSFilter natively (see ticket #4122) - // Note that this doesn't affect ISR auto-loading if any sub renderer force loading itself into the graph. - // VSFilter like filters can be blocked when building the graph and ISR auto-loading is enabled but some - // users don't want that. - return false; - } - - if (GetPlaybackMode() == PM_FILE && !s.fDisableInternalSubtitles && !FindFilter(__uuidof(CTextPassThruFilter), m_pGB)) { - // Add TextPassThru filter if it isn't already in the graph. (i.e ISR hasn't been loaded before) - // This will load all embedded subtitle tracks when user triggers ISR (load external subtitle file) for the first time. - AddTextPassThruFilter(); - } - - CString videoName; - if (GetPlaybackMode() == PM_FILE) { - videoName = m_wndPlaylistBar.GetCurFileName(); - } - - CString ext = CPath(fn).GetExtension().MakeLower(); - - if (!pSubStream && (ext == _T(".idx") || !bAutoLoad && ext == _T(".sub"))) { - CAutoPtr pVSF(DEBUG_NEW CVobSubFile(&m_csSubLock)); - if (pVSF && pVSF->Open(fn) && pVSF->GetStreamCount() > 0) { - pSubStream = pVSF.Detach(); - } - } - - if (!pSubStream && ext != _T(".idx") && ext != _T(".sup")) { - CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); - if (pRTS) { - if (pRTS->Open(fn, DEFAULT_CHARSET, _T(""), videoName) && pRTS->GetStreamCount() > 0) { -#if USE_LIBASS - if (pRTS->m_LibassContext.IsLibassActive()) { - pRTS->m_LibassContext.SetFilterGraph(m_pGB); - } -#endif - pSubStream = pRTS.Detach(); - } - } - } - - if (!pSubStream) { - CAutoPtr pPSF(DEBUG_NEW CPGSSubFile(&m_csSubLock)); - if (pPSF && pPSF->Open(fn, _T(""), videoName) && pPSF->GetStreamCount() > 0) { - pSubStream = pPSF.Detach(); - } - } - - if (pSubStream) { - SubtitleInput subInput(pSubStream); - m_ExternalSubstreams.push_back(pSubStream); - m_pSubStreams.AddTail(subInput); - - // Temporarily load fonts from 'Fonts' folder - Begin - CString path = PathUtils::DirName(fn) + L"\\fonts\\"; - ExtendMaxPathLengthIfNeeded(path); - - if (::PathIsDirectory(path)) { - WIN32_FIND_DATA fd = {0}; - HANDLE hFind; - - hFind = FindFirstFile(path + L"*.?t?", &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - CStringW ext = GetFileExt(fd.cFileName); - if (ext == ".ttf" || ext == ".otf" || ext == ".ttc") { - m_FontInstaller.InstallTempFontFile(path + fd.cFileName); - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - } - // Temporarily load fonts from 'Fonts' folder - End - - if (!m_posFirstExtSub) { - m_posFirstExtSub = m_pSubStreams.GetTailPosition(); - } - - if (pSubInput) { - *pSubInput = subInput; - } - - if (!bAutoLoad) { - m_wndPlaylistBar.AddSubtitleToCurrent(fn); - if (s.fKeepHistory) { - s.MRU.AddSubToCurrent(fn); - } - } - } - - return !!pSubStream; -} - -bool CMainFrame::LoadSubtitle(CYoutubeDLInstance::YDLSubInfo& sub) { - CAppSettings& s = AfxGetAppSettings(); - CComQIPtr pSubStream; - CAtlList preferlist; - if (!s.sYDLSubsPreference.IsEmpty()) { - if (s.sYDLSubsPreference.Find(_T(',')) != -1) { - ExplodeMin(s.sYDLSubsPreference, preferlist, ','); - } else { - ExplodeMin(s.sYDLSubsPreference, preferlist, ' '); - } - } - if (!preferlist.IsEmpty() && !CYoutubeDLInstance::isPrefer(preferlist, sub.lang)) { - return false; - } - - if (!s.IsISRAutoLoadEnabled() && (FindFilter(CLSID_VSFilter, m_pGB) || FindFilter(CLSID_XySubFilter, m_pGB))) { - // Prevent ISR from loading if VSFilter is already in graph. - // TODO: Support VSFilter natively (see ticket #4122) - // Note that this doesn't affect ISR auto-loading if any sub renderer force loading itself into the graph. - // VSFilter like filters can be blocked when building the graph and ISR auto-loading is enabled but some - // users don't want that. - return false; - } - - if (GetPlaybackMode() == PM_FILE && !s.fDisableInternalSubtitles && !FindFilter(__uuidof(CTextPassThruFilter), m_pGB)) { - // Add TextPassThru filter if it isn't already in the graph. (i.e ISR hasn't been loaded before) - // This will load all embedded subtitle tracks when user triggers ISR (load external subtitle file) for the first time. - AddTextPassThruFilter(); - } - - CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); - if (pRTS) { - bool opened = false; - if (!sub.url.IsEmpty()) { - SubtitlesProvidersUtils::stringMap strmap{}; - DWORD dwStatusCode; - CT2CA tem(sub.url); - std::string tem2(tem); - std::string data(""); - SubtitlesProvidersUtils::StringDownload(tem2, strmap, data, true, &dwStatusCode); - if (dwStatusCode != 200) { - return false; - } - if (sub.ext.IsEmpty()) { - int m2(sub.url.ReverseFind(_T('?'))); - int m3(sub.url.ReverseFind(_T('#'))); - int m = -1; - if (m2 > -1 && m3 > -1) m = std::min(m2, m3); - else if (m2 > -1) m = m2; - else if (m3 > -1) m = m3; - CString temp(sub.url); - if (m > 0) temp = sub.url.Left(m); - m = temp.ReverseFind(_T('.')); - if (m >= 0) sub.ext = temp.Mid(m + 1); - } - CString langt = sub.isAutomaticCaptions ? sub.lang + _T("[Automatic]") : sub.lang; - opened = pRTS->Open((BYTE*)data.c_str(), (int)data.length(), DEFAULT_CHARSET, _T("YoutubeDL"), langt, sub.ext); - } else if (!sub.data.IsEmpty()) { - CString langt = sub.isAutomaticCaptions ? sub.lang + _T("[Automatic]") : sub.lang; - opened = pRTS->Open(sub.data, CTextFile::enc::UTF8, DEFAULT_CHARSET, _T("YoutubeDL"), langt, sub.ext); // Do not modify charset, Now it wroks with Unicode char. - } - if (opened && pRTS->GetStreamCount() > 0) { -#if USE_LIBASS - if (pRTS->m_LibassContext.IsLibassActive()) { - pRTS->m_LibassContext.SetFilterGraph(m_pGB); - } -#endif - pSubStream = pRTS.Detach(); - } - } - - if (pSubStream) { - SubtitleInput subInput(pSubStream); - m_ExternalSubstreams.push_back(pSubStream); - m_pSubStreams.AddTail(subInput); - - if (!m_posFirstExtSub) { - m_posFirstExtSub = m_pSubStreams.GetTailPosition(); - } - } - - return !!pSubStream; -} - -// Called from GraphThread -bool CMainFrame::SetSubtitle(int i, bool bIsOffset /*= false*/, bool bDisplayMessage /*= false*/) -{ - if (!m_pCAP) { - return false; - } - if (GetLoadState() == MLS::CLOSING) { - return false; - } - - CAppSettings& s = AfxGetAppSettings(); - - SubtitleInput* pSubInput = nullptr; - if (m_iReloadSubIdx >= 0) { - pSubInput = GetSubtitleInput(m_iReloadSubIdx); - if (pSubInput) { - i = m_iReloadSubIdx; - } - m_iReloadSubIdx = -1; - } - - if (!pSubInput) { - pSubInput = GetSubtitleInput(i, bIsOffset); - } - - bool success = false; - - if (pSubInput) { - CComHeapPtr pName; - if (CComQIPtr pSSF = pSubInput->pSourceFilter) { - DWORD dwFlags; - LCID lcid = 0; - if (FAILED(pSSF->Info(i, nullptr, &dwFlags, &lcid, nullptr, &pName, nullptr, nullptr))) { - dwFlags = 0; - } - if (lcid && s.fEnableSubtitles) { - currentSubLang = ISOLang::GetLocaleStringCompat(lcid); - } else { - currentSubLang.Empty(); - } - - // Enable the track only if it isn't already the only selected track in the group - if (!(dwFlags & AMSTREAMSELECTINFO_EXCLUSIVE)) { - pSSF->Enable(i, AMSTREAMSELECTENABLE_ENABLE); - } - i = 0; - } - { - // m_csSubLock shouldn't be locked when using IAMStreamSelect::Enable or SetSubtitle - CAutoLock cAutoLock(&m_csSubLock); - pSubInput->pSubStream->SetStream(i); - } - SetSubtitle(*pSubInput, true); - - if (!pName) { - LCID lcid = 0; - pSubInput->pSubStream->GetStreamInfo(0, &pName, &lcid); - if (lcid && s.fEnableSubtitles) { - currentSubLang = ISOLang::GetLocaleStringCompat(lcid); - } else { - currentSubLang.Empty(); - } - } - - if (bDisplayMessage && pName) { - m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pName), LCID(-1), 2)); - } - success = true; - } - - if (success && s.fKeepHistory && s.bRememberTrackSelection) { - s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); - } - return success; -} - -void CMainFrame::UpdateSubtitleColorInfo() -{ - if (!m_pCAP || !m_pCurrentSubInput.pSubStream) { - return; - } - - // store video mediatype, so colorspace information can be extracted when present - // FIXME: mediatype extended colorinfo may be absent on initial connection, call this again after first frame has been decoded? - CComQIPtr pBF = m_pCAP; - CComPtr pPin = GetFirstPin(pBF); - if (pPin) { - AM_MEDIA_TYPE mt; - if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - m_pCAP->SetVideoMediaType(CMediaType(mt)); - } - } - - CComQIPtr pSRO = m_pCAP; - - LPWSTR yuvMatrix = nullptr; - int nLen; - if (m_pMVRI) { - m_pMVRI->GetString("yuvMatrix", &yuvMatrix, &nLen); - } else if (pSRO) { - pSRO->GetString("yuvMatrix", &yuvMatrix, &nLen); - } - - int targetBlackLevel = 0, targetWhiteLevel = 255; - if (m_pMVRS) { - m_pMVRS->SettingsGetInteger(L"Black", &targetBlackLevel); - m_pMVRS->SettingsGetInteger(L"White", &targetWhiteLevel); - } else if (pSRO) { - int range = 0; - pSRO->GetInt("supportedLevels", &range); - if (range == 3) { - targetBlackLevel = 16; - targetWhiteLevel = 235; - } - } - - m_pCurrentSubInput.pSubStream->SetSourceTargetInfo(yuvMatrix, targetBlackLevel, targetWhiteLevel); - LocalFree(yuvMatrix); -} - -void CMainFrame::SetSubtitle(const SubtitleInput& subInput, bool skip_lcid /* = false */) -{ - TRACE(_T("CMainFrame::SetSubtitle\n")); - - CAppSettings& s = AfxGetAppSettings(); - ResetSubtitlePosAndSize(false); - - { - CAutoLock cAutoLock(&m_csSubLock); - - bool firstuse = !m_pCurrentSubInput.pSubStream; - - if (subInput.pSubStream) { - bool found = false; - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - if (subInput.pSubStream == m_pSubStreams.GetNext(pos).pSubStream) { - found = true; - break; - } - } - // We are trying to set a subtitles stream that isn't in the list so we abort here. - if (!found) { - return; - } - } - - if (m_pCAP && m_pCurrentSubInput.pSubStream && m_pCurrentSubInput.pSubStream != subInput.pSubStream) { - m_pCAP->SetSubPicProvider(nullptr); - } - - m_pCurrentSubInput = subInput; - - UpdateSubtitleRenderingParameters(); - - if (firstuse) { - // note: can deadlock when calling ConnectionMediaType() with MPCVR when SubPicProvider!=nullptr - UpdateSubtitleColorInfo(); - } - - if (!skip_lcid) { - LCID lcid = 0; - if (m_pCurrentSubInput.pSubStream && s.fEnableSubtitles) { - CComHeapPtr pName; - m_pCurrentSubInput.pSubStream->GetStreamInfo(0, &pName, &lcid); - } - if (lcid) { - GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentSubLang); - } else { - currentSubLang.Empty(); - } - } - - if (m_pCAP) { - g_bExternalSubtitle = (std::find(m_ExternalSubstreams.cbegin(), m_ExternalSubstreams.cend(), subInput.pSubStream) != m_ExternalSubstreams.cend()); - bool use_subresync = false; - if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { -#if USE_LIBASS - if (!pRTS->m_LibassContext.IsLibassActive()) -#endif - use_subresync = true; - } - if (use_subresync) { - m_wndSubresyncBar.SetSubtitle(subInput.pSubStream, m_pCAP->GetFPS(), g_bExternalSubtitle); - } else { - m_wndSubresyncBar.SetSubtitle(nullptr, m_pCAP->GetFPS(), g_bExternalSubtitle); - } - } - } - - if (m_pCAP && s.fEnableSubtitles) { - m_pCAP->SetSubPicProvider(CComQIPtr(subInput.pSubStream)); - } - - if (s.fKeepHistory && s.bRememberTrackSelection) { - s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); - } -} - -void CMainFrame::OnAudioShiftOnOff() -{ - AfxGetAppSettings().fAudioTimeShift = !AfxGetAppSettings().fAudioTimeShift; -} - -void CMainFrame::ToggleSubtitleOnOff(bool bDisplayMessage /*= false*/) -{ - if (m_pDVS) { - bool bHideSubtitles = false; - m_pDVS->get_HideSubtitles(&bHideSubtitles); - bHideSubtitles = !bHideSubtitles; - m_pDVS->put_HideSubtitles(bHideSubtitles); - } - if (m_pCAP && (!m_pDVS || !m_pSubStreams.IsEmpty())) { - CAppSettings& s = AfxGetAppSettings(); - s.fEnableSubtitles = !s.fEnableSubtitles; - - if (s.fEnableSubtitles) { - SetSubtitle(0, true, bDisplayMessage); - } else { - if (m_pCAP) { - m_pCAP->SetSubPicProvider(nullptr); - } - currentSubLang = ResStr(IDS_AG_DISABLED); - - if (bDisplayMessage) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_SUBTITLE_STREAM_OFF)); - } - } - } -} - -void CMainFrame::ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew) -{ - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - POSITION cur = pos; - if (pSubStreamOld == m_pSubStreams.GetNext(pos).pSubStream) { - m_pSubStreams.GetAt(cur).pSubStream = pSubStreamNew; - if (m_pCurrentSubInput.pSubStream == pSubStreamOld) { - SetSubtitle(m_pSubStreams.GetAt(cur), true); - } - break; - } - } -} - -void CMainFrame::InvalidateSubtitle(DWORD_PTR nSubtitleId /*= DWORD_PTR_MAX*/, REFERENCE_TIME rtInvalidate /*= -1*/) -{ - if (m_pCAP) { - if (nSubtitleId == DWORD_PTR_MAX || nSubtitleId == (DWORD_PTR)(ISubStream*)m_pCurrentSubInput.pSubStream) { - m_pCAP->Invalidate(rtInvalidate); - } - } -} - -void CMainFrame::ReloadSubtitle() -{ - { - CAutoLock cAutoLock(&m_csSubLock); - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - m_pSubStreams.GetNext(pos).pSubStream->Reload(); - } - } - - ResetSubtitlePosAndSize(false); - - SetSubtitle(0, true); - m_wndSubresyncBar.ReloadSubtitle(); -} - -void CMainFrame::SetSubtitleTrackIdx(int index) -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (GetLoadState() == MLS::LOADED && m_pCAP) { - // Check if we want to change the enable/disable state - if (s.fEnableSubtitles != (index >= 0)) { - ToggleSubtitleOnOff(); - } - // Set the new subtitles track if needed - if (s.fEnableSubtitles) { - SetSubtitle(index); - } - } -} - -void CMainFrame::SetAudioTrackIdx(int index) -{ - if (GetLoadState() == MLS::LOADED) { - DWORD cStreams = 0; - DWORD dwFlags = AMSTREAMSELECTENABLE_ENABLE; - if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { - if ((index >= 0) && (index < ((int)cStreams))) { - m_pAudioSwitcherSS->Enable(index, dwFlags); - - m_loadedAudioTrackIndex = index; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - CComHeapPtr pszName; - if (SUCCEEDED(m_pAudioSwitcherSS->Info(index, &pmt, &dwFlags, &lcid, nullptr, &pszName, nullptr, nullptr))) { - m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pszName), lcid, 1)); - UpdateSelectedAudioStreamInfo(index, pmt, lcid); - DeleteMediaType(pmt); - } - } - } - // ToDo: use m_pSplitterSS - } -} - -int CMainFrame::GetCurrentAudioTrackIdx(CString *pstrName) -{ - if(pstrName) - pstrName->Empty(); - - if (GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_FILE && m_pGB) { - DWORD cStreams = 0; - if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { - for (int i = 0; i < (int)cStreams; i++) { - DWORD dwFlags = 0; - CComHeapPtr pName; - if (SUCCEEDED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, nullptr, &pName, nullptr, nullptr))) { - if (dwFlags & AMSTREAMSELECTINFO_ENABLED) { - if(pstrName) - *pstrName = pName; - ASSERT(m_loadedAudioTrackIndex == i); - return i; - } - } else { - break; - } - } - } - // ToDo: use m_pSplitterSS - } - return -1; -} - -int CMainFrame::GetCurrentSubtitleTrackIdx(CString *pstrName) -{ - if(pstrName) - pstrName->Empty(); - - if (GetLoadState() != MLS::LOADED) { - return -1; - } - - if (m_pCAP && !m_pSubStreams.IsEmpty()) { - int idx = 0; - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - if (CComQIPtr pSSF = subInput.pSourceFilter) { - DWORD cStreams; - if (FAILED(pSSF->Count(&cStreams))) { - continue; - } - for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { - DWORD dwFlags, dwGroup; - CComHeapPtr pName; - if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, &pName, nullptr, nullptr))) { - continue; - } - if (dwGroup != 2) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - if (pstrName) - *pstrName = pName; - return idx; - } - } - idx++; - } - } else { - CComPtr pSubStream = subInput.pSubStream; - if (!pSubStream) { - continue; - } - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - if (pstrName) { - CComHeapPtr pName; - pSubStream->GetStreamInfo(pSubStream->GetStream(), &pName, nullptr); - *pstrName = pName; - } - return idx + pSubStream->GetStream(); - } - idx += pSubStream->GetStreamCount(); - } - } - } else if (m_pSplitterSS) { - DWORD cStreams; - if (SUCCEEDED(m_pSplitterSS->Count(&cStreams))) { - int idx = 0; - for (int i = 0; i < (int)cStreams; i++) { - DWORD dwFlags, dwGroup; - CComHeapPtr pszName; - - if (FAILED(m_pSplitterSS->Info(i, nullptr, &dwFlags, nullptr, &dwGroup, &pszName, nullptr, nullptr))) - continue; - - if (dwGroup != 2) - continue; - - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - if (pstrName) - *pstrName = pszName; - return idx; - } - - idx++; - } - } - } - - return -1; -} - -REFERENCE_TIME CMainFrame::GetPos() const -{ - return (GetLoadState() == MLS::LOADED ? m_wndSeekBar.GetPos() : 0); -} - -REFERENCE_TIME CMainFrame::GetDur() const -{ - __int64 start, stop; - m_wndSeekBar.GetRange(start, stop); - return (GetLoadState() == MLS::LOADED ? stop : 0); -} - -void CMainFrame::LoadKeyFrames() -{ - UINT nKFs = 0; - m_kfs.clear(); - if (m_pKFI && S_OK == m_pKFI->GetKeyFrameCount(nKFs) && nKFs > 1) { - UINT k = nKFs; - m_kfs.resize(k); - if (FAILED(m_pKFI->GetKeyFrames(&TIME_FORMAT_MEDIA_TIME, m_kfs.data(), k)) || k != nKFs) { - m_kfs.clear(); - } - } -} - -bool CMainFrame::GetKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMin, REFERENCE_TIME rtMax, bool nearest, REFERENCE_TIME& keyframetime) const -{ - ASSERT(rtTarget >= rtMin); - ASSERT(rtTarget <= rtMax); - if (!m_kfs.empty()) { - const auto cbegin = m_kfs.cbegin(); - const auto cend = m_kfs.cend(); - ASSERT(std::is_sorted(cbegin, cend)); - - auto foundkeyframe = std::lower_bound(cbegin, cend, rtTarget); - - if (foundkeyframe == cbegin) { - // first keyframe - keyframetime = *foundkeyframe; - if ((keyframetime < rtMin) || (keyframetime > rtMax)) { - keyframetime = rtTarget; - return false; - } - } else if (foundkeyframe == cend) { - // last keyframe - keyframetime = *(--foundkeyframe); - if (keyframetime < rtMin) { - keyframetime = rtTarget; - return false; - } - } else { - keyframetime = *foundkeyframe; - if (keyframetime == rtTarget) { - return true; - } - if (keyframetime > rtMax) { - // use preceding keyframe - keyframetime = *(--foundkeyframe); - if (keyframetime < rtMin) { - keyframetime = rtTarget; - return false; - } - } else { - if (nearest) { - const auto& s = AfxGetAppSettings(); - if (s.eFastSeekMethod == s.FASTSEEK_NEAREST_KEYFRAME) { - // use closest keyframe - REFERENCE_TIME prev_keyframetime = *(--foundkeyframe); - if ((prev_keyframetime >= rtMin)) { - if ((keyframetime - rtTarget) > (rtTarget - prev_keyframetime)) { - keyframetime = prev_keyframetime; - } - } - } - } - } - } - return true; - } else { - keyframetime = rtTarget; - } - return false; -} - -REFERENCE_TIME CMainFrame::GetClosestKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMaxForwardDiff, REFERENCE_TIME rtMaxBackwardDiff) const -{ - if (rtTarget < 0LL) return 0LL; - if (rtTarget > GetDur()) return rtTarget; - - REFERENCE_TIME rtKeyframe; - REFERENCE_TIME rtMin = std::max(rtTarget - rtMaxBackwardDiff, 0LL); - REFERENCE_TIME rtMax = rtTarget + rtMaxForwardDiff; - - if (GetKeyFrame(rtTarget, rtMin, rtMax, true, rtKeyframe)) { - return rtKeyframe; - } - return rtTarget; -} - -REFERENCE_TIME CMainFrame::GetClosestKeyFramePreview(REFERENCE_TIME rtTarget) const -{ - return GetClosestKeyFrame(rtTarget, 200000000LL, 200000000LL); -} - -void CMainFrame::SeekTo(REFERENCE_TIME rtPos, bool bShowOSD /*= true*/) -{ - if (m_pMS == nullptr) { - return; - } - ASSERT(lastSeekFinish >= lastSeekStart); // ToDo: remove lastSeekStart variable if no regressions show up - ULONGLONG curTime = GetTickCount64(); - ULONGLONG ticksSinceLastSeek = curTime - lastSeekFinish; - ULONGLONG mindelay = (lastSeekFinish - lastSeekStart) > 40ULL ? 100ULL : 40ULL; - //ASSERT(rtPos != queuedSeek.rtPos || queuedSeek.seekTime == 0 || (curTime < queuedSeek.seekTime + 500ULL)); - - if (ticksSinceLastSeek < mindelay) { - //TRACE(_T("Delay seek: %lu %lu\n"), rtPos, ticksSinceLastSeek); - queuedSeek = { rtPos, curTime, bShowOSD }; - SetTimer(TIMER_DELAYEDSEEK, (UINT) (mindelay * 1.25 - ticksSinceLastSeek), nullptr); - } else { - KillTimerDelayedSeek(); - lastSeekStart = curTime; - DoSeekTo(rtPos, bShowOSD); - lastSeekFinish = GetTickCount64(); - } -} - -void CMainFrame::DoSeekTo(REFERENCE_TIME rtPos, bool bShowOSD /*= true*/) -{ - //TRACE(_T("DoSeekTo: %lu\n"), rtPos); - - ASSERT(m_pMS != nullptr); - if (m_pMS == nullptr) { - return; - } - OAFilterState fs = GetMediaState(); - - if (rtPos < 0) { - rtPos = 0; - } - - if (abRepeat.positionA && rtPos < abRepeat.positionA || abRepeat.positionB && rtPos > abRepeat.positionB) { - DisableABRepeat(); - } - - if (m_fFrameSteppingActive) { - // Cancel pending frame steps - m_pFS->CancelStep(); - m_fFrameSteppingActive = false; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } - m_nStepForwardCount = 0; - - // skip seeks when duration is unknown - if (!m_wndSeekBar.HasDuration()) { - return; - } - - if (!IsPlaybackCaptureMode()) { - __int64 start, stop; - m_wndSeekBar.GetRange(start, stop); - if (rtPos > stop) { - rtPos = stop; - } - m_wndStatusBar.SetStatusTimer(rtPos, stop, IsSubresyncBarVisible(), GetTimeFormat()); - - if (bShowOSD) { - m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 1500); - } - } - - if (GetPlaybackMode() == PM_FILE) { - if (fs == State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - - //SleepEx(5000, False); // artificial slow seek for testing purposes - if (FAILED(m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning))) { - TRACE(_T("IMediaSeeking SetPositions failure\n")); - if (abRepeat.positionA && rtPos == abRepeat.positionA) { - DisableABRepeat(); - } - } - UpdateChapterInInfoBar(); - } else if (GetPlaybackMode() == PM_DVD && m_iDVDDomain == DVD_DOMAIN_Title) { - if (fs == State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - fs = State_Paused; - } - - const REFTIME refAvgTimePerFrame = GetAvgTimePerFrame(); - if (fs == State_Paused) { - // Jump one more frame back, this is needed because we don't have any other - // way to seek to specific time without running playback to refresh state. - rtPos -= std::llround(refAvgTimePerFrame * 10000000i64); - m_pFS->CancelStep(); - } - - DVD_HMSF_TIMECODE tc = RT2HMSF(rtPos, (1.0 / refAvgTimePerFrame)); - m_pDVDC->PlayAtTime(&tc, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - - if (fs == State_Paused) { - // Do frame step to update current position in paused state - m_pFS->Step(1, nullptr); - } - } else { - ASSERT(FALSE); - } - m_fEndOfStream = false; - - OnTimer(TIMER_STREAMPOSPOLLER); - OnTimer(TIMER_STREAMPOSPOLLER2); - - SendCurrentPositionToApi(true); -} - -void CMainFrame::CleanGraph() -{ - if (!m_pGB) { - return; - } - - BeginEnumFilters(m_pGB, pEF, pBF) { - CComQIPtr pAMMF(pBF); - if (pAMMF && (pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE)) { - continue; - } - - // some capture filters forget to set AM_FILTER_MISC_FLAGS_IS_SOURCE - // or to implement the IAMFilterMiscFlags interface - if (pBF == m_pVidCap || pBF == m_pAudCap) { - continue; - } - - // XySubFilter doesn't have any pins connected when it is reading - // external subtitles - if (GetCLSID(pBF) == CLSID_XySubFilter) { - continue; - } - - if (CComQIPtr(pBF)) { - continue; - } - - int nIn, nOut, nInC, nOutC; - if (CountPins(pBF, nIn, nOut, nInC, nOutC) > 0 && (nInC + nOutC) == 0) { - TRACE(CStringW(L"Removing: ") + GetFilterName(pBF) + '\n'); - - m_pGB->RemoveFilter(pBF); - pEF->Reset(); - } - } - EndEnumFilters; -} - -#define AUDIOBUFFERLEN 500 - -static void SetLatency(IBaseFilter* pBF, int cbBuffer) -{ - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pAMBN = pPin) { - ALLOCATOR_PROPERTIES ap; - ap.cbAlign = -1; // -1 means no preference. - ap.cbBuffer = cbBuffer; - ap.cbPrefix = -1; - ap.cBuffers = -1; - pAMBN->SuggestAllocatorProperties(&ap); - } - } - EndEnumPins; -} - -HRESULT CMainFrame::BuildCapture(IPin* pPin, IBaseFilter* pBF[3], const GUID& majortype, AM_MEDIA_TYPE* pmt) -{ - IBaseFilter* pBuff = pBF[0]; - IBaseFilter* pEnc = pBF[1]; - IBaseFilter* pMux = pBF[2]; - - if (!pPin || !pMux) { - return E_FAIL; - } - - CString err; - HRESULT hr = S_OK; - CFilterInfo fi; - - if (FAILED(pMux->QueryFilterInfo(&fi)) || !fi.pGraph) { - m_pGB->AddFilter(pMux, L"Multiplexer"); - } - - CStringW prefix; - CString type; - if (majortype == MEDIATYPE_Video) { - prefix = L"Video "; - type.LoadString(IDS_CAPTURE_ERROR_VIDEO); - } else if (majortype == MEDIATYPE_Audio) { - prefix = L"Audio "; - type.LoadString(IDS_CAPTURE_ERROR_AUDIO); - } - - if (pBuff) { - hr = m_pGB->AddFilter(pBuff, prefix + L"Buffer"); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_ADD_BUFFER, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - - hr = m_pGB->ConnectFilter(pPin, pBuff); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_CONNECT_BUFF, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - - pPin = GetFirstPin(pBuff, PINDIR_OUTPUT); - } - - if (pEnc) { - hr = m_pGB->AddFilter(pEnc, prefix + L"Encoder"); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_ADD_ENCODER, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - - hr = m_pGB->ConnectFilter(pPin, pEnc); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_CONNECT_ENC, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - - pPin = GetFirstPin(pEnc, PINDIR_OUTPUT); - - if (CComQIPtr pAMSC = pPin) { - if (pmt->majortype == majortype) { - hr = pAMSC->SetFormat(pmt); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_COMPRESSION, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - } - } - - } - - //if (pMux) - { - hr = m_pGB->ConnectFilter(pPin, pMux); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_MULTIPLEXER, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - } - - CleanGraph(); - - return S_OK; -} - -bool CMainFrame::BuildToCapturePreviewPin( - IBaseFilter* pVidCap, IPin** ppVidCapPin, IPin** ppVidPrevPin, - IBaseFilter* pAudCap, IPin** ppAudCapPin, IPin** ppAudPrevPin) -{ - HRESULT hr; - *ppVidCapPin = *ppVidPrevPin = nullptr; - *ppAudCapPin = *ppAudPrevPin = nullptr; - CComPtr pDVAudPin; - - if (pVidCap) { - CComPtr pPin; - if (!pAudCap // only look for interleaved stream when we don't use any other audio capture source - && SUCCEEDED(m_pCGB->FindPin(pVidCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, TRUE, 0, &pPin))) { - CComPtr pDVSplitter; - hr = pDVSplitter.CoCreateInstance(CLSID_DVSplitter); - hr = m_pGB->AddFilter(pDVSplitter, L"DV Splitter"); - - hr = m_pCGB->RenderStream(nullptr, &MEDIATYPE_Interleaved, pPin, nullptr, pDVSplitter); - - pPin = nullptr; - hr = m_pCGB->FindPin(pDVSplitter, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Video, TRUE, 0, &pPin); - hr = m_pCGB->FindPin(pDVSplitter, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Audio, TRUE, 0, &pDVAudPin); - - CComPtr pDVDec; - hr = pDVDec.CoCreateInstance(CLSID_DVVideoCodec); - hr = m_pGB->AddFilter(pDVDec, L"DV Video Decoder"); - - hr = m_pGB->ConnectFilter(pPin, pDVDec); - - pPin = nullptr; - hr = m_pCGB->FindPin(pDVDec, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Video, TRUE, 0, &pPin); - } else if (FAILED(m_pCGB->FindPin(pVidCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, TRUE, 0, &pPin))) { - MessageBox(ResStr(IDS_CAPTURE_ERROR_VID_CAPT_PIN), ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return false; - } - - CComPtr pSmartTee; - hr = pSmartTee.CoCreateInstance(CLSID_SmartTee); - hr = m_pGB->AddFilter(pSmartTee, L"Smart Tee (video)"); - - hr = m_pGB->ConnectFilter(pPin, pSmartTee); - - hr = pSmartTee->FindPin(L"Preview", ppVidPrevPin); - hr = pSmartTee->FindPin(L"Capture", ppVidCapPin); - } - - if (pAudCap || pDVAudPin) { - CComPtr pPin; - if (pDVAudPin) { - pPin = pDVAudPin; - } else if (FAILED(m_pCGB->FindPin(pAudCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, TRUE, 0, &pPin))) { - MessageBox(ResStr(IDS_CAPTURE_ERROR_AUD_CAPT_PIN), ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return false; - } - - CComPtr pSmartTee; - hr = pSmartTee.CoCreateInstance(CLSID_SmartTee); - hr = m_pGB->AddFilter(pSmartTee, L"Smart Tee (audio)"); - - hr = m_pGB->ConnectFilter(pPin, pSmartTee); - - hr = pSmartTee->FindPin(L"Preview", ppAudPrevPin); - hr = pSmartTee->FindPin(L"Capture", ppAudCapPin); - } - - return true; -} - -bool CMainFrame::BuildGraphVideoAudio(int fVPreview, bool fVCapture, int fAPreview, bool fACapture) -{ - if (!m_pCGB) { - return false; - } - - OAFilterState fs = GetMediaState(); - - if (fs != State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_STOP); - } - - HRESULT hr; - - m_pGB->NukeDownstream(m_pVidCap); - m_pGB->NukeDownstream(m_pAudCap); - - CleanGraph(); - - if (m_pAMVSCCap) { - hr = m_pAMVSCCap->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv); - } - if (m_pAMVSCPrev) { - hr = m_pAMVSCPrev->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv); - } - if (m_pAMASC) { - hr = m_pAMASC->SetFormat(&m_wndCaptureBar.m_capdlg.m_mta); - } - - CComPtr pVidBuffer = m_wndCaptureBar.m_capdlg.m_pVidBuffer; - CComPtr pAudBuffer = m_wndCaptureBar.m_capdlg.m_pAudBuffer; - CComPtr pVidEnc = m_wndCaptureBar.m_capdlg.m_pVidEnc; - CComPtr pAudEnc = m_wndCaptureBar.m_capdlg.m_pAudEnc; - CComPtr pMux = m_wndCaptureBar.m_capdlg.m_pMux; - CComPtr pDst = m_wndCaptureBar.m_capdlg.m_pDst; - CComPtr pAudMux = m_wndCaptureBar.m_capdlg.m_pAudMux; - CComPtr pAudDst = m_wndCaptureBar.m_capdlg.m_pAudDst; - - bool fFileOutput = (pMux && pDst) || (pAudMux && pAudDst); - bool fCapture = (fVCapture || fACapture); - - if (m_pAudCap) { - AM_MEDIA_TYPE* pmt = &m_wndCaptureBar.m_capdlg.m_mta; - int ms = (fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput) ? AUDIOBUFFERLEN : 60; - if (pMux != pAudMux && fACapture) { - SetLatency(m_pAudCap, -1); - } else if (pmt->pbFormat) { - SetLatency(m_pAudCap, ((WAVEFORMATEX*)pmt->pbFormat)->nAvgBytesPerSec * ms / 1000); - } - } - - CComPtr pVidCapPin, pVidPrevPin, pAudCapPin, pAudPrevPin; - BuildToCapturePreviewPin(m_pVidCap, &pVidCapPin, &pVidPrevPin, m_pAudCap, &pAudCapPin, &pAudPrevPin); - - //if (m_pVidCap) - { - bool fVidPrev = pVidPrevPin && fVPreview; - bool fVidCap = pVidCapPin && fVCapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fVidOutput; - - if (fVPreview == 2 && !fVidCap && pVidCapPin) { - pVidPrevPin = pVidCapPin; - pVidCapPin = nullptr; - } - - if (fVidPrev) { - m_pMVRS.Release(); - m_pMVRFG.Release(); - m_pMVRSR.Release(); - - m_OSD.Stop(); - m_pCAP3.Release(); - m_pCAP2.Release(); - m_pCAP.Release(); - m_pVMRWC.Release(); - m_pVMRMC.Release(); - m_pVMB.Release(); - m_pMFVMB.Release(); - m_pMFVP.Release(); - m_pMFVDC.Release(); - m_pQP.Release(); - - m_pGB->Render(pVidPrevPin); - - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP2), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP3), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRWC), FALSE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRMC), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMB), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVMB), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVDC), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVP), TRUE); - m_pMVTO = m_pCAP; - m_pMVRSR = m_pCAP; - m_pMVRS = m_pCAP; - m_pMVRFG = m_pCAP; - - const CAppSettings& s = AfxGetAppSettings(); - m_pVideoWnd = &m_wndView; - - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } else if (m_pVMRWC) { - m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); - } - - if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is used - m_OSD.Stop(); - - if (m_pMVTO) { - m_OSD.Start(m_pVideoWnd, m_pMVTO); - } else if (m_fFullScreen && !m_fAudioOnly && m_pCAP3) { // MPCVR - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); - } else if (!m_fAudioOnly && IsD3DFullScreenMode() && (m_pVMB || m_pMFVMB)) { - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); - } else { - m_OSD.Start(m_pOSDWnd); - } - } - } - - if (fVidCap) { - IBaseFilter* pBF[3] = {pVidBuffer, pVidEnc, pMux}; - HRESULT hr2 = BuildCapture(pVidCapPin, pBF, MEDIATYPE_Video, &m_wndCaptureBar.m_capdlg.m_mtcv); - UNREFERENCED_PARAMETER(hr2); - } - - m_pAMDF.Release(); - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMDF)))) { - TRACE(_T("Warning: No IAMDroppedFrames interface for vidcap capture")); - } - } - - //if (m_pAudCap) - { - bool fAudPrev = pAudPrevPin && fAPreview; - bool fAudCap = pAudCapPin && fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput; - - if (fAPreview == 2 && !fAudCap && pAudCapPin) { - pAudPrevPin = pAudCapPin; - pAudCapPin = nullptr; - } - - if (fAudPrev) { - m_pGB->Render(pAudPrevPin); - } - - if (fAudCap) { - IBaseFilter* pBF[3] = {pAudBuffer, pAudEnc, pAudMux ? pAudMux : pMux}; - HRESULT hr2 = BuildCapture(pAudCapPin, pBF, MEDIATYPE_Audio, &m_wndCaptureBar.m_capdlg.m_mtca); - UNREFERENCED_PARAMETER(hr2); - } - } - - if ((m_pVidCap || m_pAudCap) && fCapture && fFileOutput) { - if (pMux != pDst) { - hr = m_pGB->AddFilter(pDst, L"File Writer V/A"); - hr = m_pGB->ConnectFilter(GetFirstPin(pMux, PINDIR_OUTPUT), pDst); - } - - if (CComQIPtr pCAM = pMux) { - int nIn, nOut, nInC, nOutC; - CountPins(pMux, nIn, nOut, nInC, nOutC); - pCAM->SetMasterStream(nInC - 1); - //pCAM->SetMasterStream(-1); - pCAM->SetOutputCompatibilityIndex(FALSE); - } - - if (CComQIPtr pCI = pMux) { - //if (FAILED(pCI->put_Mode(INTERLEAVE_CAPTURE))) - if (FAILED(pCI->put_Mode(INTERLEAVE_NONE_BUFFERED))) { - pCI->put_Mode(INTERLEAVE_NONE); - } - - REFERENCE_TIME rtInterleave = 10000i64 * AUDIOBUFFERLEN, rtPreroll = 0; //10000i64*500 - pCI->put_Interleaving(&rtInterleave, &rtPreroll); - } - - if (pMux != pAudMux && pAudMux != pAudDst) { - hr = m_pGB->AddFilter(pAudDst, L"File Writer A"); - hr = m_pGB->ConnectFilter(GetFirstPin(pAudMux, PINDIR_OUTPUT), pAudDst); - } - } - - REFERENCE_TIME stop = MAX_TIME; - hr = m_pCGB->ControlStream(&PIN_CATEGORY_CAPTURE, nullptr, nullptr, nullptr, &stop, 0, 0); // stop in the infinite - - CleanGraph(); - - OpenSetupVideo(); - OpenSetupAudio(); - OpenSetupStatsBar(); - OpenSetupStatusBar(); - RecalcLayout(); - - SetupVMR9ColorControl(); - - if (GetLoadState() == MLS::LOADED) { - if (fs == State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } else if (fs == State_Paused) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - } - - return true; -} - -bool CMainFrame::StartCapture() -{ - if (!m_pCGB || m_fCapturing) { - return false; - } - - if (!m_wndCaptureBar.m_capdlg.m_pMux && !m_wndCaptureBar.m_capdlg.m_pDst) { - return false; - } - - HRESULT hr; - - ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); - - // rare to see two capture filters to support IAMPushSource at the same time... - //hr = CComQIPtr(m_pGB)->SyncUsingStreamOffset(TRUE); // TODO: - - BuildGraphVideoAudio( - m_wndCaptureBar.m_capdlg.m_fVidPreview, true, - m_wndCaptureBar.m_capdlg.m_fAudPreview, true); - - hr = m_pME->CancelDefaultHandling(EC_REPAINT); - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - m_fCapturing = true; - - return true; -} - -bool CMainFrame::StopCapture() -{ - if (!m_pCGB || !m_fCapturing) { - return false; - } - - if (!m_wndCaptureBar.m_capdlg.m_pMux && !m_wndCaptureBar.m_capdlg.m_pDst) { - return false; - } - - m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_COMPLETING)); - m_fCapturing = false; - - BuildGraphVideoAudio( - m_wndCaptureBar.m_capdlg.m_fVidPreview, false, - m_wndCaptureBar.m_capdlg.m_fAudPreview, false); - - m_pME->RestoreDefaultHandling(EC_REPAINT); - - ::SetPriorityClass(::GetCurrentProcess(), AfxGetAppSettings().dwPriority); - - m_rtDurationOverride = -1; - - return true; -} - -// - -void CMainFrame::ShowOptions(int idPage/* = 0*/) -{ - // Disable the options dialog when using D3D fullscreen - if (IsD3DFullScreenMode() && !m_bFullScreenWindowIsOnSeparateDisplay) { - return; - } - - // show warning when INI file is read-only - CPath iniPath = AfxGetMyApp()->GetIniPath(); - if (PathUtils::Exists(iniPath)) { - HANDLE hFile = CreateFile(iniPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - if (hFile == INVALID_HANDLE_VALUE) { - AfxMessageBox(_T("The player settings are currently stored in an INI file located in the installation directory of the player.\n\nThe player currently does not have write access to this file, meaning any changes to the settings will not be saved.\n\nPlease remove the INI file to ensure proper functionality of the player.\n\nSettings will then be stored in the Windows Registry. You can easily backup those settings through: Options > Miscellaneous > Export"), MB_ICONWARNING, 0); - } - CloseHandle(hFile); - } - - INT_PTR iRes; - do { - CPPageSheet options(ResStr(IDS_OPTIONS_CAPTION), m_pGB, GetModalParent(), idPage); - iRes = options.DoModal(); - idPage = 0; // If we are to show the dialog again, always show the latest page - } while (iRes == CPPageSheet::APPLY_LANGUAGE_CHANGE); // check if we exited the dialog so that the language change can be applied - - switch (iRes) { - case CPPageSheet::RESET_SETTINGS: - // Request MPC-HC to close itself - SendMessage(WM_CLOSE); - // and immediately reopen - ShellExecute(nullptr, _T("open"), PathUtils::GetProgramPath(true), _T("/reset"), nullptr, SW_SHOWNORMAL); - break; - default: - ASSERT(iRes > 0 && iRes != CPPageSheet::APPLY_LANGUAGE_CHANGE); - break; - } -} - -void CMainFrame::StartWebServer(int nPort) -{ - if (!m_pWebServer) { - m_pWebServer.Attach(DEBUG_NEW CWebServer(this, nPort)); - } -} - -void CMainFrame::StopWebServer() -{ - if (m_pWebServer) { - m_pWebServer.Free(); - } -} - -void CMainFrame::SendStatusMessage(CString msg, int nTimeOut) -{ - const auto timerId = TimerOneTimeSubscriber::STATUS_ERASE; - - m_timerOneTime.Unsubscribe(timerId); - - m_tempstatus_msg.Empty(); - if (nTimeOut <= 0) { - return; - } - - m_tempstatus_msg = msg; - m_timerOneTime.Subscribe(timerId, [this] { m_tempstatus_msg.Empty(); }, nTimeOut); - - m_Lcd.SetStatusMessage(msg, nTimeOut); -} - -bool CMainFrame::CanPreviewUse() { - return (m_bUseSeekPreview && m_wndPreView && !m_fAudioOnly && m_eMediaLoadState == MLS::LOADED - && (GetPlaybackMode() == PM_DVD || GetPlaybackMode() == PM_FILE)); -} - -void CMainFrame::OpenCurPlaylistItem(REFERENCE_TIME rtStart, bool reopen /* = false */, ABRepeat abRepeat /* = ABRepeat() */) -{ - if (IsPlaylistEmpty()) { - return; - } - - CPlaylistItem pli; - if (!m_wndPlaylistBar.GetCur(pli)) { - m_wndPlaylistBar.SetFirstSelected(); - if (!m_wndPlaylistBar.GetCur(pli)) { - return; - } - } - - if (pli.m_bYoutubeDL && (reopen || pli.m_fns.GetHead() == pli.m_ydlSourceURL && m_sydlLastProcessURL != pli.m_ydlSourceURL)) { - if (ProcessYoutubeDLURL(pli.m_ydlSourceURL, false, true)) { - OpenCurPlaylistItem(rtStart, false); - return; - } - } - - CAutoPtr p(m_wndPlaylistBar.GetCurOMD(rtStart, abRepeat)); - if (p) { - OpenMedia(p); - } -} - -void CMainFrame::AddCurDevToPlaylist() -{ - if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - m_wndPlaylistBar.Append( - m_VidDispName, - m_AudDispName, - m_wndCaptureBar.m_capdlg.GetVideoInput(), - m_wndCaptureBar.m_capdlg.GetVideoChannel(), - m_wndCaptureBar.m_capdlg.GetAudioInput() - ); - } -} - -void CMainFrame::OpenMedia(CAutoPtr pOMD) -{ - auto pFileData = dynamic_cast(pOMD.m_p); - //auto pDVDData = dynamic_cast(pOMD.m_p); - auto pDeviceData = dynamic_cast(pOMD.m_p); - - // if the tuner graph is already loaded, we just change its channel - if (pDeviceData) { - if (GetLoadState() == MLS::LOADED && m_pAMTuner - && m_VidDispName == pDeviceData->DisplayName[0] && m_AudDispName == pDeviceData->DisplayName[1]) { - m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput); - m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel); - m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput); - SendNowPlayingToSkype(); - return; - } - } - - CloseMediaBeforeOpen(); - - // if the file is on some removable drive and that drive is missing, - // we yell at user before even trying to construct the graph - if (pFileData) { - CString fn = pFileData->fns.GetHead(); - int i = fn.Find(_T(":\\")); - if (i > 0) { - CString drive = fn.Left(i + 2); - UINT type = GetDriveType(drive); - CAtlList sl; - if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM && GetOpticalDiskType(drive[0], sl) != OpticalDisk_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.GetString()); - ret = AfxMessageBox(msg, MB_RETRYCANCEL); - } - } - if (ret != IDOK) { - return; - } - } - } - } - - ASSERT(!m_bOpenMediaActive); - m_bOpenMediaActive = true; - - // clear BD playlist if we are not currently opening something from it - if (!m_bIsBDPlay) { - m_MPLSPlaylist.clear(); - m_LastOpenBDPath = _T(""); - } - m_bIsBDPlay = false; - - // no need to try releasing external objects while playing - KillTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS); - - // we hereby proclaim - SetLoadState(MLS::LOADING); - - const auto& s = AfxGetAppSettings(); - - // use the graph thread only for some media types - bool bDirectShow = pFileData && !pFileData->fns.IsEmpty() && s.m_Formats.GetEngine(pFileData->fns.GetHead()) == DirectShow; - bool bUseThread = m_pGraphThread && s.fEnableWorkerThreadForOpening && (bDirectShow || !pFileData) && (s.iDefaultCaptureDevice == 1 || !pDeviceData); - bool wasMaximized = IsZoomed(); - // create d3dfs window if launching in fullscreen and d3dfs is enabled - if (s.IsD3DFullscreen() && m_fStartInD3DFullscreen) { - CreateFullScreenWindow(); - m_pVideoWnd = m_pDedicatedFSVideoWnd; - m_fStartInD3DFullscreen = false; - } else if (m_fStartInFullscreenSeparate) { - CreateFullScreenWindow(false); - m_pVideoWnd = m_pDedicatedFSVideoWnd; - m_fStartInFullscreenSeparate = false; - m_bNeedZoomAfterFullscreenExit = true; - } else { - m_pVideoWnd = &m_wndView; - } - - // activate auto-fit logic upon exiting fullscreen if - // we are opening new media in fullscreen mode - // adipose: unless we were previously maximized - if ((IsFullScreenMode()) && s.fRememberZoomLevel && !wasMaximized) { - m_bNeedZoomAfterFullscreenExit = true; - } - - // don't set video renderer output rect until the window is repositioned - m_bDelaySetOutputRect = true; - -#if 0 - // display corresponding media icon in status bar - if (pFileData) { - CString filename = m_wndPlaylistBar.GetCurFileName(); - CString ext = filename.Mid(filename.ReverseFind('.') + 1); - m_wndStatusBar.SetMediaType(ext); - } else if (pDVDData) { - m_wndStatusBar.SetMediaType(_T(".ifo")); - } else { - // TODO: Create icons for pDeviceData - m_wndStatusBar.SetMediaType(_T(".unknown")); - } -#endif - - // initiate graph creation, OpenMediaPrivate() will call OnFilePostOpenmedia() - if (bUseThread) { - VERIFY(m_evOpenPrivateFinished.Reset()); - VERIFY(m_pGraphThread->PostThreadMessage(CGraphThread::TM_OPEN, (WPARAM)0, (LPARAM)pOMD.Detach())); - m_bOpenedThroughThread = true; - } else { - OpenMediaPrivate(pOMD); - m_bOpenedThroughThread = false; - } -} - -bool CMainFrame::ResetDevice() -{ - if (m_pCAP2_preview) { - m_pCAP2_preview->ResetDevice(); - } - if (m_pCAP) { - return m_pCAP->ResetDevice(); - } - return true; -} - -bool CMainFrame::DisplayChange() -{ - if (m_pCAP2_preview) { - m_pCAP2_preview->DisplayChange(); - } - if (m_pCAP) { - return m_pCAP->DisplayChange(); - } - return true; -} - -void CMainFrame::CloseMediaBeforeOpen() -{ - if (GetLoadState() != MLS::CLOSED) { - CloseMedia(true); - } -} - -void CMainFrame::ForceCloseProcess() -{ - MessageBeep(MB_ICONEXCLAMATION); - if (CrashReporter::IsEnabled()) { - CrashReporter::Disable(); - } - TerminateProcess(GetCurrentProcess(), 0xDEADBEEF); -} - -void CMainFrame::CloseMedia(bool bNextIsQueued/* = false*/, bool bPendingFileDelete/* = false*/) -{ - TRACE(_T("CMainFrame::CloseMedia\n")); - - m_dwLastPause = 0; - - if (m_bUseSeekPreview && m_wndPreView.IsWindowVisible()) { - m_wndPreView.ShowWindow(SW_HIDE); - } - m_bUseSeekPreview = false; - m_bDVDStillOn = false; - - if (GetLoadState() == MLS::CLOSING || GetLoadState() == MLS::CLOSED) { - TRACE(_T("Ignoring duplicate close action.\n")); - return; - } - - m_media_trans_control.close(); - - if (m_bSettingUpMenus) { - SleepEx(500, false); - ASSERT(!m_bSettingUpMenus); - } - - auto& s = AfxGetAppSettings(); - bool savehistory = false; - if (GetLoadState() == MLS::LOADED) { - // abort sub search - m_pSubtitlesProviders->Abort(SubtitlesThreadType(STT_SEARCH | STT_DOWNLOAD)); - m_wndSubtitlesDownloadDialog.DoClear(); - - // save playback position - if (s.fKeepHistory && !bPendingFileDelete) { - if (m_bRememberFilePos && !m_fEndOfStream && m_dwReloadPos == 0 && m_pMS) { - REFERENCE_TIME rtNow = 0; - m_pMS->GetCurrentPosition(&rtNow); - if (rtNow > 0) { - REFERENCE_TIME rtDur = 0; - m_pMS->GetDuration(&rtDur); - if (rtNow >= rtDur || rtDur - rtNow < 50000000LL) { // at end of file - rtNow = 0; - } - } - s.MRU.UpdateCurrentFilePosition(rtNow, true); - } else if (GetPlaybackMode() == PM_DVD && m_pDVDI) { - DVD_DOMAIN DVDDomain; - if (SUCCEEDED(m_pDVDI->GetCurrentDomain(&DVDDomain))) { - if (DVDDomain == DVD_DOMAIN_Title) { - DVD_PLAYBACK_LOCATION2 Location2; - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location2))) { - DVD_POSITION dvdPosition = s.MRU.GetCurrentDVDPosition(); - if (dvdPosition.llDVDGuid) { - dvdPosition.lTitle = Location2.TitleNum; - dvdPosition.timecode = Location2.TimeCode; - } - } - } - } - } - } - - if (m_pME) { - m_pME->SetNotifyWindow(NULL, 0, 0); - } - - // save external subtitle - if (g_bExternalSubtitle && !bPendingFileDelete && - m_pCurrentSubInput.pSubStream && m_pCurrentSubInput.pSubStream->GetPath().IsEmpty()) { - const auto& s = AfxGetAppSettings(); - if (s.bAutoSaveDownloadedSubtitles) { - CString dirBuffer; - LPCTSTR dir = nullptr; - if (!s.strSubtitlePaths.IsEmpty()) { - auto start = s.strSubtitlePaths.Left(2); - if (start != _T(".") && start != _T(".;")) { - int pos = 0; - dir = dirBuffer = s.strSubtitlePaths.Tokenize(_T(";"), pos); - } - } - SubtitlesSave(dir, true); - } - } - - if (s.fKeepHistory && !bPendingFileDelete) { - savehistory = true; - } - } - - // delay showing auto-hidden controls if new media is queued - if (bNextIsQueued) { - m_controls.DelayShowNotLoaded(true); - } else { - m_controls.DelayShowNotLoaded(false); - } - - // abort if loading - bool bGraphTerminated = false; - if (GetLoadState() == MLS::LOADING) { - TRACE(_T("Media is still loading. Aborting graph.\n")); - - // tell OpenMediaPrivate() that we want to abort - m_fOpeningAborted = true; - - // close pin connection error dialog - if (mediaTypesErrorDlg) { - mediaTypesErrorDlg->SendMessage(WM_EXTERNALCLOSE, 0, 0); - // wait till error dialog has been closed - CAutoLock lck(&lockModalDialog); - } - - // abort current graph task - if (m_pGB) { - if (!m_pAMOP) { - m_pAMOP = m_pGB; - if (!m_pAMOP) { - BeginEnumFilters(m_pGB, pEF, pBF) - if (m_pAMOP = pBF) { - break; - } - EndEnumFilters; - } - } - if (m_pAMOP) { - m_pAMOP->AbortOperation(); - } - m_pGB->Abort(); // TODO: lock on graph objects somehow, this is not thread safe - } - if (m_pGB_preview) { - m_pGB_preview->Abort(); - } - - if (m_bOpenedThroughThread) { - BeginWaitCursor(); - MSG msg; - HANDLE h = m_evOpenPrivateFinished; - bool killprocess = true; - bool processmsg = true; - ULONGLONG start = GetTickCount64(); - while (processmsg && (GetTickCount64() - start < 6000ULL)) { - DWORD res = MsgWaitForMultipleObjectsEx(1, &h, 1000, QS_ALLINPUT, MWMO_INPUTAVAILABLE); - switch (res) { - case WAIT_OBJECT_0: - TRACE(_T("Graph abort successful\n")); - killprocess = false; // event has been signalled - processmsg = false; - break; - case WAIT_OBJECT_0 + 1: - // we have a message - peek and dispatch it - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - break; - case WAIT_TIMEOUT: - break; - default: // unexpected failure - processmsg = false; - break; - } - } - if (killprocess) - { - // Aborting graph failed - TRACE(_T("Failed to abort graph creation.\n")); - ForceCloseProcess(); - } - EndWaitCursor(); - } else { - // Aborting graph failed - TRACE(_T("Failed to abort graph creation.\n")); - ForceCloseProcess(); - } - - MSG msg; - // purge possible queued OnFilePostOpenmedia() - if (PeekMessage(&msg, m_hWnd, WM_POSTOPEN, WM_POSTOPEN, PM_REMOVE | PM_NOYIELD)) { - free((OpenMediaData*)msg.lParam); - } - // purge possible queued OnOpenMediaFailed() - if (PeekMessage(&msg, m_hWnd, WM_OPENFAILED, WM_OPENFAILED, PM_REMOVE | PM_NOYIELD)) { - free((OpenMediaData*)msg.lParam); - } - - // abort finished, unset the flag - m_fOpeningAborted = false; - } - - // we are on the way - m_bSettingUpMenus = true; - SetLoadState(MLS::CLOSING); - - if (m_pGB_preview) { - PreviewWindowHide(); - m_bUseSeekPreview = false; - } - - // stop the graph before destroying it - OnPlayStop(true); - - // clear any active osd messages - //m_OSD.ClearMessage(); - - // Ensure the dynamically added menu items are cleared and all references - // on objects belonging to the DirectShow graph they might hold are freed. - // Note that we need to be in closing state already when doing that - if (m_hWnd) { - SetupFiltersSubMenu(); - SetupAudioSubMenu(); - SetupSubtitlesSubMenu(); - SetupVideoStreamsSubMenu(); - SetupJumpToSubMenus(); - } - - m_bSettingUpMenus = false; - - // initiate graph destruction - if (m_pGraphThread && m_bOpenedThroughThread && !bGraphTerminated) { - // either opening or closing has to be blocked to prevent reentering them, closing is the better choice - VERIFY(m_evClosePrivateFinished.Reset()); - VERIFY(m_pGraphThread->PostThreadMessage(CGraphThread::TM_CLOSE, (WPARAM)0, (LPARAM)0)); - - HANDLE handle = m_evClosePrivateFinished; - DWORD dwWait; - ULONGLONG start = GetTickCount64(); - ULONGLONG waitdur = 10000ULL; - bool killprocess = true; - bool processmsg = true; - bool extendedwait = false; - while (processmsg) { - dwWait = MsgWaitForMultipleObjects(1, &handle, FALSE, 1000, QS_SENDMESSAGE); - switch (dwWait) { - case WAIT_OBJECT_0: - processmsg = false; // event received - killprocess = false; - break; - case WAIT_OBJECT_0 + 1: - MSG msg; - PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE); - break; - case WAIT_TIMEOUT: - break; - default: - processmsg = false; - break; - } - - if (processmsg && (GetTickCount64() - start > waitdur)) { - if (extendedwait || m_fFullScreen) { - processmsg = false; - } else { - CString msg; - if (!m_pGB && m_pGB_preview) { -#if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER && (MPC_VERSION_REV > 10) && 0 - if (CrashReporter::IsEnabled()) { - throw 1; - } -#endif - msg = L"Timeout when closing preview filter graph.\n\nClick YES to terminate player process. Click NO to wait longer (up to 15 seconds)."; - } else { - msg = L"Timeout when closing filter graph.\n\nClick YES to terminate player process. Click NO to wait longer (up to 15 seconds)."; - } - if (IDYES == AfxMessageBox(msg, MB_ICONEXCLAMATION | MB_YESNO, 0)) { - processmsg = false; - } else { - extendedwait = true; - start = GetTickCount64(); - waitdur = 15000ULL; - } - } - } - } - if (killprocess) { - TRACE(_T("Failed to close filter graph thread.\n")); - ForceCloseProcess(); - } - } else { - CloseMediaPrivate(); - } - - // graph is destroyed, update stuff - OnFilePostClosemedia(bNextIsQueued); - - if (savehistory) { - s.MRU.WriteCurrentEntry(); - } - s.MRU.current_rfe_hash.Empty(); - - TRACE(_T("Close media completed\n")); -} - -void CMainFrame::StartTunerScan(CAutoPtr pTSD) -{ - // Remove the old info during the scan - if (m_pDVBState) { - m_pDVBState->Reset(); - } - m_wndInfoBar.RemoveAllLines(); - m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); - RecalcLayout(); - OpenSetupWindowTitle(); - SendNowPlayingToSkype(); - - if (m_pGraphThread) { - m_pGraphThread->PostThreadMessage(CGraphThread::TM_TUNER_SCAN, (WPARAM)0, (LPARAM)pTSD.Detach()); - } else { - DoTunerScan(pTSD); - } -} - -void CMainFrame::StopTunerScan() -{ - m_bStopTunerScan = true; -} - -HRESULT CMainFrame::SetChannel(int nChannel) -{ - CAppSettings& s = AfxGetAppSettings(); - HRESULT hr = S_OK; - CComQIPtr pTun = m_pGB; - CBDAChannel* pChannel = s.FindChannelByPref(nChannel); - - if (s.m_DVBChannels.empty() && nChannel == INT_ERROR) { - hr = S_FALSE; // All channels have been cleared or it is the first start - } else if (pTun && pChannel && !m_pDVBState->bSetChannelActive) { - m_pDVBState->Reset(); - m_wndInfoBar.RemoveAllLines(); - m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); - RecalcLayout(); - m_pDVBState->bSetChannelActive = true; - - // Skip n intermediate ZoomVideoWindow() calls while the new size is stabilized: - switch (s.iDSVideoRendererType) { - case VIDRNDT_DS_MADVR: - if (s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS) { - m_nLockedZoomVideoWindow = 3; - } else { - m_nLockedZoomVideoWindow = 0; - } - break; - case VIDRNDT_DS_EVR_CUSTOM: - m_nLockedZoomVideoWindow = 0; - break; - default: - m_nLockedZoomVideoWindow = 0; - } - if (SUCCEEDED(hr = pTun->SetChannel(nChannel))) { - if (hr == S_FALSE) { - // Re-create all - m_nLockedZoomVideoWindow = 0; - PostMessage(WM_COMMAND, ID_FILE_OPENDEVICE); - return hr; - } - - m_pDVBState->bActive = true; - m_pDVBState->pChannel = pChannel; - m_pDVBState->sChannelName = pChannel->GetName(); - - m_wndInfoBar.SetLine(ResStr(IDS_INFOBAR_CHANNEL), m_pDVBState->sChannelName); - RecalcLayout(); - - if (s.fRememberZoomLevel && !(m_fFullScreen || IsZoomed() || IsIconic())) { - ZoomVideoWindow(); - } - MoveVideoWindow(); - - // Add temporary flag to allow EC_VIDEO_SIZE_CHANGED event to stabilize window size - // for 5 seconds since playback starts - m_bAllowWindowZoom = true; - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::AUTOFIT_TIMEOUT, [this] - { m_bAllowWindowZoom = false; }, 5000); - - UpdateCurrentChannelInfo(); - } - m_pDVBState->bSetChannelActive = false; - } else { - hr = E_FAIL; - ASSERT(FALSE); - } - - return hr; -} - -void CMainFrame::UpdateCurrentChannelInfo(bool bShowOSD /*= true*/, bool bShowInfoBar /*= false*/) -{ - const CBDAChannel* pChannel = m_pDVBState->pChannel; - CComQIPtr pTun = m_pGB; - - if (!m_pDVBState->bInfoActive && pChannel && pTun) { - if (m_pDVBState->infoData.valid()) { - m_pDVBState->bAbortInfo = true; - m_pDVBState->infoData.get(); - } - m_pDVBState->bAbortInfo = false; - m_pDVBState->bInfoActive = true; - m_pDVBState->infoData = std::async(std::launch::async, [this, pChannel, pTun, bShowOSD, bShowInfoBar] { - DVBState::EITData infoData; - infoData.hr = pTun->UpdatePSI(pChannel, infoData.NowNext); - infoData.bShowOSD = bShowOSD; - infoData.bShowInfoBar = bShowInfoBar; - if (m_pDVBState && !m_pDVBState->bAbortInfo) - { - PostMessage(WM_DVB_EIT_DATA_READY); - } - return infoData; - }); - } -} - -LRESULT CMainFrame::OnCurrentChannelInfoUpdated(WPARAM wParam, LPARAM lParam) -{ - if (!m_pDVBState->bAbortInfo && m_pDVBState->infoData.valid()) { - EventDescriptor& NowNext = m_pDVBState->NowNext; - const auto infoData = m_pDVBState->infoData.get(); - NowNext = infoData.NowNext; - - if (infoData.hr != S_FALSE) { - // Set a timer to update the infos only if channel has now/next flag - time_t tNow; - time(&tNow); - time_t tElapse = NowNext.duration - (tNow - NowNext.startTime); - if (tElapse < 0) { - tElapse = 0; - } - // We set a 15s delay to let some room for the program infos to change - tElapse += 15; - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DVBINFO_UPDATE, - [this] { UpdateCurrentChannelInfo(false, false); }, - 1000 * (UINT)tElapse); - m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(true); - } else { - m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); - } - - CString sChannelInfo = m_pDVBState->sChannelName; - m_wndInfoBar.RemoveAllLines(); - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CHANNEL), sChannelInfo); - - if (infoData.hr == S_OK) { - // EIT information parsed correctly - if (infoData.bShowOSD) { - sChannelInfo.AppendFormat(_T(" | %s (%s - %s)"), NowNext.eventName.GetString(), NowNext.strStartTime.GetString(), NowNext.strEndTime.GetString()); - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TITLE), NowNext.eventName); - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TIME), NowNext.strStartTime + _T(" - ") + NowNext.strEndTime); - - if (NowNext.parentalRating >= 0) { - CString parentRating; - if (!NowNext.parentalRating) { - parentRating.LoadString(IDS_NO_PARENTAL_RATING); - } else { - parentRating.Format(IDS_PARENTAL_RATING, NowNext.parentalRating); - } - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_PARENTAL_RATING), parentRating); - } - - if (!NowNext.content.IsEmpty()) { - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CONTENT), NowNext.content); - } - - CString description = NowNext.eventDesc; - if (!NowNext.extendedDescriptorsText.IsEmpty()) { - if (!description.IsEmpty()) { - description += _T("; "); - } - description += NowNext.extendedDescriptorsText; - } - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); - - for (const auto& item : NowNext.extendedDescriptorsItems) { - m_wndInfoBar.SetLine(item.first, item.second); - } - - if (infoData.bShowInfoBar && !m_controls.ControlChecked(CMainFrameControls::Toolbar::INFO)) { - m_controls.ToggleControl(CMainFrameControls::Toolbar::INFO); - } - } - - RecalcLayout(); - if (infoData.bShowOSD) { - m_OSD.DisplayMessage(OSD_TOPLEFT, sChannelInfo, 3500); - } - - // Update window title and skype status - OpenSetupWindowTitle(); - SendNowPlayingToSkype(); - } else { - ASSERT(FALSE); - } - - m_pDVBState->bInfoActive = false; - - return 0; -} - -// ==== Added by CASIMIR666 -void CMainFrame::SetLoadState(MLS eState) -{ - m_eMediaLoadState = eState; - SendAPICommand(CMD_STATE, L"%d", static_cast(eState)); - if (eState == MLS::LOADED) { - m_controls.DelayShowNotLoaded(false); - m_eventc.FireEvent(MpcEvent::MEDIA_LOADED); - } - UpdateControlState(UPDATE_CONTROLS_VISIBILITY); -} - -inline MLS CMainFrame::GetLoadState() const -{ - return m_eMediaLoadState; -} - -void CMainFrame::SetPlayState(MPC_PLAYSTATE iState) -{ - m_Lcd.SetPlayState((CMPC_Lcd::PlayState)iState); - SendAPICommand(CMD_PLAYMODE, L"%d", iState); - - if (m_fEndOfStream) { - SendAPICommand(CMD_NOTIFYENDOFSTREAM, L"\0"); // do not pass NULL here! - } - - if (iState == PS_PLAY) { - // Prevent sleep when playing audio and/or video, but allow screensaver when only audio - if (!m_fAudioOnly && AfxGetAppSettings().bPreventDisplaySleep) { - SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED); - } else { - SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); - } - } else { - SetThreadExecutionState(ES_CONTINUOUS); - } - - - UpdateThumbarButton(iState); -} - -bool CMainFrame::CreateFullScreenWindow(bool isD3D /* = true */) -{ - if (m_bFullScreenWindowIsD3D == isD3D && HasDedicatedFSVideoWindow()) { - return false; - } - const CAppSettings& s = AfxGetAppSettings(); - CMonitors monitors; - CMonitor monitor, currentMonitor; - - if (m_pDedicatedFSVideoWnd->IsWindow()) { - m_pDedicatedFSVideoWnd->DestroyWindow(); - } - - currentMonitor = monitors.GetNearestMonitor(this); - if (s.iMonitor == 0) { - monitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); - } - if (!monitor.IsMonitor()) { - monitor = currentMonitor; - } - - CRect monitorRect; - monitor.GetMonitorRect(monitorRect); - - m_bFullScreenWindowIsD3D = isD3D; - m_bFullScreenWindowIsOnSeparateDisplay = monitor != currentMonitor; - - // allow the mainframe to keep focus - bool ret = !!m_pDedicatedFSVideoWnd->CreateEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, _T(""), ResStr(IDS_MAINFRM_136), WS_POPUP, monitorRect, nullptr, 0); - if (ret) { - m_pDedicatedFSVideoWnd->ShowWindow(SW_SHOWNOACTIVATE); - } - return ret; -} - -bool CMainFrame::IsFrameLessWindow() const -{ - return (IsFullScreenMainFrame() || AfxGetAppSettings().eCaptionMenuMode == MODE_BORDERLESS); -} - -bool CMainFrame::IsCaptionHidden() const -{ - // If no caption, there is no menu bar. But if is no menu bar, then the caption can be. - return (!IsFullScreenMainFrame() && AfxGetAppSettings().eCaptionMenuMode > MODE_HIDEMENU); //!=MODE_SHOWCAPTIONMENU && !=MODE_HIDEMENU -} - -bool CMainFrame::IsMenuHidden() const -{ - return (!IsFullScreenMainFrame() && AfxGetAppSettings().eCaptionMenuMode != MODE_SHOWCAPTIONMENU); -} - -bool CMainFrame::IsPlaylistEmpty() const -{ - return (m_wndPlaylistBar.GetCount() == 0); -} - -bool CMainFrame::IsInteractiveVideo() const -{ - return m_fShockwaveGraph; -} - -bool CMainFrame::IsFullScreenMode() const { - return m_fFullScreen || IsD3DFullScreenMode(); -} - -bool CMainFrame::IsFullScreenMainFrame() const { - return m_fFullScreen && !HasDedicatedFSVideoWindow(); -} - -bool CMainFrame::IsFullScreenMainFrameExclusiveMPCVR() const { - return m_fFullScreen && m_bIsMPCVRExclusiveMode && !HasDedicatedFSVideoWindow(); -} - -bool CMainFrame::IsFullScreenSeparate() const { - return m_fFullScreen && HasDedicatedFSVideoWindow() && !m_bFullScreenWindowIsD3D; -} - -bool CMainFrame::HasDedicatedFSVideoWindow() const { - return m_pDedicatedFSVideoWnd && m_pDedicatedFSVideoWnd->IsWindow(); -} - -bool CMainFrame::IsD3DFullScreenMode() const -{ - return HasDedicatedFSVideoWindow() && m_bFullScreenWindowIsD3D; -}; - -bool CMainFrame::IsSubresyncBarVisible() const -{ - return !!m_wndSubresyncBar.IsWindowVisible(); -} - -void CMainFrame::SetupEVRColorControl() -{ - if (m_pMFVP) { - CMPlayerCApp* pApp = AfxGetMyApp(); - CAppSettings& s = AfxGetAppSettings(); - - if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Brightness, pApp->GetEVRColorControl(ProcAmp_Brightness)))) { - return; - } - if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Contrast, pApp->GetEVRColorControl(ProcAmp_Contrast)))) { - return; - } - if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Hue, pApp->GetEVRColorControl(ProcAmp_Hue)))) { - return; - } - if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Saturation, pApp->GetEVRColorControl(ProcAmp_Saturation)))) { - return; - } - - pApp->UpdateColorControlRange(true); - SetColorControl(ProcAmp_All, s.iBrightness, s.iContrast, s.iHue, s.iSaturation); - } -} - -// Called from GraphThread -void CMainFrame::SetupVMR9ColorControl() -{ - if (m_pVMRMC) { - CMPlayerCApp* pApp = AfxGetMyApp(); - CAppSettings& s = AfxGetAppSettings(); - - if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Brightness)))) { - return; - } - if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Contrast)))) { - return; - } - if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Hue)))) { - return; - } - if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Saturation)))) { - return; - } - - pApp->UpdateColorControlRange(false); - SetColorControl(ProcAmp_All, s.iBrightness, s.iContrast, s.iHue, s.iSaturation); - } -} - -void CMainFrame::SetColorControl(DWORD flags, int& brightness, int& contrast, int& hue, int& saturation) -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - HRESULT hr = 0; - - static VMR9ProcAmpControl ClrControl; - static DXVA2_ProcAmpValues ClrValues; - - COLORPROPERTY_RANGE* cr = 0; - if (flags & ProcAmp_Brightness) { - cr = pApp->GetColorControl(ProcAmp_Brightness); - brightness = std::min(std::max(brightness, cr->MinValue), cr->MaxValue); - } - if (flags & ProcAmp_Contrast) { - cr = pApp->GetColorControl(ProcAmp_Contrast); - contrast = std::min(std::max(contrast, cr->MinValue), cr->MaxValue); - } - if (flags & ProcAmp_Hue) { - cr = pApp->GetColorControl(ProcAmp_Hue); - hue = std::min(std::max(hue, cr->MinValue), cr->MaxValue); - } - if (flags & ProcAmp_Saturation) { - cr = pApp->GetColorControl(ProcAmp_Saturation); - saturation = std::min(std::max(saturation, cr->MinValue), cr->MaxValue); - } - - if (m_pVMRMC) { - ClrControl.dwSize = sizeof(ClrControl); - ClrControl.dwFlags = flags; - ClrControl.Brightness = (float)brightness; - ClrControl.Contrast = (float)(contrast + 100) / 100; - ClrControl.Hue = (float)hue; - ClrControl.Saturation = (float)(saturation + 100) / 100; - - hr = m_pVMRMC->SetProcAmpControl(0, &ClrControl); - } else if (m_pMFVP) { - ClrValues.Brightness = IntToFixed(brightness); - ClrValues.Contrast = IntToFixed(contrast + 100, 100); - ClrValues.Hue = IntToFixed(hue); - ClrValues.Saturation = IntToFixed(saturation + 100, 100); - - hr = m_pMFVP->SetProcAmpValues(flags, &ClrValues); - - } - // Workaround: with Intel driver the minimum values of the supported range may not actually work - if (FAILED(hr)) { - if (flags & ProcAmp_Brightness) { - cr = pApp->GetColorControl(ProcAmp_Brightness); - if (brightness == cr->MinValue) { - brightness = cr->MinValue + 1; - } - } - if (flags & ProcAmp_Hue) { - cr = pApp->GetColorControl(ProcAmp_Hue); - if (hue == cr->MinValue) { - hue = cr->MinValue + 1; - } - } - } -} - -void CMainFrame::SetClosedCaptions(bool enable) -{ - if (m_pLN21) { - m_pLN21->SetServiceState(enable ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off); - } -} - -LPCTSTR CMainFrame::GetDVDAudioFormatName(const DVD_AudioAttributes& ATR) const -{ - switch (ATR.AudioFormat) { - case DVD_AudioFormat_AC3: - return _T("AC3"); - case DVD_AudioFormat_MPEG1: - case DVD_AudioFormat_MPEG1_DRC: - return _T("MPEG1"); - case DVD_AudioFormat_MPEG2: - case DVD_AudioFormat_MPEG2_DRC: - return _T("MPEG2"); - case DVD_AudioFormat_LPCM: - return _T("LPCM"); - case DVD_AudioFormat_DTS: - return _T("DTS"); - case DVD_AudioFormat_SDDS: - return _T("SDDS"); - case DVD_AudioFormat_Other: - default: - return MAKEINTRESOURCE(IDS_MAINFRM_137); - } -} - -afx_msg void CMainFrame::OnGotoSubtitle(UINT nID) -{ - if (!m_pSubStreams.IsEmpty() && !IsPlaybackCaptureMode()) { - m_rtCurSubPos = m_wndSeekBar.GetPos(); - m_lSubtitleShift = 0; - m_wndSubresyncBar.RefreshEmbeddedTextSubtitleData(); - m_nCurSubtitle = m_wndSubresyncBar.FindNearestSub(m_rtCurSubPos, (nID == ID_GOTO_NEXT_SUB)); - if (m_nCurSubtitle >= 0 && m_pMS) { - if (nID == ID_GOTO_PREV_SUB) { - OnPlayPause(); - } - m_pMS->SetPositions(&m_rtCurSubPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - } -} - -afx_msg void CMainFrame::OnSubresyncShiftSub(UINT nID) -{ - if (m_nCurSubtitle >= 0) { - long lShift = (nID == ID_SUBRESYNC_SHIFT_DOWN) ? -100 : 100; - CString strSubShift; - - if (m_wndSubresyncBar.ShiftSubtitle(m_nCurSubtitle, lShift, m_rtCurSubPos)) { - m_lSubtitleShift += lShift; - if (m_pMS) { - m_pMS->SetPositions(&m_rtCurSubPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - } - - strSubShift.Format(IDS_MAINFRM_138, m_lSubtitleShift); - m_OSD.DisplayMessage(OSD_TOPLEFT, strSubShift); - } -} - -afx_msg void CMainFrame::OnSubtitleDelay(UINT nID) -{ - int nDelayStep = AfxGetAppSettings().nSubDelayStep; - - if (nID == ID_SUB_DELAY_DOWN) { - nDelayStep = -nDelayStep; - } - - SetSubtitleDelay(nDelayStep, /*relative=*/ true); -} - -afx_msg void CMainFrame::OnSubtitlePos(UINT nID) -{ - if (m_pCAP) { - CAppSettings& s = AfxGetAppSettings(); - switch (nID) { - case ID_SUB_POS_DOWN: - s.m_RenderersSettings.subPicVerticalShift += 2; - break; - case ID_SUB_POS_UP: - s.m_RenderersSettings.subPicVerticalShift -= 2; - break; - } - - if (GetMediaState() != State_Running) { - m_pCAP->Paint(false); - } - } -} - -afx_msg void CMainFrame::OnSubtitleFontSize(UINT nID) -{ - if (m_pCAP && m_pCurrentSubInput.pSubStream) { - CLSID clsid; - m_pCurrentSubInput.pSubStream->GetClassID(&clsid); - if (clsid == __uuidof(CRenderedTextSubtitle)) { - CAppSettings& s = AfxGetAppSettings(); - switch (nID) { - case ID_SUB_FONT_SIZE_DEC: - s.m_RenderersSettings.fontScaleOverride -= 0.05; - break; - case ID_SUB_FONT_SIZE_INC: - s.m_RenderersSettings.fontScaleOverride += 0.05; - break; - } - - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; - - if (pRTS->m_LibassContext.IsLibassActive()) { - // not supported by libass (yet) - if (!IsFullScreenMode()) { - AfxMessageBox(_T("Adjusting subtitle text size is not possible when using libass."), MB_ICONERROR, 0); - } - } - - { - CAutoLock cAutoLock(&m_csSubLock); - pRTS->Deinit(); - } - InvalidateSubtitle(); - - if (GetMediaState() != State_Running) { - m_pCAP->Paint(false); - } - } else { - if (!IsFullScreenMode()) { - AfxMessageBox(_T("Adjusting subtitle text size is not possible for image based subtitle formats."), MB_ICONERROR, 0); - } - } - } -} - -void CMainFrame::ResetSubtitlePosAndSize(bool repaint /* = false*/) -{ - CAppSettings& s = AfxGetAppSettings(); - bool changed = (s.m_RenderersSettings.fontScaleOverride != 1.0) || (s.m_RenderersSettings.subPicVerticalShift != 0); - - s.m_RenderersSettings.fontScaleOverride = 1.0; - s.m_RenderersSettings.subPicVerticalShift = 0; - - if (changed && repaint && m_pCAP && m_pCurrentSubInput.pSubStream) { - CLSID clsid; - m_pCurrentSubInput.pSubStream->GetClassID(&clsid); - if (clsid == __uuidof(CRenderedTextSubtitle)) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; - { - CAutoLock cAutoLock(&m_csSubLock); - pRTS->Deinit(); - } - InvalidateSubtitle(); - - if (GetMediaState() != State_Running) { - m_pCAP->Paint(false); - } - } - } -} - - -void CMainFrame::ProcessAPICommand(COPYDATASTRUCT* pCDS) -{ - CAtlList fns; - REFERENCE_TIME rtPos = 0; - CString fn; - - switch (pCDS->dwData) { - case CMD_OPENFILE: - fn = CString((LPCWSTR)pCDS->lpData); - if (CanSendToYoutubeDL(fn)) { - if (ProcessYoutubeDLURL(fn, false)) { - OpenCurPlaylistItem(); - return; - } else if (IsOnYDLWhitelist(fn)) { - return; - } - } - fns.AddHead(fn); - m_wndPlaylistBar.Open(fns, false); - OpenCurPlaylistItem(); - break; - case CMD_STOP: - OnPlayStop(); - break; - case CMD_CLOSEFILE: - CloseMedia(); - break; - case CMD_PLAYPAUSE: - OnPlayPlaypause(); - break; - case CMD_PLAY: - OnApiPlay(); - break; - case CMD_PAUSE: - OnApiPause(); - break; - case CMD_ADDTOPLAYLIST: - fn = CString((LPCWSTR)pCDS->lpData); - if (CanSendToYoutubeDL(fn)) { - if (ProcessYoutubeDLURL(fn, true)) { - return; - } else if (IsOnYDLWhitelist(fn)) { - return; - } - } - fns.AddHead(fn); - m_wndPlaylistBar.Append(fns, true); - break; - case CMD_STARTPLAYLIST: - OpenCurPlaylistItem(); - break; - case CMD_CLEARPLAYLIST: - m_wndPlaylistBar.Empty(); - break; - case CMD_SETPOSITION: - rtPos = 10000 * REFERENCE_TIME(_wtof((LPCWSTR)pCDS->lpData) * 1000); //with accuracy of 1 ms - // imianz: quick and dirty trick - // Pause->SeekTo->Play (in place of SeekTo only) seems to prevents in most cases - // some strange video effects on avi files (ex. locks a while and than running fast). - if (!m_fAudioOnly && GetMediaState() == State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - SeekTo(rtPos); - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } else { - SeekTo(rtPos); - } - // show current position overridden by play command - m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 2000); - break; - case CMD_SETAUDIODELAY: - rtPos = (REFERENCE_TIME)_wtol((LPCWSTR)pCDS->lpData) * 10000; - SetAudioDelay(rtPos); - break; - case CMD_SETSUBTITLEDELAY: - SetSubtitleDelay(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_SETINDEXPLAYLIST: - //m_wndPlaylistBar.SetSelIdx(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_SETAUDIOTRACK: - SetAudioTrackIdx(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_SETSUBTITLETRACK: - SetSubtitleTrackIdx(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_GETVERSION: { - CStringW buff = AfxGetMyApp()->m_strVersion; - SendAPICommand(CMD_VERSION, buff); - break; - } - case CMD_GETSUBTITLETRACKS: - SendSubtitleTracksToApi(); - break; - case CMD_GETAUDIOTRACKS: - SendAudioTracksToApi(); - break; - case CMD_GETCURRENTAUDIOTRACK: - SendAPICommand(CMD_CURRENTAUDIOTRACK, L"%d", GetCurrentAudioTrackIdx()); - break; - case CMD_GETCURRENTSUBTITLETRACK: - SendAPICommand(CMD_CURRENTSUBTITLETRACK, L"%d", GetCurrentSubtitleTrackIdx()); - break; - case CMD_GETCURRENTPOSITION: - SendCurrentPositionToApi(); - break; - case CMD_GETNOWPLAYING: - SendNowPlayingToApi(); - break; - case CMD_JUMPOFNSECONDS: - JumpOfNSeconds(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_GETPLAYLIST: - SendPlaylistToApi(); - break; - case CMD_JUMPFORWARDMED: - OnPlaySeek(ID_PLAY_SEEKFORWARDMED); - break; - case CMD_JUMPBACKWARDMED: - OnPlaySeek(ID_PLAY_SEEKBACKWARDMED); - break; - case CMD_TOGGLEFULLSCREEN: - OnViewFullscreen(); - break; - case CMD_INCREASEVOLUME: - m_wndToolBar.m_volctrl.IncreaseVolume(); - break; - case CMD_DECREASEVOLUME: - m_wndToolBar.m_volctrl.DecreaseVolume(); - break; - case CMD_SHADER_TOGGLE : - OnShaderToggle1(); - break; - case CMD_CLOSEAPP: - PostMessage(WM_CLOSE); - break; - case CMD_SETSPEED: - SetPlayingRate(_wtof((LPCWSTR)pCDS->lpData)); - break; - case CMD_SETPANSCAN: - AfxGetAppSettings().strPnSPreset = (LPCWSTR)pCDS->lpData; - ApplyPanNScanPresetString(); - break; - case CMD_OSDSHOWMESSAGE: - ShowOSDCustomMessageApi((MPC_OSDDATA*)pCDS->lpData); - break; - } -} - -void CMainFrame::SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...) -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (s.hMasterWnd) { - COPYDATASTRUCT CDS; - - va_list args; - va_start(args, fmt); - - int nBufferLen = _vsctprintf(fmt, args) + 1; // _vsctprintf doesn't count the null terminator - TCHAR* pBuff = DEBUG_NEW TCHAR[nBufferLen]; - _vstprintf_s(pBuff, nBufferLen, fmt, args); - - CDS.cbData = (DWORD)nBufferLen * sizeof(TCHAR); - CDS.dwData = nCommand; - CDS.lpData = (LPVOID)pBuff; - - ::SendMessage(s.hMasterWnd, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&CDS); - - va_end(args); - delete [] pBuff; - } -} - -void CMainFrame::SendNowPlayingToApi(bool sendtrackinfo) -{ - if (!AfxGetAppSettings().hMasterWnd) { - return; - } - - if (GetLoadState() == MLS::LOADED) { - CString title, author, description; - CString label; - CString strDur; - - if (GetPlaybackMode() == PM_FILE) { - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_TITLE), title); - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - label = !pli.m_label.IsEmpty() ? pli.m_label : pli.m_fns.GetHead(); - REFERENCE_TIME rtDur; - m_pMS->GetDuration(&rtDur); - strDur.Format(L"%.3f", rtDur / 10000000.0); - } - } else if (GetPlaybackMode() == PM_DVD) { - DVD_DOMAIN DVDDomain; - ULONG ulNumOfChapters = 0; - DVD_PLAYBACK_LOCATION2 Location; - - // Get current DVD Domain - if (SUCCEEDED(m_pDVDI->GetCurrentDomain(&DVDDomain))) { - switch (DVDDomain) { - case DVD_DOMAIN_Stop: - title = _T("DVD - Stopped"); - break; - case DVD_DOMAIN_FirstPlay: - title = _T("DVD - FirstPlay"); - break; - case DVD_DOMAIN_VideoManagerMenu: - title = _T("DVD - RootMenu"); - break; - case DVD_DOMAIN_VideoTitleSetMenu: - title = _T("DVD - TitleMenu"); - break; - case DVD_DOMAIN_Title: - title = _T("DVD - Title"); - break; - } - - // get title information - if (DVDDomain == DVD_DOMAIN_Title) { - // get current location (title number & chapter) - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location))) { - // get number of chapters in current title - VERIFY(SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters))); - } - - // get total time of title - DVD_HMSF_TIMECODE tcDur; - ULONG ulFlags; - if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { - // calculate duration in seconds - strDur.Format(L"%d", tcDur.bHours * 60 * 60 + tcDur.bMinutes * 60 + tcDur.bSeconds); - } - - // build string - // DVD - xxxxx|currenttitle|numberofchapters|currentchapter|titleduration - author.Format(L"%lu", Location.TitleNum); - description.Format(L"%lu", ulNumOfChapters); - label.Format(L"%lu", Location.ChapterNum); - } - } - } - - title.Replace(L"|", L"\\|"); - author.Replace(L"|", L"\\|"); - description.Replace(L"|", L"\\|"); - label.Replace(L"|", L"\\|"); - - CStringW buff; - buff.Format(L"%s|%s|%s|%s|%s", title.GetString(), author.GetString(), description.GetString(), label.GetString(), strDur.GetString()); - - SendAPICommand(CMD_NOWPLAYING, L"%s", static_cast(buff)); - if (sendtrackinfo) { - SendSubtitleTracksToApi(); - SendAudioTracksToApi(); - } - } -} - -void CMainFrame::SendSubtitleTracksToApi() -{ - CStringW strSubs; - if (GetLoadState() == MLS::LOADED) { - if (GetPlaybackMode() == PM_DVD) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) - && ulStreamsAvailable > 0) { - LCID DefLanguage; - int i = 0, iSelected = -1; - - DVD_SUBPICTURE_LANG_EXT ext; - if (FAILED(m_pDVDI->GetDefaultSubpictureLanguage(&DefLanguage, &ext))) { - return; - } - - for (i = 0; i < ulStreamsAvailable; i++) { - LCID Language; - if (FAILED(m_pDVDI->GetSubpictureLanguage(i, &Language))) { - continue; - } - - if (i == ulCurrentStream) { - iSelected = i; - } - - CString str; - if (Language) { - GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); - } else { - str.Format(IDS_AG_UNKNOWN, i + 1); - } - - DVD_SubpictureAttributes ATR; - if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(i, &ATR))) { - switch (ATR.LanguageExtension) { - case DVD_SP_EXT_NotSpecified: - default: - break; - case DVD_SP_EXT_Caption_Normal: - str += _T(""); - break; - case DVD_SP_EXT_Caption_Big: - str += _T(" (Big)"); - break; - case DVD_SP_EXT_Caption_Children: - str += _T(" (Children)"); - break; - case DVD_SP_EXT_CC_Normal: - str += _T(" (CC)"); - break; - case DVD_SP_EXT_CC_Big: - str += _T(" (CC Big)"); - break; - case DVD_SP_EXT_CC_Children: - str += _T(" (CC Children)"); - break; - case DVD_SP_EXT_Forced: - str += _T(" (Forced)"); - break; - case DVD_SP_EXT_DirectorComments_Normal: - str += _T(" (Director Comments)"); - break; - case DVD_SP_EXT_DirectorComments_Big: - str += _T(" (Director Comments, Big)"); - break; - case DVD_SP_EXT_DirectorComments_Children: - str += _T(" (Director Comments, Children)"); - break; - } - } - if (!strSubs.IsEmpty()) { - strSubs.Append(L"|"); - } - str.Replace(L"|", L"\\|"); - strSubs.Append(str); - } - if (AfxGetAppSettings().fEnableSubtitles) { - strSubs.AppendFormat(L"|%d", iSelected); - } else { - strSubs.Append(L"|-1"); - } - } - } else { - - POSITION pos = m_pSubStreams.GetHeadPosition(); - int i = 0, iSelected = -1; - if (pos) { - while (pos) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - - if (CComQIPtr pSSF = subInput.pSourceFilter) { - DWORD cStreams; - if (FAILED(pSSF->Count(&cStreams))) { - continue; - } - - for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { - DWORD dwFlags, dwGroup; - WCHAR* pszName = nullptr; - - if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - CString name(pszName); - CoTaskMemFree(pszName); - - if (dwGroup != 2) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream - && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - iSelected = j; - } - - if (!strSubs.IsEmpty()) { - strSubs.Append(L"|"); - } - name.Replace(L"|", L"\\|"); - strSubs.Append(name); - - i++; - } - } else { - CComPtr pSubStream = subInput.pSubStream; - if (!pSubStream) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - iSelected = i + pSubStream->GetStream(); - } - - for (int j = 0, cnt = pSubStream->GetStreamCount(); j < cnt; j++) { - WCHAR* pName = nullptr; - if (SUCCEEDED(pSubStream->GetStreamInfo(j, &pName, nullptr))) { - CString name(pName); - CoTaskMemFree(pName); - - if (!strSubs.IsEmpty()) { - strSubs.Append(L"|"); - } - name.Replace(L"|", L"\\|"); - strSubs.Append(name); - } - i++; - } - } - - } - if (AfxGetAppSettings().fEnableSubtitles) { - strSubs.AppendFormat(L"|%d", iSelected); - } else { - strSubs.Append(L"|-1"); - } - } else { - strSubs.Append(L"-1"); - } - } - } else { - strSubs.Append(L"-2"); - } - SendAPICommand(CMD_LISTSUBTITLETRACKS, L"%s", static_cast(strSubs)); -} - -void CMainFrame::SendAudioTracksToApi() -{ - CStringW strAudios; - - if (GetLoadState() == MLS::LOADED) { - DWORD cStreams = 0; - if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { - int currentStream = -1; - for (int i = 0; i < (int)cStreams; i++) { - AM_MEDIA_TYPE* pmt = nullptr; - DWORD dwFlags = 0; - LCID lcid = 0; - DWORD dwGroup = 0; - WCHAR* pszName = nullptr; - if (FAILED(m_pAudioSwitcherSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) { - return; - } - if (dwFlags == AMSTREAMSELECTINFO_EXCLUSIVE) { - currentStream = i; - } - CString name(pszName); - if (!strAudios.IsEmpty()) { - strAudios.Append(L"|"); - } - name.Replace(L"|", L"\\|"); - strAudios.AppendFormat(L"%s", name.GetString()); - if (pmt) { - DeleteMediaType(pmt); - } - if (pszName) { - CoTaskMemFree(pszName); - } - } - strAudios.AppendFormat(L"|%d", currentStream); - - } else { - strAudios.Append(L"-1"); - } - } else { - strAudios.Append(L"-2"); - } - SendAPICommand(CMD_LISTAUDIOTRACKS, L"%s", static_cast(strAudios)); - -} - -void CMainFrame::SendPlaylistToApi() -{ - CStringW strPlaylist; - POSITION pos = m_wndPlaylistBar.m_pl.GetHeadPosition(), pos2; - - while (pos) { - CPlaylistItem& pli = m_wndPlaylistBar.m_pl.GetNext(pos); - - if (pli.m_type == CPlaylistItem::file) { - pos2 = pli.m_fns.GetHeadPosition(); - while (pos2) { - CString fn = pli.m_fns.GetNext(pos2); - if (!strPlaylist.IsEmpty()) { - strPlaylist.Append(L"|"); - } - fn.Replace(L"|", L"\\|"); - strPlaylist.AppendFormat(L"%s", fn.GetString()); - } - } - } - if (strPlaylist.IsEmpty()) { - strPlaylist.Append(L"-1"); - } else { - strPlaylist.AppendFormat(L"|%d", m_wndPlaylistBar.GetSelIdx()); - } - SendAPICommand(CMD_PLAYLIST, L"%s", static_cast(strPlaylist)); -} - -void CMainFrame::SendCurrentPositionToApi(bool fNotifySeek) -{ - if (!AfxGetAppSettings().hMasterWnd) { - return; - } - - if (GetLoadState() == MLS::LOADED) { - CStringW strPos; - - if (GetPlaybackMode() == PM_FILE) { - REFERENCE_TIME rtCur; - m_pMS->GetCurrentPosition(&rtCur); - strPos.Format(L"%.3f", rtCur / 10000000.0); - } else if (GetPlaybackMode() == PM_DVD) { - DVD_PLAYBACK_LOCATION2 Location; - // get current location while playing disc, will return 0, if at a menu - if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) { - strPos.Format(L"%d", Location.TimeCode.bHours * 60 * 60 + Location.TimeCode.bMinutes * 60 + Location.TimeCode.bSeconds); - } - } - - SendAPICommand(fNotifySeek ? CMD_NOTIFYSEEK : CMD_CURRENTPOSITION, strPos); - } -} - -void CMainFrame::ShowOSDCustomMessageApi(const MPC_OSDDATA* osdData) -{ - m_OSD.DisplayMessage((OSD_MESSAGEPOS)osdData->nMsgPos, osdData->strMsg, osdData->nDurationMS); -} - -void CMainFrame::JumpOfNSeconds(int nSeconds) -{ - if (GetLoadState() == MLS::LOADED) { - REFERENCE_TIME rtCur; - - if (GetPlaybackMode() == PM_FILE) { - m_pMS->GetCurrentPosition(&rtCur); - DVD_HMSF_TIMECODE tcCur = RT2HMSF(rtCur); - long lPosition = tcCur.bHours * 60 * 60 + tcCur.bMinutes * 60 + tcCur.bSeconds + nSeconds; - - // revert the update position to REFERENCE_TIME format - tcCur.bHours = (BYTE)(lPosition / 3600); - tcCur.bMinutes = (lPosition / 60) % 60; - tcCur.bSeconds = lPosition % 60; - rtCur = HMSF2RT(tcCur); - - // quick and dirty trick: - // pause->seekto->play seems to prevents some strange - // video effect (ex. locks for a while and than running fast) - if (!m_fAudioOnly) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - SeekTo(rtCur); - if (!m_fAudioOnly) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - // show current position overridden by play command - m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 2000); - } - } - } -} - -// TODO : to be finished ! -//void CMainFrame::AutoSelectTracks() -//{ -// LCID DefAudioLanguageLcid [2] = {MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT), MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT)}; -// int DefAudioLanguageIndex [2] = {-1, -1}; -// LCID DefSubtitleLanguageLcid [2] = {0, MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)}; -// int DefSubtitleLanguageIndex[2] = {-1, -1}; -// LCID Language = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT); -// -// if ((m_iMediaLoadState == MLS::LOADING) || (m_iMediaLoadState == MLS::LOADED)) -// { -// if (GetPlaybackMode() == PM_FILE) -// { -// CComQIPtr pSS = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); -// -// DWORD cStreams = 0; -// if (pSS && SUCCEEDED(pSS->Count(&cStreams))) -// { -// for (int i = 0; i < (int)cStreams; i++) -// { -// AM_MEDIA_TYPE* pmt = nullptr; -// DWORD dwFlags = 0; -// LCID lcid = 0; -// DWORD dwGroup = 0; -// WCHAR* pszName = nullptr; -// if (FAILED(pSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) -// return; -// } -// } -// -// POSITION pos = m_pSubStreams.GetHeadPosition(); -// while (pos) -// { -// CComPtr pSubStream = m_pSubStreams.GetNext(pos).subStream; -// if (!pSubStream) continue; -// -// for (int i = 0, j = pSubStream->GetStreamCount(); i < j; i++) -// { -// WCHAR* pName = nullptr; -// if (SUCCEEDED(pSubStream->GetStreamInfo(i, &pName, &Language))) -// { -// if (DefAudioLanguageLcid[0] == Language) DefSubtitleLanguageIndex[0] = i; -// if (DefSubtitleLanguageLcid[1] == Language) DefSubtitleLanguageIndex[1] = i; -// CoTaskMemFree(pName); -// } -// } -// } -// } -// else if (GetPlaybackMode() == PM_DVD) -// { -// ULONG ulStreamsAvailable, ulCurrentStream; -// BOOL bIsDisabled; -// -// if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) -// { -// for (ULONG i = 0; i < ulStreamsAvailable; i++) -// { -// DVD_SubpictureAttributes ATR; -// if (SUCCEEDED(m_pDVDI->GetSubpictureLanguage(i, &Language))) -// { -// // Auto select forced subtitle -// if ((DefAudioLanguageLcid[0] == Language) && (ATR.LanguageExtension == DVD_SP_EXT_Forced)) -// DefSubtitleLanguageIndex[0] = i; -// -// if (DefSubtitleLanguageLcid[1] == Language) DefSubtitleLanguageIndex[1] = i; -// } -// } -// } -// -// if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulStreamsAvailable, &ulCurrentStream))) -// { -// for (ULONG i = 0; i < ulStreamsAvailable; i++) -// { -// if (SUCCEEDED(m_pDVDI->GetAudioLanguage(i, &Language))) -// { -// if (DefAudioLanguageLcid[0] == Language) DefAudioLanguageIndex[0] = i; -// if (DefAudioLanguageLcid[1] == Language) DefAudioLanguageIndex[1] = i; -// } -// } -// } -// -// // Select best audio/subtitles tracks -// if (DefAudioLanguageLcid[0] != -1) -// { -// m_pDVDC->SelectAudioStream(DefAudioLanguageIndex[0], DVD_CMD_FLAG_Block, nullptr); -// if (DefSubtitleLanguageIndex[0] != -1) -// m_pDVDC->SelectSubpictureStream(DefSubtitleLanguageIndex[0], DVD_CMD_FLAG_Block, nullptr); -// } -// else if ((DefAudioLanguageLcid[1] != -1) && (DefSubtitleLanguageLcid[1] != -1)) -// { -// m_pDVDC->SelectAudioStream (DefAudioLanguageIndex[1], DVD_CMD_FLAG_Block, nullptr); -// m_pDVDC->SelectSubpictureStream (DefSubtitleLanguageIndex[1], DVD_CMD_FLAG_Block, nullptr); -// } -// } -// -// -// } -//} - -void CMainFrame::OnFileOpendirectory() -{ - if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar)) { - return; - } - - auto& s = AfxGetAppSettings(); - CString strTitle(StrRes(IDS_MAINFRM_DIR_TITLE)); - CString path; - - MPCFolderPickerDialog fd(ForceTrailingSlash(s.lastFileOpenDirPath), FOS_PATHMUSTEXIST, GetModalParent(), IDS_MAINFRM_DIR_CHECK); - fd.m_ofn.lpstrTitle = strTitle; - - if (fd.DoModal() == IDOK) { - path = fd.GetPathName(); //getfolderpath() does not work correctly for CFolderPickerDialog - } else { - return; - } - - BOOL recur = TRUE; - fd.GetCheckButtonState(IDS_MAINFRM_DIR_CHECK, recur); - COpenDirHelper::m_incl_subdir = !!recur; - - // If we got a link file that points to a directory, follow the link - if (PathUtils::IsLinkFile(path)) { - CString resolvedPath = PathUtils::ResolveLinkFile(path); - if (PathUtils::IsDir(resolvedPath)) { - path = resolvedPath; - } - } - - path = ForceTrailingSlash(path); - s.lastFileOpenDirPath = path; - - CAtlList sl; - sl.AddTail(path); - if (COpenDirHelper::m_incl_subdir) { - PathUtils::RecurseAddDir(path, sl); - } - - m_wndPlaylistBar.Open(sl, true); - OpenCurPlaylistItem(); -} - -HRESULT CMainFrame::CreateThumbnailToolbar() -{ - if (!this || !AfxGetAppSettings().bUseEnhancedTaskBar) { - return E_FAIL; - } - - if (m_pTaskbarList || SUCCEEDED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER))) { - bool bRTLLayout = false; // Assume left-to-right layout by default - // Try to locate the window used to display the task bar - if (CWnd* pTaskBarWnd = FindWindow(_T("TaskListThumbnailWnd"), nullptr)) { - bRTLLayout = !!(pTaskBarWnd->GetExStyle() & WS_EX_LAYOUTRTL); - } - - CMPCPngImage image; - if (!image.Load(IDF_WIN7_TOOLBAR)) { - return E_FAIL; - } - - CSize size = image.GetSize(); - - if (bRTLLayout) { // We don't want the buttons to be mirrored so we pre-mirror them - // Create memory DCs for the source and destination bitmaps - CDC sourceDC, destDC; - sourceDC.CreateCompatibleDC(nullptr); - destDC.CreateCompatibleDC(nullptr); - // Swap the source bitmap with an empty one - CBitmap sourceImg; - sourceImg.Attach(image.Detach()); - // Create a temporary DC - CClientDC clientDC(nullptr); - // Create the destination bitmap - image.CreateCompatibleBitmap(&clientDC, size.cx, size.cy); - // Select the bitmaps into the DCs - HGDIOBJ oldSourceDCObj = sourceDC.SelectObject(sourceImg); - HGDIOBJ oldDestDCObj = destDC.SelectObject(image); - // Actually flip the bitmap - destDC.StretchBlt(0, 0, size.cx, size.cy, - &sourceDC, size.cx, 0, -size.cx, size.cy, - SRCCOPY); - // Reselect the old objects back into their DCs - sourceDC.SelectObject(oldSourceDCObj); - destDC.SelectObject(oldDestDCObj); - - sourceDC.DeleteDC(); - destDC.DeleteDC(); - } - - CImageList imageList; - imageList.Create(size.cy, size.cy, ILC_COLOR32, size.cx / size.cy, 0); - imageList.Add(&image, nullptr); - - if (SUCCEEDED(m_pTaskbarList->ThumbBarSetImageList(m_hWnd, imageList.GetSafeHandle()))) { - THUMBBUTTON buttons[5] = {}; - - for (size_t i = 0; i < _countof(buttons); i++) { - buttons[i].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS; - buttons[i].dwFlags = THBF_DISABLED; - buttons[i].iBitmap = 0; // Will be set later - } - - // PREVIOUS - buttons[0].iId = IDTB_BUTTON3; - // STOP - buttons[1].iId = IDTB_BUTTON1; - // PLAY/PAUSE - buttons[2].iId = IDTB_BUTTON2; - // NEXT - buttons[3].iId = IDTB_BUTTON4; - // FULLSCREEN - buttons[4].iId = IDTB_BUTTON5; - - if (bRTLLayout) { // We don't want the buttons to be mirrored so we pre-mirror them - std::reverse(buttons, buttons + _countof(buttons)); - } - - if (SUCCEEDED(m_pTaskbarList->ThumbBarAddButtons(m_hWnd, _countof(buttons), buttons))) { - return UpdateThumbarButton(); - } - } - } - - return E_FAIL; -} - -HRESULT CMainFrame::UpdateThumbarButton() -{ - MPC_PLAYSTATE state = PS_STOP; - if (GetLoadState() == MLS::LOADED) { - switch (GetMediaState()) { - case State_Running: - state = PS_PLAY; - break; - case State_Paused: - state = PS_PAUSE; - break; - } - } - return UpdateThumbarButton(state); -} - -HRESULT CMainFrame::UpdateThumbarButton(MPC_PLAYSTATE iPlayState) -{ - if (!m_pTaskbarList) { - return E_FAIL; - } - - THUMBBUTTON buttons[5] = {}; - - for (size_t i = 0; i < _countof(buttons); i++) { - buttons[i].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS; - } - - buttons[0].iId = IDTB_BUTTON3; - buttons[1].iId = IDTB_BUTTON1; - buttons[2].iId = IDTB_BUTTON2; - buttons[3].iId = IDTB_BUTTON4; - buttons[4].iId = IDTB_BUTTON5; - - const CAppSettings& s = AfxGetAppSettings(); - - if (!s.bUseEnhancedTaskBar) { - m_pTaskbarList->SetOverlayIcon(m_hWnd, nullptr, L""); - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); - - for (size_t i = 0; i < _countof(buttons); i++) { - buttons[i].dwFlags = THBF_HIDDEN; - } - } else { - buttons[0].iBitmap = 0; - StringCchCopy(buttons[0].szTip, _countof(buttons[0].szTip), ResStr(IDS_AG_PREVIOUS)); - - buttons[1].iBitmap = 1; - StringCchCopy(buttons[1].szTip, _countof(buttons[1].szTip), ResStr(IDS_AG_STOP)); - - buttons[2].iBitmap = 3; - StringCchCopy(buttons[2].szTip, _countof(buttons[2].szTip), ResStr(IDS_AG_PLAYPAUSE)); - - buttons[3].iBitmap = 4; - StringCchCopy(buttons[3].szTip, _countof(buttons[3].szTip), ResStr(IDS_AG_NEXT)); - - buttons[4].iBitmap = 5; - StringCchCopy(buttons[4].szTip, _countof(buttons[4].szTip), ResStr(IDS_AG_FULLSCREEN)); - - if (GetLoadState() == MLS::LOADED) { - HICON hIcon = nullptr; - - buttons[0].dwFlags = (!s.fUseSearchInFolder && m_wndPlaylistBar.GetCount() <= 1 && (m_pCB && m_pCB->ChapGetCount() <= 1)) ? THBF_DISABLED : THBF_ENABLED; - buttons[3].dwFlags = (!s.fUseSearchInFolder && m_wndPlaylistBar.GetCount() <= 1 && (m_pCB && m_pCB->ChapGetCount() <= 1)) ? THBF_DISABLED : THBF_ENABLED; - buttons[4].dwFlags = THBF_ENABLED; - - if (iPlayState == PS_PLAY) { - buttons[1].dwFlags = THBF_ENABLED; - buttons[2].dwFlags = THBF_ENABLED; - buttons[2].iBitmap = 2; - - hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_PLAY), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); - m_pTaskbarList->SetProgressState(m_hWnd, m_wndSeekBar.HasDuration() ? TBPF_NORMAL : TBPF_NOPROGRESS); - } else if (iPlayState == PS_STOP) { - buttons[1].dwFlags = THBF_DISABLED; - buttons[2].dwFlags = THBF_ENABLED; - buttons[2].iBitmap = 3; - - hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_STOP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); - } else if (iPlayState == PS_PAUSE) { - buttons[1].dwFlags = THBF_ENABLED; - buttons[2].dwFlags = THBF_ENABLED; - buttons[2].iBitmap = 3; - - hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_PAUSE), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); - m_pTaskbarList->SetProgressState(m_hWnd, m_wndSeekBar.HasDuration() ? TBPF_PAUSED : TBPF_NOPROGRESS); - } - - if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { - buttons[0].dwFlags = THBF_DISABLED; - buttons[1].dwFlags = THBF_DISABLED; - buttons[2].dwFlags = THBF_DISABLED; - buttons[3].dwFlags = THBF_DISABLED; - } - - m_pTaskbarList->SetOverlayIcon(m_hWnd, hIcon, L""); - - if (hIcon != nullptr) { - DestroyIcon(hIcon); - } - } else { - for (size_t i = 0; i < _countof(buttons); i++) { - buttons[i].dwFlags = THBF_DISABLED; - } - - m_pTaskbarList->SetOverlayIcon(m_hWnd, nullptr, L""); - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); - } - - UpdateThumbnailClip(); - } - - // Try to locate the window used to display the task bar to check if it is RTLed - if (CWnd* pTaskBarWnd = FindWindow(_T("TaskListThumbnailWnd"), nullptr)) { - // We don't want the buttons to be mirrored so we pre-mirror them - if (pTaskBarWnd->GetExStyle() & WS_EX_LAYOUTRTL) { - for (UINT i = 0; i < _countof(buttons); i++) { - buttons[i].iBitmap = _countof(buttons) - buttons[i].iBitmap; - } - std::reverse(buttons, buttons + _countof(buttons)); - } - } - - return m_pTaskbarList->ThumbBarUpdateButtons(m_hWnd, _countof(buttons), buttons); -} - -HRESULT CMainFrame::UpdateThumbnailClip() -{ - if (!m_pTaskbarList || !m_hWnd || !m_wndView.m_hWnd) { - return E_FAIL; - } - - const CAppSettings& s = AfxGetAppSettings(); - - CRect r; - m_wndView.GetClientRect(&r); - if (s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) { - r.OffsetRect(0, GetSystemMetrics(SM_CYMENU)); - } - - if (!s.bUseEnhancedTaskBar || (GetLoadState() != MLS::LOADED) || IsFullScreenMode() || r.Width() <= 0 || r.Height() <= 0) { - return m_pTaskbarList->SetThumbnailClip(m_hWnd, nullptr); - } - - return m_pTaskbarList->SetThumbnailClip(m_hWnd, &r); -} - -BOOL CMainFrame::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext) -{ - if (defaultMPCThemeMenu == nullptr) { - defaultMPCThemeMenu = DEBUG_NEW CMPCThemeMenu(); - } - if (lpszMenuName != NULL) { - defaultMPCThemeMenu->LoadMenu(lpszMenuName); - - if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), defaultMPCThemeMenu->m_hMenu, (LPVOID)pContext)) { - return FALSE; - } - defaultMPCThemeMenu->fulfillThemeReqs(true); - - return TRUE; - } - return FALSE; -} - -void CMainFrame::enableFileDialogHook(CMPCThemeUtil* helper) { - if (AfxGetAppSettings().bWindows10DarkThemeActive) { //hard coded behavior for windows 10 dark theme file dialogs, irrespsective of theme loaded by user (fixing windows bugs) - watchingDialog = themableDialogTypes::windowsFileDialog; - dialogHookHelper = helper; - } -} - -void CMainFrame::enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type) { - if (AppIsThemeLoaded()) { - watchingDialog = type; - dialogHookHelper = helper; - } -} - -bool CMainFrame::isSafeZone(CPoint pt) { - CRect r; - m_wndSeekBar.GetClientRect(r); - m_wndSeekBar.MapWindowPoints(this, r); - r.InflateRect(0, m_dpi.ScaleY(16)); - if (r.top < 0) r.top = 0; - - if (r.PtInRect(pt)) { - TRACE(_T("Click was inside safezone!\n")); - return true; - } - return false; -} - -LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (!m_hWnd) { - ASSERT(false); - return 0; - } - if (message == WM_ACTIVATE || message == WM_SETFOCUS) { - if (AfxGetMyApp()->m_fClosingState) { - TRACE(_T("Dropped WindowProc: message %u value %d\n"), message, LOWORD(wParam)); - return 0; - } - } - - if ((message == WM_COMMAND) && (THBN_CLICKED == HIWORD(wParam))) { - int const wmId = LOWORD(wParam); - switch (wmId) { - case IDTB_BUTTON1: - SendMessage(WM_COMMAND, ID_PLAY_STOP); - break; - case IDTB_BUTTON2: - SendMessage(WM_COMMAND, ID_PLAY_PLAYPAUSE); - break; - case IDTB_BUTTON3: - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACK); - break; - case IDTB_BUTTON4: - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); - break; - case IDTB_BUTTON5: - WINDOWPLACEMENT wp; - GetWindowPlacement(&wp); - if (wp.showCmd == SW_SHOWMINIMIZED) { - SendMessage(WM_SYSCOMMAND, SC_RESTORE, -1); - } - SetForegroundWindow(); - SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN); - break; - default: - break; - } - return 0; - } else if (watchingDialog != themableDialogTypes::None && nullptr != dialogHookHelper && message == WM_ACTIVATE && LOWORD(wParam) == WA_INACTIVE) { - dialogHookHelper->themableDialogHandle = (HWND)lParam; - foundDialog = watchingDialog; - watchingDialog = themableDialogTypes::None; - //capture but process message normally - } else if (message == WM_GETICON && foundDialog == themableDialogTypes::windowsFileDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { - dialogHookHelper->subClassFileDialog(this); - foundDialog = themableDialogTypes::None; - } else if (message == WM_ENTERIDLE && foundDialog == themableDialogTypes::toolbarCustomizeDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { - dialogHookHelper->subClassTBCustomizeDialog(this, &m_wndToolBar); - foundDialog = themableDialogTypes::None; - } - - if (message == WM_NCLBUTTONDOWN && wParam == HTCAPTION && !m_pMVRSR) { - CPoint pt = CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - ScreenToClient(&pt); - if (isSafeZone(pt)) { - return 0; - } - } - - LRESULT ret = 0; - bool bCallOurProc = true; - if (m_pMVRSR) { - // call madVR window proc directly when the interface is available - switch (message) { - case WM_CLOSE: - break; - case WM_MOUSEMOVE: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - // CMouseWnd will call madVR window proc - break; - default: - bCallOurProc = !m_pMVRSR->ParentWindowProc(m_hWnd, message, &wParam, &lParam, &ret); - } - } - if (bCallOurProc && m_hWnd) { - ret = __super::WindowProc(message, wParam, lParam); - } - - return ret; -} - -bool CMainFrame::IsAeroSnapped() -{ - bool ret = false; - WINDOWPLACEMENT wp = { sizeof(wp) }; - if (IsWindowVisible() && !IsZoomed() && !IsIconic() && GetWindowPlacement(&wp)) { - CRect rect; - GetWindowRect(rect); - if (HMONITOR hMon = MonitorFromRect(rect, MONITOR_DEFAULTTONULL)) { - MONITORINFO mi = { sizeof(mi) }; - if (GetMonitorInfo(hMon, &mi)) { - CRect wpRect(wp.rcNormalPosition); - wpRect.OffsetRect(mi.rcWork.left - mi.rcMonitor.left, mi.rcWork.top - mi.rcMonitor.top); - ret = !!(rect != wpRect); - } else { - ASSERT(FALSE); - } - } - } - return ret; -} - -UINT CMainFrame::OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData) -{ - static BOOL bWasPausedBeforeSuspention; - - switch (nPowerEvent) { - case PBT_APMSUSPEND: // System is suspending operation. - TRACE(_T("OnPowerBroadcast - suspending\n")); // For user tracking - bWasPausedBeforeSuspention = FALSE; // Reset value - - if (GetMediaState() == State_Running) { - bWasPausedBeforeSuspention = TRUE; - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); // Pause - } - break; - case PBT_APMRESUMESUSPEND: // System is resuming operation - TRACE(_T("OnPowerBroadcast - resuming\n")); // For user tracking - - // force seek to current position when resuming playback to re-initialize the video decoder - m_dwLastPause = 1; - - // Resume if we paused before suspension. - if (bWasPausedBeforeSuspention) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); // Resume - } - break; - } - - return __super::OnPowerBroadcast(nPowerEvent, nEventData); -} - -#define NOTIFY_FOR_THIS_SESSION 0 - -void CMainFrame::OnSessionChange(UINT nSessionState, UINT nId) -{ - if (AfxGetAppSettings().bLockNoPause) { - return; - } - - static BOOL bWasPausedBeforeSessionChange; - - switch (nSessionState) { - case WTS_SESSION_LOCK: - TRACE(_T("OnSessionChange - Lock session\n")); - bWasPausedBeforeSessionChange = FALSE; - - if (GetMediaState() == State_Running && !m_fAudioOnly) { - bWasPausedBeforeSessionChange = TRUE; - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - break; - case WTS_SESSION_UNLOCK: - TRACE(_T("OnSessionChange - UnLock session\n")); - - if (bWasPausedBeforeSessionChange) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - break; - } -} - -void CMainFrame::WTSRegisterSessionNotification() -{ - const WinapiFunc - fnWtsRegisterSessionNotification = { _T("wtsapi32.dll"), "WTSRegisterSessionNotification" }; - - if (fnWtsRegisterSessionNotification) { - fnWtsRegisterSessionNotification(m_hWnd, NOTIFY_FOR_THIS_SESSION); - } -} - -void CMainFrame::WTSUnRegisterSessionNotification() -{ - const WinapiFunc - fnWtsUnRegisterSessionNotification = { _T("wtsapi32.dll"), "WTSUnRegisterSessionNotification" }; - - if (fnWtsUnRegisterSessionNotification) { - fnWtsUnRegisterSessionNotification(m_hWnd); - } -} - -void CMainFrame::UpdateSkypeHandler() -{ - const auto& s = AfxGetAppSettings(); - if (s.bNotifySkype && !m_pSkypeMoodMsgHandler) { - m_pSkypeMoodMsgHandler.Attach(DEBUG_NEW SkypeMoodMsgHandler()); - m_pSkypeMoodMsgHandler->Connect(m_hWnd); - } else if (!s.bNotifySkype && m_pSkypeMoodMsgHandler) { - m_pSkypeMoodMsgHandler.Free(); - } -} - -void CMainFrame::UpdateSeekbarChapterBag() -{ - const auto& s = AfxGetAppSettings(); - if (s.fShowChapters && m_pCB && m_pCB->ChapGetCount() > 0) { - m_wndSeekBar.SetChapterBag(m_pCB); - m_OSD.SetChapterBag(m_pCB); - } else { - m_wndSeekBar.RemoveChapters(); - m_OSD.RemoveChapters(); - } -} - -void CMainFrame::UpdateAudioSwitcher() -{ - CAppSettings& s = AfxGetAppSettings(); - CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); - - if (pASF) { - pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); - pASF->EnableDownSamplingTo441(s.fDownSampleTo441); - pASF->SetAudioTimeShift(s.fAudioTimeShift ? 10000i64 * s.iAudioTimeShift : 0); - pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); - } -} - -void CMainFrame::LoadArtToViews(const CString& imagePath) -{ - m_wndView.LoadImg(imagePath); - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->LoadImg(imagePath); - } -} - -void CMainFrame::LoadArtToViews(std::vector buffer) -{ - m_wndView.LoadImg(buffer); - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->LoadImg(buffer); - } -} - -void CMainFrame::ClearArtFromViews() -{ - m_wndView.LoadImg(); - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->LoadImg(); - } -} - -void CMainFrame::UpdateControlState(UpdateControlTarget target) -{ - const auto& s = AfxGetAppSettings(); - switch (target) { - case UPDATE_VOLUME_STEP: - m_wndToolBar.m_volctrl.SetPageSize(s.nVolumeStep); - break; - case UPDATE_LOGO: - if (GetLoadState() == MLS::LOADED && m_fAudioOnly && s.bEnableCoverArt) { - CString filename = m_wndPlaylistBar.GetCurFileName(); - CString filename_no_ext; - CString filedir; - if (!PathUtils::IsURL(filename)) { - CPath path = CPath(filename); - if (path.FileExists()) { - path.RemoveExtension(); - filename_no_ext = path.m_strPath; - path.RemoveFileSpec(); - filedir = path.m_strPath; - } - } - - CString author; - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); - - CComQIPtr pFilterGraph = m_pGB; - std::vector internalCover; - if (CoverArt::FindEmbedded(pFilterGraph, internalCover)) { - LoadArtToViews(internalCover); - m_currentCoverPath = filename; - m_currentCoverAuthor = author; - } else { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli) && !pli.m_cover.IsEmpty() && CPath(pli.m_cover).FileExists()) { - LoadArtToViews(pli.m_cover); - } else if (!filedir.IsEmpty() && (m_currentCoverPath != filedir || m_currentCoverAuthor != author || currentCoverIsFileArt)) { - CString img = CoverArt::FindExternal(filename_no_ext, filedir, author, currentCoverIsFileArt); - LoadArtToViews(img); - m_currentCoverPath = filedir; - m_currentCoverAuthor = author; - } else if (!m_wndView.IsCustomImgLoaded()) { - ClearArtFromViews(); - } - } - } else { - m_currentCoverPath.Empty(); - m_currentCoverAuthor.Empty(); - ClearArtFromViews(); - } - break; - case UPDATE_SKYPE: - UpdateSkypeHandler(); - break; - case UPDATE_SEEKBAR_CHAPTERS: - UpdateSeekbarChapterBag(); - break; - case UPDATE_WINDOW_TITLE: - OpenSetupWindowTitle(); - break; - case UPDATE_AUDIO_SWITCHER: - UpdateAudioSwitcher(); - break; - case UPDATE_CONTROLS_VISIBILITY: - m_controls.UpdateToolbarsVisibility(); - break; - case UPDATE_CHILDVIEW_CURSOR_HACK: - // HACK: windowed (not renderless) video renderers created in graph thread do not - // produce WM_MOUSEMOVE message when we release mouse capture on top of it, here's a workaround - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::CHILDVIEW_CURSOR_HACK, std::bind(&CChildView::Invalidate, &m_wndView, FALSE), 16); - break; - default: - ASSERT(FALSE); - } -} - -void CMainFrame::ReloadMenus() { - // CMenu defaultMenu; - CMenu* oldMenu; - - // Destroy the dynamic menus before reloading the main menus - DestroyDynamicMenus(); - - // Reload the main menus - m_popupMenu.DestroyMenu(); - m_popupMenu.LoadMenu(IDR_POPUP); - m_mainPopupMenu.DestroyMenu(); - m_mainPopupMenu.LoadMenu(IDR_POPUPMAIN); - - oldMenu = GetMenu(); - defaultMPCThemeMenu = DEBUG_NEW CMPCThemeMenu(); //will have been destroyed - defaultMPCThemeMenu->LoadMenu(IDR_MAINFRAME); - if (oldMenu) { - // Attach the new menu to the window only if there was a menu before - SetMenu(defaultMPCThemeMenu); - // and then destroy the old one - oldMenu->DestroyMenu(); - delete oldMenu; - } - //we don't detach because we retain the cmenu - //m_hMenuDefault = defaultMenu.Detach(); - m_hMenuDefault = defaultMPCThemeMenu->GetSafeHmenu(); - - m_popupMenu.fulfillThemeReqs(); - m_mainPopupMenu.fulfillThemeReqs(); - defaultMPCThemeMenu->fulfillThemeReqs(true); - - // Reload the dynamic menus - CreateDynamicMenus(); -} - - -void CMainFrame::UpdateUILanguage() -{ - ReloadMenus(); - - // Reload the static bars - OpenSetupInfoBar(); - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - UpdateCurrentChannelInfo(false, false); - } - OpenSetupStatsBar(); - - // Reload the debug shaders dialog if need be - if (m_pDebugShaders && IsWindow(m_pDebugShaders->m_hWnd)) { - BOOL bWasVisible = m_pDebugShaders->IsWindowVisible(); - VERIFY(m_pDebugShaders->DestroyWindow()); - m_pDebugShaders = std::make_unique(); - if (bWasVisible) { - m_pDebugShaders->ShowWindow(SW_SHOWNA); - // Don't steal focus from main frame - SetActiveWindow(); - } - } -} - -bool CMainFrame::OpenBD(CString Path) -{ - CHdmvClipInfo ClipInfo; - CString strPlaylistFile; - CHdmvClipInfo::HdmvPlaylist MainPlaylist; - -#if INTERNAL_SOURCEFILTER_MPEG - const CAppSettings& s = AfxGetAppSettings(); - bool InternalMpegSplitter = s.SrcFilters[SRC_MPEG] || s.SrcFilters[SRC_MPEGTS]; -#else - bool InternalMpegSplitter = false; -#endif - - m_LastOpenBDPath = Path; - - CString ext = CPath(Path).GetExtension(); - ext.MakeLower(); - - if ((CPath(Path).IsDirectory() && Path.Find(_T("\\BDMV"))) - || CPath(Path + _T("\\BDMV")).IsDirectory() - || (!ext.IsEmpty() && ext == _T(".bdmv"))) { - if (!ext.IsEmpty() && ext == _T(".bdmv")) { - Path.Replace(_T("\\BDMV\\"), _T("\\")); - CPath _Path(Path); - _Path.RemoveFileSpec(); - Path = CString(_Path); - } else if (Path.Find(_T("\\BDMV"))) { - Path.Replace(_T("\\BDMV"), _T("\\")); - } - if (SUCCEEDED(ClipInfo.FindMainMovie(Path, strPlaylistFile, MainPlaylist, m_MPLSPlaylist))) { - m_bIsBDPlay = true; - - m_bHasBDMeta = ClipInfo.ReadMeta(Path, m_BDMeta); - - if (!InternalMpegSplitter && !ext.IsEmpty() && ext == _T(".bdmv")) { - return false; - } else { - m_wndPlaylistBar.Empty(); - CAtlList sl; - - if (InternalMpegSplitter) { - sl.AddTail(CString(strPlaylistFile)); - } else { - sl.AddTail(CString(Path + _T("\\BDMV\\index.bdmv"))); - } - - m_wndPlaylistBar.Append(sl, false); - OpenCurPlaylistItem(); - return true; - } - } - } - - m_LastOpenBDPath = _T(""); - return false; -} - -// Returns the the corresponding subInput or nullptr in case of error. -// i is modified to reflect the locale index of track -SubtitleInput* CMainFrame::GetSubtitleInput(int& i, bool bIsOffset /*= false*/) -{ - // Only 1, 0 and -1 are supported offsets - if ((bIsOffset && (i < -1 || i > 1)) || (!bIsOffset && i < 0)) { - return nullptr; - } - - POSITION pos = m_pSubStreams.GetHeadPosition(); - SubtitleInput* pSubInput = nullptr, *pSubInputPrec = nullptr; - int iLocalIdx = -1, iLocalIdxPrec = -1; - bool bNextTrack = false; - - while (pos && !pSubInput) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - - if (CComQIPtr pSSF = subInput.pSourceFilter) { - DWORD cStreams; - if (FAILED(pSSF->Count(&cStreams))) { - continue; - } - - for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { - DWORD dwFlags, dwGroup; - - if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { - continue; - } - - if (dwGroup != 2) { - continue; - } - - if (bIsOffset) { - if (bNextTrack) { // We detected previously that the next subtitles track is the one we want to select - pSubInput = &subInput; - iLocalIdx = j; - break; - } else if (subInput.pSubStream == m_pCurrentSubInput.pSubStream - && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - if (i == 0) { - pSubInput = &subInput; - iLocalIdx = j; - break; - } else if (i > 0) { - bNextTrack = true; // We want to the select the next subtitles track - } else { - // We want the previous subtitles track and we know which one it is - if (pSubInputPrec) { - pSubInput = pSubInputPrec; - iLocalIdx = iLocalIdxPrec; - break; - } - } - } - - pSubInputPrec = &subInput; - iLocalIdxPrec = j; - } else { - if (i == 0) { - pSubInput = &subInput; - iLocalIdx = j; - break; - } - - i--; - } - } - } else { - if (bIsOffset) { - if (bNextTrack) { // We detected previously that the next subtitles track is the one we want to select - pSubInput = &subInput; - iLocalIdx = 0; - break; - } else if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - iLocalIdx = subInput.pSubStream->GetStream() + i; - if (iLocalIdx >= 0 && iLocalIdx < subInput.pSubStream->GetStreamCount()) { - // The subtitles track we want to select is part of this substream - pSubInput = &subInput; - } else if (i > 0) { // We want to the select the next subtitles track - bNextTrack = true; - } else { - // We want the previous subtitles track and we know which one it is - if (pSubInputPrec) { - pSubInput = pSubInputPrec; - iLocalIdx = iLocalIdxPrec; - } - } - } else { - pSubInputPrec = &subInput; - iLocalIdxPrec = subInput.pSubStream->GetStreamCount() - 1; - } - } else { - if (i < subInput.pSubStream->GetStreamCount()) { - pSubInput = &subInput; - iLocalIdx = i; - } else { - i -= subInput.pSubStream->GetStreamCount(); - } - } - } - - // Handle special cases - if (!pos && !pSubInput && bIsOffset) { - if (bNextTrack) { // The last subtitles track was selected and we want the next one - // Let's restart the loop to select the first subtitles track - pos = m_pSubStreams.GetHeadPosition(); - } else if (i < 0) { // The first subtitles track was selected and we want the previous one - pSubInput = pSubInputPrec; // We select the last track - iLocalIdx = iLocalIdxPrec; - } - } - } - - i = iLocalIdx; - - return pSubInput; -} - -CString CMainFrame::GetFileName() -{ - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - CString path(m_wndPlaylistBar.GetCurFileName(true)); - if (!pli.m_bYoutubeDL && m_pFSF) { - CComHeapPtr pFN; - if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, nullptr))) { - path = pFN; - } - } - if (PathUtils::IsURL(path)) { - path = ShortenURL(path); - } - return pli.m_bYoutubeDL ? path : PathUtils::StripPathOrUrl(path); - } - return _T(""); -} - -CString CMainFrame::GetCaptureTitle() -{ - CString title; - - title.LoadString(IDS_CAPTURE_LIVE); - if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - CString devName = GetFriendlyName(m_VidDispName); - if (!devName.IsEmpty()) { - title.AppendFormat(_T(" | %s"), devName.GetString()); - } - } else { - CString& eventName = m_pDVBState->NowNext.eventName; - if (m_pDVBState->bActive) { - title.AppendFormat(_T(" | %s"), m_pDVBState->sChannelName.GetString()); - if (!eventName.IsEmpty()) { - title.AppendFormat(_T(" - %s"), eventName.GetString()); - } - } else { - title += _T(" | DVB"); - } - } - return title; -} - -GUID CMainFrame::GetTimeFormat() -{ - GUID ret; - if (!m_pMS || !SUCCEEDED(m_pMS->GetTimeFormat(&ret))) { - ASSERT(FALSE); - ret = TIME_FORMAT_NONE; - } - return ret; -} - -void CMainFrame::UpdateDXVAStatus() -{ - CString DXVAInfo; - // We only support getting info from LAV Video Decoder is that is what will be used 99% of the time - if (CComQIPtr pLAVVideoStatus = FindFilter(GUID_LAVVideo, m_pGB)) { - const LPCWSTR decoderName = pLAVVideoStatus->GetActiveDecoderName(); - if (decoderName == nullptr || wcscmp(decoderName, L"avcodec") == 0 || wcscmp(decoderName, L"wmv9 mft") == 0 || wcscmp(decoderName, L"msdk mvc") == 0) { - DXVAInfo = _T("H/W Decoder : None"); - } else { - m_bUsingDXVA = true; - m_HWAccelType = CFGFilterLAVVideo::GetUserFriendlyDecoderName(decoderName); - DXVAInfo.Format(_T("H/W Decoder : %s"), m_HWAccelType); - } - } else { - DXVAInfo = _T("H/W Decoder : None / Unknown"); - } - GetRenderersData()->m_strDXVAInfo = DXVAInfo; -} - -bool CMainFrame::GetDecoderType(CString& type) const -{ - if (!m_fAudioOnly) { - if (m_bUsingDXVA) { - type = m_HWAccelType; - } else { - type.LoadString(IDS_TOOLTIP_SOFTWARE_DECODING); - } - return true; - } - return false; -} - -void CMainFrame::UpdateSubtitleRenderingParameters() -{ - if (!m_pCAP) { - return; - } - - const CAppSettings& s = AfxGetAppSettings(); - if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { - bool bChangeStorageRes = false; - bool bChangePARComp = false; - double dPARCompensation = 1.0; - bool bKeepAspectRatio = s.fKeepAspectRatio; - - CSize szAspectRatio = m_pCAP->GetVideoSize(true); - CSize szVideoFrame; - if (m_pMVRI) { - // Use IMadVRInfo to get size. See http://bugs.madshi.net/view.php?id=180 - m_pMVRI->GetSize("originalVideoSize", &szVideoFrame); - bKeepAspectRatio = true; - } else { - szVideoFrame = m_pCAP->GetVideoSize(false); - } - - if (s.bSubtitleARCompensation && szAspectRatio.cx && szAspectRatio.cy && szVideoFrame.cx && szVideoFrame.cy && bKeepAspectRatio) { - if (pRTS->m_layoutRes.cx > 0) { - dPARCompensation = (double)szAspectRatio.cx * pRTS->m_layoutRes.cy / (szAspectRatio.cy * pRTS->m_layoutRes.cx); - } else { - dPARCompensation = (double)szAspectRatio.cx * szVideoFrame.cy / (szAspectRatio.cy * szVideoFrame.cx); - } - } - if (pRTS->m_dPARCompensation != dPARCompensation) { - bChangePARComp = true; - } - - if (pRTS->m_subtitleType == Subtitle::ASS || pRTS->m_subtitleType == Subtitle::SSA) { - if (szVideoFrame.cx > 0) { - if (pRTS->m_layoutRes.cx == 0 || pRTS->m_layoutRes.cy == 0) { - bChangeStorageRes = (pRTS->m_storageRes != szVideoFrame); - } else { - bChangeStorageRes = (pRTS->m_storageRes != pRTS->m_layoutRes); - } - } - } - - { - CAutoLock cAutoLock(&m_csSubLock); - if (bChangeStorageRes) { - if (pRTS->m_layoutRes.cx == 0 || pRTS->m_layoutRes.cy == 0) { - pRTS->m_storageRes = szVideoFrame; - } else { - pRTS->m_storageRes = pRTS->m_layoutRes; - } - } - if (bChangePARComp) { - pRTS->m_ePARCompensationType = CSimpleTextSubtitle::EPARCompensationType::EPCTAccurateSize_ISR; - pRTS->m_dPARCompensation = dPARCompensation; - } - - STSStyle style = s.subtitlesDefStyle; - if (pRTS->m_bUsingPlayerDefaultStyle) { - pRTS->SetDefaultStyle(style); - } else if (pRTS->GetDefaultStyle(style) && style.relativeTo == STSStyle::AUTO && s.subtitlesDefStyle.relativeTo != STSStyle::AUTO) { - style.relativeTo = s.subtitlesDefStyle.relativeTo; - pRTS->SetDefaultStyle(style); - } - pRTS->SetOverride(s.bSubtitleOverrideDefaultStyle, s.bSubtitleOverrideAllStyles, s.subtitlesDefStyle); - pRTS->SetAlignment(s.fOverridePlacement, s.nHorPos, s.nVerPos); - pRTS->SetUseFreeType(s.bUseFreeType); - pRTS->SetOpenTypeLangHint(s.strOpenTypeLangHint); - pRTS->Deinit(); - } - m_pCAP->Invalidate(); - } else if (auto pVSS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { - { - CAutoLock cAutoLock(&m_csSubLock); - pVSS->SetAlignment(s.fOverridePlacement, s.nHorPos, s.nVerPos); - } - m_pCAP->Invalidate(); - } -} - -REFTIME CMainFrame::GetAvgTimePerFrame() const -{ - REFTIME refAvgTimePerFrame = 0.0; - - if (FAILED(m_pBV->get_AvgTimePerFrame(&refAvgTimePerFrame))) { - if (m_pCAP) { - refAvgTimePerFrame = 1.0 / m_pCAP->GetFPS(); - } - - BeginEnumFilters(m_pGB, pEF, pBF) { - if (refAvgTimePerFrame > 0.0) { - break; - } - - BeginEnumPins(pBF, pEP, pPin) { - AM_MEDIA_TYPE mt; - if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (mt.majortype == MEDIATYPE_Video && mt.formattype == FORMAT_VideoInfo) { - refAvgTimePerFrame = (REFTIME)((VIDEOINFOHEADER*)mt.pbFormat)->AvgTimePerFrame / 10000000i64; - break; - } else if (mt.majortype == MEDIATYPE_Video && mt.formattype == FORMAT_VideoInfo2) { - refAvgTimePerFrame = (REFTIME)((VIDEOINFOHEADER2*)mt.pbFormat)->AvgTimePerFrame / 10000000i64; - break; - } - } - } - EndEnumPins; - } - EndEnumFilters; - } - - // Double-check that the detection is correct for DVDs - DVD_VideoAttributes VATR; - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { - double ratio; - if (VATR.ulFrameRate == 50) { - ratio = 25.0 * refAvgTimePerFrame; - // Accept 25 or 50 fps - if (!IsNearlyEqual(ratio, 1.0, 1e-2) && !IsNearlyEqual(ratio, 2.0, 1e-2)) { - refAvgTimePerFrame = 1.0 / 25.0; - } - } else { - ratio = 29.97 * refAvgTimePerFrame; - // Accept 29,97, 59.94, 23.976 or 47.952 fps - if (!IsNearlyEqual(ratio, 1.0, 1e-2) && !IsNearlyEqual(ratio, 2.0, 1e-2) - && !IsNearlyEqual(ratio, 1.25, 1e-2) && !IsNearlyEqual(ratio, 2.5, 1e-2)) { - refAvgTimePerFrame = 1.0 / 29.97; - } - } - } - - return refAvgTimePerFrame; -} - -void CMainFrame::OnVideoSizeChanged(const bool bWasAudioOnly /*= false*/) -{ - const auto& s = AfxGetAppSettings(); - if (GetLoadState() == MLS::LOADED && - ((s.fRememberZoomLevel && (s.fLimitWindowProportions || m_bAllowWindowZoom)) || m_fAudioOnly || bWasAudioOnly) && - !(IsFullScreenMode() || IsZoomed() || IsIconic() || IsAeroSnapped())) { - CSize videoSize; - if (!m_fAudioOnly && !m_bAllowWindowZoom) { - videoSize = GetVideoSize(); - } - if (videoSize.cx && videoSize.cy) { - ZoomVideoWindow(m_dLastVideoScaleFactor * std::sqrt((static_cast(m_lastVideoSize.cx) * m_lastVideoSize.cy) - / (static_cast(videoSize.cx) * videoSize.cy))); - } else { - ZoomVideoWindow(); - } - } - MoveVideoWindow(); -} - -typedef struct { - SubtitlesInfo* pSubtitlesInfo; - BOOL bActivate; - std::string fileName; - std::string fileContents; -} SubtitlesData; - -LRESULT CMainFrame::OnLoadSubtitles(WPARAM wParam, LPARAM lParam) -{ - SubtitlesData& data = *(SubtitlesData*)lParam; - - CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); - if (pRTS) { - if (pRTS->Open(CString(data.pSubtitlesInfo->Provider()->DisplayName().c_str()), - (BYTE*)(LPCSTR)data.fileContents.c_str(), (int)data.fileContents.length(), DEFAULT_CHARSET, - UTF8To16(data.fileName.c_str()), Subtitle::HearingImpairedType(data.pSubtitlesInfo->hearingImpaired), - ISOLang::ISO6391ToLcid(data.pSubtitlesInfo->languageCode.c_str())) && pRTS->GetStreamCount() > 0) { - m_wndSubtitlesDownloadDialog.DoDownloaded(*data.pSubtitlesInfo); -#if USE_LIBASS - if (pRTS->m_LibassContext.IsLibassActive()) { - pRTS->m_LibassContext.SetFilterGraph(m_pGB); - } -#endif - SubtitleInput subElement = pRTS.Detach(); - m_pSubStreams.AddTail(subElement); - if (data.bActivate) { - m_ExternalSubstreams.push_back(subElement.pSubStream); - SetSubtitle(subElement.pSubStream); - - auto& s = AfxGetAppSettings(); - if (s.fKeepHistory && s.bRememberTrackSelection && s.bAutoSaveDownloadedSubtitles) { - s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); - } - } - return TRUE; - } - } - - return FALSE; -} - -LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) -{ - CheckPointer(lParam, FALSE); - - int n = 0; - SubtitleInput* pSubInput = GetSubtitleInput(n, true); - CheckPointer(pSubInput, FALSE); - - CLSID clsid; - if (FAILED(pSubInput->pSubStream->GetClassID(&clsid)) || clsid != __uuidof(CRenderedTextSubtitle)) { - return FALSE; - } - - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; - // Only for external text subtitles - if (pRTS->m_path.IsEmpty()) { - return FALSE; - } - - SubtitlesInfo* pSubtitlesInfo = reinterpret_cast(lParam); - - pSubtitlesInfo->GetFileInfo(); - pSubtitlesInfo->releaseNames.emplace_back(UTF16To8(pRTS->m_name)); - if (pSubtitlesInfo->hearingImpaired == Subtitle::HI_UNKNOWN) { - pSubtitlesInfo->hearingImpaired = pRTS->m_eHearingImpaired; - } - - if (!pSubtitlesInfo->languageCode.length() && pRTS->m_lcid && pRTS->m_lcid != LCID(-1)) { - CString str; - GetLocaleString(pRTS->m_lcid, LOCALE_SISO639LANGNAME, str); - pSubtitlesInfo->languageCode = UTF16To8(str); - } - - pSubtitlesInfo->frameRate = m_pCAP->GetFPS(); - int delay = m_pCAP->GetSubtitleDelay(); - if (pRTS->m_mode == FRAME) { - delay = std::lround(delay * pSubtitlesInfo->frameRate / 1000.0); - } - - const CStringW fmt(L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n"); - CStringW content; - CAutoLock cAutoLock(&m_csSubLock); - for (int i = 0, j = int(pRTS->GetCount()), k = 0; i < j; i++) { - int t1 = (int)(RT2MS(pRTS->TranslateStart(i, pSubtitlesInfo->frameRate)) + delay); - if (t1 < 0) { - k++; - continue; - } - - int t2 = (int)(RT2MS(pRTS->TranslateEnd(i, pSubtitlesInfo->frameRate)) + delay); - - int hh1 = (t1 / 60 / 60 / 1000); - int mm1 = (t1 / 60 / 1000) % 60; - int ss1 = (t1 / 1000) % 60; - int ms1 = (t1) % 1000; - int hh2 = (t2 / 60 / 60 / 1000); - int mm2 = (t2 / 60 / 1000) % 60; - int ss2 = (t2 / 1000) % 60; - int ms2 = (t2) % 1000; - - content.AppendFormat(fmt, i - k + 1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, pRTS->GetStrW(i, false).GetString()); - } - - pSubtitlesInfo->fileContents = UTF16To8(content); - return TRUE; -} - -static const CString ydl_whitelist[] = { - _T("youtube.com/"), - _T("youtu.be/"), - _T("twitch.tv/"), - _T("twitch.com/") -}; - -static const CString ydl_blacklist[] = { - _T("googlevideo.com/videoplayback"), // already processed URL - _T("googlevideo.com/api/manifest"), - _T("@127.0.0.1:"), // local URL - _T("saunalahti.fi/") -}; - -bool CMainFrame::IsOnYDLWhitelist(CString url) { - for (int i = 0; i < _countof(ydl_whitelist); i++) { - if (url.Find(ydl_whitelist[i]) >= 0) { - return true; - } - } - return false; -} - -bool CMainFrame::CanSendToYoutubeDL(const CString url) -{ - if (url.Left(4).MakeLower() == _T("http") && AfxGetAppSettings().bUseYDL) { - // Blacklist: don't use for IP addresses - std::wcmatch regmatch; - std::wregex regexp(LR"(https?:\/\/(\d{1,3}\.){3}\d{1,3}.*)"); - if (std::regex_match(url.GetString(), regmatch, regexp)) { - return false; - } - - // Whitelist: popular supported sites - if (IsOnYDLWhitelist(url)) { - return true; - } - - // Blacklist: unsupported sites where YDL causes an error or long delay - for (int i = 0; i < _countof(ydl_blacklist); i++) { - if (url.Find(ydl_blacklist[i], 7) > 0) { - return false; - } - } - - // Blacklist: URL points to a file - CString baseurl; - int q = url.Find(_T('?')); - if (q > 0) { - baseurl = url.Left(q); - } else { - baseurl = url; - q = url.GetLength(); - } - int p = baseurl.ReverseFind(_T('.')); - if (p > 0 && (q - p <= 6)) { - CString ext = baseurl.Mid(p); - if (AfxGetAppSettings().m_Formats.FindExt(ext)) { - return false; - } - } - - return true; - } - return false; -} - -bool CMainFrame::ProcessYoutubeDLURL(CString url, bool append, bool replace) -{ - auto& s = AfxGetAppSettings(); - CAtlList streams; - CAtlList filenames; - CYoutubeDLInstance ydl; - CYoutubeDLInstance::YDLPlaylistInfo listinfo; - CString useragent; - - m_sydlLastProcessURL = url; - - m_wndStatusBar.SetStatusMessage(ResStr(IDS_CONTROLS_YOUTUBEDL)); - - if (!ydl.Run(url)) { - return false; - } - if (!ydl.GetHttpStreams(streams, listinfo, useragent)) { - return false; - } - - if (!append && !replace) { - m_wndPlaylistBar.Empty(); - } - - CString f_title; - - for (unsigned int i = 0; i < streams.GetCount(); i++) { - auto stream = streams.GetAt(streams.FindIndex(i)); - CString v_url = stream.video_url; - CString a_url = stream.audio_url; - filenames.RemoveAll(); - if (!v_url.IsEmpty() && (!s.bYDLAudioOnly || a_url.IsEmpty())) { - filenames.AddTail(v_url); - - } - if (!a_url.IsEmpty()) { - filenames.AddTail(a_url); - } - CString title = stream.title; - CString seasonid; - if (stream.season_number != -1) { - seasonid.Format(_T("S%02d"), stream.season_number); - } - CString episodeid; - if (stream.episode_number != -1) { - episodeid.Format(_T("E%02d"), stream.episode_number); - } - CString epiid; - if (!seasonid.IsEmpty() || !episodeid.IsEmpty()) { - epiid.Format(_T("%s%s. "), static_cast(seasonid), static_cast(episodeid)); - } - CString season; - if (!stream.series.IsEmpty()) { - season = stream.series; - CString t(stream.season.Left(6)); - if (!stream.season.IsEmpty() && (t.MakeLower() != _T("season") || stream.season_number == -1)) { - season += _T(" ") + stream.season; - } - season += _T(" - "); - } - else if (!stream.season.IsEmpty()) { - CString t(stream.season.Left(6)); - if (t.MakeLower() != _T("season") || stream.season_number == -1) { - season = stream.season + _T(" - "); - } - } - title.Format(_T("%s%s%s"), static_cast(epiid), static_cast(season), static_cast(title)); - if (i == 0) f_title = title; - - CString ydl_src = stream.webpage_url.IsEmpty() ? url : stream.webpage_url; - if (i == 0) m_sydlLastProcessURL = ydl_src; - - int targetlen = title.GetLength() > 100 ? 50 : 150 - title.GetLength(); - CString short_url = ShortenURL(ydl_src, targetlen, true); - - if (ydl_src == filenames.GetHead()) { - // Processed URL is same as input, can happen for DASH manifest files. Clear source URL to avoid reprocessing. - ydl_src = _T(""); - } - - if (replace) { - m_wndPlaylistBar.ReplaceCurrentItem(filenames, nullptr, title + " (" + short_url + ")", ydl_src, useragent, _T(""), &stream.subtitles); - break; - } else { - m_wndPlaylistBar.Append(filenames, false, nullptr, title + " (" + short_url + ")", ydl_src, useragent, _T(""), &stream.subtitles); - } - } - - if (s.fKeepHistory) { - auto* mru = &s.MRU; - RecentFileEntry r; - mru->LoadMediaHistoryEntryFN(m_sydlLastProcessURL, r); - if (streams.GetCount() > 1) { - auto h = streams.GetHead(); - if (!h.series.IsEmpty()) { - r.title = h.series; - if (!h.season.IsEmpty()) { - r.title += _T(" - ") + h.season; - } - } - else if (!h.season.IsEmpty()) { - r.title = h.season; - } - else if (!listinfo.title.IsEmpty()) { - if (!listinfo.uploader.IsEmpty()) r.title.Format(_T("%s - %s"), static_cast(listinfo.uploader), static_cast(listinfo.title)); - else r.title = listinfo.title; - } - else r.title = f_title; - } - else if (streams.GetCount() == 1) { - r.title = f_title; - } - mru->Add(r, false); - } - - if (!append && (!replace || m_wndPlaylistBar.GetCount() == 0)) { - m_wndPlaylistBar.SetFirst(); - } - return true; -} - -bool CMainFrame::DownloadWithYoutubeDL(CString url, CString filename) -{ - PROCESS_INFORMATION proc_info; - STARTUPINFO startup_info; - const auto& s = AfxGetAppSettings(); - - bool ytdlp = true; - CString args = _T("\"") + GetYDLExePath(&ytdlp) + _T("\" --console-title \"") + url + _T("\""); - if (!s.sYDLCommandLine.IsEmpty()) { - args.Append(_T(" ")); - args.Append(s.sYDLCommandLine); - } - if (s.bYDLAudioOnly && (s.sYDLCommandLine.Find(_T("-f ")) < 0)) { - args.Append(_T(" -f bestaudio")); - } - if (s.sYDLCommandLine.Find(_T("-o ")) < 0) { - args.Append(_T(" -o \"" + filename + "\"")); - } - - ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&startup_info, sizeof(STARTUPINFO)); - startup_info.cb = sizeof(STARTUPINFO); - - if (!CreateProcess(NULL, args.GetBuffer(), NULL, NULL, false, 0, - NULL, NULL, &startup_info, &proc_info)) { - AfxMessageBox(_T("An error occurred while attempting to run Youtube-DL"), MB_ICONERROR, 0); - return false; - } - - CloseHandle(proc_info.hProcess); - CloseHandle(proc_info.hThread); - - return true; -} - -void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) -{ - __super::OnSettingChange(uFlags, lpszSection); - if (SPI_SETNONCLIENTMETRICS == uFlags) { - CMPCThemeUtil::GetMetrics(true); - CMPCThemeMenu::clearDimensions(); - if (nullptr != defaultMPCThemeMenu) { - UpdateUILanguage(); //cheap way to rebuild menus--we want to do this to force them to re-measure - } - RecalcLayout(); - } -} - -BOOL CMainFrame::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) { - if (m_bUseSeekPreview && m_wndPreView.IsWindowVisible()) { - - int seek = - nFlags == MK_SHIFT ? 10 : - nFlags == MK_CONTROL ? 1 : 5; - - zDelta > 0 ? SetCursorPos(point.x + seek, point.y) : - zDelta < 0 ? SetCursorPos(point.x - seek, point.y) : SetCursorPos(point.x, point.y); - - return 0; - } - return __super::OnMouseWheel(nFlags, zDelta, point); -} - -void CMainFrame::OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt) { - if (m_wndView && m_wndView.OnMouseHWheelImpl(nFlags, zDelta, pt)) { - //HWHEEL is sent to active window, so we have to manually pass it to CMouseWnd to trap hotkeys - return; - } - __super::OnMouseHWheel(nFlags, zDelta, pt); -} - -CHdmvClipInfo::BDMVMeta CMainFrame::GetBDMVMeta() -{ - return m_BDMeta.GetHead(); -} - -BOOL CMainFrame::AppendMenuEx(CMenu& menu, UINT nFlags, UINT nIDNewItem, CString& text) -{ - text.Replace(_T("&"), _T("&&")); - auto bResult = menu.AppendMenu(nFlags, nIDNewItem, text.GetString()); - if (bResult && (nFlags & MF_DEFAULT)) { - bResult = menu.SetDefaultItem(nIDNewItem); - } - return bResult; -} - -CString CMainFrame::getBestTitle(bool fTitleBarTextTitle) { - CString title; - if (fTitleBarTextTitle && m_pAMMC[0]) { - for (const auto& pAMMC : m_pAMMC) { - if (pAMMC) { - CComBSTR bstr; - if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { - title = bstr.m_str; - title.Trim(); - if (!title.IsEmpty()) { - return title; - } - } - } - } - } - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_label && !pli.m_label.IsEmpty()) { - if (fTitleBarTextTitle || pli.m_bYoutubeDL) { - title = pli.m_label; - return title; - } - } - - CStringW ext = GetFileExt(GetFileName()); - if (ext == ".mpls" && m_bHasBDMeta) { - title = GetBDMVMeta().title; - return title; - } else if (ext != ".mpls") { - m_bHasBDMeta = false; - m_BDMeta.RemoveAll(); - } - - return L""; -} - -void CMainFrame::MediaTransportControlSetMedia() { - if (m_media_trans_control.smtc_updater && m_media_trans_control.smtc_controls) { - TRACE(_T("CMainFrame::MediaTransportControlSetMedia()\n")); - HRESULT ret = S_OK; - bool have_secondary_title = false; - - CString title = getBestTitle(); - if (title.IsEmpty()) { - title = GetFileName(); - } - - CString author; - if (m_pAMMC[0]) { - for (const auto& pAMMC : m_pAMMC) { - if (pAMMC) { - CComBSTR bstr; - if (SUCCEEDED(pAMMC->get_AuthorName(&bstr)) && bstr.Length()) { - author = bstr.m_str; - author.Trim(); - } - } - } - } - - // Set media details - if (m_fAudioOnly) { - ret = m_media_trans_control.smtc_updater->put_Type(ABI::Windows::Media::MediaPlaybackType_Music); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: put_Type error %ld\n"), ret); - return; - } - - CComPtr pMusicDisplayProperties; - ret = m_media_trans_control.smtc_updater->get_MusicProperties(&pMusicDisplayProperties); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: get_MusicProperties error %ld\n"), ret); - return; - } - - if (!title.IsEmpty()) { - HSTRING ttitle; - if (WindowsCreateString(title.GetString(), title.GetLength(), &ttitle) == S_OK) { - ret = pMusicDisplayProperties->put_Title(ttitle); - ASSERT(ret == S_OK); - } - } - if (!author.IsEmpty()) { - HSTRING temp; - if (WindowsCreateString(author.GetString(), author.GetLength(), &temp) == S_OK) { - ret = pMusicDisplayProperties->put_Artist(temp); - ASSERT(ret == S_OK); - } - } - } else { - ret = m_media_trans_control.smtc_updater->put_Type(ABI::Windows::Media::MediaPlaybackType_Video); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: put_Type error %ld\n"), ret); - return; - } - - CComPtr pVideoDisplayProperties; - ret = m_media_trans_control.smtc_updater->get_VideoProperties(&pVideoDisplayProperties); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: get_VideoProperties error %ld\n"), ret); - return; - } - - if (!title.IsEmpty()) { - HSTRING ttitle; - if (WindowsCreateString(title.GetString(), title.GetLength(), &ttitle) == S_OK) { - ret = pVideoDisplayProperties->put_Title(ttitle); - ASSERT(ret == S_OK); - } - } - CString chapter; - if (m_pCB) { - DWORD dwChapCount = m_pCB->ChapGetCount(); - if (dwChapCount) { - REFERENCE_TIME rtNow; - m_pMS->GetCurrentPosition(&rtNow); - - CComBSTR bstr; - long currentChap = m_pCB->ChapLookup(&rtNow, &bstr); - if (bstr.Length()) { - chapter.Format(_T("%s (%ld/%lu)"), bstr.m_str, std::max(0l, currentChap + 1l), dwChapCount); - } else { - chapter.Format(_T("%ld/%lu"), currentChap + 1, dwChapCount); - } - } - } - if (!chapter.IsEmpty() && chapter != title) { - HSTRING temp; - if (WindowsCreateString(chapter.GetString(), chapter.GetLength(), &temp) == S_OK) { - ret = pVideoDisplayProperties->put_Subtitle(temp); - ASSERT(ret == S_OK); - have_secondary_title = true; - } - } - if (!have_secondary_title && !author.IsEmpty() && author != title) { - HSTRING temp; - if (WindowsCreateString(author.GetString(), author.GetLength(), &temp) == S_OK) { - ret = pVideoDisplayProperties->put_Subtitle(temp); - ASSERT(ret == S_OK); - have_secondary_title = true; - } - } - } - - // Thumbnail - CComQIPtr pFilterGraph = m_pGB; - std::vector internalCover; - if (CoverArt::FindEmbedded(pFilterGraph, internalCover)) { - m_media_trans_control.loadThumbnail(internalCover.data(), internalCover.size()); - } else { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli) && !pli.m_cover.IsEmpty()) { - m_media_trans_control.loadThumbnail(pli.m_cover); - } else { - CString filename = m_wndPlaylistBar.GetCurFileName(); - CString filename_no_ext; - CString filedir; - if (!PathUtils::IsURL(filename)) { - CPath path = CPath(filename); - if (path.FileExists()) { - path.RemoveExtension(); - filename_no_ext = path.m_strPath; - path.RemoveFileSpec(); - filedir = path.m_strPath; - bool is_file_art = false; - CString img = CoverArt::FindExternal(filename_no_ext, filedir, author, is_file_art); - if (!img.IsEmpty()) { - if (m_fAudioOnly || is_file_art) { - m_media_trans_control.loadThumbnail(img); - } - } - } - } - } - } - - // Update data and status - ret = m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus::MediaPlaybackStatus_Playing); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: put_PlaybackStatus error %ld\n"), ret); - return; - } - ret = m_media_trans_control.smtc_updater->Update(); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: Update error %ld\n"), ret); - return; - } - // Enable - ret = m_media_trans_control.smtc_controls->put_IsEnabled(true); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: put_IsEnabled error %ld\n"), ret); - return; - } - } -} - -void CMainFrame::MediaTransportControlUpdateState(OAFilterState state) { - if (m_media_trans_control.smtc_controls) { - if (state == State_Running) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Playing); - else if (state == State_Paused) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Paused); - else if (state == State_Stopped) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Stopped); - else m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Changing); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "MainFrm.h" +#include "mplayerc.h" +#include "version.h" + +#include "GraphThread.h" +#include "FGFilterLAV.h" +#include "FGManager.h" +#include "FGManagerBDA.h" +#include "ShockwaveGraph.h" +#include "TextPassThruFilter.h" +#include "FakeFilterMapper2.h" + +#include "FavoriteAddDlg.h" +#include "GoToDlg.h" +#include "MediaTypesDlg.h" +#include "OpenFileDlg.h" +#include "PnSPresetsDlg.h" +#include "SaveDlg.h" +#include "SaveImageDialog.h" +#include "SaveSubtitlesFileDialog.h" +#include "SaveThumbnailsDialog.h" +#include "OpenDirHelper.h" +#include "OpenDlg.h" +#include "TunerScanDlg.h" + +#include "ComPropertySheet.h" +#include "PPageAccelTbl.h" +#include "PPageAudioSwitcher.h" +#include "PPageFileInfoSheet.h" +#include "PPageSheet.h" +#include "PPageSubStyle.h" +#include "PPageSubtitles.h" + +#include "CoverArt.h" +#include "CrashReporter.h" +#include "KeyProvider.h" +#include "SkypeMoodMsgHandler.h" +#include "Translations.h" +#include "UpdateChecker.h" +#include "WebServer.h" +#include +#include +#include + +#include "../DeCSS/VobFile.h" +#include "../Subtitles/PGSSub.h" +#include "../Subtitles/RLECodedSubtitle.h" +#include "../Subtitles/RTS.h" +#include "../Subtitles/STS.h" +#include + +#include "../filters/InternalPropertyPage.h" +#include "../filters/PinInfoWnd.h" +#include "../filters/renderer/SyncClock/SyncClock.h" +#include "../filters/transform/BufferFilter/BufferFilter.h" + +#include +#include +#include +#include + +#include "FullscreenWnd.h" +#include "Monitors.h" + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "YoutubeDL.h" +#include "CMPCThemeMenu.h" +#include "CMPCThemeDockBar.h" +#include "CMPCThemeMiniDockFrameWnd.h" +#include "RarEntrySelectorDialog.h" +#include "FileHandle.h" +#include "MPCFolderPickerDialog.h" + +#include "stb/stb_image.h" +#include "stb/stb_image_resize2.h" + +#include +#undef SubclassWindow + +// IID_IAMLine21Decoder +DECLARE_INTERFACE_IID_(IAMLine21Decoder_2, IAMLine21Decoder, "6E8D4A21-310C-11d0-B79A-00AA003767A7") {}; + +#define MIN_LOGO_WIDTH 400 +#define MIN_LOGO_HEIGHT 150 + +#define PREV_CHAP_THRESHOLD 2 + +static UINT s_uTaskbarRestart = RegisterWindowMessage(_T("TaskbarCreated")); +static UINT WM_NOTIFYICON = RegisterWindowMessage(_T("MYWM_NOTIFYICON")); +static UINT s_uTBBC = RegisterWindowMessage(_T("TaskbarButtonCreated")); + +CMainFrame::PlaybackRateMap CMainFrame::filePlaybackRates = { + { ID_PLAY_PLAYBACKRATE_025, .25f}, + { ID_PLAY_PLAYBACKRATE_050, .50f}, + { ID_PLAY_PLAYBACKRATE_075, .75f}, + { ID_PLAY_PLAYBACKRATE_090, .90f}, + { ID_PLAY_PLAYBACKRATE_100, 1.00f}, + { ID_PLAY_PLAYBACKRATE_110, 1.10f}, + { ID_PLAY_PLAYBACKRATE_125, 1.25f}, + { ID_PLAY_PLAYBACKRATE_150, 1.50f}, + { ID_PLAY_PLAYBACKRATE_200, 2.00f}, + { ID_PLAY_PLAYBACKRATE_300, 3.00f}, + { ID_PLAY_PLAYBACKRATE_400, 4.00f}, + { ID_PLAY_PLAYBACKRATE_600, 6.00f}, + { ID_PLAY_PLAYBACKRATE_800, 8.00f}, +}; + +CMainFrame::PlaybackRateMap CMainFrame::dvdPlaybackRates = { + { ID_PLAY_PLAYBACKRATE_025, .25f}, + { ID_PLAY_PLAYBACKRATE_050, .50f}, + { ID_PLAY_PLAYBACKRATE_100, 1.00f}, + { ID_PLAY_PLAYBACKRATE_200, 2.00f}, + { ID_PLAY_PLAYBACKRATE_400, 4.00f}, + { ID_PLAY_PLAYBACKRATE_800, 8.00f}, +}; + + +static bool EnsureDirectory(CString directory) +{ + int ret = SHCreateDirectoryEx(nullptr, directory, nullptr); + bool result = ret == ERROR_SUCCESS || ret == ERROR_ALREADY_EXISTS; + if (!result) { + AfxMessageBox(_T("Cannot create directory: ") + directory, MB_ICONEXCLAMATION | MB_OK); + } + return result; +} + +class CSubClock : public CUnknown, public ISubClock +{ + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(ISubClock) + CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + + REFERENCE_TIME m_rt; + +public: + CSubClock() : CUnknown(NAME("CSubClock"), nullptr) { + m_rt = 0; + } + + DECLARE_IUNKNOWN; + + // ISubClock + STDMETHODIMP SetTime(REFERENCE_TIME rt) { + m_rt = rt; + return S_OK; + } + STDMETHODIMP_(REFERENCE_TIME) GetTime() { + return m_rt; + } +}; + +bool FileFavorite::TryParse(const CString& fav, FileFavorite& ff) +{ + CAtlList parts; + return TryParse(fav, ff, parts); +} + +bool FileFavorite::TryParse(const CString& fav, FileFavorite& ff, CAtlList& parts) +{ + ExplodeEsc(fav, parts, _T(';')); + if (parts.IsEmpty()) { + return false; + } + + ff.Name = parts.RemoveHead(); + + if (!parts.IsEmpty()) { + // Start position and optional A-B marks "pos[:A:B]" + auto startPos = parts.RemoveHead(); + _stscanf_s(startPos, _T("%I64d:%I64d:%I64d"), &ff.Start, &ff.MarkA, &ff.MarkB); + ff.Start = std::max(ff.Start, 0ll); // Sanitize + } + if (!parts.IsEmpty()) { + _stscanf_s(parts.RemoveHead(), _T("%d"), &ff.RelativeDrive); + } + return true; +} + +CString FileFavorite::ToString() const +{ + CString str; + if (RelativeDrive) { + str = _T("[RD]"); + } + if (Start > 0) { // Start position + str.AppendFormat(_T("[%s]"), ReftimeToString2(Start).GetString()); + } + if (MarkA > 0 || MarkB > 0) { // A-B marks (only characters to save space) + CString abMarks; + if (MarkA > 0) { + abMarks = _T("A"); + } + if (MarkB > 0) { + abMarks.Append(_T("-B")); + } + str.AppendFormat(_T("[%s]"), abMarks.GetString()); + } + return str; +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame + +IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd) + +BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) + ON_WM_NCCREATE() + ON_WM_CREATE() + ON_WM_DESTROY() + ON_WM_CLOSE() + ON_WM_MEASUREITEM() + + ON_MESSAGE(WM_MPCVR_SWITCH_FULLSCREEN, OnMPCVRSwitchFullscreen) + + ON_REGISTERED_MESSAGE(s_uTaskbarRestart, OnTaskBarRestart) + ON_REGISTERED_MESSAGE(WM_NOTIFYICON, OnNotifyIcon) + + ON_REGISTERED_MESSAGE(s_uTBBC, OnTaskBarThumbnailsCreate) + + ON_REGISTERED_MESSAGE(SkypeMoodMsgHandler::uSkypeControlAPIAttach, OnSkypeAttach) + + ON_WM_SETFOCUS() + ON_WM_GETMINMAXINFO() + ON_WM_MOVE() + ON_WM_ENTERSIZEMOVE() + ON_WM_MOVING() + ON_WM_SIZE() + ON_WM_SIZING() + ON_WM_EXITSIZEMOVE() + ON_MESSAGE_VOID(WM_DISPLAYCHANGE, OnDisplayChange) + ON_WM_WINDOWPOSCHANGING() + + ON_MESSAGE(WM_DPICHANGED, OnDpiChanged) + + ON_WM_SYSCOMMAND() + ON_WM_ACTIVATEAPP() + ON_MESSAGE(WM_APPCOMMAND, OnAppCommand) + ON_WM_INPUT() + ON_MESSAGE(WM_HOTKEY, OnHotKey) + + ON_WM_TIMER() + + ON_MESSAGE(WM_GRAPHNOTIFY, OnGraphNotify) + ON_MESSAGE(WM_RESET_DEVICE, OnResetDevice) + ON_MESSAGE(WM_REARRANGERENDERLESS, OnRepaintRenderLess) + + ON_MESSAGE_VOID(WM_SAVESETTINGS, SaveAppSettings) + + ON_WM_NCHITTEST() + + ON_WM_HSCROLL() + + ON_WM_INITMENU() + ON_WM_INITMENUPOPUP() + ON_WM_UNINITMENUPOPUP() + + ON_WM_ENTERMENULOOP() + + ON_WM_QUERYENDSESSION() + ON_WM_ENDSESSION() + + ON_COMMAND(ID_MENU_PLAYER_SHORT, OnMenuPlayerShort) + ON_COMMAND(ID_MENU_PLAYER_LONG, OnMenuPlayerLong) + ON_COMMAND(ID_MENU_FILTERS, OnMenuFilters) + + ON_UPDATE_COMMAND_UI(IDC_PLAYERSTATUS, OnUpdatePlayerStatus) + + ON_MESSAGE(WM_POSTOPEN, OnFilePostOpenmedia) + ON_MESSAGE(WM_OPENFAILED, OnOpenMediaFailed) + ON_MESSAGE(WM_DVB_EIT_DATA_READY, OnCurrentChannelInfoUpdated) + + ON_COMMAND(ID_BOSS, OnBossKey) + + ON_COMMAND_RANGE(ID_STREAM_AUDIO_NEXT, ID_STREAM_AUDIO_PREV, OnStreamAudio) + ON_COMMAND_RANGE(ID_STREAM_SUB_NEXT, ID_STREAM_SUB_PREV, OnStreamSub) + ON_COMMAND(ID_AUDIOSHIFT_ONOFF, OnAudioShiftOnOff) + ON_COMMAND(ID_STREAM_SUB_ONOFF, OnStreamSubOnOff) + ON_COMMAND_RANGE(ID_DVD_ANGLE_NEXT, ID_DVD_ANGLE_PREV, OnDvdAngle) + ON_COMMAND_RANGE(ID_DVD_AUDIO_NEXT, ID_DVD_AUDIO_PREV, OnDvdAudio) + ON_COMMAND_RANGE(ID_DVD_SUB_NEXT, ID_DVD_SUB_PREV, OnDvdSub) + ON_COMMAND(ID_DVD_SUB_ONOFF, OnDvdSubOnOff) + + ON_COMMAND(ID_FILE_OPENQUICK, OnFileOpenQuick) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENMEDIA, OnUpdateFileOpen) + ON_COMMAND(ID_FILE_OPENMEDIA, OnFileOpenmedia) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENMEDIA, OnUpdateFileOpen) + ON_WM_COPYDATA() + ON_COMMAND(ID_FILE_OPENDVDBD, OnFileOpendvd) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENDVDBD, OnUpdateFileOpen) + ON_COMMAND(ID_FILE_OPENDEVICE, OnFileOpendevice) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENDEVICE, OnUpdateFileOpen) + ON_COMMAND_RANGE(ID_FILE_OPEN_OPTICAL_DISK_START, ID_FILE_OPEN_OPTICAL_DISK_END, OnFileOpenOpticalDisk) + ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_OPEN_OPTICAL_DISK_START, ID_FILE_OPEN_OPTICAL_DISK_END, OnUpdateFileOpen) + ON_COMMAND(ID_FILE_REOPEN, OnFileReopen) + ON_COMMAND(ID_FILE_RECYCLE, OnFileRecycle) + ON_COMMAND(ID_FILE_SAVE_COPY, OnFileSaveAs) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_COPY, OnUpdateFileSaveAs) + ON_COMMAND(ID_FILE_SAVE_IMAGE, OnFileSaveImage) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_IMAGE, OnUpdateFileSaveImage) + ON_COMMAND(ID_FILE_SAVE_IMAGE_AUTO, OnFileSaveImageAuto) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_IMAGE_AUTO, OnUpdateFileSaveImage) + ON_COMMAND(ID_CMDLINE_SAVE_THUMBNAILS, OnCmdLineSaveThumbnails) + ON_COMMAND(ID_FILE_SAVE_THUMBNAILS, OnFileSaveThumbnails) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_THUMBNAILS, OnUpdateFileSaveThumbnails) + ON_COMMAND(ID_FILE_SUBTITLES_LOAD, OnFileSubtitlesLoad) + ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_LOAD, OnUpdateFileSubtitlesLoad) + ON_COMMAND(ID_FILE_SUBTITLES_SAVE, OnFileSubtitlesSave) + ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_SAVE, OnUpdateFileSubtitlesSave) + //ON_COMMAND(ID_FILE_SUBTITLES_UPLOAD, OnFileSubtitlesUpload) + //ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_UPLOAD, OnUpdateFileSubtitlesUpload) + ON_COMMAND(ID_FILE_SUBTITLES_DOWNLOAD, OnFileSubtitlesDownload) + ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_DOWNLOAD, OnUpdateFileSubtitlesDownload) + ON_COMMAND(ID_FILE_PROPERTIES, OnFileProperties) + ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateFileProperties) + ON_COMMAND(ID_FILE_OPEN_LOCATION, OnFileOpenLocation) + ON_UPDATE_COMMAND_UI(ID_FILE_OPEN_LOCATION, OnUpdateFileProperties) + ON_COMMAND(ID_FILE_CLOSE_AND_RESTORE, OnFileCloseAndRestore) + ON_UPDATE_COMMAND_UI(ID_FILE_CLOSE_AND_RESTORE, OnUpdateFileClose) + ON_COMMAND(ID_FILE_CLOSEMEDIA, OnFileCloseMedia) + ON_UPDATE_COMMAND_UI(ID_FILE_CLOSEMEDIA, OnUpdateFileClose) + + ON_COMMAND(ID_VIEW_CAPTIONMENU, OnViewCaptionmenu) + ON_UPDATE_COMMAND_UI(ID_VIEW_CAPTIONMENU, OnUpdateViewCaptionmenu) + ON_COMMAND_RANGE(ID_VIEW_SEEKER, ID_VIEW_STATUS, OnViewControlBar) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_SEEKER, ID_VIEW_STATUS, OnUpdateViewControlBar) + ON_COMMAND(ID_VIEW_SUBRESYNC, OnViewSubresync) + ON_UPDATE_COMMAND_UI(ID_VIEW_SUBRESYNC, OnUpdateViewSubresync) + ON_COMMAND(ID_VIEW_PLAYLIST, OnViewPlaylist) + ON_UPDATE_COMMAND_UI(ID_VIEW_PLAYLIST, OnUpdateViewPlaylist) + ON_COMMAND(ID_PLAYLIST_TOGGLE_SHUFFLE, OnPlaylistToggleShuffle) + ON_COMMAND(ID_VIEW_EDITLISTEDITOR, OnViewEditListEditor) + ON_COMMAND(ID_EDL_IN, OnEDLIn) + ON_UPDATE_COMMAND_UI(ID_EDL_IN, OnUpdateEDLIn) + ON_COMMAND(ID_EDL_OUT, OnEDLOut) + ON_UPDATE_COMMAND_UI(ID_EDL_OUT, OnUpdateEDLOut) + ON_COMMAND(ID_EDL_NEWCLIP, OnEDLNewClip) + ON_UPDATE_COMMAND_UI(ID_EDL_NEWCLIP, OnUpdateEDLNewClip) + ON_COMMAND(ID_EDL_SAVE, OnEDLSave) + ON_UPDATE_COMMAND_UI(ID_EDL_SAVE, OnUpdateEDLSave) + ON_COMMAND(ID_VIEW_CAPTURE, OnViewCapture) + ON_UPDATE_COMMAND_UI(ID_VIEW_CAPTURE, OnUpdateViewCapture) + ON_COMMAND(ID_VIEW_DEBUGSHADERS, OnViewDebugShaders) + ON_UPDATE_COMMAND_UI(ID_VIEW_DEBUGSHADERS, OnUpdateViewDebugShaders) + ON_COMMAND(ID_VIEW_PRESETS_MINIMAL, OnViewMinimal) + ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_MINIMAL, OnUpdateViewMinimal) + ON_COMMAND(ID_VIEW_PRESETS_COMPACT, OnViewCompact) + ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_COMPACT, OnUpdateViewCompact) + ON_COMMAND(ID_VIEW_PRESETS_NORMAL, OnViewNormal) + ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_NORMAL, OnUpdateViewNormal) + ON_COMMAND(ID_VIEW_FULLSCREEN, OnViewFullscreen) + ON_COMMAND(ID_VIEW_FULLSCREEN_SECONDARY, OnViewFullscreenSecondary) + ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCREEN, OnUpdateViewFullscreen) + ON_COMMAND_RANGE(ID_VIEW_ZOOM_50, ID_VIEW_ZOOM_200, OnViewZoom) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_50, ID_VIEW_ZOOM_200, OnUpdateViewZoom) + ON_COMMAND_RANGE(ID_VIEW_ZOOM_25, ID_VIEW_ZOOM_25, OnViewZoom) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_25, ID_VIEW_ZOOM_25, OnUpdateViewZoom) + ON_COMMAND(ID_VIEW_ZOOM_AUTOFIT, OnViewZoomAutoFit) + ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_AUTOFIT, OnUpdateViewZoom) + ON_COMMAND(ID_VIEW_ZOOM_AUTOFIT_LARGER, OnViewZoomAutoFitLarger) + ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_AUTOFIT_LARGER, OnUpdateViewZoom) + ON_COMMAND_RANGE(ID_VIEW_ZOOM_SUB, ID_VIEW_ZOOM_ADD, OnViewModifySize) + ON_COMMAND_RANGE(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, OnViewDefaultVideoFrame) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, OnUpdateViewDefaultVideoFrame) + ON_COMMAND(ID_VIEW_VF_SWITCHZOOM, OnViewSwitchVideoFrame) + ON_COMMAND(ID_VIEW_VF_COMPMONDESKARDIFF, OnViewCompMonDeskARDiff) + ON_UPDATE_COMMAND_UI(ID_VIEW_VF_COMPMONDESKARDIFF, OnUpdateViewCompMonDeskARDiff) + ON_COMMAND_RANGE(ID_VIEW_RESET, ID_PANSCAN_CENTER, OnViewPanNScan) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_RESET, ID_PANSCAN_CENTER, OnUpdateViewPanNScan) + ON_COMMAND_RANGE(ID_PANNSCAN_PRESETS_START, ID_PANNSCAN_PRESETS_END, OnViewPanNScanPresets) + ON_UPDATE_COMMAND_UI_RANGE(ID_PANNSCAN_PRESETS_START, ID_PANNSCAN_PRESETS_END, OnUpdateViewPanNScanPresets) + ON_COMMAND_RANGE(ID_PANSCAN_ROTATEXP, ID_PANSCAN_ROTATEZM, OnViewRotate) + ON_UPDATE_COMMAND_UI_RANGE(ID_PANSCAN_ROTATEXP, ID_PANSCAN_ROTATEZM, OnUpdateViewRotate) + ON_COMMAND_RANGE(ID_PANSCAN_ROTATEZ270, ID_PANSCAN_ROTATEZ270, OnViewRotate) + ON_UPDATE_COMMAND_UI_RANGE(ID_PANSCAN_ROTATEZ270, ID_PANSCAN_ROTATEZ270, OnUpdateViewRotate) + ON_COMMAND_RANGE(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, OnViewAspectRatio) + ON_UPDATE_COMMAND_UI_RANGE(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, OnUpdateViewAspectRatio) + ON_COMMAND(ID_ASPECTRATIO_NEXT, OnViewAspectRatioNext) + ON_COMMAND_RANGE(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, OnViewOntop) + ON_UPDATE_COMMAND_UI_RANGE(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, OnUpdateViewOntop) + ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions) + + // Casimir666 + ON_UPDATE_COMMAND_UI(ID_VIEW_TEARING_TEST, OnUpdateViewTearingTest) + ON_COMMAND(ID_VIEW_TEARING_TEST, OnViewTearingTest) + ON_UPDATE_COMMAND_UI(ID_VIEW_DISPLAY_RENDERER_STATS, OnUpdateViewDisplayRendererStats) + ON_COMMAND(ID_VIEW_RESET_RENDERER_STATS, OnViewResetRendererStats) + ON_COMMAND(ID_VIEW_DISPLAY_RENDERER_STATS, OnViewDisplayRendererStats) + ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCREENGUISUPPORT, OnUpdateViewFullscreenGUISupport) + ON_UPDATE_COMMAND_UI(ID_VIEW_HIGHCOLORRESOLUTION, OnUpdateViewHighColorResolution) + ON_UPDATE_COMMAND_UI(ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION, OnUpdateViewForceInputHighColorResolution) + ON_UPDATE_COMMAND_UI(ID_VIEW_FULLFLOATINGPOINTPROCESSING, OnUpdateViewFullFloatingPointProcessing) + ON_UPDATE_COMMAND_UI(ID_VIEW_HALFFLOATINGPOINTPROCESSING, OnUpdateViewHalfFloatingPointProcessing) + ON_UPDATE_COMMAND_UI(ID_VIEW_ENABLEFRAMETIMECORRECTION, OnUpdateViewEnableFrameTimeCorrection) + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNC, OnUpdateViewVSync) + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET, OnUpdateViewVSyncOffset) + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCACCURATE, OnUpdateViewVSyncAccurate) + + ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZEVIDEO, OnUpdateViewSynchronizeVideo) + ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZEDISPLAY, OnUpdateViewSynchronizeDisplay) + ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZENEAREST, OnUpdateViewSynchronizeNearest) + + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_ENABLE, OnUpdateViewColorManagementEnable) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_AUTO, OnUpdateViewColorManagementInput) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_HDTV, OnUpdateViewColorManagementInput) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_SDTV_NTSC, OnUpdateViewColorManagementInput) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_SDTV_PAL, OnUpdateViewColorManagementInput) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_BRIGHT, OnUpdateViewColorManagementAmbientLight) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_DIM, OnUpdateViewColorManagementAmbientLight) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_DARK, OnUpdateViewColorManagementAmbientLight) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_PERCEPTUAL, OnUpdateViewColorManagementIntent) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC, OnUpdateViewColorManagementIntent) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_SATURATION, OnUpdateViewColorManagementIntent) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC, OnUpdateViewColorManagementIntent) + + ON_UPDATE_COMMAND_UI(ID_VIEW_EVROUTPUTRANGE_0_255, OnUpdateViewEVROutputRange) + ON_UPDATE_COMMAND_UI(ID_VIEW_EVROUTPUTRANGE_16_235, OnUpdateViewEVROutputRange) + + ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_BEFOREVSYNC, OnUpdateViewFlushGPU) + ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_AFTERPRESENT, OnUpdateViewFlushGPU) + ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_WAIT, OnUpdateViewFlushGPU) + + ON_UPDATE_COMMAND_UI(ID_VIEW_D3DFULLSCREEN, OnUpdateViewD3DFullscreen) + ON_UPDATE_COMMAND_UI(ID_VIEW_DISABLEDESKTOPCOMPOSITION, OnUpdateViewDisableDesktopComposition) + ON_UPDATE_COMMAND_UI(ID_VIEW_ALTERNATIVEVSYNC, OnUpdateViewAlternativeVSync) + + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET_INCREASE, OnUpdateViewVSyncOffsetIncrease) + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET_DECREASE, OnUpdateViewVSyncOffsetDecrease) + ON_COMMAND(ID_VIEW_FULLSCREENGUISUPPORT, OnViewFullscreenGUISupport) + ON_COMMAND(ID_VIEW_HIGHCOLORRESOLUTION, OnViewHighColorResolution) + ON_COMMAND(ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION, OnViewForceInputHighColorResolution) + ON_COMMAND(ID_VIEW_FULLFLOATINGPOINTPROCESSING, OnViewFullFloatingPointProcessing) + ON_COMMAND(ID_VIEW_HALFFLOATINGPOINTPROCESSING, OnViewHalfFloatingPointProcessing) + ON_COMMAND(ID_VIEW_ENABLEFRAMETIMECORRECTION, OnViewEnableFrameTimeCorrection) + ON_COMMAND(ID_VIEW_VSYNC, OnViewVSync) + ON_COMMAND(ID_VIEW_VSYNCACCURATE, OnViewVSyncAccurate) + + ON_COMMAND(ID_VIEW_SYNCHRONIZEVIDEO, OnViewSynchronizeVideo) + ON_COMMAND(ID_VIEW_SYNCHRONIZEDISPLAY, OnViewSynchronizeDisplay) + ON_COMMAND(ID_VIEW_SYNCHRONIZENEAREST, OnViewSynchronizeNearest) + + ON_COMMAND(ID_VIEW_CM_ENABLE, OnViewColorManagementEnable) + ON_COMMAND(ID_VIEW_CM_INPUT_AUTO, OnViewColorManagementInputAuto) + ON_COMMAND(ID_VIEW_CM_INPUT_HDTV, OnViewColorManagementInputHDTV) + ON_COMMAND(ID_VIEW_CM_INPUT_SDTV_NTSC, OnViewColorManagementInputSDTV_NTSC) + ON_COMMAND(ID_VIEW_CM_INPUT_SDTV_PAL, OnViewColorManagementInputSDTV_PAL) + ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_BRIGHT, OnViewColorManagementAmbientLightBright) + ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_DIM, OnViewColorManagementAmbientLightDim) + ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_DARK, OnViewColorManagementAmbientLightDark) + ON_COMMAND(ID_VIEW_CM_INTENT_PERCEPTUAL, OnViewColorManagementIntentPerceptual) + ON_COMMAND(ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC, OnViewColorManagementIntentRelativeColorimetric) + ON_COMMAND(ID_VIEW_CM_INTENT_SATURATION, OnViewColorManagementIntentSaturation) + ON_COMMAND(ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC, OnViewColorManagementIntentAbsoluteColorimetric) + + ON_COMMAND(ID_VIEW_EVROUTPUTRANGE_0_255, OnViewEVROutputRange_0_255) + ON_COMMAND(ID_VIEW_EVROUTPUTRANGE_16_235, OnViewEVROutputRange_16_235) + + ON_COMMAND(ID_VIEW_FLUSHGPU_BEFOREVSYNC, OnViewFlushGPUBeforeVSync) + ON_COMMAND(ID_VIEW_FLUSHGPU_AFTERPRESENT, OnViewFlushGPUAfterVSync) + ON_COMMAND(ID_VIEW_FLUSHGPU_WAIT, OnViewFlushGPUWait) + + ON_COMMAND(ID_VIEW_D3DFULLSCREEN, OnViewD3DFullScreen) + ON_COMMAND(ID_VIEW_DISABLEDESKTOPCOMPOSITION, OnViewDisableDesktopComposition) + ON_COMMAND(ID_VIEW_ALTERNATIVEVSYNC, OnViewAlternativeVSync) + ON_COMMAND(ID_VIEW_RESET_DEFAULT, OnViewResetDefault) + ON_COMMAND(ID_VIEW_RESET_OPTIMAL, OnViewResetOptimal) + + ON_COMMAND(ID_VIEW_VSYNCOFFSET_INCREASE, OnViewVSyncOffsetIncrease) + ON_COMMAND(ID_VIEW_VSYNCOFFSET_DECREASE, OnViewVSyncOffsetDecrease) + ON_UPDATE_COMMAND_UI(ID_PRESIZE_SHADERS_TOGGLE, OnUpdateShaderToggle1) + ON_COMMAND(ID_PRESIZE_SHADERS_TOGGLE, OnShaderToggle1) + ON_UPDATE_COMMAND_UI(ID_POSTSIZE_SHADERS_TOGGLE, OnUpdateShaderToggle2) + ON_COMMAND(ID_POSTSIZE_SHADERS_TOGGLE, OnShaderToggle2) + ON_UPDATE_COMMAND_UI(ID_VIEW_OSD_DISPLAY_TIME, OnUpdateViewOSDDisplayTime) + ON_COMMAND(ID_VIEW_OSD_DISPLAY_TIME, OnViewOSDDisplayTime) + ON_UPDATE_COMMAND_UI(ID_VIEW_OSD_SHOW_FILENAME, OnUpdateViewOSDShowFileName) + ON_COMMAND(ID_VIEW_OSD_SHOW_FILENAME, OnViewOSDShowFileName) + ON_COMMAND(ID_D3DFULLSCREEN_TOGGLE, OnD3DFullscreenToggle) + ON_COMMAND_RANGE(ID_GOTO_PREV_SUB, ID_GOTO_NEXT_SUB, OnGotoSubtitle) + ON_COMMAND_RANGE(ID_SUBRESYNC_SHIFT_DOWN, ID_SUBRESYNC_SHIFT_UP, OnSubresyncShiftSub) + ON_COMMAND_RANGE(ID_SUB_DELAY_DOWN, ID_SUB_DELAY_UP, OnSubtitleDelay) + ON_COMMAND_RANGE(ID_SUB_POS_DOWN, ID_SUB_POS_UP, OnSubtitlePos) + ON_COMMAND_RANGE(ID_SUB_FONT_SIZE_DEC, ID_SUB_FONT_SIZE_INC, OnSubtitleFontSize) + + ON_COMMAND(ID_PLAY_PLAY, OnPlayPlay) + ON_COMMAND(ID_PLAY_PAUSE, OnPlayPause) + ON_COMMAND(ID_PLAY_PLAYPAUSE, OnPlayPlaypause) + ON_COMMAND(ID_PLAY_STOP, OnPlayStop) + ON_UPDATE_COMMAND_UI(ID_PLAY_PLAY, OnUpdatePlayPauseStop) + ON_UPDATE_COMMAND_UI(ID_PLAY_PAUSE, OnUpdatePlayPauseStop) + ON_UPDATE_COMMAND_UI(ID_PLAY_PLAYPAUSE, OnUpdatePlayPauseStop) + ON_UPDATE_COMMAND_UI(ID_PLAY_STOP, OnUpdatePlayPauseStop) + ON_COMMAND_RANGE(ID_PLAY_FRAMESTEP, ID_PLAY_FRAMESTEP_BACK, OnPlayFramestep) + ON_UPDATE_COMMAND_UI(ID_PLAY_FRAMESTEP, OnUpdatePlayFramestep) + ON_COMMAND_RANGE(ID_PLAY_SEEKBACKWARDSMALL, ID_PLAY_SEEKFORWARDLARGE, OnPlaySeek) + ON_COMMAND(ID_PLAY_SEEKSET, OnPlaySeekSet) + ON_COMMAND_RANGE(ID_PLAY_SEEKKEYBACKWARD, ID_PLAY_SEEKKEYFORWARD, OnPlaySeekKey) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_SEEKBACKWARDSMALL, ID_PLAY_SEEKFORWARDLARGE, OnUpdatePlaySeek) + ON_UPDATE_COMMAND_UI(ID_PLAY_SEEKSET, OnUpdatePlaySeek) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_SEEKKEYBACKWARD, ID_PLAY_SEEKKEYFORWARD, OnUpdatePlaySeek) + ON_COMMAND_RANGE(ID_PLAY_DECRATE, ID_PLAY_INCRATE, OnPlayChangeRate) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_DECRATE, ID_PLAY_INCRATE, OnUpdatePlayChangeRate) + ON_COMMAND_RANGE(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, OnPlayChangeRate) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, OnUpdatePlayChangeRate) + ON_COMMAND(ID_PLAY_RESETRATE, OnPlayResetRate) + ON_UPDATE_COMMAND_UI(ID_PLAY_RESETRATE, OnUpdatePlayResetRate) + ON_COMMAND_RANGE(ID_PLAY_INCAUDDELAY, ID_PLAY_DECAUDDELAY, OnPlayChangeAudDelay) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_INCAUDDELAY, ID_PLAY_DECAUDDELAY, OnUpdatePlayChangeAudDelay) + ON_COMMAND(ID_FILTERS_COPY_TO_CLIPBOARD, OnPlayFiltersCopyToClipboard) + ON_COMMAND_RANGE(ID_FILTERS_SUBITEM_START, ID_FILTERS_SUBITEM_END, OnPlayFilters) + ON_UPDATE_COMMAND_UI_RANGE(ID_FILTERS_SUBITEM_START, ID_FILTERS_SUBITEM_END, OnUpdatePlayFilters) + ON_COMMAND(ID_SHADERS_SELECT, OnPlayShadersSelect) + ON_COMMAND(ID_SHADERS_PRESET_NEXT, OnPlayShadersPresetNext) + ON_COMMAND(ID_SHADERS_PRESET_PREV, OnPlayShadersPresetPrev) + ON_COMMAND_RANGE(ID_SHADERS_PRESETS_START, ID_SHADERS_PRESETS_END, OnPlayShadersPresets) + ON_COMMAND_RANGE(ID_AUDIO_SUBITEM_START, ID_AUDIO_SUBITEM_END, OnPlayAudio) + ON_COMMAND_RANGE(ID_SUBTITLES_SUBITEM_START, ID_SUBTITLES_SUBITEM_END, OnPlaySubtitles) + ON_COMMAND(ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE, OnSubtitlesDefaultStyle) + ON_COMMAND_RANGE(ID_VIDEO_STREAMS_SUBITEM_START, ID_VIDEO_STREAMS_SUBITEM_END, OnPlayVideoStreams) + ON_COMMAND_RANGE(ID_FILTERSTREAMS_SUBITEM_START, ID_FILTERSTREAMS_SUBITEM_END, OnPlayFiltersStreams) + ON_COMMAND_RANGE(ID_VOLUME_UP, ID_VOLUME_MUTE, OnPlayVolume) + ON_COMMAND_RANGE(ID_VOLUME_BOOST_INC, ID_VOLUME_BOOST_MAX, OnPlayVolumeBoost) + ON_UPDATE_COMMAND_UI_RANGE(ID_VOLUME_BOOST_INC, ID_VOLUME_BOOST_MAX, OnUpdatePlayVolumeBoost) + ON_COMMAND(ID_CUSTOM_CHANNEL_MAPPING, OnCustomChannelMapping) + ON_UPDATE_COMMAND_UI(ID_CUSTOM_CHANNEL_MAPPING, OnUpdateCustomChannelMapping) + ON_COMMAND_RANGE(ID_NORMALIZE, ID_REGAIN_VOLUME, OnNormalizeRegainVolume) + ON_UPDATE_COMMAND_UI_RANGE(ID_NORMALIZE, ID_REGAIN_VOLUME, OnUpdateNormalizeRegainVolume) + ON_COMMAND_RANGE(ID_COLOR_BRIGHTNESS_INC, ID_COLOR_RESET, OnPlayColor) + ON_UPDATE_COMMAND_UI_RANGE(ID_AFTERPLAYBACK_EXIT, ID_AFTERPLAYBACK_MONITOROFF, OnUpdateAfterplayback) + ON_COMMAND_RANGE(ID_AFTERPLAYBACK_EXIT, ID_AFTERPLAYBACK_MONITOROFF, OnAfterplayback) + ON_UPDATE_COMMAND_UI_RANGE(ID_AFTERPLAYBACK_PLAYNEXT, ID_AFTERPLAYBACK_DONOTHING, OnUpdateAfterplayback) + ON_COMMAND_RANGE(ID_AFTERPLAYBACK_PLAYNEXT, ID_AFTERPLAYBACK_DONOTHING, OnAfterplayback) + ON_COMMAND_RANGE(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, OnPlayRepeat) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, OnUpdatePlayRepeat) + ON_COMMAND_RANGE(ID_PLAY_REPEAT_AB, ID_PLAY_REPEAT_AB_MARK_B, OnABRepeat) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_REPEAT_AB, ID_PLAY_REPEAT_AB_MARK_B, OnUpdateABRepeat) + ON_COMMAND(ID_PLAY_REPEAT_FOREVER, OnPlayRepeatForever) + ON_UPDATE_COMMAND_UI(ID_PLAY_REPEAT_FOREVER, OnUpdatePlayRepeatForever) + + ON_COMMAND_RANGE(ID_NAVIGATE_SKIPBACK, ID_NAVIGATE_SKIPFORWARD, OnNavigateSkip) + ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_SKIPBACK, ID_NAVIGATE_SKIPFORWARD, OnUpdateNavigateSkip) + ON_COMMAND_RANGE(ID_NAVIGATE_SKIPBACKFILE, ID_NAVIGATE_SKIPFORWARDFILE, OnNavigateSkipFile) + ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_SKIPBACKFILE, ID_NAVIGATE_SKIPFORWARDFILE, OnUpdateNavigateSkipFile) + ON_COMMAND(ID_NAVIGATE_GOTO, OnNavigateGoto) + ON_UPDATE_COMMAND_UI(ID_NAVIGATE_GOTO, OnUpdateNavigateGoto) + ON_COMMAND_RANGE(ID_NAVIGATE_TITLEMENU, ID_NAVIGATE_CHAPTERMENU, OnNavigateMenu) + ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_TITLEMENU, ID_NAVIGATE_CHAPTERMENU, OnUpdateNavigateMenu) + ON_COMMAND_RANGE(ID_NAVIGATE_JUMPTO_SUBITEM_START, ID_NAVIGATE_JUMPTO_SUBITEM_END, OnNavigateJumpTo) + ON_COMMAND_RANGE(ID_NAVIGATE_MENU_LEFT, ID_NAVIGATE_MENU_LEAVE, OnNavigateMenuItem) + ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_MENU_LEFT, ID_NAVIGATE_MENU_LEAVE, OnUpdateNavigateMenuItem) + + ON_COMMAND(ID_NAVIGATE_TUNERSCAN, OnTunerScan) + ON_UPDATE_COMMAND_UI(ID_NAVIGATE_TUNERSCAN, OnUpdateTunerScan) + + ON_COMMAND(ID_FAVORITES_ADD, OnFavoritesAdd) + ON_UPDATE_COMMAND_UI(ID_FAVORITES_ADD, OnUpdateFavoritesAdd) + ON_COMMAND(ID_FAVORITES_QUICKADDFAVORITE, OnFavoritesQuickAddFavorite) + ON_COMMAND(ID_FAVORITES_ORGANIZE, OnFavoritesOrganize) + ON_UPDATE_COMMAND_UI(ID_FAVORITES_ORGANIZE, OnUpdateFavoritesOrganize) + ON_COMMAND_RANGE(ID_FAVORITES_FILE_START, ID_FAVORITES_FILE_END, OnFavoritesFile) + ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_FILE_START, ID_FAVORITES_FILE_END, OnUpdateFavoritesFile) + ON_COMMAND_RANGE(ID_FAVORITES_DVD_START, ID_FAVORITES_DVD_END, OnFavoritesDVD) + ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_DVD_START, ID_FAVORITES_DVD_END, OnUpdateFavoritesDVD) + ON_COMMAND_RANGE(ID_FAVORITES_DEVICE_START, ID_FAVORITES_DEVICE_END, OnFavoritesDevice) + ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_DEVICE_START, ID_FAVORITES_DEVICE_END, OnUpdateFavoritesDevice) + + ON_COMMAND(ID_RECENT_FILES_CLEAR, OnRecentFileClear) + ON_UPDATE_COMMAND_UI(ID_RECENT_FILES_CLEAR, OnUpdateRecentFileClear) + ON_COMMAND_RANGE(ID_RECENT_FILE_START, ID_RECENT_FILE_END, OnRecentFile) + ON_UPDATE_COMMAND_UI_RANGE(ID_RECENT_FILE_START, ID_RECENT_FILE_END, OnUpdateRecentFile) + + ON_COMMAND(ID_HELP_HOMEPAGE, OnHelpHomepage) + ON_COMMAND(ID_HELP_CHECKFORUPDATE, OnHelpCheckForUpdate) + ON_COMMAND(ID_HELP_TOOLBARIMAGES, OnHelpToolbarImages) + ON_COMMAND(ID_HELP_DONATE, OnHelpDonate) + + // Open Dir incl. SubDir + ON_COMMAND(ID_FILE_OPENDIRECTORY, OnFileOpendirectory) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENDIRECTORY, OnUpdateFileOpen) + ON_WM_POWERBROADCAST() + + // Navigation panel + ON_COMMAND(ID_VIEW_NAVIGATION, OnViewNavigation) + ON_UPDATE_COMMAND_UI(ID_VIEW_NAVIGATION, OnUpdateViewNavigation) + + ON_WM_WTSSESSION_CHANGE() + + ON_MESSAGE(WM_LOADSUBTITLES, OnLoadSubtitles) + ON_MESSAGE(WM_GETSUBTITLES, OnGetSubtitles) + ON_WM_DRAWITEM() + ON_WM_SETTINGCHANGE() + ON_WM_MOUSEHWHEEL() +END_MESSAGE_MAP() + +#ifdef _DEBUG +const TCHAR* GetEventString(LONG evCode) +{ +#define UNPACK_VALUE(VALUE) case VALUE: return _T(#VALUE); + switch (evCode) { + // System-defined event codes + UNPACK_VALUE(EC_COMPLETE); + UNPACK_VALUE(EC_USERABORT); + UNPACK_VALUE(EC_ERRORABORT); + //UNPACK_VALUE(EC_TIME); + UNPACK_VALUE(EC_REPAINT); + UNPACK_VALUE(EC_STREAM_ERROR_STOPPED); + UNPACK_VALUE(EC_STREAM_ERROR_STILLPLAYING); + UNPACK_VALUE(EC_ERROR_STILLPLAYING); + UNPACK_VALUE(EC_PALETTE_CHANGED); + UNPACK_VALUE(EC_VIDEO_SIZE_CHANGED); + UNPACK_VALUE(EC_QUALITY_CHANGE); + UNPACK_VALUE(EC_SHUTTING_DOWN); + UNPACK_VALUE(EC_CLOCK_CHANGED); + UNPACK_VALUE(EC_PAUSED); + UNPACK_VALUE(EC_OPENING_FILE); + UNPACK_VALUE(EC_BUFFERING_DATA); + UNPACK_VALUE(EC_FULLSCREEN_LOST); + UNPACK_VALUE(EC_ACTIVATE); + UNPACK_VALUE(EC_NEED_RESTART); + UNPACK_VALUE(EC_WINDOW_DESTROYED); + UNPACK_VALUE(EC_DISPLAY_CHANGED); + UNPACK_VALUE(EC_STARVATION); + UNPACK_VALUE(EC_OLE_EVENT); + UNPACK_VALUE(EC_NOTIFY_WINDOW); + UNPACK_VALUE(EC_STREAM_CONTROL_STOPPED); + UNPACK_VALUE(EC_STREAM_CONTROL_STARTED); + UNPACK_VALUE(EC_END_OF_SEGMENT); + UNPACK_VALUE(EC_SEGMENT_STARTED); + UNPACK_VALUE(EC_LENGTH_CHANGED); + UNPACK_VALUE(EC_DEVICE_LOST); + UNPACK_VALUE(EC_SAMPLE_NEEDED); + UNPACK_VALUE(EC_PROCESSING_LATENCY); + UNPACK_VALUE(EC_SAMPLE_LATENCY); + UNPACK_VALUE(EC_SCRUB_TIME); + UNPACK_VALUE(EC_STEP_COMPLETE); + UNPACK_VALUE(EC_TIMECODE_AVAILABLE); + UNPACK_VALUE(EC_EXTDEVICE_MODE_CHANGE); + UNPACK_VALUE(EC_STATE_CHANGE); + UNPACK_VALUE(EC_GRAPH_CHANGED); + UNPACK_VALUE(EC_CLOCK_UNSET); + UNPACK_VALUE(EC_VMR_RENDERDEVICE_SET); + UNPACK_VALUE(EC_VMR_SURFACE_FLIPPED); + UNPACK_VALUE(EC_VMR_RECONNECTION_FAILED); + UNPACK_VALUE(EC_PREPROCESS_COMPLETE); + UNPACK_VALUE(EC_CODECAPI_EVENT); + UNPACK_VALUE(EC_WMT_INDEX_EVENT); + UNPACK_VALUE(EC_WMT_EVENT); + UNPACK_VALUE(EC_BUILT); + UNPACK_VALUE(EC_UNBUILT); + UNPACK_VALUE(EC_SKIP_FRAMES); + UNPACK_VALUE(EC_PLEASE_REOPEN); + UNPACK_VALUE(EC_STATUS); + UNPACK_VALUE(EC_MARKER_HIT); + UNPACK_VALUE(EC_LOADSTATUS); + UNPACK_VALUE(EC_FILE_CLOSED); + UNPACK_VALUE(EC_ERRORABORTEX); + //UNPACK_VALUE(EC_NEW_PIN); + //UNPACK_VALUE(EC_RENDER_FINISHED); + UNPACK_VALUE(EC_EOS_SOON); + UNPACK_VALUE(EC_CONTENTPROPERTY_CHANGED); + UNPACK_VALUE(EC_BANDWIDTHCHANGE); + UNPACK_VALUE(EC_VIDEOFRAMEREADY); + // DVD-Video event codes + UNPACK_VALUE(EC_DVD_DOMAIN_CHANGE); + UNPACK_VALUE(EC_DVD_TITLE_CHANGE); + UNPACK_VALUE(EC_DVD_CHAPTER_START); + UNPACK_VALUE(EC_DVD_AUDIO_STREAM_CHANGE); + UNPACK_VALUE(EC_DVD_SUBPICTURE_STREAM_CHANGE); + UNPACK_VALUE(EC_DVD_ANGLE_CHANGE); + UNPACK_VALUE(EC_DVD_BUTTON_CHANGE); + UNPACK_VALUE(EC_DVD_VALID_UOPS_CHANGE); + UNPACK_VALUE(EC_DVD_STILL_ON); + UNPACK_VALUE(EC_DVD_STILL_OFF); + UNPACK_VALUE(EC_DVD_CURRENT_TIME); + UNPACK_VALUE(EC_DVD_ERROR); + UNPACK_VALUE(EC_DVD_WARNING); + UNPACK_VALUE(EC_DVD_CHAPTER_AUTOSTOP); + UNPACK_VALUE(EC_DVD_NO_FP_PGC); + UNPACK_VALUE(EC_DVD_PLAYBACK_RATE_CHANGE); + UNPACK_VALUE(EC_DVD_PARENTAL_LEVEL_CHANGE); + UNPACK_VALUE(EC_DVD_PLAYBACK_STOPPED); + UNPACK_VALUE(EC_DVD_ANGLES_AVAILABLE); + UNPACK_VALUE(EC_DVD_PLAYPERIOD_AUTOSTOP); + UNPACK_VALUE(EC_DVD_BUTTON_AUTO_ACTIVATED); + UNPACK_VALUE(EC_DVD_CMD_START); + UNPACK_VALUE(EC_DVD_CMD_END); + UNPACK_VALUE(EC_DVD_DISC_EJECTED); + UNPACK_VALUE(EC_DVD_DISC_INSERTED); + UNPACK_VALUE(EC_DVD_CURRENT_HMSF_TIME); + UNPACK_VALUE(EC_DVD_KARAOKE_MODE); + UNPACK_VALUE(EC_DVD_PROGRAM_CELL_CHANGE); + UNPACK_VALUE(EC_DVD_TITLE_SET_CHANGE); + UNPACK_VALUE(EC_DVD_PROGRAM_CHAIN_CHANGE); + UNPACK_VALUE(EC_DVD_VOBU_Offset); + UNPACK_VALUE(EC_DVD_VOBU_Timestamp); + UNPACK_VALUE(EC_DVD_GPRM_Change); + UNPACK_VALUE(EC_DVD_SPRM_Change); + UNPACK_VALUE(EC_DVD_BeginNavigationCommands); + UNPACK_VALUE(EC_DVD_NavigationCommand); + // Sound device error event codes + UNPACK_VALUE(EC_SNDDEV_IN_ERROR); + UNPACK_VALUE(EC_SNDDEV_OUT_ERROR); + // Custom event codes + UNPACK_VALUE(EC_BG_AUDIO_CHANGED); + UNPACK_VALUE(EC_BG_ERROR); + }; +#undef UNPACK_VALUE + return _T("UNKNOWN"); +} +#endif + +void CMainFrame::EventCallback(MpcEvent ev) +{ + const auto& s = AfxGetAppSettings(); + switch (ev) { + case MpcEvent::SHADER_SELECTION_CHANGED: + case MpcEvent::SHADER_PRERESIZE_SELECTION_CHANGED: + case MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED: + SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); + break; + case MpcEvent::DISPLAY_MODE_AUTOCHANGING: + if (GetLoadState() == MLS::LOADED && GetMediaState() == State_Running && s.autoChangeFSMode.uDelay) { + // pause if the mode is being changed during playback + OnPlayPause(); + m_bPausedForAutochangeMonitorMode = true; + } + break; + case MpcEvent::DISPLAY_MODE_AUTOCHANGED: + if (GetLoadState() == MLS::LOADED) { + if (m_bPausedForAutochangeMonitorMode && s.autoChangeFSMode.uDelay) { + // delay play if was paused due to mode change + ASSERT(GetMediaState() != State_Stopped); + const unsigned uModeChangeDelay = s.autoChangeFSMode.uDelay * 1000; + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, + std::bind(&CMainFrame::OnPlayPlay, this), uModeChangeDelay); + } else if (m_bDelaySetOutputRect) { + ASSERT(GetMediaState() == State_Stopped); + // tell OnFilePostOpenmedia() to delay entering play or paused state + m_bOpeningInAutochangedMonitorMode = true; + } + } + break; + case MpcEvent::CHANGING_UI_LANGUAGE: + UpdateUILanguage(); + break; + case MpcEvent::STREAM_POS_UPDATE_REQUEST: + OnTimer(TIMER_STREAMPOSPOLLER); + OnTimer(TIMER_STREAMPOSPOLLER2); + break; + default: + ASSERT(FALSE); + } +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame construction/destruction + +CMainFrame::CMainFrame() + : m_timerHider(this, TIMER_HIDER, 200) + , m_timerOneTime(this, TIMER_ONETIME_START, TIMER_ONETIME_END - TIMER_ONETIME_START + 1) + , m_bUsingDXVA(false) + , m_HWAccelType(nullptr) + , m_posFirstExtSub(nullptr) + , m_bDelaySetOutputRect(false) + , m_nJumpToSubMenusCount(0) + , m_nLoops(0) + , m_nLastSkipDirection(0) + , m_fCustomGraph(false) + , m_fShockwaveGraph(false) + , m_fFrameSteppingActive(false) + , m_nStepForwardCount(0) + , m_rtStepForwardStart(0) + , m_nVolumeBeforeFrameStepping(0) + , m_fEndOfStream(false) + , m_dwLastPause(0) + , m_dwReloadPos(0) + , m_iReloadAudioIdx(-1) + , m_iReloadSubIdx(-1) + , m_bRememberFilePos(false) + , m_dwLastRun(0) + , m_bBuffering(false) + , m_fLiveWM(false) + , m_rtDurationOverride(-1) + , m_iPlaybackMode(PM_NONE) + , m_lCurrentChapter(0) + , m_lChapterStartTime(0xFFFFFFFF) + , m_eMediaLoadState(MLS::CLOSED) + , m_CachedFilterState(-1) + , m_bSettingUpMenus(false) + , m_bOpenMediaActive(false) + , m_OpenMediaFailedCount(0) + , m_fFullScreen(false) + , m_bFullScreenWindowIsD3D(false) + , m_bFullScreenWindowIsOnSeparateDisplay(false) + , m_bNeedZoomAfterFullscreenExit(false) + , m_fStartInD3DFullscreen(false) + , m_fStartInFullscreenSeparate(false) + , m_pLastBar(nullptr) + , m_bFirstPlay(false) + , m_bOpeningInAutochangedMonitorMode(false) + , m_bPausedForAutochangeMonitorMode(false) + , m_fAudioOnly(true) + , m_iDVDDomain(DVD_DOMAIN_Stop) + , m_iDVDTitle(0) + , m_bDVDStillOn(false) + , m_dSpeedRate(1.0) + , m_ZoomX(1.0) + , m_ZoomY(1.0) + , m_PosX(0.5) + , m_PosY(0.5) + , m_AngleX(0) + , m_AngleY(0) + , m_AngleZ(0) + , m_iDefRotation(0) + , m_pGraphThread(nullptr) + , m_bOpenedThroughThread(false) + , m_evOpenPrivateFinished(FALSE, TRUE) + , m_evClosePrivateFinished(FALSE, TRUE) + , m_fOpeningAborted(false) + , m_bWasSnapped(false) + , m_wndSubtitlesDownloadDialog(this) + //, m_wndSubtitlesUploadDialog(this) + , m_wndFavoriteOrganizeDialog(this) + , m_bTrayIcon(false) + , m_fCapturing(false) + , m_controls(this) + , m_wndView(this) + , m_wndSeekBar(this) + , m_wndToolBar(this) + , m_wndInfoBar(this) + , m_wndStatsBar(this) + , m_wndStatusBar(this) + , m_wndSubresyncBar(this) + , m_wndPlaylistBar(this) + , m_wndPreView(this) + , m_wndCaptureBar(this) + , m_wndNavigationBar(this) + , m_pVideoWnd(nullptr) + , m_pOSDWnd(nullptr) + , m_pDedicatedFSVideoWnd(nullptr) + , m_OSD(this) + , m_nCurSubtitle(-1) + , m_lSubtitleShift(0) + , m_rtCurSubPos(0) + , m_bScanDlgOpened(false) + , m_bStopTunerScan(false) + , m_bLockedZoomVideoWindow(false) + , m_nLockedZoomVideoWindow(0) + , m_pActiveContextMenu(nullptr) + , m_pActiveSystemMenu(nullptr) + , m_bAltDownClean(false) + , m_bShowingFloatingMenubar(false) + , m_bAllowWindowZoom(false) + , m_dLastVideoScaleFactor(0) + , m_bExtOnTop(false) + , m_bIsBDPlay(false) + , m_bHasBDMeta(false) + , watchingDialog(themableDialogTypes::None) + , dialogHookHelper(nullptr) + , delayingFullScreen(false) + , restoringWindowRect(false) + , mediaTypesErrorDlg(nullptr) + , m_iStreamPosPollerInterval(100) + , currentAudioLang(_T("")) + , currentSubLang(_T("")) + , m_bToggleShader(false) + , m_bToggleShaderScreenSpace(false) + , m_MPLSPlaylist() + , m_sydlLastProcessURL() + , m_bUseSeekPreview(false) + , queuedSeek({0,0,false}) + , lastSeekStart(0) + , lastSeekFinish(0) + , defaultVideoAngle(0) + , m_media_trans_control() + , recentFilesMenuFromMRUSequence(-1) +{ + // Don't let CFrameWnd handle automatically the state of the menu items. + // This means that menu items without handlers won't be automatically + // disabled but it avoids some unwanted cases where programmatically + // disabled menu items are always re-enabled by CFrameWnd. + m_bAutoMenuEnable = FALSE; + + EventRouter::EventSelection receives; + receives.insert(MpcEvent::SHADER_SELECTION_CHANGED); + receives.insert(MpcEvent::SHADER_PRERESIZE_SELECTION_CHANGED); + receives.insert(MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED); + receives.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGING); + receives.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGED); + receives.insert(MpcEvent::CHANGING_UI_LANGUAGE); + receives.insert(MpcEvent::STREAM_POS_UPDATE_REQUEST); + EventRouter::EventSelection fires; + fires.insert(MpcEvent::SWITCHING_TO_FULLSCREEN); + fires.insert(MpcEvent::SWITCHED_TO_FULLSCREEN); + fires.insert(MpcEvent::SWITCHING_FROM_FULLSCREEN); + fires.insert(MpcEvent::SWITCHED_FROM_FULLSCREEN); + fires.insert(MpcEvent::SWITCHING_TO_FULLSCREEN_D3D); + fires.insert(MpcEvent::SWITCHED_TO_FULLSCREEN_D3D); + fires.insert(MpcEvent::MEDIA_LOADED); + fires.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGING); + fires.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGED); + fires.insert(MpcEvent::CONTEXT_MENU_POPUP_INITIALIZED); + fires.insert(MpcEvent::CONTEXT_MENU_POPUP_UNINITIALIZED); + fires.insert(MpcEvent::SYSTEM_MENU_POPUP_INITIALIZED); + fires.insert(MpcEvent::SYSTEM_MENU_POPUP_UNINITIALIZED); + fires.insert(MpcEvent::DPI_CHANGED); + GetEventd().Connect(m_eventc, receives, std::bind(&CMainFrame::EventCallback, this, std::placeholders::_1), fires); +} + +CMainFrame::~CMainFrame() +{ + if (defaultMPCThemeMenu != nullptr) { + delete defaultMPCThemeMenu; + } +} + +int CMainFrame::OnNcCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (IsWindows10OrGreater()) { + // Tell Windows to automatically handle scaling of non-client areas + // such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10 + const WinapiFunc + fnEnableNonClientDpiScaling = { _T("User32.dll"), "EnableNonClientDpiScaling" }; + + if (fnEnableNonClientDpiScaling) { + fnEnableNonClientDpiScaling(m_hWnd); + } + } + + return __super::OnNcCreate(lpCreateStruct); +} + +int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (__super::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + CMPCThemeUtil::enableWindows10DarkFrame(this); + + if (IsWindows8Point1OrGreater()) { + m_dpi.Override(m_hWnd); + } + + const WinapiFunc + fnChangeWindowMessageFilterEx = { _T("user32.dll"), "ChangeWindowMessageFilterEx" }; + + // allow taskbar messages through UIPI + if (fnChangeWindowMessageFilterEx) { + VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, s_uTaskbarRestart, MSGFLT_ALLOW, nullptr)); + VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, s_uTBBC, MSGFLT_ALLOW, nullptr)); + VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, WM_COMMAND, MSGFLT_ALLOW, nullptr)); + } + + VERIFY(m_popupMenu.LoadMenu(IDR_POPUP)); + VERIFY(m_mainPopupMenu.LoadMenu(IDR_POPUPMAIN)); + CreateDynamicMenus(); + + // 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); + + const CAppSettings& s = AfxGetAppSettings(); + + // Create OSD Window + CreateOSDBar(); + + // Create Preview Window + if (s.fSeekPreview) { + if (m_wndPreView.CreateEx(0, AfxRegisterWndClass(0), nullptr, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CRect(0, 0, 160, 109), this, 0)) { + m_wndPreView.ShowWindow(SW_HIDE); + m_wndPreView.SetRelativeSize(AfxGetAppSettings().iSeekPreviewSize); + } else { + TRACE(_T("Failed to create Preview Window")); + } + } + + // 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 + } + + m_pDedicatedFSVideoWnd = DEBUG_NEW CFullscreenWnd(this); + + m_controls.m_toolbars[CMainFrameControls::Toolbar::SEEKBAR] = &m_wndSeekBar; + m_controls.m_toolbars[CMainFrameControls::Toolbar::CONTROLS] = &m_wndToolBar; + m_controls.m_toolbars[CMainFrameControls::Toolbar::INFO] = &m_wndInfoBar; + m_controls.m_toolbars[CMainFrameControls::Toolbar::STATS] = &m_wndStatsBar; + m_controls.m_toolbars[CMainFrameControls::Toolbar::STATUS] = &m_wndStatusBar; + + // dockable bars + + EnableDocking(CBRS_ALIGN_ANY); + + bResult = m_wndSubresyncBar.Create(this, AFX_IDW_DOCKBAR_TOP, &m_csSubLock); + if (bResult) { + m_wndSubresyncBar.SetBarStyle(m_wndSubresyncBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndSubresyncBar.EnableDocking(CBRS_ALIGN_ANY); + m_wndSubresyncBar.SetHeight(200); + m_controls.m_panels[CMainFrameControls::Panel::SUBRESYNC] = &m_wndSubresyncBar; + } + bResult = bResult && m_wndPlaylistBar.Create(this, AFX_IDW_DOCKBAR_RIGHT); + if (bResult) { + m_wndPlaylistBar.SetBarStyle(m_wndPlaylistBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndPlaylistBar.EnableDocking(CBRS_ALIGN_ANY); + m_wndPlaylistBar.SetWidth(300); + m_controls.m_panels[CMainFrameControls::Panel::PLAYLIST] = &m_wndPlaylistBar; + //m_wndPlaylistBar.LoadPlaylist(GetRecentFile()); //adipose 2019-11-12; do this later after activating the frame + } + bResult = bResult && m_wndEditListEditor.Create(this, AFX_IDW_DOCKBAR_RIGHT); + if (bResult) { + m_wndEditListEditor.SetBarStyle(m_wndEditListEditor.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndEditListEditor.EnableDocking(CBRS_ALIGN_ANY); + m_controls.m_panels[CMainFrameControls::Panel::EDL] = &m_wndEditListEditor; + m_wndEditListEditor.SetHeight(100); + } + bResult = bResult && m_wndCaptureBar.Create(this, AFX_IDW_DOCKBAR_LEFT); + if (bResult) { + m_wndCaptureBar.SetBarStyle(m_wndCaptureBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndCaptureBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); + m_controls.m_panels[CMainFrameControls::Panel::CAPTURE] = &m_wndCaptureBar; + } + bResult = bResult && m_wndNavigationBar.Create(this, AFX_IDW_DOCKBAR_LEFT); + if (bResult) { + m_wndNavigationBar.SetBarStyle(m_wndNavigationBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndNavigationBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); + m_controls.m_panels[CMainFrameControls::Panel::NAVIGATION] = &m_wndNavigationBar; + } + if (!bResult) { + TRACE(_T("Failed to create all dockable bars\n")); + return -1; + } + + // Hide all controls initially + for (const auto& pair : m_controls.m_toolbars) { + pair.second->ShowWindow(SW_HIDE); + } + for (const auto& pair : m_controls.m_panels) { + pair.second->ShowWindow(SW_HIDE); + } + + m_dropTarget.Register(this); + + SetAlwaysOnTop(s.iOnTop); + + ShowTrayIcon(s.fTrayIcon); + + m_Lcd.SetVolumeRange(0, 100); + m_Lcd.SetVolume(std::max(1, s.nVolume)); + + m_pGraphThread = (CGraphThread*)AfxBeginThread(RUNTIME_CLASS(CGraphThread)); + + if (m_pGraphThread) { + m_pGraphThread->SetMainFrame(this); + } + + m_pSubtitlesProviders = std::make_unique(this); + m_wndSubtitlesDownloadDialog.Create(m_wndSubtitlesDownloadDialog.IDD, this, false); + //m_wndSubtitlesUploadDialog.Create(m_wndSubtitlesUploadDialog.IDD, this); + m_wndFavoriteOrganizeDialog.Create(m_wndFavoriteOrganizeDialog.IDD, this, false); + + if (s.nCmdlnWebServerPort != 0) { + if (s.nCmdlnWebServerPort > 0) { + StartWebServer(s.nCmdlnWebServerPort); + } else if (s.fEnableWebServer) { + StartWebServer(s.nWebServerPort); + } + } + + m_bToggleShader = s.bToggleShader; + m_bToggleShaderScreenSpace = s.bToggleShaderScreenSpace; + OpenSetupWindowTitle(true); + + WTSRegisterSessionNotification(); + + UpdateSkypeHandler(); + + m_popupMenu.fulfillThemeReqs(); + m_mainPopupMenu.fulfillThemeReqs(); + + if (s.bUseSMTC) { + m_media_trans_control.Init(this); + } + + return 0; +} + +void CMainFrame::CreateOSDBar() { + if (SUCCEEDED(m_OSD.Create(&m_wndView))) { + m_pOSDWnd = &m_wndView; + } +} + +bool CMainFrame::OSDBarSetPos() { + if (!m_OSD || !(::IsWindow(m_OSD.GetSafeHwnd())) || m_OSD.GetOSDType() != OSD_TYPE_GDI) { + return false; + } + const CAppSettings& s = AfxGetAppSettings(); + + if (s.iDSVideoRendererType == VIDRNDT_DS_MADVR || !m_wndView.IsWindowVisible()) { + if (m_OSD.IsWindowVisible()) { + m_OSD.ShowWindow(SW_HIDE); + } + return false; + } + + CRect r_wndView; + m_wndView.GetWindowRect(&r_wndView); + + int pos = 0; + + CRect MainWndRect; + m_wndView.GetWindowRect(&MainWndRect); + MainWndRect.right -= pos; + m_OSD.SetWndRect(MainWndRect); + if (m_OSD.IsWindowVisible()) { + ::PostMessageW(m_OSD.m_hWnd, WM_OSD_DRAW, WPARAM(0), LPARAM(0)); + } + + return false; +} + +void CMainFrame::DestroyOSDBar() { + if (m_OSD) { + m_OSD.Stop(); + m_OSD.DestroyWindow(); + } +} + +void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) +{ + if (lpMeasureItemStruct->CtlType == ODT_MENU) { + if (CMPCThemeMenu* cm = CMPCThemeMenu::getParentMenu(lpMeasureItemStruct->itemID)) { + cm->MeasureItem(lpMeasureItemStruct); + return; + } + } + + CFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct); +} + +void CMainFrame::OnDestroy() +{ + WTSUnRegisterSessionNotification(); + ShowTrayIcon(false); + m_dropTarget.Revoke(); + + if (m_pDebugShaders && IsWindow(m_pDebugShaders->m_hWnd)) { + VERIFY(m_pDebugShaders->DestroyWindow()); + } + + if (m_pGraphThread) { + CAMMsgEvent e; + m_pGraphThread->PostThreadMessage(CGraphThread::TM_EXIT, (WPARAM)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_ERROR); + } + } + + if (m_pDedicatedFSVideoWnd) { + if (m_pDedicatedFSVideoWnd->IsWindow()) { + m_pDedicatedFSVideoWnd->DestroyWindow(); + } + delete m_pDedicatedFSVideoWnd; + } + + m_wndPreView.DestroyWindow(); + + __super::OnDestroy(); +} + +void CMainFrame::OnClose() +{ + CAppSettings& s = AfxGetAppSettings(); + + s.bToggleShader = m_bToggleShader; + s.bToggleShaderScreenSpace = m_bToggleShaderScreenSpace; + s.dZoomX = m_ZoomX; + s.dZoomY = m_ZoomY; + + m_wndPlaylistBar.SavePlaylist(); + + m_controls.SaveState(); + + m_OSD.OnHide(); + + ShowWindow(SW_HIDE); + + if (GetLoadState() == MLS::LOADED || GetLoadState() == MLS::LOADING) { + CloseMedia(); + } + + m_wndPlaylistBar.ClearExternalPlaylistIfInvalid(); + + 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 + + AfxGetMyApp()->SetClosingState(); + + __super::OnClose(); +} + +LPCTSTR CMainFrame::GetRecentFile() const +{ + auto& MRU = AfxGetAppSettings().MRU; + MRU.ReadMediaHistory(); + for (int i = 0; i < MRU.GetSize(); i++) { + if (MRU[i].fns.GetCount() > 0 && !MRU[i].fns.GetHead().IsEmpty()) { + return MRU[i].fns.GetHead(); + } + } + return nullptr; +} + +LRESULT CMainFrame::OnTaskBarRestart(WPARAM, LPARAM) +{ + m_bTrayIcon = false; + ShowTrayIcon(AfxGetAppSettings().fTrayIcon); + return 0; +} + +LRESULT CMainFrame::OnNotifyIcon(WPARAM wParam, LPARAM lParam) +{ + if (HIWORD(lParam) != IDR_MAINFRAME) { + return -1; + } + + switch (LOWORD(lParam)) { + case WM_LBUTTONDOWN: + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + CreateThumbnailToolbar(); + MoveVideoWindow(); + SetForegroundWindow(); + break; + case WM_LBUTTONDBLCLK: + PostMessage(WM_COMMAND, ID_FILE_OPENMEDIA); + break; + case WM_RBUTTONDOWN: + case WM_CONTEXTMENU: { + SetForegroundWindow(); + m_mainPopupMenu.GetSubMenu(0)->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NOANIMATION, + GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam), GetModalParent()); + PostMessage(WM_NULL); + break; + } + case WM_MBUTTONDOWN: { + OnPlayPlaypause(); + break; + } + case WM_MOUSEMOVE: { + CString str; + GetWindowText(str); + SetTrayTip(str); + break; + } + default: + break; + } + + return 0; +} + +LRESULT CMainFrame::OnTaskBarThumbnailsCreate(WPARAM, LPARAM) +{ + return CreateThumbnailToolbar(); +} + +LRESULT CMainFrame::OnSkypeAttach(WPARAM wParam, LPARAM lParam) +{ + return m_pSkypeMoodMsgHandler ? m_pSkypeMoodMsgHandler->HandleAttach(wParam, lParam) : FALSE; +} + +void CMainFrame::ShowTrayIcon(bool bShow) +{ + NOTIFYICONDATA nid = { sizeof(nid), m_hWnd, IDR_MAINFRAME }; + + if (bShow) { + if (!m_bTrayIcon) { + nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; + nid.uCallbackMessage = WM_NOTIFYICON; + nid.uVersion = NOTIFYICON_VERSION_4; + nid.hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + StringCchCopy(nid.szTip, _countof(nid.szTip), _T("MPC-HC")); + if (Shell_NotifyIcon(NIM_ADD, &nid) && Shell_NotifyIcon(NIM_SETVERSION, &nid)) { + m_bTrayIcon = true; + } + } + } else { + if (m_bTrayIcon) { + Shell_NotifyIcon(NIM_DELETE, &nid); + m_bTrayIcon = false; + if (IsIconic()) { + // if the window was minimized to tray - show it + ShowWindow(SW_RESTORE); + } + } + } +} + +void CMainFrame::SetTrayTip(const CString& str) +{ + NOTIFYICONDATA tnid; + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = m_hWnd; + tnid.uID = IDR_MAINFRAME; + tnid.uFlags = NIF_TIP | NIF_SHOWTIP; + StringCchCopy(tnid.szTip, _countof(tnid.szTip), str); + Shell_NotifyIcon(NIM_MODIFY, &tnid); +} + +BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) +{ + if (!__super::PreCreateWindow(cs)) { + return FALSE; + } + + cs.dwExStyle &= ~WS_EX_CLIENTEDGE; + cs.lpszClass = MPC_WND_CLASS_NAME; //AfxRegisterWndClass(nullptr); + + return TRUE; +} + +BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->message == WM_KEYDOWN) { + if (pMsg->wParam == VK_ESCAPE) { + bool fEscapeNotAssigned = !AssignedToCmd(VK_ESCAPE); + + if (fEscapeNotAssigned) { + if (IsFullScreenMode()) { + OnViewFullscreen(); + if (GetLoadState() == MLS::LOADED) { + PostMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + return TRUE; + } else if (IsCaptionHidden()) { + PostMessage(WM_COMMAND, ID_VIEW_PRESETS_NORMAL); + return TRUE; + } + } + } else if (pMsg->wParam == VK_LEFT && m_pAMTuner) { + PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACK); + return TRUE; + } else if (pMsg->wParam == VK_RIGHT && m_pAMTuner) { + PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); + return TRUE; + } + } + + if ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_F10 && + m_dwMenuBarState == AFX_MBS_VISIBLE) { + // mfc doesn't hide menubar on f10, but we want to + VERIFY(SetMenuBarState(AFX_MBS_HIDDEN)); + return FALSE; + } + + if (pMsg->message == WM_KEYDOWN) { + m_bAltDownClean = false; + } + if (pMsg->message == WM_SYSKEYDOWN) { + m_bAltDownClean = (pMsg->wParam == VK_MENU); + } + if ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_MENU && + m_dwMenuBarState == AFX_MBS_HIDDEN) { + // mfc shows menubar when Ctrl->Alt->K is released in reverse order, but we don't want to + if (m_bAltDownClean) { + VERIFY(SetMenuBarState(AFX_MBS_VISIBLE)); + return FALSE; + } + return TRUE; + } + + // for compatibility with KatMouse and the like + if (pMsg->message == WM_MOUSEWHEEL && pMsg->hwnd == m_hWnd) { + pMsg->hwnd = m_wndView.m_hWnd; + return FALSE; + } + + return __super::PreTranslateMessage(pMsg); +} + +void CMainFrame::RecalcLayout(BOOL bNotify) +{ + __super::RecalcLayout(bNotify); + + CRect r; + GetWindowRect(&r); + MINMAXINFO mmi; + ZeroMemory(&mmi, sizeof(mmi)); + OnGetMinMaxInfo(&mmi); + const POINT& min = mmi.ptMinTrackSize; + if (r.Height() < min.y || r.Width() < min.x) { + r |= CRect(r.TopLeft(), CSize(min)); + MoveWindow(r); + } + OSDBarSetPos(); +} + +void CMainFrame::EnableDocking(DWORD dwDockStyle) +{ + ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY | CBRS_FLOAT_MULTI)) == 0); + + m_pFloatingFrameClass = RUNTIME_CLASS(CMPCThemeMiniDockFrameWnd); + for (int i = 0; i < 4; i++) { + if (dwDockBarMap[i][1] & dwDockStyle & CBRS_ALIGN_ANY) { + CMPCThemeDockBar* pDock = (CMPCThemeDockBar*)GetControlBar(dwDockBarMap[i][0]); + if (pDock == NULL) { + pDock = DEBUG_NEW CMPCThemeDockBar; + if (!pDock->Create(this, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD | WS_VISIBLE | + dwDockBarMap[i][1], dwDockBarMap[i][0])) { + AfxThrowResourceException(); + } + } + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame diagnostics + +#ifdef _DEBUG +void CMainFrame::AssertValid() const +{ + __super::AssertValid(); +} + +void CMainFrame::Dump(CDumpContext& dc) const +{ + __super::Dump(dc); +} + +#endif //_DEBUG + +typedef HIMC(WINAPI* pfnImmAssociateContext)(HWND, HIMC); +void dynImmAssociateContext(HWND hWnd, HIMC himc) { + HMODULE hImm32; + pfnImmAssociateContext pImmAssociateContext; + + hImm32 = LoadLibrary(_T("imm32.dll")); + if (NULL == hImm32) return; // No East Asian support + pImmAssociateContext = (pfnImmAssociateContext)GetProcAddress(hImm32, "ImmAssociateContext"); + if (NULL == pImmAssociateContext) { + FreeLibrary(hImm32); + return; + } + pImmAssociateContext(hWnd, himc); + FreeLibrary(hImm32); +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame message handlers +void CMainFrame::OnSetFocus(CWnd* pOldWnd) +{ + // forward focus to the view window + if (IsWindow(m_wndView.m_hWnd)) { + m_wndView.SetFocus(); + dynImmAssociateContext(m_wndView.m_hWnd, NULL); + } else { + dynImmAssociateContext(m_hWnd, NULL); + } +} + +BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) +{ + // let the view have first crack at the command + if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + + for (const auto& pair : m_controls.m_toolbars) { + if (pair.second->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + } + + for (const auto& pair : m_controls.m_panels) { + if (pair.second->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + } + + // otherwise, do default handling + return __super::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI) +{ + auto setLarger = [](long & a, long b) { + a = std::max(a, b); + }; + + const long saneSize = 110; + const bool bMenuVisible = GetMenuBarVisibility() == AFX_MBV_KEEPVISIBLE || m_bShowingFloatingMenubar; + + // Begin with docked controls + lpMMI->ptMinTrackSize = CPoint(m_controls.GetDockZonesMinSize(saneSize)); + + if (bMenuVisible) { + // Ensure that menubar will fit horizontally + MENUBARINFO mbi = { sizeof(mbi) }; + GetMenuBarInfo(OBJID_MENU, 0, &mbi); + long x = GetSystemMetrics(SM_CYMENU) / 2; // free space after menu + CRect rect; + for (int i = 0; GetMenuItemRect(m_hWnd, mbi.hMenu, i, &rect); i++) { + x += rect.Width(); + } + setLarger(lpMMI->ptMinTrackSize.x, x); + } + + if (IsWindow(m_wndToolBar) && m_controls.ControlChecked(CMainFrameControls::Toolbar::CONTROLS)) { + // Ensure that Controls toolbar will fit + setLarger(lpMMI->ptMinTrackSize.x, m_wndToolBar.GetMinWidth()); + } + + // Ensure that window decorations will fit + CRect decorationsRect; + VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), bMenuVisible, GetWindowExStyle(m_hWnd))); + lpMMI->ptMinTrackSize.x += decorationsRect.Width(); + lpMMI->ptMinTrackSize.y += decorationsRect.Height(); + + // Final fence + setLarger(lpMMI->ptMinTrackSize.x, GetSystemMetrics(SM_CXMIN)); + setLarger(lpMMI->ptMinTrackSize.y, GetSystemMetrics(SM_CYMIN)); + + lpMMI->ptMaxTrackSize.x = GetSystemMetrics(SM_CXVIRTUALSCREEN) + decorationsRect.Width(); + lpMMI->ptMaxTrackSize.y = GetSystemMetrics(SM_CYVIRTUALSCREEN) + + ((GetStyle() & WS_THICKFRAME) ? GetSystemMetrics(SM_CYSIZEFRAME) : 0); + + OSDBarSetPos(); +} + +void CMainFrame::OnMove(int x, int y) +{ + __super::OnMove(x, y); + + if (m_bWasSnapped && IsZoomed()) { + m_bWasSnapped = false; + } + + WINDOWPLACEMENT wp; + GetWindowPlacement(&wp); + if (!m_bNeedZoomAfterFullscreenExit && !m_fFullScreen && IsWindowVisible() && wp.flags != WPF_RESTORETOMAXIMIZED && wp.showCmd != SW_SHOWMINIMIZED) { + GetWindowRect(AfxGetAppSettings().rcLastWindowPos); + } + + OSDBarSetPos(); +} + +void CMainFrame::OnEnterSizeMove() +{ + if (m_bWasSnapped) { + VERIFY(GetCursorPos(&m_snapStartPoint)); + GetWindowRect(m_snapStartRect); + } +} + +void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect) +{ + if (AfxGetAppSettings().fSnapToDesktopEdges) { + const CSize threshold(m_dpi.ScaleX(16), m_dpi.ScaleY(16)); + + CRect rect(pRect); + + CRect windowRect; + GetWindowRect(windowRect); + + if (windowRect.Size() != rect.Size()) { + // aero snap + return; + } + + CPoint point; + VERIFY(GetCursorPos(&point)); + + if (m_bWasSnapped) { + rect.MoveToXY(point - m_snapStartPoint + m_snapStartRect.TopLeft()); + } + + CRect areaRect; + CMonitors::GetNearestMonitor(this).GetWorkAreaRect(areaRect); + const CRect invisibleBorderSize = GetInvisibleBorderSize(); + areaRect.InflateRect(invisibleBorderSize); + + bool bSnapping = false; + + if (std::abs(rect.left - areaRect.left) < threshold.cx) { + bSnapping = true; + rect.MoveToX(areaRect.left); + } else if (std::abs(rect.right - areaRect.right) < threshold.cx) { + bSnapping = true; + rect.MoveToX(areaRect.right - rect.Width()); + } + if (std::abs(rect.top - areaRect.top) < threshold.cy) { + bSnapping = true; + rect.MoveToY(areaRect.top); + } else if (std::abs(rect.bottom - areaRect.bottom) < threshold.cy) { + bSnapping = true; + rect.MoveToY(areaRect.bottom - rect.Height()); + } + + if (!m_bWasSnapped && bSnapping) { + m_snapStartPoint = point; + m_snapStartRect = pRect; + } + + *pRect = rect; + + m_bWasSnapped = bSnapping; + } else { + m_bWasSnapped = false; + } + + __super::OnMoving(fwSide, pRect); + OSDBarSetPos(); +} + +void CMainFrame::OnSize(UINT nType, int cx, int cy) +{ + if (m_bTrayIcon && nType == SIZE_MINIMIZED) { + ShowWindow(SW_HIDE); + } else { + __super::OnSize(nType, cx, cy); + if (!m_bNeedZoomAfterFullscreenExit && IsWindowVisible() && !m_fFullScreen) { + CAppSettings& s = AfxGetAppSettings(); + if (nType != SIZE_MAXIMIZED && nType != SIZE_MINIMIZED) { + GetWindowRect(s.rcLastWindowPos); + } + s.nLastWindowType = nType; + } + } + if (nType != SIZE_MINIMIZED) { + OSDBarSetPos(); + } +} + +void CMainFrame::OnSizing(UINT nSide, LPRECT lpRect) +{ + __super::OnSizing(nSide, lpRect); + + if (m_fFullScreen) { + return; + } + + bool bCtrl = GetKeyState(VK_CONTROL) < 0; + OnSizingFixWndToVideo(nSide, lpRect, bCtrl); + OnSizingSnapToScreen(nSide, lpRect, bCtrl); +} + +void CMainFrame::OnSizingFixWndToVideo(UINT nSide, LPRECT lpRect, bool bCtrl) +{ + const auto& s = AfxGetAppSettings(); + + if (GetLoadState() != MLS::LOADED || s.iDefaultVideoSize == DVS_STRETCH || + bCtrl == s.fLimitWindowProportions || IsAeroSnapped() || (m_fAudioOnly && !m_wndView.IsCustomImgLoaded())) { + return; + } + + CSize videoSize = m_fAudioOnly ? m_wndView.GetLogoSize() : GetVideoSize(); + if (videoSize.cx == 0 || videoSize.cy == 0) { + return; + } + + CRect currentWindowRect, currentViewRect; + GetWindowRect(currentWindowRect); + m_wndView.GetWindowRect(currentViewRect); + CSize controlsSize(currentWindowRect.Width() - currentViewRect.Width(), + currentWindowRect.Height() - currentViewRect.Height()); + + const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); + const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); + if (bPanelsOnVideo) { + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetVisibleDockZones(uTop, uLeft, uRight, uBottom); + if (!bToolbarsOnVideo) { + uBottom -= m_controls.GetVisibleToolbarsHeight(); + } + controlsSize.cx -= uLeft + uRight; + controlsSize.cy -= uTop + uBottom; + } else if (bToolbarsOnVideo) { + controlsSize.cy -= m_controls.GetVisibleToolbarsHeight(); + } + + CSize newWindowSize(lpRect->right - lpRect->left, lpRect->bottom - lpRect->top); + + newWindowSize -= controlsSize; + + switch (nSide) { + case WMSZ_TOP: + case WMSZ_BOTTOM: + newWindowSize.cx = long(newWindowSize.cy * videoSize.cx / (double)videoSize.cy + 0.5); + newWindowSize.cy = long(newWindowSize.cx * videoSize.cy / (double)videoSize.cx + 0.5); + break; + case WMSZ_TOPLEFT: + case WMSZ_TOPRIGHT: + case WMSZ_BOTTOMLEFT: + case WMSZ_BOTTOMRIGHT: + case WMSZ_LEFT: + case WMSZ_RIGHT: + newWindowSize.cy = long(newWindowSize.cx * videoSize.cy / (double)videoSize.cx + 0.5); + newWindowSize.cx = long(newWindowSize.cy * videoSize.cx / (double)videoSize.cy + 0.5); + break; + } + + newWindowSize += controlsSize; + + switch (nSide) { + case WMSZ_TOPLEFT: + lpRect->left = lpRect->right - newWindowSize.cx; + lpRect->top = lpRect->bottom - newWindowSize.cy; + break; + case WMSZ_TOP: + case WMSZ_TOPRIGHT: + lpRect->right = lpRect->left + newWindowSize.cx; + lpRect->top = lpRect->bottom - newWindowSize.cy; + break; + case WMSZ_RIGHT: + case WMSZ_BOTTOM: + case WMSZ_BOTTOMRIGHT: + lpRect->right = lpRect->left + newWindowSize.cx; + lpRect->bottom = lpRect->top + newWindowSize.cy; + break; + case WMSZ_LEFT: + case WMSZ_BOTTOMLEFT: + lpRect->left = lpRect->right - newWindowSize.cx; + lpRect->bottom = lpRect->top + newWindowSize.cy; + break; + } + OSDBarSetPos(); +} + +void CMainFrame::OnSizingSnapToScreen(UINT nSide, LPRECT lpRect, bool bCtrl /*= false*/) +{ + const auto& s = AfxGetAppSettings(); + if (!s.fSnapToDesktopEdges) + return; + + CRect areaRect; + CMonitors::GetNearestMonitor(this).GetWorkAreaRect(areaRect); + const CRect invisibleBorderSize = GetInvisibleBorderSize(); + areaRect.InflateRect(invisibleBorderSize); + + CRect& rect = *reinterpret_cast(lpRect); + const CSize threshold(m_dpi.ScaleX(16), m_dpi.ScaleY(16)); + const auto SnapTo = [](LONG& val, LONG to, LONG threshold) { + return (std::abs(val - to) < threshold && val != to) ? (val = to, true) : false; + }; + + CSize videoSize = GetVideoSize(); + + if (bCtrl == s.fLimitWindowProportions || videoSize.cx == 0 || videoSize.cy == 0) { + SnapTo(rect.left, areaRect.left, threshold.cx); + SnapTo(rect.top, areaRect.top, threshold.cy); + SnapTo(rect.right, areaRect.right, threshold.cx); + SnapTo(rect.bottom, areaRect.bottom, threshold.cy); + return; + } + + const CRect rectOrig(rect); + switch (nSide) { + case WMSZ_TOPLEFT: + if (SnapTo(rect.left, areaRect.left, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_LEFT, &rect); + rect.OffsetRect(0, rectOrig.bottom - rect.bottom); + if (rect.top < areaRect.top && SnapTo(rect.top, areaRect.top, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_TOP, &rect); + rect.OffsetRect(rectOrig.right - rect.right, 0); + } + } else if (SnapTo(rect.top, areaRect.top, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_TOP, &rect); + rect.OffsetRect(rectOrig.right - rect.right, 0); + if (rect.left < areaRect.left && SnapTo(rect.left, areaRect.left, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_LEFT, &rect); + rect.OffsetRect(0, rectOrig.bottom - rect.bottom); + } + } + break; + case WMSZ_TOP: + case WMSZ_TOPRIGHT: + if (SnapTo(rect.right, areaRect.right, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); + rect.OffsetRect(0, rectOrig.bottom - rect.bottom); + if (rect.top < areaRect.top && SnapTo(rect.top, areaRect.top, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_TOP, &rect); + rect.OffsetRect(rectOrig.left - rect.left, 0); + } + } + else if (SnapTo(rect.top, areaRect.top, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_TOP, &rect); + rect.OffsetRect(rectOrig.left - rect.left, 0); + if (areaRect.right < rect.right && SnapTo(rect.right, areaRect.right, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); + rect.OffsetRect(0, rectOrig.bottom - rect.bottom); + } + } + break; + case WMSZ_RIGHT: + case WMSZ_BOTTOM: + case WMSZ_BOTTOMRIGHT: + if (SnapTo(rect.right, areaRect.right, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); + if (areaRect.bottom < rect.bottom && SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); + } + } else if (SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); + if (areaRect.right < rect.right && SnapTo(rect.right, areaRect.right, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); + } + } + break; + case WMSZ_LEFT: + case WMSZ_BOTTOMLEFT: + if (SnapTo(rect.left, areaRect.left, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_LEFT, &rect); + if (areaRect.bottom < rect.bottom && SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); + rect.OffsetRect(rectOrig.right - rect.right, 0); + } + } else if (SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); + rect.OffsetRect(rectOrig.right - rect.right, 0); + if (rect.left < areaRect.left && SnapTo(rect.left, areaRect.left, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_LEFT, &rect); + } + } + break; + } +} + +void CMainFrame::OnExitSizeMove() +{ + if (m_wndView.Dragging()) { + // HACK: windowed (not renderless) video renderers may not produce WM_MOUSEMOVE message here + UpdateControlState(CMainFrame::UPDATE_CHILDVIEW_CURSOR_HACK); + } +} + +void CMainFrame::OnDisplayChange() // untested, not sure if it's working... +{ + TRACE(_T("*** CMainFrame::OnDisplayChange()\n")); + + if (GetLoadState() == MLS::LOADED) { + if (m_pGraphThread) { + CAMMsgEvent e; + m_pGraphThread->PostThreadMessage(CGraphThread::TM_DISPLAY_CHANGE, (WPARAM)0, (LPARAM)&e); + e.WaitMsg(); + } else { + DisplayChange(); + } + } + + if (HasDedicatedFSVideoWindow()) { + MONITORINFO MonitorInfo; + HMONITOR hMonitor; + + ZeroMemory(&MonitorInfo, sizeof(MonitorInfo)); + MonitorInfo.cbSize = sizeof(MonitorInfo); + + hMonitor = MonitorFromWindow(m_pDedicatedFSVideoWnd->m_hWnd, 0); + if (GetMonitorInfo(hMonitor, &MonitorInfo)) { + CRect MonitorRect = CRect(MonitorInfo.rcMonitor); + m_pDedicatedFSVideoWnd->SetWindowPos(nullptr, + MonitorRect.left, + MonitorRect.top, + MonitorRect.Width(), + MonitorRect.Height(), + SWP_NOZORDER); + MoveVideoWindow(); + } + } +} + +void CMainFrame::OnWindowPosChanging(WINDOWPOS* lpwndpos) +{ + if (!(lpwndpos->flags & SWP_NOMOVE) && IsFullScreenMainFrame()) { + HMONITOR hm = MonitorFromPoint(CPoint(lpwndpos->x, lpwndpos->y), MONITOR_DEFAULTTONULL); + MONITORINFO mi = { sizeof(mi) }; + if (GetMonitorInfo(hm, &mi)) { + lpwndpos->flags &= ~SWP_NOSIZE; + lpwndpos->cx = mi.rcMonitor.right - mi.rcMonitor.left; + lpwndpos->cy = mi.rcMonitor.bottom - mi.rcMonitor.top; + lpwndpos->x = mi.rcMonitor.left; + lpwndpos->y = mi.rcMonitor.top; + } + } + __super::OnWindowPosChanging(lpwndpos); +} + +LRESULT CMainFrame::OnDpiChanged(WPARAM wParam, LPARAM lParam) +{ + m_dpi.Override(LOWORD(wParam), HIWORD(wParam)); + m_eventc.FireEvent(MpcEvent::DPI_CHANGED); + CMPCThemeUtil::GetMetrics(true); //force reset metrics used by util class + CMPCThemeMenu::clearDimensions(); + ReloadMenus(); + if (!restoringWindowRect) { //do not adjust for DPI if restoring saved window position + MoveWindow(reinterpret_cast(lParam)); + } + RecalcLayout(); + m_wndPreView.ScaleFont(); + return 0; +} + +void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) +{ + // Only stop screensaver if video playing; allow for audio only + if ((GetMediaState() == State_Running && !m_fEndOfStream && !m_fAudioOnly) + && (((nID & 0xFFF0) == SC_SCREENSAVE) || ((nID & 0xFFF0) == SC_MONITORPOWER))) { + TRACE(_T("SC_SCREENSAVE, nID = %u, lParam = %d\n"), nID, lParam); + return; + } + + __super::OnSysCommand(nID, lParam); +} + +void CMainFrame::OnActivateApp(BOOL bActive, DWORD dwThreadID) +{ + __super::OnActivateApp(bActive, dwThreadID); + + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW); + + if (IsFullScreenMainFrame()) { + if (bActive) { + // keep the fullscreen window on top while it's active, + // we don't want notification pop-ups to cover it + SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } else { + // don't keep the fullscreen window on top when it's not active, + // we want to be able to switch to other windows nicely + struct { + void operator()() const { + CMainFrame* pMainFrame = AfxGetMainFrame(); + if (!pMainFrame || !pMainFrame->m_fFullScreen || pMainFrame->WindowExpectedOnTop() || pMainFrame->m_bExtOnTop) { + return; + } + // place our window under the new active window + // when we can't determine that window, we try later + if (CWnd* pActiveWnd = GetForegroundWindow()) { + bool bMoved = false; + if (CWnd* pActiveRootWnd = pActiveWnd->GetAncestor(GA_ROOT)) { + const DWORD dwStyle = pActiveRootWnd->GetStyle(); + const DWORD dwExStyle = pActiveRootWnd->GetExStyle(); + if (!(dwStyle & WS_CHILD) && !(dwStyle & WS_POPUP) && !(dwExStyle & WS_EX_TOPMOST)) { + if (CWnd* pLastWnd = GetDesktopWindow()->GetTopWindow()) { + while (CWnd* pWnd = pLastWnd->GetNextWindow(GW_HWNDNEXT)) { + if (*pLastWnd == *pActiveRootWnd) { + pMainFrame->SetWindowPos( + pWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + bMoved = true; + break; + } + pLastWnd = pWnd; + } + } else { + ASSERT(FALSE); + } + } + } + if (!bMoved) { + pMainFrame->SetWindowPos( + &wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + } else { + pMainFrame->m_timerOneTime.Subscribe( + TimerOneTimeSubscriber::PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW, *this, 1); + } + } + } placeUnder; + placeUnder(); + } + } +} + +LRESULT CMainFrame::OnAppCommand(WPARAM wParam, LPARAM lParam) +{ + UINT cmd = GET_APPCOMMAND_LPARAM(lParam); + UINT uDevice = GET_DEVICE_LPARAM(lParam); + + if (uDevice != FAPPCOMMAND_OEM && cmd != 0 + || cmd == APPCOMMAND_MEDIA_PLAY + || cmd == APPCOMMAND_MEDIA_PAUSE + || cmd == APPCOMMAND_MEDIA_CHANNEL_UP + || cmd == APPCOMMAND_MEDIA_CHANNEL_DOWN + || cmd == APPCOMMAND_MEDIA_RECORD + || cmd == APPCOMMAND_MEDIA_FAST_FORWARD + || cmd == APPCOMMAND_MEDIA_REWIND) { + const CAppSettings& s = AfxGetAppSettings(); + + BOOL fRet = FALSE; + + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + if (wc.appcmd == cmd && TRUE == SendMessage(WM_COMMAND, wc.cmd)) { + fRet = TRUE; + } + } + + if (fRet) { + return TRUE; + } + } + + return Default(); +} + +void CMainFrame::OnRawInput(UINT nInputcode, HRAWINPUT hRawInput) +{ + const CAppSettings& s = AfxGetAppSettings(); + UINT nMceCmd = AfxGetMyApp()->GetRemoteControlCode(nInputcode, hRawInput); + + switch (nMceCmd) { + case MCE_DETAILS: + case MCE_GUIDE: + case MCE_TVJUMP: + case MCE_STANDBY: + case MCE_OEM1: + case MCE_OEM2: + case MCE_MYTV: + case MCE_MYVIDEOS: + case MCE_MYPICTURES: + case MCE_MYMUSIC: + case MCE_RECORDEDTV: + case MCE_DVDANGLE: + case MCE_DVDAUDIO: + case MCE_DVDMENU: + case MCE_DVDSUBTITLE: + case MCE_RED: + case MCE_GREEN: + case MCE_YELLOW: + case MCE_BLUE: + case MCE_MEDIA_NEXTTRACK: + case MCE_MEDIA_PREVIOUSTRACK: + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + if (wc.appcmd == nMceCmd) { + SendMessage(WM_COMMAND, wc.cmd); + break; + } + } + break; + } +} + +LRESULT CMainFrame::OnHotKey(WPARAM wParam, LPARAM lParam) +{ + if (wParam == 0) { + ASSERT(false); + return FALSE; + } + + const CAppSettings& s = AfxGetAppSettings(); + BOOL fRet = FALSE; + + if (GetActiveWindow() == this || s.fGlobalMedia == TRUE) { + POSITION pos = s.wmcmds.GetHeadPosition(); + + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + if (wc.appcmd == wParam && TRUE == SendMessage(WM_COMMAND, wc.cmd)) { + fRet = TRUE; + } + } + } + + return fRet; +} + +bool g_bNoDuration = false; +bool g_bExternalSubtitleTime = false; +bool g_bExternalSubtitle = false; +double g_dRate = 1.0; + +void CMainFrame::OnTimer(UINT_PTR nIDEvent) +{ + switch (nIDEvent) { + case TIMER_WINDOW_FULLSCREEN: + if (AfxGetAppSettings().iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 + BOOL setEnabled = FALSE; + ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); + } + KillTimer(TIMER_WINDOW_FULLSCREEN); + delayingFullScreen = false; + break; + case TIMER_STREAMPOSPOLLER: + if (GetLoadState() == MLS::LOADED) { + REFERENCE_TIME rtNow = 0, rtDur = 0; + switch (GetPlaybackMode()) { + case PM_FILE: + g_bExternalSubtitleTime = false; + if (m_pGB && m_pMS) { + m_pMS->GetCurrentPosition(&rtNow); + if (!m_pGB || !m_pMS) return; // can happen very rarely due to race condition + m_pMS->GetDuration(&rtDur); + + if ((abRepeat.positionA && rtNow < abRepeat.positionA || abRepeat.positionB && rtNow >= abRepeat.positionB) && GetMediaState() != State_Stopped) { + PerformABRepeat(); + return; + } + + auto* pMRU = &AfxGetAppSettings().MRU; + if (m_bRememberFilePos && !m_fEndOfStream) { + pMRU->UpdateCurrentFilePosition(rtNow); + } + + // Casimir666 : autosave subtitle sync after play + if (m_nCurSubtitle >= 0 && m_rtCurSubPos != rtNow) { + if (m_lSubtitleShift) { + 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; + } + + m_wndStatusBar.SetStatusTimer(rtNow, rtDur, IsSubresyncBarVisible(), GetTimeFormat()); + } + break; + case PM_DVD: + 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 ? 30 / 1.001 + : 25.0; + + rtNow = HMSF2RT(Location.TimeCode, fps); + + if (abRepeat.positionB && rtNow >= abRepeat.positionB && GetMediaState() != State_Stopped) { + PerformABRepeat(); + return; + } + + DVD_HMSF_TIMECODE tcDur; + ULONG ulFlags; + if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { + rtDur = HMSF2RT(tcDur, fps); + } + if (m_pSubClock) { + m_pSubClock->SetTime(rtNow); + } + } + } + m_wndStatusBar.SetStatusTimer(rtNow, rtDur, IsSubresyncBarVisible(), GetTimeFormat()); + break; + case PM_ANALOG_CAPTURE: + g_bExternalSubtitleTime = true; + if (m_fCapturing) { + if (m_wndCaptureBar.m_capdlg.m_pMux) { + CComQIPtr pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux; + if (!pMuxMS || FAILED(pMuxMS->GetCurrentPosition(&rtNow))) { + if (m_pMS) { + m_pMS->GetCurrentPosition(&rtNow); + } + } + } + if (m_rtDurationOverride >= 0) { + rtDur = m_rtDurationOverride; + } + } + break; + case PM_DIGITAL_CAPTURE: + g_bExternalSubtitleTime = true; + m_pMS->GetCurrentPosition(&rtNow); + break; + default: + ASSERT(FALSE); + break; + } + + g_bNoDuration = rtDur <= 0; + m_wndSeekBar.Enable(!g_bNoDuration); + m_wndSeekBar.SetRange(0, rtDur); + m_wndSeekBar.SetPos(rtNow); + m_OSD.SetRange(rtDur); + m_OSD.SetPos(rtNow); + m_Lcd.SetMediaRange(0, rtDur); + m_Lcd.SetMediaPos(rtNow); + + if (m_pCAP) { + if (g_bExternalSubtitleTime) { + m_pCAP->SetTime(rtNow); + } + m_wndSubresyncBar.SetTime(rtNow); + m_wndSubresyncBar.SetFPS(m_pCAP->GetFPS()); + } + if (g_bExternalSubtitleTime && (m_iStreamPosPollerInterval > 40)) { + AdjustStreamPosPoller(true); + } + } + break; + case TIMER_STREAMPOSPOLLER2: + if (GetLoadState() == MLS::LOADED) { + switch (GetPlaybackMode()) { + case PM_FILE: + // no break + case PM_DVD: + if (AfxGetAppSettings().fShowCurrentTimeInOSD && m_OSD.CanShowMessage()) { + m_OSD.DisplayTime(m_wndStatusBar.GetStatusTimer()); + } + break; + case PM_DIGITAL_CAPTURE: { + EventDescriptor& NowNext = m_pDVBState->NowNext; + time_t tNow; + time(&tNow); + if (NowNext.duration > 0 && tNow >= NowNext.startTime && tNow <= NowNext.startTime + NowNext.duration) { + REFERENCE_TIME rtNow = REFERENCE_TIME(tNow - NowNext.startTime) * 10000000; + REFERENCE_TIME rtDur = REFERENCE_TIME(NowNext.duration) * 10000000; + m_wndStatusBar.SetStatusTimer(rtNow, rtDur, false, TIME_FORMAT_MEDIA_TIME); + if (AfxGetAppSettings().fShowCurrentTimeInOSD && m_OSD.CanShowMessage()) { + m_OSD.DisplayTime(m_wndStatusBar.GetStatusTimer()); + } + } else { + m_wndStatusBar.SetStatusTimer(ResStr(IDS_CAPTURE_LIVE)); + } + } + break; + case PM_ANALOG_CAPTURE: + if (!m_fCapturing) { + CString str(StrRes(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))) { + str.AppendFormat(_T(" (ch%ld)"), lChannel); + } + m_wndStatusBar.SetStatusTimer(str); + } + break; + default: + ASSERT(FALSE); + break; + } + } + break; + case TIMER_STATS: { + const CAppSettings& s = AfxGetAppSettings(); + if (m_wndStatsBar.IsVisible()) { + CString rate; + rate.Format(_T("%.3fx"), m_dSpeedRate); + if (m_pQP) { + CString info; + int tmp, tmp1; + + if (SUCCEEDED(m_pQP->get_AvgFrameRate(&tmp))) { // We hang here due to a lock that never gets released. + info.Format(_T("%d.%02d (%s)"), tmp / 100, tmp % 100, rate.GetString()); + } else { + info = _T("-"); + } + m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMERATE), info); + + if (SUCCEEDED(m_pQP->get_AvgSyncOffset(&tmp)) + && SUCCEEDED(m_pQP->get_DevSyncOffset(&tmp1))) { + info.Format(IDS_STATSBAR_SYNC_OFFSET_FORMAT, tmp, tmp1); + } else { + info = _T("-"); + } + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SYNC_OFFSET), info); + + if (SUCCEEDED(m_pQP->get_FramesDrawn(&tmp)) + && SUCCEEDED(m_pQP->get_FramesDroppedInRenderer(&tmp1))) { + info.Format(IDS_MAINFRM_6, tmp, tmp1); + } else { + info = _T("-"); + } + m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMES), info); + + if (SUCCEEDED(m_pQP->get_Jitter(&tmp))) { + info.Format(_T("%d ms"), tmp); + } else { + info = _T("-"); + } + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_JITTER), info); + } else { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_PLAYBACK_RATE), rate); + } + + if (m_pBI) { + CString sInfo; + + for (int i = 0, j = m_pBI->GetCount(); i < j; i++) { + int samples, size; + if (S_OK == m_pBI->GetStatus(i, samples, size) && (i < 2 || size > 0)) { // third pin is usually subs + sInfo.AppendFormat(_T("[P%d] %03d samples / %d KB "), i, samples, size / 1024); + } + } + + if (!sInfo.IsEmpty()) { + //sInfo.AppendFormat(_T("(p%lu)"), m_pBI->GetPriority()); + m_wndStatsBar.SetLine(StrRes(IDS_AG_BUFFERS), sInfo); + } + } + + { + // IBitRateInfo + CString sInfo; + BeginEnumFilters(m_pGB, pEF, pBF) { + unsigned i = 0; + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pBRI = pPin) { + DWORD nAvg = pBRI->GetAverageBitRate() / 1000; + + if (nAvg > 0) { + sInfo.AppendFormat(_T("[P%u] %lu/%lu kb/s "), i, nAvg, pBRI->GetCurrentBitRate() / 1000); + } + } + i++; + } + EndEnumPins; + + if (!sInfo.IsEmpty()) { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_BITRATE), sInfo + ResStr(IDS_STATSBAR_BITRATE_AVG_CUR)); + sInfo.Empty(); + } + } + EndEnumFilters; + } + } + + if (GetPlaybackMode() == PM_DVD) { // we also use this timer to update the info panel for DVD playback + ULONG ulAvailable, ulCurrent; + + // Location + + CString Location(_T('-')); + + 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(StrRes(IDS_INFOBAR_LOCATION), Location); + + // Video + + CString Video(_T('-')); + + 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_statusbarVideoSize.Format(_T("%dx%d"), VATR.ulSourceResolutionX, VATR.ulSourceResolutionY); + m_statusbarVideoFormat = VATR.Compression == DVD_VideoCompression_MPEG1 ? L"MPG1" : VATR.Compression == DVD_VideoCompression_MPEG2 ? L"MPG2" : L""; + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_VIDEO), Video); + + // Audio + + CString Audio(_T('-')); + + DVD_AudioAttributes AATR; + + if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulAvailable, &ulCurrent)) + && SUCCEEDED(m_pDVDI->GetAudioAttributes(ulCurrent, &AATR))) { + CString lang; + if (AATR.Language) { + GetLocaleString(AATR.Language, LOCALE_SENGLANGUAGE, lang); + currentAudioLang = lang; + } else { + lang.Format(IDS_AG_UNKNOWN, ulCurrent + 1); + currentAudioLang.Empty(); + } + + 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); + m_statusbarAudioFormat.Format(L"%s %dch", format, AATR.bNumberOfChannels); + + Audio.Format(IDS_MAINFRM_11, + lang.GetString(), + format.GetString(), + AATR.dwFrequency, + AATR.bQuantization, + AATR.bNumberOfChannels, + ResStr(AATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString()); + + m_wndStatusBar.SetStatusBitmap( + AATR.bNumberOfChannels == 1 ? IDB_AUDIOTYPE_MONO + : AATR.bNumberOfChannels >= 2 ? IDB_AUDIOTYPE_STEREO + : IDB_AUDIOTYPE_NOAUDIO); + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUDIO), Audio); + + // Subtitles + + CString Subtitles(_T('-')); + + BOOL bIsDisabled; + DVD_SubpictureAttributes SATR; + + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulAvailable, &ulCurrent, &bIsDisabled)) + && SUCCEEDED(m_pDVDI->GetSubpictureAttributes(ulCurrent, &SATR))) { + CString lang; + GetLocaleString(SATR.Language, LOCALE_SENGLANGUAGE, lang); + + 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.GetString()); + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_SUBTITLES), Subtitles); + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + if (m_pDVBState->bActive) { + CComQIPtr pTun = m_pGB; + BOOLEAN bPresent, bLocked; + LONG lDbStrength, lPercentQuality; + CString Signal; + + if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { + Signal.Format(IDS_STATSBAR_SIGNAL_FORMAT, (int)lDbStrength, lPercentQuality); + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), Signal); + } + } else { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), _T("-")); + } + } else if (GetPlaybackMode() == PM_FILE) { + OpenSetupInfoBar(false); + if (s.iTitleBarTextStyle == 1 && s.fTitleBarTextTitle) { + OpenSetupWindowTitle(); + } + MediaTransportControlSetMedia(); + SendNowPlayingToSkype(); + SendNowPlayingToApi(false); + } + + if (m_CachedFilterState == State_Running && !m_fAudioOnly) { + if (s.bPreventDisplaySleep) { + BOOL fActive = FALSE; + if (SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fActive, 0) && fActive) { + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, nullptr, SPIF_SENDWININICHANGE); + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, fActive, nullptr, SPIF_SENDWININICHANGE); + } + + // prevent screensaver activate, monitor sleep/turn off after playback + SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); + } + } + } + break; + case TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS: { + if (GetPlaybackMode() == PM_NONE) { + if (UnloadUnusedExternalObjects()) { + KillTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS); + } + } + } + break; + case TIMER_HIDER: + m_timerHider.NotifySubscribers(); + break; + case TIMER_DELAYEDSEEK: + KillTimer(TIMER_DELAYEDSEEK); + if (queuedSeek.seekTime > 0) { + SeekTo(queuedSeek.rtPos, queuedSeek.bShowOSD); + } + break; + default: + if (nIDEvent >= TIMER_ONETIME_START && nIDEvent <= TIMER_ONETIME_END) { + m_timerOneTime.NotifySubscribers(nIDEvent); + } else { + ASSERT(FALSE); + } + } + + __super::OnTimer(nIDEvent); +} + +void CMainFrame::DoAfterPlaybackEvent() +{ + CAppSettings& s = AfxGetAppSettings(); + bool bExitFullScreen = false; + bool bNoMoreMedia = false; + + if (s.nCLSwitches & CLSW_DONOTHING) { + // Do nothing + } else if (s.nCLSwitches & CLSW_CLOSE) { + SendMessage(WM_COMMAND, ID_FILE_EXIT); + } else if (s.nCLSwitches & CLSW_MONITOROFF) { + m_fEndOfStream = true; + bExitFullScreen = true; + SetThreadExecutionState(ES_CONTINUOUS); + SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, 2); + } else if (s.nCLSwitches & CLSW_STANDBY) { + SetPrivilege(SE_SHUTDOWN_NAME); + SetSystemPowerState(TRUE, FALSE); + SendMessage(WM_COMMAND, ID_FILE_EXIT); // Recheck if this is still needed after switching to new toolset and SetSuspendState() + } else if (s.nCLSwitches & CLSW_HIBERNATE) { + SetPrivilege(SE_SHUTDOWN_NAME); + SetSystemPowerState(FALSE, FALSE); + SendMessage(WM_COMMAND, ID_FILE_EXIT); + } else if (s.nCLSwitches & CLSW_SHUTDOWN) { + SetPrivilege(SE_SHUTDOWN_NAME); + InitiateSystemShutdownEx(nullptr, nullptr, 0, TRUE, FALSE, + SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE | SHTDN_REASON_FLAG_PLANNED); + SendMessage(WM_COMMAND, ID_FILE_EXIT); + } else if (s.nCLSwitches & CLSW_LOGOFF) { + SetPrivilege(SE_SHUTDOWN_NAME); + ExitWindowsEx(EWX_LOGOFF | EWX_FORCEIFHUNG, 0); + SendMessage(WM_COMMAND, ID_FILE_EXIT); + } else if (s.nCLSwitches & CLSW_LOCK) { + m_fEndOfStream = true; + bExitFullScreen = true; + LockWorkStation(); + } else if (s.nCLSwitches & CLSW_PLAYNEXT) { + if (!SearchInDir(true, (s.fLoopForever || m_nLoops < s.nLoops || s.bLoopFolderOnPlayNextFile))) { + m_fEndOfStream = true; + bExitFullScreen = true; + bNoMoreMedia = true; + } + } else { + // remembered after playback events + switch (s.eAfterPlayback) { + case CAppSettings::AfterPlayback::PLAY_NEXT: + if (m_wndPlaylistBar.GetCount() < 2) { // ignore global PLAY_NEXT in case of a playlist + if (!SearchInDir(true, s.bLoopFolderOnPlayNextFile)) { + SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); + } + } + break; + case CAppSettings::AfterPlayback::REWIND: + bExitFullScreen = true; + if (m_wndPlaylistBar.GetCount() > 1) { + s.nCLSwitches |= CLSW_OPEN; + PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); + } else { + SendMessage(WM_COMMAND, ID_PLAY_STOP); + } + break; + case CAppSettings::AfterPlayback::MONITOROFF: + m_fEndOfStream = true; + bExitFullScreen = true; + SetThreadExecutionState(ES_CONTINUOUS); + SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, 2); + break; + case CAppSettings::AfterPlayback::CLOSE: + SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); + break; + case CAppSettings::AfterPlayback::EXIT: + SendMessage(WM_COMMAND, ID_FILE_EXIT); + break; + default: + m_fEndOfStream = true; + bExitFullScreen = true; + break; + } + } + + if (AfxGetMyApp()->m_fClosingState) { + return; + } + + if (m_fEndOfStream) { + m_OSD.EnableShowMessage(false); + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + m_OSD.EnableShowMessage(); + if (bNoMoreMedia) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_NO_MORE_MEDIA)); + } + } + + if (bExitFullScreen && (IsFullScreenMode()) && s.fExitFullScreenAtTheEnd) { + OnViewFullscreen(); + } +} + +void CMainFrame::OnUpdateABRepeat(CCmdUI* pCmdUI) { + bool canABRepeat = GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD; + bool abRepeatActive = static_cast(abRepeat); + + switch (pCmdUI->m_nID) { + case ID_PLAY_REPEAT_AB: + pCmdUI->Enable(canABRepeat && abRepeatActive); + break; + case ID_PLAY_REPEAT_AB_MARK_A: + if (pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuItem(ID_PLAY_REPEAT_AB_MARK_A, MF_BYCOMMAND | (abRepeat.positionA ? MF_CHECKED : MF_UNCHECKED)); + } + pCmdUI->Enable(canABRepeat); + break; + case ID_PLAY_REPEAT_AB_MARK_B: + if (pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuItem(ID_PLAY_REPEAT_AB_MARK_B, MF_BYCOMMAND | (abRepeat.positionB ? MF_CHECKED : MF_UNCHECKED)); + } + pCmdUI->Enable(canABRepeat); + break; + default: + ASSERT(FALSE); + return; + } +} + + +void CMainFrame::OnABRepeat(UINT nID) { + switch (nID) { + case ID_PLAY_REPEAT_AB: + if (abRepeat) { //only support disabling from the menu + DisableABRepeat(); + } + break; + case ID_PLAY_REPEAT_AB_MARK_A: + case ID_PLAY_REPEAT_AB_MARK_B: + REFERENCE_TIME rtDur = 0; + int playmode = GetPlaybackMode(); + + bool havePos = false; + REFERENCE_TIME pos = 0; + + if (playmode == PM_FILE && m_pMS) { + m_pMS->GetDuration(&rtDur); + havePos = SUCCEEDED(m_pMS->GetCurrentPosition(&pos)); + } else if (playmode == PM_DVD && 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 ? 30 / 1.001 + : 25.0; + DVD_HMSF_TIMECODE tcDur; + ULONG ulFlags; + if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { + rtDur = HMSF2RT(tcDur, fps); + } + havePos = true; + pos = HMSF2RT(Location.TimeCode, fps); + abRepeat.dvdTitle = m_iDVDTitle; //we only support one title. so if they clear or set, we will remember the current title + } + } else { + return; + } + + if (nID == ID_PLAY_REPEAT_AB_MARK_A) { + if (abRepeat.positionA) { + abRepeat.positionA = 0; + } else if (havePos) { + abRepeat.positionA = pos; + if (abRepeat.positionA < rtDur) { + if (abRepeat.positionB && abRepeat.positionA >= abRepeat.positionB) { + abRepeat.positionB = 0; + } + } else { + abRepeat.positionA = 0; + } + } + } else if (nID == ID_PLAY_REPEAT_AB_MARK_B) { + if (abRepeat.positionB) { + abRepeat.positionB = 0; + } else if (havePos) { + abRepeat.positionB = pos; + if (abRepeat.positionB > 0 && abRepeat.positionB > abRepeat.positionA && rtDur >= abRepeat.positionB) { + if (GetMediaState() == State_Running) { + PerformABRepeat(); //we just set loop point B, so we need to repeat right now + } + } else { + abRepeat.positionB = 0; + } + } + } + + auto pMRU = &AfxGetAppSettings().MRU; + pMRU->UpdateCurrentABRepeat(abRepeat); + + m_wndSeekBar.Invalidate(); + break; + } +} + +void CMainFrame::PerformABRepeat() { + DoSeekTo(abRepeat.positionA, false); + + if (GetMediaState() == State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } +} + +void CMainFrame::DisableABRepeat() { + abRepeat = ABRepeat(); + + auto* pMRU = &AfxGetAppSettings().MRU; + pMRU->UpdateCurrentABRepeat(abRepeat); + + m_wndSeekBar.Invalidate(); +} + +bool CMainFrame::CheckABRepeat(REFERENCE_TIME& aPos, REFERENCE_TIME& bPos) { + if (GetPlaybackMode() == PM_FILE || (GetPlaybackMode() == PM_DVD && m_iDVDTitle == abRepeat.dvdTitle)) { + if (abRepeat) { + aPos = abRepeat.positionA; + bPos = abRepeat.positionB; + return true; + } + } + return false; +} + + +// +// graph event EC_COMPLETE handler +// +void CMainFrame::GraphEventComplete() +{ + CAppSettings& s = AfxGetAppSettings(); + + auto* pMRU = &s.MRU; + + + if (m_bRememberFilePos) { + pMRU->UpdateCurrentFilePosition(0, true); + } + + bool bBreak = false; + if (m_wndPlaylistBar.IsAtEnd() || s.eLoopMode == CAppSettings::LoopMode::FILE) { + ++m_nLoops; + bBreak = !!(s.nCLSwitches & CLSW_AFTERPLAYBACK_MASK); + } + + if (abRepeat) { + PerformABRepeat(); + } else if (s.fLoopForever || m_nLoops < s.nLoops) { + if (bBreak) { + DoAfterPlaybackEvent(); + } else if ((m_wndPlaylistBar.GetCount() > 1) && (s.eLoopMode == CAppSettings::LoopMode::PLAYLIST)) { + int nLoops = m_nLoops; + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARDFILE); + m_nLoops = nLoops; + } else { + if (GetMediaState() == State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } else if (m_pMS) { + REFERENCE_TIME rtDur = 0; + if ((m_pMS->GetDuration(&rtDur) == S_OK) && (rtDur >= 1000000LL) || !IsImageFile(lastOpenFile)) { // repeating still image is pointless and can cause player UI to freeze + REFERENCE_TIME rtPos = 0; + m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + if (GetMediaState() == State_Paused) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + } + } + } + } else { + DoAfterPlaybackEvent(); + } +} + +// +// our WM_GRAPHNOTIFY handler +// + +LRESULT CMainFrame::OnGraphNotify(WPARAM wParam, LPARAM lParam) +{ + CAppSettings& s = AfxGetAppSettings(); + HRESULT hr = S_OK; + + LONG evCode = 0; + LONG_PTR evParam1, evParam2; + while (!AfxGetMyApp()->m_fClosingState && m_pME && SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) { +#ifdef _DEBUG + if (evCode != EC_DVD_CURRENT_HMSF_TIME) { + TRACE(_T("--> CMainFrame::OnGraphNotify on thread: %lu; event: 0x%08x (%ws)\n"), GetCurrentThreadId(), evCode, GetEventString(evCode)); + } +#endif + CString str; + if (m_fCustomGraph) { + if (EC_BG_ERROR == evCode) { + str = CString((char*)evParam1); + } + } + hr = m_pME->FreeEventParams(evCode, evParam1, evParam2); + + switch (evCode) { + case EC_PAUSED: + if (GetLoadState() == MLS::LOADED) { + UpdateCachedMediaState(); + } + if (m_audioTrackCount > 1 && GetLoadState() == MLS::LOADED) { + CheckSelectedAudioStream(); + } + break; + case EC_COMPLETE: + UpdateCachedMediaState(); + GraphEventComplete(); + break; + case EC_ERRORABORT: + UpdateCachedMediaState(); + TRACE(_T("\thr = %08x\n"), (HRESULT)evParam1); + break; + case EC_BUFFERING_DATA: + TRACE(_T("\tBuffering data = %s\n"), evParam1 ? _T("true") : _T("false")); + m_bBuffering = !!evParam1; + break; + case EC_STEP_COMPLETE: + if (m_fFrameSteppingActive) { + m_nStepForwardCount++; + } + UpdateCachedMediaState(); + break; + case EC_DEVICE_LOST: + UpdateCachedMediaState(); + if (evParam2 == 0) { + // Device lost + if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + CComQIPtr pBF = (IUnknown*)evParam1; + if (!m_pVidCap && m_pVidCap == pBF || !m_pAudCap && m_pAudCap == pBF) { + SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); + } + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); + } + } + break; + case EC_DVD_TITLE_CHANGE: { + if (GetPlaybackMode() == PM_FILE) { + SetupChapters(); + } else if (GetPlaybackMode() == PM_DVD) { + m_iDVDTitle = (DWORD)evParam1; + + if (m_iDVDDomain == DVD_DOMAIN_Title) { + CString Domain; + Domain.Format(IDS_AG_TITLE, m_iDVDTitle); + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), Domain); + } + + SetupDVDChapters(); + } + } + break; + case EC_DVD_DOMAIN_CHANGE: { + m_iDVDDomain = (DVD_DOMAIN)evParam1; + + OpenDVDData* pDVDData = dynamic_cast(m_lastOMD.m_p); + ASSERT(pDVDData); + + CString Domain(_T('-')); + + switch (m_iDVDDomain) { + case DVD_DOMAIN_FirstPlay: + ULONGLONG llDVDGuid; + + Domain = _T("First Play"); + + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDiscID(nullptr, &llDVDGuid))) { + m_fValidDVDOpen = true; + + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("DVD Title: %lu"), s.lDVDTitle); + } + + if (s.lDVDTitle != 0) { + // Set command line position + hr = m_pDVDC->PlayTitle(s.lDVDTitle, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayTitle: 0x%08X"), hr); + m_OSD.DebugMessage(_T("DVD Chapter: %lu"), s.lDVDChapter); + } + + if (s.lDVDChapter > 1) { + hr = m_pDVDC->PlayChapterInTitle(s.lDVDTitle, s.lDVDChapter, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayChapterInTitle: 0x%08X"), hr); + } + } else { + // Trick: skip trailers with some DVDs + hr = m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("Resume: 0x%08X"), hr); + } + + // If the resume call succeeded, then we skip PlayChapterInTitle + // and PlayAtTimeInTitle. + if (hr == S_OK) { + // This might fail if the Title is not available yet? + hr = m_pDVDC->PlayAtTime(&s.DVDPosition, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayAtTime: 0x%08X"), hr); + } + } else { + if (s.fShowDebugInfo) + m_OSD.DebugMessage(_T("Timecode requested: %02d:%02d:%02d.%03d"), + s.DVDPosition.bHours, s.DVDPosition.bMinutes, + s.DVDPosition.bSeconds, s.DVDPosition.bFrames); + + // Always play chapter 1 (for now, until something else dumb happens) + hr = m_pDVDC->PlayChapterInTitle(s.lDVDTitle, 1, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayChapterInTitle: 0x%08X"), hr); + } + + // This might fail if the Title is not available yet? + hr = m_pDVDC->PlayAtTime(&s.DVDPosition, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayAtTime: 0x%08X"), hr); + } + + if (hr != S_OK) { + hr = m_pDVDC->PlayAtTimeInTitle(s.lDVDTitle, &s.DVDPosition, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayAtTimeInTitle: 0x%08X"), hr); + } + } + } // Resume + + hr = m_pDVDC->PlayAtTime(&s.DVDPosition, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayAtTime: %d"), hr); + } + } + + m_iDVDTitle = s.lDVDTitle; + s.lDVDTitle = 0; + s.lDVDChapter = 0; + } else if (pDVDData && pDVDData->pDvdState) { + // Set position from favorite + VERIFY(SUCCEEDED(m_pDVDC->SetState(pDVDData->pDvdState, DVD_CMD_FLAG_Block, nullptr))); + // We don't want to restore the position from the favorite + // if the playback is reinitialized so we clear the saved state + pDVDData->pDvdState.Release(); + } else if (s.fKeepHistory && s.fRememberDVDPos && s.MRU.GetCurrentDVDPosition().llDVDGuid) { + // Set last remembered position (if found...) + DVD_POSITION dvdPosition = s.MRU.GetCurrentDVDPosition(); + + hr = m_pDVDC->PlayTitle(dvdPosition.lTitle, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + TRACE(_T("Failed to set remembered DVD title index, hr = 0x%08X"), hr); + } else { + m_iDVDTitle = dvdPosition.lTitle; + + if (dvdPosition.timecode.bSeconds > 0 || dvdPosition.timecode.bMinutes > 0 || dvdPosition.timecode.bHours > 0 || dvdPosition.timecode.bFrames > 0) { +#if 0 + hr = m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + TRACE(_T("Failed to set remembered DVD resume flags, hr = 0x%08X"), hr); + } +#endif +#if 0 + hr = m_pDVDC->PlayAtTimeInTitle(dvdPosition.lTitle, &dvdPosition.timecode, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); +#else + hr = m_pDVDC->PlayAtTime(&dvdPosition.timecode, DVD_CMD_FLAG_Flush, nullptr); +#endif + } + + ABRepeat tmp = s.MRU.GetCurrentABRepeat(); + if (tmp.dvdTitle == m_iDVDTitle) { + abRepeat = tmp; + m_wndSeekBar.Invalidate(); + } + } + } + + if (s.fRememberZoomLevel && !IsFullScreenMode() && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { // Hack to the normal initial zoom for DVD + DXVA ... + ZoomVideoWindow(); + } + } + break; + case DVD_DOMAIN_VideoManagerMenu: + Domain = _T("Video Manager Menu"); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + break; + case DVD_DOMAIN_VideoTitleSetMenu: + Domain = _T("Video Title Set Menu"); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + break; + case DVD_DOMAIN_Title: + Domain.Format(IDS_AG_TITLE, m_iDVDTitle); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + if (s.fKeepHistory && s.fRememberDVDPos) { + s.MRU.UpdateCurrentDVDTitle(m_iDVDTitle); + } + if (!m_fValidDVDOpen && m_pDVDC) { + m_fValidDVDOpen = true; + m_pDVDC->ShowMenu(DVD_MENU_Title, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + } + break; + case DVD_DOMAIN_Stop: + Domain.LoadString(IDS_AG_STOP); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + break; + default: + Domain = _T("-"); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + break; + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), Domain); + + if (GetPlaybackMode() == PM_FILE) { + SetupChapters(); + } else if (GetPlaybackMode() == PM_DVD) { + SetupDVDChapters(); + } + +#if 0 // UOPs debug traces + if (hr == VFW_E_DVD_OPERATION_INHIBITED) { + ULONG UOPfields = 0; + pDVDI->GetCurrentUOPS(&UOPfields); + CString message; + message.Format(_T("UOP bitfield: 0x%08X; domain: %s"), UOPfields, Domain); + m_OSD.DisplayMessage(OSD_TOPLEFT, message); + } else { + m_OSD.DisplayMessage(OSD_TOPRIGHT, Domain); + } +#endif + + MoveVideoWindow(); // AR might have changed + } + break; + case EC_DVD_CURRENT_HMSF_TIME: { + s.MRU.UpdateCurrentDVDTimecode((DVD_HMSF_TIMECODE*)&evParam1); + } + break; + case EC_DVD_ERROR: { + TRACE(_T("\t%I64d %Id\n"), evParam1, evParam2); + + UINT err; + + switch (evParam1) { + case DVD_ERROR_Unexpected: + default: + err = IDS_MAINFRM_16; + break; + case DVD_ERROR_CopyProtectFail: + err = IDS_MAINFRM_17; + break; + case DVD_ERROR_InvalidDVD1_0Disc: + err = IDS_MAINFRM_18; + break; + case DVD_ERROR_InvalidDiscRegion: + err = IDS_MAINFRM_19; + break; + case DVD_ERROR_LowParentalLevel: + err = IDS_MAINFRM_20; + break; + case DVD_ERROR_MacrovisionFail: + err = IDS_MAINFRM_21; + break; + case DVD_ERROR_IncompatibleSystemAndDecoderRegions: + err = IDS_MAINFRM_22; + break; + case DVD_ERROR_IncompatibleDiscAndDecoderRegions: + err = IDS_MAINFRM_23; + break; + } + + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + m_closingmsg.LoadString(err); + } + break; + case EC_DVD_WARNING: + TRACE(_T("\t%Id %Id\n"), evParam1, evParam2); + break; + case EC_VIDEO_SIZE_CHANGED: { + CSize size((DWORD)evParam1); + TRACE(_T("\t%ldx%ld\n"), size.cx, size.cy); + const bool bWasAudioOnly = m_fAudioOnly; + m_fAudioOnly = (size.cx <= 0 || size.cy <= 0); + OnVideoSizeChanged(bWasAudioOnly); + } + break; + case EC_LENGTH_CHANGED: { + REFERENCE_TIME rtDur = 0; + m_pMS->GetDuration(&rtDur); + m_wndPlaylistBar.SetCurTime(rtDur); + OnTimer(TIMER_STREAMPOSPOLLER); + OnTimer(TIMER_STREAMPOSPOLLER2); + LoadKeyFrames(); + if (GetPlaybackMode() == PM_FILE) { + SetupChapters(); + } else if (GetPlaybackMode() == PM_DVD) { + SetupDVDChapters(); + } + } + break; + case EC_BG_AUDIO_CHANGED: + if (m_fCustomGraph) { + int nAudioChannels = (int)evParam1; + + m_wndStatusBar.SetStatusBitmap(nAudioChannels == 1 ? IDB_AUDIOTYPE_MONO + : nAudioChannels >= 2 ? IDB_AUDIOTYPE_STEREO + : IDB_AUDIOTYPE_NOAUDIO); + } + break; + case EC_BG_ERROR: + if (m_fCustomGraph) { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + m_closingmsg = !str.IsEmpty() ? str : CString(_T("Unspecified graph error")); + m_wndPlaylistBar.SetCurValid(false); + return hr; + } + break; + case EC_DVD_PLAYBACK_RATE_CHANGE: + if (m_fCustomGraph && s.autoChangeFSMode.bEnabled && + (IsFullScreenMode()) && m_iDVDDomain == DVD_DOMAIN_Title) { + AutoChangeMonitorMode(); + } + break; + case EC_CLOCK_CHANGED: + if (m_pBA && !m_fFrameSteppingActive) { + m_pBA->put_Volume(m_wndToolBar.Volume); + } + break; + case 0xfa17: + // madVR changed graph state + UpdateCachedMediaState(); + break; + case EC_DVD_STILL_ON: + m_bDVDStillOn = true; + break; + case EC_DVD_STILL_OFF: + m_bDVDStillOn = false; + break; + case EC_DVD_BUTTON_CHANGE: + case EC_DVD_SUBPICTURE_STREAM_CHANGE: + case EC_DVD_AUDIO_STREAM_CHANGE: + case EC_DVD_ANGLE_CHANGE: + case EC_DVD_VALID_UOPS_CHANGE: + case EC_DVD_CHAPTER_START: + // no action required + break; + default: + UpdateCachedMediaState(); + TRACE(_T("Unhandled graph event\n")); + } + } + + return hr; +} + +LRESULT CMainFrame::OnResetDevice(WPARAM wParam, LPARAM lParam) +{ + m_OSD.HideMessage(true); + + OAFilterState fs = GetMediaState(); + if (fs == State_Running) { + if (!IsPlaybackCaptureMode()) { + MediaControlPause(true); + } else { + MediaControlStop(true); // Capture mode doesn't support pause + } + } + + if (m_bOpenedThroughThread) { + CAMMsgEvent e; + m_pGraphThread->PostThreadMessage(CGraphThread::TM_RESET, (WPARAM)0, (LPARAM)&e); + e.WaitMsg(); + } else { + ResetDevice(); + } + + if (fs == State_Running && m_pMC) { + MediaControlRun(); + + // When restarting DVB capture, we need to set again the channel. + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + SetChannel(AfxGetAppSettings().nDVBLastChannel); + } + } + } + + if (m_OSD.CanShowMessage()) { + m_OSD.HideMessage(false); + } + + return S_OK; +} + +LRESULT CMainFrame::OnRepaintRenderLess(WPARAM wParam, LPARAM lParam) +{ + MoveVideoWindow(); + return TRUE; +} + +void CMainFrame::SaveAppSettings() +{ + MSG msg; + if (!PeekMessage(&msg, m_hWnd, WM_SAVESETTINGS, WM_SAVESETTINGS, PM_NOREMOVE | PM_NOYIELD)) { + AfxGetAppSettings().SaveSettings(); + } +} + +LRESULT CMainFrame::OnNcHitTest(CPoint point) +{ + LRESULT nHitTest = __super::OnNcHitTest(point); + return ((IsCaptionHidden()) && nHitTest == HTCLIENT) ? HTCAPTION : nHitTest; +} + +void CMainFrame::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + // pScrollBar is null when making horizontal scroll with pen tablet + if (!pScrollBar) return; + + if (pScrollBar->IsKindOf(RUNTIME_CLASS(CVolumeCtrl))) { + OnPlayVolume(0); + } else if (pScrollBar->IsKindOf(RUNTIME_CLASS(CPlayerSeekBar)) && GetLoadState() == MLS::LOADED) { + SeekTo(m_wndSeekBar.GetPos()); + } else if (*pScrollBar == *m_pVideoWnd) { + SeekTo(m_OSD.GetPos()); + } + + __super::OnHScroll(nSBCode, nPos, pScrollBar); +} + +void CMainFrame::RestoreFocus() { + CWnd* curFocus = GetFocus(); + if (curFocus && curFocus != this) { + SetFocus(); + } +} + +void CMainFrame::OnInitMenu(CMenu* pMenu) +{ + __super::OnInitMenu(pMenu); + RestoreFocus(); + + const UINT uiMenuCount = pMenu->GetMenuItemCount(); + if (uiMenuCount == -1) { + return; + } + + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + + for (UINT i = 0; i < uiMenuCount; ++i) { +#ifdef _DEBUG + CString str; + pMenu->GetMenuString(i, str, MF_BYPOSITION); + str.Remove('&'); +#endif + UINT itemID = pMenu->GetMenuItemID(i); + if (itemID == 0xFFFFFFFF) { + mii.fMask = MIIM_ID; + pMenu->GetMenuItemInfo(i, &mii, TRUE); + itemID = mii.wID; + } + + CMPCThemeMenu* pSubMenu = nullptr; + + if (itemID == ID_FAVORITES) { + SetupFavoritesSubMenu(); + pSubMenu = &m_favoritesMenu; + }/*else if (itemID == ID_RECENT_FILES) { + SetupRecentFilesSubMenu(); + pSubMenu = &m_recentFilesMenu; + }*/ + + if (pSubMenu) { + mii.fMask = MIIM_STATE | MIIM_SUBMENU; + mii.fState = (pSubMenu->GetMenuItemCount()) > 0 ? MFS_ENABLED : MFS_DISABLED; + mii.hSubMenu = *pSubMenu; + VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pMenu, i, &mii, TRUE)); + pSubMenu->fulfillThemeReqs(); + } + } +} + +void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) { + __super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu); + + if (bSysMenu) { + m_pActiveSystemMenu = pPopupMenu; + m_eventc.FireEvent(MpcEvent::SYSTEM_MENU_POPUP_INITIALIZED); + return; + } + + UINT uiMenuCount = pPopupMenu->GetMenuItemCount(); + if (uiMenuCount == -1) { + return; + } + + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + + for (UINT i = 0; i < uiMenuCount; ++i) { +#ifdef _DEBUG + CString str; + pPopupMenu->GetMenuString(i, str, MF_BYPOSITION); + str.Remove('&'); +#endif + UINT firstSubItemID = 0; + CMenu* sm = pPopupMenu->GetSubMenu(i); + if (sm) { + firstSubItemID = sm->GetMenuItemID(0); + } + + if (firstSubItemID == ID_NAVIGATE_SKIPBACK) { // is "Navigate" submenu { + UINT fState = (GetLoadState() == MLS::LOADED + && (1/*GetPlaybackMode() == PM_DVD *//*|| (GetPlaybackMode() == PM_FILE && !m_PlayList.IsEmpty())*/)) + ? MF_ENABLED + : MF_GRAYED; + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + if (firstSubItemID == ID_VIEW_VF_HALF // is "Video Frame" submenu + || firstSubItemID == ID_VIEW_INCSIZE // is "Pan&Scan" submenu + || firstSubItemID == ID_ASPECTRATIO_START // is "Override Aspect Ratio" submenu + || firstSubItemID == ID_VIEW_ZOOM_25) { // is "Zoom" submenu + UINT fState = (GetLoadState() == MLS::LOADED && !m_fAudioOnly) + ? MF_ENABLED + : MF_GRAYED; + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + + // "File -> Subtitles" submenu + if (firstSubItemID == ID_FILE_SUBTITLES_LOAD) { + UINT fState = (GetLoadState() == MLS::LOADED && !m_fAudioOnly && m_pCAP) + ? MF_ENABLED + : MF_GRAYED; + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + + // renderer settings + if (firstSubItemID == ID_VIEW_TEARING_TEST) { + UINT fState = MF_GRAYED; + const CAppSettings& s = AfxGetAppSettings(); + if (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC || s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS) { + fState = MF_ENABLED; + } + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + + UINT itemID = pPopupMenu->GetMenuItemID(i); + if (itemID == 0xFFFFFFFF) { + mii.fMask = MIIM_ID; + VERIFY(pPopupMenu->GetMenuItemInfo(i, &mii, TRUE)); + itemID = mii.wID; + } + CMPCThemeMenu* pSubMenu = nullptr; + + // debug shaders + if (itemID == ID_VIEW_DEBUGSHADERS) { + UINT fState = MF_GRAYED; + if (GetLoadState() == MLS::LOADED && !m_fAudioOnly && m_pCAP2) { + fState = MF_ENABLED; + } + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + + if (itemID == ID_FILE_OPENDISC) { + SetupOpenCDSubMenu(); + pSubMenu = &m_openCDsMenu; + } else if (itemID == ID_FILTERS) { + SetupFiltersSubMenu(); + pSubMenu = &m_filtersMenu; + } else if (itemID == ID_AUDIOS) { + SetupAudioSubMenu(); + pSubMenu = &m_audiosMenu; + } else if (itemID == ID_SUBTITLES) { + SetupSubtitlesSubMenu(); + pSubMenu = &m_subtitlesMenu; + } else if (itemID == ID_VIDEO_STREAMS) { + CString menuStr; + menuStr.LoadString(GetPlaybackMode() == PM_DVD ? IDS_MENU_VIDEO_ANGLE : IDS_MENU_VIDEO_STREAM); + + mii.fMask = MIIM_STRING; + mii.dwTypeData = (LPTSTR)(LPCTSTR)menuStr; + VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pPopupMenu, i, &mii, TRUE)); + + SetupVideoStreamsSubMenu(); + pSubMenu = &m_videoStreamsMenu; + } else if (itemID == ID_NAVIGATE_GOTO) { + // ID_NAVIGATE_GOTO is just a marker we use to insert the appropriate submenus + SetupJumpToSubMenus(pPopupMenu, i + 1); + uiMenuCount = pPopupMenu->GetMenuItemCount(); //SetupJumpToSubMenus could actually reduce the menu count! + } else if (itemID == ID_FAVORITES) { + SetupFavoritesSubMenu(); + pSubMenu = &m_favoritesMenu; + } else if (itemID == ID_RECENT_FILES) { + SetupRecentFilesSubMenu(); + pSubMenu = &m_recentFilesMenu; + } else if (itemID == ID_SHADERS) { + if (SetupShadersSubMenu()) { + pPopupMenu->EnableMenuItem(ID_SHADERS, MF_BYPOSITION | MF_ENABLED); + } else { + pPopupMenu->EnableMenuItem(ID_SHADERS, MF_BYPOSITION | MF_GRAYED); + } + pSubMenu = &m_shadersMenu; + } + + if (pSubMenu) { + mii.fMask = MIIM_STATE | MIIM_SUBMENU; + mii.fState = (pSubMenu->GetMenuItemCount() > 0) ? MF_ENABLED : MF_GRAYED; + mii.hSubMenu = *pSubMenu; + VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pPopupMenu, i, &mii, TRUE)); + pSubMenu->fulfillThemeReqs(); + } + } + + uiMenuCount = pPopupMenu->GetMenuItemCount(); + if (uiMenuCount == -1) { + return; + } + + if (!AppIsThemeLoaded()) { //themed menus draw accelerators already, no need to append + for (UINT i = 0; i < uiMenuCount; ++i) { + UINT nID = pPopupMenu->GetMenuItemID(i); + if (nID == ID_SEPARATOR || nID == -1 + || nID >= ID_FAVORITES_FILE_START && nID <= ID_FAVORITES_FILE_END + || nID >= ID_RECENT_FILE_START && nID <= ID_RECENT_FILE_END + || nID >= ID_SUBTITLES_SUBITEM_START && nID <= ID_SUBTITLES_SUBITEM_END + || nID >= ID_NAVIGATE_JUMPTO_SUBITEM_START && nID <= ID_NAVIGATE_JUMPTO_SUBITEM_END) { + continue; + } + + CString str; + pPopupMenu->GetMenuString(i, str, MF_BYPOSITION); + int k = str.Find('\t'); + if (k > 0) { + str = str.Left(k); + } + + CString key = CPPageAccelTbl::MakeAccelShortcutLabel(nID); + if (key.IsEmpty() && k < 0) { + continue; + } + str += _T("\t") + key; + + // BUG(?): this disables menu item update ui calls for some reason... + //pPopupMenu->ModifyMenu(i, MF_BYPOSITION|MF_STRING, nID, str); + + // this works fine + mii.fMask = MIIM_STRING; + mii.dwTypeData = (LPTSTR)(LPCTSTR)str; + VERIFY(pPopupMenu->SetMenuItemInfo(i, &mii, TRUE)); + } + } + + uiMenuCount = pPopupMenu->GetMenuItemCount(); + if (uiMenuCount == -1) { + return; + } + + bool fPnSPresets = false; + + for (UINT i = 0; i < uiMenuCount; ++i) { + UINT nID = pPopupMenu->GetMenuItemID(i); + + if (nID >= ID_PANNSCAN_PRESETS_START && nID < ID_PANNSCAN_PRESETS_END) { + do { + nID = pPopupMenu->GetMenuItemID(i); + VERIFY(pPopupMenu->DeleteMenu(i, MF_BYPOSITION)); + uiMenuCount--; + } while (i < uiMenuCount && nID >= ID_PANNSCAN_PRESETS_START && nID < ID_PANNSCAN_PRESETS_END); + + nID = pPopupMenu->GetMenuItemID(i); + } + + if (nID == ID_VIEW_RESET) { + fPnSPresets = true; + } + } + + if (fPnSPresets) { + bool usetheme = AppIsThemeLoaded(); + const CAppSettings& s = AfxGetAppSettings(); + INT_PTR i = 0, j = s.m_pnspresets.GetCount(); + for (; i < j; i++) { + int k = 0; + CString label = s.m_pnspresets[i].Tokenize(_T(","), k); + VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND, ID_PANNSCAN_PRESETS_START + i, label)); + CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, (UINT)(ID_PANNSCAN_PRESETS_START + i), true); + } + //if (j > 0) + { + VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND, ID_PANNSCAN_PRESETS_START + i, ResStr(IDS_PANSCAN_EDIT))); + VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND | MF_SEPARATOR)); + if (usetheme) { + CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, (UINT)(ID_PANNSCAN_PRESETS_START + i), true); + UINT pos = CMPCThemeMenu::getPosFromID(pPopupMenu, ID_VIEW_RESET); //separator is inserted right before view_reset + CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, pos - 1); + } + } + } + + if (m_pActiveContextMenu == pPopupMenu) { + m_eventc.FireEvent(MpcEvent::CONTEXT_MENU_POPUP_INITIALIZED); + } +} + +void CMainFrame::OnUnInitMenuPopup(CMenu* pPopupMenu, UINT nFlags) +{ + __super::OnUnInitMenuPopup(pPopupMenu, nFlags); + if (m_pActiveContextMenu == pPopupMenu) { + m_pActiveContextMenu = nullptr; + m_eventc.FireEvent(MpcEvent::CONTEXT_MENU_POPUP_UNINITIALIZED); + } else if (m_pActiveSystemMenu == pPopupMenu) { + m_pActiveSystemMenu = nullptr; + SendMessage(WM_CANCELMODE); // unfocus main menu if system menu was entered with alt+space + m_eventc.FireEvent(MpcEvent::SYSTEM_MENU_POPUP_UNINITIALIZED); + } +} + +void CMainFrame::OnEnterMenuLoop(BOOL bIsTrackPopupMenu) +{ + if (!bIsTrackPopupMenu && !m_pActiveSystemMenu && GetMenuBarState() == AFX_MBS_HIDDEN) { + // mfc has problems synchronizing menu visibility with modal loop in certain situations + ASSERT(!m_pActiveContextMenu); + VERIFY(SetMenuBarState(AFX_MBS_VISIBLE)); + } + __super::OnEnterMenuLoop(bIsTrackPopupMenu); +} + +BOOL CMainFrame::OnQueryEndSession() +{ + return TRUE; +} + +void CMainFrame::OnEndSession(BOOL bEnding) +{ + // do nothing for now +} + +BOOL CMainFrame::OnMenu(CMenu* pMenu) +{ + if (!pMenu) { + return FALSE; + } + + CPoint point; + GetCursorPos(&point); + + // Do not show popup menu in D3D fullscreen it has several adverse effects. + if (IsD3DFullScreenMode()) { + CWnd* pWnd = WindowFromPoint(point); + if (pWnd && *pWnd == *m_pDedicatedFSVideoWnd) { + return FALSE; + } + } + + if (AfxGetMyApp()->m_fClosingState) { + return FALSE; //prevent crash when player closes with context menu open + } + + m_pActiveContextMenu = pMenu; + + pMenu->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NOANIMATION, point.x, point.y, this); + + return TRUE; +} + +void CMainFrame::OnMenuPlayerShort() +{ + if (!AfxGetAppSettings().bAlwaysUseShortMenu && (IsMenuHidden() || IsD3DFullScreenMode())) { + OnMenu(m_mainPopupMenu.GetSubMenu(0)); + } else { + OnMenu(m_popupMenu.GetSubMenu(0)); + } +} + +void CMainFrame::OnMenuPlayerLong() +{ + OnMenu(m_mainPopupMenu.GetSubMenu(0)); +} + +void CMainFrame::OnMenuFilters() +{ + SetupFiltersSubMenu(); + OnMenu(&m_filtersMenu); +} + +void CMainFrame::OnUpdatePlayerStatus(CCmdUI* pCmdUI) +{ + if (GetLoadState() == MLS::LOADING) { + m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_OPENING)); + if (AfxGetAppSettings().bUseEnhancedTaskBar && m_pTaskbarList) { + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_INDETERMINATE); + } + } else if (GetLoadState() == MLS::LOADED) { + if (!m_tempstatus_msg.IsEmpty()) { + m_wndStatusBar.SetStatusMessage(m_tempstatus_msg); + return; + } + CString msg; + if (m_fCapturing) { + msg.LoadString(IDS_CONTROLS_CAPTURING); + + if (m_pAMDF) { + long lDropped = 0; + m_pAMDF->GetNumDropped(&lDropped); + long lNotDropped = 0; + m_pAMDF->GetNumNotDropped(&lNotDropped); + + if ((lDropped + lNotDropped) > 0) { + msg.AppendFormat(IDS_MAINFRM_37, lDropped + lNotDropped, lDropped); + } + } + + CComPtr pPin; + if (m_pCGB && SUCCEEDED(m_pCGB->FindPin(m_wndCaptureBar.m_capdlg.m_pDst, PINDIR_INPUT, nullptr, nullptr, FALSE, 0, &pPin))) { + LONGLONG size = 0; + if (CComQIPtr pStream = pPin) { + pStream->Commit(STGC_DEFAULT); + + WIN32_FIND_DATA findFileData; + HANDLE h = FindFirstFile(m_wndCaptureBar.m_capdlg.m_file, &findFileData); + if (h != INVALID_HANDLE_VALUE) { + size = ((LONGLONG)findFileData.nFileSizeHigh << 32) | findFileData.nFileSizeLow; + + if (size < 1024i64 * 1024) { + msg.AppendFormat(IDS_MAINFRM_38, size / 1024); + } else { //if (size < 1024i64*1024*1024) + msg.AppendFormat(IDS_MAINFRM_39, size / 1024 / 1024); + } + + FindClose(h); + } + } + + ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes, TotalNumberOfFreeBytes; + if (GetDiskFreeSpaceEx( + m_wndCaptureBar.m_capdlg.m_file.Left(m_wndCaptureBar.m_capdlg.m_file.ReverseFind('\\') + 1), + &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) { + if (FreeBytesAvailable.QuadPart < 1024i64 * 1024) { + msg.AppendFormat(IDS_MAINFRM_40, FreeBytesAvailable.QuadPart / 1024); + } else { //if (FreeBytesAvailable.QuadPart < 1024i64*1024*1024) + msg.AppendFormat(IDS_MAINFRM_41, FreeBytesAvailable.QuadPart / 1024 / 1024); + } + } + + if (m_wndCaptureBar.m_capdlg.m_pMux) { + __int64 pos = 0; + CComQIPtr pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux; + if (pMuxMS && SUCCEEDED(pMuxMS->GetCurrentPosition(&pos)) && pos > 0) { + double bytepersec = 10000000.0 * size / pos; + if (bytepersec > 0) { + m_rtDurationOverride = REFERENCE_TIME(10000000.0 * (FreeBytesAvailable.QuadPart + size) / bytepersec); + } + } + } + + if (m_wndCaptureBar.m_capdlg.m_pVidBuffer + || m_wndCaptureBar.m_capdlg.m_pAudBuffer) { + int nFreeVidBuffers = 0, nFreeAudBuffers = 0; + if (CComQIPtr pVB = m_wndCaptureBar.m_capdlg.m_pVidBuffer) { + nFreeVidBuffers = pVB->GetFreeBuffers(); + } + if (CComQIPtr pAB = m_wndCaptureBar.m_capdlg.m_pAudBuffer) { + nFreeAudBuffers = pAB->GetFreeBuffers(); + } + + msg.AppendFormat(IDS_MAINFRM_42, nFreeVidBuffers, nFreeAudBuffers); + } + } + } else if (m_bBuffering) { + if (m_pAMNS) { + long BufferingProgress = 0; + if (SUCCEEDED(m_pAMNS->get_BufferingProgress(&BufferingProgress)) && BufferingProgress > 0) { + msg.Format(IDS_CONTROLS_BUFFERING, BufferingProgress); + + __int64 start = 0, stop = 0; + m_wndSeekBar.GetRange(start, stop); + m_fLiveWM = (stop == start); + } + } + } else if (m_pAMOP) { + LONGLONG t = 0, c = 0; + if (SUCCEEDED(m_pAMOP->QueryProgress(&t, &c)) && t > 0 && c < t) { + msg.Format(IDS_CONTROLS_BUFFERING, c * 100 / t); + } else { + m_pAMOP.Release(); + } + } + + if (msg.IsEmpty()) { + int msg_id = 0; + switch (m_CachedFilterState) { + case State_Stopped: + msg_id = IDS_CONTROLS_STOPPED; + break; + case State_Paused: + msg_id = IDS_CONTROLS_PAUSED; + break; + case State_Running: + msg_id = IDS_CONTROLS_PLAYING; + break; + } + if (m_fFrameSteppingActive) { + msg_id = IDS_CONTROLS_PAUSED; + } + if (msg_id) { + msg.LoadString(msg_id); + + if (m_bUsingDXVA && (msg_id == IDS_CONTROLS_PAUSED || msg_id == IDS_CONTROLS_PLAYING)) { + msg.AppendFormat(_T(" %s"), ResStr(IDS_HW_INDICATOR).GetString()); + } + } + + auto& s = AfxGetAppSettings(); + + CString videoinfo; + CString fpsinfo; + CStringW audioinfo; + if (s.bShowVideoInfoInStatusbar && (!m_statusbarVideoFormat.IsEmpty() || !m_statusbarVideoSize.IsEmpty())) { + if(!m_statusbarVideoFormat.IsEmpty()) { + videoinfo.Append(m_statusbarVideoFormat); + } + if(!m_statusbarVideoSize.IsEmpty()) { + if(!m_statusbarVideoFormat.IsEmpty()) { + videoinfo.AppendChar(_T(' ')); + } + videoinfo.Append(m_statusbarVideoSize); + } + } + if (s.bShowFPSInStatusbar && m_pCAP) { + if (m_dSpeedRate != 1.0) { + fpsinfo.Format(_T("%.2lf fps (%.2lfx)"), m_pCAP->GetFPS(), m_dSpeedRate); + } else { + fpsinfo.Format(_T("%.2lf fps"), m_pCAP->GetFPS()); + } + } + + if (s.bShowAudioFormatInStatusbar && !m_statusbarAudioFormat.IsEmpty()) { + audioinfo = m_statusbarAudioFormat; + } + + if (!videoinfo.IsEmpty() || !fpsinfo.IsEmpty()) { + CStringW tinfo = L""; + AppendWithDelimiter(tinfo, videoinfo); + AppendWithDelimiter(tinfo, fpsinfo); + msg.Append(L"\u2001[" + tinfo + L"]"); + } + + if (!audioinfo.IsEmpty()) { + msg.Append(L"\u2001[" + audioinfo); + if (s.bShowLangInStatusbar && !currentAudioLang.IsEmpty()) { + msg.Append(L" " + currentAudioLang); + } + msg.Append(L"]"); + } + + if (s.bShowLangInStatusbar) { + bool showaudiolang = audioinfo.IsEmpty() && !currentAudioLang.IsEmpty(); + if (showaudiolang || !currentSubLang.IsEmpty()) { + msg.Append(_T("\u2001[")); + if (showaudiolang) { + msg.Append(L"AUD: " + currentAudioLang); + } + if (!currentSubLang.IsEmpty()) { + if (showaudiolang) { + msg.Append(_T(", ")); + } + msg.Append(L"SUB: " + currentSubLang); + } + msg.Append(_T("]")); + } + } + if (s.bShowABMarksInStatusbar) { + if (abRepeat) { + REFERENCE_TIME actualB = abRepeat.positionB; + if (actualB == 0) { + REFERENCE_TIME start = 0; + m_wndSeekBar.GetRange(start, actualB); + } + bool showhours = (actualB >= 35995000000) || (abRepeat.positionA >= 35995000000); + CString timeMarkA = showhours ? ReftimeToString2(abRepeat.positionA) : ReftimeToString3(abRepeat.positionA); + CString timeMarkB = showhours ? ReftimeToString2(actualB) : ReftimeToString3(actualB); + msg.AppendFormat(_T("\u2001[A-B %s > %s]"), timeMarkA.GetString(), timeMarkB.GetString()); + } + } + } + + m_wndStatusBar.SetStatusMessage(msg); + } else if (GetLoadState() == MLS::CLOSING) { + m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_CLOSING)); + if (AfxGetAppSettings().bUseEnhancedTaskBar && m_pTaskbarList) { + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_INDETERMINATE); + } + } else { + m_wndStatusBar.SetStatusMessage(m_closingmsg); + } +} + +LRESULT CMainFrame::OnFilePostOpenmedia(WPARAM wParam, LPARAM lParam) +{ + if (!m_pGB) { + ASSERT(FALSE); + return 1; + } + ASSERT(GetLoadState() == MLS::LOADING); + + auto& s = AfxGetAppSettings(); + + // from this on + m_bOpenMediaActive = false; + m_OpenMediaFailedCount = 0; + m_bSettingUpMenus = true; + + SetLoadState(MLS::LOADED); + ASSERT(GetMediaStateDirect() == State_Stopped); + + // destroy invisible top-level d3dfs window if there is no video renderer + if (HasDedicatedFSVideoWindow() && !m_pMFVDC && !m_pVMRWC && !m_pVW) { + m_pDedicatedFSVideoWnd->DestroyWindow(); + if (s.IsD3DFullscreen()) { + m_fStartInD3DFullscreen = true; + } else { + m_fStartInFullscreenSeparate = true; + } + } + + // auto-change monitor mode if requested + if (s.autoChangeFSMode.bEnabled && IsFullScreenMode()) { + AutoChangeMonitorMode(); + // make sure the fullscreen window is positioned properly after the mode change, + // OnWindowPosChanging() will take care of that + if (m_bOpeningInAutochangedMonitorMode && m_fFullScreen) { + CRect rect; + GetWindowRect(rect); + MoveWindow(rect); + } + } + + // set shader selection + if (m_pCAP || m_pCAP2) { + SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); + } + + // load keyframes for fast-seek + if (wParam == PM_FILE) { + LoadKeyFrames(); + } + + // remember OpenMediaData for later use + m_lastOMD.Free(); + m_lastOMD.Attach((OpenMediaData*)lParam); + if (!m_lastOMD->title) { + ASSERT(false); + m_lastOMD->title = L""; + } + + // the media opened successfully, we don't want to jump trough it anymore + UINT lastSkipDirection = m_nLastSkipDirection; + m_nLastSkipDirection = 0; + + // let the EDL do its magic + if (s.fEnableEDLEditor && !m_lastOMD->title.IsEmpty()) { + m_wndEditListEditor.OpenFile(m_lastOMD->title); + } + + // initiate Capture panel with the new media + if (auto pDeviceData = dynamic_cast(m_lastOMD.m_p)) { + m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput); + m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel); + m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput); + } + + // current playlist item was loaded successfully + m_wndPlaylistBar.SetCurValid(true); + + // set item duration in the playlist + // TODO: GetDuration() should be refactored out of this place, to some aggregating class + REFERENCE_TIME rtDur = 0; + if (m_pMS && m_pMS->GetDuration(&rtDur) == S_OK) { + m_wndPlaylistBar.SetCurTime(rtDur); + } + + // process /pns command-line arg, then discard it + ApplyPanNScanPresetString(); + + // initiate toolbars with the new media + OpenSetupInfoBar(); + OpenSetupStatsBar(); + OpenSetupStatusBar(); + OpenSetupCaptureBar(); + + // Load cover-art + if (m_fAudioOnly || HasDedicatedFSVideoWindow()) { + UpdateControlState(CMainFrame::UPDATE_LOGO); + } + + if (s.bOpenRecPanelWhenOpeningDevice) { + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + // show navigation panel when it's available and not disabled + if (!s.fHideNavigation) { + m_wndNavigationBar.m_navdlg.UpdateElementList(); + if (!m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); + } + else { + ASSERT(FALSE); + } + } + } + else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + // show capture bar + if (!m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)) { + m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); + } + else { + ASSERT(FALSE); + } + } + } + + // we don't want to wait until timers initialize the seekbar and the time counter + OnTimer(TIMER_STREAMPOSPOLLER); + OnTimer(TIMER_STREAMPOSPOLLER2); + + if (m_AngleX != 0 || m_AngleY != 0 || m_AngleZ != 0) { + PerformFlipRotate(); + } + + bool go_fullscreen = s.fLaunchfullscreen && !m_fAudioOnly && !IsFullScreenMode() && lastSkipDirection == 0 && !(s.nCLSwitches & CLSW_THUMBNAILS); + + // auto-zoom if requested + if (IsWindowVisible() && s.fRememberZoomLevel && !IsFullScreenMode() && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { + if (go_fullscreen) { + m_bNeedZoomAfterFullscreenExit = true; + } + ZoomVideoWindow(ZOOM_DEFAULT_LEVEL, go_fullscreen); + } + + if (go_fullscreen) { + OnViewFullscreen(); + } + + // Add temporary flag to allow EC_VIDEO_SIZE_CHANGED event to stabilize window size + // for 5 seconds since playback starts + m_bAllowWindowZoom = true; + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::AUTOFIT_TIMEOUT, [this] + { m_bAllowWindowZoom = false; }, 5000); + + // update control bar areas and paint bypassing the message queue + RecalcLayout(); + UpdateWindow(); + + // the window is repositioned and repainted, video renderer rect is ready to be set - + // OnPlayPlay()/OnPlayPause() will take care of that + m_bDelaySetOutputRect = false; + + if (s.nCLSwitches & CLSW_THUMBNAILS) { + MoveVideoWindow(false, true); + MediaControlPause(true); + SendMessageW(WM_COMMAND, ID_CMDLINE_SAVE_THUMBNAILS); + m_bSettingUpMenus = false; + m_bRememberFilePos = false; + SendMessageW(WM_COMMAND, ID_FILE_EXIT); + return 0; + } + + MediaTransportControlSetMedia(); + + // start playback if requested + m_bFirstPlay = true; + const auto uModeChangeDelay = s.autoChangeFSMode.uDelay * 1000; + if (!(s.nCLSwitches & CLSW_OPEN) && (s.nLoops > 0)) { + if (m_bOpeningInAutochangedMonitorMode && uModeChangeDelay) { + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, + std::bind(&CMainFrame::OnPlayPlay, this), uModeChangeDelay); + } else { + OnPlayPlay(); + } + } else { + // OnUpdatePlayPauseStop() will decide if we can pause the media + if (m_bOpeningInAutochangedMonitorMode && uModeChangeDelay) { + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, + [this] { OnCommand(ID_PLAY_PAUSE, 0); }, uModeChangeDelay); + } else { + OnCommand(ID_PLAY_PAUSE, 0); + } + } + s.nCLSwitches &= ~CLSW_OPEN; + + // Ensure the dynamically added menu items are updated + SetupFiltersSubMenu(); + SetupAudioSubMenu(); + SetupSubtitlesSubMenu(); + SetupVideoStreamsSubMenu(); + SetupJumpToSubMenus(); + SetupRecentFilesSubMenu(); + + // notify listeners + if (GetPlaybackMode() != PM_DIGITAL_CAPTURE) { + SendNowPlayingToSkype(); + SendNowPlayingToApi(); + } + + if (CanPreviewUse() && m_wndSeekBar.IsVisible()) { + CPoint point; + GetCursorPos(&point); + + CRect rect; + m_wndSeekBar.GetWindowRect(&rect); + if (rect.PtInRect(point)) { + m_wndSeekBar.PreviewWindowShow(point); + } + } + + m_bSettingUpMenus = false; + + return 0; +} + +LRESULT CMainFrame::OnOpenMediaFailed(WPARAM wParam, LPARAM lParam) +{ + ASSERT(GetLoadState() == MLS::LOADING); + SetLoadState(MLS::FAILING); + + ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); + const auto& s = AfxGetAppSettings(); + + m_lastOMD.Free(); + m_lastOMD.Attach((OpenMediaData*)lParam); + if (!m_lastOMD->title) { + ASSERT(false); + m_lastOMD->title = L""; + } + + bool bOpenNextInPlaylist = false; + bool bAfterPlaybackEvent = false; + + m_bOpenMediaActive = false; + m_OpenMediaFailedCount++; + + m_dwReloadPos = 0; + reloadABRepeat = ABRepeat(); + m_iReloadAudioIdx = -1; + m_iReloadSubIdx = -1; + + if (wParam == PM_FILE && m_OpenMediaFailedCount < 5) { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli) && pli.m_bYoutubeDL && m_sydlLastProcessURL != pli.m_ydlSourceURL) { + OpenCurPlaylistItem(0, true); // Try to reprocess if failed first time. + return 0; + } + if (m_wndPlaylistBar.GetCount() == 1) { + if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { + bOpenNextInPlaylist = SearchInDir(false, s.bLoopFolderOnPlayNextFile); + if (!bOpenNextInPlaylist) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_FIRST_IN_FOLDER)); + } + } else if (m_nLastSkipDirection == ID_NAVIGATE_SKIPFORWARD) { + bOpenNextInPlaylist = SearchInDir(true, s.bLoopFolderOnPlayNextFile); + if (!bOpenNextInPlaylist) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_LAST_IN_FOLDER)); + } + } + } else { + m_wndPlaylistBar.SetCurValid(false); + + if (m_wndPlaylistBar.IsAtEnd()) { + m_nLoops++; + } + + if (s.fLoopForever || m_nLoops < s.nLoops) { + if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { + bOpenNextInPlaylist = m_wndPlaylistBar.SetPrev(); + } else { + bOpenNextInPlaylist = m_wndPlaylistBar.SetNext(); + } + } else { + bAfterPlaybackEvent = true; + } + } + } + + CloseMedia(bOpenNextInPlaylist); + + if (m_OpenMediaFailedCount >= 5) { + m_wndPlaylistBar.SetCurValid(false); + if (m_wndPlaylistBar.IsAtEnd()) { + m_nLoops++; + } + if (s.fLoopForever || m_nLoops < s.nLoops) { + if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { + m_wndPlaylistBar.SetPrev(); + } else { + m_wndPlaylistBar.SetNext(); + } + } + m_OpenMediaFailedCount = 0; + } + else if (bOpenNextInPlaylist) { + OpenCurPlaylistItem(); + } + else if (bAfterPlaybackEvent) { + DoAfterPlaybackEvent(); + } + + return 0; +} + +void CMainFrame::OnFilePostClosemedia(bool bNextIsQueued/* = false*/) +{ + SetPlaybackMode(PM_NONE); + SetLoadState(MLS::CLOSED); + + m_bOpenMediaActive = false; + + abRepeat = ABRepeat(); + m_kfs.clear(); + + m_nCurSubtitle = -1; + m_lSubtitleShift = 0; + + CAppSettings& s = AfxGetAppSettings(); + if (!s.fSavePnSZoom) { + m_AngleX = m_AngleY = m_AngleZ = 0; + m_ZoomX = m_ZoomY = 1.0; + m_PosX = m_PosY = 0.5; + } + + if (m_closingmsg.IsEmpty()) { + m_closingmsg.LoadString(IDS_CONTROLS_CLOSED); + } + + m_wndView.SetVideoRect(); + m_wndSeekBar.Enable(false); + m_wndSeekBar.SetRange(0, 0); + m_wndSeekBar.SetPos(0); + m_wndSeekBar.RemoveChapters(); + m_wndInfoBar.RemoveAllLines(); + m_wndStatsBar.RemoveAllLines(); + m_wndStatusBar.Clear(); + m_wndStatusBar.ShowTimer(false); + currentAudioLang.Empty(); + currentSubLang.Empty(); + m_OSD.SetRange(0); + m_OSD.SetPos(0); + m_Lcd.SetMediaRange(0, 0); + m_Lcd.SetMediaPos(0); + m_statusbarVideoFormat.Empty(); + m_statusbarVideoSize.Empty(); + + m_VidDispName.Empty(); + m_AudDispName.Empty(); + m_HWAccelType = L""; + + if (!bNextIsQueued) { + UpdateControlState(CMainFrame::UPDATE_LOGO); + RecalcLayout(); + } + + if (s.fEnableEDLEditor) { + m_wndEditListEditor.CloseFile(); + } + + if (m_controls.ControlChecked(CMainFrameControls::Panel::SUBRESYNC)) { + m_controls.ToggleControl(CMainFrameControls::Panel::SUBRESYNC); + } + + if (m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)) { + m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); + } + m_wndCaptureBar.m_capdlg.SetupVideoControls(_T(""), nullptr, nullptr, nullptr); + m_wndCaptureBar.m_capdlg.SetupAudioControls(_T(""), nullptr, CInterfaceArray()); + + if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); + } + + if (!bNextIsQueued) { + OpenSetupWindowTitle(true); + } + + SetAlwaysOnTop(s.iOnTop); + + SendNowPlayingToSkype(); + + // try to release external objects + UnloadUnusedExternalObjects(); + SetTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS, 60000, nullptr); + + if (HasDedicatedFSVideoWindow()) { + if (IsD3DFullScreenMode()) { + m_fStartInD3DFullscreen = true; + } else { + m_fStartInFullscreenSeparate = true; + } + if (!bNextIsQueued) { + m_pDedicatedFSVideoWnd->DestroyWindow(); + } + } + + UpdateWindow(); // redraw +} + +void CMainFrame::OnBossKey() +{ + // Disable animation + ANIMATIONINFO AnimationInfo; + AnimationInfo.cbSize = sizeof(ANIMATIONINFO); + ::SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + int m_WindowAnimationType = AnimationInfo.iMinAnimate; + AnimationInfo.iMinAnimate = 0; + ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + if (IsFullScreenMode()) { + SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN); + } + SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, -1); + + // Enable animation + AnimationInfo.iMinAnimate = m_WindowAnimationType; + ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); +} + +void CMainFrame::OnStreamAudio(UINT nID) +{ + nID -= ID_STREAM_AUDIO_NEXT; + + if (GetLoadState() != MLS::LOADED) { + return; + } + + DWORD cStreams = 0; + if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 1) { + for (DWORD i = 0; i < cStreams; i++) { + DWORD dwFlags = 0; + DWORD dwGroup = 0; + if (FAILED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { + return; + } + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + long stream_index = (i + (nID == 0 ? 1 : cStreams - 1)) % cStreams; + if (SUCCEEDED(m_pAudioSwitcherSS->Enable(stream_index, AMSTREAMSELECTENABLE_ENABLE))) { + LCID lcid = 0; + CComHeapPtr pszName; + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(m_pAudioSwitcherSS->Info(stream_index, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) { + m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pszName), lcid, 1)); + UpdateSelectedAudioStreamInfo(stream_index, pmt, lcid); + DeleteMediaType(pmt); + } + } + break; + } + } + } else if (GetPlaybackMode() == PM_FILE) { + OnStreamSelect(nID == 0, 1); + } else if (GetPlaybackMode() == PM_DVD) { + SendMessage(WM_COMMAND, ID_DVD_AUDIO_NEXT + nID); + } + + if (m_pBA && !m_fFrameSteppingActive) { + m_pBA->put_Volume(m_wndToolBar.Volume); + } +} + +void CMainFrame::OnStreamSub(UINT nID) +{ + nID -= ID_STREAM_SUB_NEXT; + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (!m_pSubStreams.IsEmpty()) { + AfxGetAppSettings().fEnableSubtitles = true; + SetSubtitle(nID == 0 ? 1 : -1, true, true); + SetFocus(); + } else if (GetPlaybackMode() == PM_FILE) { + OnStreamSelect(nID == 0, 2); + } else if (GetPlaybackMode() == PM_DVD) { + SendMessage(WM_COMMAND, ID_DVD_SUB_NEXT + nID); + } +} + +void CMainFrame::OnStreamSubOnOff() +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pCAP && !m_pSubStreams.IsEmpty() || m_pDVS) { + ToggleSubtitleOnOff(true); + SetFocus(); + } else if (GetPlaybackMode() == PM_DVD) { + SendMessage(WM_COMMAND, ID_DVD_SUB_ONOFF); + } +} + +void CMainFrame::OnDvdAngle(UINT nID) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pDVDI && m_pDVDC) { + ULONG ulAnglesAvailable, ulCurrentAngle; + if (SUCCEEDED(m_pDVDI->GetCurrentAngle(&ulAnglesAvailable, &ulCurrentAngle)) && ulAnglesAvailable > 1) { + ulCurrentAngle += (nID == ID_DVD_ANGLE_NEXT) ? 1 : -1; + if (ulCurrentAngle > ulAnglesAvailable) { + ulCurrentAngle = 1; + } else if (ulCurrentAngle < 1) { + ulCurrentAngle = ulAnglesAvailable; + } + m_pDVDC->SelectAngle(ulCurrentAngle, DVD_CMD_FLAG_Block, nullptr); + + CString osdMessage; + osdMessage.Format(IDS_AG_ANGLE, ulCurrentAngle); + m_OSD.DisplayMessage(OSD_TOPLEFT, osdMessage); + } + } +} + +void CMainFrame::OnDvdAudio(UINT nID) +{ + nID -= ID_DVD_AUDIO_NEXT; + + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pDVDI && m_pDVDC) { + ULONG nStreamsAvailable, nCurrentStream; + if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&nStreamsAvailable, &nCurrentStream)) && nStreamsAvailable > 1) { + DVD_AudioAttributes AATR; + UINT nNextStream = (nCurrentStream + (nID == 0 ? 1 : nStreamsAvailable - 1)) % nStreamsAvailable; + + HRESULT hr = m_pDVDC->SelectAudioStream(nNextStream, DVD_CMD_FLAG_Block, nullptr); + if (SUCCEEDED(m_pDVDI->GetAudioAttributes(nNextStream, &AATR))) { + CString lang; + CString strMessage; + if (AATR.Language) { + GetLocaleString(AATR.Language, LOCALE_SENGLANGUAGE, lang); + currentAudioLang = lang; + } else { + lang.Format(IDS_AG_UNKNOWN, nNextStream + 1); + currentAudioLang.Empty(); + } + + CString format = GetDVDAudioFormatName(AATR); + CString str; + + if (!format.IsEmpty()) { + str.Format(IDS_MAINFRM_11, + lang.GetString(), + format.GetString(), + AATR.dwFrequency, + AATR.bQuantization, + AATR.bNumberOfChannels, + ResStr(AATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString()); + if (FAILED(hr)) { + str += _T(" [") + ResStr(IDS_AG_ERROR) + _T("] "); + } + strMessage.Format(IDS_AUDIO_STREAM, str.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, strMessage); + } + } + } + } +} + +void CMainFrame::OnDvdSub(UINT nID) +{ + nID -= ID_DVD_SUB_NEXT; + + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pDVDI && m_pDVDC) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) + && ulStreamsAvailable > 1) { + //UINT nNextStream = (ulCurrentStream+(nID==0?1:ulStreamsAvailable-1))%ulStreamsAvailable; + int nNextStream; + + if (!bIsDisabled) { + nNextStream = ulCurrentStream + (nID == 0 ? 1 : -1); + } else { + nNextStream = (nID == 0 ? 0 : ulStreamsAvailable - 1); + } + + if (!bIsDisabled && ((nNextStream < 0) || ((ULONG)nNextStream >= ulStreamsAvailable))) { + m_pDVDC->SetSubpictureState(FALSE, DVD_CMD_FLAG_Block, nullptr); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_SUBTITLE_STREAM_OFF)); + } else { + HRESULT hr = m_pDVDC->SelectSubpictureStream(nNextStream, DVD_CMD_FLAG_Block, nullptr); + + DVD_SubpictureAttributes SATR; + m_pDVDC->SetSubpictureState(TRUE, DVD_CMD_FLAG_Block, nullptr); + if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(nNextStream, &SATR))) { + CString lang; + CString strMessage; + GetLocaleString(SATR.Language, LOCALE_SENGLANGUAGE, lang); + + if (FAILED(hr)) { + lang += _T(" [") + ResStr(IDS_AG_ERROR) + _T("] "); + } + strMessage.Format(IDS_SUBTITLE_STREAM, lang.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, strMessage); + } + } + } + } +} + +void CMainFrame::OnDvdSubOnOff() +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pDVDI && m_pDVDC) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { + m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); + } + } +} + +// +// menu item handlers +// + +// file + +INT_PTR CMainFrame::DoFileDialogWithLastFolder(CFileDialog& fd, CStringW& lastPath) { + if (!lastPath.IsEmpty()) { + fd.m_ofn.lpstrInitialDir = lastPath; + } + INT_PTR ret = fd.DoModal(); + if (ret == IDOK) { + lastPath = GetFolderOnly(fd.m_ofn.lpstrFile); + } + return ret; +} + + +void CMainFrame::OnFileOpenQuick() +{ + if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar)) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + CString filter; + CAtlArray mask; + s.m_Formats.GetFilter(filter, mask); + + DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_ALLOWMULTISELECT | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + if (!s.fKeepHistory) { + dwFlags |= OFN_DONTADDTORECENT; + } + + COpenFileDlg fd(mask, true, nullptr, nullptr, dwFlags, filter, GetModalParent()); + if (DoFileDialogWithLastFolder(fd, s.lastQuickOpenPath) != IDOK) { + return; + } + + CAtlList fns; + + POSITION pos = fd.GetStartPosition(); + while (pos) { + fns.AddTail(fd.GetNextPathName(pos)); + } + + bool fMultipleFiles = false; + + if (fns.GetCount() > 1 + || fns.GetCount() == 1 + && (fns.GetHead()[fns.GetHead().GetLength() - 1] == '\\' + || fns.GetHead()[fns.GetHead().GetLength() - 1] == '*')) { + fMultipleFiles = true; + } + + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + SetForegroundWindow(); + + if (fns.GetCount() == 1) { + if (OpenBD(fns.GetHead())) { + return; + } + } + + m_wndPlaylistBar.Open(fns, fMultipleFiles); + + OpenCurPlaylistItem(); +} + +void CMainFrame::OnFileOpenmedia() +{ + if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar) || IsD3DFullScreenMode()) { + return; + } + + static COpenDlg dlg; + if (IsWindow(dlg.GetSafeHwnd()) && dlg.IsWindowVisible()) { + dlg.SetForegroundWindow(); + return; + } + if (dlg.DoModal() != IDOK || dlg.GetFileNames().IsEmpty()) { + return; + } + + if (!dlg.GetAppendToPlaylist()) { + CloseMediaBeforeOpen(); + } + + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + SetForegroundWindow(); + + CAtlList filenames; + + if (CanSendToYoutubeDL(dlg.GetFileNames().GetHead())) { + if (ProcessYoutubeDLURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist())) { + if (!dlg.GetAppendToPlaylist()) { + OpenCurPlaylistItem(); + } + return; + } else if (IsOnYDLWhitelist(dlg.GetFileNames().GetHead())) { + // don't bother trying to open this website URL directly + return; + } + } + + filenames.AddHeadList(&dlg.GetFileNames()); + + if (!dlg.HasMultipleFiles()) { + if (OpenBD(filenames.GetHead())) { + return; + } + } + + if (dlg.GetAppendToPlaylist()) { + m_wndPlaylistBar.Append(filenames, dlg.HasMultipleFiles()); + } else { + m_wndPlaylistBar.Open(filenames, dlg.HasMultipleFiles()); + + OpenCurPlaylistItem(); + } +} + +LRESULT CMainFrame::OnMPCVRSwitchFullscreen(WPARAM wParam, LPARAM lParam) +{ + const auto& s = AfxGetAppSettings(); + m_bIsMPCVRExclusiveMode = static_cast(wParam); + + m_OSD.Stop(); + if (m_bIsMPCVRExclusiveMode) { + TRACE(L"MPCVR exclusive full screen\n"); + bool excl_mode_controls = IsFullScreenMainFrame(); + if (excl_mode_controls && m_wndPlaylistBar.IsVisible()) { + m_wndPlaylistBar.SetHiddenDueToFullscreen(true); + } + if (s.fShowOSD || s.fShowDebugInfo) { + if (m_pVMB || m_pMFVMB) { + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, excl_mode_controls); + } + } + } else { + if (s.fShowOSD || s.fShowDebugInfo) { + m_OSD.Start(m_pOSDWnd); + OSDBarSetPos(); + } + if (m_wndPlaylistBar.IsHiddenDueToFullscreen()) { + m_wndPlaylistBar.SetHiddenDueToFullscreen(false); + } + } + + return 0; +} + +void CMainFrame::OnUpdateFileOpen(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() != MLS::LOADING); +} + +BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) +{ + if (AfxGetMyApp()->m_fClosingState) { + return FALSE; + } + + CAppSettings& s = AfxGetAppSettings(); + + if (m_pSkypeMoodMsgHandler && m_pSkypeMoodMsgHandler->HandleMessage(pWnd->GetSafeHwnd(), pCDS)) { + return TRUE; + } else if (pCDS->dwData != 0x6ABE51 || pCDS->cbData < sizeof(DWORD)) { + if (s.hMasterWnd) { + ProcessAPICommand(pCDS); + return TRUE; + } else { + return FALSE; + } + } + + if (m_bScanDlgOpened) { + return FALSE; + } + + DWORD len = *((DWORD*)pCDS->lpData); + TCHAR* pBuff = (TCHAR*)((DWORD*)pCDS->lpData + 1); + TCHAR* pBuffEnd = (TCHAR*)((BYTE*)pBuff + pCDS->cbData - sizeof(DWORD)); + + CAtlList cmdln; + + while (len-- > 0 && pBuff < pBuffEnd) { + CString str(pBuff); + pBuff += str.GetLength() + 1; + + cmdln.AddTail(str); + } + + s.ParseCommandLine(cmdln); + + if (s.nCLSwitches & CLSW_SLAVE) { + SendAPICommand(CMD_CONNECT, L"%d", PtrToInt(GetSafeHwnd())); + s.nCLSwitches &= ~CLSW_SLAVE; + } + + POSITION pos = s.slFilters.GetHeadPosition(); + while (pos) { + CString fullpath = MakeFullPath(s.slFilters.GetNext(pos)); + + CPath tmp(fullpath); + tmp.RemoveFileSpec(); + tmp.AddBackslash(); + CString path = tmp; + + WIN32_FIND_DATA fd; + ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); + HANDLE hFind = FindFirstFile(fullpath, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + continue; + } + + CFilterMapper2 fm2(false); + fm2.Register(path + fd.cFileName); + while (!fm2.m_filters.IsEmpty()) { + if (FilterOverride* f = fm2.m_filters.RemoveTail()) { + f->fTemporary = true; + + bool fFound = false; + + POSITION pos2 = s.m_filters.GetHeadPosition(); + while (pos2) { + FilterOverride* f2 = s.m_filters.GetNext(pos2); + if (f2->type == FilterOverride::EXTERNAL && !f2->path.CompareNoCase(f->path)) { + fFound = true; + break; + } + } + + if (!fFound) { + CAutoPtr p(f); + s.m_filters.AddHead(p); + } + } + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + } + + bool fSetForegroundWindow = false; + + auto applyRandomizeSwitch = [&]() { + if (s.nCLSwitches & CLSW_RANDOMIZE) { + m_wndPlaylistBar.Randomize(); + s.nCLSwitches &= ~CLSW_RANDOMIZE; + } + }; + + if ((s.nCLSwitches & CLSW_DVD) && !s.slFiles.IsEmpty()) { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + fSetForegroundWindow = true; + + CAutoPtr p(DEBUG_NEW OpenDVDData()); + if (p) { + p->path = s.slFiles.GetHead(); + p->subs.AddTailList(&s.slSubs); + } + OpenMedia(p); + s.nCLSwitches &= ~CLSW_DVD; + } else if (s.nCLSwitches & CLSW_CD) { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + fSetForegroundWindow = true; + + CAtlList sl; + + if (!s.slFiles.IsEmpty()) { + GetOpticalDiskType(s.slFiles.GetHead()[0], sl); + } else { + CString dir; + dir.ReleaseBufferSetLength(GetCurrentDirectory(2048, dir.GetBuffer(2048))); + + GetOpticalDiskType(dir[0], sl); + + for (TCHAR drive = _T('A'); sl.IsEmpty() && drive <= _T('Z'); drive++) { + GetOpticalDiskType(drive, sl); + } + } + + m_wndPlaylistBar.Open(sl, true); + applyRandomizeSwitch(); + OpenCurPlaylistItem(); + s.nCLSwitches &= ~CLSW_CD; + } else if (s.nCLSwitches & CLSW_DEVICE) { + SendMessage(WM_COMMAND, ID_FILE_OPENDEVICE); + s.nCLSwitches &= ~CLSW_DEVICE; + } else if (!s.slFiles.IsEmpty()) { + CAtlList sl; + sl.AddTailList(&s.slFiles); + + PathUtils::ParseDirs(sl); + + bool fMulti = sl.GetCount() > 1; + + if (!fMulti) { + sl.AddTailList(&s.slDubs); + } + + if (OpenBD(s.slFiles.GetHead())) { + // Nothing more to do + } else if (!fMulti && CPath(s.slFiles.GetHead() + _T("\\VIDEO_TS")).IsDirectory()) { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + fSetForegroundWindow = true; + + CAutoPtr p(DEBUG_NEW OpenDVDData()); + if (p) { + p->path = s.slFiles.GetHead(); + p->subs.AddTailList(&s.slSubs); + } + OpenMedia(p); + } else { + ULONGLONG tcnow = GetTickCount64(); + if (m_dwLastRun && ((tcnow - m_dwLastRun) < s.iRedirectOpenToAppendThreshold)) { + s.nCLSwitches |= CLSW_ADD; + } + m_dwLastRun = tcnow; + + if ((s.nCLSwitches & CLSW_ADD) && !IsPlaylistEmpty()) { + POSITION pos2 = sl.GetHeadPosition(); + while (pos2) { + CString fn = sl.GetNext(pos2); + if (!CanSendToYoutubeDL(fn) || !ProcessYoutubeDLURL(fn, true)) { + CAtlList sl2; + sl2.AddHead(fn); + m_wndPlaylistBar.Append(sl2, false, &s.slSubs); + } + } + + applyRandomizeSwitch(); + + if (s.nCLSwitches & (CLSW_OPEN | CLSW_PLAY)) { + m_wndPlaylistBar.SetLast(); + OpenCurPlaylistItem(); + } + } else { + //SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + fSetForegroundWindow = true; + + if (fMulti || sl.GetCount() == 1) { + bool first = true; + POSITION pos2 = sl.GetHeadPosition(); + while (pos2) { + CString fn = sl.GetNext(pos2); + if (!CanSendToYoutubeDL(fn) || !ProcessYoutubeDLURL(fn, !first, false)) { + CAtlList sl2; + sl2.AddHead(fn); + if (first) { + m_wndPlaylistBar.Open(sl2, false, &s.slSubs); + } else { + m_wndPlaylistBar.Append(sl2, false, &s.slSubs); + } + } + first = false; + } + } else { + // video + dub + m_wndPlaylistBar.Open(sl, false, &s.slSubs); + } + + applyRandomizeSwitch(); + if (sl.GetCount() != 1 || !IsPlaylistFile(sl.GetHead())) { //playlists already set first pos (or saved pos) + m_wndPlaylistBar.SetFirst(); + } + OpenCurPlaylistItem((s.nCLSwitches & CLSW_STARTVALID) ? s.rtStart : 0, false, s.abRepeat); + + s.nCLSwitches &= ~CLSW_STARTVALID; + s.rtStart = 0; + } + s.nCLSwitches &= ~CLSW_ADD; + } + } else if ((s.nCLSwitches & CLSW_PLAY) && !IsPlaylistEmpty()) { + OpenCurPlaylistItem(); + } else { + applyRandomizeSwitch(); + } + + if (s.nCLSwitches & CLSW_PRESET1) { + SendMessage(WM_COMMAND, ID_VIEW_PRESETS_MINIMAL); + s.nCLSwitches &= ~CLSW_PRESET1; + } else if (s.nCLSwitches & CLSW_PRESET2) { + SendMessage(WM_COMMAND, ID_VIEW_PRESETS_COMPACT); + s.nCLSwitches &= ~CLSW_PRESET2; + } else if (s.nCLSwitches & CLSW_PRESET3) { + SendMessage(WM_COMMAND, ID_VIEW_PRESETS_NORMAL); + s.nCLSwitches &= ~CLSW_PRESET3; + } + if (s.nCLSwitches & CLSW_VOLUME) { + if (IsMuted()) { + SendMessage(WM_COMMAND, ID_VOLUME_MUTE); + } + m_wndToolBar.SetVolume(s.nCmdVolume); + s.nCLSwitches &= ~CLSW_VOLUME; + } + if (s.nCLSwitches & CLSW_MUTE) { + if (!IsMuted()) { + SendMessage(WM_COMMAND, ID_VOLUME_MUTE); + } + s.nCLSwitches &= ~CLSW_MUTE; + } + + if (fSetForegroundWindow && !(s.nCLSwitches & CLSW_NOFOCUS)) { + SetForegroundWindow(); + } + + return TRUE; +} + +int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) +{ + switch (uMsg) { + case BFFM_INITIALIZED: { + //Initial directory is set here + const CAppSettings& s = AfxGetAppSettings(); + if (!s.strDVDPath.IsEmpty()) { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)s.strDVDPath); + } + break; + } + default: + break; + } + return 0; +} + +void CMainFrame::OpenDVDOrBD(CStringW path) { + if (!path.IsEmpty()) { + AfxGetAppSettings().strDVDPath = path; + if (!OpenBD(path)) { + CAutoPtr p(DEBUG_NEW OpenDVDData()); + p->path = path; + p->path.Replace(_T('/'), _T('\\')); + p->path = ForceTrailingSlash(p->path); + + OpenMedia(p); + } + } +} + +void CMainFrame::OnFileOpendvd() +{ + if ((GetLoadState() == MLS::LOADING) || IsD3DFullScreenMode()) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + CString strTitle(StrRes(IDS_MAINFRM_46)); + CString path; + + if (s.fUseDVDPath && !s.strDVDPath.IsEmpty()) { + path = s.strDVDPath; + } else { + //strDVDPath is actually used as a default to open without the dialog, + //but since it is always updated to the last path chosen, + //we can use it as the default for the dialog, too + CFolderPickerDialog fd(ForceTrailingSlash(s.strDVDPath), FOS_PATHMUSTEXIST, GetModalParent()); + fd.m_ofn.lpstrTitle = strTitle; + + if (fd.DoModal() == IDOK) { + path = fd.GetPathName(); //getfolderpath() does not work correctly for CFolderPickerDialog + } else { + return; + } + } + OpenDVDOrBD(path); +} + +void CMainFrame::OnFileOpendevice() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (GetLoadState() == MLS::LOADING) { + return; + } + + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + SetForegroundWindow(); + + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + + m_wndPlaylistBar.Empty(); + + if (s.iDefaultCaptureDevice == 0 && s.strAnalogVideo == L"dummy" && s.strAnalogAudio == L"dummy") { + // device not configured yet, open settings + ShowOptions(IDD_PPAGECAPTURE); + return; + } + + CAutoPtr p(DEBUG_NEW OpenDeviceData()); + if (p) { + p->DisplayName[0] = s.strAnalogVideo; + p->DisplayName[1] = s.strAnalogAudio; + } + OpenMedia(p); +} + +void CMainFrame::OnFileOpenOpticalDisk(UINT nID) +{ + nID -= ID_FILE_OPEN_OPTICAL_DISK_START; + + nID++; + for (TCHAR drive = _T('A'); drive <= _T('Z'); drive++) { + CAtlList sl; + + OpticalDiskType_t discType = GetOpticalDiskType(drive, sl); + switch (discType) { + case OpticalDisk_Audio: + case OpticalDisk_VideoCD: + case OpticalDisk_DVDVideo: + case OpticalDisk_BD: + nID--; + break; + default: + break; + } + + if (nID == 0) { + if (OpticalDisk_BD == discType || OpticalDisk_DVDVideo == discType) { + OpenDVDOrBD(CStringW(drive) + L":\\"); + } else { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + SetForegroundWindow(); + + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + + m_wndPlaylistBar.Open(sl, true); + OpenCurPlaylistItem(); + } + break; + } + } +} + +void CMainFrame::OnFileRecycle() +{ + // check if a file is playing + if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_FILE) { + return; + } + + OAFilterState fs = GetMediaState(); + if (fs == State_Running) { + MediaControlPause(true); + } + + m_wndPlaylistBar.DeleteFileInPlaylist(m_wndPlaylistBar.m_pl.GetPos()); +} + +void CMainFrame::OnFileReopen() +{ + if (!m_LastOpenBDPath.IsEmpty() && OpenBD(m_LastOpenBDPath)) { + return; + } + + // save playback position + if (GetLoadState() == MLS::LOADED) { + if (m_bRememberFilePos && !m_fEndOfStream && m_dwReloadPos == 0 && m_pMS) { + auto& s = AfxGetAppSettings(); + REFERENCE_TIME rtNow = 0; + m_pMS->GetCurrentPosition(&rtNow); + m_dwReloadPos = rtNow; + s.MRU.UpdateCurrentFilePosition(rtNow, true); + } + reloadABRepeat = abRepeat; + } + + OpenCurPlaylistItem(0, true); +} + +DROPEFFECT CMainFrame::OnDropAccept(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) +{ + ClientToScreen(&point); + if (CMouse::CursorOnRootWindow(point, *this)) { + UpdateControlState(UPDATE_CONTROLS_VISIBILITY); + return (dwKeyState & MK_CONTROL) ? (DROPEFFECT_COPY | DROPEFFECT_APPEND) + : (DROPEFFECT_MOVE | DROPEFFECT_LINK | DROPEFFECT_COPY); + } + + return DROPEFFECT_NONE; +} + +bool CMainFrame::IsImageFile(CStringW fn) { + CPath path(fn); + CStringW ext(path.GetExtension()); + return IsImageFileExt(ext); +} + +bool CMainFrame::IsImageFileExt(CStringW ext) { + ext.MakeLower(); + return ( + ext == _T(".jpg") || ext == _T(".jpeg") || ext == _T(".png") || ext == _T(".gif") || ext == _T(".bmp") + || ext == _T(".tiff") || ext == _T(".jpe") || ext == _T(".tga") || ext == _T(".heic") || ext == _T(".avif") + ); +} + +bool CMainFrame::IsPlaylistFile(CStringW fn) { + CPath path(fn); + CStringW ext(path.GetExtension()); + return IsPlaylistFileExt(ext); +} + +bool CMainFrame::IsPlaylistFileExt(CStringW ext) { + return (ext == _T(".m3u") || ext == _T(".m3u8") || ext == _T(".mpcpl") || ext == _T(".pls") || ext == _T(".cue") || ext == _T(".asx")); +} + +bool CMainFrame::IsAudioOrVideoFileExt(CStringW ext) { + return IsPlayableFormatExt(ext); +} + +bool CMainFrame::IsAudioFileExt(CStringW ext) { + const CMediaFormats& mf = AfxGetAppSettings().m_Formats; + ext.MakeLower(); + return mf.FindExt(ext, true); +} + +bool CMainFrame::IsPlayableFormatExt(CStringW ext) { + const CMediaFormats& mf = AfxGetAppSettings().m_Formats; + ext.MakeLower(); + return mf.FindExt(ext); +} + +bool CMainFrame::CanSkipToExt(CStringW ext, CStringW curExt) +{ + if (IsImageFileExt(curExt)) { + return IsImageFileExt(ext); + } else { + return IsPlayableFormatExt(ext); + } +} + +BOOL IsSubtitleExtension(CString ext) +{ + return (ext == _T(".srt") || ext == _T(".ssa") || ext == _T(".ass") || ext == _T(".idx") || ext == _T(".sub") || ext == _T(".webvtt") || ext == _T(".vtt") || ext == _T(".sup") || ext == _T(".smi") || ext == _T(".psb") || ext == _T(".usf") || ext == _T(".xss") || ext == _T(".rt")|| ext == _T(".txt")); +} + +BOOL IsSubtitleFilename(CString filename) +{ + CString ext = CPath(filename).GetExtension().MakeLower(); + return IsSubtitleExtension(ext); +} + +bool CMainFrame::IsAudioFilename(CString filename) +{ + CString ext = CPath(filename).GetExtension(); + return IsAudioFileExt(ext); +} + +void CMainFrame::OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) +{ + SetForegroundWindow(); + + if (slFiles.IsEmpty()) { + return; + } + + if (slFiles.GetCount() == 1 && OpenBD(slFiles.GetHead())) { + return; + } + + PathUtils::ParseDirs(slFiles); + + bool bAppend = !!(dropEffect & DROPEFFECT_APPEND); + + // Check for subtitle files + SubtitleInput subInputSelected; + CString subfile; + BOOL onlysubs = true; + BOOL subloaded = false; + BOOL canLoadSub = !bAppend && !m_fAudioOnly && GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode(); + BOOL canLoadSubISR = canLoadSub && m_pCAP && (!m_pDVS || AfxGetAppSettings().IsISRAutoLoadEnabled()); + POSITION pos = slFiles.GetHeadPosition(); + while (pos) { + SubtitleInput subInput; + POSITION curpos = pos; + subfile = slFiles.GetNext(pos); + if (IsSubtitleFilename(subfile)) { + // remove subtitle file from list + slFiles.RemoveAt(curpos); + // try to load it + if (onlysubs && canLoadSub) { + if (canLoadSubISR && LoadSubtitle(subfile, &subInput, False)) { + if (!subInputSelected.pSubStream) { + // first one + subInputSelected = subInput; + } + subloaded = true; + } else if (m_pDVS && slFiles.IsEmpty()) { + if (SUCCEEDED(m_pDVS->put_FileName((LPWSTR)(LPCWSTR)subfile))) { + m_pDVS->put_SelectedLanguage(0); + m_pDVS->put_HideSubtitles(true); + m_pDVS->put_HideSubtitles(false); + subloaded = true; + } + } + } + } + else { + onlysubs = false; + } + } + + if (onlysubs) { + if (subInputSelected.pSubStream) { + AfxGetAppSettings().fEnableSubtitles = true; + SetSubtitle(subInputSelected); + } + if (subloaded) { + CPath fn(subfile); + fn.StripPath(); + CString statusmsg(static_cast(fn)); + SendStatusMessage(statusmsg + ResStr(IDS_SUB_LOADED_SUCCESS), 3000); + } else { + SendStatusMessage(_T("Failed to load subtitle file"), 3000); + } + return; + } + + // load http url with youtube-dl, if available + if (CanSendToYoutubeDL(slFiles.GetHead())) { + CloseMediaBeforeOpen(); + if (ProcessYoutubeDLURL(slFiles.GetHead(), bAppend)) { + if (!bAppend) { + OpenCurPlaylistItem(); + } + return; + } else if (IsOnYDLWhitelist(slFiles.GetHead())) { + // don't bother trying to open this website URL directly + return; + } + } + + // add remaining items + if (bAppend) { + m_wndPlaylistBar.Append(slFiles, true); + } else { + m_wndPlaylistBar.Open(slFiles, true); + OpenCurPlaylistItem(); + } +} + +void CMainFrame::OnFileSaveAs() +{ + CString in, out, ext; + CAppSettings& s = AfxGetAppSettings(); + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + in = pli.m_fns.GetHead(); + } else { + return; + } + + if (pli.m_bYoutubeDL || PathUtils::IsURL(in)) { + // URL + if (pli.m_bYoutubeDL) { + out = _T("%(title)s.%(ext)s"); + } else { + out = _T("choose_a_filename"); + } + } else { + out = PathUtils::StripPathOrUrl(in); + ext = CPath(out).GetExtension().MakeLower(); + if (ext == _T(".cda")) { + out = out.Left(out.GetLength() - 4) + _T(".wav"); + } else if (ext == _T(".ifo")) { + out = out.Left(out.GetLength() - 4) + _T(".vob"); + } + } + + if (!pli.m_bYoutubeDL || pli.m_ydlSourceURL.IsEmpty() || (AfxGetAppSettings().sYDLCommandLine.Find(_T("-o ")) < 0)) { + CFileDialog fd(FALSE, 0, out, + OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR, + ResStr(IDS_ALL_FILES_FILTER), GetModalParent(), 0); + if (DoFileDialogWithLastFolder(fd, s.lastFileSaveCopyPath) != IDOK || !in.CompareNoCase(fd.GetPathName())) { + return; + } else { + out = fd.GetPathName(); + } + } + + if (pli.m_bYoutubeDL && !pli.m_ydlSourceURL.IsEmpty()) { + DownloadWithYoutubeDL(pli.m_ydlSourceURL, out); + return; + } + + CPath p(out); + if (!ext.IsEmpty()) { + p.AddExtension(ext); + } + + OAFilterState fs = State_Stopped; + if (m_pMC) { + m_pMC->GetState(0, &fs); + if (fs == State_Running) { + MediaControlPause(true); + } + } + + CSaveDlg dlg(in, p); + dlg.DoModal(); + + if (m_pMC && fs == State_Running) { + MediaControlRun(); + } +} + +void CMainFrame::OnUpdateFileSaveAs(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_FILE); +} + +bool CMainFrame::GetDIB(BYTE** ppData, long& size, bool fSilent) +{ + if (!ppData) { + return false; + } + if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { + return false; + } + OAFilterState fs = GetMediaState(); + if (fs != State_Paused && fs != State_Running) { + return false; + } + + *ppData = nullptr; + size = 0; + + if (fs == State_Running && !m_pCAP) { + MediaControlPause(true); // wait for completion + } + + HRESULT hr = S_OK; + CString errmsg; + + do { + if (m_pCAP) { + hr = m_pCAP->GetDIB(nullptr, (DWORD*)&size); + if (FAILED(hr)) { + errmsg.Format(IDS_GETDIB_FAILED, hr); + break; + } + + *ppData = DEBUG_NEW BYTE[size]; + if (!(*ppData)) { + return false; + } + + hr = m_pCAP->GetDIB(*ppData, (DWORD*)&size); + if (FAILED(hr)) { + errmsg.Format(IDS_GETDIB_FAILED, hr); + break; + } + } else if (m_pMFVDC) { + // Capture with EVR + BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER)}; + BYTE* pDib; + DWORD dwSize; + REFERENCE_TIME rtImage = 0; + hr = m_pMFVDC->GetCurrentImage(&bih, &pDib, &dwSize, &rtImage); + if (FAILED(hr) || dwSize == 0) { + errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); + break; + } + + size = (long)dwSize + sizeof(BITMAPINFOHEADER); + *ppData = DEBUG_NEW BYTE[size]; + if (!(*ppData)) { + return false; + } + memcpy_s(*ppData, size, &bih, sizeof(BITMAPINFOHEADER)); + memcpy_s(*ppData + sizeof(BITMAPINFOHEADER), size - sizeof(BITMAPINFOHEADER), pDib, dwSize); + CoTaskMemFree(pDib); + } else { + hr = m_pBV->GetCurrentImage(&size, nullptr); + if (FAILED(hr) || size == 0) { + errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); + break; + } + + *ppData = DEBUG_NEW BYTE[size]; + if (!(*ppData)) { + return false; + } + + hr = m_pBV->GetCurrentImage(&size, (long*)*ppData); + if (FAILED(hr)) { + errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); + break; + } + } + } while (0); + + if (!fSilent) { + if (!errmsg.IsEmpty()) { + AfxMessageBox(errmsg, MB_OK); + } + } + + if (fs == State_Running && GetMediaState() != State_Running) { + MediaControlRun(); + } + + if (FAILED(hr)) { + SAFE_DELETE_ARRAY(*ppData); + return false; + } + + return true; +} + +void CMainFrame::SaveDIB(LPCTSTR fn, BYTE* pData, long size) +{ + CPath path(fn); + + PBITMAPINFO bi = reinterpret_cast(pData); + PBITMAPINFOHEADER bih = &bi->bmiHeader; + int bpp = bih->biBitCount; + + if (bpp != 16 && bpp != 24 && bpp != 32) { + AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); + return; + } + int w = bih->biWidth; + int h = abs(bih->biHeight); + int srcpitch = w * (bpp >> 3); + int dstpitch = (w * 3 + 3) / 4 * 4; // round w * 3 to next multiple of 4 + + BYTE* p = DEBUG_NEW BYTE[dstpitch * h]; + + const BYTE* src = pData + sizeof(*bih); + + BitBltFromRGBToRGB(w, h, p, dstpitch, 24, (BYTE*)src + srcpitch * (h - 1), -srcpitch, bpp); + + { + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); + + Gdiplus::Bitmap* bm = new Gdiplus::Bitmap(w, h, dstpitch, PixelFormat24bppRGB, p); + + UINT num; // number of image encoders + UINT arraySize; // size, in bytes, of the image encoder array + + // How many encoders are there? + // How big (in bytes) is the array of all ImageCodecInfo objects? + Gdiplus::GetImageEncodersSize(&num, &arraySize); + + // Create a buffer large enough to hold the array of ImageCodecInfo + // objects that will be returned by GetImageEncoders. + Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)DEBUG_NEW BYTE[arraySize]; + + // GetImageEncoders creates an array of ImageCodecInfo objects + // and copies that array into a previously allocated buffer. + // The third argument, imageCodecInfos, is a pointer to that buffer. + Gdiplus::GetImageEncoders(num, arraySize, pImageCodecInfo); + + Gdiplus::EncoderParameters* pEncoderParameters = nullptr; + + // Find the mime type based on the extension + CString ext(path.GetExtension()); + CStringW mime; + if (ext == _T(".jpg")) { + mime = L"image/jpeg"; + + // Set the encoder parameter for jpeg quality + pEncoderParameters = DEBUG_NEW Gdiplus::EncoderParameters; + ULONG quality = AfxGetAppSettings().nJpegQuality; + + pEncoderParameters->Count = 1; + pEncoderParameters->Parameter[0].Guid = Gdiplus::EncoderQuality; + pEncoderParameters->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong; + pEncoderParameters->Parameter[0].NumberOfValues = 1; + pEncoderParameters->Parameter[0].Value = &quality; + } else if (ext == _T(".bmp")) { + mime = L"image/bmp"; + } else { + mime = L"image/png"; + } + + // Get the encoder clsid + CLSID encoderClsid = CLSID_NULL; + for (UINT i = 0; i < num && encoderClsid == CLSID_NULL; i++) { + if (wcscmp(pImageCodecInfo[i].MimeType, mime) == 0) { + encoderClsid = pImageCodecInfo[i].Clsid; + } + } + + Gdiplus::Status s = bm->Save(fn, &encoderClsid, pEncoderParameters); + + // All GDI+ objects must be destroyed before GdiplusShutdown is called + delete bm; + delete [] pImageCodecInfo; + delete pEncoderParameters; + Gdiplus::GdiplusShutdown(gdiplusToken); + delete [] p; + + if (s != Gdiplus::Ok) { + AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); + return; + } + } + + path.m_strPath.Replace(_T("\\\\"), _T("\\")); + + SendStatusMessage(m_wndStatusBar.PreparePathStatusMessage(path), 3000); +} + +HRESULT GetBasicVideoFrame(IBasicVideo* pBasicVideo, std::vector& dib) { + // IBasicVideo::GetCurrentImage() gives the original frame + + long size; + + HRESULT hr = pBasicVideo->GetCurrentImage(&size, nullptr); + if (FAILED(hr)) { + return hr; + } + if (size <= 0) { + return E_ABORT; + } + + dib.resize(size); + + hr = pBasicVideo->GetCurrentImage(&size, (long*)dib.data()); + if (FAILED(hr)) { + dib.clear(); + } + + return hr; +} + +HRESULT GetVideoDisplayControlFrame(IMFVideoDisplayControl* pVideoDisplayControl, std::vector& dib) { + // IMFVideoDisplayControl::GetCurrentImage() gives the displayed frame + + BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER) }; + BYTE* pDib; + DWORD size; + REFERENCE_TIME rtImage = 0; + + HRESULT hr = pVideoDisplayControl->GetCurrentImage(&bih, &pDib, &size, &rtImage); + if (S_OK != hr) { + return hr; + } + if (size == 0) { + return E_ABORT; + } + + dib.resize(sizeof(BITMAPINFOHEADER) + size); + + memcpy(dib.data(), &bih, sizeof(BITMAPINFOHEADER)); + memcpy(dib.data() + sizeof(BITMAPINFOHEADER), pDib, size); + CoTaskMemFree(pDib); + + return hr; +} + +HRESULT GetMadVRFrameGrabberFrame(IMadVRFrameGrabber* pMadVRFrameGrabber, std::vector& dib, bool displayed) { + LPVOID dibImage = nullptr; + HRESULT hr; + + if (displayed) { + hr = pMadVRFrameGrabber->GrabFrame(ZOOM_PLAYBACK_SIZE, 0, 0, 0, 0, 0, &dibImage, 0); + } else { + hr = pMadVRFrameGrabber->GrabFrame(ZOOM_ENCODED_SIZE, 0, 0, 0, 0, 0, &dibImage, 0); + } + + if (S_OK != hr) { + return hr; + } + if (!dibImage) { + return E_ABORT; + } + + const BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)dibImage; + + dib.resize(sizeof(BITMAPINFOHEADER) + bih->biSizeImage); + memcpy(dib.data(), dibImage, sizeof(BITMAPINFOHEADER) + bih->biSizeImage); + LocalFree(dibImage); + + return hr; +} + +HRESULT CMainFrame::GetDisplayedImage(std::vector& dib, CString& errmsg) { + errmsg.Empty(); + HRESULT hr; + + if (m_pCAP) { + LPVOID dibImage = nullptr; + hr = m_pCAP->GetDisplayedImage(&dibImage); + + if (S_OK == hr && dibImage) { + const BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)dibImage; + dib.resize(sizeof(BITMAPINFOHEADER) + bih->biSizeImage); + memcpy(dib.data(), dibImage, sizeof(BITMAPINFOHEADER) + bih->biSizeImage); + LocalFree(dibImage); + } + } + else if (m_pMFVDC) { + hr = GetVideoDisplayControlFrame(m_pMFVDC, dib); + } else if (m_pMVRFG) { + hr = GetMadVRFrameGrabberFrame(m_pMVRFG, dib, true); + } else { + hr = E_NOINTERFACE; + } + + if (FAILED(hr)) { + errmsg.Format(L"CMainFrame::GetCurrentImage() failed, 0x%08x", hr); + } + + return hr; +} + +HRESULT CMainFrame::GetCurrentFrame(std::vector& dib, CString& errmsg) { + HRESULT hr = S_OK; + errmsg.Empty(); + + OAFilterState fs = GetMediaState(); + if (m_eMediaLoadState != MLS::LOADED || m_fAudioOnly || (fs != State_Paused && fs != State_Running)) { + return E_ABORT; + } + + if (fs == State_Running && !m_pCAP) { + MediaControlPause(true); //wait for completion + } + + if (m_pCAP) { + DWORD size; + hr = m_pCAP->GetDIB(nullptr, &size); + + if (S_OK == hr) { + dib.resize(size); + hr = m_pCAP->GetDIB(dib.data(), &size); + } + + if (FAILED(hr)) { + errmsg.Format(L"ISubPicAllocatorPresenter3::GetDIB() failed, 0x%08x", hr); + } + } else if (m_pBV) { + hr = GetBasicVideoFrame(m_pBV, dib); + + if (hr == E_NOINTERFACE && m_pMFVDC) { + // hmm, EVR is not able to give the original frame, giving the displayed image + hr = GetDisplayedImage(dib, errmsg); + } else if (FAILED(hr)) { + errmsg.Format(L"IBasicVideo::GetCurrentImage() failed, 0x%08x", hr); + } + } else { + hr = E_POINTER; + errmsg.Format(L"Interface not found!"); + } + + if (fs == State_Running && GetMediaState() != State_Running) { + MediaControlRun(); + } + + return hr; +} + +HRESULT CMainFrame::GetOriginalFrame(std::vector& dib, CString& errmsg) { + HRESULT hr = S_OK; + errmsg.Empty(); + + if (m_pMVRFG) { + hr = GetMadVRFrameGrabberFrame(m_pMVRFG, dib, false); + if (FAILED(hr)) { + errmsg.Format(L"IMadVRFrameGrabber::GrabFrame() failed, 0x%08x", hr); + } + } else { + hr = GetCurrentFrame(dib, errmsg); + } + + return hr; +} + +HRESULT CMainFrame::RenderCurrentSubtitles(BYTE* pData) { + ASSERT(m_pCAP && AfxGetAppSettings().bSnapShotSubtitles && !m_pMVRFG && AfxGetAppSettings().fEnableSubtitles && AfxGetAppSettings().IsISRAutoLoadEnabled()); + CheckPointer(pData, E_FAIL); + HRESULT hr = S_FALSE; + + if (CComQIPtr pSubPicProvider = m_pCurrentSubInput.pSubStream) { + const PBITMAPINFOHEADER bih = (PBITMAPINFOHEADER)pData; + const int width = bih->biWidth; + const int height = bih->biHeight; + + REFERENCE_TIME rtNow = 0; + m_pMS->GetCurrentPosition(&rtNow); + + int delay = m_pCAP->GetSubtitleDelay(); + if (delay != 0) { + if (delay > 0 && delay * 10000LL > rtNow) { + return S_FALSE; + } else { + rtNow -= delay * 10000LL; + } + } + + int subWidth = width; + int subHeight = height; + bool needsResize = false; + if (CPGSSub* pgsSub = dynamic_cast(pSubPicProvider.p)) { + CSize sz; + if (SUCCEEDED(pgsSub->GetPresentationSegmentTextureSize(rtNow, sz))) { + subWidth = sz.cx; + subHeight = sz.cy; + needsResize = true; + } + } + + SubPicDesc spdRender; + + spdRender.type = MSP_RGB32; + spdRender.w = subWidth; + spdRender.h = abs(subHeight); + spdRender.bpp = 32; + spdRender.pitch = subWidth * 4; + spdRender.vidrect = { 0, 0, width, height }; + spdRender.bits = DEBUG_NEW BYTE[spdRender.pitch * spdRender.h]; + + CComPtr pSubPicAllocator = DEBUG_NEW CMemSubPicAllocator(spdRender.type, CSize(spdRender.w, spdRender.h)); + + CMemSubPic memSubPic(spdRender, pSubPicAllocator); + memSubPic.SetInverseAlpha(false); + memSubPic.ClearDirtyRect(); + + RECT bbox = {}; + hr = pSubPicProvider->Render(spdRender, rtNow, m_pCAP->GetFPS(), bbox); + if (needsResize) { + memSubPic.UnlockARGB(); + } + + if (S_OK == hr) { + SubPicDesc spdTarget; + spdTarget.type = MSP_RGB32; + spdTarget.w = width; + spdTarget.h = height; + spdTarget.bpp = 32; + spdTarget.pitch = -width * 4; + spdTarget.vidrect = { 0, 0, width, height }; + spdTarget.bits = (BYTE*)(bih + 1) + (width * 4) * (height - 1); + + hr = memSubPic.AlphaBlt(&spdRender.vidrect, &spdTarget.vidrect, &spdTarget); + } + } + + return hr; +} + +void CMainFrame::SaveImage(LPCWSTR fn, bool displayed, bool includeSubtitles) { + std::vector dib; + CString errmsg; + HRESULT hr; + if (displayed) { + hr = GetDisplayedImage(dib, errmsg); + } else { + hr = GetCurrentFrame(dib, errmsg); + if (includeSubtitles && m_pCAP && hr == S_OK) { + RenderCurrentSubtitles(dib.data()); + } + } + + if (hr == S_OK) { + SaveDIB(fn, dib.data(), (long)dib.size()); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_IMAGE_SAVED), 3000); + } else { + m_OSD.DisplayMessage(OSD_TOPLEFT, errmsg, 3000); + } +} + +void CMainFrame::SaveThumbnails(LPCTSTR fn) +{ + if (!m_pMC || !m_pMS || GetPlaybackMode() != PM_FILE /*&& GetPlaybackMode() != PM_DVD*/) { + return; + } + + REFERENCE_TIME rtPos = GetPos(); + REFERENCE_TIME rtDur = GetDur(); + + if (rtDur <= 0) { + AfxMessageBox(IDS_THUMBNAILS_NO_DURATION, MB_ICONWARNING | MB_OK, 0); + return; + } + + OAFilterState filterState = UpdateCachedMediaState(); + bool bWasStopped = (filterState == State_Stopped); + if (filterState != State_Paused) { + OnPlayPause(); + } + + CSize szVideoARCorrected, szVideo, szAR; + + if (m_pCAP) { + szVideo = m_pCAP->GetVideoSize(false); + szAR = m_pCAP->GetVideoSize(true); + } else if (m_pMFVDC) { + VERIFY(SUCCEEDED(m_pMFVDC->GetNativeVideoSize(&szVideo, &szAR))); + } else { + VERIFY(SUCCEEDED(m_pBV->GetVideoSize(&szVideo.cx, &szVideo.cy))); + + CComQIPtr pBV2 = m_pBV; + long lARx = 0, lARy = 0; + if (pBV2 && SUCCEEDED(pBV2->GetPreferredAspectRatio(&lARx, &lARy)) && lARx > 0 && lARy > 0) { + szAR.SetSize(lARx, lARy); + } + } + + if (szVideo.cx <= 0 || szVideo.cy <= 0) { + AfxMessageBox(IDS_THUMBNAILS_NO_FRAME_SIZE, MB_ICONWARNING | MB_OK, 0); + return; + } + + // with the overlay mixer IBasicVideo2 won't tell the new AR when changed dynamically + DVD_VideoAttributes VATR; + if (GetPlaybackMode() == PM_DVD && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { + szAR.SetSize(VATR.ulAspectX, VATR.ulAspectY); + } + + szVideoARCorrected = (szAR.cx <= 0 || szAR.cy <= 0) ? szVideo : CSize(MulDiv(szVideo.cy, szAR.cx, szAR.cy), szVideo.cy); + + const CAppSettings& s = AfxGetAppSettings(); + + int cols = std::clamp(s.iThumbCols, 1, 16); + int rows = std::clamp(s.iThumbRows, 1, 40); + + const int margin = 5; + int width = std::clamp(s.iThumbWidth, 256, 3840); + float fontscale = width / 1280.0; + int fontsize = fontscale * 16; + const int infoheight = 4 * fontsize + 6 + 2 * margin; + int height = width * szVideoARCorrected.cy / szVideoARCorrected.cx * rows / cols + infoheight; + + int dibsize = sizeof(BITMAPINFOHEADER) + width * height * 4; + + CAutoVectorPtr dib; + if (!dib.Allocate(dibsize)) { + AfxMessageBox(IDS_OUT_OF_MEMORY, MB_ICONWARNING | MB_OK, 0); + return; + } + + BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)(BYTE*)dib; + ZeroMemory(bih, sizeof(BITMAPINFOHEADER)); + bih->biSize = sizeof(BITMAPINFOHEADER); + bih->biWidth = width; + bih->biHeight = height; + bih->biPlanes = 1; + bih->biBitCount = 32; + bih->biCompression = BI_RGB; + bih->biSizeImage = width * height * 4; + memsetd(bih + 1, 0xffffff, bih->biSizeImage); + + SubPicDesc spd; + spd.w = width; + spd.h = height; + spd.bpp = 32; + spd.pitch = -width * 4; + spd.vidrect = CRect(0, 0, width, height); + spd.bits = (BYTE*)(bih + 1) + (width * 4) * (height - 1); + + bool darktheme = s.bMPCTheme && s.eModernThemeMode == CMPCTheme::ModernThemeMode::DARK; + + int gradientBase = 0xe0; + if (darktheme) { + gradientBase = 0x00; + } + // Paint the background + { + BYTE* p = (BYTE*)spd.bits; + for (int y = 0; y < spd.h; y++, p += spd.pitch) { + for (int x = 0; x < spd.w; x++) { + ((DWORD*)p)[x] = 0x010101 * (gradientBase + 0x08 * y / spd.h + 0x18 * (spd.w - x) / spd.w); + } + } + } + + CCritSec csSubLock; + RECT bbox; + CSize szThumbnail((width - margin * 2) / cols - margin * 2, (height - margin * 2 - infoheight) / rows - margin * 2); + // Ensure the thumbnails aren't ridiculously small so that the time indication can at least fit + if (szThumbnail.cx < 60 || szThumbnail.cy < 20) { + AfxMessageBox(IDS_THUMBNAIL_TOO_SMALL, MB_ICONWARNING | MB_OK, 0); + return; + } + + m_nVolumeBeforeFrameStepping = m_wndToolBar.Volume; + if (m_pBA) { + m_pBA->put_Volume(-10000); + } + + // Draw the thumbnails + std::unique_ptr thumb(new(std::nothrow) BYTE[szThumbnail.cx * szThumbnail.cy * 4]); + if (!thumb) { + return; + } + + int pics = cols * rows; + REFERENCE_TIME rtInterval = rtDur / (pics + 1LL); + for (int i = 1; i <= pics; i++) { + REFERENCE_TIME rt = rtInterval * i; + // use a keyframe if close to target time + if (rtInterval >= 100000000LL) { + REFERENCE_TIME rtMaxDiff = std::min(100000000LL, rtInterval / 10); // no more than 10 sec + rt = GetClosestKeyFrame(rt, rtMaxDiff, rtMaxDiff); + } + + DoSeekTo(rt, false); + UpdateWindow(); + + HRESULT hr = m_pFS ? m_pFS->Step(1, nullptr) : E_FAIL; + if (FAILED(hr)) { + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + AfxMessageBox(IDS_FRAME_STEP_ERROR_RENDERER, MB_ICONEXCLAMATION | MB_OK, 0); + return; + } + + bool abortloop = false; + HANDLE hGraphEvent = nullptr; + m_pME->GetEventHandle((OAEVENT*)&hGraphEvent); + while (hGraphEvent) { + DWORD res = WaitForSingleObject(hGraphEvent, 5000); + if (res == WAIT_OBJECT_0) { + LONG evCode = 0; + LONG_PTR evParam1, evParam2; + while (m_pME && SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) { + m_pME->FreeEventParams(evCode, evParam1, evParam2); + if (EC_STEP_COMPLETE == evCode) { + hGraphEvent = nullptr; + } + } + } else { + hGraphEvent = nullptr; + if (res == WAIT_TIMEOUT) { + // Likely a seek failure has occurred. For example due to an incomplete file. + REFERENCE_TIME rtCur = 0; + m_pMS->GetCurrentPosition(&rtCur); + if (rtCur >= rtDur) { + abortloop = true; + } + } + } + } + + if (abortloop) { + break; + } + + int col = (i - 1) % cols; + int row = (i - 1) / cols; + + CPoint p(2 * margin + col * (szThumbnail.cx + 2 * margin), infoheight + 2 * margin + row * (szThumbnail.cy + 2 * margin)); + CRect r(p, szThumbnail); + + CRenderedTextSubtitle rts(&csSubLock); + rts.m_SubRendererSettings.renderSSAUsingLibass = false; + rts.m_SubRendererSettings.overrideDefaultStyle = false; + rts.m_SubRendererSettings.overrideAllStyles = false; + rts.CreateDefaultStyle(0); + rts.m_storageRes = rts.m_playRes = CSize(width, height); + STSStyle* style = DEBUG_NEW STSStyle(); + style->fontName = L"Calibri"; + style->marginRect.SetRectEmpty(); + rts.AddStyle(_T("thumbs"), style); + + DVD_HMSF_TIMECODE hmsf = RT2HMS_r(rt); + CStringW str; + if (!darktheme) { + str.Format(L"{\\an7\\1c&Hffffff&\\4a&Hb0&\\bord1\\shad4\\be1}{\\p1}m %d %d l %d %d %d %d %d %d{\\p}", + r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom); + rts.Add(str, true, MS2RT(0), MS2RT(1), _T("thumbs")); // Thumbnail background + } + str.Format(L"{\\an3\\1c&Hffffff&\\3c&H000000&\\alpha&H80&\\fs%d\\b1\\bord2\\shad0\\pos(%d,%d)}%02u:%02u:%02u", + fontsize, r.right - 5, r.bottom - 3, hmsf.bHours, hmsf.bMinutes, hmsf.bSeconds); + rts.Add(str, true, MS2RT(1), MS2RT(2), _T("thumbs")); // Thumbnail time + + rts.Render(spd, 0, 25, bbox); // Draw the thumbnail background/time + + BYTE* pData = nullptr; + long size = 0; + if (!GetDIB(&pData, size)) { + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + return; + } + + BITMAPINFO* bi = (BITMAPINFO*)pData; + + if (bi->bmiHeader.biBitCount != 32) { + CString strTemp; + strTemp.Format(IDS_THUMBNAILS_INVALID_FORMAT, bi->bmiHeader.biBitCount); + AfxMessageBox(strTemp); + delete [] pData; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + return; + } + + int sw = bi->bmiHeader.biWidth; + int sh = abs(bi->bmiHeader.biHeight); + int sp = sw * 4; + const BYTE* src = pData + sizeof(bi->bmiHeader); + + stbir_resize(src, sw, sh, sp, thumb.get(), szThumbnail.cx, szThumbnail.cy, szThumbnail.cx * 4, STBIR_RGBA_PM, STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT); + + BYTE* dst = spd.bits + spd.pitch * r.top + r.left * 4; + + const BYTE* tsrc = thumb.get(); + int tsrcPitch = szThumbnail.cx * 4; + if (bi->bmiHeader.biHeight >= 0) { + tsrc += tsrcPitch * (szThumbnail.cy - 1); + tsrcPitch = -tsrcPitch; + } + for (int y = 0; y < szThumbnail.cy; y++, dst += spd.pitch, tsrc += tsrcPitch) { + memcpy(dst, tsrc, abs(tsrcPitch)); + } + + rts.Render(spd, 10000, 25, bbox); // Draw the thumbnail time + + delete [] pData; + } + + // Draw the file information + { + CRenderedTextSubtitle rts(&csSubLock); + rts.m_SubRendererSettings.renderSSAUsingLibass = false; + rts.m_SubRendererSettings.overrideDefaultStyle = false; + rts.m_SubRendererSettings.overrideAllStyles = false; + rts.CreateDefaultStyle(0); + rts.m_storageRes = rts.m_playRes = CSize(width, height); + STSStyle* style = DEBUG_NEW STSStyle(); + // Use System UI font. + CFont tempFont; + CMPCThemeUtil::getFontByType(tempFont, nullptr, CMPCThemeUtil::MessageFont); + LOGFONT lf; + if (tempFont.GetLogFont(&lf)) { + CString fontName(lf.lfFaceName); + style->fontName = fontName; + } + style->marginRect.SetRect(margin * 2, margin * 2, margin * 2, height - infoheight - margin); + rts.AddStyle(_T("thumbs"), style); + + CStringW str; + str.Format(L"{\\an9\\fs%d\\b1\\bord0\\shad0\\1c&Hffffff&}%s", infoheight - 2 * margin, L"MPC-HC"); + if (darktheme) { + str.Replace(L"\\1c&Hffffff", L"\\1c&Hc8c8c8"); + } + rts.Add(str, true, 0, 1, _T("thumbs"), _T(""), _T(""), CRect(0, 0, 0, 0), -1); + + DVD_HMSF_TIMECODE hmsf = RT2HMS_r(rtDur); + + CString title; + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_bYoutubeDL && pli.m_label && !pli.m_label.IsEmpty()) { + title = pli.m_label; + } else { + title = GetFileName(); + } + + CStringW fs; + CString curfile = m_wndPlaylistBar.GetCurFileName(); + if (!PathUtils::IsURL(curfile)) { + ExtendMaxPathLengthIfNeeded(curfile, true); + WIN32_FIND_DATA wfd; + HANDLE hFind = FindFirstFile(curfile, &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); + fs.Format(IDS_THUMBNAILS_INFO_FILESIZE, szFileSize, FormatNumber(szByteSize).GetString()); + } + } + + CStringW ar; + if (szAR.cx > 0 && szAR.cy > 0 && szAR.cx != szVideo.cx && szAR.cy != szVideo.cy) { + ar.Format(L"(%ld:%ld)", szAR.cx, szAR.cy); + } + CStringW fmt = ResStr(IDS_THUMBNAILS_INFO_HEADER); + if (darktheme) { + fmt.Replace(L"\\1c&H000000", L"\\1c&Hc8c8c8"); + } + str.Format(fmt, fontsize, + title.GetString(), fs.GetString(), szVideo.cx, szVideo.cy, ar.GetString(), hmsf.bHours, hmsf.bMinutes, hmsf.bSeconds); + rts.Add(str, true, 0, 1, _T("thumbs")); + + rts.Render(spd, 0, 25, bbox); + } + + SaveDIB(fn, (BYTE*)dib, dibsize); + + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + + if (bWasStopped) { + OnPlayStop(); + } else { + DoSeekTo(rtPos, false); + } + + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_THUMBS_SAVED), 3000); +} + +CString CMainFrame::MakeSnapshotFileName(BOOL thumbnails) +{ + CAppSettings& s = AfxGetAppSettings(); + CString prefix; + CString fn; + + ASSERT(!thumbnails || GetPlaybackMode() == PM_FILE); + + auto videoFn = GetFileName(); + auto fullName = m_wndPlaylistBar.GetCurFileName(true); + bool needsExtensionRemoval = !s.bSnapShotKeepVideoExtension; + if (IsPlaylistFile(videoFn)) { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + videoFn = pli.m_label; + needsExtensionRemoval = false; + } + } else if (needsExtensionRemoval && PathUtils::IsURL(fullName)){ + auto title = getBestTitle(); + if (!title.IsEmpty()) { + videoFn = title; + needsExtensionRemoval = false; + } + } + + + if (needsExtensionRemoval) { + int nPos = videoFn.ReverseFind('.'); + if (nPos != -1) { + videoFn = videoFn.Left(nPos); + } + } + + bool saveImagePosition, saveImageCurrentTime; + + if (m_wndSeekBar.HasDuration()) { + saveImagePosition = s.bSaveImagePosition; + saveImageCurrentTime = s.bSaveImageCurrentTime; + } else { + saveImagePosition = false; + saveImageCurrentTime = true; + } + + if (GetPlaybackMode() == PM_FILE) { + if (thumbnails) { + prefix.Format(_T("%s_thumbs"), videoFn.GetString()); + } else { + if (saveImagePosition) { + prefix.Format(_T("%s_snapshot_%s"), videoFn.GetString(), GetVidPos().GetString()); + } else { + prefix.Format(_T("%s_snapshot"), videoFn.GetString()); + } + } + } else if (GetPlaybackMode() == PM_DVD) { + if (saveImagePosition) { + prefix.Format(_T("dvd_snapshot_%s"), GetVidPos().GetString()); + } else { + prefix = _T("dvd_snapshot"); + } + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + prefix.Format(_T("%s_snapshot"), m_pDVBState->sChannelName.GetString()); + } else { + prefix = _T("snapshot"); + } + + if (!thumbnails && saveImageCurrentTime) { + CTime t = CTime::GetCurrentTime(); + fn.Format(_T("%s_[%s]%s"), PathUtils::FilterInvalidCharsFromFileName(prefix).GetString(), t.Format(_T("%Y.%m.%d_%H.%M.%S")).GetString(), s.strSnapshotExt.GetString()); + } else { + fn.Format(_T("%s%s"), PathUtils::FilterInvalidCharsFromFileName(prefix).GetString(), s.strSnapshotExt.GetString()); + } + return fn; +} + +BOOL CMainFrame::IsRendererCompatibleWithSaveImage() +{ + BOOL result = TRUE; + const CAppSettings& s = AfxGetAppSettings(); + + if (m_fShockwaveGraph) { + AfxMessageBox(IDS_SCREENSHOT_ERROR_SHOCKWAVE, MB_ICONEXCLAMATION | MB_OK, 0); + result = FALSE; + } else if (s.iDSVideoRendererType == VIDRNDT_DS_OVERLAYMIXER) { + AfxMessageBox(IDS_SCREENSHOT_ERROR_OVERLAY, MB_ICONEXCLAMATION | MB_OK, 0); + result = FALSE; + } + + return result; +} + +CString CMainFrame::GetVidPos() const +{ + CString posstr = _T(""); + if ((GetPlaybackMode() == PM_FILE) || (GetPlaybackMode() == PM_DVD)) { + __int64 start, stop, pos; + m_wndSeekBar.GetRange(start, stop); + pos = m_wndSeekBar.GetPos(); + + DVD_HMSF_TIMECODE tcNow = RT2HMSF(pos); + DVD_HMSF_TIMECODE tcDur = RT2HMSF(stop); + + if (tcDur.bHours > 0 || tcNow.bHours > 0) { + posstr.Format(_T("%02u.%02u.%02u.%03u"), tcNow.bHours, tcNow.bMinutes, tcNow.bSeconds, (pos / 10000) % 1000); + } else { + posstr.Format(_T("%02u.%02u.%03u"), tcNow.bMinutes, tcNow.bSeconds, (pos / 10000) % 1000); + } + } + + return posstr; +} + +void CMainFrame::OnFileSaveImage() +{ + CAppSettings& s = AfxGetAppSettings(); + + /* Check if a compatible renderer is being used */ + if (!IsRendererCompatibleWithSaveImage()) { + return; + } + + CPath psrc(s.strSnapshotPath); + psrc.Combine(s.strSnapshotPath.GetString(), MakeSnapshotFileName(FALSE)); + + bool subtitleOptionSupported = !m_pMVRFG && s.fEnableSubtitles && s.IsISRAutoLoadEnabled(); + + CSaveImageDialog fd(s.nJpegQuality, s.strSnapshotExt, (LPCTSTR)psrc, + _T("BMP - Windows Bitmap (*.bmp)|*.bmp|JPG - JPEG Image (*.jpg)|*.jpg|PNG - Portable Network Graphics (*.png)|*.png||"), GetModalParent(), subtitleOptionSupported); + + if (s.strSnapshotExt == _T(".bmp")) { + fd.m_pOFN->nFilterIndex = 1; + } else if (s.strSnapshotExt == _T(".jpg")) { + fd.m_pOFN->nFilterIndex = 2; + } else if (s.strSnapshotExt == _T(".png")) { + fd.m_pOFN->nFilterIndex = 3; + } + + if (fd.DoModal() != IDOK) { + return; + } + + if (fd.m_pOFN->nFilterIndex == 1) { + s.strSnapshotExt = _T(".bmp"); + } else if (fd.m_pOFN->nFilterIndex == 2) { + s.strSnapshotExt = _T(".jpg"); + s.nJpegQuality = fd.m_nJpegQuality; + } else { + fd.m_pOFN->nFilterIndex = 3; + s.strSnapshotExt = _T(".png"); + } + + CPath pdst(fd.GetPathName()); + CString ext(pdst.GetExtension().MakeLower()); + if (ext != s.strSnapshotExt) { + if (ext == _T(".bmp") || ext == _T(".jpg") || ext == _T(".png")) { + ext = s.strSnapshotExt; + } else { + ext += s.strSnapshotExt; + } + pdst.RenameExtension(ext); + } + CString path = (LPCTSTR)pdst; + pdst.RemoveFileSpec(); + s.strSnapshotPath = (LPCTSTR)pdst; + + bool includeSubtitles = subtitleOptionSupported && s.bSnapShotSubtitles; + + SaveImage(path, false, includeSubtitles); +} + +void CMainFrame::OnFileSaveImageAuto() +{ + const CAppSettings& s = AfxGetAppSettings(); + + // If path doesn't exist, Save Image instead + if (!PathUtils::IsDir(s.strSnapshotPath)) { + AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); + OnFileSaveImage(); + return; + } + + /* Check if a compatible renderer is being used */ + if (!IsRendererCompatibleWithSaveImage()) { + return; + } + + bool includeSubtitles = s.bSnapShotSubtitles && !m_pMVRFG && s.fEnableSubtitles && s.IsISRAutoLoadEnabled(); + + CString fn; + fn.Format(_T("%s\\%s"), s.strSnapshotPath.GetString(), MakeSnapshotFileName(FALSE).GetString()); + SaveImage(fn.GetString(), false, includeSubtitles); +} + +void CMainFrame::OnUpdateFileSaveImage(CCmdUI* pCmdUI) +{ + OAFilterState fs = GetMediaState(); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (fs == State_Paused || fs == State_Running)); +} + +void CMainFrame::OnCmdLineSaveThumbnails() +{ + CAppSettings& s = AfxGetAppSettings(); + + /* Check if a compatible renderer is being used */ + if (!IsRendererCompatibleWithSaveImage()) { + return; + } + + CPlaylistItem pli; + if (!m_wndPlaylistBar.GetCur(pli, true)) { + return; + } + + CPath psrc(m_wndPlaylistBar.GetCurFileName(true)); + psrc.RemoveFileSpec(); + psrc.Combine(psrc, MakeSnapshotFileName(TRUE)); + + s.iThumbRows = std::clamp(s.iThumbRows, 1, 40); + s.iThumbCols = std::clamp(s.iThumbCols, 1, 16); + s.iThumbWidth = std::clamp(s.iThumbWidth, 256, 3840); + + CString path = (LPCTSTR)psrc; + + SaveThumbnails(path); + +} + +void CMainFrame::OnFileSaveThumbnails() +{ + CAppSettings& s = AfxGetAppSettings(); + + /* Check if a compatible renderer is being used */ + if (!IsRendererCompatibleWithSaveImage()) { + return; + } + + CPath psrc(s.strSnapshotPath); + psrc.Combine(s.strSnapshotPath, MakeSnapshotFileName(TRUE)); + + CSaveThumbnailsDialog fd(s.nJpegQuality, s.iThumbRows, s.iThumbCols, s.iThumbWidth, s.strSnapshotExt, (LPCTSTR)psrc, + _T("BMP - Windows Bitmap (*.bmp)|*.bmp|JPG - JPEG Image (*.jpg)|*.jpg|PNG - Portable Network Graphics (*.png)|*.png||"), GetModalParent()); + + if (s.strSnapshotExt == _T(".bmp")) { + fd.m_pOFN->nFilterIndex = 1; + } else if (s.strSnapshotExt == _T(".jpg")) { + fd.m_pOFN->nFilterIndex = 2; + } else if (s.strSnapshotExt == _T(".png")) { + fd.m_pOFN->nFilterIndex = 3; + } + + if (fd.DoModal() != IDOK) { + return; + } + + if (fd.m_pOFN->nFilterIndex == 1) { + s.strSnapshotExt = _T(".bmp"); + } else if (fd.m_pOFN->nFilterIndex == 2) { + s.strSnapshotExt = _T(".jpg"); + s.nJpegQuality = fd.m_nJpegQuality; + } else { + fd.m_pOFN->nFilterIndex = 3; + s.strSnapshotExt = _T(".png"); + } + + s.iThumbRows = std::clamp(fd.m_rows, 1, 40); + s.iThumbCols = std::clamp(fd.m_cols, 1, 16); + s.iThumbWidth = std::clamp(fd.m_width, 256, 3840); + + CPath pdst(fd.GetPathName()); + CString ext(pdst.GetExtension().MakeLower()); + if (ext != s.strSnapshotExt) { + if (ext == _T(".bmp") || ext == _T(".jpg") || ext == _T(".png")) { + ext = s.strSnapshotExt; + } else { + ext += s.strSnapshotExt; + } + pdst.RenameExtension(ext); + } + CString path = (LPCTSTR)pdst; + pdst.RemoveFileSpec(); + s.strSnapshotPath = (LPCTSTR)pdst; + + SaveThumbnails(path); +} + +void CMainFrame::OnUpdateFileSaveThumbnails(CCmdUI* pCmdUI) +{ + OAFilterState fs = GetMediaState(); + UNREFERENCED_PARAMETER(fs); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (GetPlaybackMode() == PM_FILE /*|| GetPlaybackMode() == PM_DVD*/)); +} + +void CMainFrame::OnFileSubtitlesLoad() +{ + if (!m_pCAP && !m_pDVS) { + AfxMessageBox(IDS_CANNOT_LOAD_SUB, MB_ICONINFORMATION | MB_OK, 0); + return; + } + + DWORD dwFlags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_NOCHANGEDIR; + if (!AfxGetAppSettings().fKeepHistory) { + dwFlags |= OFN_DONTADDTORECENT; + } + CString filters; + filters.Format(_T("%s|*.srt;*.sub;*.ssa;*.ass;*.smi;*.psb;*.txt;*.idx;*.usf;*.xss;*.rt;*.sup;*.webvtt;*.vtt|%s"), + ResStr(IDS_SUBTITLE_FILES_FILTER).GetString(), ResStr(IDS_ALL_FILES_FILTER).GetString()); + + CFileDialog fd(TRUE, nullptr, nullptr, dwFlags, filters, GetModalParent()); + + OPENFILENAME& ofn = fd.GetOFN(); + // Provide a buffer big enough to hold 16 paths (which should be more than enough) + const int nBufferSize = 16 * (MAX_PATH + 1) + 1; + CString filenames; + ofn.lpstrFile = filenames.GetBuffer(nBufferSize); + ofn.nMaxFile = nBufferSize; + // Set the current file directory as default folder + CString curfile = m_wndPlaylistBar.GetCurFileName(); + if (!PathUtils::IsURL(curfile)) { + CPath defaultDir(curfile); + defaultDir.RemoveFileSpec(); + if (!defaultDir.m_strPath.IsEmpty()) { + ofn.lpstrInitialDir = defaultDir.m_strPath; + } + } + + if (fd.DoModal() == IDOK) { + bool bFirstFile = true; + POSITION pos = fd.GetStartPosition(); + while (pos) { + CString subfile = fd.GetNextPathName(pos); + if (m_pDVS) { + if (SUCCEEDED(m_pDVS->put_FileName((LPWSTR)(LPCWSTR)subfile))) { + m_pDVS->put_SelectedLanguage(0); + m_pDVS->put_HideSubtitles(true); + m_pDVS->put_HideSubtitles(false); + break; + } + } else { + SubtitleInput subInput; + if (LoadSubtitle(subfile, &subInput) && bFirstFile) { + bFirstFile = false; + // Use the subtitles file that was just added + AfxGetAppSettings().fEnableSubtitles = true; + SetSubtitle(subInput); + } + } + } + } +} + +void CMainFrame::OnUpdateFileSubtitlesLoad(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(!m_fAudioOnly && (m_pCAP || m_pDVS) && GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode()); +} + +void CMainFrame::SubtitlesSave(const TCHAR* directory, bool silent) +{ + if (lastOpenFile.IsEmpty()) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + + int i = 0; + SubtitleInput* pSubInput = GetSubtitleInput(i, true); + if (!pSubInput) { + return; + } + + CLSID clsid; + if (FAILED(pSubInput->pSubStream->GetClassID(&clsid))) { + return; + } + + CString suggestedFileName; + if (PathUtils::IsURL(lastOpenFile)) { + if (silent) { + return; + } + suggestedFileName = _T("subtitle"); + } else { + CPath path(lastOpenFile); + path.RemoveExtension(); + suggestedFileName = CString(path); + } + + if (directory && *directory) { + CPath suggestedPath(suggestedFileName); + int pos = suggestedPath.FindFileName(); + CString fileName = suggestedPath.m_strPath.Mid(pos); + CPath dirPath(directory); + if (dirPath.IsRelative()) { + dirPath = CPath(suggestedPath.m_strPath.Left(pos)) += dirPath; + } + if (EnsureDirectory(dirPath)) { + suggestedFileName = CString(dirPath += fileName); + } + else if (silent) { + return; + } + } + + bool isSaved = false; + if (clsid == __uuidof(CVobSubFile)) { + CVobSubFile* pVSF = (CVobSubFile*)(ISubStream*)pSubInput->pSubStream; + + // remember to set lpszDefExt to the first extension in the filter so that the save dialog autocompletes the extension + // and tracks attempts to overwrite in a graceful manner + if (silent) { + isSaved = pVSF->Save(suggestedFileName + _T(".idx"), m_pCAP->GetSubtitleDelay()); + } else { + CSaveSubtitlesFileDialog fd(m_pCAP->GetSubtitleDelay(), _T("idx"), suggestedFileName, + _T("VobSub (*.idx, *.sub)|*.idx;*.sub||"), GetModalParent()); + + if (fd.DoModal() == IDOK) { + CAutoLock cAutoLock(&m_csSubLock); + isSaved = pVSF->Save(fd.GetPathName(), fd.GetDelay()); + } + } + } + else if (clsid == __uuidof(CRenderedTextSubtitle)) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; + + if (s.bAddLangCodeWhenSaveSubtitles && pRTS->m_lcid && pRTS->m_lcid != LCID(-1)) { + CString str; + GetLocaleString(pRTS->m_lcid, LOCALE_SISO639LANGNAME, str); + suggestedFileName += _T('.') + str; + + if (pRTS->m_eHearingImpaired == Subtitle::HI_YES) { + suggestedFileName += _T(".hi"); + } + } + + // same thing as in the case of CVobSubFile above for lpszDefExt + if (silent) { + Subtitle::SubType type; + switch (pRTS->m_subtitleType) + { + case Subtitle::ASS: + case Subtitle::SSA: + case Subtitle::VTT: + type = Subtitle::ASS; + break; + default: + type = Subtitle::SRT; + } + + isSaved = pRTS->SaveAs( + suggestedFileName, type, m_pCAP->GetFPS(), m_pCAP->GetSubtitleDelay(), + CTextFile::DEFAULT_ENCODING, s.bSubSaveExternalStyleFile); + } else { + const std::vector types = { + Subtitle::SRT, + Subtitle::SUB, + Subtitle::SMI, + Subtitle::PSB, + Subtitle::SSA, + Subtitle::ASS + }; + + CString filter; + filter += _T("SubRip (*.srt)|*.srt|"); //1 = default + filter += _T("MicroDVD (*.sub)|*.sub|"); //2 + filter += _T("SAMI (*.smi)|*.smi|"); //3 + filter += _T("PowerDivX (*.psb)|*.psb|"); //4 + filter += _T("SubStation Alpha (*.ssa)|*.ssa|"); //5 + filter += _T("Advanced SubStation Alpha (*.ass)|*.ass|"); //6 + filter += _T("|"); + + CSaveSubtitlesFileDialog fd(pRTS->m_encoding, m_pCAP->GetSubtitleDelay(), s.bSubSaveExternalStyleFile, + _T("srt"), suggestedFileName, filter, types, GetModalParent()); + + if (pRTS->m_subtitleType == Subtitle::SSA || pRTS->m_subtitleType == Subtitle::ASS) { + fd.m_ofn.nFilterIndex = 6; //nFilterIndex is 1-based + } + + if (fd.DoModal() == IDOK) { + CAutoLock cAutoLock(&m_csSubLock); + s.bSubSaveExternalStyleFile = fd.GetSaveExternalStyleFile(); + isSaved = pRTS->SaveAs(fd.GetPathName(), types[fd.m_ofn.nFilterIndex - 1], m_pCAP->GetFPS(), fd.GetDelay(), fd.GetEncoding(), fd.GetSaveExternalStyleFile()); + } + } + } + else { + AfxMessageBox(_T("This operation is not supported.\r\nThe selected subtitles cannot be saved."), MB_ICONEXCLAMATION | MB_OK); + } + + if (isSaved && s.fKeepHistory) { + auto subPath = pSubInput->pSubStream->GetPath(); + if (!subPath.IsEmpty()) { + s.MRU.AddSubToCurrent(subPath); + } + } +} + +void CMainFrame::OnUpdateFileSubtitlesSave(CCmdUI* pCmdUI) +{ + bool bEnable = false; + + if (!m_pCurrentSubInput.pSourceFilter) { + if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { + bEnable = !pRTS->IsEmpty(); + } else if (dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { + bEnable = true; + } + } + + pCmdUI->Enable(bEnable); +} + +#if 0 +void CMainFrame::OnFileSubtitlesUpload() +{ + m_wndSubtitlesUploadDialog.ShowWindow(SW_SHOW); +} + +void CMainFrame::OnUpdateFileSubtitlesUpload(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(!m_pSubStreams.IsEmpty() && s.fEnableSubtitles); +} +#endif + +void CMainFrame::OnFileSubtitlesDownload() +{ + if (!m_fAudioOnly) { + if (m_pCAP && AfxGetAppSettings().IsISRAutoLoadEnabled()) { + m_wndSubtitlesDownloadDialog.ShowWindow(SW_SHOW); + } else { + AfxMessageBox(_T("Downloading subtitles only works when using the internal subtitle renderer."), MB_ICONINFORMATION | MB_OK, 0); + } + } +} + +void CMainFrame::OnUpdateFileSubtitlesDownload(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode() && m_pCAP && !m_fAudioOnly); +} + +void CMainFrame::OnFileProperties() +{ + CString fn; + CString ydlsrc; + if (m_pDVBState) { + fn = m_pDVBState->sChannelName; + } else { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + fn = pli.m_fns.GetHead(); + if (pli.m_bYoutubeDL) { + ydlsrc = pli.m_ydlSourceURL; + } + } + } + + ASSERT(!fn.IsEmpty()); + + CPPageFileInfoSheet fileinfo(fn, ydlsrc, this, GetModalParent()); + fileinfo.DoModal(); +} + +void CMainFrame::OnUpdateFileProperties(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() != PM_ANALOG_CAPTURE); +} + +void CMainFrame::OnFileOpenLocation() { + CString filePath = m_wndPlaylistBar.GetCurFileName(); + if (!PathUtils::IsURL(filePath)) { + ExploreToFile(filePath); + } +} + +void CMainFrame::OnFileCloseMedia() +{ + CloseMedia(); +} + +void CMainFrame::OnUpdateViewTearingTest(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC); + + pCmdUI->Enable(supported && GetLoadState() == MLS::LOADED && !m_fAudioOnly); + pCmdUI->SetCheck(supported && AfxGetMyApp()->m_Renderers.m_bTearingTest); +} + +void CMainFrame::OnViewTearingTest() +{ + AfxGetMyApp()->m_Renderers.m_bTearingTest = !AfxGetMyApp()->m_Renderers.m_bTearingTest; +} + +void CMainFrame::OnUpdateViewDisplayRendererStats(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); + + pCmdUI->Enable(supported && GetLoadState() == MLS::LOADED && !m_fAudioOnly); + pCmdUI->SetCheck(supported && AfxGetMyApp()->m_Renderers.m_iDisplayStats > 0); +} + +void CMainFrame::OnViewResetRendererStats() +{ + AfxGetMyApp()->m_Renderers.m_bResetStats = true; // Reset by "consumer" +} + +void CMainFrame::OnViewDisplayRendererStats() +{ + const CAppSettings& s = AfxGetAppSettings(); + bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); + + if (supported) { + if (m_pCAP3) { + m_pCAP3->ToggleStats(); + return; + } + + if (!AfxGetMyApp()->m_Renderers.m_iDisplayStats) { + AfxGetMyApp()->m_Renderers.m_bResetStats = true; // to reset statistics on first call ... + } + + ++AfxGetMyApp()->m_Renderers.m_iDisplayStats; + if (AfxGetMyApp()->m_Renderers.m_iDisplayStats > 3) { + AfxGetMyApp()->m_Renderers.m_iDisplayStats = 0; + } + RepaintVideo(); + } +} + +void CMainFrame::OnUpdateViewVSync(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(!supported || r.m_AdvRendSets.bVMR9VSync); +} + +void CMainFrame::OnUpdateViewVSyncOffset(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D + && r.m_AdvRendSets.bVMR9AlterativeVSync); + + pCmdUI->Enable(supported); + CString Temp; + Temp.Format(L"%d", r.m_AdvRendSets.iVMR9VSyncOffset); + pCmdUI->SetText(Temp); + CMPCThemeMenu::updateItem(pCmdUI); +} + +void CMainFrame::OnUpdateViewVSyncAccurate(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9VSyncAccurate); +} + +void CMainFrame::OnUpdateViewSynchronizeVideo(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_SYNC) && GetPlaybackMode() == PM_NONE); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeVideo); +} + +void CMainFrame::OnUpdateViewSynchronizeDisplay(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_SYNC) && GetPlaybackMode() == PM_NONE); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeDisplay); +} + +void CMainFrame::OnUpdateViewSynchronizeNearest(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_SYNC); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeNearest); +} + +void CMainFrame::OnUpdateViewColorManagementEnable(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9ColorManagementEnable); +} + +void CMainFrame::OnUpdateViewColorManagementInput(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support + && r.m_AdvRendSets.bVMR9ColorManagementEnable; + + pCmdUI->Enable(supported); + + switch (pCmdUI->m_nID) { + case ID_VIEW_CM_INPUT_AUTO: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_UNKNOWN); + break; + + case ID_VIEW_CM_INPUT_HDTV: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_HDTV); + break; + + case ID_VIEW_CM_INPUT_SDTV_NTSC: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_SDTV_NTSC); + break; + + case ID_VIEW_CM_INPUT_SDTV_PAL: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_SDTV_PAL); + break; + } +} + +void CMainFrame::OnUpdateViewColorManagementAmbientLight(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support && + r.m_AdvRendSets.bVMR9ColorManagementEnable; + + pCmdUI->Enable(supported); + + switch (pCmdUI->m_nID) { + case ID_VIEW_CM_AMBIENTLIGHT_BRIGHT: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_BRIGHT); + break; + case ID_VIEW_CM_AMBIENTLIGHT_DIM: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_DIM); + break; + case ID_VIEW_CM_AMBIENTLIGHT_DARK: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_DARK); + break; + } +} + +void CMainFrame::OnUpdateViewColorManagementIntent(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support + && r.m_AdvRendSets.bVMR9ColorManagementEnable; + + pCmdUI->Enable(supported); + + switch (pCmdUI->m_nID) { + case ID_VIEW_CM_INTENT_PERCEPTUAL: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_PERCEPTUAL); + break; + case ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC); + break; + case ID_VIEW_CM_INTENT_SATURATION: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_SATURATION); + break; + case ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC); + break; + } +} + +void CMainFrame::OnUpdateViewEVROutputRange(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + + if (pCmdUI->m_nID == ID_VIEW_EVROUTPUTRANGE_0_255) { + pCmdUI->SetCheck(r.m_AdvRendSets.iEVROutputRange == 0); + } else if (pCmdUI->m_nID == ID_VIEW_EVROUTPUTRANGE_16_235) { + pCmdUI->SetCheck(r.m_AdvRendSets.iEVROutputRange == 1); + } +} + +void CMainFrame::OnUpdateViewFlushGPU(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + + if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_BEFOREVSYNC) { + pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUBeforeVSync); + } else if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_AFTERPRESENT) { + pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUAfterPresent); + } else if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_WAIT) { + pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUWait); + } + +} + +void CMainFrame::OnUpdateViewD3DFullscreen(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(s.fD3DFullscreen); +} + +void CMainFrame::OnUpdateViewDisableDesktopComposition(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D + && !IsWindows8OrGreater()); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(supported && r.m_AdvRendSets.bVMRDisableDesktopComposition); +} + +void CMainFrame::OnUpdateViewAlternativeVSync(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9AlterativeVSync); +} + +void CMainFrame::OnUpdateViewFullscreenGUISupport(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9FullscreenGUISupport); +} + +void CMainFrame::OnUpdateViewHighColorResolution(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_b10bitSupport; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bEVRHighColorResolution); +} + +void CMainFrame::OnUpdateViewForceInputHighColorResolution(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_b10bitSupport; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bEVRForceInputHighColorResolution); +} + +void CMainFrame::OnUpdateViewFullFloatingPointProcessing(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP32Support; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9FullFloatingPointProcessing); +} + +void CMainFrame::OnUpdateViewHalfFloatingPointProcessing(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing); +} + +void CMainFrame::OnUpdateViewEnableFrameTimeCorrection(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bEVREnableFrameTimeCorrection); +} + +void CMainFrame::OnUpdateViewVSyncOffsetIncrease(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || (((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && r.m_AdvRendSets.bVMR9AlterativeVSync); + + pCmdUI->Enable(supported); +} + +void CMainFrame::OnUpdateViewVSyncOffsetDecrease(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || (((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && r.m_AdvRendSets.bVMR9AlterativeVSync); + + pCmdUI->Enable(supported); +} + +void CMainFrame::OnViewVSync() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9VSync = !r.m_AdvRendSets.bVMR9VSync; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9VSync + ? IDS_OSD_RS_VSYNC_ON : IDS_OSD_RS_VSYNC_OFF)); +} + +void CMainFrame::OnViewVSyncAccurate() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9VSyncAccurate = !r.m_AdvRendSets.bVMR9VSyncAccurate; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9VSyncAccurate + ? IDS_OSD_RS_ACCURATE_VSYNC_ON : IDS_OSD_RS_ACCURATE_VSYNC_OFF)); +} + +void CMainFrame::OnViewSynchronizeVideo() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bSynchronizeVideo = !r.m_AdvRendSets.bSynchronizeVideo; + if (r.m_AdvRendSets.bSynchronizeVideo) { + r.m_AdvRendSets.bSynchronizeDisplay = false; + r.m_AdvRendSets.bSynchronizeNearest = false; + r.m_AdvRendSets.bVMR9VSync = false; + r.m_AdvRendSets.bVMR9VSyncAccurate = false; + r.m_AdvRendSets.bVMR9AlterativeVSync = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeVideo + ? IDS_OSD_RS_SYNC_TO_DISPLAY_ON : IDS_OSD_RS_SYNC_TO_DISPLAY_ON)); +} + +void CMainFrame::OnViewSynchronizeDisplay() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bSynchronizeDisplay = !r.m_AdvRendSets.bSynchronizeDisplay; + if (r.m_AdvRendSets.bSynchronizeDisplay) { + r.m_AdvRendSets.bSynchronizeVideo = false; + r.m_AdvRendSets.bSynchronizeNearest = false; + r.m_AdvRendSets.bVMR9VSync = false; + r.m_AdvRendSets.bVMR9VSyncAccurate = false; + r.m_AdvRendSets.bVMR9AlterativeVSync = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeDisplay + ? IDS_OSD_RS_SYNC_TO_VIDEO_ON : IDS_OSD_RS_SYNC_TO_VIDEO_ON)); +} + +void CMainFrame::OnViewSynchronizeNearest() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bSynchronizeNearest = !r.m_AdvRendSets.bSynchronizeNearest; + if (r.m_AdvRendSets.bSynchronizeNearest) { + r.m_AdvRendSets.bSynchronizeVideo = false; + r.m_AdvRendSets.bSynchronizeDisplay = false; + r.m_AdvRendSets.bVMR9VSync = false; + r.m_AdvRendSets.bVMR9VSyncAccurate = false; + r.m_AdvRendSets.bVMR9AlterativeVSync = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeNearest + ? IDS_OSD_RS_PRESENT_NEAREST_ON : IDS_OSD_RS_PRESENT_NEAREST_OFF)); +} + +void CMainFrame::OnViewColorManagementEnable() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9ColorManagementEnable = !r.m_AdvRendSets.bVMR9ColorManagementEnable; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9ColorManagementEnable + ? IDS_OSD_RS_COLOR_MANAGEMENT_ON : IDS_OSD_RS_COLOR_MANAGEMENT_OFF)); +} + +void CMainFrame::OnViewColorManagementInputAuto() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_AUTO)); +} + +void CMainFrame::OnViewColorManagementInputHDTV() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_HDTV; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_HDTV)); +} + +void CMainFrame::OnViewColorManagementInputSDTV_NTSC() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_SDTV_NTSC; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_SD_NTSC)); +} + +void CMainFrame::OnViewColorManagementInputSDTV_PAL() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_SDTV_PAL; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_SD_PAL)); +} + +void CMainFrame::OnViewColorManagementAmbientLightBright() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_BRIGHT)); +} + +void CMainFrame::OnViewColorManagementAmbientLightDim() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_DIM; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_DIM)); +} + +void CMainFrame::OnViewColorManagementAmbientLightDark() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_DARK; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_DARK)); +} + +void CMainFrame::OnViewColorManagementIntentPerceptual() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_PERCEPT)); +} + +void CMainFrame::OnViewColorManagementIntentRelativeColorimetric() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_RELATIVE)); +} + +void CMainFrame::OnViewColorManagementIntentSaturation() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_SATURATION; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_SATUR)); +} + +void CMainFrame::OnViewColorManagementIntentAbsoluteColorimetric() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_ABSOLUTE)); +} + +void CMainFrame::OnViewEVROutputRange_0_255() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iEVROutputRange = 0; + CString strOSD; + strOSD.Format(IDS_OSD_RS_OUTPUT_RANGE, _T("0 - 255")); + m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); +} + +void CMainFrame::OnViewEVROutputRange_16_235() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iEVROutputRange = 1; + CString strOSD; + strOSD.Format(IDS_OSD_RS_OUTPUT_RANGE, _T("16 - 235")); + m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); +} + +void CMainFrame::OnViewFlushGPUBeforeVSync() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMRFlushGPUBeforeVSync = !r.m_AdvRendSets.bVMRFlushGPUBeforeVSync; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUBeforeVSync + ? IDS_OSD_RS_FLUSH_BEF_VSYNC_ON : IDS_OSD_RS_FLUSH_BEF_VSYNC_OFF)); +} + +void CMainFrame::OnViewFlushGPUAfterVSync() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMRFlushGPUAfterPresent = !r.m_AdvRendSets.bVMRFlushGPUAfterPresent; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUAfterPresent + ? IDS_OSD_RS_FLUSH_AFT_PRES_ON : IDS_OSD_RS_FLUSH_AFT_PRES_OFF)); +} + +void CMainFrame::OnViewFlushGPUWait() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMRFlushGPUWait = !r.m_AdvRendSets.bVMRFlushGPUWait; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUWait + ? IDS_OSD_RS_WAIT_ON : IDS_OSD_RS_WAIT_OFF)); +} + +void CMainFrame::OnViewD3DFullScreen() +{ + CAppSettings& r = AfxGetAppSettings(); + r.fD3DFullscreen = !r.fD3DFullscreen; + r.SaveSettings(); + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.fD3DFullscreen + ? IDS_OSD_RS_D3D_FULLSCREEN_ON : IDS_OSD_RS_D3D_FULLSCREEN_OFF)); +} + +void CMainFrame::OnViewDisableDesktopComposition() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMRDisableDesktopComposition = !r.m_AdvRendSets.bVMRDisableDesktopComposition; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRDisableDesktopComposition + ? IDS_OSD_RS_NO_DESKTOP_COMP_ON : IDS_OSD_RS_NO_DESKTOP_COMP_OFF)); +} + +void CMainFrame::OnViewAlternativeVSync() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9AlterativeVSync = !r.m_AdvRendSets.bVMR9AlterativeVSync; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9AlterativeVSync + ? IDS_OSD_RS_ALT_VSYNC_ON : IDS_OSD_RS_ALT_VSYNC_OFF)); +} + +void CMainFrame::OnViewResetDefault() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.SetDefault(); + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_RESET_DEFAULT)); +} + +void CMainFrame::OnViewResetOptimal() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.SetOptimal(); + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_RESET_OPTIMAL)); +} + +void CMainFrame::OnViewFullscreenGUISupport() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9FullscreenGUISupport = !r.m_AdvRendSets.bVMR9FullscreenGUISupport; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9FullscreenGUISupport + ? IDS_OSD_RS_D3D_FS_GUI_SUPP_ON : IDS_OSD_RS_D3D_FS_GUI_SUPP_OFF)); +} + +void CMainFrame::OnViewHighColorResolution() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bEVRHighColorResolution = !r.m_AdvRendSets.bEVRHighColorResolution; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVRHighColorResolution + ? IDS_OSD_RS_10BIT_RBG_OUT_ON : IDS_OSD_RS_10BIT_RBG_OUT_OFF)); +} + +void CMainFrame::OnViewForceInputHighColorResolution() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bEVRForceInputHighColorResolution = !r.m_AdvRendSets.bEVRForceInputHighColorResolution; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVRForceInputHighColorResolution + ? IDS_OSD_RS_10BIT_RBG_IN_ON : IDS_OSD_RS_10BIT_RBG_IN_OFF)); +} + +void CMainFrame::OnViewFullFloatingPointProcessing() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + if (!r.m_AdvRendSets.bVMR9FullFloatingPointProcessing) { + if (AfxMessageBox(_T("WARNING: Full Floating Point processing can sometimes cause problems. With some videos it can cause the player to freeze, crash, or display corrupted video. This happens mostly with Intel GPUs.\n\nAre you really sure that you want to enable this setting?"), MB_YESNO) == IDNO) { + return; + } + } + r.m_AdvRendSets.bVMR9FullFloatingPointProcessing = !r.m_AdvRendSets.bVMR9FullFloatingPointProcessing; + if (r.m_AdvRendSets.bVMR9FullFloatingPointProcessing) { + r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9FullFloatingPointProcessing + ? IDS_OSD_RS_FULL_FP_PROCESS_ON : IDS_OSD_RS_FULL_FP_PROCESS_OFF)); +} + +void CMainFrame::OnViewHalfFloatingPointProcessing() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing = !r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing; + if (r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing) { + r.m_AdvRendSets.bVMR9FullFloatingPointProcessing = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing + ? IDS_OSD_RS_HALF_FP_PROCESS_ON : IDS_OSD_RS_HALF_FP_PROCESS_OFF)); +} + +void CMainFrame::OnViewEnableFrameTimeCorrection() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bEVREnableFrameTimeCorrection = !r.m_AdvRendSets.bEVREnableFrameTimeCorrection; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVREnableFrameTimeCorrection + ? IDS_OSD_RS_FT_CORRECTION_ON : IDS_OSD_RS_FT_CORRECTION_OFF)); +} + +void CMainFrame::OnViewVSyncOffsetIncrease() +{ + CAppSettings& s = AfxGetAppSettings(); + CRenderersSettings& r = s.m_RenderersSettings; + CString strOSD; + if (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { + r.m_AdvRendSets.fTargetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset - 0.5; // Yeah, it should be a "-" + strOSD.Format(IDS_OSD_RS_TARGET_VSYNC_OFFSET, r.m_AdvRendSets.fTargetSyncOffset); + } else { + ++r.m_AdvRendSets.iVMR9VSyncOffset; + strOSD.Format(IDS_OSD_RS_VSYNC_OFFSET, r.m_AdvRendSets.iVMR9VSyncOffset); + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); +} + +void CMainFrame::OnViewVSyncOffsetDecrease() +{ + CAppSettings& s = AfxGetAppSettings(); + CRenderersSettings& r = s.m_RenderersSettings; + CString strOSD; + if (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { + r.m_AdvRendSets.fTargetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset + 0.5; + strOSD.Format(IDS_OSD_RS_TARGET_VSYNC_OFFSET, r.m_AdvRendSets.fTargetSyncOffset); + } else { + --r.m_AdvRendSets.iVMR9VSyncOffset; + strOSD.Format(IDS_OSD_RS_VSYNC_OFFSET, r.m_AdvRendSets.iVMR9VSyncOffset); + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); +} + +void CMainFrame::OnUpdateViewOSDDisplayTime(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(s.fShowOSD && GetLoadState() != MLS::CLOSED); + pCmdUI->SetCheck(AfxGetAppSettings().fShowCurrentTimeInOSD); +} + +void CMainFrame::OnViewOSDDisplayTime() +{ + auto &showTime = AfxGetAppSettings().fShowCurrentTimeInOSD; + showTime = !showTime; + + if (!showTime) { + m_OSD.ClearTime(); + } + + OnTimer(TIMER_STREAMPOSPOLLER2); +} + +void CMainFrame::OnUpdateViewOSDShowFileName(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(s.fShowOSD && GetLoadState() != MLS::CLOSED); +} + +void CMainFrame::OnViewOSDShowFileName() +{ + CString strOSD; + switch (GetPlaybackMode()) { + case PM_FILE: + strOSD = GetFileName(); + break; + case PM_DVD: + strOSD = _T("DVD"); + if (m_pDVDI) { + CString path; + ULONG len = 0; + if (SUCCEEDED(m_pDVDI->GetDVDDirectory(path.GetBuffer(MAX_PATH), MAX_PATH, &len)) && len) { + path.ReleaseBuffer(); + if (path.Find(_T("\\VIDEO_TS")) == 2) { + strOSD.AppendFormat(_T(" - %s"), GetDriveLabel(CPath(path)).GetString()); + } else { + strOSD.AppendFormat(_T(" - %s"), path.GetString()); + } + } + } + break; + case PM_ANALOG_CAPTURE: + strOSD = GetCaptureTitle(); + break; + case PM_DIGITAL_CAPTURE: + UpdateCurrentChannelInfo(true, false); + break; + default: // Shouldn't happen + ASSERT(FALSE); + return; + } + if (!strOSD.IsEmpty()) { + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD); + } +} + +void CMainFrame::OnUpdateShaderToggle1(CCmdUI* pCmdUI) +{ + if (AfxGetAppSettings().m_Shaders.GetCurrentPreset().GetPreResize().empty()) { + pCmdUI->Enable(FALSE); + pCmdUI->SetCheck (0); + } else { + pCmdUI->Enable(TRUE); + pCmdUI->SetCheck (m_bToggleShader); + } +} + +void CMainFrame::OnUpdateShaderToggle2(CCmdUI* pCmdUI) +{ + CAppSettings& s = AfxGetAppSettings(); + + if (s.m_Shaders.GetCurrentPreset().GetPostResize().empty()) { + pCmdUI->Enable(FALSE); + pCmdUI->SetCheck(0); + } else { + pCmdUI->Enable(TRUE); + pCmdUI->SetCheck(m_bToggleShaderScreenSpace); + } +} + +void CMainFrame::OnShaderToggle1() +{ + m_bToggleShader = !m_bToggleShader; + SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); + if (m_bToggleShader) { + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_PRESIZE_SHADERS_ENABLED)); + } else { + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_PRESIZE_SHADERS_DISABLED)); + } + + if (m_pCAP) { + RepaintVideo(); + } +} + +void CMainFrame::OnShaderToggle2() +{ + m_bToggleShaderScreenSpace = !m_bToggleShaderScreenSpace; + SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); + if (m_bToggleShaderScreenSpace) { + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_POSTSIZE_SHADERS_ENABLED)); + } else { + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_POSTSIZE_SHADERS_DISABLED)); + } + + if (m_pCAP) { + RepaintVideo(); + } +} + +void CMainFrame::OnD3DFullscreenToggle() +{ + CAppSettings& s = AfxGetAppSettings(); + CString strMsg; + + s.fD3DFullscreen = !s.fD3DFullscreen; + strMsg.LoadString(s.fD3DFullscreen ? IDS_OSD_RS_D3D_FULLSCREEN_ON : IDS_OSD_RS_D3D_FULLSCREEN_OFF); + if (GetLoadState() == MLS::CLOSED) { + m_closingmsg = strMsg; + } else { + m_OSD.DisplayMessage(OSD_TOPRIGHT, strMsg); + } +} + +void CMainFrame::OnFileCloseAndRestore() +{ + if (GetLoadState() == MLS::LOADED && IsFullScreenMode()) { + // exit fullscreen + OnViewFullscreen(); + } + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + RestoreDefaultWindowRect(); +} + +void CMainFrame::OnUpdateFileClose(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED || GetLoadState() == MLS::LOADING); +} + +// view + +void CMainFrame::SetCaptionState(MpcCaptionState eState) +{ + auto& s = AfxGetAppSettings(); + + if (eState == s.eCaptionMenuMode) { + return; + } + + const auto eOldState = s.eCaptionMenuMode; + s.eCaptionMenuMode = eState; + + if (IsFullScreenMainFrame()) { + return; + } + + DWORD dwRemove = 0, dwAdd = 0; + DWORD dwMenuFlags = GetMenuBarVisibility(); + + CRect windowRect; + + const bool bZoomed = !!IsZoomed(); + + if (!bZoomed) { + GetWindowRect(&windowRect); + CRect decorationsRect; + VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), dwMenuFlags == AFX_MBV_KEEPVISIBLE, GetWindowExStyle(m_hWnd))); + windowRect.bottom -= decorationsRect.bottom; + windowRect.right -= decorationsRect.right; + windowRect.top -= decorationsRect.top; + windowRect.left -= decorationsRect.left; + } + + const int base = MpcCaptionState::MODE_COUNT; + for (int i = eOldState; i != eState; i = (i + 1) % base) { + switch (static_cast(i)) { + case MpcCaptionState::MODE_BORDERLESS: + dwMenuFlags = AFX_MBV_KEEPVISIBLE; + dwAdd |= (WS_CAPTION | WS_THICKFRAME); + dwRemove &= ~(WS_CAPTION | WS_THICKFRAME); + break; + case MpcCaptionState::MODE_SHOWCAPTIONMENU: + dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; + break; + case MpcCaptionState::MODE_HIDEMENU: + dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; + dwAdd &= ~WS_CAPTION; + dwRemove |= WS_CAPTION; + break; + case MpcCaptionState::MODE_FRAMEONLY: + dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; + dwAdd &= ~WS_THICKFRAME; + dwRemove |= WS_THICKFRAME; + break; + default: + ASSERT(FALSE); + } + } + + UINT uFlags = SWP_NOZORDER; + if (dwRemove != dwAdd) { + uFlags |= SWP_FRAMECHANGED; + VERIFY(SetWindowLong(m_hWnd, GWL_STYLE, (GetWindowLong(m_hWnd, GWL_STYLE) | dwAdd) & ~dwRemove)); + } + + SetMenuBarVisibility(dwMenuFlags); + if (bZoomed) { + CMonitors::GetNearestMonitor(this).GetWorkAreaRect(windowRect); + } else { + VERIFY(AdjustWindowRectEx(windowRect, GetWindowStyle(m_hWnd), dwMenuFlags == AFX_MBV_KEEPVISIBLE, GetWindowExStyle(m_hWnd))); + } + + VERIFY(SetWindowPos(nullptr, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), uFlags)); + OSDBarSetPos(); +} + +void CMainFrame::OnViewCaptionmenu() +{ + const auto& s = AfxGetAppSettings(); + SetCaptionState(static_cast((s.eCaptionMenuMode + 1) % MpcCaptionState::MODE_COUNT)); +} + +void CMainFrame::OnUpdateViewCaptionmenu(CCmdUI* pCmdUI) +{ + const auto& s = AfxGetAppSettings(); + const UINT next[] = { IDS_VIEW_HIDEMENU, IDS_VIEW_FRAMEONLY, IDS_VIEW_BORDERLESS, IDS_VIEW_CAPTIONMENU }; + pCmdUI->SetText(ResStr(next[s.eCaptionMenuMode % MpcCaptionState::MODE_COUNT])); + CMPCThemeMenu::updateItem(pCmdUI); +} + +void CMainFrame::OnViewControlBar(UINT nID) +{ + nID -= ID_VIEW_SEEKER; + m_controls.ToggleControl(static_cast(nID)); +} + +void CMainFrame::OnUpdateViewControlBar(CCmdUI* pCmdUI) +{ + const UINT nID = pCmdUI->m_nID - ID_VIEW_SEEKER; + pCmdUI->SetCheck(m_controls.ControlChecked(static_cast(nID))); + if (pCmdUI->m_nID == ID_VIEW_SEEKER) { + pCmdUI->Enable(!IsPlaybackCaptureMode()); + } +} + +void CMainFrame::OnViewSubresync() +{ + m_controls.ToggleControl(CMainFrameControls::Panel::SUBRESYNC); + AdjustStreamPosPoller(true); +} + +void CMainFrame::OnUpdateViewSubresync(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::SUBRESYNC)); + bool enabled = m_pCAP && m_pCurrentSubInput.pSubStream && !IsPlaybackCaptureMode(); + if (enabled) { + CLSID clsid; + m_pCurrentSubInput.pSubStream->GetClassID(&clsid); + if (clsid == __uuidof(CRenderedTextSubtitle)) { +#if USE_LIBASS + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; + enabled = !pRTS->m_LibassContext.IsLibassActive(); +#endif + } else { + enabled = false; + } + } + pCmdUI->Enable(enabled); +} + +void CMainFrame::OnViewPlaylist() +{ + m_controls.ToggleControl(CMainFrameControls::Panel::PLAYLIST); + m_wndPlaylistBar.SetHiddenDueToFullscreen(false); +} + +void CMainFrame::OnUpdateViewPlaylist(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)); +} + +void CMainFrame::OnPlaylistToggleShuffle() { + CAppSettings& s = AfxGetAppSettings(); + s.bShufflePlaylistItems = !s.bShufflePlaylistItems; + m_wndPlaylistBar.m_pl.SetShuffle(s.bShufflePlaylistItems); +} + +void CMainFrame::OnViewEditListEditor() +{ + CAppSettings& s = AfxGetAppSettings(); + + if (s.fEnableEDLEditor || (AfxMessageBox(IDS_MB_SHOW_EDL_EDITOR, MB_ICONQUESTION | MB_YESNO, 0) == IDYES)) { + s.fEnableEDLEditor = true; + m_controls.ToggleControl(CMainFrameControls::Panel::EDL); + } +} + +void CMainFrame::OnEDLIn() +{ + if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { + REFERENCE_TIME rt; + + m_pMS->GetCurrentPosition(&rt); + m_wndEditListEditor.SetIn(rt); + } +} + +void CMainFrame::OnUpdateEDLIn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); +} + +void CMainFrame::OnEDLOut() +{ + if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { + REFERENCE_TIME rt; + + m_pMS->GetCurrentPosition(&rt); + m_wndEditListEditor.SetOut(rt); + } +} + +void CMainFrame::OnUpdateEDLOut(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); +} + +void CMainFrame::OnEDLNewClip() +{ + if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { + REFERENCE_TIME rt; + + m_pMS->GetCurrentPosition(&rt); + m_wndEditListEditor.NewClip(rt); + } +} + +void CMainFrame::OnUpdateEDLNewClip(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); +} + +void CMainFrame::OnEDLSave() +{ + if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { + m_wndEditListEditor.Save(); + } +} + +void CMainFrame::OnUpdateEDLSave(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); +} + +// Navigation menu +void CMainFrame::OnViewNavigation() +{ + const bool bHiding = m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION); + m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); + if (!bHiding) { + m_wndNavigationBar.m_navdlg.UpdateElementList(); + } + AfxGetAppSettings().fHideNavigation = bHiding; +} + +void CMainFrame::OnUpdateViewNavigation(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_DIGITAL_CAPTURE); +} + +void CMainFrame::OnViewCapture() +{ + m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); +} + +void CMainFrame::OnUpdateViewCapture(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_ANALOG_CAPTURE); +} + +void CMainFrame::OnViewDebugShaders() +{ + auto& dlg = m_pDebugShaders; + if (dlg && !dlg->m_hWnd) { + // something has destroyed the dialog and we didn't know about it + dlg = nullptr; + } + if (!dlg) { + // dialog doesn't exist - create and show it + dlg = std::make_unique(); + dlg->ShowWindow(SW_SHOW); + } else if (dlg->IsWindowVisible()) { + if (dlg->IsIconic()) { + // dialog is visible but iconic - restore it + VERIFY(dlg->ShowWindow(SW_RESTORE)); + } else { + // dialog is visible and not iconic - destroy it + VERIFY(dlg->DestroyWindow()); + ASSERT(!dlg->m_hWnd); + dlg = nullptr; + } + } else { + // dialog is not visible - show it + VERIFY(!dlg->ShowWindow(SW_SHOW)); + } +} + +void CMainFrame::OnUpdateViewDebugShaders(CCmdUI* pCmdUI) +{ + const auto& dlg = m_pDebugShaders; + pCmdUI->SetCheck(dlg && dlg->m_hWnd && dlg->IsWindowVisible()); +} + +void CMainFrame::OnViewMinimal() +{ + SetCaptionState(MODE_BORDERLESS); + m_controls.SetToolbarsSelection(CS_NONE, true); +} + +void CMainFrame::OnUpdateViewMinimal(CCmdUI* pCmdUI) +{ +} + +void CMainFrame::OnViewCompact() +{ + SetCaptionState(MODE_FRAMEONLY); + m_controls.SetToolbarsSelection(CS_SEEKBAR, true); +} + +void CMainFrame::OnUpdateViewCompact(CCmdUI* pCmdUI) +{ +} + +void CMainFrame::OnViewNormal() +{ + SetCaptionState(MODE_SHOWCAPTIONMENU); + m_controls.SetToolbarsSelection(CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR, true); +} + +void CMainFrame::OnUpdateViewNormal(CCmdUI* pCmdUI) +{ +} + +void CMainFrame::OnViewFullscreen() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (IsD3DFullScreenMode() || (s.IsD3DFullscreen() && !m_fFullScreen && !m_fAudioOnly && m_pD3DFSC && m_pMFVDC)) { + ToggleD3DFullscreen(true); + } else { + ToggleFullscreen(true, true); + } +} + +void CMainFrame::OnViewFullscreenSecondary() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (IsD3DFullScreenMode() || (s.IsD3DFullscreen() && !m_fFullScreen && !m_fAudioOnly && m_pD3DFSC && m_pMFVDC)) { + ToggleD3DFullscreen(false); + } else { + ToggleFullscreen(true, false); + } +} + +void CMainFrame::OnUpdateViewFullscreen(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED || m_fFullScreen); + pCmdUI->SetCheck(m_fFullScreen); +} + +void CMainFrame::OnViewZoom(UINT nID) +{ + double scale = (nID == ID_VIEW_ZOOM_25) ? 0.25 : (nID == ID_VIEW_ZOOM_50) ? 0.5 : (nID == ID_VIEW_ZOOM_200) ? 2.0 : 1.0; + + ZoomVideoWindow(scale); + + CString strODSMessage; + strODSMessage.Format(IDS_OSD_ZOOM, scale * 100); + m_OSD.DisplayMessage(OSD_TOPLEFT, strODSMessage, 3000); +} + +void CMainFrame::OnUpdateViewZoom(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly); +} + +void CMainFrame::OnViewZoomAutoFit() +{ + ZoomVideoWindow(ZOOM_AUTOFIT); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_ZOOM_AUTO), 3000); +} + +void CMainFrame::OnViewZoomAutoFitLarger() +{ + ZoomVideoWindow(ZOOM_AUTOFIT_LARGER); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_ZOOM_AUTO_LARGER), 3000); +} + +void CMainFrame::OnViewModifySize(UINT nID) { + if (m_fFullScreen || !m_pVideoWnd || IsZoomed() || IsIconic() || GetLoadState() != MLS::LOADED) { + return; + } + + enum resizeMethod { + autoChoose + , byHeight + , byWidth + } usedMethod; + + const CAppSettings& s = AfxGetAppSettings(); + MINMAXINFO mmi; + CSize videoSize = GetVideoOrArtSize(mmi); + int minWidth = (int)mmi.ptMinTrackSize.x; + + int mult = (nID == ID_VIEW_ZOOM_ADD ? 1 : ID_VIEW_ZOOM_SUB ? -1 : 0); + + double videoRatio = double(videoSize.cy) / double(videoSize.cx); + + CRect videoRect, workRect, maxRect; + videoRect = m_pVideoWnd->GetVideoRect(); + double videoRectRatio = double(videoRect.Height()) / double(videoRect.Width()); + bool previouslyProportional = IsNearlyEqual(videoRectRatio, videoRatio, 0.01); + + GetWorkAreaRect(workRect); + maxRect = GetZoomWindowRect(CSize(INT_MAX, INT_MAX), true); + + CRect rect, zoomRect; + GetWindowRect(&rect); + CSize targetSize; + + auto calculateZoomWindowRect = [&](resizeMethod useMethod = autoChoose, CSize forceDimension = {0,0}) { + int newWidth = videoRect.Width(); + int newHeight = videoRect.Height(); + + if (useMethod == autoChoose) { + if (double(videoRect.Height()) / videoRect.Width() + 0.01f < videoRatio) { //wider than aspect ratio, so use height instead + useMethod = byHeight; + int growPixels = int(.02f * workRect.Height()); + newHeight = videoRect.Height() + growPixels * mult; + } else { + useMethod = byWidth; + int growPixels = int(.02f * workRect.Width()); + newWidth = std::max(videoRect.Width() + growPixels * mult, minWidth); + } + } else if (useMethod == byHeight) { + newHeight = forceDimension.cy + videoRect.Height() - rect.Height(); + } else { + newWidth = forceDimension.cx + videoRect.Width() - rect.Width(); + } + + if (useMethod == byHeight) { + double newRatio = double(newHeight) / double(videoRect.Width()); + if (s.fLimitWindowProportions || previouslyProportional || SGN(newRatio - videoRatio) != SGN(videoRectRatio - videoRatio)) { + newWidth = std::max(int(ceil(newHeight / videoRatio)), minWidth); + if (mult == 1) { + newWidth = std::max(newWidth, videoRect.Width()); + } + } + } else { + double newRatio = double(videoRect.Height()) / double(newWidth); + if (s.fLimitWindowProportions || previouslyProportional || SGN(newRatio - videoRatio) != SGN(videoRectRatio - videoRatio)) { + newHeight = int(ceil(newWidth * videoRatio)); + if (mult == 1) { + newHeight = std::max(newHeight, videoRect.Height()); + } + } + } + targetSize = rect.Size() + CSize(newWidth - videoRect.Width(), newHeight - videoRect.Height()); + usedMethod = useMethod; + return GetZoomWindowRect(targetSize, true); + }; + + zoomRect = calculateZoomWindowRect(); + + CRect newRect, work; + newRect = CRect(rect.TopLeft(), targetSize); //this will be our default + + //if old rect was constrained to a single monitor, we zoom incrementally + if (GetWorkAreaRect(work) && work.PtInRect(rect.TopLeft()) && work.PtInRect(rect.BottomRight()-CSize(1,1)) + && ((zoomRect.Height() != rect.Height() && usedMethod == byHeight) || (zoomRect.Width() != rect.Width() && usedMethod == byWidth))) { + + if (zoomRect.Width() != targetSize.cx && zoomRect.Width() == maxRect.Width()) { //we appear to have been constrained by Screen Width + if (maxRect.Width() != rect.Width()) { //if it wasn't already filling the monitor horizonally, we will do that now + newRect = calculateZoomWindowRect(byWidth, maxRect.Size()); + } + } else if (zoomRect.Height() != targetSize.cy && zoomRect.Height() == maxRect.Height()) { //we appear to have been constrained by Screen Height + if (maxRect.Height() != rect.Height()) { //if it wasn't already filling the monitor vertically, we will do that now + newRect = calculateZoomWindowRect(byHeight, maxRect.Size()); + } + } else { + newRect = zoomRect; + } + } + + MoveWindow(newRect); +} + +void CMainFrame::OnViewDefaultVideoFrame(UINT nID) +{ + AfxGetAppSettings().iDefaultVideoSize = nID - ID_VIEW_VF_HALF; + m_ZoomX = m_ZoomY = 1; + m_PosX = m_PosY = 0.5; + MoveVideoWindow(); +} + +void CMainFrame::OnUpdateViewDefaultVideoFrame(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && s.iDSVideoRendererType != VIDRNDT_DS_EVR); + + int dvs = pCmdUI->m_nID - ID_VIEW_VF_HALF; + if (s.iDefaultVideoSize == dvs && pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, pCmdUI->m_nID, MF_BYCOMMAND); + } +} + +void CMainFrame::OnViewSwitchVideoFrame() +{ + CAppSettings& s = AfxGetAppSettings(); + + int vs = s.iDefaultVideoSize; + if (vs <= DVS_DOUBLE || vs == DVS_FROMOUTSIDE) { + vs = DVS_STRETCH; + } else if (vs == DVS_FROMINSIDE) { + vs = DVS_ZOOM1; + } else if (vs == DVS_ZOOM2) { + vs = DVS_FROMOUTSIDE; + } else { + vs++; + } + switch (vs) { // TODO: Read messages from resource file + case DVS_STRETCH: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_STRETCH_TO_WINDOW)); + break; + case DVS_FROMINSIDE: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_TOUCH_WINDOW_FROM_INSIDE)); + break; + case DVS_ZOOM1: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_ZOOM1)); + break; + case DVS_ZOOM2: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_ZOOM2)); + break; + case DVS_FROMOUTSIDE: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_TOUCH_WINDOW_FROM_OUTSIDE)); + break; + } + s.iDefaultVideoSize = vs; + m_ZoomX = m_ZoomY = 1; + m_PosX = m_PosY = 0.5; + MoveVideoWindow(); +} + +void CMainFrame::OnViewCompMonDeskARDiff() +{ + CAppSettings& s = AfxGetAppSettings(); + + s.fCompMonDeskARDiff = !s.fCompMonDeskARDiff; + OnVideoSizeChanged(); +} + +void CMainFrame::OnUpdateViewCompMonDeskARDiff(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + + pCmdUI->Enable(GetLoadState() == MLS::LOADED + && !m_fAudioOnly + && s.iDSVideoRendererType != VIDRNDT_DS_EVR + // This doesn't work with madVR due to the fact that it positions video itself. + // And it has exactly the same option built in. + && s.iDSVideoRendererType != VIDRNDT_DS_MADVR); + pCmdUI->SetCheck(s.fCompMonDeskARDiff); +} + +void CMainFrame::OnViewPanNScan(UINT nID) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + int x = 0, y = 0; + int dx = 0, dy = 0; + + switch (nID) { + case ID_VIEW_RESET: + // Subtitle overrides + ResetSubtitlePosAndSize(true); + // Pan&Scan + m_ZoomX = m_ZoomY = 1.0; + m_PosX = m_PosY = 0.5; + m_AngleX = m_AngleY = m_AngleZ = 0; + PerformFlipRotate(); + break; + case ID_VIEW_INCSIZE: + x = y = 1; + break; + case ID_VIEW_DECSIZE: + x = y = -1; + break; + case ID_VIEW_INCWIDTH: + x = 1; + break; + case ID_VIEW_DECWIDTH: + x = -1; + break; + case ID_VIEW_INCHEIGHT: + y = 1; + break; + case ID_VIEW_DECHEIGHT: + y = -1; + break; + case ID_PANSCAN_CENTER: + m_PosX = m_PosY = 0.5; + break; + case ID_PANSCAN_MOVELEFT: + dx = -1; + break; + case ID_PANSCAN_MOVERIGHT: + dx = 1; + break; + case ID_PANSCAN_MOVEUP: + dy = -1; + break; + case ID_PANSCAN_MOVEDOWN: + dy = 1; + break; + case ID_PANSCAN_MOVEUPLEFT: + dx = dy = -1; + break; + case ID_PANSCAN_MOVEUPRIGHT: + dx = 1; + dy = -1; + break; + case ID_PANSCAN_MOVEDOWNLEFT: + dx = -1; + dy = 1; + break; + case ID_PANSCAN_MOVEDOWNRIGHT: + dx = dy = 1; + break; + default: + break; + } + + if (x > 0 && m_ZoomX < 5.0) { + m_ZoomX = std::min(m_ZoomX * 1.02, 5.0); + } else if (x < 0 && m_ZoomX > 0.2) { + m_ZoomX = std::max(m_ZoomX / 1.02, 0.2); + } + + if (y > 0 && m_ZoomY < 5.0) { + m_ZoomY = std::min(m_ZoomY * 1.02, 5.0); + } else if (y < 0 && m_ZoomY > 0.2) { + m_ZoomY = std::max(m_ZoomY / 1.02, 0.2); + } + + if (dx < 0 && m_PosX > -0.5) { + m_PosX = std::max(m_PosX - 0.005 * m_ZoomX, -0.5); + } else if (dx > 0 && m_PosX < 1.5) { + m_PosX = std::min(m_PosX + 0.005 * m_ZoomX, 1.5); + } + + if (dy < 0 && m_PosY > -0.5) { + m_PosY = std::max(m_PosY - 0.005 * m_ZoomY, -0.5); + } else if (dy > 0 && m_PosY < 1.5) { + m_PosY = std::min(m_PosY + 0.005 * m_ZoomY, 1.5); + } + + MoveVideoWindow(true); +} + +void CMainFrame::OnUpdateViewPanNScan(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && AfxGetAppSettings().iDSVideoRendererType != VIDRNDT_DS_EVR); +} + +void CMainFrame::ApplyPanNScanPresetString() +{ + auto& s = AfxGetAppSettings(); + + if (s.strPnSPreset.IsEmpty()) + return; + + if (s.strPnSPreset.Find(',') != -1) { // try to set raw values + if (_stscanf_s(s.strPnSPreset, _T("%lf,%lf,%lf,%lf"), &m_PosX, &m_PosY, &m_ZoomX, &m_ZoomY) == 4) { + ValidatePanNScanParameters(); + MoveVideoWindow(); + } + } else { // try to set named preset + for (int i = 0; i < s.m_pnspresets.GetCount(); i++) { + int j = 0; + CString str = s.m_pnspresets[i]; + CString label = str.Tokenize(_T(","), j); + if (s.strPnSPreset == label) { + OnViewPanNScanPresets(i + ID_PANNSCAN_PRESETS_START); + } + } + } + + s.strPnSPreset.Empty(); +} + +void CMainFrame::OnViewPanNScanPresets(UINT nID) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + + nID -= ID_PANNSCAN_PRESETS_START; + + if ((INT_PTR)nID == s.m_pnspresets.GetCount()) { + CPnSPresetsDlg dlg; + dlg.m_pnspresets.Copy(s.m_pnspresets); + if (dlg.DoModal() == IDOK) { + s.m_pnspresets.Copy(dlg.m_pnspresets); + s.SaveSettings(); + } + return; + } + + m_PosX = 0.5; + m_PosY = 0.5; + m_ZoomX = 1.0; + m_ZoomY = 1.0; + + CString str = s.m_pnspresets[nID]; + + int i = 0, j = 0; + for (CString token = str.Tokenize(_T(","), i); !token.IsEmpty(); token = str.Tokenize(_T(","), i), j++) { + float f = 0; + if (_stscanf_s(token, _T("%f"), &f) != 1) { + continue; + } + + switch (j) { + case 0: + break; + case 1: + m_PosX = f; + break; + case 2: + m_PosY = f; + break; + case 3: + m_ZoomX = f; + break; + case 4: + m_ZoomY = f; + break; + default: + break; + } + } + + if (j != 5) { + return; + } + + ValidatePanNScanParameters(); + + MoveVideoWindow(true); +} + +void CMainFrame::ValidatePanNScanParameters() +{ + m_PosX = std::min(std::max(m_PosX, -0.5), 1.5); + m_PosY = std::min(std::max(m_PosY, -0.5), 1.5); + m_ZoomX = std::min(std::max(m_ZoomX, 0.2), 5.0); + m_ZoomY = std::min(std::max(m_ZoomY, 0.2), 5.0); +} + +void CMainFrame::OnUpdateViewPanNScanPresets(CCmdUI* pCmdUI) +{ + int nID = pCmdUI->m_nID - ID_PANNSCAN_PRESETS_START; + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && nID >= 0 && nID <= s.m_pnspresets.GetCount() && s.iDSVideoRendererType != VIDRNDT_DS_EVR); +} + +int nearest90(int angle) { + return int(float(angle) / 90 + 0.5) * 90; +} + +bool CMainFrame::PerformFlipRotate() +{ + HRESULT hr = E_NOTIMPL; + // Note: m_AngleZ is counterclockwise, so value 270 means rotated 90 degrees clockwise + if (m_pCAP3) { + bool isFlip = m_AngleX == 180; + bool isMirror = m_AngleY == 180; + int rotation = (360 - m_AngleZ + m_iDefRotation) % 360; + if (m_pMVRS) { + // MadVR: does not support mirror, instead of flip we rotate 180 degrees + hr = m_pCAP3->SetRotation(isFlip ? (rotation + 180) % 360 : rotation); + } else { + // MPCVR: instead of flip, we mirror plus rotate 180 degrees + hr = m_pCAP3->SetRotation(isFlip ? (rotation + 180) % 360 : rotation); + if (SUCCEEDED(hr)) { + // SetFlip actually mirrors instead of doing vertical flip + hr = m_pCAP3->SetFlip(isFlip || isMirror); + } + } + } else if (m_pCAP) { + // EVR-CP behavior for custom angles is ignored when choosing video size and zoom + // We get better results if we treat the closest 90 as the standard rotation, and custom rotate the remainder (<45deg) + int z = m_AngleZ; + if (m_pCAP2) { + int nZ = nearest90(z); + z = (z - nZ + 360) % 360; + Vector defAngle = Vector(0, 0, Vector::DegToRad((nZ - m_iDefRotation + 360) % 360)); + m_pCAP2->SetDefaultVideoAngle(defAngle); + } + + hr = m_pCAP->SetVideoAngle(Vector(Vector::DegToRad(m_AngleX), Vector::DegToRad(m_AngleY), Vector::DegToRad(z))); + } + + if (FAILED(hr)) { + m_AngleX = m_AngleY = m_AngleZ = 0; + return false; + } + if (m_pCAP2_preview) { //we support rotating preview + PreviewWindowHide(); + m_wndPreView.SetWindowSize(); + SetPreviewVideoPosition(); + //adipose: using defaultvideoangle instead of videoangle, as some oddity with AR shows up when using normal rotate with EVRCP. + //Since we only need to support 4 angles, this will work, but it *should* work with SetVideoAngle... + + hr = m_pCAP2_preview->SetDefaultVideoAngle(Vector(Vector::DegToRad(nearest90(m_AngleX)), Vector::DegToRad(nearest90(m_AngleY)), Vector::DegToRad(defaultVideoAngle + nearest90(m_AngleZ)))); + } + + return true; +} + +void CMainFrame::OnViewRotate(UINT nID) +{ + switch (nID) { + case ID_PANSCAN_ROTATEXP: + if (!m_pCAP3) { + m_AngleX += 2; + break; + } + [[fallthrough]]; // fall through for m_pCAP3 + case ID_PANSCAN_ROTATEXM: + if (m_AngleX >= 180) { + m_AngleX = 0; + } else { + m_AngleX = 180; + } + break; + case ID_PANSCAN_ROTATEYP: + if (!m_pCAP3) { + m_AngleY += 2; + break; + } + [[fallthrough]]; + case ID_PANSCAN_ROTATEYM: + if (m_AngleY >= 180) { + m_AngleY = 0; + } else { + m_AngleY = 180; + } + break; + case ID_PANSCAN_ROTATEZM: + if (m_AngleZ == 0 || m_AngleZ > 270) { + m_AngleZ = 270; + } else if (m_AngleZ > 180) { + m_AngleZ = 180; + } else if (m_AngleZ > 90) { + m_AngleZ = 90; + } else if (m_AngleZ > 0) { + m_AngleZ = 0; + } + break; + case ID_PANSCAN_ROTATEZP: + if (!m_pCAP3) { + m_AngleZ += 2; + break; + } + [[fallthrough]]; + case ID_PANSCAN_ROTATEZ270: + if (m_AngleZ < 90) { + m_AngleZ = 90; + } else if (m_AngleZ >= 270) { + m_AngleZ = 0; + } else if (m_AngleZ >= 180) { + m_AngleZ = 270; + } else if (m_AngleZ >= 90) { + m_AngleZ = 180; + } + break; + default: + return; + } + + m_AngleX %= 360; + m_AngleY %= 360; + if (m_AngleX == 180 && m_AngleY == 180) { + m_AngleX = m_AngleY = 0; + m_AngleZ += 180; + } + m_AngleZ %= 360; + + ASSERT(m_AngleX >= 0); + ASSERT(m_AngleY >= 0); + ASSERT(m_AngleZ >= 0); + + if (PerformFlipRotate()) { + // FIXME: do proper resizing of the window after rotate + if (!m_pMVRC) { + MoveVideoWindow(); + } + + CString info; + info.Format(_T("x: %d, y: %d, z: %d"), m_AngleX, m_AngleY, m_AngleZ); + SendStatusMessage(info, 3000); + } +} + +void CMainFrame::OnUpdateViewRotate(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (m_pCAP || m_pCAP3)); +} + +// FIXME +const static SIZE s_ar[] = {{0, 0}, {4, 3}, {5, 4}, {16, 9}, {235, 100}, {185, 100}}; + +void CMainFrame::OnViewAspectRatio(UINT nID) +{ + auto& s = AfxGetAppSettings(); + + CString info; + if (nID == ID_ASPECTRATIO_SAR) { + s.fKeepAspectRatio = false; + info.LoadString(IDS_ASPECT_RATIO_SAR); + } else { + s.fKeepAspectRatio = true; + CSize ar = s_ar[nID - ID_ASPECTRATIO_START]; + s.SetAspectRatioOverride(ar); + if (ar.cx && ar.cy) { + info.Format(IDS_MAINFRM_68, ar.cx, ar.cy); + } else { + info.LoadString(IDS_MAINFRM_69); + } + } + + SendStatusMessage(info, 3000); + m_OSD.DisplayMessage(OSD_TOPLEFT, info, 3000); + + OnVideoSizeChanged(); +} + +void CMainFrame::OnUpdateViewAspectRatio(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + + bool bSelected; + if (pCmdUI->m_nID == ID_ASPECTRATIO_SAR) { + bSelected = s.fKeepAspectRatio == false; + } else { + bSelected = s.fKeepAspectRatio == true && s.GetAspectRatioOverride() == s_ar[pCmdUI->m_nID - ID_ASPECTRATIO_START]; + } + if (bSelected && pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, pCmdUI->m_nID, MF_BYCOMMAND); + } + + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && s.iDSVideoRendererType != VIDRNDT_DS_EVR); +} + +void CMainFrame::OnViewAspectRatioNext() +{ + static_assert(ID_ASPECTRATIO_SAR - ID_ASPECTRATIO_START == _countof(s_ar) && ID_ASPECTRATIO_SAR == ID_ASPECTRATIO_END, + "ID_ASPECTRATIO_SAR needs to be last item in the menu."); + + const auto& s = AfxGetAppSettings(); + UINT nID = ID_ASPECTRATIO_START; + if (s.fKeepAspectRatio) { + const CSize ar = s.GetAspectRatioOverride(); + for (int i = 0; i < _countof(s_ar); i++) { + if (ar == s_ar[i]) { + nID += (i + 1) % ((ID_ASPECTRATIO_END - ID_ASPECTRATIO_START) + 1); + break; + } + } + } + + OnViewAspectRatio(nID); +} + +void CMainFrame::OnViewOntop(UINT nID) +{ + nID -= ID_ONTOP_DEFAULT; + if (AfxGetAppSettings().iOnTop == (int)nID) { + nID = !nID; + } + SetAlwaysOnTop(nID); +} + +void CMainFrame::OnUpdateViewOntop(CCmdUI* pCmdUI) +{ + int onTop = pCmdUI->m_nID - ID_ONTOP_DEFAULT; + if (AfxGetAppSettings().iOnTop == onTop && pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, pCmdUI->m_nID, MF_BYCOMMAND); + } +} + +void CMainFrame::OnViewOptions() +{ + ShowOptions(); +} + +// play + +void CMainFrame::OnPlayPlay() +{ + const CAppSettings& s = AfxGetAppSettings(); + + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); + m_bOpeningInAutochangedMonitorMode = false; + m_bPausedForAutochangeMonitorMode = false; + + if (GetLoadState() == MLS::CLOSED) { + m_bFirstPlay = false; + OpenCurPlaylistItem(); + return; + } + + if (GetLoadState() == MLS::LOADING) { + return; + } + + if (GetLoadState() == MLS::LOADED) { + // If playback was previously stopped or ended, we need to reset the window size + bool bVideoWndNeedReset = GetMediaState() == State_Stopped || m_fEndOfStream; + + KillTimersStop(); + + if (GetPlaybackMode() == PM_FILE) { + if (m_fEndOfStream) { + SendMessage(WM_COMMAND, ID_PLAY_STOP); + } else { + if (!m_fAudioOnly && m_dwLastPause && m_wndSeekBar.HasDuration() && s.iReloadAfterLongPause >= 0) { + // after long pause or hibernation, reload video file to avoid playback issues on some systems (with buggy drivers) + // in case of hibernate, m_dwLastPause equals 1 + if (m_dwLastPause == 1 || s.iReloadAfterLongPause > 0 && (GetTickCount64() - m_dwLastPause >= s.iReloadAfterLongPause * 60 * 1000)) { + m_dwReloadPos = m_wndSeekBar.GetPos(); + reloadABRepeat = abRepeat; + m_iReloadAudioIdx = GetCurrentAudioTrackIdx(); + m_iReloadSubIdx = GetCurrentSubtitleTrackIdx(); + OnFileReopen(); + return; + } + } + } + if (m_pMS) { + if (FAILED(m_pMS->SetRate(m_dSpeedRate))) { + m_dSpeedRate = 1.0; + } + } + } else if (GetPlaybackMode() == PM_DVD) { + m_dSpeedRate = 1.0; + m_pDVDC->PlayForwards(m_dSpeedRate, DVD_CMD_FLAG_Block, nullptr); + m_pDVDC->Pause(FALSE); + } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + MediaControlStop(); // audio preview won't be in sync if we run it from paused state + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + bVideoWndNeedReset = false; // SetChannel deals with MoveVideoWindow + SetChannel(s.nDVBLastChannel); + } else { + ASSERT(FALSE); + } + } else { + ASSERT(FALSE); + } + + if (bVideoWndNeedReset) { + MoveVideoWindow(false, true); + } + + if (m_fFrameSteppingActive) { + m_pFS->CancelStep(); + m_fFrameSteppingActive = false; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } else { + if (m_pBA) { + m_pBA->put_Volume(m_wndToolBar.Volume); + } + } + m_nStepForwardCount = 0; + + // Restart playback + MediaControlRun(); + + SetAlwaysOnTop(s.iOnTop); + + SetTimersPlay(); + } + + m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_PLAYING), 3000); + SetPlayState(PS_PLAY); + + OnTimer(TIMER_STREAMPOSPOLLER); + + SetupEVRColorControl(); // can be configured when streaming begins + + if (m_OSD.CanShowMessage()) { + CString strOSD; + CString strPlay(StrRes(ID_PLAY_PLAY)); + int i = strPlay.Find(_T("\n")); + if (i > 0) { + strPlay.Delete(i, strPlay.GetLength() - i); + } + + if (m_bFirstPlay) { + if (GetPlaybackMode() == PM_FILE) { + if (!m_LastOpenBDPath.IsEmpty()) { + strOSD.LoadString(IDS_PLAY_BD); + } else { + strOSD = GetFileName(); + CPlaylistItem pli; + if (!strOSD.IsEmpty() && (!m_wndPlaylistBar.GetCur(pli) || !pli.m_bYoutubeDL)) { + strOSD.TrimRight('/'); + strOSD.Replace('\\', '/'); + strOSD = strOSD.Mid(strOSD.ReverseFind('/') + 1); + } + } + } else if (GetPlaybackMode() == PM_DVD) { + strOSD.LoadString(IDS_PLAY_DVD); + } + } + + if (strOSD.IsEmpty()) { + strOSD = strPlay; + } + if (GetPlaybackMode() != PM_DIGITAL_CAPTURE) { + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + } + } + + m_bFirstPlay = false; +} + +void CMainFrame::OnPlayPause() +{ + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); + m_bOpeningInAutochangedMonitorMode = false; + + if (GetLoadState() == MLS::LOADED && GetMediaState() == State_Stopped) { + MoveVideoWindow(false, true); + } + + if (GetLoadState() == MLS::LOADED) { + if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD || GetPlaybackMode() == PM_ANALOG_CAPTURE) { + if (m_fFrameSteppingActive) { + m_pFS->CancelStep(); + m_fFrameSteppingActive = false; + m_nStepForwardCount = 0; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } + MediaControlPause(true); + } else { + ASSERT(FALSE); + } + + KillTimer(TIMER_STATS); + SetAlwaysOnTop(AfxGetAppSettings().iOnTop); + } + + CString strOSD(StrRes(ID_PLAY_PAUSE)); + int i = strOSD.Find(_T("\n")); + if (i > 0) { + strOSD.Delete(i, strOSD.GetLength() - i); + } + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_PAUSED), 3000); + SetPlayState(PS_PAUSE); +} + +void CMainFrame::OnPlayPlaypause() +{ + if (GetLoadState() == MLS::LOADED) { + OAFilterState fs = GetMediaState(); + if (fs == State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } else if (fs == State_Stopped || fs == State_Paused) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + } else if (GetLoadState() == MLS::CLOSED && !IsPlaylistEmpty()) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } +} + +void CMainFrame::OnApiPause() +{ + OAFilterState fs = GetMediaState(); + if (fs == State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } +} +void CMainFrame::OnApiPlay() +{ + OAFilterState fs = GetMediaState(); + if (fs == State_Stopped || fs == State_Paused) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } +} + +void CMainFrame::OnPlayStop() +{ + OnPlayStop(false); +} + +void CMainFrame::OnPlayStop(bool is_closing) +{ + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); + m_bOpeningInAutochangedMonitorMode = false; + m_bPausedForAutochangeMonitorMode = false; + + KillTimersStop(); + + m_wndSeekBar.SetPos(0); + if (GetLoadState() == MLS::LOADED) { + if (GetPlaybackMode() == PM_FILE) { + if (!is_closing) { + LONGLONG pos = 0; + m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + MediaControlStop(true); + if (m_bUseSeekPreview) { + MediaControlStopPreview(); + } + + if (m_pAMNS && m_pFSF) { + // After pause or stop the netshow url source filter won't continue + // on the next play command, unless we cheat it by setting the file name again. + WCHAR* pFN = nullptr; + AM_MEDIA_TYPE mt; + if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { + m_pFSF->Load(pFN, nullptr); + CoTaskMemFree(pFN); + } + } + } else if (GetPlaybackMode() == PM_DVD) { + m_pDVDC->SetOption(DVD_ResetOnStop, TRUE); + MediaControlStop(true); + m_pDVDC->SetOption(DVD_ResetOnStop, FALSE); + + if (m_bUseSeekPreview && m_pDVDC_preview) { + m_pDVDC_preview->SetOption(DVD_ResetOnStop, TRUE); + MediaControlStopPreview(); + m_pDVDC_preview->SetOption(DVD_ResetOnStop, FALSE); + } + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + MediaControlStop(true); + m_pDVBState->bActive = false; + OpenSetupWindowTitle(); + m_wndStatusBar.SetStatusTimer(StrRes(IDS_CAPTURE_LIVE)); + } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + MediaControlStop(true); + } + + m_dSpeedRate = 1.0; + + if (m_fFrameSteppingActive) { + m_pFS->CancelStep(); + m_fFrameSteppingActive = false; + m_nStepForwardCount = 0; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } + m_nStepForwardCount = 0; + } else if (GetLoadState() == MLS::CLOSING) { + MediaControlStop(true); + } + + m_nLoops = 0; + + if (m_hWnd) { + MoveVideoWindow(); + + if (!is_closing && GetLoadState() == MLS::LOADED) { + __int64 start, stop; + m_wndSeekBar.GetRange(start, stop); + if (!IsPlaybackCaptureMode()) { + m_wndStatusBar.SetStatusTimer(m_wndSeekBar.GetPos(), stop, IsSubresyncBarVisible(), GetTimeFormat()); + } + + SetAlwaysOnTop(AfxGetAppSettings().iOnTop); + } + } + + if (!is_closing && !m_fEndOfStream && GetLoadState() == MLS::LOADED) { + CString strOSD(StrRes(ID_PLAY_STOP)); + int i = strOSD.Find(_T("\n")); + if (i > 0) { + strOSD.Delete(i, strOSD.GetLength() - i); + } + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_STOPPED), 3000); + } else { + m_fEndOfStream = false; + } + + SetPlayState(PS_STOP); +} + +void CMainFrame::OnUpdatePlayPauseStop(CCmdUI* pCmdUI) +{ + bool fEnable = false; + bool fCheck = false; + + if (GetLoadState() == MLS::LOADED) { + OAFilterState fs = m_fFrameSteppingActive ? State_Paused : GetMediaState(); + + fCheck = pCmdUI->m_nID == ID_PLAY_PLAY && fs == State_Running || + pCmdUI->m_nID == ID_PLAY_PAUSE && fs == State_Paused || + pCmdUI->m_nID == ID_PLAY_STOP && fs == State_Stopped || + pCmdUI->m_nID == ID_PLAY_PLAYPAUSE && (fs == State_Paused || fs == State_Running); + + if (fs >= 0) { + if (GetPlaybackMode() == PM_FILE || IsPlaybackCaptureMode()) { + fEnable = true; + + if (m_fCapturing) { + fEnable = false; + } else if (m_fLiveWM && pCmdUI->m_nID == ID_PLAY_PAUSE) { + fEnable = false; + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE && pCmdUI->m_nID == ID_PLAY_PAUSE) { + fEnable = false; // Disable pause for digital capture mode to avoid accidental playback stop. We don't support time shifting yet. + } + } else if (GetPlaybackMode() == PM_DVD) { + fEnable = m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu + && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu; + + if (fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE) { + fEnable = false; + } + } + } + } else if (GetLoadState() == MLS::CLOSED) { + fEnable = (pCmdUI->m_nID == ID_PLAY_PLAY || pCmdUI->m_nID == ID_PLAY_PLAYPAUSE) && !IsPlaylistEmpty(); + } + + pCmdUI->SetCheck(fCheck); + pCmdUI->Enable(fEnable); +} + +void CMainFrame::OnPlayFramestep(UINT nID) +{ + if (!m_pFS && !m_pMS) { + return; + } + + KillTimerDelayedSeek(); + + m_OSD.EnableShowMessage(false); + + if (m_CachedFilterState == State_Paused) { + // Double check the state, because graph may have silently gone into a running state after performing a framestep + if (UpdateCachedMediaState() != State_Paused) { + MediaControlPause(true); + } + } else { + KillTimer(TIMER_STATS); + MediaControlPause(true); + } + + if (nID == ID_PLAY_FRAMESTEP && m_pFS) { + // To support framestep back, store the initial position when + // stepping forward + if (m_nStepForwardCount == 0) { + if (GetPlaybackMode() == PM_DVD) { + OnTimer(TIMER_STREAMPOSPOLLER); + m_rtStepForwardStart = m_wndSeekBar.GetPos(); + } else { + m_pMS->GetCurrentPosition(&m_rtStepForwardStart); + } + } + + if (!m_fFrameSteppingActive) { + m_fFrameSteppingActive = true; + m_nVolumeBeforeFrameStepping = m_wndToolBar.Volume; + if (m_pBA) { + m_pBA->put_Volume(-10000); + } + } + + HRESULT hr = m_pFS->Step(1, nullptr); + if (FAILED(hr)) { + TRACE(_T("Frame step failed.\n")); + m_fFrameSteppingActive = false; + m_nStepForwardCount = 0; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } + } else if (m_pMS && (m_nStepForwardCount == 0) && (S_OK == m_pMS->IsFormatSupported(&TIME_FORMAT_FRAME))) { + if (SUCCEEDED(m_pMS->SetTimeFormat(&TIME_FORMAT_FRAME))) { + REFERENCE_TIME rtCurPos; + + if (SUCCEEDED(m_pMS->GetCurrentPosition(&rtCurPos))) { + rtCurPos += (nID == ID_PLAY_FRAMESTEP) ? 1 : -1; + + m_pMS->SetPositions(&rtCurPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + m_pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME); + } + } else { // nID == ID_PLAY_FRAMESTEP_BACK + const REFERENCE_TIME rtAvgTimePerFrame = std::llround(GetAvgTimePerFrame() * 10000000LL); + REFERENCE_TIME rtCurPos = 0; + + if (m_nStepForwardCount) { // Exit of framestep forward, calculate current position + m_pFS->CancelStep(); + rtCurPos = m_rtStepForwardStart + m_nStepForwardCount * rtAvgTimePerFrame; + m_nStepForwardCount = 0; + rtCurPos -= rtAvgTimePerFrame; + } else if (GetPlaybackMode() == PM_DVD) { + // IMediaSeeking doesn't work properly with DVD Navigator + // Unfortunately, IDvdInfo2::GetCurrentLocation is inaccurate as well and only updates position approx. once per 500ms + // Due to inaccurate start position value, framestep backwards simply doesn't work well with DVDs. + // Seeking has same accuracy problem. Best we can do is jump back 500ms to at least get to a different frame. + OnTimer(TIMER_STREAMPOSPOLLER); + rtCurPos = m_wndSeekBar.GetPos(); + rtCurPos -= 5000000LL; + } else { + m_pMS->GetCurrentPosition(&rtCurPos); + rtCurPos -= rtAvgTimePerFrame; + } + + DoSeekTo(rtCurPos, false); + } + m_OSD.EnableShowMessage(); +} + +void CMainFrame::OnUpdatePlayFramestep(CCmdUI* pCmdUI) +{ + bool fEnable = false; + + if (pCmdUI->m_nID == ID_PLAY_FRAMESTEP) { + if (!m_fAudioOnly && !m_fLiveWM && GetLoadState() == MLS::LOADED && (GetPlaybackMode() == PM_FILE || (GetPlaybackMode() == PM_DVD && m_iDVDDomain == DVD_DOMAIN_Title))) { + if (m_pFS || m_pMS && (S_OK == m_pMS->IsFormatSupported(&TIME_FORMAT_FRAME))) { + fEnable = true; + } + } + } + pCmdUI->Enable(fEnable); +} + +void CMainFrame::OnPlaySeek(UINT nID) +{ + const auto& s = AfxGetAppSettings(); + + REFERENCE_TIME rtJumpDiff = + nID == ID_PLAY_SEEKBACKWARDSMALL ? -10000i64 * s.nJumpDistS : + nID == ID_PLAY_SEEKFORWARDSMALL ? +10000i64 * s.nJumpDistS : + nID == ID_PLAY_SEEKBACKWARDMED ? -10000i64 * s.nJumpDistM : + nID == ID_PLAY_SEEKFORWARDMED ? +10000i64 * s.nJumpDistM : + nID == ID_PLAY_SEEKBACKWARDLARGE ? -10000i64 * s.nJumpDistL : + nID == ID_PLAY_SEEKFORWARDLARGE ? +10000i64 * s.nJumpDistL : + 0; + + if (rtJumpDiff == 0) { + ASSERT(FALSE); + return; + } + + if (m_fShockwaveGraph) { + // HACK: the custom graph should support frame based seeking instead + rtJumpDiff /= 10000i64 * 100; + } + + const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); + REFERENCE_TIME rtSeekTo = rtPos + rtJumpDiff; + if (rtSeekTo < 0) { + rtSeekTo = 0; + } + + if (s.bFastSeek && !m_kfs.empty()) { + REFERENCE_TIME rtMaxForwardDiff; + REFERENCE_TIME rtMaxBackwardDiff; + if (s.bAllowInaccurateFastseek && (s.nJumpDistS >= 5000 || (nID != ID_PLAY_SEEKBACKWARDSMALL) && (nID != ID_PLAY_SEEKFORWARDSMALL))) { + if (rtJumpDiff > 0) { + rtMaxForwardDiff = 200000000LL; + rtMaxBackwardDiff = rtJumpDiff / 2; + } else { + rtMaxForwardDiff = -rtJumpDiff / 2; + rtMaxBackwardDiff = 200000000LL; + } + } else { + rtMaxForwardDiff = rtMaxBackwardDiff = std::min(100000000LL, abs(rtJumpDiff) * 3 / 10); + } + rtSeekTo = GetClosestKeyFrame(rtSeekTo, rtMaxForwardDiff, rtMaxBackwardDiff); + } + + SeekTo(rtSeekTo); +} + +void CMainFrame::OnPlaySeekSet() +{ + const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); + REFERENCE_TIME rtStart, rtStop; + m_wndSeekBar.GetRange(rtStart, rtStop); + + if (abRepeat.positionA > rtStart && abRepeat.positionA < rtStop) { + rtStart = abRepeat.positionA; + } + if (rtPos != rtStart) { + SeekTo(rtStart, false); + } +} + +void CMainFrame::AdjustStreamPosPoller(bool restart) +{ + int current_value = m_iStreamPosPollerInterval; + + if (g_bExternalSubtitleTime || IsSubresyncBarVisible()) { + m_iStreamPosPollerInterval = 40; + } else { + m_iStreamPosPollerInterval = AfxGetAppSettings().nStreamPosPollerInterval; + } + + if (restart && current_value != m_iStreamPosPollerInterval) { + if (KillTimer(TIMER_STREAMPOSPOLLER)) { + SetTimer(TIMER_STREAMPOSPOLLER, m_iStreamPosPollerInterval, nullptr); + } + } +} + +void CMainFrame::SetTimersPlay() +{ + AdjustStreamPosPoller(false); + + SetTimer(TIMER_STREAMPOSPOLLER, m_iStreamPosPollerInterval, nullptr); + SetTimer(TIMER_STREAMPOSPOLLER2, 500, nullptr); + SetTimer(TIMER_STATS, 1000, nullptr); +} + +void CMainFrame::KillTimerDelayedSeek() +{ + KillTimer(TIMER_DELAYEDSEEK); + queuedSeek = { 0, 0, false }; +} + +void CMainFrame::KillTimersStop() +{ + KillTimerDelayedSeek(); + KillTimer(TIMER_STREAMPOSPOLLER2); + KillTimer(TIMER_STREAMPOSPOLLER); + KillTimer(TIMER_STATS); + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DVBINFO_UPDATE); +} + +void CMainFrame::OnPlaySeekKey(UINT nID) +{ + if (!m_kfs.empty()) { + bool bSeekingForward = (nID == ID_PLAY_SEEKKEYFORWARD); + const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); + REFERENCE_TIME rtKeyframe; + REFERENCE_TIME rtTarget; + REFERENCE_TIME rtMin; + REFERENCE_TIME rtMax; + if (bSeekingForward) { + rtMin = rtPos + 10000LL; // at least one millisecond later + rtMax = GetDur(); + rtTarget = rtMin; + } else { + rtMin = 0; + if (GetMediaState() == State_Paused) { + rtMax = rtPos - 10000LL; + } else { + rtMax = rtPos - 5000000LL; + } + rtTarget = rtMax; + } + + if (GetKeyFrame(rtTarget, rtMin, rtMax, false, rtKeyframe)) { + SeekTo(rtKeyframe); + } + } +} + +void CMainFrame::OnUpdatePlaySeek(CCmdUI* pCmdUI) +{ + bool fEnable = false; + + if (GetLoadState() == MLS::LOADED) { + fEnable = true; + if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { + fEnable = false; + } else if (IsPlaybackCaptureMode()) { + fEnable = false; + } + } + + pCmdUI->Enable(fEnable); +} + +void CMainFrame::SetPlayingRate(double rate) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + HRESULT hr = E_FAIL; + if (GetPlaybackMode() == PM_FILE) { + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + if (m_pMS) { + hr = m_pMS->SetRate(rate); + } + } else if (GetPlaybackMode() == PM_DVD) { + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + if (rate > 0) { + hr = m_pDVDC->PlayForwards(rate, DVD_CMD_FLAG_Block, nullptr); + } else { + hr = m_pDVDC->PlayBackwards(-rate, DVD_CMD_FLAG_Block, nullptr); + } + } + if (SUCCEEDED(hr)) { + m_dSpeedRate = rate; + CString strODSMessage; + strODSMessage.Format(IDS_OSD_SPEED, rate); + m_OSD.DisplayMessage(OSD_TOPRIGHT, strODSMessage); + } +} + +void CMainFrame::OnPlayChangeRate(UINT nID) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (GetPlaybackMode() == PM_FILE) { + const CAppSettings& s = AfxGetAppSettings(); + double dSpeedStep = s.nSpeedStep / 100.0; + + if (nID == ID_PLAY_INCRATE) { + if (s.nSpeedStep > 0) { + if (m_dSpeedRate <= 0.05) { + double newrate = 1.0 - (95 / s.nSpeedStep) * dSpeedStep; + SetPlayingRate(newrate > 0.05 ? newrate : newrate + dSpeedStep); + } else { + SetPlayingRate(std::max(0.05, m_dSpeedRate + dSpeedStep)); + } + } else { + SetPlayingRate(std::max(0.0625, m_dSpeedRate * 2.0)); + } + } else if (nID == ID_PLAY_DECRATE) { + if (s.nSpeedStep > 0) { + SetPlayingRate(std::max(0.05, m_dSpeedRate - dSpeedStep)); + } else { + SetPlayingRate(std::max(0.0625, m_dSpeedRate / 2.0)); + } + } else if (nID > ID_PLAY_PLAYBACKRATE_START && nID < ID_PLAY_PLAYBACKRATE_END) { + if (filePlaybackRates.count(nID) != 0) { + SetPlayingRate(filePlaybackRates[nID]); + } else if (nID == ID_PLAY_PLAYBACKRATE_FPS24 || nID == ID_PLAY_PLAYBACKRATE_FPS25) { + if (m_pCAP) { + float target = (nID == ID_PLAY_PLAYBACKRATE_FPS24 ? 24.0f : 25.0f); + SetPlayingRate(target / m_pCAP->GetFPS()); + } + } + } + } else if (GetPlaybackMode() == PM_DVD) { + if (nID == ID_PLAY_INCRATE) { + if (m_dSpeedRate > 0) { + SetPlayingRate(m_dSpeedRate * 2.0); + } else if (m_dSpeedRate >= -1) { + SetPlayingRate(1); + } else { + SetPlayingRate(m_dSpeedRate / 2.0); + } + } else if (nID == ID_PLAY_DECRATE) { + if (m_dSpeedRate < 0) { + SetPlayingRate(m_dSpeedRate * 2.0); + } else if (m_dSpeedRate <= 1) { + SetPlayingRate(-1); + } else { + SetPlayingRate(m_dSpeedRate / 2.0); + } + } else if (nID > ID_PLAY_PLAYBACKRATE_START && nID < ID_PLAY_PLAYBACKRATE_END) { + if (dvdPlaybackRates.count(nID) != 0) { + SetPlayingRate(dvdPlaybackRates[nID]); + } + } + } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + + long lChannelMin = 0, lChannelMax = 0; + m_pAMTuner->ChannelMinMax(&lChannelMin, &lChannelMax); + long lChannel = 0, lVivSub = 0, lAudSub = 0; + m_pAMTuner->get_Channel(&lChannel, &lVivSub, &lAudSub); + + long lFreqOrg = 0, lFreqNew = -1; + m_pAMTuner->get_VideoFrequency(&lFreqOrg); + + //long lSignalStrength; + do { + if (nID == ID_PLAY_DECRATE) { + lChannel--; + } else if (nID == ID_PLAY_INCRATE) { + lChannel++; + } + + //if (lChannel < lChannelMin) lChannel = lChannelMax; + //if (lChannel > lChannelMax) lChannel = lChannelMin; + + if (lChannel < lChannelMin || lChannel > lChannelMax) { + break; + } + + if (FAILED(m_pAMTuner->put_Channel(lChannel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT))) { + break; + } + + long flFoundSignal; + m_pAMTuner->AutoTune(lChannel, &flFoundSignal); + + m_pAMTuner->get_VideoFrequency(&lFreqNew); + } while (FALSE); + /*SUCCEEDED(m_pAMTuner->SignalPresent(&lSignalStrength)) + && (lSignalStrength != AMTUNER_SIGNALPRESENT || lFreqNew == lFreqOrg));*/ + } else { + ASSERT(FALSE); + } +} + +void CMainFrame::OnUpdatePlayChangeRate(CCmdUI* pCmdUI) +{ + bool fEnable = false; + + if (GetLoadState() == MLS::LOADED) { + if (pCmdUI->m_nID > ID_PLAY_PLAYBACKRATE_START && pCmdUI->m_nID < ID_PLAY_PLAYBACKRATE_END && pCmdUI->m_pMenu) { + fEnable = false; + if (GetPlaybackMode() == PM_FILE) { + if (filePlaybackRates.count(pCmdUI->m_nID) != 0) { + fEnable = true; + if (filePlaybackRates[pCmdUI->m_nID] == m_dSpeedRate) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); + } + } else if (pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS24 || pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS25) { + fEnable = true; + if (m_pCAP) { + float target = (pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS24 ? 24.0f : 25.0f); + if (target / m_pCAP->GetFPS() == m_dSpeedRate) { + bool found = false; + for (auto const& [key, rate] : filePlaybackRates) { //make sure it wasn't a standard rate already + if (rate == m_dSpeedRate) { + found = true; + } + } + if (!found) { //must have used fps, as it didn't match a standard rate + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); + } + } + } + } + } else if (GetPlaybackMode() == PM_DVD) { + if (dvdPlaybackRates.count(pCmdUI->m_nID) != 0) { + fEnable = true; + if (dvdPlaybackRates[pCmdUI->m_nID] == m_dSpeedRate) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); + } + } + } + } else { + bool fInc = pCmdUI->m_nID == ID_PLAY_INCRATE; + + fEnable = true; + if (fInc && m_dSpeedRate >= 128.0) { + fEnable = false; + } else if (!fInc && GetPlaybackMode() == PM_FILE && m_dSpeedRate <= 0.05) { + fEnable = false; + } else if (!fInc && GetPlaybackMode() == PM_DVD && m_dSpeedRate <= -128.0) { + fEnable = false; + } else if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { + fEnable = false; + } else if (m_fShockwaveGraph) { + fEnable = false; + } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE && (!m_wndCaptureBar.m_capdlg.IsTunerActive() || m_fCapturing)) { + fEnable = false; + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + fEnable = false; + } else if (m_fLiveWM) { + fEnable = false; + } + } + } + + pCmdUI->Enable(fEnable); +} + +void CMainFrame::OnPlayResetRate() +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + HRESULT hr = E_FAIL; + + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + + if (GetPlaybackMode() == PM_FILE) { + hr = m_pMS->SetRate(1.0); + } else if (GetPlaybackMode() == PM_DVD) { + hr = m_pDVDC->PlayForwards(1.0, DVD_CMD_FLAG_Block, nullptr); + } + + if (SUCCEEDED(hr)) { + m_dSpeedRate = 1.0; + + CString strODSMessage; + strODSMessage.Format(IDS_OSD_SPEED, m_dSpeedRate); + m_OSD.DisplayMessage(OSD_TOPRIGHT, strODSMessage); + } +} + +void CMainFrame::OnUpdatePlayResetRate(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED); +} + +void CMainFrame::SetAudioDelay(REFERENCE_TIME rtShift) +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + pASF->SetAudioTimeShift(rtShift); + + if (GetLoadState() == MLS::LOADED) { + CString str; + str.Format(IDS_MAINFRM_70, rtShift / 10000); + SendStatusMessage(str, 3000); + m_OSD.DisplayMessage(OSD_TOPLEFT, str); + } + } +} + +void CMainFrame::SetSubtitleDelay(int delay_ms, bool relative) +{ + if (!m_pCAP && !m_pDVS) { + if (GetLoadState() == MLS::LOADED) { + SendStatusMessage(L"Delay is not supported by current subtitle renderer", 3000); + } + return; + } + + if (m_pDVS) { + int currentDelay, speedMul, speedDiv; + if (FAILED(m_pDVS->get_SubtitleTiming(¤tDelay, &speedMul, &speedDiv))) { + return; + } + if (relative) { + delay_ms += currentDelay; + } + + VERIFY(SUCCEEDED(m_pDVS->put_SubtitleTiming(delay_ms, speedMul, speedDiv))); + } + else { + ASSERT(m_pCAP != nullptr); + if (m_pSubStreams.IsEmpty()) { + SendStatusMessage(StrRes(IDS_SUBTITLES_ERROR), 3000); + return; + } + if (relative) { + delay_ms += m_pCAP->GetSubtitleDelay(); + } + + m_pCAP->SetSubtitleDelay(delay_ms); + } + + CString strSubDelay; + strSubDelay.Format(IDS_MAINFRM_139, delay_ms); + SendStatusMessage(strSubDelay, 3000); + m_OSD.DisplayMessage(OSD_TOPLEFT, strSubDelay); +} + +void CMainFrame::OnPlayChangeAudDelay(UINT nID) +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + REFERENCE_TIME rtShift = pASF->GetAudioTimeShift(); + rtShift += + nID == ID_PLAY_INCAUDDELAY ? 100000 : + nID == ID_PLAY_DECAUDDELAY ? -100000 : + 0; + + SetAudioDelay(rtShift); + } +} + +void CMainFrame::OnUpdatePlayChangeAudDelay(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(!!m_pGB /*&& !!FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)*/); +} + +void CMainFrame::OnPlayFiltersCopyToClipboard() +{ + // Don't translate that output since it's mostly for debugging purpose + CString filtersList = _T("Filters currently loaded:\r\n"); + // Skip the first two entries since they are the "Copy to clipboard" menu entry and a separator + for (int i = 2, count = m_filtersMenu.GetMenuItemCount(); i < count; i++) { + CString filterName; + m_filtersMenu.GetMenuString(i, filterName, MF_BYPOSITION); + filtersList.AppendFormat(_T(" - %s\r\n"), filterName.GetString()); + } + + CClipboard clipboard(this); + VERIFY(clipboard.SetText(filtersList)); +} + +bool CMainFrame::FilterSettingsByClassID(CLSID clsid, CWnd* parent) +{ + for (int a = 0; a < m_pparray.GetCount(); a++) { + CComQIPtr pBF2 = m_pparray[a]; + if (pBF2) { + CLSID tclsid; + pBF2->GetClassID(&tclsid); + if (tclsid == clsid) { + FilterSettings(m_pparray[a], parent); + return true; + } + } + } + return false; +} + +void CMainFrame::FilterSettings(CComPtr pUnk, CWnd* parent) { + CComPropertySheet ps(IDS_PROPSHEET_PROPERTIES); + + CComQIPtr pBF = pUnk; + CLSID clsid = GetCLSID(pBF); + CFGFilterLAV::LAVFILTER_TYPE LAVFilterType = CFGFilterLAV::INVALID; + bool bIsInternalLAV = CFGFilterLAV::IsInternalInstance(pBF, &LAVFilterType); + + if (CComQIPtr pSPP = pUnk) { + ULONG uIgnoredPage = ULONG(-1); + // If we are dealing with an internal filter, we want to ignore the "Formats" page. + if (bIsInternalLAV) { + uIgnoredPage = (LAVFilterType != CFGFilterLAV::AUDIO_DECODER) ? 1 : 2; + } + bool bIsInternalFilter = bIsInternalLAV || clsid == CLSID_MPCVR; + ps.AddPages(pSPP, bIsInternalFilter, uIgnoredPage); + } + + HRESULT hr; + CComPtr pPP = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr); + ps.AddPage(pPP, pBF); + + if (ps.GetPageCount() > 0) { + CMPCThemeComPropertyPage::SetDialogType(clsid); + ps.DoModal(); + OpenSetupStatusBar(); + + if (bIsInternalLAV) { + if (CComQIPtr pLAVFSettings = pBF) { + CFGFilterLAVSplitterBase::Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get current settings from LAVSplitter + settings.SaveSettings(); // Save them to the registry/ini + } + } else if (CComQIPtr pLAVVideoSettings = pBF) { + CFGFilterLAVVideo::Settings settings; + if (settings.GetSettings(pLAVVideoSettings)) { // Get current settings from LAVVideo + settings.SaveSettings(); // Save them to the registry/ini + } + } else if (CComQIPtr pLAVAudioSettings = pBF) { + CFGFilterLAVAudio::Settings settings; + if (settings.GetSettings(pLAVAudioSettings)) { // Get current settings from LAVAudio + settings.SaveSettings(); // Save them to the registry/ini + } + } + } + } +} + +void CMainFrame::OnPlayFilters(UINT nID) +{ + //ShowPPage(m_spparray[nID - ID_FILTERS_SUBITEM_START], m_hWnd); + + CComPtr pUnk = m_pparray[nID - ID_FILTERS_SUBITEM_START]; + + FilterSettings(pUnk, GetModalParent()); +} + +void CMainFrame::OnUpdatePlayFilters(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(!m_fCapturing); +} + +void CMainFrame::OnPlayShadersSelect() +{ + ShowOptions(IDD_PPAGESHADERS); +} + +void CMainFrame::OnPlayShadersPresetNext() +{ + auto& s = AfxGetAppSettings(); + if (s.m_Shaders.NextPreset()) { + CString name; + if (s.m_Shaders.GetCurrentPresetName(name)) { + CString msg; + msg.Format(IDS_OSD_SHADERS_PRESET, name.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, msg); + } + } +} + +void CMainFrame::OnPlayShadersPresetPrev() +{ + auto& s = AfxGetAppSettings(); + if (s.m_Shaders.PrevPreset()) { + CString name; + if (s.m_Shaders.GetCurrentPresetName(name)) { + CString msg; + msg.Format(IDS_OSD_SHADERS_PRESET, name.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, msg); + } + } +} + +void CMainFrame::OnPlayShadersPresets(UINT nID) +{ + ASSERT((nID >= ID_SHADERS_PRESETS_START) && (nID <= ID_SHADERS_PRESETS_END)); + auto& s = AfxGetAppSettings(); + int num = (int)nID - ID_SHADERS_PRESETS_START; + auto presets = s.m_Shaders.GetPresets(); + ASSERT(num < (int)presets.size()); + for (const auto& pair : presets) { + if (num-- == 0) { + s.m_Shaders.SetCurrentPreset(pair.first); + break; + } + } +} + +int CMainFrame::UpdateSelectedAudioStreamInfo(int index, AM_MEDIA_TYPE* pmt, LCID lcid) { + int nChannels = 0; + if (index >= 0) { + m_loadedAudioTrackIndex = index; + AfxGetAppSettings().MRU.UpdateCurrentAudioTrack(index); + } + if (pmt) { + m_statusbarAudioFormat = GetShortAudioNameFromMediaType(pmt); + AppendWithDelimiter(m_statusbarAudioFormat, GetChannelStrFromMediaType(pmt, nChannels)); + } else { + m_statusbarAudioFormat.Empty(); + } + if (lcid > 0) { + GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentAudioLang); + } else { + currentAudioLang.Empty(); + } + return nChannels; +} + +int CMainFrame::GetSelectedSubtitleTrackIndex() { + int subIdx = 0; + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + CComQIPtr pSSF = subInput.pSourceFilter; + if (pSSF) { + DWORD cStreams; + if (SUCCEEDED(pSSF->Count(&cStreams))) { + for (long j = 0; j < (long)cStreams; j++) { + DWORD dwFlags, dwGroup; + if (SUCCEEDED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 2) { + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + return subIdx; + } + subIdx++; + } + } + } + } + } else { + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + return subIdx; + } else { + subIdx += subInput.pSubStream->GetStreamCount(); + } + } + } + return 0; +} + +bool CMainFrame::IsValidSubtitleStream(int i) { + if (GetSubtitleInput(i) != nullptr) { + return true; + } + + return false; +} + +// Called from GraphThread +void CMainFrame::OnPlayAudio(UINT nID) +{ + int i = (int)nID - ID_AUDIO_SUBITEM_START; + + DWORD cStreams = 0; + + if (GetPlaybackMode() == PM_DVD) { + m_pDVDC->SelectAudioStream(i, DVD_CMD_FLAG_Block, nullptr); + LCID lcid = 0; + if (SUCCEEDED(m_pDVDI->GetAudioLanguage(i, &lcid)) && lcid != 0) { + GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentAudioLang); + } else { + currentAudioLang.Empty(); + } + } else if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { + if (i == 0) { + ShowOptions(CPPageAudioSwitcher::IDD); + } else { + LONG sidx = i - 1; + if (m_iReloadAudioIdx >= 0) { + if (m_iReloadAudioIdx < cStreams) { + sidx = m_iReloadAudioIdx; + } + m_iReloadAudioIdx = -1; + } + if (sidx >= cStreams) { //invalid stream? + return; + } + if (SUCCEEDED(m_pAudioSwitcherSS->Enable(sidx, AMSTREAMSELECTENABLE_ENABLE))) { + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(m_pAudioSwitcherSS->Info(sidx, &pmt, nullptr, &lcid, nullptr, nullptr, nullptr, nullptr))) { + UpdateSelectedAudioStreamInfo(sidx, pmt, lcid); + DeleteMediaType(pmt); + } else { + UpdateSelectedAudioStreamInfo(sidx, nullptr, -1); + } + } + } + } else if (GetPlaybackMode() == PM_FILE) { + OnNavStreamSelectSubMenu(i, 1); + AfxGetAppSettings().MRU.UpdateCurrentAudioTrack(i); + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + if (CBDAChannel* pChannel = m_pDVBState->pChannel) { + OnNavStreamSelectSubMenu(i, 1); + pChannel->SetDefaultAudio(i); + } + } +} + +void CMainFrame::OnSubtitlesDefaultStyle() +{ + CAppSettings& s = AfxGetAppSettings(); + if (!m_pSubStreams.IsEmpty()) { + s.bSubtitleOverrideDefaultStyle = !s.bSubtitleOverrideDefaultStyle; + UpdateSubtitleRenderingParameters(); + RepaintVideo(); + } +} + +void CMainFrame::OnPlaySubtitles(UINT nID) +{ + CAppSettings& s = AfxGetAppSettings(); + int i = (int)nID - ID_SUBTITLES_SUBITEM_START; + + if (GetPlaybackMode() == PM_DVD) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) + && ulStreamsAvailable) { + if (i == 0) { + m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); + } else if (i <= int(ulStreamsAvailable)) { + m_pDVDC->SelectSubpictureStream(i - 1, DVD_CMD_FLAG_Block, nullptr); + m_pDVDC->SetSubpictureState(TRUE, DVD_CMD_FLAG_Block, nullptr); + } + i -= ulStreamsAvailable + 1; + } + } + + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + if (CBDAChannel* pChannel = m_pDVBState->pChannel) { + OnNavStreamSelectSubMenu(i, 2); + pChannel->SetDefaultSubtitle(i); + SetSubtitle(i); + } + } else if (!m_pSubStreams.IsEmpty()) { + // Currently the subtitles menu contains 6 items apart from the actual subtitles list when the ISR is used + i -= 6; + + if (i == -6) { + // options + ShowOptions(CPPageSubtitles::IDD); + } else if (i == -5) { + // styles + int j = 0; + SubtitleInput* pSubInput = GetSubtitleInput(j, true); + CLSID clsid; + + if (pSubInput && SUCCEEDED(pSubInput->pSubStream->GetClassID(&clsid))) { + if (clsid == __uuidof(CRenderedTextSubtitle)) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; + + CAutoPtrArray pages; + CAtlArray styles; + + POSITION pos = pRTS->m_styles.GetStartPosition(); + for (int k = 0; pos; k++) { + CString styleName; + STSStyle* style; + pRTS->m_styles.GetNextAssoc(pos, styleName, style); + + CAutoPtr page(DEBUG_NEW CPPageSubStyle(/*isStyleDialog = */ true)); + if (style->hasAnsiStyleName) { + styleName = ToUnicode(styleName, pRTS->GetCharSet(style->charSet)); + } + page->InitStyle(styleName, *style); + pages.Add(page); + styles.Add(style); + } + + CMPCThemePropertySheet dlg(IDS_SUBTITLES_STYLES_CAPTION, GetModalParent()); + for (size_t l = 0; l < pages.GetCount(); l++) { + dlg.AddPage(pages[l]); + } + + if (dlg.DoModal() == IDOK) { + { + CAutoLock cAutoLock(&m_csSubLock); + bool defaultStyleChanged = false, otherStyleChanged = false; + + for (size_t l = 0; l < pages.GetCount(); l++) { + STSStyle tmpStyle = *styles[l]; + pages[l]->GetStyle(*styles[l]); + if (pages[l]->GetStyleName() == L"Default") { + if (*styles[l] != s.subtitlesDefStyle) { + pRTS->m_bUsingPlayerDefaultStyle = false; + pRTS->SetDefaultStyle(*styles[l]); + defaultStyleChanged = true; + } + } else if (tmpStyle != *styles[l]) { + otherStyleChanged = true; + } + } + if (otherStyleChanged || defaultStyleChanged) { + if (!defaultStyleChanged) { //it will already have triggered SetStyleChanged() internally + pRTS->SetStyleChanged(); + } + pRTS->Deinit(); + InvalidateSubtitle(); + RepaintVideo(); + m_wndSubresyncBar.ReloadSubtitle(); + } + } + } + } + } + } else if (i == -4) { + // reload + ReloadSubtitle(); + } else if (i == -3) { + // hide + ToggleSubtitleOnOff(); + } else if (i == -2) { + // override default style + s.bSubtitleOverrideDefaultStyle = !s.bSubtitleOverrideDefaultStyle; + UpdateSubtitleRenderingParameters(); + RepaintVideo(); + } else if (i == -1) { + // override all styles + s.bSubtitleOverrideAllStyles = !s.bSubtitleOverrideAllStyles; + UpdateSubtitleRenderingParameters(); + RepaintVideo(); + } else if (i >= 0) { + // this is an actual item from the subtitles list + s.fEnableSubtitles = true; + SetSubtitle(i); + } + } else if (GetPlaybackMode() == PM_FILE) { + OnNavStreamSelectSubMenu(i, 2); + } +} + +void CMainFrame::OnPlayVideoStreams(UINT nID) +{ + nID -= ID_VIDEO_STREAMS_SUBITEM_START; + + if (GetPlaybackMode() == PM_FILE) { + OnNavStreamSelectSubMenu(nID, 0); + } else if (GetPlaybackMode() == PM_DVD) { + m_pDVDC->SelectAngle(nID + 1, DVD_CMD_FLAG_Block, nullptr); + + CString osdMessage; + osdMessage.Format(IDS_AG_ANGLE, nID + 1); + m_OSD.DisplayMessage(OSD_TOPLEFT, osdMessage); + } +} + +void CMainFrame::OnPlayFiltersStreams(UINT nID) +{ + nID -= ID_FILTERSTREAMS_SUBITEM_START; + CComPtr pAMSS = m_ssarray[nID]; + UINT i = nID; + + while (i > 0 && pAMSS == m_ssarray[i - 1]) { + i--; + } + + if (FAILED(pAMSS->Enable(nID - i, AMSTREAMSELECTENABLE_ENABLE))) { + MessageBeep(UINT_MAX); + } + + OpenSetupStatusBar(); +} + +void CMainFrame::OnPlayVolume(UINT nID) +{ + if (GetLoadState() == MLS::LOADED) { + CString strVolume; + m_pBA->put_Volume(m_wndToolBar.Volume); + + //strVolume.Format (L"Vol : %d dB", m_wndToolBar.Volume / 100); + if (m_wndToolBar.Volume == -10000) { + strVolume.Format(IDS_VOLUME_OSD, 0); + } else { + strVolume.Format(IDS_VOLUME_OSD, m_wndToolBar.m_volctrl.GetPos()); + } + m_OSD.DisplayMessage(OSD_TOPLEFT, strVolume); + //SendStatusMessage(strVolume, 3000); // Now the volume is displayed in three places at once. + } + + m_Lcd.SetVolume((m_wndToolBar.Volume > -10000 ? m_wndToolBar.m_volctrl.GetPos() : 1)); +} + +void CMainFrame::OnPlayVolumeBoost(UINT nID) +{ + CAppSettings& s = AfxGetAppSettings(); + + switch (nID) { + case ID_VOLUME_BOOST_INC: + s.nAudioBoost += s.nVolumeStep; + if (s.nAudioBoost > 300) { + s.nAudioBoost = 300; + } + break; + case ID_VOLUME_BOOST_DEC: + if (s.nAudioBoost > s.nVolumeStep) { + s.nAudioBoost -= s.nVolumeStep; + } else { + s.nAudioBoost = 0; + } + break; + case ID_VOLUME_BOOST_MIN: + s.nAudioBoost = 0; + break; + case ID_VOLUME_BOOST_MAX: + s.nAudioBoost = 300; + break; + } + + SetVolumeBoost(s.nAudioBoost); +} + +void CMainFrame::SetVolumeBoost(UINT nAudioBoost) +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + bool fNormalize, fNormalizeRecover; + UINT nMaxNormFactor, nBoost; + pASF->GetNormalizeBoost2(fNormalize, nMaxNormFactor, fNormalizeRecover, nBoost); + + CString strBoost; + strBoost.Format(IDS_BOOST_OSD, nAudioBoost); + pASF->SetNormalizeBoost2(fNormalize, nMaxNormFactor, fNormalizeRecover, nAudioBoost); + m_OSD.DisplayMessage(OSD_TOPLEFT, strBoost); + } +} + +void CMainFrame::OnUpdatePlayVolumeBoost(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(); +} + +void CMainFrame::OnCustomChannelMapping() +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + CAppSettings& s = AfxGetAppSettings(); + s.fCustomChannelMapping = !s.fCustomChannelMapping; + pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(s.fCustomChannelMapping ? IDS_OSD_CUSTOM_CH_MAPPING_ON : IDS_OSD_CUSTOM_CH_MAPPING_OFF)); + } +} + +void CMainFrame::OnUpdateCustomChannelMapping(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(s.fEnableAudioSwitcher); +} + +void CMainFrame::OnNormalizeRegainVolume(UINT nID) +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + CAppSettings& s = AfxGetAppSettings(); + WORD osdMessage = 0; + + switch (nID) { + case ID_NORMALIZE: + s.fAudioNormalize = !s.fAudioNormalize; + osdMessage = s.fAudioNormalize ? IDS_OSD_NORMALIZE_ON : IDS_OSD_NORMALIZE_OFF; + break; + case ID_REGAIN_VOLUME: + s.fAudioNormalizeRecover = !s.fAudioNormalizeRecover; + osdMessage = s.fAudioNormalizeRecover ? IDS_OSD_REGAIN_VOLUME_ON : IDS_OSD_REGAIN_VOLUME_OFF; + break; + } + + pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMessage)); + } +} + +void CMainFrame::OnUpdateNormalizeRegainVolume(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(s.fEnableAudioSwitcher); +} + +void CMainFrame::OnPlayColor(UINT nID) +{ + if (m_pVMRMC || m_pMFVP) { + CAppSettings& s = AfxGetAppSettings(); + //ColorRanges* crs = AfxGetMyApp()->ColorControls; + int& brightness = s.iBrightness; + int& contrast = s.iContrast; + int& hue = s.iHue; + int& saturation = s.iSaturation; + CString tmp, str; + switch (nID) { + case ID_COLOR_BRIGHTNESS_INC: + brightness += 2; + [[fallthrough]]; + case ID_COLOR_BRIGHTNESS_DEC: + brightness -= 1; + SetColorControl(ProcAmp_Brightness, brightness, contrast, hue, saturation); + tmp.Format(brightness ? _T("%+d") : _T("%d"), brightness); + str.Format(IDS_OSD_BRIGHTNESS, tmp.GetString()); + break; + case ID_COLOR_CONTRAST_INC: + contrast += 2; + [[fallthrough]]; + case ID_COLOR_CONTRAST_DEC: + contrast -= 1; + SetColorControl(ProcAmp_Contrast, brightness, contrast, hue, saturation); + tmp.Format(contrast ? _T("%+d") : _T("%d"), contrast); + str.Format(IDS_OSD_CONTRAST, tmp.GetString()); + break; + case ID_COLOR_HUE_INC: + hue += 2; + [[fallthrough]]; + case ID_COLOR_HUE_DEC: + hue -= 1; + SetColorControl(ProcAmp_Hue, brightness, contrast, hue, saturation); + tmp.Format(hue ? _T("%+d") : _T("%d"), hue); + str.Format(IDS_OSD_HUE, tmp.GetString()); + break; + case ID_COLOR_SATURATION_INC: + saturation += 2; + [[fallthrough]]; + case ID_COLOR_SATURATION_DEC: + saturation -= 1; + SetColorControl(ProcAmp_Saturation, brightness, contrast, hue, saturation); + tmp.Format(saturation ? _T("%+d") : _T("%d"), saturation); + str.Format(IDS_OSD_SATURATION, tmp.GetString()); + break; + case ID_COLOR_RESET: + brightness = AfxGetMyApp()->GetColorControl(ProcAmp_Brightness)->DefaultValue; + contrast = AfxGetMyApp()->GetColorControl(ProcAmp_Contrast)->DefaultValue; + hue = AfxGetMyApp()->GetColorControl(ProcAmp_Hue)->DefaultValue; + saturation = AfxGetMyApp()->GetColorControl(ProcAmp_Saturation)->DefaultValue; + SetColorControl(ProcAmp_All, brightness, contrast, hue, saturation); + str.LoadString(IDS_OSD_RESET_COLOR); + break; + } + m_OSD.DisplayMessage(OSD_TOPLEFT, str); + } else { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_NO_COLORCONTROL)); + } +} + +void CMainFrame::OnAfterplayback(UINT nID) +{ + CAppSettings& s = AfxGetAppSettings(); + WORD osdMsg = 0; + bool bDisable = false; + + auto toggleOption = [&](UINT64 nID) { + bDisable = !!(s.nCLSwitches & nID); + s.nCLSwitches &= ~CLSW_AFTERPLAYBACK_MASK | nID; + s.nCLSwitches ^= nID; + }; + + switch (nID) { + case ID_AFTERPLAYBACK_EXIT: + toggleOption(CLSW_CLOSE); + osdMsg = IDS_AFTERPLAYBACK_EXIT; + break; + case ID_AFTERPLAYBACK_STANDBY: + toggleOption(CLSW_STANDBY); + osdMsg = IDS_AFTERPLAYBACK_STANDBY; + break; + case ID_AFTERPLAYBACK_HIBERNATE: + toggleOption(CLSW_HIBERNATE); + osdMsg = IDS_AFTERPLAYBACK_HIBERNATE; + break; + case ID_AFTERPLAYBACK_SHUTDOWN: + toggleOption(CLSW_SHUTDOWN); + osdMsg = IDS_AFTERPLAYBACK_SHUTDOWN; + break; + case ID_AFTERPLAYBACK_LOGOFF: + toggleOption(CLSW_LOGOFF); + osdMsg = IDS_AFTERPLAYBACK_LOGOFF; + break; + case ID_AFTERPLAYBACK_LOCK: + toggleOption(CLSW_LOCK); + osdMsg = IDS_AFTERPLAYBACK_LOCK; + break; + case ID_AFTERPLAYBACK_MONITOROFF: + toggleOption(CLSW_MONITOROFF); + osdMsg = IDS_AFTERPLAYBACK_MONITOROFF; + break; + case ID_AFTERPLAYBACK_PLAYNEXT: + toggleOption(CLSW_PLAYNEXT); + osdMsg = IDS_AFTERPLAYBACK_PLAYNEXT; + break; + case ID_AFTERPLAYBACK_DONOTHING: + toggleOption(CLSW_DONOTHING); + osdMsg = IDS_AFTERPLAYBACK_DONOTHING; + break; + } + if (bDisable) { + switch (s.eAfterPlayback) { + case CAppSettings::AfterPlayback::PLAY_NEXT: + osdMsg = IDS_AFTERPLAYBACK_PLAYNEXT; + break; + case CAppSettings::AfterPlayback::REWIND: + osdMsg = IDS_AFTERPLAYBACK_REWIND; + break; + case CAppSettings::AfterPlayback::MONITOROFF: + osdMsg = IDS_AFTERPLAYBACK_MONITOROFF; + break; + case CAppSettings::AfterPlayback::CLOSE: + osdMsg = IDS_AFTERPLAYBACK_CLOSE; + break; + case CAppSettings::AfterPlayback::EXIT: + osdMsg = IDS_AFTERPLAYBACK_EXIT; + break; + default: + ASSERT(FALSE); + [[fallthrough]]; + case CAppSettings::AfterPlayback::DO_NOTHING: + osdMsg = IDS_AFTERPLAYBACK_DONOTHING; + break; + } + } + + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMsg)); +} + +void CMainFrame::OnUpdateAfterplayback(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + bool bChecked; + bool bRadio = false; + + switch (pCmdUI->m_nID) { + case ID_AFTERPLAYBACK_EXIT: + bChecked = !!(s.nCLSwitches & CLSW_CLOSE); + bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::EXIT; + break; + case ID_AFTERPLAYBACK_STANDBY: + bChecked = !!(s.nCLSwitches & CLSW_STANDBY); + break; + case ID_AFTERPLAYBACK_HIBERNATE: + bChecked = !!(s.nCLSwitches & CLSW_HIBERNATE); + break; + case ID_AFTERPLAYBACK_SHUTDOWN: + bChecked = !!(s.nCLSwitches & CLSW_SHUTDOWN); + break; + case ID_AFTERPLAYBACK_LOGOFF: + bChecked = !!(s.nCLSwitches & CLSW_LOGOFF); + break; + case ID_AFTERPLAYBACK_LOCK: + bChecked = !!(s.nCLSwitches & CLSW_LOCK); + break; + case ID_AFTERPLAYBACK_MONITOROFF: + bChecked = !!(s.nCLSwitches & CLSW_MONITOROFF); + bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::MONITOROFF; + break; + case ID_AFTERPLAYBACK_PLAYNEXT: + bChecked = !!(s.nCLSwitches & CLSW_PLAYNEXT); + bRadio = (s.eAfterPlayback == CAppSettings::AfterPlayback::PLAY_NEXT) && (m_wndPlaylistBar.GetCount() < 2); + break; + case ID_AFTERPLAYBACK_DONOTHING: + bChecked = !!(s.nCLSwitches & CLSW_DONOTHING); + bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::DO_NOTHING; + break; + default: + ASSERT(FALSE); + return; + } + + if (IsMenu(*pCmdUI->m_pMenu)) { + MENUITEMINFO mii, cii; + ZeroMemory(&cii, sizeof(MENUITEMINFO)); + cii.cbSize = sizeof(cii); + cii.fMask = MIIM_FTYPE; + pCmdUI->m_pMenu->GetMenuItemInfo(pCmdUI->m_nID, &cii); + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE | MIIM_STATE; + mii.fType = (bRadio ? MFT_RADIOCHECK : 0) | (cii.fType & MFT_OWNERDRAW); //preserve owner draw flag + mii.fState = (bRadio ? MFS_DISABLED : 0) | (bChecked || bRadio ? MFS_CHECKED : 0); + VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pCmdUI->m_pMenu, pCmdUI->m_nID, &mii)); + } +} + +void CMainFrame::OnPlayRepeat(UINT nID) +{ + CAppSettings& s = AfxGetAppSettings(); + WORD osdMsg = 0; + + switch (nID) { + case ID_PLAY_REPEAT_ONEFILE: + s.eLoopMode = CAppSettings::LoopMode::FILE; + osdMsg = IDS_PLAYLOOPMODE_FILE; + break; + case ID_PLAY_REPEAT_WHOLEPLAYLIST: + s.eLoopMode = CAppSettings::LoopMode::PLAYLIST; + osdMsg = IDS_PLAYLOOPMODE_PLAYLIST; + break; + default: + ASSERT(FALSE); + return; + } + + m_nLoops = 0; + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMsg)); +} + +void CMainFrame::OnUpdatePlayRepeat(CCmdUI* pCmdUI) +{ + CAppSettings::LoopMode loopmode; + + switch (pCmdUI->m_nID) { + case ID_PLAY_REPEAT_ONEFILE: + loopmode = CAppSettings::LoopMode::FILE; + break; + case ID_PLAY_REPEAT_WHOLEPLAYLIST: + loopmode = CAppSettings::LoopMode::PLAYLIST; + break; + default: + ASSERT(FALSE); + return; + } + if (AfxGetAppSettings().eLoopMode == loopmode && pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, pCmdUI->m_nID, MF_BYCOMMAND); + } +} + +void CMainFrame::OnPlayRepeatForever() +{ + CAppSettings& s = AfxGetAppSettings(); + + s.fLoopForever = !s.fLoopForever; + + m_nLoops = 0; + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(s.fLoopForever ? IDS_PLAYLOOP_FOREVER_ON : IDS_PLAYLOOP_FOREVER_OFF)); +} + +void CMainFrame::OnUpdatePlayRepeatForever(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(AfxGetAppSettings().fLoopForever); +} + +bool CMainFrame::SeekToFileChapter(int iChapter, bool bRelative /*= false*/) +{ + if (GetPlaybackMode() != PM_FILE || !m_pCB) { + return false; + } + + bool ret = false; + + if (DWORD nChapters = m_pCB->ChapGetCount()) { + REFERENCE_TIME rt; + + if (bRelative) { + if (m_pMS && SUCCEEDED(m_pMS->GetCurrentPosition(&rt))) { + if (iChapter < 0) { + // Add a small threshold to jump back at least that amount of time + // This is needed when rt is near start of current chapter + rt -= PREV_CHAP_THRESHOLD * 10000000; + iChapter = 0; + iChapter = m_pCB->ChapLookupPrevious(&rt, nullptr); + // seek to start if there is no previous chapter + if (iChapter == -1 && rt >= 0) { + REFERENCE_TIME rtStart, rtStop; + m_wndSeekBar.GetRange(rtStart, rtStop); + DoSeekTo(rtStart, false); + return true; + } + } else { + iChapter = m_pCB->ChapLookupNext(&rt, nullptr); + } + } else { + return false; + } + } + + CComBSTR name; + REFERENCE_TIME rtStart, rtStop; + m_wndSeekBar.GetRange(rtStart, rtStop); + if (iChapter >= 0 && DWORD(iChapter) < nChapters && SUCCEEDED(m_pCB->ChapGet(iChapter, &rt, &name)) && rt < rtStop) { + DoSeekTo(rt, false); + SendStatusMessage(ResStr(IDS_AG_CHAPTER2) + CString(name), 3000); + ret = true; + + REFERENCE_TIME rtDur; + if (m_pMS && SUCCEEDED(m_pMS->GetDuration(&rtDur))) { + const CAppSettings& s = AfxGetAppSettings(); + CString strOSD; + REFERENCE_TIME rtShow = rt; + if (s.fRemainingTime) { + strOSD.Append(_T("-")); + rtShow = rtDur - rt; + } + if (rtDur >= 36005000000LL) { // At least 1 hour (rounded) + strOSD.AppendFormat(_T("%s / %s "), ReftimeToString2(rtShow).GetString(), ReftimeToString2(rtDur).GetString()); + } else { + strOSD.AppendFormat(_T("%s / %s "), ReftimeToString3(rtShow).GetString(), ReftimeToString3(rtDur).GetString()); + } + strOSD.AppendFormat(_T("\"%s\" (%d/%u)"), static_cast(name), iChapter + 1, nChapters); + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + } + } + } + + return ret; +} + +bool CMainFrame::SeekToDVDChapter(int iChapter, bool bRelative /*= false*/) +{ + if (GetPlaybackMode() != PM_DVD) { + return false; + } + + ULONG ulNumOfVolumes, ulVolume; + DVD_DISC_SIDE Side; + ULONG ulNumOfTitles = 0; + CheckNoLogBool(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles)); + + DVD_PLAYBACK_LOCATION2 Location; + ULONG ulNumOfChapters = 0; + ULONG uTitle = 0, uChapter = 0; + if (bRelative) { + CheckNoLogBool(m_pDVDI->GetCurrentLocation(&Location)); + + CheckNoLogBool(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters)); + + uTitle = Location.TitleNum; + uChapter = Location.ChapterNum; + + if (iChapter < 0) { + ULONG tsec = (Location.TimeCode.bHours * 3600) + + (Location.TimeCode.bMinutes * 60) + + (Location.TimeCode.bSeconds); + ULONG diff = 0; + if (m_lChapterStartTime != 0xFFFFFFFF && tsec > m_lChapterStartTime) { + diff = tsec - m_lChapterStartTime; + } + // Go the previous chapter only if more than PREV_CHAP_THRESHOLD seconds + // have passed since the beginning of the current chapter else restart it + if (diff <= PREV_CHAP_THRESHOLD) { + // If we are at the first chapter of a volume that isn't the first + // one, we skip to the last chapter of the previous volume. + if (uChapter == 1 && uTitle > 1) { + uTitle--; + CheckNoLogBool(m_pDVDI->GetNumberOfChapters(uTitle, &uChapter)); + } else if (uChapter > 1) { + uChapter--; + } + } + } else { + // If we are at the last chapter of a volume that isn't the last + // one, we skip to the first chapter of the next volume. + if (uChapter == ulNumOfChapters && uTitle < ulNumOfTitles) { + uTitle++; + uChapter = 1; + } else if (uChapter < ulNumOfChapters) { + uChapter++; + } + } + } else if (iChapter > 0) { + uChapter = ULONG(iChapter); + if (uChapter <= ulNumOfTitles) { + uTitle = uChapter; + uChapter = 1; + } else { + CheckNoLogBool(m_pDVDI->GetCurrentLocation(&Location)); + uTitle = Location.TitleNum; + uChapter -= ulNumOfTitles; + } + } + + if (uTitle && uChapter + && SUCCEEDED(m_pDVDC->PlayChapterInTitle(uTitle, uChapter, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr))) { + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location)) + && SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters))) { + CString strTitle; + strTitle.Format(IDS_AG_TITLE2, Location.TitleNum, ulNumOfTitles); + __int64 start, stop; + m_wndSeekBar.GetRange(start, stop); + + CString strOSD; + if (stop > 0) { + const CAppSettings& s = AfxGetAppSettings(); + + DVD_HMSF_TIMECODE currentHMSF = s.fRemainingTime ? RT2HMS_r(stop - HMSF2RT(Location.TimeCode)) : Location.TimeCode; + DVD_HMSF_TIMECODE stopHMSF = RT2HMS_r(stop); + strOSD.Format(_T("%s%s/%s %s, %s%02u/%02lu"), + s.fRemainingTime ? _T("- ") : _T(""), DVDtimeToString(currentHMSF, stopHMSF.bHours > 0).GetString(), DVDtimeToString(stopHMSF).GetString(), + strTitle.GetString(), ResStr(IDS_AG_CHAPTER2).GetString(), Location.ChapterNum, ulNumOfChapters); + } else { + strOSD.Format(_T("%s, %s%02u/%02lu"), strTitle.GetString(), ResStr(IDS_AG_CHAPTER2).GetString(), Location.ChapterNum, ulNumOfChapters); + } + + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + } + + return true; + } + + return false; +} + +// navigate +void CMainFrame::OnNavigateSkip(UINT nID) +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (GetPlaybackMode() == PM_FILE || CanSkipFromClosedFile()) { + m_nLastSkipDirection = nID; + + if (!SeekToFileChapter((nID == ID_NAVIGATE_SKIPBACK) ? -1 : 1, true)) { + if (nID == ID_NAVIGATE_SKIPBACK) { + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACKFILE); + } else if (nID == ID_NAVIGATE_SKIPFORWARD) { + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARDFILE); + } + } + } else if (GetPlaybackMode() == PM_DVD) { + m_dSpeedRate = 1.0; + + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + + SeekToDVDChapter((nID == ID_NAVIGATE_SKIPBACK) ? -1 : 1, true); + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + int nCurrentChannel = s.nDVBLastChannel; + + if (nID == ID_NAVIGATE_SKIPBACK) { + if (SUCCEEDED(SetChannel(nCurrentChannel - 1))) { + if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_wndNavigationBar.m_navdlg.UpdatePos(nCurrentChannel - 1); + } + } + } else if (nID == ID_NAVIGATE_SKIPFORWARD) { + if (SUCCEEDED(SetChannel(nCurrentChannel + 1))) { + if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_wndNavigationBar.m_navdlg.UpdatePos(nCurrentChannel + 1); + } + } + } + } + } +} + +bool CMainFrame::CanSkipFromClosedFile() { + if (GetPlaybackMode() == PM_NONE && AfxGetAppSettings().fUseSearchInFolder) { + if (m_wndPlaylistBar.GetCount() == 1) { + CPlaylistItem pli; + return m_wndPlaylistBar.GetCur(pli, true) && !PathUtils::IsURL(pli.m_fns.GetHead()); + } else if (m_wndPlaylistBar.GetCount() == 0 && !lastOpenFile.IsEmpty()) { + return !PathUtils::IsURL(lastOpenFile); + } + } + return false; +} + +void CMainFrame::OnUpdateNavigateSkip(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + + pCmdUI->Enable( + (GetLoadState() == MLS::LOADED + && ((GetPlaybackMode() == PM_DVD + && m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu + && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu) + || (GetPlaybackMode() == PM_FILE && s.fUseSearchInFolder) + || (GetPlaybackMode() == PM_FILE && !s.fUseSearchInFolder && (m_wndPlaylistBar.GetCount() > 1 || m_pCB->ChapGetCount() > 1)) + || (GetPlaybackMode() == PM_DIGITAL_CAPTURE && !m_pDVBState->bSetChannelActive))) + || (GetLoadState() == MLS::CLOSED && CanSkipFromClosedFile()) //to support skipping from broken file + ); +} + +void CMainFrame::OnNavigateSkipFile(UINT nID) +{ + if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_ANALOG_CAPTURE || CanSkipFromClosedFile()) { + if (m_wndPlaylistBar.GetCount() == 1 || CanSkipFromClosedFile()) { + CAppSettings& s = AfxGetAppSettings(); + if (GetPlaybackMode() == PM_ANALOG_CAPTURE || !s.fUseSearchInFolder) { + SendMessage(WM_COMMAND, ID_PLAY_STOP); // do not remove this, unless you want a circular call with OnPlayPlay() + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } else { + if (nID == ID_NAVIGATE_SKIPBACKFILE) { + if (!SearchInDir(false, s.bLoopFolderOnPlayNextFile)) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_FIRST_IN_FOLDER)); + } + } else if (nID == ID_NAVIGATE_SKIPFORWARDFILE) { + if (!SearchInDir(true, s.bLoopFolderOnPlayNextFile)) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_LAST_IN_FOLDER)); + } + } + } + } else { + if (nID == ID_NAVIGATE_SKIPBACKFILE) { + m_wndPlaylistBar.SetPrev(); + } else if (nID == ID_NAVIGATE_SKIPFORWARDFILE) { + m_wndPlaylistBar.SetNext(); + } + + OpenCurPlaylistItem(); + } + } +} + +void CMainFrame::OnUpdateNavigateSkipFile(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable( + (GetLoadState() == MLS::LOADED + && ((GetPlaybackMode() == PM_FILE && (m_wndPlaylistBar.GetCount() > 1 || s.fUseSearchInFolder)) + || (GetPlaybackMode() == PM_ANALOG_CAPTURE && !m_fCapturing && m_wndPlaylistBar.GetCount() > 1))) + || (GetLoadState() == MLS::CLOSED && CanSkipFromClosedFile()) + ); +} + +void CMainFrame::OnNavigateGoto() +{ + if ((GetLoadState() != MLS::LOADED) || IsD3DFullScreenMode()) { + return; + } + + const REFTIME atpf = GetAvgTimePerFrame(); + + REFERENCE_TIME start, dur = -1; + m_wndSeekBar.GetRange(start, dur); + CGoToDlg dlg(m_wndSeekBar.GetPos(), dur, atpf > 0.0 ? (1.0 / atpf) : 0.0); + if (IDOK != dlg.DoModal() || dlg.m_time < 0) { + return; + } + + DoSeekTo(dlg.m_time); +} + +void CMainFrame::OnUpdateNavigateGoto(CCmdUI* pCmdUI) +{ + bool fEnable = false; + + if (GetLoadState() == MLS::LOADED) { + fEnable = true; + if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { + fEnable = false; + } else if (IsPlaybackCaptureMode()) { + fEnable = false; + } + } + + pCmdUI->Enable(fEnable); +} + +void CMainFrame::OnNavigateMenu(UINT nID) +{ + nID -= ID_NAVIGATE_TITLEMENU; + + if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_DVD) { + return; + } + + m_dSpeedRate = 1.0; + + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + + m_pDVDC->ShowMenu((DVD_MENU_ID)(nID + 2), DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); +} + +void CMainFrame::OnUpdateNavigateMenu(CCmdUI* pCmdUI) +{ + UINT nID = pCmdUI->m_nID - ID_NAVIGATE_TITLEMENU; + ULONG ulUOPs; + + if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_DVD + || FAILED(m_pDVDI->GetCurrentUOPS(&ulUOPs))) { + pCmdUI->Enable(FALSE); + return; + } + + pCmdUI->Enable(!(ulUOPs & (UOP_FLAG_ShowMenu_Title << nID))); +} + +void CMainFrame::OnNavigateJumpTo(UINT nID) +{ + if (nID < ID_NAVIGATE_JUMPTO_SUBITEM_START) { + return; + } + + const CAppSettings& s = AfxGetAppSettings(); + + if (GetPlaybackMode() == PM_FILE) { + int id = nID - ID_NAVIGATE_JUMPTO_SUBITEM_START; + + if (id < (int)m_MPLSPlaylist.size() && m_MPLSPlaylist.size() > 1) { + int idx = 0; + for (auto &Item : m_MPLSPlaylist) { + if (idx == id) { + m_bIsBDPlay = true; + m_wndPlaylistBar.Empty(); + CAtlList sl; + sl.AddTail(CString(Item.m_strFileName)); + m_wndPlaylistBar.Append(sl, false); + OpenCurPlaylistItem(); + return; + } + idx++; + } + } + + if (m_MPLSPlaylist.size() > 1) { + id -= (int)m_MPLSPlaylist.size(); + } + + if (m_pCB->ChapGetCount() > 1) { + if (SeekToFileChapter(id)) { + return; + } + + id -= m_pCB->ChapGetCount(); + } + + if (id >= 0 && id < m_wndPlaylistBar.GetCount() && m_wndPlaylistBar.GetSelIdx() != id) { + m_wndPlaylistBar.SetSelIdx(id); + OpenCurPlaylistItem(); + } + } else if (GetPlaybackMode() == PM_DVD) { + SeekToDVDChapter(nID - ID_NAVIGATE_JUMPTO_SUBITEM_START + 1); + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + int nChannel = nID - ID_NAVIGATE_JUMPTO_SUBITEM_START; + + if (s.nDVBLastChannel != nChannel) { + if (SUCCEEDED(SetChannel(nChannel))) { + if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_wndNavigationBar.m_navdlg.UpdatePos(nChannel); + } + } + } + } + } +} + +void CMainFrame::OnNavigateMenuItem(UINT nID) +{ + nID -= ID_NAVIGATE_MENU_LEFT; + + if (GetPlaybackMode() == PM_DVD) { + switch (nID) { + case 0: + m_pDVDC->SelectRelativeButton(DVD_Relative_Left); + break; + case 1: + m_pDVDC->SelectRelativeButton(DVD_Relative_Right); + break; + case 2: + m_pDVDC->SelectRelativeButton(DVD_Relative_Upper); + break; + case 3: + m_pDVDC->SelectRelativeButton(DVD_Relative_Lower); + break; + case 4: + if (m_iDVDDomain == DVD_DOMAIN_Title || m_iDVDDomain == DVD_DOMAIN_VideoTitleSetMenu || m_iDVDDomain == DVD_DOMAIN_VideoManagerMenu) { + m_pDVDC->ActivateButton(); + } else { + OnPlayPlay(); + } + break; + case 5: + m_pDVDC->ReturnFromSubmenu(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + break; + case 6: + m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + break; + default: + break; + } + } else if (GetPlaybackMode() == PM_FILE) { + OnPlayPlay(); + } +} + +void CMainFrame::OnUpdateNavigateMenuItem(CCmdUI* pCmdUI) +{ + pCmdUI->Enable((GetLoadState() == MLS::LOADED) && ((GetPlaybackMode() == PM_DVD) || (GetPlaybackMode() == PM_FILE))); +} + +void CMainFrame::OnTunerScan() +{ + m_bScanDlgOpened = true; + CTunerScanDlg dlg(this); + dlg.DoModal(); + m_bScanDlgOpened = false; +} + +void CMainFrame::OnUpdateTunerScan(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_DIGITAL_CAPTURE); +} + +// favorites + +class CDVDStateStream : public CUnknown, public IStream +{ + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(IStream) + CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + + size_t m_pos; + +public: + CDVDStateStream() : CUnknown(NAME("CDVDStateStream"), nullptr) { + m_pos = 0; + } + + DECLARE_IUNKNOWN; + + CAtlArray m_data; + + // ISequentialStream + STDMETHODIMP Read(void* pv, ULONG cb, ULONG* pcbRead) { + size_t cbRead = std::min(m_data.GetCount() - m_pos, size_t(cb)); + cbRead = std::max(cbRead, size_t(0)); + if (cbRead) { + memcpy(pv, &m_data[m_pos], cbRead); + } + if (pcbRead) { + *pcbRead = (ULONG)cbRead; + } + m_pos += cbRead; + return S_OK; + } + STDMETHODIMP Write(const void* pv, ULONG cb, ULONG* pcbWritten) { + BYTE* p = (BYTE*)pv; + ULONG cbWritten = (ULONG) - 1; + while (++cbWritten < cb) { + m_data.Add(*p++); + } + if (pcbWritten) { + *pcbWritten = cbWritten; + } + return S_OK; + } + + // IStream + STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { + return E_NOTIMPL; + } + + STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize) { + return E_NOTIMPL; + } + + STDMETHODIMP CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { + return E_NOTIMPL; + } + + STDMETHODIMP Commit(DWORD grfCommitFlags) { + return E_NOTIMPL; + } + + STDMETHODIMP Revert() { + return E_NOTIMPL; + } + + STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { + return E_NOTIMPL; + } + + STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { + return E_NOTIMPL; + } + + STDMETHODIMP Stat(STATSTG* pstatstg, DWORD grfStatFlag) { + return E_NOTIMPL; + } + + STDMETHODIMP Clone(IStream** ppstm) { + return E_NOTIMPL; + } +}; + +void CMainFrame::AddFavorite(bool fDisplayMessage, bool fShowDialog) +{ + CAppSettings& s = AfxGetAppSettings(); + CAtlList args; + WORD osdMsg = 0; + const TCHAR sep = _T(';'); + + if (GetPlaybackMode() == PM_FILE) { + bool is_BD = false; + CString fn = m_wndPlaylistBar.GetCurFileNameTitle(); + if (fn.IsEmpty()) { + if (m_pFSF) { + CComHeapPtr pFN; + AM_MEDIA_TYPE mt; + if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { + fn = CStringW(pFN); + } + } + if (fn.IsEmpty()) { + return; + } + is_BD = true; + } + + CString desc = GetFileName(); + + // Name + CString name; + if (fShowDialog) { + BOOL bEnableABMarks = static_cast(abRepeat); + CFavoriteAddDlg dlg(desc, fn, bEnableABMarks); + if (dlg.DoModal() != IDOK) { + return; + } + name = dlg.m_name; + } else { + name = desc; + } + args.AddTail(name); + + // RememberPos + CString posStr = _T("0"); + if (s.bFavRememberPos) { + posStr.Format(_T("%I64d"), GetPos()); + } + // RememberABMarks + if (s.bFavRememberABMarks && abRepeat) { + posStr.AppendFormat(_T(":%I64d:%I64d"), abRepeat.positionA, abRepeat.positionB); + } + args.AddTail(posStr); + + // RelativeDrive + CString relativeDrive; + relativeDrive.Format(_T("%d"), s.bFavRelativeDrive); + + args.AddTail(relativeDrive); + + // Paths + if (is_BD) { + args.AddTail(fn); + } else { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli)) { + if (pli.m_bYoutubeDL) { + args.AddTail(pli.m_ydlSourceURL); + } else { + POSITION pos = pli.m_fns.GetHeadPosition(); + while (pos) { + args.AddTail(pli.m_fns.GetNext(pos)); + } + } + } + } + + CString str = ImplodeEsc(args, sep); + s.AddFav(FAV_FILE, str); + osdMsg = IDS_FILE_FAV_ADDED; + } else if (GetPlaybackMode() == PM_DVD) { + WCHAR path[MAX_PATH]; + ULONG len = 0; + if (SUCCEEDED(m_pDVDI->GetDVDDirectory(path, MAX_PATH, &len))) { + CString fn = path; + fn.TrimRight(_T("/\\")); + + DVD_PLAYBACK_LOCATION2 Location; + CString desc; + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location))) { + desc.Format(_T("%s - T%02u C%02u - %02u:%02u:%02u"), fn.GetString(), Location.TitleNum, Location.ChapterNum, + Location.TimeCode.bHours, Location.TimeCode.bMinutes, Location.TimeCode.bSeconds); + } else { + desc = fn; + } + // Name + CString name; + if (fShowDialog) { + CFavoriteAddDlg dlg(fn, desc); + if (dlg.DoModal() != IDOK) { + return; + } + name = dlg.m_name; + } else { + name = s.bFavRememberPos ? desc : fn; + } + args.AddTail(name); + + // RememberPos + CString pos(_T("0")); + if (s.bFavRememberPos) { + CDVDStateStream stream; + stream.AddRef(); + + CComPtr pStateData; + CComQIPtr pPersistStream; + if (SUCCEEDED(m_pDVDI->GetState(&pStateData)) + && (pPersistStream = pStateData) + && SUCCEEDED(OleSaveToStream(pPersistStream, (IStream*)&stream))) { + pos = BinToCString(stream.m_data.GetData(), stream.m_data.GetCount()); + } + } + + args.AddTail(pos); + + // Paths + args.AddTail(fn); + + CString str = ImplodeEsc(args, sep); + s.AddFav(FAV_DVD, str); + osdMsg = IDS_DVD_FAV_ADDED; + } + } // TODO: PM_ANALOG_CAPTURE and PM_DIGITAL_CAPTURE + + if (fDisplayMessage && osdMsg) { + CString osdMsgStr(StrRes(osdMsg)); + SendStatusMessage(osdMsgStr, 3000); + m_OSD.DisplayMessage(OSD_TOPLEFT, osdMsgStr, 3000); + } + if (::IsWindow(m_wndFavoriteOrganizeDialog.m_hWnd)) { + m_wndFavoriteOrganizeDialog.LoadList(); + } +} + +void CMainFrame::OnFavoritesAdd() +{ + AddFavorite(); +} + +void CMainFrame::OnUpdateFavoritesAdd(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD); +} + +void CMainFrame::OnFavoritesQuickAddFavorite() +{ + AddFavorite(true, false); +} + +void CMainFrame::OnFavoritesOrganize() +{ + m_wndFavoriteOrganizeDialog.ShowWindow(SW_SHOW); +} + +void CMainFrame::OnUpdateFavoritesOrganize(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + CAtlList sl; + s.GetFav(FAV_FILE, sl); + bool enable = !sl.IsEmpty(); + + if (!enable) { + s.GetFav(FAV_DVD, sl); + enable = !sl.IsEmpty(); + } + + pCmdUI->Enable(enable); +} + +void CMainFrame::OnRecentFileClear() +{ + if (IDYES != AfxMessageBox(IDS_RECENT_FILES_QUESTION, MB_ICONQUESTION | MB_YESNO, 0)) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + s.ClearRecentFiles(); +} + +void CMainFrame::OnUpdateRecentFileClear(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here +} + +void CMainFrame::OnFavoritesFile(UINT nID) +{ + nID -= ID_FAVORITES_FILE_START; + CAtlList sl; + AfxGetAppSettings().GetFav(FAV_FILE, sl); + + if (POSITION pos = sl.FindIndex(nID)) { + PlayFavoriteFile(sl.GetAt(pos)); + } +} + +void CMainFrame::PlayFavoriteFile(const CString& fav) +{ + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + CAtlList args; + REFERENCE_TIME rtStart = 0; + FileFavorite ff = ParseFavoriteFile(fav, args, &rtStart); + + auto firstFile = args.GetHead(); + if (!m_wndPlaylistBar.SelectFileInPlaylist(firstFile) && + (!CanSendToYoutubeDL(firstFile) || + !ProcessYoutubeDLURL(firstFile, false))) { + m_wndPlaylistBar.Open(args, false); + } + + m_wndPlaylistBar.SetCurLabel(ff.Name); + + if (GetPlaybackMode() == PM_FILE && args.GetHead() == m_lastOMD->title) { + m_pMS->SetPositions(&rtStart, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + OnPlayPlay(); + } else { + OpenCurPlaylistItem(rtStart); + } + +} + +FileFavorite CMainFrame::ParseFavoriteFile(const CString& fav, CAtlList& args, REFERENCE_TIME* prtStart) +{ + FileFavorite ff; + VERIFY(FileFavorite::TryParse(fav, ff, args)); + + abRepeat.positionA = ff.MarkA; + abRepeat.positionB = ff.MarkB; + + // Start at mark A (if set) + ff.Start = std::max(ff.Start, abRepeat.positionA); + + if (prtStart) { + *prtStart = ff.Start; + } + + // NOTE: This is just for the favorites but we could add a global settings that + // does this always when on. Could be useful when using removable devices. + // All you have to do then is plug in your 500 gb drive, full with movies and/or music, + // start MPC-HC (from the 500 gb drive) with a preloaded playlist and press play. + if (ff.RelativeDrive) { + // Get the drive MPC-HC is on and apply it to the path list + CString exePath = PathUtils::GetProgramPath(true); + + CPath exeDrive(exePath); + + if (exeDrive.StripToRoot()) { + POSITION pos = args.GetHeadPosition(); + + while (pos != nullptr) { + CString& stringPath = args.GetNext(pos); // Note the reference (!) + CPath path(stringPath); + + int rootLength = path.SkipRoot(); + + if (path.StripToRoot()) { + if (_tcsicmp(exeDrive, path) != 0) { // Do we need to replace the drive letter ? + // Replace drive letter + CString newPath(exeDrive); + + newPath += stringPath.Mid(rootLength); + + stringPath = newPath; // Note: Changes args.GetHead() + } + } + } + } + } + return ff; +} + +void CMainFrame::OnUpdateFavoritesFile(CCmdUI* pCmdUI) +{ + //UINT nID = pCmdUI->m_nID - ID_FAVORITES_FILE_START; +} + +void CMainFrame::OnRecentFile(UINT nID) +{ + CAtlList fns; + auto& MRU = AfxGetAppSettings().MRU; + RecentFileEntry r; + + // find corresponding item in MRU list, we can't directly use string from menu because it may have been shortened + nID -= ID_RECENT_FILE_START; + if (nID < MRU.GetSize()) { + r = MRU[nID]; + fns.AddHeadList(&r.fns); + } else { + ASSERT(false); + return; + } + + CloseMediaBeforeOpen(); + + if (fns.GetCount() == 1 && CanSendToYoutubeDL(r.fns.GetHead())) { + if (ProcessYoutubeDLURL(fns.GetHead(), false)) { + OpenCurPlaylistItem(); + return; + } else if (IsOnYDLWhitelist(fns.GetHead())) { + // don't bother trying to open this website URL directly + return; + } + } + + CAtlList subs; + subs.AddHeadList(&r.subs); + + if (!m_wndPlaylistBar.SelectFileInPlaylist(fns.GetHead())) { + m_wndPlaylistBar.Open(fns, false, &subs, r.title, _T(""), r.cue); + } + else { + m_wndPlaylistBar.ReplaceCurrentItem(fns, &subs, r.title, _T(""), r.cue); + } + + OpenCurPlaylistItem(); +} + +void CMainFrame::OnUpdateRecentFile(CCmdUI* pCmdUI) +{ + //UINT nID = pCmdUI->m_nID - ID_RECENT_FILE_START; +} + +void CMainFrame::OnFavoritesDVD(UINT nID) +{ + nID -= ID_FAVORITES_DVD_START; + + CAtlList sl; + AfxGetAppSettings().GetFav(FAV_DVD, sl); + + if (POSITION pos = sl.FindIndex(nID)) { + PlayFavoriteDVD(sl.GetAt(pos)); + } +} + +void CMainFrame::PlayFavoriteDVD(CString fav) +{ + CAtlList args; + CString fn; + CDVDStateStream stream; + + stream.AddRef(); + + ExplodeEsc(fav, args, _T(';'), 3); + args.RemoveHeadNoReturn(); // desc / name + CString state = args.RemoveHead(); // state + if (state != _T("0")) { + CStringToBin(state, stream.m_data); + } + fn = args.RemoveHead(); // path + + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + CComPtr pDvdState; + HRESULT hr = OleLoadFromStream((IStream*)&stream, IID_PPV_ARGS(&pDvdState)); + UNREFERENCED_PARAMETER(hr); + + CAutoPtr p(DEBUG_NEW OpenDVDData()); + if (p) { + p->path = fn; + p->pDvdState = pDvdState; + } + OpenMedia(p); +} + +void CMainFrame::OnUpdateFavoritesDVD(CCmdUI* pCmdUI) +{ + //UINT nID = pCmdUI->m_nID - ID_FAVORITES_DVD_START; +} + +void CMainFrame::OnFavoritesDevice(UINT nID) +{ + //nID -= ID_FAVORITES_DEVICE_START; +} + +void CMainFrame::OnUpdateFavoritesDevice(CCmdUI* pCmdUI) +{ + //UINT nID = pCmdUI->m_nID - ID_FAVORITES_DEVICE_START; +} + +// help + +void CMainFrame::OnHelpHomepage() +{ + ShellExecute(m_hWnd, _T("open"), WEBSITE_URL, nullptr, nullptr, SW_SHOWDEFAULT); +} + +void CMainFrame::OnHelpCheckForUpdate() +{ + UpdateChecker::CheckForUpdate(); +} + +void CMainFrame::OnHelpToolbarImages() +{ + ShellExecute(m_hWnd, _T("open"), _T("https://github.com/clsid2/mpc-hc/issues/382"), nullptr, nullptr, SW_SHOWDEFAULT); +} + +void CMainFrame::OnHelpDonate() +{ + ShellExecute(m_hWnd, _T("open"), _T("https://github.com/clsid2/mpc-hc/issues/383"), nullptr, nullptr, SW_SHOWDEFAULT); +} + +////////////////////////////////// + +static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + CAtlArray* ml = (CAtlArray*)dwData; + ml->Add(hMonitor); + return TRUE; +} + +void CMainFrame::SetDefaultWindowRect(int iMonitor) +{ + const CAppSettings& s = AfxGetAppSettings(); + CRect rcLastWindowPos = s.rcLastWindowPos; + + if (s.eCaptionMenuMode != MODE_SHOWCAPTIONMENU) { + if (s.eCaptionMenuMode == MODE_FRAMEONLY) { + ModifyStyle(WS_CAPTION, 0, SWP_NOZORDER); + } else if (s.eCaptionMenuMode == MODE_BORDERLESS) { + ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0, SWP_NOZORDER); + } + SetMenuBarVisibility(AFX_MBV_DISPLAYONFOCUS); + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } + + CMonitors monitors; + CMonitor monitor; + if (iMonitor > 0 && iMonitor <= monitors.GetCount()) { + monitor = monitors.GetMonitor(iMonitor - 1); + } else { + monitor = CMonitors::GetNearestMonitor(this); + } + + CSize windowSize; + bool tRememberPos = s.fRememberWindowPos; + MINMAXINFO mmi; + OnGetMinMaxInfo(&mmi); + + if (s.HasFixedWindowSize()) { + windowSize = CSize(std::max(s.sizeFixedWindow.cx, mmi.ptMinTrackSize.x), std::max(s.sizeFixedWindow.cy, mmi.ptMinTrackSize.y)); + if (s.fixedWindowPosition != NO_FIXED_POSITION) { + tRememberPos = true; + CRect monitorRect; + monitor.GetWorkAreaRect(&monitorRect); + monitorRect += s.fixedWindowPosition; + rcLastWindowPos.MoveToXY(monitorRect.left, monitorRect.top); + } + } else if (s.fRememberWindowSize) { + windowSize = rcLastWindowPos.Size(); + } else { + CRect windowRect; + GetWindowRect(&windowRect); + CRect clientRect; + GetClientRect(&clientRect); + + CSize logoSize = m_wndView.GetLogoSize(); + logoSize.cx = std::max(logoSize.cx, m_dpi.ScaleX(MIN_LOGO_WIDTH)); + logoSize.cy = std::max(logoSize.cy, m_dpi.ScaleY(MIN_LOGO_HEIGHT)); + + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); + + windowSize.cx = windowRect.Width() - clientRect.Width() + logoSize.cx + uLeft + uRight; + windowSize.cy = windowRect.Height() - clientRect.Height() + logoSize.cy + uTop + uBottom; + } + + bool bRestoredWindowPosition = false; + if (tRememberPos) { + CRect windowRect(rcLastWindowPos.TopLeft(), windowSize); + if ((!iMonitor && CMonitors::IsOnScreen(windowRect)) + || (iMonitor && monitor.IsOnMonitor(windowRect))) { + restoringWindowRect = true; + MoveWindow(windowRect); + restoringWindowRect = false; + bRestoredWindowPosition = true; + } + } + + if (!bRestoredWindowPosition) { + CRect windowRect(0, 0, std::max(windowSize.cx, mmi.ptMinTrackSize.x), std::max(windowSize.cy, mmi.ptMinTrackSize.y)); + monitor.CenterRectToMonitor(windowRect, TRUE); + SetWindowPos(nullptr, windowRect.left, windowRect.top, windowSize.cx, windowSize.cy, SWP_NOZORDER | SWP_NOACTIVATE); + } + + if (s.fSavePnSZoom) { + m_ZoomX = s.dZoomX; + m_ZoomY = s.dZoomY; + } +} + +void CMainFrame::SetDefaultFullscreenState() +{ + CAppSettings& s = AfxGetAppSettings(); + + bool clGoFullscreen = !(s.nCLSwitches & (CLSW_ADD | CLSW_THUMBNAILS)) && (s.nCLSwitches & CLSW_FULLSCREEN); + + if (clGoFullscreen && !s.slFiles.IsEmpty()) { + // ignore fullscreen if all files are audio + clGoFullscreen = false; + const CMediaFormats& mf = AfxGetAppSettings().m_Formats; + POSITION pos = s.slFiles.GetHeadPosition(); + while (pos) { + CString fpath = s.slFiles.GetNext(pos); + CString ext = fpath.Mid(fpath.ReverseFind('.') + 1); + if (!mf.FindExt(ext, true)) { + clGoFullscreen = true; + break; + } + } + } + + if (clGoFullscreen) { + if (s.IsD3DFullscreen()) { + m_fStartInD3DFullscreen = true; + } else { + bool launchingFullscreenSeparateControls = false; + if (s.bFullscreenSeparateControls) { + CMonitors monitors; + CMonitor currentMonitor = monitors.GetNearestMonitor(this); + CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); + if (fullscreenMonitor.IsMonitor()) { + launchingFullscreenSeparateControls = fullscreenMonitor != currentMonitor; + } + } + + if (launchingFullscreenSeparateControls) { + m_fStartInFullscreenSeparate = true; + } else { + ToggleFullscreen(true, true); + m_bNeedZoomAfterFullscreenExit = true; + } + } + s.nCLSwitches &= ~CLSW_FULLSCREEN; + } else if (s.fRememberWindowSize && s.fRememberWindowPos && !m_fFullScreen && s.fLastFullScreen) { + // Casimir666 : if fullscreen was on, put it on back + if (s.IsD3DFullscreen()) { + m_fStartInD3DFullscreen = true; + } else { + ToggleFullscreen(true, true); + m_bNeedZoomAfterFullscreenExit = true; + } + } +} + +void CMainFrame::RestoreDefaultWindowRect() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (!m_fFullScreen && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { + CSize windowSize; + + if (s.HasFixedWindowSize()) { + windowSize = s.sizeFixedWindow; + } else if (s.fRememberWindowSize) { + windowSize = s.rcLastWindowPos.Size(); + } else { + CRect windowRect; + GetWindowRect(&windowRect); + CRect clientRect; + GetClientRect(&clientRect); + + CSize logoSize = m_wndView.GetLogoSize(); + logoSize.cx = std::max(logoSize.cx, m_dpi.ScaleX(MIN_LOGO_WIDTH)); + logoSize.cy = std::max(logoSize.cy, m_dpi.ScaleY(MIN_LOGO_HEIGHT)); + + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); + + windowSize.cx = windowRect.Width() - clientRect.Width() + logoSize.cx + uLeft + uRight; + windowSize.cy = windowRect.Height() - clientRect.Height() + logoSize.cy + uTop + uBottom; + } + + if (s.fRememberWindowPos) { + MoveWindow(CRect(s.rcLastWindowPos.TopLeft(), windowSize)); + } else { + SetWindowPos(nullptr, 0, 0, windowSize.cx, windowSize.cy, SWP_NOMOVE | SWP_NOZORDER); + CenterWindow(); + } + } +} + +CRect CMainFrame::GetInvisibleBorderSize() const +{ + CRect invisibleBorders; + + if (IsWindows10OrGreater()) { + static const WinapiFunc + fnDwmGetWindowAttribute = { _T("Dwmapi.dll"), "DwmGetWindowAttribute" }; + + if (fnDwmGetWindowAttribute) { + if (SUCCEEDED(fnDwmGetWindowAttribute(GetSafeHwnd(), DWMWA_EXTENDED_FRAME_BOUNDS, &invisibleBorders, sizeof(RECT)))) { + CRect windowRect; + GetWindowRect(windowRect); + + invisibleBorders.TopLeft() = invisibleBorders.TopLeft() - windowRect.TopLeft(); + invisibleBorders.BottomRight() = windowRect.BottomRight() - invisibleBorders.BottomRight(); + } else { + ASSERT(false); + } + } + } + + return invisibleBorders; +} + +OAFilterState CMainFrame::GetMediaStateDirect() const +{ + OAFilterState ret = -1; + if (m_eMediaLoadState == MLS::LOADED) { + m_pMC->GetState(0, &ret); + } + return ret; +} + +OAFilterState CMainFrame::GetMediaState() const +{ + OAFilterState ret = -1; + if (m_eMediaLoadState == MLS::LOADED) { + if (m_CachedFilterState != -1) { + #if DEBUG & 0 + ret = GetMediaStateDirect(); + ASSERT(ret == m_CachedFilterState || m_fFrameSteppingActive); + #endif + return m_CachedFilterState; + } else { + m_pMC->GetState(0, &ret); + } + } + return ret; +} + +OAFilterState CMainFrame::UpdateCachedMediaState() +{ + m_CachedFilterState = GetMediaStateDirect(); + return m_CachedFilterState; +} + +bool CMainFrame::MediaControlRun(bool waitforcompletion) +{ + m_dwLastPause = 0; + if (m_pMC) { + m_CachedFilterState = State_Running; + if (FAILED(m_pMC->Run())) { + // still in transition to running state + if (waitforcompletion) { + m_CachedFilterState = -1; + m_pMC->GetState(0, &m_CachedFilterState); + ASSERT(m_CachedFilterState == State_Running); + } + }; + MediaTransportControlUpdateState(State_Running); + return true; + } + return false; +} + +bool CMainFrame::MediaControlPause(bool waitforcompletion) +{ + m_dwLastPause = GetTickCount64(); + if (m_pMC) { + m_CachedFilterState = State_Paused; + if (FAILED(m_pMC->Pause())) { + // still in transition to paused state + if (waitforcompletion) { + m_CachedFilterState = -1; + m_pMC->GetState(0, &m_CachedFilterState); + ASSERT(m_CachedFilterState == State_Paused); + } + } + MediaTransportControlUpdateState(State_Paused); + return true; + } + return false; +} + +bool CMainFrame::MediaControlStop(bool waitforcompletion) +{ + m_dwLastPause = 0; + if (m_pMC) { + m_pMC->GetState(0, &m_CachedFilterState); + if (m_CachedFilterState != State_Stopped) { + if (FAILED(m_pMC->Stop())) { + ASSERT(FALSE); + m_CachedFilterState = -1; + return false; + } + if (waitforcompletion) { + m_CachedFilterState = -1; + m_pMC->GetState(0, &m_CachedFilterState); + ASSERT(m_CachedFilterState == State_Stopped); + } else { + m_CachedFilterState = State_Stopped; + } + } + MediaTransportControlUpdateState(State_Stopped); + return true; + } + return false; +} + +bool CMainFrame::MediaControlStopPreview() +{ + if (m_pMC_preview) { + OAFilterState fs = -1; + m_pMC_preview->GetState(0, &fs); + if (fs != State_Stopped) { + if (FAILED(m_pMC_preview->Stop())) { + ASSERT(FALSE); + return false; + } + m_pMC_preview->GetState(0, &fs); + ASSERT(fs == State_Stopped); + } + return true; + } + return false; +} + +void CMainFrame::SetPlaybackMode(int iNewStatus) +{ + m_iPlaybackMode = iNewStatus; +} + +CSize CMainFrame::GetVideoSizeWithRotation(bool forPreview) const +{ + CSize ret = GetVideoSize(); + if (forPreview && m_pGB_preview) { + CFGManagerPlayer* fgmPreview = static_cast(m_pGB_preview.p); + if (fgmPreview && !fgmPreview->PreviewSupportsRotation()) { + //preview cannot rotate, so we need to reverse any default rotation that swapped x/y + int rotation = ((360 - m_iDefRotation) % 360) / 90; + if (rotation == 1 || rotation == 3) { + std::swap(ret.cx, ret.cy); + } + return ret; + } + } + + if (m_pCAP && !m_pCAP3) { //videosize does not consider manual rotation + int rotation = ((360 - nearest90(m_AngleZ)) % 360) / 90; //do not add in m_iDefRotation + if (rotation == 1 || rotation == 3) { //90 degrees + std::swap(ret.cx, ret.cy); + } + } + return ret; +} + +CSize CMainFrame::GetVideoSize() const +{ + CSize ret; + if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { + return ret; + } + + const CAppSettings& s = AfxGetAppSettings(); + CSize videoSize, preferedAR; + + if (m_pCAP) { + videoSize = m_pCAP->GetVideoSize(false); + preferedAR = m_pCAP->GetVideoSize(s.fKeepAspectRatio); + } else if (m_pMFVDC) { + m_pMFVDC->GetNativeVideoSize(&videoSize, &preferedAR); // TODO : check AR !! + } else if (m_pBV) { + m_pBV->GetVideoSize(&videoSize.cx, &videoSize.cy); + + long arx = 0, ary = 0; + CComQIPtr pBV2 = m_pBV; + // FIXME: It can hang here, for few seconds (CPU goes to 100%), after the window have been moving over to another screen, + // due to GetPreferredAspectRatio, if it happens before CAudioSwitcherFilter::DeliverEndFlush, it seems. + if (pBV2 && SUCCEEDED(pBV2->GetPreferredAspectRatio(&arx, &ary)) && arx > 0 && ary > 0) { + preferedAR.SetSize(arx, ary); + } + } + if (preferedAR.cx <= 0 || preferedAR.cy <= 0) { //due to IBasicVideo2 not being found, this could still be zero for .swf + preferedAR.SetSize(videoSize.cx, videoSize.cy); + } + + if (videoSize.cx <= 0 || videoSize.cy <= 0) { + return ret; + } + + if (s.fKeepAspectRatio) { + CSize overrideAR = s.GetAspectRatioOverride(); + DVD_VideoAttributes VATR; + if ((!overrideAR.cx || !overrideAR.cy) && GetPlaybackMode() == PM_DVD + && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { + overrideAR.SetSize(VATR.ulAspectX, VATR.ulAspectY); + } + if (overrideAR.cx > 0 && overrideAR.cy > 0) { + if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", double(overrideAR.cx) / overrideAR.cy))) { + ret = m_pCAP->GetVideoSize(false); + } else { + ret = CSize(MulDiv(videoSize.cy, overrideAR.cx, overrideAR.cy), videoSize.cy); + } + } else { + if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", 0.0))) { + ret = m_pCAP->GetVideoSize(false); + } else { + ret = CSize(MulDiv(videoSize.cy, preferedAR.cx, preferedAR.cy), videoSize.cy); + } + } + } else { + CSize originalVideoSize(0, 1); + if (m_pMVRI) { + m_pMVRI->GetSize("originalVideoSize", &originalVideoSize); + } + if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", + double(originalVideoSize.cx) / originalVideoSize.cy))) { + ret = m_pCAP->GetVideoSize(false); + } else { + ret = videoSize; + } + } + + if (s.fCompMonDeskARDiff + && s.iDSVideoRendererType != VIDRNDT_DS_EVR + && s.iDSVideoRendererType != VIDRNDT_DS_MADVR) + if (HDC hDC = ::GetDC(nullptr)) { + int _HORZSIZE = GetDeviceCaps(hDC, HORZSIZE); + int _VERTSIZE = GetDeviceCaps(hDC, VERTSIZE); + int _HORZRES = GetDeviceCaps(hDC, HORZRES); + int _VERTRES = GetDeviceCaps(hDC, VERTRES); + + if (_HORZSIZE > 0 && _VERTSIZE > 0 && _HORZRES > 0 && _VERTRES > 0) { + double a = 1.0 * _HORZSIZE / _VERTSIZE; + double b = 1.0 * _HORZRES / _VERTRES; + + if (b < a) { + ret.cy = (DWORD)(1.0 * ret.cy * a / b); + } else if (a < b) { + ret.cx = (DWORD)(1.0 * ret.cx * b / a); + } + } + + ::ReleaseDC(nullptr, hDC); + } + + return ret; +} + +void CMainFrame::HidePlaylistFullScreen(bool force /* = false */) +{ + if (force || m_fFullScreen) { + CAppSettings& s = AfxGetAppSettings(); + if (s.bHidePlaylistFullScreen && m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)) { + m_wndPlaylistBar.SetHiddenDueToFullscreen(true); + ShowControlBar(&m_wndPlaylistBar, FALSE, FALSE); + } + } +} + +void CMainFrame::ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo) +{ + if (IsD3DFullScreenMode()) { + ASSERT(FALSE); + return; + } + + CAppSettings& s = AfxGetAppSettings(); + + if (delayingFullScreen) { + return; //swallow request if we are in the delay period + } + + CMonitors monitors; + CMonitor defaultMonitor = monitors.GetPrimaryMonitor(); + CMonitor currentMonitor = monitors.GetNearestMonitor(this); + CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); + if (!fullscreenMonitor.IsMonitor()) { + fullscreenMonitor = currentMonitor; + } + bool fullScreenSeparate = s.bFullscreenSeparateControls && (m_pMFVDC || m_pVMRWC || m_pVW) && fullscreenMonitor.IsMonitor() && fullscreenMonitor != currentMonitor && (s.nCS & (CS_SEEKBAR | CS_TOOLBAR)); + + const CWnd* pInsertAfter = nullptr; + CRect windowRect; + DWORD dwRemove = 0, dwAdd = 0; + + if (!fullScreenSeparate && s.iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 + BOOL setEnabled = TRUE; + ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); + } + + bool restart_osd = false; + if (!m_pMVTO) { + m_OSD.Stop(); + restart_osd = s.fShowOSD || s.fShowDebugInfo; + } + + if (fullScreenSeparate) { + if (m_fFullScreen) { + m_fFullScreen = false; + } else { + if (!m_bNeedZoomAfterFullscreenExit && !s.HasFixedWindowSize()) { + // adjust control window size to minimal + m_bNeedZoomAfterFullscreenExit = true; + ZoomVideoWindow(ZOOM_DEFAULT_LEVEL, true); + } + m_fFullScreen = true; + } + s.fLastFullScreen = false; //not really, just fullScreenSecondMonitor + + if (m_fFullScreen) { + m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN); + + // Set the fullscreen display mode + if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo) { + AutoChangeMonitorMode(); + } + + CreateFullScreenWindow(false); + if (m_pD3DFSC && s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { + m_pD3DFSC->SetD3DFullscreen(true); + } + // Assign the windowed video frame and pass it to the relevant classes. + m_pVideoWnd = m_pDedicatedFSVideoWnd; + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } else if (m_pVMRWC) { + m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); + } + if (m_pVW) { + m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); + m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); + } + m_wndView.Invalidate(); + } else { + m_eventc.FireEvent(MpcEvent::SWITCHING_FROM_FULLSCREEN); + + if (m_pD3DFSC && s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { + m_pD3DFSC->SetD3DFullscreen(false); + } + m_pVideoWnd = &m_wndView; + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } else if (m_pVMRWC) { + m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); + } + if (m_pVW) { + m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); + m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); + } + if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { + SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift + } + + // Destroy the Fullscreen window and zoom the windowed video frame + m_pDedicatedFSVideoWnd->DestroyWindow(); + if (m_bNeedZoomAfterFullscreenExit) { + m_bNeedZoomAfterFullscreenExit = false; + if (s.fRememberZoomLevel) { + ZoomVideoWindow(); + } + } + } + MoveVideoWindow(); + + if (s.bHideWindowedControls) { + m_controls.UpdateToolbarsVisibility(); + } + } else { + m_fFullScreen = !m_fFullScreen; + s.fLastFullScreen = m_fFullScreen; + + if (m_fFullScreen) { + SetCursor(nullptr); // prevents cursor flickering when our window is not under the cursor + + m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN); + + HidePlaylistFullScreen(true); + + GetWindowRect(&m_lastWindowRect); + + if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo && GetPlaybackMode() != PM_NONE) { + AutoChangeMonitorMode(); + } + + dwRemove |= WS_CAPTION | WS_THICKFRAME; + if (s.fPreventMinimize && fullscreenMonitor != defaultMonitor) { + dwRemove |= WS_MINIMIZEBOX; + } + + m_bExtOnTop = !s.iOnTop && (GetExStyle() & WS_EX_TOPMOST); + pInsertAfter = &wndTopMost; + + if (fToNearest) { + fullscreenMonitor.GetMonitorRect(windowRect); + } else { + GetDesktopWindow()->GetWindowRect(windowRect); + } + } else { + m_eventc.FireEvent(MpcEvent::SWITCHING_FROM_FULLSCREEN); + + if (m_pVideoWnd != &m_wndView) { + m_pVideoWnd = &m_wndView; + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } else if (m_pVMRWC) { + m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); + } + if (m_pVW) { + m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); + m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); + } + } + m_pDedicatedFSVideoWnd->DestroyWindow(); + + if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { + SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift + } + + windowRect = m_lastWindowRect; + if (!monitors.IsOnScreen(windowRect)) { + currentMonitor.CenterRectToMonitor(windowRect, TRUE); + } + + dwAdd |= WS_MINIMIZEBOX; + if (s.eCaptionMenuMode != MODE_BORDERLESS) { + dwAdd |= WS_THICKFRAME; + if (s.eCaptionMenuMode != MODE_FRAMEONLY) { + dwAdd |= WS_CAPTION; + } + } + + if (m_wndPlaylistBar.IsHiddenDueToFullscreen() && !m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)) { + if (s.bHideWindowedControls) { + m_wndPlaylistBar.SetHiddenDueToFullscreen(false, true); + } else { + m_wndPlaylistBar.SetHiddenDueToFullscreen(false); + m_controls.ToggleControl(CMainFrameControls::Panel::PLAYLIST); + } + } + + // If MPC-HC wasn't previously set "on top" by an external tool, + // we restore the current internal on top state. (1/2) + if (!m_bExtOnTop) { + pInsertAfter = &wndNoTopMost; + } + } + + bool bZoomVideoWindow = false; + if (m_bNeedZoomAfterFullscreenExit && !m_fFullScreen) { + bZoomVideoWindow = s.fRememberZoomLevel; + m_bNeedZoomAfterFullscreenExit = false; + } + + ModifyStyle(dwRemove, dwAdd, SWP_NOZORDER); + SetWindowPos(pInsertAfter, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), + SWP_NOSENDCHANGING | SWP_FRAMECHANGED); + + // If MPC-HC wasn't previously set "on top" by an external tool, + // we restore the current internal on top state. (2/2) + if (!m_fFullScreen && !m_bExtOnTop) { + SetAlwaysOnTop(s.iOnTop); + } + + SetMenuBarVisibility((!m_fFullScreen && s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) + ? AFX_MBV_KEEPVISIBLE : AFX_MBV_DISPLAYONFOCUS); + + UpdateControlState(UPDATE_CONTROLS_VISIBILITY); + + if (bZoomVideoWindow) { + ZoomVideoWindow(); + } + MoveVideoWindow(); + } + + if (restart_osd) { + if (m_fFullScreen && m_pCAP3 && m_pMFVMB) { // MPCVR + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); + } else { + m_OSD.Start(m_pOSDWnd); + OSDBarSetPos(); + } + } + + if (m_fFullScreen) { + m_eventc.FireEvent(MpcEvent::SWITCHED_TO_FULLSCREEN); + } else { + m_eventc.FireEvent(MpcEvent::SWITCHED_FROM_FULLSCREEN); + } + + if (!fullScreenSeparate && s.iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 + UINT_PTR timerID = 0; + timerID = SetTimer(TIMER_WINDOW_FULLSCREEN, s.iFullscreenDelay, nullptr); + if (0 == timerID) { + BOOL setEnabled = FALSE; + ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); + } else { + delayingFullScreen = true; + } + RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE); + } +} + +void CMainFrame::ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo) +{ + if (m_pD3DFSC && m_pMFVDC) { + CAppSettings& s = AfxGetAppSettings(); + + bool bIsFullscreen = false; + m_pD3DFSC->GetD3DFullscreen(&bIsFullscreen); + s.fLastFullScreen = !bIsFullscreen; + + m_OSD.Stop(); + + if (bIsFullscreen) { + // Turn off D3D Fullscreen + m_pD3DFSC->SetD3DFullscreen(false); + + // Assign the windowed video frame and pass it to the relevant classes. + m_pVideoWnd = &m_wndView; + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + + if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { + SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift + } + + // Destroy the D3D Fullscreen window and zoom the windowed video frame + m_pDedicatedFSVideoWnd->DestroyWindow(); + if (m_bNeedZoomAfterFullscreenExit) { + if (s.fRememberZoomLevel) { + ZoomVideoWindow(); + } + m_bNeedZoomAfterFullscreenExit = false; + } + + if (s.fShowOSD) { + m_OSD.Start(m_pOSDWnd); + } + MoveVideoWindow(); + RecalcLayout(); + } else { + // Set the fullscreen display mode + if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo) { + AutoChangeMonitorMode(); + } + + // Create a new D3D Fullscreen window + CreateFullScreenWindow(); + + m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN_D3D); + + // Assign the windowed video frame and pass it to the relevant classes. + m_pVideoWnd = m_pDedicatedFSVideoWnd; + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + m_wndView.Invalidate(); + + MoveVideoWindow(); + + // Turn on D3D Fullscreen + m_pD3DFSC->SetD3DFullscreen(true); + + if (s.fShowOSD || s.fShowDebugInfo) { + if (m_pVMB || m_pMFVMB) { + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); + } + } + + m_eventc.FireEvent(MpcEvent::SWITCHED_TO_FULLSCREEN_D3D); + } + } else { + ASSERT(false); + } +} + +bool CMainFrame::GetCurDispMode(const CString& displayName, DisplayMode& dm) +{ + return GetDispMode(displayName, ENUM_CURRENT_SETTINGS, dm); +} + +bool CMainFrame::GetDispMode(CString displayName, int i, DisplayMode& dm) +{ + if (displayName == _T("Current") || displayName.IsEmpty()) { + CMonitor monitor = CMonitors::GetNearestMonitor(AfxGetApp()->m_pMainWnd); + monitor.GetName(displayName); + } + + DEVMODE devmode; + devmode.dmSize = sizeof(DEVMODE); + devmode.dmDriverExtra = 0; + + dm.bValid = !!EnumDisplaySettingsExW(displayName, i, &devmode, EDS_RAWMODE); + + if (dm.bValid) { + dm.size = CSize(devmode.dmPelsWidth, devmode.dmPelsHeight); + dm.bpp = devmode.dmBitsPerPel; + dm.freq = devmode.dmDisplayFrequency; + dm.dwDisplayFlags = devmode.dmDisplayFlags; + } + + return dm.bValid; +} + +void CMainFrame::SetDispMode(CString displayName, const DisplayMode& dm, int msAudioDelay) +{ + DisplayMode dmCurrent; + if (!GetCurDispMode(displayName, dmCurrent)) { + return; + } + + CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); + if (dm.size == dmCurrent.size && dm.bpp == dmCurrent.bpp && dm.freq == dmCurrent.freq) { + if (pASF) { + pASF->SetAudioTimeShift(msAudioDelay * 10000i64); + } + return; + } + + DEVMODE dmScreenSettings; + ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings)); + dmScreenSettings.dmSize = sizeof(dmScreenSettings); + dmScreenSettings.dmPelsWidth = dm.size.cx; + dmScreenSettings.dmPelsHeight = dm.size.cy; + dmScreenSettings.dmBitsPerPel = dm.bpp; + dmScreenSettings.dmDisplayFrequency = dm.freq; + dmScreenSettings.dmDisplayFlags = dm.dwDisplayFlags; + dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; + + if (displayName == _T("Current") || displayName.IsEmpty()) { + CMonitor monitor = CMonitors::GetNearestMonitor(AfxGetApp()->m_pMainWnd); + monitor.GetName(displayName); + } + + const auto& s = AfxGetAppSettings(); + LONG ret; + + m_eventc.FireEvent(MpcEvent::DISPLAY_MODE_AUTOCHANGING); + if (AfxGetAppSettings().autoChangeFSMode.bRestoreResAfterProgExit) { + ret = ChangeDisplaySettingsExW(displayName, &dmScreenSettings, nullptr, CDS_FULLSCREEN, nullptr); + } else { + ret = ChangeDisplaySettingsExW(displayName, &dmScreenSettings, nullptr, 0, nullptr); + } + m_eventc.FireEvent(MpcEvent::DISPLAY_MODE_AUTOCHANGED); + + msAudioDelay = ret == DISP_CHANGE_SUCCESSFUL ? msAudioDelay : (s.fAudioTimeShift ? s.iAudioTimeShift : 0); + if (pASF) { + pASF->SetAudioTimeShift(msAudioDelay * 10000i64); + } +} + +void CMainFrame::AutoChangeMonitorMode() +{ + const CAppSettings& s = AfxGetAppSettings(); + if (s.autoChangeFSMode.modes.empty()) { + return; + } + + double dMediaFPS = 0.0; + + if (GetPlaybackMode() == PM_FILE) { + REFERENCE_TIME m_rtTimePerFrame = 1; + // if ExtractAvgTimePerFrame isn't executed then MediaFPS=10000000.0, + // (int)(MediaFPS + 0.5)=10000000 and SetDispMode is executed to Default. + BeginEnumFilters(m_pGB, pEF, pBF) { + BeginEnumPins(pBF, pEP, pPin) { + CMediaTypeEx mt; + PIN_DIRECTION dir; + if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_OUTPUT && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame)) { + if (m_rtTimePerFrame == 0) { + m_rtTimePerFrame = 1; + } + } + } + } + EndEnumPins; + } + EndEnumFilters; + dMediaFPS = 10000000.0 / m_rtTimePerFrame; + } else if (GetPlaybackMode() == PM_DVD) { + DVD_PLAYBACK_LOCATION2 Location; + if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) { + dMediaFPS = 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; + } + } + + for (const auto& mode : s.autoChangeFSMode.modes) { + if (mode.bChecked && dMediaFPS >= mode.dFrameRateStart && dMediaFPS <= mode.dFrameRateStop) { + SetDispMode(s.strFullScreenMonitorID, mode.dm, mode.msAudioDelay); + return; + } + } + SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift +} + +void CMainFrame::MoveVideoWindow(bool fShowStats/* = false*/, bool bSetStoppedVideoRect/* = false*/) +{ + m_dLastVideoScaleFactor = 0; + m_lastVideoSize.SetSize(0, 0); + + if (!m_bDelaySetOutputRect && GetLoadState() == MLS::LOADED && !m_fAudioOnly && IsWindowVisible()) { + CRect windowRect(0, 0, 0, 0); + CRect videoRect(0, 0, 0, 0); + + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->GetClientRect(windowRect); + } else { + m_wndView.GetClientRect(windowRect); + } + + const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); + const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); + if (bPanelsOnVideo) { + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetVisibleDockZones(uTop, uLeft, uRight, uBottom); + if (!bToolbarsOnVideo) { + uBottom -= m_controls.GetVisibleToolbarsHeight(); + } + windowRect.InflateRect(uLeft, uTop, uRight, uBottom); + } else if (bToolbarsOnVideo) { + windowRect.bottom += m_controls.GetVisibleToolbarsHeight(); + } + + int nCompensateForMenubar = m_bShowingFloatingMenubar && !IsD3DFullScreenMode() ? GetSystemMetrics(SM_CYMENU) : 0; + windowRect.bottom += nCompensateForMenubar; + + OAFilterState fs = GetMediaState(); + if (fs != State_Stopped || bSetStoppedVideoRect || m_fShockwaveGraph) { + const CSize szVideo = GetVideoSize(); + + m_dLastVideoScaleFactor = std::min((double)windowRect.Size().cx / szVideo.cx, + (double)windowRect.Size().cy / szVideo.cy); + m_lastVideoSize = szVideo; + + const double dVideoAR = double(szVideo.cx) / szVideo.cy; + + // because we don't have a way to get .swf size reliably, + // other modes don't make sense + const dvstype iDefaultVideoSize = m_fShockwaveGraph ? DVS_STRETCH : + static_cast(AfxGetAppSettings().iDefaultVideoSize); + + const double dWRWidth = windowRect.Width(); + const double dWRHeight = windowRect.Height(); + + double dVRWidth = dWRHeight * dVideoAR; + double dVRHeight; + + double madVRZoomFactor = 1.0; + + switch (iDefaultVideoSize) { + case DVS_HALF: + dVRWidth = szVideo.cx * 0.5; + dVRHeight = szVideo.cy * 0.5; + break; + case DVS_NORMAL: + dVRWidth = szVideo.cx; + dVRHeight = szVideo.cy; + break; + case DVS_DOUBLE: + dVRWidth = szVideo.cx * 2.0; + dVRHeight = szVideo.cy * 2.0; + break; + case DVS_STRETCH: + dVRWidth = dWRWidth; + dVRHeight = dWRHeight; + break; + default: + ASSERT(FALSE); + [[fallthrough]]; // Fallback to "Touch Window From Inside" if settings were corrupted. + case DVS_FROMINSIDE: + if (dWRWidth < dVRWidth) { + dVRWidth = dWRWidth; + dVRHeight = dVRWidth / dVideoAR; + } else { + dVRHeight = dWRHeight; + } + break; + case DVS_FROMOUTSIDE: + if (dWRWidth > dVRWidth) { + dVRWidth = dWRWidth; + dVRHeight = dVRWidth / dVideoAR; + } else { + dVRHeight = dWRHeight; + } + break; + case DVS_ZOOM1: + case DVS_ZOOM2: { + double scale = iDefaultVideoSize == DVS_ZOOM1 ? 1.0 / 3.0 : 2.0 / 3.0; + double minw = std::min(dWRWidth, dVRWidth); + double zoomValue = (std::max(dWRWidth, dVRWidth) - minw) * scale; + madVRZoomFactor = (minw + zoomValue) / minw; + dVRWidth = minw + zoomValue; + dVRHeight = dVRWidth / dVideoAR; + break; + } + } + + // Scale video frame + double dScaledVRWidth = m_ZoomX * dVRWidth; + double dScaledVRHeight = m_ZoomY * dVRHeight; + + auto vertAlign = AfxGetAppSettings().iVerticalAlignVideo; + double vertAlignOffset = 0; + if (vertAlign == CAppSettings::verticalAlignVideoType::ALIGN_TOP) { + vertAlignOffset = -(dWRHeight - dScaledVRHeight) / 2; + } else if (vertAlign == CAppSettings::verticalAlignVideoType::ALIGN_BOTTOM) { + vertAlignOffset = (dWRHeight - dScaledVRHeight) / 2; + } + + // Position video frame + // left and top parts are allowed to be negative + videoRect.left = lround(m_PosX * (dWRWidth * 3.0 - dScaledVRWidth) - dWRWidth); + videoRect.top = lround(m_PosY * (dWRHeight * 3.0 - dScaledVRHeight) - dWRHeight + vertAlignOffset); + // right and bottom parts are always at picture center or beyond, so never negative + videoRect.right = lround(videoRect.left + dScaledVRWidth); + videoRect.bottom = lround(videoRect.top + dScaledVRHeight); + + ASSERT(videoRect.Width() == lround(dScaledVRWidth)); + ASSERT(videoRect.Height() == lround(dScaledVRHeight)); + + if (m_pMVRC) { + static constexpr const LPCWSTR madVRModesMap[] = { + L"50%", + L"100%", + L"200%", + L"stretch", + L"touchInside", + L"touchOutside", + L"touchInside", + L"touchInside" + }; + + // workaround for rotated video with MadVR + bool swapxy = ((m_iDefRotation + m_AngleZ) / 90) & 1; + double mvr_ZoomX = swapxy ? m_ZoomY : m_ZoomX; + double mvr_ZoomY = swapxy ? m_ZoomX : m_ZoomY; + double mvr_PosX = swapxy ? m_PosY : m_PosX; + double mvr_PosY = swapxy ? m_PosX : m_PosY; + + m_pMVRC->SendCommandString("setZoomMode", const_cast(madVRModesMap[iDefaultVideoSize])); + m_pMVRC->SendCommandDouble("setZoomFactorX", madVRZoomFactor * mvr_ZoomX); + m_pMVRC->SendCommandDouble("setZoomFactorY", madVRZoomFactor * mvr_ZoomY); + m_pMVRC->SendCommandDouble("setZoomOffsetX", 2 * mvr_PosX - 1.0); + m_pMVRC->SendCommandDouble("setZoomOffsetY", 2 * mvr_PosY - 1.0); + } + + if (fShowStats) { + CString info; + info.Format(_T("Pos %.3f %.3f, Zoom %.3f %.3f, AR %.3f"), m_PosX, m_PosY, m_ZoomX, m_ZoomY, double(videoRect.Width()) / videoRect.Height()); + SendStatusMessage(info, 3000); + } + } else if (m_pMVRC) { + m_pMVRC->SendCommandString("setZoomMode", const_cast(L"autoDetect")); + } + + windowRect.top -= nCompensateForMenubar; + windowRect.bottom -= nCompensateForMenubar; + + if (m_pCAP) { + m_pCAP->SetPosition(windowRect, videoRect); + UpdateSubtitleRenderingParameters(); + } else { + if (m_pBV) { + m_pBV->SetDefaultSourcePosition(); + m_pBV->SetDestinationPosition(videoRect.left, videoRect.top, videoRect.Width(), videoRect.Height()); + } + if (m_pVW) { + m_pVW->SetWindowPosition(windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height()); + } + + if (m_pMFVDC) { + m_pMFVDC->SetVideoPosition(nullptr, &windowRect); + } + } + + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->SetVideoRect(&windowRect); + } else { + m_wndView.SetVideoRect(&windowRect); + } + } else { + m_wndView.SetVideoRect(); + } +} + +void CMainFrame::SetPreviewVideoPosition() { + if (m_bUseSeekPreview) { + CPoint point; + GetCursorPos(&point); + m_wndSeekBar.ScreenToClient(&point); + m_wndSeekBar.UpdateToolTipPosition(point); + + CRect wr; + m_wndPreView.GetVideoRect(&wr); + + const CSize ws(wr.Size()); + int w = ws.cx; + int h = ws.cy; + + const CSize arxy(GetVideoSizeWithRotation()); + { + const int dh = ws.cy; + const int dw = MulDiv(dh, arxy.cx, arxy.cy); + + int minw = dw; + int maxw = dw; + if (ws.cx < dw) { + minw = ws.cx; + } else if (ws.cx > dw) { + maxw = ws.cx; + } + + const float scale = 1 / 3.0f; + w = int(minw + (maxw - minw) * scale); + h = MulDiv(w, arxy.cy, arxy.cx); + } + + const CPoint pos(int(m_PosX * (wr.Width() * 3 - w) - wr.Width()), int(m_PosY * (wr.Height() * 3 - h) - wr.Height())); + const CRect vr(pos, CSize(w, h)); + + if (m_pMFVDC_preview) { + m_pMFVDC_preview->SetVideoPosition(nullptr, wr); + m_pMFVDC_preview->SetAspectRatioMode(MFVideoARMode_PreservePicture); + } + if (m_pVMR9C_preview) { + m_pVMR9C_preview->SetVideoPosition(nullptr, wr); + m_pVMR9C_preview->SetAspectRatioMode(VMR9ARMode_LetterBox); + } + if (m_pCAP2_preview) { + m_pCAP2_preview->SetPosition(wr, wr); + } + + if (m_pBV_preview) { + m_pBV_preview->SetDefaultSourcePosition(); + m_pBV_preview->SetDestinationPosition(vr.left, vr.top, vr.Width(), vr.Height()); + } + if (m_pVW_preview) { + m_pVW_preview->SetWindowPosition(wr.left, wr.top, wr.Width(), wr.Height()); + } + } +} + +void CMainFrame::HideVideoWindow(bool fHide) +{ + CRect wr; + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->GetClientRect(&wr); + } else if (!m_fFullScreen) { + m_wndView.GetClientRect(&wr); + } else { + GetWindowRect(&wr); + + // this code is needed to work in fullscreen on secondary monitor + CRect r; + m_wndView.GetWindowRect(&r); + wr -= r.TopLeft(); + } + + if (m_pCAP) { + if (fHide) { + CRect vr = CRect(0, 0, 0, 0); + m_pCAP->SetPosition(vr, vr); // hide + } else { + m_pCAP->SetPosition(wr, wr); // show + } + } + m_bLockedZoomVideoWindow = fHide; +} + +CSize CMainFrame::GetVideoOrArtSize(MINMAXINFO& mmi) +{ + const auto& s = AfxGetAppSettings(); + CSize videoSize; + OnGetMinMaxInfo(&mmi); + + if (m_fAudioOnly) { + videoSize = m_wndView.GetLogoSize(); + + if (videoSize.cx > videoSize.cy) { + if (videoSize.cx > s.nCoverArtSizeLimit) { + videoSize.cy = MulDiv(videoSize.cy, s.nCoverArtSizeLimit, videoSize.cx); + videoSize.cx = s.nCoverArtSizeLimit; + } + } else { + if (videoSize.cy > s.nCoverArtSizeLimit) { + videoSize.cx = MulDiv(videoSize.cx, s.nCoverArtSizeLimit, videoSize.cy); + videoSize.cy = s.nCoverArtSizeLimit; + } + } + } else { + videoSize = GetVideoSize(); + } + return videoSize; +} + +CSize CMainFrame::GetZoomWindowSize(double dScale, bool ignore_video_size) +{ + CSize ret; + + if (dScale >= 0.0 && GetLoadState() == MLS::LOADED) { + const auto& s = AfxGetAppSettings(); + MINMAXINFO mmi; + CSize videoSize = GetVideoOrArtSize(mmi); + + if (ignore_video_size || videoSize.cx <= 1 || videoSize.cy <= 1) { + videoSize.SetSize(0, 0); + } + if (videoSize.cx == 0 || m_fAudioOnly && videoSize.cy < 300) { + CRect windowRect; + GetWindowRect(windowRect); + if (windowRect.Height() < 420 && windowRect.Width() < 3800) { + // keep existing width, since it probably was intentionally made wider by user + mmi.ptMinTrackSize.x = std::max(windowRect.Width(), mmi.ptMinTrackSize.x); + if (m_fAudioOnly) { + // also keep existing height + videoSize.SetSize(0, 0); + mmi.ptMinTrackSize.y = std::max(windowRect.Height(), mmi.ptMinTrackSize.y); + } + } + + } + + CSize videoTargetSize = videoSize; + + CSize controlsSize; + const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); + const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); + if (!bPanelsOnVideo) { + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); + if (bToolbarsOnVideo) { + uBottom -= m_controls.GetToolbarsHeight(); + } + controlsSize.cx = uLeft + uRight; + controlsSize.cy = uTop + uBottom; + } else if (!bToolbarsOnVideo) { + controlsSize.cy = m_controls.GetToolbarsHeight(); + } + + CRect decorationsRect; + VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU, + GetWindowExStyle(m_hWnd))); + + CRect workRect; + CMonitors::GetNearestMonitor(this).GetWorkAreaRect(workRect); + + if (workRect.Width() && workRect.Height()) { + // account for invisible borders on Windows 10 by allowing + // the window to go out of screen a bit + if (IsWindows10OrGreater()) { + workRect.InflateRect(GetInvisibleBorderSize()); + } + + if (videoSize.cx > 0) { + // don't go larger than the current monitor working area and prevent black bars in this case + CSize videoSpaceSize = workRect.Size() - controlsSize - decorationsRect.Size(); + + // Do not adjust window size for video frame aspect ratio when video size is independent from window size + const bool bAdjustWindowAR = !(s.iDefaultVideoSize == DVS_HALF || s.iDefaultVideoSize == DVS_NORMAL || s.iDefaultVideoSize == DVS_DOUBLE); + const double videoAR = videoSize.cx / (double)videoSize.cy; + + videoTargetSize = CSize(int(videoSize.cx * dScale + 0.5), int(videoSize.cy * dScale + 0.5)); + + if (videoTargetSize.cx > videoSpaceSize.cx) { + videoTargetSize.cx = videoSpaceSize.cx; + if (bAdjustWindowAR) { + videoTargetSize.cy = std::lround(videoSpaceSize.cx / videoAR); + } + } + + if (videoTargetSize.cy > videoSpaceSize.cy) { + videoTargetSize.cy = videoSpaceSize.cy; + if (bAdjustWindowAR) { + videoTargetSize.cx = std::lround(videoSpaceSize.cy * videoAR); + } + } + } + } else { + ASSERT(FALSE); + } + + ret = videoTargetSize + controlsSize + decorationsRect.Size(); + ret.cx = std::max(ret.cx, mmi.ptMinTrackSize.x); + ret.cy = std::max(ret.cy, mmi.ptMinTrackSize.y); + } else { + ASSERT(FALSE); + } + + return ret; +} + +bool CMainFrame::GetWorkAreaRect(CRect& work) { + MONITORINFO mi = { sizeof(mi) }; + if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { + work = mi.rcWork; + // account for invisible borders on Windows 10 by allowing + // the window to go out of screen a bit + if (IsWindows10OrGreater()) { + work.InflateRect(GetInvisibleBorderSize()); + } + return true; + } + return false; +} + +CRect CMainFrame::GetZoomWindowRect(const CSize& size, bool ignoreSavedPosition /*= false*/) +{ + const auto& s = AfxGetAppSettings(); + CRect ret; + GetWindowRect(ret); + + CRect rcWork; + if (GetWorkAreaRect(rcWork)) { + CSize windowSize(size); + + // don't go larger than the current monitor working area + windowSize.cx = std::min(windowSize.cx, rcWork.Width()); + windowSize.cy = std::min(windowSize.cy, rcWork.Height()); + + // retain snapping or try not to be move the center of the window + // if we don't remember its position + if (m_bWasSnapped && ret.left == rcWork.left) { + // do nothing + } else if (m_bWasSnapped && ret.right == rcWork.right) { + ret.left = ret.right - windowSize.cx; + } else if (!s.fRememberWindowPos || ignoreSavedPosition) { + ret.left += (ret.right - ret.left) / 2 - windowSize.cx / 2; + } + if (m_bWasSnapped && ret.top == rcWork.top) { + // do nothing + } else if (m_bWasSnapped && ret.bottom == rcWork.bottom) { + ret.top = ret.bottom - windowSize.cy; + } else if (!s.fRememberWindowPos || ignoreSavedPosition) { + ret.top += (ret.bottom - ret.top) / 2 - windowSize.cy / 2; + } + + ret.right = ret.left + windowSize.cx; + ret.bottom = ret.top + windowSize.cy; + + // don't go beyond the current monitor working area + if (ret.right > rcWork.right) { + ret.OffsetRect(rcWork.right - ret.right, 0); + } + if (ret.left < rcWork.left) { + ret.OffsetRect(rcWork.left - ret.left, 0); + } + if (ret.bottom > rcWork.bottom) { + ret.OffsetRect(0, rcWork.bottom - ret.bottom); + } + if (ret.top < rcWork.top) { + ret.OffsetRect(0, rcWork.top - ret.top); + } + } else { + ASSERT(FALSE); + } + + return ret; +} + +void CMainFrame::ZoomVideoWindow(double dScale/* = ZOOM_DEFAULT_LEVEL*/, bool ignore_video_size /*= false*/) +{ + const auto& s = AfxGetAppSettings(); + + if ((GetLoadState() != MLS::LOADED) || + (m_nLockedZoomVideoWindow > 0) || m_bLockedZoomVideoWindow) { + if (m_nLockedZoomVideoWindow > 0) { + m_nLockedZoomVideoWindow--; + } + return; + } + + // Leave fullscreen when changing the zoom level + if (IsFullScreenMode()) { + OnViewFullscreen(); + } + + if (!s.HasFixedWindowSize()) { + ShowWindow(SW_SHOWNOACTIVATE); + if (dScale == (double)ZOOM_DEFAULT_LEVEL) { + if (s.fRememberWindowSize) { + return; // ignore default auto-zoom setting + } + dScale = + s.iZoomLevel == -1 ? 0.25 : + s.iZoomLevel == 0 ? 0.5 : + s.iZoomLevel == 1 ? 1.0 : + s.iZoomLevel == 2 ? 2.0 : + s.iZoomLevel == 3 ? GetZoomAutoFitScale() : +// s.iZoomLevel == 4 ? GetZoomAutoFitScale(true) : + 1.0; + } else if (dScale == (double)ZOOM_AUTOFIT) { + dScale = GetZoomAutoFitScale(); + } else if (dScale <= 0.0) { + ASSERT(FALSE); + return; + } + MoveWindow(GetZoomWindowRect(GetZoomWindowSize(dScale, ignore_video_size), !s.fRememberWindowPos)); + } +} + +double CMainFrame::GetZoomAutoFitScale() +{ + if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { + return 1.0; + } + + const CAppSettings& s = AfxGetAppSettings(); + + CSize arxy = GetVideoSize(); + + // get the work area + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); + GetMonitorInfo(hMonitor, &mi); + RECT& wa = mi.rcWork; + + DWORD style = GetStyle(); + CSize decorationsSize(0, 0); + + if (style & WS_CAPTION) { + // caption + decorationsSize.cy += GetSystemMetrics(SM_CYCAPTION); + // menu + if (s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) { + decorationsSize.cy += GetSystemMetrics(SM_CYMENU); + } + } + + if (style & WS_THICKFRAME) { + // vertical borders + decorationsSize.cx += 2 * ::GetSystemMetrics(SM_CXSIZEFRAME); + // horizontal borders + decorationsSize.cy += 2 * ::GetSystemMetrics(SM_CYSIZEFRAME); + + // account for invisible borders on Windows 10 + if (IsWindows10OrGreater()) { + RECT invisibleBorders = GetInvisibleBorderSize(); + + decorationsSize.cx -= (invisibleBorders.left + invisibleBorders.right); + decorationsSize.cy -= (invisibleBorders.top + invisibleBorders.bottom); + } + + if (!(style & WS_CAPTION)) { + decorationsSize.cx -= 2; + decorationsSize.cy -= 2; + } + } + + const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); + const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); + if (!bPanelsOnVideo) { + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); + if (bToolbarsOnVideo) { + uBottom -= m_controls.GetVisibleToolbarsHeight(); + } + decorationsSize.cx += uLeft + uRight; + decorationsSize.cy += uTop + uBottom; + } else if (!bToolbarsOnVideo) { + decorationsSize.cy -= m_controls.GetVisibleToolbarsHeight(); + } + + LONG width = wa.right - wa.left; + LONG height = wa.bottom - wa.top; + + double sxMin = ((double)width * s.nAutoFitFactorMin / 100 - decorationsSize.cx) / arxy.cx; + double syMin = ((double)height * s.nAutoFitFactorMin / 100 - decorationsSize.cy) / arxy.cy; + sxMin = std::min(sxMin, syMin); + // Take movie aspect ratio into consideration + // The scaling is computed so that the height is an integer value + syMin = floor(arxy.cy * floor(arxy.cx * sxMin + 0.5) / arxy.cx + 0.5) / arxy.cy; + + double sxMax = ((double)width * s.nAutoFitFactorMax / 100 - decorationsSize.cx) / arxy.cx; + double syMax = ((double)height * s.nAutoFitFactorMax / 100 - decorationsSize.cy) / arxy.cy; + sxMax = std::min(sxMax, syMax); + // Take movie aspect ratio into consideration + // The scaling is computed so that the height is an integer value + syMax = floor(arxy.cy * floor(arxy.cx * sxMax + 0.5) / arxy.cx + 0.5) / arxy.cy; + + + if (syMin < 0.0 || syMax < 0.0) { + ASSERT(FALSE); + syMin = 0.0; + syMax = 0.0; + } + + if (syMin > 1.0) { + return syMin; + } + if (syMax < 1.0) { + return syMax; + } + return 1.0; + +} + +void CMainFrame::RepaintVideo(const bool bForceRepaint/* = false*/) +{ + if (!m_bDelaySetOutputRect && (m_pCAP || m_pMFVDC)) { + OAFilterState fs = GetMediaState(); + if (fs == State_Paused || fs == State_Stopped || bForceRepaint || (m_bDVDStillOn && GetPlaybackMode() == PM_DVD)) { + if (m_pCAP) { + m_pCAP->Paint(false); + } else if (m_pMFVDC) { + m_pMFVDC->RepaintVideo(); + } + } + } +} + +ShaderC* CMainFrame::GetShader(CString path, bool bD3D11) +{ + ShaderC* pShader = nullptr; + + CString shadersDir = ShaderList::GetShadersDir(); + CString shadersDir11 = ShaderList::GetShadersDir11(); + CString tPath = path; + tPath.Replace(shadersDir, shadersDir11); + + //if the shader exists in the Shaders11 folder, use that one + if (bD3D11 && ::PathFileExistsW(tPath)) { + path = tPath; + } + + for (auto& shader : m_ShaderCache) { + if (shader.Match(path, bD3D11)) { + pShader = &shader; + break; + } + } + + if (!pShader) { + if (::PathFileExistsW(path)) { + CStdioFile file; + if (file.Open(path, CFile::modeRead | CFile::shareDenyWrite | CFile::typeText)) { + ShaderC shader; + shader.label = path; + + CString str; + file.ReadString(str); // read first string + if (str.Left(25) == L"// $MinimumShaderProfile:") { + shader.profile = str.Mid(25).Trim(); // shader version property + } else { + file.SeekToBegin(); + } + + if (shader.profile == L"ps_4_0" && !bD3D11 || shader.profile == L"ps_5_0") { + ASSERT(false); + return nullptr; + } else if (bD3D11) { + shader.profile = L"ps_4_0"; + } else if (shader.profile == L"ps_3_sw") { + shader.profile = L"ps_3_0"; + } else if (shader.profile != L"ps_2_0" + && shader.profile != L"ps_2_a" + && shader.profile != L"ps_2_b" + && shader.profile != L"ps_3_0") { + shader.profile = L"ps_3_0"; + } + + while (file.ReadString(str)) { + shader.srcdata += str + L"\n"; + } + + shader.length = file.GetLength(); + + FILETIME ftCreate, ftAccess, ftWrite; + if (GetFileTime(file.m_hFile, &ftCreate, &ftAccess, &ftWrite)) { + shader.ftwrite = ftWrite; + } + + file.Close(); + + m_ShaderCache.push_back(shader); + pShader = &m_ShaderCache.back(); + } + } + } + + return pShader; +} + +bool CMainFrame::SaveShaderFile(ShaderC* shader) +{ + CString path; + if (AfxGetMyApp()->GetAppSavePath(path)) { + path.AppendFormat(L"Shaders\\%s.hlsl", static_cast(shader->label)); + + CStdioFile file; + if (file.Open(path, CFile::modeWrite | CFile::shareExclusive | CFile::typeText)) { + file.SetLength(0); + + CString str; + str.Format(L"// $MinimumShaderProfile: %s\n", static_cast(shader->profile)); + file.WriteString(static_cast(str)); + + file.WriteString(static_cast(shader->srcdata)); + file.Close(); + + // delete out-of-date data from the cache + for (auto it = m_ShaderCache.begin(), end = m_ShaderCache.end(); it != end; ++it) { + if (it->Match(shader->label, false)) { + m_ShaderCache.erase(it); + break; + } + } + + return true; + } + } + return false; +} + +bool CMainFrame::DeleteShaderFile(LPCWSTR label) +{ + CString path; + if (AfxGetMyApp()->GetAppSavePath(path)) { + path.AppendFormat(L"Shaders\\%s.hlsl", label); + + if (!::PathFileExistsW(path) || ::DeleteFileW(path)) { + // if the file is missing or deleted successfully, then remove it from the cache + for (auto it = m_ShaderCache.begin(), end = m_ShaderCache.end(); it != end; ++it) { + if (it->Match(label, false)) { + m_ShaderCache.erase(it); + return true; + } + } + } + } + + return false; +} + +void CMainFrame::TidyShaderCache() +{ + CString appsavepath; + if (!AfxGetMyApp()->GetAppSavePath(appsavepath)) { + return; + } + + for (auto it = m_ShaderCache.cbegin(); it != m_ShaderCache.cend(); ) { + CString path(appsavepath); + path += L"Shaders\\"; + path += (*it).label + L".hlsl"; + + CFile file; + if (file.Open(path, CFile::modeRead | CFile::modeCreate | CFile::shareDenyNone)) { + ULONGLONG length = file.GetLength(); + FILETIME ftCreate = {}, ftAccess = {}, ftWrite = {}; + GetFileTime(file.m_hFile, &ftCreate, &ftAccess, &ftWrite); + + file.Close(); + + if ((*it).length == length && CompareFileTime(&(*it).ftwrite, &ftWrite) == 0) { + it++; + continue; // actual shader + } + } + + m_ShaderCache.erase(it++); // outdated shader + } +} + +void CMainFrame::SetShaders(bool bSetPreResize/* = true*/, bool bSetPostResize/* = true*/) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + const auto& s = AfxGetAppSettings(); + bool preFailed = false, postFailed = false; + + if (m_pCAP3) { //interfaces for madVR and MPC-VR + TidyShaderCache(); + const int PShaderMode = m_pCAP3->GetPixelShaderMode(); + if (PShaderMode != 9 && PShaderMode != 11) { + return; + } + + m_pCAP3->ClearPixelShaders(TARGET_FRAME); + m_pCAP3->ClearPixelShaders(TARGET_SCREEN); + int shadercount = 0; + if (bSetPreResize) { + int preTarget; + if (s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { //for now MPC-VR does not support pre-size shaders + preTarget = TARGET_SCREEN; + } else { + preTarget = TARGET_FRAME; + } + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { + ShaderC* pShader = GetShader(shader.filePath, PShaderMode == 11); + if (pShader) { + shadercount++; + CStringW label; + label.Format(L"Shader%d", shadercount); + CStringA profile = pShader->profile; + CStringA srcdata = pShader->srcdata; + if (FAILED(m_pCAP3->AddPixelShader(preTarget, label, profile, srcdata))) { + preFailed = true; + m_pCAP3->ClearPixelShaders(preTarget); + break; + } + } + } + } + if (bSetPostResize) { + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize().ExpandMultiPassShaderList()) { + ShaderC* pShader = GetShader(shader.filePath, PShaderMode == 11); + if (pShader) { + shadercount++; + CStringW label; + label.Format(L"Shader%d", shadercount); + CStringA profile = pShader->profile; + CStringA srcdata = pShader->srcdata; + if (FAILED(m_pCAP3->AddPixelShader(TARGET_SCREEN, label, profile, srcdata))) { + postFailed = true; + m_pCAP3->ClearPixelShaders(TARGET_SCREEN); + break; + } + } + } + } + } else if (m_pCAP2) { + // When pTarget parameter of ISubPicAllocatorPresenter2::SetPixelShader2() is nullptr, + // internal video renderers select maximum available profile and madVR (the only external renderer that + // supports shader part of ISubPicAllocatorPresenter2 interface) seems to ignore it altogether. + m_pCAP2->SetPixelShader2(nullptr, nullptr, false); + if (bSetPreResize) { + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { + if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, false))) { + preFailed = true; + m_pCAP2->SetPixelShader2(nullptr, nullptr, false); + break; + } + } + } + m_pCAP2->SetPixelShader2(nullptr, nullptr, true); + if (bSetPostResize) { + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize().ExpandMultiPassShaderList()) { + if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, true))) { + postFailed = true; + m_pCAP2->SetPixelShader2(nullptr, nullptr, true); + break; + } + } + } + } else if (m_pCAP) { + // shouldn't happen, all known renderers that support ISubPicAllocatorPresenter interface + // support ISubPicAllocatorPresenter2 as well, and it takes priority + ASSERT(FALSE); + m_pCAP->SetPixelShader(nullptr, nullptr); + if (bSetPreResize) { + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { + if (FAILED(m_pCAP->SetPixelShader(shader.GetCode(), nullptr))) { + preFailed = true; + m_pCAP->SetPixelShader(nullptr, nullptr); + break; + } + } + } + postFailed = !s.m_Shaders.GetCurrentPreset().GetPostResize().empty(); + } + + CString errMsg; + if (preFailed && postFailed) { + VERIFY(errMsg.LoadString(IDS_MAINFRM_BOTH_SHADERS_FAILED)); + } else if (preFailed) { + VERIFY(errMsg.LoadString(IDS_MAINFRM_PRE_SHADERS_FAILED)); + } else if (postFailed) { + VERIFY(errMsg.LoadString(IDS_MAINFRM_POST_SHADERS_FAILED)); + } else { + return; + } + SendStatusMessage(errMsg, 3000); +} + +void CMainFrame::SetBalance(int balance) +{ + int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channel + int balance_dB; + if (balance > -100 && balance < 100) { + balance_dB = sign * (int)(100 * 20 * log10(1 - abs(balance) / 100.0f)); + } else { + balance_dB = sign * (-10000); // -10000: only left, 10000: only right + } + + if (GetLoadState() == MLS::LOADED) { + CString strBalance, strBalanceOSD; + + m_pBA->put_Balance(balance_dB); + + if (balance == 0) { + strBalance.LoadString(IDS_BALANCE); + } else if (balance < 0) { + strBalance.Format(IDS_BALANCE_L, -balance); + } else { //if (m_nBalance > 0) + strBalance.Format(IDS_BALANCE_R, balance); + } + + strBalanceOSD.Format(IDS_BALANCE_OSD, strBalance.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, strBalanceOSD); + } +} + +// +// Open/Close +// + +bool PathIsOnOpticalDisc(CString path) +{ + if (path.GetLength() >= 3 && path[1] == L':' && path[2] == L'\\') { + CString drive = path.Left(3); + UINT type = GetDriveType(drive); + return type == DRIVE_CDROM && !IsDriveVirtual(drive); + } + return false; +} + +// Called from GraphThread +void CMainFrame::OpenCreateGraphObject(OpenMediaData* pOMD) +{ + ASSERT(m_pGB == nullptr); + + m_fCustomGraph = false; + m_fShockwaveGraph = false; + + const CAppSettings& s = AfxGetAppSettings(); + + m_pGB_preview = nullptr; + m_bUseSeekPreview = s.fUseSeekbarHover && s.fSeekPreview && m_wndPreView && ::IsWindow(m_wndPreView.m_hWnd) && !(s.nCLSwitches & CLSW_THUMBNAILS); + if (m_bUseSeekPreview) { +#if 1 + if (auto pOpenDVDData = dynamic_cast(pOMD)) { + // preview does not always work good with DVD even when loaded from hdd + m_bUseSeekPreview = false; + } else +#endif + if (OpenFileData* pFileData = dynamic_cast(pOMD)) { + CString fn = pFileData->fns.GetHead(); + if (fn.IsEmpty()) { + m_bUseSeekPreview = false; + } else { + CString ext = CPath(fn).GetExtension().MakeLower(); + if (((fn.Find(L"://") >= 0) || IsAudioFileExt(ext) || ext == L".avs" || PathIsOnOpticalDisc(fn))) { + // disable seek preview for: streaming data, audio files, files on optical disc + m_bUseSeekPreview = false; + } + } + } + } + + if (auto pOpenFileData = dynamic_cast(pOMD)) { + engine_t engine = s.m_Formats.GetEngine(pOpenFileData->fns.GetHead()); + + HRESULT hr = E_FAIL; + CComPtr pUnk; + + if (engine == ShockWave) { + pUnk = (IUnknown*)(INonDelegatingUnknown*)DEBUG_NEW DSObjects::CShockwaveGraph(m_pVideoWnd->m_hWnd, hr); + if (!pUnk) { + throw (UINT)IDS_AG_OUT_OF_MEMORY; + } + + if (SUCCEEDED(hr)) { + m_pGB = CComQIPtr(pUnk); + } + if (FAILED(hr) || !m_pGB) { + throw (UINT)IDS_MAINFRM_77; + } + m_fShockwaveGraph = true; + } + + m_fCustomGraph = m_fShockwaveGraph; + + if (!m_fCustomGraph) { + CFGManagerPlayer* fgm = DEBUG_NEW CFGManagerPlayer(_T("CFGManagerPlayer"), nullptr, m_pVideoWnd->m_hWnd); + if (!pOpenFileData->useragent.IsEmpty()) { + fgm->SetUserAgent(pOpenFileData->useragent); + } + if (!pOpenFileData->referrer.IsEmpty()) { + fgm->SetReferrer(pOpenFileData->referrer); + } + m_pGB = fgm; + + if (m_pGB && m_bUseSeekPreview) { + // build graph for preview + m_pGB_preview = DEBUG_NEW CFGManagerPlayer(L"CFGManagerPlayer", nullptr, m_wndPreView.GetVideoHWND(), true); + } + } + } else if (auto pOpenDVDData = dynamic_cast(pOMD)) { + m_pGB = DEBUG_NEW CFGManagerDVD(_T("CFGManagerDVD"), nullptr, m_pVideoWnd->m_hWnd); + + if (m_bUseSeekPreview) { + if (!PathIsOnOpticalDisc(pOpenDVDData->path)) { + m_pGB_preview = DEBUG_NEW CFGManagerDVD(L"CFGManagerDVD", nullptr, m_wndPreView.GetVideoHWND(), true); + } + } + } else if (auto pOpenDeviceData = dynamic_cast(pOMD)) { + if (s.iDefaultCaptureDevice == 1) { + m_pGB = DEBUG_NEW CFGManagerBDA(_T("CFGManagerBDA"), nullptr, m_pVideoWnd->m_hWnd); + } else { + m_pGB = DEBUG_NEW CFGManagerCapture(_T("CFGManagerCapture"), nullptr, m_pVideoWnd->m_hWnd); + } + } + + if (!m_pGB) { + throw (UINT)IDS_MAINFRM_80; + } + + if (!m_pGB_preview) { + m_bUseSeekPreview = false; + } + + m_pGB->AddToROT(); + + m_pMC = m_pGB; + m_pME = m_pGB; + m_pMS = m_pGB; // general + m_pVW = m_pGB; + m_pBV = m_pGB; // video + m_pBA = m_pGB; // audio + m_pFS = m_pGB; + + if (m_bUseSeekPreview) { + m_pGB_preview->AddToROT(); + + m_pMC_preview = m_pGB_preview; + //m_pME_preview = m_pGB_preview; + m_pMS_preview = m_pGB_preview; // general + m_pVW_preview = m_pGB_preview; + m_pBV_preview = m_pGB_preview; + //m_pFS_preview = m_pGB_preview; + } + + if (!(m_pMC && m_pME && m_pMS) + || !(m_pVW && m_pBV) + || !(m_pBA)) { + throw (UINT)IDS_GRAPH_INTERFACES_ERROR; + } + + if (FAILED(m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0))) { + throw (UINT)IDS_GRAPH_TARGET_WND_ERROR; + } + + m_pProv = (IUnknown*)DEBUG_NEW CKeyProvider(); + + if (CComQIPtr pObjectWithSite = m_pGB) { + pObjectWithSite->SetSite(m_pProv); + } + + m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); +} + +CWnd* CMainFrame::GetModalParent() +{ + const CAppSettings& s = AfxGetAppSettings(); + CWnd* pParentWnd = this; + if (HasDedicatedFSVideoWindow() && s.m_RenderersSettings.m_AdvRendSets.bVMR9FullscreenGUISupport) { + pParentWnd = m_pDedicatedFSVideoWnd; + } + return pParentWnd; +} + +void CMainFrame::ShowMediaTypesDialog() { + if (!m_fOpeningAborted) { + CAutoLock lck(&lockModalDialog); + CComQIPtr pGBDE = m_pGB; + if (pGBDE && pGBDE->GetCount()) { + mediaTypesErrorDlg = DEBUG_NEW CMediaTypesDlg(pGBDE, GetModalParent()); + mediaTypesErrorDlg->DoModal(); + delete mediaTypesErrorDlg; + mediaTypesErrorDlg = nullptr; + } + } +} + +void CMainFrame::ReleasePreviewGraph() +{ + if (m_pGB_preview) { + m_pCAP2_preview.Release(); + m_pMFVP_preview.Release(); + m_pMFVDC_preview.Release(); + m_pVMR9C_preview.Release(); + + //m_pFS_preview.Release(); + m_pMS_preview.Release(); + m_pBV_preview.Release(); + m_pVW_preview.Release(); + //m_pME_preview.Release(); + m_pMC_preview.Release(); + + if (m_pDVDC_preview) { + m_pDVDC_preview.Release(); + m_pDVDI_preview.Release(); + } + + m_pGB_preview->RemoveFromROT(); + m_pGB_preview.Release(); + } +} + +HRESULT CMainFrame::PreviewWindowHide() { + HRESULT hr = S_OK; + + if (!m_bUseSeekPreview) { + return E_FAIL; + } + + if (m_wndPreView.IsWindowVisible()) { + // Disable animation + ANIMATIONINFO AnimationInfo; + AnimationInfo.cbSize = sizeof(ANIMATIONINFO); + ::SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + int WindowAnimationType = AnimationInfo.iMinAnimate; + AnimationInfo.iMinAnimate = 0; + ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + + m_wndPreView.ShowWindow(SW_HIDE); + + // Enable animation + AnimationInfo.iMinAnimate = WindowAnimationType; + ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + + if (m_pGB_preview && m_pMC_preview) { + m_pMC_preview->Pause(); + } + } + + return hr; +} + +HRESULT CMainFrame::PreviewWindowShow(REFERENCE_TIME rtCur2) { + if (!CanPreviewUse()) { + return E_FAIL; + } + + HRESULT hr = S_OK; + if (GetPlaybackMode() == PM_DVD && m_pDVDC_preview) { + DVD_PLAYBACK_LOCATION2 Loc, Loc2; + double fps = 0; + + hr = m_pDVDI->GetCurrentLocation(&Loc); + if (FAILED(hr)) { + return hr; + } + + hr = m_pDVDI_preview->GetCurrentLocation(&Loc2); + + fps = Loc.TimeCodeFlags == DVD_TC_FLAG_25fps ? 25.0 + : Loc.TimeCodeFlags == DVD_TC_FLAG_30fps ? 30.0 + : Loc.TimeCodeFlags == DVD_TC_FLAG_DropFrame ? 29.97 + : 25.0; + + DVD_HMSF_TIMECODE dvdTo = RT2HMSF(rtCur2, fps); + + if (FAILED(hr) || (Loc.TitleNum != Loc2.TitleNum)) { + hr = m_pDVDC_preview->PlayTitle(Loc.TitleNum, DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + return hr; + } + m_pDVDC_preview->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (SUCCEEDED(hr)) { + hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + return hr; + } + } else { + hr = m_pDVDC_preview->PlayChapterInTitle(Loc.TitleNum, 1, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + hr = m_pDVDC_preview->PlayAtTimeInTitle(Loc.TitleNum, &dvdTo, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + return hr; + } + } + } + } else { + hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + return hr; + } + } + + m_pDVDI_preview->GetCurrentLocation(&Loc2); + + m_pMC_preview->Run(); + Sleep(10); + m_pMC_preview->Pause(); + } else if (GetPlaybackMode() == PM_FILE && m_pMS_preview) { + hr = m_pMS_preview->SetPositions(&rtCur2, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } else { + return E_FAIL; + } + + if (FAILED(hr)) { + return hr; + } + + /* + if (GetPlaybackMode() == PM_FILE) { + hr = pFS2 ? pFS2->Step(2, nullptr) : E_FAIL; + if (SUCCEEDED(hr)) { + Sleep(10); + } + } + */ + + if (!m_wndPreView.IsWindowVisible()) { + m_wndPreView.SetRelativeSize(AfxGetAppSettings().iSeekPreviewSize); + m_wndPreView.ShowWindow(SW_SHOWNOACTIVATE); + m_wndPreView.SetWindowSize(); + } + + return hr; +} + +HRESULT CMainFrame::HandleMultipleEntryRar(CStringW fn) { + CRFSList file_list(true); //true = clears itself on destruction + int num_files, num_ok_files; + + CRARFileSource::ScanArchive(fn.GetBuffer(), &file_list, &num_files, &num_ok_files); + if (num_ok_files > 1) { + RarEntrySelectorDialog entrySelector(&file_list, GetModalParent()); + if (IDOK == entrySelector.DoModal()) { + CStringW entryName = entrySelector.GetCurrentEntry(); + if (entryName.GetLength() > 0) { + CComPtr fgm = static_cast(m_pGB.p); + return fgm->RenderRFSFileEntry(fn, nullptr, entryName); + } + } + return RFS_E_ABORT; //we found multiple entries but no entry selected. + } + return E_NOTIMPL; //not a multi-entry rar +} + +// Called from GraphThread +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; + } + if (bMainFile) { + // store info, this is used for skipping to next/previous file + pOFD->title = fn; + lastOpenFile = fn; + } + + CString ext = GetFileExt(fn); + if (ext == ".mpls") { + CString fnn = PathUtils::StripPathOrUrl(fn); + CString tempath(fn); + tempath.Replace(fnn, _T("")); + tempath.Replace(_T("BDMV\\PLAYLIST\\"), _T("")); + CHdmvClipInfo clipinfo; + m_bHasBDMeta = clipinfo.ReadMeta(tempath, m_BDMeta); + } + + HRESULT hr; + HRESULT rarHR = E_NOTIMPL; +#if INTERNAL_SOURCEFILTER_RFS + if (s.SrcFilters[SRC_RFS] && !PathUtils::IsURL(fn)) { + CString ext = CPath(fn).GetExtension().MakeLower(); + if (ext == L".rar") { + rarHR = HandleMultipleEntryRar(fn); + } + } +#endif + + if (E_NOTIMPL == rarHR) { + hr = m_pGB->RenderFile(fn, nullptr); + } else { + hr = rarHR; + } + + if (FAILED(hr)) { + if (bMainFile) { + if (m_pME) { + m_pME->SetNotifyWindow(NULL, 0, 0); + } + + if (s.fReportFailedPins) { + ShowMediaTypesDialog(); + } + + 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; + } + } + + if (bMainFile) { + bool bIsVideo = false; + bool isRFS = false; + CStringW entryRFS; + + // Check for supported interfaces + BeginEnumFilters(m_pGB, pEF, pBF); + bool fsf = false; + CLSID clsid = GetCLSID(pBF); + // IFileSourceFilter + if (!m_pFSF) { + m_pFSF = pBF; + if (m_pFSF) { + fsf = true; + if (!m_pAMNS) { + m_pAMNS = pBF; + } + if (!m_pSplitterSS) { + m_pSplitterSS = pBF; + } + if (m_bUseSeekPreview) { + if (clsid == CLSID_StillVideo || clsid == CLSID_MPCImageSource) { + m_bUseSeekPreview = false; + } else if (clsid == __uuidof(CRARFileSource)) { + WCHAR* pFN = nullptr; + AM_MEDIA_TYPE mt; + if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { + isRFS = true; + entryRFS = pFN; + CoTaskMemFree(pFN); + } + } + } + } + } + // IAMStreamSelect / IDirectVobSub + if (!fsf) { + if (clsid == __uuidof(CAudioSwitcherFilter)) { + m_pAudioSwitcherSS = pBF; + } else { + if (clsid == GUID_LAVSplitter) { + m_pSplitterSS = pBF; + } else { + if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { + m_pDVS = pBF; + m_pDVS2 = pBF; + } else { + if (clsid != CLSID_MPCBEAudioRenderer) { + if (CComQIPtr pTest = pBF) { + if (!m_pOtherSS[0]) { + m_pOtherSS[0] = pBF; + } else if (!m_pOtherSS[1]) { + m_pOtherSS[1] = pBF; + } else { + ASSERT(false); + } + } + } + } + } + } + } + // Others + if (!m_pLN21) { + m_pLN21 = pBF; + } + if (!m_pKFI) { + m_pKFI = pBF; + } + if (!m_pAMOP) { + m_pAMOP = pBF; + } + if (!m_pAMMC[0]) { + m_pAMMC[0] = pBF; + } else if (!m_pAMMC[1]) { + m_pAMMC[1] = pBF; + } + if (m_bUseSeekPreview && !bIsVideo && IsVideoRenderer(pBF)) { + bIsVideo = true; + } + EndEnumFilters; + + ASSERT(m_pFSF); + + if (!bIsVideo) { + m_bUseSeekPreview = false; + } + if (m_bUseSeekPreview && IsImageFile(fn)) { + // don't use preview for images + m_bUseSeekPreview = false; + } + + if (m_bUseSeekPreview) { + HRESULT previewHR; + if (isRFS) { + CComPtr fgm = static_cast(m_pGB_preview.p); + previewHR = fgm->RenderRFSFileEntry(fn, nullptr, entryRFS); + } else { + previewHR = m_pGB_preview->RenderFile(fn, nullptr); + } + + if (FAILED(previewHR)) { + m_bUseSeekPreview = false; + ReleasePreviewGraph(); + } + } + } else { // Audio DUB + // Check for supported interfaces + BeginEnumFilters(m_pGB, pEF, pBF); + CLSID clsid = GetCLSID(pBF); + if (clsid == GUID_LAVSplitter || clsid == GUID_LAVSplitterSource) { + m_pSplitterDubSS = pBF; + if (m_pSplitterSS && m_pSplitterSS == m_pSplitterDubSS) { + m_pSplitterDubSS.Release(); + } + } else if (clsid == __uuidof(CAudioSwitcherFilter)) { + if (!m_pAudioSwitcherSS) { + m_pAudioSwitcherSS = pBF; + } + } + EndEnumFilters; + } + + // We don't keep track of piped inputs since that hardly makes any sense + if (s.fKeepHistory && fn.Find(_T("pipe:")) != 0 && pOFD->bAddToRecent) { + if (bMainFile) { + auto* pMRU = &s.MRU; + RecentFileEntry r; + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + if (pli.m_bYoutubeDL && !pli.m_ydlSourceURL.IsEmpty()) { + pMRU->LoadMediaHistoryEntryFN(pli.m_ydlSourceURL, r); + } else { + pMRU->LoadMediaHistoryEntryFN(fn, r); + if (pli.m_fns.GetCount() > r.fns.GetCount()) { + r.fns.RemoveAll(); + r.fns.AddHeadList(&pli.m_fns); + } + SHAddToRecentDocs(SHARD_PATH, fn); + } + if (pli.m_cue) { + r.cue = pli.m_cue_filename; + } + if (pli.m_subs.GetCount() > r.subs.GetCount()) { + r.subs.RemoveAll(); + r.subs.AddHeadList(&pli.m_subs); + } + + if (pli.m_label.IsEmpty()) { + CString title; + for (const auto& pAMMC : m_pAMMC) { + if (pAMMC) { + CComBSTR bstr; + if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { + title = bstr.m_str; + title.Trim(); + break; + } + } + } + if (title.GetLength() >= 10 && !IsNameSimilar(title, PathUtils::StripPathOrUrl(fn))) { + r.title = title; + } + } else { + if (pli.m_bYoutubeDL || !IsNameSimilar(pli.m_label, PathUtils::StripPathOrUrl(fn))) { + if (!pli.m_bYoutubeDL || fn == pli.m_ydlSourceURL) { + r.title = pli.m_label; + } else { + CString videoName(pli.m_label); + int m = LastIndexOfCString(videoName, _T(" (")); + if (m > 0) { + videoName = pli.m_label.Left(m); + } + r.title = videoName; + } + } + } + } else { + ASSERT(false); + r.fns.AddHead(fn); + } + + pMRU->Add(r, true); + CStringW playListName; + if (s.bRememberExternalPlaylistPos && m_wndPlaylistBar.IsExternalPlayListActive(playListName)) { + s.SavePlayListPosition(playListName, m_wndPlaylistBar.GetSelIdx()); + } + } + else { + CPlaylistItem pli; + if (!m_wndPlaylistBar.GetCur(pli) || !pli.m_bYoutubeDL) { + CRecentFileList* pMRUDub = &s.MRUDub; + pMRUDub->ReadList(); + pMRUDub->Add(fn); + pMRUDub->WriteList(); + } + } + } + + bMainFile = false; + + if (m_fCustomGraph) { + break; + } + } + + if (s.fReportFailedPins) { + ShowMediaTypesDialog(); + } + + SetupChapters(); + + SetPlaybackMode(PM_FILE); +} + +void CMainFrame::SetupExternalChapters() +{ + // .XCHP (eXternal CHaPters) file format: + // - UTF-8 text file. + // - Located in same folder as the audio/video file, and has same base filename. + // - It will override chapter metadata that is embedded in the file. + // - Each line defines a chapter: timecode, optionally followed by a space and chapter title. + // - Timecode must be in this format: HH:MM:SS,ddd + + CString fn = m_wndPlaylistBar.GetCurFileName(true); + if (fn.IsEmpty() || PathUtils::IsURL(fn)) { + return; + } + + CPath cp(fn); + cp.RenameExtension(_T(".xchp")); + if (!cp.FileExists()) { + return; + } + fn = cp.m_strPath; + + CTextFile f(CTextFile::UTF8); + f.SetFallbackEncoding(CTextFile::ANSI); + + CString str; + if (!f.Open(fn) || !f.ReadString(str)) { + return; + } + + f.Seek(0, CFile::SeekPosition::begin); + + while (f.ReadString(str)) { + REFERENCE_TIME rt = 0; + CString name = ""; + + if (str.GetLength() > 11) { + int lHour = 0; + int lMinute = 0; + int lSecond = 0; + int lMillisec = 0; + if (_stscanf_s(str.Left(12), _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { + rt = ((((lHour * 60) + lMinute) * 60 + lSecond) * MILLISECONDS + lMillisec) * (UNITS / MILLISECONDS); + if (str.GetLength() > 12) { + name = str.Mid(12); + name.Trim(); + } + m_pCB->ChapAppend(rt, name); + } else { + break; + } + } else { + break; + } + } + m_pCB->ChapSort(); +} + +void CMainFrame::SetupChapters() +{ + // Release the old chapter bag and create a new one. + // Due to smart pointers the old chapter bag won't + // be deleted until all classes release it. + m_pCB.Release(); + m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); + + SetupExternalChapters(); + if (m_pCB->ChapGetCount() > 0) { + UpdateSeekbarChapterBag(); + return; + } + + // ToDo: add global pointer list for IDSMChapterBag + CInterfaceList pBFs; + BeginEnumFilters(m_pGB, pEF, pBF); + pBFs.AddTail(pBF); + EndEnumFilters; + + POSITION pos; + + pos = pBFs.GetHeadPosition(); + while (pos && !m_pCB->ChapGetCount()) { + IBaseFilter* pBF = pBFs.GetNext(pos); + + CComQIPtr pCB = pBF; + if (!pCB) { + continue; + } + + for (DWORD i = 0, cnt = pCB->ChapGetCount(); i < cnt; i++) { + REFERENCE_TIME rt; + CComBSTR name; + if (SUCCEEDED(pCB->ChapGet(i, &rt, &name))) { + m_pCB->ChapAppend(rt, name); + } + } + } + + pos = pBFs.GetHeadPosition(); + while (pos && !m_pCB->ChapGetCount()) { + IBaseFilter* pBF = pBFs.GetNext(pos); + + CComQIPtr pCI = pBF; + if (!pCI) { + continue; + } + + CHAR iso6391[3]; + ::GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, iso6391, 3); + CStringA iso6392 = ISOLang::ISO6391To6392(iso6391); + if (iso6392.GetLength() < 3) { + iso6392 = "eng"; + } + + UINT cnt = pCI->GetChapterCount(CHAPTER_ROOT_ID); + for (UINT i = 1; i <= cnt; i++) { + UINT cid = pCI->GetChapterId(CHAPTER_ROOT_ID, i); + + ChapterElement ce; + if (pCI->GetChapterInfo(cid, &ce)) { + char pl[3] = {iso6392[0], iso6392[1], iso6392[2]}; + char cc[] = " "; + CComBSTR name; + name.Attach(pCI->GetChapterStringInfo(cid, pl, cc)); + m_pCB->ChapAppend(ce.rtStart, name); + } + } + } + + pos = pBFs.GetHeadPosition(); + while (pos && !m_pCB->ChapGetCount()) { + IBaseFilter* pBF = pBFs.GetNext(pos); + + CComQIPtr pES = pBF; + if (!pES) { + continue; + } + + long MarkerCount = 0; + if (SUCCEEDED(pES->get_MarkerCount(&MarkerCount))) { + for (long i = 1; i <= MarkerCount; i++) { + double MarkerTime = 0; + if (SUCCEEDED(pES->GetMarkerTime(i, &MarkerTime))) { + CStringW name; + name.Format(IDS_AG_CHAPTER, i); + + CComBSTR bstr; + if (S_OK == pES->GetMarkerName(i, &bstr)) { + name = bstr; + } + + m_pCB->ChapAppend(REFERENCE_TIME(MarkerTime * 10000000), name); + } + } + } + } + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_cue) { + SetupCueChapters(pli.m_cue_filename); + } + + UpdateSeekbarChapterBag(); +} + +void CMainFrame::SetupCueChapters(CString fn) { + CString str; + int cue_index(-1); + + CPlaylistItem pli; + if (!m_wndPlaylistBar.GetCur(pli, true)) { + ASSERT(false); + return; + } + + CWebTextFile f(CTextFile::UTF8); + f.SetFallbackEncoding(CTextFile::ANSI); + if (!f.Open(fn) || !f.ReadString(str)) { + return; + } + f.Seek(0, CFile::SeekPosition::begin); + + CString base; + bool isurl = PathUtils::IsURL(fn); + if (isurl) { + int p = fn.Find(_T('?')); + if (p > 0) { + fn = fn.Left(p); + } + p = fn.ReverseFind(_T('/')); + if (p > 0) { + base = fn.Left(p + 1); + } + } + else { + CPath basefilepath(fn); + basefilepath.RemoveFileSpec(); + basefilepath.AddBackslash(); + base = basefilepath.m_strPath; + } + + CString title; + CString performer; + CAtlList trackl; + CueTrackMeta track; + int trackID(0); + + while (f.ReadString(str)) { + str.Trim(); + if (cue_index == -1 && str.Left(5) == _T("TITLE")) { + title = str.Mid(6).Trim(_T("\"")); + } + else if (cue_index == -1 && str.Left(9) == _T("PERFORMER")) { + performer = str.Mid(10).Trim(_T("\"")); + } + else if (str.Left(4) == _T("FILE")) { + if (str.Right(4) == _T("WAVE") || str.Right(3) == _T("MP3") || str.Right(4) == _T("AIFF")) { // We just support audio file. + cue_index++; + } + } + else if (cue_index >= 0) { + if (str.Left(5) == _T("TRACK") && str.Right(5) == _T("AUDIO")) { + CT2CA tmp(str.Mid(6, str.GetLength() - 12)); + const char* tmp2(tmp); + sscanf_s(tmp2, "%d", &trackID); + if (track.trackID != 0) { + trackl.AddTail(track); + track = CueTrackMeta(); + } + track.trackID = trackID; + } + else if (str.Left(5) == _T("TITLE")) { + track.title = str.Mid(6).Trim(_T("\"")); + } + else if (str.Left(9) == _T("PERFORMER")) { + track.performer = str.Mid(10).Trim(_T("\"")); + } + else if (str.Left(5) == _T("INDEX")) { + CT2CA tmp(str.Mid(6)); + const char* tmp2(tmp); + int i1(0), m(0), s(0), ms(0); + sscanf_s(tmp2, "%d %d:%d:%d", &i1, &m, &s, &ms); + if (i1 != 0) track.time = 10000i64 * ((m * 60 + s) * 1000 + ms); + } + } + } + + if (track.trackID != 0) { + trackl.AddTail(track); + } + + if ((cue_index == 0 && trackl.GetCount() == 1) || cue_index > 1) pli.m_cue = false; // avoid unnecessary parsing of cue again later + + if (trackl.GetCount() >= 1) { + POSITION p = trackl.GetHeadPosition(); + bool b(true); + do { + if (p == trackl.GetTailPosition()) b = false; + CueTrackMeta c(trackl.GetNext(p)); + if (cue_index == 0 || (cue_index > 0 && c.trackID == (pli.m_cue_index + 1))) { + CString label; + if (c.trackID != 0 && !c.title.IsEmpty()) { + label = c.title; + if (!c.performer.IsEmpty()) { + label += (_T(" - ") + c.performer); + } + else if (!performer.IsEmpty()) { + label += (_T(" - ") + performer); + } + } + REFERENCE_TIME time(c.time); + if (cue_index > 0) time = 0; // We don't support gap. + m_pCB->ChapAppend(time, label); + } + } while (b); + } +} + +void CMainFrame::SetupDVDChapters() +{ + // Release the old chapter bag and create a new one. + // Due to smart pointers the old chapter bag won't + // be deleted until all classes release it. + m_pCB.Release(); + m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); + + WCHAR buff[MAX_PATH]; + ULONG len, ulNumOfChapters; + DVD_PLAYBACK_LOCATION2 loc; + + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDVDDirectory(buff, _countof(buff), &len)) + && SUCCEEDED(m_pDVDI->GetCurrentLocation(&loc)) + && SUCCEEDED(m_pDVDI->GetNumberOfChapters(loc.TitleNum, &ulNumOfChapters))) { + CString path; + path.Format(L"%s\\video_ts.IFO", buff); + ULONG VTSN, TTN; + + if (CVobFile::GetTitleInfo(path, loc.TitleNum, VTSN, TTN)) { + path.Format(L"%s\\VTS_%02lu_0.IFO", buff, VTSN); + CAtlList files; + + CVobFile vob; + if (vob.Open(path, files, TTN, false)) { + int iChaptersCount = vob.GetChaptersCount(); + if (ulNumOfChapters == (ULONG)iChaptersCount) { + for (int i = 0; i < iChaptersCount; i++) { + REFERENCE_TIME rt = vob.GetChapterOffset(i); + + CStringW str; + str.Format(IDS_AG_CHAPTER, i + 1); + + m_pCB->ChapAppend(rt, str); + } + } else { + // Parser failed! + ASSERT(FALSE); + } + vob.Close(); + } + } + } + + m_pCB->ChapSort(); + + UpdateSeekbarChapterBag(); +} + +// Called from GraphThread +void CMainFrame::OpenDVD(OpenDVDData* pODD) +{ + lastOpenFile.Empty(); + + HRESULT hr = m_pGB->RenderFile(CStringW(pODD->path), nullptr); + + CAppSettings& s = AfxGetAppSettings(); + + if (s.fReportFailedPins) { + ShowMediaTypesDialog(); + } + + if (SUCCEEDED(hr) && m_bUseSeekPreview) { + if (FAILED(hr = m_pGB_preview->RenderFile(pODD->path, nullptr))) { + m_bUseSeekPreview = false; + } + } + + // Check for supported interfaces + BeginEnumFilters(m_pGB, pEF, pBF) + CLSID clsid = GetCLSID(pBF); + // DVD stuff + if (!m_pDVDC) { + m_pDVDC = pBF; + } + if (!m_pDVDI) { + m_pDVDI = pBF; + } + // IAMStreamSelect filters / IDirectVobSub + if (clsid == __uuidof(CAudioSwitcherFilter)) { + m_pAudioSwitcherSS = pBF; + } else { + if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { + m_pDVS = pBF; + m_pDVS2 = pBF; + } else { + if (clsid != CLSID_MPCBEAudioRenderer) { + if (CComQIPtr pTest = pBF) { + if (!m_pOtherSS[0]) { + m_pOtherSS[0] = pBF; + } else if (!m_pOtherSS[1]) { + m_pOtherSS[1] = pBF; + } else { + ASSERT(false); + } + } + } + } + } + // Others + if (!m_pLN21) { + m_pLN21 = pBF; + } + EndEnumFilters; + + ASSERT(m_pDVDC); + ASSERT(m_pDVDI); + + if (m_bUseSeekPreview) { + BeginEnumFilters(m_pGB_preview, pEF, pBF) { + if ((m_pDVDC_preview = pBF) && (m_pDVDI_preview = pBF)) { + break; + } + } + EndEnumFilters; + } + + if (hr == E_INVALIDARG) { + throw (UINT)IDS_MAINFRM_93; + } else if (hr == VFW_E_CANNOT_RENDER) { + throw (UINT)IDS_DVD_NAV_ALL_PINS_ERROR; + } else if (hr == VFW_S_PARTIAL_RENDER) { + throw (UINT)IDS_DVD_NAV_SOME_PINS_ERROR; + } else if (hr == E_NOINTERFACE || !m_pDVDC || !m_pDVDI) { + throw (UINT)IDS_DVD_INTERFACES_ERROR; + } else if (hr == VFW_E_CANNOT_LOAD_SOURCE_FILTER) { + throw (UINT)IDS_MAINFRM_94; + } else if (FAILED(hr)) { + throw (UINT)IDS_AG_FAILED; + } + + WCHAR buff[MAX_PATH]; + ULONG len = 0; + if (SUCCEEDED(hr = m_pDVDI->GetDVDDirectory(buff, _countof(buff), &len))) { + pODD->title = CString(CStringW(buff)).TrimRight(_T("\\")); + } + + if (s.fKeepHistory) { + ULONGLONG llDVDGuid; + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDiscID(nullptr, &llDVDGuid))) { + auto* pMRU = &s.MRU; + pMRU->Add(pODD->title, llDVDGuid); + } + SHAddToRecentDocs(SHARD_PATH, pODD->title); + } + + // TODO: resetdvd + m_pDVDC->SetOption(DVD_ResetOnStop, FALSE); + m_pDVDC->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); + + if (m_bUseSeekPreview && m_pDVDC_preview) { + m_pDVDC_preview->SetOption(DVD_ResetOnStop, FALSE); + m_pDVDC_preview->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); + } + + if (s.idMenuLang) { + m_pDVDC->SelectDefaultMenuLanguage(s.idMenuLang); + } + if (s.idAudioLang) { + m_pDVDC->SelectDefaultAudioLanguage(s.idAudioLang, DVD_AUD_EXT_NotSpecified); + } + if (s.idSubtitlesLang) { + m_pDVDC->SelectDefaultSubpictureLanguage(s.idSubtitlesLang, DVD_SP_EXT_NotSpecified); + } + + m_iDVDDomain = DVD_DOMAIN_Stop; + + SetPlaybackMode(PM_DVD); +} + +// Called from GraphThread +HRESULT CMainFrame::OpenBDAGraph() +{ + lastOpenFile.Empty(); + + HRESULT hr = m_pGB->RenderFile(L"", L""); + if (SUCCEEDED(hr)) { + SetPlaybackMode(PM_DIGITAL_CAPTURE); + m_pDVBState = std::make_unique(); + + // Check for supported interfaces + BeginEnumFilters(m_pGB, pEF, pBF); + bool fsf = false; + CLSID clsid = GetCLSID(pBF); + // IFileSourceFilter + if (!m_pFSF) { + m_pFSF = pBF; + if (m_pFSF) { + fsf = true; + if (!m_pAMNS) { + m_pAMNS = pBF; + } + } + } + // IAMStreamSelect / IDirectVobSub + if (!fsf) { + if (clsid == __uuidof(CAudioSwitcherFilter)) { + m_pAudioSwitcherSS = pBF; + } else { + if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { + m_pDVS = pBF; + m_pDVS2 = pBF; + } + } + } + // Others + if (!m_pLN21) { + m_pLN21 = pBF; + } + if (!m_pAMMC[0]) { + m_pAMMC[0] = pBF; + } else if (!m_pAMMC[1]) { + m_pAMMC[1] = pBF; + } + EndEnumFilters; + + ASSERT(m_pFSF); + + // BDA graph builder implements IAMStreamSelect + m_pSplitterSS = m_pGB; + } + return hr; +} + +// Called from GraphThread +void CMainFrame::OpenCapture(OpenDeviceData* pODD) +{ + lastOpenFile.Empty(); + + m_wndCaptureBar.InitControls(); + + CStringW vidfrname, audfrname; + CComPtr pVidCapTmp, pAudCapTmp; + + m_VidDispName = pODD->DisplayName[0]; + + if (!m_VidDispName.IsEmpty()) { + if (!CreateFilter(m_VidDispName, &pVidCapTmp, vidfrname)) { + throw (UINT)IDS_MAINFRM_96; + } + } + + m_AudDispName = pODD->DisplayName[1]; + + if (!m_AudDispName.IsEmpty()) { + if (!CreateFilter(m_AudDispName, &pAudCapTmp, audfrname)) { + throw (UINT)IDS_MAINFRM_96; + } + } + + if (!pVidCapTmp && !pAudCapTmp) { + throw (UINT)IDS_MAINFRM_98; + } + + m_pCGB = nullptr; + m_pVidCap = nullptr; + m_pAudCap = nullptr; + + if (FAILED(m_pCGB.CoCreateInstance(CLSID_CaptureGraphBuilder2))) { + throw (UINT)IDS_MAINFRM_99; + } + + HRESULT hr; + + m_pCGB->SetFiltergraph(m_pGB); + + if (pVidCapTmp) { + if (FAILED(hr = m_pGB->AddFilter(pVidCapTmp, vidfrname))) { + throw (UINT)IDS_CAPTURE_ERROR_VID_FILTER; + } + + m_pVidCap = pVidCapTmp; + + if (!pAudCapTmp) { + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap))) + && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); + } + + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Interleaved, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev))) + && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); + } + + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pVidCap, IID_PPV_ARGS(&m_pAMASC))) + && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pVidCap, IID_PPV_ARGS(&m_pAMASC)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap")); + } else { + m_pAudCap = m_pVidCap; + } + } else { + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); + } + + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); + } + } + + if (FAILED(m_pCGB->FindInterface(&LOOK_UPSTREAM_ONLY, nullptr, m_pVidCap, IID_PPV_ARGS(&m_pAMXBar)))) { + TRACE(_T("Warning: No IAMCrossbar interface was found\n")); + } + + if (FAILED(m_pCGB->FindInterface(&LOOK_UPSTREAM_ONLY, nullptr, m_pVidCap, IID_PPV_ARGS(&m_pAMTuner)))) { + TRACE(_T("Warning: No IAMTVTuner interface was found\n")); + } + // TODO: init m_pAMXBar + + if (m_pAMTuner) { // load saved channel + m_pAMTuner->put_CountryCode(AfxGetApp()->GetProfileInt(_T("Capture"), _T("Country"), 1)); + + int vchannel = pODD->vchannel; + if (vchannel < 0) { + vchannel = AfxGetApp()->GetProfileInt(_T("Capture\\") + CString(m_VidDispName), _T("Channel"), -1); + } + if (vchannel >= 0) { + OAFilterState fs = State_Stopped; + m_pMC->GetState(0, &fs); + if (fs == State_Running) { + MediaControlPause(true); + } + m_pAMTuner->put_Channel(vchannel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT); + if (fs == State_Running) { + MediaControlRun(); + } + } + } + } + + if (pAudCapTmp) { + if (FAILED(hr = m_pGB->AddFilter(pAudCapTmp, CStringW(audfrname)))) { + throw (UINT)IDS_CAPTURE_ERROR_AUD_FILTER; + } + + m_pAudCap = pAudCapTmp; + + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pAudCap, IID_PPV_ARGS(&m_pAMASC))) + && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pAudCap, IID_PPV_ARGS(&m_pAMASC)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap")); + } + } + + if (!(m_pVidCap || m_pAudCap)) { + throw (UINT)IDS_MAINFRM_108; + } + + pODD->title.LoadString(IDS_CAPTURE_LIVE); + + SetPlaybackMode(PM_ANALOG_CAPTURE); +} + +// Called from GraphThread +void CMainFrame::OpenCustomizeGraph() +{ + if (GetPlaybackMode() != PM_FILE && GetPlaybackMode() != PM_DVD) { + return; + } + + CleanGraph(); + + if (GetPlaybackMode() == PM_FILE) { + if (m_pCAP && AfxGetAppSettings().IsISRAutoLoadEnabled()) { + AddTextPassThruFilter(); + } + } + + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + if (r.m_AdvRendSets.bSynchronizeVideo && s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { + HRESULT hr = S_OK; + m_pRefClock = DEBUG_NEW CSyncClockFilter(nullptr, &hr); + + if (SUCCEEDED(hr) && SUCCEEDED(m_pGB->AddFilter(m_pRefClock, L"SyncClock Filter"))) { + CComQIPtr refClock = m_pRefClock; + CComQIPtr mediaFilter = m_pGB; + + if (refClock && mediaFilter) { + VERIFY(SUCCEEDED(mediaFilter->SetSyncSource(refClock))); + mediaFilter = nullptr; + refClock = nullptr; + + VERIFY(SUCCEEDED(m_pRefClock->QueryInterface(IID_PPV_ARGS(&m_pSyncClock)))); + CComQIPtr pAdviser = m_pCAP; + if (pAdviser) { + VERIFY(SUCCEEDED(pAdviser->AdviseSyncClock(m_pSyncClock))); + } + } + } + } + + if (GetPlaybackMode() == PM_DVD) { + if (m_pDVS2) { + if (!m_pSubClock) { + m_pSubClock = DEBUG_NEW CSubClock; + } + m_pDVS2->AdviseSubClock(m_pSubClock); + } + } + + CleanGraph(); +} + +// Called from GraphThread +void CMainFrame::OpenSetupVideo() +{ + m_fAudioOnly = true; + + CSize vs; + + if (m_pMFVDC) { // EVR + m_fAudioOnly = false; + m_pMFVDC->GetNativeVideoSize(&vs, nullptr); + } else if (m_pCAP) { + vs = m_pCAP->GetVideoSize(false); + m_fAudioOnly = (vs.cx <= 0 || vs.cy <= 0); + } else { + if (CComQIPtr pBV = m_pGB) { + pBV->GetVideoSize(&vs.cx, &vs.cy); + + if (vs.cx > 0 && vs.cy > 0) { + m_fAudioOnly = false; + } + } + if (m_fAudioOnly && m_pVW) { + long lVisible; + if (SUCCEEDED(m_pVW->get_Visible(&lVisible))) { + m_pVW->get_Width(&vs.cx); + m_pVW->get_Height(&vs.cy); + if (vs.cx > 0 && vs.cy > 0) { + m_fAudioOnly = false; + } + } + } + } + + if (m_fShockwaveGraph) { + m_fAudioOnly = false; + } + + 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_pVideoWnd->m_hWnd); + + for (CWnd* pWnd = m_pVideoWnd->GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) { + // 1. lets WM_SETCURSOR through (not needed as of now) + // 2. allows CMouse::CursorOnWindow() to work with m_pVideoWnd + pWnd->EnableWindow(FALSE); + } + + if (m_bUseSeekPreview) { + m_pVW_preview->put_Owner((OAHWND)m_wndPreView.GetVideoHWND()); + m_pVW_preview->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); + } + + if (m_fAudioOnly) { + if (HasDedicatedFSVideoWindow() && !AfxGetAppSettings().bFullscreenSeparateControls) { //DedicateFSWindow allowed for audio + m_pDedicatedFSVideoWnd->DestroyWindow(); + } + } else { + m_statusbarVideoSize.Format(_T("%dx%d"), vs.cx, vs.cy); + UpdateDXVAStatus(); + } +} + +// Called from GraphThread +void CMainFrame::OpenSetupAudio() +{ + m_pBA->put_Volume(m_wndToolBar.Volume); + + // FIXME + int balance = AfxGetAppSettings().nBalance; + + int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channel + if (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); +} + +void CMainFrame::OpenSetupCaptureBar() +{ + if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + if (m_pVidCap && m_pAMVSCCap) { + CComQIPtr pVfwCD = m_pVidCap; + + if (!m_pAMXBar && pVfwCD) { + m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, m_pAMVSCCap, pVfwCD); + } else { + m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, m_pAMVSCCap, m_pAMXBar, m_pAMTuner); + } + } + + if (m_pAudCap && m_pAMASC) { + CInterfaceArray pAMAIM; + + BeginEnumPins(m_pAudCap, pEP, pPin) { + if (CComQIPtr pAIM = pPin) { + pAMAIM.Add(pAIM); + } + } + EndEnumPins; + + m_wndCaptureBar.m_capdlg.SetupAudioControls(m_AudDispName, m_pAMASC, pAMAIM); + } + + BuildGraphVideoAudio( + m_wndCaptureBar.m_capdlg.m_fVidPreview, false, + m_wndCaptureBar.m_capdlg.m_fAudPreview, false); + } +} + +void CMainFrame::OpenSetupInfoBar(bool bClear /*= true*/) +{ + bool bRecalcLayout = false; + + if (bClear) { + m_wndInfoBar.RemoveAllLines(); + } + + if (GetPlaybackMode() == PM_FILE) { + CComBSTR bstr; + CString title, author, copyright, rating, description; + if (m_pAMMC[0]) { + for (const auto& pAMMC : m_pAMMC) { + if (pAMMC) { + if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { + title = bstr.m_str; + title.Trim(); + } + bstr.Empty(); + if (SUCCEEDED(pAMMC->get_AuthorName(&bstr)) && bstr.Length()) { + author = bstr.m_str; + } + bstr.Empty(); + if (SUCCEEDED(pAMMC->get_Copyright(&bstr)) && bstr.Length()) { + copyright = bstr.m_str; + } + bstr.Empty(); + if (SUCCEEDED(pAMMC->get_Rating(&bstr)) && bstr.Length()) { + rating = bstr.m_str; + } + bstr.Empty(); + if (SUCCEEDED(pAMMC->get_Description(&bstr)) && bstr.Length()) { + description = bstr.m_str; + } + bstr.Empty(); + } + } + } + + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TITLE), title); + UpdateChapterInInfoBar(); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUTHOR), author); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_COPYRIGHT), copyright); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_RATING), rating); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); + } else if (GetPlaybackMode() == PM_DVD) { + CString info(_T('-')); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), info); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_LOCATION), info); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_VIDEO), info); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUDIO), info); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_SUBTITLES), info); + } + + if (bRecalcLayout) { + RecalcLayout(); + } +} + +void CMainFrame::UpdateChapterInInfoBar() +{ + CString chapter; + if (m_pCB) { + DWORD dwChapCount = m_pCB->ChapGetCount(); + if (dwChapCount) { + REFERENCE_TIME rtNow; + m_pMS->GetCurrentPosition(&rtNow); + + if (m_pCB) { + CComBSTR bstr; + long currentChap = m_pCB->ChapLookup(&rtNow, &bstr); + if (bstr.Length()) { + chapter.Format(_T("%s (%ld/%lu)"), bstr.m_str, std::max(0l, currentChap + 1l), dwChapCount); + } else { + chapter.Format(_T("%ld/%lu"), currentChap + 1, dwChapCount); + } + } + } + } + if (m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CHAPTER), chapter)) { + RecalcLayout(); + } +} + +void CMainFrame::OpenSetupStatsBar() +{ + m_wndStatsBar.RemoveAllLines(); + + if (GetLoadState() == MLS::LOADED) { + CString info(_T('-')); + bool bFoundIBitRateInfo = false; + + BeginEnumFilters(m_pGB, pEF, pBF) { + if (!m_pQP) { + m_pQP = pBF; + } + if (!m_pBI) { + m_pBI = pBF; + } + if (!bFoundIBitRateInfo) { + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pBRI = pPin) { + bFoundIBitRateInfo = true; + break; + } + } + EndEnumPins; + } + if (m_pQP && m_pBI && bFoundIBitRateInfo) { + break; + } + } + EndEnumFilters; + + if (m_pQP) { + m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMERATE), info); + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SYNC_OFFSET), info); + m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMES), info); + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_JITTER), info); + } else { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_PLAYBACK_RATE), info); + } + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), info); + } + if (m_pBI) { + m_wndStatsBar.SetLine(StrRes(IDS_AG_BUFFERS), info); + } + if (bFoundIBitRateInfo) { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_BITRATE), info); + } + } +} + +void CMainFrame::CheckSelectedAudioStream() +{ + int nChannels = 0; + int audiostreamcount = 0; + UINT audiobitmapid = IDB_AUDIOTYPE_NOAUDIO; + m_loadedAudioTrackIndex = -1; + + if (m_pAudioSwitcherSS) { + DWORD cStreams = 0; + if (SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { + LCID lcid = 0; + DWORD dwFlags, dwGroup; + AM_MEDIA_TYPE* pmt = nullptr; + for (DWORD i = 0; i < cStreams; i++) { + if (SUCCEEDED(m_pAudioSwitcherSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 1) { + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + m_loadedAudioTrackIndex = audiostreamcount; + nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + audiostreamcount++; + } + DeleteMediaType(pmt); + } + } + } + } + if (audiostreamcount == 0 && m_pSplitterSS) { + DWORD cStreams = 0; + if (SUCCEEDED(m_pSplitterSS->Count(&cStreams)) && cStreams > 0) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + for (DWORD i = 0; i < cStreams; i++) { + if (SUCCEEDED(m_pSplitterSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 1) { + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + m_loadedAudioTrackIndex = audiostreamcount; + nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + audiostreamcount++; + } + DeleteMediaType(pmt); + } + } + } + } + if (audiostreamcount == 0 && m_pSplitterDubSS) { + DWORD cStreams = 0; + if (SUCCEEDED(m_pSplitterDubSS->Count(&cStreams)) && cStreams > 0) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + for (DWORD i = 0; i < cStreams; i++) { + if (SUCCEEDED(m_pSplitterDubSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 1) { + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + m_loadedAudioTrackIndex = audiostreamcount; + nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + audiostreamcount++; + } + DeleteMediaType(pmt); + } + } + } + } + if (audiostreamcount == 0 && !m_pAudioSwitcherSS) { // Fallback + BeginEnumFilters(m_pGB, pEF, pBF) { + CComQIPtr pBA = pBF; // implemented by audio renderers + bool notrenderer = false; + + BeginEnumPins(pBF, pEP, pPin) { + if (S_OK == m_pGB->IsPinDirection(pPin, PINDIR_INPUT) && S_OK == m_pGB->IsPinConnected(pPin)) { + AM_MEDIA_TYPE mt; + if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (mt.majortype == MEDIATYPE_Audio) { + notrenderer = !pBA; + audiostreamcount = 1; + nChannels = UpdateSelectedAudioStreamInfo(-1, &mt, -1); + break; + } else if (mt.majortype == MEDIATYPE_Midi) { + notrenderer = true; + audiostreamcount = 1; + nChannels = UpdateSelectedAudioStreamInfo(-1, &mt, -1); + break; + } + } + } + } + EndEnumPins; + + if (nChannels > 0 && notrenderer) { // prefer audio decoder above renderer + break; + } + } + EndEnumFilters; + } + + if (audiostreamcount == 0) { + m_loadedAudioTrackIndex = -1; + UpdateSelectedAudioStreamInfo(-1, nullptr, -1); + } + + if (nChannels >= 2) { + audiobitmapid = IDB_AUDIOTYPE_STEREO; + } else if (nChannels == 1) { + audiobitmapid = IDB_AUDIOTYPE_MONO; + } + m_wndStatusBar.SetStatusBitmap(audiobitmapid); +} + +void CMainFrame::OpenSetupStatusBar() +{ + m_wndStatusBar.ShowTimer(true); + + if (!m_fCustomGraph) { + CString fcc; + // Find video output pin of the source filter or splitter + BeginEnumFilters(m_pGB, pEF, pBF) { + CLSID clsid = GetCLSID(pBF); + bool splitter = (clsid == GUID_LAVSplitterSource || clsid == GUID_LAVSplitter); + // only process filters that might be splitters + if (splitter || clsid != __uuidof(CAudioSwitcherFilter) && clsid != GUID_LAVVideo && clsid != GUID_LAVAudio) { + int input_pins = 0; + BeginEnumPins(pBF, pEP, pPin) { + PIN_DIRECTION dir; + CMediaTypeEx mt; + if (SUCCEEDED(pPin->QueryDirection(&dir)) && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (dir == PINDIR_OUTPUT) { + if (mt.majortype == MEDIATYPE_Video) { + GetVideoFormatNameFromMediaType(mt.subtype, fcc); + if (splitter) { + break; + } + } + } else { + input_pins++; + splitter = (mt.majortype == MEDIATYPE_Stream); + } + } + } + EndEnumPins; + + if ((input_pins == 0 || splitter) && !fcc.IsEmpty()) { + break; + } + } + } + EndEnumFilters; + + if (!fcc.IsEmpty()) { + m_statusbarVideoFormat = fcc; + } + + CheckSelectedAudioStream(); + } +} + +// Called from GraphThread +void CMainFrame::OpenSetupWindowTitle(bool reset /*= false*/) +{ + CString title(StrRes(IDR_MAINFRAME)); +#ifdef MPCHC_LITE + title += _T(" Lite"); +#endif + + CAppSettings& s = AfxGetAppSettings(); + + int i = s.iTitleBarTextStyle; + + if (!reset && (i == 0 || i == 1)) { + // There is no path in capture mode + if (IsPlaybackCaptureMode()) { + title = GetCaptureTitle(); + } else if (i == 1) { // Show filename or title + if (GetPlaybackMode() == PM_FILE) { + title = getBestTitle(s.fTitleBarTextTitle); + bool has_title = !title.IsEmpty(); + + CStringW fn = GetFileName(); + + if (has_title && !IsNameSimilar(title, fn)) s.MRU.SetCurrentTitle(title); + + if (!has_title) { + title = fn; + } + } else if (GetPlaybackMode() == PM_DVD) { + title = _T("DVD"); + CString path; + ULONG len = 0; + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDVDDirectory(path.GetBufferSetLength(MAX_PATH), MAX_PATH, &len)) && len) { + path.ReleaseBuffer(); + if (path.Find(_T("\\VIDEO_TS")) == 2) { + title.AppendFormat(_T(" - %s"), GetDriveLabel(CPath(path)).GetString()); + } + } + } + } else { // Show full path + if (GetPlaybackMode() == PM_FILE) { + title = m_wndPlaylistBar.GetCurFileNameTitle(); + } else if (GetPlaybackMode() == PM_DVD) { + title = _T("DVD"); + ULONG len = 0; + if (m_pDVDI) { + VERIFY(SUCCEEDED(m_pDVDI->GetDVDDirectory(title.GetBufferSetLength(MAX_PATH), MAX_PATH, &len))); + title.ReleaseBuffer(); + } + } + } + } + + SetWindowText(title); + m_Lcd.SetMediaTitle(title); +} + +// Called from GraphThread +int CMainFrame::SetupAudioStreams() +{ + bool bIsSplitter = false; + int desiredTrackIndex = m_loadedAudioTrackIndex; + m_loadedAudioTrackIndex = -1; + m_audioTrackCount = 0; + + CComQIPtr pSS = m_pAudioSwitcherSS; + if (!pSS) { + bIsSplitter = true; + pSS = m_pSplitterSS; + } + + DWORD cStreams = 0; + if (pSS && SUCCEEDED(pSS->Count(&cStreams))) { + if (cStreams > 1) { + const CAppSettings& s = AfxGetAppSettings(); + + CAtlArray langs; + int tPos = 0; + CString lang = s.strAudiosLanguageOrder.Tokenize(_T(",; "), tPos); + while (tPos != -1) { + lang.MakeLower(); + langs.Add(lang); + // Try to match the full language if possible + lang = ISOLang::ISO639XToLanguage(CStringA(lang)); + if (!lang.IsEmpty()) { + langs.Add(lang.MakeLower()); + } + lang = s.strAudiosLanguageOrder.Tokenize(_T(",; "), tPos); + } + + int selected = -1, id = 0; + int maxrating = -1; + for (DWORD i = 0; i < cStreams; i++) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + WCHAR* pName = nullptr; + CComPtr pObject; + if (FAILED(pSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pName, &pObject, nullptr))) { + continue; + } + CString name(pName); + CoTaskMemFree(pName); + + if (dwGroup != 1) { + ASSERT(bIsSplitter); + continue; + } + + m_audioTrackCount++; + + int rating = 0; + // If the track is controlled by a splitter and isn't selected at splitter level + if (!(dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE))) { + bool bSkipTrack; + + // If the splitter is the internal LAV Splitter and no language preferences + // have been set at splitter level, we can override its choice safely + CComQIPtr pBF = bIsSplitter ? pSS : reinterpret_cast(pObject.p); + if (pBF && CFGFilterLAV::IsInternalInstance(pBF)) { + bSkipTrack = false; + if (CComQIPtr pLAVFSettings = pBF) { + LPWSTR langPrefs = nullptr; + if (SUCCEEDED(pLAVFSettings->GetPreferredLanguages(&langPrefs)) && langPrefs && wcslen(langPrefs)) { + bSkipTrack = true; + } + CoTaskMemFree(langPrefs); + } + } else { + bSkipTrack = !s.bAllowOverridingExternalSplitterChoice; + } + + if (bSkipTrack) { + id++; + continue; + } + } else if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + // Give selected track a slightly higher rating + rating += 1; + // Get details of currently selected track + m_loadedAudioTrackIndex = m_audioTrackCount - 1; + UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + + DeleteMediaType(pmt); + + name.Trim(); + name.MakeLower(); + + for (size_t j = 0; j < langs.GetCount(); j++) { + int num = _tstoi(langs[j]) - 1; + if (num >= 0) { // this is track number + if (id != num) { + continue; // not matched + } + } else { // this is lang string + int len = langs[j].GetLength(); + if (name.Left(len) != langs[j] && name.Find(_T("[") + langs[j]) < 0) { + continue; // not matched + } + } + rating += 16 * int(langs.GetCount() - j); + break; + } + if (name.Find(_T("[default,forced]")) != -1) { // for LAV Splitter + rating += 4 + 2; + } + if (name.Find(_T("[forced]")) != -1) { + rating += 4; + } + if (name.Find(_T("[default]")) != -1) { + rating += 2; + } + + if (rating > maxrating) { + maxrating = rating; + selected = id; + } + + id++; + } + + if (desiredTrackIndex >= 0 && desiredTrackIndex < m_audioTrackCount) { + selected = desiredTrackIndex; + } + return m_audioTrackCount > 1 ? selected + !bIsSplitter : -1; + } else if (cStreams == 1) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pSS->Info(0, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 1 && (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE))) { + m_loadedAudioTrackIndex = 0; + m_audioTrackCount = 1; + UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + DeleteMediaType(pmt); + return -1; // no need to select a specific track + } + } + } + + return -1; +} + +bool MatchSubtrackWithISOLang(CString& tname, const ISOLangT& l) +{ + int p; + + if (!l.iso6392.IsEmpty()) { + p = tname.Find(_T("[") + l.iso6392 + _T("]")); + if (p > 0) { + return true; + } + p = tname.Find(_T(".") + l.iso6392 + _T(".")); + if (p > 0) { + return true; + } + } + + if (!l.iso6391.IsEmpty()) { + p = tname.Find(_T("[") + l.iso6391 + _T("]")); + if (p > 0) { + return true; + } + p = tname.Find(_T(".") + l.iso6391 + _T(".")); + if (p > 0) { + return true; + } + p = tname.Find(_T("[") + l.iso6391 + _T("-]")); // truncated BCP47 + if (p > 0) { + return true; + } + } + + if (!l.name.IsEmpty()) { + if (l.name == _T("off")) { + return tname.Find(_T("no subtitles")) >= 0; + } + + std::list langlist; + int tPos = 0; + CString lang = l.name.Tokenize(_T(";"), tPos); + while (tPos != -1) { + lang.MakeLower().TrimLeft(); + langlist.emplace_back(lang); + lang = l.name.Tokenize(_T(";"), tPos); + } + + for (auto& substr : langlist) { + p = tname.Find(_T("\t") + substr); + if (p > 0) { + return true; + } + p = tname.Find(_T(".") + substr + _T(".")); + if (p > 0) { + return true; + } + p = tname.Find(_T("[") + substr + _T("]")); + if (p > 0) { + return true; + } + p = tname.Find(substr); + if (p == 0 || p == 3 && tname.Left(3) == _T("s: ")) { // at begin of trackname + return true; + } + } + } + + return false; +} + +// Called from GraphThread +int CMainFrame::SetupSubtitleStreams() +{ + const CAppSettings& s = AfxGetAppSettings(); + + int selected = -1; + + if (!m_pSubStreams.IsEmpty()) { + bool is_external = false; + bool externalPriority = false; + bool has_off_lang = false; + std::list> langs; + int tPos = 0; + CString lang = s.strSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); + while (tPos != -1) { + lang.MakeLower(); + ISOLangT l = ISOLangT(lang, L"", L"", 0); + + if (lang == _T("off")) { + has_off_lang = true; + } else if (lang.Find(L'-') == 2) { + // BCP 47 + } else { + l = ISOLang::ISO639XToISOLang(CStringA(lang)); + if (l.name.IsEmpty()) { // not an ISO code + l.name = lang; + } else { + l.name.MakeLower(); + } + } + + langs.emplace_back(l); + + lang = s.strSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); + } + + int i = 0; + int subcount = m_pSubStreams.GetSize(); + int maxrating = 0; + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + if (m_posFirstExtSub == pos) { + is_external = true; + externalPriority = s.fPrioritizeExternalSubtitles; + } + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + CComPtr pSubStream = subInput.pSubStream; + CComQIPtr pSSF = subInput.pSourceFilter; + + bool bAllowOverridingSplitterChoice; + // If the internal LAV Splitter has its own language preferences set, we choose not to override its choice + if (pSSF && CFGFilterLAV::IsInternalInstance(subInput.pSourceFilter)) { + bAllowOverridingSplitterChoice = true; + if (CComQIPtr pLAVFSettings = subInput.pSourceFilter) { + CComHeapPtr pLangPrefs; + LAVSubtitleMode subtitleMode = pLAVFSettings->GetSubtitleMode(); + if ((((subtitleMode == LAVSubtitleMode_Default && SUCCEEDED(pLAVFSettings->GetPreferredSubtitleLanguages(&pLangPrefs))) + || (subtitleMode == LAVSubtitleMode_Advanced && SUCCEEDED(pLAVFSettings->GetAdvancedSubtitleConfig(&pLangPrefs)))) + && pLangPrefs && wcslen(pLangPrefs)) + || subtitleMode == LAVSubtitleMode_ForcedOnly || subtitleMode == LAVSubtitleMode_NoSubs) { + bAllowOverridingSplitterChoice = false; + } + } + } else { + bAllowOverridingSplitterChoice = s.bAllowOverridingExternalSplitterChoice; + } + + int count = 0; + if (pSSF) { + DWORD cStreams; + if (SUCCEEDED(pSSF->Count(&cStreams))) { + count = (int)cStreams; + } + } else { + count = pSubStream->GetStreamCount(); + } + + for (int j = 0; j < count; j++) { + CComHeapPtr pName; + LCID lcid = 0; + int rating = 0; + if (pSSF) { + DWORD dwFlags, dwGroup = 2; + pSSF->Info(j, nullptr, &dwFlags, &lcid, &dwGroup, &pName, nullptr, nullptr); + if (dwGroup != 2) { // If the track isn't a subtitle track, we skip it + continue; + } else if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + // Give slightly higher priority to the track selected by splitter so that + // we won't override selected track in case all have the same rating. + rating += 1; + } else if (!bAllowOverridingSplitterChoice) { + // If we aren't allowed to modify the splitter choice and the current + // track isn't already selected at splitter level we need to skip it. + i++; + continue; + } + } else { + pSubStream->GetStreamInfo(j, &pName, &lcid); + } + CString name(pName); + name.Trim(); + name.MakeLower(); + + size_t k = 0; + for (const auto& l : langs) { + int num = _tstoi(l.name) - 1; + if (num >= 0) { // this is track number + if (i != num) { + k++; + continue; // not matched + } + } else { // this is lang string + if (lcid == 0 || lcid == LCID(-1) || lcid != l.lcid) { + // no LCID match, analyze track name for language match + if (!MatchSubtrackWithISOLang(name, l)) { + k++; + continue; // not matched + } + } + // LCID match + } + rating += 16 * int(langs.size() - k); + break; + } + + if (is_external) { + if (rating > 0) { + if (externalPriority) { + rating += 16 * int(langs.size() + 1); + } + } else { + if (langs.size() == 0 || name.Find(_T("\t")) == -1) { + // no preferred language or unknown sub language + if (externalPriority) { + rating += 16 * int(langs.size() + 1); + } else { + rating = 1; + } + } + } + } else { + if (s.bPreferDefaultForcedSubtitles) { + if (name.Find(_T("[default,forced]")) != -1) { // for LAV Splitter + rating += 4 + 2; + } + if (name.Find(_T("[forced]")) != -1) { + rating += 2; + } + if (name.Find(_T("[default]")) != -1) { + rating += 4; + } + } +#if 0 + if (rating == 0 && bAllowOverridingSplitterChoice && langs.size() == 0) { + // use first embedded track as fallback if there is no preferred language + rating = 1; + } +#endif + } + + if (rating > maxrating) { + maxrating = rating; + selected = i; + } + i++; + } + } + } + + if (s.IsISRAutoLoadEnabled() && !m_fAudioOnly) { + if (s.bAutoDownloadSubtitles && m_pSubStreams.IsEmpty()) { + m_pSubtitlesProviders->Search(TRUE); + } else if (m_wndSubtitlesDownloadDialog.IsWindowVisible()) { + m_pSubtitlesProviders->Search(FALSE); + } + } + + return selected; +} + +bool CMainFrame::OpenMediaPrivate(CAutoPtr pOMD) +{ + ASSERT(GetLoadState() == MLS::LOADING); + auto& s = AfxGetAppSettings(); + + m_fValidDVDOpen = false; + m_iDefRotation = 0; + + OpenFileData* pFileData = dynamic_cast(pOMD.m_p); + OpenDVDData* pDVDData = dynamic_cast(pOMD.m_p); + OpenDeviceData* pDeviceData = dynamic_cast(pOMD.m_p); + ASSERT(pFileData || pDVDData || pDeviceData); + + m_pCAP3 = nullptr; + m_pCAP2 = nullptr; + m_pCAP = nullptr; + m_pVMRWC = nullptr; + m_pVMRMC = nullptr; + m_pMFVDC = nullptr; + m_pVMB = nullptr; + m_pMFVMB = nullptr; + m_pMFVP = nullptr; + m_pMVRC = nullptr; + m_pMVRI = nullptr; + m_pMVRS = nullptr; + m_pMVRSR = nullptr; + m_pMVRFG = nullptr; + m_pMVTO = nullptr; + m_pD3DFSC = nullptr; + m_pLN21 = nullptr; + m_pCAP2_preview = nullptr; + m_pMFVDC_preview = nullptr; + m_pMFVP_preview = nullptr; + m_pVMR9C_preview = nullptr; + +#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[%u]:\n"), index); + TRACE(_T("\t%ws\n"), path.GetString()); // %ws - wide character string always + index++; + } + } + // Debug trace code - End +#endif + + CString err; + try { + auto checkAborted = [&]() { + if (m_fOpeningAborted) { + throw (UINT)IDS_AG_ABORTED; + } + }; + + OpenCreateGraphObject(pOMD); + checkAborted(); + + if (pFileData) { + OpenFile(pFileData); + } else if (pDVDData) { + 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; + } + + if (!m_pGB) { + throw (UINT)IDS_MAINFRM_88; + } + + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP2), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP3), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRWC), FALSE); // might have IVMRMixerBitmap9, but not IVMRWindowlessControl9 + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRMC), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMB), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVMB), TRUE); + + m_pMVRC = m_pCAP; + m_pMVRI = m_pCAP; + m_pMVRS = m_pCAP; + m_pMVRSR = m_pCAP; + m_pMVRFG = m_pCAP; + m_pMVTO = m_pCAP; + m_pD3DFSC = m_pCAP; + + checkAborted(); + + SetupVMR9ColorControl(); + checkAborted(); + + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVDC), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVP), TRUE); + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } + + // COMMENTED OUT: does not work at this location, need to choose the correct mode (IMFVideoProcessor::SetVideoProcessorMode) + //SetupEVRColorControl(); + + if (m_bUseSeekPreview) { + m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pMFVDC_preview), TRUE); + m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pMFVP_preview), TRUE); + m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pVMR9C_preview), TRUE); + m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pCAP2_preview), TRUE); + + RECT wr; + m_wndPreView.GetVideoRect(&wr); + if (m_pMFVDC_preview) { + m_pMFVDC_preview->SetVideoWindow(m_wndPreView.GetVideoHWND()); + m_pMFVDC_preview->SetVideoPosition(nullptr, &wr); + } + if (m_pCAP2_preview) { + m_pCAP2_preview->SetPosition(wr, wr); + } + } + + if (m_pLN21) { + m_pLN21->SetServiceState(s.fClosedCaptions ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off); + } + + checkAborted(); + + OpenCustomizeGraph(); + checkAborted(); + + OpenSetupVideo(); + checkAborted(); + + if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is used + m_OSD.Stop(); + + if (m_pMVTO) { + m_OSD.Start(m_pVideoWnd, m_pMVTO); + } else if (m_fFullScreen && !m_fAudioOnly && m_pCAP3) { // MPCVR + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); + } else if (!m_fAudioOnly && IsD3DFullScreenMode() && (m_pVMB || m_pMFVMB)) { + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); + } else { + m_OSD.Start(m_pOSDWnd); + } + } + + OpenSetupAudio(); + checkAborted(); + + if (GetPlaybackMode() == PM_FILE && pFileData) { + const CString& fn = pFileData->fns.GetHead(); + // Don't try to save file position if source isn't seekable + REFERENCE_TIME rtPos = 0; + REFERENCE_TIME rtDur = 0; + m_loadedAudioTrackIndex = -1; + m_loadedSubtitleTrackIndex = -1; + + if (m_pMS) { + m_pMS->GetDuration(&rtDur); + } + + m_bRememberFilePos = s.fKeepHistory && s.fRememberFilePos && rtDur > (s.iRememberPosForLongerThan * 10000000i64 * 60i64) && (s.bRememberPosForAudioFiles || !m_fAudioOnly); + + // Set start time but seek only after all files are loaded + if (pFileData->rtStart > 0) { // Check if an explicit start time was given + rtPos = pFileData->rtStart; + } + if (pFileData->abRepeat) { // Check if an explicit a/b repeat time was given + abRepeat = pFileData->abRepeat; + } + + if (m_dwReloadPos > 0) { + if (m_dwReloadPos < rtDur) { + rtPos = m_dwReloadPos; + } + m_dwReloadPos = 0; + } + if (reloadABRepeat) { + abRepeat = reloadABRepeat; + reloadABRepeat = ABRepeat(); + } + + auto* pMRU = &AfxGetAppSettings().MRU; + if (pMRU->rfe_array.GetCount()) { + if (!rtPos && m_bRememberFilePos) { + rtPos = pMRU->GetCurrentFilePosition(); + if (rtPos >= rtDur || rtDur - rtPos < 50000000LL) { + rtPos = 0; + } + } + if (!abRepeat && s.fKeepHistory && s.fRememberFilePos) { + abRepeat = pMRU->GetCurrentABRepeat(); + } + if (s.fKeepHistory && s.bRememberTrackSelection) { + if (m_loadedAudioTrackIndex == -1) { + m_loadedAudioTrackIndex = pMRU->GetCurrentAudioTrack(); + } + if (m_loadedSubtitleTrackIndex == -1) { + m_loadedSubtitleTrackIndex = pMRU->GetCurrentSubtitleTrack(); + } + } + } + + if (abRepeat && abRepeat.positionB > 0) { + // validate + if (abRepeat.positionB > rtDur || abRepeat.positionA >= abRepeat.positionB) { + abRepeat = ABRepeat(); + } + } + if (abRepeat) { + m_wndSeekBar.Invalidate(); + } + + if (rtPos && rtDur) { + m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + + defaultVideoAngle = 0; + if (m_pFSF && (m_pCAP2 || m_pCAP3)) { + CComQIPtr pBF = m_pFSF; + if (GetCLSID(pBF) == GUID_LAVSplitter || GetCLSID(pBF) == GUID_LAVSplitterSource) { + if (CComQIPtr pPB = pBF) { + CComVariant var; + if (SUCCEEDED(pPB->Read(_T("rotation"), &var, nullptr)) && var.vt == VT_BSTR) { + int rotatevalue = _wtoi(var.bstrVal); + if (rotatevalue == 90 || rotatevalue == 180 || rotatevalue == 270) { + m_iDefRotation = rotatevalue; + if (m_pCAP3) { + m_pCAP3->SetRotation(rotatevalue); + } else { + m_pCAP2->SetDefaultVideoAngle(Vector(0, 0, Vector::DegToRad(360 - rotatevalue))); + } + if (m_pCAP2_preview) { + defaultVideoAngle = 360 - rotatevalue; + m_pCAP2_preview->SetDefaultVideoAngle(Vector(0, 0, Vector::DegToRad(defaultVideoAngle))); + } + } + } + var.Clear(); + } + } + } + } + checkAborted(); + + if (m_pCAP && s.IsISRAutoLoadEnabled() && !m_fAudioOnly) { + if (s.fDisableInternalSubtitles) { + m_pSubStreams.RemoveAll(); // Needs to be replaced with code that checks for forced subtitles. + } + m_posFirstExtSub = nullptr; + if (!pOMD->subs.IsEmpty()) { + POSITION pos = pOMD->subs.GetHeadPosition(); + while (pos) { + LoadSubtitle(pOMD->subs.GetNext(pos), nullptr, true); + } + } + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli) && pli.m_bYoutubeDL && !s.sYDLSubsPreference.IsEmpty()) { + POSITION pos2 = pli.m_ydl_subs.GetHeadPosition(); + while (pos2) { + CYoutubeDLInstance::YDLSubInfo ydlsub = pli.m_ydl_subs.GetNext(pos2); + if (!ydlsub.isAutomaticCaptions || s.bUseAutomaticCaptions) { + LoadSubtitle(ydlsub); + } + } + } + } + checkAborted(); + + OpenSetupWindowTitle(); + checkAborted(); + + int audstm; // offset in audio track menu, AudioSwitcher adds an "Options" entry above the audio tracks + audstm = SetupAudioStreams(); + if (audstm >= 0) { + OnPlayAudio(ID_AUDIO_SUBITEM_START + audstm); + } + checkAborted(); + + int substm; + if (m_loadedSubtitleTrackIndex >= 0 && IsValidSubtitleStream(m_loadedSubtitleTrackIndex)) { + substm = m_loadedSubtitleTrackIndex; + } else { + substm = SetupSubtitleStreams(); + } + if (substm >= 0) { + SetSubtitle(substm); + } + checkAborted(); + + // apply /dubdelay command-line switch + // TODO: that command-line switch probably needs revision + if (s.rtShift != 0) { + SetAudioDelay(s.rtShift); + s.rtShift = 0; + } + } catch (LPCTSTR msg) { + err = msg; + } catch (CString& msg) { + err = msg; + } catch (UINT msg) { + err.LoadString(msg); + } + + if (m_bUseSeekPreview && m_pMC_preview) { + m_pMC_preview->Pause(); + } + + m_closingmsg = err; + + auto getMessageArgs = [&]() { + WPARAM wp = pFileData ? PM_FILE : pDVDData ? PM_DVD : pDeviceData ? (s.iDefaultCaptureDevice == 1 ? PM_DIGITAL_CAPTURE : PM_ANALOG_CAPTURE) : PM_NONE; + ASSERT(wp != PM_NONE); + LPARAM lp = (LPARAM)pOMD.Detach(); + ASSERT(lp); + return std::make_pair(wp, lp); + }; + if (err.IsEmpty()) { + auto args = getMessageArgs(); + if (!m_bOpenedThroughThread) { + ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); + OnFilePostOpenmedia(args.first, args.second); + } else { + PostMessage(WM_POSTOPEN, args.first, args.second); + } + } else if (!m_fOpeningAborted) { + auto args = getMessageArgs(); + if (!m_bOpenedThroughThread) { + ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); + OnOpenMediaFailed(args.first, args.second); + } else { + PostMessage(WM_OPENFAILED, args.first, args.second); + } + } + + return err.IsEmpty(); +} + +void CMainFrame::CloseMediaPrivate() +{ + ASSERT(GetLoadState() == MLS::CLOSING); + + MediaControlStop(true); // needed for StreamBufferSource, because m_iMediaLoadState is always MLS::CLOSED // TODO: fix the opening for such media + m_CachedFilterState = -1; + + m_fLiveWM = false; + m_fEndOfStream = false; + m_bBuffering = false; + m_rtDurationOverride = -1; + m_bUsingDXVA = false; + m_audioTrackCount = 0; + if (m_pDVBState) { + m_pDVBState->Join(); + m_pDVBState = nullptr; + } + m_pCB.Release(); + + { + CAutoLock cAutoLock(&m_csSubLock); + m_pCurrentSubInput = SubtitleInput(nullptr); + m_pSubStreams.RemoveAll(); + m_ExternalSubstreams.clear(); + } + m_pSubClock.Release(); + + if (m_pVW && !m_pMVRS) { + m_pVW->put_Owner(NULL); + } + + m_bIsMPCVRExclusiveMode = false; + + // IMPORTANT: IVMRSurfaceAllocatorNotify/IVMRSurfaceAllocatorNotify9 has to be released before the VMR/VMR9, otherwise it will crash in Release() + m_OSD.Stop(); + m_pMVRFG.Release(); + m_pMVRSR.Release(); + m_pMVRS.Release(); + m_pMVRC.Release(); + m_pMVRI.Release(); + m_pMVTO.Release(); + m_pD3DFSC.Release(); + m_pCAP3.Release(); + m_pCAP2.Release(); + m_pCAP.Release(); + m_pVMRWC.Release(); + m_pVMRMC.Release(); + m_pVMB.Release(); + m_pMFVMB.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(); + m_pFSF.Release(); + m_pKFI.Release(); + m_pAMNS.Release(); + m_pDVS.Release(); + m_pDVS2.Release(); + for (auto& pAMMC : m_pAMMC) { + pAMMC.Release(); + } + m_pAudioSwitcherSS.Release(); + m_pSplitterSS.Release(); + m_pSplitterDubSS.Release(); + for (auto& pSS : m_pOtherSS) { + pSS.Release(); + } + + if (m_pGB) { + m_pGB->RemoveFromROT(); + m_pGB.Release(); + } + + if (m_pGB_preview) { + TRACE(_T("Stopping preview graph\n")); + MediaControlStopPreview(); + TRACE(_T("Releasing preview graph\n")); + ReleasePreviewGraph(); + } + + m_pProv.Release(); + + m_fCustomGraph = m_fShockwaveGraph = false; + + m_lastOMD.Free(); + + m_FontInstaller.UninstallFonts(); +} + +bool CMainFrame::WildcardFileSearch(CString searchstr, std::set& results, bool recurse_dirs) +{ + ExtendMaxPathLengthIfNeeded(searchstr); + + CString path = searchstr; + path.Replace('/', '\\'); + int p = path.ReverseFind('\\'); + if (p < 0) return false; + path = path.Left(p + 1); + + WIN32_FIND_DATA findData; + ZeroMemory(&findData, sizeof(WIN32_FIND_DATA)); + HANDLE h = FindFirstFile(searchstr, &findData); + if (h != INVALID_HANDLE_VALUE) { + CString search_ext = searchstr.Mid(searchstr.ReverseFind('.')).MakeLower(); + bool other_ext = (search_ext != _T(".*")); + CStringW curExt = CPath(m_wndPlaylistBar.GetCurFileName()).GetExtension().MakeLower(); + + do { + CString filename = findData.cFileName; + + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (recurse_dirs && search_ext == L".*" && filename != L"." && filename != L"..") { + WildcardFileSearch(path + filename + L"\\*.*", results, true); + } + continue; + } + + CString ext = filename.Mid(filename.ReverseFind('.')).MakeLower(); + + if (CanSkipToExt(ext, curExt)) { + /* playlist and cue files should be ignored when searching dir for playable files */ + if (!IsPlaylistFileExt(ext)) { + results.insert(path + filename); + } + } else if (other_ext && search_ext == ext) { + results.insert(path + filename); + if (ext == _T(".rar")) { + break; + } + } + } while (FindNextFile(h, &findData)); + + FindClose(h); + } + + return results.size() > 0; +} + +bool CMainFrame::SearchInDir(bool bDirForward, bool bLoop /*= false*/) +{ + ASSERT(GetPlaybackMode() == PM_FILE || CanSkipFromClosedFile()); + + CString filename; + + auto pFileData = dynamic_cast(m_lastOMD.m_p); + if (!pFileData || !pFileData->title || pFileData->title.IsEmpty()) { + if (CanSkipFromClosedFile()) { + if (m_wndPlaylistBar.GetCount() == 1) { + filename = m_wndPlaylistBar.m_pl.GetHead().m_fns.GetHead(); + } else { + filename = lastOpenFile; + } + } else { + ASSERT(FALSE); + return false; + } + } else { + filename = pFileData->title; + } + + if (PathUtils::IsURL(filename)) { + return false; + } + + int p = filename.ReverseFind(_T('\\')); + if (p < 0) { + return false; + } + CString filemask = filename.Left(p + 1) + _T("*.*"); + std::set filelist; + if (!WildcardFileSearch(filemask, filelist, false)) { + return false; + } + + // We make sure that the currently opened file is added to the list + // even if it's of an unknown format. + auto current = filelist.insert(filename).first; + + if (filelist.size() < 2 && CPath(filename).FileExists()) { + return false; + } + + if (bDirForward) { + current++; + if (current == filelist.end()) { + if (bLoop) { + current = filelist.begin(); + } else { + return false; + } + } + } else { + if (current == filelist.begin()) { + if (bLoop) { + current = filelist.end(); + } else { + return false; + } + } + current--; + } + + CAtlList sl; + sl.AddHead(*current); + m_wndPlaylistBar.Open(sl, false); + OpenCurPlaylistItem(); + + return true; +} + +void CMainFrame::DoTunerScan(TunerScanData* pTSD) +{ + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + bool wasStopped = false; + if (GetMediaState() == State_Stopped) { + SetChannel(-1); + MediaControlRun(); + wasStopped = true; + } + + BOOLEAN bPresent; + BOOLEAN bLocked; + LONG lDbStrength = 0; + LONG lPercentQuality = 0; + int nOffset = pTSD->Offset ? 3 : 1; + LONG lOffsets[3] = {0, pTSD->Offset, -pTSD->Offset}; + m_bStopTunerScan = false; + pTun->Scan(0, 0, 0, NULL); // Clear maps + + for (ULONG ulFrequency = pTSD->FrequencyStart; ulFrequency <= pTSD->FrequencyStop; ulFrequency += pTSD->Bandwidth) { + bool bSucceeded = false; + for (int nOffsetPos = 0; nOffsetPos < nOffset && !bSucceeded; nOffsetPos++) { + if (SUCCEEDED(pTun->SetFrequency(ulFrequency + lOffsets[nOffsetPos], pTSD->Bandwidth, pTSD->SymbolRate))) { + Sleep(200); // Let the tuner some time to detect the signal + if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { + ::SendMessage(pTSD->Hwnd, WM_TUNER_STATS, lDbStrength, lPercentQuality); + pTun->Scan(ulFrequency + lOffsets[nOffsetPos], pTSD->Bandwidth, pTSD->SymbolRate, pTSD->Hwnd); + bSucceeded = true; + } + } + } + + int nProgress = MulDiv(ulFrequency - pTSD->FrequencyStart, 100, pTSD->FrequencyStop - pTSD->FrequencyStart); + ::SendMessage(pTSD->Hwnd, WM_TUNER_SCAN_PROGRESS, nProgress, 0); + ::SendMessage(pTSD->Hwnd, WM_TUNER_STATS, lDbStrength, lPercentQuality); + + if (m_bStopTunerScan) { + break; + } + } + + ::SendMessage(pTSD->Hwnd, WM_TUNER_SCAN_END, 0, 0); + if (wasStopped) { + SetChannel(AfxGetAppSettings().nDVBLastChannel); + MediaControlStop(); + } + } + } +} + +// Skype + +void CMainFrame::SendNowPlayingToSkype() +{ + if (!m_pSkypeMoodMsgHandler) { + return; + } + + CString msg; + + if (GetLoadState() == MLS::LOADED) { + CString title, author; + + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_TITLE), title); + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); + + if (title.IsEmpty()) { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + CString label = !pli.m_label.IsEmpty() ? pli.m_label : pli.m_fns.GetHead(); + + if (GetPlaybackMode() == PM_FILE) { + CString fn = label; + if (!pli.m_bYoutubeDL && PathUtils::IsURL(fn)) { + int i = fn.Find('?'); + if (i >= 0) { + fn = fn.Left(i); + } + } + CPath path(fn); + path.StripPath(); + path.MakePretty(); + path.RemoveExtension(); + title = (LPCTSTR)path; + author.Empty(); + } else if (IsPlaybackCaptureMode()) { + title = GetCaptureTitle(); + author.Empty(); + } else if (GetPlaybackMode() == PM_DVD) { + title = _T("DVD"); + author.Empty(); + } + } + } + + if (!author.IsEmpty()) { + msg.Format(_T("%s - %s"), author.GetString(), title.GetString()); + } else { + msg = title; + } + } + + m_pSkypeMoodMsgHandler->SendMoodMessage(msg); +} + +// dynamic menus + +void CMainFrame::CreateDynamicMenus() +{ + VERIFY(m_openCDsMenu.CreatePopupMenu()); + VERIFY(m_filtersMenu.CreatePopupMenu()); + VERIFY(m_subtitlesMenu.CreatePopupMenu()); + VERIFY(m_audiosMenu.CreatePopupMenu()); + VERIFY(m_videoStreamsMenu.CreatePopupMenu()); + VERIFY(m_chaptersMenu.CreatePopupMenu()); + VERIFY(m_titlesMenu.CreatePopupMenu()); + VERIFY(m_playlistMenu.CreatePopupMenu()); + VERIFY(m_BDPlaylistMenu.CreatePopupMenu()); + VERIFY(m_channelsMenu.CreatePopupMenu()); + VERIFY(m_favoritesMenu.CreatePopupMenu()); + VERIFY(m_shadersMenu.CreatePopupMenu()); + VERIFY(m_recentFilesMenu.CreatePopupMenu()); +} + +void CMainFrame::DestroyDynamicMenus() +{ + VERIFY(m_openCDsMenu.DestroyMenu()); + VERIFY(m_filtersMenu.DestroyMenu()); + VERIFY(m_subtitlesMenu.DestroyMenu()); + VERIFY(m_audiosMenu.DestroyMenu()); + VERIFY(m_videoStreamsMenu.DestroyMenu()); + VERIFY(m_chaptersMenu.DestroyMenu()); + VERIFY(m_titlesMenu.DestroyMenu()); + VERIFY(m_playlistMenu.DestroyMenu()); + VERIFY(m_BDPlaylistMenu.DestroyMenu()); + VERIFY(m_channelsMenu.DestroyMenu()); + VERIFY(m_favoritesMenu.DestroyMenu()); + VERIFY(m_shadersMenu.DestroyMenu()); + VERIFY(m_recentFilesMenu.DestroyMenu()); + m_nJumpToSubMenusCount = 0; +} + +void CMainFrame::SetupOpenCDSubMenu() +{ + CMenu& subMenu = m_openCDsMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (GetLoadState() == MLS::LOADING || AfxGetAppSettings().fHideCDROMsSubMenu) { + return; + } + + UINT id = ID_FILE_OPEN_OPTICAL_DISK_START; + for (TCHAR drive = _T('A'); drive <= _T('Z'); drive++) { + CAtlList files; + OpticalDiskType_t opticalDiskType = GetOpticalDiskType(drive, files); + + if (opticalDiskType != OpticalDisk_NotFound && opticalDiskType != OpticalDisk_Unknown) { + CString label = GetDriveLabel(drive); + if (label.IsEmpty()) { + switch (opticalDiskType) { + case OpticalDisk_Audio: + label = _T("Audio CD"); + break; + case OpticalDisk_VideoCD: + label = _T("(S)VCD"); + break; + case OpticalDisk_DVDVideo: + label = _T("DVD Video"); + break; + case OpticalDisk_BD: + label = _T("Blu-ray Disc"); + break; + default: + ASSERT(FALSE); + break; + } + } + + CString str; + str.Format(_T("%s (%c:)"), label.GetString(), drive); + + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, str)); + } + } +} + +void CMainFrame::SetupFiltersSubMenu() +{ + CMPCThemeMenu& subMenu = m_filtersMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + m_pparray.RemoveAll(); + m_ssarray.RemoveAll(); + + if (GetLoadState() == MLS::LOADED) { + UINT idf = 1; //used as an id, so make non-zero to start + UINT ids = ID_FILTERS_SUBITEM_START; + UINT idl = ID_FILTERSTREAMS_SUBITEM_START; + + BeginEnumFilters(m_pGB, pEF, pBF) { + CString filterName(GetFilterName(pBF)); + if (filterName.GetLength() >= 43) { + filterName = filterName.Left(40) + _T("..."); + } + + CLSID clsid = GetCLSID(pBF); + if (clsid == CLSID_AVIDec) { + CComPtr pPin = GetFirstPin(pBF); + AM_MEDIA_TYPE mt; + if (pPin && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + DWORD c = ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression; + switch (c) { + case BI_RGB: + filterName += _T(" (RGB)"); + break; + case BI_RLE4: + filterName += _T(" (RLE4)"); + break; + case BI_RLE8: + filterName += _T(" (RLE8)"); + break; + case BI_BITFIELDS: + filterName += _T(" (BITF)"); + break; + default: + filterName.AppendFormat(_T(" (%c%c%c%c)"), + (TCHAR)((c >> 0) & 0xff), + (TCHAR)((c >> 8) & 0xff), + (TCHAR)((c >> 16) & 0xff), + (TCHAR)((c >> 24) & 0xff)); + break; + } + } + } else if (clsid == CLSID_ACMWrapper) { + CComPtr pPin = GetFirstPin(pBF); + AM_MEDIA_TYPE mt; + if (pPin && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + WORD c = ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag; + filterName.AppendFormat(_T(" (0x%04x)"), (int)c); + } + } else if (clsid == __uuidof(CTextPassThruFilter) + || clsid == __uuidof(CNullTextRenderer) + || clsid == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) { // ISCR + // hide these + continue; + } + + CMenu internalSubMenu; + VERIFY(internalSubMenu.CreatePopupMenu()); + + int nPPages = 0; + + CComQIPtr pSPP = pBF; + + m_pparray.Add(pBF); + VERIFY(internalSubMenu.AppendMenu(MF_STRING | MF_ENABLED, ids, ResStr(IDS_MAINFRM_116))); + + nPPages++; + + BeginEnumPins(pBF, pEP, pPin) { + CString pinName = GetPinName(pPin); + pinName.Replace(_T("&"), _T("&&")); + + if (pSPP = pPin) { + CAUUID caGUID; + caGUID.pElems = nullptr; + if (SUCCEEDED(pSPP->GetPages(&caGUID)) && caGUID.cElems > 0) { + m_pparray.Add(pPin); + VERIFY(internalSubMenu.AppendMenu(MF_STRING | MF_ENABLED, ids + nPPages, pinName + ResStr(IDS_MAINFRM_117))); + + if (caGUID.pElems) { + CoTaskMemFree(caGUID.pElems); + } + + nPPages++; + } + } + } + EndEnumPins; + + CComQIPtr pSS = pBF; + DWORD nStreams = 0; + if (pSS && SUCCEEDED(pSS->Count(&nStreams))) { + DWORD flags = DWORD_MAX; + DWORD group = DWORD_MAX; + DWORD prevgroup = DWORD_MAX; + LCID lcid = 0; + WCHAR* wname = nullptr; + UINT uMenuFlags; + + if (nStreams > 0 && nPPages > 0) { + VERIFY(internalSubMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + } + + UINT idlstart = idl; + UINT selectedInGroup = 0; + + for (DWORD i = 0; i < nStreams; i++) { + m_ssarray.Add(pSS); + + flags = group = 0; + wname = nullptr; + if (FAILED(pSS->Info(i, nullptr, &flags, &lcid, &group, &wname, nullptr, nullptr))) { + continue; + } + + if (group != prevgroup && idl > idlstart) { + if (selectedInGroup) { + VERIFY(internalSubMenu.CheckMenuRadioItem(idlstart, idl - 1, selectedInGroup, MF_BYCOMMAND)); + selectedInGroup = 0; + } + VERIFY(internalSubMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + idlstart = idl; + } + prevgroup = group; + + uMenuFlags = MF_STRING | MF_ENABLED; + if (flags & AMSTREAMSELECTINFO_EXCLUSIVE) { + selectedInGroup = idl; + } else if (flags & AMSTREAMSELECTINFO_ENABLED) { + uMenuFlags |= MF_CHECKED; + } + + CString streamName; + if (!wname) { + streamName.LoadString(IDS_AG_UNKNOWN_STREAM); + streamName.AppendFormat(_T(" %lu"), i + 1); + } else { + streamName = wname; + streamName.Replace(_T("&"), _T("&&")); + CoTaskMemFree(wname); + } + + VERIFY(internalSubMenu.AppendMenu(uMenuFlags, idl++, streamName)); + } + if (selectedInGroup) { + VERIFY(internalSubMenu.CheckMenuRadioItem(idlstart, idl - 1, selectedInGroup, MF_BYCOMMAND)); + } + + if (nStreams == 0) { + pSS.Release(); + } + } + + if (nPPages == 1 && !pSS) { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ids, filterName)); + } else { + if (nPPages > 0 || pSS) { + UINT nFlags = MF_STRING | MF_POPUP | ((pSPP || pSS) ? MF_ENABLED : MF_GRAYED); + VERIFY(subMenu.AppendMenu(nFlags, (UINT_PTR)internalSubMenu.Detach(), filterName)); + } else { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_GRAYED, idf, filterName)); + } + } + + ids += nPPages; + idf++; + } + EndEnumFilters; + + if (subMenu.GetMenuItemCount() > 0) { + VERIFY(subMenu.InsertMenu(0, MF_STRING | MF_ENABLED | MF_BYPOSITION, ID_FILTERS_COPY_TO_CLIPBOARD, ResStr(IDS_FILTERS_COPY_TO_CLIPBOARD))); + VERIFY(subMenu.InsertMenu(1, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); + } + subMenu.fulfillThemeReqs(); + } +} + +void CMainFrame::SetupAudioSubMenu() +{ + CMenu& subMenu = m_audiosMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (GetLoadState() != MLS::LOADED) { + return; + } + + UINT id = ID_AUDIO_SUBITEM_START; + + DWORD cStreams = 0; + + if (GetPlaybackMode() == PM_DVD) { + currentAudioLang = _T(""); + ULONG ulStreamsAvailable, ulCurrentStream; + if (FAILED(m_pDVDI->GetCurrentAudio(&ulStreamsAvailable, &ulCurrentStream))) { + return; + } + + LCID DefLanguage; + DVD_AUDIO_LANG_EXT ext; + if (FAILED(m_pDVDI->GetDefaultAudioLanguage(&DefLanguage, &ext))) { + return; + } + + for (ULONG i = 0; i < ulStreamsAvailable; i++) { + LCID Language; + if (FAILED(m_pDVDI->GetAudioLanguage(i, &Language))) { + continue; + } + + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (Language == DefLanguage) { + flags |= MF_DEFAULT; + } + if (i == ulCurrentStream) { + flags |= MF_CHECKED; + if (Language) { + GetLocaleString(Language, LOCALE_SISO639LANGNAME2, currentAudioLang); + } + } + + CString str; + if (Language) { + GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); + } else { + str.Format(IDS_AG_UNKNOWN, i + 1); + } + + DVD_AudioAttributes ATR; + if (SUCCEEDED(m_pDVDI->GetAudioAttributes(i, &ATR))) { + switch (ATR.LanguageExtension) { + case DVD_AUD_EXT_NotSpecified: + default: + break; + case DVD_AUD_EXT_Captions: + str += _T(" (Captions)"); + break; + case DVD_AUD_EXT_VisuallyImpaired: + str += _T(" (Visually Impaired)"); + break; + case DVD_AUD_EXT_DirectorComments1: + str.AppendFormat(IDS_MAINFRM_121); + break; + case DVD_AUD_EXT_DirectorComments2: + str.AppendFormat(IDS_MAINFRM_122); + break; + } + + CString format = GetDVDAudioFormatName(ATR); + + if (!format.IsEmpty()) { + str.Format(IDS_MAINFRM_11, + CString(str).GetString(), + format.GetString(), + ATR.dwFrequency, + ATR.bQuantization, + ATR.bNumberOfChannels, + ResStr(ATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString() + ); + } + } + + VERIFY(AppendMenuEx(subMenu, flags, id++, str)); + } + } + // If available use the audio switcher for everything but DVDs + else if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_OPTIONS))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + + long iSel = 0; + + for (long i = 0; i < (long)cStreams; i++) { + DWORD dwFlags; + WCHAR* pName = nullptr; + if (FAILED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, nullptr, &pName, nullptr, nullptr))) { + break; + } + if (dwFlags) { + iSel = i; + } + + CString name(pName); + name.Replace(_T("&"), _T("&&")); + + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); + + CoTaskMemFree(pName); + } + VERIFY(subMenu.CheckMenuRadioItem(2, 2 + cStreams - 1, 2 + iSel, MF_BYPOSITION)); + } else if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + SetupNavStreamSelectSubMenu(subMenu, id, 1); + } +} + +void CMainFrame::SetupSubtitlesSubMenu() +{ + CMenu& subMenu = m_subtitlesMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { + return; + } + + UINT id = ID_SUBTITLES_SUBITEM_START; + + // DVD subtitles in DVD mode are never handled by the internal subtitles renderer + // but it is still possible to load external subtitles so we keep that if block + // separated from the rest + if (GetPlaybackMode() == PM_DVD) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) + && ulStreamsAvailable > 0) { + LCID DefLanguage; + DVD_SUBPICTURE_LANG_EXT ext; + if (FAILED(m_pDVDI->GetDefaultSubpictureLanguage(&DefLanguage, &ext))) { + return; + } + + VERIFY(subMenu.AppendMenu(MF_STRING | (bIsDisabled ? 0 : MF_CHECKED), id++, ResStr(IDS_DVD_SUBTITLES_ENABLE))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + + for (ULONG i = 0; i < ulStreamsAvailable; i++) { + LCID Language; + if (FAILED(m_pDVDI->GetSubpictureLanguage(i, &Language))) { + continue; + } + + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (Language == DefLanguage) { + flags |= MF_DEFAULT; + } + if (i == ulCurrentStream) { + flags |= MF_CHECKED; + } + + CString str; + if (Language) { + GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); + } else { + str.Format(IDS_AG_UNKNOWN, i + 1); + } + + DVD_SubpictureAttributes ATR; + if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(i, &ATR))) { + switch (ATR.LanguageExtension) { + case DVD_SP_EXT_NotSpecified: + default: + break; + case DVD_SP_EXT_Caption_Normal: + str += _T(""); + break; + case DVD_SP_EXT_Caption_Big: + str += _T(" (Big)"); + break; + case DVD_SP_EXT_Caption_Children: + str += _T(" (Children)"); + break; + case DVD_SP_EXT_CC_Normal: + str += _T(" (CC)"); + break; + case DVD_SP_EXT_CC_Big: + str += _T(" (CC Big)"); + break; + case DVD_SP_EXT_CC_Children: + str += _T(" (CC Children)"); + break; + case DVD_SP_EXT_Forced: + str += _T(" (Forced)"); + break; + case DVD_SP_EXT_DirectorComments_Normal: + str += _T(" (Director Comments)"); + break; + case DVD_SP_EXT_DirectorComments_Big: + str += _T(" (Director Comments, Big)"); + break; + case DVD_SP_EXT_DirectorComments_Children: + str += _T(" (Director Comments, Children)"); + break; + } + } + + VERIFY(AppendMenuEx(subMenu, flags, id++, str)); + } + } + } + + POSITION pos = m_pSubStreams.GetHeadPosition(); + + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + DWORD selected = SetupNavStreamSelectSubMenu(subMenu, id, 2); + if (selected != -1) { + SetSubtitle(selected - ID_SUBTITLES_SUBITEM_START); + } + } else if (pos) { // Internal subtitles renderer + int nItemsBeforeStart = id - ID_SUBTITLES_SUBITEM_START; + if (nItemsBeforeStart > 0) { + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + nItemsBeforeStart += 2; // Separators + } + + // Build the static menu's items + bool bTextSubtitles = false; + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_OPTIONS))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_STYLES))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_RELOAD))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_HIDE))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUB_OVERRIDE_DEFAULT_STYLE))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUB_OVERRIDE_ALL_STYLES))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + + // Build the dynamic menu's items + int i = 0, iSelected = -1; + while (pos) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + + if (CComQIPtr pSSF = subInput.pSourceFilter) { + DWORD cStreams; + if (FAILED(pSSF->Count(&cStreams))) { + continue; + } + + for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { + DWORD dwFlags, dwGroup; + CComHeapPtr pszName; + LCID lcid = 0; + if (FAILED(pSSF->Info(j, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + if (dwGroup != 2) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream + && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + iSelected = i; + } + + CString name(pszName); + /* + CString lcname = CString(name).MakeLower(); + if (lcname.Find(_T(" off")) >= 0) { + name.LoadString(IDS_AG_DISABLED); + } + */ + if (lcid != 0 && name.Find(L'\t') < 0) { + CString lcidstr; + GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); + name.Append(_T("\t") + lcidstr); + } + + name.Replace(_T("&"), _T("&&")); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); + i++; + } + } else { + CComPtr pSubStream = subInput.pSubStream; + if (!pSubStream) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + iSelected = i + pSubStream->GetStream(); + } + + for (int j = 0, cnt = pSubStream->GetStreamCount(); j < cnt; j++) { + CComHeapPtr pName; + LCID lcid = 0; + if (SUCCEEDED(pSubStream->GetStreamInfo(j, &pName, &lcid))) { + CString name(pName); + if (lcid != 0 && name.Find(L'\t') < 0) { + CString lcidstr; + GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); + name.Append(_T("\t") + lcidstr); + } + + name.Replace(_T("&"), _T("&&")); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); + } else { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_AG_UNKNOWN_STREAM))); + } + i++; + } + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + CLSID clsid; + if (SUCCEEDED(subInput.pSubStream->GetClassID(&clsid)) + && clsid == __uuidof(CRenderedTextSubtitle)) { + bTextSubtitles = true; + } + } + + // TODO: find a better way to group these entries + /*if (pos && m_pSubStreams.GetAt(pos).subStream) { + CLSID cur, next; + pSubStream->GetClassID(&cur); + m_pSubStreams.GetAt(pos).subStream->GetClassID(&next); + + if (cur != next) { + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + } + }*/ + } + + // Set the menu's items' state + const CAppSettings& s = AfxGetAppSettings(); + // Style + if (!bTextSubtitles) { + subMenu.EnableMenuItem(nItemsBeforeStart + 1, MF_BYPOSITION | MF_GRAYED); + } + // Hide + if (!s.fEnableSubtitles) { + subMenu.CheckMenuItem(nItemsBeforeStart + 4, MF_BYPOSITION | MF_CHECKED); + } + // Style overrides + if (!bTextSubtitles) { + subMenu.EnableMenuItem(nItemsBeforeStart + 5, MF_BYPOSITION | MF_GRAYED); + subMenu.EnableMenuItem(nItemsBeforeStart + 6, MF_BYPOSITION | MF_GRAYED); + } + if (s.bSubtitleOverrideDefaultStyle) { + subMenu.CheckMenuItem(nItemsBeforeStart + 5, MF_BYPOSITION | MF_CHECKED); + } + if (s.bSubtitleOverrideAllStyles) { + subMenu.CheckMenuItem(nItemsBeforeStart + 6, MF_BYPOSITION | MF_CHECKED); + } + if (iSelected >= 0) { + VERIFY(subMenu.CheckMenuRadioItem(nItemsBeforeStart + 8, nItemsBeforeStart + 8 + i - 1, nItemsBeforeStart + 8 + iSelected, MF_BYPOSITION)); + } + } else if (GetPlaybackMode() == PM_FILE) { + SetupNavStreamSelectSubMenu(subMenu, id, 2); + } +} + +void CMainFrame::SetupVideoStreamsSubMenu() +{ + CMenu& subMenu = m_videoStreamsMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (GetLoadState() != MLS::LOADED) { + return; + } + + UINT id = ID_VIDEO_STREAMS_SUBITEM_START; + + if (GetPlaybackMode() == PM_FILE) { + SetupNavStreamSelectSubMenu(subMenu, id, 0); + } else if (GetPlaybackMode() == PM_DVD) { + ULONG ulStreamsAvailable, ulCurrentStream; + if (FAILED(m_pDVDI->GetCurrentAngle(&ulStreamsAvailable, &ulCurrentStream))) { + return; + } + + if (ulStreamsAvailable < 2) { + return; // one choice is not a choice... + } + + for (ULONG i = 1; i <= ulStreamsAvailable; i++) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (i == ulCurrentStream) { + flags |= MF_CHECKED; + } + + CString str; + str.Format(IDS_AG_ANGLE, i); + + VERIFY(subMenu.AppendMenu(flags, id++, str)); + } + } +} + +void CMainFrame::SetupJumpToSubMenus(CMenu* parentMenu /*= nullptr*/, int iInsertPos /*= -1*/) +{ + const CAppSettings& s = AfxGetAppSettings(); + auto emptyMenu = [&](CMPCThemeMenu & menu) { + while (menu.RemoveMenu(0, MF_BYPOSITION)); + }; + + // Empty the submenus + emptyMenu(m_chaptersMenu); + emptyMenu(m_titlesMenu); + emptyMenu(m_playlistMenu); + emptyMenu(m_BDPlaylistMenu); + emptyMenu(m_channelsMenu); + // Remove the submenus from the "Navigate" menu + if (parentMenu && iInsertPos >= 0) { + for (; m_nJumpToSubMenusCount > 0; m_nJumpToSubMenusCount--) { + VERIFY(parentMenu->RemoveMenu(iInsertPos, MF_BYPOSITION)); + } + } + + if (GetLoadState() != MLS::LOADED) { + return; + } + + UINT id = ID_NAVIGATE_JUMPTO_SUBITEM_START, idStart, idSelected; + + auto menuStartRadioSection = [&]() { + idStart = id; + idSelected = UINT_ERROR; + }; + auto menuEndRadioSection = [&](CMenu & menu) { + if (idSelected != UINT_ERROR) { + VERIFY(menu.CheckMenuRadioItem(idStart, id - 1, idSelected, + idStart >= ID_NAVIGATE_JUMPTO_SUBITEM_START ? MF_BYCOMMAND : MF_BYPOSITION)); + } + }; + auto addSubMenuIfPossible = [&](CString subMenuName, CMenu & subMenu) { + if (parentMenu && iInsertPos >= 0) { + if (parentMenu->InsertMenu(iInsertPos + m_nJumpToSubMenusCount, MF_POPUP | MF_BYPOSITION, + (UINT_PTR)(HMENU)subMenu, subMenuName)) { + CMPCThemeMenu::fulfillThemeReqsItem(parentMenu, iInsertPos + m_nJumpToSubMenusCount); + m_nJumpToSubMenusCount++; + } else { + ASSERT(FALSE); + } + } + }; + + if (GetPlaybackMode() == PM_FILE) { + if (m_MPLSPlaylist.size() > 1) { + menuStartRadioSection(); + for (auto& Item : m_MPLSPlaylist) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + CString time = _T("[") + ReftimeToString2(Item.Duration()) + _T("]"); + CString name = PathUtils::StripPathOrUrl(Item.m_strFileName); + + if (name == m_wndPlaylistBar.m_pl.GetHead().GetLabel()) { + idSelected = id; + } + + name.Replace(_T("&"), _T("&&")); + VERIFY(m_BDPlaylistMenu.AppendMenu(flags, id++, name + '\t' + time)); + } + menuEndRadioSection(m_BDPlaylistMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_BD_PLAYLISTS), m_BDPlaylistMenu); + } + + //SetupChapters(); + if (m_pCB && m_pCB->ChapGetCount() > 1) { + REFERENCE_TIME rt = GetPos(); + DWORD j = m_pCB->ChapLookup(&rt, nullptr); + menuStartRadioSection(); + for (DWORD i = 0; i < m_pCB->ChapGetCount(); i++, id++) { + rt = 0; + CComBSTR bstr; + if (FAILED(m_pCB->ChapGet(i, &rt, &bstr))) { + continue; + } + + CString time = _T("[") + ReftimeToString2(rt) + _T("]"); + + CString name = CString(bstr); + name.Replace(_T("&"), _T("&&")); + name.Replace(_T("\t"), _T(" ")); + + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (i == j) { + idSelected = id; + } + + VERIFY(m_chaptersMenu.AppendMenu(flags, id, name + '\t' + time)); + } + menuEndRadioSection(m_chaptersMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHAPTERS), m_chaptersMenu); + } + + if (m_wndPlaylistBar.GetCount() > 1) { + menuStartRadioSection(); + POSITION pos = m_wndPlaylistBar.m_pl.GetHeadPosition(); + while (pos && id < ID_NAVIGATE_JUMPTO_SUBITEM_START + 128) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (pos == m_wndPlaylistBar.m_pl.GetPos()) { + idSelected = id; + } + CPlaylistItem& pli = m_wndPlaylistBar.m_pl.GetNext(pos); + CString name = pli.GetLabel(); + name.Replace(_T("&"), _T("&&")); + VERIFY(m_playlistMenu.AppendMenu(flags, id++, name)); + } + menuEndRadioSection(m_playlistMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_PLAYLIST), m_playlistMenu); + } + } else if (GetPlaybackMode() == PM_DVD) { + ULONG ulNumOfVolumes, ulVolume, ulNumOfTitles, ulNumOfChapters, ulUOPs; + DVD_DISC_SIDE Side; + DVD_PLAYBACK_LOCATION2 Location; + + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location)) + && SUCCEEDED(m_pDVDI->GetCurrentUOPS(&ulUOPs)) + && SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters)) + && SUCCEEDED(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles))) { + menuStartRadioSection(); + for (ULONG i = 1; i <= ulNumOfTitles; i++) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (i == Location.TitleNum) { + idSelected = id; + } + if (ulUOPs & UOP_FLAG_Play_Title) { + flags |= MF_GRAYED; + } + + CString str; + str.Format(IDS_AG_TITLE, i); + + VERIFY(m_titlesMenu.AppendMenu(flags, id++, str)); + } + menuEndRadioSection(m_titlesMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_TITLES), m_titlesMenu); + + menuStartRadioSection(); + for (ULONG i = 1; i <= ulNumOfChapters; i++) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (i == Location.ChapterNum) { + idSelected = id; + } + if (ulUOPs & UOP_FLAG_Play_Chapter) { + flags |= MF_GRAYED; + } + + CString str; + str.Format(IDS_AG_CHAPTER, i); + + VERIFY(m_chaptersMenu.AppendMenu(flags, id++, str)); + } + menuEndRadioSection(m_chaptersMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHAPTERS), m_chaptersMenu); + } + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + menuStartRadioSection(); + for (const auto& channel : s.m_DVBChannels) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + + if (channel.GetPrefNumber() == s.nDVBLastChannel) { + idSelected = id; + } + VERIFY(m_channelsMenu.AppendMenu(flags, ID_NAVIGATE_JUMPTO_SUBITEM_START + channel.GetPrefNumber(), channel.GetName())); + id++; + } + menuEndRadioSection(m_channelsMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHANNELS), m_channelsMenu); + } +} + +DWORD CMainFrame::SetupNavStreamSelectSubMenu(CMenu& subMenu, UINT id, DWORD dwSelGroup) +{ + bool bAddSeparator = false; + DWORD selected = -1; + bool streams_found = false; + + auto addStreamSelectFilter = [&](CComPtr pSS) { + DWORD cStreams; + if (!pSS || FAILED(pSS->Count(&cStreams))) { + return; + } + + bool bAdded = false; + for (DWORD i = 0; i < cStreams; i++) { + DWORD dwFlags, dwGroup; + CComHeapPtr pszName; + LCID lcid = 0; + if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + if (dwGroup != dwSelGroup) { + continue; + } + + CString name(pszName); + /* + CString lcname = CString(name).MakeLower(); + if (dwGroup == 2 && lcname.Find(_T(" off")) >= 0) { + name.LoadString(IDS_AG_DISABLED); + } + */ + if (dwGroup == 2 && lcid != 0 && name.Find(L'\t') < 0) { + CString lcidstr; + GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); + name.Append(_T("\t") + lcidstr); + } + + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (dwFlags) { + flags |= MF_CHECKED; + selected = id; + } + + if (bAddSeparator) { + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + bAddSeparator = false; + } + bAdded = true; + + name.Replace(_T("&"), _T("&&")); + VERIFY(subMenu.AppendMenu(flags, id++, name)); + } + + if (bAdded) { + bAddSeparator = true; + streams_found = true; + } + }; + + if (m_pSplitterSS) { + addStreamSelectFilter(m_pSplitterSS); + } + if (!streams_found && m_pOtherSS[0]) { + addStreamSelectFilter(m_pOtherSS[0]); + } + if (!streams_found && m_pOtherSS[1]) { + addStreamSelectFilter(m_pOtherSS[1]); + } + + return selected; +} + +void CMainFrame::OnNavStreamSelectSubMenu(UINT id, DWORD dwSelGroup) +{ + bool streams_found = false; + + auto processStreamSelectFilter = [&](CComPtr pSS) { + bool bSelected = false; + + DWORD cStreams; + if (SUCCEEDED(pSS->Count(&cStreams))) { + for (int i = 0, j = cStreams; i < j; i++) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + CComHeapPtr pszName; + + if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + if (dwGroup != dwSelGroup) { + continue; + } + + streams_found = true; + + if (id == 0) { + pSS->Enable(i, AMSTREAMSELECTENABLE_ENABLE); + bSelected = true; + break; + } + + id--; + } + } + + return bSelected; + }; + + if (m_pSplitterSS) { + if (processStreamSelectFilter(m_pSplitterSS)) return; + } + if (!streams_found && m_pOtherSS[0]) { + if (processStreamSelectFilter(m_pOtherSS[0])) return; + } + if (!streams_found && m_pOtherSS[1]) { + if (processStreamSelectFilter(m_pOtherSS[1])) return; + } +} + +void CMainFrame::OnStreamSelect(bool bForward, DWORD dwSelGroup) +{ + ASSERT(dwSelGroup == 1 || dwSelGroup == 2); + bool streams_found = false; + + auto processStreamSelectFilter = [&](CComPtr pSS) { + DWORD cStreams; + if (FAILED(pSS->Count(&cStreams))) { + return false; + } + + std::vector> streams; + size_t currentSel = SIZE_MAX; + for (DWORD i = 0; i < cStreams; i++) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + CComHeapPtr pszName; + + if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + if (dwGroup != dwSelGroup) { + continue; + } + + streams_found = true; + + if (dwFlags) { + currentSel = streams.size(); + } + streams.emplace_back(i, (int)streams.size(), lcid, CString(pszName)); + } + + size_t count = streams.size(); + if (count && currentSel != SIZE_MAX) { + size_t requested = (bForward ? currentSel + 1 : currentSel - 1) % count; + DWORD id; + int trackindex; + LCID lcid = 0; + CString name; + std::tie(id, trackindex, lcid, name) = streams.at(requested); + if (SUCCEEDED(pSS->Enable(id, AMSTREAMSELECTENABLE_ENABLE))) { + if (dwSelGroup == 1 || AfxGetAppSettings().fEnableSubtitles) { + m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(name, lcid, dwSelGroup)); + } + if (dwSelGroup == 1) { + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pSS->Info(id, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr))) { + UpdateSelectedAudioStreamInfo(trackindex, pmt, lcid); + DeleteMediaType(pmt); + } + } else { + if (lcid && AfxGetAppSettings().fEnableSubtitles) { + GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentSubLang); + } else { + currentSubLang.Empty(); + } + } + } + return true; + } + return false; + }; + + if (m_pSplitterSS) { + if (processStreamSelectFilter(m_pSplitterSS)) return; + } + if (!streams_found && m_pOtherSS[0]) { + if (processStreamSelectFilter(m_pOtherSS[0])) return; + } + if (!streams_found && m_pOtherSS[1]) { + if (processStreamSelectFilter(m_pOtherSS[1])) return; + } +} + +CString CMainFrame::GetStreamOSDString(CString name, LCID lcid, DWORD dwSelGroup) +{ + name.Replace(_T("\t"), _T(" - ")); + CString sLcid; + if (lcid && lcid != LCID(-1)) { + GetLocaleString(lcid, LOCALE_SENGLANGUAGE, sLcid); + } + if (!sLcid.IsEmpty() && CString(name).MakeLower().Find(CString(sLcid).MakeLower()) < 0) { + name += _T(" (") + sLcid + _T(")"); + } + CString strMessage; + if (dwSelGroup == 1) { + int n = 0; + if (name.Find(_T("A:")) == 0) { + n = 2; + } + strMessage.Format(IDS_AUDIO_STREAM, name.Mid(n).Trim().GetString()); + } else if (dwSelGroup == 2) { + int n = 0; + if (name.Find(_T("S:")) == 0) { + n = 2; + } + strMessage.Format(IDS_SUBTITLE_STREAM, name.Mid(n).Trim().GetString()); + } + return strMessage; +} + +void CMainFrame::SetupRecentFilesSubMenu() +{ + auto& s = AfxGetAppSettings(); + auto& MRU = s.MRU; + MRU.ReadMediaHistory(); + + if (MRU.listModifySequence == recentFilesMenuFromMRUSequence) { + return; + } + recentFilesMenuFromMRUSequence = MRU.listModifySequence; + + CMenu& subMenu = m_recentFilesMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (!s.fKeepHistory) { + return; + } + + if (MRU.GetSize() > 0) { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_RECENT_FILES_CLEAR, ResStr(IDS_RECENT_FILES_CLEAR))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + UINT id = ID_RECENT_FILE_START; + for (int i = 0; i < MRU.GetSize(); i++) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (!MRU[i].fns.IsEmpty() && !MRU[i].fns.GetHead().IsEmpty()) { + CString p = MRU[i].cue.IsEmpty() ? MRU[i].fns.GetHead() : MRU[i].cue; + if (s.bUseTitleInRecentFileList && !MRU[i].title.IsEmpty()) { + CString title(MRU[i].title); + if (title.GetLength() > 100) { + title = title.Left(40) + _T("~~~") + title.Right(57); + } + int targetlen = 150 - title.GetLength(); + if (PathUtils::IsURL(p)) { + if (title.Right(1) == L')') { + // probably already contains shorturl + p = title; + } else { + CString shorturl = ShortenURL(p, targetlen, true); + p.Format(_T("%s (%s)"), static_cast(title), static_cast(shorturl)); + } + } else { + CString fn = PathUtils::StripPathOrUrl(p); + if (fn.GetLength() > targetlen) { // If file name is too long, cut middle part. + int l = fn.GetLength(); + fn.Format(_T("%s~~~%s"), static_cast(fn.Left(l / 2 - 2 + (l % 2))), static_cast(fn.Right(l / 2 - 1))); + } + p.Format(_T("%s (%s)"), static_cast(title), static_cast(fn)); + } + } + else { + if (PathUtils::IsURL(p)) { + p = ShortenURL(p, 150); + } + if (p.GetLength() > 150) { + p.Format(_T("%s~~~%s"), static_cast(p.Left(60)), static_cast(p.Right(87))); + } + } + p.Replace(_T("&"), _T("&&")); + VERIFY(subMenu.AppendMenu(flags, id, p)); + } else { + ASSERT(false); + } + id++; + } + } +} + +void CMainFrame::SetupFavoritesSubMenu() +{ + CMenu& subMenu = m_favoritesMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + const CAppSettings& s = AfxGetAppSettings(); + + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_FAVORITES_ADD, ResStr(IDS_FAVORITES_ADD))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_FAVORITES_ORGANIZE, ResStr(IDS_FAVORITES_ORGANIZE))); + + UINT nLastGroupStart = subMenu.GetMenuItemCount(); + UINT id = ID_FAVORITES_FILE_START; + CAtlList favs; + AfxGetAppSettings().GetFav(FAV_FILE, favs); + POSITION pos = favs.GetHeadPosition(); + + while (pos) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + + CString f_str = favs.GetNext(pos); + f_str.Replace(_T("&"), _T("&&")); + f_str.Replace(_T("\t"), _T(" ")); + + FileFavorite ff; + VERIFY(FileFavorite::TryParse(f_str, ff)); + + f_str = ff.Name; + + CString str = ff.ToString(); + if (!str.IsEmpty()) { + f_str.AppendFormat(_T("\t%s"), str.GetString()); + } + + if (!f_str.IsEmpty()) { + VERIFY(subMenu.AppendMenu(flags, id, f_str)); + } + + id++; + if (id > ID_FAVORITES_FILE_END) { + break; + } + } + + if (id > ID_FAVORITES_FILE_START) { + VERIFY(subMenu.InsertMenu(nLastGroupStart, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); + } + + nLastGroupStart = subMenu.GetMenuItemCount(); + + id = ID_FAVORITES_DVD_START; + s.GetFav(FAV_DVD, favs); + pos = favs.GetHeadPosition(); + + while (pos) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + + CString str = favs.GetNext(pos); + str.Replace(_T("&"), _T("&&")); + + CAtlList sl; + ExplodeEsc(str, sl, _T(';'), 2); + + str = sl.RemoveHead(); + + if (!sl.IsEmpty()) { + // TODO + } + + if (!str.IsEmpty()) { + VERIFY(subMenu.AppendMenu(flags, id, str)); + } + + id++; + if (id > ID_FAVORITES_DVD_END) { + break; + } + } + + if (id > ID_FAVORITES_DVD_START) { + VERIFY(subMenu.InsertMenu(nLastGroupStart, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); + } + + nLastGroupStart = subMenu.GetMenuItemCount(); + + id = ID_FAVORITES_DEVICE_START; + + s.GetFav(FAV_DEVICE, favs); + + pos = favs.GetHeadPosition(); + while (pos) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + + CString str = favs.GetNext(pos); + str.Replace(_T("&"), _T("&&")); + + CAtlList sl; + ExplodeEsc(str, sl, _T(';'), 2); + + str = sl.RemoveHead(); + + if (!str.IsEmpty()) { + VERIFY(subMenu.AppendMenu(flags, id, str)); + } + + id++; + if (id > ID_FAVORITES_DEVICE_END) { + break; + } + } +} + +bool CMainFrame::SetupShadersSubMenu() +{ + const auto& s = AfxGetAppSettings(); + + CMenu& subMenu = m_shadersMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (!(s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS || s.iDSVideoRendererType == VIDRNDT_DS_MADVR || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR)) { + return false; + } + + subMenu.AppendMenu(MF_BYCOMMAND | MF_STRING | MF_ENABLED, ID_PRESIZE_SHADERS_TOGGLE, ResStr(IDS_PRESIZE_SHADERS_TOGGLE)); + subMenu.AppendMenu(MF_BYCOMMAND | MF_STRING | MF_ENABLED, ID_POSTSIZE_SHADERS_TOGGLE, ResStr(IDS_POSTSIZE_SHADERS_TOGGLE)); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_SHADERS_SELECT, ResStr(IDS_SHADERS_SELECT))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_VIEW_DEBUGSHADERS, ResStr(IDS_SHADERS_DEBUG))); + + auto presets = s.m_Shaders.GetPresets(); + if (!presets.empty()) { + CString current; + bool selected = s.m_Shaders.GetCurrentPresetName(current); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + UINT nID = ID_SHADERS_PRESETS_START; + for (const auto& pair : presets) { + if (nID > ID_SHADERS_PRESETS_END) { + // too many presets + ASSERT(FALSE); + break; + } + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, nID, pair.first)); + if (selected && pair.first == current) { + VERIFY(subMenu.CheckMenuRadioItem(nID, nID, nID, MF_BYCOMMAND)); + selected = false; + } + nID++; + } + } + return true; +} + +///////////// + +void CMainFrame::SetAlwaysOnTop(int iOnTop) +{ + CAppSettings& s = AfxGetAppSettings(); + + if (!IsFullScreenMode()) { + const CWnd* pInsertAfter = nullptr; + + if (iOnTop == 0) { + // We only want to disable "On Top" once so that + // we don't interfere with other window manager + if (s.iOnTop || !alwaysOnTopZOrderInitialized) { + pInsertAfter = &wndNoTopMost; + alwaysOnTopZOrderInitialized = true; + } + } else if (iOnTop == 1) { + pInsertAfter = &wndTopMost; + } else if (iOnTop == 2) { + pInsertAfter = (GetMediaState() == State_Running) ? &wndTopMost : &wndNoTopMost; + } else { // if (iOnTop == 3) + pInsertAfter = (GetMediaState() == State_Running && !m_fAudioOnly) ? &wndTopMost : &wndNoTopMost; + } + + if (pInsertAfter) { + SetWindowPos(pInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + + s.iOnTop = iOnTop; +} + +bool CMainFrame::WindowExpectedOnTop() { + return (AfxGetAppSettings().iOnTop == 1 || + (AfxGetAppSettings().iOnTop == 2 && GetMediaState() == State_Running) || + (AfxGetAppSettings().iOnTop == 3 && GetMediaState() == State_Running && !m_fAudioOnly)); +} + +void CMainFrame::AddTextPassThruFilter() +{ + BeginEnumFilters(m_pGB, pEF, pBF) { + if (!IsSplitter(pBF)) { + continue; + } + + BeginEnumPins(pBF, pEP, pPin) { + CComPtr pPinTo; + AM_MEDIA_TYPE mt; + if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo + && SUCCEEDED(pPin->ConnectionMediaType(&mt)) + && (mt.majortype == MEDIATYPE_Text || mt.majortype == MEDIATYPE_Subtitle)) { + InsertTextPassThruFilter(pBF, pPin, pPinTo); + } + } + EndEnumPins; + } + EndEnumFilters; +} + +HRESULT CMainFrame::InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinTo) +{ + HRESULT hr; + CComQIPtr pTPTF = DEBUG_NEW CTextPassThruFilter(this); + CStringW name; + name.Format(L"TextPassThru%p", static_cast(pTPTF)); + if (FAILED(hr = m_pGB->AddFilter(pTPTF, name))) { + return hr; + } + + OAFilterState fs = GetMediaState(); + if (fs == State_Running || fs == State_Paused) { + MediaControlStop(true); + } + + hr = pPinTo->Disconnect(); + hr = pPin->Disconnect(); + + if (FAILED(hr = m_pGB->ConnectDirect(pPin, GetFirstPin(pTPTF, PINDIR_INPUT), nullptr)) + || FAILED(hr = m_pGB->ConnectDirect(GetFirstPin(pTPTF, PINDIR_OUTPUT), pPinTo, nullptr))) { + hr = m_pGB->ConnectDirect(pPin, pPinTo, nullptr); + } else { + SubtitleInput subInput(CComQIPtr(pTPTF), pBF); + m_pSubStreams.AddTail(subInput); + } + + if (fs == State_Running) { + MediaControlRun(); + } else if (fs == State_Paused) { + MediaControlPause(); + } + + return hr; +} + +bool CMainFrame::LoadSubtitle(CString fn, SubtitleInput* pSubInput /*= nullptr*/, bool bAutoLoad /*= false*/) +{ + CAppSettings& s = AfxGetAppSettings(); + CComQIPtr pSubStream; + + if (!s.IsISRAutoLoadEnabled() && (FindFilter(CLSID_VSFilter, m_pGB) || FindFilter(CLSID_XySubFilter, m_pGB))) { + // Prevent ISR from loading if VSFilter is already in graph. + // TODO: Support VSFilter natively (see ticket #4122) + // Note that this doesn't affect ISR auto-loading if any sub renderer force loading itself into the graph. + // VSFilter like filters can be blocked when building the graph and ISR auto-loading is enabled but some + // users don't want that. + return false; + } + + if (GetPlaybackMode() == PM_FILE && !s.fDisableInternalSubtitles && !FindFilter(__uuidof(CTextPassThruFilter), m_pGB)) { + // Add TextPassThru filter if it isn't already in the graph. (i.e ISR hasn't been loaded before) + // This will load all embedded subtitle tracks when user triggers ISR (load external subtitle file) for the first time. + AddTextPassThruFilter(); + } + + CString videoName; + if (GetPlaybackMode() == PM_FILE) { + videoName = m_wndPlaylistBar.GetCurFileName(); + } + + CString ext = CPath(fn).GetExtension().MakeLower(); + + if (!pSubStream && (ext == _T(".idx") || !bAutoLoad && ext == _T(".sub"))) { + CAutoPtr pVSF(DEBUG_NEW CVobSubFile(&m_csSubLock)); + if (pVSF && pVSF->Open(fn) && pVSF->GetStreamCount() > 0) { + pSubStream = pVSF.Detach(); + } + } + + if (!pSubStream && ext != _T(".idx") && ext != _T(".sup")) { + CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); + if (pRTS) { + if (pRTS->Open(fn, DEFAULT_CHARSET, _T(""), videoName) && pRTS->GetStreamCount() > 0) { +#if USE_LIBASS + if (pRTS->m_LibassContext.IsLibassActive()) { + pRTS->m_LibassContext.SetFilterGraph(m_pGB); + } +#endif + pSubStream = pRTS.Detach(); + } + } + } + + if (!pSubStream) { + CAutoPtr pPSF(DEBUG_NEW CPGSSubFile(&m_csSubLock)); + if (pPSF && pPSF->Open(fn, _T(""), videoName) && pPSF->GetStreamCount() > 0) { + pSubStream = pPSF.Detach(); + } + } + + if (pSubStream) { + SubtitleInput subInput(pSubStream); + m_ExternalSubstreams.push_back(pSubStream); + m_pSubStreams.AddTail(subInput); + + // Temporarily load fonts from 'Fonts' folder - Begin + CString path = PathUtils::DirName(fn) + L"\\fonts\\"; + ExtendMaxPathLengthIfNeeded(path); + + if (::PathIsDirectory(path)) { + WIN32_FIND_DATA fd = {0}; + HANDLE hFind; + + hFind = FindFirstFile(path + L"*.?t?", &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + CStringW ext = GetFileExt(fd.cFileName); + if (ext == ".ttf" || ext == ".otf" || ext == ".ttc") { + m_FontInstaller.InstallTempFontFile(path + fd.cFileName); + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + } + // Temporarily load fonts from 'Fonts' folder - End + + if (!m_posFirstExtSub) { + m_posFirstExtSub = m_pSubStreams.GetTailPosition(); + } + + if (pSubInput) { + *pSubInput = subInput; + } + + if (!bAutoLoad) { + m_wndPlaylistBar.AddSubtitleToCurrent(fn); + if (s.fKeepHistory) { + s.MRU.AddSubToCurrent(fn); + } + } + } + + return !!pSubStream; +} + +bool CMainFrame::LoadSubtitle(CYoutubeDLInstance::YDLSubInfo& sub) { + CAppSettings& s = AfxGetAppSettings(); + CComQIPtr pSubStream; + CAtlList preferlist; + if (!s.sYDLSubsPreference.IsEmpty()) { + if (s.sYDLSubsPreference.Find(_T(',')) != -1) { + ExplodeMin(s.sYDLSubsPreference, preferlist, ','); + } else { + ExplodeMin(s.sYDLSubsPreference, preferlist, ' '); + } + } + if (!preferlist.IsEmpty() && !CYoutubeDLInstance::isPrefer(preferlist, sub.lang)) { + return false; + } + + if (!s.IsISRAutoLoadEnabled() && (FindFilter(CLSID_VSFilter, m_pGB) || FindFilter(CLSID_XySubFilter, m_pGB))) { + // Prevent ISR from loading if VSFilter is already in graph. + // TODO: Support VSFilter natively (see ticket #4122) + // Note that this doesn't affect ISR auto-loading if any sub renderer force loading itself into the graph. + // VSFilter like filters can be blocked when building the graph and ISR auto-loading is enabled but some + // users don't want that. + return false; + } + + if (GetPlaybackMode() == PM_FILE && !s.fDisableInternalSubtitles && !FindFilter(__uuidof(CTextPassThruFilter), m_pGB)) { + // Add TextPassThru filter if it isn't already in the graph. (i.e ISR hasn't been loaded before) + // This will load all embedded subtitle tracks when user triggers ISR (load external subtitle file) for the first time. + AddTextPassThruFilter(); + } + + CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); + if (pRTS) { + bool opened = false; + if (!sub.url.IsEmpty()) { + SubtitlesProvidersUtils::stringMap strmap{}; + DWORD dwStatusCode; + CT2CA tem(sub.url); + std::string tem2(tem); + std::string data(""); + SubtitlesProvidersUtils::StringDownload(tem2, strmap, data, true, &dwStatusCode); + if (dwStatusCode != 200) { + return false; + } + if (sub.ext.IsEmpty()) { + int m2(sub.url.ReverseFind(_T('?'))); + int m3(sub.url.ReverseFind(_T('#'))); + int m = -1; + if (m2 > -1 && m3 > -1) m = std::min(m2, m3); + else if (m2 > -1) m = m2; + else if (m3 > -1) m = m3; + CString temp(sub.url); + if (m > 0) temp = sub.url.Left(m); + m = temp.ReverseFind(_T('.')); + if (m >= 0) sub.ext = temp.Mid(m + 1); + } + CString langt = sub.isAutomaticCaptions ? sub.lang + _T("[Automatic]") : sub.lang; + opened = pRTS->Open((BYTE*)data.c_str(), (int)data.length(), DEFAULT_CHARSET, _T("YoutubeDL"), langt, sub.ext); + } else if (!sub.data.IsEmpty()) { + CString langt = sub.isAutomaticCaptions ? sub.lang + _T("[Automatic]") : sub.lang; + opened = pRTS->Open(sub.data, CTextFile::enc::UTF8, DEFAULT_CHARSET, _T("YoutubeDL"), langt, sub.ext); // Do not modify charset, Now it wroks with Unicode char. + } + if (opened && pRTS->GetStreamCount() > 0) { +#if USE_LIBASS + if (pRTS->m_LibassContext.IsLibassActive()) { + pRTS->m_LibassContext.SetFilterGraph(m_pGB); + } +#endif + pSubStream = pRTS.Detach(); + } + } + + if (pSubStream) { + SubtitleInput subInput(pSubStream); + m_ExternalSubstreams.push_back(pSubStream); + m_pSubStreams.AddTail(subInput); + + if (!m_posFirstExtSub) { + m_posFirstExtSub = m_pSubStreams.GetTailPosition(); + } + } + + return !!pSubStream; +} + +// Called from GraphThread +bool CMainFrame::SetSubtitle(int i, bool bIsOffset /*= false*/, bool bDisplayMessage /*= false*/) +{ + if (!m_pCAP) { + return false; + } + if (GetLoadState() == MLS::CLOSING) { + return false; + } + + CAppSettings& s = AfxGetAppSettings(); + + SubtitleInput* pSubInput = nullptr; + if (m_iReloadSubIdx >= 0) { + pSubInput = GetSubtitleInput(m_iReloadSubIdx); + if (pSubInput) { + i = m_iReloadSubIdx; + } + m_iReloadSubIdx = -1; + } + + if (!pSubInput) { + pSubInput = GetSubtitleInput(i, bIsOffset); + } + + bool success = false; + + if (pSubInput) { + CComHeapPtr pName; + if (CComQIPtr pSSF = pSubInput->pSourceFilter) { + DWORD dwFlags; + LCID lcid = 0; + if (FAILED(pSSF->Info(i, nullptr, &dwFlags, &lcid, nullptr, &pName, nullptr, nullptr))) { + dwFlags = 0; + } + if (lcid && s.fEnableSubtitles) { + currentSubLang = ISOLang::GetLocaleStringCompat(lcid); + } else { + currentSubLang.Empty(); + } + + // Enable the track only if it isn't already the only selected track in the group + if (!(dwFlags & AMSTREAMSELECTINFO_EXCLUSIVE)) { + pSSF->Enable(i, AMSTREAMSELECTENABLE_ENABLE); + } + i = 0; + } + { + // m_csSubLock shouldn't be locked when using IAMStreamSelect::Enable or SetSubtitle + CAutoLock cAutoLock(&m_csSubLock); + pSubInput->pSubStream->SetStream(i); + } + SetSubtitle(*pSubInput, true); + + if (!pName) { + LCID lcid = 0; + pSubInput->pSubStream->GetStreamInfo(0, &pName, &lcid); + if (lcid && s.fEnableSubtitles) { + currentSubLang = ISOLang::GetLocaleStringCompat(lcid); + } else { + currentSubLang.Empty(); + } + } + + if (bDisplayMessage && pName) { + m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pName), LCID(-1), 2)); + } + success = true; + } + + if (success && s.fKeepHistory && s.bRememberTrackSelection) { + s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); + } + return success; +} + +void CMainFrame::UpdateSubtitleColorInfo() +{ + if (!m_pCAP || !m_pCurrentSubInput.pSubStream) { + return; + } + + // store video mediatype, so colorspace information can be extracted when present + // FIXME: mediatype extended colorinfo may be absent on initial connection, call this again after first frame has been decoded? + CComQIPtr pBF = m_pCAP; + CComPtr pPin = GetFirstPin(pBF); + if (pPin) { + AM_MEDIA_TYPE mt; + if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + m_pCAP->SetVideoMediaType(CMediaType(mt)); + } + } + + CComQIPtr pSRO = m_pCAP; + + LPWSTR yuvMatrix = nullptr; + int nLen; + if (m_pMVRI) { + m_pMVRI->GetString("yuvMatrix", &yuvMatrix, &nLen); + } else if (pSRO) { + pSRO->GetString("yuvMatrix", &yuvMatrix, &nLen); + } + + int targetBlackLevel = 0, targetWhiteLevel = 255; + if (m_pMVRS) { + m_pMVRS->SettingsGetInteger(L"Black", &targetBlackLevel); + m_pMVRS->SettingsGetInteger(L"White", &targetWhiteLevel); + } else if (pSRO) { + int range = 0; + pSRO->GetInt("supportedLevels", &range); + if (range == 3) { + targetBlackLevel = 16; + targetWhiteLevel = 235; + } + } + + m_pCurrentSubInput.pSubStream->SetSourceTargetInfo(yuvMatrix, targetBlackLevel, targetWhiteLevel); + LocalFree(yuvMatrix); +} + +void CMainFrame::SetSubtitle(const SubtitleInput& subInput, bool skip_lcid /* = false */) +{ + TRACE(_T("CMainFrame::SetSubtitle\n")); + + CAppSettings& s = AfxGetAppSettings(); + ResetSubtitlePosAndSize(false); + + { + CAutoLock cAutoLock(&m_csSubLock); + + bool firstuse = !m_pCurrentSubInput.pSubStream; + + if (subInput.pSubStream) { + bool found = false; + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + if (subInput.pSubStream == m_pSubStreams.GetNext(pos).pSubStream) { + found = true; + break; + } + } + // We are trying to set a subtitles stream that isn't in the list so we abort here. + if (!found) { + return; + } + } + + if (m_pCAP && m_pCurrentSubInput.pSubStream && m_pCurrentSubInput.pSubStream != subInput.pSubStream) { + m_pCAP->SetSubPicProvider(nullptr); + } + + m_pCurrentSubInput = subInput; + + UpdateSubtitleRenderingParameters(); + + if (firstuse) { + // note: can deadlock when calling ConnectionMediaType() with MPCVR when SubPicProvider!=nullptr + UpdateSubtitleColorInfo(); + } + + if (!skip_lcid) { + LCID lcid = 0; + if (m_pCurrentSubInput.pSubStream && s.fEnableSubtitles) { + CComHeapPtr pName; + m_pCurrentSubInput.pSubStream->GetStreamInfo(0, &pName, &lcid); + } + if (lcid) { + GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentSubLang); + } else { + currentSubLang.Empty(); + } + } + + if (m_pCAP) { + g_bExternalSubtitle = (std::find(m_ExternalSubstreams.cbegin(), m_ExternalSubstreams.cend(), subInput.pSubStream) != m_ExternalSubstreams.cend()); + bool use_subresync = false; + if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { +#if USE_LIBASS + if (!pRTS->m_LibassContext.IsLibassActive()) +#endif + use_subresync = true; + } + if (use_subresync) { + m_wndSubresyncBar.SetSubtitle(subInput.pSubStream, m_pCAP->GetFPS(), g_bExternalSubtitle); + } else { + m_wndSubresyncBar.SetSubtitle(nullptr, m_pCAP->GetFPS(), g_bExternalSubtitle); + } + } + } + + if (m_pCAP && s.fEnableSubtitles) { + m_pCAP->SetSubPicProvider(CComQIPtr(subInput.pSubStream)); + } + + if (s.fKeepHistory && s.bRememberTrackSelection) { + s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); + } +} + +void CMainFrame::OnAudioShiftOnOff() +{ + AfxGetAppSettings().fAudioTimeShift = !AfxGetAppSettings().fAudioTimeShift; +} + +void CMainFrame::ToggleSubtitleOnOff(bool bDisplayMessage /*= false*/) +{ + if (m_pDVS) { + bool bHideSubtitles = false; + m_pDVS->get_HideSubtitles(&bHideSubtitles); + bHideSubtitles = !bHideSubtitles; + m_pDVS->put_HideSubtitles(bHideSubtitles); + } + if (m_pCAP && (!m_pDVS || !m_pSubStreams.IsEmpty())) { + CAppSettings& s = AfxGetAppSettings(); + s.fEnableSubtitles = !s.fEnableSubtitles; + + if (s.fEnableSubtitles) { + SetSubtitle(0, true, bDisplayMessage); + } else { + if (m_pCAP) { + m_pCAP->SetSubPicProvider(nullptr); + } + currentSubLang = ResStr(IDS_AG_DISABLED); + + if (bDisplayMessage) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_SUBTITLE_STREAM_OFF)); + } + } + } +} + +void CMainFrame::ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew) +{ + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + POSITION cur = pos; + if (pSubStreamOld == m_pSubStreams.GetNext(pos).pSubStream) { + m_pSubStreams.GetAt(cur).pSubStream = pSubStreamNew; + if (m_pCurrentSubInput.pSubStream == pSubStreamOld) { + SetSubtitle(m_pSubStreams.GetAt(cur), true); + } + break; + } + } +} + +void CMainFrame::InvalidateSubtitle(DWORD_PTR nSubtitleId /*= DWORD_PTR_MAX*/, REFERENCE_TIME rtInvalidate /*= -1*/) +{ + if (m_pCAP) { + if (nSubtitleId == DWORD_PTR_MAX || nSubtitleId == (DWORD_PTR)(ISubStream*)m_pCurrentSubInput.pSubStream) { + m_pCAP->Invalidate(rtInvalidate); + } + } +} + +void CMainFrame::ReloadSubtitle() +{ + { + CAutoLock cAutoLock(&m_csSubLock); + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + m_pSubStreams.GetNext(pos).pSubStream->Reload(); + } + } + + ResetSubtitlePosAndSize(false); + + SetSubtitle(0, true); + m_wndSubresyncBar.ReloadSubtitle(); +} + +void CMainFrame::SetSubtitleTrackIdx(int index) +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (GetLoadState() == MLS::LOADED && m_pCAP) { + // Check if we want to change the enable/disable state + if (s.fEnableSubtitles != (index >= 0)) { + ToggleSubtitleOnOff(); + } + // Set the new subtitles track if needed + if (s.fEnableSubtitles) { + SetSubtitle(index); + } + } +} + +void CMainFrame::SetAudioTrackIdx(int index) +{ + if (GetLoadState() == MLS::LOADED) { + DWORD cStreams = 0; + DWORD dwFlags = AMSTREAMSELECTENABLE_ENABLE; + if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { + if ((index >= 0) && (index < ((int)cStreams))) { + m_pAudioSwitcherSS->Enable(index, dwFlags); + + m_loadedAudioTrackIndex = index; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + CComHeapPtr pszName; + if (SUCCEEDED(m_pAudioSwitcherSS->Info(index, &pmt, &dwFlags, &lcid, nullptr, &pszName, nullptr, nullptr))) { + m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pszName), lcid, 1)); + UpdateSelectedAudioStreamInfo(index, pmt, lcid); + DeleteMediaType(pmt); + } + } + } + // ToDo: use m_pSplitterSS + } +} + +int CMainFrame::GetCurrentAudioTrackIdx(CString *pstrName) +{ + if(pstrName) + pstrName->Empty(); + + if (GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_FILE && m_pGB) { + DWORD cStreams = 0; + if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { + for (int i = 0; i < (int)cStreams; i++) { + DWORD dwFlags = 0; + CComHeapPtr pName; + if (SUCCEEDED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, nullptr, &pName, nullptr, nullptr))) { + if (dwFlags & AMSTREAMSELECTINFO_ENABLED) { + if(pstrName) + *pstrName = pName; + ASSERT(m_loadedAudioTrackIndex == i); + return i; + } + } else { + break; + } + } + } + // ToDo: use m_pSplitterSS + } + return -1; +} + +int CMainFrame::GetCurrentSubtitleTrackIdx(CString *pstrName) +{ + if(pstrName) + pstrName->Empty(); + + if (GetLoadState() != MLS::LOADED) { + return -1; + } + + if (m_pCAP && !m_pSubStreams.IsEmpty()) { + int idx = 0; + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + if (CComQIPtr pSSF = subInput.pSourceFilter) { + DWORD cStreams; + if (FAILED(pSSF->Count(&cStreams))) { + continue; + } + for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { + DWORD dwFlags, dwGroup; + CComHeapPtr pName; + if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, &pName, nullptr, nullptr))) { + continue; + } + if (dwGroup != 2) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + if (pstrName) + *pstrName = pName; + return idx; + } + } + idx++; + } + } else { + CComPtr pSubStream = subInput.pSubStream; + if (!pSubStream) { + continue; + } + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + if (pstrName) { + CComHeapPtr pName; + pSubStream->GetStreamInfo(pSubStream->GetStream(), &pName, nullptr); + *pstrName = pName; + } + return idx + pSubStream->GetStream(); + } + idx += pSubStream->GetStreamCount(); + } + } + } else if (m_pSplitterSS) { + DWORD cStreams; + if (SUCCEEDED(m_pSplitterSS->Count(&cStreams))) { + int idx = 0; + for (int i = 0; i < (int)cStreams; i++) { + DWORD dwFlags, dwGroup; + CComHeapPtr pszName; + + if (FAILED(m_pSplitterSS->Info(i, nullptr, &dwFlags, nullptr, &dwGroup, &pszName, nullptr, nullptr))) + continue; + + if (dwGroup != 2) + continue; + + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + if (pstrName) + *pstrName = pszName; + return idx; + } + + idx++; + } + } + } + + return -1; +} + +REFERENCE_TIME CMainFrame::GetPos() const +{ + return (GetLoadState() == MLS::LOADED ? m_wndSeekBar.GetPos() : 0); +} + +REFERENCE_TIME CMainFrame::GetDur() const +{ + __int64 start, stop; + m_wndSeekBar.GetRange(start, stop); + return (GetLoadState() == MLS::LOADED ? stop : 0); +} + +void CMainFrame::LoadKeyFrames() +{ + UINT nKFs = 0; + m_kfs.clear(); + if (m_pKFI && S_OK == m_pKFI->GetKeyFrameCount(nKFs) && nKFs > 1) { + UINT k = nKFs; + m_kfs.resize(k); + if (FAILED(m_pKFI->GetKeyFrames(&TIME_FORMAT_MEDIA_TIME, m_kfs.data(), k)) || k != nKFs) { + m_kfs.clear(); + } + } +} + +bool CMainFrame::GetKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMin, REFERENCE_TIME rtMax, bool nearest, REFERENCE_TIME& keyframetime) const +{ + ASSERT(rtTarget >= rtMin); + ASSERT(rtTarget <= rtMax); + if (!m_kfs.empty()) { + const auto cbegin = m_kfs.cbegin(); + const auto cend = m_kfs.cend(); + ASSERT(std::is_sorted(cbegin, cend)); + + auto foundkeyframe = std::lower_bound(cbegin, cend, rtTarget); + + if (foundkeyframe == cbegin) { + // first keyframe + keyframetime = *foundkeyframe; + if ((keyframetime < rtMin) || (keyframetime > rtMax)) { + keyframetime = rtTarget; + return false; + } + } else if (foundkeyframe == cend) { + // last keyframe + keyframetime = *(--foundkeyframe); + if (keyframetime < rtMin) { + keyframetime = rtTarget; + return false; + } + } else { + keyframetime = *foundkeyframe; + if (keyframetime == rtTarget) { + return true; + } + if (keyframetime > rtMax) { + // use preceding keyframe + keyframetime = *(--foundkeyframe); + if (keyframetime < rtMin) { + keyframetime = rtTarget; + return false; + } + } else { + if (nearest) { + const auto& s = AfxGetAppSettings(); + if (s.eFastSeekMethod == s.FASTSEEK_NEAREST_KEYFRAME) { + // use closest keyframe + REFERENCE_TIME prev_keyframetime = *(--foundkeyframe); + if ((prev_keyframetime >= rtMin)) { + if ((keyframetime - rtTarget) > (rtTarget - prev_keyframetime)) { + keyframetime = prev_keyframetime; + } + } + } + } + } + } + return true; + } else { + keyframetime = rtTarget; + } + return false; +} + +REFERENCE_TIME CMainFrame::GetClosestKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMaxForwardDiff, REFERENCE_TIME rtMaxBackwardDiff) const +{ + if (rtTarget < 0LL) return 0LL; + if (rtTarget > GetDur()) return rtTarget; + + REFERENCE_TIME rtKeyframe; + REFERENCE_TIME rtMin = std::max(rtTarget - rtMaxBackwardDiff, 0LL); + REFERENCE_TIME rtMax = rtTarget + rtMaxForwardDiff; + + if (GetKeyFrame(rtTarget, rtMin, rtMax, true, rtKeyframe)) { + return rtKeyframe; + } + return rtTarget; +} + +REFERENCE_TIME CMainFrame::GetClosestKeyFramePreview(REFERENCE_TIME rtTarget) const +{ + return GetClosestKeyFrame(rtTarget, 200000000LL, 200000000LL); +} + +void CMainFrame::SeekTo(REFERENCE_TIME rtPos, bool bShowOSD /*= true*/) +{ + if (m_pMS == nullptr) { + return; + } + ASSERT(lastSeekFinish >= lastSeekStart); // ToDo: remove lastSeekStart variable if no regressions show up + ULONGLONG curTime = GetTickCount64(); + ULONGLONG ticksSinceLastSeek = curTime - lastSeekFinish; + ULONGLONG mindelay = (lastSeekFinish - lastSeekStart) > 40ULL ? 100ULL : 40ULL; + //ASSERT(rtPos != queuedSeek.rtPos || queuedSeek.seekTime == 0 || (curTime < queuedSeek.seekTime + 500ULL)); + + if (ticksSinceLastSeek < mindelay) { + //TRACE(_T("Delay seek: %lu %lu\n"), rtPos, ticksSinceLastSeek); + queuedSeek = { rtPos, curTime, bShowOSD }; + SetTimer(TIMER_DELAYEDSEEK, (UINT) (mindelay * 1.25 - ticksSinceLastSeek), nullptr); + } else { + KillTimerDelayedSeek(); + lastSeekStart = curTime; + DoSeekTo(rtPos, bShowOSD); + lastSeekFinish = GetTickCount64(); + } +} + +void CMainFrame::DoSeekTo(REFERENCE_TIME rtPos, bool bShowOSD /*= true*/) +{ + //TRACE(_T("DoSeekTo: %lu\n"), rtPos); + + ASSERT(m_pMS != nullptr); + if (m_pMS == nullptr) { + return; + } + OAFilterState fs = GetMediaState(); + + if (rtPos < 0) { + rtPos = 0; + } + + if (abRepeat.positionA && rtPos < abRepeat.positionA || abRepeat.positionB && rtPos > abRepeat.positionB) { + DisableABRepeat(); + } + + if (m_fFrameSteppingActive) { + // Cancel pending frame steps + m_pFS->CancelStep(); + m_fFrameSteppingActive = false; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } + m_nStepForwardCount = 0; + + // skip seeks when duration is unknown + if (!m_wndSeekBar.HasDuration()) { + return; + } + + if (!IsPlaybackCaptureMode()) { + __int64 start, stop; + m_wndSeekBar.GetRange(start, stop); + if (rtPos > stop) { + rtPos = stop; + } + m_wndStatusBar.SetStatusTimer(rtPos, stop, IsSubresyncBarVisible(), GetTimeFormat()); + + if (bShowOSD) { + m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 1500); + } + } + + if (GetPlaybackMode() == PM_FILE) { + if (fs == State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + + //SleepEx(5000, False); // artificial slow seek for testing purposes + if (FAILED(m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning))) { + TRACE(_T("IMediaSeeking SetPositions failure\n")); + if (abRepeat.positionA && rtPos == abRepeat.positionA) { + DisableABRepeat(); + } + } + UpdateChapterInInfoBar(); + } else if (GetPlaybackMode() == PM_DVD && m_iDVDDomain == DVD_DOMAIN_Title) { + if (fs == State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + fs = State_Paused; + } + + const REFTIME refAvgTimePerFrame = GetAvgTimePerFrame(); + if (fs == State_Paused) { + // Jump one more frame back, this is needed because we don't have any other + // way to seek to specific time without running playback to refresh state. + rtPos -= std::llround(refAvgTimePerFrame * 10000000i64); + m_pFS->CancelStep(); + } + + DVD_HMSF_TIMECODE tc = RT2HMSF(rtPos, (1.0 / refAvgTimePerFrame)); + m_pDVDC->PlayAtTime(&tc, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + + if (fs == State_Paused) { + // Do frame step to update current position in paused state + m_pFS->Step(1, nullptr); + } + } else { + ASSERT(FALSE); + } + m_fEndOfStream = false; + + OnTimer(TIMER_STREAMPOSPOLLER); + OnTimer(TIMER_STREAMPOSPOLLER2); + + SendCurrentPositionToApi(true); +} + +void CMainFrame::CleanGraph() +{ + if (!m_pGB) { + return; + } + + BeginEnumFilters(m_pGB, pEF, pBF) { + CComQIPtr pAMMF(pBF); + if (pAMMF && (pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE)) { + continue; + } + + // some capture filters forget to set AM_FILTER_MISC_FLAGS_IS_SOURCE + // or to implement the IAMFilterMiscFlags interface + if (pBF == m_pVidCap || pBF == m_pAudCap) { + continue; + } + + // XySubFilter doesn't have any pins connected when it is reading + // external subtitles + if (GetCLSID(pBF) == CLSID_XySubFilter) { + continue; + } + + if (CComQIPtr(pBF)) { + continue; + } + + int nIn, nOut, nInC, nOutC; + if (CountPins(pBF, nIn, nOut, nInC, nOutC) > 0 && (nInC + nOutC) == 0) { + TRACE(CStringW(L"Removing: ") + GetFilterName(pBF) + '\n'); + + m_pGB->RemoveFilter(pBF); + pEF->Reset(); + } + } + EndEnumFilters; +} + +#define AUDIOBUFFERLEN 500 + +static void SetLatency(IBaseFilter* pBF, int cbBuffer) +{ + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pAMBN = pPin) { + ALLOCATOR_PROPERTIES ap; + ap.cbAlign = -1; // -1 means no preference. + ap.cbBuffer = cbBuffer; + ap.cbPrefix = -1; + ap.cBuffers = -1; + pAMBN->SuggestAllocatorProperties(&ap); + } + } + EndEnumPins; +} + +HRESULT CMainFrame::BuildCapture(IPin* pPin, IBaseFilter* pBF[3], const GUID& majortype, AM_MEDIA_TYPE* pmt) +{ + IBaseFilter* pBuff = pBF[0]; + IBaseFilter* pEnc = pBF[1]; + IBaseFilter* pMux = pBF[2]; + + if (!pPin || !pMux) { + return E_FAIL; + } + + CString err; + HRESULT hr = S_OK; + CFilterInfo fi; + + if (FAILED(pMux->QueryFilterInfo(&fi)) || !fi.pGraph) { + m_pGB->AddFilter(pMux, L"Multiplexer"); + } + + CStringW prefix; + CString type; + if (majortype == MEDIATYPE_Video) { + prefix = L"Video "; + type.LoadString(IDS_CAPTURE_ERROR_VIDEO); + } else if (majortype == MEDIATYPE_Audio) { + prefix = L"Audio "; + type.LoadString(IDS_CAPTURE_ERROR_AUDIO); + } + + if (pBuff) { + hr = m_pGB->AddFilter(pBuff, prefix + L"Buffer"); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_ADD_BUFFER, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + + hr = m_pGB->ConnectFilter(pPin, pBuff); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_CONNECT_BUFF, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + + pPin = GetFirstPin(pBuff, PINDIR_OUTPUT); + } + + if (pEnc) { + hr = m_pGB->AddFilter(pEnc, prefix + L"Encoder"); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_ADD_ENCODER, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + + hr = m_pGB->ConnectFilter(pPin, pEnc); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_CONNECT_ENC, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + + pPin = GetFirstPin(pEnc, PINDIR_OUTPUT); + + if (CComQIPtr pAMSC = pPin) { + if (pmt->majortype == majortype) { + hr = pAMSC->SetFormat(pmt); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_COMPRESSION, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + } + } + + } + + //if (pMux) + { + hr = m_pGB->ConnectFilter(pPin, pMux); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_MULTIPLEXER, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + } + + CleanGraph(); + + return S_OK; +} + +bool CMainFrame::BuildToCapturePreviewPin( + IBaseFilter* pVidCap, IPin** ppVidCapPin, IPin** ppVidPrevPin, + IBaseFilter* pAudCap, IPin** ppAudCapPin, IPin** ppAudPrevPin) +{ + HRESULT hr; + *ppVidCapPin = *ppVidPrevPin = nullptr; + *ppAudCapPin = *ppAudPrevPin = nullptr; + CComPtr pDVAudPin; + + if (pVidCap) { + CComPtr pPin; + if (!pAudCap // only look for interleaved stream when we don't use any other audio capture source + && SUCCEEDED(m_pCGB->FindPin(pVidCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, TRUE, 0, &pPin))) { + CComPtr pDVSplitter; + hr = pDVSplitter.CoCreateInstance(CLSID_DVSplitter); + hr = m_pGB->AddFilter(pDVSplitter, L"DV Splitter"); + + hr = m_pCGB->RenderStream(nullptr, &MEDIATYPE_Interleaved, pPin, nullptr, pDVSplitter); + + pPin = nullptr; + hr = m_pCGB->FindPin(pDVSplitter, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Video, TRUE, 0, &pPin); + hr = m_pCGB->FindPin(pDVSplitter, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Audio, TRUE, 0, &pDVAudPin); + + CComPtr pDVDec; + hr = pDVDec.CoCreateInstance(CLSID_DVVideoCodec); + hr = m_pGB->AddFilter(pDVDec, L"DV Video Decoder"); + + hr = m_pGB->ConnectFilter(pPin, pDVDec); + + pPin = nullptr; + hr = m_pCGB->FindPin(pDVDec, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Video, TRUE, 0, &pPin); + } else if (FAILED(m_pCGB->FindPin(pVidCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, TRUE, 0, &pPin))) { + MessageBox(ResStr(IDS_CAPTURE_ERROR_VID_CAPT_PIN), ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return false; + } + + CComPtr pSmartTee; + hr = pSmartTee.CoCreateInstance(CLSID_SmartTee); + hr = m_pGB->AddFilter(pSmartTee, L"Smart Tee (video)"); + + hr = m_pGB->ConnectFilter(pPin, pSmartTee); + + hr = pSmartTee->FindPin(L"Preview", ppVidPrevPin); + hr = pSmartTee->FindPin(L"Capture", ppVidCapPin); + } + + if (pAudCap || pDVAudPin) { + CComPtr pPin; + if (pDVAudPin) { + pPin = pDVAudPin; + } else if (FAILED(m_pCGB->FindPin(pAudCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, TRUE, 0, &pPin))) { + MessageBox(ResStr(IDS_CAPTURE_ERROR_AUD_CAPT_PIN), ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return false; + } + + CComPtr pSmartTee; + hr = pSmartTee.CoCreateInstance(CLSID_SmartTee); + hr = m_pGB->AddFilter(pSmartTee, L"Smart Tee (audio)"); + + hr = m_pGB->ConnectFilter(pPin, pSmartTee); + + hr = pSmartTee->FindPin(L"Preview", ppAudPrevPin); + hr = pSmartTee->FindPin(L"Capture", ppAudCapPin); + } + + return true; +} + +bool CMainFrame::BuildGraphVideoAudio(int fVPreview, bool fVCapture, int fAPreview, bool fACapture) +{ + if (!m_pCGB) { + return false; + } + + OAFilterState fs = GetMediaState(); + + if (fs != State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_STOP); + } + + HRESULT hr; + + m_pGB->NukeDownstream(m_pVidCap); + m_pGB->NukeDownstream(m_pAudCap); + + CleanGraph(); + + if (m_pAMVSCCap) { + hr = m_pAMVSCCap->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv); + } + if (m_pAMVSCPrev) { + hr = m_pAMVSCPrev->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv); + } + if (m_pAMASC) { + hr = m_pAMASC->SetFormat(&m_wndCaptureBar.m_capdlg.m_mta); + } + + CComPtr pVidBuffer = m_wndCaptureBar.m_capdlg.m_pVidBuffer; + CComPtr pAudBuffer = m_wndCaptureBar.m_capdlg.m_pAudBuffer; + CComPtr pVidEnc = m_wndCaptureBar.m_capdlg.m_pVidEnc; + CComPtr pAudEnc = m_wndCaptureBar.m_capdlg.m_pAudEnc; + CComPtr pMux = m_wndCaptureBar.m_capdlg.m_pMux; + CComPtr pDst = m_wndCaptureBar.m_capdlg.m_pDst; + CComPtr pAudMux = m_wndCaptureBar.m_capdlg.m_pAudMux; + CComPtr pAudDst = m_wndCaptureBar.m_capdlg.m_pAudDst; + + bool fFileOutput = (pMux && pDst) || (pAudMux && pAudDst); + bool fCapture = (fVCapture || fACapture); + + if (m_pAudCap) { + AM_MEDIA_TYPE* pmt = &m_wndCaptureBar.m_capdlg.m_mta; + int ms = (fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput) ? AUDIOBUFFERLEN : 60; + if (pMux != pAudMux && fACapture) { + SetLatency(m_pAudCap, -1); + } else if (pmt->pbFormat) { + SetLatency(m_pAudCap, ((WAVEFORMATEX*)pmt->pbFormat)->nAvgBytesPerSec * ms / 1000); + } + } + + CComPtr pVidCapPin, pVidPrevPin, pAudCapPin, pAudPrevPin; + BuildToCapturePreviewPin(m_pVidCap, &pVidCapPin, &pVidPrevPin, m_pAudCap, &pAudCapPin, &pAudPrevPin); + + //if (m_pVidCap) + { + bool fVidPrev = pVidPrevPin && fVPreview; + bool fVidCap = pVidCapPin && fVCapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fVidOutput; + + if (fVPreview == 2 && !fVidCap && pVidCapPin) { + pVidPrevPin = pVidCapPin; + pVidCapPin = nullptr; + } + + if (fVidPrev) { + m_pMVRS.Release(); + m_pMVRFG.Release(); + m_pMVRSR.Release(); + + m_OSD.Stop(); + m_pCAP3.Release(); + m_pCAP2.Release(); + m_pCAP.Release(); + m_pVMRWC.Release(); + m_pVMRMC.Release(); + m_pVMB.Release(); + m_pMFVMB.Release(); + m_pMFVP.Release(); + m_pMFVDC.Release(); + m_pQP.Release(); + + m_pGB->Render(pVidPrevPin); + + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP2), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP3), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRWC), FALSE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRMC), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMB), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVMB), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVDC), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVP), TRUE); + m_pMVTO = m_pCAP; + m_pMVRSR = m_pCAP; + m_pMVRS = m_pCAP; + m_pMVRFG = m_pCAP; + + const CAppSettings& s = AfxGetAppSettings(); + m_pVideoWnd = &m_wndView; + + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } else if (m_pVMRWC) { + m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); + } + + if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is used + m_OSD.Stop(); + + if (m_pMVTO) { + m_OSD.Start(m_pVideoWnd, m_pMVTO); + } else if (m_fFullScreen && !m_fAudioOnly && m_pCAP3) { // MPCVR + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); + } else if (!m_fAudioOnly && IsD3DFullScreenMode() && (m_pVMB || m_pMFVMB)) { + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); + } else { + m_OSD.Start(m_pOSDWnd); + } + } + } + + if (fVidCap) { + IBaseFilter* pBF[3] = {pVidBuffer, pVidEnc, pMux}; + HRESULT hr2 = BuildCapture(pVidCapPin, pBF, MEDIATYPE_Video, &m_wndCaptureBar.m_capdlg.m_mtcv); + UNREFERENCED_PARAMETER(hr2); + } + + m_pAMDF.Release(); + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMDF)))) { + TRACE(_T("Warning: No IAMDroppedFrames interface for vidcap capture")); + } + } + + //if (m_pAudCap) + { + bool fAudPrev = pAudPrevPin && fAPreview; + bool fAudCap = pAudCapPin && fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput; + + if (fAPreview == 2 && !fAudCap && pAudCapPin) { + pAudPrevPin = pAudCapPin; + pAudCapPin = nullptr; + } + + if (fAudPrev) { + m_pGB->Render(pAudPrevPin); + } + + if (fAudCap) { + IBaseFilter* pBF[3] = {pAudBuffer, pAudEnc, pAudMux ? pAudMux : pMux}; + HRESULT hr2 = BuildCapture(pAudCapPin, pBF, MEDIATYPE_Audio, &m_wndCaptureBar.m_capdlg.m_mtca); + UNREFERENCED_PARAMETER(hr2); + } + } + + if ((m_pVidCap || m_pAudCap) && fCapture && fFileOutput) { + if (pMux != pDst) { + hr = m_pGB->AddFilter(pDst, L"File Writer V/A"); + hr = m_pGB->ConnectFilter(GetFirstPin(pMux, PINDIR_OUTPUT), pDst); + } + + if (CComQIPtr pCAM = pMux) { + int nIn, nOut, nInC, nOutC; + CountPins(pMux, nIn, nOut, nInC, nOutC); + pCAM->SetMasterStream(nInC - 1); + //pCAM->SetMasterStream(-1); + pCAM->SetOutputCompatibilityIndex(FALSE); + } + + if (CComQIPtr pCI = pMux) { + //if (FAILED(pCI->put_Mode(INTERLEAVE_CAPTURE))) + if (FAILED(pCI->put_Mode(INTERLEAVE_NONE_BUFFERED))) { + pCI->put_Mode(INTERLEAVE_NONE); + } + + REFERENCE_TIME rtInterleave = 10000i64 * AUDIOBUFFERLEN, rtPreroll = 0; //10000i64*500 + pCI->put_Interleaving(&rtInterleave, &rtPreroll); + } + + if (pMux != pAudMux && pAudMux != pAudDst) { + hr = m_pGB->AddFilter(pAudDst, L"File Writer A"); + hr = m_pGB->ConnectFilter(GetFirstPin(pAudMux, PINDIR_OUTPUT), pAudDst); + } + } + + REFERENCE_TIME stop = MAX_TIME; + hr = m_pCGB->ControlStream(&PIN_CATEGORY_CAPTURE, nullptr, nullptr, nullptr, &stop, 0, 0); // stop in the infinite + + CleanGraph(); + + OpenSetupVideo(); + OpenSetupAudio(); + OpenSetupStatsBar(); + OpenSetupStatusBar(); + RecalcLayout(); + + SetupVMR9ColorControl(); + + if (GetLoadState() == MLS::LOADED) { + if (fs == State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } else if (fs == State_Paused) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + } + + return true; +} + +bool CMainFrame::StartCapture() +{ + if (!m_pCGB || m_fCapturing) { + return false; + } + + if (!m_wndCaptureBar.m_capdlg.m_pMux && !m_wndCaptureBar.m_capdlg.m_pDst) { + return false; + } + + HRESULT hr; + + ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); + + // rare to see two capture filters to support IAMPushSource at the same time... + //hr = CComQIPtr(m_pGB)->SyncUsingStreamOffset(TRUE); // TODO: + + BuildGraphVideoAudio( + m_wndCaptureBar.m_capdlg.m_fVidPreview, true, + m_wndCaptureBar.m_capdlg.m_fAudPreview, true); + + hr = m_pME->CancelDefaultHandling(EC_REPAINT); + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + m_fCapturing = true; + + return true; +} + +bool CMainFrame::StopCapture() +{ + if (!m_pCGB || !m_fCapturing) { + return false; + } + + if (!m_wndCaptureBar.m_capdlg.m_pMux && !m_wndCaptureBar.m_capdlg.m_pDst) { + return false; + } + + m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_COMPLETING)); + m_fCapturing = false; + + BuildGraphVideoAudio( + m_wndCaptureBar.m_capdlg.m_fVidPreview, false, + m_wndCaptureBar.m_capdlg.m_fAudPreview, false); + + m_pME->RestoreDefaultHandling(EC_REPAINT); + + ::SetPriorityClass(::GetCurrentProcess(), AfxGetAppSettings().dwPriority); + + m_rtDurationOverride = -1; + + return true; +} + +// + +void CMainFrame::ShowOptions(int idPage/* = 0*/) +{ + // Disable the options dialog when using D3D fullscreen + if (IsD3DFullScreenMode() && !m_bFullScreenWindowIsOnSeparateDisplay) { + return; + } + + // show warning when INI file is read-only + CPath iniPath = AfxGetMyApp()->GetIniPath(); + if (PathUtils::Exists(iniPath)) { + HANDLE hFile = CreateFile(iniPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + AfxMessageBox(_T("The player settings are currently stored in an INI file located in the installation directory of the player.\n\nThe player currently does not have write access to this file, meaning any changes to the settings will not be saved.\n\nPlease remove the INI file to ensure proper functionality of the player.\n\nSettings will then be stored in the Windows Registry. You can easily backup those settings through: Options > Miscellaneous > Export"), MB_ICONWARNING, 0); + } + CloseHandle(hFile); + } + + INT_PTR iRes; + do { + CPPageSheet options(ResStr(IDS_OPTIONS_CAPTION), m_pGB, GetModalParent(), idPage); + iRes = options.DoModal(); + idPage = 0; // If we are to show the dialog again, always show the latest page + } while (iRes == CPPageSheet::APPLY_LANGUAGE_CHANGE); // check if we exited the dialog so that the language change can be applied + + switch (iRes) { + case CPPageSheet::RESET_SETTINGS: + // Request MPC-HC to close itself + SendMessage(WM_CLOSE); + // and immediately reopen + ShellExecute(nullptr, _T("open"), PathUtils::GetProgramPath(true), _T("/reset"), nullptr, SW_SHOWNORMAL); + break; + default: + ASSERT(iRes > 0 && iRes != CPPageSheet::APPLY_LANGUAGE_CHANGE); + break; + } +} + +void CMainFrame::StartWebServer(int nPort) +{ + if (!m_pWebServer) { + m_pWebServer.Attach(DEBUG_NEW CWebServer(this, nPort)); + } +} + +void CMainFrame::StopWebServer() +{ + if (m_pWebServer) { + m_pWebServer.Free(); + } +} + +void CMainFrame::SendStatusMessage(CString msg, int nTimeOut) +{ + const auto timerId = TimerOneTimeSubscriber::STATUS_ERASE; + + m_timerOneTime.Unsubscribe(timerId); + + m_tempstatus_msg.Empty(); + if (nTimeOut <= 0) { + return; + } + + m_tempstatus_msg = msg; + m_timerOneTime.Subscribe(timerId, [this] { m_tempstatus_msg.Empty(); }, nTimeOut); + + m_Lcd.SetStatusMessage(msg, nTimeOut); +} + +bool CMainFrame::CanPreviewUse() { + return (m_bUseSeekPreview && m_wndPreView && !m_fAudioOnly && m_eMediaLoadState == MLS::LOADED + && (GetPlaybackMode() == PM_DVD || GetPlaybackMode() == PM_FILE)); +} + +void CMainFrame::OpenCurPlaylistItem(REFERENCE_TIME rtStart, bool reopen /* = false */, ABRepeat abRepeat /* = ABRepeat() */) +{ + if (IsPlaylistEmpty()) { + return; + } + + CPlaylistItem pli; + if (!m_wndPlaylistBar.GetCur(pli)) { + m_wndPlaylistBar.SetFirstSelected(); + if (!m_wndPlaylistBar.GetCur(pli)) { + return; + } + } + + if (pli.m_bYoutubeDL && (reopen || pli.m_fns.GetHead() == pli.m_ydlSourceURL && m_sydlLastProcessURL != pli.m_ydlSourceURL)) { + if (ProcessYoutubeDLURL(pli.m_ydlSourceURL, false, true)) { + OpenCurPlaylistItem(rtStart, false); + return; + } + } + + CAutoPtr p(m_wndPlaylistBar.GetCurOMD(rtStart, abRepeat)); + if (p) { + OpenMedia(p); + } +} + +void CMainFrame::AddCurDevToPlaylist() +{ + if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + m_wndPlaylistBar.Append( + m_VidDispName, + m_AudDispName, + m_wndCaptureBar.m_capdlg.GetVideoInput(), + m_wndCaptureBar.m_capdlg.GetVideoChannel(), + m_wndCaptureBar.m_capdlg.GetAudioInput() + ); + } +} + +void CMainFrame::OpenMedia(CAutoPtr pOMD) +{ + auto pFileData = dynamic_cast(pOMD.m_p); + //auto pDVDData = dynamic_cast(pOMD.m_p); + auto pDeviceData = dynamic_cast(pOMD.m_p); + + // if the tuner graph is already loaded, we just change its channel + if (pDeviceData) { + if (GetLoadState() == MLS::LOADED && m_pAMTuner + && m_VidDispName == pDeviceData->DisplayName[0] && m_AudDispName == pDeviceData->DisplayName[1]) { + m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput); + m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel); + m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput); + SendNowPlayingToSkype(); + return; + } + } + + CloseMediaBeforeOpen(); + + // if the file is on some removable drive and that drive is missing, + // we yell at user before even trying to construct the graph + if (pFileData) { + CString fn = pFileData->fns.GetHead(); + int i = fn.Find(_T(":\\")); + if (i > 0) { + CString drive = fn.Left(i + 2); + UINT type = GetDriveType(drive); + CAtlList sl; + if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM && GetOpticalDiskType(drive[0], sl) != OpticalDisk_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.GetString()); + ret = AfxMessageBox(msg, MB_RETRYCANCEL); + } + } + if (ret != IDOK) { + return; + } + } + } + } + + ASSERT(!m_bOpenMediaActive); + m_bOpenMediaActive = true; + + // clear BD playlist if we are not currently opening something from it + if (!m_bIsBDPlay) { + m_MPLSPlaylist.clear(); + m_LastOpenBDPath = _T(""); + } + m_bIsBDPlay = false; + + // no need to try releasing external objects while playing + KillTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS); + + // we hereby proclaim + SetLoadState(MLS::LOADING); + + const auto& s = AfxGetAppSettings(); + + // use the graph thread only for some media types + bool bDirectShow = pFileData && !pFileData->fns.IsEmpty() && s.m_Formats.GetEngine(pFileData->fns.GetHead()) == DirectShow; + bool bUseThread = m_pGraphThread && s.fEnableWorkerThreadForOpening && (bDirectShow || !pFileData) && (s.iDefaultCaptureDevice == 1 || !pDeviceData); + bool wasMaximized = IsZoomed(); + // create d3dfs window if launching in fullscreen and d3dfs is enabled + if (s.IsD3DFullscreen() && m_fStartInD3DFullscreen) { + CreateFullScreenWindow(); + m_pVideoWnd = m_pDedicatedFSVideoWnd; + m_fStartInD3DFullscreen = false; + } else if (m_fStartInFullscreenSeparate) { + CreateFullScreenWindow(false); + m_pVideoWnd = m_pDedicatedFSVideoWnd; + m_fStartInFullscreenSeparate = false; + m_bNeedZoomAfterFullscreenExit = true; + } else { + m_pVideoWnd = &m_wndView; + } + + // activate auto-fit logic upon exiting fullscreen if + // we are opening new media in fullscreen mode + // adipose: unless we were previously maximized + if ((IsFullScreenMode()) && s.fRememberZoomLevel && !wasMaximized) { + m_bNeedZoomAfterFullscreenExit = true; + } + + // don't set video renderer output rect until the window is repositioned + m_bDelaySetOutputRect = true; + +#if 0 + // display corresponding media icon in status bar + if (pFileData) { + CString filename = m_wndPlaylistBar.GetCurFileName(); + CString ext = filename.Mid(filename.ReverseFind('.') + 1); + m_wndStatusBar.SetMediaType(ext); + } else if (pDVDData) { + m_wndStatusBar.SetMediaType(_T(".ifo")); + } else { + // TODO: Create icons for pDeviceData + m_wndStatusBar.SetMediaType(_T(".unknown")); + } +#endif + + // initiate graph creation, OpenMediaPrivate() will call OnFilePostOpenmedia() + if (bUseThread) { + VERIFY(m_evOpenPrivateFinished.Reset()); + VERIFY(m_pGraphThread->PostThreadMessage(CGraphThread::TM_OPEN, (WPARAM)0, (LPARAM)pOMD.Detach())); + m_bOpenedThroughThread = true; + } else { + OpenMediaPrivate(pOMD); + m_bOpenedThroughThread = false; + } +} + +bool CMainFrame::ResetDevice() +{ + if (m_pCAP2_preview) { + m_pCAP2_preview->ResetDevice(); + } + if (m_pCAP) { + return m_pCAP->ResetDevice(); + } + return true; +} + +bool CMainFrame::DisplayChange() +{ + if (m_pCAP2_preview) { + m_pCAP2_preview->DisplayChange(); + } + if (m_pCAP) { + return m_pCAP->DisplayChange(); + } + return true; +} + +void CMainFrame::CloseMediaBeforeOpen() +{ + if (GetLoadState() != MLS::CLOSED) { + CloseMedia(true); + } +} + +void CMainFrame::ForceCloseProcess() +{ + MessageBeep(MB_ICONEXCLAMATION); + if (CrashReporter::IsEnabled()) { + CrashReporter::Disable(); + } + TerminateProcess(GetCurrentProcess(), 0xDEADBEEF); +} + +void CMainFrame::CloseMedia(bool bNextIsQueued/* = false*/, bool bPendingFileDelete/* = false*/) +{ + TRACE(_T("CMainFrame::CloseMedia\n")); + + m_dwLastPause = 0; + + if (m_bUseSeekPreview && m_wndPreView.IsWindowVisible()) { + m_wndPreView.ShowWindow(SW_HIDE); + } + m_bUseSeekPreview = false; + m_bDVDStillOn = false; + + if (GetLoadState() == MLS::CLOSING || GetLoadState() == MLS::CLOSED) { + TRACE(_T("Ignoring duplicate close action.\n")); + return; + } + + m_media_trans_control.close(); + + if (m_bSettingUpMenus) { + SleepEx(500, false); + ASSERT(!m_bSettingUpMenus); + } + + auto& s = AfxGetAppSettings(); + bool savehistory = false; + if (GetLoadState() == MLS::LOADED) { + // abort sub search + m_pSubtitlesProviders->Abort(SubtitlesThreadType(STT_SEARCH | STT_DOWNLOAD)); + m_wndSubtitlesDownloadDialog.DoClear(); + + // save playback position + if (s.fKeepHistory && !bPendingFileDelete) { + if (m_bRememberFilePos && !m_fEndOfStream && m_dwReloadPos == 0 && m_pMS) { + REFERENCE_TIME rtNow = 0; + m_pMS->GetCurrentPosition(&rtNow); + if (rtNow > 0) { + REFERENCE_TIME rtDur = 0; + m_pMS->GetDuration(&rtDur); + if (rtNow >= rtDur || rtDur - rtNow < 50000000LL) { // at end of file + rtNow = 0; + } + } + s.MRU.UpdateCurrentFilePosition(rtNow, true); + } else if (GetPlaybackMode() == PM_DVD && m_pDVDI) { + DVD_DOMAIN DVDDomain; + if (SUCCEEDED(m_pDVDI->GetCurrentDomain(&DVDDomain))) { + if (DVDDomain == DVD_DOMAIN_Title) { + DVD_PLAYBACK_LOCATION2 Location2; + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location2))) { + DVD_POSITION dvdPosition = s.MRU.GetCurrentDVDPosition(); + if (dvdPosition.llDVDGuid) { + dvdPosition.lTitle = Location2.TitleNum; + dvdPosition.timecode = Location2.TimeCode; + } + } + } + } + } + } + + if (m_pME) { + m_pME->SetNotifyWindow(NULL, 0, 0); + } + + // save external subtitle + if (g_bExternalSubtitle && !bPendingFileDelete && + m_pCurrentSubInput.pSubStream && m_pCurrentSubInput.pSubStream->GetPath().IsEmpty()) { + const auto& s = AfxGetAppSettings(); + if (s.bAutoSaveDownloadedSubtitles) { + CString dirBuffer; + LPCTSTR dir = nullptr; + if (!s.strSubtitlePaths.IsEmpty()) { + auto start = s.strSubtitlePaths.Left(2); + if (start != _T(".") && start != _T(".;")) { + int pos = 0; + dir = dirBuffer = s.strSubtitlePaths.Tokenize(_T(";"), pos); + } + } + SubtitlesSave(dir, true); + } + } + + if (s.fKeepHistory && !bPendingFileDelete) { + savehistory = true; + } + } + + // delay showing auto-hidden controls if new media is queued + if (bNextIsQueued) { + m_controls.DelayShowNotLoaded(true); + } else { + m_controls.DelayShowNotLoaded(false); + } + + // abort if loading + bool bGraphTerminated = false; + if (GetLoadState() == MLS::LOADING) { + TRACE(_T("Media is still loading. Aborting graph.\n")); + + // tell OpenMediaPrivate() that we want to abort + m_fOpeningAborted = true; + + // close pin connection error dialog + if (mediaTypesErrorDlg) { + mediaTypesErrorDlg->SendMessage(WM_EXTERNALCLOSE, 0, 0); + // wait till error dialog has been closed + CAutoLock lck(&lockModalDialog); + } + + // abort current graph task + if (m_pGB) { + if (!m_pAMOP) { + m_pAMOP = m_pGB; + if (!m_pAMOP) { + BeginEnumFilters(m_pGB, pEF, pBF) + if (m_pAMOP = pBF) { + break; + } + EndEnumFilters; + } + } + if (m_pAMOP) { + m_pAMOP->AbortOperation(); + } + m_pGB->Abort(); // TODO: lock on graph objects somehow, this is not thread safe + } + if (m_pGB_preview) { + m_pGB_preview->Abort(); + } + + if (m_bOpenedThroughThread) { + BeginWaitCursor(); + MSG msg; + HANDLE h = m_evOpenPrivateFinished; + bool killprocess = true; + bool processmsg = true; + ULONGLONG start = GetTickCount64(); + while (processmsg && (GetTickCount64() - start < 6000ULL)) { + DWORD res = MsgWaitForMultipleObjectsEx(1, &h, 1000, QS_ALLINPUT, MWMO_INPUTAVAILABLE); + switch (res) { + case WAIT_OBJECT_0: + TRACE(_T("Graph abort successful\n")); + killprocess = false; // event has been signalled + processmsg = false; + break; + case WAIT_OBJECT_0 + 1: + // we have a message - peek and dispatch it + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + break; + case WAIT_TIMEOUT: + break; + default: // unexpected failure + processmsg = false; + break; + } + } + if (killprocess) + { + // Aborting graph failed + TRACE(_T("Failed to abort graph creation.\n")); + ForceCloseProcess(); + } + EndWaitCursor(); + } else { + // Aborting graph failed + TRACE(_T("Failed to abort graph creation.\n")); + ForceCloseProcess(); + } + + MSG msg; + // purge possible queued OnFilePostOpenmedia() + if (PeekMessage(&msg, m_hWnd, WM_POSTOPEN, WM_POSTOPEN, PM_REMOVE | PM_NOYIELD)) { + free((OpenMediaData*)msg.lParam); + } + // purge possible queued OnOpenMediaFailed() + if (PeekMessage(&msg, m_hWnd, WM_OPENFAILED, WM_OPENFAILED, PM_REMOVE | PM_NOYIELD)) { + free((OpenMediaData*)msg.lParam); + } + + // abort finished, unset the flag + m_fOpeningAborted = false; + } + + // we are on the way + m_bSettingUpMenus = true; + SetLoadState(MLS::CLOSING); + + if (m_pGB_preview) { + PreviewWindowHide(); + m_bUseSeekPreview = false; + } + + // stop the graph before destroying it + OnPlayStop(true); + + // clear any active osd messages + //m_OSD.ClearMessage(); + + // Ensure the dynamically added menu items are cleared and all references + // on objects belonging to the DirectShow graph they might hold are freed. + // Note that we need to be in closing state already when doing that + if (m_hWnd) { + SetupFiltersSubMenu(); + SetupAudioSubMenu(); + SetupSubtitlesSubMenu(); + SetupVideoStreamsSubMenu(); + SetupJumpToSubMenus(); + } + + m_bSettingUpMenus = false; + + // initiate graph destruction + if (m_pGraphThread && m_bOpenedThroughThread && !bGraphTerminated) { + // either opening or closing has to be blocked to prevent reentering them, closing is the better choice + VERIFY(m_evClosePrivateFinished.Reset()); + VERIFY(m_pGraphThread->PostThreadMessage(CGraphThread::TM_CLOSE, (WPARAM)0, (LPARAM)0)); + + HANDLE handle = m_evClosePrivateFinished; + DWORD dwWait; + ULONGLONG start = GetTickCount64(); + ULONGLONG waitdur = 10000ULL; + bool killprocess = true; + bool processmsg = true; + bool extendedwait = false; + while (processmsg) { + dwWait = MsgWaitForMultipleObjects(1, &handle, FALSE, 1000, QS_SENDMESSAGE); + switch (dwWait) { + case WAIT_OBJECT_0: + processmsg = false; // event received + killprocess = false; + break; + case WAIT_OBJECT_0 + 1: + MSG msg; + PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE); + break; + case WAIT_TIMEOUT: + break; + default: + processmsg = false; + break; + } + + if (processmsg && (GetTickCount64() - start > waitdur)) { + if (extendedwait || m_fFullScreen) { + processmsg = false; + } else { + CString msg; + if (!m_pGB && m_pGB_preview) { +#if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER && (MPC_VERSION_REV > 10) && 0 + if (CrashReporter::IsEnabled()) { + throw 1; + } +#endif + msg = L"Timeout when closing preview filter graph.\n\nClick YES to terminate player process. Click NO to wait longer (up to 15 seconds)."; + } else { + msg = L"Timeout when closing filter graph.\n\nClick YES to terminate player process. Click NO to wait longer (up to 15 seconds)."; + } + if (IDYES == AfxMessageBox(msg, MB_ICONEXCLAMATION | MB_YESNO, 0)) { + processmsg = false; + } else { + extendedwait = true; + start = GetTickCount64(); + waitdur = 15000ULL; + } + } + } + } + if (killprocess) { + TRACE(_T("Failed to close filter graph thread.\n")); + ForceCloseProcess(); + } + } else { + CloseMediaPrivate(); + } + + // graph is destroyed, update stuff + OnFilePostClosemedia(bNextIsQueued); + + if (savehistory) { + s.MRU.WriteCurrentEntry(); + } + s.MRU.current_rfe_hash.Empty(); + + TRACE(_T("Close media completed\n")); +} + +void CMainFrame::StartTunerScan(CAutoPtr pTSD) +{ + // Remove the old info during the scan + if (m_pDVBState) { + m_pDVBState->Reset(); + } + m_wndInfoBar.RemoveAllLines(); + m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); + RecalcLayout(); + OpenSetupWindowTitle(); + SendNowPlayingToSkype(); + + if (m_pGraphThread) { + m_pGraphThread->PostThreadMessage(CGraphThread::TM_TUNER_SCAN, (WPARAM)0, (LPARAM)pTSD.Detach()); + } else { + DoTunerScan(pTSD); + } +} + +void CMainFrame::StopTunerScan() +{ + m_bStopTunerScan = true; +} + +HRESULT CMainFrame::SetChannel(int nChannel) +{ + CAppSettings& s = AfxGetAppSettings(); + HRESULT hr = S_OK; + CComQIPtr pTun = m_pGB; + CBDAChannel* pChannel = s.FindChannelByPref(nChannel); + + if (s.m_DVBChannels.empty() && nChannel == INT_ERROR) { + hr = S_FALSE; // All channels have been cleared or it is the first start + } else if (pTun && pChannel && !m_pDVBState->bSetChannelActive) { + m_pDVBState->Reset(); + m_wndInfoBar.RemoveAllLines(); + m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); + RecalcLayout(); + m_pDVBState->bSetChannelActive = true; + + // Skip n intermediate ZoomVideoWindow() calls while the new size is stabilized: + switch (s.iDSVideoRendererType) { + case VIDRNDT_DS_MADVR: + if (s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS) { + m_nLockedZoomVideoWindow = 3; + } else { + m_nLockedZoomVideoWindow = 0; + } + break; + case VIDRNDT_DS_EVR_CUSTOM: + m_nLockedZoomVideoWindow = 0; + break; + default: + m_nLockedZoomVideoWindow = 0; + } + if (SUCCEEDED(hr = pTun->SetChannel(nChannel))) { + if (hr == S_FALSE) { + // Re-create all + m_nLockedZoomVideoWindow = 0; + PostMessage(WM_COMMAND, ID_FILE_OPENDEVICE); + return hr; + } + + m_pDVBState->bActive = true; + m_pDVBState->pChannel = pChannel; + m_pDVBState->sChannelName = pChannel->GetName(); + + m_wndInfoBar.SetLine(ResStr(IDS_INFOBAR_CHANNEL), m_pDVBState->sChannelName); + RecalcLayout(); + + if (s.fRememberZoomLevel && !(m_fFullScreen || IsZoomed() || IsIconic())) { + ZoomVideoWindow(); + } + MoveVideoWindow(); + + // Add temporary flag to allow EC_VIDEO_SIZE_CHANGED event to stabilize window size + // for 5 seconds since playback starts + m_bAllowWindowZoom = true; + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::AUTOFIT_TIMEOUT, [this] + { m_bAllowWindowZoom = false; }, 5000); + + UpdateCurrentChannelInfo(); + } + m_pDVBState->bSetChannelActive = false; + } else { + hr = E_FAIL; + ASSERT(FALSE); + } + + return hr; +} + +void CMainFrame::UpdateCurrentChannelInfo(bool bShowOSD /*= true*/, bool bShowInfoBar /*= false*/) +{ + const CBDAChannel* pChannel = m_pDVBState->pChannel; + CComQIPtr pTun = m_pGB; + + if (!m_pDVBState->bInfoActive && pChannel && pTun) { + if (m_pDVBState->infoData.valid()) { + m_pDVBState->bAbortInfo = true; + m_pDVBState->infoData.get(); + } + m_pDVBState->bAbortInfo = false; + m_pDVBState->bInfoActive = true; + m_pDVBState->infoData = std::async(std::launch::async, [this, pChannel, pTun, bShowOSD, bShowInfoBar] { + DVBState::EITData infoData; + infoData.hr = pTun->UpdatePSI(pChannel, infoData.NowNext); + infoData.bShowOSD = bShowOSD; + infoData.bShowInfoBar = bShowInfoBar; + if (m_pDVBState && !m_pDVBState->bAbortInfo) + { + PostMessage(WM_DVB_EIT_DATA_READY); + } + return infoData; + }); + } +} + +LRESULT CMainFrame::OnCurrentChannelInfoUpdated(WPARAM wParam, LPARAM lParam) +{ + if (!m_pDVBState->bAbortInfo && m_pDVBState->infoData.valid()) { + EventDescriptor& NowNext = m_pDVBState->NowNext; + const auto infoData = m_pDVBState->infoData.get(); + NowNext = infoData.NowNext; + + if (infoData.hr != S_FALSE) { + // Set a timer to update the infos only if channel has now/next flag + time_t tNow; + time(&tNow); + time_t tElapse = NowNext.duration - (tNow - NowNext.startTime); + if (tElapse < 0) { + tElapse = 0; + } + // We set a 15s delay to let some room for the program infos to change + tElapse += 15; + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DVBINFO_UPDATE, + [this] { UpdateCurrentChannelInfo(false, false); }, + 1000 * (UINT)tElapse); + m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(true); + } else { + m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); + } + + CString sChannelInfo = m_pDVBState->sChannelName; + m_wndInfoBar.RemoveAllLines(); + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CHANNEL), sChannelInfo); + + if (infoData.hr == S_OK) { + // EIT information parsed correctly + if (infoData.bShowOSD) { + sChannelInfo.AppendFormat(_T(" | %s (%s - %s)"), NowNext.eventName.GetString(), NowNext.strStartTime.GetString(), NowNext.strEndTime.GetString()); + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TITLE), NowNext.eventName); + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TIME), NowNext.strStartTime + _T(" - ") + NowNext.strEndTime); + + if (NowNext.parentalRating >= 0) { + CString parentRating; + if (!NowNext.parentalRating) { + parentRating.LoadString(IDS_NO_PARENTAL_RATING); + } else { + parentRating.Format(IDS_PARENTAL_RATING, NowNext.parentalRating); + } + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_PARENTAL_RATING), parentRating); + } + + if (!NowNext.content.IsEmpty()) { + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CONTENT), NowNext.content); + } + + CString description = NowNext.eventDesc; + if (!NowNext.extendedDescriptorsText.IsEmpty()) { + if (!description.IsEmpty()) { + description += _T("; "); + } + description += NowNext.extendedDescriptorsText; + } + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); + + for (const auto& item : NowNext.extendedDescriptorsItems) { + m_wndInfoBar.SetLine(item.first, item.second); + } + + if (infoData.bShowInfoBar && !m_controls.ControlChecked(CMainFrameControls::Toolbar::INFO)) { + m_controls.ToggleControl(CMainFrameControls::Toolbar::INFO); + } + } + + RecalcLayout(); + if (infoData.bShowOSD) { + m_OSD.DisplayMessage(OSD_TOPLEFT, sChannelInfo, 3500); + } + + // Update window title and skype status + OpenSetupWindowTitle(); + SendNowPlayingToSkype(); + } else { + ASSERT(FALSE); + } + + m_pDVBState->bInfoActive = false; + + return 0; +} + +// ==== Added by CASIMIR666 +void CMainFrame::SetLoadState(MLS eState) +{ + m_eMediaLoadState = eState; + SendAPICommand(CMD_STATE, L"%d", static_cast(eState)); + if (eState == MLS::LOADED) { + m_controls.DelayShowNotLoaded(false); + m_eventc.FireEvent(MpcEvent::MEDIA_LOADED); + } + UpdateControlState(UPDATE_CONTROLS_VISIBILITY); +} + +inline MLS CMainFrame::GetLoadState() const +{ + return m_eMediaLoadState; +} + +void CMainFrame::SetPlayState(MPC_PLAYSTATE iState) +{ + m_Lcd.SetPlayState((CMPC_Lcd::PlayState)iState); + SendAPICommand(CMD_PLAYMODE, L"%d", iState); + + if (m_fEndOfStream) { + SendAPICommand(CMD_NOTIFYENDOFSTREAM, L"\0"); // do not pass NULL here! + } + + if (iState == PS_PLAY) { + // Prevent sleep when playing audio and/or video, but allow screensaver when only audio + if (!m_fAudioOnly && AfxGetAppSettings().bPreventDisplaySleep) { + SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED); + } else { + SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); + } + } else { + SetThreadExecutionState(ES_CONTINUOUS); + } + + + UpdateThumbarButton(iState); +} + +bool CMainFrame::CreateFullScreenWindow(bool isD3D /* = true */) +{ + if (m_bFullScreenWindowIsD3D == isD3D && HasDedicatedFSVideoWindow()) { + return false; + } + const CAppSettings& s = AfxGetAppSettings(); + CMonitors monitors; + CMonitor monitor, currentMonitor; + + if (m_pDedicatedFSVideoWnd->IsWindow()) { + m_pDedicatedFSVideoWnd->DestroyWindow(); + } + + currentMonitor = monitors.GetNearestMonitor(this); + if (s.iMonitor == 0) { + monitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); + } + if (!monitor.IsMonitor()) { + monitor = currentMonitor; + } + + CRect monitorRect; + monitor.GetMonitorRect(monitorRect); + + m_bFullScreenWindowIsD3D = isD3D; + m_bFullScreenWindowIsOnSeparateDisplay = monitor != currentMonitor; + + // allow the mainframe to keep focus + bool ret = !!m_pDedicatedFSVideoWnd->CreateEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, _T(""), ResStr(IDS_MAINFRM_136), WS_POPUP, monitorRect, nullptr, 0); + if (ret) { + m_pDedicatedFSVideoWnd->ShowWindow(SW_SHOWNOACTIVATE); + } + return ret; +} + +bool CMainFrame::IsFrameLessWindow() const +{ + return (IsFullScreenMainFrame() || AfxGetAppSettings().eCaptionMenuMode == MODE_BORDERLESS); +} + +bool CMainFrame::IsCaptionHidden() const +{ + // If no caption, there is no menu bar. But if is no menu bar, then the caption can be. + return (!IsFullScreenMainFrame() && AfxGetAppSettings().eCaptionMenuMode > MODE_HIDEMENU); //!=MODE_SHOWCAPTIONMENU && !=MODE_HIDEMENU +} + +bool CMainFrame::IsMenuHidden() const +{ + return (!IsFullScreenMainFrame() && AfxGetAppSettings().eCaptionMenuMode != MODE_SHOWCAPTIONMENU); +} + +bool CMainFrame::IsPlaylistEmpty() const +{ + return (m_wndPlaylistBar.GetCount() == 0); +} + +bool CMainFrame::IsInteractiveVideo() const +{ + return m_fShockwaveGraph; +} + +bool CMainFrame::IsFullScreenMode() const { + return m_fFullScreen || IsD3DFullScreenMode(); +} + +bool CMainFrame::IsFullScreenMainFrame() const { + return m_fFullScreen && !HasDedicatedFSVideoWindow(); +} + +bool CMainFrame::IsFullScreenMainFrameExclusiveMPCVR() const { + return m_fFullScreen && m_bIsMPCVRExclusiveMode && !HasDedicatedFSVideoWindow(); +} + +bool CMainFrame::IsFullScreenSeparate() const { + return m_fFullScreen && HasDedicatedFSVideoWindow() && !m_bFullScreenWindowIsD3D; +} + +bool CMainFrame::HasDedicatedFSVideoWindow() const { + return m_pDedicatedFSVideoWnd && m_pDedicatedFSVideoWnd->IsWindow(); +} + +bool CMainFrame::IsD3DFullScreenMode() const +{ + return HasDedicatedFSVideoWindow() && m_bFullScreenWindowIsD3D; +}; + +bool CMainFrame::IsSubresyncBarVisible() const +{ + return !!m_wndSubresyncBar.IsWindowVisible(); +} + +void CMainFrame::SetupEVRColorControl() +{ + if (m_pMFVP) { + CMPlayerCApp* pApp = AfxGetMyApp(); + CAppSettings& s = AfxGetAppSettings(); + + if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Brightness, pApp->GetEVRColorControl(ProcAmp_Brightness)))) { + return; + } + if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Contrast, pApp->GetEVRColorControl(ProcAmp_Contrast)))) { + return; + } + if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Hue, pApp->GetEVRColorControl(ProcAmp_Hue)))) { + return; + } + if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Saturation, pApp->GetEVRColorControl(ProcAmp_Saturation)))) { + return; + } + + pApp->UpdateColorControlRange(true); + SetColorControl(ProcAmp_All, s.iBrightness, s.iContrast, s.iHue, s.iSaturation); + } +} + +// Called from GraphThread +void CMainFrame::SetupVMR9ColorControl() +{ + if (m_pVMRMC) { + CMPlayerCApp* pApp = AfxGetMyApp(); + CAppSettings& s = AfxGetAppSettings(); + + if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Brightness)))) { + return; + } + if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Contrast)))) { + return; + } + if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Hue)))) { + return; + } + if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Saturation)))) { + return; + } + + pApp->UpdateColorControlRange(false); + SetColorControl(ProcAmp_All, s.iBrightness, s.iContrast, s.iHue, s.iSaturation); + } +} + +void CMainFrame::SetColorControl(DWORD flags, int& brightness, int& contrast, int& hue, int& saturation) +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + HRESULT hr = 0; + + static VMR9ProcAmpControl ClrControl; + static DXVA2_ProcAmpValues ClrValues; + + COLORPROPERTY_RANGE* cr = 0; + if (flags & ProcAmp_Brightness) { + cr = pApp->GetColorControl(ProcAmp_Brightness); + brightness = std::min(std::max(brightness, cr->MinValue), cr->MaxValue); + } + if (flags & ProcAmp_Contrast) { + cr = pApp->GetColorControl(ProcAmp_Contrast); + contrast = std::min(std::max(contrast, cr->MinValue), cr->MaxValue); + } + if (flags & ProcAmp_Hue) { + cr = pApp->GetColorControl(ProcAmp_Hue); + hue = std::min(std::max(hue, cr->MinValue), cr->MaxValue); + } + if (flags & ProcAmp_Saturation) { + cr = pApp->GetColorControl(ProcAmp_Saturation); + saturation = std::min(std::max(saturation, cr->MinValue), cr->MaxValue); + } + + if (m_pVMRMC) { + ClrControl.dwSize = sizeof(ClrControl); + ClrControl.dwFlags = flags; + ClrControl.Brightness = (float)brightness; + ClrControl.Contrast = (float)(contrast + 100) / 100; + ClrControl.Hue = (float)hue; + ClrControl.Saturation = (float)(saturation + 100) / 100; + + hr = m_pVMRMC->SetProcAmpControl(0, &ClrControl); + } else if (m_pMFVP) { + ClrValues.Brightness = IntToFixed(brightness); + ClrValues.Contrast = IntToFixed(contrast + 100, 100); + ClrValues.Hue = IntToFixed(hue); + ClrValues.Saturation = IntToFixed(saturation + 100, 100); + + hr = m_pMFVP->SetProcAmpValues(flags, &ClrValues); + + } + // Workaround: with Intel driver the minimum values of the supported range may not actually work + if (FAILED(hr)) { + if (flags & ProcAmp_Brightness) { + cr = pApp->GetColorControl(ProcAmp_Brightness); + if (brightness == cr->MinValue) { + brightness = cr->MinValue + 1; + } + } + if (flags & ProcAmp_Hue) { + cr = pApp->GetColorControl(ProcAmp_Hue); + if (hue == cr->MinValue) { + hue = cr->MinValue + 1; + } + } + } +} + +void CMainFrame::SetClosedCaptions(bool enable) +{ + if (m_pLN21) { + m_pLN21->SetServiceState(enable ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off); + } +} + +LPCTSTR CMainFrame::GetDVDAudioFormatName(const DVD_AudioAttributes& ATR) const +{ + switch (ATR.AudioFormat) { + case DVD_AudioFormat_AC3: + return _T("AC3"); + case DVD_AudioFormat_MPEG1: + case DVD_AudioFormat_MPEG1_DRC: + return _T("MPEG1"); + case DVD_AudioFormat_MPEG2: + case DVD_AudioFormat_MPEG2_DRC: + return _T("MPEG2"); + case DVD_AudioFormat_LPCM: + return _T("LPCM"); + case DVD_AudioFormat_DTS: + return _T("DTS"); + case DVD_AudioFormat_SDDS: + return _T("SDDS"); + case DVD_AudioFormat_Other: + default: + return MAKEINTRESOURCE(IDS_MAINFRM_137); + } +} + +afx_msg void CMainFrame::OnGotoSubtitle(UINT nID) +{ + if (!m_pSubStreams.IsEmpty() && !IsPlaybackCaptureMode()) { + m_rtCurSubPos = m_wndSeekBar.GetPos(); + m_lSubtitleShift = 0; + m_wndSubresyncBar.RefreshEmbeddedTextSubtitleData(); + m_nCurSubtitle = m_wndSubresyncBar.FindNearestSub(m_rtCurSubPos, (nID == ID_GOTO_NEXT_SUB)); + if (m_nCurSubtitle >= 0 && m_pMS) { + if (nID == ID_GOTO_PREV_SUB) { + OnPlayPause(); + } + m_pMS->SetPositions(&m_rtCurSubPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + } +} + +afx_msg void CMainFrame::OnSubresyncShiftSub(UINT nID) +{ + if (m_nCurSubtitle >= 0) { + long lShift = (nID == ID_SUBRESYNC_SHIFT_DOWN) ? -100 : 100; + CString strSubShift; + + if (m_wndSubresyncBar.ShiftSubtitle(m_nCurSubtitle, lShift, m_rtCurSubPos)) { + m_lSubtitleShift += lShift; + if (m_pMS) { + m_pMS->SetPositions(&m_rtCurSubPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + } + + strSubShift.Format(IDS_MAINFRM_138, m_lSubtitleShift); + m_OSD.DisplayMessage(OSD_TOPLEFT, strSubShift); + } +} + +afx_msg void CMainFrame::OnSubtitleDelay(UINT nID) +{ + int nDelayStep = AfxGetAppSettings().nSubDelayStep; + + if (nID == ID_SUB_DELAY_DOWN) { + nDelayStep = -nDelayStep; + } + + SetSubtitleDelay(nDelayStep, /*relative=*/ true); +} + +afx_msg void CMainFrame::OnSubtitlePos(UINT nID) +{ + if (m_pCAP) { + CAppSettings& s = AfxGetAppSettings(); + switch (nID) { + case ID_SUB_POS_DOWN: + s.m_RenderersSettings.subPicVerticalShift += 2; + break; + case ID_SUB_POS_UP: + s.m_RenderersSettings.subPicVerticalShift -= 2; + break; + } + + if (GetMediaState() != State_Running) { + m_pCAP->Paint(false); + } + } +} + +afx_msg void CMainFrame::OnSubtitleFontSize(UINT nID) +{ + if (m_pCAP && m_pCurrentSubInput.pSubStream) { + CLSID clsid; + m_pCurrentSubInput.pSubStream->GetClassID(&clsid); + if (clsid == __uuidof(CRenderedTextSubtitle)) { + CAppSettings& s = AfxGetAppSettings(); + switch (nID) { + case ID_SUB_FONT_SIZE_DEC: + s.m_RenderersSettings.fontScaleOverride -= 0.05; + break; + case ID_SUB_FONT_SIZE_INC: + s.m_RenderersSettings.fontScaleOverride += 0.05; + break; + } + + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; + + if (pRTS->m_LibassContext.IsLibassActive()) { + // not supported by libass (yet) + if (!IsFullScreenMode()) { + AfxMessageBox(_T("Adjusting subtitle text size is not possible when using libass."), MB_ICONERROR, 0); + } + } + + { + CAutoLock cAutoLock(&m_csSubLock); + pRTS->Deinit(); + } + InvalidateSubtitle(); + + if (GetMediaState() != State_Running) { + m_pCAP->Paint(false); + } + } else { + if (!IsFullScreenMode()) { + AfxMessageBox(_T("Adjusting subtitle text size is not possible for image based subtitle formats."), MB_ICONERROR, 0); + } + } + } +} + +void CMainFrame::ResetSubtitlePosAndSize(bool repaint /* = false*/) +{ + CAppSettings& s = AfxGetAppSettings(); + bool changed = (s.m_RenderersSettings.fontScaleOverride != 1.0) || (s.m_RenderersSettings.subPicVerticalShift != 0); + + s.m_RenderersSettings.fontScaleOverride = 1.0; + s.m_RenderersSettings.subPicVerticalShift = 0; + + if (changed && repaint && m_pCAP && m_pCurrentSubInput.pSubStream) { + CLSID clsid; + m_pCurrentSubInput.pSubStream->GetClassID(&clsid); + if (clsid == __uuidof(CRenderedTextSubtitle)) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; + { + CAutoLock cAutoLock(&m_csSubLock); + pRTS->Deinit(); + } + InvalidateSubtitle(); + + if (GetMediaState() != State_Running) { + m_pCAP->Paint(false); + } + } + } +} + + +void CMainFrame::ProcessAPICommand(COPYDATASTRUCT* pCDS) +{ + CAtlList fns; + REFERENCE_TIME rtPos = 0; + CString fn; + + switch (pCDS->dwData) { + case CMD_OPENFILE: + fn = CString((LPCWSTR)pCDS->lpData); + if (CanSendToYoutubeDL(fn)) { + if (ProcessYoutubeDLURL(fn, false)) { + OpenCurPlaylistItem(); + return; + } else if (IsOnYDLWhitelist(fn)) { + return; + } + } + fns.AddHead(fn); + m_wndPlaylistBar.Open(fns, false); + OpenCurPlaylistItem(); + break; + case CMD_STOP: + OnPlayStop(); + break; + case CMD_CLOSEFILE: + CloseMedia(); + break; + case CMD_PLAYPAUSE: + OnPlayPlaypause(); + break; + case CMD_PLAY: + OnApiPlay(); + break; + case CMD_PAUSE: + OnApiPause(); + break; + case CMD_ADDTOPLAYLIST: + fn = CString((LPCWSTR)pCDS->lpData); + if (CanSendToYoutubeDL(fn)) { + if (ProcessYoutubeDLURL(fn, true)) { + return; + } else if (IsOnYDLWhitelist(fn)) { + return; + } + } + fns.AddHead(fn); + m_wndPlaylistBar.Append(fns, true); + break; + case CMD_STARTPLAYLIST: + OpenCurPlaylistItem(); + break; + case CMD_CLEARPLAYLIST: + m_wndPlaylistBar.Empty(); + break; + case CMD_SETPOSITION: + rtPos = 10000 * REFERENCE_TIME(_wtof((LPCWSTR)pCDS->lpData) * 1000); //with accuracy of 1 ms + // imianz: quick and dirty trick + // Pause->SeekTo->Play (in place of SeekTo only) seems to prevents in most cases + // some strange video effects on avi files (ex. locks a while and than running fast). + if (!m_fAudioOnly && GetMediaState() == State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + SeekTo(rtPos); + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } else { + SeekTo(rtPos); + } + // show current position overridden by play command + m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 2000); + break; + case CMD_SETAUDIODELAY: + rtPos = (REFERENCE_TIME)_wtol((LPCWSTR)pCDS->lpData) * 10000; + SetAudioDelay(rtPos); + break; + case CMD_SETSUBTITLEDELAY: + SetSubtitleDelay(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_SETINDEXPLAYLIST: + //m_wndPlaylistBar.SetSelIdx(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_SETAUDIOTRACK: + SetAudioTrackIdx(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_SETSUBTITLETRACK: + SetSubtitleTrackIdx(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_GETVERSION: { + CStringW buff = AfxGetMyApp()->m_strVersion; + SendAPICommand(CMD_VERSION, buff); + break; + } + case CMD_GETSUBTITLETRACKS: + SendSubtitleTracksToApi(); + break; + case CMD_GETAUDIOTRACKS: + SendAudioTracksToApi(); + break; + case CMD_GETCURRENTAUDIOTRACK: + SendAPICommand(CMD_CURRENTAUDIOTRACK, L"%d", GetCurrentAudioTrackIdx()); + break; + case CMD_GETCURRENTSUBTITLETRACK: + SendAPICommand(CMD_CURRENTSUBTITLETRACK, L"%d", GetCurrentSubtitleTrackIdx()); + break; + case CMD_GETCURRENTPOSITION: + SendCurrentPositionToApi(); + break; + case CMD_GETNOWPLAYING: + SendNowPlayingToApi(); + break; + case CMD_JUMPOFNSECONDS: + JumpOfNSeconds(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_GETPLAYLIST: + SendPlaylistToApi(); + break; + case CMD_JUMPFORWARDMED: + OnPlaySeek(ID_PLAY_SEEKFORWARDMED); + break; + case CMD_JUMPBACKWARDMED: + OnPlaySeek(ID_PLAY_SEEKBACKWARDMED); + break; + case CMD_TOGGLEFULLSCREEN: + OnViewFullscreen(); + break; + case CMD_INCREASEVOLUME: + m_wndToolBar.m_volctrl.IncreaseVolume(); + break; + case CMD_DECREASEVOLUME: + m_wndToolBar.m_volctrl.DecreaseVolume(); + break; + case CMD_SHADER_TOGGLE : + OnShaderToggle1(); + break; + case CMD_CLOSEAPP: + PostMessage(WM_CLOSE); + break; + case CMD_SETSPEED: + SetPlayingRate(_wtof((LPCWSTR)pCDS->lpData)); + break; + case CMD_SETPANSCAN: + AfxGetAppSettings().strPnSPreset = (LPCWSTR)pCDS->lpData; + ApplyPanNScanPresetString(); + break; + case CMD_OSDSHOWMESSAGE: + ShowOSDCustomMessageApi((MPC_OSDDATA*)pCDS->lpData); + break; + } +} + +void CMainFrame::SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...) +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (s.hMasterWnd) { + COPYDATASTRUCT CDS; + + va_list args; + va_start(args, fmt); + + int nBufferLen = _vsctprintf(fmt, args) + 1; // _vsctprintf doesn't count the null terminator + TCHAR* pBuff = DEBUG_NEW TCHAR[nBufferLen]; + _vstprintf_s(pBuff, nBufferLen, fmt, args); + + CDS.cbData = (DWORD)nBufferLen * sizeof(TCHAR); + CDS.dwData = nCommand; + CDS.lpData = (LPVOID)pBuff; + + ::SendMessage(s.hMasterWnd, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&CDS); + + va_end(args); + delete [] pBuff; + } +} + +void CMainFrame::SendNowPlayingToApi(bool sendtrackinfo) +{ + if (!AfxGetAppSettings().hMasterWnd) { + return; + } + + if (GetLoadState() == MLS::LOADED) { + CString title, author, description; + CString label; + CString strDur; + + if (GetPlaybackMode() == PM_FILE) { + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_TITLE), title); + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + label = !pli.m_label.IsEmpty() ? pli.m_label : pli.m_fns.GetHead(); + REFERENCE_TIME rtDur; + m_pMS->GetDuration(&rtDur); + strDur.Format(L"%.3f", rtDur / 10000000.0); + } + } else if (GetPlaybackMode() == PM_DVD) { + DVD_DOMAIN DVDDomain; + ULONG ulNumOfChapters = 0; + DVD_PLAYBACK_LOCATION2 Location; + + // Get current DVD Domain + if (SUCCEEDED(m_pDVDI->GetCurrentDomain(&DVDDomain))) { + switch (DVDDomain) { + case DVD_DOMAIN_Stop: + title = _T("DVD - Stopped"); + break; + case DVD_DOMAIN_FirstPlay: + title = _T("DVD - FirstPlay"); + break; + case DVD_DOMAIN_VideoManagerMenu: + title = _T("DVD - RootMenu"); + break; + case DVD_DOMAIN_VideoTitleSetMenu: + title = _T("DVD - TitleMenu"); + break; + case DVD_DOMAIN_Title: + title = _T("DVD - Title"); + break; + } + + // get title information + if (DVDDomain == DVD_DOMAIN_Title) { + // get current location (title number & chapter) + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location))) { + // get number of chapters in current title + VERIFY(SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters))); + } + + // get total time of title + DVD_HMSF_TIMECODE tcDur; + ULONG ulFlags; + if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { + // calculate duration in seconds + strDur.Format(L"%d", tcDur.bHours * 60 * 60 + tcDur.bMinutes * 60 + tcDur.bSeconds); + } + + // build string + // DVD - xxxxx|currenttitle|numberofchapters|currentchapter|titleduration + author.Format(L"%lu", Location.TitleNum); + description.Format(L"%lu", ulNumOfChapters); + label.Format(L"%lu", Location.ChapterNum); + } + } + } + + title.Replace(L"|", L"\\|"); + author.Replace(L"|", L"\\|"); + description.Replace(L"|", L"\\|"); + label.Replace(L"|", L"\\|"); + + CStringW buff; + buff.Format(L"%s|%s|%s|%s|%s", title.GetString(), author.GetString(), description.GetString(), label.GetString(), strDur.GetString()); + + SendAPICommand(CMD_NOWPLAYING, L"%s", static_cast(buff)); + if (sendtrackinfo) { + SendSubtitleTracksToApi(); + SendAudioTracksToApi(); + } + } +} + +void CMainFrame::SendSubtitleTracksToApi() +{ + CStringW strSubs; + if (GetLoadState() == MLS::LOADED) { + if (GetPlaybackMode() == PM_DVD) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) + && ulStreamsAvailable > 0) { + LCID DefLanguage; + int i = 0, iSelected = -1; + + DVD_SUBPICTURE_LANG_EXT ext; + if (FAILED(m_pDVDI->GetDefaultSubpictureLanguage(&DefLanguage, &ext))) { + return; + } + + for (i = 0; i < ulStreamsAvailable; i++) { + LCID Language; + if (FAILED(m_pDVDI->GetSubpictureLanguage(i, &Language))) { + continue; + } + + if (i == ulCurrentStream) { + iSelected = i; + } + + CString str; + if (Language) { + GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); + } else { + str.Format(IDS_AG_UNKNOWN, i + 1); + } + + DVD_SubpictureAttributes ATR; + if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(i, &ATR))) { + switch (ATR.LanguageExtension) { + case DVD_SP_EXT_NotSpecified: + default: + break; + case DVD_SP_EXT_Caption_Normal: + str += _T(""); + break; + case DVD_SP_EXT_Caption_Big: + str += _T(" (Big)"); + break; + case DVD_SP_EXT_Caption_Children: + str += _T(" (Children)"); + break; + case DVD_SP_EXT_CC_Normal: + str += _T(" (CC)"); + break; + case DVD_SP_EXT_CC_Big: + str += _T(" (CC Big)"); + break; + case DVD_SP_EXT_CC_Children: + str += _T(" (CC Children)"); + break; + case DVD_SP_EXT_Forced: + str += _T(" (Forced)"); + break; + case DVD_SP_EXT_DirectorComments_Normal: + str += _T(" (Director Comments)"); + break; + case DVD_SP_EXT_DirectorComments_Big: + str += _T(" (Director Comments, Big)"); + break; + case DVD_SP_EXT_DirectorComments_Children: + str += _T(" (Director Comments, Children)"); + break; + } + } + if (!strSubs.IsEmpty()) { + strSubs.Append(L"|"); + } + str.Replace(L"|", L"\\|"); + strSubs.Append(str); + } + if (AfxGetAppSettings().fEnableSubtitles) { + strSubs.AppendFormat(L"|%d", iSelected); + } else { + strSubs.Append(L"|-1"); + } + } + } else { + + POSITION pos = m_pSubStreams.GetHeadPosition(); + int i = 0, iSelected = -1; + if (pos) { + while (pos) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + + if (CComQIPtr pSSF = subInput.pSourceFilter) { + DWORD cStreams; + if (FAILED(pSSF->Count(&cStreams))) { + continue; + } + + for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { + DWORD dwFlags, dwGroup; + WCHAR* pszName = nullptr; + + if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + CString name(pszName); + CoTaskMemFree(pszName); + + if (dwGroup != 2) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream + && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + iSelected = j; + } + + if (!strSubs.IsEmpty()) { + strSubs.Append(L"|"); + } + name.Replace(L"|", L"\\|"); + strSubs.Append(name); + + i++; + } + } else { + CComPtr pSubStream = subInput.pSubStream; + if (!pSubStream) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + iSelected = i + pSubStream->GetStream(); + } + + for (int j = 0, cnt = pSubStream->GetStreamCount(); j < cnt; j++) { + WCHAR* pName = nullptr; + if (SUCCEEDED(pSubStream->GetStreamInfo(j, &pName, nullptr))) { + CString name(pName); + CoTaskMemFree(pName); + + if (!strSubs.IsEmpty()) { + strSubs.Append(L"|"); + } + name.Replace(L"|", L"\\|"); + strSubs.Append(name); + } + i++; + } + } + + } + if (AfxGetAppSettings().fEnableSubtitles) { + strSubs.AppendFormat(L"|%d", iSelected); + } else { + strSubs.Append(L"|-1"); + } + } else { + strSubs.Append(L"-1"); + } + } + } else { + strSubs.Append(L"-2"); + } + SendAPICommand(CMD_LISTSUBTITLETRACKS, L"%s", static_cast(strSubs)); +} + +void CMainFrame::SendAudioTracksToApi() +{ + CStringW strAudios; + + if (GetLoadState() == MLS::LOADED) { + DWORD cStreams = 0; + if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { + int currentStream = -1; + for (int i = 0; i < (int)cStreams; i++) { + AM_MEDIA_TYPE* pmt = nullptr; + DWORD dwFlags = 0; + LCID lcid = 0; + DWORD dwGroup = 0; + WCHAR* pszName = nullptr; + if (FAILED(m_pAudioSwitcherSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) { + return; + } + if (dwFlags == AMSTREAMSELECTINFO_EXCLUSIVE) { + currentStream = i; + } + CString name(pszName); + if (!strAudios.IsEmpty()) { + strAudios.Append(L"|"); + } + name.Replace(L"|", L"\\|"); + strAudios.AppendFormat(L"%s", name.GetString()); + if (pmt) { + DeleteMediaType(pmt); + } + if (pszName) { + CoTaskMemFree(pszName); + } + } + strAudios.AppendFormat(L"|%d", currentStream); + + } else { + strAudios.Append(L"-1"); + } + } else { + strAudios.Append(L"-2"); + } + SendAPICommand(CMD_LISTAUDIOTRACKS, L"%s", static_cast(strAudios)); + +} + +void CMainFrame::SendPlaylistToApi() +{ + CStringW strPlaylist; + POSITION pos = m_wndPlaylistBar.m_pl.GetHeadPosition(), pos2; + + while (pos) { + CPlaylistItem& pli = m_wndPlaylistBar.m_pl.GetNext(pos); + + if (pli.m_type == CPlaylistItem::file) { + pos2 = pli.m_fns.GetHeadPosition(); + while (pos2) { + CString fn = pli.m_fns.GetNext(pos2); + if (!strPlaylist.IsEmpty()) { + strPlaylist.Append(L"|"); + } + fn.Replace(L"|", L"\\|"); + strPlaylist.AppendFormat(L"%s", fn.GetString()); + } + } + } + if (strPlaylist.IsEmpty()) { + strPlaylist.Append(L"-1"); + } else { + strPlaylist.AppendFormat(L"|%d", m_wndPlaylistBar.GetSelIdx()); + } + SendAPICommand(CMD_PLAYLIST, L"%s", static_cast(strPlaylist)); +} + +void CMainFrame::SendCurrentPositionToApi(bool fNotifySeek) +{ + if (!AfxGetAppSettings().hMasterWnd) { + return; + } + + if (GetLoadState() == MLS::LOADED) { + CStringW strPos; + + if (GetPlaybackMode() == PM_FILE) { + REFERENCE_TIME rtCur; + m_pMS->GetCurrentPosition(&rtCur); + strPos.Format(L"%.3f", rtCur / 10000000.0); + } else if (GetPlaybackMode() == PM_DVD) { + DVD_PLAYBACK_LOCATION2 Location; + // get current location while playing disc, will return 0, if at a menu + if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) { + strPos.Format(L"%d", Location.TimeCode.bHours * 60 * 60 + Location.TimeCode.bMinutes * 60 + Location.TimeCode.bSeconds); + } + } + + SendAPICommand(fNotifySeek ? CMD_NOTIFYSEEK : CMD_CURRENTPOSITION, strPos); + } +} + +void CMainFrame::ShowOSDCustomMessageApi(const MPC_OSDDATA* osdData) +{ + m_OSD.DisplayMessage((OSD_MESSAGEPOS)osdData->nMsgPos, osdData->strMsg, osdData->nDurationMS); +} + +void CMainFrame::JumpOfNSeconds(int nSeconds) +{ + if (GetLoadState() == MLS::LOADED) { + REFERENCE_TIME rtCur; + + if (GetPlaybackMode() == PM_FILE) { + m_pMS->GetCurrentPosition(&rtCur); + DVD_HMSF_TIMECODE tcCur = RT2HMSF(rtCur); + long lPosition = tcCur.bHours * 60 * 60 + tcCur.bMinutes * 60 + tcCur.bSeconds + nSeconds; + + // revert the update position to REFERENCE_TIME format + tcCur.bHours = (BYTE)(lPosition / 3600); + tcCur.bMinutes = (lPosition / 60) % 60; + tcCur.bSeconds = lPosition % 60; + rtCur = HMSF2RT(tcCur); + + // quick and dirty trick: + // pause->seekto->play seems to prevents some strange + // video effect (ex. locks for a while and than running fast) + if (!m_fAudioOnly) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + SeekTo(rtCur); + if (!m_fAudioOnly) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + // show current position overridden by play command + m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 2000); + } + } + } +} + +// TODO : to be finished ! +//void CMainFrame::AutoSelectTracks() +//{ +// LCID DefAudioLanguageLcid [2] = {MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT), MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT)}; +// int DefAudioLanguageIndex [2] = {-1, -1}; +// LCID DefSubtitleLanguageLcid [2] = {0, MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)}; +// int DefSubtitleLanguageIndex[2] = {-1, -1}; +// LCID Language = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT); +// +// if ((m_iMediaLoadState == MLS::LOADING) || (m_iMediaLoadState == MLS::LOADED)) +// { +// if (GetPlaybackMode() == PM_FILE) +// { +// CComQIPtr pSS = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); +// +// DWORD cStreams = 0; +// if (pSS && SUCCEEDED(pSS->Count(&cStreams))) +// { +// for (int i = 0; i < (int)cStreams; i++) +// { +// AM_MEDIA_TYPE* pmt = nullptr; +// DWORD dwFlags = 0; +// LCID lcid = 0; +// DWORD dwGroup = 0; +// WCHAR* pszName = nullptr; +// if (FAILED(pSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) +// return; +// } +// } +// +// POSITION pos = m_pSubStreams.GetHeadPosition(); +// while (pos) +// { +// CComPtr pSubStream = m_pSubStreams.GetNext(pos).subStream; +// if (!pSubStream) continue; +// +// for (int i = 0, j = pSubStream->GetStreamCount(); i < j; i++) +// { +// WCHAR* pName = nullptr; +// if (SUCCEEDED(pSubStream->GetStreamInfo(i, &pName, &Language))) +// { +// if (DefAudioLanguageLcid[0] == Language) DefSubtitleLanguageIndex[0] = i; +// if (DefSubtitleLanguageLcid[1] == Language) DefSubtitleLanguageIndex[1] = i; +// CoTaskMemFree(pName); +// } +// } +// } +// } +// else if (GetPlaybackMode() == PM_DVD) +// { +// ULONG ulStreamsAvailable, ulCurrentStream; +// BOOL bIsDisabled; +// +// if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) +// { +// for (ULONG i = 0; i < ulStreamsAvailable; i++) +// { +// DVD_SubpictureAttributes ATR; +// if (SUCCEEDED(m_pDVDI->GetSubpictureLanguage(i, &Language))) +// { +// // Auto select forced subtitle +// if ((DefAudioLanguageLcid[0] == Language) && (ATR.LanguageExtension == DVD_SP_EXT_Forced)) +// DefSubtitleLanguageIndex[0] = i; +// +// if (DefSubtitleLanguageLcid[1] == Language) DefSubtitleLanguageIndex[1] = i; +// } +// } +// } +// +// if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulStreamsAvailable, &ulCurrentStream))) +// { +// for (ULONG i = 0; i < ulStreamsAvailable; i++) +// { +// if (SUCCEEDED(m_pDVDI->GetAudioLanguage(i, &Language))) +// { +// if (DefAudioLanguageLcid[0] == Language) DefAudioLanguageIndex[0] = i; +// if (DefAudioLanguageLcid[1] == Language) DefAudioLanguageIndex[1] = i; +// } +// } +// } +// +// // Select best audio/subtitles tracks +// if (DefAudioLanguageLcid[0] != -1) +// { +// m_pDVDC->SelectAudioStream(DefAudioLanguageIndex[0], DVD_CMD_FLAG_Block, nullptr); +// if (DefSubtitleLanguageIndex[0] != -1) +// m_pDVDC->SelectSubpictureStream(DefSubtitleLanguageIndex[0], DVD_CMD_FLAG_Block, nullptr); +// } +// else if ((DefAudioLanguageLcid[1] != -1) && (DefSubtitleLanguageLcid[1] != -1)) +// { +// m_pDVDC->SelectAudioStream (DefAudioLanguageIndex[1], DVD_CMD_FLAG_Block, nullptr); +// m_pDVDC->SelectSubpictureStream (DefSubtitleLanguageIndex[1], DVD_CMD_FLAG_Block, nullptr); +// } +// } +// +// +// } +//} + +void CMainFrame::OnFileOpendirectory() +{ + if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar)) { + return; + } + + auto& s = AfxGetAppSettings(); + CString strTitle(StrRes(IDS_MAINFRM_DIR_TITLE)); + CString path; + + MPCFolderPickerDialog fd(ForceTrailingSlash(s.lastFileOpenDirPath), FOS_PATHMUSTEXIST, GetModalParent(), IDS_MAINFRM_DIR_CHECK); + fd.m_ofn.lpstrTitle = strTitle; + + if (fd.DoModal() == IDOK) { + path = fd.GetPathName(); //getfolderpath() does not work correctly for CFolderPickerDialog + } else { + return; + } + + BOOL recur = TRUE; + fd.GetCheckButtonState(IDS_MAINFRM_DIR_CHECK, recur); + COpenDirHelper::m_incl_subdir = !!recur; + + // If we got a link file that points to a directory, follow the link + if (PathUtils::IsLinkFile(path)) { + CString resolvedPath = PathUtils::ResolveLinkFile(path); + if (PathUtils::IsDir(resolvedPath)) { + path = resolvedPath; + } + } + + path = ForceTrailingSlash(path); + s.lastFileOpenDirPath = path; + + CAtlList sl; + sl.AddTail(path); + if (COpenDirHelper::m_incl_subdir) { + PathUtils::RecurseAddDir(path, sl); + } + + m_wndPlaylistBar.Open(sl, true); + OpenCurPlaylistItem(); +} + +HRESULT CMainFrame::CreateThumbnailToolbar() +{ + if (!this || !AfxGetAppSettings().bUseEnhancedTaskBar) { + return E_FAIL; + } + + if (m_pTaskbarList || SUCCEEDED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER))) { + bool bRTLLayout = false; // Assume left-to-right layout by default + // Try to locate the window used to display the task bar + if (CWnd* pTaskBarWnd = FindWindow(_T("TaskListThumbnailWnd"), nullptr)) { + bRTLLayout = !!(pTaskBarWnd->GetExStyle() & WS_EX_LAYOUTRTL); + } + + CMPCPngImage image; + if (!image.Load(IDF_WIN7_TOOLBAR)) { + return E_FAIL; + } + + CSize size = image.GetSize(); + + if (bRTLLayout) { // We don't want the buttons to be mirrored so we pre-mirror them + // Create memory DCs for the source and destination bitmaps + CDC sourceDC, destDC; + sourceDC.CreateCompatibleDC(nullptr); + destDC.CreateCompatibleDC(nullptr); + // Swap the source bitmap with an empty one + CBitmap sourceImg; + sourceImg.Attach(image.Detach()); + // Create a temporary DC + CClientDC clientDC(nullptr); + // Create the destination bitmap + image.CreateCompatibleBitmap(&clientDC, size.cx, size.cy); + // Select the bitmaps into the DCs + HGDIOBJ oldSourceDCObj = sourceDC.SelectObject(sourceImg); + HGDIOBJ oldDestDCObj = destDC.SelectObject(image); + // Actually flip the bitmap + destDC.StretchBlt(0, 0, size.cx, size.cy, + &sourceDC, size.cx, 0, -size.cx, size.cy, + SRCCOPY); + // Reselect the old objects back into their DCs + sourceDC.SelectObject(oldSourceDCObj); + destDC.SelectObject(oldDestDCObj); + + sourceDC.DeleteDC(); + destDC.DeleteDC(); + } + + CImageList imageList; + imageList.Create(size.cy, size.cy, ILC_COLOR32, size.cx / size.cy, 0); + imageList.Add(&image, nullptr); + + if (SUCCEEDED(m_pTaskbarList->ThumbBarSetImageList(m_hWnd, imageList.GetSafeHandle()))) { + THUMBBUTTON buttons[5] = {}; + + for (size_t i = 0; i < _countof(buttons); i++) { + buttons[i].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS; + buttons[i].dwFlags = THBF_DISABLED; + buttons[i].iBitmap = 0; // Will be set later + } + + // PREVIOUS + buttons[0].iId = IDTB_BUTTON3; + // STOP + buttons[1].iId = IDTB_BUTTON1; + // PLAY/PAUSE + buttons[2].iId = IDTB_BUTTON2; + // NEXT + buttons[3].iId = IDTB_BUTTON4; + // FULLSCREEN + buttons[4].iId = IDTB_BUTTON5; + + if (bRTLLayout) { // We don't want the buttons to be mirrored so we pre-mirror them + std::reverse(buttons, buttons + _countof(buttons)); + } + + if (SUCCEEDED(m_pTaskbarList->ThumbBarAddButtons(m_hWnd, _countof(buttons), buttons))) { + return UpdateThumbarButton(); + } + } + } + + return E_FAIL; +} + +HRESULT CMainFrame::UpdateThumbarButton() +{ + MPC_PLAYSTATE state = PS_STOP; + if (GetLoadState() == MLS::LOADED) { + switch (GetMediaState()) { + case State_Running: + state = PS_PLAY; + break; + case State_Paused: + state = PS_PAUSE; + break; + } + } + return UpdateThumbarButton(state); +} + +HRESULT CMainFrame::UpdateThumbarButton(MPC_PLAYSTATE iPlayState) +{ + if (!m_pTaskbarList) { + return E_FAIL; + } + + THUMBBUTTON buttons[5] = {}; + + for (size_t i = 0; i < _countof(buttons); i++) { + buttons[i].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS; + } + + buttons[0].iId = IDTB_BUTTON3; + buttons[1].iId = IDTB_BUTTON1; + buttons[2].iId = IDTB_BUTTON2; + buttons[3].iId = IDTB_BUTTON4; + buttons[4].iId = IDTB_BUTTON5; + + const CAppSettings& s = AfxGetAppSettings(); + + if (!s.bUseEnhancedTaskBar) { + m_pTaskbarList->SetOverlayIcon(m_hWnd, nullptr, L""); + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); + + for (size_t i = 0; i < _countof(buttons); i++) { + buttons[i].dwFlags = THBF_HIDDEN; + } + } else { + buttons[0].iBitmap = 0; + StringCchCopy(buttons[0].szTip, _countof(buttons[0].szTip), ResStr(IDS_AG_PREVIOUS)); + + buttons[1].iBitmap = 1; + StringCchCopy(buttons[1].szTip, _countof(buttons[1].szTip), ResStr(IDS_AG_STOP)); + + buttons[2].iBitmap = 3; + StringCchCopy(buttons[2].szTip, _countof(buttons[2].szTip), ResStr(IDS_AG_PLAYPAUSE)); + + buttons[3].iBitmap = 4; + StringCchCopy(buttons[3].szTip, _countof(buttons[3].szTip), ResStr(IDS_AG_NEXT)); + + buttons[4].iBitmap = 5; + StringCchCopy(buttons[4].szTip, _countof(buttons[4].szTip), ResStr(IDS_AG_FULLSCREEN)); + + if (GetLoadState() == MLS::LOADED) { + HICON hIcon = nullptr; + + buttons[0].dwFlags = (!s.fUseSearchInFolder && m_wndPlaylistBar.GetCount() <= 1 && (m_pCB && m_pCB->ChapGetCount() <= 1)) ? THBF_DISABLED : THBF_ENABLED; + buttons[3].dwFlags = (!s.fUseSearchInFolder && m_wndPlaylistBar.GetCount() <= 1 && (m_pCB && m_pCB->ChapGetCount() <= 1)) ? THBF_DISABLED : THBF_ENABLED; + buttons[4].dwFlags = THBF_ENABLED; + + if (iPlayState == PS_PLAY) { + buttons[1].dwFlags = THBF_ENABLED; + buttons[2].dwFlags = THBF_ENABLED; + buttons[2].iBitmap = 2; + + hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_PLAY), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + m_pTaskbarList->SetProgressState(m_hWnd, m_wndSeekBar.HasDuration() ? TBPF_NORMAL : TBPF_NOPROGRESS); + } else if (iPlayState == PS_STOP) { + buttons[1].dwFlags = THBF_DISABLED; + buttons[2].dwFlags = THBF_ENABLED; + buttons[2].iBitmap = 3; + + hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_STOP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); + } else if (iPlayState == PS_PAUSE) { + buttons[1].dwFlags = THBF_ENABLED; + buttons[2].dwFlags = THBF_ENABLED; + buttons[2].iBitmap = 3; + + hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_PAUSE), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + m_pTaskbarList->SetProgressState(m_hWnd, m_wndSeekBar.HasDuration() ? TBPF_PAUSED : TBPF_NOPROGRESS); + } + + if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { + buttons[0].dwFlags = THBF_DISABLED; + buttons[1].dwFlags = THBF_DISABLED; + buttons[2].dwFlags = THBF_DISABLED; + buttons[3].dwFlags = THBF_DISABLED; + } + + m_pTaskbarList->SetOverlayIcon(m_hWnd, hIcon, L""); + + if (hIcon != nullptr) { + DestroyIcon(hIcon); + } + } else { + for (size_t i = 0; i < _countof(buttons); i++) { + buttons[i].dwFlags = THBF_DISABLED; + } + + m_pTaskbarList->SetOverlayIcon(m_hWnd, nullptr, L""); + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); + } + + UpdateThumbnailClip(); + } + + // Try to locate the window used to display the task bar to check if it is RTLed + if (CWnd* pTaskBarWnd = FindWindow(_T("TaskListThumbnailWnd"), nullptr)) { + // We don't want the buttons to be mirrored so we pre-mirror them + if (pTaskBarWnd->GetExStyle() & WS_EX_LAYOUTRTL) { + for (UINT i = 0; i < _countof(buttons); i++) { + buttons[i].iBitmap = _countof(buttons) - buttons[i].iBitmap; + } + std::reverse(buttons, buttons + _countof(buttons)); + } + } + + return m_pTaskbarList->ThumbBarUpdateButtons(m_hWnd, _countof(buttons), buttons); +} + +HRESULT CMainFrame::UpdateThumbnailClip() +{ + if (!m_pTaskbarList || !m_hWnd || !m_wndView.m_hWnd) { + return E_FAIL; + } + + const CAppSettings& s = AfxGetAppSettings(); + + CRect r; + m_wndView.GetClientRect(&r); + if (s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) { + r.OffsetRect(0, GetSystemMetrics(SM_CYMENU)); + } + + if (!s.bUseEnhancedTaskBar || (GetLoadState() != MLS::LOADED) || IsFullScreenMode() || r.Width() <= 0 || r.Height() <= 0) { + return m_pTaskbarList->SetThumbnailClip(m_hWnd, nullptr); + } + + return m_pTaskbarList->SetThumbnailClip(m_hWnd, &r); +} + +BOOL CMainFrame::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext) +{ + if (defaultMPCThemeMenu == nullptr) { + defaultMPCThemeMenu = DEBUG_NEW CMPCThemeMenu(); + } + if (lpszMenuName != NULL) { + defaultMPCThemeMenu->LoadMenu(lpszMenuName); + + if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), defaultMPCThemeMenu->m_hMenu, (LPVOID)pContext)) { + return FALSE; + } + defaultMPCThemeMenu->fulfillThemeReqs(true); + + return TRUE; + } + return FALSE; +} + +void CMainFrame::enableFileDialogHook(CMPCThemeUtil* helper) { + if (AfxGetAppSettings().bWindows10DarkThemeActive) { //hard coded behavior for windows 10 dark theme file dialogs, irrespsective of theme loaded by user (fixing windows bugs) + watchingDialog = themableDialogTypes::windowsFileDialog; + dialogHookHelper = helper; + } +} + +void CMainFrame::enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type) { + if (AppIsThemeLoaded()) { + watchingDialog = type; + dialogHookHelper = helper; + } +} + +bool CMainFrame::isSafeZone(CPoint pt) { + CRect r; + m_wndSeekBar.GetClientRect(r); + m_wndSeekBar.MapWindowPoints(this, r); + r.InflateRect(0, m_dpi.ScaleY(16)); + if (r.top < 0) r.top = 0; + + if (r.PtInRect(pt)) { + TRACE(_T("Click was inside safezone!\n")); + return true; + } + return false; +} + +LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (!m_hWnd) { + ASSERT(false); + return 0; + } + if (message == WM_ACTIVATE || message == WM_SETFOCUS) { + if (AfxGetMyApp()->m_fClosingState) { + TRACE(_T("Dropped WindowProc: message %u value %d\n"), message, LOWORD(wParam)); + return 0; + } + } + + if ((message == WM_COMMAND) && (THBN_CLICKED == HIWORD(wParam))) { + int const wmId = LOWORD(wParam); + switch (wmId) { + case IDTB_BUTTON1: + SendMessage(WM_COMMAND, ID_PLAY_STOP); + break; + case IDTB_BUTTON2: + SendMessage(WM_COMMAND, ID_PLAY_PLAYPAUSE); + break; + case IDTB_BUTTON3: + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACK); + break; + case IDTB_BUTTON4: + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); + break; + case IDTB_BUTTON5: + WINDOWPLACEMENT wp; + GetWindowPlacement(&wp); + if (wp.showCmd == SW_SHOWMINIMIZED) { + SendMessage(WM_SYSCOMMAND, SC_RESTORE, -1); + } + SetForegroundWindow(); + SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN); + break; + default: + break; + } + return 0; + } else if (watchingDialog != themableDialogTypes::None && nullptr != dialogHookHelper && message == WM_ACTIVATE && LOWORD(wParam) == WA_INACTIVE) { + dialogHookHelper->themableDialogHandle = (HWND)lParam; + foundDialog = watchingDialog; + watchingDialog = themableDialogTypes::None; + //capture but process message normally + } else if (message == WM_GETICON && foundDialog == themableDialogTypes::windowsFileDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { + dialogHookHelper->subClassFileDialog(this); + foundDialog = themableDialogTypes::None; + } else if (message == WM_ENTERIDLE && foundDialog == themableDialogTypes::toolbarCustomizeDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { + dialogHookHelper->subClassTBCustomizeDialog(this, &m_wndToolBar); + foundDialog = themableDialogTypes::None; + } + + if (message == WM_NCLBUTTONDOWN && wParam == HTCAPTION && !m_pMVRSR) { + CPoint pt = CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + ScreenToClient(&pt); + if (isSafeZone(pt)) { + return 0; + } + } + + LRESULT ret = 0; + bool bCallOurProc = true; + if (m_pMVRSR) { + // call madVR window proc directly when the interface is available + switch (message) { + case WM_CLOSE: + break; + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + // CMouseWnd will call madVR window proc + break; + default: + bCallOurProc = !m_pMVRSR->ParentWindowProc(m_hWnd, message, &wParam, &lParam, &ret); + } + } + if (bCallOurProc && m_hWnd) { + ret = __super::WindowProc(message, wParam, lParam); + } + + return ret; +} + +bool CMainFrame::IsAeroSnapped() +{ + bool ret = false; + WINDOWPLACEMENT wp = { sizeof(wp) }; + if (IsWindowVisible() && !IsZoomed() && !IsIconic() && GetWindowPlacement(&wp)) { + CRect rect; + GetWindowRect(rect); + if (HMONITOR hMon = MonitorFromRect(rect, MONITOR_DEFAULTTONULL)) { + MONITORINFO mi = { sizeof(mi) }; + if (GetMonitorInfo(hMon, &mi)) { + CRect wpRect(wp.rcNormalPosition); + wpRect.OffsetRect(mi.rcWork.left - mi.rcMonitor.left, mi.rcWork.top - mi.rcMonitor.top); + ret = !!(rect != wpRect); + } else { + ASSERT(FALSE); + } + } + } + return ret; +} + +UINT CMainFrame::OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData) +{ + static BOOL bWasPausedBeforeSuspention; + + switch (nPowerEvent) { + case PBT_APMSUSPEND: // System is suspending operation. + TRACE(_T("OnPowerBroadcast - suspending\n")); // For user tracking + bWasPausedBeforeSuspention = FALSE; // Reset value + + if (GetMediaState() == State_Running) { + bWasPausedBeforeSuspention = TRUE; + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); // Pause + } + break; + case PBT_APMRESUMESUSPEND: // System is resuming operation + TRACE(_T("OnPowerBroadcast - resuming\n")); // For user tracking + + // force seek to current position when resuming playback to re-initialize the video decoder + m_dwLastPause = 1; + + // Resume if we paused before suspension. + if (bWasPausedBeforeSuspention) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); // Resume + } + break; + } + + return __super::OnPowerBroadcast(nPowerEvent, nEventData); +} + +#define NOTIFY_FOR_THIS_SESSION 0 + +void CMainFrame::OnSessionChange(UINT nSessionState, UINT nId) +{ + if (AfxGetAppSettings().bLockNoPause) { + return; + } + + static BOOL bWasPausedBeforeSessionChange; + + switch (nSessionState) { + case WTS_SESSION_LOCK: + TRACE(_T("OnSessionChange - Lock session\n")); + bWasPausedBeforeSessionChange = FALSE; + + if (GetMediaState() == State_Running && !m_fAudioOnly) { + bWasPausedBeforeSessionChange = TRUE; + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + break; + case WTS_SESSION_UNLOCK: + TRACE(_T("OnSessionChange - UnLock session\n")); + + if (bWasPausedBeforeSessionChange) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + break; + } +} + +void CMainFrame::WTSRegisterSessionNotification() +{ + const WinapiFunc + fnWtsRegisterSessionNotification = { _T("wtsapi32.dll"), "WTSRegisterSessionNotification" }; + + if (fnWtsRegisterSessionNotification) { + fnWtsRegisterSessionNotification(m_hWnd, NOTIFY_FOR_THIS_SESSION); + } +} + +void CMainFrame::WTSUnRegisterSessionNotification() +{ + const WinapiFunc + fnWtsUnRegisterSessionNotification = { _T("wtsapi32.dll"), "WTSUnRegisterSessionNotification" }; + + if (fnWtsUnRegisterSessionNotification) { + fnWtsUnRegisterSessionNotification(m_hWnd); + } +} + +void CMainFrame::UpdateSkypeHandler() +{ + const auto& s = AfxGetAppSettings(); + if (s.bNotifySkype && !m_pSkypeMoodMsgHandler) { + m_pSkypeMoodMsgHandler.Attach(DEBUG_NEW SkypeMoodMsgHandler()); + m_pSkypeMoodMsgHandler->Connect(m_hWnd); + } else if (!s.bNotifySkype && m_pSkypeMoodMsgHandler) { + m_pSkypeMoodMsgHandler.Free(); + } +} + +void CMainFrame::UpdateSeekbarChapterBag() +{ + const auto& s = AfxGetAppSettings(); + if (s.fShowChapters && m_pCB && m_pCB->ChapGetCount() > 0) { + m_wndSeekBar.SetChapterBag(m_pCB); + m_OSD.SetChapterBag(m_pCB); + } else { + m_wndSeekBar.RemoveChapters(); + m_OSD.RemoveChapters(); + } +} + +void CMainFrame::UpdateAudioSwitcher() +{ + CAppSettings& s = AfxGetAppSettings(); + CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); + + if (pASF) { + pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); + pASF->EnableDownSamplingTo441(s.fDownSampleTo441); + pASF->SetAudioTimeShift(s.fAudioTimeShift ? 10000i64 * s.iAudioTimeShift : 0); + pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); + } +} + +void CMainFrame::LoadArtToViews(const CString& imagePath) +{ + m_wndView.LoadImg(imagePath); + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->LoadImg(imagePath); + } +} + +void CMainFrame::LoadArtToViews(std::vector buffer) +{ + m_wndView.LoadImg(buffer); + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->LoadImg(buffer); + } +} + +void CMainFrame::ClearArtFromViews() +{ + m_wndView.LoadImg(); + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->LoadImg(); + } +} + +void CMainFrame::UpdateControlState(UpdateControlTarget target) +{ + const auto& s = AfxGetAppSettings(); + switch (target) { + case UPDATE_VOLUME_STEP: + m_wndToolBar.m_volctrl.SetPageSize(s.nVolumeStep); + break; + case UPDATE_LOGO: + if (GetLoadState() == MLS::LOADED && m_fAudioOnly && s.bEnableCoverArt) { + CString filename = m_wndPlaylistBar.GetCurFileName(); + CString filename_no_ext; + CString filedir; + if (!PathUtils::IsURL(filename)) { + CPath path = CPath(filename); + if (path.FileExists()) { + path.RemoveExtension(); + filename_no_ext = path.m_strPath; + path.RemoveFileSpec(); + filedir = path.m_strPath; + } + } + + CString author; + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); + + CComQIPtr pFilterGraph = m_pGB; + std::vector internalCover; + if (CoverArt::FindEmbedded(pFilterGraph, internalCover)) { + LoadArtToViews(internalCover); + m_currentCoverPath = filename; + m_currentCoverAuthor = author; + } else { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli) && !pli.m_cover.IsEmpty() && CPath(pli.m_cover).FileExists()) { + LoadArtToViews(pli.m_cover); + } else if (!filedir.IsEmpty() && (m_currentCoverPath != filedir || m_currentCoverAuthor != author || currentCoverIsFileArt)) { + CString img = CoverArt::FindExternal(filename_no_ext, filedir, author, currentCoverIsFileArt); + LoadArtToViews(img); + m_currentCoverPath = filedir; + m_currentCoverAuthor = author; + } else if (!m_wndView.IsCustomImgLoaded()) { + ClearArtFromViews(); + } + } + } else { + m_currentCoverPath.Empty(); + m_currentCoverAuthor.Empty(); + ClearArtFromViews(); + } + break; + case UPDATE_SKYPE: + UpdateSkypeHandler(); + break; + case UPDATE_SEEKBAR_CHAPTERS: + UpdateSeekbarChapterBag(); + break; + case UPDATE_WINDOW_TITLE: + OpenSetupWindowTitle(); + break; + case UPDATE_AUDIO_SWITCHER: + UpdateAudioSwitcher(); + break; + case UPDATE_CONTROLS_VISIBILITY: + m_controls.UpdateToolbarsVisibility(); + break; + case UPDATE_CHILDVIEW_CURSOR_HACK: + // HACK: windowed (not renderless) video renderers created in graph thread do not + // produce WM_MOUSEMOVE message when we release mouse capture on top of it, here's a workaround + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::CHILDVIEW_CURSOR_HACK, std::bind(&CChildView::Invalidate, &m_wndView, FALSE), 16); + break; + default: + ASSERT(FALSE); + } +} + +void CMainFrame::ReloadMenus() { + // CMenu defaultMenu; + CMenu* oldMenu; + + // Destroy the dynamic menus before reloading the main menus + DestroyDynamicMenus(); + + // Reload the main menus + m_popupMenu.DestroyMenu(); + m_popupMenu.LoadMenu(IDR_POPUP); + m_mainPopupMenu.DestroyMenu(); + m_mainPopupMenu.LoadMenu(IDR_POPUPMAIN); + + oldMenu = GetMenu(); + defaultMPCThemeMenu = DEBUG_NEW CMPCThemeMenu(); //will have been destroyed + defaultMPCThemeMenu->LoadMenu(IDR_MAINFRAME); + if (oldMenu) { + // Attach the new menu to the window only if there was a menu before + SetMenu(defaultMPCThemeMenu); + // and then destroy the old one + oldMenu->DestroyMenu(); + delete oldMenu; + } + //we don't detach because we retain the cmenu + //m_hMenuDefault = defaultMenu.Detach(); + m_hMenuDefault = defaultMPCThemeMenu->GetSafeHmenu(); + + m_popupMenu.fulfillThemeReqs(); + m_mainPopupMenu.fulfillThemeReqs(); + defaultMPCThemeMenu->fulfillThemeReqs(true); + + // Reload the dynamic menus + CreateDynamicMenus(); +} + + +void CMainFrame::UpdateUILanguage() +{ + ReloadMenus(); + + // Reload the static bars + OpenSetupInfoBar(); + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + UpdateCurrentChannelInfo(false, false); + } + OpenSetupStatsBar(); + + // Reload the debug shaders dialog if need be + if (m_pDebugShaders && IsWindow(m_pDebugShaders->m_hWnd)) { + BOOL bWasVisible = m_pDebugShaders->IsWindowVisible(); + VERIFY(m_pDebugShaders->DestroyWindow()); + m_pDebugShaders = std::make_unique(); + if (bWasVisible) { + m_pDebugShaders->ShowWindow(SW_SHOWNA); + // Don't steal focus from main frame + SetActiveWindow(); + } + } +} + +bool CMainFrame::OpenBD(CString Path) +{ + CHdmvClipInfo ClipInfo; + CString strPlaylistFile; + CHdmvClipInfo::HdmvPlaylist MainPlaylist; + +#if INTERNAL_SOURCEFILTER_MPEG + const CAppSettings& s = AfxGetAppSettings(); + bool InternalMpegSplitter = s.SrcFilters[SRC_MPEG] || s.SrcFilters[SRC_MPEGTS]; +#else + bool InternalMpegSplitter = false; +#endif + + m_LastOpenBDPath = Path; + + CString ext = CPath(Path).GetExtension(); + ext.MakeLower(); + + if ((CPath(Path).IsDirectory() && Path.Find(_T("\\BDMV"))) + || CPath(Path + _T("\\BDMV")).IsDirectory() + || (!ext.IsEmpty() && ext == _T(".bdmv"))) { + if (!ext.IsEmpty() && ext == _T(".bdmv")) { + Path.Replace(_T("\\BDMV\\"), _T("\\")); + CPath _Path(Path); + _Path.RemoveFileSpec(); + Path = CString(_Path); + } else if (Path.Find(_T("\\BDMV"))) { + Path.Replace(_T("\\BDMV"), _T("\\")); + } + if (SUCCEEDED(ClipInfo.FindMainMovie(Path, strPlaylistFile, MainPlaylist, m_MPLSPlaylist))) { + m_bIsBDPlay = true; + + m_bHasBDMeta = ClipInfo.ReadMeta(Path, m_BDMeta); + + if (!InternalMpegSplitter && !ext.IsEmpty() && ext == _T(".bdmv")) { + return false; + } else { + m_wndPlaylistBar.Empty(); + CAtlList sl; + + if (InternalMpegSplitter) { + sl.AddTail(CString(strPlaylistFile)); + } else { + sl.AddTail(CString(Path + _T("\\BDMV\\index.bdmv"))); + } + + m_wndPlaylistBar.Append(sl, false); + OpenCurPlaylistItem(); + return true; + } + } + } + + m_LastOpenBDPath = _T(""); + return false; +} + +// Returns the the corresponding subInput or nullptr in case of error. +// i is modified to reflect the locale index of track +SubtitleInput* CMainFrame::GetSubtitleInput(int& i, bool bIsOffset /*= false*/) +{ + // Only 1, 0 and -1 are supported offsets + if ((bIsOffset && (i < -1 || i > 1)) || (!bIsOffset && i < 0)) { + return nullptr; + } + + POSITION pos = m_pSubStreams.GetHeadPosition(); + SubtitleInput* pSubInput = nullptr, *pSubInputPrec = nullptr; + int iLocalIdx = -1, iLocalIdxPrec = -1; + bool bNextTrack = false; + + while (pos && !pSubInput) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + + if (CComQIPtr pSSF = subInput.pSourceFilter) { + DWORD cStreams; + if (FAILED(pSSF->Count(&cStreams))) { + continue; + } + + for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { + DWORD dwFlags, dwGroup; + + if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { + continue; + } + + if (dwGroup != 2) { + continue; + } + + if (bIsOffset) { + if (bNextTrack) { // We detected previously that the next subtitles track is the one we want to select + pSubInput = &subInput; + iLocalIdx = j; + break; + } else if (subInput.pSubStream == m_pCurrentSubInput.pSubStream + && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + if (i == 0) { + pSubInput = &subInput; + iLocalIdx = j; + break; + } else if (i > 0) { + bNextTrack = true; // We want to the select the next subtitles track + } else { + // We want the previous subtitles track and we know which one it is + if (pSubInputPrec) { + pSubInput = pSubInputPrec; + iLocalIdx = iLocalIdxPrec; + break; + } + } + } + + pSubInputPrec = &subInput; + iLocalIdxPrec = j; + } else { + if (i == 0) { + pSubInput = &subInput; + iLocalIdx = j; + break; + } + + i--; + } + } + } else { + if (bIsOffset) { + if (bNextTrack) { // We detected previously that the next subtitles track is the one we want to select + pSubInput = &subInput; + iLocalIdx = 0; + break; + } else if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + iLocalIdx = subInput.pSubStream->GetStream() + i; + if (iLocalIdx >= 0 && iLocalIdx < subInput.pSubStream->GetStreamCount()) { + // The subtitles track we want to select is part of this substream + pSubInput = &subInput; + } else if (i > 0) { // We want to the select the next subtitles track + bNextTrack = true; + } else { + // We want the previous subtitles track and we know which one it is + if (pSubInputPrec) { + pSubInput = pSubInputPrec; + iLocalIdx = iLocalIdxPrec; + } + } + } else { + pSubInputPrec = &subInput; + iLocalIdxPrec = subInput.pSubStream->GetStreamCount() - 1; + } + } else { + if (i < subInput.pSubStream->GetStreamCount()) { + pSubInput = &subInput; + iLocalIdx = i; + } else { + i -= subInput.pSubStream->GetStreamCount(); + } + } + } + + // Handle special cases + if (!pos && !pSubInput && bIsOffset) { + if (bNextTrack) { // The last subtitles track was selected and we want the next one + // Let's restart the loop to select the first subtitles track + pos = m_pSubStreams.GetHeadPosition(); + } else if (i < 0) { // The first subtitles track was selected and we want the previous one + pSubInput = pSubInputPrec; // We select the last track + iLocalIdx = iLocalIdxPrec; + } + } + } + + i = iLocalIdx; + + return pSubInput; +} + +CString CMainFrame::GetFileName() +{ + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + CString path(m_wndPlaylistBar.GetCurFileName(true)); + if (!pli.m_bYoutubeDL && m_pFSF) { + CComHeapPtr pFN; + if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, nullptr))) { + path = pFN; + } + } + if (PathUtils::IsURL(path)) { + path = ShortenURL(path); + } + return pli.m_bYoutubeDL ? path : PathUtils::StripPathOrUrl(path); + } + return _T(""); +} + +CString CMainFrame::GetCaptureTitle() +{ + CString title; + + title.LoadString(IDS_CAPTURE_LIVE); + if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + CString devName = GetFriendlyName(m_VidDispName); + if (!devName.IsEmpty()) { + title.AppendFormat(_T(" | %s"), devName.GetString()); + } + } else { + CString& eventName = m_pDVBState->NowNext.eventName; + if (m_pDVBState->bActive) { + title.AppendFormat(_T(" | %s"), m_pDVBState->sChannelName.GetString()); + if (!eventName.IsEmpty()) { + title.AppendFormat(_T(" - %s"), eventName.GetString()); + } + } else { + title += _T(" | DVB"); + } + } + return title; +} + +GUID CMainFrame::GetTimeFormat() +{ + GUID ret; + if (!m_pMS || !SUCCEEDED(m_pMS->GetTimeFormat(&ret))) { + ASSERT(FALSE); + ret = TIME_FORMAT_NONE; + } + return ret; +} + +void CMainFrame::UpdateDXVAStatus() +{ + CString DXVAInfo; + // We only support getting info from LAV Video Decoder is that is what will be used 99% of the time + if (CComQIPtr pLAVVideoStatus = FindFilter(GUID_LAVVideo, m_pGB)) { + const LPCWSTR decoderName = pLAVVideoStatus->GetActiveDecoderName(); + if (decoderName == nullptr || wcscmp(decoderName, L"avcodec") == 0 || wcscmp(decoderName, L"wmv9 mft") == 0 || wcscmp(decoderName, L"msdk mvc") == 0) { + DXVAInfo = _T("H/W Decoder : None"); + } else { + m_bUsingDXVA = true; + m_HWAccelType = CFGFilterLAVVideo::GetUserFriendlyDecoderName(decoderName); + DXVAInfo.Format(_T("H/W Decoder : %s"), m_HWAccelType); + } + } else { + DXVAInfo = _T("H/W Decoder : None / Unknown"); + } + GetRenderersData()->m_strDXVAInfo = DXVAInfo; +} + +bool CMainFrame::GetDecoderType(CString& type) const +{ + if (!m_fAudioOnly) { + if (m_bUsingDXVA) { + type = m_HWAccelType; + } else { + type.LoadString(IDS_TOOLTIP_SOFTWARE_DECODING); + } + return true; + } + return false; +} + +void CMainFrame::UpdateSubtitleRenderingParameters() +{ + if (!m_pCAP) { + return; + } + + const CAppSettings& s = AfxGetAppSettings(); + if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { + bool bChangeStorageRes = false; + bool bChangePARComp = false; + double dPARCompensation = 1.0; + bool bKeepAspectRatio = s.fKeepAspectRatio; + + CSize szAspectRatio = m_pCAP->GetVideoSize(true); + CSize szVideoFrame; + if (m_pMVRI) { + // Use IMadVRInfo to get size. See http://bugs.madshi.net/view.php?id=180 + m_pMVRI->GetSize("originalVideoSize", &szVideoFrame); + bKeepAspectRatio = true; + } else { + szVideoFrame = m_pCAP->GetVideoSize(false); + } + + if (s.bSubtitleARCompensation && szAspectRatio.cx && szAspectRatio.cy && szVideoFrame.cx && szVideoFrame.cy && bKeepAspectRatio) { + if (pRTS->m_layoutRes.cx > 0) { + dPARCompensation = (double)szAspectRatio.cx * pRTS->m_layoutRes.cy / (szAspectRatio.cy * pRTS->m_layoutRes.cx); + } else { + dPARCompensation = (double)szAspectRatio.cx * szVideoFrame.cy / (szAspectRatio.cy * szVideoFrame.cx); + } + } + if (pRTS->m_dPARCompensation != dPARCompensation) { + bChangePARComp = true; + } + + if (pRTS->m_subtitleType == Subtitle::ASS || pRTS->m_subtitleType == Subtitle::SSA) { + if (szVideoFrame.cx > 0) { + if (pRTS->m_layoutRes.cx == 0 || pRTS->m_layoutRes.cy == 0) { + bChangeStorageRes = (pRTS->m_storageRes != szVideoFrame); + } else { + bChangeStorageRes = (pRTS->m_storageRes != pRTS->m_layoutRes); + } + } + } + + { + CAutoLock cAutoLock(&m_csSubLock); + if (bChangeStorageRes) { + if (pRTS->m_layoutRes.cx == 0 || pRTS->m_layoutRes.cy == 0) { + pRTS->m_storageRes = szVideoFrame; + } else { + pRTS->m_storageRes = pRTS->m_layoutRes; + } + } + if (bChangePARComp) { + pRTS->m_ePARCompensationType = CSimpleTextSubtitle::EPARCompensationType::EPCTAccurateSize_ISR; + pRTS->m_dPARCompensation = dPARCompensation; + } + + STSStyle style = s.subtitlesDefStyle; + if (pRTS->m_bUsingPlayerDefaultStyle) { + pRTS->SetDefaultStyle(style); + } else if (pRTS->GetDefaultStyle(style) && style.relativeTo == STSStyle::AUTO && s.subtitlesDefStyle.relativeTo != STSStyle::AUTO) { + style.relativeTo = s.subtitlesDefStyle.relativeTo; + pRTS->SetDefaultStyle(style); + } + pRTS->SetOverride(s.bSubtitleOverrideDefaultStyle, s.bSubtitleOverrideAllStyles, s.subtitlesDefStyle); + pRTS->SetAlignment(s.fOverridePlacement, s.nHorPos, s.nVerPos); + pRTS->SetUseFreeType(s.bUseFreeType); + pRTS->SetOpenTypeLangHint(s.strOpenTypeLangHint); + pRTS->Deinit(); + } + m_pCAP->Invalidate(); + } else if (auto pVSS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { + { + CAutoLock cAutoLock(&m_csSubLock); + pVSS->SetAlignment(s.fOverridePlacement, s.nHorPos, s.nVerPos); + } + m_pCAP->Invalidate(); + } +} + +REFTIME CMainFrame::GetAvgTimePerFrame() const +{ + REFTIME refAvgTimePerFrame = 0.0; + + if (FAILED(m_pBV->get_AvgTimePerFrame(&refAvgTimePerFrame))) { + if (m_pCAP) { + refAvgTimePerFrame = 1.0 / m_pCAP->GetFPS(); + } + + BeginEnumFilters(m_pGB, pEF, pBF) { + if (refAvgTimePerFrame > 0.0) { + break; + } + + BeginEnumPins(pBF, pEP, pPin) { + AM_MEDIA_TYPE mt; + if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (mt.majortype == MEDIATYPE_Video && mt.formattype == FORMAT_VideoInfo) { + refAvgTimePerFrame = (REFTIME)((VIDEOINFOHEADER*)mt.pbFormat)->AvgTimePerFrame / 10000000i64; + break; + } else if (mt.majortype == MEDIATYPE_Video && mt.formattype == FORMAT_VideoInfo2) { + refAvgTimePerFrame = (REFTIME)((VIDEOINFOHEADER2*)mt.pbFormat)->AvgTimePerFrame / 10000000i64; + break; + } + } + } + EndEnumPins; + } + EndEnumFilters; + } + + // Double-check that the detection is correct for DVDs + DVD_VideoAttributes VATR; + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { + double ratio; + if (VATR.ulFrameRate == 50) { + ratio = 25.0 * refAvgTimePerFrame; + // Accept 25 or 50 fps + if (!IsNearlyEqual(ratio, 1.0, 1e-2) && !IsNearlyEqual(ratio, 2.0, 1e-2)) { + refAvgTimePerFrame = 1.0 / 25.0; + } + } else { + ratio = 29.97 * refAvgTimePerFrame; + // Accept 29,97, 59.94, 23.976 or 47.952 fps + if (!IsNearlyEqual(ratio, 1.0, 1e-2) && !IsNearlyEqual(ratio, 2.0, 1e-2) + && !IsNearlyEqual(ratio, 1.25, 1e-2) && !IsNearlyEqual(ratio, 2.5, 1e-2)) { + refAvgTimePerFrame = 1.0 / 29.97; + } + } + } + + return refAvgTimePerFrame; +} + +void CMainFrame::OnVideoSizeChanged(const bool bWasAudioOnly /*= false*/) +{ + const auto& s = AfxGetAppSettings(); + if (GetLoadState() == MLS::LOADED && + ((s.fRememberZoomLevel && (s.fLimitWindowProportions || m_bAllowWindowZoom)) || m_fAudioOnly || bWasAudioOnly) && + !(IsFullScreenMode() || IsZoomed() || IsIconic() || IsAeroSnapped())) { + CSize videoSize; + if (!m_fAudioOnly && !m_bAllowWindowZoom) { + videoSize = GetVideoSize(); + } + if (videoSize.cx && videoSize.cy) { + ZoomVideoWindow(m_dLastVideoScaleFactor * std::sqrt((static_cast(m_lastVideoSize.cx) * m_lastVideoSize.cy) + / (static_cast(videoSize.cx) * videoSize.cy))); + } else { + ZoomVideoWindow(); + } + } + MoveVideoWindow(); +} + +typedef struct { + SubtitlesInfo* pSubtitlesInfo; + BOOL bActivate; + std::string fileName; + std::string fileContents; +} SubtitlesData; + +LRESULT CMainFrame::OnLoadSubtitles(WPARAM wParam, LPARAM lParam) +{ + SubtitlesData& data = *(SubtitlesData*)lParam; + + CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); + if (pRTS) { + if (pRTS->Open(CString(data.pSubtitlesInfo->Provider()->DisplayName().c_str()), + (BYTE*)(LPCSTR)data.fileContents.c_str(), (int)data.fileContents.length(), DEFAULT_CHARSET, + UTF8To16(data.fileName.c_str()), Subtitle::HearingImpairedType(data.pSubtitlesInfo->hearingImpaired), + ISOLang::ISO6391ToLcid(data.pSubtitlesInfo->languageCode.c_str())) && pRTS->GetStreamCount() > 0) { + m_wndSubtitlesDownloadDialog.DoDownloaded(*data.pSubtitlesInfo); +#if USE_LIBASS + if (pRTS->m_LibassContext.IsLibassActive()) { + pRTS->m_LibassContext.SetFilterGraph(m_pGB); + } +#endif + SubtitleInput subElement = pRTS.Detach(); + m_pSubStreams.AddTail(subElement); + if (data.bActivate) { + m_ExternalSubstreams.push_back(subElement.pSubStream); + SetSubtitle(subElement.pSubStream); + + auto& s = AfxGetAppSettings(); + if (s.fKeepHistory && s.bRememberTrackSelection && s.bAutoSaveDownloadedSubtitles) { + s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); + } + } + return TRUE; + } + } + + return FALSE; +} + +LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) +{ + CheckPointer(lParam, FALSE); + + int n = 0; + SubtitleInput* pSubInput = GetSubtitleInput(n, true); + CheckPointer(pSubInput, FALSE); + + CLSID clsid; + if (FAILED(pSubInput->pSubStream->GetClassID(&clsid)) || clsid != __uuidof(CRenderedTextSubtitle)) { + return FALSE; + } + + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; + // Only for external text subtitles + if (pRTS->m_path.IsEmpty()) { + return FALSE; + } + + SubtitlesInfo* pSubtitlesInfo = reinterpret_cast(lParam); + + pSubtitlesInfo->GetFileInfo(); + pSubtitlesInfo->releaseNames.emplace_back(UTF16To8(pRTS->m_name)); + if (pSubtitlesInfo->hearingImpaired == Subtitle::HI_UNKNOWN) { + pSubtitlesInfo->hearingImpaired = pRTS->m_eHearingImpaired; + } + + if (!pSubtitlesInfo->languageCode.length() && pRTS->m_lcid && pRTS->m_lcid != LCID(-1)) { + CString str; + GetLocaleString(pRTS->m_lcid, LOCALE_SISO639LANGNAME, str); + pSubtitlesInfo->languageCode = UTF16To8(str); + } + + pSubtitlesInfo->frameRate = m_pCAP->GetFPS(); + int delay = m_pCAP->GetSubtitleDelay(); + if (pRTS->m_mode == FRAME) { + delay = std::lround(delay * pSubtitlesInfo->frameRate / 1000.0); + } + + const CStringW fmt(L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n"); + CStringW content; + CAutoLock cAutoLock(&m_csSubLock); + for (int i = 0, j = int(pRTS->GetCount()), k = 0; i < j; i++) { + int t1 = (int)(RT2MS(pRTS->TranslateStart(i, pSubtitlesInfo->frameRate)) + delay); + if (t1 < 0) { + k++; + continue; + } + + int t2 = (int)(RT2MS(pRTS->TranslateEnd(i, pSubtitlesInfo->frameRate)) + delay); + + int hh1 = (t1 / 60 / 60 / 1000); + int mm1 = (t1 / 60 / 1000) % 60; + int ss1 = (t1 / 1000) % 60; + int ms1 = (t1) % 1000; + int hh2 = (t2 / 60 / 60 / 1000); + int mm2 = (t2 / 60 / 1000) % 60; + int ss2 = (t2 / 1000) % 60; + int ms2 = (t2) % 1000; + + content.AppendFormat(fmt, i - k + 1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, pRTS->GetStrW(i, false).GetString()); + } + + pSubtitlesInfo->fileContents = UTF16To8(content); + return TRUE; +} + +static const CString ydl_whitelist[] = { + _T("youtube.com/"), + _T("youtu.be/"), + _T("twitch.tv/"), + _T("twitch.com/") +}; + +static const CString ydl_blacklist[] = { + _T("googlevideo.com/videoplayback"), // already processed URL + _T("googlevideo.com/api/manifest"), + _T("@127.0.0.1:"), // local URL + _T("saunalahti.fi/") +}; + +bool CMainFrame::IsOnYDLWhitelist(CString url) { + for (int i = 0; i < _countof(ydl_whitelist); i++) { + if (url.Find(ydl_whitelist[i]) >= 0) { + return true; + } + } + return false; +} + +bool CMainFrame::CanSendToYoutubeDL(const CString url) +{ + if (url.Left(4).MakeLower() == _T("http") && AfxGetAppSettings().bUseYDL) { + // Blacklist: don't use for IP addresses + std::wcmatch regmatch; + std::wregex regexp(LR"(https?:\/\/(\d{1,3}\.){3}\d{1,3}.*)"); + if (std::regex_match(url.GetString(), regmatch, regexp)) { + return false; + } + + // Whitelist: popular supported sites + if (IsOnYDLWhitelist(url)) { + return true; + } + + // Blacklist: unsupported sites where YDL causes an error or long delay + for (int i = 0; i < _countof(ydl_blacklist); i++) { + if (url.Find(ydl_blacklist[i], 7) > 0) { + return false; + } + } + + // Blacklist: URL points to a file + CString baseurl; + int q = url.Find(_T('?')); + if (q > 0) { + baseurl = url.Left(q); + } else { + baseurl = url; + q = url.GetLength(); + } + int p = baseurl.ReverseFind(_T('.')); + if (p > 0 && (q - p <= 6)) { + CString ext = baseurl.Mid(p); + if (AfxGetAppSettings().m_Formats.FindExt(ext)) { + return false; + } + } + + return true; + } + return false; +} + +bool CMainFrame::ProcessYoutubeDLURL(CString url, bool append, bool replace) +{ + auto& s = AfxGetAppSettings(); + CAtlList streams; + CAtlList filenames; + CYoutubeDLInstance ydl; + CYoutubeDLInstance::YDLPlaylistInfo listinfo; + CString useragent; + + m_sydlLastProcessURL = url; + + m_wndStatusBar.SetStatusMessage(ResStr(IDS_CONTROLS_YOUTUBEDL)); + + if (!ydl.Run(url)) { + return false; + } + if (!ydl.GetHttpStreams(streams, listinfo, useragent)) { + return false; + } + + if (!append && !replace) { + m_wndPlaylistBar.Empty(); + } + + CString f_title; + + for (unsigned int i = 0; i < streams.GetCount(); i++) { + auto stream = streams.GetAt(streams.FindIndex(i)); + CString v_url = stream.video_url; + CString a_url = stream.audio_url; + filenames.RemoveAll(); + if (!v_url.IsEmpty() && (!s.bYDLAudioOnly || a_url.IsEmpty())) { + filenames.AddTail(v_url); + + } + if (!a_url.IsEmpty()) { + filenames.AddTail(a_url); + } + CString title = stream.title; + CString seasonid; + if (stream.season_number != -1) { + seasonid.Format(_T("S%02d"), stream.season_number); + } + CString episodeid; + if (stream.episode_number != -1) { + episodeid.Format(_T("E%02d"), stream.episode_number); + } + CString epiid; + if (!seasonid.IsEmpty() || !episodeid.IsEmpty()) { + epiid.Format(_T("%s%s. "), static_cast(seasonid), static_cast(episodeid)); + } + CString season; + if (!stream.series.IsEmpty()) { + season = stream.series; + CString t(stream.season.Left(6)); + if (!stream.season.IsEmpty() && (t.MakeLower() != _T("season") || stream.season_number == -1)) { + season += _T(" ") + stream.season; + } + season += _T(" - "); + } + else if (!stream.season.IsEmpty()) { + CString t(stream.season.Left(6)); + if (t.MakeLower() != _T("season") || stream.season_number == -1) { + season = stream.season + _T(" - "); + } + } + title.Format(_T("%s%s%s"), static_cast(epiid), static_cast(season), static_cast(title)); + if (i == 0) f_title = title; + + CString ydl_src = stream.webpage_url.IsEmpty() ? url : stream.webpage_url; + if (i == 0) m_sydlLastProcessURL = ydl_src; + + int targetlen = title.GetLength() > 100 ? 50 : 150 - title.GetLength(); + CString short_url = ShortenURL(ydl_src, targetlen, true); + + if (ydl_src == filenames.GetHead()) { + // Processed URL is same as input, can happen for DASH manifest files. Clear source URL to avoid reprocessing. + ydl_src = _T(""); + } + + if (replace) { + m_wndPlaylistBar.ReplaceCurrentItem(filenames, nullptr, title + " (" + short_url + ")", ydl_src, useragent, _T(""), &stream.subtitles); + break; + } else { + m_wndPlaylistBar.Append(filenames, false, nullptr, title + " (" + short_url + ")", ydl_src, useragent, _T(""), &stream.subtitles); + } + } + + if (s.fKeepHistory) { + auto* mru = &s.MRU; + RecentFileEntry r; + mru->LoadMediaHistoryEntryFN(m_sydlLastProcessURL, r); + if (streams.GetCount() > 1) { + auto h = streams.GetHead(); + if (!h.series.IsEmpty()) { + r.title = h.series; + if (!h.season.IsEmpty()) { + r.title += _T(" - ") + h.season; + } + } + else if (!h.season.IsEmpty()) { + r.title = h.season; + } + else if (!listinfo.title.IsEmpty()) { + if (!listinfo.uploader.IsEmpty()) r.title.Format(_T("%s - %s"), static_cast(listinfo.uploader), static_cast(listinfo.title)); + else r.title = listinfo.title; + } + else r.title = f_title; + } + else if (streams.GetCount() == 1) { + r.title = f_title; + } + mru->Add(r, false); + } + + if (!append && (!replace || m_wndPlaylistBar.GetCount() == 0)) { + m_wndPlaylistBar.SetFirst(); + } + return true; +} + +bool CMainFrame::DownloadWithYoutubeDL(CString url, CString filename) +{ + PROCESS_INFORMATION proc_info; + STARTUPINFO startup_info; + const auto& s = AfxGetAppSettings(); + + bool ytdlp = true; + CString args = _T("\"") + GetYDLExePath(&ytdlp) + _T("\" --console-title \"") + url + _T("\""); + if (!s.sYDLCommandLine.IsEmpty()) { + args.Append(_T(" ")); + args.Append(s.sYDLCommandLine); + } + if (s.bYDLAudioOnly && (s.sYDLCommandLine.Find(_T("-f ")) < 0)) { + args.Append(_T(" -f bestaudio")); + } + if (s.sYDLCommandLine.Find(_T("-o ")) < 0) { + args.Append(_T(" -o \"" + filename + "\"")); + } + + ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&startup_info, sizeof(STARTUPINFO)); + startup_info.cb = sizeof(STARTUPINFO); + + if (!CreateProcess(NULL, args.GetBuffer(), NULL, NULL, false, 0, + NULL, NULL, &startup_info, &proc_info)) { + AfxMessageBox(_T("An error occurred while attempting to run Youtube-DL"), MB_ICONERROR, 0); + return false; + } + + CloseHandle(proc_info.hProcess); + CloseHandle(proc_info.hThread); + + return true; +} + +void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) +{ + __super::OnSettingChange(uFlags, lpszSection); + if (SPI_SETNONCLIENTMETRICS == uFlags) { + CMPCThemeUtil::GetMetrics(true); + CMPCThemeMenu::clearDimensions(); + if (nullptr != defaultMPCThemeMenu) { + UpdateUILanguage(); //cheap way to rebuild menus--we want to do this to force them to re-measure + } + RecalcLayout(); + } +} + +BOOL CMainFrame::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) { + if (m_bUseSeekPreview && m_wndPreView.IsWindowVisible()) { + + int seek = + nFlags == MK_SHIFT ? 10 : + nFlags == MK_CONTROL ? 1 : 5; + + zDelta > 0 ? SetCursorPos(point.x + seek, point.y) : + zDelta < 0 ? SetCursorPos(point.x - seek, point.y) : SetCursorPos(point.x, point.y); + + return 0; + } + return __super::OnMouseWheel(nFlags, zDelta, point); +} + +void CMainFrame::OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt) { + if (m_wndView && m_wndView.OnMouseHWheelImpl(nFlags, zDelta, pt)) { + //HWHEEL is sent to active window, so we have to manually pass it to CMouseWnd to trap hotkeys + return; + } + __super::OnMouseHWheel(nFlags, zDelta, pt); +} + +CHdmvClipInfo::BDMVMeta CMainFrame::GetBDMVMeta() +{ + return m_BDMeta.GetHead(); +} + +BOOL CMainFrame::AppendMenuEx(CMenu& menu, UINT nFlags, UINT nIDNewItem, CString& text) +{ + text.Replace(_T("&"), _T("&&")); + auto bResult = menu.AppendMenu(nFlags, nIDNewItem, text.GetString()); + if (bResult && (nFlags & MF_DEFAULT)) { + bResult = menu.SetDefaultItem(nIDNewItem); + } + return bResult; +} + +CString CMainFrame::getBestTitle(bool fTitleBarTextTitle) { + CString title; + if (fTitleBarTextTitle && m_pAMMC[0]) { + for (const auto& pAMMC : m_pAMMC) { + if (pAMMC) { + CComBSTR bstr; + if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { + title = bstr.m_str; + title.Trim(); + if (!title.IsEmpty()) { + return title; + } + } + } + } + } + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_label && !pli.m_label.IsEmpty()) { + if (fTitleBarTextTitle || pli.m_bYoutubeDL) { + title = pli.m_label; + return title; + } + } + + CStringW ext = GetFileExt(GetFileName()); + if (ext == ".mpls" && m_bHasBDMeta) { + title = GetBDMVMeta().title; + return title; + } else if (ext != ".mpls") { + m_bHasBDMeta = false; + m_BDMeta.RemoveAll(); + } + + return L""; +} + +void CMainFrame::MediaTransportControlSetMedia() { + if (m_media_trans_control.smtc_updater && m_media_trans_control.smtc_controls) { + TRACE(_T("CMainFrame::MediaTransportControlSetMedia()\n")); + HRESULT ret = S_OK; + bool have_secondary_title = false; + + CString title = getBestTitle(); + if (title.IsEmpty()) { + title = GetFileName(); + } + + CString author; + if (m_pAMMC[0]) { + for (const auto& pAMMC : m_pAMMC) { + if (pAMMC) { + CComBSTR bstr; + if (SUCCEEDED(pAMMC->get_AuthorName(&bstr)) && bstr.Length()) { + author = bstr.m_str; + author.Trim(); + } + } + } + } + + // Set media details + if (m_fAudioOnly) { + ret = m_media_trans_control.smtc_updater->put_Type(ABI::Windows::Media::MediaPlaybackType_Music); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: put_Type error %ld\n"), ret); + return; + } + + CComPtr pMusicDisplayProperties; + ret = m_media_trans_control.smtc_updater->get_MusicProperties(&pMusicDisplayProperties); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: get_MusicProperties error %ld\n"), ret); + return; + } + + if (!title.IsEmpty()) { + HSTRING ttitle; + if (WindowsCreateString(title.GetString(), title.GetLength(), &ttitle) == S_OK) { + ret = pMusicDisplayProperties->put_Title(ttitle); + ASSERT(ret == S_OK); + } + } + if (!author.IsEmpty()) { + HSTRING temp; + if (WindowsCreateString(author.GetString(), author.GetLength(), &temp) == S_OK) { + ret = pMusicDisplayProperties->put_Artist(temp); + ASSERT(ret == S_OK); + } + } + } else { + ret = m_media_trans_control.smtc_updater->put_Type(ABI::Windows::Media::MediaPlaybackType_Video); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: put_Type error %ld\n"), ret); + return; + } + + CComPtr pVideoDisplayProperties; + ret = m_media_trans_control.smtc_updater->get_VideoProperties(&pVideoDisplayProperties); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: get_VideoProperties error %ld\n"), ret); + return; + } + + if (!title.IsEmpty()) { + HSTRING ttitle; + if (WindowsCreateString(title.GetString(), title.GetLength(), &ttitle) == S_OK) { + ret = pVideoDisplayProperties->put_Title(ttitle); + ASSERT(ret == S_OK); + } + } + CString chapter; + if (m_pCB) { + DWORD dwChapCount = m_pCB->ChapGetCount(); + if (dwChapCount) { + REFERENCE_TIME rtNow; + m_pMS->GetCurrentPosition(&rtNow); + + CComBSTR bstr; + long currentChap = m_pCB->ChapLookup(&rtNow, &bstr); + if (bstr.Length()) { + chapter.Format(_T("%s (%ld/%lu)"), bstr.m_str, std::max(0l, currentChap + 1l), dwChapCount); + } else { + chapter.Format(_T("%ld/%lu"), currentChap + 1, dwChapCount); + } + } + } + if (!chapter.IsEmpty() && chapter != title) { + HSTRING temp; + if (WindowsCreateString(chapter.GetString(), chapter.GetLength(), &temp) == S_OK) { + ret = pVideoDisplayProperties->put_Subtitle(temp); + ASSERT(ret == S_OK); + have_secondary_title = true; + } + } + if (!have_secondary_title && !author.IsEmpty() && author != title) { + HSTRING temp; + if (WindowsCreateString(author.GetString(), author.GetLength(), &temp) == S_OK) { + ret = pVideoDisplayProperties->put_Subtitle(temp); + ASSERT(ret == S_OK); + have_secondary_title = true; + } + } + } + + // Thumbnail + CComQIPtr pFilterGraph = m_pGB; + std::vector internalCover; + if (CoverArt::FindEmbedded(pFilterGraph, internalCover)) { + m_media_trans_control.loadThumbnail(internalCover.data(), internalCover.size()); + } else { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli) && !pli.m_cover.IsEmpty()) { + m_media_trans_control.loadThumbnail(pli.m_cover); + } else { + CString filename = m_wndPlaylistBar.GetCurFileName(); + CString filename_no_ext; + CString filedir; + if (!PathUtils::IsURL(filename)) { + CPath path = CPath(filename); + if (path.FileExists()) { + path.RemoveExtension(); + filename_no_ext = path.m_strPath; + path.RemoveFileSpec(); + filedir = path.m_strPath; + bool is_file_art = false; + CString img = CoverArt::FindExternal(filename_no_ext, filedir, author, is_file_art); + if (!img.IsEmpty()) { + if (m_fAudioOnly || is_file_art) { + m_media_trans_control.loadThumbnail(img); + } + } + } + } + } + } + + // Update data and status + ret = m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus::MediaPlaybackStatus_Playing); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: put_PlaybackStatus error %ld\n"), ret); + return; + } + ret = m_media_trans_control.smtc_updater->Update(); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: Update error %ld\n"), ret); + return; + } + // Enable + ret = m_media_trans_control.smtc_controls->put_IsEnabled(true); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: put_IsEnabled error %ld\n"), ret); + return; + } + } +} + +void CMainFrame::MediaTransportControlUpdateState(OAFilterState state) { + if (m_media_trans_control.smtc_controls) { + if (state == State_Running) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Playing); + else if (state == State_Paused) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Paused); + else if (state == State_Stopped) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Stopped); + else m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Changing); + } +} diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 7cfa0d91ac6..12edc275077 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1,1411 +1,1411 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "ChildView.h" -#include "DVBChannel.h" -#include "DebugShadersDlg.h" -#include "DropTarget.h" -#include "EditListEditor.h" -#include "IBufferInfo.h" -#include "IKeyFrameInfo.h" -#include "MainFrmControls.h" -#include "MouseTouch.h" -#include "MpcApi.h" -#include "PlayerCaptureBar.h" -#include "PlayerInfoBar.h" -#include "PlayerNavigationBar.h" -#include "PlayerPlaylistBar.h" -#include "PlayerSeekBar.h" -#include "PlayerStatusBar.h" -#include "PlayerSubresyncBar.h" -#include "PlayerPreView.h" -#include "PlayerToolBar.h" -#include "SubtitleDlDlg.h" -#include "TimerWrappers.h" -#include "OSD.h" -#include "CMPCThemeMenu.h" -#include "../SubPic/MemSubPic.h" -#include -#include -#include "../DSUtil/FontInstaller.h" -#include "AppSettings.h" -#include "../filters/transform/VSFilter/IDirectVobSub.h" -#include "MediaTransControls.h" -#include "FavoriteOrganizeDlg.h" -#include "AllocatorCommon.h" - -class CDebugShadersDlg; -class CFullscreenWnd; -class SkypeMoodMsgHandler; -struct DisplayMode; -enum MpcCaptionState; -class CMediaTypesDlg; - -interface IDSMChapterBag; -interface IGraphBuilder2; -interface IMFVideoDisplayControl; -interface IMFVideoProcessor; -interface IMadVRCommand; -interface IMadVRInfo; -interface IMadVRFrameGrabber; -interface IMadVRSettings; -interface IMadVRSubclassReplacement; -interface ISubClock; -interface ISubPicAllocatorPresenter2; -interface ISubPicAllocatorPresenter; -interface ISubStream; -interface ISyncClock; -DECLARE_INTERFACE_IID(IAMLine21Decoder_2, "6E8D4A21-310C-11d0-B79A-00AA003767A7"); - -enum class MLS { - CLOSED, - LOADING, - LOADED, - CLOSING, - FAILING, -}; - -enum { - PM_NONE, - PM_FILE, - PM_DVD, - PM_ANALOG_CAPTURE, - PM_DIGITAL_CAPTURE -}; - -class OpenMediaData -{ -public: - // OpenMediaData() {} - virtual ~OpenMediaData() {} // one virtual funct is needed to enable rtti - CString title; - CAtlList subs; -}; - -class OpenFileData : public OpenMediaData -{ -public: - OpenFileData() : rtStart(0), bAddToRecent(true) {} - CAtlList fns; - REFERENCE_TIME rtStart; - ABRepeat abRepeat; - bool bAddToRecent; - CString useragent; - CString referrer; -}; - -class OpenDVDData : public OpenMediaData -{ -public: - // OpenDVDData() {} - CString path; - CComPtr pDvdState; -}; - -class OpenDeviceData : public OpenMediaData -{ -public: - OpenDeviceData() { - vinput = vchannel = ainput = -1; - } - CStringW DisplayName[2]; - int vinput, vchannel, ainput; -}; - -class TunerScanData -{ -public: - ULONG FrequencyStart; - ULONG FrequencyStop; - ULONG Bandwidth; - ULONG SymbolRate; - LONG Offset; - HWND Hwnd; -}; - -struct SeekToCommand { - REFERENCE_TIME rtPos; - ULONGLONG seekTime; - bool bShowOSD; -}; - -struct SubtitleInput { - CComQIPtr pSubStream; - CComPtr pSourceFilter; - - SubtitleInput() {}; - SubtitleInput(CComQIPtr pSubStream) : pSubStream(pSubStream) {}; - SubtitleInput(CComQIPtr pSubStream, CComPtr pSourceFilter) - : pSubStream(pSubStream), pSourceFilter(pSourceFilter) {}; -}; - -struct FileFavorite { - CString Name; - REFERENCE_TIME Start; - REFERENCE_TIME MarkA; - REFERENCE_TIME MarkB; - BOOL RelativeDrive; - - FileFavorite() { - Start = MarkA = MarkB = 0; - RelativeDrive = FALSE; - } - - static bool TryParse(const CString& fav, FileFavorite& ff); - static bool TryParse(const CString& fav, FileFavorite& ff, CAtlList& parts); - - CString ToString() const; -}; - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame - -class CMainFrame : public CFrameWnd, public CDropClient -{ -public: - - DpiHelper m_dpi; - - enum class TimerHiderSubscriber { - TOOLBARS_HIDER, - CURSOR_HIDER, - CURSOR_HIDER_D3DFS, - }; - OnDemandTimer m_timerHider; - - enum class TimerOneTimeSubscriber { - TOOLBARS_DELAY_NOTLOADED, - CHILDVIEW_CURSOR_HACK, - DELAY_IDLE, - ACTIVE_SHADER_FILES_CHANGE_COOLDOWN, - DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, - DVBINFO_UPDATE, - STATUS_ERASE, - PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW, - AUTOFIT_TIMEOUT - }; - OneTimeTimerPool m_timerOneTime; - -private: - EventClient m_eventc; - void EventCallback(MpcEvent ev); - - CMainFrameMouseHook m_mouseHook; - - enum { - TIMER_STREAMPOSPOLLER = 1, - TIMER_STREAMPOSPOLLER2, - TIMER_STATS, - TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS, - TIMER_HIDER, - TIMER_WINDOW_FULLSCREEN, - TIMER_DELAYEDSEEK, - TIMER_ONETIME_START, - TIMER_ONETIME_END = TIMER_ONETIME_START + 127, - }; - enum { - SEEK_DIRECTION_NONE, - SEEK_DIRECTION_BACKWARD, - SEEK_DIRECTION_FORWARD - }; - enum { - ZOOM_DEFAULT_LEVEL = 0, - ZOOM_AUTOFIT = -1, - ZOOM_AUTOFIT_LARGER = -2 - }; - - - typedef std::map PlaybackRateMap; - static PlaybackRateMap filePlaybackRates; - static PlaybackRateMap dvdPlaybackRates; - - friend class CPPageFileInfoSheet; - friend class CPPageLogo; - friend class CMouse; - friend class CPlayerSeekBar; // for accessing m_controls.ControlChecked() - friend class CChildView; // for accessing m_controls.DelayShowNotLoaded() - friend class CFullscreenWnd; // for accessing m_controls.DelayShowNotLoaded() - friend class CMouseWndWithArtView; // for accessing m_controls.DelayShowNotLoaded() - friend class SubtitlesProvider; - - // TODO: wrap these graph objects into a class to make it look cleaner - - CComPtr m_pGB; - CComQIPtr m_pMC; - CComQIPtr m_pME; - CComQIPtr m_pVW; - CComQIPtr m_pBV; - CComQIPtr m_pBA; - CComQIPtr m_pMS; - CComQIPtr m_pFS; - CComQIPtr m_pFSF; - CComQIPtr m_pKFI; - CComQIPtr m_pQP; - CComQIPtr m_pBI; - CComQIPtr m_pAMOP; - CComQIPtr m_pAMMC[2]; - CComQIPtr m_pAMNS; - CComQIPtr m_pAudioSwitcherSS; - CComQIPtr m_pSplitterSS; - CComQIPtr m_pSplitterDubSS; - CComQIPtr m_pOtherSS[2]; - // SmarkSeek - CComPtr m_pGB_preview; - CComQIPtr m_pMC_preview; - //CComQIPtr m_pME_preview; - CComQIPtr m_pMS_preview; - CComQIPtr m_pVW_preview; - CComQIPtr m_pBV_preview; - //CComQIPtr m_pFS_preview; - CComQIPtr m_pDVDC_preview; - CComQIPtr m_pDVDI_preview; // VtX: usually not necessary but may sometimes be necessary. - CComPtr m_pMFVDC_preview; - CComPtr m_pVMR9C_preview; - CComPtr m_pMFVP_preview; - CComPtr m_pCAP2_preview; - int defaultVideoAngle; - // - CComPtr m_pVMRMC; - CComPtr m_pMFVDC; - CComPtr m_pMFVP; - CComPtr m_pVMB; - CComPtr m_pMFVMB; - CComPtr m_pVMRWC; - - CComPtr m_pCAP; - CComPtr m_pCAP2; - CComPtr m_pCAP3; - - CComPtr m_pMVRS; - CComPtr m_pMVRSR; - CComPtr m_pMVRC; - CComPtr m_pMVRI; - CComPtr m_pMVRFG; - CComPtr m_pMVTO; - - CComPtr m_pD3DFSC; - - CComQIPtr m_pDVDC; - CComQIPtr m_pDVDI; - CComPtr m_pLN21; - - CComPtr m_pCGB; - CStringW m_VidDispName, m_AudDispName; - CComPtr m_pVidCap, m_pAudCap; - CComPtr m_pAMVCCap, m_pAMVCPrev; - CComPtr m_pAMVSCCap, m_pAMVSCPrev, m_pAMASC; - CComPtr m_pAMXBar; - CComPtr m_pAMTuner; - CComPtr m_pAMDF; - - CComPtr m_pProv; - - CComQIPtr m_pDVS; - CComQIPtr m_pDVS2; - - bool m_bUsingDXVA; - LPCTSTR m_HWAccelType; - void UpdateDXVAStatus(); - - void SetVolumeBoost(UINT nAudioBoost); - void SetBalance(int balance); - - // temp fonts loader - CFontInstaller m_FontInstaller; - - // subtitles - - CCritSec m_csSubLock; - CCritSec m_csSubtitleManagementLock; - - CList m_pSubStreams; - std::list m_ExternalSubstreams; - POSITION m_posFirstExtSub; - SubtitleInput m_pCurrentSubInput; - - // StatusBar message text parts - CString currentAudioLang; - CString currentSubLang; - CString m_statusbarVideoFormat; - CString m_statusbarAudioFormat; - CString m_statusbarVideoSize; - - SubtitleInput* GetSubtitleInput(int& i, bool bIsOffset = false); - int UpdateSelectedAudioStreamInfo(int index, AM_MEDIA_TYPE* pmt, LCID lcid); - bool IsValidSubtitleStream(int i); - int GetSelectedSubtitleTrackIndex(); - - friend class CTextPassThruFilter; - - // windowing - - bool m_bDelaySetOutputRect; - - CRect m_lastWindowRect; - - void SetDefaultWindowRect(int iMonitor = 0); - void SetDefaultFullscreenState(); - void RestoreDefaultWindowRect(); - CRect GetInvisibleBorderSize() const; - CSize GetVideoOrArtSize(MINMAXINFO& mmi); - CSize GetZoomWindowSize(double dScale, bool ignore_video_size = false); - bool GetWorkAreaRect(CRect& work); - CRect GetZoomWindowRect(const CSize& size, bool ignoreSavedPosition = false); - void ZoomVideoWindow(double dScale = ZOOM_DEFAULT_LEVEL, bool ignore_video_size = false); - double GetZoomAutoFitScale(); - - bool alwaysOnTopZOrderInitialized = false; - void SetAlwaysOnTop(int iOnTop); - bool WindowExpectedOnTop(); - - // dynamic menus - - void CreateDynamicMenus(); - void DestroyDynamicMenus(); - void SetupOpenCDSubMenu(); - void SetupFiltersSubMenu(); - void SetupAudioSubMenu(); - void SetupSubtitlesSubMenu(); - void SetupVideoStreamsSubMenu(); - void SetupJumpToSubMenus(CMenu* parentMenu = nullptr, int iInsertPos = -1); - void SetupFavoritesSubMenu(); - bool SetupShadersSubMenu(); - void SetupRecentFilesSubMenu(); - - DWORD SetupNavStreamSelectSubMenu(CMenu& subMenu, UINT id, DWORD dwSelGroup); - void OnNavStreamSelectSubMenu(UINT id, DWORD dwSelGroup); - void OnStreamSelect(bool forward, DWORD dwSelGroup); - static CString GetStreamOSDString(CString name, LCID lcid, DWORD dwSelGroup); - - void CreateOSDBar(); - bool OSDBarSetPos(); - void DestroyOSDBar(); - - CMPCThemeMenu m_mainPopupMenu, m_popupMenu; - CMPCThemeMenu m_openCDsMenu; - CMPCThemeMenu m_filtersMenu, m_subtitlesMenu, m_audiosMenu, m_videoStreamsMenu; - CMPCThemeMenu m_chaptersMenu, m_titlesMenu, m_playlistMenu, m_BDPlaylistMenu, m_channelsMenu; - CMPCThemeMenu m_favoritesMenu; - CMPCThemeMenu m_shadersMenu; - CMPCThemeMenu m_recentFilesMenu; - int recentFilesMenuFromMRUSequence; - - UINT m_nJumpToSubMenusCount; - - CInterfaceArray m_pparray; - CInterfaceArray m_ssarray; - - // chapters (file mode) - CComPtr m_pCB; - void SetupChapters(); - void SetupCueChapters(CString fn); - - // chapters (DVD mode) - void SetupDVDChapters(); - - bool SeekToFileChapter(int iChapter, bool bRelative = false); - bool SeekToDVDChapter(int iChapter, bool bRelative = false); - - void AddTextPassThruFilter(); - - int m_nLoops; - ABRepeat abRepeat, reloadABRepeat; - UINT m_nLastSkipDirection; - - int m_iStreamPosPollerInterval; - - bool m_fCustomGraph; - bool m_fShockwaveGraph; - - CComPtr m_pSubClock; - - bool m_fFrameSteppingActive; - int m_nStepForwardCount; - REFERENCE_TIME m_rtStepForwardStart; - int m_nVolumeBeforeFrameStepping; - - bool m_fEndOfStream; - ULONGLONG m_dwLastPause; - ULONGLONG m_dwReloadPos; - int m_iReloadAudioIdx; - int m_iReloadSubIdx; - - bool m_bRememberFilePos; - - ULONGLONG m_dwLastRun; - - bool m_bBuffering; - - bool m_fLiveWM; - - bool delayingFullScreen; - - bool m_bIsMPCVRExclusiveMode = false; - - void SendStatusMessage(CString msg, int nTimeOut); - CString m_tempstatus_msg, m_closingmsg; - - REFERENCE_TIME m_rtDurationOverride; - - void CleanGraph(); - - void ShowOptions(int idPage = 0); - - HRESULT GetDisplayedImage(std::vector& dib, CString& errmsg); - HRESULT GetCurrentFrame(std::vector& dib, CString& errmsg); - HRESULT GetOriginalFrame(std::vector& dib, CString& errmsg); - HRESULT RenderCurrentSubtitles(BYTE* pData); - bool GetDIB(BYTE** ppData, long& size, bool fSilent = false); - void SaveDIB(LPCTSTR fn, BYTE* pData, long size); - CString MakeSnapshotFileName(BOOL thumbnails); - BOOL IsRendererCompatibleWithSaveImage(); - void SaveImage(LPCTSTR fn, bool displayed, bool includeSubtitles); - void SaveThumbnails(LPCTSTR fn); - - // - - friend class CWebClientSocket; - friend class CWebServer; - CAutoPtr m_pWebServer; - int m_iPlaybackMode; - ULONG m_lCurrentChapter; - ULONG m_lChapterStartTime; - - CString m_currentCoverAuthor; - CString m_currentCoverPath; - bool currentCoverIsFileArt = false; - - CAutoPtr m_pSkypeMoodMsgHandler; - void SendNowPlayingToSkype(); - - MLS m_eMediaLoadState; - OAFilterState m_CachedFilterState; - - bool m_bSettingUpMenus; - bool m_bOpenMediaActive; - int m_OpenMediaFailedCount; - - REFTIME GetAvgTimePerFrame() const; - void OnVideoSizeChanged(const bool bWasAudioOnly = false); - - CDropTarget m_dropTarget; - void OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) override; - DROPEFFECT OnDropAccept(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) override; - -public: - void StartWebServer(int nPort); - void StopWebServer(); - - int GetPlaybackMode() const { - return m_iPlaybackMode; - } - bool IsPlaybackCaptureMode() const { - return GetPlaybackMode() == PM_ANALOG_CAPTURE || GetPlaybackMode() == PM_DIGITAL_CAPTURE; - } - void SetPlaybackMode(int iNewStatus); - bool IsMuted() { - return m_wndToolBar.GetVolume() == -10000; - } - int GetVolume() { - return m_wndToolBar.m_volctrl.GetPos(); - } - double GetPlayingRate() const { - return m_dSpeedRate; - } - -public: - CMainFrame(); - DECLARE_DYNAMIC(CMainFrame) - - // Attributes -public: - bool m_fFullScreen; - bool m_bNeedZoomAfterFullscreenExit; - bool m_fStartInD3DFullscreen; - bool m_fStartInFullscreenSeparate; - bool m_bFullScreenWindowIsD3D; - bool m_bFullScreenWindowIsOnSeparateDisplay; - - CComPtr m_pRefClock; // Adjustable reference clock. GothSync - CComPtr m_pSyncClock; - - bool IsFrameLessWindow() const; - bool IsCaptionHidden() const; - bool IsMenuHidden() const; - bool IsPlaylistEmpty() const; - bool IsInteractiveVideo() const; - bool IsFullScreenMode() const; - bool IsFullScreenMainFrame() const; - bool IsFullScreenMainFrameExclusiveMPCVR() const; - bool IsFullScreenSeparate() const; - bool HasDedicatedFSVideoWindow() const; - bool IsD3DFullScreenMode() const; - bool IsSubresyncBarVisible() const; - - CControlBar* m_pLastBar; - -protected: - bool m_bUseSeekPreview; - bool m_bFirstPlay; - bool m_bOpeningInAutochangedMonitorMode; - bool m_bPausedForAutochangeMonitorMode; - bool restoringWindowRect; - - bool m_fAudioOnly; - bool m_fValidDVDOpen; - CString m_LastOpenBDPath; - CAutoPtr m_lastOMD; - - DVD_DOMAIN m_iDVDDomain; - DWORD m_iDVDTitle; - bool m_bDVDStillOn; - int m_loadedAudioTrackIndex = -1; - int m_loadedSubtitleTrackIndex = -1; - int m_audioTrackCount = 0; - - double m_dSpeedRate; - double m_ZoomX, m_ZoomY, m_PosX, m_PosY; - int m_AngleX, m_AngleY, m_AngleZ; - int m_iDefRotation; - - void ForceCloseProcess(); - - // Operations - bool OpenMediaPrivate(CAutoPtr pOMD); - void CloseMediaPrivate(); - void DoTunerScan(TunerScanData* pTSD); - - CWnd* GetModalParent(); - - CCritSec lockModalDialog; - CMediaTypesDlg* mediaTypesErrorDlg; - void ShowMediaTypesDialog(); - - void OpenCreateGraphObject(OpenMediaData* pOMD); - void OpenFile(OpenFileData* pOFD); - void OpenDVD(OpenDVDData* pODD); - void OpenCapture(OpenDeviceData* pODD); - HRESULT OpenBDAGraph(); - void OpenCustomizeGraph(); - void OpenSetupVideo(); - void OpenSetupAudio(); - void OpenSetupInfoBar(bool bClear = true); - void UpdateChapterInInfoBar(); - void OpenSetupStatsBar(); - void CheckSelectedAudioStream(); - void OpenSetupStatusBar(); - void OpenSetupCaptureBar(); - void OpenSetupWindowTitle(bool reset = false); - -public: - static bool GetCurDispMode(const CString& displayName, DisplayMode& dm); - static bool GetDispMode(CString displayName, int i, DisplayMode& dm); - -protected: - void SetDispMode(CString displayName, const DisplayMode& dm, int msAudioDelay); - void AutoChangeMonitorMode(); - - void GraphEventComplete(); - - friend class CGraphThread; - CGraphThread* m_pGraphThread; - bool m_bOpenedThroughThread; - ATL::CEvent m_evOpenPrivateFinished; - ATL::CEvent m_evClosePrivateFinished; - - void LoadKeyFrames(); - std::vector m_kfs; - - bool m_fOpeningAborted; - bool m_bWasSnapped; - -protected: - friend class CSubtitleDlDlg; - CSubtitleDlDlg m_wndSubtitlesDownloadDialog; - CFavoriteOrganizeDlg m_wndFavoriteOrganizeDialog; - friend class CPPageSubMisc; - - friend class SubtitlesProviders; - std::unique_ptr m_pSubtitlesProviders; - friend struct SubtitlesInfo; - friend class SubtitlesTask; - friend class SubtitlesThread; - -public: - void OpenCurPlaylistItem(REFERENCE_TIME rtStart = 0, bool reopen = false, ABRepeat abRepeat = ABRepeat()); - void OpenMedia(CAutoPtr pOMD); - void PlayFavoriteFile(const CString& fav); - void PlayFavoriteDVD(CString fav); - FileFavorite ParseFavoriteFile(const CString& fav, CAtlList& args, REFERENCE_TIME* prtStart = nullptr); - bool ResetDevice(); - bool DisplayChange(); - void CloseMediaBeforeOpen(); - void CloseMedia(bool bNextIsQueued = false, bool bPendingFileDelete = false); - void StartTunerScan(CAutoPtr pTSD); - void StopTunerScan(); - HRESULT SetChannel(int nChannel); - - void AddCurDevToPlaylist(); - - bool m_bTrayIcon; - void ShowTrayIcon(bool bShow); - void SetTrayTip(const CString& str); - - CSize GetVideoSize() const; - CSize GetVideoSizeWithRotation(bool forPreview = false) const; - void HidePlaylistFullScreen(bool force = false); - void ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo); - void ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo); - void MoveVideoWindow(bool fShowStats = false, bool bSetStoppedVideoRect = false); - void SetPreviewVideoPosition(); - - void RepaintVideo(const bool bForceRepaint = false); - void HideVideoWindow(bool fHide); - - OAFilterState GetMediaStateDirect() const; - OAFilterState GetMediaState() const; - OAFilterState CMainFrame::UpdateCachedMediaState(); - bool MediaControlRun(bool waitforcompletion = false); - bool MediaControlPause(bool waitforcompletion = false); - bool MediaControlStop(bool waitforcompletion = false); - bool MediaControlStopPreview(); - - REFERENCE_TIME GetPos() const; - REFERENCE_TIME GetDur() const; - bool GetKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMin, REFERENCE_TIME rtMax, bool nearest, REFERENCE_TIME& keyframetime) const; - REFERENCE_TIME GetClosestKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMaxForwardDiff, REFERENCE_TIME rtMaxBackwardDiff) const; - REFERENCE_TIME GetClosestKeyFramePreview(REFERENCE_TIME rtTarget) const; - void SeekTo(REFERENCE_TIME rt, bool bShowOSD = true); - void DoSeekTo(REFERENCE_TIME rt, bool bShowOSD = true); - SeekToCommand queuedSeek; - ULONGLONG lastSeekStart; - ULONGLONG lastSeekFinish; - void SetPlayingRate(double rate); - - int SetupAudioStreams(); - int SetupSubtitleStreams(); - - bool LoadSubtitle(CString fn, SubtitleInput* pSubInput = nullptr, bool bAutoLoad = false); - bool LoadSubtitle(CYoutubeDLInstance::YDLSubInfo& sub); - bool SetSubtitle(int i, bool bIsOffset = false, bool bDisplayMessage = false); - void SetSubtitle(const SubtitleInput& subInput, bool skip_lcid = false); - void UpdateSubtitleColorInfo(); - void ToggleSubtitleOnOff(bool bDisplayMessage = false); - void ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew); - void InvalidateSubtitle(DWORD_PTR nSubtitleId = DWORD_PTR_MAX, REFERENCE_TIME rtInvalidate = -1); - void ReloadSubtitle(); - void UpdateSubtitleRenderingParameters(); - HRESULT InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinto); - - void SetAudioTrackIdx(int index); - void SetSubtitleTrackIdx(int index); - int GetCurrentAudioTrackIdx(CString *pstrName = nullptr); - int GetCurrentSubtitleTrackIdx(CString *pstrName = nullptr); - - void AddFavorite(bool fDisplayMessage = false, bool fShowDialog = true); - - CString GetFileName(); - CString GetCaptureTitle(); - - // shaders - void SetShaders(bool bSetPreResize = true, bool bSetPostResize = true); - - bool m_bToggleShader; - bool m_bToggleShaderScreenSpace; - std::list m_ShaderCache; - ShaderC* GetShader(CString path, bool bD3D11); - bool SaveShaderFile(ShaderC* shader); - bool DeleteShaderFile(LPCWSTR label); - void TidyShaderCache(); - - // 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(); - - void DoAfterPlaybackEvent(); - bool SearchInDir(bool bDirForward, bool bLoop = false); - bool WildcardFileSearch(CString searchstr, std::set& results, bool recurse_dirs); - CString lastOpenFile; - bool CanSkipFromClosedFile(); - - 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); - void EnableDocking(DWORD dwDockStyle); - - // DVB capture - void UpdateCurrentChannelInfo(bool bShowOSD = true, bool bShowInfoBar = false); - LRESULT OnCurrentChannelInfoUpdated(WPARAM wParam, LPARAM lParam); - - bool CheckABRepeat(REFERENCE_TIME& aPos, REFERENCE_TIME& bPos); - void PerformABRepeat(); - void DisableABRepeat(); - - struct DVBState { - struct EITData { - HRESULT hr = E_FAIL; - EventDescriptor NowNext; - bool bShowOSD = true; - bool bShowInfoBar = false; - }; - - CString sChannelName; // Current channel name - CBDAChannel* pChannel = nullptr; // Pointer to current channel object - EventDescriptor NowNext; // Current channel EIT - bool bActive = false; // True when channel is active - bool bSetChannelActive = false; // True when channel change is in progress - bool bInfoActive = false; // True when EIT data update is in progress - bool bAbortInfo = true; // True when aborting current EIT update - std::future infoData; - - void Reset() { - sChannelName.Empty(); - pChannel = nullptr; - NowNext = EventDescriptor(); - bActive = false; - bSetChannelActive = false; - bInfoActive = false; - bAbortInfo = true; - } - - void Join() { - if (infoData.valid()) { - bAbortInfo = true; - infoData.wait(); - } - } - - ~DVBState() { - bAbortInfo = true; - } - }; - - std::unique_ptr m_pDVBState = nullptr; - - // Implementation -public: - virtual ~CMainFrame(); -#ifdef _DEBUG - virtual void AssertValid() const; - virtual void Dump(CDumpContext& dc) const; -#endif - -protected: // control bar embedded members - friend class CMainFrameControls; - friend class CPPageToolBar; - CMainFrameControls m_controls; - friend class CPlayerBar; // it notifies m_controls of panel re-dock - - CChildView m_wndView; - - CPlayerSeekBar m_wndSeekBar; - CPlayerToolBar m_wndToolBar; - CPlayerInfoBar m_wndInfoBar; - CPlayerInfoBar m_wndStatsBar; - CPlayerStatusBar m_wndStatusBar; - - CPlayerSubresyncBar m_wndSubresyncBar; - CPlayerPlaylistBar m_wndPlaylistBar; - CPlayerCaptureBar m_wndCaptureBar; - CPlayerNavigationBar m_wndNavigationBar; - CEditListEditor m_wndEditListEditor; - - std::unique_ptr m_pDebugShaders; - - LPCTSTR GetRecentFile() const; - - friend class CPPagePlayback; // TODO - friend class CPPageAudioSwitcher; // TODO - friend class CMPlayerCApp; // TODO - - // Generated message map functions - - DECLARE_MESSAGE_MAP() - -public: - afx_msg int OnNcCreate(LPCREATESTRUCT lpCreateStruct); - 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 OnEnterSizeMove(); - afx_msg void OnMoving(UINT fwSide, LPRECT pRect); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnSizing(UINT nSide, LPRECT lpRect); - afx_msg void OnExitSizeMove(); - afx_msg void OnDisplayChange(); - afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); - - LRESULT OnDpiChanged(WPARAM wParam, LPARAM lParam); - - 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 void SaveAppSettings(); - - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - - void RestoreFocus(); - - afx_msg void OnInitMenu(CMenu* pMenu); - afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); - afx_msg void OnUnInitMenuPopup(CMenu* pPopupMenu, UINT nFlags); - afx_msg void OnEnterMenuLoop(BOOL bIsTrackPopupMenu); - - afx_msg BOOL OnQueryEndSession(); - afx_msg void OnEndSession(BOOL bEnding); - - BOOL OnMenu(CMenu* pMenu); - afx_msg void OnMenuPlayerShort(); - afx_msg void OnMenuPlayerLong(); - afx_msg void OnMenuFilters(); - - afx_msg void OnUpdatePlayerStatus(CCmdUI* pCmdUI); - - afx_msg LRESULT OnFilePostOpenmedia(WPARAM wParam, LPARAM lparam); - afx_msg LRESULT OnOpenMediaFailed(WPARAM wParam, LPARAM lParam); - void OnFilePostClosemedia(bool bNextIsQueued = false); - - afx_msg void OnBossKey(); - - afx_msg void OnStreamAudio(UINT nID); - afx_msg void OnStreamSub(UINT nID); - afx_msg void OnStreamSubOnOff(); - afx_msg void OnAudioShiftOnOff(); - afx_msg void OnDvdAngle(UINT nID); - afx_msg void OnDvdAudio(UINT nID); - afx_msg void OnDvdSub(UINT nID); - afx_msg void OnDvdSubOnOff(); - - afx_msg LRESULT OnLoadSubtitles(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnGetSubtitles(WPARAM, LPARAM lParam); - - // menu item handlers - - INT_PTR DoFileDialogWithLastFolder(CFileDialog& fd, CStringW& lastPath); - void OpenDVDOrBD(CStringW path); - - 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 OnFileOpenOpticalDisk(UINT nID); - afx_msg void OnFileReopen(); - afx_msg void OnFileRecycle(); - afx_msg void OnFileSaveAs(); - afx_msg void OnUpdateFileSaveAs(CCmdUI* pCmdUI); - afx_msg void OnFileSaveImage(); - afx_msg void OnFileSaveImageAuto(); - afx_msg void OnUpdateFileSaveImage(CCmdUI* pCmdUI); - afx_msg void OnCmdLineSaveThumbnails(); - afx_msg void OnFileSaveThumbnails(); - afx_msg void OnUpdateFileSaveThumbnails(CCmdUI* pCmdUI); - afx_msg void OnFileSubtitlesLoad(); - afx_msg void OnUpdateFileSubtitlesLoad(CCmdUI* pCmdUI); - afx_msg void OnFileSubtitlesSave() { SubtitlesSave(); } - afx_msg void OnUpdateFileSubtitlesSave(CCmdUI* pCmdUI); - //afx_msg void OnFileSubtitlesUpload(); - //afx_msg void OnUpdateFileSubtitlesUpload(CCmdUI* pCmdUI); - afx_msg void OnFileSubtitlesDownload(); - afx_msg void OnUpdateFileSubtitlesDownload(CCmdUI* pCmdUI); - afx_msg void OnFileProperties(); - afx_msg void OnUpdateFileProperties(CCmdUI* pCmdUI); - afx_msg void OnFileOpenLocation(); - afx_msg void OnFileCloseAndRestore(); - afx_msg void OnFileCloseMedia(); // no menu item - afx_msg void OnUpdateFileClose(CCmdUI* pCmdUI); - - void SetCaptionState(MpcCaptionState eState); - afx_msg void OnViewCaptionmenu(); - - afx_msg void OnViewNavigation(); - afx_msg void OnUpdateViewCaptionmenu(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewNavigation(CCmdUI* pCmdUI); - afx_msg void OnViewControlBar(UINT nID); - afx_msg void OnUpdateViewControlBar(CCmdUI* pCmdUI); - afx_msg void OnViewSubresync(); - afx_msg void OnUpdateViewSubresync(CCmdUI* pCmdUI); - afx_msg void OnViewPlaylist(); - afx_msg void OnPlaylistToggleShuffle(); - afx_msg void OnUpdateViewPlaylist(CCmdUI* pCmdUI); - afx_msg void OnViewEditListEditor(); - afx_msg void OnEDLIn(); - afx_msg void OnUpdateEDLIn(CCmdUI* pCmdUI); - afx_msg void OnEDLOut(); - afx_msg void OnUpdateEDLOut(CCmdUI* pCmdUI); - afx_msg void OnEDLNewClip(); - afx_msg void OnUpdateEDLNewClip(CCmdUI* pCmdUI); - afx_msg void OnEDLSave(); - afx_msg void OnUpdateEDLSave(CCmdUI* pCmdUI); - afx_msg void OnViewCapture(); - afx_msg void OnUpdateViewCapture(CCmdUI* pCmdUI); - afx_msg void OnViewDebugShaders(); - afx_msg void OnUpdateViewDebugShaders(CCmdUI* pCmdUI); - afx_msg void OnViewMinimal(); - afx_msg void OnUpdateViewMinimal(CCmdUI* pCmdUI); - afx_msg void OnViewCompact(); - afx_msg void OnUpdateViewCompact(CCmdUI* pCmdUI); - afx_msg void OnViewNormal(); - afx_msg void OnUpdateViewNormal(CCmdUI* pCmdUI); - afx_msg void OnViewFullscreen(); - afx_msg void OnViewFullscreenSecondary(); - afx_msg void OnUpdateViewFullscreen(CCmdUI* pCmdUI); - afx_msg void OnViewZoom(UINT nID); - afx_msg void OnUpdateViewZoom(CCmdUI* pCmdUI); - afx_msg void OnViewZoomAutoFit(); - afx_msg void OnViewZoomAutoFitLarger(); - afx_msg void OnViewModifySize(UINT nID); - afx_msg void OnViewDefaultVideoFrame(UINT nID); - afx_msg void OnUpdateViewDefaultVideoFrame(CCmdUI* pCmdUI); - afx_msg void OnViewSwitchVideoFrame(); - afx_msg void OnUpdateViewSwitchVideoFrame(CCmdUI* pCmdUI); - afx_msg void OnViewCompMonDeskARDiff(); - afx_msg void OnUpdateViewCompMonDeskARDiff(CCmdUI* pCmdUI); - afx_msg void OnViewPanNScan(UINT nID); - afx_msg void OnUpdateViewPanNScan(CCmdUI* pCmdUI); - afx_msg void OnViewPanNScanPresets(UINT nID); - afx_msg void OnUpdateViewPanNScanPresets(CCmdUI* pCmdUI); - afx_msg void OnViewRotate(UINT nID); - afx_msg void OnUpdateViewRotate(CCmdUI* pCmdUI); - afx_msg void OnViewAspectRatio(UINT nID); - afx_msg void OnUpdateViewAspectRatio(CCmdUI* pCmdUI); - afx_msg void OnViewAspectRatioNext(); - afx_msg void OnViewOntop(UINT nID); - afx_msg void OnUpdateViewOntop(CCmdUI* pCmdUI); - afx_msg void OnViewOptions(); - afx_msg void OnUpdateViewTearingTest(CCmdUI* pCmdUI); - afx_msg void OnViewTearingTest(); - afx_msg void OnUpdateViewDisplayRendererStats(CCmdUI* pCmdUI); - afx_msg void OnViewResetRendererStats(); - afx_msg void OnViewDisplayRendererStats(); - afx_msg void OnUpdateViewVSync(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewVSyncOffset(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewVSyncAccurate(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewFlushGPU(CCmdUI* pCmdUI); - - afx_msg void OnUpdateViewSynchronizeVideo(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewSynchronizeDisplay(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewSynchronizeNearest(CCmdUI* pCmdUI); - - afx_msg void OnUpdateViewD3DFullscreen(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewDisableDesktopComposition(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewAlternativeVSync(CCmdUI* pCmdUI); - - afx_msg void OnUpdateViewColorManagementEnable(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewColorManagementInput(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewColorManagementAmbientLight(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewColorManagementIntent(CCmdUI* pCmdUI); - - afx_msg void OnUpdateViewEVROutputRange(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewFullscreenGUISupport(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewHighColorResolution(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewForceInputHighColorResolution(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewFullFloatingPointProcessing(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewHalfFloatingPointProcessing(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewEnableFrameTimeCorrection(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewVSyncOffsetIncrease(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewVSyncOffsetDecrease(CCmdUI* pCmdUI); - afx_msg void OnViewVSync(); - afx_msg void OnViewVSyncAccurate(); - - afx_msg void OnViewSynchronizeVideo(); - afx_msg void OnViewSynchronizeDisplay(); - afx_msg void OnViewSynchronizeNearest(); - - afx_msg void OnViewColorManagementEnable(); - afx_msg void OnViewColorManagementInputAuto(); - afx_msg void OnViewColorManagementInputHDTV(); - afx_msg void OnViewColorManagementInputSDTV_NTSC(); - afx_msg void OnViewColorManagementInputSDTV_PAL(); - afx_msg void OnViewColorManagementAmbientLightBright(); - afx_msg void OnViewColorManagementAmbientLightDim(); - afx_msg void OnViewColorManagementAmbientLightDark(); - afx_msg void OnViewColorManagementIntentPerceptual(); - afx_msg void OnViewColorManagementIntentRelativeColorimetric(); - afx_msg void OnViewColorManagementIntentSaturation(); - afx_msg void OnViewColorManagementIntentAbsoluteColorimetric(); - - afx_msg void OnViewEVROutputRange_0_255(); - afx_msg void OnViewEVROutputRange_16_235(); - - afx_msg void OnViewFlushGPUBeforeVSync(); - afx_msg void OnViewFlushGPUAfterVSync(); - afx_msg void OnViewFlushGPUWait(); - - afx_msg void OnViewD3DFullScreen(); - afx_msg void OnViewDisableDesktopComposition(); - afx_msg void OnViewAlternativeVSync(); - afx_msg void OnViewResetDefault(); - afx_msg void OnViewResetOptimal(); - - afx_msg void OnViewFullscreenGUISupport(); - afx_msg void OnViewHighColorResolution(); - afx_msg void OnViewForceInputHighColorResolution(); - afx_msg void OnViewFullFloatingPointProcessing(); - afx_msg void OnViewHalfFloatingPointProcessing(); - afx_msg void OnViewEnableFrameTimeCorrection(); - afx_msg void OnViewVSyncOffsetIncrease(); - afx_msg void OnViewVSyncOffsetDecrease(); - afx_msg void OnUpdateShaderToggle1(CCmdUI* pCmdUI); - afx_msg void OnUpdateShaderToggle2(CCmdUI* pCmdUI); - afx_msg void OnShaderToggle1(); - afx_msg void OnShaderToggle2(); - afx_msg void OnUpdateViewOSDDisplayTime(CCmdUI* pCmdUI); - afx_msg void OnViewOSDDisplayTime(); - afx_msg void OnUpdateViewOSDShowFileName(CCmdUI* pCmdUI); - afx_msg void OnViewOSDShowFileName(); - afx_msg void OnD3DFullscreenToggle(); - afx_msg void OnGotoSubtitle(UINT nID); - afx_msg void OnSubresyncShiftSub(UINT nID); - afx_msg void OnSubtitleDelay(UINT nID); - afx_msg void OnSubtitlePos(UINT nID); - afx_msg void OnSubtitleFontSize(UINT nID); - - afx_msg void OnPlayPlay(); - afx_msg void OnPlayPause(); - afx_msg void OnPlayPlaypause(); - afx_msg void OnApiPlay(); - afx_msg void OnApiPause(); - afx_msg void OnPlayStop(); - void OnPlayStop(bool is_closing); - afx_msg void OnUpdatePlayPauseStop(CCmdUI* pCmdUI); - afx_msg void OnPlayFramestep(UINT nID); - afx_msg void OnUpdatePlayFramestep(CCmdUI* pCmdUI); - afx_msg void OnPlaySeek(UINT nID); - afx_msg void OnPlaySeekSet(); - afx_msg void OnPlaySeekKey(UINT nID); // no menu item - afx_msg void OnUpdatePlaySeek(CCmdUI* pCmdUI); - afx_msg void OnPlayChangeRate(UINT nID); - afx_msg void OnUpdatePlayChangeRate(CCmdUI* pCmdUI); - afx_msg void OnPlayResetRate(); - afx_msg void OnUpdatePlayResetRate(CCmdUI* pCmdUI); - afx_msg void OnPlayChangeAudDelay(UINT nID); - afx_msg void OnUpdatePlayChangeAudDelay(CCmdUI* pCmdUI); - afx_msg void OnPlayFiltersCopyToClipboard(); - afx_msg void OnPlayFilters(UINT nID); - afx_msg void OnUpdatePlayFilters(CCmdUI* pCmdUI); - afx_msg void OnPlayShadersSelect(); - afx_msg void OnPlayShadersPresetNext(); - afx_msg void OnPlayShadersPresetPrev(); - afx_msg void OnPlayShadersPresets(UINT nID); - afx_msg void OnPlayAudio(UINT nID); - afx_msg void OnSubtitlesDefaultStyle(); - afx_msg void OnPlaySubtitles(UINT nID); - afx_msg void OnPlayVideoStreams(UINT nID); - afx_msg void OnPlayFiltersStreams(UINT nID); - afx_msg void OnPlayVolume(UINT nID); - afx_msg void OnPlayVolumeBoost(UINT nID); - afx_msg void OnUpdatePlayVolumeBoost(CCmdUI* pCmdUI); - afx_msg void OnCustomChannelMapping(); - afx_msg void OnUpdateCustomChannelMapping(CCmdUI* pCmdUI); - afx_msg void OnNormalizeRegainVolume(UINT nID); - afx_msg void OnUpdateNormalizeRegainVolume(CCmdUI* pCmdUI); - afx_msg void OnPlayColor(UINT nID); - afx_msg void OnAfterplayback(UINT nID); - afx_msg void OnUpdateAfterplayback(CCmdUI* pCmdUI); - afx_msg void OnPlayRepeat(UINT nID); - afx_msg void OnUpdatePlayRepeat(CCmdUI* pCmdUI); - afx_msg void OnABRepeat(UINT nID); - afx_msg void OnUpdateABRepeat(CCmdUI* pCmdUI); - afx_msg void OnPlayRepeatForever(); - afx_msg void OnUpdatePlayRepeatForever(CCmdUI* pCmdUI); - - afx_msg void OnNavigateSkip(UINT nID); - afx_msg void OnUpdateNavigateSkip(CCmdUI* pCmdUI); - afx_msg void OnNavigateSkipFile(UINT nID); - afx_msg void OnUpdateNavigateSkipFile(CCmdUI* pCmdUI); - afx_msg void OnNavigateGoto(); - afx_msg void OnUpdateNavigateGoto(CCmdUI* pCmdUI); - afx_msg void OnNavigateMenu(UINT nID); - afx_msg void OnUpdateNavigateMenu(CCmdUI* pCmdUI); - afx_msg void OnNavigateJumpTo(UINT nID); - afx_msg void OnNavigateMenuItem(UINT nID); - afx_msg void OnUpdateNavigateMenuItem(CCmdUI* pCmdUI); - afx_msg void OnTunerScan(); - afx_msg void OnUpdateTunerScan(CCmdUI* pCmdUI); - - afx_msg void OnFavoritesAdd(); - afx_msg void OnUpdateFavoritesAdd(CCmdUI* pCmdUI); - afx_msg void OnFavoritesQuickAddFavorite(); - afx_msg void OnFavoritesOrganize(); - afx_msg void OnUpdateFavoritesOrganize(CCmdUI* pCmdUI); - afx_msg void OnFavoritesFile(UINT nID); - afx_msg void OnUpdateFavoritesFile(CCmdUI* pCmdUI); - afx_msg void OnFavoritesDVD(UINT nID); - afx_msg void OnUpdateFavoritesDVD(CCmdUI* pCmdUI); - afx_msg void OnFavoritesDevice(UINT nID); - afx_msg void OnUpdateFavoritesDevice(CCmdUI* pCmdUI); - afx_msg void OnRecentFileClear(); - afx_msg void OnUpdateRecentFileClear(CCmdUI* pCmdUI); - afx_msg void OnRecentFile(UINT nID); - afx_msg void OnUpdateRecentFile(CCmdUI* pCmdUI); - - afx_msg void OnHelpHomepage(); - afx_msg void OnHelpCheckForUpdate(); - afx_msg void OnHelpToolbarImages(); - afx_msg void OnHelpDonate(); - - afx_msg void OnClose(); - - bool FilterSettingsByClassID(CLSID clsid, CWnd* parent); - void FilterSettings(CComPtr pUnk, CWnd* parent); - - LRESULT OnMPCVRSwitchFullscreen(WPARAM wParam, LPARAM lParam); - - CMPC_Lcd m_Lcd; - - CMouseWndWithArtView* m_pVideoWnd; // Current Video (main display screen or 2nd) - CWnd* m_pOSDWnd; - CPreView m_wndPreView; // SeekPreview - - - void ReleasePreviewGraph(); - HRESULT PreviewWindowHide(); - HRESULT PreviewWindowShow(REFERENCE_TIME rtCur2); - HRESULT HandleMultipleEntryRar(CStringW fn); - bool CanPreviewUse(); - - CFullscreenWnd* m_pDedicatedFSVideoWnd; - COSD m_OSD; - int m_nCurSubtitle; - long m_lSubtitleShift; - REFERENCE_TIME m_rtCurSubPos; - bool m_bScanDlgOpened; - bool m_bStopTunerScan; - bool m_bLockedZoomVideoWindow; - int m_nLockedZoomVideoWindow; - - void SetLoadState(MLS eState); - MLS GetLoadState() const; - void SetPlayState(MPC_PLAYSTATE iState); - bool CreateFullScreenWindow(bool isD3D=true); - 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, bool relative = false); - //void AutoSelectTracks(); - void SetTimersPlay(); - void KillTimerDelayedSeek(); - void KillTimersStop(); - void AdjustStreamPosPoller(bool restart); - void ResetSubtitlePosAndSize(bool repaint = false); - - // MPC API functions - void ProcessAPICommand(COPYDATASTRUCT* pCDS); - void SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...); - void SendNowPlayingToApi(bool sendtrackinfo = true); - void SendSubtitleTracksToApi(); - void SendAudioTracksToApi(); - void SendPlaylistToApi(); - afx_msg void OnFileOpendirectory(); - - void SendCurrentPositionToApi(bool fNotifySeek = false); - void ShowOSDCustomMessageApi(const MPC_OSDDATA* osdData); - void JumpOfNSeconds(int seconds); - - CString GetVidPos() const; - - CComPtr m_pTaskbarList; - HRESULT CreateThumbnailToolbar(); - HRESULT UpdateThumbarButton(); - HRESULT UpdateThumbarButton(MPC_PLAYSTATE iPlayState); - HRESULT UpdateThumbnailClip(); - BOOL Create(LPCTSTR lpszClassName, - LPCTSTR lpszWindowName, - DWORD dwStyle = WS_OVERLAPPEDWINDOW, - const RECT& rect = rectDefault, - CWnd* pParentWnd = NULL, // != NULL for popups - LPCTSTR lpszMenuName = NULL, - DWORD dwExStyle = 0, - CCreateContext* pContext = NULL); - CMPCThemeMenu* defaultMPCThemeMenu = nullptr; - - bool isSafeZone(CPoint pt); - -protected: - afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); - // GDI+ - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - void WTSRegisterSessionNotification(); - void WTSUnRegisterSessionNotification(); - - CMenu* m_pActiveContextMenu; - CMenu* m_pActiveSystemMenu; - - void UpdateSkypeHandler(); - void UpdateSeekbarChapterBag(); - void UpdateAudioSwitcher(); - - void LoadArtToViews(const CString& imagePath); - void LoadArtToViews(std::vector buffer); - void ClearArtFromViews(); - - void UpdateUILanguage(); - - bool PerformFlipRotate(); - - bool m_bAltDownClean; - bool m_bShowingFloatingMenubar; - virtual void OnShowMenuBar() override { - m_bShowingFloatingMenubar = (GetMenuBarVisibility() != AFX_MBV_KEEPVISIBLE); - }; - virtual void OnHideMenuBar() override { - m_bShowingFloatingMenubar = false; - }; - virtual void SetMenuBarVisibility(DWORD dwStyle) override { - __super::SetMenuBarVisibility(dwStyle); - if (dwStyle & AFX_MBV_KEEPVISIBLE) { - m_bShowingFloatingMenubar = false; - } - }; - - bool IsAeroSnapped(); - - CPoint m_snapStartPoint; - CRect m_snapStartRect; - - bool m_bAllowWindowZoom; - double m_dLastVideoScaleFactor; - CSize m_lastVideoSize; - - bool m_bExtOnTop; // 'true' if the "on top" flag was set by an external tool - - CString m_sydlLastProcessURL; - - bool IsImageFile(CStringW fn); - bool IsPlayableFormatExt(CStringW ext); - bool IsAudioFileExt(CStringW ext); - bool IsImageFileExt(CStringW ext); - bool IsPlaylistFile(CStringW fn); - bool IsPlaylistFileExt(CStringW ext); - bool IsAudioOrVideoFileExt(CStringW ext); - bool CanSkipToExt(CStringW ext, CStringW curExt); - bool IsAudioFilename(CString filename); - - - // Handles MF_DEFAULT and escapes '&' - static BOOL AppendMenuEx(CMenu& menu, UINT nFlags, UINT nIDNewItem, CString& text); - - void SubtitlesSave(const TCHAR* directory = nullptr, bool silent = false); - - void OnSizingFixWndToVideo(UINT nSide, LPRECT lpRect, bool bCtrl = false); - void OnSizingSnapToScreen(UINT nSide, LPRECT lpRect, bool bCtrl = false); - -public: - afx_msg UINT OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData); - afx_msg void OnSessionChange(UINT nSessionState, UINT nId); - - enum UpdateControlTarget { - UPDATE_VOLUME_STEP, - UPDATE_LOGO, - UPDATE_SKYPE, - UPDATE_SEEKBAR_CHAPTERS, - UPDATE_WINDOW_TITLE, - UPDATE_AUDIO_SWITCHER, - UPDATE_CONTROLS_VISIBILITY, - UPDATE_CHILDVIEW_CURSOR_HACK, - }; - - void UpdateControlState(UpdateControlTarget target); - - void ReloadMenus(); - - // TODO: refactor it outside of MainFrm - GUID GetTimeFormat(); - - CHdmvClipInfo::HdmvPlaylist m_MPLSPlaylist; - bool m_bIsBDPlay; - bool OpenBD(CString Path); - bool m_bHasBDMeta; - CAtlList m_BDMeta; - CHdmvClipInfo::BDMVMeta GetBDMVMeta(); - - bool GetDecoderType(CString& type) const; - - static bool IsOnYDLWhitelist(const CString url); - - bool CanSendToYoutubeDL(const CString url); - bool ProcessYoutubeDLURL(CString url, bool append, bool replace = false); - bool DownloadWithYoutubeDL(CString url, CString filename); - - /** - * @brief Get title of file - * @param fTitleBarTextTitle - * @return - */ - CString getBestTitle(bool fTitleBarTextTitle = true); - MediaTransControls m_media_trans_control; - - void MediaTransportControlSetMedia(); - void MediaTransportControlUpdateState(OAFilterState state); - - enum themableDialogTypes { - None, - windowsFileDialog, - toolbarCustomizeDialog - }; - void enableFileDialogHook(CMPCThemeUtil* helper); - void enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type); -private: - themableDialogTypes watchingDialog, foundDialog; - CMPCThemeUtil* dialogHookHelper; - -public: - afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); - afx_msg void OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt); -private: - void SetupExternalChapters(); - void ApplyPanNScanPresetString(); - void ValidatePanNScanParameters(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "ChildView.h" +#include "DVBChannel.h" +#include "DebugShadersDlg.h" +#include "DropTarget.h" +#include "EditListEditor.h" +#include "IBufferInfo.h" +#include "IKeyFrameInfo.h" +#include "MainFrmControls.h" +#include "MouseTouch.h" +#include "MpcApi.h" +#include "PlayerCaptureBar.h" +#include "PlayerInfoBar.h" +#include "PlayerNavigationBar.h" +#include "PlayerPlaylistBar.h" +#include "PlayerSeekBar.h" +#include "PlayerStatusBar.h" +#include "PlayerSubresyncBar.h" +#include "PlayerPreView.h" +#include "PlayerToolBar.h" +#include "SubtitleDlDlg.h" +#include "TimerWrappers.h" +#include "OSD.h" +#include "CMPCThemeMenu.h" +#include "../SubPic/MemSubPic.h" +#include +#include +#include "../DSUtil/FontInstaller.h" +#include "AppSettings.h" +#include "../filters/transform/VSFilter/IDirectVobSub.h" +#include "MediaTransControls.h" +#include "FavoriteOrganizeDlg.h" +#include "AllocatorCommon.h" + +class CDebugShadersDlg; +class CFullscreenWnd; +class SkypeMoodMsgHandler; +struct DisplayMode; +enum MpcCaptionState; +class CMediaTypesDlg; + +interface IDSMChapterBag; +interface IGraphBuilder2; +interface IMFVideoDisplayControl; +interface IMFVideoProcessor; +interface IMadVRCommand; +interface IMadVRInfo; +interface IMadVRFrameGrabber; +interface IMadVRSettings; +interface IMadVRSubclassReplacement; +interface ISubClock; +interface ISubPicAllocatorPresenter2; +interface ISubPicAllocatorPresenter; +interface ISubStream; +interface ISyncClock; +DECLARE_INTERFACE_IID(IAMLine21Decoder_2, "6E8D4A21-310C-11d0-B79A-00AA003767A7"); + +enum class MLS { + CLOSED, + LOADING, + LOADED, + CLOSING, + FAILING, +}; + +enum { + PM_NONE, + PM_FILE, + PM_DVD, + PM_ANALOG_CAPTURE, + PM_DIGITAL_CAPTURE +}; + +class OpenMediaData +{ +public: + // OpenMediaData() {} + virtual ~OpenMediaData() {} // one virtual funct is needed to enable rtti + CString title; + CAtlList subs; +}; + +class OpenFileData : public OpenMediaData +{ +public: + OpenFileData() : rtStart(0), bAddToRecent(true) {} + CAtlList fns; + REFERENCE_TIME rtStart; + ABRepeat abRepeat; + bool bAddToRecent; + CString useragent; + CString referrer; +}; + +class OpenDVDData : public OpenMediaData +{ +public: + // OpenDVDData() {} + CString path; + CComPtr pDvdState; +}; + +class OpenDeviceData : public OpenMediaData +{ +public: + OpenDeviceData() { + vinput = vchannel = ainput = -1; + } + CStringW DisplayName[2]; + int vinput, vchannel, ainput; +}; + +class TunerScanData +{ +public: + ULONG FrequencyStart; + ULONG FrequencyStop; + ULONG Bandwidth; + ULONG SymbolRate; + LONG Offset; + HWND Hwnd; +}; + +struct SeekToCommand { + REFERENCE_TIME rtPos; + ULONGLONG seekTime; + bool bShowOSD; +}; + +struct SubtitleInput { + CComQIPtr pSubStream; + CComPtr pSourceFilter; + + SubtitleInput() {}; + SubtitleInput(CComQIPtr pSubStream) : pSubStream(pSubStream) {}; + SubtitleInput(CComQIPtr pSubStream, CComPtr pSourceFilter) + : pSubStream(pSubStream), pSourceFilter(pSourceFilter) {}; +}; + +struct FileFavorite { + CString Name; + REFERENCE_TIME Start; + REFERENCE_TIME MarkA; + REFERENCE_TIME MarkB; + BOOL RelativeDrive; + + FileFavorite() { + Start = MarkA = MarkB = 0; + RelativeDrive = FALSE; + } + + static bool TryParse(const CString& fav, FileFavorite& ff); + static bool TryParse(const CString& fav, FileFavorite& ff, CAtlList& parts); + + CString ToString() const; +}; + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame + +class CMainFrame : public CFrameWnd, public CDropClient +{ +public: + + DpiHelper m_dpi; + + enum class TimerHiderSubscriber { + TOOLBARS_HIDER, + CURSOR_HIDER, + CURSOR_HIDER_D3DFS, + }; + OnDemandTimer m_timerHider; + + enum class TimerOneTimeSubscriber { + TOOLBARS_DELAY_NOTLOADED, + CHILDVIEW_CURSOR_HACK, + DELAY_IDLE, + ACTIVE_SHADER_FILES_CHANGE_COOLDOWN, + DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, + DVBINFO_UPDATE, + STATUS_ERASE, + PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW, + AUTOFIT_TIMEOUT + }; + OneTimeTimerPool m_timerOneTime; + +private: + EventClient m_eventc; + void EventCallback(MpcEvent ev); + + CMainFrameMouseHook m_mouseHook; + + enum { + TIMER_STREAMPOSPOLLER = 1, + TIMER_STREAMPOSPOLLER2, + TIMER_STATS, + TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS, + TIMER_HIDER, + TIMER_WINDOW_FULLSCREEN, + TIMER_DELAYEDSEEK, + TIMER_ONETIME_START, + TIMER_ONETIME_END = TIMER_ONETIME_START + 127, + }; + enum { + SEEK_DIRECTION_NONE, + SEEK_DIRECTION_BACKWARD, + SEEK_DIRECTION_FORWARD + }; + enum { + ZOOM_DEFAULT_LEVEL = 0, + ZOOM_AUTOFIT = -1, + ZOOM_AUTOFIT_LARGER = -2 + }; + + + typedef std::map PlaybackRateMap; + static PlaybackRateMap filePlaybackRates; + static PlaybackRateMap dvdPlaybackRates; + + friend class CPPageFileInfoSheet; + friend class CPPageLogo; + friend class CMouse; + friend class CPlayerSeekBar; // for accessing m_controls.ControlChecked() + friend class CChildView; // for accessing m_controls.DelayShowNotLoaded() + friend class CFullscreenWnd; // for accessing m_controls.DelayShowNotLoaded() + friend class CMouseWndWithArtView; // for accessing m_controls.DelayShowNotLoaded() + friend class SubtitlesProvider; + + // TODO: wrap these graph objects into a class to make it look cleaner + + CComPtr m_pGB; + CComQIPtr m_pMC; + CComQIPtr m_pME; + CComQIPtr m_pVW; + CComQIPtr m_pBV; + CComQIPtr m_pBA; + CComQIPtr m_pMS; + CComQIPtr m_pFS; + CComQIPtr m_pFSF; + CComQIPtr m_pKFI; + CComQIPtr m_pQP; + CComQIPtr m_pBI; + CComQIPtr m_pAMOP; + CComQIPtr m_pAMMC[2]; + CComQIPtr m_pAMNS; + CComQIPtr m_pAudioSwitcherSS; + CComQIPtr m_pSplitterSS; + CComQIPtr m_pSplitterDubSS; + CComQIPtr m_pOtherSS[2]; + // SmarkSeek + CComPtr m_pGB_preview; + CComQIPtr m_pMC_preview; + //CComQIPtr m_pME_preview; + CComQIPtr m_pMS_preview; + CComQIPtr m_pVW_preview; + CComQIPtr m_pBV_preview; + //CComQIPtr m_pFS_preview; + CComQIPtr m_pDVDC_preview; + CComQIPtr m_pDVDI_preview; // VtX: usually not necessary but may sometimes be necessary. + CComPtr m_pMFVDC_preview; + CComPtr m_pVMR9C_preview; + CComPtr m_pMFVP_preview; + CComPtr m_pCAP2_preview; + int defaultVideoAngle; + // + CComPtr m_pVMRMC; + CComPtr m_pMFVDC; + CComPtr m_pMFVP; + CComPtr m_pVMB; + CComPtr m_pMFVMB; + CComPtr m_pVMRWC; + + CComPtr m_pCAP; + CComPtr m_pCAP2; + CComPtr m_pCAP3; + + CComPtr m_pMVRS; + CComPtr m_pMVRSR; + CComPtr m_pMVRC; + CComPtr m_pMVRI; + CComPtr m_pMVRFG; + CComPtr m_pMVTO; + + CComPtr m_pD3DFSC; + + CComQIPtr m_pDVDC; + CComQIPtr m_pDVDI; + CComPtr m_pLN21; + + CComPtr m_pCGB; + CStringW m_VidDispName, m_AudDispName; + CComPtr m_pVidCap, m_pAudCap; + CComPtr m_pAMVCCap, m_pAMVCPrev; + CComPtr m_pAMVSCCap, m_pAMVSCPrev, m_pAMASC; + CComPtr m_pAMXBar; + CComPtr m_pAMTuner; + CComPtr m_pAMDF; + + CComPtr m_pProv; + + CComQIPtr m_pDVS; + CComQIPtr m_pDVS2; + + bool m_bUsingDXVA; + LPCTSTR m_HWAccelType; + void UpdateDXVAStatus(); + + void SetVolumeBoost(UINT nAudioBoost); + void SetBalance(int balance); + + // temp fonts loader + CFontInstaller m_FontInstaller; + + // subtitles + + CCritSec m_csSubLock; + CCritSec m_csSubtitleManagementLock; + + CList m_pSubStreams; + std::list m_ExternalSubstreams; + POSITION m_posFirstExtSub; + SubtitleInput m_pCurrentSubInput; + + // StatusBar message text parts + CString currentAudioLang; + CString currentSubLang; + CString m_statusbarVideoFormat; + CString m_statusbarAudioFormat; + CString m_statusbarVideoSize; + + SubtitleInput* GetSubtitleInput(int& i, bool bIsOffset = false); + int UpdateSelectedAudioStreamInfo(int index, AM_MEDIA_TYPE* pmt, LCID lcid); + bool IsValidSubtitleStream(int i); + int GetSelectedSubtitleTrackIndex(); + + friend class CTextPassThruFilter; + + // windowing + + bool m_bDelaySetOutputRect; + + CRect m_lastWindowRect; + + void SetDefaultWindowRect(int iMonitor = 0); + void SetDefaultFullscreenState(); + void RestoreDefaultWindowRect(); + CRect GetInvisibleBorderSize() const; + CSize GetVideoOrArtSize(MINMAXINFO& mmi); + CSize GetZoomWindowSize(double dScale, bool ignore_video_size = false); + bool GetWorkAreaRect(CRect& work); + CRect GetZoomWindowRect(const CSize& size, bool ignoreSavedPosition = false); + void ZoomVideoWindow(double dScale = ZOOM_DEFAULT_LEVEL, bool ignore_video_size = false); + double GetZoomAutoFitScale(); + + bool alwaysOnTopZOrderInitialized = false; + void SetAlwaysOnTop(int iOnTop); + bool WindowExpectedOnTop(); + + // dynamic menus + + void CreateDynamicMenus(); + void DestroyDynamicMenus(); + void SetupOpenCDSubMenu(); + void SetupFiltersSubMenu(); + void SetupAudioSubMenu(); + void SetupSubtitlesSubMenu(); + void SetupVideoStreamsSubMenu(); + void SetupJumpToSubMenus(CMenu* parentMenu = nullptr, int iInsertPos = -1); + void SetupFavoritesSubMenu(); + bool SetupShadersSubMenu(); + void SetupRecentFilesSubMenu(); + + DWORD SetupNavStreamSelectSubMenu(CMenu& subMenu, UINT id, DWORD dwSelGroup); + void OnNavStreamSelectSubMenu(UINT id, DWORD dwSelGroup); + void OnStreamSelect(bool forward, DWORD dwSelGroup); + static CString GetStreamOSDString(CString name, LCID lcid, DWORD dwSelGroup); + + void CreateOSDBar(); + bool OSDBarSetPos(); + void DestroyOSDBar(); + + CMPCThemeMenu m_mainPopupMenu, m_popupMenu; + CMPCThemeMenu m_openCDsMenu; + CMPCThemeMenu m_filtersMenu, m_subtitlesMenu, m_audiosMenu, m_videoStreamsMenu; + CMPCThemeMenu m_chaptersMenu, m_titlesMenu, m_playlistMenu, m_BDPlaylistMenu, m_channelsMenu; + CMPCThemeMenu m_favoritesMenu; + CMPCThemeMenu m_shadersMenu; + CMPCThemeMenu m_recentFilesMenu; + int recentFilesMenuFromMRUSequence; + + UINT m_nJumpToSubMenusCount; + + CInterfaceArray m_pparray; + CInterfaceArray m_ssarray; + + // chapters (file mode) + CComPtr m_pCB; + void SetupChapters(); + void SetupCueChapters(CString fn); + + // chapters (DVD mode) + void SetupDVDChapters(); + + bool SeekToFileChapter(int iChapter, bool bRelative = false); + bool SeekToDVDChapter(int iChapter, bool bRelative = false); + + void AddTextPassThruFilter(); + + int m_nLoops; + ABRepeat abRepeat, reloadABRepeat; + UINT m_nLastSkipDirection; + + int m_iStreamPosPollerInterval; + + bool m_fCustomGraph; + bool m_fShockwaveGraph; + + CComPtr m_pSubClock; + + bool m_fFrameSteppingActive; + int m_nStepForwardCount; + REFERENCE_TIME m_rtStepForwardStart; + int m_nVolumeBeforeFrameStepping; + + bool m_fEndOfStream; + ULONGLONG m_dwLastPause; + ULONGLONG m_dwReloadPos; + int m_iReloadAudioIdx; + int m_iReloadSubIdx; + + bool m_bRememberFilePos; + + ULONGLONG m_dwLastRun; + + bool m_bBuffering; + + bool m_fLiveWM; + + bool delayingFullScreen; + + bool m_bIsMPCVRExclusiveMode = false; + + void SendStatusMessage(CString msg, int nTimeOut); + CString m_tempstatus_msg, m_closingmsg; + + REFERENCE_TIME m_rtDurationOverride; + + void CleanGraph(); + + void ShowOptions(int idPage = 0); + + HRESULT GetDisplayedImage(std::vector& dib, CString& errmsg); + HRESULT GetCurrentFrame(std::vector& dib, CString& errmsg); + HRESULT GetOriginalFrame(std::vector& dib, CString& errmsg); + HRESULT RenderCurrentSubtitles(BYTE* pData); + bool GetDIB(BYTE** ppData, long& size, bool fSilent = false); + void SaveDIB(LPCTSTR fn, BYTE* pData, long size); + CString MakeSnapshotFileName(BOOL thumbnails); + BOOL IsRendererCompatibleWithSaveImage(); + void SaveImage(LPCTSTR fn, bool displayed, bool includeSubtitles); + void SaveThumbnails(LPCTSTR fn); + + // + + friend class CWebClientSocket; + friend class CWebServer; + CAutoPtr m_pWebServer; + int m_iPlaybackMode; + ULONG m_lCurrentChapter; + ULONG m_lChapterStartTime; + + CString m_currentCoverAuthor; + CString m_currentCoverPath; + bool currentCoverIsFileArt = false; + + CAutoPtr m_pSkypeMoodMsgHandler; + void SendNowPlayingToSkype(); + + MLS m_eMediaLoadState; + OAFilterState m_CachedFilterState; + + bool m_bSettingUpMenus; + bool m_bOpenMediaActive; + int m_OpenMediaFailedCount; + + REFTIME GetAvgTimePerFrame() const; + void OnVideoSizeChanged(const bool bWasAudioOnly = false); + + CDropTarget m_dropTarget; + void OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) override; + DROPEFFECT OnDropAccept(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) override; + +public: + void StartWebServer(int nPort); + void StopWebServer(); + + int GetPlaybackMode() const { + return m_iPlaybackMode; + } + bool IsPlaybackCaptureMode() const { + return GetPlaybackMode() == PM_ANALOG_CAPTURE || GetPlaybackMode() == PM_DIGITAL_CAPTURE; + } + void SetPlaybackMode(int iNewStatus); + bool IsMuted() { + return m_wndToolBar.GetVolume() == -10000; + } + int GetVolume() { + return m_wndToolBar.m_volctrl.GetPos(); + } + double GetPlayingRate() const { + return m_dSpeedRate; + } + +public: + CMainFrame(); + DECLARE_DYNAMIC(CMainFrame) + + // Attributes +public: + bool m_fFullScreen; + bool m_bNeedZoomAfterFullscreenExit; + bool m_fStartInD3DFullscreen; + bool m_fStartInFullscreenSeparate; + bool m_bFullScreenWindowIsD3D; + bool m_bFullScreenWindowIsOnSeparateDisplay; + + CComPtr m_pRefClock; // Adjustable reference clock. GothSync + CComPtr m_pSyncClock; + + bool IsFrameLessWindow() const; + bool IsCaptionHidden() const; + bool IsMenuHidden() const; + bool IsPlaylistEmpty() const; + bool IsInteractiveVideo() const; + bool IsFullScreenMode() const; + bool IsFullScreenMainFrame() const; + bool IsFullScreenMainFrameExclusiveMPCVR() const; + bool IsFullScreenSeparate() const; + bool HasDedicatedFSVideoWindow() const; + bool IsD3DFullScreenMode() const; + bool IsSubresyncBarVisible() const; + + CControlBar* m_pLastBar; + +protected: + bool m_bUseSeekPreview; + bool m_bFirstPlay; + bool m_bOpeningInAutochangedMonitorMode; + bool m_bPausedForAutochangeMonitorMode; + bool restoringWindowRect; + + bool m_fAudioOnly; + bool m_fValidDVDOpen; + CString m_LastOpenBDPath; + CAutoPtr m_lastOMD; + + DVD_DOMAIN m_iDVDDomain; + DWORD m_iDVDTitle; + bool m_bDVDStillOn; + int m_loadedAudioTrackIndex = -1; + int m_loadedSubtitleTrackIndex = -1; + int m_audioTrackCount = 0; + + double m_dSpeedRate; + double m_ZoomX, m_ZoomY, m_PosX, m_PosY; + int m_AngleX, m_AngleY, m_AngleZ; + int m_iDefRotation; + + void ForceCloseProcess(); + + // Operations + bool OpenMediaPrivate(CAutoPtr pOMD); + void CloseMediaPrivate(); + void DoTunerScan(TunerScanData* pTSD); + + CWnd* GetModalParent(); + + CCritSec lockModalDialog; + CMediaTypesDlg* mediaTypesErrorDlg; + void ShowMediaTypesDialog(); + + void OpenCreateGraphObject(OpenMediaData* pOMD); + void OpenFile(OpenFileData* pOFD); + void OpenDVD(OpenDVDData* pODD); + void OpenCapture(OpenDeviceData* pODD); + HRESULT OpenBDAGraph(); + void OpenCustomizeGraph(); + void OpenSetupVideo(); + void OpenSetupAudio(); + void OpenSetupInfoBar(bool bClear = true); + void UpdateChapterInInfoBar(); + void OpenSetupStatsBar(); + void CheckSelectedAudioStream(); + void OpenSetupStatusBar(); + void OpenSetupCaptureBar(); + void OpenSetupWindowTitle(bool reset = false); + +public: + static bool GetCurDispMode(const CString& displayName, DisplayMode& dm); + static bool GetDispMode(CString displayName, int i, DisplayMode& dm); + +protected: + void SetDispMode(CString displayName, const DisplayMode& dm, int msAudioDelay); + void AutoChangeMonitorMode(); + + void GraphEventComplete(); + + friend class CGraphThread; + CGraphThread* m_pGraphThread; + bool m_bOpenedThroughThread; + ATL::CEvent m_evOpenPrivateFinished; + ATL::CEvent m_evClosePrivateFinished; + + void LoadKeyFrames(); + std::vector m_kfs; + + bool m_fOpeningAborted; + bool m_bWasSnapped; + +protected: + friend class CSubtitleDlDlg; + CSubtitleDlDlg m_wndSubtitlesDownloadDialog; + CFavoriteOrganizeDlg m_wndFavoriteOrganizeDialog; + friend class CPPageSubMisc; + + friend class SubtitlesProviders; + std::unique_ptr m_pSubtitlesProviders; + friend struct SubtitlesInfo; + friend class SubtitlesTask; + friend class SubtitlesThread; + +public: + void OpenCurPlaylistItem(REFERENCE_TIME rtStart = 0, bool reopen = false, ABRepeat abRepeat = ABRepeat()); + void OpenMedia(CAutoPtr pOMD); + void PlayFavoriteFile(const CString& fav); + void PlayFavoriteDVD(CString fav); + FileFavorite ParseFavoriteFile(const CString& fav, CAtlList& args, REFERENCE_TIME* prtStart = nullptr); + bool ResetDevice(); + bool DisplayChange(); + void CloseMediaBeforeOpen(); + void CloseMedia(bool bNextIsQueued = false, bool bPendingFileDelete = false); + void StartTunerScan(CAutoPtr pTSD); + void StopTunerScan(); + HRESULT SetChannel(int nChannel); + + void AddCurDevToPlaylist(); + + bool m_bTrayIcon; + void ShowTrayIcon(bool bShow); + void SetTrayTip(const CString& str); + + CSize GetVideoSize() const; + CSize GetVideoSizeWithRotation(bool forPreview = false) const; + void HidePlaylistFullScreen(bool force = false); + void ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo); + void ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo); + void MoveVideoWindow(bool fShowStats = false, bool bSetStoppedVideoRect = false); + void SetPreviewVideoPosition(); + + void RepaintVideo(const bool bForceRepaint = false); + void HideVideoWindow(bool fHide); + + OAFilterState GetMediaStateDirect() const; + OAFilterState GetMediaState() const; + OAFilterState CMainFrame::UpdateCachedMediaState(); + bool MediaControlRun(bool waitforcompletion = false); + bool MediaControlPause(bool waitforcompletion = false); + bool MediaControlStop(bool waitforcompletion = false); + bool MediaControlStopPreview(); + + REFERENCE_TIME GetPos() const; + REFERENCE_TIME GetDur() const; + bool GetKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMin, REFERENCE_TIME rtMax, bool nearest, REFERENCE_TIME& keyframetime) const; + REFERENCE_TIME GetClosestKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMaxForwardDiff, REFERENCE_TIME rtMaxBackwardDiff) const; + REFERENCE_TIME GetClosestKeyFramePreview(REFERENCE_TIME rtTarget) const; + void SeekTo(REFERENCE_TIME rt, bool bShowOSD = true); + void DoSeekTo(REFERENCE_TIME rt, bool bShowOSD = true); + SeekToCommand queuedSeek; + ULONGLONG lastSeekStart; + ULONGLONG lastSeekFinish; + void SetPlayingRate(double rate); + + int SetupAudioStreams(); + int SetupSubtitleStreams(); + + bool LoadSubtitle(CString fn, SubtitleInput* pSubInput = nullptr, bool bAutoLoad = false); + bool LoadSubtitle(CYoutubeDLInstance::YDLSubInfo& sub); + bool SetSubtitle(int i, bool bIsOffset = false, bool bDisplayMessage = false); + void SetSubtitle(const SubtitleInput& subInput, bool skip_lcid = false); + void UpdateSubtitleColorInfo(); + void ToggleSubtitleOnOff(bool bDisplayMessage = false); + void ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew); + void InvalidateSubtitle(DWORD_PTR nSubtitleId = DWORD_PTR_MAX, REFERENCE_TIME rtInvalidate = -1); + void ReloadSubtitle(); + void UpdateSubtitleRenderingParameters(); + HRESULT InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinto); + + void SetAudioTrackIdx(int index); + void SetSubtitleTrackIdx(int index); + int GetCurrentAudioTrackIdx(CString *pstrName = nullptr); + int GetCurrentSubtitleTrackIdx(CString *pstrName = nullptr); + + void AddFavorite(bool fDisplayMessage = false, bool fShowDialog = true); + + CString GetFileName(); + CString GetCaptureTitle(); + + // shaders + void SetShaders(bool bSetPreResize = true, bool bSetPostResize = true); + + bool m_bToggleShader; + bool m_bToggleShaderScreenSpace; + std::list m_ShaderCache; + ShaderC* GetShader(CString path, bool bD3D11); + bool SaveShaderFile(ShaderC* shader); + bool DeleteShaderFile(LPCWSTR label); + void TidyShaderCache(); + + // 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(); + + void DoAfterPlaybackEvent(); + bool SearchInDir(bool bDirForward, bool bLoop = false); + bool WildcardFileSearch(CString searchstr, std::set& results, bool recurse_dirs); + CString lastOpenFile; + bool CanSkipFromClosedFile(); + + 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); + void EnableDocking(DWORD dwDockStyle); + + // DVB capture + void UpdateCurrentChannelInfo(bool bShowOSD = true, bool bShowInfoBar = false); + LRESULT OnCurrentChannelInfoUpdated(WPARAM wParam, LPARAM lParam); + + bool CheckABRepeat(REFERENCE_TIME& aPos, REFERENCE_TIME& bPos); + void PerformABRepeat(); + void DisableABRepeat(); + + struct DVBState { + struct EITData { + HRESULT hr = E_FAIL; + EventDescriptor NowNext; + bool bShowOSD = true; + bool bShowInfoBar = false; + }; + + CString sChannelName; // Current channel name + CBDAChannel* pChannel = nullptr; // Pointer to current channel object + EventDescriptor NowNext; // Current channel EIT + bool bActive = false; // True when channel is active + bool bSetChannelActive = false; // True when channel change is in progress + bool bInfoActive = false; // True when EIT data update is in progress + bool bAbortInfo = true; // True when aborting current EIT update + std::future infoData; + + void Reset() { + sChannelName.Empty(); + pChannel = nullptr; + NowNext = EventDescriptor(); + bActive = false; + bSetChannelActive = false; + bInfoActive = false; + bAbortInfo = true; + } + + void Join() { + if (infoData.valid()) { + bAbortInfo = true; + infoData.wait(); + } + } + + ~DVBState() { + bAbortInfo = true; + } + }; + + std::unique_ptr m_pDVBState = nullptr; + + // Implementation +public: + virtual ~CMainFrame(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +protected: // control bar embedded members + friend class CMainFrameControls; + friend class CPPageToolBar; + CMainFrameControls m_controls; + friend class CPlayerBar; // it notifies m_controls of panel re-dock + + CChildView m_wndView; + + CPlayerSeekBar m_wndSeekBar; + CPlayerToolBar m_wndToolBar; + CPlayerInfoBar m_wndInfoBar; + CPlayerInfoBar m_wndStatsBar; + CPlayerStatusBar m_wndStatusBar; + + CPlayerSubresyncBar m_wndSubresyncBar; + CPlayerPlaylistBar m_wndPlaylistBar; + CPlayerCaptureBar m_wndCaptureBar; + CPlayerNavigationBar m_wndNavigationBar; + CEditListEditor m_wndEditListEditor; + + std::unique_ptr m_pDebugShaders; + + LPCTSTR GetRecentFile() const; + + friend class CPPagePlayback; // TODO + friend class CPPageAudioSwitcher; // TODO + friend class CMPlayerCApp; // TODO + + // Generated message map functions + + DECLARE_MESSAGE_MAP() + +public: + afx_msg int OnNcCreate(LPCREATESTRUCT lpCreateStruct); + 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 OnEnterSizeMove(); + afx_msg void OnMoving(UINT fwSide, LPRECT pRect); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnSizing(UINT nSide, LPRECT lpRect); + afx_msg void OnExitSizeMove(); + afx_msg void OnDisplayChange(); + afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); + + LRESULT OnDpiChanged(WPARAM wParam, LPARAM lParam); + + 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 void SaveAppSettings(); + + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + + void RestoreFocus(); + + afx_msg void OnInitMenu(CMenu* pMenu); + afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); + afx_msg void OnUnInitMenuPopup(CMenu* pPopupMenu, UINT nFlags); + afx_msg void OnEnterMenuLoop(BOOL bIsTrackPopupMenu); + + afx_msg BOOL OnQueryEndSession(); + afx_msg void OnEndSession(BOOL bEnding); + + BOOL OnMenu(CMenu* pMenu); + afx_msg void OnMenuPlayerShort(); + afx_msg void OnMenuPlayerLong(); + afx_msg void OnMenuFilters(); + + afx_msg void OnUpdatePlayerStatus(CCmdUI* pCmdUI); + + afx_msg LRESULT OnFilePostOpenmedia(WPARAM wParam, LPARAM lparam); + afx_msg LRESULT OnOpenMediaFailed(WPARAM wParam, LPARAM lParam); + void OnFilePostClosemedia(bool bNextIsQueued = false); + + afx_msg void OnBossKey(); + + afx_msg void OnStreamAudio(UINT nID); + afx_msg void OnStreamSub(UINT nID); + afx_msg void OnStreamSubOnOff(); + afx_msg void OnAudioShiftOnOff(); + afx_msg void OnDvdAngle(UINT nID); + afx_msg void OnDvdAudio(UINT nID); + afx_msg void OnDvdSub(UINT nID); + afx_msg void OnDvdSubOnOff(); + + afx_msg LRESULT OnLoadSubtitles(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnGetSubtitles(WPARAM, LPARAM lParam); + + // menu item handlers + + INT_PTR DoFileDialogWithLastFolder(CFileDialog& fd, CStringW& lastPath); + void OpenDVDOrBD(CStringW path); + + 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 OnFileOpenOpticalDisk(UINT nID); + afx_msg void OnFileReopen(); + afx_msg void OnFileRecycle(); + afx_msg void OnFileSaveAs(); + afx_msg void OnUpdateFileSaveAs(CCmdUI* pCmdUI); + afx_msg void OnFileSaveImage(); + afx_msg void OnFileSaveImageAuto(); + afx_msg void OnUpdateFileSaveImage(CCmdUI* pCmdUI); + afx_msg void OnCmdLineSaveThumbnails(); + afx_msg void OnFileSaveThumbnails(); + afx_msg void OnUpdateFileSaveThumbnails(CCmdUI* pCmdUI); + afx_msg void OnFileSubtitlesLoad(); + afx_msg void OnUpdateFileSubtitlesLoad(CCmdUI* pCmdUI); + afx_msg void OnFileSubtitlesSave() { SubtitlesSave(); } + afx_msg void OnUpdateFileSubtitlesSave(CCmdUI* pCmdUI); + //afx_msg void OnFileSubtitlesUpload(); + //afx_msg void OnUpdateFileSubtitlesUpload(CCmdUI* pCmdUI); + afx_msg void OnFileSubtitlesDownload(); + afx_msg void OnUpdateFileSubtitlesDownload(CCmdUI* pCmdUI); + afx_msg void OnFileProperties(); + afx_msg void OnUpdateFileProperties(CCmdUI* pCmdUI); + afx_msg void OnFileOpenLocation(); + afx_msg void OnFileCloseAndRestore(); + afx_msg void OnFileCloseMedia(); // no menu item + afx_msg void OnUpdateFileClose(CCmdUI* pCmdUI); + + void SetCaptionState(MpcCaptionState eState); + afx_msg void OnViewCaptionmenu(); + + afx_msg void OnViewNavigation(); + afx_msg void OnUpdateViewCaptionmenu(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewNavigation(CCmdUI* pCmdUI); + afx_msg void OnViewControlBar(UINT nID); + afx_msg void OnUpdateViewControlBar(CCmdUI* pCmdUI); + afx_msg void OnViewSubresync(); + afx_msg void OnUpdateViewSubresync(CCmdUI* pCmdUI); + afx_msg void OnViewPlaylist(); + afx_msg void OnPlaylistToggleShuffle(); + afx_msg void OnUpdateViewPlaylist(CCmdUI* pCmdUI); + afx_msg void OnViewEditListEditor(); + afx_msg void OnEDLIn(); + afx_msg void OnUpdateEDLIn(CCmdUI* pCmdUI); + afx_msg void OnEDLOut(); + afx_msg void OnUpdateEDLOut(CCmdUI* pCmdUI); + afx_msg void OnEDLNewClip(); + afx_msg void OnUpdateEDLNewClip(CCmdUI* pCmdUI); + afx_msg void OnEDLSave(); + afx_msg void OnUpdateEDLSave(CCmdUI* pCmdUI); + afx_msg void OnViewCapture(); + afx_msg void OnUpdateViewCapture(CCmdUI* pCmdUI); + afx_msg void OnViewDebugShaders(); + afx_msg void OnUpdateViewDebugShaders(CCmdUI* pCmdUI); + afx_msg void OnViewMinimal(); + afx_msg void OnUpdateViewMinimal(CCmdUI* pCmdUI); + afx_msg void OnViewCompact(); + afx_msg void OnUpdateViewCompact(CCmdUI* pCmdUI); + afx_msg void OnViewNormal(); + afx_msg void OnUpdateViewNormal(CCmdUI* pCmdUI); + afx_msg void OnViewFullscreen(); + afx_msg void OnViewFullscreenSecondary(); + afx_msg void OnUpdateViewFullscreen(CCmdUI* pCmdUI); + afx_msg void OnViewZoom(UINT nID); + afx_msg void OnUpdateViewZoom(CCmdUI* pCmdUI); + afx_msg void OnViewZoomAutoFit(); + afx_msg void OnViewZoomAutoFitLarger(); + afx_msg void OnViewModifySize(UINT nID); + afx_msg void OnViewDefaultVideoFrame(UINT nID); + afx_msg void OnUpdateViewDefaultVideoFrame(CCmdUI* pCmdUI); + afx_msg void OnViewSwitchVideoFrame(); + afx_msg void OnUpdateViewSwitchVideoFrame(CCmdUI* pCmdUI); + afx_msg void OnViewCompMonDeskARDiff(); + afx_msg void OnUpdateViewCompMonDeskARDiff(CCmdUI* pCmdUI); + afx_msg void OnViewPanNScan(UINT nID); + afx_msg void OnUpdateViewPanNScan(CCmdUI* pCmdUI); + afx_msg void OnViewPanNScanPresets(UINT nID); + afx_msg void OnUpdateViewPanNScanPresets(CCmdUI* pCmdUI); + afx_msg void OnViewRotate(UINT nID); + afx_msg void OnUpdateViewRotate(CCmdUI* pCmdUI); + afx_msg void OnViewAspectRatio(UINT nID); + afx_msg void OnUpdateViewAspectRatio(CCmdUI* pCmdUI); + afx_msg void OnViewAspectRatioNext(); + afx_msg void OnViewOntop(UINT nID); + afx_msg void OnUpdateViewOntop(CCmdUI* pCmdUI); + afx_msg void OnViewOptions(); + afx_msg void OnUpdateViewTearingTest(CCmdUI* pCmdUI); + afx_msg void OnViewTearingTest(); + afx_msg void OnUpdateViewDisplayRendererStats(CCmdUI* pCmdUI); + afx_msg void OnViewResetRendererStats(); + afx_msg void OnViewDisplayRendererStats(); + afx_msg void OnUpdateViewVSync(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewVSyncOffset(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewVSyncAccurate(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewFlushGPU(CCmdUI* pCmdUI); + + afx_msg void OnUpdateViewSynchronizeVideo(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewSynchronizeDisplay(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewSynchronizeNearest(CCmdUI* pCmdUI); + + afx_msg void OnUpdateViewD3DFullscreen(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewDisableDesktopComposition(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewAlternativeVSync(CCmdUI* pCmdUI); + + afx_msg void OnUpdateViewColorManagementEnable(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewColorManagementInput(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewColorManagementAmbientLight(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewColorManagementIntent(CCmdUI* pCmdUI); + + afx_msg void OnUpdateViewEVROutputRange(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewFullscreenGUISupport(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewHighColorResolution(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewForceInputHighColorResolution(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewFullFloatingPointProcessing(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewHalfFloatingPointProcessing(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewEnableFrameTimeCorrection(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewVSyncOffsetIncrease(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewVSyncOffsetDecrease(CCmdUI* pCmdUI); + afx_msg void OnViewVSync(); + afx_msg void OnViewVSyncAccurate(); + + afx_msg void OnViewSynchronizeVideo(); + afx_msg void OnViewSynchronizeDisplay(); + afx_msg void OnViewSynchronizeNearest(); + + afx_msg void OnViewColorManagementEnable(); + afx_msg void OnViewColorManagementInputAuto(); + afx_msg void OnViewColorManagementInputHDTV(); + afx_msg void OnViewColorManagementInputSDTV_NTSC(); + afx_msg void OnViewColorManagementInputSDTV_PAL(); + afx_msg void OnViewColorManagementAmbientLightBright(); + afx_msg void OnViewColorManagementAmbientLightDim(); + afx_msg void OnViewColorManagementAmbientLightDark(); + afx_msg void OnViewColorManagementIntentPerceptual(); + afx_msg void OnViewColorManagementIntentRelativeColorimetric(); + afx_msg void OnViewColorManagementIntentSaturation(); + afx_msg void OnViewColorManagementIntentAbsoluteColorimetric(); + + afx_msg void OnViewEVROutputRange_0_255(); + afx_msg void OnViewEVROutputRange_16_235(); + + afx_msg void OnViewFlushGPUBeforeVSync(); + afx_msg void OnViewFlushGPUAfterVSync(); + afx_msg void OnViewFlushGPUWait(); + + afx_msg void OnViewD3DFullScreen(); + afx_msg void OnViewDisableDesktopComposition(); + afx_msg void OnViewAlternativeVSync(); + afx_msg void OnViewResetDefault(); + afx_msg void OnViewResetOptimal(); + + afx_msg void OnViewFullscreenGUISupport(); + afx_msg void OnViewHighColorResolution(); + afx_msg void OnViewForceInputHighColorResolution(); + afx_msg void OnViewFullFloatingPointProcessing(); + afx_msg void OnViewHalfFloatingPointProcessing(); + afx_msg void OnViewEnableFrameTimeCorrection(); + afx_msg void OnViewVSyncOffsetIncrease(); + afx_msg void OnViewVSyncOffsetDecrease(); + afx_msg void OnUpdateShaderToggle1(CCmdUI* pCmdUI); + afx_msg void OnUpdateShaderToggle2(CCmdUI* pCmdUI); + afx_msg void OnShaderToggle1(); + afx_msg void OnShaderToggle2(); + afx_msg void OnUpdateViewOSDDisplayTime(CCmdUI* pCmdUI); + afx_msg void OnViewOSDDisplayTime(); + afx_msg void OnUpdateViewOSDShowFileName(CCmdUI* pCmdUI); + afx_msg void OnViewOSDShowFileName(); + afx_msg void OnD3DFullscreenToggle(); + afx_msg void OnGotoSubtitle(UINT nID); + afx_msg void OnSubresyncShiftSub(UINT nID); + afx_msg void OnSubtitleDelay(UINT nID); + afx_msg void OnSubtitlePos(UINT nID); + afx_msg void OnSubtitleFontSize(UINT nID); + + afx_msg void OnPlayPlay(); + afx_msg void OnPlayPause(); + afx_msg void OnPlayPlaypause(); + afx_msg void OnApiPlay(); + afx_msg void OnApiPause(); + afx_msg void OnPlayStop(); + void OnPlayStop(bool is_closing); + afx_msg void OnUpdatePlayPauseStop(CCmdUI* pCmdUI); + afx_msg void OnPlayFramestep(UINT nID); + afx_msg void OnUpdatePlayFramestep(CCmdUI* pCmdUI); + afx_msg void OnPlaySeek(UINT nID); + afx_msg void OnPlaySeekSet(); + afx_msg void OnPlaySeekKey(UINT nID); // no menu item + afx_msg void OnUpdatePlaySeek(CCmdUI* pCmdUI); + afx_msg void OnPlayChangeRate(UINT nID); + afx_msg void OnUpdatePlayChangeRate(CCmdUI* pCmdUI); + afx_msg void OnPlayResetRate(); + afx_msg void OnUpdatePlayResetRate(CCmdUI* pCmdUI); + afx_msg void OnPlayChangeAudDelay(UINT nID); + afx_msg void OnUpdatePlayChangeAudDelay(CCmdUI* pCmdUI); + afx_msg void OnPlayFiltersCopyToClipboard(); + afx_msg void OnPlayFilters(UINT nID); + afx_msg void OnUpdatePlayFilters(CCmdUI* pCmdUI); + afx_msg void OnPlayShadersSelect(); + afx_msg void OnPlayShadersPresetNext(); + afx_msg void OnPlayShadersPresetPrev(); + afx_msg void OnPlayShadersPresets(UINT nID); + afx_msg void OnPlayAudio(UINT nID); + afx_msg void OnSubtitlesDefaultStyle(); + afx_msg void OnPlaySubtitles(UINT nID); + afx_msg void OnPlayVideoStreams(UINT nID); + afx_msg void OnPlayFiltersStreams(UINT nID); + afx_msg void OnPlayVolume(UINT nID); + afx_msg void OnPlayVolumeBoost(UINT nID); + afx_msg void OnUpdatePlayVolumeBoost(CCmdUI* pCmdUI); + afx_msg void OnCustomChannelMapping(); + afx_msg void OnUpdateCustomChannelMapping(CCmdUI* pCmdUI); + afx_msg void OnNormalizeRegainVolume(UINT nID); + afx_msg void OnUpdateNormalizeRegainVolume(CCmdUI* pCmdUI); + afx_msg void OnPlayColor(UINT nID); + afx_msg void OnAfterplayback(UINT nID); + afx_msg void OnUpdateAfterplayback(CCmdUI* pCmdUI); + afx_msg void OnPlayRepeat(UINT nID); + afx_msg void OnUpdatePlayRepeat(CCmdUI* pCmdUI); + afx_msg void OnABRepeat(UINT nID); + afx_msg void OnUpdateABRepeat(CCmdUI* pCmdUI); + afx_msg void OnPlayRepeatForever(); + afx_msg void OnUpdatePlayRepeatForever(CCmdUI* pCmdUI); + + afx_msg void OnNavigateSkip(UINT nID); + afx_msg void OnUpdateNavigateSkip(CCmdUI* pCmdUI); + afx_msg void OnNavigateSkipFile(UINT nID); + afx_msg void OnUpdateNavigateSkipFile(CCmdUI* pCmdUI); + afx_msg void OnNavigateGoto(); + afx_msg void OnUpdateNavigateGoto(CCmdUI* pCmdUI); + afx_msg void OnNavigateMenu(UINT nID); + afx_msg void OnUpdateNavigateMenu(CCmdUI* pCmdUI); + afx_msg void OnNavigateJumpTo(UINT nID); + afx_msg void OnNavigateMenuItem(UINT nID); + afx_msg void OnUpdateNavigateMenuItem(CCmdUI* pCmdUI); + afx_msg void OnTunerScan(); + afx_msg void OnUpdateTunerScan(CCmdUI* pCmdUI); + + afx_msg void OnFavoritesAdd(); + afx_msg void OnUpdateFavoritesAdd(CCmdUI* pCmdUI); + afx_msg void OnFavoritesQuickAddFavorite(); + afx_msg void OnFavoritesOrganize(); + afx_msg void OnUpdateFavoritesOrganize(CCmdUI* pCmdUI); + afx_msg void OnFavoritesFile(UINT nID); + afx_msg void OnUpdateFavoritesFile(CCmdUI* pCmdUI); + afx_msg void OnFavoritesDVD(UINT nID); + afx_msg void OnUpdateFavoritesDVD(CCmdUI* pCmdUI); + afx_msg void OnFavoritesDevice(UINT nID); + afx_msg void OnUpdateFavoritesDevice(CCmdUI* pCmdUI); + afx_msg void OnRecentFileClear(); + afx_msg void OnUpdateRecentFileClear(CCmdUI* pCmdUI); + afx_msg void OnRecentFile(UINT nID); + afx_msg void OnUpdateRecentFile(CCmdUI* pCmdUI); + + afx_msg void OnHelpHomepage(); + afx_msg void OnHelpCheckForUpdate(); + afx_msg void OnHelpToolbarImages(); + afx_msg void OnHelpDonate(); + + afx_msg void OnClose(); + + bool FilterSettingsByClassID(CLSID clsid, CWnd* parent); + void FilterSettings(CComPtr pUnk, CWnd* parent); + + LRESULT OnMPCVRSwitchFullscreen(WPARAM wParam, LPARAM lParam); + + CMPC_Lcd m_Lcd; + + CMouseWndWithArtView* m_pVideoWnd; // Current Video (main display screen or 2nd) + CWnd* m_pOSDWnd; + CPreView m_wndPreView; // SeekPreview + + + void ReleasePreviewGraph(); + HRESULT PreviewWindowHide(); + HRESULT PreviewWindowShow(REFERENCE_TIME rtCur2); + HRESULT HandleMultipleEntryRar(CStringW fn); + bool CanPreviewUse(); + + CFullscreenWnd* m_pDedicatedFSVideoWnd; + COSD m_OSD; + int m_nCurSubtitle; + long m_lSubtitleShift; + REFERENCE_TIME m_rtCurSubPos; + bool m_bScanDlgOpened; + bool m_bStopTunerScan; + bool m_bLockedZoomVideoWindow; + int m_nLockedZoomVideoWindow; + + void SetLoadState(MLS eState); + MLS GetLoadState() const; + void SetPlayState(MPC_PLAYSTATE iState); + bool CreateFullScreenWindow(bool isD3D=true); + 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, bool relative = false); + //void AutoSelectTracks(); + void SetTimersPlay(); + void KillTimerDelayedSeek(); + void KillTimersStop(); + void AdjustStreamPosPoller(bool restart); + void ResetSubtitlePosAndSize(bool repaint = false); + + // MPC API functions + void ProcessAPICommand(COPYDATASTRUCT* pCDS); + void SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...); + void SendNowPlayingToApi(bool sendtrackinfo = true); + void SendSubtitleTracksToApi(); + void SendAudioTracksToApi(); + void SendPlaylistToApi(); + afx_msg void OnFileOpendirectory(); + + void SendCurrentPositionToApi(bool fNotifySeek = false); + void ShowOSDCustomMessageApi(const MPC_OSDDATA* osdData); + void JumpOfNSeconds(int seconds); + + CString GetVidPos() const; + + CComPtr m_pTaskbarList; + HRESULT CreateThumbnailToolbar(); + HRESULT UpdateThumbarButton(); + HRESULT UpdateThumbarButton(MPC_PLAYSTATE iPlayState); + HRESULT UpdateThumbnailClip(); + BOOL Create(LPCTSTR lpszClassName, + LPCTSTR lpszWindowName, + DWORD dwStyle = WS_OVERLAPPEDWINDOW, + const RECT& rect = rectDefault, + CWnd* pParentWnd = NULL, // != NULL for popups + LPCTSTR lpszMenuName = NULL, + DWORD dwExStyle = 0, + CCreateContext* pContext = NULL); + CMPCThemeMenu* defaultMPCThemeMenu = nullptr; + + bool isSafeZone(CPoint pt); + +protected: + afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); + // GDI+ + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + void WTSRegisterSessionNotification(); + void WTSUnRegisterSessionNotification(); + + CMenu* m_pActiveContextMenu; + CMenu* m_pActiveSystemMenu; + + void UpdateSkypeHandler(); + void UpdateSeekbarChapterBag(); + void UpdateAudioSwitcher(); + + void LoadArtToViews(const CString& imagePath); + void LoadArtToViews(std::vector buffer); + void ClearArtFromViews(); + + void UpdateUILanguage(); + + bool PerformFlipRotate(); + + bool m_bAltDownClean; + bool m_bShowingFloatingMenubar; + virtual void OnShowMenuBar() override { + m_bShowingFloatingMenubar = (GetMenuBarVisibility() != AFX_MBV_KEEPVISIBLE); + }; + virtual void OnHideMenuBar() override { + m_bShowingFloatingMenubar = false; + }; + virtual void SetMenuBarVisibility(DWORD dwStyle) override { + __super::SetMenuBarVisibility(dwStyle); + if (dwStyle & AFX_MBV_KEEPVISIBLE) { + m_bShowingFloatingMenubar = false; + } + }; + + bool IsAeroSnapped(); + + CPoint m_snapStartPoint; + CRect m_snapStartRect; + + bool m_bAllowWindowZoom; + double m_dLastVideoScaleFactor; + CSize m_lastVideoSize; + + bool m_bExtOnTop; // 'true' if the "on top" flag was set by an external tool + + CString m_sydlLastProcessURL; + + bool IsImageFile(CStringW fn); + bool IsPlayableFormatExt(CStringW ext); + bool IsAudioFileExt(CStringW ext); + bool IsImageFileExt(CStringW ext); + bool IsPlaylistFile(CStringW fn); + bool IsPlaylistFileExt(CStringW ext); + bool IsAudioOrVideoFileExt(CStringW ext); + bool CanSkipToExt(CStringW ext, CStringW curExt); + bool IsAudioFilename(CString filename); + + + // Handles MF_DEFAULT and escapes '&' + static BOOL AppendMenuEx(CMenu& menu, UINT nFlags, UINT nIDNewItem, CString& text); + + void SubtitlesSave(const TCHAR* directory = nullptr, bool silent = false); + + void OnSizingFixWndToVideo(UINT nSide, LPRECT lpRect, bool bCtrl = false); + void OnSizingSnapToScreen(UINT nSide, LPRECT lpRect, bool bCtrl = false); + +public: + afx_msg UINT OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData); + afx_msg void OnSessionChange(UINT nSessionState, UINT nId); + + enum UpdateControlTarget { + UPDATE_VOLUME_STEP, + UPDATE_LOGO, + UPDATE_SKYPE, + UPDATE_SEEKBAR_CHAPTERS, + UPDATE_WINDOW_TITLE, + UPDATE_AUDIO_SWITCHER, + UPDATE_CONTROLS_VISIBILITY, + UPDATE_CHILDVIEW_CURSOR_HACK, + }; + + void UpdateControlState(UpdateControlTarget target); + + void ReloadMenus(); + + // TODO: refactor it outside of MainFrm + GUID GetTimeFormat(); + + CHdmvClipInfo::HdmvPlaylist m_MPLSPlaylist; + bool m_bIsBDPlay; + bool OpenBD(CString Path); + bool m_bHasBDMeta; + CAtlList m_BDMeta; + CHdmvClipInfo::BDMVMeta GetBDMVMeta(); + + bool GetDecoderType(CString& type) const; + + static bool IsOnYDLWhitelist(const CString url); + + bool CanSendToYoutubeDL(const CString url); + bool ProcessYoutubeDLURL(CString url, bool append, bool replace = false); + bool DownloadWithYoutubeDL(CString url, CString filename); + + /** + * @brief Get title of file + * @param fTitleBarTextTitle + * @return + */ + CString getBestTitle(bool fTitleBarTextTitle = true); + MediaTransControls m_media_trans_control; + + void MediaTransportControlSetMedia(); + void MediaTransportControlUpdateState(OAFilterState state); + + enum themableDialogTypes { + None, + windowsFileDialog, + toolbarCustomizeDialog + }; + void enableFileDialogHook(CMPCThemeUtil* helper); + void enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type); +private: + themableDialogTypes watchingDialog, foundDialog; + CMPCThemeUtil* dialogHookHelper; + +public: + afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); + afx_msg void OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt); +private: + void SetupExternalChapters(); + void ApplyPanNScanPresetString(); + void ValidatePanNScanParameters(); +}; diff --git a/src/mpc-hc/MediaFormats.cpp b/src/mpc-hc/MediaFormats.cpp index d6b87ba7e94..3e2ca5c81a4 100644 --- a/src/mpc-hc/MediaFormats.cpp +++ b/src/mpc-hc/MediaFormats.cpp @@ -1,343 +1,343 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "MediaFormats.h" -#include "resource.h" - -// -// CMediaFormatCategory -// - -CMediaFormatCategory::CMediaFormatCategory() - : m_fAudioOnly(false) - , m_fAssociable(true) -{ -} - -CMediaFormatCategory::CMediaFormatCategory(CString label, CString description, CAtlList& exts, bool fAudioOnly, bool fAssociable) -{ - m_label = label; - m_description = description; - m_exts.AddTailList(&exts); - m_backupexts.AddTailList(&m_exts); - m_fAudioOnly = fAudioOnly; - m_fAssociable = fAssociable; -} - -CMediaFormatCategory::CMediaFormatCategory(CString label, CString description, CString exts, bool fAudioOnly, bool fAssociable) -{ - m_label = label; - m_description = description; - ExplodeMin(exts, m_exts, ' '); - POSITION pos = m_exts.GetHeadPosition(); - while (pos) { - m_exts.GetNext(pos).TrimLeft(_T('.')); - } - - m_backupexts.AddTailList(&m_exts); - m_fAudioOnly = fAudioOnly; - m_fAssociable = fAssociable; -} - -CMediaFormatCategory::~CMediaFormatCategory() -{ -} - -void CMediaFormatCategory::UpdateData(bool fSave) -{ - if (fSave) { - AfxGetApp()->WriteProfileString(_T("FileFormats2"), m_label, GetExts()); - } else { - SetExts(AfxGetApp()->GetProfileString(_T("FileFormats2"), m_label, GetExts())); - } -} - -CMediaFormatCategory::CMediaFormatCategory(const CMediaFormatCategory& mfc) -{ - *this = mfc; -} - -CMediaFormatCategory& CMediaFormatCategory::operator = (const CMediaFormatCategory& mfc) -{ - if (this != &mfc) { - m_label = mfc.m_label; - m_description = mfc.m_description; - m_exts.RemoveAll(); - m_exts.AddTailList(&mfc.m_exts); - m_backupexts.RemoveAll(); - m_backupexts.AddTailList(&mfc.m_backupexts); - m_fAudioOnly = mfc.m_fAudioOnly; - m_fAssociable = mfc.m_fAssociable; - } - return *this; -} - -void CMediaFormatCategory::RestoreDefaultExts() -{ - m_exts.RemoveAll(); - m_exts.AddTailList(&m_backupexts); -} - -void CMediaFormatCategory::SetExts(CAtlList& exts) -{ - m_exts.RemoveAll(); - m_exts.AddTailList(&exts); -} - -void CMediaFormatCategory::SetExts(CString exts) -{ - exts.Remove(_T('.')); - m_exts.RemoveAll(); - ExplodeMin(exts, m_exts, ' '); -} - -CString CMediaFormatCategory::GetFilter() const -{ - CString filter; - POSITION pos = m_exts.GetHeadPosition(); - while (pos) { - filter += _T("*.") + m_exts.GetNext(pos) + _T(";"); - } - filter.TrimRight(_T(';')); - return filter; -} - -CString CMediaFormatCategory::GetExts() const -{ - return Implode(m_exts, ' '); -} - -CString CMediaFormatCategory::GetExtsWithPeriod() const -{ - CString exts; - POSITION pos = m_exts.GetHeadPosition(); - while (pos) { - exts += _T(".") + m_exts.GetNext(pos) + _T(" "); - } - exts.TrimRight(_T(' ')); - return exts; -} - -CString CMediaFormatCategory::GetBackupExtsWithPeriod() const -{ - CString exts; - POSITION pos = m_backupexts.GetHeadPosition(); - while (pos) { - exts += _T(".") + m_backupexts.GetNext(pos) + _T(" "); - } - exts.TrimRight(_T(' ')); - return exts; -} - -// -// CMediaFormats -// - -CMediaFormats::CMediaFormats() -{ -} - -CMediaFormats::~CMediaFormats() -{ -} - -void CMediaFormats::UpdateData(bool fSave) -{ - if (fSave) { - AfxGetApp()->WriteProfileString(_T("FileFormats2"), nullptr, nullptr); - } else { - RemoveAll(); - -#define ADDFMT(f) Add(CMediaFormatCategory##f) - - ADDFMT((_T("avi"), StrRes(IDS_MFMT_AVI), _T("avi"))); - ADDFMT((_T("mpeg"), StrRes(IDS_MFMT_MPEG), _T("mpg mpeg mpe m1v m2v mpv2 mp2v pva evo m2p"))); - ADDFMT((_T("mpegts"), StrRes(IDS_MFMT_MPEGTS), _T("ts tp trp m2t m2ts mts rec ssif"))); - ADDFMT((_T("dvdvideo"), StrRes(IDS_MFMT_DVDVIDEO), _T("vob ifo"))); - ADDFMT((_T("mkv"), StrRes(IDS_MFMT_MKV), _T("mkv mk3d"))); - ADDFMT((_T("webm"), StrRes(IDS_MFMT_WEBM), _T("webm"))); - ADDFMT((_T("mp4"), StrRes(IDS_MFMT_MP4), _T("mp4 m4v mp4v mpv4 hdmov"))); - ADDFMT((_T("mov"), StrRes(IDS_MFMT_MOV), _T("mov"))); - ADDFMT((_T("3gp"), StrRes(IDS_MFMT_3GP), _T("3gp 3gpp 3g2 3gp2"))); - ADDFMT((_T("flv"), StrRes(IDS_MFMT_FLV), _T("flv f4v"))); - ADDFMT((_T("ogm"), StrRes(IDS_MFMT_OGM), _T("ogm ogv"))); - ADDFMT((_T("rm"), StrRes(IDS_MFMT_RM), _T("rm rmvb"))); - ADDFMT((_T("rt"), StrRes(IDS_MFMT_RT), _T("rt ram rpm rmm rp smi smil"))); - ADDFMT((_T("wmv"), StrRes(IDS_MFMT_WMV), _T("wmv wmp wm asf"))); - ADDFMT((_T("bink"), StrRes(IDS_MFMT_BINK), _T("smk bik"))); - ADDFMT((_T("flic"), StrRes(IDS_MFMT_FLIC), _T("fli flc flic"))); - ADDFMT((_T("dsm"), StrRes(IDS_MFMT_DSM), _T("dsm dsv dsa dss"))); - ADDFMT((_T("ivf"), StrRes(IDS_MFMT_IVF), _T("ivf"))); - ADDFMT((_T("other"), StrRes(IDS_MFMT_OTHER), _T("divx amv mxf dv dav"))); - ADDFMT((_T("bdpls"), StrRes(IDS_MFMT_BDPLS), _T("mpls bdmv"))); - ADDFMT((_T("3ga"), StrRes(IDS_MFMT_3GA), _T("3ga"), true)); - ADDFMT((_T("ac3"), StrRes(IDS_MFMT_AC3), _T("ac3"), true)); - ADDFMT((_T("dts"), StrRes(IDS_MFMT_DTS), _T("dts dtshd dtsma"), true)); - ADDFMT((_T("aiff"), StrRes(IDS_MFMT_AIFF), _T("aif aifc aiff"), true)); - ADDFMT((_T("alac"), StrRes(IDS_MFMT_ALAC), _T("alac"), true)); - ADDFMT((_T("amr"), StrRes(IDS_MFMT_AMR), _T("amr"), true)); - ADDFMT((_T("ape"), StrRes(IDS_MFMT_APE), _T("ape apl"), true)); - ADDFMT((_T("au"), StrRes(IDS_MFMT_AU), _T("au snd"), true)); - ADDFMT((_T("audiocd"), StrRes(IDS_MFMT_CDA), _T("cda"), true)); - ADDFMT((_T("flac"), StrRes(IDS_MFMT_FLAC), _T("flac"), true)); - ADDFMT((_T("m4a"), StrRes(IDS_MFMT_M4A), _T("m4a m4b m4r aac"), true)); - ADDFMT((_T("midi"), StrRes(IDS_MFMT_MIDI), _T("mid midi rmi"), true)); - ADDFMT((_T("mka"), StrRes(IDS_MFMT_MKA), _T("mka"), true)); - ADDFMT((_T("mp3"), StrRes(IDS_MFMT_MP3), _T("mp3"), true)); - ADDFMT((_T("mpa"), StrRes(IDS_MFMT_MPA), _T("mpa mp2 m1a m2a"), true)); - ADDFMT((_T("mpc"), StrRes(IDS_MFMT_MPC), _T("mpc"), true)); - ADDFMT((_T("ofr"), StrRes(IDS_MFMT_OFR), _T("ofr ofs"), true)); - ADDFMT((_T("ogg"), StrRes(IDS_MFMT_OGG), _T("ogg oga"), true)); - ADDFMT((_T("opus"), StrRes(IDS_MFMT_OPUS), _T("opus"), true)); - ADDFMT((_T("ra"), StrRes(IDS_MFMT_RA), _T("ra"), true)); - ADDFMT((_T("tak"), StrRes(IDS_MFMT_TAK), _T("tak"), true)); - ADDFMT((_T("tta"), StrRes(IDS_MFMT_TTA), _T("tta"), true)); - ADDFMT((_T("wav"), StrRes(IDS_MFMT_WAV), _T("wav"), true)); - ADDFMT((_T("wma"), StrRes(IDS_MFMT_WMA), _T("wma"), true)); - ADDFMT((_T("wavpack"), StrRes(IDS_MFMT_WV), _T("wv"), true)); - ADDFMT((_T("weba"), _T("WebA"), _T("weba"), true)); - ADDFMT((_T("other_audio"), StrRes(IDS_MFMT_OTHER_AUDIO), _T("aob mlp thd mpl spx caf dsf eac3"), true)); - ADDFMT((_T("pls"), StrRes(IDS_MFMT_PLS), _T("asx m3u m3u8 pls wvx wax wmx mpcpl"))); - ADDFMT((_T("cue"), _T("Cue sheet"), _T("cue"))); - ADDFMT((_T("swf"), StrRes(IDS_MFMT_SWF), _T("swf"))); - ADDFMT((_T("rar"), StrRes(IDS_MFMT_RAR), _T("rar"), false, false)); - ADDFMT((_T("avs"), StrRes(IDS_MFMT_AVS), _T("avs"), false, false)); -#undef ADDFMT - } - - for (size_t i = 0; i < GetCount(); i++) { - GetAt(i).UpdateData(fSave); - } -} - -bool CMediaFormats::IsUsingEngine(CString path, engine_t e) const -{ - return (GetEngine(path) == e); -} - -engine_t CMediaFormats::GetEngine(CString path) const -{ - CString ext = CPath(path.Trim()).GetExtension().MakeLower(); - if (ext == _T(".swf")) { - return ShockWave; - } - return DirectShow; -} - -bool CMediaFormats::FindExt(CString ext, bool fAudioOnly, bool fAssociableOnly) const -{ - return (FindMediaByExt(ext, fAudioOnly, fAssociableOnly) != nullptr); -} - -const CMediaFormatCategory* CMediaFormats::FindMediaByExt(CString ext, bool fAudioOnly, bool fAssociableOnly) const -{ - ext.TrimLeft(_T('.')); - - if (!ext.IsEmpty()) { - for (size_t i = 0; i < GetCount(); i++) { - const CMediaFormatCategory& mfc = GetAt(i); - if ((!fAudioOnly || mfc.IsAudioOnly()) && (!fAssociableOnly || mfc.IsAssociable()) && mfc.FindExt(ext)) { - return &mfc; - } - } - } - - return nullptr; -} - -void CMediaFormats::GetFilter(CString& filter, CAtlArray& mask) const -{ - CString strTemp; - - filter.AppendFormat(IsExtHidden() ? _T("%s|") : _T("%s (*.avi;*.mp4;*.mkv;...)|"), ResStr(IDS_AG_MEDIAFILES).GetString()); - mask.Add(_T("")); - - for (size_t i = 0; i < GetCount(); i++) { - strTemp = GetAt(i).GetFilter() + _T(";"); - mask[0] += strTemp; - filter += strTemp; - } - mask[0].TrimRight(_T(';')); - filter.TrimRight(_T(';')); - filter += _T("|"); - - for (size_t i = 0; i < GetCount(); i++) { - const CMediaFormatCategory& mfc = GetAt(i); - filter += mfc.GetDescription() + _T("|" + GetAt(i).GetFilter() + _T("|")); - mask.Add(mfc.GetFilter()); - } - - filter.AppendFormat(IDS_AG_ALLFILES); - mask.Add(_T("*.*")); - - filter += _T("|"); -} - -void CMediaFormats::GetAudioFilter(CString& filter, CAtlArray& mask) const -{ - CString strTemp; - - filter.AppendFormat(IsExtHidden() ? _T("%s|") : _T("%s (*.mp3;*.aac;*.wav;...)|"), ResStr(IDS_AG_AUDIOFILES).GetString()); - mask.Add(_T("")); - - for (size_t i = 0; i < GetCount(); i++) { - const CMediaFormatCategory& mfc = GetAt(i); - if (!mfc.IsAudioOnly()) { - continue; - } - strTemp = GetAt(i).GetFilter() + _T(";"); - mask[0] += strTemp; - filter += strTemp; - } - - mask[0].TrimRight(_T(';')); - filter.TrimRight(_T(';')); - filter += _T("|"); - - for (size_t i = 0; i < GetCount(); i++) { - const CMediaFormatCategory& mfc = GetAt(i); - if (!mfc.IsAudioOnly()) { - continue; - } - filter += mfc.GetDescription() + _T("|") + GetAt(i).GetFilter() + _T("|"); - mask.Add(mfc.GetFilter()); - } - - filter.AppendFormat(IDS_AG_ALLFILES); - mask.Add(_T("*.*")); - - filter += _T("|"); -} - -bool CMediaFormats::IsExtHidden() -{ - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), KEY_READ)) { - DWORD value; - if (ERROR_SUCCESS == key.QueryDWORDValue(_T("HideFileExt"), value)) { - return !!value; - } - } - return false; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "MediaFormats.h" +#include "resource.h" + +// +// CMediaFormatCategory +// + +CMediaFormatCategory::CMediaFormatCategory() + : m_fAudioOnly(false) + , m_fAssociable(true) +{ +} + +CMediaFormatCategory::CMediaFormatCategory(CString label, CString description, CAtlList& exts, bool fAudioOnly, bool fAssociable) +{ + m_label = label; + m_description = description; + m_exts.AddTailList(&exts); + m_backupexts.AddTailList(&m_exts); + m_fAudioOnly = fAudioOnly; + m_fAssociable = fAssociable; +} + +CMediaFormatCategory::CMediaFormatCategory(CString label, CString description, CString exts, bool fAudioOnly, bool fAssociable) +{ + m_label = label; + m_description = description; + ExplodeMin(exts, m_exts, ' '); + POSITION pos = m_exts.GetHeadPosition(); + while (pos) { + m_exts.GetNext(pos).TrimLeft(_T('.')); + } + + m_backupexts.AddTailList(&m_exts); + m_fAudioOnly = fAudioOnly; + m_fAssociable = fAssociable; +} + +CMediaFormatCategory::~CMediaFormatCategory() +{ +} + +void CMediaFormatCategory::UpdateData(bool fSave) +{ + if (fSave) { + AfxGetApp()->WriteProfileString(_T("FileFormats2"), m_label, GetExts()); + } else { + SetExts(AfxGetApp()->GetProfileString(_T("FileFormats2"), m_label, GetExts())); + } +} + +CMediaFormatCategory::CMediaFormatCategory(const CMediaFormatCategory& mfc) +{ + *this = mfc; +} + +CMediaFormatCategory& CMediaFormatCategory::operator = (const CMediaFormatCategory& mfc) +{ + if (this != &mfc) { + m_label = mfc.m_label; + m_description = mfc.m_description; + m_exts.RemoveAll(); + m_exts.AddTailList(&mfc.m_exts); + m_backupexts.RemoveAll(); + m_backupexts.AddTailList(&mfc.m_backupexts); + m_fAudioOnly = mfc.m_fAudioOnly; + m_fAssociable = mfc.m_fAssociable; + } + return *this; +} + +void CMediaFormatCategory::RestoreDefaultExts() +{ + m_exts.RemoveAll(); + m_exts.AddTailList(&m_backupexts); +} + +void CMediaFormatCategory::SetExts(CAtlList& exts) +{ + m_exts.RemoveAll(); + m_exts.AddTailList(&exts); +} + +void CMediaFormatCategory::SetExts(CString exts) +{ + exts.Remove(_T('.')); + m_exts.RemoveAll(); + ExplodeMin(exts, m_exts, ' '); +} + +CString CMediaFormatCategory::GetFilter() const +{ + CString filter; + POSITION pos = m_exts.GetHeadPosition(); + while (pos) { + filter += _T("*.") + m_exts.GetNext(pos) + _T(";"); + } + filter.TrimRight(_T(';')); + return filter; +} + +CString CMediaFormatCategory::GetExts() const +{ + return Implode(m_exts, ' '); +} + +CString CMediaFormatCategory::GetExtsWithPeriod() const +{ + CString exts; + POSITION pos = m_exts.GetHeadPosition(); + while (pos) { + exts += _T(".") + m_exts.GetNext(pos) + _T(" "); + } + exts.TrimRight(_T(' ')); + return exts; +} + +CString CMediaFormatCategory::GetBackupExtsWithPeriod() const +{ + CString exts; + POSITION pos = m_backupexts.GetHeadPosition(); + while (pos) { + exts += _T(".") + m_backupexts.GetNext(pos) + _T(" "); + } + exts.TrimRight(_T(' ')); + return exts; +} + +// +// CMediaFormats +// + +CMediaFormats::CMediaFormats() +{ +} + +CMediaFormats::~CMediaFormats() +{ +} + +void CMediaFormats::UpdateData(bool fSave) +{ + if (fSave) { + AfxGetApp()->WriteProfileString(_T("FileFormats2"), nullptr, nullptr); + } else { + RemoveAll(); + +#define ADDFMT(f) Add(CMediaFormatCategory##f) + + ADDFMT((_T("avi"), StrRes(IDS_MFMT_AVI), _T("avi"))); + ADDFMT((_T("mpeg"), StrRes(IDS_MFMT_MPEG), _T("mpg mpeg mpe m1v m2v mpv2 mp2v pva evo m2p"))); + ADDFMT((_T("mpegts"), StrRes(IDS_MFMT_MPEGTS), _T("ts tp trp m2t m2ts mts rec ssif"))); + ADDFMT((_T("dvdvideo"), StrRes(IDS_MFMT_DVDVIDEO), _T("vob ifo"))); + ADDFMT((_T("mkv"), StrRes(IDS_MFMT_MKV), _T("mkv mk3d"))); + ADDFMT((_T("webm"), StrRes(IDS_MFMT_WEBM), _T("webm"))); + ADDFMT((_T("mp4"), StrRes(IDS_MFMT_MP4), _T("mp4 m4v mp4v mpv4 hdmov"))); + ADDFMT((_T("mov"), StrRes(IDS_MFMT_MOV), _T("mov"))); + ADDFMT((_T("3gp"), StrRes(IDS_MFMT_3GP), _T("3gp 3gpp 3g2 3gp2"))); + ADDFMT((_T("flv"), StrRes(IDS_MFMT_FLV), _T("flv f4v"))); + ADDFMT((_T("ogm"), StrRes(IDS_MFMT_OGM), _T("ogm ogv"))); + ADDFMT((_T("rm"), StrRes(IDS_MFMT_RM), _T("rm rmvb"))); + ADDFMT((_T("rt"), StrRes(IDS_MFMT_RT), _T("rt ram rpm rmm rp smi smil"))); + ADDFMT((_T("wmv"), StrRes(IDS_MFMT_WMV), _T("wmv wmp wm asf"))); + ADDFMT((_T("bink"), StrRes(IDS_MFMT_BINK), _T("smk bik"))); + ADDFMT((_T("flic"), StrRes(IDS_MFMT_FLIC), _T("fli flc flic"))); + ADDFMT((_T("dsm"), StrRes(IDS_MFMT_DSM), _T("dsm dsv dsa dss"))); + ADDFMT((_T("ivf"), StrRes(IDS_MFMT_IVF), _T("ivf"))); + ADDFMT((_T("other"), StrRes(IDS_MFMT_OTHER), _T("divx amv mxf dv dav"))); + ADDFMT((_T("bdpls"), StrRes(IDS_MFMT_BDPLS), _T("mpls bdmv"))); + ADDFMT((_T("3ga"), StrRes(IDS_MFMT_3GA), _T("3ga"), true)); + ADDFMT((_T("ac3"), StrRes(IDS_MFMT_AC3), _T("ac3"), true)); + ADDFMT((_T("dts"), StrRes(IDS_MFMT_DTS), _T("dts dtshd dtsma"), true)); + ADDFMT((_T("aiff"), StrRes(IDS_MFMT_AIFF), _T("aif aifc aiff"), true)); + ADDFMT((_T("alac"), StrRes(IDS_MFMT_ALAC), _T("alac"), true)); + ADDFMT((_T("amr"), StrRes(IDS_MFMT_AMR), _T("amr"), true)); + ADDFMT((_T("ape"), StrRes(IDS_MFMT_APE), _T("ape apl"), true)); + ADDFMT((_T("au"), StrRes(IDS_MFMT_AU), _T("au snd"), true)); + ADDFMT((_T("audiocd"), StrRes(IDS_MFMT_CDA), _T("cda"), true)); + ADDFMT((_T("flac"), StrRes(IDS_MFMT_FLAC), _T("flac"), true)); + ADDFMT((_T("m4a"), StrRes(IDS_MFMT_M4A), _T("m4a m4b m4r aac"), true)); + ADDFMT((_T("midi"), StrRes(IDS_MFMT_MIDI), _T("mid midi rmi"), true)); + ADDFMT((_T("mka"), StrRes(IDS_MFMT_MKA), _T("mka"), true)); + ADDFMT((_T("mp3"), StrRes(IDS_MFMT_MP3), _T("mp3"), true)); + ADDFMT((_T("mpa"), StrRes(IDS_MFMT_MPA), _T("mpa mp2 m1a m2a"), true)); + ADDFMT((_T("mpc"), StrRes(IDS_MFMT_MPC), _T("mpc"), true)); + ADDFMT((_T("ofr"), StrRes(IDS_MFMT_OFR), _T("ofr ofs"), true)); + ADDFMT((_T("ogg"), StrRes(IDS_MFMT_OGG), _T("ogg oga"), true)); + ADDFMT((_T("opus"), StrRes(IDS_MFMT_OPUS), _T("opus"), true)); + ADDFMT((_T("ra"), StrRes(IDS_MFMT_RA), _T("ra"), true)); + ADDFMT((_T("tak"), StrRes(IDS_MFMT_TAK), _T("tak"), true)); + ADDFMT((_T("tta"), StrRes(IDS_MFMT_TTA), _T("tta"), true)); + ADDFMT((_T("wav"), StrRes(IDS_MFMT_WAV), _T("wav"), true)); + ADDFMT((_T("wma"), StrRes(IDS_MFMT_WMA), _T("wma"), true)); + ADDFMT((_T("wavpack"), StrRes(IDS_MFMT_WV), _T("wv"), true)); + ADDFMT((_T("weba"), _T("WebA"), _T("weba"), true)); + ADDFMT((_T("other_audio"), StrRes(IDS_MFMT_OTHER_AUDIO), _T("aob mlp thd mpl spx caf dsf eac3"), true)); + ADDFMT((_T("pls"), StrRes(IDS_MFMT_PLS), _T("asx m3u m3u8 pls wvx wax wmx mpcpl"))); + ADDFMT((_T("cue"), _T("Cue sheet"), _T("cue"))); + ADDFMT((_T("swf"), StrRes(IDS_MFMT_SWF), _T("swf"))); + ADDFMT((_T("rar"), StrRes(IDS_MFMT_RAR), _T("rar"), false, false)); + ADDFMT((_T("avs"), StrRes(IDS_MFMT_AVS), _T("avs"), false, false)); +#undef ADDFMT + } + + for (size_t i = 0; i < GetCount(); i++) { + GetAt(i).UpdateData(fSave); + } +} + +bool CMediaFormats::IsUsingEngine(CString path, engine_t e) const +{ + return (GetEngine(path) == e); +} + +engine_t CMediaFormats::GetEngine(CString path) const +{ + CString ext = CPath(path.Trim()).GetExtension().MakeLower(); + if (ext == _T(".swf")) { + return ShockWave; + } + return DirectShow; +} + +bool CMediaFormats::FindExt(CString ext, bool fAudioOnly, bool fAssociableOnly) const +{ + return (FindMediaByExt(ext, fAudioOnly, fAssociableOnly) != nullptr); +} + +const CMediaFormatCategory* CMediaFormats::FindMediaByExt(CString ext, bool fAudioOnly, bool fAssociableOnly) const +{ + ext.TrimLeft(_T('.')); + + if (!ext.IsEmpty()) { + for (size_t i = 0; i < GetCount(); i++) { + const CMediaFormatCategory& mfc = GetAt(i); + if ((!fAudioOnly || mfc.IsAudioOnly()) && (!fAssociableOnly || mfc.IsAssociable()) && mfc.FindExt(ext)) { + return &mfc; + } + } + } + + return nullptr; +} + +void CMediaFormats::GetFilter(CString& filter, CAtlArray& mask) const +{ + CString strTemp; + + filter.AppendFormat(IsExtHidden() ? _T("%s|") : _T("%s (*.avi;*.mp4;*.mkv;...)|"), ResStr(IDS_AG_MEDIAFILES).GetString()); + mask.Add(_T("")); + + for (size_t i = 0; i < GetCount(); i++) { + strTemp = GetAt(i).GetFilter() + _T(";"); + mask[0] += strTemp; + filter += strTemp; + } + mask[0].TrimRight(_T(';')); + filter.TrimRight(_T(';')); + filter += _T("|"); + + for (size_t i = 0; i < GetCount(); i++) { + const CMediaFormatCategory& mfc = GetAt(i); + filter += mfc.GetDescription() + _T("|" + GetAt(i).GetFilter() + _T("|")); + mask.Add(mfc.GetFilter()); + } + + filter.AppendFormat(IDS_AG_ALLFILES); + mask.Add(_T("*.*")); + + filter += _T("|"); +} + +void CMediaFormats::GetAudioFilter(CString& filter, CAtlArray& mask) const +{ + CString strTemp; + + filter.AppendFormat(IsExtHidden() ? _T("%s|") : _T("%s (*.mp3;*.aac;*.wav;...)|"), ResStr(IDS_AG_AUDIOFILES).GetString()); + mask.Add(_T("")); + + for (size_t i = 0; i < GetCount(); i++) { + const CMediaFormatCategory& mfc = GetAt(i); + if (!mfc.IsAudioOnly()) { + continue; + } + strTemp = GetAt(i).GetFilter() + _T(";"); + mask[0] += strTemp; + filter += strTemp; + } + + mask[0].TrimRight(_T(';')); + filter.TrimRight(_T(';')); + filter += _T("|"); + + for (size_t i = 0; i < GetCount(); i++) { + const CMediaFormatCategory& mfc = GetAt(i); + if (!mfc.IsAudioOnly()) { + continue; + } + filter += mfc.GetDescription() + _T("|") + GetAt(i).GetFilter() + _T("|"); + mask.Add(mfc.GetFilter()); + } + + filter.AppendFormat(IDS_AG_ALLFILES); + mask.Add(_T("*.*")); + + filter += _T("|"); +} + +bool CMediaFormats::IsExtHidden() +{ + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), KEY_READ)) { + DWORD value; + if (ERROR_SUCCESS == key.QueryDWORDValue(_T("HideFileExt"), value)) { + return !!value; + } + } + return false; +} diff --git a/src/mpc-hc/MediaFormats.h b/src/mpc-hc/MediaFormats.h index 83629319f3f..3087987e1e4 100644 --- a/src/mpc-hc/MediaFormats.h +++ b/src/mpc-hc/MediaFormats.h @@ -1,91 +1,91 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "BaseGraph.h" - - -class CMediaFormatCategory -{ -protected: - CString m_label, m_description; - CAtlList m_exts, m_backupexts; - bool m_fAudioOnly; - bool m_fAssociable; - -public: - CMediaFormatCategory(); - CMediaFormatCategory(CString label, CString description, CAtlList& exts, bool fAudioOnly = false, bool fAssociable = true); - CMediaFormatCategory(CString label, CString description, CString exts, bool fAudioOnly = false, bool fAssociable = true); - virtual ~CMediaFormatCategory(); - - void UpdateData(bool fSave); - - CMediaFormatCategory(const CMediaFormatCategory& mfc); - CMediaFormatCategory& operator = (const CMediaFormatCategory& mfc); - - void RestoreDefaultExts(); - void SetExts(CAtlList& exts); - void SetExts(CString exts); - - bool FindExt(CString ext) const { - return m_exts.Find(ext.TrimLeft(_T('.')).MakeLower()) != nullptr; - } - - CString GetLabel() const { return m_label; } - - CString GetDescription() const { return m_description; } - CString GetFilter() const; - CString GetExts() const; - CString GetExtsWithPeriod() const; - CString GetBackupExtsWithPeriod() const; - bool IsAudioOnly() const { return m_fAudioOnly; } - bool IsAssociable() const { return m_fAssociable; } - bool IsVideoOnly() const { return !m_fAudioOnly && m_label != _T("pls") && m_label != _T("cue") && m_label != _T("swf"); } -}; - -class CMediaFormats : public CAtlArray -{ -public: - CMediaFormats(); - virtual ~CMediaFormats(); - - //CMediaFormats(const CMediaFormats& mf) { *this = mf; } - CMediaFormats& operator=(const CMediaFormats& mf) { - Copy(mf); - return *this; - } - - void UpdateData(bool fSave); - - bool IsUsingEngine(CString path, engine_t e) const; - engine_t GetEngine(CString path) const; - - bool FindExt(CString ext, bool fAudioOnly = false, bool fAssociableOnly = true) const; - const CMediaFormatCategory* FindMediaByExt(CString ext, bool fAudioOnly = false, bool fAssociableOnly = true) const; - - void GetFilter(CString& filter, CAtlArray& mask) const; - void GetAudioFilter(CString& filter, CAtlArray& mask) const; - - static bool IsExtHidden(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "BaseGraph.h" + + +class CMediaFormatCategory +{ +protected: + CString m_label, m_description; + CAtlList m_exts, m_backupexts; + bool m_fAudioOnly; + bool m_fAssociable; + +public: + CMediaFormatCategory(); + CMediaFormatCategory(CString label, CString description, CAtlList& exts, bool fAudioOnly = false, bool fAssociable = true); + CMediaFormatCategory(CString label, CString description, CString exts, bool fAudioOnly = false, bool fAssociable = true); + virtual ~CMediaFormatCategory(); + + void UpdateData(bool fSave); + + CMediaFormatCategory(const CMediaFormatCategory& mfc); + CMediaFormatCategory& operator = (const CMediaFormatCategory& mfc); + + void RestoreDefaultExts(); + void SetExts(CAtlList& exts); + void SetExts(CString exts); + + bool FindExt(CString ext) const { + return m_exts.Find(ext.TrimLeft(_T('.')).MakeLower()) != nullptr; + } + + CString GetLabel() const { return m_label; } + + CString GetDescription() const { return m_description; } + CString GetFilter() const; + CString GetExts() const; + CString GetExtsWithPeriod() const; + CString GetBackupExtsWithPeriod() const; + bool IsAudioOnly() const { return m_fAudioOnly; } + bool IsAssociable() const { return m_fAssociable; } + bool IsVideoOnly() const { return !m_fAudioOnly && m_label != _T("pls") && m_label != _T("cue") && m_label != _T("swf"); } +}; + +class CMediaFormats : public CAtlArray +{ +public: + CMediaFormats(); + virtual ~CMediaFormats(); + + //CMediaFormats(const CMediaFormats& mf) { *this = mf; } + CMediaFormats& operator=(const CMediaFormats& mf) { + Copy(mf); + return *this; + } + + void UpdateData(bool fSave); + + bool IsUsingEngine(CString path, engine_t e) const; + engine_t GetEngine(CString path) const; + + bool FindExt(CString ext, bool fAudioOnly = false, bool fAssociableOnly = true) const; + const CMediaFormatCategory* FindMediaByExt(CString ext, bool fAudioOnly = false, bool fAssociableOnly = true) const; + + void GetFilter(CString& filter, CAtlArray& mask) const; + void GetAudioFilter(CString& filter, CAtlArray& mask) const; + + static bool IsExtHidden(); +}; diff --git a/src/mpc-hc/MediaTypesDlg.cpp b/src/mpc-hc/MediaTypesDlg.cpp index c49971c5934..bbb1c1fecd4 100644 --- a/src/mpc-hc/MediaTypesDlg.cpp +++ b/src/mpc-hc/MediaTypesDlg.cpp @@ -1,158 +1,158 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "MediaTypesDlg.h" -#include "DSUtil.h" -#include "moreuuids.h" - - -// CMediaTypesDlg dialog - -//IMPLEMENT_DYNAMIC(CMediaTypesDlg, CResizableDialog) -CMediaTypesDlg::CMediaTypesDlg(IGraphBuilderDeadEnd* pGBDE, CWnd* pParent /*=nullptr*/) - : CMPCThemeResizableDialog(CMediaTypesDlg::IDD, pParent) - , m_pGBDE(pGBDE) - , m_type(UNKNOWN) - , m_subtype(GUID_NULL) -{ -} - -CMediaTypesDlg::~CMediaTypesDlg() -{ -} - -void CMediaTypesDlg::DoDataExchange(CDataExchange* pDX) -{ - CResizableDialog::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO1, m_pins); - DDX_Control(pDX, IDC_EDIT1, m_report); -} - -void CMediaTypesDlg::AddLine(CString str) -{ - str.Replace(_T("\n"), _T("\r\n")); - int len = m_report.GetWindowTextLength(); - m_report.SetSel(len, len, TRUE); - m_report.ReplaceSel(str); -} - -void CMediaTypesDlg::AddMediaType(const AM_MEDIA_TYPE* pmt) -{ - m_subtype = pmt->subtype; - if (pmt->majortype == MEDIATYPE_Video) { - m_type = VIDEO; - } else if (pmt->majortype == MEDIATYPE_Audio) { - m_type = AUDIO; - } else { - m_type = UNKNOWN; - } - - CAtlList sl; - CMediaTypeEx(*pmt).Dump(sl); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - AddLine(sl.GetNext(pos) + '\n'); - } -} - -BEGIN_MESSAGE_MAP(CMediaTypesDlg, CMPCThemeResizableDialog) - ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelchangeCombo1) - ON_MESSAGE(WM_EXTERNALCLOSE, OnExternalClose) -END_MESSAGE_MAP() - - -// CMediaTypesDlg message handlers - -BOOL CMediaTypesDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - CAtlList path; - CAtlList mts; - - for (int i = 0; S_OK == m_pGBDE->GetDeadEnd(i, path, mts); i++) { - if (!path.GetCount()) { - continue; - } - m_pins.SetItemData(m_pins.AddString(CString(path.GetTail())), (DWORD_PTR)i); - } - - m_pins.SetCurSel(0); - OnCbnSelchangeCombo1(); - - AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_STATIC2, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_COMBO1, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_EDIT1, TOP_LEFT, BOTTOM_RIGHT); - AddAnchor(IDOK, BOTTOM_RIGHT); - - SetMinTrackSize(CSize(300, 200)); - fulfillThemeReqs(); - - //DWORD threadID = GetWindowThreadProcessId(m_hWnd,nullptr); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CMediaTypesDlg::OnCbnSelchangeCombo1() -{ - m_report.SetWindowText(_T("")); - - int i = m_pins.GetCurSel(); - if (i < 0) { - return; - } - - CAtlList path; - CAtlList mts; - - if (FAILED(m_pGBDE->GetDeadEnd(i, path, mts)) || !path.GetCount()) { - return; - } - - POSITION pos = path.GetHeadPosition(); - while (pos) { - AddLine(CString(path.GetNext(pos)) + _T("\n")); - if (!pos) { - AddLine(_T("\n")); - } - } - - pos = mts.GetHeadPosition(); - for (int j = 0; pos; j++) { - CString str; - str.Format(_T("Media Type %d:\n"), j); - AddLine(str); - AddLine(_T("--------------------------\n")); - AddMediaType(&mts.GetNext(pos)); - AddLine(); - } - - m_report.SetSel(0, 0); -} - -LRESULT CMediaTypesDlg::OnExternalClose(WPARAM wParam, LPARAM lParam) { - EndDialog(IDCANCEL); - return LRESULT(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "MediaTypesDlg.h" +#include "DSUtil.h" +#include "moreuuids.h" + + +// CMediaTypesDlg dialog + +//IMPLEMENT_DYNAMIC(CMediaTypesDlg, CResizableDialog) +CMediaTypesDlg::CMediaTypesDlg(IGraphBuilderDeadEnd* pGBDE, CWnd* pParent /*=nullptr*/) + : CMPCThemeResizableDialog(CMediaTypesDlg::IDD, pParent) + , m_pGBDE(pGBDE) + , m_type(UNKNOWN) + , m_subtype(GUID_NULL) +{ +} + +CMediaTypesDlg::~CMediaTypesDlg() +{ +} + +void CMediaTypesDlg::DoDataExchange(CDataExchange* pDX) +{ + CResizableDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO1, m_pins); + DDX_Control(pDX, IDC_EDIT1, m_report); +} + +void CMediaTypesDlg::AddLine(CString str) +{ + str.Replace(_T("\n"), _T("\r\n")); + int len = m_report.GetWindowTextLength(); + m_report.SetSel(len, len, TRUE); + m_report.ReplaceSel(str); +} + +void CMediaTypesDlg::AddMediaType(const AM_MEDIA_TYPE* pmt) +{ + m_subtype = pmt->subtype; + if (pmt->majortype == MEDIATYPE_Video) { + m_type = VIDEO; + } else if (pmt->majortype == MEDIATYPE_Audio) { + m_type = AUDIO; + } else { + m_type = UNKNOWN; + } + + CAtlList sl; + CMediaTypeEx(*pmt).Dump(sl); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + AddLine(sl.GetNext(pos) + '\n'); + } +} + +BEGIN_MESSAGE_MAP(CMediaTypesDlg, CMPCThemeResizableDialog) + ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelchangeCombo1) + ON_MESSAGE(WM_EXTERNALCLOSE, OnExternalClose) +END_MESSAGE_MAP() + + +// CMediaTypesDlg message handlers + +BOOL CMediaTypesDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + CAtlList path; + CAtlList mts; + + for (int i = 0; S_OK == m_pGBDE->GetDeadEnd(i, path, mts); i++) { + if (!path.GetCount()) { + continue; + } + m_pins.SetItemData(m_pins.AddString(CString(path.GetTail())), (DWORD_PTR)i); + } + + m_pins.SetCurSel(0); + OnCbnSelchangeCombo1(); + + AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_STATIC2, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_COMBO1, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_EDIT1, TOP_LEFT, BOTTOM_RIGHT); + AddAnchor(IDOK, BOTTOM_RIGHT); + + SetMinTrackSize(CSize(300, 200)); + fulfillThemeReqs(); + + //DWORD threadID = GetWindowThreadProcessId(m_hWnd,nullptr); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CMediaTypesDlg::OnCbnSelchangeCombo1() +{ + m_report.SetWindowText(_T("")); + + int i = m_pins.GetCurSel(); + if (i < 0) { + return; + } + + CAtlList path; + CAtlList mts; + + if (FAILED(m_pGBDE->GetDeadEnd(i, path, mts)) || !path.GetCount()) { + return; + } + + POSITION pos = path.GetHeadPosition(); + while (pos) { + AddLine(CString(path.GetNext(pos)) + _T("\n")); + if (!pos) { + AddLine(_T("\n")); + } + } + + pos = mts.GetHeadPosition(); + for (int j = 0; pos; j++) { + CString str; + str.Format(_T("Media Type %d:\n"), j); + AddLine(str); + AddLine(_T("--------------------------\n")); + AddMediaType(&mts.GetNext(pos)); + AddLine(); + } + + m_report.SetSel(0, 0); +} + +LRESULT CMediaTypesDlg::OnExternalClose(WPARAM wParam, LPARAM lParam) { + EndDialog(IDCANCEL); + return LRESULT(); +} diff --git a/src/mpc-hc/MediaTypesDlg.h b/src/mpc-hc/MediaTypesDlg.h index db0dd3c3208..4f81e06ded0 100644 --- a/src/mpc-hc/MediaTypesDlg.h +++ b/src/mpc-hc/MediaTypesDlg.h @@ -1,64 +1,64 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include -#include "IGraphBuilder2.h" -#include "CMPCThemeResizableDialog.h" -#include "CMPCThemeEdit.h" -#include "CMPCThemeComboBox.h" - - -#define WM_EXTERNALCLOSE WM_APP + 0x100 - -// CMediaTypesDlg dialog - -class CMediaTypesDlg : public CMPCThemeResizableDialog -{ - // DECLARE_DYNAMIC(CMediaTypesDlg) - -private: - CComPtr m_pGBDE; - enum { UNKNOWN, VIDEO, AUDIO } m_type; - GUID m_subtype; - void AddLine(CString str = _T("\n")); - void AddMediaType(const AM_MEDIA_TYPE* pmt); - -public: - CMediaTypesDlg(IGraphBuilderDeadEnd* pGBDE, CWnd* pParent = nullptr); // standard constructor - virtual ~CMediaTypesDlg(); - - // Dialog Data - enum { IDD = IDD_MEDIATYPES_DLG }; - CMPCThemeComboBox m_pins; - CMPCThemeEdit m_report; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - - DECLARE_MESSAGE_MAP() -public: - afx_msg void OnCbnSelchangeCombo1(); - afx_msg LRESULT OnExternalClose(WPARAM wParam, LPARAM lParam); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include +#include "IGraphBuilder2.h" +#include "CMPCThemeResizableDialog.h" +#include "CMPCThemeEdit.h" +#include "CMPCThemeComboBox.h" + + +#define WM_EXTERNALCLOSE WM_APP + 0x100 + +// CMediaTypesDlg dialog + +class CMediaTypesDlg : public CMPCThemeResizableDialog +{ + // DECLARE_DYNAMIC(CMediaTypesDlg) + +private: + CComPtr m_pGBDE; + enum { UNKNOWN, VIDEO, AUDIO } m_type; + GUID m_subtype; + void AddLine(CString str = _T("\n")); + void AddMediaType(const AM_MEDIA_TYPE* pmt); + +public: + CMediaTypesDlg(IGraphBuilderDeadEnd* pGBDE, CWnd* pParent = nullptr); // standard constructor + virtual ~CMediaTypesDlg(); + + // Dialog Data + enum { IDD = IDD_MEDIATYPES_DLG }; + CMPCThemeComboBox m_pins; + CMPCThemeEdit m_report; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnCbnSelchangeCombo1(); + afx_msg LRESULT OnExternalClose(WPARAM wParam, LPARAM lParam); +}; diff --git a/src/mpc-hc/Monitors.cpp b/src/mpc-hc/Monitors.cpp index 93c5ed14e97..927ad7402fc 100644 --- a/src/mpc-hc/Monitors.cpp +++ b/src/mpc-hc/Monitors.cpp @@ -1,246 +1,246 @@ -/* - * Author: Donald Kackman - * Email: don@itsEngineering.com - * Copyright 2002, Donald Kackman - * - * 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 . - * - */ - -#include "stdafx.h" -#include "Monitors.h" - - -// CMonitors - -CMonitors::CMonitors() -{ - // WARNING : GetSystemMetrics(SM_CMONITORS) return only visible display monitors, and EnumDisplayMonitors - // enumerate visible and pseudo invisible monitors !!! - // m_MonitorArray.SetSize( GetMonitorCount() ); - - ADDMONITOR addMonitor; - addMonitor.pMonitors = &m_MonitorArray; - addMonitor.currentIndex = 0; - - ::EnumDisplayMonitors(nullptr, nullptr, AddMonitorsCallBack, (LPARAM)&addMonitor); -} - -CMonitors::~CMonitors() -{ - for (int i = 0; i < m_MonitorArray.GetSize(); i++) { - delete m_MonitorArray.GetAt(i); - } -} - - -// CMonitors member functions - -BOOL CALLBACK CMonitors::AddMonitorsCallBack(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - LPADDMONITOR pAddMonitor = (LPADDMONITOR)dwData; - - CMonitor* pMonitor = DEBUG_NEW CMonitor; - pMonitor->Attach(hMonitor); - - pAddMonitor->pMonitors->Add(pMonitor); - pAddMonitor->currentIndex++; - - return TRUE; -} -// -// returns the primary monitor -CMonitor CMonitors::GetPrimaryMonitor() -{ - //the primary monitor always has its origin at 0,0 - HMONITOR hMonitor = ::MonitorFromPoint(CPoint(0, 0), MONITOR_DEFAULTTOPRIMARY); - ASSERT(IsMonitor(hMonitor)); - - CMonitor monitor; - monitor.Attach(hMonitor); - ASSERT(monitor.IsPrimaryMonitor()); - - return monitor; -} - -CMonitor CMonitors::GetMonitor(CStringW displayName) -{ - CMonitor monitor; - if (displayName != _T("Current")) { - for (int i = 0; i < GetCount(); i++) { - monitor = GetMonitor(i); - if (!monitor.IsMonitor()) { - continue; - } - CStringW str; - monitor.GetName(str); - if (displayName == str) { - break; - } - monitor.Detach(); - } - } - return monitor; -} - -CMonitor CMonitors::GetMonitor(CStringW displayName, CStringW deviceName) -{ - if (deviceName.IsEmpty()) { - return GetMonitor(displayName); - } - - CMonitor monitor; - if (displayName != _T("Current")) { - int best = -1; - for (int i = 0; i < GetCount(); i++) { - monitor = GetMonitor(i); - if (!monitor.IsMonitor()) { - continue; - } - CStringW displayName2, deviceName2; - monitor.GetNames(displayName2, deviceName2); - if (deviceName == deviceName2) { - if (displayName == displayName2) { - // exact match - best = -1; - break; - } else { - // there might be a better match in case of duplicate device names - if (best == -1) { - best = i; - } - } - } - monitor.Detach(); - } - if (best >= 0) { - monitor = GetMonitor(best); - } - } - return monitor; -} - -// -// is the given handle a valid monitor handle -BOOL CMonitors::IsMonitor(const HMONITOR hMonitor) -{ - if (hMonitor == nullptr) { - return FALSE; - } - - MATCHMONITOR match; - match.target = hMonitor; - match.foundMatch = FALSE; - - ::EnumDisplayMonitors(nullptr, nullptr, FindMatchingMonitorHandle, (LPARAM)&match); - - return match.foundMatch; -} - -//this is the callback method that gets called via IsMontior -BOOL CALLBACK CMonitors::FindMatchingMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - LPMATCHMONITOR pMatch = (LPMATCHMONITOR)dwData; - - if (hMonitor == pMatch->target) { - //found a monitor with the same handle we are looking for - pMatch->foundMatch = TRUE; - return FALSE; //stop enumerating - } - - //haven't found a match yet - pMatch->foundMatch = FALSE; - return TRUE; //keep enumerating -} - -BOOL CMonitors::AllMonitorsShareDisplayFormat() -{ - return ::GetSystemMetrics(SM_SAMEDISPLAYFORMAT); -} - -// -// the number of monitors on the system -int CMonitors::GetMonitorCount() -{ - return ::GetSystemMetrics(SM_CMONITORS); -} - -CMonitor CMonitors::GetMonitor(const int index) const -{ - ASSERT(index >= 0 && index < m_MonitorArray.GetCount()); - - CMonitor* pMonitor = static_cast(m_MonitorArray.GetAt(index)); - - return *pMonitor; -} - -// -// returns the rectangle that is the union of all active monitors -void CMonitors::GetVirtualDesktopRect(LPRECT lprc) -{ - ::SetRect(lprc, - ::GetSystemMetrics(SM_XVIRTUALSCREEN), - ::GetSystemMetrics(SM_YVIRTUALSCREEN), - ::GetSystemMetrics(SM_CXVIRTUALSCREEN), - ::GetSystemMetrics(SM_CYVIRTUALSCREEN)); - -} - -// -// these methods determine whether the given item is -// visible on any monitor -BOOL CMonitors::IsOnScreen(const LPRECT lprc) -{ - return ::MonitorFromRect(lprc, MONITOR_DEFAULTTONULL) != nullptr; -} - -BOOL CMonitors::IsOnScreen(const POINT& pt) -{ - return ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) != nullptr; -} - -BOOL CMonitors::IsOnScreen(const CWnd* pWnd) -{ - return ::MonitorFromWindow(pWnd->GetSafeHwnd(), MONITOR_DEFAULTTONULL) != nullptr; -} - -CMonitor CMonitors::GetNearestMonitor(const LPRECT lprc) -{ - CMonitor monitor; - monitor.Attach(::MonitorFromRect(lprc, MONITOR_DEFAULTTONEAREST)); - - return monitor; - -} - -CMonitor CMonitors::GetNearestMonitor(const POINT& pt) -{ - CMonitor monitor; - monitor.Attach(::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST)); - - return monitor; -} - -CMonitor CMonitors::GetNearestMonitor(const CWnd* pWnd) -{ - ASSERT(pWnd); - ASSERT(::IsWindow(pWnd->m_hWnd)); - - CMonitor monitor; - monitor.Attach(::MonitorFromWindow(pWnd->GetSafeHwnd(), MONITOR_DEFAULTTONEAREST)); - - return monitor; -} +/* + * Author: Donald Kackman + * Email: don@itsEngineering.com + * Copyright 2002, Donald Kackman + * + * 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 . + * + */ + +#include "stdafx.h" +#include "Monitors.h" + + +// CMonitors + +CMonitors::CMonitors() +{ + // WARNING : GetSystemMetrics(SM_CMONITORS) return only visible display monitors, and EnumDisplayMonitors + // enumerate visible and pseudo invisible monitors !!! + // m_MonitorArray.SetSize( GetMonitorCount() ); + + ADDMONITOR addMonitor; + addMonitor.pMonitors = &m_MonitorArray; + addMonitor.currentIndex = 0; + + ::EnumDisplayMonitors(nullptr, nullptr, AddMonitorsCallBack, (LPARAM)&addMonitor); +} + +CMonitors::~CMonitors() +{ + for (int i = 0; i < m_MonitorArray.GetSize(); i++) { + delete m_MonitorArray.GetAt(i); + } +} + + +// CMonitors member functions + +BOOL CALLBACK CMonitors::AddMonitorsCallBack(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + LPADDMONITOR pAddMonitor = (LPADDMONITOR)dwData; + + CMonitor* pMonitor = DEBUG_NEW CMonitor; + pMonitor->Attach(hMonitor); + + pAddMonitor->pMonitors->Add(pMonitor); + pAddMonitor->currentIndex++; + + return TRUE; +} +// +// returns the primary monitor +CMonitor CMonitors::GetPrimaryMonitor() +{ + //the primary monitor always has its origin at 0,0 + HMONITOR hMonitor = ::MonitorFromPoint(CPoint(0, 0), MONITOR_DEFAULTTOPRIMARY); + ASSERT(IsMonitor(hMonitor)); + + CMonitor monitor; + monitor.Attach(hMonitor); + ASSERT(monitor.IsPrimaryMonitor()); + + return monitor; +} + +CMonitor CMonitors::GetMonitor(CStringW displayName) +{ + CMonitor monitor; + if (displayName != _T("Current")) { + for (int i = 0; i < GetCount(); i++) { + monitor = GetMonitor(i); + if (!monitor.IsMonitor()) { + continue; + } + CStringW str; + monitor.GetName(str); + if (displayName == str) { + break; + } + monitor.Detach(); + } + } + return monitor; +} + +CMonitor CMonitors::GetMonitor(CStringW displayName, CStringW deviceName) +{ + if (deviceName.IsEmpty()) { + return GetMonitor(displayName); + } + + CMonitor monitor; + if (displayName != _T("Current")) { + int best = -1; + for (int i = 0; i < GetCount(); i++) { + monitor = GetMonitor(i); + if (!monitor.IsMonitor()) { + continue; + } + CStringW displayName2, deviceName2; + monitor.GetNames(displayName2, deviceName2); + if (deviceName == deviceName2) { + if (displayName == displayName2) { + // exact match + best = -1; + break; + } else { + // there might be a better match in case of duplicate device names + if (best == -1) { + best = i; + } + } + } + monitor.Detach(); + } + if (best >= 0) { + monitor = GetMonitor(best); + } + } + return monitor; +} + +// +// is the given handle a valid monitor handle +BOOL CMonitors::IsMonitor(const HMONITOR hMonitor) +{ + if (hMonitor == nullptr) { + return FALSE; + } + + MATCHMONITOR match; + match.target = hMonitor; + match.foundMatch = FALSE; + + ::EnumDisplayMonitors(nullptr, nullptr, FindMatchingMonitorHandle, (LPARAM)&match); + + return match.foundMatch; +} + +//this is the callback method that gets called via IsMontior +BOOL CALLBACK CMonitors::FindMatchingMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + LPMATCHMONITOR pMatch = (LPMATCHMONITOR)dwData; + + if (hMonitor == pMatch->target) { + //found a monitor with the same handle we are looking for + pMatch->foundMatch = TRUE; + return FALSE; //stop enumerating + } + + //haven't found a match yet + pMatch->foundMatch = FALSE; + return TRUE; //keep enumerating +} + +BOOL CMonitors::AllMonitorsShareDisplayFormat() +{ + return ::GetSystemMetrics(SM_SAMEDISPLAYFORMAT); +} + +// +// the number of monitors on the system +int CMonitors::GetMonitorCount() +{ + return ::GetSystemMetrics(SM_CMONITORS); +} + +CMonitor CMonitors::GetMonitor(const int index) const +{ + ASSERT(index >= 0 && index < m_MonitorArray.GetCount()); + + CMonitor* pMonitor = static_cast(m_MonitorArray.GetAt(index)); + + return *pMonitor; +} + +// +// returns the rectangle that is the union of all active monitors +void CMonitors::GetVirtualDesktopRect(LPRECT lprc) +{ + ::SetRect(lprc, + ::GetSystemMetrics(SM_XVIRTUALSCREEN), + ::GetSystemMetrics(SM_YVIRTUALSCREEN), + ::GetSystemMetrics(SM_CXVIRTUALSCREEN), + ::GetSystemMetrics(SM_CYVIRTUALSCREEN)); + +} + +// +// these methods determine whether the given item is +// visible on any monitor +BOOL CMonitors::IsOnScreen(const LPRECT lprc) +{ + return ::MonitorFromRect(lprc, MONITOR_DEFAULTTONULL) != nullptr; +} + +BOOL CMonitors::IsOnScreen(const POINT& pt) +{ + return ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) != nullptr; +} + +BOOL CMonitors::IsOnScreen(const CWnd* pWnd) +{ + return ::MonitorFromWindow(pWnd->GetSafeHwnd(), MONITOR_DEFAULTTONULL) != nullptr; +} + +CMonitor CMonitors::GetNearestMonitor(const LPRECT lprc) +{ + CMonitor monitor; + monitor.Attach(::MonitorFromRect(lprc, MONITOR_DEFAULTTONEAREST)); + + return monitor; + +} + +CMonitor CMonitors::GetNearestMonitor(const POINT& pt) +{ + CMonitor monitor; + monitor.Attach(::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST)); + + return monitor; +} + +CMonitor CMonitors::GetNearestMonitor(const CWnd* pWnd) +{ + ASSERT(pWnd); + ASSERT(::IsWindow(pWnd->m_hWnd)); + + CMonitor monitor; + monitor.Attach(::MonitorFromWindow(pWnd->GetSafeHwnd(), MONITOR_DEFAULTTONEAREST)); + + return monitor; +} diff --git a/src/mpc-hc/Monitors.h b/src/mpc-hc/Monitors.h index 7a69af5c010..f374853d37e 100644 --- a/src/mpc-hc/Monitors.h +++ b/src/mpc-hc/Monitors.h @@ -1,90 +1,90 @@ -/* - * Author: Donald Kackman - * Email: don@itsEngineering.com - * Copyright 2002, Donald Kackman - * - * 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 . - * - */ - -#pragma once - -#include "MultiMonitor.h" - -// CMonitors command target - -class CMonitors : public CObject -{ -public: - CMonitors(); - virtual ~CMonitors(); - - CMonitor GetMonitor(const int index) const; - - - int GetCount() const { - return (int)m_MonitorArray.GetCount(); - } - - //static members - static CMonitor GetNearestMonitor(const LPRECT lprc); - static CMonitor GetNearestMonitor(const POINT& pt); - static CMonitor GetNearestMonitor(const CWnd* pWnd); - - static BOOL IsOnScreen(const POINT& pt); - static BOOL IsOnScreen(const CWnd* pWnd); - static BOOL IsOnScreen(const LPRECT lprc); - - static void GetVirtualDesktopRect(LPRECT lprc); - - static BOOL IsMonitor(const HMONITOR hMonitor); - - static CMonitor GetPrimaryMonitor(); - CMonitor GetMonitor(CStringW displayName); - CMonitor GetMonitor(CStringW displayName, CStringW deviceName); - static BOOL AllMonitorsShareDisplayFormat(); - - static int GetMonitorCount(); - -private: - CObArray m_MonitorArray; - - typedef struct tagMATCHMONITOR { - HMONITOR target; - BOOL foundMatch; - } MATCHMONITOR, *LPMATCHMONITOR; - - static BOOL CALLBACK FindMatchingMonitorHandle( - HMONITOR hMonitor, // handle to display monitor - HDC hdcMonitor, // handle to monitor DC - LPRECT lprcMonitor, // monitor intersection rectangle - LPARAM dwData // data - ); - - - typedef struct tagADDMONITOR { - CObArray* pMonitors; - int currentIndex; - } ADDMONITOR, *LPADDMONITOR; - - static BOOL CALLBACK AddMonitorsCallBack( - HMONITOR hMonitor, // handle to display monitor - HDC hdcMonitor, // handle to monitor DC - LPRECT lprcMonitor, // monitor intersection rectangle - LPARAM dwData // data - ); - -}; +/* + * Author: Donald Kackman + * Email: don@itsEngineering.com + * Copyright 2002, Donald Kackman + * + * 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 . + * + */ + +#pragma once + +#include "MultiMonitor.h" + +// CMonitors command target + +class CMonitors : public CObject +{ +public: + CMonitors(); + virtual ~CMonitors(); + + CMonitor GetMonitor(const int index) const; + + + int GetCount() const { + return (int)m_MonitorArray.GetCount(); + } + + //static members + static CMonitor GetNearestMonitor(const LPRECT lprc); + static CMonitor GetNearestMonitor(const POINT& pt); + static CMonitor GetNearestMonitor(const CWnd* pWnd); + + static BOOL IsOnScreen(const POINT& pt); + static BOOL IsOnScreen(const CWnd* pWnd); + static BOOL IsOnScreen(const LPRECT lprc); + + static void GetVirtualDesktopRect(LPRECT lprc); + + static BOOL IsMonitor(const HMONITOR hMonitor); + + static CMonitor GetPrimaryMonitor(); + CMonitor GetMonitor(CStringW displayName); + CMonitor GetMonitor(CStringW displayName, CStringW deviceName); + static BOOL AllMonitorsShareDisplayFormat(); + + static int GetMonitorCount(); + +private: + CObArray m_MonitorArray; + + typedef struct tagMATCHMONITOR { + HMONITOR target; + BOOL foundMatch; + } MATCHMONITOR, *LPMATCHMONITOR; + + static BOOL CALLBACK FindMatchingMonitorHandle( + HMONITOR hMonitor, // handle to display monitor + HDC hdcMonitor, // handle to monitor DC + LPRECT lprcMonitor, // monitor intersection rectangle + LPARAM dwData // data + ); + + + typedef struct tagADDMONITOR { + CObArray* pMonitors; + int currentIndex; + } ADDMONITOR, *LPADDMONITOR; + + static BOOL CALLBACK AddMonitorsCallBack( + HMONITOR hMonitor, // handle to display monitor + HDC hdcMonitor, // handle to monitor DC + LPRECT lprcMonitor, // monitor intersection rectangle + LPARAM dwData // data + ); + +}; diff --git a/src/mpc-hc/MpcApi.h b/src/mpc-hc/MpcApi.h index 4b4b0e917a7..4adb929c4a9 100644 --- a/src/mpc-hc/MpcApi.h +++ b/src/mpc-hc/MpcApi.h @@ -1,286 +1,286 @@ -/* - * (C) 2006-2015 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 . - * - */ - - -/* -This file defines commands used for "MPC-HC" API. To send commands -to MPC-HC and receive playback notifications, first launch MPC-HC with the /slave command line -argument followed by a HWnd handle used to receive notification: - -..\bin\mpc-hc /slave 125421 - -After startup, MPC-HC sends a WM_COPYDATA message to host with COPYDATASTRUCT struct filled with: - - dwData : CMD_CONNECT - - lpData : Unicode string containing MPC-HC's main window handle - -To control MPC-HC, send WM_COPYDATA messages to Hwnd provided on connection. All messages should be -formatted as null-terminated Unicode strings. For commands or notifications with multiple parameters, -values are separated by |. -If a string contains a |, it will be escaped with a \ so a \| is not a separator. - -Ex: When a file is opened, MPC-HC sends to host the "now playing" notification: - - dwData : CMD_NOWPLAYING - - lpData : title|author|description|filename|duration - -Ex: When a DVD is playing, use CMD_GETNOWPLAYING to get: - - dwData : CMD_NOWPLAYING - - lpData : dvddomain|titlenumber|numberofchapters|currentchapter|titleduration - dvddomains: DVD - Stopped, DVD - FirstPlay, DVD - RootMenu, DVD - TitleMenu, DVD - Title -*/ - -#pragma once - -typedef enum MPC_LOADSTATE { - MLS_CLOSED, - MLS_LOADING, - MLS_LOADED, - MLS_CLOSING, - MLS_FAILING, -} MPC_LOADSTATE; - - -typedef enum MPC_PLAYSTATE { - PS_PLAY = 0, - PS_PAUSE = 1, - PS_STOP = 2, - PS_UNUSED = 3 -} MPC_PLAYSTATE; - - -struct MPC_OSDDATA { - int nMsgPos; // screen position constant (see OSD_MESSAGEPOS constants) - int nDurationMS; // duration in milliseconds - TCHAR strMsg[128]; // message to display in OSD -}; - -// MPC_OSDDATA. nMsgPos constants (for host side programming): -/* -typedef enum { - OSD_NOMESSAGE, - OSD_TOPLEFT, - OSD_TOPRIGHT -} OSD_MESSAGEPOS; -*/ - - -typedef enum MPCAPI_COMMAND : - unsigned int { - // ==== Commands from MPC-HC to host - - // Send after connection - // Parameter 1: MPC-HC window handle (command should be sent to this HWnd) - CMD_CONNECT = 0x50000000, - - // Send when opening or closing file - // Parameter 1: current state (see MPC_LOADSTATE enum) - CMD_STATE = 0x50000001, - - // Send when playing, pausing or closing file - // Parameter 1: current play mode (see MPC_PLAYSTATE enum) - CMD_PLAYMODE = 0x50000002, - - // Send after opening a new file - // Parameter 1: title - // Parameter 2: author - // Parameter 3: description - // Parameter 4: complete filename (path included) - // Parameter 5: duration in seconds - CMD_NOWPLAYING = 0x50000003, - - // List of subtitle tracks - // Parameter 1: Subtitle track name 0 - // Parameter 2: Subtitle track name 1 - // ... - // Parameter n: Active subtitle track, -1 if subtitles are disabled - // - // if no subtitle track present, returns -1 - // if no file loaded, returns -2 - CMD_LISTSUBTITLETRACKS = 0x50000004, - - // List of audio tracks - // Parameter 1: Audio track name 0 - // Parameter 2: Audio track name 1 - // ... - // Parameter n: Active audio track - // - // if no audio track is present, returns -1 - // if no file is loaded, returns -2 - CMD_LISTAUDIOTRACKS = 0x50000005, - - // Send index of currently selected audio track - CMD_CURRENTAUDIOTRACK = 0x5000000C, - - // Send index of currently selected subtitle track - CMD_CURRENTSUBTITLETRACK = 0x5000000D, - - // Send current playback position in response - // of CMD_GETCURRENTPOSITION. - // Parameter 1: current position in seconds - CMD_CURRENTPOSITION = 0x50000007, - - // Send the current playback position after a jump. - // (Automatically sent after a seek event). - // Parameter 1: new playback position (in seconds). - CMD_NOTIFYSEEK = 0x50000008, - - // Notify the end of current playback - // (Automatically sent). - // Parameter 1: none. - CMD_NOTIFYENDOFSTREAM = 0x50000009, - - // Send version str - // Parameter 1: MPC-HC's version - CMD_VERSION = 0x5000000A, - - // List of files in the playlist - // Parameter 1: file path 0 - // Parameter 2: file path 1 - // ... - // Parameter n: active file, -1 if no active file - CMD_PLAYLIST = 0x50000006, - - // Send information about MPC-HC closing - CMD_DISCONNECT = 0x5000000B, - - // ==== Commands from host to MPC-HC - - // Open new file - // Parameter 1: file path - CMD_OPENFILE = 0xA0000000, - - // Stop playback, but keep file / playlist - CMD_STOP = 0xA0000001, - - // Stop playback and close file / playlist - CMD_CLOSEFILE = 0xA0000002, - - // Pause or restart playback - CMD_PLAYPAUSE = 0xA0000003, - - // Unpause playback - CMD_PLAY = 0xA0000004, - - // Pause playback - CMD_PAUSE = 0xA0000005, - - // Add a new file to playlist (did not start playing) - // Parameter 1: file path - CMD_ADDTOPLAYLIST = 0xA0001000, - - // Remove all files from playlist - CMD_CLEARPLAYLIST = 0xA0001001, - - // Start playing playlist - CMD_STARTPLAYLIST = 0xA0001002, - - CMD_REMOVEFROMPLAYLIST = 0xA0001003, // TODO - - // Cue current file to specific position - // Parameter 1: new position in seconds - CMD_SETPOSITION = 0xA0002000, - - // Set the audio delay - // Parameter 1: new audio delay in ms - CMD_SETAUDIODELAY = 0xA0002001, - - // Set the subtitle delay - // Parameter 1: new subtitle delay in ms - CMD_SETSUBTITLEDELAY = 0xA0002002, - - // Set the active file in the playlist - // Parameter 1: index of the active file, -1 for no file selected - // DOESN'T WORK - CMD_SETINDEXPLAYLIST = 0xA0002003, - - // Set the audio track - // Parameter 1: index of the audio track - CMD_SETAUDIOTRACK = 0xA0002004, - - // Set the subtitle track - // Parameter 1: index of the subtitle track, -1 for disabling subtitles - CMD_SETSUBTITLETRACK = 0xA0002005, - - // Ask for a list of the subtitles tracks of the file - // return a CMD_LISTSUBTITLETRACKS - CMD_GETSUBTITLETRACKS = 0xA0003000, - - // Ask for the current playback position, - // see CMD_CURRENTPOSITION. - // Parameter 1: current position in seconds - CMD_GETCURRENTPOSITION = 0xA0003004, - - // Jump forward/backward of N seconds, - // Parameter 1: seconds (negative values for backward) - CMD_JUMPOFNSECONDS = 0xA0003005, - - // Ask slave for version - CMD_GETVERSION = 0xA0003006, - - // Ask for a list of the audio tracks of the file - // return a CMD_LISTAUDIOTRACKS - CMD_GETAUDIOTRACKS = 0xA0003001, - - // Ask for the properties of the current loaded file - // return a CMD_NOWPLAYING - CMD_GETNOWPLAYING = 0xA0003002, - - // Ask for the current playlist - // return a CMD_PLAYLIST - CMD_GETPLAYLIST = 0xA0003003, - - // Ask for the index of the currently selected audio track - // return a CMD_CURRENTAUDIOTRACK - CMD_GETCURRENTAUDIOTRACK = 0xA0003007, - - // Ask for the index of the currently selected subtitle track - // return a CMD_CURRENTSUBTITLETRACK - CMD_GETCURRENTSUBTITLETRACK = 0xA0003008, - - // Toggle FullScreen - CMD_TOGGLEFULLSCREEN = 0xA0004000, - - // Jump forward(medium) - CMD_JUMPFORWARDMED = 0xA0004001, - - // Jump backward(medium) - CMD_JUMPBACKWARDMED = 0xA0004002, - - // Increase Volume - CMD_INCREASEVOLUME = 0xA0004003, - - // Decrease volume - CMD_DECREASEVOLUME = 0xA0004004, - - // Toggle shader - CMD_SHADER_TOGGLE = 0xA0004005, - - // Close App - CMD_CLOSEAPP = 0xA0004006, - - // Set playing rate - CMD_SETSPEED = 0xA0004008, - - // Set Pan & Scan - CMD_SETPANSCAN = 0xA0004009, - - // Show host defined OSD message string - CMD_OSDSHOWMESSAGE = 0xA0005000 - -} MPCAPI_COMMAND; +/* + * (C) 2006-2015 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 . + * + */ + + +/* +This file defines commands used for "MPC-HC" API. To send commands +to MPC-HC and receive playback notifications, first launch MPC-HC with the /slave command line +argument followed by a HWnd handle used to receive notification: + +..\bin\mpc-hc /slave 125421 + +After startup, MPC-HC sends a WM_COPYDATA message to host with COPYDATASTRUCT struct filled with: + - dwData : CMD_CONNECT + - lpData : Unicode string containing MPC-HC's main window handle + +To control MPC-HC, send WM_COPYDATA messages to Hwnd provided on connection. All messages should be +formatted as null-terminated Unicode strings. For commands or notifications with multiple parameters, +values are separated by |. +If a string contains a |, it will be escaped with a \ so a \| is not a separator. + +Ex: When a file is opened, MPC-HC sends to host the "now playing" notification: + - dwData : CMD_NOWPLAYING + - lpData : title|author|description|filename|duration + +Ex: When a DVD is playing, use CMD_GETNOWPLAYING to get: + - dwData : CMD_NOWPLAYING + - lpData : dvddomain|titlenumber|numberofchapters|currentchapter|titleduration + dvddomains: DVD - Stopped, DVD - FirstPlay, DVD - RootMenu, DVD - TitleMenu, DVD - Title +*/ + +#pragma once + +typedef enum MPC_LOADSTATE { + MLS_CLOSED, + MLS_LOADING, + MLS_LOADED, + MLS_CLOSING, + MLS_FAILING, +} MPC_LOADSTATE; + + +typedef enum MPC_PLAYSTATE { + PS_PLAY = 0, + PS_PAUSE = 1, + PS_STOP = 2, + PS_UNUSED = 3 +} MPC_PLAYSTATE; + + +struct MPC_OSDDATA { + int nMsgPos; // screen position constant (see OSD_MESSAGEPOS constants) + int nDurationMS; // duration in milliseconds + TCHAR strMsg[128]; // message to display in OSD +}; + +// MPC_OSDDATA. nMsgPos constants (for host side programming): +/* +typedef enum { + OSD_NOMESSAGE, + OSD_TOPLEFT, + OSD_TOPRIGHT +} OSD_MESSAGEPOS; +*/ + + +typedef enum MPCAPI_COMMAND : + unsigned int { + // ==== Commands from MPC-HC to host + + // Send after connection + // Parameter 1: MPC-HC window handle (command should be sent to this HWnd) + CMD_CONNECT = 0x50000000, + + // Send when opening or closing file + // Parameter 1: current state (see MPC_LOADSTATE enum) + CMD_STATE = 0x50000001, + + // Send when playing, pausing or closing file + // Parameter 1: current play mode (see MPC_PLAYSTATE enum) + CMD_PLAYMODE = 0x50000002, + + // Send after opening a new file + // Parameter 1: title + // Parameter 2: author + // Parameter 3: description + // Parameter 4: complete filename (path included) + // Parameter 5: duration in seconds + CMD_NOWPLAYING = 0x50000003, + + // List of subtitle tracks + // Parameter 1: Subtitle track name 0 + // Parameter 2: Subtitle track name 1 + // ... + // Parameter n: Active subtitle track, -1 if subtitles are disabled + // + // if no subtitle track present, returns -1 + // if no file loaded, returns -2 + CMD_LISTSUBTITLETRACKS = 0x50000004, + + // List of audio tracks + // Parameter 1: Audio track name 0 + // Parameter 2: Audio track name 1 + // ... + // Parameter n: Active audio track + // + // if no audio track is present, returns -1 + // if no file is loaded, returns -2 + CMD_LISTAUDIOTRACKS = 0x50000005, + + // Send index of currently selected audio track + CMD_CURRENTAUDIOTRACK = 0x5000000C, + + // Send index of currently selected subtitle track + CMD_CURRENTSUBTITLETRACK = 0x5000000D, + + // Send current playback position in response + // of CMD_GETCURRENTPOSITION. + // Parameter 1: current position in seconds + CMD_CURRENTPOSITION = 0x50000007, + + // Send the current playback position after a jump. + // (Automatically sent after a seek event). + // Parameter 1: new playback position (in seconds). + CMD_NOTIFYSEEK = 0x50000008, + + // Notify the end of current playback + // (Automatically sent). + // Parameter 1: none. + CMD_NOTIFYENDOFSTREAM = 0x50000009, + + // Send version str + // Parameter 1: MPC-HC's version + CMD_VERSION = 0x5000000A, + + // List of files in the playlist + // Parameter 1: file path 0 + // Parameter 2: file path 1 + // ... + // Parameter n: active file, -1 if no active file + CMD_PLAYLIST = 0x50000006, + + // Send information about MPC-HC closing + CMD_DISCONNECT = 0x5000000B, + + // ==== Commands from host to MPC-HC + + // Open new file + // Parameter 1: file path + CMD_OPENFILE = 0xA0000000, + + // Stop playback, but keep file / playlist + CMD_STOP = 0xA0000001, + + // Stop playback and close file / playlist + CMD_CLOSEFILE = 0xA0000002, + + // Pause or restart playback + CMD_PLAYPAUSE = 0xA0000003, + + // Unpause playback + CMD_PLAY = 0xA0000004, + + // Pause playback + CMD_PAUSE = 0xA0000005, + + // Add a new file to playlist (did not start playing) + // Parameter 1: file path + CMD_ADDTOPLAYLIST = 0xA0001000, + + // Remove all files from playlist + CMD_CLEARPLAYLIST = 0xA0001001, + + // Start playing playlist + CMD_STARTPLAYLIST = 0xA0001002, + + CMD_REMOVEFROMPLAYLIST = 0xA0001003, // TODO + + // Cue current file to specific position + // Parameter 1: new position in seconds + CMD_SETPOSITION = 0xA0002000, + + // Set the audio delay + // Parameter 1: new audio delay in ms + CMD_SETAUDIODELAY = 0xA0002001, + + // Set the subtitle delay + // Parameter 1: new subtitle delay in ms + CMD_SETSUBTITLEDELAY = 0xA0002002, + + // Set the active file in the playlist + // Parameter 1: index of the active file, -1 for no file selected + // DOESN'T WORK + CMD_SETINDEXPLAYLIST = 0xA0002003, + + // Set the audio track + // Parameter 1: index of the audio track + CMD_SETAUDIOTRACK = 0xA0002004, + + // Set the subtitle track + // Parameter 1: index of the subtitle track, -1 for disabling subtitles + CMD_SETSUBTITLETRACK = 0xA0002005, + + // Ask for a list of the subtitles tracks of the file + // return a CMD_LISTSUBTITLETRACKS + CMD_GETSUBTITLETRACKS = 0xA0003000, + + // Ask for the current playback position, + // see CMD_CURRENTPOSITION. + // Parameter 1: current position in seconds + CMD_GETCURRENTPOSITION = 0xA0003004, + + // Jump forward/backward of N seconds, + // Parameter 1: seconds (negative values for backward) + CMD_JUMPOFNSECONDS = 0xA0003005, + + // Ask slave for version + CMD_GETVERSION = 0xA0003006, + + // Ask for a list of the audio tracks of the file + // return a CMD_LISTAUDIOTRACKS + CMD_GETAUDIOTRACKS = 0xA0003001, + + // Ask for the properties of the current loaded file + // return a CMD_NOWPLAYING + CMD_GETNOWPLAYING = 0xA0003002, + + // Ask for the current playlist + // return a CMD_PLAYLIST + CMD_GETPLAYLIST = 0xA0003003, + + // Ask for the index of the currently selected audio track + // return a CMD_CURRENTAUDIOTRACK + CMD_GETCURRENTAUDIOTRACK = 0xA0003007, + + // Ask for the index of the currently selected subtitle track + // return a CMD_CURRENTSUBTITLETRACK + CMD_GETCURRENTSUBTITLETRACK = 0xA0003008, + + // Toggle FullScreen + CMD_TOGGLEFULLSCREEN = 0xA0004000, + + // Jump forward(medium) + CMD_JUMPFORWARDMED = 0xA0004001, + + // Jump backward(medium) + CMD_JUMPBACKWARDMED = 0xA0004002, + + // Increase Volume + CMD_INCREASEVOLUME = 0xA0004003, + + // Decrease volume + CMD_DECREASEVOLUME = 0xA0004004, + + // Toggle shader + CMD_SHADER_TOGGLE = 0xA0004005, + + // Close App + CMD_CLOSEAPP = 0xA0004006, + + // Set playing rate + CMD_SETSPEED = 0xA0004008, + + // Set Pan & Scan + CMD_SETPANSCAN = 0xA0004009, + + // Show host defined OSD message string + CMD_OSDSHOWMESSAGE = 0xA0005000 + +} MPCAPI_COMMAND; diff --git a/src/mpc-hc/Mpeg2SectionData.cpp b/src/mpc-hc/Mpeg2SectionData.cpp index 0d1f8946432..777a05ebb03 100644 --- a/src/mpc-hc/Mpeg2SectionData.cpp +++ b/src/mpc-hc/Mpeg2SectionData.cpp @@ -1,879 +1,879 @@ -/* - * (C) 2009-2017 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 . - * - */ - -#include "stdafx.h" -#include "BaseClasses/streams.h" -#include - -#include "GolombBuffer.h" -#include "Mpeg2SectionData.h" -#include "FreeviewEPGDecode.h" -#include "resource.h" -#include "Logger.h" - -#define BeginEnumDescriptors(gb, nType, nLength) \ -{ \ - BYTE DescBuffer[256]; \ - size_t nLimit = (size_t)gb.BitRead(12) + gb.GetPos(); \ - while (gb.GetPos() < nLimit) { \ - MPEG2_DESCRIPTOR nType = (MPEG2_DESCRIPTOR)gb.BitRead(8); \ - WORD nLength = (WORD)gb.BitRead(8); - -#define SkipDescriptor(gb, nType, nLength) \ - gb.ReadBuffer(DescBuffer, nLength); \ - BDA_LOG(_T("Skipped descriptor : 0x%02x"), nType); \ - UNREFERENCED_PARAMETER(nType); - -#define EndEnumDescriptors }} - -#define BeginEnumDescriptorsATSC(gb, nType, nLength, bits) \ -{ \ - BYTE DescBuffer[256]; \ - size_t nLimit = (size_t)gb.BitRead(bits) + gb.GetPos(); \ - while (gb.GetPos() < nLimit) { \ - MPEG2_DESCRIPTOR nType = (MPEG2_DESCRIPTOR)gb.BitRead(8); \ - WORD nLength = (WORD)gb.BitRead(8); - - -void UTF16BE2LE(BYTE* in, int len) { - for (int i = 0; i < len; i+=2) { - BYTE in0 = in[i]; - in[i] = in[i+1]; - in[i+1] = in0; - } - in[len] = 0; - in[len + 1] = 0; -} - -CMpeg2DataParser::CMpeg2DataParser(IBaseFilter* pFilter) -{ - m_pData = pFilter; - - ZeroMemory(&m_Filter, sizeof(m_Filter)); - m_Filter.bVersionNumber = 1; - m_Filter.wFilterSize = MPEG2_FILTER_VERSION_1_SIZE; - m_Filter.fSpecifySectionNumber = TRUE; -} - -CStringW CMpeg2DataParser::ConvertString(BYTE* pBuffer, size_t uLength) -{ - static const UINT16 codepages[0x20] = { - 20269, // 00 - Default ISO/IEC 6937 - 28595, // 01 - ISO 8859-5 Cyrillic - 28596, // 02 - ISO 8859-6 Arabic - 28597, // 03 - ISO 8859-7 Greek - 28598, // 04 - ISO 8859-8 Hebrew - 28599, // 05 - ISO 8859-9 Latin 5 - 28591, // 06 - ??? - ISO/IEC 8859-10 - Latin alphabet No. 6 - 28591, // 07 - ??? - ISO/IEC 8859-11 - Latin/Thai (draft only) - 28591, // 08 - reserved - 28603, // 09 - ISO 8859-13 - Estonian - 28591, // 0a - ??? - ISO/IEC 8859-14 - Latin alphabet No. 8 (Celtic) - 28605, // 0b - ISO 8859-15 Latin 9 - 28591, // 0c - reserved - 28591, // 0d - reserved - 28591, // 0e - reserved - 28591, // 0f - reserved - 0, // 10 - See codepages10 array - 28591, // 11 - ??? - ISO/IEC 10646 - Basic Multilingual Plane (BMP) - 28591, // 12 - ??? - KSX1001-2004 - Korean Character Set - 20936, // 13 - Chinese Simplified (GB2312-80) - 950, // 14 - Chinese Traditional (Big5) - 65001, // 15 - UTF-8 encoding of ISO/IEC 10646 - Basic Multilingual Plane (BMP) - 28591, // 16 - reserved - 28591, // 17 - reserved - 28591, // 18 - reserved - 28591, // 19 - reserved - 28591, // 1a - reserved - 28591, // 1b - reserved - 28591, // 1c - reserved - 28591, // 1d - reserved - 28591, // 1e - reserved - 28591 // 1f - TODO! - }; - - static const UINT16 codepages10[0x10] = { - 28591, // 00 - reserved - 28591, // 01 - ISO 8859-1 Western European - 28592, // 02 - ISO 8859-2 Central European - 28593, // 03 - ISO 8859-3 Latin 3 - 28594, // 04 - ISO 8859-4 Baltic - 28595, // 05 - ISO 8859-5 Cyrillic - 28596, // 06 - ISO 8859-6 Arabic - 28597, // 07 - ISO 8859-7 Greek - 28598, // 08 - ISO 8859-8 Hebrew - 28599, // 09 - ISO 8859-9 Turkish - 28591, // 0a - ??? - ISO/IEC 8859-10 - 28591, // 0b - ??? - ISO/IEC 8859-11 - 28591, // 0c - ??? - ISO/IEC 8859-12 - 28603, // 0d - ISO 8859-13 Estonian - 28591, // 0e - ??? - ISO/IEC 8859-14 - 28605, // 0f - ISO 8859-15 Latin 9 - - // 0x10 to 0xFF - reserved for future use - }; - - CStringW strResult; - if (uLength > 0) { - UINT cp = CP_ACP; - int nDestSize; - - if (pBuffer[0] == 0x10) { - pBuffer++; - uLength--; - if (pBuffer[0] == 0x00) { - cp = codepages10[pBuffer[1]]; - } else { // if (pBuffer[0] > 0x00) - // reserved for future use, use default codepage - cp = codepages[0]; - } - pBuffer += 2; - uLength -= 2; - } else if (pBuffer[0] < 0x20) { - cp = codepages[pBuffer[0]]; - pBuffer++; - uLength--; - } else { // No code page indication, use the default - cp = codepages[0]; - } - - // Work around a bug in MS MultiByteToWideChar with ISO/IEC 6937 and take care of the Euro symbol special case (step 1/2)... - CArray euroSymbolPos; - if (cp == 20269) { - BYTE tmp; - for (size_t i = 0; i < uLength - 1; i++) { - if (pBuffer[i] >= 0xC1 && pBuffer[i] <= 0xCF && pBuffer[i] != 0xC9 && pBuffer[i] != 0xCC) { - // Swap the current char with the next one - tmp = pBuffer[i]; - pBuffer[i] = pBuffer[i + 1]; - pBuffer[++i] = tmp; - } else if (pBuffer[i] == 0xA4) { // was added as 0xA4 in the DVB spec - euroSymbolPos.Add(i); - } - } - // Handle last symbol if it's a - if (pBuffer[uLength - 1] == 0xA4) { - euroSymbolPos.Add(uLength - 1); - } - } - - nDestSize = MultiByteToWideChar(cp, MB_PRECOMPOSED, (LPCSTR)pBuffer, (int)uLength, nullptr, 0); - if (nDestSize > 0) { - LPWSTR strResultBuff = strResult.GetBuffer(nDestSize); - MultiByteToWideChar(cp, MB_PRECOMPOSED, (LPCSTR)pBuffer, (int)uLength, strResultBuff, nDestSize); - - // Work around a bug in MS MultiByteToWideChar with ISO/IEC 6937 and take care of the Euro symbol special case (step 2/2)... - if (cp == 20269) { - for (size_t i = 0, len = (size_t)nDestSize; i < len; i++) { - switch (strResultBuff[i]) { - case 0x60: // grave accent - strResultBuff[i] = 0x0300; - break; - case 0xb4: // acute accent - strResultBuff[i] = 0x0301; - break; - case 0x5e: // circumflex accent - strResultBuff[i] = 0x0302; - break; - case 0x7e: // tilde - strResultBuff[i] = 0x0303; - break; - case 0xaf: // macron - strResultBuff[i] = 0x0304; - break; - case 0xf8f8: // dot - strResultBuff[i] = 0x0307; - break; - } - } - - for (INT_PTR i = 0, len = euroSymbolPos.GetCount(); i < len; i++) { - strResultBuff[euroSymbolPos[i]] = _T(''); - } - } - - // Some strings seems to be null-terminated, we need to take that into account. - while (nDestSize > 0 && strResultBuff[nDestSize - 1] == L'\0') { - nDestSize--; - } - - strResult.ReleaseBuffer(nDestSize); - } - } - - return strResult; -} - -BDA_STREAM_TYPE CMpeg2DataParser::ConvertToDVBType(PES_STREAM_TYPE nType) -{ - switch (nType) { - case VIDEO_STREAM_MPEG1: - case VIDEO_STREAM_MPEG2: - return BDA_MPV; - case AUDIO_STREAM_MPEG1: - case AUDIO_STREAM_MPEG2: - return BDA_MPA; - case VIDEO_STREAM_H264: - return BDA_H264; - case VIDEO_STREAM_HEVC: - return BDA_HEVC; - case AUDIO_STREAM_AC3: - return BDA_AC3; - case AUDIO_STREAM_AC3_PLUS: - return BDA_EAC3; - case AUDIO_STREAM_AAC: - return BDA_ADTS; - case AUDIO_STREAM_AAC_LATM: - return BDA_LATM; - case SUBTITLE_STREAM: - return BDA_SUBTITLE; - } - - return BDA_UNKNOWN; -} - -HRESULT CMpeg2DataParser::ParseSIHeader(CGolombBuffer& gb, DVB_SI SIType, WORD& wSectionLength, WORD& wTSID) -{ - if (gb.BitRead(8) != SIType) { - return ERROR_INVALID_DATA; // table_id - } - gb.BitRead(1); // section_syntax_indicator - gb.BitRead(1); // reserved_future_use - gb.BitRead(2); // reserved - wSectionLength = (WORD)gb.BitRead(12); // section_length - wTSID = (WORD)gb.BitRead(16); // transport_stream_id - gb.BitRead(2); // reserved - gb.BitRead(5); // version_number - gb.BitRead(1); // current_next_indicator - gb.BitRead(8); // section_number - gb.BitRead(8); // last_section_number - - return S_OK; -} - -HRESULT CMpeg2DataParser::ParseSDT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) -{ - HRESULT hr; - CComPtr pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wONID; - WORD wSectionLength; - WORD serviceType = 0; - - CheckNoLog(m_pData->GetSection(PID_SDT, SI_SDT, &m_Filter, 15000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - // service_description_section() - CheckNoLog(ParseSIHeader(gb, SI_SDT, wSectionLength, wTSID)); - - wONID = (WORD)gb.BitRead(16); // original_network_id - gb.BitRead(8); // reserved_future_use - - while (gb.GetSize() - gb.GetPos() > 4) { - CBDAChannel Channel; - Channel.SetFrequency(ulFrequency); - Channel.SetBandwidth(ulBandwidth); - Channel.SetSymbolRate(ulSymbolRate); - Channel.SetTSID(wTSID); - Channel.SetONID(wONID); - Channel.SetSID((ULONG)gb.BitRead(16)); // service_id uimsbf - gb.BitRead(6); // reserved_future_use bslbf - gb.BitRead(1); // EIT_schedule_flag bslbf - Channel.SetNowNextFlag(!!gb.BitRead(1)); // EIT_present_following_flag bslbf - gb.BitRead(3); // running_status uimsbf - Channel.SetEncrypted(!!gb.BitRead(1)); // free_CA_mode bslbf - - // Descriptors: - BeginEnumDescriptors(gb, nType, nLength) { - switch (nType) { - case DT_SERVICE: - serviceType = (WORD)gb.BitRead(8); // service_type - nLength = (WORD)gb.BitRead(8); // service_provider_name_length - gb.ReadBuffer(DescBuffer, nLength); // service_provider_name - - nLength = (WORD)gb.BitRead(8); // service_name_length - gb.ReadBuffer(DescBuffer, nLength); // service_name - DescBuffer[nLength] = 0; - Channel.SetName(ConvertString(DescBuffer, nLength)); - BDA_LOG(_T("%-20s %lu"), Channel.GetName(), Channel.GetSID()); - break; - default: - SkipDescriptor(gb, nType, nLength); // descriptor() - break; - } - } - EndEnumDescriptors; - - - if (!Channels.Lookup(Channel.GetSID())) { - switch (serviceType) { - case DIGITAL_TV: - case DIGITAL_RADIO: - case AVC_DIGITAL_RADIO: - case MPEG2_HD_DIGITAL_TV: - case AVC_SD_TV: - case AVC_HD_TV: - case HEVC_TV: - Channels[Channel.GetSID()] = Channel; - break; - default: - BDA_LOG(_T("DVB: Skipping not supported service: %-20s %lu"), Channel.GetName(), Channel.GetSID()); - break; - } - } - } - - return S_OK; -} - -//supports Master Guide Table; see ATSC A/65:2013 -HRESULT CMpeg2DataParser::ParseMGT(enum DVB_SI &vctType) -{ - vctType = SI_undef; - HRESULT hr; - CComPtr pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - - hr = m_pData->GetSection(PID_PSIP, TID_MGT, &m_Filter, 15000, &pSectionList); - CheckNoLog(hr); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - CheckNoLog(ParseSIHeader(gb, TID_MGT, wSectionLength, wTSID)); - gb.BitRead(8); - uint16_t num_tables = gb.BitRead(16); - - for (uint8_t i = 0; i < num_tables; i++) { - uint16_t table_type = gb.BitRead(16); //table_type - - gb.BitRead(3); //reserved - uint16_t table_type_PID = gb.BitRead(13); //table_type_PID - if (table_type_PID == PID_PSIP) { //expect to find TVCT table with PID_PSIP id - if (table_type == TT_TVCT_C0 || table_type == TT_TVCT_C1) { - vctType = (DVB_SI)TID_TVCT; - } else if (table_type == TT_CVCT_C0 || table_type == TT_CVCT_C1) { - vctType = (DVB_SI)TID_CVCT; - } - } - gb.BitRead(3); //reserved - gb.BitRead(5); //table_type_version_number - gb.BitRead(32); //number_bytes - gb.BitRead(4); //reserved - - BeginEnumDescriptorsATSC(gb, nType, nLength, 12) { // for (i=0;i pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - WORD serviceType = 0; - - hr = m_pData->GetSection(PID_PSIP, vctType, &m_Filter, 15000, &pSectionList); - CheckNoLog(hr); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - CheckNoLog(ParseSIHeader(gb, vctType, wSectionLength, wTSID)); - gb.BitRead(8); //protocol_version - uint8_t num_channels = gb.BitRead(8); - - const int SHORT_NAME_LEN = 7*2; - BYTE short_name[SHORT_NAME_LEN+2]; - - for (uint8_t i = 0; i < num_channels; i++) { - gb.ReadBuffer(short_name, SHORT_NAME_LEN); //short_name - UTF16BE2LE(short_name, SHORT_NAME_LEN); - CStringW shortName((wchar_t*)short_name); - gb.BitRead(4); //reserved - uint16_t major_channel_number = gb.BitRead(10); //major_channel_number - uint16_t minor_channel_number = gb.BitRead(10); //minor_channel_number - gb.BitRead(8); //modulation_mode - gb.BitRead(32); //carrier_frequency - uint16_t channel_TSID=gb.BitRead(16); //channel_TSID - uint16_t program_number=gb.BitRead(16); //program_number - gb.BitRead(2); //ETM_location - gb.BitRead(1); //access_controlled - gb.BitRead(1); //hidden - gb.BitRead(2); //TVCT: reserved(1), CVCT: path_select(1) / out_of_band(1) - gb.BitRead(1); //hide_guide - gb.BitRead(3); //reserved - serviceType = gb.BitRead(6); //service_type - uint16_t source_id=gb.BitRead(16); //source_id - gb.BitRead(6); //reserved - BeginEnumDescriptorsATSC(gb, nType, nLength, 10) { // for (i=0;i pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - - CheckNoLog(m_pData->GetSection(PID_PAT, SI_PAT, &m_Filter, 15000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - // program_association_section() - CheckNoLog(ParseSIHeader(gb, SI_PAT, wSectionLength, wTSID)); - while (gb.GetSize() - gb.GetPos() > 4) { - WORD program_number = (WORD)gb.BitRead(16); // program_number - gb.BitRead(3); // reserved - if (program_number == 0) { - gb.BitRead(13); // network_PID - } else { - WORD program_map_PID = (WORD)gb.BitRead(13); // program_map_PID - if (Channels.Lookup(program_number)) { - Channels [program_number].SetPMT(program_map_PID); - ParsePMT(Channels [program_number]); - } - } - } - - return S_OK; -} - -HRESULT CMpeg2DataParser::ParsePMT(CBDAChannel& Channel) -{ - HRESULT hr; - CComPtr pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - - Channel.SetVideoFps(BDA_FPS_NONE); - Channel.SetVideoChroma(BDA_Chroma_NONE); - - CheckNoLog(m_pData->GetSection((PID)Channel.GetPMT(), SI_PMT, &m_Filter, 15000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - // TS_program_map_section() - CheckNoLog(ParseSIHeader(gb, SI_PMT, wSectionLength, wTSID)); - - gb.BitRead(3); // reserved - Channel.SetPCR((ULONG)gb.BitRead(13)); // PCR_PID - gb.BitRead(4); // reserved - BeginEnumDescriptors(gb, nType, nLength) { // for (i=0;i 4) { - PES_STREAM_TYPE pes_stream_type; - BDA_STREAM_TYPE dvb_stream_type; - WORD wPID; - CString strLanguage; - - pes_stream_type = (PES_STREAM_TYPE)gb.BitRead(8); // stream_type - gb.BitRead(3); // reserved - wPID = (WORD)gb.BitRead(13); // elementary_PID - gb.BitRead(4); // reserved - - BeginEnumDescriptors(gb, nType, nLength) { // ES_info_length - switch (nType) { - case DT_ISO_639_LANGUAGE: - gb.ReadBuffer(DescBuffer, nLength); - strLanguage = ConvertString(DescBuffer, 3); - break; - case DT_AC3_AUDIO: - pes_stream_type = AUDIO_STREAM_AC3; - SkipDescriptor(gb, nType, nLength); - break; - case DT_EXTENDED_AC3_AUDIO: - pes_stream_type = AUDIO_STREAM_AC3_PLUS; - SkipDescriptor(gb, nType, nLength); - break; - case DT_AAC_AUDIO: - pes_stream_type = AUDIO_STREAM_AAC_LATM; - SkipDescriptor(gb, nType, nLength); - break; - case DT_SUBTITLING: - gb.ReadBuffer(DescBuffer, nLength); - strLanguage = ConvertString(DescBuffer, 3); - pes_stream_type = SUBTITLE_STREAM; - break; - case DT_VIDEO_STREAM: { - gb.BitRead(1); // multiple_frame_rate_flag - Channel.SetVideoFps((BDA_FPS_TYPE) gb.BitRead(4)); - UINT MPEG_1_only_flag = (UINT) gb.BitRead(1); - gb.BitRead(1); // constrained_parameter_flag - gb.BitRead(1); // still_picture_flag - if (!MPEG_1_only_flag) { - gb.BitRead(8); // profile_and_level_indicator - Channel.SetVideoChroma((BDA_CHROMA_TYPE) gb.BitRead(2)); - gb.BitRead(1); // frame_rate_extension_flag - gb.BitRead(5); // Reserved - } - } - break; - case DT_TARGET_BACKGROUND_GRID: - Channel.SetVideoWidth((ULONG) gb.BitRead(14)); - Channel.SetVideoHeight((ULONG) gb.BitRead(14)); - Channel.SetVideoAR((BDA_AspectRatio_TYPE) gb.BitRead(4)); - break; - default: - SkipDescriptor(gb, nType, nLength); - break; - } - } - EndEnumDescriptors; - if ((dvb_stream_type = ConvertToDVBType(pes_stream_type)) != BDA_UNKNOWN) { - Channel.AddStreamInfo(wPID, dvb_stream_type, pes_stream_type, strLanguage); - } - } - if ((Channel.GetVideoType() == BDA_MPV) && (Channel.GetVideoPID())) { - if (Channel.GetVideoFps() == BDA_FPS_NONE) { - Channel.SetVideoFps(BDA_FPS_25_0); - } - if ((Channel.GetVideoWidth() == 0) && (Channel.GetVideoHeight() == 0)) { - Channel.SetVideoWidth(720); - Channel.SetVideoHeight(576); - } - } else if ((Channel.GetVideoType() == BDA_H264 || Channel.GetVideoType() == BDA_HEVC) && (Channel.GetVideoPID())) { - if (Channel.GetVideoFps() == BDA_FPS_NONE) { - Channel.SetVideoFps(BDA_FPS_25_0); - } - } - - - return S_OK; -} - -HRESULT CMpeg2DataParser::SetTime(CGolombBuffer& gb, EventDescriptor& NowNext) -{ - wchar_t descBuffer[6]; - time_t tNow, tTime; - tm tmTime; - long timezone; - - // init tm structures - time(&tNow); - gmtime_s(&tmTime, &tNow); - _tzset(); - _get_timezone(&timezone); // The difference in seconds between UTC and local time. - - // Start time: - tmTime.tm_hour = (int)(gb.BitRead(4) * 10); - tmTime.tm_hour += (int)gb.BitRead(4); - tmTime.tm_min = (int)(gb.BitRead(4) * 10); - tmTime.tm_min += (int)gb.BitRead(4); - tmTime.tm_sec = (int)(gb.BitRead(4) * 10); - tmTime.tm_sec += (int)gb.BitRead(4); - // Convert to time_t - // mktime() expect tm struct to be local time and since we are feeding it with GMT - // we need to compensate for timezone offset. Note that we don't compensate for DST. - // That is because tm_isdst is set to 0 (GMT) and in this case mktime() won't add any offset. - NowNext.startTime = tTime = mktime(&tmTime) - timezone; - while (tNow < tTime) { - // If current time is less than even start time it is likely that event started the day before. - // We go one day back - NowNext.startTime = tTime -= 86400; - } - - localtime_s(&tmTime, &tTime); - wcsftime(descBuffer, 6, L"%H:%M", &tmTime); - descBuffer[5] = '\0'; - NowNext.strStartTime = descBuffer; - - // Duration: - NowNext.duration = (time_t)(36000 * gb.BitRead(4)); - NowNext.duration += (time_t)(3600 * gb.BitRead(4)); - NowNext.duration += (time_t)(600 * gb.BitRead(4)); - NowNext.duration += (time_t)(60 * gb.BitRead(4)); - NowNext.duration += (time_t)(10 * gb.BitRead(4)); - NowNext.duration += (time_t)gb.BitRead(4); - - tTime += NowNext.duration; - localtime_s(&tmTime, &tTime); - wcsftime(descBuffer, 6, L"%H:%M", &tmTime); - descBuffer[5] = '\0'; - NowNext.strEndTime = descBuffer; - - return S_OK; -} - -HRESULT CMpeg2DataParser::ParseEIT(ULONG ulSID, EventDescriptor& NowNext) -{ - HRESULT hr = S_OK; - DWORD dwLength; - PSECTION data; - ULONG ulGetSID; - EventInformationSection InfoEvent; - NowNext = EventDescriptor(); - - do { - CComPtr pSectionList; - CheckNoLog(m_pData->GetSection(PID_EIT, SI_EIT_act, nullptr, 5000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - InfoEvent.TableID = (UINT8)gb.BitRead(8); - InfoEvent.SectionSyntaxIndicator = (WORD)gb.BitRead(1); - gb.BitRead(3); - InfoEvent.SectionLength = (WORD)gb.BitRead(12); - ulGetSID = (ULONG)gb.BitRead(8); - ulGetSID += 0x100 * (ULONG)gb.BitRead(8); - InfoEvent.ServiceId = ulGetSID; // This is really strange, ServiceID should be uimsbf ??? - if (InfoEvent.ServiceId == ulSID) { - gb.BitRead(2); - InfoEvent.VersionNumber = (UINT8)gb.BitRead(5); - InfoEvent.CurrentNextIndicator = (UINT8)gb.BitRead(1); - if (InfoEvent.CurrentNextIndicator == 1) { - InfoEvent.SectionNumber = (UINT8)gb.BitRead(8); - InfoEvent.LastSectionNumber = (UINT8)gb.BitRead(8); - InfoEvent.TransportStreamID = (WORD)gb.BitRead(16); - InfoEvent.OriginalNetworkID = (WORD)gb.BitRead(16); - InfoEvent.SegmentLastSectionNumber = (UINT8)gb.BitRead(8); - InfoEvent.LastTableID = (UINT8)gb.BitRead(8); - - // Info event - InfoEvent.EventID = (WORD)gb.BitRead(16); - InfoEvent.StartDate = (WORD)gb.BitRead(16); - SetTime(gb, NowNext); - - InfoEvent.RunninStatus = (WORD)gb.BitRead(3); - InfoEvent.FreeCAMode = (WORD)gb.BitRead(1); - if (InfoEvent.RunninStatus == 4) { - UINT8 nLen; - UINT8 itemsLength; - - // Descriptors: - BeginEnumDescriptors(gb, nType, nLength) { - switch (nType) { - case DT_SHORT_EVENT: - gb.BitRead(24); // ISO_639_language_code - - nLen = (UINT8)gb.BitRead(8); // event_name_length - gb.ReadBuffer(DescBuffer, nLen); - if (IsFreeviewEPG(InfoEvent.OriginalNetworkID, DescBuffer, nLen)) { - NowNext.eventName = DecodeFreeviewEPG(DescBuffer, nLen); - } else { - NowNext.eventName = ConvertString(DescBuffer, nLen); - } - - nLen = (UINT8)gb.BitRead(8); // text_length - gb.ReadBuffer(DescBuffer, nLen); - if (IsFreeviewEPG(InfoEvent.OriginalNetworkID, DescBuffer, nLen)) { - NowNext.eventDesc = DecodeFreeviewEPG(DescBuffer, nLen); - } else { - NowNext.eventDesc = ConvertString(DescBuffer, nLen); - } - break; - case DT_EXTENDED_EVENT: - gb.BitRead(4); // descriptor_number - gb.BitRead(4); // last_descriptor_number - gb.BitRead(24); // ISO_639_language_code - - itemsLength = (UINT8)gb.BitRead(8); // length_of_items - while (itemsLength > 0) { - nLen = (UINT8)gb.BitRead(8); // item_description_length - gb.ReadBuffer(DescBuffer, nLen); - CString itemDesc = ConvertString(DescBuffer, nLen); - itemsLength -= nLen + 1; - - nLen = (UINT8)gb.BitRead(8); // item_length - gb.ReadBuffer(DescBuffer, nLen); - CString itemText = ConvertString(DescBuffer, nLen); - itemsLength -= nLen + 1; - NowNext.extendedDescriptorsItems.emplace_back(itemDesc, itemText); - } - - nLen = (UINT8)gb.BitRead(8); // text_length - if (nLen > 0) { - gb.ReadBuffer(DescBuffer, nLen); - NowNext.extendedDescriptorsText += ConvertString(DescBuffer, nLen); - } - break; - case DT_PARENTAL_RATING: { - ASSERT(nLength % 4 == 0); - int rating = -1; - while (nLength >= 4) { - gb.BitRead(24); // ISO 3166 country_code - rating = (int)gb.BitRead(8); // rating - nLength -= 4; - } - if (rating >= 0 && rating <= 0x0f) { - if (rating > 0) { // 0x00 undefined - rating += 3; // 0x01 to 0x0F minimum age = rating + 3 years - } - NowNext.parentalRating = rating; - } - } - break; - case DT_CONTENT: - ASSERT(nLength % 2 == 0); - while (nLength >= 2) { - BYTE content = (BYTE)gb.BitRead(4); // content_nibble_level_1 - gb.BitRead(4); // content_nibble_level_2 - gb.BitRead(8); // user_byte - if (1 <= content && content <= 10) { - if (!NowNext.content.IsEmpty()) { - NowNext.content.Append(_T(", ")); - } - - static UINT contents[] = { - IDS_CONTENT_MOVIE_DRAMA, - IDS_CONTENT_NEWS_CURRENTAFFAIRS, - IDS_CONTENT_SHOW_GAMESHOW, - IDS_CONTENT_SPORTS, - IDS_CONTENT_CHILDREN_YOUTH_PROG, - IDS_CONTENT_MUSIC_BALLET_DANCE, - IDS_CONTENT_MUSIC_ART_CULTURE, - IDS_CONTENT_SOCIAL_POLITICAL_ECO, - IDS_CONTENT_EDUCATION_SCIENCE, - IDS_CONTENT_LEISURE - }; - - NowNext.content.AppendFormat(contents[content - 1]); - } - nLength -= 2; - } - break; - default: - SkipDescriptor(gb, nType, nLength); - break; - } - } - EndEnumDescriptors; - } - } - } - m_Filter.SectionNumber++; - } while ((InfoEvent.ServiceId != ulSID || InfoEvent.RunninStatus != 4) && m_Filter.SectionNumber <= 22); - - if (m_Filter.SectionNumber > 22 || InfoEvent.CurrentNextIndicator != 1) { - NowNext = EventDescriptor(); - hr = E_FAIL; - } - - return hr; -} - -HRESULT CMpeg2DataParser::ParseNIT() -{ - HRESULT hr; - CComPtr pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - - CheckNoLog(m_pData->GetSection(PID_NIT, SI_NIT, &m_Filter, 15000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - // network_information_section() - CheckNoLog(ParseSIHeader(gb, SI_NIT, wSectionLength, wTSID)); - - gb.BitRead(4); // reserved_future_use - BeginEnumDescriptors(gb, nType, nLength) { // for (i=0;i 4) { - WORD transport_stream_id = (WORD)gb.BitRead(16); // transport_stream_id - UNREFERENCED_PARAMETER(transport_stream_id); - WORD original_network_id = (WORD)gb.BitRead(16); // original_network_id - UNREFERENCED_PARAMETER(original_network_id); - gb.BitRead(4); // reserved_future_use - BeginEnumDescriptors(gb, nType, nLength) { - switch (nType) { - case DT_LOGICAL_CHANNEL: - for (int i = 0; i < nLength / 4; i++) { - WORD service_id = (WORD)gb.BitRead(16); - gb.BitRead(6); - WORD logical_channel_number = (WORD)gb.BitRead(10); - if (Channels.Lookup(service_id)) { - Channels[service_id].SetOriginNumber(logical_channel_number); - BDA_LOG(_T("NIT association : %d -> %s"), logical_channel_number, Channels[service_id].ToString().GetString()); - } - } - break; - default: - SkipDescriptor(gb, nType, nLength); - break; - } - } - EndEnumDescriptors; - } - - return S_OK; -} +/* + * (C) 2009-2017 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 . + * + */ + +#include "stdafx.h" +#include "BaseClasses/streams.h" +#include + +#include "GolombBuffer.h" +#include "Mpeg2SectionData.h" +#include "FreeviewEPGDecode.h" +#include "resource.h" +#include "Logger.h" + +#define BeginEnumDescriptors(gb, nType, nLength) \ +{ \ + BYTE DescBuffer[256]; \ + size_t nLimit = (size_t)gb.BitRead(12) + gb.GetPos(); \ + while (gb.GetPos() < nLimit) { \ + MPEG2_DESCRIPTOR nType = (MPEG2_DESCRIPTOR)gb.BitRead(8); \ + WORD nLength = (WORD)gb.BitRead(8); + +#define SkipDescriptor(gb, nType, nLength) \ + gb.ReadBuffer(DescBuffer, nLength); \ + BDA_LOG(_T("Skipped descriptor : 0x%02x"), nType); \ + UNREFERENCED_PARAMETER(nType); + +#define EndEnumDescriptors }} + +#define BeginEnumDescriptorsATSC(gb, nType, nLength, bits) \ +{ \ + BYTE DescBuffer[256]; \ + size_t nLimit = (size_t)gb.BitRead(bits) + gb.GetPos(); \ + while (gb.GetPos() < nLimit) { \ + MPEG2_DESCRIPTOR nType = (MPEG2_DESCRIPTOR)gb.BitRead(8); \ + WORD nLength = (WORD)gb.BitRead(8); + + +void UTF16BE2LE(BYTE* in, int len) { + for (int i = 0; i < len; i+=2) { + BYTE in0 = in[i]; + in[i] = in[i+1]; + in[i+1] = in0; + } + in[len] = 0; + in[len + 1] = 0; +} + +CMpeg2DataParser::CMpeg2DataParser(IBaseFilter* pFilter) +{ + m_pData = pFilter; + + ZeroMemory(&m_Filter, sizeof(m_Filter)); + m_Filter.bVersionNumber = 1; + m_Filter.wFilterSize = MPEG2_FILTER_VERSION_1_SIZE; + m_Filter.fSpecifySectionNumber = TRUE; +} + +CStringW CMpeg2DataParser::ConvertString(BYTE* pBuffer, size_t uLength) +{ + static const UINT16 codepages[0x20] = { + 20269, // 00 - Default ISO/IEC 6937 + 28595, // 01 - ISO 8859-5 Cyrillic + 28596, // 02 - ISO 8859-6 Arabic + 28597, // 03 - ISO 8859-7 Greek + 28598, // 04 - ISO 8859-8 Hebrew + 28599, // 05 - ISO 8859-9 Latin 5 + 28591, // 06 - ??? - ISO/IEC 8859-10 - Latin alphabet No. 6 + 28591, // 07 - ??? - ISO/IEC 8859-11 - Latin/Thai (draft only) + 28591, // 08 - reserved + 28603, // 09 - ISO 8859-13 - Estonian + 28591, // 0a - ??? - ISO/IEC 8859-14 - Latin alphabet No. 8 (Celtic) + 28605, // 0b - ISO 8859-15 Latin 9 + 28591, // 0c - reserved + 28591, // 0d - reserved + 28591, // 0e - reserved + 28591, // 0f - reserved + 0, // 10 - See codepages10 array + 28591, // 11 - ??? - ISO/IEC 10646 - Basic Multilingual Plane (BMP) + 28591, // 12 - ??? - KSX1001-2004 - Korean Character Set + 20936, // 13 - Chinese Simplified (GB2312-80) + 950, // 14 - Chinese Traditional (Big5) + 65001, // 15 - UTF-8 encoding of ISO/IEC 10646 - Basic Multilingual Plane (BMP) + 28591, // 16 - reserved + 28591, // 17 - reserved + 28591, // 18 - reserved + 28591, // 19 - reserved + 28591, // 1a - reserved + 28591, // 1b - reserved + 28591, // 1c - reserved + 28591, // 1d - reserved + 28591, // 1e - reserved + 28591 // 1f - TODO! + }; + + static const UINT16 codepages10[0x10] = { + 28591, // 00 - reserved + 28591, // 01 - ISO 8859-1 Western European + 28592, // 02 - ISO 8859-2 Central European + 28593, // 03 - ISO 8859-3 Latin 3 + 28594, // 04 - ISO 8859-4 Baltic + 28595, // 05 - ISO 8859-5 Cyrillic + 28596, // 06 - ISO 8859-6 Arabic + 28597, // 07 - ISO 8859-7 Greek + 28598, // 08 - ISO 8859-8 Hebrew + 28599, // 09 - ISO 8859-9 Turkish + 28591, // 0a - ??? - ISO/IEC 8859-10 + 28591, // 0b - ??? - ISO/IEC 8859-11 + 28591, // 0c - ??? - ISO/IEC 8859-12 + 28603, // 0d - ISO 8859-13 Estonian + 28591, // 0e - ??? - ISO/IEC 8859-14 + 28605, // 0f - ISO 8859-15 Latin 9 + + // 0x10 to 0xFF - reserved for future use + }; + + CStringW strResult; + if (uLength > 0) { + UINT cp = CP_ACP; + int nDestSize; + + if (pBuffer[0] == 0x10) { + pBuffer++; + uLength--; + if (pBuffer[0] == 0x00) { + cp = codepages10[pBuffer[1]]; + } else { // if (pBuffer[0] > 0x00) + // reserved for future use, use default codepage + cp = codepages[0]; + } + pBuffer += 2; + uLength -= 2; + } else if (pBuffer[0] < 0x20) { + cp = codepages[pBuffer[0]]; + pBuffer++; + uLength--; + } else { // No code page indication, use the default + cp = codepages[0]; + } + + // Work around a bug in MS MultiByteToWideChar with ISO/IEC 6937 and take care of the Euro symbol special case (step 1/2)... + CArray euroSymbolPos; + if (cp == 20269) { + BYTE tmp; + for (size_t i = 0; i < uLength - 1; i++) { + if (pBuffer[i] >= 0xC1 && pBuffer[i] <= 0xCF && pBuffer[i] != 0xC9 && pBuffer[i] != 0xCC) { + // Swap the current char with the next one + tmp = pBuffer[i]; + pBuffer[i] = pBuffer[i + 1]; + pBuffer[++i] = tmp; + } else if (pBuffer[i] == 0xA4) { // was added as 0xA4 in the DVB spec + euroSymbolPos.Add(i); + } + } + // Handle last symbol if it's a + if (pBuffer[uLength - 1] == 0xA4) { + euroSymbolPos.Add(uLength - 1); + } + } + + nDestSize = MultiByteToWideChar(cp, MB_PRECOMPOSED, (LPCSTR)pBuffer, (int)uLength, nullptr, 0); + if (nDestSize > 0) { + LPWSTR strResultBuff = strResult.GetBuffer(nDestSize); + MultiByteToWideChar(cp, MB_PRECOMPOSED, (LPCSTR)pBuffer, (int)uLength, strResultBuff, nDestSize); + + // Work around a bug in MS MultiByteToWideChar with ISO/IEC 6937 and take care of the Euro symbol special case (step 2/2)... + if (cp == 20269) { + for (size_t i = 0, len = (size_t)nDestSize; i < len; i++) { + switch (strResultBuff[i]) { + case 0x60: // grave accent + strResultBuff[i] = 0x0300; + break; + case 0xb4: // acute accent + strResultBuff[i] = 0x0301; + break; + case 0x5e: // circumflex accent + strResultBuff[i] = 0x0302; + break; + case 0x7e: // tilde + strResultBuff[i] = 0x0303; + break; + case 0xaf: // macron + strResultBuff[i] = 0x0304; + break; + case 0xf8f8: // dot + strResultBuff[i] = 0x0307; + break; + } + } + + for (INT_PTR i = 0, len = euroSymbolPos.GetCount(); i < len; i++) { + strResultBuff[euroSymbolPos[i]] = _T(''); + } + } + + // Some strings seems to be null-terminated, we need to take that into account. + while (nDestSize > 0 && strResultBuff[nDestSize - 1] == L'\0') { + nDestSize--; + } + + strResult.ReleaseBuffer(nDestSize); + } + } + + return strResult; +} + +BDA_STREAM_TYPE CMpeg2DataParser::ConvertToDVBType(PES_STREAM_TYPE nType) +{ + switch (nType) { + case VIDEO_STREAM_MPEG1: + case VIDEO_STREAM_MPEG2: + return BDA_MPV; + case AUDIO_STREAM_MPEG1: + case AUDIO_STREAM_MPEG2: + return BDA_MPA; + case VIDEO_STREAM_H264: + return BDA_H264; + case VIDEO_STREAM_HEVC: + return BDA_HEVC; + case AUDIO_STREAM_AC3: + return BDA_AC3; + case AUDIO_STREAM_AC3_PLUS: + return BDA_EAC3; + case AUDIO_STREAM_AAC: + return BDA_ADTS; + case AUDIO_STREAM_AAC_LATM: + return BDA_LATM; + case SUBTITLE_STREAM: + return BDA_SUBTITLE; + } + + return BDA_UNKNOWN; +} + +HRESULT CMpeg2DataParser::ParseSIHeader(CGolombBuffer& gb, DVB_SI SIType, WORD& wSectionLength, WORD& wTSID) +{ + if (gb.BitRead(8) != SIType) { + return ERROR_INVALID_DATA; // table_id + } + gb.BitRead(1); // section_syntax_indicator + gb.BitRead(1); // reserved_future_use + gb.BitRead(2); // reserved + wSectionLength = (WORD)gb.BitRead(12); // section_length + wTSID = (WORD)gb.BitRead(16); // transport_stream_id + gb.BitRead(2); // reserved + gb.BitRead(5); // version_number + gb.BitRead(1); // current_next_indicator + gb.BitRead(8); // section_number + gb.BitRead(8); // last_section_number + + return S_OK; +} + +HRESULT CMpeg2DataParser::ParseSDT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) +{ + HRESULT hr; + CComPtr pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wONID; + WORD wSectionLength; + WORD serviceType = 0; + + CheckNoLog(m_pData->GetSection(PID_SDT, SI_SDT, &m_Filter, 15000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + // service_description_section() + CheckNoLog(ParseSIHeader(gb, SI_SDT, wSectionLength, wTSID)); + + wONID = (WORD)gb.BitRead(16); // original_network_id + gb.BitRead(8); // reserved_future_use + + while (gb.GetSize() - gb.GetPos() > 4) { + CBDAChannel Channel; + Channel.SetFrequency(ulFrequency); + Channel.SetBandwidth(ulBandwidth); + Channel.SetSymbolRate(ulSymbolRate); + Channel.SetTSID(wTSID); + Channel.SetONID(wONID); + Channel.SetSID((ULONG)gb.BitRead(16)); // service_id uimsbf + gb.BitRead(6); // reserved_future_use bslbf + gb.BitRead(1); // EIT_schedule_flag bslbf + Channel.SetNowNextFlag(!!gb.BitRead(1)); // EIT_present_following_flag bslbf + gb.BitRead(3); // running_status uimsbf + Channel.SetEncrypted(!!gb.BitRead(1)); // free_CA_mode bslbf + + // Descriptors: + BeginEnumDescriptors(gb, nType, nLength) { + switch (nType) { + case DT_SERVICE: + serviceType = (WORD)gb.BitRead(8); // service_type + nLength = (WORD)gb.BitRead(8); // service_provider_name_length + gb.ReadBuffer(DescBuffer, nLength); // service_provider_name + + nLength = (WORD)gb.BitRead(8); // service_name_length + gb.ReadBuffer(DescBuffer, nLength); // service_name + DescBuffer[nLength] = 0; + Channel.SetName(ConvertString(DescBuffer, nLength)); + BDA_LOG(_T("%-20s %lu"), Channel.GetName(), Channel.GetSID()); + break; + default: + SkipDescriptor(gb, nType, nLength); // descriptor() + break; + } + } + EndEnumDescriptors; + + + if (!Channels.Lookup(Channel.GetSID())) { + switch (serviceType) { + case DIGITAL_TV: + case DIGITAL_RADIO: + case AVC_DIGITAL_RADIO: + case MPEG2_HD_DIGITAL_TV: + case AVC_SD_TV: + case AVC_HD_TV: + case HEVC_TV: + Channels[Channel.GetSID()] = Channel; + break; + default: + BDA_LOG(_T("DVB: Skipping not supported service: %-20s %lu"), Channel.GetName(), Channel.GetSID()); + break; + } + } + } + + return S_OK; +} + +//supports Master Guide Table; see ATSC A/65:2013 +HRESULT CMpeg2DataParser::ParseMGT(enum DVB_SI &vctType) +{ + vctType = SI_undef; + HRESULT hr; + CComPtr pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + + hr = m_pData->GetSection(PID_PSIP, TID_MGT, &m_Filter, 15000, &pSectionList); + CheckNoLog(hr); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + CheckNoLog(ParseSIHeader(gb, TID_MGT, wSectionLength, wTSID)); + gb.BitRead(8); + uint16_t num_tables = gb.BitRead(16); + + for (uint8_t i = 0; i < num_tables; i++) { + uint16_t table_type = gb.BitRead(16); //table_type + + gb.BitRead(3); //reserved + uint16_t table_type_PID = gb.BitRead(13); //table_type_PID + if (table_type_PID == PID_PSIP) { //expect to find TVCT table with PID_PSIP id + if (table_type == TT_TVCT_C0 || table_type == TT_TVCT_C1) { + vctType = (DVB_SI)TID_TVCT; + } else if (table_type == TT_CVCT_C0 || table_type == TT_CVCT_C1) { + vctType = (DVB_SI)TID_CVCT; + } + } + gb.BitRead(3); //reserved + gb.BitRead(5); //table_type_version_number + gb.BitRead(32); //number_bytes + gb.BitRead(4); //reserved + + BeginEnumDescriptorsATSC(gb, nType, nLength, 12) { // for (i=0;i pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + WORD serviceType = 0; + + hr = m_pData->GetSection(PID_PSIP, vctType, &m_Filter, 15000, &pSectionList); + CheckNoLog(hr); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + CheckNoLog(ParseSIHeader(gb, vctType, wSectionLength, wTSID)); + gb.BitRead(8); //protocol_version + uint8_t num_channels = gb.BitRead(8); + + const int SHORT_NAME_LEN = 7*2; + BYTE short_name[SHORT_NAME_LEN+2]; + + for (uint8_t i = 0; i < num_channels; i++) { + gb.ReadBuffer(short_name, SHORT_NAME_LEN); //short_name + UTF16BE2LE(short_name, SHORT_NAME_LEN); + CStringW shortName((wchar_t*)short_name); + gb.BitRead(4); //reserved + uint16_t major_channel_number = gb.BitRead(10); //major_channel_number + uint16_t minor_channel_number = gb.BitRead(10); //minor_channel_number + gb.BitRead(8); //modulation_mode + gb.BitRead(32); //carrier_frequency + uint16_t channel_TSID=gb.BitRead(16); //channel_TSID + uint16_t program_number=gb.BitRead(16); //program_number + gb.BitRead(2); //ETM_location + gb.BitRead(1); //access_controlled + gb.BitRead(1); //hidden + gb.BitRead(2); //TVCT: reserved(1), CVCT: path_select(1) / out_of_band(1) + gb.BitRead(1); //hide_guide + gb.BitRead(3); //reserved + serviceType = gb.BitRead(6); //service_type + uint16_t source_id=gb.BitRead(16); //source_id + gb.BitRead(6); //reserved + BeginEnumDescriptorsATSC(gb, nType, nLength, 10) { // for (i=0;i pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + + CheckNoLog(m_pData->GetSection(PID_PAT, SI_PAT, &m_Filter, 15000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + // program_association_section() + CheckNoLog(ParseSIHeader(gb, SI_PAT, wSectionLength, wTSID)); + while (gb.GetSize() - gb.GetPos() > 4) { + WORD program_number = (WORD)gb.BitRead(16); // program_number + gb.BitRead(3); // reserved + if (program_number == 0) { + gb.BitRead(13); // network_PID + } else { + WORD program_map_PID = (WORD)gb.BitRead(13); // program_map_PID + if (Channels.Lookup(program_number)) { + Channels [program_number].SetPMT(program_map_PID); + ParsePMT(Channels [program_number]); + } + } + } + + return S_OK; +} + +HRESULT CMpeg2DataParser::ParsePMT(CBDAChannel& Channel) +{ + HRESULT hr; + CComPtr pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + + Channel.SetVideoFps(BDA_FPS_NONE); + Channel.SetVideoChroma(BDA_Chroma_NONE); + + CheckNoLog(m_pData->GetSection((PID)Channel.GetPMT(), SI_PMT, &m_Filter, 15000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + // TS_program_map_section() + CheckNoLog(ParseSIHeader(gb, SI_PMT, wSectionLength, wTSID)); + + gb.BitRead(3); // reserved + Channel.SetPCR((ULONG)gb.BitRead(13)); // PCR_PID + gb.BitRead(4); // reserved + BeginEnumDescriptors(gb, nType, nLength) { // for (i=0;i 4) { + PES_STREAM_TYPE pes_stream_type; + BDA_STREAM_TYPE dvb_stream_type; + WORD wPID; + CString strLanguage; + + pes_stream_type = (PES_STREAM_TYPE)gb.BitRead(8); // stream_type + gb.BitRead(3); // reserved + wPID = (WORD)gb.BitRead(13); // elementary_PID + gb.BitRead(4); // reserved + + BeginEnumDescriptors(gb, nType, nLength) { // ES_info_length + switch (nType) { + case DT_ISO_639_LANGUAGE: + gb.ReadBuffer(DescBuffer, nLength); + strLanguage = ConvertString(DescBuffer, 3); + break; + case DT_AC3_AUDIO: + pes_stream_type = AUDIO_STREAM_AC3; + SkipDescriptor(gb, nType, nLength); + break; + case DT_EXTENDED_AC3_AUDIO: + pes_stream_type = AUDIO_STREAM_AC3_PLUS; + SkipDescriptor(gb, nType, nLength); + break; + case DT_AAC_AUDIO: + pes_stream_type = AUDIO_STREAM_AAC_LATM; + SkipDescriptor(gb, nType, nLength); + break; + case DT_SUBTITLING: + gb.ReadBuffer(DescBuffer, nLength); + strLanguage = ConvertString(DescBuffer, 3); + pes_stream_type = SUBTITLE_STREAM; + break; + case DT_VIDEO_STREAM: { + gb.BitRead(1); // multiple_frame_rate_flag + Channel.SetVideoFps((BDA_FPS_TYPE) gb.BitRead(4)); + UINT MPEG_1_only_flag = (UINT) gb.BitRead(1); + gb.BitRead(1); // constrained_parameter_flag + gb.BitRead(1); // still_picture_flag + if (!MPEG_1_only_flag) { + gb.BitRead(8); // profile_and_level_indicator + Channel.SetVideoChroma((BDA_CHROMA_TYPE) gb.BitRead(2)); + gb.BitRead(1); // frame_rate_extension_flag + gb.BitRead(5); // Reserved + } + } + break; + case DT_TARGET_BACKGROUND_GRID: + Channel.SetVideoWidth((ULONG) gb.BitRead(14)); + Channel.SetVideoHeight((ULONG) gb.BitRead(14)); + Channel.SetVideoAR((BDA_AspectRatio_TYPE) gb.BitRead(4)); + break; + default: + SkipDescriptor(gb, nType, nLength); + break; + } + } + EndEnumDescriptors; + if ((dvb_stream_type = ConvertToDVBType(pes_stream_type)) != BDA_UNKNOWN) { + Channel.AddStreamInfo(wPID, dvb_stream_type, pes_stream_type, strLanguage); + } + } + if ((Channel.GetVideoType() == BDA_MPV) && (Channel.GetVideoPID())) { + if (Channel.GetVideoFps() == BDA_FPS_NONE) { + Channel.SetVideoFps(BDA_FPS_25_0); + } + if ((Channel.GetVideoWidth() == 0) && (Channel.GetVideoHeight() == 0)) { + Channel.SetVideoWidth(720); + Channel.SetVideoHeight(576); + } + } else if ((Channel.GetVideoType() == BDA_H264 || Channel.GetVideoType() == BDA_HEVC) && (Channel.GetVideoPID())) { + if (Channel.GetVideoFps() == BDA_FPS_NONE) { + Channel.SetVideoFps(BDA_FPS_25_0); + } + } + + + return S_OK; +} + +HRESULT CMpeg2DataParser::SetTime(CGolombBuffer& gb, EventDescriptor& NowNext) +{ + wchar_t descBuffer[6]; + time_t tNow, tTime; + tm tmTime; + long timezone; + + // init tm structures + time(&tNow); + gmtime_s(&tmTime, &tNow); + _tzset(); + _get_timezone(&timezone); // The difference in seconds between UTC and local time. + + // Start time: + tmTime.tm_hour = (int)(gb.BitRead(4) * 10); + tmTime.tm_hour += (int)gb.BitRead(4); + tmTime.tm_min = (int)(gb.BitRead(4) * 10); + tmTime.tm_min += (int)gb.BitRead(4); + tmTime.tm_sec = (int)(gb.BitRead(4) * 10); + tmTime.tm_sec += (int)gb.BitRead(4); + // Convert to time_t + // mktime() expect tm struct to be local time and since we are feeding it with GMT + // we need to compensate for timezone offset. Note that we don't compensate for DST. + // That is because tm_isdst is set to 0 (GMT) and in this case mktime() won't add any offset. + NowNext.startTime = tTime = mktime(&tmTime) - timezone; + while (tNow < tTime) { + // If current time is less than even start time it is likely that event started the day before. + // We go one day back + NowNext.startTime = tTime -= 86400; + } + + localtime_s(&tmTime, &tTime); + wcsftime(descBuffer, 6, L"%H:%M", &tmTime); + descBuffer[5] = '\0'; + NowNext.strStartTime = descBuffer; + + // Duration: + NowNext.duration = (time_t)(36000 * gb.BitRead(4)); + NowNext.duration += (time_t)(3600 * gb.BitRead(4)); + NowNext.duration += (time_t)(600 * gb.BitRead(4)); + NowNext.duration += (time_t)(60 * gb.BitRead(4)); + NowNext.duration += (time_t)(10 * gb.BitRead(4)); + NowNext.duration += (time_t)gb.BitRead(4); + + tTime += NowNext.duration; + localtime_s(&tmTime, &tTime); + wcsftime(descBuffer, 6, L"%H:%M", &tmTime); + descBuffer[5] = '\0'; + NowNext.strEndTime = descBuffer; + + return S_OK; +} + +HRESULT CMpeg2DataParser::ParseEIT(ULONG ulSID, EventDescriptor& NowNext) +{ + HRESULT hr = S_OK; + DWORD dwLength; + PSECTION data; + ULONG ulGetSID; + EventInformationSection InfoEvent; + NowNext = EventDescriptor(); + + do { + CComPtr pSectionList; + CheckNoLog(m_pData->GetSection(PID_EIT, SI_EIT_act, nullptr, 5000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + InfoEvent.TableID = (UINT8)gb.BitRead(8); + InfoEvent.SectionSyntaxIndicator = (WORD)gb.BitRead(1); + gb.BitRead(3); + InfoEvent.SectionLength = (WORD)gb.BitRead(12); + ulGetSID = (ULONG)gb.BitRead(8); + ulGetSID += 0x100 * (ULONG)gb.BitRead(8); + InfoEvent.ServiceId = ulGetSID; // This is really strange, ServiceID should be uimsbf ??? + if (InfoEvent.ServiceId == ulSID) { + gb.BitRead(2); + InfoEvent.VersionNumber = (UINT8)gb.BitRead(5); + InfoEvent.CurrentNextIndicator = (UINT8)gb.BitRead(1); + if (InfoEvent.CurrentNextIndicator == 1) { + InfoEvent.SectionNumber = (UINT8)gb.BitRead(8); + InfoEvent.LastSectionNumber = (UINT8)gb.BitRead(8); + InfoEvent.TransportStreamID = (WORD)gb.BitRead(16); + InfoEvent.OriginalNetworkID = (WORD)gb.BitRead(16); + InfoEvent.SegmentLastSectionNumber = (UINT8)gb.BitRead(8); + InfoEvent.LastTableID = (UINT8)gb.BitRead(8); + + // Info event + InfoEvent.EventID = (WORD)gb.BitRead(16); + InfoEvent.StartDate = (WORD)gb.BitRead(16); + SetTime(gb, NowNext); + + InfoEvent.RunninStatus = (WORD)gb.BitRead(3); + InfoEvent.FreeCAMode = (WORD)gb.BitRead(1); + if (InfoEvent.RunninStatus == 4) { + UINT8 nLen; + UINT8 itemsLength; + + // Descriptors: + BeginEnumDescriptors(gb, nType, nLength) { + switch (nType) { + case DT_SHORT_EVENT: + gb.BitRead(24); // ISO_639_language_code + + nLen = (UINT8)gb.BitRead(8); // event_name_length + gb.ReadBuffer(DescBuffer, nLen); + if (IsFreeviewEPG(InfoEvent.OriginalNetworkID, DescBuffer, nLen)) { + NowNext.eventName = DecodeFreeviewEPG(DescBuffer, nLen); + } else { + NowNext.eventName = ConvertString(DescBuffer, nLen); + } + + nLen = (UINT8)gb.BitRead(8); // text_length + gb.ReadBuffer(DescBuffer, nLen); + if (IsFreeviewEPG(InfoEvent.OriginalNetworkID, DescBuffer, nLen)) { + NowNext.eventDesc = DecodeFreeviewEPG(DescBuffer, nLen); + } else { + NowNext.eventDesc = ConvertString(DescBuffer, nLen); + } + break; + case DT_EXTENDED_EVENT: + gb.BitRead(4); // descriptor_number + gb.BitRead(4); // last_descriptor_number + gb.BitRead(24); // ISO_639_language_code + + itemsLength = (UINT8)gb.BitRead(8); // length_of_items + while (itemsLength > 0) { + nLen = (UINT8)gb.BitRead(8); // item_description_length + gb.ReadBuffer(DescBuffer, nLen); + CString itemDesc = ConvertString(DescBuffer, nLen); + itemsLength -= nLen + 1; + + nLen = (UINT8)gb.BitRead(8); // item_length + gb.ReadBuffer(DescBuffer, nLen); + CString itemText = ConvertString(DescBuffer, nLen); + itemsLength -= nLen + 1; + NowNext.extendedDescriptorsItems.emplace_back(itemDesc, itemText); + } + + nLen = (UINT8)gb.BitRead(8); // text_length + if (nLen > 0) { + gb.ReadBuffer(DescBuffer, nLen); + NowNext.extendedDescriptorsText += ConvertString(DescBuffer, nLen); + } + break; + case DT_PARENTAL_RATING: { + ASSERT(nLength % 4 == 0); + int rating = -1; + while (nLength >= 4) { + gb.BitRead(24); // ISO 3166 country_code + rating = (int)gb.BitRead(8); // rating + nLength -= 4; + } + if (rating >= 0 && rating <= 0x0f) { + if (rating > 0) { // 0x00 undefined + rating += 3; // 0x01 to 0x0F minimum age = rating + 3 years + } + NowNext.parentalRating = rating; + } + } + break; + case DT_CONTENT: + ASSERT(nLength % 2 == 0); + while (nLength >= 2) { + BYTE content = (BYTE)gb.BitRead(4); // content_nibble_level_1 + gb.BitRead(4); // content_nibble_level_2 + gb.BitRead(8); // user_byte + if (1 <= content && content <= 10) { + if (!NowNext.content.IsEmpty()) { + NowNext.content.Append(_T(", ")); + } + + static UINT contents[] = { + IDS_CONTENT_MOVIE_DRAMA, + IDS_CONTENT_NEWS_CURRENTAFFAIRS, + IDS_CONTENT_SHOW_GAMESHOW, + IDS_CONTENT_SPORTS, + IDS_CONTENT_CHILDREN_YOUTH_PROG, + IDS_CONTENT_MUSIC_BALLET_DANCE, + IDS_CONTENT_MUSIC_ART_CULTURE, + IDS_CONTENT_SOCIAL_POLITICAL_ECO, + IDS_CONTENT_EDUCATION_SCIENCE, + IDS_CONTENT_LEISURE + }; + + NowNext.content.AppendFormat(contents[content - 1]); + } + nLength -= 2; + } + break; + default: + SkipDescriptor(gb, nType, nLength); + break; + } + } + EndEnumDescriptors; + } + } + } + m_Filter.SectionNumber++; + } while ((InfoEvent.ServiceId != ulSID || InfoEvent.RunninStatus != 4) && m_Filter.SectionNumber <= 22); + + if (m_Filter.SectionNumber > 22 || InfoEvent.CurrentNextIndicator != 1) { + NowNext = EventDescriptor(); + hr = E_FAIL; + } + + return hr; +} + +HRESULT CMpeg2DataParser::ParseNIT() +{ + HRESULT hr; + CComPtr pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + + CheckNoLog(m_pData->GetSection(PID_NIT, SI_NIT, &m_Filter, 15000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + // network_information_section() + CheckNoLog(ParseSIHeader(gb, SI_NIT, wSectionLength, wTSID)); + + gb.BitRead(4); // reserved_future_use + BeginEnumDescriptors(gb, nType, nLength) { // for (i=0;i 4) { + WORD transport_stream_id = (WORD)gb.BitRead(16); // transport_stream_id + UNREFERENCED_PARAMETER(transport_stream_id); + WORD original_network_id = (WORD)gb.BitRead(16); // original_network_id + UNREFERENCED_PARAMETER(original_network_id); + gb.BitRead(4); // reserved_future_use + BeginEnumDescriptors(gb, nType, nLength) { + switch (nType) { + case DT_LOGICAL_CHANNEL: + for (int i = 0; i < nLength / 4; i++) { + WORD service_id = (WORD)gb.BitRead(16); + gb.BitRead(6); + WORD logical_channel_number = (WORD)gb.BitRead(10); + if (Channels.Lookup(service_id)) { + Channels[service_id].SetOriginNumber(logical_channel_number); + BDA_LOG(_T("NIT association : %d -> %s"), logical_channel_number, Channels[service_id].ToString().GetString()); + } + } + break; + default: + SkipDescriptor(gb, nType, nLength); + break; + } + } + EndEnumDescriptors; + } + + return S_OK; +} diff --git a/src/mpc-hc/Mpeg2SectionData.h b/src/mpc-hc/Mpeg2SectionData.h index 860afdf4c67..5544dad852e 100644 --- a/src/mpc-hc/Mpeg2SectionData.h +++ b/src/mpc-hc/Mpeg2SectionData.h @@ -1,94 +1,94 @@ -/* - * (C) 2009-2013, 2016 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 . - * - */ - -#pragma once - -#include "DVBChannel.h" -#include -#include - -class CGolombBuffer; - -#pragma pack(push, 1) -struct SI_HEADER { - UINT8 TableID; - WORD SectionSyntaxIndicator : 1; - WORD Reserved1 : 3; - WORD SectionLength : 12; - WORD BouquetID; - UINT8 Reserved2 : 1; - UINT8 VersionNumber : 5; - UINT8 CurrentNextIndicator : 1; - UINT8 SectionNumber; - UINT8 LastSectionNumber; -}; - -struct EventInformationSection { - UINT8 TableID; - WORD SectionSyntaxIndicator : 1; - WORD Reserved1 : 3; - WORD SectionLength : 12; - ULONG ServiceId; - UINT8 Reserved2 : 2; - UINT8 VersionNumber : 5; - UINT8 CurrentNextIndicator : 1; - UINT8 SectionNumber; - UINT8 LastSectionNumber; - WORD TransportStreamID; - WORD OriginalNetworkID; - UINT8 SegmentLastSectionNumber; - UINT8 LastTableID; - WORD EventID; - WORD StartDate; - UINT8 StartTime[6]; - UINT8 Duration[6]; - WORD RunninStatus : 3; - WORD FreeCAMode : 1; - WORD DescriptorsLoopLength : 12; - -}; - -class CMpeg2DataParser -{ -public: - CMpeg2DataParser(IBaseFilter* pFilter); - - HRESULT ParseSDT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate); - HRESULT ParseVCT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, enum DVB_SI vctType); - HRESULT ParseMGT(enum DVB_SI &vctType); - HRESULT ParsePAT(); - HRESULT ParseNIT(); - HRESULT ParseEIT(ULONG ulSID, EventDescriptor& NowNext); - HRESULT ParsePMT(CBDAChannel& Channel); - - static CStringW ConvertString(BYTE* pBuffer, size_t uLength); - - CAtlMap Channels; - -private: - CComQIPtr m_pData; - MPEG2_FILTER m_Filter; - - - BDA_STREAM_TYPE ConvertToDVBType(PES_STREAM_TYPE nType); - HRESULT ParseSIHeader(CGolombBuffer& gb, DVB_SI SIType, WORD& wSectionLength, WORD& wTSID); - HRESULT SetTime(CGolombBuffer& gb, EventDescriptor& NowNext); -}; -#pragma pack(pop) +/* + * (C) 2009-2013, 2016 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 . + * + */ + +#pragma once + +#include "DVBChannel.h" +#include +#include + +class CGolombBuffer; + +#pragma pack(push, 1) +struct SI_HEADER { + UINT8 TableID; + WORD SectionSyntaxIndicator : 1; + WORD Reserved1 : 3; + WORD SectionLength : 12; + WORD BouquetID; + UINT8 Reserved2 : 1; + UINT8 VersionNumber : 5; + UINT8 CurrentNextIndicator : 1; + UINT8 SectionNumber; + UINT8 LastSectionNumber; +}; + +struct EventInformationSection { + UINT8 TableID; + WORD SectionSyntaxIndicator : 1; + WORD Reserved1 : 3; + WORD SectionLength : 12; + ULONG ServiceId; + UINT8 Reserved2 : 2; + UINT8 VersionNumber : 5; + UINT8 CurrentNextIndicator : 1; + UINT8 SectionNumber; + UINT8 LastSectionNumber; + WORD TransportStreamID; + WORD OriginalNetworkID; + UINT8 SegmentLastSectionNumber; + UINT8 LastTableID; + WORD EventID; + WORD StartDate; + UINT8 StartTime[6]; + UINT8 Duration[6]; + WORD RunninStatus : 3; + WORD FreeCAMode : 1; + WORD DescriptorsLoopLength : 12; + +}; + +class CMpeg2DataParser +{ +public: + CMpeg2DataParser(IBaseFilter* pFilter); + + HRESULT ParseSDT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate); + HRESULT ParseVCT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, enum DVB_SI vctType); + HRESULT ParseMGT(enum DVB_SI &vctType); + HRESULT ParsePAT(); + HRESULT ParseNIT(); + HRESULT ParseEIT(ULONG ulSID, EventDescriptor& NowNext); + HRESULT ParsePMT(CBDAChannel& Channel); + + static CStringW ConvertString(BYTE* pBuffer, size_t uLength); + + CAtlMap Channels; + +private: + CComQIPtr m_pData; + MPEG2_FILTER m_Filter; + + + BDA_STREAM_TYPE ConvertToDVBType(PES_STREAM_TYPE nType); + HRESULT ParseSIHeader(CGolombBuffer& gb, DVB_SI SIType, WORD& wSectionLength, WORD& wTSID); + HRESULT SetTime(CGolombBuffer& gb, EventDescriptor& NowNext); +}; +#pragma pack(pop) diff --git a/src/mpc-hc/MultiMonitor.cpp b/src/mpc-hc/MultiMonitor.cpp index d6d3010a77f..2a62da0f590 100644 --- a/src/mpc-hc/MultiMonitor.cpp +++ b/src/mpc-hc/MultiMonitor.cpp @@ -1,263 +1,263 @@ -/* - * Author: Donald Kackman - * Email: don@itsEngineering.com - * Copyright 2002, Donald Kackman - * - * 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 . - * - */ - -#include "stdafx.h" -#include "MultiMonitor.h" -#include "Monitors.h" - -// CMonitor - -// constucts a monitor class not attached to any handle -CMonitor::CMonitor() : m_hMonitor(nullptr) -{ -} - -// copy constructor -CMonitor::CMonitor(const CMonitor& monitor) -{ - m_hMonitor = (HMONITOR)monitor; -} - -CMonitor::~CMonitor() -{ -} - -void CMonitor::Attach(const HMONITOR hMonitor) -{ - ASSERT(CMonitors::IsMonitor(hMonitor)); - - m_hMonitor = hMonitor; -} - -HMONITOR CMonitor::Detach() -{ - HMONITOR hMonitor = m_hMonitor; - m_hMonitor = nullptr; - return hMonitor; -} - -// creates an HDC for the monitor -// it is up to the client to call DeleteDC -// -// for normal multimonitor drawing it is not necessary to get a -// dc for each monitor. Windows takes care of drawing correctly -// on all monitors -// -// Only very exacting applications would need a DC for each monitor -HDC CMonitor::CreateDC() const -{ - ASSERT(IsMonitor()); - - CString name; - GetName(name); - - //create a dc for this display - HDC hdc = ::CreateDC(name, name, nullptr, nullptr); - ASSERT(hdc != nullptr); - - //set the viewport based on the monitor rect's relation to the primary monitor - CRect rect; - GetMonitorRect(&rect); - - ::SetViewportOrgEx(hdc, -rect.left, -rect.top, nullptr); - ::SetViewportExtEx(hdc, rect.Width(), rect.Height(), nullptr); - - return hdc; -} - -int CMonitor::GetBitsPerPixel() const -{ - HDC hdc = CreateDC(); - int ret = ::GetDeviceCaps(hdc, BITSPIXEL) * ::GetDeviceCaps(hdc, PLANES); - VERIFY(::DeleteDC(hdc)); - - return ret; -} - -void CMonitor::GetName(CString& displayName) const -{ - ASSERT(IsMonitor()); - - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - - displayName = mi.szDevice; -} - -void CMonitor::GetNames(CString& displayName, CString& deviceName) const -{ - ASSERT(IsMonitor()); - - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - - displayName = mi.szDevice; - - DISPLAY_DEVICE displayDevice = { sizeof(displayDevice) }; - if (EnumDisplayDevices(displayName, 0, &displayDevice, 0)) { - deviceName = displayDevice.DeviceString; - } else { - deviceName = L""; - } -} - -// -// these methods return true if any part of the item intersects the monitor rect -BOOL CMonitor::IsOnMonitor(const POINT& pt) const -{ - CRect rect; - GetMonitorRect(rect); - - return rect.PtInRect(pt); -} - -BOOL CMonitor::IsOnMonitor(const CWnd* pWnd) const -{ - CRect rect; - GetMonitorRect(rect); - - ASSERT(::IsWindow(pWnd->GetSafeHwnd())); - CRect wndRect; - pWnd->GetWindowRect(&wndRect); - - return rect.IntersectRect(rect, wndRect); -} - -BOOL CMonitor::IsOnMonitor(const LPRECT lprc) const -{ - CRect rect; - GetMonitorRect(rect); - - return rect.IntersectRect(rect, lprc); -} - -void CMonitor::GetMonitorRect(LPRECT lprc) const -{ - ASSERT(IsMonitor()); - - MONITORINFO mi; - RECT rc; - - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - rc = mi.rcMonitor; - - ::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom); -} - -// -// the work area does not include the start bar -void CMonitor::GetWorkAreaRect(LPRECT lprc) const -{ - ASSERT(IsMonitor()); - - MONITORINFO mi; - RECT rc; - - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - rc = mi.rcWork; - - ::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom); -} - -//these two center methods are adapted from David Campbell's -//MSJ article (see comment at the top of the header file) -void CMonitor::CenterRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect) const -{ - int w = lprc->right - lprc->left; - int h = lprc->bottom - lprc->top; - - CRect rect; - if (UseWorkAreaRect) { - GetWorkAreaRect(&rect); - } else { - GetMonitorRect(&rect); - } - - // MPC-HC custom code start - // Added rounding to get exactly the same rect as the CWnd::CenterWindow method returns. - lprc->left = std::lround(rect.left + (rect.Width() - w) / 2.0); - lprc->top = std::lround(rect.top + (rect.Height() - h) / 2.0); - // MPC-HC custom code end - lprc->right = lprc->left + w; - lprc->bottom = lprc->top + h; -} - -void CMonitor::CenterWindowToMonitor(CWnd* const pWnd, const BOOL UseWorkAreaRect) const -{ - ASSERT(IsMonitor()); - ASSERT(pWnd); - ASSERT(::IsWindow(pWnd->m_hWnd)); - - CRect rect; - pWnd->GetWindowRect(&rect); - CenterRectToMonitor(&rect, UseWorkAreaRect); - // MPC-HC custom code start - // Check if we are a child window and modify the coordinates accordingly - if (pWnd->GetStyle() & WS_CHILD) { - pWnd->GetParent()->ScreenToClient(&rect); - } - // MPC-HC custom code end - pWnd->SetWindowPos(nullptr, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); -} - -void CMonitor::ClipRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect) const -{ - int w = lprc->right - lprc->left; - int h = lprc->bottom - lprc->top; - - CRect rect; - if (UseWorkAreaRect) { - GetWorkAreaRect(&rect); - } else { - GetMonitorRect(&rect); - } - - lprc->left = std::max(rect.left, std::min(rect.right - w, lprc->left)); - lprc->top = std::max(rect.top, std::min(rect.bottom - h, lprc->top)); - lprc->right = lprc->left + w; - lprc->bottom = lprc->top + h; -} - -// -// is the instance the primary monitor -BOOL CMonitor::IsPrimaryMonitor() const -{ - ASSERT(IsMonitor()); - - MONITORINFO mi; - - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - - return mi.dwFlags == MONITORINFOF_PRIMARY; -} - -// -// is the instance currently attached to a valid monitor handle -BOOL CMonitor::IsMonitor() const -{ - return CMonitors::IsMonitor(m_hMonitor); -} +/* + * Author: Donald Kackman + * Email: don@itsEngineering.com + * Copyright 2002, Donald Kackman + * + * 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 . + * + */ + +#include "stdafx.h" +#include "MultiMonitor.h" +#include "Monitors.h" + +// CMonitor + +// constucts a monitor class not attached to any handle +CMonitor::CMonitor() : m_hMonitor(nullptr) +{ +} + +// copy constructor +CMonitor::CMonitor(const CMonitor& monitor) +{ + m_hMonitor = (HMONITOR)monitor; +} + +CMonitor::~CMonitor() +{ +} + +void CMonitor::Attach(const HMONITOR hMonitor) +{ + ASSERT(CMonitors::IsMonitor(hMonitor)); + + m_hMonitor = hMonitor; +} + +HMONITOR CMonitor::Detach() +{ + HMONITOR hMonitor = m_hMonitor; + m_hMonitor = nullptr; + return hMonitor; +} + +// creates an HDC for the monitor +// it is up to the client to call DeleteDC +// +// for normal multimonitor drawing it is not necessary to get a +// dc for each monitor. Windows takes care of drawing correctly +// on all monitors +// +// Only very exacting applications would need a DC for each monitor +HDC CMonitor::CreateDC() const +{ + ASSERT(IsMonitor()); + + CString name; + GetName(name); + + //create a dc for this display + HDC hdc = ::CreateDC(name, name, nullptr, nullptr); + ASSERT(hdc != nullptr); + + //set the viewport based on the monitor rect's relation to the primary monitor + CRect rect; + GetMonitorRect(&rect); + + ::SetViewportOrgEx(hdc, -rect.left, -rect.top, nullptr); + ::SetViewportExtEx(hdc, rect.Width(), rect.Height(), nullptr); + + return hdc; +} + +int CMonitor::GetBitsPerPixel() const +{ + HDC hdc = CreateDC(); + int ret = ::GetDeviceCaps(hdc, BITSPIXEL) * ::GetDeviceCaps(hdc, PLANES); + VERIFY(::DeleteDC(hdc)); + + return ret; +} + +void CMonitor::GetName(CString& displayName) const +{ + ASSERT(IsMonitor()); + + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + + displayName = mi.szDevice; +} + +void CMonitor::GetNames(CString& displayName, CString& deviceName) const +{ + ASSERT(IsMonitor()); + + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + + displayName = mi.szDevice; + + DISPLAY_DEVICE displayDevice = { sizeof(displayDevice) }; + if (EnumDisplayDevices(displayName, 0, &displayDevice, 0)) { + deviceName = displayDevice.DeviceString; + } else { + deviceName = L""; + } +} + +// +// these methods return true if any part of the item intersects the monitor rect +BOOL CMonitor::IsOnMonitor(const POINT& pt) const +{ + CRect rect; + GetMonitorRect(rect); + + return rect.PtInRect(pt); +} + +BOOL CMonitor::IsOnMonitor(const CWnd* pWnd) const +{ + CRect rect; + GetMonitorRect(rect); + + ASSERT(::IsWindow(pWnd->GetSafeHwnd())); + CRect wndRect; + pWnd->GetWindowRect(&wndRect); + + return rect.IntersectRect(rect, wndRect); +} + +BOOL CMonitor::IsOnMonitor(const LPRECT lprc) const +{ + CRect rect; + GetMonitorRect(rect); + + return rect.IntersectRect(rect, lprc); +} + +void CMonitor::GetMonitorRect(LPRECT lprc) const +{ + ASSERT(IsMonitor()); + + MONITORINFO mi; + RECT rc; + + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + rc = mi.rcMonitor; + + ::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom); +} + +// +// the work area does not include the start bar +void CMonitor::GetWorkAreaRect(LPRECT lprc) const +{ + ASSERT(IsMonitor()); + + MONITORINFO mi; + RECT rc; + + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + rc = mi.rcWork; + + ::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom); +} + +//these two center methods are adapted from David Campbell's +//MSJ article (see comment at the top of the header file) +void CMonitor::CenterRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect) const +{ + int w = lprc->right - lprc->left; + int h = lprc->bottom - lprc->top; + + CRect rect; + if (UseWorkAreaRect) { + GetWorkAreaRect(&rect); + } else { + GetMonitorRect(&rect); + } + + // MPC-HC custom code start + // Added rounding to get exactly the same rect as the CWnd::CenterWindow method returns. + lprc->left = std::lround(rect.left + (rect.Width() - w) / 2.0); + lprc->top = std::lround(rect.top + (rect.Height() - h) / 2.0); + // MPC-HC custom code end + lprc->right = lprc->left + w; + lprc->bottom = lprc->top + h; +} + +void CMonitor::CenterWindowToMonitor(CWnd* const pWnd, const BOOL UseWorkAreaRect) const +{ + ASSERT(IsMonitor()); + ASSERT(pWnd); + ASSERT(::IsWindow(pWnd->m_hWnd)); + + CRect rect; + pWnd->GetWindowRect(&rect); + CenterRectToMonitor(&rect, UseWorkAreaRect); + // MPC-HC custom code start + // Check if we are a child window and modify the coordinates accordingly + if (pWnd->GetStyle() & WS_CHILD) { + pWnd->GetParent()->ScreenToClient(&rect); + } + // MPC-HC custom code end + pWnd->SetWindowPos(nullptr, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); +} + +void CMonitor::ClipRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect) const +{ + int w = lprc->right - lprc->left; + int h = lprc->bottom - lprc->top; + + CRect rect; + if (UseWorkAreaRect) { + GetWorkAreaRect(&rect); + } else { + GetMonitorRect(&rect); + } + + lprc->left = std::max(rect.left, std::min(rect.right - w, lprc->left)); + lprc->top = std::max(rect.top, std::min(rect.bottom - h, lprc->top)); + lprc->right = lprc->left + w; + lprc->bottom = lprc->top + h; +} + +// +// is the instance the primary monitor +BOOL CMonitor::IsPrimaryMonitor() const +{ + ASSERT(IsMonitor()); + + MONITORINFO mi; + + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + + return mi.dwFlags == MONITORINFOF_PRIMARY; +} + +// +// is the instance currently attached to a valid monitor handle +BOOL CMonitor::IsMonitor() const +{ + return CMonitors::IsMonitor(m_hMonitor); +} diff --git a/src/mpc-hc/MultiMonitor.h b/src/mpc-hc/MultiMonitor.h index c43ebbc20c7..434875b24ca 100644 --- a/src/mpc-hc/MultiMonitor.h +++ b/src/mpc-hc/MultiMonitor.h @@ -1,89 +1,89 @@ -/* - * Author: Donald Kackman - * Email: don@itsEngineering.com - * Copyright 2002, Donald Kackman - * - * 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 . - * - */ - -/* - * David Campbell's article - * How to Exploit Multiple Monitor Support in Memphis and Windows NT 5.0 - * is very helpful for multimonitor api calls - * http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0697/monitor/monitor.htm&nav=/msj/0697/newnav.htm -*/ - -// CMonitor - -#pragma once - -class CMonitor : public CObject -{ -public: - //construction destruction - CMonitor(); - CMonitor(const CMonitor& monitor); - virtual ~CMonitor(); - - //operations - void Attach(const HMONITOR hMonitor); - HMONITOR Detach(); - - void ClipRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect = FALSE) const; - void CenterRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect = FALSE) const; - void CenterWindowToMonitor(CWnd* const pWnd, const BOOL UseWorkAreaRect = FALSE) const; - - HDC CreateDC() const; - - //properties - void GetMonitorRect(LPRECT lprc) const; - void GetWorkAreaRect(LPRECT lprc) const; - - void GetName(CString& displayName) const; - void GetNames(CString& displayName, CString& deviceName) const; - - int GetBitsPerPixel() const; - - BOOL IsOnMonitor(const POINT& pt) const; - BOOL IsOnMonitor(const CWnd* pWnd) const; - BOOL IsOnMonitor(const LPRECT lprc) const; - - BOOL IsPrimaryMonitor() const; - BOOL IsMonitor() const; - - //operators - operator HMONITOR() const { - return this == nullptr ? nullptr : m_hMonitor; - } - - BOOL operator ==(const CMonitor& monitor) const { - return m_hMonitor == (HMONITOR)monitor; - } - - BOOL operator !=(const CMonitor& monitor) const { - return !(*this == monitor); - } - - CMonitor& operator =(const CMonitor& monitor) { - m_hMonitor = (HMONITOR)monitor; - return *this; - } - -private: - HMONITOR m_hMonitor; - -}; +/* + * Author: Donald Kackman + * Email: don@itsEngineering.com + * Copyright 2002, Donald Kackman + * + * 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 . + * + */ + +/* + * David Campbell's article + * How to Exploit Multiple Monitor Support in Memphis and Windows NT 5.0 + * is very helpful for multimonitor api calls + * http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0697/monitor/monitor.htm&nav=/msj/0697/newnav.htm +*/ + +// CMonitor + +#pragma once + +class CMonitor : public CObject +{ +public: + //construction destruction + CMonitor(); + CMonitor(const CMonitor& monitor); + virtual ~CMonitor(); + + //operations + void Attach(const HMONITOR hMonitor); + HMONITOR Detach(); + + void ClipRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect = FALSE) const; + void CenterRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect = FALSE) const; + void CenterWindowToMonitor(CWnd* const pWnd, const BOOL UseWorkAreaRect = FALSE) const; + + HDC CreateDC() const; + + //properties + void GetMonitorRect(LPRECT lprc) const; + void GetWorkAreaRect(LPRECT lprc) const; + + void GetName(CString& displayName) const; + void GetNames(CString& displayName, CString& deviceName) const; + + int GetBitsPerPixel() const; + + BOOL IsOnMonitor(const POINT& pt) const; + BOOL IsOnMonitor(const CWnd* pWnd) const; + BOOL IsOnMonitor(const LPRECT lprc) const; + + BOOL IsPrimaryMonitor() const; + BOOL IsMonitor() const; + + //operators + operator HMONITOR() const { + return this == nullptr ? nullptr : m_hMonitor; + } + + BOOL operator ==(const CMonitor& monitor) const { + return m_hMonitor == (HMONITOR)monitor; + } + + BOOL operator !=(const CMonitor& monitor) const { + return !(*this == monitor); + } + + CMonitor& operator =(const CMonitor& monitor) { + m_hMonitor = (HMONITOR)monitor; + return *this; + } + +private: + HMONITOR m_hMonitor; + +}; diff --git a/src/mpc-hc/OpenDirHelper.cpp b/src/mpc-hc/OpenDirHelper.cpp index 5b18a31cc12..1cfd265e02b 100644 --- a/src/mpc-hc/OpenDirHelper.cpp +++ b/src/mpc-hc/OpenDirHelper.cpp @@ -1,113 +1,113 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include "MainFrm.h" -#include "OpenDirHelper.h" -#include "PathUtils.h" - - -WNDPROC COpenDirHelper::CBProc; -bool COpenDirHelper::m_incl_subdir; -CString COpenDirHelper::strLastOpenDir; - -void COpenDirHelper::SetFont(HWND hwnd, LPCTSTR FontName, int FontSize) -{ - HFONT hf, hfOld; - LOGFONT lf; - ZeroMemory(&lf, sizeof(LOGFONT)); - HDC hdc = GetDC(hwnd); - - GetObject(GetWindowFont(hwnd), sizeof(lf), &lf); - lf.lfWeight = FW_REGULAR; - lf.lfHeight = (LONG)FontSize; - _tcscpy_s(lf.lfFaceName, FontName); - hf = CreateFontIndirect(&lf); - SetBkMode(hdc, OPAQUE); - - hfOld = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); // get old font - SendMessage(hwnd, WM_SETFONT, (WPARAM)hf, TRUE); // set new font - - if (!hfOld && (hfOld != hf)) { - DeleteObject(hfOld); // if the old font is not system font or the same as newfont, release it. - } - ReleaseDC(hwnd, hdc); -} - -// Subclass procedure -LRESULT APIENTRY COpenDirHelper::CheckBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (uMsg == WM_LBUTTONUP) { - if ((SendMessage(hwnd, BM_GETCHECK, 0, 0)) == 1) { - m_incl_subdir = FALSE; - } else { - m_incl_subdir = TRUE; - } - } - return CallWindowProc(CBProc, hwnd, uMsg, wParam, lParam); -} - -int CALLBACK COpenDirHelper::BrowseCallbackProcDIR(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) -{ - // Initialization callback message - if (uMsg == BFFM_INITIALIZED) { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)strLastOpenDir); - - HWND checkbox; - RECT ListViewRect; - RECT Dialog; - RECT ClientArea; - RECT ButtonRect; - - checkbox = CreateWindowEx(0, _T("BUTTON"), ResStr(IDS_MAINFRM_DIR_CHECK), - WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | BS_AUTOCHECKBOX | BS_MULTILINE, - 0, 100, 100, 50, hwnd, 0, AfxGetApp()->m_hInstance, nullptr); - - HWND ListView = FindWindowEx(hwnd, nullptr, _T("SysTreeView32"), nullptr); - - HWND id_ok = GetDlgItem(hwnd, IDOK); - HWND id_cancel = GetDlgItem(hwnd, IDCANCEL); - - GetWindowRect(hwnd, &Dialog); - MoveWindow(hwnd, Dialog.left, Dialog.top, Dialog.right - Dialog.left + 50, Dialog.bottom - Dialog.top + 70, TRUE); - GetWindowRect(hwnd, &Dialog); - - GetClientRect(hwnd, &ClientArea); - - GetWindowRect(ListView, &ListViewRect); - MoveWindow(ListView, ListViewRect.left - Dialog.left - 3, ListViewRect.top - Dialog.top - 75, ListViewRect.right - ListViewRect.left + 49, ListViewRect.bottom - ListViewRect.top + 115, TRUE); - GetWindowRect(ListView, &ListViewRect); - - GetWindowRect(id_ok, &ButtonRect); - MoveWindow(id_ok, ButtonRect.left - Dialog.left + 49, ButtonRect.top - Dialog.top + 40, ButtonRect.right - ButtonRect.left, ButtonRect.bottom - ButtonRect.top, TRUE); - - GetWindowRect(id_cancel, &ButtonRect); - MoveWindow(id_cancel, ButtonRect.left - Dialog.left + 49, ButtonRect.top - Dialog.top + 40, ButtonRect.right - ButtonRect.left, ButtonRect.bottom - ButtonRect.top, TRUE); - - SetWindowPos(checkbox, HWND_BOTTOM, ListViewRect.left - Dialog.left - 3, ClientArea.bottom - 35, 180, 27, SWP_SHOWWINDOW); - SetFont(checkbox, _T("Tahoma"), 13); - - CBProc = (WNDPROC)SetWindowLongPtr(checkbox, GWLP_WNDPROC, (LONG_PTR)CheckBoxSubclassProc); - SendMessage(checkbox, BM_SETCHECK, (WPARAM)m_incl_subdir, 0); - } - - return 0; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include "MainFrm.h" +#include "OpenDirHelper.h" +#include "PathUtils.h" + + +WNDPROC COpenDirHelper::CBProc; +bool COpenDirHelper::m_incl_subdir; +CString COpenDirHelper::strLastOpenDir; + +void COpenDirHelper::SetFont(HWND hwnd, LPCTSTR FontName, int FontSize) +{ + HFONT hf, hfOld; + LOGFONT lf; + ZeroMemory(&lf, sizeof(LOGFONT)); + HDC hdc = GetDC(hwnd); + + GetObject(GetWindowFont(hwnd), sizeof(lf), &lf); + lf.lfWeight = FW_REGULAR; + lf.lfHeight = (LONG)FontSize; + _tcscpy_s(lf.lfFaceName, FontName); + hf = CreateFontIndirect(&lf); + SetBkMode(hdc, OPAQUE); + + hfOld = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); // get old font + SendMessage(hwnd, WM_SETFONT, (WPARAM)hf, TRUE); // set new font + + if (!hfOld && (hfOld != hf)) { + DeleteObject(hfOld); // if the old font is not system font or the same as newfont, release it. + } + ReleaseDC(hwnd, hdc); +} + +// Subclass procedure +LRESULT APIENTRY COpenDirHelper::CheckBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_LBUTTONUP) { + if ((SendMessage(hwnd, BM_GETCHECK, 0, 0)) == 1) { + m_incl_subdir = FALSE; + } else { + m_incl_subdir = TRUE; + } + } + return CallWindowProc(CBProc, hwnd, uMsg, wParam, lParam); +} + +int CALLBACK COpenDirHelper::BrowseCallbackProcDIR(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + // Initialization callback message + if (uMsg == BFFM_INITIALIZED) { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)strLastOpenDir); + + HWND checkbox; + RECT ListViewRect; + RECT Dialog; + RECT ClientArea; + RECT ButtonRect; + + checkbox = CreateWindowEx(0, _T("BUTTON"), ResStr(IDS_MAINFRM_DIR_CHECK), + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | BS_AUTOCHECKBOX | BS_MULTILINE, + 0, 100, 100, 50, hwnd, 0, AfxGetApp()->m_hInstance, nullptr); + + HWND ListView = FindWindowEx(hwnd, nullptr, _T("SysTreeView32"), nullptr); + + HWND id_ok = GetDlgItem(hwnd, IDOK); + HWND id_cancel = GetDlgItem(hwnd, IDCANCEL); + + GetWindowRect(hwnd, &Dialog); + MoveWindow(hwnd, Dialog.left, Dialog.top, Dialog.right - Dialog.left + 50, Dialog.bottom - Dialog.top + 70, TRUE); + GetWindowRect(hwnd, &Dialog); + + GetClientRect(hwnd, &ClientArea); + + GetWindowRect(ListView, &ListViewRect); + MoveWindow(ListView, ListViewRect.left - Dialog.left - 3, ListViewRect.top - Dialog.top - 75, ListViewRect.right - ListViewRect.left + 49, ListViewRect.bottom - ListViewRect.top + 115, TRUE); + GetWindowRect(ListView, &ListViewRect); + + GetWindowRect(id_ok, &ButtonRect); + MoveWindow(id_ok, ButtonRect.left - Dialog.left + 49, ButtonRect.top - Dialog.top + 40, ButtonRect.right - ButtonRect.left, ButtonRect.bottom - ButtonRect.top, TRUE); + + GetWindowRect(id_cancel, &ButtonRect); + MoveWindow(id_cancel, ButtonRect.left - Dialog.left + 49, ButtonRect.top - Dialog.top + 40, ButtonRect.right - ButtonRect.left, ButtonRect.bottom - ButtonRect.top, TRUE); + + SetWindowPos(checkbox, HWND_BOTTOM, ListViewRect.left - Dialog.left - 3, ClientArea.bottom - 35, 180, 27, SWP_SHOWWINDOW); + SetFont(checkbox, _T("Tahoma"), 13); + + CBProc = (WNDPROC)SetWindowLongPtr(checkbox, GWLP_WNDPROC, (LONG_PTR)CheckBoxSubclassProc); + SendMessage(checkbox, BM_SETCHECK, (WPARAM)m_incl_subdir, 0); + } + + return 0; +} diff --git a/src/mpc-hc/OpenDirHelper.h b/src/mpc-hc/OpenDirHelper.h index 85311ff42fe..ec40aec7a2d 100644 --- a/src/mpc-hc/OpenDirHelper.h +++ b/src/mpc-hc/OpenDirHelper.h @@ -1,36 +1,36 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015, 2017 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 . - * - */ - -#pragma once - -class COpenDirHelper -{ -public: - static WNDPROC CBProc; - static bool m_incl_subdir; - static CString strLastOpenDir; - - static void SetFont(HWND hwnd, LPCTSTR FontName, int FontSize); - // Subclass procedure - static LRESULT APIENTRY CheckBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - - static int CALLBACK BrowseCallbackProcDIR(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015, 2017 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 . + * + */ + +#pragma once + +class COpenDirHelper +{ +public: + static WNDPROC CBProc; + static bool m_incl_subdir; + static CString strLastOpenDir; + + static void SetFont(HWND hwnd, LPCTSTR FontName, int FontSize); + // Subclass procedure + static LRESULT APIENTRY CheckBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + static int CALLBACK BrowseCallbackProcDIR(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); +}; diff --git a/src/mpc-hc/OpenDlg.cpp b/src/mpc-hc/OpenDlg.cpp index c27a7f28843..332b03216b1 100644 --- a/src/mpc-hc/OpenDlg.cpp +++ b/src/mpc-hc/OpenDlg.cpp @@ -1,237 +1,237 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include -#include "mplayerc.h" -#include "PathUtils.h" -#include "OpenDlg.h" -#include "OpenFileDlg.h" - - -// COpenDlg dialog - -//IMPLEMENT_DYNAMIC(COpenDlg, CMPCThemeResizableDialog) -COpenDlg::COpenDlg(CWnd* pParent /*=nullptr*/) - : CMPCThemeResizableDialog(COpenDlg::IDD, pParent) - , m_bAppendToPlaylist(FALSE) - , m_bMultipleFiles(false) -{ -} - -COpenDlg::~COpenDlg() -{ -} - -void COpenDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Control(pDX, IDR_MAINFRAME, m_icon); - DDX_Control(pDX, IDC_COMBO1, m_cbMRU); - DDX_CBString(pDX, IDC_COMBO1, m_path); - DDX_Control(pDX, IDC_COMBO2, m_cbMRUDub); - DDX_CBString(pDX, IDC_COMBO2, m_pathDub); - DDX_Control(pDX, IDC_STATIC1, m_labelDub); - DDX_Check(pDX, IDC_CHECK1, m_bAppendToPlaylist); - fulfillThemeReqs(); -} - - -BEGIN_MESSAGE_MAP(COpenDlg, CMPCThemeResizableDialog) - ON_BN_CLICKED(IDC_BUTTON1, OnBrowseFile) - ON_BN_CLICKED(IDC_BUTTON2, OnBrowseDubFile) - ON_BN_CLICKED(IDOK, OnOk) - ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateDub) - ON_UPDATE_COMMAND_UI(IDC_COMBO2, OnUpdateDub) - ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateDub) - ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOk) -END_MESSAGE_MAP() - - -// COpenDlg message handlers - -BOOL COpenDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - m_icon.SetIcon((HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED)); - - CAppSettings& s = AfxGetAppSettings(); - - auto& MRU = s.MRU; - MRU.ReadMediaHistory(); - m_cbMRU.ResetContent(); - for (int i = 0; i < MRU.GetSize(); i++) { - if (MRU[i].fns.GetCount() >0 && !MRU[i].fns.GetHead().IsEmpty()) { - m_cbMRU.AddString(MRU[i].fns.GetHead()); - } - } - CorrectComboListWidth(m_cbMRU); - - CRecentFileList& MRUDub = s.MRUDub; - MRUDub.ReadList(); - m_cbMRUDub.ResetContent(); - for (int i = 0; i < MRUDub.GetSize(); i++) { - if (!MRUDub[i].IsEmpty()) { - m_cbMRUDub.AddString(MRUDub[i]); - } - } - CorrectComboListWidth(m_cbMRUDub); - - if (m_cbMRU.GetCount() > 0) { - m_cbMRU.SetCurSel(0); - } - - m_fns.RemoveAll(); - m_path.Empty(); - m_pathDub.Empty(); - m_bMultipleFiles = false; - m_bAppendToPlaylist = FALSE; - - AddAnchor(m_cbMRU, TOP_LEFT, TOP_RIGHT); - AddAnchor(m_cbMRUDub, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_BUTTON1, TOP_RIGHT); - AddAnchor(IDC_BUTTON2, TOP_RIGHT); - AddAnchor(IDOK, TOP_RIGHT); - AddAnchor(IDCANCEL, TOP_RIGHT); - AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); - - CRect r; - GetWindowRect(r); - CSize size = r.Size(); - SetMinTrackSize(size); - size.cx = 1000; - SetMaxTrackSize(size); - - fulfillThemeReqs(); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -static CString GetFileName(CString str) -{ - CPath p = str; - p.StripPath(); - return (LPCTSTR)p; -} - -void COpenDlg::OnBrowseFile() -{ - UpdateData(); - - CAppSettings& s = AfxGetAppSettings(); - - CString filter; - CAtlArray mask; - s.m_Formats.GetFilter(filter, mask); - - DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR; - if (!s.fKeepHistory) { - dwFlags |= OFN_DONTADDTORECENT; - } - - COpenFileDlg fd(mask, true, nullptr, m_path, dwFlags, filter, this); - if (m_path.IsEmpty() && s.fKeepHistory && !s.lastQuickOpenPath.IsEmpty()) { - fd.m_ofn.lpstrInitialDir = s.lastQuickOpenPath; - } - if (fd.DoModal() != IDOK) { - return; - } - - m_fns.RemoveAll(); - - POSITION pos = fd.GetStartPosition(); - while (pos) { - m_fns.AddTail(fd.GetNextPathName(pos)); - } - - if (!m_fns.IsEmpty()) { - if (s.fKeepHistory) { - s.lastQuickOpenPath = PathUtils::DirName(m_fns.GetHead()); - } - - if (m_fns.GetCount() > 1) { - m_bMultipleFiles = true; - EndDialog(IDOK); - return; - } else if (m_fns.GetHead()[m_fns.GetHead().GetLength() - 1] == '\\' || m_fns.GetHead()[m_fns.GetHead().GetLength() - 1] == '*') { - m_bMultipleFiles = true; - EndDialog(IDOK); - return; - } - } - - m_cbMRU.SetWindowText(fd.GetPathName()); -} - -void COpenDlg::OnBrowseDubFile() -{ - UpdateData(); - - const CAppSettings& s = AfxGetAppSettings(); - - CString filter; - CAtlArray mask; - s.m_Formats.GetAudioFilter(filter, mask); - - DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR; - if (!s.fKeepHistory) { - dwFlags |= OFN_DONTADDTORECENT; - } - - COpenFileDlg fd(mask, false, nullptr, m_pathDub, dwFlags, filter, this); - if (m_pathDub.IsEmpty() && s.fKeepHistory && !s.lastQuickOpenPath.IsEmpty()) { - fd.m_ofn.lpstrInitialDir = s.lastQuickOpenPath; - } - if (fd.DoModal() != IDOK) { - return; - } - - m_cbMRUDub.SetWindowText(fd.GetPathName()); -} - -void COpenDlg::OnOk() -{ - UpdateData(); - - m_fns.RemoveAll(); - m_fns.AddTail(PathUtils::Unquote(m_path)); - if (m_cbMRUDub.IsWindowEnabled() && !m_pathDub.IsEmpty()) { - m_fns.AddTail(PathUtils::Unquote(m_pathDub)); - } - - m_bMultipleFiles = false; - - OnOK(); -} - -void COpenDlg::OnUpdateDub(CCmdUI* pCmdUI) -{ - UpdateData(); - pCmdUI->Enable(AfxGetAppSettings().m_Formats.GetEngine(m_path) == DirectShow); -} - -void COpenDlg::OnUpdateOk(CCmdUI* pCmdUI) -{ - UpdateData(); - pCmdUI->Enable(!m_path.IsEmpty() || !m_pathDub.IsEmpty()); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include +#include "mplayerc.h" +#include "PathUtils.h" +#include "OpenDlg.h" +#include "OpenFileDlg.h" + + +// COpenDlg dialog + +//IMPLEMENT_DYNAMIC(COpenDlg, CMPCThemeResizableDialog) +COpenDlg::COpenDlg(CWnd* pParent /*=nullptr*/) + : CMPCThemeResizableDialog(COpenDlg::IDD, pParent) + , m_bAppendToPlaylist(FALSE) + , m_bMultipleFiles(false) +{ +} + +COpenDlg::~COpenDlg() +{ +} + +void COpenDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDR_MAINFRAME, m_icon); + DDX_Control(pDX, IDC_COMBO1, m_cbMRU); + DDX_CBString(pDX, IDC_COMBO1, m_path); + DDX_Control(pDX, IDC_COMBO2, m_cbMRUDub); + DDX_CBString(pDX, IDC_COMBO2, m_pathDub); + DDX_Control(pDX, IDC_STATIC1, m_labelDub); + DDX_Check(pDX, IDC_CHECK1, m_bAppendToPlaylist); + fulfillThemeReqs(); +} + + +BEGIN_MESSAGE_MAP(COpenDlg, CMPCThemeResizableDialog) + ON_BN_CLICKED(IDC_BUTTON1, OnBrowseFile) + ON_BN_CLICKED(IDC_BUTTON2, OnBrowseDubFile) + ON_BN_CLICKED(IDOK, OnOk) + ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateDub) + ON_UPDATE_COMMAND_UI(IDC_COMBO2, OnUpdateDub) + ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateDub) + ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOk) +END_MESSAGE_MAP() + + +// COpenDlg message handlers + +BOOL COpenDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + m_icon.SetIcon((HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED)); + + CAppSettings& s = AfxGetAppSettings(); + + auto& MRU = s.MRU; + MRU.ReadMediaHistory(); + m_cbMRU.ResetContent(); + for (int i = 0; i < MRU.GetSize(); i++) { + if (MRU[i].fns.GetCount() >0 && !MRU[i].fns.GetHead().IsEmpty()) { + m_cbMRU.AddString(MRU[i].fns.GetHead()); + } + } + CorrectComboListWidth(m_cbMRU); + + CRecentFileList& MRUDub = s.MRUDub; + MRUDub.ReadList(); + m_cbMRUDub.ResetContent(); + for (int i = 0; i < MRUDub.GetSize(); i++) { + if (!MRUDub[i].IsEmpty()) { + m_cbMRUDub.AddString(MRUDub[i]); + } + } + CorrectComboListWidth(m_cbMRUDub); + + if (m_cbMRU.GetCount() > 0) { + m_cbMRU.SetCurSel(0); + } + + m_fns.RemoveAll(); + m_path.Empty(); + m_pathDub.Empty(); + m_bMultipleFiles = false; + m_bAppendToPlaylist = FALSE; + + AddAnchor(m_cbMRU, TOP_LEFT, TOP_RIGHT); + AddAnchor(m_cbMRUDub, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_BUTTON1, TOP_RIGHT); + AddAnchor(IDC_BUTTON2, TOP_RIGHT); + AddAnchor(IDOK, TOP_RIGHT); + AddAnchor(IDCANCEL, TOP_RIGHT); + AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); + + CRect r; + GetWindowRect(r); + CSize size = r.Size(); + SetMinTrackSize(size); + size.cx = 1000; + SetMaxTrackSize(size); + + fulfillThemeReqs(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +static CString GetFileName(CString str) +{ + CPath p = str; + p.StripPath(); + return (LPCTSTR)p; +} + +void COpenDlg::OnBrowseFile() +{ + UpdateData(); + + CAppSettings& s = AfxGetAppSettings(); + + CString filter; + CAtlArray mask; + s.m_Formats.GetFilter(filter, mask); + + DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR; + if (!s.fKeepHistory) { + dwFlags |= OFN_DONTADDTORECENT; + } + + COpenFileDlg fd(mask, true, nullptr, m_path, dwFlags, filter, this); + if (m_path.IsEmpty() && s.fKeepHistory && !s.lastQuickOpenPath.IsEmpty()) { + fd.m_ofn.lpstrInitialDir = s.lastQuickOpenPath; + } + if (fd.DoModal() != IDOK) { + return; + } + + m_fns.RemoveAll(); + + POSITION pos = fd.GetStartPosition(); + while (pos) { + m_fns.AddTail(fd.GetNextPathName(pos)); + } + + if (!m_fns.IsEmpty()) { + if (s.fKeepHistory) { + s.lastQuickOpenPath = PathUtils::DirName(m_fns.GetHead()); + } + + if (m_fns.GetCount() > 1) { + m_bMultipleFiles = true; + EndDialog(IDOK); + return; + } else if (m_fns.GetHead()[m_fns.GetHead().GetLength() - 1] == '\\' || m_fns.GetHead()[m_fns.GetHead().GetLength() - 1] == '*') { + m_bMultipleFiles = true; + EndDialog(IDOK); + return; + } + } + + m_cbMRU.SetWindowText(fd.GetPathName()); +} + +void COpenDlg::OnBrowseDubFile() +{ + UpdateData(); + + const CAppSettings& s = AfxGetAppSettings(); + + CString filter; + CAtlArray mask; + s.m_Formats.GetAudioFilter(filter, mask); + + DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR; + if (!s.fKeepHistory) { + dwFlags |= OFN_DONTADDTORECENT; + } + + COpenFileDlg fd(mask, false, nullptr, m_pathDub, dwFlags, filter, this); + if (m_pathDub.IsEmpty() && s.fKeepHistory && !s.lastQuickOpenPath.IsEmpty()) { + fd.m_ofn.lpstrInitialDir = s.lastQuickOpenPath; + } + if (fd.DoModal() != IDOK) { + return; + } + + m_cbMRUDub.SetWindowText(fd.GetPathName()); +} + +void COpenDlg::OnOk() +{ + UpdateData(); + + m_fns.RemoveAll(); + m_fns.AddTail(PathUtils::Unquote(m_path)); + if (m_cbMRUDub.IsWindowEnabled() && !m_pathDub.IsEmpty()) { + m_fns.AddTail(PathUtils::Unquote(m_pathDub)); + } + + m_bMultipleFiles = false; + + OnOK(); +} + +void COpenDlg::OnUpdateDub(CCmdUI* pCmdUI) +{ + UpdateData(); + pCmdUI->Enable(AfxGetAppSettings().m_Formats.GetEngine(m_path) == DirectShow); +} + +void COpenDlg::OnUpdateOk(CCmdUI* pCmdUI) +{ + UpdateData(); + pCmdUI->Enable(!m_path.IsEmpty() || !m_pathDub.IsEmpty()); +} diff --git a/src/mpc-hc/OpenDlg.h b/src/mpc-hc/OpenDlg.h index b1ecd01168f..07902266c95 100644 --- a/src/mpc-hc/OpenDlg.h +++ b/src/mpc-hc/OpenDlg.h @@ -1,68 +1,68 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "resource.h" -#include "CMPCThemeResizableDialog.h" -#include "CMPCThemeStatic.h" -#include "CMPCThemeComboBox.h" - -// COpenDlg dialog - -class COpenDlg : public CMPCThemeResizableDialog -{ - // DECLARE_DYNAMIC(COpenDlg) -private: - CStatic m_icon; - CMPCThemeComboBox m_cbMRU; - CString m_path; - CMPCThemeComboBox m_cbMRUDub; - CString m_pathDub; - CMPCThemeStatic m_labelDub; - BOOL m_bAppendToPlaylist; - - bool m_bMultipleFiles; - CAtlList m_fns; - -public: - COpenDlg(CWnd* pParent = nullptr); - virtual ~COpenDlg(); - - // Dialog Data - enum { IDD = IDD_OPEN_DLG }; - - const CAtlList& GetFileNames() const { return m_fns; } - bool HasMultipleFiles() const { return m_bMultipleFiles; } - bool GetAppendToPlaylist() const { return !!m_bAppendToPlaylist; } - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - - DECLARE_MESSAGE_MAP() - - afx_msg void OnBrowseFile(); - afx_msg void OnBrowseDubFile(); - afx_msg void OnOk(); - afx_msg void OnUpdateDub(CCmdUI* pCmdUI); - afx_msg void OnUpdateOk(CCmdUI* pCmdUI); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "resource.h" +#include "CMPCThemeResizableDialog.h" +#include "CMPCThemeStatic.h" +#include "CMPCThemeComboBox.h" + +// COpenDlg dialog + +class COpenDlg : public CMPCThemeResizableDialog +{ + // DECLARE_DYNAMIC(COpenDlg) +private: + CStatic m_icon; + CMPCThemeComboBox m_cbMRU; + CString m_path; + CMPCThemeComboBox m_cbMRUDub; + CString m_pathDub; + CMPCThemeStatic m_labelDub; + BOOL m_bAppendToPlaylist; + + bool m_bMultipleFiles; + CAtlList m_fns; + +public: + COpenDlg(CWnd* pParent = nullptr); + virtual ~COpenDlg(); + + // Dialog Data + enum { IDD = IDD_OPEN_DLG }; + + const CAtlList& GetFileNames() const { return m_fns; } + bool HasMultipleFiles() const { return m_bMultipleFiles; } + bool GetAppendToPlaylist() const { return !!m_bAppendToPlaylist; } + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnBrowseFile(); + afx_msg void OnBrowseDubFile(); + afx_msg void OnOk(); + afx_msg void OnUpdateDub(CCmdUI* pCmdUI); + afx_msg void OnUpdateOk(CCmdUI* pCmdUI); +}; diff --git a/src/mpc-hc/OpenFileDlg.cpp b/src/mpc-hc/OpenFileDlg.cpp index f7bdc68cd10..910119038a2 100644 --- a/src/mpc-hc/OpenFileDlg.cpp +++ b/src/mpc-hc/OpenFileDlg.cpp @@ -1,237 +1,237 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "OpenFileDlg.h" - -#define __DUMMY__ _T("*.*") - -bool COpenFileDlg::m_fAllowDirSelection = false; -WNDPROC COpenFileDlg::m_wndProc = nullptr; - - -// COpenFileDlg - -IMPLEMENT_DYNAMIC(COpenFileDlg, CFileDialog) -COpenFileDlg::COpenFileDlg(CAtlArray& mask, bool fAllowDirSelection, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, - DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) - : CFileDialog(TRUE, lpszDefExt, lpszFileName, dwFlags | OFN_NOVALIDATE, lpszFilter, pParentWnd, 0) - , m_mask(mask) -{ - m_defaultDir = lpszFileName; - m_defaultDir.RemoveFileSpec(); - - m_fAllowDirSelection = fAllowDirSelection; - m_pOFN->lpstrInitialDir = m_defaultDir.FileExists() ? (LPCTSTR)m_defaultDir : nullptr; - - m_buff = DEBUG_NEW TCHAR[10000]; - m_buff[0] = 0; - m_pOFN->lpstrFile = m_buff; - m_pOFN->nMaxFile = 10000; -} - -COpenFileDlg::~COpenFileDlg() -{ - delete [] m_buff; -} - -BEGIN_MESSAGE_MAP(COpenFileDlg, CFileDialog) - ON_WM_DESTROY() -END_MESSAGE_MAP() - - -// COpenFileDlg message handlers - -LRESULT CALLBACK COpenFileDlg::WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK - && m_fAllowDirSelection) { - CAutoVectorPtr path; - // MAX_PATH should be bigger for multiple selection, but we are only interested if it's zero length - // note: allocating MAX_PATH only will cause a buffer overrun for too long strings, and will result in a silent app disappearing crash, 100% reproducible - if (path.Allocate(MAX_PATH + 1) && ::GetDlgItemText(hwnd, cmb13, (TCHAR*)path, MAX_PATH) == 0) { - ::SendMessage(hwnd, CDM_SETCONTROLTEXT, edt1, (LPARAM)__DUMMY__); - } - } - - return CallWindowProc(COpenFileDlg::m_wndProc, hwnd, message, wParam, lParam); -} - -BOOL COpenFileDlg::OnInitDialog() -{ - CFileDialog::OnInitDialog(); - - m_wndProc = (WNDPROC)SetWindowLongPtr(GetParent()->m_hWnd, GWLP_WNDPROC, (LONG_PTR)WindowProcNew); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void COpenFileDlg::OnDestroy() -{ - int i = GetPathName().Find(__DUMMY__); - if (i >= 0) { - m_pOFN->lpstrFile[i] = m_pOFN->lpstrFile[i + 1] = 0; - } - - CFileDialog::OnDestroy(); -} - -BOOL COpenFileDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) -{ - ASSERT(pResult != nullptr); - - OFNOTIFY* pNotify = (OFNOTIFY*)lParam; - // allow message map to override - if (__super::OnNotify(wParam, lParam, pResult)) { - ASSERT(pNotify->hdr.code != CDN_INCLUDEITEM); - return TRUE; - } - - switch (pNotify->hdr.code) { - case CDN_INCLUDEITEM: - if (OnIncludeItem((OFNOTIFYEX*)lParam, pResult)) { - return TRUE; - } - break; - } - - return FALSE; // not handled -} - -BOOL COpenFileDlg::OnIncludeItem(OFNOTIFYEX* pOFNEx, LRESULT* pResult) -{ - CString fn; - if (!SHGetPathFromIDList((PIDLIST_ABSOLUTE)pOFNEx->pidl, fn.GetBuffer(MAX_PATH))) { - fn.ReleaseBuffer(0); - IShellFolder* psf = (IShellFolder*)pOFNEx->psf; - PCUITEMID_CHILD pidl = (PCUITEMID_CHILD)pOFNEx->pidl; - STRRET s; - CComHeapPtr fnTmp; - if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &s)) - && SUCCEEDED(StrRetToStr(&s, pidl, &fnTmp))) { - fn = fnTmp; - } - } else { - fn.ReleaseBuffer(); - } - - /* - WIN32_FILE_ATTRIBUTE_DATA fad; - if (GetFileAttributesEx(fn, GetFileExInfoStandard, &fad) - && (fad.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) - return FALSE; - */ - int i = fn.ReverseFind('.'), j = fn.ReverseFind('\\'); - if (i < 0 || i < j) { - return FALSE; - } - - CString mask = m_mask[pOFNEx->lpOFN->nFilterIndex - 1] + _T(";"); - CString ext = fn.Mid(i).MakeLower() + _T(";"); - - *pResult = mask.Find(ext) >= 0 || mask.Find(_T("*.*")) >= 0; - - return TRUE; -} - -// override CFileDialog::GetNextPathName() and increase max path length -CString COpenFileDlg::GetNextPathName(POSITION& pos) const -{ - BOOL bExplorer = m_ofn.Flags & OFN_EXPLORER; - TCHAR chDelimiter; - if (bExplorer) - chDelimiter = '\0'; - else - chDelimiter = ' '; - - LPTSTR lpsz = (LPTSTR)pos; - if (lpsz == m_ofn.lpstrFile) // first time - { - if ((m_ofn.Flags & OFN_ALLOWMULTISELECT) == 0) - { - pos = NULL; - return m_ofn.lpstrFile; - } - - // find char pos after first Delimiter - while (*lpsz != chDelimiter && *lpsz != '\0') - lpsz = _tcsinc(lpsz); - lpsz = _tcsinc(lpsz); - - // if single selection then return only selection - if (*lpsz == 0) - { - pos = NULL; - return m_ofn.lpstrFile; - } - } - - CString strBasePath = m_ofn.lpstrFile; - if (!bExplorer) - { - LPTSTR lpszPath = m_ofn.lpstrFile; - while (*lpszPath != chDelimiter) - lpszPath = _tcsinc(lpszPath); - strBasePath = strBasePath.Left(int(lpszPath - m_ofn.lpstrFile)); - } - - LPTSTR lpszFileName = lpsz; - CString strFileName = lpsz; - - // find char pos at next Delimiter - while (*lpsz != chDelimiter && *lpsz != '\0') - lpsz = _tcsinc(lpsz); - - if (!bExplorer && *lpsz == '\0') - pos = NULL; - else - { - if (!bExplorer) - strFileName = strFileName.Left(int(lpsz - lpszFileName)); - - lpsz = _tcsinc(lpsz); - if (*lpsz == '\0') // if double terminated then done - pos = NULL; - else - pos = (POSITION)lpsz; - } - - TCHAR strDrive[_MAX_DRIVE], strDir[4 * _MAX_DIR], strName[4 * _MAX_FNAME], strExt[_MAX_EXT]; - Checked::tsplitpath_s(strFileName, strDrive, _MAX_DRIVE, strDir, 4 * _MAX_DIR, strName, 4 * _MAX_FNAME, strExt, _MAX_EXT); - TCHAR strPath[4 * _MAX_PATH]; - if (*strDrive || *strDir) - { - Checked::tcscpy_s(strPath, _countof(strPath), strFileName); - } else - { - if ((strBasePath.GetLength() != 3) || (strBasePath[1] != ':') || (strBasePath[2] != '\\')) - { - strBasePath += _T("\\"); - } - Checked::tsplitpath_s(strBasePath, strDrive, _MAX_DRIVE, strDir, 4 * _MAX_DIR, NULL, 0, NULL, 0); - Checked::tmakepath_s(strPath, 4 * _MAX_PATH, strDrive, strDir, strName, strExt); - } - - return strPath; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "OpenFileDlg.h" + +#define __DUMMY__ _T("*.*") + +bool COpenFileDlg::m_fAllowDirSelection = false; +WNDPROC COpenFileDlg::m_wndProc = nullptr; + + +// COpenFileDlg + +IMPLEMENT_DYNAMIC(COpenFileDlg, CFileDialog) +COpenFileDlg::COpenFileDlg(CAtlArray& mask, bool fAllowDirSelection, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, + DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) + : CFileDialog(TRUE, lpszDefExt, lpszFileName, dwFlags | OFN_NOVALIDATE, lpszFilter, pParentWnd, 0) + , m_mask(mask) +{ + m_defaultDir = lpszFileName; + m_defaultDir.RemoveFileSpec(); + + m_fAllowDirSelection = fAllowDirSelection; + m_pOFN->lpstrInitialDir = m_defaultDir.FileExists() ? (LPCTSTR)m_defaultDir : nullptr; + + m_buff = DEBUG_NEW TCHAR[10000]; + m_buff[0] = 0; + m_pOFN->lpstrFile = m_buff; + m_pOFN->nMaxFile = 10000; +} + +COpenFileDlg::~COpenFileDlg() +{ + delete [] m_buff; +} + +BEGIN_MESSAGE_MAP(COpenFileDlg, CFileDialog) + ON_WM_DESTROY() +END_MESSAGE_MAP() + + +// COpenFileDlg message handlers + +LRESULT CALLBACK COpenFileDlg::WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK + && m_fAllowDirSelection) { + CAutoVectorPtr path; + // MAX_PATH should be bigger for multiple selection, but we are only interested if it's zero length + // note: allocating MAX_PATH only will cause a buffer overrun for too long strings, and will result in a silent app disappearing crash, 100% reproducible + if (path.Allocate(MAX_PATH + 1) && ::GetDlgItemText(hwnd, cmb13, (TCHAR*)path, MAX_PATH) == 0) { + ::SendMessage(hwnd, CDM_SETCONTROLTEXT, edt1, (LPARAM)__DUMMY__); + } + } + + return CallWindowProc(COpenFileDlg::m_wndProc, hwnd, message, wParam, lParam); +} + +BOOL COpenFileDlg::OnInitDialog() +{ + CFileDialog::OnInitDialog(); + + m_wndProc = (WNDPROC)SetWindowLongPtr(GetParent()->m_hWnd, GWLP_WNDPROC, (LONG_PTR)WindowProcNew); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void COpenFileDlg::OnDestroy() +{ + int i = GetPathName().Find(__DUMMY__); + if (i >= 0) { + m_pOFN->lpstrFile[i] = m_pOFN->lpstrFile[i + 1] = 0; + } + + CFileDialog::OnDestroy(); +} + +BOOL COpenFileDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + ASSERT(pResult != nullptr); + + OFNOTIFY* pNotify = (OFNOTIFY*)lParam; + // allow message map to override + if (__super::OnNotify(wParam, lParam, pResult)) { + ASSERT(pNotify->hdr.code != CDN_INCLUDEITEM); + return TRUE; + } + + switch (pNotify->hdr.code) { + case CDN_INCLUDEITEM: + if (OnIncludeItem((OFNOTIFYEX*)lParam, pResult)) { + return TRUE; + } + break; + } + + return FALSE; // not handled +} + +BOOL COpenFileDlg::OnIncludeItem(OFNOTIFYEX* pOFNEx, LRESULT* pResult) +{ + CString fn; + if (!SHGetPathFromIDList((PIDLIST_ABSOLUTE)pOFNEx->pidl, fn.GetBuffer(MAX_PATH))) { + fn.ReleaseBuffer(0); + IShellFolder* psf = (IShellFolder*)pOFNEx->psf; + PCUITEMID_CHILD pidl = (PCUITEMID_CHILD)pOFNEx->pidl; + STRRET s; + CComHeapPtr fnTmp; + if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &s)) + && SUCCEEDED(StrRetToStr(&s, pidl, &fnTmp))) { + fn = fnTmp; + } + } else { + fn.ReleaseBuffer(); + } + + /* + WIN32_FILE_ATTRIBUTE_DATA fad; + if (GetFileAttributesEx(fn, GetFileExInfoStandard, &fad) + && (fad.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) + return FALSE; + */ + int i = fn.ReverseFind('.'), j = fn.ReverseFind('\\'); + if (i < 0 || i < j) { + return FALSE; + } + + CString mask = m_mask[pOFNEx->lpOFN->nFilterIndex - 1] + _T(";"); + CString ext = fn.Mid(i).MakeLower() + _T(";"); + + *pResult = mask.Find(ext) >= 0 || mask.Find(_T("*.*")) >= 0; + + return TRUE; +} + +// override CFileDialog::GetNextPathName() and increase max path length +CString COpenFileDlg::GetNextPathName(POSITION& pos) const +{ + BOOL bExplorer = m_ofn.Flags & OFN_EXPLORER; + TCHAR chDelimiter; + if (bExplorer) + chDelimiter = '\0'; + else + chDelimiter = ' '; + + LPTSTR lpsz = (LPTSTR)pos; + if (lpsz == m_ofn.lpstrFile) // first time + { + if ((m_ofn.Flags & OFN_ALLOWMULTISELECT) == 0) + { + pos = NULL; + return m_ofn.lpstrFile; + } + + // find char pos after first Delimiter + while (*lpsz != chDelimiter && *lpsz != '\0') + lpsz = _tcsinc(lpsz); + lpsz = _tcsinc(lpsz); + + // if single selection then return only selection + if (*lpsz == 0) + { + pos = NULL; + return m_ofn.lpstrFile; + } + } + + CString strBasePath = m_ofn.lpstrFile; + if (!bExplorer) + { + LPTSTR lpszPath = m_ofn.lpstrFile; + while (*lpszPath != chDelimiter) + lpszPath = _tcsinc(lpszPath); + strBasePath = strBasePath.Left(int(lpszPath - m_ofn.lpstrFile)); + } + + LPTSTR lpszFileName = lpsz; + CString strFileName = lpsz; + + // find char pos at next Delimiter + while (*lpsz != chDelimiter && *lpsz != '\0') + lpsz = _tcsinc(lpsz); + + if (!bExplorer && *lpsz == '\0') + pos = NULL; + else + { + if (!bExplorer) + strFileName = strFileName.Left(int(lpsz - lpszFileName)); + + lpsz = _tcsinc(lpsz); + if (*lpsz == '\0') // if double terminated then done + pos = NULL; + else + pos = (POSITION)lpsz; + } + + TCHAR strDrive[_MAX_DRIVE], strDir[4 * _MAX_DIR], strName[4 * _MAX_FNAME], strExt[_MAX_EXT]; + Checked::tsplitpath_s(strFileName, strDrive, _MAX_DRIVE, strDir, 4 * _MAX_DIR, strName, 4 * _MAX_FNAME, strExt, _MAX_EXT); + TCHAR strPath[4 * _MAX_PATH]; + if (*strDrive || *strDir) + { + Checked::tcscpy_s(strPath, _countof(strPath), strFileName); + } else + { + if ((strBasePath.GetLength() != 3) || (strBasePath[1] != ':') || (strBasePath[2] != '\\')) + { + strBasePath += _T("\\"); + } + Checked::tsplitpath_s(strBasePath, strDrive, _MAX_DRIVE, strDir, 4 * _MAX_DIR, NULL, 0, NULL, 0); + Checked::tmakepath_s(strPath, 4 * _MAX_PATH, strDrive, strDir, strName, strExt); + } + + return strPath; +} diff --git a/src/mpc-hc/OpenFileDlg.h b/src/mpc-hc/OpenFileDlg.h index 4b4d7089eb4..f9cb428e381 100644 --- a/src/mpc-hc/OpenFileDlg.h +++ b/src/mpc-hc/OpenFileDlg.h @@ -1,62 +1,62 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include - - -// COpenFileDlg - -class COpenFileDlg : public CFileDialog -{ - DECLARE_DYNAMIC(COpenFileDlg) - -private: - TCHAR* m_buff; - CAtlArray& m_mask; - CPath m_defaultDir; - -public: - COpenFileDlg(CAtlArray& mask, bool fAllowDirSelection, - LPCTSTR lpszDefExt = nullptr, - LPCTSTR lpszFileName = nullptr, - DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, - LPCTSTR lpszFilter = nullptr, - CWnd* pParentWnd = nullptr); - virtual ~COpenFileDlg(); - - static bool m_fAllowDirSelection; - static WNDPROC m_wndProc; - static LRESULT CALLBACK WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - - virtual BOOL OnInitDialog(); - -protected: - DECLARE_MESSAGE_MAP() - virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); - virtual BOOL OnIncludeItem(OFNOTIFYEX* pOFNEx, LRESULT* pResult); - -public: - afx_msg void OnDestroy(); - CString GetNextPathName(POSITION& pos) const; -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include + + +// COpenFileDlg + +class COpenFileDlg : public CFileDialog +{ + DECLARE_DYNAMIC(COpenFileDlg) + +private: + TCHAR* m_buff; + CAtlArray& m_mask; + CPath m_defaultDir; + +public: + COpenFileDlg(CAtlArray& mask, bool fAllowDirSelection, + LPCTSTR lpszDefExt = nullptr, + LPCTSTR lpszFileName = nullptr, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + LPCTSTR lpszFilter = nullptr, + CWnd* pParentWnd = nullptr); + virtual ~COpenFileDlg(); + + static bool m_fAllowDirSelection; + static WNDPROC m_wndProc; + static LRESULT CALLBACK WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + + virtual BOOL OnInitDialog(); + +protected: + DECLARE_MESSAGE_MAP() + virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); + virtual BOOL OnIncludeItem(OFNOTIFYEX* pOFNEx, LRESULT* pResult); + +public: + afx_msg void OnDestroy(); + CString GetNextPathName(POSITION& pos) const; +}; diff --git a/src/mpc-hc/PPageAccelTbl.cpp b/src/mpc-hc/PPageAccelTbl.cpp index 486babd6eb9..42b65b29966 100644 --- a/src/mpc-hc/PPageAccelTbl.cpp +++ b/src/mpc-hc/PPageAccelTbl.cpp @@ -1,1452 +1,1452 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "PPageAccelTbl.h" -#include "AppSettings.h" - -#define DUP_KEY (1<<12) -#define DUP_APPCMD (1<<13) -#define DUP_RMCMD (1<<14) -#define MASK_DUP (DUP_KEY|DUP_APPCMD|DUP_RMCMD) - -struct APP_COMMAND { - UINT appcmd; - LPCTSTR cmdname; -}; - -static constexpr APP_COMMAND g_CommandList[] = { - {0, _T("")}, - {APPCOMMAND_MEDIA_PLAY_PAUSE, _T("MEDIA_PLAY_PAUSE")}, - {APPCOMMAND_MEDIA_PLAY, _T("MEDIA_PLAY")}, - {APPCOMMAND_MEDIA_PAUSE, _T("MEDIA_PAUSE")}, - {APPCOMMAND_MEDIA_STOP, _T("MEDIA_STOP")}, - {APPCOMMAND_MEDIA_NEXTTRACK, _T("MEDIA_NEXTTRACK")}, - {APPCOMMAND_MEDIA_PREVIOUSTRACK, _T("MEDIA_PREVIOUSTRACK")}, - {APPCOMMAND_MEDIA_FAST_FORWARD, _T("MEDIA_FAST_FORWARD")}, - {APPCOMMAND_MEDIA_REWIND, _T("MEDIA_REWIND")}, - {APPCOMMAND_MEDIA_CHANNEL_UP, _T("MEDIA_CHANNEL_UP")}, - {APPCOMMAND_MEDIA_CHANNEL_DOWN, _T("MEDIA_CHANNEL_DOWN")}, - {APPCOMMAND_MEDIA_RECORD, _T("MEDIA_RECORD")}, - {APPCOMMAND_VOLUME_DOWN, _T("VOLUME_DOWN")}, - {APPCOMMAND_VOLUME_UP, _T("VOLUME_UP")}, - {APPCOMMAND_VOLUME_MUTE, _T("VOLUME_MUTE")}, - {APPCOMMAND_LAUNCH_MEDIA_SELECT, _T("LAUNCH_MEDIA_SELECT")}, - /* - {APPCOMMAND_BROWSER_BACKWARD, _T("BROWSER_BACKWARD")}, - {APPCOMMAND_BROWSER_FORWARD, _T("BROWSER_FORWARD")}, - {APPCOMMAND_BROWSER_REFRESH, _T("BROWSER_REFRESH")}, - {APPCOMMAND_BROWSER_STOP, _T("BROWSER_STOP")}, - {APPCOMMAND_BROWSER_SEARCH, _T("BROWSER_SEARCH")}, - {APPCOMMAND_BROWSER_FAVORITES, _T("BROWSER_FAVORITES")}, - {APPCOMMAND_BROWSER_HOME, _T("BROWSER_HOME")}, - */ - {APPCOMMAND_LAUNCH_APP1, _T("LAUNCH_APP1")}, - {APPCOMMAND_LAUNCH_APP2, _T("LAUNCH_APP2")}, - {APPCOMMAND_OPEN, _T("OPEN")}, - {APPCOMMAND_CLOSE, _T("CLOSE")}, - {APPCOMMAND_DELETE, _T("DELETE")}, - {MCE_DETAILS, _T("MCE_DETAILS")}, - {MCE_GUIDE, _T("MCE_GUIDE")}, - {MCE_TVJUMP, _T("MCE_TVJUMP")}, - {MCE_STANDBY, _T("MCE_STANDBY")}, - {MCE_OEM1, _T("MCE_OEM1")}, - {MCE_OEM2, _T("MCE_OEM2")}, - {MCE_MYTV, _T("MCE_MYTV")}, - {MCE_MYVIDEOS, _T("MCE_MYVIDEOS")}, - {MCE_MYPICTURES, _T("MCE_MYPICTURES")}, - {MCE_MYMUSIC, _T("MCE_MYMUSIC")}, - {MCE_RECORDEDTV, _T("MCE_RECORDEDTV")}, - {MCE_DVDANGLE, _T("MCE_DVDANGLE")}, - {MCE_DVDAUDIO, _T("MCE_DVDAUDIO")}, - {MCE_DVDMENU, _T("MCE_DVDMENU")}, - {MCE_DVDSUBTITLE, _T("MCE_DVDSUBTITLE")}, - {MCE_RED, _T("MCE_RED")}, - {MCE_GREEN, _T("MCE_GREEN")}, - {MCE_YELLOW, _T("MCE_YELLOW")}, - {MCE_BLUE, _T("MCE_BLUE")}, - {MCE_MEDIA_NEXTTRACK, _T("MCE_MEDIA_NEXTTRACK")}, - {MCE_MEDIA_PREVIOUSTRACK, _T("MCE_MEDIA_PREVIOUSTRACK")} -}; - -// CPPageAccelTbl dialog - -IMPLEMENT_DYNAMIC(CPPageAccelTbl, CMPCThemePPageBase) -CPPageAccelTbl::CPPageAccelTbl() - : CMPCThemePPageBase(CPPageAccelTbl::IDD, CPPageAccelTbl::IDD) - , m_counter(0) - , m_list(0) - , m_fWinLirc(FALSE) - , m_WinLircLink(_T("http://winlirc.sourceforge.net/")) - , m_fUIce(FALSE) - , m_UIceLink(L"https://web.archive.org/web/20160609195532/http://www.mediatexx.com/") // home site no longer works - , m_nStatusTimerID(0) - , filterTimerID(0) - , sortDirection(HDF_SORTUP) - , m_fGlobalMedia(FALSE) -{ -} - -CPPageAccelTbl::~CPPageAccelTbl() -{ -} - -BOOL CPPageAccelTbl::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN - && (pMsg->hwnd == m_WinLircEdit.m_hWnd || pMsg->hwnd == m_UIceEdit.m_hWnd)) { - OnApply(); - return TRUE; - } - - return __super::PreTranslateMessage(pMsg); -} - -void CPPageAccelTbl::UpdateKeyDupFlags() -{ - for (int row = 0; row < m_list.GetItemCount(); row++) { - auto itemData = (ITEMDATA*)m_list.GetItemData(row); - const wmcmd& wc = m_wmcmds.GetAt(itemData->index); - - itemData->flag &= ~DUP_KEY; - - if (wc.key) { - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; m_wmcmds.GetNext(pos)) { - if (itemData->index == pos) { continue; } - - if (wc.key == m_wmcmds.GetAt(pos).key && (wc.fVirt & (FCONTROL | FALT | FSHIFT)) == (m_wmcmds.GetAt(pos).fVirt & (FCONTROL | FALT | FSHIFT))) { - itemData->flag |= DUP_KEY; - break; - } - } - } - } -} - -void CPPageAccelTbl::UpdateAppcmdDupFlags() -{ - for (int row = 0; row < m_list.GetItemCount(); row++) { - auto itemData = (ITEMDATA*)m_list.GetItemData(row); - const wmcmd& wc = m_wmcmds.GetAt(itemData->index); - - itemData->flag &= ~DUP_APPCMD; - - if (wc.appcmd) { - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; m_wmcmds.GetNext(pos)) { - if (itemData->index == pos) { continue; } - - if (wc.appcmd == m_wmcmds.GetAt(pos).appcmd) { - itemData->flag |= DUP_APPCMD; - break; - } - } - } - } -} - -void CPPageAccelTbl::UpdateRmcmdDupFlags() -{ - for (int row = 0; row < m_list.GetItemCount(); row++) { - auto itemData = (ITEMDATA*)m_list.GetItemData(row); - const wmcmd& wc = m_wmcmds.GetAt(itemData->index); - - itemData->flag &= ~DUP_RMCMD; - - if (wc.rmcmd.GetLength()) { - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; m_wmcmds.GetNext(pos)) { - if (itemData->index == pos) { continue; } - - if (wc.rmcmd.CompareNoCase(m_wmcmds.GetAt(pos).rmcmd) == 0) { - itemData->flag |= DUP_RMCMD; - break; - } - } - } - } -} - -void CPPageAccelTbl::UpdateAllDupFlags() -{ - UpdateKeyDupFlags(); - UpdateAppcmdDupFlags(); - UpdateRmcmdDupFlags(); -} - -void CPPageAccelTbl::SetupList(bool allowResize) -{ - for (int row = 0; row < m_list.GetItemCount(); row++) { - wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(row))->index); - - CString hotkey; - HotkeyModToString(wc.key, wc.fVirt, hotkey); - m_list.SetItemText(row, COL_KEY, hotkey); - - CString id; - id.Format(_T("%u"), wc.cmd); - m_list.SetItemText(row, COL_ID, id); - - m_list.SetItemText(row, COL_APPCMD, MakeAppCommandLabel(wc.appcmd)); - - m_list.SetItemText(row, COL_RMCMD, CString(wc.rmcmd)); - - CString repcnt; - repcnt.Format(_T("%d"), wc.rmrepcnt); - m_list.SetItemText(row, COL_RMREPCNT, repcnt); - } - - UpdateAllDupFlags(); - - if (allowResize) { - for (int nCol = COL_CMD; nCol <= COL_RMREPCNT; nCol++) { - m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE); - int contentSize = m_list.GetColumnWidth(nCol); - m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE_USEHEADER); - if (contentSize > m_list.GetColumnWidth(nCol)) { - m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE); - } - } - for (int nCol = COL_CMD; nCol <= COL_RMREPCNT; nCol++) { - int contentSize = m_list.GetColumnWidth(nCol); - m_list.SetColumnWidth(nCol, contentSize); - } - } -} - -CString CPPageAccelTbl::MakeAccelModLabel(BYTE fVirt) -{ - CString str; - if (fVirt & FCONTROL) { - if (!str.IsEmpty()) { - str += _T(" + "); - } - str += _T("Ctrl"); - } - if (fVirt & FALT) { - if (!str.IsEmpty()) { - str += _T(" + "); - } - str += _T("Alt"); - } - if (fVirt & FSHIFT) { - if (!str.IsEmpty()) { - str += _T(" + "); - } - str += _T("Shift"); - } - if (str.IsEmpty()) { - str.LoadString(IDS_AG_NONE); - } - return str; -} - -CString CPPageAccelTbl::MakeAccelShortcutLabel(UINT id) -{ - CList& wmcmds = AfxGetAppSettings().wmcmds; - POSITION pos = wmcmds.GetHeadPosition(); - while (pos) { - ACCEL& a = wmcmds.GetNext(pos); - if (a.cmd == id) { - return (MakeAccelShortcutLabel(a)); - } - } - - return _T(""); -} - -CString CPPageAccelTbl::MakeAccelShortcutLabel(const ACCEL& a) -{ - if (!a.key) { - return _T(""); - } - - // Reference page for Virtual-Key Codes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.100%29.aspx - CString str; - - switch (a.key) { - case VK_LBUTTON: - str = _T("LBtn"); - break; - case VK_RBUTTON: - str = _T("RBtn"); - break; - case VK_CANCEL: - str = _T("Cancel"); - break; - case VK_MBUTTON: - str = _T("MBtn"); - break; - case VK_XBUTTON1: - str = _T("X1Btn"); - break; - case VK_XBUTTON2: - str = _T("X2Btn"); - break; - case VK_BACK: - str = _T("Back"); - break; - case VK_TAB: - str = _T("Tab"); - break; - case VK_CLEAR: - str = _T("Clear"); - break; - case VK_RETURN: - str = _T("Enter"); - break; - case VK_SHIFT: - str = _T("Shift"); - break; - case VK_CONTROL: - str = _T("Ctrl"); - break; - case VK_MENU: - str = _T("Alt"); - break; - case VK_PAUSE: - str = _T("Pause"); - break; - case VK_CAPITAL: - str = _T("Capital"); - break; - // case VK_KANA: str = _T("Kana"); break; - // case VK_HANGEUL: str = _T("Hangeul"); break; - case VK_HANGUL: - str = _T("Hangul"); - break; - case VK_JUNJA: - str = _T("Junja"); - break; - case VK_FINAL: - str = _T("Final"); - break; - // case VK_HANJA: str = _T("Hanja"); break; - case VK_KANJI: - str = _T("Kanji"); - break; - case VK_ESCAPE: - str = _T("Escape"); - break; - case VK_CONVERT: - str = _T("Convert"); - break; - case VK_NONCONVERT: - str = _T("Non Convert"); - break; - case VK_ACCEPT: - str = _T("Accept"); - break; - case VK_MODECHANGE: - str = _T("Mode Change"); - break; - case VK_SPACE: - str = _T("Space"); - break; - case VK_PRIOR: - str = _T("PgUp"); - break; - case VK_NEXT: - str = _T("PgDn"); - break; - case VK_END: - str = _T("End"); - break; - case VK_HOME: - str = _T("Home"); - break; - case VK_LEFT: - str = _T("Left"); - break; - case VK_UP: - str = _T("Up"); - break; - case VK_RIGHT: - str = _T("Right"); - break; - case VK_DOWN: - str = _T("Down"); - break; - case VK_SELECT: - str = _T("Select"); - break; - case VK_PRINT: - str = _T("Print"); - break; - case VK_EXECUTE: - str = _T("Execute"); - break; - case VK_SNAPSHOT: - str = _T("Snapshot"); - break; - case VK_INSERT: - str = _T("Insert"); - break; - case VK_DELETE: - str = _T("Delete"); - break; - case VK_HELP: - str = _T("Help"); - break; - case VK_LWIN: - str = _T("LWin"); - break; - case VK_RWIN: - str = _T("RWin"); - break; - case VK_APPS: - str = _T("Apps"); - break; - case VK_SLEEP: - str = _T("Sleep"); - break; - case VK_NUMPAD0: - str = _T("Numpad 0"); - break; - case VK_NUMPAD1: - str = _T("Numpad 1"); - break; - case VK_NUMPAD2: - str = _T("Numpad 2"); - break; - case VK_NUMPAD3: - str = _T("Numpad 3"); - break; - case VK_NUMPAD4: - str = _T("Numpad 4"); - break; - case VK_NUMPAD5: - str = _T("Numpad 5"); - break; - case VK_NUMPAD6: - str = _T("Numpad 6"); - break; - case VK_NUMPAD7: - str = _T("Numpad 7"); - break; - case VK_NUMPAD8: - str = _T("Numpad 8"); - break; - case VK_NUMPAD9: - str = _T("Numpad 9"); - break; - case VK_MULTIPLY: - str = _T("Multiply"); - break; - case VK_ADD: - str = _T("Add"); - break; - case VK_SEPARATOR: - str = _T("Separator"); - break; - case VK_SUBTRACT: - str = _T("Subtract"); - break; - case VK_DECIMAL: - str = _T("Decimal"); - break; - case VK_DIVIDE: - str = _T("Divide"); - break; - case VK_F1: - str = _T("F1"); - break; - case VK_F2: - str = _T("F2"); - break; - case VK_F3: - str = _T("F3"); - break; - case VK_F4: - str = _T("F4"); - break; - case VK_F5: - str = _T("F5"); - break; - case VK_F6: - str = _T("F6"); - break; - case VK_F7: - str = _T("F7"); - break; - case VK_F8: - str = _T("F8"); - break; - case VK_F9: - str = _T("F9"); - break; - case VK_F10: - str = _T("F10"); - break; - case VK_F11: - str = _T("F11"); - break; - case VK_F12: - str = _T("F12"); - break; - case VK_F13: - str = _T("F13"); - break; - case VK_F14: - str = _T("F14"); - break; - case VK_F15: - str = _T("F15"); - break; - case VK_F16: - str = _T("F16"); - break; - case VK_F17: - str = _T("F17"); - break; - case VK_F18: - str = _T("F18"); - break; - case VK_F19: - str = _T("F19"); - break; - case VK_F20: - str = _T("F20"); - break; - case VK_F21: - str = _T("F21"); - break; - case VK_F22: - str = _T("F22"); - break; - case VK_F23: - str = _T("F23"); - break; - case VK_F24: - str = _T("F24"); - break; - case VK_NUMLOCK: - str = _T("Numlock"); - break; - case VK_SCROLL: - str = _T("Scroll"); - break; - // case VK_OEM_NEC_EQUAL: str = _T("OEM NEC Equal"); break; - case VK_OEM_FJ_JISHO: - str = _T("OEM FJ Jisho"); - break; - case VK_OEM_FJ_MASSHOU: - str = _T("OEM FJ Msshou"); - break; - case VK_OEM_FJ_TOUROKU: - str = _T("OEM FJ Touroku"); - break; - case VK_OEM_FJ_LOYA: - str = _T("OEM FJ Loya"); - break; - case VK_OEM_FJ_ROYA: - str = _T("OEM FJ Roya"); - break; - case VK_LSHIFT: - str = _T("LShift"); - break; - case VK_RSHIFT: - str = _T("RShift"); - break; - case VK_LCONTROL: - str = _T("LCtrl"); - break; - case VK_RCONTROL: - str = _T("RCtrl"); - break; - case VK_LMENU: - str = _T("LAlt"); - break; - case VK_RMENU: - str = _T("RAlt"); - break; - case VK_BROWSER_BACK: - str = _T("Browser Back"); - break; - case VK_BROWSER_FORWARD: - str = _T("Browser Forward"); - break; - case VK_BROWSER_REFRESH: - str = _T("Browser Refresh"); - break; - case VK_BROWSER_STOP: - str = _T("Browser Stop"); - break; - case VK_BROWSER_SEARCH: - str = _T("Browser Search"); - break; - case VK_BROWSER_FAVORITES: - str = _T("Browser Favorites"); - break; - case VK_BROWSER_HOME: - str = _T("Browser Home"); - break; - case VK_VOLUME_MUTE: - str = _T("Volume Mute"); - break; - case VK_VOLUME_DOWN: - str = _T("Volume Down"); - break; - case VK_VOLUME_UP: - str = _T("Volume Up"); - break; - case VK_MEDIA_NEXT_TRACK: - str = _T("Media Next Track"); - break; - case VK_MEDIA_PREV_TRACK: - str = _T("Media Prev Track"); - break; - case VK_MEDIA_STOP: - str = _T("Media Stop"); - break; - case VK_MEDIA_PLAY_PAUSE: - str = _T("Media Play/Pause"); - break; - case VK_LAUNCH_MAIL: - str = _T("Launch Mail"); - break; - case VK_LAUNCH_MEDIA_SELECT: - str = _T("Launch Media Select"); - break; - case VK_LAUNCH_APP1: - str = _T("Launch App1"); - break; - case VK_LAUNCH_APP2: - str = _T("Launch App2"); - break; - case VK_OEM_1: - str = _T("OEM 1"); - break; - case VK_OEM_PLUS: - str = _T("Plus"); - break; - case VK_OEM_COMMA: - str = _T("Comma"); - break; - case VK_OEM_MINUS: - str = _T("Minus"); - break; - case VK_OEM_PERIOD: - str = _T("Period"); - break; - case VK_OEM_2: - str = _T("OEM 2"); - break; - case VK_OEM_3: - str = _T("`"); - break; - case VK_OEM_4: - str = _T("["); - break; - case VK_OEM_5: - str = _T("OEM 5"); - break; - case VK_OEM_6: - str = _T("]"); - break; - case VK_OEM_7: - str = _T("OEM 7"); - break; - case VK_OEM_8: - str = _T("OEM 8"); - break; - case VK_OEM_AX: - str = _T("OEM AX"); - break; - case VK_OEM_102: - str = _T("OEM 102"); - break; - case VK_ICO_HELP: - str = _T("ICO Help"); - break; - case VK_ICO_00: - str = _T("ICO 00"); - break; - case VK_PROCESSKEY: - str = _T("Process Key"); - break; - case VK_ICO_CLEAR: - str = _T("ICO Clear"); - break; - case VK_PACKET: - str = _T("Packet"); - break; - case VK_OEM_RESET: - str = _T("OEM Reset"); - break; - case VK_OEM_JUMP: - str = _T("OEM Jump"); - break; - case VK_OEM_PA1: - str = _T("OEM PA1"); - break; - case VK_OEM_PA2: - str = _T("OEM PA2"); - break; - case VK_OEM_PA3: - str = _T("OEM PA3"); - break; - case VK_OEM_WSCTRL: - str = _T("OEM WSCtrl"); - break; - case VK_OEM_CUSEL: - str = _T("OEM CUSEL"); - break; - case VK_OEM_ATTN: - str = _T("OEM ATTN"); - break; - case VK_OEM_FINISH: - str = _T("OEM Finish"); - break; - case VK_OEM_COPY: - str = _T("OEM Copy"); - break; - case VK_OEM_AUTO: - str = _T("OEM Auto"); - break; - case VK_OEM_ENLW: - str = _T("OEM ENLW"); - break; - case VK_OEM_BACKTAB: - str = _T("OEM Backtab"); - break; - case VK_ATTN: - str = _T("ATTN"); - break; - case VK_CRSEL: - str = _T("CRSEL"); - break; - case VK_EXSEL: - str = _T("EXSEL"); - break; - case VK_EREOF: - str = _T("EREOF"); - break; - case VK_PLAY: - str = _T("Play"); - break; - case VK_ZOOM: - str = _T("Zoom"); - break; - case VK_NONAME: - str = _T("Noname"); - break; - case VK_PA1: - str = _T("PA1"); - break; - case VK_OEM_CLEAR: - str = _T("OEM Clear"); - break; - case 0x07: - case 0x0E: - case 0x0F: - case 0x16: - case 0x1A: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - str.Format(_T("Undefined (0x%02x)"), (TCHAR)a.key); - break; - case 0x0A: - case 0x0B: - case 0x5E: - case 0xB8: - case 0xB9: - case 0xC1: - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xE0: - str.Format(_T("Reserved (0x%02x)"), (TCHAR)a.key); - break; - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xE8: - str.Format(_T("Unassigned (0x%02x)"), (TCHAR)a.key); - break; - case 0xFF: - str = _T("Multimedia keys"); - break; - default: - str.Format(_T("%c"), (TCHAR)a.key); - break; - } - - if (a.fVirt & (FCONTROL | FALT | FSHIFT)) { - str = MakeAccelModLabel(a.fVirt) + _T(" + ") + str; - } - - str.Replace(_T(" + "), _T("+")); - - return str; -} - -CString CPPageAccelTbl::MakeAppCommandLabel(UINT id) -{ - for (int i = 0; i < _countof(g_CommandList); i++) { - if (g_CommandList[i].appcmd == id) { - return CString(g_CommandList[i].cmdname); - } - } - return id == 0 ? _T("") : _T("Invalid"); -} - -void CPPageAccelTbl::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Text(pDX, IDC_EDIT1, m_WinLircAddr); - DDX_Control(pDX, IDC_EDIT1, m_WinLircEdit); - DDX_Control(pDX, IDC_STATICLINK, m_WinLircLink); - DDX_Check(pDX, IDC_CHECK1, m_fWinLirc); - DDX_Text(pDX, IDC_EDIT2, m_UIceAddr); - DDX_Control(pDX, IDC_EDIT2, m_UIceEdit); - DDX_Control(pDX, IDC_EDIT3, filterEdit); - DDX_Control(pDX, IDC_STATICLINK2, m_UIceLink); - DDX_Check(pDX, IDC_CHECK9, m_fUIce); - DDX_Check(pDX, IDC_CHECK2, m_fGlobalMedia); -} - -BEGIN_MESSAGE_MAP(CPPageAccelTbl, CPPageBase) - ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_LIST1, OnBeginListLabelEdit) - ON_NOTIFY(LVN_DOLABELEDIT, IDC_LIST1, OnDoListLabelEdit) - ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST1, OnEndListLabelEdit) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnListColumnClick) - ON_EN_CHANGE(IDC_EDIT3, OnChangeFilterEdit) - ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSelectAll) - ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedReset) - ON_WM_TIMER() - ON_WM_CTLCOLOR() - ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST1, OnCustomdrawList) -END_MESSAGE_MAP() - -// CPPageAccelTbl message handlers - -static 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)) { - CPlayerListCtrl* pList = (CPlayerListCtrl*)CWnd::FromHandle(control); - - for (int i = 0, j = pList->GetItemCount(); i < j; i++) { - pList->SetItemState(i, LVIS_SELECTED, LVIS_SELECTED); - } - - return 0; - } - } - - return CallWindowProc(OldControlProc, control, message, wParam, lParam); // call control's own windowproc -} - -BOOL CPPageAccelTbl::OnInitDialog() -{ - __super::OnInitDialog(); - - CAppSettings& s = AfxGetAppSettings(); - - m_wmcmds.RemoveAll(); - m_wmcmds.AddTail(&s.wmcmds); - m_fWinLirc = s.fWinLirc; - m_WinLircAddr = s.strWinLircAddr; - m_fUIce = s.fUIce; - m_UIceAddr = s.strUIceAddr; - m_fGlobalMedia = s.fGlobalMedia; - - CString text; - text.Format(IDS_STRING_COLON, _T("WinLIRC")); - m_WinLircLink.SetWindowText(text); - text.Format(IDS_STRING_COLON, _T("uICE")); - m_UIceLink.SetWindowText(text); - - UpdateData(FALSE); - - CRect r; - GetDlgItem(IDC_PLACEHOLDER)->GetWindowRect(r); - ScreenToClient(r); - - m_list.CreateEx( - WS_EX_CLIENTEDGE, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | LVS_REPORT | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS, - r, this, IDC_LIST1); - - //m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES ); - m_list.setAdditionalStyles(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES); - m_list.setColorInterface(this); - - //this list was created dynamically but lives in a dialog. if we don't inherit the parent font, - //it will be scaled by text zoom settings, which looks bad in an unscaled dialog - CFont* curDialogFont = GetFont(); - if (curDialogFont && curDialogFont->m_hObject) { - m_list.SetFont(curDialogFont); - } - - for (int i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++) { - m_list.DeleteColumn(0); - } - m_list.InsertColumn(COL_CMD, ResStr(IDS_AG_COMMAND), LVCFMT_LEFT, 80); - m_list.InsertColumn(COL_KEY, ResStr(IDS_AG_KEY), LVCFMT_LEFT, 80); - m_list.InsertColumn(COL_ID, _T("ID"), LVCFMT_LEFT, 40); - m_list.InsertColumn(COL_APPCMD, ResStr(IDS_AG_APP_COMMAND), LVCFMT_LEFT, 120); - m_list.InsertColumn(COL_RMCMD, _T("RemoteCmd"), LVCFMT_LEFT, 80); - m_list.InsertColumn(COL_RMREPCNT, _T("RepCnt"), LVCFMT_CENTER, 60); - - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; m_wmcmds.GetNext(pos)) { - int row = m_list.InsertItem(m_list.GetItemCount(), m_wmcmds.GetAt(pos).GetName(), COL_CMD); - auto itemData = std::make_unique(); - itemData->index = pos; - m_list.SetItemData(row, (DWORD_PTR)itemData.get()); - m_pItemsData.push_back(std::move(itemData)); - } - - SetupList(); - - m_list.SetColumnWidth(COL_CMD, LVSCW_AUTOSIZE); - m_list.SetColumnWidth(COL_KEY, LVSCW_AUTOSIZE); - m_list.SetColumnWidth(COL_ID, LVSCW_AUTOSIZE_USEHEADER); - - // subclass the keylist control - OldControlProc = (WNDPROC)SetWindowLongPtr(m_list.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 -} - -BOOL CPPageAccelTbl::OnApply() -{ - AfxGetMyApp()->UnregisterHotkeys(); - UpdateData(); - - CAppSettings& s = AfxGetAppSettings(); - - s.wmcmds.RemoveAll(); - s.wmcmds.AddTail(&m_wmcmds); - - if (s.hAccel) { - DestroyAcceleratorTable(s.hAccel); - } - - CAtlArray pAccel; - pAccel.SetCount(ACCEL_LIST_SIZE); - int accel_count = 0; - POSITION pos = m_wmcmds.GetHeadPosition(); - for (int i = 0; pos; i++) { - ACCEL x = m_wmcmds.GetNext(pos); - if (x.key > 0) { - pAccel[accel_count] = x; - accel_count++; - } - } - s.hAccel = CreateAcceleratorTable(pAccel.GetData(), accel_count); - - CFrameWnd* parent = GetParentFrame(); - if (parent) { - parent->m_hAccelTable = s.hAccel; - } - - s.fWinLirc = !!m_fWinLirc; - s.strWinLircAddr = m_WinLircAddr; - if (s.fWinLirc) { - s.WinLircClient.Connect(m_WinLircAddr); - } - s.fUIce = !!m_fUIce; - s.strUIceAddr = m_UIceAddr; - if (s.fUIce) { - s.UIceClient.Connect(m_UIceAddr); - } - s.fGlobalMedia = !!m_fGlobalMedia; - - AfxGetMyApp()->RegisterHotkeys(); - - return __super::OnApply(); -} - -void CPPageAccelTbl::OnBnClickedSelectAll() -{ - m_list.SetFocus(); - - for (int i = 0, j = m_list.GetItemCount(); i < j; i++) { - m_list.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED); - } -} - -void CPPageAccelTbl::OnBnClickedReset() -{ - m_list.SetFocus(); - - POSITION pos = m_list.GetFirstSelectedItemPosition(); - if (!pos) { - return; - } - - while (pos) { - int ni = m_list.GetNextSelectedItem(pos); - POSITION pi = ((ITEMDATA*)m_list.GetItemData(ni))->index; - wmcmd& wc = m_wmcmds.GetAt(pi); - wc.Restore(); - } - - SetupList(); - - SetModified(); -} - -void CPPageAccelTbl::OnChangeFilterEdit() -{ - KillTimer(filterTimerID); - filterTimerID = SetTimer(2, 100, NULL); -} - -void CPPageAccelTbl::FilterList() -{ - CString filter; - filterEdit.GetWindowText(filter); - LANGID langid = AfxGetAppSettings().language; - filter = NormalizeUnicodeStrForSearch(filter, langid); - - m_list.SetRedraw(false); - m_list.DeleteAllItems(); - m_pItemsData.clear(); - - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; ) { - CString hotkey, id, name, sname; - - wmcmd& wc = m_wmcmds.GetAt(pos); - - HotkeyModToString(wc.key, wc.fVirt, hotkey); - id.Format(_T("%u"), wc.cmd); - sname = wc.GetName(); - - sname = NormalizeUnicodeStrForSearch(sname, langid); - id = NormalizeUnicodeStrForSearch(id, langid); - hotkey = NormalizeUnicodeStrForSearch(hotkey, langid); - - if (filter.IsEmpty() || sname.Find(filter) != -1 || hotkey.Find(filter) != -1 || id.Find(filter) != -1) { - int row = m_list.InsertItem(m_list.GetItemCount(), wc.GetName(), COL_CMD); - auto itemData = std::make_unique(); - itemData->index = pos; - m_list.SetItemData(row, (DWORD_PTR)itemData.get()); - m_pItemsData.push_back(std::move(itemData)); - } - m_wmcmds.GetNext(pos); - } - SetupList(false); - m_list.SetRedraw(true); - m_list.RedrawWindow(); -} - -void CPPageAccelTbl::GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) { - auto itemData = (ITEMDATA*)m_list.GetItemData(nItem); - auto dup = itemData->flag; - if (iSubItem == COL_CMD && dup - || iSubItem == COL_KEY && (dup & DUP_KEY) - || iSubItem == COL_APPCMD && (dup & DUP_APPCMD) - || iSubItem == COL_RMCMD && (dup & DUP_RMCMD)) { - if (AppIsThemeLoaded()) { - clrTextBk = CMPCTheme::ListCtrlErrorColor; - overrideSelectedBG = true; - } else { - clrTextBk = RGB(255, 130, 120); - } - } else { - if (AppIsThemeLoaded()) { - clrTextBk = CMPCTheme::ContentBGColor; - } else { - clrTextBk = GetSysColor(COLOR_WINDOW); - } - } -} - -void CPPageAccelTbl::GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) { - horzGridColor = CMPCTheme::ListCtrlGridColor; - vertGridColor = CMPCTheme::ListCtrlGridColor; -} - -void CPPageAccelTbl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult) { - NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); - *pResult = CDRF_DODEFAULT; - - if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage) { - *pResult = CDRF_NOTIFYITEMDRAW; - } else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage) { - *pResult = CDRF_NOTIFYSUBITEMDRAW; - } else if ((CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage) { - bool ignore; - GetCustomTextColors(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, pLVCD->clrText, pLVCD->clrTextBk, ignore); - *pResult = CDRF_DODEFAULT; - } -} - -void CPPageAccelTbl::OnBeginListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (pItem->iItem < 0) { - return; - } - - if (pItem->iSubItem == COL_KEY || pItem->iSubItem == COL_APPCMD || pItem->iSubItem == COL_RMCMD || pItem->iSubItem == COL_RMREPCNT) { - *pResult = TRUE; - } -} - -static BYTE s_mods[] = {0, FALT, FCONTROL, FSHIFT, FCONTROL | FALT, FCONTROL | FSHIFT, FALT | FSHIFT, FCONTROL | FALT | FSHIFT}; - -void CPPageAccelTbl::OnDoListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - if (pItem->iItem < 0) { - *pResult = FALSE; - return; - } - - *pResult = TRUE; - - - wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(pItem->iItem))->index); - - CAtlList sl; - int nSel = -1; - - auto createHotkey = [&](auto virt, auto key) { - m_list.ShowInPlaceWinHotkey(pItem->iItem, pItem->iSubItem); - CWinHotkeyCtrl* pWinHotkey = (CWinHotkeyCtrl*)m_list.GetDlgItem(IDC_WINHOTKEY1); - UINT cod = 0, mod = 0; - if (virt & FALT) { - mod |= MOD_ALT; - } - if (virt & FCONTROL) { - mod |= MOD_CONTROL; - } - if (virt & FSHIFT) { - mod |= MOD_SHIFT; - } - cod = key; - pWinHotkey->SetWinHotkey(cod, mod); - }; - - switch (pItem->iSubItem) { - case COL_KEY: - createHotkey(wc.fVirt, wc.key); - break; - case COL_APPCMD: - for (int i = 0; i < _countof(g_CommandList); i++) { - sl.AddTail(g_CommandList[i].cmdname); - if (wc.appcmd == g_CommandList[i].appcmd) { - nSel = i; - } - } - - m_list.ShowInPlaceComboBox(pItem->iItem, pItem->iSubItem, sl, nSel); - break; - case COL_RMCMD: - m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem); - break; - case COL_RMREPCNT: - m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem); - break; - default: - *pResult = FALSE; - break; - } -} - -int CPPageAccelTbl::CompareFunc(LPARAM lParam1, LPARAM lParam2) -{ - int result; - - CString strItem1 = m_list.GetItemText(static_cast(lParam1), sortColumn); - CString strItem2 = m_list.GetItemText(static_cast(lParam2), sortColumn); - if (sortColumn == COL_ID || sortColumn == COL_RMREPCNT) { - wmcmd& wc1 = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(static_cast(lParam1)))->index); - wmcmd& wc2 = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(static_cast(lParam2)))->index); - - result = wc1.cmd == wc2.cmd ? 0 : (wc1.cmd < wc2.cmd ? -1 : 1); - } else { - result = strItem1.Compare(strItem2); - } - - if (sortDirection == HDF_SORTUP) { - return result; - } else { - return -result; - } -} - -static int CALLBACK StaticCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) -{ - CPPageAccelTbl* ppAccelTbl = (CPPageAccelTbl*)lParamSort; - return ppAccelTbl->CompareFunc(lParam1, lParam2); -} - -void CPPageAccelTbl::UpdateHeaderSort(int column, int sort) -{ - CHeaderCtrl* hdr = m_list.GetHeaderCtrl(); - HDITEMW hItem = { 0 }; - hItem.mask = HDI_FORMAT; - if (hdr->GetItem(column, &hItem)) { - if (sort == HDF_SORTUP) { - hItem.fmt |= HDF_SORTUP; - hItem.fmt &= ~HDF_SORTDOWN; - } else if (sort == HDF_SORTDOWN) { - hItem.fmt |= HDF_SORTDOWN; - hItem.fmt &= ~HDF_SORTUP; - } else { //no sort - hItem.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); - } - hdr->SetItem(column, &hItem); - } -} - -void CPPageAccelTbl::OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult) -{ - NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; - int colToSort = pNMListView->iSubItem; - if (colToSort == sortColumn) { - sortDirection = sortDirection == HDF_SORTUP ? HDF_SORTDOWN : HDF_SORTUP; - } else { - if (sortColumn != -1) { - UpdateHeaderSort(sortColumn, 0); //clear old sort - } - sortColumn = colToSort; - sortDirection = HDF_SORTUP; - } - m_list.SortItemsEx(StaticCompareFunc, (LPARAM)this); - UpdateHeaderSort(sortColumn, sortDirection); -} - -void CPPageAccelTbl::OnEndListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (!m_list.m_fInPlaceDirty) { - return; - } - - if (pItem->iItem < 0) { - return; - } - wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(pItem->iItem))->index); - - auto updateHotkey = [&](auto &virt, auto &key) { - UINT cod, mod; - CWinHotkeyCtrl* pWinHotkey = (CWinHotkeyCtrl*)m_list.GetDlgItem(IDC_WINHOTKEY1); - pWinHotkey->GetWinHotkey(&cod, &mod); - ASSERT(cod < WORD_MAX); - key = (WORD)cod; - virt = FVIRTKEY; - if (mod & MOD_ALT) { - virt |= FALT; - } - if (mod & MOD_CONTROL) { - virt |= FCONTROL; - } - if (mod & MOD_SHIFT) { - virt |= FSHIFT; - } - - CString str; - HotkeyToString(key, mod, str); - m_list.SetItemText(pItem->iItem, pItem->iSubItem, str); - - *pResult = TRUE; - UpdateKeyDupFlags(); - }; - - WORD discard; - switch (pItem->iSubItem) { - case COL_KEY: - updateHotkey(wc.fVirt, wc.key); - break; - case COL_APPCMD: { - ptrdiff_t i = pItem->lParam; - if (i >= 0 && i < _countof(g_CommandList)) { - wc.appcmd = g_CommandList[i].appcmd; - m_list.SetItemText(pItem->iItem, COL_APPCMD, pItem->pszText); - *pResult = TRUE; - UpdateAppcmdDupFlags(); - } - } - break; - case COL_RMCMD: { - CString cmd = pItem->pszText; - cmd.Trim(); - cmd.Replace(_T(' '), ('_')); - m_list.SetItemText(pItem->iItem, pItem->iSubItem, cmd); - wc.rmcmd = cmd; - *pResult = TRUE; - UpdateRmcmdDupFlags(); - break; - } - case COL_RMREPCNT: - CString str = pItem->pszText; - wc.rmrepcnt = _tcstol(str.Trim(), nullptr, 10); - str.Format(_T("%d"), wc.rmrepcnt); - m_list.SetItemText(pItem->iItem, pItem->iSubItem, str); - *pResult = TRUE; - break; - } - - if (*pResult) { - m_list.RedrawWindow(); - SetModified(); - } -} - -void CPPageAccelTbl::OnTimer(UINT_PTR nIDEvent) -{ - if (nIDEvent == m_nStatusTimerID) { - UpdateData(); - - CAppSettings& s = AfxGetAppSettings(); - - if (m_fWinLirc) { - CString addr; - m_WinLircEdit.GetWindowText(addr); - s.WinLircClient.Connect(addr); - } - - m_WinLircEdit.Invalidate(); - - if (m_fUIce) { - CString addr; - m_UIceEdit.GetWindowText(addr); - s.UIceClient.Connect(addr); - } - - m_UIceEdit.Invalidate(); - - m_counter++; - } else if (nIDEvent == filterTimerID) { - KillTimer(filterTimerID); - FilterList(); - } else { - __super::OnTimer(nIDEvent); - } -} - -HBRUSH CPPageAccelTbl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - - const CAppSettings& s = AfxGetAppSettings(); - if (AppIsThemeLoaded()) { - return hbr; //should have already been handled inside themed ctlcolor - } - int status = -1; - - if (*pWnd == m_WinLircEdit) { - status = s.WinLircClient.GetStatus(); - } else if (*pWnd == m_UIceEdit) { - status = s.UIceClient.GetStatus(); - } - - if (status == 0 || status == 2 && (m_counter & 1)) { - pDC->SetTextColor(0x0000ff); - } else if (status == 1) { - pDC->SetTextColor(0x008000); - } - - return hbr; -} - -BOOL CPPageAccelTbl::OnSetActive() -{ - m_nStatusTimerID = SetTimer(1, 1000, nullptr); - - return CPPageBase::OnSetActive(); -} - -BOOL CPPageAccelTbl::OnKillActive() -{ - KillTimer(m_nStatusTimerID); - m_nStatusTimerID = 0; - - return CPPageBase::OnKillActive(); -} - -void CPPageAccelTbl::OnCancel() -{ - CAppSettings& s = AfxGetAppSettings(); - - if (!s.fWinLirc) { - s.WinLircClient.DisConnect(); - } - if (!s.fUIce) { - s.UIceClient.DisConnect(); - } - - __super::OnCancel(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "PPageAccelTbl.h" +#include "AppSettings.h" + +#define DUP_KEY (1<<12) +#define DUP_APPCMD (1<<13) +#define DUP_RMCMD (1<<14) +#define MASK_DUP (DUP_KEY|DUP_APPCMD|DUP_RMCMD) + +struct APP_COMMAND { + UINT appcmd; + LPCTSTR cmdname; +}; + +static constexpr APP_COMMAND g_CommandList[] = { + {0, _T("")}, + {APPCOMMAND_MEDIA_PLAY_PAUSE, _T("MEDIA_PLAY_PAUSE")}, + {APPCOMMAND_MEDIA_PLAY, _T("MEDIA_PLAY")}, + {APPCOMMAND_MEDIA_PAUSE, _T("MEDIA_PAUSE")}, + {APPCOMMAND_MEDIA_STOP, _T("MEDIA_STOP")}, + {APPCOMMAND_MEDIA_NEXTTRACK, _T("MEDIA_NEXTTRACK")}, + {APPCOMMAND_MEDIA_PREVIOUSTRACK, _T("MEDIA_PREVIOUSTRACK")}, + {APPCOMMAND_MEDIA_FAST_FORWARD, _T("MEDIA_FAST_FORWARD")}, + {APPCOMMAND_MEDIA_REWIND, _T("MEDIA_REWIND")}, + {APPCOMMAND_MEDIA_CHANNEL_UP, _T("MEDIA_CHANNEL_UP")}, + {APPCOMMAND_MEDIA_CHANNEL_DOWN, _T("MEDIA_CHANNEL_DOWN")}, + {APPCOMMAND_MEDIA_RECORD, _T("MEDIA_RECORD")}, + {APPCOMMAND_VOLUME_DOWN, _T("VOLUME_DOWN")}, + {APPCOMMAND_VOLUME_UP, _T("VOLUME_UP")}, + {APPCOMMAND_VOLUME_MUTE, _T("VOLUME_MUTE")}, + {APPCOMMAND_LAUNCH_MEDIA_SELECT, _T("LAUNCH_MEDIA_SELECT")}, + /* + {APPCOMMAND_BROWSER_BACKWARD, _T("BROWSER_BACKWARD")}, + {APPCOMMAND_BROWSER_FORWARD, _T("BROWSER_FORWARD")}, + {APPCOMMAND_BROWSER_REFRESH, _T("BROWSER_REFRESH")}, + {APPCOMMAND_BROWSER_STOP, _T("BROWSER_STOP")}, + {APPCOMMAND_BROWSER_SEARCH, _T("BROWSER_SEARCH")}, + {APPCOMMAND_BROWSER_FAVORITES, _T("BROWSER_FAVORITES")}, + {APPCOMMAND_BROWSER_HOME, _T("BROWSER_HOME")}, + */ + {APPCOMMAND_LAUNCH_APP1, _T("LAUNCH_APP1")}, + {APPCOMMAND_LAUNCH_APP2, _T("LAUNCH_APP2")}, + {APPCOMMAND_OPEN, _T("OPEN")}, + {APPCOMMAND_CLOSE, _T("CLOSE")}, + {APPCOMMAND_DELETE, _T("DELETE")}, + {MCE_DETAILS, _T("MCE_DETAILS")}, + {MCE_GUIDE, _T("MCE_GUIDE")}, + {MCE_TVJUMP, _T("MCE_TVJUMP")}, + {MCE_STANDBY, _T("MCE_STANDBY")}, + {MCE_OEM1, _T("MCE_OEM1")}, + {MCE_OEM2, _T("MCE_OEM2")}, + {MCE_MYTV, _T("MCE_MYTV")}, + {MCE_MYVIDEOS, _T("MCE_MYVIDEOS")}, + {MCE_MYPICTURES, _T("MCE_MYPICTURES")}, + {MCE_MYMUSIC, _T("MCE_MYMUSIC")}, + {MCE_RECORDEDTV, _T("MCE_RECORDEDTV")}, + {MCE_DVDANGLE, _T("MCE_DVDANGLE")}, + {MCE_DVDAUDIO, _T("MCE_DVDAUDIO")}, + {MCE_DVDMENU, _T("MCE_DVDMENU")}, + {MCE_DVDSUBTITLE, _T("MCE_DVDSUBTITLE")}, + {MCE_RED, _T("MCE_RED")}, + {MCE_GREEN, _T("MCE_GREEN")}, + {MCE_YELLOW, _T("MCE_YELLOW")}, + {MCE_BLUE, _T("MCE_BLUE")}, + {MCE_MEDIA_NEXTTRACK, _T("MCE_MEDIA_NEXTTRACK")}, + {MCE_MEDIA_PREVIOUSTRACK, _T("MCE_MEDIA_PREVIOUSTRACK")} +}; + +// CPPageAccelTbl dialog + +IMPLEMENT_DYNAMIC(CPPageAccelTbl, CMPCThemePPageBase) +CPPageAccelTbl::CPPageAccelTbl() + : CMPCThemePPageBase(CPPageAccelTbl::IDD, CPPageAccelTbl::IDD) + , m_counter(0) + , m_list(0) + , m_fWinLirc(FALSE) + , m_WinLircLink(_T("http://winlirc.sourceforge.net/")) + , m_fUIce(FALSE) + , m_UIceLink(L"https://web.archive.org/web/20160609195532/http://www.mediatexx.com/") // home site no longer works + , m_nStatusTimerID(0) + , filterTimerID(0) + , sortDirection(HDF_SORTUP) + , m_fGlobalMedia(FALSE) +{ +} + +CPPageAccelTbl::~CPPageAccelTbl() +{ +} + +BOOL CPPageAccelTbl::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN + && (pMsg->hwnd == m_WinLircEdit.m_hWnd || pMsg->hwnd == m_UIceEdit.m_hWnd)) { + OnApply(); + return TRUE; + } + + return __super::PreTranslateMessage(pMsg); +} + +void CPPageAccelTbl::UpdateKeyDupFlags() +{ + for (int row = 0; row < m_list.GetItemCount(); row++) { + auto itemData = (ITEMDATA*)m_list.GetItemData(row); + const wmcmd& wc = m_wmcmds.GetAt(itemData->index); + + itemData->flag &= ~DUP_KEY; + + if (wc.key) { + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; m_wmcmds.GetNext(pos)) { + if (itemData->index == pos) { continue; } + + if (wc.key == m_wmcmds.GetAt(pos).key && (wc.fVirt & (FCONTROL | FALT | FSHIFT)) == (m_wmcmds.GetAt(pos).fVirt & (FCONTROL | FALT | FSHIFT))) { + itemData->flag |= DUP_KEY; + break; + } + } + } + } +} + +void CPPageAccelTbl::UpdateAppcmdDupFlags() +{ + for (int row = 0; row < m_list.GetItemCount(); row++) { + auto itemData = (ITEMDATA*)m_list.GetItemData(row); + const wmcmd& wc = m_wmcmds.GetAt(itemData->index); + + itemData->flag &= ~DUP_APPCMD; + + if (wc.appcmd) { + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; m_wmcmds.GetNext(pos)) { + if (itemData->index == pos) { continue; } + + if (wc.appcmd == m_wmcmds.GetAt(pos).appcmd) { + itemData->flag |= DUP_APPCMD; + break; + } + } + } + } +} + +void CPPageAccelTbl::UpdateRmcmdDupFlags() +{ + for (int row = 0; row < m_list.GetItemCount(); row++) { + auto itemData = (ITEMDATA*)m_list.GetItemData(row); + const wmcmd& wc = m_wmcmds.GetAt(itemData->index); + + itemData->flag &= ~DUP_RMCMD; + + if (wc.rmcmd.GetLength()) { + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; m_wmcmds.GetNext(pos)) { + if (itemData->index == pos) { continue; } + + if (wc.rmcmd.CompareNoCase(m_wmcmds.GetAt(pos).rmcmd) == 0) { + itemData->flag |= DUP_RMCMD; + break; + } + } + } + } +} + +void CPPageAccelTbl::UpdateAllDupFlags() +{ + UpdateKeyDupFlags(); + UpdateAppcmdDupFlags(); + UpdateRmcmdDupFlags(); +} + +void CPPageAccelTbl::SetupList(bool allowResize) +{ + for (int row = 0; row < m_list.GetItemCount(); row++) { + wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(row))->index); + + CString hotkey; + HotkeyModToString(wc.key, wc.fVirt, hotkey); + m_list.SetItemText(row, COL_KEY, hotkey); + + CString id; + id.Format(_T("%u"), wc.cmd); + m_list.SetItemText(row, COL_ID, id); + + m_list.SetItemText(row, COL_APPCMD, MakeAppCommandLabel(wc.appcmd)); + + m_list.SetItemText(row, COL_RMCMD, CString(wc.rmcmd)); + + CString repcnt; + repcnt.Format(_T("%d"), wc.rmrepcnt); + m_list.SetItemText(row, COL_RMREPCNT, repcnt); + } + + UpdateAllDupFlags(); + + if (allowResize) { + for (int nCol = COL_CMD; nCol <= COL_RMREPCNT; nCol++) { + m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE); + int contentSize = m_list.GetColumnWidth(nCol); + m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE_USEHEADER); + if (contentSize > m_list.GetColumnWidth(nCol)) { + m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE); + } + } + for (int nCol = COL_CMD; nCol <= COL_RMREPCNT; nCol++) { + int contentSize = m_list.GetColumnWidth(nCol); + m_list.SetColumnWidth(nCol, contentSize); + } + } +} + +CString CPPageAccelTbl::MakeAccelModLabel(BYTE fVirt) +{ + CString str; + if (fVirt & FCONTROL) { + if (!str.IsEmpty()) { + str += _T(" + "); + } + str += _T("Ctrl"); + } + if (fVirt & FALT) { + if (!str.IsEmpty()) { + str += _T(" + "); + } + str += _T("Alt"); + } + if (fVirt & FSHIFT) { + if (!str.IsEmpty()) { + str += _T(" + "); + } + str += _T("Shift"); + } + if (str.IsEmpty()) { + str.LoadString(IDS_AG_NONE); + } + return str; +} + +CString CPPageAccelTbl::MakeAccelShortcutLabel(UINT id) +{ + CList& wmcmds = AfxGetAppSettings().wmcmds; + POSITION pos = wmcmds.GetHeadPosition(); + while (pos) { + ACCEL& a = wmcmds.GetNext(pos); + if (a.cmd == id) { + return (MakeAccelShortcutLabel(a)); + } + } + + return _T(""); +} + +CString CPPageAccelTbl::MakeAccelShortcutLabel(const ACCEL& a) +{ + if (!a.key) { + return _T(""); + } + + // Reference page for Virtual-Key Codes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.100%29.aspx + CString str; + + switch (a.key) { + case VK_LBUTTON: + str = _T("LBtn"); + break; + case VK_RBUTTON: + str = _T("RBtn"); + break; + case VK_CANCEL: + str = _T("Cancel"); + break; + case VK_MBUTTON: + str = _T("MBtn"); + break; + case VK_XBUTTON1: + str = _T("X1Btn"); + break; + case VK_XBUTTON2: + str = _T("X2Btn"); + break; + case VK_BACK: + str = _T("Back"); + break; + case VK_TAB: + str = _T("Tab"); + break; + case VK_CLEAR: + str = _T("Clear"); + break; + case VK_RETURN: + str = _T("Enter"); + break; + case VK_SHIFT: + str = _T("Shift"); + break; + case VK_CONTROL: + str = _T("Ctrl"); + break; + case VK_MENU: + str = _T("Alt"); + break; + case VK_PAUSE: + str = _T("Pause"); + break; + case VK_CAPITAL: + str = _T("Capital"); + break; + // case VK_KANA: str = _T("Kana"); break; + // case VK_HANGEUL: str = _T("Hangeul"); break; + case VK_HANGUL: + str = _T("Hangul"); + break; + case VK_JUNJA: + str = _T("Junja"); + break; + case VK_FINAL: + str = _T("Final"); + break; + // case VK_HANJA: str = _T("Hanja"); break; + case VK_KANJI: + str = _T("Kanji"); + break; + case VK_ESCAPE: + str = _T("Escape"); + break; + case VK_CONVERT: + str = _T("Convert"); + break; + case VK_NONCONVERT: + str = _T("Non Convert"); + break; + case VK_ACCEPT: + str = _T("Accept"); + break; + case VK_MODECHANGE: + str = _T("Mode Change"); + break; + case VK_SPACE: + str = _T("Space"); + break; + case VK_PRIOR: + str = _T("PgUp"); + break; + case VK_NEXT: + str = _T("PgDn"); + break; + case VK_END: + str = _T("End"); + break; + case VK_HOME: + str = _T("Home"); + break; + case VK_LEFT: + str = _T("Left"); + break; + case VK_UP: + str = _T("Up"); + break; + case VK_RIGHT: + str = _T("Right"); + break; + case VK_DOWN: + str = _T("Down"); + break; + case VK_SELECT: + str = _T("Select"); + break; + case VK_PRINT: + str = _T("Print"); + break; + case VK_EXECUTE: + str = _T("Execute"); + break; + case VK_SNAPSHOT: + str = _T("Snapshot"); + break; + case VK_INSERT: + str = _T("Insert"); + break; + case VK_DELETE: + str = _T("Delete"); + break; + case VK_HELP: + str = _T("Help"); + break; + case VK_LWIN: + str = _T("LWin"); + break; + case VK_RWIN: + str = _T("RWin"); + break; + case VK_APPS: + str = _T("Apps"); + break; + case VK_SLEEP: + str = _T("Sleep"); + break; + case VK_NUMPAD0: + str = _T("Numpad 0"); + break; + case VK_NUMPAD1: + str = _T("Numpad 1"); + break; + case VK_NUMPAD2: + str = _T("Numpad 2"); + break; + case VK_NUMPAD3: + str = _T("Numpad 3"); + break; + case VK_NUMPAD4: + str = _T("Numpad 4"); + break; + case VK_NUMPAD5: + str = _T("Numpad 5"); + break; + case VK_NUMPAD6: + str = _T("Numpad 6"); + break; + case VK_NUMPAD7: + str = _T("Numpad 7"); + break; + case VK_NUMPAD8: + str = _T("Numpad 8"); + break; + case VK_NUMPAD9: + str = _T("Numpad 9"); + break; + case VK_MULTIPLY: + str = _T("Multiply"); + break; + case VK_ADD: + str = _T("Add"); + break; + case VK_SEPARATOR: + str = _T("Separator"); + break; + case VK_SUBTRACT: + str = _T("Subtract"); + break; + case VK_DECIMAL: + str = _T("Decimal"); + break; + case VK_DIVIDE: + str = _T("Divide"); + break; + case VK_F1: + str = _T("F1"); + break; + case VK_F2: + str = _T("F2"); + break; + case VK_F3: + str = _T("F3"); + break; + case VK_F4: + str = _T("F4"); + break; + case VK_F5: + str = _T("F5"); + break; + case VK_F6: + str = _T("F6"); + break; + case VK_F7: + str = _T("F7"); + break; + case VK_F8: + str = _T("F8"); + break; + case VK_F9: + str = _T("F9"); + break; + case VK_F10: + str = _T("F10"); + break; + case VK_F11: + str = _T("F11"); + break; + case VK_F12: + str = _T("F12"); + break; + case VK_F13: + str = _T("F13"); + break; + case VK_F14: + str = _T("F14"); + break; + case VK_F15: + str = _T("F15"); + break; + case VK_F16: + str = _T("F16"); + break; + case VK_F17: + str = _T("F17"); + break; + case VK_F18: + str = _T("F18"); + break; + case VK_F19: + str = _T("F19"); + break; + case VK_F20: + str = _T("F20"); + break; + case VK_F21: + str = _T("F21"); + break; + case VK_F22: + str = _T("F22"); + break; + case VK_F23: + str = _T("F23"); + break; + case VK_F24: + str = _T("F24"); + break; + case VK_NUMLOCK: + str = _T("Numlock"); + break; + case VK_SCROLL: + str = _T("Scroll"); + break; + // case VK_OEM_NEC_EQUAL: str = _T("OEM NEC Equal"); break; + case VK_OEM_FJ_JISHO: + str = _T("OEM FJ Jisho"); + break; + case VK_OEM_FJ_MASSHOU: + str = _T("OEM FJ Msshou"); + break; + case VK_OEM_FJ_TOUROKU: + str = _T("OEM FJ Touroku"); + break; + case VK_OEM_FJ_LOYA: + str = _T("OEM FJ Loya"); + break; + case VK_OEM_FJ_ROYA: + str = _T("OEM FJ Roya"); + break; + case VK_LSHIFT: + str = _T("LShift"); + break; + case VK_RSHIFT: + str = _T("RShift"); + break; + case VK_LCONTROL: + str = _T("LCtrl"); + break; + case VK_RCONTROL: + str = _T("RCtrl"); + break; + case VK_LMENU: + str = _T("LAlt"); + break; + case VK_RMENU: + str = _T("RAlt"); + break; + case VK_BROWSER_BACK: + str = _T("Browser Back"); + break; + case VK_BROWSER_FORWARD: + str = _T("Browser Forward"); + break; + case VK_BROWSER_REFRESH: + str = _T("Browser Refresh"); + break; + case VK_BROWSER_STOP: + str = _T("Browser Stop"); + break; + case VK_BROWSER_SEARCH: + str = _T("Browser Search"); + break; + case VK_BROWSER_FAVORITES: + str = _T("Browser Favorites"); + break; + case VK_BROWSER_HOME: + str = _T("Browser Home"); + break; + case VK_VOLUME_MUTE: + str = _T("Volume Mute"); + break; + case VK_VOLUME_DOWN: + str = _T("Volume Down"); + break; + case VK_VOLUME_UP: + str = _T("Volume Up"); + break; + case VK_MEDIA_NEXT_TRACK: + str = _T("Media Next Track"); + break; + case VK_MEDIA_PREV_TRACK: + str = _T("Media Prev Track"); + break; + case VK_MEDIA_STOP: + str = _T("Media Stop"); + break; + case VK_MEDIA_PLAY_PAUSE: + str = _T("Media Play/Pause"); + break; + case VK_LAUNCH_MAIL: + str = _T("Launch Mail"); + break; + case VK_LAUNCH_MEDIA_SELECT: + str = _T("Launch Media Select"); + break; + case VK_LAUNCH_APP1: + str = _T("Launch App1"); + break; + case VK_LAUNCH_APP2: + str = _T("Launch App2"); + break; + case VK_OEM_1: + str = _T("OEM 1"); + break; + case VK_OEM_PLUS: + str = _T("Plus"); + break; + case VK_OEM_COMMA: + str = _T("Comma"); + break; + case VK_OEM_MINUS: + str = _T("Minus"); + break; + case VK_OEM_PERIOD: + str = _T("Period"); + break; + case VK_OEM_2: + str = _T("OEM 2"); + break; + case VK_OEM_3: + str = _T("`"); + break; + case VK_OEM_4: + str = _T("["); + break; + case VK_OEM_5: + str = _T("OEM 5"); + break; + case VK_OEM_6: + str = _T("]"); + break; + case VK_OEM_7: + str = _T("OEM 7"); + break; + case VK_OEM_8: + str = _T("OEM 8"); + break; + case VK_OEM_AX: + str = _T("OEM AX"); + break; + case VK_OEM_102: + str = _T("OEM 102"); + break; + case VK_ICO_HELP: + str = _T("ICO Help"); + break; + case VK_ICO_00: + str = _T("ICO 00"); + break; + case VK_PROCESSKEY: + str = _T("Process Key"); + break; + case VK_ICO_CLEAR: + str = _T("ICO Clear"); + break; + case VK_PACKET: + str = _T("Packet"); + break; + case VK_OEM_RESET: + str = _T("OEM Reset"); + break; + case VK_OEM_JUMP: + str = _T("OEM Jump"); + break; + case VK_OEM_PA1: + str = _T("OEM PA1"); + break; + case VK_OEM_PA2: + str = _T("OEM PA2"); + break; + case VK_OEM_PA3: + str = _T("OEM PA3"); + break; + case VK_OEM_WSCTRL: + str = _T("OEM WSCtrl"); + break; + case VK_OEM_CUSEL: + str = _T("OEM CUSEL"); + break; + case VK_OEM_ATTN: + str = _T("OEM ATTN"); + break; + case VK_OEM_FINISH: + str = _T("OEM Finish"); + break; + case VK_OEM_COPY: + str = _T("OEM Copy"); + break; + case VK_OEM_AUTO: + str = _T("OEM Auto"); + break; + case VK_OEM_ENLW: + str = _T("OEM ENLW"); + break; + case VK_OEM_BACKTAB: + str = _T("OEM Backtab"); + break; + case VK_ATTN: + str = _T("ATTN"); + break; + case VK_CRSEL: + str = _T("CRSEL"); + break; + case VK_EXSEL: + str = _T("EXSEL"); + break; + case VK_EREOF: + str = _T("EREOF"); + break; + case VK_PLAY: + str = _T("Play"); + break; + case VK_ZOOM: + str = _T("Zoom"); + break; + case VK_NONAME: + str = _T("Noname"); + break; + case VK_PA1: + str = _T("PA1"); + break; + case VK_OEM_CLEAR: + str = _T("OEM Clear"); + break; + case 0x07: + case 0x0E: + case 0x0F: + case 0x16: + case 0x1A: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + str.Format(_T("Undefined (0x%02x)"), (TCHAR)a.key); + break; + case 0x0A: + case 0x0B: + case 0x5E: + case 0xB8: + case 0xB9: + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xE0: + str.Format(_T("Reserved (0x%02x)"), (TCHAR)a.key); + break; + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xE8: + str.Format(_T("Unassigned (0x%02x)"), (TCHAR)a.key); + break; + case 0xFF: + str = _T("Multimedia keys"); + break; + default: + str.Format(_T("%c"), (TCHAR)a.key); + break; + } + + if (a.fVirt & (FCONTROL | FALT | FSHIFT)) { + str = MakeAccelModLabel(a.fVirt) + _T(" + ") + str; + } + + str.Replace(_T(" + "), _T("+")); + + return str; +} + +CString CPPageAccelTbl::MakeAppCommandLabel(UINT id) +{ + for (int i = 0; i < _countof(g_CommandList); i++) { + if (g_CommandList[i].appcmd == id) { + return CString(g_CommandList[i].cmdname); + } + } + return id == 0 ? _T("") : _T("Invalid"); +} + +void CPPageAccelTbl::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Text(pDX, IDC_EDIT1, m_WinLircAddr); + DDX_Control(pDX, IDC_EDIT1, m_WinLircEdit); + DDX_Control(pDX, IDC_STATICLINK, m_WinLircLink); + DDX_Check(pDX, IDC_CHECK1, m_fWinLirc); + DDX_Text(pDX, IDC_EDIT2, m_UIceAddr); + DDX_Control(pDX, IDC_EDIT2, m_UIceEdit); + DDX_Control(pDX, IDC_EDIT3, filterEdit); + DDX_Control(pDX, IDC_STATICLINK2, m_UIceLink); + DDX_Check(pDX, IDC_CHECK9, m_fUIce); + DDX_Check(pDX, IDC_CHECK2, m_fGlobalMedia); +} + +BEGIN_MESSAGE_MAP(CPPageAccelTbl, CPPageBase) + ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_LIST1, OnBeginListLabelEdit) + ON_NOTIFY(LVN_DOLABELEDIT, IDC_LIST1, OnDoListLabelEdit) + ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST1, OnEndListLabelEdit) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnListColumnClick) + ON_EN_CHANGE(IDC_EDIT3, OnChangeFilterEdit) + ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSelectAll) + ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedReset) + ON_WM_TIMER() + ON_WM_CTLCOLOR() + ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST1, OnCustomdrawList) +END_MESSAGE_MAP() + +// CPPageAccelTbl message handlers + +static 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)) { + CPlayerListCtrl* pList = (CPlayerListCtrl*)CWnd::FromHandle(control); + + for (int i = 0, j = pList->GetItemCount(); i < j; i++) { + pList->SetItemState(i, LVIS_SELECTED, LVIS_SELECTED); + } + + return 0; + } + } + + return CallWindowProc(OldControlProc, control, message, wParam, lParam); // call control's own windowproc +} + +BOOL CPPageAccelTbl::OnInitDialog() +{ + __super::OnInitDialog(); + + CAppSettings& s = AfxGetAppSettings(); + + m_wmcmds.RemoveAll(); + m_wmcmds.AddTail(&s.wmcmds); + m_fWinLirc = s.fWinLirc; + m_WinLircAddr = s.strWinLircAddr; + m_fUIce = s.fUIce; + m_UIceAddr = s.strUIceAddr; + m_fGlobalMedia = s.fGlobalMedia; + + CString text; + text.Format(IDS_STRING_COLON, _T("WinLIRC")); + m_WinLircLink.SetWindowText(text); + text.Format(IDS_STRING_COLON, _T("uICE")); + m_UIceLink.SetWindowText(text); + + UpdateData(FALSE); + + CRect r; + GetDlgItem(IDC_PLACEHOLDER)->GetWindowRect(r); + ScreenToClient(r); + + m_list.CreateEx( + WS_EX_CLIENTEDGE, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | LVS_REPORT | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS, + r, this, IDC_LIST1); + + //m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES ); + m_list.setAdditionalStyles(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES); + m_list.setColorInterface(this); + + //this list was created dynamically but lives in a dialog. if we don't inherit the parent font, + //it will be scaled by text zoom settings, which looks bad in an unscaled dialog + CFont* curDialogFont = GetFont(); + if (curDialogFont && curDialogFont->m_hObject) { + m_list.SetFont(curDialogFont); + } + + for (int i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++) { + m_list.DeleteColumn(0); + } + m_list.InsertColumn(COL_CMD, ResStr(IDS_AG_COMMAND), LVCFMT_LEFT, 80); + m_list.InsertColumn(COL_KEY, ResStr(IDS_AG_KEY), LVCFMT_LEFT, 80); + m_list.InsertColumn(COL_ID, _T("ID"), LVCFMT_LEFT, 40); + m_list.InsertColumn(COL_APPCMD, ResStr(IDS_AG_APP_COMMAND), LVCFMT_LEFT, 120); + m_list.InsertColumn(COL_RMCMD, _T("RemoteCmd"), LVCFMT_LEFT, 80); + m_list.InsertColumn(COL_RMREPCNT, _T("RepCnt"), LVCFMT_CENTER, 60); + + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; m_wmcmds.GetNext(pos)) { + int row = m_list.InsertItem(m_list.GetItemCount(), m_wmcmds.GetAt(pos).GetName(), COL_CMD); + auto itemData = std::make_unique(); + itemData->index = pos; + m_list.SetItemData(row, (DWORD_PTR)itemData.get()); + m_pItemsData.push_back(std::move(itemData)); + } + + SetupList(); + + m_list.SetColumnWidth(COL_CMD, LVSCW_AUTOSIZE); + m_list.SetColumnWidth(COL_KEY, LVSCW_AUTOSIZE); + m_list.SetColumnWidth(COL_ID, LVSCW_AUTOSIZE_USEHEADER); + + // subclass the keylist control + OldControlProc = (WNDPROC)SetWindowLongPtr(m_list.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 +} + +BOOL CPPageAccelTbl::OnApply() +{ + AfxGetMyApp()->UnregisterHotkeys(); + UpdateData(); + + CAppSettings& s = AfxGetAppSettings(); + + s.wmcmds.RemoveAll(); + s.wmcmds.AddTail(&m_wmcmds); + + if (s.hAccel) { + DestroyAcceleratorTable(s.hAccel); + } + + CAtlArray pAccel; + pAccel.SetCount(ACCEL_LIST_SIZE); + int accel_count = 0; + POSITION pos = m_wmcmds.GetHeadPosition(); + for (int i = 0; pos; i++) { + ACCEL x = m_wmcmds.GetNext(pos); + if (x.key > 0) { + pAccel[accel_count] = x; + accel_count++; + } + } + s.hAccel = CreateAcceleratorTable(pAccel.GetData(), accel_count); + + CFrameWnd* parent = GetParentFrame(); + if (parent) { + parent->m_hAccelTable = s.hAccel; + } + + s.fWinLirc = !!m_fWinLirc; + s.strWinLircAddr = m_WinLircAddr; + if (s.fWinLirc) { + s.WinLircClient.Connect(m_WinLircAddr); + } + s.fUIce = !!m_fUIce; + s.strUIceAddr = m_UIceAddr; + if (s.fUIce) { + s.UIceClient.Connect(m_UIceAddr); + } + s.fGlobalMedia = !!m_fGlobalMedia; + + AfxGetMyApp()->RegisterHotkeys(); + + return __super::OnApply(); +} + +void CPPageAccelTbl::OnBnClickedSelectAll() +{ + m_list.SetFocus(); + + for (int i = 0, j = m_list.GetItemCount(); i < j; i++) { + m_list.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED); + } +} + +void CPPageAccelTbl::OnBnClickedReset() +{ + m_list.SetFocus(); + + POSITION pos = m_list.GetFirstSelectedItemPosition(); + if (!pos) { + return; + } + + while (pos) { + int ni = m_list.GetNextSelectedItem(pos); + POSITION pi = ((ITEMDATA*)m_list.GetItemData(ni))->index; + wmcmd& wc = m_wmcmds.GetAt(pi); + wc.Restore(); + } + + SetupList(); + + SetModified(); +} + +void CPPageAccelTbl::OnChangeFilterEdit() +{ + KillTimer(filterTimerID); + filterTimerID = SetTimer(2, 100, NULL); +} + +void CPPageAccelTbl::FilterList() +{ + CString filter; + filterEdit.GetWindowText(filter); + LANGID langid = AfxGetAppSettings().language; + filter = NormalizeUnicodeStrForSearch(filter, langid); + + m_list.SetRedraw(false); + m_list.DeleteAllItems(); + m_pItemsData.clear(); + + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; ) { + CString hotkey, id, name, sname; + + wmcmd& wc = m_wmcmds.GetAt(pos); + + HotkeyModToString(wc.key, wc.fVirt, hotkey); + id.Format(_T("%u"), wc.cmd); + sname = wc.GetName(); + + sname = NormalizeUnicodeStrForSearch(sname, langid); + id = NormalizeUnicodeStrForSearch(id, langid); + hotkey = NormalizeUnicodeStrForSearch(hotkey, langid); + + if (filter.IsEmpty() || sname.Find(filter) != -1 || hotkey.Find(filter) != -1 || id.Find(filter) != -1) { + int row = m_list.InsertItem(m_list.GetItemCount(), wc.GetName(), COL_CMD); + auto itemData = std::make_unique(); + itemData->index = pos; + m_list.SetItemData(row, (DWORD_PTR)itemData.get()); + m_pItemsData.push_back(std::move(itemData)); + } + m_wmcmds.GetNext(pos); + } + SetupList(false); + m_list.SetRedraw(true); + m_list.RedrawWindow(); +} + +void CPPageAccelTbl::GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) { + auto itemData = (ITEMDATA*)m_list.GetItemData(nItem); + auto dup = itemData->flag; + if (iSubItem == COL_CMD && dup + || iSubItem == COL_KEY && (dup & DUP_KEY) + || iSubItem == COL_APPCMD && (dup & DUP_APPCMD) + || iSubItem == COL_RMCMD && (dup & DUP_RMCMD)) { + if (AppIsThemeLoaded()) { + clrTextBk = CMPCTheme::ListCtrlErrorColor; + overrideSelectedBG = true; + } else { + clrTextBk = RGB(255, 130, 120); + } + } else { + if (AppIsThemeLoaded()) { + clrTextBk = CMPCTheme::ContentBGColor; + } else { + clrTextBk = GetSysColor(COLOR_WINDOW); + } + } +} + +void CPPageAccelTbl::GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) { + horzGridColor = CMPCTheme::ListCtrlGridColor; + vertGridColor = CMPCTheme::ListCtrlGridColor; +} + +void CPPageAccelTbl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult) { + NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); + *pResult = CDRF_DODEFAULT; + + if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage) { + *pResult = CDRF_NOTIFYITEMDRAW; + } else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage) { + *pResult = CDRF_NOTIFYSUBITEMDRAW; + } else if ((CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage) { + bool ignore; + GetCustomTextColors(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, pLVCD->clrText, pLVCD->clrTextBk, ignore); + *pResult = CDRF_DODEFAULT; + } +} + +void CPPageAccelTbl::OnBeginListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (pItem->iItem < 0) { + return; + } + + if (pItem->iSubItem == COL_KEY || pItem->iSubItem == COL_APPCMD || pItem->iSubItem == COL_RMCMD || pItem->iSubItem == COL_RMREPCNT) { + *pResult = TRUE; + } +} + +static BYTE s_mods[] = {0, FALT, FCONTROL, FSHIFT, FCONTROL | FALT, FCONTROL | FSHIFT, FALT | FSHIFT, FCONTROL | FALT | FSHIFT}; + +void CPPageAccelTbl::OnDoListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + if (pItem->iItem < 0) { + *pResult = FALSE; + return; + } + + *pResult = TRUE; + + + wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(pItem->iItem))->index); + + CAtlList sl; + int nSel = -1; + + auto createHotkey = [&](auto virt, auto key) { + m_list.ShowInPlaceWinHotkey(pItem->iItem, pItem->iSubItem); + CWinHotkeyCtrl* pWinHotkey = (CWinHotkeyCtrl*)m_list.GetDlgItem(IDC_WINHOTKEY1); + UINT cod = 0, mod = 0; + if (virt & FALT) { + mod |= MOD_ALT; + } + if (virt & FCONTROL) { + mod |= MOD_CONTROL; + } + if (virt & FSHIFT) { + mod |= MOD_SHIFT; + } + cod = key; + pWinHotkey->SetWinHotkey(cod, mod); + }; + + switch (pItem->iSubItem) { + case COL_KEY: + createHotkey(wc.fVirt, wc.key); + break; + case COL_APPCMD: + for (int i = 0; i < _countof(g_CommandList); i++) { + sl.AddTail(g_CommandList[i].cmdname); + if (wc.appcmd == g_CommandList[i].appcmd) { + nSel = i; + } + } + + m_list.ShowInPlaceComboBox(pItem->iItem, pItem->iSubItem, sl, nSel); + break; + case COL_RMCMD: + m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem); + break; + case COL_RMREPCNT: + m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem); + break; + default: + *pResult = FALSE; + break; + } +} + +int CPPageAccelTbl::CompareFunc(LPARAM lParam1, LPARAM lParam2) +{ + int result; + + CString strItem1 = m_list.GetItemText(static_cast(lParam1), sortColumn); + CString strItem2 = m_list.GetItemText(static_cast(lParam2), sortColumn); + if (sortColumn == COL_ID || sortColumn == COL_RMREPCNT) { + wmcmd& wc1 = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(static_cast(lParam1)))->index); + wmcmd& wc2 = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(static_cast(lParam2)))->index); + + result = wc1.cmd == wc2.cmd ? 0 : (wc1.cmd < wc2.cmd ? -1 : 1); + } else { + result = strItem1.Compare(strItem2); + } + + if (sortDirection == HDF_SORTUP) { + return result; + } else { + return -result; + } +} + +static int CALLBACK StaticCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + CPPageAccelTbl* ppAccelTbl = (CPPageAccelTbl*)lParamSort; + return ppAccelTbl->CompareFunc(lParam1, lParam2); +} + +void CPPageAccelTbl::UpdateHeaderSort(int column, int sort) +{ + CHeaderCtrl* hdr = m_list.GetHeaderCtrl(); + HDITEMW hItem = { 0 }; + hItem.mask = HDI_FORMAT; + if (hdr->GetItem(column, &hItem)) { + if (sort == HDF_SORTUP) { + hItem.fmt |= HDF_SORTUP; + hItem.fmt &= ~HDF_SORTDOWN; + } else if (sort == HDF_SORTDOWN) { + hItem.fmt |= HDF_SORTDOWN; + hItem.fmt &= ~HDF_SORTUP; + } else { //no sort + hItem.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); + } + hdr->SetItem(column, &hItem); + } +} + +void CPPageAccelTbl::OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; + int colToSort = pNMListView->iSubItem; + if (colToSort == sortColumn) { + sortDirection = sortDirection == HDF_SORTUP ? HDF_SORTDOWN : HDF_SORTUP; + } else { + if (sortColumn != -1) { + UpdateHeaderSort(sortColumn, 0); //clear old sort + } + sortColumn = colToSort; + sortDirection = HDF_SORTUP; + } + m_list.SortItemsEx(StaticCompareFunc, (LPARAM)this); + UpdateHeaderSort(sortColumn, sortDirection); +} + +void CPPageAccelTbl::OnEndListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (!m_list.m_fInPlaceDirty) { + return; + } + + if (pItem->iItem < 0) { + return; + } + wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(pItem->iItem))->index); + + auto updateHotkey = [&](auto &virt, auto &key) { + UINT cod, mod; + CWinHotkeyCtrl* pWinHotkey = (CWinHotkeyCtrl*)m_list.GetDlgItem(IDC_WINHOTKEY1); + pWinHotkey->GetWinHotkey(&cod, &mod); + ASSERT(cod < WORD_MAX); + key = (WORD)cod; + virt = FVIRTKEY; + if (mod & MOD_ALT) { + virt |= FALT; + } + if (mod & MOD_CONTROL) { + virt |= FCONTROL; + } + if (mod & MOD_SHIFT) { + virt |= FSHIFT; + } + + CString str; + HotkeyToString(key, mod, str); + m_list.SetItemText(pItem->iItem, pItem->iSubItem, str); + + *pResult = TRUE; + UpdateKeyDupFlags(); + }; + + WORD discard; + switch (pItem->iSubItem) { + case COL_KEY: + updateHotkey(wc.fVirt, wc.key); + break; + case COL_APPCMD: { + ptrdiff_t i = pItem->lParam; + if (i >= 0 && i < _countof(g_CommandList)) { + wc.appcmd = g_CommandList[i].appcmd; + m_list.SetItemText(pItem->iItem, COL_APPCMD, pItem->pszText); + *pResult = TRUE; + UpdateAppcmdDupFlags(); + } + } + break; + case COL_RMCMD: { + CString cmd = pItem->pszText; + cmd.Trim(); + cmd.Replace(_T(' '), ('_')); + m_list.SetItemText(pItem->iItem, pItem->iSubItem, cmd); + wc.rmcmd = cmd; + *pResult = TRUE; + UpdateRmcmdDupFlags(); + break; + } + case COL_RMREPCNT: + CString str = pItem->pszText; + wc.rmrepcnt = _tcstol(str.Trim(), nullptr, 10); + str.Format(_T("%d"), wc.rmrepcnt); + m_list.SetItemText(pItem->iItem, pItem->iSubItem, str); + *pResult = TRUE; + break; + } + + if (*pResult) { + m_list.RedrawWindow(); + SetModified(); + } +} + +void CPPageAccelTbl::OnTimer(UINT_PTR nIDEvent) +{ + if (nIDEvent == m_nStatusTimerID) { + UpdateData(); + + CAppSettings& s = AfxGetAppSettings(); + + if (m_fWinLirc) { + CString addr; + m_WinLircEdit.GetWindowText(addr); + s.WinLircClient.Connect(addr); + } + + m_WinLircEdit.Invalidate(); + + if (m_fUIce) { + CString addr; + m_UIceEdit.GetWindowText(addr); + s.UIceClient.Connect(addr); + } + + m_UIceEdit.Invalidate(); + + m_counter++; + } else if (nIDEvent == filterTimerID) { + KillTimer(filterTimerID); + FilterList(); + } else { + __super::OnTimer(nIDEvent); + } +} + +HBRUSH CPPageAccelTbl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + + const CAppSettings& s = AfxGetAppSettings(); + if (AppIsThemeLoaded()) { + return hbr; //should have already been handled inside themed ctlcolor + } + int status = -1; + + if (*pWnd == m_WinLircEdit) { + status = s.WinLircClient.GetStatus(); + } else if (*pWnd == m_UIceEdit) { + status = s.UIceClient.GetStatus(); + } + + if (status == 0 || status == 2 && (m_counter & 1)) { + pDC->SetTextColor(0x0000ff); + } else if (status == 1) { + pDC->SetTextColor(0x008000); + } + + return hbr; +} + +BOOL CPPageAccelTbl::OnSetActive() +{ + m_nStatusTimerID = SetTimer(1, 1000, nullptr); + + return CPPageBase::OnSetActive(); +} + +BOOL CPPageAccelTbl::OnKillActive() +{ + KillTimer(m_nStatusTimerID); + m_nStatusTimerID = 0; + + return CPPageBase::OnKillActive(); +} + +void CPPageAccelTbl::OnCancel() +{ + CAppSettings& s = AfxGetAppSettings(); + + if (!s.fWinLirc) { + s.WinLircClient.DisConnect(); + } + if (!s.fUIce) { + s.UIceClient.DisConnect(); + } + + __super::OnCancel(); +} diff --git a/src/mpc-hc/PPageAccelTbl.h b/src/mpc-hc/PPageAccelTbl.h index 28a6ce5d0f1..b2dbc11ed7f 100644 --- a/src/mpc-hc/PPageAccelTbl.h +++ b/src/mpc-hc/PPageAccelTbl.h @@ -1,125 +1,125 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 see Authors.txt - * - * This film_liste 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 . - * - */ - -#pragma once - -#include "PPageBase.h" -#include "PlayerListCtrl.h" -#include "StaticLink.h" -#include "WinHotkeyCtrl.h" -#include "vkCodes.h" -#include "CMPCThemePPageBase.h" -#include "CMPCThemeStaticLink.h" -#include "CMPCThemeEdit.h" - -// CPPageAccelTbl dialog - -class CPPageAccelTbl : public CMPCThemePPageBase - , public CMPCThemeListCtrlCustomInterface -{ -private: - enum { - COL_CMD, - COL_KEY, - COL_ID, - COL_APPCMD, - COL_RMCMD, - COL_RMREPCNT - }; - - enum { APPCOMMAND_LAST = APPCOMMAND_DWM_FLIP3D }; - - CList m_wmcmds; - - void UpdateKeyDupFlags(); - void UpdateAppcmdDupFlags(); - void UpdateRmcmdDupFlags(); - void UpdateAllDupFlags(); - - int m_counter; - struct ITEMDATA - { - POSITION index = 0; - DWORD flag = 0; - }; - std::vector> m_pItemsData; - - CPlayerListCtrl m_list; - int sortColumn = -1; - int sortDirection; - BOOL m_fWinLirc; - CString m_WinLircAddr; - CMPCThemeEdit m_WinLircEdit; - CMPCThemeStaticLink m_WinLircLink; - BOOL m_fUIce; - CString m_UIceAddr; - CMPCThemeEdit m_UIceEdit; - CMPCThemeEdit filterEdit; - CMPCThemeStaticLink m_UIceLink; - UINT_PTR m_nStatusTimerID, filterTimerID; - BOOL m_fGlobalMedia; - - static CString MakeAccelModLabel(BYTE fVirt); - static CString MakeAccelShortcutLabel(const ACCEL& a); - static CString MakeAppCommandLabel(UINT id); - - void SetupList(bool allowResize = true); - -public: - DECLARE_DYNAMIC(CPPageAccelTbl) - - CPPageAccelTbl(); - virtual ~CPPageAccelTbl(); - - // Dialog Data - enum { IDD = IDD_PPAGEACCELTBL }; - - static CString MakeAccelShortcutLabel(UINT id); - int CompareFunc(LPARAM lParam1, LPARAM lParam2); - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual BOOL OnApply(); - virtual BOOL PreTranslateMessage(MSG* pMsg); - virtual BOOL OnSetActive(); - virtual BOOL OnKillActive(); - void UpdateHeaderSort(int column, int sort); - void FilterList(); - virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG); - virtual void DoCustomPrePaint() {} - virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor); - - DECLARE_MESSAGE_MAP() - - afx_msg void OnBeginListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDoListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnEndListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnBnClickedSelectAll(); - afx_msg void OnBnClickedReset(); - afx_msg void OnChangeFilterEdit(); - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - afx_msg void OnTimer(UINT_PTR nIDEvent); - afx_msg void OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult); - - virtual void OnCancel(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 see Authors.txt + * + * This film_liste 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 . + * + */ + +#pragma once + +#include "PPageBase.h" +#include "PlayerListCtrl.h" +#include "StaticLink.h" +#include "WinHotkeyCtrl.h" +#include "vkCodes.h" +#include "CMPCThemePPageBase.h" +#include "CMPCThemeStaticLink.h" +#include "CMPCThemeEdit.h" + +// CPPageAccelTbl dialog + +class CPPageAccelTbl : public CMPCThemePPageBase + , public CMPCThemeListCtrlCustomInterface +{ +private: + enum { + COL_CMD, + COL_KEY, + COL_ID, + COL_APPCMD, + COL_RMCMD, + COL_RMREPCNT + }; + + enum { APPCOMMAND_LAST = APPCOMMAND_DWM_FLIP3D }; + + CList m_wmcmds; + + void UpdateKeyDupFlags(); + void UpdateAppcmdDupFlags(); + void UpdateRmcmdDupFlags(); + void UpdateAllDupFlags(); + + int m_counter; + struct ITEMDATA + { + POSITION index = 0; + DWORD flag = 0; + }; + std::vector> m_pItemsData; + + CPlayerListCtrl m_list; + int sortColumn = -1; + int sortDirection; + BOOL m_fWinLirc; + CString m_WinLircAddr; + CMPCThemeEdit m_WinLircEdit; + CMPCThemeStaticLink m_WinLircLink; + BOOL m_fUIce; + CString m_UIceAddr; + CMPCThemeEdit m_UIceEdit; + CMPCThemeEdit filterEdit; + CMPCThemeStaticLink m_UIceLink; + UINT_PTR m_nStatusTimerID, filterTimerID; + BOOL m_fGlobalMedia; + + static CString MakeAccelModLabel(BYTE fVirt); + static CString MakeAccelShortcutLabel(const ACCEL& a); + static CString MakeAppCommandLabel(UINT id); + + void SetupList(bool allowResize = true); + +public: + DECLARE_DYNAMIC(CPPageAccelTbl) + + CPPageAccelTbl(); + virtual ~CPPageAccelTbl(); + + // Dialog Data + enum { IDD = IDD_PPAGEACCELTBL }; + + static CString MakeAccelShortcutLabel(UINT id); + int CompareFunc(LPARAM lParam1, LPARAM lParam2); + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual BOOL OnApply(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL OnSetActive(); + virtual BOOL OnKillActive(); + void UpdateHeaderSort(int column, int sort); + void FilterList(); + virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG); + virtual void DoCustomPrePaint() {} + virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnBeginListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDoListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnEndListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnBnClickedSelectAll(); + afx_msg void OnBnClickedReset(); + afx_msg void OnChangeFilterEdit(); + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg void OnTimer(UINT_PTR nIDEvent); + afx_msg void OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult); + + virtual void OnCancel(); +}; diff --git a/src/mpc-hc/PPageAudioSwitcher.cpp b/src/mpc-hc/PPageAudioSwitcher.cpp index 6f61ecb24ed..95596a25bc8 100644 --- a/src/mpc-hc/PPageAudioSwitcher.cpp +++ b/src/mpc-hc/PPageAudioSwitcher.cpp @@ -1,440 +1,440 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include -#include "mplayerc.h" -#include "MainFrm.h" -#include "PPageAudioSwitcher.h" -#include "CMPCTheme.h" -#include "CMPCThemeHeaderCtrl.h" - - -// CPPageAudioSwitcher dialog - -#pragma warning(push) -#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized -IMPLEMENT_DYNAMIC(CPPageAudioSwitcher, CMPCThemePPageBase) -CPPageAudioSwitcher::CPPageAudioSwitcher(IFilterGraph* pFG) -#if 1 - : CMPCThemePPageBase(CPPageAudioSwitcher::IDD, CPPageAudioSwitcher::IDD) -#else - : CMPCThemePPageBase(CPPageAudioSwitcher::IDD, IDS_AUDIOSWITCHER) -#endif - , m_pSpeakerToChannelMap() - , m_dwChannelMask(0) - , m_fEnableAudioSwitcher(FALSE) - , m_fAudioNormalize(FALSE) - , m_nAudioMaxNormFactor(400) - , m_fAudioNormalizeRecover(FALSE) - , m_AudioBoostPos(0) - , m_fDownSampleTo441(FALSE) - , m_fCustomChannelMapping(FALSE) - , m_nChannels(0) - , m_tAudioTimeShift(0) - , m_fAudioTimeShift(FALSE) -{ - CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), pFG); - - if (pASF) { - pASF->GetInputSpeakerConfig(&m_dwChannelMask); - m_nChannels = pASF->GetNumberOfInputChannels(); - } -} -#pragma warning(pop) - -CPPageAudioSwitcher::~CPPageAudioSwitcher() -{ -} - -void CPPageAudioSwitcher::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Check(pDX, IDC_CHECK5, m_fAudioNormalize); - DDX_Text(pDX, IDC_EDIT3, m_nAudioMaxNormFactor); - DDX_Control(pDX, IDC_SPIN3, m_AudioMaxNormFactorSpin); - DDX_Check(pDX, IDC_CHECK6, m_fAudioNormalizeRecover); - DDX_Slider(pDX, IDC_SLIDER1, m_AudioBoostPos); - DDX_Control(pDX, IDC_SLIDER1, m_AudioBoostCtrl); - DDX_Check(pDX, IDC_CHECK3, m_fDownSampleTo441); - DDX_Check(pDX, IDC_CHECK1, m_fCustomChannelMapping); - DDX_Control(pDX, IDC_EDIT1, m_nChannelsCtrl); - DDX_Text(pDX, IDC_EDIT1, m_nChannels); - if (m_nChannels > AS_MAX_CHANNELS) { - m_nChannels = AS_MAX_CHANNELS; - SetDlgItemText(IDC_EDIT1, L"18"); - } - DDX_Control(pDX, IDC_SPIN1, m_nChannelsSpinCtrl); - DDX_Control(pDX, IDC_LIST1, m_list); - DDX_Check(pDX, IDC_CHECK2, m_fEnableAudioSwitcher); - DDX_Control(pDX, IDC_CHECK3, m_fDownSampleTo441Ctrl); - DDX_Control(pDX, IDC_CHECK1, m_fCustomChannelMappingCtrl); - DDX_Control(pDX, IDC_EDIT2, m_tAudioTimeShiftCtrl); - DDX_Control(pDX, IDC_SPIN2, m_tAudioTimeShiftSpin); - DDX_Text(pDX, IDC_EDIT2, m_tAudioTimeShift); - DDX_Check(pDX, IDC_CHECK4, m_fAudioTimeShift); - DDX_Control(pDX, IDC_CHECK4, m_fAudioTimeShiftCtrl); -} - -BEGIN_MESSAGE_MAP(CPPageAudioSwitcher, CMPCThemePPageBase) - ON_NOTIFY(NM_CLICK, IDC_LIST1, OnNMClickList1) - ON_WM_DRAWITEM() - ON_EN_CHANGE(IDC_EDIT1, OnEnChangeEdit1) - ON_UPDATE_COMMAND_UI(IDC_STATIC6, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_SLIDER1, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_CHECK5, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_STATIC4, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_STATIC5, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_CHECK6, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_EDIT2, OnUpdateTimeShift) - ON_UPDATE_COMMAND_UI(IDC_SPIN2, OnUpdateTimeShift) - ON_UPDATE_COMMAND_UI(IDC_CHECK3, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_CHECK4, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_CHECK1, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_EDIT1, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_SPIN1, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_LIST1, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_STATIC2, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_STATIC3, OnUpdateChannelMapping) - ON_WM_HSCROLL() - ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) -END_MESSAGE_MAP() - - -// CPPageAudioSwitcher message handlers - -BOOL CPPageAudioSwitcher::OnInitDialog() -{ - __super::OnInitDialog(); - - const CAppSettings& s = AfxGetAppSettings(); - - m_fEnableAudioSwitcher = s.fEnableAudioSwitcher; - m_fAudioNormalize = s.fAudioNormalize; - m_nAudioMaxNormFactor = s.nAudioMaxNormFactor; - m_AudioMaxNormFactorSpin.SetRange32(100, 1000); - m_fAudioNormalizeRecover = s.fAudioNormalizeRecover; - m_AudioBoostCtrl.SetRange(0, 300); - m_AudioBoostCtrl.SetPageSize(10); - m_AudioBoostPos = s.nAudioBoost; - m_fDownSampleTo441 = s.fDownSampleTo441; - m_fAudioTimeShift = s.fAudioTimeShift; - m_tAudioTimeShift = s.iAudioTimeShift; - m_tAudioTimeShiftSpin.SetRange32(-1000 * 60 * 60 * 24, 1000 * 60 * 60 * 24); - m_fCustomChannelMapping = s.fCustomChannelMapping; - memcpy(m_pSpeakerToChannelMap, s.pSpeakerToChannelMap, sizeof(s.pSpeakerToChannelMap)); - - m_nChannels = std::clamp(s.nSpeakerChannels, 1, AS_MAX_CHANNELS); - m_nChannelsSpinCtrl.SetRange(1, AS_MAX_CHANNELS); - - m_list.setAdditionalStyles(0); //cleans up styles if necessary for mpc theme - m_list.InsertColumn(0, _T(""), LVCFMT_LEFT, 100); - m_list.InsertItem(0, _T("")); - m_list.InsertItem(1, ResStr(IDS_FRONT_LEFT)); - m_list.InsertItem(2, ResStr(IDS_FRONT_RIGHT)); - m_list.InsertItem(3, ResStr(IDS_FRONT_CENTER)); - m_list.InsertItem(4, ResStr(IDS_LOW_FREQUENCY)); - m_list.InsertItem(5, ResStr(IDS_BACK_LEFT)); - m_list.InsertItem(6, ResStr(IDS_BACK_RIGHT)); - m_list.InsertItem(7, ResStr(IDS_FRONT_LEFT_OF_CENTER)); - m_list.InsertItem(8, ResStr(IDS_FRONT_RIGHT_OF_CENTER)); - m_list.InsertItem(9, ResStr(IDS_BACK_CENTER)); - m_list.InsertItem(10, ResStr(IDS_SIDE_LEFT)); - m_list.InsertItem(11, ResStr(IDS_SIDE_RIGHT)); - m_list.InsertItem(12, ResStr(IDS_TOP_CENTER)); - m_list.InsertItem(13, ResStr(IDS_TOP_FRONT_LEFT)); - m_list.InsertItem(14, ResStr(IDS_TOP_FRONT_CENTER)); - m_list.InsertItem(15, ResStr(IDS_TOP_FRONT_RIGHT)); - m_list.InsertItem(16, ResStr(IDS_TOP_BACK_LEFT)); - m_list.InsertItem(17, ResStr(IDS_TOP_BACK_CENTER)); - m_list.InsertItem(18, ResStr(IDS_TOP_BACK_RIGHT)); - m_list.SetColumnWidth(0, LVSCW_AUTOSIZE); - - for (int i = 1; i <= AS_MAX_CHANNELS; i++) { - m_list.InsertColumn(i, _T(""), LVCFMT_CENTER, 16); - CString n; - n.Format(_T("%d"), i); - m_list.SetItemText(0, i, n); - // m_list.SetColumnWidth(i, LVSCW_AUTOSIZE); - // m_list.SetColumnWidth(i, m_list.GetColumnWidth(i)*8/10); - } - - EnableThemedDialogTooltips(this); - m_tooltip.Create(this); - m_tooltip.Activate(TRUE); - - CorrectComboBoxHeaderWidth(GetDlgItem(IDC_CHECK5)); - - UpdateData(FALSE); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -BOOL CPPageAudioSwitcher::OnApply() -{ - UpdateData(); - - CAppSettings& s = AfxGetAppSettings(); - - s.fEnableAudioSwitcher = !!m_fEnableAudioSwitcher; - s.fAudioNormalize = !!m_fAudioNormalize; - if (m_nAudioMaxNormFactor > 1000) { - m_nAudioMaxNormFactor = 1000; - } else if (m_nAudioMaxNormFactor < 100) { - m_nAudioMaxNormFactor = 100; - } - s.nAudioMaxNormFactor = m_nAudioMaxNormFactor; - s.fAudioNormalizeRecover = !!m_fAudioNormalizeRecover; - s.nAudioBoost = m_AudioBoostPos; - s.fDownSampleTo441 = !!m_fDownSampleTo441; - s.fAudioTimeShift = !!m_fAudioTimeShift; - s.iAudioTimeShift = m_tAudioTimeShift; - s.fCustomChannelMapping = !!m_fCustomChannelMapping; - memcpy(s.pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); - s.nSpeakerChannels = std::clamp(m_nChannels, 1, AS_MAX_CHANNELS); - - // There is no main frame when the option dialog is displayed stand-alone - if (CMainFrame* pMainFrame = AfxGetMainFrame()) { - pMainFrame->UpdateControlState(CMainFrame::UPDATE_AUDIO_SWITCHER); - } - - return __super::OnApply(); -} - -void CPPageAudioSwitcher::OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pNMHDR; - - if (lpnmlv->iItem > 0 && lpnmlv->iSubItem > 0 && lpnmlv->iSubItem <= m_nChannels) { - UpdateData(); - m_pSpeakerToChannelMap[m_nChannels - 1][lpnmlv->iItem - 1] ^= 1 << (lpnmlv->iSubItem - 1); - m_list.RedrawItems(lpnmlv->iItem, lpnmlv->iItem); - SetModified(); - - if (GetKeyState(VK_SHIFT) & 0x8000) { - OnApply(); - } - } - - *pResult = 0; -} - -void CPPageAudioSwitcher::OnEnChangeEdit1() -{ - if (IsWindow(m_list.m_hWnd)) { - UpdateData(); - m_list.Invalidate(); - SetModified(); - } -} - -void CPPageAudioSwitcher::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - if (nIDCtl != IDC_LIST1) { - return; - } - - // if (lpDrawItemStruct->itemID == 0) - // UpdateData(); - - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - - pDC->SetBkMode(TRANSPARENT); - - COLORREF frameClr, textClr, textDisabledClr, textNAClr; - COLORREF oldBkColor = pDC->GetBkColor(); - if (AppNeedsThemedControls()) { - frameClr = CMPCTheme::AudioSwitcherGridColor; - textClr = CMPCTheme::TextFGColor; - textDisabledClr = CMPCTheme::ContentTextDisabledFGColorFade; - textNAClr = CMPCTheme::ContentTextDisabledFGColorFade2; - pDC->SetBkColor(CMPCTheme::ContentBGColor); - CRect bgRect = lpDrawItemStruct->rcItem; - pDC->FillSolidRect(bgRect, CMPCTheme::ContentBGColor); - } else { - frameClr = 0xe0e0e0; - textClr = 0; - textDisabledClr = 0xb0b0b0; - textNAClr = 0xe0e0e0; - } - - CPen p(PS_INSIDEFRAME, 1, frameClr); - CPen* old = pDC->SelectObject(&p); - - pDC->MoveTo(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - 1); - pDC->LineTo(lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom - 1); - - CHeaderCtrl* pHeader = m_list.GetHeaderCtrl(); - int nColumnCount = pHeader->GetItemCount(); - - for (int i = 0; i < nColumnCount; i++) { - CRect r, rb; - m_list.GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_BOUNDS, rb); - m_list.GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_LABEL, r); - - pDC->MoveTo(r.right - 1, r.top); - pDC->LineTo(r.right - 1, r.bottom - 1); - - CSize s = pDC->GetTextExtent(m_list.GetItemText(lpDrawItemStruct->itemID, i)); - - if (i == 0) { - r.left = rb.left; - - if (lpDrawItemStruct->itemID == 0) { - pDC->MoveTo(0, 0); - pDC->LineTo(r.right, r.bottom - 1); - } else { - pDC->SetTextColor(m_list.IsWindowEnabled() ? textClr : textDisabledClr); - pDC->TextOut(r.left + 1, (r.top + r.bottom - s.cy) / 2, m_list.GetItemText(lpDrawItemStruct->itemID, i)); - } - } else { - pDC->SetTextColor(i > m_nChannels ? textNAClr : (!m_list.IsWindowEnabled() ? textDisabledClr : textClr)); - - if (lpDrawItemStruct->itemID == 0) { - pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, m_list.GetItemText(lpDrawItemStruct->itemID, i)); - } else { - if (m_dwChannelMask & (1 << (lpDrawItemStruct->itemID - 1))) { - int nBitsSet = 0; - - for (int j = 1; j <= (1 << (lpDrawItemStruct->itemID - 1)); j <<= 1) { - if (m_dwChannelMask & j) { - nBitsSet++; - } - } - - if (nBitsSet == i) { - COLORREF tmp = pDC->GetTextColor(); - - pDC->SetTextColor(textNAClr); - CFont f; - f.CreatePointFont(MulDiv(100, 96, pDC->GetDeviceCaps(LOGPIXELSX)), _T("Marlett")); - CFont* old2 = pDC->SelectObject(&f); - UNREFERENCED_PARAMETER(old2); - s = pDC->GetTextExtent(_T("g")); - pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, _T("g")); - - pDC->SetTextColor(tmp); - } - } - - if (m_pSpeakerToChannelMap[m_nChannels - 1][lpDrawItemStruct->itemID - 1] & (1 << (i - 1))) { - CFont f; - f.CreatePointFont(MulDiv(100, 96, pDC->GetDeviceCaps(LOGPIXELSX)), _T("Marlett")); - CFont* old2 = pDC->SelectObject(&f); - s = pDC->GetTextExtent(_T("a")); - pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, _T("a")); - pDC->SelectObject(old2); - } - } - } - } - - pDC->SetBkColor(oldBkColor); - pDC->SelectObject(old); -} - -void CPPageAudioSwitcher::OnUpdateAudioSwitcher(CCmdUI* pCmdUI) -{ - // UpdateData(); - pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/); -} - -void CPPageAudioSwitcher::OnUpdateNormalize(CCmdUI* pCmdUI) -{ - // UpdateData(); - pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ - && IsDlgButtonChecked(IDC_CHECK5)/*m_fNormalize*/); -} - -void CPPageAudioSwitcher::OnUpdateTimeShift(CCmdUI* pCmdUI) -{ - // UpdateData(); - pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ - && IsDlgButtonChecked(IDC_CHECK4)/*m_fAudioTimeShift)*/); -} - -void CPPageAudioSwitcher::OnUpdateChannelMapping(CCmdUI* pCmdUI) -{ - // UpdateData(); - pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ - && IsDlgButtonChecked(IDC_CHECK1)/*m_fCustomChannelMapping*/); -} - -void CPPageAudioSwitcher::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - if (*pScrollBar == m_AudioBoostCtrl) { - UpdateData(); - ((CMainFrame*)GetParentFrame())->SetVolumeBoost(m_AudioBoostPos); // nice shortcut... - } - RedrawDialogTooltipIfVisible(); //if the scroll is caused by a wheel or arrows, the default tooltip may be active due to hover, in which case, we want to update - - SetModified(); - - __super::OnHScroll(nSBCode, nPos, pScrollBar); -} - -BOOL CPPageAudioSwitcher::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) -{ - TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR; - - UINT_PTR nID = pNMHDR->idFrom; - if (pTTT->uFlags & TTF_IDISHWND) { - nID = ::GetDlgCtrlID((HWND)nID); - } - - bool bRet = false; - - static CString strTipText; - - switch (nID) { - case IDC_SLIDER1: - strTipText.Format(IDS_BOOST, m_AudioBoostCtrl.GetPos()); - bRet = true; - break; - case IDC_EDIT2: - case IDC_SPIN2: - strTipText.LoadString(IDS_TIME_SHIFT_TOOLTIP); - bRet = true; - break; - } - - if (bRet) { - pTTT->lpszText = (LPWSTR)(LPCWSTR)strTipText; - PlaceThemedDialogTooltip(nID); - } - - return bRet; -} - -void CPPageAudioSwitcher::OnCancel() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if ((UINT)m_AudioBoostPos != s.nAudioBoost) { - ((CMainFrame*)GetParentFrame())->SetVolumeBoost(s.nAudioBoost); - } - - __super::OnCancel(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include +#include "mplayerc.h" +#include "MainFrm.h" +#include "PPageAudioSwitcher.h" +#include "CMPCTheme.h" +#include "CMPCThemeHeaderCtrl.h" + + +// CPPageAudioSwitcher dialog + +#pragma warning(push) +#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized +IMPLEMENT_DYNAMIC(CPPageAudioSwitcher, CMPCThemePPageBase) +CPPageAudioSwitcher::CPPageAudioSwitcher(IFilterGraph* pFG) +#if 1 + : CMPCThemePPageBase(CPPageAudioSwitcher::IDD, CPPageAudioSwitcher::IDD) +#else + : CMPCThemePPageBase(CPPageAudioSwitcher::IDD, IDS_AUDIOSWITCHER) +#endif + , m_pSpeakerToChannelMap() + , m_dwChannelMask(0) + , m_fEnableAudioSwitcher(FALSE) + , m_fAudioNormalize(FALSE) + , m_nAudioMaxNormFactor(400) + , m_fAudioNormalizeRecover(FALSE) + , m_AudioBoostPos(0) + , m_fDownSampleTo441(FALSE) + , m_fCustomChannelMapping(FALSE) + , m_nChannels(0) + , m_tAudioTimeShift(0) + , m_fAudioTimeShift(FALSE) +{ + CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), pFG); + + if (pASF) { + pASF->GetInputSpeakerConfig(&m_dwChannelMask); + m_nChannels = pASF->GetNumberOfInputChannels(); + } +} +#pragma warning(pop) + +CPPageAudioSwitcher::~CPPageAudioSwitcher() +{ +} + +void CPPageAudioSwitcher::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Check(pDX, IDC_CHECK5, m_fAudioNormalize); + DDX_Text(pDX, IDC_EDIT3, m_nAudioMaxNormFactor); + DDX_Control(pDX, IDC_SPIN3, m_AudioMaxNormFactorSpin); + DDX_Check(pDX, IDC_CHECK6, m_fAudioNormalizeRecover); + DDX_Slider(pDX, IDC_SLIDER1, m_AudioBoostPos); + DDX_Control(pDX, IDC_SLIDER1, m_AudioBoostCtrl); + DDX_Check(pDX, IDC_CHECK3, m_fDownSampleTo441); + DDX_Check(pDX, IDC_CHECK1, m_fCustomChannelMapping); + DDX_Control(pDX, IDC_EDIT1, m_nChannelsCtrl); + DDX_Text(pDX, IDC_EDIT1, m_nChannels); + if (m_nChannels > AS_MAX_CHANNELS) { + m_nChannels = AS_MAX_CHANNELS; + SetDlgItemText(IDC_EDIT1, L"18"); + } + DDX_Control(pDX, IDC_SPIN1, m_nChannelsSpinCtrl); + DDX_Control(pDX, IDC_LIST1, m_list); + DDX_Check(pDX, IDC_CHECK2, m_fEnableAudioSwitcher); + DDX_Control(pDX, IDC_CHECK3, m_fDownSampleTo441Ctrl); + DDX_Control(pDX, IDC_CHECK1, m_fCustomChannelMappingCtrl); + DDX_Control(pDX, IDC_EDIT2, m_tAudioTimeShiftCtrl); + DDX_Control(pDX, IDC_SPIN2, m_tAudioTimeShiftSpin); + DDX_Text(pDX, IDC_EDIT2, m_tAudioTimeShift); + DDX_Check(pDX, IDC_CHECK4, m_fAudioTimeShift); + DDX_Control(pDX, IDC_CHECK4, m_fAudioTimeShiftCtrl); +} + +BEGIN_MESSAGE_MAP(CPPageAudioSwitcher, CMPCThemePPageBase) + ON_NOTIFY(NM_CLICK, IDC_LIST1, OnNMClickList1) + ON_WM_DRAWITEM() + ON_EN_CHANGE(IDC_EDIT1, OnEnChangeEdit1) + ON_UPDATE_COMMAND_UI(IDC_STATIC6, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_SLIDER1, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_CHECK5, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_STATIC4, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_STATIC5, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_CHECK6, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_EDIT2, OnUpdateTimeShift) + ON_UPDATE_COMMAND_UI(IDC_SPIN2, OnUpdateTimeShift) + ON_UPDATE_COMMAND_UI(IDC_CHECK3, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_CHECK4, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_CHECK1, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_EDIT1, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_SPIN1, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_LIST1, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_STATIC2, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_STATIC3, OnUpdateChannelMapping) + ON_WM_HSCROLL() + ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) +END_MESSAGE_MAP() + + +// CPPageAudioSwitcher message handlers + +BOOL CPPageAudioSwitcher::OnInitDialog() +{ + __super::OnInitDialog(); + + const CAppSettings& s = AfxGetAppSettings(); + + m_fEnableAudioSwitcher = s.fEnableAudioSwitcher; + m_fAudioNormalize = s.fAudioNormalize; + m_nAudioMaxNormFactor = s.nAudioMaxNormFactor; + m_AudioMaxNormFactorSpin.SetRange32(100, 1000); + m_fAudioNormalizeRecover = s.fAudioNormalizeRecover; + m_AudioBoostCtrl.SetRange(0, 300); + m_AudioBoostCtrl.SetPageSize(10); + m_AudioBoostPos = s.nAudioBoost; + m_fDownSampleTo441 = s.fDownSampleTo441; + m_fAudioTimeShift = s.fAudioTimeShift; + m_tAudioTimeShift = s.iAudioTimeShift; + m_tAudioTimeShiftSpin.SetRange32(-1000 * 60 * 60 * 24, 1000 * 60 * 60 * 24); + m_fCustomChannelMapping = s.fCustomChannelMapping; + memcpy(m_pSpeakerToChannelMap, s.pSpeakerToChannelMap, sizeof(s.pSpeakerToChannelMap)); + + m_nChannels = std::clamp(s.nSpeakerChannels, 1, AS_MAX_CHANNELS); + m_nChannelsSpinCtrl.SetRange(1, AS_MAX_CHANNELS); + + m_list.setAdditionalStyles(0); //cleans up styles if necessary for mpc theme + m_list.InsertColumn(0, _T(""), LVCFMT_LEFT, 100); + m_list.InsertItem(0, _T("")); + m_list.InsertItem(1, ResStr(IDS_FRONT_LEFT)); + m_list.InsertItem(2, ResStr(IDS_FRONT_RIGHT)); + m_list.InsertItem(3, ResStr(IDS_FRONT_CENTER)); + m_list.InsertItem(4, ResStr(IDS_LOW_FREQUENCY)); + m_list.InsertItem(5, ResStr(IDS_BACK_LEFT)); + m_list.InsertItem(6, ResStr(IDS_BACK_RIGHT)); + m_list.InsertItem(7, ResStr(IDS_FRONT_LEFT_OF_CENTER)); + m_list.InsertItem(8, ResStr(IDS_FRONT_RIGHT_OF_CENTER)); + m_list.InsertItem(9, ResStr(IDS_BACK_CENTER)); + m_list.InsertItem(10, ResStr(IDS_SIDE_LEFT)); + m_list.InsertItem(11, ResStr(IDS_SIDE_RIGHT)); + m_list.InsertItem(12, ResStr(IDS_TOP_CENTER)); + m_list.InsertItem(13, ResStr(IDS_TOP_FRONT_LEFT)); + m_list.InsertItem(14, ResStr(IDS_TOP_FRONT_CENTER)); + m_list.InsertItem(15, ResStr(IDS_TOP_FRONT_RIGHT)); + m_list.InsertItem(16, ResStr(IDS_TOP_BACK_LEFT)); + m_list.InsertItem(17, ResStr(IDS_TOP_BACK_CENTER)); + m_list.InsertItem(18, ResStr(IDS_TOP_BACK_RIGHT)); + m_list.SetColumnWidth(0, LVSCW_AUTOSIZE); + + for (int i = 1; i <= AS_MAX_CHANNELS; i++) { + m_list.InsertColumn(i, _T(""), LVCFMT_CENTER, 16); + CString n; + n.Format(_T("%d"), i); + m_list.SetItemText(0, i, n); + // m_list.SetColumnWidth(i, LVSCW_AUTOSIZE); + // m_list.SetColumnWidth(i, m_list.GetColumnWidth(i)*8/10); + } + + EnableThemedDialogTooltips(this); + m_tooltip.Create(this); + m_tooltip.Activate(TRUE); + + CorrectComboBoxHeaderWidth(GetDlgItem(IDC_CHECK5)); + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +BOOL CPPageAudioSwitcher::OnApply() +{ + UpdateData(); + + CAppSettings& s = AfxGetAppSettings(); + + s.fEnableAudioSwitcher = !!m_fEnableAudioSwitcher; + s.fAudioNormalize = !!m_fAudioNormalize; + if (m_nAudioMaxNormFactor > 1000) { + m_nAudioMaxNormFactor = 1000; + } else if (m_nAudioMaxNormFactor < 100) { + m_nAudioMaxNormFactor = 100; + } + s.nAudioMaxNormFactor = m_nAudioMaxNormFactor; + s.fAudioNormalizeRecover = !!m_fAudioNormalizeRecover; + s.nAudioBoost = m_AudioBoostPos; + s.fDownSampleTo441 = !!m_fDownSampleTo441; + s.fAudioTimeShift = !!m_fAudioTimeShift; + s.iAudioTimeShift = m_tAudioTimeShift; + s.fCustomChannelMapping = !!m_fCustomChannelMapping; + memcpy(s.pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); + s.nSpeakerChannels = std::clamp(m_nChannels, 1, AS_MAX_CHANNELS); + + // There is no main frame when the option dialog is displayed stand-alone + if (CMainFrame* pMainFrame = AfxGetMainFrame()) { + pMainFrame->UpdateControlState(CMainFrame::UPDATE_AUDIO_SWITCHER); + } + + return __super::OnApply(); +} + +void CPPageAudioSwitcher::OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pNMHDR; + + if (lpnmlv->iItem > 0 && lpnmlv->iSubItem > 0 && lpnmlv->iSubItem <= m_nChannels) { + UpdateData(); + m_pSpeakerToChannelMap[m_nChannels - 1][lpnmlv->iItem - 1] ^= 1 << (lpnmlv->iSubItem - 1); + m_list.RedrawItems(lpnmlv->iItem, lpnmlv->iItem); + SetModified(); + + if (GetKeyState(VK_SHIFT) & 0x8000) { + OnApply(); + } + } + + *pResult = 0; +} + +void CPPageAudioSwitcher::OnEnChangeEdit1() +{ + if (IsWindow(m_list.m_hWnd)) { + UpdateData(); + m_list.Invalidate(); + SetModified(); + } +} + +void CPPageAudioSwitcher::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (nIDCtl != IDC_LIST1) { + return; + } + + // if (lpDrawItemStruct->itemID == 0) + // UpdateData(); + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + + pDC->SetBkMode(TRANSPARENT); + + COLORREF frameClr, textClr, textDisabledClr, textNAClr; + COLORREF oldBkColor = pDC->GetBkColor(); + if (AppNeedsThemedControls()) { + frameClr = CMPCTheme::AudioSwitcherGridColor; + textClr = CMPCTheme::TextFGColor; + textDisabledClr = CMPCTheme::ContentTextDisabledFGColorFade; + textNAClr = CMPCTheme::ContentTextDisabledFGColorFade2; + pDC->SetBkColor(CMPCTheme::ContentBGColor); + CRect bgRect = lpDrawItemStruct->rcItem; + pDC->FillSolidRect(bgRect, CMPCTheme::ContentBGColor); + } else { + frameClr = 0xe0e0e0; + textClr = 0; + textDisabledClr = 0xb0b0b0; + textNAClr = 0xe0e0e0; + } + + CPen p(PS_INSIDEFRAME, 1, frameClr); + CPen* old = pDC->SelectObject(&p); + + pDC->MoveTo(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - 1); + pDC->LineTo(lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom - 1); + + CHeaderCtrl* pHeader = m_list.GetHeaderCtrl(); + int nColumnCount = pHeader->GetItemCount(); + + for (int i = 0; i < nColumnCount; i++) { + CRect r, rb; + m_list.GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_BOUNDS, rb); + m_list.GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_LABEL, r); + + pDC->MoveTo(r.right - 1, r.top); + pDC->LineTo(r.right - 1, r.bottom - 1); + + CSize s = pDC->GetTextExtent(m_list.GetItemText(lpDrawItemStruct->itemID, i)); + + if (i == 0) { + r.left = rb.left; + + if (lpDrawItemStruct->itemID == 0) { + pDC->MoveTo(0, 0); + pDC->LineTo(r.right, r.bottom - 1); + } else { + pDC->SetTextColor(m_list.IsWindowEnabled() ? textClr : textDisabledClr); + pDC->TextOut(r.left + 1, (r.top + r.bottom - s.cy) / 2, m_list.GetItemText(lpDrawItemStruct->itemID, i)); + } + } else { + pDC->SetTextColor(i > m_nChannels ? textNAClr : (!m_list.IsWindowEnabled() ? textDisabledClr : textClr)); + + if (lpDrawItemStruct->itemID == 0) { + pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, m_list.GetItemText(lpDrawItemStruct->itemID, i)); + } else { + if (m_dwChannelMask & (1 << (lpDrawItemStruct->itemID - 1))) { + int nBitsSet = 0; + + for (int j = 1; j <= (1 << (lpDrawItemStruct->itemID - 1)); j <<= 1) { + if (m_dwChannelMask & j) { + nBitsSet++; + } + } + + if (nBitsSet == i) { + COLORREF tmp = pDC->GetTextColor(); + + pDC->SetTextColor(textNAClr); + CFont f; + f.CreatePointFont(MulDiv(100, 96, pDC->GetDeviceCaps(LOGPIXELSX)), _T("Marlett")); + CFont* old2 = pDC->SelectObject(&f); + UNREFERENCED_PARAMETER(old2); + s = pDC->GetTextExtent(_T("g")); + pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, _T("g")); + + pDC->SetTextColor(tmp); + } + } + + if (m_pSpeakerToChannelMap[m_nChannels - 1][lpDrawItemStruct->itemID - 1] & (1 << (i - 1))) { + CFont f; + f.CreatePointFont(MulDiv(100, 96, pDC->GetDeviceCaps(LOGPIXELSX)), _T("Marlett")); + CFont* old2 = pDC->SelectObject(&f); + s = pDC->GetTextExtent(_T("a")); + pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, _T("a")); + pDC->SelectObject(old2); + } + } + } + } + + pDC->SetBkColor(oldBkColor); + pDC->SelectObject(old); +} + +void CPPageAudioSwitcher::OnUpdateAudioSwitcher(CCmdUI* pCmdUI) +{ + // UpdateData(); + pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/); +} + +void CPPageAudioSwitcher::OnUpdateNormalize(CCmdUI* pCmdUI) +{ + // UpdateData(); + pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ + && IsDlgButtonChecked(IDC_CHECK5)/*m_fNormalize*/); +} + +void CPPageAudioSwitcher::OnUpdateTimeShift(CCmdUI* pCmdUI) +{ + // UpdateData(); + pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ + && IsDlgButtonChecked(IDC_CHECK4)/*m_fAudioTimeShift)*/); +} + +void CPPageAudioSwitcher::OnUpdateChannelMapping(CCmdUI* pCmdUI) +{ + // UpdateData(); + pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ + && IsDlgButtonChecked(IDC_CHECK1)/*m_fCustomChannelMapping*/); +} + +void CPPageAudioSwitcher::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + if (*pScrollBar == m_AudioBoostCtrl) { + UpdateData(); + ((CMainFrame*)GetParentFrame())->SetVolumeBoost(m_AudioBoostPos); // nice shortcut... + } + RedrawDialogTooltipIfVisible(); //if the scroll is caused by a wheel or arrows, the default tooltip may be active due to hover, in which case, we want to update + + SetModified(); + + __super::OnHScroll(nSBCode, nPos, pScrollBar); +} + +BOOL CPPageAudioSwitcher::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) +{ + TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR; + + UINT_PTR nID = pNMHDR->idFrom; + if (pTTT->uFlags & TTF_IDISHWND) { + nID = ::GetDlgCtrlID((HWND)nID); + } + + bool bRet = false; + + static CString strTipText; + + switch (nID) { + case IDC_SLIDER1: + strTipText.Format(IDS_BOOST, m_AudioBoostCtrl.GetPos()); + bRet = true; + break; + case IDC_EDIT2: + case IDC_SPIN2: + strTipText.LoadString(IDS_TIME_SHIFT_TOOLTIP); + bRet = true; + break; + } + + if (bRet) { + pTTT->lpszText = (LPWSTR)(LPCWSTR)strTipText; + PlaceThemedDialogTooltip(nID); + } + + return bRet; +} + +void CPPageAudioSwitcher::OnCancel() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if ((UINT)m_AudioBoostPos != s.nAudioBoost) { + ((CMainFrame*)GetParentFrame())->SetVolumeBoost(s.nAudioBoost); + } + + __super::OnCancel(); +} diff --git a/src/mpc-hc/PPageAudioSwitcher.h b/src/mpc-hc/PPageAudioSwitcher.h index a5bec944bfe..36c3649ab14 100644 --- a/src/mpc-hc/PPageAudioSwitcher.h +++ b/src/mpc-hc/PPageAudioSwitcher.h @@ -1,94 +1,94 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "CMPCThemePPageBase.h" -#include "FloatEdit.h" -#include "../filters/switcher/AudioSwitcher/AudioSwitcher.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeSliderCtrl.h" -#include "CMPCThemeEdit.h" -#include "CMPCThemeSpinButtonCtrl.h" -#include "CMPCThemePlayerListCtrl.h" - - - - -// CPPageAudioSwitcher dialog - -class CPPageAudioSwitcher : public CMPCThemePPageBase -{ - DECLARE_DYNAMIC(CPPageAudioSwitcher) - -private: - DWORD m_pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]; - DWORD m_dwChannelMask; - - BOOL m_fEnableAudioSwitcher; - BOOL m_fAudioNormalize; - UINT m_nAudioMaxNormFactor; - CMPCThemeSpinButtonCtrl m_AudioMaxNormFactorSpin; - BOOL m_fAudioNormalizeRecover; - int m_AudioBoostPos; - CMPCThemeSliderCtrl m_AudioBoostCtrl; - BOOL m_fDownSampleTo441; - CMPCThemeRadioOrCheck m_fDownSampleTo441Ctrl; - BOOL m_fCustomChannelMapping; - CMPCThemeRadioOrCheck m_fCustomChannelMappingCtrl; - CMPCThemeEdit m_nChannelsCtrl; - int m_nChannels; - CMPCThemeSpinButtonCtrl m_nChannelsSpinCtrl; - CMPCThemePlayerListCtrl m_list; - int m_tAudioTimeShift; - CMPCThemeRadioOrCheck m_fAudioTimeShiftCtrl; - CMPCThemeIntEdit m_tAudioTimeShiftCtrl; - CMPCThemeSpinButtonCtrl m_tAudioTimeShiftSpin; - BOOL m_fAudioTimeShift; - - // tooltip for slidercontrol - CToolTipCtrl m_tooltip; -public: - CPPageAudioSwitcher(IFilterGraph* pFG); - virtual ~CPPageAudioSwitcher(); - - // Dialog Data - enum { IDD = IDD_PPAGEAUDIOSWITCHER }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual BOOL OnApply(); - - DECLARE_MESSAGE_MAP() - - afx_msg void OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); - afx_msg void OnEnChangeEdit1(); - afx_msg void OnUpdateAudioSwitcher(CCmdUI* pCmdUI); - afx_msg void OnUpdateNormalize(CCmdUI* pCmdUI); - afx_msg void OnUpdateTimeShift(CCmdUI* pCmdUI); - afx_msg void OnUpdateChannelMapping(CCmdUI* pCmdUI); - - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); - virtual void OnCancel(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "CMPCThemePPageBase.h" +#include "FloatEdit.h" +#include "../filters/switcher/AudioSwitcher/AudioSwitcher.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeSliderCtrl.h" +#include "CMPCThemeEdit.h" +#include "CMPCThemeSpinButtonCtrl.h" +#include "CMPCThemePlayerListCtrl.h" + + + + +// CPPageAudioSwitcher dialog + +class CPPageAudioSwitcher : public CMPCThemePPageBase +{ + DECLARE_DYNAMIC(CPPageAudioSwitcher) + +private: + DWORD m_pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]; + DWORD m_dwChannelMask; + + BOOL m_fEnableAudioSwitcher; + BOOL m_fAudioNormalize; + UINT m_nAudioMaxNormFactor; + CMPCThemeSpinButtonCtrl m_AudioMaxNormFactorSpin; + BOOL m_fAudioNormalizeRecover; + int m_AudioBoostPos; + CMPCThemeSliderCtrl m_AudioBoostCtrl; + BOOL m_fDownSampleTo441; + CMPCThemeRadioOrCheck m_fDownSampleTo441Ctrl; + BOOL m_fCustomChannelMapping; + CMPCThemeRadioOrCheck m_fCustomChannelMappingCtrl; + CMPCThemeEdit m_nChannelsCtrl; + int m_nChannels; + CMPCThemeSpinButtonCtrl m_nChannelsSpinCtrl; + CMPCThemePlayerListCtrl m_list; + int m_tAudioTimeShift; + CMPCThemeRadioOrCheck m_fAudioTimeShiftCtrl; + CMPCThemeIntEdit m_tAudioTimeShiftCtrl; + CMPCThemeSpinButtonCtrl m_tAudioTimeShiftSpin; + BOOL m_fAudioTimeShift; + + // tooltip for slidercontrol + CToolTipCtrl m_tooltip; +public: + CPPageAudioSwitcher(IFilterGraph* pFG); + virtual ~CPPageAudioSwitcher(); + + // Dialog Data + enum { IDD = IDD_PPAGEAUDIOSWITCHER }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual BOOL OnApply(); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); + afx_msg void OnEnChangeEdit1(); + afx_msg void OnUpdateAudioSwitcher(CCmdUI* pCmdUI); + afx_msg void OnUpdateNormalize(CCmdUI* pCmdUI); + afx_msg void OnUpdateTimeShift(CCmdUI* pCmdUI); + afx_msg void OnUpdateChannelMapping(CCmdUI* pCmdUI); + + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); + virtual void OnCancel(); +}; diff --git a/src/mpc-hc/PPageBase.cpp b/src/mpc-hc/PPageBase.cpp index b7e316e15f0..777278fee36 100644 --- a/src/mpc-hc/PPageBase.cpp +++ b/src/mpc-hc/PPageBase.cpp @@ -1,191 +1,191 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "MainFrm.h" -#include "mplayerc.h" -#include "PPageBase.h" -#include "SettingsDefines.h" -#include "ComPropertySheet.h" - - -// CPPageBase dialog - -IMPLEMENT_DYNAMIC(CPPageBase, CCmdUIPropertyPage) -CPPageBase::CPPageBase(UINT nIDTemplate, UINT nIDCaption) - : CCmdUIPropertyPage(nIDTemplate, nIDCaption) -{ -} - -CPPageBase::~CPPageBase() -{ -} - -void CPPageBase::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); -} - -bool CPPageBase::FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT) -{ - bool bNeedTooltip = false; - - CDC* pDC = comboBox.GetDC(); - CFont* pFont = comboBox.GetFont(); - CFont* pOldFont = pDC->SelectObject(pFont); - - TEXTMETRIC tm; - pDC->GetTextMetrics(&tm); - - CRect comboBoxRect; - comboBox.GetWindowRect(comboBoxRect); - comboBoxRect.right -= GetSystemMetrics(SM_CXVSCROLL) + 2 * GetSystemMetrics(SM_CXEDGE); - - int i = comboBox.GetCurSel(); - CString str; - comboBox.GetLBText(i, str); - CSize textSize; - textSize = pDC->GetTextExtent(str); - pDC->SelectObject(pOldFont); - comboBox.ReleaseDC(pDC); - textSize.cx += tm.tmAveCharWidth; - - if (textSize.cx > comboBoxRect.Width()) { - bNeedTooltip = true; - if (str.GetLength() > _countof(pTTT->szText) - 1) { - str.Truncate(_countof(pTTT->szText) - 1); - } - _tcscpy_s(pTTT->szText, str); - pTTT->hinst = nullptr; - } - - return bNeedTooltip; -} - -void CPPageBase::CreateToolTip() -{ - m_wndToolTip.Create(this, TTS_NOPREFIX); - m_wndToolTip.Activate(TRUE); - m_wndToolTip.SetMaxTipWidth(300); - m_wndToolTip.SetDelayTime(TTDT_AUTOPOP, 10000); - for (CWnd* pChild = GetWindow(GW_CHILD); pChild; pChild = pChild->GetWindow(GW_HWNDNEXT)) { - CString strToolTip; - if (strToolTip.LoadString(pChild->GetDlgCtrlID())) { - m_wndToolTip.AddTool(pChild, strToolTip); - } - } -} - -void CPPageBase::SetButtonIcon(UINT nIDButton, IconDef iconDef) -{ - if (!m_buttonIcons.count(iconDef)) { - CImage img; - if (iconDef.svgTargetWidth) { - SVGImage::LoadIconDef(iconDef, img); - } else { - img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); - } - CImageList& imageList = m_buttonIcons[iconDef]; - imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 1, 0); - imageList.Add(CBitmap::FromHandle(img), nullptr); - } - - BUTTON_IMAGELIST buttonImageList; - buttonImageList.himl = m_buttonIcons[iconDef]; - buttonImageList.margin = { 0, 0, 0, 0 }; - buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; - static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); -} - -BOOL CPPageBase::PreTranslateMessage(MSG* pMsg) -{ - if (IsWindow(m_wndToolTip)) - if (pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST) { - MSG msg; - memcpy(&msg, pMsg, sizeof(MSG)); - for (HWND hWndParent = ::GetParent(msg.hwnd); - hWndParent && hWndParent != m_hWnd; - hWndParent = ::GetParent(hWndParent)) { - msg.hwnd = hWndParent; - } - - if (msg.hwnd) { - m_wndToolTip.RelayEvent(&msg); - } - } - - return __super::PreTranslateMessage(pMsg); -} - -BEGIN_MESSAGE_MAP(CPPageBase, CCmdUIPropertyPage) - ON_WM_DESTROY() -END_MESSAGE_MAP() - - -// CPPageBase message handlers - -BOOL CPPageBase::OnSetActive() -{ - ASSERT(IS_INTRESOURCE(m_pPSP->pszTemplate)); - AfxGetAppSettings().nLastUsedPage = (WORD)(ULONG_PTR)m_pPSP->pszTemplate; - SetRedraw(false); //adipose: disable redraw due to CPropertyPage::OnSetActive forcing ddx, which causes "optimized" redraw of comboboxes without consulting subclass paint method - BOOL ret = __super::OnSetActive(); - SetRedraw(true); //adipose: reenable redraw. no regressions observed by enabling after ddx - return ret; -} - -BOOL CPPageBase::OnApply() -{ - // There is no main frame when the option dialog is displayed stand-alone - if (CMainFrame* pMainFrame = AfxGetMainFrame()) { - pMainFrame->PostMessage(WM_SAVESETTINGS); - } - return __super::OnApply(); -} - -void CPPageBase::OnDestroy() -{ - __super::OnDestroy(); - m_wndToolTip.DestroyWindow(); -} - -void CPPageBase::ShowPPage(CUnknown* (WINAPI* CreateInstance)(LPUNKNOWN lpunk, HRESULT* phr)) { - if (!CreateInstance) { - return; - } - - HRESULT hr; - CUnknown* pObj = CreateInstance(nullptr, &hr); - - if (!pObj) { - return; - } - - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pObj; - - if (SUCCEEDED(hr)) { - if (CComQIPtr pSPP = pUnk) { - CComPropertySheet ps(ResStr(IDS_PROPSHEET_PROPERTIES), this); - ps.AddPages(pSPP); - ps.DoModal(); - } - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "MainFrm.h" +#include "mplayerc.h" +#include "PPageBase.h" +#include "SettingsDefines.h" +#include "ComPropertySheet.h" + + +// CPPageBase dialog + +IMPLEMENT_DYNAMIC(CPPageBase, CCmdUIPropertyPage) +CPPageBase::CPPageBase(UINT nIDTemplate, UINT nIDCaption) + : CCmdUIPropertyPage(nIDTemplate, nIDCaption) +{ +} + +CPPageBase::~CPPageBase() +{ +} + +void CPPageBase::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); +} + +bool CPPageBase::FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT) +{ + bool bNeedTooltip = false; + + CDC* pDC = comboBox.GetDC(); + CFont* pFont = comboBox.GetFont(); + CFont* pOldFont = pDC->SelectObject(pFont); + + TEXTMETRIC tm; + pDC->GetTextMetrics(&tm); + + CRect comboBoxRect; + comboBox.GetWindowRect(comboBoxRect); + comboBoxRect.right -= GetSystemMetrics(SM_CXVSCROLL) + 2 * GetSystemMetrics(SM_CXEDGE); + + int i = comboBox.GetCurSel(); + CString str; + comboBox.GetLBText(i, str); + CSize textSize; + textSize = pDC->GetTextExtent(str); + pDC->SelectObject(pOldFont); + comboBox.ReleaseDC(pDC); + textSize.cx += tm.tmAveCharWidth; + + if (textSize.cx > comboBoxRect.Width()) { + bNeedTooltip = true; + if (str.GetLength() > _countof(pTTT->szText) - 1) { + str.Truncate(_countof(pTTT->szText) - 1); + } + _tcscpy_s(pTTT->szText, str); + pTTT->hinst = nullptr; + } + + return bNeedTooltip; +} + +void CPPageBase::CreateToolTip() +{ + m_wndToolTip.Create(this, TTS_NOPREFIX); + m_wndToolTip.Activate(TRUE); + m_wndToolTip.SetMaxTipWidth(300); + m_wndToolTip.SetDelayTime(TTDT_AUTOPOP, 10000); + for (CWnd* pChild = GetWindow(GW_CHILD); pChild; pChild = pChild->GetWindow(GW_HWNDNEXT)) { + CString strToolTip; + if (strToolTip.LoadString(pChild->GetDlgCtrlID())) { + m_wndToolTip.AddTool(pChild, strToolTip); + } + } +} + +void CPPageBase::SetButtonIcon(UINT nIDButton, IconDef iconDef) +{ + if (!m_buttonIcons.count(iconDef)) { + CImage img; + if (iconDef.svgTargetWidth) { + SVGImage::LoadIconDef(iconDef, img); + } else { + img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); + } + CImageList& imageList = m_buttonIcons[iconDef]; + imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 1, 0); + imageList.Add(CBitmap::FromHandle(img), nullptr); + } + + BUTTON_IMAGELIST buttonImageList; + buttonImageList.himl = m_buttonIcons[iconDef]; + buttonImageList.margin = { 0, 0, 0, 0 }; + buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; + static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); +} + +BOOL CPPageBase::PreTranslateMessage(MSG* pMsg) +{ + if (IsWindow(m_wndToolTip)) + if (pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST) { + MSG msg; + memcpy(&msg, pMsg, sizeof(MSG)); + for (HWND hWndParent = ::GetParent(msg.hwnd); + hWndParent && hWndParent != m_hWnd; + hWndParent = ::GetParent(hWndParent)) { + msg.hwnd = hWndParent; + } + + if (msg.hwnd) { + m_wndToolTip.RelayEvent(&msg); + } + } + + return __super::PreTranslateMessage(pMsg); +} + +BEGIN_MESSAGE_MAP(CPPageBase, CCmdUIPropertyPage) + ON_WM_DESTROY() +END_MESSAGE_MAP() + + +// CPPageBase message handlers + +BOOL CPPageBase::OnSetActive() +{ + ASSERT(IS_INTRESOURCE(m_pPSP->pszTemplate)); + AfxGetAppSettings().nLastUsedPage = (WORD)(ULONG_PTR)m_pPSP->pszTemplate; + SetRedraw(false); //adipose: disable redraw due to CPropertyPage::OnSetActive forcing ddx, which causes "optimized" redraw of comboboxes without consulting subclass paint method + BOOL ret = __super::OnSetActive(); + SetRedraw(true); //adipose: reenable redraw. no regressions observed by enabling after ddx + return ret; +} + +BOOL CPPageBase::OnApply() +{ + // There is no main frame when the option dialog is displayed stand-alone + if (CMainFrame* pMainFrame = AfxGetMainFrame()) { + pMainFrame->PostMessage(WM_SAVESETTINGS); + } + return __super::OnApply(); +} + +void CPPageBase::OnDestroy() +{ + __super::OnDestroy(); + m_wndToolTip.DestroyWindow(); +} + +void CPPageBase::ShowPPage(CUnknown* (WINAPI* CreateInstance)(LPUNKNOWN lpunk, HRESULT* phr)) { + if (!CreateInstance) { + return; + } + + HRESULT hr; + CUnknown* pObj = CreateInstance(nullptr, &hr); + + if (!pObj) { + return; + } + + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pObj; + + if (SUCCEEDED(hr)) { + if (CComQIPtr pSPP = pUnk) { + CComPropertySheet ps(ResStr(IDS_PROPSHEET_PROPERTIES), this); + ps.AddPages(pSPP); + ps.DoModal(); + } + } +} diff --git a/src/mpc-hc/PPageBase.h b/src/mpc-hc/PPageBase.h index 89f0450efa2..9471ed5f04b 100644 --- a/src/mpc-hc/PPageBase.h +++ b/src/mpc-hc/PPageBase.h @@ -1,61 +1,61 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "ResizableLib/ResizableDialog.h" -#include "CMPCThemeToolTipCtrl.h" -#include "SVGImage.h" - -// CPPageBase dialog -using namespace SVGImage; -class CPPageBase : public CCmdUIPropertyPage -{ - DECLARE_DYNAMIC(CPPageBase) - -protected: - CMPCThemeToolTipCtrl m_wndToolTip; - std::map m_buttonIcons; - - static bool FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT); - - void CreateToolTip(); - - void SetButtonIcon(UINT nIDButton, IconDef iconDef); - -public: - CPPageBase(UINT nIDTemplate, UINT nIDCaption = 0); - virtual ~CPPageBase(); - - // Dialog Data - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL PreTranslateMessage(MSG* pMsg); - virtual BOOL OnSetActive(); - virtual BOOL OnApply(); - void ShowPPage(CUnknown* (__stdcall* CreateInstance)(LPUNKNOWN lpunk, HRESULT* phr)); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnDestroy(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "ResizableLib/ResizableDialog.h" +#include "CMPCThemeToolTipCtrl.h" +#include "SVGImage.h" + +// CPPageBase dialog +using namespace SVGImage; +class CPPageBase : public CCmdUIPropertyPage +{ + DECLARE_DYNAMIC(CPPageBase) + +protected: + CMPCThemeToolTipCtrl m_wndToolTip; + std::map m_buttonIcons; + + static bool FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT); + + void CreateToolTip(); + + void SetButtonIcon(UINT nIDButton, IconDef iconDef); + +public: + CPPageBase(UINT nIDTemplate, UINT nIDCaption = 0); + virtual ~CPPageBase(); + + // Dialog Data + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL OnSetActive(); + virtual BOOL OnApply(); + void ShowPPage(CUnknown* (__stdcall* CreateInstance)(LPUNKNOWN lpunk, HRESULT* phr)); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnDestroy(); +}; diff --git a/src/mpc-hc/PPageCapture.cpp b/src/mpc-hc/PPageCapture.cpp index 584710b6726..e6a01dd32e8 100644 --- a/src/mpc-hc/PPageCapture.cpp +++ b/src/mpc-hc/PPageCapture.cpp @@ -1,730 +1,730 @@ -/* - * (C) 2009-2015, 2017 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 . - * - */ - -// PPageCapture.cpp : implementation file -// - -#include "stdafx.h" -#include -#include -#include -#include -#include - -#include "mplayerc.h" -#include "PPageCapture.h" -#include "DSUtil.h" - - -struct cc_t { - long code; - AnalogVideoStandard standard; - const TCHAR* str; -} static constexpr s_countrycodes[] = { - {1, AnalogVideo_NTSC_M, _T("USA")}, - /* - {1, AnalogVideo_NTSC_M, _T("Anguilla")}, - {1, AnalogVideo_NTSC_M, _T("Antigua")}, - {1, AnalogVideo_NTSC_M, _T("Bahamas")}, - {1, AnalogVideo_NTSC_M, _T("Barbados")}, - {1, AnalogVideo_NTSC_M, _T("Bermuda")}, - {1, AnalogVideo_NTSC_M, _T("British Virgin Islands")}, - {1, AnalogVideo_NTSC_M, _T("Canada")}, - {1, AnalogVideo_NTSC_M, _T("Cayman Islands")}, - {1, AnalogVideo_NTSC_M, _T("Dominica")}, - {1, AnalogVideo_NTSC_M, _T("Dominican Republic")}, - {1, AnalogVideo_NTSC_M, _T("Grenada")}, - {1, AnalogVideo_NTSC_M, _T("Jamaica")}, - {1, AnalogVideo_NTSC_M, _T("Montserrat")}, - {1, AnalogVideo_NTSC_M, _T("Nevis")}, - {1, AnalogVideo_NTSC_M, _T("St. Kitts")}, - {1, AnalogVideo_NTSC_M, _T("St. Vincent and the Grenadines")}, - {1, AnalogVideo_NTSC_M, _T("Trinidad and Tobago")}, - {1, AnalogVideo_NTSC_M, _T("Turks and Caicos Islands")}, - {1, AnalogVideo_NTSC_M, _T("Barbuda")}, - {1, AnalogVideo_NTSC_M, _T("Puerto Rico")}, - {1, AnalogVideo_NTSC_M, _T("Saint Lucia")}, - {1, AnalogVideo_NTSC_M, _T("United States Virgin Islands")}, - */ - {2, AnalogVideo_NTSC_M, _T("Canada")}, - {7, AnalogVideo_SECAM_D, _T("Russia")}, - /* - {7, AnalogVideo_SECAM_D, _T("Kazakhstan")}, - {7, AnalogVideo_SECAM_D, _T("Kyrgyzstan")}, - {7, AnalogVideo_SECAM_D, _T("Tajikistan")}, - {7, AnalogVideo_SECAM_D, _T("Turkmenistan")}, - {7, AnalogVideo_SECAM_D, _T("Uzbekistan")}, - */ - {20, AnalogVideo_SECAM_B, _T("Egypt")}, - {27, AnalogVideo_PAL_I, _T("South Africa")}, - {30, AnalogVideo_SECAM_B, _T("Greece")}, - {31, AnalogVideo_PAL_B, _T("Netherlands")}, - {32, AnalogVideo_PAL_B, _T("Belgium")}, - {33, AnalogVideo_SECAM_L, _T("France")}, - {34, AnalogVideo_PAL_B, _T("Spain")}, - {36, AnalogVideo_SECAM_D, _T("Hungary")}, - {39, AnalogVideo_PAL_B, _T("Italy")}, - // {39, AnalogVideo_PAL_B, _T("Vatican City")}, - {40, AnalogVideo_PAL_D, _T("Romania")}, - {41, AnalogVideo_PAL_B, _T("Switzerland")}, - // {41, AnalogVideo_PAL_B, _T("Liechtenstein")}, - {43, AnalogVideo_PAL_B, _T("Austria")}, - {44, AnalogVideo_PAL_I, _T("United Kingdom")}, - {45, AnalogVideo_PAL_B, _T("Denmark")}, - {46, AnalogVideo_PAL_B, _T("Sweden")}, - {47, AnalogVideo_PAL_B, _T("Norway")}, - {48, AnalogVideo_PAL_B, _T("Poland")}, - {49, AnalogVideo_PAL_B, _T("Germany")}, - {51, AnalogVideo_NTSC_M, _T("Peru")}, - {52, AnalogVideo_NTSC_M, _T("Mexico")}, - {53, AnalogVideo_NTSC_M, _T("Cuba")}, - // {53, AnalogVideo_NTSC_M, _T("Guantanamo Bay")}, - {54, AnalogVideo_PAL_N, _T("Argentina")}, - {55, AnalogVideo_PAL_M, _T("Brazil")}, - {56, AnalogVideo_NTSC_M, _T("Chile")}, - {57, AnalogVideo_NTSC_M, _T("Colombia")}, - {58, AnalogVideo_NTSC_M, _T("Bolivarian Republic of Venezuela")}, - {60, AnalogVideo_PAL_B, _T("Malaysia")}, - {61, AnalogVideo_PAL_B, _T("Australia")}, - // {61, AnalogVideo_NTSC_M, _T("Cocos-Keeling Islands")}, - {62, AnalogVideo_PAL_B, _T("Indonesia")}, - {63, AnalogVideo_NTSC_M, _T("Philippines")}, - {64, AnalogVideo_PAL_B, _T("New Zealand")}, - {65, AnalogVideo_PAL_B, _T("Singapore")}, - {66, AnalogVideo_PAL_B, _T("Thailand")}, - {81, AnalogVideo_NTSC_M_J, _T("Japan")}, - {82, AnalogVideo_NTSC_M, _T("Korea (South)")}, - {84, AnalogVideo_NTSC_M, _T("Vietnam")}, - {86, AnalogVideo_PAL_D, _T("China")}, - {90, AnalogVideo_PAL_B, _T("Turkey")}, - {91, AnalogVideo_PAL_B, _T("India")}, - {92, AnalogVideo_PAL_B, _T("Pakistan")}, - {93, AnalogVideo_PAL_B, _T("Afghanistan")}, - {94, AnalogVideo_PAL_B, _T("Sri Lanka")}, - {95, AnalogVideo_NTSC_M, _T("Myanmar")}, - {98, AnalogVideo_SECAM_B, _T("Iran")}, - {212, AnalogVideo_SECAM_B, _T("Morocco")}, - {213, AnalogVideo_PAL_B, _T("Algeria")}, - {216, AnalogVideo_SECAM_B, _T("Tunisia")}, - {218, AnalogVideo_SECAM_B, _T("Libya")}, - {220, AnalogVideo_SECAM_K, _T("Gambia")}, - {221, AnalogVideo_SECAM_K, _T("Senegal Republic")}, - {222, AnalogVideo_SECAM_B, _T("Mauritania")}, - {223, AnalogVideo_SECAM_K, _T("Mali")}, - {224, AnalogVideo_SECAM_K, _T("Guinea")}, - {225, AnalogVideo_SECAM_K, _T("Cote D'Ivoire")}, - {226, AnalogVideo_SECAM_K, _T("Burkina Faso")}, - {227, AnalogVideo_SECAM_K, _T("Niger")}, - {228, AnalogVideo_SECAM_K, _T("Togo")}, - {229, AnalogVideo_SECAM_K, _T("Benin")}, - {230, AnalogVideo_SECAM_B, _T("Mauritius")}, - {231, AnalogVideo_PAL_B, _T("Liberia")}, - {232, AnalogVideo_PAL_B, _T("Sierra Leone")}, - {233, AnalogVideo_PAL_B, _T("Ghana")}, - {234, AnalogVideo_PAL_B, _T("Nigeria")}, - {235, AnalogVideo_PAL_B, _T("Chad")}, - {236, AnalogVideo_PAL_B, _T("Central African Republic")}, - {237, AnalogVideo_PAL_B, _T("Cameroon")}, - {238, AnalogVideo_NTSC_M, _T("Cape Verde Islands")}, - {239, AnalogVideo_PAL_B, _T("Sao Tome and Principe")}, - {240, AnalogVideo_SECAM_B, _T("Equatorial Guinea")}, - {241, AnalogVideo_SECAM_K, _T("Gabon")}, - {242, AnalogVideo_SECAM_D, _T("Congo")}, - {243, AnalogVideo_SECAM_K, _T("Congo(DRC)")}, - {244, AnalogVideo_PAL_I, _T("Angola")}, - {245, AnalogVideo_NTSC_M, _T("Guinea-Bissau")}, - {246, AnalogVideo_NTSC_M, _T("Diego Garcia")}, - {247, AnalogVideo_NTSC_M, _T("Ascension Island")}, - {248, AnalogVideo_PAL_B, _T("Seychelle Islands")}, - {249, AnalogVideo_PAL_B, _T("Sudan")}, - {250, AnalogVideo_PAL_B, _T("Rwanda")}, - {251, AnalogVideo_PAL_B, _T("Ethiopia")}, - {252, AnalogVideo_PAL_B, _T("Somalia")}, - {253, AnalogVideo_SECAM_K, _T("Djibouti")}, - {254, AnalogVideo_PAL_B, _T("Kenya")}, - {255, AnalogVideo_PAL_B, _T("Tanzania")}, - {256, AnalogVideo_PAL_B, _T("Uganda")}, - {257, AnalogVideo_SECAM_K, _T("Burundi")}, - {258, AnalogVideo_PAL_B, _T("Mozambique")}, - {260, AnalogVideo_PAL_B, _T("Zambia")}, - {261, AnalogVideo_SECAM_K, _T("Madagascar")}, - {262, AnalogVideo_SECAM_K, _T("Reunion Island")}, - {263, AnalogVideo_PAL_B, _T("Zimbabwe")}, - {264, AnalogVideo_PAL_I, _T("Namibia")}, - {265, AnalogVideo_NTSC_M, _T("Malawi")}, - {266, AnalogVideo_PAL_I, _T("Lesotho")}, - {267, AnalogVideo_SECAM_K, _T("Botswana")}, - {268, AnalogVideo_PAL_B, _T("Swaziland")}, - {269, AnalogVideo_SECAM_K, _T("Mayotte Island")}, - // {269, AnalogVideo_NTSC_M, _T("Comoros")}, - {290, AnalogVideo_NTSC_M, _T("St. Helena")}, - {291, AnalogVideo_NTSC_M, _T("Eritrea")}, - {297, AnalogVideo_NTSC_M, _T("Aruba")}, - {298, AnalogVideo_PAL_B, _T("Faroe Islands")}, - {299, AnalogVideo_NTSC_M, _T("Greenland")}, - {350, AnalogVideo_PAL_B, _T("Gibraltar")}, - {351, AnalogVideo_PAL_B, _T("Portugal")}, - {352, AnalogVideo_PAL_B, _T("Luxembourg")}, - {353, AnalogVideo_PAL_I, _T("Ireland")}, - {354, AnalogVideo_PAL_B, _T("Iceland")}, - {355, AnalogVideo_PAL_B, _T("Albania")}, - {356, AnalogVideo_PAL_B, _T("Malta")}, - {357, AnalogVideo_PAL_B, _T("Cyprus")}, - {358, AnalogVideo_PAL_B, _T("Finland")}, - {359, AnalogVideo_SECAM_D, _T("Bulgaria")}, - {370, AnalogVideo_PAL_B, _T("Lithuania")}, - {371, AnalogVideo_SECAM_D, _T("Latvia")}, - {372, AnalogVideo_PAL_B, _T("Estonia")}, - {373, AnalogVideo_SECAM_D, _T("Moldova")}, - {374, AnalogVideo_SECAM_D, _T("Armenia")}, - {375, AnalogVideo_SECAM_D, _T("Belarus")}, - {376, AnalogVideo_NTSC_M, _T("Andorra")}, - {377, AnalogVideo_SECAM_G, _T("Monaco")}, - {378, AnalogVideo_PAL_B, _T("San Marino")}, - {380, AnalogVideo_SECAM_D, _T("Ukraine")}, - {381, AnalogVideo_PAL_B, _T("Serbia")}, - {385, AnalogVideo_PAL_B, _T("Croatia")}, - {386, AnalogVideo_PAL_B, _T("Slovenia")}, - {387, AnalogVideo_PAL_B, _T("Bosnia and Herzegovina")}, - {389, AnalogVideo_PAL_B, _T("F.Y.R.O.M. (Former Yugoslav Republic of Macedonia)")}, - {420, AnalogVideo_PAL_D, _T("Czech Republic")}, - {421, AnalogVideo_PAL_B, _T("Slovak Republic")}, - {500, AnalogVideo_PAL_I, _T("Falkland Islands (Islas Malvinas)")}, - {501, AnalogVideo_NTSC_M, _T("Belize")}, - {502, AnalogVideo_NTSC_M, _T("Guatemala")}, - {503, AnalogVideo_NTSC_M, _T("El Salvador")}, - {504, AnalogVideo_NTSC_M, _T("Honduras")}, - {505, AnalogVideo_NTSC_M, _T("Nicaragua")}, - {506, AnalogVideo_NTSC_M, _T("Costa Rica")}, - {507, AnalogVideo_NTSC_M, _T("Panama")}, - {508, AnalogVideo_SECAM_K, _T("St. Pierre and Miquelon")}, - {509, AnalogVideo_NTSC_M, _T("Haiti")}, - {590, AnalogVideo_SECAM_K, _T("Guadeloupe")}, - // {590, AnalogVideo_NTSC_M, _T("French Antilles")}, - {591, AnalogVideo_PAL_N, _T("Bolivia")}, - {592, AnalogVideo_SECAM_K, _T("Guyana")}, - {593, AnalogVideo_NTSC_M, _T("Ecuador")}, - {594, AnalogVideo_SECAM_K, _T("French Guiana")}, - {595, AnalogVideo_PAL_N, _T("Paraguay")}, - {596, AnalogVideo_SECAM_K, _T("Martinique")}, - {597, AnalogVideo_NTSC_M, _T("Suriname")}, - {598, AnalogVideo_PAL_N, _T("Uruguay")}, - {599, AnalogVideo_NTSC_M, _T("Netherlands Antilles")}, - {670, AnalogVideo_NTSC_M, _T("Saipan Island")}, - // {670, AnalogVideo_NTSC_M, _T("Rota Island")}, - // {670, AnalogVideo_NTSC_M, _T("Tinian Island")}, - {671, AnalogVideo_NTSC_M, _T("Guam")}, - // {672, AnalogVideo_NTSC_M, _T("Christmas Island")}, - // {672, AnalogVideo_NTSC_M, _T("Australian Antarctic Territory")}, - // {672, AnalogVideo_PAL_B, _T("Norfolk Island")}, - {673, AnalogVideo_PAL_B, _T("Brunei")}, - {674, AnalogVideo_NTSC_M, _T("Nauru")}, - {675, AnalogVideo_PAL_B, _T("Papua New Guinea")}, - {676, AnalogVideo_NTSC_M, _T("Tonga")}, - {677, AnalogVideo_NTSC_M, _T("Solomon Islands")}, - {678, AnalogVideo_NTSC_M, _T("Vanuatu")}, - {679, AnalogVideo_NTSC_M, _T("Fiji Islands")}, - {680, AnalogVideo_NTSC_M, _T("Palau")}, - {681, AnalogVideo_SECAM_K, _T("Wallis and Futuna Islands")}, - {682, AnalogVideo_PAL_B, _T("Cook Islands")}, - {683, AnalogVideo_NTSC_M, _T("Niue")}, - {684, AnalogVideo_NTSC_M, _T("Territory of American Samoa")}, - {685, AnalogVideo_PAL_B, _T("Samoa")}, - {686, AnalogVideo_PAL_B, _T("Kiribati Republic")}, - {687, AnalogVideo_SECAM_K, _T("New Caledonia")}, - {688, AnalogVideo_NTSC_M, _T("Tuvalu")}, - {689, AnalogVideo_SECAM_K, _T("French Polynesia")}, - {690, AnalogVideo_NTSC_M, _T("Tokelau")}, - {691, AnalogVideo_NTSC_M, _T("Micronesia")}, - {692, AnalogVideo_NTSC_M, _T("Marshall Islands")}, - {850, AnalogVideo_SECAM_D, _T("Korea (North)")}, - {852, AnalogVideo_PAL_I, _T("Hong Kong SAR")}, - {853, AnalogVideo_PAL_I, _T("Macao SAR")}, - {855, AnalogVideo_PAL_B, _T("Cambodia")}, - {856, AnalogVideo_PAL_B, _T("Laos")}, - {871, AnalogVideo_NTSC_M, _T("INMARSAT (Atlantic-East)")}, - {872, AnalogVideo_NTSC_M, _T("INMARSAT (Pacific)")}, - {873, AnalogVideo_NTSC_M, _T("INMARSAT (Indian)")}, - {874, AnalogVideo_NTSC_M, _T("INMARSAT (Atlantic-West)")}, - {880, AnalogVideo_PAL_B, _T("Bangladesh")}, - {886, AnalogVideo_NTSC_M, _T("Taiwan")}, - {960, AnalogVideo_PAL_B, _T("Maldives")}, - {961, AnalogVideo_SECAM_B, _T("Lebanon")}, - {962, AnalogVideo_PAL_B, _T("Jordan")}, - {963, AnalogVideo_SECAM_B, _T("Syria")}, - {964, AnalogVideo_SECAM_B, _T("Iraq")}, - {965, AnalogVideo_PAL_B, _T("Kuwait")}, - {966, AnalogVideo_SECAM_B, _T("Saudi Arabia")}, - {967, AnalogVideo_PAL_B, _T("Yemen")}, - {968, AnalogVideo_PAL_B, _T("Oman")}, - {971, AnalogVideo_PAL_B, _T("United Arab Emirates")}, - {972, AnalogVideo_PAL_B, _T("Israel")}, - {973, AnalogVideo_PAL_B, _T("Bahrain")}, - {974, AnalogVideo_PAL_B, _T("Qatar")}, - {975, AnalogVideo_NTSC_M, _T("Bhutan")}, - {976, AnalogVideo_SECAM_D, _T("Mongolia")}, - {977, AnalogVideo_PAL_B, _T("Nepal")}, - {994, AnalogVideo_SECAM_D, _T("Azerbaijan")}, - {995, AnalogVideo_SECAM_D, _T("Georgia")} -}; - - -// CPPageCapture dialog - -IMPLEMENT_DYNAMIC(CPPageCapture, CMPCThemePPageBase) - -CPPageCapture::CPPageCapture() - : CMPCThemePPageBase(CPPageCapture::IDD, CPPageCapture::IDD) - , m_iDefaultDevice(0) -{ -} - -CPPageCapture::~CPPageCapture() -{ -} - -void CPPageCapture::DoDataExchange(CDataExchange* pDX) -{ - CMPCThemePPageBase::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO1, m_cbAnalogVideo); - DDX_Control(pDX, IDC_COMBO2, m_cbAnalogAudio); - DDX_Control(pDX, IDC_COMBO9, m_cbAnalogCountry); - DDX_Control(pDX, IDC_COMBO4, m_cbDigitalNetworkProvider); - DDX_Control(pDX, IDC_COMBO5, m_cbDigitalTuner); - DDX_Control(pDX, IDC_COMBO3, m_cbDigitalReceiver); - DDX_Radio(pDX, IDC_RADIO1, m_iDefaultDevice); - DDX_Control(pDX, IDC_COMBO6, m_cbRebuildFilterGraph); - DDX_Control(pDX, IDC_COMBO7, m_cbStopFilterGraph); -} - -BEGIN_MESSAGE_MAP(CPPageCapture, CMPCThemePPageBase) - ON_UPDATE_COMMAND_UI(IDC_COMBO1, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_COMBO2, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_COMBO9, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_STATIC2, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_STATIC3, OnUpdateAnalog) - //ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_COMBO5, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_STATIC4, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_STATIC5, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_COMBO3, OnUpdateDigitalReciver) - ON_UPDATE_COMMAND_UI(IDC_STATIC6, OnUpdateDigitalReciver) - ON_UPDATE_COMMAND_UI(IDC_COMBO6, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_COMBO7, OnUpdateDigitalStopFilterGraph) - ON_UPDATE_COMMAND_UI(IDC_CHECK1, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_PPAGECAPTURE_ST10, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_PPAGECAPTURE_ST11, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_PPAGECAPTURE_ST12, OnUpdateDigitalStopFilterGraph) - ON_UPDATE_COMMAND_UI(IDC_PPAGECAPTURE_DESC1, OnUpdateDigital) - ON_CBN_SELCHANGE(IDC_COMBO6, OnSelChangeRebuildFilterGraph) - ON_CBN_SELCHANGE(IDC_COMBO7, OnSelChangeStopFilterGraph) - ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) -END_MESSAGE_MAP() - -// CPPageCapture message handlers - -BOOL CPPageCapture::OnInitDialog() -{ - __super::OnInitDialog(); - - SetHandCursor(m_hWnd, IDC_COMBO1); - - const CAppSettings& s = AfxGetAppSettings(); - - FindAnalogDevices(); - FindDigitalDevices(); - - if (m_cbAnalogVideo.GetCount() && m_cbDigitalTuner.GetCount()) { - m_iDefaultDevice = s.iDefaultCaptureDevice; - } else if (m_cbAnalogVideo.GetCount()) { - m_iDefaultDevice = 0; - GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE); - } else if (m_cbDigitalTuner.GetCount()) { - m_iDefaultDevice = 1; - GetDlgItem(IDC_RADIO1)->EnableWindow(FALSE); - } else { - m_iDefaultDevice = s.iDefaultCaptureDevice; - GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE); - GetDlgItem(IDC_RADIO1)->EnableWindow(FALSE); - } - - //we don't offer other providers anymore, but in case someone wants to know what is being used, we leave this here, disabled and defaulted - //note this setting is not used anywhere and Network Provider is hard-coded elsewhere in the code - m_cbDigitalNetworkProvider.AddString(_T("Microsoft Network Provider")); - m_cbDigitalNetworkProvider.SetCurSel(0); - GetDlgItem(IDC_COMBO4)->EnableWindow(FALSE); - - m_cbRebuildFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_FG0)); - m_cbRebuildFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_FG1)); - m_cbRebuildFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_FG2)); - m_cbRebuildFilterGraph.SetCurSel(s.nDVBRebuildFilterGraph); - CorrectComboListWidth(m_cbRebuildFilterGraph); - - m_cbStopFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_SFG0)); - m_cbStopFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_SFG1)); - m_cbStopFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_SFG2)); - m_cbStopFilterGraph.SetCurSel(s.nDVBStopFilterGraph); - CorrectComboListWidth(m_cbStopFilterGraph); - - OnSelChangeRebuildFilterGraph(); - OnSelChangeStopFilterGraph(); - - UpdateData(FALSE); - - SaveFoundDevices(); // Save (new) devices to ensure that comboboxes reflect actual settings. - - AdjustDynamicWidgets(); - EnableThemedDialogTooltips(this); - - return TRUE; -} - -BOOL CPPageCapture::OnApply() -{ - UpdateData(); - SaveFoundDevices(); - return __super::OnApply(); -} - -void CPPageCapture::OnUpdateAnalog(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(IsDlgButtonChecked(IDC_RADIO1) && m_cbAnalogVideo.GetCount()); -} - -void CPPageCapture::OnUpdateDigital(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(IsDlgButtonChecked(IDC_RADIO2) && m_cbDigitalTuner.GetCount()); -} - -void CPPageCapture::OnUpdateDigitalReciver(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(IsDlgButtonChecked(IDC_RADIO2) && m_cbDigitalReceiver.GetCount()); -} - -void CPPageCapture::OnUpdateDigitalStopFilterGraph(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(IsDlgButtonChecked(IDC_RADIO2) && m_cbDigitalTuner.GetCount() && - (m_cbRebuildFilterGraph.GetCurSel() != 2)); -} - -void CPPageCapture::OnSelChangeRebuildFilterGraph() -{ - if (m_cbRebuildFilterGraph.GetCurSel() == 0) { - GetDlgItem(IDC_PPAGECAPTURE_DESC1)->SetWindowText(ResStr(IDS_PPAGE_CAPTURE_FGDESC0)); - } else if (m_cbRebuildFilterGraph.GetCurSel() == 1) { - GetDlgItem(IDC_PPAGECAPTURE_DESC1)->SetWindowText(ResStr(IDS_PPAGE_CAPTURE_FGDESC1)); - } else if (m_cbRebuildFilterGraph.GetCurSel() == 2) { - GetDlgItem(IDC_PPAGECAPTURE_DESC1)->SetWindowText(ResStr(IDS_PPAGE_CAPTURE_FGDESC2)); - } else { - GetDlgItem(IDC_PPAGECAPTURE_DESC1)->SetWindowText(_T("")); - } - SetModified(); -} - - -void CPPageCapture::OnSelChangeStopFilterGraph() -{ - SetModified(); -} - -BOOL CPPageCapture::OnToolTipNotify(UINT id, NMHDR* pNMH, LRESULT* pResult) -{ - LPTOOLTIPTEXT pTTT = reinterpret_cast(pNMH); - - UINT_PTR nID = pNMH->idFrom; - if (pTTT->uFlags & TTF_IDISHWND) { - nID = ::GetDlgCtrlID((HWND)nID); - } - - BOOL bRet = FALSE; - - switch (nID) { - case IDC_COMBO1: - bRet = FillComboToolTip(m_cbAnalogVideo, pTTT); - break; - case IDC_COMBO2: - bRet = FillComboToolTip(m_cbAnalogAudio, pTTT); - break; - case IDC_COMBO9: - bRet = FillComboToolTip(m_cbAnalogCountry, pTTT); - break; -/* - case IDC_COMBO4: - bRet = FillComboToolTip(m_cbDigitalNetworkProvider, pTTT); - break; -*/ - case IDC_COMBO5: - bRet = FillComboToolTip(m_cbDigitalTuner, pTTT); - break; - case IDC_COMBO3: - bRet = FillComboToolTip(m_cbDigitalReceiver, pTTT); - break; - case IDC_COMBO6: - bRet = FillComboToolTip(m_cbRebuildFilterGraph, pTTT); - break; - case IDC_COMBO7: - bRet = FillComboToolTip(m_cbStopFilterGraph, pTTT); - break; - } - - if (bRet) { - PlaceThemedDialogTooltip(nID); - } - - return bRet; -} - - -void CPPageCapture::FindAnalogDevices() -{ - const CAppSettings& s = AfxGetAppSettings(); - int iSel = 0; - - // List video devices - BeginEnumSysDev(CLSID_VideoInputDeviceCategory, pMoniker) { - CComPtr pPB; - pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)); - - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - int i = m_cbAnalogVideo.AddString(CString(var.bstrVal)); - CComHeapPtr strName; - if (SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName))) { - m_vidnames.Add(CString(strName)); - if (s.strAnalogVideo == CString(strName)) { - iSel = i; - } - } - } - } - EndEnumSysDev; - - if (m_cbAnalogVideo.GetCount()) { - m_cbAnalogVideo.SetCurSel(iSel); - } else { - return; - } - - // List audio devices - iSel = 0; - { - int i = m_cbAnalogAudio.AddString(_T("

Create(SubtitlesProviders* pOwner) { \ - return std::make_shared

(pOwner); \ - } \ -private: \ - virtual std::string Name() const override { return #P; } \ - virtual std::string DisplayName() const override { return N; } \ - virtual std::string Url() const override { return U; } \ - virtual const std::set& Languages() const override; \ - virtual bool Flags(DWORD dwFlags) const override { return (dwFlags & (F)) == dwFlags; } \ - virtual int Icon() const override { return I; } \ -private: \ - virtual SRESULT Search(const SubtitlesInfo& pFileInfo) override; \ - virtual SRESULT Download(SubtitlesInfo& pSubtitlesInfo) override; -#define DEFINE_SUBTITLESPROVIDER_END \ -}; - -#if 0 -DEFINE_SUBTITLESPROVIDER_BEGIN(OpenSubtitles, "OpenSubtitles.org", "https://api.opensubtitles.org", IDI_OPENSUBTITLES, SPF_LOGIN | SPF_HASH | SPF_UPLOAD) -void Initialize() override; -bool NeedLogin() override; -SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; -SRESULT LogOut() override; -SRESULT Hash(SubtitlesInfo& pFileInfo) override; -SRESULT Upload(const SubtitlesInfo& pSubtitlesInfo) override; -std::unique_ptr xmlrpc; -XmlRpcValue token; -DEFINE_SUBTITLESPROVIDER_END -#endif - -DEFINE_SUBTITLESPROVIDER_BEGIN(OpenSubtitles2, "OpenSubtitles.com", "https://www.opensubtitles.com", IDI_OPENSUBTITLES, SPF_LOGIN | SPF_HASH) -void Initialize() override; -bool NeedLogin() override; -SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; -SRESULT LogOut() override; -SRESULT Hash(SubtitlesInfo& pFileInfo) override; - -struct Response { - DWORD code; - std::string text; -}; - -bool CallAPI(CHttpFile* httpFile, CString& headers, std::string& body, Response& response); -bool CallAPI(CHttpFile* httpFile, CString& headers, Response& response); -bool CallAPIResponse(CHttpFile* httpFile, Response& response); -bool GetOptionalValue(const rapidjson::Value& node, const char* path, std::string& result); -bool GetOptionalValue(const rapidjson::Value& node, const char* path, int& result); -bool GetOptionalValue(const rapidjson::Value& node, const char* path, double& result); - -CString token; -static constexpr TCHAR* APIKEY = _T("s2GJfwwPNA74kkeXudFAdiHIqTDjgrmq"); -DEFINE_SUBTITLESPROVIDER_END - -DEFINE_SUBTITLESPROVIDER_BEGIN(podnapisi, "Podnapisi", "https://www.podnapisi.net", IDI_PODNAPISI, SPF_SEARCH) -SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; -SRESULT Hash(SubtitlesInfo& pFileInfo) override; -DEFINE_SUBTITLESPROVIDER_END - -DEFINE_SUBTITLESPROVIDER_BEGIN(Napisy24, "Napisy24", "https://napisy24.pl/", IDI_N24, SPF_HASH | SPF_SEARCH) -SRESULT Hash(SubtitlesInfo& pFileInfo) override; -DEFINE_SUBTITLESPROVIDER_END - -static const struct { - const char* code; - const char* name; -} podnapisi_languages[] = { - { /* 0*/ "", "" }, { /* 1*/ "sl", "Slovenian" }, { /* 2*/ "en", "English" }, - { /* 3*/ "no", "Norwegian" }, { /* 4*/ "ko", "Korean" }, { /* 5*/ "de", "German" }, - { /* 6*/ "is", "Icelandic" }, { /* 7*/ "cs", "Czech" }, { /* 8*/ "fr", "French" }, - { /* 9*/ "it", "Italian" }, { /*10*/ "bs", "Bosnian" }, { /*11*/ "ja", "Japanese" }, - { /*12*/ "ar", "Arabic" }, { /*13*/ "ro", "Romanian" }, { /*14*/ "es", "Argentino" }, - { /*15*/ "hu", "Hungarian" }, { /*16*/ "el", "Greek" }, { /*17*/ "zh", "Chinese" }, - { /*18*/ "", "" }, { /*19*/ "lt", "Lithuanian" }, { /*20*/ "et", "Estonian" }, - { /*21*/ "lv", "Latvian" }, { /*22*/ "he", "Hebrew" }, { /*23*/ "nl", "Dutch" }, - { /*24*/ "da", "Danish" }, { /*25*/ "sv", "Swedish" }, { /*26*/ "pl", "Polish" }, - { /*27*/ "ru", "Russian" }, { /*28*/ "es", "Spanish" }, { /*29*/ "sq", "Albanian" }, - { /*30*/ "tr", "Turkish" }, { /*31*/ "fi", "Finnish" }, { /*32*/ "pt", "Portuguese" }, - { /*33*/ "bg", "Bulgarian" }, { /*34*/ "", "" }, { /*35*/ "mk", "Macedonian" }, - { /*36*/ "sr", "Serbian" }, { /*37*/ "sk", "Slovak" }, { /*38*/ "hr", "Croatian" }, - { /*39*/ "", "" }, { /*40*/ "zh", "Mandarin" }, { /*41*/ "", "" }, - { /*42*/ "hi", "Hindi" }, { /*43*/ "", "" }, { /*44*/ "th", "Thai" }, - { /*45*/ "", "" }, { /*46*/ "uk", "Ukrainian" }, { /*47*/ "sr", "Serbian (Cyrillic)" }, - { /*48*/ "pb", "Brazilian" }, { /*49*/ "ga", "Irish" }, { /*50*/ "be", "Belarus" }, - { /*51*/ "vi", "Vietnamese" }, { /*52*/ "fa", "Farsi" }, { /*53*/ "ca", "Catalan" }, - { /*54*/ "id", "Indonesian" }, { /*55*/ "ms", "Malay" }, { /*56*/ "si", "Sinhala" }, - { /*57*/ "kl", "Greenlandic" }, { /*58*/ "kk", "Kazakh" }, { /*59*/ "bn", "Bengali" }, -}; +/* + * (C) 2016-2017 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 . + * + */ + +#pragma once + +#include "SubtitlesProviders.h" +#include "VersionInfo.h" +#include "rapidjson/include/rapidjson/document.h" +#include "XmlRpc4Win/TimXmlRpc.h" + +#define DEFINE_SUBTITLESPROVIDER_BEGIN(P, N, U, I, F) \ +class P final : public SubtitlesProvider { \ +public: \ + P(SubtitlesProviders* pOwner) \ + : SubtitlesProvider(pOwner) { \ + Initialize(); \ + } \ + ~P() { Uninitialize(); } \ + P(P const&) = delete; \ + P& operator=(P const&) = delete; \ + static std::shared_ptr

Create(SubtitlesProviders* pOwner) { \ + return std::make_shared

(pOwner); \ + } \ +private: \ + virtual std::string Name() const override { return #P; } \ + virtual std::string DisplayName() const override { return N; } \ + virtual std::string Url() const override { return U; } \ + virtual const std::set& Languages() const override; \ + virtual bool Flags(DWORD dwFlags) const override { return (dwFlags & (F)) == dwFlags; } \ + virtual int Icon() const override { return I; } \ +private: \ + virtual SRESULT Search(const SubtitlesInfo& pFileInfo) override; \ + virtual SRESULT Download(SubtitlesInfo& pSubtitlesInfo) override; +#define DEFINE_SUBTITLESPROVIDER_END \ +}; + +#if 0 +DEFINE_SUBTITLESPROVIDER_BEGIN(OpenSubtitles, "OpenSubtitles.org", "https://api.opensubtitles.org", IDI_OPENSUBTITLES, SPF_LOGIN | SPF_HASH | SPF_UPLOAD) +void Initialize() override; +bool NeedLogin() override; +SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; +SRESULT LogOut() override; +SRESULT Hash(SubtitlesInfo& pFileInfo) override; +SRESULT Upload(const SubtitlesInfo& pSubtitlesInfo) override; +std::unique_ptr xmlrpc; +XmlRpcValue token; +DEFINE_SUBTITLESPROVIDER_END +#endif + +DEFINE_SUBTITLESPROVIDER_BEGIN(OpenSubtitles2, "OpenSubtitles.com", "https://www.opensubtitles.com", IDI_OPENSUBTITLES, SPF_LOGIN | SPF_HASH) +void Initialize() override; +bool NeedLogin() override; +SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; +SRESULT LogOut() override; +SRESULT Hash(SubtitlesInfo& pFileInfo) override; + +struct Response { + DWORD code; + std::string text; +}; + +bool CallAPI(CHttpFile* httpFile, CString& headers, std::string& body, Response& response); +bool CallAPI(CHttpFile* httpFile, CString& headers, Response& response); +bool CallAPIResponse(CHttpFile* httpFile, Response& response); +bool GetOptionalValue(const rapidjson::Value& node, const char* path, std::string& result); +bool GetOptionalValue(const rapidjson::Value& node, const char* path, int& result); +bool GetOptionalValue(const rapidjson::Value& node, const char* path, double& result); + +CString token; +static constexpr TCHAR* APIKEY = _T("s2GJfwwPNA74kkeXudFAdiHIqTDjgrmq"); +DEFINE_SUBTITLESPROVIDER_END + +DEFINE_SUBTITLESPROVIDER_BEGIN(podnapisi, "Podnapisi", "https://www.podnapisi.net", IDI_PODNAPISI, SPF_SEARCH) +SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; +SRESULT Hash(SubtitlesInfo& pFileInfo) override; +DEFINE_SUBTITLESPROVIDER_END + +DEFINE_SUBTITLESPROVIDER_BEGIN(Napisy24, "Napisy24", "https://napisy24.pl/", IDI_N24, SPF_HASH | SPF_SEARCH) +SRESULT Hash(SubtitlesInfo& pFileInfo) override; +DEFINE_SUBTITLESPROVIDER_END + +static const struct { + const char* code; + const char* name; +} podnapisi_languages[] = { + { /* 0*/ "", "" }, { /* 1*/ "sl", "Slovenian" }, { /* 2*/ "en", "English" }, + { /* 3*/ "no", "Norwegian" }, { /* 4*/ "ko", "Korean" }, { /* 5*/ "de", "German" }, + { /* 6*/ "is", "Icelandic" }, { /* 7*/ "cs", "Czech" }, { /* 8*/ "fr", "French" }, + { /* 9*/ "it", "Italian" }, { /*10*/ "bs", "Bosnian" }, { /*11*/ "ja", "Japanese" }, + { /*12*/ "ar", "Arabic" }, { /*13*/ "ro", "Romanian" }, { /*14*/ "es", "Argentino" }, + { /*15*/ "hu", "Hungarian" }, { /*16*/ "el", "Greek" }, { /*17*/ "zh", "Chinese" }, + { /*18*/ "", "" }, { /*19*/ "lt", "Lithuanian" }, { /*20*/ "et", "Estonian" }, + { /*21*/ "lv", "Latvian" }, { /*22*/ "he", "Hebrew" }, { /*23*/ "nl", "Dutch" }, + { /*24*/ "da", "Danish" }, { /*25*/ "sv", "Swedish" }, { /*26*/ "pl", "Polish" }, + { /*27*/ "ru", "Russian" }, { /*28*/ "es", "Spanish" }, { /*29*/ "sq", "Albanian" }, + { /*30*/ "tr", "Turkish" }, { /*31*/ "fi", "Finnish" }, { /*32*/ "pt", "Portuguese" }, + { /*33*/ "bg", "Bulgarian" }, { /*34*/ "", "" }, { /*35*/ "mk", "Macedonian" }, + { /*36*/ "sr", "Serbian" }, { /*37*/ "sk", "Slovak" }, { /*38*/ "hr", "Croatian" }, + { /*39*/ "", "" }, { /*40*/ "zh", "Mandarin" }, { /*41*/ "", "" }, + { /*42*/ "hi", "Hindi" }, { /*43*/ "", "" }, { /*44*/ "th", "Thai" }, + { /*45*/ "", "" }, { /*46*/ "uk", "Ukrainian" }, { /*47*/ "sr", "Serbian (Cyrillic)" }, + { /*48*/ "pb", "Brazilian" }, { /*49*/ "ga", "Irish" }, { /*50*/ "be", "Belarus" }, + { /*51*/ "vi", "Vietnamese" }, { /*52*/ "fa", "Farsi" }, { /*53*/ "ca", "Catalan" }, + { /*54*/ "id", "Indonesian" }, { /*55*/ "ms", "Malay" }, { /*56*/ "si", "Sinhala" }, + { /*57*/ "kl", "Greenlandic" }, { /*58*/ "kk", "Kazakh" }, { /*59*/ "bn", "Bengali" }, +}; diff --git a/src/mpc-hc/SubtitlesProviders.h b/src/mpc-hc/SubtitlesProviders.h index 872902768ae..4d20b19ad1b 100644 --- a/src/mpc-hc/SubtitlesProviders.h +++ b/src/mpc-hc/SubtitlesProviders.h @@ -1,443 +1,443 @@ -/* - * (C) 2016-2017 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 . - * - */ - -#pragma once - -#include "SubtitlesProvidersUtils.h" -#include "../Subtitles/SubtitleHelpers.h" -#include "base64/base64.h" -#include "VersionInfo.h" - -class CMainFrame; -struct SubtitlesInfo; -class SubtitlesThread; -class SubtitlesTask; -class SubtitlesProvider; -class SubtitlesProviders; - -using SubtitlesList = std::list; - -enum SubtitlesProviderFlags { - SPF_SEARCH = 0x00000000, - SPF_LOGIN = 0x00000001, - SPF_HASH = 0x00000002, -}; - -enum SubtitlesProviderLogin { - SPL_UNDEFINED = 0x00000000, - SPL_FAILED = 0x00000001, - SPL_ANONYMOUS = 0x00000002, - SPL_REGISTERED = 0x00000004, -}; - -enum SRESULT { - SR_UNDEFINED, - SR_SUCCEEDED, - SR_FAILED, - SR_ABORTED, - // Specific to search only - SR_TOOMANY, -}; - -enum SubtitlesThreadType { - STT_UNDEFINED = 0x00000000, - STT_SEARCH = 0x00000001, - STT_DOWNLOAD = 0x00000002, - STT_MANUALSEARCH = 0x00000008 -}; - - -struct SubtitlesInfo { - SubtitlesInfo() - : fileProvider(nullptr) - , uid(UINT_ERROR) - , score(0ul) - , fileSize(ULONGLONG_ERROR) - , year(INT_ERROR) - , seasonNumber(INT_ERROR) - , episodeNumber(INT_ERROR) - , discNumber(INT_ERROR) - , hearingImpaired(Subtitle::HI_UNKNOWN) - , discCount(INT_ERROR) - , downloadCount(INT_ERROR) - , corrected(0) - , frameRate(-1.0) - , framesNumber(INT_ERROR) - , lengthMs(ULONGLONG_ERROR) {} - bool operator<(const SubtitlesInfo& rhs) const { return score > rhs.score; } - HRESULT GetFileInfo(const std::string& sFileName = std::string()); - void Download(bool bActivate); - void OpenUrl() const; - std::shared_ptr Provider() const { return fileProvider; } - void Provider(std::shared_ptr pProvider) { fileProvider = pProvider; } - DWORD Score() const { return score; } - void Set(std::shared_ptr pProvider, BYTE nLanguage, BYTE nHearingImpaired, SHORT nScore) { - static UINT i(0); - // run twice to check whether i has reached MAXUINT32 which is invalid - if (uid == UINT_ERROR) { - uid = ++i; - if (uid == UINT_ERROR) { - uid = ++i; - } - } - fileProvider = pProvider; - score = MAKELONG(nScore + 0x10, MAKEWORD(nHearingImpaired, nLanguage)); - } - - std::string DisplayTitle() const { - std::string _title(title); - if (!title2.empty()) { - _title.append(": " + title2); - } - if (year != -1) { - _title.append(" (" + std::to_string(year) + ")"); - } - return _title; - } - - std::string NormalizeString(std::string sTitle) const { - // remove ' and ' from string and replace '!?&:\' with ' ' to get more accurate results - sTitle = std::regex_replace(sTitle, std::regex(" and ", SubtitlesProvidersUtils::RegexFlags), " "); - sTitle = std::regex_replace(sTitle, std::regex(" *[!?&:] *", SubtitlesProvidersUtils::RegexFlags), " "); - sTitle = std::regex_replace(sTitle, std::regex("'", SubtitlesProvidersUtils::RegexFlags), ""); - - return sTitle; - } - - std::string NormalizeTitle() const { return NormalizeString(title); } - UINT UID() const { return uid; } - -private: - std::shared_ptr fileProvider; - UINT uid; - DWORD score; -public: - // file properties - std::wstring filePathW; - std::string filePath; - std::string fileName; - std::string fileExtension; - ULONGLONG fileSize; - std::string fileContents; - std::string fileHash; - CComQIPtr pAsyncReader; - - // file name properties - std::string title; - std::string country; - int year; - std::string episode; - int seasonNumber; - int episodeNumber; - std::string title2; - std::string resolution; - std::string format; - std::string audioCodec; - std::string videoCodec; - std::string releaseGroup; - int discNumber; - - // subtitles properties - std::string id; - std::string imdbid; - std::string languageCode; - std::string languageName; - std::string url; - std::list releaseNames; - int hearingImpaired; - int discCount; - int downloadCount; - int corrected; - - // video properties - double frameRate; - int framesNumber; - ULONGLONG lengthMs; - - CString manualSearchString; -}; - - -class CWinThreadProc -{ -public: - CWinThreadProc() : m_pThread(nullptr), m_bAbort(false) {} - virtual ~CWinThreadProc() = default; - - operator CWinThread* () const { return m_pThread; } - - bool IsThreadRunning() const { return m_pThread != nullptr; } - volatile bool& IsThreadAborting() { return m_bAbort; } - - CWinThread* CreateThread() { - if (!IsThreadRunning()) { - m_pThread = AfxBeginThread(_ThreadProc, this); - } - return m_pThread; - } - void AbortThread() { - if (IsThreadRunning()) { - m_bAbort = true; - } - } - void WaitThread() const { - if (IsThreadRunning()) { - ::WaitForSingleObjectEx(*m_pThread, INFINITE, TRUE); - } - } - -private: - static UINT _ThreadProc(LPVOID pThreadParams) { - CWinThreadProc* pThread = static_cast(pThreadParams); - pThread->ThreadProc(); - return 0; - } - virtual void ThreadProc() PURE; - - CWinThread* m_pThread; - volatile bool m_bAbort; -}; - - -class SubtitlesThread final : public CWinThreadProc -{ - friend class SubtitlesProvider; - friend class SubtitlesTask; -public: - SubtitlesThread(SubtitlesTask* pTask, const SubtitlesInfo& pFileInfo, std::shared_ptr pProvider) - : m_pTask(pTask) - , m_pFileInfo(pFileInfo) - { m_pFileInfo.Provider(pProvider); } - -private: - void Set(SubtitlesInfo& pSubtitlesInfo); - - void ThreadProc() override; - void Search(); - void Download(SubtitlesInfo& pFileInfo, BOOL bActivate); - void Download(); - - void CheckAbortAndThrow() { - if (IsThreadAborting()) { - throw E_ABORT; - } - } - - SubtitlesTask* m_pTask; - SubtitlesInfo m_pFileInfo; - SubtitlesList m_pSubtitlesList; -}; - - -class SubtitlesTask final : public CWinThreadProc -{ - friend class SubtitlesThread; -public: - // Search - SubtitlesTask(CMainFrame* pMainFrame, bool bAutoDownload, const std::list& sLanguages); - SubtitlesTask(CMainFrame* pMainFrame, bool bAutoDownload, const std::list& sLanguages, CString manualSearch); - // Download - SubtitlesTask(CMainFrame* pMainFrame, SubtitlesInfo& pSubtitlesInfo, bool bActivate); - - SubtitlesThreadType Type() const { return m_nType; }; - BYTE GetLangPriority(const std::string& sLanguage) { - return m_LangPriority.count(sLanguage) ? m_LangPriority[sLanguage] : 0; - } - - void InsertThread(SubtitlesThread* pThread) { - CAutoLock cAutoLock(&m_csThreads); - m_pThreads.push_back(pThread); - } - - void RemoveThread(SubtitlesThread* pThread) { - { - CAutoLock cAutoLock(&m_csThreads); - m_pThreads.remove(pThread); - } - delete pThread; - } - - void Abort() { - if(!this) return; - CAutoLock cAutoLock(&m_csThreads); - for (auto& iter : m_pThreads) { - iter->AbortThread(); - } - AbortThread(); - } - -private: - void ThreadProc() override; - - CMainFrame* m_pMainFrame; - std::list m_pThreads; - CCritSec m_csThreads; - CCritSec m_csDownload; - - SubtitlesInfo m_pFileInfo; - bool m_bActivate; - SubtitlesThreadType m_nType; - bool m_bAutoDownload; - std::unordered_map m_AutoDownload; - std::unordered_map m_LangPriority; - - CString manualSearch; -}; - -class SubtitlesProvider -{ -public: - SubtitlesProvider(SubtitlesProviders* pOwner); - virtual ~SubtitlesProvider() = default; - -public: // implemented - virtual std::string Name() const PURE; - virtual std::string DisplayName() const PURE; - virtual std::string Url() const PURE; - virtual const std::set& Languages() const PURE; - virtual bool Flags(DWORD dwFlags) const PURE; - virtual int Icon() const PURE; - virtual SRESULT Search(const SubtitlesInfo& pFileInfo) PURE; - virtual SRESULT Download(SubtitlesInfo& pSubtitlesInfo) PURE; - -protected: // overridden - virtual void Initialize() {} - virtual void Uninitialize() { LogOut(); } -public: // overridden - virtual bool NeedLogin() { return !(m_nLoggedIn & (SPL_REGISTERED | SPL_ANONYMOUS)); } - virtual SRESULT Login(const std::string&, const std::string&) { return SR_UNDEFINED; } - virtual SRESULT LogOut() { - m_nLoggedIn = SPL_UNDEFINED; - return SR_SUCCEEDED; - } - virtual SRESULT Hash(SubtitlesInfo&) { return SR_UNDEFINED; } - virtual std::string UserAgent() const { - return SubtitlesProvidersUtils::StringFormat("MPC-HC v%u.%u.%u", - VersionInfo::GetMajorNumber(), - VersionInfo::GetMinorNumber(), - VersionInfo::GetPatchNumber()); - } - - bool LoginInternal(); - void OpenUrl() const; - size_t Index() const; - static bool CheckInternetConnection(); - static bool CheckLanguage(const std::string& sLanguageCode); - std::list GetLanguagesIntersection() const; - std::list GetLanguagesIntersection(std::list&& userSelectedLangauges) const; - bool SupportsUserSelectedLanguages() const; - SRESULT DownloadInternal(std::string url, std::string referer, std::string& data) const; - static void Set(SubtitlesInfo& pSubtitlesInfo); - static bool IsAborting(); - - BOOL Enabled(SubtitlesProviderFlags nFlag) { return m_bSearch; } - void Enabled(SubtitlesProviderFlags nFlag, BOOL bEnabled) { - m_bSearch = bEnabled; - } - std::string UserName() const { return m_sUserName; }; - void UserName(std::string sUserName) { m_sUserName = sUserName; }; - std::string Password(bool bDecrypt = true) { - return bDecrypt - ? SubtitlesProvidersUtils::StringDecrypt(Base64::decode(m_sPassword), SubtitlesProvidersUtils::StringGenerateUniqueKey()) - : m_sPassword; - }; - void Password(LPCSTR sPassword, bool bEncrypt = true) { - m_sPassword = bEncrypt - ? Base64::encode(SubtitlesProvidersUtils::StringEncrypt(sPassword, SubtitlesProvidersUtils::StringGenerateUniqueKey())) - : sPassword; - }; - SubtitlesProviders& Providers() const { return *m_pOwner; } - int GetIconIndex() const { return m_nIconIndex; } - void SetIconIndex(int nIconIndex) { m_nIconIndex = nIconIndex; } - -private: - BOOL m_bSearch; - std::string m_sUserName; - std::string m_sPassword; - SubtitlesProviders* m_pOwner; - int m_nIconIndex; -protected: - SubtitlesProviderLogin m_nLoggedIn; -}; - -class SubtitlesProviders final -{ -public: - explicit SubtitlesProviders(CMainFrame* pMainFrame); - ~SubtitlesProviders(); - SubtitlesProviders(SubtitlesProviders const&) = delete; - SubtitlesProviders& operator=(SubtitlesProviders const&) = delete; - -private: - void RegisterProviders(); - template - void Register(SubtitlesProviders* pOwner) { - m_pProviders.push_back(T::Create(pOwner)); - auto& provider = m_pProviders.back(); - HICON hIcon = ::LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(provider->Icon())); - provider->SetIconIndex(m_himl.Add(hIcon)); - DestroyIcon(hIcon); - } - -public: - const std::vector>& Providers() const { - return m_pProviders; - }; - static BOOL SubtitlesProviders::CheckInternetConnection(); - - void ReadSettings(); - std::string WriteSettings(); - - void Search(bool bAutoDownload); - void ManualSearch(bool bAutoDownload, CString manualSearch); - void Download(SubtitlesInfo& pSubtitlesInfo, bool bActivate); - void Abort(SubtitlesThreadType nType); - - void InsertTask(SubtitlesTask* pTask) { - CAutoLock cAutoLock(&m_csTasks); - m_pTasks.push_back(pTask); - } - - void RemoveTask(SubtitlesTask* pTask) { - CAutoLock cAutoLock(&m_csTasks); - if(!m_pTasks.empty()) { - m_pTasks.remove(pTask); - } - } - - void MoveUp(size_t nIndex) { - std::iter_swap(m_pProviders.begin() + nIndex, m_pProviders.begin() + nIndex - 1); - } - - void MoveDown(size_t nIndex) { - std::iter_swap(m_pProviders.begin() + nIndex, m_pProviders.begin() + nIndex + 1); - } - - CImageList& GetImageList() { return m_himl; } - -private: - CMainFrame* m_pMainFrame; - - std::vector> m_pProviders; - - CCritSec m_csTasks; - std::list m_pTasks; - CImageList m_himl; -}; +/* + * (C) 2016-2017 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 . + * + */ + +#pragma once + +#include "SubtitlesProvidersUtils.h" +#include "../Subtitles/SubtitleHelpers.h" +#include "base64/base64.h" +#include "VersionInfo.h" + +class CMainFrame; +struct SubtitlesInfo; +class SubtitlesThread; +class SubtitlesTask; +class SubtitlesProvider; +class SubtitlesProviders; + +using SubtitlesList = std::list; + +enum SubtitlesProviderFlags { + SPF_SEARCH = 0x00000000, + SPF_LOGIN = 0x00000001, + SPF_HASH = 0x00000002, +}; + +enum SubtitlesProviderLogin { + SPL_UNDEFINED = 0x00000000, + SPL_FAILED = 0x00000001, + SPL_ANONYMOUS = 0x00000002, + SPL_REGISTERED = 0x00000004, +}; + +enum SRESULT { + SR_UNDEFINED, + SR_SUCCEEDED, + SR_FAILED, + SR_ABORTED, + // Specific to search only + SR_TOOMANY, +}; + +enum SubtitlesThreadType { + STT_UNDEFINED = 0x00000000, + STT_SEARCH = 0x00000001, + STT_DOWNLOAD = 0x00000002, + STT_MANUALSEARCH = 0x00000008 +}; + + +struct SubtitlesInfo { + SubtitlesInfo() + : fileProvider(nullptr) + , uid(UINT_ERROR) + , score(0ul) + , fileSize(ULONGLONG_ERROR) + , year(INT_ERROR) + , seasonNumber(INT_ERROR) + , episodeNumber(INT_ERROR) + , discNumber(INT_ERROR) + , hearingImpaired(Subtitle::HI_UNKNOWN) + , discCount(INT_ERROR) + , downloadCount(INT_ERROR) + , corrected(0) + , frameRate(-1.0) + , framesNumber(INT_ERROR) + , lengthMs(ULONGLONG_ERROR) {} + bool operator<(const SubtitlesInfo& rhs) const { return score > rhs.score; } + HRESULT GetFileInfo(const std::string& sFileName = std::string()); + void Download(bool bActivate); + void OpenUrl() const; + std::shared_ptr Provider() const { return fileProvider; } + void Provider(std::shared_ptr pProvider) { fileProvider = pProvider; } + DWORD Score() const { return score; } + void Set(std::shared_ptr pProvider, BYTE nLanguage, BYTE nHearingImpaired, SHORT nScore) { + static UINT i(0); + // run twice to check whether i has reached MAXUINT32 which is invalid + if (uid == UINT_ERROR) { + uid = ++i; + if (uid == UINT_ERROR) { + uid = ++i; + } + } + fileProvider = pProvider; + score = MAKELONG(nScore + 0x10, MAKEWORD(nHearingImpaired, nLanguage)); + } + + std::string DisplayTitle() const { + std::string _title(title); + if (!title2.empty()) { + _title.append(": " + title2); + } + if (year != -1) { + _title.append(" (" + std::to_string(year) + ")"); + } + return _title; + } + + std::string NormalizeString(std::string sTitle) const { + // remove ' and ' from string and replace '!?&:\' with ' ' to get more accurate results + sTitle = std::regex_replace(sTitle, std::regex(" and ", SubtitlesProvidersUtils::RegexFlags), " "); + sTitle = std::regex_replace(sTitle, std::regex(" *[!?&:] *", SubtitlesProvidersUtils::RegexFlags), " "); + sTitle = std::regex_replace(sTitle, std::regex("'", SubtitlesProvidersUtils::RegexFlags), ""); + + return sTitle; + } + + std::string NormalizeTitle() const { return NormalizeString(title); } + UINT UID() const { return uid; } + +private: + std::shared_ptr fileProvider; + UINT uid; + DWORD score; +public: + // file properties + std::wstring filePathW; + std::string filePath; + std::string fileName; + std::string fileExtension; + ULONGLONG fileSize; + std::string fileContents; + std::string fileHash; + CComQIPtr pAsyncReader; + + // file name properties + std::string title; + std::string country; + int year; + std::string episode; + int seasonNumber; + int episodeNumber; + std::string title2; + std::string resolution; + std::string format; + std::string audioCodec; + std::string videoCodec; + std::string releaseGroup; + int discNumber; + + // subtitles properties + std::string id; + std::string imdbid; + std::string languageCode; + std::string languageName; + std::string url; + std::list releaseNames; + int hearingImpaired; + int discCount; + int downloadCount; + int corrected; + + // video properties + double frameRate; + int framesNumber; + ULONGLONG lengthMs; + + CString manualSearchString; +}; + + +class CWinThreadProc +{ +public: + CWinThreadProc() : m_pThread(nullptr), m_bAbort(false) {} + virtual ~CWinThreadProc() = default; + + operator CWinThread* () const { return m_pThread; } + + bool IsThreadRunning() const { return m_pThread != nullptr; } + volatile bool& IsThreadAborting() { return m_bAbort; } + + CWinThread* CreateThread() { + if (!IsThreadRunning()) { + m_pThread = AfxBeginThread(_ThreadProc, this); + } + return m_pThread; + } + void AbortThread() { + if (IsThreadRunning()) { + m_bAbort = true; + } + } + void WaitThread() const { + if (IsThreadRunning()) { + ::WaitForSingleObjectEx(*m_pThread, INFINITE, TRUE); + } + } + +private: + static UINT _ThreadProc(LPVOID pThreadParams) { + CWinThreadProc* pThread = static_cast(pThreadParams); + pThread->ThreadProc(); + return 0; + } + virtual void ThreadProc() PURE; + + CWinThread* m_pThread; + volatile bool m_bAbort; +}; + + +class SubtitlesThread final : public CWinThreadProc +{ + friend class SubtitlesProvider; + friend class SubtitlesTask; +public: + SubtitlesThread(SubtitlesTask* pTask, const SubtitlesInfo& pFileInfo, std::shared_ptr pProvider) + : m_pTask(pTask) + , m_pFileInfo(pFileInfo) + { m_pFileInfo.Provider(pProvider); } + +private: + void Set(SubtitlesInfo& pSubtitlesInfo); + + void ThreadProc() override; + void Search(); + void Download(SubtitlesInfo& pFileInfo, BOOL bActivate); + void Download(); + + void CheckAbortAndThrow() { + if (IsThreadAborting()) { + throw E_ABORT; + } + } + + SubtitlesTask* m_pTask; + SubtitlesInfo m_pFileInfo; + SubtitlesList m_pSubtitlesList; +}; + + +class SubtitlesTask final : public CWinThreadProc +{ + friend class SubtitlesThread; +public: + // Search + SubtitlesTask(CMainFrame* pMainFrame, bool bAutoDownload, const std::list& sLanguages); + SubtitlesTask(CMainFrame* pMainFrame, bool bAutoDownload, const std::list& sLanguages, CString manualSearch); + // Download + SubtitlesTask(CMainFrame* pMainFrame, SubtitlesInfo& pSubtitlesInfo, bool bActivate); + + SubtitlesThreadType Type() const { return m_nType; }; + BYTE GetLangPriority(const std::string& sLanguage) { + return m_LangPriority.count(sLanguage) ? m_LangPriority[sLanguage] : 0; + } + + void InsertThread(SubtitlesThread* pThread) { + CAutoLock cAutoLock(&m_csThreads); + m_pThreads.push_back(pThread); + } + + void RemoveThread(SubtitlesThread* pThread) { + { + CAutoLock cAutoLock(&m_csThreads); + m_pThreads.remove(pThread); + } + delete pThread; + } + + void Abort() { + if(!this) return; + CAutoLock cAutoLock(&m_csThreads); + for (auto& iter : m_pThreads) { + iter->AbortThread(); + } + AbortThread(); + } + +private: + void ThreadProc() override; + + CMainFrame* m_pMainFrame; + std::list m_pThreads; + CCritSec m_csThreads; + CCritSec m_csDownload; + + SubtitlesInfo m_pFileInfo; + bool m_bActivate; + SubtitlesThreadType m_nType; + bool m_bAutoDownload; + std::unordered_map m_AutoDownload; + std::unordered_map m_LangPriority; + + CString manualSearch; +}; + +class SubtitlesProvider +{ +public: + SubtitlesProvider(SubtitlesProviders* pOwner); + virtual ~SubtitlesProvider() = default; + +public: // implemented + virtual std::string Name() const PURE; + virtual std::string DisplayName() const PURE; + virtual std::string Url() const PURE; + virtual const std::set& Languages() const PURE; + virtual bool Flags(DWORD dwFlags) const PURE; + virtual int Icon() const PURE; + virtual SRESULT Search(const SubtitlesInfo& pFileInfo) PURE; + virtual SRESULT Download(SubtitlesInfo& pSubtitlesInfo) PURE; + +protected: // overridden + virtual void Initialize() {} + virtual void Uninitialize() { LogOut(); } +public: // overridden + virtual bool NeedLogin() { return !(m_nLoggedIn & (SPL_REGISTERED | SPL_ANONYMOUS)); } + virtual SRESULT Login(const std::string&, const std::string&) { return SR_UNDEFINED; } + virtual SRESULT LogOut() { + m_nLoggedIn = SPL_UNDEFINED; + return SR_SUCCEEDED; + } + virtual SRESULT Hash(SubtitlesInfo&) { return SR_UNDEFINED; } + virtual std::string UserAgent() const { + return SubtitlesProvidersUtils::StringFormat("MPC-HC v%u.%u.%u", + VersionInfo::GetMajorNumber(), + VersionInfo::GetMinorNumber(), + VersionInfo::GetPatchNumber()); + } + + bool LoginInternal(); + void OpenUrl() const; + size_t Index() const; + static bool CheckInternetConnection(); + static bool CheckLanguage(const std::string& sLanguageCode); + std::list GetLanguagesIntersection() const; + std::list GetLanguagesIntersection(std::list&& userSelectedLangauges) const; + bool SupportsUserSelectedLanguages() const; + SRESULT DownloadInternal(std::string url, std::string referer, std::string& data) const; + static void Set(SubtitlesInfo& pSubtitlesInfo); + static bool IsAborting(); + + BOOL Enabled(SubtitlesProviderFlags nFlag) { return m_bSearch; } + void Enabled(SubtitlesProviderFlags nFlag, BOOL bEnabled) { + m_bSearch = bEnabled; + } + std::string UserName() const { return m_sUserName; }; + void UserName(std::string sUserName) { m_sUserName = sUserName; }; + std::string Password(bool bDecrypt = true) { + return bDecrypt + ? SubtitlesProvidersUtils::StringDecrypt(Base64::decode(m_sPassword), SubtitlesProvidersUtils::StringGenerateUniqueKey()) + : m_sPassword; + }; + void Password(LPCSTR sPassword, bool bEncrypt = true) { + m_sPassword = bEncrypt + ? Base64::encode(SubtitlesProvidersUtils::StringEncrypt(sPassword, SubtitlesProvidersUtils::StringGenerateUniqueKey())) + : sPassword; + }; + SubtitlesProviders& Providers() const { return *m_pOwner; } + int GetIconIndex() const { return m_nIconIndex; } + void SetIconIndex(int nIconIndex) { m_nIconIndex = nIconIndex; } + +private: + BOOL m_bSearch; + std::string m_sUserName; + std::string m_sPassword; + SubtitlesProviders* m_pOwner; + int m_nIconIndex; +protected: + SubtitlesProviderLogin m_nLoggedIn; +}; + +class SubtitlesProviders final +{ +public: + explicit SubtitlesProviders(CMainFrame* pMainFrame); + ~SubtitlesProviders(); + SubtitlesProviders(SubtitlesProviders const&) = delete; + SubtitlesProviders& operator=(SubtitlesProviders const&) = delete; + +private: + void RegisterProviders(); + template + void Register(SubtitlesProviders* pOwner) { + m_pProviders.push_back(T::Create(pOwner)); + auto& provider = m_pProviders.back(); + HICON hIcon = ::LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(provider->Icon())); + provider->SetIconIndex(m_himl.Add(hIcon)); + DestroyIcon(hIcon); + } + +public: + const std::vector>& Providers() const { + return m_pProviders; + }; + static BOOL SubtitlesProviders::CheckInternetConnection(); + + void ReadSettings(); + std::string WriteSettings(); + + void Search(bool bAutoDownload); + void ManualSearch(bool bAutoDownload, CString manualSearch); + void Download(SubtitlesInfo& pSubtitlesInfo, bool bActivate); + void Abort(SubtitlesThreadType nType); + + void InsertTask(SubtitlesTask* pTask) { + CAutoLock cAutoLock(&m_csTasks); + m_pTasks.push_back(pTask); + } + + void RemoveTask(SubtitlesTask* pTask) { + CAutoLock cAutoLock(&m_csTasks); + if(!m_pTasks.empty()) { + m_pTasks.remove(pTask); + } + } + + void MoveUp(size_t nIndex) { + std::iter_swap(m_pProviders.begin() + nIndex, m_pProviders.begin() + nIndex - 1); + } + + void MoveDown(size_t nIndex) { + std::iter_swap(m_pProviders.begin() + nIndex, m_pProviders.begin() + nIndex + 1); + } + + CImageList& GetImageList() { return m_himl; } + +private: + CMainFrame* m_pMainFrame; + + std::vector> m_pProviders; + + CCritSec m_csTasks; + std::list m_pTasks; + CImageList m_himl; +}; diff --git a/src/mpc-hc/TextPassThruFilter.cpp b/src/mpc-hc/TextPassThruFilter.cpp index 184f6c45eca..16361a29367 100644 --- a/src/mpc-hc/TextPassThruFilter.cpp +++ b/src/mpc-hc/TextPassThruFilter.cpp @@ -1,255 +1,255 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#include "stdafx.h" -#include -#include "mplayerc.h" -#include "MainFrm.h" -#include "TextPassThruFilter.h" -#include "moreuuids.h" -#include "DSUtil.h" -#include "../Subtitles/SubtitleInputPin.h" - -// -// CTextPassThruInputPin -// - -class CTextPassThruInputPin : public CSubtitleInputPin -{ - CTextPassThruFilter* m_pTPTFilter; - CComPtr m_pSubStreamOld; - -protected: - void AddSubStream(ISubStream* pSubStream) { - if (m_pSubStreamOld) { - if (pSubStream) { - m_pTPTFilter->m_pMainFrame->ReplaceSubtitle(m_pSubStreamOld, pSubStream); - } - m_pSubStreamOld = nullptr; - } - } - - void RemoveSubStream(ISubStream* pSubStream) { - m_pSubStreamOld = pSubStream; - } - - void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) { - m_pTPTFilter->m_pMainFrame->InvalidateSubtitle((DWORD_PTR)pSubStream, rtStart); - } - -public: - CTextPassThruInputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP EndOfStream(); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - - HRESULT CompleteConnect(IPin* pReceivePin); -}; - -// -// CTextPassThruOutputPin -// - -class CTextPassThruOutputPin : public CBaseOutputPin -{ - CTextPassThruFilter* m_pTPTFilter; - -public: - CTextPassThruOutputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, HRESULT* phr); - - HRESULT CheckMediaType(const CMediaType* mtOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) { - return S_OK; - } -}; - -/////////// - -CTextPassThruInputPin::CTextPassThruInputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr) - : CSubtitleInputPin(pTPTFilter, pLock, pSubLock, phr) - , m_pTPTFilter(pTPTFilter) -{ -} - -STDMETHODIMP CTextPassThruInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - HRESULT hr = __super::NewSegment(tStart, tStop, dRate); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->DeliverNewSegment(tStart, tStop, dRate); -} - -STDMETHODIMP CTextPassThruInputPin::Receive(IMediaSample* pSample) -{ - HRESULT hr = __super::Receive(pSample); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->Deliver(pSample); -} - -STDMETHODIMP CTextPassThruInputPin::EndOfStream() -{ - HRESULT hr = __super::EndOfStream(); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->DeliverEndOfStream(); -} - -STDMETHODIMP CTextPassThruInputPin::BeginFlush() -{ - HRESULT hr = __super::BeginFlush(); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->DeliverBeginFlush(); -} - -STDMETHODIMP CTextPassThruInputPin::EndFlush() -{ - HRESULT hr = __super::EndFlush(); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->DeliverEndFlush(); -} - -HRESULT CTextPassThruInputPin::CompleteConnect(IPin* pReceivePin) -{ - HRESULT hr = __super::CompleteConnect(pReceivePin); - if (FAILED(hr) || !m_pTPTFilter->m_pOutput->IsConnected()) { - return hr; - } - return m_pTPTFilter->ReconnectPin(m_pTPTFilter->m_pOutput, &m_mt); -} - -// - -CTextPassThruOutputPin::CTextPassThruOutputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, HRESULT* phr) - : CBaseOutputPin(NAME(""), pTPTFilter, pLock, phr, L"Out") - , m_pTPTFilter(pTPTFilter) -{ -} - -HRESULT CTextPassThruOutputPin::CheckMediaType(const CMediaType* mtOut) -{ - CMediaType mt; - return S_OK == m_pTPTFilter->m_pInput->ConnectionMediaType(&mt) && mt == *mtOut - ? S_OK - : E_FAIL; -} - -HRESULT CTextPassThruOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pTPTFilter->m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - CComPtr pAllocatorIn; - m_pTPTFilter->m_pInput->GetAllocator(&pAllocatorIn); - if (!pAllocatorIn) { - return E_UNEXPECTED; - } - - pAllocatorIn->GetProperties(pProperties); - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -HRESULT CTextPassThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - if (m_pTPTFilter->m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - m_pTPTFilter->m_pInput->ConnectionMediaType(pmt); - - return S_OK; -} - -// -// CTextPassThruFilter -// - -CTextPassThruFilter::CTextPassThruFilter(CMainFrame* pMainFrame) - : CBaseFilter(NAME("CTextPassThruFilter"), nullptr, this, __uuidof(this)) - , m_pMainFrame(pMainFrame) -{ - HRESULT hr; - m_pInput = DEBUG_NEW CTextPassThruInputPin(this, this, &m_pMainFrame->m_csSubLock, &hr); - m_pOutput = DEBUG_NEW CTextPassThruOutputPin(this, this, &hr); -} - -CTextPassThruFilter::~CTextPassThruFilter() -{ - delete m_pInput; - m_pInput = nullptr; - delete m_pOutput; - m_pOutput = nullptr; -} - -STDMETHODIMP CTextPassThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - if (m_pInput && riid == __uuidof(ISubStream)) { - if (CComPtr pSubStream = m_pInput->GetSubStream()) { - *ppv = pSubStream.Detach(); - return S_OK; - } - } - - return __super::NonDelegatingQueryInterface(riid, ppv); -} - -int CTextPassThruFilter::GetPinCount() -{ - return 2; -} - -CBasePin* CTextPassThruFilter::GetPin(int n) -{ - if (n == 0) { - return m_pInput; - } else if (n == 1) { - return m_pOutput; - } - return nullptr; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#include "stdafx.h" +#include +#include "mplayerc.h" +#include "MainFrm.h" +#include "TextPassThruFilter.h" +#include "moreuuids.h" +#include "DSUtil.h" +#include "../Subtitles/SubtitleInputPin.h" + +// +// CTextPassThruInputPin +// + +class CTextPassThruInputPin : public CSubtitleInputPin +{ + CTextPassThruFilter* m_pTPTFilter; + CComPtr m_pSubStreamOld; + +protected: + void AddSubStream(ISubStream* pSubStream) { + if (m_pSubStreamOld) { + if (pSubStream) { + m_pTPTFilter->m_pMainFrame->ReplaceSubtitle(m_pSubStreamOld, pSubStream); + } + m_pSubStreamOld = nullptr; + } + } + + void RemoveSubStream(ISubStream* pSubStream) { + m_pSubStreamOld = pSubStream; + } + + void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) { + m_pTPTFilter->m_pMainFrame->InvalidateSubtitle((DWORD_PTR)pSubStream, rtStart); + } + +public: + CTextPassThruInputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP EndOfStream(); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + + HRESULT CompleteConnect(IPin* pReceivePin); +}; + +// +// CTextPassThruOutputPin +// + +class CTextPassThruOutputPin : public CBaseOutputPin +{ + CTextPassThruFilter* m_pTPTFilter; + +public: + CTextPassThruOutputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, HRESULT* phr); + + HRESULT CheckMediaType(const CMediaType* mtOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) { + return S_OK; + } +}; + +/////////// + +CTextPassThruInputPin::CTextPassThruInputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr) + : CSubtitleInputPin(pTPTFilter, pLock, pSubLock, phr) + , m_pTPTFilter(pTPTFilter) +{ +} + +STDMETHODIMP CTextPassThruInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + HRESULT hr = __super::NewSegment(tStart, tStop, dRate); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->DeliverNewSegment(tStart, tStop, dRate); +} + +STDMETHODIMP CTextPassThruInputPin::Receive(IMediaSample* pSample) +{ + HRESULT hr = __super::Receive(pSample); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->Deliver(pSample); +} + +STDMETHODIMP CTextPassThruInputPin::EndOfStream() +{ + HRESULT hr = __super::EndOfStream(); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->DeliverEndOfStream(); +} + +STDMETHODIMP CTextPassThruInputPin::BeginFlush() +{ + HRESULT hr = __super::BeginFlush(); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->DeliverBeginFlush(); +} + +STDMETHODIMP CTextPassThruInputPin::EndFlush() +{ + HRESULT hr = __super::EndFlush(); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->DeliverEndFlush(); +} + +HRESULT CTextPassThruInputPin::CompleteConnect(IPin* pReceivePin) +{ + HRESULT hr = __super::CompleteConnect(pReceivePin); + if (FAILED(hr) || !m_pTPTFilter->m_pOutput->IsConnected()) { + return hr; + } + return m_pTPTFilter->ReconnectPin(m_pTPTFilter->m_pOutput, &m_mt); +} + +// + +CTextPassThruOutputPin::CTextPassThruOutputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, HRESULT* phr) + : CBaseOutputPin(NAME(""), pTPTFilter, pLock, phr, L"Out") + , m_pTPTFilter(pTPTFilter) +{ +} + +HRESULT CTextPassThruOutputPin::CheckMediaType(const CMediaType* mtOut) +{ + CMediaType mt; + return S_OK == m_pTPTFilter->m_pInput->ConnectionMediaType(&mt) && mt == *mtOut + ? S_OK + : E_FAIL; +} + +HRESULT CTextPassThruOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pTPTFilter->m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + CComPtr pAllocatorIn; + m_pTPTFilter->m_pInput->GetAllocator(&pAllocatorIn); + if (!pAllocatorIn) { + return E_UNEXPECTED; + } + + pAllocatorIn->GetProperties(pProperties); + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +HRESULT CTextPassThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + if (m_pTPTFilter->m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + m_pTPTFilter->m_pInput->ConnectionMediaType(pmt); + + return S_OK; +} + +// +// CTextPassThruFilter +// + +CTextPassThruFilter::CTextPassThruFilter(CMainFrame* pMainFrame) + : CBaseFilter(NAME("CTextPassThruFilter"), nullptr, this, __uuidof(this)) + , m_pMainFrame(pMainFrame) +{ + HRESULT hr; + m_pInput = DEBUG_NEW CTextPassThruInputPin(this, this, &m_pMainFrame->m_csSubLock, &hr); + m_pOutput = DEBUG_NEW CTextPassThruOutputPin(this, this, &hr); +} + +CTextPassThruFilter::~CTextPassThruFilter() +{ + delete m_pInput; + m_pInput = nullptr; + delete m_pOutput; + m_pOutput = nullptr; +} + +STDMETHODIMP CTextPassThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + if (m_pInput && riid == __uuidof(ISubStream)) { + if (CComPtr pSubStream = m_pInput->GetSubStream()) { + *ppv = pSubStream.Detach(); + return S_OK; + } + } + + return __super::NonDelegatingQueryInterface(riid, ppv); +} + +int CTextPassThruFilter::GetPinCount() +{ + return 2; +} + +CBasePin* CTextPassThruFilter::GetPin(int n) +{ + if (n == 0) { + return m_pInput; + } else if (n == 1) { + return m_pOutput; + } + return nullptr; +} diff --git a/src/mpc-hc/TextPassThruFilter.h b/src/mpc-hc/TextPassThruFilter.h index 78758659b82..7304989c2a2 100644 --- a/src/mpc-hc/TextPassThruFilter.h +++ b/src/mpc-hc/TextPassThruFilter.h @@ -1,46 +1,46 @@ -/* - * (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 . - * - */ - -#pragma once - -class CTextPassThruInputPin; - -class __declspec(uuid("E2BA9B7B-B65D-4804-ACB2-89C3E55511DB")) - CTextPassThruFilter : public CBaseFilter, public CCritSec -{ - friend class CTextPassThruInputPin; - friend class CTextPassThruOutputPin; - - CTextPassThruInputPin* m_pInput; - CTextPassThruOutputPin* m_pOutput; - - CMainFrame* m_pMainFrame; - -public: - CTextPassThruFilter(CMainFrame* pMainFrame); - virtual ~CTextPassThruFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - int GetPinCount(); - CBasePin* GetPin(int n); -}; +/* + * (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 . + * + */ + +#pragma once + +class CTextPassThruInputPin; + +class __declspec(uuid("E2BA9B7B-B65D-4804-ACB2-89C3E55511DB")) + CTextPassThruFilter : public CBaseFilter, public CCritSec +{ + friend class CTextPassThruInputPin; + friend class CTextPassThruOutputPin; + + CTextPassThruInputPin* m_pInput; + CTextPassThruOutputPin* m_pOutput; + + CMainFrame* m_pMainFrame; + +public: + CTextPassThruFilter(CMainFrame* pMainFrame); + virtual ~CTextPassThruFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + int GetPinCount(); + CBasePin* GetPin(int n); +}; diff --git a/src/mpc-hc/TunerScanDlg.cpp b/src/mpc-hc/TunerScanDlg.cpp index da7360c5957..dd915300f32 100644 --- a/src/mpc-hc/TunerScanDlg.cpp +++ b/src/mpc-hc/TunerScanDlg.cpp @@ -1,317 +1,317 @@ -/* - * (C) 2009-2017 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 . - * - */ - -// TunerScanDlg.cpp : implementation file -// - -#include "stdafx.h" -#include "mplayerc.h" -#include "MainFrm.h" -#include "TunerScanDlg.h" -#include "DVBChannel.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" - - -enum TSC_COLUMN { - TSCC_NUMBER, - TSCC_NAME, - TSCC_FREQUENCY, - TSCC_ENCRYPTED, - TSCC_VIDEO_FORMAT, - TSCC_VIDEO_FPS, - TSCC_VIDEO_RES, - TSCC_VIDEO_AR, - TSCC_CHANNEL -}; - -// CTunerScanDlg dialog - -IMPLEMENT_DYNAMIC(CTunerScanDlg, CMPCThemeDialog) - -CTunerScanDlg::CTunerScanDlg(CMainFrame* pMainFrame) - : CMPCThemeDialog(CTunerScanDlg::IDD, pMainFrame) - , m_pMainFrame(pMainFrame) - , m_bInProgress(false) -{ - const CAppSettings& s = AfxGetAppSettings(); - - m_ulFrequencyStart = s.iBDAScanFreqStart; - m_ulFrequencyEnd = s.iBDAScanFreqEnd; - m_ulBandwidth = s.iBDABandwidth * 1000; - m_ulSymbolRate = s.iBDASymbolRate; - m_bUseOffset = s.fBDAUseOffset; - m_lOffset = s.iBDAOffset; - m_bIgnoreEncryptedChannels = s.fBDAIgnoreEncryptedChannels; -} - -CTunerScanDlg::~CTunerScanDlg() -{ -} - -BOOL CTunerScanDlg::OnInitDialog() -{ - CMPCThemeDialog::OnInitDialog(); - - m_OffsetEditBox.EnableWindow(m_bUseOffset); - - m_ChannelList.InsertColumn(TSCC_NUMBER, ResStr(IDS_DVB_CHANNEL_NUMBER), LVCFMT_LEFT, 35); - m_ChannelList.InsertColumn(TSCC_NAME, ResStr(IDS_DVB_CHANNEL_NAME), LVCFMT_LEFT, 190); - m_ChannelList.InsertColumn(TSCC_FREQUENCY, ResStr(IDS_DVB_CHANNEL_FREQUENCY), LVCFMT_LEFT, 65); - m_ChannelList.InsertColumn(TSCC_ENCRYPTED, ResStr(IDS_DVB_CHANNEL_ENCRYPTION), LVCFMT_CENTER, 55); - m_ChannelList.InsertColumn(TSCC_VIDEO_FORMAT, ResStr(IDS_DVB_CHANNEL_FORMAT), LVCFMT_CENTER, 55); - m_ChannelList.InsertColumn(TSCC_VIDEO_FPS, ResStr(IDS_DVB_CHANNEL_FPS), LVCFMT_CENTER, 50); - m_ChannelList.InsertColumn(TSCC_VIDEO_RES, ResStr(IDS_DVB_CHANNEL_RESOLUTION), LVCFMT_CENTER, 70); - m_ChannelList.InsertColumn(TSCC_VIDEO_AR, ResStr(IDS_DVB_CHANNEL_ASPECT_RATIO), LVCFMT_CENTER, 50); - m_ChannelList.InsertColumn(TSCC_CHANNEL, _T("Channel"), LVCFMT_LEFT, 0); - - m_Progress.SetRange(0, 100); - CMPCThemeUtil::fulfillThemeReqs(&m_Progress); - m_Strength.SetRange(0, 100); - CMPCThemeUtil::fulfillThemeReqs(&m_Strength); - m_Quality.SetRange(0, 100); - CMPCThemeUtil::fulfillThemeReqs(&m_Quality); - - m_btnSave.EnableWindow(FALSE); - - return TRUE; -} - -void CTunerScanDlg::DoDataExchange(CDataExchange* pDX) -{ - CMPCThemeDialog::DoDataExchange(pDX); - DDX_Text(pDX, IDC_FREQ_START, m_ulFrequencyStart); - DDX_Text(pDX, IDC_FREQ_END, m_ulFrequencyEnd); - DDX_Text(pDX, IDC_BANDWIDTH, m_ulBandwidth); - DDX_Text(pDX, IDC_SYMBOLRATE, m_ulSymbolRate); - DDX_Text(pDX, IDC_OFFSET, m_lOffset); - DDX_Check(pDX, IDC_CHECK_OFFSET, m_bUseOffset); - DDX_Check(pDX, IDC_CHECK_IGNORE_ENCRYPTED, m_bIgnoreEncryptedChannels); - DDX_Control(pDX, IDC_PROGRESS, m_Progress); - DDX_Control(pDX, IDC_STRENGTH, m_Strength); - DDX_Control(pDX, IDC_QUALITY, m_Quality); - DDX_Control(pDX, IDC_CHANNEL_LIST, m_ChannelList); - DDX_Control(pDX, ID_START, m_btnStart); - DDX_Control(pDX, ID_SAVE, m_btnSave); - DDX_Control(pDX, IDCANCEL, m_btnCancel); - DDX_Control(pDX, IDC_OFFSET, m_OffsetEditBox); - fulfillThemeReqs(); -} - -BEGIN_MESSAGE_MAP(CTunerScanDlg, CMPCThemeDialog) - ON_MESSAGE(WM_TUNER_SCAN_PROGRESS, OnScanProgress) - ON_MESSAGE(WM_TUNER_SCAN_END, OnScanEnd) - ON_MESSAGE(WM_TUNER_STATS, OnStats) - ON_MESSAGE(WM_TUNER_NEW_CHANNEL, OnNewChannel) - ON_BN_CLICKED(ID_SAVE, &CTunerScanDlg::OnBnClickedSave) - ON_BN_CLICKED(ID_START, &CTunerScanDlg::OnBnClickedStart) - ON_BN_CLICKED(IDCANCEL, &CTunerScanDlg::OnBnClickedCancel) - ON_BN_CLICKED(IDC_CHECK_OFFSET, &CTunerScanDlg::OnBnClickedCheckOffset) -END_MESSAGE_MAP() - -// CTunerScanDlg message handlers - -void CTunerScanDlg::OnBnClickedSave() -{ - auto& DVBChannels = AfxGetAppSettings().m_DVBChannels; - const size_t maxChannelsNum = ID_NAVIGATE_JUMPTO_SUBITEM_END - ID_NAVIGATE_JUMPTO_SUBITEM_START + 1; - - for (int i = 0; i < m_ChannelList.GetItemCount(); i++) { - try { - CBDAChannel channel(m_ChannelList.GetItemText(i, TSCC_CHANNEL)); - auto it = std::find(std::begin(DVBChannels), std::end(DVBChannels), channel); - if (it != DVBChannels.end()) { - // replace existing channel - channel.SetPrefNumber(it->GetPrefNumber()); - *it = channel; - } else { - // add new channel to the end - const size_t size = DVBChannels.size(); - if (size < maxChannelsNum) { - channel.SetPrefNumber((int)size); - DVBChannels.push_back(channel); - } else { - // Just to be safe. We have 600 channels limit, but we never know what user might load there. - CString msg; - msg.Format(_T("Unable to add new channel \"%s\" to the list. Channels list is full. Please notify developers about the problem."), channel.GetName()); - AfxMessageBox(msg, MB_OK | MB_ICONERROR); - } - } - } catch (CException* e) { - // The tokenisation can fail if the input string was invalid - TRACE(_T("Failed to parse a DVB channel from string \"%s\""), m_ChannelList.GetItemText(i, TSCC_CHANNEL).GetString()); - ASSERT(FALSE); - e->Delete(); - } - } - m_pMainFrame->SetChannel(0); - - OnOK(); -} - -void CTunerScanDlg::OnBnClickedStart() -{ - if (!m_bInProgress) { - UpdateData(true); - CAutoPtr pTSD(DEBUG_NEW TunerScanData); - pTSD->Hwnd = m_hWnd; - pTSD->FrequencyStart = m_ulFrequencyStart; - pTSD->FrequencyStop = m_ulFrequencyEnd; - pTSD->Bandwidth = m_ulBandwidth; - pTSD->SymbolRate = m_ulSymbolRate; - pTSD->Offset = m_bUseOffset ? m_lOffset : 0; - SaveScanSettings(); - - m_ChannelList.DeleteAllItems(); - m_pMainFrame->StartTunerScan(pTSD); - - SetProgress(true); - } else { - m_pMainFrame->StopTunerScan(); - } -} - -void CTunerScanDlg::OnBnClickedCancel() -{ - if (m_bInProgress) { - m_pMainFrame->StopTunerScan(); - } - m_pMainFrame->SetChannel(AfxGetAppSettings().nDVBLastChannel); - - OnCancel(); -} - -void CTunerScanDlg::OnBnClickedCheckOffset() -{ - UpdateData(true); - m_OffsetEditBox.EnableWindow(m_bUseOffset); -} - -LRESULT CTunerScanDlg::OnScanProgress(WPARAM wParam, LPARAM lParam) -{ - m_Progress.SetPos(static_cast(wParam)); - return TRUE; -} - -LRESULT CTunerScanDlg::OnScanEnd(WPARAM wParam, LPARAM lParam) -{ - SetProgress(false); - return TRUE; -} - -LRESULT CTunerScanDlg::OnStats(WPARAM wParam, LPARAM lParam) -{ - m_Strength.SetPos((int)wParam); - m_Quality.SetPos((int)lParam); - return TRUE; -} - -LRESULT CTunerScanDlg::OnNewChannel(WPARAM wParam, LPARAM lParam) -{ - try { - CBDAChannel channel((LPCTSTR)lParam); - if (!m_bIgnoreEncryptedChannels || !channel.IsEncrypted()) { - CString strTemp; - int nItem, nChannelNumber; - - if (channel.GetOriginNumber() != 0) { // LCN is available - nChannelNumber = channel.GetOriginNumber(); - // Insert new channel so that channels are sorted by their logical number - for (nItem = 0; nItem < m_ChannelList.GetItemCount(); nItem++) { - if ((int)m_ChannelList.GetItemData(nItem) > nChannelNumber || (int)m_ChannelList.GetItemData(nItem) == 0) { - break; - } - } - } else { - nChannelNumber = 0; - nItem = m_ChannelList.GetItemCount(); - } - - strTemp.Format(_T("%d"), nChannelNumber); - nItem = m_ChannelList.InsertItem(nItem, strTemp); - - m_ChannelList.SetItemData(nItem, channel.GetOriginNumber()); - - m_ChannelList.SetItemText(nItem, TSCC_NAME, channel.GetName()); - - strTemp.Format(_T("%lu"), channel.GetFrequency()); - m_ChannelList.SetItemText(nItem, TSCC_FREQUENCY, strTemp); - - m_ChannelList.SetItemText(nItem, TSCC_ENCRYPTED, ResStr(channel.IsEncrypted() ? IDS_YES : IDS_NO)); - if (channel.GetVideoType() == BDA_H264) { - strTemp = _T("H.264"); - } else if (channel.GetVideoType() == BDA_HEVC) { - strTemp = _T("HEVC"); - } else if (channel.GetVideoPID()) { - strTemp = _T("MPEG-2"); - } else { - strTemp = _T("-"); - } - m_ChannelList.SetItemText(nItem, TSCC_VIDEO_FORMAT, strTemp); - strTemp = channel.GetVideoFpsDesc(); - m_ChannelList.SetItemText(nItem, TSCC_VIDEO_FPS, strTemp); - if (channel.GetVideoWidth() || channel.GetVideoHeight()) { - strTemp.Format(_T("%lux%lu"), channel.GetVideoWidth(), channel.GetVideoHeight()); - } else { - strTemp = _T("-"); - } - m_ChannelList.SetItemText(nItem, TSCC_VIDEO_RES, strTemp); - strTemp.Format(_T("%lu/%lu"), channel.GetVideoARy(), channel.GetVideoARx()); - m_ChannelList.SetItemText(nItem, TSCC_VIDEO_AR, strTemp); - m_ChannelList.SetItemText(nItem, TSCC_CHANNEL, (LPCTSTR) lParam); - } - } catch (CException* e) { - // The tokenisation can fail if the input string was invalid - TRACE(_T("Failed to parse a DVB channel from string \"%s\""), (LPCTSTR)lParam); - ASSERT(FALSE); - e->Delete(); - return FALSE; - } - - return TRUE; -} - -void CTunerScanDlg::SetProgress(bool bState) -{ - if (bState) { - m_btnStart.SetWindowTextW(ResStr(IDS_DVB_CHANNEL_STOP_SCAN)); - m_btnSave.EnableWindow(FALSE); - } else { - m_btnStart.SetWindowTextW(ResStr(IDS_DVB_CHANNEL_START_SCAN)); - m_Progress.SetPos(0); - m_btnSave.EnableWindow(TRUE); - } - - m_bInProgress = bState; -} - -void CTunerScanDlg::SaveScanSettings() -{ - CAppSettings& s = AfxGetAppSettings(); - - s.iBDAScanFreqStart = m_ulFrequencyStart; - s.iBDAScanFreqEnd = m_ulFrequencyEnd; - div_t bdw = div(m_ulBandwidth, 1000); - s.iBDABandwidth = bdw.quot; - s.iBDASymbolRate = m_ulSymbolRate; - s.fBDAUseOffset = !!m_bUseOffset; - s.iBDAOffset = m_lOffset; - s.fBDAIgnoreEncryptedChannels = !!m_bIgnoreEncryptedChannels; -} +/* + * (C) 2009-2017 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 . + * + */ + +// TunerScanDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "mplayerc.h" +#include "MainFrm.h" +#include "TunerScanDlg.h" +#include "DVBChannel.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" + + +enum TSC_COLUMN { + TSCC_NUMBER, + TSCC_NAME, + TSCC_FREQUENCY, + TSCC_ENCRYPTED, + TSCC_VIDEO_FORMAT, + TSCC_VIDEO_FPS, + TSCC_VIDEO_RES, + TSCC_VIDEO_AR, + TSCC_CHANNEL +}; + +// CTunerScanDlg dialog + +IMPLEMENT_DYNAMIC(CTunerScanDlg, CMPCThemeDialog) + +CTunerScanDlg::CTunerScanDlg(CMainFrame* pMainFrame) + : CMPCThemeDialog(CTunerScanDlg::IDD, pMainFrame) + , m_pMainFrame(pMainFrame) + , m_bInProgress(false) +{ + const CAppSettings& s = AfxGetAppSettings(); + + m_ulFrequencyStart = s.iBDAScanFreqStart; + m_ulFrequencyEnd = s.iBDAScanFreqEnd; + m_ulBandwidth = s.iBDABandwidth * 1000; + m_ulSymbolRate = s.iBDASymbolRate; + m_bUseOffset = s.fBDAUseOffset; + m_lOffset = s.iBDAOffset; + m_bIgnoreEncryptedChannels = s.fBDAIgnoreEncryptedChannels; +} + +CTunerScanDlg::~CTunerScanDlg() +{ +} + +BOOL CTunerScanDlg::OnInitDialog() +{ + CMPCThemeDialog::OnInitDialog(); + + m_OffsetEditBox.EnableWindow(m_bUseOffset); + + m_ChannelList.InsertColumn(TSCC_NUMBER, ResStr(IDS_DVB_CHANNEL_NUMBER), LVCFMT_LEFT, 35); + m_ChannelList.InsertColumn(TSCC_NAME, ResStr(IDS_DVB_CHANNEL_NAME), LVCFMT_LEFT, 190); + m_ChannelList.InsertColumn(TSCC_FREQUENCY, ResStr(IDS_DVB_CHANNEL_FREQUENCY), LVCFMT_LEFT, 65); + m_ChannelList.InsertColumn(TSCC_ENCRYPTED, ResStr(IDS_DVB_CHANNEL_ENCRYPTION), LVCFMT_CENTER, 55); + m_ChannelList.InsertColumn(TSCC_VIDEO_FORMAT, ResStr(IDS_DVB_CHANNEL_FORMAT), LVCFMT_CENTER, 55); + m_ChannelList.InsertColumn(TSCC_VIDEO_FPS, ResStr(IDS_DVB_CHANNEL_FPS), LVCFMT_CENTER, 50); + m_ChannelList.InsertColumn(TSCC_VIDEO_RES, ResStr(IDS_DVB_CHANNEL_RESOLUTION), LVCFMT_CENTER, 70); + m_ChannelList.InsertColumn(TSCC_VIDEO_AR, ResStr(IDS_DVB_CHANNEL_ASPECT_RATIO), LVCFMT_CENTER, 50); + m_ChannelList.InsertColumn(TSCC_CHANNEL, _T("Channel"), LVCFMT_LEFT, 0); + + m_Progress.SetRange(0, 100); + CMPCThemeUtil::fulfillThemeReqs(&m_Progress); + m_Strength.SetRange(0, 100); + CMPCThemeUtil::fulfillThemeReqs(&m_Strength); + m_Quality.SetRange(0, 100); + CMPCThemeUtil::fulfillThemeReqs(&m_Quality); + + m_btnSave.EnableWindow(FALSE); + + return TRUE; +} + +void CTunerScanDlg::DoDataExchange(CDataExchange* pDX) +{ + CMPCThemeDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_FREQ_START, m_ulFrequencyStart); + DDX_Text(pDX, IDC_FREQ_END, m_ulFrequencyEnd); + DDX_Text(pDX, IDC_BANDWIDTH, m_ulBandwidth); + DDX_Text(pDX, IDC_SYMBOLRATE, m_ulSymbolRate); + DDX_Text(pDX, IDC_OFFSET, m_lOffset); + DDX_Check(pDX, IDC_CHECK_OFFSET, m_bUseOffset); + DDX_Check(pDX, IDC_CHECK_IGNORE_ENCRYPTED, m_bIgnoreEncryptedChannels); + DDX_Control(pDX, IDC_PROGRESS, m_Progress); + DDX_Control(pDX, IDC_STRENGTH, m_Strength); + DDX_Control(pDX, IDC_QUALITY, m_Quality); + DDX_Control(pDX, IDC_CHANNEL_LIST, m_ChannelList); + DDX_Control(pDX, ID_START, m_btnStart); + DDX_Control(pDX, ID_SAVE, m_btnSave); + DDX_Control(pDX, IDCANCEL, m_btnCancel); + DDX_Control(pDX, IDC_OFFSET, m_OffsetEditBox); + fulfillThemeReqs(); +} + +BEGIN_MESSAGE_MAP(CTunerScanDlg, CMPCThemeDialog) + ON_MESSAGE(WM_TUNER_SCAN_PROGRESS, OnScanProgress) + ON_MESSAGE(WM_TUNER_SCAN_END, OnScanEnd) + ON_MESSAGE(WM_TUNER_STATS, OnStats) + ON_MESSAGE(WM_TUNER_NEW_CHANNEL, OnNewChannel) + ON_BN_CLICKED(ID_SAVE, &CTunerScanDlg::OnBnClickedSave) + ON_BN_CLICKED(ID_START, &CTunerScanDlg::OnBnClickedStart) + ON_BN_CLICKED(IDCANCEL, &CTunerScanDlg::OnBnClickedCancel) + ON_BN_CLICKED(IDC_CHECK_OFFSET, &CTunerScanDlg::OnBnClickedCheckOffset) +END_MESSAGE_MAP() + +// CTunerScanDlg message handlers + +void CTunerScanDlg::OnBnClickedSave() +{ + auto& DVBChannels = AfxGetAppSettings().m_DVBChannels; + const size_t maxChannelsNum = ID_NAVIGATE_JUMPTO_SUBITEM_END - ID_NAVIGATE_JUMPTO_SUBITEM_START + 1; + + for (int i = 0; i < m_ChannelList.GetItemCount(); i++) { + try { + CBDAChannel channel(m_ChannelList.GetItemText(i, TSCC_CHANNEL)); + auto it = std::find(std::begin(DVBChannels), std::end(DVBChannels), channel); + if (it != DVBChannels.end()) { + // replace existing channel + channel.SetPrefNumber(it->GetPrefNumber()); + *it = channel; + } else { + // add new channel to the end + const size_t size = DVBChannels.size(); + if (size < maxChannelsNum) { + channel.SetPrefNumber((int)size); + DVBChannels.push_back(channel); + } else { + // Just to be safe. We have 600 channels limit, but we never know what user might load there. + CString msg; + msg.Format(_T("Unable to add new channel \"%s\" to the list. Channels list is full. Please notify developers about the problem."), channel.GetName()); + AfxMessageBox(msg, MB_OK | MB_ICONERROR); + } + } + } catch (CException* e) { + // The tokenisation can fail if the input string was invalid + TRACE(_T("Failed to parse a DVB channel from string \"%s\""), m_ChannelList.GetItemText(i, TSCC_CHANNEL).GetString()); + ASSERT(FALSE); + e->Delete(); + } + } + m_pMainFrame->SetChannel(0); + + OnOK(); +} + +void CTunerScanDlg::OnBnClickedStart() +{ + if (!m_bInProgress) { + UpdateData(true); + CAutoPtr pTSD(DEBUG_NEW TunerScanData); + pTSD->Hwnd = m_hWnd; + pTSD->FrequencyStart = m_ulFrequencyStart; + pTSD->FrequencyStop = m_ulFrequencyEnd; + pTSD->Bandwidth = m_ulBandwidth; + pTSD->SymbolRate = m_ulSymbolRate; + pTSD->Offset = m_bUseOffset ? m_lOffset : 0; + SaveScanSettings(); + + m_ChannelList.DeleteAllItems(); + m_pMainFrame->StartTunerScan(pTSD); + + SetProgress(true); + } else { + m_pMainFrame->StopTunerScan(); + } +} + +void CTunerScanDlg::OnBnClickedCancel() +{ + if (m_bInProgress) { + m_pMainFrame->StopTunerScan(); + } + m_pMainFrame->SetChannel(AfxGetAppSettings().nDVBLastChannel); + + OnCancel(); +} + +void CTunerScanDlg::OnBnClickedCheckOffset() +{ + UpdateData(true); + m_OffsetEditBox.EnableWindow(m_bUseOffset); +} + +LRESULT CTunerScanDlg::OnScanProgress(WPARAM wParam, LPARAM lParam) +{ + m_Progress.SetPos(static_cast(wParam)); + return TRUE; +} + +LRESULT CTunerScanDlg::OnScanEnd(WPARAM wParam, LPARAM lParam) +{ + SetProgress(false); + return TRUE; +} + +LRESULT CTunerScanDlg::OnStats(WPARAM wParam, LPARAM lParam) +{ + m_Strength.SetPos((int)wParam); + m_Quality.SetPos((int)lParam); + return TRUE; +} + +LRESULT CTunerScanDlg::OnNewChannel(WPARAM wParam, LPARAM lParam) +{ + try { + CBDAChannel channel((LPCTSTR)lParam); + if (!m_bIgnoreEncryptedChannels || !channel.IsEncrypted()) { + CString strTemp; + int nItem, nChannelNumber; + + if (channel.GetOriginNumber() != 0) { // LCN is available + nChannelNumber = channel.GetOriginNumber(); + // Insert new channel so that channels are sorted by their logical number + for (nItem = 0; nItem < m_ChannelList.GetItemCount(); nItem++) { + if ((int)m_ChannelList.GetItemData(nItem) > nChannelNumber || (int)m_ChannelList.GetItemData(nItem) == 0) { + break; + } + } + } else { + nChannelNumber = 0; + nItem = m_ChannelList.GetItemCount(); + } + + strTemp.Format(_T("%d"), nChannelNumber); + nItem = m_ChannelList.InsertItem(nItem, strTemp); + + m_ChannelList.SetItemData(nItem, channel.GetOriginNumber()); + + m_ChannelList.SetItemText(nItem, TSCC_NAME, channel.GetName()); + + strTemp.Format(_T("%lu"), channel.GetFrequency()); + m_ChannelList.SetItemText(nItem, TSCC_FREQUENCY, strTemp); + + m_ChannelList.SetItemText(nItem, TSCC_ENCRYPTED, ResStr(channel.IsEncrypted() ? IDS_YES : IDS_NO)); + if (channel.GetVideoType() == BDA_H264) { + strTemp = _T("H.264"); + } else if (channel.GetVideoType() == BDA_HEVC) { + strTemp = _T("HEVC"); + } else if (channel.GetVideoPID()) { + strTemp = _T("MPEG-2"); + } else { + strTemp = _T("-"); + } + m_ChannelList.SetItemText(nItem, TSCC_VIDEO_FORMAT, strTemp); + strTemp = channel.GetVideoFpsDesc(); + m_ChannelList.SetItemText(nItem, TSCC_VIDEO_FPS, strTemp); + if (channel.GetVideoWidth() || channel.GetVideoHeight()) { + strTemp.Format(_T("%lux%lu"), channel.GetVideoWidth(), channel.GetVideoHeight()); + } else { + strTemp = _T("-"); + } + m_ChannelList.SetItemText(nItem, TSCC_VIDEO_RES, strTemp); + strTemp.Format(_T("%lu/%lu"), channel.GetVideoARy(), channel.GetVideoARx()); + m_ChannelList.SetItemText(nItem, TSCC_VIDEO_AR, strTemp); + m_ChannelList.SetItemText(nItem, TSCC_CHANNEL, (LPCTSTR) lParam); + } + } catch (CException* e) { + // The tokenisation can fail if the input string was invalid + TRACE(_T("Failed to parse a DVB channel from string \"%s\""), (LPCTSTR)lParam); + ASSERT(FALSE); + e->Delete(); + return FALSE; + } + + return TRUE; +} + +void CTunerScanDlg::SetProgress(bool bState) +{ + if (bState) { + m_btnStart.SetWindowTextW(ResStr(IDS_DVB_CHANNEL_STOP_SCAN)); + m_btnSave.EnableWindow(FALSE); + } else { + m_btnStart.SetWindowTextW(ResStr(IDS_DVB_CHANNEL_START_SCAN)); + m_Progress.SetPos(0); + m_btnSave.EnableWindow(TRUE); + } + + m_bInProgress = bState; +} + +void CTunerScanDlg::SaveScanSettings() +{ + CAppSettings& s = AfxGetAppSettings(); + + s.iBDAScanFreqStart = m_ulFrequencyStart; + s.iBDAScanFreqEnd = m_ulFrequencyEnd; + div_t bdw = div(m_ulBandwidth, 1000); + s.iBDABandwidth = bdw.quot; + s.iBDASymbolRate = m_ulSymbolRate; + s.fBDAUseOffset = !!m_bUseOffset; + s.iBDAOffset = m_lOffset; + s.fBDAIgnoreEncryptedChannels = !!m_bIgnoreEncryptedChannels; +} diff --git a/src/mpc-hc/TunerScanDlg.h b/src/mpc-hc/TunerScanDlg.h index 8363f8bfb6e..08a649b5d45 100644 --- a/src/mpc-hc/TunerScanDlg.h +++ b/src/mpc-hc/TunerScanDlg.h @@ -1,80 +1,80 @@ -/* - * (C) 2009-2014 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 . - * - */ - -#pragma once - -#include -#include -#include "CMPCThemeDialog.h" -#include "CMPCThemeEdit.h" -#include "CMPCThemePlayerListCtrl.h" -#include "CMPCThemeButton.h" - - -// CTunerScanDlg dialog - -class CTunerScanDlg : public CMPCThemeDialog -{ - CMainFrame* m_pMainFrame; - - DECLARE_DYNAMIC(CTunerScanDlg) - -public: - CTunerScanDlg(CMainFrame* pMainFrame); // standard constructor - virtual ~CTunerScanDlg(); - - // Dialog Data - enum { IDD = IDD_TUNER_SCAN }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - void SetProgress(bool bState); - void SaveScanSettings(); - - DECLARE_MESSAGE_MAP() -public: - ULONG m_ulFrequencyStart; - ULONG m_ulFrequencyEnd; - ULONG m_ulBandwidth; - ULONG m_ulSymbolRate; - LONG m_lOffset; - CMPCThemeEdit m_OffsetEditBox; - BOOL m_bUseOffset; - BOOL m_bIgnoreEncryptedChannels; - CProgressCtrl m_Progress; - CProgressCtrl m_Strength; - CProgressCtrl m_Quality; - CMPCThemePlayerListCtrl m_ChannelList; - bool m_bInProgress; - - afx_msg LRESULT OnScanProgress(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnScanEnd(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnStats(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnNewChannel(WPARAM wParam, LPARAM lParam); - - afx_msg void OnBnClickedCheckOffset(); - afx_msg void OnBnClickedSave(); - afx_msg void OnBnClickedStart(); - afx_msg void OnBnClickedCancel(); - virtual BOOL OnInitDialog(); - CMPCThemeButton m_btnStart; - CMPCThemeButton m_btnSave; - CMPCThemeButton m_btnCancel; -}; +/* + * (C) 2009-2014 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 . + * + */ + +#pragma once + +#include +#include +#include "CMPCThemeDialog.h" +#include "CMPCThemeEdit.h" +#include "CMPCThemePlayerListCtrl.h" +#include "CMPCThemeButton.h" + + +// CTunerScanDlg dialog + +class CTunerScanDlg : public CMPCThemeDialog +{ + CMainFrame* m_pMainFrame; + + DECLARE_DYNAMIC(CTunerScanDlg) + +public: + CTunerScanDlg(CMainFrame* pMainFrame); // standard constructor + virtual ~CTunerScanDlg(); + + // Dialog Data + enum { IDD = IDD_TUNER_SCAN }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + void SetProgress(bool bState); + void SaveScanSettings(); + + DECLARE_MESSAGE_MAP() +public: + ULONG m_ulFrequencyStart; + ULONG m_ulFrequencyEnd; + ULONG m_ulBandwidth; + ULONG m_ulSymbolRate; + LONG m_lOffset; + CMPCThemeEdit m_OffsetEditBox; + BOOL m_bUseOffset; + BOOL m_bIgnoreEncryptedChannels; + CProgressCtrl m_Progress; + CProgressCtrl m_Strength; + CProgressCtrl m_Quality; + CMPCThemePlayerListCtrl m_ChannelList; + bool m_bInProgress; + + afx_msg LRESULT OnScanProgress(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnScanEnd(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnStats(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnNewChannel(WPARAM wParam, LPARAM lParam); + + afx_msg void OnBnClickedCheckOffset(); + afx_msg void OnBnClickedSave(); + afx_msg void OnBnClickedStart(); + afx_msg void OnBnClickedCancel(); + virtual BOOL OnInitDialog(); + CMPCThemeButton m_btnStart; + CMPCThemeButton m_btnSave; + CMPCThemeButton m_btnCancel; +}; diff --git a/src/mpc-hc/UpdateChecker.cpp b/src/mpc-hc/UpdateChecker.cpp index 1ce0e123928..7d963fbc0f8 100644 --- a/src/mpc-hc/UpdateChecker.cpp +++ b/src/mpc-hc/UpdateChecker.cpp @@ -1,288 +1,288 @@ -/* - * (C) 2012-2014, 2017 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 . - * - */ - - -#include "stdafx.h" -#include "mpc-hc_config.h" -#include "VersionInfo.h" -#include "UpdateChecker.h" -#include "UpdateCheckerDlg.h" -#include "SettingsDefines.h" -#include "mplayerc.h" -#include "AppSettings.h" - -#include - -const Version UpdateChecker::MPC_HC_VERSION = { - VersionInfo::GetMajorNumber(), - VersionInfo::GetMinorNumber(), - VersionInfo::GetPatchNumber(), - VersionInfo::GetRevisionNumber() -}; -const LPCTSTR UpdateChecker::MPC_HC_UPDATE_URL = UPDATE_URL; - -bool UpdateChecker::bIsCheckingForUpdate = false; -CCritSec UpdateChecker::csIsCheckingForUpdate; - -UpdateChecker::UpdateChecker(CString versionFileURL) - : versionFileURL(versionFileURL) - , latestVersion() -{ -} - -UpdateChecker::~UpdateChecker() -{ -} - -Update_Status UpdateChecker::IsUpdateAvailable(const Version& currentVersion) -{ - Update_Status update_status = IsUpdateAvailable(currentVersion, false); - if (update_status == UPDATER_ERROR) update_status = IsUpdateAvailable(currentVersion, true); - return update_status; -} - -Update_Status UpdateChecker::IsUpdateAvailable(const Version& currentVersion, bool useBackupURL) -{ - Update_Status updateAvailable = UPDATER_LATEST_STABLE; - - try { - CInternetSession internet; - -#pragma warning(push) -#pragma warning(disable: 4996) - OSVERSIONINFOEX osVersion = { sizeof(OSVERSIONINFOEX) }; - GetVersionEx(reinterpret_cast(&osVersion)); -#pragma warning(pop) - CString osVersionStr; - osVersionStr.Format(_T("Windows %1u.%1u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion); - -#if !defined(_WIN64) - // 32-bit programs run on both 32-bit and 64-bit Windows - // so must sniff - BOOL f64 = FALSE; - if (IsWow64Process(GetCurrentProcess(), &f64) && f64) -#endif - { - osVersionStr += _T(" x64"); - } - - CString headersFmt = _T("User-Agent: MPC-HC"); - if (VersionInfo::Is64Bit()) { - headersFmt += _T(" (64-bit)"); - } -#ifdef MPCHC_LITE - headersFmt += _T(" Lite"); -#endif - headersFmt += _T(" (%s)/"); - headersFmt += VersionInfo::GetFullVersionString(); - headersFmt += _T("\r\n"); - - CString headers; - headers.Format(headersFmt, osVersionStr.GetString()); - - CString fileURL; - if (useBackupURL) fileURL = BACKUP_UPDATE_URL; - else fileURL = versionFileURL; - - CHttpFile* versionFile = (CHttpFile*) internet.OpenURL(fileURL, - 1, - INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, - headers, - DWORD(-1)); - - if (versionFile) { - CString latestVersionStr; - char buffer[101]; - UINT br = 0; - - while ((br = versionFile->Read(buffer, 50)) > 0) { - buffer[br] = '\0'; - latestVersionStr += buffer; - } - - if (!ParseVersion(latestVersionStr, latestVersion)) { - updateAvailable = UPDATER_ERROR; - } else { - time_t lastCheck = time(nullptr); - AfxGetApp()->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_UPDATER_LAST_CHECK, (LPBYTE)&lastCheck, sizeof(time_t)); - - int comp = CompareVersion(currentVersion, latestVersion); - - if (comp < 0) { - CString ignoredVersionStr = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_UPDATER_IGNORE_VERSION, _T("0.0.0.0")); - Version ignoredVersion; - bool ignored = false; - - if (ParseVersion(ignoredVersionStr, ignoredVersion)) { - ignored = (CompareVersion(ignoredVersion, latestVersion) >= 0); - } - - updateAvailable = ignored ? UPDATER_UPDATE_AVAILABLE_IGNORED : UPDATER_UPDATE_AVAILABLE; - } else if (comp > 0) { - updateAvailable = UPDATER_NEWER_VERSION; - } - } - - versionFile->Close(); // Close() isn't called by the destructor - delete versionFile; - } else { - updateAvailable = UPDATER_ERROR; - } - } catch (CInternetException* pEx) { - updateAvailable = UPDATER_ERROR; - pEx->Delete(); - } - - return updateAvailable; -} - -Update_Status UpdateChecker::IsUpdateAvailable() -{ - return IsUpdateAvailable(MPC_HC_VERSION); -} - -void UpdateChecker::IgnoreLatestVersion() -{ - CString ignoredVersionStr; - ignoredVersionStr.Format(_T("%u.%u.%u.%u"), latestVersion.major, latestVersion.minor, latestVersion.patch, latestVersion.revision); - - AfxGetApp()->WriteProfileString(IDS_R_SETTINGS, IDS_RS_UPDATER_IGNORE_VERSION, ignoredVersionStr); -} - -bool UpdateChecker::ParseVersion(const CString& versionStr, Version& version) -{ - bool success = false; - - if (!versionStr.IsEmpty()) { - UINT v[4]; - int curPos = 0; - UINT i = 0; - CString resToken = versionStr.Tokenize(_T("."), curPos); - - success = !resToken.IsEmpty(); - - while (!resToken.IsEmpty() && i < _countof(v) && success) { - if (1 != _stscanf_s(resToken, _T("%u"), v + i)) { - success = false; - } - - resToken = versionStr.Tokenize(_T("."), curPos); - i++; - } - - success = success && (i == _countof(v)); - - if (success) { - version.major = v[0]; - version.minor = v[1]; - version.patch = v[2]; - version.revision = v[3]; - } - } - - return success; -} - -int UpdateChecker::CompareVersion(const Version& v1, const Version& v2) -{ - if (v1.major > v2.major) { - return 1; - } else if (v1.major < v2.major) { - return -1; - } else if (v1.minor > v2.minor) { - return 1; - } else if (v1.minor < v2.minor) { - return -1; - } else if (v1.patch > v2.patch) { - return 1; - } else if (v1.patch < v2.patch) { - return -1; - } else if (v1.revision > v2.revision) { - return 1; - } else if (v1.revision < v2.revision) { - return -1; - } else { - return 0; - } -} - -bool UpdateChecker::IsAutoUpdateEnabled() -{ - int& status = AfxGetAppSettings().nUpdaterAutoCheck; - - if (status == AUTOUPDATE_UNKNOWN) { // First run - status = (AfxMessageBox(IDS_UPDATE_CONFIG_AUTO_CHECK, MB_ICONQUESTION | MB_YESNO, 0) == IDYES) ? AUTOUPDATE_ENABLE : AUTOUPDATE_DISABLE; - } - - return (status == AUTOUPDATE_ENABLE); -} - -bool UpdateChecker::IsTimeToAutoUpdate() -{ - time_t* lastCheck = nullptr; - UINT nRead; - - if (!AfxGetApp()->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_UPDATER_LAST_CHECK, (LPBYTE*)&lastCheck, &nRead) || nRead != sizeof(time_t)) { - if (lastCheck) { - delete [] lastCheck; - } - - return true; - } - - bool isTimeToAutoUpdate = (time(nullptr) >= *lastCheck + AfxGetAppSettings().nUpdaterDelay * 24 * 3600); - - delete [] lastCheck; - - return isTimeToAutoUpdate; -} - -static UINT RunCheckForUpdateThread(LPVOID pParam) -{ - bool autoCheck = !!pParam; - - if (!autoCheck || UpdateChecker::IsTimeToAutoUpdate()) { - UpdateChecker updateChecker(UpdateChecker::MPC_HC_UPDATE_URL); - - Update_Status status = updateChecker.IsUpdateAvailable(); - - if (!autoCheck || status == UPDATER_UPDATE_AVAILABLE) { - UpdateCheckerDlg dlg(status, updateChecker.GetLatestVersion()); - - if (dlg.DoModal() == IDC_UPDATE_IGNORE_BUTTON) { - updateChecker.IgnoreLatestVersion(); - } - } - } - - UpdateChecker::bIsCheckingForUpdate = false; - - return 0; -} - -void UpdateChecker::CheckForUpdate(bool autoCheck /*= false*/) -{ - CAutoLock lock(&csIsCheckingForUpdate); - - if (!bIsCheckingForUpdate) { - bIsCheckingForUpdate = true; - AfxBeginThread(RunCheckForUpdateThread, (LPVOID)autoCheck); - } -} +/* + * (C) 2012-2014, 2017 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 . + * + */ + + +#include "stdafx.h" +#include "mpc-hc_config.h" +#include "VersionInfo.h" +#include "UpdateChecker.h" +#include "UpdateCheckerDlg.h" +#include "SettingsDefines.h" +#include "mplayerc.h" +#include "AppSettings.h" + +#include + +const Version UpdateChecker::MPC_HC_VERSION = { + VersionInfo::GetMajorNumber(), + VersionInfo::GetMinorNumber(), + VersionInfo::GetPatchNumber(), + VersionInfo::GetRevisionNumber() +}; +const LPCTSTR UpdateChecker::MPC_HC_UPDATE_URL = UPDATE_URL; + +bool UpdateChecker::bIsCheckingForUpdate = false; +CCritSec UpdateChecker::csIsCheckingForUpdate; + +UpdateChecker::UpdateChecker(CString versionFileURL) + : versionFileURL(versionFileURL) + , latestVersion() +{ +} + +UpdateChecker::~UpdateChecker() +{ +} + +Update_Status UpdateChecker::IsUpdateAvailable(const Version& currentVersion) +{ + Update_Status update_status = IsUpdateAvailable(currentVersion, false); + if (update_status == UPDATER_ERROR) update_status = IsUpdateAvailable(currentVersion, true); + return update_status; +} + +Update_Status UpdateChecker::IsUpdateAvailable(const Version& currentVersion, bool useBackupURL) +{ + Update_Status updateAvailable = UPDATER_LATEST_STABLE; + + try { + CInternetSession internet; + +#pragma warning(push) +#pragma warning(disable: 4996) + OSVERSIONINFOEX osVersion = { sizeof(OSVERSIONINFOEX) }; + GetVersionEx(reinterpret_cast(&osVersion)); +#pragma warning(pop) + CString osVersionStr; + osVersionStr.Format(_T("Windows %1u.%1u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion); + +#if !defined(_WIN64) + // 32-bit programs run on both 32-bit and 64-bit Windows + // so must sniff + BOOL f64 = FALSE; + if (IsWow64Process(GetCurrentProcess(), &f64) && f64) +#endif + { + osVersionStr += _T(" x64"); + } + + CString headersFmt = _T("User-Agent: MPC-HC"); + if (VersionInfo::Is64Bit()) { + headersFmt += _T(" (64-bit)"); + } +#ifdef MPCHC_LITE + headersFmt += _T(" Lite"); +#endif + headersFmt += _T(" (%s)/"); + headersFmt += VersionInfo::GetFullVersionString(); + headersFmt += _T("\r\n"); + + CString headers; + headers.Format(headersFmt, osVersionStr.GetString()); + + CString fileURL; + if (useBackupURL) fileURL = BACKUP_UPDATE_URL; + else fileURL = versionFileURL; + + CHttpFile* versionFile = (CHttpFile*) internet.OpenURL(fileURL, + 1, + INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, + headers, + DWORD(-1)); + + if (versionFile) { + CString latestVersionStr; + char buffer[101]; + UINT br = 0; + + while ((br = versionFile->Read(buffer, 50)) > 0) { + buffer[br] = '\0'; + latestVersionStr += buffer; + } + + if (!ParseVersion(latestVersionStr, latestVersion)) { + updateAvailable = UPDATER_ERROR; + } else { + time_t lastCheck = time(nullptr); + AfxGetApp()->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_UPDATER_LAST_CHECK, (LPBYTE)&lastCheck, sizeof(time_t)); + + int comp = CompareVersion(currentVersion, latestVersion); + + if (comp < 0) { + CString ignoredVersionStr = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_UPDATER_IGNORE_VERSION, _T("0.0.0.0")); + Version ignoredVersion; + bool ignored = false; + + if (ParseVersion(ignoredVersionStr, ignoredVersion)) { + ignored = (CompareVersion(ignoredVersion, latestVersion) >= 0); + } + + updateAvailable = ignored ? UPDATER_UPDATE_AVAILABLE_IGNORED : UPDATER_UPDATE_AVAILABLE; + } else if (comp > 0) { + updateAvailable = UPDATER_NEWER_VERSION; + } + } + + versionFile->Close(); // Close() isn't called by the destructor + delete versionFile; + } else { + updateAvailable = UPDATER_ERROR; + } + } catch (CInternetException* pEx) { + updateAvailable = UPDATER_ERROR; + pEx->Delete(); + } + + return updateAvailable; +} + +Update_Status UpdateChecker::IsUpdateAvailable() +{ + return IsUpdateAvailable(MPC_HC_VERSION); +} + +void UpdateChecker::IgnoreLatestVersion() +{ + CString ignoredVersionStr; + ignoredVersionStr.Format(_T("%u.%u.%u.%u"), latestVersion.major, latestVersion.minor, latestVersion.patch, latestVersion.revision); + + AfxGetApp()->WriteProfileString(IDS_R_SETTINGS, IDS_RS_UPDATER_IGNORE_VERSION, ignoredVersionStr); +} + +bool UpdateChecker::ParseVersion(const CString& versionStr, Version& version) +{ + bool success = false; + + if (!versionStr.IsEmpty()) { + UINT v[4]; + int curPos = 0; + UINT i = 0; + CString resToken = versionStr.Tokenize(_T("."), curPos); + + success = !resToken.IsEmpty(); + + while (!resToken.IsEmpty() && i < _countof(v) && success) { + if (1 != _stscanf_s(resToken, _T("%u"), v + i)) { + success = false; + } + + resToken = versionStr.Tokenize(_T("."), curPos); + i++; + } + + success = success && (i == _countof(v)); + + if (success) { + version.major = v[0]; + version.minor = v[1]; + version.patch = v[2]; + version.revision = v[3]; + } + } + + return success; +} + +int UpdateChecker::CompareVersion(const Version& v1, const Version& v2) +{ + if (v1.major > v2.major) { + return 1; + } else if (v1.major < v2.major) { + return -1; + } else if (v1.minor > v2.minor) { + return 1; + } else if (v1.minor < v2.minor) { + return -1; + } else if (v1.patch > v2.patch) { + return 1; + } else if (v1.patch < v2.patch) { + return -1; + } else if (v1.revision > v2.revision) { + return 1; + } else if (v1.revision < v2.revision) { + return -1; + } else { + return 0; + } +} + +bool UpdateChecker::IsAutoUpdateEnabled() +{ + int& status = AfxGetAppSettings().nUpdaterAutoCheck; + + if (status == AUTOUPDATE_UNKNOWN) { // First run + status = (AfxMessageBox(IDS_UPDATE_CONFIG_AUTO_CHECK, MB_ICONQUESTION | MB_YESNO, 0) == IDYES) ? AUTOUPDATE_ENABLE : AUTOUPDATE_DISABLE; + } + + return (status == AUTOUPDATE_ENABLE); +} + +bool UpdateChecker::IsTimeToAutoUpdate() +{ + time_t* lastCheck = nullptr; + UINT nRead; + + if (!AfxGetApp()->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_UPDATER_LAST_CHECK, (LPBYTE*)&lastCheck, &nRead) || nRead != sizeof(time_t)) { + if (lastCheck) { + delete [] lastCheck; + } + + return true; + } + + bool isTimeToAutoUpdate = (time(nullptr) >= *lastCheck + AfxGetAppSettings().nUpdaterDelay * 24 * 3600); + + delete [] lastCheck; + + return isTimeToAutoUpdate; +} + +static UINT RunCheckForUpdateThread(LPVOID pParam) +{ + bool autoCheck = !!pParam; + + if (!autoCheck || UpdateChecker::IsTimeToAutoUpdate()) { + UpdateChecker updateChecker(UpdateChecker::MPC_HC_UPDATE_URL); + + Update_Status status = updateChecker.IsUpdateAvailable(); + + if (!autoCheck || status == UPDATER_UPDATE_AVAILABLE) { + UpdateCheckerDlg dlg(status, updateChecker.GetLatestVersion()); + + if (dlg.DoModal() == IDC_UPDATE_IGNORE_BUTTON) { + updateChecker.IgnoreLatestVersion(); + } + } + } + + UpdateChecker::bIsCheckingForUpdate = false; + + return 0; +} + +void UpdateChecker::CheckForUpdate(bool autoCheck /*= false*/) +{ + CAutoLock lock(&csIsCheckingForUpdate); + + if (!bIsCheckingForUpdate) { + bIsCheckingForUpdate = true; + AfxBeginThread(RunCheckForUpdateThread, (LPVOID)autoCheck); + } +} diff --git a/src/mpc-hc/UpdateChecker.h b/src/mpc-hc/UpdateChecker.h index fc10d8abf3f..f0e4f10672e 100644 --- a/src/mpc-hc/UpdateChecker.h +++ b/src/mpc-hc/UpdateChecker.h @@ -1,87 +1,87 @@ -/* - * (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 . - * - */ - -#pragma once - -#include - -struct Version { - UINT major; - UINT minor; - UINT patch; - UINT revision; - - CString ToString() const { - CString versionStr; - - versionStr.Format(_T("%u.%u.%u"), major, minor, patch); - if (revision) { - versionStr.AppendFormat(_T(".%u"), revision); - } - - return versionStr; - } -}; - -enum Update_Status { - UPDATER_ERROR = -1, - UPDATER_LATEST_STABLE, - UPDATER_NEWER_VERSION, - UPDATER_UPDATE_AVAILABLE, - UPDATER_UPDATE_AVAILABLE_IGNORED -}; - -enum AutoUpdate_Status { - AUTOUPDATE_UNKNOWN = -1, - AUTOUPDATE_DISABLE, - AUTOUPDATE_ENABLE -}; - -class UpdateChecker -{ -public: - static const Version MPC_HC_VERSION; - static const LPCTSTR MPC_HC_UPDATE_URL; - - UpdateChecker(CString versionFileURL); - ~UpdateChecker(); - - Update_Status IsUpdateAvailable(const Version& currentVersion, bool useBackupURL); - Update_Status IsUpdateAvailable(const Version& currentVersion); - Update_Status IsUpdateAvailable(); - const Version& GetLatestVersion() const { return latestVersion; }; - void IgnoreLatestVersion(); - - static bool IsAutoUpdateEnabled(); - static bool IsTimeToAutoUpdate(); - static void CheckForUpdate(bool autoCheck = false); - -private: - static bool bIsCheckingForUpdate; - static CCritSec csIsCheckingForUpdate; - - CString versionFileURL; - Version latestVersion; - - static bool ParseVersion(const CString& versionStr, Version& version); - static int CompareVersion(const Version& v1, const Version& v2); - - friend static UINT RunCheckForUpdateThread(LPVOID pParam); -}; +/* + * (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 . + * + */ + +#pragma once + +#include + +struct Version { + UINT major; + UINT minor; + UINT patch; + UINT revision; + + CString ToString() const { + CString versionStr; + + versionStr.Format(_T("%u.%u.%u"), major, minor, patch); + if (revision) { + versionStr.AppendFormat(_T(".%u"), revision); + } + + return versionStr; + } +}; + +enum Update_Status { + UPDATER_ERROR = -1, + UPDATER_LATEST_STABLE, + UPDATER_NEWER_VERSION, + UPDATER_UPDATE_AVAILABLE, + UPDATER_UPDATE_AVAILABLE_IGNORED +}; + +enum AutoUpdate_Status { + AUTOUPDATE_UNKNOWN = -1, + AUTOUPDATE_DISABLE, + AUTOUPDATE_ENABLE +}; + +class UpdateChecker +{ +public: + static const Version MPC_HC_VERSION; + static const LPCTSTR MPC_HC_UPDATE_URL; + + UpdateChecker(CString versionFileURL); + ~UpdateChecker(); + + Update_Status IsUpdateAvailable(const Version& currentVersion, bool useBackupURL); + Update_Status IsUpdateAvailable(const Version& currentVersion); + Update_Status IsUpdateAvailable(); + const Version& GetLatestVersion() const { return latestVersion; }; + void IgnoreLatestVersion(); + + static bool IsAutoUpdateEnabled(); + static bool IsTimeToAutoUpdate(); + static void CheckForUpdate(bool autoCheck = false); + +private: + static bool bIsCheckingForUpdate; + static CCritSec csIsCheckingForUpdate; + + CString versionFileURL; + Version latestVersion; + + static bool ParseVersion(const CString& versionStr, Version& version); + static int CompareVersion(const Version& v1, const Version& v2); + + friend static UINT RunCheckForUpdateThread(LPVOID pParam); +}; diff --git a/src/mpc-hc/UpdateCheckerDlg.cpp b/src/mpc-hc/UpdateCheckerDlg.cpp index ebff3b40ab6..babbd78069a 100644 --- a/src/mpc-hc/UpdateCheckerDlg.cpp +++ b/src/mpc-hc/UpdateCheckerDlg.cpp @@ -1,132 +1,132 @@ -/* - * (C) 2012-2013, 2017 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 . - * - */ - - -#include -#include "stdafx.h" -#include "UpdateCheckerDlg.h" -#include "mpc-hc_config.h" - -IMPLEMENT_DYNAMIC(UpdateCheckerDlg, CMPCThemeDialog) - -UpdateCheckerDlg::UpdateCheckerDlg(Update_Status updateStatus, const Version& latestVersion, CWnd* pParent /*=nullptr*/) - : CMPCThemeDialog(UpdateCheckerDlg::IDD, pParent) - , m_updateStatus(updateStatus) -{ - switch (updateStatus) { - case UPDATER_UPDATE_AVAILABLE: - case UPDATER_UPDATE_AVAILABLE_IGNORED: - m_text.Format(IDS_NEW_UPDATE_AVAILABLE, - latestVersion.ToString().GetString(), - UpdateChecker::MPC_HC_VERSION.ToString().GetString()); - break; - case UPDATER_LATEST_STABLE: - m_text.LoadString(IDS_USING_LATEST_STABLE); - break; - case UPDATER_NEWER_VERSION: - m_text.Format(IDS_USING_NEWER_VERSION, - UpdateChecker::MPC_HC_VERSION.ToString().GetString(), - latestVersion.ToString().GetString()); - break; - case UPDATER_ERROR: - m_text.LoadString(IDS_UPDATE_ERROR); - break; - default: - ASSERT(0); // should never happen - } -} - -UpdateCheckerDlg::~UpdateCheckerDlg() -{ -} - -void UpdateCheckerDlg::DoDataExchange(CDataExchange* pDX) -{ - CMPCThemeDialog::DoDataExchange(pDX); - DDX_Text(pDX, IDC_UPDATE_DLG_TEXT, m_text); - DDX_Control(pDX, IDC_UPDATE_ICON, m_icon); - DDX_Control(pDX, IDC_UPDATE_DL_BUTTON, m_dlButton); - DDX_Control(pDX, IDC_UPDATE_LATER_BUTTON, m_laterButton); - DDX_Control(pDX, IDC_UPDATE_IGNORE_BUTTON, m_ignoreButton); - fulfillThemeReqs(); -} - - -BEGIN_MESSAGE_MAP(UpdateCheckerDlg, CMPCThemeDialog) - ON_BN_CLICKED(IDC_UPDATE_DL_BUTTON, OnOpenDownloadPage) - ON_BN_CLICKED(IDC_UPDATE_LATER_BUTTON, OnUpdateLater) - ON_BN_CLICKED(IDC_UPDATE_IGNORE_BUTTON, OnIgnoreUpdate) -END_MESSAGE_MAP() - -BOOL UpdateCheckerDlg::OnInitDialog() -{ - BOOL ret = __super::OnInitDialog(); - - switch (m_updateStatus) { - case UPDATER_UPDATE_AVAILABLE: - case UPDATER_UPDATE_AVAILABLE_IGNORED: - m_icon.SetIcon(LoadIcon(nullptr, IDI_QUESTION)); - break; - case UPDATER_LATEST_STABLE: - case UPDATER_NEWER_VERSION: - case UPDATER_ERROR: { - m_icon.SetIcon(LoadIcon(nullptr, (m_updateStatus == UPDATER_ERROR) ? IDI_WARNING : IDI_INFORMATION)); - m_dlButton.ShowWindow(SW_HIDE); - m_laterButton.ShowWindow(SW_HIDE); - m_ignoreButton.SetWindowText(ResStr(IDS_UPDATE_CLOSE)); - - CRect buttonRect, windowRect; - m_ignoreButton.GetWindowRect(&buttonRect); - ScreenToClient(&buttonRect); - // Reduce the button width - buttonRect.left += 30; - // Center the button - GetWindowRect(&windowRect); - buttonRect.MoveToX((windowRect.Width() - buttonRect.Width()) / 2); - m_ignoreButton.MoveWindow(&buttonRect); - - // Change the default button - SetDefID(IDC_UPDATE_IGNORE_BUTTON); - ret = FALSE; // Focus has been set explicitly - } - break; - default: - ASSERT(0); // should never happen - } - - return ret; -} - -void UpdateCheckerDlg::OnOpenDownloadPage() -{ - ShellExecute(nullptr, _T("open"), DOWNLOAD_URL, nullptr, nullptr, SW_SHOWNORMAL); - - EndDialog(IDC_UPDATE_DL_BUTTON); -} - -void UpdateCheckerDlg::OnUpdateLater() -{ - EndDialog(IDC_UPDATE_LATER_BUTTON); -} - -void UpdateCheckerDlg::OnIgnoreUpdate() -{ - EndDialog((m_updateStatus == UPDATER_UPDATE_AVAILABLE) ? IDC_UPDATE_IGNORE_BUTTON : 0); -} +/* + * (C) 2012-2013, 2017 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 . + * + */ + + +#include +#include "stdafx.h" +#include "UpdateCheckerDlg.h" +#include "mpc-hc_config.h" + +IMPLEMENT_DYNAMIC(UpdateCheckerDlg, CMPCThemeDialog) + +UpdateCheckerDlg::UpdateCheckerDlg(Update_Status updateStatus, const Version& latestVersion, CWnd* pParent /*=nullptr*/) + : CMPCThemeDialog(UpdateCheckerDlg::IDD, pParent) + , m_updateStatus(updateStatus) +{ + switch (updateStatus) { + case UPDATER_UPDATE_AVAILABLE: + case UPDATER_UPDATE_AVAILABLE_IGNORED: + m_text.Format(IDS_NEW_UPDATE_AVAILABLE, + latestVersion.ToString().GetString(), + UpdateChecker::MPC_HC_VERSION.ToString().GetString()); + break; + case UPDATER_LATEST_STABLE: + m_text.LoadString(IDS_USING_LATEST_STABLE); + break; + case UPDATER_NEWER_VERSION: + m_text.Format(IDS_USING_NEWER_VERSION, + UpdateChecker::MPC_HC_VERSION.ToString().GetString(), + latestVersion.ToString().GetString()); + break; + case UPDATER_ERROR: + m_text.LoadString(IDS_UPDATE_ERROR); + break; + default: + ASSERT(0); // should never happen + } +} + +UpdateCheckerDlg::~UpdateCheckerDlg() +{ +} + +void UpdateCheckerDlg::DoDataExchange(CDataExchange* pDX) +{ + CMPCThemeDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_UPDATE_DLG_TEXT, m_text); + DDX_Control(pDX, IDC_UPDATE_ICON, m_icon); + DDX_Control(pDX, IDC_UPDATE_DL_BUTTON, m_dlButton); + DDX_Control(pDX, IDC_UPDATE_LATER_BUTTON, m_laterButton); + DDX_Control(pDX, IDC_UPDATE_IGNORE_BUTTON, m_ignoreButton); + fulfillThemeReqs(); +} + + +BEGIN_MESSAGE_MAP(UpdateCheckerDlg, CMPCThemeDialog) + ON_BN_CLICKED(IDC_UPDATE_DL_BUTTON, OnOpenDownloadPage) + ON_BN_CLICKED(IDC_UPDATE_LATER_BUTTON, OnUpdateLater) + ON_BN_CLICKED(IDC_UPDATE_IGNORE_BUTTON, OnIgnoreUpdate) +END_MESSAGE_MAP() + +BOOL UpdateCheckerDlg::OnInitDialog() +{ + BOOL ret = __super::OnInitDialog(); + + switch (m_updateStatus) { + case UPDATER_UPDATE_AVAILABLE: + case UPDATER_UPDATE_AVAILABLE_IGNORED: + m_icon.SetIcon(LoadIcon(nullptr, IDI_QUESTION)); + break; + case UPDATER_LATEST_STABLE: + case UPDATER_NEWER_VERSION: + case UPDATER_ERROR: { + m_icon.SetIcon(LoadIcon(nullptr, (m_updateStatus == UPDATER_ERROR) ? IDI_WARNING : IDI_INFORMATION)); + m_dlButton.ShowWindow(SW_HIDE); + m_laterButton.ShowWindow(SW_HIDE); + m_ignoreButton.SetWindowText(ResStr(IDS_UPDATE_CLOSE)); + + CRect buttonRect, windowRect; + m_ignoreButton.GetWindowRect(&buttonRect); + ScreenToClient(&buttonRect); + // Reduce the button width + buttonRect.left += 30; + // Center the button + GetWindowRect(&windowRect); + buttonRect.MoveToX((windowRect.Width() - buttonRect.Width()) / 2); + m_ignoreButton.MoveWindow(&buttonRect); + + // Change the default button + SetDefID(IDC_UPDATE_IGNORE_BUTTON); + ret = FALSE; // Focus has been set explicitly + } + break; + default: + ASSERT(0); // should never happen + } + + return ret; +} + +void UpdateCheckerDlg::OnOpenDownloadPage() +{ + ShellExecute(nullptr, _T("open"), DOWNLOAD_URL, nullptr, nullptr, SW_SHOWNORMAL); + + EndDialog(IDC_UPDATE_DL_BUTTON); +} + +void UpdateCheckerDlg::OnUpdateLater() +{ + EndDialog(IDC_UPDATE_LATER_BUTTON); +} + +void UpdateCheckerDlg::OnIgnoreUpdate() +{ + EndDialog((m_updateStatus == UPDATER_UPDATE_AVAILABLE) ? IDC_UPDATE_IGNORE_BUTTON : 0); +} diff --git a/src/mpc-hc/UpdateCheckerDlg.h b/src/mpc-hc/UpdateCheckerDlg.h index 9ffd583ec94..2013504985c 100644 --- a/src/mpc-hc/UpdateCheckerDlg.h +++ b/src/mpc-hc/UpdateCheckerDlg.h @@ -1,54 +1,54 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "resource.h" -#include "UpdateChecker.h" -#include "CMPCThemeDialog.h" -#include "CMPCThemeButton.h" - -class UpdateCheckerDlg : public CMPCThemeDialog -{ - DECLARE_DYNAMIC(UpdateCheckerDlg) - -public: - UpdateCheckerDlg(Update_Status updateStatus, const Version& latestVersion, CWnd* pParent = nullptr); - virtual ~UpdateCheckerDlg(); - - enum { IDD = IDD_UPDATE_DIALOG }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); - afx_msg virtual BOOL OnInitDialog(); - afx_msg void OnOpenDownloadPage(); - afx_msg void OnUpdateLater(); - afx_msg void OnIgnoreUpdate(); - - DECLARE_MESSAGE_MAP() -private: - Update_Status m_updateStatus; - CString m_text; - CStatic m_icon; - CMPCThemeButton m_dlButton; - CMPCThemeButton m_laterButton; - CMPCThemeButton m_ignoreButton; -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "resource.h" +#include "UpdateChecker.h" +#include "CMPCThemeDialog.h" +#include "CMPCThemeButton.h" + +class UpdateCheckerDlg : public CMPCThemeDialog +{ + DECLARE_DYNAMIC(UpdateCheckerDlg) + +public: + UpdateCheckerDlg(Update_Status updateStatus, const Version& latestVersion, CWnd* pParent = nullptr); + virtual ~UpdateCheckerDlg(); + + enum { IDD = IDD_UPDATE_DIALOG }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); + afx_msg virtual BOOL OnInitDialog(); + afx_msg void OnOpenDownloadPage(); + afx_msg void OnUpdateLater(); + afx_msg void OnIgnoreUpdate(); + + DECLARE_MESSAGE_MAP() +private: + Update_Status m_updateStatus; + CString m_text; + CStatic m_icon; + CMPCThemeButton m_dlButton; + CMPCThemeButton m_laterButton; + CMPCThemeButton m_ignoreButton; +}; diff --git a/src/mpc-hc/VMROSD.cpp b/src/mpc-hc/VMROSD.cpp index fbba5b7bc36..e7b1562986b 100644 --- a/src/mpc-hc/VMROSD.cpp +++ b/src/mpc-hc/VMROSD.cpp @@ -1,662 +1,662 @@ -/* - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "VMROSD.h" -#include "mplayerc.h" -#include "DSMPropertyBag.h" -#include "MainFrm.h" -#include -#include "CMPCTheme.h" - -#define SEEKBAR_HEIGHT 60 -#define SLIDER_BAR_MARGIN 10 -#define SLIDER_BAR_HEIGHT 10 -#define SLIDER_CURSOR_HEIGHT 30 -#define SLIDER_CURSOR_WIDTH 15 -#define SLIDER_CHAP_WIDTH 4 -#define SLIDER_CHAP_HEIGHT 10 - - -CVMROSD::CVMROSD(CMainFrame* pMainFrame) - : m_pVMB(nullptr) - , m_pMFVMB(nullptr) - , m_pMVTO(nullptr) - , m_pCB(nullptr) - , m_pMainFrame(pMainFrame) - , m_pWnd(nullptr) - , m_iFontSize(0) - , m_bCursorMoving(false) - , m_bShowSeekBar(false) - , m_bSeekBarVisible(false) - , m_llSeekMin(0) - , m_llSeekMax(0) - , m_llSeekPos(0) - , m_bShowMessage(true) - , m_nMessagePos(OSD_NOMESSAGE) - , timerExpires(GetTickCount()) -{ - m_colors[OSD_TRANSPARENT] = RGB(0, 0, 0); - if (AppIsThemeLoaded()) { - m_colors[OSD_BACKGROUND] = CMPCTheme::ContentBGColor; - m_colors[OSD_BORDER] = CMPCTheme::WindowBorderColorDim; - m_colors[OSD_TEXT] = CMPCTheme::TextFGColor; - m_colors[OSD_BAR] = CMPCTheme::ScrollBGColor; - m_colors[OSD_CURSOR] = CMPCTheme::ScrollThumbColor; - m_colors[OSD_DEBUGCLR] = CMPCTheme::DebugColorRed; - - for (int a = OSD_TRANSPARENT + 1; a < std::size(m_colors); a++) { - if (m_colors[a] == 0) { //we cannot permit any standard color to be transparent=RGB(0,0,0) - m_colors[a] = RGB(1,1,1); - } - } - } else { - m_colors[OSD_BACKGROUND] = RGB(32, 40, 48); - m_colors[OSD_BORDER] = RGB(48, 56, 62); - m_colors[OSD_TEXT] = RGB(224, 224, 224); - m_colors[OSD_BAR] = RGB(64, 72, 80); - m_colors[OSD_CURSOR] = RGB(192, 200, 208); - m_colors[OSD_DEBUGCLR] = RGB(128, 136, 144); - } - - m_penBorder.CreatePen(PS_SOLID, 1, m_colors[OSD_BORDER]); - m_penCursor.CreatePen(PS_SOLID, 4, m_colors[OSD_CURSOR]); - m_brushBack.CreateSolidBrush(m_colors[OSD_BACKGROUND]); - m_brushBar.CreateSolidBrush(m_colors[OSD_BAR]); - m_brushChapter.CreateSolidBrush(m_colors[OSD_CURSOR]); - m_debugBrushBack.CreateSolidBrush(m_colors[OSD_DEBUGCLR]); - m_debugPenBorder.CreatePen(PS_SOLID, 1, m_colors[OSD_BORDER]); - - ZeroMemory(&m_bitmapInfo, sizeof(m_bitmapInfo)); - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - ZeroMemory(&m_MFVideoAlphaBitmap, sizeof(m_MFVideoAlphaBitmap)); -} - -CVMROSD::~CVMROSD() -{ - Stop(); - m_memDC.DeleteDC(); - m_penBorder.DeleteObject(); - m_penCursor.DeleteObject(); - m_brushBack.DeleteObject(); - m_brushBar.DeleteObject(); - m_brushChapter.DeleteObject(); - m_debugBrushBack.DeleteObject(); - m_debugPenBorder.DeleteObject(); -} - -void CVMROSD::SetSize(const CRect& wndRect, const CRect& videoRect) -{ - if (m_pWnd && (m_pVMB || m_pMFVMB)) { - if (m_bSeekBarVisible) { - m_bCursorMoving = false; - m_bSeekBarVisible = false; - Invalidate(); - } - - // Vanilla VMR9/EVR renderers draw the OSD relative to the video frame - const CAppSettings& s = AfxGetAppSettings(); - m_rectWnd = (s.iDSVideoRendererType != VIDRNDT_DS_VMR9WINDOWED - && s.iDSVideoRendererType != VIDRNDT_DS_EVR) ? wndRect : videoRect; - m_rectWnd.MoveToXY(0, 0); - - m_rectSeekBar.left = m_rectWnd.left; - m_rectSeekBar.right = m_rectWnd.right; - m_rectSeekBar.top = m_rectWnd.bottom - SEEKBAR_HEIGHT; - m_rectSeekBar.bottom = m_rectSeekBar.top + SEEKBAR_HEIGHT; - - UpdateBitmap(); - } -} - -void CVMROSD::UpdateBitmap() -{ - CAutoLock lock(&m_csLock); - CWindowDC dc(m_pWnd); - - m_memDC.DeleteDC(); - ZeroMemory(&m_bitmapInfo, sizeof(m_bitmapInfo)); - - if (m_memDC.CreateCompatibleDC(&dc)) { - BITMAPINFO bmi; - HBITMAP hbmpRender; - - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = m_rectWnd.Width(); - bmi.bmiHeader.biHeight = - m_rectWnd.Height(); // top-down - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - - hbmpRender = CreateDIBSection(m_memDC, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0); - m_memDC.SelectObject(hbmpRender); - - if (::GetObject(hbmpRender, sizeof(BITMAP), &m_bitmapInfo) != 0) { - // Configure the VMR's bitmap structure - if (m_pVMB) { - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - m_VMR9AlphaBitmap.dwFlags = VMRBITMAP_HDC | VMRBITMAP_SRCCOLORKEY; - m_VMR9AlphaBitmap.hdc = m_memDC; - m_VMR9AlphaBitmap.rSrc = m_rectWnd; - m_VMR9AlphaBitmap.rDest.left = 0; - m_VMR9AlphaBitmap.rDest.top = 0; - m_VMR9AlphaBitmap.rDest.right = 1.0; - m_VMR9AlphaBitmap.rDest.bottom = 1.0; - m_VMR9AlphaBitmap.fAlpha = 1.0; - m_VMR9AlphaBitmap.clrSrcKey = m_colors[OSD_TRANSPARENT]; - } else if (m_pMFVMB) { - ZeroMemory(&m_MFVideoAlphaBitmap, sizeof(m_MFVideoAlphaBitmap)); - m_MFVideoAlphaBitmap.params.dwFlags = MFVideoAlphaBitmap_SrcColorKey; - m_MFVideoAlphaBitmap.params.clrSrcKey = m_colors[OSD_TRANSPARENT]; - m_MFVideoAlphaBitmap.params.rcSrc = m_rectWnd; - m_MFVideoAlphaBitmap.params.nrcDest.right = 1; - m_MFVideoAlphaBitmap.params.nrcDest.bottom = 1; - m_MFVideoAlphaBitmap.GetBitmapFromDC = TRUE; - m_MFVideoAlphaBitmap.bitmap.hdc = m_memDC; - } - m_memDC.SetTextColor(m_colors[OSD_TEXT]); - m_memDC.SetBkMode(TRANSPARENT); - } - - if (m_mainFont.GetSafeHandle()) { - m_memDC.SelectObject(m_mainFont); - } - - DeleteObject(hbmpRender); - } -} - -void CVMROSD::Start(CWnd* pWnd, IVMRMixerBitmap9* pVMB, bool bShowSeekBar) -{ - m_pVMB = pVMB; - m_pMFVMB = nullptr; - m_pMVTO = nullptr; - m_pWnd = pWnd; - m_bShowSeekBar = bShowSeekBar; - UpdateBitmap(); -} - -void CVMROSD::Start(CWnd* pWnd, IMFVideoMixerBitmap* pMFVMB, bool bShowSeekBar) -{ - m_pMFVMB = pMFVMB; - m_pVMB = nullptr; - m_pMVTO = nullptr; - m_pWnd = pWnd; - m_bShowSeekBar = bShowSeekBar; - UpdateBitmap(); -} - -void CVMROSD::Start(CWnd* pWnd, IMadVRTextOsd* pMVTO) -{ - m_pMFVMB = nullptr; - m_pVMB = nullptr; - m_pMVTO = pMVTO; - m_pWnd = pWnd; -} - -void CVMROSD::Stop() -{ - m_pVMB.Release(); - m_pMFVMB.Release(); - m_pMVTO.Release(); - if (m_pWnd) { - m_pWnd->KillTimer((UINT_PTR)this); - m_pWnd = nullptr; - } -} - -void CVMROSD::SetVideoWindow(CWnd* pWnd) -{ - CAutoLock lock(&m_csLock); - - if (m_pWnd) { - m_pWnd->KillTimer((UINT_PTR)this); - } - m_pWnd = pWnd; - m_pWnd->SetTimer((UINT_PTR)this, 1000, TimerFunc); - UpdateBitmap(); -} - -void CVMROSD::DrawRect(const CRect* rect, CBrush* pBrush, CPen* pPen) -{ - if (pPen) { - m_memDC.SelectObject(pPen); - } else { - m_memDC.SelectStockObject(NULL_PEN); - } - - if (pBrush) { - m_memDC.SelectObject(pBrush); - } else { - m_memDC.SelectStockObject(HOLLOW_BRUSH); - } - - m_memDC.Rectangle(rect); -} - -void CVMROSD::DrawSlider(CRect* rect, __int64 llMin, __int64 llMax, __int64 llPos) -{ - m_rectBar.left = rect->left + SLIDER_BAR_MARGIN; - m_rectBar.right = rect->right - SLIDER_BAR_MARGIN; - m_rectBar.top = rect->top + (rect->Height() - SLIDER_BAR_HEIGHT) / 2; - m_rectBar.bottom = m_rectBar.top + SLIDER_BAR_HEIGHT; - - if (llMax == llMin) { - m_rectCursor.left = m_rectBar.left; - } else { - m_rectCursor.left = m_rectBar.left + (long)(m_rectBar.Width() * llPos / (llMax - llMin)); - } - m_rectCursor.left -= SLIDER_CURSOR_WIDTH / 2; - m_rectCursor.right = m_rectCursor.left + SLIDER_CURSOR_WIDTH; - m_rectCursor.top = rect->top + (rect->Height() - SLIDER_CURSOR_HEIGHT) / 2; - m_rectCursor.bottom = m_rectCursor.top + SLIDER_CURSOR_HEIGHT; - - DrawRect(rect, &m_brushBack, &m_penBorder); - DrawRect(&m_rectBar, &m_brushBar); - - if (m_pCB && m_pCB->ChapGetCount() > 1 && llMax != llMin) { - REFERENCE_TIME rt; - for (DWORD i = 0; i < m_pCB->ChapGetCount(); ++i) { - if (SUCCEEDED(m_pCB->ChapGet(i, &rt, nullptr))) { - __int64 pos = m_rectBar.Width() * rt / (llMax - llMin); - if (pos < 0) { - continue; - } - - CRect r; - r.left = m_rectBar.left + (LONG)pos - SLIDER_CHAP_WIDTH / 2; - r.top = rect->top + (rect->Height() - SLIDER_CHAP_HEIGHT) / 2; - r.right = r.left + SLIDER_CHAP_WIDTH; - r.bottom = r.top + SLIDER_CHAP_HEIGHT; - - DrawRect(&r, &m_brushChapter); - } - } - } - - DrawRect(&m_rectCursor, nullptr, &m_penCursor); -} - -void CVMROSD::DrawMessage() -{ - if (!m_bitmapInfo.bmWidth || !m_bitmapInfo.bmHeight || !m_bitmapInfo.bmBitsPixel) { - return; - } - if (m_nMessagePos != OSD_NOMESSAGE) { - CRect rectRestrictedWnd(m_rectWnd); - rectRestrictedWnd.DeflateRect(10, 10); - CRect rectText; - CRect rectOSD; - - DWORD uFormat = DT_SINGLELINE | DT_NOPREFIX; - m_memDC.DrawText(m_strMessage, &rectText, uFormat | DT_CALCRECT); - rectText.InflateRect(10, 5); - - rectOSD = rectText; - switch (m_nMessagePos) { - case OSD_TOPLEFT: - rectOSD.MoveToXY(10, 10); - break; - case OSD_TOPRIGHT: - default: - rectOSD.MoveToXY(m_rectWnd.Width() - rectText.Width() - 10, 10); - break; - } - rectOSD &= rectRestrictedWnd; - - DrawRect(&rectOSD, &m_brushBack, &m_penBorder); - uFormat |= DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS; - rectOSD.DeflateRect(10, 5); - m_memDC.DrawText(m_strMessage, &rectOSD, uFormat); - } -} - -void CVMROSD::DrawDebug() -{ - if (!m_debugMessages.IsEmpty()) { - CString msg, tmp; - POSITION pos; - pos = m_debugMessages.GetHeadPosition(); - msg.Format(_T("%s"), m_debugMessages.GetNext(pos).GetString()); - - while (pos) { - tmp = m_debugMessages.GetNext(pos); - if (!tmp.IsEmpty()) { - msg.AppendFormat(_T("\r\n%s"), tmp.GetString()); - } - } - - CRect rectText(0, 0, 0, 0); - CRect rectMessages; - m_memDC.DrawText(msg, &rectText, DT_CALCRECT); - rectText.InflateRect(20, 10); - - int l, r, t, b; - l = (m_rectWnd.Width() >> 1) - (rectText.Width() >> 1) - 10; - r = (m_rectWnd.Width() >> 1) + (rectText.Width() >> 1) + 10; - t = (m_rectWnd.Height() >> 1) - (rectText.Height() >> 1) - 10; - b = (m_rectWnd.Height() >> 1) + (rectText.Height() >> 1) + 10; - rectMessages = CRect(l, t, r, b); - DrawRect(&rectMessages, &m_debugBrushBack, &m_debugPenBorder); - m_memDC.DrawText(msg, &rectMessages, DT_CENTER | DT_VCENTER); - } -} - -void CVMROSD::Invalidate() -{ - CAutoLock lock(&m_csLock); - if (!m_bitmapInfo.bmWidth || !m_bitmapInfo.bmHeight || !m_bitmapInfo.bmBitsPixel) { - return; - } - memsetd(m_bitmapInfo.bmBits, 0xff000000, m_bitmapInfo.bmWidth * m_bitmapInfo.bmHeight * (m_bitmapInfo.bmBitsPixel / 8)); - - if (m_bSeekBarVisible) { - DrawSlider(&m_rectSeekBar, m_llSeekMin, m_llSeekMax, m_llSeekPos); - } - DrawMessage(); - DrawDebug(); - - if (m_pVMB) { - m_VMR9AlphaBitmap.dwFlags &= ~VMRBITMAP_DISABLE; - m_pVMB->SetAlphaBitmap(&m_VMR9AlphaBitmap); - } else if (m_pMFVMB) { - m_pMFVMB->SetAlphaBitmap(&m_MFVideoAlphaBitmap); - } - - m_pMainFrame->RepaintVideo(); -} - -void CVMROSD::UpdateSeekBarPos(CPoint point) -{ - m_llSeekPos = (point.x - m_rectBar.left) * (m_llSeekMax - m_llSeekMin) / (m_rectBar.Width() - SLIDER_CURSOR_WIDTH); - m_llSeekPos = std::max(m_llSeekPos, m_llSeekMin); - m_llSeekPos = std::min(m_llSeekPos, m_llSeekMax); - - const CAppSettings& s = AfxGetAppSettings(); - if (s.bFastSeek ^ (GetKeyState(VK_SHIFT) < 0)) { - REFERENCE_TIME rtMaxDiff = s.bAllowInaccurateFastseek ? 200000000LL : std::min(100000000LL, m_llSeekMax / 30); - m_llSeekPos = m_pMainFrame->GetClosestKeyFrame(m_llSeekPos, rtMaxDiff, rtMaxDiff); - } - - if (m_pWnd) { - AfxGetApp()->GetMainWnd()->PostMessage(WM_HSCROLL, (WPARAM)0, reinterpret_cast(m_pWnd->m_hWnd)); - } -} - -bool CVMROSD::OnMouseMove(UINT nFlags, CPoint point) -{ - bool bRet = false; - - if (m_pVMB || m_pMFVMB) { - if (m_bCursorMoving) { - bRet = true; - UpdateSeekBarPos(point); - Invalidate(); - } else if (m_bShowSeekBar && m_rectSeekBar.PtInRect(point)) { - bRet = true; - if (!m_bSeekBarVisible) { - m_bSeekBarVisible = true; - Invalidate(); - } - } else if (m_bSeekBarVisible) { - OnMouseLeave(); - } - } - - return bRet; -} - -void CVMROSD::OnMouseLeave() -{ - const bool bHideSeekbar = (m_pVMB || m_pMFVMB) && m_bSeekBarVisible; - m_bCursorMoving = false; - m_bSeekBarVisible = false; - - if (bHideSeekbar) { - // Add new timer for removing any messages - if (m_pWnd) { - m_pWnd->KillTimer((UINT_PTR)this); - m_pWnd->SetTimer((UINT_PTR)this, 1000, TimerFunc); - } - Invalidate(); - } -} - -bool CVMROSD::OnLButtonDown(UINT nFlags, CPoint point) -{ - bool bRet = false; - if (m_pVMB || m_pMFVMB) { - if (m_rectCursor.PtInRect(point)) { - m_bCursorMoving = true; - bRet = true; - if (m_pWnd) { - ASSERT(dynamic_cast(m_pWnd)); - m_pWnd->SetCapture(); - } - } else if (m_rectSeekBar.PtInRect(point)) { - bRet = true; - UpdateSeekBarPos(point); - Invalidate(); - } - } - - return bRet; -} - -bool CVMROSD::OnLButtonUp(UINT nFlags, CPoint point) -{ - bool bRet = false; - - if (m_pVMB || m_pMFVMB) { - m_bCursorMoving = false; - - bRet = (m_rectCursor.PtInRect(point) || m_rectSeekBar.PtInRect(point)); - } - return bRet; -} - -__int64 CVMROSD::GetPos() const -{ - return m_llSeekPos; -} - -void CVMROSD::SetPos(__int64 pos) -{ - m_llSeekPos = pos; - if (m_bSeekBarVisible) { - Invalidate(); - } -} - -void CVMROSD::SetRange(__int64 start, __int64 stop) -{ - m_llSeekMin = start; - m_llSeekMax = stop; -} - -void CVMROSD::GetRange(__int64& start, __int64& stop) -{ - start = m_llSeekMin; - stop = m_llSeekMax; -} - -void CVMROSD::TimerFunc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime) -{ - CVMROSD* pVMROSD = (CVMROSD*)nIDEvent; - if (pVMROSD) { - if (!pVMROSD->currentTime.IsEmpty()) { - pVMROSD->DisplayTime(pVMROSD->currentTime); - } else { - pVMROSD->ClearMessage(); - } - } - KillTimer(hWnd, nIDEvent); -} - -void CVMROSD::ClearTime() -{ - currentTime = L""; - if (timerExpires == timerExpiresForTime) { - ClearMessage(); - } -} - -void CVMROSD::ClearMessage(bool hide) -{ - CAutoLock lock(&m_csLock); - if (m_bSeekBarVisible) { - return; - } - - if (!hide) { - m_nMessagePos = OSD_NOMESSAGE; - } - - if (m_pVMB) { - DWORD dwBackup = (m_VMR9AlphaBitmap.dwFlags | VMRBITMAP_DISABLE); - m_VMR9AlphaBitmap.dwFlags = VMRBITMAP_DISABLE; - m_pVMB->SetAlphaBitmap(&m_VMR9AlphaBitmap); - m_VMR9AlphaBitmap.dwFlags = dwBackup; - } else if (m_pMFVMB) { - m_pMFVMB->ClearAlphaBitmap(); - } else if (m_pMVTO) { - m_pMVTO->OsdClearMessage(); - } - - m_pMainFrame->RepaintVideo(); -} - -void CVMROSD::DisplayTime(LPCTSTR strTime) -{ - currentTime = strTime; - if (timerExpires < GetTickCount() || timerExpires == timerExpiresForTime) { - DisplayMessage(OSD_TOPLEFT, strTime, 1000); - timerExpiresForTime = timerExpires; - } -} - - -void CVMROSD::DisplayMessage(OSD_MESSAGEPOS nPos, LPCTSTR strMsg, int nDuration, int iFontSize, CString fontName) -{ - if (!m_bShowMessage) { - return; - } - - if (m_pVMB || m_pMFVMB) { - if (nPos != OSD_DEBUG) { - m_nMessagePos = nPos; - m_strMessage = strMsg; - } else { - m_debugMessages.AddTail(strMsg); - if (m_debugMessages.GetCount() > 20) { - m_debugMessages.RemoveHead(); - } - nDuration = -1; - } - - int iOldFontSize = m_iFontSize; - CString oldFontName = m_fontName; - const CAppSettings& s = AfxGetAppSettings(); - - if (iFontSize == 0) { - m_iFontSize = s.nOSDSize; - } else { - m_iFontSize = iFontSize; - } - if (m_iFontSize < 10 || m_iFontSize > 50) { - m_iFontSize = 20; - } - if (fontName.IsEmpty()) { - m_fontName = s.strOSDFont; - } else { - m_fontName = fontName; - } - - if (iOldFontSize != m_iFontSize || oldFontName != m_fontName) { - if (m_mainFont.GetSafeHandle()) { - m_mainFont.DeleteObject(); - } - - m_mainFont.CreatePointFont(m_iFontSize * 10, m_fontName); - m_memDC.SelectObject(m_mainFont); - } - - if (m_pWnd) { - m_pWnd->KillTimer((UINT_PTR)this); - if (nDuration != -1) { - timerExpires = GetTickCount() + nDuration; - m_pWnd->SetTimer((UINT_PTR)this, nDuration, TimerFunc); - } - } - Invalidate(); - } else if (m_pMVTO) { - m_pMVTO->OsdDisplayMessage(strMsg, nDuration); - } -} - -void CVMROSD::DebugMessage(LPCTSTR format, ...) -{ - CString msg; - va_list argList; - va_start(argList, format); - msg.FormatV(format, argList); - va_end(argList); - - DisplayMessage(OSD_DEBUG, msg); -} - -void CVMROSD::HideMessage(bool hide) -{ - if (m_pVMB || m_pMFVMB) { - if (hide) { - ClearMessage(true); - } else { - Invalidate(); - } - } -} - -void CVMROSD::EnableShowMessage(bool enabled) -{ - m_bShowMessage = enabled; -} - -bool CVMROSD::CanShowMessage() -{ - return m_bShowMessage && (m_pVMB || m_pMFVMB || m_pMVTO); -} - -void CVMROSD::EnableShowSeekBar(bool enabled) -{ - m_bShowSeekBar = enabled; -} - -void CVMROSD::SetChapterBag(IDSMChapterBag* pCB) -{ - CAutoLock lock(&m_csLock); - m_pCB = pCB; - Invalidate(); -} - -void CVMROSD::RemoveChapters() -{ - SetChapterBag(nullptr); -} +/* + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "VMROSD.h" +#include "mplayerc.h" +#include "DSMPropertyBag.h" +#include "MainFrm.h" +#include +#include "CMPCTheme.h" + +#define SEEKBAR_HEIGHT 60 +#define SLIDER_BAR_MARGIN 10 +#define SLIDER_BAR_HEIGHT 10 +#define SLIDER_CURSOR_HEIGHT 30 +#define SLIDER_CURSOR_WIDTH 15 +#define SLIDER_CHAP_WIDTH 4 +#define SLIDER_CHAP_HEIGHT 10 + + +CVMROSD::CVMROSD(CMainFrame* pMainFrame) + : m_pVMB(nullptr) + , m_pMFVMB(nullptr) + , m_pMVTO(nullptr) + , m_pCB(nullptr) + , m_pMainFrame(pMainFrame) + , m_pWnd(nullptr) + , m_iFontSize(0) + , m_bCursorMoving(false) + , m_bShowSeekBar(false) + , m_bSeekBarVisible(false) + , m_llSeekMin(0) + , m_llSeekMax(0) + , m_llSeekPos(0) + , m_bShowMessage(true) + , m_nMessagePos(OSD_NOMESSAGE) + , timerExpires(GetTickCount()) +{ + m_colors[OSD_TRANSPARENT] = RGB(0, 0, 0); + if (AppIsThemeLoaded()) { + m_colors[OSD_BACKGROUND] = CMPCTheme::ContentBGColor; + m_colors[OSD_BORDER] = CMPCTheme::WindowBorderColorDim; + m_colors[OSD_TEXT] = CMPCTheme::TextFGColor; + m_colors[OSD_BAR] = CMPCTheme::ScrollBGColor; + m_colors[OSD_CURSOR] = CMPCTheme::ScrollThumbColor; + m_colors[OSD_DEBUGCLR] = CMPCTheme::DebugColorRed; + + for (int a = OSD_TRANSPARENT + 1; a < std::size(m_colors); a++) { + if (m_colors[a] == 0) { //we cannot permit any standard color to be transparent=RGB(0,0,0) + m_colors[a] = RGB(1,1,1); + } + } + } else { + m_colors[OSD_BACKGROUND] = RGB(32, 40, 48); + m_colors[OSD_BORDER] = RGB(48, 56, 62); + m_colors[OSD_TEXT] = RGB(224, 224, 224); + m_colors[OSD_BAR] = RGB(64, 72, 80); + m_colors[OSD_CURSOR] = RGB(192, 200, 208); + m_colors[OSD_DEBUGCLR] = RGB(128, 136, 144); + } + + m_penBorder.CreatePen(PS_SOLID, 1, m_colors[OSD_BORDER]); + m_penCursor.CreatePen(PS_SOLID, 4, m_colors[OSD_CURSOR]); + m_brushBack.CreateSolidBrush(m_colors[OSD_BACKGROUND]); + m_brushBar.CreateSolidBrush(m_colors[OSD_BAR]); + m_brushChapter.CreateSolidBrush(m_colors[OSD_CURSOR]); + m_debugBrushBack.CreateSolidBrush(m_colors[OSD_DEBUGCLR]); + m_debugPenBorder.CreatePen(PS_SOLID, 1, m_colors[OSD_BORDER]); + + ZeroMemory(&m_bitmapInfo, sizeof(m_bitmapInfo)); + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + ZeroMemory(&m_MFVideoAlphaBitmap, sizeof(m_MFVideoAlphaBitmap)); +} + +CVMROSD::~CVMROSD() +{ + Stop(); + m_memDC.DeleteDC(); + m_penBorder.DeleteObject(); + m_penCursor.DeleteObject(); + m_brushBack.DeleteObject(); + m_brushBar.DeleteObject(); + m_brushChapter.DeleteObject(); + m_debugBrushBack.DeleteObject(); + m_debugPenBorder.DeleteObject(); +} + +void CVMROSD::SetSize(const CRect& wndRect, const CRect& videoRect) +{ + if (m_pWnd && (m_pVMB || m_pMFVMB)) { + if (m_bSeekBarVisible) { + m_bCursorMoving = false; + m_bSeekBarVisible = false; + Invalidate(); + } + + // Vanilla VMR9/EVR renderers draw the OSD relative to the video frame + const CAppSettings& s = AfxGetAppSettings(); + m_rectWnd = (s.iDSVideoRendererType != VIDRNDT_DS_VMR9WINDOWED + && s.iDSVideoRendererType != VIDRNDT_DS_EVR) ? wndRect : videoRect; + m_rectWnd.MoveToXY(0, 0); + + m_rectSeekBar.left = m_rectWnd.left; + m_rectSeekBar.right = m_rectWnd.right; + m_rectSeekBar.top = m_rectWnd.bottom - SEEKBAR_HEIGHT; + m_rectSeekBar.bottom = m_rectSeekBar.top + SEEKBAR_HEIGHT; + + UpdateBitmap(); + } +} + +void CVMROSD::UpdateBitmap() +{ + CAutoLock lock(&m_csLock); + CWindowDC dc(m_pWnd); + + m_memDC.DeleteDC(); + ZeroMemory(&m_bitmapInfo, sizeof(m_bitmapInfo)); + + if (m_memDC.CreateCompatibleDC(&dc)) { + BITMAPINFO bmi; + HBITMAP hbmpRender; + + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = m_rectWnd.Width(); + bmi.bmiHeader.biHeight = - m_rectWnd.Height(); // top-down + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + hbmpRender = CreateDIBSection(m_memDC, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0); + m_memDC.SelectObject(hbmpRender); + + if (::GetObject(hbmpRender, sizeof(BITMAP), &m_bitmapInfo) != 0) { + // Configure the VMR's bitmap structure + if (m_pVMB) { + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + m_VMR9AlphaBitmap.dwFlags = VMRBITMAP_HDC | VMRBITMAP_SRCCOLORKEY; + m_VMR9AlphaBitmap.hdc = m_memDC; + m_VMR9AlphaBitmap.rSrc = m_rectWnd; + m_VMR9AlphaBitmap.rDest.left = 0; + m_VMR9AlphaBitmap.rDest.top = 0; + m_VMR9AlphaBitmap.rDest.right = 1.0; + m_VMR9AlphaBitmap.rDest.bottom = 1.0; + m_VMR9AlphaBitmap.fAlpha = 1.0; + m_VMR9AlphaBitmap.clrSrcKey = m_colors[OSD_TRANSPARENT]; + } else if (m_pMFVMB) { + ZeroMemory(&m_MFVideoAlphaBitmap, sizeof(m_MFVideoAlphaBitmap)); + m_MFVideoAlphaBitmap.params.dwFlags = MFVideoAlphaBitmap_SrcColorKey; + m_MFVideoAlphaBitmap.params.clrSrcKey = m_colors[OSD_TRANSPARENT]; + m_MFVideoAlphaBitmap.params.rcSrc = m_rectWnd; + m_MFVideoAlphaBitmap.params.nrcDest.right = 1; + m_MFVideoAlphaBitmap.params.nrcDest.bottom = 1; + m_MFVideoAlphaBitmap.GetBitmapFromDC = TRUE; + m_MFVideoAlphaBitmap.bitmap.hdc = m_memDC; + } + m_memDC.SetTextColor(m_colors[OSD_TEXT]); + m_memDC.SetBkMode(TRANSPARENT); + } + + if (m_mainFont.GetSafeHandle()) { + m_memDC.SelectObject(m_mainFont); + } + + DeleteObject(hbmpRender); + } +} + +void CVMROSD::Start(CWnd* pWnd, IVMRMixerBitmap9* pVMB, bool bShowSeekBar) +{ + m_pVMB = pVMB; + m_pMFVMB = nullptr; + m_pMVTO = nullptr; + m_pWnd = pWnd; + m_bShowSeekBar = bShowSeekBar; + UpdateBitmap(); +} + +void CVMROSD::Start(CWnd* pWnd, IMFVideoMixerBitmap* pMFVMB, bool bShowSeekBar) +{ + m_pMFVMB = pMFVMB; + m_pVMB = nullptr; + m_pMVTO = nullptr; + m_pWnd = pWnd; + m_bShowSeekBar = bShowSeekBar; + UpdateBitmap(); +} + +void CVMROSD::Start(CWnd* pWnd, IMadVRTextOsd* pMVTO) +{ + m_pMFVMB = nullptr; + m_pVMB = nullptr; + m_pMVTO = pMVTO; + m_pWnd = pWnd; +} + +void CVMROSD::Stop() +{ + m_pVMB.Release(); + m_pMFVMB.Release(); + m_pMVTO.Release(); + if (m_pWnd) { + m_pWnd->KillTimer((UINT_PTR)this); + m_pWnd = nullptr; + } +} + +void CVMROSD::SetVideoWindow(CWnd* pWnd) +{ + CAutoLock lock(&m_csLock); + + if (m_pWnd) { + m_pWnd->KillTimer((UINT_PTR)this); + } + m_pWnd = pWnd; + m_pWnd->SetTimer((UINT_PTR)this, 1000, TimerFunc); + UpdateBitmap(); +} + +void CVMROSD::DrawRect(const CRect* rect, CBrush* pBrush, CPen* pPen) +{ + if (pPen) { + m_memDC.SelectObject(pPen); + } else { + m_memDC.SelectStockObject(NULL_PEN); + } + + if (pBrush) { + m_memDC.SelectObject(pBrush); + } else { + m_memDC.SelectStockObject(HOLLOW_BRUSH); + } + + m_memDC.Rectangle(rect); +} + +void CVMROSD::DrawSlider(CRect* rect, __int64 llMin, __int64 llMax, __int64 llPos) +{ + m_rectBar.left = rect->left + SLIDER_BAR_MARGIN; + m_rectBar.right = rect->right - SLIDER_BAR_MARGIN; + m_rectBar.top = rect->top + (rect->Height() - SLIDER_BAR_HEIGHT) / 2; + m_rectBar.bottom = m_rectBar.top + SLIDER_BAR_HEIGHT; + + if (llMax == llMin) { + m_rectCursor.left = m_rectBar.left; + } else { + m_rectCursor.left = m_rectBar.left + (long)(m_rectBar.Width() * llPos / (llMax - llMin)); + } + m_rectCursor.left -= SLIDER_CURSOR_WIDTH / 2; + m_rectCursor.right = m_rectCursor.left + SLIDER_CURSOR_WIDTH; + m_rectCursor.top = rect->top + (rect->Height() - SLIDER_CURSOR_HEIGHT) / 2; + m_rectCursor.bottom = m_rectCursor.top + SLIDER_CURSOR_HEIGHT; + + DrawRect(rect, &m_brushBack, &m_penBorder); + DrawRect(&m_rectBar, &m_brushBar); + + if (m_pCB && m_pCB->ChapGetCount() > 1 && llMax != llMin) { + REFERENCE_TIME rt; + for (DWORD i = 0; i < m_pCB->ChapGetCount(); ++i) { + if (SUCCEEDED(m_pCB->ChapGet(i, &rt, nullptr))) { + __int64 pos = m_rectBar.Width() * rt / (llMax - llMin); + if (pos < 0) { + continue; + } + + CRect r; + r.left = m_rectBar.left + (LONG)pos - SLIDER_CHAP_WIDTH / 2; + r.top = rect->top + (rect->Height() - SLIDER_CHAP_HEIGHT) / 2; + r.right = r.left + SLIDER_CHAP_WIDTH; + r.bottom = r.top + SLIDER_CHAP_HEIGHT; + + DrawRect(&r, &m_brushChapter); + } + } + } + + DrawRect(&m_rectCursor, nullptr, &m_penCursor); +} + +void CVMROSD::DrawMessage() +{ + if (!m_bitmapInfo.bmWidth || !m_bitmapInfo.bmHeight || !m_bitmapInfo.bmBitsPixel) { + return; + } + if (m_nMessagePos != OSD_NOMESSAGE) { + CRect rectRestrictedWnd(m_rectWnd); + rectRestrictedWnd.DeflateRect(10, 10); + CRect rectText; + CRect rectOSD; + + DWORD uFormat = DT_SINGLELINE | DT_NOPREFIX; + m_memDC.DrawText(m_strMessage, &rectText, uFormat | DT_CALCRECT); + rectText.InflateRect(10, 5); + + rectOSD = rectText; + switch (m_nMessagePos) { + case OSD_TOPLEFT: + rectOSD.MoveToXY(10, 10); + break; + case OSD_TOPRIGHT: + default: + rectOSD.MoveToXY(m_rectWnd.Width() - rectText.Width() - 10, 10); + break; + } + rectOSD &= rectRestrictedWnd; + + DrawRect(&rectOSD, &m_brushBack, &m_penBorder); + uFormat |= DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS; + rectOSD.DeflateRect(10, 5); + m_memDC.DrawText(m_strMessage, &rectOSD, uFormat); + } +} + +void CVMROSD::DrawDebug() +{ + if (!m_debugMessages.IsEmpty()) { + CString msg, tmp; + POSITION pos; + pos = m_debugMessages.GetHeadPosition(); + msg.Format(_T("%s"), m_debugMessages.GetNext(pos).GetString()); + + while (pos) { + tmp = m_debugMessages.GetNext(pos); + if (!tmp.IsEmpty()) { + msg.AppendFormat(_T("\r\n%s"), tmp.GetString()); + } + } + + CRect rectText(0, 0, 0, 0); + CRect rectMessages; + m_memDC.DrawText(msg, &rectText, DT_CALCRECT); + rectText.InflateRect(20, 10); + + int l, r, t, b; + l = (m_rectWnd.Width() >> 1) - (rectText.Width() >> 1) - 10; + r = (m_rectWnd.Width() >> 1) + (rectText.Width() >> 1) + 10; + t = (m_rectWnd.Height() >> 1) - (rectText.Height() >> 1) - 10; + b = (m_rectWnd.Height() >> 1) + (rectText.Height() >> 1) + 10; + rectMessages = CRect(l, t, r, b); + DrawRect(&rectMessages, &m_debugBrushBack, &m_debugPenBorder); + m_memDC.DrawText(msg, &rectMessages, DT_CENTER | DT_VCENTER); + } +} + +void CVMROSD::Invalidate() +{ + CAutoLock lock(&m_csLock); + if (!m_bitmapInfo.bmWidth || !m_bitmapInfo.bmHeight || !m_bitmapInfo.bmBitsPixel) { + return; + } + memsetd(m_bitmapInfo.bmBits, 0xff000000, m_bitmapInfo.bmWidth * m_bitmapInfo.bmHeight * (m_bitmapInfo.bmBitsPixel / 8)); + + if (m_bSeekBarVisible) { + DrawSlider(&m_rectSeekBar, m_llSeekMin, m_llSeekMax, m_llSeekPos); + } + DrawMessage(); + DrawDebug(); + + if (m_pVMB) { + m_VMR9AlphaBitmap.dwFlags &= ~VMRBITMAP_DISABLE; + m_pVMB->SetAlphaBitmap(&m_VMR9AlphaBitmap); + } else if (m_pMFVMB) { + m_pMFVMB->SetAlphaBitmap(&m_MFVideoAlphaBitmap); + } + + m_pMainFrame->RepaintVideo(); +} + +void CVMROSD::UpdateSeekBarPos(CPoint point) +{ + m_llSeekPos = (point.x - m_rectBar.left) * (m_llSeekMax - m_llSeekMin) / (m_rectBar.Width() - SLIDER_CURSOR_WIDTH); + m_llSeekPos = std::max(m_llSeekPos, m_llSeekMin); + m_llSeekPos = std::min(m_llSeekPos, m_llSeekMax); + + const CAppSettings& s = AfxGetAppSettings(); + if (s.bFastSeek ^ (GetKeyState(VK_SHIFT) < 0)) { + REFERENCE_TIME rtMaxDiff = s.bAllowInaccurateFastseek ? 200000000LL : std::min(100000000LL, m_llSeekMax / 30); + m_llSeekPos = m_pMainFrame->GetClosestKeyFrame(m_llSeekPos, rtMaxDiff, rtMaxDiff); + } + + if (m_pWnd) { + AfxGetApp()->GetMainWnd()->PostMessage(WM_HSCROLL, (WPARAM)0, reinterpret_cast(m_pWnd->m_hWnd)); + } +} + +bool CVMROSD::OnMouseMove(UINT nFlags, CPoint point) +{ + bool bRet = false; + + if (m_pVMB || m_pMFVMB) { + if (m_bCursorMoving) { + bRet = true; + UpdateSeekBarPos(point); + Invalidate(); + } else if (m_bShowSeekBar && m_rectSeekBar.PtInRect(point)) { + bRet = true; + if (!m_bSeekBarVisible) { + m_bSeekBarVisible = true; + Invalidate(); + } + } else if (m_bSeekBarVisible) { + OnMouseLeave(); + } + } + + return bRet; +} + +void CVMROSD::OnMouseLeave() +{ + const bool bHideSeekbar = (m_pVMB || m_pMFVMB) && m_bSeekBarVisible; + m_bCursorMoving = false; + m_bSeekBarVisible = false; + + if (bHideSeekbar) { + // Add new timer for removing any messages + if (m_pWnd) { + m_pWnd->KillTimer((UINT_PTR)this); + m_pWnd->SetTimer((UINT_PTR)this, 1000, TimerFunc); + } + Invalidate(); + } +} + +bool CVMROSD::OnLButtonDown(UINT nFlags, CPoint point) +{ + bool bRet = false; + if (m_pVMB || m_pMFVMB) { + if (m_rectCursor.PtInRect(point)) { + m_bCursorMoving = true; + bRet = true; + if (m_pWnd) { + ASSERT(dynamic_cast(m_pWnd)); + m_pWnd->SetCapture(); + } + } else if (m_rectSeekBar.PtInRect(point)) { + bRet = true; + UpdateSeekBarPos(point); + Invalidate(); + } + } + + return bRet; +} + +bool CVMROSD::OnLButtonUp(UINT nFlags, CPoint point) +{ + bool bRet = false; + + if (m_pVMB || m_pMFVMB) { + m_bCursorMoving = false; + + bRet = (m_rectCursor.PtInRect(point) || m_rectSeekBar.PtInRect(point)); + } + return bRet; +} + +__int64 CVMROSD::GetPos() const +{ + return m_llSeekPos; +} + +void CVMROSD::SetPos(__int64 pos) +{ + m_llSeekPos = pos; + if (m_bSeekBarVisible) { + Invalidate(); + } +} + +void CVMROSD::SetRange(__int64 start, __int64 stop) +{ + m_llSeekMin = start; + m_llSeekMax = stop; +} + +void CVMROSD::GetRange(__int64& start, __int64& stop) +{ + start = m_llSeekMin; + stop = m_llSeekMax; +} + +void CVMROSD::TimerFunc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime) +{ + CVMROSD* pVMROSD = (CVMROSD*)nIDEvent; + if (pVMROSD) { + if (!pVMROSD->currentTime.IsEmpty()) { + pVMROSD->DisplayTime(pVMROSD->currentTime); + } else { + pVMROSD->ClearMessage(); + } + } + KillTimer(hWnd, nIDEvent); +} + +void CVMROSD::ClearTime() +{ + currentTime = L""; + if (timerExpires == timerExpiresForTime) { + ClearMessage(); + } +} + +void CVMROSD::ClearMessage(bool hide) +{ + CAutoLock lock(&m_csLock); + if (m_bSeekBarVisible) { + return; + } + + if (!hide) { + m_nMessagePos = OSD_NOMESSAGE; + } + + if (m_pVMB) { + DWORD dwBackup = (m_VMR9AlphaBitmap.dwFlags | VMRBITMAP_DISABLE); + m_VMR9AlphaBitmap.dwFlags = VMRBITMAP_DISABLE; + m_pVMB->SetAlphaBitmap(&m_VMR9AlphaBitmap); + m_VMR9AlphaBitmap.dwFlags = dwBackup; + } else if (m_pMFVMB) { + m_pMFVMB->ClearAlphaBitmap(); + } else if (m_pMVTO) { + m_pMVTO->OsdClearMessage(); + } + + m_pMainFrame->RepaintVideo(); +} + +void CVMROSD::DisplayTime(LPCTSTR strTime) +{ + currentTime = strTime; + if (timerExpires < GetTickCount() || timerExpires == timerExpiresForTime) { + DisplayMessage(OSD_TOPLEFT, strTime, 1000); + timerExpiresForTime = timerExpires; + } +} + + +void CVMROSD::DisplayMessage(OSD_MESSAGEPOS nPos, LPCTSTR strMsg, int nDuration, int iFontSize, CString fontName) +{ + if (!m_bShowMessage) { + return; + } + + if (m_pVMB || m_pMFVMB) { + if (nPos != OSD_DEBUG) { + m_nMessagePos = nPos; + m_strMessage = strMsg; + } else { + m_debugMessages.AddTail(strMsg); + if (m_debugMessages.GetCount() > 20) { + m_debugMessages.RemoveHead(); + } + nDuration = -1; + } + + int iOldFontSize = m_iFontSize; + CString oldFontName = m_fontName; + const CAppSettings& s = AfxGetAppSettings(); + + if (iFontSize == 0) { + m_iFontSize = s.nOSDSize; + } else { + m_iFontSize = iFontSize; + } + if (m_iFontSize < 10 || m_iFontSize > 50) { + m_iFontSize = 20; + } + if (fontName.IsEmpty()) { + m_fontName = s.strOSDFont; + } else { + m_fontName = fontName; + } + + if (iOldFontSize != m_iFontSize || oldFontName != m_fontName) { + if (m_mainFont.GetSafeHandle()) { + m_mainFont.DeleteObject(); + } + + m_mainFont.CreatePointFont(m_iFontSize * 10, m_fontName); + m_memDC.SelectObject(m_mainFont); + } + + if (m_pWnd) { + m_pWnd->KillTimer((UINT_PTR)this); + if (nDuration != -1) { + timerExpires = GetTickCount() + nDuration; + m_pWnd->SetTimer((UINT_PTR)this, nDuration, TimerFunc); + } + } + Invalidate(); + } else if (m_pMVTO) { + m_pMVTO->OsdDisplayMessage(strMsg, nDuration); + } +} + +void CVMROSD::DebugMessage(LPCTSTR format, ...) +{ + CString msg; + va_list argList; + va_start(argList, format); + msg.FormatV(format, argList); + va_end(argList); + + DisplayMessage(OSD_DEBUG, msg); +} + +void CVMROSD::HideMessage(bool hide) +{ + if (m_pVMB || m_pMFVMB) { + if (hide) { + ClearMessage(true); + } else { + Invalidate(); + } + } +} + +void CVMROSD::EnableShowMessage(bool enabled) +{ + m_bShowMessage = enabled; +} + +bool CVMROSD::CanShowMessage() +{ + return m_bShowMessage && (m_pVMB || m_pMFVMB || m_pMVTO); +} + +void CVMROSD::EnableShowSeekBar(bool enabled) +{ + m_bShowSeekBar = enabled; +} + +void CVMROSD::SetChapterBag(IDSMChapterBag* pCB) +{ + CAutoLock lock(&m_csLock); + m_pCB = pCB; + Invalidate(); +} + +void CVMROSD::RemoveChapters() +{ + SetChapterBag(nullptr); +} diff --git a/src/mpc-hc/VMROSD.h b/src/mpc-hc/VMROSD.h index a85015afa5a..fdcdb57a361 100644 --- a/src/mpc-hc/VMROSD.h +++ b/src/mpc-hc/VMROSD.h @@ -1,144 +1,144 @@ -/* - * (C) 2006-2014, 2016 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 . - * - */ - -#pragma once - -#include -#include - - -enum OSD_COLORS { - OSD_TRANSPARENT, - OSD_BACKGROUND, - OSD_BORDER, - OSD_TEXT, - OSD_BAR, - OSD_CURSOR, - OSD_DEBUGCLR, - OSD_LAST -}; - -enum OSD_MESSAGEPOS { - OSD_NOMESSAGE, - OSD_TOPLEFT, - OSD_TOPRIGHT, - OSD_DEBUG -}; - -interface IMadVRTextOsd; -interface IDSMChapterBag; -class CMainFrame; - -class CVMROSD -{ -public: - CVMROSD(CMainFrame* pMainFrame); - ~CVMROSD(); - - void Start(CWnd* pWnd, IVMRMixerBitmap9* pVMB, bool bShowSeekBar); - void Start(CWnd* pWnd, IMFVideoMixerBitmap* pVMB, bool bShowSeekBar); - void Start(CWnd* pWnd, IMadVRTextOsd* pMVTO); - void Stop(); - - void DisplayTime(LPCTSTR strTime); - void DisplayMessage(OSD_MESSAGEPOS nPos, LPCTSTR strMsg, int nDuration = 5000, int iFontSize = 0, CString fontName = _T("")); - void DebugMessage(LPCTSTR format, ...); - void ClearTime(); - void ClearMessage(bool hide = false); - void HideMessage(bool hide); - void EnableShowMessage(bool enabled = true); - bool CanShowMessage(); - - __int64 GetPos() const; - void SetPos(__int64 pos); - void SetRange(__int64 start, __int64 stop); - void GetRange(__int64& start, __int64& stop); - - void SetSize(const CRect& wndRect, const CRect& videoRect); - bool OnMouseMove(UINT nFlags, CPoint point); - void OnMouseLeave(); - bool OnLButtonDown(UINT nFlags, CPoint point); - bool OnLButtonUp(UINT nFlags, CPoint point); - - void EnableShowSeekBar(bool enabled = true); - void SetVideoWindow(CWnd* pWnd); - - void SetChapterBag(IDSMChapterBag* pCB); - void RemoveChapters(); -private: - CComPtr m_pVMB; - CComPtr m_pMFVMB; - CComPtr m_pMVTO; - CComPtr m_pCB; - - CMainFrame* m_pMainFrame; - CWnd* m_pWnd; - - CCritSec m_csLock; - CDC m_memDC; - VMR9AlphaBitmap m_VMR9AlphaBitmap; - MFVideoAlphaBitmap m_MFVideoAlphaBitmap; - BITMAP m_bitmapInfo; - - CFont m_mainFont; - CPen m_penBorder; - CPen m_penCursor; - CBrush m_brushBack; - CBrush m_brushBar; - CBrush m_brushChapter; - CPen m_debugPenBorder; - CBrush m_debugBrushBack; - int m_iFontSize; - CString m_fontName; - - CStringW currentTime; - DWORD timerExpires, timerExpiresForTime; - - CRect m_rectWnd; - COLORREF m_colors[OSD_LAST]; - - // Seekbar - CRect m_rectSeekBar; - CRect m_rectCursor; - CRect m_rectBar; - bool m_bCursorMoving; - bool m_bShowSeekBar; - bool m_bSeekBarVisible; - __int64 m_llSeekMin; - __int64 m_llSeekMax; - __int64 m_llSeekPos; - - bool m_bShowMessage; - - // Messages - CString m_strMessage; - OSD_MESSAGEPOS m_nMessagePos; - CList m_debugMessages; - - void UpdateBitmap(); - void UpdateSeekBarPos(CPoint point); - void DrawSlider(CRect* rect, __int64 llMin, __int64 llMax, __int64 llPos); - void DrawRect(const CRect* rect, CBrush* pBrush = nullptr, CPen* pPen = nullptr); - void Invalidate(); - void DrawMessage(); - void DrawDebug(); - - static void CALLBACK TimerFunc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime); -}; +/* + * (C) 2006-2014, 2016 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 . + * + */ + +#pragma once + +#include +#include + + +enum OSD_COLORS { + OSD_TRANSPARENT, + OSD_BACKGROUND, + OSD_BORDER, + OSD_TEXT, + OSD_BAR, + OSD_CURSOR, + OSD_DEBUGCLR, + OSD_LAST +}; + +enum OSD_MESSAGEPOS { + OSD_NOMESSAGE, + OSD_TOPLEFT, + OSD_TOPRIGHT, + OSD_DEBUG +}; + +interface IMadVRTextOsd; +interface IDSMChapterBag; +class CMainFrame; + +class CVMROSD +{ +public: + CVMROSD(CMainFrame* pMainFrame); + ~CVMROSD(); + + void Start(CWnd* pWnd, IVMRMixerBitmap9* pVMB, bool bShowSeekBar); + void Start(CWnd* pWnd, IMFVideoMixerBitmap* pVMB, bool bShowSeekBar); + void Start(CWnd* pWnd, IMadVRTextOsd* pMVTO); + void Stop(); + + void DisplayTime(LPCTSTR strTime); + void DisplayMessage(OSD_MESSAGEPOS nPos, LPCTSTR strMsg, int nDuration = 5000, int iFontSize = 0, CString fontName = _T("")); + void DebugMessage(LPCTSTR format, ...); + void ClearTime(); + void ClearMessage(bool hide = false); + void HideMessage(bool hide); + void EnableShowMessage(bool enabled = true); + bool CanShowMessage(); + + __int64 GetPos() const; + void SetPos(__int64 pos); + void SetRange(__int64 start, __int64 stop); + void GetRange(__int64& start, __int64& stop); + + void SetSize(const CRect& wndRect, const CRect& videoRect); + bool OnMouseMove(UINT nFlags, CPoint point); + void OnMouseLeave(); + bool OnLButtonDown(UINT nFlags, CPoint point); + bool OnLButtonUp(UINT nFlags, CPoint point); + + void EnableShowSeekBar(bool enabled = true); + void SetVideoWindow(CWnd* pWnd); + + void SetChapterBag(IDSMChapterBag* pCB); + void RemoveChapters(); +private: + CComPtr m_pVMB; + CComPtr m_pMFVMB; + CComPtr m_pMVTO; + CComPtr m_pCB; + + CMainFrame* m_pMainFrame; + CWnd* m_pWnd; + + CCritSec m_csLock; + CDC m_memDC; + VMR9AlphaBitmap m_VMR9AlphaBitmap; + MFVideoAlphaBitmap m_MFVideoAlphaBitmap; + BITMAP m_bitmapInfo; + + CFont m_mainFont; + CPen m_penBorder; + CPen m_penCursor; + CBrush m_brushBack; + CBrush m_brushBar; + CBrush m_brushChapter; + CPen m_debugPenBorder; + CBrush m_debugBrushBack; + int m_iFontSize; + CString m_fontName; + + CStringW currentTime; + DWORD timerExpires, timerExpiresForTime; + + CRect m_rectWnd; + COLORREF m_colors[OSD_LAST]; + + // Seekbar + CRect m_rectSeekBar; + CRect m_rectCursor; + CRect m_rectBar; + bool m_bCursorMoving; + bool m_bShowSeekBar; + bool m_bSeekBarVisible; + __int64 m_llSeekMin; + __int64 m_llSeekMax; + __int64 m_llSeekPos; + + bool m_bShowMessage; + + // Messages + CString m_strMessage; + OSD_MESSAGEPOS m_nMessagePos; + CList m_debugMessages; + + void UpdateBitmap(); + void UpdateSeekBarPos(CPoint point); + void DrawSlider(CRect* rect, __int64 llMin, __int64 llMax, __int64 llPos); + void DrawRect(const CRect* rect, CBrush* pBrush = nullptr, CPen* pPen = nullptr); + void Invalidate(); + void DrawMessage(); + void DrawDebug(); + + static void CALLBACK TimerFunc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime); +}; diff --git a/src/mpc-hc/VolumeCtrl.cpp b/src/mpc-hc/VolumeCtrl.cpp index c1ba6d4f994..aeac5905d58 100644 --- a/src/mpc-hc/VolumeCtrl.cpp +++ b/src/mpc-hc/VolumeCtrl.cpp @@ -1,498 +1,498 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "VolumeCtrl.h" -#include "AppSettings.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "MainFrm.h" -#undef SubclassWindow - - -// CVolumeCtrl - -IMPLEMENT_DYNAMIC(CVolumeCtrl, CSliderCtrl) -CVolumeCtrl::CVolumeCtrl(bool fSelfDrawn) - : m_fSelfDrawn(fSelfDrawn) - , m_bDrag(false) - , m_bHover(false) - , modernStyle(AfxGetAppSettings().bMPCTheme) -{ -} - -CVolumeCtrl::~CVolumeCtrl() -{ -} - -bool CVolumeCtrl::Create(CWnd* pParentWnd) -{ - DWORD tooltipStyle = AppIsThemeLoaded() ? 0 : TBS_TOOLTIPS; - if (!CSliderCtrl::Create(WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_HORZ | tooltipStyle, CRect(0, 0, 0, 0), pParentWnd, IDC_SLIDER1)) { - return false; - } - - const CAppSettings& s = AfxGetAppSettings(); - EnableToolTips(TRUE); - SetRange(0, 100); - SetPos(s.nVolume); - SetPageSize(s.nVolumeStep); - SetLineSize(0); - - if (AppIsThemeLoaded()) { - CToolTipCtrl* pTip = GetToolTips(); - if (NULL != pTip) { - themedToolTip.SubclassWindow(pTip->m_hWnd); - } - } - - return true; -} - -void CVolumeCtrl::SetPosInternal(int pos) -{ - SetPos(pos); - GetParent()->PostMessage(WM_HSCROLL, MAKEWPARAM(static_cast(pos), SB_THUMBPOSITION), reinterpret_cast(m_hWnd)); // this will be reflected back on us - POINT p; - ::GetCursorPos(&p); - ScreenToClient(&p); - checkHover(p); -} - -void CVolumeCtrl::IncreaseVolume() -{ - // align volume up to step. recommend using steps 1, 2, 5 and 10 - SetPosInternal(GetPos() + GetPageSize() - GetPos() % GetPageSize()); - -} - -void CVolumeCtrl::DecreaseVolume() -{ - // align volume down to step. recommend using steps 1, 2, 5 and 10 - int m = GetPos() % GetPageSize(); - SetPosInternal(GetPos() - (m ? m : GetPageSize())); -} - -BEGIN_MESSAGE_MAP(CVolumeCtrl, CSliderCtrl) - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw) - ON_WM_LBUTTONDOWN() - ON_WM_SETFOCUS() - ON_WM_HSCROLL_REFLECT() - ON_WM_SETCURSOR() - ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) - ON_WM_MOUSEWHEEL() - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONUP() - ON_WM_MOUSELEAVE() - ON_WM_PAINT() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -// CVolumeCtrl message handlers - -void CVolumeCtrl::getCustomChannelRect(LPRECT rc) -{ - if (AppIsThemeLoaded()) { - CRect channelRect; - GetClientRect(channelRect); - CopyRect(rc, CRect(channelRect.left, channelRect.top, channelRect.right - AfxGetMainFrame()->m_dpi.ScaleFloorX(2), channelRect.bottom)); - } else { - CRect channelRect; - GetChannelRect(channelRect); - CRect thumbRect; - GetThumbRect(thumbRect); - - CopyRect(rc, CRect(channelRect.left, thumbRect.top + 2, channelRect.right - 2, thumbRect.bottom - 2)); - } -} - -void CVolumeCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); - - LRESULT lr = CDRF_DODEFAULT; - - bool usetheme = AppIsThemeLoaded(); - - if (m_fSelfDrawn) - switch (pNMCD->dwDrawStage) { - case CDDS_PREPAINT: - lr = CDRF_NOTIFYITEMDRAW; - break; - - case CDDS_ITEMPREPAINT: - - if (pNMCD->dwItemSpec == TBCD_CHANNEL) { - CDC dc; - dc.Attach(pNMCD->hdc); - - if (usetheme) { - CRect rect; - GetClientRect(rect); - dc.FillSolidRect(&rect, CMPCTheme::PlayerBGColor); - } - - getCustomChannelRect(&pNMCD->rc); - - if (usetheme) { - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - CRect r(pNMCD->rc); - r.DeflateRect(0, dpiWindow.ScaleFloorY(6), 0, dpiWindow.ScaleFloorY(6)); - dc.FillSolidRect(r, CMPCTheme::ScrollBGColor); - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - } else { - CPen shadow; - CPen light; - shadow.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); - light.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT)); - CPen* old = dc.SelectObject(&light); - dc.MoveTo(pNMCD->rc.right, pNMCD->rc.top); - dc.LineTo(pNMCD->rc.right, pNMCD->rc.bottom); - dc.LineTo(pNMCD->rc.left, pNMCD->rc.bottom); - dc.SelectObject(&shadow); - dc.LineTo(pNMCD->rc.right, pNMCD->rc.top); - dc.SelectObject(old); - shadow.DeleteObject(); - light.DeleteObject(); - } - - dc.Detach(); - lr = CDRF_SKIPDEFAULT; - } else if (pNMCD->dwItemSpec == TBCD_THUMB) { - CDC dc; - dc.Attach(pNMCD->hdc); - pNMCD->rc.bottom--; - CRect r(pNMCD->rc); - r.DeflateRect(0, 0, 1, 0); - - COLORREF shadow = GetSysColor(COLOR_3DSHADOW); - COLORREF light = GetSysColor(COLOR_3DHILIGHT); - if (usetheme) { - CBrush fb; - if (m_bDrag) { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbDragColor); - } else if (m_bHover) { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbHoverColor); - } else { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbColor); - } - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - } else { - dc.Draw3dRect(&r, light, 0); - r.DeflateRect(0, 0, 1, 1); - dc.Draw3dRect(&r, light, shadow); - r.DeflateRect(1, 1, 1, 1); - dc.FillSolidRect(&r, GetSysColor(COLOR_BTNFACE)); - dc.SetPixel(r.left + 7, r.top - 1, GetSysColor(COLOR_BTNFACE)); - } - - dc.Detach(); - lr = CDRF_SKIPDEFAULT; - } - - break; - }; - - pNMCD->uItemState &= ~CDIS_FOCUS; - - *pResult = lr; -} - -void CVolumeCtrl::OnLButtonDown(UINT nFlags, CPoint point) -{ - CRect r; - GetChannelRect(&r); - - if (r.left >= r.right) { - return; - } - - int start, stop; - GetRange(start, stop); - - if (!(AppIsThemeLoaded() && modernStyle)) { - r.left += 3; - r.right -= 4; - } - - if (point.x < r.left) { - SetPosInternal(start); - } else if (point.x >= r.right) { - SetPosInternal(stop); - } else { - int w = r.right - r.left; - if (start < stop) { - if (!(AppIsThemeLoaded() && modernStyle)) { - SetPosInternal(start + ((stop - start) * (point.x - r.left) + (w / 2)) / w); - } else { - SetPosInternal(start + lround((stop - start) * float(point.x - r.left) / w)); - } - } - } - m_bDrag = true; - if (AppIsThemeLoaded() && modernStyle) { - if (themedToolTip.m_hWnd) { - TOOLINFO ti = { sizeof(TOOLINFO) }; - ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_ABSOLUTE; - ti.hwnd = m_hWnd; - ti.uId = (UINT_PTR)m_hWnd; - ti.hinst = AfxGetInstanceHandle(); - ti.lpszText = LPSTR_TEXTCALLBACK; - - themedToolTip.SendMessage(TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti); - } - - updateModernVolCtrl(point); - SetCapture(); - } else { - invalidateThumb(); - CSliderCtrl::OnLButtonDown(nFlags, point); - } -} - -void CVolumeCtrl::OnSetFocus(CWnd* pOldWnd) -{ - CSliderCtrl::OnSetFocus(pOldWnd); - - AfxGetMainWnd()->SetFocus(); // don't focus on us, parents will take care of our positioning -} - -void CVolumeCtrl::HScroll(UINT nSBCode, UINT nPos) -{ - auto &s = AfxGetAppSettings(); - auto oldVolume = s.nVolume; - s.nVolume = GetPos(); - - CFrameWnd* pFrame = GetParentFrame(); - if (pFrame && pFrame != GetParent()) { - pFrame->PostMessage(WM_HSCROLL, MAKEWPARAM(static_cast(nPos), static_cast(nSBCode)), reinterpret_cast(m_hWnd)); - if (s.nVolume != oldVolume) { - CRect r; - getCustomChannelRect(r); - InvalidateRect(r); //needed to redraw the volume text - } - } -} - -BOOL CVolumeCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) -{ - ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_HAND)); - return TRUE; -} - -BOOL CVolumeCtrl::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) -{ - TOOLTIPTEXT* pTTT = reinterpret_cast(pNMHDR); - CString str; - str.Format(IDS_VOLUME, GetPos()); - _tcscpy_s(pTTT->szText, str); - pTTT->hinst = nullptr; - - *pResult = 0; - - return TRUE; -} - -BOOL CVolumeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) -{ - if (zDelta > 0) { - IncreaseVolume(); - } else if (zDelta < 0) { - DecreaseVolume(); - } else { - return FALSE; - } - return TRUE; -} - -void CVolumeCtrl::invalidateThumb() -{ - if (!(AppIsThemeLoaded() && modernStyle)) { - SetRangeMax(100, TRUE); - } -} - - -void CVolumeCtrl::checkHover(CPoint point) -{ - CRect thumbRect; - GetThumbRect(thumbRect); - bool oldHover = m_bHover; - m_bHover = false; - if (thumbRect.PtInRect(point)) { - m_bHover = true; - } - - if (m_bHover != oldHover) { - invalidateThumb(); - } -} - -void CVolumeCtrl::updateModernVolCtrl(CPoint point) -{ - //CSliderCtrl::OnMouseMove yields bad results due to assumption of thumb width - //we must do all position calculation ourselves, and send correct position to tooltip - - CRect r; - GetChannelRect(&r); - - int start, stop; - GetRange(start, stop); - int useX; - if (point.x < r.left) { - SetPosInternal(start); - useX = r.left; - } else if (point.x >= r.right) { - SetPosInternal(stop); - useX = r.right; - } else { - int w = r.right - r.left; - if (start < stop) { - SetPosInternal(start + lround((stop - start) * float(point.x - r.left) / w)); - } - useX = point.x; - } - POINT p = { useX, point.y }; - ClientToScreen(&p); - CRect ttRect; - if (themedToolTip.m_hWnd) { - CRect cr = r; - ClientToScreen(cr); - themedToolTip.GetWindowRect(ttRect); - p.y = cr.top - ttRect.Height(); - themedToolTip.SendMessage(TTM_TRACKPOSITION, 0, MAKELPARAM(p.x, p.y)); - } - - RECT ur; - getCustomChannelRect(&ur); - RedrawWindow(&ur, nullptr, RDW_INVALIDATE); //we must redraw the whole channel with the modern volume ctrl. by default only areas where thumb has been are invalidated -} - - -void CVolumeCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - checkHover(point); - - if (AppIsThemeLoaded() && modernStyle && m_bDrag) { - updateModernVolCtrl(point); - } else { - CSliderCtrl::OnMouseMove(nFlags, point); - } -} - - -void CVolumeCtrl::OnLButtonUp(UINT nFlags, CPoint point) -{ - if (AppIsThemeLoaded() && modernStyle) { - if (m_bDrag) { - ReleaseCapture(); - } - m_bDrag = false; - if (themedToolTip.m_hWnd) { - themedToolTip.SendMessage(TTM_TRACKACTIVATE, FALSE, 0); - } - } else { - m_bDrag = false; - invalidateThumb(); - checkHover(point); - CSliderCtrl::OnLButtonUp(nFlags, point); - } -} - - -void CVolumeCtrl::OnMouseLeave() -{ - checkHover(CPoint(-1 - 1)); - CSliderCtrl::OnMouseLeave(); -} - - -void CVolumeCtrl::OnPaint() { - if (m_fSelfDrawn && AppIsThemeLoaded() && modernStyle) { - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - CPaintDC dc(this); - CRect r, cr; - GetClientRect(cr); - - CDC dcMem; - CBitmap bmMem; - CRect memRect = { 0, 0, cr.right, cr.bottom }; - CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, memRect); - - dcMem.FillSolidRect(&memRect, CMPCTheme::PlayerBGColor); - getCustomChannelRect(r); - //r.DeflateRect(0, dpiWindow.ScaleFloorY(3), 0, dpiWindow.ScaleFloorY(2)); - r.OffsetRect(-cr.TopLeft()); - - CRect filledRect, unfilledRect; - filledRect = r; - filledRect.right = r.left + lround(r.Width() * float(GetPos()) / 100); - dcMem.FillSolidRect(&filledRect, CMPCTheme::ScrollProgressColor); - - if (filledRect.right < r.right) { //do not fill bg if already full - unfilledRect = r; - unfilledRect.left = filledRect.right; - dcMem.FillSolidRect(&unfilledRect, CMPCTheme::ScrollBGColor); - } - - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dcMem.FrameRect(r, &fb); - fb.DeleteObject(); - - dcMem.SetTextColor(CMPCTheme::TextFGColor); - CFont f; - LOGFONT lf = { 0 }; - lf.lfHeight = r.Height(); - lf.lfQuality = CLEARTYPE_QUALITY; - wcscpy_s(lf.lfFaceName, L"Calibri"); - f.CreateFontIndirectW(&lf); - CFont* oldFont = (CFont*)dcMem.SelectObject(&f); - int oldMode = dcMem.SetBkMode(TRANSPARENT); - CStringW str; - str.Format(IDS_VOLUME, GetPos()); - dcMem.DrawTextW(str, r, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX); - dcMem.SelectObject(oldFont); - dcMem.SetBkMode(oldMode); - - CMPCThemeUtil::flushMemDC(&dc, dcMem, memRect); - } else { - __super::OnPaint(); //can trigger OnNMCustomdraw - } -} - -BOOL CVolumeCtrl::OnEraseBkgnd(CDC* pDC) { - if (m_fSelfDrawn && AppIsThemeLoaded() && modernStyle) { - return TRUE; - } else { - return CSliderCtrl::OnEraseBkgnd(pDC); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "VolumeCtrl.h" +#include "AppSettings.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "MainFrm.h" +#undef SubclassWindow + + +// CVolumeCtrl + +IMPLEMENT_DYNAMIC(CVolumeCtrl, CSliderCtrl) +CVolumeCtrl::CVolumeCtrl(bool fSelfDrawn) + : m_fSelfDrawn(fSelfDrawn) + , m_bDrag(false) + , m_bHover(false) + , modernStyle(AfxGetAppSettings().bMPCTheme) +{ +} + +CVolumeCtrl::~CVolumeCtrl() +{ +} + +bool CVolumeCtrl::Create(CWnd* pParentWnd) +{ + DWORD tooltipStyle = AppIsThemeLoaded() ? 0 : TBS_TOOLTIPS; + if (!CSliderCtrl::Create(WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_HORZ | tooltipStyle, CRect(0, 0, 0, 0), pParentWnd, IDC_SLIDER1)) { + return false; + } + + const CAppSettings& s = AfxGetAppSettings(); + EnableToolTips(TRUE); + SetRange(0, 100); + SetPos(s.nVolume); + SetPageSize(s.nVolumeStep); + SetLineSize(0); + + if (AppIsThemeLoaded()) { + CToolTipCtrl* pTip = GetToolTips(); + if (NULL != pTip) { + themedToolTip.SubclassWindow(pTip->m_hWnd); + } + } + + return true; +} + +void CVolumeCtrl::SetPosInternal(int pos) +{ + SetPos(pos); + GetParent()->PostMessage(WM_HSCROLL, MAKEWPARAM(static_cast(pos), SB_THUMBPOSITION), reinterpret_cast(m_hWnd)); // this will be reflected back on us + POINT p; + ::GetCursorPos(&p); + ScreenToClient(&p); + checkHover(p); +} + +void CVolumeCtrl::IncreaseVolume() +{ + // align volume up to step. recommend using steps 1, 2, 5 and 10 + SetPosInternal(GetPos() + GetPageSize() - GetPos() % GetPageSize()); + +} + +void CVolumeCtrl::DecreaseVolume() +{ + // align volume down to step. recommend using steps 1, 2, 5 and 10 + int m = GetPos() % GetPageSize(); + SetPosInternal(GetPos() - (m ? m : GetPageSize())); +} + +BEGIN_MESSAGE_MAP(CVolumeCtrl, CSliderCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw) + ON_WM_LBUTTONDOWN() + ON_WM_SETFOCUS() + ON_WM_HSCROLL_REFLECT() + ON_WM_SETCURSOR() + ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) + ON_WM_MOUSEWHEEL() + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONUP() + ON_WM_MOUSELEAVE() + ON_WM_PAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +// CVolumeCtrl message handlers + +void CVolumeCtrl::getCustomChannelRect(LPRECT rc) +{ + if (AppIsThemeLoaded()) { + CRect channelRect; + GetClientRect(channelRect); + CopyRect(rc, CRect(channelRect.left, channelRect.top, channelRect.right - AfxGetMainFrame()->m_dpi.ScaleFloorX(2), channelRect.bottom)); + } else { + CRect channelRect; + GetChannelRect(channelRect); + CRect thumbRect; + GetThumbRect(thumbRect); + + CopyRect(rc, CRect(channelRect.left, thumbRect.top + 2, channelRect.right - 2, thumbRect.bottom - 2)); + } +} + +void CVolumeCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); + + LRESULT lr = CDRF_DODEFAULT; + + bool usetheme = AppIsThemeLoaded(); + + if (m_fSelfDrawn) + switch (pNMCD->dwDrawStage) { + case CDDS_PREPAINT: + lr = CDRF_NOTIFYITEMDRAW; + break; + + case CDDS_ITEMPREPAINT: + + if (pNMCD->dwItemSpec == TBCD_CHANNEL) { + CDC dc; + dc.Attach(pNMCD->hdc); + + if (usetheme) { + CRect rect; + GetClientRect(rect); + dc.FillSolidRect(&rect, CMPCTheme::PlayerBGColor); + } + + getCustomChannelRect(&pNMCD->rc); + + if (usetheme) { + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + CRect r(pNMCD->rc); + r.DeflateRect(0, dpiWindow.ScaleFloorY(6), 0, dpiWindow.ScaleFloorY(6)); + dc.FillSolidRect(r, CMPCTheme::ScrollBGColor); + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + } else { + CPen shadow; + CPen light; + shadow.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); + light.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT)); + CPen* old = dc.SelectObject(&light); + dc.MoveTo(pNMCD->rc.right, pNMCD->rc.top); + dc.LineTo(pNMCD->rc.right, pNMCD->rc.bottom); + dc.LineTo(pNMCD->rc.left, pNMCD->rc.bottom); + dc.SelectObject(&shadow); + dc.LineTo(pNMCD->rc.right, pNMCD->rc.top); + dc.SelectObject(old); + shadow.DeleteObject(); + light.DeleteObject(); + } + + dc.Detach(); + lr = CDRF_SKIPDEFAULT; + } else if (pNMCD->dwItemSpec == TBCD_THUMB) { + CDC dc; + dc.Attach(pNMCD->hdc); + pNMCD->rc.bottom--; + CRect r(pNMCD->rc); + r.DeflateRect(0, 0, 1, 0); + + COLORREF shadow = GetSysColor(COLOR_3DSHADOW); + COLORREF light = GetSysColor(COLOR_3DHILIGHT); + if (usetheme) { + CBrush fb; + if (m_bDrag) { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbDragColor); + } else if (m_bHover) { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbHoverColor); + } else { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbColor); + } + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + } else { + dc.Draw3dRect(&r, light, 0); + r.DeflateRect(0, 0, 1, 1); + dc.Draw3dRect(&r, light, shadow); + r.DeflateRect(1, 1, 1, 1); + dc.FillSolidRect(&r, GetSysColor(COLOR_BTNFACE)); + dc.SetPixel(r.left + 7, r.top - 1, GetSysColor(COLOR_BTNFACE)); + } + + dc.Detach(); + lr = CDRF_SKIPDEFAULT; + } + + break; + }; + + pNMCD->uItemState &= ~CDIS_FOCUS; + + *pResult = lr; +} + +void CVolumeCtrl::OnLButtonDown(UINT nFlags, CPoint point) +{ + CRect r; + GetChannelRect(&r); + + if (r.left >= r.right) { + return; + } + + int start, stop; + GetRange(start, stop); + + if (!(AppIsThemeLoaded() && modernStyle)) { + r.left += 3; + r.right -= 4; + } + + if (point.x < r.left) { + SetPosInternal(start); + } else if (point.x >= r.right) { + SetPosInternal(stop); + } else { + int w = r.right - r.left; + if (start < stop) { + if (!(AppIsThemeLoaded() && modernStyle)) { + SetPosInternal(start + ((stop - start) * (point.x - r.left) + (w / 2)) / w); + } else { + SetPosInternal(start + lround((stop - start) * float(point.x - r.left) / w)); + } + } + } + m_bDrag = true; + if (AppIsThemeLoaded() && modernStyle) { + if (themedToolTip.m_hWnd) { + TOOLINFO ti = { sizeof(TOOLINFO) }; + ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_ABSOLUTE; + ti.hwnd = m_hWnd; + ti.uId = (UINT_PTR)m_hWnd; + ti.hinst = AfxGetInstanceHandle(); + ti.lpszText = LPSTR_TEXTCALLBACK; + + themedToolTip.SendMessage(TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti); + } + + updateModernVolCtrl(point); + SetCapture(); + } else { + invalidateThumb(); + CSliderCtrl::OnLButtonDown(nFlags, point); + } +} + +void CVolumeCtrl::OnSetFocus(CWnd* pOldWnd) +{ + CSliderCtrl::OnSetFocus(pOldWnd); + + AfxGetMainWnd()->SetFocus(); // don't focus on us, parents will take care of our positioning +} + +void CVolumeCtrl::HScroll(UINT nSBCode, UINT nPos) +{ + auto &s = AfxGetAppSettings(); + auto oldVolume = s.nVolume; + s.nVolume = GetPos(); + + CFrameWnd* pFrame = GetParentFrame(); + if (pFrame && pFrame != GetParent()) { + pFrame->PostMessage(WM_HSCROLL, MAKEWPARAM(static_cast(nPos), static_cast(nSBCode)), reinterpret_cast(m_hWnd)); + if (s.nVolume != oldVolume) { + CRect r; + getCustomChannelRect(r); + InvalidateRect(r); //needed to redraw the volume text + } + } +} + +BOOL CVolumeCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_HAND)); + return TRUE; +} + +BOOL CVolumeCtrl::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) +{ + TOOLTIPTEXT* pTTT = reinterpret_cast(pNMHDR); + CString str; + str.Format(IDS_VOLUME, GetPos()); + _tcscpy_s(pTTT->szText, str); + pTTT->hinst = nullptr; + + *pResult = 0; + + return TRUE; +} + +BOOL CVolumeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) +{ + if (zDelta > 0) { + IncreaseVolume(); + } else if (zDelta < 0) { + DecreaseVolume(); + } else { + return FALSE; + } + return TRUE; +} + +void CVolumeCtrl::invalidateThumb() +{ + if (!(AppIsThemeLoaded() && modernStyle)) { + SetRangeMax(100, TRUE); + } +} + + +void CVolumeCtrl::checkHover(CPoint point) +{ + CRect thumbRect; + GetThumbRect(thumbRect); + bool oldHover = m_bHover; + m_bHover = false; + if (thumbRect.PtInRect(point)) { + m_bHover = true; + } + + if (m_bHover != oldHover) { + invalidateThumb(); + } +} + +void CVolumeCtrl::updateModernVolCtrl(CPoint point) +{ + //CSliderCtrl::OnMouseMove yields bad results due to assumption of thumb width + //we must do all position calculation ourselves, and send correct position to tooltip + + CRect r; + GetChannelRect(&r); + + int start, stop; + GetRange(start, stop); + int useX; + if (point.x < r.left) { + SetPosInternal(start); + useX = r.left; + } else if (point.x >= r.right) { + SetPosInternal(stop); + useX = r.right; + } else { + int w = r.right - r.left; + if (start < stop) { + SetPosInternal(start + lround((stop - start) * float(point.x - r.left) / w)); + } + useX = point.x; + } + POINT p = { useX, point.y }; + ClientToScreen(&p); + CRect ttRect; + if (themedToolTip.m_hWnd) { + CRect cr = r; + ClientToScreen(cr); + themedToolTip.GetWindowRect(ttRect); + p.y = cr.top - ttRect.Height(); + themedToolTip.SendMessage(TTM_TRACKPOSITION, 0, MAKELPARAM(p.x, p.y)); + } + + RECT ur; + getCustomChannelRect(&ur); + RedrawWindow(&ur, nullptr, RDW_INVALIDATE); //we must redraw the whole channel with the modern volume ctrl. by default only areas where thumb has been are invalidated +} + + +void CVolumeCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + checkHover(point); + + if (AppIsThemeLoaded() && modernStyle && m_bDrag) { + updateModernVolCtrl(point); + } else { + CSliderCtrl::OnMouseMove(nFlags, point); + } +} + + +void CVolumeCtrl::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (AppIsThemeLoaded() && modernStyle) { + if (m_bDrag) { + ReleaseCapture(); + } + m_bDrag = false; + if (themedToolTip.m_hWnd) { + themedToolTip.SendMessage(TTM_TRACKACTIVATE, FALSE, 0); + } + } else { + m_bDrag = false; + invalidateThumb(); + checkHover(point); + CSliderCtrl::OnLButtonUp(nFlags, point); + } +} + + +void CVolumeCtrl::OnMouseLeave() +{ + checkHover(CPoint(-1 - 1)); + CSliderCtrl::OnMouseLeave(); +} + + +void CVolumeCtrl::OnPaint() { + if (m_fSelfDrawn && AppIsThemeLoaded() && modernStyle) { + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + CPaintDC dc(this); + CRect r, cr; + GetClientRect(cr); + + CDC dcMem; + CBitmap bmMem; + CRect memRect = { 0, 0, cr.right, cr.bottom }; + CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, memRect); + + dcMem.FillSolidRect(&memRect, CMPCTheme::PlayerBGColor); + getCustomChannelRect(r); + //r.DeflateRect(0, dpiWindow.ScaleFloorY(3), 0, dpiWindow.ScaleFloorY(2)); + r.OffsetRect(-cr.TopLeft()); + + CRect filledRect, unfilledRect; + filledRect = r; + filledRect.right = r.left + lround(r.Width() * float(GetPos()) / 100); + dcMem.FillSolidRect(&filledRect, CMPCTheme::ScrollProgressColor); + + if (filledRect.right < r.right) { //do not fill bg if already full + unfilledRect = r; + unfilledRect.left = filledRect.right; + dcMem.FillSolidRect(&unfilledRect, CMPCTheme::ScrollBGColor); + } + + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dcMem.FrameRect(r, &fb); + fb.DeleteObject(); + + dcMem.SetTextColor(CMPCTheme::TextFGColor); + CFont f; + LOGFONT lf = { 0 }; + lf.lfHeight = r.Height(); + lf.lfQuality = CLEARTYPE_QUALITY; + wcscpy_s(lf.lfFaceName, L"Calibri"); + f.CreateFontIndirectW(&lf); + CFont* oldFont = (CFont*)dcMem.SelectObject(&f); + int oldMode = dcMem.SetBkMode(TRANSPARENT); + CStringW str; + str.Format(IDS_VOLUME, GetPos()); + dcMem.DrawTextW(str, r, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX); + dcMem.SelectObject(oldFont); + dcMem.SetBkMode(oldMode); + + CMPCThemeUtil::flushMemDC(&dc, dcMem, memRect); + } else { + __super::OnPaint(); //can trigger OnNMCustomdraw + } +} + +BOOL CVolumeCtrl::OnEraseBkgnd(CDC* pDC) { + if (m_fSelfDrawn && AppIsThemeLoaded() && modernStyle) { + return TRUE; + } else { + return CSliderCtrl::OnEraseBkgnd(pDC); + } +} diff --git a/src/mpc-hc/VolumeCtrl.h b/src/mpc-hc/VolumeCtrl.h index 40b35e7e68c..8cb18a11f51 100644 --- a/src/mpc-hc/VolumeCtrl.h +++ b/src/mpc-hc/VolumeCtrl.h @@ -1,66 +1,66 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2015 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 . - * - */ - -#pragma once -#include "CMPCThemeToolTipCtrl.h" - -// CVolumeCtrl - -class CVolumeCtrl : public CSliderCtrl -{ - DECLARE_DYNAMIC(CVolumeCtrl) - -private: - bool m_fSelfDrawn; - -public: - CVolumeCtrl(bool fSelfDrawn = true); - virtual ~CVolumeCtrl(); - - bool Create(CWnd* pParentWnd); - void IncreaseVolume(), DecreaseVolume(); - void SetPosInternal(int pos); - -protected: - afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); - void getCustomChannelRect(LPRECT rc); - void updateModernVolCtrl(CPoint point); - bool m_bDrag, m_bHover; - bool modernStyle; - CMPCThemeToolTipCtrl themedToolTip; - - DECLARE_MESSAGE_MAP() - -public: - afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnSetFocus(CWnd* pOldWnd); - afx_msg void HScroll(UINT nSBCode, UINT nPos); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint point); - void invalidateThumb(); - void checkHover(CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2015 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 . + * + */ + +#pragma once +#include "CMPCThemeToolTipCtrl.h" + +// CVolumeCtrl + +class CVolumeCtrl : public CSliderCtrl +{ + DECLARE_DYNAMIC(CVolumeCtrl) + +private: + bool m_fSelfDrawn; + +public: + CVolumeCtrl(bool fSelfDrawn = true); + virtual ~CVolumeCtrl(); + + bool Create(CWnd* pParentWnd); + void IncreaseVolume(), DecreaseVolume(); + void SetPosInternal(int pos); + +protected: + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + void getCustomChannelRect(LPRECT rc); + void updateModernVolCtrl(CPoint point); + bool m_bDrag, m_bHover; + bool modernStyle; + CMPCThemeToolTipCtrl themedToolTip; + + DECLARE_MESSAGE_MAP() + +public: + afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void HScroll(UINT nSBCode, UINT nPos); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint point); + void invalidateThumb(); + void checkHover(CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; diff --git a/src/mpc-hc/WebClientSocket.cpp b/src/mpc-hc/WebClientSocket.cpp index eea682390ab..5ca0f60c495 100644 --- a/src/mpc-hc/WebClientSocket.cpp +++ b/src/mpc-hc/WebClientSocket.cpp @@ -1,1018 +1,1018 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "resource.h" -#include "MainFrm.h" -#include "../Subtitles/TextFile.h" -#include "WebServer.h" -#include "WebClientSocket.h" -#include "text.h" -#include "PathUtils.h" - -#define MAX_HEADER_SIZE 512 * 1024 -#define MAX_DATA_SIZE 2 * 1024 * 1024 - -CWebClientSocket::CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame) - : m_pWebServer(pWebServer) - , m_pMainFrame(pMainFrame) - , m_buffLen(0) - , m_buffMaxLen(2048) - , m_buffLenProcessed(0) - , m_parsingState(PARSING_HEADER) - , m_dataLen(0) -{ - m_buff = DEBUG_NEW char[m_buffMaxLen]; -} - -CWebClientSocket::~CWebClientSocket() -{ - delete [] m_buff; -} - -bool CWebClientSocket::SetCookie(CStringA name, CString value, __time64_t expire, CString path, CString domain) -{ - if (name.IsEmpty()) { - return false; - } - if (value.IsEmpty()) { - m_cookie.RemoveKey(name); - return true; - } - - m_cookie[name] = value; - - m_cookieattribs[name].path = path; - m_cookieattribs[name].domain = domain; - - if (expire >= 0) { - CTime t(expire); - SYSTEMTIME st; - t.GetAsSystemTime(st); - CStringA str; - SystemTimeToHttpDate(st, str); - m_cookieattribs[name].expire = str; - } - - return true; -} - -void CWebClientSocket::Clear() -{ - m_buffLen = 0; - m_buffLenProcessed = 0; - - m_parsingState = PARSING_HEADER; - - m_dataLen = 0; - - m_hdrlines.RemoveAll(); - m_data.Empty(); - - m_cmd.Empty(); - m_path.Empty(); - m_ver.Empty(); - m_get.RemoveAll(); - m_post.RemoveAll(); - m_cookie.RemoveAll(); - m_request.RemoveAll(); -} - -void CWebClientSocket::HandleRequest() -{ - // remember new cookies - - CStringA cookie; - if (m_hdrlines.Lookup("cookie", cookie)) { - CAtlList sl; - Explode(cookie, sl, ';'); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - CAtlList sl2; - Explode(sl.GetNext(pos), sl2, '=', 2); - if (sl2.GetCount() == 2) { - m_cookie[sl2.GetHead()] = UTF8To16(sl2.GetTail()); - } else { - m_cookie[sl2.GetHead()].Empty(); - } - } - } - - // start new session - - if (!m_cookie.Lookup("MPCSESSIONID", m_sessid)) { - srand((unsigned int)time(nullptr)); - m_sessid.Format(_T("%08x"), rand() * 0x12345678); - SetCookie("MPCSESSIONID", m_sessid); - } else { - // TODO: load session - } - - CStringA reshdr, resbody; - - if (m_cmd == "GET" || m_cmd == "HEAD" || m_cmd == "POST") { - int i = m_path.Find('?'); - if (i >= 0) { - m_query = m_path.Mid(i + 1); - m_path.Truncate(i); - } - m_path = UrlDecode(m_path); - - if (!m_query.IsEmpty()) { - int j = m_query.Find('#'); - if (j >= 0) { - m_query.Truncate(j); - } - - CAtlList sl; - Explode(m_query, sl, '&'); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - CAtlList sl2; - Explode(sl.GetNext(pos), sl2, '=', 2); - if (sl2.GetCount() == 2) { - m_get[sl2.GetHead()] = UTF8To16(UrlDecode(sl2.GetTail())); - } else { - m_get[sl2.GetHead()] = _T(""); - } - } - } - - // m_request <-- m_get+m_post+m_cookie - { - CStringA key; - CString value; - POSITION pos; - pos = m_get.GetStartPosition(); - while (pos) { - m_get.GetNextAssoc(pos, key, value); - m_request[key] = value; - } - pos = m_post.GetStartPosition(); - while (pos) { - m_post.GetNextAssoc(pos, key, value); - m_request[key] = value; - } - pos = m_cookie.GetStartPosition(); - while (pos) { - m_cookie.GetNextAssoc(pos, key, value); - m_request[key] = value; - } - } - - m_pWebServer->OnRequest(this, reshdr, resbody); - } else { - reshdr = "HTTP/1.0 400 Bad Request\r\n"; - } - - if (!reshdr.IsEmpty()) { - // cookies - { - POSITION pos = m_cookie.GetStartPosition(); - while (pos) { - CStringA key; - CString value; - m_cookie.GetNextAssoc(pos, key, value); - reshdr += "Set-Cookie: " + key + "=" + TToA(value); - POSITION pos2 = m_cookieattribs.GetStartPosition(); - while (pos2) { - cookie_attribs attribs; - m_cookieattribs.GetNextAssoc(pos2, key, attribs); - if (!attribs.path.IsEmpty()) { - reshdr += "; path=" + attribs.path; - } - if (!attribs.expire.IsEmpty()) { - reshdr += "; expire=" + attribs.expire; - } - if (!attribs.domain.IsEmpty()) { - reshdr += "; domain=" + attribs.domain; - } - } - reshdr += "\r\n"; - } - } - - reshdr += - "Access-Control-Allow-Origin: *\r\n" - "Server: MPC-HC WebServer\r\n" - "Connection: close\r\n" - "\r\n"; - - Send(reshdr, reshdr.GetLength()); - - if (m_cmd != "HEAD" && reshdr.Find("HTTP/1.0 200 OK") == 0 && !resbody.IsEmpty()) { - Send(resbody, resbody.GetLength()); - } - - CStringA connection = "close"; - m_hdrlines.Lookup("connection", connection); - - Clear(); - - // TODO - // if (connection == _T("close")) - OnClose(0); - } -} - -void CWebClientSocket::ParseHeader(const char* headerEnd) -{ - char* start = m_buff, *end; - - // Parse the request type - end = strchr(start, ' '); - if (!end) { - ASSERT(false); - return; - } - m_cmd.SetString(start, int(end - start)); - m_cmd.MakeUpper(); - start = end + 1; - end = strchr(start, ' '); - if (!end) { - ASSERT(false); - return; - } - m_path.SetString(start, int(end - start)); - start = end + 1; - end = strstr(start, "\r\n"); - m_ver.SetString(start, int(end - start)); - m_ver.MakeUpper(); - - CStringA key, val; - start = end + 2; - while (start < headerEnd) { - // Parse the header fields - end = strchr(start, ':'); - key.SetString(start, int(end - start)); - start = end + 1; - end = strstr(start, "\r\n"); - val.SetString(start, int(end - start)); - start = end + 2; - - m_hdrlines[key.MakeLower()] = val; - } - - if (m_cmd == "POST") { - CStringA str; - if (m_hdrlines.Lookup("content-length", str)) { - m_dataLen = strtol(str, nullptr, 10); - } - } - m_parsingState = (m_dataLen > 0) ? PARSING_POST_DATA : PARSING_DONE; -} - -void CWebClientSocket::ParsePostData() -{ - char* start = m_buff, *end; - char* endData = m_buff + m_buffLen; - CStringA key, val; - - while (start < endData) { - end = strchr(start, '='); - if (!end) { - break; - } - key.SetString(start, int(end - start)); - start = end + 1; - end = strchr(start, '&'); - if (!end) { - end = endData; - } - val.SetString(start, int(end - start)); - start = end + 1; - - m_post[key.MakeLower()] = UTF8To16(UrlDecode(val)); - } - - m_parsingState = PARSING_DONE; -} -// - -void CWebClientSocket::OnReceive(int nErrorCode) -{ - if (nErrorCode == 0 && m_parsingState != PARSING_DONE) { - if (m_buffMaxLen - m_buffLen <= 1) { - char* buff = (char*)realloc(m_buff, 2 * m_buffMaxLen * sizeof(char)); - if (buff) { - m_buff = buff; - m_buffMaxLen *= 2; - } else { - ASSERT(0); - } - } - - int nRead = Receive(m_buff + m_buffLen, m_buffMaxLen - m_buffLen - 1); - if (nRead > 0) { - m_buffLen += nRead; - m_buff[m_buffLen] = '\0'; - - switch (m_parsingState) { - case PARSING_HEADER: { - // Search the header end - char* headerEnd = strstr(m_buff + m_buffLenProcessed, "\r\n\r\n"); - - if (headerEnd) { - ParseHeader(headerEnd); - if (m_dataLen > MAX_DATA_SIZE) { - // Refuse the connection if someone tries to send - // more than MAX_DATA_SIZE of size. - OnClose(0); - return; - } - - headerEnd += 4; - m_buffLen = std::max(int(m_buff + m_buffLen - headerEnd), 0); - if (m_buffLen > 0) { - memcpy(m_buff, headerEnd, m_buffLen + 1); - if (m_buffLen >= m_dataLen) { - ParsePostData(); - } - } - } else if (m_buffLen > MAX_HEADER_SIZE) { - // If we got more than MAX_HEADER_SIZE of data without finding - // the end of the header we close the connection. - OnClose(0); - return; - } else { - // Start next search from current end of the file - m_buffLenProcessed += nRead; - } - } - break; - case PARSING_POST_DATA: { - if (m_buffLen >= m_dataLen) { - ParsePostData(); - } - } - break; - } - - if (m_parsingState == PARSING_DONE) { - HandleRequest(); - } - } - } -} - -void CWebClientSocket::OnClose(int nErrorCode) -{ - // TODO: save session - m_pWebServer->OnClose(this); - __super::OnClose(nErrorCode); -} - -//////////////////// - -bool CWebClientSocket::OnCommand(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString arg; - if (m_request.Lookup("wm_command", arg)) { - int id = _ttol(arg); - - if (id > 0) { - if (id == ID_FILE_EXIT) { - m_pMainFrame->PostMessage(WM_COMMAND, id); - } else { - m_pMainFrame->SendMessage(WM_COMMAND, id); - } - } else { - if (arg == _T(CMD_SETPOS) && m_request.Lookup("position", arg)) { - int h, m, s, ms = 0; - TCHAR c; - if (_stscanf_s(arg, _T("%d%c%d%c%d%c%d"), &h, &c, 1, &m, &c, 1, &s, &c, 1, &ms) >= 5) { - REFERENCE_TIME rtPos = 10000i64 * (((h * 60 + m) * 60 + s) * 1000 + ms); - m_pMainFrame->SeekTo(rtPos); - for (int retries = 20; retries-- > 0; Sleep(50)) { - if (abs((int)((rtPos - m_pMainFrame->GetPos()) / 10000)) < 100) { - break; - } - } - } - } else if (arg == _T(CMD_SETPOS) && m_request.Lookup("percent", arg)) { - float percent = 0; - if (_stscanf_s(arg, _T("%f"), &percent) == 1) { - m_pMainFrame->SeekTo((REFERENCE_TIME)(percent / 100 * m_pMainFrame->GetDur())); - } - } else if (arg == _T(CMD_SETVOLUME) && m_request.Lookup("volume", arg)) { - int volume = _tcstol(arg, nullptr, 10); - m_pMainFrame->m_wndToolBar.Volume = std::min(std::max(volume, 0), 100); - m_pMainFrame->OnPlayVolume(0); - } - } - } - - CStringA ref; - if (!m_hdrlines.Lookup("referer", ref)) { - return true; - } - - hdr = - "HTTP/1.0 302 Found\r\n" - "Location: " + ref + "\r\n"; - - return true; -} - -bool CWebClientSocket::OnIndex(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CStringA wmcoptions; - - // generate page - - const CAppSettings& s = AfxGetAppSettings(); - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - CStringA str; - str.Format("%u", wc.cmd); - CStringA valueName(UTF8(wc.GetName())); - valueName.Replace("&", "&"); - wmcoptions += "\r\n"; - } - - m_pWebServer->LoadPage(IDR_HTML_INDEX, body, AToT(m_path)); - body.Replace("[wmcoptions]", wmcoptions); - - return true; -} - -bool CWebClientSocket::OnInfo(CStringA& hdr, CStringA& body, CStringA& mime) -{ - m_pWebServer->LoadPage(IDR_HTML_INFO, body, AToT(m_path)); - body.Replace("[version]", UTF8(AfxGetMyApp()->m_strVersion)); - body.Replace("[file]", UTF8(m_pMainFrame->GetFileName())); - body.Replace("[position]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); - body.Replace("[duration]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); - body.Replace("[size]", UTF8(GetSize())); - return true; -} - -bool CWebClientSocket::OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CAtlList rootdrives; - for (TCHAR drive[] = _T("A:"); drive[0] <= _T('Z'); drive[0]++) { - if (GetDriveType(drive) != DRIVE_NO_ROOT_DIR) { - rootdrives.AddTail(CStringA(drive) + '\\'); - } - } - // process GET - - CString path; - CFileStatus fs; - if (m_get.Lookup("path", path)) { - if (!PathUtils::IsURL(path) && CFileGetStatus(path, fs) && !(fs.m_attribute & CFile::directory)) { - // TODO: make a new message for just opening files, this is a bit overkill now... - - CAtlList cmdln; - - cmdln.AddTail(path); - - CString focus; - if (m_get.Lookup("focus", focus) && !focus.CompareNoCase(_T("no"))) { - cmdln.AddTail(_T("/nofocus")); - } - - int len = 0; - - POSITION pos = cmdln.GetHeadPosition(); - while (pos) { - CString& str = cmdln.GetNext(pos); - len += (str.GetLength() + 1) * sizeof(TCHAR); - } - - CAutoVectorPtr buff; - if (buff.Allocate(4 + len)) { - BYTE* p = buff; - *(DWORD*)p = (DWORD)cmdln.GetCount(); - p += sizeof(DWORD); - - pos = cmdln.GetHeadPosition(); - while (pos) { - CString& str = cmdln.GetNext(pos); - len = (str.GetLength() + 1) * sizeof(TCHAR); - memcpy(p, (LPCTSTR)str, len); - p += len; - } - - COPYDATASTRUCT cds; - cds.dwData = 0x6ABE51; - cds.cbData = DWORD(p - buff); - cds.lpData = (void*)(BYTE*)buff; - m_pMainFrame->SendMessage(WM_COPYDATA, (WPARAM)nullptr, (LPARAM)&cds); - } - - CPath p(path); - p.RemoveFileSpec(); - path = (LPCTSTR)p; - } - } else { - path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); - - if (!PathUtils::IsURL(path) && CFileGetStatus(path, fs) && !(fs.m_attribute & CFile::directory)) { - CPath p(path); - p.RemoveFileSpec(); - path = (LPCTSTR)p; - } - } - - if (PathUtils::IsURL(path)) { - path.Empty(); - } - - if (!path.IsEmpty() && CFileGetStatus(path, fs) && (fs.m_attribute & CFile::directory) - || path.Find(_T("\\")) == 0) { // FIXME - CPath p(path); - p.Canonicalize(); - p.MakePretty(); - p.AddBackslash(); - path = (LPCTSTR)p; - } - - CStringA files; - - if (path.IsEmpty()) { - POSITION pos = rootdrives.GetHeadPosition(); - while (pos) { - CStringA& drive = rootdrives.GetNext(pos); - - files += "\r\n"; - files += - "" + drive + "\r\n" - "Directory\r\n" - " \r\n" - " \r\n"; - files += "\r\n"; - } - - path = _T("Root"); - } else { - CString parent; - - if (path.GetLength() > 3) { - CPath p(path + ".."); - p.Canonicalize(); - p.AddBackslash(); - parent = (LPCTSTR)p; - } - - files += "\r\n"; - files += - "..\r\n" - "Directory\r\n" - " \r\n" - " \r\n"; - files += "\r\n"; - - WIN32_FIND_DATA fd; - ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); - - HANDLE hFind = FindFirstFile(path + "*.*", &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || fd.cFileName[0] == '.') { - continue; - } - - CString fullpath = path + fd.cFileName; - - files += "\r\n"; - files += - "" + UTF8(fd.cFileName) + "\r\n" - "Directory\r\n" - " \r\n" - "" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "\r\n"; - files += "\r\n"; - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - - hFind = FindFirstFile(path + "*.*", &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - continue; - } - - CString fullpath = path + fd.cFileName; - TCHAR* ext = _tcsrchr(fd.cFileName, '.'); - if (ext != nullptr) { - ext++; - } - - CStringA size; - size.Format("%I64uK", ((UINT64)fd.nFileSizeHigh << 22) | (fd.nFileSizeLow >> 10)); - - CString type(_T(" ")); - LoadType(fullpath, type); - - if (ext != nullptr) { - files += "\r\n"; - } else { - files += "\r\n"; - } - files += - "" + UTF8(fd.cFileName) + "\r\n" - "" + UTF8(type) + "\r\n" - "" + size + "\r\n" - "" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "\r\n"; - files += "\r\n"; - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - } - - m_pWebServer->LoadPage(IDR_HTML_BROWSER, body, AToT(m_path)); - body.Replace("[currentdir]", HtmlSpecialChars(UTF8(path))); - body.Replace("[currentfiles]", files); - - return true; -} - -bool CWebClientSocket::OnControls(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); - CString dir; - - if (!path.IsEmpty() && !PathUtils::IsURL(path)) { - CPath p(path); - p.RemoveFileSpec(); - dir = (LPCTSTR)p; - } - - OAFilterState fs = m_pMainFrame->GetMediaState(); - CString state; - state.Format(_T("%d"), fs); - CString statestring; - switch (fs) { - case State_Stopped: - statestring.LoadString(IDS_CONTROLS_STOPPED); - break; - case State_Paused: - statestring.LoadString(IDS_CONTROLS_PAUSED); - break; - case State_Running: - statestring.LoadString(IDS_CONTROLS_PLAYING); - break; - default: - statestring = _T("N/A"); - break; - } - - CString volumelevel, muted; - volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos()); - muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0); - - CString reloadtime(_T("0")); // TODO - - m_pWebServer->LoadPage(IDR_HTML_CONTROLS, body, AToT(m_path)); - body.Replace("[filepatharg]", UTF8Arg(path)); - body.Replace("[filepath]", UTF8(path)); - body.Replace("[filedirarg]", UTF8Arg(dir)); - body.Replace("[filedir]", UTF8(dir)); - body.Replace("[state]", UTF8(state)); - body.Replace("[statestring]", UTF8(statestring)); - body.Replace("[position]", UTF8(NumToCString(std::lround(m_pMainFrame->GetPos() / 10000i64)))); - body.Replace("[positionstring]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); - body.Replace("[duration]", UTF8(NumToCString(std::lround(m_pMainFrame->GetDur() / 10000i64)))); - body.Replace("[durationstring]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); - body.Replace("[volumelevel]", UTF8(volumelevel)); - body.Replace("[muted]", UTF8(muted)); - body.Replace("[playbackrate]", UTF8(NumToCString(m_pMainFrame->GetPlayingRate()))); - body.Replace("[reloadtime]", UTF8(reloadtime)); - - return true; -} - -bool CWebClientSocket::OnVariables(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); - CString dir; - CString strName; - - if (!path.IsEmpty() && !PathUtils::IsURL(path)) { - CPath p(path); - p.RemoveFileSpec(); - dir = (LPCTSTR)p; - } - - OAFilterState fs = m_pMainFrame->GetMediaState(); - CString state; - state.Format(_T("%d"), fs); - CString statestring; - switch (fs) { - case State_Stopped: - statestring.LoadString(IDS_CONTROLS_STOPPED); - break; - case State_Paused: - statestring.LoadString(IDS_CONTROLS_PAUSED); - break; - case State_Running: - statestring.LoadString(IDS_CONTROLS_PLAYING); - break; - default: - statestring = _T("N/A"); - break; - } - - CString volumelevel, muted; - volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos()); - muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0); - - CString reloadtime(_T("0")); // TODO - - m_pWebServer->LoadPage(IDR_HTML_VARIABLES, body, AToT(m_path)); - body.Replace("[file]", UTF8(m_pMainFrame->GetFileName())); - body.Replace("[filepatharg]", UTF8Arg(path)); - body.Replace("[filepath]", UTF8(path)); - body.Replace("[filedirarg]", UTF8Arg(dir)); - body.Replace("[filedir]", UTF8(dir)); - body.Replace("[state]", UTF8(state)); - body.Replace("[statestring]", UTF8(statestring)); - body.Replace("[position]", UTF8(NumToCString(std::lround(m_pMainFrame->GetPos() / 10000i64)))); - body.Replace("[positionstring]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); - body.Replace("[duration]", UTF8(NumToCString(std::lround(m_pMainFrame->GetDur() / 10000i64)))); - body.Replace("[durationstring]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); - body.Replace("[volumelevel]", UTF8(volumelevel)); - body.Replace("[muted]", UTF8(muted)); - body.Replace("[playbackrate]", UTF8(NumToCString(m_pMainFrame->GetPlayingRate()))); - body.Replace("[size]", UTF8(GetSize())); - body.Replace("[reloadtime]", UTF8(reloadtime)); - body.Replace("[version]", UTF8(AfxGetMyApp()->m_strVersion)); - m_pMainFrame->GetCurrentAudioTrackIdx(&strName); - body.Replace("[audiotrack]", UTF8(strName)); - m_pMainFrame->GetCurrentSubtitleTrackIdx(&strName); - body.Replace("[subtitletrack]", UTF8(strName)); - - return true; -} - -bool CWebClientSocket::OnStatus(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString title; - m_pMainFrame->GetWindowText(title); - - CPath file(m_pMainFrame->m_wndPlaylistBar.GetCurFileName()); - - CString status; - OAFilterState fs = m_pMainFrame->GetMediaState(); - switch (fs) { - case State_Stopped: - status.LoadString(IDS_CONTROLS_STOPPED); - break; - case State_Paused: - status.LoadString(IDS_CONTROLS_PAUSED); - break; - case State_Running: - status.LoadString(IDS_CONTROLS_PLAYING); - break; - default: - status = _T("N/A"); - break; - } - - REFERENCE_TIME pos = m_pMainFrame->GetPos(); - REFERENCE_TIME dur = m_pMainFrame->GetDur(); - - title.Replace(_T("'"), _T("\\'")); - status.Replace(_T("'"), _T("\\'")); - - body.Format("OnStatus(\"%s\", \"%s\", %ld, \"%s\", %ld, \"%s\", %d, %d, \"%s\")", // , \"%s\" - UTF8(title).GetString(), UTF8(status).GetString(), - std::lround(pos / 10000i64), UTF8(ReftimeToString2(pos)).GetString(), - std::lround(dur / 10000i64), UTF8(ReftimeToString2(dur)).GetString(), - m_pMainFrame->IsMuted(), m_pMainFrame->GetVolume(), - UTF8(file).GetString()/*, UTF8(dir)*/); - - return true; -} - -bool CWebClientSocket::OnError404(CStringA& hdr, CStringA& body, CStringA& mime) -{ - m_pWebServer->LoadPage(IDR_HTML_404, body, AToT(m_path)); - return true; -} - -bool CWebClientSocket::OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime) -{ - m_pWebServer->LoadPage(IDR_HTML_PLAYER, body, AToT(m_path)); - if (AfxGetAppSettings().bWebUIEnablePreview) { - body.Replace("[preview]", - "\"snapshot\""); - } else { - body.Replace("[preview]", UTF8(StrRes(IDS_WEBUI_DISABLED_PREVIEW_MSG))); - } - return true; -} - -bool CWebClientSocket::OnSnapshotJpeg(CStringA& hdr, CStringA& body, CStringA& mime) -{ - // TODO: add quality control and return logo when nothing is loaded - - bool bRet = false; - - BYTE* pData = nullptr; - long size = 0; - if (!AfxGetAppSettings().bWebUIEnablePreview) { - hdr = "HTTP/1.0 403 Forbidden\r\n"; - bRet = true; - } else if (m_pMainFrame->GetDIB(&pData, size, true)) { - PBITMAPINFO bi = reinterpret_cast(pData); - PBITMAPINFOHEADER bih = &bi->bmiHeader; - - int bpp = bih->biBitCount; - if (bpp != 16 && bpp != 24 && bpp != 32) { - return false; - } - int w = bih->biWidth; - int h = abs(bih->biHeight); - BYTE* p = DEBUG_NEW BYTE[w * h * 4]; - - const BYTE* src = pData + sizeof(*bih); - - int srcpitch = w * (bpp >> 3); - int dstpitch = w * 4; - - BitBltFromRGBToRGB(w, h, p, dstpitch, 32, (BYTE*)src + srcpitch * (h - 1), -srcpitch, bpp); - - { - CBitmap bmp; - bmp.CreateBitmap(w, h, bih->biPlanes, bpp, p); - delete [] p; - - CImage img; - img.Attach(bmp); - IStream* pStream = nullptr; - CByteArray ba; - if (SUCCEEDED(CreateStreamOnHGlobal(nullptr, TRUE, &pStream))) { - if (SUCCEEDED(img.Save(pStream, Gdiplus::ImageFormatJPEG))) { - ULARGE_INTEGER ulnSize; - LARGE_INTEGER lnOffset; - lnOffset.QuadPart = 0; - if (SUCCEEDED(pStream->Seek(lnOffset, STREAM_SEEK_END, &ulnSize))) { - if (SUCCEEDED(pStream->Seek(lnOffset, STREAM_SEEK_SET, 0))) { - ULONG ulBytesRead; - ba.SetSize((INT_PTR)ulnSize.QuadPart); - pStream->Read(ba.GetData(), (ULONG)ulnSize.QuadPart, &ulBytesRead); - } - } - } - } - - pStream->Release(); - delete [] pData; - - hdr += - "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" - "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" - "Pragma: no-cache\r\n"; - body = CStringA((char*)ba.GetData(), (int)ba.GetCount()); - mime = "image/jpeg"; - bRet = true; - } - } - - return bRet; -} - -bool CWebClientSocket::OnViewRes(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString id; - if (!m_get.Lookup("id", id)) { - return false; - } - - uintptr_t key = 0; - if (1 != _stscanf_s(id, _T("%Ix"), &key) || key == 0) { - return false; - } - - CAutoLock cAutoLock(&CDSMResource::m_csResources); - - CDSMResource* res = nullptr; - if (!CDSMResource::m_resources.Lookup(key, res) || !res) { - return false; - } - - body = CStringA((const char*)res->data.GetData(), (int)res->data.GetCount()); - mime = res->mime; - - return true; -} - -static CStringA GetChannelsJSON(const std::vector& channels) -{ - // begin the JSON object with the "channels" array inside - CStringA jsonChannels = "{ \"channels\" : ["; - - for (auto it = channels.begin(); it != channels.end();) { - // fill the array with individual channel objects - jsonChannels += it->ToJSON(); - if (++it == channels.end()) { - break; - } - jsonChannels += ","; - } - - // terminate the array and the object, and return. - jsonChannels += "] }"; - return jsonChannels; -} - -bool CWebClientSocket::OnDVBChannels(CStringA& hdr, CStringA& body, CStringA& mime) -{ - if (m_pMainFrame->GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - mime = "application/json"; - body = GetChannelsJSON(AfxGetAppSettings().m_DVBChannels); - } else { - // if we're not currently running the capture, report the service as - // unavailable and return. - hdr = "HTTP/1.0 503 Service Unavailable\r\n"; - } - - // the request is always "handled", successfully or not. - return true; -} - -bool CWebClientSocket::OnDVBSetChannel(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString requestParam; - int channelIdx; - if (m_pMainFrame->GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - // the 'idx' GET parameter should contain a valid integer of the - // channel to switch to. - if (m_get.Lookup("idx", requestParam) - && _stscanf_s(requestParam, _T("%d"), &channelIdx) == 1 - && channelIdx >= 0) { - if (AfxGetAppSettings().FindChannelByPref(channelIdx)) { - m_pMainFrame->SendMessage(WM_COMMAND, channelIdx + ID_NAVIGATE_JUMPTO_SUBITEM_START); - } else { - // Return a 404 if requested channel number was not found. - hdr = "HTTP/1.0 404 Not Found\r\n"; - } - } else { - // invalid parameters. - hdr = "HTTP/1.0 400 Bad Request\r\n"; - } - } else { - // not running the capture - don't report channels. - hdr = "HTTP/1.0 503 Service Unavailable\r\n"; - } - return true; -} - -CString CWebClientSocket::GetSize() const -{ - CString sizeString; - LONGLONG size = 0; - - if (CComQIPtr pBF = m_pMainFrame->m_pFSF) { - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pAR = pPin) { - LONGLONG total, available; - if (SUCCEEDED(pAR->Length(&total, &available))) { - size = total; - break; - } - } - } - EndEnumPins; - } - - if (size == 0) { - WIN32_FIND_DATA wfd; - HANDLE hFind = FindFirstFile(m_pMainFrame->m_wndPlaylistBar.GetCurFileName(), &wfd); - if (hFind != INVALID_HANDLE_VALUE) { - FindClose(hFind); - size = (LONGLONG(wfd.nFileSizeHigh) << 32) | wfd.nFileSizeLow; - } - } - - const int MAX_FILE_SIZE_BUFFER = 65; - TCHAR szFileSize[MAX_FILE_SIZE_BUFFER]; - StrFormatByteSizeW(size, szFileSize, MAX_FILE_SIZE_BUFFER); - sizeString.Format(L"%s", szFileSize); - - return sizeString; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "resource.h" +#include "MainFrm.h" +#include "../Subtitles/TextFile.h" +#include "WebServer.h" +#include "WebClientSocket.h" +#include "text.h" +#include "PathUtils.h" + +#define MAX_HEADER_SIZE 512 * 1024 +#define MAX_DATA_SIZE 2 * 1024 * 1024 + +CWebClientSocket::CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame) + : m_pWebServer(pWebServer) + , m_pMainFrame(pMainFrame) + , m_buffLen(0) + , m_buffMaxLen(2048) + , m_buffLenProcessed(0) + , m_parsingState(PARSING_HEADER) + , m_dataLen(0) +{ + m_buff = DEBUG_NEW char[m_buffMaxLen]; +} + +CWebClientSocket::~CWebClientSocket() +{ + delete [] m_buff; +} + +bool CWebClientSocket::SetCookie(CStringA name, CString value, __time64_t expire, CString path, CString domain) +{ + if (name.IsEmpty()) { + return false; + } + if (value.IsEmpty()) { + m_cookie.RemoveKey(name); + return true; + } + + m_cookie[name] = value; + + m_cookieattribs[name].path = path; + m_cookieattribs[name].domain = domain; + + if (expire >= 0) { + CTime t(expire); + SYSTEMTIME st; + t.GetAsSystemTime(st); + CStringA str; + SystemTimeToHttpDate(st, str); + m_cookieattribs[name].expire = str; + } + + return true; +} + +void CWebClientSocket::Clear() +{ + m_buffLen = 0; + m_buffLenProcessed = 0; + + m_parsingState = PARSING_HEADER; + + m_dataLen = 0; + + m_hdrlines.RemoveAll(); + m_data.Empty(); + + m_cmd.Empty(); + m_path.Empty(); + m_ver.Empty(); + m_get.RemoveAll(); + m_post.RemoveAll(); + m_cookie.RemoveAll(); + m_request.RemoveAll(); +} + +void CWebClientSocket::HandleRequest() +{ + // remember new cookies + + CStringA cookie; + if (m_hdrlines.Lookup("cookie", cookie)) { + CAtlList sl; + Explode(cookie, sl, ';'); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + CAtlList sl2; + Explode(sl.GetNext(pos), sl2, '=', 2); + if (sl2.GetCount() == 2) { + m_cookie[sl2.GetHead()] = UTF8To16(sl2.GetTail()); + } else { + m_cookie[sl2.GetHead()].Empty(); + } + } + } + + // start new session + + if (!m_cookie.Lookup("MPCSESSIONID", m_sessid)) { + srand((unsigned int)time(nullptr)); + m_sessid.Format(_T("%08x"), rand() * 0x12345678); + SetCookie("MPCSESSIONID", m_sessid); + } else { + // TODO: load session + } + + CStringA reshdr, resbody; + + if (m_cmd == "GET" || m_cmd == "HEAD" || m_cmd == "POST") { + int i = m_path.Find('?'); + if (i >= 0) { + m_query = m_path.Mid(i + 1); + m_path.Truncate(i); + } + m_path = UrlDecode(m_path); + + if (!m_query.IsEmpty()) { + int j = m_query.Find('#'); + if (j >= 0) { + m_query.Truncate(j); + } + + CAtlList sl; + Explode(m_query, sl, '&'); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + CAtlList sl2; + Explode(sl.GetNext(pos), sl2, '=', 2); + if (sl2.GetCount() == 2) { + m_get[sl2.GetHead()] = UTF8To16(UrlDecode(sl2.GetTail())); + } else { + m_get[sl2.GetHead()] = _T(""); + } + } + } + + // m_request <-- m_get+m_post+m_cookie + { + CStringA key; + CString value; + POSITION pos; + pos = m_get.GetStartPosition(); + while (pos) { + m_get.GetNextAssoc(pos, key, value); + m_request[key] = value; + } + pos = m_post.GetStartPosition(); + while (pos) { + m_post.GetNextAssoc(pos, key, value); + m_request[key] = value; + } + pos = m_cookie.GetStartPosition(); + while (pos) { + m_cookie.GetNextAssoc(pos, key, value); + m_request[key] = value; + } + } + + m_pWebServer->OnRequest(this, reshdr, resbody); + } else { + reshdr = "HTTP/1.0 400 Bad Request\r\n"; + } + + if (!reshdr.IsEmpty()) { + // cookies + { + POSITION pos = m_cookie.GetStartPosition(); + while (pos) { + CStringA key; + CString value; + m_cookie.GetNextAssoc(pos, key, value); + reshdr += "Set-Cookie: " + key + "=" + TToA(value); + POSITION pos2 = m_cookieattribs.GetStartPosition(); + while (pos2) { + cookie_attribs attribs; + m_cookieattribs.GetNextAssoc(pos2, key, attribs); + if (!attribs.path.IsEmpty()) { + reshdr += "; path=" + attribs.path; + } + if (!attribs.expire.IsEmpty()) { + reshdr += "; expire=" + attribs.expire; + } + if (!attribs.domain.IsEmpty()) { + reshdr += "; domain=" + attribs.domain; + } + } + reshdr += "\r\n"; + } + } + + reshdr += + "Access-Control-Allow-Origin: *\r\n" + "Server: MPC-HC WebServer\r\n" + "Connection: close\r\n" + "\r\n"; + + Send(reshdr, reshdr.GetLength()); + + if (m_cmd != "HEAD" && reshdr.Find("HTTP/1.0 200 OK") == 0 && !resbody.IsEmpty()) { + Send(resbody, resbody.GetLength()); + } + + CStringA connection = "close"; + m_hdrlines.Lookup("connection", connection); + + Clear(); + + // TODO + // if (connection == _T("close")) + OnClose(0); + } +} + +void CWebClientSocket::ParseHeader(const char* headerEnd) +{ + char* start = m_buff, *end; + + // Parse the request type + end = strchr(start, ' '); + if (!end) { + ASSERT(false); + return; + } + m_cmd.SetString(start, int(end - start)); + m_cmd.MakeUpper(); + start = end + 1; + end = strchr(start, ' '); + if (!end) { + ASSERT(false); + return; + } + m_path.SetString(start, int(end - start)); + start = end + 1; + end = strstr(start, "\r\n"); + m_ver.SetString(start, int(end - start)); + m_ver.MakeUpper(); + + CStringA key, val; + start = end + 2; + while (start < headerEnd) { + // Parse the header fields + end = strchr(start, ':'); + key.SetString(start, int(end - start)); + start = end + 1; + end = strstr(start, "\r\n"); + val.SetString(start, int(end - start)); + start = end + 2; + + m_hdrlines[key.MakeLower()] = val; + } + + if (m_cmd == "POST") { + CStringA str; + if (m_hdrlines.Lookup("content-length", str)) { + m_dataLen = strtol(str, nullptr, 10); + } + } + m_parsingState = (m_dataLen > 0) ? PARSING_POST_DATA : PARSING_DONE; +} + +void CWebClientSocket::ParsePostData() +{ + char* start = m_buff, *end; + char* endData = m_buff + m_buffLen; + CStringA key, val; + + while (start < endData) { + end = strchr(start, '='); + if (!end) { + break; + } + key.SetString(start, int(end - start)); + start = end + 1; + end = strchr(start, '&'); + if (!end) { + end = endData; + } + val.SetString(start, int(end - start)); + start = end + 1; + + m_post[key.MakeLower()] = UTF8To16(UrlDecode(val)); + } + + m_parsingState = PARSING_DONE; +} +// + +void CWebClientSocket::OnReceive(int nErrorCode) +{ + if (nErrorCode == 0 && m_parsingState != PARSING_DONE) { + if (m_buffMaxLen - m_buffLen <= 1) { + char* buff = (char*)realloc(m_buff, 2 * m_buffMaxLen * sizeof(char)); + if (buff) { + m_buff = buff; + m_buffMaxLen *= 2; + } else { + ASSERT(0); + } + } + + int nRead = Receive(m_buff + m_buffLen, m_buffMaxLen - m_buffLen - 1); + if (nRead > 0) { + m_buffLen += nRead; + m_buff[m_buffLen] = '\0'; + + switch (m_parsingState) { + case PARSING_HEADER: { + // Search the header end + char* headerEnd = strstr(m_buff + m_buffLenProcessed, "\r\n\r\n"); + + if (headerEnd) { + ParseHeader(headerEnd); + if (m_dataLen > MAX_DATA_SIZE) { + // Refuse the connection if someone tries to send + // more than MAX_DATA_SIZE of size. + OnClose(0); + return; + } + + headerEnd += 4; + m_buffLen = std::max(int(m_buff + m_buffLen - headerEnd), 0); + if (m_buffLen > 0) { + memcpy(m_buff, headerEnd, m_buffLen + 1); + if (m_buffLen >= m_dataLen) { + ParsePostData(); + } + } + } else if (m_buffLen > MAX_HEADER_SIZE) { + // If we got more than MAX_HEADER_SIZE of data without finding + // the end of the header we close the connection. + OnClose(0); + return; + } else { + // Start next search from current end of the file + m_buffLenProcessed += nRead; + } + } + break; + case PARSING_POST_DATA: { + if (m_buffLen >= m_dataLen) { + ParsePostData(); + } + } + break; + } + + if (m_parsingState == PARSING_DONE) { + HandleRequest(); + } + } + } +} + +void CWebClientSocket::OnClose(int nErrorCode) +{ + // TODO: save session + m_pWebServer->OnClose(this); + __super::OnClose(nErrorCode); +} + +//////////////////// + +bool CWebClientSocket::OnCommand(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString arg; + if (m_request.Lookup("wm_command", arg)) { + int id = _ttol(arg); + + if (id > 0) { + if (id == ID_FILE_EXIT) { + m_pMainFrame->PostMessage(WM_COMMAND, id); + } else { + m_pMainFrame->SendMessage(WM_COMMAND, id); + } + } else { + if (arg == _T(CMD_SETPOS) && m_request.Lookup("position", arg)) { + int h, m, s, ms = 0; + TCHAR c; + if (_stscanf_s(arg, _T("%d%c%d%c%d%c%d"), &h, &c, 1, &m, &c, 1, &s, &c, 1, &ms) >= 5) { + REFERENCE_TIME rtPos = 10000i64 * (((h * 60 + m) * 60 + s) * 1000 + ms); + m_pMainFrame->SeekTo(rtPos); + for (int retries = 20; retries-- > 0; Sleep(50)) { + if (abs((int)((rtPos - m_pMainFrame->GetPos()) / 10000)) < 100) { + break; + } + } + } + } else if (arg == _T(CMD_SETPOS) && m_request.Lookup("percent", arg)) { + float percent = 0; + if (_stscanf_s(arg, _T("%f"), &percent) == 1) { + m_pMainFrame->SeekTo((REFERENCE_TIME)(percent / 100 * m_pMainFrame->GetDur())); + } + } else if (arg == _T(CMD_SETVOLUME) && m_request.Lookup("volume", arg)) { + int volume = _tcstol(arg, nullptr, 10); + m_pMainFrame->m_wndToolBar.Volume = std::min(std::max(volume, 0), 100); + m_pMainFrame->OnPlayVolume(0); + } + } + } + + CStringA ref; + if (!m_hdrlines.Lookup("referer", ref)) { + return true; + } + + hdr = + "HTTP/1.0 302 Found\r\n" + "Location: " + ref + "\r\n"; + + return true; +} + +bool CWebClientSocket::OnIndex(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CStringA wmcoptions; + + // generate page + + const CAppSettings& s = AfxGetAppSettings(); + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + CStringA str; + str.Format("%u", wc.cmd); + CStringA valueName(UTF8(wc.GetName())); + valueName.Replace("&", "&"); + wmcoptions += "\r\n"; + } + + m_pWebServer->LoadPage(IDR_HTML_INDEX, body, AToT(m_path)); + body.Replace("[wmcoptions]", wmcoptions); + + return true; +} + +bool CWebClientSocket::OnInfo(CStringA& hdr, CStringA& body, CStringA& mime) +{ + m_pWebServer->LoadPage(IDR_HTML_INFO, body, AToT(m_path)); + body.Replace("[version]", UTF8(AfxGetMyApp()->m_strVersion)); + body.Replace("[file]", UTF8(m_pMainFrame->GetFileName())); + body.Replace("[position]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); + body.Replace("[duration]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); + body.Replace("[size]", UTF8(GetSize())); + return true; +} + +bool CWebClientSocket::OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CAtlList rootdrives; + for (TCHAR drive[] = _T("A:"); drive[0] <= _T('Z'); drive[0]++) { + if (GetDriveType(drive) != DRIVE_NO_ROOT_DIR) { + rootdrives.AddTail(CStringA(drive) + '\\'); + } + } + // process GET + + CString path; + CFileStatus fs; + if (m_get.Lookup("path", path)) { + if (!PathUtils::IsURL(path) && CFileGetStatus(path, fs) && !(fs.m_attribute & CFile::directory)) { + // TODO: make a new message for just opening files, this is a bit overkill now... + + CAtlList cmdln; + + cmdln.AddTail(path); + + CString focus; + if (m_get.Lookup("focus", focus) && !focus.CompareNoCase(_T("no"))) { + cmdln.AddTail(_T("/nofocus")); + } + + int len = 0; + + POSITION pos = cmdln.GetHeadPosition(); + while (pos) { + CString& str = cmdln.GetNext(pos); + len += (str.GetLength() + 1) * sizeof(TCHAR); + } + + CAutoVectorPtr buff; + if (buff.Allocate(4 + len)) { + BYTE* p = buff; + *(DWORD*)p = (DWORD)cmdln.GetCount(); + p += sizeof(DWORD); + + pos = cmdln.GetHeadPosition(); + while (pos) { + CString& str = cmdln.GetNext(pos); + len = (str.GetLength() + 1) * sizeof(TCHAR); + memcpy(p, (LPCTSTR)str, len); + p += len; + } + + COPYDATASTRUCT cds; + cds.dwData = 0x6ABE51; + cds.cbData = DWORD(p - buff); + cds.lpData = (void*)(BYTE*)buff; + m_pMainFrame->SendMessage(WM_COPYDATA, (WPARAM)nullptr, (LPARAM)&cds); + } + + CPath p(path); + p.RemoveFileSpec(); + path = (LPCTSTR)p; + } + } else { + path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); + + if (!PathUtils::IsURL(path) && CFileGetStatus(path, fs) && !(fs.m_attribute & CFile::directory)) { + CPath p(path); + p.RemoveFileSpec(); + path = (LPCTSTR)p; + } + } + + if (PathUtils::IsURL(path)) { + path.Empty(); + } + + if (!path.IsEmpty() && CFileGetStatus(path, fs) && (fs.m_attribute & CFile::directory) + || path.Find(_T("\\")) == 0) { // FIXME + CPath p(path); + p.Canonicalize(); + p.MakePretty(); + p.AddBackslash(); + path = (LPCTSTR)p; + } + + CStringA files; + + if (path.IsEmpty()) { + POSITION pos = rootdrives.GetHeadPosition(); + while (pos) { + CStringA& drive = rootdrives.GetNext(pos); + + files += "\r\n"; + files += + "" + drive + "\r\n" + "Directory\r\n" + " \r\n" + " \r\n"; + files += "\r\n"; + } + + path = _T("Root"); + } else { + CString parent; + + if (path.GetLength() > 3) { + CPath p(path + ".."); + p.Canonicalize(); + p.AddBackslash(); + parent = (LPCTSTR)p; + } + + files += "\r\n"; + files += + "..\r\n" + "Directory\r\n" + " \r\n" + " \r\n"; + files += "\r\n"; + + WIN32_FIND_DATA fd; + ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); + + HANDLE hFind = FindFirstFile(path + "*.*", &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || fd.cFileName[0] == '.') { + continue; + } + + CString fullpath = path + fd.cFileName; + + files += "\r\n"; + files += + "" + UTF8(fd.cFileName) + "\r\n" + "Directory\r\n" + " \r\n" + "" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "\r\n"; + files += "\r\n"; + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + + hFind = FindFirstFile(path + "*.*", &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + continue; + } + + CString fullpath = path + fd.cFileName; + TCHAR* ext = _tcsrchr(fd.cFileName, '.'); + if (ext != nullptr) { + ext++; + } + + CStringA size; + size.Format("%I64uK", ((UINT64)fd.nFileSizeHigh << 22) | (fd.nFileSizeLow >> 10)); + + CString type(_T(" ")); + LoadType(fullpath, type); + + if (ext != nullptr) { + files += "\r\n"; + } else { + files += "\r\n"; + } + files += + "" + UTF8(fd.cFileName) + "\r\n" + "" + UTF8(type) + "\r\n" + "" + size + "\r\n" + "" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "\r\n"; + files += "\r\n"; + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + } + + m_pWebServer->LoadPage(IDR_HTML_BROWSER, body, AToT(m_path)); + body.Replace("[currentdir]", HtmlSpecialChars(UTF8(path))); + body.Replace("[currentfiles]", files); + + return true; +} + +bool CWebClientSocket::OnControls(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); + CString dir; + + if (!path.IsEmpty() && !PathUtils::IsURL(path)) { + CPath p(path); + p.RemoveFileSpec(); + dir = (LPCTSTR)p; + } + + OAFilterState fs = m_pMainFrame->GetMediaState(); + CString state; + state.Format(_T("%d"), fs); + CString statestring; + switch (fs) { + case State_Stopped: + statestring.LoadString(IDS_CONTROLS_STOPPED); + break; + case State_Paused: + statestring.LoadString(IDS_CONTROLS_PAUSED); + break; + case State_Running: + statestring.LoadString(IDS_CONTROLS_PLAYING); + break; + default: + statestring = _T("N/A"); + break; + } + + CString volumelevel, muted; + volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos()); + muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0); + + CString reloadtime(_T("0")); // TODO + + m_pWebServer->LoadPage(IDR_HTML_CONTROLS, body, AToT(m_path)); + body.Replace("[filepatharg]", UTF8Arg(path)); + body.Replace("[filepath]", UTF8(path)); + body.Replace("[filedirarg]", UTF8Arg(dir)); + body.Replace("[filedir]", UTF8(dir)); + body.Replace("[state]", UTF8(state)); + body.Replace("[statestring]", UTF8(statestring)); + body.Replace("[position]", UTF8(NumToCString(std::lround(m_pMainFrame->GetPos() / 10000i64)))); + body.Replace("[positionstring]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); + body.Replace("[duration]", UTF8(NumToCString(std::lround(m_pMainFrame->GetDur() / 10000i64)))); + body.Replace("[durationstring]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); + body.Replace("[volumelevel]", UTF8(volumelevel)); + body.Replace("[muted]", UTF8(muted)); + body.Replace("[playbackrate]", UTF8(NumToCString(m_pMainFrame->GetPlayingRate()))); + body.Replace("[reloadtime]", UTF8(reloadtime)); + + return true; +} + +bool CWebClientSocket::OnVariables(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); + CString dir; + CString strName; + + if (!path.IsEmpty() && !PathUtils::IsURL(path)) { + CPath p(path); + p.RemoveFileSpec(); + dir = (LPCTSTR)p; + } + + OAFilterState fs = m_pMainFrame->GetMediaState(); + CString state; + state.Format(_T("%d"), fs); + CString statestring; + switch (fs) { + case State_Stopped: + statestring.LoadString(IDS_CONTROLS_STOPPED); + break; + case State_Paused: + statestring.LoadString(IDS_CONTROLS_PAUSED); + break; + case State_Running: + statestring.LoadString(IDS_CONTROLS_PLAYING); + break; + default: + statestring = _T("N/A"); + break; + } + + CString volumelevel, muted; + volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos()); + muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0); + + CString reloadtime(_T("0")); // TODO + + m_pWebServer->LoadPage(IDR_HTML_VARIABLES, body, AToT(m_path)); + body.Replace("[file]", UTF8(m_pMainFrame->GetFileName())); + body.Replace("[filepatharg]", UTF8Arg(path)); + body.Replace("[filepath]", UTF8(path)); + body.Replace("[filedirarg]", UTF8Arg(dir)); + body.Replace("[filedir]", UTF8(dir)); + body.Replace("[state]", UTF8(state)); + body.Replace("[statestring]", UTF8(statestring)); + body.Replace("[position]", UTF8(NumToCString(std::lround(m_pMainFrame->GetPos() / 10000i64)))); + body.Replace("[positionstring]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); + body.Replace("[duration]", UTF8(NumToCString(std::lround(m_pMainFrame->GetDur() / 10000i64)))); + body.Replace("[durationstring]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); + body.Replace("[volumelevel]", UTF8(volumelevel)); + body.Replace("[muted]", UTF8(muted)); + body.Replace("[playbackrate]", UTF8(NumToCString(m_pMainFrame->GetPlayingRate()))); + body.Replace("[size]", UTF8(GetSize())); + body.Replace("[reloadtime]", UTF8(reloadtime)); + body.Replace("[version]", UTF8(AfxGetMyApp()->m_strVersion)); + m_pMainFrame->GetCurrentAudioTrackIdx(&strName); + body.Replace("[audiotrack]", UTF8(strName)); + m_pMainFrame->GetCurrentSubtitleTrackIdx(&strName); + body.Replace("[subtitletrack]", UTF8(strName)); + + return true; +} + +bool CWebClientSocket::OnStatus(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString title; + m_pMainFrame->GetWindowText(title); + + CPath file(m_pMainFrame->m_wndPlaylistBar.GetCurFileName()); + + CString status; + OAFilterState fs = m_pMainFrame->GetMediaState(); + switch (fs) { + case State_Stopped: + status.LoadString(IDS_CONTROLS_STOPPED); + break; + case State_Paused: + status.LoadString(IDS_CONTROLS_PAUSED); + break; + case State_Running: + status.LoadString(IDS_CONTROLS_PLAYING); + break; + default: + status = _T("N/A"); + break; + } + + REFERENCE_TIME pos = m_pMainFrame->GetPos(); + REFERENCE_TIME dur = m_pMainFrame->GetDur(); + + title.Replace(_T("'"), _T("\\'")); + status.Replace(_T("'"), _T("\\'")); + + body.Format("OnStatus(\"%s\", \"%s\", %ld, \"%s\", %ld, \"%s\", %d, %d, \"%s\")", // , \"%s\" + UTF8(title).GetString(), UTF8(status).GetString(), + std::lround(pos / 10000i64), UTF8(ReftimeToString2(pos)).GetString(), + std::lround(dur / 10000i64), UTF8(ReftimeToString2(dur)).GetString(), + m_pMainFrame->IsMuted(), m_pMainFrame->GetVolume(), + UTF8(file).GetString()/*, UTF8(dir)*/); + + return true; +} + +bool CWebClientSocket::OnError404(CStringA& hdr, CStringA& body, CStringA& mime) +{ + m_pWebServer->LoadPage(IDR_HTML_404, body, AToT(m_path)); + return true; +} + +bool CWebClientSocket::OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime) +{ + m_pWebServer->LoadPage(IDR_HTML_PLAYER, body, AToT(m_path)); + if (AfxGetAppSettings().bWebUIEnablePreview) { + body.Replace("[preview]", + "\"snapshot\""); + } else { + body.Replace("[preview]", UTF8(StrRes(IDS_WEBUI_DISABLED_PREVIEW_MSG))); + } + return true; +} + +bool CWebClientSocket::OnSnapshotJpeg(CStringA& hdr, CStringA& body, CStringA& mime) +{ + // TODO: add quality control and return logo when nothing is loaded + + bool bRet = false; + + BYTE* pData = nullptr; + long size = 0; + if (!AfxGetAppSettings().bWebUIEnablePreview) { + hdr = "HTTP/1.0 403 Forbidden\r\n"; + bRet = true; + } else if (m_pMainFrame->GetDIB(&pData, size, true)) { + PBITMAPINFO bi = reinterpret_cast(pData); + PBITMAPINFOHEADER bih = &bi->bmiHeader; + + int bpp = bih->biBitCount; + if (bpp != 16 && bpp != 24 && bpp != 32) { + return false; + } + int w = bih->biWidth; + int h = abs(bih->biHeight); + BYTE* p = DEBUG_NEW BYTE[w * h * 4]; + + const BYTE* src = pData + sizeof(*bih); + + int srcpitch = w * (bpp >> 3); + int dstpitch = w * 4; + + BitBltFromRGBToRGB(w, h, p, dstpitch, 32, (BYTE*)src + srcpitch * (h - 1), -srcpitch, bpp); + + { + CBitmap bmp; + bmp.CreateBitmap(w, h, bih->biPlanes, bpp, p); + delete [] p; + + CImage img; + img.Attach(bmp); + IStream* pStream = nullptr; + CByteArray ba; + if (SUCCEEDED(CreateStreamOnHGlobal(nullptr, TRUE, &pStream))) { + if (SUCCEEDED(img.Save(pStream, Gdiplus::ImageFormatJPEG))) { + ULARGE_INTEGER ulnSize; + LARGE_INTEGER lnOffset; + lnOffset.QuadPart = 0; + if (SUCCEEDED(pStream->Seek(lnOffset, STREAM_SEEK_END, &ulnSize))) { + if (SUCCEEDED(pStream->Seek(lnOffset, STREAM_SEEK_SET, 0))) { + ULONG ulBytesRead; + ba.SetSize((INT_PTR)ulnSize.QuadPart); + pStream->Read(ba.GetData(), (ULONG)ulnSize.QuadPart, &ulBytesRead); + } + } + } + } + + pStream->Release(); + delete [] pData; + + hdr += + "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" + "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" + "Pragma: no-cache\r\n"; + body = CStringA((char*)ba.GetData(), (int)ba.GetCount()); + mime = "image/jpeg"; + bRet = true; + } + } + + return bRet; +} + +bool CWebClientSocket::OnViewRes(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString id; + if (!m_get.Lookup("id", id)) { + return false; + } + + uintptr_t key = 0; + if (1 != _stscanf_s(id, _T("%Ix"), &key) || key == 0) { + return false; + } + + CAutoLock cAutoLock(&CDSMResource::m_csResources); + + CDSMResource* res = nullptr; + if (!CDSMResource::m_resources.Lookup(key, res) || !res) { + return false; + } + + body = CStringA((const char*)res->data.GetData(), (int)res->data.GetCount()); + mime = res->mime; + + return true; +} + +static CStringA GetChannelsJSON(const std::vector& channels) +{ + // begin the JSON object with the "channels" array inside + CStringA jsonChannels = "{ \"channels\" : ["; + + for (auto it = channels.begin(); it != channels.end();) { + // fill the array with individual channel objects + jsonChannels += it->ToJSON(); + if (++it == channels.end()) { + break; + } + jsonChannels += ","; + } + + // terminate the array and the object, and return. + jsonChannels += "] }"; + return jsonChannels; +} + +bool CWebClientSocket::OnDVBChannels(CStringA& hdr, CStringA& body, CStringA& mime) +{ + if (m_pMainFrame->GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + mime = "application/json"; + body = GetChannelsJSON(AfxGetAppSettings().m_DVBChannels); + } else { + // if we're not currently running the capture, report the service as + // unavailable and return. + hdr = "HTTP/1.0 503 Service Unavailable\r\n"; + } + + // the request is always "handled", successfully or not. + return true; +} + +bool CWebClientSocket::OnDVBSetChannel(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString requestParam; + int channelIdx; + if (m_pMainFrame->GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + // the 'idx' GET parameter should contain a valid integer of the + // channel to switch to. + if (m_get.Lookup("idx", requestParam) + && _stscanf_s(requestParam, _T("%d"), &channelIdx) == 1 + && channelIdx >= 0) { + if (AfxGetAppSettings().FindChannelByPref(channelIdx)) { + m_pMainFrame->SendMessage(WM_COMMAND, channelIdx + ID_NAVIGATE_JUMPTO_SUBITEM_START); + } else { + // Return a 404 if requested channel number was not found. + hdr = "HTTP/1.0 404 Not Found\r\n"; + } + } else { + // invalid parameters. + hdr = "HTTP/1.0 400 Bad Request\r\n"; + } + } else { + // not running the capture - don't report channels. + hdr = "HTTP/1.0 503 Service Unavailable\r\n"; + } + return true; +} + +CString CWebClientSocket::GetSize() const +{ + CString sizeString; + LONGLONG size = 0; + + if (CComQIPtr pBF = m_pMainFrame->m_pFSF) { + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pAR = pPin) { + LONGLONG total, available; + if (SUCCEEDED(pAR->Length(&total, &available))) { + size = total; + break; + } + } + } + EndEnumPins; + } + + if (size == 0) { + WIN32_FIND_DATA wfd; + HANDLE hFind = FindFirstFile(m_pMainFrame->m_wndPlaylistBar.GetCurFileName(), &wfd); + if (hFind != INVALID_HANDLE_VALUE) { + FindClose(hFind); + size = (LONGLONG(wfd.nFileSizeHigh) << 32) | wfd.nFileSizeLow; + } + } + + const int MAX_FILE_SIZE_BUFFER = 65; + TCHAR szFileSize[MAX_FILE_SIZE_BUFFER]; + StrFormatByteSizeW(size, szFileSize, MAX_FILE_SIZE_BUFFER); + sizeString.Format(L"%s", szFileSize); + + return sizeString; +} diff --git a/src/mpc-hc/WebClientSocket.h b/src/mpc-hc/WebClientSocket.h index eccd24be3bf..e7c7e8338a7 100644 --- a/src/mpc-hc/WebClientSocket.h +++ b/src/mpc-hc/WebClientSocket.h @@ -1,85 +1,85 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -class CWebServer; - -class CWebClientSocket : public CAsyncSocket -{ - CWebServer* m_pWebServer; - CMainFrame* m_pMainFrame; - - char* m_buff; - int m_buffLen, m_buffMaxLen, m_buffLenProcessed; - - enum PARSING_STATE { - PARSING_HEADER, - PARSING_POST_DATA, - PARSING_DONE - }; - PARSING_STATE m_parsingState; - int m_dataLen; - - struct cookie_attribs { - CString path, expire, domain; - }; - CAtlStringMap m_cookieattribs; - - void Clear(); - void HandleRequest(); - void ParseHeader(const char* headerEnd); - void ParsePostData(); - -protected: - void OnReceive(int nErrorCode); - void OnClose(int nErrorCode); - -public: - CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame); - virtual ~CWebClientSocket(); - - bool SetCookie(CStringA name, CString value = _T(""), __time64_t expire = -1, CString path = _T("/"), CString domain = _T("")); - - CString m_sessid; - CStringA m_cmd, m_path, m_query, m_ver; - CStringA m_data; - CAtlStringMap m_hdrlines; - CAtlStringMap m_get, m_post, m_cookie; - CAtlStringMap m_request; - - bool OnCommand(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnIndex(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnInfo(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnControls(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnVariables(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnStatus(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnError404(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnSnapshotJpeg(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnViewRes(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnDVBChannels(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnDVBSetChannel(CStringA& hdr, CStringA& body, CStringA& mime); - -private: - CString GetSize() const; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +class CWebServer; + +class CWebClientSocket : public CAsyncSocket +{ + CWebServer* m_pWebServer; + CMainFrame* m_pMainFrame; + + char* m_buff; + int m_buffLen, m_buffMaxLen, m_buffLenProcessed; + + enum PARSING_STATE { + PARSING_HEADER, + PARSING_POST_DATA, + PARSING_DONE + }; + PARSING_STATE m_parsingState; + int m_dataLen; + + struct cookie_attribs { + CString path, expire, domain; + }; + CAtlStringMap m_cookieattribs; + + void Clear(); + void HandleRequest(); + void ParseHeader(const char* headerEnd); + void ParsePostData(); + +protected: + void OnReceive(int nErrorCode); + void OnClose(int nErrorCode); + +public: + CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame); + virtual ~CWebClientSocket(); + + bool SetCookie(CStringA name, CString value = _T(""), __time64_t expire = -1, CString path = _T("/"), CString domain = _T("")); + + CString m_sessid; + CStringA m_cmd, m_path, m_query, m_ver; + CStringA m_data; + CAtlStringMap m_hdrlines; + CAtlStringMap m_get, m_post, m_cookie; + CAtlStringMap m_request; + + bool OnCommand(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnIndex(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnInfo(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnControls(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnVariables(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnStatus(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnError404(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnSnapshotJpeg(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnViewRes(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnDVBChannels(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnDVBSetChannel(CStringA& hdr, CStringA& body, CStringA& mime); + +private: + CString GetSize() const; +}; diff --git a/src/mpc-hc/WebServer.cpp b/src/mpc-hc/WebServer.cpp index 3fe88be4ff7..b6d2ffb9ee5 100644 --- a/src/mpc-hc/WebServer.cpp +++ b/src/mpc-hc/WebServer.cpp @@ -1,715 +1,715 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "resource.h" -#include "MainFrm.h" -#include -#include "zlib/zlib.h" -#include "WebServerSocket.h" -#include "WebClientSocket.h" -#include "WebServer.h" -#include "VersionInfo.h" -#include "PathUtils.h" - - -CAtlStringMap CWebServer::m_internalpages; -CAtlStringMap CWebServer::m_downloads; -CAtlStringMap CWebServer::m_mimes; - -CWebServer::CWebServer(CMainFrame* pMainFrame, int nPort) - : m_pMainFrame(pMainFrame) - , m_nPort(nPort) -{ - m_webroot = CPath(PathUtils::GetProgramPath()); - const CAppSettings& s = AfxGetAppSettings(); - - CString WebRoot = s.strWebRoot; - WebRoot.Replace('/', '\\'); - WebRoot.Trim(); - CPath p(WebRoot); - if (WebRoot.Find(_T(":\\")) < 0 && WebRoot.Find(_T("\\\\")) < 0) { - m_webroot.Append(WebRoot); - } else { - m_webroot = p; - } - m_webroot.Canonicalize(); - m_webroot.MakePretty(); - if (!m_webroot.IsDirectory()) { - m_webroot = CPath(); - } - - CAtlList sl; - Explode(s.strWebServerCGI, sl, ';'); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - CAtlList sl2; - CString ext = Explode(sl.GetNext(pos), sl2, '=', 2); - if (sl2.GetCount() < 2) { - continue; - } - m_cgi[ext] = sl2.GetTail(); - } - - m_ThreadId = 0; - m_hThread = ::CreateThread(nullptr, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId); -} - -CWebServer::~CWebServer() -{ - if (m_hThread != nullptr) { - PostThreadMessage(m_ThreadId, WM_QUIT, (WPARAM)0, (LPARAM)0); - if (WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT) { - TerminateThread(m_hThread, 0xDEAD); - } - EXECUTE_ASSERT(CloseHandle(m_hThread)); - } -} - -void CWebServer::Init() -{ - m_internalpages["/"] = &CWebClientSocket::OnIndex; - m_internalpages["/404.html"] = &CWebClientSocket::OnError404; - m_internalpages["/browser.html"] = &CWebClientSocket::OnBrowser; - m_internalpages["/command.html"] = &CWebClientSocket::OnCommand; - m_internalpages["/controls.html"] = &CWebClientSocket::OnControls; - m_internalpages["/index.html"] = &CWebClientSocket::OnIndex; - m_internalpages["/info.html"] = &CWebClientSocket::OnInfo; - m_internalpages["/player.html"] = &CWebClientSocket::OnPlayer; - m_internalpages["/snapshot.jpg"] = &CWebClientSocket::OnSnapshotJpeg; - m_internalpages["/status.html"] = &CWebClientSocket::OnStatus; - m_internalpages["/variables.html"] = &CWebClientSocket::OnVariables; - m_internalpages["/viewres.html"] = &CWebClientSocket::OnViewRes; - m_internalpages["/dvb/channels.json"] = &CWebClientSocket::OnDVBChannels; - m_internalpages["/dvb/setchannel"] = &CWebClientSocket::OnDVBSetChannel; - - m_downloads["/default.css"] = IDF_DEFAULT_CSS; - m_downloads["/favicon.ico"] = IDF_FAVICON; - m_downloads["/img/1pix.png"] = IDF_1PIX_PNG; - m_downloads["/img/bottomside.png"] = IDF_BOTTOMSIDE_PNG; - m_downloads["/img/controlback.png"] = IDF_CONTROLBACK_PNG; - m_downloads["/img/controlbuttondecrate.png"] = IDF_CONTROLBUTTONDECRATE_PNG; - m_downloads["/img/controlbuttonincrate.png"] = IDF_CONTROLBUTTONINCRATE_PNG; - m_downloads["/img/controlbuttonpause.png"] = IDF_CONTROLBUTTONPAUSE_PNG; - m_downloads["/img/controlbuttonplay.png"] = IDF_CONTROLBUTTONPLAY_PNG; - m_downloads["/img/controlbuttonskipback.png"] = IDF_CONTROLBUTTONSKIPBACK_PNG; - m_downloads["/img/controlbuttonskipforward.png"] = IDF_CONTROLBUTTONSKIPFORWARD_PNG; - m_downloads["/img/controlbuttonstep.png"] = IDF_CONTROLBUTTONSTEP_PNG; - m_downloads["/img/controlbuttonstop.png"] = IDF_CONTROLBUTTONSTOP_PNG; - m_downloads["/img/controlvolumebar.png"] = IDF_CONTROLVOLUMEBAR_PNG; - m_downloads["/img/controlvolumegrip.png"] = IDF_CONTROLVOLUMEGRIP_PNG; - m_downloads["/img/controlvolumeoff.png"] = IDF_CONTROLVOLUMEOFF_PNG; - m_downloads["/img/controlvolumeon.png"] = IDF_CONTROLVOLUMEON_PNG; - m_downloads["/img/headerback.png"] = IDF_HEADERBACK_PNG; - m_downloads["/img/headerclose.png"] = IDF_HEADERCLOSE_PNG; - m_downloads["/img/headericon.png"] = IDF_HEADERICON_PNG; - m_downloads["/img/leftbottomside.png"] = IDF_LEFTBOTTOMSIDE_PNG; - m_downloads["/img/leftside.png"] = IDF_LEFTSIDE_PNG; - m_downloads["/img/rightbottomside.png"] = IDF_RIGHTBOTTOMSIDE_PNG; - m_downloads["/img/rightside.png"] = IDF_RIGHTSIDE_PNG; - m_downloads["/img/seekbargrip.png"] = IDF_SEEKBARGRIP_PNG; - m_downloads["/img/seekbarleft.png"] = IDF_SEEKBARLEFT_PNG; - m_downloads["/img/seekbarmid.png"] = IDF_SEEKBARMID_PNG; - m_downloads["/img/seekbarright.png"] = IDF_SEEKBARRIGHT_PNG; - m_downloads["/img/sliderback.png"] = IDF_SLIDERBACK_PNG; - m_downloads["/img/slidergrip.png"] = IDF_SLIDERGRIP_PNG; - m_downloads["/img/vbg.png"] = IDF_VBR_PNG; - m_downloads["/img/vbs.png"] = IDF_VBS_PNG; - m_downloads["/javascript.js"] = IDF_JAVASCRIPT; - -#if 0 - CRegKey key; - CString str(_T("MIME\\Database\\Content Type")); - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, str, KEY_READ)) { - TCHAR buff[256]; - DWORD len = _countof(buff); - for (int i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len); i++, len = _countof(buff)) { - CRegKey mime; - TCHAR ext[64]; - ULONG len2 = _countof(ext); - if (ERROR_SUCCESS == mime.Open(HKEY_CLASSES_ROOT, str + _T("\\") + buff, KEY_READ) - && ERROR_SUCCESS == mime.QueryStringValue(_T("Extension"), ext, &len2)) { - m_mimes[CStringA(ext).MakeLower()] = CStringA(buff).MakeLower(); - } - } - } -#endif - - m_mimes[".bmp"] = "image/bmp"; - m_mimes[".css"] = "text/css"; - m_mimes[".gif"] = "image/gif"; - m_mimes[".htm"] = "text/html"; - m_mimes[".html"] = "text/html"; - m_mimes[".jpeg"] = "image/jpeg"; - m_mimes[".jpg"] = "image/jpeg"; - m_mimes[".js"] = "text/javascript"; - m_mimes[".json"] = "text/plain"; - m_mimes[".png"] = "image/png"; - m_mimes[".txt"] = "text/plain"; - m_mimes[".ico"] = "image/x-icon"; -} - -DWORD WINAPI CWebServer::StaticThreadProc(LPVOID lpParam) -{ - SetThreadName(DWORD(-1), "WebServer Thread"); - return ((CWebServer*)lpParam)->ThreadProc(); -} - -DWORD CWebServer::ThreadProc() -{ - if (!AfxSocketInit(nullptr)) { - return DWORD_ERROR; - } - - CWebServerSocket s(this, m_nPort); - - MSG msg; - while ((int)GetMessage(&msg, nullptr, 0, 0) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return 0; -} - -static void PutFileContents(LPCTSTR fn, const CStringA& data) -{ - FILE* f = nullptr; - if (!_tfopen_s(&f, fn, _T("wb"))) { - fwrite((LPCSTR)data, 1, data.GetLength(), f); - fclose(f); - } -} - -void CWebServer::Deploy(CString dir) -{ - CStringA data; - if (LoadResource(IDR_HTML_INDEX, data, RT_HTML)) { - PutFileContents(dir + _T("index.html"), data); - } - if (LoadResource(IDR_HTML_INFO, data, RT_HTML)) { - PutFileContents(dir + _T("info.html"), data); - } - if (LoadResource(IDR_HTML_BROWSER, data, RT_HTML)) { - PutFileContents(dir + _T("browser.html"), data); - } - if (LoadResource(IDR_HTML_CONTROLS, data, RT_HTML)) { - PutFileContents(dir + _T("controls.html"), data); - } - if (LoadResource(IDR_HTML_VARIABLES, data, RT_HTML)) { - PutFileContents(dir + _T("variables.html"), data); - } - if (LoadResource(IDR_HTML_404, data, RT_HTML)) { - PutFileContents(dir + _T("404.html"), data); - } - if (LoadResource(IDR_HTML_PLAYER, data, RT_HTML)) { - PutFileContents(dir + _T("player.html"), data); - } - - // Create the needed folder - CreateDirectory(dir + _T("img"), nullptr); - - POSITION pos = m_downloads.GetStartPosition(); - while (pos) { - CStringA fn; - UINT id; - m_downloads.GetNextAssoc(pos, fn, id); - if (LoadResource(id, data, _T("FILE")) || LoadResource(id, data, _T("PNG"))) { - PutFileContents(dir + AToT(fn), data); - } - } -} - -bool CWebServer::ToLocalPath(CString& path, CString& redir) -{ - if (!path.IsEmpty() && m_webroot.IsDirectory()) { - CString str = path; - str.Replace('/', '\\'); - str.TrimLeft('\\'); - - CPath p; - p.Combine(m_webroot, str); - p.Canonicalize(); - - if (p.IsDirectory()) { - CAtlList sl; - Explode(AfxGetAppSettings().strWebDefIndex, sl, ';'); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - str = sl.GetNext(pos); - CPath p2 = p; - p2.Append(str); - if (p2.FileExists()) { - p = p2; - redir = path; - if (redir.GetAt(redir.GetLength() - 1) != '/') { - redir += _T('/'); - } - redir += str; - break; - } - } - } - - if (_tcslen(p) > _tcslen(m_webroot) && p.FileExists()) { - path = (LPCTSTR)p; - return true; - } - } - - return false; -} - -bool CWebServer::LoadPage(UINT resid, CStringA& str, CString path) -{ - CString redir; - if (ToLocalPath(path, redir)) { - FILE* f = nullptr; - if (!_tfopen_s(&f, path, _T("rb"))) { - fseek(f, 0, 2); - char* buff = str.GetBufferSetLength(ftell(f)); - fseek(f, 0, 0); - int len = (int)fread(buff, 1, str.GetLength(), f); - fclose(f); - return len == str.GetLength(); - } - } - - return LoadResource(resid, str, RT_HTML); -} - -void CWebServer::OnAccept(CWebServerSocket* pServer) -{ - CAutoPtr p(DEBUG_NEW CWebClientSocket(this, m_pMainFrame)); - if (pServer->Accept(*p)) { - CString name; - UINT port; - if (AfxGetAppSettings().fWebServerLocalhostOnly && p->GetPeerName(name, port) && name != _T("127.0.0.1")) { - p->Close(); - return; - } - - m_clients.AddTail(p); - } -} - -void CWebServer::OnClose(const CWebClientSocket* pClient) -{ - POSITION pos = m_clients.GetHeadPosition(); - while (pos) { - POSITION cur = pos; - if (m_clients.GetNext(pos) == pClient) { - m_clients.RemoveAt(cur); - break; - } - } -} - -void CWebServer::OnRequest(CWebClientSocket* pClient, CStringA& hdr, CStringA& body) -{ - const CAppSettings& s = AfxGetAppSettings(); - - CPath p(AToT(pClient->m_path)); - CStringA ext = p.GetExtension().MakeLower(); - CStringA mime; - if (ext.IsEmpty()) { - mime = "text/html"; - } else { - if (!m_mimes.Lookup(ext, mime)) { - mime = "none"; - } - } - - hdr = "HTTP/1.0 200 OK\r\n"; - - bool fHandled = false, fCGI = false; - - if (m_webroot.IsDirectory()) { - CStringA tmphdr; - fHandled = fCGI = CallCGI(pClient, tmphdr, body, mime); - - if (fHandled) { - tmphdr.Replace("\r\n", "\n"); - CAtlList hdrlines; - ExplodeMin(tmphdr, hdrlines, '\n'); - POSITION pos = hdrlines.GetHeadPosition(); - while (pos) { - POSITION cur = pos; - CAtlList sl; - CStringA key = Explode(hdrlines.GetNext(pos), sl, ':', 2); - if (sl.GetCount() < 2) { - continue; - } - key.Trim().MakeLower(); - if (key == "content-type") { - mime = sl.GetTail().Trim(); - hdrlines.RemoveAt(cur); - } else if (key == "content-length") { - hdrlines.RemoveAt(cur); - } - } - tmphdr = Implode(hdrlines, "\r\n"); - hdr += tmphdr + "\r\n"; - } - } - - RequestHandler rh = nullptr; - if (!fHandled && m_internalpages.Lookup(pClient->m_path, rh) && (pClient->*rh)(hdr, body, mime)) { - if (mime.IsEmpty()) { - mime = "text/html"; - } - - CString redir; - if (pClient->m_get.Lookup("redir", redir) - || pClient->m_post.Lookup("redir", redir)) { - if (redir.IsEmpty()) { - redir = '/'; - } - - hdr = - "HTTP/1.0 302 Found\r\n" - "Location: " + CStringA(redir) + "\r\n"; - return; - } - - fHandled = true; - } - - if (!fHandled && m_webroot.IsDirectory()) { - fHandled = LoadPage(0, body, UTF8To16(pClient->m_path)); - } - - UINT resid; - if (!fHandled && m_downloads.Lookup(pClient->m_path, resid) - && (LoadResource(resid, body, _T("FILE")) || LoadResource(resid, body, _T("PNG")))) { - if (mime.IsEmpty()) { - mime = "application/octet-stream"; - } - fHandled = true; - } - - if (!fHandled) { - hdr = mime == "text/html" - ? "HTTP/1.0 301 Moved Permanently\r\n" "Location: /404.html\r\n" - : "HTTP/1.0 404 Not Found\r\n"; - return; - } - - /* Don't cache html, js and css files */ - if ((mime == "text/html" || mime == "text/javascript" || mime == "text/css") && !fCGI) { - if (mime == "text/html") { - hdr += - "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" - "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" - "Pragma: no-cache\r\n"; - - CStringA debug; - if (s.fWebServerPrintDebugInfo) { - debug += "


\r\n";
-
-                CStringA key;
-                POSITION pos;
-
-                {
-                    CStringA value;
-
-                    pos = pClient->m_hdrlines.GetStartPosition();
-                    while (pos) {
-                        pClient->m_hdrlines.GetNextAssoc(pos, key, value);
-                        debug += "HEADER[" + key + "] = " + value + "\r\n";
-                    }
-                }
-                debug += "cmd: " + pClient->m_cmd + "\r\n";
-                debug += "path: " + pClient->m_path + "\r\n";
-                debug += "ver: " + pClient->m_ver + "\r\n";
-
-                {
-                    CString value;
-
-                    pos = pClient->m_get.GetStartPosition();
-                    while (pos) {
-                        pClient->m_get.GetNextAssoc(pos, key, value);
-                        debug += "GET[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
-                    }
-                    pos = pClient->m_post.GetStartPosition();
-                    while (pos) {
-                        pClient->m_post.GetNextAssoc(pos, key, value);
-                        debug += "POST[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
-                    }
-                    pos = pClient->m_cookie.GetStartPosition();
-                    while (pos) {
-                        pClient->m_cookie.GetNextAssoc(pos, key, value);
-                        debug += "COOKIE[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
-                    }
-                    pos = pClient->m_request.GetStartPosition();
-                    while (pos) {
-                        pClient->m_request.GetNextAssoc(pos, key, value);
-                        debug += "REQUEST[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
-                    }
-                }
-                debug += "
"; - } - body.Replace("[debug]", debug); - } - - body.Replace("[browserpath]", "/browser.html"); - body.Replace("[commandpath]", "/command.html"); - body.Replace("[controlspath]", "/controls.html"); - body.Replace("[indexpath]", "/index.html"); - body.Replace("[path]", pClient->m_path); - body.Replace("[setposcommand]", CMD_SETPOS); - body.Replace("[setvolumecommand]", CMD_SETVOLUME); - body.Replace("[wmcname]", "wm_command"); - // TODO: add more general tags to replace - } - - // gzip - if (s.fWebServerUseCompression && !body.IsEmpty() - && hdr.Find("Content-Encoding:") < 0 && ext != ".png" && ext != ".jpeg" && ext != ".gif") - do { - CStringA accept_encoding; - pClient->m_hdrlines.Lookup("accept-encoding", accept_encoding); - accept_encoding.MakeLower(); - CAtlList sl; - ExplodeMin(accept_encoding, sl, ','); - if (!sl.Find("gzip")) { - break; - } - - // Allocate deflate state - z_stream strm; - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); - if (ret != Z_OK) { - ASSERT(0); - break; - } - - int gzippedBuffLen = body.GetLength(); - BYTE* gzippedBuff = DEBUG_NEW BYTE[gzippedBuffLen]; - - // Compress - strm.avail_in = body.GetLength(); - strm.next_in = (Bytef*)(LPCSTR)body; - - strm.avail_out = gzippedBuffLen; - strm.next_out = gzippedBuff; - - ret = deflate(&strm, Z_FINISH); - if (ret != Z_STREAM_END || strm.avail_in != 0) { - ASSERT(0); - deflateEnd(&strm); - delete [] gzippedBuff; - break; - } - gzippedBuffLen -= strm.avail_out; - memcpy(body.GetBufferSetLength(gzippedBuffLen), gzippedBuff, gzippedBuffLen); - - // Clean up - deflateEnd(&strm); - delete [] gzippedBuff; - - hdr += "Content-Encoding: gzip\r\n"; - } while (0); - - CStringA content; - content.Format( - "Content-Type: %s\r\n" - "Content-Length: %d\r\n", - mime.GetString(), body.GetLength()); - hdr += content; -} - -static DWORD WINAPI KillCGI(LPVOID lParam) -{ - HANDLE hProcess = (HANDLE)lParam; - if (WaitForSingleObject(hProcess, 30000) == WAIT_TIMEOUT) { - TerminateProcess(hProcess, 0); - } - return 0; -} - -bool CWebServer::CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString path = pClient->m_path, redir = path; - if (!ToLocalPath(path, redir)) { - return false; - } - CString ext = CPath(path).GetExtension().MakeLower(); - CPath dir(path); - dir.RemoveFileSpec(); - - CString cgi; - if (!m_cgi.Lookup(ext, cgi) || !CPath(cgi).FileExists()) { - return false; - } - - HANDLE hProcess = GetCurrentProcess(); - HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup = nullptr; - HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup = nullptr; - - SECURITY_ATTRIBUTES saAttr; - ZeroMemory(&saAttr, sizeof(saAttr)); - saAttr.nLength = sizeof(saAttr); - saAttr.bInheritHandle = TRUE; - - if (CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { - BOOL fSuccess = DuplicateHandle(hProcess, hChildStdoutRd, hProcess, &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS); - UNREFERENCED_PARAMETER(fSuccess); - CloseHandle(hChildStdoutRd); - } - - if (CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { - BOOL fSuccess = DuplicateHandle(hProcess, hChildStdinWr, hProcess, &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS); - UNREFERENCED_PARAMETER(fSuccess); - CloseHandle(hChildStdinWr); - } - - STARTUPINFO siStartInfo; - ZeroMemory(&siStartInfo, sizeof(siStartInfo)); - siStartInfo.cb = sizeof(siStartInfo); - siStartInfo.hStdError = hChildStdoutWr; - siStartInfo.hStdOutput = hChildStdoutWr; - siStartInfo.hStdInput = hChildStdinRd; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - siStartInfo.wShowWindow = SW_HIDE; - - PROCESS_INFORMATION piProcInfo; - ZeroMemory(&piProcInfo, sizeof(piProcInfo)); - - CStringA envstr; - - LPVOID lpvEnv = GetEnvironmentStrings(); - if (lpvEnv) { - CAtlList env; - for (LPTSTR lpszVariable = (LPTSTR)lpvEnv; *lpszVariable; lpszVariable += _tcslen(lpszVariable) + 1) { - if (lpszVariable != (LPTSTR)lpvEnv) { - env.AddTail(lpszVariable); - } - } - - env.AddTail(_T("GATEWAY_INTERFACE=CGI/1.1")); - env.AddTail(_T("SERVER_SOFTWARE=MPC-HC/") + VersionInfo::GetVersionString()); - env.AddTail(_T("SERVER_PROTOCOL=") + AToT(pClient->m_ver)); - env.AddTail(_T("REQUEST_METHOD=") + AToT(pClient->m_cmd)); - env.AddTail(_T("PATH_INFO=") + redir); - env.AddTail(_T("PATH_TRANSLATED=") + path); - env.AddTail(_T("SCRIPT_NAME=") + redir); - env.AddTail(_T("QUERY_STRING=") + AToT(pClient->m_query)); - - { - CStringA str; - if (pClient->m_hdrlines.Lookup("content-type", str)) { - env.AddTail(_T("CONTENT_TYPE=") + AToT(str)); - } - if (pClient->m_hdrlines.Lookup("content-length", str)) { - env.AddTail(_T("CONTENT_LENGTH=") + AToT(str)); - } - } - - POSITION pos = pClient->m_hdrlines.GetStartPosition(); - while (pos) { - CString key = pClient->m_hdrlines.GetKeyAt(pos); - CString value = pClient->m_hdrlines.GetNextValue(pos); - key.Replace(_T("-"), _T("_")); - key.MakeUpper(); - env.AddTail(_T("HTTP_") + key + _T("=") + value); - } - - CString str, name; - UINT port; - - if (pClient->GetPeerName(name, port)) { - str.Format(_T("%u"), port); - env.AddTail(_T("REMOTE_ADDR=") + name); - env.AddTail(_T("REMOTE_HOST=") + name); - env.AddTail(_T("REMOTE_PORT=") + str); - } - - if (pClient->GetSockName(name, port)) { - str.Format(_T("%u"), port); - env.AddTail(_T("SERVER_NAME=") + name); - env.AddTail(_T("SERVER_PORT=") + str); - } - - env.AddTail(_T("\0")); - - str = Implode(env, '\0'); - envstr = CStringA(str, str.GetLength()); - - FreeEnvironmentStrings((LPTSTR)lpvEnv); - } - - TCHAR* cmdln = DEBUG_NEW TCHAR[32768]; - _sntprintf_s(cmdln, 32768, 32768, _T("\"%s\" \"%s\""), cgi.GetString(), path.GetString()); - - if (hChildStdinRd && hChildStdoutWr) - if (CreateProcess( - nullptr, cmdln, nullptr, nullptr, TRUE, 0, - envstr.GetLength() ? (LPVOID)(LPCSTR)envstr : nullptr, - dir, &siStartInfo, &piProcInfo)) { - DWORD ThreadId; - VERIFY(CreateThread(nullptr, 0, KillCGI, (LPVOID)piProcInfo.hProcess, 0, &ThreadId)); - - static const int BUFFSIZE = 1024; - DWORD dwRead, dwWritten = 0; - - int i = 0, len = pClient->m_data.GetLength(); - for (; i < len; i += dwWritten) { - if (!WriteFile(hChildStdinWrDup, (LPCSTR)pClient->m_data + i, std::min(len - i, BUFFSIZE), &dwWritten, nullptr)) { - break; - } - } - - CloseHandle(hChildStdinWrDup); - CloseHandle(hChildStdoutWr); - - body.Empty(); - - CStringA buff; - while (i == len && ReadFile(hChildStdoutRdDup, buff.GetBuffer(BUFFSIZE), BUFFSIZE, &dwRead, nullptr) && dwRead) { - buff.ReleaseBufferSetLength(dwRead); - body += buff; - } - - int hdrend = body.Find("\r\n\r\n"); - if (hdrend >= 0) { - hdr = body.Left(hdrend + 2); - body = body.Mid(hdrend + 4); - } - - CloseHandle(hChildStdinRd); - CloseHandle(hChildStdoutRdDup); - - CloseHandle(piProcInfo.hProcess); - CloseHandle(piProcInfo.hThread); - } else { - body = "CGI Error"; - } - - delete [] cmdln; - - return true; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "resource.h" +#include "MainFrm.h" +#include +#include "zlib/zlib.h" +#include "WebServerSocket.h" +#include "WebClientSocket.h" +#include "WebServer.h" +#include "VersionInfo.h" +#include "PathUtils.h" + + +CAtlStringMap CWebServer::m_internalpages; +CAtlStringMap CWebServer::m_downloads; +CAtlStringMap CWebServer::m_mimes; + +CWebServer::CWebServer(CMainFrame* pMainFrame, int nPort) + : m_pMainFrame(pMainFrame) + , m_nPort(nPort) +{ + m_webroot = CPath(PathUtils::GetProgramPath()); + const CAppSettings& s = AfxGetAppSettings(); + + CString WebRoot = s.strWebRoot; + WebRoot.Replace('/', '\\'); + WebRoot.Trim(); + CPath p(WebRoot); + if (WebRoot.Find(_T(":\\")) < 0 && WebRoot.Find(_T("\\\\")) < 0) { + m_webroot.Append(WebRoot); + } else { + m_webroot = p; + } + m_webroot.Canonicalize(); + m_webroot.MakePretty(); + if (!m_webroot.IsDirectory()) { + m_webroot = CPath(); + } + + CAtlList sl; + Explode(s.strWebServerCGI, sl, ';'); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + CAtlList sl2; + CString ext = Explode(sl.GetNext(pos), sl2, '=', 2); + if (sl2.GetCount() < 2) { + continue; + } + m_cgi[ext] = sl2.GetTail(); + } + + m_ThreadId = 0; + m_hThread = ::CreateThread(nullptr, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId); +} + +CWebServer::~CWebServer() +{ + if (m_hThread != nullptr) { + PostThreadMessage(m_ThreadId, WM_QUIT, (WPARAM)0, (LPARAM)0); + if (WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT) { + TerminateThread(m_hThread, 0xDEAD); + } + EXECUTE_ASSERT(CloseHandle(m_hThread)); + } +} + +void CWebServer::Init() +{ + m_internalpages["/"] = &CWebClientSocket::OnIndex; + m_internalpages["/404.html"] = &CWebClientSocket::OnError404; + m_internalpages["/browser.html"] = &CWebClientSocket::OnBrowser; + m_internalpages["/command.html"] = &CWebClientSocket::OnCommand; + m_internalpages["/controls.html"] = &CWebClientSocket::OnControls; + m_internalpages["/index.html"] = &CWebClientSocket::OnIndex; + m_internalpages["/info.html"] = &CWebClientSocket::OnInfo; + m_internalpages["/player.html"] = &CWebClientSocket::OnPlayer; + m_internalpages["/snapshot.jpg"] = &CWebClientSocket::OnSnapshotJpeg; + m_internalpages["/status.html"] = &CWebClientSocket::OnStatus; + m_internalpages["/variables.html"] = &CWebClientSocket::OnVariables; + m_internalpages["/viewres.html"] = &CWebClientSocket::OnViewRes; + m_internalpages["/dvb/channels.json"] = &CWebClientSocket::OnDVBChannels; + m_internalpages["/dvb/setchannel"] = &CWebClientSocket::OnDVBSetChannel; + + m_downloads["/default.css"] = IDF_DEFAULT_CSS; + m_downloads["/favicon.ico"] = IDF_FAVICON; + m_downloads["/img/1pix.png"] = IDF_1PIX_PNG; + m_downloads["/img/bottomside.png"] = IDF_BOTTOMSIDE_PNG; + m_downloads["/img/controlback.png"] = IDF_CONTROLBACK_PNG; + m_downloads["/img/controlbuttondecrate.png"] = IDF_CONTROLBUTTONDECRATE_PNG; + m_downloads["/img/controlbuttonincrate.png"] = IDF_CONTROLBUTTONINCRATE_PNG; + m_downloads["/img/controlbuttonpause.png"] = IDF_CONTROLBUTTONPAUSE_PNG; + m_downloads["/img/controlbuttonplay.png"] = IDF_CONTROLBUTTONPLAY_PNG; + m_downloads["/img/controlbuttonskipback.png"] = IDF_CONTROLBUTTONSKIPBACK_PNG; + m_downloads["/img/controlbuttonskipforward.png"] = IDF_CONTROLBUTTONSKIPFORWARD_PNG; + m_downloads["/img/controlbuttonstep.png"] = IDF_CONTROLBUTTONSTEP_PNG; + m_downloads["/img/controlbuttonstop.png"] = IDF_CONTROLBUTTONSTOP_PNG; + m_downloads["/img/controlvolumebar.png"] = IDF_CONTROLVOLUMEBAR_PNG; + m_downloads["/img/controlvolumegrip.png"] = IDF_CONTROLVOLUMEGRIP_PNG; + m_downloads["/img/controlvolumeoff.png"] = IDF_CONTROLVOLUMEOFF_PNG; + m_downloads["/img/controlvolumeon.png"] = IDF_CONTROLVOLUMEON_PNG; + m_downloads["/img/headerback.png"] = IDF_HEADERBACK_PNG; + m_downloads["/img/headerclose.png"] = IDF_HEADERCLOSE_PNG; + m_downloads["/img/headericon.png"] = IDF_HEADERICON_PNG; + m_downloads["/img/leftbottomside.png"] = IDF_LEFTBOTTOMSIDE_PNG; + m_downloads["/img/leftside.png"] = IDF_LEFTSIDE_PNG; + m_downloads["/img/rightbottomside.png"] = IDF_RIGHTBOTTOMSIDE_PNG; + m_downloads["/img/rightside.png"] = IDF_RIGHTSIDE_PNG; + m_downloads["/img/seekbargrip.png"] = IDF_SEEKBARGRIP_PNG; + m_downloads["/img/seekbarleft.png"] = IDF_SEEKBARLEFT_PNG; + m_downloads["/img/seekbarmid.png"] = IDF_SEEKBARMID_PNG; + m_downloads["/img/seekbarright.png"] = IDF_SEEKBARRIGHT_PNG; + m_downloads["/img/sliderback.png"] = IDF_SLIDERBACK_PNG; + m_downloads["/img/slidergrip.png"] = IDF_SLIDERGRIP_PNG; + m_downloads["/img/vbg.png"] = IDF_VBR_PNG; + m_downloads["/img/vbs.png"] = IDF_VBS_PNG; + m_downloads["/javascript.js"] = IDF_JAVASCRIPT; + +#if 0 + CRegKey key; + CString str(_T("MIME\\Database\\Content Type")); + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, str, KEY_READ)) { + TCHAR buff[256]; + DWORD len = _countof(buff); + for (int i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len); i++, len = _countof(buff)) { + CRegKey mime; + TCHAR ext[64]; + ULONG len2 = _countof(ext); + if (ERROR_SUCCESS == mime.Open(HKEY_CLASSES_ROOT, str + _T("\\") + buff, KEY_READ) + && ERROR_SUCCESS == mime.QueryStringValue(_T("Extension"), ext, &len2)) { + m_mimes[CStringA(ext).MakeLower()] = CStringA(buff).MakeLower(); + } + } + } +#endif + + m_mimes[".bmp"] = "image/bmp"; + m_mimes[".css"] = "text/css"; + m_mimes[".gif"] = "image/gif"; + m_mimes[".htm"] = "text/html"; + m_mimes[".html"] = "text/html"; + m_mimes[".jpeg"] = "image/jpeg"; + m_mimes[".jpg"] = "image/jpeg"; + m_mimes[".js"] = "text/javascript"; + m_mimes[".json"] = "text/plain"; + m_mimes[".png"] = "image/png"; + m_mimes[".txt"] = "text/plain"; + m_mimes[".ico"] = "image/x-icon"; +} + +DWORD WINAPI CWebServer::StaticThreadProc(LPVOID lpParam) +{ + SetThreadName(DWORD(-1), "WebServer Thread"); + return ((CWebServer*)lpParam)->ThreadProc(); +} + +DWORD CWebServer::ThreadProc() +{ + if (!AfxSocketInit(nullptr)) { + return DWORD_ERROR; + } + + CWebServerSocket s(this, m_nPort); + + MSG msg; + while ((int)GetMessage(&msg, nullptr, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; +} + +static void PutFileContents(LPCTSTR fn, const CStringA& data) +{ + FILE* f = nullptr; + if (!_tfopen_s(&f, fn, _T("wb"))) { + fwrite((LPCSTR)data, 1, data.GetLength(), f); + fclose(f); + } +} + +void CWebServer::Deploy(CString dir) +{ + CStringA data; + if (LoadResource(IDR_HTML_INDEX, data, RT_HTML)) { + PutFileContents(dir + _T("index.html"), data); + } + if (LoadResource(IDR_HTML_INFO, data, RT_HTML)) { + PutFileContents(dir + _T("info.html"), data); + } + if (LoadResource(IDR_HTML_BROWSER, data, RT_HTML)) { + PutFileContents(dir + _T("browser.html"), data); + } + if (LoadResource(IDR_HTML_CONTROLS, data, RT_HTML)) { + PutFileContents(dir + _T("controls.html"), data); + } + if (LoadResource(IDR_HTML_VARIABLES, data, RT_HTML)) { + PutFileContents(dir + _T("variables.html"), data); + } + if (LoadResource(IDR_HTML_404, data, RT_HTML)) { + PutFileContents(dir + _T("404.html"), data); + } + if (LoadResource(IDR_HTML_PLAYER, data, RT_HTML)) { + PutFileContents(dir + _T("player.html"), data); + } + + // Create the needed folder + CreateDirectory(dir + _T("img"), nullptr); + + POSITION pos = m_downloads.GetStartPosition(); + while (pos) { + CStringA fn; + UINT id; + m_downloads.GetNextAssoc(pos, fn, id); + if (LoadResource(id, data, _T("FILE")) || LoadResource(id, data, _T("PNG"))) { + PutFileContents(dir + AToT(fn), data); + } + } +} + +bool CWebServer::ToLocalPath(CString& path, CString& redir) +{ + if (!path.IsEmpty() && m_webroot.IsDirectory()) { + CString str = path; + str.Replace('/', '\\'); + str.TrimLeft('\\'); + + CPath p; + p.Combine(m_webroot, str); + p.Canonicalize(); + + if (p.IsDirectory()) { + CAtlList sl; + Explode(AfxGetAppSettings().strWebDefIndex, sl, ';'); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + str = sl.GetNext(pos); + CPath p2 = p; + p2.Append(str); + if (p2.FileExists()) { + p = p2; + redir = path; + if (redir.GetAt(redir.GetLength() - 1) != '/') { + redir += _T('/'); + } + redir += str; + break; + } + } + } + + if (_tcslen(p) > _tcslen(m_webroot) && p.FileExists()) { + path = (LPCTSTR)p; + return true; + } + } + + return false; +} + +bool CWebServer::LoadPage(UINT resid, CStringA& str, CString path) +{ + CString redir; + if (ToLocalPath(path, redir)) { + FILE* f = nullptr; + if (!_tfopen_s(&f, path, _T("rb"))) { + fseek(f, 0, 2); + char* buff = str.GetBufferSetLength(ftell(f)); + fseek(f, 0, 0); + int len = (int)fread(buff, 1, str.GetLength(), f); + fclose(f); + return len == str.GetLength(); + } + } + + return LoadResource(resid, str, RT_HTML); +} + +void CWebServer::OnAccept(CWebServerSocket* pServer) +{ + CAutoPtr p(DEBUG_NEW CWebClientSocket(this, m_pMainFrame)); + if (pServer->Accept(*p)) { + CString name; + UINT port; + if (AfxGetAppSettings().fWebServerLocalhostOnly && p->GetPeerName(name, port) && name != _T("127.0.0.1")) { + p->Close(); + return; + } + + m_clients.AddTail(p); + } +} + +void CWebServer::OnClose(const CWebClientSocket* pClient) +{ + POSITION pos = m_clients.GetHeadPosition(); + while (pos) { + POSITION cur = pos; + if (m_clients.GetNext(pos) == pClient) { + m_clients.RemoveAt(cur); + break; + } + } +} + +void CWebServer::OnRequest(CWebClientSocket* pClient, CStringA& hdr, CStringA& body) +{ + const CAppSettings& s = AfxGetAppSettings(); + + CPath p(AToT(pClient->m_path)); + CStringA ext = p.GetExtension().MakeLower(); + CStringA mime; + if (ext.IsEmpty()) { + mime = "text/html"; + } else { + if (!m_mimes.Lookup(ext, mime)) { + mime = "none"; + } + } + + hdr = "HTTP/1.0 200 OK\r\n"; + + bool fHandled = false, fCGI = false; + + if (m_webroot.IsDirectory()) { + CStringA tmphdr; + fHandled = fCGI = CallCGI(pClient, tmphdr, body, mime); + + if (fHandled) { + tmphdr.Replace("\r\n", "\n"); + CAtlList hdrlines; + ExplodeMin(tmphdr, hdrlines, '\n'); + POSITION pos = hdrlines.GetHeadPosition(); + while (pos) { + POSITION cur = pos; + CAtlList sl; + CStringA key = Explode(hdrlines.GetNext(pos), sl, ':', 2); + if (sl.GetCount() < 2) { + continue; + } + key.Trim().MakeLower(); + if (key == "content-type") { + mime = sl.GetTail().Trim(); + hdrlines.RemoveAt(cur); + } else if (key == "content-length") { + hdrlines.RemoveAt(cur); + } + } + tmphdr = Implode(hdrlines, "\r\n"); + hdr += tmphdr + "\r\n"; + } + } + + RequestHandler rh = nullptr; + if (!fHandled && m_internalpages.Lookup(pClient->m_path, rh) && (pClient->*rh)(hdr, body, mime)) { + if (mime.IsEmpty()) { + mime = "text/html"; + } + + CString redir; + if (pClient->m_get.Lookup("redir", redir) + || pClient->m_post.Lookup("redir", redir)) { + if (redir.IsEmpty()) { + redir = '/'; + } + + hdr = + "HTTP/1.0 302 Found\r\n" + "Location: " + CStringA(redir) + "\r\n"; + return; + } + + fHandled = true; + } + + if (!fHandled && m_webroot.IsDirectory()) { + fHandled = LoadPage(0, body, UTF8To16(pClient->m_path)); + } + + UINT resid; + if (!fHandled && m_downloads.Lookup(pClient->m_path, resid) + && (LoadResource(resid, body, _T("FILE")) || LoadResource(resid, body, _T("PNG")))) { + if (mime.IsEmpty()) { + mime = "application/octet-stream"; + } + fHandled = true; + } + + if (!fHandled) { + hdr = mime == "text/html" + ? "HTTP/1.0 301 Moved Permanently\r\n" "Location: /404.html\r\n" + : "HTTP/1.0 404 Not Found\r\n"; + return; + } + + /* Don't cache html, js and css files */ + if ((mime == "text/html" || mime == "text/javascript" || mime == "text/css") && !fCGI) { + if (mime == "text/html") { + hdr += + "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" + "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" + "Pragma: no-cache\r\n"; + + CStringA debug; + if (s.fWebServerPrintDebugInfo) { + debug += "

\r\n";
+
+                CStringA key;
+                POSITION pos;
+
+                {
+                    CStringA value;
+
+                    pos = pClient->m_hdrlines.GetStartPosition();
+                    while (pos) {
+                        pClient->m_hdrlines.GetNextAssoc(pos, key, value);
+                        debug += "HEADER[" + key + "] = " + value + "\r\n";
+                    }
+                }
+                debug += "cmd: " + pClient->m_cmd + "\r\n";
+                debug += "path: " + pClient->m_path + "\r\n";
+                debug += "ver: " + pClient->m_ver + "\r\n";
+
+                {
+                    CString value;
+
+                    pos = pClient->m_get.GetStartPosition();
+                    while (pos) {
+                        pClient->m_get.GetNextAssoc(pos, key, value);
+                        debug += "GET[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
+                    }
+                    pos = pClient->m_post.GetStartPosition();
+                    while (pos) {
+                        pClient->m_post.GetNextAssoc(pos, key, value);
+                        debug += "POST[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
+                    }
+                    pos = pClient->m_cookie.GetStartPosition();
+                    while (pos) {
+                        pClient->m_cookie.GetNextAssoc(pos, key, value);
+                        debug += "COOKIE[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
+                    }
+                    pos = pClient->m_request.GetStartPosition();
+                    while (pos) {
+                        pClient->m_request.GetNextAssoc(pos, key, value);
+                        debug += "REQUEST[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
+                    }
+                }
+                debug += "
"; + } + body.Replace("[debug]", debug); + } + + body.Replace("[browserpath]", "/browser.html"); + body.Replace("[commandpath]", "/command.html"); + body.Replace("[controlspath]", "/controls.html"); + body.Replace("[indexpath]", "/index.html"); + body.Replace("[path]", pClient->m_path); + body.Replace("[setposcommand]", CMD_SETPOS); + body.Replace("[setvolumecommand]", CMD_SETVOLUME); + body.Replace("[wmcname]", "wm_command"); + // TODO: add more general tags to replace + } + + // gzip + if (s.fWebServerUseCompression && !body.IsEmpty() + && hdr.Find("Content-Encoding:") < 0 && ext != ".png" && ext != ".jpeg" && ext != ".gif") + do { + CStringA accept_encoding; + pClient->m_hdrlines.Lookup("accept-encoding", accept_encoding); + accept_encoding.MakeLower(); + CAtlList sl; + ExplodeMin(accept_encoding, sl, ','); + if (!sl.Find("gzip")) { + break; + } + + // Allocate deflate state + z_stream strm; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) { + ASSERT(0); + break; + } + + int gzippedBuffLen = body.GetLength(); + BYTE* gzippedBuff = DEBUG_NEW BYTE[gzippedBuffLen]; + + // Compress + strm.avail_in = body.GetLength(); + strm.next_in = (Bytef*)(LPCSTR)body; + + strm.avail_out = gzippedBuffLen; + strm.next_out = gzippedBuff; + + ret = deflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END || strm.avail_in != 0) { + ASSERT(0); + deflateEnd(&strm); + delete [] gzippedBuff; + break; + } + gzippedBuffLen -= strm.avail_out; + memcpy(body.GetBufferSetLength(gzippedBuffLen), gzippedBuff, gzippedBuffLen); + + // Clean up + deflateEnd(&strm); + delete [] gzippedBuff; + + hdr += "Content-Encoding: gzip\r\n"; + } while (0); + + CStringA content; + content.Format( + "Content-Type: %s\r\n" + "Content-Length: %d\r\n", + mime.GetString(), body.GetLength()); + hdr += content; +} + +static DWORD WINAPI KillCGI(LPVOID lParam) +{ + HANDLE hProcess = (HANDLE)lParam; + if (WaitForSingleObject(hProcess, 30000) == WAIT_TIMEOUT) { + TerminateProcess(hProcess, 0); + } + return 0; +} + +bool CWebServer::CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString path = pClient->m_path, redir = path; + if (!ToLocalPath(path, redir)) { + return false; + } + CString ext = CPath(path).GetExtension().MakeLower(); + CPath dir(path); + dir.RemoveFileSpec(); + + CString cgi; + if (!m_cgi.Lookup(ext, cgi) || !CPath(cgi).FileExists()) { + return false; + } + + HANDLE hProcess = GetCurrentProcess(); + HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup = nullptr; + HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup = nullptr; + + SECURITY_ATTRIBUTES saAttr; + ZeroMemory(&saAttr, sizeof(saAttr)); + saAttr.nLength = sizeof(saAttr); + saAttr.bInheritHandle = TRUE; + + if (CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { + BOOL fSuccess = DuplicateHandle(hProcess, hChildStdoutRd, hProcess, &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS); + UNREFERENCED_PARAMETER(fSuccess); + CloseHandle(hChildStdoutRd); + } + + if (CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { + BOOL fSuccess = DuplicateHandle(hProcess, hChildStdinWr, hProcess, &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS); + UNREFERENCED_PARAMETER(fSuccess); + CloseHandle(hChildStdinWr); + } + + STARTUPINFO siStartInfo; + ZeroMemory(&siStartInfo, sizeof(siStartInfo)); + siStartInfo.cb = sizeof(siStartInfo); + siStartInfo.hStdError = hChildStdoutWr; + siStartInfo.hStdOutput = hChildStdoutWr; + siStartInfo.hStdInput = hChildStdinRd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION piProcInfo; + ZeroMemory(&piProcInfo, sizeof(piProcInfo)); + + CStringA envstr; + + LPVOID lpvEnv = GetEnvironmentStrings(); + if (lpvEnv) { + CAtlList env; + for (LPTSTR lpszVariable = (LPTSTR)lpvEnv; *lpszVariable; lpszVariable += _tcslen(lpszVariable) + 1) { + if (lpszVariable != (LPTSTR)lpvEnv) { + env.AddTail(lpszVariable); + } + } + + env.AddTail(_T("GATEWAY_INTERFACE=CGI/1.1")); + env.AddTail(_T("SERVER_SOFTWARE=MPC-HC/") + VersionInfo::GetVersionString()); + env.AddTail(_T("SERVER_PROTOCOL=") + AToT(pClient->m_ver)); + env.AddTail(_T("REQUEST_METHOD=") + AToT(pClient->m_cmd)); + env.AddTail(_T("PATH_INFO=") + redir); + env.AddTail(_T("PATH_TRANSLATED=") + path); + env.AddTail(_T("SCRIPT_NAME=") + redir); + env.AddTail(_T("QUERY_STRING=") + AToT(pClient->m_query)); + + { + CStringA str; + if (pClient->m_hdrlines.Lookup("content-type", str)) { + env.AddTail(_T("CONTENT_TYPE=") + AToT(str)); + } + if (pClient->m_hdrlines.Lookup("content-length", str)) { + env.AddTail(_T("CONTENT_LENGTH=") + AToT(str)); + } + } + + POSITION pos = pClient->m_hdrlines.GetStartPosition(); + while (pos) { + CString key = pClient->m_hdrlines.GetKeyAt(pos); + CString value = pClient->m_hdrlines.GetNextValue(pos); + key.Replace(_T("-"), _T("_")); + key.MakeUpper(); + env.AddTail(_T("HTTP_") + key + _T("=") + value); + } + + CString str, name; + UINT port; + + if (pClient->GetPeerName(name, port)) { + str.Format(_T("%u"), port); + env.AddTail(_T("REMOTE_ADDR=") + name); + env.AddTail(_T("REMOTE_HOST=") + name); + env.AddTail(_T("REMOTE_PORT=") + str); + } + + if (pClient->GetSockName(name, port)) { + str.Format(_T("%u"), port); + env.AddTail(_T("SERVER_NAME=") + name); + env.AddTail(_T("SERVER_PORT=") + str); + } + + env.AddTail(_T("\0")); + + str = Implode(env, '\0'); + envstr = CStringA(str, str.GetLength()); + + FreeEnvironmentStrings((LPTSTR)lpvEnv); + } + + TCHAR* cmdln = DEBUG_NEW TCHAR[32768]; + _sntprintf_s(cmdln, 32768, 32768, _T("\"%s\" \"%s\""), cgi.GetString(), path.GetString()); + + if (hChildStdinRd && hChildStdoutWr) + if (CreateProcess( + nullptr, cmdln, nullptr, nullptr, TRUE, 0, + envstr.GetLength() ? (LPVOID)(LPCSTR)envstr : nullptr, + dir, &siStartInfo, &piProcInfo)) { + DWORD ThreadId; + VERIFY(CreateThread(nullptr, 0, KillCGI, (LPVOID)piProcInfo.hProcess, 0, &ThreadId)); + + static const int BUFFSIZE = 1024; + DWORD dwRead, dwWritten = 0; + + int i = 0, len = pClient->m_data.GetLength(); + for (; i < len; i += dwWritten) { + if (!WriteFile(hChildStdinWrDup, (LPCSTR)pClient->m_data + i, std::min(len - i, BUFFSIZE), &dwWritten, nullptr)) { + break; + } + } + + CloseHandle(hChildStdinWrDup); + CloseHandle(hChildStdoutWr); + + body.Empty(); + + CStringA buff; + while (i == len && ReadFile(hChildStdoutRdDup, buff.GetBuffer(BUFFSIZE), BUFFSIZE, &dwRead, nullptr) && dwRead) { + buff.ReleaseBufferSetLength(dwRead); + body += buff; + } + + int hdrend = body.Find("\r\n\r\n"); + if (hdrend >= 0) { + hdr = body.Left(hdrend + 2); + body = body.Mid(hdrend + 4); + } + + CloseHandle(hChildStdinRd); + CloseHandle(hChildStdoutRdDup); + + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + } else { + body = "CGI Error"; + } + + delete [] cmdln; + + return true; +} diff --git a/src/mpc-hc/WebServer.h b/src/mpc-hc/WebServer.h index 8b7854b38e9..68e40093975 100644 --- a/src/mpc-hc/WebServer.h +++ b/src/mpc-hc/WebServer.h @@ -1,73 +1,73 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include -#include -#include - -#define UTF8(str) UTF16To8(TToW(str)) -#define UTF8Arg(str) UrlEncode(UTF8(str)) -#define CMD_SETPOS "-1" -#define CMD_SETVOLUME "-2" - - -class CWebServerSocket; -class CWebClientSocket; -class CMainFrame; - -class CWebServer -{ - CMainFrame* m_pMainFrame; - int m_nPort; - - DWORD ThreadProc(); - static DWORD WINAPI StaticThreadProc(LPVOID lpParam); - DWORD m_ThreadId; - HANDLE m_hThread; - - CAutoPtrList m_clients; - - typedef bool (CWebClientSocket::*RequestHandler)(CStringA& hdr, CStringA& body, CStringA& mime); - static CAtlStringMap m_internalpages; - static CAtlStringMap m_downloads; - static CAtlStringMap m_mimes; - CPath m_webroot; - - CAtlStringMap<> m_cgi; - bool CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime); - -public: - CWebServer(CMainFrame* pMainFrame, int nPort = 13579); - virtual ~CWebServer(); - - static void Init(); - - static void Deploy(CString dir); - - bool ToLocalPath(CString& path, CString& redir); - bool LoadPage(UINT resid, CStringA& str, CString path = _T("")); - - void OnAccept(CWebServerSocket* pServer); - void OnClose(const CWebClientSocket* pClient); - void OnRequest(CWebClientSocket* pClient, CStringA& reshdr, CStringA& resbody); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include +#include +#include + +#define UTF8(str) UTF16To8(TToW(str)) +#define UTF8Arg(str) UrlEncode(UTF8(str)) +#define CMD_SETPOS "-1" +#define CMD_SETVOLUME "-2" + + +class CWebServerSocket; +class CWebClientSocket; +class CMainFrame; + +class CWebServer +{ + CMainFrame* m_pMainFrame; + int m_nPort; + + DWORD ThreadProc(); + static DWORD WINAPI StaticThreadProc(LPVOID lpParam); + DWORD m_ThreadId; + HANDLE m_hThread; + + CAutoPtrList m_clients; + + typedef bool (CWebClientSocket::*RequestHandler)(CStringA& hdr, CStringA& body, CStringA& mime); + static CAtlStringMap m_internalpages; + static CAtlStringMap m_downloads; + static CAtlStringMap m_mimes; + CPath m_webroot; + + CAtlStringMap<> m_cgi; + bool CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime); + +public: + CWebServer(CMainFrame* pMainFrame, int nPort = 13579); + virtual ~CWebServer(); + + static void Init(); + + static void Deploy(CString dir); + + bool ToLocalPath(CString& path, CString& redir); + bool LoadPage(UINT resid, CStringA& str, CString path = _T("")); + + void OnAccept(CWebServerSocket* pServer); + void OnClose(const CWebClientSocket* pClient); + void OnRequest(CWebClientSocket* pClient, CStringA& reshdr, CStringA& resbody); +}; diff --git a/src/mpc-hc/WebServerSocket.cpp b/src/mpc-hc/WebServerSocket.cpp index 6a73fea73a8..274370f3cee 100644 --- a/src/mpc-hc/WebServerSocket.cpp +++ b/src/mpc-hc/WebServerSocket.cpp @@ -1,45 +1,45 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "WebServer.h" -#include "WebServerSocket.h" - - -CWebServerSocket::CWebServerSocket(CWebServer* pWebServer, int port) - : m_pWebServer(pWebServer) -{ - Create(port); - Listen(); -} - -CWebServerSocket::~CWebServerSocket() -{ -} - -void CWebServerSocket::OnAccept(int nErrorCode) -{ - if (nErrorCode == 0 && m_pWebServer) { - m_pWebServer->OnAccept(this); - } - - __super::OnAccept(nErrorCode); -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "WebServer.h" +#include "WebServerSocket.h" + + +CWebServerSocket::CWebServerSocket(CWebServer* pWebServer, int port) + : m_pWebServer(pWebServer) +{ + Create(port); + Listen(); +} + +CWebServerSocket::~CWebServerSocket() +{ +} + +void CWebServerSocket::OnAccept(int nErrorCode) +{ + if (nErrorCode == 0 && m_pWebServer) { + m_pWebServer->OnAccept(this); + } + + __super::OnAccept(nErrorCode); +} diff --git a/src/mpc-hc/WebServerSocket.h b/src/mpc-hc/WebServerSocket.h index f1248bb76e6..d4185924d7b 100644 --- a/src/mpc-hc/WebServerSocket.h +++ b/src/mpc-hc/WebServerSocket.h @@ -1,36 +1,36 @@ -/* - * (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 . - * - */ - -#pragma once - -class CWebServer; - -class CWebServerSocket : public CAsyncSocket -{ - CWebServer* m_pWebServer; - -protected: - void OnAccept(int nErrorCode); - -public: - CWebServerSocket(CWebServer* pWebServer, int port = 13579); - virtual ~CWebServerSocket(); -}; +/* + * (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 . + * + */ + +#pragma once + +class CWebServer; + +class CWebServerSocket : public CAsyncSocket +{ + CWebServer* m_pWebServer; + +protected: + void OnAccept(int nErrorCode); + +public: + CWebServerSocket(CWebServer* pWebServer, int port = 13579); + virtual ~CWebServerSocket(); +}; diff --git a/src/mpc-hc/WinHotkeyCtrl.cpp b/src/mpc-hc/WinHotkeyCtrl.cpp index 134d4030aa5..3c4620edac6 100644 --- a/src/mpc-hc/WinHotkeyCtrl.cpp +++ b/src/mpc-hc/WinHotkeyCtrl.cpp @@ -1,317 +1,317 @@ -/* - * (C) 2011-2014 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 . - * - */ - -#include "stdafx.h" -#include "resource.h" -#include "WinHotkeyCtrl.h" -#include "vkCodes.h" -#include "mplayerc.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeMenu.h" - -#define WM_KEY (WM_USER + 444) - -// CWinHotkeyCtrl - -HHOOK CWinHotkeyCtrl::sm_hhookKb = nullptr; -CWinHotkeyCtrl* CWinHotkeyCtrl::sm_pwhcFocus = nullptr; - - -IMPLEMENT_DYNAMIC(CWinHotkeyCtrl, CEdit) -CWinHotkeyCtrl::CWinHotkeyCtrl() - : m_vkCode(0) - , m_vkCode_def(0) - , m_fModSet(0) - , m_fModRel(0) - , m_fModSet_def(0) - , m_fIsPressed(FALSE) - , isMouseModifier(false) -{ -} - -CWinHotkeyCtrl::~CWinHotkeyCtrl() -{ -} - -BEGIN_MESSAGE_MAP(CWinHotkeyCtrl, CEditWithButton) - ON_MESSAGE(WM_KEY, OnKey) - ON_WM_CHAR() - ON_WM_SETCURSOR() - ON_WM_SETFOCUS() - ON_WM_KILLFOCUS() - ON_WM_CONTEXTMENU() - ON_WM_DESTROY() - ON_MESSAGE(EDIT_BUTTON_LEFTCLICKED, OnLeftClick) -END_MESSAGE_MAP() - -// CWinHotkeyCtrl - -void CWinHotkeyCtrl::PreSubclassWindow() -{ - CEditWithButton::PreSubclassWindow(); - UpdateText(); -} - -LRESULT CALLBACK CWinHotkeyCtrl::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = 1; - - if (nCode == HC_ACTION && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN || - wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && sm_pwhcFocus) { - sm_pwhcFocus->PostMessage(WM_KEY, ((PKBDLLHOOKSTRUCT)lParam)->vkCode, (wParam & 1)); - } - return lResult; -} - -BOOL CWinHotkeyCtrl::InstallKbHook() -{ - if (sm_pwhcFocus && sm_hhookKb) { - sm_pwhcFocus->UninstallKbHook(); - } - sm_pwhcFocus = this; - - sm_hhookKb = ::SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)LowLevelKeyboardProc, GetModuleHandle(nullptr), 0); - - return (sm_hhookKb != nullptr); -} - -BOOL CWinHotkeyCtrl::UninstallKbHook() -{ - BOOL fOk = FALSE; - if (sm_hhookKb) { - fOk = ::UnhookWindowsHookEx(sm_hhookKb); - sm_hhookKb = nullptr; - } - sm_pwhcFocus = nullptr; - return fOk; -} - - -void CWinHotkeyCtrl::UpdateText() -{ - CString sText; - if (isMouseModifier) { - HotkeyToString(0, m_fModSet, sText); - } else { - HotkeyToString(m_vkCode, m_fModSet, sText); - } - SetWindowText((LPCTSTR)sText); - SetSel(0x8fffffff, 0x8fffffff, FALSE); -} - -DWORD CWinHotkeyCtrl::GetWinHotkey() -{ - return MAKEWORD(m_vkCode, m_fModSet); -} - -BOOL CWinHotkeyCtrl::GetWinHotkey(UINT* pvkCode, UINT* pfModifiers) -{ - *pvkCode = m_vkCode; - *pfModifiers = m_fModSet; - return (m_vkCode != 0); -} - -void CWinHotkeyCtrl::SetWinHotkey(DWORD dwHk) -{ - SetWinHotkey(LOBYTE(LOWORD(dwHk)), HIBYTE(LOWORD(dwHk))); -} - -void CWinHotkeyCtrl::SetWinHotkey(UINT vkCode, UINT fModifiers) -{ - m_vkCode = m_vkCode_def = vkCode; - m_fModSet = m_fModSet_def = m_fModRel = fModifiers; - m_fIsPressed = FALSE; - - UpdateText(); -} - -void CWinHotkeyCtrl::DrawButton(CRect rectButton) -{ - if (AppIsThemeLoaded()) { - CWindowDC dc(this); - bool disabled = 0 != (GetStyle() & (ES_READONLY | WS_DISABLED)); - bool selected = GetButtonThemeState() == PBS_PRESSED; - bool highlighted = GetButtonThemeState() == PBS_HOT; - CFont* pOldFont = dc.SelectObject(GetFont()); - CMPCThemeButton::drawButtonBase(&dc, rectButton, GetButtonText(), selected, highlighted, false, disabled, true, false); - dc.SelectObject(pOldFont); - } else { - __super::DrawButton(rectButton); - } -} - -LRESULT CWinHotkeyCtrl::OnKey(WPARAM wParam, LPARAM lParam) -{ - DWORD fMod = 0; - BOOL fRedraw = TRUE; - - switch (wParam) { - case VK_CONTROL: - case VK_LCONTROL: - case VK_RCONTROL: - fMod = MOD_CONTROL; - break; - case VK_MENU: - case VK_LMENU: - case VK_RMENU: - fMod = MOD_ALT; - break; - case VK_SHIFT: - case VK_LSHIFT: - case VK_RSHIFT: - fMod = MOD_SHIFT; - break; - } - - if (fMod) { // modifier - if (!lParam) { // press - if (!m_fIsPressed && m_vkCode) { - m_fModSet = m_fModRel = 0; - m_vkCode = 0; - } - m_fModRel &= ~fMod; - } else if (m_fModSet & fMod) { // release - m_fModRel |= fMod; - } - - if (m_fIsPressed || !m_vkCode) { - if (!lParam) { // press - if (!(m_fModSet & fMod)) { // new modifier - m_fModSet |= fMod; - } else { - fRedraw = FALSE; - } - } else { - m_fModSet &= ~fMod; - } - } - } else { // another key - if (wParam == VK_DELETE && m_fModSet == (MOD_CONTROL | MOD_ALT) // skip "Ctrl+Alt+Del" - || wParam == VK_LWIN || wParam == VK_RWIN // skip "Win" - || wParam == VK_SNAPSHOT // skip "PrintScreen" - || wParam == VK_ESCAPE && (m_fModSet == MOD_CONTROL || m_fModSet == MOD_ALT) // skip "Ctrl+Esc", "Alt+Esc" - || wParam == VK_TAB && m_fModSet == MOD_ALT) { // skip "Alt+Tab" - m_fModSet = m_fModRel = 0; - m_vkCode = 0; - m_fIsPressed = FALSE; - } else if (wParam == m_vkCode && lParam) { - m_fIsPressed = FALSE; - fRedraw = FALSE; - } else { - if (!m_fIsPressed && !lParam) { // pressed a another key - if (m_fModRel & m_fModSet) { - m_fModSet = m_fModRel = 0; - } - m_vkCode = (UINT)wParam; - m_fIsPressed = TRUE; - } - } - } - if (fRedraw) { - UpdateText(); - } - - return 0L; -} - -LRESULT CWinHotkeyCtrl::OnLeftClick(WPARAM wParam, LPARAM lParam) -{ - CRect r; - CPoint pt; - CEditWithButton::GetWindowRect(r); - CRect rectButton = GetButtonRect(r); - pt = rectButton.BottomRight(); - pt.x = pt.x - (rectButton.Width()); - OnContextMenu(this, pt); - return 0; -} - -// CWinHotkeyCtrl message handlers - -void CWinHotkeyCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) -{ -} - -BOOL CWinHotkeyCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) -{ - return FALSE; -} - -void CWinHotkeyCtrl::OnSetFocus(CWnd* pOldWnd) -{ - InstallKbHook(); - CEditWithButton::OnSetFocus(pOldWnd); -} - -void CWinHotkeyCtrl::OnKillFocus(CWnd* pNewWnd) -{ - UninstallKbHook(); - CEditWithButton::OnKillFocus(pNewWnd); -} - -void CWinHotkeyCtrl::OnContextMenu(CWnd*, CPoint pt) -{ - CMPCThemeMenu menu; - menu.CreatePopupMenu(); - UINT cod = 0, mod = 0; - menu.AppendMenu(MF_STRING, 1, ResStr(IDS_APPLY)); - menu.AppendMenu(MF_STRING, 2, ResStr(IDS_CLEAR)); - menu.AppendMenu(MF_STRING, 3, ResStr(IDS_CANCEL)); - if (AppNeedsThemedControls()) { - menu.fulfillThemeReqs(); - } - - UINT uMenuID = menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_VERPOSANIMATION | TPM_NONOTIFY | TPM_RETURNCMD, - pt.x, pt.y, this, nullptr); - - if (uMenuID) { - switch (uMenuID) { - case 1: - GetWinHotkey(&cod, &mod); - if (cod == 0 || m_vkCode == 0) { - mod = m_fModSet = m_fModRel = 0; - } - SetWinHotkey(cod, mod); - m_fIsPressed = FALSE; - break; - case 2: - m_fModSet = m_fModRel = 0; - m_vkCode = 0; - m_fIsPressed = FALSE; - break; - case 3: - m_fModSet = m_fModRel = m_fModSet_def; - m_vkCode = m_vkCode_def; - m_fIsPressed = FALSE; - break; - } - UpdateText(); - GetParent() ->SetFocus(); - } - -} - -void CWinHotkeyCtrl::OnDestroy() -{ - if (sm_pwhcFocus == this) { - sm_pwhcFocus->UninstallKbHook(); - } - CEditWithButton::OnDestroy(); -} +/* + * (C) 2011-2014 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 . + * + */ + +#include "stdafx.h" +#include "resource.h" +#include "WinHotkeyCtrl.h" +#include "vkCodes.h" +#include "mplayerc.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeMenu.h" + +#define WM_KEY (WM_USER + 444) + +// CWinHotkeyCtrl + +HHOOK CWinHotkeyCtrl::sm_hhookKb = nullptr; +CWinHotkeyCtrl* CWinHotkeyCtrl::sm_pwhcFocus = nullptr; + + +IMPLEMENT_DYNAMIC(CWinHotkeyCtrl, CEdit) +CWinHotkeyCtrl::CWinHotkeyCtrl() + : m_vkCode(0) + , m_vkCode_def(0) + , m_fModSet(0) + , m_fModRel(0) + , m_fModSet_def(0) + , m_fIsPressed(FALSE) + , isMouseModifier(false) +{ +} + +CWinHotkeyCtrl::~CWinHotkeyCtrl() +{ +} + +BEGIN_MESSAGE_MAP(CWinHotkeyCtrl, CEditWithButton) + ON_MESSAGE(WM_KEY, OnKey) + ON_WM_CHAR() + ON_WM_SETCURSOR() + ON_WM_SETFOCUS() + ON_WM_KILLFOCUS() + ON_WM_CONTEXTMENU() + ON_WM_DESTROY() + ON_MESSAGE(EDIT_BUTTON_LEFTCLICKED, OnLeftClick) +END_MESSAGE_MAP() + +// CWinHotkeyCtrl + +void CWinHotkeyCtrl::PreSubclassWindow() +{ + CEditWithButton::PreSubclassWindow(); + UpdateText(); +} + +LRESULT CALLBACK CWinHotkeyCtrl::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = 1; + + if (nCode == HC_ACTION && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN || + wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && sm_pwhcFocus) { + sm_pwhcFocus->PostMessage(WM_KEY, ((PKBDLLHOOKSTRUCT)lParam)->vkCode, (wParam & 1)); + } + return lResult; +} + +BOOL CWinHotkeyCtrl::InstallKbHook() +{ + if (sm_pwhcFocus && sm_hhookKb) { + sm_pwhcFocus->UninstallKbHook(); + } + sm_pwhcFocus = this; + + sm_hhookKb = ::SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)LowLevelKeyboardProc, GetModuleHandle(nullptr), 0); + + return (sm_hhookKb != nullptr); +} + +BOOL CWinHotkeyCtrl::UninstallKbHook() +{ + BOOL fOk = FALSE; + if (sm_hhookKb) { + fOk = ::UnhookWindowsHookEx(sm_hhookKb); + sm_hhookKb = nullptr; + } + sm_pwhcFocus = nullptr; + return fOk; +} + + +void CWinHotkeyCtrl::UpdateText() +{ + CString sText; + if (isMouseModifier) { + HotkeyToString(0, m_fModSet, sText); + } else { + HotkeyToString(m_vkCode, m_fModSet, sText); + } + SetWindowText((LPCTSTR)sText); + SetSel(0x8fffffff, 0x8fffffff, FALSE); +} + +DWORD CWinHotkeyCtrl::GetWinHotkey() +{ + return MAKEWORD(m_vkCode, m_fModSet); +} + +BOOL CWinHotkeyCtrl::GetWinHotkey(UINT* pvkCode, UINT* pfModifiers) +{ + *pvkCode = m_vkCode; + *pfModifiers = m_fModSet; + return (m_vkCode != 0); +} + +void CWinHotkeyCtrl::SetWinHotkey(DWORD dwHk) +{ + SetWinHotkey(LOBYTE(LOWORD(dwHk)), HIBYTE(LOWORD(dwHk))); +} + +void CWinHotkeyCtrl::SetWinHotkey(UINT vkCode, UINT fModifiers) +{ + m_vkCode = m_vkCode_def = vkCode; + m_fModSet = m_fModSet_def = m_fModRel = fModifiers; + m_fIsPressed = FALSE; + + UpdateText(); +} + +void CWinHotkeyCtrl::DrawButton(CRect rectButton) +{ + if (AppIsThemeLoaded()) { + CWindowDC dc(this); + bool disabled = 0 != (GetStyle() & (ES_READONLY | WS_DISABLED)); + bool selected = GetButtonThemeState() == PBS_PRESSED; + bool highlighted = GetButtonThemeState() == PBS_HOT; + CFont* pOldFont = dc.SelectObject(GetFont()); + CMPCThemeButton::drawButtonBase(&dc, rectButton, GetButtonText(), selected, highlighted, false, disabled, true, false); + dc.SelectObject(pOldFont); + } else { + __super::DrawButton(rectButton); + } +} + +LRESULT CWinHotkeyCtrl::OnKey(WPARAM wParam, LPARAM lParam) +{ + DWORD fMod = 0; + BOOL fRedraw = TRUE; + + switch (wParam) { + case VK_CONTROL: + case VK_LCONTROL: + case VK_RCONTROL: + fMod = MOD_CONTROL; + break; + case VK_MENU: + case VK_LMENU: + case VK_RMENU: + fMod = MOD_ALT; + break; + case VK_SHIFT: + case VK_LSHIFT: + case VK_RSHIFT: + fMod = MOD_SHIFT; + break; + } + + if (fMod) { // modifier + if (!lParam) { // press + if (!m_fIsPressed && m_vkCode) { + m_fModSet = m_fModRel = 0; + m_vkCode = 0; + } + m_fModRel &= ~fMod; + } else if (m_fModSet & fMod) { // release + m_fModRel |= fMod; + } + + if (m_fIsPressed || !m_vkCode) { + if (!lParam) { // press + if (!(m_fModSet & fMod)) { // new modifier + m_fModSet |= fMod; + } else { + fRedraw = FALSE; + } + } else { + m_fModSet &= ~fMod; + } + } + } else { // another key + if (wParam == VK_DELETE && m_fModSet == (MOD_CONTROL | MOD_ALT) // skip "Ctrl+Alt+Del" + || wParam == VK_LWIN || wParam == VK_RWIN // skip "Win" + || wParam == VK_SNAPSHOT // skip "PrintScreen" + || wParam == VK_ESCAPE && (m_fModSet == MOD_CONTROL || m_fModSet == MOD_ALT) // skip "Ctrl+Esc", "Alt+Esc" + || wParam == VK_TAB && m_fModSet == MOD_ALT) { // skip "Alt+Tab" + m_fModSet = m_fModRel = 0; + m_vkCode = 0; + m_fIsPressed = FALSE; + } else if (wParam == m_vkCode && lParam) { + m_fIsPressed = FALSE; + fRedraw = FALSE; + } else { + if (!m_fIsPressed && !lParam) { // pressed a another key + if (m_fModRel & m_fModSet) { + m_fModSet = m_fModRel = 0; + } + m_vkCode = (UINT)wParam; + m_fIsPressed = TRUE; + } + } + } + if (fRedraw) { + UpdateText(); + } + + return 0L; +} + +LRESULT CWinHotkeyCtrl::OnLeftClick(WPARAM wParam, LPARAM lParam) +{ + CRect r; + CPoint pt; + CEditWithButton::GetWindowRect(r); + CRect rectButton = GetButtonRect(r); + pt = rectButton.BottomRight(); + pt.x = pt.x - (rectButton.Width()); + OnContextMenu(this, pt); + return 0; +} + +// CWinHotkeyCtrl message handlers + +void CWinHotkeyCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ +} + +BOOL CWinHotkeyCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + return FALSE; +} + +void CWinHotkeyCtrl::OnSetFocus(CWnd* pOldWnd) +{ + InstallKbHook(); + CEditWithButton::OnSetFocus(pOldWnd); +} + +void CWinHotkeyCtrl::OnKillFocus(CWnd* pNewWnd) +{ + UninstallKbHook(); + CEditWithButton::OnKillFocus(pNewWnd); +} + +void CWinHotkeyCtrl::OnContextMenu(CWnd*, CPoint pt) +{ + CMPCThemeMenu menu; + menu.CreatePopupMenu(); + UINT cod = 0, mod = 0; + menu.AppendMenu(MF_STRING, 1, ResStr(IDS_APPLY)); + menu.AppendMenu(MF_STRING, 2, ResStr(IDS_CLEAR)); + menu.AppendMenu(MF_STRING, 3, ResStr(IDS_CANCEL)); + if (AppNeedsThemedControls()) { + menu.fulfillThemeReqs(); + } + + UINT uMenuID = menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_VERPOSANIMATION | TPM_NONOTIFY | TPM_RETURNCMD, + pt.x, pt.y, this, nullptr); + + if (uMenuID) { + switch (uMenuID) { + case 1: + GetWinHotkey(&cod, &mod); + if (cod == 0 || m_vkCode == 0) { + mod = m_fModSet = m_fModRel = 0; + } + SetWinHotkey(cod, mod); + m_fIsPressed = FALSE; + break; + case 2: + m_fModSet = m_fModRel = 0; + m_vkCode = 0; + m_fIsPressed = FALSE; + break; + case 3: + m_fModSet = m_fModRel = m_fModSet_def; + m_vkCode = m_vkCode_def; + m_fIsPressed = FALSE; + break; + } + UpdateText(); + GetParent() ->SetFocus(); + } + +} + +void CWinHotkeyCtrl::OnDestroy() +{ + if (sm_pwhcFocus == this) { + sm_pwhcFocus->UninstallKbHook(); + } + CEditWithButton::OnDestroy(); +} diff --git a/src/mpc-hc/WinHotkeyCtrl.h b/src/mpc-hc/WinHotkeyCtrl.h index 6609a14c154..2147ff33cde 100644 --- a/src/mpc-hc/WinHotkeyCtrl.h +++ b/src/mpc-hc/WinHotkeyCtrl.h @@ -1,72 +1,72 @@ -/* - * (C) 2011-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 . - * - */ - -#pragma once - -#include "EditWithButton.h" - -// CWinHotkeyCtrl - -class CWinHotkeyCtrl : public CEditWithButton -{ - DECLARE_DYNAMIC(CWinHotkeyCtrl) - -public: - CWinHotkeyCtrl(); - virtual ~CWinHotkeyCtrl(); - - void UpdateText(); - DWORD GetWinHotkey(); - BOOL GetWinHotkey(UINT* pvkCode, UINT* pfModifiers); - void SetWinHotkey(DWORD dwHk); - void SetWinHotkey(UINT vkCode, UINT fModifiers); - virtual void DrawButton(CRect rectButton); - void SetIsMouseModifier(bool _isMouseModifier) { isMouseModifier = _isMouseModifier; }; - -private: - static HHOOK sm_hhookKb; - static CWinHotkeyCtrl* sm_pwhcFocus; - bool isMouseModifier; - - UINT m_vkCode, m_vkCode_def; - DWORD m_fModSet, m_fModRel, m_fModSet_def; - BOOL m_fIsPressed; - -private: - BOOL InstallKbHook(); - BOOL UninstallKbHook(); - - static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); - - afx_msg LRESULT OnKey(WPARAM wParam, LPARAM lParam); - -protected: - DECLARE_MESSAGE_MAP() -public: - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); - afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); - afx_msg void OnSetFocus(CWnd* pOldWnd); - afx_msg void OnKillFocus(CWnd* pNewWnd); - afx_msg void OnContextMenu(CWnd*, CPoint pt); - afx_msg void OnDestroy(); - afx_msg LRESULT OnLeftClick(WPARAM wParam, LPARAM lParam); -protected: - virtual void PreSubclassWindow(); -}; +/* + * (C) 2011-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 . + * + */ + +#pragma once + +#include "EditWithButton.h" + +// CWinHotkeyCtrl + +class CWinHotkeyCtrl : public CEditWithButton +{ + DECLARE_DYNAMIC(CWinHotkeyCtrl) + +public: + CWinHotkeyCtrl(); + virtual ~CWinHotkeyCtrl(); + + void UpdateText(); + DWORD GetWinHotkey(); + BOOL GetWinHotkey(UINT* pvkCode, UINT* pfModifiers); + void SetWinHotkey(DWORD dwHk); + void SetWinHotkey(UINT vkCode, UINT fModifiers); + virtual void DrawButton(CRect rectButton); + void SetIsMouseModifier(bool _isMouseModifier) { isMouseModifier = _isMouseModifier; }; + +private: + static HHOOK sm_hhookKb; + static CWinHotkeyCtrl* sm_pwhcFocus; + bool isMouseModifier; + + UINT m_vkCode, m_vkCode_def; + DWORD m_fModSet, m_fModRel, m_fModSet_def; + BOOL m_fIsPressed; + +private: + BOOL InstallKbHook(); + BOOL UninstallKbHook(); + + static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); + + afx_msg LRESULT OnKey(WPARAM wParam, LPARAM lParam); + +protected: + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnKillFocus(CWnd* pNewWnd); + afx_msg void OnContextMenu(CWnd*, CPoint pt); + afx_msg void OnDestroy(); + afx_msg LRESULT OnLeftClick(WPARAM wParam, LPARAM lParam); +protected: + virtual void PreSubclassWindow(); +}; diff --git a/src/mpc-hc/mpc-hc.vcxproj b/src/mpc-hc/mpc-hc.vcxproj index b1b0de618f7..8641c298138 100644 --- a/src/mpc-hc/mpc-hc.vcxproj +++ b/src/mpc-hc/mpc-hc.vcxproj @@ -1,843 +1,843 @@ - - - - - Debug Lite - Win32 - - - Debug Lite - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Lite - Win32 - - - Release Lite - x64 - - - Release - Win32 - - - Release - x64 - - - - mpc-hc - {8CE7E5D0-C821-47AC-A247-28EC95B34670} - mpc-hc - MFCProj - - - - - Application - Static - Unicode - - - - - - - - - - - $(SolutionDir)bin\mpc-hc_x86_$(Configuration)\ - $(SolutionDir)bin\mpc-hc_x86_$(Configuration)\ - $(SolutionDir)bin\mpc-hc_x64_$(Configuration)\ - $(SolutionDir)bin\mpc-hc_x64_$(Configuration)\ - $(SolutionDir)bin\mpc-hc_x86\ - $(SolutionDir)bin\mpc-hc_x86 Lite\ - $(SolutionDir)bin\mpc-hc_x64\ - $(SolutionDir)bin\mpc-hc_x64 Lite\ - $(ProjectName)64 - - - - ..\..\include;%(AdditionalIncludeDirectories) - - - crypt32.lib;delayimp.lib;dsound.lib;dxguid.lib;GdiPlus.lib;Psapi.lib;SetupAPI.lib;UxTheme.lib;Vfw32.lib;Winmm.lib;dwmapi.lib;strmiids.lib;Uuid.Lib;Version.lib;Bcrypt.lib;RuntimeObject.lib;%(AdditionalDependencies) - psapi.dll;api-ms-win-shcore-stream-winrt-l1-1-0.dll;api-ms-win-core-winrt-l1-1-0.dll;api-ms-win-core-winrt-string-l1-1-0.dll;%(DelayLoadDLLs) - true - - - ..\..\include;..\DSUtil;..\filters\renderer\VideoRenderers;..\thirdparty;..\thirdparty\AudioTools;..\thirdparty\MediaInfo\library\Source;..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) - - - $(ProjectDir)res\mpc-hc.exe.manifest %(AdditionalManifestFiles) - false - - - - - $(SolutionDir)lib64;$(SolutionDir)src\thirdparty\LAVFilters\src\thirdparty\64\lib;%(AdditionalLibraryDirectories) - - - - - $(SolutionDir)lib;$(SolutionDir)src\thirdparty\LAVFilters\src\thirdparty\32\lib;%(AdditionalLibraryDirectories) - - - - - $(SolutionDir)bin\lib\Release_$(Platform);%(AdditionalLibraryDirectories) - msvcrt.lib;vcruntime.lib;ucrt.lib - - - 26812 - NDEBUG;%(PreprocessorDefinitions) - USE_DRDUMP_CRASH_REPORTER=1;%(PreprocessorDefinitions) - - - - - 26812 - - - $(SolutionDir)bin\lib\Debug_$(Platform);%(AdditionalLibraryDirectories) - - - - - AudioSwitcher.lib;BaseClasses.lib;BaseMuxer.lib;BufferFilter.lib;CmdUI.lib;DeCSS.lib;DSMMuxer.lib;DSUtil.lib;Filters.lib;kasumi.lib;LCDUI.lib;lcms2.lib;MatroskaMuxer.lib;ResizableLib.lib;sizecbar.lib;StreamDriveThru.lib;SubPic.lib;Subtitles.lib;SubtitleSource.lib;SyncClock.lib;system.lib;TreePropSheet.lib;unrar.lib;VideoRenderers.lib;WavDest.lib;zlib.lib;minhook.lib;tinyxml2.lib;RARFileSource.lib;MpcAudioRenderer.lib;AudioTools.lib;ffmpeg.lib;freetype2.lib;%(AdditionalDependencies) - - - MPCHC_LITE;%(PreprocessorDefinitions) - - - false - - - - - RARFileSource.res;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ICO - - - ICO - - - ICO - - - ICO - - - - true - - - true - - - true - - - true - - - true - - - true - - - BMP - - - RC2 - - - RC2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {981574ae-5a5e-4f27-bdf1-1b841e374cff} - - - {1a2dfd1a-3c6c-44d1-909d-294af646b575} - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {1b6de4c0-9d27-4150-a327-e7f3b492b5f0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {db5f93b2-54d0-4474-a588-d259be36c832} - - - {65361c7c-83d6-42e4-870c-4dc85ae641fe} - - - {67827491-8162-4039-9132-f934abc836a0} - - - {eb202b68-8029-4985-b914-e94b44d2e230} - - - {37768b3f-89bc-4c16-b2a8-767c5da84c3f} - - - {1e91f58c-0bae-4021-8087-d1864d8ec066} - - - {ae399b7e-2b2c-4a96-9016-c5c74b0a2fa0} - - - {9f31d122-e84d-485a-a58d-09dad01a56ce} - - - {543d40e9-8ca6-4e4b-9936-90cba562b268} - - - {4d3b4ff4-535a-4201-ab7d-9aec1e737a95} - - - {664e726b-eeee-403a-ac15-345d9c9e1375} - - - {0b63409d-674d-47f8-a84e-87dbb7783189} - - - {fb565a7a-50dc-4a0d-852d-5e7f74dab82c} - - - {f50e74c2-5be7-4c9b-b1e7-6ca19cfad34e} - - - {8f998497-9c51-4faa-83e4-1d85b22cba13} - - - {d8db3e7e-d50e-4ec3-a9b9-dad18f5fe466} - - - {9dcfd02a-16a0-4766-bc18-66163e21929d} - - - {f6b06383-3ffd-403b-9867-4aa82a20aa83} - - - {d514ea4d-eafb-47a9-a437-a582ca571251} - - - {5e56335f-0fb1-4eea-b240-d8dc5e0608e4} - - - {0fd9bf8f-2397-4e23-b41e-e4624f35d646} - false - true - false - true - false - - - {438286b7-a9f4-411d-bcc5-948c40e37d8f} - - - {dbf1e8f7-5b7d-4cbf-842a-b7e0c02520dc} - - - {78b079bd-9fc7-4b9e-b4a6-96da0f00248b} - - - {08091723-a142-478b-a092-20741ba8fae2} - - - {9db795b7-e8bd-4846-82a5-c6d2577b1aaf} - - - {acf5c64b-78aa-4730-91a2-24f4910fbad9} - - - {19677dfd-c020-434d-9cb1-d0f105e72770} - - - {1704ea01-6b21-4362-9f1f-44d25cf2e0d7} - - - {85763f39-23df-4c04-b7df-7fbe3e7cf336} - - - {cfe70273-7a79-4815-af95-1e02e2675e37} - - - {d0620ef4-1313-40d5-9069-a82f6fe26994} - - - {2b7f22d7-1750-47c5-8709-1a3688b62499} - - - {bb2b61af-734a-4dad-9326-07f4f9ea088f} - false - true - false - true - false - - - {4c7a1953-cbc4-42d5-a12f-bb512c64b547} - false - true - false - true - false - - - {7cbde5a1-9cbb-4139-93f5-09d8dba4427f} - false - true - false - true - false - - - {e02f0c35-fb01-4059-90f9-9ac19dc22fba} - - - {da8461c4-7683-4360-9372-2a9e0f1795c2} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {f3d02050-f39a-4103-8343-09285359a495} - false - true - false - true - false - - - {2fcd4b66-9cf9-4c8f-bc70-37cd20002d49} - - - {03208025-d5c2-426a-b0fa-251d4338f30c} - - - {476b97b4-f079-4a44-af89-52ca30c35e28} - - - {4cc7ae86-3e0a-430a-bff4-bf00204cafb0} - - - {61e6eb4d-2f1a-443b-94b0-e8200b26e99f} - - - {ab494732-ef6d-44d0-bcf8-80ff04858d10} - - - {303B855A-137D-45E9-AF6D-B7241C6E66D6} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug Lite + Win32 + + + Debug Lite + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Lite + Win32 + + + Release Lite + x64 + + + Release + Win32 + + + Release + x64 + + + + mpc-hc + {8CE7E5D0-C821-47AC-A247-28EC95B34670} + mpc-hc + MFCProj + + + + + Application + Static + Unicode + + + + + + + + + + + $(SolutionDir)bin\mpc-hc_x86_$(Configuration)\ + $(SolutionDir)bin\mpc-hc_x86_$(Configuration)\ + $(SolutionDir)bin\mpc-hc_x64_$(Configuration)\ + $(SolutionDir)bin\mpc-hc_x64_$(Configuration)\ + $(SolutionDir)bin\mpc-hc_x86\ + $(SolutionDir)bin\mpc-hc_x86 Lite\ + $(SolutionDir)bin\mpc-hc_x64\ + $(SolutionDir)bin\mpc-hc_x64 Lite\ + $(ProjectName)64 + + + + ..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;delayimp.lib;dsound.lib;dxguid.lib;GdiPlus.lib;Psapi.lib;SetupAPI.lib;UxTheme.lib;Vfw32.lib;Winmm.lib;dwmapi.lib;strmiids.lib;Uuid.Lib;Version.lib;Bcrypt.lib;RuntimeObject.lib;%(AdditionalDependencies) + psapi.dll;api-ms-win-shcore-stream-winrt-l1-1-0.dll;api-ms-win-core-winrt-l1-1-0.dll;api-ms-win-core-winrt-string-l1-1-0.dll;%(DelayLoadDLLs) + true + + + ..\..\include;..\DSUtil;..\filters\renderer\VideoRenderers;..\thirdparty;..\thirdparty\AudioTools;..\thirdparty\MediaInfo\library\Source;..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) + + + $(ProjectDir)res\mpc-hc.exe.manifest %(AdditionalManifestFiles) + false + + + + + $(SolutionDir)lib64;$(SolutionDir)src\thirdparty\LAVFilters\src\thirdparty\64\lib;%(AdditionalLibraryDirectories) + + + + + $(SolutionDir)lib;$(SolutionDir)src\thirdparty\LAVFilters\src\thirdparty\32\lib;%(AdditionalLibraryDirectories) + + + + + $(SolutionDir)bin\lib\Release_$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;vcruntime.lib;ucrt.lib + + + 26812 + NDEBUG;%(PreprocessorDefinitions) + USE_DRDUMP_CRASH_REPORTER=1;%(PreprocessorDefinitions) + + + + + 26812 + + + $(SolutionDir)bin\lib\Debug_$(Platform);%(AdditionalLibraryDirectories) + + + + + AudioSwitcher.lib;BaseClasses.lib;BaseMuxer.lib;BufferFilter.lib;CmdUI.lib;DeCSS.lib;DSMMuxer.lib;DSUtil.lib;Filters.lib;kasumi.lib;LCDUI.lib;lcms2.lib;MatroskaMuxer.lib;ResizableLib.lib;sizecbar.lib;StreamDriveThru.lib;SubPic.lib;Subtitles.lib;SubtitleSource.lib;SyncClock.lib;system.lib;TreePropSheet.lib;unrar.lib;VideoRenderers.lib;WavDest.lib;zlib.lib;minhook.lib;tinyxml2.lib;RARFileSource.lib;MpcAudioRenderer.lib;AudioTools.lib;ffmpeg.lib;freetype2.lib;%(AdditionalDependencies) + + + MPCHC_LITE;%(PreprocessorDefinitions) + + + false + + + + + RARFileSource.res;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICO + + + ICO + + + ICO + + + ICO + + + + true + + + true + + + true + + + true + + + true + + + true + + + BMP + + + RC2 + + + RC2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {981574ae-5a5e-4f27-bdf1-1b841e374cff} + + + {1a2dfd1a-3c6c-44d1-909d-294af646b575} + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {1b6de4c0-9d27-4150-a327-e7f3b492b5f0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {db5f93b2-54d0-4474-a588-d259be36c832} + + + {65361c7c-83d6-42e4-870c-4dc85ae641fe} + + + {67827491-8162-4039-9132-f934abc836a0} + + + {eb202b68-8029-4985-b914-e94b44d2e230} + + + {37768b3f-89bc-4c16-b2a8-767c5da84c3f} + + + {1e91f58c-0bae-4021-8087-d1864d8ec066} + + + {ae399b7e-2b2c-4a96-9016-c5c74b0a2fa0} + + + {9f31d122-e84d-485a-a58d-09dad01a56ce} + + + {543d40e9-8ca6-4e4b-9936-90cba562b268} + + + {4d3b4ff4-535a-4201-ab7d-9aec1e737a95} + + + {664e726b-eeee-403a-ac15-345d9c9e1375} + + + {0b63409d-674d-47f8-a84e-87dbb7783189} + + + {fb565a7a-50dc-4a0d-852d-5e7f74dab82c} + + + {f50e74c2-5be7-4c9b-b1e7-6ca19cfad34e} + + + {8f998497-9c51-4faa-83e4-1d85b22cba13} + + + {d8db3e7e-d50e-4ec3-a9b9-dad18f5fe466} + + + {9dcfd02a-16a0-4766-bc18-66163e21929d} + + + {f6b06383-3ffd-403b-9867-4aa82a20aa83} + + + {d514ea4d-eafb-47a9-a437-a582ca571251} + + + {5e56335f-0fb1-4eea-b240-d8dc5e0608e4} + + + {0fd9bf8f-2397-4e23-b41e-e4624f35d646} + false + true + false + true + false + + + {438286b7-a9f4-411d-bcc5-948c40e37d8f} + + + {dbf1e8f7-5b7d-4cbf-842a-b7e0c02520dc} + + + {78b079bd-9fc7-4b9e-b4a6-96da0f00248b} + + + {08091723-a142-478b-a092-20741ba8fae2} + + + {9db795b7-e8bd-4846-82a5-c6d2577b1aaf} + + + {acf5c64b-78aa-4730-91a2-24f4910fbad9} + + + {19677dfd-c020-434d-9cb1-d0f105e72770} + + + {1704ea01-6b21-4362-9f1f-44d25cf2e0d7} + + + {85763f39-23df-4c04-b7df-7fbe3e7cf336} + + + {cfe70273-7a79-4815-af95-1e02e2675e37} + + + {d0620ef4-1313-40d5-9069-a82f6fe26994} + + + {2b7f22d7-1750-47c5-8709-1a3688b62499} + + + {bb2b61af-734a-4dad-9326-07f4f9ea088f} + false + true + false + true + false + + + {4c7a1953-cbc4-42d5-a12f-bb512c64b547} + false + true + false + true + false + + + {7cbde5a1-9cbb-4139-93f5-09d8dba4427f} + false + true + false + true + false + + + {e02f0c35-fb01-4059-90f9-9ac19dc22fba} + + + {da8461c4-7683-4360-9372-2a9e0f1795c2} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {f3d02050-f39a-4103-8343-09285359a495} + false + true + false + true + false + + + {2fcd4b66-9cf9-4c8f-bc70-37cd20002d49} + + + {03208025-d5c2-426a-b0fa-251d4338f30c} + + + {476b97b4-f079-4a44-af89-52ca30c35e28} + + + {4cc7ae86-3e0a-430a-bff4-bf00204cafb0} + + + {61e6eb4d-2f1a-443b-94b0-e8200b26e99f} + + + {ab494732-ef6d-44d0-bcf8-80ff04858d10} + + + {303B855A-137D-45E9-AF6D-B7241C6E66D6} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/mpc-hc/mpc-hc.vcxproj.filters b/src/mpc-hc/mpc-hc.vcxproj.filters index 0eed9ce49c5..b1cb82c3350 100644 --- a/src/mpc-hc/mpc-hc.vcxproj.filters +++ b/src/mpc-hc/mpc-hc.vcxproj.filters @@ -1,1477 +1,1477 @@ - - - - - {43c75f5f-5e94-4d15-8f45-b39b7c36bd62} - - - {77a009db-eea1-41f2-8671-661a4843634e} - - - {36ad4cd9-ded8-4c35-8a6d-1ffb3ddc2684} - - - {ad577ec8-11b8-4fcf-8b57-72f6cdabf032} - - - {cf28b89c-1840-4771-ad84-96c85e9958b5} - - - {cea104bc-b14e-42eb-9bf9-2201c523f77d} - - - {ff5c37c3-46a0-4f57-b30e-02d892b73a00} - - - {b48234f3-b7a0-4dc2-b23b-f4c33349aab1} - - - {bd4abfc8-fc90-4a1d-adc4-7800f1ad7d31} - - - {aa019fb8-debd-45de-af25-ab3d5e22a7f3} - - - {c65b298e-e9cf-447f-a27a-1d30b7bd7d81} - - - {6c92dae3-76cc-449a-aa1d-f6d72742e757} - - - {ee8489ea-968c-44c9-ae3a-35eb518513d2} - ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - {26bd0b2a-4fea-4c63-b05b-f28243ac8d95} - - - {85c6230e-fa6b-497b-8d98-d4a066c86f48} - - - {662236d7-ad89-4026-bb57-bb27667da2e6} - - - {631eb474-a93b-4b48-a054-9758e8a1f959} - - - {361375c5-889a-4432-90ba-83741194f7d1} - - - {ef61c989-5105-4782-9fed-e8a56be95a46} - - - {4a9b9989-f6a5-499e-9611-c7bfe024b7a3} - - - {3e62affc-727b-4af9-95eb-76f4eb63918c} - - - {d7f40587-25b5-46f1-90bb-6751caca4922} - - - {c80b5d75-ba77-444e-98a0-c5af5d89a88c} - - - {acb8c198-52e0-46e0-9e15-8991856fcb18} - - - {0453474a-2716-4c52-b5f4-cf6bd9e31ed0} - - - {1d73f7db-64e8-4bc8-b0ca-72847253f467} - - - {20afe682-61a3-4123-9012-4c918a03f482} - - - {3161f4ab-a606-4c27-9c63-d360ba1ffdc4} - - - {1cb607bd-a0b1-4e2b-b73f-54332475cb25} - - - {f0d8891c-1071-47c7-97bd-2ce27c366246} - - - - - Player Config - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Custom Controls - - - Modal Dialogs - - - Custom Controls - - - Custom Controls - - - DVB - - - Modal Dialogs - - - Modal Dialogs - - - Graph - - - Graph - - - Graph - - - Graph - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Toolbars - - - Toolbars - - - Property Dialogs\LAV Filters Options - - - Property Dialogs\LAV Filters Options - - - Graph\Shockwave Flash - - - Player Config - - - Custom Controls - - - DVB - - - Helpers - - - Integration\Logitech LCD - - - Player Config - - - Modal Dialogs - - - Helpers - - - Helpers - - - DVB - - - Helpers - - - Helpers - - - Panels - - - Toolbars - - - Custom Controls - - - Toolbars - - - Modal Dialogs - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\File Properties - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Player Config - - - Graph\Shockwave Flash - - - Integration\Skype - - - Custom Controls - - - Custom Controls - - - Subtitles - - - Subtitles - - - Subtitles - - - Subtitles - - - Player Config - - - Modal Dialogs - - - Modal Dialogs - - - Build Info - - - Helpers - - - Custom Controls - - - Integration\Web - - - Integration\Web - - - Integration\Web - - - Custom Controls - - - Graph - - - Graph - - - - Graph - - - Graph - - - Graph - - - Graph - - - - - - - - - - Main View - - - Main View - - - Main View - - - Main View - - - Panels - - - Panels - - - Panels - - - Panels - - - Panels - - - Panels - - - Helpers - - - Crash Reporter - - - Property Dialogs\Player Options\Pages - - - Helpers - - - Subtitles - - - Helpers - - - Helpers - - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme\thirdparty - - - MPCTheme\thirdparty - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - - MPCTheme - - - Toolbars - - - Main View - - - Modal Dialogs - - - Main View - - - Property Dialogs\Player Options\Pages - - - MPCTheme - - - Helpers - - - MPCTheme - - - MPCTheme - - - - Main View - - - Helpers - - - Property Dialogs\Player Options\Pages - - - Modal Dialogs - - - Modal Dialogs - - - Property Dialogs\Player Options\Pages - - - - - Player Config - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Custom Controls - - - Modal Dialogs - - - Custom Controls - - - Custom Controls - - - DVB - - - Modal Dialogs - - - Modal Dialogs - - - Graph - - - Graph - - - Graph - - - Graph - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Toolbars - - - Toolbars - - - Property Dialogs\LAV Filters Options - - - Property Dialogs\LAV Filters Options - - - Graph\Shockwave Flash - - - Player Config - - - Custom Controls - - - DVB - - - Helpers - - - Player Config - - - Integration\Logitech LCD - - - Player Config - - - Modal Dialogs - - - Helpers - - - Integration - - - Helpers - - - DVB - - - Helpers - - - Helpers - - - Panels - - - Toolbars - - - Custom Controls - - - Toolbars - - - Modal Dialogs - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\File Properties - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Player Config - - - Player Config - - - Graph\Shockwave Flash - - - Integration\Skype - - - Custom Controls - - - Custom Controls - - - Helpers - - - Subtitles - - - Subtitles - - - Subtitles - - - Subtitles - - - Helpers - - - Player Config - - - Modal Dialogs - - - Modal Dialogs - - - Build Info - - - Helpers - - - Custom Controls - - - Integration\Web - - - Integration\Web - - - Integration\Web - - - Custom Controls - - - Graph - - - Graph - - - - Graph - - - Graph - - - Graph - - - Graph - - - Graph - - - Graph - - - - - - - - - - - Main View - - - Main View - - - Main View - - - Main View - - - Build Info - - - Panels - - - Panels - - - Panels - - - Panels - - - Panels - - - Panels - - - Helpers - - - Helpers - - - Crash Reporter - - - Property Dialogs\Player Options\Pages - - - Helpers - - - Subtitles - - - Helpers - - - Helpers - - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme\thirdparty - - - MPCTheme\thirdparty - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - - MPCTheme - - - Toolbars - - - Main View - - - Modal Dialogs - - - Main View - - - - Property Dialogs\Player Options\Pages - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - - Main View - - - Helpers - - - Property Dialogs\Player Options\Pages - - - Modal Dialogs - - - Modal Dialogs - - - Property Dialogs\Player Options\Pages - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files\shaders - - - Resource Files\shaders - - - Resource Files\shaders - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files - - - - - Resource Files - - - - - Resource Files - - - - - Resource Files - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - - - - - - - - - Resource Files - - - Resource Files - - - Resource Files - - + + + + + {43c75f5f-5e94-4d15-8f45-b39b7c36bd62} + + + {77a009db-eea1-41f2-8671-661a4843634e} + + + {36ad4cd9-ded8-4c35-8a6d-1ffb3ddc2684} + + + {ad577ec8-11b8-4fcf-8b57-72f6cdabf032} + + + {cf28b89c-1840-4771-ad84-96c85e9958b5} + + + {cea104bc-b14e-42eb-9bf9-2201c523f77d} + + + {ff5c37c3-46a0-4f57-b30e-02d892b73a00} + + + {b48234f3-b7a0-4dc2-b23b-f4c33349aab1} + + + {bd4abfc8-fc90-4a1d-adc4-7800f1ad7d31} + + + {aa019fb8-debd-45de-af25-ab3d5e22a7f3} + + + {c65b298e-e9cf-447f-a27a-1d30b7bd7d81} + + + {6c92dae3-76cc-449a-aa1d-f6d72742e757} + + + {ee8489ea-968c-44c9-ae3a-35eb518513d2} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {26bd0b2a-4fea-4c63-b05b-f28243ac8d95} + + + {85c6230e-fa6b-497b-8d98-d4a066c86f48} + + + {662236d7-ad89-4026-bb57-bb27667da2e6} + + + {631eb474-a93b-4b48-a054-9758e8a1f959} + + + {361375c5-889a-4432-90ba-83741194f7d1} + + + {ef61c989-5105-4782-9fed-e8a56be95a46} + + + {4a9b9989-f6a5-499e-9611-c7bfe024b7a3} + + + {3e62affc-727b-4af9-95eb-76f4eb63918c} + + + {d7f40587-25b5-46f1-90bb-6751caca4922} + + + {c80b5d75-ba77-444e-98a0-c5af5d89a88c} + + + {acb8c198-52e0-46e0-9e15-8991856fcb18} + + + {0453474a-2716-4c52-b5f4-cf6bd9e31ed0} + + + {1d73f7db-64e8-4bc8-b0ca-72847253f467} + + + {20afe682-61a3-4123-9012-4c918a03f482} + + + {3161f4ab-a606-4c27-9c63-d360ba1ffdc4} + + + {1cb607bd-a0b1-4e2b-b73f-54332475cb25} + + + {f0d8891c-1071-47c7-97bd-2ce27c366246} + + + + + Player Config + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Custom Controls + + + Modal Dialogs + + + Custom Controls + + + Custom Controls + + + DVB + + + Modal Dialogs + + + Modal Dialogs + + + Graph + + + Graph + + + Graph + + + Graph + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Toolbars + + + Toolbars + + + Property Dialogs\LAV Filters Options + + + Property Dialogs\LAV Filters Options + + + Graph\Shockwave Flash + + + Player Config + + + Custom Controls + + + DVB + + + Helpers + + + Integration\Logitech LCD + + + Player Config + + + Modal Dialogs + + + Helpers + + + Helpers + + + DVB + + + Helpers + + + Helpers + + + Panels + + + Toolbars + + + Custom Controls + + + Toolbars + + + Modal Dialogs + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\File Properties + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Player Config + + + Graph\Shockwave Flash + + + Integration\Skype + + + Custom Controls + + + Custom Controls + + + Subtitles + + + Subtitles + + + Subtitles + + + Subtitles + + + Player Config + + + Modal Dialogs + + + Modal Dialogs + + + Build Info + + + Helpers + + + Custom Controls + + + Integration\Web + + + Integration\Web + + + Integration\Web + + + Custom Controls + + + Graph + + + Graph + + + + Graph + + + Graph + + + Graph + + + Graph + + + + + + + + + + Main View + + + Main View + + + Main View + + + Main View + + + Panels + + + Panels + + + Panels + + + Panels + + + Panels + + + Panels + + + Helpers + + + Crash Reporter + + + Property Dialogs\Player Options\Pages + + + Helpers + + + Subtitles + + + Helpers + + + Helpers + + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme\thirdparty + + + MPCTheme\thirdparty + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + + MPCTheme + + + Toolbars + + + Main View + + + Modal Dialogs + + + Main View + + + Property Dialogs\Player Options\Pages + + + MPCTheme + + + Helpers + + + MPCTheme + + + MPCTheme + + + + Main View + + + Helpers + + + Property Dialogs\Player Options\Pages + + + Modal Dialogs + + + Modal Dialogs + + + Property Dialogs\Player Options\Pages + + + + + Player Config + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Custom Controls + + + Modal Dialogs + + + Custom Controls + + + Custom Controls + + + DVB + + + Modal Dialogs + + + Modal Dialogs + + + Graph + + + Graph + + + Graph + + + Graph + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Toolbars + + + Toolbars + + + Property Dialogs\LAV Filters Options + + + Property Dialogs\LAV Filters Options + + + Graph\Shockwave Flash + + + Player Config + + + Custom Controls + + + DVB + + + Helpers + + + Player Config + + + Integration\Logitech LCD + + + Player Config + + + Modal Dialogs + + + Helpers + + + Integration + + + Helpers + + + DVB + + + Helpers + + + Helpers + + + Panels + + + Toolbars + + + Custom Controls + + + Toolbars + + + Modal Dialogs + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\File Properties + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Player Config + + + Player Config + + + Graph\Shockwave Flash + + + Integration\Skype + + + Custom Controls + + + Custom Controls + + + Helpers + + + Subtitles + + + Subtitles + + + Subtitles + + + Subtitles + + + Helpers + + + Player Config + + + Modal Dialogs + + + Modal Dialogs + + + Build Info + + + Helpers + + + Custom Controls + + + Integration\Web + + + Integration\Web + + + Integration\Web + + + Custom Controls + + + Graph + + + Graph + + + + Graph + + + Graph + + + Graph + + + Graph + + + Graph + + + Graph + + + + + + + + + + + Main View + + + Main View + + + Main View + + + Main View + + + Build Info + + + Panels + + + Panels + + + Panels + + + Panels + + + Panels + + + Panels + + + Helpers + + + Helpers + + + Crash Reporter + + + Property Dialogs\Player Options\Pages + + + Helpers + + + Subtitles + + + Helpers + + + Helpers + + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme\thirdparty + + + MPCTheme\thirdparty + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + + MPCTheme + + + Toolbars + + + Main View + + + Modal Dialogs + + + Main View + + + + Property Dialogs\Player Options\Pages + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + + Main View + + + Helpers + + + Property Dialogs\Player Options\Pages + + + Modal Dialogs + + + Modal Dialogs + + + Property Dialogs\Player Options\Pages + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files\shaders + + + Resource Files\shaders + + + Resource Files\shaders + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files + + + + + Resource Files + + + + + Resource Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + + + + + + + + + Resource Files + + + Resource Files + + + Resource Files + + \ No newline at end of file diff --git a/src/mpc-hc/mpciconlib/mpciconlib.cpp b/src/mpc-hc/mpciconlib/mpciconlib.cpp index 579eee56e7d..3ece30da1f3 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.cpp +++ b/src/mpc-hc/mpciconlib/mpciconlib.cpp @@ -1,273 +1,273 @@ -/* - * (C) 2008-2013, 2015 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 . - * - */ - -#include -#include - -#include "mpciconlib.h" - -int main() -{ - return 0; -} - -extern "C" __declspec(dllexport) UINT GetIconLibVersion() -{ - return ICON_LIB_VERSION; -} - -extern "C" __declspec(dllexport) int GetIconIndex(LPCTSTR ext) -{ - int iconIndex = IDI_NONE; - - if (_tcsicmp(ext, _T(".3g2")) == 0) { - iconIndex = IDI_MOV_ICON; - } else if (_tcsicmp(ext, _T(".3ga")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".3gp")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".3gp2")) == 0) { - iconIndex = IDI_MOV_ICON; - } else if (_tcsicmp(ext, _T(".3gpp")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".aac")) == 0) { - iconIndex = IDI_AAC_ICON; - } else if (_tcsicmp(ext, _T(".ac3")) == 0) { - iconIndex = IDI_AC3_ICON; - } else if (_tcsicmp(ext, _T(".aif")) == 0) { - iconIndex = IDI_AIFF_ICON; - } else if (_tcsicmp(ext, _T(".aifc")) == 0) { - iconIndex = IDI_AIFF_ICON; - } else if (_tcsicmp(ext, _T(".aiff")) == 0) { - iconIndex = IDI_AIFF_ICON; - } else if (_tcsicmp(ext, _T(".alac")) == 0) { - iconIndex = IDI_ALAC_ICON; - } else if (_tcsicmp(ext, _T(".amr")) == 0) { - iconIndex = IDI_AMR_ICON; - } else if (_tcsicmp(ext, _T(".amv")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".aob")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".ape")) == 0) { - iconIndex = IDI_APE_ICON; - } else if (_tcsicmp(ext, _T(".apl")) == 0) { - iconIndex = IDI_APE_ICON; - } else if (_tcsicmp(ext, _T(".asf")) == 0) { - iconIndex = IDI_WMV_ICON; - } else if (_tcsicmp(ext, _T(".asx")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".au")) == 0) { - iconIndex = IDI_AU_ICON; - } else if (_tcsicmp(ext, _T(".avi")) == 0) { - iconIndex = IDI_AVI_ICON; - } else if (_tcsicmp(ext, _T(".bdmv")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".bik")) == 0) { - iconIndex = IDI_BINK_ICON; - } else if (_tcsicmp(ext, _T(".cda")) == 0) { - iconIndex = IDI_CDA_ICON; - } else if (_tcsicmp(ext, _T(".divx")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".dsa")) == 0) { - iconIndex = IDI_DSM_ICON; - } else if (_tcsicmp(ext, _T(".dsm")) == 0) { - iconIndex = IDI_DSM_ICON; - } else if (_tcsicmp(ext, _T(".dss")) == 0) { - iconIndex = IDI_DSM_ICON; - } else if (_tcsicmp(ext, _T(".dsv")) == 0) { - iconIndex = IDI_DSM_ICON; - } else if (_tcsicmp(ext, _T(".dts")) == 0) { - iconIndex = IDI_DTS_ICON; - } else if (_tcsicmp(ext, _T(".dtshd")) == 0) { - iconIndex = IDI_DTS_ICON; - } else if (_tcsicmp(ext, _T(".dtsma")) == 0) { - iconIndex = IDI_DTS_ICON; - } else if (_tcsicmp(ext, _T(".evo")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".f4v")) == 0) { - iconIndex = IDI_FLV_ICON; - } else if (_tcsicmp(ext, _T(".flac")) == 0) { - iconIndex = IDI_FLAC_ICON; - } else if (_tcsicmp(ext, _T(".flc")) == 0) { - iconIndex = IDI_FLIC_ICON; - } else if (_tcsicmp(ext, _T(".fli")) == 0) { - iconIndex = IDI_FLIC_ICON; - } else if (_tcsicmp(ext, _T(".flic")) == 0) { - iconIndex = IDI_FLIC_ICON; - } else if (_tcsicmp(ext, _T(".flv")) == 0) { - iconIndex = IDI_FLV_ICON; - } else if (_tcsicmp(ext, _T(".hdmov")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".iflv")) == 0) { - iconIndex = IDI_FLV_ICON; - } else if (_tcsicmp(ext, _T(".ifo")) == 0) { - iconIndex = IDI_IFO_ICON; - } else if (_tcsicmp(ext, _T(".ivf")) == 0) { - iconIndex = IDI_IVF_ICON; - } else if (_tcsicmp(ext, _T(".m1a")) == 0) { - iconIndex = IDI_MPA_ICON; - } else if (_tcsicmp(ext, _T(".m1v")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".m2a")) == 0) { - iconIndex = IDI_MPA_ICON; - } else if (_tcsicmp(ext, _T(".m2p")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".m2t")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".m2ts")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".m2v")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".m3u")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".m3u8")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".m4a")) == 0) { - iconIndex = IDI_AAC_ICON; - } else if (_tcsicmp(ext, _T(".m4b")) == 0) { - iconIndex = IDI_AAC_ICON; - } else if (_tcsicmp(ext, _T(".m4r")) == 0) { - iconIndex = IDI_AAC_ICON; - } else if (_tcsicmp(ext, _T(".m4v")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".mid")) == 0) { - iconIndex = IDI_MIDI_ICON; - } else if (_tcsicmp(ext, _T(".midi")) == 0) { - iconIndex = IDI_MIDI_ICON; - } else if (_tcsicmp(ext, _T(".mka")) == 0) { - iconIndex = IDI_MKA_ICON; - } else if (_tcsicmp(ext, _T(".mkv")) == 0) { - iconIndex = IDI_MKV_ICON; - } else if (_tcsicmp(ext, _T(".mlp")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".mov")) == 0) { - iconIndex = IDI_MOV_ICON; - } else if (_tcsicmp(ext, _T(".mp2")) == 0) { - iconIndex = IDI_MPA_ICON; - } else if (_tcsicmp(ext, _T(".mp2v")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mp3")) == 0) { - iconIndex = IDI_MP3_ICON; - } else if (_tcsicmp(ext, _T(".mp4")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".mp4v")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".mpa")) == 0) { - iconIndex = IDI_MPA_ICON; - } else if (_tcsicmp(ext, _T(".mpc")) == 0) { - iconIndex = IDI_MPC_ICON; - } else if (_tcsicmp(ext, _T(".mpcpl")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".cue")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".mpe")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mpeg")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mpg")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mpls")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".mpv2")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mpv4")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".mts")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".ofr")) == 0) { - iconIndex = IDI_OFR_ICON; - } else if (_tcsicmp(ext, _T(".ofs")) == 0) { - iconIndex = IDI_OFR_ICON; - } else if (_tcsicmp(ext, _T(".oga")) == 0) { - iconIndex = IDI_OGG_ICON; - } else if (_tcsicmp(ext, _T(".ogg")) == 0) { - iconIndex = IDI_OGG_ICON; - } else if (_tcsicmp(ext, _T(".ogm")) == 0) { - iconIndex = IDI_OGM_ICON; - } else if (_tcsicmp(ext, _T(".ogv")) == 0) { - iconIndex = IDI_OGM_ICON; - } else if (_tcsicmp(ext, _T(".opus")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".pls")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".pva")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".ra")) == 0) { - iconIndex = IDI_RA_ICON; - } else if (_tcsicmp(ext, _T(".ram")) == 0) { - iconIndex = IDI_RM_ICON; - } else if (_tcsicmp(ext, _T(".rm")) == 0) { - iconIndex = IDI_RM_ICON; - } else if (_tcsicmp(ext, _T(".rmi")) == 0) { - iconIndex = IDI_MIDI_ICON; - } else if (_tcsicmp(ext, _T(".rmm")) == 0) { - iconIndex = IDI_RM_ICON; - } else if (_tcsicmp(ext, _T(".rmvb")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".rp")) == 0) { - iconIndex = IDI_RT_ICON; - } else if (_tcsicmp(ext, _T(".rt")) == 0) { - iconIndex = IDI_RT_ICON; - } else if (_tcsicmp(ext, _T(".smil")) == 0) { - iconIndex = IDI_RT_ICON; - } else if (_tcsicmp(ext, _T(".smk")) == 0) { - iconIndex = IDI_SMK_ICON; - } else if (_tcsicmp(ext, _T(".snd")) == 0) { - iconIndex = IDI_AU_ICON; - } else if (_tcsicmp(ext, _T(".swf")) == 0) { - iconIndex = IDI_SWF_ICON; - } else if (_tcsicmp(ext, _T(".tp")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".trp")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".ts")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".rec")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".tak")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".tta")) == 0) { - iconIndex = IDI_TTA_ICON; - } else if (_tcsicmp(ext, _T(".vob")) == 0) { - iconIndex = IDI_VOB_ICON; - } else if (_tcsicmp(ext, _T(".wav")) == 0) { - iconIndex = IDI_WAV_ICON; - } else if (_tcsicmp(ext, _T(".wax")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".webm")) == 0) { - iconIndex = IDI_WEBM_ICON; - } else if (_tcsicmp(ext, _T(".wm")) == 0) { - iconIndex = IDI_WMV_ICON; - } else if (_tcsicmp(ext, _T(".wma")) == 0) { - iconIndex = IDI_WMA_ICON; - } else if (_tcsicmp(ext, _T(".wmp")) == 0) { - iconIndex = IDI_WMV_ICON; - } else if (_tcsicmp(ext, _T(".wmv")) == 0) { - iconIndex = IDI_WMV_ICON; - } else if (_tcsicmp(ext, _T(".wmx")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".wv")) == 0) { - iconIndex = IDI_WV_ICON; - } else if (_tcsicmp(ext, _T(".wvx")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } - - return iconIndex; -} +/* + * (C) 2008-2013, 2015 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 . + * + */ + +#include +#include + +#include "mpciconlib.h" + +int main() +{ + return 0; +} + +extern "C" __declspec(dllexport) UINT GetIconLibVersion() +{ + return ICON_LIB_VERSION; +} + +extern "C" __declspec(dllexport) int GetIconIndex(LPCTSTR ext) +{ + int iconIndex = IDI_NONE; + + if (_tcsicmp(ext, _T(".3g2")) == 0) { + iconIndex = IDI_MOV_ICON; + } else if (_tcsicmp(ext, _T(".3ga")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".3gp")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".3gp2")) == 0) { + iconIndex = IDI_MOV_ICON; + } else if (_tcsicmp(ext, _T(".3gpp")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".aac")) == 0) { + iconIndex = IDI_AAC_ICON; + } else if (_tcsicmp(ext, _T(".ac3")) == 0) { + iconIndex = IDI_AC3_ICON; + } else if (_tcsicmp(ext, _T(".aif")) == 0) { + iconIndex = IDI_AIFF_ICON; + } else if (_tcsicmp(ext, _T(".aifc")) == 0) { + iconIndex = IDI_AIFF_ICON; + } else if (_tcsicmp(ext, _T(".aiff")) == 0) { + iconIndex = IDI_AIFF_ICON; + } else if (_tcsicmp(ext, _T(".alac")) == 0) { + iconIndex = IDI_ALAC_ICON; + } else if (_tcsicmp(ext, _T(".amr")) == 0) { + iconIndex = IDI_AMR_ICON; + } else if (_tcsicmp(ext, _T(".amv")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".aob")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".ape")) == 0) { + iconIndex = IDI_APE_ICON; + } else if (_tcsicmp(ext, _T(".apl")) == 0) { + iconIndex = IDI_APE_ICON; + } else if (_tcsicmp(ext, _T(".asf")) == 0) { + iconIndex = IDI_WMV_ICON; + } else if (_tcsicmp(ext, _T(".asx")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".au")) == 0) { + iconIndex = IDI_AU_ICON; + } else if (_tcsicmp(ext, _T(".avi")) == 0) { + iconIndex = IDI_AVI_ICON; + } else if (_tcsicmp(ext, _T(".bdmv")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".bik")) == 0) { + iconIndex = IDI_BINK_ICON; + } else if (_tcsicmp(ext, _T(".cda")) == 0) { + iconIndex = IDI_CDA_ICON; + } else if (_tcsicmp(ext, _T(".divx")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".dsa")) == 0) { + iconIndex = IDI_DSM_ICON; + } else if (_tcsicmp(ext, _T(".dsm")) == 0) { + iconIndex = IDI_DSM_ICON; + } else if (_tcsicmp(ext, _T(".dss")) == 0) { + iconIndex = IDI_DSM_ICON; + } else if (_tcsicmp(ext, _T(".dsv")) == 0) { + iconIndex = IDI_DSM_ICON; + } else if (_tcsicmp(ext, _T(".dts")) == 0) { + iconIndex = IDI_DTS_ICON; + } else if (_tcsicmp(ext, _T(".dtshd")) == 0) { + iconIndex = IDI_DTS_ICON; + } else if (_tcsicmp(ext, _T(".dtsma")) == 0) { + iconIndex = IDI_DTS_ICON; + } else if (_tcsicmp(ext, _T(".evo")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".f4v")) == 0) { + iconIndex = IDI_FLV_ICON; + } else if (_tcsicmp(ext, _T(".flac")) == 0) { + iconIndex = IDI_FLAC_ICON; + } else if (_tcsicmp(ext, _T(".flc")) == 0) { + iconIndex = IDI_FLIC_ICON; + } else if (_tcsicmp(ext, _T(".fli")) == 0) { + iconIndex = IDI_FLIC_ICON; + } else if (_tcsicmp(ext, _T(".flic")) == 0) { + iconIndex = IDI_FLIC_ICON; + } else if (_tcsicmp(ext, _T(".flv")) == 0) { + iconIndex = IDI_FLV_ICON; + } else if (_tcsicmp(ext, _T(".hdmov")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".iflv")) == 0) { + iconIndex = IDI_FLV_ICON; + } else if (_tcsicmp(ext, _T(".ifo")) == 0) { + iconIndex = IDI_IFO_ICON; + } else if (_tcsicmp(ext, _T(".ivf")) == 0) { + iconIndex = IDI_IVF_ICON; + } else if (_tcsicmp(ext, _T(".m1a")) == 0) { + iconIndex = IDI_MPA_ICON; + } else if (_tcsicmp(ext, _T(".m1v")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".m2a")) == 0) { + iconIndex = IDI_MPA_ICON; + } else if (_tcsicmp(ext, _T(".m2p")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".m2t")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".m2ts")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".m2v")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".m3u")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".m3u8")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".m4a")) == 0) { + iconIndex = IDI_AAC_ICON; + } else if (_tcsicmp(ext, _T(".m4b")) == 0) { + iconIndex = IDI_AAC_ICON; + } else if (_tcsicmp(ext, _T(".m4r")) == 0) { + iconIndex = IDI_AAC_ICON; + } else if (_tcsicmp(ext, _T(".m4v")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".mid")) == 0) { + iconIndex = IDI_MIDI_ICON; + } else if (_tcsicmp(ext, _T(".midi")) == 0) { + iconIndex = IDI_MIDI_ICON; + } else if (_tcsicmp(ext, _T(".mka")) == 0) { + iconIndex = IDI_MKA_ICON; + } else if (_tcsicmp(ext, _T(".mkv")) == 0) { + iconIndex = IDI_MKV_ICON; + } else if (_tcsicmp(ext, _T(".mlp")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".mov")) == 0) { + iconIndex = IDI_MOV_ICON; + } else if (_tcsicmp(ext, _T(".mp2")) == 0) { + iconIndex = IDI_MPA_ICON; + } else if (_tcsicmp(ext, _T(".mp2v")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mp3")) == 0) { + iconIndex = IDI_MP3_ICON; + } else if (_tcsicmp(ext, _T(".mp4")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".mp4v")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".mpa")) == 0) { + iconIndex = IDI_MPA_ICON; + } else if (_tcsicmp(ext, _T(".mpc")) == 0) { + iconIndex = IDI_MPC_ICON; + } else if (_tcsicmp(ext, _T(".mpcpl")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".cue")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".mpe")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mpeg")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mpg")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mpls")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".mpv2")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mpv4")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".mts")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".ofr")) == 0) { + iconIndex = IDI_OFR_ICON; + } else if (_tcsicmp(ext, _T(".ofs")) == 0) { + iconIndex = IDI_OFR_ICON; + } else if (_tcsicmp(ext, _T(".oga")) == 0) { + iconIndex = IDI_OGG_ICON; + } else if (_tcsicmp(ext, _T(".ogg")) == 0) { + iconIndex = IDI_OGG_ICON; + } else if (_tcsicmp(ext, _T(".ogm")) == 0) { + iconIndex = IDI_OGM_ICON; + } else if (_tcsicmp(ext, _T(".ogv")) == 0) { + iconIndex = IDI_OGM_ICON; + } else if (_tcsicmp(ext, _T(".opus")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".pls")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".pva")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".ra")) == 0) { + iconIndex = IDI_RA_ICON; + } else if (_tcsicmp(ext, _T(".ram")) == 0) { + iconIndex = IDI_RM_ICON; + } else if (_tcsicmp(ext, _T(".rm")) == 0) { + iconIndex = IDI_RM_ICON; + } else if (_tcsicmp(ext, _T(".rmi")) == 0) { + iconIndex = IDI_MIDI_ICON; + } else if (_tcsicmp(ext, _T(".rmm")) == 0) { + iconIndex = IDI_RM_ICON; + } else if (_tcsicmp(ext, _T(".rmvb")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".rp")) == 0) { + iconIndex = IDI_RT_ICON; + } else if (_tcsicmp(ext, _T(".rt")) == 0) { + iconIndex = IDI_RT_ICON; + } else if (_tcsicmp(ext, _T(".smil")) == 0) { + iconIndex = IDI_RT_ICON; + } else if (_tcsicmp(ext, _T(".smk")) == 0) { + iconIndex = IDI_SMK_ICON; + } else if (_tcsicmp(ext, _T(".snd")) == 0) { + iconIndex = IDI_AU_ICON; + } else if (_tcsicmp(ext, _T(".swf")) == 0) { + iconIndex = IDI_SWF_ICON; + } else if (_tcsicmp(ext, _T(".tp")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".trp")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".ts")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".rec")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".tak")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".tta")) == 0) { + iconIndex = IDI_TTA_ICON; + } else if (_tcsicmp(ext, _T(".vob")) == 0) { + iconIndex = IDI_VOB_ICON; + } else if (_tcsicmp(ext, _T(".wav")) == 0) { + iconIndex = IDI_WAV_ICON; + } else if (_tcsicmp(ext, _T(".wax")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".webm")) == 0) { + iconIndex = IDI_WEBM_ICON; + } else if (_tcsicmp(ext, _T(".wm")) == 0) { + iconIndex = IDI_WMV_ICON; + } else if (_tcsicmp(ext, _T(".wma")) == 0) { + iconIndex = IDI_WMA_ICON; + } else if (_tcsicmp(ext, _T(".wmp")) == 0) { + iconIndex = IDI_WMV_ICON; + } else if (_tcsicmp(ext, _T(".wmv")) == 0) { + iconIndex = IDI_WMV_ICON; + } else if (_tcsicmp(ext, _T(".wmx")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".wv")) == 0) { + iconIndex = IDI_WV_ICON; + } else if (_tcsicmp(ext, _T(".wvx")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } + + return iconIndex; +} diff --git a/src/mpc-hc/mpciconlib/mpciconlib.h b/src/mpc-hc/mpciconlib/mpciconlib.h index 3fa71694287..dd311863084 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.h +++ b/src/mpc-hc/mpciconlib/mpciconlib.h @@ -1,86 +1,86 @@ -/* - * (C) 2008-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 . - * - */ - -/* The version number of the icon library. Should be incremented when the indexes are changed. */ -#define ICON_LIB_VERSION 3 - -/* The values below correspond to the icon indexes. - * The order should be exactly the same as in the mpciconlib.rc file. - * There should be no gaps in the numbering. So be careful - * when adding/removing icons. - */ - -#define IDI_NONE -1 -#define IDI_OTHER_ICON 0 -#define IDI_AAC_ICON 1 -#define IDI_AC3_ICON 2 -#define IDI_AIFF_ICON 3 -#define IDI_ALAC_ICON 4 -#define IDI_AMR_ICON 5 -#define IDI_APE_ICON 6 -#define IDI_AU_ICON 7 -#define IDI_AVI_ICON 8 -#define IDI_BINK_ICON 9 -#define IDI_CDA_ICON 10 -#define IDI_DSM_ICON 11 -#define IDI_DTS_ICON 12 -#define IDI_FLAC_ICON 13 -#define IDI_FLIC_ICON 14 -#define IDI_FLV_ICON 15 -#define IDI_IFO_ICON 16 -#define IDI_IVF_ICON 17 -#define IDI_MIDI_ICON 18 -#define IDI_MKA_ICON 19 -#define IDI_MKV_ICON 20 -#define IDI_MOV_ICON 21 -#define IDI_MP3_ICON 22 -#define IDI_MP4_ICON 23 -#define IDI_MPA_ICON 24 -#define IDI_MPC_ICON 25 -#define IDI_MPEG_ICON 26 -#define IDI_OFR_ICON 27 -#define IDI_OGG_ICON 28 -#define IDI_OGM_ICON 29 -#define IDI_PLAYLIST_ICON 30 -#define IDI_RA_ICON 31 -#define IDI_RM_ICON 32 -#define IDI_RT_ICON 33 -#define IDI_SMK_ICON 34 -#define IDI_SWF_ICON 35 -#define IDI_TS_ICON 36 -#define IDI_TTA_ICON 37 -#define IDI_VOB_ICON 38 -#define IDI_WAV_ICON 39 -#define IDI_WEBM_ICON 40 -#define IDI_WMA_ICON 41 -#define IDI_WMV_ICON 42 -#define IDI_WV_ICON 43 - - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 44 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +/* + * (C) 2008-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 . + * + */ + +/* The version number of the icon library. Should be incremented when the indexes are changed. */ +#define ICON_LIB_VERSION 3 + +/* The values below correspond to the icon indexes. + * The order should be exactly the same as in the mpciconlib.rc file. + * There should be no gaps in the numbering. So be careful + * when adding/removing icons. + */ + +#define IDI_NONE -1 +#define IDI_OTHER_ICON 0 +#define IDI_AAC_ICON 1 +#define IDI_AC3_ICON 2 +#define IDI_AIFF_ICON 3 +#define IDI_ALAC_ICON 4 +#define IDI_AMR_ICON 5 +#define IDI_APE_ICON 6 +#define IDI_AU_ICON 7 +#define IDI_AVI_ICON 8 +#define IDI_BINK_ICON 9 +#define IDI_CDA_ICON 10 +#define IDI_DSM_ICON 11 +#define IDI_DTS_ICON 12 +#define IDI_FLAC_ICON 13 +#define IDI_FLIC_ICON 14 +#define IDI_FLV_ICON 15 +#define IDI_IFO_ICON 16 +#define IDI_IVF_ICON 17 +#define IDI_MIDI_ICON 18 +#define IDI_MKA_ICON 19 +#define IDI_MKV_ICON 20 +#define IDI_MOV_ICON 21 +#define IDI_MP3_ICON 22 +#define IDI_MP4_ICON 23 +#define IDI_MPA_ICON 24 +#define IDI_MPC_ICON 25 +#define IDI_MPEG_ICON 26 +#define IDI_OFR_ICON 27 +#define IDI_OGG_ICON 28 +#define IDI_OGM_ICON 29 +#define IDI_PLAYLIST_ICON 30 +#define IDI_RA_ICON 31 +#define IDI_RM_ICON 32 +#define IDI_RT_ICON 33 +#define IDI_SMK_ICON 34 +#define IDI_SWF_ICON 35 +#define IDI_TS_ICON 36 +#define IDI_TTA_ICON 37 +#define IDI_VOB_ICON 38 +#define IDI_WAV_ICON 39 +#define IDI_WEBM_ICON 40 +#define IDI_WMA_ICON 41 +#define IDI_WMV_ICON 42 +#define IDI_WV_ICON 43 + + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 44 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/mpc-hc/mpciconlib/mpciconlib.rc b/src/mpc-hc/mpciconlib/mpciconlib.rc index a7202b8a94b..54305aff3a8 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.rc +++ b/src/mpc-hc/mpciconlib/mpciconlib.rc @@ -1,154 +1,154 @@ -// Microsoft Visual C++ generated resource script. -// -#include "mpciconlib.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "mpciconlib.h\0" - "version.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// The icons should have the exact same order as in "mpciconlib.h" ! -IDI_OTHER_ICON ICON "icons\\other.ico" -IDI_AAC_ICON ICON "icons\\aac.ico" -IDI_AC3_ICON ICON "icons\\ac3.ico" -IDI_AIFF_ICON ICON "icons\\aiff.ico" -IDI_ALAC_ICON ICON "icons\\alac.ico" -IDI_AMR_ICON ICON "icons\\amr.ico" -IDI_APE_ICON ICON "icons\\ape.ico" -IDI_AU_ICON ICON "icons\\au.ico" -IDI_AVI_ICON ICON "icons\\avi.ico" -IDI_BINK_ICON ICON "icons\\bink.ico" -IDI_CDA_ICON ICON "icons\\cda.ico" -IDI_DSM_ICON ICON "icons\\dsm.ico" -IDI_DTS_ICON ICON "icons\\dts.ico" -IDI_FLAC_ICON ICON "icons\\flac.ico" -IDI_FLIC_ICON ICON "icons\\flic.ico" -IDI_FLV_ICON ICON "icons\\flv.ico" -IDI_IFO_ICON ICON "icons\\ifo.ico" -IDI_IVF_ICON ICON "icons\\ivf.ico" -IDI_MIDI_ICON ICON "icons\\midi.ico" -IDI_MKA_ICON ICON "icons\\mka.ico" -IDI_MKV_ICON ICON "icons\\mkv.ico" -IDI_MOV_ICON ICON "icons\\mov.ico" -IDI_MP3_ICON ICON "icons\\mp3.ico" -IDI_MP4_ICON ICON "icons\\mp4.ico" -IDI_MPA_ICON ICON "icons\\mpa.ico" -IDI_MPC_ICON ICON "icons\\mpc.ico" -IDI_MPEG_ICON ICON "icons\\mpeg.ico" -IDI_OFR_ICON ICON "icons\\ofr.ico" -IDI_OGG_ICON ICON "icons\\ogg.ico" -IDI_OGM_ICON ICON "icons\\ogm.ico" -IDI_PLAYLIST_ICON ICON "icons\\playlist.ico" -IDI_RA_ICON ICON "icons\\ra.ico" -IDI_RM_ICON ICON "icons\\rm.ico" -IDI_RT_ICON ICON "icons\\rt.ico" -IDI_SMK_ICON ICON "icons\\smk.ico" -IDI_SWF_ICON ICON "icons\\swf.ico" -IDI_TS_ICON ICON "icons\\ts.ico" -IDI_TTA_ICON ICON "icons\\tta.ico" -IDI_VOB_ICON ICON "icons\\vob.ico" -IDI_WAV_ICON ICON "icons\\wav.ico" -IDI_WEBM_ICON ICON "icons\\webm.ico" -IDI_WMA_ICON ICON "icons\\wma.ico" -IDI_WMV_ICON ICON "icons\\wmv.ico" -IDI_WV_ICON ICON "icons\\wv.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "MPC-HC Icon Library" - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "MPC-HC Icon Library" - VALUE "FileVersion", MPC_VERSION_STR - VALUE "InternalName", "mpciconlib" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "mpciconlib.dll" - VALUE "ProductName", "MPC-HC Icon Library" - VALUE "ProductVersion", MPC_VERSION_STR - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "mpciconlib.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "mpciconlib.h\0" + "version.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// The icons should have the exact same order as in "mpciconlib.h" ! +IDI_OTHER_ICON ICON "icons\\other.ico" +IDI_AAC_ICON ICON "icons\\aac.ico" +IDI_AC3_ICON ICON "icons\\ac3.ico" +IDI_AIFF_ICON ICON "icons\\aiff.ico" +IDI_ALAC_ICON ICON "icons\\alac.ico" +IDI_AMR_ICON ICON "icons\\amr.ico" +IDI_APE_ICON ICON "icons\\ape.ico" +IDI_AU_ICON ICON "icons\\au.ico" +IDI_AVI_ICON ICON "icons\\avi.ico" +IDI_BINK_ICON ICON "icons\\bink.ico" +IDI_CDA_ICON ICON "icons\\cda.ico" +IDI_DSM_ICON ICON "icons\\dsm.ico" +IDI_DTS_ICON ICON "icons\\dts.ico" +IDI_FLAC_ICON ICON "icons\\flac.ico" +IDI_FLIC_ICON ICON "icons\\flic.ico" +IDI_FLV_ICON ICON "icons\\flv.ico" +IDI_IFO_ICON ICON "icons\\ifo.ico" +IDI_IVF_ICON ICON "icons\\ivf.ico" +IDI_MIDI_ICON ICON "icons\\midi.ico" +IDI_MKA_ICON ICON "icons\\mka.ico" +IDI_MKV_ICON ICON "icons\\mkv.ico" +IDI_MOV_ICON ICON "icons\\mov.ico" +IDI_MP3_ICON ICON "icons\\mp3.ico" +IDI_MP4_ICON ICON "icons\\mp4.ico" +IDI_MPA_ICON ICON "icons\\mpa.ico" +IDI_MPC_ICON ICON "icons\\mpc.ico" +IDI_MPEG_ICON ICON "icons\\mpeg.ico" +IDI_OFR_ICON ICON "icons\\ofr.ico" +IDI_OGG_ICON ICON "icons\\ogg.ico" +IDI_OGM_ICON ICON "icons\\ogm.ico" +IDI_PLAYLIST_ICON ICON "icons\\playlist.ico" +IDI_RA_ICON ICON "icons\\ra.ico" +IDI_RM_ICON ICON "icons\\rm.ico" +IDI_RT_ICON ICON "icons\\rt.ico" +IDI_SMK_ICON ICON "icons\\smk.ico" +IDI_SWF_ICON ICON "icons\\swf.ico" +IDI_TS_ICON ICON "icons\\ts.ico" +IDI_TTA_ICON ICON "icons\\tta.ico" +IDI_VOB_ICON ICON "icons\\vob.ico" +IDI_WAV_ICON ICON "icons\\wav.ico" +IDI_WEBM_ICON ICON "icons\\webm.ico" +IDI_WMA_ICON ICON "icons\\wma.ico" +IDI_WMV_ICON ICON "icons\\wmv.ico" +IDI_WV_ICON ICON "icons\\wv.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "MPC-HC Icon Library" + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "MPC-HC Icon Library" + VALUE "FileVersion", MPC_VERSION_STR + VALUE "InternalName", "mpciconlib" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "mpciconlib.dll" + VALUE "ProductName", "MPC-HC Icon Library" + VALUE "ProductVersion", MPC_VERSION_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/mpc-hc/mpciconlib/mpciconlib.vcxproj b/src/mpc-hc/mpciconlib/mpciconlib.vcxproj index 8008b02eaa8..f719902895f 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.vcxproj +++ b/src/mpc-hc/mpciconlib/mpciconlib.vcxproj @@ -1,114 +1,114 @@ - - - - - Release - Win32 - - - Release - x64 - - - - {86251DC4-9298-424C-AE6C-07844F79C0B5} - mpciconlib - Win32Proj - mpciconlib - - - - - DynamicLibrary - Unicode - - - - - - - - - - - $(SolutionDir)bin\mpc-hc_x86\ - $(SolutionDir)bin\mpc-hc_x64\ - - - $(SolutionDir)bin15\mpc-hc_x86\ - $(SolutionDir)bin15\mpc-hc_x64\ - - - - NotUsing - - - true - $(IntDir)$(TargetName).pdb - libucrt.lib;%(AdditionalDependencies) - - - ..\..\..\include - NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Release + Win32 + + + Release + x64 + + + + {86251DC4-9298-424C-AE6C-07844F79C0B5} + mpciconlib + Win32Proj + mpciconlib + + + + + DynamicLibrary + Unicode + + + + + + + + + + + $(SolutionDir)bin\mpc-hc_x86\ + $(SolutionDir)bin\mpc-hc_x64\ + + + $(SolutionDir)bin15\mpc-hc_x86\ + $(SolutionDir)bin15\mpc-hc_x64\ + + + + NotUsing + + + true + $(IntDir)$(TargetName).pdb + libucrt.lib;%(AdditionalDependencies) + + + ..\..\..\include + NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/mpc-hc/mpciconlib/mpciconlib.vcxproj.filters b/src/mpc-hc/mpciconlib/mpciconlib.vcxproj.filters index c00c5c34b70..cdd171fb8e6 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.vcxproj.filters +++ b/src/mpc-hc/mpciconlib/mpciconlib.vcxproj.filters @@ -1,172 +1,172 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - {a30fae36-ef1d-4888-83c4-6ef86520877d} - - - - - Source Files - - - - - Header Files - - - Header Files - - - - - Resource Files - - - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {a30fae36-ef1d-4888-83c4-6ef86520877d} + + + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + \ No newline at end of file diff --git a/src/mpc-hc/mpcresources/mpcresources.vcxproj b/src/mpc-hc/mpcresources/mpcresources.vcxproj index 2ee18f37681..afea46cf0df 100644 --- a/src/mpc-hc/mpcresources/mpcresources.vcxproj +++ b/src/mpc-hc/mpcresources/mpcresources.vcxproj @@ -1,596 +1,596 @@ - - - - - Release Arabic - Win32 - - - Release Arabic - x64 - - - Release Armenian - Win32 - - - Release Armenian - x64 - - - Release Basque - Win32 - - - Release Basque - x64 - - - Release Belarusian - Win32 - - - Release Belarusian - x64 - - - Release Bengali - Win32 - - - Release Bengali - x64 - - - Release Bosnian - Win32 - - - Release Bosnian - x64 - - - Release Bulgarian - Win32 - - - Release Bulgarian - x64 - - - Release Catalan - Win32 - - - Release Catalan - x64 - - - Release Chinese Simplified - Win32 - - - Release Chinese Simplified - x64 - - - Release Chinese Traditional - Win32 - - - Release Chinese Traditional - x64 - - - Release Croatian - Win32 - - - Release Croatian - x64 - - - Release Czech - Win32 - - - Release Czech - x64 - - - Release Danish - Win32 - - - Release Danish - x64 - - - Release Dutch - Win32 - - - Release Dutch - x64 - - - Release English (British) - Win32 - - - Release English (British) - x64 - - - Release Finnish - Win32 - - - Release Finnish - x64 - - - Release French - Win32 - - - Release French - x64 - - - Release Galician - Win32 - - - Release Galician - x64 - - - Release German - Win32 - - - Release German - x64 - - - Release Greek - Win32 - - - Release Greek - x64 - - - Release Hebrew - Win32 - - - Release Hebrew - x64 - - - Release Hungarian - Win32 - - - Release Hungarian - x64 - - - Release Indonesian - Win32 - - - Release Indonesian - x64 - - - Release Italian - Win32 - - - Release Italian - x64 - - - Release Japanese - Win32 - - - Release Japanese - x64 - - - Release Korean - Win32 - - - Release Korean - x64 - - - Release Lithuanian - Win32 - - - Release Lithuanian - x64 - - - Release Malay - Win32 - - - Release Malay - x64 - - - Release Polish - Win32 - - - Release Polish - x64 - - - Release Portuguese (Brazil) - Win32 - - - Release Portuguese (Brazil) - x64 - - - Release Portuguese (Portugal) - Win32 - - - Release Portuguese (Portugal) - x64 - - - Release Punjabi - Win32 - - - Release Punjabi - x64 - - - Release Romanian - Win32 - - - Release Romanian - x64 - - - Release Russian - Win32 - - - Release Russian - x64 - - - Release Serbian - Win32 - - - Release Serbian - x64 - - - Release Slovak - Win32 - - - Release Slovak - x64 - - - Release Slovenian - Win32 - - - Release Slovenian - x64 - - - Release Spanish - Win32 - - - Release Spanish - x64 - - - Release Swedish - Win32 - - - Release Swedish - x64 - - - Release Tatar - Win32 - - - Release Tatar - x64 - - - Release Thai - Win32 - - - Release Thai - x64 - - - Release Turkish - Win32 - - - Release Turkish - x64 - - - Release Ukrainian - Win32 - - - Release Ukrainian - x64 - - - Release Vietnamese - Win32 - - - Release Vietnamese - x64 - - - - {A57CBE1A-3703-4237-950A-FC5F594FDB43} - mpcresources - Win32Proj - mpcresources - - - - - DynamicLibrary - Unicode - - - - - - - - - - - $(SolutionDir)bin\mpc-hc_x86\Lang\ - $(SolutionDir)bin\mpc-hc_x64\Lang\ - $(SolutionDir)bin\obj\Release_$(Platform)\$(ProjectName)\$(Configuration)\ - $(ProjectName).ar - $(ProjectName).hy - $(ProjectName).eu - $(ProjectName).be - $(ProjectName).bn - $(ProjectName).bs_BA - $(ProjectName).bg - $(ProjectName).ca - $(ProjectName).zh_CN - $(ProjectName).zh_TW - $(ProjectName).hr - $(ProjectName).cs - $(ProjectName).da - $(ProjectName).nl - $(ProjectName).en_GB - $(ProjectName).fi - $(ProjectName).fr - $(ProjectName).gl - $(ProjectName).de - $(ProjectName).el - $(ProjectName).he - $(ProjectName).hu - $(ProjectName).id - $(ProjectName).it - $(ProjectName).ja - $(ProjectName).ko - $(ProjectName).lt - $(ProjectName).ms_MY - $(ProjectName).pl - $(ProjectName).pt_BR - $(ProjectName).pt_PT - $(ProjectName).pa - $(ProjectName).ro - $(ProjectName).ru - $(ProjectName).sr - $(ProjectName).sk - $(ProjectName).sl - $(ProjectName).es - $(ProjectName).sv - $(ProjectName).tt - $(ProjectName).th_TH - $(ProjectName).tr - $(ProjectName).uk - $(ProjectName).vi - - - $(SolutionDir)bin15\mpc-hc_x86\Lang\ - $(SolutionDir)bin15\mpc-hc_x64\Lang\ - $(SolutionDir)bin15\obj\Release_$(Platform)\$(ProjectName)\$(Configuration)\ - - - - false - - - Default - false - true - true - - - ..\..\..\include;..;%(AdditionalIncludeDirectories) - NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) - - - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - - - - - - - {904017f7-ee7a-49b6-a000-0d2fe5d5809a} - false - - - - - - + + + + + Release Arabic + Win32 + + + Release Arabic + x64 + + + Release Armenian + Win32 + + + Release Armenian + x64 + + + Release Basque + Win32 + + + Release Basque + x64 + + + Release Belarusian + Win32 + + + Release Belarusian + x64 + + + Release Bengali + Win32 + + + Release Bengali + x64 + + + Release Bosnian + Win32 + + + Release Bosnian + x64 + + + Release Bulgarian + Win32 + + + Release Bulgarian + x64 + + + Release Catalan + Win32 + + + Release Catalan + x64 + + + Release Chinese Simplified + Win32 + + + Release Chinese Simplified + x64 + + + Release Chinese Traditional + Win32 + + + Release Chinese Traditional + x64 + + + Release Croatian + Win32 + + + Release Croatian + x64 + + + Release Czech + Win32 + + + Release Czech + x64 + + + Release Danish + Win32 + + + Release Danish + x64 + + + Release Dutch + Win32 + + + Release Dutch + x64 + + + Release English (British) + Win32 + + + Release English (British) + x64 + + + Release Finnish + Win32 + + + Release Finnish + x64 + + + Release French + Win32 + + + Release French + x64 + + + Release Galician + Win32 + + + Release Galician + x64 + + + Release German + Win32 + + + Release German + x64 + + + Release Greek + Win32 + + + Release Greek + x64 + + + Release Hebrew + Win32 + + + Release Hebrew + x64 + + + Release Hungarian + Win32 + + + Release Hungarian + x64 + + + Release Indonesian + Win32 + + + Release Indonesian + x64 + + + Release Italian + Win32 + + + Release Italian + x64 + + + Release Japanese + Win32 + + + Release Japanese + x64 + + + Release Korean + Win32 + + + Release Korean + x64 + + + Release Lithuanian + Win32 + + + Release Lithuanian + x64 + + + Release Malay + Win32 + + + Release Malay + x64 + + + Release Polish + Win32 + + + Release Polish + x64 + + + Release Portuguese (Brazil) + Win32 + + + Release Portuguese (Brazil) + x64 + + + Release Portuguese (Portugal) + Win32 + + + Release Portuguese (Portugal) + x64 + + + Release Punjabi + Win32 + + + Release Punjabi + x64 + + + Release Romanian + Win32 + + + Release Romanian + x64 + + + Release Russian + Win32 + + + Release Russian + x64 + + + Release Serbian + Win32 + + + Release Serbian + x64 + + + Release Slovak + Win32 + + + Release Slovak + x64 + + + Release Slovenian + Win32 + + + Release Slovenian + x64 + + + Release Spanish + Win32 + + + Release Spanish + x64 + + + Release Swedish + Win32 + + + Release Swedish + x64 + + + Release Tatar + Win32 + + + Release Tatar + x64 + + + Release Thai + Win32 + + + Release Thai + x64 + + + Release Turkish + Win32 + + + Release Turkish + x64 + + + Release Ukrainian + Win32 + + + Release Ukrainian + x64 + + + Release Vietnamese + Win32 + + + Release Vietnamese + x64 + + + + {A57CBE1A-3703-4237-950A-FC5F594FDB43} + mpcresources + Win32Proj + mpcresources + + + + + DynamicLibrary + Unicode + + + + + + + + + + + $(SolutionDir)bin\mpc-hc_x86\Lang\ + $(SolutionDir)bin\mpc-hc_x64\Lang\ + $(SolutionDir)bin\obj\Release_$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName).ar + $(ProjectName).hy + $(ProjectName).eu + $(ProjectName).be + $(ProjectName).bn + $(ProjectName).bs_BA + $(ProjectName).bg + $(ProjectName).ca + $(ProjectName).zh_CN + $(ProjectName).zh_TW + $(ProjectName).hr + $(ProjectName).cs + $(ProjectName).da + $(ProjectName).nl + $(ProjectName).en_GB + $(ProjectName).fi + $(ProjectName).fr + $(ProjectName).gl + $(ProjectName).de + $(ProjectName).el + $(ProjectName).he + $(ProjectName).hu + $(ProjectName).id + $(ProjectName).it + $(ProjectName).ja + $(ProjectName).ko + $(ProjectName).lt + $(ProjectName).ms_MY + $(ProjectName).pl + $(ProjectName).pt_BR + $(ProjectName).pt_PT + $(ProjectName).pa + $(ProjectName).ro + $(ProjectName).ru + $(ProjectName).sr + $(ProjectName).sk + $(ProjectName).sl + $(ProjectName).es + $(ProjectName).sv + $(ProjectName).tt + $(ProjectName).th_TH + $(ProjectName).tr + $(ProjectName).uk + $(ProjectName).vi + + + $(SolutionDir)bin15\mpc-hc_x86\Lang\ + $(SolutionDir)bin15\mpc-hc_x64\Lang\ + $(SolutionDir)bin15\obj\Release_$(Platform)\$(ProjectName)\$(Configuration)\ + + + + false + + + Default + false + true + true + + + ..\..\..\include;..;%(AdditionalIncludeDirectories) + NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + + + {904017f7-ee7a-49b6-a000-0d2fe5d5809a} + false + + + + + + diff --git a/src/mpc-hc/mpcresources/mpcresources.vcxproj.filters b/src/mpc-hc/mpcresources/mpcresources.vcxproj.filters index ab875c6db94..1ce5258f723 100644 --- a/src/mpc-hc/mpcresources/mpcresources.vcxproj.filters +++ b/src/mpc-hc/mpcresources/mpcresources.vcxproj.filters @@ -1,160 +1,160 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - - - Header Files - - - Header Files - - - - - Resource Files - - - + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + diff --git a/src/mpc-hc/mplayerc.cpp b/src/mpc-hc/mplayerc.cpp index 88de0955d8d..0a7b0cbd2f0 100644 --- a/src/mpc-hc/mplayerc.cpp +++ b/src/mpc-hc/mplayerc.cpp @@ -1,2825 +1,2825 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "AboutDlg.h" -#include "CmdLineHelpDlg.h" -#include "CrashReporter.h" -#include "DSUtil.h" -#include "FakeFilterMapper2.h" -#include "FileAssoc.h" -#include "FileVersionInfo.h" -#include "Ifo.h" -#include "MainFrm.h" -#include "MhookHelper.h" -#include "PPageFormats.h" -#include "PPageSheet.h" -#include "PathUtils.h" -#include "Struct.h" -#include "UpdateChecker.h" -#include "WebServer.h" -#include "WinAPIUtils.h" -#include "mpc-hc_config.h" -#include "winddk/ntddcdvd.h" -#include -#include -#include -#include -#include "ExceptionHandler.h" -#include "FGFilterLAV.h" -#include "CMPCThemeMsgBox.h" -#include "version.h" -#include "psapi.h" - -HICON LoadIcon(CString fn, bool bSmallIcon, DpiHelper* pDpiHelper/* = nullptr*/) -{ - if (fn.IsEmpty()) { - return nullptr; - } - - CString ext = fn.Left(fn.Find(_T("://")) + 1).TrimRight(':'); - if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) { - ext = _T(".") + fn.Mid(fn.ReverseFind('.') + 1); - } - - CSize size(bSmallIcon ? GetSystemMetrics(SM_CXSMICON) : GetSystemMetrics(SM_CXICON), - bSmallIcon ? GetSystemMetrics(SM_CYSMICON) : GetSystemMetrics(SM_CYICON)); - - if (pDpiHelper) { - size.cx = pDpiHelper->ScaleSystemToOverrideX(size.cx); - size.cy = pDpiHelper->ScaleSystemToOverrideY(size.cy); - } - - typedef HRESULT(WINAPI * LIWSD)(HINSTANCE, PCWSTR, int, int, HICON*); - auto loadIcon = [&size](PCWSTR pszName) { - LIWSD pLIWSD = (LIWSD)GetProcAddress(GetModuleHandle(_T("comctl32.dll")), "LoadIconWithScaleDown"); - HICON ret = nullptr; - if (pLIWSD) { - pLIWSD(AfxGetInstanceHandle(), pszName, size.cx, size.cy, &ret); - } else { - ret = (HICON)LoadImage(AfxGetInstanceHandle(), pszName, IMAGE_ICON, size.cx, size.cy, 0); - } - return ret; - }; - - if (!ext.CompareNoCase(_T(".ifo"))) { - if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_DVD))) { - return hIcon; - } - } - - if (!ext.CompareNoCase(_T(".cda"))) { - if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_AUDIOCD))) { - return hIcon; - } - } - - if (!ext.CompareNoCase(_T(".unknown"))) { - if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_UNKNOWN))) { - return hIcon; - } - } - - do { - CRegKey key; - TCHAR buff[256]; - ULONG len; - - auto openRegKey = [&](HKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValueName) { - if (ERROR_SUCCESS == key.Open(hKeyParent, lpszKeyName, KEY_READ)) { - len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - CString progId; - - if (ERROR_SUCCESS == key.QueryStringValue(lpszValueName, buff, &len) && !(progId = buff).Trim().IsEmpty()) { - return (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, progId + _T("\\DefaultIcon"), KEY_READ)); - } - } - return false; - }; - - if (!openRegKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\") + ext + _T("\\UserChoice"), _T("Progid")) - && !openRegKey(HKEY_CLASSES_ROOT, ext, nullptr) - && ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, ext + _T("\\DefaultIcon"), KEY_READ)) { - break; - } - - CString icon; - len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len) || (icon = buff).Trim().IsEmpty()) { - break; - } - - int i = icon.ReverseFind(','); - if (i < 0) { - break; - } - - int id = 0; - if (_stscanf_s(icon.Mid(i + 1), _T("%d"), &id) != 1) { - break; - } - - icon = icon.Left(i); - icon.Trim(_T(" \\\"")); - - HICON hIcon = nullptr; - UINT cnt = bSmallIcon - ? ExtractIconEx(icon, id, nullptr, &hIcon, 1) - : ExtractIconEx(icon, id, &hIcon, nullptr, 1); - if (hIcon && cnt == 1) { - return hIcon; - } - } while (0); - - return loadIcon(MAKEINTRESOURCE(IDI_UNKNOWN)); -} - -bool LoadType(CString fn, CString& type) -{ - bool found = false; - - if (!fn.IsEmpty()) { - CString ext = fn.Left(fn.Find(_T("://")) + 1).TrimRight(':'); - if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) { - ext = _T(".") + fn.Mid(fn.ReverseFind('.') + 1); - } - - // Try MPC-HC's internal formats list - const CMediaFormatCategory* mfc = AfxGetAppSettings().m_Formats.FindMediaByExt(ext); - - if (mfc != nullptr) { - found = true; - type = mfc->GetDescription(); - } else { // Fallback to registry - CRegKey key; - TCHAR buff[256]; - ULONG len; - - CString tmp = _T(""); - CString mplayerc_ext = _T("mplayerc") + ext; - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, mplayerc_ext)) { - tmp = mplayerc_ext; - } - - if (!tmp.IsEmpty() || ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, ext)) { - found = true; - - if (tmp.IsEmpty()) { - tmp = ext; - } - - while (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, tmp)) { - len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - - if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len)) { - break; - } - - CString str(buff); - str.Trim(); - - if (str.IsEmpty() || str == tmp) { - break; - } - - tmp = str; - } - - type = tmp; - } - } - } - - return found; -} - -bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype) -{ - str.Empty(); - HRSRC hrsrc = FindResource(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(resid), restype); - if (!hrsrc) { - return false; - } - HGLOBAL hGlobal = LoadResource(AfxGetApp()->m_hInstance, hrsrc); - if (!hGlobal) { - return false; - } - DWORD size = SizeofResource(AfxGetApp()->m_hInstance, hrsrc); - if (!size) { - return false; - } - memcpy(str.GetBufferSetLength(size), LockResource(hGlobal), size); - return true; -} - -static bool FindRedir(const CUrl& src,const CString& body, CAtlList& urls, const std::vector& res) -{ - bool bDetectHLS = false; - for (const auto re : res) { - std::wcmatch mc; - - for (LPCTSTR s = body; std::regex_search(s, mc, re); s += mc.position() + mc.length()) { - CString url = mc[mc.size() - 1].str().c_str(); - url.Trim(); - - if (url.CompareNoCase(_T("asf path")) == 0) { - continue; - } - if (url.Find(_T("EXTM3U")) == 0 || url.Find(_T("#EXTINF")) == 0) { - bDetectHLS = true; - continue; - } - // Detect HTTP Live Streaming and let the source filter handle that - if (bDetectHLS - && (url.Find(_T("EXT-X-STREAM-INF:")) != -1 - || url.Find(_T("EXT-X-TARGETDURATION:")) != -1 - || url.Find(_T("EXT-X-MEDIA-SEQUENCE:")) != -1)) { - urls.RemoveAll(); - break; - } - - CUrl dst; - dst.CrackUrl(CString(url)); - if (_tcsicmp(src.GetSchemeName(), dst.GetSchemeName()) - || _tcsicmp(src.GetHostName(), dst.GetHostName()) - || _tcsicmp(src.GetUrlPath(), dst.GetUrlPath())) { - urls.AddTail(url); - } else { - // recursive - urls.RemoveAll(); - break; - } - } - } - - return !urls.IsEmpty(); -} - -static bool FindRedir(const CString& fn, CAtlList& fns, const std::vector& res) -{ - CString body; - - CTextFile f(CTextFile::UTF8); - if (f.Open(fn)) { - int i = 0; - for (CString tmp; i < 10000 && f.ReadString(tmp); body += tmp + '\n', ++i) { - ; - } - } - - CString dir = fn.Left(std::max(fn.ReverseFind('/'), fn.ReverseFind('\\')) + 1); // "ReverseFindOneOf" - - for (const auto re : res) { - std::wcmatch mc; - - for (LPCTSTR s = body; std::regex_search(s, mc, re); s += mc.position() + mc.length()) { - CString fn2 = mc[mc.size() - 1].str().c_str(); - fn2.Trim(); - - if (!fn2.CompareNoCase(_T("asf path"))) { - continue; - } - if (fn2.Find(_T("EXTM3U")) == 0 || fn2.Find(_T("#EXTINF")) == 0) { - continue; - } - - if (fn2.Find(_T(":")) < 0 && fn2.Find(_T("\\\\")) != 0 && fn2.Find(_T("//")) != 0) { - CPath p; - p.Combine(dir, fn2); - fn2 = (LPCTSTR)p; - } - - if (!fn2.CompareNoCase(fn)) { - continue; - } - - fns.AddTail(fn2); - } - } - - return !fns.IsEmpty(); -} - - -CString GetContentType(CString fn, CAtlList* redir) -{ - fn.Trim(); - if (fn.IsEmpty()) { - return ""; - } - - CUrl url; - CString content, body; - BOOL url_fail = false; - BOOL ishttp = false; - BOOL parsefile = false; - BOOL isurl = PathUtils::IsURL(fn); - - // Get content type based on the URI scheme - if (isurl) { - url.CrackUrl(fn); - - if (_tcsicmp(url.GetSchemeName(), _T("pnm")) == 0) { - return "audio/x-pn-realaudio"; - } - if (_tcsicmp(url.GetSchemeName(), _T("mms")) == 0) { - return "video/x-ms-asf"; - } - if (_tcsicmp(url.GetSchemeName(), _T("http")) == 0 || _tcsicmp(url.GetSchemeName(), _T("https")) == 0) { - ishttp = true; - } else { - return ""; - } - } - - CString ext = CPath(fn).GetExtension().MakeLower(); - int p = ext.FindOneOf(_T("?#")); - if (p > 0) { - ext = ext.Left(p); - } - - // no further analysis needed if known audio/video extension and points directly to a file - if (!ext.IsEmpty()) { - if (ext == _T(".mp4") || ext == _T(".m4v") || ext == _T(".mov") || ext == _T(".mkv") || ext == _T(".webm") || ext == _T(".avi") || ext == _T(".wmv") || ext == _T(".mpg") || ext == _T(".mpeg") || ext == _T(".flv") || ext == _T(".ogm") || ext == _T(".m2ts") || ext == _T(".ts")) { - content = _T("video"); - } else if (ext == _T(".mp3") || ext == _T(".m4a") || ext == _T(".aac") || ext == _T(".flac") || ext == _T(".mka") || ext == _T(".ogg") || ext == _T(".opus")) { - content = _T("audio"); - } else if (ext == _T(".mpcpl")) { - content = _T("application/x-mpc-playlist"); - } else if (ext == _T(".m3u") || ext == _T(".m3u8")) { - content = _T("audio/x-mpegurl"); - } else if (ext == _T(".bdmv")) { - content = _T("application/x-bdmv-playlist"); - } else if (ext == _T(".cue")) { - content = _T("application/x-cue-sheet"); - } else if (ext == _T(".swf")) { - content = _T("application/x-shockwave-flash"); - } - - if (!content.IsEmpty()) { - return content; - } - } - - // Get content type by getting the header response from server - if (ishttp) { - CInternetSession internet; - internet.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 5000); - CString headers = _T("User-Agent: MPC-HC"); - CHttpFile* httpFile = NULL; - try { - httpFile = (CHttpFile*)internet.OpenURL(fn, - 1, - INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, - headers, - DWORD(-1)); - } - catch (CInternetException* pEx) - { - pEx->Delete(); - url_fail = true; // Timeout has most likely occured, server unreachable - return content; - } - - if (httpFile) { - //CString strContentType; - //httpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS, strContentType); // Check also HTTP_QUERY_RAW_HEADERS_CRLF - //DWORD dw = 8192; // Arbitrary 8192 char length for Url (should handle most cases) - //CString urlredirect; // Retrieve the new Url in case we encountered an HTTP redirection (HTTP 302 code) - //httpFile->QueryOption(INTERNET_OPTION_URL, urlredirect.GetBuffer(8192), &dw); - DWORD dwStatus; - httpFile->QueryInfoStatusCode(dwStatus); - switch (dwStatus) { - case HTTP_STATUS_OK: // 200 request completed - case HTTP_STATUS_CREATED: // 201 object created, reason = new URI - case HTTP_STATUS_ACCEPTED: // 202 async completion (TBS) - case HTTP_STATUS_PARTIAL: // 203 partial completion - case HTTP_STATUS_NO_CONTENT: // 204 no info to return - case HTTP_STATUS_RESET_CONTENT: // 205 request completed, but clear form - case HTTP_STATUS_PARTIAL_CONTENT: // 206 partial GET furfilled - case HTTP_STATUS_AMBIGUOUS: // 300 server couldn't decide what to return - case HTTP_STATUS_MOVED: // 301 object permanently moved - case HTTP_STATUS_REDIRECT: // 302 object temporarily moved - case HTTP_STATUS_REDIRECT_METHOD: // 303 redirection w/ new access method - case HTTP_STATUS_NOT_MODIFIED: // 304 if-modified-since was not modified - case HTTP_STATUS_USE_PROXY: // 305 redirection to proxy, location header specifies proxy to use - case HTTP_STATUS_REDIRECT_KEEP_VERB: // 307 HTTP/1.1: keep same verb - case 308/*HTTP_STATUS_PERMANENT_REDIRECT*/: // 308 Object permanently moved keep verb - break; - default: - //CString strStatus; - //httpFile->QueryInfo(HTTP_QUERY_STATUS_TEXT, strStatus); // Status String - eg OK, Not Found - url_fail = true; - } - - if (url_fail) { - httpFile->Close(); // Close() isn't called by the destructor - delete httpFile; - return content; - } - - if (content.IsEmpty()) { - httpFile->QueryInfo(HTTP_QUERY_CONTENT_TYPE, content); // Content-Type - eg text/html - } - - long contentsize = 0; - CString contentlength = _T(""); - if (httpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, contentlength)) { - contentsize = _ttol(contentlength); - } - - // Partial download of response body to further identify content types - if (content.IsEmpty() && contentsize < 256*1024) { - UINT br = 0; - char buffer[513] = ""; - while (body.GetLength() < 256) { - br = httpFile->Read(buffer, 256); - if (br == 0) { - break; - } - buffer[br] = '\0'; - body += buffer; - } - if (body.GetLength() >= 8) { - BOOL exit = false; - if (!wcsncmp((LPCWSTR)body, _T(".ra"), 3)) { - content = _T("audio/x-pn-realaudio"); - exit = true; - } else if (!wcsncmp((LPCWSTR)body, _T(".RMF"), 4)) { - content = _T("audio/x-pn-realaudio"); - exit = true; - } - - if (exit) { - httpFile->Close(); - delete httpFile; - return content; - } - } - } - // Download larger piece of response body in case it's a playlist - if (redir && contentsize < 256*1024 && (content == _T("audio/x-scpls") || content == _T("audio/scpls") - || content == _T("video/x-ms-asf") || content == _T("text/plain") - || content == _T("application/octet-stream") || content == _T("application/pls+xml"))) { - UINT br = 0; - char buffer[513] = ""; - while (body.GetLength() < 64 * 1024) { // should be enough for a playlist... - br = httpFile->Read(buffer, 256); - if (br == 0) { - break; - } - buffer[br] = '\0'; - body += buffer; - } - } - - httpFile->Close(); - delete httpFile; - } - } - - // If content type is empty, plain text or octet-stream (weird server!) GUESS by extension if it exists..... - if (content.IsEmpty() || content == _T("text/plain") || content == _T("application/octet-stream")) { - if (ext == _T(".pls")) { - content = _T("audio/x-scpls"); - parsefile = true; - } else if (ext == _T(".asx")) { - content = _T("video/x-ms-asf"); - parsefile = true; - } else if (ext == _T(".ram")) { - content = _T("audio/x-pn-realaudio"); - parsefile = true; - } - } - - if (redir && !content.IsEmpty() && (isurl && !body.IsEmpty() || !isurl && parsefile)) { - std::vector res; - const std::wregex::flag_type reFlags = std::wregex::icase | std::wregex::optimize; - - if (content == _T("video/x-ms-asf")) { - // ...://..."/> - res.emplace_back(_T("[a-zA-Z]+://[^\n\">]*"), reFlags); - // Ref#n= ...://...\n - res.emplace_back(_T("Ref\\d+\\s*=\\s*[\"]*([a-zA-Z]+://[^\n\"]+)"), reFlags); - } - else if (content == _T("audio/x-scpls") || content == _T("audio/scpls") || content == _T("application/pls+xml")) { - // File1=...\n - res.emplace_back(_T("file\\d+\\s*=\\s*[\"]*([^\n\"]+)"), reFlags); - } - else if (content == _T("audio/x-pn-realaudio")) { - // rtsp://... - res.emplace_back(_T("rtsp://[^\n]+"), reFlags); - // http://... - res.emplace_back(_T("http://[^\n]+"), reFlags); - } - - if (res.size()) { - if (isurl) { - FindRedir(url, body, *redir, res); - } else { - FindRedir(fn, *redir, res); - } - } - } - - return content; -} - -WORD AssignedToCmd(UINT keyValue) -{ - if (keyValue == 0) { - ASSERT(false); - return 0; - } - - WORD assignTo = 0; - const CAppSettings& s = AfxGetAppSettings(); - - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos && !assignTo) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - - if (wc.key == keyValue) { - assignTo = wc.cmd; - } - } - - return assignTo; -} - -std::map GetAudioDeviceList() { - std::map devicelist; - BeginEnumSysDev(CLSID_AudioRendererCategory, pMoniker) { - CComHeapPtr olestr; - if (FAILED(pMoniker->GetDisplayName(0, 0, &olestr))) { - continue; - } - CStringW dispname(olestr); - CStringW friendlyname; - CComPtr pPB; - if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)))) { - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - CStringW frname(var.bstrVal); - var.Clear(); - friendlyname = frname; - } - } else { - friendlyname = dispname; - } - devicelist.emplace(friendlyname, dispname); - } - EndEnumSysDev; - - return devicelist; -} - -void SetAudioRenderer(int AudioDevNo) -{ - CStringArray dispnames; - AfxGetMyApp()->m_AudioRendererDisplayName_CL = _T(""); - dispnames.Add(_T("")); - dispnames.Add(AUDRNDT_INTERNAL); - dispnames.Add(AUDRNDT_MPC); - int devcount = 3; - - std::map devicelist = GetAudioDeviceList(); - - for (auto it = devicelist.cbegin(); it != devicelist.cend(); it++) { - dispnames.Add((*it).second); - devcount++; - } - - dispnames.Add(AUDRNDT_NULL_COMP); - dispnames.Add(AUDRNDT_NULL_UNCOMP); - devcount += 2; - - if (AudioDevNo >= 1 && AudioDevNo <= devcount) { - AfxGetMyApp()->m_AudioRendererDisplayName_CL = dispnames[AudioDevNo - 1]; - } -} - -void SetHandCursor(HWND m_hWnd, UINT nID) -{ - SetClassLongPtr(GetDlgItem(m_hWnd, nID), GCLP_HCURSOR, (LONG_PTR)AfxGetApp()->LoadStandardCursor(IDC_HAND)); -} - -// CMPlayerCApp - -CMPlayerCApp::CMPlayerCApp() - : m_hNTDLL(nullptr) - , m_bDelayingIdle(false) - , m_bProfileInitialized(false) - , m_bQueuedProfileFlush(false) - , m_dwProfileLastAccessTick(0) - , m_fClosingState(false) - , m_bThemeLoaded(false) -{ - m_strVersion = FileVersionInfo::GetFileVersionStr(PathUtils::GetProgramPath(true)); - - ZeroMemory(&m_ColorControl, sizeof(m_ColorControl)); - ResetColorControlRange(); - - ZeroMemory(&m_VMR9ColorControl, sizeof(m_VMR9ColorControl)); - m_VMR9ColorControl[0].dwSize = sizeof(VMR9ProcAmpControlRange); - m_VMR9ColorControl[0].dwProperty = ProcAmpControl9_Brightness; - m_VMR9ColorControl[1].dwSize = sizeof(VMR9ProcAmpControlRange); - m_VMR9ColorControl[1].dwProperty = ProcAmpControl9_Contrast; - m_VMR9ColorControl[2].dwSize = sizeof(VMR9ProcAmpControlRange); - m_VMR9ColorControl[2].dwProperty = ProcAmpControl9_Hue; - m_VMR9ColorControl[3].dwSize = sizeof(VMR9ProcAmpControlRange); - m_VMR9ColorControl[3].dwProperty = ProcAmpControl9_Saturation; - - ZeroMemory(&m_EVRColorControl, sizeof(m_EVRColorControl)); - - GetRemoteControlCode = GetRemoteControlCodeMicrosoft; -} - -CMPlayerCApp::~CMPlayerCApp() -{ - if (m_hNTDLL) { - FreeLibrary(m_hNTDLL); - } - // Wait for any pending I/O operations to be canceled - while (WAIT_IO_COMPLETION == SleepEx(0, TRUE)); -} - -int CMPlayerCApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, - UINT nIDPrompt) -{ - if (AppIsThemeLoaded()) { - CWnd* pParentWnd = CWnd::GetActiveWindow(); - if (pParentWnd == NULL) { - pParentWnd = GetMainWnd(); - if (pParentWnd == NULL) { - return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt); - } else { - pParentWnd = pParentWnd->GetLastActivePopup(); - } - } - - CMPCThemeMsgBox dlgMessage(pParentWnd, lpszPrompt, _T(""), nType, - nIDPrompt); - - return (int)dlgMessage.DoModal(); - } else { - return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt); - } -} - -void CMPlayerCApp::DelayedIdle() -{ - m_bDelayingIdle = false; -} - -BOOL CMPlayerCApp::IsIdleMessage(MSG* pMsg) -{ - BOOL ret = __super::IsIdleMessage(pMsg); - if (ret && pMsg->message == WM_MOUSEMOVE) { - if (m_bDelayingIdle) { - ret = FALSE; - } else { - auto pMainFrm = AfxGetMainFrame(); - if (pMainFrm && m_pMainWnd) { - const unsigned uTimeout = 100; - // delay next WM_MOUSEMOVE initiated idle for uTimeout ms - // if there will be no WM_MOUSEMOVE messages, WM_TIMER will initiate the idle - pMainFrm->m_timerOneTime.Subscribe( - CMainFrame::TimerOneTimeSubscriber::DELAY_IDLE, std::bind(&CMPlayerCApp::DelayedIdle, this), uTimeout); - m_bDelayingIdle = true; - } - } - } - return ret; -} - -BOOL CMPlayerCApp::OnIdle(LONG lCount) -{ - BOOL ret = __super::OnIdle(lCount); - - if (!ret) { - FlushProfile(false); - } - - return ret; -} - -BOOL CMPlayerCApp::PumpMessage() -{ - return MsgWaitForMultipleObjectsEx(0, nullptr, INFINITE, QS_ALLINPUT, - MWMO_INPUTAVAILABLE | MWMO_ALERTABLE) == WAIT_IO_COMPLETION ? TRUE : __super::PumpMessage(); -} - -void CMPlayerCApp::ShowCmdlnSwitches() const -{ - CString cmdLine; - - if ((m_s->nCLSwitches & CLSW_UNRECOGNIZEDSWITCH) && __argc > 0) { - cmdLine = __targv[0]; - for (int i = 1; i < __argc; i++) { - cmdLine.AppendFormat(_T(" %s"), __targv[i]); - } - } - - CmdLineHelpDlg dlg(cmdLine); - dlg.DoModal(); -} - -CMPlayerCApp theApp; // The one and only CMPlayerCApp object - -HWND g_hWnd = nullptr; - -bool CMPlayerCApp::StoreSettingsToIni() -{ - std::lock_guard lock(m_profileMutex); - - CString ini = GetIniPath(); - free((void*)m_pszRegistryKey); - m_pszRegistryKey = nullptr; - free((void*)m_pszProfileName); - m_pszProfileName = _tcsdup(ini); - - return true; -} - -bool CMPlayerCApp::StoreSettingsToRegistry() -{ - std::lock_guard lock(m_profileMutex); - - free((void*)m_pszRegistryKey); - m_pszRegistryKey = nullptr; - - SetRegistryKey(_T("MPC-HC")); - - return true; -} - -CString CMPlayerCApp::GetIniPath() const -{ - CString path = PathUtils::GetProgramPath(true); - path = path.Left(path.ReverseFind('.') + 1) + _T("ini"); - return path; -} - -bool CMPlayerCApp::IsIniValid() const -{ - return PathUtils::Exists(GetIniPath()); -} - -bool CMPlayerCApp::GetAppSavePath(CString& path) -{ - if (IsIniValid()) { // If settings ini file found, store stuff in the same folder as the exe file - path = PathUtils::GetProgramPath(); - } else { - return GetAppDataPath(path); - } - - return true; -} - -bool CMPlayerCApp::GetAppDataPath(CString& path) -{ - path.Empty(); - - HRESULT hr = SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, 0, path.GetBuffer(MAX_PATH)); - path.ReleaseBuffer(); - if (FAILED(hr)) { - return false; - } - CPath p; - p.Combine(path, _T("MPC-HC")); - path = (LPCTSTR)p; - - return true; -} - -bool CMPlayerCApp::ChangeSettingsLocation(bool useIni) -{ - std::lock_guard lock(m_profileMutex); - - bool success; - - // Load favorites so that they can be correctly saved to the new location - CAtlList filesFav, DVDsFav, devicesFav; - m_s->GetFav(FAV_FILE, filesFav); - m_s->GetFav(FAV_DVD, DVDsFav); - m_s->GetFav(FAV_DEVICE, devicesFav); - - if (useIni) { - success = StoreSettingsToIni(); - // No need to delete old mpc-hc.ini, - // as it will be overwritten during CAppSettings::SaveSettings() - } else { - success = StoreSettingsToRegistry(); - _tremove(GetIniPath()); - } - - // Save favorites to the new location - m_s->SetFav(FAV_FILE, filesFav); - m_s->SetFav(FAV_DVD, DVDsFav); - m_s->SetFav(FAV_DEVICE, devicesFav); - - // Save external filters to the new location - m_s->SaveExternalFilters(); - - // Write settings immediately - m_s->SaveSettings(true); - - return success; -} - -bool CMPlayerCApp::ExportSettings(CString savePath, CString subKey) -{ - bool success = false; - m_s->SaveSettings(); - - if (IsIniValid()) { - success = !!CopyFile(GetIniPath(), savePath, FALSE); - } else { - CString regKey; - if (subKey.IsEmpty()) { - regKey.Format(_T("Software\\%s\\%s"), m_pszRegistryKey, m_pszProfileName); - } else { - regKey.Format(_T("Software\\%s\\%s\\%s"), m_pszRegistryKey, m_pszProfileName, subKey.GetString()); - } - - FILE* fStream; - errno_t error = _tfopen_s(&fStream, savePath, _T("wt,ccs=UNICODE")); - CStdioFile file(fStream); - file.WriteString(_T("Windows Registry Editor Version 5.00\n\n")); - - success = !error && ExportRegistryKey(file, HKEY_CURRENT_USER, regKey); - - file.Close(); - if (!success && !error) { - DeleteFile(savePath); - } - } - - return success; -} - -void CMPlayerCApp::InitProfile() -{ - std::lock_guard lock(m_profileMutex); - - if (!m_pszRegistryKey) { - // Don't reread mpc-hc.ini if the cache needs to be flushed or it was accessed recently - if (m_bProfileInitialized && (m_bQueuedProfileFlush || GetTickCount64() - m_dwProfileLastAccessTick < 100ULL)) { - m_dwProfileLastAccessTick = GetTickCount64(); - return; - } - - m_bProfileInitialized = true; - m_dwProfileLastAccessTick = GetTickCount64(); - - ASSERT(m_pszProfileName); - if (!PathUtils::Exists(m_pszProfileName)) { - return; - } - - FILE* fp; - int fpStatus; - do { // Open mpc-hc.ini in UNICODE mode, retry if it is already being used by another process - fp = _tfsopen(m_pszProfileName, _T("r, ccs=UNICODE"), _SH_SECURE); - if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { - break; - } - Sleep(100); - } while (true); - if (!fp) { - ASSERT(FALSE); - return; - } - if (_ftell_nolock(fp) == 0L) { - // No BOM was consumed, assume mpc-hc.ini is ANSI encoded - fpStatus = fclose(fp); - ASSERT(fpStatus == 0); - do { // Reopen mpc-hc.ini in ANSI mode, retry if it is already being used by another process - fp = _tfsopen(m_pszProfileName, _T("r"), _SH_SECURE); - if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { - break; - } - Sleep(100); - } while (true); - if (!fp) { - ASSERT(FALSE); - return; - } - } - - CStdioFile file(fp); - - ASSERT(!m_bQueuedProfileFlush); - m_ProfileMap.clear(); - - CString line, section, var, val; - while (file.ReadString(line)) { - // Parse mpc-hc.ini file, this parser: - // - doesn't trim whitespaces - // - doesn't remove quotation marks - // - omits keys with empty names - // - omits unnamed sections - int pos = 0; - if (line[0] == _T('[')) { - pos = line.Find(_T(']')); - if (pos == -1) { - continue; - } - section = line.Mid(1, pos - 1); - } else if (line[0] != _T(';')) { - pos = line.Find(_T('=')); - if (pos == -1) { - continue; - } - var = line.Mid(0, pos); - val = line.Mid(pos + 1); - if (!section.IsEmpty() && !var.IsEmpty()) { - m_ProfileMap[section][var] = val; - } - } - } - fpStatus = fclose(fp); - ASSERT(fpStatus == 0); - - m_dwProfileLastAccessTick = GetTickCount64(); - } -} - -void CMPlayerCApp::FlushProfile(bool bForce/* = true*/) -{ - std::lock_guard lock(m_profileMutex); - - if (!m_pszRegistryKey) { - if (!bForce && !m_bQueuedProfileFlush) { - return; - } - - m_bQueuedProfileFlush = false; - - ASSERT(m_bProfileInitialized); - ASSERT(m_pszProfileName); - - FILE* fp; - int fpStatus; - do { // Open mpc-hc.ini, retry if it is already being used by another process - fp = _tfsopen(m_pszProfileName, _T("w, ccs=UTF-8"), _SH_SECURE); - if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { - break; - } - Sleep(100); - } while (true); - if (!fp) { - ASSERT(FALSE); - return; - } - CStdioFile file(fp); - CString line; - try { - file.WriteString(_T("; MPC-HC\n")); - for (auto it1 = m_ProfileMap.begin(); it1 != m_ProfileMap.end(); ++it1) { - line.Format(_T("[%s]\n"), it1->first.GetString()); - file.WriteString(line); - for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) { - line.Format(_T("%s=%s\n"), it2->first.GetString(), it2->second.GetString()); - file.WriteString(line); - } - } - } catch (CFileException& e) { - // Fail silently if disk is full - UNREFERENCED_PARAMETER(e); - ASSERT(FALSE); - } - fpStatus = fclose(fp); - ASSERT(fpStatus == 0); - } -} - -BOOL CMPlayerCApp::GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes) -{ - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - return CWinAppEx::GetProfileBinary(lpszSection, lpszEntry, ppData, pBytes); - } else { - if (!lpszSection || !lpszEntry || !ppData || !pBytes) { - ASSERT(FALSE); - return FALSE; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - CString valueStr; - - InitProfile(); - auto it1 = m_ProfileMap.find(sectionStr); - if (it1 != m_ProfileMap.end()) { - auto it2 = it1->second.find(keyStr); - if (it2 != it1->second.end()) { - valueStr = it2->second; - } - } - if (valueStr.IsEmpty()) { - return FALSE; - } - int length = valueStr.GetLength(); - // Encoding: each 4-bit sequence is coded in one character, from 'A' for 0x0 to 'P' for 0xf - if (length % 2) { - ASSERT(FALSE); - return FALSE; - } - for (int i = 0; i < length; i++) { - if (valueStr[i] < 'A' || valueStr[i] > 'P') { - ASSERT(FALSE); - return FALSE; - } - } - *pBytes = length / 2; - *ppData = new (std::nothrow) BYTE[*pBytes]; - if (!(*ppData)) { - ASSERT(FALSE); - return FALSE; - } - for (UINT i = 0; i < *pBytes; i++) { - (*ppData)[i] = BYTE((valueStr[i * 2] - 'A') | ((valueStr[i * 2 + 1] - 'A') << 4)); - } - return TRUE; - } -} - -UINT CMPlayerCApp::GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) -{ - std::lock_guard lock(m_profileMutex); - - int res = nDefault; - if (m_pszRegistryKey) { - res = CWinAppEx::GetProfileInt(lpszSection, lpszEntry, nDefault); - } else { - if (!lpszSection || !lpszEntry) { - ASSERT(FALSE); - return res; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return res; - } - - InitProfile(); - auto it1 = m_ProfileMap.find(sectionStr); - if (it1 != m_ProfileMap.end()) { - auto it2 = it1->second.find(keyStr); - if (it2 != it1->second.end()) { - res = _ttoi(it2->second); - } - } - } - return res; -} - -std::list CMPlayerCApp::GetSectionSubKeys(LPCWSTR lpszSection) { - std::lock_guard lock(m_profileMutex); - - std::list keys; - - if (m_pszRegistryKey) { - WCHAR achKey[MAX_REGKEY_LEN]; // buffer for subkey name - DWORD cbName; // size of name string - DWORD cSubKeys = 0; // number of subkeys - - if (HKEY hAppKey = GetAppRegistryKey()) { - HKEY hSectionKey; - if (ERROR_SUCCESS == RegOpenKeyExW(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey)) { - RegQueryInfoKeyW(hSectionKey, NULL, NULL, NULL, &cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - - if (cSubKeys) { - for (DWORD i = 0; i < cSubKeys; i++) { - cbName = MAX_REGKEY_LEN; - if (ERROR_SUCCESS == RegEnumKeyExW(hSectionKey, i, achKey, &cbName, NULL, NULL, NULL, NULL)){ - keys.push_back(achKey); - } - } - } - } - } - } else { - if (!lpszSection) { - ASSERT(FALSE); - return keys; - } - CStringW sectionStr(lpszSection); - if (sectionStr.IsEmpty()) { - ASSERT(FALSE); - return keys; - } - InitProfile(); - auto it1 = m_ProfileMap.begin(); - while (it1 != m_ProfileMap.end()) { - if (it1->first.Find(sectionStr + L"\\") == 0) { - CStringW subKey = it1->first.Mid(sectionStr.GetLength() + 1); - if (subKey.Find(L"\\") == -1) { - keys.push_back(subKey); - } - } - it1++; - } - - } - return keys; -} - - -CString CMPlayerCApp::GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault) -{ - std::lock_guard lock(m_profileMutex); - - CString res; - if (m_pszRegistryKey) { - res = CWinAppEx::GetProfileString(lpszSection, lpszEntry, lpszDefault); - } else { - if (!lpszSection || !lpszEntry) { - ASSERT(FALSE); - return res; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return res; - } - if (lpszDefault) { - res = lpszDefault; - } - - InitProfile(); - auto it1 = m_ProfileMap.find(sectionStr); - if (it1 != m_ProfileMap.end()) { - auto it2 = it1->second.find(keyStr); - if (it2 != it1->second.end()) { - res = it2->second; - } - } - } - return res; -} - -BOOL CMPlayerCApp::WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes) -{ - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - return CWinAppEx::WriteProfileBinary(lpszSection, lpszEntry, pData, nBytes); - } else { - if (!lpszSection || !lpszEntry || !pData || !nBytes) { - ASSERT(FALSE); - return FALSE; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - CString valueStr; - - TCHAR* buffer = valueStr.GetBufferSetLength(nBytes * 2); - // Encoding: each 4-bit sequence is coded in one character, from 'A' for 0x0 to 'P' for 0xf - for (UINT i = 0; i < nBytes; i++) { - buffer[i * 2] = 'A' + (pData[i] & 0xf); - buffer[i * 2 + 1] = 'A' + (pData[i] >> 4 & 0xf); - } - valueStr.ReleaseBufferSetLength(nBytes * 2); - - InitProfile(); - CString& old = m_ProfileMap[sectionStr][keyStr]; - if (old != valueStr) { - old = valueStr; - m_bQueuedProfileFlush = true; - } - return TRUE; - } -} - -LONG CMPlayerCApp::RemoveProfileKey(LPCWSTR lpszSection, LPCWSTR lpszEntry) { - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - if (HKEY hAppKey = GetAppRegistryKey()) { - HKEY hSectionKey; - if (ERROR_SUCCESS == RegOpenKeyEx(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey)) { - return CWinAppEx::DelRegTree(hSectionKey, lpszEntry); - } - } - } else { - if (!lpszSection || !lpszEntry) { - ASSERT(FALSE); - return 1; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return 1; - } - - InitProfile(); - auto it1 = m_ProfileMap.find(sectionStr + L"\\" + keyStr); - if (it1 != m_ProfileMap.end()) { - m_ProfileMap.erase(it1); - m_bQueuedProfileFlush = true; - } - } - return 0; -} - -BOOL CMPlayerCApp::WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) -{ - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - return CWinAppEx::WriteProfileInt(lpszSection, lpszEntry, nValue); - } else { - if (!lpszSection || !lpszEntry) { - ASSERT(FALSE); - return FALSE; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - CString valueStr; - valueStr.Format(_T("%d"), nValue); - - InitProfile(); - CString& old = m_ProfileMap[sectionStr][keyStr]; - if (old != valueStr) { - old = valueStr; - m_bQueuedProfileFlush = true; - } - return TRUE; - } -} - -BOOL CMPlayerCApp::WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) -{ - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - return CWinAppEx::WriteProfileString(lpszSection, lpszEntry, lpszValue); - } else { - if (!lpszSection) { - ASSERT(FALSE); - return FALSE; - } - CString sectionStr(lpszSection); - if (sectionStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - CString keyStr(lpszEntry); - if (lpszEntry && keyStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - - InitProfile(); - - // Mimic CWinAppEx::WriteProfileString() behavior - if (lpszEntry) { - if (lpszValue) { - CString& old = m_ProfileMap[sectionStr][keyStr]; - if (old != lpszValue) { - old = lpszValue; - m_bQueuedProfileFlush = true; - } - } else { // Delete key - auto it = m_ProfileMap.find(sectionStr); - if (it != m_ProfileMap.end()) { - if (it->second.erase(keyStr)) { - m_bQueuedProfileFlush = true; - } - } - } - } else { // Delete section - if (m_ProfileMap.erase(sectionStr)) { - m_bQueuedProfileFlush = true; - } - } - return TRUE; - } -} - -bool CMPlayerCApp::HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry) -{ - std::lock_guard lock(m_profileMutex); - - bool ret = false; - if (m_pszRegistryKey) { - if (HKEY hAppKey = GetAppRegistryKey()) { - HKEY hSectionKey; - if (RegOpenKeyEx(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey) == ERROR_SUCCESS) { - LONG lResult = RegQueryValueEx(hSectionKey, lpszEntry, nullptr, nullptr, nullptr, nullptr); - ret = (lResult == ERROR_SUCCESS); - VERIFY(RegCloseKey(hSectionKey) == ERROR_SUCCESS); - } - VERIFY(RegCloseKey(hAppKey) == ERROR_SUCCESS); - } else { - ASSERT(FALSE); - } - } else { - InitProfile(); - auto it1 = m_ProfileMap.find(lpszSection); - if (it1 != m_ProfileMap.end()) { - auto& sectionMap = it1->second; - auto it2 = sectionMap.find(lpszEntry); - ret = (it2 != sectionMap.end()); - } - } - return ret; -} - -std::vector CMPlayerCApp::GetProfileVectorInt(CString strSection, CString strKey) { - std::vector vData; - UINT uSize = theApp.GetProfileInt(strSection, strKey + _T("Size"), 0); - UINT uSizeRead = 0; - BYTE* temp = nullptr; - theApp.GetProfileBinary(strSection, strKey, &temp, &uSizeRead); - if (uSizeRead == uSize) { - vData.resize(uSizeRead / sizeof(int), 0); - memcpy(vData.data(), temp, uSizeRead); - } - delete[] temp; - temp = nullptr; - return vData; -} - - -void CMPlayerCApp::WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData) { - UINT uSize = static_cast(sizeof(int) * vData.size()); - theApp.WriteProfileBinary( - strSection, - strKey, - (LPBYTE)vData.data(), - uSize - ); - theApp.WriteProfileInt(strSection, strKey + _T("Size"), uSize); -} - -void CMPlayerCApp::PreProcessCommandLine() -{ - m_cmdln.RemoveAll(); - - for (int i = 1; i < __argc; i++) { - m_cmdln.AddTail(CString(__targv[i]).Trim(_T(" \""))); - } -} - -bool CMPlayerCApp::SendCommandLine(HWND hWnd) -{ - if (m_cmdln.IsEmpty()) { - return false; - } - - int bufflen = sizeof(DWORD); - - POSITION pos = m_cmdln.GetHeadPosition(); - while (pos) { - bufflen += (m_cmdln.GetNext(pos).GetLength() + 1) * sizeof(TCHAR); - } - - CAutoVectorPtr buff; - if (!buff.Allocate(bufflen)) { - return FALSE; - } - - BYTE* p = buff; - - *(DWORD*)p = (DWORD)m_cmdln.GetCount(); - p += sizeof(DWORD); - - pos = m_cmdln.GetHeadPosition(); - while (pos) { - const CString& s = m_cmdln.GetNext(pos); - int len = (s.GetLength() + 1) * sizeof(TCHAR); - memcpy(p, s, len); - p += len; - } - - COPYDATASTRUCT cds; - cds.dwData = 0x6ABE51; - cds.cbData = bufflen; - cds.lpData = (void*)(BYTE*)buff; - - return !!SendMessageTimeoutW(hWnd, WM_COPYDATA, (WPARAM)nullptr, (LPARAM)&cds, SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 5000, nullptr); -} - -// CMPlayerCApp initialization - -// This hook prevents the program from reporting that a debugger is attached -BOOL(WINAPI* Real_IsDebuggerPresent)() = IsDebuggerPresent; -BOOL WINAPI Mine_IsDebuggerPresent() -{ - TRACE(_T("Oops, somebody was trying to be naughty! (called IsDebuggerPresent)\n")); - return FALSE; -} - -// This hook prevents the program from reporting that a debugger is attached -NTSTATUS(WINAPI* Real_NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG) = nullptr; -NTSTATUS WINAPI Mine_NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength) -{ - NTSTATUS nRet; - - nRet = Real_NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength); - - if (ProcessInformationClass == ProcessBasicInformation) { - PROCESS_BASIC_INFORMATION* pbi = (PROCESS_BASIC_INFORMATION*)ProcessInformation; - PEB_NT* pPEB = (PEB_NT*)pbi->PebBaseAddress; - PEB_NT PEB; - - ReadProcessMemory(ProcessHandle, pPEB, &PEB, sizeof(PEB), nullptr); - PEB.BeingDebugged = FALSE; - WriteProcessMemory(ProcessHandle, pPEB, &PEB, sizeof(PEB), nullptr); - } else if (ProcessInformationClass == 7) { // ProcessDebugPort - BOOL* pDebugPort = (BOOL*)ProcessInformation; - *pDebugPort = FALSE; - } - - return nRet; -} - -#define USE_DLL_BLOCKLIST 1 - -#if USE_DLL_BLOCKLIST -#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) - -typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT; - -typedef enum _SECTION_INFORMATION_CLASS { - SectionBasicInformation = 0, - SectionImageInformation -} SECTION_INFORMATION_CLASS; - -typedef struct _SECTION_BASIC_INFORMATION { - PVOID BaseAddress; - ULONG Attributes; - LARGE_INTEGER Size; -} SECTION_BASIC_INFORMATION; - -typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtMapViewOfSection)(HANDLE, HANDLE, PVOID, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT, ULONG, ULONG); -typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtUnmapViewOfSection)(HANDLE, PVOID); -typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); -typedef DWORD(STDMETHODCALLTYPE* pfn_GetMappedFileNameW)(HANDLE, LPVOID, LPWSTR, DWORD); - -static pfn_NtMapViewOfSection Real_NtMapViewOfSection = nullptr; -static pfn_NtUnmapViewOfSection Real_NtUnmapViewOfSection = nullptr; -static pfn_NtQuerySection Real_NtQuerySection = nullptr; -static pfn_GetMappedFileNameW Real_GetMappedFileNameW = nullptr; - -typedef struct { - // DLL name, lower case, with backslash as prefix - const wchar_t* name; - size_t name_len; -} blocked_module_t; - -// list of modules that can cause crashes or other unwanted behavior -static blocked_module_t moduleblocklist[] = { -#if WIN64 - // Logitech codec - {_T("\\lvcod64.dll"), 12}, - // ProxyCodec64 - {_T("\\pxc0.dll"), 9}, -#else - {_T("\\mlc.dll"), 8}, -#endif - // Lame - {_T("\\lameacm.acm"), 12}, - // ffdshow vfw - {_T("\\ff_vfw.dll"), 11}, -#if WIN64 - // Trusteer Rapport - {_T("\\rooksbas_x64.dll"), 17}, - {_T("\\rooksdol_x64.dll"), 17}, - {_T("\\rapportgh_x64.dll"), 18}, -#endif - // ASUS GamerOSD - {_T("\\atkdx11disp.dll"), 16}, - // ASUS GPU TWEAK II OSD - {_T("\\gtii-osd64.dll"), 15}, - {_T("\\gtii-osd64-vk.dll"), 18}, - // Nahimic Audio - {L"\\nahimicmsidevprops.dll", 23}, - {L"\\nahimicmsiosd.dll", 18}, - // LoiLoGameRecorder - {_T("\\loilocap.dll"), 13}, - // Other - {_T("\\tortoiseoverlays.dll"), 21}, -#if WIN64 - // Sizer - {_T("\\hook64.dll"), 11}, -#endif -}; - -bool IsBlockedModule(wchar_t* modulename) -{ - size_t mod_name_len = wcslen(modulename); - - //TRACE(L"Checking module blocklist: %s\n", modulename); - - for (size_t i = 0; i < _countof(moduleblocklist); i++) { - blocked_module_t* b = &moduleblocklist[i]; - if (mod_name_len > b->name_len) { - wchar_t* dll_ptr = modulename + mod_name_len - b->name_len; - if (_wcsicmp(dll_ptr, b->name) == 0) { - //AfxMessageBox(modulename); - TRACE(L"Blocked module load: %s\n", modulename); - return true; - } - } - } - - return false; -} - -NTSTATUS STDMETHODCALLTYPE Mine_NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, - PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) -{ - NTSTATUS ret = Real_NtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); - - // Verify map and process - if (ret < 0 || ProcessHandle != GetCurrentProcess()) - return ret; - - // Fetch section information - SIZE_T wrote = 0; - SECTION_BASIC_INFORMATION section_information; - if (Real_NtQuerySection(SectionHandle, SectionBasicInformation, §ion_information, sizeof(section_information), &wrote) < 0) - return ret; - - // Verify fetch was successful - if (wrote != sizeof(section_information)) - return ret; - - // We're not interested in non-image maps - if (!(section_information.Attributes & SEC_IMAGE)) - return ret; - - // Get the actual filename if possible - wchar_t fileName[MAX_PATH]; - // ToDo: switch to PSAPI_VERSION=2 and directly use K32GetMappedFileNameW ? - if (Real_GetMappedFileNameW(ProcessHandle, *BaseAddress, fileName, _countof(fileName)) == 0) - return ret; - - if (IsBlockedModule(fileName)) { - Real_NtUnmapViewOfSection(ProcessHandle, BaseAddress); - ret = STATUS_UNSUCCESSFUL; - } - - return ret; -} -#endif - -static LONG Mine_ChangeDisplaySettingsEx(LONG ret, DWORD dwFlags, LPVOID lParam) -{ - if (dwFlags & CDS_VIDEOPARAMETERS) { - VIDEOPARAMETERS* vp = (VIDEOPARAMETERS*)lParam; - - if (vp->Guid == GUIDFromCString(_T("{02C62061-1097-11d1-920F-00A024DF156E}")) - && (vp->dwFlags & VP_FLAGS_COPYPROTECT)) { - if (vp->dwCommand == VP_COMMAND_GET) { - if ((vp->dwTVStandard & VP_TV_STANDARD_WIN_VGA) - && vp->dwTVStandard != VP_TV_STANDARD_WIN_VGA) { - TRACE(_T("Ooops, tv-out enabled? macrovision checks suck...")); - vp->dwTVStandard = VP_TV_STANDARD_WIN_VGA; - } - } else if (vp->dwCommand == VP_COMMAND_SET) { - TRACE(_T("Ooops, as I already told ya, no need for any macrovision bs here")); - return 0; - } - } - } - - return ret; -} - -// These two hooks prevent the program from requesting Macrovision checks -LONG(WINAPI* Real_ChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID) = ChangeDisplaySettingsExA; -LONG(WINAPI* Real_ChangeDisplaySettingsExW)(LPCWSTR, LPDEVMODEW, HWND, DWORD, LPVOID) = ChangeDisplaySettingsExW; -LONG WINAPI Mine_ChangeDisplaySettingsExA(LPCSTR lpszDeviceName, LPDEVMODEA lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam) -{ - return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExA(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam); -} -LONG WINAPI Mine_ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, LPDEVMODEW lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam) -{ - return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam); -} - -// This hook forces files to open even if they are currently being written -HANDLE(WINAPI* Real_CreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileA; -HANDLE WINAPI Mine_CreateFileA(LPCSTR p1, DWORD p2, DWORD p3, LPSECURITY_ATTRIBUTES p4, DWORD p5, DWORD p6, HANDLE p7) -{ - p3 |= FILE_SHARE_WRITE; - - return Real_CreateFileA(p1, p2, p3, p4, p5, p6, p7); -} - -static BOOL CreateFakeVideoTS(LPCWSTR strIFOPath, LPWSTR strFakeFile, size_t nFakeFileSize) -{ - BOOL bRet = FALSE; - WCHAR szTempPath[MAX_PATH]; - WCHAR strFileName[MAX_PATH]; - WCHAR strExt[_MAX_EXT]; - CIfo Ifo; - - if (!GetTempPathW(MAX_PATH, szTempPath)) { - return FALSE; - } - - _wsplitpath_s(strIFOPath, nullptr, 0, nullptr, 0, strFileName, _countof(strFileName), strExt, _countof(strExt)); - _snwprintf_s(strFakeFile, nFakeFileSize, _TRUNCATE, L"%sMPC%s%s", szTempPath, strFileName, strExt); - - if (Ifo.OpenFile(strIFOPath) && Ifo.RemoveUOPs() && Ifo.SaveFile(strFakeFile)) { - bRet = TRUE; - } - - return bRet; -} - -// This hook forces files to open even if they are currently being written and hijacks -// IFO file opening so that a modified IFO with no forbidden operations is opened instead. -HANDLE(WINAPI* Real_CreateFileW)(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileW; -HANDLE WINAPI Mine_CreateFileW(LPCWSTR p1, DWORD p2, DWORD p3, LPSECURITY_ATTRIBUTES p4, DWORD p5, DWORD p6, HANDLE p7) -{ - HANDLE hFile = INVALID_HANDLE_VALUE; - size_t nLen = wcslen(p1); - - p3 |= FILE_SHARE_WRITE; - - if (nLen >= 4 && _wcsicmp(p1 + nLen - 4, L".ifo") == 0) { - WCHAR strFakeFile[MAX_PATH]; - if (CreateFakeVideoTS(p1, strFakeFile, _countof(strFakeFile))) { - hFile = Real_CreateFileW(strFakeFile, p2, p3, p4, p5, p6, p7); - } - } - - if (hFile == INVALID_HANDLE_VALUE) { - hFile = Real_CreateFileW(p1, p2, p3, p4, p5, p6, p7); - } - - return hFile; -} - -// This hooks disables the DVD version check -BOOL(WINAPI* Real_DeviceIoControl)(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED) = DeviceIoControl; -BOOL WINAPI Mine_DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) -{ - BOOL ret = Real_DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); - if (IOCTL_DVD_GET_REGION == dwIoControlCode && lpOutBuffer && nOutBufferSize == sizeof(DVD_REGION)) { - DVD_REGION* pDVDRegion = (DVD_REGION*)lpOutBuffer; - - if (pDVDRegion->RegionData > 0) { - UCHAR disc_regions = ~pDVDRegion->RegionData; - if ((disc_regions & pDVDRegion->SystemRegion) == 0) { - if (disc_regions & 1) pDVDRegion->SystemRegion = 1; - else if (disc_regions & 2) pDVDRegion->SystemRegion = 2; - else if (disc_regions & 4) pDVDRegion->SystemRegion = 4; - else if (disc_regions & 8) pDVDRegion->SystemRegion = 8; - else if (disc_regions & 16) pDVDRegion->SystemRegion = 16; - else if (disc_regions & 32) pDVDRegion->SystemRegion = 32; - else if (disc_regions & 128) pDVDRegion->SystemRegion = 128; - ret = true; - } - } else if (pDVDRegion->SystemRegion == 0) { - pDVDRegion->SystemRegion = 1; - ret = true; - } - } - return ret; -} - -MMRESULT(WINAPI* Real_mixerSetControlDetails)(HMIXEROBJ, LPMIXERCONTROLDETAILS, DWORD) = mixerSetControlDetails; -MMRESULT WINAPI Mine_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) -{ - if (fdwDetails == (MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)) { - return MMSYSERR_NOERROR; // don't touch the mixer, kthx - } - return Real_mixerSetControlDetails(hmxobj, pmxcd, fdwDetails); -} - -BOOL (WINAPI* Real_LockWindowUpdate)(HWND) = LockWindowUpdate; -BOOL WINAPI Mine_LockWindowUpdate(HWND hWndLock) -{ - // TODO: Check if needed on Windows 8+ - if (hWndLock == ::GetDesktopWindow()) { - // locking the desktop window with aero active locks the entire compositor, - // unfortunately MFC does that (when dragging CControlBar) and we want to prevent it - return FALSE; - } else { - return Real_LockWindowUpdate(hWndLock); - } -} - -BOOL RegQueryBoolValue(HKEY hKeyRoot, LPCWSTR lpSubKey, LPCWSTR lpValuename, BOOL defaultvalue) { - BOOL result = defaultvalue; - HKEY hKeyOpen; - DWORD rv = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKeyOpen); - if (rv == ERROR_SUCCESS) { - DWORD data; - DWORD dwBufferSize = sizeof(DWORD); - rv = RegQueryValueEx(hKeyOpen, lpValuename, NULL, NULL, reinterpret_cast(&data), &dwBufferSize); - if (rv == ERROR_SUCCESS) { - result = (data > 0); - } - RegCloseKey(hKeyOpen); - } - return result; -} - -#if USE_DRDUMP_CRASH_REPORTER -void DisableCrashReporter() -{ - if (CrashReporter::IsEnabled()) { - CrashReporter::Disable(); - MPCExceptionHandler::Enable(); - } -} -#endif - -BOOL CMPlayerCApp::InitInstance() -{ - // Remove the working directory from the search path to work around the DLL preloading vulnerability - SetDllDirectory(_T("")); - - // At this point we have not hooked this function yet so we get the real result - if (!IsDebuggerPresent()) { -#if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER - if (RegQueryBoolValue(HKEY_CURRENT_USER, _T("Software\\MPC-HC\\MPC-HC\\Settings"), _T("EnableCrashReporter"), true)) { - CrashReporter::Enable(); - if (!CrashReporter::IsEnabled()) { - MPCExceptionHandler::Enable(); - } - } else { - MPCExceptionHandler::Enable(); - } -#else - MPCExceptionHandler::Enable(); -#endif - } - - if (!HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0)) { - TRACE(_T("Failed to enable \"terminate on corruption\" heap option, error %u\n"), GetLastError()); - ASSERT(FALSE); - } - - bool bHookingSuccessful = MH_Initialize() == MH_OK; - -#ifndef _DEBUG - bHookingSuccessful &= !!Mhook_SetHookEx(&Real_IsDebuggerPresent, Mine_IsDebuggerPresent); -#endif - - m_hNTDLL = LoadLibrary(_T("ntdll.dll")); -#if 0 -#ifndef _DEBUG // Disable NtQueryInformationProcess in debug (prevent VS debugger to stop on crash address) - if (m_hNTDLL) { - Real_NtQueryInformationProcess = (decltype(Real_NtQueryInformationProcess))GetProcAddress(m_hNTDLL, "NtQueryInformationProcess"); - - if (Real_NtQueryInformationProcess) { - bHookingSuccessful &= !!Mhook_SetHookEx(&Real_NtQueryInformationProcess, Mine_NtQueryInformationProcess); - } - } -#endif -#endif - - bHookingSuccessful &= !!Mhook_SetHookEx(&Real_CreateFileW, Mine_CreateFileW); - bHookingSuccessful &= !!Mhook_SetHookEx(&Real_DeviceIoControl, Mine_DeviceIoControl); - - bHookingSuccessful &= MH_EnableHook(MH_ALL_HOOKS) == MH_OK; - - if (!bHookingSuccessful) { - AfxMessageBox(IDS_HOOKS_FAILED); - } - -#if USE_DLL_BLOCKLIST - if (m_hNTDLL) { - Real_NtMapViewOfSection = (pfn_NtMapViewOfSection)GetProcAddress(m_hNTDLL, "NtMapViewOfSection"); - Real_NtUnmapViewOfSection = (pfn_NtUnmapViewOfSection)GetProcAddress(m_hNTDLL, "NtUnmapViewOfSection"); - Real_NtQuerySection = (pfn_NtQuerySection)GetProcAddress(m_hNTDLL, "NtQuerySection"); - Real_GetMappedFileNameW = (pfn_GetMappedFileNameW)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "K32GetMappedFileNameW"); - if (Real_NtMapViewOfSection && Real_NtUnmapViewOfSection && Real_NtQuerySection && Real_GetMappedFileNameW) { - VERIFY(Mhook_SetHookEx(&Real_NtMapViewOfSection, Mine_NtMapViewOfSection)); - } - } -#endif - - // If those hooks fail it's annoying but try to run anyway without reporting any error in release mode - VERIFY(Mhook_SetHookEx(&Real_ChangeDisplaySettingsExA, Mine_ChangeDisplaySettingsExA)); - VERIFY(Mhook_SetHookEx(&Real_ChangeDisplaySettingsExW, Mine_ChangeDisplaySettingsExW)); - VERIFY(Mhook_SetHookEx(&Real_CreateFileA, Mine_CreateFileA)); // The internal splitter uses the right share mode anyway so this is no big deal - VERIFY(Mhook_SetHookEx(&Real_LockWindowUpdate, Mine_LockWindowUpdate)); - VERIFY(Mhook_SetHookEx(&Real_mixerSetControlDetails, Mine_mixerSetControlDetails)); - MH_EnableHook(MH_ALL_HOOKS); - - CFilterMapper2::Init(); - - if (FAILED(OleInitialize(nullptr))) { - AfxMessageBox(_T("OleInitialize failed!")); - return FALSE; - } - - m_s = std::make_unique(); - - // Be careful if you move that code: IDR_MAINFRAME icon can only be loaded from the executable, - // LoadIcon can't be used after the language DLL has been set as the main resource. - HICON icon = LoadIcon(IDR_MAINFRAME); - - WNDCLASS wndcls; - ZeroMemory(&wndcls, sizeof(WNDCLASS)); - wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; - wndcls.lpfnWndProc = ::DefWindowProc; - wndcls.hInstance = AfxGetInstanceHandle(); - wndcls.hIcon = icon; - wndcls.hCursor = LoadCursor(IDC_ARROW); - wndcls.hbrBackground = 0;//(HBRUSH)(COLOR_WINDOW + 1); // no bkg brush, the view and the bars should always fill the whole client area - wndcls.lpszMenuName = nullptr; - wndcls.lpszClassName = MPC_WND_CLASS_NAME; - - if (!AfxRegisterClass(&wndcls)) { - AfxMessageBox(_T("MainFrm class registration failed!")); - return FALSE; - } - - if (!AfxSocketInit(nullptr)) { - AfxMessageBox(_T("AfxSocketInit failed!")); - return FALSE; - } - - PreProcessCommandLine(); - - if (IsIniValid()) { - StoreSettingsToIni(); - } else { - StoreSettingsToRegistry(); - } - - m_s->ParseCommandLine(m_cmdln); - - VERIFY(SetCurrentDirectory(PathUtils::GetProgramPath())); - - if (m_s->nCLSwitches & (CLSW_HELP | CLSW_UNRECOGNIZEDSWITCH)) { // show commandline help window - m_s->LoadSettings(); - ShowCmdlnSwitches(); - return FALSE; - } - - if (m_s->nCLSwitches & CLSW_RESET) { // reset settings - // We want the other instances to be closed before resetting the settings. - HWND hWnd = FindWindow(MPC_WND_CLASS_NAME, nullptr); - - while (hWnd) { - Sleep(500); - - hWnd = FindWindow(MPC_WND_CLASS_NAME, nullptr); - - if (hWnd && MessageBox(nullptr, ResStr(IDS_RESET_SETTINGS_MUTEX), ResStr(IDS_RESET_SETTINGS), MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDCANCEL) { - return FALSE; - } - } - - // If the profile was already cached, it should be cleared here - ASSERT(!m_bProfileInitialized); - - // Remove the settings - if (IsIniValid()) { - FILE* fp; - do { // Open mpc-hc.ini, retry if it is already being used by another process - fp = _tfsopen(m_pszProfileName, _T("w"), _SH_SECURE); - if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { - break; - } - Sleep(100); - } while (true); - if (fp) { - // Close without writing anything, it should produce empty file - VERIFY(fclose(fp) == 0); - } else { - ASSERT(FALSE); - } - } else { - CRegKey key; - // Clear settings - key.Attach(GetAppRegistryKey()); - VERIFY(key.RecurseDeleteKey(_T("")) == ERROR_SUCCESS); - VERIFY(key.Close() == ERROR_SUCCESS); - // Set ExePath value to prevent settings migration - key.Attach(GetAppRegistryKey()); - VERIFY(key.SetStringValue(_T("ExePath"), PathUtils::GetProgramPath(true)) == ERROR_SUCCESS); - VERIFY(key.Close() == ERROR_SUCCESS); - } - - // Remove the current playlist if it exists - CString strSavePath; - if (GetAppSavePath(strSavePath)) { - CPath playlistPath; - playlistPath.Combine(strSavePath, _T("default.mpcpl")); - - if (playlistPath.FileExists()) { - try { - CFile::Remove(playlistPath); - } catch (...) {} - } - } - } - - if ((m_s->nCLSwitches & CLSW_CLOSE) && m_s->slFiles.IsEmpty()) { // "/close" switch and empty file list - return FALSE; - } - - if (m_s->nCLSwitches & (CLSW_REGEXTVID | CLSW_REGEXTAUD | CLSW_REGEXTPL)) { // register file types - m_s->fileAssoc.RegisterApp(); - - CMediaFormats& mf = m_s->m_Formats; - mf.UpdateData(false); - - bool bAudioOnly; - - auto iconLib = m_s->fileAssoc.GetIconLib(); - if (iconLib) { - iconLib->SaveVersion(); - } - - for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { - bool bPlaylist = !mf[i].GetLabel().CompareNoCase(_T("pls")); - - if (bPlaylist && !(m_s->nCLSwitches & CLSW_REGEXTPL)) { - continue; - } - - bAudioOnly = mf[i].IsAudioOnly(); - - if (((m_s->nCLSwitches & CLSW_REGEXTVID) && !bAudioOnly) || - ((m_s->nCLSwitches & CLSW_REGEXTAUD) && bAudioOnly) || - ((m_s->nCLSwitches & CLSW_REGEXTPL) && bPlaylist)) { - m_s->fileAssoc.Register(mf[i], true, false, true); - } - } - - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); - - return FALSE; - } - - if (m_s->nCLSwitches & CLSW_UNREGEXT) { // unregistered file types - CMediaFormats& mf = m_s->m_Formats; - mf.UpdateData(false); - - for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { - m_s->fileAssoc.Register(mf[i], false, false, false); - } - - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); - - return FALSE; - } - - if (m_s->nCLSwitches & CLSW_ICONSASSOC) { - CMediaFormats& mf = m_s->m_Formats; - mf.UpdateData(false); - - CAtlList registeredExts; - m_s->fileAssoc.GetAssociatedExtensionsFromRegistry(registeredExts); - - m_s->fileAssoc.ReAssocIcons(registeredExts); - - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); - - return FALSE; - } - - // Enable to open options with administrator privilege (for Vista UAC) - if (m_s->nCLSwitches & CLSW_ADMINOPTION) { - m_s->LoadSettings(); // read all settings. long time but not critical at this point - - switch (m_s->iAdminOption) { - case CPPageFormats::IDD: { - CPPageSheet options(ResStr(IDS_OPTIONS_CAPTION), nullptr, nullptr, m_s->iAdminOption); - options.LockPage(); - options.DoModal(); - } - break; - - default: - ASSERT(FALSE); - } - return FALSE; - } - - if (m_s->nCLSwitches & (CLSW_CONFIGLAVSPLITTER | CLSW_CONFIGLAVAUDIO | CLSW_CONFIGLAVVIDEO)) { - m_s->LoadSettings(); - if (m_s->nCLSwitches & CLSW_CONFIGLAVSPLITTER) { - CFGFilterLAVSplitter::ShowPropertyPages(NULL); - } - if (m_s->nCLSwitches & CLSW_CONFIGLAVAUDIO) { - CFGFilterLAVAudio::ShowPropertyPages(NULL); - } - if (m_s->nCLSwitches & CLSW_CONFIGLAVVIDEO) { - CFGFilterLAVVideo::ShowPropertyPages(NULL); - } - return FALSE; - } - - m_mutexOneInstance.Create(nullptr, TRUE, MPC_WND_CLASS_NAME); - - if (GetLastError() == ERROR_ALREADY_EXISTS) { - if ((m_s->nCLSwitches & CLSW_ADD) || !(m_s->GetAllowMultiInst() || m_s->nCLSwitches & CLSW_NEW || m_cmdln.IsEmpty())) { - DWORD res = WaitForSingleObject(m_mutexOneInstance.m_h, 5000); - if (res == WAIT_OBJECT_0 || res == WAIT_ABANDONED) { - HWND hWnd = ::FindWindow(MPC_WND_CLASS_NAME, nullptr); - if (hWnd) { - DWORD dwProcessId = 0; - if (GetWindowThreadProcessId(hWnd, &dwProcessId) && dwProcessId) { - VERIFY(AllowSetForegroundWindow(dwProcessId)); - } else { - ASSERT(FALSE); - } - if (!(m_s->nCLSwitches & CLSW_MINIMIZED) && IsIconic(hWnd) && - (!(m_s->nCLSwitches & CLSW_ADD) || m_s->nCLSwitches & CLSW_PLAY) //do not restore when adding to playlist of minimized player, unless also playing - ) { - ShowWindow(hWnd, SW_RESTORE); - } - if (SendCommandLine(hWnd)) { - m_mutexOneInstance.Close(); - return FALSE; - } - } - } - if ((m_s->nCLSwitches & CLSW_ADD)) { - ASSERT(FALSE); - return FALSE; // don't open new instance if SendCommandLine() failed - } - } - } - - if (!IsIniValid()) { - CRegKey key; - if (ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, _T("Software\\MPC-HC\\MPC-HC"))) { - if (RegQueryValueEx(key, _T("ExePath"), 0, nullptr, nullptr, nullptr) != ERROR_SUCCESS) { // First launch - // Move registry settings from the old to the new location - CRegKey oldKey; - if (ERROR_SUCCESS == oldKey.Open(HKEY_CURRENT_USER, _T("Software\\Gabest\\Media Player Classic"), KEY_READ)) { - SHCopyKey(oldKey, _T(""), key, 0); - } - } - - key.SetStringValue(_T("ExePath"), PathUtils::GetProgramPath(true)); - } - } - - m_s->UpdateSettings(); // update settings - m_s->LoadSettings(); // read settings - - #if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER - if (!m_s->bEnableCrashReporter) { - DisableCrashReporter(); - } - #endif - - m_AudioRendererDisplayName_CL = _T(""); - - if (!__super::InitInstance()) { - AfxMessageBox(_T("InitInstance failed!")); - return FALSE; - } - - AfxEnableControlContainer(); - - CMainFrame* pFrame; - try { - pFrame = DEBUG_NEW CMainFrame; - if (!pFrame || !pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, nullptr, nullptr)) { - MessageBox(nullptr, ResStr(IDS_FRAME_INIT_FAILED), m_pszAppName, MB_ICONERROR | MB_OK); - return FALSE; - } - } catch (...) { - return FALSE; - } - - m_pMainWnd = pFrame; - pFrame->m_controls.LoadState(); - CPoint borderAdjustDirection; - pFrame->SetDefaultWindowRect((m_s->nCLSwitches & CLSW_MONITOR) ? m_s->iMonitor : 0); - if (!m_s->slFiles.IsEmpty()) { - pFrame->m_controls.DelayShowNotLoaded(true); - } - pFrame->SetDefaultFullscreenState(); - pFrame->UpdateControlState(CMainFrame::UPDATE_CONTROLS_VISIBILITY); - pFrame->SetIcon(icon, TRUE); - - bool bRestoreLastWindowType = (m_s->fRememberWindowSize || m_s->fRememberWindowPos) && !m_s->fLastFullScreen && !m_s->fLaunchfullscreen; - bool bMinimized = (m_s->nCLSwitches & CLSW_MINIMIZED) || (bRestoreLastWindowType && m_s->nLastWindowType == SIZE_MINIMIZED); - bool bMaximized = bRestoreLastWindowType && m_s->nLastWindowType == SIZE_MAXIMIZED; - - if (bMinimized) { - m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWMINNOACTIVE : SW_SHOWMINIMIZED; - } else if (bMaximized) { - // Show maximized without focus is not supported nor make sense. - m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWNOACTIVATE : SW_SHOWMAXIMIZED; - } else { - m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL; - } - - pFrame->ActivateFrame(m_nCmdShow); - - if (AfxGetAppSettings().HasFixedWindowSize() && IsWindows8OrGreater()) {//make adjustments for drop shadow frame - CRect rect, frame; - pFrame->GetWindowRect(&rect); - CRect diff = pFrame->GetInvisibleBorderSize(); - if (!diff.IsRectNull()) { - rect.InflateRect(diff); - pFrame->SetWindowPos(nullptr, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER | SWP_NOACTIVATE); - } - } - - /* adipose 2019-11-12: - LoadPlayList this used to be performed inside OnCreate, - but due to all toolbars being hidden, EnsureVisible does not correctly - scroll to the current file in the playlist. We call after activating - the frame to fix this issue. - */ - pFrame->m_wndPlaylistBar.LoadPlaylist(pFrame->GetRecentFile()); - - pFrame->UpdateWindow(); - - - if (bMinimized && bMaximized) { - WINDOWPLACEMENT wp; - GetWindowPlacement(*pFrame, &wp); - wp.flags = WPF_RESTORETOMAXIMIZED; - SetWindowPlacement(*pFrame, &wp); - } - - pFrame->m_hAccelTable = m_s->hAccel; - m_s->WinLircClient.SetHWND(m_pMainWnd->m_hWnd); - if (m_s->fWinLirc) { - m_s->WinLircClient.Connect(m_s->strWinLircAddr); - } - m_s->UIceClient.SetHWND(m_pMainWnd->m_hWnd); - if (m_s->fUIce) { - m_s->UIceClient.Connect(m_s->strUIceAddr); - } - - if (UpdateChecker::IsAutoUpdateEnabled()) { - UpdateChecker::CheckForUpdate(true); - } - - if (!m_pMainWnd) return false; - - SendCommandLine(m_pMainWnd->m_hWnd); - RegisterHotkeys(); - - // set HIGH I/O Priority for better playback performance - if (m_hNTDLL) { - typedef NTSTATUS(WINAPI * FUNC_NTSETINFORMATIONPROCESS)(HANDLE, ULONG, PVOID, ULONG); - FUNC_NTSETINFORMATIONPROCESS NtSetInformationProcess = (FUNC_NTSETINFORMATIONPROCESS)GetProcAddress(m_hNTDLL, "NtSetInformationProcess"); - - if (NtSetInformationProcess && SetPrivilege(SE_INC_BASE_PRIORITY_NAME)) { - ULONG IoPriority = 3; - ULONG ProcessIoPriority = 0x21; - NTSTATUS NtStatus = NtSetInformationProcess(GetCurrentProcess(), ProcessIoPriority, &IoPriority, sizeof(ULONG)); - TRACE(_T("Set I/O Priority - %d\n"), NtStatus); - UNREFERENCED_PARAMETER(NtStatus); - } - } - - m_mutexOneInstance.Release(); - - CWebServer::Init(); - - if (m_s->fAssociatedWithIcons) { - m_s->fileAssoc.CheckIconsAssoc(); - } - - return TRUE; -} - -UINT CMPlayerCApp::GetRemoteControlCodeMicrosoft(UINT nInputcode, HRAWINPUT hRawInput) -{ - UINT dwSize = 0; - UINT nMceCmd = 0; - - // Support for MCE remote control - UINT ret = GetRawInputData(hRawInput, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); - if (ret == 0 && dwSize > 0) { - BYTE* pRawBuffer = DEBUG_NEW BYTE[dwSize]; - if (GetRawInputData(hRawInput, RID_INPUT, pRawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) != -1) { - RAWINPUT* raw = (RAWINPUT*)pRawBuffer; - if (raw->header.dwType == RIM_TYPEHID && raw->data.hid.dwSizeHid >= 3) { - nMceCmd = 0x10000 + (raw->data.hid.bRawData[1] | raw->data.hid.bRawData[2] << 8); - } - } - delete [] pRawBuffer; - } - - return nMceCmd; -} - -UINT CMPlayerCApp::GetRemoteControlCodeSRM7500(UINT nInputcode, HRAWINPUT hRawInput) -{ - UINT dwSize = 0; - UINT nMceCmd = 0; - - UINT ret = GetRawInputData(hRawInput, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); - if (ret == 0 && dwSize > 21) { - BYTE* pRawBuffer = DEBUG_NEW BYTE[dwSize]; - if (GetRawInputData(hRawInput, RID_INPUT, pRawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) != -1) { - RAWINPUT* raw = (RAWINPUT*)pRawBuffer; - - // data.hid.bRawData[21] set to one when key is pressed - if (raw->header.dwType == RIM_TYPEHID && raw->data.hid.dwSizeHid >= 22 && raw->data.hid.bRawData[21] == 1) { - // data.hid.bRawData[21] has keycode - switch (raw->data.hid.bRawData[20]) { - case 0x0033: - nMceCmd = MCE_DETAILS; - break; - case 0x0022: - nMceCmd = MCE_GUIDE; - break; - case 0x0036: - nMceCmd = MCE_MYTV; - break; - case 0x0026: - nMceCmd = MCE_RECORDEDTV; - break; - case 0x0005: - nMceCmd = MCE_RED; - break; - case 0x0002: - nMceCmd = MCE_GREEN; - break; - case 0x0045: - nMceCmd = MCE_YELLOW; - break; - case 0x0046: - nMceCmd = MCE_BLUE; - break; - case 0x000A: - nMceCmd = MCE_MEDIA_PREVIOUSTRACK; - break; - case 0x004A: - nMceCmd = MCE_MEDIA_NEXTTRACK; - break; - } - } - } - delete [] pRawBuffer; - } - - return nMceCmd; -} - -void CMPlayerCApp::RegisterHotkeys() -{ - CAutoVectorPtr inputDeviceList; - UINT nInputDeviceCount = 0, nErrCode; - RID_DEVICE_INFO deviceInfo; - RAWINPUTDEVICE MCEInputDevice[] = { - // usUsagePage usUsage dwFlags hwndTarget - { 0xFFBC, 0x88, 0, nullptr}, - { 0x000C, 0x01, 0, nullptr}, - { 0x000C, 0x80, 0, nullptr} - }; - - // Register MCE Remote Control raw input - for (unsigned int i = 0; i < _countof(MCEInputDevice); i++) { - MCEInputDevice[i].hwndTarget = m_pMainWnd->m_hWnd; - } - - // Get the size of the device list - nErrCode = GetRawInputDeviceList(nullptr, &nInputDeviceCount, sizeof(RAWINPUTDEVICELIST)); - inputDeviceList.Attach(DEBUG_NEW RAWINPUTDEVICELIST[nInputDeviceCount]); - if (nErrCode == UINT(-1) || !nInputDeviceCount || !inputDeviceList) { - ASSERT(nErrCode != UINT(-1)); - return; - } - - nErrCode = GetRawInputDeviceList(inputDeviceList, &nInputDeviceCount, sizeof(RAWINPUTDEVICELIST)); - if (nErrCode == UINT(-1)) { - ASSERT(FALSE); - return; - } - - for (UINT i = 0; i < nInputDeviceCount; i++) { - UINT nTemp = deviceInfo.cbSize = sizeof(deviceInfo); - - if (GetRawInputDeviceInfo(inputDeviceList[i].hDevice, RIDI_DEVICEINFO, &deviceInfo, &nTemp) > 0) { - if (deviceInfo.hid.dwVendorId == 0x00000471 && // Philips HID vendor id - deviceInfo.hid.dwProductId == 0x00000617) { // IEEE802.15.4 RF Dongle (SRM 7500) - MCEInputDevice[0].usUsagePage = deviceInfo.hid.usUsagePage; - MCEInputDevice[0].usUsage = deviceInfo.hid.usUsage; - GetRemoteControlCode = GetRemoteControlCodeSRM7500; - } - } - } - - RegisterRawInputDevices(MCEInputDevice, _countof(MCEInputDevice), sizeof(RAWINPUTDEVICE)); - - if (m_s->fGlobalMedia) { - POSITION pos = m_s->wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = m_s->wmcmds.GetNext(pos); - if (wc.appcmd != 0) { - UINT vkappcmd = GetVKFromAppCommand(wc.appcmd); - if (vkappcmd > 0) { - RegisterHotKey(m_pMainWnd->m_hWnd, wc.appcmd, 0, vkappcmd); - } - } - } - } -} - -void CMPlayerCApp::UnregisterHotkeys() -{ - if (m_s->fGlobalMedia) { - POSITION pos = m_s->wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = m_s->wmcmds.GetNext(pos); - if (wc.appcmd != 0) { - UnregisterHotKey(m_pMainWnd->m_hWnd, wc.appcmd); - } - } - } -} - -UINT CMPlayerCApp::GetVKFromAppCommand(UINT nAppCommand) -{ - // Note: Only a subset of AppCommands have a VirtualKey - switch (nAppCommand) { - case APPCOMMAND_MEDIA_PLAY_PAUSE: - return VK_MEDIA_PLAY_PAUSE; - case APPCOMMAND_MEDIA_STOP: - return VK_MEDIA_STOP; - case APPCOMMAND_MEDIA_NEXTTRACK: - return VK_MEDIA_NEXT_TRACK; - case APPCOMMAND_MEDIA_PREVIOUSTRACK: - return VK_MEDIA_PREV_TRACK; - case APPCOMMAND_VOLUME_DOWN: - return VK_VOLUME_DOWN; - case APPCOMMAND_VOLUME_UP: - return VK_VOLUME_UP; - case APPCOMMAND_VOLUME_MUTE: - return VK_VOLUME_MUTE; - case APPCOMMAND_LAUNCH_MEDIA_SELECT: - return VK_LAUNCH_MEDIA_SELECT; - case APPCOMMAND_BROWSER_BACKWARD: - return VK_BROWSER_BACK; - case APPCOMMAND_BROWSER_FORWARD: - return VK_BROWSER_FORWARD; - case APPCOMMAND_BROWSER_REFRESH: - return VK_BROWSER_REFRESH; - case APPCOMMAND_BROWSER_STOP: - return VK_BROWSER_STOP; - case APPCOMMAND_BROWSER_SEARCH: - return VK_BROWSER_SEARCH; - case APPCOMMAND_BROWSER_FAVORITES: - return VK_BROWSER_FAVORITES; - case APPCOMMAND_BROWSER_HOME: - return VK_BROWSER_HOME; - case APPCOMMAND_LAUNCH_APP1: - return VK_LAUNCH_APP1; - case APPCOMMAND_LAUNCH_APP2: - return VK_LAUNCH_APP2; - } - - return 0; -} - -int CMPlayerCApp::ExitInstance() -{ - // We might be exiting before m_s is initialized. - if (m_s) { - m_s->SaveSettings(); - m_s = nullptr; - } - - CMPCPngImage::CleanUp(); - - MH_Uninitialize(); - - OleUninitialize(); - - return CWinAppEx::ExitInstance(); -} - -BOOL CMPlayerCApp::SaveAllModified() -{ - // CWinApp::SaveAllModified - // Called by the framework to save all documents - // when the application's main frame window is to be closed, - // or through a WM_QUERYENDSESSION message. - if (m_s && !m_fClosingState) { - if (auto pMainFrame = AfxFindMainFrame()) { - if (pMainFrame->GetLoadState() != MLS::CLOSED) { - pMainFrame->CloseMedia(); - } - } - } - - return TRUE; -} - -// CMPlayerCApp message handlers - -BEGIN_MESSAGE_MAP(CMPlayerCApp, CWinAppEx) - ON_COMMAND(ID_HELP_ABOUT, OnAppAbout) - ON_COMMAND(ID_FILE_EXIT, OnFileExit) - ON_COMMAND(ID_HELP_SHOWCOMMANDLINESWITCHES, OnHelpShowcommandlineswitches) -END_MESSAGE_MAP() - -void CMPlayerCApp::OnAppAbout() -{ - CAboutDlg aboutDlg; - aboutDlg.DoModal(); -} - -void CMPlayerCApp::SetClosingState() -{ - m_fClosingState = true; -#if USE_DRDUMP_CRASH_REPORTER & (MPC_VERSION_REV < 20) - DisableCrashReporter(); -#endif -} - -void CMPlayerCApp::OnFileExit() -{ - OnAppExit(); -} - -void CMPlayerCApp::OnHelpShowcommandlineswitches() -{ - ShowCmdlnSwitches(); -} - -// CRemoteCtrlClient - -CRemoteCtrlClient::CRemoteCtrlClient() - : m_pWnd(nullptr) - , m_nStatus(DISCONNECTED) -{ -} - -void CRemoteCtrlClient::SetHWND(HWND hWnd) -{ - CAutoLock cAutoLock(&m_csLock); - - m_pWnd = CWnd::FromHandle(hWnd); -} - -void CRemoteCtrlClient::Connect(CString addr) -{ - CAutoLock cAutoLock(&m_csLock); - - if (m_nStatus == CONNECTING && m_addr == addr) { - TRACE(_T("CRemoteCtrlClient (Connect): already connecting to %s\n"), addr.GetString()); - return; - } - - if (m_nStatus == CONNECTED && m_addr == addr) { - TRACE(_T("CRemoteCtrlClient (Connect): already connected to %s\n"), addr.GetString()); - return; - } - - m_nStatus = CONNECTING; - - TRACE(_T("CRemoteCtrlClient (Connect): connecting to %s\n"), addr.GetString()); - - Close(); - - Create(); - - CString ip = addr.Left(addr.Find(':') + 1).TrimRight(':'); - int port = _tcstol(addr.Mid(addr.Find(':') + 1), nullptr, 10); - - __super::Connect(ip, port); - - m_addr = addr; -} - -void CRemoteCtrlClient::DisConnect() -{ - CAutoLock cAutoLock(&m_csLock); - - ShutDown(2); - Close(); -} - -void CRemoteCtrlClient::OnConnect(int nErrorCode) -{ - CAutoLock cAutoLock(&m_csLock); - - m_nStatus = (nErrorCode == 0 ? CONNECTED : DISCONNECTED); - - TRACE(_T("CRemoteCtrlClient (OnConnect): %d\n"), nErrorCode); -} - -void CRemoteCtrlClient::OnClose(int nErrorCode) -{ - CAutoLock cAutoLock(&m_csLock); - - if (m_hSocket != INVALID_SOCKET && m_nStatus == CONNECTED) { - TRACE(_T("CRemoteCtrlClient (OnClose): connection lost\n")); - } - - m_nStatus = DISCONNECTED; - - TRACE(_T("CRemoteCtrlClient (OnClose): %d\n"), nErrorCode); -} - -void CRemoteCtrlClient::OnReceive(int nErrorCode) -{ - if (nErrorCode != 0 || !m_pWnd) { - return; - } - - CStringA str; - int ret = Receive(str.GetBuffer(256), 255, 0); - if (ret <= 0) { - return; - } - str.ReleaseBuffer(ret); - - TRACE(_T("CRemoteCtrlClient (OnReceive): %S\n"), str.GetString()); - - OnCommand(str); - - __super::OnReceive(nErrorCode); -} - -void CRemoteCtrlClient::ExecuteCommand(CStringA cmd, int repcnt) -{ - cmd.Trim(); - if (cmd.IsEmpty()) { - return; - } - cmd.Replace(' ', '_'); - - const CAppSettings& s = AfxGetAppSettings(); - - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - if ((repcnt == 0 && wc.rmrepcnt == 0 || wc.rmrepcnt > 0 && (repcnt % wc.rmrepcnt) == 0) - && (wc.rmcmd.CompareNoCase(cmd) == 0 || wc.cmd == (WORD)strtol(cmd, nullptr, 10))) { - CAutoLock cAutoLock(&m_csLock); - TRACE(_T("CRemoteCtrlClient (calling command): %s\n"), wc.GetName().GetString()); - m_pWnd->SendMessage(WM_COMMAND, wc.cmd); - break; - } - } -} - -// CWinLircClient - -CWinLircClient::CWinLircClient() -{ -} - -void CWinLircClient::OnCommand(CStringA str) -{ - TRACE(_T("CWinLircClient (OnCommand): %S\n"), str.GetString()); - - int i = 0, j = 0, repcnt = 0; - for (CStringA token = str.Tokenize(" ", i); - !token.IsEmpty(); - token = str.Tokenize(" ", i), j++) { - if (j == 1) { - repcnt = strtol(token, nullptr, 16); - } else if (j == 2) { - ExecuteCommand(token, repcnt); - } - } -} - -// CUIceClient - -CUIceClient::CUIceClient() -{ -} - -void CUIceClient::OnCommand(CStringA str) -{ - TRACE(_T("CUIceClient (OnCommand): %S\n"), str.GetString()); - - CStringA cmd; - int i = 0, j = 0; - for (CStringA token = str.Tokenize("|", i); - !token.IsEmpty(); - token = str.Tokenize("|", i), j++) { - if (j == 0) { - cmd = token; - } else if (j == 1) { - ExecuteCommand(cmd, strtol(token, nullptr, 16)); - } - } -} - -// CMPlayerCApp continuation - -COLORPROPERTY_RANGE* CMPlayerCApp::GetColorControl(ControlType nFlag) -{ - switch (nFlag) { - case ProcAmp_Brightness: - return &m_ColorControl[0]; - case ProcAmp_Contrast: - return &m_ColorControl[1]; - case ProcAmp_Hue: - return &m_ColorControl[2]; - case ProcAmp_Saturation: - return &m_ColorControl[3]; - } - return nullptr; -} - -void CMPlayerCApp::ResetColorControlRange() -{ - m_ColorControl[0].dwProperty = ProcAmp_Brightness; - m_ColorControl[0].MinValue = -100; - m_ColorControl[0].MaxValue = 100; - m_ColorControl[0].DefaultValue = 0; - m_ColorControl[0].StepSize = 1; - m_ColorControl[1].dwProperty = ProcAmp_Contrast; - m_ColorControl[1].MinValue = -100; - m_ColorControl[1].MaxValue = 100; - m_ColorControl[1].DefaultValue = 0; - m_ColorControl[1].StepSize = 1; - m_ColorControl[2].dwProperty = ProcAmp_Hue; - m_ColorControl[2].MinValue = -180; - m_ColorControl[2].MaxValue = 180; - m_ColorControl[2].DefaultValue = 0; - m_ColorControl[2].StepSize = 1; - m_ColorControl[3].dwProperty = ProcAmp_Saturation; - m_ColorControl[3].MinValue = -100; - m_ColorControl[3].MaxValue = 100; - m_ColorControl[3].DefaultValue = 0; - m_ColorControl[3].StepSize = 1; -} - -void CMPlayerCApp::UpdateColorControlRange(bool isEVR) -{ - if (isEVR) { - // Brightness - m_ColorControl[0].MinValue = FixedToInt(m_EVRColorControl[0].MinValue); - m_ColorControl[0].MaxValue = FixedToInt(m_EVRColorControl[0].MaxValue); - m_ColorControl[0].DefaultValue = FixedToInt(m_EVRColorControl[0].DefaultValue); - m_ColorControl[0].StepSize = std::max(1, FixedToInt(m_EVRColorControl[0].StepSize)); - // Contrast - m_ColorControl[1].MinValue = FixedToInt(m_EVRColorControl[1].MinValue, 100) - 100; - m_ColorControl[1].MaxValue = FixedToInt(m_EVRColorControl[1].MaxValue, 100) - 100; - m_ColorControl[1].DefaultValue = FixedToInt(m_EVRColorControl[1].DefaultValue, 100) - 100; - m_ColorControl[1].StepSize = std::max(1, FixedToInt(m_EVRColorControl[1].StepSize, 100)); - // Hue - m_ColorControl[2].MinValue = FixedToInt(m_EVRColorControl[2].MinValue); - m_ColorControl[2].MaxValue = FixedToInt(m_EVRColorControl[2].MaxValue); - m_ColorControl[2].DefaultValue = FixedToInt(m_EVRColorControl[2].DefaultValue); - m_ColorControl[2].StepSize = std::max(1, FixedToInt(m_EVRColorControl[2].StepSize)); - // Saturation - m_ColorControl[3].MinValue = FixedToInt(m_EVRColorControl[3].MinValue, 100) - 100; - m_ColorControl[3].MaxValue = FixedToInt(m_EVRColorControl[3].MaxValue, 100) - 100; - m_ColorControl[3].DefaultValue = FixedToInt(m_EVRColorControl[3].DefaultValue, 100) - 100; - m_ColorControl[3].StepSize = std::max(1, FixedToInt(m_EVRColorControl[3].StepSize, 100)); - } else { - // Brightness - m_ColorControl[0].MinValue = (int)floor(m_VMR9ColorControl[0].MinValue + 0.5); - m_ColorControl[0].MaxValue = (int)floor(m_VMR9ColorControl[0].MaxValue + 0.5); - m_ColorControl[0].DefaultValue = (int)floor(m_VMR9ColorControl[0].DefaultValue + 0.5); - m_ColorControl[0].StepSize = std::max(1, (int)(m_VMR9ColorControl[0].StepSize + 0.5)); - // Contrast - if (*(int*)&m_VMR9ColorControl[1].MinValue == 1036830720) { - m_VMR9ColorControl[1].MinValue = 0.11f; //fix NVIDIA bug - } - m_ColorControl[1].MinValue = (int)floor(m_VMR9ColorControl[1].MinValue * 100 + 0.5) - 100; - m_ColorControl[1].MaxValue = (int)floor(m_VMR9ColorControl[1].MaxValue * 100 + 0.5) - 100; - m_ColorControl[1].DefaultValue = (int)floor(m_VMR9ColorControl[1].DefaultValue * 100 + 0.5) - 100; - m_ColorControl[1].StepSize = std::max(1, (int)(m_VMR9ColorControl[1].StepSize * 100 + 0.5)); - // Hue - m_ColorControl[2].MinValue = (int)floor(m_VMR9ColorControl[2].MinValue + 0.5); - m_ColorControl[2].MaxValue = (int)floor(m_VMR9ColorControl[2].MaxValue + 0.5); - m_ColorControl[2].DefaultValue = (int)floor(m_VMR9ColorControl[2].DefaultValue + 0.5); - m_ColorControl[2].StepSize = std::max(1, (int)(m_VMR9ColorControl[2].StepSize + 0.5)); - // Saturation - m_ColorControl[3].MinValue = (int)floor(m_VMR9ColorControl[3].MinValue * 100 + 0.5) - 100; - m_ColorControl[3].MaxValue = (int)floor(m_VMR9ColorControl[3].MaxValue * 100 + 0.5) - 100; - m_ColorControl[3].DefaultValue = (int)floor(m_VMR9ColorControl[3].DefaultValue * 100 + 0.5) - 100; - m_ColorControl[3].StepSize = std::max(1, (int)(m_VMR9ColorControl[3].StepSize * 100 + 0.5)); - } - - // Brightness - if (m_ColorControl[0].MinValue < -100) { - m_ColorControl[0].MinValue = -100; - } - if (m_ColorControl[0].MaxValue > 100) { - m_ColorControl[0].MaxValue = 100; - } - // Contrast - if (m_ColorControl[1].MinValue == m_ColorControl[1].MaxValue) { // when ProcAmp is unsupported - m_ColorControl[1].MinValue = m_ColorControl[1].MaxValue = m_ColorControl[1].DefaultValue = 0; - } - if (m_ColorControl[1].MinValue < -100) { - m_ColorControl[1].MinValue = -100; - } - if (m_ColorControl[1].MaxValue > 100) { - m_ColorControl[1].MaxValue = 100; - } - // Hue - if (m_ColorControl[2].MinValue < -180) { - m_ColorControl[2].MinValue = -180; - } - if (m_ColorControl[2].MaxValue > 180) { - m_ColorControl[2].MaxValue = 180; - } - // Saturation - if (m_ColorControl[3].MinValue == m_ColorControl[3].MaxValue) { // when ProcAmp is unsupported - m_ColorControl[3].MinValue = m_ColorControl[3].MaxValue = m_ColorControl[3].DefaultValue = 0; - } - if (m_ColorControl[3].MinValue < -100) { - m_ColorControl[3].MinValue = -100; - } - if (m_ColorControl[3].MaxValue > 100) { - m_ColorControl[3].MaxValue = 100; - } -} - -VMR9ProcAmpControlRange* CMPlayerCApp::GetVMR9ColorControl(ControlType nFlag) -{ - switch (nFlag) { - case ProcAmp_Brightness: - return &m_VMR9ColorControl[0]; - case ProcAmp_Contrast: - return &m_VMR9ColorControl[1]; - case ProcAmp_Hue: - return &m_VMR9ColorControl[2]; - case ProcAmp_Saturation: - return &m_VMR9ColorControl[3]; - } - return nullptr; -} - -DXVA2_ValueRange* CMPlayerCApp::GetEVRColorControl(ControlType nFlag) -{ - switch (nFlag) { - case ProcAmp_Brightness: - return &m_EVRColorControl[0]; - case ProcAmp_Contrast: - return &m_EVRColorControl[1]; - case ProcAmp_Hue: - return &m_EVRColorControl[2]; - case ProcAmp_Saturation: - return &m_EVRColorControl[3]; - } - return nullptr; -} - -void CMPlayerCApp::RunAsAdministrator(LPCTSTR strCommand, LPCTSTR strArgs, bool bWaitProcess) -{ - SHELLEXECUTEINFO execinfo; - ZeroMemory(&execinfo, sizeof(execinfo)); - execinfo.lpFile = strCommand; - execinfo.cbSize = sizeof(execinfo); - execinfo.lpVerb = _T("runas"); - execinfo.fMask = SEE_MASK_NOCLOSEPROCESS; - execinfo.nShow = SW_SHOWDEFAULT; - execinfo.lpParameters = strArgs; - - ShellExecuteEx(&execinfo); - - if (bWaitProcess) { - WaitForSingleObject(execinfo.hProcess, INFINITE); - } -} - +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "AboutDlg.h" +#include "CmdLineHelpDlg.h" +#include "CrashReporter.h" +#include "DSUtil.h" +#include "FakeFilterMapper2.h" +#include "FileAssoc.h" +#include "FileVersionInfo.h" +#include "Ifo.h" +#include "MainFrm.h" +#include "MhookHelper.h" +#include "PPageFormats.h" +#include "PPageSheet.h" +#include "PathUtils.h" +#include "Struct.h" +#include "UpdateChecker.h" +#include "WebServer.h" +#include "WinAPIUtils.h" +#include "mpc-hc_config.h" +#include "winddk/ntddcdvd.h" +#include +#include +#include +#include +#include "ExceptionHandler.h" +#include "FGFilterLAV.h" +#include "CMPCThemeMsgBox.h" +#include "version.h" +#include "psapi.h" + +HICON LoadIcon(CString fn, bool bSmallIcon, DpiHelper* pDpiHelper/* = nullptr*/) +{ + if (fn.IsEmpty()) { + return nullptr; + } + + CString ext = fn.Left(fn.Find(_T("://")) + 1).TrimRight(':'); + if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) { + ext = _T(".") + fn.Mid(fn.ReverseFind('.') + 1); + } + + CSize size(bSmallIcon ? GetSystemMetrics(SM_CXSMICON) : GetSystemMetrics(SM_CXICON), + bSmallIcon ? GetSystemMetrics(SM_CYSMICON) : GetSystemMetrics(SM_CYICON)); + + if (pDpiHelper) { + size.cx = pDpiHelper->ScaleSystemToOverrideX(size.cx); + size.cy = pDpiHelper->ScaleSystemToOverrideY(size.cy); + } + + typedef HRESULT(WINAPI * LIWSD)(HINSTANCE, PCWSTR, int, int, HICON*); + auto loadIcon = [&size](PCWSTR pszName) { + LIWSD pLIWSD = (LIWSD)GetProcAddress(GetModuleHandle(_T("comctl32.dll")), "LoadIconWithScaleDown"); + HICON ret = nullptr; + if (pLIWSD) { + pLIWSD(AfxGetInstanceHandle(), pszName, size.cx, size.cy, &ret); + } else { + ret = (HICON)LoadImage(AfxGetInstanceHandle(), pszName, IMAGE_ICON, size.cx, size.cy, 0); + } + return ret; + }; + + if (!ext.CompareNoCase(_T(".ifo"))) { + if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_DVD))) { + return hIcon; + } + } + + if (!ext.CompareNoCase(_T(".cda"))) { + if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_AUDIOCD))) { + return hIcon; + } + } + + if (!ext.CompareNoCase(_T(".unknown"))) { + if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_UNKNOWN))) { + return hIcon; + } + } + + do { + CRegKey key; + TCHAR buff[256]; + ULONG len; + + auto openRegKey = [&](HKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValueName) { + if (ERROR_SUCCESS == key.Open(hKeyParent, lpszKeyName, KEY_READ)) { + len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + CString progId; + + if (ERROR_SUCCESS == key.QueryStringValue(lpszValueName, buff, &len) && !(progId = buff).Trim().IsEmpty()) { + return (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, progId + _T("\\DefaultIcon"), KEY_READ)); + } + } + return false; + }; + + if (!openRegKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\") + ext + _T("\\UserChoice"), _T("Progid")) + && !openRegKey(HKEY_CLASSES_ROOT, ext, nullptr) + && ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, ext + _T("\\DefaultIcon"), KEY_READ)) { + break; + } + + CString icon; + len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len) || (icon = buff).Trim().IsEmpty()) { + break; + } + + int i = icon.ReverseFind(','); + if (i < 0) { + break; + } + + int id = 0; + if (_stscanf_s(icon.Mid(i + 1), _T("%d"), &id) != 1) { + break; + } + + icon = icon.Left(i); + icon.Trim(_T(" \\\"")); + + HICON hIcon = nullptr; + UINT cnt = bSmallIcon + ? ExtractIconEx(icon, id, nullptr, &hIcon, 1) + : ExtractIconEx(icon, id, &hIcon, nullptr, 1); + if (hIcon && cnt == 1) { + return hIcon; + } + } while (0); + + return loadIcon(MAKEINTRESOURCE(IDI_UNKNOWN)); +} + +bool LoadType(CString fn, CString& type) +{ + bool found = false; + + if (!fn.IsEmpty()) { + CString ext = fn.Left(fn.Find(_T("://")) + 1).TrimRight(':'); + if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) { + ext = _T(".") + fn.Mid(fn.ReverseFind('.') + 1); + } + + // Try MPC-HC's internal formats list + const CMediaFormatCategory* mfc = AfxGetAppSettings().m_Formats.FindMediaByExt(ext); + + if (mfc != nullptr) { + found = true; + type = mfc->GetDescription(); + } else { // Fallback to registry + CRegKey key; + TCHAR buff[256]; + ULONG len; + + CString tmp = _T(""); + CString mplayerc_ext = _T("mplayerc") + ext; + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, mplayerc_ext)) { + tmp = mplayerc_ext; + } + + if (!tmp.IsEmpty() || ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, ext)) { + found = true; + + if (tmp.IsEmpty()) { + tmp = ext; + } + + while (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, tmp)) { + len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + + if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len)) { + break; + } + + CString str(buff); + str.Trim(); + + if (str.IsEmpty() || str == tmp) { + break; + } + + tmp = str; + } + + type = tmp; + } + } + } + + return found; +} + +bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype) +{ + str.Empty(); + HRSRC hrsrc = FindResource(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(resid), restype); + if (!hrsrc) { + return false; + } + HGLOBAL hGlobal = LoadResource(AfxGetApp()->m_hInstance, hrsrc); + if (!hGlobal) { + return false; + } + DWORD size = SizeofResource(AfxGetApp()->m_hInstance, hrsrc); + if (!size) { + return false; + } + memcpy(str.GetBufferSetLength(size), LockResource(hGlobal), size); + return true; +} + +static bool FindRedir(const CUrl& src,const CString& body, CAtlList& urls, const std::vector& res) +{ + bool bDetectHLS = false; + for (const auto re : res) { + std::wcmatch mc; + + for (LPCTSTR s = body; std::regex_search(s, mc, re); s += mc.position() + mc.length()) { + CString url = mc[mc.size() - 1].str().c_str(); + url.Trim(); + + if (url.CompareNoCase(_T("asf path")) == 0) { + continue; + } + if (url.Find(_T("EXTM3U")) == 0 || url.Find(_T("#EXTINF")) == 0) { + bDetectHLS = true; + continue; + } + // Detect HTTP Live Streaming and let the source filter handle that + if (bDetectHLS + && (url.Find(_T("EXT-X-STREAM-INF:")) != -1 + || url.Find(_T("EXT-X-TARGETDURATION:")) != -1 + || url.Find(_T("EXT-X-MEDIA-SEQUENCE:")) != -1)) { + urls.RemoveAll(); + break; + } + + CUrl dst; + dst.CrackUrl(CString(url)); + if (_tcsicmp(src.GetSchemeName(), dst.GetSchemeName()) + || _tcsicmp(src.GetHostName(), dst.GetHostName()) + || _tcsicmp(src.GetUrlPath(), dst.GetUrlPath())) { + urls.AddTail(url); + } else { + // recursive + urls.RemoveAll(); + break; + } + } + } + + return !urls.IsEmpty(); +} + +static bool FindRedir(const CString& fn, CAtlList& fns, const std::vector& res) +{ + CString body; + + CTextFile f(CTextFile::UTF8); + if (f.Open(fn)) { + int i = 0; + for (CString tmp; i < 10000 && f.ReadString(tmp); body += tmp + '\n', ++i) { + ; + } + } + + CString dir = fn.Left(std::max(fn.ReverseFind('/'), fn.ReverseFind('\\')) + 1); // "ReverseFindOneOf" + + for (const auto re : res) { + std::wcmatch mc; + + for (LPCTSTR s = body; std::regex_search(s, mc, re); s += mc.position() + mc.length()) { + CString fn2 = mc[mc.size() - 1].str().c_str(); + fn2.Trim(); + + if (!fn2.CompareNoCase(_T("asf path"))) { + continue; + } + if (fn2.Find(_T("EXTM3U")) == 0 || fn2.Find(_T("#EXTINF")) == 0) { + continue; + } + + if (fn2.Find(_T(":")) < 0 && fn2.Find(_T("\\\\")) != 0 && fn2.Find(_T("//")) != 0) { + CPath p; + p.Combine(dir, fn2); + fn2 = (LPCTSTR)p; + } + + if (!fn2.CompareNoCase(fn)) { + continue; + } + + fns.AddTail(fn2); + } + } + + return !fns.IsEmpty(); +} + + +CString GetContentType(CString fn, CAtlList* redir) +{ + fn.Trim(); + if (fn.IsEmpty()) { + return ""; + } + + CUrl url; + CString content, body; + BOOL url_fail = false; + BOOL ishttp = false; + BOOL parsefile = false; + BOOL isurl = PathUtils::IsURL(fn); + + // Get content type based on the URI scheme + if (isurl) { + url.CrackUrl(fn); + + if (_tcsicmp(url.GetSchemeName(), _T("pnm")) == 0) { + return "audio/x-pn-realaudio"; + } + if (_tcsicmp(url.GetSchemeName(), _T("mms")) == 0) { + return "video/x-ms-asf"; + } + if (_tcsicmp(url.GetSchemeName(), _T("http")) == 0 || _tcsicmp(url.GetSchemeName(), _T("https")) == 0) { + ishttp = true; + } else { + return ""; + } + } + + CString ext = CPath(fn).GetExtension().MakeLower(); + int p = ext.FindOneOf(_T("?#")); + if (p > 0) { + ext = ext.Left(p); + } + + // no further analysis needed if known audio/video extension and points directly to a file + if (!ext.IsEmpty()) { + if (ext == _T(".mp4") || ext == _T(".m4v") || ext == _T(".mov") || ext == _T(".mkv") || ext == _T(".webm") || ext == _T(".avi") || ext == _T(".wmv") || ext == _T(".mpg") || ext == _T(".mpeg") || ext == _T(".flv") || ext == _T(".ogm") || ext == _T(".m2ts") || ext == _T(".ts")) { + content = _T("video"); + } else if (ext == _T(".mp3") || ext == _T(".m4a") || ext == _T(".aac") || ext == _T(".flac") || ext == _T(".mka") || ext == _T(".ogg") || ext == _T(".opus")) { + content = _T("audio"); + } else if (ext == _T(".mpcpl")) { + content = _T("application/x-mpc-playlist"); + } else if (ext == _T(".m3u") || ext == _T(".m3u8")) { + content = _T("audio/x-mpegurl"); + } else if (ext == _T(".bdmv")) { + content = _T("application/x-bdmv-playlist"); + } else if (ext == _T(".cue")) { + content = _T("application/x-cue-sheet"); + } else if (ext == _T(".swf")) { + content = _T("application/x-shockwave-flash"); + } + + if (!content.IsEmpty()) { + return content; + } + } + + // Get content type by getting the header response from server + if (ishttp) { + CInternetSession internet; + internet.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 5000); + CString headers = _T("User-Agent: MPC-HC"); + CHttpFile* httpFile = NULL; + try { + httpFile = (CHttpFile*)internet.OpenURL(fn, + 1, + INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, + headers, + DWORD(-1)); + } + catch (CInternetException* pEx) + { + pEx->Delete(); + url_fail = true; // Timeout has most likely occured, server unreachable + return content; + } + + if (httpFile) { + //CString strContentType; + //httpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS, strContentType); // Check also HTTP_QUERY_RAW_HEADERS_CRLF + //DWORD dw = 8192; // Arbitrary 8192 char length for Url (should handle most cases) + //CString urlredirect; // Retrieve the new Url in case we encountered an HTTP redirection (HTTP 302 code) + //httpFile->QueryOption(INTERNET_OPTION_URL, urlredirect.GetBuffer(8192), &dw); + DWORD dwStatus; + httpFile->QueryInfoStatusCode(dwStatus); + switch (dwStatus) { + case HTTP_STATUS_OK: // 200 request completed + case HTTP_STATUS_CREATED: // 201 object created, reason = new URI + case HTTP_STATUS_ACCEPTED: // 202 async completion (TBS) + case HTTP_STATUS_PARTIAL: // 203 partial completion + case HTTP_STATUS_NO_CONTENT: // 204 no info to return + case HTTP_STATUS_RESET_CONTENT: // 205 request completed, but clear form + case HTTP_STATUS_PARTIAL_CONTENT: // 206 partial GET furfilled + case HTTP_STATUS_AMBIGUOUS: // 300 server couldn't decide what to return + case HTTP_STATUS_MOVED: // 301 object permanently moved + case HTTP_STATUS_REDIRECT: // 302 object temporarily moved + case HTTP_STATUS_REDIRECT_METHOD: // 303 redirection w/ new access method + case HTTP_STATUS_NOT_MODIFIED: // 304 if-modified-since was not modified + case HTTP_STATUS_USE_PROXY: // 305 redirection to proxy, location header specifies proxy to use + case HTTP_STATUS_REDIRECT_KEEP_VERB: // 307 HTTP/1.1: keep same verb + case 308/*HTTP_STATUS_PERMANENT_REDIRECT*/: // 308 Object permanently moved keep verb + break; + default: + //CString strStatus; + //httpFile->QueryInfo(HTTP_QUERY_STATUS_TEXT, strStatus); // Status String - eg OK, Not Found + url_fail = true; + } + + if (url_fail) { + httpFile->Close(); // Close() isn't called by the destructor + delete httpFile; + return content; + } + + if (content.IsEmpty()) { + httpFile->QueryInfo(HTTP_QUERY_CONTENT_TYPE, content); // Content-Type - eg text/html + } + + long contentsize = 0; + CString contentlength = _T(""); + if (httpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, contentlength)) { + contentsize = _ttol(contentlength); + } + + // Partial download of response body to further identify content types + if (content.IsEmpty() && contentsize < 256*1024) { + UINT br = 0; + char buffer[513] = ""; + while (body.GetLength() < 256) { + br = httpFile->Read(buffer, 256); + if (br == 0) { + break; + } + buffer[br] = '\0'; + body += buffer; + } + if (body.GetLength() >= 8) { + BOOL exit = false; + if (!wcsncmp((LPCWSTR)body, _T(".ra"), 3)) { + content = _T("audio/x-pn-realaudio"); + exit = true; + } else if (!wcsncmp((LPCWSTR)body, _T(".RMF"), 4)) { + content = _T("audio/x-pn-realaudio"); + exit = true; + } + + if (exit) { + httpFile->Close(); + delete httpFile; + return content; + } + } + } + // Download larger piece of response body in case it's a playlist + if (redir && contentsize < 256*1024 && (content == _T("audio/x-scpls") || content == _T("audio/scpls") + || content == _T("video/x-ms-asf") || content == _T("text/plain") + || content == _T("application/octet-stream") || content == _T("application/pls+xml"))) { + UINT br = 0; + char buffer[513] = ""; + while (body.GetLength() < 64 * 1024) { // should be enough for a playlist... + br = httpFile->Read(buffer, 256); + if (br == 0) { + break; + } + buffer[br] = '\0'; + body += buffer; + } + } + + httpFile->Close(); + delete httpFile; + } + } + + // If content type is empty, plain text or octet-stream (weird server!) GUESS by extension if it exists..... + if (content.IsEmpty() || content == _T("text/plain") || content == _T("application/octet-stream")) { + if (ext == _T(".pls")) { + content = _T("audio/x-scpls"); + parsefile = true; + } else if (ext == _T(".asx")) { + content = _T("video/x-ms-asf"); + parsefile = true; + } else if (ext == _T(".ram")) { + content = _T("audio/x-pn-realaudio"); + parsefile = true; + } + } + + if (redir && !content.IsEmpty() && (isurl && !body.IsEmpty() || !isurl && parsefile)) { + std::vector res; + const std::wregex::flag_type reFlags = std::wregex::icase | std::wregex::optimize; + + if (content == _T("video/x-ms-asf")) { + // ...://..."/> + res.emplace_back(_T("[a-zA-Z]+://[^\n\">]*"), reFlags); + // Ref#n= ...://...\n + res.emplace_back(_T("Ref\\d+\\s*=\\s*[\"]*([a-zA-Z]+://[^\n\"]+)"), reFlags); + } + else if (content == _T("audio/x-scpls") || content == _T("audio/scpls") || content == _T("application/pls+xml")) { + // File1=...\n + res.emplace_back(_T("file\\d+\\s*=\\s*[\"]*([^\n\"]+)"), reFlags); + } + else if (content == _T("audio/x-pn-realaudio")) { + // rtsp://... + res.emplace_back(_T("rtsp://[^\n]+"), reFlags); + // http://... + res.emplace_back(_T("http://[^\n]+"), reFlags); + } + + if (res.size()) { + if (isurl) { + FindRedir(url, body, *redir, res); + } else { + FindRedir(fn, *redir, res); + } + } + } + + return content; +} + +WORD AssignedToCmd(UINT keyValue) +{ + if (keyValue == 0) { + ASSERT(false); + return 0; + } + + WORD assignTo = 0; + const CAppSettings& s = AfxGetAppSettings(); + + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos && !assignTo) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + + if (wc.key == keyValue) { + assignTo = wc.cmd; + } + } + + return assignTo; +} + +std::map GetAudioDeviceList() { + std::map devicelist; + BeginEnumSysDev(CLSID_AudioRendererCategory, pMoniker) { + CComHeapPtr olestr; + if (FAILED(pMoniker->GetDisplayName(0, 0, &olestr))) { + continue; + } + CStringW dispname(olestr); + CStringW friendlyname; + CComPtr pPB; + if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)))) { + CComVariant var; + if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + CStringW frname(var.bstrVal); + var.Clear(); + friendlyname = frname; + } + } else { + friendlyname = dispname; + } + devicelist.emplace(friendlyname, dispname); + } + EndEnumSysDev; + + return devicelist; +} + +void SetAudioRenderer(int AudioDevNo) +{ + CStringArray dispnames; + AfxGetMyApp()->m_AudioRendererDisplayName_CL = _T(""); + dispnames.Add(_T("")); + dispnames.Add(AUDRNDT_INTERNAL); + dispnames.Add(AUDRNDT_MPC); + int devcount = 3; + + std::map devicelist = GetAudioDeviceList(); + + for (auto it = devicelist.cbegin(); it != devicelist.cend(); it++) { + dispnames.Add((*it).second); + devcount++; + } + + dispnames.Add(AUDRNDT_NULL_COMP); + dispnames.Add(AUDRNDT_NULL_UNCOMP); + devcount += 2; + + if (AudioDevNo >= 1 && AudioDevNo <= devcount) { + AfxGetMyApp()->m_AudioRendererDisplayName_CL = dispnames[AudioDevNo - 1]; + } +} + +void SetHandCursor(HWND m_hWnd, UINT nID) +{ + SetClassLongPtr(GetDlgItem(m_hWnd, nID), GCLP_HCURSOR, (LONG_PTR)AfxGetApp()->LoadStandardCursor(IDC_HAND)); +} + +// CMPlayerCApp + +CMPlayerCApp::CMPlayerCApp() + : m_hNTDLL(nullptr) + , m_bDelayingIdle(false) + , m_bProfileInitialized(false) + , m_bQueuedProfileFlush(false) + , m_dwProfileLastAccessTick(0) + , m_fClosingState(false) + , m_bThemeLoaded(false) +{ + m_strVersion = FileVersionInfo::GetFileVersionStr(PathUtils::GetProgramPath(true)); + + ZeroMemory(&m_ColorControl, sizeof(m_ColorControl)); + ResetColorControlRange(); + + ZeroMemory(&m_VMR9ColorControl, sizeof(m_VMR9ColorControl)); + m_VMR9ColorControl[0].dwSize = sizeof(VMR9ProcAmpControlRange); + m_VMR9ColorControl[0].dwProperty = ProcAmpControl9_Brightness; + m_VMR9ColorControl[1].dwSize = sizeof(VMR9ProcAmpControlRange); + m_VMR9ColorControl[1].dwProperty = ProcAmpControl9_Contrast; + m_VMR9ColorControl[2].dwSize = sizeof(VMR9ProcAmpControlRange); + m_VMR9ColorControl[2].dwProperty = ProcAmpControl9_Hue; + m_VMR9ColorControl[3].dwSize = sizeof(VMR9ProcAmpControlRange); + m_VMR9ColorControl[3].dwProperty = ProcAmpControl9_Saturation; + + ZeroMemory(&m_EVRColorControl, sizeof(m_EVRColorControl)); + + GetRemoteControlCode = GetRemoteControlCodeMicrosoft; +} + +CMPlayerCApp::~CMPlayerCApp() +{ + if (m_hNTDLL) { + FreeLibrary(m_hNTDLL); + } + // Wait for any pending I/O operations to be canceled + while (WAIT_IO_COMPLETION == SleepEx(0, TRUE)); +} + +int CMPlayerCApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, + UINT nIDPrompt) +{ + if (AppIsThemeLoaded()) { + CWnd* pParentWnd = CWnd::GetActiveWindow(); + if (pParentWnd == NULL) { + pParentWnd = GetMainWnd(); + if (pParentWnd == NULL) { + return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt); + } else { + pParentWnd = pParentWnd->GetLastActivePopup(); + } + } + + CMPCThemeMsgBox dlgMessage(pParentWnd, lpszPrompt, _T(""), nType, + nIDPrompt); + + return (int)dlgMessage.DoModal(); + } else { + return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt); + } +} + +void CMPlayerCApp::DelayedIdle() +{ + m_bDelayingIdle = false; +} + +BOOL CMPlayerCApp::IsIdleMessage(MSG* pMsg) +{ + BOOL ret = __super::IsIdleMessage(pMsg); + if (ret && pMsg->message == WM_MOUSEMOVE) { + if (m_bDelayingIdle) { + ret = FALSE; + } else { + auto pMainFrm = AfxGetMainFrame(); + if (pMainFrm && m_pMainWnd) { + const unsigned uTimeout = 100; + // delay next WM_MOUSEMOVE initiated idle for uTimeout ms + // if there will be no WM_MOUSEMOVE messages, WM_TIMER will initiate the idle + pMainFrm->m_timerOneTime.Subscribe( + CMainFrame::TimerOneTimeSubscriber::DELAY_IDLE, std::bind(&CMPlayerCApp::DelayedIdle, this), uTimeout); + m_bDelayingIdle = true; + } + } + } + return ret; +} + +BOOL CMPlayerCApp::OnIdle(LONG lCount) +{ + BOOL ret = __super::OnIdle(lCount); + + if (!ret) { + FlushProfile(false); + } + + return ret; +} + +BOOL CMPlayerCApp::PumpMessage() +{ + return MsgWaitForMultipleObjectsEx(0, nullptr, INFINITE, QS_ALLINPUT, + MWMO_INPUTAVAILABLE | MWMO_ALERTABLE) == WAIT_IO_COMPLETION ? TRUE : __super::PumpMessage(); +} + +void CMPlayerCApp::ShowCmdlnSwitches() const +{ + CString cmdLine; + + if ((m_s->nCLSwitches & CLSW_UNRECOGNIZEDSWITCH) && __argc > 0) { + cmdLine = __targv[0]; + for (int i = 1; i < __argc; i++) { + cmdLine.AppendFormat(_T(" %s"), __targv[i]); + } + } + + CmdLineHelpDlg dlg(cmdLine); + dlg.DoModal(); +} + +CMPlayerCApp theApp; // The one and only CMPlayerCApp object + +HWND g_hWnd = nullptr; + +bool CMPlayerCApp::StoreSettingsToIni() +{ + std::lock_guard lock(m_profileMutex); + + CString ini = GetIniPath(); + free((void*)m_pszRegistryKey); + m_pszRegistryKey = nullptr; + free((void*)m_pszProfileName); + m_pszProfileName = _tcsdup(ini); + + return true; +} + +bool CMPlayerCApp::StoreSettingsToRegistry() +{ + std::lock_guard lock(m_profileMutex); + + free((void*)m_pszRegistryKey); + m_pszRegistryKey = nullptr; + + SetRegistryKey(_T("MPC-HC")); + + return true; +} + +CString CMPlayerCApp::GetIniPath() const +{ + CString path = PathUtils::GetProgramPath(true); + path = path.Left(path.ReverseFind('.') + 1) + _T("ini"); + return path; +} + +bool CMPlayerCApp::IsIniValid() const +{ + return PathUtils::Exists(GetIniPath()); +} + +bool CMPlayerCApp::GetAppSavePath(CString& path) +{ + if (IsIniValid()) { // If settings ini file found, store stuff in the same folder as the exe file + path = PathUtils::GetProgramPath(); + } else { + return GetAppDataPath(path); + } + + return true; +} + +bool CMPlayerCApp::GetAppDataPath(CString& path) +{ + path.Empty(); + + HRESULT hr = SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, 0, path.GetBuffer(MAX_PATH)); + path.ReleaseBuffer(); + if (FAILED(hr)) { + return false; + } + CPath p; + p.Combine(path, _T("MPC-HC")); + path = (LPCTSTR)p; + + return true; +} + +bool CMPlayerCApp::ChangeSettingsLocation(bool useIni) +{ + std::lock_guard lock(m_profileMutex); + + bool success; + + // Load favorites so that they can be correctly saved to the new location + CAtlList filesFav, DVDsFav, devicesFav; + m_s->GetFav(FAV_FILE, filesFav); + m_s->GetFav(FAV_DVD, DVDsFav); + m_s->GetFav(FAV_DEVICE, devicesFav); + + if (useIni) { + success = StoreSettingsToIni(); + // No need to delete old mpc-hc.ini, + // as it will be overwritten during CAppSettings::SaveSettings() + } else { + success = StoreSettingsToRegistry(); + _tremove(GetIniPath()); + } + + // Save favorites to the new location + m_s->SetFav(FAV_FILE, filesFav); + m_s->SetFav(FAV_DVD, DVDsFav); + m_s->SetFav(FAV_DEVICE, devicesFav); + + // Save external filters to the new location + m_s->SaveExternalFilters(); + + // Write settings immediately + m_s->SaveSettings(true); + + return success; +} + +bool CMPlayerCApp::ExportSettings(CString savePath, CString subKey) +{ + bool success = false; + m_s->SaveSettings(); + + if (IsIniValid()) { + success = !!CopyFile(GetIniPath(), savePath, FALSE); + } else { + CString regKey; + if (subKey.IsEmpty()) { + regKey.Format(_T("Software\\%s\\%s"), m_pszRegistryKey, m_pszProfileName); + } else { + regKey.Format(_T("Software\\%s\\%s\\%s"), m_pszRegistryKey, m_pszProfileName, subKey.GetString()); + } + + FILE* fStream; + errno_t error = _tfopen_s(&fStream, savePath, _T("wt,ccs=UNICODE")); + CStdioFile file(fStream); + file.WriteString(_T("Windows Registry Editor Version 5.00\n\n")); + + success = !error && ExportRegistryKey(file, HKEY_CURRENT_USER, regKey); + + file.Close(); + if (!success && !error) { + DeleteFile(savePath); + } + } + + return success; +} + +void CMPlayerCApp::InitProfile() +{ + std::lock_guard lock(m_profileMutex); + + if (!m_pszRegistryKey) { + // Don't reread mpc-hc.ini if the cache needs to be flushed or it was accessed recently + if (m_bProfileInitialized && (m_bQueuedProfileFlush || GetTickCount64() - m_dwProfileLastAccessTick < 100ULL)) { + m_dwProfileLastAccessTick = GetTickCount64(); + return; + } + + m_bProfileInitialized = true; + m_dwProfileLastAccessTick = GetTickCount64(); + + ASSERT(m_pszProfileName); + if (!PathUtils::Exists(m_pszProfileName)) { + return; + } + + FILE* fp; + int fpStatus; + do { // Open mpc-hc.ini in UNICODE mode, retry if it is already being used by another process + fp = _tfsopen(m_pszProfileName, _T("r, ccs=UNICODE"), _SH_SECURE); + if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { + break; + } + Sleep(100); + } while (true); + if (!fp) { + ASSERT(FALSE); + return; + } + if (_ftell_nolock(fp) == 0L) { + // No BOM was consumed, assume mpc-hc.ini is ANSI encoded + fpStatus = fclose(fp); + ASSERT(fpStatus == 0); + do { // Reopen mpc-hc.ini in ANSI mode, retry if it is already being used by another process + fp = _tfsopen(m_pszProfileName, _T("r"), _SH_SECURE); + if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { + break; + } + Sleep(100); + } while (true); + if (!fp) { + ASSERT(FALSE); + return; + } + } + + CStdioFile file(fp); + + ASSERT(!m_bQueuedProfileFlush); + m_ProfileMap.clear(); + + CString line, section, var, val; + while (file.ReadString(line)) { + // Parse mpc-hc.ini file, this parser: + // - doesn't trim whitespaces + // - doesn't remove quotation marks + // - omits keys with empty names + // - omits unnamed sections + int pos = 0; + if (line[0] == _T('[')) { + pos = line.Find(_T(']')); + if (pos == -1) { + continue; + } + section = line.Mid(1, pos - 1); + } else if (line[0] != _T(';')) { + pos = line.Find(_T('=')); + if (pos == -1) { + continue; + } + var = line.Mid(0, pos); + val = line.Mid(pos + 1); + if (!section.IsEmpty() && !var.IsEmpty()) { + m_ProfileMap[section][var] = val; + } + } + } + fpStatus = fclose(fp); + ASSERT(fpStatus == 0); + + m_dwProfileLastAccessTick = GetTickCount64(); + } +} + +void CMPlayerCApp::FlushProfile(bool bForce/* = true*/) +{ + std::lock_guard lock(m_profileMutex); + + if (!m_pszRegistryKey) { + if (!bForce && !m_bQueuedProfileFlush) { + return; + } + + m_bQueuedProfileFlush = false; + + ASSERT(m_bProfileInitialized); + ASSERT(m_pszProfileName); + + FILE* fp; + int fpStatus; + do { // Open mpc-hc.ini, retry if it is already being used by another process + fp = _tfsopen(m_pszProfileName, _T("w, ccs=UTF-8"), _SH_SECURE); + if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { + break; + } + Sleep(100); + } while (true); + if (!fp) { + ASSERT(FALSE); + return; + } + CStdioFile file(fp); + CString line; + try { + file.WriteString(_T("; MPC-HC\n")); + for (auto it1 = m_ProfileMap.begin(); it1 != m_ProfileMap.end(); ++it1) { + line.Format(_T("[%s]\n"), it1->first.GetString()); + file.WriteString(line); + for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) { + line.Format(_T("%s=%s\n"), it2->first.GetString(), it2->second.GetString()); + file.WriteString(line); + } + } + } catch (CFileException& e) { + // Fail silently if disk is full + UNREFERENCED_PARAMETER(e); + ASSERT(FALSE); + } + fpStatus = fclose(fp); + ASSERT(fpStatus == 0); + } +} + +BOOL CMPlayerCApp::GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes) +{ + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + return CWinAppEx::GetProfileBinary(lpszSection, lpszEntry, ppData, pBytes); + } else { + if (!lpszSection || !lpszEntry || !ppData || !pBytes) { + ASSERT(FALSE); + return FALSE; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + CString valueStr; + + InitProfile(); + auto it1 = m_ProfileMap.find(sectionStr); + if (it1 != m_ProfileMap.end()) { + auto it2 = it1->second.find(keyStr); + if (it2 != it1->second.end()) { + valueStr = it2->second; + } + } + if (valueStr.IsEmpty()) { + return FALSE; + } + int length = valueStr.GetLength(); + // Encoding: each 4-bit sequence is coded in one character, from 'A' for 0x0 to 'P' for 0xf + if (length % 2) { + ASSERT(FALSE); + return FALSE; + } + for (int i = 0; i < length; i++) { + if (valueStr[i] < 'A' || valueStr[i] > 'P') { + ASSERT(FALSE); + return FALSE; + } + } + *pBytes = length / 2; + *ppData = new (std::nothrow) BYTE[*pBytes]; + if (!(*ppData)) { + ASSERT(FALSE); + return FALSE; + } + for (UINT i = 0; i < *pBytes; i++) { + (*ppData)[i] = BYTE((valueStr[i * 2] - 'A') | ((valueStr[i * 2 + 1] - 'A') << 4)); + } + return TRUE; + } +} + +UINT CMPlayerCApp::GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) +{ + std::lock_guard lock(m_profileMutex); + + int res = nDefault; + if (m_pszRegistryKey) { + res = CWinAppEx::GetProfileInt(lpszSection, lpszEntry, nDefault); + } else { + if (!lpszSection || !lpszEntry) { + ASSERT(FALSE); + return res; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return res; + } + + InitProfile(); + auto it1 = m_ProfileMap.find(sectionStr); + if (it1 != m_ProfileMap.end()) { + auto it2 = it1->second.find(keyStr); + if (it2 != it1->second.end()) { + res = _ttoi(it2->second); + } + } + } + return res; +} + +std::list CMPlayerCApp::GetSectionSubKeys(LPCWSTR lpszSection) { + std::lock_guard lock(m_profileMutex); + + std::list keys; + + if (m_pszRegistryKey) { + WCHAR achKey[MAX_REGKEY_LEN]; // buffer for subkey name + DWORD cbName; // size of name string + DWORD cSubKeys = 0; // number of subkeys + + if (HKEY hAppKey = GetAppRegistryKey()) { + HKEY hSectionKey; + if (ERROR_SUCCESS == RegOpenKeyExW(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey)) { + RegQueryInfoKeyW(hSectionKey, NULL, NULL, NULL, &cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + if (cSubKeys) { + for (DWORD i = 0; i < cSubKeys; i++) { + cbName = MAX_REGKEY_LEN; + if (ERROR_SUCCESS == RegEnumKeyExW(hSectionKey, i, achKey, &cbName, NULL, NULL, NULL, NULL)){ + keys.push_back(achKey); + } + } + } + } + } + } else { + if (!lpszSection) { + ASSERT(FALSE); + return keys; + } + CStringW sectionStr(lpszSection); + if (sectionStr.IsEmpty()) { + ASSERT(FALSE); + return keys; + } + InitProfile(); + auto it1 = m_ProfileMap.begin(); + while (it1 != m_ProfileMap.end()) { + if (it1->first.Find(sectionStr + L"\\") == 0) { + CStringW subKey = it1->first.Mid(sectionStr.GetLength() + 1); + if (subKey.Find(L"\\") == -1) { + keys.push_back(subKey); + } + } + it1++; + } + + } + return keys; +} + + +CString CMPlayerCApp::GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault) +{ + std::lock_guard lock(m_profileMutex); + + CString res; + if (m_pszRegistryKey) { + res = CWinAppEx::GetProfileString(lpszSection, lpszEntry, lpszDefault); + } else { + if (!lpszSection || !lpszEntry) { + ASSERT(FALSE); + return res; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return res; + } + if (lpszDefault) { + res = lpszDefault; + } + + InitProfile(); + auto it1 = m_ProfileMap.find(sectionStr); + if (it1 != m_ProfileMap.end()) { + auto it2 = it1->second.find(keyStr); + if (it2 != it1->second.end()) { + res = it2->second; + } + } + } + return res; +} + +BOOL CMPlayerCApp::WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes) +{ + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + return CWinAppEx::WriteProfileBinary(lpszSection, lpszEntry, pData, nBytes); + } else { + if (!lpszSection || !lpszEntry || !pData || !nBytes) { + ASSERT(FALSE); + return FALSE; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + CString valueStr; + + TCHAR* buffer = valueStr.GetBufferSetLength(nBytes * 2); + // Encoding: each 4-bit sequence is coded in one character, from 'A' for 0x0 to 'P' for 0xf + for (UINT i = 0; i < nBytes; i++) { + buffer[i * 2] = 'A' + (pData[i] & 0xf); + buffer[i * 2 + 1] = 'A' + (pData[i] >> 4 & 0xf); + } + valueStr.ReleaseBufferSetLength(nBytes * 2); + + InitProfile(); + CString& old = m_ProfileMap[sectionStr][keyStr]; + if (old != valueStr) { + old = valueStr; + m_bQueuedProfileFlush = true; + } + return TRUE; + } +} + +LONG CMPlayerCApp::RemoveProfileKey(LPCWSTR lpszSection, LPCWSTR lpszEntry) { + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + if (HKEY hAppKey = GetAppRegistryKey()) { + HKEY hSectionKey; + if (ERROR_SUCCESS == RegOpenKeyEx(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey)) { + return CWinAppEx::DelRegTree(hSectionKey, lpszEntry); + } + } + } else { + if (!lpszSection || !lpszEntry) { + ASSERT(FALSE); + return 1; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return 1; + } + + InitProfile(); + auto it1 = m_ProfileMap.find(sectionStr + L"\\" + keyStr); + if (it1 != m_ProfileMap.end()) { + m_ProfileMap.erase(it1); + m_bQueuedProfileFlush = true; + } + } + return 0; +} + +BOOL CMPlayerCApp::WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) +{ + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + return CWinAppEx::WriteProfileInt(lpszSection, lpszEntry, nValue); + } else { + if (!lpszSection || !lpszEntry) { + ASSERT(FALSE); + return FALSE; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + CString valueStr; + valueStr.Format(_T("%d"), nValue); + + InitProfile(); + CString& old = m_ProfileMap[sectionStr][keyStr]; + if (old != valueStr) { + old = valueStr; + m_bQueuedProfileFlush = true; + } + return TRUE; + } +} + +BOOL CMPlayerCApp::WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) +{ + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + return CWinAppEx::WriteProfileString(lpszSection, lpszEntry, lpszValue); + } else { + if (!lpszSection) { + ASSERT(FALSE); + return FALSE; + } + CString sectionStr(lpszSection); + if (sectionStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + CString keyStr(lpszEntry); + if (lpszEntry && keyStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + + InitProfile(); + + // Mimic CWinAppEx::WriteProfileString() behavior + if (lpszEntry) { + if (lpszValue) { + CString& old = m_ProfileMap[sectionStr][keyStr]; + if (old != lpszValue) { + old = lpszValue; + m_bQueuedProfileFlush = true; + } + } else { // Delete key + auto it = m_ProfileMap.find(sectionStr); + if (it != m_ProfileMap.end()) { + if (it->second.erase(keyStr)) { + m_bQueuedProfileFlush = true; + } + } + } + } else { // Delete section + if (m_ProfileMap.erase(sectionStr)) { + m_bQueuedProfileFlush = true; + } + } + return TRUE; + } +} + +bool CMPlayerCApp::HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry) +{ + std::lock_guard lock(m_profileMutex); + + bool ret = false; + if (m_pszRegistryKey) { + if (HKEY hAppKey = GetAppRegistryKey()) { + HKEY hSectionKey; + if (RegOpenKeyEx(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey) == ERROR_SUCCESS) { + LONG lResult = RegQueryValueEx(hSectionKey, lpszEntry, nullptr, nullptr, nullptr, nullptr); + ret = (lResult == ERROR_SUCCESS); + VERIFY(RegCloseKey(hSectionKey) == ERROR_SUCCESS); + } + VERIFY(RegCloseKey(hAppKey) == ERROR_SUCCESS); + } else { + ASSERT(FALSE); + } + } else { + InitProfile(); + auto it1 = m_ProfileMap.find(lpszSection); + if (it1 != m_ProfileMap.end()) { + auto& sectionMap = it1->second; + auto it2 = sectionMap.find(lpszEntry); + ret = (it2 != sectionMap.end()); + } + } + return ret; +} + +std::vector CMPlayerCApp::GetProfileVectorInt(CString strSection, CString strKey) { + std::vector vData; + UINT uSize = theApp.GetProfileInt(strSection, strKey + _T("Size"), 0); + UINT uSizeRead = 0; + BYTE* temp = nullptr; + theApp.GetProfileBinary(strSection, strKey, &temp, &uSizeRead); + if (uSizeRead == uSize) { + vData.resize(uSizeRead / sizeof(int), 0); + memcpy(vData.data(), temp, uSizeRead); + } + delete[] temp; + temp = nullptr; + return vData; +} + + +void CMPlayerCApp::WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData) { + UINT uSize = static_cast(sizeof(int) * vData.size()); + theApp.WriteProfileBinary( + strSection, + strKey, + (LPBYTE)vData.data(), + uSize + ); + theApp.WriteProfileInt(strSection, strKey + _T("Size"), uSize); +} + +void CMPlayerCApp::PreProcessCommandLine() +{ + m_cmdln.RemoveAll(); + + for (int i = 1; i < __argc; i++) { + m_cmdln.AddTail(CString(__targv[i]).Trim(_T(" \""))); + } +} + +bool CMPlayerCApp::SendCommandLine(HWND hWnd) +{ + if (m_cmdln.IsEmpty()) { + return false; + } + + int bufflen = sizeof(DWORD); + + POSITION pos = m_cmdln.GetHeadPosition(); + while (pos) { + bufflen += (m_cmdln.GetNext(pos).GetLength() + 1) * sizeof(TCHAR); + } + + CAutoVectorPtr buff; + if (!buff.Allocate(bufflen)) { + return FALSE; + } + + BYTE* p = buff; + + *(DWORD*)p = (DWORD)m_cmdln.GetCount(); + p += sizeof(DWORD); + + pos = m_cmdln.GetHeadPosition(); + while (pos) { + const CString& s = m_cmdln.GetNext(pos); + int len = (s.GetLength() + 1) * sizeof(TCHAR); + memcpy(p, s, len); + p += len; + } + + COPYDATASTRUCT cds; + cds.dwData = 0x6ABE51; + cds.cbData = bufflen; + cds.lpData = (void*)(BYTE*)buff; + + return !!SendMessageTimeoutW(hWnd, WM_COPYDATA, (WPARAM)nullptr, (LPARAM)&cds, SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 5000, nullptr); +} + +// CMPlayerCApp initialization + +// This hook prevents the program from reporting that a debugger is attached +BOOL(WINAPI* Real_IsDebuggerPresent)() = IsDebuggerPresent; +BOOL WINAPI Mine_IsDebuggerPresent() +{ + TRACE(_T("Oops, somebody was trying to be naughty! (called IsDebuggerPresent)\n")); + return FALSE; +} + +// This hook prevents the program from reporting that a debugger is attached +NTSTATUS(WINAPI* Real_NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG) = nullptr; +NTSTATUS WINAPI Mine_NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength) +{ + NTSTATUS nRet; + + nRet = Real_NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength); + + if (ProcessInformationClass == ProcessBasicInformation) { + PROCESS_BASIC_INFORMATION* pbi = (PROCESS_BASIC_INFORMATION*)ProcessInformation; + PEB_NT* pPEB = (PEB_NT*)pbi->PebBaseAddress; + PEB_NT PEB; + + ReadProcessMemory(ProcessHandle, pPEB, &PEB, sizeof(PEB), nullptr); + PEB.BeingDebugged = FALSE; + WriteProcessMemory(ProcessHandle, pPEB, &PEB, sizeof(PEB), nullptr); + } else if (ProcessInformationClass == 7) { // ProcessDebugPort + BOOL* pDebugPort = (BOOL*)ProcessInformation; + *pDebugPort = FALSE; + } + + return nRet; +} + +#define USE_DLL_BLOCKLIST 1 + +#if USE_DLL_BLOCKLIST +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) + +typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT; + +typedef enum _SECTION_INFORMATION_CLASS { + SectionBasicInformation = 0, + SectionImageInformation +} SECTION_INFORMATION_CLASS; + +typedef struct _SECTION_BASIC_INFORMATION { + PVOID BaseAddress; + ULONG Attributes; + LARGE_INTEGER Size; +} SECTION_BASIC_INFORMATION; + +typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtMapViewOfSection)(HANDLE, HANDLE, PVOID, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT, ULONG, ULONG); +typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtUnmapViewOfSection)(HANDLE, PVOID); +typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); +typedef DWORD(STDMETHODCALLTYPE* pfn_GetMappedFileNameW)(HANDLE, LPVOID, LPWSTR, DWORD); + +static pfn_NtMapViewOfSection Real_NtMapViewOfSection = nullptr; +static pfn_NtUnmapViewOfSection Real_NtUnmapViewOfSection = nullptr; +static pfn_NtQuerySection Real_NtQuerySection = nullptr; +static pfn_GetMappedFileNameW Real_GetMappedFileNameW = nullptr; + +typedef struct { + // DLL name, lower case, with backslash as prefix + const wchar_t* name; + size_t name_len; +} blocked_module_t; + +// list of modules that can cause crashes or other unwanted behavior +static blocked_module_t moduleblocklist[] = { +#if WIN64 + // Logitech codec + {_T("\\lvcod64.dll"), 12}, + // ProxyCodec64 + {_T("\\pxc0.dll"), 9}, +#else + {_T("\\mlc.dll"), 8}, +#endif + // Lame + {_T("\\lameacm.acm"), 12}, + // ffdshow vfw + {_T("\\ff_vfw.dll"), 11}, +#if WIN64 + // Trusteer Rapport + {_T("\\rooksbas_x64.dll"), 17}, + {_T("\\rooksdol_x64.dll"), 17}, + {_T("\\rapportgh_x64.dll"), 18}, +#endif + // ASUS GamerOSD + {_T("\\atkdx11disp.dll"), 16}, + // ASUS GPU TWEAK II OSD + {_T("\\gtii-osd64.dll"), 15}, + {_T("\\gtii-osd64-vk.dll"), 18}, + // Nahimic Audio + {L"\\nahimicmsidevprops.dll", 23}, + {L"\\nahimicmsiosd.dll", 18}, + // LoiLoGameRecorder + {_T("\\loilocap.dll"), 13}, + // Other + {_T("\\tortoiseoverlays.dll"), 21}, +#if WIN64 + // Sizer + {_T("\\hook64.dll"), 11}, +#endif +}; + +bool IsBlockedModule(wchar_t* modulename) +{ + size_t mod_name_len = wcslen(modulename); + + //TRACE(L"Checking module blocklist: %s\n", modulename); + + for (size_t i = 0; i < _countof(moduleblocklist); i++) { + blocked_module_t* b = &moduleblocklist[i]; + if (mod_name_len > b->name_len) { + wchar_t* dll_ptr = modulename + mod_name_len - b->name_len; + if (_wcsicmp(dll_ptr, b->name) == 0) { + //AfxMessageBox(modulename); + TRACE(L"Blocked module load: %s\n", modulename); + return true; + } + } + } + + return false; +} + +NTSTATUS STDMETHODCALLTYPE Mine_NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, + PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) +{ + NTSTATUS ret = Real_NtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); + + // Verify map and process + if (ret < 0 || ProcessHandle != GetCurrentProcess()) + return ret; + + // Fetch section information + SIZE_T wrote = 0; + SECTION_BASIC_INFORMATION section_information; + if (Real_NtQuerySection(SectionHandle, SectionBasicInformation, §ion_information, sizeof(section_information), &wrote) < 0) + return ret; + + // Verify fetch was successful + if (wrote != sizeof(section_information)) + return ret; + + // We're not interested in non-image maps + if (!(section_information.Attributes & SEC_IMAGE)) + return ret; + + // Get the actual filename if possible + wchar_t fileName[MAX_PATH]; + // ToDo: switch to PSAPI_VERSION=2 and directly use K32GetMappedFileNameW ? + if (Real_GetMappedFileNameW(ProcessHandle, *BaseAddress, fileName, _countof(fileName)) == 0) + return ret; + + if (IsBlockedModule(fileName)) { + Real_NtUnmapViewOfSection(ProcessHandle, BaseAddress); + ret = STATUS_UNSUCCESSFUL; + } + + return ret; +} +#endif + +static LONG Mine_ChangeDisplaySettingsEx(LONG ret, DWORD dwFlags, LPVOID lParam) +{ + if (dwFlags & CDS_VIDEOPARAMETERS) { + VIDEOPARAMETERS* vp = (VIDEOPARAMETERS*)lParam; + + if (vp->Guid == GUIDFromCString(_T("{02C62061-1097-11d1-920F-00A024DF156E}")) + && (vp->dwFlags & VP_FLAGS_COPYPROTECT)) { + if (vp->dwCommand == VP_COMMAND_GET) { + if ((vp->dwTVStandard & VP_TV_STANDARD_WIN_VGA) + && vp->dwTVStandard != VP_TV_STANDARD_WIN_VGA) { + TRACE(_T("Ooops, tv-out enabled? macrovision checks suck...")); + vp->dwTVStandard = VP_TV_STANDARD_WIN_VGA; + } + } else if (vp->dwCommand == VP_COMMAND_SET) { + TRACE(_T("Ooops, as I already told ya, no need for any macrovision bs here")); + return 0; + } + } + } + + return ret; +} + +// These two hooks prevent the program from requesting Macrovision checks +LONG(WINAPI* Real_ChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID) = ChangeDisplaySettingsExA; +LONG(WINAPI* Real_ChangeDisplaySettingsExW)(LPCWSTR, LPDEVMODEW, HWND, DWORD, LPVOID) = ChangeDisplaySettingsExW; +LONG WINAPI Mine_ChangeDisplaySettingsExA(LPCSTR lpszDeviceName, LPDEVMODEA lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam) +{ + return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExA(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam); +} +LONG WINAPI Mine_ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, LPDEVMODEW lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam) +{ + return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam); +} + +// This hook forces files to open even if they are currently being written +HANDLE(WINAPI* Real_CreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileA; +HANDLE WINAPI Mine_CreateFileA(LPCSTR p1, DWORD p2, DWORD p3, LPSECURITY_ATTRIBUTES p4, DWORD p5, DWORD p6, HANDLE p7) +{ + p3 |= FILE_SHARE_WRITE; + + return Real_CreateFileA(p1, p2, p3, p4, p5, p6, p7); +} + +static BOOL CreateFakeVideoTS(LPCWSTR strIFOPath, LPWSTR strFakeFile, size_t nFakeFileSize) +{ + BOOL bRet = FALSE; + WCHAR szTempPath[MAX_PATH]; + WCHAR strFileName[MAX_PATH]; + WCHAR strExt[_MAX_EXT]; + CIfo Ifo; + + if (!GetTempPathW(MAX_PATH, szTempPath)) { + return FALSE; + } + + _wsplitpath_s(strIFOPath, nullptr, 0, nullptr, 0, strFileName, _countof(strFileName), strExt, _countof(strExt)); + _snwprintf_s(strFakeFile, nFakeFileSize, _TRUNCATE, L"%sMPC%s%s", szTempPath, strFileName, strExt); + + if (Ifo.OpenFile(strIFOPath) && Ifo.RemoveUOPs() && Ifo.SaveFile(strFakeFile)) { + bRet = TRUE; + } + + return bRet; +} + +// This hook forces files to open even if they are currently being written and hijacks +// IFO file opening so that a modified IFO with no forbidden operations is opened instead. +HANDLE(WINAPI* Real_CreateFileW)(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileW; +HANDLE WINAPI Mine_CreateFileW(LPCWSTR p1, DWORD p2, DWORD p3, LPSECURITY_ATTRIBUTES p4, DWORD p5, DWORD p6, HANDLE p7) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + size_t nLen = wcslen(p1); + + p3 |= FILE_SHARE_WRITE; + + if (nLen >= 4 && _wcsicmp(p1 + nLen - 4, L".ifo") == 0) { + WCHAR strFakeFile[MAX_PATH]; + if (CreateFakeVideoTS(p1, strFakeFile, _countof(strFakeFile))) { + hFile = Real_CreateFileW(strFakeFile, p2, p3, p4, p5, p6, p7); + } + } + + if (hFile == INVALID_HANDLE_VALUE) { + hFile = Real_CreateFileW(p1, p2, p3, p4, p5, p6, p7); + } + + return hFile; +} + +// This hooks disables the DVD version check +BOOL(WINAPI* Real_DeviceIoControl)(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED) = DeviceIoControl; +BOOL WINAPI Mine_DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) +{ + BOOL ret = Real_DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + if (IOCTL_DVD_GET_REGION == dwIoControlCode && lpOutBuffer && nOutBufferSize == sizeof(DVD_REGION)) { + DVD_REGION* pDVDRegion = (DVD_REGION*)lpOutBuffer; + + if (pDVDRegion->RegionData > 0) { + UCHAR disc_regions = ~pDVDRegion->RegionData; + if ((disc_regions & pDVDRegion->SystemRegion) == 0) { + if (disc_regions & 1) pDVDRegion->SystemRegion = 1; + else if (disc_regions & 2) pDVDRegion->SystemRegion = 2; + else if (disc_regions & 4) pDVDRegion->SystemRegion = 4; + else if (disc_regions & 8) pDVDRegion->SystemRegion = 8; + else if (disc_regions & 16) pDVDRegion->SystemRegion = 16; + else if (disc_regions & 32) pDVDRegion->SystemRegion = 32; + else if (disc_regions & 128) pDVDRegion->SystemRegion = 128; + ret = true; + } + } else if (pDVDRegion->SystemRegion == 0) { + pDVDRegion->SystemRegion = 1; + ret = true; + } + } + return ret; +} + +MMRESULT(WINAPI* Real_mixerSetControlDetails)(HMIXEROBJ, LPMIXERCONTROLDETAILS, DWORD) = mixerSetControlDetails; +MMRESULT WINAPI Mine_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) +{ + if (fdwDetails == (MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)) { + return MMSYSERR_NOERROR; // don't touch the mixer, kthx + } + return Real_mixerSetControlDetails(hmxobj, pmxcd, fdwDetails); +} + +BOOL (WINAPI* Real_LockWindowUpdate)(HWND) = LockWindowUpdate; +BOOL WINAPI Mine_LockWindowUpdate(HWND hWndLock) +{ + // TODO: Check if needed on Windows 8+ + if (hWndLock == ::GetDesktopWindow()) { + // locking the desktop window with aero active locks the entire compositor, + // unfortunately MFC does that (when dragging CControlBar) and we want to prevent it + return FALSE; + } else { + return Real_LockWindowUpdate(hWndLock); + } +} + +BOOL RegQueryBoolValue(HKEY hKeyRoot, LPCWSTR lpSubKey, LPCWSTR lpValuename, BOOL defaultvalue) { + BOOL result = defaultvalue; + HKEY hKeyOpen; + DWORD rv = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKeyOpen); + if (rv == ERROR_SUCCESS) { + DWORD data; + DWORD dwBufferSize = sizeof(DWORD); + rv = RegQueryValueEx(hKeyOpen, lpValuename, NULL, NULL, reinterpret_cast(&data), &dwBufferSize); + if (rv == ERROR_SUCCESS) { + result = (data > 0); + } + RegCloseKey(hKeyOpen); + } + return result; +} + +#if USE_DRDUMP_CRASH_REPORTER +void DisableCrashReporter() +{ + if (CrashReporter::IsEnabled()) { + CrashReporter::Disable(); + MPCExceptionHandler::Enable(); + } +} +#endif + +BOOL CMPlayerCApp::InitInstance() +{ + // Remove the working directory from the search path to work around the DLL preloading vulnerability + SetDllDirectory(_T("")); + + // At this point we have not hooked this function yet so we get the real result + if (!IsDebuggerPresent()) { +#if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER + if (RegQueryBoolValue(HKEY_CURRENT_USER, _T("Software\\MPC-HC\\MPC-HC\\Settings"), _T("EnableCrashReporter"), true)) { + CrashReporter::Enable(); + if (!CrashReporter::IsEnabled()) { + MPCExceptionHandler::Enable(); + } + } else { + MPCExceptionHandler::Enable(); + } +#else + MPCExceptionHandler::Enable(); +#endif + } + + if (!HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0)) { + TRACE(_T("Failed to enable \"terminate on corruption\" heap option, error %u\n"), GetLastError()); + ASSERT(FALSE); + } + + bool bHookingSuccessful = MH_Initialize() == MH_OK; + +#ifndef _DEBUG + bHookingSuccessful &= !!Mhook_SetHookEx(&Real_IsDebuggerPresent, Mine_IsDebuggerPresent); +#endif + + m_hNTDLL = LoadLibrary(_T("ntdll.dll")); +#if 0 +#ifndef _DEBUG // Disable NtQueryInformationProcess in debug (prevent VS debugger to stop on crash address) + if (m_hNTDLL) { + Real_NtQueryInformationProcess = (decltype(Real_NtQueryInformationProcess))GetProcAddress(m_hNTDLL, "NtQueryInformationProcess"); + + if (Real_NtQueryInformationProcess) { + bHookingSuccessful &= !!Mhook_SetHookEx(&Real_NtQueryInformationProcess, Mine_NtQueryInformationProcess); + } + } +#endif +#endif + + bHookingSuccessful &= !!Mhook_SetHookEx(&Real_CreateFileW, Mine_CreateFileW); + bHookingSuccessful &= !!Mhook_SetHookEx(&Real_DeviceIoControl, Mine_DeviceIoControl); + + bHookingSuccessful &= MH_EnableHook(MH_ALL_HOOKS) == MH_OK; + + if (!bHookingSuccessful) { + AfxMessageBox(IDS_HOOKS_FAILED); + } + +#if USE_DLL_BLOCKLIST + if (m_hNTDLL) { + Real_NtMapViewOfSection = (pfn_NtMapViewOfSection)GetProcAddress(m_hNTDLL, "NtMapViewOfSection"); + Real_NtUnmapViewOfSection = (pfn_NtUnmapViewOfSection)GetProcAddress(m_hNTDLL, "NtUnmapViewOfSection"); + Real_NtQuerySection = (pfn_NtQuerySection)GetProcAddress(m_hNTDLL, "NtQuerySection"); + Real_GetMappedFileNameW = (pfn_GetMappedFileNameW)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "K32GetMappedFileNameW"); + if (Real_NtMapViewOfSection && Real_NtUnmapViewOfSection && Real_NtQuerySection && Real_GetMappedFileNameW) { + VERIFY(Mhook_SetHookEx(&Real_NtMapViewOfSection, Mine_NtMapViewOfSection)); + } + } +#endif + + // If those hooks fail it's annoying but try to run anyway without reporting any error in release mode + VERIFY(Mhook_SetHookEx(&Real_ChangeDisplaySettingsExA, Mine_ChangeDisplaySettingsExA)); + VERIFY(Mhook_SetHookEx(&Real_ChangeDisplaySettingsExW, Mine_ChangeDisplaySettingsExW)); + VERIFY(Mhook_SetHookEx(&Real_CreateFileA, Mine_CreateFileA)); // The internal splitter uses the right share mode anyway so this is no big deal + VERIFY(Mhook_SetHookEx(&Real_LockWindowUpdate, Mine_LockWindowUpdate)); + VERIFY(Mhook_SetHookEx(&Real_mixerSetControlDetails, Mine_mixerSetControlDetails)); + MH_EnableHook(MH_ALL_HOOKS); + + CFilterMapper2::Init(); + + if (FAILED(OleInitialize(nullptr))) { + AfxMessageBox(_T("OleInitialize failed!")); + return FALSE; + } + + m_s = std::make_unique(); + + // Be careful if you move that code: IDR_MAINFRAME icon can only be loaded from the executable, + // LoadIcon can't be used after the language DLL has been set as the main resource. + HICON icon = LoadIcon(IDR_MAINFRAME); + + WNDCLASS wndcls; + ZeroMemory(&wndcls, sizeof(WNDCLASS)); + wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wndcls.lpfnWndProc = ::DefWindowProc; + wndcls.hInstance = AfxGetInstanceHandle(); + wndcls.hIcon = icon; + wndcls.hCursor = LoadCursor(IDC_ARROW); + wndcls.hbrBackground = 0;//(HBRUSH)(COLOR_WINDOW + 1); // no bkg brush, the view and the bars should always fill the whole client area + wndcls.lpszMenuName = nullptr; + wndcls.lpszClassName = MPC_WND_CLASS_NAME; + + if (!AfxRegisterClass(&wndcls)) { + AfxMessageBox(_T("MainFrm class registration failed!")); + return FALSE; + } + + if (!AfxSocketInit(nullptr)) { + AfxMessageBox(_T("AfxSocketInit failed!")); + return FALSE; + } + + PreProcessCommandLine(); + + if (IsIniValid()) { + StoreSettingsToIni(); + } else { + StoreSettingsToRegistry(); + } + + m_s->ParseCommandLine(m_cmdln); + + VERIFY(SetCurrentDirectory(PathUtils::GetProgramPath())); + + if (m_s->nCLSwitches & (CLSW_HELP | CLSW_UNRECOGNIZEDSWITCH)) { // show commandline help window + m_s->LoadSettings(); + ShowCmdlnSwitches(); + return FALSE; + } + + if (m_s->nCLSwitches & CLSW_RESET) { // reset settings + // We want the other instances to be closed before resetting the settings. + HWND hWnd = FindWindow(MPC_WND_CLASS_NAME, nullptr); + + while (hWnd) { + Sleep(500); + + hWnd = FindWindow(MPC_WND_CLASS_NAME, nullptr); + + if (hWnd && MessageBox(nullptr, ResStr(IDS_RESET_SETTINGS_MUTEX), ResStr(IDS_RESET_SETTINGS), MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDCANCEL) { + return FALSE; + } + } + + // If the profile was already cached, it should be cleared here + ASSERT(!m_bProfileInitialized); + + // Remove the settings + if (IsIniValid()) { + FILE* fp; + do { // Open mpc-hc.ini, retry if it is already being used by another process + fp = _tfsopen(m_pszProfileName, _T("w"), _SH_SECURE); + if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { + break; + } + Sleep(100); + } while (true); + if (fp) { + // Close without writing anything, it should produce empty file + VERIFY(fclose(fp) == 0); + } else { + ASSERT(FALSE); + } + } else { + CRegKey key; + // Clear settings + key.Attach(GetAppRegistryKey()); + VERIFY(key.RecurseDeleteKey(_T("")) == ERROR_SUCCESS); + VERIFY(key.Close() == ERROR_SUCCESS); + // Set ExePath value to prevent settings migration + key.Attach(GetAppRegistryKey()); + VERIFY(key.SetStringValue(_T("ExePath"), PathUtils::GetProgramPath(true)) == ERROR_SUCCESS); + VERIFY(key.Close() == ERROR_SUCCESS); + } + + // Remove the current playlist if it exists + CString strSavePath; + if (GetAppSavePath(strSavePath)) { + CPath playlistPath; + playlistPath.Combine(strSavePath, _T("default.mpcpl")); + + if (playlistPath.FileExists()) { + try { + CFile::Remove(playlistPath); + } catch (...) {} + } + } + } + + if ((m_s->nCLSwitches & CLSW_CLOSE) && m_s->slFiles.IsEmpty()) { // "/close" switch and empty file list + return FALSE; + } + + if (m_s->nCLSwitches & (CLSW_REGEXTVID | CLSW_REGEXTAUD | CLSW_REGEXTPL)) { // register file types + m_s->fileAssoc.RegisterApp(); + + CMediaFormats& mf = m_s->m_Formats; + mf.UpdateData(false); + + bool bAudioOnly; + + auto iconLib = m_s->fileAssoc.GetIconLib(); + if (iconLib) { + iconLib->SaveVersion(); + } + + for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { + bool bPlaylist = !mf[i].GetLabel().CompareNoCase(_T("pls")); + + if (bPlaylist && !(m_s->nCLSwitches & CLSW_REGEXTPL)) { + continue; + } + + bAudioOnly = mf[i].IsAudioOnly(); + + if (((m_s->nCLSwitches & CLSW_REGEXTVID) && !bAudioOnly) || + ((m_s->nCLSwitches & CLSW_REGEXTAUD) && bAudioOnly) || + ((m_s->nCLSwitches & CLSW_REGEXTPL) && bPlaylist)) { + m_s->fileAssoc.Register(mf[i], true, false, true); + } + } + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + + return FALSE; + } + + if (m_s->nCLSwitches & CLSW_UNREGEXT) { // unregistered file types + CMediaFormats& mf = m_s->m_Formats; + mf.UpdateData(false); + + for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { + m_s->fileAssoc.Register(mf[i], false, false, false); + } + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + + return FALSE; + } + + if (m_s->nCLSwitches & CLSW_ICONSASSOC) { + CMediaFormats& mf = m_s->m_Formats; + mf.UpdateData(false); + + CAtlList registeredExts; + m_s->fileAssoc.GetAssociatedExtensionsFromRegistry(registeredExts); + + m_s->fileAssoc.ReAssocIcons(registeredExts); + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + + return FALSE; + } + + // Enable to open options with administrator privilege (for Vista UAC) + if (m_s->nCLSwitches & CLSW_ADMINOPTION) { + m_s->LoadSettings(); // read all settings. long time but not critical at this point + + switch (m_s->iAdminOption) { + case CPPageFormats::IDD: { + CPPageSheet options(ResStr(IDS_OPTIONS_CAPTION), nullptr, nullptr, m_s->iAdminOption); + options.LockPage(); + options.DoModal(); + } + break; + + default: + ASSERT(FALSE); + } + return FALSE; + } + + if (m_s->nCLSwitches & (CLSW_CONFIGLAVSPLITTER | CLSW_CONFIGLAVAUDIO | CLSW_CONFIGLAVVIDEO)) { + m_s->LoadSettings(); + if (m_s->nCLSwitches & CLSW_CONFIGLAVSPLITTER) { + CFGFilterLAVSplitter::ShowPropertyPages(NULL); + } + if (m_s->nCLSwitches & CLSW_CONFIGLAVAUDIO) { + CFGFilterLAVAudio::ShowPropertyPages(NULL); + } + if (m_s->nCLSwitches & CLSW_CONFIGLAVVIDEO) { + CFGFilterLAVVideo::ShowPropertyPages(NULL); + } + return FALSE; + } + + m_mutexOneInstance.Create(nullptr, TRUE, MPC_WND_CLASS_NAME); + + if (GetLastError() == ERROR_ALREADY_EXISTS) { + if ((m_s->nCLSwitches & CLSW_ADD) || !(m_s->GetAllowMultiInst() || m_s->nCLSwitches & CLSW_NEW || m_cmdln.IsEmpty())) { + DWORD res = WaitForSingleObject(m_mutexOneInstance.m_h, 5000); + if (res == WAIT_OBJECT_0 || res == WAIT_ABANDONED) { + HWND hWnd = ::FindWindow(MPC_WND_CLASS_NAME, nullptr); + if (hWnd) { + DWORD dwProcessId = 0; + if (GetWindowThreadProcessId(hWnd, &dwProcessId) && dwProcessId) { + VERIFY(AllowSetForegroundWindow(dwProcessId)); + } else { + ASSERT(FALSE); + } + if (!(m_s->nCLSwitches & CLSW_MINIMIZED) && IsIconic(hWnd) && + (!(m_s->nCLSwitches & CLSW_ADD) || m_s->nCLSwitches & CLSW_PLAY) //do not restore when adding to playlist of minimized player, unless also playing + ) { + ShowWindow(hWnd, SW_RESTORE); + } + if (SendCommandLine(hWnd)) { + m_mutexOneInstance.Close(); + return FALSE; + } + } + } + if ((m_s->nCLSwitches & CLSW_ADD)) { + ASSERT(FALSE); + return FALSE; // don't open new instance if SendCommandLine() failed + } + } + } + + if (!IsIniValid()) { + CRegKey key; + if (ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, _T("Software\\MPC-HC\\MPC-HC"))) { + if (RegQueryValueEx(key, _T("ExePath"), 0, nullptr, nullptr, nullptr) != ERROR_SUCCESS) { // First launch + // Move registry settings from the old to the new location + CRegKey oldKey; + if (ERROR_SUCCESS == oldKey.Open(HKEY_CURRENT_USER, _T("Software\\Gabest\\Media Player Classic"), KEY_READ)) { + SHCopyKey(oldKey, _T(""), key, 0); + } + } + + key.SetStringValue(_T("ExePath"), PathUtils::GetProgramPath(true)); + } + } + + m_s->UpdateSettings(); // update settings + m_s->LoadSettings(); // read settings + + #if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER + if (!m_s->bEnableCrashReporter) { + DisableCrashReporter(); + } + #endif + + m_AudioRendererDisplayName_CL = _T(""); + + if (!__super::InitInstance()) { + AfxMessageBox(_T("InitInstance failed!")); + return FALSE; + } + + AfxEnableControlContainer(); + + CMainFrame* pFrame; + try { + pFrame = DEBUG_NEW CMainFrame; + if (!pFrame || !pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, nullptr, nullptr)) { + MessageBox(nullptr, ResStr(IDS_FRAME_INIT_FAILED), m_pszAppName, MB_ICONERROR | MB_OK); + return FALSE; + } + } catch (...) { + return FALSE; + } + + m_pMainWnd = pFrame; + pFrame->m_controls.LoadState(); + CPoint borderAdjustDirection; + pFrame->SetDefaultWindowRect((m_s->nCLSwitches & CLSW_MONITOR) ? m_s->iMonitor : 0); + if (!m_s->slFiles.IsEmpty()) { + pFrame->m_controls.DelayShowNotLoaded(true); + } + pFrame->SetDefaultFullscreenState(); + pFrame->UpdateControlState(CMainFrame::UPDATE_CONTROLS_VISIBILITY); + pFrame->SetIcon(icon, TRUE); + + bool bRestoreLastWindowType = (m_s->fRememberWindowSize || m_s->fRememberWindowPos) && !m_s->fLastFullScreen && !m_s->fLaunchfullscreen; + bool bMinimized = (m_s->nCLSwitches & CLSW_MINIMIZED) || (bRestoreLastWindowType && m_s->nLastWindowType == SIZE_MINIMIZED); + bool bMaximized = bRestoreLastWindowType && m_s->nLastWindowType == SIZE_MAXIMIZED; + + if (bMinimized) { + m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWMINNOACTIVE : SW_SHOWMINIMIZED; + } else if (bMaximized) { + // Show maximized without focus is not supported nor make sense. + m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWNOACTIVATE : SW_SHOWMAXIMIZED; + } else { + m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL; + } + + pFrame->ActivateFrame(m_nCmdShow); + + if (AfxGetAppSettings().HasFixedWindowSize() && IsWindows8OrGreater()) {//make adjustments for drop shadow frame + CRect rect, frame; + pFrame->GetWindowRect(&rect); + CRect diff = pFrame->GetInvisibleBorderSize(); + if (!diff.IsRectNull()) { + rect.InflateRect(diff); + pFrame->SetWindowPos(nullptr, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER | SWP_NOACTIVATE); + } + } + + /* adipose 2019-11-12: + LoadPlayList this used to be performed inside OnCreate, + but due to all toolbars being hidden, EnsureVisible does not correctly + scroll to the current file in the playlist. We call after activating + the frame to fix this issue. + */ + pFrame->m_wndPlaylistBar.LoadPlaylist(pFrame->GetRecentFile()); + + pFrame->UpdateWindow(); + + + if (bMinimized && bMaximized) { + WINDOWPLACEMENT wp; + GetWindowPlacement(*pFrame, &wp); + wp.flags = WPF_RESTORETOMAXIMIZED; + SetWindowPlacement(*pFrame, &wp); + } + + pFrame->m_hAccelTable = m_s->hAccel; + m_s->WinLircClient.SetHWND(m_pMainWnd->m_hWnd); + if (m_s->fWinLirc) { + m_s->WinLircClient.Connect(m_s->strWinLircAddr); + } + m_s->UIceClient.SetHWND(m_pMainWnd->m_hWnd); + if (m_s->fUIce) { + m_s->UIceClient.Connect(m_s->strUIceAddr); + } + + if (UpdateChecker::IsAutoUpdateEnabled()) { + UpdateChecker::CheckForUpdate(true); + } + + if (!m_pMainWnd) return false; + + SendCommandLine(m_pMainWnd->m_hWnd); + RegisterHotkeys(); + + // set HIGH I/O Priority for better playback performance + if (m_hNTDLL) { + typedef NTSTATUS(WINAPI * FUNC_NTSETINFORMATIONPROCESS)(HANDLE, ULONG, PVOID, ULONG); + FUNC_NTSETINFORMATIONPROCESS NtSetInformationProcess = (FUNC_NTSETINFORMATIONPROCESS)GetProcAddress(m_hNTDLL, "NtSetInformationProcess"); + + if (NtSetInformationProcess && SetPrivilege(SE_INC_BASE_PRIORITY_NAME)) { + ULONG IoPriority = 3; + ULONG ProcessIoPriority = 0x21; + NTSTATUS NtStatus = NtSetInformationProcess(GetCurrentProcess(), ProcessIoPriority, &IoPriority, sizeof(ULONG)); + TRACE(_T("Set I/O Priority - %d\n"), NtStatus); + UNREFERENCED_PARAMETER(NtStatus); + } + } + + m_mutexOneInstance.Release(); + + CWebServer::Init(); + + if (m_s->fAssociatedWithIcons) { + m_s->fileAssoc.CheckIconsAssoc(); + } + + return TRUE; +} + +UINT CMPlayerCApp::GetRemoteControlCodeMicrosoft(UINT nInputcode, HRAWINPUT hRawInput) +{ + UINT dwSize = 0; + UINT nMceCmd = 0; + + // Support for MCE remote control + UINT ret = GetRawInputData(hRawInput, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); + if (ret == 0 && dwSize > 0) { + BYTE* pRawBuffer = DEBUG_NEW BYTE[dwSize]; + if (GetRawInputData(hRawInput, RID_INPUT, pRawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) != -1) { + RAWINPUT* raw = (RAWINPUT*)pRawBuffer; + if (raw->header.dwType == RIM_TYPEHID && raw->data.hid.dwSizeHid >= 3) { + nMceCmd = 0x10000 + (raw->data.hid.bRawData[1] | raw->data.hid.bRawData[2] << 8); + } + } + delete [] pRawBuffer; + } + + return nMceCmd; +} + +UINT CMPlayerCApp::GetRemoteControlCodeSRM7500(UINT nInputcode, HRAWINPUT hRawInput) +{ + UINT dwSize = 0; + UINT nMceCmd = 0; + + UINT ret = GetRawInputData(hRawInput, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); + if (ret == 0 && dwSize > 21) { + BYTE* pRawBuffer = DEBUG_NEW BYTE[dwSize]; + if (GetRawInputData(hRawInput, RID_INPUT, pRawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) != -1) { + RAWINPUT* raw = (RAWINPUT*)pRawBuffer; + + // data.hid.bRawData[21] set to one when key is pressed + if (raw->header.dwType == RIM_TYPEHID && raw->data.hid.dwSizeHid >= 22 && raw->data.hid.bRawData[21] == 1) { + // data.hid.bRawData[21] has keycode + switch (raw->data.hid.bRawData[20]) { + case 0x0033: + nMceCmd = MCE_DETAILS; + break; + case 0x0022: + nMceCmd = MCE_GUIDE; + break; + case 0x0036: + nMceCmd = MCE_MYTV; + break; + case 0x0026: + nMceCmd = MCE_RECORDEDTV; + break; + case 0x0005: + nMceCmd = MCE_RED; + break; + case 0x0002: + nMceCmd = MCE_GREEN; + break; + case 0x0045: + nMceCmd = MCE_YELLOW; + break; + case 0x0046: + nMceCmd = MCE_BLUE; + break; + case 0x000A: + nMceCmd = MCE_MEDIA_PREVIOUSTRACK; + break; + case 0x004A: + nMceCmd = MCE_MEDIA_NEXTTRACK; + break; + } + } + } + delete [] pRawBuffer; + } + + return nMceCmd; +} + +void CMPlayerCApp::RegisterHotkeys() +{ + CAutoVectorPtr inputDeviceList; + UINT nInputDeviceCount = 0, nErrCode; + RID_DEVICE_INFO deviceInfo; + RAWINPUTDEVICE MCEInputDevice[] = { + // usUsagePage usUsage dwFlags hwndTarget + { 0xFFBC, 0x88, 0, nullptr}, + { 0x000C, 0x01, 0, nullptr}, + { 0x000C, 0x80, 0, nullptr} + }; + + // Register MCE Remote Control raw input + for (unsigned int i = 0; i < _countof(MCEInputDevice); i++) { + MCEInputDevice[i].hwndTarget = m_pMainWnd->m_hWnd; + } + + // Get the size of the device list + nErrCode = GetRawInputDeviceList(nullptr, &nInputDeviceCount, sizeof(RAWINPUTDEVICELIST)); + inputDeviceList.Attach(DEBUG_NEW RAWINPUTDEVICELIST[nInputDeviceCount]); + if (nErrCode == UINT(-1) || !nInputDeviceCount || !inputDeviceList) { + ASSERT(nErrCode != UINT(-1)); + return; + } + + nErrCode = GetRawInputDeviceList(inputDeviceList, &nInputDeviceCount, sizeof(RAWINPUTDEVICELIST)); + if (nErrCode == UINT(-1)) { + ASSERT(FALSE); + return; + } + + for (UINT i = 0; i < nInputDeviceCount; i++) { + UINT nTemp = deviceInfo.cbSize = sizeof(deviceInfo); + + if (GetRawInputDeviceInfo(inputDeviceList[i].hDevice, RIDI_DEVICEINFO, &deviceInfo, &nTemp) > 0) { + if (deviceInfo.hid.dwVendorId == 0x00000471 && // Philips HID vendor id + deviceInfo.hid.dwProductId == 0x00000617) { // IEEE802.15.4 RF Dongle (SRM 7500) + MCEInputDevice[0].usUsagePage = deviceInfo.hid.usUsagePage; + MCEInputDevice[0].usUsage = deviceInfo.hid.usUsage; + GetRemoteControlCode = GetRemoteControlCodeSRM7500; + } + } + } + + RegisterRawInputDevices(MCEInputDevice, _countof(MCEInputDevice), sizeof(RAWINPUTDEVICE)); + + if (m_s->fGlobalMedia) { + POSITION pos = m_s->wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = m_s->wmcmds.GetNext(pos); + if (wc.appcmd != 0) { + UINT vkappcmd = GetVKFromAppCommand(wc.appcmd); + if (vkappcmd > 0) { + RegisterHotKey(m_pMainWnd->m_hWnd, wc.appcmd, 0, vkappcmd); + } + } + } + } +} + +void CMPlayerCApp::UnregisterHotkeys() +{ + if (m_s->fGlobalMedia) { + POSITION pos = m_s->wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = m_s->wmcmds.GetNext(pos); + if (wc.appcmd != 0) { + UnregisterHotKey(m_pMainWnd->m_hWnd, wc.appcmd); + } + } + } +} + +UINT CMPlayerCApp::GetVKFromAppCommand(UINT nAppCommand) +{ + // Note: Only a subset of AppCommands have a VirtualKey + switch (nAppCommand) { + case APPCOMMAND_MEDIA_PLAY_PAUSE: + return VK_MEDIA_PLAY_PAUSE; + case APPCOMMAND_MEDIA_STOP: + return VK_MEDIA_STOP; + case APPCOMMAND_MEDIA_NEXTTRACK: + return VK_MEDIA_NEXT_TRACK; + case APPCOMMAND_MEDIA_PREVIOUSTRACK: + return VK_MEDIA_PREV_TRACK; + case APPCOMMAND_VOLUME_DOWN: + return VK_VOLUME_DOWN; + case APPCOMMAND_VOLUME_UP: + return VK_VOLUME_UP; + case APPCOMMAND_VOLUME_MUTE: + return VK_VOLUME_MUTE; + case APPCOMMAND_LAUNCH_MEDIA_SELECT: + return VK_LAUNCH_MEDIA_SELECT; + case APPCOMMAND_BROWSER_BACKWARD: + return VK_BROWSER_BACK; + case APPCOMMAND_BROWSER_FORWARD: + return VK_BROWSER_FORWARD; + case APPCOMMAND_BROWSER_REFRESH: + return VK_BROWSER_REFRESH; + case APPCOMMAND_BROWSER_STOP: + return VK_BROWSER_STOP; + case APPCOMMAND_BROWSER_SEARCH: + return VK_BROWSER_SEARCH; + case APPCOMMAND_BROWSER_FAVORITES: + return VK_BROWSER_FAVORITES; + case APPCOMMAND_BROWSER_HOME: + return VK_BROWSER_HOME; + case APPCOMMAND_LAUNCH_APP1: + return VK_LAUNCH_APP1; + case APPCOMMAND_LAUNCH_APP2: + return VK_LAUNCH_APP2; + } + + return 0; +} + +int CMPlayerCApp::ExitInstance() +{ + // We might be exiting before m_s is initialized. + if (m_s) { + m_s->SaveSettings(); + m_s = nullptr; + } + + CMPCPngImage::CleanUp(); + + MH_Uninitialize(); + + OleUninitialize(); + + return CWinAppEx::ExitInstance(); +} + +BOOL CMPlayerCApp::SaveAllModified() +{ + // CWinApp::SaveAllModified + // Called by the framework to save all documents + // when the application's main frame window is to be closed, + // or through a WM_QUERYENDSESSION message. + if (m_s && !m_fClosingState) { + if (auto pMainFrame = AfxFindMainFrame()) { + if (pMainFrame->GetLoadState() != MLS::CLOSED) { + pMainFrame->CloseMedia(); + } + } + } + + return TRUE; +} + +// CMPlayerCApp message handlers + +BEGIN_MESSAGE_MAP(CMPlayerCApp, CWinAppEx) + ON_COMMAND(ID_HELP_ABOUT, OnAppAbout) + ON_COMMAND(ID_FILE_EXIT, OnFileExit) + ON_COMMAND(ID_HELP_SHOWCOMMANDLINESWITCHES, OnHelpShowcommandlineswitches) +END_MESSAGE_MAP() + +void CMPlayerCApp::OnAppAbout() +{ + CAboutDlg aboutDlg; + aboutDlg.DoModal(); +} + +void CMPlayerCApp::SetClosingState() +{ + m_fClosingState = true; +#if USE_DRDUMP_CRASH_REPORTER & (MPC_VERSION_REV < 20) + DisableCrashReporter(); +#endif +} + +void CMPlayerCApp::OnFileExit() +{ + OnAppExit(); +} + +void CMPlayerCApp::OnHelpShowcommandlineswitches() +{ + ShowCmdlnSwitches(); +} + +// CRemoteCtrlClient + +CRemoteCtrlClient::CRemoteCtrlClient() + : m_pWnd(nullptr) + , m_nStatus(DISCONNECTED) +{ +} + +void CRemoteCtrlClient::SetHWND(HWND hWnd) +{ + CAutoLock cAutoLock(&m_csLock); + + m_pWnd = CWnd::FromHandle(hWnd); +} + +void CRemoteCtrlClient::Connect(CString addr) +{ + CAutoLock cAutoLock(&m_csLock); + + if (m_nStatus == CONNECTING && m_addr == addr) { + TRACE(_T("CRemoteCtrlClient (Connect): already connecting to %s\n"), addr.GetString()); + return; + } + + if (m_nStatus == CONNECTED && m_addr == addr) { + TRACE(_T("CRemoteCtrlClient (Connect): already connected to %s\n"), addr.GetString()); + return; + } + + m_nStatus = CONNECTING; + + TRACE(_T("CRemoteCtrlClient (Connect): connecting to %s\n"), addr.GetString()); + + Close(); + + Create(); + + CString ip = addr.Left(addr.Find(':') + 1).TrimRight(':'); + int port = _tcstol(addr.Mid(addr.Find(':') + 1), nullptr, 10); + + __super::Connect(ip, port); + + m_addr = addr; +} + +void CRemoteCtrlClient::DisConnect() +{ + CAutoLock cAutoLock(&m_csLock); + + ShutDown(2); + Close(); +} + +void CRemoteCtrlClient::OnConnect(int nErrorCode) +{ + CAutoLock cAutoLock(&m_csLock); + + m_nStatus = (nErrorCode == 0 ? CONNECTED : DISCONNECTED); + + TRACE(_T("CRemoteCtrlClient (OnConnect): %d\n"), nErrorCode); +} + +void CRemoteCtrlClient::OnClose(int nErrorCode) +{ + CAutoLock cAutoLock(&m_csLock); + + if (m_hSocket != INVALID_SOCKET && m_nStatus == CONNECTED) { + TRACE(_T("CRemoteCtrlClient (OnClose): connection lost\n")); + } + + m_nStatus = DISCONNECTED; + + TRACE(_T("CRemoteCtrlClient (OnClose): %d\n"), nErrorCode); +} + +void CRemoteCtrlClient::OnReceive(int nErrorCode) +{ + if (nErrorCode != 0 || !m_pWnd) { + return; + } + + CStringA str; + int ret = Receive(str.GetBuffer(256), 255, 0); + if (ret <= 0) { + return; + } + str.ReleaseBuffer(ret); + + TRACE(_T("CRemoteCtrlClient (OnReceive): %S\n"), str.GetString()); + + OnCommand(str); + + __super::OnReceive(nErrorCode); +} + +void CRemoteCtrlClient::ExecuteCommand(CStringA cmd, int repcnt) +{ + cmd.Trim(); + if (cmd.IsEmpty()) { + return; + } + cmd.Replace(' ', '_'); + + const CAppSettings& s = AfxGetAppSettings(); + + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + if ((repcnt == 0 && wc.rmrepcnt == 0 || wc.rmrepcnt > 0 && (repcnt % wc.rmrepcnt) == 0) + && (wc.rmcmd.CompareNoCase(cmd) == 0 || wc.cmd == (WORD)strtol(cmd, nullptr, 10))) { + CAutoLock cAutoLock(&m_csLock); + TRACE(_T("CRemoteCtrlClient (calling command): %s\n"), wc.GetName().GetString()); + m_pWnd->SendMessage(WM_COMMAND, wc.cmd); + break; + } + } +} + +// CWinLircClient + +CWinLircClient::CWinLircClient() +{ +} + +void CWinLircClient::OnCommand(CStringA str) +{ + TRACE(_T("CWinLircClient (OnCommand): %S\n"), str.GetString()); + + int i = 0, j = 0, repcnt = 0; + for (CStringA token = str.Tokenize(" ", i); + !token.IsEmpty(); + token = str.Tokenize(" ", i), j++) { + if (j == 1) { + repcnt = strtol(token, nullptr, 16); + } else if (j == 2) { + ExecuteCommand(token, repcnt); + } + } +} + +// CUIceClient + +CUIceClient::CUIceClient() +{ +} + +void CUIceClient::OnCommand(CStringA str) +{ + TRACE(_T("CUIceClient (OnCommand): %S\n"), str.GetString()); + + CStringA cmd; + int i = 0, j = 0; + for (CStringA token = str.Tokenize("|", i); + !token.IsEmpty(); + token = str.Tokenize("|", i), j++) { + if (j == 0) { + cmd = token; + } else if (j == 1) { + ExecuteCommand(cmd, strtol(token, nullptr, 16)); + } + } +} + +// CMPlayerCApp continuation + +COLORPROPERTY_RANGE* CMPlayerCApp::GetColorControl(ControlType nFlag) +{ + switch (nFlag) { + case ProcAmp_Brightness: + return &m_ColorControl[0]; + case ProcAmp_Contrast: + return &m_ColorControl[1]; + case ProcAmp_Hue: + return &m_ColorControl[2]; + case ProcAmp_Saturation: + return &m_ColorControl[3]; + } + return nullptr; +} + +void CMPlayerCApp::ResetColorControlRange() +{ + m_ColorControl[0].dwProperty = ProcAmp_Brightness; + m_ColorControl[0].MinValue = -100; + m_ColorControl[0].MaxValue = 100; + m_ColorControl[0].DefaultValue = 0; + m_ColorControl[0].StepSize = 1; + m_ColorControl[1].dwProperty = ProcAmp_Contrast; + m_ColorControl[1].MinValue = -100; + m_ColorControl[1].MaxValue = 100; + m_ColorControl[1].DefaultValue = 0; + m_ColorControl[1].StepSize = 1; + m_ColorControl[2].dwProperty = ProcAmp_Hue; + m_ColorControl[2].MinValue = -180; + m_ColorControl[2].MaxValue = 180; + m_ColorControl[2].DefaultValue = 0; + m_ColorControl[2].StepSize = 1; + m_ColorControl[3].dwProperty = ProcAmp_Saturation; + m_ColorControl[3].MinValue = -100; + m_ColorControl[3].MaxValue = 100; + m_ColorControl[3].DefaultValue = 0; + m_ColorControl[3].StepSize = 1; +} + +void CMPlayerCApp::UpdateColorControlRange(bool isEVR) +{ + if (isEVR) { + // Brightness + m_ColorControl[0].MinValue = FixedToInt(m_EVRColorControl[0].MinValue); + m_ColorControl[0].MaxValue = FixedToInt(m_EVRColorControl[0].MaxValue); + m_ColorControl[0].DefaultValue = FixedToInt(m_EVRColorControl[0].DefaultValue); + m_ColorControl[0].StepSize = std::max(1, FixedToInt(m_EVRColorControl[0].StepSize)); + // Contrast + m_ColorControl[1].MinValue = FixedToInt(m_EVRColorControl[1].MinValue, 100) - 100; + m_ColorControl[1].MaxValue = FixedToInt(m_EVRColorControl[1].MaxValue, 100) - 100; + m_ColorControl[1].DefaultValue = FixedToInt(m_EVRColorControl[1].DefaultValue, 100) - 100; + m_ColorControl[1].StepSize = std::max(1, FixedToInt(m_EVRColorControl[1].StepSize, 100)); + // Hue + m_ColorControl[2].MinValue = FixedToInt(m_EVRColorControl[2].MinValue); + m_ColorControl[2].MaxValue = FixedToInt(m_EVRColorControl[2].MaxValue); + m_ColorControl[2].DefaultValue = FixedToInt(m_EVRColorControl[2].DefaultValue); + m_ColorControl[2].StepSize = std::max(1, FixedToInt(m_EVRColorControl[2].StepSize)); + // Saturation + m_ColorControl[3].MinValue = FixedToInt(m_EVRColorControl[3].MinValue, 100) - 100; + m_ColorControl[3].MaxValue = FixedToInt(m_EVRColorControl[3].MaxValue, 100) - 100; + m_ColorControl[3].DefaultValue = FixedToInt(m_EVRColorControl[3].DefaultValue, 100) - 100; + m_ColorControl[3].StepSize = std::max(1, FixedToInt(m_EVRColorControl[3].StepSize, 100)); + } else { + // Brightness + m_ColorControl[0].MinValue = (int)floor(m_VMR9ColorControl[0].MinValue + 0.5); + m_ColorControl[0].MaxValue = (int)floor(m_VMR9ColorControl[0].MaxValue + 0.5); + m_ColorControl[0].DefaultValue = (int)floor(m_VMR9ColorControl[0].DefaultValue + 0.5); + m_ColorControl[0].StepSize = std::max(1, (int)(m_VMR9ColorControl[0].StepSize + 0.5)); + // Contrast + if (*(int*)&m_VMR9ColorControl[1].MinValue == 1036830720) { + m_VMR9ColorControl[1].MinValue = 0.11f; //fix NVIDIA bug + } + m_ColorControl[1].MinValue = (int)floor(m_VMR9ColorControl[1].MinValue * 100 + 0.5) - 100; + m_ColorControl[1].MaxValue = (int)floor(m_VMR9ColorControl[1].MaxValue * 100 + 0.5) - 100; + m_ColorControl[1].DefaultValue = (int)floor(m_VMR9ColorControl[1].DefaultValue * 100 + 0.5) - 100; + m_ColorControl[1].StepSize = std::max(1, (int)(m_VMR9ColorControl[1].StepSize * 100 + 0.5)); + // Hue + m_ColorControl[2].MinValue = (int)floor(m_VMR9ColorControl[2].MinValue + 0.5); + m_ColorControl[2].MaxValue = (int)floor(m_VMR9ColorControl[2].MaxValue + 0.5); + m_ColorControl[2].DefaultValue = (int)floor(m_VMR9ColorControl[2].DefaultValue + 0.5); + m_ColorControl[2].StepSize = std::max(1, (int)(m_VMR9ColorControl[2].StepSize + 0.5)); + // Saturation + m_ColorControl[3].MinValue = (int)floor(m_VMR9ColorControl[3].MinValue * 100 + 0.5) - 100; + m_ColorControl[3].MaxValue = (int)floor(m_VMR9ColorControl[3].MaxValue * 100 + 0.5) - 100; + m_ColorControl[3].DefaultValue = (int)floor(m_VMR9ColorControl[3].DefaultValue * 100 + 0.5) - 100; + m_ColorControl[3].StepSize = std::max(1, (int)(m_VMR9ColorControl[3].StepSize * 100 + 0.5)); + } + + // Brightness + if (m_ColorControl[0].MinValue < -100) { + m_ColorControl[0].MinValue = -100; + } + if (m_ColorControl[0].MaxValue > 100) { + m_ColorControl[0].MaxValue = 100; + } + // Contrast + if (m_ColorControl[1].MinValue == m_ColorControl[1].MaxValue) { // when ProcAmp is unsupported + m_ColorControl[1].MinValue = m_ColorControl[1].MaxValue = m_ColorControl[1].DefaultValue = 0; + } + if (m_ColorControl[1].MinValue < -100) { + m_ColorControl[1].MinValue = -100; + } + if (m_ColorControl[1].MaxValue > 100) { + m_ColorControl[1].MaxValue = 100; + } + // Hue + if (m_ColorControl[2].MinValue < -180) { + m_ColorControl[2].MinValue = -180; + } + if (m_ColorControl[2].MaxValue > 180) { + m_ColorControl[2].MaxValue = 180; + } + // Saturation + if (m_ColorControl[3].MinValue == m_ColorControl[3].MaxValue) { // when ProcAmp is unsupported + m_ColorControl[3].MinValue = m_ColorControl[3].MaxValue = m_ColorControl[3].DefaultValue = 0; + } + if (m_ColorControl[3].MinValue < -100) { + m_ColorControl[3].MinValue = -100; + } + if (m_ColorControl[3].MaxValue > 100) { + m_ColorControl[3].MaxValue = 100; + } +} + +VMR9ProcAmpControlRange* CMPlayerCApp::GetVMR9ColorControl(ControlType nFlag) +{ + switch (nFlag) { + case ProcAmp_Brightness: + return &m_VMR9ColorControl[0]; + case ProcAmp_Contrast: + return &m_VMR9ColorControl[1]; + case ProcAmp_Hue: + return &m_VMR9ColorControl[2]; + case ProcAmp_Saturation: + return &m_VMR9ColorControl[3]; + } + return nullptr; +} + +DXVA2_ValueRange* CMPlayerCApp::GetEVRColorControl(ControlType nFlag) +{ + switch (nFlag) { + case ProcAmp_Brightness: + return &m_EVRColorControl[0]; + case ProcAmp_Contrast: + return &m_EVRColorControl[1]; + case ProcAmp_Hue: + return &m_EVRColorControl[2]; + case ProcAmp_Saturation: + return &m_EVRColorControl[3]; + } + return nullptr; +} + +void CMPlayerCApp::RunAsAdministrator(LPCTSTR strCommand, LPCTSTR strArgs, bool bWaitProcess) +{ + SHELLEXECUTEINFO execinfo; + ZeroMemory(&execinfo, sizeof(execinfo)); + execinfo.lpFile = strCommand; + execinfo.cbSize = sizeof(execinfo); + execinfo.lpVerb = _T("runas"); + execinfo.fMask = SEE_MASK_NOCLOSEPROCESS; + execinfo.nShow = SW_SHOWDEFAULT; + execinfo.lpParameters = strArgs; + + ShellExecuteEx(&execinfo); + + if (bWaitProcess) { + WaitForSingleObject(execinfo.hProcess, INFINITE); + } +} + diff --git a/src/mpc-hc/mplayerc.h b/src/mpc-hc/mplayerc.h index 8ec7937dc75..30bb8e671fc 100644 --- a/src/mpc-hc/mplayerc.h +++ b/src/mpc-hc/mplayerc.h @@ -1,234 +1,234 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#ifndef __AFXWIN_H__ -#error include 'stdafx.h' before including this file for PCH -#endif - -#include "EventDispatcher.h" -#include "DpiHelper.h" -#include "AppSettings.h" -#include "../filters/renderer/VideoRenderers/RenderersSettings.h" -#include "resource.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#define MPC_WND_CLASS_NAME L"MediaPlayerClassicW" - -// define the default logo we use -#define DEF_LOGO IDF_LOGO3 - -#define MIN_MODERN_SEEKBAR_HEIGHT 8 -#define DEF_MODERN_SEEKBAR_HEIGHT 16 -#define MAX_MODERN_SEEKBAR_HEIGHT 64 - -#define MIN_TOOLBAR_HEIGHT 16 -#define DEF_TOOLBAR_HEIGHT 24 -#define MAX_TOOLBAR_HEIGHT 128 - - -#define MIN_FULLSCREEN_DELAY 0 -#define MAX_FULLSCREEN_DELAY 500 -#define MAX_REGKEY_LEN 255 - -extern HICON LoadIcon(CString fn, bool bSmallIcon, DpiHelper* pDpiHelper = nullptr); -extern bool LoadType(CString fn, CString& type); -extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); -extern CString GetContentType(CString fn, CAtlList* redir = nullptr); -extern WORD AssignedToCmd(UINT keyValue); -extern std::map GetAudioDeviceList(); -extern void SetAudioRenderer(int AudioDevNo); -extern void SetHandCursor(HWND m_hWnd, UINT nID); - -__inline DXVA2_Fixed32 IntToFixed(__in const int _int_, __in const short divisor = 1) -{ - // special converter that is resistant to MS bugs - DXVA2_Fixed32 _fixed_; - _fixed_.Value = SHORT(_int_ / divisor); - _fixed_.Fraction = USHORT((_int_ % divisor * 0x10000 + divisor / 2) / divisor); - return _fixed_; -} - -__inline int FixedToInt(__in const DXVA2_Fixed32& _fixed_, __in const short factor = 1) -{ - // special converter that is resistant to MS bugs - return (int)_fixed_.Value * factor + ((int)_fixed_.Fraction * factor + 0x8000) / 0x10000; -} - -enum { - WM_GRAPHNOTIFY = WM_RESET_DEVICE + 1, - WM_POSTOPEN, - WM_OPENFAILED, - WM_SAVESETTINGS, - WM_TUNER_SCAN_PROGRESS, - WM_TUNER_SCAN_END, - WM_TUNER_STATS, - WM_TUNER_NEW_CHANNEL, - WM_DVB_EIT_DATA_READY, - WM_LOADSUBTITLES, - WM_GETSUBTITLES, - WM_OSD_HIDE, - WM_OSD_DRAW, - WM_MPCVR_SWITCH_FULLSCREEN = WM_APP + 4096, -}; - -enum ControlType { - ProcAmp_Brightness = 0x1, - ProcAmp_Contrast = 0x2, - ProcAmp_Hue = 0x4, - ProcAmp_Saturation = 0x8, - ProcAmp_All = ProcAmp_Brightness | ProcAmp_Contrast | ProcAmp_Hue | ProcAmp_Saturation -}; - -struct COLORPROPERTY_RANGE { - DWORD dwProperty; - int MinValue; - int MaxValue; - int DefaultValue; - int StepSize; -}; - -class CAppSettings; - -class CMPlayerCApp : public CWinAppEx -{ - HMODULE m_hNTDLL; - - ATL::CMutex m_mutexOneInstance; - - CAtlList m_cmdln; - void PreProcessCommandLine(); - bool SendCommandLine(HWND hWnd); - UINT GetVKFromAppCommand(UINT nAppCommand); - - COLORPROPERTY_RANGE m_ColorControl[4]; - VMR9ProcAmpControlRange m_VMR9ColorControl[4]; - DXVA2_ValueRange m_EVRColorControl[4]; - - static UINT GetRemoteControlCodeMicrosoft(UINT nInputcode, HRAWINPUT hRawInput); - static UINT GetRemoteControlCodeSRM7500(UINT nInputcode, HRAWINPUT hRawInput); - - bool m_bDelayingIdle; - void DelayedIdle(); - virtual BOOL IsIdleMessage(MSG* pMsg) override; - virtual BOOL OnIdle(LONG lCount) override; - virtual BOOL PumpMessage() override; - -public: - CMPlayerCApp(); - ~CMPlayerCApp(); - - int DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT nIDPrompt); - - EventRouter m_eventd; - - void ShowCmdlnSwitches() const; - - bool StoreSettingsToIni(); - bool StoreSettingsToRegistry(); - CString GetIniPath() const; - bool IsIniValid() const; - bool ChangeSettingsLocation(bool useIni); - bool ExportSettings(CString savePath, CString subKey = _T("")); - -private: - std::map, CStringUtils::IgnoreCaseLess> m_ProfileMap; - bool m_bProfileInitialized; - bool m_bQueuedProfileFlush; - void InitProfile(); - std::recursive_mutex m_profileMutex; - ULONGLONG m_dwProfileLastAccessTick; - -public: - void FlushProfile(bool bForce = true); - virtual BOOL GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes) override; - virtual UINT GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) override; - - std::list GetSectionSubKeys(LPCWSTR lpszSection); - virtual CString GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = nullptr) override; - virtual BOOL WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes) override; - virtual LONG RemoveProfileKey(LPCWSTR lpszSection, LPCWSTR lpszEntry); - virtual BOOL WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) override; - virtual BOOL WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) override; - bool HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry); - std::vector GetProfileVectorInt(CString strSection, CString strKey); - void WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData); - - bool GetAppSavePath(CString& path); - bool GetAppDataPath(CString& path); - - bool m_fClosingState; - bool m_bThemeLoaded; - CRenderersData m_Renderers; - CString m_strVersion; - CString m_AudioRendererDisplayName_CL; - - std::unique_ptr m_s; - - typedef UINT(*PTR_GetRemoteControlCode)(UINT nInputcode, HRAWINPUT hRawInput); - - PTR_GetRemoteControlCode GetRemoteControlCode; - COLORPROPERTY_RANGE* GetColorControl(ControlType nFlag); - void ResetColorControlRange(); - void UpdateColorControlRange(bool isEVR); - VMR9ProcAmpControlRange* GetVMR9ColorControl(ControlType nFlag); - DXVA2_ValueRange* GetEVRColorControl(ControlType nFlag); - - static void RunAsAdministrator(LPCTSTR strCommand, LPCTSTR strArgs, bool bWaitProcess); - - void RegisterHotkeys(); - void UnregisterHotkeys(); - -public: - virtual BOOL InitInstance() override; - virtual int ExitInstance() override; - virtual BOOL SaveAllModified() override; - -public: - void SetClosingState(); - -public: - DECLARE_MESSAGE_MAP() - afx_msg void OnAppAbout(); - afx_msg void OnFileExit(); - afx_msg void OnHelpShowcommandlineswitches(); -}; - -#define AfxGetAppSettings() (*static_cast(AfxGetApp())->m_s.get()) -#define AfxGetMyApp() static_cast(AfxGetApp()) - -#define GetEventd() AfxGetMyApp()->m_eventd - -#define AppIsThemeLoaded() (static_cast(AfxGetApp())->m_bThemeLoaded) -#define AppNeedsThemedControls() (AppIsThemeLoaded() && CMPCTheme::drawThemedControls) - -#define AfxGetMainFrame() static_cast(AfxGetMainWnd()) -#define AfxFindMainFrame() dynamic_cast(AfxGetMainWnd()) +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#ifndef __AFXWIN_H__ +#error include 'stdafx.h' before including this file for PCH +#endif + +#include "EventDispatcher.h" +#include "DpiHelper.h" +#include "AppSettings.h" +#include "../filters/renderer/VideoRenderers/RenderersSettings.h" +#include "resource.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MPC_WND_CLASS_NAME L"MediaPlayerClassicW" + +// define the default logo we use +#define DEF_LOGO IDF_LOGO3 + +#define MIN_MODERN_SEEKBAR_HEIGHT 8 +#define DEF_MODERN_SEEKBAR_HEIGHT 16 +#define MAX_MODERN_SEEKBAR_HEIGHT 64 + +#define MIN_TOOLBAR_HEIGHT 16 +#define DEF_TOOLBAR_HEIGHT 24 +#define MAX_TOOLBAR_HEIGHT 128 + + +#define MIN_FULLSCREEN_DELAY 0 +#define MAX_FULLSCREEN_DELAY 500 +#define MAX_REGKEY_LEN 255 + +extern HICON LoadIcon(CString fn, bool bSmallIcon, DpiHelper* pDpiHelper = nullptr); +extern bool LoadType(CString fn, CString& type); +extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); +extern CString GetContentType(CString fn, CAtlList* redir = nullptr); +extern WORD AssignedToCmd(UINT keyValue); +extern std::map GetAudioDeviceList(); +extern void SetAudioRenderer(int AudioDevNo); +extern void SetHandCursor(HWND m_hWnd, UINT nID); + +__inline DXVA2_Fixed32 IntToFixed(__in const int _int_, __in const short divisor = 1) +{ + // special converter that is resistant to MS bugs + DXVA2_Fixed32 _fixed_; + _fixed_.Value = SHORT(_int_ / divisor); + _fixed_.Fraction = USHORT((_int_ % divisor * 0x10000 + divisor / 2) / divisor); + return _fixed_; +} + +__inline int FixedToInt(__in const DXVA2_Fixed32& _fixed_, __in const short factor = 1) +{ + // special converter that is resistant to MS bugs + return (int)_fixed_.Value * factor + ((int)_fixed_.Fraction * factor + 0x8000) / 0x10000; +} + +enum { + WM_GRAPHNOTIFY = WM_RESET_DEVICE + 1, + WM_POSTOPEN, + WM_OPENFAILED, + WM_SAVESETTINGS, + WM_TUNER_SCAN_PROGRESS, + WM_TUNER_SCAN_END, + WM_TUNER_STATS, + WM_TUNER_NEW_CHANNEL, + WM_DVB_EIT_DATA_READY, + WM_LOADSUBTITLES, + WM_GETSUBTITLES, + WM_OSD_HIDE, + WM_OSD_DRAW, + WM_MPCVR_SWITCH_FULLSCREEN = WM_APP + 4096, +}; + +enum ControlType { + ProcAmp_Brightness = 0x1, + ProcAmp_Contrast = 0x2, + ProcAmp_Hue = 0x4, + ProcAmp_Saturation = 0x8, + ProcAmp_All = ProcAmp_Brightness | ProcAmp_Contrast | ProcAmp_Hue | ProcAmp_Saturation +}; + +struct COLORPROPERTY_RANGE { + DWORD dwProperty; + int MinValue; + int MaxValue; + int DefaultValue; + int StepSize; +}; + +class CAppSettings; + +class CMPlayerCApp : public CWinAppEx +{ + HMODULE m_hNTDLL; + + ATL::CMutex m_mutexOneInstance; + + CAtlList m_cmdln; + void PreProcessCommandLine(); + bool SendCommandLine(HWND hWnd); + UINT GetVKFromAppCommand(UINT nAppCommand); + + COLORPROPERTY_RANGE m_ColorControl[4]; + VMR9ProcAmpControlRange m_VMR9ColorControl[4]; + DXVA2_ValueRange m_EVRColorControl[4]; + + static UINT GetRemoteControlCodeMicrosoft(UINT nInputcode, HRAWINPUT hRawInput); + static UINT GetRemoteControlCodeSRM7500(UINT nInputcode, HRAWINPUT hRawInput); + + bool m_bDelayingIdle; + void DelayedIdle(); + virtual BOOL IsIdleMessage(MSG* pMsg) override; + virtual BOOL OnIdle(LONG lCount) override; + virtual BOOL PumpMessage() override; + +public: + CMPlayerCApp(); + ~CMPlayerCApp(); + + int DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT nIDPrompt); + + EventRouter m_eventd; + + void ShowCmdlnSwitches() const; + + bool StoreSettingsToIni(); + bool StoreSettingsToRegistry(); + CString GetIniPath() const; + bool IsIniValid() const; + bool ChangeSettingsLocation(bool useIni); + bool ExportSettings(CString savePath, CString subKey = _T("")); + +private: + std::map, CStringUtils::IgnoreCaseLess> m_ProfileMap; + bool m_bProfileInitialized; + bool m_bQueuedProfileFlush; + void InitProfile(); + std::recursive_mutex m_profileMutex; + ULONGLONG m_dwProfileLastAccessTick; + +public: + void FlushProfile(bool bForce = true); + virtual BOOL GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes) override; + virtual UINT GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) override; + + std::list GetSectionSubKeys(LPCWSTR lpszSection); + virtual CString GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = nullptr) override; + virtual BOOL WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes) override; + virtual LONG RemoveProfileKey(LPCWSTR lpszSection, LPCWSTR lpszEntry); + virtual BOOL WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) override; + virtual BOOL WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) override; + bool HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry); + std::vector GetProfileVectorInt(CString strSection, CString strKey); + void WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData); + + bool GetAppSavePath(CString& path); + bool GetAppDataPath(CString& path); + + bool m_fClosingState; + bool m_bThemeLoaded; + CRenderersData m_Renderers; + CString m_strVersion; + CString m_AudioRendererDisplayName_CL; + + std::unique_ptr m_s; + + typedef UINT(*PTR_GetRemoteControlCode)(UINT nInputcode, HRAWINPUT hRawInput); + + PTR_GetRemoteControlCode GetRemoteControlCode; + COLORPROPERTY_RANGE* GetColorControl(ControlType nFlag); + void ResetColorControlRange(); + void UpdateColorControlRange(bool isEVR); + VMR9ProcAmpControlRange* GetVMR9ColorControl(ControlType nFlag); + DXVA2_ValueRange* GetEVRColorControl(ControlType nFlag); + + static void RunAsAdministrator(LPCTSTR strCommand, LPCTSTR strArgs, bool bWaitProcess); + + void RegisterHotkeys(); + void UnregisterHotkeys(); + +public: + virtual BOOL InitInstance() override; + virtual int ExitInstance() override; + virtual BOOL SaveAllModified() override; + +public: + void SetClosingState(); + +public: + DECLARE_MESSAGE_MAP() + afx_msg void OnAppAbout(); + afx_msg void OnFileExit(); + afx_msg void OnHelpShowcommandlineswitches(); +}; + +#define AfxGetAppSettings() (*static_cast(AfxGetApp())->m_s.get()) +#define AfxGetMyApp() static_cast(AfxGetApp()) + +#define GetEventd() AfxGetMyApp()->m_eventd + +#define AppIsThemeLoaded() (static_cast(AfxGetApp())->m_bThemeLoaded) +#define AppNeedsThemedControls() (AppIsThemeLoaded() && CMPCTheme::drawThemedControls) + +#define AfxGetMainFrame() static_cast(AfxGetMainWnd()) +#define AfxFindMainFrame() dynamic_cast(AfxGetMainWnd()) diff --git a/src/mpc-hc/res/mpc-hc.exe.manifest.conf b/src/mpc-hc/res/mpc-hc.exe.manifest.conf index 09930765368..80eb1e293ce 100644 --- a/src/mpc-hc/res/mpc-hc.exe.manifest.conf +++ b/src/mpc-hc/res/mpc-hc.exe.manifest.conf @@ -1,45 +1,45 @@ - - - - MPC-HC - - - - - - - - - - - - - - - - - - - - - - - - True/PM - PerMonitorV2, PerMonitor - true - - + + + + MPC-HC + + + + + + + + + + + + + + + + + + + + + + + + True/PM + PerMonitorV2, PerMonitor + true + + \ No newline at end of file diff --git a/src/mpc-hc/res/shaders/empty.psh b/src/mpc-hc/res/shaders/empty.psh index dc2fa90b3e7..8578320e26e 100644 --- a/src/mpc-hc/res/shaders/empty.psh +++ b/src/mpc-hc/res/shaders/empty.psh @@ -1,17 +1,17 @@ -sampler s0 : register(s0); -float4 p0 : register(c0); -float4 p1 : register(c1); - -#define width (p0[0]) -#define height (p0[1]) -#define counter (p0[2]) -#define clock (p0[3]) -#define one_over_width (p1[0]) -#define one_over_height (p1[1]) -#define PI acos(-1) - -float4 main(float2 tex : TEXCOORD0) : COLOR { - float4 c0 = tex2D(s0, tex); - - return c0; -} +sampler s0 : register(s0); +float4 p0 : register(c0); +float4 p1 : register(c1); + +#define width (p0[0]) +#define height (p0[1]) +#define counter (p0[2]) +#define clock (p0[3]) +#define one_over_width (p1[0]) +#define one_over_height (p1[1]) +#define PI acos(-1) + +float4 main(float2 tex : TEXCOORD0) : COLOR { + float4 c0 = tex2D(s0, tex); + + return c0; +} diff --git a/src/mpc-hc/res/shaders/final.psh b/src/mpc-hc/res/shaders/final.psh index c39b5078ea6..1070d4cac0d 100644 --- a/src/mpc-hc/res/shaders/final.psh +++ b/src/mpc-hc/res/shaders/final.psh @@ -1,29 +1,29 @@ -#define LUT3D_ENABLED (_LUT3D_ENABLED_VALUE_) - -sampler image : register(s0); - -sampler ditherMatrix : register(s1); -float2 ditherMatrixCoordScale : register(c0); - -// Maximum quantized integer value -static const float QUANTIZATION = _QUANTIZATION_VALUE_; - -#if LUT3D_ENABLED -sampler lut3D : register(s2); -static const float LUT3D_SIZE = _LUT3D_SIZE_VALUE_; - -// 3D LUT texture coordinate scale and offset required for correct linear interpolation -static const float LUT3D_SCALE = (LUT3D_SIZE - 1.0f) / LUT3D_SIZE; -static const float LUT3D_OFFSET = 1.0f / (2.0f * LUT3D_SIZE); -#endif - -float4 main(float2 imageCoord : TEXCOORD0) : COLOR { - float4 pixel = tex2D(image, imageCoord); - -#if LUT3D_ENABLED - pixel = tex3D(lut3D, pixel.rgb * LUT3D_SCALE + LUT3D_OFFSET); -#endif - - float4 ditherValue = tex2D(ditherMatrix, imageCoord * ditherMatrixCoordScale); - return floor(pixel * QUANTIZATION + ditherValue) / QUANTIZATION; -} +#define LUT3D_ENABLED (_LUT3D_ENABLED_VALUE_) + +sampler image : register(s0); + +sampler ditherMatrix : register(s1); +float2 ditherMatrixCoordScale : register(c0); + +// Maximum quantized integer value +static const float QUANTIZATION = _QUANTIZATION_VALUE_; + +#if LUT3D_ENABLED +sampler lut3D : register(s2); +static const float LUT3D_SIZE = _LUT3D_SIZE_VALUE_; + +// 3D LUT texture coordinate scale and offset required for correct linear interpolation +static const float LUT3D_SCALE = (LUT3D_SIZE - 1.0f) / LUT3D_SIZE; +static const float LUT3D_OFFSET = 1.0f / (2.0f * LUT3D_SIZE); +#endif + +float4 main(float2 imageCoord : TEXCOORD0) : COLOR { + float4 pixel = tex2D(image, imageCoord); + +#if LUT3D_ENABLED + pixel = tex3D(lut3D, pixel.rgb * LUT3D_SCALE + LUT3D_OFFSET); +#endif + + float4 ditherValue = tex2D(ditherMatrix, imageCoord * ditherMatrixCoordScale); + return floor(pixel * QUANTIZATION + ditherValue) / QUANTIZATION; +} diff --git a/src/mpc-hc/res/shaders/resizer.psh b/src/mpc-hc/res/shaders/resizer.psh index 180bce84cd0..9a45f678dbf 100644 --- a/src/mpc-hc/res/shaders/resizer.psh +++ b/src/mpc-hc/res/shaders/resizer.psh @@ -1,115 +1,115 @@ -sampler s0 : register(s0); -sampler s1 : register(s1); -sampler s2 : register(s2); -sampler s3 : register(s3); -sampler s4 : register(s4); - -float4 dxdy05 : register(c0); -float2 dxdy : register(c1); -float2 dx : register(c2); -float2 dy : register(c3); - -#define A _The_Value_Of_A_Is_Set_Here_ - -// none of the resizers here can be used for 1:1 mapping! -// tex * size won't be 0, 1, 2, 3, ... as you might expect, but something like 0, 0.999, 2.001, 2.999, ... -// this means when the fractional part becomes 0.999 we will be interpolating with the wrong value!!! - -struct PS_INPUT { - float2 t0 : TEXCOORD0; - float2 t1 : TEXCOORD1; - float2 t2 : TEXCOORD2; - float2 t3 : TEXCOORD3; - float2 t4 : TEXCOORD4; -}; - -float4 main_bilinear(PS_INPUT input) : COLOR { - float2 PixelPos = input.t0; - float2 dd = frac(PixelPos); - float2 ExactPixel = PixelPos - dd; - float2 samplePos = ExactPixel * dxdy + dxdy05; - - float4 c = lerp( - lerp(tex2D(s0, samplePos), tex2D(s0, samplePos + dx), dd.x), - lerp(tex2D(s0, samplePos + dy), tex2D(s0, samplePos + dxdy), dd.x), - dd.y); - - return c; -} - -static float4x4 tco = { - 0, A, -2 * A, A, - 1, 0, -A - 3, A + 2, - 0, -A, 2 * A + 3, -A - 2, - 0, 0, A, -A -}; - -float4 taps(float t) -{ - return mul(tco, float4(1, t, t * t, t * t * t)); -} - -float4 SampleX(float4 tx, float2 t0) -{ - return - mul(tx, - float4x4( - tex2D(s0, t0 - dx), - tex2D(s0, t0), - tex2D(s0, t0 + dx), - tex2D(s0, t0 + dx + dx) - ) - ); -} - -float4 SampleY(float4 tx, float4 ty, float2 t0) -{ - return - mul(ty, - float4x4( - SampleX(tx, t0 - dy), - SampleX(tx, t0), - SampleX(tx, t0 + dy), - SampleX(tx, t0 + dy + dy) - ) - ); -} - -float4 main_bicubic1pass(PS_INPUT input) : COLOR { - float2 PixelPos = input.t0; - float2 dd = frac(PixelPos); - float2 ExactPixel = PixelPos - dd; - float2 samplePos = ExactPixel * dxdy + dxdy05; - return SampleY(taps(dd.x), taps(dd.y), samplePos); -} - -float4 Sample(float4 t, float2 samplePos, float2 sampleD) -{ - return - mul(t, - float4x4( - tex2D(s0, samplePos - sampleD), - tex2D(s0, samplePos), - tex2D(s0, samplePos + sampleD), - tex2D(s0, samplePos + sampleD + sampleD) - ) - ); -} - -float4 main_bicubic2pass_pass1(PS_INPUT input) : COLOR { - float2 PixelPos = input.t0; - float2 dd = frac(PixelPos); - float2 ExactPixel = PixelPos - dd; - float2 samplePos = ExactPixel * dxdy + dxdy05; - - return Sample(taps(dd.x), samplePos, dx); -} - -float4 main_bicubic2pass_pass2(PS_INPUT input) : COLOR { - float2 PixelPos = input.t0; - float2 dd = frac(PixelPos); - float2 ExactPixel = PixelPos - dd; - float2 samplePos = ExactPixel * dxdy + dxdy05; - - return Sample(taps(dd.y), samplePos, dy); -} +sampler s0 : register(s0); +sampler s1 : register(s1); +sampler s2 : register(s2); +sampler s3 : register(s3); +sampler s4 : register(s4); + +float4 dxdy05 : register(c0); +float2 dxdy : register(c1); +float2 dx : register(c2); +float2 dy : register(c3); + +#define A _The_Value_Of_A_Is_Set_Here_ + +// none of the resizers here can be used for 1:1 mapping! +// tex * size won't be 0, 1, 2, 3, ... as you might expect, but something like 0, 0.999, 2.001, 2.999, ... +// this means when the fractional part becomes 0.999 we will be interpolating with the wrong value!!! + +struct PS_INPUT { + float2 t0 : TEXCOORD0; + float2 t1 : TEXCOORD1; + float2 t2 : TEXCOORD2; + float2 t3 : TEXCOORD3; + float2 t4 : TEXCOORD4; +}; + +float4 main_bilinear(PS_INPUT input) : COLOR { + float2 PixelPos = input.t0; + float2 dd = frac(PixelPos); + float2 ExactPixel = PixelPos - dd; + float2 samplePos = ExactPixel * dxdy + dxdy05; + + float4 c = lerp( + lerp(tex2D(s0, samplePos), tex2D(s0, samplePos + dx), dd.x), + lerp(tex2D(s0, samplePos + dy), tex2D(s0, samplePos + dxdy), dd.x), + dd.y); + + return c; +} + +static float4x4 tco = { + 0, A, -2 * A, A, + 1, 0, -A - 3, A + 2, + 0, -A, 2 * A + 3, -A - 2, + 0, 0, A, -A +}; + +float4 taps(float t) +{ + return mul(tco, float4(1, t, t * t, t * t * t)); +} + +float4 SampleX(float4 tx, float2 t0) +{ + return + mul(tx, + float4x4( + tex2D(s0, t0 - dx), + tex2D(s0, t0), + tex2D(s0, t0 + dx), + tex2D(s0, t0 + dx + dx) + ) + ); +} + +float4 SampleY(float4 tx, float4 ty, float2 t0) +{ + return + mul(ty, + float4x4( + SampleX(tx, t0 - dy), + SampleX(tx, t0), + SampleX(tx, t0 + dy), + SampleX(tx, t0 + dy + dy) + ) + ); +} + +float4 main_bicubic1pass(PS_INPUT input) : COLOR { + float2 PixelPos = input.t0; + float2 dd = frac(PixelPos); + float2 ExactPixel = PixelPos - dd; + float2 samplePos = ExactPixel * dxdy + dxdy05; + return SampleY(taps(dd.x), taps(dd.y), samplePos); +} + +float4 Sample(float4 t, float2 samplePos, float2 sampleD) +{ + return + mul(t, + float4x4( + tex2D(s0, samplePos - sampleD), + tex2D(s0, samplePos), + tex2D(s0, samplePos + sampleD), + tex2D(s0, samplePos + sampleD + sampleD) + ) + ); +} + +float4 main_bicubic2pass_pass1(PS_INPUT input) : COLOR { + float2 PixelPos = input.t0; + float2 dd = frac(PixelPos); + float2 ExactPixel = PixelPos - dd; + float2 samplePos = ExactPixel * dxdy + dxdy05; + + return Sample(taps(dd.x), samplePos, dx); +} + +float4 main_bicubic2pass_pass2(PS_INPUT input) : COLOR { + float2 PixelPos = input.t0; + float2 dd = frac(PixelPos); + float2 ExactPixel = PixelPos - dd; + float2 samplePos = ExactPixel * dxdy + dxdy05; + + return Sample(taps(dd.y), samplePos, dy); +} diff --git a/src/mpc-hc/res/web/404.html b/src/mpc-hc/res/web/404.html index 805f6ecc58d..b5f8769984c 100644 --- a/src/mpc-hc/res/web/404.html +++ b/src/mpc-hc/res/web/404.html @@ -1,14 +1,14 @@ - - - - - MPC-HC WebServer - Page Not Found - - - - -

Page Not Found

-

Sorry, but the page you were trying to view does not exist.

-[debug] - - + + + + + MPC-HC WebServer - Page Not Found + + + + +

Page Not Found

+

Sorry, but the page you were trying to view does not exist.

+[debug] + + diff --git a/src/mpc-hc/res/web/browser.html b/src/mpc-hc/res/web/browser.html index 22da98397c9..f78ff0620c7 100644 --- a/src/mpc-hc/res/web/browser.html +++ b/src/mpc-hc/res/web/browser.html @@ -1,33 +1,33 @@ - - - - - MPC-HC WebServer - File Browser - - - - -
- - - - -
- Location: [currentdir] -
-
-   -
- - - - - - - - [currentfiles] -
NameTypeSizeDate Modified
-
-[debug] - - + + + + + MPC-HC WebServer - File Browser + + + + +
+ + + + +
+ Location: [currentdir] +
+
+   +
+ + + + + + + + [currentfiles] +
NameTypeSizeDate Modified
+
+[debug] + + diff --git a/src/mpc-hc/res/web/controls.html b/src/mpc-hc/res/web/controls.html index a31b8edf5a5..2cbd44e5d0e 100644 --- a/src/mpc-hc/res/web/controls.html +++ b/src/mpc-hc/res/web/controls.html @@ -1,1204 +1,1204 @@ - - - - - MPC-HC WebServer - Controls - - - - - - -
- File Info - - - - - - - - - - -
- Loaded file: - [filepath] - Browse... -
Status: [statestring] - - - - - - -
[positionstring]/[durationstring]
-
- - -
- -
-
-
-
-
-
- - Goto control - - - - - - - - -
- - - - - - -
1pixslidergrip1pix
-
- - - - - - -
-
-
-
-
- - - - - -
Playback control - - - - - - - - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
-
 Seek - - - - - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
-
-
-
- - - - - - - - - -
Volume control - - - - - - - - - - -
-
- - -
-
- - - - - -
- - - - - - -
1pixvbs1pix
-
- -
-
- - -
- - -
-
-
- - -
-
-
 Playlist - - - - - -
-
- - -
-
-
- - -
-
-
 Panic Button - - - - -
-
- - -
-
-
 Audio Delay - - - - - -
-
- - -
-
-
- - -
-
-
-
-
-
- - - - - -
Pan&Scan Move - - - - - - - - - - - - - - - - -
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
 Pan&Scan Size - - - - - - - - - - - - - -
  - - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
-
-
-
- - - - - - -
Video Frame - - - - - - - - - - - - - -
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
DVD Menu Controler - - - - - - - - - - - - - - - -
  - - - - -
-
- - -
-
-
 
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
 Misc - - - - - - - - - - - - - - - -
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
-
-
-
- - - - - - -
Zoom control - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
 Fullscreen control - - - - - -
-
- - -
-
-
- - -
-
-
-
-
-
- - - - - - -
Player views - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
Detachable Controls - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
-
-
- - - - -
Generic Audio/Subtitles - - - - - - - - -
-
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
-
-
-
-
- - - - - - -
Subtitles - - - - - -
-
- - -
-
-
- - -
-
-
 DVD Angles/Audio/Subtitles - - - - - - - - - - - -
-
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
-
-
-
-
- - - - - - -
DVD Menus - - - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
 MPC-HC's Menus - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
-
-
-
- Always On Top - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-[debug] - - + + + + + MPC-HC WebServer - Controls + + + + + + +
+ File Info + + + + + + + + + + +
+ Loaded file: + [filepath] + Browse... +
Status: [statestring] + + + + + + +
[positionstring]/[durationstring]
+
+ + +
+ +
+
+
+
+
+
+ + Goto control + + + + + + + + +
+ + + + + + +
1pixslidergrip1pix
+
+ + + + + + +
+
+
+
+
+ + + + + +
Playback control + + + + + + + + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
+
 Seek + + + + + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + + + + +
Volume control + + + + + + + + + + +
+
+ + +
+
+ + + + + +
+ + + + + + +
1pixvbs1pix
+
+ +
+
+ + +
+ + +
+
+
+ + +
+
+
 Playlist + + + + + +
+
+ + +
+
+
+ + +
+
+
 Panic Button + + + + +
+
+ + +
+
+
 Audio Delay + + + + + +
+
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + +
Pan&Scan Move + + + + + + + + + + + + + + + + +
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
 Pan&Scan Size + + + + + + + + + + + + + +
  + + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
+
+
+
+ + + + + + +
Video Frame + + + + + + + + + + + + + +
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
DVD Menu Controler + + + + + + + + + + + + + + + +
  + + + + +
+
+ + +
+
+
 
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
 Misc + + + + + + + + + + + + + + + +
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
+
+
+
+ + + + + + +
Zoom control + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
 Fullscreen control + + + + + +
+
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + +
Player views + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
Detachable Controls + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+
+
+ + + + +
Generic Audio/Subtitles + + + + + + + + +
+
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + +
Subtitles + + + + + +
+
+ + +
+
+
+ + +
+
+
 DVD Angles/Audio/Subtitles + + + + + + + + + + + +
+
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + +
DVD Menus + + + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
 MPC-HC's Menus + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+
+
+
+ Always On Top + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+[debug] + + diff --git a/src/mpc-hc/res/web/default.css b/src/mpc-hc/res/web/default.css index f004c480380..e88faed5f49 100644 --- a/src/mpc-hc/res/web/default.css +++ b/src/mpc-hc/res/web/default.css @@ -1,350 +1,350 @@ -/*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ -progress,sub,sup{vertical-align:baseline} -button,hr,input,select{overflow:visible} -[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0} -html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} -body{margin:0} -article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block} -audio,canvas,progress,video{display:inline-block} -audio:not([controls]){display:none;height:0} -[hidden],template{display:none} -a{background-color:transparent} -a:active,a:hover{outline-width:0} -abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted} -b,strong{font-weight:bolder} -dfn{font-style:italic} -h1{font-size:2em;margin:.67em 0} -mark{background-color:#ff0;color:#000} -small{font-size:80%} -sub,sup{font-size:75%;line-height:0;position:relative} -sub{bottom:-.25em} -sup{top:-.5em} -img{border-style:none} -svg:not(:root){overflow:hidden} -code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em} -figure{margin:1em 40px} -hr{box-sizing:content-box;height:0} -button,input,select,textarea{font:inherit;margin:0} -optgroup{font-weight:700} -button,select{text-transform:none} -[type=button],[type=reset],[type=submit],button{cursor:pointer} -[disabled]{cursor:default} -[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button} -button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} -button:-moz-focusring,input:-moz-focusring{outline:ButtonText dotted 1px} -fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} -legend{color:inherit;display:table;max-width:100%;white-space:normal} -textarea{overflow:auto} -[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto} -[type=search]{-webkit-appearance:textfield} -[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none} -/* END OF normalize.css v4.0.0 */ - - -/* common */ -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -body { - font: 14px Arial, Verdana, Helvetica, Sans-Serif; -} - -img { - margin: 0; - padding: 0; -} - -.text-center { - text-align: center; -} - -.text-right { - text-align: right; -} - -.browser-warning { - background-color: red; - padding: 10px; -} - - -/* browser.html */ -.browser-table { - border-collapse: collapse; - width: 100%; -} - -.browser-table, -.browser-table th, -.browser-table td { - border: 2px solid black; - padding: 4px; -} - -.browser-table th { - font-weight: bold; - white-space: nowrap; -} - -.browser-table th:first-child { - width: 100%; -} - -.dirname { - font-weight: bold; -} - - - -/* controls.html */ -td, -th { - padding: 0; -} -#slider { - background: url(img/sliderback.png) no-repeat; - width: 515px; - height: 20px; -} - -#slider img { - cursor: pointer; -} - -#v { - background: url(img/vbg.png) no-repeat; - width: 110px; - height: 20px; - cursor: pointer; -} - -#v img { - cursor: pointer; -} - -#muted { - min-width: 29px; -} - -.nobr { - white-space: nowrap; -} - -form input { - min-width: 20px; - min-height: 24px; - vertical-align: middle; -} - - - -/* player.html */ -#player { - margin: 0 auto; -} - -#player, -#player table, -#player td, -#player th { - border-collapse: separate; - border-spacing: 0; - padding: 0; -} - -#player td { - font: 13px Sans-Serif; -} - -#header td { - height: 30px; -} - -#headerIcon { - background: url(img/headericon.png) no-repeat; - width: 22px; -} - -#headerBack { - background: url(img/headerback.png) repeat-x; - color: white; - font-weight: bold !important; -} - -#headerClose { - background: url(img/headerclose.png) no-repeat; - width: 28px; -} - -#durstr, -#posstr, -#status, -#title { - display: inline; -} - -#menu td { - font-size: 12px; - padding: 2px 6px; -} - -#menu-help { - width: 100%; -} - -#controlbar, -#menu { - background-color: #ECE6D4; - width: 100%; -} - -#statusbar { - padding: 4px 2px 1px 2px !important; - width: 100%; -} - -#statusbar td { - font-size: 12px; -} - -#statusbar, -#video { - background-color: black; - color: white; -} - -#video { - cursor: pointer; -} - -#snapshot { - margin-bottom: -4px; -} - -#controlbar { - background: url(img/controlback.png) repeat-x; - height: 28px; -} - -#controlbuttonplay { - background: url(img/controlbuttonplay.png) no-repeat; - width: 25px; - height: 28px; - cursor: pointer; -} - -#controlbuttonpause { - background: url(img/controlbuttonpause.png) no-repeat; - width: 23px; - height: 28px; - cursor: pointer; -} - -#controlbuttonstop { - background: url(img/controlbuttonstop.png) no-repeat; - width: 25px; - height: 28px; - cursor: pointer; -} - -#controlbuttonskipback { - background: url(img/controlbuttonskipback.png) no-repeat; - width: 24px; - height: 28px; - cursor: pointer; -} - -#controlbuttondecrate { - background: url(img/controlbuttondecrate.png) no-repeat; - width: 22px; - height: 28px; - cursor: pointer; -} - -#controlbuttonincrate { - background: url(img/controlbuttonincrate.png) no-repeat; - width: 23px; - height: 28px; - cursor: pointer; -} - -#controlbuttonskipforward { - background: url(img/controlbuttonskipforward.png) no-repeat; - width: 28px; - height: 28px; - cursor: pointer; -} - -#controlbuttonstep { - background: url(img/controlbuttonstep.png) no-repeat; - width: 31px; - height: 28px; - cursor: pointer; -} - -#controlvolumemute { - background: url(img/controlvolumeon.png) no-repeat; - width: 28px; - height: 28px; - cursor: pointer; -} - -#controlvolumebar { - background: url(img/controlvolumebar.png) no-repeat; - width: 55px; - height: 28px; - cursor: pointer; -} - -#seekbar { - background: url(img/seekbarmid.png) repeat-x; - margin-top: 1px; - width: 100%; - cursor: pointer; -} - -#seekbar td { - font-size: 0; -} - -#leftside { - background: url(img/leftside.png) repeat-y; - width: 4px; -} - -#rightside { - background: url(img/rightside.png) repeat-y; - width: 4px; -} - -#leftbottomside { - background: url(img/leftbottomside.png) repeat-x; - width: 4px; - height: 4px; -} - -#bottomside { - background: url(img/bottomside.png) repeat-x; - height: 4px; -} - -#rightbottomside { - background: url(img/rightbottomside.png) repeat-x; - width: 4px; - height: 4px; -} - -#center, -#header { - width: 100%; -} +/*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ +progress,sub,sup{vertical-align:baseline} +button,hr,input,select{overflow:visible} +[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0} +html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} +body{margin:0} +article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block} +audio,canvas,progress,video{display:inline-block} +audio:not([controls]){display:none;height:0} +[hidden],template{display:none} +a{background-color:transparent} +a:active,a:hover{outline-width:0} +abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted} +b,strong{font-weight:bolder} +dfn{font-style:italic} +h1{font-size:2em;margin:.67em 0} +mark{background-color:#ff0;color:#000} +small{font-size:80%} +sub,sup{font-size:75%;line-height:0;position:relative} +sub{bottom:-.25em} +sup{top:-.5em} +img{border-style:none} +svg:not(:root){overflow:hidden} +code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em} +figure{margin:1em 40px} +hr{box-sizing:content-box;height:0} +button,input,select,textarea{font:inherit;margin:0} +optgroup{font-weight:700} +button,select{text-transform:none} +[type=button],[type=reset],[type=submit],button{cursor:pointer} +[disabled]{cursor:default} +[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button} +button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} +button:-moz-focusring,input:-moz-focusring{outline:ButtonText dotted 1px} +fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} +legend{color:inherit;display:table;max-width:100%;white-space:normal} +textarea{overflow:auto} +[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto} +[type=search]{-webkit-appearance:textfield} +[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none} +/* END OF normalize.css v4.0.0 */ + + +/* common */ +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +body { + font: 14px Arial, Verdana, Helvetica, Sans-Serif; +} + +img { + margin: 0; + padding: 0; +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.browser-warning { + background-color: red; + padding: 10px; +} + + +/* browser.html */ +.browser-table { + border-collapse: collapse; + width: 100%; +} + +.browser-table, +.browser-table th, +.browser-table td { + border: 2px solid black; + padding: 4px; +} + +.browser-table th { + font-weight: bold; + white-space: nowrap; +} + +.browser-table th:first-child { + width: 100%; +} + +.dirname { + font-weight: bold; +} + + + +/* controls.html */ +td, +th { + padding: 0; +} +#slider { + background: url(img/sliderback.png) no-repeat; + width: 515px; + height: 20px; +} + +#slider img { + cursor: pointer; +} + +#v { + background: url(img/vbg.png) no-repeat; + width: 110px; + height: 20px; + cursor: pointer; +} + +#v img { + cursor: pointer; +} + +#muted { + min-width: 29px; +} + +.nobr { + white-space: nowrap; +} + +form input { + min-width: 20px; + min-height: 24px; + vertical-align: middle; +} + + + +/* player.html */ +#player { + margin: 0 auto; +} + +#player, +#player table, +#player td, +#player th { + border-collapse: separate; + border-spacing: 0; + padding: 0; +} + +#player td { + font: 13px Sans-Serif; +} + +#header td { + height: 30px; +} + +#headerIcon { + background: url(img/headericon.png) no-repeat; + width: 22px; +} + +#headerBack { + background: url(img/headerback.png) repeat-x; + color: white; + font-weight: bold !important; +} + +#headerClose { + background: url(img/headerclose.png) no-repeat; + width: 28px; +} + +#durstr, +#posstr, +#status, +#title { + display: inline; +} + +#menu td { + font-size: 12px; + padding: 2px 6px; +} + +#menu-help { + width: 100%; +} + +#controlbar, +#menu { + background-color: #ECE6D4; + width: 100%; +} + +#statusbar { + padding: 4px 2px 1px 2px !important; + width: 100%; +} + +#statusbar td { + font-size: 12px; +} + +#statusbar, +#video { + background-color: black; + color: white; +} + +#video { + cursor: pointer; +} + +#snapshot { + margin-bottom: -4px; +} + +#controlbar { + background: url(img/controlback.png) repeat-x; + height: 28px; +} + +#controlbuttonplay { + background: url(img/controlbuttonplay.png) no-repeat; + width: 25px; + height: 28px; + cursor: pointer; +} + +#controlbuttonpause { + background: url(img/controlbuttonpause.png) no-repeat; + width: 23px; + height: 28px; + cursor: pointer; +} + +#controlbuttonstop { + background: url(img/controlbuttonstop.png) no-repeat; + width: 25px; + height: 28px; + cursor: pointer; +} + +#controlbuttonskipback { + background: url(img/controlbuttonskipback.png) no-repeat; + width: 24px; + height: 28px; + cursor: pointer; +} + +#controlbuttondecrate { + background: url(img/controlbuttondecrate.png) no-repeat; + width: 22px; + height: 28px; + cursor: pointer; +} + +#controlbuttonincrate { + background: url(img/controlbuttonincrate.png) no-repeat; + width: 23px; + height: 28px; + cursor: pointer; +} + +#controlbuttonskipforward { + background: url(img/controlbuttonskipforward.png) no-repeat; + width: 28px; + height: 28px; + cursor: pointer; +} + +#controlbuttonstep { + background: url(img/controlbuttonstep.png) no-repeat; + width: 31px; + height: 28px; + cursor: pointer; +} + +#controlvolumemute { + background: url(img/controlvolumeon.png) no-repeat; + width: 28px; + height: 28px; + cursor: pointer; +} + +#controlvolumebar { + background: url(img/controlvolumebar.png) no-repeat; + width: 55px; + height: 28px; + cursor: pointer; +} + +#seekbar { + background: url(img/seekbarmid.png) repeat-x; + margin-top: 1px; + width: 100%; + cursor: pointer; +} + +#seekbar td { + font-size: 0; +} + +#leftside { + background: url(img/leftside.png) repeat-y; + width: 4px; +} + +#rightside { + background: url(img/rightside.png) repeat-y; + width: 4px; +} + +#leftbottomside { + background: url(img/leftbottomside.png) repeat-x; + width: 4px; + height: 4px; +} + +#bottomside { + background: url(img/bottomside.png) repeat-x; + height: 4px; +} + +#rightbottomside { + background: url(img/rightbottomside.png) repeat-x; + width: 4px; + height: 4px; +} + +#center, +#header { + width: 100%; +} diff --git a/src/mpc-hc/res/web/index.html b/src/mpc-hc/res/web/index.html index b1a43c005fd..2d3980ca4a0 100644 --- a/src/mpc-hc/res/web/index.html +++ b/src/mpc-hc/res/web/index.html @@ -1,25 +1,25 @@ - - - - - MPC-HC WebServer - - - - -

Demo page; submit patches if you want this page updated.

-

And if you are already here, why don't you try sending a few commands to MPC-HC, just to see if it works :)

-
-
- - -
-
-

File browser

-

The media player interface made by chobits

-

MPC-HC in the browser

-

Info page

-

Variables page

-[debug] - - + + + + + MPC-HC WebServer + + + + +

Demo page; submit patches if you want this page updated.

+

And if you are already here, why don't you try sending a few commands to MPC-HC, just to see if it works :)

+
+
+ + +
+
+

File browser

+

The media player interface made by chobits

+

MPC-HC in the browser

+

Info page

+

Variables page

+[debug] + + diff --git a/src/mpc-hc/res/web/info.html b/src/mpc-hc/res/web/info.html index 7653385b80f..81ea463e77c 100644 --- a/src/mpc-hc/res/web/info.html +++ b/src/mpc-hc/res/web/info.html @@ -1,14 +1,14 @@ - - - - - MPC-HC WebServer - Info - - - - - -

« MPC-HC v[version] • [file] • [position]/[duration] • [size] »

-[debug] - - + + + + + MPC-HC WebServer - Info + + + + + +

« MPC-HC v[version] • [file] • [position]/[duration] • [size] »

+[debug] + + diff --git a/src/mpc-hc/res/web/javascript.js b/src/mpc-hc/res/web/javascript.js index 0b65eab1fe9..508b23909cd 100644 --- a/src/mpc-hc/res/web/javascript.js +++ b/src/mpc-hc/res/web/javascript.js @@ -1,574 +1,574 @@ -/* jshint browser:true, camelcase:true, curly:true, es3:true, eqeqeq:true, - immed:true, indent:4, latedef:true, quotmark:double, strict:true, undef:true, - unused:true */ - -/* global ActiveXObject */ -/* exported controlsInit, positionUpdate, onLoadSnapshot, onAbortErrorSnapshot, - onCommand, playerInit */ - - -var filePath; -var curPos; -var len; -var state; -var pbr; -var eta; -var volume; -var muted; // 1 no sound -var startTime = new Date().getTime(); -var sliderSize = 500; -var sliderButtonWidth = 15; -var vsb = 10; -var vss = 100; -var vs; -var sc = 0; -var rdirt; -var Live; -var re; -var sas; -var cpf; -var cp; -var s; -var m; -var sb1; -var sb2; -var sb3; -var vs1; -var vs2; -var vs3; -var etaup = false; -var httpRequestStatus; - - -// common functions -function getById(id) { - "use strict"; - return document.getElementById(id); -} - -function getOffsetX(m) { - "use strict"; - var x = m.offsetLeft; - while (m.offsetParent) { - x += (m = m.offsetParent).offsetLeft; - } - return x; -} - - -// controls.html -function timeSyntax(ts) { - "use strict"; - var b = ""; - for (var a = 0, len = ts.length; a < len; a++) { - switch (ts.charAt(a)) { - case "0": - b += "0"; - break; - case "1": - b += "1"; - break; - case "2": - b += "2"; - break; - case "3": - b += "3"; - break; - case "4": - b += "4"; - break; - case "5": - b += "5"; - break; - case "6": - b += "6"; - break; - case "7": - b += "7"; - break; - case "8": - b += "8"; - break; - case "9": - b += "9"; - break; - case ".": - b += "."; - break; - case ":": - b += ":"; - break; - default: - break; - } - } - return b; -} - -function parseTime(y) { - "use strict"; - var ts = timeSyntax(y); - var t = 0; - var p1 = ts.indexOf("."); - var p2 = ts.indexOf(":"); - var p3 = ts.indexOf(":", p2 + 1); - var p4 = ts.indexOf(":", p3 + 1); - - if (p4 !== -1 || (p1 !== -1 && p2 !== -1 && p2 > p1) || (p1 !== -1 && p3 !== -1 && p3 > p1)) { - return -2000; - } - if (p1 === -1) { - p1 = ts.length + 1; - } else { - p1 = p1; - } - if (p2 === -1) { - t = parseFloat((ts + " ").substring(0, p1 + 4)); - } - if (p2 !== -1 && p3 === -1) { - t = parseInt(ts.substring(0, p2), 10) * 60 + parseFloat("0" + (ts + " ").substring(p2 + 1, p1 + 4)); - } - if (p2 !== -1 && p3 !== -1) { - t = parseInt(ts.substring(0, p2), 10) * 3600 + parseInt(ts.substring(p2 + 1, p3), 10) * 60 + parseFloat("0" + (ts + " ").substring(p3 + 1, p1 + 4)); - } - return t; -} - -function update(a, b) { - "use strict"; - if (a === -2000) { - return false; - } - if (b) { - if (a > len && !Live) { - curPos = len; - } else { - curPos = a < 0 ? 0 : a; - } - m = curPos * sliderSize / len; - } else { - if (a > sliderSize) { - m = sliderSize; - } else { - m = a < 0 ? 0 : a; - } - curPos = m * len / sliderSize; - } - if (m > sb1.width) { - sb3.width = sliderSize - Math.floor(m); - sb1.width = m; - } else { - sb1.width = m; - sb3.width = sliderSize - sb1.width; - } - return true; -} - -function pad(number, len) { - "use strict"; - var str = String(number); - while (str.length < len) { - str = "0" + str; - } - return str; -} - -function secondsToTS(a, b) { - "use strict"; - var a1 = Math.floor(a / 3600000); - var a2 = Math.floor(a / 60000) % 60; - var a3 = Math.floor(a / 1000) % 60; - var a4 = Math.floor(a) % 1000; - var a1s = pad(a1.toString(), 2); - var a2s = pad(a2.toString(), 2); - var a3s = pad(a3.toString(), 2); - var a4s = pad(a4.toString(), 3); - - switch (b) { - case 1: - return a1s; - case 2: - return a2s; - case 3: - return a3s; - case 4: - return a4s; - case 5: - case 6: - case 7: - return a1s + ":" + a2s + ":" + a3s; - default: - return ((a1 > 0 ? (a1s + ":") : "") + a2s + ":" + a3s); - } -} - -function postForm(wmc, ext, extv) { - "use strict"; - getById("fwmc").value = wmc; - getById("fextra").value = extv; - getById("fextra").name = ext; - getById("ef").submit(); - return true; -} - -function autoplay(a) { - "use strict"; - if (etaup && re.checked === true) { - etaup = false; - setTimeout(function () { - etaup = true; - if (re.checked === true) { - postForm(0, "null", 0); - } - }, 5000); - } - setTimeout(autoplay, rdirt); - var ct = new Date().getTime(); - var cap = pbr * (ct - startTime); - if (cap > len && !Live) { - if (re.checked === true) { - setTimeout(function () { - window.location = window.location; - }, 5000); - } - } - cap = ((cap > len && !Live) ? len : (cap < 0 ? 0 : cap)); - if (sas.checked === true || a === true) { - update(cap, true); - cpf.value = secondsToTS(cap, 5); - } - var gg = " " + secondsToTS(cap, 5) + " "; - cp.innerHTML = gg; - return true; -} - -function sliderClick(e) { - "use strict"; - update((window.event ? window.event.clientX - 3 : e.clientX) + document.body.scrollLeft - getOffsetX(s) - Math.floor(sliderButtonWidth / 2) + sc, false); - cpf.value = secondsToTS(curPos, 5); - sas.checked = false; - return true; -} - -function volumeUpdate(a, b) { - "use strict"; - if (b) { - if (a > 100) { - volume = 100; - } else { - volume = a < 0 ? 0 : a; - } - m = volume * vss / 100; - } else { - if (a > vss) { - m = vss; - } else { - m = a < 0 ? 0 : a; - } - volume = m * 100 / vss; - } - volume = Math.ceil(volume); - vs1.width = m; - vs3.width = vss - vs1.width; - return true; -} - -function volSliderClick(e) { - "use strict"; - var ret = volumeUpdate((window.event ? window.event.clientX - 3 : e.clientX) + document.body.scrollLeft - getOffsetX(vs) - Math.floor(vsb / 2) + sc, false); - return ret; -} - - -if (eta === 0) { - if (state < 0 && filePath.length > 0) { - eta = 2; - } else { - eta = 120; - } -} - -function controlsInit(_filePath, _curPos, _length, _state, _pbr, _eta, _volume, _muted) { - "use strict"; - filePath = decodeURIComponent(_filePath); - curPos = _curPos; - len = _length; - state = _state; - pbr = _pbr; - eta = _eta; - volume = _volume; - muted = _muted; - - if (eta > 0) { - setTimeout(function () { - etaup = true; - if (re.checked === true) { - postForm(0, "null", 0); - } - }, 1000 * eta); - } - Live = len < 1; - startTime -= curPos; - rdirt = len * pbr / sliderSize; - rdirt = Math.floor(rdirt > 1000 ? 1000 : (rdirt < 300 ? 300 : rdirt)); - cpf = getById("pos"); - cp = getById("time"); - sas = getById("SliderAutoScroll"); - re = getById("reloadenabled"); - s = getById("slider"); - sb1 = getById("c1"); - sb2 = getById("c2"); - sb3 = getById("c3"); - vs = getById("v"); - vs1 = getById("v1"); - vs2 = getById("v2"); - vs3 = getById("v3"); - - if (muted === 1) { - getById("muted").innerHTML = "M"; - } - vs2.title = volume; - sb2.title = secondsToTS(curPos, 5); - s.height = sb1.height = sb2.height = sb3.height = vs.height = vs1.height = vs2.height = vs3.height = 20; - s.width = sliderSize + (sb2.width = sliderButtonWidth); - vs.width = vss + (vs2.width = vsb); - sb1.onclick = sb2.onclick = sb3.onclick = sliderClick; - vs1.onclick = vs2.onclick = vs3.onclick = volSliderClick; - sas.checked = true; - cp.innerHTML = cpf.value = secondsToTS(curPos, 5); - if (state === 2 && pbr !== 0) { - autoplay(); - } - volumeUpdate(volume, true); - return update(curPos, true); -} - -function positionUpdate() { - "use strict"; - if (event.keyCode < 46 || event.keyCode > 58 || event.keyCode === 47) { - return false; - } - setTimeout(function () { - update(parseFloat(parseTime(cpf.value)), true); - }, 1); - return true; -} - - -// player.html -function getXMLHTTP() { - "use strict"; - try { - return new ActiveXObject("Msxml2.XMLHTTP"); - } catch (e) { - try { - return new ActiveXObject("Microsoft.XMLHTTP"); - } catch (err) {} - } - if (typeof XMLHttpRequest !== "undefined") { - return new XMLHttpRequest(); - } - return null; -} - -function makeRequest(req) { - "use strict"; - var httpRequest = getXMLHTTP(); - try { - httpRequest.open("GET", req, true); - httpRequest.send(null); - } catch (e) {} -} - -function onStatus (title, status, pos, posStr, dur, durStr, muted, volume) { - "use strict"; - var maxTitle = 70; - var timestr; - var el; - - if (dur > 0 && posStr && durStr) { - timestr = posStr + " / " + durStr; - } else { - timestr = " "; - } - - if (title.length > maxTitle) { - title = title.substr(0, maxTitle - 3) + "…"; - } - if (!dur || dur === 0) { - dur = 1; - } - - el = getById("title"); - if (el) { - el.innerHTML = title; - } - - var sbpercent = Math.floor(100 * pos / dur); - el = getById("seekbarchleft"); - if (el) { - el.width = sbpercent > 0 ? sbpercent + "%" : "1px"; - } - - el = getById("seekbarchright"); - if (el) { - el.width = sbpercent < 100 ? (100 - sbpercent) + "%" : "1px"; - } - - el = getById("seekbargrip"); - if (el) { - el.title = posStr; - } - - el = getById("status"); - if (el && el.innerHTML !== status) { - el.innerHTML = status; - } - - el = getById("timer"); - if (el && el.innerHTML !== timestr) { - el.innerHTML = timestr; - } - - el = getById("controlvolumemute"); - if (el) { - var url = "url(img/controlvolume" + (muted ? "off" : "on") + ".png)"; - if (el.style.backgroundImage !== url) { - el.style.backgroundImage = url; - } - } - - el = getById("controlvolumegrip"); - if (el) { - el.title = volume; - volume = (getById("controlvolumebar").offsetWidth - el.offsetWidth) * volume / 100; - el.style.position = "relative"; - el.style.top = "2px"; - el.style.left = Math.floor(volume) + "px"; - } -} - -function onReadyStateChange() { - "use strict"; - var statusRegExp = /OnStatus\("(.*)", "(.*)", (\d+), "(.*)", (\d+), "(.*)", (\d+), (\d+), "(.*)"\)/; - - if (httpRequestStatus && httpRequestStatus.readyState === 4 && httpRequestStatus.responseText) { - if (httpRequestStatus.responseText.charAt(0) !== "<") { - var params = statusRegExp.exec(httpRequestStatus.responseText); - onStatus(params[1], params[2], parseInt(params[3], 10), params[4], parseInt(params[5], 10), params[6], parseInt(params[7], 10), parseInt(params[8], 10), params[9]); - } else { - alert(httpRequestStatus.responseText); - } - httpRequestStatus = null; - } -} - -function statusLoop() { - "use strict"; - - if (!httpRequestStatus || httpRequestStatus.readyState === 0) { - httpRequestStatus = getXMLHTTP(); - try { - httpRequestStatus.open("GET", "status.html", true); - httpRequestStatus.onreadystatechange = onReadyStateChange; - httpRequestStatus.send(null); - } catch (e) {} - } - setTimeout(statusLoop, 500); -} - -var snapshotCounter = 0; - -function loadSnapshot() { - "use strict"; - var img = getById("snapshot"); - if (img) { - img.src = "snapshot.jpg?" + snapshotCounter++; - } -} - -function onLoadSnapshot() { - "use strict"; - setTimeout(loadSnapshot, 500); -} - -function onAbortErrorSnapshot() { - "use strict"; - setTimeout(loadSnapshot, 5000); -} - -function onSeek(e) { - "use strict"; - var left = 0; - var right = 0; - var percent; - var sb; - - sb = getById("seekbarchleft"); - if (sb) { - left = getOffsetX(sb); - } - - sb = getById("seekbarchright"); - if (sb) { - right = getOffsetX(sb) + sb.offsetWidth; - } - - sb = getById("seekbargrip"); - if (sb) { - left += sb.offsetWidth / 2; - right -= sb.offsetWidth / 2; - } - if (left > 0 && left < right) { - percent = 100 * ((window.event ? window.event.clientX : e.clientX) - left) / (right - left); - if (percent < 0) { - percent = 0; - } else if (percent > 100) { - percent = 100; - } - makeRequest("command.html?wm_command=[setposcommand]&percent=" + percent); - } -} - -function onVolume(e) { - "use strict"; - var left = 0; - var right = 0; - var percent; - var cv = getById("controlvolumebar"); - - if (cv) { - left = getOffsetX(cv) + 3; - right = getOffsetX(cv) + cv.offsetWidth - 3; - } - if (left > 0 && left < right) { - percent = 100 * ((window.event ? window.event.clientX : e.clientX) - left) / (right - left); - if (percent < 0) { - percent = 0; - } else if (percent > 100) { - percent = 100; - } - makeRequest("command.html?wm_command=[setvolumecommand]&volume=" + percent); - } -} - -function onCommand(id) { - "use strict"; - makeRequest("command.html?wm_command=" + id); -} - -function playerInit() { - "use strict"; - statusLoop(); - loadSnapshot(); - - var el = getById("seekbar"); - if (el) { - el.onclick = onSeek; - } - - el = getById("controlvolumebar"); - if (el) { - el.onclick = onVolume; - } -} +/* jshint browser:true, camelcase:true, curly:true, es3:true, eqeqeq:true, + immed:true, indent:4, latedef:true, quotmark:double, strict:true, undef:true, + unused:true */ + +/* global ActiveXObject */ +/* exported controlsInit, positionUpdate, onLoadSnapshot, onAbortErrorSnapshot, + onCommand, playerInit */ + + +var filePath; +var curPos; +var len; +var state; +var pbr; +var eta; +var volume; +var muted; // 1 no sound +var startTime = new Date().getTime(); +var sliderSize = 500; +var sliderButtonWidth = 15; +var vsb = 10; +var vss = 100; +var vs; +var sc = 0; +var rdirt; +var Live; +var re; +var sas; +var cpf; +var cp; +var s; +var m; +var sb1; +var sb2; +var sb3; +var vs1; +var vs2; +var vs3; +var etaup = false; +var httpRequestStatus; + + +// common functions +function getById(id) { + "use strict"; + return document.getElementById(id); +} + +function getOffsetX(m) { + "use strict"; + var x = m.offsetLeft; + while (m.offsetParent) { + x += (m = m.offsetParent).offsetLeft; + } + return x; +} + + +// controls.html +function timeSyntax(ts) { + "use strict"; + var b = ""; + for (var a = 0, len = ts.length; a < len; a++) { + switch (ts.charAt(a)) { + case "0": + b += "0"; + break; + case "1": + b += "1"; + break; + case "2": + b += "2"; + break; + case "3": + b += "3"; + break; + case "4": + b += "4"; + break; + case "5": + b += "5"; + break; + case "6": + b += "6"; + break; + case "7": + b += "7"; + break; + case "8": + b += "8"; + break; + case "9": + b += "9"; + break; + case ".": + b += "."; + break; + case ":": + b += ":"; + break; + default: + break; + } + } + return b; +} + +function parseTime(y) { + "use strict"; + var ts = timeSyntax(y); + var t = 0; + var p1 = ts.indexOf("."); + var p2 = ts.indexOf(":"); + var p3 = ts.indexOf(":", p2 + 1); + var p4 = ts.indexOf(":", p3 + 1); + + if (p4 !== -1 || (p1 !== -1 && p2 !== -1 && p2 > p1) || (p1 !== -1 && p3 !== -1 && p3 > p1)) { + return -2000; + } + if (p1 === -1) { + p1 = ts.length + 1; + } else { + p1 = p1; + } + if (p2 === -1) { + t = parseFloat((ts + " ").substring(0, p1 + 4)); + } + if (p2 !== -1 && p3 === -1) { + t = parseInt(ts.substring(0, p2), 10) * 60 + parseFloat("0" + (ts + " ").substring(p2 + 1, p1 + 4)); + } + if (p2 !== -1 && p3 !== -1) { + t = parseInt(ts.substring(0, p2), 10) * 3600 + parseInt(ts.substring(p2 + 1, p3), 10) * 60 + parseFloat("0" + (ts + " ").substring(p3 + 1, p1 + 4)); + } + return t; +} + +function update(a, b) { + "use strict"; + if (a === -2000) { + return false; + } + if (b) { + if (a > len && !Live) { + curPos = len; + } else { + curPos = a < 0 ? 0 : a; + } + m = curPos * sliderSize / len; + } else { + if (a > sliderSize) { + m = sliderSize; + } else { + m = a < 0 ? 0 : a; + } + curPos = m * len / sliderSize; + } + if (m > sb1.width) { + sb3.width = sliderSize - Math.floor(m); + sb1.width = m; + } else { + sb1.width = m; + sb3.width = sliderSize - sb1.width; + } + return true; +} + +function pad(number, len) { + "use strict"; + var str = String(number); + while (str.length < len) { + str = "0" + str; + } + return str; +} + +function secondsToTS(a, b) { + "use strict"; + var a1 = Math.floor(a / 3600000); + var a2 = Math.floor(a / 60000) % 60; + var a3 = Math.floor(a / 1000) % 60; + var a4 = Math.floor(a) % 1000; + var a1s = pad(a1.toString(), 2); + var a2s = pad(a2.toString(), 2); + var a3s = pad(a3.toString(), 2); + var a4s = pad(a4.toString(), 3); + + switch (b) { + case 1: + return a1s; + case 2: + return a2s; + case 3: + return a3s; + case 4: + return a4s; + case 5: + case 6: + case 7: + return a1s + ":" + a2s + ":" + a3s; + default: + return ((a1 > 0 ? (a1s + ":") : "") + a2s + ":" + a3s); + } +} + +function postForm(wmc, ext, extv) { + "use strict"; + getById("fwmc").value = wmc; + getById("fextra").value = extv; + getById("fextra").name = ext; + getById("ef").submit(); + return true; +} + +function autoplay(a) { + "use strict"; + if (etaup && re.checked === true) { + etaup = false; + setTimeout(function () { + etaup = true; + if (re.checked === true) { + postForm(0, "null", 0); + } + }, 5000); + } + setTimeout(autoplay, rdirt); + var ct = new Date().getTime(); + var cap = pbr * (ct - startTime); + if (cap > len && !Live) { + if (re.checked === true) { + setTimeout(function () { + window.location = window.location; + }, 5000); + } + } + cap = ((cap > len && !Live) ? len : (cap < 0 ? 0 : cap)); + if (sas.checked === true || a === true) { + update(cap, true); + cpf.value = secondsToTS(cap, 5); + } + var gg = " " + secondsToTS(cap, 5) + " "; + cp.innerHTML = gg; + return true; +} + +function sliderClick(e) { + "use strict"; + update((window.event ? window.event.clientX - 3 : e.clientX) + document.body.scrollLeft - getOffsetX(s) - Math.floor(sliderButtonWidth / 2) + sc, false); + cpf.value = secondsToTS(curPos, 5); + sas.checked = false; + return true; +} + +function volumeUpdate(a, b) { + "use strict"; + if (b) { + if (a > 100) { + volume = 100; + } else { + volume = a < 0 ? 0 : a; + } + m = volume * vss / 100; + } else { + if (a > vss) { + m = vss; + } else { + m = a < 0 ? 0 : a; + } + volume = m * 100 / vss; + } + volume = Math.ceil(volume); + vs1.width = m; + vs3.width = vss - vs1.width; + return true; +} + +function volSliderClick(e) { + "use strict"; + var ret = volumeUpdate((window.event ? window.event.clientX - 3 : e.clientX) + document.body.scrollLeft - getOffsetX(vs) - Math.floor(vsb / 2) + sc, false); + return ret; +} + + +if (eta === 0) { + if (state < 0 && filePath.length > 0) { + eta = 2; + } else { + eta = 120; + } +} + +function controlsInit(_filePath, _curPos, _length, _state, _pbr, _eta, _volume, _muted) { + "use strict"; + filePath = decodeURIComponent(_filePath); + curPos = _curPos; + len = _length; + state = _state; + pbr = _pbr; + eta = _eta; + volume = _volume; + muted = _muted; + + if (eta > 0) { + setTimeout(function () { + etaup = true; + if (re.checked === true) { + postForm(0, "null", 0); + } + }, 1000 * eta); + } + Live = len < 1; + startTime -= curPos; + rdirt = len * pbr / sliderSize; + rdirt = Math.floor(rdirt > 1000 ? 1000 : (rdirt < 300 ? 300 : rdirt)); + cpf = getById("pos"); + cp = getById("time"); + sas = getById("SliderAutoScroll"); + re = getById("reloadenabled"); + s = getById("slider"); + sb1 = getById("c1"); + sb2 = getById("c2"); + sb3 = getById("c3"); + vs = getById("v"); + vs1 = getById("v1"); + vs2 = getById("v2"); + vs3 = getById("v3"); + + if (muted === 1) { + getById("muted").innerHTML = "M"; + } + vs2.title = volume; + sb2.title = secondsToTS(curPos, 5); + s.height = sb1.height = sb2.height = sb3.height = vs.height = vs1.height = vs2.height = vs3.height = 20; + s.width = sliderSize + (sb2.width = sliderButtonWidth); + vs.width = vss + (vs2.width = vsb); + sb1.onclick = sb2.onclick = sb3.onclick = sliderClick; + vs1.onclick = vs2.onclick = vs3.onclick = volSliderClick; + sas.checked = true; + cp.innerHTML = cpf.value = secondsToTS(curPos, 5); + if (state === 2 && pbr !== 0) { + autoplay(); + } + volumeUpdate(volume, true); + return update(curPos, true); +} + +function positionUpdate() { + "use strict"; + if (event.keyCode < 46 || event.keyCode > 58 || event.keyCode === 47) { + return false; + } + setTimeout(function () { + update(parseFloat(parseTime(cpf.value)), true); + }, 1); + return true; +} + + +// player.html +function getXMLHTTP() { + "use strict"; + try { + return new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) { + try { + return new ActiveXObject("Microsoft.XMLHTTP"); + } catch (err) {} + } + if (typeof XMLHttpRequest !== "undefined") { + return new XMLHttpRequest(); + } + return null; +} + +function makeRequest(req) { + "use strict"; + var httpRequest = getXMLHTTP(); + try { + httpRequest.open("GET", req, true); + httpRequest.send(null); + } catch (e) {} +} + +function onStatus (title, status, pos, posStr, dur, durStr, muted, volume) { + "use strict"; + var maxTitle = 70; + var timestr; + var el; + + if (dur > 0 && posStr && durStr) { + timestr = posStr + " / " + durStr; + } else { + timestr = " "; + } + + if (title.length > maxTitle) { + title = title.substr(0, maxTitle - 3) + "…"; + } + if (!dur || dur === 0) { + dur = 1; + } + + el = getById("title"); + if (el) { + el.innerHTML = title; + } + + var sbpercent = Math.floor(100 * pos / dur); + el = getById("seekbarchleft"); + if (el) { + el.width = sbpercent > 0 ? sbpercent + "%" : "1px"; + } + + el = getById("seekbarchright"); + if (el) { + el.width = sbpercent < 100 ? (100 - sbpercent) + "%" : "1px"; + } + + el = getById("seekbargrip"); + if (el) { + el.title = posStr; + } + + el = getById("status"); + if (el && el.innerHTML !== status) { + el.innerHTML = status; + } + + el = getById("timer"); + if (el && el.innerHTML !== timestr) { + el.innerHTML = timestr; + } + + el = getById("controlvolumemute"); + if (el) { + var url = "url(img/controlvolume" + (muted ? "off" : "on") + ".png)"; + if (el.style.backgroundImage !== url) { + el.style.backgroundImage = url; + } + } + + el = getById("controlvolumegrip"); + if (el) { + el.title = volume; + volume = (getById("controlvolumebar").offsetWidth - el.offsetWidth) * volume / 100; + el.style.position = "relative"; + el.style.top = "2px"; + el.style.left = Math.floor(volume) + "px"; + } +} + +function onReadyStateChange() { + "use strict"; + var statusRegExp = /OnStatus\("(.*)", "(.*)", (\d+), "(.*)", (\d+), "(.*)", (\d+), (\d+), "(.*)"\)/; + + if (httpRequestStatus && httpRequestStatus.readyState === 4 && httpRequestStatus.responseText) { + if (httpRequestStatus.responseText.charAt(0) !== "<") { + var params = statusRegExp.exec(httpRequestStatus.responseText); + onStatus(params[1], params[2], parseInt(params[3], 10), params[4], parseInt(params[5], 10), params[6], parseInt(params[7], 10), parseInt(params[8], 10), params[9]); + } else { + alert(httpRequestStatus.responseText); + } + httpRequestStatus = null; + } +} + +function statusLoop() { + "use strict"; + + if (!httpRequestStatus || httpRequestStatus.readyState === 0) { + httpRequestStatus = getXMLHTTP(); + try { + httpRequestStatus.open("GET", "status.html", true); + httpRequestStatus.onreadystatechange = onReadyStateChange; + httpRequestStatus.send(null); + } catch (e) {} + } + setTimeout(statusLoop, 500); +} + +var snapshotCounter = 0; + +function loadSnapshot() { + "use strict"; + var img = getById("snapshot"); + if (img) { + img.src = "snapshot.jpg?" + snapshotCounter++; + } +} + +function onLoadSnapshot() { + "use strict"; + setTimeout(loadSnapshot, 500); +} + +function onAbortErrorSnapshot() { + "use strict"; + setTimeout(loadSnapshot, 5000); +} + +function onSeek(e) { + "use strict"; + var left = 0; + var right = 0; + var percent; + var sb; + + sb = getById("seekbarchleft"); + if (sb) { + left = getOffsetX(sb); + } + + sb = getById("seekbarchright"); + if (sb) { + right = getOffsetX(sb) + sb.offsetWidth; + } + + sb = getById("seekbargrip"); + if (sb) { + left += sb.offsetWidth / 2; + right -= sb.offsetWidth / 2; + } + if (left > 0 && left < right) { + percent = 100 * ((window.event ? window.event.clientX : e.clientX) - left) / (right - left); + if (percent < 0) { + percent = 0; + } else if (percent > 100) { + percent = 100; + } + makeRequest("command.html?wm_command=[setposcommand]&percent=" + percent); + } +} + +function onVolume(e) { + "use strict"; + var left = 0; + var right = 0; + var percent; + var cv = getById("controlvolumebar"); + + if (cv) { + left = getOffsetX(cv) + 3; + right = getOffsetX(cv) + cv.offsetWidth - 3; + } + if (left > 0 && left < right) { + percent = 100 * ((window.event ? window.event.clientX : e.clientX) - left) / (right - left); + if (percent < 0) { + percent = 0; + } else if (percent > 100) { + percent = 100; + } + makeRequest("command.html?wm_command=[setvolumecommand]&volume=" + percent); + } +} + +function onCommand(id) { + "use strict"; + makeRequest("command.html?wm_command=" + id); +} + +function playerInit() { + "use strict"; + statusLoop(); + loadSnapshot(); + + var el = getById("seekbar"); + if (el) { + el.onclick = onSeek; + } + + el = getById("controlvolumebar"); + if (el) { + el.onclick = onVolume; + } +} diff --git a/src/mpc-hc/res/web/player.html b/src/mpc-hc/res/web/player.html index dc306314e17..1216e91026e 100644 --- a/src/mpc-hc/res/web/player.html +++ b/src/mpc-hc/res/web/player.html @@ -1,109 +1,109 @@ - - - - - MPC-HC WebServer - Player - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - - -
- - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- [preview] -
- - - - - - - - -
seekbarleftseekbargripseekbarright
-
- - - - - - - - - - - - - - -
  - control volume grip -
-
- - - - - -
 
-
-
-
-[debug] - - + + + + + MPC-HC WebServer - Player + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ [preview] +
+ + + + + + + + +
seekbarleftseekbargripseekbarright
+
+ + + + + + + + + + + + + + +
  + control volume grip +
+
+ + + + + +
 
+
+
+
+[debug] + + diff --git a/src/mpc-hc/res/web/variables.html b/src/mpc-hc/res/web/variables.html index a831d33acf4..36cddffe29c 100644 --- a/src/mpc-hc/res/web/variables.html +++ b/src/mpc-hc/res/web/variables.html @@ -1,31 +1,31 @@ - - - - - MPC-HC WebServer - Variables - - - - -

[file]

-

[filepatharg]

-

[filepath]

-

[filedirarg]

-

[filedir]

-

[state]

-

[statestring]

-

[position]

-

[positionstring]

-

[duration]

-

[durationstring]

-

[volumelevel]

-

[muted]

-

[playbackrate]

-

[size]

-

[reloadtime]

-

[version]

-

[audiotrack]

-

[subtitletrack]

-[debug] - - + + + + + MPC-HC WebServer - Variables + + + + +

[file]

+

[filepatharg]

+

[filepath]

+

[filedirarg]

+

[filedir]

+

[state]

+

[statestring]

+

[position]

+

[positionstring]

+

[duration]

+

[durationstring]

+

[volumelevel]

+

[muted]

+

[playbackrate]

+

[size]

+

[reloadtime]

+

[version]

+

[audiotrack]

+

[subtitletrack]

+[debug] + + diff --git a/src/mpc-hc/resource.h b/src/mpc-hc/resource.h index 0cd406fd264..f7b1fd1de46 100644 --- a/src/mpc-hc/resource.h +++ b/src/mpc-hc/resource.h @@ -1,1770 +1,1770 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by mpc-hc.rc -// -#define IDR_MAINFRAME 128 -#define IDR_POPUP 130 -#define IDR_POPUPMAIN 133 -#define IDB_PLAYERTOOLBAR 201 -#define IDB_AUDIOTYPE_NOAUDIO 202 -#define IDB_AUDIOTYPE_MONO 203 -#define IDB_AUDIOTYPE_STEREO 204 -#define IDB_CHECKBOX 205 -#define IDF_LOGO0 206 -#define IDF_LOGO1 207 -#define IDF_LOGO2 208 -#define IDF_LOGO3 209 -#define IDF_TICKCROSS 210 -#define IDB_STREAMTYPES 215 -#define IDB_SHADER_UP 216 -#define IDB_SHADER_DOWN 217 -#define IDB_SHADER_DEL 218 -#define IDB_CHECK_ALL 219 -#define IDB_UNCHECK_ALL 220 -#define IDB_CHECK_AUDIO 221 -#define IDB_CHECK_VIDEO 222 -#define IDI_SINGLE 300 -#define IDI_MULTI 301 -#define IDI_DVD 302 -#define IDI_AUDIOCD 303 -#define IDI_UNKNOWN 304 -#define IDR_AVI_FILECOPY 400 -#define IDR_HTML_INFO 500 -#define IDR_HTML_INDEX 501 -#define IDR_HTML_404 502 -#define IDR_HTML_BROWSER 503 -#define IDR_HTML_CONTROLS 504 -#define IDR_HTML_PLAYER 505 -#define IDF_DEFAULT_CSS 506 -#define IDF_VBR_PNG 507 -#define IDF_VBS_PNG 508 -#define IDF_SLIDERGRIP_PNG 509 -#define IDF_1PIX_PNG 510 -#define IDF_SLIDERBACK_PNG 511 -#define IDF_HEADERICON_PNG 512 -#define IDF_HEADERBACK_PNG 513 -#define IDF_HEADERCLOSE_PNG 514 -#define IDF_LEFTSIDE_PNG 515 -#define IDF_RIGHTSIDE_PNG 516 -#define IDF_BOTTOMSIDE_PNG 517 -#define IDF_LEFTBOTTOMSIDE_PNG 518 -#define IDF_RIGHTBOTTOMSIDE_PNG 519 -#define IDF_SEEKBARLEFT_PNG 520 -#define IDF_SEEKBARMID_PNG 521 -#define IDF_SEEKBARRIGHT_PNG 522 -#define IDF_SEEKBARGRIP_PNG 523 -#define IDF_CONTROLBACK_PNG 524 -#define IDF_CONTROLBUTTONPLAY_PNG 525 -#define IDF_CONTROLBUTTONPAUSE_PNG 526 -#define IDF_CONTROLBUTTONSTOP_PNG 527 -#define IDF_CONTROLBUTTONSKIPBACK_PNG 528 -#define IDF_CONTROLBUTTONDECRATE_PNG 529 -#define IDF_CONTROLBUTTONINCRATE_PNG 530 -#define IDF_CONTROLBUTTONSKIPFORWARD_PNG 531 -#define IDF_CONTROLBUTTONSTEP_PNG 532 -#define IDF_CONTROLVOLUMEON_PNG 533 -#define IDF_CONTROLVOLUMEOFF_PNG 534 -#define IDF_CONTROLVOLUMEBAR_PNG 535 -#define IDF_CONTROLVOLUMEGRIP_PNG 536 -#define IDR_HTML_VARIABLES 537 -#define IDF_JAVASCRIPT 538 -#define IDF_FAVICON 539 -#define IDF_SHADER_RESIZER 700 -#define IDF_SHADER_EMPTY 701 -#define IDF_SHADER_FINAL 702 -#define IDF_SVG_TOOLBAR 703 -#define IDF_SVG_BUTTONS 704 -#define IDF_SVG_ARROW 705 -#define ID_FILE_OPENMEDIA 800 -#define ID_FILE_OPENDVDBD 801 -#define ID_FILE_OPENDEVICE 802 -#define ID_FILE_CLOSEMEDIA 803 -#define ID_FILE_CLOSE_AND_RESTORE 804 -#define ID_FILE_SAVE_COPY 805 -#define ID_FILE_SAVE_IMAGE 806 -#define ID_FILE_SAVE_IMAGE_AUTO 807 -#define ID_FILE_SAVE_THUMBNAILS 808 -#define ID_FILE_SUBTITLES_LOAD 809 -#define ID_FILE_SUBTITLES_SAVE 810 -#define ID_FILE_SUBTITLES_DOWNLOAD 812 -#define ID_VIEW_ZOOM_25 813 -#define ID_FILE_PROPERTIES 814 -#define ID_VIEW_OPTIONS 815 -#define ID_FILE_EXIT 816 -#define ID_VIEW_CAPTIONMENU 817 -#define ID_VIEW_SEEKER 818 -#define ID_VIEW_CONTROLS 819 -#define ID_VIEW_INFORMATION 820 -#define ID_VIEW_STATISTICS 821 -#define ID_VIEW_STATUS 822 -#define ID_VIEW_SUBRESYNC 823 -#define ID_VIEW_PLAYLIST 824 -#define ID_VIEW_CAPTURE 825 -#define ID_VIEW_DEBUGSHADERS 826 -#define ID_VIEW_PRESETS_MINIMAL 827 -#define ID_VIEW_PRESETS_COMPACT 828 -#define ID_VIEW_PRESETS_NORMAL 829 -#define ID_VIEW_FULLSCREEN 830 -#define ID_VIEW_FULLSCREEN_SECONDARY 831 -#define ID_VIEW_ZOOM_50 832 -#define ID_VIEW_ZOOM_100 833 -#define ID_VIEW_ZOOM_200 834 -#define ID_VIEW_VF_HALF 835 -#define ID_VIEW_VF_NORMAL 836 -#define ID_VIEW_VF_DOUBLE 837 -#define ID_VIEW_VF_STRETCH 838 -#define ID_VIEW_VF_FROMINSIDE 839 -#define ID_VIEW_VF_FROMOUTSIDE 840 -#define ID_VIEW_VF_ZOOM1 841 -#define ID_VIEW_VF_ZOOM2 842 -#define ID_VIEW_VF_SWITCHZOOM 843 -#define ID_VIEW_VF_COMPMONDESKARDIFF 845 -#define ID_VIEW_EDITLISTEDITOR 846 -#define ID_EDL_IN 847 -#define ID_EDL_OUT 848 -#define ID_EDL_NEWCLIP 849 -#define ID_ASPECTRATIO_START 850 -#define ID_ASPECTRATIO_DAR 850 -#define ID_ASPECTRATIO_4_3 851 -#define ID_ASPECTRATIO_5_4 852 -#define ID_ASPECTRATIO_16_9 853 -#define ID_ASPECTRATIO_235_100 854 -#define ID_ASPECTRATIO_185_100 855 -#define ID_ASPECTRATIO_SAR 856 -#define ID_ASPECTRATIO_END 856 -#define ID_ASPECTRATIO_NEXT 859 -#define ID_EDL_SAVE 860 -#define ID_VIEW_RESET 861 -#define ID_VIEW_INCSIZE 862 -#define ID_VIEW_DECSIZE 863 -#define ID_VIEW_INCWIDTH 864 -#define ID_VIEW_DECWIDTH 865 -#define ID_VIEW_INCHEIGHT 866 -#define ID_VIEW_DECHEIGHT 867 -#define ID_PANSCAN_MOVELEFT 868 -#define ID_PANSCAN_MOVERIGHT 869 -#define ID_PANSCAN_MOVEUP 870 -#define ID_PANSCAN_MOVEDOWN 871 -#define ID_PANSCAN_MOVEUPLEFT 872 -#define ID_PANSCAN_MOVEUPRIGHT 873 -#define ID_PANSCAN_MOVEDOWNLEFT 874 -#define ID_PANSCAN_MOVEDOWNRIGHT 875 -#define ID_PANSCAN_CENTER 876 -#define ID_PANSCAN_ROTATEXP 877 -#define ID_PANSCAN_ROTATEXM 878 -#define ID_PANSCAN_ROTATEYP 879 -#define ID_PANSCAN_ROTATEYM 880 -#define ID_PANSCAN_ROTATEZP 881 -#define ID_PANSCAN_ROTATEZM 882 -#define ID_ONTOP_DEFAULT 883 -#define ID_ONTOP_ALWAYS 884 -#define ID_ONTOP_WHILEPLAYING 885 -#define ID_ONTOP_WHILEPLAYINGVIDEO 886 -#define ID_PLAY_PLAY 887 -#define ID_PLAY_PAUSE 888 -#define ID_PLAY_PLAYPAUSE 889 -#define IDS_SHADERNOTES 889 -#define ID_PLAY_STOP 890 -#define ID_PLAY_FRAMESTEP 891 -#define ID_PLAY_FRAMESTEP_BACK 892 -#define ID_NAVIGATE_GOTO 893 -#define ID_PLAY_DECRATE 894 -#define ID_PLAY_INCRATE 895 -#define ID_PLAY_RESETRATE 896 -#define ID_PLAY_SEEKKEYBACKWARD 897 -#define ID_PLAY_SEEKKEYFORWARD 898 -#define ID_PLAY_SEEKBACKWARDSMALL 899 -#define ID_PLAY_SEEKFORWARDSMALL 900 -#define ID_PLAY_SEEKBACKWARDMED 901 -#define ID_PLAY_SEEKFORWARDMED 902 -#define ID_PLAY_SEEKBACKWARDLARGE 903 -#define ID_PLAY_SEEKFORWARDLARGE 904 -#define ID_PLAY_INCAUDDELAY 905 -#define ID_PLAY_DECAUDDELAY 906 -#define ID_VOLUME_UP 907 -#define ID_VOLUME_DOWN 908 -#define ID_VOLUME_MUTE 909 -#define ID_VOLUME_MUTE_OFF 910 -#define ID_VOLUME_MUTE_DISABLED 911 -#define ID_AFTERPLAYBACK_EXIT 912 -#define ID_AFTERPLAYBACK_STANDBY 913 -#define ID_AFTERPLAYBACK_HIBERNATE 914 -#define ID_AFTERPLAYBACK_SHUTDOWN 915 -#define ID_AFTERPLAYBACK_LOGOFF 916 -#define ID_AFTERPLAYBACK_LOCK 917 -#define ID_AFTERPLAYBACK_MONITOROFF 918 -#define ID_NAVIGATE_SKIPBACKFILE 919 -#define ID_NAVIGATE_SKIPFORWARDFILE 920 -#define ID_NAVIGATE_SKIPBACK 921 -#define ID_NAVIGATE_SKIPFORWARD 922 -#define ID_NAVIGATE_TITLEMENU 923 -#define ID_NAVIGATE_ROOTMENU 924 -#define ID_NAVIGATE_SUBPICTUREMENU 925 -#define ID_NAVIGATE_AUDIOMENU 926 -#define ID_NAVIGATE_ANGLEMENU 927 -#define ID_NAVIGATE_CHAPTERMENU 928 -#define ID_NAVIGATE_MENU_LEFT 929 -#define ID_NAVIGATE_MENU_RIGHT 930 -#define ID_NAVIGATE_MENU_UP 931 -#define ID_NAVIGATE_MENU_DOWN 932 -#define ID_NAVIGATE_MENU_ACTIVATE 933 -#define ID_NAVIGATE_MENU_BACK 934 -#define ID_NAVIGATE_MENU_LEAVE 935 -#define ID_FAVORITES 936 -#define ID_FAVORITES_ORGANIZE 937 -#define ID_FAVORITES_ADD 938 -#define ID_HELP_HOMEPAGE 939 -#define ID_HELP_DONATE 940 -#define ID_HELP_SHOWCOMMANDLINESWITCHES 941 -#define ID_HELP_TOOLBARIMAGES 942 -#define ID_HELP_ABOUT 943 -#define ID_BOSS 944 -#define ID_DUMMYSEPARATOR 945 -#define ID_BUTTONSEP 946 -#define ID_AFTERPLAYBACK_PLAYNEXT 947 -#define ID_AFTERPLAYBACK_DONOTHING 948 -#define ID_MENU_PLAYER_SHORT 949 -#define ID_MENU_PLAYER_LONG 950 -#define ID_MENU_FILTERS 951 -#define ID_STREAM_AUDIO_NEXT 952 -#define ID_STREAM_AUDIO_PREV 953 -#define ID_STREAM_SUB_NEXT 954 -#define ID_STREAM_SUB_PREV 955 -#define ID_STREAM_SUB_ONOFF 956 -#define ID_AUDIOSHIFT_ONOFF 960 -#define ID_DVD_ANGLE_NEXT 961 -#define ID_DVD_ANGLE_PREV 962 -#define ID_DVD_AUDIO_NEXT 963 -#define ID_DVD_AUDIO_PREV 964 -#define ID_DVD_SUB_NEXT 965 -#define ID_DVD_SUB_PREV 966 -#define ID_DVD_SUB_ONOFF 967 -#define ID_VIEW_ZOOM_AUTOFIT 968 -#define ID_FILE_OPENQUICK 969 -#define ID_VOLUME_BOOST_INC 970 -#define ID_VOLUME_BOOST_DEC 971 -#define ID_VOLUME_BOOST_MIN 972 -#define ID_VOLUME_BOOST_MAX 973 -#define ID_NAVIGATE_TUNERSCAN 974 -#define ID_FAVORITES_QUICKADDFAVORITE 975 -#define ID_FILE_REOPEN 976 -#define ID_FILTERS 977 -#define ID_AUDIOS 978 -#define ID_SUBTITLES 979 -#define ID_VIDEO_STREAMS 980 -#define ID_COLOR_BRIGHTNESS_INC 984 -#define ID_COLOR_BRIGHTNESS_DEC 985 -#define ID_COLOR_CONTRAST_INC 986 -#define ID_COLOR_CONTRAST_DEC 987 -#define ID_COLOR_HUE_INC 988 -#define ID_COLOR_HUE_DEC 989 -#define ID_COLOR_SATURATION_INC 990 -#define ID_COLOR_SATURATION_DEC 991 -#define ID_COLOR_RESET 992 -#define ID_CUSTOM_CHANNEL_MAPPING 993 -#define ID_NORMALIZE 994 -#define ID_REGAIN_VOLUME 995 -#define ID_PLAY_SEEKSET 996 -#define ID_PANSCAN_ROTATEZ270 997 -#define ID_PRESIZE_SHADERS_TOGGLE 998 -#define ID_POSTSIZE_SHADERS_TOGGLE 999 -#define ID_FILTERS_COPY_TO_CLIPBOARD 1999 -#define ID_FILTERS_SUBITEM_START 2000 -#define ID_FILTERS_SUBITEM_END 2099 -#define ID_FILTERSTREAMS_SUBITEM_START 2100 -#define ID_FILTERSTREAMS_SUBITEM_END 2199 -#define ID_AUDIO_SUBITEM_START 2200 -#define ID_AUDIO_SUBITEM_END 2299 -#define ID_SUBTITLES_SUBITEM_START 2300 -#define ID_SUBTITLES_SUBITEM_END 2399 -#define ID_VIDEO_STREAMS_SUBITEM_START 2400 -#define ID_VIDEO_STREAMS_SUBITEM_END 2499 -#define ID_FAVORITES_FILE_START 2800 -#define ID_FAVORITES_FILE_END 3799 -#define ID_FAVORITES_DVD_START 3800 -#define ID_FAVORITES_DVD_END 3899 -#define ID_FAVORITES_DEVICE_START 3900 -#define ID_FAVORITES_DEVICE_END 3999 -#define ID_FILE_OPEN_OPTICAL_DISK_START 4000 -#define ID_FILE_OPEN_OPTICAL_DISK_END 4099 -#define ID_PANNSCAN_PRESETS_START 4100 -#define ID_PANNSCAN_PRESETS_END 4199 -#define ID_SHADERS_SELECT 4200 -#define ID_SHADERS_PRESETS_START 4201 -#define ID_SHADERS_PRESETS_END 4299 -#define ID_NAVIGATE_JUMPTO_SUBITEM_START 4300 -#define ID_NAVIGATE_JUMPTO_SUBITEM_END 4899 -#define ID_VIEW_ZOOM_AUTOFIT_LARGER 4900 -#define ID_PLAY_PLAYBACKRATE_START 5000 -#define ID_PLAY_PLAYBACKRATE_025 5001 -#define ID_PLAY_PLAYBACKRATE_050 5002 -#define ID_PLAY_PLAYBACKRATE_075 5003 -#define ID_PLAY_PLAYBACKRATE_090 5004 -#define ID_PLAY_PLAYBACKRATE_100 5005 -#define ID_PLAY_PLAYBACKRATE_110 5006 -#define ID_PLAY_PLAYBACKRATE_125 5007 -#define ID_PLAY_PLAYBACKRATE_150 5008 -#define ID_PLAY_PLAYBACKRATE_200 5009 -#define ID_PLAY_PLAYBACKRATE_300 5010 -#define ID_PLAY_PLAYBACKRATE_400 5011 -#define ID_PLAY_PLAYBACKRATE_600 5012 -#define ID_PLAY_PLAYBACKRATE_800 5013 -#define ID_PLAY_PLAYBACKRATE_FPS24 5020 -#define ID_PLAY_PLAYBACKRATE_FPS25 5021 -#define ID_PLAY_PLAYBACKRATE_END 5029 -#define ID_PLAYLIST_TOGGLE_SHUFFLE 5030 -#define ID_CMDLINE_SAVE_THUMBNAILS 5031 -#define ID_MOUSE_ADD_CMD 5032 -#define IDS_FILTER_SETTINGS_CAPTION 7000 -#define IDD_OPEN_DLG 10000 -#define IDD_MEDIATYPES_DLG 10002 -#define IDD_SAVE_DLG 10004 -#define IDD_SUBTITLEDL_DLG 10005 -#define IDD_FILEPROPDETAILS 10010 -#define IDD_FILEPROPCLIP 10011 -#define IDD_PNSPRESET_DLG 10015 -#define IDD_GOTO_DLG 10016 -#define IDD_FAVADD 10017 -#define IDD_FAVORGANIZE 10018 -#define IDD_ABOUTBOX 10019 -#define IDD_PLAYERINFOBAR 10020 -#define IDD_PLAYERSTATUSBAR 10021 -#define IDD_PLAYERSEEKBAR 10022 -#define IDD_PPAGEPLAYBACK 10023 -#define IDD_PPAGEPLAYER 10024 -#define IDD_PPAGEDVD 10025 -#define IDD_PPAGESUBTITLES 10026 -#define IDD_PPAGEFORMATS 10027 -#define IDD_PPAGETWEAKS 10028 -#define IDD_PPAGEAUDIOSWITCHER 10029 -#define IDD_PPAGEEXTERNALFILTERS 10030 -#define IDD_PPAGESHADERS 10031 -#define IDD_PPAGEACCELTBL 10032 -#define IDD_PPAGESUBSTYLE 10033 -#define IDD_PPAGEINTERNALFILTERS 10036 -#define IDD_PPAGELOGO 10037 -#define IDD_PPAGETHEME 10038 -#define IDD_PPAGEOUTPUT 10039 -#define IDD_PPAGEWEBSERVER 10040 -#define IDD_CAPTURE_DLG 10045 -#define IDD_ADDREGFILTER 10046 -#define IDD_SELECTMEDIATYPE 10047 -#define IDD_COMPROPERTYPAGE 10048 -#define IDD_FILEPROPRES 10049 -#define IDD_PPAGEMISC 10052 -#define IDD_FILEMEDIAINFO 10053 -#define IDD_PPAGECAPTURE 10054 -#define IDD_PPAGESYNC 10055 -#define IDD_PPAGEFULLSCREEN 10056 -#define IDD_RFS_FILELIST_EXT 10057 -#define IDD_PPAGEAUDIORENDERER 10058 -#define IDD_PPAGEMOUSE 10059 -#define IDC_COMBO1 11000 -#define IDC_COMBO2 11001 -#define IDC_COMBO3 11002 -#define IDC_COMBO4 11003 -#define IDC_COMBO5 11004 -#define IDC_COMBO6 11005 -#define IDC_COMBO7 11006 -#define IDC_COMBO8 11007 -#define IDC_COMBO9 11008 -#define IDC_COMBO10 11009 -#define IDC_COMBO11 11010 -#define IDC_COMBO12 11011 -#define IDC_COMBO14 11013 -#define IDC_SLIDER1 11020 -#define IDC_SLIDER2 11021 -#define IDC_SLIDER3 11022 -#define IDC_SLIDER4 11023 -#define IDC_SLI_BRIGHTNESS 11025 -#define IDC_SLI_HUE 11026 -#define IDC_SLI_SATURATION 11027 -#define IDC_RADIO1 11040 -#define IDC_RADIO2 11041 -#define IDC_RADIO3 11042 -#define IDC_RADIO4 11043 -#define IDC_RADIO5 11044 -#define IDC_RADIO6 11045 -#define IDC_RADIO7 11046 -#define IDC_RADIO8 11047 -#define IDC_RADIO9 11048 -#define IDC_RADIO10 11049 -#define IDC_RADIO11 11050 -#define IDC_EDIT1 11060 -#define IDC_EDIT3 11061 -#define IDC_EDIT2 11062 -#define IDC_EDIT4 11063 -#define IDC_EDIT5 11064 -#define IDC_EDIT6 11065 -#define IDC_EDIT7 11066 -#define IDC_EDIT8 11067 -#define IDC_EDIT9 11068 -#define IDC_EDIT10 11069 -#define IDC_WINHOTKEY1 11070 -#define IDC_CHECK1 11080 -#define IDC_CHECK2 11081 -#define IDC_CHECK3 11082 -#define IDC_CHECK4 11083 -#define IDC_CHECK5 11084 -#define IDC_CHECK6 11085 -#define IDC_CHECK7 11086 -#define IDC_CHECK8 11087 -#define IDC_CHECK9 11088 -#define IDC_CHECK10 11089 -#define IDC_CHECK11 11090 -#define IDC_CHECK12 11091 -#define IDC_CHECK13 11092 -#define IDC_CHECK14 11093 -#define IDC_SPIN1 11100 -#define IDC_SPIN2 11101 -#define IDC_SPIN3 11102 -#define IDC_SPIN4 11103 -#define IDC_SPIN5 11104 -#define IDC_SPIN6 11105 -#define IDC_SPIN7 11106 -#define IDC_SPIN8 11107 -#define IDC_SPIN9 11108 -#define IDC_SPIN10 11109 -#define IDC_BUTTON1 11120 -#define IDC_BUTTON2 11121 -#define IDC_BUTTON3 11122 -#define IDC_BUTTON4 11123 -#define IDC_BUTTON5 11124 -#define IDC_BUTTON6 11125 -#define IDC_BUTTON7 11126 -#define IDC_BUTTON8 11127 -#define IDC_BUTTON9 11128 -#define IDC_BUTTON10 11129 -#define IDC_BUTTON11 11130 -#define IDC_BUTTON12 11131 -#define IDC_BUTTON13 11132 -#define IDC_RESET_SETTINGS 11133 -#define IDC_EXPORT_SETTINGS 11134 -#define IDC_TREE1 11140 -#define IDC_LIST1 11160 -#define IDC_LIST2 11161 -#define IDC_LIST3 11162 -#define IDC_TAB1 11200 -#define IDC_ANIMATE1 11220 -#define IDC_PROGRESS1 11240 -#define IDC_STATIC1 11260 -#define IDC_STATIC2 11261 -#define IDC_STATIC3 11262 -#define IDC_STATIC4 11263 -#define IDC_STATIC5 11264 -#define IDC_STATIC6 11265 -#define IDC_STATIC7 11266 -#define IDC_STATIC8 11267 -#define IDC_STATIC9 11268 -#define IDC_STATIC10 11269 -#define IDC_STATIC11 11270 -#define IDC_DVDPATH 12000 -#define IDC_SUBRESYNCLIST 12001 -#define IDC_PLAYLIST 12002 -#define IDC_COLORPRI 12003 -#define IDC_COLORSEC 12004 -#define IDC_COLOROUTL 12005 -#define IDC_COLORSHAD 12006 -#define IDC_STATICLINK 12007 -#define IDC_STATICLINK2 12008 -#define IDC_DEFAULTICON 12009 -#define IDC_PLACEHOLDER 12010 -#define IDC_REPORT 12011 -#define IDC_FROMTO 12012 -#define IDC_STATIC_BALANCE 12013 -#define IDC_LOGOPREVIEW 12014 -#define IDC_LOGOFILENAME 12016 -#define IDC_AUTHOR 12018 -#define IDC_CHECK_RELATIVETO 12019 -#define IDC_CHECK_NO_SUB_ANIM 12021 -#define IDC_SUBPIC_TO_BUFFER 12022 -#define IDC_BUTTON_EXT_SET 12023 -#define IDC_OK1 12024 -#define IDC_OK2 12025 -#define IDC_PLAYERSTATUS 12026 -#define IDC_PLAYERTIME 12027 -#define IDC_EDITLIST 12028 -#define IDC_CHECK_SUB_AR_COMPENSATION 12029 -#define IDC_CHECK_ALLOW_DROPPING_SUBPIC 12030 -#define IDC_DSSYSDEF 12100 -#define IDC_DSOVERLAYMIXER 12102 -#define IDC_DSVMR9WIN 12104 -#define IDC_DSVMR9REN 12106 -#define IDC_DSDXR 12107 -#define IDC_DSNULL_COMP 12108 -#define IDC_DSNULL_UNCOMP 12109 -#define IDC_DSEVR_CUSTOM 12111 -#define IDC_DSMADVR 12112 -#define IDC_DSSYNC 12113 -#define IDC_REGULARSURF 12127 -#define IDC_TEXTURESURF2D 12128 -#define IDC_TEXTURESURF3D 12129 -#define IDC_DX9RESIZER_COMBO 12130 -#define IDC_DSVMR9LOADMIXER 12131 -#define IDC_DX_SURFACE 12133 -#define IDC_BUTTON_MI 12136 -#define IDC_MIEDIT 12137 -#define IDC_LISTCHANNELS 12138 -#define IDC_STATUSBAR 12139 -#define IDC_PPAGECAPTURE_DESC1 12140 -#define IDC_DSMPCVR 12141 -#define IDS_SRC_VTS 14002 -#define IDS_SRC_RFS 14003 -#define IDS_INTERNAL_LAVF 14004 -#define IDS_INTERNAL_LAVF_WMV 14005 -#define IDS_AG_OPEN_FILE_LOCATION 14006 -#define IDS_AG_OPENDIRECTORY 14007 -#define IDS_PLAYLIST_OPEN 14114 -#define IDS_PLAYLIST_ADD 14115 -#define IDS_PLAYLIST_REMOVE 14116 -#define IDS_PLAYLIST_CLEAR 14117 -#define IDS_PLAYLIST_COPYTOCLIPBOARD 14118 -#define IDS_PLAYLIST_SAVE 14119 -#define IDS_PLAYLIST_SAVEAS 14120 -#define IDS_PLAYLIST_SORTBYLABEL 14121 -#define IDS_PLAYLIST_SORTBYPATH 14122 -#define IDS_PLAYLIST_RANDOMIZE 14123 -#define IDS_PLAYLIST_RESTORE 14124 -#define IDS_SUBRESYNC_SEPARATOR 14125 -#define IDS_SUBRESYNC_DELETE 14126 -#define IDS_SUBRESYNC_DUPLICATE 14127 -#define IDS_SUBRESYNC_RESET 14128 -#define IDS_SUBRESYNC_ORIGINAL 14129 -#define IDS_SUBRESYNC_CURRENT 14130 -#define IDS_SUBRESYNC_EDIT 14131 -#define IDS_SUBRESYNC_YES 14132 -#define IDS_SUBRESYNC_NO 14133 -#define IDS_SUBRESYNC_DECREASE 14134 -#define IDS_SUBRESYNC_INCREASE 14135 -#define IDS_OPTIONS_CAPTION 14136 -#define IDS_SHADERS_SELECT 14137 -#define IDS_SHADERS_DEBUG 14138 -#define IDS_FAVORITES_ADD 14153 -#define IDS_FAVORITES_ORGANIZE 14154 -#define IDS_PLAYLIST_SHUFFLE 14155 -#define IDS_PLAYLIST_SHOWFOLDER 14156 -#define IDS_CONTROLS_CLOSING 14157 -#define IDS_CONTROLS_PLAYING 14158 -#define IDS_CONTROLS_PAUSED 14159 -#define IDS_CONTROLS_STOPPED 14160 -#define IDS_CONTROLS_BUFFERING 14161 -#define IDS_CONTROLS_CAPTURING 14162 -#define IDS_CONTROLS_OPENING 14163 -#define IDS_CONTROLS_CLOSED 14164 -#define IDS_SUBTITLES_OPTIONS 14165 -#define IDS_SUBTITLES_STYLES 14166 -#define IDS_SUBTITLES_RELOAD 14167 -#define IDS_SUBTITLES_HIDE 14168 -#define IDS_PANSCAN_EDIT 14169 -#define IDS_INFOBAR_TITLE 14170 -#define IDS_INFOBAR_AUTHOR 14171 -#define IDS_INFOBAR_COPYRIGHT 14172 -#define IDS_INFOBAR_RATING 14173 -#define IDS_INFOBAR_DESCRIPTION 14174 -#define IDS_INFOBAR_DOMAIN 14175 -#define IDS_INFOBAR_LOCATION 14176 -#define IDS_INFOBAR_VIDEO 14177 -#define IDS_INFOBAR_AUDIO 14178 -#define IDS_INFOBAR_SUBTITLES 14179 -#define IDS_INFOBAR_CHAPTER 14180 -#define IDS_CONTROLS_COMPLETING 14181 -#define IDS_AUTOPLAY_PLAYVIDEO 14182 -#define IDS_AUTOPLAY_PLAYMUSIC 14183 -#define IDS_AUTOPLAY_PLAYAUDIOCD 14184 -#define IDS_AUTOPLAY_PLAYDVDMOVIE 14185 -#define IDS_PROPSHEET_PROPERTIES 14186 -#define IDS_PLAY_LOOPMODE_FILE 14187 -#define IDS_SUB_OVERRIDE_DEFAULT_STYLE 14188 -#define IDS_PLAY_LOOPMODE_PLAYLIST 14189 -#define IDS_FAVFILES 14190 -#define IDS_FAVDVDS 14191 -#define IDS_INFOBAR_CHANNEL 14192 -#define IDS_INFOBAR_TIME 14193 -#define IDS_STATSBAR_SYNC_OFFSET 14194 -#define IDS_STATSBAR_SYNC_OFFSET_FORMAT 14195 -#define IDS_STATSBAR_JITTER 14196 -#define IDS_STATSBAR_BITRATE 14197 -#define IDS_STATSBAR_BITRATE_AVG_CUR 14198 -#define IDS_STATSBAR_SIGNAL 14199 -#define IDS_STATSBAR_SIGNAL_FORMAT 14200 -#define IDS_SUBTITLES_STYLES_CAPTION 14201 -#define IDS_TEXT_SUB_RENDERING_TARGET 14202 -#define IDS_PLAYLOOPMODE_PLAYLIST 14203 -#define IDS_PLAYLOOPMODE_FILE 14204 -#define IDS_PLAYLOOP_FOREVER_ON 14205 -#define IDS_PLAYLOOP_FOREVER_OFF 14206 -#define IDS_PLAYLOOP_FOREVER 14207 -#define IDS_PLAYLOOPMODE_AB 14208 -#define IDS_PLAY_LOOPMODE_AB 14209 -#define IDS_PLAYLOOPMODE_AB_MARK_A 14210 -#define IDS_PLAYLOOPMODE_AB_MARK_B 14211 -#define IDS_SNAPSHOT_SUBTITLES 14212 -#define IDS_THEMEMODE_DARK 14213 -#define IDS_THEMEMODE_LIGHT 14214 -#define IDS_THEMEMODE_WINDOWS 14215 -#define IDS_SUB_OVERRIDE_ALL_STYLES 14216 -#define IDD_TUNER_SCAN 20002 -#define IDS_OSD_DISPLAY_RENDERER_STATS 20003 -#define IDD_PPAGELOGO2 20003 -#define IDS_OSD_RESET_RENDERER_STATS 20004 -#define IDD_NAVIGATION_DLG 20005 -#define IDD_PPAGESUBMISC 20006 -#define IDS_VIEW_BORDERLESS 20007 -#define IDS_VIEW_FRAMEONLY 20008 -#define IDS_VIEW_CAPTIONMENU 20009 -#define IDS_VIEW_HIDEMENU 20010 -#define IDD_UPDATE_DIALOG 20011 -#define IDF_WIN7_TOOLBAR 20012 -#define IDD_DEBUGSHADERS_DLG 20013 -#define IDD_PPAGEADVANCED 20014 -#define IDD_CMD_LINE_HELP 20016 -#define IDD_CRASH_REPORTER 20017 -#define IDD_PPAGEDPICALC 20018 -#define IDD_RAR_ENTRY_SELECTOR 20019 -#define IDD_ADDCOMMAND_DLG 20020 -#define IDD_PPAGETOOLBAR 20021 -#define IDB_DT_CB_96 20050 -#define IDB_DT_CB_120 20051 -#define IDB_DT_CB_144 20052 -#define IDB_DT_CB_192 20053 -#define IDB_DT_RADIO_96 20054 -#define IDB_DT_RADIO_120 20055 -#define IDB_DT_RADIO_144 20056 -#define IDB_DT_RADIO_129 20057 -#define IDB_DT_RADIO_192 20057 -#define IDS_MESSAGEBOX_CANCEL 20059 -#define IDS_MESSAGEBOX_ABORT 20060 -#define IDS_MESSAGEBOX_RETRY 20061 -#define IDS_MESSAGEBOX_IGNORE 20062 -#define IDS_MESSAGEBOX_OK 20063 -#define IDS_MESSAGEBOX_CONTINUE 20064 -#define IDS_AG_TOGGLE_DEFAULT_SUBTITLE_STYLE 20065 -#define ID_FILE_OPEN_LOCATION 20066 -#define IDB_NOIMAGE 20067 -#define IDB_GRIPPER_168 20070 -#define IDB_GRIPPER_144 20071 -#define IDB_GRIPPER_192 20073 -#define IDB_GRIPPER_96 20074 -#define IDB_PNG1 20075 -#define IDB_GRIPPER_120 20075 -#define IDI_OPENSUBTITLES 21001 -#define IDI_PODNAPISI 21002 -#define IDI_N24 21006 -#define IDC_FULLSCREEN_MONITOR_CHECK 22002 -#define IDC_SLI_CONTRAST 22003 -#define IDC_RESET 22004 -#define IDC_DVD_POS 22005 -#define IDC_FILE_POS 22006 -#define IDC_EVR_BUFFERS 22010 -#define IDC_VERSION 22011 -#define IDC_SHOW_OSD 22013 -#define IDC_EVR_BUFFERS_TXT 22014 -#define IDC_LAVFILTERS_VERSION 22016 -#define IDC_DSVMR9ALTERNATIVEVSYNC 22017 -#define IDC_HOMEPAGE_LINK 22018 -#define IDC_QUALITY 22019 -#define IDC_PROGRESS 22020 -#define IDC_FREQ_START 22021 -#define IDC_BANDWIDTH 22022 -#define IDC_FREQ_END 22023 -#define IDC_CHANNEL_LIST 22024 -#define ID_START 22025 -#define IDC_SYMBOLRATE 22026 -#define ID_SAVE 22030 -#define IDC_STRENGTH 22031 -#define IDC_SYNCVIDEO 22032 -#define IDC_SYNCDISPLAY 22033 -#define IDC_CYCLEDELTA 22034 -#define IDC_LINEDELTA 22035 -#define IDC_COLUMNDELTA 22036 -#define IDC_TARGETSYNCOFFSET 22037 -#define IDC_CONTROLLIMIT 22038 -#define IDC_SYNCNEAREST 22040 -#define IDC_D3D9DEVICE 22041 -#define IDC_NAVIGATION_SCAN 22043 -#define IDC_D3D9DEVICE_COMBO 22045 -#define IDC_NAVIGATION_INFO 22046 -#define IDC_NAVIGATION_FILTERSTATIONS 22047 -#define IDC_CHECK_OFFSET 22048 -#define IDC_OFFSET 22049 -#define IDC_CHECK_IGNORE_ENCRYPTED 22050 -#define IDC_UPDATE_DLG_TEXT 22051 -#define IDC_UPDATE_ICON 22052 -#define IDC_UPDATE_DL_BUTTON 22053 -#define IDC_UPDATE_LATER_BUTTON 22054 -#define IDC_UPDATE_IGNORE_BUTTON 22055 -#define IDC_AUTHORS_LINK 22056 -#define IDC_CHECK_LCD 22059 -#define IDC_VIDRND_COMBO 22060 -#define IDC_AUDRND_COMBO 22063 -#define IDC_VIDRND_DXVA_SUPPORT 22064 -#define IDC_VIDRND_SHADER_SUPPORT 22065 -#define IDC_VIDRND_SUBTITLE_SUPPORT 22066 -#define IDC_VIDRND_SAVEIMAGE_SUPPORT 22067 -#define IDC_VIDRND_ROTATION_SUPPORT 22068 -#define IDC_VOLUMESTEP 22073 -#define IDC_VOLUMESTEP_SPIN 22074 -#define IDC_SPEEDSTEP 22075 -#define IDC_SPEEDSTEP_SPIN 22076 -#define IDC_EXPORT_KEYS 22077 -#define IDC_PPAGECAPTURE_ST10 22078 -#define IDC_PPAGECAPTURE_ST11 22079 -#define IDC_PPAGECAPTURE_ST12 22080 -#define IDC_FASTSEEK_CHECK 22081 -#define IDC_ASSOCIATE_ALL_FORMATS 22082 -#define IDC_ASSOCIATE_VIDEO_FORMATS 22083 -#define IDC_ASSOCIATE_AUDIO_FORMATS 22084 -#define IDC_CLEAR_ALL_ASSOCIATIONS 22085 -#define IDC_SEEK_PREVIEW 22086 -#define IDC_CHECK_AUTOSAVE_ONLINE_SUBTITLE 22087 -#define IDC_STATIC21 22088 -#define IDC_STATIC22 22089 -#define IDC_STATIC23 22090 -#define IDC_STATIC_LIBASS 22091 -#define IDC_MODERNSEEKBARHEIGHT 22092 -#define IDC_MODERNSEEKBARHEIGHT_SPIN 22093 -#define ID_SUB_DELAY_DOWN 24000 -#define ID_SUB_DELAY_UP 24001 -#define IDS_MPLAYERC_104 24002 -#define IDS_MPLAYERC_105 24003 -#define IDS_FILE_SAVE_THUMBNAILS 24005 -#define ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION 24028 -#define ID_VIEW_FULLFLOATINGPOINTPROCESSING 24029 -#define ID_VIEW_CM_ENABLE 24030 -#define ID_VIEW_CM_INPUT_AUTO 24031 -#define ID_VIEW_CM_INPUT_HDTV 24032 -#define ID_VIEW_CM_INPUT_SDTV_NTSC 24033 -#define ID_VIEW_CM_INPUT_SDTV_PAL 24034 -#define ID_VIEW_CM_AMBIENTLIGHT_BRIGHT 24035 -#define ID_VIEW_CM_AMBIENTLIGHT_DIM 24037 -#define ID_VIEW_CM_AMBIENTLIGHT_DARK 24038 -#define ID_VIEW_CM_INTENT_PERCEPTUAL 24039 -#define ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC 24040 -#define ID_VIEW_CM_INTENT_SATURATION 24041 -#define ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC 24042 -#define ID_VIEW_HALFFLOATINGPOINTPROCESSING 24043 -#define ID_FILE_RECYCLE 24044 -#define ID_VIEW_MPCTHEME 24045 -#define PLAYER_PLAYLIST_UPDATE_SCROLLBAR 24048 -#define IDF_LOGO4 24050 -#define ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE 24051 -#define ID_SUB_POS_DOWN 24052 -#define ID_SUB_POS_UP 24053 -#define ID_SUB_FONT_SIZE_DEC 24054 -#define ID_SUB_FONT_SIZE_INC 24055 -#define IDS_SUB_POS_DOWN 24056 -#define IDS_SUB_POS_UP 24057 -#define IDS_SUB_FONT_SIZE_DEC 24058 -#define IDS_SUB_FONT_SIZE_INC 24059 -#define ID_VIEW_TEARING_TEST 32769 -#define ID_FILE_OPENDISC 32774 -#define ID_SHADERS 32775 -#define ID_VIEW_OSD_SHOW_FILENAME 32777 -#define ID_VIEW_OSD_DISPLAY_TIME 32778 -#define ID_D3DFULLSCREEN_TOGGLE 32779 -#define ID_GOTO_PREV_SUB 32780 -#define ID_GOTO_NEXT_SUB 32781 -#define ID_SUBRESYNC_SHIFT_DOWN 32782 -#define ID_SUBRESYNC_SHIFT_UP 32783 -#define ID_VIEW_DISPLAY_RENDERER_STATS 32784 -#define ID_VIEW_RESET_RENDERER_STATS 32785 -#define IDS_AG_CLOSE 32830 -#define IDS_AG_NONE 32832 -#define IDS_AG_COMMAND 32833 -#define IDS_AG_KEY 32834 -#define IDS_AG_MOUSE 32836 -#define IDS_AG_APP_COMMAND 32838 -#define IDS_AG_MEDIAFILES 32871 -#define IDS_AG_ALLFILES 32872 -#define IDS_AG_AUDIOFILES 32873 -#define IDS_AG_NOT_KNOWN 32876 -#define IDS_MPLAYERC_0 32877 -#define IDS_AG_OPEN_FILE 32878 -#define IDS_AG_OPEN_DVD 32879 -#define IDS_AG_OPEN_DEVICE 32880 -#define IDS_AG_SAVE_AS 32881 -#define IDS_AG_SAVE_IMAGE 32882 -#define IDS_MPLAYERC_6 32883 -#define IDS_OSD_IMAGE_SAVED 32884 -#define IDS_AG_LOAD_SUBTITLES 32885 -#define IDS_AG_SAVE_SUBTITLES 32886 -#define IDS_AG_PROPERTIES 32887 -#define IDS_AG_EXIT 32888 -#define IDS_AG_PLAYPAUSE 32889 -#define IDS_AG_PLAY 32890 -#define IDS_AG_STOP 32891 -#define IDS_AG_FRAMESTEP 32892 -#define IDS_MPLAYERC_16 32893 -#define IDS_AG_GO_TO 32894 -#define IDS_AG_INCREASE_RATE 32895 -#define IDS_AG_DECREASE_RATE 32896 -#define IDS_AG_RESET_RATE 32897 -#define IDS_MPLAYERC_21 32898 -#define IDS_MPLAYERC_22 32899 -#define IDS_MPLAYERC_23 32900 -#define IDS_MPLAYERC_24 32901 -#define IDS_MPLAYERC_25 32902 -#define IDS_MPLAYERC_26 32903 -#define IDS_MPLAYERC_27 32904 -#define IDS_MPLAYERC_28 32905 -#define IDS_MPLAYERC_29 32906 -#define IDS_MPLAYERC_30 32907 -#define IDS_AG_NEXT 32908 -#define IDS_AG_PREVIOUS 32909 -#define IDS_AG_NEXT_FILE 32910 -#define IDS_AG_PREVIOUS_FILE 32911 -#define IDS_AG_VIEW_MINIMAL 32912 -#define IDS_AG_VIEW_COMPACT 32913 -#define IDS_AG_VIEW_NORMAL 32914 -#define IDS_AG_FULLSCREEN 32915 -#define IDS_MPLAYERC_39 32916 -#define IDS_AG_ZOOM_AUTO_FIT 32917 -#define IDS_AG_VIDFRM_HALF 32918 -#define IDS_AG_VIDFRM_NORMAL 32919 -#define IDS_AG_VIDFRM_DOUBLE 32920 -#define IDS_AG_ALWAYS_ON_TOP 32921 -#define IDS_AG_PNS_INC_SIZE 32922 -#define IDS_AG_PNS_INC_WIDTH 32923 -#define IDS_MPLAYERC_47 32924 -#define IDS_AG_PNS_DEC_SIZE 32925 -#define IDS_AG_PNS_DEC_WIDTH 32926 -#define IDS_MPLAYERC_50 32927 -#define IDS_AG_PNS_CENTER 32928 -#define IDS_AG_PNS_LEFT 32929 -#define IDS_AG_PNS_RIGHT 32930 -#define IDS_AG_PNS_UP 32931 -#define IDS_AG_PNS_DOWN 32932 -#define IDS_AG_PNS_UPLEFT 32933 -#define IDS_AG_PNS_UPRIGHT 32934 -#define IDS_AG_PNS_DOWNLEFT 32935 -#define IDS_MPLAYERC_59 32936 -#define IDS_AG_VOLUME_UP 32937 -#define IDS_AG_VOLUME_DOWN 32938 -#define IDS_AG_VOLUME_MUTE 32939 -#define IDS_MPLAYERC_63 32940 -#define IDS_AG_DVD_ROOT_MENU 32941 -#define IDS_MPLAYERC_65 32942 -#define IDS_MPLAYERC_66 32943 -#define IDS_MPLAYERC_67 32944 -#define IDS_MPLAYERC_68 32945 -#define IDS_AG_DVD_MENU_LEFT 32946 -#define IDS_MPLAYERC_70 32947 -#define IDS_AG_DVD_MENU_UP 32948 -#define IDS_AG_DVD_MENU_DOWN 32949 -#define IDS_MPLAYERC_73 32950 -#define IDS_AG_DVD_MENU_BACK 32951 -#define IDS_MPLAYERC_75 32952 -#define IDS_AG_BOSS_KEY 32953 -#define IDS_MPLAYERC_77 32954 -#define IDS_MPLAYERC_78 32955 -#define IDS_AG_FILTERS_MENU 32956 -#define IDS_AG_OPTIONS 32957 -#define IDS_AG_NEXT_AUDIO 32958 -#define IDS_AG_PREV_AUDIO 32959 -#define IDS_AG_NEXT_SUBTITLE 32960 -#define IDS_AG_PREV_SUBTITLE 32961 -#define IDS_MPLAYERC_85 32962 -#define IDS_MPLAYERC_86 32963 -#define IDS_MPLAYERC_91 32968 -#define IDS_MPLAYERC_92 32969 -#define IDS_MPLAYERC_93 32970 -#define IDS_MPLAYERC_94 32971 -#define IDS_MPLAYERC_95 32972 -#define IDS_MPLAYERC_96 32973 -#define IDS_MPLAYERC_97 32974 -#define IDS_OSD_DISPLAY_CURRENT_TIME 32975 -#define IDS_MPLAYERC_99 32976 -#define IDS_MPLAYERC_100 32977 -#define IDS_MPLAYERC_101 32978 -#define IDS_MPLAYERC_102 32979 -#define IDS_MPLAYERC_103 32980 -#define IDS_AG_SEEKSET 32982 -#define IDS_OSD_SHOW_FILENAME 32983 -#define IDS_PLAY_DVD 32984 -#define IDS_PLAY_BD 32985 -#define IDS_PPAGEWEBSERVER_0 32996 -#define IDS_MAINFRM_2 33014 -#define IDS_AG_SUBTITLES_SAVED 33015 -#define IDS_MAINFRM_4 33016 -#define IDS_AG_FRAMERATE 33017 -#define IDS_MAINFRM_6 33018 -#define IDS_AG_FRAMES 33019 -#define IDS_AG_BUFFERS 33020 -#define IDS_MAINFRM_9 33021 -#define IDS_MAINFRM_10 33022 -#define IDS_MAINFRM_11 33023 -#define IDS_AG_TITLE 33024 -#define IDS_MAINFRM_16 33025 -#define IDS_MAINFRM_17 33026 -#define IDS_MAINFRM_18 33027 -#define IDS_MAINFRM_19 33028 -#define IDS_MAINFRM_20 33029 -#define IDS_MAINFRM_21 33030 -#define IDS_MAINFRM_22 33031 -#define IDS_MAINFRM_23 33032 -#define IDS_AG_ASPECT_RATIO 33045 -#define IDS_MAINFRM_37 33046 -#define IDS_MAINFRM_38 33047 -#define IDS_MAINFRM_39 33048 -#define IDS_MAINFRM_40 33049 -#define IDS_MAINFRM_41 33050 -#define IDS_MAINFRM_42 33051 -#define IDS_AG_ERROR 33052 -#define IDS_SUBTITLE_STREAM_OFF 33053 -#define IDS_SUBTITLE_STREAM 33054 -#define IDS_MAINFRM_46 33055 -#define IDS_SUB_LOADED_SUCCESS 33056 -#define IDS_ALL_FILES_FILTER 33057 -#define IDS_GETDIB_FAILED 33058 -#define IDS_GETCURRENTIMAGE_FAILED 33059 -#define IDS_SCREENSHOT_ERROR 33060 -#define IDS_THUMBNAILS_NO_DURATION 33061 -#define IDS_THUMBNAILS_NO_FRAME_SIZE 33062 -#define IDS_OUT_OF_MEMORY 33063 -#define IDS_THUMBNAILS_INVALID_FORMAT 33064 -#define IDS_THUMBNAILS_INFO_FILESIZE 33065 -#define IDS_THUMBNAILS_INFO_HEADER 33066 -#define IDS_THUMBNAIL_TOO_SMALL 33067 -#define IDS_CANNOT_LOAD_SUB 33068 -#define IDS_SUBTITLE_FILES_FILTER 33069 -#define IDS_MAINFRM_68 33075 -#define IDS_MAINFRM_69 33076 -#define IDS_MAINFRM_70 33077 -#define IDS_AG_CHAPTER 33078 -#define IDS_AG_OUT_OF_MEMORY 33081 -#define IDS_MAINFRM_77 33082 -#define IDS_MAINFRM_80 33084 -#define IDS_MAINFRM_81 33085 -#define IDS_MAINFRM_82 33086 -#define IDS_MAINFRM_83 33087 -#define IDS_MAINFRM_84 33088 -#define IDS_MAINFRM_86 33089 -#define IDS_MAINFRM_87 33090 -#define IDS_MAINFRM_88 33091 -#define IDS_MAINFRM_89 33092 -#define IDS_MAINFRM_90 33093 -#define IDS_MAINFRM_91 33094 -#define IDS_MAINFRM_92 33095 -#define IDS_MAINFRM_93 33096 -#define IDS_MAINFRM_94 33097 -#define IDS_AG_FAILED 33098 -#define IDS_MAINFRM_96 33099 -#define IDS_MAINFRM_98 33100 -#define IDS_MAINFRM_99 33101 -#define IDS_MAINFRM_108 33106 -#define IDS_AG_SOUND 33107 -#define IDS_MAINFRM_114 33108 -#define IDS_AG_ABORTED 33109 -#define IDS_MAINFRM_116 33110 -#define IDS_MAINFRM_117 33111 -#define IDS_AG_UNKNOWN_STREAM 33112 -#define IDS_AG_UNKNOWN 33113 -#define IDS_AG_VSYNC 33114 -#define IDS_MAINFRM_121 33115 -#define IDS_MAINFRM_122 33116 -#define IDS_DVD_SUBTITLES_ENABLE 33117 -#define IDS_AG_ANGLE 33118 -#define IDS_AG_VSYNCOFFSET_INCREASE 33119 -#define IDS_AG_DISABLED 33120 -#define IDS_AG_VSYNCOFFSET_DECREASE 33121 -#define IDS_MAINFRM_136 33126 -#define IDS_MAINFRM_137 33127 -#define IDS_MAINFRM_138 33128 -#define IDS_VOLUME_BOOST_INC 33129 -#define IDS_VOLUME_BOOST_DEC 33130 -#define IDS_VOLUME_BOOST_MIN 33131 -#define IDS_VOLUME_BOOST_MAX 33132 -#define IDS_USAGE 33133 -#define IDS_UNKNOWN_SWITCH 33134 -#define IDS_ADD_TO_PLAYLIST 33161 -#define IDS_OPEN_WITH_MPC 33162 -#define IDS_CANNOT_CHANGE_FORMAT 33163 -#define IDS_APP_DESCRIPTION 33164 -#define IDS_MAINFRM_12 33165 -#define IDS_MAINFRM_13 33166 -#define IDS_D3DFS_WARNING 33190 -#define IDS_MAINFRM_139 33191 -#define IDS_AG_TITLE2 33192 -#define IDS_REALVIDEO_INCOMPATIBLE 33193 -#define IDS_THUMB_ROWNUMBER 33195 -#define IDS_THUMB_COLNUMBER 33196 -#define IDS_THUMB_IMAGE_WIDTH 33197 -#define IDS_AG_CHAPTER2 33201 -#define IDS_VOLUME_OSD 33202 -#define IDS_BOOST_OSD 33203 -#define IDS_BALANCE_OSD 33204 -#define IDS_FULLSCREENMONITOR_CURRENT 33205 -#define ID_FILE_OPENDIRECTORY 33208 -#define IDS_MAINFRM_DIR_TITLE 33209 -#define IDS_MAINFRM_DIR_CHECK 33210 -#define IDS_AG_PAUSE 33212 -#define IDS_AG_TOGGLE_CAPTION 33213 -#define IDS_AG_TOGGLE_SEEKER 33214 -#define IDS_AG_TOGGLE_CONTROLS 33215 -#define IDS_AG_TOGGLE_INFO 33216 -#define IDS_AG_TOGGLE_STATS 33217 -#define IDS_AG_TOGGLE_STATUS 33218 -#define IDS_AG_TOGGLE_SUBRESYNC 33219 -#define IDS_AG_TOGGLE_PLAYLIST 33220 -#define IDS_AG_TOGGLE_CAPTURE 33221 -#define IDS_AG_TOGGLE_DEBUGSHADERS 33222 -#define IDS_AG_ZOOM_50 33223 -#define IDS_AG_ZOOM_100 33224 -#define IDS_AG_ZOOM_200 33225 -#define IDS_AG_NEXT_AR_PRESET 33226 -#define IDS_AG_VIDFRM_STRETCH 33227 -#define IDS_AG_VIDFRM_INSIDE 33228 -#define IDS_AG_VIDFRM_OUTSIDE 33229 -#define IDS_AG_PNS_RESET 33230 -#define IDS_AG_PNS_ROTATEX_P 33231 -#define IDS_AG_PNS_ROTATEX_M 33232 -#define IDS_AG_PNS_ROTATEY_P 33233 -#define IDS_AG_PNS_ROTATEY_M 33234 -#define IDS_AG_PNS_ROTATEZ_P 33235 -#define IDS_AG_PNS_ROTATEZ_M 33236 -#define IDS_AG_TEARING_TEST 33237 -#define IDS_SCALE_16_9 33239 -#define IDS_SCALE_WIDESCREEN 33240 -#define IDS_SCALE_ULTRAWIDE 33241 -#define IDS_PLAYLIST_HIDEFS 33242 -#define ID_VIEW_VSYNC 33243 -#define ID_VIEW_VSYNCOFFSET 33245 -#define ID_VIEW_VSYNCOFFSET_DECREASE 33246 -#define ID_VIEW_VSYNCOFFSET_INCREASE 33247 -#define IDS_AG_TOGGLE_NAVIGATION 33248 -#define ID_VIEW_VSYNCACCURATE 33260 -#define IDS_AG_VSYNCACCURATE 33261 -#define ID_VIEW_FULLSCREENGUISUPPORT 33263 -#define ID_VIEW_HIGHCOLORRESOLUTION 33264 -#define ID_VIEW_ENABLEFRAMETIMECORRECTION 33265 -#define ID_VIEW_EVROUTPUTRANGE 33269 -#define ID_VIEW_EVROUTPUTRANGE_0_255 33273 -#define ID_VIEW_EVROUTPUTRANGE_16_235 33274 -#define IDS_AG_ENABLEFRAMETIMECORRECTION 33275 -#define IDS_AG_TOGGLE_EDITLISTEDITOR 33277 -#define IDS_AG_EDL_IN 33278 -#define IDS_AG_EDL_OUT 33279 -#define IDS_AG_EDL_NEW_CLIP 33280 -#define ID_RECENT_FILES 33281 -#define ID_RECENT_FILES_CLEAR 33282 -#define IDS_RECENT_FILES_CLEAR 33283 -#define IDS_RECENT_FILES_QUESTION 33284 -#define ID_VIEW_FLUSHGPU_BEFOREVSYNC 33286 -#define ID_VIEW_FLUSHGPU_AFTERPRESENT 33287 -#define ID_VIEW_FLUSHGPU_WAIT 33288 -#define ID_VIEW_D3DFULLSCREEN 33289 -#define ID_VIEW_DISABLEDESKTOPCOMPOSITION 33290 -#define ID_VIEW_ALTERNATIVEVSYNC 33291 -#define ID_VIEW_RESET_DEFAULT 33292 -#define ID_VIEW_RESET_OPTIMAL 33293 -#define IDS_AG_EDL_SAVE 33294 -#define IDC_RESETDEVICE 33400 -#define IDS_NAVIGATE_TUNERSCAN 33401 -#define IDS_SUBTITLES_ERROR 33402 -#define IDC_CHECK_ENHANCED_TASKBAR 33403 -#define IDC_CACHESHADERS 33404 -#define ID_VIEW_SYNCHRONIZEVIDEO 33408 -#define ID_VIEW_SYNCHRONIZEDISPLAY 33409 -#define ID_VIEW_SYNCHRONIZENEAREST 33410 -#define ID_VIEW_NAVIGATION 33415 -#define IDS_AG_VIDFRM_ZOOM1 33419 -#define IDS_AG_VIDFRM_ZOOM2 33420 -#define IDS_AG_VIDFRM_SWITCHZOOM 33422 -#define IDS_ENABLE_ALL_FILTERS 33423 -#define IDS_DISABLE_ALL_FILTERS 33424 -#define IDS_ENABLE_AUDIO_FILTERS 33425 -#define IDS_DISABLE_AUDIO_FILTERS 33426 -#define IDS_ENABLE_VIDEO_FILTERS 33427 -#define IDS_DISABLE_VIDEO_FILTERS 33428 -#define IDS_STRETCH_TO_WINDOW 33429 -#define IDS_TOUCH_WINDOW_FROM_INSIDE 33430 -#define IDS_ZOOM1 33431 -#define IDS_ZOOM2 33432 -#define IDS_TOUCH_WINDOW_FROM_OUTSIDE 33433 -#define IDS_AUDIO_STREAM 33434 -#define IDS_AG_REOPEN 33435 -#define IDS_TIME_TOOLTIP_ABOVE 33440 -#define IDS_TIME_TOOLTIP_BELOW 33441 -#define IDS_VIDEO_STREAM 33442 -#define IDS_APPLY 33443 -#define IDS_CLEAR 33444 -#define IDS_CANCEL 33445 -#define IDS_THUMB_THUMBNAILS 33446 -#define IDS_THUMB_PIXELS 33447 -#define IDS_TEXTFILE_ENC 33448 -#define ID_PLAY_REPEAT_FOREVER 33449 -#define ID_PLAY_REPEAT_ONEFILE 33450 -#define ID_PLAY_REPEAT_WHOLEPLAYLIST 33451 -#define IDS_AG_ZOOM_25 33452 -#define ID_PLAY_REPEAT_AB 33453 -#define IDS_AG_MOUSE_MODIFIER 33453 -#define ID_PLAY_REPEAT_AB_MARK_A 33454 -#define ID_PLAY_REPEAT_AB_MARK_B 33455 -#define ID_VIEW_ZOOM_SUB 33456 -#define ID_VIEW_ZOOM_ADD 33457 -#define IDS_AG_ZOOM_ADD 33458 -#define IDS_AG_ZOOM_SUB 33459 -#define IDS_SEEKBAR_HOVER_PREVIEW 33460 -#define IDS_SEEKBAR_HOVER_TOOLTIP 33461 -#define ID_RECENT_FILE_START 34000 -#define ID_RECENT_FILE_END 34999 -#define IDS_MFMT_AVI 39001 -#define IDS_MFMT_MPEG 39002 -#define IDS_MFMT_MPEGTS 39003 -#define IDS_MFMT_DVDVIDEO 39004 -#define IDS_MFMT_MKV 39005 -#define IDS_MFMT_WEBM 39006 -#define IDS_MFMT_MP4 39007 -#define IDS_MFMT_MOV 39008 -#define IDS_MFMT_3GP 39009 -#define IDS_MFMT_3GA 39010 -#define IDS_MFMT_FLV 39011 -#define IDS_MFMT_OGM 39012 -#define IDS_MFMT_RM 39013 -#define IDS_MFMT_RT 39014 -#define IDS_MFMT_WMV 39015 -#define IDS_MFMT_BINK 39018 -#define IDS_MFMT_FLIC 39019 -#define IDS_MFMT_DSM 39020 -#define IDS_MFMT_IVF 39021 -#define IDS_MFMT_AVS 39022 -#define IDS_MFMT_OTHER 39401 -#define IDS_MFMT_SWF 39403 -#define IDS_MFMT_OTHER_AUDIO 39404 -#define IDS_MFMT_AC3 39501 -#define IDS_MFMT_AIFF 39502 -#define IDS_MFMT_ALAC 39503 -#define IDS_MFMT_AMR 39504 -#define IDS_MFMT_APE 39505 -#define IDS_MFMT_AU 39506 -#define IDS_MFMT_CDA 39507 -#define IDS_MFMT_FLAC 39508 -#define IDS_MFMT_M4A 39509 -#define IDS_MFMT_MIDI 39510 -#define IDS_MFMT_MKA 39511 -#define IDS_MFMT_MP3 39512 -#define IDS_MFMT_MPA 39513 -#define IDS_MFMT_MPC 39514 -#define IDS_MFMT_OFR 39515 -#define IDS_MFMT_OGG 39516 -#define IDS_MFMT_RA 39517 -#define IDS_MFMT_TAK 39518 -#define IDS_MFMT_TTA 39519 -#define IDS_MFMT_WAV 39520 -#define IDS_MFMT_WMA 39521 -#define IDS_MFMT_WV 39522 -#define IDS_MFMT_OPUS 39523 -#define IDS_MFMT_DTS 39524 -#define IDS_MFMT_PLS 39901 -#define IDS_MFMT_BDPLS 39902 -#define IDS_MFMT_RAR 39903 -#define IDTB_BUTTON1 40001 -#define IDTB_BUTTON2 40002 -#define IDTB_BUTTON3 40003 -#define IDTB_BUTTON4 40004 -#define IDTB_BUTTON5 40005 -#define IDR_TB_PLAY 41001 -#define IDR_TB_PAUSE 41002 -#define IDR_TB_STOP 41003 -#define IDS_FRONT_LEFT 41006 -#define IDS_FRONT_RIGHT 41007 -#define IDS_FRONT_CENTER 41008 -#define IDS_LOW_FREQUENCY 41009 -#define IDS_BACK_LEFT 41010 -#define IDS_BACK_RIGHT 41011 -#define IDS_FRONT_LEFT_OF_CENTER 41012 -#define IDS_FRONT_RIGHT_OF_CENTER 41013 -#define IDS_BACK_CENTER 41014 -#define IDS_SIDE_LEFT 41015 -#define IDS_SIDE_RIGHT 41016 -#define IDS_TOP_CENTER 41017 -#define IDS_TOP_FRONT_LEFT 41018 -#define IDS_TOP_FRONT_CENTER 41019 -#define IDS_TOP_FRONT_RIGHT 41020 -#define IDS_TOP_BACK_LEFT 41021 -#define IDS_TOP_BACK_CENTER 41022 -#define IDS_TOP_BACK_RIGHT 41023 -#define IDS_LOGO_AUTHOR 41024 -#define IDC_RESTORERESCHECK 41025 -#define IDS_NO_MORE_MEDIA 41026 -#define IDS_FIRST_IN_FOLDER 41027 -#define IDS_LAST_IN_FOLDER 41028 -#define IDS_FAVORITES_QUICKADDFAVORITE 41105 -#define IDS_DVB_CHANNEL_NUMBER 41109 -#define IDS_DVB_CHANNEL_NAME 41110 -#define IDS_DVB_CHANNEL_FREQUENCY 41111 -#define IDS_DVB_CHANNEL_ENCRYPTION 41112 -#define IDS_YES 41113 -#define IDS_NO 41114 -#define IDS_DVB_CHANNEL_START_SCAN 41115 -#define IDS_DVB_CHANNEL_STOP_SCAN 41116 -#define IDS_DVB_TVNAV_SEERADIO 41117 -#define IDS_DVB_TVNAV_SEETV 41118 -#define IDS_DVB_CHANNEL_FORMAT 41119 -#define IDS_DVB_CHANNEL_FPS 41120 -#define IDS_DVB_CHANNEL_RESOLUTION 41121 -#define IDS_DVB_CHANNEL_ASPECT_RATIO 41122 -#define IDS_OSD_RS_VSYNC_ON 41200 -#define IDS_OSD_RS_VSYNC_OFF 41201 -#define IDS_OSD_RS_ACCURATE_VSYNC_ON 41202 -#define IDS_OSD_RS_ACCURATE_VSYNC_OFF 41203 -#define IDS_OSD_RS_SYNC_TO_DISPLAY_ON 41204 -#define IDS_OSD_RS_SYNC_TO_DISPLAY_OFF 41205 -#define IDS_OSD_RS_SYNC_TO_VIDEO_ON 41206 -#define IDS_OSD_RS_SYNC_TO_VIDEO_OFF 41207 -#define IDS_OSD_RS_PRESENT_NEAREST_ON 41208 -#define IDS_OSD_RS_PRESENT_NEAREST_OFF 41209 -#define IDS_OSD_RS_COLOR_MANAGEMENT_ON 41210 -#define IDS_OSD_RS_COLOR_MANAGEMENT_OFF 41211 -#define IDS_OSD_RS_INPUT_TYPE_AUTO 41212 -#define IDS_OSD_RS_INPUT_TYPE_HDTV 41213 -#define IDS_OSD_RS_INPUT_TYPE_SD_NTSC 41214 -#define IDS_OSD_RS_INPUT_TYPE_SD_PAL 41215 -#define IDS_OSD_RS_AMBIENT_LIGHT_BRIGHT 41216 -#define IDS_OSD_RS_AMBIENT_LIGHT_DIM 41217 -#define IDS_OSD_RS_AMBIENT_LIGHT_DARK 41218 -#define IDS_OSD_RS_REND_INTENT_PERCEPT 41219 -#define IDS_OSD_RS_REND_INTENT_RELATIVE 41220 -#define IDS_OSD_RS_REND_INTENT_SATUR 41221 -#define IDS_OSD_RS_REND_INTENT_ABSOLUTE 41222 -#define IDS_OSD_RS_OUTPUT_RANGE 41223 -#define IDS_OSD_RS_FLUSH_BEF_VSYNC_ON 41224 -#define IDS_OSD_RS_FLUSH_BEF_VSYNC_OFF 41225 -#define IDS_OSD_RS_FLUSH_AFT_PRES_ON 41226 -#define IDS_OSD_RS_FLUSH_AFT_PRES_OFF 41227 -#define IDS_OSD_RS_WAIT_ON 41228 -#define IDS_OSD_RS_WAIT_OFF 41229 -#define IDS_OSD_RS_D3D_FULLSCREEN_ON 41230 -#define IDS_OSD_RS_D3D_FULLSCREEN_OFF 41231 -#define IDS_OSD_RS_NO_DESKTOP_COMP_ON 41232 -#define IDS_OSD_RS_NO_DESKTOP_COMP_OFF 41233 -#define IDS_OSD_RS_ALT_VSYNC_ON 41234 -#define IDS_OSD_RS_ALT_VSYNC_OFF 41235 -#define IDS_OSD_RS_RESET_DEFAULT 41236 -#define IDS_OSD_RS_RESET_OPTIMAL 41237 -#define IDS_OSD_RS_D3D_FS_GUI_SUPP_ON 41238 -#define IDS_OSD_RS_D3D_FS_GUI_SUPP_OFF 41239 -#define IDS_OSD_RS_10BIT_RBG_OUT_ON 41240 -#define IDS_OSD_RS_10BIT_RBG_OUT_OFF 41241 -#define IDS_OSD_RS_10BIT_RBG_IN_ON 41242 -#define IDS_OSD_RS_10BIT_RBG_IN_OFF 41243 -#define IDS_OSD_RS_FULL_FP_PROCESS_ON 41244 -#define IDS_OSD_RS_FULL_FP_PROCESS_OFF 41245 -#define IDS_OSD_RS_HALF_FP_PROCESS_ON 41246 -#define IDS_OSD_RS_HALF_FP_PROCESS_OFF 41247 -#define IDS_OSD_RS_FT_CORRECTION_ON 41248 -#define IDS_OSD_RS_FT_CORRECTION_OFF 41249 -#define IDS_OSD_RS_TARGET_VSYNC_OFFSET 41250 -#define IDS_OSD_RS_VSYNC_OFFSET 41251 -#define IDS_OSD_SPEED 41252 -#define IDS_OSD_THUMBS_SAVED 41253 -#define IDS_MENU_VIDEO_STREAM 41254 -#define IDS_MENU_VIDEO_ANGLE 41255 -#define IDS_RESET_SETTINGS 41256 -#define IDS_RESET_SETTINGS_WARNING 41257 -#define IDS_RESET_SETTINGS_MUTEX 41258 -#define IDS_EXPORT_SETTINGS 41259 -#define IDS_EXPORT_SETTINGS_WARNING 41260 -#define IDS_EXPORT_SETTINGS_SUCCESS 41261 -#define IDS_EXPORT_SETTINGS_FAILED 41262 -#define IDS_BDA_ERROR 41263 -#define IDS_BDA_ERROR_CREATE_TUNER 41264 -#define IDS_BDA_ERROR_CREATE_RECEIVER 41265 -#define IDS_BDA_ERROR_CONNECT_NW_TUNER 41266 -#define IDS_BDA_ERROR_CONNECT_TUNER_REC 41267 -#define IDS_BDA_ERROR_CONNECT_TUNER 41268 -#define IDS_BDA_ERROR_DEMULTIPLEXER 41269 -#define IDS_GOTO_ERROR_PARSING_TIME 41270 -#define IDS_GOTO_ERROR_PARSING_TEXT 41271 -#define IDS_GOTO_ERROR_PARSING_FPS 41272 -#define IDS_FRAME_STEP_ERROR_RENDERER 41273 -#define IDS_SCREENSHOT_ERROR_SHOCKWAVE 41276 -#define IDS_SCREENSHOT_ERROR_OVERLAY 41277 -#define IDS_SUBDL_DLG_CONNECT_ERROR 41278 -#define IDS_MB_SHOW_EDL_EDITOR 41279 -#define IDS_CAPTURE_ERROR 41280 -#define IDS_CAPTURE_ERROR_VIDEO 41281 -#define IDS_CAPTURE_ERROR_AUDIO 41282 -#define IDS_CAPTURE_ERROR_ADD_BUFFER 41283 -#define IDS_CAPTURE_ERROR_CONNECT_BUFF 41284 -#define IDS_CAPTURE_ERROR_ADD_ENCODER 41285 -#define IDS_CAPTURE_ERROR_CONNECT_ENC 41286 -#define IDS_CAPTURE_ERROR_COMPRESSION 41287 -#define IDS_CAPTURE_ERROR_MULTIPLEXER 41288 -#define IDS_CAPTURE_ERROR_VID_CAPT_PIN 41289 -#define IDS_CAPTURE_ERROR_AUD_CAPT_PIN 41290 -#define IDS_CAPTURE_ERROR_OUT_FILE 41291 -#define IDS_CAPTURE_ERROR_AUD_OUT_FILE 41292 -#define IDS_SUBRESYNC_TIME_FORMAT 41293 -#define IDS_EXTERNAL_FILTERS_ERROR_MT 41294 -#define IDS_WEBSERVER_ERROR_TEST 41295 -#define IDS_AFTERPLAYBACK_EXIT 41296 -#define IDS_AFTERPLAYBACK_STANDBY 41297 -#define IDS_AFTERPLAYBACK_HIBERNATE 41298 -#define IDS_AFTERPLAYBACK_SHUTDOWN 41299 -#define IDS_AFTERPLAYBACK_LOGOFF 41300 -#define IDS_AFTERPLAYBACK_LOCK 41301 -#define IDS_AFTERPLAYBACK_MONITOROFF 41302 -#define IDS_AFTERPLAYBACK_PLAYNEXT 41303 -#define IDS_AFTERPLAYBACK_DONOTHING 41304 -#define IDS_OSD_BRIGHTNESS 41305 -#define IDS_OSD_CONTRAST 41306 -#define IDS_OSD_HUE 41307 -#define IDS_OSD_SATURATION 41308 -#define IDS_OSD_RESET_COLOR 41309 -#define IDS_OSD_NO_COLORCONTROL 41310 -#define IDS_BRIGHTNESS_INC 41311 -#define IDS_BRIGHTNESS_DEC 41312 -#define IDS_CONTRAST_INC 41313 -#define IDS_CONTRAST_DEC 41314 -#define IDS_HUE_INC 41315 -#define IDS_HUE_DEC 41316 -#define IDS_SATURATION_INC 41317 -#define IDS_SATURATION_DEC 41318 -#define IDS_RESET_COLOR 41319 -#define ID_HELP_CHECKFORUPDATE 41321 -#define IDS_USING_LATEST_STABLE 41322 -#define IDS_USING_NEWER_VERSION 41323 -#define IDS_NEW_UPDATE_AVAILABLE 41324 -#define IDS_UPDATE_ERROR 41325 -#define IDS_UPDATE_CLOSE 41326 -#define IDS_OSD_ZOOM 41327 -#define IDS_OSD_ZOOM_AUTO 41328 -#define IDS_CUSTOM_CHANNEL_MAPPING 41329 -#define IDS_OSD_CUSTOM_CH_MAPPING_ON 41330 -#define IDS_OSD_CUSTOM_CH_MAPPING_OFF 41331 -#define IDS_NORMALIZE 41332 -#define IDS_OSD_NORMALIZE_ON 41333 -#define IDS_OSD_NORMALIZE_OFF 41334 -#define IDS_REGAIN_VOLUME 41335 -#define IDS_OSD_REGAIN_VOLUME_ON 41336 -#define IDS_OSD_REGAIN_VOLUME_OFF 41337 -#define IDS_SIZE_UNIT_BYTES 41338 -#define IDS_SIZE_UNIT_K 41339 -#define IDS_SIZE_UNIT_M 41340 -#define IDS_SIZE_UNIT_G 41341 -#define IDS_SPEED_UNIT_K 41342 -#define IDS_SPEED_UNIT_M 41343 -#define IDS_SPEED_UNIT_G 41344 -#define IDS_FILE_FAV_ADDED 41345 -#define IDS_DVD_FAV_ADDED 41346 -#define IDS_CAPTURE_SETTINGS 41347 -#define IDS_NAVIGATION_BAR 41348 -#define IDS_SUBRESYNC_CAPTION 41350 -#define IDS_SUBRESYNC_CLN_TIME 41351 -#define IDS_SUBRESYNC_CLN_END 41352 -#define IDS_SUBRESYNC_CLN_PREVIEW 41353 -#define IDS_SUBRESYNC_CLN_VOB_ID 41354 -#define IDS_SUBRESYNC_CLN_CELL_ID 41355 -#define IDS_SUBRESYNC_CLN_FORCED 41356 -#define IDS_SUBRESYNC_CLN_TEXT 41357 -#define IDS_SUBRESYNC_CLN_STYLE 41358 -#define IDS_SUBRESYNC_CLN_FONT 41359 -#define IDS_SUBRESYNC_CLN_CHARSET 41360 -#define IDS_SUBRESYNC_CLN_UNICODE 41361 -#define IDS_SUBRESYNC_CLN_LAYER 41362 -#define IDS_SUBRESYNC_CLN_ACTOR 41363 -#define IDS_SUBRESYNC_CLN_EFFECT 41364 -#define IDS_PLAYLIST_CAPTION 41365 -#define IDS_PPAGE_FS_CLN_ON_OFF 41366 -#define IDS_PPAGE_FS_CLN_FROM_FPS 41367 -#define IDS_PPAGE_FS_CLN_TO_FPS 41368 -#define IDS_PPAGE_FS_CLN_DISPLAY_MODE 41369 -#define IDS_PPAGE_FS_DEFAULT 41370 -#define IDS_PPAGE_FS_OTHER 41371 -#define IDS_PPAGE_OUTPUT_SYS_DEF 41372 -#define IDS_GRAPH_INTERFACES_ERROR 41373 -#define IDS_GRAPH_TARGET_WND_ERROR 41374 -#define IDS_DVD_NAV_ALL_PINS_ERROR 41375 -#define IDS_DVD_NAV_SOME_PINS_ERROR 41376 -#define IDS_DVD_INTERFACES_ERROR 41377 -#define IDS_CAPTURE_LIVE 41378 -#define IDS_CAPTURE_ERROR_VID_FILTER 41379 -#define IDS_CAPTURE_ERROR_AUD_FILTER 41380 -#define IDS_CAPTURE_ERROR_DEVICE 41381 -#define IDS_INVALID_PARAMS_ERROR 41382 -#define IDS_EDIT_LIST_EDITOR 41383 -#define IDS_GOTO_ERROR_INVALID_TIME 41384 -#define IDS_MISSING_ICONS_LIB 41386 -#define IDS_SUBDL_DLG_FILENAME_COL 41387 -#define IDS_SUBDL_DLG_LANGUAGE_COL 41388 -#define IDS_SUBDL_DLG_FORMAT_COL 41389 -#define IDS_SUBDL_DLG_DISC_COL 41390 -#define IDS_SUBDL_DLG_TITLES_COL 41391 -#define IDS_SUBDL_DLG_DOWNLOADING 41392 -#define IDS_SUBDL_DLG_PARSING 41393 -#define IDS_SUBDL_DLG_NOT_FOUND 41394 -#define IDS_SUBDL_DLG_SUBS_AVAIL 41395 -#define IDS_UPDATE_CONFIG_AUTO_CHECK 41396 -#define IDS_ZOOM_50 41397 -#define IDS_ZOOM_100 41398 -#define IDS_ZOOM_200 41399 -#define IDS_ZOOM_AUTOFIT 41400 -#define IDS_ZOOM_AUTOFIT_LARGER 41401 -#define IDS_AG_ZOOM_AUTO_FIT_LARGER 41402 -#define IDS_OSD_ZOOM_AUTO_LARGER 41403 -#define IDS_TOOLTIP_EXPLORE_TO_FILE 41404 -#define IDS_TOOLTIP_REMAINING_TIME 41405 -#define IDS_UPDATE_DELAY_ERROR_TITLE 41406 -#define IDS_UPDATE_DELAY_ERROR_MSG 41407 -#define IDS_AUDIOSWITCHER 41408 -#define IDS_ICONS_REASSOC_DLG_TITLE 41409 -#define IDS_ICONS_REASSOC_DLG_INSTR 41410 -#define IDS_ICONS_REASSOC_DLG_CONTENT 41411 -#define IDS_PPAGE_OUTPUT_OLDRENDERER 41412 -#define IDS_PPAGE_OUTPUT_OVERLAYMIXER 41413 -#define IDS_ZOOM_25 41414 -#define IDS_PPAGE_OUTPUT_VMR9WINDOWED 41415 -#define IDS_PPAGE_OUTPUT_VMR9RENDERLESS 41417 -#define IDS_PPAGE_OUTPUT_EVR 41418 -#define IDS_PPAGE_OUTPUT_EVR_CUSTOM 41419 -#define IDS_PPAGE_OUTPUT_DXR 41420 -#define IDS_PPAGE_OUTPUT_NULL_COMP 41421 -#define IDS_PPAGE_OUTPUT_NULL_UNCOMP 41422 -#define IDS_PPAGE_OUTPUT_MADVR 41423 -#define IDS_PPAGE_OUTPUT_SYNC 41424 -#define IDS_PPAGE_OUTPUT_AUD_MPC_REND 41425 -#define IDS_PPAGE_OUTPUT_SURF_OFFSCREEN 41427 -#define IDS_PPAGE_OUTPUT_SURF_2D 41428 -#define IDS_PPAGE_OUTPUT_SURF_3D 41429 -#define IDS_PPAGE_OUTPUT_RESIZE_NN 41430 -#define IDS_PPAGE_OUTPUT_RESIZER_BILIN 41431 -#define IDS_PPAGE_OUTPUT_RESIZER_BIL_PS 41432 -#define IDS_PPAGE_OUTPUT_RESIZER_BICUB1 41433 -#define IDS_PPAGE_OUTPUT_RESIZER_BICUB2 41434 -#define IDS_PPAGE_OUTPUT_RESIZER_BICUB3 41435 -#define IDS_PPAGE_OUTPUT_UNAVAILABLE 41436 -#define IDS_PPAGE_OUTPUT_UNAVAILABLEMSG 41437 -#define IDS_PPAGE_OUTPUT_AUD_NULL_COMP 41438 -#define IDS_PPAGE_OUTPUT_AUD_NULL_UNCOMP 41439 -#define IDS_PPAGE_OUTPUT_AUD_INTERNAL_REND 41440 -#define IDS_EMB_RESOURCES_VIEWER_NAME 41441 -#define IDS_EMB_RESOURCES_VIEWER_TYPE 41442 -#define IDS_EMB_RESOURCES_VIEWER_INFO 41443 -#define IDS_SUBTITLES_DOWNLOAD 41444 -#define IDS_SUBTITLES_UPLOAD 41445 -#define IDS_SUBFILE_DELAY 41448 -#define IDS_SPEEDSTEP_AUTO 41449 -#define IDS_EXPORT_SETTINGS_NO_KEYS 41450 -#define IDS_RFS_NO_FILES 41451 -#define IDS_RFS_COMPRESSED 41452 -#define IDS_RFS_ENCRYPTED 41453 -#define IDS_RFS_MISSING_VOLS 41454 -#define IDS_OSD_D3DFS_REMINDER 41455 -#define IDS_LANG_PREF_EXAMPLE 41456 -#define IDS_OVERRIDE_EXT_SPLITTER_CHOICE 41457 -#define IDC_SPLITTER_CONF 41458 -#define IDC_VIDEO_DEC_CONF 41459 -#define IDC_AUDIO_DEC_CONF 41460 -#define IDS_NAVIGATE_BD_PLAYLISTS 41461 -#define IDS_NAVIGATE_PLAYLIST 41462 -#define IDS_NAVIGATE_CHAPTERS 41463 -#define IDS_NAVIGATE_TITLES 41464 -#define IDS_NAVIGATE_CHANNELS 41465 -#define IDS_PPAGE_OUTPUT_MPCVR 41466 -#define IDS_PPAGE_OUTPUT_VMR7 41467 -#define IDS_MOUSE_CLICK_MIDDLE 41702 -#define IDS_MOUSE_CLICK_X1 41703 -#define IDS_MOUSE_CLICK_X2 41704 -#define IDS_MOUSE_WHEEL_UP 41705 -#define IDS_MOUSE_WHEEL_DOWN 41706 -#define IDS_MOUSE_WHEEL_LEFT 41707 -#define IDS_MOUSE_WHEEL_RIGHT 41708 -#define IDS_MOUSE_ACTION 41710 -#define IDS_MOUSE_COMMAND 41711 -#define IDS_MOUSE_RIGHT_BUTTON 41712 -#define IDS_PPAGE_CAPTURE_FG0 57345 -#define IDS_PPAGE_CAPTURE_FG1 57346 -#define IDS_PPAGE_CAPTURE_FG2 57347 -#define IDS_PPAGE_CAPTURE_FGDESC0 57348 -#define IDS_PPAGE_CAPTURE_FGDESC1 57349 -#define IDS_PPAGE_CAPTURE_FGDESC2 57350 -#define IDS_PPAGE_CAPTURE_SFG0 57351 -#define IDS_PPAGE_CAPTURE_SFG1 57352 -#define IDS_PPAGE_CAPTURE_SFG2 57353 -#define IDS_INFOBAR_PARENTAL_RATING 57354 -#define IDS_PARENTAL_RATING 57355 -#define IDS_NO_PARENTAL_RATING 57356 -#define IDS_INFOBAR_CONTENT 57357 -#define IDS_CONTENT_MOVIE_DRAMA 57358 -#define IDS_CONTENT_NEWS_CURRENTAFFAIRS 57359 -#define IDS_CONTENT_SHOW_GAMESHOW 57360 -#define IDS_CONTENT_SPORTS 57361 -#define IDS_CONTENT_CHILDREN_YOUTH_PROG 57362 -#define IDS_CONTENT_MUSIC_BALLET_DANCE 57363 -#define IDS_CONTENT_MUSIC_ART_CULTURE 57364 -#define IDS_CONTENT_SOCIAL_POLITICAL_ECO 57365 -#define IDS_CONTENT_LEISURE 57366 -#define IDS_FILE_RECYCLE 57367 -#define IDS_AG_SAVE_COPY 57368 -#define IDS_FASTSEEK_LATEST 57369 -#define IDS_FASTSEEK_NEAREST 57370 -#define IDS_HOOKS_FAILED 57371 -#define IDS_PPAGEFULLSCREEN_SHOWNEVER 57372 -#define IDS_PPAGEFULLSCREEN_SHOWMOVED 57373 -#define IDS_PPAGEFULLSCREEN_SHOHHOVERED 57374 -#define IDS_MAINFRM_PRE_SHADERS_FAILED 57375 -#define IDS_MAINFRM_POST_SHADERS_FAILED 57376 -#define IDS_MAINFRM_BOTH_SHADERS_FAILED 57377 -#define IDS_DEBUGSHADERS_FIRSTRUN_MSG 57378 -#define IDS_SHADER_DLL_ERR_0 57379 -#define IDS_SHADER_DLL_ERR_1 57380 -#define IDS_OSD_SHADERS_PRESET 57381 -#define ID_SHADERS_PRESET_NEXT 57382 -#define IDS_AG_SHADERS_PRESET_NEXT 57383 -#define ID_SHADERS_PRESET_PREV 57384 -#define IDS_AG_SHADERS_PRESET_PREV 57385 -#define IDS_STRING_COLON 57386 -#define IDS_RECORD_START 57387 -#define IDS_RECORD_STOP 57388 -#define IDS_BALANCE 57389 -#define IDS_BALANCE_L 57390 -#define IDS_BALANCE_R 57391 -#define IDS_VOLUME 57392 -#define IDS_BOOST 57393 -#define IDS_PLAYLIST_ADDFOLDER 57394 -#define IDS_HW_INDICATOR 57395 -#define IDS_TOOLTIP_SOFTWARE_DECODING 57396 -#define IDS_STATSBAR_PLAYBACK_RATE 57397 -#define IDS_FILTERS_COPY_TO_CLIPBOARD 57398 -#define IDS_CREDENTIALS_SERVER 57399 -#define IDS_CREDENTIALS_CONNECT 57400 -#define IDS_SUB_SAVE_EXTERNAL_STYLE_FILE 57401 -#define IDS_CONTENT_EDUCATION_SCIENCE 57402 -#define IDS_PPAGEADVANCED_HIDE_WINDOWED 57403 -#define IDS_PPAGEADVANCED_BLOCK_VSFILTER 57404 -#define IDS_PPAGEADVANCED_COL_NAME 57405 -#define IDS_PPAGEADVANCED_COL_VALUE 57406 -#define IDS_PPAGEADVANCED_RECENT_FILES_NUMBER 57407 -#define IDS_PPAGEADVANCED_FILE_POS_LONGER 57408 -#define IDS_PPAGEADVANCED_FILE_POS_AUDIO 57409 -#define IDS_AFTER_PLAYBACK_DO_NOTHING 57410 -#define IDS_AFTER_PLAYBACK_PLAY_NEXT 57411 -#define IDS_AFTER_PLAYBACK_REWIND 57412 -#define IDS_AFTER_PLAYBACK_CLOSE 57413 -#define IDS_AFTER_PLAYBACK_EXIT 57414 -#define IDS_AFTER_PLAYBACK_MONITOROFF 57415 -#define IDS_IMAGE_JPEG_QUALITY 57416 -#define IDS_IMAGE_QUALITY 57417 -#define IDS_PPAGEADVANCED_COVER_SIZE_LIMIT 57418 -#define IDS_SUBTITLE_DELAY_STEP_TOOLTIP 57419 -#define IDS_HOTKEY_NOT_DEFINED 57420 -#define IDS_NAVIGATION_WATCH 57421 -#define IDS_NAVIGATION_MOVE_UP 57422 -#define IDS_NAVIGATION_MOVE_DOWN 57423 -#define IDS_NAVIGATION_SORT 57424 -#define IDS_NAVIGATION_REMOVE_ALL 57425 -#define IDS_REMOVE_CHANNELS_QUESTION 57426 -#define IDS_MEDIAINFO_NO_INFO_AVAILABLE 57427 -#define IDS_MEDIAINFO_ANALYSIS_IN_PROGRESS 57428 -#define IDS_ASPECT_RATIO_FMT 57429 -#define IDS_PPAGEADVANCED_LOGGER 57430 -#define IDS_TIMER_REMAINING_TIME 57431 -#define IDS_TIMER_HIGH_PRECISION 57432 -#define IDS_AFTERPLAYBACK_REWIND 57433 -#define IDS_AFTERPLAYBACK_CLOSE 57434 -#define IDS_FRAME_INIT_FAILED 57435 -#define IDS_TIME_SHIFT_TOOLTIP 57436 -#define IDS_WEBUI_DISABLED_PREVIEW_MSG 57437 -#define IDS_WEBUI_PREVIEW_WARNING 57438 -#define IDS_SUBTITLE_RENDERER_INTERNAL 57439 -#define IDS_SUBTITLE_RENDERER_VS_FILTER 57440 -#define IDS_SUBTITLE_RENDERER_XY_SUB_FILTER 57441 -#define IDS_SUBDL_DLG_PROVIDER_COL 57442 -#define IDS_SUBDL_DLG_HI_COL 57443 -#define IDS_SUBDL_DLG_DOWNLOADS_COL 57444 -#define IDS_SUBDL_DLG_SCORE_COL 57445 -#define IDS_SUBDL_DLG_FAILED 57446 -#define IDS_SUBDL_DLG_ABORTED 57447 -#define IDS_SUBDL_DLG_FOUND 57448 -#define IDS_SUBDL_DLG_NOTFOUND 57449 -#define IDS_SUBDL_DLG_TITLE 57450 -#define IDS_SUBDL_DLG_SEARCHING 57451 -#define IDS_SUBDL_DLG_ABORTING 57452 -#define IDS_SUBUL_DLG_USERNAME_COL 57453 -#define IDS_SUBUL_DLG_STATUS_COL 57454 -#define IDS_SUBUL_DLG_STATUS_READY 57455 -#define IDS_SUBUL_DLG_STATUS_NOTIMPLEMENTED 57456 -#define IDS_SUBUL_DLG_STATUS_UPLOADING 57457 -#define IDS_SUBUL_DLG_STATUS_UPLOADED 57458 -#define IDS_SUBUL_DLG_STATUS_FAILED 57459 -#define IDS_SUBUL_DLG_STATUS_ABORTED 57460 -#define IDS_SUBUL_DLG_STATUS_ALREADYEXISTS 57461 -#define IDS_SUBUL_DLG_UPLOADING 57462 -#define IDS_SUBUL_DLG_UPLOADED 57463 -#define IDS_SUBUL_DLG_ABORTED 57464 -#define IDS_SUBUL_DLG_FAILED 57465 -#define IDS_SUBMENU_DOWNLOAD 57466 -#define IDS_SUBMENU_SETUP 57467 -#define IDS_SUBMENU_RESET 57468 -#define IDS_SUBMENU_MOVEUP 57469 -#define IDS_SUBMENU_MOVEDOWN 57470 -#define IDS_SUBMENU_OPENURL 57471 -#define IDS_SUBPP_DLG_LANGUAGES_COL 57472 -#define IDS_SUBPP_DLG_LANGUAGES_ERROR 57473 -#define IDS_SUB_CREDENTIALS_TITLE 57474 -#define IDS_SUB_CREDENTIALS_MSG 57475 -#define IDS_ASPECT_RATIO_SAR 57476 -#define IDS_SUBDL_DLG_DOWNLOADED 57477 -#define IDS_SUBUL_DLG_TITLE 57478 -#define IDS_SUBUL_DLG_CONFIRM 57479 -#define IDS_SUBPP_DLG_FETCHING_LANGUAGES 57480 -#define IDS_SUB_CREDENTIALS_ERROR 57481 -#define IDS_SUB_AUTODL_IGNORE_TOOLTIP 57482 -#define IDS_CMD_PATHNAME 57483 -#define IDS_CMD_DUB 57484 -#define IDS_CMD_DUBDELAY 57485 -#define IDS_CMD_D3DFS 57486 -#define IDS_CMD_SUB 57487 -#define IDS_CMD_FILTER 57488 -#define IDS_CMD_DVD 57489 -#define IDS_CMD_DVDPOS_TC 57490 -#define IDS_CMD_DVDPOS_TIME 57491 -#define IDS_CMD_CD 57492 -#define IDS_CMD_DEVICE 57493 -#define IDS_CMD_OPEN 57494 -#define IDS_CMD_PLAY 57495 -#define IDS_CMD_CLOSE 57496 -#define IDS_CMD_SHUTDOWN 57497 -#define IDS_CMD_STANDBY 57498 -#define IDS_CMD_HIBERNATE 57499 -#define IDS_CMD_LOGOFF 57500 -#define IDS_CMD_LOCK 57501 -#define IDS_CMD_MONITOROFF 57502 -#define IDS_CMD_PLAYNEXT 57503 -#define IDS_CMD_FULLSCREEN 57504 -#define IDS_CMD_MINIMIZED 57505 -#define IDS_CMD_NEW 57506 -#define IDS_CMD_ADD 57507 -#define IDS_CMD_RANDOMIZE 57508 -#define IDS_CMD_REGVID 57509 -#define IDS_CMD_REGAUD 57510 -#define IDS_CMD_REGPL 57511 -#define IDS_CMD_REGALL 57512 -#define IDS_CMD_UNREGALL 57513 -#define IDS_CMD_START 57514 -#define IDS_CMD_STARTPOS 57515 -#define IDS_CMD_FIXEDSIZE 57516 -#define IDS_CMD_MONITOR 57517 -#define IDS_CMD_AUDIORENDERER 57518 -#define IDS_CMD_SHADERPRESET 57519 -#define IDS_CMD_PNS 57520 -#define IDS_CMD_ICONASSOC 57521 -#define IDS_CMD_NOFOCUS 57522 -#define IDS_CMD_WEBPORT 57523 -#define IDS_CMD_DEBUG 57524 -#define IDS_CMD_NOCRASHREPORTER 57525 -#define IDS_CMD_SLAVE 57526 -#define IDS_CMD_HWGPU 57527 -#define IDS_CMD_RESET 57528 -#define IDS_CMD_HELP 57529 -#define IDS_PPAGEADVANCED_SCORE 57530 -#define IDS_PPAGE_FS_CLN_AUDIO_DELAY 57531 -#define IDS_PPAGEADVANCED_DEFAULTTOOLBARSIZE 57532 -#define IDS_PPAGEADVANCED_USE_LEGACY_TOOLBAR 57533 -#define IDS_SUBMENU_COPYURL 57535 -#define IDS_CMD_VIEWPRESET 57536 -#define IDS_CMD_MUTE 57537 -#define IDS_CMD_VOLUME 57538 -#define IDS_YOUTUBEDL_NOT_FOUND 57539 -#define IDS_CONTROLS_YOUTUBEDL 57540 -#define IDS_VERTICAL_ALIGN_VIDEO_TOP 57541 -#define IDS_VERTICAL_ALIGN_VIDEO_MIDDLE 57542 -#define IDS_VERTICAL_ALIGN_VIDEO_BOTTOM 57543 -#define IDS_PPAGEADVANCED_USE_YDL 57544 -#define IDS_PPAGEADVANCED_YDL_MAX_HEIGHT 57545 -#define IDS_PPAGEADVANCED_YDL_VIDEO_FORMAT 57546 -#define IDS_PPAGEADVANCED_YDL_AUDIO_ONLY 57547 -#define IDS_PPAGEADVANCED_YDL_COMMAND_LINE 57548 -#define IDS_PPAGEADVANCED_SAVEIMAGE_POSITION 57549 -#define IDS_PPAGEADVANCED_SAVEIMAGE_CURRENTTIME 57550 -#define IDS_PPAGEADVANCED_ALLOW_INACCURATE_FASTSEEK 57551 -#define IDS_PPAGEADVANCED_LOOP_FOLDER_NEXT_FILE 57552 -#define IDS_PPAGEADVANCED_MODERNSEEKBAR 57553 -#define IDS_PPAGEADVANCED_MODERNSEEKBARHEIGHT 57554 -#define IDS_PPAGEADVANCED_FULLSCREEN_DELAY 57555 -#define IDS_PPAGEADVANCED_SNAPSHOTSUBTITLES 57556 -#define IDS_PPAGEADVANCED_SNAPSHOTKEEPVIDEOEXTENSION 57557 -#define IDS_PPAGEADVANCED_CRASHREPORTER 57558 -#define IDS_PRESIZE_SHADERS_ENABLED 57559 -#define IDS_PRESIZE_SHADERS_DISABLED 57560 -#define IDS_PRESIZE_SHADERS_TOGGLE 57561 -#define IDS_AG_PRESIZE_SHADERS_TOGGLE 57562 -#define IDS_POSTSIZE_SHADERS_ENABLED 57563 -#define IDS_POSTSIZE_SHADERS_DISABLED 57564 -#define IDS_POSTSIZE_SHADERS_TOGGLE 57565 -#define IDS_AG_POSTSIZE_SHADERS_TOGGLE 57566 -#define IDS_PPAGEADVANCED_TIME_REFRESH_INTERVAL 57567 -#define IDS_PPAGEADVANCED_SHOW_LANG_STATUSBAR 57568 -#define IDS_PPAGEADVANCED_SHOW_FPS_STATUSBAR 57569 -#define IDS_PPAGEADVANCED_ADD_LANGCODE_WHEN_SAVE_SUBTITLES 57570 -#define IDS_PPAGEADVANCED_USE_TITLE_IN_RECENT_FILE_LIST 57571 -#define IDS_PPAGEADVANCED_SHOW_ABMARKS_STATUSBAR 57572 -#define IDS_PPAGEADVANCED_SHOW_VIDEOINFO_STATUSBAR 57573 -#define IDS_PPAGEADVANCED_OPEN_REC_PANEL_WHEN_OPENING_DEVICE 57621 -#define IDS_PPAGEADVANCED_ALWAYS_USE_SHORT_MENU 57622 -#define IDS_PPAGEADVANCED_FULLSCREEN_SEPARATE_CONTROLS 57623 -#define IDS_PPAGEADVANCED_BLOCKRDP 57624 -#define IDS_PPAGEADVANCED_YDL_EXEPATH 57625 -#define IDS_PPAGEADVANCED_YDL_SUBS_PREFERENCE 57626 -#define IDS_PPAGEADVANCED_USE_AUTOMATIC_CAPTIONS 57627 -#define IDS_PPAGEADVANCED_USE_SMTC 57628 -#define IDS_PPAGEADVANCED_LOCK_NOPAUSE 57629 -#define IDS_PPAGEADVANCED_RELOAD_AFTER_LONG_PAUSE 57630 -#define IDS_PPAGEADVANCED_REDIRECT_OPEN_TO_APPEND_THRESHOLD 57631 -#define IDS_SUBTITLE_RENDERER_NONE 57632 -#define IDS_PPAGEADVANCED_MOUSE_LEFTUP_DELAY 57633 -#define IDS_PPAGEADVANCED_USE_FREETYPE 57634 -#define IDS_PPAGEADVANCED_USE_MEDIAINFO_LOAD_FILE_DURATION 57635 -#define IDS_TIMER_SHOW_PERCENTAGE 57636 -#define IDS_SUBDL_DLG_FAILED_DL 57637 -#define IDS_PPAGEADVANCED_FILEPOS_PLAYLIST 57638 -#define IDS_PPAGEADVANCED_FILEPOS_TRACK_SELECTION 57639 -#define IDS_PPAGEADVANCED_YDL_AUDIO_FORMAT 57640 -#define IDS_PPAGEADVANCED_PREVENT_DISPLAY_SLEEP 57641 -#define IDS_PPAGEADVANCED_STILL_VIDEO_DURATION 57642 -#define IDS_PPAGEADVANCED_CAPTURE_DEINTERLACE 57643 -#define IDS_PLAYLIST_TOGGLE_SHUFFLE 57644 -#define IDS_AUDIOSHIFT_ONOFF 57645 -#define IDS_SAVEDIALOG_INCLUDE_SUBS 57646 -#define IDS_PPAGEADVANCED_PAUSE_WHILE_DRAGGING_SEEKBAR 57647 -#define IDS_CMD_THUMBNAILS 57648 -#define IDS_PPAGEADVANCED_CONFIRM_FILE_DELETE 57649 -#define IDS_PPAGEADVANCED_LIBASS_FOR_SRT 57650 -#define IDS_CMD_AB_START 57651 -#define IDS_CMD_AB_END 57652 -#define IDS_ARS_WASAPI_MODE 57700 -#define IDS_ARS_EXCLUSIVE 57701 -#define IDS_ARS_SHARED 57702 -#define IDS_ARS_BITEXACT_OUTPUT 57703 -#define IDS_ARS_SYSTEM_LAYOUT_CHANNELS 57704 -#define IDS_ARS_SOUND_DEVICE 57705 -#define IDS_ARS_RELEASE_DEVICE_IDLE 57706 -#define IDS_ARS_CROSSFEED 57707 -#define IDS_ARS_DEVICE_PERIOD 57708 -#define IDS_ARS_ALT_CHECK_FORMAT 57709 -#define IDS_ARS_STATUS 57710 -#define IDS_ARS_DEVICE 57711 -#define IDS_ARS_MODE 57712 -#define IDS_ARS_INPUT 57713 -#define IDS_ARS_OUTPUT 57714 -#define IDS_ARS_FORMAT 57715 -#define IDS_ARS_SAMPLERATE 57716 -#define IDS_ARS_CHANNELS 57717 -#define IDS_ARS_WASAPI_METHOD 57718 -#define IDS_ARS_DUMMY_CHANNELS 57719 -#define IDS_ARS_TIP_BITEXACT_OUTPUT 57720 -#define IDS_ARS_TIP_ALT_CHECK_FORMAT 57721 -#define IDS_FILTER_RESET_SETTINGS 57722 -#define IDS_AG_DEFAULT 57723 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 20077 -#define _APS_NEXT_COMMAND_VALUE 33462 -#define _APS_NEXT_CONTROL_VALUE 22094 -#define _APS_NEXT_SYMED_VALUE 24052 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by mpc-hc.rc +// +#define IDR_MAINFRAME 128 +#define IDR_POPUP 130 +#define IDR_POPUPMAIN 133 +#define IDB_PLAYERTOOLBAR 201 +#define IDB_AUDIOTYPE_NOAUDIO 202 +#define IDB_AUDIOTYPE_MONO 203 +#define IDB_AUDIOTYPE_STEREO 204 +#define IDB_CHECKBOX 205 +#define IDF_LOGO0 206 +#define IDF_LOGO1 207 +#define IDF_LOGO2 208 +#define IDF_LOGO3 209 +#define IDF_TICKCROSS 210 +#define IDB_STREAMTYPES 215 +#define IDB_SHADER_UP 216 +#define IDB_SHADER_DOWN 217 +#define IDB_SHADER_DEL 218 +#define IDB_CHECK_ALL 219 +#define IDB_UNCHECK_ALL 220 +#define IDB_CHECK_AUDIO 221 +#define IDB_CHECK_VIDEO 222 +#define IDI_SINGLE 300 +#define IDI_MULTI 301 +#define IDI_DVD 302 +#define IDI_AUDIOCD 303 +#define IDI_UNKNOWN 304 +#define IDR_AVI_FILECOPY 400 +#define IDR_HTML_INFO 500 +#define IDR_HTML_INDEX 501 +#define IDR_HTML_404 502 +#define IDR_HTML_BROWSER 503 +#define IDR_HTML_CONTROLS 504 +#define IDR_HTML_PLAYER 505 +#define IDF_DEFAULT_CSS 506 +#define IDF_VBR_PNG 507 +#define IDF_VBS_PNG 508 +#define IDF_SLIDERGRIP_PNG 509 +#define IDF_1PIX_PNG 510 +#define IDF_SLIDERBACK_PNG 511 +#define IDF_HEADERICON_PNG 512 +#define IDF_HEADERBACK_PNG 513 +#define IDF_HEADERCLOSE_PNG 514 +#define IDF_LEFTSIDE_PNG 515 +#define IDF_RIGHTSIDE_PNG 516 +#define IDF_BOTTOMSIDE_PNG 517 +#define IDF_LEFTBOTTOMSIDE_PNG 518 +#define IDF_RIGHTBOTTOMSIDE_PNG 519 +#define IDF_SEEKBARLEFT_PNG 520 +#define IDF_SEEKBARMID_PNG 521 +#define IDF_SEEKBARRIGHT_PNG 522 +#define IDF_SEEKBARGRIP_PNG 523 +#define IDF_CONTROLBACK_PNG 524 +#define IDF_CONTROLBUTTONPLAY_PNG 525 +#define IDF_CONTROLBUTTONPAUSE_PNG 526 +#define IDF_CONTROLBUTTONSTOP_PNG 527 +#define IDF_CONTROLBUTTONSKIPBACK_PNG 528 +#define IDF_CONTROLBUTTONDECRATE_PNG 529 +#define IDF_CONTROLBUTTONINCRATE_PNG 530 +#define IDF_CONTROLBUTTONSKIPFORWARD_PNG 531 +#define IDF_CONTROLBUTTONSTEP_PNG 532 +#define IDF_CONTROLVOLUMEON_PNG 533 +#define IDF_CONTROLVOLUMEOFF_PNG 534 +#define IDF_CONTROLVOLUMEBAR_PNG 535 +#define IDF_CONTROLVOLUMEGRIP_PNG 536 +#define IDR_HTML_VARIABLES 537 +#define IDF_JAVASCRIPT 538 +#define IDF_FAVICON 539 +#define IDF_SHADER_RESIZER 700 +#define IDF_SHADER_EMPTY 701 +#define IDF_SHADER_FINAL 702 +#define IDF_SVG_TOOLBAR 703 +#define IDF_SVG_BUTTONS 704 +#define IDF_SVG_ARROW 705 +#define ID_FILE_OPENMEDIA 800 +#define ID_FILE_OPENDVDBD 801 +#define ID_FILE_OPENDEVICE 802 +#define ID_FILE_CLOSEMEDIA 803 +#define ID_FILE_CLOSE_AND_RESTORE 804 +#define ID_FILE_SAVE_COPY 805 +#define ID_FILE_SAVE_IMAGE 806 +#define ID_FILE_SAVE_IMAGE_AUTO 807 +#define ID_FILE_SAVE_THUMBNAILS 808 +#define ID_FILE_SUBTITLES_LOAD 809 +#define ID_FILE_SUBTITLES_SAVE 810 +#define ID_FILE_SUBTITLES_DOWNLOAD 812 +#define ID_VIEW_ZOOM_25 813 +#define ID_FILE_PROPERTIES 814 +#define ID_VIEW_OPTIONS 815 +#define ID_FILE_EXIT 816 +#define ID_VIEW_CAPTIONMENU 817 +#define ID_VIEW_SEEKER 818 +#define ID_VIEW_CONTROLS 819 +#define ID_VIEW_INFORMATION 820 +#define ID_VIEW_STATISTICS 821 +#define ID_VIEW_STATUS 822 +#define ID_VIEW_SUBRESYNC 823 +#define ID_VIEW_PLAYLIST 824 +#define ID_VIEW_CAPTURE 825 +#define ID_VIEW_DEBUGSHADERS 826 +#define ID_VIEW_PRESETS_MINIMAL 827 +#define ID_VIEW_PRESETS_COMPACT 828 +#define ID_VIEW_PRESETS_NORMAL 829 +#define ID_VIEW_FULLSCREEN 830 +#define ID_VIEW_FULLSCREEN_SECONDARY 831 +#define ID_VIEW_ZOOM_50 832 +#define ID_VIEW_ZOOM_100 833 +#define ID_VIEW_ZOOM_200 834 +#define ID_VIEW_VF_HALF 835 +#define ID_VIEW_VF_NORMAL 836 +#define ID_VIEW_VF_DOUBLE 837 +#define ID_VIEW_VF_STRETCH 838 +#define ID_VIEW_VF_FROMINSIDE 839 +#define ID_VIEW_VF_FROMOUTSIDE 840 +#define ID_VIEW_VF_ZOOM1 841 +#define ID_VIEW_VF_ZOOM2 842 +#define ID_VIEW_VF_SWITCHZOOM 843 +#define ID_VIEW_VF_COMPMONDESKARDIFF 845 +#define ID_VIEW_EDITLISTEDITOR 846 +#define ID_EDL_IN 847 +#define ID_EDL_OUT 848 +#define ID_EDL_NEWCLIP 849 +#define ID_ASPECTRATIO_START 850 +#define ID_ASPECTRATIO_DAR 850 +#define ID_ASPECTRATIO_4_3 851 +#define ID_ASPECTRATIO_5_4 852 +#define ID_ASPECTRATIO_16_9 853 +#define ID_ASPECTRATIO_235_100 854 +#define ID_ASPECTRATIO_185_100 855 +#define ID_ASPECTRATIO_SAR 856 +#define ID_ASPECTRATIO_END 856 +#define ID_ASPECTRATIO_NEXT 859 +#define ID_EDL_SAVE 860 +#define ID_VIEW_RESET 861 +#define ID_VIEW_INCSIZE 862 +#define ID_VIEW_DECSIZE 863 +#define ID_VIEW_INCWIDTH 864 +#define ID_VIEW_DECWIDTH 865 +#define ID_VIEW_INCHEIGHT 866 +#define ID_VIEW_DECHEIGHT 867 +#define ID_PANSCAN_MOVELEFT 868 +#define ID_PANSCAN_MOVERIGHT 869 +#define ID_PANSCAN_MOVEUP 870 +#define ID_PANSCAN_MOVEDOWN 871 +#define ID_PANSCAN_MOVEUPLEFT 872 +#define ID_PANSCAN_MOVEUPRIGHT 873 +#define ID_PANSCAN_MOVEDOWNLEFT 874 +#define ID_PANSCAN_MOVEDOWNRIGHT 875 +#define ID_PANSCAN_CENTER 876 +#define ID_PANSCAN_ROTATEXP 877 +#define ID_PANSCAN_ROTATEXM 878 +#define ID_PANSCAN_ROTATEYP 879 +#define ID_PANSCAN_ROTATEYM 880 +#define ID_PANSCAN_ROTATEZP 881 +#define ID_PANSCAN_ROTATEZM 882 +#define ID_ONTOP_DEFAULT 883 +#define ID_ONTOP_ALWAYS 884 +#define ID_ONTOP_WHILEPLAYING 885 +#define ID_ONTOP_WHILEPLAYINGVIDEO 886 +#define ID_PLAY_PLAY 887 +#define ID_PLAY_PAUSE 888 +#define ID_PLAY_PLAYPAUSE 889 +#define IDS_SHADERNOTES 889 +#define ID_PLAY_STOP 890 +#define ID_PLAY_FRAMESTEP 891 +#define ID_PLAY_FRAMESTEP_BACK 892 +#define ID_NAVIGATE_GOTO 893 +#define ID_PLAY_DECRATE 894 +#define ID_PLAY_INCRATE 895 +#define ID_PLAY_RESETRATE 896 +#define ID_PLAY_SEEKKEYBACKWARD 897 +#define ID_PLAY_SEEKKEYFORWARD 898 +#define ID_PLAY_SEEKBACKWARDSMALL 899 +#define ID_PLAY_SEEKFORWARDSMALL 900 +#define ID_PLAY_SEEKBACKWARDMED 901 +#define ID_PLAY_SEEKFORWARDMED 902 +#define ID_PLAY_SEEKBACKWARDLARGE 903 +#define ID_PLAY_SEEKFORWARDLARGE 904 +#define ID_PLAY_INCAUDDELAY 905 +#define ID_PLAY_DECAUDDELAY 906 +#define ID_VOLUME_UP 907 +#define ID_VOLUME_DOWN 908 +#define ID_VOLUME_MUTE 909 +#define ID_VOLUME_MUTE_OFF 910 +#define ID_VOLUME_MUTE_DISABLED 911 +#define ID_AFTERPLAYBACK_EXIT 912 +#define ID_AFTERPLAYBACK_STANDBY 913 +#define ID_AFTERPLAYBACK_HIBERNATE 914 +#define ID_AFTERPLAYBACK_SHUTDOWN 915 +#define ID_AFTERPLAYBACK_LOGOFF 916 +#define ID_AFTERPLAYBACK_LOCK 917 +#define ID_AFTERPLAYBACK_MONITOROFF 918 +#define ID_NAVIGATE_SKIPBACKFILE 919 +#define ID_NAVIGATE_SKIPFORWARDFILE 920 +#define ID_NAVIGATE_SKIPBACK 921 +#define ID_NAVIGATE_SKIPFORWARD 922 +#define ID_NAVIGATE_TITLEMENU 923 +#define ID_NAVIGATE_ROOTMENU 924 +#define ID_NAVIGATE_SUBPICTUREMENU 925 +#define ID_NAVIGATE_AUDIOMENU 926 +#define ID_NAVIGATE_ANGLEMENU 927 +#define ID_NAVIGATE_CHAPTERMENU 928 +#define ID_NAVIGATE_MENU_LEFT 929 +#define ID_NAVIGATE_MENU_RIGHT 930 +#define ID_NAVIGATE_MENU_UP 931 +#define ID_NAVIGATE_MENU_DOWN 932 +#define ID_NAVIGATE_MENU_ACTIVATE 933 +#define ID_NAVIGATE_MENU_BACK 934 +#define ID_NAVIGATE_MENU_LEAVE 935 +#define ID_FAVORITES 936 +#define ID_FAVORITES_ORGANIZE 937 +#define ID_FAVORITES_ADD 938 +#define ID_HELP_HOMEPAGE 939 +#define ID_HELP_DONATE 940 +#define ID_HELP_SHOWCOMMANDLINESWITCHES 941 +#define ID_HELP_TOOLBARIMAGES 942 +#define ID_HELP_ABOUT 943 +#define ID_BOSS 944 +#define ID_DUMMYSEPARATOR 945 +#define ID_BUTTONSEP 946 +#define ID_AFTERPLAYBACK_PLAYNEXT 947 +#define ID_AFTERPLAYBACK_DONOTHING 948 +#define ID_MENU_PLAYER_SHORT 949 +#define ID_MENU_PLAYER_LONG 950 +#define ID_MENU_FILTERS 951 +#define ID_STREAM_AUDIO_NEXT 952 +#define ID_STREAM_AUDIO_PREV 953 +#define ID_STREAM_SUB_NEXT 954 +#define ID_STREAM_SUB_PREV 955 +#define ID_STREAM_SUB_ONOFF 956 +#define ID_AUDIOSHIFT_ONOFF 960 +#define ID_DVD_ANGLE_NEXT 961 +#define ID_DVD_ANGLE_PREV 962 +#define ID_DVD_AUDIO_NEXT 963 +#define ID_DVD_AUDIO_PREV 964 +#define ID_DVD_SUB_NEXT 965 +#define ID_DVD_SUB_PREV 966 +#define ID_DVD_SUB_ONOFF 967 +#define ID_VIEW_ZOOM_AUTOFIT 968 +#define ID_FILE_OPENQUICK 969 +#define ID_VOLUME_BOOST_INC 970 +#define ID_VOLUME_BOOST_DEC 971 +#define ID_VOLUME_BOOST_MIN 972 +#define ID_VOLUME_BOOST_MAX 973 +#define ID_NAVIGATE_TUNERSCAN 974 +#define ID_FAVORITES_QUICKADDFAVORITE 975 +#define ID_FILE_REOPEN 976 +#define ID_FILTERS 977 +#define ID_AUDIOS 978 +#define ID_SUBTITLES 979 +#define ID_VIDEO_STREAMS 980 +#define ID_COLOR_BRIGHTNESS_INC 984 +#define ID_COLOR_BRIGHTNESS_DEC 985 +#define ID_COLOR_CONTRAST_INC 986 +#define ID_COLOR_CONTRAST_DEC 987 +#define ID_COLOR_HUE_INC 988 +#define ID_COLOR_HUE_DEC 989 +#define ID_COLOR_SATURATION_INC 990 +#define ID_COLOR_SATURATION_DEC 991 +#define ID_COLOR_RESET 992 +#define ID_CUSTOM_CHANNEL_MAPPING 993 +#define ID_NORMALIZE 994 +#define ID_REGAIN_VOLUME 995 +#define ID_PLAY_SEEKSET 996 +#define ID_PANSCAN_ROTATEZ270 997 +#define ID_PRESIZE_SHADERS_TOGGLE 998 +#define ID_POSTSIZE_SHADERS_TOGGLE 999 +#define ID_FILTERS_COPY_TO_CLIPBOARD 1999 +#define ID_FILTERS_SUBITEM_START 2000 +#define ID_FILTERS_SUBITEM_END 2099 +#define ID_FILTERSTREAMS_SUBITEM_START 2100 +#define ID_FILTERSTREAMS_SUBITEM_END 2199 +#define ID_AUDIO_SUBITEM_START 2200 +#define ID_AUDIO_SUBITEM_END 2299 +#define ID_SUBTITLES_SUBITEM_START 2300 +#define ID_SUBTITLES_SUBITEM_END 2399 +#define ID_VIDEO_STREAMS_SUBITEM_START 2400 +#define ID_VIDEO_STREAMS_SUBITEM_END 2499 +#define ID_FAVORITES_FILE_START 2800 +#define ID_FAVORITES_FILE_END 3799 +#define ID_FAVORITES_DVD_START 3800 +#define ID_FAVORITES_DVD_END 3899 +#define ID_FAVORITES_DEVICE_START 3900 +#define ID_FAVORITES_DEVICE_END 3999 +#define ID_FILE_OPEN_OPTICAL_DISK_START 4000 +#define ID_FILE_OPEN_OPTICAL_DISK_END 4099 +#define ID_PANNSCAN_PRESETS_START 4100 +#define ID_PANNSCAN_PRESETS_END 4199 +#define ID_SHADERS_SELECT 4200 +#define ID_SHADERS_PRESETS_START 4201 +#define ID_SHADERS_PRESETS_END 4299 +#define ID_NAVIGATE_JUMPTO_SUBITEM_START 4300 +#define ID_NAVIGATE_JUMPTO_SUBITEM_END 4899 +#define ID_VIEW_ZOOM_AUTOFIT_LARGER 4900 +#define ID_PLAY_PLAYBACKRATE_START 5000 +#define ID_PLAY_PLAYBACKRATE_025 5001 +#define ID_PLAY_PLAYBACKRATE_050 5002 +#define ID_PLAY_PLAYBACKRATE_075 5003 +#define ID_PLAY_PLAYBACKRATE_090 5004 +#define ID_PLAY_PLAYBACKRATE_100 5005 +#define ID_PLAY_PLAYBACKRATE_110 5006 +#define ID_PLAY_PLAYBACKRATE_125 5007 +#define ID_PLAY_PLAYBACKRATE_150 5008 +#define ID_PLAY_PLAYBACKRATE_200 5009 +#define ID_PLAY_PLAYBACKRATE_300 5010 +#define ID_PLAY_PLAYBACKRATE_400 5011 +#define ID_PLAY_PLAYBACKRATE_600 5012 +#define ID_PLAY_PLAYBACKRATE_800 5013 +#define ID_PLAY_PLAYBACKRATE_FPS24 5020 +#define ID_PLAY_PLAYBACKRATE_FPS25 5021 +#define ID_PLAY_PLAYBACKRATE_END 5029 +#define ID_PLAYLIST_TOGGLE_SHUFFLE 5030 +#define ID_CMDLINE_SAVE_THUMBNAILS 5031 +#define ID_MOUSE_ADD_CMD 5032 +#define IDS_FILTER_SETTINGS_CAPTION 7000 +#define IDD_OPEN_DLG 10000 +#define IDD_MEDIATYPES_DLG 10002 +#define IDD_SAVE_DLG 10004 +#define IDD_SUBTITLEDL_DLG 10005 +#define IDD_FILEPROPDETAILS 10010 +#define IDD_FILEPROPCLIP 10011 +#define IDD_PNSPRESET_DLG 10015 +#define IDD_GOTO_DLG 10016 +#define IDD_FAVADD 10017 +#define IDD_FAVORGANIZE 10018 +#define IDD_ABOUTBOX 10019 +#define IDD_PLAYERINFOBAR 10020 +#define IDD_PLAYERSTATUSBAR 10021 +#define IDD_PLAYERSEEKBAR 10022 +#define IDD_PPAGEPLAYBACK 10023 +#define IDD_PPAGEPLAYER 10024 +#define IDD_PPAGEDVD 10025 +#define IDD_PPAGESUBTITLES 10026 +#define IDD_PPAGEFORMATS 10027 +#define IDD_PPAGETWEAKS 10028 +#define IDD_PPAGEAUDIOSWITCHER 10029 +#define IDD_PPAGEEXTERNALFILTERS 10030 +#define IDD_PPAGESHADERS 10031 +#define IDD_PPAGEACCELTBL 10032 +#define IDD_PPAGESUBSTYLE 10033 +#define IDD_PPAGEINTERNALFILTERS 10036 +#define IDD_PPAGELOGO 10037 +#define IDD_PPAGETHEME 10038 +#define IDD_PPAGEOUTPUT 10039 +#define IDD_PPAGEWEBSERVER 10040 +#define IDD_CAPTURE_DLG 10045 +#define IDD_ADDREGFILTER 10046 +#define IDD_SELECTMEDIATYPE 10047 +#define IDD_COMPROPERTYPAGE 10048 +#define IDD_FILEPROPRES 10049 +#define IDD_PPAGEMISC 10052 +#define IDD_FILEMEDIAINFO 10053 +#define IDD_PPAGECAPTURE 10054 +#define IDD_PPAGESYNC 10055 +#define IDD_PPAGEFULLSCREEN 10056 +#define IDD_RFS_FILELIST_EXT 10057 +#define IDD_PPAGEAUDIORENDERER 10058 +#define IDD_PPAGEMOUSE 10059 +#define IDC_COMBO1 11000 +#define IDC_COMBO2 11001 +#define IDC_COMBO3 11002 +#define IDC_COMBO4 11003 +#define IDC_COMBO5 11004 +#define IDC_COMBO6 11005 +#define IDC_COMBO7 11006 +#define IDC_COMBO8 11007 +#define IDC_COMBO9 11008 +#define IDC_COMBO10 11009 +#define IDC_COMBO11 11010 +#define IDC_COMBO12 11011 +#define IDC_COMBO14 11013 +#define IDC_SLIDER1 11020 +#define IDC_SLIDER2 11021 +#define IDC_SLIDER3 11022 +#define IDC_SLIDER4 11023 +#define IDC_SLI_BRIGHTNESS 11025 +#define IDC_SLI_HUE 11026 +#define IDC_SLI_SATURATION 11027 +#define IDC_RADIO1 11040 +#define IDC_RADIO2 11041 +#define IDC_RADIO3 11042 +#define IDC_RADIO4 11043 +#define IDC_RADIO5 11044 +#define IDC_RADIO6 11045 +#define IDC_RADIO7 11046 +#define IDC_RADIO8 11047 +#define IDC_RADIO9 11048 +#define IDC_RADIO10 11049 +#define IDC_RADIO11 11050 +#define IDC_EDIT1 11060 +#define IDC_EDIT3 11061 +#define IDC_EDIT2 11062 +#define IDC_EDIT4 11063 +#define IDC_EDIT5 11064 +#define IDC_EDIT6 11065 +#define IDC_EDIT7 11066 +#define IDC_EDIT8 11067 +#define IDC_EDIT9 11068 +#define IDC_EDIT10 11069 +#define IDC_WINHOTKEY1 11070 +#define IDC_CHECK1 11080 +#define IDC_CHECK2 11081 +#define IDC_CHECK3 11082 +#define IDC_CHECK4 11083 +#define IDC_CHECK5 11084 +#define IDC_CHECK6 11085 +#define IDC_CHECK7 11086 +#define IDC_CHECK8 11087 +#define IDC_CHECK9 11088 +#define IDC_CHECK10 11089 +#define IDC_CHECK11 11090 +#define IDC_CHECK12 11091 +#define IDC_CHECK13 11092 +#define IDC_CHECK14 11093 +#define IDC_SPIN1 11100 +#define IDC_SPIN2 11101 +#define IDC_SPIN3 11102 +#define IDC_SPIN4 11103 +#define IDC_SPIN5 11104 +#define IDC_SPIN6 11105 +#define IDC_SPIN7 11106 +#define IDC_SPIN8 11107 +#define IDC_SPIN9 11108 +#define IDC_SPIN10 11109 +#define IDC_BUTTON1 11120 +#define IDC_BUTTON2 11121 +#define IDC_BUTTON3 11122 +#define IDC_BUTTON4 11123 +#define IDC_BUTTON5 11124 +#define IDC_BUTTON6 11125 +#define IDC_BUTTON7 11126 +#define IDC_BUTTON8 11127 +#define IDC_BUTTON9 11128 +#define IDC_BUTTON10 11129 +#define IDC_BUTTON11 11130 +#define IDC_BUTTON12 11131 +#define IDC_BUTTON13 11132 +#define IDC_RESET_SETTINGS 11133 +#define IDC_EXPORT_SETTINGS 11134 +#define IDC_TREE1 11140 +#define IDC_LIST1 11160 +#define IDC_LIST2 11161 +#define IDC_LIST3 11162 +#define IDC_TAB1 11200 +#define IDC_ANIMATE1 11220 +#define IDC_PROGRESS1 11240 +#define IDC_STATIC1 11260 +#define IDC_STATIC2 11261 +#define IDC_STATIC3 11262 +#define IDC_STATIC4 11263 +#define IDC_STATIC5 11264 +#define IDC_STATIC6 11265 +#define IDC_STATIC7 11266 +#define IDC_STATIC8 11267 +#define IDC_STATIC9 11268 +#define IDC_STATIC10 11269 +#define IDC_STATIC11 11270 +#define IDC_DVDPATH 12000 +#define IDC_SUBRESYNCLIST 12001 +#define IDC_PLAYLIST 12002 +#define IDC_COLORPRI 12003 +#define IDC_COLORSEC 12004 +#define IDC_COLOROUTL 12005 +#define IDC_COLORSHAD 12006 +#define IDC_STATICLINK 12007 +#define IDC_STATICLINK2 12008 +#define IDC_DEFAULTICON 12009 +#define IDC_PLACEHOLDER 12010 +#define IDC_REPORT 12011 +#define IDC_FROMTO 12012 +#define IDC_STATIC_BALANCE 12013 +#define IDC_LOGOPREVIEW 12014 +#define IDC_LOGOFILENAME 12016 +#define IDC_AUTHOR 12018 +#define IDC_CHECK_RELATIVETO 12019 +#define IDC_CHECK_NO_SUB_ANIM 12021 +#define IDC_SUBPIC_TO_BUFFER 12022 +#define IDC_BUTTON_EXT_SET 12023 +#define IDC_OK1 12024 +#define IDC_OK2 12025 +#define IDC_PLAYERSTATUS 12026 +#define IDC_PLAYERTIME 12027 +#define IDC_EDITLIST 12028 +#define IDC_CHECK_SUB_AR_COMPENSATION 12029 +#define IDC_CHECK_ALLOW_DROPPING_SUBPIC 12030 +#define IDC_DSSYSDEF 12100 +#define IDC_DSOVERLAYMIXER 12102 +#define IDC_DSVMR9WIN 12104 +#define IDC_DSVMR9REN 12106 +#define IDC_DSDXR 12107 +#define IDC_DSNULL_COMP 12108 +#define IDC_DSNULL_UNCOMP 12109 +#define IDC_DSEVR_CUSTOM 12111 +#define IDC_DSMADVR 12112 +#define IDC_DSSYNC 12113 +#define IDC_REGULARSURF 12127 +#define IDC_TEXTURESURF2D 12128 +#define IDC_TEXTURESURF3D 12129 +#define IDC_DX9RESIZER_COMBO 12130 +#define IDC_DSVMR9LOADMIXER 12131 +#define IDC_DX_SURFACE 12133 +#define IDC_BUTTON_MI 12136 +#define IDC_MIEDIT 12137 +#define IDC_LISTCHANNELS 12138 +#define IDC_STATUSBAR 12139 +#define IDC_PPAGECAPTURE_DESC1 12140 +#define IDC_DSMPCVR 12141 +#define IDS_SRC_VTS 14002 +#define IDS_SRC_RFS 14003 +#define IDS_INTERNAL_LAVF 14004 +#define IDS_INTERNAL_LAVF_WMV 14005 +#define IDS_AG_OPEN_FILE_LOCATION 14006 +#define IDS_AG_OPENDIRECTORY 14007 +#define IDS_PLAYLIST_OPEN 14114 +#define IDS_PLAYLIST_ADD 14115 +#define IDS_PLAYLIST_REMOVE 14116 +#define IDS_PLAYLIST_CLEAR 14117 +#define IDS_PLAYLIST_COPYTOCLIPBOARD 14118 +#define IDS_PLAYLIST_SAVE 14119 +#define IDS_PLAYLIST_SAVEAS 14120 +#define IDS_PLAYLIST_SORTBYLABEL 14121 +#define IDS_PLAYLIST_SORTBYPATH 14122 +#define IDS_PLAYLIST_RANDOMIZE 14123 +#define IDS_PLAYLIST_RESTORE 14124 +#define IDS_SUBRESYNC_SEPARATOR 14125 +#define IDS_SUBRESYNC_DELETE 14126 +#define IDS_SUBRESYNC_DUPLICATE 14127 +#define IDS_SUBRESYNC_RESET 14128 +#define IDS_SUBRESYNC_ORIGINAL 14129 +#define IDS_SUBRESYNC_CURRENT 14130 +#define IDS_SUBRESYNC_EDIT 14131 +#define IDS_SUBRESYNC_YES 14132 +#define IDS_SUBRESYNC_NO 14133 +#define IDS_SUBRESYNC_DECREASE 14134 +#define IDS_SUBRESYNC_INCREASE 14135 +#define IDS_OPTIONS_CAPTION 14136 +#define IDS_SHADERS_SELECT 14137 +#define IDS_SHADERS_DEBUG 14138 +#define IDS_FAVORITES_ADD 14153 +#define IDS_FAVORITES_ORGANIZE 14154 +#define IDS_PLAYLIST_SHUFFLE 14155 +#define IDS_PLAYLIST_SHOWFOLDER 14156 +#define IDS_CONTROLS_CLOSING 14157 +#define IDS_CONTROLS_PLAYING 14158 +#define IDS_CONTROLS_PAUSED 14159 +#define IDS_CONTROLS_STOPPED 14160 +#define IDS_CONTROLS_BUFFERING 14161 +#define IDS_CONTROLS_CAPTURING 14162 +#define IDS_CONTROLS_OPENING 14163 +#define IDS_CONTROLS_CLOSED 14164 +#define IDS_SUBTITLES_OPTIONS 14165 +#define IDS_SUBTITLES_STYLES 14166 +#define IDS_SUBTITLES_RELOAD 14167 +#define IDS_SUBTITLES_HIDE 14168 +#define IDS_PANSCAN_EDIT 14169 +#define IDS_INFOBAR_TITLE 14170 +#define IDS_INFOBAR_AUTHOR 14171 +#define IDS_INFOBAR_COPYRIGHT 14172 +#define IDS_INFOBAR_RATING 14173 +#define IDS_INFOBAR_DESCRIPTION 14174 +#define IDS_INFOBAR_DOMAIN 14175 +#define IDS_INFOBAR_LOCATION 14176 +#define IDS_INFOBAR_VIDEO 14177 +#define IDS_INFOBAR_AUDIO 14178 +#define IDS_INFOBAR_SUBTITLES 14179 +#define IDS_INFOBAR_CHAPTER 14180 +#define IDS_CONTROLS_COMPLETING 14181 +#define IDS_AUTOPLAY_PLAYVIDEO 14182 +#define IDS_AUTOPLAY_PLAYMUSIC 14183 +#define IDS_AUTOPLAY_PLAYAUDIOCD 14184 +#define IDS_AUTOPLAY_PLAYDVDMOVIE 14185 +#define IDS_PROPSHEET_PROPERTIES 14186 +#define IDS_PLAY_LOOPMODE_FILE 14187 +#define IDS_SUB_OVERRIDE_DEFAULT_STYLE 14188 +#define IDS_PLAY_LOOPMODE_PLAYLIST 14189 +#define IDS_FAVFILES 14190 +#define IDS_FAVDVDS 14191 +#define IDS_INFOBAR_CHANNEL 14192 +#define IDS_INFOBAR_TIME 14193 +#define IDS_STATSBAR_SYNC_OFFSET 14194 +#define IDS_STATSBAR_SYNC_OFFSET_FORMAT 14195 +#define IDS_STATSBAR_JITTER 14196 +#define IDS_STATSBAR_BITRATE 14197 +#define IDS_STATSBAR_BITRATE_AVG_CUR 14198 +#define IDS_STATSBAR_SIGNAL 14199 +#define IDS_STATSBAR_SIGNAL_FORMAT 14200 +#define IDS_SUBTITLES_STYLES_CAPTION 14201 +#define IDS_TEXT_SUB_RENDERING_TARGET 14202 +#define IDS_PLAYLOOPMODE_PLAYLIST 14203 +#define IDS_PLAYLOOPMODE_FILE 14204 +#define IDS_PLAYLOOP_FOREVER_ON 14205 +#define IDS_PLAYLOOP_FOREVER_OFF 14206 +#define IDS_PLAYLOOP_FOREVER 14207 +#define IDS_PLAYLOOPMODE_AB 14208 +#define IDS_PLAY_LOOPMODE_AB 14209 +#define IDS_PLAYLOOPMODE_AB_MARK_A 14210 +#define IDS_PLAYLOOPMODE_AB_MARK_B 14211 +#define IDS_SNAPSHOT_SUBTITLES 14212 +#define IDS_THEMEMODE_DARK 14213 +#define IDS_THEMEMODE_LIGHT 14214 +#define IDS_THEMEMODE_WINDOWS 14215 +#define IDS_SUB_OVERRIDE_ALL_STYLES 14216 +#define IDD_TUNER_SCAN 20002 +#define IDS_OSD_DISPLAY_RENDERER_STATS 20003 +#define IDD_PPAGELOGO2 20003 +#define IDS_OSD_RESET_RENDERER_STATS 20004 +#define IDD_NAVIGATION_DLG 20005 +#define IDD_PPAGESUBMISC 20006 +#define IDS_VIEW_BORDERLESS 20007 +#define IDS_VIEW_FRAMEONLY 20008 +#define IDS_VIEW_CAPTIONMENU 20009 +#define IDS_VIEW_HIDEMENU 20010 +#define IDD_UPDATE_DIALOG 20011 +#define IDF_WIN7_TOOLBAR 20012 +#define IDD_DEBUGSHADERS_DLG 20013 +#define IDD_PPAGEADVANCED 20014 +#define IDD_CMD_LINE_HELP 20016 +#define IDD_CRASH_REPORTER 20017 +#define IDD_PPAGEDPICALC 20018 +#define IDD_RAR_ENTRY_SELECTOR 20019 +#define IDD_ADDCOMMAND_DLG 20020 +#define IDD_PPAGETOOLBAR 20021 +#define IDB_DT_CB_96 20050 +#define IDB_DT_CB_120 20051 +#define IDB_DT_CB_144 20052 +#define IDB_DT_CB_192 20053 +#define IDB_DT_RADIO_96 20054 +#define IDB_DT_RADIO_120 20055 +#define IDB_DT_RADIO_144 20056 +#define IDB_DT_RADIO_129 20057 +#define IDB_DT_RADIO_192 20057 +#define IDS_MESSAGEBOX_CANCEL 20059 +#define IDS_MESSAGEBOX_ABORT 20060 +#define IDS_MESSAGEBOX_RETRY 20061 +#define IDS_MESSAGEBOX_IGNORE 20062 +#define IDS_MESSAGEBOX_OK 20063 +#define IDS_MESSAGEBOX_CONTINUE 20064 +#define IDS_AG_TOGGLE_DEFAULT_SUBTITLE_STYLE 20065 +#define ID_FILE_OPEN_LOCATION 20066 +#define IDB_NOIMAGE 20067 +#define IDB_GRIPPER_168 20070 +#define IDB_GRIPPER_144 20071 +#define IDB_GRIPPER_192 20073 +#define IDB_GRIPPER_96 20074 +#define IDB_PNG1 20075 +#define IDB_GRIPPER_120 20075 +#define IDI_OPENSUBTITLES 21001 +#define IDI_PODNAPISI 21002 +#define IDI_N24 21006 +#define IDC_FULLSCREEN_MONITOR_CHECK 22002 +#define IDC_SLI_CONTRAST 22003 +#define IDC_RESET 22004 +#define IDC_DVD_POS 22005 +#define IDC_FILE_POS 22006 +#define IDC_EVR_BUFFERS 22010 +#define IDC_VERSION 22011 +#define IDC_SHOW_OSD 22013 +#define IDC_EVR_BUFFERS_TXT 22014 +#define IDC_LAVFILTERS_VERSION 22016 +#define IDC_DSVMR9ALTERNATIVEVSYNC 22017 +#define IDC_HOMEPAGE_LINK 22018 +#define IDC_QUALITY 22019 +#define IDC_PROGRESS 22020 +#define IDC_FREQ_START 22021 +#define IDC_BANDWIDTH 22022 +#define IDC_FREQ_END 22023 +#define IDC_CHANNEL_LIST 22024 +#define ID_START 22025 +#define IDC_SYMBOLRATE 22026 +#define ID_SAVE 22030 +#define IDC_STRENGTH 22031 +#define IDC_SYNCVIDEO 22032 +#define IDC_SYNCDISPLAY 22033 +#define IDC_CYCLEDELTA 22034 +#define IDC_LINEDELTA 22035 +#define IDC_COLUMNDELTA 22036 +#define IDC_TARGETSYNCOFFSET 22037 +#define IDC_CONTROLLIMIT 22038 +#define IDC_SYNCNEAREST 22040 +#define IDC_D3D9DEVICE 22041 +#define IDC_NAVIGATION_SCAN 22043 +#define IDC_D3D9DEVICE_COMBO 22045 +#define IDC_NAVIGATION_INFO 22046 +#define IDC_NAVIGATION_FILTERSTATIONS 22047 +#define IDC_CHECK_OFFSET 22048 +#define IDC_OFFSET 22049 +#define IDC_CHECK_IGNORE_ENCRYPTED 22050 +#define IDC_UPDATE_DLG_TEXT 22051 +#define IDC_UPDATE_ICON 22052 +#define IDC_UPDATE_DL_BUTTON 22053 +#define IDC_UPDATE_LATER_BUTTON 22054 +#define IDC_UPDATE_IGNORE_BUTTON 22055 +#define IDC_AUTHORS_LINK 22056 +#define IDC_CHECK_LCD 22059 +#define IDC_VIDRND_COMBO 22060 +#define IDC_AUDRND_COMBO 22063 +#define IDC_VIDRND_DXVA_SUPPORT 22064 +#define IDC_VIDRND_SHADER_SUPPORT 22065 +#define IDC_VIDRND_SUBTITLE_SUPPORT 22066 +#define IDC_VIDRND_SAVEIMAGE_SUPPORT 22067 +#define IDC_VIDRND_ROTATION_SUPPORT 22068 +#define IDC_VOLUMESTEP 22073 +#define IDC_VOLUMESTEP_SPIN 22074 +#define IDC_SPEEDSTEP 22075 +#define IDC_SPEEDSTEP_SPIN 22076 +#define IDC_EXPORT_KEYS 22077 +#define IDC_PPAGECAPTURE_ST10 22078 +#define IDC_PPAGECAPTURE_ST11 22079 +#define IDC_PPAGECAPTURE_ST12 22080 +#define IDC_FASTSEEK_CHECK 22081 +#define IDC_ASSOCIATE_ALL_FORMATS 22082 +#define IDC_ASSOCIATE_VIDEO_FORMATS 22083 +#define IDC_ASSOCIATE_AUDIO_FORMATS 22084 +#define IDC_CLEAR_ALL_ASSOCIATIONS 22085 +#define IDC_SEEK_PREVIEW 22086 +#define IDC_CHECK_AUTOSAVE_ONLINE_SUBTITLE 22087 +#define IDC_STATIC21 22088 +#define IDC_STATIC22 22089 +#define IDC_STATIC23 22090 +#define IDC_STATIC_LIBASS 22091 +#define IDC_MODERNSEEKBARHEIGHT 22092 +#define IDC_MODERNSEEKBARHEIGHT_SPIN 22093 +#define ID_SUB_DELAY_DOWN 24000 +#define ID_SUB_DELAY_UP 24001 +#define IDS_MPLAYERC_104 24002 +#define IDS_MPLAYERC_105 24003 +#define IDS_FILE_SAVE_THUMBNAILS 24005 +#define ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION 24028 +#define ID_VIEW_FULLFLOATINGPOINTPROCESSING 24029 +#define ID_VIEW_CM_ENABLE 24030 +#define ID_VIEW_CM_INPUT_AUTO 24031 +#define ID_VIEW_CM_INPUT_HDTV 24032 +#define ID_VIEW_CM_INPUT_SDTV_NTSC 24033 +#define ID_VIEW_CM_INPUT_SDTV_PAL 24034 +#define ID_VIEW_CM_AMBIENTLIGHT_BRIGHT 24035 +#define ID_VIEW_CM_AMBIENTLIGHT_DIM 24037 +#define ID_VIEW_CM_AMBIENTLIGHT_DARK 24038 +#define ID_VIEW_CM_INTENT_PERCEPTUAL 24039 +#define ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC 24040 +#define ID_VIEW_CM_INTENT_SATURATION 24041 +#define ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC 24042 +#define ID_VIEW_HALFFLOATINGPOINTPROCESSING 24043 +#define ID_FILE_RECYCLE 24044 +#define ID_VIEW_MPCTHEME 24045 +#define PLAYER_PLAYLIST_UPDATE_SCROLLBAR 24048 +#define IDF_LOGO4 24050 +#define ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE 24051 +#define ID_SUB_POS_DOWN 24052 +#define ID_SUB_POS_UP 24053 +#define ID_SUB_FONT_SIZE_DEC 24054 +#define ID_SUB_FONT_SIZE_INC 24055 +#define IDS_SUB_POS_DOWN 24056 +#define IDS_SUB_POS_UP 24057 +#define IDS_SUB_FONT_SIZE_DEC 24058 +#define IDS_SUB_FONT_SIZE_INC 24059 +#define ID_VIEW_TEARING_TEST 32769 +#define ID_FILE_OPENDISC 32774 +#define ID_SHADERS 32775 +#define ID_VIEW_OSD_SHOW_FILENAME 32777 +#define ID_VIEW_OSD_DISPLAY_TIME 32778 +#define ID_D3DFULLSCREEN_TOGGLE 32779 +#define ID_GOTO_PREV_SUB 32780 +#define ID_GOTO_NEXT_SUB 32781 +#define ID_SUBRESYNC_SHIFT_DOWN 32782 +#define ID_SUBRESYNC_SHIFT_UP 32783 +#define ID_VIEW_DISPLAY_RENDERER_STATS 32784 +#define ID_VIEW_RESET_RENDERER_STATS 32785 +#define IDS_AG_CLOSE 32830 +#define IDS_AG_NONE 32832 +#define IDS_AG_COMMAND 32833 +#define IDS_AG_KEY 32834 +#define IDS_AG_MOUSE 32836 +#define IDS_AG_APP_COMMAND 32838 +#define IDS_AG_MEDIAFILES 32871 +#define IDS_AG_ALLFILES 32872 +#define IDS_AG_AUDIOFILES 32873 +#define IDS_AG_NOT_KNOWN 32876 +#define IDS_MPLAYERC_0 32877 +#define IDS_AG_OPEN_FILE 32878 +#define IDS_AG_OPEN_DVD 32879 +#define IDS_AG_OPEN_DEVICE 32880 +#define IDS_AG_SAVE_AS 32881 +#define IDS_AG_SAVE_IMAGE 32882 +#define IDS_MPLAYERC_6 32883 +#define IDS_OSD_IMAGE_SAVED 32884 +#define IDS_AG_LOAD_SUBTITLES 32885 +#define IDS_AG_SAVE_SUBTITLES 32886 +#define IDS_AG_PROPERTIES 32887 +#define IDS_AG_EXIT 32888 +#define IDS_AG_PLAYPAUSE 32889 +#define IDS_AG_PLAY 32890 +#define IDS_AG_STOP 32891 +#define IDS_AG_FRAMESTEP 32892 +#define IDS_MPLAYERC_16 32893 +#define IDS_AG_GO_TO 32894 +#define IDS_AG_INCREASE_RATE 32895 +#define IDS_AG_DECREASE_RATE 32896 +#define IDS_AG_RESET_RATE 32897 +#define IDS_MPLAYERC_21 32898 +#define IDS_MPLAYERC_22 32899 +#define IDS_MPLAYERC_23 32900 +#define IDS_MPLAYERC_24 32901 +#define IDS_MPLAYERC_25 32902 +#define IDS_MPLAYERC_26 32903 +#define IDS_MPLAYERC_27 32904 +#define IDS_MPLAYERC_28 32905 +#define IDS_MPLAYERC_29 32906 +#define IDS_MPLAYERC_30 32907 +#define IDS_AG_NEXT 32908 +#define IDS_AG_PREVIOUS 32909 +#define IDS_AG_NEXT_FILE 32910 +#define IDS_AG_PREVIOUS_FILE 32911 +#define IDS_AG_VIEW_MINIMAL 32912 +#define IDS_AG_VIEW_COMPACT 32913 +#define IDS_AG_VIEW_NORMAL 32914 +#define IDS_AG_FULLSCREEN 32915 +#define IDS_MPLAYERC_39 32916 +#define IDS_AG_ZOOM_AUTO_FIT 32917 +#define IDS_AG_VIDFRM_HALF 32918 +#define IDS_AG_VIDFRM_NORMAL 32919 +#define IDS_AG_VIDFRM_DOUBLE 32920 +#define IDS_AG_ALWAYS_ON_TOP 32921 +#define IDS_AG_PNS_INC_SIZE 32922 +#define IDS_AG_PNS_INC_WIDTH 32923 +#define IDS_MPLAYERC_47 32924 +#define IDS_AG_PNS_DEC_SIZE 32925 +#define IDS_AG_PNS_DEC_WIDTH 32926 +#define IDS_MPLAYERC_50 32927 +#define IDS_AG_PNS_CENTER 32928 +#define IDS_AG_PNS_LEFT 32929 +#define IDS_AG_PNS_RIGHT 32930 +#define IDS_AG_PNS_UP 32931 +#define IDS_AG_PNS_DOWN 32932 +#define IDS_AG_PNS_UPLEFT 32933 +#define IDS_AG_PNS_UPRIGHT 32934 +#define IDS_AG_PNS_DOWNLEFT 32935 +#define IDS_MPLAYERC_59 32936 +#define IDS_AG_VOLUME_UP 32937 +#define IDS_AG_VOLUME_DOWN 32938 +#define IDS_AG_VOLUME_MUTE 32939 +#define IDS_MPLAYERC_63 32940 +#define IDS_AG_DVD_ROOT_MENU 32941 +#define IDS_MPLAYERC_65 32942 +#define IDS_MPLAYERC_66 32943 +#define IDS_MPLAYERC_67 32944 +#define IDS_MPLAYERC_68 32945 +#define IDS_AG_DVD_MENU_LEFT 32946 +#define IDS_MPLAYERC_70 32947 +#define IDS_AG_DVD_MENU_UP 32948 +#define IDS_AG_DVD_MENU_DOWN 32949 +#define IDS_MPLAYERC_73 32950 +#define IDS_AG_DVD_MENU_BACK 32951 +#define IDS_MPLAYERC_75 32952 +#define IDS_AG_BOSS_KEY 32953 +#define IDS_MPLAYERC_77 32954 +#define IDS_MPLAYERC_78 32955 +#define IDS_AG_FILTERS_MENU 32956 +#define IDS_AG_OPTIONS 32957 +#define IDS_AG_NEXT_AUDIO 32958 +#define IDS_AG_PREV_AUDIO 32959 +#define IDS_AG_NEXT_SUBTITLE 32960 +#define IDS_AG_PREV_SUBTITLE 32961 +#define IDS_MPLAYERC_85 32962 +#define IDS_MPLAYERC_86 32963 +#define IDS_MPLAYERC_91 32968 +#define IDS_MPLAYERC_92 32969 +#define IDS_MPLAYERC_93 32970 +#define IDS_MPLAYERC_94 32971 +#define IDS_MPLAYERC_95 32972 +#define IDS_MPLAYERC_96 32973 +#define IDS_MPLAYERC_97 32974 +#define IDS_OSD_DISPLAY_CURRENT_TIME 32975 +#define IDS_MPLAYERC_99 32976 +#define IDS_MPLAYERC_100 32977 +#define IDS_MPLAYERC_101 32978 +#define IDS_MPLAYERC_102 32979 +#define IDS_MPLAYERC_103 32980 +#define IDS_AG_SEEKSET 32982 +#define IDS_OSD_SHOW_FILENAME 32983 +#define IDS_PLAY_DVD 32984 +#define IDS_PLAY_BD 32985 +#define IDS_PPAGEWEBSERVER_0 32996 +#define IDS_MAINFRM_2 33014 +#define IDS_AG_SUBTITLES_SAVED 33015 +#define IDS_MAINFRM_4 33016 +#define IDS_AG_FRAMERATE 33017 +#define IDS_MAINFRM_6 33018 +#define IDS_AG_FRAMES 33019 +#define IDS_AG_BUFFERS 33020 +#define IDS_MAINFRM_9 33021 +#define IDS_MAINFRM_10 33022 +#define IDS_MAINFRM_11 33023 +#define IDS_AG_TITLE 33024 +#define IDS_MAINFRM_16 33025 +#define IDS_MAINFRM_17 33026 +#define IDS_MAINFRM_18 33027 +#define IDS_MAINFRM_19 33028 +#define IDS_MAINFRM_20 33029 +#define IDS_MAINFRM_21 33030 +#define IDS_MAINFRM_22 33031 +#define IDS_MAINFRM_23 33032 +#define IDS_AG_ASPECT_RATIO 33045 +#define IDS_MAINFRM_37 33046 +#define IDS_MAINFRM_38 33047 +#define IDS_MAINFRM_39 33048 +#define IDS_MAINFRM_40 33049 +#define IDS_MAINFRM_41 33050 +#define IDS_MAINFRM_42 33051 +#define IDS_AG_ERROR 33052 +#define IDS_SUBTITLE_STREAM_OFF 33053 +#define IDS_SUBTITLE_STREAM 33054 +#define IDS_MAINFRM_46 33055 +#define IDS_SUB_LOADED_SUCCESS 33056 +#define IDS_ALL_FILES_FILTER 33057 +#define IDS_GETDIB_FAILED 33058 +#define IDS_GETCURRENTIMAGE_FAILED 33059 +#define IDS_SCREENSHOT_ERROR 33060 +#define IDS_THUMBNAILS_NO_DURATION 33061 +#define IDS_THUMBNAILS_NO_FRAME_SIZE 33062 +#define IDS_OUT_OF_MEMORY 33063 +#define IDS_THUMBNAILS_INVALID_FORMAT 33064 +#define IDS_THUMBNAILS_INFO_FILESIZE 33065 +#define IDS_THUMBNAILS_INFO_HEADER 33066 +#define IDS_THUMBNAIL_TOO_SMALL 33067 +#define IDS_CANNOT_LOAD_SUB 33068 +#define IDS_SUBTITLE_FILES_FILTER 33069 +#define IDS_MAINFRM_68 33075 +#define IDS_MAINFRM_69 33076 +#define IDS_MAINFRM_70 33077 +#define IDS_AG_CHAPTER 33078 +#define IDS_AG_OUT_OF_MEMORY 33081 +#define IDS_MAINFRM_77 33082 +#define IDS_MAINFRM_80 33084 +#define IDS_MAINFRM_81 33085 +#define IDS_MAINFRM_82 33086 +#define IDS_MAINFRM_83 33087 +#define IDS_MAINFRM_84 33088 +#define IDS_MAINFRM_86 33089 +#define IDS_MAINFRM_87 33090 +#define IDS_MAINFRM_88 33091 +#define IDS_MAINFRM_89 33092 +#define IDS_MAINFRM_90 33093 +#define IDS_MAINFRM_91 33094 +#define IDS_MAINFRM_92 33095 +#define IDS_MAINFRM_93 33096 +#define IDS_MAINFRM_94 33097 +#define IDS_AG_FAILED 33098 +#define IDS_MAINFRM_96 33099 +#define IDS_MAINFRM_98 33100 +#define IDS_MAINFRM_99 33101 +#define IDS_MAINFRM_108 33106 +#define IDS_AG_SOUND 33107 +#define IDS_MAINFRM_114 33108 +#define IDS_AG_ABORTED 33109 +#define IDS_MAINFRM_116 33110 +#define IDS_MAINFRM_117 33111 +#define IDS_AG_UNKNOWN_STREAM 33112 +#define IDS_AG_UNKNOWN 33113 +#define IDS_AG_VSYNC 33114 +#define IDS_MAINFRM_121 33115 +#define IDS_MAINFRM_122 33116 +#define IDS_DVD_SUBTITLES_ENABLE 33117 +#define IDS_AG_ANGLE 33118 +#define IDS_AG_VSYNCOFFSET_INCREASE 33119 +#define IDS_AG_DISABLED 33120 +#define IDS_AG_VSYNCOFFSET_DECREASE 33121 +#define IDS_MAINFRM_136 33126 +#define IDS_MAINFRM_137 33127 +#define IDS_MAINFRM_138 33128 +#define IDS_VOLUME_BOOST_INC 33129 +#define IDS_VOLUME_BOOST_DEC 33130 +#define IDS_VOLUME_BOOST_MIN 33131 +#define IDS_VOLUME_BOOST_MAX 33132 +#define IDS_USAGE 33133 +#define IDS_UNKNOWN_SWITCH 33134 +#define IDS_ADD_TO_PLAYLIST 33161 +#define IDS_OPEN_WITH_MPC 33162 +#define IDS_CANNOT_CHANGE_FORMAT 33163 +#define IDS_APP_DESCRIPTION 33164 +#define IDS_MAINFRM_12 33165 +#define IDS_MAINFRM_13 33166 +#define IDS_D3DFS_WARNING 33190 +#define IDS_MAINFRM_139 33191 +#define IDS_AG_TITLE2 33192 +#define IDS_REALVIDEO_INCOMPATIBLE 33193 +#define IDS_THUMB_ROWNUMBER 33195 +#define IDS_THUMB_COLNUMBER 33196 +#define IDS_THUMB_IMAGE_WIDTH 33197 +#define IDS_AG_CHAPTER2 33201 +#define IDS_VOLUME_OSD 33202 +#define IDS_BOOST_OSD 33203 +#define IDS_BALANCE_OSD 33204 +#define IDS_FULLSCREENMONITOR_CURRENT 33205 +#define ID_FILE_OPENDIRECTORY 33208 +#define IDS_MAINFRM_DIR_TITLE 33209 +#define IDS_MAINFRM_DIR_CHECK 33210 +#define IDS_AG_PAUSE 33212 +#define IDS_AG_TOGGLE_CAPTION 33213 +#define IDS_AG_TOGGLE_SEEKER 33214 +#define IDS_AG_TOGGLE_CONTROLS 33215 +#define IDS_AG_TOGGLE_INFO 33216 +#define IDS_AG_TOGGLE_STATS 33217 +#define IDS_AG_TOGGLE_STATUS 33218 +#define IDS_AG_TOGGLE_SUBRESYNC 33219 +#define IDS_AG_TOGGLE_PLAYLIST 33220 +#define IDS_AG_TOGGLE_CAPTURE 33221 +#define IDS_AG_TOGGLE_DEBUGSHADERS 33222 +#define IDS_AG_ZOOM_50 33223 +#define IDS_AG_ZOOM_100 33224 +#define IDS_AG_ZOOM_200 33225 +#define IDS_AG_NEXT_AR_PRESET 33226 +#define IDS_AG_VIDFRM_STRETCH 33227 +#define IDS_AG_VIDFRM_INSIDE 33228 +#define IDS_AG_VIDFRM_OUTSIDE 33229 +#define IDS_AG_PNS_RESET 33230 +#define IDS_AG_PNS_ROTATEX_P 33231 +#define IDS_AG_PNS_ROTATEX_M 33232 +#define IDS_AG_PNS_ROTATEY_P 33233 +#define IDS_AG_PNS_ROTATEY_M 33234 +#define IDS_AG_PNS_ROTATEZ_P 33235 +#define IDS_AG_PNS_ROTATEZ_M 33236 +#define IDS_AG_TEARING_TEST 33237 +#define IDS_SCALE_16_9 33239 +#define IDS_SCALE_WIDESCREEN 33240 +#define IDS_SCALE_ULTRAWIDE 33241 +#define IDS_PLAYLIST_HIDEFS 33242 +#define ID_VIEW_VSYNC 33243 +#define ID_VIEW_VSYNCOFFSET 33245 +#define ID_VIEW_VSYNCOFFSET_DECREASE 33246 +#define ID_VIEW_VSYNCOFFSET_INCREASE 33247 +#define IDS_AG_TOGGLE_NAVIGATION 33248 +#define ID_VIEW_VSYNCACCURATE 33260 +#define IDS_AG_VSYNCACCURATE 33261 +#define ID_VIEW_FULLSCREENGUISUPPORT 33263 +#define ID_VIEW_HIGHCOLORRESOLUTION 33264 +#define ID_VIEW_ENABLEFRAMETIMECORRECTION 33265 +#define ID_VIEW_EVROUTPUTRANGE 33269 +#define ID_VIEW_EVROUTPUTRANGE_0_255 33273 +#define ID_VIEW_EVROUTPUTRANGE_16_235 33274 +#define IDS_AG_ENABLEFRAMETIMECORRECTION 33275 +#define IDS_AG_TOGGLE_EDITLISTEDITOR 33277 +#define IDS_AG_EDL_IN 33278 +#define IDS_AG_EDL_OUT 33279 +#define IDS_AG_EDL_NEW_CLIP 33280 +#define ID_RECENT_FILES 33281 +#define ID_RECENT_FILES_CLEAR 33282 +#define IDS_RECENT_FILES_CLEAR 33283 +#define IDS_RECENT_FILES_QUESTION 33284 +#define ID_VIEW_FLUSHGPU_BEFOREVSYNC 33286 +#define ID_VIEW_FLUSHGPU_AFTERPRESENT 33287 +#define ID_VIEW_FLUSHGPU_WAIT 33288 +#define ID_VIEW_D3DFULLSCREEN 33289 +#define ID_VIEW_DISABLEDESKTOPCOMPOSITION 33290 +#define ID_VIEW_ALTERNATIVEVSYNC 33291 +#define ID_VIEW_RESET_DEFAULT 33292 +#define ID_VIEW_RESET_OPTIMAL 33293 +#define IDS_AG_EDL_SAVE 33294 +#define IDC_RESETDEVICE 33400 +#define IDS_NAVIGATE_TUNERSCAN 33401 +#define IDS_SUBTITLES_ERROR 33402 +#define IDC_CHECK_ENHANCED_TASKBAR 33403 +#define IDC_CACHESHADERS 33404 +#define ID_VIEW_SYNCHRONIZEVIDEO 33408 +#define ID_VIEW_SYNCHRONIZEDISPLAY 33409 +#define ID_VIEW_SYNCHRONIZENEAREST 33410 +#define ID_VIEW_NAVIGATION 33415 +#define IDS_AG_VIDFRM_ZOOM1 33419 +#define IDS_AG_VIDFRM_ZOOM2 33420 +#define IDS_AG_VIDFRM_SWITCHZOOM 33422 +#define IDS_ENABLE_ALL_FILTERS 33423 +#define IDS_DISABLE_ALL_FILTERS 33424 +#define IDS_ENABLE_AUDIO_FILTERS 33425 +#define IDS_DISABLE_AUDIO_FILTERS 33426 +#define IDS_ENABLE_VIDEO_FILTERS 33427 +#define IDS_DISABLE_VIDEO_FILTERS 33428 +#define IDS_STRETCH_TO_WINDOW 33429 +#define IDS_TOUCH_WINDOW_FROM_INSIDE 33430 +#define IDS_ZOOM1 33431 +#define IDS_ZOOM2 33432 +#define IDS_TOUCH_WINDOW_FROM_OUTSIDE 33433 +#define IDS_AUDIO_STREAM 33434 +#define IDS_AG_REOPEN 33435 +#define IDS_TIME_TOOLTIP_ABOVE 33440 +#define IDS_TIME_TOOLTIP_BELOW 33441 +#define IDS_VIDEO_STREAM 33442 +#define IDS_APPLY 33443 +#define IDS_CLEAR 33444 +#define IDS_CANCEL 33445 +#define IDS_THUMB_THUMBNAILS 33446 +#define IDS_THUMB_PIXELS 33447 +#define IDS_TEXTFILE_ENC 33448 +#define ID_PLAY_REPEAT_FOREVER 33449 +#define ID_PLAY_REPEAT_ONEFILE 33450 +#define ID_PLAY_REPEAT_WHOLEPLAYLIST 33451 +#define IDS_AG_ZOOM_25 33452 +#define ID_PLAY_REPEAT_AB 33453 +#define IDS_AG_MOUSE_MODIFIER 33453 +#define ID_PLAY_REPEAT_AB_MARK_A 33454 +#define ID_PLAY_REPEAT_AB_MARK_B 33455 +#define ID_VIEW_ZOOM_SUB 33456 +#define ID_VIEW_ZOOM_ADD 33457 +#define IDS_AG_ZOOM_ADD 33458 +#define IDS_AG_ZOOM_SUB 33459 +#define IDS_SEEKBAR_HOVER_PREVIEW 33460 +#define IDS_SEEKBAR_HOVER_TOOLTIP 33461 +#define ID_RECENT_FILE_START 34000 +#define ID_RECENT_FILE_END 34999 +#define IDS_MFMT_AVI 39001 +#define IDS_MFMT_MPEG 39002 +#define IDS_MFMT_MPEGTS 39003 +#define IDS_MFMT_DVDVIDEO 39004 +#define IDS_MFMT_MKV 39005 +#define IDS_MFMT_WEBM 39006 +#define IDS_MFMT_MP4 39007 +#define IDS_MFMT_MOV 39008 +#define IDS_MFMT_3GP 39009 +#define IDS_MFMT_3GA 39010 +#define IDS_MFMT_FLV 39011 +#define IDS_MFMT_OGM 39012 +#define IDS_MFMT_RM 39013 +#define IDS_MFMT_RT 39014 +#define IDS_MFMT_WMV 39015 +#define IDS_MFMT_BINK 39018 +#define IDS_MFMT_FLIC 39019 +#define IDS_MFMT_DSM 39020 +#define IDS_MFMT_IVF 39021 +#define IDS_MFMT_AVS 39022 +#define IDS_MFMT_OTHER 39401 +#define IDS_MFMT_SWF 39403 +#define IDS_MFMT_OTHER_AUDIO 39404 +#define IDS_MFMT_AC3 39501 +#define IDS_MFMT_AIFF 39502 +#define IDS_MFMT_ALAC 39503 +#define IDS_MFMT_AMR 39504 +#define IDS_MFMT_APE 39505 +#define IDS_MFMT_AU 39506 +#define IDS_MFMT_CDA 39507 +#define IDS_MFMT_FLAC 39508 +#define IDS_MFMT_M4A 39509 +#define IDS_MFMT_MIDI 39510 +#define IDS_MFMT_MKA 39511 +#define IDS_MFMT_MP3 39512 +#define IDS_MFMT_MPA 39513 +#define IDS_MFMT_MPC 39514 +#define IDS_MFMT_OFR 39515 +#define IDS_MFMT_OGG 39516 +#define IDS_MFMT_RA 39517 +#define IDS_MFMT_TAK 39518 +#define IDS_MFMT_TTA 39519 +#define IDS_MFMT_WAV 39520 +#define IDS_MFMT_WMA 39521 +#define IDS_MFMT_WV 39522 +#define IDS_MFMT_OPUS 39523 +#define IDS_MFMT_DTS 39524 +#define IDS_MFMT_PLS 39901 +#define IDS_MFMT_BDPLS 39902 +#define IDS_MFMT_RAR 39903 +#define IDTB_BUTTON1 40001 +#define IDTB_BUTTON2 40002 +#define IDTB_BUTTON3 40003 +#define IDTB_BUTTON4 40004 +#define IDTB_BUTTON5 40005 +#define IDR_TB_PLAY 41001 +#define IDR_TB_PAUSE 41002 +#define IDR_TB_STOP 41003 +#define IDS_FRONT_LEFT 41006 +#define IDS_FRONT_RIGHT 41007 +#define IDS_FRONT_CENTER 41008 +#define IDS_LOW_FREQUENCY 41009 +#define IDS_BACK_LEFT 41010 +#define IDS_BACK_RIGHT 41011 +#define IDS_FRONT_LEFT_OF_CENTER 41012 +#define IDS_FRONT_RIGHT_OF_CENTER 41013 +#define IDS_BACK_CENTER 41014 +#define IDS_SIDE_LEFT 41015 +#define IDS_SIDE_RIGHT 41016 +#define IDS_TOP_CENTER 41017 +#define IDS_TOP_FRONT_LEFT 41018 +#define IDS_TOP_FRONT_CENTER 41019 +#define IDS_TOP_FRONT_RIGHT 41020 +#define IDS_TOP_BACK_LEFT 41021 +#define IDS_TOP_BACK_CENTER 41022 +#define IDS_TOP_BACK_RIGHT 41023 +#define IDS_LOGO_AUTHOR 41024 +#define IDC_RESTORERESCHECK 41025 +#define IDS_NO_MORE_MEDIA 41026 +#define IDS_FIRST_IN_FOLDER 41027 +#define IDS_LAST_IN_FOLDER 41028 +#define IDS_FAVORITES_QUICKADDFAVORITE 41105 +#define IDS_DVB_CHANNEL_NUMBER 41109 +#define IDS_DVB_CHANNEL_NAME 41110 +#define IDS_DVB_CHANNEL_FREQUENCY 41111 +#define IDS_DVB_CHANNEL_ENCRYPTION 41112 +#define IDS_YES 41113 +#define IDS_NO 41114 +#define IDS_DVB_CHANNEL_START_SCAN 41115 +#define IDS_DVB_CHANNEL_STOP_SCAN 41116 +#define IDS_DVB_TVNAV_SEERADIO 41117 +#define IDS_DVB_TVNAV_SEETV 41118 +#define IDS_DVB_CHANNEL_FORMAT 41119 +#define IDS_DVB_CHANNEL_FPS 41120 +#define IDS_DVB_CHANNEL_RESOLUTION 41121 +#define IDS_DVB_CHANNEL_ASPECT_RATIO 41122 +#define IDS_OSD_RS_VSYNC_ON 41200 +#define IDS_OSD_RS_VSYNC_OFF 41201 +#define IDS_OSD_RS_ACCURATE_VSYNC_ON 41202 +#define IDS_OSD_RS_ACCURATE_VSYNC_OFF 41203 +#define IDS_OSD_RS_SYNC_TO_DISPLAY_ON 41204 +#define IDS_OSD_RS_SYNC_TO_DISPLAY_OFF 41205 +#define IDS_OSD_RS_SYNC_TO_VIDEO_ON 41206 +#define IDS_OSD_RS_SYNC_TO_VIDEO_OFF 41207 +#define IDS_OSD_RS_PRESENT_NEAREST_ON 41208 +#define IDS_OSD_RS_PRESENT_NEAREST_OFF 41209 +#define IDS_OSD_RS_COLOR_MANAGEMENT_ON 41210 +#define IDS_OSD_RS_COLOR_MANAGEMENT_OFF 41211 +#define IDS_OSD_RS_INPUT_TYPE_AUTO 41212 +#define IDS_OSD_RS_INPUT_TYPE_HDTV 41213 +#define IDS_OSD_RS_INPUT_TYPE_SD_NTSC 41214 +#define IDS_OSD_RS_INPUT_TYPE_SD_PAL 41215 +#define IDS_OSD_RS_AMBIENT_LIGHT_BRIGHT 41216 +#define IDS_OSD_RS_AMBIENT_LIGHT_DIM 41217 +#define IDS_OSD_RS_AMBIENT_LIGHT_DARK 41218 +#define IDS_OSD_RS_REND_INTENT_PERCEPT 41219 +#define IDS_OSD_RS_REND_INTENT_RELATIVE 41220 +#define IDS_OSD_RS_REND_INTENT_SATUR 41221 +#define IDS_OSD_RS_REND_INTENT_ABSOLUTE 41222 +#define IDS_OSD_RS_OUTPUT_RANGE 41223 +#define IDS_OSD_RS_FLUSH_BEF_VSYNC_ON 41224 +#define IDS_OSD_RS_FLUSH_BEF_VSYNC_OFF 41225 +#define IDS_OSD_RS_FLUSH_AFT_PRES_ON 41226 +#define IDS_OSD_RS_FLUSH_AFT_PRES_OFF 41227 +#define IDS_OSD_RS_WAIT_ON 41228 +#define IDS_OSD_RS_WAIT_OFF 41229 +#define IDS_OSD_RS_D3D_FULLSCREEN_ON 41230 +#define IDS_OSD_RS_D3D_FULLSCREEN_OFF 41231 +#define IDS_OSD_RS_NO_DESKTOP_COMP_ON 41232 +#define IDS_OSD_RS_NO_DESKTOP_COMP_OFF 41233 +#define IDS_OSD_RS_ALT_VSYNC_ON 41234 +#define IDS_OSD_RS_ALT_VSYNC_OFF 41235 +#define IDS_OSD_RS_RESET_DEFAULT 41236 +#define IDS_OSD_RS_RESET_OPTIMAL 41237 +#define IDS_OSD_RS_D3D_FS_GUI_SUPP_ON 41238 +#define IDS_OSD_RS_D3D_FS_GUI_SUPP_OFF 41239 +#define IDS_OSD_RS_10BIT_RBG_OUT_ON 41240 +#define IDS_OSD_RS_10BIT_RBG_OUT_OFF 41241 +#define IDS_OSD_RS_10BIT_RBG_IN_ON 41242 +#define IDS_OSD_RS_10BIT_RBG_IN_OFF 41243 +#define IDS_OSD_RS_FULL_FP_PROCESS_ON 41244 +#define IDS_OSD_RS_FULL_FP_PROCESS_OFF 41245 +#define IDS_OSD_RS_HALF_FP_PROCESS_ON 41246 +#define IDS_OSD_RS_HALF_FP_PROCESS_OFF 41247 +#define IDS_OSD_RS_FT_CORRECTION_ON 41248 +#define IDS_OSD_RS_FT_CORRECTION_OFF 41249 +#define IDS_OSD_RS_TARGET_VSYNC_OFFSET 41250 +#define IDS_OSD_RS_VSYNC_OFFSET 41251 +#define IDS_OSD_SPEED 41252 +#define IDS_OSD_THUMBS_SAVED 41253 +#define IDS_MENU_VIDEO_STREAM 41254 +#define IDS_MENU_VIDEO_ANGLE 41255 +#define IDS_RESET_SETTINGS 41256 +#define IDS_RESET_SETTINGS_WARNING 41257 +#define IDS_RESET_SETTINGS_MUTEX 41258 +#define IDS_EXPORT_SETTINGS 41259 +#define IDS_EXPORT_SETTINGS_WARNING 41260 +#define IDS_EXPORT_SETTINGS_SUCCESS 41261 +#define IDS_EXPORT_SETTINGS_FAILED 41262 +#define IDS_BDA_ERROR 41263 +#define IDS_BDA_ERROR_CREATE_TUNER 41264 +#define IDS_BDA_ERROR_CREATE_RECEIVER 41265 +#define IDS_BDA_ERROR_CONNECT_NW_TUNER 41266 +#define IDS_BDA_ERROR_CONNECT_TUNER_REC 41267 +#define IDS_BDA_ERROR_CONNECT_TUNER 41268 +#define IDS_BDA_ERROR_DEMULTIPLEXER 41269 +#define IDS_GOTO_ERROR_PARSING_TIME 41270 +#define IDS_GOTO_ERROR_PARSING_TEXT 41271 +#define IDS_GOTO_ERROR_PARSING_FPS 41272 +#define IDS_FRAME_STEP_ERROR_RENDERER 41273 +#define IDS_SCREENSHOT_ERROR_SHOCKWAVE 41276 +#define IDS_SCREENSHOT_ERROR_OVERLAY 41277 +#define IDS_SUBDL_DLG_CONNECT_ERROR 41278 +#define IDS_MB_SHOW_EDL_EDITOR 41279 +#define IDS_CAPTURE_ERROR 41280 +#define IDS_CAPTURE_ERROR_VIDEO 41281 +#define IDS_CAPTURE_ERROR_AUDIO 41282 +#define IDS_CAPTURE_ERROR_ADD_BUFFER 41283 +#define IDS_CAPTURE_ERROR_CONNECT_BUFF 41284 +#define IDS_CAPTURE_ERROR_ADD_ENCODER 41285 +#define IDS_CAPTURE_ERROR_CONNECT_ENC 41286 +#define IDS_CAPTURE_ERROR_COMPRESSION 41287 +#define IDS_CAPTURE_ERROR_MULTIPLEXER 41288 +#define IDS_CAPTURE_ERROR_VID_CAPT_PIN 41289 +#define IDS_CAPTURE_ERROR_AUD_CAPT_PIN 41290 +#define IDS_CAPTURE_ERROR_OUT_FILE 41291 +#define IDS_CAPTURE_ERROR_AUD_OUT_FILE 41292 +#define IDS_SUBRESYNC_TIME_FORMAT 41293 +#define IDS_EXTERNAL_FILTERS_ERROR_MT 41294 +#define IDS_WEBSERVER_ERROR_TEST 41295 +#define IDS_AFTERPLAYBACK_EXIT 41296 +#define IDS_AFTERPLAYBACK_STANDBY 41297 +#define IDS_AFTERPLAYBACK_HIBERNATE 41298 +#define IDS_AFTERPLAYBACK_SHUTDOWN 41299 +#define IDS_AFTERPLAYBACK_LOGOFF 41300 +#define IDS_AFTERPLAYBACK_LOCK 41301 +#define IDS_AFTERPLAYBACK_MONITOROFF 41302 +#define IDS_AFTERPLAYBACK_PLAYNEXT 41303 +#define IDS_AFTERPLAYBACK_DONOTHING 41304 +#define IDS_OSD_BRIGHTNESS 41305 +#define IDS_OSD_CONTRAST 41306 +#define IDS_OSD_HUE 41307 +#define IDS_OSD_SATURATION 41308 +#define IDS_OSD_RESET_COLOR 41309 +#define IDS_OSD_NO_COLORCONTROL 41310 +#define IDS_BRIGHTNESS_INC 41311 +#define IDS_BRIGHTNESS_DEC 41312 +#define IDS_CONTRAST_INC 41313 +#define IDS_CONTRAST_DEC 41314 +#define IDS_HUE_INC 41315 +#define IDS_HUE_DEC 41316 +#define IDS_SATURATION_INC 41317 +#define IDS_SATURATION_DEC 41318 +#define IDS_RESET_COLOR 41319 +#define ID_HELP_CHECKFORUPDATE 41321 +#define IDS_USING_LATEST_STABLE 41322 +#define IDS_USING_NEWER_VERSION 41323 +#define IDS_NEW_UPDATE_AVAILABLE 41324 +#define IDS_UPDATE_ERROR 41325 +#define IDS_UPDATE_CLOSE 41326 +#define IDS_OSD_ZOOM 41327 +#define IDS_OSD_ZOOM_AUTO 41328 +#define IDS_CUSTOM_CHANNEL_MAPPING 41329 +#define IDS_OSD_CUSTOM_CH_MAPPING_ON 41330 +#define IDS_OSD_CUSTOM_CH_MAPPING_OFF 41331 +#define IDS_NORMALIZE 41332 +#define IDS_OSD_NORMALIZE_ON 41333 +#define IDS_OSD_NORMALIZE_OFF 41334 +#define IDS_REGAIN_VOLUME 41335 +#define IDS_OSD_REGAIN_VOLUME_ON 41336 +#define IDS_OSD_REGAIN_VOLUME_OFF 41337 +#define IDS_SIZE_UNIT_BYTES 41338 +#define IDS_SIZE_UNIT_K 41339 +#define IDS_SIZE_UNIT_M 41340 +#define IDS_SIZE_UNIT_G 41341 +#define IDS_SPEED_UNIT_K 41342 +#define IDS_SPEED_UNIT_M 41343 +#define IDS_SPEED_UNIT_G 41344 +#define IDS_FILE_FAV_ADDED 41345 +#define IDS_DVD_FAV_ADDED 41346 +#define IDS_CAPTURE_SETTINGS 41347 +#define IDS_NAVIGATION_BAR 41348 +#define IDS_SUBRESYNC_CAPTION 41350 +#define IDS_SUBRESYNC_CLN_TIME 41351 +#define IDS_SUBRESYNC_CLN_END 41352 +#define IDS_SUBRESYNC_CLN_PREVIEW 41353 +#define IDS_SUBRESYNC_CLN_VOB_ID 41354 +#define IDS_SUBRESYNC_CLN_CELL_ID 41355 +#define IDS_SUBRESYNC_CLN_FORCED 41356 +#define IDS_SUBRESYNC_CLN_TEXT 41357 +#define IDS_SUBRESYNC_CLN_STYLE 41358 +#define IDS_SUBRESYNC_CLN_FONT 41359 +#define IDS_SUBRESYNC_CLN_CHARSET 41360 +#define IDS_SUBRESYNC_CLN_UNICODE 41361 +#define IDS_SUBRESYNC_CLN_LAYER 41362 +#define IDS_SUBRESYNC_CLN_ACTOR 41363 +#define IDS_SUBRESYNC_CLN_EFFECT 41364 +#define IDS_PLAYLIST_CAPTION 41365 +#define IDS_PPAGE_FS_CLN_ON_OFF 41366 +#define IDS_PPAGE_FS_CLN_FROM_FPS 41367 +#define IDS_PPAGE_FS_CLN_TO_FPS 41368 +#define IDS_PPAGE_FS_CLN_DISPLAY_MODE 41369 +#define IDS_PPAGE_FS_DEFAULT 41370 +#define IDS_PPAGE_FS_OTHER 41371 +#define IDS_PPAGE_OUTPUT_SYS_DEF 41372 +#define IDS_GRAPH_INTERFACES_ERROR 41373 +#define IDS_GRAPH_TARGET_WND_ERROR 41374 +#define IDS_DVD_NAV_ALL_PINS_ERROR 41375 +#define IDS_DVD_NAV_SOME_PINS_ERROR 41376 +#define IDS_DVD_INTERFACES_ERROR 41377 +#define IDS_CAPTURE_LIVE 41378 +#define IDS_CAPTURE_ERROR_VID_FILTER 41379 +#define IDS_CAPTURE_ERROR_AUD_FILTER 41380 +#define IDS_CAPTURE_ERROR_DEVICE 41381 +#define IDS_INVALID_PARAMS_ERROR 41382 +#define IDS_EDIT_LIST_EDITOR 41383 +#define IDS_GOTO_ERROR_INVALID_TIME 41384 +#define IDS_MISSING_ICONS_LIB 41386 +#define IDS_SUBDL_DLG_FILENAME_COL 41387 +#define IDS_SUBDL_DLG_LANGUAGE_COL 41388 +#define IDS_SUBDL_DLG_FORMAT_COL 41389 +#define IDS_SUBDL_DLG_DISC_COL 41390 +#define IDS_SUBDL_DLG_TITLES_COL 41391 +#define IDS_SUBDL_DLG_DOWNLOADING 41392 +#define IDS_SUBDL_DLG_PARSING 41393 +#define IDS_SUBDL_DLG_NOT_FOUND 41394 +#define IDS_SUBDL_DLG_SUBS_AVAIL 41395 +#define IDS_UPDATE_CONFIG_AUTO_CHECK 41396 +#define IDS_ZOOM_50 41397 +#define IDS_ZOOM_100 41398 +#define IDS_ZOOM_200 41399 +#define IDS_ZOOM_AUTOFIT 41400 +#define IDS_ZOOM_AUTOFIT_LARGER 41401 +#define IDS_AG_ZOOM_AUTO_FIT_LARGER 41402 +#define IDS_OSD_ZOOM_AUTO_LARGER 41403 +#define IDS_TOOLTIP_EXPLORE_TO_FILE 41404 +#define IDS_TOOLTIP_REMAINING_TIME 41405 +#define IDS_UPDATE_DELAY_ERROR_TITLE 41406 +#define IDS_UPDATE_DELAY_ERROR_MSG 41407 +#define IDS_AUDIOSWITCHER 41408 +#define IDS_ICONS_REASSOC_DLG_TITLE 41409 +#define IDS_ICONS_REASSOC_DLG_INSTR 41410 +#define IDS_ICONS_REASSOC_DLG_CONTENT 41411 +#define IDS_PPAGE_OUTPUT_OLDRENDERER 41412 +#define IDS_PPAGE_OUTPUT_OVERLAYMIXER 41413 +#define IDS_ZOOM_25 41414 +#define IDS_PPAGE_OUTPUT_VMR9WINDOWED 41415 +#define IDS_PPAGE_OUTPUT_VMR9RENDERLESS 41417 +#define IDS_PPAGE_OUTPUT_EVR 41418 +#define IDS_PPAGE_OUTPUT_EVR_CUSTOM 41419 +#define IDS_PPAGE_OUTPUT_DXR 41420 +#define IDS_PPAGE_OUTPUT_NULL_COMP 41421 +#define IDS_PPAGE_OUTPUT_NULL_UNCOMP 41422 +#define IDS_PPAGE_OUTPUT_MADVR 41423 +#define IDS_PPAGE_OUTPUT_SYNC 41424 +#define IDS_PPAGE_OUTPUT_AUD_MPC_REND 41425 +#define IDS_PPAGE_OUTPUT_SURF_OFFSCREEN 41427 +#define IDS_PPAGE_OUTPUT_SURF_2D 41428 +#define IDS_PPAGE_OUTPUT_SURF_3D 41429 +#define IDS_PPAGE_OUTPUT_RESIZE_NN 41430 +#define IDS_PPAGE_OUTPUT_RESIZER_BILIN 41431 +#define IDS_PPAGE_OUTPUT_RESIZER_BIL_PS 41432 +#define IDS_PPAGE_OUTPUT_RESIZER_BICUB1 41433 +#define IDS_PPAGE_OUTPUT_RESIZER_BICUB2 41434 +#define IDS_PPAGE_OUTPUT_RESIZER_BICUB3 41435 +#define IDS_PPAGE_OUTPUT_UNAVAILABLE 41436 +#define IDS_PPAGE_OUTPUT_UNAVAILABLEMSG 41437 +#define IDS_PPAGE_OUTPUT_AUD_NULL_COMP 41438 +#define IDS_PPAGE_OUTPUT_AUD_NULL_UNCOMP 41439 +#define IDS_PPAGE_OUTPUT_AUD_INTERNAL_REND 41440 +#define IDS_EMB_RESOURCES_VIEWER_NAME 41441 +#define IDS_EMB_RESOURCES_VIEWER_TYPE 41442 +#define IDS_EMB_RESOURCES_VIEWER_INFO 41443 +#define IDS_SUBTITLES_DOWNLOAD 41444 +#define IDS_SUBTITLES_UPLOAD 41445 +#define IDS_SUBFILE_DELAY 41448 +#define IDS_SPEEDSTEP_AUTO 41449 +#define IDS_EXPORT_SETTINGS_NO_KEYS 41450 +#define IDS_RFS_NO_FILES 41451 +#define IDS_RFS_COMPRESSED 41452 +#define IDS_RFS_ENCRYPTED 41453 +#define IDS_RFS_MISSING_VOLS 41454 +#define IDS_OSD_D3DFS_REMINDER 41455 +#define IDS_LANG_PREF_EXAMPLE 41456 +#define IDS_OVERRIDE_EXT_SPLITTER_CHOICE 41457 +#define IDC_SPLITTER_CONF 41458 +#define IDC_VIDEO_DEC_CONF 41459 +#define IDC_AUDIO_DEC_CONF 41460 +#define IDS_NAVIGATE_BD_PLAYLISTS 41461 +#define IDS_NAVIGATE_PLAYLIST 41462 +#define IDS_NAVIGATE_CHAPTERS 41463 +#define IDS_NAVIGATE_TITLES 41464 +#define IDS_NAVIGATE_CHANNELS 41465 +#define IDS_PPAGE_OUTPUT_MPCVR 41466 +#define IDS_PPAGE_OUTPUT_VMR7 41467 +#define IDS_MOUSE_CLICK_MIDDLE 41702 +#define IDS_MOUSE_CLICK_X1 41703 +#define IDS_MOUSE_CLICK_X2 41704 +#define IDS_MOUSE_WHEEL_UP 41705 +#define IDS_MOUSE_WHEEL_DOWN 41706 +#define IDS_MOUSE_WHEEL_LEFT 41707 +#define IDS_MOUSE_WHEEL_RIGHT 41708 +#define IDS_MOUSE_ACTION 41710 +#define IDS_MOUSE_COMMAND 41711 +#define IDS_MOUSE_RIGHT_BUTTON 41712 +#define IDS_PPAGE_CAPTURE_FG0 57345 +#define IDS_PPAGE_CAPTURE_FG1 57346 +#define IDS_PPAGE_CAPTURE_FG2 57347 +#define IDS_PPAGE_CAPTURE_FGDESC0 57348 +#define IDS_PPAGE_CAPTURE_FGDESC1 57349 +#define IDS_PPAGE_CAPTURE_FGDESC2 57350 +#define IDS_PPAGE_CAPTURE_SFG0 57351 +#define IDS_PPAGE_CAPTURE_SFG1 57352 +#define IDS_PPAGE_CAPTURE_SFG2 57353 +#define IDS_INFOBAR_PARENTAL_RATING 57354 +#define IDS_PARENTAL_RATING 57355 +#define IDS_NO_PARENTAL_RATING 57356 +#define IDS_INFOBAR_CONTENT 57357 +#define IDS_CONTENT_MOVIE_DRAMA 57358 +#define IDS_CONTENT_NEWS_CURRENTAFFAIRS 57359 +#define IDS_CONTENT_SHOW_GAMESHOW 57360 +#define IDS_CONTENT_SPORTS 57361 +#define IDS_CONTENT_CHILDREN_YOUTH_PROG 57362 +#define IDS_CONTENT_MUSIC_BALLET_DANCE 57363 +#define IDS_CONTENT_MUSIC_ART_CULTURE 57364 +#define IDS_CONTENT_SOCIAL_POLITICAL_ECO 57365 +#define IDS_CONTENT_LEISURE 57366 +#define IDS_FILE_RECYCLE 57367 +#define IDS_AG_SAVE_COPY 57368 +#define IDS_FASTSEEK_LATEST 57369 +#define IDS_FASTSEEK_NEAREST 57370 +#define IDS_HOOKS_FAILED 57371 +#define IDS_PPAGEFULLSCREEN_SHOWNEVER 57372 +#define IDS_PPAGEFULLSCREEN_SHOWMOVED 57373 +#define IDS_PPAGEFULLSCREEN_SHOHHOVERED 57374 +#define IDS_MAINFRM_PRE_SHADERS_FAILED 57375 +#define IDS_MAINFRM_POST_SHADERS_FAILED 57376 +#define IDS_MAINFRM_BOTH_SHADERS_FAILED 57377 +#define IDS_DEBUGSHADERS_FIRSTRUN_MSG 57378 +#define IDS_SHADER_DLL_ERR_0 57379 +#define IDS_SHADER_DLL_ERR_1 57380 +#define IDS_OSD_SHADERS_PRESET 57381 +#define ID_SHADERS_PRESET_NEXT 57382 +#define IDS_AG_SHADERS_PRESET_NEXT 57383 +#define ID_SHADERS_PRESET_PREV 57384 +#define IDS_AG_SHADERS_PRESET_PREV 57385 +#define IDS_STRING_COLON 57386 +#define IDS_RECORD_START 57387 +#define IDS_RECORD_STOP 57388 +#define IDS_BALANCE 57389 +#define IDS_BALANCE_L 57390 +#define IDS_BALANCE_R 57391 +#define IDS_VOLUME 57392 +#define IDS_BOOST 57393 +#define IDS_PLAYLIST_ADDFOLDER 57394 +#define IDS_HW_INDICATOR 57395 +#define IDS_TOOLTIP_SOFTWARE_DECODING 57396 +#define IDS_STATSBAR_PLAYBACK_RATE 57397 +#define IDS_FILTERS_COPY_TO_CLIPBOARD 57398 +#define IDS_CREDENTIALS_SERVER 57399 +#define IDS_CREDENTIALS_CONNECT 57400 +#define IDS_SUB_SAVE_EXTERNAL_STYLE_FILE 57401 +#define IDS_CONTENT_EDUCATION_SCIENCE 57402 +#define IDS_PPAGEADVANCED_HIDE_WINDOWED 57403 +#define IDS_PPAGEADVANCED_BLOCK_VSFILTER 57404 +#define IDS_PPAGEADVANCED_COL_NAME 57405 +#define IDS_PPAGEADVANCED_COL_VALUE 57406 +#define IDS_PPAGEADVANCED_RECENT_FILES_NUMBER 57407 +#define IDS_PPAGEADVANCED_FILE_POS_LONGER 57408 +#define IDS_PPAGEADVANCED_FILE_POS_AUDIO 57409 +#define IDS_AFTER_PLAYBACK_DO_NOTHING 57410 +#define IDS_AFTER_PLAYBACK_PLAY_NEXT 57411 +#define IDS_AFTER_PLAYBACK_REWIND 57412 +#define IDS_AFTER_PLAYBACK_CLOSE 57413 +#define IDS_AFTER_PLAYBACK_EXIT 57414 +#define IDS_AFTER_PLAYBACK_MONITOROFF 57415 +#define IDS_IMAGE_JPEG_QUALITY 57416 +#define IDS_IMAGE_QUALITY 57417 +#define IDS_PPAGEADVANCED_COVER_SIZE_LIMIT 57418 +#define IDS_SUBTITLE_DELAY_STEP_TOOLTIP 57419 +#define IDS_HOTKEY_NOT_DEFINED 57420 +#define IDS_NAVIGATION_WATCH 57421 +#define IDS_NAVIGATION_MOVE_UP 57422 +#define IDS_NAVIGATION_MOVE_DOWN 57423 +#define IDS_NAVIGATION_SORT 57424 +#define IDS_NAVIGATION_REMOVE_ALL 57425 +#define IDS_REMOVE_CHANNELS_QUESTION 57426 +#define IDS_MEDIAINFO_NO_INFO_AVAILABLE 57427 +#define IDS_MEDIAINFO_ANALYSIS_IN_PROGRESS 57428 +#define IDS_ASPECT_RATIO_FMT 57429 +#define IDS_PPAGEADVANCED_LOGGER 57430 +#define IDS_TIMER_REMAINING_TIME 57431 +#define IDS_TIMER_HIGH_PRECISION 57432 +#define IDS_AFTERPLAYBACK_REWIND 57433 +#define IDS_AFTERPLAYBACK_CLOSE 57434 +#define IDS_FRAME_INIT_FAILED 57435 +#define IDS_TIME_SHIFT_TOOLTIP 57436 +#define IDS_WEBUI_DISABLED_PREVIEW_MSG 57437 +#define IDS_WEBUI_PREVIEW_WARNING 57438 +#define IDS_SUBTITLE_RENDERER_INTERNAL 57439 +#define IDS_SUBTITLE_RENDERER_VS_FILTER 57440 +#define IDS_SUBTITLE_RENDERER_XY_SUB_FILTER 57441 +#define IDS_SUBDL_DLG_PROVIDER_COL 57442 +#define IDS_SUBDL_DLG_HI_COL 57443 +#define IDS_SUBDL_DLG_DOWNLOADS_COL 57444 +#define IDS_SUBDL_DLG_SCORE_COL 57445 +#define IDS_SUBDL_DLG_FAILED 57446 +#define IDS_SUBDL_DLG_ABORTED 57447 +#define IDS_SUBDL_DLG_FOUND 57448 +#define IDS_SUBDL_DLG_NOTFOUND 57449 +#define IDS_SUBDL_DLG_TITLE 57450 +#define IDS_SUBDL_DLG_SEARCHING 57451 +#define IDS_SUBDL_DLG_ABORTING 57452 +#define IDS_SUBUL_DLG_USERNAME_COL 57453 +#define IDS_SUBUL_DLG_STATUS_COL 57454 +#define IDS_SUBUL_DLG_STATUS_READY 57455 +#define IDS_SUBUL_DLG_STATUS_NOTIMPLEMENTED 57456 +#define IDS_SUBUL_DLG_STATUS_UPLOADING 57457 +#define IDS_SUBUL_DLG_STATUS_UPLOADED 57458 +#define IDS_SUBUL_DLG_STATUS_FAILED 57459 +#define IDS_SUBUL_DLG_STATUS_ABORTED 57460 +#define IDS_SUBUL_DLG_STATUS_ALREADYEXISTS 57461 +#define IDS_SUBUL_DLG_UPLOADING 57462 +#define IDS_SUBUL_DLG_UPLOADED 57463 +#define IDS_SUBUL_DLG_ABORTED 57464 +#define IDS_SUBUL_DLG_FAILED 57465 +#define IDS_SUBMENU_DOWNLOAD 57466 +#define IDS_SUBMENU_SETUP 57467 +#define IDS_SUBMENU_RESET 57468 +#define IDS_SUBMENU_MOVEUP 57469 +#define IDS_SUBMENU_MOVEDOWN 57470 +#define IDS_SUBMENU_OPENURL 57471 +#define IDS_SUBPP_DLG_LANGUAGES_COL 57472 +#define IDS_SUBPP_DLG_LANGUAGES_ERROR 57473 +#define IDS_SUB_CREDENTIALS_TITLE 57474 +#define IDS_SUB_CREDENTIALS_MSG 57475 +#define IDS_ASPECT_RATIO_SAR 57476 +#define IDS_SUBDL_DLG_DOWNLOADED 57477 +#define IDS_SUBUL_DLG_TITLE 57478 +#define IDS_SUBUL_DLG_CONFIRM 57479 +#define IDS_SUBPP_DLG_FETCHING_LANGUAGES 57480 +#define IDS_SUB_CREDENTIALS_ERROR 57481 +#define IDS_SUB_AUTODL_IGNORE_TOOLTIP 57482 +#define IDS_CMD_PATHNAME 57483 +#define IDS_CMD_DUB 57484 +#define IDS_CMD_DUBDELAY 57485 +#define IDS_CMD_D3DFS 57486 +#define IDS_CMD_SUB 57487 +#define IDS_CMD_FILTER 57488 +#define IDS_CMD_DVD 57489 +#define IDS_CMD_DVDPOS_TC 57490 +#define IDS_CMD_DVDPOS_TIME 57491 +#define IDS_CMD_CD 57492 +#define IDS_CMD_DEVICE 57493 +#define IDS_CMD_OPEN 57494 +#define IDS_CMD_PLAY 57495 +#define IDS_CMD_CLOSE 57496 +#define IDS_CMD_SHUTDOWN 57497 +#define IDS_CMD_STANDBY 57498 +#define IDS_CMD_HIBERNATE 57499 +#define IDS_CMD_LOGOFF 57500 +#define IDS_CMD_LOCK 57501 +#define IDS_CMD_MONITOROFF 57502 +#define IDS_CMD_PLAYNEXT 57503 +#define IDS_CMD_FULLSCREEN 57504 +#define IDS_CMD_MINIMIZED 57505 +#define IDS_CMD_NEW 57506 +#define IDS_CMD_ADD 57507 +#define IDS_CMD_RANDOMIZE 57508 +#define IDS_CMD_REGVID 57509 +#define IDS_CMD_REGAUD 57510 +#define IDS_CMD_REGPL 57511 +#define IDS_CMD_REGALL 57512 +#define IDS_CMD_UNREGALL 57513 +#define IDS_CMD_START 57514 +#define IDS_CMD_STARTPOS 57515 +#define IDS_CMD_FIXEDSIZE 57516 +#define IDS_CMD_MONITOR 57517 +#define IDS_CMD_AUDIORENDERER 57518 +#define IDS_CMD_SHADERPRESET 57519 +#define IDS_CMD_PNS 57520 +#define IDS_CMD_ICONASSOC 57521 +#define IDS_CMD_NOFOCUS 57522 +#define IDS_CMD_WEBPORT 57523 +#define IDS_CMD_DEBUG 57524 +#define IDS_CMD_NOCRASHREPORTER 57525 +#define IDS_CMD_SLAVE 57526 +#define IDS_CMD_HWGPU 57527 +#define IDS_CMD_RESET 57528 +#define IDS_CMD_HELP 57529 +#define IDS_PPAGEADVANCED_SCORE 57530 +#define IDS_PPAGE_FS_CLN_AUDIO_DELAY 57531 +#define IDS_PPAGEADVANCED_DEFAULTTOOLBARSIZE 57532 +#define IDS_PPAGEADVANCED_USE_LEGACY_TOOLBAR 57533 +#define IDS_SUBMENU_COPYURL 57535 +#define IDS_CMD_VIEWPRESET 57536 +#define IDS_CMD_MUTE 57537 +#define IDS_CMD_VOLUME 57538 +#define IDS_YOUTUBEDL_NOT_FOUND 57539 +#define IDS_CONTROLS_YOUTUBEDL 57540 +#define IDS_VERTICAL_ALIGN_VIDEO_TOP 57541 +#define IDS_VERTICAL_ALIGN_VIDEO_MIDDLE 57542 +#define IDS_VERTICAL_ALIGN_VIDEO_BOTTOM 57543 +#define IDS_PPAGEADVANCED_USE_YDL 57544 +#define IDS_PPAGEADVANCED_YDL_MAX_HEIGHT 57545 +#define IDS_PPAGEADVANCED_YDL_VIDEO_FORMAT 57546 +#define IDS_PPAGEADVANCED_YDL_AUDIO_ONLY 57547 +#define IDS_PPAGEADVANCED_YDL_COMMAND_LINE 57548 +#define IDS_PPAGEADVANCED_SAVEIMAGE_POSITION 57549 +#define IDS_PPAGEADVANCED_SAVEIMAGE_CURRENTTIME 57550 +#define IDS_PPAGEADVANCED_ALLOW_INACCURATE_FASTSEEK 57551 +#define IDS_PPAGEADVANCED_LOOP_FOLDER_NEXT_FILE 57552 +#define IDS_PPAGEADVANCED_MODERNSEEKBAR 57553 +#define IDS_PPAGEADVANCED_MODERNSEEKBARHEIGHT 57554 +#define IDS_PPAGEADVANCED_FULLSCREEN_DELAY 57555 +#define IDS_PPAGEADVANCED_SNAPSHOTSUBTITLES 57556 +#define IDS_PPAGEADVANCED_SNAPSHOTKEEPVIDEOEXTENSION 57557 +#define IDS_PPAGEADVANCED_CRASHREPORTER 57558 +#define IDS_PRESIZE_SHADERS_ENABLED 57559 +#define IDS_PRESIZE_SHADERS_DISABLED 57560 +#define IDS_PRESIZE_SHADERS_TOGGLE 57561 +#define IDS_AG_PRESIZE_SHADERS_TOGGLE 57562 +#define IDS_POSTSIZE_SHADERS_ENABLED 57563 +#define IDS_POSTSIZE_SHADERS_DISABLED 57564 +#define IDS_POSTSIZE_SHADERS_TOGGLE 57565 +#define IDS_AG_POSTSIZE_SHADERS_TOGGLE 57566 +#define IDS_PPAGEADVANCED_TIME_REFRESH_INTERVAL 57567 +#define IDS_PPAGEADVANCED_SHOW_LANG_STATUSBAR 57568 +#define IDS_PPAGEADVANCED_SHOW_FPS_STATUSBAR 57569 +#define IDS_PPAGEADVANCED_ADD_LANGCODE_WHEN_SAVE_SUBTITLES 57570 +#define IDS_PPAGEADVANCED_USE_TITLE_IN_RECENT_FILE_LIST 57571 +#define IDS_PPAGEADVANCED_SHOW_ABMARKS_STATUSBAR 57572 +#define IDS_PPAGEADVANCED_SHOW_VIDEOINFO_STATUSBAR 57573 +#define IDS_PPAGEADVANCED_OPEN_REC_PANEL_WHEN_OPENING_DEVICE 57621 +#define IDS_PPAGEADVANCED_ALWAYS_USE_SHORT_MENU 57622 +#define IDS_PPAGEADVANCED_FULLSCREEN_SEPARATE_CONTROLS 57623 +#define IDS_PPAGEADVANCED_BLOCKRDP 57624 +#define IDS_PPAGEADVANCED_YDL_EXEPATH 57625 +#define IDS_PPAGEADVANCED_YDL_SUBS_PREFERENCE 57626 +#define IDS_PPAGEADVANCED_USE_AUTOMATIC_CAPTIONS 57627 +#define IDS_PPAGEADVANCED_USE_SMTC 57628 +#define IDS_PPAGEADVANCED_LOCK_NOPAUSE 57629 +#define IDS_PPAGEADVANCED_RELOAD_AFTER_LONG_PAUSE 57630 +#define IDS_PPAGEADVANCED_REDIRECT_OPEN_TO_APPEND_THRESHOLD 57631 +#define IDS_SUBTITLE_RENDERER_NONE 57632 +#define IDS_PPAGEADVANCED_MOUSE_LEFTUP_DELAY 57633 +#define IDS_PPAGEADVANCED_USE_FREETYPE 57634 +#define IDS_PPAGEADVANCED_USE_MEDIAINFO_LOAD_FILE_DURATION 57635 +#define IDS_TIMER_SHOW_PERCENTAGE 57636 +#define IDS_SUBDL_DLG_FAILED_DL 57637 +#define IDS_PPAGEADVANCED_FILEPOS_PLAYLIST 57638 +#define IDS_PPAGEADVANCED_FILEPOS_TRACK_SELECTION 57639 +#define IDS_PPAGEADVANCED_YDL_AUDIO_FORMAT 57640 +#define IDS_PPAGEADVANCED_PREVENT_DISPLAY_SLEEP 57641 +#define IDS_PPAGEADVANCED_STILL_VIDEO_DURATION 57642 +#define IDS_PPAGEADVANCED_CAPTURE_DEINTERLACE 57643 +#define IDS_PLAYLIST_TOGGLE_SHUFFLE 57644 +#define IDS_AUDIOSHIFT_ONOFF 57645 +#define IDS_SAVEDIALOG_INCLUDE_SUBS 57646 +#define IDS_PPAGEADVANCED_PAUSE_WHILE_DRAGGING_SEEKBAR 57647 +#define IDS_CMD_THUMBNAILS 57648 +#define IDS_PPAGEADVANCED_CONFIRM_FILE_DELETE 57649 +#define IDS_PPAGEADVANCED_LIBASS_FOR_SRT 57650 +#define IDS_CMD_AB_START 57651 +#define IDS_CMD_AB_END 57652 +#define IDS_ARS_WASAPI_MODE 57700 +#define IDS_ARS_EXCLUSIVE 57701 +#define IDS_ARS_SHARED 57702 +#define IDS_ARS_BITEXACT_OUTPUT 57703 +#define IDS_ARS_SYSTEM_LAYOUT_CHANNELS 57704 +#define IDS_ARS_SOUND_DEVICE 57705 +#define IDS_ARS_RELEASE_DEVICE_IDLE 57706 +#define IDS_ARS_CROSSFEED 57707 +#define IDS_ARS_DEVICE_PERIOD 57708 +#define IDS_ARS_ALT_CHECK_FORMAT 57709 +#define IDS_ARS_STATUS 57710 +#define IDS_ARS_DEVICE 57711 +#define IDS_ARS_MODE 57712 +#define IDS_ARS_INPUT 57713 +#define IDS_ARS_OUTPUT 57714 +#define IDS_ARS_FORMAT 57715 +#define IDS_ARS_SAMPLERATE 57716 +#define IDS_ARS_CHANNELS 57717 +#define IDS_ARS_WASAPI_METHOD 57718 +#define IDS_ARS_DUMMY_CHANNELS 57719 +#define IDS_ARS_TIP_BITEXACT_OUTPUT 57720 +#define IDS_ARS_TIP_ALT_CHECK_FORMAT 57721 +#define IDS_FILTER_RESET_SETTINGS 57722 +#define IDS_AG_DEFAULT 57723 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 20077 +#define _APS_NEXT_COMMAND_VALUE 33462 +#define _APS_NEXT_CONTROL_VALUE 22094 +#define _APS_NEXT_SYMED_VALUE 24052 +#endif +#endif diff --git a/src/mpc-hc/stdafx.cpp b/src/mpc-hc/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/mpc-hc/stdafx.cpp +++ b/src/mpc-hc/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/mpc-hc/stdafx.h b/src/mpc-hc/stdafx.h index dd818264290..a090be11bbe 100644 --- a/src/mpc-hc/stdafx.h +++ b/src/mpc-hc/stdafx.h @@ -1,89 +1,89 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#pragma once - -#define GDIPVER 0x0110 - -#include -#include // MFC core and standard components -#include // MFC extensions -#include // MFC Automation classes -#include // MFC support for Internet Explorer 4 Common Controls -#include -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Workaround compilation errors when including GDI+ with NOMINMAX defined -namespace Gdiplus -{ - using std::min; - using std::max; -}; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "sizecbar/scbarg.h" -#include "ResizableLib/ResizableDialog.h" -#include "BaseClasses/streams.h" - -#include "LcdSupport.h" - -template -class CAtlStringMap : public CAtlMap> {}; - -#define CheckAndLog(x, msg) hr = ##x; if (FAILED(hr)) { TRACE(msg _T(": 0x%08x\n"), hr); return hr; } -#define CheckNoLog(x) hr = ##x; if (FAILED(hr)) { return hr; } -#define CheckNoLogBool(x) if (FAILED(x)) { return false; } - - - -#include "DSUtil.h" -#include "mpc-hc_config.h" -#include "resource.h" +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#pragma once + +#define GDIPVER 0x0110 + +#include +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#include +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Workaround compilation errors when including GDI+ with NOMINMAX defined +namespace Gdiplus +{ + using std::min; + using std::max; +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sizecbar/scbarg.h" +#include "ResizableLib/ResizableDialog.h" +#include "BaseClasses/streams.h" + +#include "LcdSupport.h" + +template +class CAtlStringMap : public CAtlMap> {}; + +#define CheckAndLog(x, msg) hr = ##x; if (FAILED(hr)) { TRACE(msg _T(": 0x%08x\n"), hr); return hr; } +#define CheckNoLog(x) hr = ##x; if (FAILED(hr)) { return hr; } +#define CheckNoLogBool(x) if (FAILED(x)) { return false; } + + + +#include "DSUtil.h" +#include "mpc-hc_config.h" +#include "resource.h" diff --git a/src/mpc-hc/vkCodes.cpp b/src/mpc-hc/vkCodes.cpp index e4370a3ffb1..ec4d7fd9b65 100644 --- a/src/mpc-hc/vkCodes.cpp +++ b/src/mpc-hc/vkCodes.cpp @@ -1,337 +1,337 @@ -/* - * (C) 2011-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 . - * - */ - - -#include "stdafx.h" -#include "vkCodes.h" - -PCTSTR GetKeyName(UINT vkCode) -{ - ASSERT(vkCode < 256); - vkCode &= 0xff; - - static PCTSTR s_pszKeys[256] = { - _T("Unused"), - _T("Left mouse button"), - _T("Right mouse button"), - _T("Control-break"), - _T("Middle mouse button"), - _T("X1 mouse button"), - _T("X2 mouse button"), - _T("Undefined"), - _T("Backspace"), - _T("Tab"), - _T("Unknown"), - _T("Unknown"), - _T("Clear"), - _T("Enter"), - _T("Unknown"), - _T("Unknown"), - _T("Shift"), - _T("Control"), - _T("Alt"), - _T("Pause"), - _T("Caps Lock"), - _T("IME Kana mode"), - _T("Unknown"), - _T("IME Junja mode"), - _T("IME final mode"), - _T("IME Hanja mode"), - _T("Unknown"), - _T("Esc"), - _T("IME convert"), - _T("IME nonconvert"), - _T("IME accept"), - _T("IME mode change"), - _T("Space"), - _T("Page Up"), - _T("Page Down"), - _T("End"), - _T("Home"), - _T("Left Arrow"), - _T("Up Arrow"), - _T("Right Arrow"), - _T("Down Arrow"), - _T("Select"), - _T("Print"), - _T("Execute"), - _T("Print Screen"), - _T("Ins"), - _T("Del"), - _T("Help"), - _T("0"), - _T("1"), - _T("2"), - _T("3"), - _T("4"), - _T("5"), - _T("6"), - _T("7"), - _T("8"), - _T("9"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("A"), - _T("B"), - _T("C"), - _T("D"), - _T("E"), - _T("F"), - _T("G"), - _T("H"), - _T("I"), - _T("J"), - _T("K"), - _T("L"), - _T("M"), - _T("N"), - _T("O"), - _T("P"), - _T("Q"), - _T("R"), - _T("S"), - _T("T"), - _T("U"), - _T("V"), - _T("W"), - _T("X"), - _T("Y"), - _T("Z"), - _T("Left Win"), - _T("Right Win"), - _T("App"), - _T("Unknown"), - _T("Sleep"), - _T("Num 0"), - _T("Num 1"), - _T("Num 2"), - _T("Num 3"), - _T("Num 4"), - _T("Num 5"), - _T("Num 6"), - _T("Num 7"), - _T("Num 8"), - _T("Num 9"), - _T("Mul"), - _T("Add"), - _T("Separator"), - _T("Sub"), - _T("Decimal"), - _T("Div"), - _T("F1"), - _T("F2"), - _T("F3"), - _T("F4"), - _T("F5"), - _T("F6"), - _T("F7"), - _T("F8"), - _T("F9"), - _T("F10"), - _T("F11"), - _T("F12"), - _T("F13"), - _T("F14"), - _T("F15"), - _T("F16"), - _T("F17"), - _T("F18"), - _T("F19"), - _T("F20"), - _T("F21"), - _T("F22"), - _T("F23"), - _T("F24"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Num Lock"), - _T("Scroll Lock"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Left Shift"), - _T("Right Shift"), - _T("Left Control"), - _T("Right Control"), - _T("Left Alt"), - _T("Right Alt"), - _T("Browser Back"), - _T("Browser Forward"), - _T("Browser Refresh"), - _T("Browser Stop"), - _T("Browser Search"), - _T("Browser Favorites"), - _T("Browser Home"), - _T("Volume Mute"), - _T("Volume Down"), - _T("Volume Up"), - _T("Next Track"), - _T("Previous Track"), - _T("Stop Media"), - _T("Play/Pause Media"), - _T("Start Mail"), - _T("Select Media"), - _T("Start App 1"), - _T("Start App 2"), - _T("Unknown"), - _T("Unknown"), - _T(";"), - _T("="), - _T(","), - _T("_"), - _T("."), - _T("/"), - _T("`"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("["), - _T("\\"), - _T("]"), - _T("'"), - _T("OEM"), - _T("Unknown"), - _T("OEM"), - _T("<> or \\|"), - _T("OEM"), - _T("OEM"), - _T("IME Process key"), - _T("OEM"), - _T("VK_PACKET"), - _T("Unknown"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("Attn"), - _T("CrSel"), - _T("ExSel"), - _T("Erase EOF"), - _T("Play"), - _T("Zoom"), - _T("Unknown"), - _T("PA1"), - _T("Clear"), - _T("Unknown") - }; - - return s_pszKeys[vkCode]; -} - -//----------------------------------------------------------------- - -BOOL HotkeyToString(UINT vkCode, UINT fModifiers, CString& s) -{ - - s.Empty(); - if (fModifiers & MOD_CONTROL) { - s += _T("Ctrl + "); - } - if (fModifiers & MOD_ALT) { - s += _T("Alt + "); - } - if (fModifiers & MOD_SHIFT) { - s += _T("Shift + "); - } - if (vkCode) { - s += GetKeyName(vkCode); - } - - return !s.IsEmpty(); -} - -BOOL HotkeyModToString(UINT vkCode, BYTE fModifiers, CString& s) -{ - s.Empty(); - - if (fModifiers & FCONTROL) { - s += _T("Ctrl + "); - } - if (fModifiers & FALT) { - s += _T("Alt + "); - } - if (fModifiers & FSHIFT) { - s += _T("Shift + "); - } - if (vkCode) { - s += GetKeyName(vkCode); - } - - return !s.IsEmpty(); -} - -BOOL HotkeyToString(DWORD dwHk, CString& s) -{ - return HotkeyToString(LOBYTE(LOWORD(dwHk)), HIBYTE(LOWORD(dwHk)), s); -} +/* + * (C) 2011-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 . + * + */ + + +#include "stdafx.h" +#include "vkCodes.h" + +PCTSTR GetKeyName(UINT vkCode) +{ + ASSERT(vkCode < 256); + vkCode &= 0xff; + + static PCTSTR s_pszKeys[256] = { + _T("Unused"), + _T("Left mouse button"), + _T("Right mouse button"), + _T("Control-break"), + _T("Middle mouse button"), + _T("X1 mouse button"), + _T("X2 mouse button"), + _T("Undefined"), + _T("Backspace"), + _T("Tab"), + _T("Unknown"), + _T("Unknown"), + _T("Clear"), + _T("Enter"), + _T("Unknown"), + _T("Unknown"), + _T("Shift"), + _T("Control"), + _T("Alt"), + _T("Pause"), + _T("Caps Lock"), + _T("IME Kana mode"), + _T("Unknown"), + _T("IME Junja mode"), + _T("IME final mode"), + _T("IME Hanja mode"), + _T("Unknown"), + _T("Esc"), + _T("IME convert"), + _T("IME nonconvert"), + _T("IME accept"), + _T("IME mode change"), + _T("Space"), + _T("Page Up"), + _T("Page Down"), + _T("End"), + _T("Home"), + _T("Left Arrow"), + _T("Up Arrow"), + _T("Right Arrow"), + _T("Down Arrow"), + _T("Select"), + _T("Print"), + _T("Execute"), + _T("Print Screen"), + _T("Ins"), + _T("Del"), + _T("Help"), + _T("0"), + _T("1"), + _T("2"), + _T("3"), + _T("4"), + _T("5"), + _T("6"), + _T("7"), + _T("8"), + _T("9"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("A"), + _T("B"), + _T("C"), + _T("D"), + _T("E"), + _T("F"), + _T("G"), + _T("H"), + _T("I"), + _T("J"), + _T("K"), + _T("L"), + _T("M"), + _T("N"), + _T("O"), + _T("P"), + _T("Q"), + _T("R"), + _T("S"), + _T("T"), + _T("U"), + _T("V"), + _T("W"), + _T("X"), + _T("Y"), + _T("Z"), + _T("Left Win"), + _T("Right Win"), + _T("App"), + _T("Unknown"), + _T("Sleep"), + _T("Num 0"), + _T("Num 1"), + _T("Num 2"), + _T("Num 3"), + _T("Num 4"), + _T("Num 5"), + _T("Num 6"), + _T("Num 7"), + _T("Num 8"), + _T("Num 9"), + _T("Mul"), + _T("Add"), + _T("Separator"), + _T("Sub"), + _T("Decimal"), + _T("Div"), + _T("F1"), + _T("F2"), + _T("F3"), + _T("F4"), + _T("F5"), + _T("F6"), + _T("F7"), + _T("F8"), + _T("F9"), + _T("F10"), + _T("F11"), + _T("F12"), + _T("F13"), + _T("F14"), + _T("F15"), + _T("F16"), + _T("F17"), + _T("F18"), + _T("F19"), + _T("F20"), + _T("F21"), + _T("F22"), + _T("F23"), + _T("F24"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Num Lock"), + _T("Scroll Lock"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Left Shift"), + _T("Right Shift"), + _T("Left Control"), + _T("Right Control"), + _T("Left Alt"), + _T("Right Alt"), + _T("Browser Back"), + _T("Browser Forward"), + _T("Browser Refresh"), + _T("Browser Stop"), + _T("Browser Search"), + _T("Browser Favorites"), + _T("Browser Home"), + _T("Volume Mute"), + _T("Volume Down"), + _T("Volume Up"), + _T("Next Track"), + _T("Previous Track"), + _T("Stop Media"), + _T("Play/Pause Media"), + _T("Start Mail"), + _T("Select Media"), + _T("Start App 1"), + _T("Start App 2"), + _T("Unknown"), + _T("Unknown"), + _T(";"), + _T("="), + _T(","), + _T("_"), + _T("."), + _T("/"), + _T("`"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("["), + _T("\\"), + _T("]"), + _T("'"), + _T("OEM"), + _T("Unknown"), + _T("OEM"), + _T("<> or \\|"), + _T("OEM"), + _T("OEM"), + _T("IME Process key"), + _T("OEM"), + _T("VK_PACKET"), + _T("Unknown"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("Attn"), + _T("CrSel"), + _T("ExSel"), + _T("Erase EOF"), + _T("Play"), + _T("Zoom"), + _T("Unknown"), + _T("PA1"), + _T("Clear"), + _T("Unknown") + }; + + return s_pszKeys[vkCode]; +} + +//----------------------------------------------------------------- + +BOOL HotkeyToString(UINT vkCode, UINT fModifiers, CString& s) +{ + + s.Empty(); + if (fModifiers & MOD_CONTROL) { + s += _T("Ctrl + "); + } + if (fModifiers & MOD_ALT) { + s += _T("Alt + "); + } + if (fModifiers & MOD_SHIFT) { + s += _T("Shift + "); + } + if (vkCode) { + s += GetKeyName(vkCode); + } + + return !s.IsEmpty(); +} + +BOOL HotkeyModToString(UINT vkCode, BYTE fModifiers, CString& s) +{ + s.Empty(); + + if (fModifiers & FCONTROL) { + s += _T("Ctrl + "); + } + if (fModifiers & FALT) { + s += _T("Alt + "); + } + if (fModifiers & FSHIFT) { + s += _T("Shift + "); + } + if (vkCode) { + s += GetKeyName(vkCode); + } + + return !s.IsEmpty(); +} + +BOOL HotkeyToString(DWORD dwHk, CString& s) +{ + return HotkeyToString(LOBYTE(LOWORD(dwHk)), HIBYTE(LOWORD(dwHk)), s); +} diff --git a/src/mpc-hc/vkCodes.h b/src/mpc-hc/vkCodes.h index 4562c736015..216b80dd1c3 100644 --- a/src/mpc-hc/vkCodes.h +++ b/src/mpc-hc/vkCodes.h @@ -1,26 +1,26 @@ -/* - * (C) 2011-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 . - * - */ - -#pragma once - -PCTSTR GetKeyName(UINT); -BOOL HotkeyToString(UINT, UINT, CString&); -BOOL HotkeyModToString(UINT, BYTE, CString&); -BOOL HotkeyToString(DWORD, CString&); +/* + * (C) 2011-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 . + * + */ + +#pragma once + +PCTSTR GetKeyName(UINT); +BOOL HotkeyToString(UINT, UINT, CString&); +BOOL HotkeyModToString(UINT, BYTE, CString&); +BOOL HotkeyToString(DWORD, CString&); diff --git a/src/thirdparty/AsyncReader/AsyncReader.vcxproj b/src/thirdparty/AsyncReader/AsyncReader.vcxproj index 4451075cc30..508bbbb0df4 100644 --- a/src/thirdparty/AsyncReader/AsyncReader.vcxproj +++ b/src/thirdparty/AsyncReader/AsyncReader.vcxproj @@ -1,68 +1,68 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {9F31D122-E84D-485A-A58D-09DAD01A56CE} - AsyncReader - Win32Proj - AsyncReader - - - - - StaticLibrary - Unicode - - - - - - - - - - - - - ..\..\..\..\include;..;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - Create - - - - - - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {9F31D122-E84D-485A-A58D-09DAD01A56CE} + AsyncReader + Win32Proj + AsyncReader + + + + + StaticLibrary + Unicode + + + + + + + + + + + + + ..\..\..\..\include;..;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + Create + + + + + + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/thirdparty/AsyncReader/AsyncReader.vcxproj.filters b/src/thirdparty/AsyncReader/AsyncReader.vcxproj.filters index 1d92fb5a700..3ba609ca8d8 100644 --- a/src/thirdparty/AsyncReader/AsyncReader.vcxproj.filters +++ b/src/thirdparty/AsyncReader/AsyncReader.vcxproj.filters @@ -1,35 +1,35 @@ - - - - - {fa80e2e7-af1c-4fe8-8023-725cf9d0c9e8} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {f27d6e75-1d82-4d17-adcd-a9d38cc032c5} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - + + + + + {fa80e2e7-af1c-4fe8-8023-725cf9d0c9e8} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {f27d6e75-1d82-4d17-adcd-a9d38cc032c5} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/AsyncReader/asyncio.cpp b/src/thirdparty/AsyncReader/asyncio.cpp index ada6e48158f..3503b6e3111 100644 --- a/src/thirdparty/AsyncReader/asyncio.cpp +++ b/src/thirdparty/AsyncReader/asyncio.cpp @@ -1,709 +1,709 @@ -//------------------------------------------------------------------------------ -// File: AsyncIo.cpp -// -// Desc: DirectShow sample code - base library with I/O functionality. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "stdafx.h" -#include "BaseClasses/streams.h" -#include "asyncio.h" - -// --- CAsyncRequest --- - - -// implementation of CAsyncRequest representing a single -// outstanding request. All the i/o for this object is done -// in the Complete method. - - -// init the params for this request. -// Read is not issued until the complete call -HRESULT -CAsyncRequest::Request( - CAsyncIo *pIo, - CAsyncStream *pStream, - LONGLONG llPos, - LONG lLength, - BOOL bAligned, - BYTE* pBuffer, - LPVOID pContext, // filter's context - DWORD_PTR dwUser) // downstream filter's context -{ - m_pIo = pIo; - m_pStream = pStream; - m_llPos = llPos; - m_lLength = lLength; - m_bAligned = bAligned; - m_pBuffer = pBuffer; - m_pContext = pContext; - m_dwUser = dwUser; - m_hr = VFW_E_TIMEOUT; // not done yet - - return S_OK; -} - - -// issue the i/o if not overlapped, and block until i/o complete. -// returns error code of file i/o -// -// -HRESULT -CAsyncRequest::Complete() -{ - m_pStream->Lock(); - - m_hr = m_pStream->SetPointer(m_llPos); - if(S_OK == m_hr) - { - DWORD dwActual; - - m_hr = m_pStream->Read(m_pBuffer, m_lLength, m_bAligned, &dwActual); - if(m_hr == OLE_S_FIRST) - { - if(m_pContext) - { - IMediaSample *pSample = reinterpret_cast(m_pContext); - pSample->SetDiscontinuity(TRUE); - m_hr = S_OK; - } - } - - if(FAILED(m_hr)) - { - } - else if(dwActual != (DWORD)m_lLength) - { - // tell caller size changed - probably because of EOF - m_lLength = (LONG) dwActual; - m_hr = S_FALSE; - } - else - { - m_hr = S_OK; - } - } - - m_pStream->Unlock(); - return m_hr; -} - - -// --- CAsyncIo --- - -// note - all events created manual reset - -CAsyncIo::CAsyncIo(CAsyncStream *pStream) - : m_pStream(pStream), - m_bFlushing(FALSE), - m_listWork(NAME("Work list")), - m_listDone(NAME("Done list")), - m_evWork(TRUE), - m_evDone(TRUE), - m_cItemsOut(0), - m_bWaiting(FALSE), - m_evStop(TRUE), - m_hThread(NULL) -{ - -} - - -CAsyncIo::~CAsyncIo() -{ - // move everything to the done list - BeginFlush(); - - // shutdown worker thread - CloseThread(); - - // empty the done list - POSITION pos = m_listDone.GetHeadPosition(); - while(pos) - { - CAsyncRequest* pRequest = m_listDone.GetNext(pos); - delete pRequest; - } - - m_listDone.RemoveAll(); -} - - -// ready for async activity - call this before calling Request. -// -// start the worker thread if we need to -// -// !!! use overlapped i/o if possible -HRESULT -CAsyncIo::AsyncActive(void) -{ - return StartThread(); -} - -// call this when no more async activity will happen before -// the next AsyncActive call -// -// stop the worker thread if active -HRESULT -CAsyncIo::AsyncInactive(void) -{ - return CloseThread(); -} - - -// add a request to the queue. -HRESULT -CAsyncIo::Request( - LONGLONG llPos, - LONG lLength, - BOOL bAligned, - BYTE * pBuffer, - LPVOID pContext, - DWORD_PTR dwUser) -{ - if(bAligned) - { - if(!IsAligned(llPos) || - !IsAligned(lLength) || - !IsAligned((LONG_PTR) pBuffer)) - { - return VFW_E_BADALIGN; - } - } - - CAsyncRequest* pRequest = new CAsyncRequest; - if (!pRequest) - return E_OUTOFMEMORY; - - HRESULT hr = pRequest->Request(this, - m_pStream, - llPos, - lLength, - bAligned, - pBuffer, - pContext, - dwUser); - if(SUCCEEDED(hr)) - { - // might fail if flushing - hr = PutWorkItem(pRequest); - } - - if(FAILED(hr)) - { - delete pRequest; - } - - return hr; -} - - -// wait for the next request to complete -HRESULT -CAsyncIo::WaitForNext( - DWORD dwTimeout, - LPVOID * ppContext, - DWORD_PTR * pdwUser, - LONG * pcbActual) -{ - CheckPointer(ppContext,E_POINTER); - CheckPointer(pdwUser,E_POINTER); - CheckPointer(pcbActual,E_POINTER); - - // some errors find a sample, others don't. Ensure that - // *ppContext is NULL if no sample found - *ppContext = NULL; - - // wait until the event is set, but since we are not - // holding the critsec when waiting, we may need to re-wait - for(;;) - { - if(!m_evDone.Wait(dwTimeout)) - { - // timeout occurred - return VFW_E_TIMEOUT; - } - - // get next event from list - CAsyncRequest* pRequest = GetDoneItem(); - if(pRequest) - { - // found a completed request - - // check if ok - HRESULT hr = pRequest->GetHResult(); - if(hr == S_FALSE) - { - // this means the actual length was less than - // requested - may be ok if he aligned the end of file - if((pRequest->GetActualLength() + - pRequest->GetStart()) == Size()) - { - hr = S_OK; - } - else - { - // it was an actual read error - hr = E_FAIL; - } - } - - // return actual bytes read - *pcbActual = pRequest->GetActualLength(); - - // return his context - *ppContext = pRequest->GetContext(); - *pdwUser = pRequest->GetUser(); - - delete pRequest; - return hr; - } - else - { - // Hold the critical section while checking the list state - CAutoLock lck(&m_csLists); - if(m_bFlushing && !m_bWaiting) - { - // can't block as we are between BeginFlush and EndFlush - - // but note that if m_bWaiting is set, then there are some - // items not yet complete that we should block for. - - return VFW_E_WRONG_STATE; - } - } - - // done item was grabbed between completion and - // us locking m_csLists. - } -} - - -// perform a synchronous read request on this thread. -// Need to hold m_csFile while doing this (done in request object) -HRESULT -CAsyncIo::SyncReadAligned( - LONGLONG llPos, - LONG lLength, - BYTE * pBuffer, - LONG * pcbActual, - PVOID pvContext) -{ - CheckPointer(pcbActual,E_POINTER); - - if(!IsAligned(llPos) || - !IsAligned(lLength) || - !IsAligned((LONG_PTR) pBuffer)) - { - return VFW_E_BADALIGN; - } - - CAsyncRequest request; - - HRESULT hr = request.Request(this, - m_pStream, - llPos, - lLength, - TRUE, - pBuffer, - pvContext, - 0); - if(FAILED(hr)) - return hr; - - hr = request.Complete(); - - // return actual data length - *pcbActual = request.GetActualLength(); - return hr; -} - - -HRESULT -CAsyncIo::Length(LONGLONG *pllTotal, LONGLONG *pllAvailable) -{ - CheckPointer(pllTotal,E_POINTER); - - *pllTotal = m_pStream->Size(pllAvailable); - return S_OK; -} - - -// cancel all items on the worklist onto the done list -// and refuse further requests or further WaitForNext calls -// until the end flush -// -// WaitForNext must return with NULL only if there are no successful requests. -// So Flush does the following: -// 1. set m_bFlushing ensures no more requests succeed -// 2. move all items from work list to the done list. -// 3. If there are any outstanding requests, then we need to release the -// critsec to allow them to complete. The m_bWaiting as well as ensuring -// that we are signalled when they are all done is also used to indicate -// to WaitForNext that it should continue to block. -// 4. Once all outstanding requests are complete, we force m_evDone set and -// m_bFlushing set and m_bWaiting false. This ensures that WaitForNext will -// not block when the done list is empty. -HRESULT -CAsyncIo::BeginFlush() -{ - // hold the lock while emptying the work list - { - CAutoLock lock(&m_csLists); - - // prevent further requests being queued. - // Also WaitForNext will refuse to block if this is set - // unless m_bWaiting is also set which it will be when we release - // the critsec if there are any outstanding). - m_bFlushing = TRUE; - - CAsyncRequest * preq; - while((preq = GetWorkItem()) != 0) - { - preq->Cancel(); - PutDoneItem(preq); - } - - // now wait for any outstanding requests to complete - if(m_cItemsOut > 0) - { - // can be only one person waiting - ASSERT(!m_bWaiting); - - // this tells the completion routine that we need to be - // signalled via m_evAllDone when all outstanding items are - // done. It also tells WaitForNext to continue blocking. - m_bWaiting = TRUE; - } - else - { - // all done - - // force m_evDone set so that even if list is empty, - // WaitForNext will not block - // don't do this until we are sure that all - // requests are on the done list. - m_evDone.Set(); - return S_OK; - } - } - - ASSERT(m_bWaiting); - - // wait without holding critsec - for(;;) - { - m_evAllDone.Wait(); - { - // hold critsec to check - CAutoLock lock(&m_csLists); - - if(m_cItemsOut == 0) - { - // now we are sure that all outstanding requests are on - // the done list and no more will be accepted - m_bWaiting = FALSE; - - // force m_evDone set so that even if list is empty, - // WaitForNext will not block - // don't do this until we are sure that all - // requests are on the done list. - m_evDone.Set(); - - return S_OK; - } - } - } -} - - -// end a flushing state -HRESULT -CAsyncIo::EndFlush() -{ - CAutoLock lock(&m_csLists); - - m_bFlushing = FALSE; - - ASSERT(!m_bWaiting); - - // m_evDone might have been set by BeginFlush - ensure it is - // set IFF m_listDone is non-empty - if(m_listDone.GetCount() > 0) - { - m_evDone.Set(); - } - else - { - m_evDone.Reset(); - } - - return S_OK; -} - - -// start the thread -HRESULT -CAsyncIo::StartThread(void) -{ - if(m_hThread) - { - return S_OK; - } - - // clear the stop event before starting - m_evStop.Reset(); - - DWORD dwThreadID; - m_hThread = CreateThread(NULL, - 0, - InitialThreadProc, - this, - 0, - &dwThreadID); - if(!m_hThread) - { - DWORD dwErr = GetLastError(); - return HRESULT_FROM_WIN32(dwErr); - } - - return S_OK; -} - - -// stop the thread and close the handle -HRESULT -CAsyncIo::CloseThread(void) -{ - // signal the thread-exit object - m_evStop.Set(); - - if(m_hThread) - { - WaitForSingleObject(m_hThread, INFINITE); - CloseHandle(m_hThread); - m_hThread = NULL; - } - - return S_OK; -} - - -// manage the list of requests. hold m_csLists and ensure -// that the (manual reset) event hevList is set when things on -// the list but reset when the list is empty. -// returns null if list empty -CAsyncRequest* -CAsyncIo::GetWorkItem() -{ - CAutoLock lck(&m_csLists); - CAsyncRequest * preq = m_listWork.RemoveHead(); - - // force event set correctly - if(m_listWork.GetCount() == 0) - { - m_evWork.Reset(); - } - - return preq; -} - - -// get an item from the done list -CAsyncRequest* -CAsyncIo::GetDoneItem() -{ - CAutoLock lock(&m_csLists); - CAsyncRequest * preq = m_listDone.RemoveHead(); - - // force event set correctly if list now empty - // or we're in the final stages of flushing - // Note that during flushing the way it's supposed to work is that - // everything is shoved on the Done list then the application is - // supposed to pull until it gets nothing more - // - // Thus we should not set m_evDone unconditionally until everything - // has moved to the done list which means we must wait until - // cItemsOut is 0 (which is guaranteed by m_bWaiting being TRUE). - - if(m_listDone.GetCount() == 0 && - (!m_bFlushing || m_bWaiting)) - { - m_evDone.Reset(); - } - - return preq; -} - - -// put an item on the work list - fail if bFlushing -HRESULT -CAsyncIo::PutWorkItem(CAsyncRequest* pRequest) -{ - CAutoLock lock(&m_csLists); - HRESULT hr; - - if(m_bFlushing) - { - hr = VFW_E_WRONG_STATE; - } - else if(m_listWork.AddTail(pRequest)) - { - // event should now be in a set state - force this - m_evWork.Set(); - - // start the thread now if not already started - hr = StartThread(); - - } - else - { - hr = E_OUTOFMEMORY; - } - - return(hr); -} - - -// put an item on the done list - ok to do this when -// flushing -HRESULT -CAsyncIo::PutDoneItem(CAsyncRequest* pRequest) -{ - ASSERT(CritCheckIn(&m_csLists)); - - if(m_listDone.AddTail(pRequest)) - { - // event should now be in a set state - force this - m_evDone.Set(); - return S_OK; - } - else - { - return E_OUTOFMEMORY; - } -} - - -// called on thread to process any active requests -void -CAsyncIo::ProcessRequests(void) -{ - // lock to get the item and increment the outstanding count - CAsyncRequest * preq = NULL; - - for(;;) - { - { - CAutoLock lock(&m_csLists); - - preq = GetWorkItem(); - if(preq == NULL) - { - // done - return; - } - - // one more item not on the done or work list - m_cItemsOut++; - - // release critsec - } - - preq->Complete(); - - // regain critsec to replace on done list - { - CAutoLock l(&m_csLists); - - PutDoneItem(preq); - - if(--m_cItemsOut == 0) - { - if(m_bWaiting) - m_evAllDone.Set(); - } - } - } -} - - -// the thread proc - assumes that DWORD thread param is the -// this pointer -DWORD -CAsyncIo::ThreadProc(void) -{ - HANDLE ahev[] = {m_evStop, m_evWork}; - - for(;;) - { - DWORD dw = WaitForMultipleObjects(2, - ahev, - FALSE, - INFINITE); - if(dw == WAIT_OBJECT_0+1) - { - // requests need processing - ProcessRequests(); - } - else - { - // any error or stop event - we should exit - return 0; - } - } -} - - -// perform a synchronous read request on this thread. -// may not be aligned - so we will have to buffer. -HRESULT -CAsyncIo::SyncRead( - LONGLONG llPos, - LONG lLength, - BYTE * pBuffer) -{ - if(IsAligned(llPos) && - IsAligned(lLength) && - IsAligned((LONG_PTR) pBuffer)) - { - LONG cbUnused; - return SyncReadAligned(llPos, lLength, pBuffer, &cbUnused, NULL); - } - - // not aligned with requirements - use buffered file handle. - //!!! might want to fix this to buffer the data ourselves? - - CAsyncRequest request; - - HRESULT hr = request.Request(this, - m_pStream, - llPos, - lLength, - FALSE, - pBuffer, - NULL, - 0); - - if(FAILED(hr)) - { - return hr; - } - - return request.Complete(); -} - - -// Return the alignment -HRESULT -CAsyncIo::Alignment(LONG *pAlignment) -{ - CheckPointer(pAlignment,E_POINTER); - - *pAlignment = Alignment(); - return S_OK; -} - - +//------------------------------------------------------------------------------ +// File: AsyncIo.cpp +// +// Desc: DirectShow sample code - base library with I/O functionality. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "stdafx.h" +#include "BaseClasses/streams.h" +#include "asyncio.h" + +// --- CAsyncRequest --- + + +// implementation of CAsyncRequest representing a single +// outstanding request. All the i/o for this object is done +// in the Complete method. + + +// init the params for this request. +// Read is not issued until the complete call +HRESULT +CAsyncRequest::Request( + CAsyncIo *pIo, + CAsyncStream *pStream, + LONGLONG llPos, + LONG lLength, + BOOL bAligned, + BYTE* pBuffer, + LPVOID pContext, // filter's context + DWORD_PTR dwUser) // downstream filter's context +{ + m_pIo = pIo; + m_pStream = pStream; + m_llPos = llPos; + m_lLength = lLength; + m_bAligned = bAligned; + m_pBuffer = pBuffer; + m_pContext = pContext; + m_dwUser = dwUser; + m_hr = VFW_E_TIMEOUT; // not done yet + + return S_OK; +} + + +// issue the i/o if not overlapped, and block until i/o complete. +// returns error code of file i/o +// +// +HRESULT +CAsyncRequest::Complete() +{ + m_pStream->Lock(); + + m_hr = m_pStream->SetPointer(m_llPos); + if(S_OK == m_hr) + { + DWORD dwActual; + + m_hr = m_pStream->Read(m_pBuffer, m_lLength, m_bAligned, &dwActual); + if(m_hr == OLE_S_FIRST) + { + if(m_pContext) + { + IMediaSample *pSample = reinterpret_cast(m_pContext); + pSample->SetDiscontinuity(TRUE); + m_hr = S_OK; + } + } + + if(FAILED(m_hr)) + { + } + else if(dwActual != (DWORD)m_lLength) + { + // tell caller size changed - probably because of EOF + m_lLength = (LONG) dwActual; + m_hr = S_FALSE; + } + else + { + m_hr = S_OK; + } + } + + m_pStream->Unlock(); + return m_hr; +} + + +// --- CAsyncIo --- + +// note - all events created manual reset + +CAsyncIo::CAsyncIo(CAsyncStream *pStream) + : m_pStream(pStream), + m_bFlushing(FALSE), + m_listWork(NAME("Work list")), + m_listDone(NAME("Done list")), + m_evWork(TRUE), + m_evDone(TRUE), + m_cItemsOut(0), + m_bWaiting(FALSE), + m_evStop(TRUE), + m_hThread(NULL) +{ + +} + + +CAsyncIo::~CAsyncIo() +{ + // move everything to the done list + BeginFlush(); + + // shutdown worker thread + CloseThread(); + + // empty the done list + POSITION pos = m_listDone.GetHeadPosition(); + while(pos) + { + CAsyncRequest* pRequest = m_listDone.GetNext(pos); + delete pRequest; + } + + m_listDone.RemoveAll(); +} + + +// ready for async activity - call this before calling Request. +// +// start the worker thread if we need to +// +// !!! use overlapped i/o if possible +HRESULT +CAsyncIo::AsyncActive(void) +{ + return StartThread(); +} + +// call this when no more async activity will happen before +// the next AsyncActive call +// +// stop the worker thread if active +HRESULT +CAsyncIo::AsyncInactive(void) +{ + return CloseThread(); +} + + +// add a request to the queue. +HRESULT +CAsyncIo::Request( + LONGLONG llPos, + LONG lLength, + BOOL bAligned, + BYTE * pBuffer, + LPVOID pContext, + DWORD_PTR dwUser) +{ + if(bAligned) + { + if(!IsAligned(llPos) || + !IsAligned(lLength) || + !IsAligned((LONG_PTR) pBuffer)) + { + return VFW_E_BADALIGN; + } + } + + CAsyncRequest* pRequest = new CAsyncRequest; + if (!pRequest) + return E_OUTOFMEMORY; + + HRESULT hr = pRequest->Request(this, + m_pStream, + llPos, + lLength, + bAligned, + pBuffer, + pContext, + dwUser); + if(SUCCEEDED(hr)) + { + // might fail if flushing + hr = PutWorkItem(pRequest); + } + + if(FAILED(hr)) + { + delete pRequest; + } + + return hr; +} + + +// wait for the next request to complete +HRESULT +CAsyncIo::WaitForNext( + DWORD dwTimeout, + LPVOID * ppContext, + DWORD_PTR * pdwUser, + LONG * pcbActual) +{ + CheckPointer(ppContext,E_POINTER); + CheckPointer(pdwUser,E_POINTER); + CheckPointer(pcbActual,E_POINTER); + + // some errors find a sample, others don't. Ensure that + // *ppContext is NULL if no sample found + *ppContext = NULL; + + // wait until the event is set, but since we are not + // holding the critsec when waiting, we may need to re-wait + for(;;) + { + if(!m_evDone.Wait(dwTimeout)) + { + // timeout occurred + return VFW_E_TIMEOUT; + } + + // get next event from list + CAsyncRequest* pRequest = GetDoneItem(); + if(pRequest) + { + // found a completed request + + // check if ok + HRESULT hr = pRequest->GetHResult(); + if(hr == S_FALSE) + { + // this means the actual length was less than + // requested - may be ok if he aligned the end of file + if((pRequest->GetActualLength() + + pRequest->GetStart()) == Size()) + { + hr = S_OK; + } + else + { + // it was an actual read error + hr = E_FAIL; + } + } + + // return actual bytes read + *pcbActual = pRequest->GetActualLength(); + + // return his context + *ppContext = pRequest->GetContext(); + *pdwUser = pRequest->GetUser(); + + delete pRequest; + return hr; + } + else + { + // Hold the critical section while checking the list state + CAutoLock lck(&m_csLists); + if(m_bFlushing && !m_bWaiting) + { + // can't block as we are between BeginFlush and EndFlush + + // but note that if m_bWaiting is set, then there are some + // items not yet complete that we should block for. + + return VFW_E_WRONG_STATE; + } + } + + // done item was grabbed between completion and + // us locking m_csLists. + } +} + + +// perform a synchronous read request on this thread. +// Need to hold m_csFile while doing this (done in request object) +HRESULT +CAsyncIo::SyncReadAligned( + LONGLONG llPos, + LONG lLength, + BYTE * pBuffer, + LONG * pcbActual, + PVOID pvContext) +{ + CheckPointer(pcbActual,E_POINTER); + + if(!IsAligned(llPos) || + !IsAligned(lLength) || + !IsAligned((LONG_PTR) pBuffer)) + { + return VFW_E_BADALIGN; + } + + CAsyncRequest request; + + HRESULT hr = request.Request(this, + m_pStream, + llPos, + lLength, + TRUE, + pBuffer, + pvContext, + 0); + if(FAILED(hr)) + return hr; + + hr = request.Complete(); + + // return actual data length + *pcbActual = request.GetActualLength(); + return hr; +} + + +HRESULT +CAsyncIo::Length(LONGLONG *pllTotal, LONGLONG *pllAvailable) +{ + CheckPointer(pllTotal,E_POINTER); + + *pllTotal = m_pStream->Size(pllAvailable); + return S_OK; +} + + +// cancel all items on the worklist onto the done list +// and refuse further requests or further WaitForNext calls +// until the end flush +// +// WaitForNext must return with NULL only if there are no successful requests. +// So Flush does the following: +// 1. set m_bFlushing ensures no more requests succeed +// 2. move all items from work list to the done list. +// 3. If there are any outstanding requests, then we need to release the +// critsec to allow them to complete. The m_bWaiting as well as ensuring +// that we are signalled when they are all done is also used to indicate +// to WaitForNext that it should continue to block. +// 4. Once all outstanding requests are complete, we force m_evDone set and +// m_bFlushing set and m_bWaiting false. This ensures that WaitForNext will +// not block when the done list is empty. +HRESULT +CAsyncIo::BeginFlush() +{ + // hold the lock while emptying the work list + { + CAutoLock lock(&m_csLists); + + // prevent further requests being queued. + // Also WaitForNext will refuse to block if this is set + // unless m_bWaiting is also set which it will be when we release + // the critsec if there are any outstanding). + m_bFlushing = TRUE; + + CAsyncRequest * preq; + while((preq = GetWorkItem()) != 0) + { + preq->Cancel(); + PutDoneItem(preq); + } + + // now wait for any outstanding requests to complete + if(m_cItemsOut > 0) + { + // can be only one person waiting + ASSERT(!m_bWaiting); + + // this tells the completion routine that we need to be + // signalled via m_evAllDone when all outstanding items are + // done. It also tells WaitForNext to continue blocking. + m_bWaiting = TRUE; + } + else + { + // all done + + // force m_evDone set so that even if list is empty, + // WaitForNext will not block + // don't do this until we are sure that all + // requests are on the done list. + m_evDone.Set(); + return S_OK; + } + } + + ASSERT(m_bWaiting); + + // wait without holding critsec + for(;;) + { + m_evAllDone.Wait(); + { + // hold critsec to check + CAutoLock lock(&m_csLists); + + if(m_cItemsOut == 0) + { + // now we are sure that all outstanding requests are on + // the done list and no more will be accepted + m_bWaiting = FALSE; + + // force m_evDone set so that even if list is empty, + // WaitForNext will not block + // don't do this until we are sure that all + // requests are on the done list. + m_evDone.Set(); + + return S_OK; + } + } + } +} + + +// end a flushing state +HRESULT +CAsyncIo::EndFlush() +{ + CAutoLock lock(&m_csLists); + + m_bFlushing = FALSE; + + ASSERT(!m_bWaiting); + + // m_evDone might have been set by BeginFlush - ensure it is + // set IFF m_listDone is non-empty + if(m_listDone.GetCount() > 0) + { + m_evDone.Set(); + } + else + { + m_evDone.Reset(); + } + + return S_OK; +} + + +// start the thread +HRESULT +CAsyncIo::StartThread(void) +{ + if(m_hThread) + { + return S_OK; + } + + // clear the stop event before starting + m_evStop.Reset(); + + DWORD dwThreadID; + m_hThread = CreateThread(NULL, + 0, + InitialThreadProc, + this, + 0, + &dwThreadID); + if(!m_hThread) + { + DWORD dwErr = GetLastError(); + return HRESULT_FROM_WIN32(dwErr); + } + + return S_OK; +} + + +// stop the thread and close the handle +HRESULT +CAsyncIo::CloseThread(void) +{ + // signal the thread-exit object + m_evStop.Set(); + + if(m_hThread) + { + WaitForSingleObject(m_hThread, INFINITE); + CloseHandle(m_hThread); + m_hThread = NULL; + } + + return S_OK; +} + + +// manage the list of requests. hold m_csLists and ensure +// that the (manual reset) event hevList is set when things on +// the list but reset when the list is empty. +// returns null if list empty +CAsyncRequest* +CAsyncIo::GetWorkItem() +{ + CAutoLock lck(&m_csLists); + CAsyncRequest * preq = m_listWork.RemoveHead(); + + // force event set correctly + if(m_listWork.GetCount() == 0) + { + m_evWork.Reset(); + } + + return preq; +} + + +// get an item from the done list +CAsyncRequest* +CAsyncIo::GetDoneItem() +{ + CAutoLock lock(&m_csLists); + CAsyncRequest * preq = m_listDone.RemoveHead(); + + // force event set correctly if list now empty + // or we're in the final stages of flushing + // Note that during flushing the way it's supposed to work is that + // everything is shoved on the Done list then the application is + // supposed to pull until it gets nothing more + // + // Thus we should not set m_evDone unconditionally until everything + // has moved to the done list which means we must wait until + // cItemsOut is 0 (which is guaranteed by m_bWaiting being TRUE). + + if(m_listDone.GetCount() == 0 && + (!m_bFlushing || m_bWaiting)) + { + m_evDone.Reset(); + } + + return preq; +} + + +// put an item on the work list - fail if bFlushing +HRESULT +CAsyncIo::PutWorkItem(CAsyncRequest* pRequest) +{ + CAutoLock lock(&m_csLists); + HRESULT hr; + + if(m_bFlushing) + { + hr = VFW_E_WRONG_STATE; + } + else if(m_listWork.AddTail(pRequest)) + { + // event should now be in a set state - force this + m_evWork.Set(); + + // start the thread now if not already started + hr = StartThread(); + + } + else + { + hr = E_OUTOFMEMORY; + } + + return(hr); +} + + +// put an item on the done list - ok to do this when +// flushing +HRESULT +CAsyncIo::PutDoneItem(CAsyncRequest* pRequest) +{ + ASSERT(CritCheckIn(&m_csLists)); + + if(m_listDone.AddTail(pRequest)) + { + // event should now be in a set state - force this + m_evDone.Set(); + return S_OK; + } + else + { + return E_OUTOFMEMORY; + } +} + + +// called on thread to process any active requests +void +CAsyncIo::ProcessRequests(void) +{ + // lock to get the item and increment the outstanding count + CAsyncRequest * preq = NULL; + + for(;;) + { + { + CAutoLock lock(&m_csLists); + + preq = GetWorkItem(); + if(preq == NULL) + { + // done + return; + } + + // one more item not on the done or work list + m_cItemsOut++; + + // release critsec + } + + preq->Complete(); + + // regain critsec to replace on done list + { + CAutoLock l(&m_csLists); + + PutDoneItem(preq); + + if(--m_cItemsOut == 0) + { + if(m_bWaiting) + m_evAllDone.Set(); + } + } + } +} + + +// the thread proc - assumes that DWORD thread param is the +// this pointer +DWORD +CAsyncIo::ThreadProc(void) +{ + HANDLE ahev[] = {m_evStop, m_evWork}; + + for(;;) + { + DWORD dw = WaitForMultipleObjects(2, + ahev, + FALSE, + INFINITE); + if(dw == WAIT_OBJECT_0+1) + { + // requests need processing + ProcessRequests(); + } + else + { + // any error or stop event - we should exit + return 0; + } + } +} + + +// perform a synchronous read request on this thread. +// may not be aligned - so we will have to buffer. +HRESULT +CAsyncIo::SyncRead( + LONGLONG llPos, + LONG lLength, + BYTE * pBuffer) +{ + if(IsAligned(llPos) && + IsAligned(lLength) && + IsAligned((LONG_PTR) pBuffer)) + { + LONG cbUnused; + return SyncReadAligned(llPos, lLength, pBuffer, &cbUnused, NULL); + } + + // not aligned with requirements - use buffered file handle. + //!!! might want to fix this to buffer the data ourselves? + + CAsyncRequest request; + + HRESULT hr = request.Request(this, + m_pStream, + llPos, + lLength, + FALSE, + pBuffer, + NULL, + 0); + + if(FAILED(hr)) + { + return hr; + } + + return request.Complete(); +} + + +// Return the alignment +HRESULT +CAsyncIo::Alignment(LONG *pAlignment) +{ + CheckPointer(pAlignment,E_POINTER); + + *pAlignment = Alignment(); + return S_OK; +} + + diff --git a/src/thirdparty/AsyncReader/asyncio.h b/src/thirdparty/AsyncReader/asyncio.h index 7cdc58de91e..8fc56200284 100644 --- a/src/thirdparty/AsyncReader/asyncio.h +++ b/src/thirdparty/AsyncReader/asyncio.h @@ -1,280 +1,280 @@ -//------------------------------------------------------------------------------ -// File: AsyncIo.h -// -// Desc: DirectShow sample code - base library for I/O functionality. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __ASYNCIO_H__ -#define __ASYNCIO_H__ - -// -// definition of CAsyncFile object that performs file access. It provides -// asynchronous, unbuffered, aligned reads from a file, using a worker thread -// on win95 and potentially overlapped i/o if available. - -// !!! Need to use real overlapped i/o if available -// currently only uses worker thread, not overlapped i/o - - -class CAsyncIo; -class CAsyncStream; - -// -// Model the stream we read from based on a file-like interface -// -class CAsyncStream -{ -public: - virtual ~CAsyncStream() {}; - virtual HRESULT SetPointer(LONGLONG llPos) = 0; - virtual HRESULT Read(PBYTE pbBuffer, - DWORD dwBytesToRead, - BOOL bAlign, - LPDWORD pdwBytesRead) = 0; - - virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0; - virtual DWORD Alignment() = 0; - virtual void Lock() = 0; - virtual void Unlock() = 0; - //virtual void SetStopHandle(HANDLE hevStop) {} -}; - -// represents a single request and performs the i/o. Can be called on either -// worker thread or app thread, but must hold pcsFile across file accesses. -// (ie across SetFilePointer/ReadFile pairs) -class CAsyncRequest -{ - CAsyncIo *m_pIo; - CAsyncStream *m_pStream; - LONGLONG m_llPos; - BOOL m_bAligned; - LONG m_lLength; - BYTE* m_pBuffer; - LPVOID m_pContext; - DWORD_PTR m_dwUser; - HRESULT m_hr; - -public: - // init the params for this request. Issue the i/o - // if overlapped i/o is possible. - HRESULT Request( - CAsyncIo *pIo, - CAsyncStream *pStream, - LONGLONG llPos, - LONG lLength, - BOOL bAligned, - BYTE* pBuffer, - LPVOID pContext, // filter's context - DWORD_PTR dwUser); // downstream filter's context - - // issue the i/o if not overlapped, and block until i/o complete. - // returns error code of file i/o - HRESULT Complete(); - - // cancels the i/o. blocks until i/o is no longer pending - HRESULT Cancel() - { - return S_OK; - }; - - // accessor functions - LPVOID GetContext() - { - return m_pContext; - }; - - DWORD_PTR GetUser() - { - return m_dwUser; - }; - - HRESULT GetHResult() { - return m_hr; - }; - - // we set m_lLength to the actual length - LONG GetActualLength() { - return m_lLength; - }; - - LONGLONG GetStart() { - return m_llPos; - }; -}; - - -typedef CGenericList CRequestList; - -// this class needs a worker thread, but the ones defined in classes\base -// are not suitable (they assume you have one message sent or posted per -// request, whereas here for efficiency we want just to set an event when -// there is work on the queue). -// -// we create CAsyncRequest objects and queue them on m_listWork. The worker -// thread pulls them off, completes them and puts them on m_listDone. -// The events m_evWork and m_evDone are set when the corresponding lists are -// not empty. -// -// Synchronous requests are done on the caller thread. These should be -// synchronised by the caller, but to make sure we hold m_csFile across -// the SetFilePointer/ReadFile code. -// -// Flush by calling BeginFlush. This rejects all further requests (by -// setting m_bFlushing within m_csLists), cancels all requests and moves them -// to the done list, and sets m_evDone to ensure that no WaitForNext operations -// will block. Call EndFlush to cancel this state. -// -// we support unaligned calls to SyncRead. This is done by opening the file -// twice if we are using unbuffered i/o (m_dwAlign > 1). -// !!!fix this to buffer on top of existing file handle? -class CAsyncIo -{ - - CCritSec m_csReader; - CAsyncStream *m_pStream; - - CCritSec m_csLists; // locks access to the list and events - BOOL m_bFlushing; // true if between BeginFlush/EndFlush - - CRequestList m_listWork; - CRequestList m_listDone; - - CAMEvent m_evWork; // set when list is not empty - CAMEvent m_evDone; - - // for correct flush behaviour: all protected by m_csLists - LONG m_cItemsOut; // nr of items not on listDone or listWork - BOOL m_bWaiting; // TRUE if someone waiting for m_evAllDone - CAMEvent m_evAllDone; // signal when m_cItemsOut goes to 0 if m_cWaiting - - - CAMEvent m_evStop; // set when thread should exit - HANDLE m_hThread; - - LONGLONG Size() { - ASSERT(m_pStream != NULL); - return m_pStream->Size(); - }; - - // start the thread - HRESULT StartThread(void); - - // stop the thread and close the handle - HRESULT CloseThread(void); - - // manage the list of requests. hold m_csLists and ensure - // that the (manual reset) event hevList is set when things on - // the list but reset when the list is empty. - // returns null if list empty - CAsyncRequest* GetWorkItem(); - - // get an item from the done list - CAsyncRequest* GetDoneItem(); - - // put an item on the work list - HRESULT PutWorkItem(CAsyncRequest* pRequest); - - // put an item on the done list - HRESULT PutDoneItem(CAsyncRequest* pRequest); - - // called on thread to process any active requests - void ProcessRequests(void); - - // initial static thread proc calls ThreadProc with DWORD - // param as this - static DWORD WINAPI InitialThreadProc(LPVOID pv) { - CAsyncIo * pThis = (CAsyncIo*) pv; - return pThis->ThreadProc(); - }; - - DWORD ThreadProc(void); - -public: - - CAsyncIo(CAsyncStream *pStream); - ~CAsyncIo(); - - // open the file - HRESULT Open(LPCTSTR pName); - - // ready for async activity - call this before - // calling Request - HRESULT AsyncActive(void); - - // call this when no more async activity will happen before - // the next AsyncActive call - HRESULT AsyncInactive(void); - - // queue a requested read. must be aligned. - HRESULT Request( - LONGLONG llPos, - LONG lLength, - BOOL bAligned, - BYTE* pBuffer, - LPVOID pContext, - DWORD_PTR dwUser); - - // wait for the next read to complete - HRESULT WaitForNext( - DWORD dwTimeout, - LPVOID *ppContext, - DWORD_PTR * pdwUser, - LONG * pcbActual); - - // perform a read of an already aligned buffer - HRESULT SyncReadAligned( - LONGLONG llPos, - LONG lLength, - BYTE* pBuffer, - LONG* pcbActual, - PVOID pvContext); - - // perform a synchronous read. will be buffered - // if not aligned. - HRESULT SyncRead( - LONGLONG llPos, - LONG lLength, - BYTE* pBuffer); - - // return length - HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable); - - // all Reader positions, read lengths and memory locations must - // be aligned to this. - HRESULT Alignment(LONG* pl); - - HRESULT BeginFlush(); - HRESULT EndFlush(); - - LONG Alignment() - { - return m_pStream->Alignment(); - }; - - BOOL IsAligned(LONG_PTR l) - { - // LONG_PTR is long on 32-bit or __int64 on 64-bit. - if ( (static_cast(l & 0xffffffff) & (Alignment() -1)) == 0 ) - { - return TRUE; - } - else - { - return FALSE; - } - }; - -#ifndef _WIN64 - BOOL IsAligned(LONGLONG ll) { - return IsAligned( (LONG) (ll & 0xffffffff)); - }; -#endif - - // Accessor - HANDLE StopEvent() const { return m_evDone; } -}; - -#endif // __ASYNCIO_H__ +//------------------------------------------------------------------------------ +// File: AsyncIo.h +// +// Desc: DirectShow sample code - base library for I/O functionality. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __ASYNCIO_H__ +#define __ASYNCIO_H__ + +// +// definition of CAsyncFile object that performs file access. It provides +// asynchronous, unbuffered, aligned reads from a file, using a worker thread +// on win95 and potentially overlapped i/o if available. + +// !!! Need to use real overlapped i/o if available +// currently only uses worker thread, not overlapped i/o + + +class CAsyncIo; +class CAsyncStream; + +// +// Model the stream we read from based on a file-like interface +// +class CAsyncStream +{ +public: + virtual ~CAsyncStream() {}; + virtual HRESULT SetPointer(LONGLONG llPos) = 0; + virtual HRESULT Read(PBYTE pbBuffer, + DWORD dwBytesToRead, + BOOL bAlign, + LPDWORD pdwBytesRead) = 0; + + virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0; + virtual DWORD Alignment() = 0; + virtual void Lock() = 0; + virtual void Unlock() = 0; + //virtual void SetStopHandle(HANDLE hevStop) {} +}; + +// represents a single request and performs the i/o. Can be called on either +// worker thread or app thread, but must hold pcsFile across file accesses. +// (ie across SetFilePointer/ReadFile pairs) +class CAsyncRequest +{ + CAsyncIo *m_pIo; + CAsyncStream *m_pStream; + LONGLONG m_llPos; + BOOL m_bAligned; + LONG m_lLength; + BYTE* m_pBuffer; + LPVOID m_pContext; + DWORD_PTR m_dwUser; + HRESULT m_hr; + +public: + // init the params for this request. Issue the i/o + // if overlapped i/o is possible. + HRESULT Request( + CAsyncIo *pIo, + CAsyncStream *pStream, + LONGLONG llPos, + LONG lLength, + BOOL bAligned, + BYTE* pBuffer, + LPVOID pContext, // filter's context + DWORD_PTR dwUser); // downstream filter's context + + // issue the i/o if not overlapped, and block until i/o complete. + // returns error code of file i/o + HRESULT Complete(); + + // cancels the i/o. blocks until i/o is no longer pending + HRESULT Cancel() + { + return S_OK; + }; + + // accessor functions + LPVOID GetContext() + { + return m_pContext; + }; + + DWORD_PTR GetUser() + { + return m_dwUser; + }; + + HRESULT GetHResult() { + return m_hr; + }; + + // we set m_lLength to the actual length + LONG GetActualLength() { + return m_lLength; + }; + + LONGLONG GetStart() { + return m_llPos; + }; +}; + + +typedef CGenericList CRequestList; + +// this class needs a worker thread, but the ones defined in classes\base +// are not suitable (they assume you have one message sent or posted per +// request, whereas here for efficiency we want just to set an event when +// there is work on the queue). +// +// we create CAsyncRequest objects and queue them on m_listWork. The worker +// thread pulls them off, completes them and puts them on m_listDone. +// The events m_evWork and m_evDone are set when the corresponding lists are +// not empty. +// +// Synchronous requests are done on the caller thread. These should be +// synchronised by the caller, but to make sure we hold m_csFile across +// the SetFilePointer/ReadFile code. +// +// Flush by calling BeginFlush. This rejects all further requests (by +// setting m_bFlushing within m_csLists), cancels all requests and moves them +// to the done list, and sets m_evDone to ensure that no WaitForNext operations +// will block. Call EndFlush to cancel this state. +// +// we support unaligned calls to SyncRead. This is done by opening the file +// twice if we are using unbuffered i/o (m_dwAlign > 1). +// !!!fix this to buffer on top of existing file handle? +class CAsyncIo +{ + + CCritSec m_csReader; + CAsyncStream *m_pStream; + + CCritSec m_csLists; // locks access to the list and events + BOOL m_bFlushing; // true if between BeginFlush/EndFlush + + CRequestList m_listWork; + CRequestList m_listDone; + + CAMEvent m_evWork; // set when list is not empty + CAMEvent m_evDone; + + // for correct flush behaviour: all protected by m_csLists + LONG m_cItemsOut; // nr of items not on listDone or listWork + BOOL m_bWaiting; // TRUE if someone waiting for m_evAllDone + CAMEvent m_evAllDone; // signal when m_cItemsOut goes to 0 if m_cWaiting + + + CAMEvent m_evStop; // set when thread should exit + HANDLE m_hThread; + + LONGLONG Size() { + ASSERT(m_pStream != NULL); + return m_pStream->Size(); + }; + + // start the thread + HRESULT StartThread(void); + + // stop the thread and close the handle + HRESULT CloseThread(void); + + // manage the list of requests. hold m_csLists and ensure + // that the (manual reset) event hevList is set when things on + // the list but reset when the list is empty. + // returns null if list empty + CAsyncRequest* GetWorkItem(); + + // get an item from the done list + CAsyncRequest* GetDoneItem(); + + // put an item on the work list + HRESULT PutWorkItem(CAsyncRequest* pRequest); + + // put an item on the done list + HRESULT PutDoneItem(CAsyncRequest* pRequest); + + // called on thread to process any active requests + void ProcessRequests(void); + + // initial static thread proc calls ThreadProc with DWORD + // param as this + static DWORD WINAPI InitialThreadProc(LPVOID pv) { + CAsyncIo * pThis = (CAsyncIo*) pv; + return pThis->ThreadProc(); + }; + + DWORD ThreadProc(void); + +public: + + CAsyncIo(CAsyncStream *pStream); + ~CAsyncIo(); + + // open the file + HRESULT Open(LPCTSTR pName); + + // ready for async activity - call this before + // calling Request + HRESULT AsyncActive(void); + + // call this when no more async activity will happen before + // the next AsyncActive call + HRESULT AsyncInactive(void); + + // queue a requested read. must be aligned. + HRESULT Request( + LONGLONG llPos, + LONG lLength, + BOOL bAligned, + BYTE* pBuffer, + LPVOID pContext, + DWORD_PTR dwUser); + + // wait for the next read to complete + HRESULT WaitForNext( + DWORD dwTimeout, + LPVOID *ppContext, + DWORD_PTR * pdwUser, + LONG * pcbActual); + + // perform a read of an already aligned buffer + HRESULT SyncReadAligned( + LONGLONG llPos, + LONG lLength, + BYTE* pBuffer, + LONG* pcbActual, + PVOID pvContext); + + // perform a synchronous read. will be buffered + // if not aligned. + HRESULT SyncRead( + LONGLONG llPos, + LONG lLength, + BYTE* pBuffer); + + // return length + HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable); + + // all Reader positions, read lengths and memory locations must + // be aligned to this. + HRESULT Alignment(LONG* pl); + + HRESULT BeginFlush(); + HRESULT EndFlush(); + + LONG Alignment() + { + return m_pStream->Alignment(); + }; + + BOOL IsAligned(LONG_PTR l) + { + // LONG_PTR is long on 32-bit or __int64 on 64-bit. + if ( (static_cast(l & 0xffffffff) & (Alignment() -1)) == 0 ) + { + return TRUE; + } + else + { + return FALSE; + } + }; + +#ifndef _WIN64 + BOOL IsAligned(LONGLONG ll) { + return IsAligned( (LONG) (ll & 0xffffffff)); + }; +#endif + + // Accessor + HANDLE StopEvent() const { return m_evDone; } +}; + +#endif // __ASYNCIO_H__ diff --git a/src/thirdparty/AsyncReader/asyncrdr.cpp b/src/thirdparty/AsyncReader/asyncrdr.cpp index 3213ba4e50c..524afe52b1f 100644 --- a/src/thirdparty/AsyncReader/asyncrdr.cpp +++ b/src/thirdparty/AsyncReader/asyncrdr.cpp @@ -1,454 +1,454 @@ -//------------------------------------------------------------------------------ -// File: AsyncRdr.cpp -// -// Desc: DirectShow sample code - base library with I/O functionality. -// This file implements I/O source filter methods and output pin -// methods for CAsyncReader and CAsyncOutputPin. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "stdafx.h" -#include "BaseClasses/streams.h" -#include "asyncio.h" -#include "asyncrdr.h" - -// --- CAsyncOutputPin implementation --- - -CAsyncOutputPin::CAsyncOutputPin( - HRESULT * phr, - CAsyncReader *pReader, - CAsyncIo *pIo, - CCritSec * pLock) - : CBasePin( - NAME("Async output pin"), - pReader, - pLock, - phr, - L"Output", - PINDIR_OUTPUT), - m_pReader(pReader), - m_pIo(pIo), - m_bQueriedForAsyncReader(FALSE) -{ -} - -CAsyncOutputPin::~CAsyncOutputPin() -{ -} - - -STDMETHODIMP CAsyncOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv,E_POINTER); - - if(riid == IID_IAsyncReader) - { - m_bQueriedForAsyncReader = TRUE; - return GetInterface((IAsyncReader*) this, ppv); - } - else - { - return CBasePin::NonDelegatingQueryInterface(riid, ppv); - } -} - - -HRESULT CAsyncOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType) -{ - if(iPosition < 0) - { - return E_INVALIDARG; - } - if(iPosition > 0) - { - return VFW_S_NO_MORE_ITEMS; - } - - CheckPointer(pMediaType,E_POINTER); - CheckPointer(m_pReader,E_UNEXPECTED); - - *pMediaType = *m_pReader->LoadType(); - - return S_OK; -} - - -HRESULT CAsyncOutputPin::CheckMediaType(const CMediaType* pType) -{ - CAutoLock lck(m_pLock); - - /* We treat MEDIASUBTYPE_NULL subtype as a wild card */ - if((m_pReader->LoadType()->majortype == pType->majortype) && - (m_pReader->LoadType()->subtype == MEDIASUBTYPE_NULL || - m_pReader->LoadType()->subtype == pType->subtype)) - { - return S_OK; - } - - return S_FALSE; -} - - -HRESULT CAsyncOutputPin::InitAllocator(IMemAllocator **ppAlloc) -{ - CheckPointer(ppAlloc,E_POINTER); - - HRESULT hr = NOERROR; - CMemAllocator *pMemObject = NULL; - - *ppAlloc = NULL; - - /* Create a default memory allocator */ - pMemObject = new CMemAllocator(NAME("Base memory allocator"), NULL, &hr); - if(pMemObject == NULL) - { - return E_OUTOFMEMORY; - } - if(FAILED(hr)) - { - delete pMemObject; - return hr; - } - - /* Get a reference counted IID_IMemAllocator interface */ - hr = pMemObject->QueryInterface(IID_IMemAllocator,(void **)ppAlloc); - if(FAILED(hr)) - { - delete pMemObject; - return E_NOINTERFACE; - } - - ASSERT(*ppAlloc != NULL); - return NOERROR; -} - - -// we need to return an addrefed allocator, even if it is the preferred -// one, since he doesn't know whether it is the preferred one or not. -STDMETHODIMP -CAsyncOutputPin::RequestAllocator( - IMemAllocator* pPreferred, - ALLOCATOR_PROPERTIES* pProps, - IMemAllocator ** ppActual) -{ - CheckPointer(pPreferred,E_POINTER); - CheckPointer(pProps,E_POINTER); - CheckPointer(ppActual,E_POINTER); - ASSERT(m_pIo); - - // we care about alignment but nothing else - if(!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign)) - { - m_pIo->Alignment(&pProps->cbAlign); - } - - ALLOCATOR_PROPERTIES Actual; - HRESULT hr; - - if(pPreferred) - { - hr = pPreferred->SetProperties(pProps, &Actual); - - if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) - { - pPreferred->AddRef(); - *ppActual = pPreferred; - return S_OK; - } - } - - // create our own allocator - IMemAllocator* pAlloc; - hr = InitAllocator(&pAlloc); - if(FAILED(hr)) - { - return hr; - } - - //...and see if we can make it suitable - hr = pAlloc->SetProperties(pProps, &Actual); - if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) - { - // we need to release our refcount on pAlloc, and addref - // it to pass a refcount to the caller - this is a net nothing. - *ppActual = pAlloc; - return S_OK; - } - - // failed to find a suitable allocator - pAlloc->Release(); - - // if we failed because of the IsAligned test, the error code will - // not be failure - if(SUCCEEDED(hr)) - { - hr = VFW_E_BADALIGN; - } - return hr; -} - - -// queue an aligned read request. call WaitForNext to get -// completion. -STDMETHODIMP CAsyncOutputPin::Request( - IMediaSample* pSample, - DWORD_PTR dwUser) // user context -{ - CheckPointer(pSample,E_POINTER); - - REFERENCE_TIME tStart, tStop; - HRESULT hr = pSample->GetTime(&tStart, &tStop); - if(FAILED(hr)) - { - return hr; - } - - LONGLONG llPos = tStart / UNITS; - LONG lLength = (LONG) ((tStop - tStart) / UNITS); - - LONGLONG llTotal=0, llAvailable=0; - - hr = m_pIo->Length(&llTotal, &llAvailable); - if(llPos + lLength > llTotal) - { - // the end needs to be aligned, but may have been aligned - // on a coarser alignment. - LONG lAlign; - m_pIo->Alignment(&lAlign); - - llTotal = (llTotal + lAlign -1) & ~(lAlign-1); - - if(llPos + lLength > llTotal) - { - lLength = (LONG) (llTotal - llPos); - - // must be reducing this! - ASSERT((llTotal * UNITS) <= tStop); - tStop = llTotal * UNITS; - pSample->SetTime(&tStart, &tStop); - } - } - - BYTE* pBuffer; - hr = pSample->GetPointer(&pBuffer); - if(FAILED(hr)) - { - return hr; - } - - return m_pIo->Request(llPos, - lLength, - TRUE, - pBuffer, - (LPVOID)pSample, - dwUser); -} - - -// sync-aligned request. just like a request/waitfornext pair. -STDMETHODIMP -CAsyncOutputPin::SyncReadAligned( - IMediaSample* pSample) -{ - CheckPointer(pSample,E_POINTER); - - REFERENCE_TIME tStart, tStop; - HRESULT hr = pSample->GetTime(&tStart, &tStop); - if(FAILED(hr)) - { - return hr; - } - - LONGLONG llPos = tStart / UNITS; - LONG lLength = (LONG) ((tStop - tStart) / UNITS); - - LONGLONG llTotal; - LONGLONG llAvailable; - - hr = m_pIo->Length(&llTotal, &llAvailable); - if(llPos + lLength > llTotal) - { - // the end needs to be aligned, but may have been aligned - // on a coarser alignment. - LONG lAlign; - m_pIo->Alignment(&lAlign); - - llTotal = (llTotal + lAlign -1) & ~(lAlign-1); - - if(llPos + lLength > llTotal) - { - lLength = (LONG) (llTotal - llPos); - - // must be reducing this! - ASSERT((llTotal * UNITS) <= tStop); - tStop = llTotal * UNITS; - pSample->SetTime(&tStart, &tStop); - } - } - - BYTE* pBuffer; - hr = pSample->GetPointer(&pBuffer); - if(FAILED(hr)) - { - return hr; - } - - LONG cbActual; - hr = m_pIo->SyncReadAligned(llPos, - lLength, - pBuffer, - &cbActual, - pSample); - - pSample->SetActualDataLength(cbActual); - return hr; -} - - -// -// collect the next ready sample -STDMETHODIMP -CAsyncOutputPin::WaitForNext( - DWORD dwTimeout, - IMediaSample** ppSample, // completed sample - DWORD_PTR * pdwUser) // user context -{ - CheckPointer(ppSample,E_POINTER); - - LONG cbActual; - IMediaSample* pSample=0; - - HRESULT hr = m_pIo->WaitForNext(dwTimeout, - (LPVOID*) &pSample, - pdwUser, - &cbActual); - - if(SUCCEEDED(hr)) - { - pSample->SetActualDataLength(cbActual); - } - - *ppSample = pSample; - return hr; -} - - -// -// synchronous read that need not be aligned. -STDMETHODIMP -CAsyncOutputPin::SyncRead( - LONGLONG llPosition, // absolute Io position - LONG lLength, // nr bytes required - BYTE* pBuffer) // write data here -{ - return m_pIo->SyncRead(llPosition, lLength, pBuffer); -} - - -// return the length of the file, and the length currently -// available locally. We only support locally accessible files, -// so they are always the same -STDMETHODIMP -CAsyncOutputPin::Length( - LONGLONG* pTotal, - LONGLONG* pAvailable) -{ - return m_pIo->Length(pTotal, pAvailable); -} - - -STDMETHODIMP -CAsyncOutputPin::BeginFlush(void) -{ - return m_pIo->BeginFlush(); -} - - -STDMETHODIMP -CAsyncOutputPin::EndFlush(void) -{ - return m_pIo->EndFlush(); -} - - -STDMETHODIMP -CAsyncOutputPin::Connect( - IPin * pReceivePin, - const AM_MEDIA_TYPE *pmt // optional media type -) -{ - return m_pReader->Connect(pReceivePin, pmt); -} - - - -// --- CAsyncReader implementation --- - -#pragma warning(disable:4355) - -CAsyncReader::CAsyncReader( - LPCTSTR pName, - LPUNKNOWN pUnk, - CAsyncStream *pStream, - HRESULT *phr, - const CLSID& clsid) // MPC-HC patch - : CBaseFilter( - pName, - pUnk, - &m_csFilter, - clsid, // MPC-HC patch - NULL - ), - m_Io(pStream), - m_OutputPin( - phr, - this, - &m_Io, - &m_csFilter) - -{ -} - -CAsyncReader::~CAsyncReader() -{ -} - -// MPC-HC patch start -STDMETHODIMP CAsyncReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - (riid == __uuidof(IAMFilterMiscFlags)) ? GetInterface((IAMFilterMiscFlags*)this, ppv) : - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IAMFilterMiscFlags - -ULONG CAsyncReader::GetMiscFlags() -{ - return AM_FILTER_MISC_FLAGS_IS_SOURCE; -} -// MPC-HC patch end - -int CAsyncReader::GetPinCount() -{ - return 1; -} - -CBasePin * CAsyncReader::GetPin(int n) -{ - if((GetPinCount() > 0) && (n == 0)) - { - return &m_OutputPin; - } - else - { - return NULL; - } -} - - - +//------------------------------------------------------------------------------ +// File: AsyncRdr.cpp +// +// Desc: DirectShow sample code - base library with I/O functionality. +// This file implements I/O source filter methods and output pin +// methods for CAsyncReader and CAsyncOutputPin. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "stdafx.h" +#include "BaseClasses/streams.h" +#include "asyncio.h" +#include "asyncrdr.h" + +// --- CAsyncOutputPin implementation --- + +CAsyncOutputPin::CAsyncOutputPin( + HRESULT * phr, + CAsyncReader *pReader, + CAsyncIo *pIo, + CCritSec * pLock) + : CBasePin( + NAME("Async output pin"), + pReader, + pLock, + phr, + L"Output", + PINDIR_OUTPUT), + m_pReader(pReader), + m_pIo(pIo), + m_bQueriedForAsyncReader(FALSE) +{ +} + +CAsyncOutputPin::~CAsyncOutputPin() +{ +} + + +STDMETHODIMP CAsyncOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv,E_POINTER); + + if(riid == IID_IAsyncReader) + { + m_bQueriedForAsyncReader = TRUE; + return GetInterface((IAsyncReader*) this, ppv); + } + else + { + return CBasePin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +HRESULT CAsyncOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType) +{ + if(iPosition < 0) + { + return E_INVALIDARG; + } + if(iPosition > 0) + { + return VFW_S_NO_MORE_ITEMS; + } + + CheckPointer(pMediaType,E_POINTER); + CheckPointer(m_pReader,E_UNEXPECTED); + + *pMediaType = *m_pReader->LoadType(); + + return S_OK; +} + + +HRESULT CAsyncOutputPin::CheckMediaType(const CMediaType* pType) +{ + CAutoLock lck(m_pLock); + + /* We treat MEDIASUBTYPE_NULL subtype as a wild card */ + if((m_pReader->LoadType()->majortype == pType->majortype) && + (m_pReader->LoadType()->subtype == MEDIASUBTYPE_NULL || + m_pReader->LoadType()->subtype == pType->subtype)) + { + return S_OK; + } + + return S_FALSE; +} + + +HRESULT CAsyncOutputPin::InitAllocator(IMemAllocator **ppAlloc) +{ + CheckPointer(ppAlloc,E_POINTER); + + HRESULT hr = NOERROR; + CMemAllocator *pMemObject = NULL; + + *ppAlloc = NULL; + + /* Create a default memory allocator */ + pMemObject = new CMemAllocator(NAME("Base memory allocator"), NULL, &hr); + if(pMemObject == NULL) + { + return E_OUTOFMEMORY; + } + if(FAILED(hr)) + { + delete pMemObject; + return hr; + } + + /* Get a reference counted IID_IMemAllocator interface */ + hr = pMemObject->QueryInterface(IID_IMemAllocator,(void **)ppAlloc); + if(FAILED(hr)) + { + delete pMemObject; + return E_NOINTERFACE; + } + + ASSERT(*ppAlloc != NULL); + return NOERROR; +} + + +// we need to return an addrefed allocator, even if it is the preferred +// one, since he doesn't know whether it is the preferred one or not. +STDMETHODIMP +CAsyncOutputPin::RequestAllocator( + IMemAllocator* pPreferred, + ALLOCATOR_PROPERTIES* pProps, + IMemAllocator ** ppActual) +{ + CheckPointer(pPreferred,E_POINTER); + CheckPointer(pProps,E_POINTER); + CheckPointer(ppActual,E_POINTER); + ASSERT(m_pIo); + + // we care about alignment but nothing else + if(!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign)) + { + m_pIo->Alignment(&pProps->cbAlign); + } + + ALLOCATOR_PROPERTIES Actual; + HRESULT hr; + + if(pPreferred) + { + hr = pPreferred->SetProperties(pProps, &Actual); + + if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) + { + pPreferred->AddRef(); + *ppActual = pPreferred; + return S_OK; + } + } + + // create our own allocator + IMemAllocator* pAlloc; + hr = InitAllocator(&pAlloc); + if(FAILED(hr)) + { + return hr; + } + + //...and see if we can make it suitable + hr = pAlloc->SetProperties(pProps, &Actual); + if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) + { + // we need to release our refcount on pAlloc, and addref + // it to pass a refcount to the caller - this is a net nothing. + *ppActual = pAlloc; + return S_OK; + } + + // failed to find a suitable allocator + pAlloc->Release(); + + // if we failed because of the IsAligned test, the error code will + // not be failure + if(SUCCEEDED(hr)) + { + hr = VFW_E_BADALIGN; + } + return hr; +} + + +// queue an aligned read request. call WaitForNext to get +// completion. +STDMETHODIMP CAsyncOutputPin::Request( + IMediaSample* pSample, + DWORD_PTR dwUser) // user context +{ + CheckPointer(pSample,E_POINTER); + + REFERENCE_TIME tStart, tStop; + HRESULT hr = pSample->GetTime(&tStart, &tStop); + if(FAILED(hr)) + { + return hr; + } + + LONGLONG llPos = tStart / UNITS; + LONG lLength = (LONG) ((tStop - tStart) / UNITS); + + LONGLONG llTotal=0, llAvailable=0; + + hr = m_pIo->Length(&llTotal, &llAvailable); + if(llPos + lLength > llTotal) + { + // the end needs to be aligned, but may have been aligned + // on a coarser alignment. + LONG lAlign; + m_pIo->Alignment(&lAlign); + + llTotal = (llTotal + lAlign -1) & ~(lAlign-1); + + if(llPos + lLength > llTotal) + { + lLength = (LONG) (llTotal - llPos); + + // must be reducing this! + ASSERT((llTotal * UNITS) <= tStop); + tStop = llTotal * UNITS; + pSample->SetTime(&tStart, &tStop); + } + } + + BYTE* pBuffer; + hr = pSample->GetPointer(&pBuffer); + if(FAILED(hr)) + { + return hr; + } + + return m_pIo->Request(llPos, + lLength, + TRUE, + pBuffer, + (LPVOID)pSample, + dwUser); +} + + +// sync-aligned request. just like a request/waitfornext pair. +STDMETHODIMP +CAsyncOutputPin::SyncReadAligned( + IMediaSample* pSample) +{ + CheckPointer(pSample,E_POINTER); + + REFERENCE_TIME tStart, tStop; + HRESULT hr = pSample->GetTime(&tStart, &tStop); + if(FAILED(hr)) + { + return hr; + } + + LONGLONG llPos = tStart / UNITS; + LONG lLength = (LONG) ((tStop - tStart) / UNITS); + + LONGLONG llTotal; + LONGLONG llAvailable; + + hr = m_pIo->Length(&llTotal, &llAvailable); + if(llPos + lLength > llTotal) + { + // the end needs to be aligned, but may have been aligned + // on a coarser alignment. + LONG lAlign; + m_pIo->Alignment(&lAlign); + + llTotal = (llTotal + lAlign -1) & ~(lAlign-1); + + if(llPos + lLength > llTotal) + { + lLength = (LONG) (llTotal - llPos); + + // must be reducing this! + ASSERT((llTotal * UNITS) <= tStop); + tStop = llTotal * UNITS; + pSample->SetTime(&tStart, &tStop); + } + } + + BYTE* pBuffer; + hr = pSample->GetPointer(&pBuffer); + if(FAILED(hr)) + { + return hr; + } + + LONG cbActual; + hr = m_pIo->SyncReadAligned(llPos, + lLength, + pBuffer, + &cbActual, + pSample); + + pSample->SetActualDataLength(cbActual); + return hr; +} + + +// +// collect the next ready sample +STDMETHODIMP +CAsyncOutputPin::WaitForNext( + DWORD dwTimeout, + IMediaSample** ppSample, // completed sample + DWORD_PTR * pdwUser) // user context +{ + CheckPointer(ppSample,E_POINTER); + + LONG cbActual; + IMediaSample* pSample=0; + + HRESULT hr = m_pIo->WaitForNext(dwTimeout, + (LPVOID*) &pSample, + pdwUser, + &cbActual); + + if(SUCCEEDED(hr)) + { + pSample->SetActualDataLength(cbActual); + } + + *ppSample = pSample; + return hr; +} + + +// +// synchronous read that need not be aligned. +STDMETHODIMP +CAsyncOutputPin::SyncRead( + LONGLONG llPosition, // absolute Io position + LONG lLength, // nr bytes required + BYTE* pBuffer) // write data here +{ + return m_pIo->SyncRead(llPosition, lLength, pBuffer); +} + + +// return the length of the file, and the length currently +// available locally. We only support locally accessible files, +// so they are always the same +STDMETHODIMP +CAsyncOutputPin::Length( + LONGLONG* pTotal, + LONGLONG* pAvailable) +{ + return m_pIo->Length(pTotal, pAvailable); +} + + +STDMETHODIMP +CAsyncOutputPin::BeginFlush(void) +{ + return m_pIo->BeginFlush(); +} + + +STDMETHODIMP +CAsyncOutputPin::EndFlush(void) +{ + return m_pIo->EndFlush(); +} + + +STDMETHODIMP +CAsyncOutputPin::Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type +) +{ + return m_pReader->Connect(pReceivePin, pmt); +} + + + +// --- CAsyncReader implementation --- + +#pragma warning(disable:4355) + +CAsyncReader::CAsyncReader( + LPCTSTR pName, + LPUNKNOWN pUnk, + CAsyncStream *pStream, + HRESULT *phr, + const CLSID& clsid) // MPC-HC patch + : CBaseFilter( + pName, + pUnk, + &m_csFilter, + clsid, // MPC-HC patch + NULL + ), + m_Io(pStream), + m_OutputPin( + phr, + this, + &m_Io, + &m_csFilter) + +{ +} + +CAsyncReader::~CAsyncReader() +{ +} + +// MPC-HC patch start +STDMETHODIMP CAsyncReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + (riid == __uuidof(IAMFilterMiscFlags)) ? GetInterface((IAMFilterMiscFlags*)this, ppv) : + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IAMFilterMiscFlags + +ULONG CAsyncReader::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_SOURCE; +} +// MPC-HC patch end + +int CAsyncReader::GetPinCount() +{ + return 1; +} + +CBasePin * CAsyncReader::GetPin(int n) +{ + if((GetPinCount() > 0) && (n == 0)) + { + return &m_OutputPin; + } + else + { + return NULL; + } +} + + + diff --git a/src/thirdparty/AsyncReader/asyncrdr.h b/src/thirdparty/AsyncReader/asyncrdr.h index 33f447ef660..e4a6ea6505c 100644 --- a/src/thirdparty/AsyncReader/asyncrdr.h +++ b/src/thirdparty/AsyncReader/asyncrdr.h @@ -1,236 +1,236 @@ -//------------------------------------------------------------------------------ -// File: AsyncRdr.h -// -// Desc: DirectShow sample code - base library for I/O functionality. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __ASYNCRDR_H__ -#define __ASYNCRDR_H__ - - -// -// AsyncRdr -// -// Defines an IO source filter. -// -// This filter (CAsyncReader) supports IBaseFilter and IFileSourceFilter interfaces from the -// filter object itself. It has a single output pin (CAsyncOutputPin) -// which supports IPin and IAsyncReader. -// -// This filter is essentially a wrapper for the CAsyncFile class that does -// all the work. -// - - -// the filter class (defined below) -class CAsyncReader; - - -// the output pin class -class CAsyncOutputPin - : public IAsyncReader, - public CBasePin -{ -protected: - CAsyncReader* m_pReader; - CAsyncIo * m_pIo; - - // This is set every time we're asked to return an IAsyncReader - // interface - // This allows us to know if the downstream pin can use - // this transport, otherwise we can hook up to thinks like the - // dump filter and nothing happens - BOOL m_bQueriedForAsyncReader; - - HRESULT InitAllocator(IMemAllocator **ppAlloc); - -public: - // constructor and destructor - CAsyncOutputPin( - HRESULT * phr, - CAsyncReader *pReader, - CAsyncIo *pIo, - CCritSec * pLock); - - ~CAsyncOutputPin(); - - // --- CUnknown --- - - // need to expose IAsyncReader - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID, void**); - - // --- IPin methods --- - STDMETHODIMP Connect( - IPin * pReceivePin, - const AM_MEDIA_TYPE *pmt // optional media type - ); - - // --- CBasePin methods --- - - // return the types we prefer - this will return the known - // file type - HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); - - // can we support this type? - HRESULT CheckMediaType(const CMediaType* pType); - - // Clear the flag so we see if IAsyncReader is queried for - HRESULT CheckConnect(IPin *pPin) - { - m_bQueriedForAsyncReader = FALSE; - return CBasePin::CheckConnect(pPin); - } - - // See if it was asked for - HRESULT CompleteConnect(IPin *pReceivePin) - { - if (m_bQueriedForAsyncReader) { - return CBasePin::CompleteConnect(pReceivePin); - } else { - -#ifdef VFW_E_NO_TRANSPORT - return VFW_E_NO_TRANSPORT; -#else - return E_FAIL; -#endif - } - } - - // Remove our connection status - HRESULT BreakConnect() - { - m_bQueriedForAsyncReader = FALSE; - return CBasePin::BreakConnect(); - } - - // --- IAsyncReader methods --- - // pass in your preferred allocator and your preferred properties. - // method returns the actual allocator to be used. Call GetProperties - // on returned allocator to learn alignment and prefix etc chosen. - // this allocator will be not be committed and decommitted by - // the async reader, only by the consumer. - STDMETHODIMP RequestAllocator( - IMemAllocator* pPreferred, - ALLOCATOR_PROPERTIES* pProps, - IMemAllocator ** ppActual); - - // queue a request for data. - // media sample start and stop times contain the requested absolute - // byte position (start inclusive, stop exclusive). - // may fail if sample not obtained from agreed allocator. - // may fail if start/stop position does not match agreed alignment. - // samples allocated from source pin's allocator may fail - // GetPointer until after returning from WaitForNext. - STDMETHODIMP Request( - IMediaSample* pSample, - DWORD_PTR dwUser); // user context - - // block until the next sample is completed or the timeout occurs. - // timeout (millisecs) may be 0 or INFINITE. Samples may not - // be delivered in order. If there is a read error of any sort, a - // notification will already have been sent by the source filter, - // and STDMETHODIMP will be an error. - STDMETHODIMP WaitForNext( - DWORD dwTimeout, - IMediaSample** ppSample, // completed sample - DWORD_PTR * pdwUser); // user context - - // sync read of data. Sample passed in must have been acquired from - // the agreed allocator. Start and stop position must be aligned. - // equivalent to a Request/WaitForNext pair, but may avoid the - // need for a thread on the source filter. - STDMETHODIMP SyncReadAligned( - IMediaSample* pSample); - - - // sync read. works in stopped state as well as run state. - // need not be aligned. Will fail if read is beyond actual total - // length. - STDMETHODIMP SyncRead( - LONGLONG llPosition, // absolute file position - LONG lLength, // nr bytes required - BYTE* pBuffer); // write data here - - // return total length of stream, and currently available length. - // reads for beyond the available length but within the total length will - // normally succeed but may block for a long period. - STDMETHODIMP Length( - LONGLONG* pTotal, - LONGLONG* pAvailable); - - // cause all outstanding reads to return, possibly with a failure code - // (VFW_E_TIMEOUT) indicating they were cancelled. - // these are defined on IAsyncReader and IPin - STDMETHODIMP BeginFlush(void); - STDMETHODIMP EndFlush(void); - -}; - - -// -// The filter object itself. Supports IBaseFilter through -// CBaseFilter and also IFileSourceFilter directly in this object - -class CAsyncReader : public CBaseFilter, public IAMFilterMiscFlags -{ - -protected: - // filter-wide lock - CCritSec m_csFilter; - - // all i/o done here - CAsyncIo m_Io; - - // our output pin - CAsyncOutputPin m_OutputPin; - - // Type we think our data is - CMediaType m_mt; - -public: - - // construction / destruction - - CAsyncReader( - LPCTSTR pName, - LPUNKNOWN pUnk, - CAsyncStream *pStream, - HRESULT *phr, - const CLSID& clsid); // MPC-HC patch - - ~CAsyncReader(); - -// MPC-HC patch start - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IAMFilterMiscFlags - STDMETHODIMP_(ULONG) GetMiscFlags(); -// MPC-HC patch end - - // --- CBaseFilter methods --- - int GetPinCount(); - CBasePin *GetPin(int n); - - // --- Access our media type - const CMediaType *LoadType() const - { - return &m_mt; - } - - virtual HRESULT Connect( - IPin * pReceivePin, - const AM_MEDIA_TYPE *pmt // optional media type - ) - { - return m_OutputPin.CBasePin::Connect(pReceivePin, pmt); - } -}; - - - -#endif //__ASYNCRDR_H__ +//------------------------------------------------------------------------------ +// File: AsyncRdr.h +// +// Desc: DirectShow sample code - base library for I/O functionality. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __ASYNCRDR_H__ +#define __ASYNCRDR_H__ + + +// +// AsyncRdr +// +// Defines an IO source filter. +// +// This filter (CAsyncReader) supports IBaseFilter and IFileSourceFilter interfaces from the +// filter object itself. It has a single output pin (CAsyncOutputPin) +// which supports IPin and IAsyncReader. +// +// This filter is essentially a wrapper for the CAsyncFile class that does +// all the work. +// + + +// the filter class (defined below) +class CAsyncReader; + + +// the output pin class +class CAsyncOutputPin + : public IAsyncReader, + public CBasePin +{ +protected: + CAsyncReader* m_pReader; + CAsyncIo * m_pIo; + + // This is set every time we're asked to return an IAsyncReader + // interface + // This allows us to know if the downstream pin can use + // this transport, otherwise we can hook up to thinks like the + // dump filter and nothing happens + BOOL m_bQueriedForAsyncReader; + + HRESULT InitAllocator(IMemAllocator **ppAlloc); + +public: + // constructor and destructor + CAsyncOutputPin( + HRESULT * phr, + CAsyncReader *pReader, + CAsyncIo *pIo, + CCritSec * pLock); + + ~CAsyncOutputPin(); + + // --- CUnknown --- + + // need to expose IAsyncReader + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID, void**); + + // --- IPin methods --- + STDMETHODIMP Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type + ); + + // --- CBasePin methods --- + + // return the types we prefer - this will return the known + // file type + HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); + + // can we support this type? + HRESULT CheckMediaType(const CMediaType* pType); + + // Clear the flag so we see if IAsyncReader is queried for + HRESULT CheckConnect(IPin *pPin) + { + m_bQueriedForAsyncReader = FALSE; + return CBasePin::CheckConnect(pPin); + } + + // See if it was asked for + HRESULT CompleteConnect(IPin *pReceivePin) + { + if (m_bQueriedForAsyncReader) { + return CBasePin::CompleteConnect(pReceivePin); + } else { + +#ifdef VFW_E_NO_TRANSPORT + return VFW_E_NO_TRANSPORT; +#else + return E_FAIL; +#endif + } + } + + // Remove our connection status + HRESULT BreakConnect() + { + m_bQueriedForAsyncReader = FALSE; + return CBasePin::BreakConnect(); + } + + // --- IAsyncReader methods --- + // pass in your preferred allocator and your preferred properties. + // method returns the actual allocator to be used. Call GetProperties + // on returned allocator to learn alignment and prefix etc chosen. + // this allocator will be not be committed and decommitted by + // the async reader, only by the consumer. + STDMETHODIMP RequestAllocator( + IMemAllocator* pPreferred, + ALLOCATOR_PROPERTIES* pProps, + IMemAllocator ** ppActual); + + // queue a request for data. + // media sample start and stop times contain the requested absolute + // byte position (start inclusive, stop exclusive). + // may fail if sample not obtained from agreed allocator. + // may fail if start/stop position does not match agreed alignment. + // samples allocated from source pin's allocator may fail + // GetPointer until after returning from WaitForNext. + STDMETHODIMP Request( + IMediaSample* pSample, + DWORD_PTR dwUser); // user context + + // block until the next sample is completed or the timeout occurs. + // timeout (millisecs) may be 0 or INFINITE. Samples may not + // be delivered in order. If there is a read error of any sort, a + // notification will already have been sent by the source filter, + // and STDMETHODIMP will be an error. + STDMETHODIMP WaitForNext( + DWORD dwTimeout, + IMediaSample** ppSample, // completed sample + DWORD_PTR * pdwUser); // user context + + // sync read of data. Sample passed in must have been acquired from + // the agreed allocator. Start and stop position must be aligned. + // equivalent to a Request/WaitForNext pair, but may avoid the + // need for a thread on the source filter. + STDMETHODIMP SyncReadAligned( + IMediaSample* pSample); + + + // sync read. works in stopped state as well as run state. + // need not be aligned. Will fail if read is beyond actual total + // length. + STDMETHODIMP SyncRead( + LONGLONG llPosition, // absolute file position + LONG lLength, // nr bytes required + BYTE* pBuffer); // write data here + + // return total length of stream, and currently available length. + // reads for beyond the available length but within the total length will + // normally succeed but may block for a long period. + STDMETHODIMP Length( + LONGLONG* pTotal, + LONGLONG* pAvailable); + + // cause all outstanding reads to return, possibly with a failure code + // (VFW_E_TIMEOUT) indicating they were cancelled. + // these are defined on IAsyncReader and IPin + STDMETHODIMP BeginFlush(void); + STDMETHODIMP EndFlush(void); + +}; + + +// +// The filter object itself. Supports IBaseFilter through +// CBaseFilter and also IFileSourceFilter directly in this object + +class CAsyncReader : public CBaseFilter, public IAMFilterMiscFlags +{ + +protected: + // filter-wide lock + CCritSec m_csFilter; + + // all i/o done here + CAsyncIo m_Io; + + // our output pin + CAsyncOutputPin m_OutputPin; + + // Type we think our data is + CMediaType m_mt; + +public: + + // construction / destruction + + CAsyncReader( + LPCTSTR pName, + LPUNKNOWN pUnk, + CAsyncStream *pStream, + HRESULT *phr, + const CLSID& clsid); // MPC-HC patch + + ~CAsyncReader(); + +// MPC-HC patch start + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IAMFilterMiscFlags + STDMETHODIMP_(ULONG) GetMiscFlags(); +// MPC-HC patch end + + // --- CBaseFilter methods --- + int GetPinCount(); + CBasePin *GetPin(int n); + + // --- Access our media type + const CMediaType *LoadType() const + { + return &m_mt; + } + + virtual HRESULT Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type + ) + { + return m_OutputPin.CBasePin::Connect(pReceivePin, pmt); + } +}; + + + +#endif //__ASYNCRDR_H__ diff --git a/src/thirdparty/AsyncReader/stdafx.cpp b/src/thirdparty/AsyncReader/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/thirdparty/AsyncReader/stdafx.cpp +++ b/src/thirdparty/AsyncReader/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/thirdparty/AsyncReader/stdafx.h b/src/thirdparty/AsyncReader/stdafx.h index eff1a53f6f4..bf1cd08b021 100644 --- a/src/thirdparty/AsyncReader/stdafx.h +++ b/src/thirdparty/AsyncReader/stdafx.h @@ -1,28 +1,28 @@ -/* - * (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 . - * - */ - -#pragma once - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif - -#include "BaseClasses/streams.h" +/* + * (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 . + * + */ + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif + +#include "BaseClasses/streams.h" diff --git a/src/thirdparty/BaseClasses/BaseClasses.vcxproj b/src/thirdparty/BaseClasses/BaseClasses.vcxproj index 08b173e6574..91160f6e31b 100644 --- a/src/thirdparty/BaseClasses/BaseClasses.vcxproj +++ b/src/thirdparty/BaseClasses/BaseClasses.vcxproj @@ -1,130 +1,130 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA} - BaseClasses - Win32Proj - BaseClasses - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - streams.h - - - strmiids.lib;Winmm.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA} + BaseClasses + Win32Proj + BaseClasses + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + streams.h + + + strmiids.lib;Winmm.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/BaseClasses/BaseClasses.vcxproj.filters b/src/thirdparty/BaseClasses/BaseClasses.vcxproj.filters index 604be071873..de39b30833c 100644 --- a/src/thirdparty/BaseClasses/BaseClasses.vcxproj.filters +++ b/src/thirdparty/BaseClasses/BaseClasses.vcxproj.filters @@ -1,224 +1,224 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/src/thirdparty/BaseClasses/amextra.cpp b/src/thirdparty/BaseClasses/amextra.cpp index 582451bc9b6..518f9859a9a 100644 --- a/src/thirdparty/BaseClasses/amextra.cpp +++ b/src/thirdparty/BaseClasses/amextra.cpp @@ -1,111 +1,111 @@ -//------------------------------------------------------------------------------ -// File: AMExtra.cpp -// -// Desc: DirectShow base classes - implements CRenderedInputPin class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" // DirectShow base class definitions -#include // Needed for definition of timeGetTime -#include // Standard data type limit definitions -#include "measure.h" // Used for time critical log functions - -#include "amextra.h" - -#pragma warning(disable:4355) - -// Implements CRenderedInputPin class - -CRenderedInputPin::CRenderedInputPin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), - m_bAtEndOfStream(FALSE), - m_bCompleteNotified(FALSE) -{ -} -#ifdef UNICODE -CRenderedInputPin::CRenderedInputPin(__in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), - m_bAtEndOfStream(FALSE), - m_bCompleteNotified(FALSE) -{ -} -#endif - -// Flush end of stream condition - caller should do any -// necessary stream level locking before calling this - -STDMETHODIMP CRenderedInputPin::EndOfStream() -{ - HRESULT hr = CheckStreaming(); - - // Do EC_COMPLETE handling for rendered pins - if (S_OK == hr && !m_bAtEndOfStream) { - m_bAtEndOfStream = TRUE; - FILTER_STATE fs; - EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs))); - if (fs == State_Running) { - DoCompleteHandling(); - } - } - return hr; -} - - -// Called to complete the flush - -STDMETHODIMP CRenderedInputPin::EndFlush() -{ - CAutoLock lck(m_pLock); - - // Clean up renderer state - m_bAtEndOfStream = FALSE; - m_bCompleteNotified = FALSE; - - return CBaseInputPin::EndFlush(); -} - - -// Notify of Run() from filter - -HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart) -{ - UNREFERENCED_PARAMETER(tStart); - m_bCompleteNotified = FALSE; - if (m_bAtEndOfStream) { - DoCompleteHandling(); - } - return S_OK; -} - - -// Clear status on going into paused state - -HRESULT CRenderedInputPin::Active() -{ - m_bAtEndOfStream = FALSE; - m_bCompleteNotified = FALSE; - return CBaseInputPin::Active(); -} - - -// Do stuff to deliver end of stream - -void CRenderedInputPin::DoCompleteHandling() -{ - ASSERT(m_bAtEndOfStream); - if (!m_bCompleteNotified) { - m_bCompleteNotified = TRUE; - m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter); - } -} - +//------------------------------------------------------------------------------ +// File: AMExtra.cpp +// +// Desc: DirectShow base classes - implements CRenderedInputPin class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" // DirectShow base class definitions +#include // Needed for definition of timeGetTime +#include // Standard data type limit definitions +#include "measure.h" // Used for time critical log functions + +#include "amextra.h" + +#pragma warning(disable:4355) + +// Implements CRenderedInputPin class + +CRenderedInputPin::CRenderedInputPin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), + m_bAtEndOfStream(FALSE), + m_bCompleteNotified(FALSE) +{ +} +#ifdef UNICODE +CRenderedInputPin::CRenderedInputPin(__in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), + m_bAtEndOfStream(FALSE), + m_bCompleteNotified(FALSE) +{ +} +#endif + +// Flush end of stream condition - caller should do any +// necessary stream level locking before calling this + +STDMETHODIMP CRenderedInputPin::EndOfStream() +{ + HRESULT hr = CheckStreaming(); + + // Do EC_COMPLETE handling for rendered pins + if (S_OK == hr && !m_bAtEndOfStream) { + m_bAtEndOfStream = TRUE; + FILTER_STATE fs; + EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs))); + if (fs == State_Running) { + DoCompleteHandling(); + } + } + return hr; +} + + +// Called to complete the flush + +STDMETHODIMP CRenderedInputPin::EndFlush() +{ + CAutoLock lck(m_pLock); + + // Clean up renderer state + m_bAtEndOfStream = FALSE; + m_bCompleteNotified = FALSE; + + return CBaseInputPin::EndFlush(); +} + + +// Notify of Run() from filter + +HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart) +{ + UNREFERENCED_PARAMETER(tStart); + m_bCompleteNotified = FALSE; + if (m_bAtEndOfStream) { + DoCompleteHandling(); + } + return S_OK; +} + + +// Clear status on going into paused state + +HRESULT CRenderedInputPin::Active() +{ + m_bAtEndOfStream = FALSE; + m_bCompleteNotified = FALSE; + return CBaseInputPin::Active(); +} + + +// Do stuff to deliver end of stream + +void CRenderedInputPin::DoCompleteHandling() +{ + ASSERT(m_bAtEndOfStream); + if (!m_bCompleteNotified) { + m_bCompleteNotified = TRUE; + m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter); + } +} + diff --git a/src/thirdparty/BaseClasses/amextra.h b/src/thirdparty/BaseClasses/amextra.h index 5a861bf12a2..3caf64ce9f9 100644 --- a/src/thirdparty/BaseClasses/amextra.h +++ b/src/thirdparty/BaseClasses/amextra.h @@ -1,56 +1,56 @@ -//------------------------------------------------------------------------------ -// File: AMExtra.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __AMEXTRA__ -#define __AMEXTRA__ - -// Simple rendered input pin -// -// NOTE if your filter queues stuff before rendering then it may not be -// appropriate to use this class -// -// In that case queue the end of stream condition until the last sample -// is actually rendered and flush the condition appropriately - -class CRenderedInputPin : public CBaseInputPin -{ -public: - - CRenderedInputPin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CRenderedInputPin(__in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#endif - - // Override methods to track end of stream state - STDMETHODIMP EndOfStream(); - STDMETHODIMP EndFlush(); - - HRESULT Active(); - HRESULT Run(REFERENCE_TIME tStart); - -protected: - - // Member variables to track state - BOOL m_bAtEndOfStream; // Set by EndOfStream - BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE - -private: - void DoCompleteHandling(); -}; - -#endif // __AMEXTRA__ - +//------------------------------------------------------------------------------ +// File: AMExtra.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __AMEXTRA__ +#define __AMEXTRA__ + +// Simple rendered input pin +// +// NOTE if your filter queues stuff before rendering then it may not be +// appropriate to use this class +// +// In that case queue the end of stream condition until the last sample +// is actually rendered and flush the condition appropriately + +class CRenderedInputPin : public CBaseInputPin +{ +public: + + CRenderedInputPin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CRenderedInputPin(__in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#endif + + // Override methods to track end of stream state + STDMETHODIMP EndOfStream(); + STDMETHODIMP EndFlush(); + + HRESULT Active(); + HRESULT Run(REFERENCE_TIME tStart); + +protected: + + // Member variables to track state + BOOL m_bAtEndOfStream; // Set by EndOfStream + BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE + +private: + void DoCompleteHandling(); +}; + +#endif // __AMEXTRA__ + diff --git a/src/thirdparty/BaseClasses/amfilter.cpp b/src/thirdparty/BaseClasses/amfilter.cpp index 175f04c2520..835d36fd5ce 100644 --- a/src/thirdparty/BaseClasses/amfilter.cpp +++ b/src/thirdparty/BaseClasses/amfilter.cpp @@ -1,5373 +1,5373 @@ -//------------------------------------------------------------------------------ -// File: AMFilter.cpp -// -// Desc: DirectShow base classes - implements class hierarchy for streams -// architecture. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -//===================================================================== -//===================================================================== -// The following classes are declared in this header: -// -// -// CBaseMediaFilter Basic IMediaFilter support (abstract class) -// CBaseFilter Support for IBaseFilter (incl. IMediaFilter) -// CEnumPins Enumerate input and output pins -// CEnumMediaTypes Enumerate the preferred pin formats -// CBasePin Abstract base class for IPin interface -// CBaseOutputPin Adds data provider member functions -// CBaseInputPin Implements IMemInputPin interface -// CMediaSample Basic transport unit for IMemInputPin -// CBaseAllocator General list guff for most allocators -// CMemAllocator Implements memory buffer allocation -// -//===================================================================== -//===================================================================== - -#include "streams.h" -#include - -#ifdef DXMPERF -#include "dxmperf.h" -#endif // DXMPERF - - -//===================================================================== -// Helpers -//===================================================================== -STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator) -{ - return CoCreateInstance(CLSID_MemoryAllocator, - 0, - CLSCTX_INPROC_SERVER, - IID_IMemAllocator, - (void **)ppAllocator); -} - -// Put this one here rather than in ctlutil.cpp to avoid linking -// anything brought in by ctlutil.cpp -STDAPI CreatePosPassThru( - __in_opt LPUNKNOWN pAgg, - BOOL bRenderer, - IPin *pPin, - __deref_out IUnknown **ppPassThru -) -{ - *ppPassThru = NULL; - IUnknown *pUnkSeek; - HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru, - pAgg, - CLSCTX_INPROC_SERVER, - IID_IUnknown, - (void **)&pUnkSeek - ); - if (FAILED(hr)) { - return hr; - } - - ISeekingPassThru *pPassThru; - hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru); - if (FAILED(hr)) { - pUnkSeek->Release(); - return hr; - } - hr = pPassThru->Init(bRenderer, pPin); - pPassThru->Release(); - if (FAILED(hr)) { - pUnkSeek->Release(); - return hr; - } - *ppPassThru = pUnkSeek; - return S_OK; -} - - - -#define CONNECT_TRACE_LEVEL 3 - -//===================================================================== -//===================================================================== -// Implements CBaseMediaFilter -//===================================================================== -//===================================================================== - - -/* Constructor */ - -CBaseMediaFilter::CBaseMediaFilter(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid) : - CUnknown(pName, pUnk), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL) -{ -} - - -/* Destructor */ - -CBaseMediaFilter::~CBaseMediaFilter() -{ - // must be stopped, but can't call Stop here since - // our critsec has been destroyed. - - /* Release any clock we were using */ - - if (m_pClock) { - m_pClock->Release(); - m_pClock = NULL; - } -} - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP -CBaseMediaFilter::NonDelegatingQueryInterface( - REFIID riid, - __deref_out void ** ppv) -{ - if (riid == IID_IMediaFilter) { - return GetInterface((IMediaFilter *) this, ppv); - } else if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - -/* Return the filter's clsid */ -STDMETHODIMP -CBaseMediaFilter::GetClassID(__out CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = m_clsid; - return NOERROR; -} - -/* Override this if your state changes are not done synchronously */ - -STDMETHODIMP -CBaseMediaFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State) -{ - UNREFERENCED_PARAMETER(dwMSecs); - CheckPointer(State,E_POINTER); - ValidateReadWritePtr(State,sizeof(FILTER_STATE)); - - *State = m_State; - return S_OK; -} - - -/* Set the clock we will use for synchronisation */ - -STDMETHODIMP -CBaseMediaFilter::SetSyncSource(__inout_opt IReferenceClock *pClock) -{ - CAutoLock cObjectLock(m_pLock); - - // Ensure the new one does not go away - even if the same as the old - if (pClock) { - pClock->AddRef(); - } - - // if we have a clock, release it - if (m_pClock) { - m_pClock->Release(); - } - - // Set the new reference clock (might be NULL) - // Should we query it to ensure it is a clock? Consider for a debug build. - m_pClock = pClock; - - return NOERROR; -} - -/* Return the clock we are using for synchronisation */ -STDMETHODIMP -CBaseMediaFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock) -{ - CheckPointer(pClock,E_POINTER); - ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pClock) { - // returning an interface... addref it... - m_pClock->AddRef(); - } - *pClock = (IReferenceClock*)m_pClock; - return NOERROR; -} - - -/* Put the filter into a stopped state */ - -STDMETHODIMP -CBaseMediaFilter::Stop() -{ - CAutoLock cObjectLock(m_pLock); - - m_State = State_Stopped; - return S_OK; -} - - -/* Put the filter into a paused state */ - -STDMETHODIMP -CBaseMediaFilter::Pause() -{ - CAutoLock cObjectLock(m_pLock); - - m_State = State_Paused; - return S_OK; -} - - -// Put the filter into a running state. - -// The time parameter is the offset to be added to the samples' -// stream time to get the reference time at which they should be presented. -// -// you can either add these two and compare it against the reference clock, -// or you can call CBaseMediaFilter::StreamTime and compare that against -// the sample timestamp. - -STDMETHODIMP -CBaseMediaFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cObjectLock(m_pLock); - - // remember the stream time offset - m_tStart = tStart; - - if (m_State == State_Stopped){ - HRESULT hr = Pause(); - - if (FAILED(hr)) { - return hr; - } - } - m_State = State_Running; - return S_OK; -} - - -// -// return the current stream time - samples with start timestamps of this -// time or before should be rendered by now -HRESULT -CBaseMediaFilter::StreamTime(CRefTime& rtStream) -{ - // Caller must lock for synchronization - // We can't grab the filter lock because we want to be able to call - // this from worker threads without deadlocking - - if (m_pClock == NULL) { - return VFW_E_NO_CLOCK; - } - - // get the current reference time - HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); - if (FAILED(hr)) { - return hr; - } - - // subtract the stream offset to get stream time - rtStream -= m_tStart; - - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CBaseFilter -//===================================================================== -//===================================================================== - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid, - __deref_out void **ppv) -{ - /* Do we have this interface */ - - if (riid == IID_IBaseFilter) { - return GetInterface((IBaseFilter *) this, ppv); - } else if (riid == IID_IMediaFilter) { - return GetInterface((IMediaFilter *) this, ppv); - } else if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); - } else if (riid == IID_IAMovieSetup) { - return GetInterface((IAMovieSetup *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - -#ifdef _DEBUG -STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease() -{ - if (m_cRef == 1) { - KASSERT(m_pGraph == NULL); - } - return CUnknown::NonDelegatingRelease(); -} -#endif - - -/* Constructor */ - -CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - ASSERT(pLock != NULL); -} - -/* Passes in a redundant HRESULT argument */ - -CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid, - __inout HRESULT *phr) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - ASSERT(pLock != NULL); - UNREFERENCED_PARAMETER(phr); -} - -#ifdef UNICODE -CBaseFilter::CBaseFilter(__in_opt LPCSTR pName, - __in_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - ASSERT(pLock != NULL); -} -CBaseFilter::CBaseFilter(__in_opt LPCSTR pName, - __in_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid, - __inout HRESULT *phr) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - ASSERT(pLock != NULL); - UNREFERENCED_PARAMETER(phr); -} -#endif - -/* Destructor */ - -CBaseFilter::~CBaseFilter() -{ -#ifdef DXMPERF - PERFLOG_DTOR( L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink - // When we did we had the circular reference problem. Nothing would go away. - - delete[] m_pName; - - // must be stopped, but can't call Stop here since - // our critsec has been destroyed. - - /* Release any clock we were using */ - if (m_pClock) { - m_pClock->Release(); - m_pClock = NULL; - } -} - -/* Return the filter's clsid */ -STDMETHODIMP -CBaseFilter::GetClassID(__out CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = m_clsid; - return NOERROR; -} - -/* Override this if your state changes are not done synchronously */ -STDMETHODIMP -CBaseFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State) -{ - UNREFERENCED_PARAMETER(dwMSecs); - CheckPointer(State,E_POINTER); - ValidateReadWritePtr(State,sizeof(FILTER_STATE)); - - *State = m_State; - return S_OK; -} - - -/* Set the clock we will use for synchronisation */ - -STDMETHODIMP -CBaseFilter::SetSyncSource(__in_opt IReferenceClock *pClock) -{ - CAutoLock cObjectLock(m_pLock); - - // Ensure the new one does not go away - even if the same as the old - if (pClock) { - pClock->AddRef(); - } - - // if we have a clock, release it - if (m_pClock) { - m_pClock->Release(); - } - - // Set the new reference clock (might be NULL) - // Should we query it to ensure it is a clock? Consider for a debug build. - m_pClock = pClock; - - return NOERROR; -} - -/* Return the clock we are using for synchronisation */ -STDMETHODIMP -CBaseFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock) -{ - CheckPointer(pClock,E_POINTER); - ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pClock) { - // returning an interface... addref it... - m_pClock->AddRef(); - } - *pClock = (IReferenceClock*)m_pClock; - return NOERROR; -} - - - -// override CBaseMediaFilter Stop method, to deactivate any pins this -// filter has. -STDMETHODIMP -CBaseFilter::Stop() -{ - CAutoLock cObjectLock(m_pLock); - HRESULT hr = NOERROR; - - // notify all pins of the state change - if (m_State != State_Stopped) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - if (NULL == pPin) { - break; - } - - // Disconnected pins are not activated - this saves pins worrying - // about this state themselves. We ignore the return code to make - // sure everyone is inactivated regardless. The base input pin - // class can return an error if it has no allocator but Stop can - // be used to resync the graph state after something has gone bad - - if (pPin->IsConnected()) { - HRESULT hrTmp = pPin->Inactive(); - if (FAILED(hrTmp) && SUCCEEDED(hr)) { - hr = hrTmp; - } - } - } - } - -#ifdef DXMPERF - PERFLOG_STOP( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State ); -#endif // DXMPERF - - m_State = State_Stopped; - return hr; -} - - -// override CBaseMediaFilter Pause method to activate any pins -// this filter has (also called from Run) - -STDMETHODIMP -CBaseFilter::Pause() -{ - CAutoLock cObjectLock(m_pLock); - - // notify all pins of the change to active state - if (m_State == State_Stopped) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - if (NULL == pPin) { - break; - } - - // Disconnected pins are not activated - this saves pins - // worrying about this state themselves - - if (pPin->IsConnected()) { - HRESULT hr = pPin->Active(); - if (FAILED(hr)) { - return hr; - } - } - } - } - - -#ifdef DXMPERF - PERFLOG_PAUSE( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State ); -#endif // DXMPERF - - m_State = State_Paused; - return S_OK; -} - -// Put the filter into a running state. - -// The time parameter is the offset to be added to the samples' -// stream time to get the reference time at which they should be presented. -// -// you can either add these two and compare it against the reference clock, -// or you can call CBaseFilter::StreamTime and compare that against -// the sample timestamp. - -STDMETHODIMP -CBaseFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cObjectLock(m_pLock); - - // remember the stream time offset - m_tStart = tStart; - - if (m_State == State_Stopped){ - HRESULT hr = Pause(); - - if (FAILED(hr)) { - return hr; - } - } - // notify all pins of the change to active state - if (m_State != State_Running) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - if (NULL == pPin) { - break; - } - - // Disconnected pins are not activated - this saves pins - // worrying about this state themselves - - if (pPin->IsConnected()) { - HRESULT hr = pPin->Run(tStart); - if (FAILED(hr)) { - return hr; - } - } - } - } - -#ifdef DXMPERF - PERFLOG_RUN( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, tStart, m_State ); -#endif // DXMPERF - - m_State = State_Running; - return S_OK; -} - -// -// return the current stream time - samples with start timestamps of this -// time or before should be rendered by now -HRESULT -CBaseFilter::StreamTime(CRefTime& rtStream) -{ - // Caller must lock for synchronization - // We can't grab the filter lock because we want to be able to call - // this from worker threads without deadlocking - - if (m_pClock == NULL) { - return VFW_E_NO_CLOCK; - } - - // get the current reference time - HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); - if (FAILED(hr)) { - return hr; - } - - // subtract the stream offset to get stream time - rtStream -= m_tStart; - - return S_OK; -} - - -/* Create an enumerator for the pins attached to this filter */ - -STDMETHODIMP -CBaseFilter::EnumPins(__deref_out IEnumPins **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); - - /* Create a new ref counted enumerator */ - - *ppEnum = new CEnumPins(this, - NULL); - - return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR; -} - - -// default behaviour of FindPin is to assume pins are named -// by their pin names -STDMETHODIMP -CBaseFilter::FindPin( - LPCWSTR Id, - __deref_out IPin ** ppPin -) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - - // We're going to search the pin list so maintain integrity - CAutoLock lck(m_pLock); - int iCount = GetPinCount(); - for (int i = 0; i < iCount; i++) { - CBasePin *pPin = GetPin(i); - if (NULL == pPin) { - break; - } - - if (0 == lstrcmpW(pPin->Name(), Id)) { - // Found one that matches - // - // AddRef() and return it - *ppPin = pPin; - pPin->AddRef(); - return S_OK; - } - } - *ppPin = NULL; - return VFW_E_NOT_FOUND; -} - -/* Return information about this filter */ - -STDMETHODIMP -CBaseFilter::QueryFilterInfo(__out FILTER_INFO * pInfo) -{ - CheckPointer(pInfo,E_POINTER); - ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO)); - - if (m_pName) { - (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); - } else { - pInfo->achName[0] = L'\0'; - } - pInfo->pGraph = m_pGraph; - if (m_pGraph) - m_pGraph->AddRef(); - return NOERROR; -} - - -/* Provide the filter with a filter graph */ - -STDMETHODIMP -CBaseFilter::JoinFilterGraph( - __inout_opt IFilterGraph * pGraph, - __in_opt LPCWSTR pName) -{ - CAutoLock cObjectLock(m_pLock); - - // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink) - - m_pGraph = pGraph; - if (m_pGraph) { - HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink, - (void**) &m_pSink); - if (FAILED(hr)) { - ASSERT(m_pSink == NULL); - } - else m_pSink->Release(); // we do NOT keep a reference on it. - } else { - // if graph pointer is null, then we should - // also release the IMediaEventSink on the same object - we don't - // refcount it, so just set it to null - m_pSink = NULL; - } - - - if (m_pName) { - delete[] m_pName; - m_pName = NULL; - } - - if (pName) { - size_t namelen; - HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &namelen); - if (FAILED(hr)) { - return hr; - } - m_pName = new WCHAR[namelen + 1]; - if (m_pName) { - (void)StringCchCopyW(m_pName, namelen + 1, pName); - } else { - return E_OUTOFMEMORY; - } - } - -#ifdef DXMPERF - PERFLOG_JOINGRAPH( m_pName ? m_pName : L"CBaseFilter",(IBaseFilter *) this, pGraph ); -#endif // DXMPERF - - return NOERROR; -} - - -// return a Vendor information string. Optional - may return E_NOTIMPL. -// memory returned should be freed using CoTaskMemFree -// default implementation returns E_NOTIMPL -STDMETHODIMP -CBaseFilter::QueryVendorInfo( - __deref_out LPWSTR* pVendorInfo) -{ - UNREFERENCED_PARAMETER(pVendorInfo); - return E_NOTIMPL; -} - - -// send an event notification to the filter graph if we know about it. -// returns S_OK if delivered, S_FALSE if the filter graph does not sink -// events, or an error otherwise. -HRESULT -CBaseFilter::NotifyEvent( - long EventCode, - LONG_PTR EventParam1, - LONG_PTR EventParam2) -{ - // Snapshot so we don't have to lock up - IMediaEventSink *pSink = m_pSink; - if (pSink) { - if (EC_COMPLETE == EventCode) { - EventParam2 = (LONG_PTR)(IBaseFilter*)this; - } - - return pSink->Notify(EventCode, EventParam1, EventParam2); - } else { - return E_NOTIMPL; - } -} - -// Request reconnect -// pPin is the pin to reconnect -// pmt is the type to reconnect with - can be NULL -// Calls ReconnectEx on the filter graph -HRESULT -CBaseFilter::ReconnectPin( - IPin *pPin, - __in_opt AM_MEDIA_TYPE const *pmt -) -{ - IFilterGraph2 *pGraph2; - if (m_pGraph != NULL) { - HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2); - if (SUCCEEDED(hr)) { - hr = pGraph2->ReconnectEx(pPin, pmt); - pGraph2->Release(); - return hr; - } else { - return m_pGraph->Reconnect(pPin); - } - } else { - return E_NOINTERFACE; - } -} - - - -/* This is the same idea as the media type version does for type enumeration - on pins but for the list of pins available. So if the list of pins you - provide changes dynamically then either override this virtual function - to provide the version number, or more simply call IncrementPinVersion */ - -LONG CBaseFilter::GetPinVersion() -{ - return m_PinVersion; -} - - -/* Increment the current pin version cookie */ - -void CBaseFilter::IncrementPinVersion() -{ - InterlockedIncrement(&m_PinVersion); -} - -/* register filter */ - -STDMETHODIMP CBaseFilter::Register() -{ - // get setup data, if it exists - // - LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - // init is ref counted so call just in case - // we're being called cold. - // - HRESULT hr = CoInitialize( (LPVOID)NULL ); - ASSERT( SUCCEEDED(hr) ); - - // get hold of IFilterMapper - // - IFilterMapper *pIFM; - hr = CoCreateInstance( CLSID_FilterMapper - , NULL - , CLSCTX_INPROC_SERVER - , IID_IFilterMapper - , (void **)&pIFM ); - if( SUCCEEDED(hr) ) - { - hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE ); - pIFM->Release(); - } - - // and clear up - // - CoFreeUnusedLibraries(); - CoUninitialize(); - - return NOERROR; -} - - -/* unregister filter */ - -STDMETHODIMP CBaseFilter::Unregister() -{ - // get setup data, if it exists - // - LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - // OLE init is ref counted so call - // just in case we're being called cold. - // - HRESULT hr = CoInitialize( (LPVOID)NULL ); - ASSERT( SUCCEEDED(hr) ); - - // get hold of IFilterMapper - // - IFilterMapper *pIFM; - hr = CoCreateInstance( CLSID_FilterMapper - , NULL - , CLSCTX_INPROC_SERVER - , IID_IFilterMapper - , (void **)&pIFM ); - if( SUCCEEDED(hr) ) - { - hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE ); - - // release interface - // - pIFM->Release(); - } - - // clear up - // - CoFreeUnusedLibraries(); - CoUninitialize(); - - // handle one acceptable "error" - that - // of filter not being registered! - // (couldn't find a suitable #define'd - // name for the error!) - // - if( 0x80070002 == hr) - return NOERROR; - else - return hr; -} - - -//===================================================================== -//===================================================================== -// Implements CEnumPins -//===================================================================== -//===================================================================== - - -CEnumPins::CEnumPins(__in CBaseFilter *pFilter, - __in_opt CEnumPins *pEnumPins) : - m_Position(0), - m_PinCount(0), - m_pFilter(pFilter), - m_cRef(1), // Already ref counted - m_PinCache(NAME("Pin Cache")) -{ - -#ifdef _DEBUG - m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0); -#endif - - /* We must be owned by a filter derived from CBaseFilter */ - - ASSERT(pFilter != NULL); - - /* Hold a reference count on our filter */ - m_pFilter->AddRef(); - - /* Are we creating a new enumerator */ - - if (pEnumPins == NULL) { - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - } else { - ASSERT(m_Position <= m_PinCount); - m_Position = pEnumPins->m_Position; - m_PinCount = pEnumPins->m_PinCount; - m_Version = pEnumPins->m_Version; - m_PinCache.AddTail(&(pEnumPins->m_PinCache)); - } -} - - -/* Destructor releases the reference count on our filter NOTE since we hold - a reference count on the filter who created us we know it is safe to - release it, no access can be made to it afterwards though as we have just - caused the last reference count to go and the object to be deleted */ - -CEnumPins::~CEnumPins() -{ - m_pFilter->Release(); - -#ifdef _DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif -} - - -/* Override this to say what interfaces we support where */ - -STDMETHODIMP -CEnumPins::QueryInterface(REFIID riid, __deref_out void **ppv) -{ - CheckPointer(ppv, E_POINTER); - - /* Do we have this interface */ - - if (riid == IID_IEnumPins || riid == IID_IUnknown) { - return GetInterface((IEnumPins *) this, ppv); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CEnumPins::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -STDMETHODIMP_(ULONG) -CEnumPins::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) { - delete this; - } - return cRef; -} - -/* One of an enumerator's basic member functions allows us to create a cloned - interface that initially has the same state. Since we are taking a snapshot - of an object (current position and all) we must lock access at the start */ - -STDMETHODIMP -CEnumPins::Clone(__deref_out IEnumPins **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); - HRESULT hr = NOERROR; - - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - *ppEnum = NULL; - hr = VFW_E_ENUM_OUT_OF_SYNC; - } else { - *ppEnum = new CEnumPins(m_pFilter, - this); - if (*ppEnum == NULL) { - hr = E_OUTOFMEMORY; - } - } - return hr; -} - - -/* Return the next pin after the current position */ - -STDMETHODIMP -CEnumPins::Next(ULONG cPins, // place this many pins... - __out_ecount(cPins) IPin **ppPins, // ...in this array - __out_opt ULONG *pcFetched) // actual count passed returned here -{ - CheckPointer(ppPins,E_POINTER); - ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *)); - - ASSERT(ppPins); - - if (pcFetched!=NULL) { - ValidateWritePtr(pcFetched, sizeof(ULONG)); - *pcFetched = 0; // default unless we succeed - } - // now check that the parameter is valid - else if (cPins>1) { // pcFetched == NULL - return E_INVALIDARG; - } - ULONG cFetched = 0; // increment as we get each one. - - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - // If we are out of sync, we should refresh the enumerator. - // This will reset the position and update the other members, but - // will not clear cache of pins we have already returned. - Refresh(); - } - - /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed - so we must QI for the IPin (which increments its reference count) - If while we are retrieving a pin from the filter an error occurs we - assume that our internal state is stale with respect to the filter - (for example someone has deleted a pin) so we - return VFW_E_ENUM_OUT_OF_SYNC */ - - while (cFetched < cPins && m_PinCount > m_Position) { - - /* Get the next pin object from the filter */ - - CBasePin *pPin = m_pFilter->GetPin(m_Position++); - if (pPin == NULL) { - // If this happend, and it's not the first time through, then we've got a problem, - // since we should really go back and release the iPins, which we have previously - // AddRef'ed. - ASSERT( cFetched==0 ); - return VFW_E_ENUM_OUT_OF_SYNC; - } - // MPC-HC custom code begin - if (pPin == (CBasePin *)0x3) { - return E_FAIL; - } - // MPC-HC custom code end - - /* We only want to return this pin, if it is not in our cache */ - if (0 == m_PinCache.Find(pPin)) - { - /* From the object get an IPin interface */ - - *ppPins = pPin; - pPin->AddRef(); - - cFetched++; - ppPins++; - - m_PinCache.AddTail(pPin); - } - } - - if (pcFetched!=NULL) { - *pcFetched = cFetched; - } - - return (cPins==cFetched ? NOERROR : S_FALSE); -} - - -/* Skip over one or more entries in the enumerator */ - -STDMETHODIMP -CEnumPins::Skip(ULONG cPins) -{ - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - /* Work out how many pins are left to skip over */ - /* We could position at the end if we are asked to skip too many... */ - /* ..which would match the base implementation for CEnumMediaTypes::Skip */ - - ULONG PinsLeft = m_PinCount - m_Position; - if (cPins > PinsLeft) { - return S_FALSE; - } - m_Position += cPins; - return NOERROR; -} - - -/* Set the current position back to the start */ -/* Reset has 4 simple steps: - * - * Set position to head of list - * Sync enumerator with object being enumerated - * Clear the cache of pins already returned - * return S_OK - */ - -STDMETHODIMP -CEnumPins::Reset() -{ - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - - m_Position = 0; - - // Clear the cache - m_PinCache.RemoveAll(); - - return S_OK; -} - - -/* Set the current position back to the start */ -/* Refresh has 3 simple steps: - * - * Set position to head of list - * Sync enumerator with object being enumerated - * return S_OK - */ - -STDMETHODIMP -CEnumPins::Refresh() -{ - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - - m_Position = 0; - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CEnumMediaTypes -//===================================================================== -//===================================================================== - - -CEnumMediaTypes::CEnumMediaTypes(__in CBasePin *pPin, - __in_opt CEnumMediaTypes *pEnumMediaTypes) : - m_Position(0), - m_pPin(pPin), - m_cRef(1) -{ - -#ifdef _DEBUG - m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0); -#endif - - /* We must be owned by a pin derived from CBasePin */ - - ASSERT(pPin != NULL); - - /* Hold a reference count on our pin */ - m_pPin->AddRef(); - - /* Are we creating a new enumerator */ - - if (pEnumMediaTypes == NULL) { - m_Version = m_pPin->GetMediaTypeVersion(); - return; - } - - m_Position = pEnumMediaTypes->m_Position; - m_Version = pEnumMediaTypes->m_Version; -} - - -/* Destructor releases the reference count on our base pin. NOTE since we hold - a reference count on the pin who created us we know it is safe to release - it, no access can be made to it afterwards though as we might have just - caused the last reference count to go and the object to be deleted */ - -CEnumMediaTypes::~CEnumMediaTypes() -{ -#ifdef _DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif - m_pPin->Release(); -} - - -/* Override this to say what interfaces we support where */ - -STDMETHODIMP -CEnumMediaTypes::QueryInterface(REFIID riid, __deref_out void **ppv) -{ - CheckPointer(ppv, E_POINTER); - - /* Do we have this interface */ - - if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) { - return GetInterface((IEnumMediaTypes *) this, ppv); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CEnumMediaTypes::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -STDMETHODIMP_(ULONG) -CEnumMediaTypes::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) { - delete this; - } - return cRef; -} - -/* One of an enumerator's basic member functions allows us to create a cloned - interface that initially has the same state. Since we are taking a snapshot - of an object (current position and all) we must lock access at the start */ - -STDMETHODIMP -CEnumMediaTypes::Clone(__deref_out IEnumMediaTypes **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); - HRESULT hr = NOERROR; - - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - *ppEnum = NULL; - hr = VFW_E_ENUM_OUT_OF_SYNC; - } else { - - *ppEnum = new CEnumMediaTypes(m_pPin, - this); - - if (*ppEnum == NULL) { - hr = E_OUTOFMEMORY; - } - } - return hr; -} - - -/* Enumerate the next pin(s) after the current position. The client using this - interface passes in a pointer to an array of pointers each of which will - be filled in with a pointer to a fully initialised media type format - Return NOERROR if it all works, - S_FALSE if fewer than cMediaTypes were enumerated. - VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by - state changes in the filter - The actual count always correctly reflects the number of types in the array. -*/ - -STDMETHODIMP -CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types... - __out_ecount(cMediaTypes) AM_MEDIA_TYPE **ppMediaTypes, // ...in this array - __out ULONG *pcFetched) // actual count passed -{ - CheckPointer(ppMediaTypes,E_POINTER); - ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *)); - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - if (pcFetched!=NULL) { - ValidateWritePtr(pcFetched, sizeof(ULONG)); - *pcFetched = 0; // default unless we succeed - } - // now check that the parameter is valid - else if (cMediaTypes>1) { // pcFetched == NULL - return E_INVALIDARG; - } - ULONG cFetched = 0; // increment as we get each one. - - /* Return each media type by asking the filter for them in turn - If we - have an error code retured to us while we are retrieving a media type - we assume that our internal state is stale with respect to the filter - (for example the window size changing) so we return - VFW_E_ENUM_OUT_OF_SYNC */ - - while (cMediaTypes) { - - CMediaType cmt; - - HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt); - if (S_OK != hr) { - break; - } - - /* We now have a CMediaType object that contains the next media type - but when we assign it to the array position we CANNOT just assign - the AM_MEDIA_TYPE structure because as soon as the object goes out of - scope it will delete the memory we have just copied. The function - we use is CreateMediaType which allocates a task memory block */ - - /* Transfer across the format block manually to save an allocate - and free on the format block and generally go faster */ - - *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - if (*ppMediaTypes == NULL) { - break; - } - - /* Do a regular copy */ - **ppMediaTypes = cmt; - - /* Make sure the destructor doesn't free these */ - cmt.pbFormat = NULL; - cmt.cbFormat = NULL; - cmt.pUnk = NULL; - - - ppMediaTypes++; - cFetched++; - cMediaTypes--; - } - - if (pcFetched!=NULL) { - *pcFetched = cFetched; - } - - return ( cMediaTypes==0 ? NOERROR : S_FALSE ); -} - - -/* Skip over one or more entries in the enumerator */ - -STDMETHODIMP -CEnumMediaTypes::Skip(ULONG cMediaTypes) -{ - // If we're skipping 0 elements we're guaranteed to skip the - // correct number of elements - if (cMediaTypes == 0) { - return S_OK; - } - - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - m_Position += cMediaTypes; - - /* See if we're over the end */ - CMediaType cmt; - return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE; -} - - -/* Set the current position back to the start */ -/* Reset has 3 simple steps: - * - * set position to head of list - * sync enumerator with object being enumerated - * return S_OK - */ - -STDMETHODIMP -CEnumMediaTypes::Reset() - -{ - m_Position = 0; - - // Bring the enumerator back into step with the current state. This - // may be a noop but ensures that the enumerator will be valid on the - // next call. - m_Version = m_pPin->GetMediaTypeVersion(); - return NOERROR; -} - - -//===================================================================== -//===================================================================== -// Implements CBasePin -//===================================================================== -//===================================================================== - - -/* NOTE The implementation of this class calls the CUnknown constructor with - a NULL outer unknown pointer. This has the effect of making us a self - contained class, ie any QueryInterface, AddRef or Release calls will be - routed to the class's NonDelegatingUnknown methods. You will typically - find that the classes that do this then override one or more of these - virtual functions to provide more specialised behaviour. A good example - of this is where a class wants to keep the QueryInterface internal but - still wants its lifetime controlled by the external object */ - -/* Constructor */ - -CBasePin::CBasePin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName, - PIN_DIRECTION dir) : - CUnknown( pObjectName, NULL ), - m_pFilter(pFilter), - m_pLock(pLock), - m_pName(NULL), - m_Connected(NULL), - m_dir(dir), - m_bRunTimeError(FALSE), - m_pQSink(NULL), - m_TypeVersion(1), - m_tStart(), - m_tStop(MAX_TIME), - m_bCanReconnectWhenActive(false), - m_bTryMyTypesFirst(false), - m_dRate(1.0) -{ - /* WARNING - pFilter is often not a properly constituted object at - this state (in particular QueryInterface may not work) - this - is because its owner is often its containing object and we - have been called from the containing object's constructor so - the filter's owner has not yet had its CUnknown constructor - called - */ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this ); -#endif // DXMPERF - - ASSERT(pFilter != NULL); - ASSERT(pLock != NULL); - - if (pName) { - size_t cchName; - HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName); - if (SUCCEEDED(hr)) { - m_pName = new WCHAR[cchName + 1]; - if (m_pName) { - (void)StringCchCopyW(m_pName, cchName + 1, pName); - } - } - } - -#ifdef _DEBUG - m_cRef = 0; -#endif -} - -#ifdef UNICODE -CBasePin::CBasePin(__in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName, - PIN_DIRECTION dir) : - CUnknown( pObjectName, NULL ), - m_pFilter(pFilter), - m_pLock(pLock), - m_pName(NULL), - m_Connected(NULL), - m_dir(dir), - m_bRunTimeError(FALSE), - m_pQSink(NULL), - m_TypeVersion(1), - m_tStart(), - m_tStop(MAX_TIME), - m_bCanReconnectWhenActive(false), - m_bTryMyTypesFirst(false), - m_dRate(1.0) -{ - /* WARNING - pFilter is often not a properly constituted object at - this state (in particular QueryInterface may not work) - this - is because its owner is often its containing object and we - have been called from the containing object's constructor so - the filter's owner has not yet had its CUnknown constructor - called - */ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this ); -#endif // DXMPERF - - ASSERT(pFilter != NULL); - ASSERT(pLock != NULL); - - if (pName) { - size_t cchName; - HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName); - if (SUCCEEDED(hr)) { - m_pName = new WCHAR[cchName + 1]; - if (m_pName) { - (void)StringCchCopyW(m_pName, cchName + 1, pName); - } - } - } - - -#ifdef _DEBUG - m_cRef = 0; -#endif -} -#endif - -/* Destructor since a connected pin holds a reference count on us there is - no way that we can be deleted unless we are not currently connected */ - -CBasePin::~CBasePin() -{ -#ifdef DXMPERF - PERFLOG_DTOR( m_pName ? m_pName : L"CBasePin", (IPin *) this ); -#endif // DXMPERF - - // We don't call disconnect because if the filter is going away - // all the pins must have a reference count of zero so they must - // have been disconnected anyway - (but check the assumption) - ASSERT(m_Connected == FALSE); - - delete[] m_pName; - - // check the internal reference count is consistent - ASSERT(m_cRef == 0); -} - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP -CBasePin::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) -{ - /* Do we have this interface */ - - if (riid == IID_IPin) { - return GetInterface((IPin *) this, ppv); - } else if (riid == IID_IQualityControl) { - return GetInterface((IQualityControl *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* Override to increment the owning filter's reference count */ - -STDMETHODIMP_(ULONG) -CBasePin::NonDelegatingAddRef() -{ - ASSERT(InterlockedIncrement(&m_cRef) > 0); - return m_pFilter->AddRef(); -} - - -/* Override to decrement the owning filter's reference count */ - -STDMETHODIMP_(ULONG) -CBasePin::NonDelegatingRelease() -{ - ASSERT(InterlockedDecrement(&m_cRef) >= 0); - return m_pFilter->Release(); -} - - -/* Displays pin connection information */ - -#ifdef _DEBUG -void -CBasePin::DisplayPinInfo(IPin *pReceivePin) -{ - - if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { - PIN_INFO ConnectPinInfo; - PIN_INFO ReceivePinInfo; - - if (FAILED(QueryPinInfo(&ConnectPinInfo))) { - StringCchCopyW(ConnectPinInfo.achName, sizeof(ConnectPinInfo.achName)/sizeof(WCHAR), L"Bad Pin"); - } else { - QueryPinInfoReleaseFilter(ConnectPinInfo); - } - - if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) { - StringCchCopyW(ReceivePinInfo.achName, sizeof(ReceivePinInfo.achName)/sizeof(WCHAR), L"Bad Pin"); - } else { - QueryPinInfoReleaseFilter(ReceivePinInfo); - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :"))); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName)); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName)); - } -} -#endif - - -/* Displays general information on the pin media type */ - -#ifdef _DEBUG -void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) -{ - UNREFERENCED_PARAMETER(pPin); - if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:"))); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"), - GuidNames[*pmt->Type()])); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"), - GuidNames[*pmt->Subtype()])); - } -} -#endif - -/* Asked to connect to a pin. A pin is always attached to an owning filter - object so we always delegate our locking to that object. We first of all - retrieve a media type enumerator for the input pin and see if we accept - any of the formats that it would ideally like, failing that we retrieve - our enumerator and see if it will accept any of our preferred types */ - -STDMETHODIMP -CBasePin::Connect( - IPin * pReceivePin, - __in_opt const AM_MEDIA_TYPE *pmt // optional media type -) -{ - CheckPointer(pReceivePin,E_POINTER); - ValidateReadPtr(pReceivePin,sizeof(IPin)); - CAutoLock cObjectLock(m_pLock); - DisplayPinInfo(pReceivePin); - - /* See if we are already connected */ - - if (m_Connected) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected"))); - return VFW_E_ALREADY_CONNECTED; - } - - /* See if the filter is active */ - if (!IsStopped() && !m_bCanReconnectWhenActive) { - return VFW_E_NOT_STOPPED; - } - - - // Find a mutually agreeable media type - - // Pass in the template media type. If this is partially specified, - // each of the enumerated media types will need to be checked against - // it. If it is non-null and fully specified, we will just try to connect - // with this. - - const CMediaType * ptype = (CMediaType*)pmt; - HRESULT hr = AgreeMediaType(pReceivePin, ptype); - if (FAILED(hr)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type"))); - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - -#ifdef DXMPERF - PERFLOG_CONNECT( (IPin *) this, pReceivePin, hr, pmt ); -#endif // DXMPERF - - return hr; - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded"))); - -#ifdef DXMPERF - PERFLOG_CONNECT( (IPin *) this, pReceivePin, NOERROR, pmt ); -#endif // DXMPERF - - return NOERROR; -} - -// given a specific media type, attempt a connection (includes -// checking that the type is acceptable to this pin) -HRESULT -CBasePin::AttemptConnection( - IPin* pReceivePin, // connect to this pin - const CMediaType* pmt // using this type -) -{ - // The caller should hold the filter lock becasue this function - // uses m_Connected. The caller should also hold the filter lock - // because this function calls SetMediaType(), IsStopped() and - // CompleteConnect(). - ASSERT(CritCheckIn(m_pLock)); - - // Check that the connection is valid -- need to do this for every - // connect attempt since BreakConnect will undo it. - HRESULT hr = CheckConnect(pReceivePin); - if (FAILED(hr)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed"))); - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - return hr; - } - - DisplayTypeInfo(pReceivePin, pmt); - - /* Check we will accept this media type */ - - hr = CheckMediaType(pmt); - if (hr == NOERROR) { - - /* Make ourselves look connected otherwise ReceiveConnection - may not be able to complete the connection - */ - m_Connected = pReceivePin; - m_Connected->AddRef(); - hr = SetMediaType(pmt); - if (SUCCEEDED(hr)) { - /* See if the other pin will accept this type */ - - hr = pReceivePin->ReceiveConnection((IPin *)this, pmt); - if (SUCCEEDED(hr)) { - /* Complete the connection */ - - hr = CompleteConnect(pReceivePin); - if (SUCCEEDED(hr)) { - return hr; - } else { - DbgLog((LOG_TRACE, - CONNECT_TRACE_LEVEL, - TEXT("Failed to complete connection"))); - pReceivePin->Disconnect(); - } - } - } - } else { - // we cannot use this media type - - // return a specific media type error if there is one - // or map a general failure code to something more helpful - // (in particular S_FALSE gets changed to an error code) - if (SUCCEEDED(hr) || - (hr == E_FAIL) || - (hr == E_INVALIDARG)) { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } - } - - // BreakConnect and release any connection here in case CheckMediaType - // failed, or if we set anything up during a call back during - // ReceiveConnection. - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - /* If failed then undo our state */ - if (m_Connected) { - m_Connected->Release(); - m_Connected = NULL; - } - - return hr; -} - -/* Given an enumerator we cycle through all the media types it proposes and - firstly suggest them to our derived pin class and if that succeeds try - them with the pin in a ReceiveConnection call. This means that if our pin - proposes a media type we still check in here that we can support it. This - is deliberate so that in simple cases the enumerator can hold all of the - media types even if some of them are not really currently available */ - -HRESULT CBasePin::TryMediaTypes( - IPin *pReceivePin, - __in_opt const CMediaType *pmt, - IEnumMediaTypes *pEnum) -{ - /* Reset the current enumerator position */ - - HRESULT hr = pEnum->Reset(); - if (FAILED(hr)) { - return hr; - } - - CMediaType *pMediaType = NULL; - ULONG ulMediaCount = 0; - - // attempt to remember a specific error code if there is one - HRESULT hrFailure = S_OK; - - for (;;) { - - /* Retrieve the next media type NOTE each time round the loop the - enumerator interface will allocate another AM_MEDIA_TYPE structure - If we are successful then we copy it into our output object, if - not then we must delete the memory allocated before returning */ - - hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount); - if (hr != S_OK) { - if (S_OK == hrFailure) { - hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; - } - return hrFailure; - } - - - ASSERT(ulMediaCount == 1); - ASSERT(pMediaType); - - // check that this matches the partial type (if any) - - if (pMediaType && - ((pmt == NULL) || - pMediaType->MatchesPartial(pmt))) { - - hr = AttemptConnection(pReceivePin, pMediaType); - - // attempt to remember a specific error code - if (FAILED(hr) && - SUCCEEDED(hrFailure) && - (hr != E_FAIL) && - (hr != E_INVALIDARG) && - (hr != VFW_E_TYPE_NOT_ACCEPTED)) { - hrFailure = hr; - } - } else { - hr = VFW_E_NO_ACCEPTABLE_TYPES; - } - - if(pMediaType) { - DeleteMediaType(pMediaType); - pMediaType = NULL; - } - - if (S_OK == hr) { - return hr; - } - } -} - - -/* This is called to make the connection, including the taask of finding - a media type for the pin connection. pmt is the proposed media type - from the Connect call: if this is fully specified, we will try that. - Otherwise we enumerate and try all the input pin's types first and - if that fails we then enumerate and try all our preferred media types. - For each media type we check it against pmt (if non-null and partially - specified) as well as checking that both pins will accept it. - */ - -HRESULT CBasePin::AgreeMediaType( - IPin *pReceivePin, - const CMediaType *pmt) -{ - ASSERT(pReceivePin); - IEnumMediaTypes *pEnumMediaTypes = NULL; - - // if the media type is fully specified then use that - if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) { - - // if this media type fails, then we must fail the connection - // since if pmt is nonnull we are only allowed to connect - // using a type that matches it. - - return AttemptConnection(pReceivePin, pmt); - } - - - /* Try the other pin's enumerator */ - - HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; - - for (int i = 0; i < 2; i++) { - HRESULT hr; - if (i == (int)m_bTryMyTypesFirst) { - hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes); - } else { - hr = EnumMediaTypes(&pEnumMediaTypes); - } - if (SUCCEEDED(hr)) { - ASSERT(pEnumMediaTypes); - hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes); - pEnumMediaTypes->Release(); - if (SUCCEEDED(hr)) { - return NOERROR; - } else { - // try to remember specific error codes if there are any - if ((hr != E_FAIL) && - (hr != E_INVALIDARG) && - (hr != VFW_E_TYPE_NOT_ACCEPTED)) { - hrFailure = hr; - } - } - } - } - - return hrFailure; -} - - -/* Called when we want to complete a connection to another filter. Failing - this will also fail the connection and disconnect the other pin as well */ - -HRESULT -CBasePin::CompleteConnect(IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - return NOERROR; -} - - -/* This is called to set the format for a pin connection - CheckMediaType - will have been called to check the connection format and if it didn't - return an error code then this (virtual) function will be invoked */ - -HRESULT -CBasePin::SetMediaType(const CMediaType *pmt) -{ - HRESULT hr = m_mt.Set(*pmt); - if (FAILED(hr)) { - return hr; - } - - return NOERROR; -} - - -/* This is called during Connect() to provide a virtual method that can do - any specific check needed for connection such as QueryInterface. This - base class method just checks that the pin directions don't match */ - -HRESULT -CBasePin::CheckConnect(IPin * pPin) -{ - /* Check that pin directions DONT match */ - - PIN_DIRECTION pd; - pPin->QueryDirection(&pd); - - ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT)); - ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT)); - - // we should allow for non-input and non-output connections? - if (pd == m_dir) { - return VFW_E_INVALID_DIRECTION; - } - return NOERROR; -} - - -/* This is called when we realise we can't make a connection to the pin and - must undo anything we did in CheckConnect - override to release QIs done */ - -HRESULT -CBasePin::BreakConnect() -{ - return NOERROR; -} - - -/* Called normally by an output pin on an input pin to try and establish a - connection. -*/ - -STDMETHODIMP -CBasePin::ReceiveConnection( - IPin * pConnector, // this is the pin who we will connect to - const AM_MEDIA_TYPE *pmt // this is the media type we will exchange -) -{ - CheckPointer(pConnector,E_POINTER); - CheckPointer(pmt,E_POINTER); - ValidateReadPtr(pConnector,sizeof(IPin)); - ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); - CAutoLock cObjectLock(m_pLock); - - /* Are we already connected */ - if (m_Connected) { - return VFW_E_ALREADY_CONNECTED; - } - - /* See if the filter is active */ - if (!IsStopped() && !m_bCanReconnectWhenActive) { - return VFW_E_NOT_STOPPED; - } - - HRESULT hr = CheckConnect(pConnector); - if (FAILED(hr)) { - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - -#ifdef DXMPERF - PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); -#endif // DXMPERF - - return hr; - } - - /* Ask derived class if this media type is ok */ - - CMediaType * pcmt = (CMediaType*) pmt; - hr = CheckMediaType(pcmt); - if (hr != NOERROR) { - // no -we don't support this media type - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - // return a specific media type error if there is one - // or map a general failure code to something more helpful - // (in particular S_FALSE gets changed to an error code) - if (SUCCEEDED(hr) || - (hr == E_FAIL) || - (hr == E_INVALIDARG)) { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } - -#ifdef DXMPERF - PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); -#endif // DXMPERF - - return hr; - } - - /* Complete the connection */ - - m_Connected = pConnector; - m_Connected->AddRef(); - hr = SetMediaType(pcmt); - if (SUCCEEDED(hr)) { - hr = CompleteConnect(pConnector); - if (SUCCEEDED(hr)) { - -#ifdef DXMPERF - PERFLOG_RXCONNECT( pConnector, (IPin *) this, NOERROR, pmt ); -#endif // DXMPERF - - return NOERROR; - } - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection."))); - m_Connected->Release(); - m_Connected = NULL; - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - -#ifdef DXMPERF - PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); -#endif // DXMPERF - - return hr; -} - - -/* Called when we want to terminate a pin connection */ - -STDMETHODIMP -CBasePin::Disconnect() -{ - CAutoLock cObjectLock(m_pLock); - - /* See if the filter is active */ - if (!IsStopped()) { - return VFW_E_NOT_STOPPED; - } - - return DisconnectInternal(); -} - -STDMETHODIMP -CBasePin::DisconnectInternal() -{ - ASSERT(CritCheckIn(m_pLock)); - - if (m_Connected) { - HRESULT hr = BreakConnect(); - if( FAILED( hr ) ) { - -#ifdef DXMPERF - PERFLOG_DISCONNECT( (IPin *) this, m_Connected, hr ); -#endif // DXMPERF - - // There is usually a bug in the program if BreakConnect() fails. - DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." ); - return hr; - } - - m_Connected->Release(); - m_Connected = NULL; - -#ifdef DXMPERF - PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_OK ); -#endif // DXMPERF - - return S_OK; - } else { - // no connection - not an error - -#ifdef DXMPERF - PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_FALSE ); -#endif // DXMPERF - - return S_FALSE; - } -} - - -/* Return an AddRef()'d pointer to the connected pin if there is one */ -STDMETHODIMP -CBasePin::ConnectedTo( - __deref_out IPin **ppPin -) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - // - // It's pointless to lock here. - // The caller should ensure integrity. - // - - IPin *pPin = m_Connected; - *ppPin = pPin; - if (pPin != NULL) { - pPin->AddRef(); - return S_OK; - } else { - ASSERT(*ppPin == NULL); - return VFW_E_NOT_CONNECTED; - } -} - -/* Return the media type of the connection */ -STDMETHODIMP -CBasePin::ConnectionMediaType( - __out AM_MEDIA_TYPE *pmt -) -{ - CheckPointer(pmt,E_POINTER); - ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE)); - CAutoLock cObjectLock(m_pLock); - - /* Copy constructor of m_mt allocates the memory */ - if (IsConnected()) { - CopyMediaType( pmt, &m_mt ); - return S_OK; - } else { - ((CMediaType *)pmt)->InitMediaType(); - return VFW_E_NOT_CONNECTED; - } -} - -/* Return information about the filter we are connect to */ - -STDMETHODIMP -CBasePin::QueryPinInfo( - __out PIN_INFO * pInfo -) -{ - CheckPointer(pInfo,E_POINTER); - ValidateReadWritePtr(pInfo,sizeof(PIN_INFO)); - - pInfo->pFilter = m_pFilter; - if (m_pFilter) { - m_pFilter->AddRef(); - } - - if (m_pName) { - (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); - } else { - pInfo->achName[0] = L'\0'; - } - - pInfo->dir = m_dir; - - return NOERROR; -} - -STDMETHODIMP -CBasePin::QueryDirection( - __out PIN_DIRECTION * pPinDir -) -{ - CheckPointer(pPinDir,E_POINTER); - ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION)); - - *pPinDir = m_dir; - return NOERROR; -} - -// Default QueryId to return the pin's name -STDMETHODIMP -CBasePin::QueryId( - __deref_out LPWSTR * Id -) -{ - // We're not going away because someone's got a pointer to us - // so there's no need to lock - - return AMGetWideString(Name(), Id); -} - -/* Does this pin support this media type WARNING this interface function does - not lock the main object as it is meant to be asynchronous by nature - if - the media types you support depend on some internal state that is updated - dynamically then you will need to implement locking in a derived class */ - -STDMETHODIMP -CBasePin::QueryAccept( - const AM_MEDIA_TYPE *pmt -) -{ - CheckPointer(pmt,E_POINTER); - ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); - - /* The CheckMediaType method is valid to return error codes if the media - type is horrible, an example might be E_INVALIDARG. What we do here - is map all the error codes into either S_OK or S_FALSE regardless */ - - HRESULT hr = CheckMediaType((CMediaType*)pmt); - if (FAILED(hr)) { - return S_FALSE; - } - // note that the only defined success codes should be S_OK and S_FALSE... - return hr; -} - - -/* This can be called to return an enumerator for the pin's list of preferred - media types. An input pin is not obliged to have any preferred formats - although it can do. For example, the window renderer has a preferred type - which describes a video image that matches the current window size. All - output pins should expose at least one preferred format otherwise it is - possible that neither pin has any types and so no connection is possible */ - -STDMETHODIMP -CBasePin::EnumMediaTypes( - __deref_out IEnumMediaTypes **ppEnum -) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); - - /* Create a new ref counted enumerator */ - - *ppEnum = new CEnumMediaTypes(this, - NULL); - - if (*ppEnum == NULL) { - return E_OUTOFMEMORY; - } - - return NOERROR; -} - - - -/* This is a virtual function that returns a media type corresponding with - place iPosition in the list. This base class simply returns an error as - we support no media types by default but derived classes should override */ - -HRESULT CBasePin::GetMediaType(int iPosition, __inout CMediaType *pMediaType) -{ - UNREFERENCED_PARAMETER(iPosition); - UNREFERENCED_PARAMETER(pMediaType); - return E_UNEXPECTED; -} - - -/* This is a virtual function that returns the current media type version. - The base class initialises the media type enumerators with the value 1 - By default we always returns that same value. A Derived class may change - the list of media types available and after doing so it should increment - the version either in a method derived from this, or more simply by just - incrementing the m_TypeVersion base pin variable. The type enumerators - call this when they want to see if their enumerations are out of date */ - -LONG CBasePin::GetMediaTypeVersion() -{ - return m_TypeVersion; -} - - -/* Increment the cookie representing the current media type version */ - -void CBasePin::IncrementTypeVersion() -{ - InterlockedIncrement(&m_TypeVersion); -} - - -/* Called by IMediaFilter implementation when the state changes from Stopped - to either paused or running and in derived classes could do things like - commit memory and grab hardware resource (the default is to do nothing) */ - -HRESULT -CBasePin::Active(void) -{ - return NOERROR; -} - -/* Called by IMediaFilter implementation when the state changes from - to either paused to running and in derived classes could do things like - commit memory and grab hardware resource (the default is to do nothing) */ - -HRESULT -CBasePin::Run(REFERENCE_TIME tStart) -{ - UNREFERENCED_PARAMETER(tStart); - return NOERROR; -} - - -/* Also called by the IMediaFilter implementation when the state changes to - Stopped at which point you should decommit allocators and free hardware - resources you grabbed in the Active call (default is also to do nothing) */ - -HRESULT -CBasePin::Inactive(void) -{ - m_bRunTimeError = FALSE; - return NOERROR; -} - - -// Called when no more data will arrive -STDMETHODIMP -CBasePin::EndOfStream(void) -{ - return S_OK; -} - - -STDMETHODIMP -CBasePin::SetSink(IQualityControl * piqc) -{ - CAutoLock cObjectLock(m_pLock); - if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl)); - m_pQSink = piqc; - return NOERROR; -} // SetSink - - -STDMETHODIMP -CBasePin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(q); - UNREFERENCED_PARAMETER(pSender); - DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)"); - return E_NOTIMPL; -} //Notify - - -// NewSegment notifies of the start/stop/rate applying to the data -// about to be received. Default implementation records data and -// returns S_OK. -// Override this to pass downstream. -STDMETHODIMP -CBasePin::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - m_tStart = tStart; - m_tStop = tStop; - m_dRate = dRate; - - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CBaseOutputPin -//===================================================================== -//===================================================================== - - -CBaseOutputPin::CBaseOutputPin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), - m_pAllocator(NULL), - m_pInputPin(NULL) -{ - ASSERT(pFilter); -} - -#ifdef UNICODE -CBaseOutputPin::CBaseOutputPin(__in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), - m_pAllocator(NULL), - m_pInputPin(NULL) -{ - ASSERT(pFilter); -} -#endif - -/* This is called after a media type has been proposed - - Try to complete the connection by agreeing the allocator -*/ -HRESULT -CBaseOutputPin::CompleteConnect(IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - return DecideAllocator(m_pInputPin, &m_pAllocator); -} - - -/* This method is called when the output pin is about to try and connect to - an input pin. It is at this point that you should try and grab any extra - interfaces that you need, in this case IMemInputPin. Because this is - only called if we are not currently connected we do NOT need to call - BreakConnect. This also makes it easier to derive classes from us as - BreakConnect is only called when we actually have to break a connection - (or a partly made connection) and not when we are checking a connection */ - -/* Overriden from CBasePin */ - -HRESULT -CBaseOutputPin::CheckConnect(IPin * pPin) -{ - HRESULT hr = CBasePin::CheckConnect(pPin); - if (FAILED(hr)) { - return hr; - } - - // get an input pin and an allocator interface - hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin); - if (FAILED(hr)) { - return hr; - } - return NOERROR; -} - - -/* Overriden from CBasePin */ - -HRESULT -CBaseOutputPin::BreakConnect() -{ - /* Release any allocator we hold */ - - if (m_pAllocator) { - // Always decommit the allocator because a downstream filter may or - // may not decommit the connection's allocator. A memory leak could - // occur if the allocator is not decommited when a connection is broken. - HRESULT hr = m_pAllocator->Decommit(); - if( FAILED( hr ) ) { - return hr; - } - - m_pAllocator->Release(); - m_pAllocator = NULL; - } - - /* Release any input pin interface we hold */ - - if (m_pInputPin) { - m_pInputPin->Release(); - m_pInputPin = NULL; - } - return NOERROR; -} - - -/* This is called when the input pin didn't give us a valid allocator */ - -HRESULT -CBaseOutputPin::InitAllocator(__deref_out IMemAllocator **ppAlloc) -{ - return CreateMemoryAllocator(ppAlloc); -} - - -/* Decide on an allocator, override this if you want to use your own allocator - Override DecideBufferSize to call SetProperties. If the input pin fails - the GetAllocator call then this will construct a CMemAllocator and call - DecideBufferSize on that, and if that fails then we are completely hosed. - If the you succeed the DecideBufferSize call, we will notify the input - pin of the selected allocator. NOTE this is called during Connect() which - therefore looks after grabbing and locking the object's critical section */ - -// We query the input pin for its requested properties and pass this to -// DecideBufferSize to allow it to fulfill requests that it is happy -// with (eg most people don't care about alignment and are thus happy to -// use the downstream pin's alignment request). - -HRESULT -CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, __deref_out IMemAllocator **ppAlloc) -{ - HRESULT hr = NOERROR; - *ppAlloc = NULL; - - // get downstream prop request - // the derived class may modify this in DecideBufferSize, but - // we assume that he will consistently modify it the same way, - // so we only get it once - ALLOCATOR_PROPERTIES prop; - ZeroMemory(&prop, sizeof(prop)); - - // whatever he returns, we assume prop is either all zeros - // or he has filled it out. - pPin->GetAllocatorRequirements(&prop); - - // if he doesn't care about alignment, then set it to 1 - if (prop.cbAlign == 0) { - prop.cbAlign = 1; - } - - /* Try the allocator provided by the input pin */ - - hr = pPin->GetAllocator(ppAlloc); - if (SUCCEEDED(hr)) { - - hr = DecideBufferSize(*ppAlloc, &prop); - if (SUCCEEDED(hr)) { - hr = pPin->NotifyAllocator(*ppAlloc, FALSE); - if (SUCCEEDED(hr)) { - return NOERROR; - } - } - } - - /* If the GetAllocator failed we may not have an interface */ - - if (*ppAlloc) { - (*ppAlloc)->Release(); - *ppAlloc = NULL; - } - - /* Try the output pin's allocator by the same method */ - - hr = InitAllocator(ppAlloc); - if (SUCCEEDED(hr)) { - - // note - the properties passed here are in the same - // structure as above and may have been modified by - // the previous call to DecideBufferSize - hr = DecideBufferSize(*ppAlloc, &prop); - if (SUCCEEDED(hr)) { - hr = pPin->NotifyAllocator(*ppAlloc, FALSE); - if (SUCCEEDED(hr)) { - return NOERROR; - } - } - } - - /* Likewise we may not have an interface to release */ - - if (*ppAlloc) { - (*ppAlloc)->Release(); - *ppAlloc = NULL; - } - return hr; -} - - -/* This returns an empty sample buffer from the allocator WARNING the same - dangers and restrictions apply here as described below for Deliver() */ - -HRESULT -CBaseOutputPin::GetDeliveryBuffer(__deref_out IMediaSample ** ppSample, - __in_opt REFERENCE_TIME * pStartTime, - __in_opt REFERENCE_TIME * pEndTime, - DWORD dwFlags) -{ - if (m_pAllocator != NULL) { - return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags); - } else { - return E_NOINTERFACE; - } -} - - -/* Deliver a filled-in sample to the connected input pin. NOTE the object must - have locked itself before calling us otherwise we may get halfway through - executing this method only to find the filter graph has got in and - disconnected us from the input pin. If the filter has no worker threads - then the lock is best applied on Receive(), otherwise it should be done - when the worker thread is ready to deliver. There is a wee snag to worker - threads that this shows up. The worker thread must lock the object when - it is ready to deliver a sample, but it may have to wait until a state - change has completed, but that may never complete because the state change - is waiting for the worker thread to complete. The way to handle this is for - the state change code to grab the critical section, then set an abort event - for the worker thread, then release the critical section and wait for the - worker thread to see the event we set and then signal that it has finished - (with another event). At which point the state change code can complete */ - -// note (if you've still got any breath left after reading that) that you -// need to release the sample yourself after this call. if the connected -// input pin needs to hold onto the sample beyond the call, it will addref -// the sample itself. - -// of course you must release this one and call GetDeliveryBuffer for the -// next. You cannot reuse it directly. - -HRESULT -CBaseOutputPin::Deliver(IMediaSample * pSample) -{ - if (m_pInputPin == NULL) { - return VFW_E_NOT_CONNECTED; - } - -#ifdef DXMPERF - PERFLOG_DELIVER( m_pName ? m_pName : L"CBaseOutputPin", (IPin *) this, (IPin *) m_pInputPin, pSample, &m_mt ); -#endif // DXMPERF - - return m_pInputPin->Receive(pSample); -} - - -// called from elsewhere in our filter to pass EOS downstream to -// our connected input pin -HRESULT -CBaseOutputPin::DeliverEndOfStream(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->EndOfStream(); -} - - -/* Commit the allocator's memory, this is called through IMediaFilter - which is responsible for locking the object before calling us */ - -HRESULT -CBaseOutputPin::Active(void) -{ - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - return m_pAllocator->Commit(); -} - - -/* Free up or unprepare allocator's memory, this is called through - IMediaFilter which is responsible for locking the object first */ - -HRESULT -CBaseOutputPin::Inactive(void) -{ - m_bRunTimeError = FALSE; - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - return m_pAllocator->Decommit(); -} - -// we have a default handling of EndOfStream which is to return -// an error, since this should be called on input pins only -STDMETHODIMP -CBaseOutputPin::EndOfStream(void) -{ - return E_UNEXPECTED; -} - - -// BeginFlush should be called on input pins only -STDMETHODIMP -CBaseOutputPin::BeginFlush(void) -{ - return E_UNEXPECTED; -} - -// EndFlush should be called on input pins only -STDMETHODIMP -CBaseOutputPin::EndFlush(void) -{ - return E_UNEXPECTED; -} - -// call BeginFlush on the connected input pin -HRESULT -CBaseOutputPin::DeliverBeginFlush(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->BeginFlush(); -} - -// call EndFlush on the connected input pin -HRESULT -CBaseOutputPin::DeliverEndFlush(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->EndFlush(); -} -// deliver NewSegment to connected pin -HRESULT -CBaseOutputPin::DeliverNewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->NewSegment(tStart, tStop, dRate); -} - - -//===================================================================== -//===================================================================== -// Implements CBaseInputPin -//===================================================================== -//===================================================================== - - -/* Constructor creates a default allocator object */ - -CBaseInputPin::CBaseInputPin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pPinName) : - CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), - m_pAllocator(NULL), - m_bReadOnly(FALSE), - m_bFlushing(FALSE) -{ - ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); -} - -#ifdef UNICODE -CBaseInputPin::CBaseInputPin(__in LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pPinName) : - CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), - m_pAllocator(NULL), - m_bReadOnly(FALSE), - m_bFlushing(FALSE) -{ - ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); -} -#endif - -/* Destructor releases it's reference count on the default allocator */ - -CBaseInputPin::~CBaseInputPin() -{ - if (m_pAllocator != NULL) { - m_pAllocator->Release(); - m_pAllocator = NULL; - } -} - - -// override this to publicise our interfaces -STDMETHODIMP -CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - /* Do we know about this interface */ - - if (riid == IID_IMemInputPin) { - return GetInterface((IMemInputPin *) this, ppv); - } else { - return CBasePin::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* Return the allocator interface that this input pin would like the output - pin to use. NOTE subsequent calls to GetAllocator should all return an - interface onto the SAME object so we create one object at the start - - Note: - The allocator is Release()'d on disconnect and replaced on - NotifyAllocator(). - - Override this to provide your own allocator. -*/ - -STDMETHODIMP -CBaseInputPin::GetAllocator( - __deref_out IMemAllocator **ppAllocator) -{ - CheckPointer(ppAllocator,E_POINTER); - ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pAllocator == NULL) { - HRESULT hr = CreateMemoryAllocator(&m_pAllocator); - if (FAILED(hr)) { - return hr; - } - } - ASSERT(m_pAllocator != NULL); - *ppAllocator = m_pAllocator; - m_pAllocator->AddRef(); - return NOERROR; -} - - -/* Tell the input pin which allocator the output pin is actually going to use - Override this if you care - NOTE the locking we do both here and also in - GetAllocator is unnecessary but derived classes that do something useful - will undoubtedly have to lock the object so this might help remind people */ - -STDMETHODIMP -CBaseInputPin::NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly) -{ - CheckPointer(pAllocator,E_POINTER); - ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); - CAutoLock cObjectLock(m_pLock); - - IMemAllocator *pOldAllocator = m_pAllocator; - pAllocator->AddRef(); - m_pAllocator = pAllocator; - - if (pOldAllocator != NULL) { - pOldAllocator->Release(); - } - - // the readonly flag indicates whether samples from this allocator should - // be regarded as readonly - if true, then inplace transforms will not be - // allowed. - m_bReadOnly = (BYTE)bReadOnly; - return NOERROR; -} - - -HRESULT -CBaseInputPin::BreakConnect() -{ - /* We don't need our allocator any more */ - if (m_pAllocator) { - // Always decommit the allocator because a downstream filter may or - // may not decommit the connection's allocator. A memory leak could - // occur if the allocator is not decommited when a pin is disconnected. - HRESULT hr = m_pAllocator->Decommit(); - if( FAILED( hr ) ) { - return hr; - } - - m_pAllocator->Release(); - m_pAllocator = NULL; - } - - return S_OK; -} - - -/* Do something with this media sample - this base class checks to see if the - format has changed with this media sample and if so checks that the filter - will accept it, generating a run time error if not. Once we have raised a - run time error we set a flag so that no more samples will be accepted - - It is important that any filter should override this method and implement - synchronization so that samples are not processed when the pin is - disconnected etc -*/ - -STDMETHODIMP -CBaseInputPin::Receive(IMediaSample *pSample) -{ - CheckPointer(pSample,E_POINTER); - ValidateReadPtr(pSample,sizeof(IMediaSample)); - ASSERT(pSample); - - HRESULT hr = CheckStreaming(); - if (S_OK != hr) { - return hr; - } - -#ifdef DXMPERF - PERFLOG_RECEIVE( m_pName ? m_pName : L"CBaseInputPin", (IPin *) m_Connected, (IPin *) this, pSample, &m_mt ); -#endif // DXMPERF - - - /* Check for IMediaSample2 */ - IMediaSample2 *pSample2; - if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { - hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps); - pSample2->Release(); - if (FAILED(hr)) { - return hr; - } - } else { - /* Get the properties the hard way */ - m_SampleProps.cbData = sizeof(m_SampleProps); - m_SampleProps.dwTypeSpecificFlags = 0; - m_SampleProps.dwStreamId = AM_STREAM_MEDIA; - m_SampleProps.dwSampleFlags = 0; - if (S_OK == pSample->IsDiscontinuity()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; - } - if (S_OK == pSample->IsPreroll()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL; - } - if (S_OK == pSample->IsSyncPoint()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; - } - if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart, - &m_SampleProps.tStop))) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID | - AM_SAMPLE_STOPVALID; - } - if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED; - } - pSample->GetPointer(&m_SampleProps.pbBuffer); - m_SampleProps.lActual = pSample->GetActualDataLength(); - m_SampleProps.cbBuffer = pSample->GetSize(); - } - - /* Has the format changed in this sample */ - - if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) { - return NOERROR; - } - - /* Check the derived class accepts this format */ - /* This shouldn't fail as the source must call QueryAccept first */ - - hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType); - - if (hr == NOERROR) { - return NOERROR; - } - - /* Raise a runtime error if we fail the media type */ - - m_bRunTimeError = TRUE; - EndOfStream(); - m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0); - return VFW_E_INVALIDMEDIATYPE; -} - - -/* Receive multiple samples */ -STDMETHODIMP -CBaseInputPin::ReceiveMultiple ( - __in_ecount(nSamples) IMediaSample **pSamples, - long nSamples, - __out long *nSamplesProcessed) -{ - CheckPointer(pSamples,E_POINTER); - ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *)); - - HRESULT hr = S_OK; - *nSamplesProcessed = 0; - while (nSamples-- > 0) { - hr = Receive(pSamples[*nSamplesProcessed]); - - /* S_FALSE means don't send any more */ - if (hr != S_OK) { - break; - } - (*nSamplesProcessed)++; - } - return hr; -} - -/* See if Receive() might block */ -STDMETHODIMP -CBaseInputPin::ReceiveCanBlock() -{ - /* Ask all the output pins if they block - If there are no output pin assume we do block - */ - int cPins = m_pFilter->GetPinCount(); - int cOutputPins = 0; - for (int c = 0; c < cPins; c++) { - CBasePin *pPin = m_pFilter->GetPin(c); - if (NULL == pPin) { - break; - } - PIN_DIRECTION pd; - HRESULT hr = pPin->QueryDirection(&pd); - if (FAILED(hr)) { - return hr; - } - - if (pd == PINDIR_OUTPUT) { - - IPin *pConnected; - hr = pPin->ConnectedTo(&pConnected); - if (SUCCEEDED(hr)) { - ASSERT(pConnected != NULL); - cOutputPins++; - IMemInputPin *pInputPin; - hr = pConnected->QueryInterface( - IID_IMemInputPin, - (void **)&pInputPin); - pConnected->Release(); - if (SUCCEEDED(hr)) { - hr = pInputPin->ReceiveCanBlock(); - pInputPin->Release(); - if (hr != S_FALSE) { - return S_OK; - } - } else { - /* There's a transport we don't understand here */ - return S_OK; - } - } - } - } - return cOutputPins == 0 ? S_OK : S_FALSE; -} - -// Default handling for BeginFlush - call at the beginning -// of your implementation (makes sure that all Receive calls -// fail). After calling this, you need to free any queued data -// and then call downstream. -STDMETHODIMP -CBaseInputPin::BeginFlush(void) -{ - // BeginFlush is NOT synchronized with streaming but is part of - // a control action - hence we synchronize with the filter - CAutoLock lck(m_pLock); - - // if we are already in mid-flush, this is probably a mistake - // though not harmful - try to pick it up for now so I can think about it - ASSERT(!m_bFlushing); - - // first thing to do is ensure that no further Receive calls succeed - m_bFlushing = TRUE; - - // now discard any data and call downstream - must do that - // in derived classes - return S_OK; -} - -// default handling for EndFlush - call at end of your implementation -// - before calling this, ensure that there is no queued data and no thread -// pushing any more without a further receive, then call downstream, -// then call this method to clear the m_bFlushing flag and re-enable -// receives -STDMETHODIMP -CBaseInputPin::EndFlush(void) -{ - // Endlush is NOT synchronized with streaming but is part of - // a control action - hence we synchronize with the filter - CAutoLock lck(m_pLock); - - // almost certainly a mistake if we are not in mid-flush - ASSERT(m_bFlushing); - - // before calling, sync with pushing thread and ensure - // no more data is going downstream, then call EndFlush on - // downstream pins. - - // now re-enable Receives - m_bFlushing = FALSE; - - // No more errors - m_bRunTimeError = FALSE; - - return S_OK; -} - - -STDMETHODIMP -CBaseInputPin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(q); - CheckPointer(pSender,E_POINTER); - ValidateReadPtr(pSender,sizeof(IBaseFilter)); - DbgBreak("IQuality::Notify called on an input pin"); - return NOERROR; -} // Notify - -/* Free up or unprepare allocator's memory, this is called through - IMediaFilter which is responsible for locking the object first */ - -HRESULT -CBaseInputPin::Inactive(void) -{ - m_bRunTimeError = FALSE; - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - - m_bFlushing = FALSE; - - return m_pAllocator->Decommit(); -} - -// what requirements do we have of the allocator - override if you want -// to support other people's allocators but need a specific alignment -// or prefix. -STDMETHODIMP -CBaseInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps) -{ - UNREFERENCED_PARAMETER(pProps); - return E_NOTIMPL; -} - -// Check if it's OK to process data -// -HRESULT -CBaseInputPin::CheckStreaming() -{ - // Shouldn't be able to get any data if we're not connected! - ASSERT(IsConnected()); - - // Don't process stuff in Stopped state - if (IsStopped()) { - return VFW_E_WRONG_STATE; - } - if (m_bFlushing) { - return S_FALSE; - } - if (m_bRunTimeError) { - return VFW_E_RUNTIME_ERROR; - } - return S_OK; -} - -// Pass on the Quality notification q to -// a. Our QualityControl sink (if we have one) or else -// b. to our upstream filter -// and if that doesn't work, throw it away with a bad return code -HRESULT -CBaseInputPin::PassNotify(Quality& q) -{ - // We pass the message on, which means that we find the quality sink - // for our input pin and send it there - - DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform"))); - if (m_pQSink!=NULL) { - return m_pQSink->Notify(m_pFilter, q); - } else { - // no sink set, so pass it upstream - HRESULT hr; - IQualityControl * pIQC; - - hr = VFW_E_NOT_FOUND; // default - if (m_Connected) { - m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC); - - if (pIQC!=NULL) { - hr = pIQC->Notify(m_pFilter, q); - pIQC->Release(); - } - } - return hr; - } - -} // PassNotify - -//===================================================================== -//===================================================================== -// Memory allocation class, implements CMediaSample -//===================================================================== -//===================================================================== - - -/* NOTE The implementation of this class calls the CUnknown constructor with - a NULL outer unknown pointer. This has the effect of making us a self - contained class, ie any QueryInterface, AddRef or Release calls will be - routed to the class's NonDelegatingUnknown methods. You will typically - find that the classes that do this then override one or more of these - virtual functions to provide more specialised behaviour. A good example - of this is where a class wants to keep the QueryInterface internal but - still wants it's lifetime controlled by the external object */ - -/* The last two parameters have default values of NULL and zero */ - -CMediaSample::CMediaSample(__in_opt LPCTSTR pName, - __in_opt CBaseAllocator *pAllocator, - __inout_opt HRESULT *phr, - __in_bcount_opt(length) LPBYTE pBuffer, - LONG length) : - m_pBuffer(pBuffer), // Initialise the buffer - m_cbBuffer(length), // And it's length - m_lActual(length), // By default, actual = length - m_pMediaType(NULL), // No media type change - m_dwFlags(0), // Nothing set - m_cRef(0), // 0 ref count - m_dwTypeSpecificFlags(0), // Type specific flags - m_dwStreamId(AM_STREAM_MEDIA), // Stream id - m_pAllocator(pAllocator), // Allocator - m_pNext(NULL), - m_Start(0), - m_End(0), - m_MediaStart(0), - m_MediaEnd(0) -{ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CMediaSample", (IMediaSample *) this ); -#endif // DXMPERF - - /* We must have an owner and it must also be derived from class - CBaseAllocator BUT we do not hold a reference count on it */ - - ASSERT(pAllocator); - - if (length < 0) { - *phr = VFW_E_BUFFER_OVERFLOW; - m_cbBuffer = 0; - } -} - -#ifdef UNICODE -CMediaSample::CMediaSample(__in_opt LPCSTR pName, - __in_opt CBaseAllocator *pAllocator, - __inout_opt HRESULT *phr, - __in_bcount_opt(length) LPBYTE pBuffer, - LONG length) : - m_pBuffer(pBuffer), // Initialise the buffer - m_cbBuffer(length), // And it's length - m_lActual(length), // By default, actual = length - m_pMediaType(NULL), // No media type change - m_dwFlags(0), // Nothing set - m_cRef(0), // 0 ref count - m_dwTypeSpecificFlags(0), // Type specific flags - m_dwStreamId(AM_STREAM_MEDIA), // Stream id - m_pAllocator(pAllocator), // Allocator - m_pNext(NULL), - m_Start(0), - m_End(0), - m_MediaStart(0), - m_MediaEnd(0) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CMediaSample", (IMediaSample *) this ); -#endif // DXMPERF - - /* We must have an owner and it must also be derived from class - CBaseAllocator BUT we do not hold a reference count on it */ - - ASSERT(pAllocator); -} -#endif - -/* Destructor deletes the media type memory */ - -CMediaSample::~CMediaSample() -{ -#ifdef DXMPERF - PERFLOG_DTOR( L"CMediaSample", (IMediaSample *) this ); -#endif // DXMPERF - - if (m_pMediaType) { - DeleteMediaType(m_pMediaType); - } -} - -/* Override this to publicise our interfaces */ - -STDMETHODIMP -CMediaSample::QueryInterface(REFIID riid, __deref_out void **ppv) -{ - if (riid == IID_IMediaSample || - riid == IID_IMediaSample2 || - riid == IID_IUnknown) { - return GetInterface((IMediaSample *) this, ppv); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CMediaSample::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - - -// -- CMediaSample lifetimes -- -// -// On final release of this sample buffer it is not deleted but -// returned to the freelist of the owning memory allocator -// -// The allocator may be waiting for the last buffer to be placed on the free -// list in order to decommit all the memory, so the ReleaseBuffer() call may -// result in this sample being deleted. We also need to hold a refcount on -// the allocator to stop that going away until we have finished with this. -// However, we cannot release the allocator before the ReleaseBuffer, as the -// release may cause us to be deleted. Similarly we can't do it afterwards. -// -// Thus we must leave it to the allocator to hold an addref on our behalf. -// When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer -// is called, he releases himself, possibly causing us and him to be deleted. - - -STDMETHODIMP_(ULONG) -CMediaSample::Release() -{ - /* Decrement our own private reference count */ - LONG lRef; - if (m_cRef == 1) { - lRef = 0; - m_cRef = 0; - } else { - lRef = InterlockedDecrement(&m_cRef); - } - ASSERT(lRef >= 0); - - DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"), - this, m_cRef)); - - /* Did we release our final reference count */ - if (lRef == 0) { - /* Free all resources */ - if (m_dwFlags & Sample_TypeChanged) { - SetMediaType(NULL); - } - ASSERT(m_pMediaType == NULL); - m_dwFlags = 0; - m_dwTypeSpecificFlags = 0; - m_dwStreamId = AM_STREAM_MEDIA; - - /* This may cause us to be deleted */ - // Our refcount is reliably 0 thus no-one will mess with us - m_pAllocator->ReleaseBuffer(this); - } - return (ULONG)lRef; -} - - -// set the buffer pointer and length. Used by allocators that -// want variable sized pointers or pointers into already-read data. -// This is only available through a CMediaSample* not an IMediaSample* -// and so cannot be changed by clients. -HRESULT -CMediaSample::SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes) -{ - if (cBytes < 0) { - return VFW_E_BUFFER_OVERFLOW; - } - m_pBuffer = ptr; // new buffer area (could be null) - m_cbBuffer = cBytes; // length of buffer - m_lActual = cBytes; // length of data in buffer (assume full) - - return S_OK; -} - - -// get me a read/write pointer to this buffer's memory. I will actually -// want to use sizeUsed bytes. -STDMETHODIMP -CMediaSample::GetPointer(__deref_out BYTE ** ppBuffer) -{ - ValidateReadWritePtr(ppBuffer,sizeof(BYTE *)); - - // creator must have set pointer either during - // constructor or by SetPointer - ASSERT(m_pBuffer); - - *ppBuffer = m_pBuffer; - return NOERROR; -} - - -// return the size in bytes of this buffer -STDMETHODIMP_(LONG) -CMediaSample::GetSize(void) -{ - return m_cbBuffer; -} - - -// get the stream time at which this sample should start and finish. -STDMETHODIMP -CMediaSample::GetTime( - __out REFERENCE_TIME * pTimeStart, // put time here - __out REFERENCE_TIME * pTimeEnd -) -{ - ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME)); - ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME)); - - if (!(m_dwFlags & Sample_StopValid)) { - if (!(m_dwFlags & Sample_TimeValid)) { - return VFW_E_SAMPLE_TIME_NOT_SET; - } else { - *pTimeStart = m_Start; - - // Make sure old stuff works - *pTimeEnd = m_Start + 1; - return VFW_S_NO_STOP_TIME; - } - } - - *pTimeStart = m_Start; - *pTimeEnd = m_End; - return NOERROR; -} - - -// Set the stream time at which this sample should start and finish. -// NULL pointers means the time is reset -STDMETHODIMP -CMediaSample::SetTime( - __in_opt REFERENCE_TIME * pTimeStart, - __in_opt REFERENCE_TIME * pTimeEnd -) -{ - if (pTimeStart == NULL) { - ASSERT(pTimeEnd == NULL); - m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid); - } else { - if (pTimeEnd == NULL) { - m_Start = *pTimeStart; - m_dwFlags |= Sample_TimeValid; - m_dwFlags &= ~Sample_StopValid; - } else { - ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME)); - ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME)); - ASSERT(*pTimeEnd >= *pTimeStart); - - m_Start = *pTimeStart; - m_End = *pTimeEnd; - m_dwFlags |= Sample_TimeValid | Sample_StopValid; - } - } - return NOERROR; -} - - -// get the media times (eg bytes) for this sample -STDMETHODIMP -CMediaSample::GetMediaTime( - __out LONGLONG * pTimeStart, - __out LONGLONG * pTimeEnd -) -{ - ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG)); - ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG)); - - if (!(m_dwFlags & Sample_MediaTimeValid)) { - return VFW_E_MEDIA_TIME_NOT_SET; - } - - *pTimeStart = m_MediaStart; - *pTimeEnd = (m_MediaStart + m_MediaEnd); - return NOERROR; -} - - -// Set the media times for this sample -STDMETHODIMP -CMediaSample::SetMediaTime( - __in_opt LONGLONG * pTimeStart, - __in_opt LONGLONG * pTimeEnd -) -{ - if (pTimeStart == NULL) { - ASSERT(pTimeEnd == NULL); - m_dwFlags &= ~Sample_MediaTimeValid; - } else { - if (NULL == pTimeEnd) { - return E_POINTER; - } - ValidateReadPtr(pTimeStart,sizeof(LONGLONG)); - ValidateReadPtr(pTimeEnd,sizeof(LONGLONG)); - ASSERT(*pTimeEnd >= *pTimeStart); - - m_MediaStart = *pTimeStart; - m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart); - m_dwFlags |= Sample_MediaTimeValid; - } - return NOERROR; -} - - -STDMETHODIMP -CMediaSample::IsSyncPoint(void) -{ - if (m_dwFlags & Sample_SyncPoint) { - return S_OK; - } else { - return S_FALSE; - } -} - - -STDMETHODIMP -CMediaSample::SetSyncPoint(BOOL bIsSyncPoint) -{ - if (bIsSyncPoint) { - m_dwFlags |= Sample_SyncPoint; - } else { - m_dwFlags &= ~Sample_SyncPoint; - } - return NOERROR; -} - -// returns S_OK if there is a discontinuity in the data (this same is -// not a continuation of the previous stream of data -// - there has been a seek). -STDMETHODIMP -CMediaSample::IsDiscontinuity(void) -{ - if (m_dwFlags & Sample_Discontinuity) { - return S_OK; - } else { - return S_FALSE; - } -} - -// set the discontinuity property - TRUE if this sample is not a -// continuation, but a new sample after a seek. -STDMETHODIMP -CMediaSample::SetDiscontinuity(BOOL bDiscont) -{ - // should be TRUE or FALSE - if (bDiscont) { - m_dwFlags |= Sample_Discontinuity; - } else { - m_dwFlags &= ~Sample_Discontinuity; - } - return S_OK; -} - -STDMETHODIMP -CMediaSample::IsPreroll(void) -{ - if (m_dwFlags & Sample_Preroll) { - return S_OK; - } else { - return S_FALSE; - } -} - - -STDMETHODIMP -CMediaSample::SetPreroll(BOOL bIsPreroll) -{ - if (bIsPreroll) { - m_dwFlags |= Sample_Preroll; - } else { - m_dwFlags &= ~Sample_Preroll; - } - return NOERROR; -} - -STDMETHODIMP_(LONG) -CMediaSample::GetActualDataLength(void) -{ - return m_lActual; -} - - -STDMETHODIMP -CMediaSample::SetActualDataLength(LONG lActual) -{ - if (lActual > m_cbBuffer || lActual < 0) { - ASSERT(lActual <= GetSize()); - return VFW_E_BUFFER_OVERFLOW; - } - m_lActual = lActual; - return NOERROR; -} - - -/* These allow for limited format changes in band */ - -STDMETHODIMP -CMediaSample::GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType) -{ - ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *)); - ASSERT(ppMediaType); - - /* Do we have a new media type for them */ - - if (!(m_dwFlags & Sample_TypeChanged)) { - ASSERT(m_pMediaType == NULL); - *ppMediaType = NULL; - return S_FALSE; - } - - ASSERT(m_pMediaType); - - /* Create a copy of our media type */ - - *ppMediaType = CreateMediaType(m_pMediaType); - if (*ppMediaType == NULL) { - return E_OUTOFMEMORY; - } - return NOERROR; -} - - -/* Mark this sample as having a different format type */ - -STDMETHODIMP -CMediaSample::SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType) -{ - /* Delete the current media type */ - - if (m_pMediaType) { - DeleteMediaType(m_pMediaType); - m_pMediaType = NULL; - } - - /* Mechanism for resetting the format type */ - - if (pMediaType == NULL) { - m_dwFlags &= ~Sample_TypeChanged; - return NOERROR; - } - - ASSERT(pMediaType); - ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE)); - - /* Take a copy of the media type */ - - m_pMediaType = CreateMediaType(pMediaType); - if (m_pMediaType == NULL) { - m_dwFlags &= ~Sample_TypeChanged; - return E_OUTOFMEMORY; - } - - m_dwFlags |= Sample_TypeChanged; - return NOERROR; -} - -// Set and get properties (IMediaSample2) -STDMETHODIMP CMediaSample::GetProperties( - DWORD cbProperties, - __out_bcount(cbProperties) BYTE * pbProperties -) -{ - if (0 != cbProperties) { - CheckPointer(pbProperties, E_POINTER); - // Return generic stuff up to the length - AM_SAMPLE2_PROPERTIES Props; - Props.cbData = std::min(cbProperties, (ULONG)sizeof(Props)); - Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid; - Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags; - Props.pbBuffer = m_pBuffer; - Props.cbBuffer = m_cbBuffer; - Props.lActual = m_lActual; - Props.tStart = m_Start; - Props.tStop = m_End; - Props.dwStreamId = m_dwStreamId; - if (m_dwFlags & AM_SAMPLE_TYPECHANGED) { - Props.pMediaType = m_pMediaType; - } else { - Props.pMediaType = NULL; - } - CopyMemory(pbProperties, &Props, Props.cbData); - } - return S_OK; -} - -#define CONTAINS_FIELD(type, field, offset) \ - ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset) - -HRESULT CMediaSample::SetProperties( - DWORD cbProperties, - __in_bcount(cbProperties) const BYTE * pbProperties -) -{ - - /* Generic properties */ - AM_MEDIA_TYPE *pMediaType = NULL; - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) { - CheckPointer(pbProperties, E_POINTER); - AM_SAMPLE2_PROPERTIES *pProps = - (AM_SAMPLE2_PROPERTIES *)pbProperties; - - /* Don't use more data than is actually there */ - if (pProps->cbData < cbProperties) { - cbProperties = pProps->cbData; - } - /* We only handle IMediaSample2 */ - if (cbProperties > sizeof(*pProps) || - pProps->cbData > sizeof(*pProps)) { - return E_INVALIDARG; - } - /* Do checks first, the assignments (for backout) */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { - /* Check the flags */ - if (pProps->dwSampleFlags & - (~Sample_ValidFlags | Sample_MediaTimeValid)) { - return E_INVALIDARG; - } - /* Check a flag isn't being set for a property - not being provided - */ - if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) && - !(m_dwFlags & AM_SAMPLE_TIMEVALID) && - !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { - return E_INVALIDARG; - } - } - /* NB - can't SET the pointer or size */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) { - - /* Check pbBuffer */ - if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) { - return E_INVALIDARG; - } - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) { - - /* Check cbBuffer */ - if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) { - return E_INVALIDARG; - } - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) && - CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { - - /* Check lActual */ - if (pProps->cbBuffer < pProps->lActual) { - return E_INVALIDARG; - } - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { - - /* Check pMediaType */ - if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { - CheckPointer(pProps->pMediaType, E_POINTER); - pMediaType = CreateMediaType(pProps->pMediaType); - if (pMediaType == NULL) { - return E_OUTOFMEMORY; - } - } - } - - /* Now do the assignments */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) { - m_dwStreamId = pProps->dwStreamId; - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { - /* Set the flags */ - m_dwFlags = pProps->dwSampleFlags | - (m_dwFlags & Sample_MediaTimeValid); - m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - } else { - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) { - m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - } - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { - /* Set lActual */ - m_lActual = pProps->lActual; - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { - - /* Set the times */ - m_End = pProps->tStop; - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) { - - /* Set the times */ - m_Start = pProps->tStart; - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { - /* Set pMediaType */ - if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { - if (m_pMediaType != NULL) { - DeleteMediaType(m_pMediaType); - } - m_pMediaType = pMediaType; - } - } - - /* Fix up the type changed flag to correctly reflect the current state - If, for instance the input contained no type change but the - output does then if we don't do this we'd lose the - output media type. - */ - if (m_pMediaType) { - m_dwFlags |= Sample_TypeChanged; - } else { - m_dwFlags &= ~Sample_TypeChanged; - } - } - - return S_OK; -} - - -// -// The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(), -// IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the -// connected input pin. The application thread calls Block(). The -// following class members can only be called by the streaming thread. -// -// Deliver() -// DeliverNewSegment() -// StartUsingOutputPin() -// StopUsingOutputPin() -// ChangeOutputFormat() -// ChangeMediaType() -// DynamicReconnect() -// -// The following class members can only be called by the application thread. -// -// Block() -// SynchronousBlockOutputPin() -// AsynchronousBlockOutputPin() -// - -CDynamicOutputPin::CDynamicOutputPin( - __in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), - m_hStopEvent(NULL), - m_pGraphConfig(NULL), - m_bPinUsesReadOnlyAllocator(FALSE), - m_BlockState(NOT_BLOCKED), - m_hUnblockOutputPinEvent(NULL), - m_hNotifyCallerPinBlockedEvent(NULL), - m_dwBlockCallerThreadID(0), - m_dwNumOutstandingOutputPinUsers(0) -{ - HRESULT hr = Initialize(); - if( FAILED( hr ) ) { - *phr = hr; - return; - } -} - -#ifdef UNICODE -CDynamicOutputPin::CDynamicOutputPin( - __in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), - m_hStopEvent(NULL), - m_pGraphConfig(NULL), - m_bPinUsesReadOnlyAllocator(FALSE), - m_BlockState(NOT_BLOCKED), - m_hUnblockOutputPinEvent(NULL), - m_hNotifyCallerPinBlockedEvent(NULL), - m_dwBlockCallerThreadID(0), - m_dwNumOutstandingOutputPinUsers(0) -{ - HRESULT hr = Initialize(); - if( FAILED( hr ) ) { - *phr = hr; - return; - } -} -#endif - -CDynamicOutputPin::~CDynamicOutputPin() -{ - if(NULL != m_hUnblockOutputPinEvent) { - // This call should not fail because we have access to m_hUnblockOutputPinEvent - // and m_hUnblockOutputPinEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent)); - } - - if(NULL != m_hNotifyCallerPinBlockedEvent) { - // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent - // and m_hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - } -} - -HRESULT CDynamicOutputPin::Initialize(void) -{ - m_hUnblockOutputPinEvent = ::CreateEvent( NULL, // The event will have the default security descriptor. - TRUE, // This is a manual reset event. - TRUE, // The event is initially signaled. - NULL ); // The event is not named. - - // CreateEvent() returns NULL if an error occurs. - if(NULL == m_hUnblockOutputPinEvent) { - return AmGetLastErrorToHResult(); - } - - // Set flag to say we can reconnect while streaming. - SetReconnectWhenActive(true); - - return S_OK; -} - -STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - if(riid == IID_IPinFlowControl) { - return GetInterface(static_cast(this), ppv); - } else { - return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); - } -} - -STDMETHODIMP CDynamicOutputPin::Disconnect(void) -{ - CAutoLock cObjectLock(m_pLock); - return DisconnectInternal(); -} - -STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent) -{ - const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK; - - // Check for illegal flags. - if(dwBlockFlags & ~VALID_FLAGS) { - return E_INVALIDARG; - } - - // Make sure the event is unsignaled. - if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) { - if( !::ResetEvent( hEvent ) ) { - return AmGetLastErrorToHResult(); - } - } - - // No flags are set if we are unblocking the output pin. - if(0 == dwBlockFlags) { - - // This parameter should be NULL because unblock operations are always synchronous. - // There is no need to notify the caller when the event is done. - if(NULL != hEvent) { - return E_INVALIDARG; - } - } - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - HRESULT hr; - - if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) { - // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous. - // If hEvent is not NULL, the block is asynchronous. - if(NULL == hEvent) { - hr = SynchronousBlockOutputPin(); - } else { - hr = AsynchronousBlockOutputPin(hEvent); - } - } else { - hr = UnblockOutputPin(); - } - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - if(FAILED(hr)) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void) -{ - HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL, // The event will have the default security attributes. - FALSE, // This is an automatic reset event. - FALSE, // The event is initially unsignaled. - NULL ); // The event is not named. - - // CreateEvent() returns NULL if an error occurs. - if(NULL == hNotifyCallerPinBlockedEvent) { - return AmGetLastErrorToHResult(); - } - - HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent); - if(FAILED(hr)) { - // This call should not fail because we have access to hNotifyCallerPinBlockedEvent - // and hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); - - return hr; - } - - hr = WaitEvent(hNotifyCallerPinBlockedEvent); - - // This call should not fail because we have access to hNotifyCallerPinBlockedEvent - // and hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); - - if(FAILED(hr)) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent) -{ - // This function holds the m_BlockStateLock because it uses - // m_dwBlockCallerThreadID, m_BlockState and - // m_hNotifyCallerPinBlockedEvent. - CAutoLock alBlockStateLock(&m_BlockStateLock); - - if(NOT_BLOCKED != m_BlockState) { - if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) { - return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD; - } else { - return VFW_E_PIN_ALREADY_BLOCKED; - } - } - - BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(), - hNotifyCallerPinBlockedEvent, - ::GetCurrentProcess(), - &m_hNotifyCallerPinBlockedEvent, - EVENT_MODIFY_STATE, - FALSE, - 0 ); - if( !fSuccess ) { - return AmGetLastErrorToHResult(); - } - - m_BlockState = PENDING; - m_dwBlockCallerThreadID = ::GetCurrentThreadId(); - - // The output pin cannot be blocked if the streaming thread is - // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive() - // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it - // cannot be blocked if the streaming thread is calling DynamicReconnect(), - // ChangeMediaType() or ChangeOutputFormat(). - if(!StreamingThreadUsingOutputPin()) { - - // The output pin can be immediately blocked. - BlockOutputPin(); - } - - return S_OK; -} - -void CDynamicOutputPin::BlockOutputPin(void) -{ - // The caller should always hold the m_BlockStateLock because this function - // uses m_BlockState and m_hNotifyCallerPinBlockedEvent. - ASSERT(CritCheckIn(&m_BlockStateLock)); - - // This function should not be called if the streaming thread is modifying - // the connection state or it's passing data downstream. - ASSERT(!StreamingThreadUsingOutputPin()); - - // This should not fail because we successfully created the event - // and we have the security permissions to change it's state. - EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent)); - - // This event should not fail because AsynchronousBlockOutputPin() successfully - // duplicated this handle and we have the appropriate security permissions. - EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - - m_BlockState = BLOCKED; - m_hNotifyCallerPinBlockedEvent = NULL; -} - -HRESULT CDynamicOutputPin::UnblockOutputPin(void) -{ - // UnblockOutputPin() holds the m_BlockStateLock because it - // uses m_BlockState, m_dwBlockCallerThreadID and - // m_hNotifyCallerPinBlockedEvent. - CAutoLock alBlockStateLock(&m_BlockStateLock); - - if(NOT_BLOCKED == m_BlockState) { - return S_FALSE; - } - - // This should not fail because we successfully created the event - // and we have the security permissions to change it's state. - EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent)); - - // Cancel the block operation if it's still pending. - if(NULL != m_hNotifyCallerPinBlockedEvent) { - // This event should not fail because AsynchronousBlockOutputPin() successfully - // duplicated this handle and we have the appropriate security permissions. - EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - } - - m_BlockState = NOT_BLOCKED; - m_dwBlockCallerThreadID = 0; - m_hNotifyCallerPinBlockedEvent = NULL; - - return S_OK; -} - -HRESULT CDynamicOutputPin::StartUsingOutputPin(void) -{ - // The caller should not hold m_BlockStateLock. If the caller does, - // a deadlock could occur. - ASSERT(CritCheckOut(&m_BlockStateLock)); - - CAutoLock alBlockStateLock(&m_BlockStateLock); - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - // Are we in the middle of a block operation? - while(BLOCKED == m_BlockState) { - m_BlockStateLock.Unlock(); - - // If this ASSERT fires, a deadlock could occur. The caller should make sure - // that this thread never acquires the Block State lock more than once. - ASSERT(CritCheckOut( &m_BlockStateLock )); - - // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event - // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired. - // See the Windows SDK documentation for more information on - // WaitForMultipleObjects(). - const DWORD UNBLOCK = WAIT_OBJECT_0; - const DWORD STOP = WAIT_OBJECT_0 + 1; - - HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent }; - DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE); - - DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE ); - - m_BlockStateLock.Lock(); - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - switch( dwReturnValue ) { - case UNBLOCK: - break; - - case STOP: - return VFW_E_STATE_CHANGED; - - case WAIT_FAILED: - return AmGetLastErrorToHResult(); - - default: - DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." ); - return E_UNEXPECTED; - } - } - - m_dwNumOutstandingOutputPinUsers++; - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - return S_OK; -} - -void CDynamicOutputPin::StopUsingOutputPin(void) -{ - CAutoLock alBlockStateLock(&m_BlockStateLock); - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - m_dwNumOutstandingOutputPinUsers--; - - if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) { - BlockOutputPin(); - } - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG -} - -bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void) -{ - CAutoLock alBlockStateLock(&m_BlockStateLock); - - return (m_dwNumOutstandingOutputPinUsers > 0); -} - -void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent) -{ - // This pointer is not addrefed because filters are not allowed to - // hold references to the filter graph manager. See the documentation for - // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information. - m_pGraphConfig = pGraphConfig; - - m_hStopEvent = hStopEvent; -} - -HRESULT CDynamicOutputPin::Active(void) -{ - // Make sure the user initialized the object by calling SetConfigInfo(). - if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) { - DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. ); - return E_FAIL; - } - - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then Active() is called. An event - // handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); - - return CBaseOutputPin::Active(); -} - -HRESULT CDynamicOutputPin::Inactive(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then Active() is called. An event - // handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(SetEvent(m_hStopEvent)); - - return CBaseOutputPin::Inactive(); -} - -HRESULT CDynamicOutputPin::DeliverBeginFlush(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. - // An event handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(SetEvent(m_hStopEvent)); - - return CBaseOutputPin::DeliverBeginFlush(); -} - -HRESULT CDynamicOutputPin::DeliverEndFlush(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. - // An event handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); - - return CBaseOutputPin::DeliverEndFlush(); -} - - -// ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly -// reconnects the output pin. -HRESULT CDynamicOutputPin::ChangeOutputFormat - ( - const AM_MEDIA_TYPE *pmt, - REFERENCE_TIME tSegmentStart, - REFERENCE_TIME tSegmentStop, - double dSegmentRate - ) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - // Callers should always pass a valid media type to ChangeOutputFormat() . - ASSERT(NULL != pmt); - - CMediaType cmt(*pmt); - HRESULT hr = ChangeMediaType(&cmt); - if (FAILED(hr)) { - return hr; - } - - hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate); - if( FAILED( hr ) ) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - // This function assumes the filter graph is running. - ASSERT(!IsStopped()); - - if(!IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - /* First check if the downstream pin will accept a dynamic - format change - */ - QzCComPtr pConnection; - - m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection); - if(pConnection != NULL) { - - if(S_OK == pConnection->DynamicQueryAccept(pmt)) { - - HRESULT hr = ChangeMediaTypeHelper(pmt); - if(FAILED(hr)) { - return hr; - } - - return S_OK; - } - } - - /* Can't do the dynamic connection */ - return DynamicReconnect(pmt); -} - -HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - HRESULT hr = m_Connected->ReceiveConnection(this, pmt); - if(FAILED(hr)) { - return hr; - } - - hr = SetMediaType(pmt); - if(FAILED(hr)) { - return hr; - } - - // Does this pin use the local memory transport? - if(NULL != m_pInputPin) { - // This function assumes that m_pInputPin and m_Connected are - // two different interfaces to the same object. - ASSERT(::IsEqualObject(m_Connected, m_pInputPin)); - - ALLOCATOR_PROPERTIES apInputPinRequirements; - apInputPinRequirements.cbAlign = 0; - apInputPinRequirements.cbBuffer = 0; - apInputPinRequirements.cbPrefix = 0; - apInputPinRequirements.cBuffers = 0; - - m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements); - - // A zero allignment does not make any sense. - if(0 == apInputPinRequirements.cbAlign) { - apInputPinRequirements.cbAlign = 1; - } - - hr = m_pAllocator->Decommit(); - if(FAILED(hr)) { - return hr; - } - - hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements); - if(FAILED(hr)) { - return hr; - } - - hr = m_pAllocator->Commit(); - if(FAILED(hr)) { - return hr; - } - - hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator); - if(FAILED(hr)) { - return hr; - } - } - - return S_OK; -} - -// this method has to be called from the thread that is pushing data, -// and it's the caller's responsibility to make sure that the thread -// has no outstand samples because they cannot be delivered after a -// reconnect -// -HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt ) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) { - return E_FAIL; - } - - HRESULT hr = m_pGraphConfig->Reconnect( - this, - NULL, - pmt, - NULL, - m_hStopEvent, - AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS ); - - return hr; -} - -HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); - if(SUCCEEDED(hr)) { - if(!IsStopped() && m_pAllocator) { - hr = m_pAllocator->Commit(); - ASSERT(hr != VFW_E_ALREADY_COMMITTED); - } - } - - return hr; -} - -#ifdef _DEBUG -void CDynamicOutputPin::AssertValid(void) -{ - // Make sure the object was correctly initialized. - - // This ASSERT only fires if the object failed to initialize - // and the user ignored the constructor's return code (phr). - ASSERT(NULL != m_hUnblockOutputPinEvent); - - // If either of these ASSERTs fire, the user did not correctly call - // SetConfigInfo(). - ASSERT(NULL != m_hStopEvent); - ASSERT(NULL != m_pGraphConfig); - - // Make sure the block state is consistent. - - CAutoLock alBlockStateLock(&m_BlockStateLock); - - // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED. - ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState)); - - // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete - // immediately. - ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) || - ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) ); - - // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and - // the user is not trying to block the pin. - ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState)); - - // If this ASSERT fires, the streaming thread is using the output pin and the - // output pin is blocked. - ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) || - ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) || - ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) ); -} -#endif // DEBUG - -HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent) -{ - const DWORD EVENT_SIGNALED = WAIT_OBJECT_0; - - DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE); - - switch( dwReturnValue ) { - case EVENT_SIGNALED: - return S_OK; - - case WAIT_FAILED: - return AmGetLastErrorToHResult(); - - default: - DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." ); - return E_UNEXPECTED; - } -} - -//===================================================================== -//===================================================================== -// Implements CBaseAllocator -//===================================================================== -//===================================================================== - - -/* Constructor overrides the default settings for the free list to request - that it be alertable (ie the list can be cast to a handle which can be - passed to WaitForSingleObject). Both of the allocator lists also ask for - object locking, the all list matches the object default settings but I - have included them here just so it is obvious what kind of list it is */ - -CBaseAllocator::CBaseAllocator(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - BOOL bEvent, - BOOL fEnableReleaseCallback - ) : - CUnknown(pName, pUnk), - m_lAllocated(0), - m_bChanged(FALSE), - m_bCommitted(FALSE), - m_bDecommitInProgress(FALSE), - m_lSize(0), - m_lCount(0), - m_lAlignment(0), - m_lPrefix(0), - m_hSem(NULL), - m_lWaiting(0), - m_fEnableReleaseCallback(fEnableReleaseCallback), - m_pNotify(NULL) -{ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBaseAllocator", (IMemAllocator *) this ); -#endif // DXMPERF - - if (bEvent) { - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - } -} - -#ifdef UNICODE -CBaseAllocator::CBaseAllocator(__in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - BOOL bEvent, - BOOL fEnableReleaseCallback) : - CUnknown(pName, pUnk), - m_lAllocated(0), - m_bChanged(FALSE), - m_bCommitted(FALSE), - m_bDecommitInProgress(FALSE), - m_lSize(0), - m_lCount(0), - m_lAlignment(0), - m_lPrefix(0), - m_hSem(NULL), - m_lWaiting(0), - m_fEnableReleaseCallback(fEnableReleaseCallback), - m_pNotify(NULL) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CBaseAllocator", (IMemAllocator *) this ); -#endif // DXMPERF - - if (bEvent) { - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - } -} -#endif - -/* Destructor */ - -CBaseAllocator::~CBaseAllocator() -{ - // we can't call Decommit here since that would mean a call to a - // pure virtual in destructor. - // We must assume that the derived class has gone into decommit state in - // its destructor. -#ifdef DXMPERF - PERFLOG_DTOR( L"CBaseAllocator", (IMemAllocator *) this ); -#endif // DXMPERF - - ASSERT(!m_bCommitted); - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } - if (m_pNotify) { - m_pNotify->Release(); - } -} - - -/* Override this to publicise our interfaces */ - -STDMETHODIMP -CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - /* Do we know about this interface */ - - if (riid == IID_IMemAllocator || - riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) { - return GetInterface((IMemAllocatorCallbackTemp *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* This sets the size and count of the required samples. The memory isn't - actually allocated until Commit() is called, if memory has already been - allocated then assuming no samples are outstanding the user may call us - to change the buffering, the memory will be released in Commit() */ - -STDMETHODIMP -CBaseAllocator::SetProperties( - __in ALLOCATOR_PROPERTIES* pRequest, - __out ALLOCATOR_PROPERTIES* pActual) -{ - CheckPointer(pRequest, E_POINTER); - CheckPointer(pActual, E_POINTER); - ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES)); - CAutoLock cObjectLock(this); - - ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); - - ASSERT(pRequest->cbBuffer > 0); - - /* Check the alignment requested */ - if (pRequest->cbAlign != 1) { - DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"), - pRequest->cbAlign)); - return VFW_E_BADALIGN; - } - - /* Can't do this if already committed, there is an argument that says we - should not reject the SetProperties call if there are buffers still - active. However this is called by the source filter, which is the same - person who is holding the samples. Therefore it is not unreasonable - for them to free all their samples before changing the requirements */ - - if (m_bCommitted) { - return VFW_E_ALREADY_COMMITTED; - } - - /* Must be no outstanding buffers */ - - if (m_lAllocated != m_lFree.GetCount()) { - return VFW_E_BUFFERS_OUTSTANDING; - } - - /* There isn't any real need to check the parameters as they - will just be rejected when the user finally calls Commit */ - - pActual->cbBuffer = m_lSize = pRequest->cbBuffer; - pActual->cBuffers = m_lCount = pRequest->cBuffers; - pActual->cbAlign = m_lAlignment = pRequest->cbAlign; - pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; - - m_bChanged = TRUE; - return NOERROR; -} - -STDMETHODIMP -CBaseAllocator::GetProperties( - __out ALLOCATOR_PROPERTIES * pActual) -{ - CheckPointer(pActual,E_POINTER); - ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); - - CAutoLock cObjectLock(this); - pActual->cbBuffer = m_lSize; - pActual->cBuffers = m_lCount; - pActual->cbAlign = m_lAlignment; - pActual->cbPrefix = m_lPrefix; - return NOERROR; -} - -// get container for a sample. Blocking, synchronous call to get the -// next free buffer (as represented by an IMediaSample interface). -// on return, the time etc properties will be invalid, but the buffer -// pointer and size will be correct. - -HRESULT CBaseAllocator::GetBuffer(__deref_out IMediaSample **ppBuffer, - __in_opt REFERENCE_TIME *pStartTime, - __in_opt REFERENCE_TIME *pEndTime, - DWORD dwFlags - ) -{ - UNREFERENCED_PARAMETER(pStartTime); - UNREFERENCED_PARAMETER(pEndTime); - UNREFERENCED_PARAMETER(dwFlags); - CMediaSample *pSample; - - *ppBuffer = NULL; - for (;;) - { - { // scope for lock - CAutoLock cObjectLock(this); - - /* Check we are committed */ - if (!m_bCommitted) { - return VFW_E_NOT_COMMITTED; - } - pSample = (CMediaSample *) m_lFree.RemoveHead(); - if (pSample == NULL) { - SetWaiting(); - } - } - - /* If we didn't get a sample then wait for the list to signal */ - - if (pSample) { - break; - } - if (dwFlags & AM_GBF_NOWAIT) { - return VFW_E_TIMEOUT; - } - ASSERT(m_hSem != NULL); - WaitForSingleObject(m_hSem, INFINITE); - } - - /* Addref the buffer up to one. On release - back to zero instead of being deleted, it will requeue itself by - calling the ReleaseBuffer member function. NOTE the owner of a - media sample must always be derived from CBaseAllocator */ - - - ASSERT(pSample->m_cRef == 0); - pSample->m_cRef = 1; - *ppBuffer = pSample; - -#ifdef DXMPERF - PERFLOG_GETBUFFER( (IMemAllocator *) this, pSample ); -#endif // DXMPERF - - return NOERROR; -} - - -/* Final release of a CMediaSample will call this */ - -STDMETHODIMP -CBaseAllocator::ReleaseBuffer(IMediaSample * pSample) -{ - CheckPointer(pSample,E_POINTER); - ValidateReadPtr(pSample,sizeof(IMediaSample)); - -#ifdef DXMPERF - PERFLOG_RELBUFFER( (IMemAllocator *) this, pSample ); -#endif // DXMPERF - - - BOOL bRelease = FALSE; - { - CAutoLock cal(this); - - /* Put back on the free list */ - - m_lFree.Add((CMediaSample *)pSample); - if (m_lWaiting != 0) { - NotifySample(); - } - - // if there is a pending Decommit, then we need to complete it by - // calling Free() when the last buffer is placed on the free list - - LONG l1 = m_lFree.GetCount(); - if (m_bDecommitInProgress && (l1 == m_lAllocated)) { - Free(); - m_bDecommitInProgress = FALSE; - bRelease = TRUE; - } - } - - if (m_pNotify) { - - ASSERT(m_fEnableReleaseCallback); - - // - // Note that this is not synchronized with setting up a notification - // method. - // - m_pNotify->NotifyRelease(); - } - - /* For each buffer there is one AddRef, made in GetBuffer and released - here. This may cause the allocator and all samples to be deleted */ - - if (bRelease) { - Release(); - } - return NOERROR; -} - -STDMETHODIMP -CBaseAllocator::SetNotify( - IMemAllocatorNotifyCallbackTemp* pNotify - ) -{ - ASSERT(m_fEnableReleaseCallback); - CAutoLock lck(this); - if (pNotify) { - pNotify->AddRef(); - } - if (m_pNotify) { - m_pNotify->Release(); - } - m_pNotify = pNotify; - return S_OK; -} - -STDMETHODIMP -CBaseAllocator::GetFreeCount( - __out LONG* plBuffersFree - ) -{ - ASSERT(m_fEnableReleaseCallback); - CAutoLock cObjectLock(this); - *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount(); - return NOERROR; -} - -void -CBaseAllocator::NotifySample() -{ - if (m_lWaiting != 0) { - ASSERT(m_hSem != NULL); - ReleaseSemaphore(m_hSem, m_lWaiting, 0); - m_lWaiting = 0; - } -} - -STDMETHODIMP -CBaseAllocator::Commit() -{ - /* Check we are not decommitted */ - CAutoLock cObjectLock(this); - - // cannot need to alloc or re-alloc if we are committed - if (m_bCommitted) { - return NOERROR; - } - - /* Allow GetBuffer calls */ - - m_bCommitted = TRUE; - - // is there a pending decommit ? if so, just cancel it - if (m_bDecommitInProgress) { - m_bDecommitInProgress = FALSE; - - // don't call Alloc at this point. He cannot allow SetProperties - // between Decommit and the last free, so the buffer size cannot have - // changed. And because some of the buffers are not free yet, he - // cannot re-alloc anyway. - return NOERROR; - } - - DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize)); - - // actually need to allocate the samples - HRESULT hr = Alloc(); - if (FAILED(hr)) { - m_bCommitted = FALSE; - return hr; - } - AddRef(); - return NOERROR; -} - - -STDMETHODIMP -CBaseAllocator::Decommit() -{ - BOOL bRelease = FALSE; - { - /* Check we are not already decommitted */ - CAutoLock cObjectLock(this); - if (m_bCommitted == FALSE) { - if (m_bDecommitInProgress == FALSE) { - return NOERROR; - } - } - - /* No more GetBuffer calls will succeed */ - m_bCommitted = FALSE; - - // are any buffers outstanding? - if (m_lFree.GetCount() < m_lAllocated) { - // please complete the decommit when last buffer is freed - m_bDecommitInProgress = TRUE; - } else { - m_bDecommitInProgress = FALSE; - - // need to complete the decommit here as there are no - // outstanding buffers - - Free(); - bRelease = TRUE; - } - - // Tell anyone waiting that they can go now so we can - // reject their call -#pragma warning(push) -#ifndef _PREFAST_ -#pragma warning(disable:4068) -#endif -#pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "Suppress warning related to Free() invalidating 'this' which is no applicable to CBaseAllocator::Free()") - NotifySample(); - -#pragma warning(pop) - } - - if (bRelease) { - Release(); - } - return NOERROR; -} - - -/* Base definition of allocation which checks we are ok to go ahead and do - the full allocation. We return S_FALSE if the requirements are the same */ - -HRESULT -CBaseAllocator::Alloc(void) -{ - /* Error if he hasn't set the size yet */ - if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) { - return VFW_E_SIZENOTSET; - } - - /* should never get here while buffers outstanding */ - ASSERT(m_lFree.GetCount() == m_lAllocated); - - /* If the requirements haven't changed then don't reallocate */ - if (m_bChanged == FALSE) { - return S_FALSE; - } - - return NOERROR; -} - -/* Implement CBaseAllocator::CSampleList::Remove(pSample) - Removes pSample from the list -*/ -void -CBaseAllocator::CSampleList::Remove(__inout CMediaSample * pSample) -{ - CMediaSample **pSearch; - for (pSearch = &m_List; - *pSearch != NULL; - pSearch = &(CBaseAllocator::NextSample(*pSearch))) { - if (*pSearch == pSample) { - *pSearch = CBaseAllocator::NextSample(pSample); - CBaseAllocator::NextSample(pSample) = NULL; - m_nOnList--; - return; - } - } - DbgBreak("Couldn't find sample in list"); -} - -//===================================================================== -//===================================================================== -// Implements CMemAllocator -//===================================================================== -//===================================================================== - - -/* This goes in the factory template table to create new instances */ -CUnknown *CMemAllocator::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) -{ - CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr); - return pUnkRet; -} - -CMemAllocator::CMemAllocator( - __in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr) - : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), - m_pBuffer(NULL) -{ -} - -#ifdef UNICODE -CMemAllocator::CMemAllocator( - __in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr) - : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), - m_pBuffer(NULL) -{ -} -#endif - -/* This sets the size and count of the required samples. The memory isn't - actually allocated until Commit() is called, if memory has already been - allocated then assuming no samples are outstanding the user may call us - to change the buffering, the memory will be released in Commit() */ -STDMETHODIMP -CMemAllocator::SetProperties( - __in ALLOCATOR_PROPERTIES* pRequest, - __out ALLOCATOR_PROPERTIES* pActual) -{ - CheckPointer(pActual,E_POINTER); - ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); - CAutoLock cObjectLock(this); - - ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); - - ASSERT(pRequest->cbBuffer > 0); - - SYSTEM_INFO SysInfo; - GetSystemInfo(&SysInfo); - - /* Check the alignment request is a power of 2 */ - if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) { - DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"), - pRequest->cbAlign)); - } - /* Check the alignment requested */ - if (pRequest->cbAlign == 0 || - (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) { - DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"), - pRequest->cbAlign, SysInfo.dwAllocationGranularity)); - return VFW_E_BADALIGN; - } - - /* Can't do this if already committed, there is an argument that says we - should not reject the SetProperties call if there are buffers still - active. However this is called by the source filter, which is the same - person who is holding the samples. Therefore it is not unreasonable - for them to free all their samples before changing the requirements */ - - if (m_bCommitted == TRUE) { - return VFW_E_ALREADY_COMMITTED; - } - - /* Must be no outstanding buffers */ - - if (m_lFree.GetCount() < m_lAllocated) { - return VFW_E_BUFFERS_OUTSTANDING; - } - - /* There isn't any real need to check the parameters as they - will just be rejected when the user finally calls Commit */ - - // round length up to alignment - remember that prefix is included in - // the alignment - LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix; - LONG lRemainder = lSize % pRequest->cbAlign; - if (lRemainder != 0) { - lSize = lSize - lRemainder + pRequest->cbAlign; - } - pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix); - - pActual->cBuffers = m_lCount = pRequest->cBuffers; - pActual->cbAlign = m_lAlignment = pRequest->cbAlign; - pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; - - m_bChanged = TRUE; - return NOERROR; -} - -// override this to allocate our resources when Commit is called. -// -// note that our resources may be already allocated when this is called, -// since we don't free them on Decommit. We will only be called when in -// decommit state with all buffers free. -// -// object locked by caller -HRESULT -CMemAllocator::Alloc(void) -{ - CAutoLock lck(this); - - /* Check he has called SetProperties */ - HRESULT hr = CBaseAllocator::Alloc(); - if (FAILED(hr)) { - return hr; - } - - /* If the requirements haven't changed then don't reallocate */ - if (hr == S_FALSE) { - ASSERT(m_pBuffer); - return NOERROR; - } - ASSERT(hr == S_OK); // we use this fact in the loop below - - /* Free the old resources */ - if (m_pBuffer) { - ReallyFree(); - } - - /* Make sure we've got reasonable values */ - if ( m_lSize < 0 || m_lPrefix < 0 || m_lCount < 0 ) { - return E_OUTOFMEMORY; - } - - /* Compute the aligned size */ - LONG lAlignedSize = m_lSize + m_lPrefix; - - /* Check overflow */ - if (lAlignedSize < m_lSize) { - return E_OUTOFMEMORY; - } - - if (m_lAlignment > 1) { - LONG lRemainder = lAlignedSize % m_lAlignment; - if (lRemainder != 0) { - LONG lNewSize = lAlignedSize + m_lAlignment - lRemainder; - if (lNewSize < lAlignedSize) { - return E_OUTOFMEMORY; - } - lAlignedSize = lNewSize; - } - } - - /* Create the contiguous memory block for the samples - making sure it's properly aligned (64K should be enough!) - */ - ASSERT(lAlignedSize % m_lAlignment == 0); - - LONGLONG lToAllocate = m_lCount * (LONGLONG)lAlignedSize; - - /* Check overflow */ - if (lToAllocate > MAXLONG) { - return E_OUTOFMEMORY; - } - - m_pBuffer = (PBYTE)VirtualAlloc(NULL, - (LONG)lToAllocate, - MEM_COMMIT, - PAGE_READWRITE); - - if (m_pBuffer == NULL) { - return E_OUTOFMEMORY; - } - - LPBYTE pNext = m_pBuffer; - CMediaSample *pSample; - - ASSERT(m_lAllocated == 0); - - // Create the new samples - we have allocated m_lSize bytes for each sample - // plus m_lPrefix bytes per sample as a prefix. We set the pointer to - // the memory after the prefix - so that GetPointer() will return a pointer - // to m_lSize bytes. - for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { - - - pSample = new CMediaSample( - NAME("Default memory media sample"), - this, - &hr, - pNext + m_lPrefix, // GetPointer() value - m_lSize); // not including prefix - - ASSERT(SUCCEEDED(hr)); - if (pSample == NULL) { - return E_OUTOFMEMORY; - } - - // This CANNOT fail - m_lFree.Add(pSample); - } - - m_bChanged = FALSE; - return NOERROR; -} - - -// override this to free up any resources we have allocated. -// called from the base class on Decommit when all buffers have been -// returned to the free list. -// -// caller has already locked the object. - -// in our case, we keep the memory until we are deleted, so -// we do nothing here. The memory is deleted in the destructor by -// calling ReallyFree() -void -CMemAllocator::Free(void) -{ - return; -} - - -// called from the destructor (and from Alloc if changing size/count) to -// actually free up the memory -void -CMemAllocator::ReallyFree(void) -{ - /* Should never be deleting this unless all buffers are freed */ - - ASSERT(m_lAllocated == m_lFree.GetCount()); - - /* Free up all the CMediaSamples */ - - CMediaSample *pSample; - for (;;) { - pSample = m_lFree.RemoveHead(); - if (pSample != NULL) { - delete pSample; - } else { - break; - } - } - - m_lAllocated = 0; - - // free the block of buffer memory - if (m_pBuffer) { - EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE)); - m_pBuffer = NULL; - } -} - - -/* Destructor frees our memory resources */ - -CMemAllocator::~CMemAllocator() -{ - Decommit(); - ReallyFree(); -} - -// ------------------------------------------------------------------------ -// filter registration through IFilterMapper. used if IFilterMapper is -// not found (Quartz 1.0 install) - -STDAPI -AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper * pIFM - , BOOL bRegister ) -{ - DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - - // unregister filter - // (as pins are subkeys of filter's CLSID key - // they do not need to be removed separately). - // - DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); - HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) ); - - - if( bRegister ) - { - // register filter - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); - hr = pIFM->RegisterFilter( *(psetupdata->clsID) - , psetupdata->strName - , psetupdata->dwMerit ); - if( SUCCEEDED(hr) ) - { - // all its pins - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins"))); - for( UINT m1=0; m1 < psetupdata->nPins; m1++ ) - { - hr = pIFM->RegisterPin( *(psetupdata->clsID) - , psetupdata->lpPin[m1].strName - , psetupdata->lpPin[m1].bRendered - , psetupdata->lpPin[m1].bOutput - , psetupdata->lpPin[m1].bZero - , psetupdata->lpPin[m1].bMany - , *(psetupdata->lpPin[m1].clsConnectsToFilter) - , psetupdata->lpPin[m1].strConnectsToPin ); - - if( SUCCEEDED(hr) ) - { - // and each pin's media types - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types"))); - for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ ) - { - hr = pIFM->RegisterPinType( *(psetupdata->clsID) - , psetupdata->lpPin[m1].strName - , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType) - , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) ); - if( FAILED(hr) ) break; - } - if( FAILED(hr) ) break; - } - if( FAILED(hr) ) break; - } - } - } - - // handle one acceptable "error" - that - // of filter not being registered! - // (couldn't find a suitable #define'd - // name for the error!) - // - if( 0x80070002 == hr) - return NOERROR; - else - return hr; -} - -// Remove warnings about unreferenced inline functions -#pragma warning(disable:4514) - +//------------------------------------------------------------------------------ +// File: AMFilter.cpp +// +// Desc: DirectShow base classes - implements class hierarchy for streams +// architecture. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +//===================================================================== +//===================================================================== +// The following classes are declared in this header: +// +// +// CBaseMediaFilter Basic IMediaFilter support (abstract class) +// CBaseFilter Support for IBaseFilter (incl. IMediaFilter) +// CEnumPins Enumerate input and output pins +// CEnumMediaTypes Enumerate the preferred pin formats +// CBasePin Abstract base class for IPin interface +// CBaseOutputPin Adds data provider member functions +// CBaseInputPin Implements IMemInputPin interface +// CMediaSample Basic transport unit for IMemInputPin +// CBaseAllocator General list guff for most allocators +// CMemAllocator Implements memory buffer allocation +// +//===================================================================== +//===================================================================== + +#include "streams.h" +#include + +#ifdef DXMPERF +#include "dxmperf.h" +#endif // DXMPERF + + +//===================================================================== +// Helpers +//===================================================================== +STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator) +{ + return CoCreateInstance(CLSID_MemoryAllocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IMemAllocator, + (void **)ppAllocator); +} + +// Put this one here rather than in ctlutil.cpp to avoid linking +// anything brought in by ctlutil.cpp +STDAPI CreatePosPassThru( + __in_opt LPUNKNOWN pAgg, + BOOL bRenderer, + IPin *pPin, + __deref_out IUnknown **ppPassThru +) +{ + *ppPassThru = NULL; + IUnknown *pUnkSeek; + HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru, + pAgg, + CLSCTX_INPROC_SERVER, + IID_IUnknown, + (void **)&pUnkSeek + ); + if (FAILED(hr)) { + return hr; + } + + ISeekingPassThru *pPassThru; + hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru); + if (FAILED(hr)) { + pUnkSeek->Release(); + return hr; + } + hr = pPassThru->Init(bRenderer, pPin); + pPassThru->Release(); + if (FAILED(hr)) { + pUnkSeek->Release(); + return hr; + } + *ppPassThru = pUnkSeek; + return S_OK; +} + + + +#define CONNECT_TRACE_LEVEL 3 + +//===================================================================== +//===================================================================== +// Implements CBaseMediaFilter +//===================================================================== +//===================================================================== + + +/* Constructor */ + +CBaseMediaFilter::CBaseMediaFilter(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid) : + CUnknown(pName, pUnk), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL) +{ +} + + +/* Destructor */ + +CBaseMediaFilter::~CBaseMediaFilter() +{ + // must be stopped, but can't call Stop here since + // our critsec has been destroyed. + + /* Release any clock we were using */ + + if (m_pClock) { + m_pClock->Release(); + m_pClock = NULL; + } +} + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP +CBaseMediaFilter::NonDelegatingQueryInterface( + REFIID riid, + __deref_out void ** ppv) +{ + if (riid == IID_IMediaFilter) { + return GetInterface((IMediaFilter *) this, ppv); + } else if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + +/* Return the filter's clsid */ +STDMETHODIMP +CBaseMediaFilter::GetClassID(__out CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = m_clsid; + return NOERROR; +} + +/* Override this if your state changes are not done synchronously */ + +STDMETHODIMP +CBaseMediaFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State) +{ + UNREFERENCED_PARAMETER(dwMSecs); + CheckPointer(State,E_POINTER); + ValidateReadWritePtr(State,sizeof(FILTER_STATE)); + + *State = m_State; + return S_OK; +} + + +/* Set the clock we will use for synchronisation */ + +STDMETHODIMP +CBaseMediaFilter::SetSyncSource(__inout_opt IReferenceClock *pClock) +{ + CAutoLock cObjectLock(m_pLock); + + // Ensure the new one does not go away - even if the same as the old + if (pClock) { + pClock->AddRef(); + } + + // if we have a clock, release it + if (m_pClock) { + m_pClock->Release(); + } + + // Set the new reference clock (might be NULL) + // Should we query it to ensure it is a clock? Consider for a debug build. + m_pClock = pClock; + + return NOERROR; +} + +/* Return the clock we are using for synchronisation */ +STDMETHODIMP +CBaseMediaFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock) +{ + CheckPointer(pClock,E_POINTER); + ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pClock) { + // returning an interface... addref it... + m_pClock->AddRef(); + } + *pClock = (IReferenceClock*)m_pClock; + return NOERROR; +} + + +/* Put the filter into a stopped state */ + +STDMETHODIMP +CBaseMediaFilter::Stop() +{ + CAutoLock cObjectLock(m_pLock); + + m_State = State_Stopped; + return S_OK; +} + + +/* Put the filter into a paused state */ + +STDMETHODIMP +CBaseMediaFilter::Pause() +{ + CAutoLock cObjectLock(m_pLock); + + m_State = State_Paused; + return S_OK; +} + + +// Put the filter into a running state. + +// The time parameter is the offset to be added to the samples' +// stream time to get the reference time at which they should be presented. +// +// you can either add these two and compare it against the reference clock, +// or you can call CBaseMediaFilter::StreamTime and compare that against +// the sample timestamp. + +STDMETHODIMP +CBaseMediaFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cObjectLock(m_pLock); + + // remember the stream time offset + m_tStart = tStart; + + if (m_State == State_Stopped){ + HRESULT hr = Pause(); + + if (FAILED(hr)) { + return hr; + } + } + m_State = State_Running; + return S_OK; +} + + +// +// return the current stream time - samples with start timestamps of this +// time or before should be rendered by now +HRESULT +CBaseMediaFilter::StreamTime(CRefTime& rtStream) +{ + // Caller must lock for synchronization + // We can't grab the filter lock because we want to be able to call + // this from worker threads without deadlocking + + if (m_pClock == NULL) { + return VFW_E_NO_CLOCK; + } + + // get the current reference time + HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); + if (FAILED(hr)) { + return hr; + } + + // subtract the stream offset to get stream time + rtStream -= m_tStart; + + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CBaseFilter +//===================================================================== +//===================================================================== + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid, + __deref_out void **ppv) +{ + /* Do we have this interface */ + + if (riid == IID_IBaseFilter) { + return GetInterface((IBaseFilter *) this, ppv); + } else if (riid == IID_IMediaFilter) { + return GetInterface((IMediaFilter *) this, ppv); + } else if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } else if (riid == IID_IAMovieSetup) { + return GetInterface((IAMovieSetup *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + +#ifdef _DEBUG +STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease() +{ + if (m_cRef == 1) { + KASSERT(m_pGraph == NULL); + } + return CUnknown::NonDelegatingRelease(); +} +#endif + + +/* Constructor */ + +CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + ASSERT(pLock != NULL); +} + +/* Passes in a redundant HRESULT argument */ + +CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid, + __inout HRESULT *phr) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + ASSERT(pLock != NULL); + UNREFERENCED_PARAMETER(phr); +} + +#ifdef UNICODE +CBaseFilter::CBaseFilter(__in_opt LPCSTR pName, + __in_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + ASSERT(pLock != NULL); +} +CBaseFilter::CBaseFilter(__in_opt LPCSTR pName, + __in_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid, + __inout HRESULT *phr) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + ASSERT(pLock != NULL); + UNREFERENCED_PARAMETER(phr); +} +#endif + +/* Destructor */ + +CBaseFilter::~CBaseFilter() +{ +#ifdef DXMPERF + PERFLOG_DTOR( L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink + // When we did we had the circular reference problem. Nothing would go away. + + delete[] m_pName; + + // must be stopped, but can't call Stop here since + // our critsec has been destroyed. + + /* Release any clock we were using */ + if (m_pClock) { + m_pClock->Release(); + m_pClock = NULL; + } +} + +/* Return the filter's clsid */ +STDMETHODIMP +CBaseFilter::GetClassID(__out CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = m_clsid; + return NOERROR; +} + +/* Override this if your state changes are not done synchronously */ +STDMETHODIMP +CBaseFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State) +{ + UNREFERENCED_PARAMETER(dwMSecs); + CheckPointer(State,E_POINTER); + ValidateReadWritePtr(State,sizeof(FILTER_STATE)); + + *State = m_State; + return S_OK; +} + + +/* Set the clock we will use for synchronisation */ + +STDMETHODIMP +CBaseFilter::SetSyncSource(__in_opt IReferenceClock *pClock) +{ + CAutoLock cObjectLock(m_pLock); + + // Ensure the new one does not go away - even if the same as the old + if (pClock) { + pClock->AddRef(); + } + + // if we have a clock, release it + if (m_pClock) { + m_pClock->Release(); + } + + // Set the new reference clock (might be NULL) + // Should we query it to ensure it is a clock? Consider for a debug build. + m_pClock = pClock; + + return NOERROR; +} + +/* Return the clock we are using for synchronisation */ +STDMETHODIMP +CBaseFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock) +{ + CheckPointer(pClock,E_POINTER); + ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pClock) { + // returning an interface... addref it... + m_pClock->AddRef(); + } + *pClock = (IReferenceClock*)m_pClock; + return NOERROR; +} + + + +// override CBaseMediaFilter Stop method, to deactivate any pins this +// filter has. +STDMETHODIMP +CBaseFilter::Stop() +{ + CAutoLock cObjectLock(m_pLock); + HRESULT hr = NOERROR; + + // notify all pins of the state change + if (m_State != State_Stopped) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + if (NULL == pPin) { + break; + } + + // Disconnected pins are not activated - this saves pins worrying + // about this state themselves. We ignore the return code to make + // sure everyone is inactivated regardless. The base input pin + // class can return an error if it has no allocator but Stop can + // be used to resync the graph state after something has gone bad + + if (pPin->IsConnected()) { + HRESULT hrTmp = pPin->Inactive(); + if (FAILED(hrTmp) && SUCCEEDED(hr)) { + hr = hrTmp; + } + } + } + } + +#ifdef DXMPERF + PERFLOG_STOP( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State ); +#endif // DXMPERF + + m_State = State_Stopped; + return hr; +} + + +// override CBaseMediaFilter Pause method to activate any pins +// this filter has (also called from Run) + +STDMETHODIMP +CBaseFilter::Pause() +{ + CAutoLock cObjectLock(m_pLock); + + // notify all pins of the change to active state + if (m_State == State_Stopped) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + if (NULL == pPin) { + break; + } + + // Disconnected pins are not activated - this saves pins + // worrying about this state themselves + + if (pPin->IsConnected()) { + HRESULT hr = pPin->Active(); + if (FAILED(hr)) { + return hr; + } + } + } + } + + +#ifdef DXMPERF + PERFLOG_PAUSE( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State ); +#endif // DXMPERF + + m_State = State_Paused; + return S_OK; +} + +// Put the filter into a running state. + +// The time parameter is the offset to be added to the samples' +// stream time to get the reference time at which they should be presented. +// +// you can either add these two and compare it against the reference clock, +// or you can call CBaseFilter::StreamTime and compare that against +// the sample timestamp. + +STDMETHODIMP +CBaseFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cObjectLock(m_pLock); + + // remember the stream time offset + m_tStart = tStart; + + if (m_State == State_Stopped){ + HRESULT hr = Pause(); + + if (FAILED(hr)) { + return hr; + } + } + // notify all pins of the change to active state + if (m_State != State_Running) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + if (NULL == pPin) { + break; + } + + // Disconnected pins are not activated - this saves pins + // worrying about this state themselves + + if (pPin->IsConnected()) { + HRESULT hr = pPin->Run(tStart); + if (FAILED(hr)) { + return hr; + } + } + } + } + +#ifdef DXMPERF + PERFLOG_RUN( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, tStart, m_State ); +#endif // DXMPERF + + m_State = State_Running; + return S_OK; +} + +// +// return the current stream time - samples with start timestamps of this +// time or before should be rendered by now +HRESULT +CBaseFilter::StreamTime(CRefTime& rtStream) +{ + // Caller must lock for synchronization + // We can't grab the filter lock because we want to be able to call + // this from worker threads without deadlocking + + if (m_pClock == NULL) { + return VFW_E_NO_CLOCK; + } + + // get the current reference time + HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); + if (FAILED(hr)) { + return hr; + } + + // subtract the stream offset to get stream time + rtStream -= m_tStart; + + return S_OK; +} + + +/* Create an enumerator for the pins attached to this filter */ + +STDMETHODIMP +CBaseFilter::EnumPins(__deref_out IEnumPins **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); + + /* Create a new ref counted enumerator */ + + *ppEnum = new CEnumPins(this, + NULL); + + return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR; +} + + +// default behaviour of FindPin is to assume pins are named +// by their pin names +STDMETHODIMP +CBaseFilter::FindPin( + LPCWSTR Id, + __deref_out IPin ** ppPin +) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + + // We're going to search the pin list so maintain integrity + CAutoLock lck(m_pLock); + int iCount = GetPinCount(); + for (int i = 0; i < iCount; i++) { + CBasePin *pPin = GetPin(i); + if (NULL == pPin) { + break; + } + + if (0 == lstrcmpW(pPin->Name(), Id)) { + // Found one that matches + // + // AddRef() and return it + *ppPin = pPin; + pPin->AddRef(); + return S_OK; + } + } + *ppPin = NULL; + return VFW_E_NOT_FOUND; +} + +/* Return information about this filter */ + +STDMETHODIMP +CBaseFilter::QueryFilterInfo(__out FILTER_INFO * pInfo) +{ + CheckPointer(pInfo,E_POINTER); + ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO)); + + if (m_pName) { + (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); + } else { + pInfo->achName[0] = L'\0'; + } + pInfo->pGraph = m_pGraph; + if (m_pGraph) + m_pGraph->AddRef(); + return NOERROR; +} + + +/* Provide the filter with a filter graph */ + +STDMETHODIMP +CBaseFilter::JoinFilterGraph( + __inout_opt IFilterGraph * pGraph, + __in_opt LPCWSTR pName) +{ + CAutoLock cObjectLock(m_pLock); + + // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink) + + m_pGraph = pGraph; + if (m_pGraph) { + HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink, + (void**) &m_pSink); + if (FAILED(hr)) { + ASSERT(m_pSink == NULL); + } + else m_pSink->Release(); // we do NOT keep a reference on it. + } else { + // if graph pointer is null, then we should + // also release the IMediaEventSink on the same object - we don't + // refcount it, so just set it to null + m_pSink = NULL; + } + + + if (m_pName) { + delete[] m_pName; + m_pName = NULL; + } + + if (pName) { + size_t namelen; + HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &namelen); + if (FAILED(hr)) { + return hr; + } + m_pName = new WCHAR[namelen + 1]; + if (m_pName) { + (void)StringCchCopyW(m_pName, namelen + 1, pName); + } else { + return E_OUTOFMEMORY; + } + } + +#ifdef DXMPERF + PERFLOG_JOINGRAPH( m_pName ? m_pName : L"CBaseFilter",(IBaseFilter *) this, pGraph ); +#endif // DXMPERF + + return NOERROR; +} + + +// return a Vendor information string. Optional - may return E_NOTIMPL. +// memory returned should be freed using CoTaskMemFree +// default implementation returns E_NOTIMPL +STDMETHODIMP +CBaseFilter::QueryVendorInfo( + __deref_out LPWSTR* pVendorInfo) +{ + UNREFERENCED_PARAMETER(pVendorInfo); + return E_NOTIMPL; +} + + +// send an event notification to the filter graph if we know about it. +// returns S_OK if delivered, S_FALSE if the filter graph does not sink +// events, or an error otherwise. +HRESULT +CBaseFilter::NotifyEvent( + long EventCode, + LONG_PTR EventParam1, + LONG_PTR EventParam2) +{ + // Snapshot so we don't have to lock up + IMediaEventSink *pSink = m_pSink; + if (pSink) { + if (EC_COMPLETE == EventCode) { + EventParam2 = (LONG_PTR)(IBaseFilter*)this; + } + + return pSink->Notify(EventCode, EventParam1, EventParam2); + } else { + return E_NOTIMPL; + } +} + +// Request reconnect +// pPin is the pin to reconnect +// pmt is the type to reconnect with - can be NULL +// Calls ReconnectEx on the filter graph +HRESULT +CBaseFilter::ReconnectPin( + IPin *pPin, + __in_opt AM_MEDIA_TYPE const *pmt +) +{ + IFilterGraph2 *pGraph2; + if (m_pGraph != NULL) { + HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2); + if (SUCCEEDED(hr)) { + hr = pGraph2->ReconnectEx(pPin, pmt); + pGraph2->Release(); + return hr; + } else { + return m_pGraph->Reconnect(pPin); + } + } else { + return E_NOINTERFACE; + } +} + + + +/* This is the same idea as the media type version does for type enumeration + on pins but for the list of pins available. So if the list of pins you + provide changes dynamically then either override this virtual function + to provide the version number, or more simply call IncrementPinVersion */ + +LONG CBaseFilter::GetPinVersion() +{ + return m_PinVersion; +} + + +/* Increment the current pin version cookie */ + +void CBaseFilter::IncrementPinVersion() +{ + InterlockedIncrement(&m_PinVersion); +} + +/* register filter */ + +STDMETHODIMP CBaseFilter::Register() +{ + // get setup data, if it exists + // + LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + // init is ref counted so call just in case + // we're being called cold. + // + HRESULT hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper + // + IFilterMapper *pIFM; + hr = CoCreateInstance( CLSID_FilterMapper + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper + , (void **)&pIFM ); + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE ); + pIFM->Release(); + } + + // and clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + + return NOERROR; +} + + +/* unregister filter */ + +STDMETHODIMP CBaseFilter::Unregister() +{ + // get setup data, if it exists + // + LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + // OLE init is ref counted so call + // just in case we're being called cold. + // + HRESULT hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper + // + IFilterMapper *pIFM; + hr = CoCreateInstance( CLSID_FilterMapper + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper + , (void **)&pIFM ); + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE ); + + // release interface + // + pIFM->Release(); + } + + // clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + + +//===================================================================== +//===================================================================== +// Implements CEnumPins +//===================================================================== +//===================================================================== + + +CEnumPins::CEnumPins(__in CBaseFilter *pFilter, + __in_opt CEnumPins *pEnumPins) : + m_Position(0), + m_PinCount(0), + m_pFilter(pFilter), + m_cRef(1), // Already ref counted + m_PinCache(NAME("Pin Cache")) +{ + +#ifdef _DEBUG + m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0); +#endif + + /* We must be owned by a filter derived from CBaseFilter */ + + ASSERT(pFilter != NULL); + + /* Hold a reference count on our filter */ + m_pFilter->AddRef(); + + /* Are we creating a new enumerator */ + + if (pEnumPins == NULL) { + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + } else { + ASSERT(m_Position <= m_PinCount); + m_Position = pEnumPins->m_Position; + m_PinCount = pEnumPins->m_PinCount; + m_Version = pEnumPins->m_Version; + m_PinCache.AddTail(&(pEnumPins->m_PinCache)); + } +} + + +/* Destructor releases the reference count on our filter NOTE since we hold + a reference count on the filter who created us we know it is safe to + release it, no access can be made to it afterwards though as we have just + caused the last reference count to go and the object to be deleted */ + +CEnumPins::~CEnumPins() +{ + m_pFilter->Release(); + +#ifdef _DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + + +/* Override this to say what interfaces we support where */ + +STDMETHODIMP +CEnumPins::QueryInterface(REFIID riid, __deref_out void **ppv) +{ + CheckPointer(ppv, E_POINTER); + + /* Do we have this interface */ + + if (riid == IID_IEnumPins || riid == IID_IUnknown) { + return GetInterface((IEnumPins *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CEnumPins::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) +CEnumPins::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) { + delete this; + } + return cRef; +} + +/* One of an enumerator's basic member functions allows us to create a cloned + interface that initially has the same state. Since we are taking a snapshot + of an object (current position and all) we must lock access at the start */ + +STDMETHODIMP +CEnumPins::Clone(__deref_out IEnumPins **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); + HRESULT hr = NOERROR; + + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + *ppEnum = NULL; + hr = VFW_E_ENUM_OUT_OF_SYNC; + } else { + *ppEnum = new CEnumPins(m_pFilter, + this); + if (*ppEnum == NULL) { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + + +/* Return the next pin after the current position */ + +STDMETHODIMP +CEnumPins::Next(ULONG cPins, // place this many pins... + __out_ecount(cPins) IPin **ppPins, // ...in this array + __out_opt ULONG *pcFetched) // actual count passed returned here +{ + CheckPointer(ppPins,E_POINTER); + ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *)); + + ASSERT(ppPins); + + if (pcFetched!=NULL) { + ValidateWritePtr(pcFetched, sizeof(ULONG)); + *pcFetched = 0; // default unless we succeed + } + // now check that the parameter is valid + else if (cPins>1) { // pcFetched == NULL + return E_INVALIDARG; + } + ULONG cFetched = 0; // increment as we get each one. + + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + // If we are out of sync, we should refresh the enumerator. + // This will reset the position and update the other members, but + // will not clear cache of pins we have already returned. + Refresh(); + } + + /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed + so we must QI for the IPin (which increments its reference count) + If while we are retrieving a pin from the filter an error occurs we + assume that our internal state is stale with respect to the filter + (for example someone has deleted a pin) so we + return VFW_E_ENUM_OUT_OF_SYNC */ + + while (cFetched < cPins && m_PinCount > m_Position) { + + /* Get the next pin object from the filter */ + + CBasePin *pPin = m_pFilter->GetPin(m_Position++); + if (pPin == NULL) { + // If this happend, and it's not the first time through, then we've got a problem, + // since we should really go back and release the iPins, which we have previously + // AddRef'ed. + ASSERT( cFetched==0 ); + return VFW_E_ENUM_OUT_OF_SYNC; + } + // MPC-HC custom code begin + if (pPin == (CBasePin *)0x3) { + return E_FAIL; + } + // MPC-HC custom code end + + /* We only want to return this pin, if it is not in our cache */ + if (0 == m_PinCache.Find(pPin)) + { + /* From the object get an IPin interface */ + + *ppPins = pPin; + pPin->AddRef(); + + cFetched++; + ppPins++; + + m_PinCache.AddTail(pPin); + } + } + + if (pcFetched!=NULL) { + *pcFetched = cFetched; + } + + return (cPins==cFetched ? NOERROR : S_FALSE); +} + + +/* Skip over one or more entries in the enumerator */ + +STDMETHODIMP +CEnumPins::Skip(ULONG cPins) +{ + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + /* Work out how many pins are left to skip over */ + /* We could position at the end if we are asked to skip too many... */ + /* ..which would match the base implementation for CEnumMediaTypes::Skip */ + + ULONG PinsLeft = m_PinCount - m_Position; + if (cPins > PinsLeft) { + return S_FALSE; + } + m_Position += cPins; + return NOERROR; +} + + +/* Set the current position back to the start */ +/* Reset has 4 simple steps: + * + * Set position to head of list + * Sync enumerator with object being enumerated + * Clear the cache of pins already returned + * return S_OK + */ + +STDMETHODIMP +CEnumPins::Reset() +{ + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + + m_Position = 0; + + // Clear the cache + m_PinCache.RemoveAll(); + + return S_OK; +} + + +/* Set the current position back to the start */ +/* Refresh has 3 simple steps: + * + * Set position to head of list + * Sync enumerator with object being enumerated + * return S_OK + */ + +STDMETHODIMP +CEnumPins::Refresh() +{ + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + + m_Position = 0; + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CEnumMediaTypes +//===================================================================== +//===================================================================== + + +CEnumMediaTypes::CEnumMediaTypes(__in CBasePin *pPin, + __in_opt CEnumMediaTypes *pEnumMediaTypes) : + m_Position(0), + m_pPin(pPin), + m_cRef(1) +{ + +#ifdef _DEBUG + m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0); +#endif + + /* We must be owned by a pin derived from CBasePin */ + + ASSERT(pPin != NULL); + + /* Hold a reference count on our pin */ + m_pPin->AddRef(); + + /* Are we creating a new enumerator */ + + if (pEnumMediaTypes == NULL) { + m_Version = m_pPin->GetMediaTypeVersion(); + return; + } + + m_Position = pEnumMediaTypes->m_Position; + m_Version = pEnumMediaTypes->m_Version; +} + + +/* Destructor releases the reference count on our base pin. NOTE since we hold + a reference count on the pin who created us we know it is safe to release + it, no access can be made to it afterwards though as we might have just + caused the last reference count to go and the object to be deleted */ + +CEnumMediaTypes::~CEnumMediaTypes() +{ +#ifdef _DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif + m_pPin->Release(); +} + + +/* Override this to say what interfaces we support where */ + +STDMETHODIMP +CEnumMediaTypes::QueryInterface(REFIID riid, __deref_out void **ppv) +{ + CheckPointer(ppv, E_POINTER); + + /* Do we have this interface */ + + if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) { + return GetInterface((IEnumMediaTypes *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CEnumMediaTypes::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) +CEnumMediaTypes::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) { + delete this; + } + return cRef; +} + +/* One of an enumerator's basic member functions allows us to create a cloned + interface that initially has the same state. Since we are taking a snapshot + of an object (current position and all) we must lock access at the start */ + +STDMETHODIMP +CEnumMediaTypes::Clone(__deref_out IEnumMediaTypes **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + HRESULT hr = NOERROR; + + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + *ppEnum = NULL; + hr = VFW_E_ENUM_OUT_OF_SYNC; + } else { + + *ppEnum = new CEnumMediaTypes(m_pPin, + this); + + if (*ppEnum == NULL) { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + + +/* Enumerate the next pin(s) after the current position. The client using this + interface passes in a pointer to an array of pointers each of which will + be filled in with a pointer to a fully initialised media type format + Return NOERROR if it all works, + S_FALSE if fewer than cMediaTypes were enumerated. + VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by + state changes in the filter + The actual count always correctly reflects the number of types in the array. +*/ + +STDMETHODIMP +CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types... + __out_ecount(cMediaTypes) AM_MEDIA_TYPE **ppMediaTypes, // ...in this array + __out ULONG *pcFetched) // actual count passed +{ + CheckPointer(ppMediaTypes,E_POINTER); + ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *)); + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + if (pcFetched!=NULL) { + ValidateWritePtr(pcFetched, sizeof(ULONG)); + *pcFetched = 0; // default unless we succeed + } + // now check that the parameter is valid + else if (cMediaTypes>1) { // pcFetched == NULL + return E_INVALIDARG; + } + ULONG cFetched = 0; // increment as we get each one. + + /* Return each media type by asking the filter for them in turn - If we + have an error code retured to us while we are retrieving a media type + we assume that our internal state is stale with respect to the filter + (for example the window size changing) so we return + VFW_E_ENUM_OUT_OF_SYNC */ + + while (cMediaTypes) { + + CMediaType cmt; + + HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt); + if (S_OK != hr) { + break; + } + + /* We now have a CMediaType object that contains the next media type + but when we assign it to the array position we CANNOT just assign + the AM_MEDIA_TYPE structure because as soon as the object goes out of + scope it will delete the memory we have just copied. The function + we use is CreateMediaType which allocates a task memory block */ + + /* Transfer across the format block manually to save an allocate + and free on the format block and generally go faster */ + + *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (*ppMediaTypes == NULL) { + break; + } + + /* Do a regular copy */ + **ppMediaTypes = cmt; + + /* Make sure the destructor doesn't free these */ + cmt.pbFormat = NULL; + cmt.cbFormat = NULL; + cmt.pUnk = NULL; + + + ppMediaTypes++; + cFetched++; + cMediaTypes--; + } + + if (pcFetched!=NULL) { + *pcFetched = cFetched; + } + + return ( cMediaTypes==0 ? NOERROR : S_FALSE ); +} + + +/* Skip over one or more entries in the enumerator */ + +STDMETHODIMP +CEnumMediaTypes::Skip(ULONG cMediaTypes) +{ + // If we're skipping 0 elements we're guaranteed to skip the + // correct number of elements + if (cMediaTypes == 0) { + return S_OK; + } + + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + m_Position += cMediaTypes; + + /* See if we're over the end */ + CMediaType cmt; + return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE; +} + + +/* Set the current position back to the start */ +/* Reset has 3 simple steps: + * + * set position to head of list + * sync enumerator with object being enumerated + * return S_OK + */ + +STDMETHODIMP +CEnumMediaTypes::Reset() + +{ + m_Position = 0; + + // Bring the enumerator back into step with the current state. This + // may be a noop but ensures that the enumerator will be valid on the + // next call. + m_Version = m_pPin->GetMediaTypeVersion(); + return NOERROR; +} + + +//===================================================================== +//===================================================================== +// Implements CBasePin +//===================================================================== +//===================================================================== + + +/* NOTE The implementation of this class calls the CUnknown constructor with + a NULL outer unknown pointer. This has the effect of making us a self + contained class, ie any QueryInterface, AddRef or Release calls will be + routed to the class's NonDelegatingUnknown methods. You will typically + find that the classes that do this then override one or more of these + virtual functions to provide more specialised behaviour. A good example + of this is where a class wants to keep the QueryInterface internal but + still wants its lifetime controlled by the external object */ + +/* Constructor */ + +CBasePin::CBasePin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName, + PIN_DIRECTION dir) : + CUnknown( pObjectName, NULL ), + m_pFilter(pFilter), + m_pLock(pLock), + m_pName(NULL), + m_Connected(NULL), + m_dir(dir), + m_bRunTimeError(FALSE), + m_pQSink(NULL), + m_TypeVersion(1), + m_tStart(), + m_tStop(MAX_TIME), + m_bCanReconnectWhenActive(false), + m_bTryMyTypesFirst(false), + m_dRate(1.0) +{ + /* WARNING - pFilter is often not a properly constituted object at + this state (in particular QueryInterface may not work) - this + is because its owner is often its containing object and we + have been called from the containing object's constructor so + the filter's owner has not yet had its CUnknown constructor + called + */ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this ); +#endif // DXMPERF + + ASSERT(pFilter != NULL); + ASSERT(pLock != NULL); + + if (pName) { + size_t cchName; + HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName); + if (SUCCEEDED(hr)) { + m_pName = new WCHAR[cchName + 1]; + if (m_pName) { + (void)StringCchCopyW(m_pName, cchName + 1, pName); + } + } + } + +#ifdef _DEBUG + m_cRef = 0; +#endif +} + +#ifdef UNICODE +CBasePin::CBasePin(__in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName, + PIN_DIRECTION dir) : + CUnknown( pObjectName, NULL ), + m_pFilter(pFilter), + m_pLock(pLock), + m_pName(NULL), + m_Connected(NULL), + m_dir(dir), + m_bRunTimeError(FALSE), + m_pQSink(NULL), + m_TypeVersion(1), + m_tStart(), + m_tStop(MAX_TIME), + m_bCanReconnectWhenActive(false), + m_bTryMyTypesFirst(false), + m_dRate(1.0) +{ + /* WARNING - pFilter is often not a properly constituted object at + this state (in particular QueryInterface may not work) - this + is because its owner is often its containing object and we + have been called from the containing object's constructor so + the filter's owner has not yet had its CUnknown constructor + called + */ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this ); +#endif // DXMPERF + + ASSERT(pFilter != NULL); + ASSERT(pLock != NULL); + + if (pName) { + size_t cchName; + HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName); + if (SUCCEEDED(hr)) { + m_pName = new WCHAR[cchName + 1]; + if (m_pName) { + (void)StringCchCopyW(m_pName, cchName + 1, pName); + } + } + } + + +#ifdef _DEBUG + m_cRef = 0; +#endif +} +#endif + +/* Destructor since a connected pin holds a reference count on us there is + no way that we can be deleted unless we are not currently connected */ + +CBasePin::~CBasePin() +{ +#ifdef DXMPERF + PERFLOG_DTOR( m_pName ? m_pName : L"CBasePin", (IPin *) this ); +#endif // DXMPERF + + // We don't call disconnect because if the filter is going away + // all the pins must have a reference count of zero so they must + // have been disconnected anyway - (but check the assumption) + ASSERT(m_Connected == FALSE); + + delete[] m_pName; + + // check the internal reference count is consistent + ASSERT(m_cRef == 0); +} + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP +CBasePin::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) +{ + /* Do we have this interface */ + + if (riid == IID_IPin) { + return GetInterface((IPin *) this, ppv); + } else if (riid == IID_IQualityControl) { + return GetInterface((IQualityControl *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* Override to increment the owning filter's reference count */ + +STDMETHODIMP_(ULONG) +CBasePin::NonDelegatingAddRef() +{ + ASSERT(InterlockedIncrement(&m_cRef) > 0); + return m_pFilter->AddRef(); +} + + +/* Override to decrement the owning filter's reference count */ + +STDMETHODIMP_(ULONG) +CBasePin::NonDelegatingRelease() +{ + ASSERT(InterlockedDecrement(&m_cRef) >= 0); + return m_pFilter->Release(); +} + + +/* Displays pin connection information */ + +#ifdef _DEBUG +void +CBasePin::DisplayPinInfo(IPin *pReceivePin) +{ + + if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { + PIN_INFO ConnectPinInfo; + PIN_INFO ReceivePinInfo; + + if (FAILED(QueryPinInfo(&ConnectPinInfo))) { + StringCchCopyW(ConnectPinInfo.achName, sizeof(ConnectPinInfo.achName)/sizeof(WCHAR), L"Bad Pin"); + } else { + QueryPinInfoReleaseFilter(ConnectPinInfo); + } + + if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) { + StringCchCopyW(ReceivePinInfo.achName, sizeof(ReceivePinInfo.achName)/sizeof(WCHAR), L"Bad Pin"); + } else { + QueryPinInfoReleaseFilter(ReceivePinInfo); + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :"))); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName)); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName)); + } +} +#endif + + +/* Displays general information on the pin media type */ + +#ifdef _DEBUG +void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) +{ + UNREFERENCED_PARAMETER(pPin); + if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:"))); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"), + GuidNames[*pmt->Type()])); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"), + GuidNames[*pmt->Subtype()])); + } +} +#endif + +/* Asked to connect to a pin. A pin is always attached to an owning filter + object so we always delegate our locking to that object. We first of all + retrieve a media type enumerator for the input pin and see if we accept + any of the formats that it would ideally like, failing that we retrieve + our enumerator and see if it will accept any of our preferred types */ + +STDMETHODIMP +CBasePin::Connect( + IPin * pReceivePin, + __in_opt const AM_MEDIA_TYPE *pmt // optional media type +) +{ + CheckPointer(pReceivePin,E_POINTER); + ValidateReadPtr(pReceivePin,sizeof(IPin)); + CAutoLock cObjectLock(m_pLock); + DisplayPinInfo(pReceivePin); + + /* See if we are already connected */ + + if (m_Connected) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected"))); + return VFW_E_ALREADY_CONNECTED; + } + + /* See if the filter is active */ + if (!IsStopped() && !m_bCanReconnectWhenActive) { + return VFW_E_NOT_STOPPED; + } + + + // Find a mutually agreeable media type - + // Pass in the template media type. If this is partially specified, + // each of the enumerated media types will need to be checked against + // it. If it is non-null and fully specified, we will just try to connect + // with this. + + const CMediaType * ptype = (CMediaType*)pmt; + HRESULT hr = AgreeMediaType(pReceivePin, ptype); + if (FAILED(hr)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type"))); + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + +#ifdef DXMPERF + PERFLOG_CONNECT( (IPin *) this, pReceivePin, hr, pmt ); +#endif // DXMPERF + + return hr; + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded"))); + +#ifdef DXMPERF + PERFLOG_CONNECT( (IPin *) this, pReceivePin, NOERROR, pmt ); +#endif // DXMPERF + + return NOERROR; +} + +// given a specific media type, attempt a connection (includes +// checking that the type is acceptable to this pin) +HRESULT +CBasePin::AttemptConnection( + IPin* pReceivePin, // connect to this pin + const CMediaType* pmt // using this type +) +{ + // The caller should hold the filter lock becasue this function + // uses m_Connected. The caller should also hold the filter lock + // because this function calls SetMediaType(), IsStopped() and + // CompleteConnect(). + ASSERT(CritCheckIn(m_pLock)); + + // Check that the connection is valid -- need to do this for every + // connect attempt since BreakConnect will undo it. + HRESULT hr = CheckConnect(pReceivePin); + if (FAILED(hr)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed"))); + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + return hr; + } + + DisplayTypeInfo(pReceivePin, pmt); + + /* Check we will accept this media type */ + + hr = CheckMediaType(pmt); + if (hr == NOERROR) { + + /* Make ourselves look connected otherwise ReceiveConnection + may not be able to complete the connection + */ + m_Connected = pReceivePin; + m_Connected->AddRef(); + hr = SetMediaType(pmt); + if (SUCCEEDED(hr)) { + /* See if the other pin will accept this type */ + + hr = pReceivePin->ReceiveConnection((IPin *)this, pmt); + if (SUCCEEDED(hr)) { + /* Complete the connection */ + + hr = CompleteConnect(pReceivePin); + if (SUCCEEDED(hr)) { + return hr; + } else { + DbgLog((LOG_TRACE, + CONNECT_TRACE_LEVEL, + TEXT("Failed to complete connection"))); + pReceivePin->Disconnect(); + } + } + } + } else { + // we cannot use this media type + + // return a specific media type error if there is one + // or map a general failure code to something more helpful + // (in particular S_FALSE gets changed to an error code) + if (SUCCEEDED(hr) || + (hr == E_FAIL) || + (hr == E_INVALIDARG)) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + } + + // BreakConnect and release any connection here in case CheckMediaType + // failed, or if we set anything up during a call back during + // ReceiveConnection. + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + /* If failed then undo our state */ + if (m_Connected) { + m_Connected->Release(); + m_Connected = NULL; + } + + return hr; +} + +/* Given an enumerator we cycle through all the media types it proposes and + firstly suggest them to our derived pin class and if that succeeds try + them with the pin in a ReceiveConnection call. This means that if our pin + proposes a media type we still check in here that we can support it. This + is deliberate so that in simple cases the enumerator can hold all of the + media types even if some of them are not really currently available */ + +HRESULT CBasePin::TryMediaTypes( + IPin *pReceivePin, + __in_opt const CMediaType *pmt, + IEnumMediaTypes *pEnum) +{ + /* Reset the current enumerator position */ + + HRESULT hr = pEnum->Reset(); + if (FAILED(hr)) { + return hr; + } + + CMediaType *pMediaType = NULL; + ULONG ulMediaCount = 0; + + // attempt to remember a specific error code if there is one + HRESULT hrFailure = S_OK; + + for (;;) { + + /* Retrieve the next media type NOTE each time round the loop the + enumerator interface will allocate another AM_MEDIA_TYPE structure + If we are successful then we copy it into our output object, if + not then we must delete the memory allocated before returning */ + + hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount); + if (hr != S_OK) { + if (S_OK == hrFailure) { + hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; + } + return hrFailure; + } + + + ASSERT(ulMediaCount == 1); + ASSERT(pMediaType); + + // check that this matches the partial type (if any) + + if (pMediaType && + ((pmt == NULL) || + pMediaType->MatchesPartial(pmt))) { + + hr = AttemptConnection(pReceivePin, pMediaType); + + // attempt to remember a specific error code + if (FAILED(hr) && + SUCCEEDED(hrFailure) && + (hr != E_FAIL) && + (hr != E_INVALIDARG) && + (hr != VFW_E_TYPE_NOT_ACCEPTED)) { + hrFailure = hr; + } + } else { + hr = VFW_E_NO_ACCEPTABLE_TYPES; + } + + if(pMediaType) { + DeleteMediaType(pMediaType); + pMediaType = NULL; + } + + if (S_OK == hr) { + return hr; + } + } +} + + +/* This is called to make the connection, including the taask of finding + a media type for the pin connection. pmt is the proposed media type + from the Connect call: if this is fully specified, we will try that. + Otherwise we enumerate and try all the input pin's types first and + if that fails we then enumerate and try all our preferred media types. + For each media type we check it against pmt (if non-null and partially + specified) as well as checking that both pins will accept it. + */ + +HRESULT CBasePin::AgreeMediaType( + IPin *pReceivePin, + const CMediaType *pmt) +{ + ASSERT(pReceivePin); + IEnumMediaTypes *pEnumMediaTypes = NULL; + + // if the media type is fully specified then use that + if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) { + + // if this media type fails, then we must fail the connection + // since if pmt is nonnull we are only allowed to connect + // using a type that matches it. + + return AttemptConnection(pReceivePin, pmt); + } + + + /* Try the other pin's enumerator */ + + HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; + + for (int i = 0; i < 2; i++) { + HRESULT hr; + if (i == (int)m_bTryMyTypesFirst) { + hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes); + } else { + hr = EnumMediaTypes(&pEnumMediaTypes); + } + if (SUCCEEDED(hr)) { + ASSERT(pEnumMediaTypes); + hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes); + pEnumMediaTypes->Release(); + if (SUCCEEDED(hr)) { + return NOERROR; + } else { + // try to remember specific error codes if there are any + if ((hr != E_FAIL) && + (hr != E_INVALIDARG) && + (hr != VFW_E_TYPE_NOT_ACCEPTED)) { + hrFailure = hr; + } + } + } + } + + return hrFailure; +} + + +/* Called when we want to complete a connection to another filter. Failing + this will also fail the connection and disconnect the other pin as well */ + +HRESULT +CBasePin::CompleteConnect(IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + return NOERROR; +} + + +/* This is called to set the format for a pin connection - CheckMediaType + will have been called to check the connection format and if it didn't + return an error code then this (virtual) function will be invoked */ + +HRESULT +CBasePin::SetMediaType(const CMediaType *pmt) +{ + HRESULT hr = m_mt.Set(*pmt); + if (FAILED(hr)) { + return hr; + } + + return NOERROR; +} + + +/* This is called during Connect() to provide a virtual method that can do + any specific check needed for connection such as QueryInterface. This + base class method just checks that the pin directions don't match */ + +HRESULT +CBasePin::CheckConnect(IPin * pPin) +{ + /* Check that pin directions DONT match */ + + PIN_DIRECTION pd; + pPin->QueryDirection(&pd); + + ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT)); + ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT)); + + // we should allow for non-input and non-output connections? + if (pd == m_dir) { + return VFW_E_INVALID_DIRECTION; + } + return NOERROR; +} + + +/* This is called when we realise we can't make a connection to the pin and + must undo anything we did in CheckConnect - override to release QIs done */ + +HRESULT +CBasePin::BreakConnect() +{ + return NOERROR; +} + + +/* Called normally by an output pin on an input pin to try and establish a + connection. +*/ + +STDMETHODIMP +CBasePin::ReceiveConnection( + IPin * pConnector, // this is the pin who we will connect to + const AM_MEDIA_TYPE *pmt // this is the media type we will exchange +) +{ + CheckPointer(pConnector,E_POINTER); + CheckPointer(pmt,E_POINTER); + ValidateReadPtr(pConnector,sizeof(IPin)); + ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); + CAutoLock cObjectLock(m_pLock); + + /* Are we already connected */ + if (m_Connected) { + return VFW_E_ALREADY_CONNECTED; + } + + /* See if the filter is active */ + if (!IsStopped() && !m_bCanReconnectWhenActive) { + return VFW_E_NOT_STOPPED; + } + + HRESULT hr = CheckConnect(pConnector); + if (FAILED(hr)) { + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + +#ifdef DXMPERF + PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); +#endif // DXMPERF + + return hr; + } + + /* Ask derived class if this media type is ok */ + + CMediaType * pcmt = (CMediaType*) pmt; + hr = CheckMediaType(pcmt); + if (hr != NOERROR) { + // no -we don't support this media type + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + // return a specific media type error if there is one + // or map a general failure code to something more helpful + // (in particular S_FALSE gets changed to an error code) + if (SUCCEEDED(hr) || + (hr == E_FAIL) || + (hr == E_INVALIDARG)) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + +#ifdef DXMPERF + PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); +#endif // DXMPERF + + return hr; + } + + /* Complete the connection */ + + m_Connected = pConnector; + m_Connected->AddRef(); + hr = SetMediaType(pcmt); + if (SUCCEEDED(hr)) { + hr = CompleteConnect(pConnector); + if (SUCCEEDED(hr)) { + +#ifdef DXMPERF + PERFLOG_RXCONNECT( pConnector, (IPin *) this, NOERROR, pmt ); +#endif // DXMPERF + + return NOERROR; + } + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection."))); + m_Connected->Release(); + m_Connected = NULL; + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + +#ifdef DXMPERF + PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); +#endif // DXMPERF + + return hr; +} + + +/* Called when we want to terminate a pin connection */ + +STDMETHODIMP +CBasePin::Disconnect() +{ + CAutoLock cObjectLock(m_pLock); + + /* See if the filter is active */ + if (!IsStopped()) { + return VFW_E_NOT_STOPPED; + } + + return DisconnectInternal(); +} + +STDMETHODIMP +CBasePin::DisconnectInternal() +{ + ASSERT(CritCheckIn(m_pLock)); + + if (m_Connected) { + HRESULT hr = BreakConnect(); + if( FAILED( hr ) ) { + +#ifdef DXMPERF + PERFLOG_DISCONNECT( (IPin *) this, m_Connected, hr ); +#endif // DXMPERF + + // There is usually a bug in the program if BreakConnect() fails. + DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." ); + return hr; + } + + m_Connected->Release(); + m_Connected = NULL; + +#ifdef DXMPERF + PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_OK ); +#endif // DXMPERF + + return S_OK; + } else { + // no connection - not an error + +#ifdef DXMPERF + PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_FALSE ); +#endif // DXMPERF + + return S_FALSE; + } +} + + +/* Return an AddRef()'d pointer to the connected pin if there is one */ +STDMETHODIMP +CBasePin::ConnectedTo( + __deref_out IPin **ppPin +) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + // + // It's pointless to lock here. + // The caller should ensure integrity. + // + + IPin *pPin = m_Connected; + *ppPin = pPin; + if (pPin != NULL) { + pPin->AddRef(); + return S_OK; + } else { + ASSERT(*ppPin == NULL); + return VFW_E_NOT_CONNECTED; + } +} + +/* Return the media type of the connection */ +STDMETHODIMP +CBasePin::ConnectionMediaType( + __out AM_MEDIA_TYPE *pmt +) +{ + CheckPointer(pmt,E_POINTER); + ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE)); + CAutoLock cObjectLock(m_pLock); + + /* Copy constructor of m_mt allocates the memory */ + if (IsConnected()) { + CopyMediaType( pmt, &m_mt ); + return S_OK; + } else { + ((CMediaType *)pmt)->InitMediaType(); + return VFW_E_NOT_CONNECTED; + } +} + +/* Return information about the filter we are connect to */ + +STDMETHODIMP +CBasePin::QueryPinInfo( + __out PIN_INFO * pInfo +) +{ + CheckPointer(pInfo,E_POINTER); + ValidateReadWritePtr(pInfo,sizeof(PIN_INFO)); + + pInfo->pFilter = m_pFilter; + if (m_pFilter) { + m_pFilter->AddRef(); + } + + if (m_pName) { + (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); + } else { + pInfo->achName[0] = L'\0'; + } + + pInfo->dir = m_dir; + + return NOERROR; +} + +STDMETHODIMP +CBasePin::QueryDirection( + __out PIN_DIRECTION * pPinDir +) +{ + CheckPointer(pPinDir,E_POINTER); + ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION)); + + *pPinDir = m_dir; + return NOERROR; +} + +// Default QueryId to return the pin's name +STDMETHODIMP +CBasePin::QueryId( + __deref_out LPWSTR * Id +) +{ + // We're not going away because someone's got a pointer to us + // so there's no need to lock + + return AMGetWideString(Name(), Id); +} + +/* Does this pin support this media type WARNING this interface function does + not lock the main object as it is meant to be asynchronous by nature - if + the media types you support depend on some internal state that is updated + dynamically then you will need to implement locking in a derived class */ + +STDMETHODIMP +CBasePin::QueryAccept( + const AM_MEDIA_TYPE *pmt +) +{ + CheckPointer(pmt,E_POINTER); + ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); + + /* The CheckMediaType method is valid to return error codes if the media + type is horrible, an example might be E_INVALIDARG. What we do here + is map all the error codes into either S_OK or S_FALSE regardless */ + + HRESULT hr = CheckMediaType((CMediaType*)pmt); + if (FAILED(hr)) { + return S_FALSE; + } + // note that the only defined success codes should be S_OK and S_FALSE... + return hr; +} + + +/* This can be called to return an enumerator for the pin's list of preferred + media types. An input pin is not obliged to have any preferred formats + although it can do. For example, the window renderer has a preferred type + which describes a video image that matches the current window size. All + output pins should expose at least one preferred format otherwise it is + possible that neither pin has any types and so no connection is possible */ + +STDMETHODIMP +CBasePin::EnumMediaTypes( + __deref_out IEnumMediaTypes **ppEnum +) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + + /* Create a new ref counted enumerator */ + + *ppEnum = new CEnumMediaTypes(this, + NULL); + + if (*ppEnum == NULL) { + return E_OUTOFMEMORY; + } + + return NOERROR; +} + + + +/* This is a virtual function that returns a media type corresponding with + place iPosition in the list. This base class simply returns an error as + we support no media types by default but derived classes should override */ + +HRESULT CBasePin::GetMediaType(int iPosition, __inout CMediaType *pMediaType) +{ + UNREFERENCED_PARAMETER(iPosition); + UNREFERENCED_PARAMETER(pMediaType); + return E_UNEXPECTED; +} + + +/* This is a virtual function that returns the current media type version. + The base class initialises the media type enumerators with the value 1 + By default we always returns that same value. A Derived class may change + the list of media types available and after doing so it should increment + the version either in a method derived from this, or more simply by just + incrementing the m_TypeVersion base pin variable. The type enumerators + call this when they want to see if their enumerations are out of date */ + +LONG CBasePin::GetMediaTypeVersion() +{ + return m_TypeVersion; +} + + +/* Increment the cookie representing the current media type version */ + +void CBasePin::IncrementTypeVersion() +{ + InterlockedIncrement(&m_TypeVersion); +} + + +/* Called by IMediaFilter implementation when the state changes from Stopped + to either paused or running and in derived classes could do things like + commit memory and grab hardware resource (the default is to do nothing) */ + +HRESULT +CBasePin::Active(void) +{ + return NOERROR; +} + +/* Called by IMediaFilter implementation when the state changes from + to either paused to running and in derived classes could do things like + commit memory and grab hardware resource (the default is to do nothing) */ + +HRESULT +CBasePin::Run(REFERENCE_TIME tStart) +{ + UNREFERENCED_PARAMETER(tStart); + return NOERROR; +} + + +/* Also called by the IMediaFilter implementation when the state changes to + Stopped at which point you should decommit allocators and free hardware + resources you grabbed in the Active call (default is also to do nothing) */ + +HRESULT +CBasePin::Inactive(void) +{ + m_bRunTimeError = FALSE; + return NOERROR; +} + + +// Called when no more data will arrive +STDMETHODIMP +CBasePin::EndOfStream(void) +{ + return S_OK; +} + + +STDMETHODIMP +CBasePin::SetSink(IQualityControl * piqc) +{ + CAutoLock cObjectLock(m_pLock); + if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl)); + m_pQSink = piqc; + return NOERROR; +} // SetSink + + +STDMETHODIMP +CBasePin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(q); + UNREFERENCED_PARAMETER(pSender); + DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)"); + return E_NOTIMPL; +} //Notify + + +// NewSegment notifies of the start/stop/rate applying to the data +// about to be received. Default implementation records data and +// returns S_OK. +// Override this to pass downstream. +STDMETHODIMP +CBasePin::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + m_tStart = tStart; + m_tStop = tStop; + m_dRate = dRate; + + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CBaseOutputPin +//===================================================================== +//===================================================================== + + +CBaseOutputPin::CBaseOutputPin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), + m_pAllocator(NULL), + m_pInputPin(NULL) +{ + ASSERT(pFilter); +} + +#ifdef UNICODE +CBaseOutputPin::CBaseOutputPin(__in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), + m_pAllocator(NULL), + m_pInputPin(NULL) +{ + ASSERT(pFilter); +} +#endif + +/* This is called after a media type has been proposed + + Try to complete the connection by agreeing the allocator +*/ +HRESULT +CBaseOutputPin::CompleteConnect(IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + return DecideAllocator(m_pInputPin, &m_pAllocator); +} + + +/* This method is called when the output pin is about to try and connect to + an input pin. It is at this point that you should try and grab any extra + interfaces that you need, in this case IMemInputPin. Because this is + only called if we are not currently connected we do NOT need to call + BreakConnect. This also makes it easier to derive classes from us as + BreakConnect is only called when we actually have to break a connection + (or a partly made connection) and not when we are checking a connection */ + +/* Overriden from CBasePin */ + +HRESULT +CBaseOutputPin::CheckConnect(IPin * pPin) +{ + HRESULT hr = CBasePin::CheckConnect(pPin); + if (FAILED(hr)) { + return hr; + } + + // get an input pin and an allocator interface + hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin); + if (FAILED(hr)) { + return hr; + } + return NOERROR; +} + + +/* Overriden from CBasePin */ + +HRESULT +CBaseOutputPin::BreakConnect() +{ + /* Release any allocator we hold */ + + if (m_pAllocator) { + // Always decommit the allocator because a downstream filter may or + // may not decommit the connection's allocator. A memory leak could + // occur if the allocator is not decommited when a connection is broken. + HRESULT hr = m_pAllocator->Decommit(); + if( FAILED( hr ) ) { + return hr; + } + + m_pAllocator->Release(); + m_pAllocator = NULL; + } + + /* Release any input pin interface we hold */ + + if (m_pInputPin) { + m_pInputPin->Release(); + m_pInputPin = NULL; + } + return NOERROR; +} + + +/* This is called when the input pin didn't give us a valid allocator */ + +HRESULT +CBaseOutputPin::InitAllocator(__deref_out IMemAllocator **ppAlloc) +{ + return CreateMemoryAllocator(ppAlloc); +} + + +/* Decide on an allocator, override this if you want to use your own allocator + Override DecideBufferSize to call SetProperties. If the input pin fails + the GetAllocator call then this will construct a CMemAllocator and call + DecideBufferSize on that, and if that fails then we are completely hosed. + If the you succeed the DecideBufferSize call, we will notify the input + pin of the selected allocator. NOTE this is called during Connect() which + therefore looks after grabbing and locking the object's critical section */ + +// We query the input pin for its requested properties and pass this to +// DecideBufferSize to allow it to fulfill requests that it is happy +// with (eg most people don't care about alignment and are thus happy to +// use the downstream pin's alignment request). + +HRESULT +CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, __deref_out IMemAllocator **ppAlloc) +{ + HRESULT hr = NOERROR; + *ppAlloc = NULL; + + // get downstream prop request + // the derived class may modify this in DecideBufferSize, but + // we assume that he will consistently modify it the same way, + // so we only get it once + ALLOCATOR_PROPERTIES prop; + ZeroMemory(&prop, sizeof(prop)); + + // whatever he returns, we assume prop is either all zeros + // or he has filled it out. + pPin->GetAllocatorRequirements(&prop); + + // if he doesn't care about alignment, then set it to 1 + if (prop.cbAlign == 0) { + prop.cbAlign = 1; + } + + /* Try the allocator provided by the input pin */ + + hr = pPin->GetAllocator(ppAlloc); + if (SUCCEEDED(hr)) { + + hr = DecideBufferSize(*ppAlloc, &prop); + if (SUCCEEDED(hr)) { + hr = pPin->NotifyAllocator(*ppAlloc, FALSE); + if (SUCCEEDED(hr)) { + return NOERROR; + } + } + } + + /* If the GetAllocator failed we may not have an interface */ + + if (*ppAlloc) { + (*ppAlloc)->Release(); + *ppAlloc = NULL; + } + + /* Try the output pin's allocator by the same method */ + + hr = InitAllocator(ppAlloc); + if (SUCCEEDED(hr)) { + + // note - the properties passed here are in the same + // structure as above and may have been modified by + // the previous call to DecideBufferSize + hr = DecideBufferSize(*ppAlloc, &prop); + if (SUCCEEDED(hr)) { + hr = pPin->NotifyAllocator(*ppAlloc, FALSE); + if (SUCCEEDED(hr)) { + return NOERROR; + } + } + } + + /* Likewise we may not have an interface to release */ + + if (*ppAlloc) { + (*ppAlloc)->Release(); + *ppAlloc = NULL; + } + return hr; +} + + +/* This returns an empty sample buffer from the allocator WARNING the same + dangers and restrictions apply here as described below for Deliver() */ + +HRESULT +CBaseOutputPin::GetDeliveryBuffer(__deref_out IMediaSample ** ppSample, + __in_opt REFERENCE_TIME * pStartTime, + __in_opt REFERENCE_TIME * pEndTime, + DWORD dwFlags) +{ + if (m_pAllocator != NULL) { + return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags); + } else { + return E_NOINTERFACE; + } +} + + +/* Deliver a filled-in sample to the connected input pin. NOTE the object must + have locked itself before calling us otherwise we may get halfway through + executing this method only to find the filter graph has got in and + disconnected us from the input pin. If the filter has no worker threads + then the lock is best applied on Receive(), otherwise it should be done + when the worker thread is ready to deliver. There is a wee snag to worker + threads that this shows up. The worker thread must lock the object when + it is ready to deliver a sample, but it may have to wait until a state + change has completed, but that may never complete because the state change + is waiting for the worker thread to complete. The way to handle this is for + the state change code to grab the critical section, then set an abort event + for the worker thread, then release the critical section and wait for the + worker thread to see the event we set and then signal that it has finished + (with another event). At which point the state change code can complete */ + +// note (if you've still got any breath left after reading that) that you +// need to release the sample yourself after this call. if the connected +// input pin needs to hold onto the sample beyond the call, it will addref +// the sample itself. + +// of course you must release this one and call GetDeliveryBuffer for the +// next. You cannot reuse it directly. + +HRESULT +CBaseOutputPin::Deliver(IMediaSample * pSample) +{ + if (m_pInputPin == NULL) { + return VFW_E_NOT_CONNECTED; + } + +#ifdef DXMPERF + PERFLOG_DELIVER( m_pName ? m_pName : L"CBaseOutputPin", (IPin *) this, (IPin *) m_pInputPin, pSample, &m_mt ); +#endif // DXMPERF + + return m_pInputPin->Receive(pSample); +} + + +// called from elsewhere in our filter to pass EOS downstream to +// our connected input pin +HRESULT +CBaseOutputPin::DeliverEndOfStream(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->EndOfStream(); +} + + +/* Commit the allocator's memory, this is called through IMediaFilter + which is responsible for locking the object before calling us */ + +HRESULT +CBaseOutputPin::Active(void) +{ + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + return m_pAllocator->Commit(); +} + + +/* Free up or unprepare allocator's memory, this is called through + IMediaFilter which is responsible for locking the object first */ + +HRESULT +CBaseOutputPin::Inactive(void) +{ + m_bRunTimeError = FALSE; + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + return m_pAllocator->Decommit(); +} + +// we have a default handling of EndOfStream which is to return +// an error, since this should be called on input pins only +STDMETHODIMP +CBaseOutputPin::EndOfStream(void) +{ + return E_UNEXPECTED; +} + + +// BeginFlush should be called on input pins only +STDMETHODIMP +CBaseOutputPin::BeginFlush(void) +{ + return E_UNEXPECTED; +} + +// EndFlush should be called on input pins only +STDMETHODIMP +CBaseOutputPin::EndFlush(void) +{ + return E_UNEXPECTED; +} + +// call BeginFlush on the connected input pin +HRESULT +CBaseOutputPin::DeliverBeginFlush(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->BeginFlush(); +} + +// call EndFlush on the connected input pin +HRESULT +CBaseOutputPin::DeliverEndFlush(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->EndFlush(); +} +// deliver NewSegment to connected pin +HRESULT +CBaseOutputPin::DeliverNewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->NewSegment(tStart, tStop, dRate); +} + + +//===================================================================== +//===================================================================== +// Implements CBaseInputPin +//===================================================================== +//===================================================================== + + +/* Constructor creates a default allocator object */ + +CBaseInputPin::CBaseInputPin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pPinName) : + CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), + m_pAllocator(NULL), + m_bReadOnly(FALSE), + m_bFlushing(FALSE) +{ + ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); +} + +#ifdef UNICODE +CBaseInputPin::CBaseInputPin(__in LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pPinName) : + CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), + m_pAllocator(NULL), + m_bReadOnly(FALSE), + m_bFlushing(FALSE) +{ + ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); +} +#endif + +/* Destructor releases it's reference count on the default allocator */ + +CBaseInputPin::~CBaseInputPin() +{ + if (m_pAllocator != NULL) { + m_pAllocator->Release(); + m_pAllocator = NULL; + } +} + + +// override this to publicise our interfaces +STDMETHODIMP +CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + /* Do we know about this interface */ + + if (riid == IID_IMemInputPin) { + return GetInterface((IMemInputPin *) this, ppv); + } else { + return CBasePin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* Return the allocator interface that this input pin would like the output + pin to use. NOTE subsequent calls to GetAllocator should all return an + interface onto the SAME object so we create one object at the start + + Note: + The allocator is Release()'d on disconnect and replaced on + NotifyAllocator(). + + Override this to provide your own allocator. +*/ + +STDMETHODIMP +CBaseInputPin::GetAllocator( + __deref_out IMemAllocator **ppAllocator) +{ + CheckPointer(ppAllocator,E_POINTER); + ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pAllocator == NULL) { + HRESULT hr = CreateMemoryAllocator(&m_pAllocator); + if (FAILED(hr)) { + return hr; + } + } + ASSERT(m_pAllocator != NULL); + *ppAllocator = m_pAllocator; + m_pAllocator->AddRef(); + return NOERROR; +} + + +/* Tell the input pin which allocator the output pin is actually going to use + Override this if you care - NOTE the locking we do both here and also in + GetAllocator is unnecessary but derived classes that do something useful + will undoubtedly have to lock the object so this might help remind people */ + +STDMETHODIMP +CBaseInputPin::NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly) +{ + CheckPointer(pAllocator,E_POINTER); + ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); + CAutoLock cObjectLock(m_pLock); + + IMemAllocator *pOldAllocator = m_pAllocator; + pAllocator->AddRef(); + m_pAllocator = pAllocator; + + if (pOldAllocator != NULL) { + pOldAllocator->Release(); + } + + // the readonly flag indicates whether samples from this allocator should + // be regarded as readonly - if true, then inplace transforms will not be + // allowed. + m_bReadOnly = (BYTE)bReadOnly; + return NOERROR; +} + + +HRESULT +CBaseInputPin::BreakConnect() +{ + /* We don't need our allocator any more */ + if (m_pAllocator) { + // Always decommit the allocator because a downstream filter may or + // may not decommit the connection's allocator. A memory leak could + // occur if the allocator is not decommited when a pin is disconnected. + HRESULT hr = m_pAllocator->Decommit(); + if( FAILED( hr ) ) { + return hr; + } + + m_pAllocator->Release(); + m_pAllocator = NULL; + } + + return S_OK; +} + + +/* Do something with this media sample - this base class checks to see if the + format has changed with this media sample and if so checks that the filter + will accept it, generating a run time error if not. Once we have raised a + run time error we set a flag so that no more samples will be accepted + + It is important that any filter should override this method and implement + synchronization so that samples are not processed when the pin is + disconnected etc +*/ + +STDMETHODIMP +CBaseInputPin::Receive(IMediaSample *pSample) +{ + CheckPointer(pSample,E_POINTER); + ValidateReadPtr(pSample,sizeof(IMediaSample)); + ASSERT(pSample); + + HRESULT hr = CheckStreaming(); + if (S_OK != hr) { + return hr; + } + +#ifdef DXMPERF + PERFLOG_RECEIVE( m_pName ? m_pName : L"CBaseInputPin", (IPin *) m_Connected, (IPin *) this, pSample, &m_mt ); +#endif // DXMPERF + + + /* Check for IMediaSample2 */ + IMediaSample2 *pSample2; + if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { + hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps); + pSample2->Release(); + if (FAILED(hr)) { + return hr; + } + } else { + /* Get the properties the hard way */ + m_SampleProps.cbData = sizeof(m_SampleProps); + m_SampleProps.dwTypeSpecificFlags = 0; + m_SampleProps.dwStreamId = AM_STREAM_MEDIA; + m_SampleProps.dwSampleFlags = 0; + if (S_OK == pSample->IsDiscontinuity()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + } + if (S_OK == pSample->IsPreroll()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL; + } + if (S_OK == pSample->IsSyncPoint()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; + } + if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart, + &m_SampleProps.tStop))) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID | + AM_SAMPLE_STOPVALID; + } + if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED; + } + pSample->GetPointer(&m_SampleProps.pbBuffer); + m_SampleProps.lActual = pSample->GetActualDataLength(); + m_SampleProps.cbBuffer = pSample->GetSize(); + } + + /* Has the format changed in this sample */ + + if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) { + return NOERROR; + } + + /* Check the derived class accepts this format */ + /* This shouldn't fail as the source must call QueryAccept first */ + + hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType); + + if (hr == NOERROR) { + return NOERROR; + } + + /* Raise a runtime error if we fail the media type */ + + m_bRunTimeError = TRUE; + EndOfStream(); + m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0); + return VFW_E_INVALIDMEDIATYPE; +} + + +/* Receive multiple samples */ +STDMETHODIMP +CBaseInputPin::ReceiveMultiple ( + __in_ecount(nSamples) IMediaSample **pSamples, + long nSamples, + __out long *nSamplesProcessed) +{ + CheckPointer(pSamples,E_POINTER); + ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *)); + + HRESULT hr = S_OK; + *nSamplesProcessed = 0; + while (nSamples-- > 0) { + hr = Receive(pSamples[*nSamplesProcessed]); + + /* S_FALSE means don't send any more */ + if (hr != S_OK) { + break; + } + (*nSamplesProcessed)++; + } + return hr; +} + +/* See if Receive() might block */ +STDMETHODIMP +CBaseInputPin::ReceiveCanBlock() +{ + /* Ask all the output pins if they block + If there are no output pin assume we do block + */ + int cPins = m_pFilter->GetPinCount(); + int cOutputPins = 0; + for (int c = 0; c < cPins; c++) { + CBasePin *pPin = m_pFilter->GetPin(c); + if (NULL == pPin) { + break; + } + PIN_DIRECTION pd; + HRESULT hr = pPin->QueryDirection(&pd); + if (FAILED(hr)) { + return hr; + } + + if (pd == PINDIR_OUTPUT) { + + IPin *pConnected; + hr = pPin->ConnectedTo(&pConnected); + if (SUCCEEDED(hr)) { + ASSERT(pConnected != NULL); + cOutputPins++; + IMemInputPin *pInputPin; + hr = pConnected->QueryInterface( + IID_IMemInputPin, + (void **)&pInputPin); + pConnected->Release(); + if (SUCCEEDED(hr)) { + hr = pInputPin->ReceiveCanBlock(); + pInputPin->Release(); + if (hr != S_FALSE) { + return S_OK; + } + } else { + /* There's a transport we don't understand here */ + return S_OK; + } + } + } + } + return cOutputPins == 0 ? S_OK : S_FALSE; +} + +// Default handling for BeginFlush - call at the beginning +// of your implementation (makes sure that all Receive calls +// fail). After calling this, you need to free any queued data +// and then call downstream. +STDMETHODIMP +CBaseInputPin::BeginFlush(void) +{ + // BeginFlush is NOT synchronized with streaming but is part of + // a control action - hence we synchronize with the filter + CAutoLock lck(m_pLock); + + // if we are already in mid-flush, this is probably a mistake + // though not harmful - try to pick it up for now so I can think about it + ASSERT(!m_bFlushing); + + // first thing to do is ensure that no further Receive calls succeed + m_bFlushing = TRUE; + + // now discard any data and call downstream - must do that + // in derived classes + return S_OK; +} + +// default handling for EndFlush - call at end of your implementation +// - before calling this, ensure that there is no queued data and no thread +// pushing any more without a further receive, then call downstream, +// then call this method to clear the m_bFlushing flag and re-enable +// receives +STDMETHODIMP +CBaseInputPin::EndFlush(void) +{ + // Endlush is NOT synchronized with streaming but is part of + // a control action - hence we synchronize with the filter + CAutoLock lck(m_pLock); + + // almost certainly a mistake if we are not in mid-flush + ASSERT(m_bFlushing); + + // before calling, sync with pushing thread and ensure + // no more data is going downstream, then call EndFlush on + // downstream pins. + + // now re-enable Receives + m_bFlushing = FALSE; + + // No more errors + m_bRunTimeError = FALSE; + + return S_OK; +} + + +STDMETHODIMP +CBaseInputPin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(q); + CheckPointer(pSender,E_POINTER); + ValidateReadPtr(pSender,sizeof(IBaseFilter)); + DbgBreak("IQuality::Notify called on an input pin"); + return NOERROR; +} // Notify + +/* Free up or unprepare allocator's memory, this is called through + IMediaFilter which is responsible for locking the object first */ + +HRESULT +CBaseInputPin::Inactive(void) +{ + m_bRunTimeError = FALSE; + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + + m_bFlushing = FALSE; + + return m_pAllocator->Decommit(); +} + +// what requirements do we have of the allocator - override if you want +// to support other people's allocators but need a specific alignment +// or prefix. +STDMETHODIMP +CBaseInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps) +{ + UNREFERENCED_PARAMETER(pProps); + return E_NOTIMPL; +} + +// Check if it's OK to process data +// +HRESULT +CBaseInputPin::CheckStreaming() +{ + // Shouldn't be able to get any data if we're not connected! + ASSERT(IsConnected()); + + // Don't process stuff in Stopped state + if (IsStopped()) { + return VFW_E_WRONG_STATE; + } + if (m_bFlushing) { + return S_FALSE; + } + if (m_bRunTimeError) { + return VFW_E_RUNTIME_ERROR; + } + return S_OK; +} + +// Pass on the Quality notification q to +// a. Our QualityControl sink (if we have one) or else +// b. to our upstream filter +// and if that doesn't work, throw it away with a bad return code +HRESULT +CBaseInputPin::PassNotify(Quality& q) +{ + // We pass the message on, which means that we find the quality sink + // for our input pin and send it there + + DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform"))); + if (m_pQSink!=NULL) { + return m_pQSink->Notify(m_pFilter, q); + } else { + // no sink set, so pass it upstream + HRESULT hr; + IQualityControl * pIQC; + + hr = VFW_E_NOT_FOUND; // default + if (m_Connected) { + m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC); + + if (pIQC!=NULL) { + hr = pIQC->Notify(m_pFilter, q); + pIQC->Release(); + } + } + return hr; + } + +} // PassNotify + +//===================================================================== +//===================================================================== +// Memory allocation class, implements CMediaSample +//===================================================================== +//===================================================================== + + +/* NOTE The implementation of this class calls the CUnknown constructor with + a NULL outer unknown pointer. This has the effect of making us a self + contained class, ie any QueryInterface, AddRef or Release calls will be + routed to the class's NonDelegatingUnknown methods. You will typically + find that the classes that do this then override one or more of these + virtual functions to provide more specialised behaviour. A good example + of this is where a class wants to keep the QueryInterface internal but + still wants it's lifetime controlled by the external object */ + +/* The last two parameters have default values of NULL and zero */ + +CMediaSample::CMediaSample(__in_opt LPCTSTR pName, + __in_opt CBaseAllocator *pAllocator, + __inout_opt HRESULT *phr, + __in_bcount_opt(length) LPBYTE pBuffer, + LONG length) : + m_pBuffer(pBuffer), // Initialise the buffer + m_cbBuffer(length), // And it's length + m_lActual(length), // By default, actual = length + m_pMediaType(NULL), // No media type change + m_dwFlags(0), // Nothing set + m_cRef(0), // 0 ref count + m_dwTypeSpecificFlags(0), // Type specific flags + m_dwStreamId(AM_STREAM_MEDIA), // Stream id + m_pAllocator(pAllocator), // Allocator + m_pNext(NULL), + m_Start(0), + m_End(0), + m_MediaStart(0), + m_MediaEnd(0) +{ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CMediaSample", (IMediaSample *) this ); +#endif // DXMPERF + + /* We must have an owner and it must also be derived from class + CBaseAllocator BUT we do not hold a reference count on it */ + + ASSERT(pAllocator); + + if (length < 0) { + *phr = VFW_E_BUFFER_OVERFLOW; + m_cbBuffer = 0; + } +} + +#ifdef UNICODE +CMediaSample::CMediaSample(__in_opt LPCSTR pName, + __in_opt CBaseAllocator *pAllocator, + __inout_opt HRESULT *phr, + __in_bcount_opt(length) LPBYTE pBuffer, + LONG length) : + m_pBuffer(pBuffer), // Initialise the buffer + m_cbBuffer(length), // And it's length + m_lActual(length), // By default, actual = length + m_pMediaType(NULL), // No media type change + m_dwFlags(0), // Nothing set + m_cRef(0), // 0 ref count + m_dwTypeSpecificFlags(0), // Type specific flags + m_dwStreamId(AM_STREAM_MEDIA), // Stream id + m_pAllocator(pAllocator), // Allocator + m_pNext(NULL), + m_Start(0), + m_End(0), + m_MediaStart(0), + m_MediaEnd(0) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CMediaSample", (IMediaSample *) this ); +#endif // DXMPERF + + /* We must have an owner and it must also be derived from class + CBaseAllocator BUT we do not hold a reference count on it */ + + ASSERT(pAllocator); +} +#endif + +/* Destructor deletes the media type memory */ + +CMediaSample::~CMediaSample() +{ +#ifdef DXMPERF + PERFLOG_DTOR( L"CMediaSample", (IMediaSample *) this ); +#endif // DXMPERF + + if (m_pMediaType) { + DeleteMediaType(m_pMediaType); + } +} + +/* Override this to publicise our interfaces */ + +STDMETHODIMP +CMediaSample::QueryInterface(REFIID riid, __deref_out void **ppv) +{ + if (riid == IID_IMediaSample || + riid == IID_IMediaSample2 || + riid == IID_IUnknown) { + return GetInterface((IMediaSample *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CMediaSample::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + + +// -- CMediaSample lifetimes -- +// +// On final release of this sample buffer it is not deleted but +// returned to the freelist of the owning memory allocator +// +// The allocator may be waiting for the last buffer to be placed on the free +// list in order to decommit all the memory, so the ReleaseBuffer() call may +// result in this sample being deleted. We also need to hold a refcount on +// the allocator to stop that going away until we have finished with this. +// However, we cannot release the allocator before the ReleaseBuffer, as the +// release may cause us to be deleted. Similarly we can't do it afterwards. +// +// Thus we must leave it to the allocator to hold an addref on our behalf. +// When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer +// is called, he releases himself, possibly causing us and him to be deleted. + + +STDMETHODIMP_(ULONG) +CMediaSample::Release() +{ + /* Decrement our own private reference count */ + LONG lRef; + if (m_cRef == 1) { + lRef = 0; + m_cRef = 0; + } else { + lRef = InterlockedDecrement(&m_cRef); + } + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"), + this, m_cRef)); + + /* Did we release our final reference count */ + if (lRef == 0) { + /* Free all resources */ + if (m_dwFlags & Sample_TypeChanged) { + SetMediaType(NULL); + } + ASSERT(m_pMediaType == NULL); + m_dwFlags = 0; + m_dwTypeSpecificFlags = 0; + m_dwStreamId = AM_STREAM_MEDIA; + + /* This may cause us to be deleted */ + // Our refcount is reliably 0 thus no-one will mess with us + m_pAllocator->ReleaseBuffer(this); + } + return (ULONG)lRef; +} + + +// set the buffer pointer and length. Used by allocators that +// want variable sized pointers or pointers into already-read data. +// This is only available through a CMediaSample* not an IMediaSample* +// and so cannot be changed by clients. +HRESULT +CMediaSample::SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes) +{ + if (cBytes < 0) { + return VFW_E_BUFFER_OVERFLOW; + } + m_pBuffer = ptr; // new buffer area (could be null) + m_cbBuffer = cBytes; // length of buffer + m_lActual = cBytes; // length of data in buffer (assume full) + + return S_OK; +} + + +// get me a read/write pointer to this buffer's memory. I will actually +// want to use sizeUsed bytes. +STDMETHODIMP +CMediaSample::GetPointer(__deref_out BYTE ** ppBuffer) +{ + ValidateReadWritePtr(ppBuffer,sizeof(BYTE *)); + + // creator must have set pointer either during + // constructor or by SetPointer + ASSERT(m_pBuffer); + + *ppBuffer = m_pBuffer; + return NOERROR; +} + + +// return the size in bytes of this buffer +STDMETHODIMP_(LONG) +CMediaSample::GetSize(void) +{ + return m_cbBuffer; +} + + +// get the stream time at which this sample should start and finish. +STDMETHODIMP +CMediaSample::GetTime( + __out REFERENCE_TIME * pTimeStart, // put time here + __out REFERENCE_TIME * pTimeEnd +) +{ + ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME)); + ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME)); + + if (!(m_dwFlags & Sample_StopValid)) { + if (!(m_dwFlags & Sample_TimeValid)) { + return VFW_E_SAMPLE_TIME_NOT_SET; + } else { + *pTimeStart = m_Start; + + // Make sure old stuff works + *pTimeEnd = m_Start + 1; + return VFW_S_NO_STOP_TIME; + } + } + + *pTimeStart = m_Start; + *pTimeEnd = m_End; + return NOERROR; +} + + +// Set the stream time at which this sample should start and finish. +// NULL pointers means the time is reset +STDMETHODIMP +CMediaSample::SetTime( + __in_opt REFERENCE_TIME * pTimeStart, + __in_opt REFERENCE_TIME * pTimeEnd +) +{ + if (pTimeStart == NULL) { + ASSERT(pTimeEnd == NULL); + m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid); + } else { + if (pTimeEnd == NULL) { + m_Start = *pTimeStart; + m_dwFlags |= Sample_TimeValid; + m_dwFlags &= ~Sample_StopValid; + } else { + ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME)); + ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME)); + ASSERT(*pTimeEnd >= *pTimeStart); + + m_Start = *pTimeStart; + m_End = *pTimeEnd; + m_dwFlags |= Sample_TimeValid | Sample_StopValid; + } + } + return NOERROR; +} + + +// get the media times (eg bytes) for this sample +STDMETHODIMP +CMediaSample::GetMediaTime( + __out LONGLONG * pTimeStart, + __out LONGLONG * pTimeEnd +) +{ + ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG)); + ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG)); + + if (!(m_dwFlags & Sample_MediaTimeValid)) { + return VFW_E_MEDIA_TIME_NOT_SET; + } + + *pTimeStart = m_MediaStart; + *pTimeEnd = (m_MediaStart + m_MediaEnd); + return NOERROR; +} + + +// Set the media times for this sample +STDMETHODIMP +CMediaSample::SetMediaTime( + __in_opt LONGLONG * pTimeStart, + __in_opt LONGLONG * pTimeEnd +) +{ + if (pTimeStart == NULL) { + ASSERT(pTimeEnd == NULL); + m_dwFlags &= ~Sample_MediaTimeValid; + } else { + if (NULL == pTimeEnd) { + return E_POINTER; + } + ValidateReadPtr(pTimeStart,sizeof(LONGLONG)); + ValidateReadPtr(pTimeEnd,sizeof(LONGLONG)); + ASSERT(*pTimeEnd >= *pTimeStart); + + m_MediaStart = *pTimeStart; + m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart); + m_dwFlags |= Sample_MediaTimeValid; + } + return NOERROR; +} + + +STDMETHODIMP +CMediaSample::IsSyncPoint(void) +{ + if (m_dwFlags & Sample_SyncPoint) { + return S_OK; + } else { + return S_FALSE; + } +} + + +STDMETHODIMP +CMediaSample::SetSyncPoint(BOOL bIsSyncPoint) +{ + if (bIsSyncPoint) { + m_dwFlags |= Sample_SyncPoint; + } else { + m_dwFlags &= ~Sample_SyncPoint; + } + return NOERROR; +} + +// returns S_OK if there is a discontinuity in the data (this same is +// not a continuation of the previous stream of data +// - there has been a seek). +STDMETHODIMP +CMediaSample::IsDiscontinuity(void) +{ + if (m_dwFlags & Sample_Discontinuity) { + return S_OK; + } else { + return S_FALSE; + } +} + +// set the discontinuity property - TRUE if this sample is not a +// continuation, but a new sample after a seek. +STDMETHODIMP +CMediaSample::SetDiscontinuity(BOOL bDiscont) +{ + // should be TRUE or FALSE + if (bDiscont) { + m_dwFlags |= Sample_Discontinuity; + } else { + m_dwFlags &= ~Sample_Discontinuity; + } + return S_OK; +} + +STDMETHODIMP +CMediaSample::IsPreroll(void) +{ + if (m_dwFlags & Sample_Preroll) { + return S_OK; + } else { + return S_FALSE; + } +} + + +STDMETHODIMP +CMediaSample::SetPreroll(BOOL bIsPreroll) +{ + if (bIsPreroll) { + m_dwFlags |= Sample_Preroll; + } else { + m_dwFlags &= ~Sample_Preroll; + } + return NOERROR; +} + +STDMETHODIMP_(LONG) +CMediaSample::GetActualDataLength(void) +{ + return m_lActual; +} + + +STDMETHODIMP +CMediaSample::SetActualDataLength(LONG lActual) +{ + if (lActual > m_cbBuffer || lActual < 0) { + ASSERT(lActual <= GetSize()); + return VFW_E_BUFFER_OVERFLOW; + } + m_lActual = lActual; + return NOERROR; +} + + +/* These allow for limited format changes in band */ + +STDMETHODIMP +CMediaSample::GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType) +{ + ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *)); + ASSERT(ppMediaType); + + /* Do we have a new media type for them */ + + if (!(m_dwFlags & Sample_TypeChanged)) { + ASSERT(m_pMediaType == NULL); + *ppMediaType = NULL; + return S_FALSE; + } + + ASSERT(m_pMediaType); + + /* Create a copy of our media type */ + + *ppMediaType = CreateMediaType(m_pMediaType); + if (*ppMediaType == NULL) { + return E_OUTOFMEMORY; + } + return NOERROR; +} + + +/* Mark this sample as having a different format type */ + +STDMETHODIMP +CMediaSample::SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType) +{ + /* Delete the current media type */ + + if (m_pMediaType) { + DeleteMediaType(m_pMediaType); + m_pMediaType = NULL; + } + + /* Mechanism for resetting the format type */ + + if (pMediaType == NULL) { + m_dwFlags &= ~Sample_TypeChanged; + return NOERROR; + } + + ASSERT(pMediaType); + ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE)); + + /* Take a copy of the media type */ + + m_pMediaType = CreateMediaType(pMediaType); + if (m_pMediaType == NULL) { + m_dwFlags &= ~Sample_TypeChanged; + return E_OUTOFMEMORY; + } + + m_dwFlags |= Sample_TypeChanged; + return NOERROR; +} + +// Set and get properties (IMediaSample2) +STDMETHODIMP CMediaSample::GetProperties( + DWORD cbProperties, + __out_bcount(cbProperties) BYTE * pbProperties +) +{ + if (0 != cbProperties) { + CheckPointer(pbProperties, E_POINTER); + // Return generic stuff up to the length + AM_SAMPLE2_PROPERTIES Props; + Props.cbData = std::min(cbProperties, (ULONG)sizeof(Props)); + Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid; + Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags; + Props.pbBuffer = m_pBuffer; + Props.cbBuffer = m_cbBuffer; + Props.lActual = m_lActual; + Props.tStart = m_Start; + Props.tStop = m_End; + Props.dwStreamId = m_dwStreamId; + if (m_dwFlags & AM_SAMPLE_TYPECHANGED) { + Props.pMediaType = m_pMediaType; + } else { + Props.pMediaType = NULL; + } + CopyMemory(pbProperties, &Props, Props.cbData); + } + return S_OK; +} + +#define CONTAINS_FIELD(type, field, offset) \ + ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset) + +HRESULT CMediaSample::SetProperties( + DWORD cbProperties, + __in_bcount(cbProperties) const BYTE * pbProperties +) +{ + + /* Generic properties */ + AM_MEDIA_TYPE *pMediaType = NULL; + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) { + CheckPointer(pbProperties, E_POINTER); + AM_SAMPLE2_PROPERTIES *pProps = + (AM_SAMPLE2_PROPERTIES *)pbProperties; + + /* Don't use more data than is actually there */ + if (pProps->cbData < cbProperties) { + cbProperties = pProps->cbData; + } + /* We only handle IMediaSample2 */ + if (cbProperties > sizeof(*pProps) || + pProps->cbData > sizeof(*pProps)) { + return E_INVALIDARG; + } + /* Do checks first, the assignments (for backout) */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { + /* Check the flags */ + if (pProps->dwSampleFlags & + (~Sample_ValidFlags | Sample_MediaTimeValid)) { + return E_INVALIDARG; + } + /* Check a flag isn't being set for a property + not being provided + */ + if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) && + !(m_dwFlags & AM_SAMPLE_TIMEVALID) && + !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { + return E_INVALIDARG; + } + } + /* NB - can't SET the pointer or size */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) { + + /* Check pbBuffer */ + if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) { + return E_INVALIDARG; + } + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) { + + /* Check cbBuffer */ + if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) { + return E_INVALIDARG; + } + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) && + CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { + + /* Check lActual */ + if (pProps->cbBuffer < pProps->lActual) { + return E_INVALIDARG; + } + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { + + /* Check pMediaType */ + if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { + CheckPointer(pProps->pMediaType, E_POINTER); + pMediaType = CreateMediaType(pProps->pMediaType); + if (pMediaType == NULL) { + return E_OUTOFMEMORY; + } + } + } + + /* Now do the assignments */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) { + m_dwStreamId = pProps->dwStreamId; + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { + /* Set the flags */ + m_dwFlags = pProps->dwSampleFlags | + (m_dwFlags & Sample_MediaTimeValid); + m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + } else { + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) { + m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + } + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { + /* Set lActual */ + m_lActual = pProps->lActual; + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { + + /* Set the times */ + m_End = pProps->tStop; + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) { + + /* Set the times */ + m_Start = pProps->tStart; + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { + /* Set pMediaType */ + if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { + if (m_pMediaType != NULL) { + DeleteMediaType(m_pMediaType); + } + m_pMediaType = pMediaType; + } + } + + /* Fix up the type changed flag to correctly reflect the current state + If, for instance the input contained no type change but the + output does then if we don't do this we'd lose the + output media type. + */ + if (m_pMediaType) { + m_dwFlags |= Sample_TypeChanged; + } else { + m_dwFlags &= ~Sample_TypeChanged; + } + } + + return S_OK; +} + + +// +// The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(), +// IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the +// connected input pin. The application thread calls Block(). The +// following class members can only be called by the streaming thread. +// +// Deliver() +// DeliverNewSegment() +// StartUsingOutputPin() +// StopUsingOutputPin() +// ChangeOutputFormat() +// ChangeMediaType() +// DynamicReconnect() +// +// The following class members can only be called by the application thread. +// +// Block() +// SynchronousBlockOutputPin() +// AsynchronousBlockOutputPin() +// + +CDynamicOutputPin::CDynamicOutputPin( + __in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), + m_hStopEvent(NULL), + m_pGraphConfig(NULL), + m_bPinUsesReadOnlyAllocator(FALSE), + m_BlockState(NOT_BLOCKED), + m_hUnblockOutputPinEvent(NULL), + m_hNotifyCallerPinBlockedEvent(NULL), + m_dwBlockCallerThreadID(0), + m_dwNumOutstandingOutputPinUsers(0) +{ + HRESULT hr = Initialize(); + if( FAILED( hr ) ) { + *phr = hr; + return; + } +} + +#ifdef UNICODE +CDynamicOutputPin::CDynamicOutputPin( + __in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), + m_hStopEvent(NULL), + m_pGraphConfig(NULL), + m_bPinUsesReadOnlyAllocator(FALSE), + m_BlockState(NOT_BLOCKED), + m_hUnblockOutputPinEvent(NULL), + m_hNotifyCallerPinBlockedEvent(NULL), + m_dwBlockCallerThreadID(0), + m_dwNumOutstandingOutputPinUsers(0) +{ + HRESULT hr = Initialize(); + if( FAILED( hr ) ) { + *phr = hr; + return; + } +} +#endif + +CDynamicOutputPin::~CDynamicOutputPin() +{ + if(NULL != m_hUnblockOutputPinEvent) { + // This call should not fail because we have access to m_hUnblockOutputPinEvent + // and m_hUnblockOutputPinEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent)); + } + + if(NULL != m_hNotifyCallerPinBlockedEvent) { + // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent + // and m_hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + } +} + +HRESULT CDynamicOutputPin::Initialize(void) +{ + m_hUnblockOutputPinEvent = ::CreateEvent( NULL, // The event will have the default security descriptor. + TRUE, // This is a manual reset event. + TRUE, // The event is initially signaled. + NULL ); // The event is not named. + + // CreateEvent() returns NULL if an error occurs. + if(NULL == m_hUnblockOutputPinEvent) { + return AmGetLastErrorToHResult(); + } + + // Set flag to say we can reconnect while streaming. + SetReconnectWhenActive(true); + + return S_OK; +} + +STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + if(riid == IID_IPinFlowControl) { + return GetInterface(static_cast(this), ppv); + } else { + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); + } +} + +STDMETHODIMP CDynamicOutputPin::Disconnect(void) +{ + CAutoLock cObjectLock(m_pLock); + return DisconnectInternal(); +} + +STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent) +{ + const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK; + + // Check for illegal flags. + if(dwBlockFlags & ~VALID_FLAGS) { + return E_INVALIDARG; + } + + // Make sure the event is unsignaled. + if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) { + if( !::ResetEvent( hEvent ) ) { + return AmGetLastErrorToHResult(); + } + } + + // No flags are set if we are unblocking the output pin. + if(0 == dwBlockFlags) { + + // This parameter should be NULL because unblock operations are always synchronous. + // There is no need to notify the caller when the event is done. + if(NULL != hEvent) { + return E_INVALIDARG; + } + } + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + HRESULT hr; + + if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) { + // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous. + // If hEvent is not NULL, the block is asynchronous. + if(NULL == hEvent) { + hr = SynchronousBlockOutputPin(); + } else { + hr = AsynchronousBlockOutputPin(hEvent); + } + } else { + hr = UnblockOutputPin(); + } + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + if(FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void) +{ + HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL, // The event will have the default security attributes. + FALSE, // This is an automatic reset event. + FALSE, // The event is initially unsignaled. + NULL ); // The event is not named. + + // CreateEvent() returns NULL if an error occurs. + if(NULL == hNotifyCallerPinBlockedEvent) { + return AmGetLastErrorToHResult(); + } + + HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent); + if(FAILED(hr)) { + // This call should not fail because we have access to hNotifyCallerPinBlockedEvent + // and hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); + + return hr; + } + + hr = WaitEvent(hNotifyCallerPinBlockedEvent); + + // This call should not fail because we have access to hNotifyCallerPinBlockedEvent + // and hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); + + if(FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent) +{ + // This function holds the m_BlockStateLock because it uses + // m_dwBlockCallerThreadID, m_BlockState and + // m_hNotifyCallerPinBlockedEvent. + CAutoLock alBlockStateLock(&m_BlockStateLock); + + if(NOT_BLOCKED != m_BlockState) { + if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) { + return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD; + } else { + return VFW_E_PIN_ALREADY_BLOCKED; + } + } + + BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(), + hNotifyCallerPinBlockedEvent, + ::GetCurrentProcess(), + &m_hNotifyCallerPinBlockedEvent, + EVENT_MODIFY_STATE, + FALSE, + 0 ); + if( !fSuccess ) { + return AmGetLastErrorToHResult(); + } + + m_BlockState = PENDING; + m_dwBlockCallerThreadID = ::GetCurrentThreadId(); + + // The output pin cannot be blocked if the streaming thread is + // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive() + // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it + // cannot be blocked if the streaming thread is calling DynamicReconnect(), + // ChangeMediaType() or ChangeOutputFormat(). + if(!StreamingThreadUsingOutputPin()) { + + // The output pin can be immediately blocked. + BlockOutputPin(); + } + + return S_OK; +} + +void CDynamicOutputPin::BlockOutputPin(void) +{ + // The caller should always hold the m_BlockStateLock because this function + // uses m_BlockState and m_hNotifyCallerPinBlockedEvent. + ASSERT(CritCheckIn(&m_BlockStateLock)); + + // This function should not be called if the streaming thread is modifying + // the connection state or it's passing data downstream. + ASSERT(!StreamingThreadUsingOutputPin()); + + // This should not fail because we successfully created the event + // and we have the security permissions to change it's state. + EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent)); + + // This event should not fail because AsynchronousBlockOutputPin() successfully + // duplicated this handle and we have the appropriate security permissions. + EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + + m_BlockState = BLOCKED; + m_hNotifyCallerPinBlockedEvent = NULL; +} + +HRESULT CDynamicOutputPin::UnblockOutputPin(void) +{ + // UnblockOutputPin() holds the m_BlockStateLock because it + // uses m_BlockState, m_dwBlockCallerThreadID and + // m_hNotifyCallerPinBlockedEvent. + CAutoLock alBlockStateLock(&m_BlockStateLock); + + if(NOT_BLOCKED == m_BlockState) { + return S_FALSE; + } + + // This should not fail because we successfully created the event + // and we have the security permissions to change it's state. + EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent)); + + // Cancel the block operation if it's still pending. + if(NULL != m_hNotifyCallerPinBlockedEvent) { + // This event should not fail because AsynchronousBlockOutputPin() successfully + // duplicated this handle and we have the appropriate security permissions. + EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + } + + m_BlockState = NOT_BLOCKED; + m_dwBlockCallerThreadID = 0; + m_hNotifyCallerPinBlockedEvent = NULL; + + return S_OK; +} + +HRESULT CDynamicOutputPin::StartUsingOutputPin(void) +{ + // The caller should not hold m_BlockStateLock. If the caller does, + // a deadlock could occur. + ASSERT(CritCheckOut(&m_BlockStateLock)); + + CAutoLock alBlockStateLock(&m_BlockStateLock); + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + // Are we in the middle of a block operation? + while(BLOCKED == m_BlockState) { + m_BlockStateLock.Unlock(); + + // If this ASSERT fires, a deadlock could occur. The caller should make sure + // that this thread never acquires the Block State lock more than once. + ASSERT(CritCheckOut( &m_BlockStateLock )); + + // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event + // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired. + // See the Windows SDK documentation for more information on + // WaitForMultipleObjects(). + const DWORD UNBLOCK = WAIT_OBJECT_0; + const DWORD STOP = WAIT_OBJECT_0 + 1; + + HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent }; + DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE); + + DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE ); + + m_BlockStateLock.Lock(); + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + switch( dwReturnValue ) { + case UNBLOCK: + break; + + case STOP: + return VFW_E_STATE_CHANGED; + + case WAIT_FAILED: + return AmGetLastErrorToHResult(); + + default: + DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." ); + return E_UNEXPECTED; + } + } + + m_dwNumOutstandingOutputPinUsers++; + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + return S_OK; +} + +void CDynamicOutputPin::StopUsingOutputPin(void) +{ + CAutoLock alBlockStateLock(&m_BlockStateLock); + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + m_dwNumOutstandingOutputPinUsers--; + + if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) { + BlockOutputPin(); + } + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG +} + +bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void) +{ + CAutoLock alBlockStateLock(&m_BlockStateLock); + + return (m_dwNumOutstandingOutputPinUsers > 0); +} + +void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent) +{ + // This pointer is not addrefed because filters are not allowed to + // hold references to the filter graph manager. See the documentation for + // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information. + m_pGraphConfig = pGraphConfig; + + m_hStopEvent = hStopEvent; +} + +HRESULT CDynamicOutputPin::Active(void) +{ + // Make sure the user initialized the object by calling SetConfigInfo(). + if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) { + DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. ); + return E_FAIL; + } + + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then Active() is called. An event + // handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); + + return CBaseOutputPin::Active(); +} + +HRESULT CDynamicOutputPin::Inactive(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then Active() is called. An event + // handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(SetEvent(m_hStopEvent)); + + return CBaseOutputPin::Inactive(); +} + +HRESULT CDynamicOutputPin::DeliverBeginFlush(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. + // An event handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(SetEvent(m_hStopEvent)); + + return CBaseOutputPin::DeliverBeginFlush(); +} + +HRESULT CDynamicOutputPin::DeliverEndFlush(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. + // An event handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); + + return CBaseOutputPin::DeliverEndFlush(); +} + + +// ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly +// reconnects the output pin. +HRESULT CDynamicOutputPin::ChangeOutputFormat + ( + const AM_MEDIA_TYPE *pmt, + REFERENCE_TIME tSegmentStart, + REFERENCE_TIME tSegmentStop, + double dSegmentRate + ) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + // Callers should always pass a valid media type to ChangeOutputFormat() . + ASSERT(NULL != pmt); + + CMediaType cmt(*pmt); + HRESULT hr = ChangeMediaType(&cmt); + if (FAILED(hr)) { + return hr; + } + + hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate); + if( FAILED( hr ) ) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + // This function assumes the filter graph is running. + ASSERT(!IsStopped()); + + if(!IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + /* First check if the downstream pin will accept a dynamic + format change + */ + QzCComPtr pConnection; + + m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection); + if(pConnection != NULL) { + + if(S_OK == pConnection->DynamicQueryAccept(pmt)) { + + HRESULT hr = ChangeMediaTypeHelper(pmt); + if(FAILED(hr)) { + return hr; + } + + return S_OK; + } + } + + /* Can't do the dynamic connection */ + return DynamicReconnect(pmt); +} + +HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + HRESULT hr = m_Connected->ReceiveConnection(this, pmt); + if(FAILED(hr)) { + return hr; + } + + hr = SetMediaType(pmt); + if(FAILED(hr)) { + return hr; + } + + // Does this pin use the local memory transport? + if(NULL != m_pInputPin) { + // This function assumes that m_pInputPin and m_Connected are + // two different interfaces to the same object. + ASSERT(::IsEqualObject(m_Connected, m_pInputPin)); + + ALLOCATOR_PROPERTIES apInputPinRequirements; + apInputPinRequirements.cbAlign = 0; + apInputPinRequirements.cbBuffer = 0; + apInputPinRequirements.cbPrefix = 0; + apInputPinRequirements.cBuffers = 0; + + m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements); + + // A zero allignment does not make any sense. + if(0 == apInputPinRequirements.cbAlign) { + apInputPinRequirements.cbAlign = 1; + } + + hr = m_pAllocator->Decommit(); + if(FAILED(hr)) { + return hr; + } + + hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements); + if(FAILED(hr)) { + return hr; + } + + hr = m_pAllocator->Commit(); + if(FAILED(hr)) { + return hr; + } + + hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator); + if(FAILED(hr)) { + return hr; + } + } + + return S_OK; +} + +// this method has to be called from the thread that is pushing data, +// and it's the caller's responsibility to make sure that the thread +// has no outstand samples because they cannot be delivered after a +// reconnect +// +HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt ) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) { + return E_FAIL; + } + + HRESULT hr = m_pGraphConfig->Reconnect( + this, + NULL, + pmt, + NULL, + m_hStopEvent, + AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS ); + + return hr; +} + +HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); + if(SUCCEEDED(hr)) { + if(!IsStopped() && m_pAllocator) { + hr = m_pAllocator->Commit(); + ASSERT(hr != VFW_E_ALREADY_COMMITTED); + } + } + + return hr; +} + +#ifdef _DEBUG +void CDynamicOutputPin::AssertValid(void) +{ + // Make sure the object was correctly initialized. + + // This ASSERT only fires if the object failed to initialize + // and the user ignored the constructor's return code (phr). + ASSERT(NULL != m_hUnblockOutputPinEvent); + + // If either of these ASSERTs fire, the user did not correctly call + // SetConfigInfo(). + ASSERT(NULL != m_hStopEvent); + ASSERT(NULL != m_pGraphConfig); + + // Make sure the block state is consistent. + + CAutoLock alBlockStateLock(&m_BlockStateLock); + + // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED. + ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState)); + + // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete + // immediately. + ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) || + ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) ); + + // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and + // the user is not trying to block the pin. + ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState)); + + // If this ASSERT fires, the streaming thread is using the output pin and the + // output pin is blocked. + ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) || + ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) || + ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) ); +} +#endif // DEBUG + +HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent) +{ + const DWORD EVENT_SIGNALED = WAIT_OBJECT_0; + + DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE); + + switch( dwReturnValue ) { + case EVENT_SIGNALED: + return S_OK; + + case WAIT_FAILED: + return AmGetLastErrorToHResult(); + + default: + DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." ); + return E_UNEXPECTED; + } +} + +//===================================================================== +//===================================================================== +// Implements CBaseAllocator +//===================================================================== +//===================================================================== + + +/* Constructor overrides the default settings for the free list to request + that it be alertable (ie the list can be cast to a handle which can be + passed to WaitForSingleObject). Both of the allocator lists also ask for + object locking, the all list matches the object default settings but I + have included them here just so it is obvious what kind of list it is */ + +CBaseAllocator::CBaseAllocator(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + BOOL bEvent, + BOOL fEnableReleaseCallback + ) : + CUnknown(pName, pUnk), + m_lAllocated(0), + m_bChanged(FALSE), + m_bCommitted(FALSE), + m_bDecommitInProgress(FALSE), + m_lSize(0), + m_lCount(0), + m_lAlignment(0), + m_lPrefix(0), + m_hSem(NULL), + m_lWaiting(0), + m_fEnableReleaseCallback(fEnableReleaseCallback), + m_pNotify(NULL) +{ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBaseAllocator", (IMemAllocator *) this ); +#endif // DXMPERF + + if (bEvent) { + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + } +} + +#ifdef UNICODE +CBaseAllocator::CBaseAllocator(__in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + BOOL bEvent, + BOOL fEnableReleaseCallback) : + CUnknown(pName, pUnk), + m_lAllocated(0), + m_bChanged(FALSE), + m_bCommitted(FALSE), + m_bDecommitInProgress(FALSE), + m_lSize(0), + m_lCount(0), + m_lAlignment(0), + m_lPrefix(0), + m_hSem(NULL), + m_lWaiting(0), + m_fEnableReleaseCallback(fEnableReleaseCallback), + m_pNotify(NULL) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CBaseAllocator", (IMemAllocator *) this ); +#endif // DXMPERF + + if (bEvent) { + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + } +} +#endif + +/* Destructor */ + +CBaseAllocator::~CBaseAllocator() +{ + // we can't call Decommit here since that would mean a call to a + // pure virtual in destructor. + // We must assume that the derived class has gone into decommit state in + // its destructor. +#ifdef DXMPERF + PERFLOG_DTOR( L"CBaseAllocator", (IMemAllocator *) this ); +#endif // DXMPERF + + ASSERT(!m_bCommitted); + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } + if (m_pNotify) { + m_pNotify->Release(); + } +} + + +/* Override this to publicise our interfaces */ + +STDMETHODIMP +CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + /* Do we know about this interface */ + + if (riid == IID_IMemAllocator || + riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) { + return GetInterface((IMemAllocatorCallbackTemp *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* This sets the size and count of the required samples. The memory isn't + actually allocated until Commit() is called, if memory has already been + allocated then assuming no samples are outstanding the user may call us + to change the buffering, the memory will be released in Commit() */ + +STDMETHODIMP +CBaseAllocator::SetProperties( + __in ALLOCATOR_PROPERTIES* pRequest, + __out ALLOCATOR_PROPERTIES* pActual) +{ + CheckPointer(pRequest, E_POINTER); + CheckPointer(pActual, E_POINTER); + ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES)); + CAutoLock cObjectLock(this); + + ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); + + ASSERT(pRequest->cbBuffer > 0); + + /* Check the alignment requested */ + if (pRequest->cbAlign != 1) { + DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"), + pRequest->cbAlign)); + return VFW_E_BADALIGN; + } + + /* Can't do this if already committed, there is an argument that says we + should not reject the SetProperties call if there are buffers still + active. However this is called by the source filter, which is the same + person who is holding the samples. Therefore it is not unreasonable + for them to free all their samples before changing the requirements */ + + if (m_bCommitted) { + return VFW_E_ALREADY_COMMITTED; + } + + /* Must be no outstanding buffers */ + + if (m_lAllocated != m_lFree.GetCount()) { + return VFW_E_BUFFERS_OUTSTANDING; + } + + /* There isn't any real need to check the parameters as they + will just be rejected when the user finally calls Commit */ + + pActual->cbBuffer = m_lSize = pRequest->cbBuffer; + pActual->cBuffers = m_lCount = pRequest->cBuffers; + pActual->cbAlign = m_lAlignment = pRequest->cbAlign; + pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; + + m_bChanged = TRUE; + return NOERROR; +} + +STDMETHODIMP +CBaseAllocator::GetProperties( + __out ALLOCATOR_PROPERTIES * pActual) +{ + CheckPointer(pActual,E_POINTER); + ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); + + CAutoLock cObjectLock(this); + pActual->cbBuffer = m_lSize; + pActual->cBuffers = m_lCount; + pActual->cbAlign = m_lAlignment; + pActual->cbPrefix = m_lPrefix; + return NOERROR; +} + +// get container for a sample. Blocking, synchronous call to get the +// next free buffer (as represented by an IMediaSample interface). +// on return, the time etc properties will be invalid, but the buffer +// pointer and size will be correct. + +HRESULT CBaseAllocator::GetBuffer(__deref_out IMediaSample **ppBuffer, + __in_opt REFERENCE_TIME *pStartTime, + __in_opt REFERENCE_TIME *pEndTime, + DWORD dwFlags + ) +{ + UNREFERENCED_PARAMETER(pStartTime); + UNREFERENCED_PARAMETER(pEndTime); + UNREFERENCED_PARAMETER(dwFlags); + CMediaSample *pSample; + + *ppBuffer = NULL; + for (;;) + { + { // scope for lock + CAutoLock cObjectLock(this); + + /* Check we are committed */ + if (!m_bCommitted) { + return VFW_E_NOT_COMMITTED; + } + pSample = (CMediaSample *) m_lFree.RemoveHead(); + if (pSample == NULL) { + SetWaiting(); + } + } + + /* If we didn't get a sample then wait for the list to signal */ + + if (pSample) { + break; + } + if (dwFlags & AM_GBF_NOWAIT) { + return VFW_E_TIMEOUT; + } + ASSERT(m_hSem != NULL); + WaitForSingleObject(m_hSem, INFINITE); + } + + /* Addref the buffer up to one. On release + back to zero instead of being deleted, it will requeue itself by + calling the ReleaseBuffer member function. NOTE the owner of a + media sample must always be derived from CBaseAllocator */ + + + ASSERT(pSample->m_cRef == 0); + pSample->m_cRef = 1; + *ppBuffer = pSample; + +#ifdef DXMPERF + PERFLOG_GETBUFFER( (IMemAllocator *) this, pSample ); +#endif // DXMPERF + + return NOERROR; +} + + +/* Final release of a CMediaSample will call this */ + +STDMETHODIMP +CBaseAllocator::ReleaseBuffer(IMediaSample * pSample) +{ + CheckPointer(pSample,E_POINTER); + ValidateReadPtr(pSample,sizeof(IMediaSample)); + +#ifdef DXMPERF + PERFLOG_RELBUFFER( (IMemAllocator *) this, pSample ); +#endif // DXMPERF + + + BOOL bRelease = FALSE; + { + CAutoLock cal(this); + + /* Put back on the free list */ + + m_lFree.Add((CMediaSample *)pSample); + if (m_lWaiting != 0) { + NotifySample(); + } + + // if there is a pending Decommit, then we need to complete it by + // calling Free() when the last buffer is placed on the free list + + LONG l1 = m_lFree.GetCount(); + if (m_bDecommitInProgress && (l1 == m_lAllocated)) { + Free(); + m_bDecommitInProgress = FALSE; + bRelease = TRUE; + } + } + + if (m_pNotify) { + + ASSERT(m_fEnableReleaseCallback); + + // + // Note that this is not synchronized with setting up a notification + // method. + // + m_pNotify->NotifyRelease(); + } + + /* For each buffer there is one AddRef, made in GetBuffer and released + here. This may cause the allocator and all samples to be deleted */ + + if (bRelease) { + Release(); + } + return NOERROR; +} + +STDMETHODIMP +CBaseAllocator::SetNotify( + IMemAllocatorNotifyCallbackTemp* pNotify + ) +{ + ASSERT(m_fEnableReleaseCallback); + CAutoLock lck(this); + if (pNotify) { + pNotify->AddRef(); + } + if (m_pNotify) { + m_pNotify->Release(); + } + m_pNotify = pNotify; + return S_OK; +} + +STDMETHODIMP +CBaseAllocator::GetFreeCount( + __out LONG* plBuffersFree + ) +{ + ASSERT(m_fEnableReleaseCallback); + CAutoLock cObjectLock(this); + *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount(); + return NOERROR; +} + +void +CBaseAllocator::NotifySample() +{ + if (m_lWaiting != 0) { + ASSERT(m_hSem != NULL); + ReleaseSemaphore(m_hSem, m_lWaiting, 0); + m_lWaiting = 0; + } +} + +STDMETHODIMP +CBaseAllocator::Commit() +{ + /* Check we are not decommitted */ + CAutoLock cObjectLock(this); + + // cannot need to alloc or re-alloc if we are committed + if (m_bCommitted) { + return NOERROR; + } + + /* Allow GetBuffer calls */ + + m_bCommitted = TRUE; + + // is there a pending decommit ? if so, just cancel it + if (m_bDecommitInProgress) { + m_bDecommitInProgress = FALSE; + + // don't call Alloc at this point. He cannot allow SetProperties + // between Decommit and the last free, so the buffer size cannot have + // changed. And because some of the buffers are not free yet, he + // cannot re-alloc anyway. + return NOERROR; + } + + DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize)); + + // actually need to allocate the samples + HRESULT hr = Alloc(); + if (FAILED(hr)) { + m_bCommitted = FALSE; + return hr; + } + AddRef(); + return NOERROR; +} + + +STDMETHODIMP +CBaseAllocator::Decommit() +{ + BOOL bRelease = FALSE; + { + /* Check we are not already decommitted */ + CAutoLock cObjectLock(this); + if (m_bCommitted == FALSE) { + if (m_bDecommitInProgress == FALSE) { + return NOERROR; + } + } + + /* No more GetBuffer calls will succeed */ + m_bCommitted = FALSE; + + // are any buffers outstanding? + if (m_lFree.GetCount() < m_lAllocated) { + // please complete the decommit when last buffer is freed + m_bDecommitInProgress = TRUE; + } else { + m_bDecommitInProgress = FALSE; + + // need to complete the decommit here as there are no + // outstanding buffers + + Free(); + bRelease = TRUE; + } + + // Tell anyone waiting that they can go now so we can + // reject their call +#pragma warning(push) +#ifndef _PREFAST_ +#pragma warning(disable:4068) +#endif +#pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "Suppress warning related to Free() invalidating 'this' which is no applicable to CBaseAllocator::Free()") + NotifySample(); + +#pragma warning(pop) + } + + if (bRelease) { + Release(); + } + return NOERROR; +} + + +/* Base definition of allocation which checks we are ok to go ahead and do + the full allocation. We return S_FALSE if the requirements are the same */ + +HRESULT +CBaseAllocator::Alloc(void) +{ + /* Error if he hasn't set the size yet */ + if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) { + return VFW_E_SIZENOTSET; + } + + /* should never get here while buffers outstanding */ + ASSERT(m_lFree.GetCount() == m_lAllocated); + + /* If the requirements haven't changed then don't reallocate */ + if (m_bChanged == FALSE) { + return S_FALSE; + } + + return NOERROR; +} + +/* Implement CBaseAllocator::CSampleList::Remove(pSample) + Removes pSample from the list +*/ +void +CBaseAllocator::CSampleList::Remove(__inout CMediaSample * pSample) +{ + CMediaSample **pSearch; + for (pSearch = &m_List; + *pSearch != NULL; + pSearch = &(CBaseAllocator::NextSample(*pSearch))) { + if (*pSearch == pSample) { + *pSearch = CBaseAllocator::NextSample(pSample); + CBaseAllocator::NextSample(pSample) = NULL; + m_nOnList--; + return; + } + } + DbgBreak("Couldn't find sample in list"); +} + +//===================================================================== +//===================================================================== +// Implements CMemAllocator +//===================================================================== +//===================================================================== + + +/* This goes in the factory template table to create new instances */ +CUnknown *CMemAllocator::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) +{ + CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr); + return pUnkRet; +} + +CMemAllocator::CMemAllocator( + __in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr) + : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), + m_pBuffer(NULL) +{ +} + +#ifdef UNICODE +CMemAllocator::CMemAllocator( + __in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr) + : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), + m_pBuffer(NULL) +{ +} +#endif + +/* This sets the size and count of the required samples. The memory isn't + actually allocated until Commit() is called, if memory has already been + allocated then assuming no samples are outstanding the user may call us + to change the buffering, the memory will be released in Commit() */ +STDMETHODIMP +CMemAllocator::SetProperties( + __in ALLOCATOR_PROPERTIES* pRequest, + __out ALLOCATOR_PROPERTIES* pActual) +{ + CheckPointer(pActual,E_POINTER); + ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); + CAutoLock cObjectLock(this); + + ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); + + ASSERT(pRequest->cbBuffer > 0); + + SYSTEM_INFO SysInfo; + GetSystemInfo(&SysInfo); + + /* Check the alignment request is a power of 2 */ + if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) { + DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"), + pRequest->cbAlign)); + } + /* Check the alignment requested */ + if (pRequest->cbAlign == 0 || + (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) { + DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"), + pRequest->cbAlign, SysInfo.dwAllocationGranularity)); + return VFW_E_BADALIGN; + } + + /* Can't do this if already committed, there is an argument that says we + should not reject the SetProperties call if there are buffers still + active. However this is called by the source filter, which is the same + person who is holding the samples. Therefore it is not unreasonable + for them to free all their samples before changing the requirements */ + + if (m_bCommitted == TRUE) { + return VFW_E_ALREADY_COMMITTED; + } + + /* Must be no outstanding buffers */ + + if (m_lFree.GetCount() < m_lAllocated) { + return VFW_E_BUFFERS_OUTSTANDING; + } + + /* There isn't any real need to check the parameters as they + will just be rejected when the user finally calls Commit */ + + // round length up to alignment - remember that prefix is included in + // the alignment + LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix; + LONG lRemainder = lSize % pRequest->cbAlign; + if (lRemainder != 0) { + lSize = lSize - lRemainder + pRequest->cbAlign; + } + pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix); + + pActual->cBuffers = m_lCount = pRequest->cBuffers; + pActual->cbAlign = m_lAlignment = pRequest->cbAlign; + pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; + + m_bChanged = TRUE; + return NOERROR; +} + +// override this to allocate our resources when Commit is called. +// +// note that our resources may be already allocated when this is called, +// since we don't free them on Decommit. We will only be called when in +// decommit state with all buffers free. +// +// object locked by caller +HRESULT +CMemAllocator::Alloc(void) +{ + CAutoLock lck(this); + + /* Check he has called SetProperties */ + HRESULT hr = CBaseAllocator::Alloc(); + if (FAILED(hr)) { + return hr; + } + + /* If the requirements haven't changed then don't reallocate */ + if (hr == S_FALSE) { + ASSERT(m_pBuffer); + return NOERROR; + } + ASSERT(hr == S_OK); // we use this fact in the loop below + + /* Free the old resources */ + if (m_pBuffer) { + ReallyFree(); + } + + /* Make sure we've got reasonable values */ + if ( m_lSize < 0 || m_lPrefix < 0 || m_lCount < 0 ) { + return E_OUTOFMEMORY; + } + + /* Compute the aligned size */ + LONG lAlignedSize = m_lSize + m_lPrefix; + + /* Check overflow */ + if (lAlignedSize < m_lSize) { + return E_OUTOFMEMORY; + } + + if (m_lAlignment > 1) { + LONG lRemainder = lAlignedSize % m_lAlignment; + if (lRemainder != 0) { + LONG lNewSize = lAlignedSize + m_lAlignment - lRemainder; + if (lNewSize < lAlignedSize) { + return E_OUTOFMEMORY; + } + lAlignedSize = lNewSize; + } + } + + /* Create the contiguous memory block for the samples + making sure it's properly aligned (64K should be enough!) + */ + ASSERT(lAlignedSize % m_lAlignment == 0); + + LONGLONG lToAllocate = m_lCount * (LONGLONG)lAlignedSize; + + /* Check overflow */ + if (lToAllocate > MAXLONG) { + return E_OUTOFMEMORY; + } + + m_pBuffer = (PBYTE)VirtualAlloc(NULL, + (LONG)lToAllocate, + MEM_COMMIT, + PAGE_READWRITE); + + if (m_pBuffer == NULL) { + return E_OUTOFMEMORY; + } + + LPBYTE pNext = m_pBuffer; + CMediaSample *pSample; + + ASSERT(m_lAllocated == 0); + + // Create the new samples - we have allocated m_lSize bytes for each sample + // plus m_lPrefix bytes per sample as a prefix. We set the pointer to + // the memory after the prefix - so that GetPointer() will return a pointer + // to m_lSize bytes. + for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { + + + pSample = new CMediaSample( + NAME("Default memory media sample"), + this, + &hr, + pNext + m_lPrefix, // GetPointer() value + m_lSize); // not including prefix + + ASSERT(SUCCEEDED(hr)); + if (pSample == NULL) { + return E_OUTOFMEMORY; + } + + // This CANNOT fail + m_lFree.Add(pSample); + } + + m_bChanged = FALSE; + return NOERROR; +} + + +// override this to free up any resources we have allocated. +// called from the base class on Decommit when all buffers have been +// returned to the free list. +// +// caller has already locked the object. + +// in our case, we keep the memory until we are deleted, so +// we do nothing here. The memory is deleted in the destructor by +// calling ReallyFree() +void +CMemAllocator::Free(void) +{ + return; +} + + +// called from the destructor (and from Alloc if changing size/count) to +// actually free up the memory +void +CMemAllocator::ReallyFree(void) +{ + /* Should never be deleting this unless all buffers are freed */ + + ASSERT(m_lAllocated == m_lFree.GetCount()); + + /* Free up all the CMediaSamples */ + + CMediaSample *pSample; + for (;;) { + pSample = m_lFree.RemoveHead(); + if (pSample != NULL) { + delete pSample; + } else { + break; + } + } + + m_lAllocated = 0; + + // free the block of buffer memory + if (m_pBuffer) { + EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE)); + m_pBuffer = NULL; + } +} + + +/* Destructor frees our memory resources */ + +CMemAllocator::~CMemAllocator() +{ + Decommit(); + ReallyFree(); +} + +// ------------------------------------------------------------------------ +// filter registration through IFilterMapper. used if IFilterMapper is +// not found (Quartz 1.0 install) + +STDAPI +AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper * pIFM + , BOOL bRegister ) +{ + DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + + // unregister filter + // (as pins are subkeys of filter's CLSID key + // they do not need to be removed separately). + // + DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); + HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) ); + + + if( bRegister ) + { + // register filter + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); + hr = pIFM->RegisterFilter( *(psetupdata->clsID) + , psetupdata->strName + , psetupdata->dwMerit ); + if( SUCCEEDED(hr) ) + { + // all its pins + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins"))); + for( UINT m1=0; m1 < psetupdata->nPins; m1++ ) + { + hr = pIFM->RegisterPin( *(psetupdata->clsID) + , psetupdata->lpPin[m1].strName + , psetupdata->lpPin[m1].bRendered + , psetupdata->lpPin[m1].bOutput + , psetupdata->lpPin[m1].bZero + , psetupdata->lpPin[m1].bMany + , *(psetupdata->lpPin[m1].clsConnectsToFilter) + , psetupdata->lpPin[m1].strConnectsToPin ); + + if( SUCCEEDED(hr) ) + { + // and each pin's media types + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types"))); + for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ ) + { + hr = pIFM->RegisterPinType( *(psetupdata->clsID) + , psetupdata->lpPin[m1].strName + , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType) + , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) ); + if( FAILED(hr) ) break; + } + if( FAILED(hr) ) break; + } + if( FAILED(hr) ) break; + } + } + } + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + +// Remove warnings about unreferenced inline functions +#pragma warning(disable:4514) + diff --git a/src/thirdparty/BaseClasses/amfilter.h b/src/thirdparty/BaseClasses/amfilter.h index 82e0268f4c6..1f725437489 100644 --- a/src/thirdparty/BaseClasses/amfilter.h +++ b/src/thirdparty/BaseClasses/amfilter.h @@ -1,1587 +1,1587 @@ -//------------------------------------------------------------------------------ -// File: AMFilter.h -// -// Desc: DirectShow base classes - efines class hierarchy for streams -// architecture. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __FILTER__ -#define __FILTER__ - -/* The following classes are declared in this header: */ - -class CBaseMediaFilter; // IMediaFilter support -class CBaseFilter; // IBaseFilter,IMediaFilter support -class CBasePin; // Abstract base class for IPin interface -class CEnumPins; // Enumerate input and output pins -class CEnumMediaTypes; // Enumerate the pin's preferred formats -class CBaseOutputPin; // Adds data provider member functions -class CBaseInputPin; // Implements IMemInputPin interface -class CMediaSample; // Basic transport unit for IMemInputPin -class CBaseAllocator; // General list guff for most allocators -class CMemAllocator; // Implements memory buffer allocation - - -//===================================================================== -//===================================================================== -// -// QueryFilterInfo and QueryPinInfo AddRef the interface pointers -// they return. You can use the macro below to release the interface. -// -//===================================================================== -//===================================================================== - -#define QueryFilterInfoReleaseGraph(fi) if ((fi).pGraph) (fi).pGraph->Release(); - -#define QueryPinInfoReleaseFilter(pi) if ((pi).pFilter) (pi).pFilter->Release(); - -//===================================================================== -//===================================================================== -// Defines CBaseMediaFilter -// -// Abstract base class implementing IMediaFilter. -// -// Typically you will derive your filter from CBaseFilter rather than -// this, unless you are implementing an object such as a plug-in -// distributor that needs to support IMediaFilter but not IBaseFilter. -// -// Note that IMediaFilter is derived from IPersist to allow query of -// class id. -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseMediaFilter : public CUnknown, - public IMediaFilter -{ - -protected: - - FILTER_STATE m_State; // current state: running, paused - IReferenceClock *m_pClock; // this filter's reference clock - // note: all filters in a filter graph use the same clock - - // offset from stream time to reference time - CRefTime m_tStart; - - CLSID m_clsid; // This filters clsid - // used for serialization - CCritSec *m_pLock; // Object we use for locking - -public: - - CBaseMediaFilter( - __in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid); - - virtual ~CBaseMediaFilter(); - - DECLARE_IUNKNOWN - - // override this to say what interfaces we support where - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - - // - // --- IPersist method --- - // - - STDMETHODIMP GetClassID(__out CLSID *pClsID); - - // --- IMediaFilter methods --- - - STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); - - STDMETHODIMP SetSyncSource(__inout_opt IReferenceClock *pClock); - - STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock); - - // default implementation of Stop and Pause just record the - // state. Override to activate or de-activate your filter. - // Note that Run when called from Stopped state will call Pause - // to ensure activation, so if you are a source or transform - // you will probably not need to override Run. - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - - - // the start parameter is the difference to be added to the - // sample's stream time to get the reference time for - // its presentation - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // --- helper methods --- - - // return the current stream time - ie find out what - // stream time should be appearing now - virtual HRESULT StreamTime(CRefTime& rtStream); - - // Is the filter currently active? (running or paused) - BOOL IsActive() { - CAutoLock cObjectLock(m_pLock); - return ((m_State == State_Paused) || (m_State == State_Running)); - }; -}; - -//===================================================================== -//===================================================================== -// Defines CBaseFilter -// -// An abstract class providing basic IBaseFilter support for pin -// enumeration and filter information reading. -// -// We cannot derive from CBaseMediaFilter since methods in IMediaFilter -// are also in IBaseFilter and would be ambiguous. Since much of the code -// assumes that they derive from a class that has m_State and other state -// directly available, we duplicate code from CBaseMediaFilter rather than -// having a member variable. -// -// Derive your filter from this, or from a derived object such as -// CTransformFilter. -//===================================================================== -//===================================================================== - - -class AM_NOVTABLE CBaseFilter : public CUnknown, // Handles an IUnknown - public IBaseFilter, // The Filter Interface - public IAMovieSetup // For un/registration -{ - -friend class CBasePin; - -protected: - FILTER_STATE m_State; // current state: running, paused - IReferenceClock *m_pClock; // this graph's ref clock - CRefTime m_tStart; // offset from stream time to reference time - CLSID m_clsid; // This filters clsid - // used for serialization - CCritSec *m_pLock; // Object we use for locking - - WCHAR *m_pName; // Full filter name - IFilterGraph *m_pGraph; // Graph we belong to - IMediaEventSink *m_pSink; // Called with notify events - LONG m_PinVersion; // Current pin version - -public: - - CBaseFilter( - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // IUnknown of delegating object - __in CCritSec *pLock, // Object who maintains lock - REFCLSID clsid); // The clsid to be used to serialize this filter - - CBaseFilter( - __in_opt LPCTSTR pName, // Object description - __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object - __in CCritSec *pLock, // Object who maintains lock - REFCLSID clsid, // The clsid to be used to serialize this filter - __inout HRESULT *phr); // General OLE return code -#ifdef UNICODE - CBaseFilter( - __in_opt LPCSTR pName, // Object description - __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object - __in CCritSec *pLock, // Object who maintains lock - REFCLSID clsid); // The clsid to be used to serialize this filter - - CBaseFilter( - __in_opt LPCSTR pName, // Object description - __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object - __in CCritSec *pLock, // Object who maintains lock - REFCLSID clsid, // The clsid to be used to serialize this filter - __inout HRESULT *phr); // General OLE return code -#endif - ~CBaseFilter(); - - DECLARE_IUNKNOWN - - // override this to say what interfaces we support where - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); -#ifdef _DEBUG - STDMETHODIMP_(ULONG) NonDelegatingRelease(); -#endif - - // - // --- IPersist method --- - // - - STDMETHODIMP GetClassID(__out CLSID *pClsID); - - // --- IMediaFilter methods --- - - STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); - - STDMETHODIMP SetSyncSource(__in_opt IReferenceClock *pClock); - - STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock); - - - // override Stop and Pause so we can activate the pins. - // Note that Run will call Pause first if activation needed. - // Override these if you want to activate your filter rather than - // your pins. - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - - // the start parameter is the difference to be added to the - // sample's stream time to get the reference time for - // its presentation - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // --- helper methods --- - - // return the current stream time - ie find out what - // stream time should be appearing now - virtual HRESULT StreamTime(CRefTime& rtStream); - - // Is the filter currently active? - BOOL IsActive() { - CAutoLock cObjectLock(m_pLock); - return ((m_State == State_Paused) || (m_State == State_Running)); - }; - - // Is this filter stopped (without locking) - BOOL IsStopped() { - return (m_State == State_Stopped); - }; - - // - // --- IBaseFilter methods --- - // - - // pin enumerator - STDMETHODIMP EnumPins( - __deref_out IEnumPins ** ppEnum); - - - // default behaviour of FindPin assumes pin ids are their names - STDMETHODIMP FindPin( - LPCWSTR Id, - __deref_out IPin ** ppPin - ); - - STDMETHODIMP QueryFilterInfo( - __out FILTER_INFO * pInfo); - - STDMETHODIMP JoinFilterGraph( - __inout_opt IFilterGraph * pGraph, - __in_opt LPCWSTR pName); - - // return a Vendor information string. Optional - may return E_NOTIMPL. - // memory returned should be freed using CoTaskMemFree - // default implementation returns E_NOTIMPL - STDMETHODIMP QueryVendorInfo( - __deref_out LPWSTR* pVendorInfo - ); - - // --- helper methods --- - - // send an event notification to the filter graph if we know about it. - // returns S_OK if delivered, S_FALSE if the filter graph does not sink - // events, or an error otherwise. - HRESULT NotifyEvent( - long EventCode, - LONG_PTR EventParam1, - LONG_PTR EventParam2); - - // return the filter graph we belong to - __out_opt IFilterGraph *GetFilterGraph() { - return m_pGraph; - } - - // Request reconnect - // pPin is the pin to reconnect - // pmt is the type to reconnect with - can be NULL - // Calls ReconnectEx on the filter graph - HRESULT ReconnectPin(IPin *pPin, __in_opt AM_MEDIA_TYPE const *pmt); - - // find out the current pin version (used by enumerators) - virtual LONG GetPinVersion(); - void IncrementPinVersion(); - - // you need to supply these to access the pins from the enumerator - // and for default Stop and Pause/Run activation. - virtual int GetPinCount() PURE; - virtual CBasePin *GetPin(int n) PURE; - - // --- IAMovieSetup methods --- - - STDMETHODIMP Register(); // ask filter to register itself - STDMETHODIMP Unregister(); // and unregister itself - - // --- setup helper methods --- - // (override to return filters setup data) - - virtual __out_opt LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; } - -}; - - -//===================================================================== -//===================================================================== -// Defines CBasePin -// -// Abstract class that supports the basics of IPin -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl -{ - -protected: - - WCHAR * m_pName; // This pin's name - IPin *m_Connected; // Pin we have connected to - PIN_DIRECTION m_dir; // Direction of this pin - CCritSec *m_pLock; // Object we use for locking - bool m_bRunTimeError; // Run time error generated - bool m_bCanReconnectWhenActive; // OK to reconnect when active - bool m_bTryMyTypesFirst; // When connecting enumerate - // this pin's types first - CBaseFilter *m_pFilter; // Filter we were created by - IQualityControl *m_pQSink; // Target for Quality messages - LONG m_TypeVersion; // Holds current type version - CMediaType m_mt; // Media type of connection - - CRefTime m_tStart; // time from NewSegment call - CRefTime m_tStop; // time from NewSegment - double m_dRate; // rate from NewSegment - -#ifdef _DEBUG - LONG m_cRef; // Ref count tracing -#endif - - // displays pin connection information - -#ifdef _DEBUG - void DisplayPinInfo(IPin *pReceivePin); - void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt); -#else - void DisplayPinInfo(IPin *pReceivePin) {}; - void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {}; -#endif - - // used to agree a media type for a pin connection - - // given a specific media type, attempt a connection (includes - // checking that the type is acceptable to this pin) - HRESULT - AttemptConnection( - IPin* pReceivePin, // connect to this pin - const CMediaType* pmt // using this type - ); - - // try all the media types in this enumerator - for each that - // we accept, try to connect using ReceiveConnection. - HRESULT TryMediaTypes( - IPin *pReceivePin, // connect to this pin - __in_opt const CMediaType *pmt, // proposed type from Connect - IEnumMediaTypes *pEnum); // try this enumerator - - // establish a connection with a suitable mediatype. Needs to - // propose a media type if the pmt pointer is null or partially - // specified - use TryMediaTypes on both our and then the other pin's - // enumerator until we find one that works. - HRESULT AgreeMediaType( - IPin *pReceivePin, // connect to this pin - const CMediaType *pmt); // proposed type from Connect - -public: - - CBasePin( - __in_opt LPCTSTR pObjectName, // Object description - __in CBaseFilter *pFilter, // Owning filter who knows about pins - __in CCritSec *pLock, // Object who implements the lock - __inout HRESULT *phr, // General OLE return code - __in_opt LPCWSTR pName, // Pin name for us - PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT -#ifdef UNICODE - CBasePin( - __in_opt LPCSTR pObjectName, // Object description - __in CBaseFilter *pFilter, // Owning filter who knows about pins - __in CCritSec *pLock, // Object who implements the lock - __inout HRESULT *phr, // General OLE return code - __in_opt LPCWSTR pName, // Pin name for us - PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT -#endif - virtual ~CBasePin(); - - DECLARE_IUNKNOWN - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - - // --- IPin methods --- - - // take lead role in establishing a connection. Media type pointer - // may be null, or may point to partially-specified mediatype - // (subtype or format type may be GUID_NULL). - STDMETHODIMP Connect( - IPin * pReceivePin, - __in_opt const AM_MEDIA_TYPE *pmt // optional media type - ); - - // (passive) accept a connection from another pin - STDMETHODIMP ReceiveConnection( - IPin * pConnector, // this is the initiating connecting pin - const AM_MEDIA_TYPE *pmt // this is the media type we will exchange - ); - - STDMETHODIMP Disconnect(); - - STDMETHODIMP ConnectedTo(__deref_out IPin **pPin); - - STDMETHODIMP ConnectionMediaType(__out AM_MEDIA_TYPE *pmt); - - STDMETHODIMP QueryPinInfo( - __out PIN_INFO * pInfo - ); - - STDMETHODIMP QueryDirection( - __out PIN_DIRECTION * pPinDir - ); - - STDMETHODIMP QueryId( - __deref_out LPWSTR * Id - ); - - // does the pin support this media type - STDMETHODIMP QueryAccept( - const AM_MEDIA_TYPE *pmt - ); - - // return an enumerator for this pins preferred media types - STDMETHODIMP EnumMediaTypes( - __deref_out IEnumMediaTypes **ppEnum - ); - - // return an array of IPin* - the pins that this pin internally connects to - // All pins put in the array must be AddReffed (but no others) - // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE - // Default: return E_NOTIMPL - // The filter graph will interpret NOT_IMPL as any input pin connects to - // all visible output pins and vice versa. - // apPin can be NULL if nPin==0 (not otherwise). - STDMETHODIMP QueryInternalConnections( - __out_ecount_part(*nPin,*nPin) IPin* *apPin, // array of IPin* - __inout ULONG *nPin // on input, the number of slots - // on output the number of pins - ) { return E_NOTIMPL; } - - // Called when no more data will be sent - STDMETHODIMP EndOfStream(void); - - // Begin/EndFlush still PURE - - // NewSegment notifies of the start/stop/rate applying to the data - // about to be received. Default implementation records data and - // returns S_OK. - // Override this to pass downstream. - STDMETHODIMP NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - //================================================================================ - // IQualityControl methods - //================================================================================ - - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - STDMETHODIMP SetSink(IQualityControl * piqc); - - // --- helper methods --- - - // Returns true if the pin is connected. false otherwise. - BOOL IsConnected(void) {return (m_Connected != NULL); }; - // Return the pin this is connected to (if any) - IPin * GetConnected() { return m_Connected; }; - - // Check if our filter is currently stopped - BOOL IsStopped() { - return (m_pFilter->m_State == State_Stopped); - }; - - // find out the current type version (used by enumerators) - virtual LONG GetMediaTypeVersion(); - void IncrementTypeVersion(); - - // switch the pin to active (paused or running) mode - // not an error to call this if already active - virtual HRESULT Active(void); - - // switch the pin to inactive state - may already be inactive - virtual HRESULT Inactive(void); - - // Notify of Run() from filter - virtual HRESULT Run(REFERENCE_TIME tStart); - - // check if the pin can support this specific proposed type and format - virtual HRESULT CheckMediaType(const CMediaType *) PURE; - - // set the connection to use this format (previously agreed) - virtual HRESULT SetMediaType(const CMediaType *); - - // check that the connection is ok before verifying it - // can be overridden eg to check what interfaces will be supported. - virtual HRESULT CheckConnect(IPin *); - - // Set and release resources required for a connection - virtual HRESULT BreakConnect(); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // returns the preferred formats for a pin - virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); - - // access to NewSegment values - REFERENCE_TIME CurrentStopTime() { - return m_tStop; - } - REFERENCE_TIME CurrentStartTime() { - return m_tStart; - } - double CurrentRate() { - return m_dRate; - } - - // Access name - LPWSTR Name() { return m_pName; }; - - // Can reconnectwhen active? - void SetReconnectWhenActive(bool bCanReconnect) - { - m_bCanReconnectWhenActive = bCanReconnect; - } - - bool CanReconnectWhenActive() - { - return m_bCanReconnectWhenActive; - } - -protected: - STDMETHODIMP DisconnectInternal(); -}; - - -//===================================================================== -//===================================================================== -// Defines CEnumPins -// -// Pin enumerator class that works by calling CBaseFilter. This interface -// is provided by CBaseFilter::EnumPins and calls GetPinCount() and -// GetPin() to enumerate existing pins. Needs to be a separate object so -// that it can be cloned (creating an existing object at the same -// position in the enumeration) -// -//===================================================================== -//===================================================================== - -class CEnumPins : public IEnumPins // The interface we support -{ - int m_Position; // Current ordinal position - int m_PinCount; // Number of pins available - CBaseFilter *m_pFilter; // The filter who owns us - LONG m_Version; // Pin version information - LONG m_cRef; - - typedef CGenericList CPinList; - - CPinList m_PinCache; // These pointers have not been AddRef'ed and - // so they should not be dereferenced. They are - // merely kept to ID which pins have been enumerated. - -#ifdef _DEBUG - DWORD m_dwCookie; -#endif - - /* If while we are retrieving a pin for example from the filter an error - occurs we assume that our internal state is stale with respect to the - filter (someone may have deleted all the pins). We can check before - starting whether or not the operation is likely to fail by asking the - filter what it's current version number is. If the filter has not - overriden the GetPinVersion method then this will always match */ - - BOOL AreWeOutOfSync() { - return (m_pFilter->GetPinVersion() == m_Version ? FALSE : TRUE); - }; - - /* This method performs the same operations as Reset, except is does not clear - the cache of pins already enumerated. */ - - STDMETHODIMP Refresh(); - -public: - - CEnumPins( - __in CBaseFilter *pFilter, - __in_opt CEnumPins *pEnumPins); - - virtual ~CEnumPins(); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // IEnumPins - STDMETHODIMP Next( - ULONG cPins, // place this many pins... - __out_ecount(cPins) IPin ** ppPins, // ...in this array of IPin* - __out_opt ULONG * pcFetched // actual count passed returned here - ); - - STDMETHODIMP Skip(ULONG cPins); - STDMETHODIMP Reset(); - STDMETHODIMP Clone(__deref_out IEnumPins **ppEnum); - - -}; - - -//===================================================================== -//===================================================================== -// Defines CEnumMediaTypes -// -// Enumerates the preferred formats for input and output pins -//===================================================================== -//===================================================================== - -class CEnumMediaTypes : public IEnumMediaTypes // The interface we support -{ - int m_Position; // Current ordinal position - CBasePin *m_pPin; // The pin who owns us - LONG m_Version; // Media type version value - LONG m_cRef; -#ifdef _DEBUG - DWORD m_dwCookie; -#endif - - /* The media types a filter supports can be quite dynamic so we add to - the general IEnumXXXX interface the ability to be signaled when they - change via an event handle the connected filter supplies. Until the - Reset method is called after the state changes all further calls to - the enumerator (except Reset) will return E_UNEXPECTED error code */ - - BOOL AreWeOutOfSync() { - return (m_pPin->GetMediaTypeVersion() == m_Version ? FALSE : TRUE); - }; - -public: - - CEnumMediaTypes( - __in CBasePin *pPin, - __in_opt CEnumMediaTypes *pEnumMediaTypes); - - virtual ~CEnumMediaTypes(); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // IEnumMediaTypes - STDMETHODIMP Next( - ULONG cMediaTypes, // place this many pins... - __out_ecount(cMediaTypes) AM_MEDIA_TYPE ** ppMediaTypes, // ...in this array - __out_opt ULONG * pcFetched // actual count passed - ); - - STDMETHODIMP Skip(ULONG cMediaTypes); - STDMETHODIMP Reset(); - STDMETHODIMP Clone(__deref_out IEnumMediaTypes **ppEnum); -}; - - - - -//===================================================================== -//===================================================================== -// Defines CBaseOutputPin -// -// class derived from CBasePin that can pass buffers to a connected pin -// that supports IMemInputPin. Supports IPin. -// -// Derive your output pin from this. -// -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseOutputPin : public CBasePin -{ - -protected: - - IMemAllocator *m_pAllocator; - IMemInputPin *m_pInputPin; // interface on the downstreaminput pin - // set up in CheckConnect when we connect. - -public: - - CBaseOutputPin( - __in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CBaseOutputPin( - __in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#endif - // override CompleteConnect() so we can negotiate an allocator - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // negotiate the allocator and its buffer size/count and other properties - // Calls DecideBufferSize to set properties - virtual HRESULT DecideAllocator(IMemInputPin * pPin, __deref_out IMemAllocator ** pAlloc); - - // override this to set the buffer size and count. Return an error - // if the size/count is not to your liking. - // The allocator properties passed in are those requested by the - // input pin - use eg the alignment and prefix members if you have - // no preference on these. - virtual HRESULT DecideBufferSize( - IMemAllocator * pAlloc, - __inout ALLOCATOR_PROPERTIES * ppropInputRequest - ) PURE; - - // returns an empty sample buffer from the allocator - virtual HRESULT GetDeliveryBuffer(__deref_out IMediaSample ** ppSample, - __in_opt REFERENCE_TIME * pStartTime, - __in_opt REFERENCE_TIME * pEndTime, - DWORD dwFlags); - - // deliver a filled-in sample to the connected input pin - // note - you need to release it after calling this. The receiving - // pin will addref the sample if it needs to hold it beyond the - // call. - virtual HRESULT Deliver(IMediaSample *); - - // override this to control the connection - virtual HRESULT InitAllocator(__deref_out IMemAllocator **ppAlloc); - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - - // override to call Commit and Decommit - HRESULT Active(void); - HRESULT Inactive(void); - - // we have a default handling of EndOfStream which is to return - // an error, since this should be called on input pins only - STDMETHODIMP EndOfStream(void); - - // called from elsewhere in our filter to pass EOS downstream to - // our connected input pin - virtual HRESULT DeliverEndOfStream(void); - - // same for Begin/EndFlush - we handle Begin/EndFlush since it - // is an error on an output pin, and we have Deliver methods to - // call the methods on the connected pin - STDMETHODIMP BeginFlush(void); - STDMETHODIMP EndFlush(void); - virtual HRESULT DeliverBeginFlush(void); - virtual HRESULT DeliverEndFlush(void); - - // deliver NewSegment to connected pin - you will need to - // override this if you queue any data in your output pin. - virtual HRESULT DeliverNewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - //================================================================================ - // IQualityControl methods - //================================================================================ - - // All inherited from CBasePin and not overridden here. - // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - // STDMETHODIMP SetSink(IQualityControl * piqc); -}; - - -//===================================================================== -//===================================================================== -// Defines CBaseInputPin -// -// derive your standard input pin from this. -// you need to supply GetMediaType and CheckConnect etc (see CBasePin), -// and you need to supply Receive to do something more useful. -// -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseInputPin : public CBasePin, - public IMemInputPin -{ - -protected: - - IMemAllocator *m_pAllocator; // Default memory allocator - - // allocator is read-only, so received samples - // cannot be modified (probably only relevant to in-place - // transforms - BYTE m_bReadOnly; - - // in flushing state (between BeginFlush and EndFlush) - // if TRUE, all Receives are returned with S_FALSE - BYTE m_bFlushing; - - // Sample properties - initalized in Receive - AM_SAMPLE2_PROPERTIES m_SampleProps; - -public: - - CBaseInputPin( - __in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CBaseInputPin( - __in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#endif - virtual ~CBaseInputPin(); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - // return the allocator interface that this input pin - // would like the output pin to use - STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator); - - // tell the input pin which allocator the output pin is actually - // going to use. - STDMETHODIMP NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly); - - // do something with this media sample - STDMETHODIMP Receive(IMediaSample *pSample); - - // do something with these media samples - STDMETHODIMP ReceiveMultiple ( - __in_ecount(nSamples) IMediaSample **pSamples, - long nSamples, - __out long *nSamplesProcessed); - - // See if Receive() blocks - STDMETHODIMP ReceiveCanBlock(); - - // Default handling for BeginFlush - call at the beginning - // of your implementation (makes sure that all Receive calls - // fail). After calling this, you need to free any queued data - // and then call downstream. - STDMETHODIMP BeginFlush(void); - - // default handling for EndFlush - call at end of your implementation - // - before calling this, ensure that there is no queued data and no thread - // pushing any more without a further receive, then call downstream, - // then call this method to clear the m_bFlushing flag and re-enable - // receives - STDMETHODIMP EndFlush(void); - - // this method is optional (can return E_NOTIMPL). - // default implementation returns E_NOTIMPL. Override if you have - // specific alignment or prefix needs, but could use an upstream - // allocator - STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps); - - // Release the pin's allocator. - HRESULT BreakConnect(); - - // helper method to check the read-only flag - BOOL IsReadOnly() { - return m_bReadOnly; - }; - - // helper method to see if we are flushing - BOOL IsFlushing() { - return m_bFlushing; - }; - - // Override this for checking whether it's OK to process samples - // Also call this from EndOfStream. - virtual HRESULT CheckStreaming(); - - // Pass a Quality notification on to the appropriate sink - HRESULT PassNotify(Quality& q); - - - //================================================================================ - // IQualityControl methods (from CBasePin) - //================================================================================ - - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - // no need to override: - // STDMETHODIMP SetSink(IQualityControl * piqc); - - - // switch the pin to inactive state - may already be inactive - virtual HRESULT Inactive(void); - - // Return sample properties pointer - AM_SAMPLE2_PROPERTIES * SampleProps() { - ASSERT(m_SampleProps.cbData != 0); - return &m_SampleProps; - } - -}; - -/////////////////////////////////////////////////////////////////////////// -// CDynamicOutputPin -// - -class CDynamicOutputPin : public CBaseOutputPin, - public IPinFlowControl -{ -public: -#ifdef UNICODE - CDynamicOutputPin( - __in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#endif - - CDynamicOutputPin( - __in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); - - ~CDynamicOutputPin(); - - // IUnknown Methods - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - // IPin Methods - STDMETHODIMP Disconnect(void); - - // IPinFlowControl Methods - STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent); - - // Set graph config info - void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent); - - #ifdef _DEBUG - virtual HRESULT Deliver(IMediaSample *pSample); - virtual HRESULT DeliverEndOfStream(void); - virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - #endif // DEBUG - - HRESULT DeliverBeginFlush(void); - HRESULT DeliverEndFlush(void); - - HRESULT Inactive(void); - HRESULT Active(void); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - virtual HRESULT StartUsingOutputPin(void); - virtual void StopUsingOutputPin(void); - virtual bool StreamingThreadUsingOutputPin(void); - - HRESULT ChangeOutputFormat - ( - const AM_MEDIA_TYPE *pmt, - REFERENCE_TIME tSegmentStart, - REFERENCE_TIME tSegmentStop, - double dSegmentRate - ); - HRESULT ChangeMediaType(const CMediaType *pmt); - HRESULT DynamicReconnect(const CMediaType *pmt); - -protected: - HRESULT SynchronousBlockOutputPin(void); - HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent); - HRESULT UnblockOutputPin(void); - - void BlockOutputPin(void); - void ResetBlockState(void); - - static HRESULT WaitEvent(HANDLE hEvent); - - enum BLOCK_STATE - { - NOT_BLOCKED, - PENDING, - BLOCKED - }; - - // This lock should be held when the following class members are - // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState, - // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers. - CCritSec m_BlockStateLock; - - // This event should be signaled when the output pin is - // not blocked. This is a manual reset event. For more - // information on events, see the documentation for - // CreateEvent() in the Windows SDK. - HANDLE m_hUnblockOutputPinEvent; - - // This event will be signaled when block operation succeedes or - // when the user cancels the block operation. The block operation - // can be canceled by calling IPinFlowControl2::Block( 0, NULL ) - // while the block operation is pending. - HANDLE m_hNotifyCallerPinBlockedEvent; - - // The state of the current block operation. - BLOCK_STATE m_BlockState; - - // The ID of the thread which last called IPinFlowControl::Block(). - // For more information on thread IDs, see the documentation for - // GetCurrentThreadID() in the Windows SDK. - DWORD m_dwBlockCallerThreadID; - - // The number of times StartUsingOutputPin() has been sucessfully - // called and a corresponding call to StopUsingOutputPin() has not - // been made. When this variable is greater than 0, the streaming - // thread is calling IPin::NewSegment(), IPin::EndOfStream(), - // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The - // streaming thread could also be calling: DynamicReconnect(), - // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot - // be blocked while the output pin is being used. - DWORD m_dwNumOutstandingOutputPinUsers; - - // This event should be set when the IMediaFilter::Stop() is called. - // This is a manual reset event. It is also set when the output pin - // delivers a flush to the connected input pin. - HANDLE m_hStopEvent; - IGraphConfig* m_pGraphConfig; - - // TRUE if the output pin's allocator's samples are read only. - // Otherwise FALSE. For more information, see the documentation - // for IMemInputPin::NotifyAllocator(). - BOOL m_bPinUsesReadOnlyAllocator; - -private: - HRESULT Initialize(void); - HRESULT ChangeMediaTypeHelper(const CMediaType *pmt); - - #ifdef _DEBUG - void AssertValid(void); - #endif // DEBUG -}; - -class CAutoUsingOutputPin -{ -public: - CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ); - ~CAutoUsingOutputPin(); - -private: - CDynamicOutputPin* m_pOutputPin; -}; - -inline CAutoUsingOutputPin::CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ) : - m_pOutputPin(NULL) -{ - // The caller should always pass in valid pointers. - ASSERT( NULL != pOutputPin ); - ASSERT( NULL != phr ); - - // Make sure the user initialized phr. - ASSERT( S_OK == *phr ); - - HRESULT hr = pOutputPin->StartUsingOutputPin(); - if( FAILED( hr ) ) - { - *phr = hr; - return; - } - - m_pOutputPin = pOutputPin; -} - -inline CAutoUsingOutputPin::~CAutoUsingOutputPin() -{ - if( NULL != m_pOutputPin ) - { - m_pOutputPin->StopUsingOutputPin(); - } -} - -#ifdef _DEBUG - -inline HRESULT CDynamicOutputPin::Deliver(IMediaSample *pSample) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - return CBaseOutputPin::Deliver(pSample); -} - -inline HRESULT CDynamicOutputPin::DeliverEndOfStream(void) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT( StreamingThreadUsingOutputPin() ); - - return CBaseOutputPin::DeliverEndOfStream(); -} - -inline HRESULT CDynamicOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - return CBaseOutputPin::DeliverNewSegment(tStart, tStop, dRate); -} - -#endif // DEBUG - -//===================================================================== -//===================================================================== -// Memory allocators -// -// the shared memory transport between pins requires the input pin -// to provide a memory allocator that can provide sample objects. A -// sample object supports the IMediaSample interface. -// -// CBaseAllocator handles the management of free and busy samples. It -// allocates CMediaSample objects. CBaseAllocator is an abstract class: -// in particular it has no method of initializing the list of free -// samples. CMemAllocator is derived from CBaseAllocator and initializes -// the list of samples using memory from the standard IMalloc interface. -// -// If you want your buffers to live in some special area of memory, -// derive your allocator object from CBaseAllocator. If you derive your -// IMemInputPin interface object from CBaseMemInputPin, you will get -// CMemAllocator-based allocation etc for free and will just need to -// supply the Receive handling, and media type / format negotiation. -//===================================================================== -//===================================================================== - - -//===================================================================== -//===================================================================== -// Defines CMediaSample -// -// an object of this class supports IMediaSample and represents a buffer -// for media data with some associated properties. Releasing it returns -// it to a freelist managed by a CBaseAllocator derived object. -//===================================================================== -//===================================================================== - -class CMediaSample : public IMediaSample2 // The interface we support -{ - -protected: - - friend class CBaseAllocator; - - /* Values for dwFlags - these are used for backward compatiblity - only now - use AM_SAMPLE_xxx - */ - enum { Sample_SyncPoint = 0x01, /* Is this a sync point */ - Sample_Preroll = 0x02, /* Is this a preroll sample */ - Sample_Discontinuity = 0x04, /* Set if start of new segment */ - Sample_TypeChanged = 0x08, /* Has the type changed */ - Sample_TimeValid = 0x10, /* Set if time is valid */ - Sample_MediaTimeValid = 0x20, /* Is the media time valid */ - Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */ - Sample_StopValid = 0x100, /* Stop time valid */ - Sample_ValidFlags = 0x1FF - }; - - /* Properties, the media sample class can be a container for a format - change in which case we take a copy of a type through the SetMediaType - interface function and then return it when GetMediaType is called. As - we do no internal processing on it we leave it as a pointer */ - - DWORD m_dwFlags; /* Flags for this sample */ - /* Type specific flags are packed - into the top word - */ - DWORD m_dwTypeSpecificFlags; /* Media type specific flags */ - __field_ecount_opt(m_cbBuffer) LPBYTE m_pBuffer; /* Pointer to the complete buffer */ - LONG m_lActual; /* Length of data in this sample */ - LONG m_cbBuffer; /* Size of the buffer */ - CBaseAllocator *m_pAllocator; /* The allocator who owns us */ - CMediaSample *m_pNext; /* Chaining in free list */ - REFERENCE_TIME m_Start; /* Start sample time */ - REFERENCE_TIME m_End; /* End sample time */ - LONGLONG m_MediaStart; /* Real media start position */ - LONG m_MediaEnd; /* A difference to get the end */ - AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */ - DWORD m_dwStreamId; /* Stream id */ -public: - LONG m_cRef; /* Reference count */ - - -public: - - CMediaSample( - __in_opt LPCTSTR pName, - __in_opt CBaseAllocator *pAllocator, - __inout_opt HRESULT *phr, - __in_bcount_opt(length) LPBYTE pBuffer = NULL, - LONG length = 0); -#ifdef UNICODE - CMediaSample( - __in_opt LPCSTR pName, - __in_opt CBaseAllocator *pAllocator, - __inout_opt HRESULT *phr, - __in_bcount_opt(length) LPBYTE pBuffer = NULL, - LONG length = 0); -#endif - - virtual ~CMediaSample(); - - /* Note the media sample does not delegate to its owner */ - - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // set the buffer pointer and length. Used by allocators that - // want variable sized pointers or pointers into already-read data. - // This is only available through a CMediaSample* not an IMediaSample* - // and so cannot be changed by clients. - HRESULT SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes); - - // Get me a read/write pointer to this buffer's memory. - STDMETHODIMP GetPointer(__deref_out BYTE ** ppBuffer); - - STDMETHODIMP_(LONG) GetSize(void); - - // get the stream time at which this sample should start and finish. - STDMETHODIMP GetTime( - __out REFERENCE_TIME * pTimeStart, // put time here - __out REFERENCE_TIME * pTimeEnd - ); - - // Set the stream time at which this sample should start and finish. - STDMETHODIMP SetTime( - __in_opt REFERENCE_TIME * pTimeStart, // put time here - __in_opt REFERENCE_TIME * pTimeEnd - ); - STDMETHODIMP IsSyncPoint(void); - STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint); - STDMETHODIMP IsPreroll(void); - STDMETHODIMP SetPreroll(BOOL bIsPreroll); - - STDMETHODIMP_(LONG) GetActualDataLength(void); - STDMETHODIMP SetActualDataLength(LONG lActual); - - // these allow for limited format changes in band - - STDMETHODIMP GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType); - STDMETHODIMP SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType); - - // returns S_OK if there is a discontinuity in the data (this same is - // not a continuation of the previous stream of data - // - there has been a seek). - STDMETHODIMP IsDiscontinuity(void); - // set the discontinuity property - TRUE if this sample is not a - // continuation, but a new sample after a seek. - STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity); - - // get the media times for this sample - STDMETHODIMP GetMediaTime( - __out LONGLONG * pTimeStart, - __out LONGLONG * pTimeEnd - ); - - // Set the media times for this sample - STDMETHODIMP SetMediaTime( - __in_opt LONGLONG * pTimeStart, - __in_opt LONGLONG * pTimeEnd - ); - - // Set and get properties (IMediaSample2) - STDMETHODIMP GetProperties( - DWORD cbProperties, - __out_bcount(cbProperties) BYTE * pbProperties - ); - - STDMETHODIMP SetProperties( - DWORD cbProperties, - __in_bcount(cbProperties) const BYTE * pbProperties - ); -}; - - -//===================================================================== -//===================================================================== -// Defines CBaseAllocator -// -// Abstract base class that manages a list of media samples -// -// This class provides support for getting buffers from the free list, -// including handling of commit and (asynchronous) decommit. -// -// Derive from this class and override the Alloc and Free functions to -// allocate your CMediaSample (or derived) objects and add them to the -// free list, preparing them as necessary. -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseAllocator : public CUnknown,// A non delegating IUnknown - public IMemAllocatorCallbackTemp, // The interface we support - public CCritSec // Provides object locking -{ - class CSampleList; - friend class CSampleList; - - /* Trick to get at protected member in CMediaSample */ - static CMediaSample * &NextSample(__in CMediaSample *pSample) - { - return pSample->m_pNext; - }; - - /* Mini list class for the free list */ - class CSampleList - { - public: - CSampleList() : m_List(NULL), m_nOnList(0) {}; -#ifdef _DEBUG - ~CSampleList() - { - ASSERT(m_nOnList == 0); - }; -#endif - CMediaSample *Head() const { return m_List; }; - CMediaSample *Next(__in CMediaSample *pSample) const { return CBaseAllocator::NextSample(pSample); }; - int GetCount() const { return m_nOnList; }; - void Add(__inout CMediaSample *pSample) - { - ASSERT(pSample != NULL); - CBaseAllocator::NextSample(pSample) = m_List; - m_List = pSample; - m_nOnList++; - }; - CMediaSample *RemoveHead() - { - CMediaSample *pSample = m_List; - if (pSample != NULL) { - m_List = CBaseAllocator::NextSample(m_List); - m_nOnList--; - } - return pSample; - }; - void Remove(__inout CMediaSample *pSample); - - public: - CMediaSample *m_List; - int m_nOnList; - }; -protected: - - CSampleList m_lFree; // Free list - - /* Note to overriders of CBaseAllocator. - - We use a lazy signalling mechanism for waiting for samples. - This means we don't call the OS if no waits occur. - - In order to implement this: - - 1. When a new sample is added to m_lFree call NotifySample() which - calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and - sets m_lWaiting to 0. - This must all be done holding the allocator's critical section. - - 2. When waiting for a sample call SetWaiting() which increments - m_lWaiting BEFORE leaving the allocator's critical section. - - 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE) - having left the allocator's critical section. The effect of - this is to remove 1 from the semaphore's count. You MUST call - this once having incremented m_lWaiting. - - The following are then true when the critical section is not held : - (let nWaiting = number about to wait or waiting) - - (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0) - (2) m_lWaiting + Semaphore count == nWaiting - - We would deadlock if - nWaiting != 0 && - m_lFree.GetCount() != 0 && - Semaphore count == 0 - - But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so - from (2) Semaphore count == nWaiting (which is non-0) so the - deadlock can't happen. - */ - - HANDLE m_hSem; // For signalling - long m_lWaiting; // Waiting for a free element - long m_lCount; // how many buffers we have agreed to provide - long m_lAllocated; // how many buffers are currently allocated - long m_lSize; // agreed size of each buffer - long m_lAlignment; // agreed alignment - long m_lPrefix; // agreed prefix (preceeds GetPointer() value) - BOOL m_bChanged; // Have the buffer requirements changed - - // if true, we are decommitted and can't allocate memory - BOOL m_bCommitted; - // if true, the decommit has happened, but we haven't called Free yet - // as there are still outstanding buffers - BOOL m_bDecommitInProgress; - - // Notification interface - IMemAllocatorNotifyCallbackTemp *m_pNotify; - - BOOL m_fEnableReleaseCallback; - - // called to decommit the memory when the last buffer is freed - // pure virtual - need to override this - virtual void Free(void) PURE; - - // override to allocate the memory when commit called - virtual HRESULT Alloc(void); - -public: - - CBaseAllocator( - __in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *, - BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); -#ifdef UNICODE - CBaseAllocator( - __in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *, - BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); -#endif - virtual ~CBaseAllocator(); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - STDMETHODIMP SetProperties( - __in ALLOCATOR_PROPERTIES* pRequest, - __out ALLOCATOR_PROPERTIES* pActual); - - // return the properties actually being used on this allocator - STDMETHODIMP GetProperties( - __out ALLOCATOR_PROPERTIES* pProps); - - // override Commit to allocate memory. We handle the GetBuffer - //state changes - STDMETHODIMP Commit(); - - // override this to handle the memory freeing. We handle any outstanding - // GetBuffer calls - STDMETHODIMP Decommit(); - - // get container for a sample. Blocking, synchronous call to get the - // next free buffer (as represented by an IMediaSample interface). - // on return, the time etc properties will be invalid, but the buffer - // pointer and size will be correct. The two time parameters are - // optional and either may be NULL, they may alternatively be set to - // the start and end times the sample will have attached to it - // bPrevFramesSkipped is not used (used only by the video renderer's - // allocator where it affects quality management in direct draw). - - STDMETHODIMP GetBuffer(__deref_out IMediaSample **ppBuffer, - __in_opt REFERENCE_TIME * pStartTime, - __in_opt REFERENCE_TIME * pEndTime, - DWORD dwFlags); - - // final release of a CMediaSample will call this - STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer); - // obsolete:: virtual void PutOnFreeList(CMediaSample * pSample); - - STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); - - STDMETHODIMP GetFreeCount(__out LONG *plBuffersFree); - - // Notify that a sample is available - void NotifySample(); - - // Notify that we're waiting for a sample - void SetWaiting() { m_lWaiting++; }; -}; - - -//===================================================================== -//===================================================================== -// Defines CMemAllocator -// -// this is an allocator based on CBaseAllocator that allocates sample -// buffers in main memory (from 'new'). You must call SetProperties -// before calling Commit. -// -// we don't free the memory when going into Decommit state. The simplest -// way to implement this without complicating CBaseAllocator is to -// have a Free() function, called to go into decommit state, that does -// nothing and a ReallyFree function called from our destructor that -// actually frees the memory. -//===================================================================== -//===================================================================== - -// Make me one from quartz.dll -STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator); - -class CMemAllocator : public CBaseAllocator -{ - -protected: - - LPBYTE m_pBuffer; // combined memory for all buffers - - // override to free the memory when decommit completes - // - we actually do nothing, and save the memory until deletion. - void Free(void); - - // called from the destructor (and from Alloc if changing size/count) to - // actually free up the memory - void ReallyFree(void); - - // overriden to allocate the memory when commit called - HRESULT Alloc(void); - -public: - /* This goes in the factory template table to create new instances */ - static CUnknown *CreateInstance(__inout_opt LPUNKNOWN, __inout HRESULT *); - - STDMETHODIMP SetProperties( - __in ALLOCATOR_PROPERTIES* pRequest, - __out ALLOCATOR_PROPERTIES* pActual); - - CMemAllocator(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *); -#ifdef UNICODE - CMemAllocator(__in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *); -#endif - ~CMemAllocator(); -}; - -// helper used by IAMovieSetup implementation -STDAPI -AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper * pIFM - , BOOL bRegister ); - - -/////////////////////////////////////////////////////////////////////////// -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -/////////////////////////////////////////////////////////////////////////// - -#endif /* __FILTER__ */ - - - +//------------------------------------------------------------------------------ +// File: AMFilter.h +// +// Desc: DirectShow base classes - efines class hierarchy for streams +// architecture. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __FILTER__ +#define __FILTER__ + +/* The following classes are declared in this header: */ + +class CBaseMediaFilter; // IMediaFilter support +class CBaseFilter; // IBaseFilter,IMediaFilter support +class CBasePin; // Abstract base class for IPin interface +class CEnumPins; // Enumerate input and output pins +class CEnumMediaTypes; // Enumerate the pin's preferred formats +class CBaseOutputPin; // Adds data provider member functions +class CBaseInputPin; // Implements IMemInputPin interface +class CMediaSample; // Basic transport unit for IMemInputPin +class CBaseAllocator; // General list guff for most allocators +class CMemAllocator; // Implements memory buffer allocation + + +//===================================================================== +//===================================================================== +// +// QueryFilterInfo and QueryPinInfo AddRef the interface pointers +// they return. You can use the macro below to release the interface. +// +//===================================================================== +//===================================================================== + +#define QueryFilterInfoReleaseGraph(fi) if ((fi).pGraph) (fi).pGraph->Release(); + +#define QueryPinInfoReleaseFilter(pi) if ((pi).pFilter) (pi).pFilter->Release(); + +//===================================================================== +//===================================================================== +// Defines CBaseMediaFilter +// +// Abstract base class implementing IMediaFilter. +// +// Typically you will derive your filter from CBaseFilter rather than +// this, unless you are implementing an object such as a plug-in +// distributor that needs to support IMediaFilter but not IBaseFilter. +// +// Note that IMediaFilter is derived from IPersist to allow query of +// class id. +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseMediaFilter : public CUnknown, + public IMediaFilter +{ + +protected: + + FILTER_STATE m_State; // current state: running, paused + IReferenceClock *m_pClock; // this filter's reference clock + // note: all filters in a filter graph use the same clock + + // offset from stream time to reference time + CRefTime m_tStart; + + CLSID m_clsid; // This filters clsid + // used for serialization + CCritSec *m_pLock; // Object we use for locking + +public: + + CBaseMediaFilter( + __in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid); + + virtual ~CBaseMediaFilter(); + + DECLARE_IUNKNOWN + + // override this to say what interfaces we support where + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + + // + // --- IPersist method --- + // + + STDMETHODIMP GetClassID(__out CLSID *pClsID); + + // --- IMediaFilter methods --- + + STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); + + STDMETHODIMP SetSyncSource(__inout_opt IReferenceClock *pClock); + + STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock); + + // default implementation of Stop and Pause just record the + // state. Override to activate or de-activate your filter. + // Note that Run when called from Stopped state will call Pause + // to ensure activation, so if you are a source or transform + // you will probably not need to override Run. + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + + + // the start parameter is the difference to be added to the + // sample's stream time to get the reference time for + // its presentation + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // --- helper methods --- + + // return the current stream time - ie find out what + // stream time should be appearing now + virtual HRESULT StreamTime(CRefTime& rtStream); + + // Is the filter currently active? (running or paused) + BOOL IsActive() { + CAutoLock cObjectLock(m_pLock); + return ((m_State == State_Paused) || (m_State == State_Running)); + }; +}; + +//===================================================================== +//===================================================================== +// Defines CBaseFilter +// +// An abstract class providing basic IBaseFilter support for pin +// enumeration and filter information reading. +// +// We cannot derive from CBaseMediaFilter since methods in IMediaFilter +// are also in IBaseFilter and would be ambiguous. Since much of the code +// assumes that they derive from a class that has m_State and other state +// directly available, we duplicate code from CBaseMediaFilter rather than +// having a member variable. +// +// Derive your filter from this, or from a derived object such as +// CTransformFilter. +//===================================================================== +//===================================================================== + + +class AM_NOVTABLE CBaseFilter : public CUnknown, // Handles an IUnknown + public IBaseFilter, // The Filter Interface + public IAMovieSetup // For un/registration +{ + +friend class CBasePin; + +protected: + FILTER_STATE m_State; // current state: running, paused + IReferenceClock *m_pClock; // this graph's ref clock + CRefTime m_tStart; // offset from stream time to reference time + CLSID m_clsid; // This filters clsid + // used for serialization + CCritSec *m_pLock; // Object we use for locking + + WCHAR *m_pName; // Full filter name + IFilterGraph *m_pGraph; // Graph we belong to + IMediaEventSink *m_pSink; // Called with notify events + LONG m_PinVersion; // Current pin version + +public: + + CBaseFilter( + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // IUnknown of delegating object + __in CCritSec *pLock, // Object who maintains lock + REFCLSID clsid); // The clsid to be used to serialize this filter + + CBaseFilter( + __in_opt LPCTSTR pName, // Object description + __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object + __in CCritSec *pLock, // Object who maintains lock + REFCLSID clsid, // The clsid to be used to serialize this filter + __inout HRESULT *phr); // General OLE return code +#ifdef UNICODE + CBaseFilter( + __in_opt LPCSTR pName, // Object description + __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object + __in CCritSec *pLock, // Object who maintains lock + REFCLSID clsid); // The clsid to be used to serialize this filter + + CBaseFilter( + __in_opt LPCSTR pName, // Object description + __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object + __in CCritSec *pLock, // Object who maintains lock + REFCLSID clsid, // The clsid to be used to serialize this filter + __inout HRESULT *phr); // General OLE return code +#endif + ~CBaseFilter(); + + DECLARE_IUNKNOWN + + // override this to say what interfaces we support where + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); +#ifdef _DEBUG + STDMETHODIMP_(ULONG) NonDelegatingRelease(); +#endif + + // + // --- IPersist method --- + // + + STDMETHODIMP GetClassID(__out CLSID *pClsID); + + // --- IMediaFilter methods --- + + STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); + + STDMETHODIMP SetSyncSource(__in_opt IReferenceClock *pClock); + + STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock); + + + // override Stop and Pause so we can activate the pins. + // Note that Run will call Pause first if activation needed. + // Override these if you want to activate your filter rather than + // your pins. + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + + // the start parameter is the difference to be added to the + // sample's stream time to get the reference time for + // its presentation + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // --- helper methods --- + + // return the current stream time - ie find out what + // stream time should be appearing now + virtual HRESULT StreamTime(CRefTime& rtStream); + + // Is the filter currently active? + BOOL IsActive() { + CAutoLock cObjectLock(m_pLock); + return ((m_State == State_Paused) || (m_State == State_Running)); + }; + + // Is this filter stopped (without locking) + BOOL IsStopped() { + return (m_State == State_Stopped); + }; + + // + // --- IBaseFilter methods --- + // + + // pin enumerator + STDMETHODIMP EnumPins( + __deref_out IEnumPins ** ppEnum); + + + // default behaviour of FindPin assumes pin ids are their names + STDMETHODIMP FindPin( + LPCWSTR Id, + __deref_out IPin ** ppPin + ); + + STDMETHODIMP QueryFilterInfo( + __out FILTER_INFO * pInfo); + + STDMETHODIMP JoinFilterGraph( + __inout_opt IFilterGraph * pGraph, + __in_opt LPCWSTR pName); + + // return a Vendor information string. Optional - may return E_NOTIMPL. + // memory returned should be freed using CoTaskMemFree + // default implementation returns E_NOTIMPL + STDMETHODIMP QueryVendorInfo( + __deref_out LPWSTR* pVendorInfo + ); + + // --- helper methods --- + + // send an event notification to the filter graph if we know about it. + // returns S_OK if delivered, S_FALSE if the filter graph does not sink + // events, or an error otherwise. + HRESULT NotifyEvent( + long EventCode, + LONG_PTR EventParam1, + LONG_PTR EventParam2); + + // return the filter graph we belong to + __out_opt IFilterGraph *GetFilterGraph() { + return m_pGraph; + } + + // Request reconnect + // pPin is the pin to reconnect + // pmt is the type to reconnect with - can be NULL + // Calls ReconnectEx on the filter graph + HRESULT ReconnectPin(IPin *pPin, __in_opt AM_MEDIA_TYPE const *pmt); + + // find out the current pin version (used by enumerators) + virtual LONG GetPinVersion(); + void IncrementPinVersion(); + + // you need to supply these to access the pins from the enumerator + // and for default Stop and Pause/Run activation. + virtual int GetPinCount() PURE; + virtual CBasePin *GetPin(int n) PURE; + + // --- IAMovieSetup methods --- + + STDMETHODIMP Register(); // ask filter to register itself + STDMETHODIMP Unregister(); // and unregister itself + + // --- setup helper methods --- + // (override to return filters setup data) + + virtual __out_opt LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; } + +}; + + +//===================================================================== +//===================================================================== +// Defines CBasePin +// +// Abstract class that supports the basics of IPin +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl +{ + +protected: + + WCHAR * m_pName; // This pin's name + IPin *m_Connected; // Pin we have connected to + PIN_DIRECTION m_dir; // Direction of this pin + CCritSec *m_pLock; // Object we use for locking + bool m_bRunTimeError; // Run time error generated + bool m_bCanReconnectWhenActive; // OK to reconnect when active + bool m_bTryMyTypesFirst; // When connecting enumerate + // this pin's types first + CBaseFilter *m_pFilter; // Filter we were created by + IQualityControl *m_pQSink; // Target for Quality messages + LONG m_TypeVersion; // Holds current type version + CMediaType m_mt; // Media type of connection + + CRefTime m_tStart; // time from NewSegment call + CRefTime m_tStop; // time from NewSegment + double m_dRate; // rate from NewSegment + +#ifdef _DEBUG + LONG m_cRef; // Ref count tracing +#endif + + // displays pin connection information + +#ifdef _DEBUG + void DisplayPinInfo(IPin *pReceivePin); + void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt); +#else + void DisplayPinInfo(IPin *pReceivePin) {}; + void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {}; +#endif + + // used to agree a media type for a pin connection + + // given a specific media type, attempt a connection (includes + // checking that the type is acceptable to this pin) + HRESULT + AttemptConnection( + IPin* pReceivePin, // connect to this pin + const CMediaType* pmt // using this type + ); + + // try all the media types in this enumerator - for each that + // we accept, try to connect using ReceiveConnection. + HRESULT TryMediaTypes( + IPin *pReceivePin, // connect to this pin + __in_opt const CMediaType *pmt, // proposed type from Connect + IEnumMediaTypes *pEnum); // try this enumerator + + // establish a connection with a suitable mediatype. Needs to + // propose a media type if the pmt pointer is null or partially + // specified - use TryMediaTypes on both our and then the other pin's + // enumerator until we find one that works. + HRESULT AgreeMediaType( + IPin *pReceivePin, // connect to this pin + const CMediaType *pmt); // proposed type from Connect + +public: + + CBasePin( + __in_opt LPCTSTR pObjectName, // Object description + __in CBaseFilter *pFilter, // Owning filter who knows about pins + __in CCritSec *pLock, // Object who implements the lock + __inout HRESULT *phr, // General OLE return code + __in_opt LPCWSTR pName, // Pin name for us + PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT +#ifdef UNICODE + CBasePin( + __in_opt LPCSTR pObjectName, // Object description + __in CBaseFilter *pFilter, // Owning filter who knows about pins + __in CCritSec *pLock, // Object who implements the lock + __inout HRESULT *phr, // General OLE return code + __in_opt LPCWSTR pName, // Pin name for us + PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT +#endif + virtual ~CBasePin(); + + DECLARE_IUNKNOWN + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + + // --- IPin methods --- + + // take lead role in establishing a connection. Media type pointer + // may be null, or may point to partially-specified mediatype + // (subtype or format type may be GUID_NULL). + STDMETHODIMP Connect( + IPin * pReceivePin, + __in_opt const AM_MEDIA_TYPE *pmt // optional media type + ); + + // (passive) accept a connection from another pin + STDMETHODIMP ReceiveConnection( + IPin * pConnector, // this is the initiating connecting pin + const AM_MEDIA_TYPE *pmt // this is the media type we will exchange + ); + + STDMETHODIMP Disconnect(); + + STDMETHODIMP ConnectedTo(__deref_out IPin **pPin); + + STDMETHODIMP ConnectionMediaType(__out AM_MEDIA_TYPE *pmt); + + STDMETHODIMP QueryPinInfo( + __out PIN_INFO * pInfo + ); + + STDMETHODIMP QueryDirection( + __out PIN_DIRECTION * pPinDir + ); + + STDMETHODIMP QueryId( + __deref_out LPWSTR * Id + ); + + // does the pin support this media type + STDMETHODIMP QueryAccept( + const AM_MEDIA_TYPE *pmt + ); + + // return an enumerator for this pins preferred media types + STDMETHODIMP EnumMediaTypes( + __deref_out IEnumMediaTypes **ppEnum + ); + + // return an array of IPin* - the pins that this pin internally connects to + // All pins put in the array must be AddReffed (but no others) + // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE + // Default: return E_NOTIMPL + // The filter graph will interpret NOT_IMPL as any input pin connects to + // all visible output pins and vice versa. + // apPin can be NULL if nPin==0 (not otherwise). + STDMETHODIMP QueryInternalConnections( + __out_ecount_part(*nPin,*nPin) IPin* *apPin, // array of IPin* + __inout ULONG *nPin // on input, the number of slots + // on output the number of pins + ) { return E_NOTIMPL; } + + // Called when no more data will be sent + STDMETHODIMP EndOfStream(void); + + // Begin/EndFlush still PURE + + // NewSegment notifies of the start/stop/rate applying to the data + // about to be received. Default implementation records data and + // returns S_OK. + // Override this to pass downstream. + STDMETHODIMP NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + //================================================================================ + // IQualityControl methods + //================================================================================ + + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + STDMETHODIMP SetSink(IQualityControl * piqc); + + // --- helper methods --- + + // Returns true if the pin is connected. false otherwise. + BOOL IsConnected(void) {return (m_Connected != NULL); }; + // Return the pin this is connected to (if any) + IPin * GetConnected() { return m_Connected; }; + + // Check if our filter is currently stopped + BOOL IsStopped() { + return (m_pFilter->m_State == State_Stopped); + }; + + // find out the current type version (used by enumerators) + virtual LONG GetMediaTypeVersion(); + void IncrementTypeVersion(); + + // switch the pin to active (paused or running) mode + // not an error to call this if already active + virtual HRESULT Active(void); + + // switch the pin to inactive state - may already be inactive + virtual HRESULT Inactive(void); + + // Notify of Run() from filter + virtual HRESULT Run(REFERENCE_TIME tStart); + + // check if the pin can support this specific proposed type and format + virtual HRESULT CheckMediaType(const CMediaType *) PURE; + + // set the connection to use this format (previously agreed) + virtual HRESULT SetMediaType(const CMediaType *); + + // check that the connection is ok before verifying it + // can be overridden eg to check what interfaces will be supported. + virtual HRESULT CheckConnect(IPin *); + + // Set and release resources required for a connection + virtual HRESULT BreakConnect(); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // returns the preferred formats for a pin + virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); + + // access to NewSegment values + REFERENCE_TIME CurrentStopTime() { + return m_tStop; + } + REFERENCE_TIME CurrentStartTime() { + return m_tStart; + } + double CurrentRate() { + return m_dRate; + } + + // Access name + LPWSTR Name() { return m_pName; }; + + // Can reconnectwhen active? + void SetReconnectWhenActive(bool bCanReconnect) + { + m_bCanReconnectWhenActive = bCanReconnect; + } + + bool CanReconnectWhenActive() + { + return m_bCanReconnectWhenActive; + } + +protected: + STDMETHODIMP DisconnectInternal(); +}; + + +//===================================================================== +//===================================================================== +// Defines CEnumPins +// +// Pin enumerator class that works by calling CBaseFilter. This interface +// is provided by CBaseFilter::EnumPins and calls GetPinCount() and +// GetPin() to enumerate existing pins. Needs to be a separate object so +// that it can be cloned (creating an existing object at the same +// position in the enumeration) +// +//===================================================================== +//===================================================================== + +class CEnumPins : public IEnumPins // The interface we support +{ + int m_Position; // Current ordinal position + int m_PinCount; // Number of pins available + CBaseFilter *m_pFilter; // The filter who owns us + LONG m_Version; // Pin version information + LONG m_cRef; + + typedef CGenericList CPinList; + + CPinList m_PinCache; // These pointers have not been AddRef'ed and + // so they should not be dereferenced. They are + // merely kept to ID which pins have been enumerated. + +#ifdef _DEBUG + DWORD m_dwCookie; +#endif + + /* If while we are retrieving a pin for example from the filter an error + occurs we assume that our internal state is stale with respect to the + filter (someone may have deleted all the pins). We can check before + starting whether or not the operation is likely to fail by asking the + filter what it's current version number is. If the filter has not + overriden the GetPinVersion method then this will always match */ + + BOOL AreWeOutOfSync() { + return (m_pFilter->GetPinVersion() == m_Version ? FALSE : TRUE); + }; + + /* This method performs the same operations as Reset, except is does not clear + the cache of pins already enumerated. */ + + STDMETHODIMP Refresh(); + +public: + + CEnumPins( + __in CBaseFilter *pFilter, + __in_opt CEnumPins *pEnumPins); + + virtual ~CEnumPins(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IEnumPins + STDMETHODIMP Next( + ULONG cPins, // place this many pins... + __out_ecount(cPins) IPin ** ppPins, // ...in this array of IPin* + __out_opt ULONG * pcFetched // actual count passed returned here + ); + + STDMETHODIMP Skip(ULONG cPins); + STDMETHODIMP Reset(); + STDMETHODIMP Clone(__deref_out IEnumPins **ppEnum); + + +}; + + +//===================================================================== +//===================================================================== +// Defines CEnumMediaTypes +// +// Enumerates the preferred formats for input and output pins +//===================================================================== +//===================================================================== + +class CEnumMediaTypes : public IEnumMediaTypes // The interface we support +{ + int m_Position; // Current ordinal position + CBasePin *m_pPin; // The pin who owns us + LONG m_Version; // Media type version value + LONG m_cRef; +#ifdef _DEBUG + DWORD m_dwCookie; +#endif + + /* The media types a filter supports can be quite dynamic so we add to + the general IEnumXXXX interface the ability to be signaled when they + change via an event handle the connected filter supplies. Until the + Reset method is called after the state changes all further calls to + the enumerator (except Reset) will return E_UNEXPECTED error code */ + + BOOL AreWeOutOfSync() { + return (m_pPin->GetMediaTypeVersion() == m_Version ? FALSE : TRUE); + }; + +public: + + CEnumMediaTypes( + __in CBasePin *pPin, + __in_opt CEnumMediaTypes *pEnumMediaTypes); + + virtual ~CEnumMediaTypes(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IEnumMediaTypes + STDMETHODIMP Next( + ULONG cMediaTypes, // place this many pins... + __out_ecount(cMediaTypes) AM_MEDIA_TYPE ** ppMediaTypes, // ...in this array + __out_opt ULONG * pcFetched // actual count passed + ); + + STDMETHODIMP Skip(ULONG cMediaTypes); + STDMETHODIMP Reset(); + STDMETHODIMP Clone(__deref_out IEnumMediaTypes **ppEnum); +}; + + + + +//===================================================================== +//===================================================================== +// Defines CBaseOutputPin +// +// class derived from CBasePin that can pass buffers to a connected pin +// that supports IMemInputPin. Supports IPin. +// +// Derive your output pin from this. +// +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseOutputPin : public CBasePin +{ + +protected: + + IMemAllocator *m_pAllocator; + IMemInputPin *m_pInputPin; // interface on the downstreaminput pin + // set up in CheckConnect when we connect. + +public: + + CBaseOutputPin( + __in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CBaseOutputPin( + __in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#endif + // override CompleteConnect() so we can negotiate an allocator + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // negotiate the allocator and its buffer size/count and other properties + // Calls DecideBufferSize to set properties + virtual HRESULT DecideAllocator(IMemInputPin * pPin, __deref_out IMemAllocator ** pAlloc); + + // override this to set the buffer size and count. Return an error + // if the size/count is not to your liking. + // The allocator properties passed in are those requested by the + // input pin - use eg the alignment and prefix members if you have + // no preference on these. + virtual HRESULT DecideBufferSize( + IMemAllocator * pAlloc, + __inout ALLOCATOR_PROPERTIES * ppropInputRequest + ) PURE; + + // returns an empty sample buffer from the allocator + virtual HRESULT GetDeliveryBuffer(__deref_out IMediaSample ** ppSample, + __in_opt REFERENCE_TIME * pStartTime, + __in_opt REFERENCE_TIME * pEndTime, + DWORD dwFlags); + + // deliver a filled-in sample to the connected input pin + // note - you need to release it after calling this. The receiving + // pin will addref the sample if it needs to hold it beyond the + // call. + virtual HRESULT Deliver(IMediaSample *); + + // override this to control the connection + virtual HRESULT InitAllocator(__deref_out IMemAllocator **ppAlloc); + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + + // override to call Commit and Decommit + HRESULT Active(void); + HRESULT Inactive(void); + + // we have a default handling of EndOfStream which is to return + // an error, since this should be called on input pins only + STDMETHODIMP EndOfStream(void); + + // called from elsewhere in our filter to pass EOS downstream to + // our connected input pin + virtual HRESULT DeliverEndOfStream(void); + + // same for Begin/EndFlush - we handle Begin/EndFlush since it + // is an error on an output pin, and we have Deliver methods to + // call the methods on the connected pin + STDMETHODIMP BeginFlush(void); + STDMETHODIMP EndFlush(void); + virtual HRESULT DeliverBeginFlush(void); + virtual HRESULT DeliverEndFlush(void); + + // deliver NewSegment to connected pin - you will need to + // override this if you queue any data in your output pin. + virtual HRESULT DeliverNewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + //================================================================================ + // IQualityControl methods + //================================================================================ + + // All inherited from CBasePin and not overridden here. + // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + // STDMETHODIMP SetSink(IQualityControl * piqc); +}; + + +//===================================================================== +//===================================================================== +// Defines CBaseInputPin +// +// derive your standard input pin from this. +// you need to supply GetMediaType and CheckConnect etc (see CBasePin), +// and you need to supply Receive to do something more useful. +// +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseInputPin : public CBasePin, + public IMemInputPin +{ + +protected: + + IMemAllocator *m_pAllocator; // Default memory allocator + + // allocator is read-only, so received samples + // cannot be modified (probably only relevant to in-place + // transforms + BYTE m_bReadOnly; + + // in flushing state (between BeginFlush and EndFlush) + // if TRUE, all Receives are returned with S_FALSE + BYTE m_bFlushing; + + // Sample properties - initalized in Receive + AM_SAMPLE2_PROPERTIES m_SampleProps; + +public: + + CBaseInputPin( + __in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CBaseInputPin( + __in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#endif + virtual ~CBaseInputPin(); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + // return the allocator interface that this input pin + // would like the output pin to use + STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator); + + // tell the input pin which allocator the output pin is actually + // going to use. + STDMETHODIMP NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly); + + // do something with this media sample + STDMETHODIMP Receive(IMediaSample *pSample); + + // do something with these media samples + STDMETHODIMP ReceiveMultiple ( + __in_ecount(nSamples) IMediaSample **pSamples, + long nSamples, + __out long *nSamplesProcessed); + + // See if Receive() blocks + STDMETHODIMP ReceiveCanBlock(); + + // Default handling for BeginFlush - call at the beginning + // of your implementation (makes sure that all Receive calls + // fail). After calling this, you need to free any queued data + // and then call downstream. + STDMETHODIMP BeginFlush(void); + + // default handling for EndFlush - call at end of your implementation + // - before calling this, ensure that there is no queued data and no thread + // pushing any more without a further receive, then call downstream, + // then call this method to clear the m_bFlushing flag and re-enable + // receives + STDMETHODIMP EndFlush(void); + + // this method is optional (can return E_NOTIMPL). + // default implementation returns E_NOTIMPL. Override if you have + // specific alignment or prefix needs, but could use an upstream + // allocator + STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps); + + // Release the pin's allocator. + HRESULT BreakConnect(); + + // helper method to check the read-only flag + BOOL IsReadOnly() { + return m_bReadOnly; + }; + + // helper method to see if we are flushing + BOOL IsFlushing() { + return m_bFlushing; + }; + + // Override this for checking whether it's OK to process samples + // Also call this from EndOfStream. + virtual HRESULT CheckStreaming(); + + // Pass a Quality notification on to the appropriate sink + HRESULT PassNotify(Quality& q); + + + //================================================================================ + // IQualityControl methods (from CBasePin) + //================================================================================ + + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + // no need to override: + // STDMETHODIMP SetSink(IQualityControl * piqc); + + + // switch the pin to inactive state - may already be inactive + virtual HRESULT Inactive(void); + + // Return sample properties pointer + AM_SAMPLE2_PROPERTIES * SampleProps() { + ASSERT(m_SampleProps.cbData != 0); + return &m_SampleProps; + } + +}; + +/////////////////////////////////////////////////////////////////////////// +// CDynamicOutputPin +// + +class CDynamicOutputPin : public CBaseOutputPin, + public IPinFlowControl +{ +public: +#ifdef UNICODE + CDynamicOutputPin( + __in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#endif + + CDynamicOutputPin( + __in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); + + ~CDynamicOutputPin(); + + // IUnknown Methods + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + // IPin Methods + STDMETHODIMP Disconnect(void); + + // IPinFlowControl Methods + STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent); + + // Set graph config info + void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent); + + #ifdef _DEBUG + virtual HRESULT Deliver(IMediaSample *pSample); + virtual HRESULT DeliverEndOfStream(void); + virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + #endif // DEBUG + + HRESULT DeliverBeginFlush(void); + HRESULT DeliverEndFlush(void); + + HRESULT Inactive(void); + HRESULT Active(void); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + virtual HRESULT StartUsingOutputPin(void); + virtual void StopUsingOutputPin(void); + virtual bool StreamingThreadUsingOutputPin(void); + + HRESULT ChangeOutputFormat + ( + const AM_MEDIA_TYPE *pmt, + REFERENCE_TIME tSegmentStart, + REFERENCE_TIME tSegmentStop, + double dSegmentRate + ); + HRESULT ChangeMediaType(const CMediaType *pmt); + HRESULT DynamicReconnect(const CMediaType *pmt); + +protected: + HRESULT SynchronousBlockOutputPin(void); + HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent); + HRESULT UnblockOutputPin(void); + + void BlockOutputPin(void); + void ResetBlockState(void); + + static HRESULT WaitEvent(HANDLE hEvent); + + enum BLOCK_STATE + { + NOT_BLOCKED, + PENDING, + BLOCKED + }; + + // This lock should be held when the following class members are + // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState, + // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers. + CCritSec m_BlockStateLock; + + // This event should be signaled when the output pin is + // not blocked. This is a manual reset event. For more + // information on events, see the documentation for + // CreateEvent() in the Windows SDK. + HANDLE m_hUnblockOutputPinEvent; + + // This event will be signaled when block operation succeedes or + // when the user cancels the block operation. The block operation + // can be canceled by calling IPinFlowControl2::Block( 0, NULL ) + // while the block operation is pending. + HANDLE m_hNotifyCallerPinBlockedEvent; + + // The state of the current block operation. + BLOCK_STATE m_BlockState; + + // The ID of the thread which last called IPinFlowControl::Block(). + // For more information on thread IDs, see the documentation for + // GetCurrentThreadID() in the Windows SDK. + DWORD m_dwBlockCallerThreadID; + + // The number of times StartUsingOutputPin() has been sucessfully + // called and a corresponding call to StopUsingOutputPin() has not + // been made. When this variable is greater than 0, the streaming + // thread is calling IPin::NewSegment(), IPin::EndOfStream(), + // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The + // streaming thread could also be calling: DynamicReconnect(), + // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot + // be blocked while the output pin is being used. + DWORD m_dwNumOutstandingOutputPinUsers; + + // This event should be set when the IMediaFilter::Stop() is called. + // This is a manual reset event. It is also set when the output pin + // delivers a flush to the connected input pin. + HANDLE m_hStopEvent; + IGraphConfig* m_pGraphConfig; + + // TRUE if the output pin's allocator's samples are read only. + // Otherwise FALSE. For more information, see the documentation + // for IMemInputPin::NotifyAllocator(). + BOOL m_bPinUsesReadOnlyAllocator; + +private: + HRESULT Initialize(void); + HRESULT ChangeMediaTypeHelper(const CMediaType *pmt); + + #ifdef _DEBUG + void AssertValid(void); + #endif // DEBUG +}; + +class CAutoUsingOutputPin +{ +public: + CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ); + ~CAutoUsingOutputPin(); + +private: + CDynamicOutputPin* m_pOutputPin; +}; + +inline CAutoUsingOutputPin::CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ) : + m_pOutputPin(NULL) +{ + // The caller should always pass in valid pointers. + ASSERT( NULL != pOutputPin ); + ASSERT( NULL != phr ); + + // Make sure the user initialized phr. + ASSERT( S_OK == *phr ); + + HRESULT hr = pOutputPin->StartUsingOutputPin(); + if( FAILED( hr ) ) + { + *phr = hr; + return; + } + + m_pOutputPin = pOutputPin; +} + +inline CAutoUsingOutputPin::~CAutoUsingOutputPin() +{ + if( NULL != m_pOutputPin ) + { + m_pOutputPin->StopUsingOutputPin(); + } +} + +#ifdef _DEBUG + +inline HRESULT CDynamicOutputPin::Deliver(IMediaSample *pSample) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + return CBaseOutputPin::Deliver(pSample); +} + +inline HRESULT CDynamicOutputPin::DeliverEndOfStream(void) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT( StreamingThreadUsingOutputPin() ); + + return CBaseOutputPin::DeliverEndOfStream(); +} + +inline HRESULT CDynamicOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + return CBaseOutputPin::DeliverNewSegment(tStart, tStop, dRate); +} + +#endif // DEBUG + +//===================================================================== +//===================================================================== +// Memory allocators +// +// the shared memory transport between pins requires the input pin +// to provide a memory allocator that can provide sample objects. A +// sample object supports the IMediaSample interface. +// +// CBaseAllocator handles the management of free and busy samples. It +// allocates CMediaSample objects. CBaseAllocator is an abstract class: +// in particular it has no method of initializing the list of free +// samples. CMemAllocator is derived from CBaseAllocator and initializes +// the list of samples using memory from the standard IMalloc interface. +// +// If you want your buffers to live in some special area of memory, +// derive your allocator object from CBaseAllocator. If you derive your +// IMemInputPin interface object from CBaseMemInputPin, you will get +// CMemAllocator-based allocation etc for free and will just need to +// supply the Receive handling, and media type / format negotiation. +//===================================================================== +//===================================================================== + + +//===================================================================== +//===================================================================== +// Defines CMediaSample +// +// an object of this class supports IMediaSample and represents a buffer +// for media data with some associated properties. Releasing it returns +// it to a freelist managed by a CBaseAllocator derived object. +//===================================================================== +//===================================================================== + +class CMediaSample : public IMediaSample2 // The interface we support +{ + +protected: + + friend class CBaseAllocator; + + /* Values for dwFlags - these are used for backward compatiblity + only now - use AM_SAMPLE_xxx + */ + enum { Sample_SyncPoint = 0x01, /* Is this a sync point */ + Sample_Preroll = 0x02, /* Is this a preroll sample */ + Sample_Discontinuity = 0x04, /* Set if start of new segment */ + Sample_TypeChanged = 0x08, /* Has the type changed */ + Sample_TimeValid = 0x10, /* Set if time is valid */ + Sample_MediaTimeValid = 0x20, /* Is the media time valid */ + Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */ + Sample_StopValid = 0x100, /* Stop time valid */ + Sample_ValidFlags = 0x1FF + }; + + /* Properties, the media sample class can be a container for a format + change in which case we take a copy of a type through the SetMediaType + interface function and then return it when GetMediaType is called. As + we do no internal processing on it we leave it as a pointer */ + + DWORD m_dwFlags; /* Flags for this sample */ + /* Type specific flags are packed + into the top word + */ + DWORD m_dwTypeSpecificFlags; /* Media type specific flags */ + __field_ecount_opt(m_cbBuffer) LPBYTE m_pBuffer; /* Pointer to the complete buffer */ + LONG m_lActual; /* Length of data in this sample */ + LONG m_cbBuffer; /* Size of the buffer */ + CBaseAllocator *m_pAllocator; /* The allocator who owns us */ + CMediaSample *m_pNext; /* Chaining in free list */ + REFERENCE_TIME m_Start; /* Start sample time */ + REFERENCE_TIME m_End; /* End sample time */ + LONGLONG m_MediaStart; /* Real media start position */ + LONG m_MediaEnd; /* A difference to get the end */ + AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */ + DWORD m_dwStreamId; /* Stream id */ +public: + LONG m_cRef; /* Reference count */ + + +public: + + CMediaSample( + __in_opt LPCTSTR pName, + __in_opt CBaseAllocator *pAllocator, + __inout_opt HRESULT *phr, + __in_bcount_opt(length) LPBYTE pBuffer = NULL, + LONG length = 0); +#ifdef UNICODE + CMediaSample( + __in_opt LPCSTR pName, + __in_opt CBaseAllocator *pAllocator, + __inout_opt HRESULT *phr, + __in_bcount_opt(length) LPBYTE pBuffer = NULL, + LONG length = 0); +#endif + + virtual ~CMediaSample(); + + /* Note the media sample does not delegate to its owner */ + + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // set the buffer pointer and length. Used by allocators that + // want variable sized pointers or pointers into already-read data. + // This is only available through a CMediaSample* not an IMediaSample* + // and so cannot be changed by clients. + HRESULT SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes); + + // Get me a read/write pointer to this buffer's memory. + STDMETHODIMP GetPointer(__deref_out BYTE ** ppBuffer); + + STDMETHODIMP_(LONG) GetSize(void); + + // get the stream time at which this sample should start and finish. + STDMETHODIMP GetTime( + __out REFERENCE_TIME * pTimeStart, // put time here + __out REFERENCE_TIME * pTimeEnd + ); + + // Set the stream time at which this sample should start and finish. + STDMETHODIMP SetTime( + __in_opt REFERENCE_TIME * pTimeStart, // put time here + __in_opt REFERENCE_TIME * pTimeEnd + ); + STDMETHODIMP IsSyncPoint(void); + STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint); + STDMETHODIMP IsPreroll(void); + STDMETHODIMP SetPreroll(BOOL bIsPreroll); + + STDMETHODIMP_(LONG) GetActualDataLength(void); + STDMETHODIMP SetActualDataLength(LONG lActual); + + // these allow for limited format changes in band + + STDMETHODIMP GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType); + STDMETHODIMP SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType); + + // returns S_OK if there is a discontinuity in the data (this same is + // not a continuation of the previous stream of data + // - there has been a seek). + STDMETHODIMP IsDiscontinuity(void); + // set the discontinuity property - TRUE if this sample is not a + // continuation, but a new sample after a seek. + STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity); + + // get the media times for this sample + STDMETHODIMP GetMediaTime( + __out LONGLONG * pTimeStart, + __out LONGLONG * pTimeEnd + ); + + // Set the media times for this sample + STDMETHODIMP SetMediaTime( + __in_opt LONGLONG * pTimeStart, + __in_opt LONGLONG * pTimeEnd + ); + + // Set and get properties (IMediaSample2) + STDMETHODIMP GetProperties( + DWORD cbProperties, + __out_bcount(cbProperties) BYTE * pbProperties + ); + + STDMETHODIMP SetProperties( + DWORD cbProperties, + __in_bcount(cbProperties) const BYTE * pbProperties + ); +}; + + +//===================================================================== +//===================================================================== +// Defines CBaseAllocator +// +// Abstract base class that manages a list of media samples +// +// This class provides support for getting buffers from the free list, +// including handling of commit and (asynchronous) decommit. +// +// Derive from this class and override the Alloc and Free functions to +// allocate your CMediaSample (or derived) objects and add them to the +// free list, preparing them as necessary. +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseAllocator : public CUnknown,// A non delegating IUnknown + public IMemAllocatorCallbackTemp, // The interface we support + public CCritSec // Provides object locking +{ + class CSampleList; + friend class CSampleList; + + /* Trick to get at protected member in CMediaSample */ + static CMediaSample * &NextSample(__in CMediaSample *pSample) + { + return pSample->m_pNext; + }; + + /* Mini list class for the free list */ + class CSampleList + { + public: + CSampleList() : m_List(NULL), m_nOnList(0) {}; +#ifdef _DEBUG + ~CSampleList() + { + ASSERT(m_nOnList == 0); + }; +#endif + CMediaSample *Head() const { return m_List; }; + CMediaSample *Next(__in CMediaSample *pSample) const { return CBaseAllocator::NextSample(pSample); }; + int GetCount() const { return m_nOnList; }; + void Add(__inout CMediaSample *pSample) + { + ASSERT(pSample != NULL); + CBaseAllocator::NextSample(pSample) = m_List; + m_List = pSample; + m_nOnList++; + }; + CMediaSample *RemoveHead() + { + CMediaSample *pSample = m_List; + if (pSample != NULL) { + m_List = CBaseAllocator::NextSample(m_List); + m_nOnList--; + } + return pSample; + }; + void Remove(__inout CMediaSample *pSample); + + public: + CMediaSample *m_List; + int m_nOnList; + }; +protected: + + CSampleList m_lFree; // Free list + + /* Note to overriders of CBaseAllocator. + + We use a lazy signalling mechanism for waiting for samples. + This means we don't call the OS if no waits occur. + + In order to implement this: + + 1. When a new sample is added to m_lFree call NotifySample() which + calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and + sets m_lWaiting to 0. + This must all be done holding the allocator's critical section. + + 2. When waiting for a sample call SetWaiting() which increments + m_lWaiting BEFORE leaving the allocator's critical section. + + 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE) + having left the allocator's critical section. The effect of + this is to remove 1 from the semaphore's count. You MUST call + this once having incremented m_lWaiting. + + The following are then true when the critical section is not held : + (let nWaiting = number about to wait or waiting) + + (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0) + (2) m_lWaiting + Semaphore count == nWaiting + + We would deadlock if + nWaiting != 0 && + m_lFree.GetCount() != 0 && + Semaphore count == 0 + + But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so + from (2) Semaphore count == nWaiting (which is non-0) so the + deadlock can't happen. + */ + + HANDLE m_hSem; // For signalling + long m_lWaiting; // Waiting for a free element + long m_lCount; // how many buffers we have agreed to provide + long m_lAllocated; // how many buffers are currently allocated + long m_lSize; // agreed size of each buffer + long m_lAlignment; // agreed alignment + long m_lPrefix; // agreed prefix (preceeds GetPointer() value) + BOOL m_bChanged; // Have the buffer requirements changed + + // if true, we are decommitted and can't allocate memory + BOOL m_bCommitted; + // if true, the decommit has happened, but we haven't called Free yet + // as there are still outstanding buffers + BOOL m_bDecommitInProgress; + + // Notification interface + IMemAllocatorNotifyCallbackTemp *m_pNotify; + + BOOL m_fEnableReleaseCallback; + + // called to decommit the memory when the last buffer is freed + // pure virtual - need to override this + virtual void Free(void) PURE; + + // override to allocate the memory when commit called + virtual HRESULT Alloc(void); + +public: + + CBaseAllocator( + __in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *, + BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); +#ifdef UNICODE + CBaseAllocator( + __in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *, + BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); +#endif + virtual ~CBaseAllocator(); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + STDMETHODIMP SetProperties( + __in ALLOCATOR_PROPERTIES* pRequest, + __out ALLOCATOR_PROPERTIES* pActual); + + // return the properties actually being used on this allocator + STDMETHODIMP GetProperties( + __out ALLOCATOR_PROPERTIES* pProps); + + // override Commit to allocate memory. We handle the GetBuffer + //state changes + STDMETHODIMP Commit(); + + // override this to handle the memory freeing. We handle any outstanding + // GetBuffer calls + STDMETHODIMP Decommit(); + + // get container for a sample. Blocking, synchronous call to get the + // next free buffer (as represented by an IMediaSample interface). + // on return, the time etc properties will be invalid, but the buffer + // pointer and size will be correct. The two time parameters are + // optional and either may be NULL, they may alternatively be set to + // the start and end times the sample will have attached to it + // bPrevFramesSkipped is not used (used only by the video renderer's + // allocator where it affects quality management in direct draw). + + STDMETHODIMP GetBuffer(__deref_out IMediaSample **ppBuffer, + __in_opt REFERENCE_TIME * pStartTime, + __in_opt REFERENCE_TIME * pEndTime, + DWORD dwFlags); + + // final release of a CMediaSample will call this + STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer); + // obsolete:: virtual void PutOnFreeList(CMediaSample * pSample); + + STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); + + STDMETHODIMP GetFreeCount(__out LONG *plBuffersFree); + + // Notify that a sample is available + void NotifySample(); + + // Notify that we're waiting for a sample + void SetWaiting() { m_lWaiting++; }; +}; + + +//===================================================================== +//===================================================================== +// Defines CMemAllocator +// +// this is an allocator based on CBaseAllocator that allocates sample +// buffers in main memory (from 'new'). You must call SetProperties +// before calling Commit. +// +// we don't free the memory when going into Decommit state. The simplest +// way to implement this without complicating CBaseAllocator is to +// have a Free() function, called to go into decommit state, that does +// nothing and a ReallyFree function called from our destructor that +// actually frees the memory. +//===================================================================== +//===================================================================== + +// Make me one from quartz.dll +STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator); + +class CMemAllocator : public CBaseAllocator +{ + +protected: + + LPBYTE m_pBuffer; // combined memory for all buffers + + // override to free the memory when decommit completes + // - we actually do nothing, and save the memory until deletion. + void Free(void); + + // called from the destructor (and from Alloc if changing size/count) to + // actually free up the memory + void ReallyFree(void); + + // overriden to allocate the memory when commit called + HRESULT Alloc(void); + +public: + /* This goes in the factory template table to create new instances */ + static CUnknown *CreateInstance(__inout_opt LPUNKNOWN, __inout HRESULT *); + + STDMETHODIMP SetProperties( + __in ALLOCATOR_PROPERTIES* pRequest, + __out ALLOCATOR_PROPERTIES* pActual); + + CMemAllocator(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *); +#ifdef UNICODE + CMemAllocator(__in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *); +#endif + ~CMemAllocator(); +}; + +// helper used by IAMovieSetup implementation +STDAPI +AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper * pIFM + , BOOL bRegister ); + + +/////////////////////////////////////////////////////////////////////////// +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +/////////////////////////////////////////////////////////////////////////// + +#endif /* __FILTER__ */ + + + diff --git a/src/thirdparty/BaseClasses/amvideo.cpp b/src/thirdparty/BaseClasses/amvideo.cpp index 6af1a3fddd5..c407fe34466 100644 --- a/src/thirdparty/BaseClasses/amvideo.cpp +++ b/src/thirdparty/BaseClasses/amvideo.cpp @@ -1,275 +1,275 @@ -//------------------------------------------------------------------------------ -// File: AMVideo.cpp -// -// Desc: DirectShow base classes - implements helper functions for -// bitmap formats. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -// These are bit field masks for true colour devices - -const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F}; -const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F}; -const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF}; - -// This maps bitmap subtypes into a bits per pixel value and also a -// name. unicode and ansi versions are stored because we have to -// return a pointer to a static string. -const struct { - const GUID *pSubtype; - WORD BitCount; - LPCSTR pName; - LPCWSTR wszName; -} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome", - &MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA", - &MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8", - &MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)", - &MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)", - &MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24", - &MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32", - &MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32", - &MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay", - &GUID_NULL, 0, "UNKNOWN", L"UNKNOWN" -}; - -// Return the size of the bitmap as defined by this header - -STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader) -{ - return DIBSIZE(*pHeader); -} - - -// This is called if the header has a 16 bit colour depth and needs to work -// out the detailed type from the bit fields (either RGB 565 or RGB 555) - -STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader) -{ - BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader; - ASSERT(pbmiHeader->biBitCount == 16); - - // If its BI_RGB then it's RGB 555 by default - - if (pbmiHeader->biCompression == BI_RGB) { - return MEDIASUBTYPE_RGB555; - } - - // Compare the bit fields with RGB 555 - - DWORD *pMask = (DWORD *) pbmInfo->bmiColors; - if (pMask[0] == bits555[0]) { - if (pMask[1] == bits555[1]) { - if (pMask[2] == bits555[2]) { - return MEDIASUBTYPE_RGB555; - } - } - } - - // Compare the bit fields with RGB 565 - - pMask = (DWORD *) pbmInfo->bmiColors; - if (pMask[0] == bits565[0]) { - if (pMask[1] == bits565[1]) { - if (pMask[2] == bits565[2]) { - return MEDIASUBTYPE_RGB565; - } - } - } - return GUID_NULL; -} - - -// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is -// used to describe it in format negotiations. For example a video codec fills -// in the format block with a VIDEOINFO structure, it also fills in the major -// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit -// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8 - -STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader) -{ - ASSERT(pbmiHeader); - - // If it's not RGB then create a GUID from the compression type - - if (pbmiHeader->biCompression != BI_RGB) { - if (pbmiHeader->biCompression != BI_BITFIELDS) { - FOURCCMap FourCCMap(pbmiHeader->biCompression); - return (const GUID) FourCCMap; - } - } - - // Map the RGB DIB bit depth to a image GUID - - switch(pbmiHeader->biBitCount) { - case 1 : return MEDIASUBTYPE_RGB1; - case 4 : return MEDIASUBTYPE_RGB4; - case 8 : return MEDIASUBTYPE_RGB8; - case 16 : return GetTrueColorType(pbmiHeader); - case 24 : return MEDIASUBTYPE_RGB24; - case 32 : return MEDIASUBTYPE_RGB32; - } - return GUID_NULL; -} - - -// Given a video bitmap subtype we return the number of bits per pixel it uses -// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the -// GUID subtype is not found in the table we return an invalid USHRT_MAX - -STDAPI_(WORD) GetBitCount(const GUID *pSubtype) -{ - ASSERT(pSubtype); - const GUID *pMediaSubtype; - INT iPosition = 0; - - // Scan the mapping list seeing if the source GUID matches any known - // bitmap subtypes, the list is terminated by a GUID_NULL entry - - for (;;) { - pMediaSubtype = BitCountMap[iPosition].pSubtype; - if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) { - return USHRT_MAX; - } - if (IsEqualGUID(*pMediaSubtype,*pSubtype)) { - return BitCountMap[iPosition].BitCount; - } - iPosition++; - } -} - - -// Given a bitmap subtype we return a description name that can be used for -// debug purposes. In a retail build this function still returns the names -// If the subtype isn't found in the lookup table we return string UNKNOWN - -int LocateSubtype(const GUID *pSubtype) -{ - ASSERT(pSubtype); - const GUID *pMediaSubtype; - INT iPosition = 0; - - // Scan the mapping list seeing if the source GUID matches any known - // bitmap subtypes, the list is terminated by a GUID_NULL entry - - for (;;) { - pMediaSubtype = BitCountMap[iPosition].pSubtype; - if (IsEqualGUID(*pMediaSubtype,*pSubtype) || - IsEqualGUID(*pMediaSubtype,GUID_NULL) - ) - { - break; - } - - iPosition++; - } - - return iPosition; -} - - - -STDAPI_(LPCWSTR) GetSubtypeNameW(const GUID *pSubtype) -{ - return BitCountMap[LocateSubtype(pSubtype)].wszName; -} - -STDAPI_(LPCSTR) GetSubtypeNameA(const GUID *pSubtype) -{ - return BitCountMap[LocateSubtype(pSubtype)].pName; -} - -#ifndef GetSubtypeName -#error wxutil.h should have defined GetSubtypeName -#endif -#undef GetSubtypeName - -// this is here for people that linked to it directly; most people -// would use the header file that picks the A or W version. -STDAPI_(LPCSTR) GetSubtypeName(const GUID *pSubtype) -{ - return GetSubtypeNameA(pSubtype); -} - - -// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER -// This is really messy to deal with because it invariably has fields that -// follow it holding bit fields, palettes and the rest. This function gives -// the number of bytes required to hold a VIDEOINFO that represents it. This -// count includes the prefix information (like the rcSource rectangle) the -// BITMAPINFOHEADER field, and any other colour information on the end. -// -// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make -// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't -// right at the start of the VIDEOINFO (there are a number of other fields), -// -// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); -// - -STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader) -{ - // Everyone has this to start with this - LONG Size = SIZE_PREHEADER + pHeader->biSize; - - ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER)); - - // Does this format use a palette, if the number of colours actually used - // is zero then it is set to the maximum that are allowed for that colour - // depth (an example is 256 for eight bits). Truecolour formats may also - // pass a palette with them in which case the used count is non zero - - // This would scare me. - ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0); - - if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) { - LONG Entries = (DWORD) 1 << pHeader->biBitCount; - if (pHeader->biClrUsed) { - Entries = pHeader->biClrUsed; - } - Size += Entries * sizeof(RGBQUAD); - } - - // Truecolour formats may have a BI_BITFIELDS specifier for compression - // type which means that room for three DWORDs should be allocated that - // specify where in each pixel the RGB colour components may be found - - if (pHeader->biCompression == BI_BITFIELDS) { - Size += SIZE_MASKS; - } - - // A BITMAPINFO for a palettised image may also contain a palette map that - // provides the information to map from a source palette to a destination - // palette during a BitBlt for example, because this information is only - // ever processed during drawing you don't normally store the palette map - // nor have any way of knowing if it is present in the data structure - - return Size; -} - - -// Returns TRUE if the VIDEOINFO contains a palette - -STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo) -{ - if (PALETTISED(pVideoInfo) == FALSE) { - if (pVideoInfo->bmiHeader.biClrUsed == 0) { - return FALSE; - } - } - return TRUE; -} - - -// Return a pointer to the first entry in a palette - -STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo) -{ - if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { - return TRUECOLOR(pVideoInfo)->bmiColors; - } - return COLORS(pVideoInfo); -} +//------------------------------------------------------------------------------ +// File: AMVideo.cpp +// +// Desc: DirectShow base classes - implements helper functions for +// bitmap formats. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +// These are bit field masks for true colour devices + +const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F}; +const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F}; +const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF}; + +// This maps bitmap subtypes into a bits per pixel value and also a +// name. unicode and ansi versions are stored because we have to +// return a pointer to a static string. +const struct { + const GUID *pSubtype; + WORD BitCount; + LPCSTR pName; + LPCWSTR wszName; +} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome", + &MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA", + &MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8", + &MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)", + &MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)", + &MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24", + &MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32", + &MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32", + &MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay", + &GUID_NULL, 0, "UNKNOWN", L"UNKNOWN" +}; + +// Return the size of the bitmap as defined by this header + +STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader) +{ + return DIBSIZE(*pHeader); +} + + +// This is called if the header has a 16 bit colour depth and needs to work +// out the detailed type from the bit fields (either RGB 565 or RGB 555) + +STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader) +{ + BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader; + ASSERT(pbmiHeader->biBitCount == 16); + + // If its BI_RGB then it's RGB 555 by default + + if (pbmiHeader->biCompression == BI_RGB) { + return MEDIASUBTYPE_RGB555; + } + + // Compare the bit fields with RGB 555 + + DWORD *pMask = (DWORD *) pbmInfo->bmiColors; + if (pMask[0] == bits555[0]) { + if (pMask[1] == bits555[1]) { + if (pMask[2] == bits555[2]) { + return MEDIASUBTYPE_RGB555; + } + } + } + + // Compare the bit fields with RGB 565 + + pMask = (DWORD *) pbmInfo->bmiColors; + if (pMask[0] == bits565[0]) { + if (pMask[1] == bits565[1]) { + if (pMask[2] == bits565[2]) { + return MEDIASUBTYPE_RGB565; + } + } + } + return GUID_NULL; +} + + +// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is +// used to describe it in format negotiations. For example a video codec fills +// in the format block with a VIDEOINFO structure, it also fills in the major +// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit +// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8 + +STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader) +{ + ASSERT(pbmiHeader); + + // If it's not RGB then create a GUID from the compression type + + if (pbmiHeader->biCompression != BI_RGB) { + if (pbmiHeader->biCompression != BI_BITFIELDS) { + FOURCCMap FourCCMap(pbmiHeader->biCompression); + return (const GUID) FourCCMap; + } + } + + // Map the RGB DIB bit depth to a image GUID + + switch(pbmiHeader->biBitCount) { + case 1 : return MEDIASUBTYPE_RGB1; + case 4 : return MEDIASUBTYPE_RGB4; + case 8 : return MEDIASUBTYPE_RGB8; + case 16 : return GetTrueColorType(pbmiHeader); + case 24 : return MEDIASUBTYPE_RGB24; + case 32 : return MEDIASUBTYPE_RGB32; + } + return GUID_NULL; +} + + +// Given a video bitmap subtype we return the number of bits per pixel it uses +// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the +// GUID subtype is not found in the table we return an invalid USHRT_MAX + +STDAPI_(WORD) GetBitCount(const GUID *pSubtype) +{ + ASSERT(pSubtype); + const GUID *pMediaSubtype; + INT iPosition = 0; + + // Scan the mapping list seeing if the source GUID matches any known + // bitmap subtypes, the list is terminated by a GUID_NULL entry + + for (;;) { + pMediaSubtype = BitCountMap[iPosition].pSubtype; + if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) { + return USHRT_MAX; + } + if (IsEqualGUID(*pMediaSubtype,*pSubtype)) { + return BitCountMap[iPosition].BitCount; + } + iPosition++; + } +} + + +// Given a bitmap subtype we return a description name that can be used for +// debug purposes. In a retail build this function still returns the names +// If the subtype isn't found in the lookup table we return string UNKNOWN + +int LocateSubtype(const GUID *pSubtype) +{ + ASSERT(pSubtype); + const GUID *pMediaSubtype; + INT iPosition = 0; + + // Scan the mapping list seeing if the source GUID matches any known + // bitmap subtypes, the list is terminated by a GUID_NULL entry + + for (;;) { + pMediaSubtype = BitCountMap[iPosition].pSubtype; + if (IsEqualGUID(*pMediaSubtype,*pSubtype) || + IsEqualGUID(*pMediaSubtype,GUID_NULL) + ) + { + break; + } + + iPosition++; + } + + return iPosition; +} + + + +STDAPI_(LPCWSTR) GetSubtypeNameW(const GUID *pSubtype) +{ + return BitCountMap[LocateSubtype(pSubtype)].wszName; +} + +STDAPI_(LPCSTR) GetSubtypeNameA(const GUID *pSubtype) +{ + return BitCountMap[LocateSubtype(pSubtype)].pName; +} + +#ifndef GetSubtypeName +#error wxutil.h should have defined GetSubtypeName +#endif +#undef GetSubtypeName + +// this is here for people that linked to it directly; most people +// would use the header file that picks the A or W version. +STDAPI_(LPCSTR) GetSubtypeName(const GUID *pSubtype) +{ + return GetSubtypeNameA(pSubtype); +} + + +// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER +// This is really messy to deal with because it invariably has fields that +// follow it holding bit fields, palettes and the rest. This function gives +// the number of bytes required to hold a VIDEOINFO that represents it. This +// count includes the prefix information (like the rcSource rectangle) the +// BITMAPINFOHEADER field, and any other colour information on the end. +// +// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make +// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't +// right at the start of the VIDEOINFO (there are a number of other fields), +// +// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); +// + +STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader) +{ + // Everyone has this to start with this + LONG Size = SIZE_PREHEADER + pHeader->biSize; + + ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER)); + + // Does this format use a palette, if the number of colours actually used + // is zero then it is set to the maximum that are allowed for that colour + // depth (an example is 256 for eight bits). Truecolour formats may also + // pass a palette with them in which case the used count is non zero + + // This would scare me. + ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0); + + if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) { + LONG Entries = (DWORD) 1 << pHeader->biBitCount; + if (pHeader->biClrUsed) { + Entries = pHeader->biClrUsed; + } + Size += Entries * sizeof(RGBQUAD); + } + + // Truecolour formats may have a BI_BITFIELDS specifier for compression + // type which means that room for three DWORDs should be allocated that + // specify where in each pixel the RGB colour components may be found + + if (pHeader->biCompression == BI_BITFIELDS) { + Size += SIZE_MASKS; + } + + // A BITMAPINFO for a palettised image may also contain a palette map that + // provides the information to map from a source palette to a destination + // palette during a BitBlt for example, because this information is only + // ever processed during drawing you don't normally store the palette map + // nor have any way of knowing if it is present in the data structure + + return Size; +} + + +// Returns TRUE if the VIDEOINFO contains a palette + +STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo) +{ + if (PALETTISED(pVideoInfo) == FALSE) { + if (pVideoInfo->bmiHeader.biClrUsed == 0) { + return FALSE; + } + } + return TRUE; +} + + +// Return a pointer to the first entry in a palette + +STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo) +{ + if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { + return TRUECOLOR(pVideoInfo)->bmiColors; + } + return COLORS(pVideoInfo); +} diff --git a/src/thirdparty/BaseClasses/arithutil.cpp b/src/thirdparty/BaseClasses/arithutil.cpp index 54156cd8e02..5e0bd1fffb3 100644 --- a/src/thirdparty/BaseClasses/arithutil.cpp +++ b/src/thirdparty/BaseClasses/arithutil.cpp @@ -1,360 +1,360 @@ -//------------------------------------------------------------------------------ -// File: ArithUtil.cpp -// -// Desc: DirectShow base classes - implements helper classes for building -// multimedia filters. -// -// Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - -#include "streams.h" - -// -// Declare function from largeint.h we need so that PPC can build -// - -// -// Enlarged integer divide - 64-bits / 32-bits > 32-bits -// - -#ifndef _X86_ - -#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) - -__inline -ULONG -WINAPI -EnlargedUnsignedDivide ( - IN ULARGE_INTEGER Dividend, - IN ULONG Divisor, - IN PULONG Remainder - ) -{ - // return remainder if necessary - if (Remainder != NULL) - *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); - return (ULONG)(LLtoU64(Dividend) / Divisor); -} - -#else -__inline -ULONG -WINAPI -EnlargedUnsignedDivide ( - IN ULARGE_INTEGER Dividend, - IN ULONG Divisor, - IN PULONG Remainder - ) -{ - ULONG ulResult; - _asm { - mov eax,Dividend.LowPart - mov edx,Dividend.HighPart - mov ecx,Remainder - div Divisor - or ecx,ecx - jz short label - mov [ecx],edx -label: - mov ulResult,eax - } - return ulResult; -} -#endif - - -/* Arithmetic functions to help with time format conversions -*/ - -#ifdef _M_ALPHA -// work around bug in version 12.00.8385 of the alpha compiler where -// UInt32x32To64 sign-extends its arguments (?) -#undef UInt32x32To64 -#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) -#endif - -/* Compute (a * b + d) / c */ -LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) -{ - /* Compute the absolute values to avoid signed arithmetic problems */ - ULARGE_INTEGER ua, ub; - DWORDLONG uc; - - ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); - ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); - uc = (DWORDLONG)(c >= 0 ? c : -c); - BOOL bSign = (a < 0) ^ (b < 0); - - /* Do long multiplication */ - ULARGE_INTEGER p[2]; - p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); - - /* This next computation cannot overflow into p[1].HighPart because - the max number we can compute here is: - - (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart - (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 - - == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) - == 2 ** 96 - 2 ** 33 + 1 - < 2 ** 96 - */ - - ULARGE_INTEGER x; - x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + - UInt32x32To64(ua.HighPart, ub.LowPart) + - p[0].HighPart; - p[0].HighPart = x.LowPart; - p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; - - if (d != 0) { - ULARGE_INTEGER ud[2]; - if (bSign) { - ud[0].QuadPart = (DWORDLONG)(-d); - if (d > 0) { - /* -d < 0 */ - ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; - } else { - ud[1].QuadPart = (DWORDLONG)0; - } - } else { - ud[0].QuadPart = (DWORDLONG)d; - if (d < 0) { - ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; - } else { - ud[1].QuadPart = (DWORDLONG)0; - } - } - /* Now do extended addition */ - ULARGE_INTEGER uliTotal; - - /* Add ls DWORDs */ - uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; - p[0].LowPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add 2nd most ls DWORDs */ - uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; - p[0].HighPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add MS DWORDLONGs - no carry expected */ - p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; - - /* Now see if we got a sign change from the addition */ - if ((LONG)p[1].HighPart < 0) { - bSign = !bSign; - - /* Negate the current value (ugh!) */ - p[0].QuadPart = ~p[0].QuadPart; - p[1].QuadPart = ~p[1].QuadPart; - p[0].QuadPart += 1; - p[1].QuadPart += (p[0].QuadPart == 0); - } - } - - /* Now for the division */ - if (c < 0) { - bSign = !bSign; - } - - - /* This will catch c == 0 and overflow */ - if (uc <= p[1].QuadPart) { - return bSign ? (LONGLONG)0x8000000000000000 : - (LONGLONG)0x7FFFFFFFFFFFFFFF; - } - - DWORDLONG ullResult; - - /* Do the division */ - /* If the dividend is a DWORD_LONG use the compiler */ - if (p[1].QuadPart == 0) { - ullResult = p[0].QuadPart / uc; - return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; - } - - /* If the divisor is a DWORD then its simpler */ - ULARGE_INTEGER ulic; - ulic.QuadPart = uc; - if (ulic.HighPart == 0) { - ULARGE_INTEGER uliDividend; - ULARGE_INTEGER uliResult; - DWORD dwDivisor = (DWORD)uc; - // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); - uliDividend.HighPart = p[1].LowPart; - uliDividend.LowPart = p[0].HighPart; -#ifndef USE_LARGEINT - uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); - p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); - uliResult.LowPart = 0; - uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; -#else - /* NOTE - this routine will take exceptions if - the result does not fit in a DWORD - */ - if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { - uliResult.HighPart = EnlargedUnsignedDivide( - uliDividend, - dwDivisor, - &p[0].HighPart); - } else { - uliResult.HighPart = 0; - } - uliResult.LowPart = EnlargedUnsignedDivide( - p[0], - dwDivisor, - NULL); -#endif - return bSign ? -(LONGLONG)uliResult.QuadPart : - (LONGLONG)uliResult.QuadPart; - } - - - ullResult = 0; - - /* OK - do long division */ - for (int i = 0; i < 64; i++) { - ullResult <<= 1; - - /* Shift 128 bit p left 1 */ - p[1].QuadPart <<= 1; - if ((p[0].HighPart & 0x80000000) != 0) { - p[1].LowPart++; - } - p[0].QuadPart <<= 1; - - /* Compare */ - if (uc <= p[1].QuadPart) { - p[1].QuadPart -= uc; - ullResult += 1; - } - } - - return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; -} - -LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) -{ - ULARGE_INTEGER ua; - DWORD ub; - DWORD uc; - - /* Compute the absolute values to avoid signed arithmetic problems */ - ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); - ub = (DWORD)(b >= 0 ? b : -b); - uc = (DWORD)(c >= 0 ? c : -c); - BOOL bSign = (a < 0) ^ (b < 0); - - /* Do long multiplication */ - ULARGE_INTEGER p0; - DWORD p1; - p0.QuadPart = UInt32x32To64(ua.LowPart, ub); - - if (ua.HighPart != 0) { - ULARGE_INTEGER x; - x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; - p0.HighPart = x.LowPart; - p1 = x.HighPart; - } else { - p1 = 0; - } - - if (d != 0) { - ULARGE_INTEGER ud0; - DWORD ud1; - - if (bSign) { - // - // Cast d to LONGLONG first otherwise -0x80000000 sign extends - // incorrectly - // - ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); - if (d > 0) { - /* -d < 0 */ - ud1 = (DWORD)-1; - } else { - ud1 = (DWORD)0; - } - } else { - ud0.QuadPart = (DWORDLONG)d; - if (d < 0) { - ud1 = (DWORD)-1; - } else { - ud1 = (DWORD)0; - } - } - /* Now do extended addition */ - ULARGE_INTEGER uliTotal; - - /* Add ls DWORDs */ - uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; - p0.LowPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add 2nd most ls DWORDs */ - uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; - p0.HighPart = uliTotal.LowPart; - - /* Add MS DWORDLONGs - no carry expected */ - p1 += ud1 + uliTotal.HighPart; - - /* Now see if we got a sign change from the addition */ - if ((LONG)p1 < 0) { - bSign = !bSign; - - /* Negate the current value (ugh!) */ - p0.QuadPart = ~p0.QuadPart; - p1 = ~p1; - p0.QuadPart += 1; - p1 += (p0.QuadPart == 0); - } - } - - /* Now for the division */ - if (c < 0) { - bSign = !bSign; - } - - - /* This will catch c == 0 and overflow */ - if (uc <= p1) { - return bSign ? (LONGLONG)0x8000000000000000 : - (LONGLONG)0x7FFFFFFFFFFFFFFF; - } - - /* Do the division */ - - /* If the divisor is a DWORD then its simpler */ - ULARGE_INTEGER uliDividend; - ULARGE_INTEGER uliResult; - DWORD dwDivisor = uc; - uliDividend.HighPart = p1; - uliDividend.LowPart = p0.HighPart; - /* NOTE - this routine will take exceptions if - the result does not fit in a DWORD - */ - if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { - uliResult.HighPart = EnlargedUnsignedDivide( - uliDividend, - dwDivisor, - &p0.HighPart); - } else { - uliResult.HighPart = 0; - } - uliResult.LowPart = EnlargedUnsignedDivide( - p0, - dwDivisor, - NULL); - return bSign ? -(LONGLONG)uliResult.QuadPart : - (LONGLONG)uliResult.QuadPart; -} +//------------------------------------------------------------------------------ +// File: ArithUtil.cpp +// +// Desc: DirectShow base classes - implements helper classes for building +// multimedia filters. +// +// Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +#include "streams.h" + +// +// Declare function from largeint.h we need so that PPC can build +// + +// +// Enlarged integer divide - 64-bits / 32-bits > 32-bits +// + +#ifndef _X86_ + +#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) + +__inline +ULONG +WINAPI +EnlargedUnsignedDivide ( + IN ULARGE_INTEGER Dividend, + IN ULONG Divisor, + IN PULONG Remainder + ) +{ + // return remainder if necessary + if (Remainder != NULL) + *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); + return (ULONG)(LLtoU64(Dividend) / Divisor); +} + +#else +__inline +ULONG +WINAPI +EnlargedUnsignedDivide ( + IN ULARGE_INTEGER Dividend, + IN ULONG Divisor, + IN PULONG Remainder + ) +{ + ULONG ulResult; + _asm { + mov eax,Dividend.LowPart + mov edx,Dividend.HighPart + mov ecx,Remainder + div Divisor + or ecx,ecx + jz short label + mov [ecx],edx +label: + mov ulResult,eax + } + return ulResult; +} +#endif + + +/* Arithmetic functions to help with time format conversions +*/ + +#ifdef _M_ALPHA +// work around bug in version 12.00.8385 of the alpha compiler where +// UInt32x32To64 sign-extends its arguments (?) +#undef UInt32x32To64 +#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) +#endif + +/* Compute (a * b + d) / c */ +LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) +{ + /* Compute the absolute values to avoid signed arithmetic problems */ + ULARGE_INTEGER ua, ub; + DWORDLONG uc; + + ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); + ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); + uc = (DWORDLONG)(c >= 0 ? c : -c); + BOOL bSign = (a < 0) ^ (b < 0); + + /* Do long multiplication */ + ULARGE_INTEGER p[2]; + p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); + + /* This next computation cannot overflow into p[1].HighPart because + the max number we can compute here is: + + (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart + (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 + + == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) + == 2 ** 96 - 2 ** 33 + 1 + < 2 ** 96 + */ + + ULARGE_INTEGER x; + x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + + UInt32x32To64(ua.HighPart, ub.LowPart) + + p[0].HighPart; + p[0].HighPart = x.LowPart; + p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; + + if (d != 0) { + ULARGE_INTEGER ud[2]; + if (bSign) { + ud[0].QuadPart = (DWORDLONG)(-d); + if (d > 0) { + /* -d < 0 */ + ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; + } else { + ud[1].QuadPart = (DWORDLONG)0; + } + } else { + ud[0].QuadPart = (DWORDLONG)d; + if (d < 0) { + ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; + } else { + ud[1].QuadPart = (DWORDLONG)0; + } + } + /* Now do extended addition */ + ULARGE_INTEGER uliTotal; + + /* Add ls DWORDs */ + uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; + p[0].LowPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add 2nd most ls DWORDs */ + uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; + p[0].HighPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add MS DWORDLONGs - no carry expected */ + p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; + + /* Now see if we got a sign change from the addition */ + if ((LONG)p[1].HighPart < 0) { + bSign = !bSign; + + /* Negate the current value (ugh!) */ + p[0].QuadPart = ~p[0].QuadPart; + p[1].QuadPart = ~p[1].QuadPart; + p[0].QuadPart += 1; + p[1].QuadPart += (p[0].QuadPart == 0); + } + } + + /* Now for the division */ + if (c < 0) { + bSign = !bSign; + } + + + /* This will catch c == 0 and overflow */ + if (uc <= p[1].QuadPart) { + return bSign ? (LONGLONG)0x8000000000000000 : + (LONGLONG)0x7FFFFFFFFFFFFFFF; + } + + DWORDLONG ullResult; + + /* Do the division */ + /* If the dividend is a DWORD_LONG use the compiler */ + if (p[1].QuadPart == 0) { + ullResult = p[0].QuadPart / uc; + return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; + } + + /* If the divisor is a DWORD then its simpler */ + ULARGE_INTEGER ulic; + ulic.QuadPart = uc; + if (ulic.HighPart == 0) { + ULARGE_INTEGER uliDividend; + ULARGE_INTEGER uliResult; + DWORD dwDivisor = (DWORD)uc; + // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); + uliDividend.HighPart = p[1].LowPart; + uliDividend.LowPart = p[0].HighPart; +#ifndef USE_LARGEINT + uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); + p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); + uliResult.LowPart = 0; + uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; +#else + /* NOTE - this routine will take exceptions if + the result does not fit in a DWORD + */ + if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { + uliResult.HighPart = EnlargedUnsignedDivide( + uliDividend, + dwDivisor, + &p[0].HighPart); + } else { + uliResult.HighPart = 0; + } + uliResult.LowPart = EnlargedUnsignedDivide( + p[0], + dwDivisor, + NULL); +#endif + return bSign ? -(LONGLONG)uliResult.QuadPart : + (LONGLONG)uliResult.QuadPart; + } + + + ullResult = 0; + + /* OK - do long division */ + for (int i = 0; i < 64; i++) { + ullResult <<= 1; + + /* Shift 128 bit p left 1 */ + p[1].QuadPart <<= 1; + if ((p[0].HighPart & 0x80000000) != 0) { + p[1].LowPart++; + } + p[0].QuadPart <<= 1; + + /* Compare */ + if (uc <= p[1].QuadPart) { + p[1].QuadPart -= uc; + ullResult += 1; + } + } + + return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; +} + +LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) +{ + ULARGE_INTEGER ua; + DWORD ub; + DWORD uc; + + /* Compute the absolute values to avoid signed arithmetic problems */ + ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); + ub = (DWORD)(b >= 0 ? b : -b); + uc = (DWORD)(c >= 0 ? c : -c); + BOOL bSign = (a < 0) ^ (b < 0); + + /* Do long multiplication */ + ULARGE_INTEGER p0; + DWORD p1; + p0.QuadPart = UInt32x32To64(ua.LowPart, ub); + + if (ua.HighPart != 0) { + ULARGE_INTEGER x; + x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; + p0.HighPart = x.LowPart; + p1 = x.HighPart; + } else { + p1 = 0; + } + + if (d != 0) { + ULARGE_INTEGER ud0; + DWORD ud1; + + if (bSign) { + // + // Cast d to LONGLONG first otherwise -0x80000000 sign extends + // incorrectly + // + ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); + if (d > 0) { + /* -d < 0 */ + ud1 = (DWORD)-1; + } else { + ud1 = (DWORD)0; + } + } else { + ud0.QuadPart = (DWORDLONG)d; + if (d < 0) { + ud1 = (DWORD)-1; + } else { + ud1 = (DWORD)0; + } + } + /* Now do extended addition */ + ULARGE_INTEGER uliTotal; + + /* Add ls DWORDs */ + uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; + p0.LowPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add 2nd most ls DWORDs */ + uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; + p0.HighPart = uliTotal.LowPart; + + /* Add MS DWORDLONGs - no carry expected */ + p1 += ud1 + uliTotal.HighPart; + + /* Now see if we got a sign change from the addition */ + if ((LONG)p1 < 0) { + bSign = !bSign; + + /* Negate the current value (ugh!) */ + p0.QuadPart = ~p0.QuadPart; + p1 = ~p1; + p0.QuadPart += 1; + p1 += (p0.QuadPart == 0); + } + } + + /* Now for the division */ + if (c < 0) { + bSign = !bSign; + } + + + /* This will catch c == 0 and overflow */ + if (uc <= p1) { + return bSign ? (LONGLONG)0x8000000000000000 : + (LONGLONG)0x7FFFFFFFFFFFFFFF; + } + + /* Do the division */ + + /* If the divisor is a DWORD then its simpler */ + ULARGE_INTEGER uliDividend; + ULARGE_INTEGER uliResult; + DWORD dwDivisor = uc; + uliDividend.HighPart = p1; + uliDividend.LowPart = p0.HighPart; + /* NOTE - this routine will take exceptions if + the result does not fit in a DWORD + */ + if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { + uliResult.HighPart = EnlargedUnsignedDivide( + uliDividend, + dwDivisor, + &p0.HighPart); + } else { + uliResult.HighPart = 0; + } + uliResult.LowPart = EnlargedUnsignedDivide( + p0, + dwDivisor, + NULL); + return bSign ? -(LONGLONG)uliResult.QuadPart : + (LONGLONG)uliResult.QuadPart; +} diff --git a/src/thirdparty/BaseClasses/cache.h b/src/thirdparty/BaseClasses/cache.h index 0a807c27ef9..a2d57524ac7 100644 --- a/src/thirdparty/BaseClasses/cache.h +++ b/src/thirdparty/BaseClasses/cache.h @@ -1,74 +1,74 @@ -//------------------------------------------------------------------------------ -// File: Cache.h -// -// Desc: DirectShow base classes - efines a non-MFC generic cache class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* This class implements a simple cache. A cache object is instantiated - with the number of items it is to hold. An item is a pointer to an - object derived from CBaseObject (helps reduce memory leaks). The cache - can then have objects added to it and removed from it. The cache size - is fixed at construction time and may therefore run out or be flooded. - If it runs out it returns a NULL pointer, if it fills up it also returns - a NULL pointer instead of a pointer to the object just inserted */ - -/* Making these classes inherit from CBaseObject does nothing for their - functionality but it allows us to check there are no memory leaks */ - -/* WARNING Be very careful when using this class, what it lets you do is - store and retrieve objects so that you can minimise object creation - which in turns improves efficiency. However the object you store is - exactly the same as the object you get back which means that it short - circuits the constructor initialisation phase. This means any class - variables the object has (eg pointers) are highly likely to be invalid. - Therefore ensure you reinitialise the object before using it again */ - - -#ifndef __CACHE__ -#define __CACHE__ - - -class CCache : CBaseObject { - - /* Make copy constructor and assignment operator inaccessible */ - - CCache(const CCache &refCache); - CCache &operator=(const CCache &refCache); - -private: - - /* These are initialised in the constructor. The first variable points to - an array of pointers, each of which points to a CBaseObject derived - object. The m_iCacheSize is the static fixed size for the cache and the - m_iUsed defines the number of places filled with objects at any time. - We fill the array of pointers from the start (ie m_ppObjects[0] first) - and then only add and remove objects from the end position, so in this - respect the array of object pointers should be treated as a stack */ - - CBaseObject **m_ppObjects; - const INT m_iCacheSize; - INT m_iUsed; - -public: - - CCache(__in_opt LPCTSTR pName,INT iItems); - virtual ~CCache(); - - /* Add an item to the cache */ - CBaseObject *AddToCache(__in CBaseObject *pObject); - - /* Remove an item from the cache */ - CBaseObject *RemoveFromCache(); - - /* Delete all the objects held in the cache */ - void RemoveAll(void); - - /* Return the cache size which is set during construction */ - INT GetCacheSize(void) const {return m_iCacheSize;}; -}; - -#endif /* __CACHE__ */ - +//------------------------------------------------------------------------------ +// File: Cache.h +// +// Desc: DirectShow base classes - efines a non-MFC generic cache class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* This class implements a simple cache. A cache object is instantiated + with the number of items it is to hold. An item is a pointer to an + object derived from CBaseObject (helps reduce memory leaks). The cache + can then have objects added to it and removed from it. The cache size + is fixed at construction time and may therefore run out or be flooded. + If it runs out it returns a NULL pointer, if it fills up it also returns + a NULL pointer instead of a pointer to the object just inserted */ + +/* Making these classes inherit from CBaseObject does nothing for their + functionality but it allows us to check there are no memory leaks */ + +/* WARNING Be very careful when using this class, what it lets you do is + store and retrieve objects so that you can minimise object creation + which in turns improves efficiency. However the object you store is + exactly the same as the object you get back which means that it short + circuits the constructor initialisation phase. This means any class + variables the object has (eg pointers) are highly likely to be invalid. + Therefore ensure you reinitialise the object before using it again */ + + +#ifndef __CACHE__ +#define __CACHE__ + + +class CCache : CBaseObject { + + /* Make copy constructor and assignment operator inaccessible */ + + CCache(const CCache &refCache); + CCache &operator=(const CCache &refCache); + +private: + + /* These are initialised in the constructor. The first variable points to + an array of pointers, each of which points to a CBaseObject derived + object. The m_iCacheSize is the static fixed size for the cache and the + m_iUsed defines the number of places filled with objects at any time. + We fill the array of pointers from the start (ie m_ppObjects[0] first) + and then only add and remove objects from the end position, so in this + respect the array of object pointers should be treated as a stack */ + + CBaseObject **m_ppObjects; + const INT m_iCacheSize; + INT m_iUsed; + +public: + + CCache(__in_opt LPCTSTR pName,INT iItems); + virtual ~CCache(); + + /* Add an item to the cache */ + CBaseObject *AddToCache(__in CBaseObject *pObject); + + /* Remove an item from the cache */ + CBaseObject *RemoveFromCache(); + + /* Delete all the objects held in the cache */ + void RemoveAll(void); + + /* Return the cache size which is set during construction */ + INT GetCacheSize(void) const {return m_iCacheSize;}; +}; + +#endif /* __CACHE__ */ + diff --git a/src/thirdparty/BaseClasses/checkbmi.h b/src/thirdparty/BaseClasses/checkbmi.h index 72879679c1f..9761daec24e 100644 --- a/src/thirdparty/BaseClasses/checkbmi.h +++ b/src/thirdparty/BaseClasses/checkbmi.h @@ -1,120 +1,120 @@ -// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. - -#ifndef _CHECKBMI_H_ -#define _CHECKBMI_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// Helper -__inline BOOL MultiplyCheckOverflow(DWORD a, DWORD b, __deref_out_range(==, a * b) DWORD *pab) { - *pab = a * b; - if ((a == 0) || (((*pab) / a) == b)) { - return TRUE; - } - return FALSE; -} - - -// Checks if the fields in a BITMAPINFOHEADER won't generate -// overlows and buffer overruns -// This is not a complete check and does not guarantee code using this structure will be secure -// from attack -// Bugs this is guarding against: -// 1. Total structure size calculation overflowing -// 2. biClrUsed > 256 for 8-bit palettized content -// 3. Total bitmap size in bytes overflowing -// 4. biSize < size of the base structure leading to accessessing random memory -// 5. Total structure size exceeding know size of data -// - -__success(return != 0) __inline BOOL ValidateBitmapInfoHeader( - const BITMAPINFOHEADER *pbmi, // pointer to structure to check - __out_range(>=, sizeof(BITMAPINFOHEADER)) DWORD cbSize // size of memory block containing structure -) -{ - DWORD dwWidthInBytes; - DWORD dwBpp; - DWORD dwWidthInBits; - DWORD dwHeight; - DWORD dwSizeImage; - DWORD dwClrUsed; - - // Reject bad parameters - do the size check first to avoid reading bad memory - if (cbSize < sizeof(BITMAPINFOHEADER) || - pbmi->biSize < sizeof(BITMAPINFOHEADER) || - pbmi->biSize > 4096) { - return FALSE; - } - - // Reject 0 size - if (pbmi->biWidth == 0 || pbmi->biHeight == 0) { - return FALSE; - } - - // Use bpp of 200 for validating against further overflows if not set for compressed format - dwBpp = 200; - - if (pbmi->biBitCount > dwBpp) { - return FALSE; - } - - // Strictly speaking abs can overflow so cast explicitly to DWORD - dwHeight = (DWORD)abs(pbmi->biHeight); - - if (!MultiplyCheckOverflow(dwBpp, (DWORD)pbmi->biWidth, &dwWidthInBits)) { - return FALSE; - } - - // Compute correct width in bytes - rounding up to 4 bytes - dwWidthInBytes = (dwWidthInBits / 8 + 3) & ~3; - - if (!MultiplyCheckOverflow(dwWidthInBytes, dwHeight, &dwSizeImage)) { - return FALSE; - } - - // Fail if total size is 0 - this catches indivual quantities being 0 - // Also don't allow huge values > 1GB which might cause arithmetic - // errors for users - if (dwSizeImage > 0x40000000 || - pbmi->biSizeImage > 0x40000000) { - return FALSE; - } - - // Fail if biClrUsed looks bad - if (pbmi->biClrUsed > 256) { - return FALSE; - } - - if (pbmi->biClrUsed == 0 && pbmi->biBitCount <= 8 && pbmi->biBitCount > 0) { - dwClrUsed = (1 << pbmi->biBitCount); - } else { - dwClrUsed = pbmi->biClrUsed; - } - - // Check total size - if (cbSize < pbmi->biSize + dwClrUsed * sizeof(RGBQUAD) + - (pbmi->biCompression == BI_BITFIELDS ? 3 * sizeof(DWORD) : 0)) { - return FALSE; - } - - // If it is RGB validate biSizeImage - lots of code assumes the size is correct - if (pbmi->biCompression == BI_RGB || pbmi->biCompression == BI_BITFIELDS) { - if (pbmi->biSizeImage != 0) { - DWORD dwBits = (DWORD)pbmi->biWidth * (DWORD)pbmi->biBitCount; - DWORD dwWidthInBytes = ((DWORD)((dwBits+31) & (~31)) / 8); - DWORD dwTotalSize = (DWORD)abs(pbmi->biHeight) * dwWidthInBytes; - if (dwTotalSize > pbmi->biSizeImage) { - return FALSE; - } - } - } - return TRUE; -} - -#ifdef __cplusplus -} -#endif - -#endif // _CHECKBMI_H_ +// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. + +#ifndef _CHECKBMI_H_ +#define _CHECKBMI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Helper +__inline BOOL MultiplyCheckOverflow(DWORD a, DWORD b, __deref_out_range(==, a * b) DWORD *pab) { + *pab = a * b; + if ((a == 0) || (((*pab) / a) == b)) { + return TRUE; + } + return FALSE; +} + + +// Checks if the fields in a BITMAPINFOHEADER won't generate +// overlows and buffer overruns +// This is not a complete check and does not guarantee code using this structure will be secure +// from attack +// Bugs this is guarding against: +// 1. Total structure size calculation overflowing +// 2. biClrUsed > 256 for 8-bit palettized content +// 3. Total bitmap size in bytes overflowing +// 4. biSize < size of the base structure leading to accessessing random memory +// 5. Total structure size exceeding know size of data +// + +__success(return != 0) __inline BOOL ValidateBitmapInfoHeader( + const BITMAPINFOHEADER *pbmi, // pointer to structure to check + __out_range(>=, sizeof(BITMAPINFOHEADER)) DWORD cbSize // size of memory block containing structure +) +{ + DWORD dwWidthInBytes; + DWORD dwBpp; + DWORD dwWidthInBits; + DWORD dwHeight; + DWORD dwSizeImage; + DWORD dwClrUsed; + + // Reject bad parameters - do the size check first to avoid reading bad memory + if (cbSize < sizeof(BITMAPINFOHEADER) || + pbmi->biSize < sizeof(BITMAPINFOHEADER) || + pbmi->biSize > 4096) { + return FALSE; + } + + // Reject 0 size + if (pbmi->biWidth == 0 || pbmi->biHeight == 0) { + return FALSE; + } + + // Use bpp of 200 for validating against further overflows if not set for compressed format + dwBpp = 200; + + if (pbmi->biBitCount > dwBpp) { + return FALSE; + } + + // Strictly speaking abs can overflow so cast explicitly to DWORD + dwHeight = (DWORD)abs(pbmi->biHeight); + + if (!MultiplyCheckOverflow(dwBpp, (DWORD)pbmi->biWidth, &dwWidthInBits)) { + return FALSE; + } + + // Compute correct width in bytes - rounding up to 4 bytes + dwWidthInBytes = (dwWidthInBits / 8 + 3) & ~3; + + if (!MultiplyCheckOverflow(dwWidthInBytes, dwHeight, &dwSizeImage)) { + return FALSE; + } + + // Fail if total size is 0 - this catches indivual quantities being 0 + // Also don't allow huge values > 1GB which might cause arithmetic + // errors for users + if (dwSizeImage > 0x40000000 || + pbmi->biSizeImage > 0x40000000) { + return FALSE; + } + + // Fail if biClrUsed looks bad + if (pbmi->biClrUsed > 256) { + return FALSE; + } + + if (pbmi->biClrUsed == 0 && pbmi->biBitCount <= 8 && pbmi->biBitCount > 0) { + dwClrUsed = (1 << pbmi->biBitCount); + } else { + dwClrUsed = pbmi->biClrUsed; + } + + // Check total size + if (cbSize < pbmi->biSize + dwClrUsed * sizeof(RGBQUAD) + + (pbmi->biCompression == BI_BITFIELDS ? 3 * sizeof(DWORD) : 0)) { + return FALSE; + } + + // If it is RGB validate biSizeImage - lots of code assumes the size is correct + if (pbmi->biCompression == BI_RGB || pbmi->biCompression == BI_BITFIELDS) { + if (pbmi->biSizeImage != 0) { + DWORD dwBits = (DWORD)pbmi->biWidth * (DWORD)pbmi->biBitCount; + DWORD dwWidthInBytes = ((DWORD)((dwBits+31) & (~31)) / 8); + DWORD dwTotalSize = (DWORD)abs(pbmi->biHeight) * dwWidthInBytes; + if (dwTotalSize > pbmi->biSizeImage) { + return FALSE; + } + } + } + return TRUE; +} + +#ifdef __cplusplus +} +#endif + +#endif // _CHECKBMI_H_ diff --git a/src/thirdparty/BaseClasses/combase.cpp b/src/thirdparty/BaseClasses/combase.cpp index c369bbf1c2f..dd1b5a7996e 100644 --- a/src/thirdparty/BaseClasses/combase.cpp +++ b/src/thirdparty/BaseClasses/combase.cpp @@ -1,266 +1,266 @@ -//------------------------------------------------------------------------------ -// File: ComBase.cpp -// -// Desc: DirectShow base classes - implements class hierarchy for creating -// COM objects. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions - - -/* Define the static member variable */ - -LONG CBaseObject::m_cObjects = 0; - - -/* Constructor */ - -CBaseObject::CBaseObject(__in_opt LPCTSTR pName) -{ - /* Increment the number of active objects */ - InterlockedIncrement(&m_cObjects); - -#ifdef _DEBUG - -#ifdef UNICODE - m_dwCookie = DbgRegisterObjectCreation(0, pName); -#else - m_dwCookie = DbgRegisterObjectCreation(pName, 0); -#endif - -#endif -} - -#ifdef UNICODE -CBaseObject::CBaseObject(const char *pName) -{ - /* Increment the number of active objects */ - InterlockedIncrement(&m_cObjects); - -#ifdef _DEBUG - m_dwCookie = DbgRegisterObjectCreation(pName, 0); -#endif -} -#endif - -HINSTANCE hlibOLEAut32; - -/* Destructor */ - -CBaseObject::~CBaseObject() -{ - /* Decrement the number of objects active */ - if (InterlockedDecrement(&m_cObjects) == 0) { - if (hlibOLEAut32) { - FreeLibrary(hlibOLEAut32); - - hlibOLEAut32 = 0; - } - }; - - -#ifdef _DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif -} - -static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll"); - -HINSTANCE LoadOLEAut32() -{ - if (hlibOLEAut32 == 0) { - - hlibOLEAut32 = LoadLibrary(szOle32Aut); - } - - return hlibOLEAut32; -} - - -/* Constructor */ - -// We know we use "this" in the initialization list, we also know we don't modify *phr. -#pragma warning( disable : 4355 4100 ) -CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk) -: CBaseObject(pName) -/* Start the object with a reference count of zero - when the */ -/* object is queried for it's first interface this may be */ -/* incremented depending on whether or not this object is */ -/* currently being aggregated upon */ -, m_cRef(0) -/* Set our pointer to our IUnknown interface. */ -/* If we have an outer, use its, otherwise use ours. */ -/* This pointer effectivly points to the owner of */ -/* this object and can be accessed by the GetOwner() method. */ -, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) - /* Why the double cast? Well, the inner cast is a type-safe cast */ - /* to pointer to a type from which we inherit. The second is */ - /* type-unsafe but works because INonDelegatingUnknown "behaves */ - /* like" IUnknown. (Only the names on the methods change.) */ -{ - // Everything we need to do has been done in the initializer list -} - -// This does the same as above except it has a useless HRESULT argument -// use the previous constructor, this is just left for compatibility... -CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) : - CBaseObject(pName), - m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ -} - -#ifdef UNICODE -CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk) -: CBaseObject(pName), m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ } - -CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) : - CBaseObject(pName), m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ } - -#endif - -#pragma warning( default : 4355 4100 ) - - -/* QueryInterface */ - -STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) -{ - CheckPointer(ppv,E_POINTER); - ValidateReadWritePtr(ppv,sizeof(PVOID)); - - /* We know only about IUnknown */ - - if (riid == IID_IUnknown) { - GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv); - return NOERROR; - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -/* We have to ensure that we DON'T use a max macro, since these will typically */ -/* lead to one of the parameters being evaluated twice. Since we are worried */ -/* about concurrency, we can't afford to access the m_cRef twice since we can't */ -/* afford to run the risk that its value having changed between accesses. */ - -template inline static T ourmax( const T & a, const T & b ) -{ - return a > b ? a : b; -} - -/* AddRef */ - -STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef() -{ - LONG lRef = InterlockedIncrement( &m_cRef ); - ASSERT(lRef > 0); - UNREFERENCED_PARAMETER(lRef); - DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"), - m_dwCookie, m_cRef)); - return ourmax(ULONG(m_cRef), 1ul); -} - - -/* Release */ - -STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease() -{ - /* If the reference count drops to zero delete ourselves */ - - LONG lRef = InterlockedDecrement( &m_cRef ); - ASSERT(lRef >= 0); - - DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"), - m_dwCookie, m_cRef)); - if (lRef == 0) { - - // COM rules say we must protect against re-entrancy. - // If we are an aggregator and we hold our own interfaces - // on the aggregatee, the QI for these interfaces will - // addref ourselves. So after doing the QI we must release - // a ref count on ourselves. Then, before releasing the - // private interface, we must addref ourselves. When we do - // this from the destructor here it will result in the ref - // count going to 1 and then back to 0 causing us to - // re-enter the destructor. Hence we add an extra refcount here - // once we know we will delete the object. - // for an example aggregator see filgraph\distrib.cpp. - - m_cRef++; - - delete this; - return ULONG(0); - } else { - // Don't touch m_cRef again even in this leg as the object - // may have just been released on another thread too - return ourmax(ULONG(lRef), 1ul); - } -} - - -/* Return an interface pointer to a requesting client - performing a thread safe AddRef as necessary */ - -STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = pUnk; - pUnk->AddRef(); - return NOERROR; -} - - -/* Compares two interfaces and returns TRUE if they are on the same object */ - -BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond) -{ - /* Different objects can't have the same interface pointer for - any interface - */ - if (pFirst == pSecond) { - return TRUE; - } - /* OK - do it the hard way - check if they have the same - IUnknown pointers - a single object can only have one of these - */ - LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface - LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface - HRESULT hr; // General OLE return code - - ASSERT(pFirst); - ASSERT(pSecond); - - /* See if the IUnknown pointers match */ - - hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1); - if (FAILED(hr)) { - return FALSE; - } - ASSERT(pUnknown1); - - /* Release the extra interface we hold */ - - pUnknown1->Release(); - - hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2); - if (FAILED(hr)) { - return FALSE; - } - ASSERT(pUnknown2); - - /* Release the extra interface we hold */ - - pUnknown2->Release(); - return (pUnknown1 == pUnknown2); -} - +//------------------------------------------------------------------------------ +// File: ComBase.cpp +// +// Desc: DirectShow base classes - implements class hierarchy for creating +// COM objects. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions + + +/* Define the static member variable */ + +LONG CBaseObject::m_cObjects = 0; + + +/* Constructor */ + +CBaseObject::CBaseObject(__in_opt LPCTSTR pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef _DEBUG + +#ifdef UNICODE + m_dwCookie = DbgRegisterObjectCreation(0, pName); +#else + m_dwCookie = DbgRegisterObjectCreation(pName, 0); +#endif + +#endif +} + +#ifdef UNICODE +CBaseObject::CBaseObject(const char *pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef _DEBUG + m_dwCookie = DbgRegisterObjectCreation(pName, 0); +#endif +} +#endif + +HINSTANCE hlibOLEAut32; + +/* Destructor */ + +CBaseObject::~CBaseObject() +{ + /* Decrement the number of objects active */ + if (InterlockedDecrement(&m_cObjects) == 0) { + if (hlibOLEAut32) { + FreeLibrary(hlibOLEAut32); + + hlibOLEAut32 = 0; + } + }; + + +#ifdef _DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + +static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll"); + +HINSTANCE LoadOLEAut32() +{ + if (hlibOLEAut32 == 0) { + + hlibOLEAut32 = LoadLibrary(szOle32Aut); + } + + return hlibOLEAut32; +} + + +/* Constructor */ + +// We know we use "this" in the initialization list, we also know we don't modify *phr. +#pragma warning( disable : 4355 4100 ) +CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk) +: CBaseObject(pName) +/* Start the object with a reference count of zero - when the */ +/* object is queried for it's first interface this may be */ +/* incremented depending on whether or not this object is */ +/* currently being aggregated upon */ +, m_cRef(0) +/* Set our pointer to our IUnknown interface. */ +/* If we have an outer, use its, otherwise use ours. */ +/* This pointer effectivly points to the owner of */ +/* this object and can be accessed by the GetOwner() method. */ +, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) + /* Why the double cast? Well, the inner cast is a type-safe cast */ + /* to pointer to a type from which we inherit. The second is */ + /* type-unsafe but works because INonDelegatingUnknown "behaves */ + /* like" IUnknown. (Only the names on the methods change.) */ +{ + // Everything we need to do has been done in the initializer list +} + +// This does the same as above except it has a useless HRESULT argument +// use the previous constructor, this is just left for compatibility... +CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) : + CBaseObject(pName), + m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ +} + +#ifdef UNICODE +CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk) +: CBaseObject(pName), m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ } + +CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) : + CBaseObject(pName), m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ } + +#endif + +#pragma warning( default : 4355 4100 ) + + +/* QueryInterface */ + +STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + + /* We know only about IUnknown */ + + if (riid == IID_IUnknown) { + GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv); + return NOERROR; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +/* We have to ensure that we DON'T use a max macro, since these will typically */ +/* lead to one of the parameters being evaluated twice. Since we are worried */ +/* about concurrency, we can't afford to access the m_cRef twice since we can't */ +/* afford to run the risk that its value having changed between accesses. */ + +template inline static T ourmax( const T & a, const T & b ) +{ + return a > b ? a : b; +} + +/* AddRef */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef() +{ + LONG lRef = InterlockedIncrement( &m_cRef ); + ASSERT(lRef > 0); + UNREFERENCED_PARAMETER(lRef); + DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"), + m_dwCookie, m_cRef)); + return ourmax(ULONG(m_cRef), 1ul); +} + + +/* Release */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease() +{ + /* If the reference count drops to zero delete ourselves */ + + LONG lRef = InterlockedDecrement( &m_cRef ); + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"), + m_dwCookie, m_cRef)); + if (lRef == 0) { + + // COM rules say we must protect against re-entrancy. + // If we are an aggregator and we hold our own interfaces + // on the aggregatee, the QI for these interfaces will + // addref ourselves. So after doing the QI we must release + // a ref count on ourselves. Then, before releasing the + // private interface, we must addref ourselves. When we do + // this from the destructor here it will result in the ref + // count going to 1 and then back to 0 causing us to + // re-enter the destructor. Hence we add an extra refcount here + // once we know we will delete the object. + // for an example aggregator see filgraph\distrib.cpp. + + m_cRef++; + + delete this; + return ULONG(0); + } else { + // Don't touch m_cRef again even in this leg as the object + // may have just been released on another thread too + return ourmax(ULONG(lRef), 1ul); + } +} + + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = pUnk; + pUnk->AddRef(); + return NOERROR; +} + + +/* Compares two interfaces and returns TRUE if they are on the same object */ + +BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond) +{ + /* Different objects can't have the same interface pointer for + any interface + */ + if (pFirst == pSecond) { + return TRUE; + } + /* OK - do it the hard way - check if they have the same + IUnknown pointers - a single object can only have one of these + */ + LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface + LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface + HRESULT hr; // General OLE return code + + ASSERT(pFirst); + ASSERT(pSecond); + + /* See if the IUnknown pointers match */ + + hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1); + if (FAILED(hr)) { + return FALSE; + } + ASSERT(pUnknown1); + + /* Release the extra interface we hold */ + + pUnknown1->Release(); + + hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2); + if (FAILED(hr)) { + return FALSE; + } + ASSERT(pUnknown2); + + /* Release the extra interface we hold */ + + pUnknown2->Release(); + return (pUnknown1 == pUnknown2); +} + diff --git a/src/thirdparty/BaseClasses/combase.h b/src/thirdparty/BaseClasses/combase.h index d051bf92518..cf7907bdedb 100644 --- a/src/thirdparty/BaseClasses/combase.h +++ b/src/thirdparty/BaseClasses/combase.h @@ -1,315 +1,315 @@ -//------------------------------------------------------------------------------ -// File: ComBase.h -// -// Desc: DirectShow base classes - defines a class hierarchy for creating -// COM objects. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* - -a. Derive your COM object from CUnknown - -b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * - and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls - to. The HRESULT * allows error codes to be passed around constructors and - the TCHAR * is a descriptive name that can be printed on the debugger. - - It is important that constructors only change the HRESULT * if they have - to set an ERROR code, if it was successful then leave it alone or you may - overwrite an error code from an object previously created. - - When you call a constructor the descriptive name should be in static store - as we do not copy the string. To stop large amounts of memory being used - in retail builds by all these static strings use the NAME macro, - - CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); - if (FAILED(hr)) { - return hr; - } - - In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class - knows not to do anything with objects that don't have a name. - -c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and - TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an - error, or just simply pass it through to the constructor. - - The object creation will fail in the class factory if the HRESULT indicates - an error (ie FAILED(HRESULT) == TRUE) - -d. Create a FactoryTemplate with your object's class id and CreateInstance - function. - -Then (for each interface) either - -Multiple inheritance - -1. Also derive it from ISomeInterface -2. Include DECLARE_IUNKNOWN in your class definition to declare - implementations of QueryInterface, AddRef and Release that - call the outer unknown -3. Override NonDelegatingQueryInterface to expose ISomeInterface by - code something like - - if (riid == IID_ISomeInterface) { - return GetInterface((ISomeInterface *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -4. Declare and implement the member functions of ISomeInterface. - -or: Nested interfaces - -1. Declare a class derived from CUnknown -2. Include DECLARE_IUNKNOWN in your class definition -3. Override NonDelegatingQueryInterface to expose ISomeInterface by - code something like - - if (riid == IID_ISomeInterface) { - return GetInterface((ISomeInterface *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -4. Implement the member functions of ISomeInterface. Use GetOwner() to - access the COM object class. - -And in your COM object class: - -5. Make the nested class a friend of the COM object class, and declare - an instance of the nested class as a member of the COM object class. - - NOTE that because you must always pass the outer unknown and an hResult - to the CUnknown constructor you cannot use a default constructor, in - other words you will have to make the member variable a pointer to the - class and make a NEW call in your constructor to actually create it. - -6. override the NonDelegatingQueryInterface with code like this: - - if (riid == IID_ISomeInterface) { - return m_pImplFilter-> - NonDelegatingQueryInterface(IID_ISomeInterface, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -You can have mixed classes which support some interfaces via multiple -inheritance and some via nested classes - -*/ - -#ifndef __COMBASE__ -#define __COMBASE__ - -// Filter Setup data structures no defined in axextend.idl - -typedef REGPINTYPES -AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE; - -typedef REGFILTERPINS -AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN; - -// warning C4510: '_AMOVIESETUP_FILTER' : default constructor could not be generated, see declaration of '_AMOVIESETUP_FILTER' -// warning C4610: struct '_AMOVIESETUP_FILTER' can never be instantiated - user defined constructor required -// http://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx -// 'once' - Display the specified message(s) only one time. -// warning-specifier 'once' doesn't work -//#pragma warning( once : 4510 4610 ) -#pragma warning( push ) -#pragma warning( disable : 4510 4610 ) -typedef struct _AMOVIESETUP_FILTER -{ - const CLSID * clsID; - const WCHAR * strName; - DWORD dwMerit; - UINT nPins; - const AMOVIESETUP_PIN * lpPin; - const CLSID filterCategory; -} -AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER; -#pragma warning( pop ) - -/* The DLLENTRY module initializes the module handle on loading */ - -extern HINSTANCE g_hInst; - -/* On DLL load remember which platform we are running on */ - -extern DWORD g_amPlatform; -extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx - -/* Version of IUnknown that is renamed to allow a class to support both - non delegating and delegating IUnknowns in the same COM object */ - -#ifndef INONDELEGATINGUNKNOWN_DEFINED -DECLARE_INTERFACE(INonDelegatingUnknown) -{ - STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; - STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; -}; -#define INONDELEGATINGUNKNOWN_DEFINED -#endif - -typedef INonDelegatingUnknown *PNDUNKNOWN; - - -/* This is the base object class that supports active object counting. As - part of the debug facilities we trace every time a C++ object is created - or destroyed. The name of the object has to be passed up through the class - derivation list during construction as you cannot call virtual functions - in the constructor. The downside of all this is that every single object - constructor has to take an object name parameter that describes it */ - -class CBaseObject -{ - -private: - - // Disable the copy constructor and assignment by default so you will get - // compiler errors instead of unexpected behaviour if you pass objects - // by value or assign objects. - CBaseObject(const CBaseObject& objectSrc); // no implementation - void operator=(const CBaseObject& objectSrc); // no implementation - -private: - static LONG m_cObjects; /* Total number of objects active */ - -protected: -#ifdef _DEBUG - DWORD m_dwCookie; /* Cookie identifying this object */ -#endif - - -public: - - /* These increment and decrement the number of active objects */ - - CBaseObject(__in_opt LPCTSTR pName); -#ifdef UNICODE - CBaseObject(__in_opt LPCSTR pName); -#endif - ~CBaseObject(); - - /* Call this to find if there are any CUnknown derived objects active */ - - static LONG ObjectsActive() { - return m_cObjects; - }; -}; - - -/* An object that supports one or more COM interfaces will be based on - this class. It supports counting of total objects for DLLCanUnloadNow - support, and an implementation of the core non delegating IUnknown */ - -class AM_NOVTABLE CUnknown : public INonDelegatingUnknown, - public CBaseObject -{ -private: - const LPUNKNOWN m_pUnknown; /* Owner of this object */ - -protected: /* So we can override NonDelegatingRelease() */ - volatile LONG m_cRef; /* Number of reference counts */ - -public: - - CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk); - virtual ~CUnknown() {}; - - // This is redundant, just use the other constructor - // as we never touch the HRESULT in this anyway - CUnknown(__in_opt LPCTSTR Name, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr); -#ifdef UNICODE - CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk); - CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk,__inout_opt HRESULT *phr); -#endif - - /* Return the owner of this object */ - - LPUNKNOWN GetOwner() const { - return m_pUnknown; - }; - - /* Called from the class factory to create a new instance, it is - pure virtual so it must be overriden in your derived class */ - - /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ - - /* Non delegating unknown implementation */ - - STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **); - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); -}; - -/* Return an interface pointer to a requesting client - performing a thread safe AddRef as necessary */ - -STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv); - -/* A function that can create a new COM object */ - -typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(__in_opt LPUNKNOWN pUnkOuter, __inout_opt HRESULT *phr); - -/* A function (can be NULL) which is called from the DLL entrypoint - routine for each factory template: - - bLoading - TRUE on DLL load, FALSE on DLL unload - rclsid - the m_ClsID of the entry -*/ -typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); - -/* Create one of these per object class in an array so that - the default class factory code can create new instances */ - -class CFactoryTemplate { - -public: - - const WCHAR * m_Name; - const CLSID * m_ClsID; - LPFNNewCOMObject m_lpfnNew; - LPFNInitRoutine m_lpfnInit; - const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; - - BOOL IsClassID(REFCLSID rclsid) const { - return (IsEqualCLSID(*m_ClsID,rclsid)); - }; - - CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) const { - CheckPointer(phr,NULL); - return m_lpfnNew(pUnk, phr); - }; -}; - - -/* You must override the (pure virtual) NonDelegatingQueryInterface to return - interface pointers (using GetInterface) to the interfaces your derived - class supports (the default implementation only supports IUnknown) */ - -#define DECLARE_IUNKNOWN \ - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \ - return GetOwner()->QueryInterface(riid,ppv); \ - }; \ - STDMETHODIMP_(ULONG) AddRef() { \ - return GetOwner()->AddRef(); \ - }; \ - STDMETHODIMP_(ULONG) Release() { \ - return GetOwner()->Release(); \ - }; - - - -HINSTANCE LoadOLEAut32(); - - -#endif /* __COMBASE__ */ - - - - +//------------------------------------------------------------------------------ +// File: ComBase.h +// +// Desc: DirectShow base classes - defines a class hierarchy for creating +// COM objects. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* + +a. Derive your COM object from CUnknown + +b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * + and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls + to. The HRESULT * allows error codes to be passed around constructors and + the TCHAR * is a descriptive name that can be printed on the debugger. + + It is important that constructors only change the HRESULT * if they have + to set an ERROR code, if it was successful then leave it alone or you may + overwrite an error code from an object previously created. + + When you call a constructor the descriptive name should be in static store + as we do not copy the string. To stop large amounts of memory being used + in retail builds by all these static strings use the NAME macro, + + CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); + if (FAILED(hr)) { + return hr; + } + + In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class + knows not to do anything with objects that don't have a name. + +c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and + TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an + error, or just simply pass it through to the constructor. + + The object creation will fail in the class factory if the HRESULT indicates + an error (ie FAILED(HRESULT) == TRUE) + +d. Create a FactoryTemplate with your object's class id and CreateInstance + function. + +Then (for each interface) either + +Multiple inheritance + +1. Also derive it from ISomeInterface +2. Include DECLARE_IUNKNOWN in your class definition to declare + implementations of QueryInterface, AddRef and Release that + call the outer unknown +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Declare and implement the member functions of ISomeInterface. + +or: Nested interfaces + +1. Declare a class derived from CUnknown +2. Include DECLARE_IUNKNOWN in your class definition +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Implement the member functions of ISomeInterface. Use GetOwner() to + access the COM object class. + +And in your COM object class: + +5. Make the nested class a friend of the COM object class, and declare + an instance of the nested class as a member of the COM object class. + + NOTE that because you must always pass the outer unknown and an hResult + to the CUnknown constructor you cannot use a default constructor, in + other words you will have to make the member variable a pointer to the + class and make a NEW call in your constructor to actually create it. + +6. override the NonDelegatingQueryInterface with code like this: + + if (riid == IID_ISomeInterface) { + return m_pImplFilter-> + NonDelegatingQueryInterface(IID_ISomeInterface, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +You can have mixed classes which support some interfaces via multiple +inheritance and some via nested classes + +*/ + +#ifndef __COMBASE__ +#define __COMBASE__ + +// Filter Setup data structures no defined in axextend.idl + +typedef REGPINTYPES +AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE; + +typedef REGFILTERPINS +AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN; + +// warning C4510: '_AMOVIESETUP_FILTER' : default constructor could not be generated, see declaration of '_AMOVIESETUP_FILTER' +// warning C4610: struct '_AMOVIESETUP_FILTER' can never be instantiated - user defined constructor required +// http://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx +// 'once' - Display the specified message(s) only one time. +// warning-specifier 'once' doesn't work +//#pragma warning( once : 4510 4610 ) +#pragma warning( push ) +#pragma warning( disable : 4510 4610 ) +typedef struct _AMOVIESETUP_FILTER +{ + const CLSID * clsID; + const WCHAR * strName; + DWORD dwMerit; + UINT nPins; + const AMOVIESETUP_PIN * lpPin; + const CLSID filterCategory; +} +AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER; +#pragma warning( pop ) + +/* The DLLENTRY module initializes the module handle on loading */ + +extern HINSTANCE g_hInst; + +/* On DLL load remember which platform we are running on */ + +extern DWORD g_amPlatform; +extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx + +/* Version of IUnknown that is renamed to allow a class to support both + non delegating and delegating IUnknowns in the same COM object */ + +#ifndef INONDELEGATINGUNKNOWN_DEFINED +DECLARE_INTERFACE(INonDelegatingUnknown) +{ + STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; + STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; +}; +#define INONDELEGATINGUNKNOWN_DEFINED +#endif + +typedef INonDelegatingUnknown *PNDUNKNOWN; + + +/* This is the base object class that supports active object counting. As + part of the debug facilities we trace every time a C++ object is created + or destroyed. The name of the object has to be passed up through the class + derivation list during construction as you cannot call virtual functions + in the constructor. The downside of all this is that every single object + constructor has to take an object name parameter that describes it */ + +class CBaseObject +{ + +private: + + // Disable the copy constructor and assignment by default so you will get + // compiler errors instead of unexpected behaviour if you pass objects + // by value or assign objects. + CBaseObject(const CBaseObject& objectSrc); // no implementation + void operator=(const CBaseObject& objectSrc); // no implementation + +private: + static LONG m_cObjects; /* Total number of objects active */ + +protected: +#ifdef _DEBUG + DWORD m_dwCookie; /* Cookie identifying this object */ +#endif + + +public: + + /* These increment and decrement the number of active objects */ + + CBaseObject(__in_opt LPCTSTR pName); +#ifdef UNICODE + CBaseObject(__in_opt LPCSTR pName); +#endif + ~CBaseObject(); + + /* Call this to find if there are any CUnknown derived objects active */ + + static LONG ObjectsActive() { + return m_cObjects; + }; +}; + + +/* An object that supports one or more COM interfaces will be based on + this class. It supports counting of total objects for DLLCanUnloadNow + support, and an implementation of the core non delegating IUnknown */ + +class AM_NOVTABLE CUnknown : public INonDelegatingUnknown, + public CBaseObject +{ +private: + const LPUNKNOWN m_pUnknown; /* Owner of this object */ + +protected: /* So we can override NonDelegatingRelease() */ + volatile LONG m_cRef; /* Number of reference counts */ + +public: + + CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk); + virtual ~CUnknown() {}; + + // This is redundant, just use the other constructor + // as we never touch the HRESULT in this anyway + CUnknown(__in_opt LPCTSTR Name, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr); +#ifdef UNICODE + CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk); + CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk,__inout_opt HRESULT *phr); +#endif + + /* Return the owner of this object */ + + LPUNKNOWN GetOwner() const { + return m_pUnknown; + }; + + /* Called from the class factory to create a new instance, it is + pure virtual so it must be overriden in your derived class */ + + /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ + + /* Non delegating unknown implementation */ + + STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); +}; + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv); + +/* A function that can create a new COM object */ + +typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(__in_opt LPUNKNOWN pUnkOuter, __inout_opt HRESULT *phr); + +/* A function (can be NULL) which is called from the DLL entrypoint + routine for each factory template: + + bLoading - TRUE on DLL load, FALSE on DLL unload + rclsid - the m_ClsID of the entry +*/ +typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); + +/* Create one of these per object class in an array so that + the default class factory code can create new instances */ + +class CFactoryTemplate { + +public: + + const WCHAR * m_Name; + const CLSID * m_ClsID; + LPFNNewCOMObject m_lpfnNew; + LPFNInitRoutine m_lpfnInit; + const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; + + BOOL IsClassID(REFCLSID rclsid) const { + return (IsEqualCLSID(*m_ClsID,rclsid)); + }; + + CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) const { + CheckPointer(phr,NULL); + return m_lpfnNew(pUnk, phr); + }; +}; + + +/* You must override the (pure virtual) NonDelegatingQueryInterface to return + interface pointers (using GetInterface) to the interfaces your derived + class supports (the default implementation only supports IUnknown) */ + +#define DECLARE_IUNKNOWN \ + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \ + return GetOwner()->QueryInterface(riid,ppv); \ + }; \ + STDMETHODIMP_(ULONG) AddRef() { \ + return GetOwner()->AddRef(); \ + }; \ + STDMETHODIMP_(ULONG) Release() { \ + return GetOwner()->Release(); \ + }; + + + +HINSTANCE LoadOLEAut32(); + + +#endif /* __COMBASE__ */ + + + + diff --git a/src/thirdparty/BaseClasses/cprop.cpp b/src/thirdparty/BaseClasses/cprop.cpp index 58bf8654dc7..08993b01c21 100644 --- a/src/thirdparty/BaseClasses/cprop.cpp +++ b/src/thirdparty/BaseClasses/cprop.cpp @@ -1,384 +1,384 @@ -//------------------------------------------------------------------------------ -// File: CProp.cpp -// -// Desc: DirectShow base classes - implements CBasePropertyPage class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - -// Constructor for the base property page class. As described in the header -// file we must be initialised with dialog and title resource identifiers. -// The class supports IPropertyPage and overrides AddRef and Release calls -// to keep track of the reference counts. When the last count is released -// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces -// previously obtained by the property page when it had SetObjects called - -CBasePropertyPage::CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name - __inout_opt LPUNKNOWN pUnk, // COM Delegator - int DialogId, // Resource ID - int TitleId) : // To get tital - CUnknown(pName,pUnk), - m_DialogId(DialogId), - m_TitleId(TitleId), - m_hwnd(NULL), - m_Dlg(NULL), - m_pPageSite(NULL), - m_bObjectSet(FALSE), - m_bDirty(FALSE) -{ -} - -#ifdef UNICODE -CBasePropertyPage::CBasePropertyPage(__in_opt LPCSTR pName, // Debug only name - __inout_opt LPUNKNOWN pUnk, // COM Delegator - int DialogId, // Resource ID - int TitleId) : // To get tital - CUnknown(pName,pUnk), - m_DialogId(DialogId), - m_TitleId(TitleId), - m_hwnd(NULL), - m_Dlg(NULL), - m_pPageSite(NULL), - m_bObjectSet(FALSE), - m_bDirty(FALSE) -{ -} -#endif - -// Increment our reference count - -STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef() -{ - LONG lRef = InterlockedIncrement(&m_cRef); - ASSERT(lRef > 0); - UNREFERENCED_PARAMETER(lRef); - return std::max(ULONG(m_cRef),1ul); -} - - -// Release a reference count and protect against reentrancy - -STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease() -{ - // If the reference count drops to zero delete ourselves - - LONG lRef = InterlockedDecrement(&m_cRef); - if (lRef == 0) { - m_cRef++; - SetPageSite(NULL); - SetObjects(0,NULL); - delete this; - return ULONG(0); - } else { - // Don't touch m_cRef again here! - return std::max(ULONG(lRef),1ul); - } -} - - -// Expose our IPropertyPage interface - -STDMETHODIMP -CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) -{ - if (riid == IID_IPropertyPage) { - return GetInterface((IPropertyPage *)this,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid,ppv); - } -} - - -// Get the page info so that the page site can size itself - -STDMETHODIMP CBasePropertyPage::GetPageInfo(__out LPPROPPAGEINFO pPageInfo) -{ - CheckPointer(pPageInfo,E_POINTER); - WCHAR wszTitle[STR_MAX_LENGTH]; - WideStringFromResource(wszTitle,m_TitleId); - - // Allocate dynamic memory for the property page title - - LPOLESTR pszTitle; - HRESULT hr = AMGetWideString(wszTitle, &pszTitle); - if (FAILED(hr)) { - NOTE("No caption memory"); - return hr; - } - - pPageInfo->cb = sizeof(PROPPAGEINFO); - pPageInfo->pszTitle = pszTitle; - pPageInfo->pszDocString = NULL; - pPageInfo->pszHelpFile = NULL; - pPageInfo->dwHelpContext = 0; - - // Set defaults in case GetDialogSize fails - pPageInfo->size.cx = 340; - pPageInfo->size.cy = 150; - - GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size); - return NOERROR; -} - - -// Handles the messages for our property window - -INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - CBasePropertyPage *pPropertyPage; - - switch (uMsg) { - - case WM_INITDIALOG: - - SetWindowLongPtr(hwnd, DWLP_USER, lParam); - - // This pointer may be NULL when calculating size - - pPropertyPage = (CBasePropertyPage *) lParam; - if (pPropertyPage == NULL) { - return (LRESULT) 1; - } - pPropertyPage->m_Dlg = hwnd; - } - - // This pointer may be NULL when calculating size - - pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); - if (pPropertyPage == NULL) { - return (LRESULT) 1; - } - return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam); -} - - -// Tells us the object that should be informed of the property changes - -STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,__in_ecount_opt(cObjects) LPUNKNOWN *ppUnk) -{ - if (cObjects == 1) { - - if ((ppUnk == NULL) || (*ppUnk == NULL)) { - return E_POINTER; - } - - // Set a flag to say that we have set the Object - m_bObjectSet = TRUE ; - return OnConnect(*ppUnk); - - } else if (cObjects == 0) { - - // Set a flag to say that we have not set the Object for the page - m_bObjectSet = FALSE ; - return OnDisconnect(); - } - - DbgBreak("No support for more than one object"); - return E_UNEXPECTED; -} - - -// Create the window we will use to edit properties - -STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent, - LPCRECT pRect, - BOOL fModal) -{ - CheckPointer(pRect,E_POINTER); - - // Return failure if SetObject has not been called. - if (m_bObjectSet == FALSE) { - return E_UNEXPECTED; - } - - if (m_hwnd) { - return E_UNEXPECTED; - } - - m_hwnd = CreateDialogParam(g_hInst, - MAKEINTRESOURCE(m_DialogId), - hwndParent, - DialogProc, - (LPARAM) this); - if (m_hwnd == NULL) { - return E_OUTOFMEMORY; - } - - OnActivate(); - Move(pRect); - return Show(SW_SHOWNORMAL); -} - - -// Set the position of the property page - -STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect) -{ - CheckPointer(pRect,E_POINTER); - - if (m_hwnd == NULL) { - return E_UNEXPECTED; - } - - MoveWindow(m_hwnd, // Property page handle - pRect->left, // x coordinate - pRect->top, // y coordinate - WIDTH(pRect), // Overall window width - HEIGHT(pRect), // And likewise height - TRUE); // Should we repaint it - - return NOERROR; -} - - -// Display the property dialog - -STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow) -{ - // Have we been activated yet - - if (m_hwnd == NULL) { - return E_UNEXPECTED; - } - - // Ignore wrong show flags - - if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { - return E_INVALIDARG; - } - - ShowWindow(m_hwnd,nCmdShow); - InvalidateRect(m_hwnd,NULL,TRUE); - return NOERROR; -} - - -// Destroy the property page dialog - -STDMETHODIMP CBasePropertyPage::Deactivate(void) -{ - if (m_hwnd == NULL) { - return E_UNEXPECTED; - } - - // Remove WS_EX_CONTROLPARENT before DestroyWindow call - - DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE); - dwStyle = dwStyle & (~WS_EX_CONTROLPARENT); - - // Set m_hwnd to be NULL temporarily so the message handler - // for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT - // style back in - HWND hwnd = m_hwnd; - m_hwnd = NULL; - SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle); - m_hwnd = hwnd; - - OnDeactivate(); - - // Destroy the dialog window - - DestroyWindow(m_hwnd); - m_hwnd = NULL; - return NOERROR; -} - - -// Tells the application property page site - -STDMETHODIMP CBasePropertyPage::SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite) -{ - if (pPageSite) { - - if (m_pPageSite) { - return E_UNEXPECTED; - } - - m_pPageSite = pPageSite; - m_pPageSite->AddRef(); - - } else { - - if (m_pPageSite == NULL) { - return E_UNEXPECTED; - } - - m_pPageSite->Release(); - m_pPageSite = NULL; - } - return NOERROR; -} - - -// Apply any changes so far made - -STDMETHODIMP CBasePropertyPage::Apply() -{ - // In ActiveMovie 1.0 we used to check whether we had been activated or - // not. This is too constrictive. Apply should be allowed as long as - // SetObject was called to set an object. So we will no longer check to - // see if we have been activated (ie., m_hWnd != NULL), but instead - // make sure that m_bObjectSet is TRUE (ie., SetObject has been called). - - if (m_bObjectSet == FALSE) { - return E_UNEXPECTED; - } - - // Must have had a site set - - if (m_pPageSite == NULL) { - return E_UNEXPECTED; - } - - // Has anything changed - - if (m_bDirty == FALSE) { - return NOERROR; - } - - // Commit derived class changes - - HRESULT hr = OnApplyChanges(); - if (SUCCEEDED(hr)) { - m_bDirty = FALSE; - } - return hr; -} - - -// Base class definition for message handling - -INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) -{ - // we would like the TAB key to move around the tab stops in our property - // page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT - // style behind our back, so we need to switch it back on now behind its - // back. Otherwise the tab key will be useless in every page. - // - - CBasePropertyPage *pPropertyPage; - { - pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); - - if (pPropertyPage->m_hwnd == NULL) { - return 0; - } - switch (uMsg) { - case WM_STYLECHANGING: - if (wParam == GWL_EXSTYLE) { - LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam; - lpss->styleNew |= WS_EX_CONTROLPARENT; - return 0; - } - } - } - - return DefWindowProc(hwnd,uMsg,wParam,lParam); -} - +//------------------------------------------------------------------------------ +// File: CProp.cpp +// +// Desc: DirectShow base classes - implements CBasePropertyPage class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + +// Constructor for the base property page class. As described in the header +// file we must be initialised with dialog and title resource identifiers. +// The class supports IPropertyPage and overrides AddRef and Release calls +// to keep track of the reference counts. When the last count is released +// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces +// previously obtained by the property page when it had SetObjects called + +CBasePropertyPage::CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name + __inout_opt LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId) : // To get tital + CUnknown(pName,pUnk), + m_DialogId(DialogId), + m_TitleId(TitleId), + m_hwnd(NULL), + m_Dlg(NULL), + m_pPageSite(NULL), + m_bObjectSet(FALSE), + m_bDirty(FALSE) +{ +} + +#ifdef UNICODE +CBasePropertyPage::CBasePropertyPage(__in_opt LPCSTR pName, // Debug only name + __inout_opt LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId) : // To get tital + CUnknown(pName,pUnk), + m_DialogId(DialogId), + m_TitleId(TitleId), + m_hwnd(NULL), + m_Dlg(NULL), + m_pPageSite(NULL), + m_bObjectSet(FALSE), + m_bDirty(FALSE) +{ +} +#endif + +// Increment our reference count + +STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef() +{ + LONG lRef = InterlockedIncrement(&m_cRef); + ASSERT(lRef > 0); + UNREFERENCED_PARAMETER(lRef); + return std::max(ULONG(m_cRef),1ul); +} + + +// Release a reference count and protect against reentrancy + +STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease() +{ + // If the reference count drops to zero delete ourselves + + LONG lRef = InterlockedDecrement(&m_cRef); + if (lRef == 0) { + m_cRef++; + SetPageSite(NULL); + SetObjects(0,NULL); + delete this; + return ULONG(0); + } else { + // Don't touch m_cRef again here! + return std::max(ULONG(lRef),1ul); + } +} + + +// Expose our IPropertyPage interface + +STDMETHODIMP +CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) +{ + if (riid == IID_IPropertyPage) { + return GetInterface((IPropertyPage *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +// Get the page info so that the page site can size itself + +STDMETHODIMP CBasePropertyPage::GetPageInfo(__out LPPROPPAGEINFO pPageInfo) +{ + CheckPointer(pPageInfo,E_POINTER); + WCHAR wszTitle[STR_MAX_LENGTH]; + WideStringFromResource(wszTitle,m_TitleId); + + // Allocate dynamic memory for the property page title + + LPOLESTR pszTitle; + HRESULT hr = AMGetWideString(wszTitle, &pszTitle); + if (FAILED(hr)) { + NOTE("No caption memory"); + return hr; + } + + pPageInfo->cb = sizeof(PROPPAGEINFO); + pPageInfo->pszTitle = pszTitle; + pPageInfo->pszDocString = NULL; + pPageInfo->pszHelpFile = NULL; + pPageInfo->dwHelpContext = 0; + + // Set defaults in case GetDialogSize fails + pPageInfo->size.cx = 340; + pPageInfo->size.cy = 150; + + GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size); + return NOERROR; +} + + +// Handles the messages for our property window + +INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + CBasePropertyPage *pPropertyPage; + + switch (uMsg) { + + case WM_INITDIALOG: + + SetWindowLongPtr(hwnd, DWLP_USER, lParam); + + // This pointer may be NULL when calculating size + + pPropertyPage = (CBasePropertyPage *) lParam; + if (pPropertyPage == NULL) { + return (LRESULT) 1; + } + pPropertyPage->m_Dlg = hwnd; + } + + // This pointer may be NULL when calculating size + + pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); + if (pPropertyPage == NULL) { + return (LRESULT) 1; + } + return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam); +} + + +// Tells us the object that should be informed of the property changes + +STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,__in_ecount_opt(cObjects) LPUNKNOWN *ppUnk) +{ + if (cObjects == 1) { + + if ((ppUnk == NULL) || (*ppUnk == NULL)) { + return E_POINTER; + } + + // Set a flag to say that we have set the Object + m_bObjectSet = TRUE ; + return OnConnect(*ppUnk); + + } else if (cObjects == 0) { + + // Set a flag to say that we have not set the Object for the page + m_bObjectSet = FALSE ; + return OnDisconnect(); + } + + DbgBreak("No support for more than one object"); + return E_UNEXPECTED; +} + + +// Create the window we will use to edit properties + +STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent, + LPCRECT pRect, + BOOL fModal) +{ + CheckPointer(pRect,E_POINTER); + + // Return failure if SetObject has not been called. + if (m_bObjectSet == FALSE) { + return E_UNEXPECTED; + } + + if (m_hwnd) { + return E_UNEXPECTED; + } + + m_hwnd = CreateDialogParam(g_hInst, + MAKEINTRESOURCE(m_DialogId), + hwndParent, + DialogProc, + (LPARAM) this); + if (m_hwnd == NULL) { + return E_OUTOFMEMORY; + } + + OnActivate(); + Move(pRect); + return Show(SW_SHOWNORMAL); +} + + +// Set the position of the property page + +STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect) +{ + CheckPointer(pRect,E_POINTER); + + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + MoveWindow(m_hwnd, // Property page handle + pRect->left, // x coordinate + pRect->top, // y coordinate + WIDTH(pRect), // Overall window width + HEIGHT(pRect), // And likewise height + TRUE); // Should we repaint it + + return NOERROR; +} + + +// Display the property dialog + +STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow) +{ + // Have we been activated yet + + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + // Ignore wrong show flags + + if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { + return E_INVALIDARG; + } + + ShowWindow(m_hwnd,nCmdShow); + InvalidateRect(m_hwnd,NULL,TRUE); + return NOERROR; +} + + +// Destroy the property page dialog + +STDMETHODIMP CBasePropertyPage::Deactivate(void) +{ + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + // Remove WS_EX_CONTROLPARENT before DestroyWindow call + + DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE); + dwStyle = dwStyle & (~WS_EX_CONTROLPARENT); + + // Set m_hwnd to be NULL temporarily so the message handler + // for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT + // style back in + HWND hwnd = m_hwnd; + m_hwnd = NULL; + SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle); + m_hwnd = hwnd; + + OnDeactivate(); + + // Destroy the dialog window + + DestroyWindow(m_hwnd); + m_hwnd = NULL; + return NOERROR; +} + + +// Tells the application property page site + +STDMETHODIMP CBasePropertyPage::SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite) +{ + if (pPageSite) { + + if (m_pPageSite) { + return E_UNEXPECTED; + } + + m_pPageSite = pPageSite; + m_pPageSite->AddRef(); + + } else { + + if (m_pPageSite == NULL) { + return E_UNEXPECTED; + } + + m_pPageSite->Release(); + m_pPageSite = NULL; + } + return NOERROR; +} + + +// Apply any changes so far made + +STDMETHODIMP CBasePropertyPage::Apply() +{ + // In ActiveMovie 1.0 we used to check whether we had been activated or + // not. This is too constrictive. Apply should be allowed as long as + // SetObject was called to set an object. So we will no longer check to + // see if we have been activated (ie., m_hWnd != NULL), but instead + // make sure that m_bObjectSet is TRUE (ie., SetObject has been called). + + if (m_bObjectSet == FALSE) { + return E_UNEXPECTED; + } + + // Must have had a site set + + if (m_pPageSite == NULL) { + return E_UNEXPECTED; + } + + // Has anything changed + + if (m_bDirty == FALSE) { + return NOERROR; + } + + // Commit derived class changes + + HRESULT hr = OnApplyChanges(); + if (SUCCEEDED(hr)) { + m_bDirty = FALSE; + } + return hr; +} + + +// Base class definition for message handling + +INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + // we would like the TAB key to move around the tab stops in our property + // page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT + // style behind our back, so we need to switch it back on now behind its + // back. Otherwise the tab key will be useless in every page. + // + + CBasePropertyPage *pPropertyPage; + { + pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); + + if (pPropertyPage->m_hwnd == NULL) { + return 0; + } + switch (uMsg) { + case WM_STYLECHANGING: + if (wParam == GWL_EXSTYLE) { + LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam; + lpss->styleNew |= WS_EX_CONTROLPARENT; + return 0; + } + } + } + + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + diff --git a/src/thirdparty/BaseClasses/cprop.h b/src/thirdparty/BaseClasses/cprop.h index db4494067ef..a030f8ff077 100644 --- a/src/thirdparty/BaseClasses/cprop.h +++ b/src/thirdparty/BaseClasses/cprop.h @@ -1,95 +1,95 @@ -//------------------------------------------------------------------------------ -// File: CProp.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __CPROP__ -#define __CPROP__ - -// Base property page class. Filters typically expose custom properties by -// implementing special control interfaces, examples are IDirectDrawVideo -// and IQualProp on renderers. This allows property pages to be built that -// use the given interface. Applications such as the ActiveMovie OCX query -// filters for the property pages they support and expose them to the user -// -// This class provides all the framework for a property page. A property -// page is a COM object that supports IPropertyPage. We should be created -// with a resource ID for the dialog which we will load when required. We -// should also be given in the constructor a resource ID for a title string -// we will load from the DLLs STRINGTABLE. The property page titles must be -// stored in resource files so that they can be easily internationalised -// -// We have a number of virtual methods (not PURE) that may be overriden in -// derived classes to query for interfaces and so on. These functions have -// simple implementations here that just return NOERROR. Derived classes -// will almost definately have to override the message handler method called -// OnReceiveMessage. We have a static dialog procedure that calls the method -// so that derived classes don't have to fiddle around with the this pointer - -class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown -{ -protected: - - LPPROPERTYPAGESITE m_pPageSite; // Details for our property site - HWND m_hwnd; // Window handle for the page - HWND m_Dlg; // Actual dialog window handle - BOOL m_bDirty; // Has anything been changed - int m_TitleId; // Resource identifier for title - int m_DialogId; // Dialog resource identifier - - static INT_PTR CALLBACK DialogProc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -private: - BOOL m_bObjectSet ; // SetObject has been called or not. -public: - - CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name - __inout_opt LPUNKNOWN pUnk, // COM Delegator - int DialogId, // Resource ID - int TitleId); // To get tital - -#ifdef UNICODE - CBasePropertyPage(__in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - int DialogId, - int TitleId); -#endif - virtual ~CBasePropertyPage() { }; - DECLARE_IUNKNOWN - - // Override these virtual methods - - virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; }; - virtual HRESULT OnDisconnect() { return NOERROR; }; - virtual HRESULT OnActivate() { return NOERROR; }; - virtual HRESULT OnDeactivate() { return NOERROR; }; - virtual HRESULT OnApplyChanges() { return NOERROR; }; - virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - - // These implement an IPropertyPage interface - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite); - STDMETHODIMP Activate(HWND hwndParent, LPCRECT prect,BOOL fModal); - STDMETHODIMP Deactivate(void); - STDMETHODIMP GetPageInfo(__out LPPROPPAGEINFO pPageInfo); - STDMETHODIMP SetObjects(ULONG cObjects, __in_ecount_opt(cObjects) LPUNKNOWN *ppUnk); - STDMETHODIMP Show(UINT nCmdShow); - STDMETHODIMP Move(LPCRECT prect); - STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; } - STDMETHODIMP Apply(void); - STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; } - STDMETHODIMP TranslateAccelerator(__inout LPMSG lpMsg) { return E_NOTIMPL; } -}; - -#endif // __CPROP__ - +//------------------------------------------------------------------------------ +// File: CProp.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CPROP__ +#define __CPROP__ + +// Base property page class. Filters typically expose custom properties by +// implementing special control interfaces, examples are IDirectDrawVideo +// and IQualProp on renderers. This allows property pages to be built that +// use the given interface. Applications such as the ActiveMovie OCX query +// filters for the property pages they support and expose them to the user +// +// This class provides all the framework for a property page. A property +// page is a COM object that supports IPropertyPage. We should be created +// with a resource ID for the dialog which we will load when required. We +// should also be given in the constructor a resource ID for a title string +// we will load from the DLLs STRINGTABLE. The property page titles must be +// stored in resource files so that they can be easily internationalised +// +// We have a number of virtual methods (not PURE) that may be overriden in +// derived classes to query for interfaces and so on. These functions have +// simple implementations here that just return NOERROR. Derived classes +// will almost definately have to override the message handler method called +// OnReceiveMessage. We have a static dialog procedure that calls the method +// so that derived classes don't have to fiddle around with the this pointer + +class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown +{ +protected: + + LPPROPERTYPAGESITE m_pPageSite; // Details for our property site + HWND m_hwnd; // Window handle for the page + HWND m_Dlg; // Actual dialog window handle + BOOL m_bDirty; // Has anything been changed + int m_TitleId; // Resource identifier for title + int m_DialogId; // Dialog resource identifier + + static INT_PTR CALLBACK DialogProc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +private: + BOOL m_bObjectSet ; // SetObject has been called or not. +public: + + CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name + __inout_opt LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId); // To get tital + +#ifdef UNICODE + CBasePropertyPage(__in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + int DialogId, + int TitleId); +#endif + virtual ~CBasePropertyPage() { }; + DECLARE_IUNKNOWN + + // Override these virtual methods + + virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; }; + virtual HRESULT OnDisconnect() { return NOERROR; }; + virtual HRESULT OnActivate() { return NOERROR; }; + virtual HRESULT OnDeactivate() { return NOERROR; }; + virtual HRESULT OnApplyChanges() { return NOERROR; }; + virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + + // These implement an IPropertyPage interface + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite); + STDMETHODIMP Activate(HWND hwndParent, LPCRECT prect,BOOL fModal); + STDMETHODIMP Deactivate(void); + STDMETHODIMP GetPageInfo(__out LPPROPPAGEINFO pPageInfo); + STDMETHODIMP SetObjects(ULONG cObjects, __in_ecount_opt(cObjects) LPUNKNOWN *ppUnk); + STDMETHODIMP Show(UINT nCmdShow); + STDMETHODIMP Move(LPCRECT prect); + STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; } + STDMETHODIMP Apply(void); + STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; } + STDMETHODIMP TranslateAccelerator(__inout LPMSG lpMsg) { return E_NOTIMPL; } +}; + +#endif // __CPROP__ + diff --git a/src/thirdparty/BaseClasses/ctlutil.cpp b/src/thirdparty/BaseClasses/ctlutil.cpp index 04870767d2b..07cb089cb05 100644 --- a/src/thirdparty/BaseClasses/ctlutil.cpp +++ b/src/thirdparty/BaseClasses/ctlutil.cpp @@ -1,2539 +1,2539 @@ -//------------------------------------------------------------------------------ -// File: CtlUtil.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Base classes implementing IDispatch parsing for the basic control dual -// interfaces. Derive from these and implement just the custom method and -// property methods. We also implement CPosPassThru that can be used by -// renderers and transforms to pass by IMediaPosition and IMediaSeeking - - -#include "streams.h" -#include -#include "seekpt.h" - -// 'bool' non standard reserved word -#pragma warning(disable:4237) - - -// --- CBaseDispatch implementation ---------- -CBaseDispatch::~CBaseDispatch() -{ - if (m_pti) { - m_pti->Release(); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CBaseDispatch::GetTypeInfoCount(__out UINT * pctinfo) -{ - CheckPointer(pctinfo,E_POINTER); - ValidateReadWritePtr(pctinfo,sizeof(UINT *)); - *pctinfo = 1; - return S_OK; -} - - -typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)( - const OLECHAR FAR *szFile, - __deref_out ITypeLib FAR* FAR* pptlib); - -typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid, - WORD wVerMajor, - WORD wVerMinor, - LCID lcid, - __deref_out ITypeLib FAR* FAR* pptlib); - -// attempt to find our type library - -STDMETHODIMP -CBaseDispatch::GetTypeInfo( - REFIID riid, - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - CheckPointer(pptinfo,E_POINTER); - ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *)); - HRESULT hr; - - *pptinfo = NULL; - - // we only support one type element - if (0 != itinfo) { - return TYPE_E_ELEMENTNOTFOUND; - } - - // always look for neutral - if (NULL == m_pti) { - - LPLOADTYPELIB lpfnLoadTypeLib; - LPLOADREGTYPELIB lpfnLoadRegTypeLib; - ITypeLib *ptlib; - HINSTANCE hInst; - - static const char szTypeLib[] = "LoadTypeLib"; - static const char szRegTypeLib[] = "LoadRegTypeLib"; - static const WCHAR szControl[] = L"control.tlb"; - - // - // Try to get the Ole32Aut.dll module handle. - // - - hInst = LoadOLEAut32(); - if (hInst == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst, - szRegTypeLib); - if (lpfnLoadRegTypeLib == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - - hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0 - lcid, &ptlib); - - if (FAILED(hr)) { - - // attempt to load directly - this will fill the - // registry in if it finds it - - lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib); - if (lpfnLoadTypeLib == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - - hr = (*lpfnLoadTypeLib)(szControl, &ptlib); - if (FAILED(hr)) { - return hr; - } - } - - hr = ptlib->GetTypeInfoOfGuid( - riid, - &m_pti); - - ptlib->Release(); - - if (FAILED(hr)) { - return hr; - } - } - - *pptinfo = m_pti; - m_pti->AddRef(); - return S_OK; -} - - -STDMETHODIMP -CBaseDispatch::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - // although the IDispatch riid is dead, we use this to pass from - // the interface implementation class to us the iid we are talking about. - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti); - - if (SUCCEEDED(hr)) { - hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid); - - pti->Release(); - } - return hr; -} - - -// --- CMediaControl implementation --------- - -CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - -// expose our interfaces IMediaControl and IUnknown - -STDMETHODIMP -CMediaControl::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaControl) { - return GetInterface( (IMediaControl *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaControl::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaControl::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaControl, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaControl::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaControl, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaControl::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaControl *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- CMediaEvent implementation ---------- - - -CMediaEvent::CMediaEvent(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - - -// expose our interfaces IMediaEvent and IUnknown - -STDMETHODIMP -CMediaEvent::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) { - return GetInterface( (IMediaEventEx *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaEvent::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaEvent::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaEvent, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaEvent::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaEvent, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaEvent::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaEvent *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- CMediaPosition implementation ---------- - - -CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - -CMediaPosition::CMediaPosition(__in_opt LPCTSTR name, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT * phr) : - CUnknown(name, pUnk) -{ - UNREFERENCED_PARAMETER(phr); -} - - -// expose our interfaces IMediaPosition and IUnknown - -STDMETHODIMP -CMediaPosition::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaPosition) { - return GetInterface( (IMediaPosition *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaPosition::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaPosition::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaPosition, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaPosition::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaPosition, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaPosition::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaPosition *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IMediaPosition and IMediaSeeking pass through class ---------- - - -CPosPassThru::CPosPassThru(__in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - IPin *pPin) : - CMediaPosition(pName,pUnk), - m_pPin(pPin) -{ - if (pPin == NULL) { - *phr = E_POINTER; - return; - } -} - - -// Expose our IMediaSeeking and IMediaPosition interfaces - -STDMETHODIMP -CPosPassThru::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) -{ - CheckPointer(ppv,E_POINTER); - *ppv = NULL; - - if (riid == IID_IMediaSeeking) { - return GetInterface( static_cast(this), ppv); - } - return CMediaPosition::NonDelegatingQueryInterface(riid,ppv); -} - - -// Return the IMediaPosition interface from our peer - -HRESULT -CPosPassThru::GetPeer(IMediaPosition ** ppMP) -{ - *ppMP = NULL; - - IPin *pConnected; - HRESULT hr = m_pPin->ConnectedTo(&pConnected); - if (FAILED(hr)) { - return E_NOTIMPL; - } - IMediaPosition * pMP; - hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP); - pConnected->Release(); - if (FAILED(hr)) { - return E_NOTIMPL; - } - - *ppMP = pMP; - return S_OK; -} - - -// Return the IMediaSeeking interface from our peer - -HRESULT -CPosPassThru::GetPeerSeeking(__deref_out IMediaSeeking ** ppMS) -{ - *ppMS = NULL; - - IPin *pConnected; - HRESULT hr = m_pPin->ConnectedTo(&pConnected); - if (FAILED(hr)) { - return E_NOTIMPL; - } - IMediaSeeking * pMS; - hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS); - pConnected->Release(); - if (FAILED(hr)) { - return E_NOTIMPL; - } - - *ppMS = pMS; - return S_OK; -} - - -// --- IMediaSeeking methods ---------- - - -STDMETHODIMP -CPosPassThru::GetCapabilities(__out DWORD * pCaps) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetCapabilities(pCaps); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::CheckCapabilities(__inout DWORD * pCaps) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->CheckCapabilities(pCaps); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::IsFormatSupported(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->IsFormatSupported(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::QueryPreferredFormat(__out GUID *pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->QueryPreferredFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetTimeFormat(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->SetTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetTimeFormat(__out GUID *pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::IsUsingTimeFormat(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->IsUsingTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::ConvertTimeFormat(__out LONGLONG * pTarget, - __in_opt const GUID * pTargetFormat, - LONGLONG Source, - __in_opt const GUID * pSourceFormat ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat ); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetPositions( __inout_opt LONGLONG * pCurrent, - DWORD CurrentFlags, - __inout_opt LONGLONG * pStop, - DWORD StopFlags ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags ); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::GetPositions(__out_opt LONGLONG *pCurrent, __out_opt LONGLONG * pStop) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetPositions(pCurrent,pStop); - pMS->Release(); - return hr; -} - -HRESULT -CPosPassThru::GetSeekingLongLong -( HRESULT (__stdcall IMediaSeeking::*pMethod)( __out LONGLONG * ) -, LONGLONG * pll -) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (SUCCEEDED(hr)) - { - hr = (pMS->*pMethod)(pll); - pMS->Release(); - } - return hr; -} - -// If we don't have a current position then ask upstream - -STDMETHODIMP -CPosPassThru::GetCurrentPosition(__out LONGLONG *pCurrent) -{ - // Can we report the current position - HRESULT hr = GetMediaTime(pCurrent,NULL); - if (SUCCEEDED(hr)) hr = NOERROR; - else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent ); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetStopPosition(__out LONGLONG *pStop) -{ - return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop ); -} - -STDMETHODIMP -CPosPassThru::GetDuration(__out LONGLONG *pDuration) -{ - return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration ); -} - - -STDMETHODIMP -CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll) -{ - return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll ); -} - - -STDMETHODIMP -CPosPassThru::GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetAvailable( pEarliest, pLatest ); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetRate(__out double * pdRate) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - hr = pMS->GetRate(pdRate); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetRate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - hr = pMS->SetRate(dRate); - pMS->Release(); - return hr; -} - - - - -// --- IMediaPosition methods ---------- - - -STDMETHODIMP -CPosPassThru::get_Duration(__out REFTIME * plength) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - - hr = pMP->get_Duration(plength); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_CurrentPosition(__out REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_CurrentPosition(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_CurrentPosition(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_CurrentPosition(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_StopTime(__out REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_StopTime(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_StopTime(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_StopTime(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_PrerollTime(__out REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_PrerollTime(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_PrerollTime(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_PrerollTime(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_Rate(__out double * pdRate) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_Rate(pdRate); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_Rate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_Rate(dRate); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::CanSeekForward(__out LONG *pCanSeekForward) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->CanSeekForward(pCanSeekForward); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::CanSeekBackward(__out LONG *pCanSeekBackward) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->CanSeekBackward(pCanSeekBackward); - pMP->Release(); - return hr; -} - - -// --- Implements the CRendererPosPassThru class ---------- - - -// Media times (eg current frame, field, sample etc) are passed through the -// filtergraph in media samples. When a renderer gets a sample with media -// times in it, it will call one of the RegisterMediaTime methods we expose -// (one takes an IMediaSample, the other takes the media times direct). We -// store the media times internally and return them in GetCurrentPosition. - -CRendererPosPassThru::CRendererPosPassThru(__in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - IPin *pPin) : - CPosPassThru(pName,pUnk,phr,pPin), - m_StartMedia(0), - m_EndMedia(0), - m_bReset(TRUE) -{ -} - - -// Sets the media times the object should report - -HRESULT -CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample) -{ - ASSERT(pMediaSample); - LONGLONG StartMedia; - LONGLONG EndMedia; - - CAutoLock cAutoLock(&m_PositionLock); - - // Get the media times from the sample - - HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia); - if (FAILED(hr)) - { - ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET); - return hr; - } - - m_StartMedia = StartMedia; - m_EndMedia = EndMedia; - m_bReset = FALSE; - return NOERROR; -} - - -// Sets the media times the object should report - -HRESULT -CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime) -{ - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = StartTime; - m_EndMedia = EndTime; - m_bReset = FALSE; - return NOERROR; -} - - -// Return the current media times registered in the object - -HRESULT -CRendererPosPassThru::GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) -{ - ASSERT(pStartTime); - - CAutoLock cAutoLock(&m_PositionLock); - if (m_bReset == TRUE) { - return E_FAIL; - } - - // We don't have to return the end time - - HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME ); - if (pEndTime && SUCCEEDED(hr)) { - hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME ); - } - return hr; -} - - -// Resets the media times we hold - -HRESULT -CRendererPosPassThru::ResetMediaTime() -{ - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = 0; - m_EndMedia = 0; - m_bReset = TRUE; - return NOERROR; -} - -// Intended to be called by the owing filter during EOS processing so -// that the media times can be adjusted to the stop time. This ensures -// that the GetCurrentPosition will actully get to the stop position. -HRESULT -CRendererPosPassThru::EOS() -{ - HRESULT hr; - - if ( m_bReset == TRUE ) hr = E_FAIL; - else - { - LONGLONG llStop; - if (SUCCEEDED(hr=GetStopPosition(&llStop))) - { - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = - m_EndMedia = llStop; - } - } - return hr; -} - -// -- CSourceSeeking implementation ------------ - -CSourceSeeking::CSourceSeeking( - __in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT* phr, - __in CCritSec * pLock) : - CUnknown(pName, pUnk), - m_pLock(pLock), - m_rtStart((long)0) -{ - m_rtStop = _I64_MAX / 2; - m_rtDuration = m_rtStop; - m_dRateSeeking = 1.0; - - m_dwSeekingCaps = AM_SEEKING_CanSeekForwards - | AM_SEEKING_CanSeekBackwards - | AM_SEEKING_CanSeekAbsolute - | AM_SEEKING_CanGetStopPos - | AM_SEEKING_CanGetDuration; -} - -HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - if(riid == IID_IMediaSeeking) { - CheckPointer(ppv, E_POINTER); - return GetInterface(static_cast(this), ppv); - } - else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - // only seeking in time (REFERENCE_TIME units) is supported - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -HRESULT CSourceSeeking::QueryPreferredFormat(__out GUID *pFormat) -{ - CheckPointer(pFormat, E_POINTER); - *pFormat = TIME_FORMAT_MEDIA_TIME; - return S_OK; -} - -HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - // nothing to set; just check that it's TIME_FORMAT_TIME - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG; -} - -HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -HRESULT CSourceSeeking::GetTimeFormat(__out GUID *pFormat) -{ - CheckPointer(pFormat, E_POINTER); - *pFormat = TIME_FORMAT_MEDIA_TIME; - return S_OK; -} - -HRESULT CSourceSeeking::GetDuration(__out LONGLONG *pDuration) -{ - CheckPointer(pDuration, E_POINTER); - CAutoLock lock(m_pLock); - *pDuration = m_rtDuration; - return S_OK; -} - -HRESULT CSourceSeeking::GetStopPosition(__out LONGLONG *pStop) -{ - CheckPointer(pStop, E_POINTER); - CAutoLock lock(m_pLock); - *pStop = m_rtStop; - return S_OK; -} - -HRESULT CSourceSeeking::GetCurrentPosition(__out LONGLONG *pCurrent) -{ - // GetCurrentPosition is typically supported only in renderers and - // not in source filters. - return E_NOTIMPL; -} - -HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities ) -{ - CheckPointer(pCapabilities, E_POINTER); - *pCapabilities = m_dwSeekingCaps; - return S_OK; -} - -HRESULT CSourceSeeking::CheckCapabilities( __inout DWORD * pCapabilities ) -{ - CheckPointer(pCapabilities, E_POINTER); - - // make sure all requested capabilities are in our mask - return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK; -} - -HRESULT CSourceSeeking::ConvertTimeFormat( __out LONGLONG * pTarget, - __in_opt const GUID * pTargetFormat, - LONGLONG Source, - __in_opt const GUID * pSourceFormat ) -{ - CheckPointer(pTarget, E_POINTER); - // format guids can be null to indicate current format - - // since we only support TIME_FORMAT_MEDIA_TIME, we don't really - // offer any conversions. - if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME) - { - if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME) - { - *pTarget = Source; - return S_OK; - } - } - - return E_INVALIDARG; -} - - -HRESULT CSourceSeeking::SetPositions( __inout_opt LONGLONG * pCurrent, - DWORD CurrentFlags, - __inout_opt LONGLONG * pStop, - DWORD StopFlags ) -{ - DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask; - DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask; - - if(StopFlags) { - CheckPointer(pStop, E_POINTER); - - // accept only relative, incremental, or absolute positioning - if(StopPosBits != StopFlags) { - return E_INVALIDARG; - } - } - - if(CurrentFlags) { - CheckPointer(pCurrent, E_POINTER); - if(StartPosBits != AM_SEEKING_AbsolutePositioning && - StartPosBits != AM_SEEKING_RelativePositioning) { - return E_INVALIDARG; - } - } - - - // scope for autolock - { - CAutoLock lock(m_pLock); - - // set start position - if(StartPosBits == AM_SEEKING_AbsolutePositioning) - { - m_rtStart = *pCurrent; - } - else if(StartPosBits == AM_SEEKING_RelativePositioning) - { - m_rtStart += *pCurrent; - } - - // set stop position - if(StopPosBits == AM_SEEKING_AbsolutePositioning) - { - m_rtStop = *pStop; - } - else if(StopPosBits == AM_SEEKING_IncrementalPositioning) - { - m_rtStop = m_rtStart + *pStop; - } - else if(StopPosBits == AM_SEEKING_RelativePositioning) - { - m_rtStop = m_rtStop + *pStop; - } - } - - - HRESULT hr = S_OK; - if(SUCCEEDED(hr) && StopPosBits) { - hr = ChangeStop(); - } - if(StartPosBits) { - hr = ChangeStart(); - } - - return hr; -} - - -HRESULT CSourceSeeking::GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ) -{ - if(pCurrent) { - *pCurrent = m_rtStart; - } - if(pStop) { - *pStop = m_rtStop; - } - - return S_OK; -} - - -HRESULT CSourceSeeking::GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ) -{ - if(pEarliest) { - *pEarliest = 0; - } - if(pLatest) { - CAutoLock lock(m_pLock); - *pLatest = m_rtDuration; - } - return S_OK; -} - -HRESULT CSourceSeeking::SetRate( double dRate) -{ - { - CAutoLock lock(m_pLock); - m_dRateSeeking = dRate; - } - return ChangeRate(); -} - -HRESULT CSourceSeeking::GetRate( __out double * pdRate) -{ - CheckPointer(pdRate, E_POINTER); - CAutoLock lock(m_pLock); - *pdRate = m_dRateSeeking; - return S_OK; -} - -HRESULT CSourceSeeking::GetPreroll(__out LONGLONG *pPreroll) -{ - CheckPointer(pPreroll, E_POINTER); - *pPreroll = 0; - return S_OK; -} - - - - - -// --- CSourcePosition implementation ---------- - - -CSourcePosition::CSourcePosition(__in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT* phr, - __in CCritSec * pLock) : - CMediaPosition(pName, pUnk), - m_pLock(pLock), - m_Start(CRefTime((LONGLONG)0)) -{ - m_Stop = _I64_MAX; - m_Rate = 1.0; -} - - -STDMETHODIMP -CSourcePosition::get_Duration(__out REFTIME * plength) -{ - CheckPointer(plength,E_POINTER); - ValidateReadWritePtr(plength,sizeof(REFTIME)); - CAutoLock lock(m_pLock); - - *plength = m_Duration; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_CurrentPosition(REFTIME llTime) -{ - m_pLock->Lock(); - m_Start = llTime; - m_pLock->Unlock(); - - return ChangeStart(); -} - - -STDMETHODIMP -CSourcePosition::get_StopTime(__out REFTIME * pllTime) -{ - CheckPointer(pllTime,E_POINTER); - ValidateReadWritePtr(pllTime,sizeof(REFTIME)); - CAutoLock lock(m_pLock); - - *pllTime = m_Stop; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_StopTime(REFTIME llTime) -{ - m_pLock->Lock(); - m_Stop = llTime; - m_pLock->Unlock(); - - return ChangeStop(); -} - - -STDMETHODIMP -CSourcePosition::get_PrerollTime(__out REFTIME * pllTime) -{ - CheckPointer(pllTime,E_POINTER); - ValidateReadWritePtr(pllTime,sizeof(REFTIME)); - return E_NOTIMPL; -} - - -STDMETHODIMP -CSourcePosition::put_PrerollTime(REFTIME llTime) -{ - return E_NOTIMPL; -} - - -STDMETHODIMP -CSourcePosition::get_Rate(__out double * pdRate) -{ - CheckPointer(pdRate,E_POINTER); - ValidateReadWritePtr(pdRate,sizeof(double)); - CAutoLock lock(m_pLock); - - *pdRate = m_Rate; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_Rate(double dRate) -{ - m_pLock->Lock(); - m_Rate = dRate; - m_pLock->Unlock(); - - return ChangeRate(); -} - - -// By default we can seek forwards - -STDMETHODIMP -CSourcePosition::CanSeekForward(__out LONG *pCanSeekForward) -{ - CheckPointer(pCanSeekForward,E_POINTER); - *pCanSeekForward = OATRUE; - return S_OK; -} - - -// By default we can seek backwards - -STDMETHODIMP -CSourcePosition::CanSeekBackward(__out LONG *pCanSeekBackward) -{ - CheckPointer(pCanSeekBackward,E_POINTER); - *pCanSeekBackward = OATRUE; - return S_OK; -} - - -// --- Implementation of CBasicAudio class ---------- - - -CBasicAudio::CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - -// overriden to publicise our interfaces - -STDMETHODIMP -CBasicAudio::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IBasicAudio) { - return GetInterface( (IBasicAudio *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBasicAudio::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IBasicAudio, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBasicAudio::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IBasicAudio, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBasicAudio::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IBasicAudio *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IVideoWindow implementation ---------- - -CBaseVideoWindow::CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - - -// overriden to publicise our interfaces - -STDMETHODIMP -CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IVideoWindow) { - return GetInterface( (IVideoWindow *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBaseVideoWindow::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IVideoWindow, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBaseVideoWindow::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IVideoWindow, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBaseVideoWindow::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IVideoWindow *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IBasicVideo implementation ---------- - - -CBaseBasicVideo::CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - - -// overriden to publicise our interfaces - -STDMETHODIMP -CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) { - return GetInterface( static_cast(this), ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBaseBasicVideo::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IBasicVideo, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBaseBasicVideo::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IBasicVideo, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBaseBasicVideo::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IBasicVideo *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- Implementation of Deferred Commands ---------- - - -CDispParams::CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr) -{ - cNamedArgs = 0; - rgdispidNamedArgs = NULL; - cArgs = nArgs; - - if (cArgs) { - rgvarg = new VARIANT[cArgs]; - if (NULL == rgvarg) { - cArgs = 0; - if (phr) { - *phr = E_OUTOFMEMORY; - } - return; - } - - for (UINT i = 0; i < cArgs; i++) { - - // Why aren't we using VariantCopy? - - VARIANT * pDest = &rgvarg[i]; - VARIANT * pSrc = &pArgs[i]; - - pDest->vt = pSrc->vt; - switch(pDest->vt) { - - case VT_I4: - pDest->lVal = pSrc->lVal; - break; - - case VT_UI1: - pDest->bVal = pSrc->bVal; - break; - - case VT_I2: - pDest->iVal = pSrc->iVal; - break; - - case VT_R4: - pDest->fltVal = pSrc->fltVal; - break; - - case VT_R8: - pDest->dblVal = pSrc->dblVal; - break; - - case VT_BOOL: - pDest->boolVal = pSrc->boolVal; - break; - - case VT_ERROR: - pDest->scode = pSrc->scode; - break; - - case VT_CY: - pDest->cyVal = pSrc->cyVal; - break; - - case VT_DATE: - pDest->date = pSrc->date; - break; - - case VT_BSTR: - if ((PVOID)pSrc->bstrVal == NULL) { - pDest->bstrVal = NULL; - } else { - - // a BSTR is a WORD followed by a UNICODE string. - // the pointer points just after the WORD - - WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR))); - OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))]; - if (pch) { - WORD *pui = (WORD*)pch; - *pui = len; - pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR)); - CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR)); - } else { - cArgs = i; - if (phr) { - *phr = E_OUTOFMEMORY; - } - } - } - break; - - case VT_UNKNOWN: - pDest->punkVal = pSrc->punkVal; - pDest->punkVal->AddRef(); - break; - - case VT_DISPATCH: - pDest->pdispVal = pSrc->pdispVal; - pDest->pdispVal->AddRef(); - break; - - default: - // a type we haven't got round to adding yet! - ASSERT(0); - break; - } - } - - } else { - rgvarg = NULL; - } - -} - - -CDispParams::~CDispParams() -{ - for (UINT i = 0; i < cArgs; i++) { - switch(rgvarg[i].vt) { - case VT_BSTR: - // Explicitly cast BSTR to PVOID to tell code scanning tools we really mean to test the pointer - if ((PVOID)rgvarg[i].bstrVal != NULL) { - OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR)); - delete pch; - } - break; - - case VT_UNKNOWN: - rgvarg[i].punkVal->Release(); - break; - - case VT_DISPATCH: - rgvarg[i].pdispVal->Release(); - break; - } - } - delete[] rgvarg; -} - - -// lifetime is controlled by refcounts (see defer.h) - -CDeferredCommand::CDeferredCommand( - __inout CCmdQueue * pQ, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT * phr, - __in LPUNKNOWN pUnkExecutor, - REFTIME time, - __in GUID* iid, - long dispidMethod, - short wFlags, - long nArgs, - __in_ecount(nArgs) VARIANT* pDispParams, - __out VARIANT* pvarResult, - __out short* puArgErr, - BOOL bStream - ) : - CUnknown(NAME("DeferredCommand"), pUnk), - m_pQueue(pQ), - m_pUnk(pUnkExecutor), - m_iid(iid), - m_dispidMethod(dispidMethod), - m_wFlags(wFlags), - m_DispParams(nArgs, pDispParams, phr), - m_pvarResult(pvarResult), - m_bStream(bStream), - m_hrResult(E_ABORT), - m_DispId(0) - -{ - // convert REFTIME to REFERENCE_TIME - COARefTime convertor(time); - m_time = convertor; - - // no check of time validity - it's ok to queue a command that's - // already late - - // check iid is supportable on pUnk by QueryInterface for it - IUnknown * pInterface; - HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); - if (FAILED(hr)) { - *phr = hr; - return; - } - pInterface->Release(); - - - // !!! check dispidMethod and param/return types using typelib - ITypeInfo *pti; - hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti); - if (FAILED(hr)) { - *phr = hr; - return; - } - // !!! some sort of ITypeInfo validity check here - pti->Release(); - - - // Fix up the dispid for put and get - if (wFlags == DISPATCH_PROPERTYPUT) { - m_DispParams.cNamedArgs = 1; - m_DispId = DISPID_PROPERTYPUT; - m_DispParams.rgdispidNamedArgs = &m_DispId; - } - - // all checks ok - add to queue - hr = pQ->Insert(this); - if (FAILED(hr)) { - *phr = hr; - } -} - - -// refcounts are held by caller of InvokeAt... and by list. So if -// we get here, we can't be on the list - -#if 0 -CDeferredCommand::~CDeferredCommand() -{ - // this assert is invalid since if the queue is deleted while we are - // still on the queue, we will have been removed by the queue and this - // m_pQueue will not have been modified. - // ASSERT(m_pQueue == NULL); - - // we don't hold a ref count on pUnk, which is the object that should - // execute the command. - // This is because there would otherwise be a circular refcount problem - // since pUnk probably owns the CmdQueue object that has a refcount - // on us. - // The lifetime of pUnk is guaranteed by it being part of, or lifetime - // controlled by, our parent object. As long as we are on the list, pUnk - // must be valid. Once we are off the list, we do not use pUnk. - -} -#endif - - -// overriden to publicise our interfaces - -STDMETHODIMP -CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, __out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IDeferredCommand) { - return GetInterface( (IDeferredCommand *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// remove from q. this will reduce the refcount by one (since the q -// holds a count) but can't make us go away since he must have a -// refcount in order to call this method. - -STDMETHODIMP -CDeferredCommand::Cancel() -{ - if (m_pQueue == NULL) { - return VFW_E_ALREADY_CANCELLED; - } - - HRESULT hr = m_pQueue->Remove(this); - if (FAILED(hr)) { - return hr; - } - - m_pQueue = NULL; - return S_OK; -} - - -STDMETHODIMP -CDeferredCommand::Confidence(__out LONG* pConfidence) -{ - return E_NOTIMPL; -} - - -STDMETHODIMP -CDeferredCommand::GetHResult(__out HRESULT * phrResult) -{ - CheckPointer(phrResult,E_POINTER); - ValidateReadWritePtr(phrResult,sizeof(HRESULT)); - - if (m_pQueue != NULL) { - return E_ABORT; - } - *phrResult = m_hrResult; - return S_OK; -} - - -// set the time to be a new time (checking that it is valid) and -// then requeue - -STDMETHODIMP -CDeferredCommand::Postpone(REFTIME newtime) -{ - - // check that this time is not past - // convert REFTIME to REFERENCE_TIME - COARefTime convertor(newtime); - - // check that the time has not passed - if (m_pQueue->CheckTime(convertor, IsStreamTime())) { - return VFW_E_TIME_ALREADY_PASSED; - } - - // extract from list - HRESULT hr = m_pQueue->Remove(this); - if (FAILED(hr)) { - return hr; - } - - // change time - m_time = convertor; - - // requeue - hr = m_pQueue->Insert(this); - - return hr; -} - - -HRESULT -CDeferredCommand::Invoke() -{ - // check that we are still outstanding - if (m_pQueue == NULL) { - return VFW_E_ALREADY_CANCELLED; - } - - // get the type info - ITypeInfo* pti; - HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti); - if (FAILED(hr)) { - return hr; - } - - // qi for the expected interface and then invoke it. Note that we have to - // treat the returned interface as IUnknown since we don't know its type. - IUnknown* pInterface; - - hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); - if (FAILED(hr)) { - pti->Release(); - return hr; - } - - EXCEPINFO expinfo; - UINT uArgErr; - m_hrResult = pti->Invoke( - pInterface, - GetMethod(), - GetFlags(), - GetParams(), - GetResult(), - &expinfo, - &uArgErr); - - // release the interface we QI'd for - pInterface->Release(); - pti->Release(); - - - // remove from list whether or not successful - // or we loop indefinitely - hr = m_pQueue->Remove(this); - m_pQueue = NULL; - return hr; -} - - - -// --- CCmdQueue methods ---------- - - -CCmdQueue::CCmdQueue(__inout_opt HRESULT *phr) : - m_listPresentation(NAME("Presentation time command list")), - m_listStream(NAME("Stream time command list")), - m_evDue(TRUE, phr), // manual reset - m_dwAdvise(0), - m_pClock(NULL), - m_bRunning(FALSE) -{ -} - - -CCmdQueue::~CCmdQueue() -{ - // empty all our lists - - // we hold a refcount on each, so traverse and Release each - // entry then RemoveAll to empty the list - POSITION pos = m_listPresentation.GetHeadPosition(); - - while(pos) { - CDeferredCommand* pCmd = m_listPresentation.GetNext(pos); - pCmd->Release(); - } - m_listPresentation.RemoveAll(); - - pos = m_listStream.GetHeadPosition(); - - while(pos) { - CDeferredCommand* pCmd = m_listStream.GetNext(pos); - pCmd->Release(); - } - m_listStream.RemoveAll(); - - if (m_pClock) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - m_dwAdvise = 0; - } - m_pClock->Release(); - } -} - - -// returns a new CDeferredCommand object that will be initialised with -// the parameters and will be added to the queue during construction. -// returns S_OK if successfully created otherwise an error and -// no object has been queued. - -HRESULT -CCmdQueue::New( - __out CDeferredCommand **ppCmd, - __in LPUNKNOWN pUnk, // this object will execute command - REFTIME time, - __in GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - __in_ecount(cArgs) VARIANT* pDispParams, - __out VARIANT* pvarResult, - __out short* puArgErr, - BOOL bStream -) -{ - CAutoLock lock(&m_Lock); - - HRESULT hr = S_OK; - *ppCmd = NULL; - - CDeferredCommand* pCmd; - pCmd = new CDeferredCommand( - this, - NULL, // not aggregated - &hr, - pUnk, // this guy will execute - time, - iid, - dispidMethod, - wFlags, - cArgs, - pDispParams, - pvarResult, - puArgErr, - bStream); - - if (pCmd == NULL) { - hr = E_OUTOFMEMORY; - } else { - *ppCmd = pCmd; - } - return hr; -} - - -HRESULT -CCmdQueue::Insert(__in CDeferredCommand* pCmd) -{ - CAutoLock lock(&m_Lock); - - // addref the item - pCmd->AddRef(); - - CGenericList * pList; - if (pCmd->IsStreamTime()) { - pList = &m_listStream; - } else { - pList = &m_listPresentation; - } - POSITION pos = pList->GetHeadPosition(); - - // seek past all items that are before us - while (pos && - (pList->GetValid(pos)->GetTime() <= pCmd->GetTime())) { - - pList->GetNext(pos); - } - - // now at end of list or in front of items that come later - if (!pos) { - pList->AddTail(pCmd); - } else { - pList->AddBefore(pos, pCmd); - } - - SetTimeAdvise(); - return S_OK; -} - - -HRESULT -CCmdQueue::Remove(__in CDeferredCommand* pCmd) -{ - CAutoLock lock(&m_Lock); - HRESULT hr = S_OK; - - CGenericList * pList; - if (pCmd->IsStreamTime()) { - pList = &m_listStream; - } else { - pList = &m_listPresentation; - } - POSITION pos = pList->GetHeadPosition(); - - // traverse the list - while (pos && (pList->GetValid(pos) != pCmd)) { - pList->GetNext(pos); - } - - // did we drop off the end? - if (!pos) { - hr = VFW_E_NOT_FOUND; - } else { - - // found it - now take off list - pList->Remove(pos); - - // Insert did an AddRef, so release it - pCmd->Release(); - - // check that timer request is still for earliest time - SetTimeAdvise(); - } - return hr; -} - - -// set the clock used for timing - -HRESULT -CCmdQueue::SetSyncSource(__in_opt IReferenceClock* pClock) -{ - CAutoLock lock(&m_Lock); - - // addref the new clock first in case they are the same - if (pClock) { - pClock->AddRef(); - } - - // kill any advise on the old clock - if (m_pClock) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - m_dwAdvise = 0; - } - m_pClock->Release(); - } - m_pClock = pClock; - - // set up a new advise - SetTimeAdvise(); - return S_OK; -} - - -// set up a timer event with the reference clock - -void -CCmdQueue::SetTimeAdvise(void) -{ - // make sure we have a clock to use - if (!m_pClock) { - return; - } - - // reset the event whenever we are requesting a new signal - m_evDue.Reset(); - - // time 0 is earliest - CRefTime current; - - // find the earliest presentation time - POSITION pos = m_listPresentation.GetHeadPosition(); - if (pos != NULL) { - current = m_listPresentation.GetValid(pos)->GetTime(); - } - - // if we're running, check the stream times too - if (m_bRunning) { - - CRefTime t; - pos = m_listStream.GetHeadPosition(); - if (NULL != pos) { - t = m_listStream.GetValid(pos)->GetTime(); - - // add on stream time offset to get presentation time - t += m_StreamTimeOffset; - - // is this earlier? - if ((current == TimeZero) || (t < current)) { - current = t; - } - } - } - - // need to change? - if ((current > TimeZero) && (current != m_tCurrentAdvise)) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - // reset the event whenever we are requesting a new signal - m_evDue.Reset(); - } - - // ask for time advice - the first two params are either - // stream time offset and stream time or - // presentation time and 0. we always use the latter - HRESULT hr = m_pClock->AdviseTime( - (REFERENCE_TIME)current, - TimeZero, - (HEVENT) HANDLE(m_evDue), - &m_dwAdvise); - - ASSERT(SUCCEEDED(hr)); - UNREFERENCED_PARAMETER(hr); - m_tCurrentAdvise = current; - } -} - - -// switch to run mode. Streamtime to Presentation time mapping known. - -HRESULT -CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset) -{ - CAutoLock lock(&m_Lock); - - m_StreamTimeOffset = tStreamTimeOffset; - m_bRunning = TRUE; - - // ensure advise is accurate - SetTimeAdvise(); - return S_OK; -} - - -// switch to Stopped or Paused mode. Time mapping not known. - -HRESULT -CCmdQueue::EndRun() -{ - CAutoLock lock(&m_Lock); - - m_bRunning = FALSE; - - // check timer setting - stream times - SetTimeAdvise(); - return S_OK; -} - - -// return a pointer to the next due command. Blocks for msTimeout -// milliseconds until there is a due command. -// Stream-time commands will only become due between Run and Endrun calls. -// The command remains queued until invoked or cancelled. -// Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). -// -// returns an AddRef'd object - -HRESULT -CCmdQueue::GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout) -{ - // loop until we timeout or find a due command - for (;;) { - - { - CAutoLock lock(&m_Lock); - - - // find the earliest command - CDeferredCommand * pCmd = NULL; - - // check the presentation time and the - // stream time list to find the earliest - - POSITION pos = m_listPresentation.GetHeadPosition(); - - if (NULL != pos) { - pCmd = m_listPresentation.GetValid(pos); - } - - if (m_bRunning) { - pos = m_listStream.GetHeadPosition(); - if (NULL != pos) { - CDeferredCommand* pStrm = m_listStream.GetValid(pos); - - CRefTime t = pStrm->GetTime() + m_StreamTimeOffset; - if (!pCmd || (t < pCmd->GetTime())) { - pCmd = pStrm; - } - } - } - - // if we have found one, is it due? - if (pCmd) { - if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) { - - // yes it's due - addref it - pCmd->AddRef(); - *ppCmd = pCmd; - return S_OK; - } - } - } - - // block until the advise is signalled - if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) { - return E_ABORT; - } - } -} - - -// return a pointer to a command that will be due for a given time. -// Pass in a stream time here. The stream time offset will be passed -// in via the Run method. -// Commands remain queued until invoked or cancelled. -// This method will not block. It will report E_ABORT if there are no -// commands due yet. -// -// returns an AddRef'd object - -HRESULT -CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, __out CDeferredCommand**ppCmd) -{ - CAutoLock lock(&m_Lock); - - CRefTime tStream(rtStream); - - // find the earliest stream and presentation time commands - CDeferredCommand* pStream = NULL; - POSITION pos = m_listStream.GetHeadPosition(); - if (NULL != pos) { - pStream = m_listStream.GetValid(pos); - } - CDeferredCommand* pPresent = NULL; - pos = m_listPresentation.GetHeadPosition(); - if (NULL != pos) { - pPresent = m_listPresentation.GetValid(pos); - } - - // is there a presentation time that has passed already - if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) { - pPresent->AddRef(); - *ppCmd = pPresent; - return S_OK; - } - - // is there a stream time command due before this stream time - if (pStream && (pStream->GetTime() <= tStream)) { - pStream->AddRef(); - *ppCmd = pStream; - return S_OK; - } - - // if we are running, we can map presentation times to - // stream time. In this case, is there a presentation time command - // that will be due before this stream time is presented? - if (m_bRunning && pPresent) { - - // this stream time will appear at... - tStream += m_StreamTimeOffset; - - // due before that? - if (pPresent->GetTime() <= tStream) { - *ppCmd = pPresent; - return S_OK; - } - } - - // no commands due yet - return VFW_E_NOT_FOUND; -} - +//------------------------------------------------------------------------------ +// File: CtlUtil.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Base classes implementing IDispatch parsing for the basic control dual +// interfaces. Derive from these and implement just the custom method and +// property methods. We also implement CPosPassThru that can be used by +// renderers and transforms to pass by IMediaPosition and IMediaSeeking + + +#include "streams.h" +#include +#include "seekpt.h" + +// 'bool' non standard reserved word +#pragma warning(disable:4237) + + +// --- CBaseDispatch implementation ---------- +CBaseDispatch::~CBaseDispatch() +{ + if (m_pti) { + m_pti->Release(); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CBaseDispatch::GetTypeInfoCount(__out UINT * pctinfo) +{ + CheckPointer(pctinfo,E_POINTER); + ValidateReadWritePtr(pctinfo,sizeof(UINT *)); + *pctinfo = 1; + return S_OK; +} + + +typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)( + const OLECHAR FAR *szFile, + __deref_out ITypeLib FAR* FAR* pptlib); + +typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid, + WORD wVerMajor, + WORD wVerMinor, + LCID lcid, + __deref_out ITypeLib FAR* FAR* pptlib); + +// attempt to find our type library + +STDMETHODIMP +CBaseDispatch::GetTypeInfo( + REFIID riid, + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + CheckPointer(pptinfo,E_POINTER); + ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *)); + HRESULT hr; + + *pptinfo = NULL; + + // we only support one type element + if (0 != itinfo) { + return TYPE_E_ELEMENTNOTFOUND; + } + + // always look for neutral + if (NULL == m_pti) { + + LPLOADTYPELIB lpfnLoadTypeLib; + LPLOADREGTYPELIB lpfnLoadRegTypeLib; + ITypeLib *ptlib; + HINSTANCE hInst; + + static const char szTypeLib[] = "LoadTypeLib"; + static const char szRegTypeLib[] = "LoadRegTypeLib"; + static const WCHAR szControl[] = L"control.tlb"; + + // + // Try to get the Ole32Aut.dll module handle. + // + + hInst = LoadOLEAut32(); + if (hInst == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst, + szRegTypeLib); + if (lpfnLoadRegTypeLib == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + + hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0 + lcid, &ptlib); + + if (FAILED(hr)) { + + // attempt to load directly - this will fill the + // registry in if it finds it + + lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib); + if (lpfnLoadTypeLib == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + + hr = (*lpfnLoadTypeLib)(szControl, &ptlib); + if (FAILED(hr)) { + return hr; + } + } + + hr = ptlib->GetTypeInfoOfGuid( + riid, + &m_pti); + + ptlib->Release(); + + if (FAILED(hr)) { + return hr; + } + } + + *pptinfo = m_pti; + m_pti->AddRef(); + return S_OK; +} + + +STDMETHODIMP +CBaseDispatch::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + // although the IDispatch riid is dead, we use this to pass from + // the interface implementation class to us the iid we are talking about. + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti); + + if (SUCCEEDED(hr)) { + hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid); + + pti->Release(); + } + return hr; +} + + +// --- CMediaControl implementation --------- + +CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + +// expose our interfaces IMediaControl and IUnknown + +STDMETHODIMP +CMediaControl::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaControl) { + return GetInterface( (IMediaControl *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaControl::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaControl::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaControl, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaControl::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaControl, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaControl::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaControl *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- CMediaEvent implementation ---------- + + +CMediaEvent::CMediaEvent(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + + +// expose our interfaces IMediaEvent and IUnknown + +STDMETHODIMP +CMediaEvent::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) { + return GetInterface( (IMediaEventEx *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaEvent::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaEvent::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaEvent, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaEvent::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaEvent, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaEvent::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaEvent *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- CMediaPosition implementation ---------- + + +CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + +CMediaPosition::CMediaPosition(__in_opt LPCTSTR name, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT * phr) : + CUnknown(name, pUnk) +{ + UNREFERENCED_PARAMETER(phr); +} + + +// expose our interfaces IMediaPosition and IUnknown + +STDMETHODIMP +CMediaPosition::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaPosition) { + return GetInterface( (IMediaPosition *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaPosition::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaPosition::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaPosition, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaPosition::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaPosition, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaPosition::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaPosition *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IMediaPosition and IMediaSeeking pass through class ---------- + + +CPosPassThru::CPosPassThru(__in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + IPin *pPin) : + CMediaPosition(pName,pUnk), + m_pPin(pPin) +{ + if (pPin == NULL) { + *phr = E_POINTER; + return; + } +} + + +// Expose our IMediaSeeking and IMediaPosition interfaces + +STDMETHODIMP +CPosPassThru::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) +{ + CheckPointer(ppv,E_POINTER); + *ppv = NULL; + + if (riid == IID_IMediaSeeking) { + return GetInterface( static_cast(this), ppv); + } + return CMediaPosition::NonDelegatingQueryInterface(riid,ppv); +} + + +// Return the IMediaPosition interface from our peer + +HRESULT +CPosPassThru::GetPeer(IMediaPosition ** ppMP) +{ + *ppMP = NULL; + + IPin *pConnected; + HRESULT hr = m_pPin->ConnectedTo(&pConnected); + if (FAILED(hr)) { + return E_NOTIMPL; + } + IMediaPosition * pMP; + hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP); + pConnected->Release(); + if (FAILED(hr)) { + return E_NOTIMPL; + } + + *ppMP = pMP; + return S_OK; +} + + +// Return the IMediaSeeking interface from our peer + +HRESULT +CPosPassThru::GetPeerSeeking(__deref_out IMediaSeeking ** ppMS) +{ + *ppMS = NULL; + + IPin *pConnected; + HRESULT hr = m_pPin->ConnectedTo(&pConnected); + if (FAILED(hr)) { + return E_NOTIMPL; + } + IMediaSeeking * pMS; + hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS); + pConnected->Release(); + if (FAILED(hr)) { + return E_NOTIMPL; + } + + *ppMS = pMS; + return S_OK; +} + + +// --- IMediaSeeking methods ---------- + + +STDMETHODIMP +CPosPassThru::GetCapabilities(__out DWORD * pCaps) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetCapabilities(pCaps); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::CheckCapabilities(__inout DWORD * pCaps) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->CheckCapabilities(pCaps); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::IsFormatSupported(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->IsFormatSupported(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::QueryPreferredFormat(__out GUID *pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->QueryPreferredFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetTimeFormat(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->SetTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetTimeFormat(__out GUID *pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::IsUsingTimeFormat(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->IsUsingTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::ConvertTimeFormat(__out LONGLONG * pTarget, + __in_opt const GUID * pTargetFormat, + LONGLONG Source, + __in_opt const GUID * pSourceFormat ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat ); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetPositions( __inout_opt LONGLONG * pCurrent, + DWORD CurrentFlags, + __inout_opt LONGLONG * pStop, + DWORD StopFlags ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags ); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::GetPositions(__out_opt LONGLONG *pCurrent, __out_opt LONGLONG * pStop) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetPositions(pCurrent,pStop); + pMS->Release(); + return hr; +} + +HRESULT +CPosPassThru::GetSeekingLongLong +( HRESULT (__stdcall IMediaSeeking::*pMethod)( __out LONGLONG * ) +, LONGLONG * pll +) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (SUCCEEDED(hr)) + { + hr = (pMS->*pMethod)(pll); + pMS->Release(); + } + return hr; +} + +// If we don't have a current position then ask upstream + +STDMETHODIMP +CPosPassThru::GetCurrentPosition(__out LONGLONG *pCurrent) +{ + // Can we report the current position + HRESULT hr = GetMediaTime(pCurrent,NULL); + if (SUCCEEDED(hr)) hr = NOERROR; + else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent ); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetStopPosition(__out LONGLONG *pStop) +{ + return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop ); +} + +STDMETHODIMP +CPosPassThru::GetDuration(__out LONGLONG *pDuration) +{ + return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration ); +} + + +STDMETHODIMP +CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll) +{ + return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll ); +} + + +STDMETHODIMP +CPosPassThru::GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetAvailable( pEarliest, pLatest ); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetRate(__out double * pdRate) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + hr = pMS->GetRate(pdRate); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetRate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + hr = pMS->SetRate(dRate); + pMS->Release(); + return hr; +} + + + + +// --- IMediaPosition methods ---------- + + +STDMETHODIMP +CPosPassThru::get_Duration(__out REFTIME * plength) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + + hr = pMP->get_Duration(plength); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_CurrentPosition(__out REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_CurrentPosition(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_CurrentPosition(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_CurrentPosition(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_StopTime(__out REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_StopTime(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_StopTime(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_StopTime(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_PrerollTime(__out REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_PrerollTime(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_PrerollTime(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_PrerollTime(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_Rate(__out double * pdRate) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_Rate(pdRate); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_Rate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_Rate(dRate); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::CanSeekForward(__out LONG *pCanSeekForward) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->CanSeekForward(pCanSeekForward); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::CanSeekBackward(__out LONG *pCanSeekBackward) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->CanSeekBackward(pCanSeekBackward); + pMP->Release(); + return hr; +} + + +// --- Implements the CRendererPosPassThru class ---------- + + +// Media times (eg current frame, field, sample etc) are passed through the +// filtergraph in media samples. When a renderer gets a sample with media +// times in it, it will call one of the RegisterMediaTime methods we expose +// (one takes an IMediaSample, the other takes the media times direct). We +// store the media times internally and return them in GetCurrentPosition. + +CRendererPosPassThru::CRendererPosPassThru(__in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + IPin *pPin) : + CPosPassThru(pName,pUnk,phr,pPin), + m_StartMedia(0), + m_EndMedia(0), + m_bReset(TRUE) +{ +} + + +// Sets the media times the object should report + +HRESULT +CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample) +{ + ASSERT(pMediaSample); + LONGLONG StartMedia; + LONGLONG EndMedia; + + CAutoLock cAutoLock(&m_PositionLock); + + // Get the media times from the sample + + HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia); + if (FAILED(hr)) + { + ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET); + return hr; + } + + m_StartMedia = StartMedia; + m_EndMedia = EndMedia; + m_bReset = FALSE; + return NOERROR; +} + + +// Sets the media times the object should report + +HRESULT +CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime) +{ + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = StartTime; + m_EndMedia = EndTime; + m_bReset = FALSE; + return NOERROR; +} + + +// Return the current media times registered in the object + +HRESULT +CRendererPosPassThru::GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) +{ + ASSERT(pStartTime); + + CAutoLock cAutoLock(&m_PositionLock); + if (m_bReset == TRUE) { + return E_FAIL; + } + + // We don't have to return the end time + + HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME ); + if (pEndTime && SUCCEEDED(hr)) { + hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME ); + } + return hr; +} + + +// Resets the media times we hold + +HRESULT +CRendererPosPassThru::ResetMediaTime() +{ + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = 0; + m_EndMedia = 0; + m_bReset = TRUE; + return NOERROR; +} + +// Intended to be called by the owing filter during EOS processing so +// that the media times can be adjusted to the stop time. This ensures +// that the GetCurrentPosition will actully get to the stop position. +HRESULT +CRendererPosPassThru::EOS() +{ + HRESULT hr; + + if ( m_bReset == TRUE ) hr = E_FAIL; + else + { + LONGLONG llStop; + if (SUCCEEDED(hr=GetStopPosition(&llStop))) + { + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = + m_EndMedia = llStop; + } + } + return hr; +} + +// -- CSourceSeeking implementation ------------ + +CSourceSeeking::CSourceSeeking( + __in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT* phr, + __in CCritSec * pLock) : + CUnknown(pName, pUnk), + m_pLock(pLock), + m_rtStart((long)0) +{ + m_rtStop = _I64_MAX / 2; + m_rtDuration = m_rtStop; + m_dRateSeeking = 1.0; + + m_dwSeekingCaps = AM_SEEKING_CanSeekForwards + | AM_SEEKING_CanSeekBackwards + | AM_SEEKING_CanSeekAbsolute + | AM_SEEKING_CanGetStopPos + | AM_SEEKING_CanGetDuration; +} + +HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + if(riid == IID_IMediaSeeking) { + CheckPointer(ppv, E_POINTER); + return GetInterface(static_cast(this), ppv); + } + else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + // only seeking in time (REFERENCE_TIME units) is supported + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +HRESULT CSourceSeeking::QueryPreferredFormat(__out GUID *pFormat) +{ + CheckPointer(pFormat, E_POINTER); + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + // nothing to set; just check that it's TIME_FORMAT_TIME + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG; +} + +HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +HRESULT CSourceSeeking::GetTimeFormat(__out GUID *pFormat) +{ + CheckPointer(pFormat, E_POINTER); + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT CSourceSeeking::GetDuration(__out LONGLONG *pDuration) +{ + CheckPointer(pDuration, E_POINTER); + CAutoLock lock(m_pLock); + *pDuration = m_rtDuration; + return S_OK; +} + +HRESULT CSourceSeeking::GetStopPosition(__out LONGLONG *pStop) +{ + CheckPointer(pStop, E_POINTER); + CAutoLock lock(m_pLock); + *pStop = m_rtStop; + return S_OK; +} + +HRESULT CSourceSeeking::GetCurrentPosition(__out LONGLONG *pCurrent) +{ + // GetCurrentPosition is typically supported only in renderers and + // not in source filters. + return E_NOTIMPL; +} + +HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities ) +{ + CheckPointer(pCapabilities, E_POINTER); + *pCapabilities = m_dwSeekingCaps; + return S_OK; +} + +HRESULT CSourceSeeking::CheckCapabilities( __inout DWORD * pCapabilities ) +{ + CheckPointer(pCapabilities, E_POINTER); + + // make sure all requested capabilities are in our mask + return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK; +} + +HRESULT CSourceSeeking::ConvertTimeFormat( __out LONGLONG * pTarget, + __in_opt const GUID * pTargetFormat, + LONGLONG Source, + __in_opt const GUID * pSourceFormat ) +{ + CheckPointer(pTarget, E_POINTER); + // format guids can be null to indicate current format + + // since we only support TIME_FORMAT_MEDIA_TIME, we don't really + // offer any conversions. + if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME) + { + if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME) + { + *pTarget = Source; + return S_OK; + } + } + + return E_INVALIDARG; +} + + +HRESULT CSourceSeeking::SetPositions( __inout_opt LONGLONG * pCurrent, + DWORD CurrentFlags, + __inout_opt LONGLONG * pStop, + DWORD StopFlags ) +{ + DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask; + DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask; + + if(StopFlags) { + CheckPointer(pStop, E_POINTER); + + // accept only relative, incremental, or absolute positioning + if(StopPosBits != StopFlags) { + return E_INVALIDARG; + } + } + + if(CurrentFlags) { + CheckPointer(pCurrent, E_POINTER); + if(StartPosBits != AM_SEEKING_AbsolutePositioning && + StartPosBits != AM_SEEKING_RelativePositioning) { + return E_INVALIDARG; + } + } + + + // scope for autolock + { + CAutoLock lock(m_pLock); + + // set start position + if(StartPosBits == AM_SEEKING_AbsolutePositioning) + { + m_rtStart = *pCurrent; + } + else if(StartPosBits == AM_SEEKING_RelativePositioning) + { + m_rtStart += *pCurrent; + } + + // set stop position + if(StopPosBits == AM_SEEKING_AbsolutePositioning) + { + m_rtStop = *pStop; + } + else if(StopPosBits == AM_SEEKING_IncrementalPositioning) + { + m_rtStop = m_rtStart + *pStop; + } + else if(StopPosBits == AM_SEEKING_RelativePositioning) + { + m_rtStop = m_rtStop + *pStop; + } + } + + + HRESULT hr = S_OK; + if(SUCCEEDED(hr) && StopPosBits) { + hr = ChangeStop(); + } + if(StartPosBits) { + hr = ChangeStart(); + } + + return hr; +} + + +HRESULT CSourceSeeking::GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ) +{ + if(pCurrent) { + *pCurrent = m_rtStart; + } + if(pStop) { + *pStop = m_rtStop; + } + + return S_OK; +} + + +HRESULT CSourceSeeking::GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ) +{ + if(pEarliest) { + *pEarliest = 0; + } + if(pLatest) { + CAutoLock lock(m_pLock); + *pLatest = m_rtDuration; + } + return S_OK; +} + +HRESULT CSourceSeeking::SetRate( double dRate) +{ + { + CAutoLock lock(m_pLock); + m_dRateSeeking = dRate; + } + return ChangeRate(); +} + +HRESULT CSourceSeeking::GetRate( __out double * pdRate) +{ + CheckPointer(pdRate, E_POINTER); + CAutoLock lock(m_pLock); + *pdRate = m_dRateSeeking; + return S_OK; +} + +HRESULT CSourceSeeking::GetPreroll(__out LONGLONG *pPreroll) +{ + CheckPointer(pPreroll, E_POINTER); + *pPreroll = 0; + return S_OK; +} + + + + + +// --- CSourcePosition implementation ---------- + + +CSourcePosition::CSourcePosition(__in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT* phr, + __in CCritSec * pLock) : + CMediaPosition(pName, pUnk), + m_pLock(pLock), + m_Start(CRefTime((LONGLONG)0)) +{ + m_Stop = _I64_MAX; + m_Rate = 1.0; +} + + +STDMETHODIMP +CSourcePosition::get_Duration(__out REFTIME * plength) +{ + CheckPointer(plength,E_POINTER); + ValidateReadWritePtr(plength,sizeof(REFTIME)); + CAutoLock lock(m_pLock); + + *plength = m_Duration; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_CurrentPosition(REFTIME llTime) +{ + m_pLock->Lock(); + m_Start = llTime; + m_pLock->Unlock(); + + return ChangeStart(); +} + + +STDMETHODIMP +CSourcePosition::get_StopTime(__out REFTIME * pllTime) +{ + CheckPointer(pllTime,E_POINTER); + ValidateReadWritePtr(pllTime,sizeof(REFTIME)); + CAutoLock lock(m_pLock); + + *pllTime = m_Stop; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_StopTime(REFTIME llTime) +{ + m_pLock->Lock(); + m_Stop = llTime; + m_pLock->Unlock(); + + return ChangeStop(); +} + + +STDMETHODIMP +CSourcePosition::get_PrerollTime(__out REFTIME * pllTime) +{ + CheckPointer(pllTime,E_POINTER); + ValidateReadWritePtr(pllTime,sizeof(REFTIME)); + return E_NOTIMPL; +} + + +STDMETHODIMP +CSourcePosition::put_PrerollTime(REFTIME llTime) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP +CSourcePosition::get_Rate(__out double * pdRate) +{ + CheckPointer(pdRate,E_POINTER); + ValidateReadWritePtr(pdRate,sizeof(double)); + CAutoLock lock(m_pLock); + + *pdRate = m_Rate; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_Rate(double dRate) +{ + m_pLock->Lock(); + m_Rate = dRate; + m_pLock->Unlock(); + + return ChangeRate(); +} + + +// By default we can seek forwards + +STDMETHODIMP +CSourcePosition::CanSeekForward(__out LONG *pCanSeekForward) +{ + CheckPointer(pCanSeekForward,E_POINTER); + *pCanSeekForward = OATRUE; + return S_OK; +} + + +// By default we can seek backwards + +STDMETHODIMP +CSourcePosition::CanSeekBackward(__out LONG *pCanSeekBackward) +{ + CheckPointer(pCanSeekBackward,E_POINTER); + *pCanSeekBackward = OATRUE; + return S_OK; +} + + +// --- Implementation of CBasicAudio class ---------- + + +CBasicAudio::CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + +// overriden to publicise our interfaces + +STDMETHODIMP +CBasicAudio::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IBasicAudio) { + return GetInterface( (IBasicAudio *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBasicAudio::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IBasicAudio, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBasicAudio::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IBasicAudio, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBasicAudio::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IBasicAudio *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IVideoWindow implementation ---------- + +CBaseVideoWindow::CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + + +// overriden to publicise our interfaces + +STDMETHODIMP +CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IVideoWindow) { + return GetInterface( (IVideoWindow *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBaseVideoWindow::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IVideoWindow, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBaseVideoWindow::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IVideoWindow, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBaseVideoWindow::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IVideoWindow *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IBasicVideo implementation ---------- + + +CBaseBasicVideo::CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + + +// overriden to publicise our interfaces + +STDMETHODIMP +CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) { + return GetInterface( static_cast(this), ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBaseBasicVideo::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IBasicVideo, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBaseBasicVideo::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IBasicVideo, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBaseBasicVideo::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IBasicVideo *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- Implementation of Deferred Commands ---------- + + +CDispParams::CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr) +{ + cNamedArgs = 0; + rgdispidNamedArgs = NULL; + cArgs = nArgs; + + if (cArgs) { + rgvarg = new VARIANT[cArgs]; + if (NULL == rgvarg) { + cArgs = 0; + if (phr) { + *phr = E_OUTOFMEMORY; + } + return; + } + + for (UINT i = 0; i < cArgs; i++) { + + // Why aren't we using VariantCopy? + + VARIANT * pDest = &rgvarg[i]; + VARIANT * pSrc = &pArgs[i]; + + pDest->vt = pSrc->vt; + switch(pDest->vt) { + + case VT_I4: + pDest->lVal = pSrc->lVal; + break; + + case VT_UI1: + pDest->bVal = pSrc->bVal; + break; + + case VT_I2: + pDest->iVal = pSrc->iVal; + break; + + case VT_R4: + pDest->fltVal = pSrc->fltVal; + break; + + case VT_R8: + pDest->dblVal = pSrc->dblVal; + break; + + case VT_BOOL: + pDest->boolVal = pSrc->boolVal; + break; + + case VT_ERROR: + pDest->scode = pSrc->scode; + break; + + case VT_CY: + pDest->cyVal = pSrc->cyVal; + break; + + case VT_DATE: + pDest->date = pSrc->date; + break; + + case VT_BSTR: + if ((PVOID)pSrc->bstrVal == NULL) { + pDest->bstrVal = NULL; + } else { + + // a BSTR is a WORD followed by a UNICODE string. + // the pointer points just after the WORD + + WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR))); + OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))]; + if (pch) { + WORD *pui = (WORD*)pch; + *pui = len; + pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR)); + CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR)); + } else { + cArgs = i; + if (phr) { + *phr = E_OUTOFMEMORY; + } + } + } + break; + + case VT_UNKNOWN: + pDest->punkVal = pSrc->punkVal; + pDest->punkVal->AddRef(); + break; + + case VT_DISPATCH: + pDest->pdispVal = pSrc->pdispVal; + pDest->pdispVal->AddRef(); + break; + + default: + // a type we haven't got round to adding yet! + ASSERT(0); + break; + } + } + + } else { + rgvarg = NULL; + } + +} + + +CDispParams::~CDispParams() +{ + for (UINT i = 0; i < cArgs; i++) { + switch(rgvarg[i].vt) { + case VT_BSTR: + // Explicitly cast BSTR to PVOID to tell code scanning tools we really mean to test the pointer + if ((PVOID)rgvarg[i].bstrVal != NULL) { + OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR)); + delete pch; + } + break; + + case VT_UNKNOWN: + rgvarg[i].punkVal->Release(); + break; + + case VT_DISPATCH: + rgvarg[i].pdispVal->Release(); + break; + } + } + delete[] rgvarg; +} + + +// lifetime is controlled by refcounts (see defer.h) + +CDeferredCommand::CDeferredCommand( + __inout CCmdQueue * pQ, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT * phr, + __in LPUNKNOWN pUnkExecutor, + REFTIME time, + __in GUID* iid, + long dispidMethod, + short wFlags, + long nArgs, + __in_ecount(nArgs) VARIANT* pDispParams, + __out VARIANT* pvarResult, + __out short* puArgErr, + BOOL bStream + ) : + CUnknown(NAME("DeferredCommand"), pUnk), + m_pQueue(pQ), + m_pUnk(pUnkExecutor), + m_iid(iid), + m_dispidMethod(dispidMethod), + m_wFlags(wFlags), + m_DispParams(nArgs, pDispParams, phr), + m_pvarResult(pvarResult), + m_bStream(bStream), + m_hrResult(E_ABORT), + m_DispId(0) + +{ + // convert REFTIME to REFERENCE_TIME + COARefTime convertor(time); + m_time = convertor; + + // no check of time validity - it's ok to queue a command that's + // already late + + // check iid is supportable on pUnk by QueryInterface for it + IUnknown * pInterface; + HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); + if (FAILED(hr)) { + *phr = hr; + return; + } + pInterface->Release(); + + + // !!! check dispidMethod and param/return types using typelib + ITypeInfo *pti; + hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti); + if (FAILED(hr)) { + *phr = hr; + return; + } + // !!! some sort of ITypeInfo validity check here + pti->Release(); + + + // Fix up the dispid for put and get + if (wFlags == DISPATCH_PROPERTYPUT) { + m_DispParams.cNamedArgs = 1; + m_DispId = DISPID_PROPERTYPUT; + m_DispParams.rgdispidNamedArgs = &m_DispId; + } + + // all checks ok - add to queue + hr = pQ->Insert(this); + if (FAILED(hr)) { + *phr = hr; + } +} + + +// refcounts are held by caller of InvokeAt... and by list. So if +// we get here, we can't be on the list + +#if 0 +CDeferredCommand::~CDeferredCommand() +{ + // this assert is invalid since if the queue is deleted while we are + // still on the queue, we will have been removed by the queue and this + // m_pQueue will not have been modified. + // ASSERT(m_pQueue == NULL); + + // we don't hold a ref count on pUnk, which is the object that should + // execute the command. + // This is because there would otherwise be a circular refcount problem + // since pUnk probably owns the CmdQueue object that has a refcount + // on us. + // The lifetime of pUnk is guaranteed by it being part of, or lifetime + // controlled by, our parent object. As long as we are on the list, pUnk + // must be valid. Once we are off the list, we do not use pUnk. + +} +#endif + + +// overriden to publicise our interfaces + +STDMETHODIMP +CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, __out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IDeferredCommand) { + return GetInterface( (IDeferredCommand *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// remove from q. this will reduce the refcount by one (since the q +// holds a count) but can't make us go away since he must have a +// refcount in order to call this method. + +STDMETHODIMP +CDeferredCommand::Cancel() +{ + if (m_pQueue == NULL) { + return VFW_E_ALREADY_CANCELLED; + } + + HRESULT hr = m_pQueue->Remove(this); + if (FAILED(hr)) { + return hr; + } + + m_pQueue = NULL; + return S_OK; +} + + +STDMETHODIMP +CDeferredCommand::Confidence(__out LONG* pConfidence) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP +CDeferredCommand::GetHResult(__out HRESULT * phrResult) +{ + CheckPointer(phrResult,E_POINTER); + ValidateReadWritePtr(phrResult,sizeof(HRESULT)); + + if (m_pQueue != NULL) { + return E_ABORT; + } + *phrResult = m_hrResult; + return S_OK; +} + + +// set the time to be a new time (checking that it is valid) and +// then requeue + +STDMETHODIMP +CDeferredCommand::Postpone(REFTIME newtime) +{ + + // check that this time is not past + // convert REFTIME to REFERENCE_TIME + COARefTime convertor(newtime); + + // check that the time has not passed + if (m_pQueue->CheckTime(convertor, IsStreamTime())) { + return VFW_E_TIME_ALREADY_PASSED; + } + + // extract from list + HRESULT hr = m_pQueue->Remove(this); + if (FAILED(hr)) { + return hr; + } + + // change time + m_time = convertor; + + // requeue + hr = m_pQueue->Insert(this); + + return hr; +} + + +HRESULT +CDeferredCommand::Invoke() +{ + // check that we are still outstanding + if (m_pQueue == NULL) { + return VFW_E_ALREADY_CANCELLED; + } + + // get the type info + ITypeInfo* pti; + HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti); + if (FAILED(hr)) { + return hr; + } + + // qi for the expected interface and then invoke it. Note that we have to + // treat the returned interface as IUnknown since we don't know its type. + IUnknown* pInterface; + + hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); + if (FAILED(hr)) { + pti->Release(); + return hr; + } + + EXCEPINFO expinfo; + UINT uArgErr; + m_hrResult = pti->Invoke( + pInterface, + GetMethod(), + GetFlags(), + GetParams(), + GetResult(), + &expinfo, + &uArgErr); + + // release the interface we QI'd for + pInterface->Release(); + pti->Release(); + + + // remove from list whether or not successful + // or we loop indefinitely + hr = m_pQueue->Remove(this); + m_pQueue = NULL; + return hr; +} + + + +// --- CCmdQueue methods ---------- + + +CCmdQueue::CCmdQueue(__inout_opt HRESULT *phr) : + m_listPresentation(NAME("Presentation time command list")), + m_listStream(NAME("Stream time command list")), + m_evDue(TRUE, phr), // manual reset + m_dwAdvise(0), + m_pClock(NULL), + m_bRunning(FALSE) +{ +} + + +CCmdQueue::~CCmdQueue() +{ + // empty all our lists + + // we hold a refcount on each, so traverse and Release each + // entry then RemoveAll to empty the list + POSITION pos = m_listPresentation.GetHeadPosition(); + + while(pos) { + CDeferredCommand* pCmd = m_listPresentation.GetNext(pos); + pCmd->Release(); + } + m_listPresentation.RemoveAll(); + + pos = m_listStream.GetHeadPosition(); + + while(pos) { + CDeferredCommand* pCmd = m_listStream.GetNext(pos); + pCmd->Release(); + } + m_listStream.RemoveAll(); + + if (m_pClock) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + m_dwAdvise = 0; + } + m_pClock->Release(); + } +} + + +// returns a new CDeferredCommand object that will be initialised with +// the parameters and will be added to the queue during construction. +// returns S_OK if successfully created otherwise an error and +// no object has been queued. + +HRESULT +CCmdQueue::New( + __out CDeferredCommand **ppCmd, + __in LPUNKNOWN pUnk, // this object will execute command + REFTIME time, + __in GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + __in_ecount(cArgs) VARIANT* pDispParams, + __out VARIANT* pvarResult, + __out short* puArgErr, + BOOL bStream +) +{ + CAutoLock lock(&m_Lock); + + HRESULT hr = S_OK; + *ppCmd = NULL; + + CDeferredCommand* pCmd; + pCmd = new CDeferredCommand( + this, + NULL, // not aggregated + &hr, + pUnk, // this guy will execute + time, + iid, + dispidMethod, + wFlags, + cArgs, + pDispParams, + pvarResult, + puArgErr, + bStream); + + if (pCmd == NULL) { + hr = E_OUTOFMEMORY; + } else { + *ppCmd = pCmd; + } + return hr; +} + + +HRESULT +CCmdQueue::Insert(__in CDeferredCommand* pCmd) +{ + CAutoLock lock(&m_Lock); + + // addref the item + pCmd->AddRef(); + + CGenericList * pList; + if (pCmd->IsStreamTime()) { + pList = &m_listStream; + } else { + pList = &m_listPresentation; + } + POSITION pos = pList->GetHeadPosition(); + + // seek past all items that are before us + while (pos && + (pList->GetValid(pos)->GetTime() <= pCmd->GetTime())) { + + pList->GetNext(pos); + } + + // now at end of list or in front of items that come later + if (!pos) { + pList->AddTail(pCmd); + } else { + pList->AddBefore(pos, pCmd); + } + + SetTimeAdvise(); + return S_OK; +} + + +HRESULT +CCmdQueue::Remove(__in CDeferredCommand* pCmd) +{ + CAutoLock lock(&m_Lock); + HRESULT hr = S_OK; + + CGenericList * pList; + if (pCmd->IsStreamTime()) { + pList = &m_listStream; + } else { + pList = &m_listPresentation; + } + POSITION pos = pList->GetHeadPosition(); + + // traverse the list + while (pos && (pList->GetValid(pos) != pCmd)) { + pList->GetNext(pos); + } + + // did we drop off the end? + if (!pos) { + hr = VFW_E_NOT_FOUND; + } else { + + // found it - now take off list + pList->Remove(pos); + + // Insert did an AddRef, so release it + pCmd->Release(); + + // check that timer request is still for earliest time + SetTimeAdvise(); + } + return hr; +} + + +// set the clock used for timing + +HRESULT +CCmdQueue::SetSyncSource(__in_opt IReferenceClock* pClock) +{ + CAutoLock lock(&m_Lock); + + // addref the new clock first in case they are the same + if (pClock) { + pClock->AddRef(); + } + + // kill any advise on the old clock + if (m_pClock) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + m_dwAdvise = 0; + } + m_pClock->Release(); + } + m_pClock = pClock; + + // set up a new advise + SetTimeAdvise(); + return S_OK; +} + + +// set up a timer event with the reference clock + +void +CCmdQueue::SetTimeAdvise(void) +{ + // make sure we have a clock to use + if (!m_pClock) { + return; + } + + // reset the event whenever we are requesting a new signal + m_evDue.Reset(); + + // time 0 is earliest + CRefTime current; + + // find the earliest presentation time + POSITION pos = m_listPresentation.GetHeadPosition(); + if (pos != NULL) { + current = m_listPresentation.GetValid(pos)->GetTime(); + } + + // if we're running, check the stream times too + if (m_bRunning) { + + CRefTime t; + pos = m_listStream.GetHeadPosition(); + if (NULL != pos) { + t = m_listStream.GetValid(pos)->GetTime(); + + // add on stream time offset to get presentation time + t += m_StreamTimeOffset; + + // is this earlier? + if ((current == TimeZero) || (t < current)) { + current = t; + } + } + } + + // need to change? + if ((current > TimeZero) && (current != m_tCurrentAdvise)) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + // reset the event whenever we are requesting a new signal + m_evDue.Reset(); + } + + // ask for time advice - the first two params are either + // stream time offset and stream time or + // presentation time and 0. we always use the latter + HRESULT hr = m_pClock->AdviseTime( + (REFERENCE_TIME)current, + TimeZero, + (HEVENT) HANDLE(m_evDue), + &m_dwAdvise); + + ASSERT(SUCCEEDED(hr)); + UNREFERENCED_PARAMETER(hr); + m_tCurrentAdvise = current; + } +} + + +// switch to run mode. Streamtime to Presentation time mapping known. + +HRESULT +CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset) +{ + CAutoLock lock(&m_Lock); + + m_StreamTimeOffset = tStreamTimeOffset; + m_bRunning = TRUE; + + // ensure advise is accurate + SetTimeAdvise(); + return S_OK; +} + + +// switch to Stopped or Paused mode. Time mapping not known. + +HRESULT +CCmdQueue::EndRun() +{ + CAutoLock lock(&m_Lock); + + m_bRunning = FALSE; + + // check timer setting - stream times + SetTimeAdvise(); + return S_OK; +} + + +// return a pointer to the next due command. Blocks for msTimeout +// milliseconds until there is a due command. +// Stream-time commands will only become due between Run and Endrun calls. +// The command remains queued until invoked or cancelled. +// Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). +// +// returns an AddRef'd object + +HRESULT +CCmdQueue::GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout) +{ + // loop until we timeout or find a due command + for (;;) { + + { + CAutoLock lock(&m_Lock); + + + // find the earliest command + CDeferredCommand * pCmd = NULL; + + // check the presentation time and the + // stream time list to find the earliest + + POSITION pos = m_listPresentation.GetHeadPosition(); + + if (NULL != pos) { + pCmd = m_listPresentation.GetValid(pos); + } + + if (m_bRunning) { + pos = m_listStream.GetHeadPosition(); + if (NULL != pos) { + CDeferredCommand* pStrm = m_listStream.GetValid(pos); + + CRefTime t = pStrm->GetTime() + m_StreamTimeOffset; + if (!pCmd || (t < pCmd->GetTime())) { + pCmd = pStrm; + } + } + } + + // if we have found one, is it due? + if (pCmd) { + if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) { + + // yes it's due - addref it + pCmd->AddRef(); + *ppCmd = pCmd; + return S_OK; + } + } + } + + // block until the advise is signalled + if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) { + return E_ABORT; + } + } +} + + +// return a pointer to a command that will be due for a given time. +// Pass in a stream time here. The stream time offset will be passed +// in via the Run method. +// Commands remain queued until invoked or cancelled. +// This method will not block. It will report E_ABORT if there are no +// commands due yet. +// +// returns an AddRef'd object + +HRESULT +CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, __out CDeferredCommand**ppCmd) +{ + CAutoLock lock(&m_Lock); + + CRefTime tStream(rtStream); + + // find the earliest stream and presentation time commands + CDeferredCommand* pStream = NULL; + POSITION pos = m_listStream.GetHeadPosition(); + if (NULL != pos) { + pStream = m_listStream.GetValid(pos); + } + CDeferredCommand* pPresent = NULL; + pos = m_listPresentation.GetHeadPosition(); + if (NULL != pos) { + pPresent = m_listPresentation.GetValid(pos); + } + + // is there a presentation time that has passed already + if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) { + pPresent->AddRef(); + *ppCmd = pPresent; + return S_OK; + } + + // is there a stream time command due before this stream time + if (pStream && (pStream->GetTime() <= tStream)) { + pStream->AddRef(); + *ppCmd = pStream; + return S_OK; + } + + // if we are running, we can map presentation times to + // stream time. In this case, is there a presentation time command + // that will be due before this stream time is presented? + if (m_bRunning && pPresent) { + + // this stream time will appear at... + tStream += m_StreamTimeOffset; + + // due before that? + if (pPresent->GetTime() <= tStream) { + *ppCmd = pPresent; + return S_OK; + } + } + + // no commands due yet + return VFW_E_NOT_FOUND; +} + diff --git a/src/thirdparty/BaseClasses/ctlutil.h b/src/thirdparty/BaseClasses/ctlutil.h index 79af5e1df23..0c6665ef2e0 100644 --- a/src/thirdparty/BaseClasses/ctlutil.h +++ b/src/thirdparty/BaseClasses/ctlutil.h @@ -1,923 +1,923 @@ -//------------------------------------------------------------------------------ -// File: CtlUtil.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Base classes implementing IDispatch parsing for the basic control dual -// interfaces. Derive from these and implement just the custom method and -// property methods. We also implement CPosPassThru that can be used by -// renderers and transforms to pass by IMediaPosition and IMediaSeeking - -#ifndef __CTLUTIL__ -#define __CTLUTIL__ - -// OLE Automation has different ideas of TRUE and FALSE - -#define OATRUE (-1) -#define OAFALSE (0) - - -// It's possible that we could replace this class with CreateStdDispatch - -class CBaseDispatch -{ - ITypeInfo * m_pti; - -public: - - CBaseDispatch() : m_pti(NULL) {} - ~CBaseDispatch(); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - REFIID riid, - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); -}; - - -class AM_NOVTABLE CMediaControl : - public IMediaControl, - public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CMediaControl(const TCHAR *, LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); -}; - - -class AM_NOVTABLE CMediaEvent : - public IMediaEventEx, - public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CMediaEvent(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); -}; - - -class AM_NOVTABLE CMediaPosition : - public IMediaPosition, - public CUnknown -{ - CBaseDispatch m_basedisp; - - -public: - - CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT *phr); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); - -}; - - -// OA-compatibility means that we must use double as the RefTime value, -// and REFERENCE_TIME (essentially a LONGLONG) within filters. -// this class converts between the two - -class COARefTime : public CRefTime { -public: - - COARefTime() { - }; - - COARefTime(CRefTime t) - : CRefTime(t) - { - }; - - COARefTime(REFERENCE_TIME t) - : CRefTime(t) - { - }; - - COARefTime(double d) { - m_time = (LONGLONG) (d * 10000000); - }; - - operator double() { - return double(m_time) / 10000000; - }; - - operator REFERENCE_TIME() { - return m_time; - }; - - COARefTime& operator=(const double& rd) { - m_time = (LONGLONG) (rd * 10000000); - return *this; - } - - COARefTime& operator=(const REFERENCE_TIME& rt) { - m_time = rt; - return *this; - } - - inline BOOL operator==(const COARefTime& rt) - { - return m_time == rt.m_time; - }; - - inline BOOL operator!=(const COARefTime& rt) - { - return m_time != rt.m_time; - }; - - inline BOOL operator < (const COARefTime& rt) - { - return m_time < rt.m_time; - }; - - inline BOOL operator > (const COARefTime& rt) - { - return m_time > rt.m_time; - }; - - inline BOOL operator >= (const COARefTime& rt) - { - return m_time >= rt.m_time; - }; - - inline BOOL operator <= (const COARefTime& rt) - { - return m_time <= rt.m_time; - }; - - inline COARefTime operator+(const COARefTime& rt) - { - return COARefTime(m_time + rt.m_time); - }; - - inline COARefTime operator-(const COARefTime& rt) - { - return COARefTime(m_time - rt.m_time); - }; - - inline COARefTime operator*(LONG l) - { - return COARefTime(m_time * l); - }; - - inline COARefTime operator/(LONG l) - { - return COARefTime(m_time / l); - }; - -private: - // Prevent bugs from constructing from LONG (which gets - // converted to double and then multiplied by 10000000 - COARefTime(LONG); - LONG operator=(LONG); -}; - - -// A utility class that handles IMediaPosition and IMediaSeeking on behalf -// of single-input pin renderers, or transform filters. -// -// Renderers will expose this from the filter; transform filters will -// expose it from the output pin and not the renderer. -// -// Create one of these, giving it your IPin* for your input pin, and delegate -// all IMediaPosition methods to it. It will query the input pin for -// IMediaPosition and respond appropriately. -// -// Call ForceRefresh if the pin connection changes. -// -// This class no longer caches the upstream IMediaPosition or IMediaSeeking -// it acquires it on each method call. This means ForceRefresh is not needed. -// The method is kept for source compatibility and to minimise the changes -// if we need to put it back later for performance reasons. - -class CPosPassThru : public IMediaSeeking, public CMediaPosition -{ - IPin *m_pPin; - - HRESULT GetPeer(__deref_out IMediaPosition **ppMP); - HRESULT GetPeerSeeking(__deref_out IMediaSeeking **ppMS); - -public: - - CPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); - DECLARE_IUNKNOWN - - HRESULT ForceRefresh() { - return S_OK; - }; - - // override to return an accurate current position - virtual HRESULT GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) { - return E_FAIL; - } - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); - - // IMediaSeeking methods - STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); - STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); - STDMETHODIMP SetTimeFormat(const GUID * pFormat); - STDMETHODIMP GetTimeFormat(__out GUID *pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); - STDMETHODIMP IsFormatSupported( const GUID * pFormat); - STDMETHODIMP QueryPreferredFormat( __out GUID *pFormat); - STDMETHODIMP ConvertTimeFormat(__out LONGLONG * pTarget, - __in_opt const GUID * pTargetFormat, - LONGLONG Source, - __in_opt const GUID * pSourceFormat ); - STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags - , __inout_opt LONGLONG * pStop, DWORD StopFlags ); - - STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); - STDMETHODIMP GetCurrentPosition( __out LONGLONG * pCurrent ); - STDMETHODIMP GetStopPosition( __out LONGLONG * pStop ); - STDMETHODIMP SetRate( double dRate); - STDMETHODIMP GetRate( __out double * pdRate); - STDMETHODIMP GetDuration( __out LONGLONG *pDuration); - STDMETHODIMP GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ); - STDMETHODIMP GetPreroll( __out LONGLONG *pllPreroll ); - - // IMediaPosition properties - STDMETHODIMP get_Duration(__out REFTIME * plength); - STDMETHODIMP put_CurrentPosition(REFTIME llTime); - STDMETHODIMP get_StopTime(__out REFTIME * pllTime); - STDMETHODIMP put_StopTime(REFTIME llTime); - STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); - STDMETHODIMP put_PrerollTime(REFTIME llTime); - STDMETHODIMP get_Rate(__out double * pdRate); - STDMETHODIMP put_Rate(double dRate); - STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime); - STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); - STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); - -private: - HRESULT GetSeekingLongLong( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ), - __out LONGLONG * pll ); -}; - - -// Adds the ability to return a current position - -class CRendererPosPassThru : public CPosPassThru -{ - CCritSec m_PositionLock; // Locks access to our position - LONGLONG m_StartMedia; // Start media time last seen - LONGLONG m_EndMedia; // And likewise the end media - BOOL m_bReset; // Have media times been set - -public: - - // Used to help with passing media times through graph - - CRendererPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); - HRESULT RegisterMediaTime(IMediaSample *pMediaSample); - HRESULT RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime); - HRESULT GetMediaTime(__out LONGLONG *pStartTime,__out_opt LONGLONG *pEndTime); - HRESULT ResetMediaTime(); - HRESULT EOS(); -}; - -STDAPI CreatePosPassThru( - __in_opt LPUNKNOWN pAgg, - BOOL bRenderer, - IPin *pPin, - __deref_out IUnknown **ppPassThru -); - -// A class that handles the IDispatch part of IBasicAudio and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBasicAudio : public IBasicAudio, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBasicAudio(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); -}; - - -// A class that handles the IDispatch part of IBasicVideo and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBaseBasicVideo : public IBasicVideo2, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBaseBasicVideo(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); - - STDMETHODIMP GetPreferredAspectRatio( - __out long *plAspectX, - __out long *plAspectY) - { - return E_NOTIMPL; - } -}; - - -// A class that handles the IDispatch part of IVideoWindow and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBaseVideoWindow : public IVideoWindow, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBaseVideoWindow(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); -}; - - -// abstract class to help source filters with their implementation -// of IMediaPosition. Derive from this and set the duration (and stop -// position). Also override NotifyChange to do something when the properties -// change. - -class AM_NOVTABLE CSourcePosition : public CMediaPosition -{ - -public: - CSourcePosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); - - // IMediaPosition methods - STDMETHODIMP get_Duration(__out REFTIME * plength); - STDMETHODIMP put_CurrentPosition(REFTIME llTime); - STDMETHODIMP get_StopTime(__out REFTIME * pllTime); - STDMETHODIMP put_StopTime(REFTIME llTime); - STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); - STDMETHODIMP put_PrerollTime(REFTIME llTime); - STDMETHODIMP get_Rate(__out double * pdRate); - STDMETHODIMP put_Rate(double dRate); - STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); - STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); - - // override if you can return the data you are actually working on - STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime) { - return E_NOTIMPL; - }; - -protected: - - // we call this to notify changes. Override to handle them - virtual HRESULT ChangeStart() PURE; - virtual HRESULT ChangeStop() PURE; - virtual HRESULT ChangeRate() PURE; - - COARefTime m_Duration; - COARefTime m_Start; - COARefTime m_Stop; - double m_Rate; - - CCritSec * m_pLock; -}; - -class AM_NOVTABLE CSourceSeeking : - public IMediaSeeking, - public CUnknown -{ - -public: - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - // IMediaSeeking methods - - STDMETHODIMP IsFormatSupported(const GUID * pFormat); - STDMETHODIMP QueryPreferredFormat(__out GUID *pFormat); - STDMETHODIMP SetTimeFormat(const GUID * pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); - STDMETHODIMP GetTimeFormat(__out GUID *pFormat); - STDMETHODIMP GetDuration(__out LONGLONG *pDuration); - STDMETHODIMP GetStopPosition(__out LONGLONG *pStop); - STDMETHODIMP GetCurrentPosition(__out LONGLONG *pCurrent); - STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); - STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); - STDMETHODIMP ConvertTimeFormat( __out LONGLONG * pTarget, - __in_opt const GUID * pTargetFormat, - LONGLONG Source, - __in_opt const GUID * pSourceFormat ); - - STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags - , __inout_opt LONGLONG * pStop, DWORD StopFlags ); - - STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); - - STDMETHODIMP GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ); - STDMETHODIMP SetRate( double dRate); - STDMETHODIMP GetRate( __out double * pdRate); - STDMETHODIMP GetPreroll(__out LONGLONG *pPreroll); - - -protected: - - // ctor - CSourceSeeking(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); - - // we call this to notify changes. Override to handle them - virtual HRESULT ChangeStart() PURE; - virtual HRESULT ChangeStop() PURE; - virtual HRESULT ChangeRate() PURE; - - REFERENCE_TIME m_rtDuration; // length of stream - REFERENCE_TIME m_rtStart; // source will start here - REFERENCE_TIME m_rtStop; // source will stop here - double m_dRateSeeking; - - // seeking capabilities - DWORD m_dwSeekingCaps; - - CCritSec * m_pLock; -}; - - -// Base classes supporting Deferred commands. - -// Deferred commands are queued by calls to methods on the IQueueCommand -// interface, exposed by the filtergraph and by some filters. A successful -// call to one of these methods will return an IDeferredCommand interface -// representing the queued command. -// -// A CDeferredCommand object represents a single deferred command, and exposes -// the IDeferredCommand interface as well as other methods permitting time -// checks and actual execution. It contains a reference to the CCommandQueue -// object on which it is queued. -// -// CCommandQueue is a base class providing a queue of CDeferredCommand -// objects, and methods to add, remove, check status and invoke the queued -// commands. A CCommandQueue object would be part of an object that -// implemented IQueueCommand. - -class CCmdQueue; - -// take a copy of the params and store them. Release any allocated -// memory in destructor - -class CDispParams : public DISPPARAMS -{ -public: - CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr = NULL); - ~CDispParams(); -}; - - -// CDeferredCommand lifetime is controlled by refcounts. Caller of -// InvokeAt.. gets a refcounted interface pointer, and the CCmdQueue -// object also holds a refcount on us. Calling Cancel or Invoke takes -// us off the CCmdQueue and thus reduces the refcount by 1. Once taken -// off the queue we cannot be put back on the queue. - -class CDeferredCommand - : public CUnknown, - public IDeferredCommand -{ -public: - - CDeferredCommand( - __inout CCmdQueue * pQ, - __in_opt LPUNKNOWN pUnk, // aggregation outer unk - __inout HRESULT * phr, - __in LPUNKNOWN pUnkExecutor, // object that will execute this cmd - REFTIME time, - __in GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - __in_ecount(cArgs) VARIANT* pDispParams, - __out VARIANT* pvarResult, - __out short* puArgErr, - BOOL bStream - ); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __out void **ppv); - - // IDeferredCommand methods - STDMETHODIMP Cancel(); - STDMETHODIMP Confidence( - __out LONG* pConfidence); - STDMETHODIMP Postpone( - REFTIME newtime); - STDMETHODIMP GetHResult( - __out HRESULT* phrResult); - - // other public methods - - HRESULT Invoke(); - - // access methods - - // returns TRUE if streamtime, FALSE if presentation time - BOOL IsStreamTime() { - return m_bStream; - }; - - CRefTime GetTime() { - return m_time; - }; - - REFIID GetIID() { - return *m_iid; - }; - - long GetMethod() { - return m_dispidMethod; - }; - - short GetFlags() { - return m_wFlags; - }; - - DISPPARAMS* GetParams() { - return &m_DispParams; - }; - - VARIANT* GetResult() { - return m_pvarResult; - }; - -protected: - - CCmdQueue* m_pQueue; - - // pUnk for the interface that we will execute the command on - LPUNKNOWN m_pUnk; - - // stored command data - REFERENCE_TIME m_time; - GUID* m_iid; - long m_dispidMethod; - short m_wFlags; - VARIANT* m_pvarResult; - BOOL m_bStream; - CDispParams m_DispParams; - DISPID m_DispId; // For get and put - - // we use this for ITypeInfo access - CBaseDispatch m_Dispatch; - - // save retval here - HRESULT m_hrResult; -}; - - -// a list of CDeferredCommand objects. this is a base class providing -// the basics of access to the list. If you want to use CDeferredCommand -// objects then your queue needs to be derived from this class. - -class AM_NOVTABLE CCmdQueue -{ -public: - CCmdQueue(__inout_opt HRESULT *phr = NULL); - virtual ~CCmdQueue(); - - // returns a new CDeferredCommand object that will be initialised with - // the parameters and will be added to the queue during construction. - // returns S_OK if successfully created otherwise an error and - // no object has been queued. - virtual HRESULT New( - __out CDeferredCommand **ppCmd, - __in LPUNKNOWN pUnk, - REFTIME time, - __in GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - __in_ecount(cArgs) VARIANT* pDispParams, - __out VARIANT* pvarResult, - __out short* puArgErr, - BOOL bStream - ); - - // called by the CDeferredCommand object to add and remove itself - // from the queue - virtual HRESULT Insert(__in CDeferredCommand* pCmd); - virtual HRESULT Remove(__in CDeferredCommand* pCmd); - - // Command-Due Checking - // - // There are two schemes of synchronisation: coarse and accurate. In - // coarse mode, you wait till the time arrives and then execute the cmd. - // In accurate mode, you wait until you are processing the sample that - // will appear at the time, and then execute the command. It's up to the - // filter which one it will implement. The filtergraph will always - // implement coarse mode for commands queued at the filtergraph. - // - // If you want coarse sync, you probably want to wait until there is a - // command due, and then execute it. You can do this by calling - // GetDueCommand. If you have several things to wait for, get the - // event handle from GetDueHandle() and when this is signalled then call - // GetDueCommand. Stream time will only advance between calls to Run and - // EndRun. Note that to avoid an extra thread there is no guarantee that - // if the handle is set there will be a command ready. Each time the - // event is signalled, call GetDueCommand (probably with a 0 timeout); - // This may return E_ABORT. - // - // If you want accurate sync, you must call GetCommandDueFor, passing - // as a parameter the stream time of the samples you are about to process. - // This will return: - // -- a stream-time command due at or before that stream time - // -- a presentation-time command due at or before the - // time that stream time will be presented (only between Run - // and EndRun calls, since outside of this, the mapping from - // stream time to presentation time is not known. - // -- any presentation-time command due now. - // This means that if you want accurate synchronisation on samples that - // might be processed during Paused mode, you need to use - // stream-time commands. - // - // In all cases, commands remain queued until Invoked or Cancelled. The - // setting and resetting of the event handle is managed entirely by this - // queue object. - - // set the clock used for timing - virtual HRESULT SetSyncSource(__in_opt IReferenceClock*); - - // switch to run mode. Streamtime to Presentation time mapping known. - virtual HRESULT Run(REFERENCE_TIME tStreamTimeOffset); - - // switch to Stopped or Paused mode. Time mapping not known. - virtual HRESULT EndRun(); - - // return a pointer to the next due command. Blocks for msTimeout - // milliseconds until there is a due command. - // Stream-time commands will only become due between Run and Endrun calls. - // The command remains queued until invoked or cancelled. - // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). - // Returns an AddRef-ed object - virtual HRESULT GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout); - - // return the event handle that will be signalled whenever - // there are deferred commands due for execution (when GetDueCommand - // will not block). - HANDLE GetDueHandle() { - return HANDLE(m_evDue); - }; - - // return a pointer to a command that will be due for a given time. - // Pass in a stream time here. The stream time offset will be passed - // in via the Run method. - // Commands remain queued until invoked or cancelled. - // This method will not block. It will report VFW_E_NOT_FOUND if there - // are no commands due yet. - // Returns an AddRef-ed object - virtual HRESULT GetCommandDueFor(REFERENCE_TIME tStream, __out CDeferredCommand**ppCmd); - - // check if a given time is due (TRUE if it is due yet) - BOOL CheckTime(CRefTime time, BOOL bStream) { - - // if no clock, nothing is due! - if (!m_pClock) { - return FALSE; - } - - // stream time - if (bStream) { - - // not valid if not running - if (!m_bRunning) { - return FALSE; - } - // add on known stream time offset to get presentation time - time += m_StreamTimeOffset; - } - - CRefTime Now; - m_pClock->GetTime((REFERENCE_TIME*)&Now); - return (time <= Now); - }; - -protected: - - // protect access to lists etc - CCritSec m_Lock; - - // commands queued in presentation time are stored here - CGenericList m_listPresentation; - - // commands queued in stream time are stored here - CGenericList m_listStream; - - // set when any commands are due - CAMEvent m_evDue; - - // creates an advise for the earliest time required, if any - void SetTimeAdvise(void); - - // advise id from reference clock (0 if no outstanding advise) - DWORD_PTR m_dwAdvise; - - // advise time is for this presentation time - CRefTime m_tCurrentAdvise; - - // the reference clock we are using (addrefed) - IReferenceClock* m_pClock; - - // true when running - BOOL m_bRunning; - - // contains stream time offset when m_bRunning is true - CRefTime m_StreamTimeOffset; -}; - -#endif // __CTLUTIL__ +//------------------------------------------------------------------------------ +// File: CtlUtil.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Base classes implementing IDispatch parsing for the basic control dual +// interfaces. Derive from these and implement just the custom method and +// property methods. We also implement CPosPassThru that can be used by +// renderers and transforms to pass by IMediaPosition and IMediaSeeking + +#ifndef __CTLUTIL__ +#define __CTLUTIL__ + +// OLE Automation has different ideas of TRUE and FALSE + +#define OATRUE (-1) +#define OAFALSE (0) + + +// It's possible that we could replace this class with CreateStdDispatch + +class CBaseDispatch +{ + ITypeInfo * m_pti; + +public: + + CBaseDispatch() : m_pti(NULL) {} + ~CBaseDispatch(); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + REFIID riid, + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); +}; + + +class AM_NOVTABLE CMediaControl : + public IMediaControl, + public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CMediaControl(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); +}; + + +class AM_NOVTABLE CMediaEvent : + public IMediaEventEx, + public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CMediaEvent(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); +}; + + +class AM_NOVTABLE CMediaPosition : + public IMediaPosition, + public CUnknown +{ + CBaseDispatch m_basedisp; + + +public: + + CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT *phr); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); + +}; + + +// OA-compatibility means that we must use double as the RefTime value, +// and REFERENCE_TIME (essentially a LONGLONG) within filters. +// this class converts between the two + +class COARefTime : public CRefTime { +public: + + COARefTime() { + }; + + COARefTime(CRefTime t) + : CRefTime(t) + { + }; + + COARefTime(REFERENCE_TIME t) + : CRefTime(t) + { + }; + + COARefTime(double d) { + m_time = (LONGLONG) (d * 10000000); + }; + + operator double() { + return double(m_time) / 10000000; + }; + + operator REFERENCE_TIME() { + return m_time; + }; + + COARefTime& operator=(const double& rd) { + m_time = (LONGLONG) (rd * 10000000); + return *this; + } + + COARefTime& operator=(const REFERENCE_TIME& rt) { + m_time = rt; + return *this; + } + + inline BOOL operator==(const COARefTime& rt) + { + return m_time == rt.m_time; + }; + + inline BOOL operator!=(const COARefTime& rt) + { + return m_time != rt.m_time; + }; + + inline BOOL operator < (const COARefTime& rt) + { + return m_time < rt.m_time; + }; + + inline BOOL operator > (const COARefTime& rt) + { + return m_time > rt.m_time; + }; + + inline BOOL operator >= (const COARefTime& rt) + { + return m_time >= rt.m_time; + }; + + inline BOOL operator <= (const COARefTime& rt) + { + return m_time <= rt.m_time; + }; + + inline COARefTime operator+(const COARefTime& rt) + { + return COARefTime(m_time + rt.m_time); + }; + + inline COARefTime operator-(const COARefTime& rt) + { + return COARefTime(m_time - rt.m_time); + }; + + inline COARefTime operator*(LONG l) + { + return COARefTime(m_time * l); + }; + + inline COARefTime operator/(LONG l) + { + return COARefTime(m_time / l); + }; + +private: + // Prevent bugs from constructing from LONG (which gets + // converted to double and then multiplied by 10000000 + COARefTime(LONG); + LONG operator=(LONG); +}; + + +// A utility class that handles IMediaPosition and IMediaSeeking on behalf +// of single-input pin renderers, or transform filters. +// +// Renderers will expose this from the filter; transform filters will +// expose it from the output pin and not the renderer. +// +// Create one of these, giving it your IPin* for your input pin, and delegate +// all IMediaPosition methods to it. It will query the input pin for +// IMediaPosition and respond appropriately. +// +// Call ForceRefresh if the pin connection changes. +// +// This class no longer caches the upstream IMediaPosition or IMediaSeeking +// it acquires it on each method call. This means ForceRefresh is not needed. +// The method is kept for source compatibility and to minimise the changes +// if we need to put it back later for performance reasons. + +class CPosPassThru : public IMediaSeeking, public CMediaPosition +{ + IPin *m_pPin; + + HRESULT GetPeer(__deref_out IMediaPosition **ppMP); + HRESULT GetPeerSeeking(__deref_out IMediaSeeking **ppMS); + +public: + + CPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); + DECLARE_IUNKNOWN + + HRESULT ForceRefresh() { + return S_OK; + }; + + // override to return an accurate current position + virtual HRESULT GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) { + return E_FAIL; + } + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); + + // IMediaSeeking methods + STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); + STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); + STDMETHODIMP SetTimeFormat(const GUID * pFormat); + STDMETHODIMP GetTimeFormat(__out GUID *pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); + STDMETHODIMP IsFormatSupported( const GUID * pFormat); + STDMETHODIMP QueryPreferredFormat( __out GUID *pFormat); + STDMETHODIMP ConvertTimeFormat(__out LONGLONG * pTarget, + __in_opt const GUID * pTargetFormat, + LONGLONG Source, + __in_opt const GUID * pSourceFormat ); + STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags + , __inout_opt LONGLONG * pStop, DWORD StopFlags ); + + STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); + STDMETHODIMP GetCurrentPosition( __out LONGLONG * pCurrent ); + STDMETHODIMP GetStopPosition( __out LONGLONG * pStop ); + STDMETHODIMP SetRate( double dRate); + STDMETHODIMP GetRate( __out double * pdRate); + STDMETHODIMP GetDuration( __out LONGLONG *pDuration); + STDMETHODIMP GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ); + STDMETHODIMP GetPreroll( __out LONGLONG *pllPreroll ); + + // IMediaPosition properties + STDMETHODIMP get_Duration(__out REFTIME * plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(__out REFTIME * pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(__out double * pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime); + STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); + STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); + +private: + HRESULT GetSeekingLongLong( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ), + __out LONGLONG * pll ); +}; + + +// Adds the ability to return a current position + +class CRendererPosPassThru : public CPosPassThru +{ + CCritSec m_PositionLock; // Locks access to our position + LONGLONG m_StartMedia; // Start media time last seen + LONGLONG m_EndMedia; // And likewise the end media + BOOL m_bReset; // Have media times been set + +public: + + // Used to help with passing media times through graph + + CRendererPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); + HRESULT RegisterMediaTime(IMediaSample *pMediaSample); + HRESULT RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime); + HRESULT GetMediaTime(__out LONGLONG *pStartTime,__out_opt LONGLONG *pEndTime); + HRESULT ResetMediaTime(); + HRESULT EOS(); +}; + +STDAPI CreatePosPassThru( + __in_opt LPUNKNOWN pAgg, + BOOL bRenderer, + IPin *pPin, + __deref_out IUnknown **ppPassThru +); + +// A class that handles the IDispatch part of IBasicAudio and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBasicAudio : public IBasicAudio, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBasicAudio(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); +}; + + +// A class that handles the IDispatch part of IBasicVideo and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBaseBasicVideo : public IBasicVideo2, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBaseBasicVideo(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); + + STDMETHODIMP GetPreferredAspectRatio( + __out long *plAspectX, + __out long *plAspectY) + { + return E_NOTIMPL; + } +}; + + +// A class that handles the IDispatch part of IVideoWindow and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBaseVideoWindow : public IVideoWindow, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBaseVideoWindow(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); +}; + + +// abstract class to help source filters with their implementation +// of IMediaPosition. Derive from this and set the duration (and stop +// position). Also override NotifyChange to do something when the properties +// change. + +class AM_NOVTABLE CSourcePosition : public CMediaPosition +{ + +public: + CSourcePosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); + + // IMediaPosition methods + STDMETHODIMP get_Duration(__out REFTIME * plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(__out REFTIME * pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(__out double * pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); + STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); + + // override if you can return the data you are actually working on + STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime) { + return E_NOTIMPL; + }; + +protected: + + // we call this to notify changes. Override to handle them + virtual HRESULT ChangeStart() PURE; + virtual HRESULT ChangeStop() PURE; + virtual HRESULT ChangeRate() PURE; + + COARefTime m_Duration; + COARefTime m_Start; + COARefTime m_Stop; + double m_Rate; + + CCritSec * m_pLock; +}; + +class AM_NOVTABLE CSourceSeeking : + public IMediaSeeking, + public CUnknown +{ + +public: + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + // IMediaSeeking methods + + STDMETHODIMP IsFormatSupported(const GUID * pFormat); + STDMETHODIMP QueryPreferredFormat(__out GUID *pFormat); + STDMETHODIMP SetTimeFormat(const GUID * pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); + STDMETHODIMP GetTimeFormat(__out GUID *pFormat); + STDMETHODIMP GetDuration(__out LONGLONG *pDuration); + STDMETHODIMP GetStopPosition(__out LONGLONG *pStop); + STDMETHODIMP GetCurrentPosition(__out LONGLONG *pCurrent); + STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); + STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); + STDMETHODIMP ConvertTimeFormat( __out LONGLONG * pTarget, + __in_opt const GUID * pTargetFormat, + LONGLONG Source, + __in_opt const GUID * pSourceFormat ); + + STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags + , __inout_opt LONGLONG * pStop, DWORD StopFlags ); + + STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); + + STDMETHODIMP GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ); + STDMETHODIMP SetRate( double dRate); + STDMETHODIMP GetRate( __out double * pdRate); + STDMETHODIMP GetPreroll(__out LONGLONG *pPreroll); + + +protected: + + // ctor + CSourceSeeking(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); + + // we call this to notify changes. Override to handle them + virtual HRESULT ChangeStart() PURE; + virtual HRESULT ChangeStop() PURE; + virtual HRESULT ChangeRate() PURE; + + REFERENCE_TIME m_rtDuration; // length of stream + REFERENCE_TIME m_rtStart; // source will start here + REFERENCE_TIME m_rtStop; // source will stop here + double m_dRateSeeking; + + // seeking capabilities + DWORD m_dwSeekingCaps; + + CCritSec * m_pLock; +}; + + +// Base classes supporting Deferred commands. + +// Deferred commands are queued by calls to methods on the IQueueCommand +// interface, exposed by the filtergraph and by some filters. A successful +// call to one of these methods will return an IDeferredCommand interface +// representing the queued command. +// +// A CDeferredCommand object represents a single deferred command, and exposes +// the IDeferredCommand interface as well as other methods permitting time +// checks and actual execution. It contains a reference to the CCommandQueue +// object on which it is queued. +// +// CCommandQueue is a base class providing a queue of CDeferredCommand +// objects, and methods to add, remove, check status and invoke the queued +// commands. A CCommandQueue object would be part of an object that +// implemented IQueueCommand. + +class CCmdQueue; + +// take a copy of the params and store them. Release any allocated +// memory in destructor + +class CDispParams : public DISPPARAMS +{ +public: + CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr = NULL); + ~CDispParams(); +}; + + +// CDeferredCommand lifetime is controlled by refcounts. Caller of +// InvokeAt.. gets a refcounted interface pointer, and the CCmdQueue +// object also holds a refcount on us. Calling Cancel or Invoke takes +// us off the CCmdQueue and thus reduces the refcount by 1. Once taken +// off the queue we cannot be put back on the queue. + +class CDeferredCommand + : public CUnknown, + public IDeferredCommand +{ +public: + + CDeferredCommand( + __inout CCmdQueue * pQ, + __in_opt LPUNKNOWN pUnk, // aggregation outer unk + __inout HRESULT * phr, + __in LPUNKNOWN pUnkExecutor, // object that will execute this cmd + REFTIME time, + __in GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + __in_ecount(cArgs) VARIANT* pDispParams, + __out VARIANT* pvarResult, + __out short* puArgErr, + BOOL bStream + ); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __out void **ppv); + + // IDeferredCommand methods + STDMETHODIMP Cancel(); + STDMETHODIMP Confidence( + __out LONG* pConfidence); + STDMETHODIMP Postpone( + REFTIME newtime); + STDMETHODIMP GetHResult( + __out HRESULT* phrResult); + + // other public methods + + HRESULT Invoke(); + + // access methods + + // returns TRUE if streamtime, FALSE if presentation time + BOOL IsStreamTime() { + return m_bStream; + }; + + CRefTime GetTime() { + return m_time; + }; + + REFIID GetIID() { + return *m_iid; + }; + + long GetMethod() { + return m_dispidMethod; + }; + + short GetFlags() { + return m_wFlags; + }; + + DISPPARAMS* GetParams() { + return &m_DispParams; + }; + + VARIANT* GetResult() { + return m_pvarResult; + }; + +protected: + + CCmdQueue* m_pQueue; + + // pUnk for the interface that we will execute the command on + LPUNKNOWN m_pUnk; + + // stored command data + REFERENCE_TIME m_time; + GUID* m_iid; + long m_dispidMethod; + short m_wFlags; + VARIANT* m_pvarResult; + BOOL m_bStream; + CDispParams m_DispParams; + DISPID m_DispId; // For get and put + + // we use this for ITypeInfo access + CBaseDispatch m_Dispatch; + + // save retval here + HRESULT m_hrResult; +}; + + +// a list of CDeferredCommand objects. this is a base class providing +// the basics of access to the list. If you want to use CDeferredCommand +// objects then your queue needs to be derived from this class. + +class AM_NOVTABLE CCmdQueue +{ +public: + CCmdQueue(__inout_opt HRESULT *phr = NULL); + virtual ~CCmdQueue(); + + // returns a new CDeferredCommand object that will be initialised with + // the parameters and will be added to the queue during construction. + // returns S_OK if successfully created otherwise an error and + // no object has been queued. + virtual HRESULT New( + __out CDeferredCommand **ppCmd, + __in LPUNKNOWN pUnk, + REFTIME time, + __in GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + __in_ecount(cArgs) VARIANT* pDispParams, + __out VARIANT* pvarResult, + __out short* puArgErr, + BOOL bStream + ); + + // called by the CDeferredCommand object to add and remove itself + // from the queue + virtual HRESULT Insert(__in CDeferredCommand* pCmd); + virtual HRESULT Remove(__in CDeferredCommand* pCmd); + + // Command-Due Checking + // + // There are two schemes of synchronisation: coarse and accurate. In + // coarse mode, you wait till the time arrives and then execute the cmd. + // In accurate mode, you wait until you are processing the sample that + // will appear at the time, and then execute the command. It's up to the + // filter which one it will implement. The filtergraph will always + // implement coarse mode for commands queued at the filtergraph. + // + // If you want coarse sync, you probably want to wait until there is a + // command due, and then execute it. You can do this by calling + // GetDueCommand. If you have several things to wait for, get the + // event handle from GetDueHandle() and when this is signalled then call + // GetDueCommand. Stream time will only advance between calls to Run and + // EndRun. Note that to avoid an extra thread there is no guarantee that + // if the handle is set there will be a command ready. Each time the + // event is signalled, call GetDueCommand (probably with a 0 timeout); + // This may return E_ABORT. + // + // If you want accurate sync, you must call GetCommandDueFor, passing + // as a parameter the stream time of the samples you are about to process. + // This will return: + // -- a stream-time command due at or before that stream time + // -- a presentation-time command due at or before the + // time that stream time will be presented (only between Run + // and EndRun calls, since outside of this, the mapping from + // stream time to presentation time is not known. + // -- any presentation-time command due now. + // This means that if you want accurate synchronisation on samples that + // might be processed during Paused mode, you need to use + // stream-time commands. + // + // In all cases, commands remain queued until Invoked or Cancelled. The + // setting and resetting of the event handle is managed entirely by this + // queue object. + + // set the clock used for timing + virtual HRESULT SetSyncSource(__in_opt IReferenceClock*); + + // switch to run mode. Streamtime to Presentation time mapping known. + virtual HRESULT Run(REFERENCE_TIME tStreamTimeOffset); + + // switch to Stopped or Paused mode. Time mapping not known. + virtual HRESULT EndRun(); + + // return a pointer to the next due command. Blocks for msTimeout + // milliseconds until there is a due command. + // Stream-time commands will only become due between Run and Endrun calls. + // The command remains queued until invoked or cancelled. + // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). + // Returns an AddRef-ed object + virtual HRESULT GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout); + + // return the event handle that will be signalled whenever + // there are deferred commands due for execution (when GetDueCommand + // will not block). + HANDLE GetDueHandle() { + return HANDLE(m_evDue); + }; + + // return a pointer to a command that will be due for a given time. + // Pass in a stream time here. The stream time offset will be passed + // in via the Run method. + // Commands remain queued until invoked or cancelled. + // This method will not block. It will report VFW_E_NOT_FOUND if there + // are no commands due yet. + // Returns an AddRef-ed object + virtual HRESULT GetCommandDueFor(REFERENCE_TIME tStream, __out CDeferredCommand**ppCmd); + + // check if a given time is due (TRUE if it is due yet) + BOOL CheckTime(CRefTime time, BOOL bStream) { + + // if no clock, nothing is due! + if (!m_pClock) { + return FALSE; + } + + // stream time + if (bStream) { + + // not valid if not running + if (!m_bRunning) { + return FALSE; + } + // add on known stream time offset to get presentation time + time += m_StreamTimeOffset; + } + + CRefTime Now; + m_pClock->GetTime((REFERENCE_TIME*)&Now); + return (time <= Now); + }; + +protected: + + // protect access to lists etc + CCritSec m_Lock; + + // commands queued in presentation time are stored here + CGenericList m_listPresentation; + + // commands queued in stream time are stored here + CGenericList m_listStream; + + // set when any commands are due + CAMEvent m_evDue; + + // creates an advise for the earliest time required, if any + void SetTimeAdvise(void); + + // advise id from reference clock (0 if no outstanding advise) + DWORD_PTR m_dwAdvise; + + // advise time is for this presentation time + CRefTime m_tCurrentAdvise; + + // the reference clock we are using (addrefed) + IReferenceClock* m_pClock; + + // true when running + BOOL m_bRunning; + + // contains stream time offset when m_bRunning is true + CRefTime m_StreamTimeOffset; +}; + +#endif // __CTLUTIL__ diff --git a/src/thirdparty/BaseClasses/ddmm.cpp b/src/thirdparty/BaseClasses/ddmm.cpp index 0bcdeb944d8..79b8a093758 100644 --- a/src/thirdparty/BaseClasses/ddmm.cpp +++ b/src/thirdparty/BaseClasses/ddmm.cpp @@ -1,129 +1,129 @@ -//------------------------------------------------------------------------------ -// File: DDMM.cpp -// -// Desc: DirectShow base classes - implements routines for using DirectDraw -// on a multimonitor system. -// -// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include -#include "ddmm.h" - -/* - * FindDeviceCallback - */ -typedef struct { - LPSTR szDevice; - GUID* lpGUID; - GUID GUID; - BOOL fFound; -} FindDeviceData; - -BOOL CALLBACK FindDeviceCallback(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam) -{ - FindDeviceData *p = (FindDeviceData*)lParam; - - if (lstrcmpiA(p->szDevice, szDevice) == 0) { - if (lpGUID) { - p->GUID = *lpGUID; - p->lpGUID = &p->GUID; - } else { - p->lpGUID = NULL; - } - p->fFound = TRUE; - return FALSE; - } - return TRUE; -} - - -BOOL CALLBACK FindDeviceCallbackEx(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam, HMONITOR hMonitor) -{ - FindDeviceData *p = (FindDeviceData*)lParam; - - if (lstrcmpiA(p->szDevice, szDevice) == 0) { - if (lpGUID) { - p->GUID = *lpGUID; - p->lpGUID = &p->GUID; - } else { - p->lpGUID = NULL; - } - p->fFound = TRUE; - return FALSE; - } - return TRUE; -} - - -/* - * DirectDrawCreateFromDevice - * - * create a DirectDraw object for a particular device - */ -IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) -{ - IDirectDraw* pdd = NULL; - FindDeviceData find; - - if (szDevice == NULL) { - DirectDrawCreateP(NULL, &pdd, NULL); - return pdd; - } - - find.szDevice = szDevice; - find.fFound = FALSE; - DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find); - - if (find.fFound) - { - // - // In 4bpp mode the following DDraw call causes a message box to be popped - // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we - // make sure it doesn't happen. - // - UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - DirectDrawCreateP(find.lpGUID, &pdd, NULL); - SetErrorMode(ErrorMode); - } - - return pdd; -} - - -/* - * DirectDrawCreateFromDeviceEx - * - * create a DirectDraw object for a particular device - */ -IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) -{ - IDirectDraw* pdd = NULL; - FindDeviceData find; - - if (szDevice == NULL) { - DirectDrawCreateP(NULL, &pdd, NULL); - return pdd; - } - - find.szDevice = szDevice; - find.fFound = FALSE; - DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find, - DDENUM_ATTACHEDSECONDARYDEVICES); - - if (find.fFound) - { - // - // In 4bpp mode the following DDraw call causes a message box to be popped - // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we - // make sure it doesn't happen. - // - UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - DirectDrawCreateP(find.lpGUID, &pdd, NULL); - SetErrorMode(ErrorMode); - } - - return pdd; -} +//------------------------------------------------------------------------------ +// File: DDMM.cpp +// +// Desc: DirectShow base classes - implements routines for using DirectDraw +// on a multimonitor system. +// +// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include +#include "ddmm.h" + +/* + * FindDeviceCallback + */ +typedef struct { + LPSTR szDevice; + GUID* lpGUID; + GUID GUID; + BOOL fFound; +} FindDeviceData; + +BOOL CALLBACK FindDeviceCallback(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam) +{ + FindDeviceData *p = (FindDeviceData*)lParam; + + if (lstrcmpiA(p->szDevice, szDevice) == 0) { + if (lpGUID) { + p->GUID = *lpGUID; + p->lpGUID = &p->GUID; + } else { + p->lpGUID = NULL; + } + p->fFound = TRUE; + return FALSE; + } + return TRUE; +} + + +BOOL CALLBACK FindDeviceCallbackEx(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam, HMONITOR hMonitor) +{ + FindDeviceData *p = (FindDeviceData*)lParam; + + if (lstrcmpiA(p->szDevice, szDevice) == 0) { + if (lpGUID) { + p->GUID = *lpGUID; + p->lpGUID = &p->GUID; + } else { + p->lpGUID = NULL; + } + p->fFound = TRUE; + return FALSE; + } + return TRUE; +} + + +/* + * DirectDrawCreateFromDevice + * + * create a DirectDraw object for a particular device + */ +IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) +{ + IDirectDraw* pdd = NULL; + FindDeviceData find; + + if (szDevice == NULL) { + DirectDrawCreateP(NULL, &pdd, NULL); + return pdd; + } + + find.szDevice = szDevice; + find.fFound = FALSE; + DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find); + + if (find.fFound) + { + // + // In 4bpp mode the following DDraw call causes a message box to be popped + // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we + // make sure it doesn't happen. + // + UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + DirectDrawCreateP(find.lpGUID, &pdd, NULL); + SetErrorMode(ErrorMode); + } + + return pdd; +} + + +/* + * DirectDrawCreateFromDeviceEx + * + * create a DirectDraw object for a particular device + */ +IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) +{ + IDirectDraw* pdd = NULL; + FindDeviceData find; + + if (szDevice == NULL) { + DirectDrawCreateP(NULL, &pdd, NULL); + return pdd; + } + + find.szDevice = szDevice; + find.fFound = FALSE; + DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find, + DDENUM_ATTACHEDSECONDARYDEVICES); + + if (find.fFound) + { + // + // In 4bpp mode the following DDraw call causes a message box to be popped + // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we + // make sure it doesn't happen. + // + UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + DirectDrawCreateP(find.lpGUID, &pdd, NULL); + SetErrorMode(ErrorMode); + } + + return pdd; +} diff --git a/src/thirdparty/BaseClasses/ddmm.h b/src/thirdparty/BaseClasses/ddmm.h index 7b311bc101e..c773d58891d 100644 --- a/src/thirdparty/BaseClasses/ddmm.h +++ b/src/thirdparty/BaseClasses/ddmm.h @@ -1,28 +1,28 @@ -//------------------------------------------------------------------------------ -// File: DDMM.h -// -// Desc: DirectShow base classes - efines routines for using DirectDraw -// on a multimonitor system. -// -// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifdef __cplusplus -extern "C" { /* Assume C declarations for C++ */ -#endif /* __cplusplus */ - -// DDRAW.H might not include these -#ifndef DDENUM_ATTACHEDSECONDARYDEVICES -#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L -#endif - -typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN); -typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID); - -IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR, PDRAWCREATE, PDRAWENUM); -IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +//------------------------------------------------------------------------------ +// File: DDMM.h +// +// Desc: DirectShow base classes - efines routines for using DirectDraw +// on a multimonitor system. +// +// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +// DDRAW.H might not include these +#ifndef DDENUM_ATTACHEDSECONDARYDEVICES +#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L +#endif + +typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN); +typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID); + +IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR, PDRAWCREATE, PDRAWENUM); +IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/src/thirdparty/BaseClasses/dllentry.cpp b/src/thirdparty/BaseClasses/dllentry.cpp index 6424f27f445..f6d46da9010 100644 --- a/src/thirdparty/BaseClasses/dllentry.cpp +++ b/src/thirdparty/BaseClasses/dllentry.cpp @@ -1,365 +1,365 @@ -//------------------------------------------------------------------------------ -// File: DlleEntry.cpp -// -// Desc: DirectShow base classes - implements classes used to support dll -// entry points for COM objects. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -#ifdef _DEBUG -#ifdef UNICODE -#ifndef _UNICODE -#define _UNICODE -#endif // _UNICODE -#endif // UNICODE - -#include -#endif // DEBUG -#include - -extern CFactoryTemplate g_Templates[]; -extern int g_cTemplates; - -HINSTANCE g_hInst; -DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx) -OSVERSIONINFO g_osInfo; - -// -// an instance of this is created by the DLLGetClassObject entrypoint -// it uses the CFactoryTemplate object it is given to support the -// IClassFactory interface - -class CClassFactory : public IClassFactory, public CBaseObject -{ - -private: - const CFactoryTemplate *const m_pTemplate; - - ULONG m_cRef; - - static int m_cLocked; -public: - CClassFactory(const CFactoryTemplate *); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void ** ppv); - STDMETHODIMP_(ULONG)AddRef(); - STDMETHODIMP_(ULONG)Release(); - - // IClassFactory - STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, __deref_out void **pv); - STDMETHODIMP LockServer(BOOL fLock); - - // allow DLLGetClassObject to know about global server lock status - static BOOL IsLocked() { - return (m_cLocked > 0); - }; -}; - -// process-wide dll locked state -int CClassFactory::m_cLocked = 0; - -CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate) -: CBaseObject(NAME("Class Factory")) -, m_cRef(0) -, m_pTemplate(pTemplate) -{ -} - - -STDMETHODIMP -CClassFactory::QueryInterface(REFIID riid,__deref_out void **ppv) -{ - CheckPointer(ppv,E_POINTER) - ValidateReadWritePtr(ppv,sizeof(PVOID)); - *ppv = NULL; - - // any interface on this object is the object pointer. - if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) { - *ppv = (LPVOID) this; - // AddRef returned interface pointer - ((LPUNKNOWN) *ppv)->AddRef(); - return NOERROR; - } - - return ResultFromScode(E_NOINTERFACE); -} - - -STDMETHODIMP_(ULONG) -CClassFactory::AddRef() -{ - return ++m_cRef; -} - -STDMETHODIMP_(ULONG) -CClassFactory::Release() -{ - LONG lRef = InterlockedDecrement((volatile LONG *)&m_cRef); - if (lRef == 0) { - delete this; - return 0; - } else { - return lRef; - } -} - -STDMETHODIMP -CClassFactory::CreateInstance( - LPUNKNOWN pUnkOuter, - REFIID riid, - __deref_out void **pv) -{ - CheckPointer(pv,E_POINTER) - ValidateReadWritePtr(pv,sizeof(void *)); - *pv = NULL; - - /* Enforce the normal OLE rules regarding interfaces and delegation */ - - if (pUnkOuter != NULL) { - if (IsEqualIID(riid,IID_IUnknown) == FALSE) { - *pv = NULL; - return ResultFromScode(E_NOINTERFACE); - } - } - - /* Create the new object through the derived class's create function */ - - HRESULT hr = NOERROR; - CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr); - - if (pObj == NULL) { - *pv = NULL; - if (SUCCEEDED(hr)) { - hr = E_OUTOFMEMORY; - } - return hr; - } - - /* Delete the object if we got a construction error */ - - if (FAILED(hr)) { - delete pObj; - *pv = NULL; - return hr; - } - - /* Get a reference counted interface on the object */ - - /* We wrap the non-delegating QI with NDAddRef & NDRelease. */ - /* This protects any outer object from being prematurely */ - /* released by an inner object that may have to be created */ - /* in order to supply the requested interface. */ - pObj->NonDelegatingAddRef(); - hr = pObj->NonDelegatingQueryInterface(riid, pv); - pObj->NonDelegatingRelease(); - /* Note that if NonDelegatingQueryInterface fails, it will */ - /* not increment the ref count, so the NonDelegatingRelease */ - /* will drop the ref back to zero and the object will "self-*/ - /* destruct". Hence we don't need additional tidy-up code */ - /* to cope with NonDelegatingQueryInterface failing. */ - - if (SUCCEEDED(hr)) { - ASSERT(*pv); - } - - return hr; -} - -STDMETHODIMP -CClassFactory::LockServer(BOOL fLock) -{ - if (fLock) { - m_cLocked++; - } else { - m_cLocked--; - } - return NOERROR; -} - - -// --- COM entrypoints ----------------------------------------- - -//called by COM to get the class factory object for a given class -__control_entrypoint(DllExport) STDAPI -DllGetClassObject( - __in REFCLSID rClsID, - __in REFIID riid, - __deref_out void **pv) -{ - *pv = NULL; - if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) { - return E_NOINTERFACE; - } - - // traverse the array of templates looking for one with this - // class id - for (int i = 0; i < g_cTemplates; i++) { - const CFactoryTemplate * pT = &g_Templates[i]; - if (pT->IsClassID(rClsID)) { - - // found a template - make a class factory based on this - // template - - *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT); - if (*pv == NULL) { - return E_OUTOFMEMORY; - } - ((LPUNKNOWN)*pv)->AddRef(); - return NOERROR; - } - } - return CLASS_E_CLASSNOTAVAILABLE; -} - -// -// Call any initialization routines -// -void -DllInitClasses(BOOL bLoading) -{ - int i; - - // traverse the array of templates calling the init routine - // if they have one - for (i = 0; i < g_cTemplates; i++) { - const CFactoryTemplate * pT = &g_Templates[i]; - if (pT->m_lpfnInit != NULL) { - (*pT->m_lpfnInit)(bLoading, pT->m_ClsID); - } - } - -} - -// called by COM to determine if this dll can be unloaded -// return ok unless there are outstanding objects or a lock requested -// by IClassFactory::LockServer -// -// CClassFactory has a static function that can tell us about the locks, -// and CCOMObject has a static function that can tell us about the active -// object count -STDAPI -DllCanUnloadNow() -{ - DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"), - CClassFactory::IsLocked(), - CBaseObject::ObjectsActive())); - - if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) { - return S_FALSE; - } else { - return S_OK; - } -} - - -// --- standard WIN32 entrypoints -------------------------------------- -extern "C" void __cdecl __security_init_cookie(void); -extern "C" BOOL WINAPI _DllEntryPoint(HINSTANCE, ULONG, __inout_opt LPVOID); -#pragma comment(linker, "/merge:.CRT=.rdata") - -extern "C" -DECLSPEC_NOINLINE -BOOL -WINAPI -DllEntryPoint( - HINSTANCE hInstance, - ULONG ulReason, - __inout_opt LPVOID pv - ) -{ - if ( ulReason == DLL_PROCESS_ATTACH ) { - // Must happen before any other code is executed. Thankfully - it's re-entrant - __security_init_cookie(); - } - return _DllEntryPoint(hInstance, ulReason, pv); -} - - -DECLSPEC_NOINLINE -BOOL -WINAPI -_DllEntryPoint( - HINSTANCE hInstance, - ULONG ulReason, - __inout_opt LPVOID pv - ) -{ -#ifdef _DEBUG - extern bool g_fDbgInDllEntryPoint; - g_fDbgInDllEntryPoint = true; -#endif - - switch (ulReason) - { - - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hInstance); - DbgInitialise(hInstance); - - { - // The platform identifier is used to work out whether - // full unicode support is available or not. Hence the - // default will be the lowest common denominator - i.e. N/A - g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails - - g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo); - if (GetVersionEx(&g_osInfo)) { - g_amPlatform = g_osInfo.dwPlatformId; - } else { - DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95"))); - } - } - - g_hInst = hInstance; - DllInitClasses(TRUE); - break; - - case DLL_PROCESS_DETACH: - DllInitClasses(FALSE); - -#ifdef _DEBUG - if (CBaseObject::ObjectsActive()) { - DbgSetModuleLevel(LOG_MEMORY, 2); - TCHAR szInfo[512]; - extern TCHAR m_ModuleName[]; // Cut down module name - - TCHAR FullName[MAX_PATH]; // Load the full path and module name - TCHAR *pName; // Searches from the end for a backslash - - GetModuleFileName(NULL,FullName,MAX_PATH); - pName = _tcsrchr(FullName,'\\'); - if (pName == NULL) { - pName = FullName; - } else { - pName++; - } - - (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("Executable: %s Pid %x Tid %x. "), - pName, GetCurrentProcessId(), GetCurrentThreadId()); - - (void)StringCchPrintf(szInfo+lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), TEXT("Module %s, %d objects left active!"), - m_ModuleName, CBaseObject::ObjectsActive()); - DbgAssert(szInfo, TEXT(__FILE__),__LINE__); - - // If running remotely wait for the Assert to be acknowledged - // before dumping out the object register - DbgDumpObjectRegister(); - } - DbgTerminate(); -#endif - break; - } - -#ifdef _DEBUG - g_fDbgInDllEntryPoint = false; -#endif - return TRUE; -} - - +//------------------------------------------------------------------------------ +// File: DlleEntry.cpp +// +// Desc: DirectShow base classes - implements classes used to support dll +// entry points for COM objects. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +#ifdef _DEBUG +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif // _UNICODE +#endif // UNICODE + +#include +#endif // DEBUG +#include + +extern CFactoryTemplate g_Templates[]; +extern int g_cTemplates; + +HINSTANCE g_hInst; +DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx) +OSVERSIONINFO g_osInfo; + +// +// an instance of this is created by the DLLGetClassObject entrypoint +// it uses the CFactoryTemplate object it is given to support the +// IClassFactory interface + +class CClassFactory : public IClassFactory, public CBaseObject +{ + +private: + const CFactoryTemplate *const m_pTemplate; + + ULONG m_cRef; + + static int m_cLocked; +public: + CClassFactory(const CFactoryTemplate *); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void ** ppv); + STDMETHODIMP_(ULONG)AddRef(); + STDMETHODIMP_(ULONG)Release(); + + // IClassFactory + STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, __deref_out void **pv); + STDMETHODIMP LockServer(BOOL fLock); + + // allow DLLGetClassObject to know about global server lock status + static BOOL IsLocked() { + return (m_cLocked > 0); + }; +}; + +// process-wide dll locked state +int CClassFactory::m_cLocked = 0; + +CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate) +: CBaseObject(NAME("Class Factory")) +, m_cRef(0) +, m_pTemplate(pTemplate) +{ +} + + +STDMETHODIMP +CClassFactory::QueryInterface(REFIID riid,__deref_out void **ppv) +{ + CheckPointer(ppv,E_POINTER) + ValidateReadWritePtr(ppv,sizeof(PVOID)); + *ppv = NULL; + + // any interface on this object is the object pointer. + if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) { + *ppv = (LPVOID) this; + // AddRef returned interface pointer + ((LPUNKNOWN) *ppv)->AddRef(); + return NOERROR; + } + + return ResultFromScode(E_NOINTERFACE); +} + + +STDMETHODIMP_(ULONG) +CClassFactory::AddRef() +{ + return ++m_cRef; +} + +STDMETHODIMP_(ULONG) +CClassFactory::Release() +{ + LONG lRef = InterlockedDecrement((volatile LONG *)&m_cRef); + if (lRef == 0) { + delete this; + return 0; + } else { + return lRef; + } +} + +STDMETHODIMP +CClassFactory::CreateInstance( + LPUNKNOWN pUnkOuter, + REFIID riid, + __deref_out void **pv) +{ + CheckPointer(pv,E_POINTER) + ValidateReadWritePtr(pv,sizeof(void *)); + *pv = NULL; + + /* Enforce the normal OLE rules regarding interfaces and delegation */ + + if (pUnkOuter != NULL) { + if (IsEqualIID(riid,IID_IUnknown) == FALSE) { + *pv = NULL; + return ResultFromScode(E_NOINTERFACE); + } + } + + /* Create the new object through the derived class's create function */ + + HRESULT hr = NOERROR; + CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr); + + if (pObj == NULL) { + *pv = NULL; + if (SUCCEEDED(hr)) { + hr = E_OUTOFMEMORY; + } + return hr; + } + + /* Delete the object if we got a construction error */ + + if (FAILED(hr)) { + delete pObj; + *pv = NULL; + return hr; + } + + /* Get a reference counted interface on the object */ + + /* We wrap the non-delegating QI with NDAddRef & NDRelease. */ + /* This protects any outer object from being prematurely */ + /* released by an inner object that may have to be created */ + /* in order to supply the requested interface. */ + pObj->NonDelegatingAddRef(); + hr = pObj->NonDelegatingQueryInterface(riid, pv); + pObj->NonDelegatingRelease(); + /* Note that if NonDelegatingQueryInterface fails, it will */ + /* not increment the ref count, so the NonDelegatingRelease */ + /* will drop the ref back to zero and the object will "self-*/ + /* destruct". Hence we don't need additional tidy-up code */ + /* to cope with NonDelegatingQueryInterface failing. */ + + if (SUCCEEDED(hr)) { + ASSERT(*pv); + } + + return hr; +} + +STDMETHODIMP +CClassFactory::LockServer(BOOL fLock) +{ + if (fLock) { + m_cLocked++; + } else { + m_cLocked--; + } + return NOERROR; +} + + +// --- COM entrypoints ----------------------------------------- + +//called by COM to get the class factory object for a given class +__control_entrypoint(DllExport) STDAPI +DllGetClassObject( + __in REFCLSID rClsID, + __in REFIID riid, + __deref_out void **pv) +{ + *pv = NULL; + if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) { + return E_NOINTERFACE; + } + + // traverse the array of templates looking for one with this + // class id + for (int i = 0; i < g_cTemplates; i++) { + const CFactoryTemplate * pT = &g_Templates[i]; + if (pT->IsClassID(rClsID)) { + + // found a template - make a class factory based on this + // template + + *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT); + if (*pv == NULL) { + return E_OUTOFMEMORY; + } + ((LPUNKNOWN)*pv)->AddRef(); + return NOERROR; + } + } + return CLASS_E_CLASSNOTAVAILABLE; +} + +// +// Call any initialization routines +// +void +DllInitClasses(BOOL bLoading) +{ + int i; + + // traverse the array of templates calling the init routine + // if they have one + for (i = 0; i < g_cTemplates; i++) { + const CFactoryTemplate * pT = &g_Templates[i]; + if (pT->m_lpfnInit != NULL) { + (*pT->m_lpfnInit)(bLoading, pT->m_ClsID); + } + } + +} + +// called by COM to determine if this dll can be unloaded +// return ok unless there are outstanding objects or a lock requested +// by IClassFactory::LockServer +// +// CClassFactory has a static function that can tell us about the locks, +// and CCOMObject has a static function that can tell us about the active +// object count +STDAPI +DllCanUnloadNow() +{ + DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"), + CClassFactory::IsLocked(), + CBaseObject::ObjectsActive())); + + if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) { + return S_FALSE; + } else { + return S_OK; + } +} + + +// --- standard WIN32 entrypoints -------------------------------------- +extern "C" void __cdecl __security_init_cookie(void); +extern "C" BOOL WINAPI _DllEntryPoint(HINSTANCE, ULONG, __inout_opt LPVOID); +#pragma comment(linker, "/merge:.CRT=.rdata") + +extern "C" +DECLSPEC_NOINLINE +BOOL +WINAPI +DllEntryPoint( + HINSTANCE hInstance, + ULONG ulReason, + __inout_opt LPVOID pv + ) +{ + if ( ulReason == DLL_PROCESS_ATTACH ) { + // Must happen before any other code is executed. Thankfully - it's re-entrant + __security_init_cookie(); + } + return _DllEntryPoint(hInstance, ulReason, pv); +} + + +DECLSPEC_NOINLINE +BOOL +WINAPI +_DllEntryPoint( + HINSTANCE hInstance, + ULONG ulReason, + __inout_opt LPVOID pv + ) +{ +#ifdef _DEBUG + extern bool g_fDbgInDllEntryPoint; + g_fDbgInDllEntryPoint = true; +#endif + + switch (ulReason) + { + + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstance); + DbgInitialise(hInstance); + + { + // The platform identifier is used to work out whether + // full unicode support is available or not. Hence the + // default will be the lowest common denominator - i.e. N/A + g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails + + g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo); + if (GetVersionEx(&g_osInfo)) { + g_amPlatform = g_osInfo.dwPlatformId; + } else { + DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95"))); + } + } + + g_hInst = hInstance; + DllInitClasses(TRUE); + break; + + case DLL_PROCESS_DETACH: + DllInitClasses(FALSE); + +#ifdef _DEBUG + if (CBaseObject::ObjectsActive()) { + DbgSetModuleLevel(LOG_MEMORY, 2); + TCHAR szInfo[512]; + extern TCHAR m_ModuleName[]; // Cut down module name + + TCHAR FullName[MAX_PATH]; // Load the full path and module name + TCHAR *pName; // Searches from the end for a backslash + + GetModuleFileName(NULL,FullName,MAX_PATH); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) { + pName = FullName; + } else { + pName++; + } + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("Executable: %s Pid %x Tid %x. "), + pName, GetCurrentProcessId(), GetCurrentThreadId()); + + (void)StringCchPrintf(szInfo+lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), TEXT("Module %s, %d objects left active!"), + m_ModuleName, CBaseObject::ObjectsActive()); + DbgAssert(szInfo, TEXT(__FILE__),__LINE__); + + // If running remotely wait for the Assert to be acknowledged + // before dumping out the object register + DbgDumpObjectRegister(); + } + DbgTerminate(); +#endif + break; + } + +#ifdef _DEBUG + g_fDbgInDllEntryPoint = false; +#endif + return TRUE; +} + + diff --git a/src/thirdparty/BaseClasses/dllsetup.cpp b/src/thirdparty/BaseClasses/dllsetup.cpp index 28454b73fca..aaa95d04692 100644 --- a/src/thirdparty/BaseClasses/dllsetup.cpp +++ b/src/thirdparty/BaseClasses/dllsetup.cpp @@ -1,696 +1,696 @@ -//------------------------------------------------------------------------------ -// File: DllSetup.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -//--------------------------------------------------------------------------- -// defines - -#define MAX_KEY_LEN 260 - - -//--------------------------------------------------------------------------- -// externally defined functions/variable - -extern int g_cTemplates; -extern CFactoryTemplate g_Templates[]; - -//--------------------------------------------------------------------------- -// -// EliminateSubKey -// -// Try to enumerate all keys under this one. -// if we find anything, delete it completely. -// Otherwise just delete it. -// -// note - this was pinched/duplicated from -// Filgraph\Mapper.cpp - so should it be in -// a lib somewhere? -// -//--------------------------------------------------------------------------- - -STDAPI -EliminateSubKey( HKEY hkey, LPCTSTR strSubKey ) -{ - HKEY hk; - if (0 == lstrlen(strSubKey) ) { - // defensive approach - return E_FAIL; - } - - LONG lreturn = RegOpenKeyEx( hkey - , strSubKey - , 0 - , MAXIMUM_ALLOWED - , &hk ); - - ASSERT( lreturn == ERROR_SUCCESS - || lreturn == ERROR_FILE_NOT_FOUND - || lreturn == ERROR_INVALID_HANDLE ); - - if( ERROR_SUCCESS == lreturn ) - { - // Keep on enumerating the first (zero-th) - // key and deleting that - - for( ; ; ) - { - TCHAR Buffer[MAX_KEY_LEN]; - DWORD dw = MAX_KEY_LEN; - FILETIME ft; - - lreturn = RegEnumKeyEx( hk - , 0 - , Buffer - , &dw - , NULL - , NULL - , NULL - , &ft); - - ASSERT( lreturn == ERROR_SUCCESS - || lreturn == ERROR_NO_MORE_ITEMS ); - - if( ERROR_SUCCESS == lreturn ) - { - EliminateSubKey(hk, Buffer); - } - else - { - break; - } - } - - RegCloseKey(hk); - RegDeleteKey(hkey, strSubKey); - } - - return NOERROR; -} - - -//--------------------------------------------------------------------------- -// -// AMovieSetupRegisterServer() -// -// registers specfied file "szFileName" as server for -// CLSID "clsServer". A description is also required. -// The ThreadingModel and ServerType are optional, as -// they default to InprocServer32 (i.e. dll) and Both. -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieSetupRegisterServer( CLSID clsServer - , LPCWSTR szDescription - , LPCWSTR szFileName - , LPCWSTR szThreadingModel = L"Both" - , LPCWSTR szServerType = L"InprocServer32" ) -{ - // temp buffer - // - TCHAR achTemp[MAX_PATH]; - - // convert CLSID uuid to string and write - // out subkey as string - CLSID\{} - // - OLECHAR szCLSID[CHARS_IN_GUID]; - HRESULT hr = StringFromGUID2( clsServer - , szCLSID - , CHARS_IN_GUID ); - ASSERT( SUCCEEDED(hr) ); - UNREFERENCED_PARAMETER(hr); - - // create key - // - HKEY hkey; - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("CLSID\\%ls"), szCLSID ); - LONG lreturn = RegCreateKey( HKEY_CLASSES_ROOT - , (LPCTSTR)achTemp - , &hkey ); - if( ERROR_SUCCESS != lreturn ) - { - return AmHresultFromWin32(lreturn); - } - - // set description string - // - - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szDescription ); - lreturn = RegSetValue( hkey - , (LPCTSTR)NULL - , REG_SZ - , achTemp - , sizeof(achTemp) ); - if( ERROR_SUCCESS != lreturn ) - { - RegCloseKey( hkey ); - return AmHresultFromWin32(lreturn); - } - - // create CLSID\\{"CLSID"}\\"ServerType" key, - // using key to CLSID\\{"CLSID"} passed back by - // last call to RegCreateKey(). - // - HKEY hsubkey; - - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szServerType ); - lreturn = RegCreateKey( hkey - , achTemp - , &hsubkey ); - if( ERROR_SUCCESS != lreturn ) - { - RegCloseKey( hkey ); - return AmHresultFromWin32(lreturn); - } - - // set Server string - // - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szFileName ); - lreturn = RegSetValue( hsubkey - , (LPCTSTR)NULL - , REG_SZ - , (LPCTSTR)achTemp - , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); - if( ERROR_SUCCESS != lreturn ) - { - RegCloseKey( hkey ); - RegCloseKey( hsubkey ); - return AmHresultFromWin32(lreturn); - } - - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szThreadingModel ); - lreturn = RegSetValueEx( hsubkey - , TEXT("ThreadingModel") - , 0L - , REG_SZ - , (CONST BYTE *)achTemp - , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); - - // close hkeys - // - RegCloseKey( hkey ); - RegCloseKey( hsubkey ); - - // and return - // - return HRESULT_FROM_WIN32(lreturn); - -} - - -//--------------------------------------------------------------------------- -// -// AMovieSetupUnregisterServer() -// -// default ActiveMovie dll setup function -// - to use must be called from an exported -// function named DllRegisterServer() -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieSetupUnregisterServer( CLSID clsServer ) -{ - // convert CLSID uuid to string and write - // out subkey CLSID\{} - // - OLECHAR szCLSID[CHARS_IN_GUID]; - HRESULT hr = StringFromGUID2( clsServer - , szCLSID - , CHARS_IN_GUID ); - ASSERT( SUCCEEDED(hr) ); - - TCHAR achBuffer[MAX_KEY_LEN]; - (void)StringCchPrintf( achBuffer, NUMELMS(achBuffer), TEXT("CLSID\\%ls"), szCLSID ); - - // delete subkey - // - - hr = EliminateSubKey( HKEY_CLASSES_ROOT, achBuffer ); - ASSERT( SUCCEEDED(hr) ); - - // return - // - return NOERROR; -} - - -//--------------------------------------------------------------------------- -// -// AMovieSetupRegisterFilter through IFilterMapper2 -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper2 * pIFM2 - , BOOL bRegister ) -{ - DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - - // unregister filter - // (as pins are subkeys of filter's CLSID key - // they do not need to be removed separately). - // - DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); - HRESULT hr = pIFM2->UnregisterFilter( - 0, // default category - 0, // default instance name - *psetupdata->clsID ); - - - if( bRegister ) - { - REGFILTER2 rf2; - rf2.dwVersion = 1; - rf2.dwMerit = psetupdata->dwMerit; - rf2.cPins = psetupdata->nPins; - rf2.rgPins = psetupdata->lpPin; - - const CLSID *filterCategory=&psetupdata->filterCategory; - - // register filter - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); - hr = pIFM2->RegisterFilter(*psetupdata->clsID - , psetupdata->strName - , 0 // moniker - ,filterCategory // category - , NULL // instance - , &rf2); - } - - // handle one acceptable "error" - that - // of filter not being registered! - // (couldn't find a suitable #define'd - // name for the error!) - // - if( 0x80070002 == hr) - return NOERROR; - else - return hr; -} - - -//--------------------------------------------------------------------------- -// -// RegisterAllServers() -// -//--------------------------------------------------------------------------- - -STDAPI -RegisterAllServers( LPCWSTR szFileName, BOOL bRegister ) -{ - HRESULT hr = NOERROR; - - for( int i = 0; i < g_cTemplates; i++ ) - { - // get i'th template - // - const CFactoryTemplate *pT = &g_Templates[i]; - - DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), - (LPCWSTR)pT->m_Name )); - - // register CLSID and InprocServer32 - // - if( bRegister ) - { - hr = AMovieSetupRegisterServer( *(pT->m_ClsID) - , (LPCWSTR)pT->m_Name - , szFileName ); - } - else - { - hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); - } - - // check final error for this pass - // and break loop if we failed - // - if( FAILED(hr) ) - break; - } - - return hr; -} - - -//--------------------------------------------------------------------------- -// -// AMovieDllRegisterServer2() -// -// default ActiveMovie dll setup function -// - to use must be called from an exported -// function named DllRegisterServer() -// -// this function is table driven using the -// static members of the CFactoryTemplate -// class defined in the dll. -// -// it registers the Dll as the InprocServer32 -// and then calls the IAMovieSetup.Register -// method. -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieDllRegisterServer2( BOOL bRegister ) -{ - HRESULT hr = NOERROR; - - DbgLog((LOG_TRACE, 2, TEXT("AMovieDllRegisterServer2()"))); - - // get file name (where g_hInst is the - // instance handle of the filter dll) - // - WCHAR achFileName[MAX_PATH]; - - // WIN95 doesn't support GetModuleFileNameW - // - { - char achTemp[MAX_PATH]; - - DbgLog((LOG_TRACE, 2, TEXT("- get module file name"))); - - // g_hInst handle is set in our dll entry point. Make sure - // DllEntryPoint in dllentry.cpp is called - ASSERT(g_hInst != 0); - - if( 0 == GetModuleFileNameA( g_hInst - , achTemp - , sizeof(achTemp) ) ) - { - // we've failed! - DWORD dwerr = GetLastError(); - return AmHresultFromWin32(dwerr); - } - - MultiByteToWideChar( CP_ACP - , 0L - , achTemp - , lstrlenA(achTemp) + 1 - , achFileName - , NUMELMS(achFileName) ); - } - - // - // first registering, register all OLE servers - // - if( bRegister ) - { - DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); - hr = RegisterAllServers( achFileName, TRUE ); - } - - // - // next, register/unregister all filters - // - - if( SUCCEEDED(hr) ) - { - // init is ref counted so call just in case - // we're being called cold. - // - DbgLog((LOG_TRACE, 2, TEXT("- CoInitialize"))); - hr = CoInitialize( (LPVOID)NULL ); - ASSERT( SUCCEEDED(hr) ); - - // get hold of IFilterMapper2 - // - DbgLog((LOG_TRACE, 2, TEXT("- obtain IFilterMapper2"))); - IFilterMapper2 *pIFM2 = 0; - IFilterMapper *pIFM = 0; - hr = CoCreateInstance( CLSID_FilterMapper2 - , NULL - , CLSCTX_INPROC_SERVER - , IID_IFilterMapper2 - , (void **)&pIFM2 ); - if(FAILED(hr)) - { - DbgLog((LOG_TRACE, 2, TEXT("- trying IFilterMapper instead"))); - - hr = CoCreateInstance( - CLSID_FilterMapper, - NULL, - CLSCTX_INPROC_SERVER, - IID_IFilterMapper, - (void **)&pIFM); - } - if( SUCCEEDED(hr) ) - { - // scan through array of CFactoryTemplates - // registering servers and filters. - // - DbgLog((LOG_TRACE, 2, TEXT("- register Filters"))); - for( int i = 0; i < g_cTemplates; i++ ) - { - // get i'th template - // - const CFactoryTemplate *pT = &g_Templates[i]; - - if( NULL != pT->m_pAMovieSetup_Filter ) - { - DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), (LPCWSTR)pT->m_Name )); - - if(pIFM2) - { - hr = AMovieSetupRegisterFilter2( pT->m_pAMovieSetup_Filter, pIFM2, bRegister ); - } - else - { - hr = AMovieSetupRegisterFilter( pT->m_pAMovieSetup_Filter, pIFM, bRegister ); - } - } - - // check final error for this pass - // and break loop if we failed - // - if( FAILED(hr) ) - break; - } - - // release interface - // - if(pIFM2) - pIFM2->Release(); - else - pIFM->Release(); - - } - - // and clear up - // - CoFreeUnusedLibraries(); - CoUninitialize(); - } - - // - // if unregistering, unregister all OLE servers - // - if( SUCCEEDED(hr) && !bRegister ) - { - DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); - hr = RegisterAllServers( achFileName, FALSE ); - } - - DbgLog((LOG_TRACE, 2, TEXT("- return %0x"), hr)); - return hr; -} - - -//--------------------------------------------------------------------------- -// -// AMovieDllRegisterServer() -// -// default ActiveMovie dll setup function -// - to use must be called from an exported -// function named DllRegisterServer() -// -// this function is table driven using the -// static members of the CFactoryTemplate -// class defined in the dll. -// -// it registers the Dll as the InprocServer32 -// and then calls the IAMovieSetup.Register -// method. -// -//--------------------------------------------------------------------------- - - -STDAPI -AMovieDllRegisterServer( void ) -{ - HRESULT hr = NOERROR; - - // get file name (where g_hInst is the - // instance handle of the filter dll) - // - WCHAR achFileName[MAX_PATH]; - - { - // WIN95 doesn't support GetModuleFileNameW - // - char achTemp[MAX_PATH]; - - if( 0 == GetModuleFileNameA( g_hInst - , achTemp - , sizeof(achTemp) ) ) - { - // we've failed! - DWORD dwerr = GetLastError(); - return AmHresultFromWin32(dwerr); - } - - MultiByteToWideChar( CP_ACP - , 0L - , achTemp - , lstrlenA(achTemp) + 1 - , achFileName - , NUMELMS(achFileName) ); - } - - // scan through array of CFactoryTemplates - // registering servers and filters. - // - for( int i = 0; i < g_cTemplates; i++ ) - { - // get i'th template - // - const CFactoryTemplate *pT = &g_Templates[i]; - - // register CLSID and InprocServer32 - // - hr = AMovieSetupRegisterServer( *(pT->m_ClsID) - , (LPCWSTR)pT->m_Name - , achFileName ); - - // instantiate all servers and get hold of - // IAMovieSetup, if implemented, and call - // IAMovieSetup.Register() method - // - if( SUCCEEDED(hr) && (NULL != pT->m_lpfnNew) ) - { - // instantiate object - // - PAMOVIESETUP psetup; - hr = CoCreateInstance( *(pT->m_ClsID) - , 0 - , CLSCTX_INPROC_SERVER - , IID_IAMovieSetup - , reinterpret_cast(&psetup) ); - if( SUCCEEDED(hr) ) - { - hr = psetup->Unregister(); - if( SUCCEEDED(hr) ) - hr = psetup->Register(); - psetup->Release(); - } - else - { - if( (E_NOINTERFACE == hr ) - || (VFW_E_NEED_OWNER == hr ) ) - hr = NOERROR; - } - } - - // check final error for this pass - // and break loop if we failed - // - if( FAILED(hr) ) - break; - - } // end-for - - return hr; -} - - -//--------------------------------------------------------------------------- -// -// AMovieDllUnregisterServer() -// -// default ActiveMovie dll uninstall function -// - to use must be called from an exported -// function named DllRegisterServer() -// -// this function is table driven using the -// static members of the CFactoryTemplate -// class defined in the dll. -// -// it calls the IAMovieSetup.Unregister -// method and then unregisters the Dll -// as the InprocServer32 -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieDllUnregisterServer() -{ - // initialize return code - // - HRESULT hr = NOERROR; - - // scan through CFactory template and unregister - // all OLE servers and filters. - // - for( int i = g_cTemplates; i--; ) - { - // get i'th template - // - const CFactoryTemplate *pT = &g_Templates[i]; - - // check method exists - // - if( NULL != pT->m_lpfnNew ) - { - // instantiate object - // - PAMOVIESETUP psetup; - hr = CoCreateInstance( *(pT->m_ClsID) - , 0 - , CLSCTX_INPROC_SERVER - , IID_IAMovieSetup - , reinterpret_cast(&psetup) ); - if( SUCCEEDED(hr) ) - { - hr = psetup->Unregister(); - psetup->Release(); - } - else - { - if( (E_NOINTERFACE == hr ) - || (VFW_E_NEED_OWNER == hr ) ) - hr = NOERROR; - } - } - - // unregister CLSID and InprocServer32 - // - if( SUCCEEDED(hr) ) - { - hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); - } - - // check final error for this pass - // and break loop if we failed - // - if( FAILED(hr) ) - break; - } - - return hr; -} +//------------------------------------------------------------------------------ +// File: DllSetup.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +//--------------------------------------------------------------------------- +// defines + +#define MAX_KEY_LEN 260 + + +//--------------------------------------------------------------------------- +// externally defined functions/variable + +extern int g_cTemplates; +extern CFactoryTemplate g_Templates[]; + +//--------------------------------------------------------------------------- +// +// EliminateSubKey +// +// Try to enumerate all keys under this one. +// if we find anything, delete it completely. +// Otherwise just delete it. +// +// note - this was pinched/duplicated from +// Filgraph\Mapper.cpp - so should it be in +// a lib somewhere? +// +//--------------------------------------------------------------------------- + +STDAPI +EliminateSubKey( HKEY hkey, LPCTSTR strSubKey ) +{ + HKEY hk; + if (0 == lstrlen(strSubKey) ) { + // defensive approach + return E_FAIL; + } + + LONG lreturn = RegOpenKeyEx( hkey + , strSubKey + , 0 + , MAXIMUM_ALLOWED + , &hk ); + + ASSERT( lreturn == ERROR_SUCCESS + || lreturn == ERROR_FILE_NOT_FOUND + || lreturn == ERROR_INVALID_HANDLE ); + + if( ERROR_SUCCESS == lreturn ) + { + // Keep on enumerating the first (zero-th) + // key and deleting that + + for( ; ; ) + { + TCHAR Buffer[MAX_KEY_LEN]; + DWORD dw = MAX_KEY_LEN; + FILETIME ft; + + lreturn = RegEnumKeyEx( hk + , 0 + , Buffer + , &dw + , NULL + , NULL + , NULL + , &ft); + + ASSERT( lreturn == ERROR_SUCCESS + || lreturn == ERROR_NO_MORE_ITEMS ); + + if( ERROR_SUCCESS == lreturn ) + { + EliminateSubKey(hk, Buffer); + } + else + { + break; + } + } + + RegCloseKey(hk); + RegDeleteKey(hkey, strSubKey); + } + + return NOERROR; +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupRegisterServer() +// +// registers specfied file "szFileName" as server for +// CLSID "clsServer". A description is also required. +// The ThreadingModel and ServerType are optional, as +// they default to InprocServer32 (i.e. dll) and Both. +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupRegisterServer( CLSID clsServer + , LPCWSTR szDescription + , LPCWSTR szFileName + , LPCWSTR szThreadingModel = L"Both" + , LPCWSTR szServerType = L"InprocServer32" ) +{ + // temp buffer + // + TCHAR achTemp[MAX_PATH]; + + // convert CLSID uuid to string and write + // out subkey as string - CLSID\{} + // + OLECHAR szCLSID[CHARS_IN_GUID]; + HRESULT hr = StringFromGUID2( clsServer + , szCLSID + , CHARS_IN_GUID ); + ASSERT( SUCCEEDED(hr) ); + UNREFERENCED_PARAMETER(hr); + + // create key + // + HKEY hkey; + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("CLSID\\%ls"), szCLSID ); + LONG lreturn = RegCreateKey( HKEY_CLASSES_ROOT + , (LPCTSTR)achTemp + , &hkey ); + if( ERROR_SUCCESS != lreturn ) + { + return AmHresultFromWin32(lreturn); + } + + // set description string + // + + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szDescription ); + lreturn = RegSetValue( hkey + , (LPCTSTR)NULL + , REG_SZ + , achTemp + , sizeof(achTemp) ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + return AmHresultFromWin32(lreturn); + } + + // create CLSID\\{"CLSID"}\\"ServerType" key, + // using key to CLSID\\{"CLSID"} passed back by + // last call to RegCreateKey(). + // + HKEY hsubkey; + + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szServerType ); + lreturn = RegCreateKey( hkey + , achTemp + , &hsubkey ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + return AmHresultFromWin32(lreturn); + } + + // set Server string + // + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szFileName ); + lreturn = RegSetValue( hsubkey + , (LPCTSTR)NULL + , REG_SZ + , (LPCTSTR)achTemp + , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + RegCloseKey( hsubkey ); + return AmHresultFromWin32(lreturn); + } + + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szThreadingModel ); + lreturn = RegSetValueEx( hsubkey + , TEXT("ThreadingModel") + , 0L + , REG_SZ + , (CONST BYTE *)achTemp + , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); + + // close hkeys + // + RegCloseKey( hkey ); + RegCloseKey( hsubkey ); + + // and return + // + return HRESULT_FROM_WIN32(lreturn); + +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupUnregisterServer() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupUnregisterServer( CLSID clsServer ) +{ + // convert CLSID uuid to string and write + // out subkey CLSID\{} + // + OLECHAR szCLSID[CHARS_IN_GUID]; + HRESULT hr = StringFromGUID2( clsServer + , szCLSID + , CHARS_IN_GUID ); + ASSERT( SUCCEEDED(hr) ); + + TCHAR achBuffer[MAX_KEY_LEN]; + (void)StringCchPrintf( achBuffer, NUMELMS(achBuffer), TEXT("CLSID\\%ls"), szCLSID ); + + // delete subkey + // + + hr = EliminateSubKey( HKEY_CLASSES_ROOT, achBuffer ); + ASSERT( SUCCEEDED(hr) ); + + // return + // + return NOERROR; +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupRegisterFilter through IFilterMapper2 +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper2 * pIFM2 + , BOOL bRegister ) +{ + DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + + // unregister filter + // (as pins are subkeys of filter's CLSID key + // they do not need to be removed separately). + // + DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); + HRESULT hr = pIFM2->UnregisterFilter( + 0, // default category + 0, // default instance name + *psetupdata->clsID ); + + + if( bRegister ) + { + REGFILTER2 rf2; + rf2.dwVersion = 1; + rf2.dwMerit = psetupdata->dwMerit; + rf2.cPins = psetupdata->nPins; + rf2.rgPins = psetupdata->lpPin; + + const CLSID *filterCategory=&psetupdata->filterCategory; + + // register filter + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); + hr = pIFM2->RegisterFilter(*psetupdata->clsID + , psetupdata->strName + , 0 // moniker + ,filterCategory // category + , NULL // instance + , &rf2); + } + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + + +//--------------------------------------------------------------------------- +// +// RegisterAllServers() +// +//--------------------------------------------------------------------------- + +STDAPI +RegisterAllServers( LPCWSTR szFileName, BOOL bRegister ) +{ + HRESULT hr = NOERROR; + + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), + (LPCWSTR)pT->m_Name )); + + // register CLSID and InprocServer32 + // + if( bRegister ) + { + hr = AMovieSetupRegisterServer( *(pT->m_ClsID) + , (LPCWSTR)pT->m_Name + , szFileName ); + } + else + { + hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllRegisterServer2() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it registers the Dll as the InprocServer32 +// and then calls the IAMovieSetup.Register +// method. +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieDllRegisterServer2( BOOL bRegister ) +{ + HRESULT hr = NOERROR; + + DbgLog((LOG_TRACE, 2, TEXT("AMovieDllRegisterServer2()"))); + + // get file name (where g_hInst is the + // instance handle of the filter dll) + // + WCHAR achFileName[MAX_PATH]; + + // WIN95 doesn't support GetModuleFileNameW + // + { + char achTemp[MAX_PATH]; + + DbgLog((LOG_TRACE, 2, TEXT("- get module file name"))); + + // g_hInst handle is set in our dll entry point. Make sure + // DllEntryPoint in dllentry.cpp is called + ASSERT(g_hInst != 0); + + if( 0 == GetModuleFileNameA( g_hInst + , achTemp + , sizeof(achTemp) ) ) + { + // we've failed! + DWORD dwerr = GetLastError(); + return AmHresultFromWin32(dwerr); + } + + MultiByteToWideChar( CP_ACP + , 0L + , achTemp + , lstrlenA(achTemp) + 1 + , achFileName + , NUMELMS(achFileName) ); + } + + // + // first registering, register all OLE servers + // + if( bRegister ) + { + DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); + hr = RegisterAllServers( achFileName, TRUE ); + } + + // + // next, register/unregister all filters + // + + if( SUCCEEDED(hr) ) + { + // init is ref counted so call just in case + // we're being called cold. + // + DbgLog((LOG_TRACE, 2, TEXT("- CoInitialize"))); + hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper2 + // + DbgLog((LOG_TRACE, 2, TEXT("- obtain IFilterMapper2"))); + IFilterMapper2 *pIFM2 = 0; + IFilterMapper *pIFM = 0; + hr = CoCreateInstance( CLSID_FilterMapper2 + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper2 + , (void **)&pIFM2 ); + if(FAILED(hr)) + { + DbgLog((LOG_TRACE, 2, TEXT("- trying IFilterMapper instead"))); + + hr = CoCreateInstance( + CLSID_FilterMapper, + NULL, + CLSCTX_INPROC_SERVER, + IID_IFilterMapper, + (void **)&pIFM); + } + if( SUCCEEDED(hr) ) + { + // scan through array of CFactoryTemplates + // registering servers and filters. + // + DbgLog((LOG_TRACE, 2, TEXT("- register Filters"))); + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + if( NULL != pT->m_pAMovieSetup_Filter ) + { + DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), (LPCWSTR)pT->m_Name )); + + if(pIFM2) + { + hr = AMovieSetupRegisterFilter2( pT->m_pAMovieSetup_Filter, pIFM2, bRegister ); + } + else + { + hr = AMovieSetupRegisterFilter( pT->m_pAMovieSetup_Filter, pIFM, bRegister ); + } + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + // release interface + // + if(pIFM2) + pIFM2->Release(); + else + pIFM->Release(); + + } + + // and clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + } + + // + // if unregistering, unregister all OLE servers + // + if( SUCCEEDED(hr) && !bRegister ) + { + DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); + hr = RegisterAllServers( achFileName, FALSE ); + } + + DbgLog((LOG_TRACE, 2, TEXT("- return %0x"), hr)); + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllRegisterServer() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it registers the Dll as the InprocServer32 +// and then calls the IAMovieSetup.Register +// method. +// +//--------------------------------------------------------------------------- + + +STDAPI +AMovieDllRegisterServer( void ) +{ + HRESULT hr = NOERROR; + + // get file name (where g_hInst is the + // instance handle of the filter dll) + // + WCHAR achFileName[MAX_PATH]; + + { + // WIN95 doesn't support GetModuleFileNameW + // + char achTemp[MAX_PATH]; + + if( 0 == GetModuleFileNameA( g_hInst + , achTemp + , sizeof(achTemp) ) ) + { + // we've failed! + DWORD dwerr = GetLastError(); + return AmHresultFromWin32(dwerr); + } + + MultiByteToWideChar( CP_ACP + , 0L + , achTemp + , lstrlenA(achTemp) + 1 + , achFileName + , NUMELMS(achFileName) ); + } + + // scan through array of CFactoryTemplates + // registering servers and filters. + // + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + // register CLSID and InprocServer32 + // + hr = AMovieSetupRegisterServer( *(pT->m_ClsID) + , (LPCWSTR)pT->m_Name + , achFileName ); + + // instantiate all servers and get hold of + // IAMovieSetup, if implemented, and call + // IAMovieSetup.Register() method + // + if( SUCCEEDED(hr) && (NULL != pT->m_lpfnNew) ) + { + // instantiate object + // + PAMOVIESETUP psetup; + hr = CoCreateInstance( *(pT->m_ClsID) + , 0 + , CLSCTX_INPROC_SERVER + , IID_IAMovieSetup + , reinterpret_cast(&psetup) ); + if( SUCCEEDED(hr) ) + { + hr = psetup->Unregister(); + if( SUCCEEDED(hr) ) + hr = psetup->Register(); + psetup->Release(); + } + else + { + if( (E_NOINTERFACE == hr ) + || (VFW_E_NEED_OWNER == hr ) ) + hr = NOERROR; + } + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + + } // end-for + + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllUnregisterServer() +// +// default ActiveMovie dll uninstall function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it calls the IAMovieSetup.Unregister +// method and then unregisters the Dll +// as the InprocServer32 +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieDllUnregisterServer() +{ + // initialize return code + // + HRESULT hr = NOERROR; + + // scan through CFactory template and unregister + // all OLE servers and filters. + // + for( int i = g_cTemplates; i--; ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + // check method exists + // + if( NULL != pT->m_lpfnNew ) + { + // instantiate object + // + PAMOVIESETUP psetup; + hr = CoCreateInstance( *(pT->m_ClsID) + , 0 + , CLSCTX_INPROC_SERVER + , IID_IAMovieSetup + , reinterpret_cast(&psetup) ); + if( SUCCEEDED(hr) ) + { + hr = psetup->Unregister(); + psetup->Release(); + } + else + { + if( (E_NOINTERFACE == hr ) + || (VFW_E_NEED_OWNER == hr ) ) + hr = NOERROR; + } + } + + // unregister CLSID and InprocServer32 + // + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + return hr; +} diff --git a/src/thirdparty/BaseClasses/dllsetup.h b/src/thirdparty/BaseClasses/dllsetup.h index e363b8b6ac2..aaac2ec5e98 100644 --- a/src/thirdparty/BaseClasses/dllsetup.h +++ b/src/thirdparty/BaseClasses/dllsetup.h @@ -1,46 +1,46 @@ -//------------------------------------------------------------------------------ -// File: DllSetup.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// To be self registering, OLE servers must -// export functions named DllRegisterServer -// and DllUnregisterServer. To allow use of -// custom and default implementations the -// defaults are named AMovieDllRegisterServer -// and AMovieDllUnregisterServer. -// -// To the use the default implementation you -// must provide stub functions. -// -// i.e. STDAPI DllRegisterServer() -// { -// return AMovieDllRegisterServer(); -// } -// -// STDAPI DllUnregisterServer() -// { -// return AMovieDllUnregisterServer(); -// } -// -// -// AMovieDllRegisterServer calls IAMovieSetup.Register(), and -// AMovieDllUnregisterServer calls IAMovieSetup.Unregister(). - -STDAPI AMovieDllRegisterServer2( BOOL ); -STDAPI AMovieDllRegisterServer(); -STDAPI AMovieDllUnregisterServer(); - -// helper functions -STDAPI EliminateSubKey( HKEY, LPCTSTR ); - - -STDAPI -AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper2 * pIFM2 - , BOOL bRegister ); - +//------------------------------------------------------------------------------ +// File: DllSetup.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// To be self registering, OLE servers must +// export functions named DllRegisterServer +// and DllUnregisterServer. To allow use of +// custom and default implementations the +// defaults are named AMovieDllRegisterServer +// and AMovieDllUnregisterServer. +// +// To the use the default implementation you +// must provide stub functions. +// +// i.e. STDAPI DllRegisterServer() +// { +// return AMovieDllRegisterServer(); +// } +// +// STDAPI DllUnregisterServer() +// { +// return AMovieDllUnregisterServer(); +// } +// +// +// AMovieDllRegisterServer calls IAMovieSetup.Register(), and +// AMovieDllUnregisterServer calls IAMovieSetup.Unregister(). + +STDAPI AMovieDllRegisterServer2( BOOL ); +STDAPI AMovieDllRegisterServer(); +STDAPI AMovieDllUnregisterServer(); + +// helper functions +STDAPI EliminateSubKey( HKEY, LPCTSTR ); + + +STDAPI +AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper2 * pIFM2 + , BOOL bRegister ); + diff --git a/src/thirdparty/BaseClasses/dxmperf.h b/src/thirdparty/BaseClasses/dxmperf.h index 54a21203b83..dc58ad72383 100644 --- a/src/thirdparty/BaseClasses/dxmperf.h +++ b/src/thirdparty/BaseClasses/dxmperf.h @@ -1,250 +1,250 @@ -//------------------------------------------------------------------------------ -// File: DXMPerf.h -// -// Desc: Macros for DirectShow performance logging. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef _DXMPERF_H_ -#define _DXMPERF_H_ - -#include -#include "perflog.h" - -#ifdef _IA64_ -extern "C" unsigned __int64 __getReg( int whichReg ); -#pragma intrinsic(__getReg) -#endif // _IA64_ - - -inline ULONGLONG _RDTSC( void ) { -#ifdef _X86_ - LARGE_INTEGER li; - __asm { - _emit 0x0F - _emit 0x31 - mov li.LowPart,eax - mov li.HighPart,edx - } - return li.QuadPart; - -#if 0 // This isn't tested yet - -#elif defined (_IA64_) - -#define INL_REGID_APITC 3116 - return __getReg( INL_REGID_APITC ); - -#endif // 0 - -#else // unsupported platform - // not implemented on non x86/IA64 platforms - return 0; -#endif // _X86_/_IA64_ -} - -#define DXMPERF_VIDEOREND 0x00000001 -#define DXMPERF_AUDIOGLITCH 0x00000002 -//#define GETTIME_BIT 0x00000001 -//#define AUDIOREND_BIT 0x00000004 -//#define FRAMEDROP_BIT 0x00000008 -#define AUDIOBREAK_BIT 0x00000010 -#define DXMPERF_AUDIORECV 0x00000020 -#define DXMPERF_AUDIOSLAVE 0x00000040 -#define DXMPERF_AUDIOBREAK 0x00000080 - -#define PERFLOG_CTOR( name, iface ) -#define PERFLOG_DTOR( name, iface ) -#define PERFLOG_DELIVER( name, source, dest, sample, pmt ) -#define PERFLOG_RECEIVE( name, source, dest, sample, pmt ) -#define PERFLOG_RUN( name, iface, time, oldstate ) -#define PERFLOG_PAUSE( name, iface, oldstate ) -#define PERFLOG_STOP( name, iface, oldstate ) -#define PERFLOG_JOINGRAPH( name, iface, graph ) -#define PERFLOG_GETBUFFER( allocator, sample ) -#define PERFLOG_RELBUFFER( allocator, sample ) -#define PERFLOG_CONNECT( connector, connectee, status, pmt ) -#define PERFLOG_RXCONNECT( connector, connectee, status, pmt ) -#define PERFLOG_DISCONNECT( disconnector, disconnectee, status ) - -#define PERFLOG_GETTIME( clock, time ) /*{ \ - PERFINFO_WMI_GETTIME perfData; \ - if (NULL != g_pTraceEvent) { \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_GETTIME; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (ULONGLONG) (time); \ - if (g_perfMasks[GETTIME_INDEX] & GETTIME_BIT) \ - (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ - } \ - }*/ - -#define PERFLOG_AUDIOREND( clocktime, sampletime, psample, bytetime, cbytes ) /*{ \ - PERFINFO_WMI_AVREND perfData; \ - if (NULL != g_pTraceEvent) { \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOREND; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (clocktime); \ - perfData.data.sampleTime = (sampletime); \ - if (g_perfMasks[AUDIOREND_INDEX] & AUDIOREND_BIT) \ - (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ - } \ - }*/ - -#define PERFLOG_AUDIORECV(StreamTime,SampleStart,SampleStop,Discontinuity,Duration) \ - if (PerflogEnableFlags & DXMPERF_AUDIORECV) { \ - PERFINFO_WMI_AUDIORECV perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIORECV; \ - perfData.data.streamTime = StreamTime; \ - perfData.data.sampleStart = SampleStart; \ - perfData.data.sampleStop = SampleStop; \ - perfData.data.discontinuity = Discontinuity; \ - perfData.data.hwduration = Duration; \ - PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_AUDIOSLAVE(MasterClock,SlaveClock,ErrorAccum,LastHighErrorSeen,LastLowErrorSeen) \ - if (PerflogEnableFlags & DXMPERF_AUDIOSLAVE) { \ - PERFINFO_WMI_AUDIOSLAVE perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOSLAVE; \ - perfData.data.masterClock = MasterClock; \ - perfData.data.slaveClock = SlaveClock; \ - perfData.data.errorAccum = ErrorAccum; \ - perfData.data.lastHighErrorSeen = LastHighErrorSeen;\ - perfData.data.lastLowErrorSeen = LastLowErrorSeen; \ - PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_AUDIOADDBREAK(IterNextWrite,OffsetNextWrite,IterWrite,OffsetWrite) \ - if (PerflogEnableFlags & DXMPERF_AUDIOBREAK) { \ - PERFINFO_WMI_AUDIOADDBREAK perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOADDBREAK; \ - perfData.data.iterNextWrite = IterNextWrite; \ - perfData.data.offsetNextWrite = OffsetNextWrite; \ - perfData.data.iterWrite = IterWrite; \ - perfData.data.offsetWrite = OffsetWrite; \ - PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_VIDEOREND( sampletime, clocktime, psample ) \ - if (PerflogEnableFlags & DXMPERF_VIDEOREND) { \ - PERFINFO_WMI_AVREND perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_VIDEOREND; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (clocktime); \ - perfData.data.sampleTime = (sampletime); \ - PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_AUDIOGLITCH( instance, glitchtype, currenttime, previoustime ) \ - if (PerflogEnableFlags & DXMPERF_AUDIOGLITCH) { \ - PERFINFO_WMI_AUDIOGLITCH perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_DSOUNDGLITCH; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.glitchType = (glitchtype); \ - perfData.data.sampleTime = (currenttime); \ - perfData.data.previousTime = (previoustime); \ - perfData.data.instanceId = (instance); \ - PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_FRAMEDROP( sampletime, clocktime, psample, renderer ) /*{ \ - PERFINFO_WMI_FRAMEDROP perfData; \ - if (NULL != g_pTraceEvent) { \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_FRAMEDROP; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (clocktime); \ - perfData.data.frameTime = (sampletime); \ - if (g_perfMasks[FRAMEDROP_INDEX] & FRAMEDROP_BIT) \ - (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ - } \ - }*/ - -/* -#define PERFLOG_AUDIOBREAK( nextwrite, writepos, msecs ) { \ - PERFINFO_WMI_AUDIOBREAK perfData; \ - if (NULL != g_pTraceEvent) { \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOBREAK; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (writepos); \ - perfData.data.sampleTime = (nextwrite); \ - perfData.data.sampleDuration = (msecs); \ - if (g_perfMasks[AUDIOBREAK_INDEX] & AUDIOBREAK_BIT) \ - (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ - } \ - } -*/ - -#define PERFLOG_AUDIOBREAK( nextwrite, writepos, msecs ) \ - if (PerflogEnableFlags & AUDIOBREAK_BIT) { \ - PERFINFO_WMI_AUDIOBREAK perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOBREAK; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (writepos); \ - perfData.data.sampleTime = (nextwrite); \ - perfData.data.sampleDuration = (msecs); \ - PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ - } \ - - -inline -VOID PERFLOG_STREAMTRACE( - ULONG Level, - ULONG Id, - ULONGLONG DShowClock, - ULONGLONG Data1, - ULONGLONG Data2, - ULONGLONG Data3, - ULONGLONG Data4 - ) -{ - if (Level <= PerflogModuleLevel) - { - PERFINFO_WMI_STREAMTRACE perfData; - memset( &perfData, 0, sizeof( perfData ) ); - perfData.header.Size = sizeof( perfData ); - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; - perfData.header.Guid = GUID_STREAMTRACE; - perfData.data.dshowClock = DShowClock; - perfData.data.id = Id; - perfData.data.data[0] = Data1; - perfData.data.data[1] = Data2; - perfData.data.data[2] = Data3; - perfData.data.data[3] = Data4; - PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); - } -} - - -#endif // _DXMPERF_H_ +//------------------------------------------------------------------------------ +// File: DXMPerf.h +// +// Desc: Macros for DirectShow performance logging. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef _DXMPERF_H_ +#define _DXMPERF_H_ + +#include +#include "perflog.h" + +#ifdef _IA64_ +extern "C" unsigned __int64 __getReg( int whichReg ); +#pragma intrinsic(__getReg) +#endif // _IA64_ + + +inline ULONGLONG _RDTSC( void ) { +#ifdef _X86_ + LARGE_INTEGER li; + __asm { + _emit 0x0F + _emit 0x31 + mov li.LowPart,eax + mov li.HighPart,edx + } + return li.QuadPart; + +#if 0 // This isn't tested yet + +#elif defined (_IA64_) + +#define INL_REGID_APITC 3116 + return __getReg( INL_REGID_APITC ); + +#endif // 0 + +#else // unsupported platform + // not implemented on non x86/IA64 platforms + return 0; +#endif // _X86_/_IA64_ +} + +#define DXMPERF_VIDEOREND 0x00000001 +#define DXMPERF_AUDIOGLITCH 0x00000002 +//#define GETTIME_BIT 0x00000001 +//#define AUDIOREND_BIT 0x00000004 +//#define FRAMEDROP_BIT 0x00000008 +#define AUDIOBREAK_BIT 0x00000010 +#define DXMPERF_AUDIORECV 0x00000020 +#define DXMPERF_AUDIOSLAVE 0x00000040 +#define DXMPERF_AUDIOBREAK 0x00000080 + +#define PERFLOG_CTOR( name, iface ) +#define PERFLOG_DTOR( name, iface ) +#define PERFLOG_DELIVER( name, source, dest, sample, pmt ) +#define PERFLOG_RECEIVE( name, source, dest, sample, pmt ) +#define PERFLOG_RUN( name, iface, time, oldstate ) +#define PERFLOG_PAUSE( name, iface, oldstate ) +#define PERFLOG_STOP( name, iface, oldstate ) +#define PERFLOG_JOINGRAPH( name, iface, graph ) +#define PERFLOG_GETBUFFER( allocator, sample ) +#define PERFLOG_RELBUFFER( allocator, sample ) +#define PERFLOG_CONNECT( connector, connectee, status, pmt ) +#define PERFLOG_RXCONNECT( connector, connectee, status, pmt ) +#define PERFLOG_DISCONNECT( disconnector, disconnectee, status ) + +#define PERFLOG_GETTIME( clock, time ) /*{ \ + PERFINFO_WMI_GETTIME perfData; \ + if (NULL != g_pTraceEvent) { \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_GETTIME; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (ULONGLONG) (time); \ + if (g_perfMasks[GETTIME_INDEX] & GETTIME_BIT) \ + (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ + } \ + }*/ + +#define PERFLOG_AUDIOREND( clocktime, sampletime, psample, bytetime, cbytes ) /*{ \ + PERFINFO_WMI_AVREND perfData; \ + if (NULL != g_pTraceEvent) { \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOREND; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (clocktime); \ + perfData.data.sampleTime = (sampletime); \ + if (g_perfMasks[AUDIOREND_INDEX] & AUDIOREND_BIT) \ + (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ + } \ + }*/ + +#define PERFLOG_AUDIORECV(StreamTime,SampleStart,SampleStop,Discontinuity,Duration) \ + if (PerflogEnableFlags & DXMPERF_AUDIORECV) { \ + PERFINFO_WMI_AUDIORECV perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIORECV; \ + perfData.data.streamTime = StreamTime; \ + perfData.data.sampleStart = SampleStart; \ + perfData.data.sampleStop = SampleStop; \ + perfData.data.discontinuity = Discontinuity; \ + perfData.data.hwduration = Duration; \ + PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_AUDIOSLAVE(MasterClock,SlaveClock,ErrorAccum,LastHighErrorSeen,LastLowErrorSeen) \ + if (PerflogEnableFlags & DXMPERF_AUDIOSLAVE) { \ + PERFINFO_WMI_AUDIOSLAVE perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOSLAVE; \ + perfData.data.masterClock = MasterClock; \ + perfData.data.slaveClock = SlaveClock; \ + perfData.data.errorAccum = ErrorAccum; \ + perfData.data.lastHighErrorSeen = LastHighErrorSeen;\ + perfData.data.lastLowErrorSeen = LastLowErrorSeen; \ + PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_AUDIOADDBREAK(IterNextWrite,OffsetNextWrite,IterWrite,OffsetWrite) \ + if (PerflogEnableFlags & DXMPERF_AUDIOBREAK) { \ + PERFINFO_WMI_AUDIOADDBREAK perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOADDBREAK; \ + perfData.data.iterNextWrite = IterNextWrite; \ + perfData.data.offsetNextWrite = OffsetNextWrite; \ + perfData.data.iterWrite = IterWrite; \ + perfData.data.offsetWrite = OffsetWrite; \ + PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_VIDEOREND( sampletime, clocktime, psample ) \ + if (PerflogEnableFlags & DXMPERF_VIDEOREND) { \ + PERFINFO_WMI_AVREND perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_VIDEOREND; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (clocktime); \ + perfData.data.sampleTime = (sampletime); \ + PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_AUDIOGLITCH( instance, glitchtype, currenttime, previoustime ) \ + if (PerflogEnableFlags & DXMPERF_AUDIOGLITCH) { \ + PERFINFO_WMI_AUDIOGLITCH perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_DSOUNDGLITCH; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.glitchType = (glitchtype); \ + perfData.data.sampleTime = (currenttime); \ + perfData.data.previousTime = (previoustime); \ + perfData.data.instanceId = (instance); \ + PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_FRAMEDROP( sampletime, clocktime, psample, renderer ) /*{ \ + PERFINFO_WMI_FRAMEDROP perfData; \ + if (NULL != g_pTraceEvent) { \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_FRAMEDROP; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (clocktime); \ + perfData.data.frameTime = (sampletime); \ + if (g_perfMasks[FRAMEDROP_INDEX] & FRAMEDROP_BIT) \ + (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ + } \ + }*/ + +/* +#define PERFLOG_AUDIOBREAK( nextwrite, writepos, msecs ) { \ + PERFINFO_WMI_AUDIOBREAK perfData; \ + if (NULL != g_pTraceEvent) { \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOBREAK; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (writepos); \ + perfData.data.sampleTime = (nextwrite); \ + perfData.data.sampleDuration = (msecs); \ + if (g_perfMasks[AUDIOBREAK_INDEX] & AUDIOBREAK_BIT) \ + (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ + } \ + } +*/ + +#define PERFLOG_AUDIOBREAK( nextwrite, writepos, msecs ) \ + if (PerflogEnableFlags & AUDIOBREAK_BIT) { \ + PERFINFO_WMI_AUDIOBREAK perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOBREAK; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (writepos); \ + perfData.data.sampleTime = (nextwrite); \ + perfData.data.sampleDuration = (msecs); \ + PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ + } \ + + +inline +VOID PERFLOG_STREAMTRACE( + ULONG Level, + ULONG Id, + ULONGLONG DShowClock, + ULONGLONG Data1, + ULONGLONG Data2, + ULONGLONG Data3, + ULONGLONG Data4 + ) +{ + if (Level <= PerflogModuleLevel) + { + PERFINFO_WMI_STREAMTRACE perfData; + memset( &perfData, 0, sizeof( perfData ) ); + perfData.header.Size = sizeof( perfData ); + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; + perfData.header.Guid = GUID_STREAMTRACE; + perfData.data.dshowClock = DShowClock; + perfData.data.id = Id; + perfData.data.data[0] = Data1; + perfData.data.data[1] = Data2; + perfData.data.data[2] = Data3; + perfData.data.data[3] = Data4; + PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); + } +} + + +#endif // _DXMPERF_H_ diff --git a/src/thirdparty/BaseClasses/fourcc.h b/src/thirdparty/BaseClasses/fourcc.h index 19c0fcdbc56..f4f71e9621f 100644 --- a/src/thirdparty/BaseClasses/fourcc.h +++ b/src/thirdparty/BaseClasses/fourcc.h @@ -1,101 +1,101 @@ -//------------------------------------------------------------------------------ -// File: FourCC.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// FOURCCMap -// -// provides a mapping between old-style multimedia format DWORDs -// and new-style GUIDs. -// -// A range of 4 billion GUIDs has been allocated to ensure that this -// mapping can be done straightforwardly one-to-one in both directions. -// -// January 95 - - -#ifndef __FOURCC__ -#define __FOURCC__ - - -// Multimedia format types are marked with DWORDs built from four 8-bit -// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include -// a subtype GUID. In order to simplify the mapping, GUIDs in the range: -// XXXXXXXX-0000-0010-8000-00AA00389B71 -// are reserved for FOURCCs. - -class FOURCCMap : public GUID -{ - -public: - FOURCCMap(); - FOURCCMap(DWORD Fourcc); - FOURCCMap(const GUID *); - - - DWORD GetFOURCC(void); - void SetFOURCC(DWORD fourcc); - void SetFOURCC(const GUID *); - -private: - void InitGUID(); -}; - -#define GUID_Data2 0 -#define GUID_Data3 0x10 -#define GUID_Data4_1 0xaa000080 -#define GUID_Data4_2 0x719b3800 - -inline void -FOURCCMap::InitGUID() { - Data2 = GUID_Data2; - Data3 = GUID_Data3; - ((DWORD *)Data4)[0] = GUID_Data4_1; - ((DWORD *)Data4)[1] = GUID_Data4_2; -} - -inline -FOURCCMap::FOURCCMap() { - InitGUID(); - SetFOURCC( DWORD(0)); -} - -inline -FOURCCMap::FOURCCMap(DWORD fourcc) -{ - InitGUID(); - SetFOURCC(fourcc); -} - -inline -FOURCCMap::FOURCCMap(const GUID * pGuid) -{ - InitGUID(); - SetFOURCC(pGuid); -} - -inline void -FOURCCMap::SetFOURCC(const GUID * pGuid) -{ - FOURCCMap * p = (FOURCCMap*) pGuid; - SetFOURCC(p->GetFOURCC()); -} - -inline void -FOURCCMap::SetFOURCC(DWORD fourcc) -{ - Data1 = fourcc; -} - -inline DWORD -FOURCCMap::GetFOURCC(void) -{ - return Data1; -} - -#endif /* __FOURCC__ */ - +//------------------------------------------------------------------------------ +// File: FourCC.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// FOURCCMap +// +// provides a mapping between old-style multimedia format DWORDs +// and new-style GUIDs. +// +// A range of 4 billion GUIDs has been allocated to ensure that this +// mapping can be done straightforwardly one-to-one in both directions. +// +// January 95 + + +#ifndef __FOURCC__ +#define __FOURCC__ + + +// Multimedia format types are marked with DWORDs built from four 8-bit +// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include +// a subtype GUID. In order to simplify the mapping, GUIDs in the range: +// XXXXXXXX-0000-0010-8000-00AA00389B71 +// are reserved for FOURCCs. + +class FOURCCMap : public GUID +{ + +public: + FOURCCMap(); + FOURCCMap(DWORD Fourcc); + FOURCCMap(const GUID *); + + + DWORD GetFOURCC(void); + void SetFOURCC(DWORD fourcc); + void SetFOURCC(const GUID *); + +private: + void InitGUID(); +}; + +#define GUID_Data2 0 +#define GUID_Data3 0x10 +#define GUID_Data4_1 0xaa000080 +#define GUID_Data4_2 0x719b3800 + +inline void +FOURCCMap::InitGUID() { + Data2 = GUID_Data2; + Data3 = GUID_Data3; + ((DWORD *)Data4)[0] = GUID_Data4_1; + ((DWORD *)Data4)[1] = GUID_Data4_2; +} + +inline +FOURCCMap::FOURCCMap() { + InitGUID(); + SetFOURCC( DWORD(0)); +} + +inline +FOURCCMap::FOURCCMap(DWORD fourcc) +{ + InitGUID(); + SetFOURCC(fourcc); +} + +inline +FOURCCMap::FOURCCMap(const GUID * pGuid) +{ + InitGUID(); + SetFOURCC(pGuid); +} + +inline void +FOURCCMap::SetFOURCC(const GUID * pGuid) +{ + FOURCCMap * p = (FOURCCMap*) pGuid; + SetFOURCC(p->GetFOURCC()); +} + +inline void +FOURCCMap::SetFOURCC(DWORD fourcc) +{ + Data1 = fourcc; +} + +inline DWORD +FOURCCMap::GetFOURCC(void) +{ + return Data1; +} + +#endif /* __FOURCC__ */ + diff --git a/src/thirdparty/BaseClasses/measure.h b/src/thirdparty/BaseClasses/measure.h index a71a0753260..0babc86008e 100644 --- a/src/thirdparty/BaseClasses/measure.h +++ b/src/thirdparty/BaseClasses/measure.h @@ -1,222 +1,222 @@ -//------------------------------------------------------------------------------ -// File: Measure.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* - The idea is to pepper the source code with interesting measurements and - have the last few thousand of these recorded in a circular buffer that - can be post-processed to give interesting numbers. - - WHAT THE LOG LOOKS LIKE: - - Time (sec) Type Delta Incident_Name - 0.055,41 NOTE -. Incident Nine - Another note - 0.055,42 NOTE 0.000,01 Incident Nine - Another note - 0.055,44 NOTE 0.000,02 Incident Nine - Another note - 0.055,45 STOP -. Incident Eight - Also random - 0.055,47 START -. Incident Seven - Random - 0.055,49 NOTE 0.000,05 Incident Nine - Another note - ------- ---------------- - 0.125,60 STOP 0.000,03 Msr_Stop - 0.125,62 START -. Msr_Start - 0.125,63 START -. Incident Two - Start/Stop - 0.125,65 STOP 0.000,03 Msr_Start - 0.125,66 START -. Msr_Stop - 0.125,68 STOP 0.000,05 Incident Two - Start/Stop - 0.125,70 STOP 0.000,04 Msr_Stop - 0.125,72 START -. Msr_Start - 0.125,73 START -. Incident Two - Start/Stop - 0.125,75 STOP 0.000,03 Msr_Start - 0.125,77 START -. Msr_Stop - 0.125,78 STOP 0.000,05 Incident Two - Start/Stop - 0.125,80 STOP 0.000,03 Msr_Stop - 0.125,81 NOTE -. Incident Three - single Note - 0.125,83 START -. Incident Four - Start, no stop - 0.125,85 START -. Incident Five - Single Start/Stop - 0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop - -Number Average StdDev Smallest Largest Incident_Name - 10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note - 50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop - 1 -. -. -. -. Incident Three - single Note - 0 -. -. -. -. Incident Four - Start, no stop - 1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop - 0 -. -. -. -. Incident Six - zero occurrences - 100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random - 100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random - 5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note - 10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note - 50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start - 50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop - - WHAT IT MEANS: - The log shows what happened and when. Each line shows the time at which - something happened (see WHAT YOU CODE below) what it was that happened - and (if approporate) the time since the corresponding previous event - (that's the delta column). - - The statistics show how many times each event occurred, what the average - delta time was, also the standard deviation, largest and smalles delta. - - WHAT YOU CODE: - - Before anything else executes: - register your ids - - int id1 = Msr_Register("Incident One - Note"); - int id2 = Msr_Register("Incident Two - Start/Stop"); - int id3 = Msr_Register("Incident Three - single Note"); - etc. - - At interesting moments: - - // To measure a repetitive event - e.g. end of bitblt to screen - Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!" - - or - - // To measure an elapsed time e.g. time taken to decode an MPEG B-frame - Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame" - . . . - MsrStop(Id2); // "Finished MPEG decode" - - At the end: - - HANDLE hFile; - hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - Msr_Dump(hFile); // This writes the log out to the file - CloseHandle(hFile); - - or - - Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... )); - // but if you are writing it out to the debugger - // then the times are probably all garbage because - // the debugger can make things run awfully slow. - - A given id should be used either for start / stop or Note calls. If Notes - are mixed in with Starts and Stops their statistics will be gibberish. - - If you code the calls in upper case i.e. MSR_START(idMunge); then you get - macros which will turn into nothing unless PERF is defined. - - You can reset the statistical counts for a given id by calling Reset(Id). - They are reset by default at the start. - It logs Reset as a special incident, so you can see it in the log. - - The log is a circular buffer in storage (to try to minimise disk I/O). - It overwrites the oldest entries once full. The statistics include ALL - incidents since the last Reset, whether still visible in the log or not. -*/ - -#ifndef __MEASURE__ -#define __MEASURE__ - -#ifdef PERF -#define MSR_INIT() Msr_Init() -#define MSR_TERMINATE() Msr_Terminate() -#define MSR_REGISTER(a) Msr_Register(a) -#define MSR_RESET(a) Msr_Reset(a) -#define MSR_CONTROL(a) Msr_Control(a) -#define MSR_START(a) Msr_Start(a) -#define MSR_STOP(a) Msr_Stop(a) -#define MSR_NOTE(a) Msr_Note(a) -#define MSR_INTEGER(a,b) Msr_Integer(a,b) -#define MSR_DUMP(a) Msr_Dump(a) -#define MSR_DUMPSTATS(a) Msr_DumpStats(a) -#else -#define MSR_INIT() ((void)0) -#define MSR_TERMINATE() ((void)0) -#define MSR_REGISTER(a) 0 -#define MSR_RESET(a) ((void)0) -#define MSR_CONTROL(a) ((void)0) -#define MSR_START(a) ((void)0) -#define MSR_STOP(a) ((void)0) -#define MSR_NOTE(a) ((void)0) -#define MSR_INTEGER(a,b) ((void)0) -#define MSR_DUMP(a) ((void)0) -#define MSR_DUMPSTATS(a) ((void)0) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// This must be called first - (called by the DllEntry) - -void WINAPI Msr_Init(void); - - -// Call this last to clean up (or just let it fall off the end - who cares?) - -void WINAPI Msr_Terminate(void); - - -// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note -// everything that's logged is called an "incident". - -int WINAPI Msr_Register(__in LPTSTR Incident); - - -// Reset the statistical counts for an incident - -void WINAPI Msr_Reset(int Id); - - -// Reset all the counts for all incidents -#define MSR_RESET_ALL 0 -#define MSR_PAUSE 1 -#define MSR_RUN 2 - -void WINAPI Msr_Control(int iAction); - - -// log the start of an operation - -void WINAPI Msr_Start(int Id); - - -// log the end of an operation - -void WINAPI Msr_Stop(int Id); - - -// log a one-off or repetitive operation - -void WINAPI Msr_Note(int Id); - - -// log an integer (on which we can see statistics later) -void WINAPI Msr_Integer(int Id, int n); - - -// print out all the vaialable log (it may have wrapped) and then the statistics. -// When the log wraps you lose log but the statistics are still complete. -// hFIle==NULL => use DbgLog -// otherwise hFile must have come from CreateFile or OpenFile. - -void WINAPI Msr_Dump(HANDLE hFile); - - -// just dump the statistics - never mind the log - -void WINAPI Msr_DumpStats(HANDLE hFile); - -// Type definitions in case you want to declare a pointer to the dump functions -// (makes it a trifle easier to do dynamic linking -// i.e. LoadModule, GetProcAddress and call that) - -// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever -typedef void WINAPI MSR_DUMPPROC(HANDLE hFile); -typedef void WINAPI MSR_CONTROLPROC(int iAction); - - -#ifdef __cplusplus -} -#endif - -#endif // __MEASURE__ +//------------------------------------------------------------------------------ +// File: Measure.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* + The idea is to pepper the source code with interesting measurements and + have the last few thousand of these recorded in a circular buffer that + can be post-processed to give interesting numbers. + + WHAT THE LOG LOOKS LIKE: + + Time (sec) Type Delta Incident_Name + 0.055,41 NOTE -. Incident Nine - Another note + 0.055,42 NOTE 0.000,01 Incident Nine - Another note + 0.055,44 NOTE 0.000,02 Incident Nine - Another note + 0.055,45 STOP -. Incident Eight - Also random + 0.055,47 START -. Incident Seven - Random + 0.055,49 NOTE 0.000,05 Incident Nine - Another note + ------- ---------------- + 0.125,60 STOP 0.000,03 Msr_Stop + 0.125,62 START -. Msr_Start + 0.125,63 START -. Incident Two - Start/Stop + 0.125,65 STOP 0.000,03 Msr_Start + 0.125,66 START -. Msr_Stop + 0.125,68 STOP 0.000,05 Incident Two - Start/Stop + 0.125,70 STOP 0.000,04 Msr_Stop + 0.125,72 START -. Msr_Start + 0.125,73 START -. Incident Two - Start/Stop + 0.125,75 STOP 0.000,03 Msr_Start + 0.125,77 START -. Msr_Stop + 0.125,78 STOP 0.000,05 Incident Two - Start/Stop + 0.125,80 STOP 0.000,03 Msr_Stop + 0.125,81 NOTE -. Incident Three - single Note + 0.125,83 START -. Incident Four - Start, no stop + 0.125,85 START -. Incident Five - Single Start/Stop + 0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop + +Number Average StdDev Smallest Largest Incident_Name + 10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note + 50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop + 1 -. -. -. -. Incident Three - single Note + 0 -. -. -. -. Incident Four - Start, no stop + 1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop + 0 -. -. -. -. Incident Six - zero occurrences + 100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random + 100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random + 5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note + 10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note + 50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start + 50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop + + WHAT IT MEANS: + The log shows what happened and when. Each line shows the time at which + something happened (see WHAT YOU CODE below) what it was that happened + and (if approporate) the time since the corresponding previous event + (that's the delta column). + + The statistics show how many times each event occurred, what the average + delta time was, also the standard deviation, largest and smalles delta. + + WHAT YOU CODE: + + Before anything else executes: - register your ids + + int id1 = Msr_Register("Incident One - Note"); + int id2 = Msr_Register("Incident Two - Start/Stop"); + int id3 = Msr_Register("Incident Three - single Note"); + etc. + + At interesting moments: + + // To measure a repetitive event - e.g. end of bitblt to screen + Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!" + + or + + // To measure an elapsed time e.g. time taken to decode an MPEG B-frame + Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame" + . . . + MsrStop(Id2); // "Finished MPEG decode" + + At the end: + + HANDLE hFile; + hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + Msr_Dump(hFile); // This writes the log out to the file + CloseHandle(hFile); + + or + + Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... )); + // but if you are writing it out to the debugger + // then the times are probably all garbage because + // the debugger can make things run awfully slow. + + A given id should be used either for start / stop or Note calls. If Notes + are mixed in with Starts and Stops their statistics will be gibberish. + + If you code the calls in upper case i.e. MSR_START(idMunge); then you get + macros which will turn into nothing unless PERF is defined. + + You can reset the statistical counts for a given id by calling Reset(Id). + They are reset by default at the start. + It logs Reset as a special incident, so you can see it in the log. + + The log is a circular buffer in storage (to try to minimise disk I/O). + It overwrites the oldest entries once full. The statistics include ALL + incidents since the last Reset, whether still visible in the log or not. +*/ + +#ifndef __MEASURE__ +#define __MEASURE__ + +#ifdef PERF +#define MSR_INIT() Msr_Init() +#define MSR_TERMINATE() Msr_Terminate() +#define MSR_REGISTER(a) Msr_Register(a) +#define MSR_RESET(a) Msr_Reset(a) +#define MSR_CONTROL(a) Msr_Control(a) +#define MSR_START(a) Msr_Start(a) +#define MSR_STOP(a) Msr_Stop(a) +#define MSR_NOTE(a) Msr_Note(a) +#define MSR_INTEGER(a,b) Msr_Integer(a,b) +#define MSR_DUMP(a) Msr_Dump(a) +#define MSR_DUMPSTATS(a) Msr_DumpStats(a) +#else +#define MSR_INIT() ((void)0) +#define MSR_TERMINATE() ((void)0) +#define MSR_REGISTER(a) 0 +#define MSR_RESET(a) ((void)0) +#define MSR_CONTROL(a) ((void)0) +#define MSR_START(a) ((void)0) +#define MSR_STOP(a) ((void)0) +#define MSR_NOTE(a) ((void)0) +#define MSR_INTEGER(a,b) ((void)0) +#define MSR_DUMP(a) ((void)0) +#define MSR_DUMPSTATS(a) ((void)0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// This must be called first - (called by the DllEntry) + +void WINAPI Msr_Init(void); + + +// Call this last to clean up (or just let it fall off the end - who cares?) + +void WINAPI Msr_Terminate(void); + + +// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note +// everything that's logged is called an "incident". + +int WINAPI Msr_Register(__in LPTSTR Incident); + + +// Reset the statistical counts for an incident + +void WINAPI Msr_Reset(int Id); + + +// Reset all the counts for all incidents +#define MSR_RESET_ALL 0 +#define MSR_PAUSE 1 +#define MSR_RUN 2 + +void WINAPI Msr_Control(int iAction); + + +// log the start of an operation + +void WINAPI Msr_Start(int Id); + + +// log the end of an operation + +void WINAPI Msr_Stop(int Id); + + +// log a one-off or repetitive operation + +void WINAPI Msr_Note(int Id); + + +// log an integer (on which we can see statistics later) +void WINAPI Msr_Integer(int Id, int n); + + +// print out all the vaialable log (it may have wrapped) and then the statistics. +// When the log wraps you lose log but the statistics are still complete. +// hFIle==NULL => use DbgLog +// otherwise hFile must have come from CreateFile or OpenFile. + +void WINAPI Msr_Dump(HANDLE hFile); + + +// just dump the statistics - never mind the log + +void WINAPI Msr_DumpStats(HANDLE hFile); + +// Type definitions in case you want to declare a pointer to the dump functions +// (makes it a trifle easier to do dynamic linking +// i.e. LoadModule, GetProcAddress and call that) + +// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever +typedef void WINAPI MSR_DUMPPROC(HANDLE hFile); +typedef void WINAPI MSR_CONTROLPROC(int iAction); + + +#ifdef __cplusplus +} +#endif + +#endif // __MEASURE__ diff --git a/src/thirdparty/BaseClasses/msgthrd.h b/src/thirdparty/BaseClasses/msgthrd.h index 45adc01cf09..208f03c82d6 100644 --- a/src/thirdparty/BaseClasses/msgthrd.h +++ b/src/thirdparty/BaseClasses/msgthrd.h @@ -1,120 +1,120 @@ -//------------------------------------------------------------------------------ -// File: MsgThrd.h -// -// Desc: DirectShow base classes - provides support for a worker thread -// class to which one can asynchronously post messages. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Message class - really just a structure. -// -class CMsg { -public: - UINT uMsg; - DWORD dwFlags; - LPVOID lpParam; - CAMEvent *pEvent; - - CMsg(UINT u, DWORD dw, __inout_opt LPVOID lp, __in_opt CAMEvent *pEvnt) - : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {} - - CMsg() - : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {} -}; - -// This is the actual thread class. It exports all the usual thread control -// functions. The created thread is different from a normal WIN32 thread in -// that it is prompted to perform particaular tasks by responding to messages -// posted to its message queue. -// -class AM_NOVTABLE CMsgThread { -private: - static DWORD WINAPI DefaultThreadProc(__inout LPVOID lpParam); - DWORD m_ThreadId; - HANDLE m_hThread; - -protected: - - // if you want to override GetThreadMsg to block on other things - // as well as this queue, you need access to this - CGenericList m_ThreadQueue; - CCritSec m_Lock; - HANDLE m_hSem; - LONG m_lWaiting; - -public: - CMsgThread() - : m_ThreadId(0), - m_hThread(NULL), - m_lWaiting(0), - m_hSem(NULL), - // make a list with a cache of 5 items - m_ThreadQueue(NAME("MsgThread list"), 5) - { - } - - ~CMsgThread(); - // override this if you want to block on other things as well - // as the message loop - void virtual GetThreadMsg(__out CMsg *msg); - - // override this if you want to do something on thread startup - virtual void OnThreadInit() { - }; - - BOOL CreateThread(); - - BOOL WaitForThreadExit(__out LPDWORD lpdwExitCode) { - if (m_hThread != NULL) { - WaitForSingleObject(m_hThread, INFINITE); - return GetExitCodeThread(m_hThread, lpdwExitCode); - } - return FALSE; - } - - DWORD ResumeThread() { - return ::ResumeThread(m_hThread); - } - - DWORD SuspendThread() { - return ::SuspendThread(m_hThread); - } - - int GetThreadPriority() { - return ::GetThreadPriority(m_hThread); - } - - BOOL SetThreadPriority(int nPriority) { - return ::SetThreadPriority(m_hThread, nPriority); - } - - HANDLE GetThreadHandle() { - return m_hThread; - } - - DWORD GetThreadId() { - return m_ThreadId; - } - - - void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags, - __in_opt LPVOID lpMsgParam, __in_opt CAMEvent *pEvent = NULL) { - CAutoLock lck(&m_Lock); - CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent); - m_ThreadQueue.AddTail(pMsg); - if (m_lWaiting != 0) { - ReleaseSemaphore(m_hSem, m_lWaiting, 0); - m_lWaiting = 0; - } - } - - // This is the function prototype of the function that the client - // supplies. It is always called on the created thread, never on - // the creator thread. - // - virtual LRESULT ThreadMessageProc( - UINT uMsg, DWORD dwFlags, __inout_opt LPVOID lpParam, __in_opt CAMEvent *pEvent) = 0; -}; - +//------------------------------------------------------------------------------ +// File: MsgThrd.h +// +// Desc: DirectShow base classes - provides support for a worker thread +// class to which one can asynchronously post messages. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Message class - really just a structure. +// +class CMsg { +public: + UINT uMsg; + DWORD dwFlags; + LPVOID lpParam; + CAMEvent *pEvent; + + CMsg(UINT u, DWORD dw, __inout_opt LPVOID lp, __in_opt CAMEvent *pEvnt) + : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {} + + CMsg() + : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {} +}; + +// This is the actual thread class. It exports all the usual thread control +// functions. The created thread is different from a normal WIN32 thread in +// that it is prompted to perform particaular tasks by responding to messages +// posted to its message queue. +// +class AM_NOVTABLE CMsgThread { +private: + static DWORD WINAPI DefaultThreadProc(__inout LPVOID lpParam); + DWORD m_ThreadId; + HANDLE m_hThread; + +protected: + + // if you want to override GetThreadMsg to block on other things + // as well as this queue, you need access to this + CGenericList m_ThreadQueue; + CCritSec m_Lock; + HANDLE m_hSem; + LONG m_lWaiting; + +public: + CMsgThread() + : m_ThreadId(0), + m_hThread(NULL), + m_lWaiting(0), + m_hSem(NULL), + // make a list with a cache of 5 items + m_ThreadQueue(NAME("MsgThread list"), 5) + { + } + + ~CMsgThread(); + // override this if you want to block on other things as well + // as the message loop + void virtual GetThreadMsg(__out CMsg *msg); + + // override this if you want to do something on thread startup + virtual void OnThreadInit() { + }; + + BOOL CreateThread(); + + BOOL WaitForThreadExit(__out LPDWORD lpdwExitCode) { + if (m_hThread != NULL) { + WaitForSingleObject(m_hThread, INFINITE); + return GetExitCodeThread(m_hThread, lpdwExitCode); + } + return FALSE; + } + + DWORD ResumeThread() { + return ::ResumeThread(m_hThread); + } + + DWORD SuspendThread() { + return ::SuspendThread(m_hThread); + } + + int GetThreadPriority() { + return ::GetThreadPriority(m_hThread); + } + + BOOL SetThreadPriority(int nPriority) { + return ::SetThreadPriority(m_hThread, nPriority); + } + + HANDLE GetThreadHandle() { + return m_hThread; + } + + DWORD GetThreadId() { + return m_ThreadId; + } + + + void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags, + __in_opt LPVOID lpMsgParam, __in_opt CAMEvent *pEvent = NULL) { + CAutoLock lck(&m_Lock); + CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent); + m_ThreadQueue.AddTail(pMsg); + if (m_lWaiting != 0) { + ReleaseSemaphore(m_hSem, m_lWaiting, 0); + m_lWaiting = 0; + } + } + + // This is the function prototype of the function that the client + // supplies. It is always called on the created thread, never on + // the creator thread. + // + virtual LRESULT ThreadMessageProc( + UINT uMsg, DWORD dwFlags, __inout_opt LPVOID lpParam, __in_opt CAMEvent *pEvent) = 0; +}; + diff --git a/src/thirdparty/BaseClasses/mtype.cpp b/src/thirdparty/BaseClasses/mtype.cpp index 325c2c07cec..4fb78df7635 100644 --- a/src/thirdparty/BaseClasses/mtype.cpp +++ b/src/thirdparty/BaseClasses/mtype.cpp @@ -1,478 +1,478 @@ -//------------------------------------------------------------------------------ -// File: MType.cpp -// -// Desc: DirectShow base classes - implements a class that holds and -// manages media type information. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// helper class that derived pin objects can use to compare media -// types etc. Has same data members as the struct AM_MEDIA_TYPE defined -// in the streams IDL file, but also has (non-virtual) functions - -#include "streams.h" -#include - -CMediaType::~CMediaType(){ - FreeMediaType(*this); -} - - -CMediaType::CMediaType() -{ - InitMediaType(); -} - - -CMediaType::CMediaType(const GUID * type) -{ - InitMediaType(); - majortype = *type; -} - - -// copy constructor does a deep copy of the format block - -CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, __out_opt HRESULT* phr) -{ - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr) && (NULL != phr)) { - *phr = hr; - } -} - - -CMediaType::CMediaType(const CMediaType& rt, __out_opt HRESULT* phr) -{ - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr) && (NULL != phr)) { - *phr = hr; - } -} - - -// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate -// the following assignment operator itself, however it could introduce some -// memory conflicts and leaks in the process because the structure contains -// a dynamically allocated block (pbFormat) which it will not copy correctly - -CMediaType& -CMediaType::operator=(const AM_MEDIA_TYPE& rt) -{ - Set(rt); - return *this; -} - -CMediaType& -CMediaType::operator=(const CMediaType& rt) -{ - *this = (AM_MEDIA_TYPE &) rt; - return *this; -} - -BOOL -CMediaType::operator == (const CMediaType& rt) const -{ - // I don't believe we need to check sample size or - // temporal compression flags, since I think these must - // be represented in the type, subtype and format somehow. They - // are pulled out as separate flags so that people who don't understand - // the particular format representation can still see them, but - // they should duplicate information in the format block. - - return ((IsEqualGUID(majortype,rt.majortype) == TRUE) && - (IsEqualGUID(subtype,rt.subtype) == TRUE) && - (IsEqualGUID(formattype,rt.formattype) == TRUE) && - (cbFormat == rt.cbFormat) && - ( (cbFormat == 0) || - pbFormat != NULL && rt.pbFormat != NULL && - (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0))); -} - - -BOOL -CMediaType::operator != (const CMediaType& rt) const -{ - /* Check to see if they are equal */ - - if (*this == rt) { - return FALSE; - } - return TRUE; -} - - -HRESULT -CMediaType::Set(const CMediaType& rt) -{ - return Set((AM_MEDIA_TYPE &) rt); -} - - -HRESULT -CMediaType::Set(const AM_MEDIA_TYPE& rt) -{ - if (&rt != this) { - FreeMediaType(*this); - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr)) { - return E_OUTOFMEMORY; - } - } - - return S_OK; -} - - -BOOL -CMediaType::IsValid() const -{ - return (!IsEqualGUID(majortype,GUID_NULL)); -} - - -void -CMediaType::SetType(const GUID* ptype) -{ - majortype = *ptype; -} - - -void -CMediaType::SetSubtype(const GUID* ptype) -{ - subtype = *ptype; -} - - -ULONG -CMediaType::GetSampleSize() const { - if (IsFixedSize()) { - return lSampleSize; - } else { - return 0; - } -} - - -void -CMediaType::SetSampleSize(ULONG sz) { - if (sz == 0) { - SetVariableSize(); - } else { - bFixedSizeSamples = TRUE; - lSampleSize = sz; - } -} - - -void -CMediaType::SetVariableSize() { - bFixedSizeSamples = FALSE; -} - - -void -CMediaType::SetTemporalCompression(BOOL bCompressed) { - bTemporalCompression = bCompressed; -} - -BOOL -CMediaType::SetFormat(__in_bcount(cb) BYTE * pformat, ULONG cb) -{ - if (NULL == AllocFormatBuffer(cb)) - return(FALSE); - - ASSERT(pbFormat); - memcpy(pbFormat, pformat, cb); - return(TRUE); -} - - -// set the type of the media type format block, this type defines what you -// will actually find in the format pointer. For example FORMAT_VideoInfo or -// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a -// property set. Before sending out media types this should be filled in. - -void -CMediaType::SetFormatType(const GUID *pformattype) -{ - formattype = *pformattype; -} - - -// reset the format buffer - -void CMediaType::ResetFormatBuffer() -{ - if (cbFormat) { - CoTaskMemFree((PVOID)pbFormat); - } - cbFormat = 0; - pbFormat = NULL; -} - - -// allocate length bytes for the format and return a read/write pointer -// If we cannot allocate the new block of memory we return NULL leaving -// the original block of memory untouched (as does ReallocFormatBuffer) - -BYTE* -CMediaType::AllocFormatBuffer(ULONG length) -{ - ASSERT(length); - - // do the types have the same buffer size - - if (cbFormat == length) { - return pbFormat; - } - - // allocate the new format buffer - - BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); - if (pNewFormat == NULL) { - if (length <= cbFormat) return pbFormat; //reuse the old block anyway. - return NULL; - } - - // delete the old format - - if (cbFormat != 0) { - ASSERT(pbFormat); - CoTaskMemFree((PVOID)pbFormat); - } - - cbFormat = length; - pbFormat = pNewFormat; - return pbFormat; -} - - -// reallocate length bytes for the format and return a read/write pointer -// to it. We keep as much information as we can given the new buffer size -// if this fails the original format buffer is left untouched. The caller -// is responsible for ensuring the size of memory required is non zero - -BYTE* -CMediaType::ReallocFormatBuffer(ULONG length) -{ - ASSERT(length); - - // do the types have the same buffer size - - if (cbFormat == length) { - return pbFormat; - } - - // allocate the new format buffer - - BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); - if (pNewFormat == NULL) { - if (length <= cbFormat) return pbFormat; //reuse the old block anyway. - return NULL; - } - - // copy any previous format (or part of if new is smaller) - // delete the old format and replace with the new one - - if (cbFormat != 0) { - ASSERT(pbFormat); - memcpy(pNewFormat,pbFormat,std::min(length,cbFormat)); - CoTaskMemFree((PVOID)pbFormat); - } - - cbFormat = length; - pbFormat = pNewFormat; - return pNewFormat; -} - -// initialise a media type structure - -void CMediaType::InitMediaType() -{ - ZeroMemory((PVOID)this, sizeof(*this)); - lSampleSize = 1; - bFixedSizeSamples = TRUE; -} - - -// a partially specified media type can be passed to IPin::Connect -// as a constraint on the media type used in the connection. -// the type, subtype or format type can be null. -BOOL -CMediaType::IsPartiallySpecified(void) const -{ - if ((majortype == GUID_NULL) || - (formattype == GUID_NULL)) { - return TRUE; - } else { - return FALSE; - } -} - -BOOL -CMediaType::MatchesPartial(const CMediaType* ppartial) const -{ - if ((ppartial->majortype != GUID_NULL) && - (majortype != ppartial->majortype)) { - return FALSE; - } - if ((ppartial->subtype != GUID_NULL) && - (subtype != ppartial->subtype)) { - return FALSE; - } - - if (ppartial->formattype != GUID_NULL) { - // if the format block is specified then it must match exactly - if (formattype != ppartial->formattype) { - return FALSE; - } - if (cbFormat != ppartial->cbFormat) { - return FALSE; - } - if ((cbFormat != 0) && - (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) { - return FALSE; - } - } - - return TRUE; - -} - - - -// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure -// which is useful when calling IEnumMediaTypes::Next as the interface -// implementation allocates the structures which you must later delete -// the format block may also be a pointer to an interface to release - -void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt) -{ - // allow NULL pointers for coding simplicity - - if (pmt == NULL) { - return; - } - - FreeMediaType(*pmt); - CoTaskMemFree((PVOID)pmt); -} - - -// this also comes in useful when using the IEnumMediaTypes interface so -// that you can copy a media type, you can do nearly the same by creating -// a CMediaType object but as soon as it goes out of scope the destructor -// will delete the memory it allocated (this takes a copy of the memory) - -AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc) -{ - ASSERT(pSrc); - - // Allocate a block of memory for the media type - - AM_MEDIA_TYPE *pMediaType = - (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - - if (pMediaType == NULL) { - return NULL; - } - // Copy the variable length format block - - HRESULT hr = CopyMediaType(pMediaType,pSrc); - if (FAILED(hr)) { - CoTaskMemFree((PVOID)pMediaType); - return NULL; - } - - return pMediaType; -} - - -// Copy 1 media type to another - -HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) -{ - // We'll leak if we copy onto one that already exists - there's one - // case we can check like that - copying to itself. - ASSERT(pmtSource != pmtTarget); - *pmtTarget = *pmtSource; - if (pmtSource->cbFormat != 0) { - ASSERT(pmtSource->pbFormat != NULL); - pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat); - if (pmtTarget->pbFormat == NULL) { - pmtTarget->cbFormat = 0; - return E_OUTOFMEMORY; - } else { - CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat, - pmtTarget->cbFormat); - } - } - if (pmtTarget->pUnk != NULL) { - pmtTarget->pUnk->AddRef(); - } - - return S_OK; -} - -// Free an existing media type (ie free resources it holds) - -void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt) -{ - if (mt.cbFormat != 0) { - CoTaskMemFree((PVOID)mt.pbFormat); - - // Strictly unnecessary but tidier - mt.cbFormat = 0; - mt.pbFormat = NULL; - } - if (mt.pUnk != NULL) { - mt.pUnk->Release(); - mt.pUnk = NULL; - } -} - -// Initialize a media type from a WAVEFORMATEX - -STDAPI CreateAudioMediaType( - const WAVEFORMATEX *pwfx, - __out AM_MEDIA_TYPE *pmt, - BOOL bSetFormat -) -{ - pmt->majortype = MEDIATYPE_Audio; - if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat; - } else { - pmt->subtype = FOURCCMap(pwfx->wFormatTag); - } - pmt->formattype = FORMAT_WaveFormatEx; - pmt->bFixedSizeSamples = TRUE; - pmt->bTemporalCompression = FALSE; - pmt->lSampleSize = pwfx->nBlockAlign; - pmt->pUnk = NULL; - if (bSetFormat) { - if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { - pmt->cbFormat = sizeof(WAVEFORMATEX); - } else { - pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize; - } - pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat); - if (pmt->pbFormat == NULL) { - return E_OUTOFMEMORY; - } - if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { - CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); - ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0; - } else { - CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat); - } - } - return S_OK; -} - -// eliminate very many spurious warnings from MS compiler -#pragma warning(disable:4514) +//------------------------------------------------------------------------------ +// File: MType.cpp +// +// Desc: DirectShow base classes - implements a class that holds and +// manages media type information. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// helper class that derived pin objects can use to compare media +// types etc. Has same data members as the struct AM_MEDIA_TYPE defined +// in the streams IDL file, but also has (non-virtual) functions + +#include "streams.h" +#include + +CMediaType::~CMediaType(){ + FreeMediaType(*this); +} + + +CMediaType::CMediaType() +{ + InitMediaType(); +} + + +CMediaType::CMediaType(const GUID * type) +{ + InitMediaType(); + majortype = *type; +} + + +// copy constructor does a deep copy of the format block + +CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, __out_opt HRESULT* phr) +{ + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr) && (NULL != phr)) { + *phr = hr; + } +} + + +CMediaType::CMediaType(const CMediaType& rt, __out_opt HRESULT* phr) +{ + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr) && (NULL != phr)) { + *phr = hr; + } +} + + +// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate +// the following assignment operator itself, however it could introduce some +// memory conflicts and leaks in the process because the structure contains +// a dynamically allocated block (pbFormat) which it will not copy correctly + +CMediaType& +CMediaType::operator=(const AM_MEDIA_TYPE& rt) +{ + Set(rt); + return *this; +} + +CMediaType& +CMediaType::operator=(const CMediaType& rt) +{ + *this = (AM_MEDIA_TYPE &) rt; + return *this; +} + +BOOL +CMediaType::operator == (const CMediaType& rt) const +{ + // I don't believe we need to check sample size or + // temporal compression flags, since I think these must + // be represented in the type, subtype and format somehow. They + // are pulled out as separate flags so that people who don't understand + // the particular format representation can still see them, but + // they should duplicate information in the format block. + + return ((IsEqualGUID(majortype,rt.majortype) == TRUE) && + (IsEqualGUID(subtype,rt.subtype) == TRUE) && + (IsEqualGUID(formattype,rt.formattype) == TRUE) && + (cbFormat == rt.cbFormat) && + ( (cbFormat == 0) || + pbFormat != NULL && rt.pbFormat != NULL && + (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0))); +} + + +BOOL +CMediaType::operator != (const CMediaType& rt) const +{ + /* Check to see if they are equal */ + + if (*this == rt) { + return FALSE; + } + return TRUE; +} + + +HRESULT +CMediaType::Set(const CMediaType& rt) +{ + return Set((AM_MEDIA_TYPE &) rt); +} + + +HRESULT +CMediaType::Set(const AM_MEDIA_TYPE& rt) +{ + if (&rt != this) { + FreeMediaType(*this); + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr)) { + return E_OUTOFMEMORY; + } + } + + return S_OK; +} + + +BOOL +CMediaType::IsValid() const +{ + return (!IsEqualGUID(majortype,GUID_NULL)); +} + + +void +CMediaType::SetType(const GUID* ptype) +{ + majortype = *ptype; +} + + +void +CMediaType::SetSubtype(const GUID* ptype) +{ + subtype = *ptype; +} + + +ULONG +CMediaType::GetSampleSize() const { + if (IsFixedSize()) { + return lSampleSize; + } else { + return 0; + } +} + + +void +CMediaType::SetSampleSize(ULONG sz) { + if (sz == 0) { + SetVariableSize(); + } else { + bFixedSizeSamples = TRUE; + lSampleSize = sz; + } +} + + +void +CMediaType::SetVariableSize() { + bFixedSizeSamples = FALSE; +} + + +void +CMediaType::SetTemporalCompression(BOOL bCompressed) { + bTemporalCompression = bCompressed; +} + +BOOL +CMediaType::SetFormat(__in_bcount(cb) BYTE * pformat, ULONG cb) +{ + if (NULL == AllocFormatBuffer(cb)) + return(FALSE); + + ASSERT(pbFormat); + memcpy(pbFormat, pformat, cb); + return(TRUE); +} + + +// set the type of the media type format block, this type defines what you +// will actually find in the format pointer. For example FORMAT_VideoInfo or +// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a +// property set. Before sending out media types this should be filled in. + +void +CMediaType::SetFormatType(const GUID *pformattype) +{ + formattype = *pformattype; +} + + +// reset the format buffer + +void CMediaType::ResetFormatBuffer() +{ + if (cbFormat) { + CoTaskMemFree((PVOID)pbFormat); + } + cbFormat = 0; + pbFormat = NULL; +} + + +// allocate length bytes for the format and return a read/write pointer +// If we cannot allocate the new block of memory we return NULL leaving +// the original block of memory untouched (as does ReallocFormatBuffer) + +BYTE* +CMediaType::AllocFormatBuffer(ULONG length) +{ + ASSERT(length); + + // do the types have the same buffer size + + if (cbFormat == length) { + return pbFormat; + } + + // allocate the new format buffer + + BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); + if (pNewFormat == NULL) { + if (length <= cbFormat) return pbFormat; //reuse the old block anyway. + return NULL; + } + + // delete the old format + + if (cbFormat != 0) { + ASSERT(pbFormat); + CoTaskMemFree((PVOID)pbFormat); + } + + cbFormat = length; + pbFormat = pNewFormat; + return pbFormat; +} + + +// reallocate length bytes for the format and return a read/write pointer +// to it. We keep as much information as we can given the new buffer size +// if this fails the original format buffer is left untouched. The caller +// is responsible for ensuring the size of memory required is non zero + +BYTE* +CMediaType::ReallocFormatBuffer(ULONG length) +{ + ASSERT(length); + + // do the types have the same buffer size + + if (cbFormat == length) { + return pbFormat; + } + + // allocate the new format buffer + + BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); + if (pNewFormat == NULL) { + if (length <= cbFormat) return pbFormat; //reuse the old block anyway. + return NULL; + } + + // copy any previous format (or part of if new is smaller) + // delete the old format and replace with the new one + + if (cbFormat != 0) { + ASSERT(pbFormat); + memcpy(pNewFormat,pbFormat,std::min(length,cbFormat)); + CoTaskMemFree((PVOID)pbFormat); + } + + cbFormat = length; + pbFormat = pNewFormat; + return pNewFormat; +} + +// initialise a media type structure + +void CMediaType::InitMediaType() +{ + ZeroMemory((PVOID)this, sizeof(*this)); + lSampleSize = 1; + bFixedSizeSamples = TRUE; +} + + +// a partially specified media type can be passed to IPin::Connect +// as a constraint on the media type used in the connection. +// the type, subtype or format type can be null. +BOOL +CMediaType::IsPartiallySpecified(void) const +{ + if ((majortype == GUID_NULL) || + (formattype == GUID_NULL)) { + return TRUE; + } else { + return FALSE; + } +} + +BOOL +CMediaType::MatchesPartial(const CMediaType* ppartial) const +{ + if ((ppartial->majortype != GUID_NULL) && + (majortype != ppartial->majortype)) { + return FALSE; + } + if ((ppartial->subtype != GUID_NULL) && + (subtype != ppartial->subtype)) { + return FALSE; + } + + if (ppartial->formattype != GUID_NULL) { + // if the format block is specified then it must match exactly + if (formattype != ppartial->formattype) { + return FALSE; + } + if (cbFormat != ppartial->cbFormat) { + return FALSE; + } + if ((cbFormat != 0) && + (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) { + return FALSE; + } + } + + return TRUE; + +} + + + +// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure +// which is useful when calling IEnumMediaTypes::Next as the interface +// implementation allocates the structures which you must later delete +// the format block may also be a pointer to an interface to release + +void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt) +{ + // allow NULL pointers for coding simplicity + + if (pmt == NULL) { + return; + } + + FreeMediaType(*pmt); + CoTaskMemFree((PVOID)pmt); +} + + +// this also comes in useful when using the IEnumMediaTypes interface so +// that you can copy a media type, you can do nearly the same by creating +// a CMediaType object but as soon as it goes out of scope the destructor +// will delete the memory it allocated (this takes a copy of the memory) + +AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc) +{ + ASSERT(pSrc); + + // Allocate a block of memory for the media type + + AM_MEDIA_TYPE *pMediaType = + (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + + if (pMediaType == NULL) { + return NULL; + } + // Copy the variable length format block + + HRESULT hr = CopyMediaType(pMediaType,pSrc); + if (FAILED(hr)) { + CoTaskMemFree((PVOID)pMediaType); + return NULL; + } + + return pMediaType; +} + + +// Copy 1 media type to another + +HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) +{ + // We'll leak if we copy onto one that already exists - there's one + // case we can check like that - copying to itself. + ASSERT(pmtSource != pmtTarget); + *pmtTarget = *pmtSource; + if (pmtSource->cbFormat != 0) { + ASSERT(pmtSource->pbFormat != NULL); + pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat); + if (pmtTarget->pbFormat == NULL) { + pmtTarget->cbFormat = 0; + return E_OUTOFMEMORY; + } else { + CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat, + pmtTarget->cbFormat); + } + } + if (pmtTarget->pUnk != NULL) { + pmtTarget->pUnk->AddRef(); + } + + return S_OK; +} + +// Free an existing media type (ie free resources it holds) + +void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt) +{ + if (mt.cbFormat != 0) { + CoTaskMemFree((PVOID)mt.pbFormat); + + // Strictly unnecessary but tidier + mt.cbFormat = 0; + mt.pbFormat = NULL; + } + if (mt.pUnk != NULL) { + mt.pUnk->Release(); + mt.pUnk = NULL; + } +} + +// Initialize a media type from a WAVEFORMATEX + +STDAPI CreateAudioMediaType( + const WAVEFORMATEX *pwfx, + __out AM_MEDIA_TYPE *pmt, + BOOL bSetFormat +) +{ + pmt->majortype = MEDIATYPE_Audio; + if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat; + } else { + pmt->subtype = FOURCCMap(pwfx->wFormatTag); + } + pmt->formattype = FORMAT_WaveFormatEx; + pmt->bFixedSizeSamples = TRUE; + pmt->bTemporalCompression = FALSE; + pmt->lSampleSize = pwfx->nBlockAlign; + pmt->pUnk = NULL; + if (bSetFormat) { + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { + pmt->cbFormat = sizeof(WAVEFORMATEX); + } else { + pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize; + } + pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat); + if (pmt->pbFormat == NULL) { + return E_OUTOFMEMORY; + } + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { + CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); + ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0; + } else { + CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat); + } + } + return S_OK; +} + +// eliminate very many spurious warnings from MS compiler +#pragma warning(disable:4514) diff --git a/src/thirdparty/BaseClasses/mtype.h b/src/thirdparty/BaseClasses/mtype.h index fc2fe53eeda..9402f0644a1 100644 --- a/src/thirdparty/BaseClasses/mtype.h +++ b/src/thirdparty/BaseClasses/mtype.h @@ -1,89 +1,89 @@ -//------------------------------------------------------------------------------ -// File: MtType.h -// -// Desc: DirectShow base classes - defines a class that holds and manages -// media type information. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __MTYPE__ -#define __MTYPE__ - -/* Helper class that derived pin objects can use to compare media - types etc. Has same data members as the struct AM_MEDIA_TYPE defined - in the streams IDL file, but also has (non-virtual) functions */ - -class CMediaType : public _AMMediaType { - -public: - - ~CMediaType(); - CMediaType(); - CMediaType(const GUID * majortype); - CMediaType(const AM_MEDIA_TYPE&, __out_opt HRESULT* phr = NULL); - CMediaType(const CMediaType&, __out_opt HRESULT* phr = NULL); - - CMediaType& operator=(const CMediaType&); - CMediaType& operator=(const AM_MEDIA_TYPE&); - - BOOL operator == (const CMediaType&) const; - BOOL operator != (const CMediaType&) const; - - HRESULT Set(const CMediaType& rt); - HRESULT Set(const AM_MEDIA_TYPE& rt); - - BOOL IsValid() const; - - const GUID *Type() const { return &majortype;} ; - void SetType(const GUID *); - const GUID *Subtype() const { return &subtype;} ; - void SetSubtype(const GUID *); - - BOOL IsFixedSize() const {return bFixedSizeSamples; }; - BOOL IsTemporalCompressed() const {return bTemporalCompression; }; - ULONG GetSampleSize() const; - - void SetSampleSize(ULONG sz); - void SetVariableSize(); - void SetTemporalCompression(BOOL bCompressed); - - // read/write pointer to format - can't change length without - // calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer - - BYTE* Format() const {return pbFormat; }; - ULONG FormatLength() const { return cbFormat; }; - - void SetFormatType(const GUID *); - const GUID *FormatType() const {return &formattype; }; - BOOL SetFormat(__in_bcount(length) BYTE *pFormat, ULONG length); - void ResetFormatBuffer(); - BYTE* AllocFormatBuffer(ULONG length); - BYTE* ReallocFormatBuffer(ULONG length); - - void InitMediaType(); - - BOOL MatchesPartial(const CMediaType* ppartial) const; - BOOL IsPartiallySpecified(void) const; -}; - - -/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE - structure which is useful when using the IEnumMediaFormats interface as - the implementation allocates the structures which you must later delete */ - -void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt); -AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc); -HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource); -void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt); - -// Initialize a media type from a WAVEFORMATEX - -STDAPI CreateAudioMediaType( - const WAVEFORMATEX *pwfx, - __out AM_MEDIA_TYPE *pmt, - BOOL bSetFormat); - -#endif /* __MTYPE__ */ - +//------------------------------------------------------------------------------ +// File: MtType.h +// +// Desc: DirectShow base classes - defines a class that holds and manages +// media type information. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __MTYPE__ +#define __MTYPE__ + +/* Helper class that derived pin objects can use to compare media + types etc. Has same data members as the struct AM_MEDIA_TYPE defined + in the streams IDL file, but also has (non-virtual) functions */ + +class CMediaType : public _AMMediaType { + +public: + + ~CMediaType(); + CMediaType(); + CMediaType(const GUID * majortype); + CMediaType(const AM_MEDIA_TYPE&, __out_opt HRESULT* phr = NULL); + CMediaType(const CMediaType&, __out_opt HRESULT* phr = NULL); + + CMediaType& operator=(const CMediaType&); + CMediaType& operator=(const AM_MEDIA_TYPE&); + + BOOL operator == (const CMediaType&) const; + BOOL operator != (const CMediaType&) const; + + HRESULT Set(const CMediaType& rt); + HRESULT Set(const AM_MEDIA_TYPE& rt); + + BOOL IsValid() const; + + const GUID *Type() const { return &majortype;} ; + void SetType(const GUID *); + const GUID *Subtype() const { return &subtype;} ; + void SetSubtype(const GUID *); + + BOOL IsFixedSize() const {return bFixedSizeSamples; }; + BOOL IsTemporalCompressed() const {return bTemporalCompression; }; + ULONG GetSampleSize() const; + + void SetSampleSize(ULONG sz); + void SetVariableSize(); + void SetTemporalCompression(BOOL bCompressed); + + // read/write pointer to format - can't change length without + // calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer + + BYTE* Format() const {return pbFormat; }; + ULONG FormatLength() const { return cbFormat; }; + + void SetFormatType(const GUID *); + const GUID *FormatType() const {return &formattype; }; + BOOL SetFormat(__in_bcount(length) BYTE *pFormat, ULONG length); + void ResetFormatBuffer(); + BYTE* AllocFormatBuffer(ULONG length); + BYTE* ReallocFormatBuffer(ULONG length); + + void InitMediaType(); + + BOOL MatchesPartial(const CMediaType* ppartial) const; + BOOL IsPartiallySpecified(void) const; +}; + + +/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE + structure which is useful when using the IEnumMediaFormats interface as + the implementation allocates the structures which you must later delete */ + +void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt); +AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc); +HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource); +void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt); + +// Initialize a media type from a WAVEFORMATEX + +STDAPI CreateAudioMediaType( + const WAVEFORMATEX *pwfx, + __out AM_MEDIA_TYPE *pmt, + BOOL bSetFormat); + +#endif /* __MTYPE__ */ + diff --git a/src/thirdparty/BaseClasses/outputq.cpp b/src/thirdparty/BaseClasses/outputq.cpp index d290e300800..9d4cc97211e 100644 --- a/src/thirdparty/BaseClasses/outputq.cpp +++ b/src/thirdparty/BaseClasses/outputq.cpp @@ -1,801 +1,801 @@ -//------------------------------------------------------------------------------ -// File: OutputQ.cpp -// -// Desc: DirectShow base classes - implements COutputQueue class used by an -// output pin which may sometimes want to queue output samples on a -// separate thread and sometimes call Receive() directly on the input -// pin. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - - -// -// COutputQueue Constructor : -// -// Determines if a thread is to be created and creates resources -// -// pInputPin - the downstream input pin we're queueing samples to -// -// phr - changed to a failure code if this function fails -// (otherwise unchanges) -// -// bAuto - Ask pInputPin if it can block in Receive by calling -// its ReceiveCanBlock method and create a thread if -// it can block, otherwise not. -// -// bQueue - if bAuto == FALSE then we create a thread if and only -// if bQueue == TRUE -// -// lBatchSize - work in batches of lBatchSize -// -// bBatchEact - Use exact batch sizes so don't send until the -// batch is full or SendAnyway() is called -// -// lListSize - If we create a thread make the list of samples queued -// to the thread have this size cache -// -// dwPriority - If we create a thread set its priority to this -// -COutputQueue::COutputQueue( - IPin *pInputPin, // Pin to send stuff to - __inout HRESULT *phr, // 'Return code' - BOOL bAuto, // Ask pin if queue or not - BOOL bQueue, // Send through queue - LONG lBatchSize, // Batch - BOOL bBatchExact, // Batch exactly to BatchSize - LONG lListSize, - DWORD dwPriority, - bool bFlushingOpt // flushing optimization - ) : m_lBatchSize(lBatchSize), - m_bBatchExact(bBatchExact && (lBatchSize > 1)), - m_hThread(NULL), - m_hSem(NULL), - m_List(NULL), - m_pPin(pInputPin), - m_ppSamples(NULL), - m_lWaiting(0), - m_evFlushComplete(FALSE, phr), - m_pInputPin(NULL), - m_bSendAnyway(FALSE), - m_nBatched(0), - m_bFlushing(FALSE), - m_bFlushed(TRUE), - m_bFlushingOpt(bFlushingOpt), - m_bTerminate(FALSE), - m_hEventPop(NULL), - m_hr(S_OK) -{ - ASSERT(m_lBatchSize > 0); - - - if (FAILED(*phr)) { - return; - } - - // Check the input pin is OK and cache its IMemInputPin interface - - *phr = pInputPin->QueryInterface(IID_IMemInputPin, (void **)&m_pInputPin); - if (FAILED(*phr)) { - return; - } - - // See if we should ask the downstream pin - - if (bAuto) { - HRESULT hr = m_pInputPin->ReceiveCanBlock(); - if (SUCCEEDED(hr)) { - bQueue = hr == S_OK; - } - } - - // Create our sample batch - - m_ppSamples = new PMEDIASAMPLE[m_lBatchSize]; - if (m_ppSamples == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - - // If we're queueing allocate resources - - if (bQueue) { - DbgLog((LOG_TRACE, 2, TEXT("Creating thread for output pin"))); - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - DWORD dwError = GetLastError(); - *phr = AmHresultFromWin32(dwError); - return; - } - m_List = new CSampleList(NAME("Sample Queue List"), - lListSize, - FALSE // No lock - ); - if (m_List == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - - - DWORD dwThreadId; - m_hThread = CreateThread(NULL, - 0, - InitialThreadProc, - (LPVOID)this, - 0, - &dwThreadId); - if (m_hThread == NULL) { - DWORD dwError = GetLastError(); - *phr = AmHresultFromWin32(dwError); - return; - } - SetThreadPriority(m_hThread, dwPriority); - } else { - DbgLog((LOG_TRACE, 2, TEXT("Calling input pin directly - no thread"))); - } -} - -// -// COutputQueuee Destructor : -// -// Free all resources - -// -// Thread, -// Batched samples -// -COutputQueue::~COutputQueue() -{ - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue::~COutputQueue"))); - /* Free our pointer */ - if (m_pInputPin != NULL) { - m_pInputPin->Release(); - } - if (m_hThread != NULL) { - { - CAutoLock lck(this); - m_bTerminate = TRUE; - m_hr = S_FALSE; - NotifyThread(); - } - DbgWaitForSingleObject(m_hThread); - EXECUTE_ASSERT(CloseHandle(m_hThread)); - - // The thread frees the samples when asked to terminate - - ASSERT(m_List->GetCount() == 0); - delete m_List; - } else { - FreeSamples(); - } - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } - delete [] m_ppSamples; -} - -// -// Call the real thread proc as a member function -// -DWORD WINAPI COutputQueue::InitialThreadProc(__in LPVOID pv) -{ - HRESULT hrCoInit = CAMThread::CoInitializeHelper(); - - COutputQueue *pSampleQueue = (COutputQueue *)pv; - DWORD dwReturn = pSampleQueue->ThreadProc(); - - if(hrCoInit == S_OK) { - CoUninitialize(); - } - - return dwReturn; -} - -// -// Thread sending the samples downstream : -// -// When there is nothing to do the thread sets m_lWaiting (while -// holding the critical section) and then waits for m_hSem to be -// set (not holding the critical section) -// -DWORD COutputQueue::ThreadProc() -{ - for (;;) { - BOOL bWait = FALSE; - IMediaSample *pSample; - LONG lNumberToSend = 0; // Local copy - NewSegmentPacket* ppacket = NULL; - - // - // Get a batch of samples and send it if possible - // In any case exit the loop if there is a control action - // requested - // - { - CAutoLock lck(this); - for (;;) { - - if (m_bTerminate) { - FreeSamples(); - return 0; - } - if (m_bFlushing) { - FreeSamples(); - SetEvent(m_evFlushComplete); - } - - // Get a sample off the list - - pSample = m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - if (pSample != NULL && - !IsSpecialSample(pSample)) { - - // If its just a regular sample just add it to the batch - // and exit the loop if the batch is full - - m_ppSamples[m_nBatched++] = pSample; - if (m_nBatched == m_lBatchSize) { - break; - } - } else { - - // If there was nothing in the queue and there's nothing - // to send (either because there's nothing or the batch - // isn't full) then prepare to wait - - if (pSample == NULL && - (m_bBatchExact || m_nBatched == 0)) { - - // Tell other thread to set the event when there's - // something do to - - ASSERT(m_lWaiting == 0); - m_lWaiting++; - bWait = TRUE; - } else { - - // We break out of the loop on SEND_PACKET unless - // there's nothing to send - - if (pSample == SEND_PACKET && m_nBatched == 0) { - continue; - } - - if (pSample == NEW_SEGMENT) { - // now we need the parameters - we are - // guaranteed that the next packet contains them - ppacket = (NewSegmentPacket *) m_List->RemoveHead(); - // we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - ASSERT(ppacket); - } - // EOS_PACKET falls through here and we exit the loop - // In this way it acts like SEND_PACKET - } - break; - } - } - if (!bWait) { - // We look at m_nBatched from the client side so keep - // it up to date inside the critical section - lNumberToSend = m_nBatched; // Local copy - m_nBatched = 0; - } - } - - // Wait for some more data - - if (bWait) { - DbgWaitForSingleObject(m_hSem); - continue; - } - - - - // OK - send it if there's anything to send - // We DON'T check m_bBatchExact here because either we've got - // a full batch or we dropped through because we got - // SEND_PACKET or EOS_PACKET - both of which imply we should - // flush our batch - - if (lNumberToSend != 0) { - long nProcessed; - if (m_hr == S_OK) { - ASSERT(!m_bFlushed); - HRESULT hr = m_pInputPin->ReceiveMultiple(m_ppSamples, - lNumberToSend, - &nProcessed); - /* Don't overwrite a flushing state HRESULT */ - CAutoLock lck(this); - if (m_hr == S_OK) { - m_hr = hr; - } - ASSERT(!m_bFlushed); - } - while (lNumberToSend != 0) { - m_ppSamples[--lNumberToSend]->Release(); - } - if (m_hr != S_OK) { - - // In any case wait for more data - S_OK just - // means there wasn't an error - - DbgLog((LOG_ERROR, 2, TEXT("ReceiveMultiple returned %8.8X"), - m_hr)); - } - } - - // Check for end of stream - - if (pSample == EOS_PACKET) { - - // We don't send even end of stream on if we've previously - // returned something other than S_OK - // This is because in that case the pin which returned - // something other than S_OK should have either sent - // EndOfStream() or notified the filter graph - - if (m_hr == S_OK) { - DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); - HRESULT hr = m_pPin->EndOfStream(); - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); - } - } - } - - // Data from a new source - - if (pSample == RESET_PACKET) { - m_hr = S_OK; - SetEvent(m_evFlushComplete); - } - - if (pSample == NEW_SEGMENT) { - m_pPin->NewSegment(ppacket->tStart, ppacket->tStop, ppacket->dRate); - delete ppacket; - } - } -} - -// Send batched stuff anyway -void COutputQueue::SendAnyway() -{ - if (!IsQueued()) { - - // m_bSendAnyway is a private parameter checked in ReceiveMultiple - - m_bSendAnyway = TRUE; - LONG nProcessed; - ReceiveMultiple(NULL, 0, &nProcessed); - m_bSendAnyway = FALSE; - - } else { - CAutoLock lck(this); - QueueSample(SEND_PACKET); - NotifyThread(); - } -} - -void -COutputQueue::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (!IsQueued()) { - if (S_OK == m_hr) { - if (m_bBatchExact) { - SendAnyway(); - } - m_pPin->NewSegment(tStart, tStop, dRate); - } - } else { - if (m_hr == S_OK) { - // - // we need to queue the new segment to appear in order in the - // data, but we need to pass parameters to it. Rather than - // take the hit of wrapping every single sample so we can tell - // special ones apart, we queue special pointers to indicate - // special packets, and we guarantee (by holding the - // critical section) that the packet immediately following a - // NEW_SEGMENT value is a NewSegmentPacket containing the - // parameters. - NewSegmentPacket * ppack = new NewSegmentPacket; - if (ppack == NULL) { - return; - } - ppack->tStart = tStart; - ppack->tStop = tStop; - ppack->dRate = dRate; - - CAutoLock lck(this); - QueueSample(NEW_SEGMENT); - QueueSample( (IMediaSample*) ppack); - NotifyThread(); - } - } -} - - -// -// End of Stream is queued to output device -// -void COutputQueue::EOS() -{ - CAutoLock lck(this); - if (!IsQueued()) { - if (m_bBatchExact) { - SendAnyway(); - } - if (m_hr == S_OK) { - DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); - m_bFlushed = FALSE; - HRESULT hr = m_pPin->EndOfStream(); - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); - } - } - } else { - if (m_hr == S_OK) { - m_bFlushed = FALSE; - QueueSample(EOS_PACKET); - NotifyThread(); - } - } -} - -// -// Flush all the samples in the queue -// -void COutputQueue::BeginFlush() -{ - if (IsQueued()) { - { - CAutoLock lck(this); - - // block receives -- we assume this is done by the - // filter in which we are a component - - // discard all queued data - - m_bFlushing = TRUE; - - // Make sure we discard all samples from now on - - if (m_hr == S_OK) { - m_hr = S_FALSE; - } - - // Optimize so we don't keep calling downstream all the time - - if (m_bFlushed && m_bFlushingOpt) { - return; - } - - // Make sure we really wait for the flush to complete - m_evFlushComplete.Reset(); - - NotifyThread(); - } - - // pass this downstream - - m_pPin->BeginFlush(); - } else { - // pass downstream first to avoid deadlocks - m_pPin->BeginFlush(); - CAutoLock lck(this); - // discard all queued data - - m_bFlushing = TRUE; - - // Make sure we discard all samples from now on - - if (m_hr == S_OK) { - m_hr = S_FALSE; - } - } - -} - -// -// leave flush mode - pass this downstream -void COutputQueue::EndFlush() -{ - { - CAutoLock lck(this); - ASSERT(m_bFlushing); - if (m_bFlushingOpt && m_bFlushed && IsQueued()) { - m_bFlushing = FALSE; - m_hr = S_OK; - return; - } - } - - // sync with pushing thread -- done in BeginFlush - // ensure no more data to go downstream -- done in BeginFlush - // - // Because we are synching here there is no need to hold the critical - // section (in fact we'd deadlock if we did!) - - if (IsQueued()) { - m_evFlushComplete.Wait(); - } else { - FreeSamples(); - } - - // Be daring - the caller has guaranteed no samples will arrive - // before EndFlush() returns - - m_bFlushing = FALSE; - m_bFlushed = TRUE; - - // call EndFlush on downstream pins - - m_pPin->EndFlush(); - - m_hr = S_OK; -} - -// COutputQueue::QueueSample -// -// private method to Send a sample to the output queue -// The critical section MUST be held when this is called - -void COutputQueue::QueueSample(IMediaSample *pSample) -{ - if (NULL == m_List->AddTail(pSample)) { - if (!IsSpecialSample(pSample)) { - pSample->Release(); - } - } -} - -// -// COutputQueue::Receive() -// -// Send a single sample by the multiple sample route -// (NOTE - this could be optimized if necessary) -// -// On return the sample will have been Release()'d -// - -HRESULT COutputQueue::Receive(IMediaSample *pSample) -{ - LONG nProcessed; - return ReceiveMultiple(&pSample, 1, &nProcessed); -} - -// -// COutputQueue::ReceiveMultiple() -// -// Send a set of samples to the downstream pin -// -// ppSamples - array of samples -// nSamples - how many -// nSamplesProcessed - How many were processed -// -// On return all samples will have been Release()'d -// - -HRESULT COutputQueue::ReceiveMultiple ( - __in_ecount(nSamples) IMediaSample **ppSamples, - long nSamples, - __out long *nSamplesProcessed) -{ - if (nSamples < 0) { - return E_INVALIDARG; - } - - CAutoLock lck(this); - // Either call directly or queue up the samples - - if (!IsQueued()) { - - // If we already had a bad return code then just return - - if (S_OK != m_hr) { - - // If we've never received anything since the last Flush() - // and the sticky return code is not S_OK we must be - // flushing - // ((!A || B) is equivalent to A implies B) - ASSERT(!m_bFlushed || m_bFlushing); - - // We're supposed to Release() them anyway! - *nSamplesProcessed = 0; - for (int i = 0; i < nSamples; i++) { - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (direct) : Discarding %d samples code 0x%8.8X"), - nSamples, m_hr)); - ppSamples[i]->Release(); - } - - return m_hr; - } - // - // If we're flushing the sticky return code should be S_FALSE - // - ASSERT(!m_bFlushing); - m_bFlushed = FALSE; - - ASSERT(m_nBatched < m_lBatchSize); - ASSERT(m_nBatched == 0 || m_bBatchExact); - - // Loop processing the samples in batches - - LONG iLost = 0; - long iDone = 0; - for (iDone = 0; - iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway); - ) { - -//pragma message (REMIND("Implement threshold scheme")) - ASSERT(m_nBatched < m_lBatchSize); - if (iDone < nSamples) { - m_ppSamples[m_nBatched++] = ppSamples[iDone++]; - } - if (m_nBatched == m_lBatchSize || - nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) { - LONG nDone; - DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"), - m_nBatched)); - - if (m_hr == S_OK) { - m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples, - m_nBatched, - &nDone); - } else { - nDone = 0; - } - iLost += m_nBatched - nDone; - for (LONG i = 0; i < m_nBatched; i++) { - m_ppSamples[i]->Release(); - } - m_nBatched = 0; - } - } - *nSamplesProcessed = iDone - iLost; - if (*nSamplesProcessed < 0) { - *nSamplesProcessed = 0; - } - return m_hr; - } else { - /* We're sending to our thread */ - - if (m_hr != S_OK) { - *nSamplesProcessed = 0; - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (queued) : Discarding %d samples code 0x%8.8X"), - nSamples, m_hr)); - for (int i = 0; i < nSamples; i++) { - ppSamples[i]->Release(); - } - return m_hr; - } - m_bFlushed = FALSE; - for (long i = 0; i < nSamples; i++) { - QueueSample(ppSamples[i]); - } - *nSamplesProcessed = nSamples; - if (!m_bBatchExact || - m_nBatched + m_List->GetCount() >= m_lBatchSize) { - NotifyThread(); - } - return S_OK; - } -} - -// Get ready for new data - cancels sticky m_hr -void COutputQueue::Reset() -{ - if (!IsQueued()) { - m_hr = S_OK; - } else { - { - CAutoLock lck(this); - QueueSample(RESET_PACKET); - NotifyThread(); - } - m_evFlushComplete.Wait(); - } -} - -// Remove and Release() all queued and Batched samples -void COutputQueue::FreeSamples() -{ - CAutoLock lck(this); - if (IsQueued()) { - for (;;) { - IMediaSample *pSample = m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - if (pSample == NULL) { - break; - } - if (!IsSpecialSample(pSample)) { - pSample->Release(); - } else { - if (pSample == NEW_SEGMENT) { - // Free NEW_SEGMENT packet - NewSegmentPacket *ppacket = - (NewSegmentPacket *) m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - ASSERT(ppacket != NULL); - delete ppacket; - } - } - } - } - for (int i = 0; i < m_nBatched; i++) { - m_ppSamples[i]->Release(); - } - m_nBatched = 0; -} - -// Notify the thread if there is something to do -// -// The critical section MUST be held when this is called -void COutputQueue::NotifyThread() -{ - // Optimize - no need to signal if it's not waiting - ASSERT(IsQueued()); - if (m_lWaiting) { - ReleaseSemaphore(m_hSem, m_lWaiting, NULL); - m_lWaiting = 0; - } -} - -// See if there's any work to do -// Returns -// TRUE if there is nothing on the queue and nothing in the batch -// and all data has been sent -// FALSE otherwise -// -BOOL COutputQueue::IsIdle() -{ - CAutoLock lck(this); - - // We're idle if - // there is no thread (!IsQueued()) OR - // the thread is waiting for more work (m_lWaiting != 0) - // AND - // there's nothing in the current batch (m_nBatched == 0) - - if (IsQueued() && m_lWaiting == 0 || m_nBatched != 0) { - return FALSE; - } else { - - // If we're idle it shouldn't be possible for there - // to be anything on the work queue - - ASSERT(!IsQueued() || m_List->GetCount() == 0); - return TRUE; - } -} - - -void COutputQueue::SetPopEvent(HANDLE hEvent) -{ - m_hEventPop = hEvent; -} +//------------------------------------------------------------------------------ +// File: OutputQ.cpp +// +// Desc: DirectShow base classes - implements COutputQueue class used by an +// output pin which may sometimes want to queue output samples on a +// separate thread and sometimes call Receive() directly on the input +// pin. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + + +// +// COutputQueue Constructor : +// +// Determines if a thread is to be created and creates resources +// +// pInputPin - the downstream input pin we're queueing samples to +// +// phr - changed to a failure code if this function fails +// (otherwise unchanges) +// +// bAuto - Ask pInputPin if it can block in Receive by calling +// its ReceiveCanBlock method and create a thread if +// it can block, otherwise not. +// +// bQueue - if bAuto == FALSE then we create a thread if and only +// if bQueue == TRUE +// +// lBatchSize - work in batches of lBatchSize +// +// bBatchEact - Use exact batch sizes so don't send until the +// batch is full or SendAnyway() is called +// +// lListSize - If we create a thread make the list of samples queued +// to the thread have this size cache +// +// dwPriority - If we create a thread set its priority to this +// +COutputQueue::COutputQueue( + IPin *pInputPin, // Pin to send stuff to + __inout HRESULT *phr, // 'Return code' + BOOL bAuto, // Ask pin if queue or not + BOOL bQueue, // Send through queue + LONG lBatchSize, // Batch + BOOL bBatchExact, // Batch exactly to BatchSize + LONG lListSize, + DWORD dwPriority, + bool bFlushingOpt // flushing optimization + ) : m_lBatchSize(lBatchSize), + m_bBatchExact(bBatchExact && (lBatchSize > 1)), + m_hThread(NULL), + m_hSem(NULL), + m_List(NULL), + m_pPin(pInputPin), + m_ppSamples(NULL), + m_lWaiting(0), + m_evFlushComplete(FALSE, phr), + m_pInputPin(NULL), + m_bSendAnyway(FALSE), + m_nBatched(0), + m_bFlushing(FALSE), + m_bFlushed(TRUE), + m_bFlushingOpt(bFlushingOpt), + m_bTerminate(FALSE), + m_hEventPop(NULL), + m_hr(S_OK) +{ + ASSERT(m_lBatchSize > 0); + + + if (FAILED(*phr)) { + return; + } + + // Check the input pin is OK and cache its IMemInputPin interface + + *phr = pInputPin->QueryInterface(IID_IMemInputPin, (void **)&m_pInputPin); + if (FAILED(*phr)) { + return; + } + + // See if we should ask the downstream pin + + if (bAuto) { + HRESULT hr = m_pInputPin->ReceiveCanBlock(); + if (SUCCEEDED(hr)) { + bQueue = hr == S_OK; + } + } + + // Create our sample batch + + m_ppSamples = new PMEDIASAMPLE[m_lBatchSize]; + if (m_ppSamples == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + + // If we're queueing allocate resources + + if (bQueue) { + DbgLog((LOG_TRACE, 2, TEXT("Creating thread for output pin"))); + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + DWORD dwError = GetLastError(); + *phr = AmHresultFromWin32(dwError); + return; + } + m_List = new CSampleList(NAME("Sample Queue List"), + lListSize, + FALSE // No lock + ); + if (m_List == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + + + DWORD dwThreadId; + m_hThread = CreateThread(NULL, + 0, + InitialThreadProc, + (LPVOID)this, + 0, + &dwThreadId); + if (m_hThread == NULL) { + DWORD dwError = GetLastError(); + *phr = AmHresultFromWin32(dwError); + return; + } + SetThreadPriority(m_hThread, dwPriority); + } else { + DbgLog((LOG_TRACE, 2, TEXT("Calling input pin directly - no thread"))); + } +} + +// +// COutputQueuee Destructor : +// +// Free all resources - +// +// Thread, +// Batched samples +// +COutputQueue::~COutputQueue() +{ + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue::~COutputQueue"))); + /* Free our pointer */ + if (m_pInputPin != NULL) { + m_pInputPin->Release(); + } + if (m_hThread != NULL) { + { + CAutoLock lck(this); + m_bTerminate = TRUE; + m_hr = S_FALSE; + NotifyThread(); + } + DbgWaitForSingleObject(m_hThread); + EXECUTE_ASSERT(CloseHandle(m_hThread)); + + // The thread frees the samples when asked to terminate + + ASSERT(m_List->GetCount() == 0); + delete m_List; + } else { + FreeSamples(); + } + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } + delete [] m_ppSamples; +} + +// +// Call the real thread proc as a member function +// +DWORD WINAPI COutputQueue::InitialThreadProc(__in LPVOID pv) +{ + HRESULT hrCoInit = CAMThread::CoInitializeHelper(); + + COutputQueue *pSampleQueue = (COutputQueue *)pv; + DWORD dwReturn = pSampleQueue->ThreadProc(); + + if(hrCoInit == S_OK) { + CoUninitialize(); + } + + return dwReturn; +} + +// +// Thread sending the samples downstream : +// +// When there is nothing to do the thread sets m_lWaiting (while +// holding the critical section) and then waits for m_hSem to be +// set (not holding the critical section) +// +DWORD COutputQueue::ThreadProc() +{ + for (;;) { + BOOL bWait = FALSE; + IMediaSample *pSample; + LONG lNumberToSend = 0; // Local copy + NewSegmentPacket* ppacket = NULL; + + // + // Get a batch of samples and send it if possible + // In any case exit the loop if there is a control action + // requested + // + { + CAutoLock lck(this); + for (;;) { + + if (m_bTerminate) { + FreeSamples(); + return 0; + } + if (m_bFlushing) { + FreeSamples(); + SetEvent(m_evFlushComplete); + } + + // Get a sample off the list + + pSample = m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + if (pSample != NULL && + !IsSpecialSample(pSample)) { + + // If its just a regular sample just add it to the batch + // and exit the loop if the batch is full + + m_ppSamples[m_nBatched++] = pSample; + if (m_nBatched == m_lBatchSize) { + break; + } + } else { + + // If there was nothing in the queue and there's nothing + // to send (either because there's nothing or the batch + // isn't full) then prepare to wait + + if (pSample == NULL && + (m_bBatchExact || m_nBatched == 0)) { + + // Tell other thread to set the event when there's + // something do to + + ASSERT(m_lWaiting == 0); + m_lWaiting++; + bWait = TRUE; + } else { + + // We break out of the loop on SEND_PACKET unless + // there's nothing to send + + if (pSample == SEND_PACKET && m_nBatched == 0) { + continue; + } + + if (pSample == NEW_SEGMENT) { + // now we need the parameters - we are + // guaranteed that the next packet contains them + ppacket = (NewSegmentPacket *) m_List->RemoveHead(); + // we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + ASSERT(ppacket); + } + // EOS_PACKET falls through here and we exit the loop + // In this way it acts like SEND_PACKET + } + break; + } + } + if (!bWait) { + // We look at m_nBatched from the client side so keep + // it up to date inside the critical section + lNumberToSend = m_nBatched; // Local copy + m_nBatched = 0; + } + } + + // Wait for some more data + + if (bWait) { + DbgWaitForSingleObject(m_hSem); + continue; + } + + + + // OK - send it if there's anything to send + // We DON'T check m_bBatchExact here because either we've got + // a full batch or we dropped through because we got + // SEND_PACKET or EOS_PACKET - both of which imply we should + // flush our batch + + if (lNumberToSend != 0) { + long nProcessed; + if (m_hr == S_OK) { + ASSERT(!m_bFlushed); + HRESULT hr = m_pInputPin->ReceiveMultiple(m_ppSamples, + lNumberToSend, + &nProcessed); + /* Don't overwrite a flushing state HRESULT */ + CAutoLock lck(this); + if (m_hr == S_OK) { + m_hr = hr; + } + ASSERT(!m_bFlushed); + } + while (lNumberToSend != 0) { + m_ppSamples[--lNumberToSend]->Release(); + } + if (m_hr != S_OK) { + + // In any case wait for more data - S_OK just + // means there wasn't an error + + DbgLog((LOG_ERROR, 2, TEXT("ReceiveMultiple returned %8.8X"), + m_hr)); + } + } + + // Check for end of stream + + if (pSample == EOS_PACKET) { + + // We don't send even end of stream on if we've previously + // returned something other than S_OK + // This is because in that case the pin which returned + // something other than S_OK should have either sent + // EndOfStream() or notified the filter graph + + if (m_hr == S_OK) { + DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); + HRESULT hr = m_pPin->EndOfStream(); + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); + } + } + } + + // Data from a new source + + if (pSample == RESET_PACKET) { + m_hr = S_OK; + SetEvent(m_evFlushComplete); + } + + if (pSample == NEW_SEGMENT) { + m_pPin->NewSegment(ppacket->tStart, ppacket->tStop, ppacket->dRate); + delete ppacket; + } + } +} + +// Send batched stuff anyway +void COutputQueue::SendAnyway() +{ + if (!IsQueued()) { + + // m_bSendAnyway is a private parameter checked in ReceiveMultiple + + m_bSendAnyway = TRUE; + LONG nProcessed; + ReceiveMultiple(NULL, 0, &nProcessed); + m_bSendAnyway = FALSE; + + } else { + CAutoLock lck(this); + QueueSample(SEND_PACKET); + NotifyThread(); + } +} + +void +COutputQueue::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (!IsQueued()) { + if (S_OK == m_hr) { + if (m_bBatchExact) { + SendAnyway(); + } + m_pPin->NewSegment(tStart, tStop, dRate); + } + } else { + if (m_hr == S_OK) { + // + // we need to queue the new segment to appear in order in the + // data, but we need to pass parameters to it. Rather than + // take the hit of wrapping every single sample so we can tell + // special ones apart, we queue special pointers to indicate + // special packets, and we guarantee (by holding the + // critical section) that the packet immediately following a + // NEW_SEGMENT value is a NewSegmentPacket containing the + // parameters. + NewSegmentPacket * ppack = new NewSegmentPacket; + if (ppack == NULL) { + return; + } + ppack->tStart = tStart; + ppack->tStop = tStop; + ppack->dRate = dRate; + + CAutoLock lck(this); + QueueSample(NEW_SEGMENT); + QueueSample( (IMediaSample*) ppack); + NotifyThread(); + } + } +} + + +// +// End of Stream is queued to output device +// +void COutputQueue::EOS() +{ + CAutoLock lck(this); + if (!IsQueued()) { + if (m_bBatchExact) { + SendAnyway(); + } + if (m_hr == S_OK) { + DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); + m_bFlushed = FALSE; + HRESULT hr = m_pPin->EndOfStream(); + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); + } + } + } else { + if (m_hr == S_OK) { + m_bFlushed = FALSE; + QueueSample(EOS_PACKET); + NotifyThread(); + } + } +} + +// +// Flush all the samples in the queue +// +void COutputQueue::BeginFlush() +{ + if (IsQueued()) { + { + CAutoLock lck(this); + + // block receives -- we assume this is done by the + // filter in which we are a component + + // discard all queued data + + m_bFlushing = TRUE; + + // Make sure we discard all samples from now on + + if (m_hr == S_OK) { + m_hr = S_FALSE; + } + + // Optimize so we don't keep calling downstream all the time + + if (m_bFlushed && m_bFlushingOpt) { + return; + } + + // Make sure we really wait for the flush to complete + m_evFlushComplete.Reset(); + + NotifyThread(); + } + + // pass this downstream + + m_pPin->BeginFlush(); + } else { + // pass downstream first to avoid deadlocks + m_pPin->BeginFlush(); + CAutoLock lck(this); + // discard all queued data + + m_bFlushing = TRUE; + + // Make sure we discard all samples from now on + + if (m_hr == S_OK) { + m_hr = S_FALSE; + } + } + +} + +// +// leave flush mode - pass this downstream +void COutputQueue::EndFlush() +{ + { + CAutoLock lck(this); + ASSERT(m_bFlushing); + if (m_bFlushingOpt && m_bFlushed && IsQueued()) { + m_bFlushing = FALSE; + m_hr = S_OK; + return; + } + } + + // sync with pushing thread -- done in BeginFlush + // ensure no more data to go downstream -- done in BeginFlush + // + // Because we are synching here there is no need to hold the critical + // section (in fact we'd deadlock if we did!) + + if (IsQueued()) { + m_evFlushComplete.Wait(); + } else { + FreeSamples(); + } + + // Be daring - the caller has guaranteed no samples will arrive + // before EndFlush() returns + + m_bFlushing = FALSE; + m_bFlushed = TRUE; + + // call EndFlush on downstream pins + + m_pPin->EndFlush(); + + m_hr = S_OK; +} + +// COutputQueue::QueueSample +// +// private method to Send a sample to the output queue +// The critical section MUST be held when this is called + +void COutputQueue::QueueSample(IMediaSample *pSample) +{ + if (NULL == m_List->AddTail(pSample)) { + if (!IsSpecialSample(pSample)) { + pSample->Release(); + } + } +} + +// +// COutputQueue::Receive() +// +// Send a single sample by the multiple sample route +// (NOTE - this could be optimized if necessary) +// +// On return the sample will have been Release()'d +// + +HRESULT COutputQueue::Receive(IMediaSample *pSample) +{ + LONG nProcessed; + return ReceiveMultiple(&pSample, 1, &nProcessed); +} + +// +// COutputQueue::ReceiveMultiple() +// +// Send a set of samples to the downstream pin +// +// ppSamples - array of samples +// nSamples - how many +// nSamplesProcessed - How many were processed +// +// On return all samples will have been Release()'d +// + +HRESULT COutputQueue::ReceiveMultiple ( + __in_ecount(nSamples) IMediaSample **ppSamples, + long nSamples, + __out long *nSamplesProcessed) +{ + if (nSamples < 0) { + return E_INVALIDARG; + } + + CAutoLock lck(this); + // Either call directly or queue up the samples + + if (!IsQueued()) { + + // If we already had a bad return code then just return + + if (S_OK != m_hr) { + + // If we've never received anything since the last Flush() + // and the sticky return code is not S_OK we must be + // flushing + // ((!A || B) is equivalent to A implies B) + ASSERT(!m_bFlushed || m_bFlushing); + + // We're supposed to Release() them anyway! + *nSamplesProcessed = 0; + for (int i = 0; i < nSamples; i++) { + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (direct) : Discarding %d samples code 0x%8.8X"), + nSamples, m_hr)); + ppSamples[i]->Release(); + } + + return m_hr; + } + // + // If we're flushing the sticky return code should be S_FALSE + // + ASSERT(!m_bFlushing); + m_bFlushed = FALSE; + + ASSERT(m_nBatched < m_lBatchSize); + ASSERT(m_nBatched == 0 || m_bBatchExact); + + // Loop processing the samples in batches + + LONG iLost = 0; + long iDone = 0; + for (iDone = 0; + iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway); + ) { + +//pragma message (REMIND("Implement threshold scheme")) + ASSERT(m_nBatched < m_lBatchSize); + if (iDone < nSamples) { + m_ppSamples[m_nBatched++] = ppSamples[iDone++]; + } + if (m_nBatched == m_lBatchSize || + nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) { + LONG nDone; + DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"), + m_nBatched)); + + if (m_hr == S_OK) { + m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples, + m_nBatched, + &nDone); + } else { + nDone = 0; + } + iLost += m_nBatched - nDone; + for (LONG i = 0; i < m_nBatched; i++) { + m_ppSamples[i]->Release(); + } + m_nBatched = 0; + } + } + *nSamplesProcessed = iDone - iLost; + if (*nSamplesProcessed < 0) { + *nSamplesProcessed = 0; + } + return m_hr; + } else { + /* We're sending to our thread */ + + if (m_hr != S_OK) { + *nSamplesProcessed = 0; + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (queued) : Discarding %d samples code 0x%8.8X"), + nSamples, m_hr)); + for (int i = 0; i < nSamples; i++) { + ppSamples[i]->Release(); + } + return m_hr; + } + m_bFlushed = FALSE; + for (long i = 0; i < nSamples; i++) { + QueueSample(ppSamples[i]); + } + *nSamplesProcessed = nSamples; + if (!m_bBatchExact || + m_nBatched + m_List->GetCount() >= m_lBatchSize) { + NotifyThread(); + } + return S_OK; + } +} + +// Get ready for new data - cancels sticky m_hr +void COutputQueue::Reset() +{ + if (!IsQueued()) { + m_hr = S_OK; + } else { + { + CAutoLock lck(this); + QueueSample(RESET_PACKET); + NotifyThread(); + } + m_evFlushComplete.Wait(); + } +} + +// Remove and Release() all queued and Batched samples +void COutputQueue::FreeSamples() +{ + CAutoLock lck(this); + if (IsQueued()) { + for (;;) { + IMediaSample *pSample = m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + if (pSample == NULL) { + break; + } + if (!IsSpecialSample(pSample)) { + pSample->Release(); + } else { + if (pSample == NEW_SEGMENT) { + // Free NEW_SEGMENT packet + NewSegmentPacket *ppacket = + (NewSegmentPacket *) m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + ASSERT(ppacket != NULL); + delete ppacket; + } + } + } + } + for (int i = 0; i < m_nBatched; i++) { + m_ppSamples[i]->Release(); + } + m_nBatched = 0; +} + +// Notify the thread if there is something to do +// +// The critical section MUST be held when this is called +void COutputQueue::NotifyThread() +{ + // Optimize - no need to signal if it's not waiting + ASSERT(IsQueued()); + if (m_lWaiting) { + ReleaseSemaphore(m_hSem, m_lWaiting, NULL); + m_lWaiting = 0; + } +} + +// See if there's any work to do +// Returns +// TRUE if there is nothing on the queue and nothing in the batch +// and all data has been sent +// FALSE otherwise +// +BOOL COutputQueue::IsIdle() +{ + CAutoLock lck(this); + + // We're idle if + // there is no thread (!IsQueued()) OR + // the thread is waiting for more work (m_lWaiting != 0) + // AND + // there's nothing in the current batch (m_nBatched == 0) + + if (IsQueued() && m_lWaiting == 0 || m_nBatched != 0) { + return FALSE; + } else { + + // If we're idle it shouldn't be possible for there + // to be anything on the work queue + + ASSERT(!IsQueued() || m_List->GetCount() == 0); + return TRUE; + } +} + + +void COutputQueue::SetPopEvent(HANDLE hEvent) +{ + m_hEventPop = hEvent; +} diff --git a/src/thirdparty/BaseClasses/outputq.h b/src/thirdparty/BaseClasses/outputq.h index db3d42433f1..7e60b53a990 100644 --- a/src/thirdparty/BaseClasses/outputq.h +++ b/src/thirdparty/BaseClasses/outputq.h @@ -1,137 +1,137 @@ -//------------------------------------------------------------------------------ -// File: OutputQ.h -// -// Desc: DirectShow base classes - defines the COutputQueue class, which -// makes a queue of samples and sends them to an output pin. The -// class will optionally send the samples to the pin directly. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -typedef CGenericList CSampleList; - -class COutputQueue : public CCritSec -{ -public: - // Constructor - COutputQueue(IPin *pInputPin, // Pin to send stuff to - __inout HRESULT *phr, // 'Return code' - BOOL bAuto = TRUE, // Ask pin if blocks - BOOL bQueue = TRUE, // Send through queue (ignored if - // bAuto set) - LONG lBatchSize = 1, // Batch - BOOL bBatchExact = FALSE,// Batch exactly to BatchSize - LONG lListSize = // Likely number in the list - DEFAULTCACHE, - DWORD dwPriority = // Priority of thread to create - THREAD_PRIORITY_NORMAL, - bool bFlushingOpt = false // flushing optimization - ); - ~COutputQueue(); - - // enter flush state - discard all data - void BeginFlush(); // Begin flushing samples - - // re-enable receives (pass this downstream) - void EndFlush(); // Complete flush of samples - downstream - // pin guaranteed not to block at this stage - - void EOS(); // Call this on End of stream - - void SendAnyway(); // Send batched samples anyway (if bBatchExact set) - - void NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - HRESULT Receive(IMediaSample *pSample); - - // do something with these media samples - HRESULT ReceiveMultiple ( - __in_ecount(nSamples) IMediaSample **pSamples, - long nSamples, - __out long *nSamplesProcessed); - - void Reset(); // Reset m_hr ready for more data - - // See if its idle or not - BOOL IsIdle(); - - // give the class an event to fire after everything removed from the queue - void SetPopEvent(HANDLE hEvent); - -protected: - static DWORD WINAPI InitialThreadProc(__in LPVOID pv); - DWORD ThreadProc(); - BOOL IsQueued() - { - return m_List != NULL; - }; - - // The critical section MUST be held when this is called - void QueueSample(IMediaSample *pSample); - - BOOL IsSpecialSample(IMediaSample *pSample) - { - return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16); - }; - - // Remove and Release() batched and queued samples - void FreeSamples(); - - // Notify the thread there is something to do - void NotifyThread(); - - -protected: - // Queue 'messages' - #define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch - #define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream - #define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr - #define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment - - // new segment packet is always followed by one of these - struct NewSegmentPacket { - REFERENCE_TIME tStart; - REFERENCE_TIME tStop; - double dRate; - }; - - // Remember input stuff - IPin * const m_pPin; - IMemInputPin * m_pInputPin; - BOOL const m_bBatchExact; - LONG const m_lBatchSize; - - CSampleList * m_List; - HANDLE m_hSem; - CAMEvent m_evFlushComplete; - HANDLE m_hThread; - __field_ecount_opt(m_lBatchSize) IMediaSample ** m_ppSamples; - __range(0, m_lBatchSize) LONG m_nBatched; - - // Wait optimization - LONG m_lWaiting; - // Flush synchronization - BOOL m_bFlushing; - - // flushing optimization. some downstream filters have trouble - // with the queue's flushing optimization. other rely on it - BOOL m_bFlushed; - bool m_bFlushingOpt; - - // Terminate now - BOOL m_bTerminate; - - // Send anyway flag for batching - BOOL m_bSendAnyway; - - // Deferred 'return code' - HRESULT volatile m_hr; - - // an event that can be fired after every deliver - HANDLE m_hEventPop; -}; - +//------------------------------------------------------------------------------ +// File: OutputQ.h +// +// Desc: DirectShow base classes - defines the COutputQueue class, which +// makes a queue of samples and sends them to an output pin. The +// class will optionally send the samples to the pin directly. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +typedef CGenericList CSampleList; + +class COutputQueue : public CCritSec +{ +public: + // Constructor + COutputQueue(IPin *pInputPin, // Pin to send stuff to + __inout HRESULT *phr, // 'Return code' + BOOL bAuto = TRUE, // Ask pin if blocks + BOOL bQueue = TRUE, // Send through queue (ignored if + // bAuto set) + LONG lBatchSize = 1, // Batch + BOOL bBatchExact = FALSE,// Batch exactly to BatchSize + LONG lListSize = // Likely number in the list + DEFAULTCACHE, + DWORD dwPriority = // Priority of thread to create + THREAD_PRIORITY_NORMAL, + bool bFlushingOpt = false // flushing optimization + ); + ~COutputQueue(); + + // enter flush state - discard all data + void BeginFlush(); // Begin flushing samples + + // re-enable receives (pass this downstream) + void EndFlush(); // Complete flush of samples - downstream + // pin guaranteed not to block at this stage + + void EOS(); // Call this on End of stream + + void SendAnyway(); // Send batched samples anyway (if bBatchExact set) + + void NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + HRESULT Receive(IMediaSample *pSample); + + // do something with these media samples + HRESULT ReceiveMultiple ( + __in_ecount(nSamples) IMediaSample **pSamples, + long nSamples, + __out long *nSamplesProcessed); + + void Reset(); // Reset m_hr ready for more data + + // See if its idle or not + BOOL IsIdle(); + + // give the class an event to fire after everything removed from the queue + void SetPopEvent(HANDLE hEvent); + +protected: + static DWORD WINAPI InitialThreadProc(__in LPVOID pv); + DWORD ThreadProc(); + BOOL IsQueued() + { + return m_List != NULL; + }; + + // The critical section MUST be held when this is called + void QueueSample(IMediaSample *pSample); + + BOOL IsSpecialSample(IMediaSample *pSample) + { + return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16); + }; + + // Remove and Release() batched and queued samples + void FreeSamples(); + + // Notify the thread there is something to do + void NotifyThread(); + + +protected: + // Queue 'messages' + #define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch + #define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream + #define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr + #define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment + + // new segment packet is always followed by one of these + struct NewSegmentPacket { + REFERENCE_TIME tStart; + REFERENCE_TIME tStop; + double dRate; + }; + + // Remember input stuff + IPin * const m_pPin; + IMemInputPin * m_pInputPin; + BOOL const m_bBatchExact; + LONG const m_lBatchSize; + + CSampleList * m_List; + HANDLE m_hSem; + CAMEvent m_evFlushComplete; + HANDLE m_hThread; + __field_ecount_opt(m_lBatchSize) IMediaSample ** m_ppSamples; + __range(0, m_lBatchSize) LONG m_nBatched; + + // Wait optimization + LONG m_lWaiting; + // Flush synchronization + BOOL m_bFlushing; + + // flushing optimization. some downstream filters have trouble + // with the queue's flushing optimization. other rely on it + BOOL m_bFlushed; + bool m_bFlushingOpt; + + // Terminate now + BOOL m_bTerminate; + + // Send anyway flag for batching + BOOL m_bSendAnyway; + + // Deferred 'return code' + HRESULT volatile m_hr; + + // an event that can be fired after every deliver + HANDLE m_hEventPop; +}; + diff --git a/src/thirdparty/BaseClasses/perflog.cpp b/src/thirdparty/BaseClasses/perflog.cpp index 4c35faf82c4..3b90fe6a0c5 100644 --- a/src/thirdparty/BaseClasses/perflog.cpp +++ b/src/thirdparty/BaseClasses/perflog.cpp @@ -1,347 +1,347 @@ -//------------------------------------------------------------------------------ -// File: perflog.cpp -// -// Desc: Macros for DirectShow performance logging. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - -#pragma warning (disable:4201) - -#include "streams.h" -#include -#include -#include -#include -#include -#include -#include "perflog.h" - -// -// Local function prototypes. -// - -ULONG -WINAPI -PerflogCallback ( - WMIDPREQUESTCODE RequestCode, - __in PVOID Context, - __out ULONG* BufferSize, - __in PVOID Buffer - ); - -// -// Event tracing function pointers. -// We have to do this to run on down-level platforms. -// - -#ifdef UNICODE - -ULONG -(__stdcall * _RegisterTraceGuids) ( - __in IN WMIDPREQUEST RequestAddress, - __in IN PVOID RequestContext, - IN LPCGUID ControlGuid, - IN ULONG GuidCount, - __in IN PTRACE_GUID_REGISTRATION TraceGuidReg, - IN LPCWSTR MofImagePath, - IN LPCWSTR MofResourceName, - OUT PTRACEHANDLE RegistrationHandle - ); - -#define REGISTERTRACEGUIDS_NAME "RegisterTraceGuidsW" - -#else - -ULONG -(__stdcall * _RegisterTraceGuids) ( - __in IN WMIDPREQUEST RequestAddress, - __in IN PVOID RequestContext, - IN LPCGUID ControlGuid, - IN ULONG GuidCount, - __in IN PTRACE_GUID_REGISTRATION TraceGuidReg, - IN LPCSTR MofImagePath, - IN LPCSTR MofResourceName, - __out OUT PTRACEHANDLE RegistrationHandle - ); - -#define REGISTERTRACEGUIDS_NAME "RegisterTraceGuidsA" - -#endif - -ULONG -(__stdcall * _UnregisterTraceGuids) ( - TRACEHANDLE RegistrationHandle - ); - -TRACEHANDLE -(__stdcall * _GetTraceLoggerHandle) ( - __in PVOID Buffer - ); - -UCHAR -(__stdcall * _GetTraceEnableLevel) ( - TRACEHANDLE TraceHandle - ); - -ULONG -(__stdcall * _GetTraceEnableFlags) ( - TRACEHANDLE TraceHandle - ); - -ULONG -(__stdcall * _TraceEvent) ( - TRACEHANDLE TraceHandle, - __in PEVENT_TRACE_HEADER EventTrace - ); - -HINSTANCE _Advapi32; - -// -// Global variables. -// - -BOOL EventTracingAvailable=FALSE; -ULONG PerflogEnableFlags; -UCHAR PerflogEnableLevel; -ULONG PerflogModuleLevel = 0; -void (*OnStateChanged)(void); -TRACEHANDLE PerflogTraceHandle=NULL; -TRACEHANDLE PerflogRegHandle; - -// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. -// See the documentation for wsprintf()'s lpOut parameter for more information. -const INT iDEBUGINFO = 1024; // Used to format strings - -// -// This routine initializes performance logging. -// It should be called from DllMain(). -// - - -VOID -PerflogReadModuleLevel( - HINSTANCE hInstance - ) -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - TCHAR szFullName[iDEBUGINFO]; // Load the full path and module name - HKEY hModuleKey; // Module key handle - LPTSTR pName; // Searches from the end for a backslash - DWORD dwKeySize, dwKeyType, dwKeyValue; - - DWORD dwSize = GetModuleFileName( - (hInstance ? hInstance : GetModuleHandle( NULL )), - szFullName, - iDEBUGINFO ); - - if (0 == dwSize || iDEBUGINFO == dwSize) { - return; - } - - pName = _tcsrchr(szFullName,'\\'); - if (pName == NULL) { - pName = szFullName; - } else { - pName++; - } - - /* Construct the base key name */ - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("SOFTWARE\\Debug\\%s"),pName); - - /* Open the key for this module */ - lReturn = - RegOpenKeyEx( - HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - KEY_QUERY_VALUE, // Desired security access - &hModuleKey ); // Opened handle buffer - - if (lReturn != ERROR_SUCCESS) { - return; - } - - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hModuleKey, // Handle to an open key - TEXT("PERFLOG"), - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) &dwKeyValue, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - if ((lReturn == ERROR_SUCCESS) && (dwKeyType == REG_DWORD)) - { - PerflogModuleLevel = dwKeyValue; - } - - RegCloseKey(hModuleKey); -} - -BOOL PerflogInitIfEnabled( - IN HINSTANCE hInstance, - __in IN PPERFLOG_LOGGING_PARAMS LogParams - ) -{ - PerflogReadModuleLevel( hInstance ); - if (PerflogModuleLevel) - { - return PerflogInitialize( LogParams ); - } - else - { - return FALSE; - } -} - -BOOL -PerflogInitialize ( - __in IN PPERFLOG_LOGGING_PARAMS LogParams - ) -{ - ULONG status; - - // - // If we're running on a recent-enough platform, this will get - // pointers to the event tracing routines. - // - - _Advapi32 = GetModuleHandle (_T("ADVAPI32.DLL")); - if (_Advapi32 == NULL) { - return FALSE; - } - - *((FARPROC*) &_RegisterTraceGuids) = GetProcAddress (_Advapi32, REGISTERTRACEGUIDS_NAME); - *((FARPROC*) &_UnregisterTraceGuids) = GetProcAddress (_Advapi32, "UnregisterTraceGuids"); - *((FARPROC*) &_GetTraceLoggerHandle) = GetProcAddress (_Advapi32, "GetTraceLoggerHandle"); - *((FARPROC*) &_GetTraceEnableLevel) = GetProcAddress (_Advapi32, "GetTraceEnableLevel"); - *((FARPROC*) &_GetTraceEnableFlags) = GetProcAddress (_Advapi32, "GetTraceEnableFlags"); - *((FARPROC*) &_TraceEvent) = GetProcAddress (_Advapi32, "TraceEvent"); - - if (_RegisterTraceGuids == NULL || - _UnregisterTraceGuids == NULL || - _GetTraceEnableLevel == NULL || - _GetTraceEnableFlags == NULL || - _TraceEvent == NULL) { - - return FALSE; - } - - EventTracingAvailable = TRUE; - - OnStateChanged = LogParams->OnStateChanged; - - // - // Register our GUIDs. - // - - status = _RegisterTraceGuids (PerflogCallback, - LogParams, - &LogParams->ControlGuid, - LogParams->NumberOfTraceGuids, - LogParams->TraceGuids, - NULL, - NULL, - &PerflogRegHandle); - - return (status == ERROR_SUCCESS); -} - -// -// This routine shuts down performance logging. -// - -VOID -PerflogShutdown ( - VOID - ) -{ - if (!EventTracingAvailable) { - return; - } - - _UnregisterTraceGuids (PerflogRegHandle); - PerflogRegHandle = NULL; - PerflogTraceHandle = NULL; -} - -// -// Event tracing callback routine. -// It's called when controllers call event tracing control functions. -// - -ULONG -WINAPI -PerflogCallback ( - WMIDPREQUESTCODE RequestCode, - __in PVOID Context, - __out ULONG* BufferSize, - __in PVOID Buffer - ) -{ - ULONG status; - - UNREFERENCED_PARAMETER (Context); - - ASSERT (EventTracingAvailable); - - status = ERROR_SUCCESS; - - switch (RequestCode) { - - case WMI_ENABLE_EVENTS: - PerflogTraceHandle = _GetTraceLoggerHandle (Buffer); - PerflogEnableFlags = _GetTraceEnableFlags (PerflogTraceHandle); - PerflogEnableLevel = _GetTraceEnableLevel (PerflogTraceHandle); - break; - - case WMI_DISABLE_EVENTS: - PerflogTraceHandle = NULL; - PerflogEnableFlags = 0; - PerflogEnableLevel = 0; - break; - - default: - status = ERROR_INVALID_PARAMETER; - } - - if (OnStateChanged != NULL) { - OnStateChanged(); - } - - *BufferSize = 0; - return status; -} - -// -// Logging routine. -// - -VOID -PerflogTraceEvent ( - __in PEVENT_TRACE_HEADER Event - ) -{ - if (!EventTracingAvailable) { - return; - } - - _TraceEvent (PerflogTraceHandle, Event); -} - -VOID -PerflogTraceEventLevel( - ULONG Level, - __in PEVENT_TRACE_HEADER Event - ) -{ - if ((!EventTracingAvailable) || (Level <= PerflogModuleLevel)) { - return; - } - - _TraceEvent (PerflogTraceHandle, Event); -} - - +//------------------------------------------------------------------------------ +// File: perflog.cpp +// +// Desc: Macros for DirectShow performance logging. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +#pragma warning (disable:4201) + +#include "streams.h" +#include +#include +#include +#include +#include +#include +#include "perflog.h" + +// +// Local function prototypes. +// + +ULONG +WINAPI +PerflogCallback ( + WMIDPREQUESTCODE RequestCode, + __in PVOID Context, + __out ULONG* BufferSize, + __in PVOID Buffer + ); + +// +// Event tracing function pointers. +// We have to do this to run on down-level platforms. +// + +#ifdef UNICODE + +ULONG +(__stdcall * _RegisterTraceGuids) ( + __in IN WMIDPREQUEST RequestAddress, + __in IN PVOID RequestContext, + IN LPCGUID ControlGuid, + IN ULONG GuidCount, + __in IN PTRACE_GUID_REGISTRATION TraceGuidReg, + IN LPCWSTR MofImagePath, + IN LPCWSTR MofResourceName, + OUT PTRACEHANDLE RegistrationHandle + ); + +#define REGISTERTRACEGUIDS_NAME "RegisterTraceGuidsW" + +#else + +ULONG +(__stdcall * _RegisterTraceGuids) ( + __in IN WMIDPREQUEST RequestAddress, + __in IN PVOID RequestContext, + IN LPCGUID ControlGuid, + IN ULONG GuidCount, + __in IN PTRACE_GUID_REGISTRATION TraceGuidReg, + IN LPCSTR MofImagePath, + IN LPCSTR MofResourceName, + __out OUT PTRACEHANDLE RegistrationHandle + ); + +#define REGISTERTRACEGUIDS_NAME "RegisterTraceGuidsA" + +#endif + +ULONG +(__stdcall * _UnregisterTraceGuids) ( + TRACEHANDLE RegistrationHandle + ); + +TRACEHANDLE +(__stdcall * _GetTraceLoggerHandle) ( + __in PVOID Buffer + ); + +UCHAR +(__stdcall * _GetTraceEnableLevel) ( + TRACEHANDLE TraceHandle + ); + +ULONG +(__stdcall * _GetTraceEnableFlags) ( + TRACEHANDLE TraceHandle + ); + +ULONG +(__stdcall * _TraceEvent) ( + TRACEHANDLE TraceHandle, + __in PEVENT_TRACE_HEADER EventTrace + ); + +HINSTANCE _Advapi32; + +// +// Global variables. +// + +BOOL EventTracingAvailable=FALSE; +ULONG PerflogEnableFlags; +UCHAR PerflogEnableLevel; +ULONG PerflogModuleLevel = 0; +void (*OnStateChanged)(void); +TRACEHANDLE PerflogTraceHandle=NULL; +TRACEHANDLE PerflogRegHandle; + +// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. +// See the documentation for wsprintf()'s lpOut parameter for more information. +const INT iDEBUGINFO = 1024; // Used to format strings + +// +// This routine initializes performance logging. +// It should be called from DllMain(). +// + + +VOID +PerflogReadModuleLevel( + HINSTANCE hInstance + ) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + TCHAR szFullName[iDEBUGINFO]; // Load the full path and module name + HKEY hModuleKey; // Module key handle + LPTSTR pName; // Searches from the end for a backslash + DWORD dwKeySize, dwKeyType, dwKeyValue; + + DWORD dwSize = GetModuleFileName( + (hInstance ? hInstance : GetModuleHandle( NULL )), + szFullName, + iDEBUGINFO ); + + if (0 == dwSize || iDEBUGINFO == dwSize) { + return; + } + + pName = _tcsrchr(szFullName,'\\'); + if (pName == NULL) { + pName = szFullName; + } else { + pName++; + } + + /* Construct the base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("SOFTWARE\\Debug\\%s"),pName); + + /* Open the key for this module */ + lReturn = + RegOpenKeyEx( + HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + KEY_QUERY_VALUE, // Desired security access + &hModuleKey ); // Opened handle buffer + + if (lReturn != ERROR_SUCCESS) { + return; + } + + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hModuleKey, // Handle to an open key + TEXT("PERFLOG"), + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwKeyValue, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + if ((lReturn == ERROR_SUCCESS) && (dwKeyType == REG_DWORD)) + { + PerflogModuleLevel = dwKeyValue; + } + + RegCloseKey(hModuleKey); +} + +BOOL PerflogInitIfEnabled( + IN HINSTANCE hInstance, + __in IN PPERFLOG_LOGGING_PARAMS LogParams + ) +{ + PerflogReadModuleLevel( hInstance ); + if (PerflogModuleLevel) + { + return PerflogInitialize( LogParams ); + } + else + { + return FALSE; + } +} + +BOOL +PerflogInitialize ( + __in IN PPERFLOG_LOGGING_PARAMS LogParams + ) +{ + ULONG status; + + // + // If we're running on a recent-enough platform, this will get + // pointers to the event tracing routines. + // + + _Advapi32 = GetModuleHandle (_T("ADVAPI32.DLL")); + if (_Advapi32 == NULL) { + return FALSE; + } + + *((FARPROC*) &_RegisterTraceGuids) = GetProcAddress (_Advapi32, REGISTERTRACEGUIDS_NAME); + *((FARPROC*) &_UnregisterTraceGuids) = GetProcAddress (_Advapi32, "UnregisterTraceGuids"); + *((FARPROC*) &_GetTraceLoggerHandle) = GetProcAddress (_Advapi32, "GetTraceLoggerHandle"); + *((FARPROC*) &_GetTraceEnableLevel) = GetProcAddress (_Advapi32, "GetTraceEnableLevel"); + *((FARPROC*) &_GetTraceEnableFlags) = GetProcAddress (_Advapi32, "GetTraceEnableFlags"); + *((FARPROC*) &_TraceEvent) = GetProcAddress (_Advapi32, "TraceEvent"); + + if (_RegisterTraceGuids == NULL || + _UnregisterTraceGuids == NULL || + _GetTraceEnableLevel == NULL || + _GetTraceEnableFlags == NULL || + _TraceEvent == NULL) { + + return FALSE; + } + + EventTracingAvailable = TRUE; + + OnStateChanged = LogParams->OnStateChanged; + + // + // Register our GUIDs. + // + + status = _RegisterTraceGuids (PerflogCallback, + LogParams, + &LogParams->ControlGuid, + LogParams->NumberOfTraceGuids, + LogParams->TraceGuids, + NULL, + NULL, + &PerflogRegHandle); + + return (status == ERROR_SUCCESS); +} + +// +// This routine shuts down performance logging. +// + +VOID +PerflogShutdown ( + VOID + ) +{ + if (!EventTracingAvailable) { + return; + } + + _UnregisterTraceGuids (PerflogRegHandle); + PerflogRegHandle = NULL; + PerflogTraceHandle = NULL; +} + +// +// Event tracing callback routine. +// It's called when controllers call event tracing control functions. +// + +ULONG +WINAPI +PerflogCallback ( + WMIDPREQUESTCODE RequestCode, + __in PVOID Context, + __out ULONG* BufferSize, + __in PVOID Buffer + ) +{ + ULONG status; + + UNREFERENCED_PARAMETER (Context); + + ASSERT (EventTracingAvailable); + + status = ERROR_SUCCESS; + + switch (RequestCode) { + + case WMI_ENABLE_EVENTS: + PerflogTraceHandle = _GetTraceLoggerHandle (Buffer); + PerflogEnableFlags = _GetTraceEnableFlags (PerflogTraceHandle); + PerflogEnableLevel = _GetTraceEnableLevel (PerflogTraceHandle); + break; + + case WMI_DISABLE_EVENTS: + PerflogTraceHandle = NULL; + PerflogEnableFlags = 0; + PerflogEnableLevel = 0; + break; + + default: + status = ERROR_INVALID_PARAMETER; + } + + if (OnStateChanged != NULL) { + OnStateChanged(); + } + + *BufferSize = 0; + return status; +} + +// +// Logging routine. +// + +VOID +PerflogTraceEvent ( + __in PEVENT_TRACE_HEADER Event + ) +{ + if (!EventTracingAvailable) { + return; + } + + _TraceEvent (PerflogTraceHandle, Event); +} + +VOID +PerflogTraceEventLevel( + ULONG Level, + __in PEVENT_TRACE_HEADER Event + ) +{ + if ((!EventTracingAvailable) || (Level <= PerflogModuleLevel)) { + return; + } + + _TraceEvent (PerflogTraceHandle, Event); +} + + diff --git a/src/thirdparty/BaseClasses/perflog.h b/src/thirdparty/BaseClasses/perflog.h index 503a1304f25..05d6404f6ae 100644 --- a/src/thirdparty/BaseClasses/perflog.h +++ b/src/thirdparty/BaseClasses/perflog.h @@ -1,56 +1,56 @@ -//------------------------------------------------------------------------------ -// File: perflog.h -// -// Desc: Performance logging framework. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - -typedef struct _PERFLOG_LOGGING_PARAMS { - GUID ControlGuid; - void (*OnStateChanged)(void); - ULONG NumberOfTraceGuids; - TRACE_GUID_REGISTRATION TraceGuids[ANYSIZE_ARRAY]; -} PERFLOG_LOGGING_PARAMS, *PPERFLOG_LOGGING_PARAMS; - -BOOL -PerflogInitIfEnabled( - IN HINSTANCE hInstance, - __in PPERFLOG_LOGGING_PARAMS LogParams - ); - -BOOL -PerflogInitialize ( - __in PPERFLOG_LOGGING_PARAMS LogParams - ); - -VOID -PerflogShutdown ( - VOID - ); - -VOID -PerflogTraceEvent ( - __in PEVENT_TRACE_HEADER Event - ); - -extern ULONG PerflogEnableFlags; -extern UCHAR PerflogEnableLevel; -extern ULONG PerflogModuleLevel; -extern TRACEHANDLE PerflogTraceHandle; -extern TRACEHANDLE PerflogRegHandle; - -#define PerflogTracingEnabled() (PerflogTraceHandle != 0) - -#define PerflogEvent( _x_ ) PerflogTraceEventLevel _x_ - -VOID -PerflogTraceEventLevel( - ULONG Level, - __in PEVENT_TRACE_HEADER Event - ); - -VOID -PerflogTraceEvent ( - __in PEVENT_TRACE_HEADER Event - ); +//------------------------------------------------------------------------------ +// File: perflog.h +// +// Desc: Performance logging framework. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +typedef struct _PERFLOG_LOGGING_PARAMS { + GUID ControlGuid; + void (*OnStateChanged)(void); + ULONG NumberOfTraceGuids; + TRACE_GUID_REGISTRATION TraceGuids[ANYSIZE_ARRAY]; +} PERFLOG_LOGGING_PARAMS, *PPERFLOG_LOGGING_PARAMS; + +BOOL +PerflogInitIfEnabled( + IN HINSTANCE hInstance, + __in PPERFLOG_LOGGING_PARAMS LogParams + ); + +BOOL +PerflogInitialize ( + __in PPERFLOG_LOGGING_PARAMS LogParams + ); + +VOID +PerflogShutdown ( + VOID + ); + +VOID +PerflogTraceEvent ( + __in PEVENT_TRACE_HEADER Event + ); + +extern ULONG PerflogEnableFlags; +extern UCHAR PerflogEnableLevel; +extern ULONG PerflogModuleLevel; +extern TRACEHANDLE PerflogTraceHandle; +extern TRACEHANDLE PerflogRegHandle; + +#define PerflogTracingEnabled() (PerflogTraceHandle != 0) + +#define PerflogEvent( _x_ ) PerflogTraceEventLevel _x_ + +VOID +PerflogTraceEventLevel( + ULONG Level, + __in PEVENT_TRACE_HEADER Event + ); + +VOID +PerflogTraceEvent ( + __in PEVENT_TRACE_HEADER Event + ); diff --git a/src/thirdparty/BaseClasses/perfstruct.h b/src/thirdparty/BaseClasses/perfstruct.h index 9c67b738d0b..b57657c820c 100644 --- a/src/thirdparty/BaseClasses/perfstruct.h +++ b/src/thirdparty/BaseClasses/perfstruct.h @@ -1,194 +1,194 @@ -//------------------------------------------------------------------------------ -// File: PerfStruct.h -// -// Desc: Structures for DirectShow performance logging. -// -// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef _PERFSTRUCT_H_ -#define _PERFSTRUCT_H_ - -#include -#include - -// {28CF047A-2437-4b24-B653-B9446A419A69} -DEFINE_GUID(GUID_DSHOW_CTL, -0x28cf047a, 0x2437, 0x4b24, 0xb6, 0x53, 0xb9, 0x44, 0x6a, 0x41, 0x9a, 0x69); - -// {D0DA7AD6-AE80-4de5-AAFC-C126711E7593} -DEFINE_GUID(GUID_VIDEOREND, -0xd0da7ad6, 0xae80, 0x4de5, 0xaa, 0xfc, 0xc1, 0x26, 0x71, 0x1e, 0x75, 0x93); - -// {DC70AC3E-93E5-48db-88AB-E42064EC276A} -DEFINE_GUID(GUID_DSOUNDGLITCH, -0xdc70ac3e, 0x93e5, 0x48db, 0x88, 0xab, 0xe4, 0x20, 0x64, 0xec, 0x27, 0x6a); - -// {3d7e7d93-2fc8-4a07-a719-e0922ff2899} -DEFINE_GUID(GUID_STREAMTRACE, -0x3d7e7d93, 0x2fc8, 0x4a07, 0xa7, 0x19, 0xe0, 0x92, 0x2f, 0xf2, 0x89, 0x9e); - -// AZFIX: the following GUIDs aren't useful right now. - -// {3C33F7F5-EE54-493c-BA25-1656539C05AC} -DEFINE_GUID(GUID_GETTIME, -0x3c33f7f5, 0xee54, 0x493c, 0xba, 0x25, 0x16, 0x56, 0x53, 0x9c, 0x5, 0xac); - -// {CC44B44D-8169-4952-9E4A-A4E13295E492} -DEFINE_GUID(GUID_AUDIOREND, -0xcc44b44d, 0x8169, 0x4952, 0x9e, 0x4a, 0xa4, 0xe1, 0x32, 0x95, 0xe4, 0x92); - -// {775D19BF-4D8B-4de6-8DC9-66BAC7B310A2} -DEFINE_GUID(GUID_FRAMEDROP, -0x775d19bf, 0x4d8b, 0x4de6, 0x8d, 0xc9, 0x66, 0xba, 0xc7, 0xb3, 0x10, 0xa2); - -// {56D29065-EFBE-42dc-8C29-E325DC9C27D5} -DEFINE_GUID(GUID_AUDIOBREAK, -0x56d29065, 0xefbe, 0x42dc, 0x8c, 0x29, 0xe3, 0x25, 0xdc, 0x9c, 0x27, 0xd5); - -// {E1E6EA87-95A8-497e-BFBA-0295AEBCC707} -DEFINE_GUID(GUID_AUDIORECV, -0xe1e6ea87, 0x95a8, 0x497e, 0xbf, 0xba, 0x2, 0x95, 0xae, 0xbc, 0xc7, 0x7); - -// {10F7768A-B1E7-4242-AD90-A2D44683D9F0} -DEFINE_GUID(GUID_AUDIOSLAVE, -0x10f7768a, 0xb1e7, 0x4242, 0xad, 0x90, 0xa2, 0xd4, 0x46, 0x83, 0xd9, 0xf0); - -// {8983803D-691A-49bc-8FF6-962A39C0198F} -DEFINE_GUID(GUID_AUDIOADDBREAK, -0x8983803d, 0x691a, 0x49bc, 0x8f, 0xf6, 0x96, 0x2a, 0x39, 0xc0, 0x19, 0x8f); - -#define GLITCHTYPE_DSOUNDFIRSTGOOD 0 -#define GLITCHTYPE_DSOUNDFIRSTBAD 1 - -typedef struct PERFINFO_DSHOW_AUDIOGLITCH { - ULONGLONG cycleCounter; - DWORD glitchType; - LONGLONG sampleTime; - LONGLONG previousTime; - ULONG_PTR instanceId; -} PERFINFO_DSHOW_AUDIOGLITCH, *PPERFINFO_DSHOW_AUDIOGLITCH; - -typedef struct PERFINFO_WMI_AUDIOGLITCH { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIOGLITCH data; -} PERFINFO_WMI_AUDIO_GLITCH, *PPERFINFO_WMI_AUDIOGLITCH; - -typedef struct PERFINFO_DSHOW_GETTIME { - ULONGLONG cycleCounter; - ULONGLONG dshowClock; -} PERFINFO_DSHOW_GETTIME, *PPERFINFO_DSHOW_GETTIME; - -typedef struct PERFINFO_WMI_GETTIME { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_GETTIME data; -} PERFINFO_WMI_GETTIME, *PPERFINFO_WMI_GETTIME; - -typedef struct PERFINFO_DSHOW_AVREND { - ULONGLONG cycleCounter; - ULONGLONG dshowClock; - ULONGLONG sampleTime; -} PERFINFO_DSHOW_AVREND, *PPERFINFO_DSHOW_AVREND; - -typedef struct PERFINFO_WMI_AVREND { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AVREND data; -} PERFINFO_WMI_AVREND, *PPERFINFO_WMI_AVREND; - -typedef struct PERFINFO_DSHOW_AUDIOBREAK { - ULONGLONG cycleCounter; - ULONGLONG dshowClock; - ULONGLONG sampleTime; - ULONGLONG sampleDuration; -} PERFINFO_DSHOW_AUDIOBREAK, *PPERFINFO_DSHOW_AUDIOBREAK; - -typedef struct PERFINFO_WMI_AUDIOBREAK { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIOBREAK data; -} PERFINFO_WMI_AUDIOBREAK, *PPERFINFO_WMI_AUDIOBREAK; - -typedef struct PERFINFO_DSHOW_FRAMEDROP { - ULONGLONG cycleCounter; - ULONGLONG dshowClock; - ULONGLONG frameTime; -} PERFINFO_DSHOW_FRAMEDROP, *PPERFINFO_DSHOW_FRAMEDROP; - -typedef struct PERFINFO_WMI_FRAMEDROP { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_FRAMEDROP data; -} PERFINFO_WMI_FRAMEDROP, *PPERFINFO_WMI_FRAMEDROP; - -#define PERFINFO_STREAMTRACE_MPEG2DEMUX_PTS_TRANSLATION 1 -#define PERFINFO_STREAMTRACE_MPEG2DEMUX_SAMPLE_RECEIVED 2 -#define PERFINFO_STREAMTRACE_VMR_BEGIN_ADVISE 3 -#define PERFINFO_STREAMTRACE_VMR_END_ADVISE 4 -#define PERFINFO_STREAMTRACE_VMR_RECEIVE 5 -#define PERFINFO_STREAMTRACE_VMR_BEGIN_DEINTERLACE 6 -#define PERFINFO_STREAMTRACE_VMR_END_DEINTERLACE 7 -#define PERFINFO_STREAMTRACE_VMR_BEGIN_DECODE 8 -#define PERFINFO_STREAMTRACE_VMR_END_DECODE 9 -#define PERFINFO_STREAMTRACE_VMR_DROPPED_FRAME 10 -#define PERFINFO_STREAMTRACE_ENCDEC_DTFILTERINPUT 11 -#define PERFINFO_STREAMTRACE_ENCDEC_DTFILTEROUTPUT 12 -#define PERFINFO_STREAMTRACE_ENCDEC_ETFILTERINPUT 13 -#define PERFINFO_STREAMTRACE_ENCDEC_ETFILTEROUTPUT 14 -#define PERFINFO_STREAMTRACE_ENCDEC_XDSCODECINPUT 15 -#define PERFINFO_STREAMTRACE_SBE_DVRANALYSISINPUT_RECEIVE 16 -#define PERFINFO_STREAMTRACE_SBE_DVRANALYSISINPUT_DELIVER 17 -#define PERFINFO_STREAMTRACE_SBE_DVRINPUTPIN_RECEIVE 18 -#define PERFINFO_STREAMTRACE_SBE_DVROUTPUTPIN_RECEIVE 19 -#define PERFINFO_STREAMTRACE_VMR_RENDER_TIME 20 - -typedef struct _PERFINFO_DSHOW_STREAMTRACE { - ULONG id; - ULONG reserved; - ULONGLONG dshowClock; - ULONGLONG data[ 4 ]; -} PERFINFO_DSHOW_STREAMTRACE, *PPERFINFO_DSHOW_STREAMTRACE; - -typedef struct _PERFINFO_WMI_STREAMTRACE { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_STREAMTRACE data; -} PERFINFO_WMI_STREAMTRACE, *PPERFINFO_WMI_STREAMTRACE; - - -typedef struct PERFINFO_DSHOW_AUDIORECV { - LONGLONG streamTime ; - LONGLONG sampleStart ; - LONGLONG sampleStop ; - LONGLONG hwduration ; - BOOL discontinuity ; -} PERFINFO_DSHOW_AUDIORECV, *PPERFINFO_DSHOW_AUDIORECV; - -typedef struct PERFINFO_WMI_AUDIORECV { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIORECV data; -} PERFINFO_WMI_AUDIORECV, *PPERFINFO_WMI_AUDIORECV; - -typedef struct PERFINFO_DSHOW_AUDIOSLAVE { - LONGLONG masterClock ; - LONGLONG slaveClock ; - LONGLONG errorAccum ; - LONGLONG lastHighErrorSeen ; - LONGLONG lastLowErrorSeen ; -} PERFINFO_DSHOW_AUDIOSLAVE, *PPERFINFO_DSHOW_AUDIOSLAVE; - -typedef struct PERFINFO_WMI_AUDIOSLAVE { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIOSLAVE data; -} PERFINFO_WMI_AUDIOSLAVE, *PPERFINFO_WMI_AUDIOSLAVE; - -typedef struct PERFINFO_DSHOW_AUDIOADDBREAK { - DWORD iterNextWrite ; - DWORD offsetNextWrite ; - DWORD iterWrite ; - DWORD offsetWrite ; -} PERFINFO_DSHOW_AUDIOADDBREAK, *PPERFINFO_DSHOW_AUDIOADDBREAK; - -typedef struct PERFINFO_WMI_AUDIOADDBREAK { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIOADDBREAK data; -} PERFINFO_WMI_AUDIOADDBREAK, *PPERFINFO_WMI_AUDIOADDBREAK; - -#endif // _PREFSTRUCT_H_ +//------------------------------------------------------------------------------ +// File: PerfStruct.h +// +// Desc: Structures for DirectShow performance logging. +// +// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef _PERFSTRUCT_H_ +#define _PERFSTRUCT_H_ + +#include +#include + +// {28CF047A-2437-4b24-B653-B9446A419A69} +DEFINE_GUID(GUID_DSHOW_CTL, +0x28cf047a, 0x2437, 0x4b24, 0xb6, 0x53, 0xb9, 0x44, 0x6a, 0x41, 0x9a, 0x69); + +// {D0DA7AD6-AE80-4de5-AAFC-C126711E7593} +DEFINE_GUID(GUID_VIDEOREND, +0xd0da7ad6, 0xae80, 0x4de5, 0xaa, 0xfc, 0xc1, 0x26, 0x71, 0x1e, 0x75, 0x93); + +// {DC70AC3E-93E5-48db-88AB-E42064EC276A} +DEFINE_GUID(GUID_DSOUNDGLITCH, +0xdc70ac3e, 0x93e5, 0x48db, 0x88, 0xab, 0xe4, 0x20, 0x64, 0xec, 0x27, 0x6a); + +// {3d7e7d93-2fc8-4a07-a719-e0922ff2899} +DEFINE_GUID(GUID_STREAMTRACE, +0x3d7e7d93, 0x2fc8, 0x4a07, 0xa7, 0x19, 0xe0, 0x92, 0x2f, 0xf2, 0x89, 0x9e); + +// AZFIX: the following GUIDs aren't useful right now. + +// {3C33F7F5-EE54-493c-BA25-1656539C05AC} +DEFINE_GUID(GUID_GETTIME, +0x3c33f7f5, 0xee54, 0x493c, 0xba, 0x25, 0x16, 0x56, 0x53, 0x9c, 0x5, 0xac); + +// {CC44B44D-8169-4952-9E4A-A4E13295E492} +DEFINE_GUID(GUID_AUDIOREND, +0xcc44b44d, 0x8169, 0x4952, 0x9e, 0x4a, 0xa4, 0xe1, 0x32, 0x95, 0xe4, 0x92); + +// {775D19BF-4D8B-4de6-8DC9-66BAC7B310A2} +DEFINE_GUID(GUID_FRAMEDROP, +0x775d19bf, 0x4d8b, 0x4de6, 0x8d, 0xc9, 0x66, 0xba, 0xc7, 0xb3, 0x10, 0xa2); + +// {56D29065-EFBE-42dc-8C29-E325DC9C27D5} +DEFINE_GUID(GUID_AUDIOBREAK, +0x56d29065, 0xefbe, 0x42dc, 0x8c, 0x29, 0xe3, 0x25, 0xdc, 0x9c, 0x27, 0xd5); + +// {E1E6EA87-95A8-497e-BFBA-0295AEBCC707} +DEFINE_GUID(GUID_AUDIORECV, +0xe1e6ea87, 0x95a8, 0x497e, 0xbf, 0xba, 0x2, 0x95, 0xae, 0xbc, 0xc7, 0x7); + +// {10F7768A-B1E7-4242-AD90-A2D44683D9F0} +DEFINE_GUID(GUID_AUDIOSLAVE, +0x10f7768a, 0xb1e7, 0x4242, 0xad, 0x90, 0xa2, 0xd4, 0x46, 0x83, 0xd9, 0xf0); + +// {8983803D-691A-49bc-8FF6-962A39C0198F} +DEFINE_GUID(GUID_AUDIOADDBREAK, +0x8983803d, 0x691a, 0x49bc, 0x8f, 0xf6, 0x96, 0x2a, 0x39, 0xc0, 0x19, 0x8f); + +#define GLITCHTYPE_DSOUNDFIRSTGOOD 0 +#define GLITCHTYPE_DSOUNDFIRSTBAD 1 + +typedef struct PERFINFO_DSHOW_AUDIOGLITCH { + ULONGLONG cycleCounter; + DWORD glitchType; + LONGLONG sampleTime; + LONGLONG previousTime; + ULONG_PTR instanceId; +} PERFINFO_DSHOW_AUDIOGLITCH, *PPERFINFO_DSHOW_AUDIOGLITCH; + +typedef struct PERFINFO_WMI_AUDIOGLITCH { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIOGLITCH data; +} PERFINFO_WMI_AUDIO_GLITCH, *PPERFINFO_WMI_AUDIOGLITCH; + +typedef struct PERFINFO_DSHOW_GETTIME { + ULONGLONG cycleCounter; + ULONGLONG dshowClock; +} PERFINFO_DSHOW_GETTIME, *PPERFINFO_DSHOW_GETTIME; + +typedef struct PERFINFO_WMI_GETTIME { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_GETTIME data; +} PERFINFO_WMI_GETTIME, *PPERFINFO_WMI_GETTIME; + +typedef struct PERFINFO_DSHOW_AVREND { + ULONGLONG cycleCounter; + ULONGLONG dshowClock; + ULONGLONG sampleTime; +} PERFINFO_DSHOW_AVREND, *PPERFINFO_DSHOW_AVREND; + +typedef struct PERFINFO_WMI_AVREND { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AVREND data; +} PERFINFO_WMI_AVREND, *PPERFINFO_WMI_AVREND; + +typedef struct PERFINFO_DSHOW_AUDIOBREAK { + ULONGLONG cycleCounter; + ULONGLONG dshowClock; + ULONGLONG sampleTime; + ULONGLONG sampleDuration; +} PERFINFO_DSHOW_AUDIOBREAK, *PPERFINFO_DSHOW_AUDIOBREAK; + +typedef struct PERFINFO_WMI_AUDIOBREAK { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIOBREAK data; +} PERFINFO_WMI_AUDIOBREAK, *PPERFINFO_WMI_AUDIOBREAK; + +typedef struct PERFINFO_DSHOW_FRAMEDROP { + ULONGLONG cycleCounter; + ULONGLONG dshowClock; + ULONGLONG frameTime; +} PERFINFO_DSHOW_FRAMEDROP, *PPERFINFO_DSHOW_FRAMEDROP; + +typedef struct PERFINFO_WMI_FRAMEDROP { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_FRAMEDROP data; +} PERFINFO_WMI_FRAMEDROP, *PPERFINFO_WMI_FRAMEDROP; + +#define PERFINFO_STREAMTRACE_MPEG2DEMUX_PTS_TRANSLATION 1 +#define PERFINFO_STREAMTRACE_MPEG2DEMUX_SAMPLE_RECEIVED 2 +#define PERFINFO_STREAMTRACE_VMR_BEGIN_ADVISE 3 +#define PERFINFO_STREAMTRACE_VMR_END_ADVISE 4 +#define PERFINFO_STREAMTRACE_VMR_RECEIVE 5 +#define PERFINFO_STREAMTRACE_VMR_BEGIN_DEINTERLACE 6 +#define PERFINFO_STREAMTRACE_VMR_END_DEINTERLACE 7 +#define PERFINFO_STREAMTRACE_VMR_BEGIN_DECODE 8 +#define PERFINFO_STREAMTRACE_VMR_END_DECODE 9 +#define PERFINFO_STREAMTRACE_VMR_DROPPED_FRAME 10 +#define PERFINFO_STREAMTRACE_ENCDEC_DTFILTERINPUT 11 +#define PERFINFO_STREAMTRACE_ENCDEC_DTFILTEROUTPUT 12 +#define PERFINFO_STREAMTRACE_ENCDEC_ETFILTERINPUT 13 +#define PERFINFO_STREAMTRACE_ENCDEC_ETFILTEROUTPUT 14 +#define PERFINFO_STREAMTRACE_ENCDEC_XDSCODECINPUT 15 +#define PERFINFO_STREAMTRACE_SBE_DVRANALYSISINPUT_RECEIVE 16 +#define PERFINFO_STREAMTRACE_SBE_DVRANALYSISINPUT_DELIVER 17 +#define PERFINFO_STREAMTRACE_SBE_DVRINPUTPIN_RECEIVE 18 +#define PERFINFO_STREAMTRACE_SBE_DVROUTPUTPIN_RECEIVE 19 +#define PERFINFO_STREAMTRACE_VMR_RENDER_TIME 20 + +typedef struct _PERFINFO_DSHOW_STREAMTRACE { + ULONG id; + ULONG reserved; + ULONGLONG dshowClock; + ULONGLONG data[ 4 ]; +} PERFINFO_DSHOW_STREAMTRACE, *PPERFINFO_DSHOW_STREAMTRACE; + +typedef struct _PERFINFO_WMI_STREAMTRACE { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_STREAMTRACE data; +} PERFINFO_WMI_STREAMTRACE, *PPERFINFO_WMI_STREAMTRACE; + + +typedef struct PERFINFO_DSHOW_AUDIORECV { + LONGLONG streamTime ; + LONGLONG sampleStart ; + LONGLONG sampleStop ; + LONGLONG hwduration ; + BOOL discontinuity ; +} PERFINFO_DSHOW_AUDIORECV, *PPERFINFO_DSHOW_AUDIORECV; + +typedef struct PERFINFO_WMI_AUDIORECV { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIORECV data; +} PERFINFO_WMI_AUDIORECV, *PPERFINFO_WMI_AUDIORECV; + +typedef struct PERFINFO_DSHOW_AUDIOSLAVE { + LONGLONG masterClock ; + LONGLONG slaveClock ; + LONGLONG errorAccum ; + LONGLONG lastHighErrorSeen ; + LONGLONG lastLowErrorSeen ; +} PERFINFO_DSHOW_AUDIOSLAVE, *PPERFINFO_DSHOW_AUDIOSLAVE; + +typedef struct PERFINFO_WMI_AUDIOSLAVE { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIOSLAVE data; +} PERFINFO_WMI_AUDIOSLAVE, *PPERFINFO_WMI_AUDIOSLAVE; + +typedef struct PERFINFO_DSHOW_AUDIOADDBREAK { + DWORD iterNextWrite ; + DWORD offsetNextWrite ; + DWORD iterWrite ; + DWORD offsetWrite ; +} PERFINFO_DSHOW_AUDIOADDBREAK, *PPERFINFO_DSHOW_AUDIOADDBREAK; + +typedef struct PERFINFO_WMI_AUDIOADDBREAK { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIOADDBREAK data; +} PERFINFO_WMI_AUDIOADDBREAK, *PPERFINFO_WMI_AUDIOADDBREAK; + +#endif // _PREFSTRUCT_H_ diff --git a/src/thirdparty/BaseClasses/pstream.cpp b/src/thirdparty/BaseClasses/pstream.cpp index 01ab0b00b27..6d47269521c 100644 --- a/src/thirdparty/BaseClasses/pstream.cpp +++ b/src/thirdparty/BaseClasses/pstream.cpp @@ -1,197 +1,197 @@ -//------------------------------------------------------------------------------ -// File: PStream.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -#ifdef PERF -#include -#endif -// #include "pstream.h" in streams.h - -// -// Constructor -// -CPersistStream::CPersistStream(IUnknown *punk, __inout HRESULT *phr) - : mPS_fDirty(FALSE) -{ - mPS_dwFileVersion = GetSoftwareVersion(); -} - - -// -// Destructor -// -CPersistStream::~CPersistStream() { - // Nothing to do -} - -#if 0 -SAMPLE CODE TO COPY - not active at the moment - -// -// NonDelegatingQueryInterface -// -// This object supports IPersist & IPersistStream -STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); // ??? - } - else if (riid == IID_IPersistStream) { - return GetInterface((IPersistStream *) this, ppv); - } - else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} -#endif - - -// -// WriteToStream -// -// Writes to the stream (default action is to write nothing) -HRESULT CPersistStream::WriteToStream(IStream *pStream) -{ - // You can override this to do things like - // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL); - - return NOERROR; -} - - - -HRESULT CPersistStream::ReadFromStream(IStream * pStream) -{ - // You can override this to do things like - // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL); - - return NOERROR; -} - - -// -// Load -// -// Load all the data from the given stream -STDMETHODIMP CPersistStream::Load(LPSTREAM pStm) -{ - HRESULT hr; - // Load the version number then the data - mPS_dwFileVersion = ReadInt(pStm, hr); - if (FAILED(hr)) { - return hr; - } - - return ReadFromStream(pStm); -} // Load - - - -// -// Save -// -// Save the contents of this Stream. -STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty) -{ - - HRESULT hr = WriteInt(pStm, GetSoftwareVersion()); - if (FAILED(hr)) { - return hr; - } - - hr = WriteToStream(pStm); - if (FAILED(hr)) { - return hr; - } - - mPS_fDirty = !fClearDirty; - - return hr; -} // Save - - -// WriteInt -// -// Writes an integer to an IStream as 11 UNICODE characters followed by one space. -// You could use this for shorts or unsigneds or anything (up to 32 bits) -// where the value isn't actually truncated by squeezing it into 32 bits. -// Values such as (unsigned) 0x80000000 would come out as -2147483648 -// but would then load as 0x80000000 through ReadInt. Cast as you please. - -STDAPI WriteInt(IStream *pIStream, int n) -{ - WCHAR Buff[13]; // Allows for trailing null that we don't write - (void)StringCchPrintfW(Buff, NUMELMS(Buff),L"%011d ",n); - return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL); -} // WriteInt - - -// ReadInt -// -// Reads an integer from an IStream. -// Read as 4 bytes. You could use this for shorts or unsigneds or anything -// where the value isn't actually truncated by squeezing it into 32 bits -// Striped down subset of what sscanf can do (without dragging in the C runtime) - -STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr) -{ - - int Sign = 1; - unsigned int n = 0; // result wil be n*Sign - WCHAR wch; - - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - - if (wch==L'-'){ - Sign = -1; - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - } - - for( ; ; ) { - if (wch>=L'0' && wch<=L'9') { - n = 10*n+(int)(wch-L'0'); - } else if ( wch == L' ' - || wch == L'\t' - || wch == L'\r' - || wch == L'\n' - || wch == L'\0' - ) { - break; - } else { - hr = VFW_E_INVALID_FILE_FORMAT; - return 0; - } - - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - } - - if (n==0x80000000 && Sign==-1) { - // This is the negative number that has no positive version! - return (int)n; - } - else return (int)n * Sign; -} // ReadInt - - -// The microsoft C/C++ compile generates level 4 warnings to the effect that -// a particular inline function (from some base class) was not needed. -// This line gets rid of hundreds of such unwanted messages and makes -// -W4 compilation feasible: -#pragma warning(disable: 4514) +//------------------------------------------------------------------------------ +// File: PStream.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +#ifdef PERF +#include +#endif +// #include "pstream.h" in streams.h + +// +// Constructor +// +CPersistStream::CPersistStream(IUnknown *punk, __inout HRESULT *phr) + : mPS_fDirty(FALSE) +{ + mPS_dwFileVersion = GetSoftwareVersion(); +} + + +// +// Destructor +// +CPersistStream::~CPersistStream() { + // Nothing to do +} + +#if 0 +SAMPLE CODE TO COPY - not active at the moment + +// +// NonDelegatingQueryInterface +// +// This object supports IPersist & IPersistStream +STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); // ??? + } + else if (riid == IID_IPersistStream) { + return GetInterface((IPersistStream *) this, ppv); + } + else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} +#endif + + +// +// WriteToStream +// +// Writes to the stream (default action is to write nothing) +HRESULT CPersistStream::WriteToStream(IStream *pStream) +{ + // You can override this to do things like + // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL); + + return NOERROR; +} + + + +HRESULT CPersistStream::ReadFromStream(IStream * pStream) +{ + // You can override this to do things like + // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL); + + return NOERROR; +} + + +// +// Load +// +// Load all the data from the given stream +STDMETHODIMP CPersistStream::Load(LPSTREAM pStm) +{ + HRESULT hr; + // Load the version number then the data + mPS_dwFileVersion = ReadInt(pStm, hr); + if (FAILED(hr)) { + return hr; + } + + return ReadFromStream(pStm); +} // Load + + + +// +// Save +// +// Save the contents of this Stream. +STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty) +{ + + HRESULT hr = WriteInt(pStm, GetSoftwareVersion()); + if (FAILED(hr)) { + return hr; + } + + hr = WriteToStream(pStm); + if (FAILED(hr)) { + return hr; + } + + mPS_fDirty = !fClearDirty; + + return hr; +} // Save + + +// WriteInt +// +// Writes an integer to an IStream as 11 UNICODE characters followed by one space. +// You could use this for shorts or unsigneds or anything (up to 32 bits) +// where the value isn't actually truncated by squeezing it into 32 bits. +// Values such as (unsigned) 0x80000000 would come out as -2147483648 +// but would then load as 0x80000000 through ReadInt. Cast as you please. + +STDAPI WriteInt(IStream *pIStream, int n) +{ + WCHAR Buff[13]; // Allows for trailing null that we don't write + (void)StringCchPrintfW(Buff, NUMELMS(Buff),L"%011d ",n); + return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL); +} // WriteInt + + +// ReadInt +// +// Reads an integer from an IStream. +// Read as 4 bytes. You could use this for shorts or unsigneds or anything +// where the value isn't actually truncated by squeezing it into 32 bits +// Striped down subset of what sscanf can do (without dragging in the C runtime) + +STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr) +{ + + int Sign = 1; + unsigned int n = 0; // result wil be n*Sign + WCHAR wch; + + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + + if (wch==L'-'){ + Sign = -1; + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + } + + for( ; ; ) { + if (wch>=L'0' && wch<=L'9') { + n = 10*n+(int)(wch-L'0'); + } else if ( wch == L' ' + || wch == L'\t' + || wch == L'\r' + || wch == L'\n' + || wch == L'\0' + ) { + break; + } else { + hr = VFW_E_INVALID_FILE_FORMAT; + return 0; + } + + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + } + + if (n==0x80000000 && Sign==-1) { + // This is the negative number that has no positive version! + return (int)n; + } + else return (int)n * Sign; +} // ReadInt + + +// The microsoft C/C++ compile generates level 4 warnings to the effect that +// a particular inline function (from some base class) was not needed. +// This line gets rid of hundreds of such unwanted messages and makes +// -W4 compilation feasible: +#pragma warning(disable: 4514) diff --git a/src/thirdparty/BaseClasses/pstream.h b/src/thirdparty/BaseClasses/pstream.h index 04b6af62434..2e278abf0c3 100644 --- a/src/thirdparty/BaseClasses/pstream.h +++ b/src/thirdparty/BaseClasses/pstream.h @@ -1,114 +1,114 @@ -//------------------------------------------------------------------------------ -// File: PStream.h -// -// Desc: DirectShow base classes - defines a class for persistent properties -// of filters. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __PSTREAM__ -#define __PSTREAM__ - -// Base class for persistent properties of filters -// (i.e. filter properties in saved graphs) - -// The simplest way to use this is: -// 1. Arrange for your filter to inherit this class -// 2. Implement in your class WriteToStream and ReadFromStream -// These will override the "do nothing" functions here. -// 3. Change your NonDelegatingQueryInterface to handle IPersistStream -// 4. Implement SizeMax to return the number of bytes of data you save. -// If you save UNICODE data, don't forget a char is 2 bytes. -// 5. Whenever your data changes, call SetDirty() -// -// At some point you may decide to alter, or extend the format of your data. -// At that point you will wish that you had a version number in all the old -// saved graphs, so that you can tell, when you read them, whether they -// represent the old or new form. To assist you in this, this class -// writes and reads a version number. -// When it writes, it calls GetSoftwareVersion() to enquire what version -// of the software we have at the moment. (In effect this is a version number -// of the data layout in the file). It writes this as the first thing in the data. -// If you want to change the version, implement (override) GetSoftwareVersion(). -// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream, -// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading -// an old version file. -// Normally you should accept files whose version is no newer than the software -// version that's reading them. - - -// CPersistStream -// -// Implements IPersistStream. -// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for -// more implementation information. -class CPersistStream : public IPersistStream { - private: - - // Internal state: - - protected: - DWORD mPS_dwFileVersion; // version number of file (being read) - BOOL mPS_fDirty; - - public: - - // IPersistStream methods - - STDMETHODIMP IsDirty() - {return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean - STDMETHODIMP Load(LPSTREAM pStm); - STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty); - STDMETHODIMP GetSizeMax(__out ULARGE_INTEGER * pcbSize) - // Allow 24 bytes for version. - { pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; } - - // implementation - - CPersistStream(IUnknown *punk, __inout HRESULT *phr); - ~CPersistStream(); - - HRESULT SetDirty(BOOL fDirty) - { mPS_fDirty = fDirty; return NOERROR;} - - - // override to reveal IPersist & IPersistStream - // STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - // --- IPersist --- - - // You must override this to provide your own class id - STDMETHODIMP GetClassID(__out CLSID *pClsid) PURE; - - // overrideable if you want - // file version number. Override it if you ever change format - virtual DWORD GetSoftwareVersion(void) { return 0; } - - - //========================================================================= - // OVERRIDE THESE to read and write your data - // OVERRIDE THESE to read and write your data - // OVERRIDE THESE to read and write your data - - virtual int SizeMax() {return 0;} - virtual HRESULT WriteToStream(IStream *pStream); - virtual HRESULT ReadFromStream(IStream *pStream); - //========================================================================= - - private: - -}; - - -// --- Useful helpers --- - - -// Writes an int to an IStream as UNICODE. -STDAPI WriteInt(IStream *pIStream, int n); - -// inverse of WriteInt -STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr); - -#endif // __PSTREAM__ +//------------------------------------------------------------------------------ +// File: PStream.h +// +// Desc: DirectShow base classes - defines a class for persistent properties +// of filters. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __PSTREAM__ +#define __PSTREAM__ + +// Base class for persistent properties of filters +// (i.e. filter properties in saved graphs) + +// The simplest way to use this is: +// 1. Arrange for your filter to inherit this class +// 2. Implement in your class WriteToStream and ReadFromStream +// These will override the "do nothing" functions here. +// 3. Change your NonDelegatingQueryInterface to handle IPersistStream +// 4. Implement SizeMax to return the number of bytes of data you save. +// If you save UNICODE data, don't forget a char is 2 bytes. +// 5. Whenever your data changes, call SetDirty() +// +// At some point you may decide to alter, or extend the format of your data. +// At that point you will wish that you had a version number in all the old +// saved graphs, so that you can tell, when you read them, whether they +// represent the old or new form. To assist you in this, this class +// writes and reads a version number. +// When it writes, it calls GetSoftwareVersion() to enquire what version +// of the software we have at the moment. (In effect this is a version number +// of the data layout in the file). It writes this as the first thing in the data. +// If you want to change the version, implement (override) GetSoftwareVersion(). +// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream, +// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading +// an old version file. +// Normally you should accept files whose version is no newer than the software +// version that's reading them. + + +// CPersistStream +// +// Implements IPersistStream. +// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for +// more implementation information. +class CPersistStream : public IPersistStream { + private: + + // Internal state: + + protected: + DWORD mPS_dwFileVersion; // version number of file (being read) + BOOL mPS_fDirty; + + public: + + // IPersistStream methods + + STDMETHODIMP IsDirty() + {return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean + STDMETHODIMP Load(LPSTREAM pStm); + STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty); + STDMETHODIMP GetSizeMax(__out ULARGE_INTEGER * pcbSize) + // Allow 24 bytes for version. + { pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; } + + // implementation + + CPersistStream(IUnknown *punk, __inout HRESULT *phr); + ~CPersistStream(); + + HRESULT SetDirty(BOOL fDirty) + { mPS_fDirty = fDirty; return NOERROR;} + + + // override to reveal IPersist & IPersistStream + // STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // --- IPersist --- + + // You must override this to provide your own class id + STDMETHODIMP GetClassID(__out CLSID *pClsid) PURE; + + // overrideable if you want + // file version number. Override it if you ever change format + virtual DWORD GetSoftwareVersion(void) { return 0; } + + + //========================================================================= + // OVERRIDE THESE to read and write your data + // OVERRIDE THESE to read and write your data + // OVERRIDE THESE to read and write your data + + virtual int SizeMax() {return 0;} + virtual HRESULT WriteToStream(IStream *pStream); + virtual HRESULT ReadFromStream(IStream *pStream); + //========================================================================= + + private: + +}; + + +// --- Useful helpers --- + + +// Writes an int to an IStream as UNICODE. +STDAPI WriteInt(IStream *pIStream, int n); + +// inverse of WriteInt +STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr); + +#endif // __PSTREAM__ diff --git a/src/thirdparty/BaseClasses/pullpin.cpp b/src/thirdparty/BaseClasses/pullpin.cpp index c979270c97b..9bcbf6a50f8 100644 --- a/src/thirdparty/BaseClasses/pullpin.cpp +++ b/src/thirdparty/BaseClasses/pullpin.cpp @@ -1,593 +1,593 @@ -//------------------------------------------------------------------------------ -// File: PullPin.cpp -// -// Desc: DirectShow base classes - implements CPullPin class that pulls data -// from IAsyncReader. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "pullpin.h" - -#ifdef DXMPERF -#include "dxmperf.h" -#endif // DXMPERF - - -CPullPin::CPullPin() - : m_pReader(NULL), - m_pAlloc(NULL), - m_State(TM_Exit), - m_tStart(0), - m_tStop(0), - m_tDuration(0), - m_bSync(FALSE) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CPullPin", this ); -#endif // DXMPERF - -} - -CPullPin::~CPullPin() -{ - Disconnect(); - -#ifdef DXMPERF - PERFLOG_DTOR( L"CPullPin", this ); -#endif // DXMPERF - -} - -// returns S_OK if successfully connected to an IAsyncReader interface -// from this object -// Optional allocator should be proposed as a preferred allocator if -// necessary -HRESULT -CPullPin::Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync) -{ - CAutoLock lock(&m_AccessLock); - - if (m_pReader) { - return VFW_E_ALREADY_CONNECTED; - } - - HRESULT hr = pUnk->QueryInterface(IID_IAsyncReader, (void**)&m_pReader); - if (FAILED(hr)) { - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - PERFLOG_CONNECT( this, pUnk, hr, pmt ); - } -#endif // DXMPERF - - return(hr); - } - - hr = DecideAllocator(pAlloc, NULL); - if (FAILED(hr)) { - Disconnect(); - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - PERFLOG_CONNECT( this, pUnk, hr, pmt ); - } -#endif // DXMPERF - - return hr; - } - - LONGLONG llTotal, llAvail; - hr = m_pReader->Length(&llTotal, &llAvail); - if (FAILED(hr)) { - Disconnect(); - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - PERFLOG_CONNECT( this, pUnk, hr, pmt ); - } -#endif - - return hr; - } - - // convert from file position to reference time - m_tDuration = llTotal * UNITS; - m_tStop = m_tDuration; - m_tStart = 0; - - m_bSync = bSync; - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - PERFLOG_CONNECT( this, pUnk, S_OK, pmt ); - } -#endif // DXMPERF - - - return S_OK; -} - -// disconnect any connection made in Connect -HRESULT -CPullPin::Disconnect() -{ - CAutoLock lock(&m_AccessLock); - - StopThread(); - - -#ifdef DXMPERF - PERFLOG_DISCONNECT( this, m_pReader, S_OK ); -#endif // DXMPERF - - - if (m_pReader) { - m_pReader->Release(); - m_pReader = NULL; - } - - if (m_pAlloc) { - m_pAlloc->Release(); - m_pAlloc = NULL; - } - - return S_OK; -} - -// agree an allocator using RequestAllocator - optional -// props param specifies your requirements (non-zero fields). -// returns an error code if fail to match requirements. -// optional IMemAllocator interface is offered as a preferred allocator -// but no error occurs if it can't be met. -HRESULT -CPullPin::DecideAllocator( - IMemAllocator * pAlloc, - __inout_opt ALLOCATOR_PROPERTIES * pProps) -{ - ALLOCATOR_PROPERTIES *pRequest; - ALLOCATOR_PROPERTIES Request; - if (pProps == NULL) { - Request.cBuffers = 3; - Request.cbBuffer = 64*1024; - Request.cbAlign = 0; - Request.cbPrefix = 0; - pRequest = &Request; - } else { - pRequest = pProps; - } - HRESULT hr = m_pReader->RequestAllocator( - pAlloc, - pRequest, - &m_pAlloc); - return hr; -} - -// start pulling data -HRESULT -CPullPin::Active(void) -{ - ASSERT(!ThreadExists()); - return StartThread(); -} - -// stop pulling data -HRESULT -CPullPin::Inactive(void) -{ - StopThread(); - - return S_OK; -} - -HRESULT -CPullPin::Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop) -{ - CAutoLock lock(&m_AccessLock); - - ThreadMsg AtStart = m_State; - - if (AtStart == TM_Start) { - BeginFlush(); - PauseThread(); - EndFlush(); - } - - m_tStart = tStart; - m_tStop = tStop; - - HRESULT hr = S_OK; - if (AtStart == TM_Start) { - hr = StartThread(); - } - - return hr; -} - -HRESULT -CPullPin::Duration(__out REFERENCE_TIME* ptDuration) -{ - *ptDuration = m_tDuration; - return S_OK; -} - - -HRESULT -CPullPin::StartThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!m_pAlloc || !m_pReader) { - return E_UNEXPECTED; - } - - HRESULT hr; - if (!ThreadExists()) { - - // commit allocator - hr = m_pAlloc->Commit(); - if (FAILED(hr)) { - return hr; - } - - // start thread - if (!Create()) { - return E_FAIL; - } - } - - m_State = TM_Start; - hr = (HRESULT) CallWorker(m_State); - return hr; -} - -HRESULT -CPullPin::PauseThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return E_UNEXPECTED; - } - - // need to flush to ensure the thread is not blocked - // in WaitForNext - HRESULT hr = m_pReader->BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - m_State = TM_Pause; - hr = CallWorker(TM_Pause); - - m_pReader->EndFlush(); - return hr; -} - -HRESULT -CPullPin::StopThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return S_FALSE; - } - - // need to flush to ensure the thread is not blocked - // in WaitForNext - HRESULT hr = m_pReader->BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - m_State = TM_Exit; - hr = CallWorker(TM_Exit); - - m_pReader->EndFlush(); - - // wait for thread to completely exit - Close(); - - // decommit allocator - if (m_pAlloc) { - m_pAlloc->Decommit(); - } - - return S_OK; -} - - -DWORD -CPullPin::ThreadProc(void) -{ - for (;;) { - DWORD cmd = GetRequest(); - switch(cmd) { - case TM_Exit: - Reply(S_OK); - return 0; - - case TM_Pause: - // we are paused already - Reply(S_OK); - break; - - case TM_Start: - Reply(S_OK); - Process(); - break; - } - - // at this point, there should be no outstanding requests on the - // upstream filter. - // We should force begin/endflush to ensure that this is true. - // !!!Note that we may currently be inside a BeginFlush/EndFlush pair - // on another thread, but the premature EndFlush will do no harm now - // that we are idle. - m_pReader->BeginFlush(); - CleanupCancelled(); - m_pReader->EndFlush(); - } -} - -HRESULT -CPullPin::QueueSample( - __inout REFERENCE_TIME& tCurrent, - REFERENCE_TIME tAlignStop, - BOOL bDiscontinuity - ) -{ - IMediaSample* pSample; - - HRESULT hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); - if (FAILED(hr)) { - return hr; - } - - LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); - if (tStopThis > tAlignStop) { - tStopThis = tAlignStop; - } - pSample->SetTime(&tCurrent, &tStopThis); - tCurrent = tStopThis; - - pSample->SetDiscontinuity(bDiscontinuity); - - hr = m_pReader->Request( - pSample, - 0); - if (FAILED(hr)) { - pSample->Release(); - - CleanupCancelled(); - OnError(hr); - } - return hr; -} - -HRESULT -CPullPin::CollectAndDeliver( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop) -{ - IMediaSample* pSample = NULL; // better be sure pSample is set - DWORD_PTR dwUnused; - HRESULT hr = m_pReader->WaitForNext( - INFINITE, - &pSample, - &dwUnused); - if (FAILED(hr)) { - if (pSample) { - pSample->Release(); - } - } else { - hr = DeliverSample(pSample, tStart, tStop); - } - if (FAILED(hr)) { - CleanupCancelled(); - OnError(hr); - } - return hr; - -} - -HRESULT -CPullPin::DeliverSample( - IMediaSample* pSample, - REFERENCE_TIME tStart, - REFERENCE_TIME tStop - ) -{ - // fix up sample if past actual stop (for sector alignment) - REFERENCE_TIME t1, t2; - if (S_OK == pSample->GetTime(&t1, &t2)) { - if (t2 > tStop) { - t2 = tStop; - } - - // adjust times to be relative to (aligned) start time - t1 -= tStart; - t2 -= tStart; - HRESULT hr = pSample->SetTime(&t1, &t2); - if (FAILED(hr)) { - return hr; - } - } - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - pSample->GetMediaType( &pmt ); - PERFLOG_RECEIVE( L"CPullPin", m_pReader, this, pSample, pmt ); - } -#endif - - HRESULT hr = Receive(pSample); - pSample->Release(); - return hr; -} - -void -CPullPin::Process(void) -{ - // is there anything to do? - if (m_tStop <= m_tStart) { - EndOfStream(); - return; - } - - BOOL bDiscontinuity = TRUE; - - // if there is more than one sample at the allocator, - // then try to queue 2 at once in order to overlap. - // -- get buffer count and required alignment - ALLOCATOR_PROPERTIES Actual; - HRESULT hr = m_pAlloc->GetProperties(&Actual); - - // align the start position downwards - REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS; - REFERENCE_TIME tCurrent = tStart; - - REFERENCE_TIME tStop = m_tStop; - if (tStop > m_tDuration) { - tStop = m_tDuration; - } - - // align the stop position - may be past stop, but that - // doesn't matter - REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS; - - - DWORD dwRequest; - - if (!m_bSync) { - - // Break out of the loop either if we get to the end or we're asked - // to do something else - while (tCurrent < tAlignStop) { - - // Break out without calling EndOfStream if we're asked to - // do something different - if (CheckRequest(&dwRequest)) { - return; - } - - // queue a first sample - if (Actual.cBuffers > 1) { - - hr = QueueSample(tCurrent, tAlignStop, TRUE); - bDiscontinuity = FALSE; - - if (FAILED(hr)) { - return; - } - } - - - - // loop queueing second and waiting for first.. - while (tCurrent < tAlignStop) { - - hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity); - bDiscontinuity = FALSE; - - if (FAILED(hr)) { - return; - } - - hr = CollectAndDeliver(tStart, tStop); - if (S_OK != hr) { - - // stop if error, or if downstream filter said - // to stop. - return; - } - } - - if (Actual.cBuffers > 1) { - hr = CollectAndDeliver(tStart, tStop); - if (FAILED(hr)) { - return; - } - } - } - } else { - - // sync version of above loop - while (tCurrent < tAlignStop) { - - // Break out without calling EndOfStream if we're asked to - // do something different - if (CheckRequest(&dwRequest)) { - return; - } - - IMediaSample* pSample; - - hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); - if (FAILED(hr)) { - OnError(hr); - return; - } - - LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); - if (tStopThis > tAlignStop) { - tStopThis = tAlignStop; - } - pSample->SetTime(&tCurrent, &tStopThis); - tCurrent = tStopThis; - - if (bDiscontinuity) { - pSample->SetDiscontinuity(TRUE); - bDiscontinuity = FALSE; - } - - hr = m_pReader->SyncReadAligned(pSample); - - if (FAILED(hr)) { - pSample->Release(); - OnError(hr); - return; - } - - hr = DeliverSample(pSample, tStart, tStop); - if (hr != S_OK) { - if (FAILED(hr)) { - OnError(hr); - } - return; - } - } - } - - EndOfStream(); -} - -// after a flush, cancelled i/o will be waiting for collection -// and release -void -CPullPin::CleanupCancelled(void) -{ - for (;;) { - IMediaSample * pSample; - DWORD_PTR dwUnused; - - HRESULT hr = m_pReader->WaitForNext( - 0, // no wait - &pSample, - &dwUnused); - UNREFERENCED_PARAMETER(hr); - if(pSample) { - pSample->Release(); - } else { - // no more samples - return; - } - } -} +//------------------------------------------------------------------------------ +// File: PullPin.cpp +// +// Desc: DirectShow base classes - implements CPullPin class that pulls data +// from IAsyncReader. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "pullpin.h" + +#ifdef DXMPERF +#include "dxmperf.h" +#endif // DXMPERF + + +CPullPin::CPullPin() + : m_pReader(NULL), + m_pAlloc(NULL), + m_State(TM_Exit), + m_tStart(0), + m_tStop(0), + m_tDuration(0), + m_bSync(FALSE) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CPullPin", this ); +#endif // DXMPERF + +} + +CPullPin::~CPullPin() +{ + Disconnect(); + +#ifdef DXMPERF + PERFLOG_DTOR( L"CPullPin", this ); +#endif // DXMPERF + +} + +// returns S_OK if successfully connected to an IAsyncReader interface +// from this object +// Optional allocator should be proposed as a preferred allocator if +// necessary +HRESULT +CPullPin::Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync) +{ + CAutoLock lock(&m_AccessLock); + + if (m_pReader) { + return VFW_E_ALREADY_CONNECTED; + } + + HRESULT hr = pUnk->QueryInterface(IID_IAsyncReader, (void**)&m_pReader); + if (FAILED(hr)) { + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + PERFLOG_CONNECT( this, pUnk, hr, pmt ); + } +#endif // DXMPERF + + return(hr); + } + + hr = DecideAllocator(pAlloc, NULL); + if (FAILED(hr)) { + Disconnect(); + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + PERFLOG_CONNECT( this, pUnk, hr, pmt ); + } +#endif // DXMPERF + + return hr; + } + + LONGLONG llTotal, llAvail; + hr = m_pReader->Length(&llTotal, &llAvail); + if (FAILED(hr)) { + Disconnect(); + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + PERFLOG_CONNECT( this, pUnk, hr, pmt ); + } +#endif + + return hr; + } + + // convert from file position to reference time + m_tDuration = llTotal * UNITS; + m_tStop = m_tDuration; + m_tStart = 0; + + m_bSync = bSync; + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + PERFLOG_CONNECT( this, pUnk, S_OK, pmt ); + } +#endif // DXMPERF + + + return S_OK; +} + +// disconnect any connection made in Connect +HRESULT +CPullPin::Disconnect() +{ + CAutoLock lock(&m_AccessLock); + + StopThread(); + + +#ifdef DXMPERF + PERFLOG_DISCONNECT( this, m_pReader, S_OK ); +#endif // DXMPERF + + + if (m_pReader) { + m_pReader->Release(); + m_pReader = NULL; + } + + if (m_pAlloc) { + m_pAlloc->Release(); + m_pAlloc = NULL; + } + + return S_OK; +} + +// agree an allocator using RequestAllocator - optional +// props param specifies your requirements (non-zero fields). +// returns an error code if fail to match requirements. +// optional IMemAllocator interface is offered as a preferred allocator +// but no error occurs if it can't be met. +HRESULT +CPullPin::DecideAllocator( + IMemAllocator * pAlloc, + __inout_opt ALLOCATOR_PROPERTIES * pProps) +{ + ALLOCATOR_PROPERTIES *pRequest; + ALLOCATOR_PROPERTIES Request; + if (pProps == NULL) { + Request.cBuffers = 3; + Request.cbBuffer = 64*1024; + Request.cbAlign = 0; + Request.cbPrefix = 0; + pRequest = &Request; + } else { + pRequest = pProps; + } + HRESULT hr = m_pReader->RequestAllocator( + pAlloc, + pRequest, + &m_pAlloc); + return hr; +} + +// start pulling data +HRESULT +CPullPin::Active(void) +{ + ASSERT(!ThreadExists()); + return StartThread(); +} + +// stop pulling data +HRESULT +CPullPin::Inactive(void) +{ + StopThread(); + + return S_OK; +} + +HRESULT +CPullPin::Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop) +{ + CAutoLock lock(&m_AccessLock); + + ThreadMsg AtStart = m_State; + + if (AtStart == TM_Start) { + BeginFlush(); + PauseThread(); + EndFlush(); + } + + m_tStart = tStart; + m_tStop = tStop; + + HRESULT hr = S_OK; + if (AtStart == TM_Start) { + hr = StartThread(); + } + + return hr; +} + +HRESULT +CPullPin::Duration(__out REFERENCE_TIME* ptDuration) +{ + *ptDuration = m_tDuration; + return S_OK; +} + + +HRESULT +CPullPin::StartThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!m_pAlloc || !m_pReader) { + return E_UNEXPECTED; + } + + HRESULT hr; + if (!ThreadExists()) { + + // commit allocator + hr = m_pAlloc->Commit(); + if (FAILED(hr)) { + return hr; + } + + // start thread + if (!Create()) { + return E_FAIL; + } + } + + m_State = TM_Start; + hr = (HRESULT) CallWorker(m_State); + return hr; +} + +HRESULT +CPullPin::PauseThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return E_UNEXPECTED; + } + + // need to flush to ensure the thread is not blocked + // in WaitForNext + HRESULT hr = m_pReader->BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + m_State = TM_Pause; + hr = CallWorker(TM_Pause); + + m_pReader->EndFlush(); + return hr; +} + +HRESULT +CPullPin::StopThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return S_FALSE; + } + + // need to flush to ensure the thread is not blocked + // in WaitForNext + HRESULT hr = m_pReader->BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + m_State = TM_Exit; + hr = CallWorker(TM_Exit); + + m_pReader->EndFlush(); + + // wait for thread to completely exit + Close(); + + // decommit allocator + if (m_pAlloc) { + m_pAlloc->Decommit(); + } + + return S_OK; +} + + +DWORD +CPullPin::ThreadProc(void) +{ + for (;;) { + DWORD cmd = GetRequest(); + switch(cmd) { + case TM_Exit: + Reply(S_OK); + return 0; + + case TM_Pause: + // we are paused already + Reply(S_OK); + break; + + case TM_Start: + Reply(S_OK); + Process(); + break; + } + + // at this point, there should be no outstanding requests on the + // upstream filter. + // We should force begin/endflush to ensure that this is true. + // !!!Note that we may currently be inside a BeginFlush/EndFlush pair + // on another thread, but the premature EndFlush will do no harm now + // that we are idle. + m_pReader->BeginFlush(); + CleanupCancelled(); + m_pReader->EndFlush(); + } +} + +HRESULT +CPullPin::QueueSample( + __inout REFERENCE_TIME& tCurrent, + REFERENCE_TIME tAlignStop, + BOOL bDiscontinuity + ) +{ + IMediaSample* pSample; + + HRESULT hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); + if (FAILED(hr)) { + return hr; + } + + LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); + if (tStopThis > tAlignStop) { + tStopThis = tAlignStop; + } + pSample->SetTime(&tCurrent, &tStopThis); + tCurrent = tStopThis; + + pSample->SetDiscontinuity(bDiscontinuity); + + hr = m_pReader->Request( + pSample, + 0); + if (FAILED(hr)) { + pSample->Release(); + + CleanupCancelled(); + OnError(hr); + } + return hr; +} + +HRESULT +CPullPin::CollectAndDeliver( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop) +{ + IMediaSample* pSample = NULL; // better be sure pSample is set + DWORD_PTR dwUnused; + HRESULT hr = m_pReader->WaitForNext( + INFINITE, + &pSample, + &dwUnused); + if (FAILED(hr)) { + if (pSample) { + pSample->Release(); + } + } else { + hr = DeliverSample(pSample, tStart, tStop); + } + if (FAILED(hr)) { + CleanupCancelled(); + OnError(hr); + } + return hr; + +} + +HRESULT +CPullPin::DeliverSample( + IMediaSample* pSample, + REFERENCE_TIME tStart, + REFERENCE_TIME tStop + ) +{ + // fix up sample if past actual stop (for sector alignment) + REFERENCE_TIME t1, t2; + if (S_OK == pSample->GetTime(&t1, &t2)) { + if (t2 > tStop) { + t2 = tStop; + } + + // adjust times to be relative to (aligned) start time + t1 -= tStart; + t2 -= tStart; + HRESULT hr = pSample->SetTime(&t1, &t2); + if (FAILED(hr)) { + return hr; + } + } + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + pSample->GetMediaType( &pmt ); + PERFLOG_RECEIVE( L"CPullPin", m_pReader, this, pSample, pmt ); + } +#endif + + HRESULT hr = Receive(pSample); + pSample->Release(); + return hr; +} + +void +CPullPin::Process(void) +{ + // is there anything to do? + if (m_tStop <= m_tStart) { + EndOfStream(); + return; + } + + BOOL bDiscontinuity = TRUE; + + // if there is more than one sample at the allocator, + // then try to queue 2 at once in order to overlap. + // -- get buffer count and required alignment + ALLOCATOR_PROPERTIES Actual; + HRESULT hr = m_pAlloc->GetProperties(&Actual); + + // align the start position downwards + REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS; + REFERENCE_TIME tCurrent = tStart; + + REFERENCE_TIME tStop = m_tStop; + if (tStop > m_tDuration) { + tStop = m_tDuration; + } + + // align the stop position - may be past stop, but that + // doesn't matter + REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS; + + + DWORD dwRequest; + + if (!m_bSync) { + + // Break out of the loop either if we get to the end or we're asked + // to do something else + while (tCurrent < tAlignStop) { + + // Break out without calling EndOfStream if we're asked to + // do something different + if (CheckRequest(&dwRequest)) { + return; + } + + // queue a first sample + if (Actual.cBuffers > 1) { + + hr = QueueSample(tCurrent, tAlignStop, TRUE); + bDiscontinuity = FALSE; + + if (FAILED(hr)) { + return; + } + } + + + + // loop queueing second and waiting for first.. + while (tCurrent < tAlignStop) { + + hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity); + bDiscontinuity = FALSE; + + if (FAILED(hr)) { + return; + } + + hr = CollectAndDeliver(tStart, tStop); + if (S_OK != hr) { + + // stop if error, or if downstream filter said + // to stop. + return; + } + } + + if (Actual.cBuffers > 1) { + hr = CollectAndDeliver(tStart, tStop); + if (FAILED(hr)) { + return; + } + } + } + } else { + + // sync version of above loop + while (tCurrent < tAlignStop) { + + // Break out without calling EndOfStream if we're asked to + // do something different + if (CheckRequest(&dwRequest)) { + return; + } + + IMediaSample* pSample; + + hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); + if (FAILED(hr)) { + OnError(hr); + return; + } + + LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); + if (tStopThis > tAlignStop) { + tStopThis = tAlignStop; + } + pSample->SetTime(&tCurrent, &tStopThis); + tCurrent = tStopThis; + + if (bDiscontinuity) { + pSample->SetDiscontinuity(TRUE); + bDiscontinuity = FALSE; + } + + hr = m_pReader->SyncReadAligned(pSample); + + if (FAILED(hr)) { + pSample->Release(); + OnError(hr); + return; + } + + hr = DeliverSample(pSample, tStart, tStop); + if (hr != S_OK) { + if (FAILED(hr)) { + OnError(hr); + } + return; + } + } + } + + EndOfStream(); +} + +// after a flush, cancelled i/o will be waiting for collection +// and release +void +CPullPin::CleanupCancelled(void) +{ + for (;;) { + IMediaSample * pSample; + DWORD_PTR dwUnused; + + HRESULT hr = m_pReader->WaitForNext( + 0, // no wait + &pSample, + &dwUnused); + UNREFERENCED_PARAMETER(hr); + if(pSample) { + pSample->Release(); + } else { + // no more samples + return; + } + } +} diff --git a/src/thirdparty/BaseClasses/pullpin.h b/src/thirdparty/BaseClasses/pullpin.h index 03ad40ec9af..db4f4071e2e 100644 --- a/src/thirdparty/BaseClasses/pullpin.h +++ b/src/thirdparty/BaseClasses/pullpin.h @@ -1,152 +1,152 @@ -//------------------------------------------------------------------------------ -// File: PullPin.h -// -// Desc: DirectShow base classes - defines CPullPin class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __PULLPIN_H__ -#define __PULLPIN_H__ - -// -// CPullPin -// -// object supporting pulling data from an IAsyncReader interface. -// Given a start/stop position, calls a pure Receive method with each -// IMediaSample received. -// -// This is essentially for use in a MemInputPin when it finds itself -// connected to an IAsyncReader pin instead of a pushing pin. -// - -class CPullPin : public CAMThread -{ - IAsyncReader* m_pReader; - REFERENCE_TIME m_tStart; - REFERENCE_TIME m_tStop; - REFERENCE_TIME m_tDuration; - BOOL m_bSync; - - enum ThreadMsg { - TM_Pause, // stop pulling and wait for next message - TM_Start, // start pulling - TM_Exit, // stop and exit - }; - - ThreadMsg m_State; - - // override pure thread proc from CAMThread - DWORD ThreadProc(void); - - // running pull method (check m_bSync) - void Process(void); - - // clean up any cancelled i/o after a flush - void CleanupCancelled(void); - - // suspend thread from pulling, eg during seek - HRESULT PauseThread(); - - // start thread pulling - create thread if necy - HRESULT StartThread(); - - // stop and close thread - HRESULT StopThread(); - - // called from ProcessAsync to queue and collect requests - HRESULT QueueSample( - __inout REFERENCE_TIME& tCurrent, - REFERENCE_TIME tAlignStop, - BOOL bDiscontinuity); - - HRESULT CollectAndDeliver( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop); - - HRESULT DeliverSample( - IMediaSample* pSample, - REFERENCE_TIME tStart, - REFERENCE_TIME tStop); - -protected: - IMemAllocator * m_pAlloc; - -public: - CPullPin(); - virtual ~CPullPin(); - - // returns S_OK if successfully connected to an IAsyncReader interface - // from this object - // Optional allocator should be proposed as a preferred allocator if - // necessary - // bSync is TRUE if we are to use sync reads instead of the - // async methods. - HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync); - - // disconnect any connection made in Connect - HRESULT Disconnect(); - - // agree an allocator using RequestAllocator - optional - // props param specifies your requirements (non-zero fields). - // returns an error code if fail to match requirements. - // optional IMemAllocator interface is offered as a preferred allocator - // but no error occurs if it can't be met. - virtual HRESULT DecideAllocator( - IMemAllocator* pAlloc, - __inout_opt ALLOCATOR_PROPERTIES * pProps); - - // set start and stop position. if active, will start immediately at - // the new position. Default is 0 to duration - HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop); - - // return the total duration - HRESULT Duration(__out REFERENCE_TIME* ptDuration); - - // start pulling data - HRESULT Active(void); - - // stop pulling data - HRESULT Inactive(void); - - // helper functions - LONGLONG AlignDown(LONGLONG ll, LONG lAlign) { - // aligning downwards is just truncation - return ll & ~(lAlign-1); - }; - - LONGLONG AlignUp(LONGLONG ll, LONG lAlign) { - // align up: round up to next boundary - return (ll + (lAlign -1)) & ~(lAlign -1); - }; - - // GetReader returns the (addrefed) IAsyncReader interface - // for SyncRead etc - IAsyncReader* GetReader() { - m_pReader->AddRef(); - return m_pReader; - }; - - // -- pure -- - - // override this to handle data arrival - // return value other than S_OK will stop data - virtual HRESULT Receive(IMediaSample*) PURE; - - // override this to handle end-of-stream - virtual HRESULT EndOfStream(void) PURE; - - // called on runtime errors that will have caused pulling - // to stop - // these errors are all returned from the upstream filter, who - // will have already reported any errors to the filtergraph. - virtual void OnError(HRESULT hr) PURE; - - // flush this pin and all downstream - virtual HRESULT BeginFlush() PURE; - virtual HRESULT EndFlush() PURE; - -}; - -#endif //__PULLPIN_H__ +//------------------------------------------------------------------------------ +// File: PullPin.h +// +// Desc: DirectShow base classes - defines CPullPin class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __PULLPIN_H__ +#define __PULLPIN_H__ + +// +// CPullPin +// +// object supporting pulling data from an IAsyncReader interface. +// Given a start/stop position, calls a pure Receive method with each +// IMediaSample received. +// +// This is essentially for use in a MemInputPin when it finds itself +// connected to an IAsyncReader pin instead of a pushing pin. +// + +class CPullPin : public CAMThread +{ + IAsyncReader* m_pReader; + REFERENCE_TIME m_tStart; + REFERENCE_TIME m_tStop; + REFERENCE_TIME m_tDuration; + BOOL m_bSync; + + enum ThreadMsg { + TM_Pause, // stop pulling and wait for next message + TM_Start, // start pulling + TM_Exit, // stop and exit + }; + + ThreadMsg m_State; + + // override pure thread proc from CAMThread + DWORD ThreadProc(void); + + // running pull method (check m_bSync) + void Process(void); + + // clean up any cancelled i/o after a flush + void CleanupCancelled(void); + + // suspend thread from pulling, eg during seek + HRESULT PauseThread(); + + // start thread pulling - create thread if necy + HRESULT StartThread(); + + // stop and close thread + HRESULT StopThread(); + + // called from ProcessAsync to queue and collect requests + HRESULT QueueSample( + __inout REFERENCE_TIME& tCurrent, + REFERENCE_TIME tAlignStop, + BOOL bDiscontinuity); + + HRESULT CollectAndDeliver( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop); + + HRESULT DeliverSample( + IMediaSample* pSample, + REFERENCE_TIME tStart, + REFERENCE_TIME tStop); + +protected: + IMemAllocator * m_pAlloc; + +public: + CPullPin(); + virtual ~CPullPin(); + + // returns S_OK if successfully connected to an IAsyncReader interface + // from this object + // Optional allocator should be proposed as a preferred allocator if + // necessary + // bSync is TRUE if we are to use sync reads instead of the + // async methods. + HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync); + + // disconnect any connection made in Connect + HRESULT Disconnect(); + + // agree an allocator using RequestAllocator - optional + // props param specifies your requirements (non-zero fields). + // returns an error code if fail to match requirements. + // optional IMemAllocator interface is offered as a preferred allocator + // but no error occurs if it can't be met. + virtual HRESULT DecideAllocator( + IMemAllocator* pAlloc, + __inout_opt ALLOCATOR_PROPERTIES * pProps); + + // set start and stop position. if active, will start immediately at + // the new position. Default is 0 to duration + HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop); + + // return the total duration + HRESULT Duration(__out REFERENCE_TIME* ptDuration); + + // start pulling data + HRESULT Active(void); + + // stop pulling data + HRESULT Inactive(void); + + // helper functions + LONGLONG AlignDown(LONGLONG ll, LONG lAlign) { + // aligning downwards is just truncation + return ll & ~(lAlign-1); + }; + + LONGLONG AlignUp(LONGLONG ll, LONG lAlign) { + // align up: round up to next boundary + return (ll + (lAlign -1)) & ~(lAlign -1); + }; + + // GetReader returns the (addrefed) IAsyncReader interface + // for SyncRead etc + IAsyncReader* GetReader() { + m_pReader->AddRef(); + return m_pReader; + }; + + // -- pure -- + + // override this to handle data arrival + // return value other than S_OK will stop data + virtual HRESULT Receive(IMediaSample*) PURE; + + // override this to handle end-of-stream + virtual HRESULT EndOfStream(void) PURE; + + // called on runtime errors that will have caused pulling + // to stop + // these errors are all returned from the upstream filter, who + // will have already reported any errors to the filtergraph. + virtual void OnError(HRESULT hr) PURE; + + // flush this pin and all downstream + virtual HRESULT BeginFlush() PURE; + virtual HRESULT EndFlush() PURE; + +}; + +#endif //__PULLPIN_H__ diff --git a/src/thirdparty/BaseClasses/refclock.cpp b/src/thirdparty/BaseClasses/refclock.cpp index 993204e11e4..a35033f1729 100644 --- a/src/thirdparty/BaseClasses/refclock.cpp +++ b/src/thirdparty/BaseClasses/refclock.cpp @@ -1,403 +1,403 @@ -//------------------------------------------------------------------------------ -// File: RefClock.cpp -// -// Desc: DirectShow base classes - implements the IReferenceClock interface. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -#ifdef DXMPERF -#include "dxmperf.h" -#endif // DXMPERF - - -// 'this' used in constructor list -#pragma warning(disable:4355) - - -STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface( - REFIID riid, - __deref_out void ** ppv) -{ - HRESULT hr; - - if (riid == IID_IReferenceClock) - { - hr = GetInterface((IReferenceClock *) this, ppv); - } - else if (riid == IID_IReferenceClockTimerControl) - { - hr = GetInterface((IReferenceClockTimerControl *) this, ppv); - } - else - { - hr = CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - return hr; -} - -CBaseReferenceClock::~CBaseReferenceClock() -{ -#ifdef DXMPERF - PERFLOG_DTOR( L"CBaseReferenceClock", (IReferenceClock *) this ); -#endif // DXMPERF - - if (m_TimerResolution) timeEndPeriod(m_TimerResolution); - - if (m_pSchedule) - { - m_pSchedule->DumpLinkedList(); - } - - if (m_hThread) - { - m_bAbort = TRUE; - TriggerThread(); - WaitForSingleObject( m_hThread, INFINITE ); - EXECUTE_ASSERT( CloseHandle(m_hThread) ); - m_hThread = NULL; - EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); - delete m_pSchedule; - } -} - -// A derived class may supply a hThreadEvent if it has its own thread that will take care -// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread() -// to see what such a thread has to do.) -CBaseReferenceClock::CBaseReferenceClock( __in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - __inout_opt CAMSchedule * pShed ) -: CUnknown( pName, pUnk ) -, m_rtLastGotTime(0) -, m_TimerResolution(0) -, m_bAbort( FALSE ) -, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) -, m_hThread(NULL) -, m_rtNextAdvise(0) -{ - -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBaseReferenceClock", (IReferenceClock *) this ); -#endif // DXMPERF - - ASSERT(m_pSchedule); - if (!m_pSchedule) - { - *phr = E_OUTOFMEMORY; - } - else - { - // Set up the highest resolution timer we can manage - TIMECAPS tc; - m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) - ? tc.wPeriodMin - : 1; - - timeBeginPeriod(m_TimerResolution); - - /* Initialise our system times - the derived clock should set the right values */ - m_dwPrevSystemTime = timeGetTime(); - m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime; - - #ifdef PERF - m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime")); - #endif - - if ( !pShed ) - { - DWORD ThreadID; - m_hThread = ::CreateThread(NULL, // Security attributes - (DWORD) 0, // Initial stack size - AdviseThreadFunction, // Thread start address - (LPVOID) this, // Thread parameter - (DWORD) 0, // Creation flags - &ThreadID); // Thread identifier - - if (m_hThread) - { - SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL ); - } - else - { - *phr = E_FAIL; - EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); - delete m_pSchedule; - m_pSchedule = NULL; - } - } - } -} - -void CBaseReferenceClock::Restart (IN REFERENCE_TIME rtMinTime) -{ - Lock(); - m_rtLastGotTime = rtMinTime ; - Unlock(); -} - -STDMETHODIMP CBaseReferenceClock::GetTime(__out REFERENCE_TIME *pTime) -{ - HRESULT hr; - if (pTime) - { - REFERENCE_TIME rtNow; - Lock(); - rtNow = GetPrivateTime(); - if (rtNow > m_rtLastGotTime) - { - m_rtLastGotTime = rtNow; - hr = S_OK; - } - else - { - hr = S_FALSE; - } - *pTime = m_rtLastGotTime; - Unlock(); - MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)) ); - -#ifdef DXMPERF - PERFLOG_GETTIME( (IReferenceClock *) this, *pTime ); -#endif // DXMPERF - - } - else hr = E_POINTER; - - return hr; -} - -/* Ask for an async notification that a time has elapsed */ - -STDMETHODIMP CBaseReferenceClock::AdviseTime( - REFERENCE_TIME baseTime, // base reference time - REFERENCE_TIME streamTime, // stream offset time - HEVENT hEvent, // advise via this event - __out DWORD_PTR *pdwAdviseCookie)// where your cookie goes -{ - CheckPointer(pdwAdviseCookie, E_POINTER); - *pdwAdviseCookie = 0; - - // Check that the event is not already set - ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0)); - - HRESULT hr; - - const REFERENCE_TIME lRefTime = baseTime + streamTime; - if ( lRefTime <= 0 || lRefTime == MAX_TIME ) - { - hr = E_INVALIDARG; - } - else - { - *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE ); - hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; - } - return hr; -} - - -/* Ask for an asynchronous periodic notification that a time has elapsed */ - -STDMETHODIMP CBaseReferenceClock::AdvisePeriodic( - REFERENCE_TIME StartTime, // starting at this time - REFERENCE_TIME PeriodTime, // time between notifications - HSEMAPHORE hSemaphore, // advise via a semaphore - __out DWORD_PTR *pdwAdviseCookie) // where your cookie goes -{ - CheckPointer(pdwAdviseCookie, E_POINTER); - *pdwAdviseCookie = 0; - - HRESULT hr; - if (StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME ) - { - *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE ); - hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; - } - else hr = E_INVALIDARG; - - return hr; -} - - -STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) -{ - return m_pSchedule->Unadvise(dwAdviseCookie); -} - - -REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() -{ - CAutoLock cObjectLock(this); - - - /* If the clock has wrapped then the current time will be less than - * the last time we were notified so add on the extra milliseconds - * - * The time period is long enough so that the likelihood of - * successive calls spanning the clock cycle is not considered. - */ - - DWORD dwTime = timeGetTime(); - { - m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime)); - m_dwPrevSystemTime = dwTime; - } - - return m_rtPrivateTime; -} - - -/* Adjust the current time by the input value. This allows an - external time source to work out some of the latency of the clock - system and adjust the "current" time accordingly. The intent is - that the time returned to the user is synchronised to a clock - source and allows drift to be catered for. - - For example: if the clock source detects a drift it can pass a delta - to the current time rather than having to set an explicit time. -*/ - -STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) -{ -#ifdef _DEBUG - - // Just break if passed an improper time delta value - LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta; - if (llDelta > UNITS * 1000) { - DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta"))); - //DebugBreak(); - } - - // We're going to calculate a "severity" for the time change. Max -1 - // min 8. We'll then use this as the debug logging level for a - // debug log message. - const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs - - DWORD delta = abs(usDelta); // varying delta - // Severity == 8 - ceil(log(abs( micro-secs delta))) - int Severity = 8; - while ( delta > 0 ) - { - delta >>= 3; // div 8 - Severity--; - } - - // Sev == 0 => > 2 second delta! - DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity, - TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."), - Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)), - DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) )); - - // Don't want the DbgBreak to fire when running stress on debug-builds. - #ifdef BREAK_ON_SEVERE_TIME_DELTA - if (Severity < 0) - DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"), - TEXT(__FILE__),__LINE__); - #endif - -#endif - - CAutoLock cObjectLock(this); - m_rtPrivateTime += TimeDelta; - // If time goes forwards, and we have advises, then we need to - // trigger the thread so that it can re-evaluate its wait time. - // Since we don't want the cost of the thread switches if the change - // is really small, only do it if clock goes forward by more than - // 0.5 millisecond. If the time goes backwards, the thread will - // wake up "early" (relativly speaking) and will re-evaluate at - // that time. - if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread(); - return NOERROR; -} - -// Thread stuff - -DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(__in LPVOID p) -{ - return DWORD(reinterpret_cast(p)->AdviseThread()); -} - -HRESULT CBaseReferenceClock::AdviseThread() -{ - DWORD dwWait = INFINITE; - - // The first thing we do is wait until something interesting happens - // (meaning a first advise or shutdown). This prevents us calling - // GetPrivateTime immediately which is goodness as that is a virtual - // routine and the derived class may not yet be constructed. (This - // thread is created in the base class constructor.) - - while ( !m_bAbort ) - { - // Wait for an interesting event to happen - DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait )); - WaitForSingleObject(m_pSchedule->GetEvent(), dwWait); - if (m_bAbort) break; - - // There are several reasons why we need to work from the internal - // time, mainly to do with what happens when time goes backwards. - // Mainly, it stop us looping madly if an event is just about to - // expire when the clock goes backward (i.e. GetTime stop for a - // while). - const REFERENCE_TIME rtNow = GetPrivateTime(); - - DbgLog((LOG_TIMING, 3, - TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"), - ConvertToMilliseconds(rtNow) )); - - // We must add in a millisecond, since this is the resolution of our - // WaitForSingleObject timer. Failure to do so will cause us to loop - // franticly for (approx) 1 a millisecond. - m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow ); - LONGLONG llWait = m_rtNextAdvise - rtNow; - - ASSERT( llWait > 0 ); - - llWait = ConvertToMilliseconds(llWait); - // DON'T replace this with a max!! (The type's of these things is VERY important) - dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait); - }; - return NOERROR; -} - -HRESULT CBaseReferenceClock::SetDefaultTimerResolution( - REFERENCE_TIME timerResolution // in 100ns - ) -{ - CAutoLock cObjectLock(this); - if( 0 == timerResolution ) { - if( m_TimerResolution ) { - timeEndPeriod( m_TimerResolution ); - m_TimerResolution = 0; - } - } else { - TIMECAPS tc; - DWORD dwMinResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) - ? tc.wPeriodMin - : 1; - DWORD dwResolution = std::max(dwMinResolution, DWORD(timerResolution / 10000)); - if( dwResolution != m_TimerResolution ) { - timeEndPeriod(m_TimerResolution); - m_TimerResolution = dwResolution; - timeBeginPeriod( m_TimerResolution ); - } - } - return S_OK; -} - -HRESULT CBaseReferenceClock::GetDefaultTimerResolution( - __out REFERENCE_TIME* pTimerResolution // in 100ns - ) -{ - if( !pTimerResolution ) { - return E_POINTER; - } - CAutoLock cObjectLock(this); - *pTimerResolution = m_TimerResolution * 10000i64; - return S_OK; -} +//------------------------------------------------------------------------------ +// File: RefClock.cpp +// +// Desc: DirectShow base classes - implements the IReferenceClock interface. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +#ifdef DXMPERF +#include "dxmperf.h" +#endif // DXMPERF + + +// 'this' used in constructor list +#pragma warning(disable:4355) + + +STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface( + REFIID riid, + __deref_out void ** ppv) +{ + HRESULT hr; + + if (riid == IID_IReferenceClock) + { + hr = GetInterface((IReferenceClock *) this, ppv); + } + else if (riid == IID_IReferenceClockTimerControl) + { + hr = GetInterface((IReferenceClockTimerControl *) this, ppv); + } + else + { + hr = CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + return hr; +} + +CBaseReferenceClock::~CBaseReferenceClock() +{ +#ifdef DXMPERF + PERFLOG_DTOR( L"CBaseReferenceClock", (IReferenceClock *) this ); +#endif // DXMPERF + + if (m_TimerResolution) timeEndPeriod(m_TimerResolution); + + if (m_pSchedule) + { + m_pSchedule->DumpLinkedList(); + } + + if (m_hThread) + { + m_bAbort = TRUE; + TriggerThread(); + WaitForSingleObject( m_hThread, INFINITE ); + EXECUTE_ASSERT( CloseHandle(m_hThread) ); + m_hThread = NULL; + EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); + delete m_pSchedule; + } +} + +// A derived class may supply a hThreadEvent if it has its own thread that will take care +// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread() +// to see what such a thread has to do.) +CBaseReferenceClock::CBaseReferenceClock( __in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + __inout_opt CAMSchedule * pShed ) +: CUnknown( pName, pUnk ) +, m_rtLastGotTime(0) +, m_TimerResolution(0) +, m_bAbort( FALSE ) +, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) +, m_hThread(NULL) +, m_rtNextAdvise(0) +{ + +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBaseReferenceClock", (IReferenceClock *) this ); +#endif // DXMPERF + + ASSERT(m_pSchedule); + if (!m_pSchedule) + { + *phr = E_OUTOFMEMORY; + } + else + { + // Set up the highest resolution timer we can manage + TIMECAPS tc; + m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) + ? tc.wPeriodMin + : 1; + + timeBeginPeriod(m_TimerResolution); + + /* Initialise our system times - the derived clock should set the right values */ + m_dwPrevSystemTime = timeGetTime(); + m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime; + + #ifdef PERF + m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime")); + #endif + + if ( !pShed ) + { + DWORD ThreadID; + m_hThread = ::CreateThread(NULL, // Security attributes + (DWORD) 0, // Initial stack size + AdviseThreadFunction, // Thread start address + (LPVOID) this, // Thread parameter + (DWORD) 0, // Creation flags + &ThreadID); // Thread identifier + + if (m_hThread) + { + SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL ); + } + else + { + *phr = E_FAIL; + EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); + delete m_pSchedule; + m_pSchedule = NULL; + } + } + } +} + +void CBaseReferenceClock::Restart (IN REFERENCE_TIME rtMinTime) +{ + Lock(); + m_rtLastGotTime = rtMinTime ; + Unlock(); +} + +STDMETHODIMP CBaseReferenceClock::GetTime(__out REFERENCE_TIME *pTime) +{ + HRESULT hr; + if (pTime) + { + REFERENCE_TIME rtNow; + Lock(); + rtNow = GetPrivateTime(); + if (rtNow > m_rtLastGotTime) + { + m_rtLastGotTime = rtNow; + hr = S_OK; + } + else + { + hr = S_FALSE; + } + *pTime = m_rtLastGotTime; + Unlock(); + MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)) ); + +#ifdef DXMPERF + PERFLOG_GETTIME( (IReferenceClock *) this, *pTime ); +#endif // DXMPERF + + } + else hr = E_POINTER; + + return hr; +} + +/* Ask for an async notification that a time has elapsed */ + +STDMETHODIMP CBaseReferenceClock::AdviseTime( + REFERENCE_TIME baseTime, // base reference time + REFERENCE_TIME streamTime, // stream offset time + HEVENT hEvent, // advise via this event + __out DWORD_PTR *pdwAdviseCookie)// where your cookie goes +{ + CheckPointer(pdwAdviseCookie, E_POINTER); + *pdwAdviseCookie = 0; + + // Check that the event is not already set + ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0)); + + HRESULT hr; + + const REFERENCE_TIME lRefTime = baseTime + streamTime; + if ( lRefTime <= 0 || lRefTime == MAX_TIME ) + { + hr = E_INVALIDARG; + } + else + { + *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE ); + hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; + } + return hr; +} + + +/* Ask for an asynchronous periodic notification that a time has elapsed */ + +STDMETHODIMP CBaseReferenceClock::AdvisePeriodic( + REFERENCE_TIME StartTime, // starting at this time + REFERENCE_TIME PeriodTime, // time between notifications + HSEMAPHORE hSemaphore, // advise via a semaphore + __out DWORD_PTR *pdwAdviseCookie) // where your cookie goes +{ + CheckPointer(pdwAdviseCookie, E_POINTER); + *pdwAdviseCookie = 0; + + HRESULT hr; + if (StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME ) + { + *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE ); + hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; + } + else hr = E_INVALIDARG; + + return hr; +} + + +STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) +{ + return m_pSchedule->Unadvise(dwAdviseCookie); +} + + +REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() +{ + CAutoLock cObjectLock(this); + + + /* If the clock has wrapped then the current time will be less than + * the last time we were notified so add on the extra milliseconds + * + * The time period is long enough so that the likelihood of + * successive calls spanning the clock cycle is not considered. + */ + + DWORD dwTime = timeGetTime(); + { + m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime)); + m_dwPrevSystemTime = dwTime; + } + + return m_rtPrivateTime; +} + + +/* Adjust the current time by the input value. This allows an + external time source to work out some of the latency of the clock + system and adjust the "current" time accordingly. The intent is + that the time returned to the user is synchronised to a clock + source and allows drift to be catered for. + + For example: if the clock source detects a drift it can pass a delta + to the current time rather than having to set an explicit time. +*/ + +STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) +{ +#ifdef _DEBUG + + // Just break if passed an improper time delta value + LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta; + if (llDelta > UNITS * 1000) { + DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta"))); + //DebugBreak(); + } + + // We're going to calculate a "severity" for the time change. Max -1 + // min 8. We'll then use this as the debug logging level for a + // debug log message. + const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs + + DWORD delta = abs(usDelta); // varying delta + // Severity == 8 - ceil(log(abs( micro-secs delta))) + int Severity = 8; + while ( delta > 0 ) + { + delta >>= 3; // div 8 + Severity--; + } + + // Sev == 0 => > 2 second delta! + DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity, + TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."), + Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)), + DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) )); + + // Don't want the DbgBreak to fire when running stress on debug-builds. + #ifdef BREAK_ON_SEVERE_TIME_DELTA + if (Severity < 0) + DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"), + TEXT(__FILE__),__LINE__); + #endif + +#endif + + CAutoLock cObjectLock(this); + m_rtPrivateTime += TimeDelta; + // If time goes forwards, and we have advises, then we need to + // trigger the thread so that it can re-evaluate its wait time. + // Since we don't want the cost of the thread switches if the change + // is really small, only do it if clock goes forward by more than + // 0.5 millisecond. If the time goes backwards, the thread will + // wake up "early" (relativly speaking) and will re-evaluate at + // that time. + if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread(); + return NOERROR; +} + +// Thread stuff + +DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(__in LPVOID p) +{ + return DWORD(reinterpret_cast(p)->AdviseThread()); +} + +HRESULT CBaseReferenceClock::AdviseThread() +{ + DWORD dwWait = INFINITE; + + // The first thing we do is wait until something interesting happens + // (meaning a first advise or shutdown). This prevents us calling + // GetPrivateTime immediately which is goodness as that is a virtual + // routine and the derived class may not yet be constructed. (This + // thread is created in the base class constructor.) + + while ( !m_bAbort ) + { + // Wait for an interesting event to happen + DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait )); + WaitForSingleObject(m_pSchedule->GetEvent(), dwWait); + if (m_bAbort) break; + + // There are several reasons why we need to work from the internal + // time, mainly to do with what happens when time goes backwards. + // Mainly, it stop us looping madly if an event is just about to + // expire when the clock goes backward (i.e. GetTime stop for a + // while). + const REFERENCE_TIME rtNow = GetPrivateTime(); + + DbgLog((LOG_TIMING, 3, + TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"), + ConvertToMilliseconds(rtNow) )); + + // We must add in a millisecond, since this is the resolution of our + // WaitForSingleObject timer. Failure to do so will cause us to loop + // franticly for (approx) 1 a millisecond. + m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow ); + LONGLONG llWait = m_rtNextAdvise - rtNow; + + ASSERT( llWait > 0 ); + + llWait = ConvertToMilliseconds(llWait); + // DON'T replace this with a max!! (The type's of these things is VERY important) + dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait); + }; + return NOERROR; +} + +HRESULT CBaseReferenceClock::SetDefaultTimerResolution( + REFERENCE_TIME timerResolution // in 100ns + ) +{ + CAutoLock cObjectLock(this); + if( 0 == timerResolution ) { + if( m_TimerResolution ) { + timeEndPeriod( m_TimerResolution ); + m_TimerResolution = 0; + } + } else { + TIMECAPS tc; + DWORD dwMinResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) + ? tc.wPeriodMin + : 1; + DWORD dwResolution = std::max(dwMinResolution, DWORD(timerResolution / 10000)); + if( dwResolution != m_TimerResolution ) { + timeEndPeriod(m_TimerResolution); + m_TimerResolution = dwResolution; + timeBeginPeriod( m_TimerResolution ); + } + } + return S_OK; +} + +HRESULT CBaseReferenceClock::GetDefaultTimerResolution( + __out REFERENCE_TIME* pTimerResolution // in 100ns + ) +{ + if( !pTimerResolution ) { + return E_POINTER; + } + CAutoLock cObjectLock(this); + *pTimerResolution = m_TimerResolution * 10000i64; + return S_OK; +} diff --git a/src/thirdparty/BaseClasses/refclock.h b/src/thirdparty/BaseClasses/refclock.h index 2a8d38434b7..d5e9affbcb0 100644 --- a/src/thirdparty/BaseClasses/refclock.h +++ b/src/thirdparty/BaseClasses/refclock.h @@ -1,184 +1,184 @@ -//------------------------------------------------------------------------------ -// File: RefClock.h -// -// Desc: DirectShow base classes - defines the IReferenceClock interface. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __BASEREFCLOCK__ -#define __BASEREFCLOCK__ - -#include "Schedule.h" - -const UINT RESOLUTION = 1; /* High resolution timer */ -const INT ADVISE_CACHE = 4; /* Default cache size */ -const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */ - -inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT) -{ - /* This converts an arbitrary value representing a reference time - into a MILLISECONDS value for use in subsequent system calls */ - - return (RT / (UNITS / MILLISECONDS)); -} - -/* This class hierarchy will support an IReferenceClock interface so - that an audio card (or other externally driven clock) can update the - system wide clock that everyone uses. - - The interface will be pretty thin with probably just one update method - This interface has not yet been defined. - */ - -/* This abstract base class implements the IReferenceClock - * interface. Classes that actually provide clock signals (from - * whatever source) have to be derived from this class. - * - * The abstract class provides implementations for: - * CUnknown support - * locking support (CCritSec) - * client advise code (creates a thread) - * - * Question: what can we do about quality? Change the timer - * resolution to lower the system load? Up the priority of the - * timer thread to force more responsive signals? - * - * During class construction we create a worker thread that is destroyed during - * destuction. This thread executes a series of WaitForSingleObject calls, - * waking up when a command is given to the thread or the next wake up point - * is reached. The wakeup points are determined by clients making Advise - * calls. - * - * Each advise call defines a point in time when they wish to be notified. A - * periodic advise is a series of these such events. We maintain a list of - * advise links and calculate when the nearest event notification is due for. - * We then call WaitForSingleObject with a timeout equal to this time. The - * handle we wait on is used by the class to signal that something has changed - * and that we must reschedule the next event. This typically happens when - * someone comes in and asks for an advise link while we are waiting for an - * event to timeout. - * - * While we are modifying the list of advise requests we - * are protected from interference through a critical section. Clients are NOT - * advised through callbacks. One shot clients have an event set, while - * periodic clients have a semaphore released for each event notification. A - * semaphore allows a client to be kept up to date with the number of events - * actually triggered and be assured that they can't miss multiple events being - * set. - * - * Keeping track of advises is taken care of by the CAMSchedule class. - */ - -class CBaseReferenceClock -: public CUnknown, public IReferenceClock, public CCritSec, public IReferenceClockTimerControl -{ -protected: - virtual ~CBaseReferenceClock(); // Don't let me be created on the stack! -public: - CBaseReferenceClock(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - __inout_opt CAMSchedule * pSched = 0 ); - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - - DECLARE_IUNKNOWN - - /* IReferenceClock methods */ - // Derived classes must implement GetPrivateTime(). All our GetTime - // does is call GetPrivateTime and then check so that time does not - // go backwards. A return code of S_FALSE implies that the internal - // clock has gone backwards and GetTime time has halted until internal - // time has caught up. (Don't know if this will be much use to folk, - // but it seems odd not to use the return code for something useful.) - STDMETHODIMP GetTime(__out REFERENCE_TIME *pTime); - // When this is called, it sets m_rtLastGotTime to the time it returns. - - /* Provide standard mechanisms for scheduling events */ - - /* Ask for an async notification that a time has elapsed */ - STDMETHODIMP AdviseTime( - REFERENCE_TIME baseTime, // base reference time - REFERENCE_TIME streamTime, // stream offset time - HEVENT hEvent, // advise via this event - __out DWORD_PTR *pdwAdviseCookie// where your cookie goes - ); - - /* Ask for an asynchronous periodic notification that a time has elapsed */ - STDMETHODIMP AdvisePeriodic( - REFERENCE_TIME StartTime, // starting at this time - REFERENCE_TIME PeriodTime, // time between notifications - HSEMAPHORE hSemaphore, // advise via a semaphore - __out DWORD_PTR *pdwAdviseCookie// where your cookie goes - ); - - /* Cancel a request for notification(s) - if the notification was - * a one shot timer then this function doesn't need to be called - * as the advise is automatically cancelled, however it does no - * harm to explicitly cancel a one-shot advise. It is REQUIRED that - * clients call Unadvise to clear a Periodic advise setting. - */ - - STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie); - - /* Methods for the benefit of derived classes or outer objects */ - - // GetPrivateTime() is the REAL clock. GetTime is just a cover for - // it. Derived classes will probably override this method but not - // GetTime() itself. - // The important point about GetPrivateTime() is it's allowed to go - // backwards. Our GetTime() will keep returning the LastGotTime - // until GetPrivateTime() catches up. - virtual REFERENCE_TIME GetPrivateTime(); - - /* Provide a method for correcting drift */ - STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta ); - - CAMSchedule * GetSchedule() const { return m_pSchedule; } - - // IReferenceClockTimerControl methods - // - // Setting a default of 0 disables the default of 1ms - STDMETHODIMP SetDefaultTimerResolution( - REFERENCE_TIME timerResolution // in 100ns - ); - STDMETHODIMP GetDefaultTimerResolution( - __out REFERENCE_TIME* pTimerResolution // in 100ns - ); - -private: - REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time - DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime - REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime - REFERENCE_TIME m_rtNextAdvise; // Time of next advise - UINT m_TimerResolution; - -#ifdef PERF - int m_idGetSystemTime; -#endif - -// Thread stuff -public: - void TriggerThread() // Wakes thread up. Need to do this if - { // time to next advise needs reevaluating. - EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent())); - } - - -private: - BOOL m_bAbort; // Flag used for thread shutdown - HANDLE m_hThread; // Thread handle - - HRESULT AdviseThread(); // Method in which the advise thread runs - static DWORD __stdcall AdviseThreadFunction(__in LPVOID); // Function used to get there - -protected: - CAMSchedule * m_pSchedule; - - void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ; -}; - -#endif - +//------------------------------------------------------------------------------ +// File: RefClock.h +// +// Desc: DirectShow base classes - defines the IReferenceClock interface. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __BASEREFCLOCK__ +#define __BASEREFCLOCK__ + +#include "Schedule.h" + +const UINT RESOLUTION = 1; /* High resolution timer */ +const INT ADVISE_CACHE = 4; /* Default cache size */ +const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */ + +inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT) +{ + /* This converts an arbitrary value representing a reference time + into a MILLISECONDS value for use in subsequent system calls */ + + return (RT / (UNITS / MILLISECONDS)); +} + +/* This class hierarchy will support an IReferenceClock interface so + that an audio card (or other externally driven clock) can update the + system wide clock that everyone uses. + + The interface will be pretty thin with probably just one update method + This interface has not yet been defined. + */ + +/* This abstract base class implements the IReferenceClock + * interface. Classes that actually provide clock signals (from + * whatever source) have to be derived from this class. + * + * The abstract class provides implementations for: + * CUnknown support + * locking support (CCritSec) + * client advise code (creates a thread) + * + * Question: what can we do about quality? Change the timer + * resolution to lower the system load? Up the priority of the + * timer thread to force more responsive signals? + * + * During class construction we create a worker thread that is destroyed during + * destuction. This thread executes a series of WaitForSingleObject calls, + * waking up when a command is given to the thread or the next wake up point + * is reached. The wakeup points are determined by clients making Advise + * calls. + * + * Each advise call defines a point in time when they wish to be notified. A + * periodic advise is a series of these such events. We maintain a list of + * advise links and calculate when the nearest event notification is due for. + * We then call WaitForSingleObject with a timeout equal to this time. The + * handle we wait on is used by the class to signal that something has changed + * and that we must reschedule the next event. This typically happens when + * someone comes in and asks for an advise link while we are waiting for an + * event to timeout. + * + * While we are modifying the list of advise requests we + * are protected from interference through a critical section. Clients are NOT + * advised through callbacks. One shot clients have an event set, while + * periodic clients have a semaphore released for each event notification. A + * semaphore allows a client to be kept up to date with the number of events + * actually triggered and be assured that they can't miss multiple events being + * set. + * + * Keeping track of advises is taken care of by the CAMSchedule class. + */ + +class CBaseReferenceClock +: public CUnknown, public IReferenceClock, public CCritSec, public IReferenceClockTimerControl +{ +protected: + virtual ~CBaseReferenceClock(); // Don't let me be created on the stack! +public: + CBaseReferenceClock(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + __inout_opt CAMSchedule * pSched = 0 ); + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + + DECLARE_IUNKNOWN + + /* IReferenceClock methods */ + // Derived classes must implement GetPrivateTime(). All our GetTime + // does is call GetPrivateTime and then check so that time does not + // go backwards. A return code of S_FALSE implies that the internal + // clock has gone backwards and GetTime time has halted until internal + // time has caught up. (Don't know if this will be much use to folk, + // but it seems odd not to use the return code for something useful.) + STDMETHODIMP GetTime(__out REFERENCE_TIME *pTime); + // When this is called, it sets m_rtLastGotTime to the time it returns. + + /* Provide standard mechanisms for scheduling events */ + + /* Ask for an async notification that a time has elapsed */ + STDMETHODIMP AdviseTime( + REFERENCE_TIME baseTime, // base reference time + REFERENCE_TIME streamTime, // stream offset time + HEVENT hEvent, // advise via this event + __out DWORD_PTR *pdwAdviseCookie// where your cookie goes + ); + + /* Ask for an asynchronous periodic notification that a time has elapsed */ + STDMETHODIMP AdvisePeriodic( + REFERENCE_TIME StartTime, // starting at this time + REFERENCE_TIME PeriodTime, // time between notifications + HSEMAPHORE hSemaphore, // advise via a semaphore + __out DWORD_PTR *pdwAdviseCookie// where your cookie goes + ); + + /* Cancel a request for notification(s) - if the notification was + * a one shot timer then this function doesn't need to be called + * as the advise is automatically cancelled, however it does no + * harm to explicitly cancel a one-shot advise. It is REQUIRED that + * clients call Unadvise to clear a Periodic advise setting. + */ + + STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie); + + /* Methods for the benefit of derived classes or outer objects */ + + // GetPrivateTime() is the REAL clock. GetTime is just a cover for + // it. Derived classes will probably override this method but not + // GetTime() itself. + // The important point about GetPrivateTime() is it's allowed to go + // backwards. Our GetTime() will keep returning the LastGotTime + // until GetPrivateTime() catches up. + virtual REFERENCE_TIME GetPrivateTime(); + + /* Provide a method for correcting drift */ + STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta ); + + CAMSchedule * GetSchedule() const { return m_pSchedule; } + + // IReferenceClockTimerControl methods + // + // Setting a default of 0 disables the default of 1ms + STDMETHODIMP SetDefaultTimerResolution( + REFERENCE_TIME timerResolution // in 100ns + ); + STDMETHODIMP GetDefaultTimerResolution( + __out REFERENCE_TIME* pTimerResolution // in 100ns + ); + +private: + REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time + DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime + REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime + REFERENCE_TIME m_rtNextAdvise; // Time of next advise + UINT m_TimerResolution; + +#ifdef PERF + int m_idGetSystemTime; +#endif + +// Thread stuff +public: + void TriggerThread() // Wakes thread up. Need to do this if + { // time to next advise needs reevaluating. + EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent())); + } + + +private: + BOOL m_bAbort; // Flag used for thread shutdown + HANDLE m_hThread; // Thread handle + + HRESULT AdviseThread(); // Method in which the advise thread runs + static DWORD __stdcall AdviseThreadFunction(__in LPVOID); // Function used to get there + +protected: + CAMSchedule * m_pSchedule; + + void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ; +}; + +#endif + diff --git a/src/thirdparty/BaseClasses/reftime.h b/src/thirdparty/BaseClasses/reftime.h index 5bc99a6946d..0ed32f6e175 100644 --- a/src/thirdparty/BaseClasses/reftime.h +++ b/src/thirdparty/BaseClasses/reftime.h @@ -1,116 +1,116 @@ -//------------------------------------------------------------------------------ -// File: RefTime.h -// -// Desc: DirectShow base classes - defines CRefTime, a class that manages -// reference times. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// CRefTime -// -// Manage reference times. -// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual) -// functions providing simple comparison, conversion and arithmetic. -// -// A reference time (at the moment) is a unit of seconds represented in -// 100ns units as is used in the Win32 FILETIME structure. BUT the time -// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it -// will either be stream time or reference time depending upon context -// -// This class provides simple arithmetic operations on reference times -// -// keep non-virtual otherwise the data layout will not be the same as -// REFERENCE_TIME - - -// ----- -// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but -// you will need to do so explicitly -// ----- - - -#ifndef __REFTIME__ -#define __REFTIME__ - - -const LONGLONG MILLISECONDS = (1000); // 10 ^ 3 -const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9 -const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7 - -/* Unfortunately an inline function here generates a call to __allmul - - even for constants! -*/ -#define MILLISECONDS_TO_100NS_UNITS(lMs) \ - Int32x32To64((lMs), (UNITS / MILLISECONDS)) - -class CRefTime -{ -public: - - // *MUST* be the only data member so that this class is exactly - // equivalent to a REFERENCE_TIME. - // Also, must be *no virtual functions* - - REFERENCE_TIME m_time; - - inline CRefTime() - { - // default to 0 time - m_time = 0; - }; - - inline CRefTime(LONG msecs) - { - m_time = MILLISECONDS_TO_100NS_UNITS(msecs); - }; - - inline CRefTime(REFERENCE_TIME rt) - { - m_time = rt; - }; - - inline operator REFERENCE_TIME() const - { - return m_time; - }; - - inline CRefTime& operator=(const CRefTime& rt) - { - m_time = rt.m_time; - return *this; - }; - - inline CRefTime& operator=(const LONGLONG ll) - { - m_time = ll; - return *this; - }; - - inline CRefTime& operator+=(const CRefTime& rt) - { - return (*this = *this + rt); - }; - - inline CRefTime& operator-=(const CRefTime& rt) - { - return (*this = *this - rt); - }; - - inline LONG Millisecs(void) - { - return (LONG)(m_time / (UNITS / MILLISECONDS)); - }; - - inline LONGLONG GetUnits(void) - { - return m_time; - }; -}; - -const LONGLONG TimeZero = 0; - -#endif /* __REFTIME__ */ - +//------------------------------------------------------------------------------ +// File: RefTime.h +// +// Desc: DirectShow base classes - defines CRefTime, a class that manages +// reference times. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// CRefTime +// +// Manage reference times. +// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual) +// functions providing simple comparison, conversion and arithmetic. +// +// A reference time (at the moment) is a unit of seconds represented in +// 100ns units as is used in the Win32 FILETIME structure. BUT the time +// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it +// will either be stream time or reference time depending upon context +// +// This class provides simple arithmetic operations on reference times +// +// keep non-virtual otherwise the data layout will not be the same as +// REFERENCE_TIME + + +// ----- +// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but +// you will need to do so explicitly +// ----- + + +#ifndef __REFTIME__ +#define __REFTIME__ + + +const LONGLONG MILLISECONDS = (1000); // 10 ^ 3 +const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9 +const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7 + +/* Unfortunately an inline function here generates a call to __allmul + - even for constants! +*/ +#define MILLISECONDS_TO_100NS_UNITS(lMs) \ + Int32x32To64((lMs), (UNITS / MILLISECONDS)) + +class CRefTime +{ +public: + + // *MUST* be the only data member so that this class is exactly + // equivalent to a REFERENCE_TIME. + // Also, must be *no virtual functions* + + REFERENCE_TIME m_time; + + inline CRefTime() + { + // default to 0 time + m_time = 0; + }; + + inline CRefTime(LONG msecs) + { + m_time = MILLISECONDS_TO_100NS_UNITS(msecs); + }; + + inline CRefTime(REFERENCE_TIME rt) + { + m_time = rt; + }; + + inline operator REFERENCE_TIME() const + { + return m_time; + }; + + inline CRefTime& operator=(const CRefTime& rt) + { + m_time = rt.m_time; + return *this; + }; + + inline CRefTime& operator=(const LONGLONG ll) + { + m_time = ll; + return *this; + }; + + inline CRefTime& operator+=(const CRefTime& rt) + { + return (*this = *this + rt); + }; + + inline CRefTime& operator-=(const CRefTime& rt) + { + return (*this = *this - rt); + }; + + inline LONG Millisecs(void) + { + return (LONG)(m_time / (UNITS / MILLISECONDS)); + }; + + inline LONGLONG GetUnits(void) + { + return m_time; + }; +}; + +const LONGLONG TimeZero = 0; + +#endif /* __REFTIME__ */ + diff --git a/src/thirdparty/BaseClasses/renbase.cpp b/src/thirdparty/BaseClasses/renbase.cpp index 27018a22e1b..fb6956eb7c4 100644 --- a/src/thirdparty/BaseClasses/renbase.cpp +++ b/src/thirdparty/BaseClasses/renbase.cpp @@ -1,2858 +1,2858 @@ -//------------------------------------------------------------------------------ -// File: RenBase.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" // DirectShow base class definitions -#include // Needed for definition of timeGetTime -#include // Standard data type limit definitions -#include "measure.h" // Used for time critical log functions - -#pragma warning(disable:4355) - -// Helper function for clamping time differences -int inline TimeDiff(REFERENCE_TIME rt) -{ - if (rt < - (50 * UNITS)) { - return -(50 * UNITS); - } else - if (rt > 50 * UNITS) { - return 50 * UNITS; - } else return (int)rt; -} - -// Implements the CBaseRenderer class - -CBaseRenderer::CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer - __in_opt LPCTSTR pName, // Debug ONLY description - __inout_opt LPUNKNOWN pUnk, // Aggregated owner object - __inout HRESULT *phr) : // General OLE return code - - CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass), - m_evComplete(TRUE, phr), - m_RenderEvent(FALSE, phr), - m_bAbort(FALSE), - m_pPosition(NULL), - m_ThreadSignal(TRUE, phr), - m_bStreaming(FALSE), - m_bEOS(FALSE), - m_bEOSDelivered(FALSE), - m_pMediaSample(NULL), - m_dwAdvise(0), - m_pQSink(NULL), - m_pInputPin(NULL), - m_bRepaintStatus(TRUE), - m_SignalTime(0), - m_bInReceive(FALSE), - m_EndOfStreamTimer(0) -{ - if (SUCCEEDED(*phr)) { - Ready(); -#ifdef PERF - m_idBaseStamp = MSR_REGISTER(TEXT("BaseRenderer: sample time stamp")); - m_idBaseRenderTime = MSR_REGISTER(TEXT("BaseRenderer: draw time (msec)")); - m_idBaseAccuracy = MSR_REGISTER(TEXT("BaseRenderer: Accuracy (msec)")); -#endif - } -} - - -// Delete the dynamically allocated IMediaPosition and IMediaSeeking helper -// object. The object is created when somebody queries us. These are standard -// control interfaces for seeking and setting start/stop positions and rates. -// We will probably also have made an input pin based on CRendererInputPin -// that has to be deleted, it's created when an enumerator calls our GetPin - -CBaseRenderer::~CBaseRenderer() -{ - ASSERT(m_bStreaming == FALSE); - ASSERT(m_EndOfStreamTimer == 0); - StopStreaming(); - ClearPendingSample(); - - // Delete any IMediaPosition implementation - - if (m_pPosition) { - delete m_pPosition; - m_pPosition = NULL; - } - - // Delete any input pin created - - if (m_pInputPin) { - delete m_pInputPin; - m_pInputPin = NULL; - } - - // Release any Quality sink - - ASSERT(m_pQSink == NULL); -} - - -// This returns the IMediaPosition and IMediaSeeking interfaces - -HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid, __deref_out void **ppv) -{ - CAutoLock cObjectCreationLock(&m_ObjectCreationLock); - if (m_pPosition) { - return m_pPosition->NonDelegatingQueryInterface(riid,ppv); - } - - CBasePin *pPin = GetPin(0); - if (NULL == pPin) { - return E_OUTOFMEMORY; - } - - HRESULT hr = NOERROR; - - // Create implementation of this dynamically since sometimes we may - // never try and do a seek. The helper object implements a position - // control interface (IMediaPosition) which in fact simply takes the - // calls normally from the filter graph and passes them upstream - - m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"), - CBaseFilter::GetOwner(), - (HRESULT *) &hr, - pPin); - if (m_pPosition == NULL) { - return E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - delete m_pPosition; - m_pPosition = NULL; - return E_NOINTERFACE; - } - return GetMediaPositionInterface(riid,ppv); -} - - -// Overriden to say what interfaces we support and where - -STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - // Do we have this interface - - if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { - return GetMediaPositionInterface(riid,ppv); - } else { - return CBaseFilter::NonDelegatingQueryInterface(riid,ppv); - } -} - - -// This is called whenever we change states, we have a manual reset event that -// is signalled whenever we don't won't the source filter thread to wait in us -// (such as in a stopped state) and likewise is not signalled whenever it can -// wait (during paused and running) this function sets or resets the thread -// event. The event is used to stop source filter threads waiting in Receive - -HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait) -{ - if (bCanWait == TRUE) { - m_ThreadSignal.Reset(); - } else { - m_ThreadSignal.Set(); - } - return NOERROR; -} - - -#ifdef _DEBUG -// Dump the current renderer state to the debug terminal. The hardest part of -// the renderer is the window where we unlock everything to wait for a clock -// to signal it is time to draw or for the application to cancel everything -// by stopping the filter. If we get things wrong we can leave the thread in -// WaitForRenderTime with no way for it to ever get out and we will deadlock - -void CBaseRenderer::DisplayRendererState() -{ - DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime"))); - - // No way should this be signalled at this point - - BOOL bSignalled = m_ThreadSignal.Check(); - DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled)); - - // Now output the current renderer state variables - - DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State)); - - DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort)); - - DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming)); - - DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise)); - - DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample)); - - DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS)); - - DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered)); - - DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus)); - - - // Output the delayed end of stream timer information - - DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer)); - - DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime))); - - - // Should never timeout during a flushing state - - BOOL bFlushing = m_pInputPin->IsFlushing(); - DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing)); - - // Display the time we were told to start at - DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time))); - - // Have we got a reference clock - if (m_pClock == NULL) return; - - // Get the current time from the wall clock - - CRefTime CurrentTime,StartTime,EndTime; - m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime); - CRefTime Offset = CurrentTime - m_tStart; - - // Display the current time from the clock - - DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time))); - - DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs())); - - - // Do we have a sample ready to render - if (m_pMediaSample == NULL) return; - - m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime); - DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"), - StartTime.Millisecs(),EndTime.Millisecs())); - - // Calculate how long it is until it is due for rendering - CRefTime Wait = (m_tStart + StartTime) - CurrentTime; - DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs())); -} -#endif - - -// Wait until the clock sets the timer event or we're otherwise signalled. We -// set an arbitrary timeout for this wait and if it fires then we display the -// current renderer state on the debugger. It will often fire if the filter's -// left paused in an application however it may also fire during stress tests -// if the synchronisation with application seeks and state changes is faulty - -#define RENDER_TIMEOUT 10000 - -HRESULT CBaseRenderer::WaitForRenderTime() -{ - HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent }; - DWORD Result = WAIT_TIMEOUT; - - // Wait for either the time to arrive or for us to be stopped - - OnWaitStart(); - while (Result == WAIT_TIMEOUT) { - Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT); - -#ifdef _DEBUG - if (Result == WAIT_TIMEOUT) DisplayRendererState(); -#endif - - } - OnWaitEnd(); - - // We may have been awoken without the timer firing - - if (Result == WAIT_OBJECT_0) { - return VFW_E_STATE_CHANGED; - } - - SignalTimerFired(); - return NOERROR; -} - - -// Poll waiting for Receive to complete. This really matters when -// Receive may set the palette and cause window messages -// The problem is that if we don't really wait for a renderer to -// stop processing we can deadlock waiting for a transform which -// is calling the renderer's Receive() method because the transform's -// Stop method doesn't know to process window messages to unblock -// the renderer's Receive processing -void CBaseRenderer::WaitForReceiveToComplete() -{ - for (;;) { - if (!m_bInReceive) { - break; - } - - MSG msg; - // Receive all interthread snedmessages - PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); - - Sleep(1); - } - - // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call - // above just cleared the changebit which will cause some messaging - // calls to block (waitMessage, MsgWaitFor...) now. - // Post a dummy message to set the QS_POSTMESSAGE bit again - if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { - // Send dummy message - PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); - } -} - -// A filter can have four discrete states, namely Stopped, Running, Paused, -// Intermediate. We are in an intermediate state if we are currently trying -// to pause but haven't yet got the first sample (or if we have been flushed -// in paused state and therefore still have to wait for a sample to arrive) - -// This class contains an event called m_evComplete which is signalled when -// the current state is completed and is not signalled when we are waiting to -// complete the last state transition. As mentioned above the only time we -// use this at the moment is when we wait for a media sample in paused state -// If while we are waiting we receive an end of stream notification from the -// source filter then we know no data is imminent so we can reset the event -// This means that when we transition to paused the source filter must call -// end of stream on us or send us an image otherwise we'll hang indefinately - - -// Simple internal way of getting the real state - -FILTER_STATE CBaseRenderer::GetRealState() { - return m_State; -} - - -// The renderer doesn't complete the full transition to paused states until -// it has got one media sample to render. If you ask it for its state while -// it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE - -STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State) -{ - CheckPointer(State,E_POINTER); - - if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) { - *State = m_State; - return VFW_S_STATE_INTERMEDIATE; - } - *State = m_State; - return NOERROR; -} - - -// If we're pausing and we have no samples we don't complete the transition -// to State_Paused and we return S_FALSE. However if the m_bAbort flag has -// been set then all samples are rejected so there is no point waiting for -// one. If we do have a sample then return NOERROR. We will only ever return -// VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample -// (calling GetState after either being stopped or Run will NOT return this) - -HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState) -{ - // Allow us to be paused when disconnected - - if (m_pInputPin->IsConnected() == FALSE) { - Ready(); - return S_OK; - } - - // Have we run off the end of stream - - if (IsEndOfStream() == TRUE) { - Ready(); - return S_OK; - } - - // Make sure we get fresh data after being stopped - - if (HaveCurrentSample() == TRUE) { - if (OldState != State_Stopped) { - Ready(); - return S_OK; - } - } - NotReady(); - return S_FALSE; -} - - -// When we stop the filter the things we do are:- - -// Decommit the allocator being used in the connection -// Release the source filter if it's waiting in Receive -// Cancel any advise link we set up with the clock -// Any end of stream signalled is now obsolete so reset -// Allow us to be stopped when we are not connected - -STDMETHODIMP CBaseRenderer::Stop() -{ - CAutoLock cRendererLock(&m_InterfaceLock); - - // Make sure there really is a state change - - if (m_State == State_Stopped) { - return NOERROR; - } - - // Is our input pin connected - - if (m_pInputPin->IsConnected() == FALSE) { - NOTE("Input pin is not connected"); - m_State = State_Stopped; - return NOERROR; - } - - CBaseFilter::Stop(); - - // If we are going into a stopped state then we must decommit whatever - // allocator we are using it so that any source filter waiting in the - // GetBuffer can be released and unlock themselves for a state change - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Decommit(); - } - - // Cancel any scheduled rendering - - SetRepaintStatus(TRUE); - StopStreaming(); - SourceThreadCanWait(FALSE); - ResetEndOfStream(); - CancelNotification(); - - // There should be no outstanding clock advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - - Ready(); - WaitForReceiveToComplete(); - m_bAbort = FALSE; - - return NOERROR; -} - - -// When we pause the filter the things we do are:- - -// Commit the allocator being used in the connection -// Allow a source filter thread to wait in Receive -// Cancel any clock advise link (we may be running) -// Possibly complete the state change if we have data -// Allow us to be paused when we are not connected - -STDMETHODIMP CBaseRenderer::Pause() -{ - CAutoLock cRendererLock(&m_InterfaceLock); - FILTER_STATE OldState = m_State; - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // Make sure there really is a state change - - if (m_State == State_Paused) { - return CompleteStateChange(State_Paused); - } - - // Has our input pin been connected - - if (m_pInputPin->IsConnected() == FALSE) { - NOTE("Input pin is not connected"); - m_State = State_Paused; - return CompleteStateChange(State_Paused); - } - - // Pause the base filter class - - HRESULT hr = CBaseFilter::Pause(); - if (FAILED(hr)) { - NOTE("Pause failed"); - return hr; - } - - // Enable EC_REPAINT events again - - SetRepaintStatus(TRUE); - StopStreaming(); - SourceThreadCanWait(TRUE); - CancelNotification(); - ResetEndOfStreamTimer(); - - // If we are going into a paused state then we must commit whatever - // allocator we are using it so that any source filter can call the - // GetBuffer and expect to get a buffer without returning an error - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Commit(); - } - - // There should be no outstanding advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // When we come out of a stopped state we must clear any image we were - // holding onto for frame refreshing. Since renderers see state changes - // first we can reset ourselves ready to accept the source thread data - // Paused or running after being stopped causes the current position to - // be reset so we're not interested in passing end of stream signals - - if (OldState == State_Stopped) { - m_bAbort = FALSE; - ClearPendingSample(); - } - return CompleteStateChange(OldState); -} - - -// When we run the filter the things we do are:- - -// Commit the allocator being used in the connection -// Allow a source filter thread to wait in Receive -// Signal the render event just to get us going -// Start the base class by calling StartStreaming -// Allow us to be run when we are not connected -// Signal EC_COMPLETE if we are not connected - -STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime) -{ - CAutoLock cRendererLock(&m_InterfaceLock); - FILTER_STATE OldState = m_State; - - // Make sure there really is a state change - - if (m_State == State_Running) { - return NOERROR; - } - - // Send EC_COMPLETE if we're not connected - - if (m_pInputPin->IsConnected() == FALSE) { - NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); - m_State = State_Running; - return NOERROR; - } - - Ready(); - - // Pause the base filter class - - HRESULT hr = CBaseFilter::Run(StartTime); - if (FAILED(hr)) { - NOTE("Run failed"); - return hr; - } - - // Allow the source thread to wait - ASSERT(m_pInputPin->IsFlushing() == FALSE); - SourceThreadCanWait(TRUE); - SetRepaintStatus(FALSE); - - // There should be no outstanding advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // If we are going into a running state then we must commit whatever - // allocator we are using it so that any source filter can call the - // GetBuffer and expect to get a buffer without returning an error - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Commit(); - } - - // When we come out of a stopped state we must clear any image we were - // holding onto for frame refreshing. Since renderers see state changes - // first we can reset ourselves ready to accept the source thread data - // Paused or running after being stopped causes the current position to - // be reset so we're not interested in passing end of stream signals - - if (OldState == State_Stopped) { - m_bAbort = FALSE; - ClearPendingSample(); - } - return StartStreaming(); -} - - -// Return the number of input pins we support - -int CBaseRenderer::GetPinCount() -{ - if (m_pInputPin == NULL) { - // Try to create it - (void)GetPin(0); - } - return m_pInputPin != NULL ? 1 : 0; -} - - -// We only support one input pin and it is numbered zero - -CBasePin *CBaseRenderer::GetPin(int n) -{ - CAutoLock cObjectCreationLock(&m_ObjectCreationLock); - - // Should only ever be called with zero - ASSERT(n == 0); - - if (n != 0) { - return NULL; - } - - // Create the input pin if not already done so - - if (m_pInputPin == NULL) { - - // hr must be initialized to NOERROR because - // CRendererInputPin's constructor only changes - // hr's value if an error occurs. - HRESULT hr = NOERROR; - - m_pInputPin = new CRendererInputPin(this,&hr,L"In"); - if (NULL == m_pInputPin) { - return NULL; - } - - if (FAILED(hr)) { - delete m_pInputPin; - m_pInputPin = NULL; - return NULL; - } - } - return m_pInputPin; -} - - -// If "In" then return the IPin for our input pin, otherwise NULL and error - -STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - - if (0==lstrcmpW(Id,L"In")) { - *ppPin = GetPin(0); - if (*ppPin) { - (*ppPin)->AddRef(); - } else { - return E_OUTOFMEMORY; - } - } else { - *ppPin = NULL; - return VFW_E_NOT_FOUND; - } - return NOERROR; -} - - -// Called when the input pin receives an EndOfStream notification. If we have -// not got a sample, then notify EC_COMPLETE now. If we have samples, then set -// m_bEOS and check for this on completing samples. If we're waiting to pause -// then complete the transition to paused state by setting the state event - -HRESULT CBaseRenderer::EndOfStream() -{ - // Ignore these calls if we are stopped - - if (m_State == State_Stopped) { - return NOERROR; - } - - // If we have a sample then wait for it to be rendered - - m_bEOS = TRUE; - if (m_pMediaSample) { - return NOERROR; - } - - // If we are waiting for pause then we are now ready since we cannot now - // carry on waiting for a sample to arrive since we are being told there - // won't be any. This sets an event that the GetState function picks up - - Ready(); - - // Only signal completion now if we are running otherwise queue it until - // we do run in StartStreaming. This is used when we seek because a seek - // causes a pause where early notification of completion is misleading - - if (m_bStreaming) { - SendEndOfStream(); - } - return NOERROR; -} - - -// When we are told to flush we should release the source thread - -HRESULT CBaseRenderer::BeginFlush() -{ - // If paused then report state intermediate until we get some data - - if (m_State == State_Paused) { - NotReady(); - } - - SourceThreadCanWait(FALSE); - CancelNotification(); - ClearPendingSample(); - // Wait for Receive to complete - WaitForReceiveToComplete(); - - return NOERROR; -} - - -// After flushing the source thread can wait in Receive again - -HRESULT CBaseRenderer::EndFlush() -{ - // Reset the current sample media time - if (m_pPosition) m_pPosition->ResetMediaTime(); - - // There should be no outstanding advise - - ASSERT(CancelNotification() == S_FALSE); - SourceThreadCanWait(TRUE); - return NOERROR; -} - - -// We can now send EC_REPAINTs if so required - -HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin) -{ - // The caller should always hold the interface lock because - // the function uses CBaseFilter::m_State. - ASSERT(CritCheckIn(&m_InterfaceLock)); - - m_bAbort = FALSE; - - if (State_Running == GetRealState()) { - HRESULT hr = StartStreaming(); - if (FAILED(hr)) { - return hr; - } - - SetRepaintStatus(FALSE); - } else { - SetRepaintStatus(TRUE); - } - - return NOERROR; -} - - -// Called when we go paused or running - -HRESULT CBaseRenderer::Active() -{ - return NOERROR; -} - - -// Called when we go into a stopped state - -HRESULT CBaseRenderer::Inactive() -{ - if (m_pPosition) { - m_pPosition->ResetMediaTime(); - } - // People who derive from this may want to override this behaviour - // to keep hold of the sample in some circumstances - ClearPendingSample(); - - return NOERROR; -} - - -// Tell derived classes about the media type agreed - -HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt) -{ - return NOERROR; -} - - -// When we break the input pin connection we should reset the EOS flags. When -// we are asked for either IMediaPosition or IMediaSeeking we will create a -// CPosPassThru object to handles media time pass through. When we're handed -// samples we store (by calling CPosPassThru::RegisterMediaTime) their media -// times so we can then return a real current position of data being rendered - -HRESULT CBaseRenderer::BreakConnect() -{ - // Do we have a quality management sink - - if (m_pQSink) { - m_pQSink->Release(); - m_pQSink = NULL; - } - - // Check we have a valid connection - - if (m_pInputPin->IsConnected() == FALSE) { - return S_FALSE; - } - - // Check we are stopped before disconnecting - if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) { - return VFW_E_NOT_STOPPED; - } - - SetRepaintStatus(FALSE); - ResetEndOfStream(); - ClearPendingSample(); - m_bAbort = FALSE; - - if (State_Running == m_State) { - StopStreaming(); - } - - return NOERROR; -} - - -// Retrieves the sample times for this samples (note the sample times are -// passed in by reference not value). We return S_FALSE to say schedule this -// sample according to the times on the sample. We also return S_OK in -// which case the object should simply render the sample data immediately - -HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample, - __out REFERENCE_TIME *pStartTime, - __out REFERENCE_TIME *pEndTime) -{ - ASSERT(m_dwAdvise == 0); - ASSERT(pMediaSample); - - // If the stop time for this sample is before or the same as start time, - // then just ignore it (release it) and schedule the next one in line - // Source filters should always fill in the start and end times properly! - - if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) { - if (*pEndTime < *pStartTime) { - return VFW_E_START_TIME_AFTER_END; - } - } else { - // no time set in the sample... draw it now? - return S_OK; - } - - // Can't synchronise without a clock so we return S_OK which tells the - // caller that the sample should be rendered immediately without going - // through the overhead of setting a timer advise link with the clock - - if (m_pClock == NULL) { - return S_OK; - } - return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime); -} - - -// By default all samples are drawn according to their time stamps so we -// return S_FALSE. Returning S_OK means draw immediately, this is used -// by the derived video renderer class in its quality management. - -HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, - __out REFERENCE_TIME *ptrStart, - __out REFERENCE_TIME *ptrEnd) -{ - return S_FALSE; -} - - -// We must always reset the current advise time to zero after a timer fires -// because there are several possible ways which lead us not to do any more -// scheduling such as the pending image being cleared after state changes - -void CBaseRenderer::SignalTimerFired() -{ - m_dwAdvise = 0; -} - - -// Cancel any notification currently scheduled. This is called by the owning -// window object when it is told to stop streaming. If there is no timer link -// outstanding then calling this is benign otherwise we go ahead and cancel -// We must always reset the render event as the quality management code can -// signal immediate rendering by setting the event without setting an advise -// link. If we're subsequently stopped and run the first attempt to setup an -// advise link with the reference clock will find the event still signalled - -HRESULT CBaseRenderer::CancelNotification() -{ - ASSERT(m_dwAdvise == 0 || m_pClock); - DWORD_PTR dwAdvise = m_dwAdvise; - - // Have we a live advise link - - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - SignalTimerFired(); - ASSERT(m_dwAdvise == 0); - } - - // Clear the event and return our status - - m_RenderEvent.Reset(); - return (dwAdvise ? S_OK : S_FALSE); -} - - -// Responsible for setting up one shot advise links with the clock -// Return FALSE if the sample is to be dropped (not drawn at all) -// Return TRUE if the sample is to be drawn and in this case also -// arrange for m_RenderEvent to be set at the appropriate time - -BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample) -{ - REFERENCE_TIME StartSample, EndSample; - - // Is someone pulling our leg - - if (pMediaSample == NULL) { - return FALSE; - } - - // Get the next sample due up for rendering. If there aren't any ready - // then GetNextSampleTimes returns an error. If there is one to be done - // then it succeeds and yields the sample times. If it is due now then - // it returns S_OK other if it's to be done when due it returns S_FALSE - - HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample); - if (FAILED(hr)) { - return FALSE; - } - - // If we don't have a reference clock then we cannot set up the advise - // time so we simply set the event indicating an image to render. This - // will cause us to run flat out without any timing or synchronisation - - if (hr == S_OK) { - EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent)); - return TRUE; - } - - ASSERT(m_dwAdvise == 0); - ASSERT(m_pClock); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - - // We do have a valid reference clock interface so we can ask it to - // set an event when the image comes due for rendering. We pass in - // the reference time we were told to start at and also the current - // stream time which is the offset from the start reference time - - hr = m_pClock->AdviseTime( - (REFERENCE_TIME) m_tStart, // Start run time - StartSample, // Stream time - (HEVENT)(HANDLE) m_RenderEvent, // Render notification - &m_dwAdvise); // Advise cookie - - if (SUCCEEDED(hr)) { - return TRUE; - } - - // We could not schedule the next sample for rendering despite the fact - // we have a valid sample here. This is a fair indication that either - // the system clock is wrong or the time stamp for the sample is duff - - ASSERT(m_dwAdvise == 0); - return FALSE; -} - - -// This is called when a sample comes due for rendering. We pass the sample -// on to the derived class. After rendering we will initialise the timer for -// the next sample, NOTE signal that the last one fired first, if we don't -// do this it thinks there is still one outstanding that hasn't completed - -HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample) -{ - // If the media sample is NULL then we will have been notified by the - // clock that another sample is ready but in the mean time someone has - // stopped us streaming which causes the next sample to be released - - if (pMediaSample == NULL) { - return S_FALSE; - } - - // If we have stopped streaming then don't render any more samples, the - // thread that got in and locked us and then reset this flag does not - // clear the pending sample as we can use it to refresh any output device - - if (m_bStreaming == FALSE) { - return S_FALSE; - } - - // Time how long the rendering takes - - OnRenderStart(pMediaSample); - DoRenderSample(pMediaSample); - OnRenderEnd(pMediaSample); - - return NOERROR; -} - - -// Checks if there is a sample waiting at the renderer - -BOOL CBaseRenderer::HaveCurrentSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - return (m_pMediaSample == NULL ? FALSE : TRUE); -} - - -// Returns the current sample waiting at the video renderer. We AddRef the -// sample before returning so that should it come due for rendering the -// person who called this method will hold the remaining reference count -// that will stop the sample being added back onto the allocator free list - -IMediaSample *CBaseRenderer::GetCurrentSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_pMediaSample) { - m_pMediaSample->AddRef(); - } - return m_pMediaSample; -} - - -// Called when the source delivers us a sample. We go through a few checks to -// make sure the sample can be rendered. If we are running (streaming) then we -// have the sample scheduled with the reference clock, if we are not streaming -// then we have received an sample in paused mode so we can complete any state -// transition. On leaving this function everything will be unlocked so an app -// thread may get in and change our state to stopped (for example) in which -// case it will also signal the thread event so that our wait call is stopped - -HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample) -{ - CAutoLock cInterfaceLock(&m_InterfaceLock); - m_bInReceive = TRUE; - - // Check our flushing and filter state - - // This function must hold the interface lock because it calls - // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses - // CBasePin::m_bRunTimeError. - HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample); - - if (hr != NOERROR) { - m_bInReceive = FALSE; - return E_FAIL; - } - - // Has the type changed on a media sample. We do all rendering - // synchronously on the source thread, which has a side effect - // that only one buffer is ever outstanding. Therefore when we - // have Receive called we can go ahead and change the format - // Since the format change can cause a SendMessage we just don't - // lock - if (m_pInputPin->SampleProps()->pMediaType) { - hr = m_pInputPin->SetMediaType( - (CMediaType *)m_pInputPin->SampleProps()->pMediaType); - if (FAILED(hr)) { - m_bInReceive = FALSE; - return hr; - } - } - - - CAutoLock cSampleLock(&m_RendererLock); - - ASSERT(IsActive() == TRUE); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - ASSERT(m_pInputPin->IsConnected() == TRUE); - ASSERT(m_pMediaSample == NULL); - - // Return an error if we already have a sample waiting for rendering - // source pins must serialise the Receive calls - we also check that - // no data is being sent after the source signalled an end of stream - - if (m_pMediaSample || m_bEOS || m_bAbort) { - Ready(); - m_bInReceive = FALSE; - return E_UNEXPECTED; - } - - // Store the media times from this sample - if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample); - - // Schedule the next sample if we are streaming - - if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) { - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(CancelNotification() == S_FALSE); - m_bInReceive = FALSE; - return VFW_E_SAMPLE_REJECTED; - } - - // Store the sample end time for EC_COMPLETE handling - m_SignalTime = m_pInputPin->SampleProps()->tStop; - - // BEWARE we sometimes keep the sample even after returning the thread to - // the source filter such as when we go into a stopped state (we keep it - // to refresh the device with) so we must AddRef it to keep it safely. If - // we start flushing the source thread is released and any sample waiting - // will be released otherwise GetBuffer may never return (see BeginFlush) - - m_pMediaSample = pMediaSample; - m_pMediaSample->AddRef(); - - if (m_bStreaming == FALSE) { - SetRepaintStatus(TRUE); - } - return NOERROR; -} - - -// Called by the source filter when we have a sample to render. Under normal -// circumstances we set an advise link with the clock, wait for the time to -// arrive and then render the data using the PURE virtual DoRenderSample that -// the derived class will have overriden. After rendering the sample we may -// also signal EOS if it was the last one sent before EndOfStream was called - -HRESULT CBaseRenderer::Receive(IMediaSample *pSample) -{ - ASSERT(pSample); - - // It may return VFW_E_SAMPLE_REJECTED code to say don't bother - - HRESULT hr = PrepareReceive(pSample); - ASSERT(m_bInReceive == SUCCEEDED(hr)); - if (FAILED(hr)) { - if (hr == VFW_E_SAMPLE_REJECTED) { - return NOERROR; - } - return hr; - } - - // We realize the palette in "PrepareRender()" so we have to give away the - // filter lock here. - if (m_State == State_Paused) { - PrepareRender(); - // no need to use InterlockedExchange - m_bInReceive = FALSE; - { - // We must hold both these locks - CAutoLock cRendererLock(&m_InterfaceLock); - if (m_State == State_Stopped) - return NOERROR; - - m_bInReceive = TRUE; - CAutoLock cSampleLock(&m_RendererLock); - OnReceiveFirstSample(pSample); - } - Ready(); - } - // Having set an advise link with the clock we sit and wait. We may be - // awoken by the clock firing or by a state change. The rendering call - // will lock the critical section and check we can still render the data - - hr = WaitForRenderTime(); - if (FAILED(hr)) { - m_bInReceive = FALSE; - return NOERROR; - } - - PrepareRender(); - - // Set this here and poll it until we work out the locking correctly - // It can't be right that the streaming stuff grabs the interface - // lock - after all we want to be able to wait for this stuff - // to complete - m_bInReceive = FALSE; - - // We must hold both these locks - CAutoLock cRendererLock(&m_InterfaceLock); - - // since we gave away the filter wide lock, the sate of the filter could - // have chnaged to Stopped - if (m_State == State_Stopped) - return NOERROR; - - CAutoLock cSampleLock(&m_RendererLock); - - // Deal with this sample - - Render(m_pMediaSample); - ClearPendingSample(); - SendEndOfStream(); - CancelNotification(); - return NOERROR; -} - - -// This is called when we stop or are inactivated to clear the pending sample -// We release the media sample interface so that they can be allocated to the -// source filter again, unless of course we are changing state to inactive in -// which case GetBuffer will return an error. We must also reset the current -// media sample to NULL so that we know we do not currently have an image - -HRESULT CBaseRenderer::ClearPendingSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_pMediaSample) { - m_pMediaSample->Release(); - m_pMediaSample = NULL; - } - return NOERROR; -} - - -// Used to signal end of stream according to the sample end time - -void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier - UINT uMsg, // Not currently used - DWORD_PTR dwUser,// User information - DWORD_PTR dw1, // Windows reserved - DWORD_PTR dw2) // is also reserved -{ - CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser; - NOTE1("EndOfStreamTimer called (%d)",uID); - pRenderer->TimerCallback(); -} - -// Do the timer callback work -void CBaseRenderer::TimerCallback() -{ - // Lock for synchronization (but don't hold this lock when calling - // timeKillEvent) - CAutoLock cRendererLock(&m_RendererLock); - - // See if we should signal end of stream now - - if (m_EndOfStreamTimer) { - m_EndOfStreamTimer = 0; - SendEndOfStream(); - } -} - - -// If we are at the end of the stream signal the filter graph but do not set -// the state flag back to FALSE. Once we drop off the end of the stream we -// leave the flag set (until a subsequent ResetEndOfStream). Each sample we -// get delivered will update m_SignalTime to be the last sample's end time. -// We must wait this long before signalling end of stream to the filtergraph - -#define TIMEOUT_DELIVERYWAIT 50 -#define TIMEOUT_RESOLUTION 10 - -HRESULT CBaseRenderer::SendEndOfStream() -{ - ASSERT(CritCheckIn(&m_RendererLock)); - if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) { - return NOERROR; - } - - // If there is no clock then signal immediately - if (m_pClock == NULL) { - return NotifyEndOfStream(); - } - - // How long into the future is the delivery time - - REFERENCE_TIME Signal = m_tStart + m_SignalTime; - REFERENCE_TIME CurrentTime; - m_pClock->GetTime(&CurrentTime); - LONG Delay = LONG((Signal - CurrentTime) / 10000); - - // Dump the timing information to the debugger - - NOTE1("Delay until end of stream delivery %d",Delay); - NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime)); - NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal)); - - // Wait for the delivery time to arrive - - if (Delay < TIMEOUT_DELIVERYWAIT) { - return NotifyEndOfStream(); - } - - // Signal a timer callback on another worker thread - - m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer - TIMEOUT_RESOLUTION, // Timer resolution - EndOfStreamTimer, // Callback function - DWORD_PTR(this), // Used information - TIME_ONESHOT); // Type of callback - if (m_EndOfStreamTimer == 0) { - return NotifyEndOfStream(); - } - return NOERROR; -} - - -// Signals EC_COMPLETE to the filtergraph manager - -HRESULT CBaseRenderer::NotifyEndOfStream() -{ - CAutoLock cRendererLock(&m_RendererLock); - ASSERT(m_bEOSDelivered == FALSE); - ASSERT(m_EndOfStreamTimer == 0); - - // Has the filter changed state - - if (m_bStreaming == FALSE) { - ASSERT(m_EndOfStreamTimer == 0); - return NOERROR; - } - - // Reset the end of stream timer - m_EndOfStreamTimer = 0; - - // If we've been using the IMediaPosition interface, set it's start - // and end media "times" to the stop position by hand. This ensures - // that we actually get to the end, even if the MPEG guestimate has - // been bad or if the quality management dropped the last few frames - - if (m_pPosition) m_pPosition->EOS(); - m_bEOSDelivered = TRUE; - NOTE("Sending EC_COMPLETE..."); - return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); -} - - -// Reset the end of stream flag, this is typically called when we transfer to -// stopped states since that resets the current position back to the start so -// we will receive more samples or another EndOfStream if there aren't any. We -// keep two separate flags one to say we have run off the end of the stream -// (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE -// to the filter graph. We need the latter otherwise we can end up sending an -// EC_COMPLETE every time the source changes state and calls our EndOfStream - -HRESULT CBaseRenderer::ResetEndOfStream() -{ - ResetEndOfStreamTimer(); - CAutoLock cRendererLock(&m_RendererLock); - - m_bEOS = FALSE; - m_bEOSDelivered = FALSE; - m_SignalTime = 0; - - return NOERROR; -} - - -// Kills any outstanding end of stream timer - -void CBaseRenderer::ResetEndOfStreamTimer() -{ - ASSERT(CritCheckOut(&m_RendererLock)); - if (m_EndOfStreamTimer) { - timeKillEvent(m_EndOfStreamTimer); - m_EndOfStreamTimer = 0; - } -} - - -// This is called when we start running so that we can schedule any pending -// image we have with the clock and display any timing information. If we -// don't have any sample but we have queued an EOS flag then we send it. If -// we do have a sample then we wait until that has been rendered before we -// signal the filter graph otherwise we may change state before it's done - -HRESULT CBaseRenderer::StartStreaming() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_bStreaming == TRUE) { - return NOERROR; - } - - // Reset the streaming times ready for running - - m_bStreaming = TRUE; - - timeBeginPeriod(1); - OnStartStreaming(); - - // There should be no outstanding advise - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(CancelNotification() == S_FALSE); - - // If we have an EOS and no data then deliver it now - - if (m_pMediaSample == NULL) { - return SendEndOfStream(); - } - - // Have the data rendered - - ASSERT(m_pMediaSample); - if (!ScheduleSample(m_pMediaSample)) - m_RenderEvent.Set(); - - return NOERROR; -} - - -// This is called when we stop streaming so that we can set our internal flag -// indicating we are not now to schedule any more samples arriving. The state -// change methods in the filter implementation take care of cancelling any -// clock advise link we have set up and clearing any pending sample we have - -HRESULT CBaseRenderer::StopStreaming() -{ - CAutoLock cRendererLock(&m_RendererLock); - m_bEOSDelivered = FALSE; - - if (m_bStreaming == TRUE) { - m_bStreaming = FALSE; - OnStopStreaming(); - timeEndPeriod(1); - } - return NOERROR; -} - - -// We have a boolean flag that is reset when we have signalled EC_REPAINT to -// the filter graph. We set this when we receive an image so that should any -// conditions arise again we can send another one. By having a flag we ensure -// we don't flood the filter graph with redundant calls. We do not set the -// event when we receive an EndOfStream call since there is no point in us -// sending further EC_REPAINTs. In particular the AutoShowWindow method and -// the DirectDraw object use this method to control the window repainting - -void CBaseRenderer::SetRepaintStatus(BOOL bRepaint) -{ - CAutoLock cSampleLock(&m_RendererLock); - m_bRepaintStatus = bRepaint; -} - - -// Pass the window handle to the upstream filter - -void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd) -{ - IMediaEventSink *pSink; - - // Does the pin support IMediaEventSink - HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink); - if (SUCCEEDED(hr)) { - pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); - pSink->Release(); - } - NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); -} - - -// Signal an EC_REPAINT to the filter graph. This can be used to have data -// sent to us. For example when a video window is first displayed it may -// not have an image to display, at which point it signals EC_REPAINT. The -// filtergraph will either pause the graph if stopped or if already paused -// it will call put_CurrentPosition of the current position. Setting the -// current position to itself has the stream flushed and the image resent - -#define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_))); - -void CBaseRenderer::SendRepaint() -{ - CAutoLock cSampleLock(&m_RendererLock); - ASSERT(m_pInputPin); - - // We should not send repaint notifications when... - // - An end of stream has been notified - // - Our input pin is being flushed - // - The input pin is not connected - // - We have aborted a video playback - // - There is a repaint already sent - - if (m_bAbort == FALSE) { - if (m_pInputPin->IsConnected() == TRUE) { - if (m_pInputPin->IsFlushing() == FALSE) { - if (IsEndOfStream() == FALSE) { - if (m_bRepaintStatus == TRUE) { - IPin *pPin = (IPin *) m_pInputPin; - NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0); - SetRepaintStatus(FALSE); - RLOG("Sending repaint"); - } - } - } - } - } -} - - -// When a video window detects a display change (WM_DISPLAYCHANGE message) it -// can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The -// filtergraph will stop everyone and reconnect our input pin. As we're then -// reconnected we can accept the media type that matches the new display mode -// since we may no longer be able to draw the current image type efficiently - -BOOL CBaseRenderer::OnDisplayChange() -{ - // Ignore if we are not connected yet - - CAutoLock cSampleLock(&m_RendererLock); - if (m_pInputPin->IsConnected() == FALSE) { - return FALSE; - } - - RLOG("Notification of EC_DISPLAY_CHANGE"); - - // Pass our input pin as parameter on the event - - IPin *pPin = (IPin *) m_pInputPin; - m_pInputPin->AddRef(); - NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0); - SetAbortSignal(TRUE); - ClearPendingSample(); - m_pInputPin->Release(); - - return TRUE; -} - - -// Called just before we start drawing. -// Store the current time in m_trRenderStart to allow the rendering time to be -// logged. Log the time stamp of the sample and how late it is (neg is early) - -void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample) -{ -#ifdef PERF - REFERENCE_TIME trStart, trEnd; - pMediaSample->GetTime(&trStart, &trEnd); - - MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits - - m_pClock->GetTime(&m_trRenderStart); - MSR_INTEGER(0, (int)m_trRenderStart); - REFERENCE_TIME trStream; - trStream = m_trRenderStart-m_tStart; // convert reftime to stream time - MSR_INTEGER(0,(int)trStream); - - const int trLate = (int)(trStream - trStart); - MSR_INTEGER(m_idBaseAccuracy, trLate/10000); // dump in mSec -#endif - -} // OnRenderStart - - -// Called directly after drawing an image. -// calculate the time spent drawing and log it. - -void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample) -{ -#ifdef PERF - REFERENCE_TIME trNow; - m_pClock->GetTime(&trNow); - MSR_INTEGER(0,(int)trNow); - int t = (int)((trNow - m_trRenderStart)/10000); // convert UNITS->msec - MSR_INTEGER(m_idBaseRenderTime, t); -#endif -} // OnRenderEnd - - - - -// Constructor must be passed the base renderer object - -CRendererInputPin::CRendererInputPin(__inout CBaseRenderer *pRenderer, - __inout HRESULT *phr, - __in_opt LPCWSTR pPinName) : - CBaseInputPin(NAME("Renderer pin"), - pRenderer, - &pRenderer->m_InterfaceLock, - (HRESULT *) phr, - pPinName) -{ - m_pRenderer = pRenderer; - ASSERT(m_pRenderer); -} - - -// Signals end of data stream on the input pin - -STDMETHODIMP CRendererInputPin::EndOfStream() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - - // Make sure we're streaming ok - - HRESULT hr = CheckStreaming(); - if (hr != NOERROR) { - return hr; - } - - // Pass it onto the renderer - - hr = m_pRenderer->EndOfStream(); - if (SUCCEEDED(hr)) { - hr = CBaseInputPin::EndOfStream(); - } - return hr; -} - - -// Signals start of flushing on the input pin - we do the final reset end of -// stream with the renderer lock unlocked but with the interface lock locked -// We must do this because we call timeKillEvent, our timer callback method -// has to take the renderer lock to serialise our state. Therefore holding a -// renderer lock when calling timeKillEvent could cause a deadlock condition - -STDMETHODIMP CRendererInputPin::BeginFlush() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - { - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - CBaseInputPin::BeginFlush(); - m_pRenderer->BeginFlush(); - } - return m_pRenderer->ResetEndOfStream(); -} - - -// Signals end of flushing on the input pin - -STDMETHODIMP CRendererInputPin::EndFlush() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - - HRESULT hr = m_pRenderer->EndFlush(); - if (SUCCEEDED(hr)) { - hr = CBaseInputPin::EndFlush(); - } - return hr; -} - - -// Pass the sample straight through to the renderer object - -STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample) -{ - HRESULT hr = m_pRenderer->Receive(pSample); - if (FAILED(hr)) { - - // A deadlock could occur if the caller holds the renderer lock and - // attempts to acquire the interface lock. - ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock)); - - { - // The interface lock must be held when the filter is calling - // IsStopped() or IsFlushing(). The interface lock must also - // be held because the function uses m_bRunTimeError. - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - - // We do not report errors which occur while the filter is stopping, - // flushing or if the m_bAbort flag is set . Errors are expected to - // occur during these operations and the streaming thread correctly - // handles the errors. - if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) { - - // EC_ERRORABORT's first parameter is the error which caused - // the event and its' last parameter is 0. See the Direct - // Show SDK documentation for more information. - m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0); - - { - CAutoLock alRendererLock(&m_pRenderer->m_RendererLock); - if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) { - m_pRenderer->NotifyEndOfStream(); - } - } - - m_bRunTimeError = TRUE; - } - } - } - - return hr; -} - - -// Called when the input pin is disconnected - -HRESULT CRendererInputPin::BreakConnect() -{ - HRESULT hr = m_pRenderer->BreakConnect(); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::BreakConnect(); -} - - -// Called when the input pin is connected - -HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CompleteConnect(pReceivePin); -} - - -// Give the pin id of our one and only pin - -STDMETHODIMP CRendererInputPin::QueryId(__deref_out LPWSTR *Id) -{ - CheckPointer(Id,E_POINTER); - - const WCHAR szIn[] = L"In"; - - *Id = (LPWSTR)CoTaskMemAlloc(sizeof(szIn)); - if (*Id == NULL) { - return E_OUTOFMEMORY; - } - CopyMemory(*Id, szIn, sizeof(szIn)); - return NOERROR; -} - - -// Will the filter accept this media type - -HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt) -{ - return m_pRenderer->CheckMediaType(pmt); -} - - -// Called when we go paused or running - -HRESULT CRendererInputPin::Active() -{ - return m_pRenderer->Active(); -} - - -// Called when we go into a stopped state - -HRESULT CRendererInputPin::Inactive() -{ - // The caller must hold the interface lock because - // this function uses m_bRunTimeError. - ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock)); - - m_bRunTimeError = FALSE; - - return m_pRenderer->Inactive(); -} - - -// Tell derived classes about the media type agreed - -HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt) -{ - HRESULT hr = CBaseInputPin::SetMediaType(pmt); - if (FAILED(hr)) { - return hr; - } - return m_pRenderer->SetMediaType(pmt); -} - - -// We do not keep an event object to use when setting up a timer link with -// the clock but are given a pointer to one by the owning object through the -// SetNotificationObject method - this must be initialised before starting -// We can override the default quality management process to have it always -// draw late frames, this is currently done by having the following registry -// key (actually an INI key) called DrawLateFrames set to 1 (default is 0) - -const TCHAR AMQUALITY[] = TEXT("ActiveMovie"); -const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames"); - -CBaseVideoRenderer::CBaseVideoRenderer( - REFCLSID RenderClass, // CLSID for this renderer - __in_opt LPCTSTR pName, // Debug ONLY description - __inout_opt LPUNKNOWN pUnk, // Aggregated owner object - __inout HRESULT *phr) : // General OLE return code - - CBaseRenderer(RenderClass,pName,pUnk,phr), - m_cFramesDropped(0), - m_cFramesDrawn(0), - m_bSupplierHandlingQuality(FALSE) -{ - ResetStreamingTimes(); - -#ifdef PERF - m_idTimeStamp = MSR_REGISTER(TEXT("Frame time stamp")); - m_idEarliness = MSR_REGISTER(TEXT("Earliness fudge")); - m_idTarget = MSR_REGISTER(TEXT("Target (mSec)")); - m_idSchLateTime = MSR_REGISTER(TEXT("mSec late when scheduled")); - m_idDecision = MSR_REGISTER(TEXT("Scheduler decision code")); - m_idQualityRate = MSR_REGISTER(TEXT("Quality rate sent")); - m_idQualityTime = MSR_REGISTER(TEXT("Quality time sent")); - m_idWaitReal = MSR_REGISTER(TEXT("Render wait")); - // m_idWait = MSR_REGISTER(TEXT("wait time recorded (msec)")); - m_idFrameAccuracy = MSR_REGISTER(TEXT("Frame accuracy (msecs)")); - m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE); - //m_idSendQuality = MSR_REGISTER(TEXT("Processing Quality message")); - - m_idRenderAvg = MSR_REGISTER(TEXT("Render draw time Avg")); - m_idFrameAvg = MSR_REGISTER(TEXT("FrameAvg")); - m_idWaitAvg = MSR_REGISTER(TEXT("WaitAvg")); - m_idDuration = MSR_REGISTER(TEXT("Duration")); - m_idThrottle = MSR_REGISTER(TEXT("Audio-video throttle wait")); - // m_idDebug = MSR_REGISTER(TEXT("Debug stuff")); -#endif // PERF -} // Constructor - - -// Destructor is just a placeholder - -CBaseVideoRenderer::~CBaseVideoRenderer() -{ - ASSERT(m_dwAdvise == 0); -} - - -// The timing functions in this class are called by the window object and by -// the renderer's allocator. -// The windows object calls timing functions as it receives media sample -// images for drawing using GDI. -// The allocator calls timing functions when it starts passing DCI/DirectDraw -// surfaces which are not rendered in the same way; The decompressor writes -// directly to the surface with no separate rendering, so those code paths -// call direct into us. Since we only ever hand out DCI/DirectDraw surfaces -// when we have allocated one and only one image we know there cannot be any -// conflict between the two. -// -// We use timeGetTime to return the timing counts we use (since it's relative -// performance we are interested in rather than absolute compared to a clock) -// The window object sets the accuracy of the system clock (normally 1ms) by -// calling timeBeginPeriod/timeEndPeriod when it changes streaming states - - -// Reset all times controlling streaming. -// Set them so that -// 1. Frames will not initially be dropped -// 2. The first frame will definitely be drawn (achieved by saying that there -// has not ben a frame drawn for a long time). - -HRESULT CBaseVideoRenderer::ResetStreamingTimes() -{ - m_trLastDraw = -1000; // set up as first frame since ages (1 sec) ago - m_tStreamingStart = timeGetTime(); - m_trRenderAvg = 0; - m_trFrameAvg = -1; // -1000 fps == "unset" - m_trDuration = 0; // 0 - strange value - m_trRenderLast = 0; - m_trWaitAvg = 0; - m_tRenderStart = 0; - m_cFramesDrawn = 0; - m_cFramesDropped = 0; - m_iTotAcc = 0; - m_iSumSqAcc = 0; - m_iSumSqFrameTime = 0; - m_trFrame = 0; // hygeine - not really needed - m_trLate = 0; // hygeine - not really needed - m_iSumFrameTime = 0; - m_nNormal = 0; - m_trEarliness = 0; - m_trTarget = -300000; // 30mSec early - m_trThrottle = 0; - m_trRememberStampForPerf = 0; - -#ifdef PERF - m_trRememberFrameForPerf = 0; -#endif - - return NOERROR; -} // ResetStreamingTimes - - -// Reset all times controlling streaming. Note that we're now streaming. We -// don't need to set the rendering event to have the source filter released -// as it is done during the Run processing. When we are run we immediately -// release the source filter thread and draw any image waiting (that image -// may already have been drawn once as a poster frame while we were paused) - -HRESULT CBaseVideoRenderer::OnStartStreaming() -{ - ResetStreamingTimes(); - return NOERROR; -} // OnStartStreaming - - -// Called at end of streaming. Fixes times for property page report - -HRESULT CBaseVideoRenderer::OnStopStreaming() -{ - m_tStreamingStart = timeGetTime()-m_tStreamingStart; - return NOERROR; -} // OnStopStreaming - - -// Called when we start waiting for a rendering event. -// Used to update times spent waiting and not waiting. - -void CBaseVideoRenderer::OnWaitStart() -{ - MSR_START(m_idWaitReal); -} // OnWaitStart - - -// Called when we are awoken from the wait in the window OR by our allocator -// when it is hanging around until the next sample is due for rendering on a -// DCI/DirectDraw surface. We add the wait time into our rolling average. -// We grab the interface lock so that we're serialised with the application -// thread going through the run code - which in due course ends up calling -// ResetStreaming times - possibly as we run through this section of code - -void CBaseVideoRenderer::OnWaitEnd() -{ -#ifdef PERF - MSR_STOP(m_idWaitReal); - // for a perf build we want to know just exactly how late we REALLY are. - // even if this means that we have to look at the clock again. - - REFERENCE_TIME trRealStream; // the real time now expressed as stream time. -#if 0 - m_pClock->GetTime(&trRealStream); // Calling clock here causes W95 deadlock! -#else - // We will be discarding overflows like mad here! - // This is wrong really because timeGetTime() can wrap but it's - // only for PERF - REFERENCE_TIME tr = timeGetTime()*10000; - trRealStream = tr + m_llTimeOffset; -#endif - trRealStream -= m_tStart; // convert to stream time (this is a reftime) - - if (m_trRememberStampForPerf==0) { - // This is probably the poster frame at the start, and it is not scheduled - // in the usual way at all. Just count it. The rememberstamp gets set - // in ShouldDrawSampleNow, so this does invalid frame recording until we - // actually start playing. - PreparePerformanceData(0, 0); - } else { - int trLate = (int)(trRealStream - m_trRememberStampForPerf); - int trFrame = (int)(tr - m_trRememberFrameForPerf); - PreparePerformanceData(trLate, trFrame); - } - m_trRememberFrameForPerf = tr; -#endif //PERF -} // OnWaitEnd - - -// Put data on one side that describes the lateness of the current frame. -// We don't yet know whether it will actually be drawn. In direct draw mode, -// this decision is up to the filter upstream, and it could change its mind. -// The rules say that if it did draw it must call Receive(). One way or -// another we eventually get into either OnRenderStart or OnDirectRender and -// these both call RecordFrameLateness to update the statistics. - -void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame) -{ - m_trLate = trLate; - m_trFrame = trFrame; -} // PreparePerformanceData - - -// update the statistics: -// m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn -// Note that because the properties page reports using these variables, -// 1. We need to be inside a critical section -// 2. They must all be updated together. Updating the sums here and the count -// elsewhere can result in imaginary jitter (i.e. attempts to find square roots -// of negative numbers) in the property page code. - -void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame) -{ - // Record how timely we are. - int tLate = trLate/10000; - - // Best estimate of moment of appearing on the screen is average of - // start and end draw times. Here we have only the end time. This may - // tend to show us as spuriously late by up to 1/2 frame rate achieved. - // Decoder probably monitors draw time. We don't bother. - MSR_INTEGER( m_idFrameAccuracy, tLate ); - - // This is a kludge - we can get frames that are very late - // especially (at start-up) and they invalidate the statistics. - // So ignore things that are more than 1 sec off. - if (tLate>1000 || tLate<-1000) { - if (m_cFramesDrawn<=1) { - tLate = 0; - } else if (tLate>0) { - tLate = 1000; - } else { - tLate = -1000; - } - } - // The very first frame often has a invalid time, so don't - // count it into the statistics. (???) - if (m_cFramesDrawn>1) { - m_iTotAcc += tLate; - m_iSumSqAcc += (tLate*tLate); - } - - // calculate inter-frame time. Doesn't make sense for first frame - // second frame suffers from invalid first frame stamp. - if (m_cFramesDrawn>2) { - int tFrame = trFrame/10000; // convert to mSec else it overflows - - // This is a kludge. It can overflow anyway (a pause can cause - // a very long inter-frame time) and it overflows at 2**31/10**7 - // or about 215 seconds i.e. 3min 35sec - if (tFrame>1000||tFrame<0) tFrame = 1000; - m_iSumSqFrameTime += tFrame*tFrame; - ASSERT(m_iSumSqFrameTime>=0); - m_iSumFrameTime += tFrame; - } - ++m_cFramesDrawn; - -} // RecordFrameLateness - - -void CBaseVideoRenderer::ThrottleWait() -{ - if (m_trThrottle>0) { - int iThrottle = m_trThrottle/10000; // convert to mSec - MSR_INTEGER( m_idThrottle, iThrottle); - DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle)); - Sleep(iThrottle); - } else { - Sleep(0); - } -} // ThrottleWait - - -// Whenever a frame is rendered it goes though either OnRenderStart -// or OnDirectRender. Data that are generated during ShouldDrawSample -// are added to the statistics by calling RecordFrameLateness from both -// these two places. - -// Called in place of OnRenderStart..OnRenderEnd -// When a DirectDraw image is drawn -void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample) -{ - m_trRenderAvg = 0; - m_trRenderLast = 5000000; // If we mode switch, we do NOT want this - // to inhibit the new average getting going! - // so we set it to half a second - // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); - RecordFrameLateness(m_trLate, m_trFrame); - ThrottleWait(); -} // OnDirectRender - - -// Called just before we start drawing. All we do is to get the current clock -// time (from the system) and return. We have to store the start render time -// in a member variable because it isn't used until we complete the drawing -// The rest is just performance logging. - -void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample) -{ - RecordFrameLateness(m_trLate, m_trFrame); - m_tRenderStart = timeGetTime(); -} // OnRenderStart - - -// Called directly after drawing an image. We calculate the time spent in the -// drawing code and if this doesn't appear to have any odd looking spikes in -// it then we add it to the current average draw time. Measurement spikes may -// occur if the drawing thread is interrupted and switched to somewhere else. - -void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample) -{ - // The renderer time can vary erratically if we are interrupted so we do - // some smoothing to help get more sensible figures out but even that is - // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83 - - int tr = (timeGetTime() - m_tRenderStart)*10000; // convert mSec->UNITS - if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) { - // DO_MOVING_AVG(m_trRenderAvg, tr); - m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD; - } - m_trRenderLast = tr; - ThrottleWait(); -} // OnRenderEnd - - -STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc) -{ - - m_pQSink = piqc; - - return NOERROR; -} // SetSink - - -STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q) -{ - // NOTE: We are NOT getting any locks here. We could be called - // asynchronously and possibly even on a time critical thread of - // someone else's - so we do the minumum. We only set one state - // variable (an integer) and if that happens to be in the middle - // of another thread reading it they will just get either the new - // or the old value. Locking would achieve no more than this. - - // It might be nice to check that we are being called from m_pGraph, but - // it turns out to be a millisecond or so per throw! - - // This is heuristics, these numbers are aimed at being "what works" - // rather than anything based on some theory. - // We use a hyperbola because it's easy to calculate and it includes - // a panic button asymptote (which we push off just to the left) - // The throttling fits the following table (roughly) - // Proportion Throttle (msec) - // >=1000 0 - // 900 3 - // 800 7 - // 700 11 - // 600 17 - // 500 25 - // 400 35 - // 300 50 - // 200 72 - // 125 100 - // 100 112 - // 50 146 - // 0 200 - - // (some evidence that we could go for a sharper kink - e.g. no throttling - // until below the 750 mark - might give fractionally more frames on a - // P60-ish machine). The easy way to get these coefficients is to use - // Renbase.xls follow the instructions therein using excel solver. - - if (q.Proportion>=1000) { m_trThrottle = 0; } - else { - // The DWORD is to make quite sure I get unsigned arithmetic - // as the constant is between 2**31 and 2**32 - m_trThrottle = -330000 + (388880000/(q.Proportion+167)); - } - return NOERROR; -} // Notify - - -// Send a message to indicate what our supplier should do about quality. -// Theory: -// What a supplier wants to know is "is the frame I'm working on NOW -// going to be late?". -// F1 is the frame at the supplier (as above) -// Tf1 is the due time for F1 -// T1 is the time at that point (NOW!) -// Tr1 is the time that f1 WILL actually be rendered -// L1 is the latency of the graph for frame F1 = Tr1-T1 -// D1 (for delay) is how late F1 will be beyond its due time i.e. -// D1 = (Tr1-Tf1) which is what the supplier really wants to know. -// Unfortunately Tr1 is in the future and is unknown, so is L1 -// -// We could estimate L1 by its value for a previous frame, -// L0 = Tr0-T0 and work off -// D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1) -// Rearranging terms: -// D1' = (T1-T0) + (Tr0-Tf1) -// adding (Tf0-Tf0) and rearranging again: -// = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1) -// = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0) -// But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the -// Late field in the quality message that we send. -// The other two terms just state what correction should be applied before -// using the lateness of F0 to predict the lateness of F1. -// (T1-T0) says how much time has actually passed (we have lost this much) -// (Tf1-Tf0) says how much time should have passed if we were keeping pace -// (we have gained this much). -// -// Suppliers should therefore work off: -// Quality.Late + (T1-T0) - (Tf1-Tf0) -// and see if this is "acceptably late" or even early (i.e. negative). -// They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from -// the time stamps in the frames. They get Quality.Late from us. -// - -HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate, - REFERENCE_TIME trRealStream) -{ - Quality q; - HRESULT hr; - - // If we are the main user of time, then report this as Flood/Dry. - // If our suppliers are, then report it as Famine/Glut. - // - // We need to take action, but avoid hunting. Hunting is caused by - // 1. Taking too much action too soon and overshooting - // 2. Taking too long to react (so averaging can CAUSE hunting). - // - // The reason why we use trLate as well as Wait is to reduce hunting; - // if the wait time is coming down and about to go into the red, we do - // NOT want to rely on some average which is only telling is that it used - // to be OK once. - - q.TimeStamp = (REFERENCE_TIME)trRealStream; - - if (m_trFrameAvg<0) { - q.Type = Famine; // guess - } - // Is the greater part of the time taken bltting or something else - else if (m_trFrameAvg > 2*m_trRenderAvg) { - q.Type = Famine; // mainly other - } else { - q.Type = Flood; // mainly bltting - } - - q.Proportion = 1000; // default - - if (m_trFrameAvg<0) { - // leave it alone - we don't know enough - } - else if ( trLate> 0 ) { - // try to catch up over the next second - // We could be Really, REALLY late, but rendering all the frames - // anyway, just because it's so cheap. - - q.Proportion = 1000 - (int)((trLate)/(UNITS/1000)); - if (q.Proportion<500) { - q.Proportion = 500; // don't go daft. (could've been negative!) - } else { - } - - } else if ( m_trWaitAvg>20000 - && trLate<-20000 - ){ - // Go cautiously faster - aim at 2mSec wait. - if (m_trWaitAvg>=m_trFrameAvg) { - // This can happen because of some fudges. - // The waitAvg is how long we originally planned to wait - // The frameAvg is more honest. - // It means that we are spending a LOT of time waiting - q.Proportion = 2000; // double. - } else { - if (m_trFrameAvg+20000 > m_trWaitAvg) { - q.Proportion - = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg)); - } else { - // We're apparently spending more than the whole frame time waiting. - // Assume that the averages are slightly out of kilter, but that we - // are indeed doing a lot of waiting. (This leg probably never - // happens, but the code avoids any potential divide by zero). - q.Proportion = 2000; - } - } - - if (q.Proportion>2000) { - q.Proportion = 2000; // don't go crazy. - } - } - - // Tell the supplier how late frames are when they get rendered - // That's how late we are now. - // If we are in directdraw mode then the guy upstream can see the drawing - // times and we'll just report on the start time. He can figure out any - // offset to apply. If we are in DIB Section mode then we will apply an - // extra offset which is half of our drawing time. This is usually small - // but can sometimes be the dominant effect. For this we will use the - // average drawing time rather than the last frame. If the last frame took - // a long time to draw and made us late, that's already in the lateness - // figure. We should not add it in again unless we expect the next frame - // to be the same. We don't, we expect the average to be a better shot. - // In direct draw mode the RenderAvg will be zero. - - q.Late = trLate + m_trRenderAvg/2; - - // log what we're doing - MSR_INTEGER(m_idQualityRate, q.Proportion); - MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 ); - - // A specific sink interface may be set through IPin - - if (m_pQSink==NULL) { - // Get our input pin's peer. We send quality management messages - // to any nominated receiver of these things (set in the IPin - // interface), or else to our source filter. - - IQualityControl *pQC = NULL; - IPin *pOutputPin = m_pInputPin->GetConnected(); - ASSERT(pOutputPin != NULL); - - // And get an AddRef'd quality control interface - - hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC); - if (SUCCEEDED(hr)) { - m_pQSink = pQC; - } - } - if (m_pQSink) { - return m_pQSink->Notify(this,q); - } - - return S_FALSE; - -} // SendQuality - - -// We are called with a valid IMediaSample image to decide whether this is to -// be drawn or not. There must be a reference clock in operation. -// Return S_OK if it is to be drawn Now (as soon as possible) -// Return S_FALSE if it is to be drawn when it's due -// Return an error if we want to drop it -// m_nNormal=-1 indicates that we dropped the previous frame and so this -// one should be drawn early. Respect it and update it. -// Use current stream time plus a number of heuristics (detailed below) -// to make the decision - -HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, - __inout REFERENCE_TIME *ptrStart, - __inout REFERENCE_TIME *ptrEnd) -{ - - // Don't call us unless there's a clock interface to synchronise with - ASSERT(m_pClock); - - MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32)); // high order 32 bits - MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart)); // low order 32 bits - - // We lose a bit of time depending on the monitor type waiting for the next - // screen refresh. On average this might be about 8mSec - so it will be - // later than we think when the picture appears. To compensate a bit - // we bias the media samples by -8mSec i.e. 80000 UNITs. - // We don't ever make a stream time negative (call it paranoia) - if (*ptrStart>=80000) { - *ptrStart -= 80000; - *ptrEnd -= 80000; // bias stop to to retain valid frame duration - } - - // Cache the time stamp now. We will want to compare what we did with what - // we started with (after making the monitor allowance). - m_trRememberStampForPerf = *ptrStart; - - // Get reference times (current and late) - REFERENCE_TIME trRealStream; // the real time now expressed as stream time. - m_pClock->GetTime(&trRealStream); -#ifdef PERF - // While the reference clock is expensive: - // Remember the offset from timeGetTime and use that. - // This overflows all over the place, but when we subtract to get - // differences the overflows all cancel out. - m_llTimeOffset = trRealStream-timeGetTime()*10000; -#endif - trRealStream -= m_tStart; // convert to stream time (this is a reftime) - - // We have to wory about two versions of "lateness". The truth, which we - // try to work out here and the one measured against m_trTarget which - // includes long term feedback. We report statistics against the truth - // but for operational decisions we work to the target. - // We use TimeDiff to make sure we get an integer because we - // may actually be late (or more likely early if there is a big time - // gap) by a very long time. - const int trTrueLate = TimeDiff(trRealStream - *ptrStart); - const int trLate = trTrueLate; - - MSR_INTEGER(m_idSchLateTime, trTrueLate/10000); - - // Send quality control messages upstream, measured against target - HRESULT hr = SendQuality(trLate, trRealStream); - // Note: the filter upstream is allowed to this FAIL meaning "you do it". - m_bSupplierHandlingQuality = (hr==S_OK); - - // Decision time! Do we drop, draw when ready or draw immediately? - - const int trDuration = (int)(*ptrEnd - *ptrStart); - { - // We need to see if the frame rate of the file has just changed. - // This would make comparing our previous frame rate with the current - // frame rate inefficent. Hang on a moment though. I've seen files - // where the frames vary between 33 and 34 mSec so as to average - // 30fps. A minor variation like that won't hurt us. - int t = m_trDuration/32; - if ( trDuration > m_trDuration+t - || trDuration < m_trDuration-t - ) { - // There's a major variation. Reset the average frame rate to - // exactly the current rate to disable decision 9002 for this frame, - // and remember the new rate. - m_trFrameAvg = trDuration; - m_trDuration = trDuration; - } - } - - MSR_INTEGER(m_idEarliness, m_trEarliness/10000); - MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); - MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000); - MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000); - MSR_INTEGER(m_idDuration, trDuration/10000); - -#ifdef PERF - if (S_OK==pMediaSample->IsDiscontinuity()) { - MSR_INTEGER(m_idDecision, 9000); - } -#endif - - // Control the graceful slide back from slow to fast machine mode. - // After a frame drop accept an early frame and set the earliness to here - // If this frame is already later than the earliness then slide it to here - // otherwise do the standard slide (reduce by about 12% per frame). - // Note: earliness is normally NEGATIVE - BOOL bJustDroppedFrame - = ( m_bSupplierHandlingQuality - // Can't use the pin sample properties because we might - // not be in Receive when we call this - && (S_OK == pMediaSample->IsDiscontinuity()) // he just dropped one - ) - || (m_nNormal==-1); // we just dropped one - - - // Set m_trEarliness (slide back from slow to fast machine mode) - if (trLate>0) { - m_trEarliness = 0; // we are no longer in fast machine mode at all! - } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) { - m_trEarliness = trLate; // Things have slipped of their own accord - } else { - m_trEarliness = m_trEarliness - m_trEarliness/8; // graceful slide - } - - // prepare the new wait average - but don't pollute the old one until - // we have finished with it. - int trWaitAvg; - { - // We never mix in a negative wait. This causes us to believe in fast machines - // slightly more. - int trL = trLate<0 ? -trLate : 0; - trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; - } - - - int trFrame; - { - REFERENCE_TIME tr = trRealStream - m_trLastDraw; // Cd be large - 4 min pause! - if (tr>10000000) { - tr = 10000000; // 1 second - arbitrarily. - } - trFrame = int(tr); - } - - // We will DRAW this frame IF... - if ( - // ...the time we are spending drawing is a small fraction of the total - // observed inter-frame time so that dropping it won't help much. - (3*m_trRenderAvg <= m_trFrameAvg) - - // ...or our supplier is NOT handling things and the next frame would - // be less timely than this one or our supplier CLAIMS to be handling - // things, and is now less than a full FOUR frames late. - || ( m_bSupplierHandlingQuality - ? (trLate <= trDuration*4) - : (trLate+trLate < trDuration) - ) - - // ...or we are on average waiting for over eight milliseconds then - // this may be just a glitch. Draw it and we'll hope to catch up. - || (m_trWaitAvg > 80000) - - // ...or we haven't drawn an image for over a second. We will update - // the display, which stops the video looking hung. - // Do this regardless of how late this media sample is. - || ((trRealStream - m_trLastDraw) > UNITS) - - ) { - HRESULT Result; - - // We are going to play this frame. We may want to play it early. - // We will play it early if we think we are in slow machine mode. - // If we think we are NOT in slow machine mode, we will still play - // it early by m_trEarliness as this controls the graceful slide back. - // and in addition we aim at being m_trTarget late rather than "on time". - - BOOL bPlayASAP = FALSE; - - // we will play it AT ONCE (slow machine mode) if... - - // ...we are playing catch-up - if ( bJustDroppedFrame) { - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9001); - } - - // ...or if we are running below the true frame rate - // exact comparisons are glitchy, for these measurements, - // so add an extra 5% or so - else if ( (m_trFrameAvg > trDuration + trDuration/16) - - // It's possible to get into a state where we are losing ground, but - // are a very long way ahead. To avoid this or recover from it - // we refuse to play early by more than 10 frames. - && (trLate > - trDuration*10) - ){ - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9002); - } -#if 0 - // ...or if we have been late and are less than one frame early - else if ( (trLate + trDuration > 0) - && (m_trWaitAvg<=20000) - ) { - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9003); - } -#endif - // We will NOT play it at once if we are grossly early. On very slow frame - // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just - // because we got starved (for instance by the net) and dropped one frame - // some time or other. If we are more than 900mSec early, then wait. - if (trLate<-9000000) { - bPlayASAP = FALSE; - } - - if (bPlayASAP) { - - m_nNormal = 0; - MSR_INTEGER(m_idDecision, 0); - // When we are here, we are in slow-machine mode. trLate may well - // oscillate between negative and positive when the supplier is - // dropping frames to keep sync. We should not let that mislead - // us into thinking that we have as much as zero spare time! - // We just update with a zero wait. - m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; - - // Assume that we draw it immediately. Update inter-frame stats - m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD; -#ifndef PERF - // If this is NOT a perf build, then report what we know so far - // without looking at the clock any more. This assumes that we - // actually wait for exactly the time we hope to. It also reports - // how close we get to the manipulated time stamps that we now have - // rather than the ones we originally started with. It will - // therefore be a little optimistic. However it's fast. - PreparePerformanceData(trTrueLate, trFrame); -#endif - m_trLastDraw = trRealStream; - if (m_trEarliness > trLate) { - m_trEarliness = trLate; // if we are actually early, this is neg - } - Result = S_OK; // Draw it now - - } else { - ++m_nNormal; - // Set the average frame rate to EXACTLY the ideal rate. - // If we are exiting slow-machine mode then we will have caught up - // and be running ahead, so as we slide back to exact timing we will - // have a longer than usual gap at this point. If we record this - // real gap then we'll think that we're running slow and go back - // into slow-machine mode and vever get it straight. - m_trFrameAvg = trDuration; - MSR_INTEGER(m_idDecision, 1); - - // Play it early by m_trEarliness and by m_trTarget - - { - int trE = m_trEarliness; - if (trE < -m_trFrameAvg) { - trE = -m_trFrameAvg; - } - *ptrStart += trE; // N.B. earliness is negative - } - - int Delay = -trTrueLate; - Result = Delay<=0 ? S_OK : S_FALSE; // OK = draw now, FALSE = wait - - m_trWaitAvg = trWaitAvg; - - // Predict when it will actually be drawn and update frame stats - - if (Result==S_FALSE) { // We are going to wait - trFrame = TimeDiff(*ptrStart-m_trLastDraw); - m_trLastDraw = *ptrStart; - } else { - // trFrame is already = trRealStream-m_trLastDraw; - m_trLastDraw = trRealStream; - } -#ifndef PERF - int iAccuracy; - if (Delay>0) { - // Report lateness based on when we intend to play it - iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf); - } else { - // Report lateness based on playing it *now*. - iAccuracy = trTrueLate; // trRealStream-RememberStampForPerf; - } - PreparePerformanceData(iAccuracy, trFrame); -#endif - } - return Result; - } - - // We are going to drop this frame! - // Of course in DirectDraw mode the guy upstream may draw it anyway. - - // This will probably give a large negative wack to the wait avg. - m_trWaitAvg = trWaitAvg; - -#ifdef PERF - // Respect registry setting - debug only! - if (m_bDrawLateFrames) { - return S_OK; // draw it when it's ready - } // even though it's late. -#endif - - // We are going to drop this frame so draw the next one early - // n.b. if the supplier is doing direct draw then he may draw it anyway - // but he's doing something funny to arrive here in that case. - - MSR_INTEGER(m_idDecision, 2); - m_nNormal = -1; - return E_FAIL; // drop it - -} // ShouldDrawSampleNow - - -// NOTE we're called by both the window thread and the source filter thread -// so we have to be protected by a critical section (locked before called) -// Also, when the window thread gets signalled to render an image, it always -// does so regardless of how late it is. All the degradation is done when we -// are scheduling the next sample to be drawn. Hence when we start an advise -// link to draw a sample, that sample's time will always become the last one -// drawn - unless of course we stop streaming in which case we cancel links - -BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample) -{ - // We override ShouldDrawSampleNow to add quality management - - BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample); - if (bDrawImage == FALSE) { - ++m_cFramesDropped; - return FALSE; - } - - // m_cFramesDrawn must NOT be updated here. It has to be updated - // in RecordFrameLateness at the same time as the other statistics. - return TRUE; -} - - -// Implementation of IQualProp interface needed to support the property page -// This is how the property page gets the data out of the scheduler. We are -// passed into the constructor the owning object in the COM sense, this will -// either be the video renderer or an external IUnknown if we're aggregated. -// We initialise our CUnknown base class with this interface pointer. Then -// all we have to do is to override NonDelegatingQueryInterface to expose -// our IQualProp interface. The AddRef and Release are handled automatically -// by the base class and will be passed on to the appropriate outer object - -STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(__out int *pcFramesDropped) -{ - CheckPointer(pcFramesDropped,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - *pcFramesDropped = m_cFramesDropped; - return NOERROR; -} // get_FramesDroppedInRenderer - - -// Set *pcFramesDrawn to the number of frames drawn since -// streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn) -{ - CheckPointer(pcFramesDrawn,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - *pcFramesDrawn = m_cFramesDrawn; - return NOERROR; -} // get_FramesDrawn - - -// Set iAvgFrameRate to the frames per hundred secs since -// streaming started. 0 otherwise. - -STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate) -{ - CheckPointer(piAvgFrameRate,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - int t; - if (m_bStreaming) { - t = timeGetTime()-m_tStreamingStart; - } else { - t = m_tStreamingStart; - } - - if (t<=0) { - *piAvgFrameRate = 0; - ASSERT(m_cFramesDrawn == 0); - } else { - // i is frames per hundred seconds - *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t); - } - return NOERROR; -} // get_AvgFrameRate - - -// Set *piAvg to the average sync offset since streaming started -// in mSec. The sync offset is the time in mSec between when the frame -// should have been drawn and when the frame was actually drawn. - -STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset(__out int *piAvg) -{ - CheckPointer(piAvg,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - if (NULL==m_pClock) { - *piAvg = 0; - return NOERROR; - } - - // Note that we didn't gather the stats on the first frame - // so we use m_cFramesDrawn-1 here - if (m_cFramesDrawn<=1) { - *piAvg = 0; - } else { - *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1)); - } - return NOERROR; -} // get_AvgSyncOffset - - -// To avoid dragging in the maths library - a cheap -// approximate integer square root. -// We do this by getting a starting guess which is between 1 -// and 2 times too large, followed by THREE iterations of -// Newton Raphson. (That will give accuracy to the nearest mSec -// for the range in question - roughly 0..1000) -// -// It would be faster to use a linear interpolation and ONE NR, but -// who cares. If anyone does - the best linear interpolation is -// to approximates sqrt(x) by -// y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1)) -// 0r y = x*0.41421 + 0.59467 -// This minimises the maximal error in the range in question. -// (error is about +0.008883 and then one NR will give error .0000something -// (Of course these are integers, so you can't just multiply by 0.41421 -// you'd have to do some sort of MulDiv). -// Anyone wanna check my maths? (This is only for a property display!) - -int isqrt(int x) -{ - int s = 1; - // Make s an initial guess for sqrt(x) - if (x > 0x40000000) { - s = 0x8000; // prevent any conceivable closed loop - } else { - while (s*s=0) s = (s*s+x)/(2*s); - if (s>=0) s = (s*s+x)/(2*s); - } - } - return s; -} - -// -// Do estimates for standard deviations for per-frame -// statistics -// -HRESULT CBaseVideoRenderer::GetStdDev( - int nSamples, - __out int *piResult, - LONGLONG llSumSq, - LONGLONG iTot -) -{ - CheckPointer(piResult,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - if (NULL==m_pClock) { - *piResult = 0; - return NOERROR; - } - - // If S is the Sum of the Squares of observations and - // T the Total (i.e. sum) of the observations and there were - // N observations, then an estimate of the standard deviation is - // sqrt( (S - T**2/N) / (N-1) ) - - if (nSamples<=1) { - *piResult = 0; - } else { - LONGLONG x; - // First frames have invalid stamps, so we get no stats for them - // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 - - // so we use m_cFramesDrawn-1 here - x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0); - x = x / (nSamples-1); - ASSERT(x>=0); - *piResult = isqrt((LONG)x); - } - return NOERROR; -} - -// Set *piDev to the standard deviation in mSec of the sync offset -// of each frame since streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset(__out int *piDev) -{ - // First frames have invalid stamps, so we get no stats for them - // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 - return GetStdDev(m_cFramesDrawn - 1, - piDev, - m_iSumSqAcc, - m_iTotAcc); -} // get_DevSyncOffset - - -// Set *piJitter to the standard deviation in mSec of the inter-frame time -// of frames since streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_Jitter(__out int *piJitter) -{ - // First frames have invalid stamps, so we get no stats for them - // So second frame gives invalid inter-frame time - // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2 - return GetStdDev(m_cFramesDrawn - 2, - piJitter, - m_iSumSqFrameTime, - m_iSumFrameTime); -} // get_Jitter - - -// Overidden to return our IQualProp interface - -STDMETHODIMP -CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv) -{ - // We return IQualProp and delegate everything else - - if (riid == IID_IQualProp) { - return GetInterface( (IQualProp *)this, ppv); - } else if (riid == IID_IQualityControl) { - return GetInterface( (IQualityControl *)this, ppv); - } - return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv); -} - - -// Override JoinFilterGraph so that, just before leaving -// the graph we can send an EC_WINDOW_DESTROYED event - -STDMETHODIMP -CBaseVideoRenderer::JoinFilterGraph(__inout_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName) -{ - // Since we send EC_ACTIVATE, we also need to ensure - // we send EC_WINDOW_DESTROYED or the resource manager may be - // holding us as a focus object - if (!pGraph && m_pGraph) { - - // We were in a graph and now we're not - // Do this properly in case we are aggregated - IBaseFilter* pFilter = this; - NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0); - } - return CBaseFilter::JoinFilterGraph(pGraph, pName); -} - - -// This removes a large number of level 4 warnings from the -// Microsoft compiler which in this case are not very useful -#pragma warning(disable: 4514) - +//------------------------------------------------------------------------------ +// File: RenBase.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" // DirectShow base class definitions +#include // Needed for definition of timeGetTime +#include // Standard data type limit definitions +#include "measure.h" // Used for time critical log functions + +#pragma warning(disable:4355) + +// Helper function for clamping time differences +int inline TimeDiff(REFERENCE_TIME rt) +{ + if (rt < - (50 * UNITS)) { + return -(50 * UNITS); + } else + if (rt > 50 * UNITS) { + return 50 * UNITS; + } else return (int)rt; +} + +// Implements the CBaseRenderer class + +CBaseRenderer::CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer + __in_opt LPCTSTR pName, // Debug ONLY description + __inout_opt LPUNKNOWN pUnk, // Aggregated owner object + __inout HRESULT *phr) : // General OLE return code + + CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass), + m_evComplete(TRUE, phr), + m_RenderEvent(FALSE, phr), + m_bAbort(FALSE), + m_pPosition(NULL), + m_ThreadSignal(TRUE, phr), + m_bStreaming(FALSE), + m_bEOS(FALSE), + m_bEOSDelivered(FALSE), + m_pMediaSample(NULL), + m_dwAdvise(0), + m_pQSink(NULL), + m_pInputPin(NULL), + m_bRepaintStatus(TRUE), + m_SignalTime(0), + m_bInReceive(FALSE), + m_EndOfStreamTimer(0) +{ + if (SUCCEEDED(*phr)) { + Ready(); +#ifdef PERF + m_idBaseStamp = MSR_REGISTER(TEXT("BaseRenderer: sample time stamp")); + m_idBaseRenderTime = MSR_REGISTER(TEXT("BaseRenderer: draw time (msec)")); + m_idBaseAccuracy = MSR_REGISTER(TEXT("BaseRenderer: Accuracy (msec)")); +#endif + } +} + + +// Delete the dynamically allocated IMediaPosition and IMediaSeeking helper +// object. The object is created when somebody queries us. These are standard +// control interfaces for seeking and setting start/stop positions and rates. +// We will probably also have made an input pin based on CRendererInputPin +// that has to be deleted, it's created when an enumerator calls our GetPin + +CBaseRenderer::~CBaseRenderer() +{ + ASSERT(m_bStreaming == FALSE); + ASSERT(m_EndOfStreamTimer == 0); + StopStreaming(); + ClearPendingSample(); + + // Delete any IMediaPosition implementation + + if (m_pPosition) { + delete m_pPosition; + m_pPosition = NULL; + } + + // Delete any input pin created + + if (m_pInputPin) { + delete m_pInputPin; + m_pInputPin = NULL; + } + + // Release any Quality sink + + ASSERT(m_pQSink == NULL); +} + + +// This returns the IMediaPosition and IMediaSeeking interfaces + +HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid, __deref_out void **ppv) +{ + CAutoLock cObjectCreationLock(&m_ObjectCreationLock); + if (m_pPosition) { + return m_pPosition->NonDelegatingQueryInterface(riid,ppv); + } + + CBasePin *pPin = GetPin(0); + if (NULL == pPin) { + return E_OUTOFMEMORY; + } + + HRESULT hr = NOERROR; + + // Create implementation of this dynamically since sometimes we may + // never try and do a seek. The helper object implements a position + // control interface (IMediaPosition) which in fact simply takes the + // calls normally from the filter graph and passes them upstream + + m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"), + CBaseFilter::GetOwner(), + (HRESULT *) &hr, + pPin); + if (m_pPosition == NULL) { + return E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + delete m_pPosition; + m_pPosition = NULL; + return E_NOINTERFACE; + } + return GetMediaPositionInterface(riid,ppv); +} + + +// Overriden to say what interfaces we support and where + +STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + // Do we have this interface + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + return GetMediaPositionInterface(riid,ppv); + } else { + return CBaseFilter::NonDelegatingQueryInterface(riid,ppv); + } +} + + +// This is called whenever we change states, we have a manual reset event that +// is signalled whenever we don't won't the source filter thread to wait in us +// (such as in a stopped state) and likewise is not signalled whenever it can +// wait (during paused and running) this function sets or resets the thread +// event. The event is used to stop source filter threads waiting in Receive + +HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait) +{ + if (bCanWait == TRUE) { + m_ThreadSignal.Reset(); + } else { + m_ThreadSignal.Set(); + } + return NOERROR; +} + + +#ifdef _DEBUG +// Dump the current renderer state to the debug terminal. The hardest part of +// the renderer is the window where we unlock everything to wait for a clock +// to signal it is time to draw or for the application to cancel everything +// by stopping the filter. If we get things wrong we can leave the thread in +// WaitForRenderTime with no way for it to ever get out and we will deadlock + +void CBaseRenderer::DisplayRendererState() +{ + DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime"))); + + // No way should this be signalled at this point + + BOOL bSignalled = m_ThreadSignal.Check(); + DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled)); + + // Now output the current renderer state variables + + DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State)); + + DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort)); + + DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming)); + + DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise)); + + DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample)); + + DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS)); + + DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered)); + + DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus)); + + + // Output the delayed end of stream timer information + + DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer)); + + DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime))); + + + // Should never timeout during a flushing state + + BOOL bFlushing = m_pInputPin->IsFlushing(); + DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing)); + + // Display the time we were told to start at + DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time))); + + // Have we got a reference clock + if (m_pClock == NULL) return; + + // Get the current time from the wall clock + + CRefTime CurrentTime,StartTime,EndTime; + m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime); + CRefTime Offset = CurrentTime - m_tStart; + + // Display the current time from the clock + + DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time))); + + DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs())); + + + // Do we have a sample ready to render + if (m_pMediaSample == NULL) return; + + m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime); + DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"), + StartTime.Millisecs(),EndTime.Millisecs())); + + // Calculate how long it is until it is due for rendering + CRefTime Wait = (m_tStart + StartTime) - CurrentTime; + DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs())); +} +#endif + + +// Wait until the clock sets the timer event or we're otherwise signalled. We +// set an arbitrary timeout for this wait and if it fires then we display the +// current renderer state on the debugger. It will often fire if the filter's +// left paused in an application however it may also fire during stress tests +// if the synchronisation with application seeks and state changes is faulty + +#define RENDER_TIMEOUT 10000 + +HRESULT CBaseRenderer::WaitForRenderTime() +{ + HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent }; + DWORD Result = WAIT_TIMEOUT; + + // Wait for either the time to arrive or for us to be stopped + + OnWaitStart(); + while (Result == WAIT_TIMEOUT) { + Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT); + +#ifdef _DEBUG + if (Result == WAIT_TIMEOUT) DisplayRendererState(); +#endif + + } + OnWaitEnd(); + + // We may have been awoken without the timer firing + + if (Result == WAIT_OBJECT_0) { + return VFW_E_STATE_CHANGED; + } + + SignalTimerFired(); + return NOERROR; +} + + +// Poll waiting for Receive to complete. This really matters when +// Receive may set the palette and cause window messages +// The problem is that if we don't really wait for a renderer to +// stop processing we can deadlock waiting for a transform which +// is calling the renderer's Receive() method because the transform's +// Stop method doesn't know to process window messages to unblock +// the renderer's Receive processing +void CBaseRenderer::WaitForReceiveToComplete() +{ + for (;;) { + if (!m_bInReceive) { + break; + } + + MSG msg; + // Receive all interthread snedmessages + PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); + + Sleep(1); + } + + // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call + // above just cleared the changebit which will cause some messaging + // calls to block (waitMessage, MsgWaitFor...) now. + // Post a dummy message to set the QS_POSTMESSAGE bit again + if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { + // Send dummy message + PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); + } +} + +// A filter can have four discrete states, namely Stopped, Running, Paused, +// Intermediate. We are in an intermediate state if we are currently trying +// to pause but haven't yet got the first sample (or if we have been flushed +// in paused state and therefore still have to wait for a sample to arrive) + +// This class contains an event called m_evComplete which is signalled when +// the current state is completed and is not signalled when we are waiting to +// complete the last state transition. As mentioned above the only time we +// use this at the moment is when we wait for a media sample in paused state +// If while we are waiting we receive an end of stream notification from the +// source filter then we know no data is imminent so we can reset the event +// This means that when we transition to paused the source filter must call +// end of stream on us or send us an image otherwise we'll hang indefinately + + +// Simple internal way of getting the real state + +FILTER_STATE CBaseRenderer::GetRealState() { + return m_State; +} + + +// The renderer doesn't complete the full transition to paused states until +// it has got one media sample to render. If you ask it for its state while +// it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE + +STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State) +{ + CheckPointer(State,E_POINTER); + + if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) { + *State = m_State; + return VFW_S_STATE_INTERMEDIATE; + } + *State = m_State; + return NOERROR; +} + + +// If we're pausing and we have no samples we don't complete the transition +// to State_Paused and we return S_FALSE. However if the m_bAbort flag has +// been set then all samples are rejected so there is no point waiting for +// one. If we do have a sample then return NOERROR. We will only ever return +// VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample +// (calling GetState after either being stopped or Run will NOT return this) + +HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState) +{ + // Allow us to be paused when disconnected + + if (m_pInputPin->IsConnected() == FALSE) { + Ready(); + return S_OK; + } + + // Have we run off the end of stream + + if (IsEndOfStream() == TRUE) { + Ready(); + return S_OK; + } + + // Make sure we get fresh data after being stopped + + if (HaveCurrentSample() == TRUE) { + if (OldState != State_Stopped) { + Ready(); + return S_OK; + } + } + NotReady(); + return S_FALSE; +} + + +// When we stop the filter the things we do are:- + +// Decommit the allocator being used in the connection +// Release the source filter if it's waiting in Receive +// Cancel any advise link we set up with the clock +// Any end of stream signalled is now obsolete so reset +// Allow us to be stopped when we are not connected + +STDMETHODIMP CBaseRenderer::Stop() +{ + CAutoLock cRendererLock(&m_InterfaceLock); + + // Make sure there really is a state change + + if (m_State == State_Stopped) { + return NOERROR; + } + + // Is our input pin connected + + if (m_pInputPin->IsConnected() == FALSE) { + NOTE("Input pin is not connected"); + m_State = State_Stopped; + return NOERROR; + } + + CBaseFilter::Stop(); + + // If we are going into a stopped state then we must decommit whatever + // allocator we are using it so that any source filter waiting in the + // GetBuffer can be released and unlock themselves for a state change + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Decommit(); + } + + // Cancel any scheduled rendering + + SetRepaintStatus(TRUE); + StopStreaming(); + SourceThreadCanWait(FALSE); + ResetEndOfStream(); + CancelNotification(); + + // There should be no outstanding clock advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + + Ready(); + WaitForReceiveToComplete(); + m_bAbort = FALSE; + + return NOERROR; +} + + +// When we pause the filter the things we do are:- + +// Commit the allocator being used in the connection +// Allow a source filter thread to wait in Receive +// Cancel any clock advise link (we may be running) +// Possibly complete the state change if we have data +// Allow us to be paused when we are not connected + +STDMETHODIMP CBaseRenderer::Pause() +{ + CAutoLock cRendererLock(&m_InterfaceLock); + FILTER_STATE OldState = m_State; + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // Make sure there really is a state change + + if (m_State == State_Paused) { + return CompleteStateChange(State_Paused); + } + + // Has our input pin been connected + + if (m_pInputPin->IsConnected() == FALSE) { + NOTE("Input pin is not connected"); + m_State = State_Paused; + return CompleteStateChange(State_Paused); + } + + // Pause the base filter class + + HRESULT hr = CBaseFilter::Pause(); + if (FAILED(hr)) { + NOTE("Pause failed"); + return hr; + } + + // Enable EC_REPAINT events again + + SetRepaintStatus(TRUE); + StopStreaming(); + SourceThreadCanWait(TRUE); + CancelNotification(); + ResetEndOfStreamTimer(); + + // If we are going into a paused state then we must commit whatever + // allocator we are using it so that any source filter can call the + // GetBuffer and expect to get a buffer without returning an error + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Commit(); + } + + // There should be no outstanding advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // When we come out of a stopped state we must clear any image we were + // holding onto for frame refreshing. Since renderers see state changes + // first we can reset ourselves ready to accept the source thread data + // Paused or running after being stopped causes the current position to + // be reset so we're not interested in passing end of stream signals + + if (OldState == State_Stopped) { + m_bAbort = FALSE; + ClearPendingSample(); + } + return CompleteStateChange(OldState); +} + + +// When we run the filter the things we do are:- + +// Commit the allocator being used in the connection +// Allow a source filter thread to wait in Receive +// Signal the render event just to get us going +// Start the base class by calling StartStreaming +// Allow us to be run when we are not connected +// Signal EC_COMPLETE if we are not connected + +STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime) +{ + CAutoLock cRendererLock(&m_InterfaceLock); + FILTER_STATE OldState = m_State; + + // Make sure there really is a state change + + if (m_State == State_Running) { + return NOERROR; + } + + // Send EC_COMPLETE if we're not connected + + if (m_pInputPin->IsConnected() == FALSE) { + NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); + m_State = State_Running; + return NOERROR; + } + + Ready(); + + // Pause the base filter class + + HRESULT hr = CBaseFilter::Run(StartTime); + if (FAILED(hr)) { + NOTE("Run failed"); + return hr; + } + + // Allow the source thread to wait + ASSERT(m_pInputPin->IsFlushing() == FALSE); + SourceThreadCanWait(TRUE); + SetRepaintStatus(FALSE); + + // There should be no outstanding advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // If we are going into a running state then we must commit whatever + // allocator we are using it so that any source filter can call the + // GetBuffer and expect to get a buffer without returning an error + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Commit(); + } + + // When we come out of a stopped state we must clear any image we were + // holding onto for frame refreshing. Since renderers see state changes + // first we can reset ourselves ready to accept the source thread data + // Paused or running after being stopped causes the current position to + // be reset so we're not interested in passing end of stream signals + + if (OldState == State_Stopped) { + m_bAbort = FALSE; + ClearPendingSample(); + } + return StartStreaming(); +} + + +// Return the number of input pins we support + +int CBaseRenderer::GetPinCount() +{ + if (m_pInputPin == NULL) { + // Try to create it + (void)GetPin(0); + } + return m_pInputPin != NULL ? 1 : 0; +} + + +// We only support one input pin and it is numbered zero + +CBasePin *CBaseRenderer::GetPin(int n) +{ + CAutoLock cObjectCreationLock(&m_ObjectCreationLock); + + // Should only ever be called with zero + ASSERT(n == 0); + + if (n != 0) { + return NULL; + } + + // Create the input pin if not already done so + + if (m_pInputPin == NULL) { + + // hr must be initialized to NOERROR because + // CRendererInputPin's constructor only changes + // hr's value if an error occurs. + HRESULT hr = NOERROR; + + m_pInputPin = new CRendererInputPin(this,&hr,L"In"); + if (NULL == m_pInputPin) { + return NULL; + } + + if (FAILED(hr)) { + delete m_pInputPin; + m_pInputPin = NULL; + return NULL; + } + } + return m_pInputPin; +} + + +// If "In" then return the IPin for our input pin, otherwise NULL and error + +STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + + if (0==lstrcmpW(Id,L"In")) { + *ppPin = GetPin(0); + if (*ppPin) { + (*ppPin)->AddRef(); + } else { + return E_OUTOFMEMORY; + } + } else { + *ppPin = NULL; + return VFW_E_NOT_FOUND; + } + return NOERROR; +} + + +// Called when the input pin receives an EndOfStream notification. If we have +// not got a sample, then notify EC_COMPLETE now. If we have samples, then set +// m_bEOS and check for this on completing samples. If we're waiting to pause +// then complete the transition to paused state by setting the state event + +HRESULT CBaseRenderer::EndOfStream() +{ + // Ignore these calls if we are stopped + + if (m_State == State_Stopped) { + return NOERROR; + } + + // If we have a sample then wait for it to be rendered + + m_bEOS = TRUE; + if (m_pMediaSample) { + return NOERROR; + } + + // If we are waiting for pause then we are now ready since we cannot now + // carry on waiting for a sample to arrive since we are being told there + // won't be any. This sets an event that the GetState function picks up + + Ready(); + + // Only signal completion now if we are running otherwise queue it until + // we do run in StartStreaming. This is used when we seek because a seek + // causes a pause where early notification of completion is misleading + + if (m_bStreaming) { + SendEndOfStream(); + } + return NOERROR; +} + + +// When we are told to flush we should release the source thread + +HRESULT CBaseRenderer::BeginFlush() +{ + // If paused then report state intermediate until we get some data + + if (m_State == State_Paused) { + NotReady(); + } + + SourceThreadCanWait(FALSE); + CancelNotification(); + ClearPendingSample(); + // Wait for Receive to complete + WaitForReceiveToComplete(); + + return NOERROR; +} + + +// After flushing the source thread can wait in Receive again + +HRESULT CBaseRenderer::EndFlush() +{ + // Reset the current sample media time + if (m_pPosition) m_pPosition->ResetMediaTime(); + + // There should be no outstanding advise + + ASSERT(CancelNotification() == S_FALSE); + SourceThreadCanWait(TRUE); + return NOERROR; +} + + +// We can now send EC_REPAINTs if so required + +HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin) +{ + // The caller should always hold the interface lock because + // the function uses CBaseFilter::m_State. + ASSERT(CritCheckIn(&m_InterfaceLock)); + + m_bAbort = FALSE; + + if (State_Running == GetRealState()) { + HRESULT hr = StartStreaming(); + if (FAILED(hr)) { + return hr; + } + + SetRepaintStatus(FALSE); + } else { + SetRepaintStatus(TRUE); + } + + return NOERROR; +} + + +// Called when we go paused or running + +HRESULT CBaseRenderer::Active() +{ + return NOERROR; +} + + +// Called when we go into a stopped state + +HRESULT CBaseRenderer::Inactive() +{ + if (m_pPosition) { + m_pPosition->ResetMediaTime(); + } + // People who derive from this may want to override this behaviour + // to keep hold of the sample in some circumstances + ClearPendingSample(); + + return NOERROR; +} + + +// Tell derived classes about the media type agreed + +HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt) +{ + return NOERROR; +} + + +// When we break the input pin connection we should reset the EOS flags. When +// we are asked for either IMediaPosition or IMediaSeeking we will create a +// CPosPassThru object to handles media time pass through. When we're handed +// samples we store (by calling CPosPassThru::RegisterMediaTime) their media +// times so we can then return a real current position of data being rendered + +HRESULT CBaseRenderer::BreakConnect() +{ + // Do we have a quality management sink + + if (m_pQSink) { + m_pQSink->Release(); + m_pQSink = NULL; + } + + // Check we have a valid connection + + if (m_pInputPin->IsConnected() == FALSE) { + return S_FALSE; + } + + // Check we are stopped before disconnecting + if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) { + return VFW_E_NOT_STOPPED; + } + + SetRepaintStatus(FALSE); + ResetEndOfStream(); + ClearPendingSample(); + m_bAbort = FALSE; + + if (State_Running == m_State) { + StopStreaming(); + } + + return NOERROR; +} + + +// Retrieves the sample times for this samples (note the sample times are +// passed in by reference not value). We return S_FALSE to say schedule this +// sample according to the times on the sample. We also return S_OK in +// which case the object should simply render the sample data immediately + +HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample, + __out REFERENCE_TIME *pStartTime, + __out REFERENCE_TIME *pEndTime) +{ + ASSERT(m_dwAdvise == 0); + ASSERT(pMediaSample); + + // If the stop time for this sample is before or the same as start time, + // then just ignore it (release it) and schedule the next one in line + // Source filters should always fill in the start and end times properly! + + if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) { + if (*pEndTime < *pStartTime) { + return VFW_E_START_TIME_AFTER_END; + } + } else { + // no time set in the sample... draw it now? + return S_OK; + } + + // Can't synchronise without a clock so we return S_OK which tells the + // caller that the sample should be rendered immediately without going + // through the overhead of setting a timer advise link with the clock + + if (m_pClock == NULL) { + return S_OK; + } + return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime); +} + + +// By default all samples are drawn according to their time stamps so we +// return S_FALSE. Returning S_OK means draw immediately, this is used +// by the derived video renderer class in its quality management. + +HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, + __out REFERENCE_TIME *ptrStart, + __out REFERENCE_TIME *ptrEnd) +{ + return S_FALSE; +} + + +// We must always reset the current advise time to zero after a timer fires +// because there are several possible ways which lead us not to do any more +// scheduling such as the pending image being cleared after state changes + +void CBaseRenderer::SignalTimerFired() +{ + m_dwAdvise = 0; +} + + +// Cancel any notification currently scheduled. This is called by the owning +// window object when it is told to stop streaming. If there is no timer link +// outstanding then calling this is benign otherwise we go ahead and cancel +// We must always reset the render event as the quality management code can +// signal immediate rendering by setting the event without setting an advise +// link. If we're subsequently stopped and run the first attempt to setup an +// advise link with the reference clock will find the event still signalled + +HRESULT CBaseRenderer::CancelNotification() +{ + ASSERT(m_dwAdvise == 0 || m_pClock); + DWORD_PTR dwAdvise = m_dwAdvise; + + // Have we a live advise link + + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + SignalTimerFired(); + ASSERT(m_dwAdvise == 0); + } + + // Clear the event and return our status + + m_RenderEvent.Reset(); + return (dwAdvise ? S_OK : S_FALSE); +} + + +// Responsible for setting up one shot advise links with the clock +// Return FALSE if the sample is to be dropped (not drawn at all) +// Return TRUE if the sample is to be drawn and in this case also +// arrange for m_RenderEvent to be set at the appropriate time + +BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample) +{ + REFERENCE_TIME StartSample, EndSample; + + // Is someone pulling our leg + + if (pMediaSample == NULL) { + return FALSE; + } + + // Get the next sample due up for rendering. If there aren't any ready + // then GetNextSampleTimes returns an error. If there is one to be done + // then it succeeds and yields the sample times. If it is due now then + // it returns S_OK other if it's to be done when due it returns S_FALSE + + HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample); + if (FAILED(hr)) { + return FALSE; + } + + // If we don't have a reference clock then we cannot set up the advise + // time so we simply set the event indicating an image to render. This + // will cause us to run flat out without any timing or synchronisation + + if (hr == S_OK) { + EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent)); + return TRUE; + } + + ASSERT(m_dwAdvise == 0); + ASSERT(m_pClock); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + + // We do have a valid reference clock interface so we can ask it to + // set an event when the image comes due for rendering. We pass in + // the reference time we were told to start at and also the current + // stream time which is the offset from the start reference time + + hr = m_pClock->AdviseTime( + (REFERENCE_TIME) m_tStart, // Start run time + StartSample, // Stream time + (HEVENT)(HANDLE) m_RenderEvent, // Render notification + &m_dwAdvise); // Advise cookie + + if (SUCCEEDED(hr)) { + return TRUE; + } + + // We could not schedule the next sample for rendering despite the fact + // we have a valid sample here. This is a fair indication that either + // the system clock is wrong or the time stamp for the sample is duff + + ASSERT(m_dwAdvise == 0); + return FALSE; +} + + +// This is called when a sample comes due for rendering. We pass the sample +// on to the derived class. After rendering we will initialise the timer for +// the next sample, NOTE signal that the last one fired first, if we don't +// do this it thinks there is still one outstanding that hasn't completed + +HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample) +{ + // If the media sample is NULL then we will have been notified by the + // clock that another sample is ready but in the mean time someone has + // stopped us streaming which causes the next sample to be released + + if (pMediaSample == NULL) { + return S_FALSE; + } + + // If we have stopped streaming then don't render any more samples, the + // thread that got in and locked us and then reset this flag does not + // clear the pending sample as we can use it to refresh any output device + + if (m_bStreaming == FALSE) { + return S_FALSE; + } + + // Time how long the rendering takes + + OnRenderStart(pMediaSample); + DoRenderSample(pMediaSample); + OnRenderEnd(pMediaSample); + + return NOERROR; +} + + +// Checks if there is a sample waiting at the renderer + +BOOL CBaseRenderer::HaveCurrentSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + return (m_pMediaSample == NULL ? FALSE : TRUE); +} + + +// Returns the current sample waiting at the video renderer. We AddRef the +// sample before returning so that should it come due for rendering the +// person who called this method will hold the remaining reference count +// that will stop the sample being added back onto the allocator free list + +IMediaSample *CBaseRenderer::GetCurrentSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_pMediaSample) { + m_pMediaSample->AddRef(); + } + return m_pMediaSample; +} + + +// Called when the source delivers us a sample. We go through a few checks to +// make sure the sample can be rendered. If we are running (streaming) then we +// have the sample scheduled with the reference clock, if we are not streaming +// then we have received an sample in paused mode so we can complete any state +// transition. On leaving this function everything will be unlocked so an app +// thread may get in and change our state to stopped (for example) in which +// case it will also signal the thread event so that our wait call is stopped + +HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample) +{ + CAutoLock cInterfaceLock(&m_InterfaceLock); + m_bInReceive = TRUE; + + // Check our flushing and filter state + + // This function must hold the interface lock because it calls + // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses + // CBasePin::m_bRunTimeError. + HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample); + + if (hr != NOERROR) { + m_bInReceive = FALSE; + return E_FAIL; + } + + // Has the type changed on a media sample. We do all rendering + // synchronously on the source thread, which has a side effect + // that only one buffer is ever outstanding. Therefore when we + // have Receive called we can go ahead and change the format + // Since the format change can cause a SendMessage we just don't + // lock + if (m_pInputPin->SampleProps()->pMediaType) { + hr = m_pInputPin->SetMediaType( + (CMediaType *)m_pInputPin->SampleProps()->pMediaType); + if (FAILED(hr)) { + m_bInReceive = FALSE; + return hr; + } + } + + + CAutoLock cSampleLock(&m_RendererLock); + + ASSERT(IsActive() == TRUE); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + ASSERT(m_pInputPin->IsConnected() == TRUE); + ASSERT(m_pMediaSample == NULL); + + // Return an error if we already have a sample waiting for rendering + // source pins must serialise the Receive calls - we also check that + // no data is being sent after the source signalled an end of stream + + if (m_pMediaSample || m_bEOS || m_bAbort) { + Ready(); + m_bInReceive = FALSE; + return E_UNEXPECTED; + } + + // Store the media times from this sample + if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample); + + // Schedule the next sample if we are streaming + + if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) { + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(CancelNotification() == S_FALSE); + m_bInReceive = FALSE; + return VFW_E_SAMPLE_REJECTED; + } + + // Store the sample end time for EC_COMPLETE handling + m_SignalTime = m_pInputPin->SampleProps()->tStop; + + // BEWARE we sometimes keep the sample even after returning the thread to + // the source filter such as when we go into a stopped state (we keep it + // to refresh the device with) so we must AddRef it to keep it safely. If + // we start flushing the source thread is released and any sample waiting + // will be released otherwise GetBuffer may never return (see BeginFlush) + + m_pMediaSample = pMediaSample; + m_pMediaSample->AddRef(); + + if (m_bStreaming == FALSE) { + SetRepaintStatus(TRUE); + } + return NOERROR; +} + + +// Called by the source filter when we have a sample to render. Under normal +// circumstances we set an advise link with the clock, wait for the time to +// arrive and then render the data using the PURE virtual DoRenderSample that +// the derived class will have overriden. After rendering the sample we may +// also signal EOS if it was the last one sent before EndOfStream was called + +HRESULT CBaseRenderer::Receive(IMediaSample *pSample) +{ + ASSERT(pSample); + + // It may return VFW_E_SAMPLE_REJECTED code to say don't bother + + HRESULT hr = PrepareReceive(pSample); + ASSERT(m_bInReceive == SUCCEEDED(hr)); + if (FAILED(hr)) { + if (hr == VFW_E_SAMPLE_REJECTED) { + return NOERROR; + } + return hr; + } + + // We realize the palette in "PrepareRender()" so we have to give away the + // filter lock here. + if (m_State == State_Paused) { + PrepareRender(); + // no need to use InterlockedExchange + m_bInReceive = FALSE; + { + // We must hold both these locks + CAutoLock cRendererLock(&m_InterfaceLock); + if (m_State == State_Stopped) + return NOERROR; + + m_bInReceive = TRUE; + CAutoLock cSampleLock(&m_RendererLock); + OnReceiveFirstSample(pSample); + } + Ready(); + } + // Having set an advise link with the clock we sit and wait. We may be + // awoken by the clock firing or by a state change. The rendering call + // will lock the critical section and check we can still render the data + + hr = WaitForRenderTime(); + if (FAILED(hr)) { + m_bInReceive = FALSE; + return NOERROR; + } + + PrepareRender(); + + // Set this here and poll it until we work out the locking correctly + // It can't be right that the streaming stuff grabs the interface + // lock - after all we want to be able to wait for this stuff + // to complete + m_bInReceive = FALSE; + + // We must hold both these locks + CAutoLock cRendererLock(&m_InterfaceLock); + + // since we gave away the filter wide lock, the sate of the filter could + // have chnaged to Stopped + if (m_State == State_Stopped) + return NOERROR; + + CAutoLock cSampleLock(&m_RendererLock); + + // Deal with this sample + + Render(m_pMediaSample); + ClearPendingSample(); + SendEndOfStream(); + CancelNotification(); + return NOERROR; +} + + +// This is called when we stop or are inactivated to clear the pending sample +// We release the media sample interface so that they can be allocated to the +// source filter again, unless of course we are changing state to inactive in +// which case GetBuffer will return an error. We must also reset the current +// media sample to NULL so that we know we do not currently have an image + +HRESULT CBaseRenderer::ClearPendingSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_pMediaSample) { + m_pMediaSample->Release(); + m_pMediaSample = NULL; + } + return NOERROR; +} + + +// Used to signal end of stream according to the sample end time + +void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier + UINT uMsg, // Not currently used + DWORD_PTR dwUser,// User information + DWORD_PTR dw1, // Windows reserved + DWORD_PTR dw2) // is also reserved +{ + CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser; + NOTE1("EndOfStreamTimer called (%d)",uID); + pRenderer->TimerCallback(); +} + +// Do the timer callback work +void CBaseRenderer::TimerCallback() +{ + // Lock for synchronization (but don't hold this lock when calling + // timeKillEvent) + CAutoLock cRendererLock(&m_RendererLock); + + // See if we should signal end of stream now + + if (m_EndOfStreamTimer) { + m_EndOfStreamTimer = 0; + SendEndOfStream(); + } +} + + +// If we are at the end of the stream signal the filter graph but do not set +// the state flag back to FALSE. Once we drop off the end of the stream we +// leave the flag set (until a subsequent ResetEndOfStream). Each sample we +// get delivered will update m_SignalTime to be the last sample's end time. +// We must wait this long before signalling end of stream to the filtergraph + +#define TIMEOUT_DELIVERYWAIT 50 +#define TIMEOUT_RESOLUTION 10 + +HRESULT CBaseRenderer::SendEndOfStream() +{ + ASSERT(CritCheckIn(&m_RendererLock)); + if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) { + return NOERROR; + } + + // If there is no clock then signal immediately + if (m_pClock == NULL) { + return NotifyEndOfStream(); + } + + // How long into the future is the delivery time + + REFERENCE_TIME Signal = m_tStart + m_SignalTime; + REFERENCE_TIME CurrentTime; + m_pClock->GetTime(&CurrentTime); + LONG Delay = LONG((Signal - CurrentTime) / 10000); + + // Dump the timing information to the debugger + + NOTE1("Delay until end of stream delivery %d",Delay); + NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime)); + NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal)); + + // Wait for the delivery time to arrive + + if (Delay < TIMEOUT_DELIVERYWAIT) { + return NotifyEndOfStream(); + } + + // Signal a timer callback on another worker thread + + m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer + TIMEOUT_RESOLUTION, // Timer resolution + EndOfStreamTimer, // Callback function + DWORD_PTR(this), // Used information + TIME_ONESHOT); // Type of callback + if (m_EndOfStreamTimer == 0) { + return NotifyEndOfStream(); + } + return NOERROR; +} + + +// Signals EC_COMPLETE to the filtergraph manager + +HRESULT CBaseRenderer::NotifyEndOfStream() +{ + CAutoLock cRendererLock(&m_RendererLock); + ASSERT(m_bEOSDelivered == FALSE); + ASSERT(m_EndOfStreamTimer == 0); + + // Has the filter changed state + + if (m_bStreaming == FALSE) { + ASSERT(m_EndOfStreamTimer == 0); + return NOERROR; + } + + // Reset the end of stream timer + m_EndOfStreamTimer = 0; + + // If we've been using the IMediaPosition interface, set it's start + // and end media "times" to the stop position by hand. This ensures + // that we actually get to the end, even if the MPEG guestimate has + // been bad or if the quality management dropped the last few frames + + if (m_pPosition) m_pPosition->EOS(); + m_bEOSDelivered = TRUE; + NOTE("Sending EC_COMPLETE..."); + return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); +} + + +// Reset the end of stream flag, this is typically called when we transfer to +// stopped states since that resets the current position back to the start so +// we will receive more samples or another EndOfStream if there aren't any. We +// keep two separate flags one to say we have run off the end of the stream +// (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE +// to the filter graph. We need the latter otherwise we can end up sending an +// EC_COMPLETE every time the source changes state and calls our EndOfStream + +HRESULT CBaseRenderer::ResetEndOfStream() +{ + ResetEndOfStreamTimer(); + CAutoLock cRendererLock(&m_RendererLock); + + m_bEOS = FALSE; + m_bEOSDelivered = FALSE; + m_SignalTime = 0; + + return NOERROR; +} + + +// Kills any outstanding end of stream timer + +void CBaseRenderer::ResetEndOfStreamTimer() +{ + ASSERT(CritCheckOut(&m_RendererLock)); + if (m_EndOfStreamTimer) { + timeKillEvent(m_EndOfStreamTimer); + m_EndOfStreamTimer = 0; + } +} + + +// This is called when we start running so that we can schedule any pending +// image we have with the clock and display any timing information. If we +// don't have any sample but we have queued an EOS flag then we send it. If +// we do have a sample then we wait until that has been rendered before we +// signal the filter graph otherwise we may change state before it's done + +HRESULT CBaseRenderer::StartStreaming() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_bStreaming == TRUE) { + return NOERROR; + } + + // Reset the streaming times ready for running + + m_bStreaming = TRUE; + + timeBeginPeriod(1); + OnStartStreaming(); + + // There should be no outstanding advise + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(CancelNotification() == S_FALSE); + + // If we have an EOS and no data then deliver it now + + if (m_pMediaSample == NULL) { + return SendEndOfStream(); + } + + // Have the data rendered + + ASSERT(m_pMediaSample); + if (!ScheduleSample(m_pMediaSample)) + m_RenderEvent.Set(); + + return NOERROR; +} + + +// This is called when we stop streaming so that we can set our internal flag +// indicating we are not now to schedule any more samples arriving. The state +// change methods in the filter implementation take care of cancelling any +// clock advise link we have set up and clearing any pending sample we have + +HRESULT CBaseRenderer::StopStreaming() +{ + CAutoLock cRendererLock(&m_RendererLock); + m_bEOSDelivered = FALSE; + + if (m_bStreaming == TRUE) { + m_bStreaming = FALSE; + OnStopStreaming(); + timeEndPeriod(1); + } + return NOERROR; +} + + +// We have a boolean flag that is reset when we have signalled EC_REPAINT to +// the filter graph. We set this when we receive an image so that should any +// conditions arise again we can send another one. By having a flag we ensure +// we don't flood the filter graph with redundant calls. We do not set the +// event when we receive an EndOfStream call since there is no point in us +// sending further EC_REPAINTs. In particular the AutoShowWindow method and +// the DirectDraw object use this method to control the window repainting + +void CBaseRenderer::SetRepaintStatus(BOOL bRepaint) +{ + CAutoLock cSampleLock(&m_RendererLock); + m_bRepaintStatus = bRepaint; +} + + +// Pass the window handle to the upstream filter + +void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd) +{ + IMediaEventSink *pSink; + + // Does the pin support IMediaEventSink + HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink); + if (SUCCEEDED(hr)) { + pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); + pSink->Release(); + } + NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); +} + + +// Signal an EC_REPAINT to the filter graph. This can be used to have data +// sent to us. For example when a video window is first displayed it may +// not have an image to display, at which point it signals EC_REPAINT. The +// filtergraph will either pause the graph if stopped or if already paused +// it will call put_CurrentPosition of the current position. Setting the +// current position to itself has the stream flushed and the image resent + +#define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_))); + +void CBaseRenderer::SendRepaint() +{ + CAutoLock cSampleLock(&m_RendererLock); + ASSERT(m_pInputPin); + + // We should not send repaint notifications when... + // - An end of stream has been notified + // - Our input pin is being flushed + // - The input pin is not connected + // - We have aborted a video playback + // - There is a repaint already sent + + if (m_bAbort == FALSE) { + if (m_pInputPin->IsConnected() == TRUE) { + if (m_pInputPin->IsFlushing() == FALSE) { + if (IsEndOfStream() == FALSE) { + if (m_bRepaintStatus == TRUE) { + IPin *pPin = (IPin *) m_pInputPin; + NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0); + SetRepaintStatus(FALSE); + RLOG("Sending repaint"); + } + } + } + } + } +} + + +// When a video window detects a display change (WM_DISPLAYCHANGE message) it +// can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The +// filtergraph will stop everyone and reconnect our input pin. As we're then +// reconnected we can accept the media type that matches the new display mode +// since we may no longer be able to draw the current image type efficiently + +BOOL CBaseRenderer::OnDisplayChange() +{ + // Ignore if we are not connected yet + + CAutoLock cSampleLock(&m_RendererLock); + if (m_pInputPin->IsConnected() == FALSE) { + return FALSE; + } + + RLOG("Notification of EC_DISPLAY_CHANGE"); + + // Pass our input pin as parameter on the event + + IPin *pPin = (IPin *) m_pInputPin; + m_pInputPin->AddRef(); + NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0); + SetAbortSignal(TRUE); + ClearPendingSample(); + m_pInputPin->Release(); + + return TRUE; +} + + +// Called just before we start drawing. +// Store the current time in m_trRenderStart to allow the rendering time to be +// logged. Log the time stamp of the sample and how late it is (neg is early) + +void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample) +{ +#ifdef PERF + REFERENCE_TIME trStart, trEnd; + pMediaSample->GetTime(&trStart, &trEnd); + + MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits + + m_pClock->GetTime(&m_trRenderStart); + MSR_INTEGER(0, (int)m_trRenderStart); + REFERENCE_TIME trStream; + trStream = m_trRenderStart-m_tStart; // convert reftime to stream time + MSR_INTEGER(0,(int)trStream); + + const int trLate = (int)(trStream - trStart); + MSR_INTEGER(m_idBaseAccuracy, trLate/10000); // dump in mSec +#endif + +} // OnRenderStart + + +// Called directly after drawing an image. +// calculate the time spent drawing and log it. + +void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample) +{ +#ifdef PERF + REFERENCE_TIME trNow; + m_pClock->GetTime(&trNow); + MSR_INTEGER(0,(int)trNow); + int t = (int)((trNow - m_trRenderStart)/10000); // convert UNITS->msec + MSR_INTEGER(m_idBaseRenderTime, t); +#endif +} // OnRenderEnd + + + + +// Constructor must be passed the base renderer object + +CRendererInputPin::CRendererInputPin(__inout CBaseRenderer *pRenderer, + __inout HRESULT *phr, + __in_opt LPCWSTR pPinName) : + CBaseInputPin(NAME("Renderer pin"), + pRenderer, + &pRenderer->m_InterfaceLock, + (HRESULT *) phr, + pPinName) +{ + m_pRenderer = pRenderer; + ASSERT(m_pRenderer); +} + + +// Signals end of data stream on the input pin + +STDMETHODIMP CRendererInputPin::EndOfStream() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + + // Make sure we're streaming ok + + HRESULT hr = CheckStreaming(); + if (hr != NOERROR) { + return hr; + } + + // Pass it onto the renderer + + hr = m_pRenderer->EndOfStream(); + if (SUCCEEDED(hr)) { + hr = CBaseInputPin::EndOfStream(); + } + return hr; +} + + +// Signals start of flushing on the input pin - we do the final reset end of +// stream with the renderer lock unlocked but with the interface lock locked +// We must do this because we call timeKillEvent, our timer callback method +// has to take the renderer lock to serialise our state. Therefore holding a +// renderer lock when calling timeKillEvent could cause a deadlock condition + +STDMETHODIMP CRendererInputPin::BeginFlush() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + { + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + CBaseInputPin::BeginFlush(); + m_pRenderer->BeginFlush(); + } + return m_pRenderer->ResetEndOfStream(); +} + + +// Signals end of flushing on the input pin + +STDMETHODIMP CRendererInputPin::EndFlush() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + + HRESULT hr = m_pRenderer->EndFlush(); + if (SUCCEEDED(hr)) { + hr = CBaseInputPin::EndFlush(); + } + return hr; +} + + +// Pass the sample straight through to the renderer object + +STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample) +{ + HRESULT hr = m_pRenderer->Receive(pSample); + if (FAILED(hr)) { + + // A deadlock could occur if the caller holds the renderer lock and + // attempts to acquire the interface lock. + ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock)); + + { + // The interface lock must be held when the filter is calling + // IsStopped() or IsFlushing(). The interface lock must also + // be held because the function uses m_bRunTimeError. + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + + // We do not report errors which occur while the filter is stopping, + // flushing or if the m_bAbort flag is set . Errors are expected to + // occur during these operations and the streaming thread correctly + // handles the errors. + if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) { + + // EC_ERRORABORT's first parameter is the error which caused + // the event and its' last parameter is 0. See the Direct + // Show SDK documentation for more information. + m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0); + + { + CAutoLock alRendererLock(&m_pRenderer->m_RendererLock); + if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) { + m_pRenderer->NotifyEndOfStream(); + } + } + + m_bRunTimeError = TRUE; + } + } + } + + return hr; +} + + +// Called when the input pin is disconnected + +HRESULT CRendererInputPin::BreakConnect() +{ + HRESULT hr = m_pRenderer->BreakConnect(); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::BreakConnect(); +} + + +// Called when the input pin is connected + +HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CompleteConnect(pReceivePin); +} + + +// Give the pin id of our one and only pin + +STDMETHODIMP CRendererInputPin::QueryId(__deref_out LPWSTR *Id) +{ + CheckPointer(Id,E_POINTER); + + const WCHAR szIn[] = L"In"; + + *Id = (LPWSTR)CoTaskMemAlloc(sizeof(szIn)); + if (*Id == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(*Id, szIn, sizeof(szIn)); + return NOERROR; +} + + +// Will the filter accept this media type + +HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt) +{ + return m_pRenderer->CheckMediaType(pmt); +} + + +// Called when we go paused or running + +HRESULT CRendererInputPin::Active() +{ + return m_pRenderer->Active(); +} + + +// Called when we go into a stopped state + +HRESULT CRendererInputPin::Inactive() +{ + // The caller must hold the interface lock because + // this function uses m_bRunTimeError. + ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock)); + + m_bRunTimeError = FALSE; + + return m_pRenderer->Inactive(); +} + + +// Tell derived classes about the media type agreed + +HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt) +{ + HRESULT hr = CBaseInputPin::SetMediaType(pmt); + if (FAILED(hr)) { + return hr; + } + return m_pRenderer->SetMediaType(pmt); +} + + +// We do not keep an event object to use when setting up a timer link with +// the clock but are given a pointer to one by the owning object through the +// SetNotificationObject method - this must be initialised before starting +// We can override the default quality management process to have it always +// draw late frames, this is currently done by having the following registry +// key (actually an INI key) called DrawLateFrames set to 1 (default is 0) + +const TCHAR AMQUALITY[] = TEXT("ActiveMovie"); +const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames"); + +CBaseVideoRenderer::CBaseVideoRenderer( + REFCLSID RenderClass, // CLSID for this renderer + __in_opt LPCTSTR pName, // Debug ONLY description + __inout_opt LPUNKNOWN pUnk, // Aggregated owner object + __inout HRESULT *phr) : // General OLE return code + + CBaseRenderer(RenderClass,pName,pUnk,phr), + m_cFramesDropped(0), + m_cFramesDrawn(0), + m_bSupplierHandlingQuality(FALSE) +{ + ResetStreamingTimes(); + +#ifdef PERF + m_idTimeStamp = MSR_REGISTER(TEXT("Frame time stamp")); + m_idEarliness = MSR_REGISTER(TEXT("Earliness fudge")); + m_idTarget = MSR_REGISTER(TEXT("Target (mSec)")); + m_idSchLateTime = MSR_REGISTER(TEXT("mSec late when scheduled")); + m_idDecision = MSR_REGISTER(TEXT("Scheduler decision code")); + m_idQualityRate = MSR_REGISTER(TEXT("Quality rate sent")); + m_idQualityTime = MSR_REGISTER(TEXT("Quality time sent")); + m_idWaitReal = MSR_REGISTER(TEXT("Render wait")); + // m_idWait = MSR_REGISTER(TEXT("wait time recorded (msec)")); + m_idFrameAccuracy = MSR_REGISTER(TEXT("Frame accuracy (msecs)")); + m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE); + //m_idSendQuality = MSR_REGISTER(TEXT("Processing Quality message")); + + m_idRenderAvg = MSR_REGISTER(TEXT("Render draw time Avg")); + m_idFrameAvg = MSR_REGISTER(TEXT("FrameAvg")); + m_idWaitAvg = MSR_REGISTER(TEXT("WaitAvg")); + m_idDuration = MSR_REGISTER(TEXT("Duration")); + m_idThrottle = MSR_REGISTER(TEXT("Audio-video throttle wait")); + // m_idDebug = MSR_REGISTER(TEXT("Debug stuff")); +#endif // PERF +} // Constructor + + +// Destructor is just a placeholder + +CBaseVideoRenderer::~CBaseVideoRenderer() +{ + ASSERT(m_dwAdvise == 0); +} + + +// The timing functions in this class are called by the window object and by +// the renderer's allocator. +// The windows object calls timing functions as it receives media sample +// images for drawing using GDI. +// The allocator calls timing functions when it starts passing DCI/DirectDraw +// surfaces which are not rendered in the same way; The decompressor writes +// directly to the surface with no separate rendering, so those code paths +// call direct into us. Since we only ever hand out DCI/DirectDraw surfaces +// when we have allocated one and only one image we know there cannot be any +// conflict between the two. +// +// We use timeGetTime to return the timing counts we use (since it's relative +// performance we are interested in rather than absolute compared to a clock) +// The window object sets the accuracy of the system clock (normally 1ms) by +// calling timeBeginPeriod/timeEndPeriod when it changes streaming states + + +// Reset all times controlling streaming. +// Set them so that +// 1. Frames will not initially be dropped +// 2. The first frame will definitely be drawn (achieved by saying that there +// has not ben a frame drawn for a long time). + +HRESULT CBaseVideoRenderer::ResetStreamingTimes() +{ + m_trLastDraw = -1000; // set up as first frame since ages (1 sec) ago + m_tStreamingStart = timeGetTime(); + m_trRenderAvg = 0; + m_trFrameAvg = -1; // -1000 fps == "unset" + m_trDuration = 0; // 0 - strange value + m_trRenderLast = 0; + m_trWaitAvg = 0; + m_tRenderStart = 0; + m_cFramesDrawn = 0; + m_cFramesDropped = 0; + m_iTotAcc = 0; + m_iSumSqAcc = 0; + m_iSumSqFrameTime = 0; + m_trFrame = 0; // hygeine - not really needed + m_trLate = 0; // hygeine - not really needed + m_iSumFrameTime = 0; + m_nNormal = 0; + m_trEarliness = 0; + m_trTarget = -300000; // 30mSec early + m_trThrottle = 0; + m_trRememberStampForPerf = 0; + +#ifdef PERF + m_trRememberFrameForPerf = 0; +#endif + + return NOERROR; +} // ResetStreamingTimes + + +// Reset all times controlling streaming. Note that we're now streaming. We +// don't need to set the rendering event to have the source filter released +// as it is done during the Run processing. When we are run we immediately +// release the source filter thread and draw any image waiting (that image +// may already have been drawn once as a poster frame while we were paused) + +HRESULT CBaseVideoRenderer::OnStartStreaming() +{ + ResetStreamingTimes(); + return NOERROR; +} // OnStartStreaming + + +// Called at end of streaming. Fixes times for property page report + +HRESULT CBaseVideoRenderer::OnStopStreaming() +{ + m_tStreamingStart = timeGetTime()-m_tStreamingStart; + return NOERROR; +} // OnStopStreaming + + +// Called when we start waiting for a rendering event. +// Used to update times spent waiting and not waiting. + +void CBaseVideoRenderer::OnWaitStart() +{ + MSR_START(m_idWaitReal); +} // OnWaitStart + + +// Called when we are awoken from the wait in the window OR by our allocator +// when it is hanging around until the next sample is due for rendering on a +// DCI/DirectDraw surface. We add the wait time into our rolling average. +// We grab the interface lock so that we're serialised with the application +// thread going through the run code - which in due course ends up calling +// ResetStreaming times - possibly as we run through this section of code + +void CBaseVideoRenderer::OnWaitEnd() +{ +#ifdef PERF + MSR_STOP(m_idWaitReal); + // for a perf build we want to know just exactly how late we REALLY are. + // even if this means that we have to look at the clock again. + + REFERENCE_TIME trRealStream; // the real time now expressed as stream time. +#if 0 + m_pClock->GetTime(&trRealStream); // Calling clock here causes W95 deadlock! +#else + // We will be discarding overflows like mad here! + // This is wrong really because timeGetTime() can wrap but it's + // only for PERF + REFERENCE_TIME tr = timeGetTime()*10000; + trRealStream = tr + m_llTimeOffset; +#endif + trRealStream -= m_tStart; // convert to stream time (this is a reftime) + + if (m_trRememberStampForPerf==0) { + // This is probably the poster frame at the start, and it is not scheduled + // in the usual way at all. Just count it. The rememberstamp gets set + // in ShouldDrawSampleNow, so this does invalid frame recording until we + // actually start playing. + PreparePerformanceData(0, 0); + } else { + int trLate = (int)(trRealStream - m_trRememberStampForPerf); + int trFrame = (int)(tr - m_trRememberFrameForPerf); + PreparePerformanceData(trLate, trFrame); + } + m_trRememberFrameForPerf = tr; +#endif //PERF +} // OnWaitEnd + + +// Put data on one side that describes the lateness of the current frame. +// We don't yet know whether it will actually be drawn. In direct draw mode, +// this decision is up to the filter upstream, and it could change its mind. +// The rules say that if it did draw it must call Receive(). One way or +// another we eventually get into either OnRenderStart or OnDirectRender and +// these both call RecordFrameLateness to update the statistics. + +void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame) +{ + m_trLate = trLate; + m_trFrame = trFrame; +} // PreparePerformanceData + + +// update the statistics: +// m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn +// Note that because the properties page reports using these variables, +// 1. We need to be inside a critical section +// 2. They must all be updated together. Updating the sums here and the count +// elsewhere can result in imaginary jitter (i.e. attempts to find square roots +// of negative numbers) in the property page code. + +void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame) +{ + // Record how timely we are. + int tLate = trLate/10000; + + // Best estimate of moment of appearing on the screen is average of + // start and end draw times. Here we have only the end time. This may + // tend to show us as spuriously late by up to 1/2 frame rate achieved. + // Decoder probably monitors draw time. We don't bother. + MSR_INTEGER( m_idFrameAccuracy, tLate ); + + // This is a kludge - we can get frames that are very late + // especially (at start-up) and they invalidate the statistics. + // So ignore things that are more than 1 sec off. + if (tLate>1000 || tLate<-1000) { + if (m_cFramesDrawn<=1) { + tLate = 0; + } else if (tLate>0) { + tLate = 1000; + } else { + tLate = -1000; + } + } + // The very first frame often has a invalid time, so don't + // count it into the statistics. (???) + if (m_cFramesDrawn>1) { + m_iTotAcc += tLate; + m_iSumSqAcc += (tLate*tLate); + } + + // calculate inter-frame time. Doesn't make sense for first frame + // second frame suffers from invalid first frame stamp. + if (m_cFramesDrawn>2) { + int tFrame = trFrame/10000; // convert to mSec else it overflows + + // This is a kludge. It can overflow anyway (a pause can cause + // a very long inter-frame time) and it overflows at 2**31/10**7 + // or about 215 seconds i.e. 3min 35sec + if (tFrame>1000||tFrame<0) tFrame = 1000; + m_iSumSqFrameTime += tFrame*tFrame; + ASSERT(m_iSumSqFrameTime>=0); + m_iSumFrameTime += tFrame; + } + ++m_cFramesDrawn; + +} // RecordFrameLateness + + +void CBaseVideoRenderer::ThrottleWait() +{ + if (m_trThrottle>0) { + int iThrottle = m_trThrottle/10000; // convert to mSec + MSR_INTEGER( m_idThrottle, iThrottle); + DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle)); + Sleep(iThrottle); + } else { + Sleep(0); + } +} // ThrottleWait + + +// Whenever a frame is rendered it goes though either OnRenderStart +// or OnDirectRender. Data that are generated during ShouldDrawSample +// are added to the statistics by calling RecordFrameLateness from both +// these two places. + +// Called in place of OnRenderStart..OnRenderEnd +// When a DirectDraw image is drawn +void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample) +{ + m_trRenderAvg = 0; + m_trRenderLast = 5000000; // If we mode switch, we do NOT want this + // to inhibit the new average getting going! + // so we set it to half a second + // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); + RecordFrameLateness(m_trLate, m_trFrame); + ThrottleWait(); +} // OnDirectRender + + +// Called just before we start drawing. All we do is to get the current clock +// time (from the system) and return. We have to store the start render time +// in a member variable because it isn't used until we complete the drawing +// The rest is just performance logging. + +void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample) +{ + RecordFrameLateness(m_trLate, m_trFrame); + m_tRenderStart = timeGetTime(); +} // OnRenderStart + + +// Called directly after drawing an image. We calculate the time spent in the +// drawing code and if this doesn't appear to have any odd looking spikes in +// it then we add it to the current average draw time. Measurement spikes may +// occur if the drawing thread is interrupted and switched to somewhere else. + +void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample) +{ + // The renderer time can vary erratically if we are interrupted so we do + // some smoothing to help get more sensible figures out but even that is + // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83 + + int tr = (timeGetTime() - m_tRenderStart)*10000; // convert mSec->UNITS + if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) { + // DO_MOVING_AVG(m_trRenderAvg, tr); + m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD; + } + m_trRenderLast = tr; + ThrottleWait(); +} // OnRenderEnd + + +STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc) +{ + + m_pQSink = piqc; + + return NOERROR; +} // SetSink + + +STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q) +{ + // NOTE: We are NOT getting any locks here. We could be called + // asynchronously and possibly even on a time critical thread of + // someone else's - so we do the minumum. We only set one state + // variable (an integer) and if that happens to be in the middle + // of another thread reading it they will just get either the new + // or the old value. Locking would achieve no more than this. + + // It might be nice to check that we are being called from m_pGraph, but + // it turns out to be a millisecond or so per throw! + + // This is heuristics, these numbers are aimed at being "what works" + // rather than anything based on some theory. + // We use a hyperbola because it's easy to calculate and it includes + // a panic button asymptote (which we push off just to the left) + // The throttling fits the following table (roughly) + // Proportion Throttle (msec) + // >=1000 0 + // 900 3 + // 800 7 + // 700 11 + // 600 17 + // 500 25 + // 400 35 + // 300 50 + // 200 72 + // 125 100 + // 100 112 + // 50 146 + // 0 200 + + // (some evidence that we could go for a sharper kink - e.g. no throttling + // until below the 750 mark - might give fractionally more frames on a + // P60-ish machine). The easy way to get these coefficients is to use + // Renbase.xls follow the instructions therein using excel solver. + + if (q.Proportion>=1000) { m_trThrottle = 0; } + else { + // The DWORD is to make quite sure I get unsigned arithmetic + // as the constant is between 2**31 and 2**32 + m_trThrottle = -330000 + (388880000/(q.Proportion+167)); + } + return NOERROR; +} // Notify + + +// Send a message to indicate what our supplier should do about quality. +// Theory: +// What a supplier wants to know is "is the frame I'm working on NOW +// going to be late?". +// F1 is the frame at the supplier (as above) +// Tf1 is the due time for F1 +// T1 is the time at that point (NOW!) +// Tr1 is the time that f1 WILL actually be rendered +// L1 is the latency of the graph for frame F1 = Tr1-T1 +// D1 (for delay) is how late F1 will be beyond its due time i.e. +// D1 = (Tr1-Tf1) which is what the supplier really wants to know. +// Unfortunately Tr1 is in the future and is unknown, so is L1 +// +// We could estimate L1 by its value for a previous frame, +// L0 = Tr0-T0 and work off +// D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1) +// Rearranging terms: +// D1' = (T1-T0) + (Tr0-Tf1) +// adding (Tf0-Tf0) and rearranging again: +// = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1) +// = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0) +// But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the +// Late field in the quality message that we send. +// The other two terms just state what correction should be applied before +// using the lateness of F0 to predict the lateness of F1. +// (T1-T0) says how much time has actually passed (we have lost this much) +// (Tf1-Tf0) says how much time should have passed if we were keeping pace +// (we have gained this much). +// +// Suppliers should therefore work off: +// Quality.Late + (T1-T0) - (Tf1-Tf0) +// and see if this is "acceptably late" or even early (i.e. negative). +// They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from +// the time stamps in the frames. They get Quality.Late from us. +// + +HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate, + REFERENCE_TIME trRealStream) +{ + Quality q; + HRESULT hr; + + // If we are the main user of time, then report this as Flood/Dry. + // If our suppliers are, then report it as Famine/Glut. + // + // We need to take action, but avoid hunting. Hunting is caused by + // 1. Taking too much action too soon and overshooting + // 2. Taking too long to react (so averaging can CAUSE hunting). + // + // The reason why we use trLate as well as Wait is to reduce hunting; + // if the wait time is coming down and about to go into the red, we do + // NOT want to rely on some average which is only telling is that it used + // to be OK once. + + q.TimeStamp = (REFERENCE_TIME)trRealStream; + + if (m_trFrameAvg<0) { + q.Type = Famine; // guess + } + // Is the greater part of the time taken bltting or something else + else if (m_trFrameAvg > 2*m_trRenderAvg) { + q.Type = Famine; // mainly other + } else { + q.Type = Flood; // mainly bltting + } + + q.Proportion = 1000; // default + + if (m_trFrameAvg<0) { + // leave it alone - we don't know enough + } + else if ( trLate> 0 ) { + // try to catch up over the next second + // We could be Really, REALLY late, but rendering all the frames + // anyway, just because it's so cheap. + + q.Proportion = 1000 - (int)((trLate)/(UNITS/1000)); + if (q.Proportion<500) { + q.Proportion = 500; // don't go daft. (could've been negative!) + } else { + } + + } else if ( m_trWaitAvg>20000 + && trLate<-20000 + ){ + // Go cautiously faster - aim at 2mSec wait. + if (m_trWaitAvg>=m_trFrameAvg) { + // This can happen because of some fudges. + // The waitAvg is how long we originally planned to wait + // The frameAvg is more honest. + // It means that we are spending a LOT of time waiting + q.Proportion = 2000; // double. + } else { + if (m_trFrameAvg+20000 > m_trWaitAvg) { + q.Proportion + = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg)); + } else { + // We're apparently spending more than the whole frame time waiting. + // Assume that the averages are slightly out of kilter, but that we + // are indeed doing a lot of waiting. (This leg probably never + // happens, but the code avoids any potential divide by zero). + q.Proportion = 2000; + } + } + + if (q.Proportion>2000) { + q.Proportion = 2000; // don't go crazy. + } + } + + // Tell the supplier how late frames are when they get rendered + // That's how late we are now. + // If we are in directdraw mode then the guy upstream can see the drawing + // times and we'll just report on the start time. He can figure out any + // offset to apply. If we are in DIB Section mode then we will apply an + // extra offset which is half of our drawing time. This is usually small + // but can sometimes be the dominant effect. For this we will use the + // average drawing time rather than the last frame. If the last frame took + // a long time to draw and made us late, that's already in the lateness + // figure. We should not add it in again unless we expect the next frame + // to be the same. We don't, we expect the average to be a better shot. + // In direct draw mode the RenderAvg will be zero. + + q.Late = trLate + m_trRenderAvg/2; + + // log what we're doing + MSR_INTEGER(m_idQualityRate, q.Proportion); + MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 ); + + // A specific sink interface may be set through IPin + + if (m_pQSink==NULL) { + // Get our input pin's peer. We send quality management messages + // to any nominated receiver of these things (set in the IPin + // interface), or else to our source filter. + + IQualityControl *pQC = NULL; + IPin *pOutputPin = m_pInputPin->GetConnected(); + ASSERT(pOutputPin != NULL); + + // And get an AddRef'd quality control interface + + hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC); + if (SUCCEEDED(hr)) { + m_pQSink = pQC; + } + } + if (m_pQSink) { + return m_pQSink->Notify(this,q); + } + + return S_FALSE; + +} // SendQuality + + +// We are called with a valid IMediaSample image to decide whether this is to +// be drawn or not. There must be a reference clock in operation. +// Return S_OK if it is to be drawn Now (as soon as possible) +// Return S_FALSE if it is to be drawn when it's due +// Return an error if we want to drop it +// m_nNormal=-1 indicates that we dropped the previous frame and so this +// one should be drawn early. Respect it and update it. +// Use current stream time plus a number of heuristics (detailed below) +// to make the decision + +HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, + __inout REFERENCE_TIME *ptrStart, + __inout REFERENCE_TIME *ptrEnd) +{ + + // Don't call us unless there's a clock interface to synchronise with + ASSERT(m_pClock); + + MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32)); // high order 32 bits + MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart)); // low order 32 bits + + // We lose a bit of time depending on the monitor type waiting for the next + // screen refresh. On average this might be about 8mSec - so it will be + // later than we think when the picture appears. To compensate a bit + // we bias the media samples by -8mSec i.e. 80000 UNITs. + // We don't ever make a stream time negative (call it paranoia) + if (*ptrStart>=80000) { + *ptrStart -= 80000; + *ptrEnd -= 80000; // bias stop to to retain valid frame duration + } + + // Cache the time stamp now. We will want to compare what we did with what + // we started with (after making the monitor allowance). + m_trRememberStampForPerf = *ptrStart; + + // Get reference times (current and late) + REFERENCE_TIME trRealStream; // the real time now expressed as stream time. + m_pClock->GetTime(&trRealStream); +#ifdef PERF + // While the reference clock is expensive: + // Remember the offset from timeGetTime and use that. + // This overflows all over the place, but when we subtract to get + // differences the overflows all cancel out. + m_llTimeOffset = trRealStream-timeGetTime()*10000; +#endif + trRealStream -= m_tStart; // convert to stream time (this is a reftime) + + // We have to wory about two versions of "lateness". The truth, which we + // try to work out here and the one measured against m_trTarget which + // includes long term feedback. We report statistics against the truth + // but for operational decisions we work to the target. + // We use TimeDiff to make sure we get an integer because we + // may actually be late (or more likely early if there is a big time + // gap) by a very long time. + const int trTrueLate = TimeDiff(trRealStream - *ptrStart); + const int trLate = trTrueLate; + + MSR_INTEGER(m_idSchLateTime, trTrueLate/10000); + + // Send quality control messages upstream, measured against target + HRESULT hr = SendQuality(trLate, trRealStream); + // Note: the filter upstream is allowed to this FAIL meaning "you do it". + m_bSupplierHandlingQuality = (hr==S_OK); + + // Decision time! Do we drop, draw when ready or draw immediately? + + const int trDuration = (int)(*ptrEnd - *ptrStart); + { + // We need to see if the frame rate of the file has just changed. + // This would make comparing our previous frame rate with the current + // frame rate inefficent. Hang on a moment though. I've seen files + // where the frames vary between 33 and 34 mSec so as to average + // 30fps. A minor variation like that won't hurt us. + int t = m_trDuration/32; + if ( trDuration > m_trDuration+t + || trDuration < m_trDuration-t + ) { + // There's a major variation. Reset the average frame rate to + // exactly the current rate to disable decision 9002 for this frame, + // and remember the new rate. + m_trFrameAvg = trDuration; + m_trDuration = trDuration; + } + } + + MSR_INTEGER(m_idEarliness, m_trEarliness/10000); + MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); + MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000); + MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000); + MSR_INTEGER(m_idDuration, trDuration/10000); + +#ifdef PERF + if (S_OK==pMediaSample->IsDiscontinuity()) { + MSR_INTEGER(m_idDecision, 9000); + } +#endif + + // Control the graceful slide back from slow to fast machine mode. + // After a frame drop accept an early frame and set the earliness to here + // If this frame is already later than the earliness then slide it to here + // otherwise do the standard slide (reduce by about 12% per frame). + // Note: earliness is normally NEGATIVE + BOOL bJustDroppedFrame + = ( m_bSupplierHandlingQuality + // Can't use the pin sample properties because we might + // not be in Receive when we call this + && (S_OK == pMediaSample->IsDiscontinuity()) // he just dropped one + ) + || (m_nNormal==-1); // we just dropped one + + + // Set m_trEarliness (slide back from slow to fast machine mode) + if (trLate>0) { + m_trEarliness = 0; // we are no longer in fast machine mode at all! + } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) { + m_trEarliness = trLate; // Things have slipped of their own accord + } else { + m_trEarliness = m_trEarliness - m_trEarliness/8; // graceful slide + } + + // prepare the new wait average - but don't pollute the old one until + // we have finished with it. + int trWaitAvg; + { + // We never mix in a negative wait. This causes us to believe in fast machines + // slightly more. + int trL = trLate<0 ? -trLate : 0; + trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; + } + + + int trFrame; + { + REFERENCE_TIME tr = trRealStream - m_trLastDraw; // Cd be large - 4 min pause! + if (tr>10000000) { + tr = 10000000; // 1 second - arbitrarily. + } + trFrame = int(tr); + } + + // We will DRAW this frame IF... + if ( + // ...the time we are spending drawing is a small fraction of the total + // observed inter-frame time so that dropping it won't help much. + (3*m_trRenderAvg <= m_trFrameAvg) + + // ...or our supplier is NOT handling things and the next frame would + // be less timely than this one or our supplier CLAIMS to be handling + // things, and is now less than a full FOUR frames late. + || ( m_bSupplierHandlingQuality + ? (trLate <= trDuration*4) + : (trLate+trLate < trDuration) + ) + + // ...or we are on average waiting for over eight milliseconds then + // this may be just a glitch. Draw it and we'll hope to catch up. + || (m_trWaitAvg > 80000) + + // ...or we haven't drawn an image for over a second. We will update + // the display, which stops the video looking hung. + // Do this regardless of how late this media sample is. + || ((trRealStream - m_trLastDraw) > UNITS) + + ) { + HRESULT Result; + + // We are going to play this frame. We may want to play it early. + // We will play it early if we think we are in slow machine mode. + // If we think we are NOT in slow machine mode, we will still play + // it early by m_trEarliness as this controls the graceful slide back. + // and in addition we aim at being m_trTarget late rather than "on time". + + BOOL bPlayASAP = FALSE; + + // we will play it AT ONCE (slow machine mode) if... + + // ...we are playing catch-up + if ( bJustDroppedFrame) { + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9001); + } + + // ...or if we are running below the true frame rate + // exact comparisons are glitchy, for these measurements, + // so add an extra 5% or so + else if ( (m_trFrameAvg > trDuration + trDuration/16) + + // It's possible to get into a state where we are losing ground, but + // are a very long way ahead. To avoid this or recover from it + // we refuse to play early by more than 10 frames. + && (trLate > - trDuration*10) + ){ + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9002); + } +#if 0 + // ...or if we have been late and are less than one frame early + else if ( (trLate + trDuration > 0) + && (m_trWaitAvg<=20000) + ) { + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9003); + } +#endif + // We will NOT play it at once if we are grossly early. On very slow frame + // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just + // because we got starved (for instance by the net) and dropped one frame + // some time or other. If we are more than 900mSec early, then wait. + if (trLate<-9000000) { + bPlayASAP = FALSE; + } + + if (bPlayASAP) { + + m_nNormal = 0; + MSR_INTEGER(m_idDecision, 0); + // When we are here, we are in slow-machine mode. trLate may well + // oscillate between negative and positive when the supplier is + // dropping frames to keep sync. We should not let that mislead + // us into thinking that we have as much as zero spare time! + // We just update with a zero wait. + m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; + + // Assume that we draw it immediately. Update inter-frame stats + m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD; +#ifndef PERF + // If this is NOT a perf build, then report what we know so far + // without looking at the clock any more. This assumes that we + // actually wait for exactly the time we hope to. It also reports + // how close we get to the manipulated time stamps that we now have + // rather than the ones we originally started with. It will + // therefore be a little optimistic. However it's fast. + PreparePerformanceData(trTrueLate, trFrame); +#endif + m_trLastDraw = trRealStream; + if (m_trEarliness > trLate) { + m_trEarliness = trLate; // if we are actually early, this is neg + } + Result = S_OK; // Draw it now + + } else { + ++m_nNormal; + // Set the average frame rate to EXACTLY the ideal rate. + // If we are exiting slow-machine mode then we will have caught up + // and be running ahead, so as we slide back to exact timing we will + // have a longer than usual gap at this point. If we record this + // real gap then we'll think that we're running slow and go back + // into slow-machine mode and vever get it straight. + m_trFrameAvg = trDuration; + MSR_INTEGER(m_idDecision, 1); + + // Play it early by m_trEarliness and by m_trTarget + + { + int trE = m_trEarliness; + if (trE < -m_trFrameAvg) { + trE = -m_trFrameAvg; + } + *ptrStart += trE; // N.B. earliness is negative + } + + int Delay = -trTrueLate; + Result = Delay<=0 ? S_OK : S_FALSE; // OK = draw now, FALSE = wait + + m_trWaitAvg = trWaitAvg; + + // Predict when it will actually be drawn and update frame stats + + if (Result==S_FALSE) { // We are going to wait + trFrame = TimeDiff(*ptrStart-m_trLastDraw); + m_trLastDraw = *ptrStart; + } else { + // trFrame is already = trRealStream-m_trLastDraw; + m_trLastDraw = trRealStream; + } +#ifndef PERF + int iAccuracy; + if (Delay>0) { + // Report lateness based on when we intend to play it + iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf); + } else { + // Report lateness based on playing it *now*. + iAccuracy = trTrueLate; // trRealStream-RememberStampForPerf; + } + PreparePerformanceData(iAccuracy, trFrame); +#endif + } + return Result; + } + + // We are going to drop this frame! + // Of course in DirectDraw mode the guy upstream may draw it anyway. + + // This will probably give a large negative wack to the wait avg. + m_trWaitAvg = trWaitAvg; + +#ifdef PERF + // Respect registry setting - debug only! + if (m_bDrawLateFrames) { + return S_OK; // draw it when it's ready + } // even though it's late. +#endif + + // We are going to drop this frame so draw the next one early + // n.b. if the supplier is doing direct draw then he may draw it anyway + // but he's doing something funny to arrive here in that case. + + MSR_INTEGER(m_idDecision, 2); + m_nNormal = -1; + return E_FAIL; // drop it + +} // ShouldDrawSampleNow + + +// NOTE we're called by both the window thread and the source filter thread +// so we have to be protected by a critical section (locked before called) +// Also, when the window thread gets signalled to render an image, it always +// does so regardless of how late it is. All the degradation is done when we +// are scheduling the next sample to be drawn. Hence when we start an advise +// link to draw a sample, that sample's time will always become the last one +// drawn - unless of course we stop streaming in which case we cancel links + +BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample) +{ + // We override ShouldDrawSampleNow to add quality management + + BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample); + if (bDrawImage == FALSE) { + ++m_cFramesDropped; + return FALSE; + } + + // m_cFramesDrawn must NOT be updated here. It has to be updated + // in RecordFrameLateness at the same time as the other statistics. + return TRUE; +} + + +// Implementation of IQualProp interface needed to support the property page +// This is how the property page gets the data out of the scheduler. We are +// passed into the constructor the owning object in the COM sense, this will +// either be the video renderer or an external IUnknown if we're aggregated. +// We initialise our CUnknown base class with this interface pointer. Then +// all we have to do is to override NonDelegatingQueryInterface to expose +// our IQualProp interface. The AddRef and Release are handled automatically +// by the base class and will be passed on to the appropriate outer object + +STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(__out int *pcFramesDropped) +{ + CheckPointer(pcFramesDropped,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + *pcFramesDropped = m_cFramesDropped; + return NOERROR; +} // get_FramesDroppedInRenderer + + +// Set *pcFramesDrawn to the number of frames drawn since +// streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn) +{ + CheckPointer(pcFramesDrawn,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + *pcFramesDrawn = m_cFramesDrawn; + return NOERROR; +} // get_FramesDrawn + + +// Set iAvgFrameRate to the frames per hundred secs since +// streaming started. 0 otherwise. + +STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate) +{ + CheckPointer(piAvgFrameRate,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + int t; + if (m_bStreaming) { + t = timeGetTime()-m_tStreamingStart; + } else { + t = m_tStreamingStart; + } + + if (t<=0) { + *piAvgFrameRate = 0; + ASSERT(m_cFramesDrawn == 0); + } else { + // i is frames per hundred seconds + *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t); + } + return NOERROR; +} // get_AvgFrameRate + + +// Set *piAvg to the average sync offset since streaming started +// in mSec. The sync offset is the time in mSec between when the frame +// should have been drawn and when the frame was actually drawn. + +STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset(__out int *piAvg) +{ + CheckPointer(piAvg,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + if (NULL==m_pClock) { + *piAvg = 0; + return NOERROR; + } + + // Note that we didn't gather the stats on the first frame + // so we use m_cFramesDrawn-1 here + if (m_cFramesDrawn<=1) { + *piAvg = 0; + } else { + *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1)); + } + return NOERROR; +} // get_AvgSyncOffset + + +// To avoid dragging in the maths library - a cheap +// approximate integer square root. +// We do this by getting a starting guess which is between 1 +// and 2 times too large, followed by THREE iterations of +// Newton Raphson. (That will give accuracy to the nearest mSec +// for the range in question - roughly 0..1000) +// +// It would be faster to use a linear interpolation and ONE NR, but +// who cares. If anyone does - the best linear interpolation is +// to approximates sqrt(x) by +// y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1)) +// 0r y = x*0.41421 + 0.59467 +// This minimises the maximal error in the range in question. +// (error is about +0.008883 and then one NR will give error .0000something +// (Of course these are integers, so you can't just multiply by 0.41421 +// you'd have to do some sort of MulDiv). +// Anyone wanna check my maths? (This is only for a property display!) + +int isqrt(int x) +{ + int s = 1; + // Make s an initial guess for sqrt(x) + if (x > 0x40000000) { + s = 0x8000; // prevent any conceivable closed loop + } else { + while (s*s=0) s = (s*s+x)/(2*s); + if (s>=0) s = (s*s+x)/(2*s); + } + } + return s; +} + +// +// Do estimates for standard deviations for per-frame +// statistics +// +HRESULT CBaseVideoRenderer::GetStdDev( + int nSamples, + __out int *piResult, + LONGLONG llSumSq, + LONGLONG iTot +) +{ + CheckPointer(piResult,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + if (NULL==m_pClock) { + *piResult = 0; + return NOERROR; + } + + // If S is the Sum of the Squares of observations and + // T the Total (i.e. sum) of the observations and there were + // N observations, then an estimate of the standard deviation is + // sqrt( (S - T**2/N) / (N-1) ) + + if (nSamples<=1) { + *piResult = 0; + } else { + LONGLONG x; + // First frames have invalid stamps, so we get no stats for them + // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 + + // so we use m_cFramesDrawn-1 here + x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0); + x = x / (nSamples-1); + ASSERT(x>=0); + *piResult = isqrt((LONG)x); + } + return NOERROR; +} + +// Set *piDev to the standard deviation in mSec of the sync offset +// of each frame since streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset(__out int *piDev) +{ + // First frames have invalid stamps, so we get no stats for them + // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 + return GetStdDev(m_cFramesDrawn - 1, + piDev, + m_iSumSqAcc, + m_iTotAcc); +} // get_DevSyncOffset + + +// Set *piJitter to the standard deviation in mSec of the inter-frame time +// of frames since streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_Jitter(__out int *piJitter) +{ + // First frames have invalid stamps, so we get no stats for them + // So second frame gives invalid inter-frame time + // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2 + return GetStdDev(m_cFramesDrawn - 2, + piJitter, + m_iSumSqFrameTime, + m_iSumFrameTime); +} // get_Jitter + + +// Overidden to return our IQualProp interface + +STDMETHODIMP +CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv) +{ + // We return IQualProp and delegate everything else + + if (riid == IID_IQualProp) { + return GetInterface( (IQualProp *)this, ppv); + } else if (riid == IID_IQualityControl) { + return GetInterface( (IQualityControl *)this, ppv); + } + return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv); +} + + +// Override JoinFilterGraph so that, just before leaving +// the graph we can send an EC_WINDOW_DESTROYED event + +STDMETHODIMP +CBaseVideoRenderer::JoinFilterGraph(__inout_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName) +{ + // Since we send EC_ACTIVATE, we also need to ensure + // we send EC_WINDOW_DESTROYED or the resource manager may be + // holding us as a focus object + if (!pGraph && m_pGraph) { + + // We were in a graph and now we're not + // Do this properly in case we are aggregated + IBaseFilter* pFilter = this; + NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0); + } + return CBaseFilter::JoinFilterGraph(pGraph, pName); +} + + +// This removes a large number of level 4 warnings from the +// Microsoft compiler which in this case are not very useful +#pragma warning(disable: 4514) + diff --git a/src/thirdparty/BaseClasses/renbase.h b/src/thirdparty/BaseClasses/renbase.h index 695f07837ea..5ba24d99ae1 100644 --- a/src/thirdparty/BaseClasses/renbase.h +++ b/src/thirdparty/BaseClasses/renbase.h @@ -1,478 +1,478 @@ -//------------------------------------------------------------------------------ -// File: RenBase.h -// -// Desc: DirectShow base classes - defines a generic ActiveX base renderer -// class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __RENBASE__ -#define __RENBASE__ - -// Forward class declarations - -class CBaseRenderer; -class CBaseVideoRenderer; -class CRendererInputPin; - -// This is our input pin class that channels calls to the renderer - -class CRendererInputPin : public CBaseInputPin -{ -protected: - - CBaseRenderer *m_pRenderer; - -public: - - CRendererInputPin(__inout CBaseRenderer *pRenderer, - __inout HRESULT *phr, - __in_opt LPCWSTR Name); - - // Overriden from the base pin classes - - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - HRESULT SetMediaType(const CMediaType *pmt); - HRESULT CheckMediaType(const CMediaType *pmt); - HRESULT Active(); - HRESULT Inactive(); - - // Add rendering behaviour to interface functions - - STDMETHODIMP QueryId(__deref_out LPWSTR *Id); - STDMETHODIMP EndOfStream(); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - STDMETHODIMP Receive(IMediaSample *pMediaSample); - - // Helper - IMemAllocator inline *Allocator() const - { - return m_pAllocator; - } -}; - -// Main renderer class that handles synchronisation and state changes - -class CBaseRenderer : public CBaseFilter -{ -protected: - - friend class CRendererInputPin; - - friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier - UINT uMsg, // Not currently used - DWORD_PTR dwUser, // User information - DWORD_PTR dw1, // Windows reserved - DWORD_PTR dw2); // Is also reserved - - CRendererPosPassThru *m_pPosition; // Media seeking pass by object - CAMEvent m_RenderEvent; // Used to signal timer events - CAMEvent m_ThreadSignal; // Signalled to release worker thread - CAMEvent m_evComplete; // Signalled when state complete - BOOL m_bAbort; // Stop us from rendering more data - BOOL m_bStreaming; // Are we currently streaming - DWORD_PTR m_dwAdvise; // Timer advise cookie - IMediaSample *m_pMediaSample; // Current image media sample - BOOL m_bEOS; // Any more samples in the stream - BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE - CRendererInputPin *m_pInputPin; // Our renderer input pin object - CCritSec m_InterfaceLock; // Critical section for interfaces - CCritSec m_RendererLock; // Controls access to internals - IQualityControl * m_pQSink; // QualityControl sink - BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT - // Avoid some deadlocks by tracking filter during stop - volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive - // And actually processing the sample - REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE - UINT m_EndOfStreamTimer; // Used to signal end of stream - CCritSec m_ObjectCreationLock; // This lock protects the creation and - // of m_pPosition and m_pInputPin. It - // ensures that two threads cannot create - // either object simultaneously. - -public: - - CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer - __in_opt LPCTSTR pName, // Debug ONLY description - __inout_opt LPUNKNOWN pUnk, // Aggregated owner object - __inout HRESULT *phr); // General OLE return code - - ~CBaseRenderer(); - - // Overriden to say what interfaces we support and where - - virtual HRESULT GetMediaPositionInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **); - - virtual HRESULT SourceThreadCanWait(BOOL bCanWait); - -#ifdef _DEBUG - // Debug only dump of the renderer state - void DisplayRendererState(); -#endif - virtual HRESULT WaitForRenderTime(); - virtual HRESULT CompleteStateChange(FILTER_STATE OldState); - - // Return internal information about this filter - - BOOL IsEndOfStream() { return m_bEOS; }; - BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; - BOOL IsStreaming() { return m_bStreaming; }; - void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; - virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { }; - CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; - - // Permit access to the transition state - - void Ready() { m_evComplete.Set(); }; - void NotReady() { m_evComplete.Reset(); }; - BOOL CheckReady() { return m_evComplete.Check(); }; - - virtual int GetPinCount(); - virtual CBasePin *GetPin(int n); - FILTER_STATE GetRealState(); - void SendRepaint(); - void SendNotifyWindow(IPin *pPin,HWND hwnd); - BOOL OnDisplayChange(); - void SetRepaintStatus(BOOL bRepaint); - - // Override the filter and pin interface functions - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME StartTime); - STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); - STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin); - - // These are available for a quality management implementation - - virtual void OnRenderStart(IMediaSample *pMediaSample); - virtual void OnRenderEnd(IMediaSample *pMediaSample); - virtual HRESULT OnStartStreaming() { return NOERROR; }; - virtual HRESULT OnStopStreaming() { return NOERROR; }; - virtual void OnWaitStart() { }; - virtual void OnWaitEnd() { }; - virtual void PrepareRender() { }; - -#ifdef PERF - REFERENCE_TIME m_trRenderStart; // Just before we started drawing - // Set in OnRenderStart, Used in OnRenderEnd - int m_idBaseStamp; // MSR_id for frame time stamp - int m_idBaseRenderTime; // MSR_id for true wait time - int m_idBaseAccuracy; // MSR_id for time frame is late (int) -#endif - - // Quality management implementation for scheduling rendering - - virtual BOOL ScheduleSample(IMediaSample *pMediaSample); - virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, - __out REFERENCE_TIME *pStartTime, - __out REFERENCE_TIME *pEndTime); - - virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, - __out REFERENCE_TIME *ptrStart, - __out REFERENCE_TIME *ptrEnd); - - // Lots of end of stream complexities - - void TimerCallback(); - void ResetEndOfStreamTimer(); - HRESULT NotifyEndOfStream(); - virtual HRESULT SendEndOfStream(); - virtual HRESULT ResetEndOfStream(); - virtual HRESULT EndOfStream(); - - // Rendering is based around the clock - - void SignalTimerFired(); - virtual HRESULT CancelNotification(); - virtual HRESULT ClearPendingSample(); - - // Called when the filter changes state - - virtual HRESULT Active(); - virtual HRESULT Inactive(); - virtual HRESULT StartStreaming(); - virtual HRESULT StopStreaming(); - virtual HRESULT BeginFlush(); - virtual HRESULT EndFlush(); - - // Deal with connections and type changes - - virtual HRESULT BreakConnect(); - virtual HRESULT SetMediaType(const CMediaType *pmt); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // These look after the handling of data samples - - virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); - virtual HRESULT Receive(IMediaSample *pMediaSample); - virtual BOOL HaveCurrentSample(); - virtual IMediaSample *GetCurrentSample(); - virtual HRESULT Render(IMediaSample *pMediaSample); - - // Derived classes MUST override these - virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; - virtual HRESULT CheckMediaType(const CMediaType *) PURE; - - // Helper - void WaitForReceiveToComplete(); -}; - - -// CBaseVideoRenderer is a renderer class (see its ancestor class) and -// it handles scheduling of media samples so that they are drawn at the -// correct time by the reference clock. It implements a degradation -// strategy. Possible degradation modes are: -// Drop frames here (only useful if the drawing takes significant time) -// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip. -// Signal supplier to change the frame rate - i.e. ongoing skipping. -// Or any combination of the above. -// In order to determine what's useful to try we need to know what's going -// on. This is done by timing various operations (including the supplier). -// This timing is done by using timeGetTime as it is accurate enough and -// usually cheaper than calling the reference clock. It also tells the -// truth if there is an audio break and the reference clock stops. -// We provide a number of public entry points (named OnXxxStart, OnXxxEnd) -// which the rest of the renderer calls at significant moments. These do -// the timing. - -// the number of frames that the sliding averages are averaged over. -// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD -#define AVGPERIOD 4 -#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD) -// Spot the bug in this macro - I can't. but it doesn't work! - -class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class - public IQualProp, // Property page guff - public IQualityControl // Allow throttling -{ -protected: - - // Hungarian: - // tFoo is the time Foo in mSec (beware m_tStart from filter.h) - // trBar is the time Bar by the reference clock - - //****************************************************************** - // State variables to control synchronisation - //****************************************************************** - - // Control of sending Quality messages. We need to know whether - // we are in trouble (e.g. frames being dropped) and where the time - // is being spent. - - // When we drop a frame we play the next one early. - // The frame after that is likely to wait before drawing and counting this - // wait as spare time is unfair, so we count it as a zero wait. - // We therefore need to know whether we are playing frames early or not. - - int m_nNormal; // The number of consecutive frames - // drawn at their normal time (not early) - // -1 means we just dropped a frame. - -#ifdef PERF - BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm - // not keen on people using it!) -#endif - - BOOL m_bSupplierHandlingQuality;// The response to Quality messages says - // our supplier is handling things. - // We will allow things to go extra late - // before dropping frames. We will play - // very early after he has dropped one. - - // Control of scheduling, frame dropping etc. - // We need to know where the time is being spent so as to tell whether - // we should be taking action here, signalling supplier or what. - // The variables are initialised to a mode of NOT dropping frames. - // They will tell the truth after a few frames. - // We typically record a start time for an event, later we get the time - // again and subtract to get the elapsed time, and we average this over - // a few frames. The average is used to tell what mode we are in. - - // Although these are reference times (64 bit) they are all DIFFERENCES - // between times which are small. An int will go up to 214 secs before - // overflow. Avoiding 64 bit multiplications and divisions seems - // worth while. - - - - // Audio-video throttling. If the user has turned up audio quality - // very high (in principle it could be any other stream, not just audio) - // then we can receive cries for help via the graph manager. In this case - // we put in a wait for some time after rendering each frame. - int m_trThrottle; - - // The time taken to render (i.e. BitBlt) frames controls which component - // needs to degrade. If the blt is expensive, the renderer degrades. - // If the blt is cheap it's done anyway and the supplier degrades. - int m_trRenderAvg; // Time frames are taking to blt - int m_trRenderLast; // Time for last frame blt - int m_tRenderStart; // Just before we started drawing (mSec) - // derived from timeGetTime. - - // When frames are dropped we will play the next frame as early as we can. - // If it was a false alarm and the machine is fast we slide gently back to - // normal timing. To do this, we record the offset showing just how early - // we really are. This will normally be negative meaning early or zero. - int m_trEarliness; - - // Target provides slow long-term feedback to try to reduce the - // average sync offset to zero. Whenever a frame is actually rendered - // early we add a msec or two, whenever late we take off a few. - // We add or take off 1/32 of the error time. - // Eventually we should be hovering around zero. For a really bad case - // where we were (say) 300mSec off, it might take 100 odd frames to - // settle down. The rate of change of this is intended to be slower - // than any other mechanism in Quartz, thereby avoiding hunting. - int m_trTarget; - - // The proportion of time spent waiting for the right moment to blt - // controls whether we bother to drop a frame or whether we reckon that - // we're doing well enough that we can stand a one-frame glitch. - int m_trWaitAvg; // Average of last few wait times - // (actually we just average how early - // we were). Negative here means LATE. - - // The average inter-frame time. - // This is used to calculate the proportion of the time used by the - // three operations (supplying us, waiting, rendering) - int m_trFrameAvg; // Average inter-frame time - int m_trDuration; // duration of last frame. - -#ifdef PERF - // Performance logging identifiers - int m_idTimeStamp; // MSR_id for frame time stamp - int m_idEarliness; // MSR_id for earliness fudge - int m_idTarget; // MSR_id for Target fudge - int m_idWaitReal; // MSR_id for true wait time - int m_idWait; // MSR_id for wait time recorded - int m_idFrameAccuracy; // MSR_id for time frame is late (int) - int m_idRenderAvg; // MSR_id for Render time recorded (int) - int m_idSchLateTime; // MSR_id for lateness at scheduler - int m_idQualityRate; // MSR_id for Quality rate requested - int m_idQualityTime; // MSR_id for Quality time requested - int m_idDecision; // MSR_id for decision code - int m_idDuration; // MSR_id for duration of a frame - int m_idThrottle; // MSR_id for audio-video throttling - //int m_idDebug; // MSR_id for trace style debugging - //int m_idSendQuality; // MSR_id for timing the notifications per se -#endif // PERF - REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame - // with no earliness fudges etc. -#ifdef PERF - REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered - - // debug... - int m_idFrameAvg; - int m_idWaitAvg; -#endif - - // PROPERTY PAGE - // This has edit fields that show the user what's happening - // These member variables hold these counts. - - int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER - int m_cFramesDrawn; // Frames since streaming started seen BY THE - // RENDERER (some may be dropped upstream) - - // Next two support average sync offset and standard deviation of sync offset. - LONGLONG m_iTotAcc; // Sum of accuracies in mSec - LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec) - - // Next two allow jitter calculation. Jitter is std deviation of frame time. - REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times) - LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec) - LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec - - // To get performance statistics on frame rate, jitter etc, we need - // to record the lateness and inter-frame time. What we actually need are the - // data above (sum, sum of squares and number of entries for each) but the data - // is generated just ahead of time and only later do we discover whether the - // frame was actually drawn or not. So we have to hang on to the data - int m_trLate; // hold onto frame lateness - int m_trFrame; // hold onto inter-frame time - - int m_tStreamingStart; // if streaming then time streaming started - // else time of last streaming session - // used for property page statistics -#ifdef PERF - LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time -#endif - -public: - - - CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer - __in_opt LPCTSTR pName, // Debug ONLY description - __inout_opt LPUNKNOWN pUnk, // Aggregated owner object - __inout HRESULT *phr); // General OLE return code - - ~CBaseVideoRenderer(); - - // IQualityControl methods - Notify allows audio-video throttling - - STDMETHODIMP SetSink( IQualityControl * piqc); - STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q); - - // These provide a full video quality management implementation - - void OnRenderStart(IMediaSample *pMediaSample); - void OnRenderEnd(IMediaSample *pMediaSample); - void OnWaitStart(); - void OnWaitEnd(); - HRESULT OnStartStreaming(); - HRESULT OnStopStreaming(); - void ThrottleWait(); - - // Handle the statistics gathering for our quality management - - void PreparePerformanceData(int trLate, int trFrame); - virtual void RecordFrameLateness(int trLate, int trFrame); - virtual void OnDirectRender(IMediaSample *pMediaSample); - virtual HRESULT ResetStreamingTimes(); - BOOL ScheduleSample(IMediaSample *pMediaSample); - HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, - __inout REFERENCE_TIME *ptrStart, - __inout REFERENCE_TIME *ptrEnd); - - virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream); - STDMETHODIMP JoinFilterGraph(__inout_opt IFilterGraph * pGraph, __in_opt LPCWSTR pName); - - // - // Do estimates for standard deviations for per-frame - // statistics - // - // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) / - // (m_cFramesDrawn - 2) - // or 0 if m_cFramesDrawn <= 3 - // - HRESULT GetStdDev( - int nSamples, - __out int *piResult, - LONGLONG llSumSq, - LONGLONG iTot - ); -public: - - // IQualProp property page support - - STDMETHODIMP get_FramesDroppedInRenderer(__out int *cFramesDropped); - STDMETHODIMP get_FramesDrawn(__out int *pcFramesDrawn); - STDMETHODIMP get_AvgFrameRate(__out int *piAvgFrameRate); - STDMETHODIMP get_Jitter(__out int *piJitter); - STDMETHODIMP get_AvgSyncOffset(__out int *piAvg); - STDMETHODIMP get_DevSyncOffset(__out int *piDev); - - // Implement an IUnknown interface and expose IQualProp - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv); -}; - -#endif // __RENBASE__ - +//------------------------------------------------------------------------------ +// File: RenBase.h +// +// Desc: DirectShow base classes - defines a generic ActiveX base renderer +// class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __RENBASE__ +#define __RENBASE__ + +// Forward class declarations + +class CBaseRenderer; +class CBaseVideoRenderer; +class CRendererInputPin; + +// This is our input pin class that channels calls to the renderer + +class CRendererInputPin : public CBaseInputPin +{ +protected: + + CBaseRenderer *m_pRenderer; + +public: + + CRendererInputPin(__inout CBaseRenderer *pRenderer, + __inout HRESULT *phr, + __in_opt LPCWSTR Name); + + // Overriden from the base pin classes + + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + HRESULT SetMediaType(const CMediaType *pmt); + HRESULT CheckMediaType(const CMediaType *pmt); + HRESULT Active(); + HRESULT Inactive(); + + // Add rendering behaviour to interface functions + + STDMETHODIMP QueryId(__deref_out LPWSTR *Id); + STDMETHODIMP EndOfStream(); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + STDMETHODIMP Receive(IMediaSample *pMediaSample); + + // Helper + IMemAllocator inline *Allocator() const + { + return m_pAllocator; + } +}; + +// Main renderer class that handles synchronisation and state changes + +class CBaseRenderer : public CBaseFilter +{ +protected: + + friend class CRendererInputPin; + + friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier + UINT uMsg, // Not currently used + DWORD_PTR dwUser, // User information + DWORD_PTR dw1, // Windows reserved + DWORD_PTR dw2); // Is also reserved + + CRendererPosPassThru *m_pPosition; // Media seeking pass by object + CAMEvent m_RenderEvent; // Used to signal timer events + CAMEvent m_ThreadSignal; // Signalled to release worker thread + CAMEvent m_evComplete; // Signalled when state complete + BOOL m_bAbort; // Stop us from rendering more data + BOOL m_bStreaming; // Are we currently streaming + DWORD_PTR m_dwAdvise; // Timer advise cookie + IMediaSample *m_pMediaSample; // Current image media sample + BOOL m_bEOS; // Any more samples in the stream + BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE + CRendererInputPin *m_pInputPin; // Our renderer input pin object + CCritSec m_InterfaceLock; // Critical section for interfaces + CCritSec m_RendererLock; // Controls access to internals + IQualityControl * m_pQSink; // QualityControl sink + BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT + // Avoid some deadlocks by tracking filter during stop + volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive + // And actually processing the sample + REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE + UINT m_EndOfStreamTimer; // Used to signal end of stream + CCritSec m_ObjectCreationLock; // This lock protects the creation and + // of m_pPosition and m_pInputPin. It + // ensures that two threads cannot create + // either object simultaneously. + +public: + + CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer + __in_opt LPCTSTR pName, // Debug ONLY description + __inout_opt LPUNKNOWN pUnk, // Aggregated owner object + __inout HRESULT *phr); // General OLE return code + + ~CBaseRenderer(); + + // Overriden to say what interfaces we support and where + + virtual HRESULT GetMediaPositionInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **); + + virtual HRESULT SourceThreadCanWait(BOOL bCanWait); + +#ifdef _DEBUG + // Debug only dump of the renderer state + void DisplayRendererState(); +#endif + virtual HRESULT WaitForRenderTime(); + virtual HRESULT CompleteStateChange(FILTER_STATE OldState); + + // Return internal information about this filter + + BOOL IsEndOfStream() { return m_bEOS; }; + BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; + BOOL IsStreaming() { return m_bStreaming; }; + void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; + virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { }; + CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; + + // Permit access to the transition state + + void Ready() { m_evComplete.Set(); }; + void NotReady() { m_evComplete.Reset(); }; + BOOL CheckReady() { return m_evComplete.Check(); }; + + virtual int GetPinCount(); + virtual CBasePin *GetPin(int n); + FILTER_STATE GetRealState(); + void SendRepaint(); + void SendNotifyWindow(IPin *pPin,HWND hwnd); + BOOL OnDisplayChange(); + void SetRepaintStatus(BOOL bRepaint); + + // Override the filter and pin interface functions + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME StartTime); + STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); + STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin); + + // These are available for a quality management implementation + + virtual void OnRenderStart(IMediaSample *pMediaSample); + virtual void OnRenderEnd(IMediaSample *pMediaSample); + virtual HRESULT OnStartStreaming() { return NOERROR; }; + virtual HRESULT OnStopStreaming() { return NOERROR; }; + virtual void OnWaitStart() { }; + virtual void OnWaitEnd() { }; + virtual void PrepareRender() { }; + +#ifdef PERF + REFERENCE_TIME m_trRenderStart; // Just before we started drawing + // Set in OnRenderStart, Used in OnRenderEnd + int m_idBaseStamp; // MSR_id for frame time stamp + int m_idBaseRenderTime; // MSR_id for true wait time + int m_idBaseAccuracy; // MSR_id for time frame is late (int) +#endif + + // Quality management implementation for scheduling rendering + + virtual BOOL ScheduleSample(IMediaSample *pMediaSample); + virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, + __out REFERENCE_TIME *pStartTime, + __out REFERENCE_TIME *pEndTime); + + virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, + __out REFERENCE_TIME *ptrStart, + __out REFERENCE_TIME *ptrEnd); + + // Lots of end of stream complexities + + void TimerCallback(); + void ResetEndOfStreamTimer(); + HRESULT NotifyEndOfStream(); + virtual HRESULT SendEndOfStream(); + virtual HRESULT ResetEndOfStream(); + virtual HRESULT EndOfStream(); + + // Rendering is based around the clock + + void SignalTimerFired(); + virtual HRESULT CancelNotification(); + virtual HRESULT ClearPendingSample(); + + // Called when the filter changes state + + virtual HRESULT Active(); + virtual HRESULT Inactive(); + virtual HRESULT StartStreaming(); + virtual HRESULT StopStreaming(); + virtual HRESULT BeginFlush(); + virtual HRESULT EndFlush(); + + // Deal with connections and type changes + + virtual HRESULT BreakConnect(); + virtual HRESULT SetMediaType(const CMediaType *pmt); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // These look after the handling of data samples + + virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); + virtual HRESULT Receive(IMediaSample *pMediaSample); + virtual BOOL HaveCurrentSample(); + virtual IMediaSample *GetCurrentSample(); + virtual HRESULT Render(IMediaSample *pMediaSample); + + // Derived classes MUST override these + virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; + virtual HRESULT CheckMediaType(const CMediaType *) PURE; + + // Helper + void WaitForReceiveToComplete(); +}; + + +// CBaseVideoRenderer is a renderer class (see its ancestor class) and +// it handles scheduling of media samples so that they are drawn at the +// correct time by the reference clock. It implements a degradation +// strategy. Possible degradation modes are: +// Drop frames here (only useful if the drawing takes significant time) +// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip. +// Signal supplier to change the frame rate - i.e. ongoing skipping. +// Or any combination of the above. +// In order to determine what's useful to try we need to know what's going +// on. This is done by timing various operations (including the supplier). +// This timing is done by using timeGetTime as it is accurate enough and +// usually cheaper than calling the reference clock. It also tells the +// truth if there is an audio break and the reference clock stops. +// We provide a number of public entry points (named OnXxxStart, OnXxxEnd) +// which the rest of the renderer calls at significant moments. These do +// the timing. + +// the number of frames that the sliding averages are averaged over. +// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD +#define AVGPERIOD 4 +#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD) +// Spot the bug in this macro - I can't. but it doesn't work! + +class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class + public IQualProp, // Property page guff + public IQualityControl // Allow throttling +{ +protected: + + // Hungarian: + // tFoo is the time Foo in mSec (beware m_tStart from filter.h) + // trBar is the time Bar by the reference clock + + //****************************************************************** + // State variables to control synchronisation + //****************************************************************** + + // Control of sending Quality messages. We need to know whether + // we are in trouble (e.g. frames being dropped) and where the time + // is being spent. + + // When we drop a frame we play the next one early. + // The frame after that is likely to wait before drawing and counting this + // wait as spare time is unfair, so we count it as a zero wait. + // We therefore need to know whether we are playing frames early or not. + + int m_nNormal; // The number of consecutive frames + // drawn at their normal time (not early) + // -1 means we just dropped a frame. + +#ifdef PERF + BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm + // not keen on people using it!) +#endif + + BOOL m_bSupplierHandlingQuality;// The response to Quality messages says + // our supplier is handling things. + // We will allow things to go extra late + // before dropping frames. We will play + // very early after he has dropped one. + + // Control of scheduling, frame dropping etc. + // We need to know where the time is being spent so as to tell whether + // we should be taking action here, signalling supplier or what. + // The variables are initialised to a mode of NOT dropping frames. + // They will tell the truth after a few frames. + // We typically record a start time for an event, later we get the time + // again and subtract to get the elapsed time, and we average this over + // a few frames. The average is used to tell what mode we are in. + + // Although these are reference times (64 bit) they are all DIFFERENCES + // between times which are small. An int will go up to 214 secs before + // overflow. Avoiding 64 bit multiplications and divisions seems + // worth while. + + + + // Audio-video throttling. If the user has turned up audio quality + // very high (in principle it could be any other stream, not just audio) + // then we can receive cries for help via the graph manager. In this case + // we put in a wait for some time after rendering each frame. + int m_trThrottle; + + // The time taken to render (i.e. BitBlt) frames controls which component + // needs to degrade. If the blt is expensive, the renderer degrades. + // If the blt is cheap it's done anyway and the supplier degrades. + int m_trRenderAvg; // Time frames are taking to blt + int m_trRenderLast; // Time for last frame blt + int m_tRenderStart; // Just before we started drawing (mSec) + // derived from timeGetTime. + + // When frames are dropped we will play the next frame as early as we can. + // If it was a false alarm and the machine is fast we slide gently back to + // normal timing. To do this, we record the offset showing just how early + // we really are. This will normally be negative meaning early or zero. + int m_trEarliness; + + // Target provides slow long-term feedback to try to reduce the + // average sync offset to zero. Whenever a frame is actually rendered + // early we add a msec or two, whenever late we take off a few. + // We add or take off 1/32 of the error time. + // Eventually we should be hovering around zero. For a really bad case + // where we were (say) 300mSec off, it might take 100 odd frames to + // settle down. The rate of change of this is intended to be slower + // than any other mechanism in Quartz, thereby avoiding hunting. + int m_trTarget; + + // The proportion of time spent waiting for the right moment to blt + // controls whether we bother to drop a frame or whether we reckon that + // we're doing well enough that we can stand a one-frame glitch. + int m_trWaitAvg; // Average of last few wait times + // (actually we just average how early + // we were). Negative here means LATE. + + // The average inter-frame time. + // This is used to calculate the proportion of the time used by the + // three operations (supplying us, waiting, rendering) + int m_trFrameAvg; // Average inter-frame time + int m_trDuration; // duration of last frame. + +#ifdef PERF + // Performance logging identifiers + int m_idTimeStamp; // MSR_id for frame time stamp + int m_idEarliness; // MSR_id for earliness fudge + int m_idTarget; // MSR_id for Target fudge + int m_idWaitReal; // MSR_id for true wait time + int m_idWait; // MSR_id for wait time recorded + int m_idFrameAccuracy; // MSR_id for time frame is late (int) + int m_idRenderAvg; // MSR_id for Render time recorded (int) + int m_idSchLateTime; // MSR_id for lateness at scheduler + int m_idQualityRate; // MSR_id for Quality rate requested + int m_idQualityTime; // MSR_id for Quality time requested + int m_idDecision; // MSR_id for decision code + int m_idDuration; // MSR_id for duration of a frame + int m_idThrottle; // MSR_id for audio-video throttling + //int m_idDebug; // MSR_id for trace style debugging + //int m_idSendQuality; // MSR_id for timing the notifications per se +#endif // PERF + REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame + // with no earliness fudges etc. +#ifdef PERF + REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered + + // debug... + int m_idFrameAvg; + int m_idWaitAvg; +#endif + + // PROPERTY PAGE + // This has edit fields that show the user what's happening + // These member variables hold these counts. + + int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER + int m_cFramesDrawn; // Frames since streaming started seen BY THE + // RENDERER (some may be dropped upstream) + + // Next two support average sync offset and standard deviation of sync offset. + LONGLONG m_iTotAcc; // Sum of accuracies in mSec + LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec) + + // Next two allow jitter calculation. Jitter is std deviation of frame time. + REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times) + LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec) + LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec + + // To get performance statistics on frame rate, jitter etc, we need + // to record the lateness and inter-frame time. What we actually need are the + // data above (sum, sum of squares and number of entries for each) but the data + // is generated just ahead of time and only later do we discover whether the + // frame was actually drawn or not. So we have to hang on to the data + int m_trLate; // hold onto frame lateness + int m_trFrame; // hold onto inter-frame time + + int m_tStreamingStart; // if streaming then time streaming started + // else time of last streaming session + // used for property page statistics +#ifdef PERF + LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time +#endif + +public: + + + CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer + __in_opt LPCTSTR pName, // Debug ONLY description + __inout_opt LPUNKNOWN pUnk, // Aggregated owner object + __inout HRESULT *phr); // General OLE return code + + ~CBaseVideoRenderer(); + + // IQualityControl methods - Notify allows audio-video throttling + + STDMETHODIMP SetSink( IQualityControl * piqc); + STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q); + + // These provide a full video quality management implementation + + void OnRenderStart(IMediaSample *pMediaSample); + void OnRenderEnd(IMediaSample *pMediaSample); + void OnWaitStart(); + void OnWaitEnd(); + HRESULT OnStartStreaming(); + HRESULT OnStopStreaming(); + void ThrottleWait(); + + // Handle the statistics gathering for our quality management + + void PreparePerformanceData(int trLate, int trFrame); + virtual void RecordFrameLateness(int trLate, int trFrame); + virtual void OnDirectRender(IMediaSample *pMediaSample); + virtual HRESULT ResetStreamingTimes(); + BOOL ScheduleSample(IMediaSample *pMediaSample); + HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, + __inout REFERENCE_TIME *ptrStart, + __inout REFERENCE_TIME *ptrEnd); + + virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream); + STDMETHODIMP JoinFilterGraph(__inout_opt IFilterGraph * pGraph, __in_opt LPCWSTR pName); + + // + // Do estimates for standard deviations for per-frame + // statistics + // + // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) / + // (m_cFramesDrawn - 2) + // or 0 if m_cFramesDrawn <= 3 + // + HRESULT GetStdDev( + int nSamples, + __out int *piResult, + LONGLONG llSumSq, + LONGLONG iTot + ); +public: + + // IQualProp property page support + + STDMETHODIMP get_FramesDroppedInRenderer(__out int *cFramesDropped); + STDMETHODIMP get_FramesDrawn(__out int *pcFramesDrawn); + STDMETHODIMP get_AvgFrameRate(__out int *piAvgFrameRate); + STDMETHODIMP get_Jitter(__out int *piJitter); + STDMETHODIMP get_AvgSyncOffset(__out int *piAvg); + STDMETHODIMP get_DevSyncOffset(__out int *piDev); + + // Implement an IUnknown interface and expose IQualProp + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv); +}; + +#endif // __RENBASE__ + diff --git a/src/thirdparty/BaseClasses/schedule.cpp b/src/thirdparty/BaseClasses/schedule.cpp index 3f20d7c27af..4638a5e1786 100644 --- a/src/thirdparty/BaseClasses/schedule.cpp +++ b/src/thirdparty/BaseClasses/schedule.cpp @@ -1,288 +1,288 @@ -//------------------------------------------------------------------------------ -// File: Schedule.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - -// DbgLog values (all on LOG_TIMING): -// -// 2 for schedulting, firing and shunting of events -// 3 for wait delays and wake-up times of event thread -// 4 for details of whats on the list when the thread awakes - -/* Construct & destructors */ - -CAMSchedule::CAMSchedule( HANDLE ev ) -: CBaseObject(TEXT("CAMSchedule")) -, head(&z, 0), z(0, MAX_TIME) -, m_dwNextCookie(0), m_dwAdviseCount(0) -, m_pAdviseCache(0), m_dwCacheCount(0) -, m_ev( ev ) -{ - head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0; -} - -CAMSchedule::~CAMSchedule() -{ - m_Serialize.Lock(); - - // Delete cache - CAdvisePacket * p = m_pAdviseCache; - while (p) - { - CAdvisePacket *const p_next = p->m_next; - delete p; - p = p_next; - } - - ASSERT( m_dwAdviseCount == 0 ); - // Better to be safe than sorry - if ( m_dwAdviseCount > 0 ) - { - DumpLinkedList(); - while ( !head.m_next->IsZ() ) - { - head.DeleteNext(); - --m_dwAdviseCount; - } - } - - // If, in the debug version, we assert twice, it means, not only - // did we have left over advises, but we have also let m_dwAdviseCount - // get out of sync. with the number of advises actually on the list. - ASSERT( m_dwAdviseCount == 0 ); - - m_Serialize.Unlock(); -} - -/* Public methods */ - -DWORD CAMSchedule::GetAdviseCount() -{ - // No need to lock, m_dwAdviseCount is 32bits & declared volatile - return m_dwAdviseCount; -} - -REFERENCE_TIME CAMSchedule::GetNextAdviseTime() -{ - CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing - return head.m_next->m_rtEventTime; -} - -DWORD_PTR CAMSchedule::AddAdvisePacket -( const REFERENCE_TIME & time1 -, const REFERENCE_TIME & time2 -, HANDLE h, BOOL periodic -) -{ - // Since we use MAX_TIME as a sentry, we can't afford to - // schedule a notification at MAX_TIME - ASSERT( time1 < MAX_TIME ); - DWORD_PTR Result; - CAdvisePacket * p; - - m_Serialize.Lock(); - - if (m_pAdviseCache) - { - p = m_pAdviseCache; - m_pAdviseCache = p->m_next; - --m_dwCacheCount; - } - else - { - p = new CAdvisePacket(); - } - if (p) - { - p->m_rtEventTime = time1; p->m_rtPeriod = time2; - p->m_hNotify = h; p->m_bPeriodic = periodic; - Result = AddAdvisePacket( p ); - } - else Result = 0; - - m_Serialize.Unlock(); - - return Result; -} - -HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) -{ - HRESULT hr = S_FALSE; - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - m_Serialize.Lock(); - p_n = p_prev->Next(); - while ( p_n ) // The Next() method returns NULL when it hits z - { - if ( p_n->m_dwAdviseCookie == dwAdviseCookie ) - { - Delete( p_prev->RemoveNext() ); - --m_dwAdviseCount; - hr = S_OK; - // Having found one cookie that matches, there should be no more -#ifdef _DEBUG - p_n = p_prev->Next(); - while (p_n) - { - ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie); - p_prev = p_n; - p_n = p_prev->Next(); - } -#endif - break; - } - p_prev = p_n; - p_n = p_prev->Next(); - }; - m_Serialize.Unlock(); - return hr; -} - -REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) -{ - REFERENCE_TIME rtNextTime; - CAdvisePacket * pAdvise; - - DbgLog((LOG_TIMING, 2, - TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS)))); - - CAutoLock lck(&m_Serialize); - - #ifdef _DEBUG - if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList(); - #endif - - // Note - DON'T cache the difference, it might overflow - while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) && - !pAdvise->IsZ() ) - { - ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!! - - ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE); - - if (pAdvise->m_bPeriodic == TRUE) - { - ReleaseSemaphore(pAdvise->m_hNotify,1,NULL); - pAdvise->m_rtEventTime += pAdvise->m_rtPeriod; - ShuntHead(); - } - else - { - ASSERT( pAdvise->m_bPeriodic == FALSE ); - EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify)); - --m_dwAdviseCount; - Delete( head.RemoveNext() ); - } - - } - - DbgLog((LOG_TIMING, 3, - TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."), - DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie )); - - return rtNextTime; -} - -/* Private methods */ - -DWORD_PTR CAMSchedule::AddAdvisePacket( __inout CAdvisePacket * pPacket ) -{ - ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME); - ASSERT(CritCheckIn(&m_Serialize)); - - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - - const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie; - // This relies on the fact that z is a sentry with a maximal m_rtEventTime - for(;;p_prev = p_n) - { - p_n = p_prev->m_next; - if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break; - } - p_prev->InsertAfter( pPacket ); - ++m_dwAdviseCount; - - DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"), - pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); - - // If packet added at the head, then clock needs to re-evaluate wait time. - if ( p_prev == &head ) SetEvent( m_ev ); - - return Result; -} - -void CAMSchedule::Delete( __inout CAdvisePacket * pPacket ) -{ - if ( m_dwCacheCount >= dwCacheMax ) delete pPacket; - else - { - m_Serialize.Lock(); - pPacket->m_next = m_pAdviseCache; - m_pAdviseCache = pPacket; - ++m_dwCacheCount; - m_Serialize.Unlock(); - } -} - - -// Takes the head of the list & repositions it -void CAMSchedule::ShuntHead() -{ - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - - m_Serialize.Lock(); - CAdvisePacket *const pPacket = head.m_next; - - // This will catch both an empty list, - // and if somehow a MAX_TIME time gets into the list - // (which would also break this method). - ASSERT( pPacket->m_rtEventTime < MAX_TIME ); - - // This relies on the fact that z is a sentry with a maximal m_rtEventTime - for(;;p_prev = p_n) - { - p_n = p_prev->m_next; - if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break; - } - // If p_prev == pPacket then we're already in the right place - if (p_prev != pPacket) - { - head.m_next = pPacket->m_next; - (p_prev->m_next = pPacket)->m_next = p_n; - } - #ifdef _DEBUG - DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"), - pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); - #endif - m_Serialize.Unlock(); -} - - -#ifdef _DEBUG -void CAMSchedule::DumpLinkedList() -{ - m_Serialize.Lock(); - int i=0; - DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this)); - for ( CAdvisePacket * p = &head - ; p - ; p = p->m_next , i++ - ) - { - DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"), - i, - p->m_dwAdviseCookie, - p->m_rtEventTime / (UNITS / MILLISECONDS) - )); - } - m_Serialize.Unlock(); -} -#endif +//------------------------------------------------------------------------------ +// File: Schedule.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + +// DbgLog values (all on LOG_TIMING): +// +// 2 for schedulting, firing and shunting of events +// 3 for wait delays and wake-up times of event thread +// 4 for details of whats on the list when the thread awakes + +/* Construct & destructors */ + +CAMSchedule::CAMSchedule( HANDLE ev ) +: CBaseObject(TEXT("CAMSchedule")) +, head(&z, 0), z(0, MAX_TIME) +, m_dwNextCookie(0), m_dwAdviseCount(0) +, m_pAdviseCache(0), m_dwCacheCount(0) +, m_ev( ev ) +{ + head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0; +} + +CAMSchedule::~CAMSchedule() +{ + m_Serialize.Lock(); + + // Delete cache + CAdvisePacket * p = m_pAdviseCache; + while (p) + { + CAdvisePacket *const p_next = p->m_next; + delete p; + p = p_next; + } + + ASSERT( m_dwAdviseCount == 0 ); + // Better to be safe than sorry + if ( m_dwAdviseCount > 0 ) + { + DumpLinkedList(); + while ( !head.m_next->IsZ() ) + { + head.DeleteNext(); + --m_dwAdviseCount; + } + } + + // If, in the debug version, we assert twice, it means, not only + // did we have left over advises, but we have also let m_dwAdviseCount + // get out of sync. with the number of advises actually on the list. + ASSERT( m_dwAdviseCount == 0 ); + + m_Serialize.Unlock(); +} + +/* Public methods */ + +DWORD CAMSchedule::GetAdviseCount() +{ + // No need to lock, m_dwAdviseCount is 32bits & declared volatile + return m_dwAdviseCount; +} + +REFERENCE_TIME CAMSchedule::GetNextAdviseTime() +{ + CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing + return head.m_next->m_rtEventTime; +} + +DWORD_PTR CAMSchedule::AddAdvisePacket +( const REFERENCE_TIME & time1 +, const REFERENCE_TIME & time2 +, HANDLE h, BOOL periodic +) +{ + // Since we use MAX_TIME as a sentry, we can't afford to + // schedule a notification at MAX_TIME + ASSERT( time1 < MAX_TIME ); + DWORD_PTR Result; + CAdvisePacket * p; + + m_Serialize.Lock(); + + if (m_pAdviseCache) + { + p = m_pAdviseCache; + m_pAdviseCache = p->m_next; + --m_dwCacheCount; + } + else + { + p = new CAdvisePacket(); + } + if (p) + { + p->m_rtEventTime = time1; p->m_rtPeriod = time2; + p->m_hNotify = h; p->m_bPeriodic = periodic; + Result = AddAdvisePacket( p ); + } + else Result = 0; + + m_Serialize.Unlock(); + + return Result; +} + +HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) +{ + HRESULT hr = S_FALSE; + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + m_Serialize.Lock(); + p_n = p_prev->Next(); + while ( p_n ) // The Next() method returns NULL when it hits z + { + if ( p_n->m_dwAdviseCookie == dwAdviseCookie ) + { + Delete( p_prev->RemoveNext() ); + --m_dwAdviseCount; + hr = S_OK; + // Having found one cookie that matches, there should be no more +#ifdef _DEBUG + p_n = p_prev->Next(); + while (p_n) + { + ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie); + p_prev = p_n; + p_n = p_prev->Next(); + } +#endif + break; + } + p_prev = p_n; + p_n = p_prev->Next(); + }; + m_Serialize.Unlock(); + return hr; +} + +REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) +{ + REFERENCE_TIME rtNextTime; + CAdvisePacket * pAdvise; + + DbgLog((LOG_TIMING, 2, + TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS)))); + + CAutoLock lck(&m_Serialize); + + #ifdef _DEBUG + if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList(); + #endif + + // Note - DON'T cache the difference, it might overflow + while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) && + !pAdvise->IsZ() ) + { + ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!! + + ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE); + + if (pAdvise->m_bPeriodic == TRUE) + { + ReleaseSemaphore(pAdvise->m_hNotify,1,NULL); + pAdvise->m_rtEventTime += pAdvise->m_rtPeriod; + ShuntHead(); + } + else + { + ASSERT( pAdvise->m_bPeriodic == FALSE ); + EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify)); + --m_dwAdviseCount; + Delete( head.RemoveNext() ); + } + + } + + DbgLog((LOG_TIMING, 3, + TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."), + DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie )); + + return rtNextTime; +} + +/* Private methods */ + +DWORD_PTR CAMSchedule::AddAdvisePacket( __inout CAdvisePacket * pPacket ) +{ + ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME); + ASSERT(CritCheckIn(&m_Serialize)); + + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + + const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie; + // This relies on the fact that z is a sentry with a maximal m_rtEventTime + for(;;p_prev = p_n) + { + p_n = p_prev->m_next; + if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break; + } + p_prev->InsertAfter( pPacket ); + ++m_dwAdviseCount; + + DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"), + pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); + + // If packet added at the head, then clock needs to re-evaluate wait time. + if ( p_prev == &head ) SetEvent( m_ev ); + + return Result; +} + +void CAMSchedule::Delete( __inout CAdvisePacket * pPacket ) +{ + if ( m_dwCacheCount >= dwCacheMax ) delete pPacket; + else + { + m_Serialize.Lock(); + pPacket->m_next = m_pAdviseCache; + m_pAdviseCache = pPacket; + ++m_dwCacheCount; + m_Serialize.Unlock(); + } +} + + +// Takes the head of the list & repositions it +void CAMSchedule::ShuntHead() +{ + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + + m_Serialize.Lock(); + CAdvisePacket *const pPacket = head.m_next; + + // This will catch both an empty list, + // and if somehow a MAX_TIME time gets into the list + // (which would also break this method). + ASSERT( pPacket->m_rtEventTime < MAX_TIME ); + + // This relies on the fact that z is a sentry with a maximal m_rtEventTime + for(;;p_prev = p_n) + { + p_n = p_prev->m_next; + if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break; + } + // If p_prev == pPacket then we're already in the right place + if (p_prev != pPacket) + { + head.m_next = pPacket->m_next; + (p_prev->m_next = pPacket)->m_next = p_n; + } + #ifdef _DEBUG + DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"), + pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); + #endif + m_Serialize.Unlock(); +} + + +#ifdef _DEBUG +void CAMSchedule::DumpLinkedList() +{ + m_Serialize.Lock(); + int i=0; + DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this)); + for ( CAdvisePacket * p = &head + ; p + ; p = p->m_next , i++ + ) + { + DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"), + i, + p->m_dwAdviseCookie, + p->m_rtEventTime / (UNITS / MILLISECONDS) + )); + } + m_Serialize.Unlock(); +} +#endif diff --git a/src/thirdparty/BaseClasses/schedule.h b/src/thirdparty/BaseClasses/schedule.h index c35e0098b39..ff49a44c318 100644 --- a/src/thirdparty/BaseClasses/schedule.h +++ b/src/thirdparty/BaseClasses/schedule.h @@ -1,140 +1,140 @@ -//------------------------------------------------------------------------------ -// File: Schedule.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __CAMSchedule__ -#define __CAMSchedule__ - -class CAMSchedule : private CBaseObject -{ -public: - virtual ~CAMSchedule(); - // ev is the event we should fire if the advise time needs re-evaluating - CAMSchedule( HANDLE ev ); - - DWORD GetAdviseCount(); - REFERENCE_TIME GetNextAdviseTime(); - - // We need a method for derived classes to add advise packets, we return the cookie - DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); - // And a way to cancel - HRESULT Unadvise(DWORD_PTR dwAdviseCookie); - - // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. - // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of - // whoever is using this helper class (typically a clock). - REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); - - // Get the event handle which will be set if advise time requires re-evaluation. - HANDLE GetEvent() const { return m_ev; } - -private: - // We define the nodes that will be used in our singly linked list - // of advise packets. The list is ordered by time, with the - // elements that will expire first at the front. - class CAdvisePacket - { - public: - CAdvisePacket() - : m_next(NULL) - , m_rtEventTime(0) - , m_dwAdviseCookie(0) - , m_rtPeriod(0) - , m_hNotify(NULL) - , m_bPeriodic(FALSE) - {} - - CAdvisePacket * m_next; - DWORD_PTR m_dwAdviseCookie; - REFERENCE_TIME m_rtEventTime; // Time at which event should be set - REFERENCE_TIME m_rtPeriod; // Periodic time - HANDLE m_hNotify; // Handle to event or semephore - BOOL m_bPeriodic; // TRUE => Periodic event - - CAdvisePacket( __inout_opt CAdvisePacket * next, LONGLONG time ) - : m_next(next) - , m_rtEventTime(time) - , m_dwAdviseCookie(0) - , m_rtPeriod(0) - , m_hNotify(NULL) - , m_bPeriodic(FALSE) - {} - - void InsertAfter( __inout CAdvisePacket * p ) - { - p->m_next = m_next; - m_next = p; - } - - int IsZ() const // That is, is it the node that represents the end of the list - { return m_next == 0; } - - CAdvisePacket * RemoveNext() - { - CAdvisePacket *const next = m_next; - CAdvisePacket *const new_next = next->m_next; - m_next = new_next; - return next; - } - - void DeleteNext() - { - delete RemoveNext(); - } - - CAdvisePacket * Next() const - { - CAdvisePacket * result = m_next; - if (result->IsZ()) result = 0; - return result; - } - - DWORD_PTR Cookie() const - { return m_dwAdviseCookie; } - }; - - // Structure is: - // head -> elmt1 -> elmt2 -> z -> null - // So an empty list is: head -> z -> null - // Having head & z as links makes insertaion, - // deletion and shunting much easier. - CAdvisePacket head, z; // z is both a tail and a sentry - - volatile DWORD_PTR m_dwNextCookie; // Strictly increasing - volatile DWORD m_dwAdviseCount; // Number of elements on list - - CCritSec m_Serialize; - - // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) - DWORD_PTR AddAdvisePacket( __inout CAdvisePacket * pPacket ); - // Event that we should set if the packed added above will be the next to fire. - const HANDLE m_ev; - - // A Shunt is where we have changed the first element in the - // list and want it re-evaluating (i.e. repositioned) in - // the list. - void ShuntHead(); - - // Rather than delete advise packets, we cache them for future use - CAdvisePacket * m_pAdviseCache; - DWORD m_dwCacheCount; - enum { dwCacheMax = 5 }; // Don't bother caching more than five - - void Delete( __inout CAdvisePacket * pLink );// This "Delete" will cache the Link - -// Attributes and methods for debugging -public: -#ifdef _DEBUG - void DumpLinkedList(); -#else - void DumpLinkedList() {} -#endif - -}; - -#endif // __CAMSchedule__ +//------------------------------------------------------------------------------ +// File: Schedule.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CAMSchedule__ +#define __CAMSchedule__ + +class CAMSchedule : private CBaseObject +{ +public: + virtual ~CAMSchedule(); + // ev is the event we should fire if the advise time needs re-evaluating + CAMSchedule( HANDLE ev ); + + DWORD GetAdviseCount(); + REFERENCE_TIME GetNextAdviseTime(); + + // We need a method for derived classes to add advise packets, we return the cookie + DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); + // And a way to cancel + HRESULT Unadvise(DWORD_PTR dwAdviseCookie); + + // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. + // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of + // whoever is using this helper class (typically a clock). + REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); + + // Get the event handle which will be set if advise time requires re-evaluation. + HANDLE GetEvent() const { return m_ev; } + +private: + // We define the nodes that will be used in our singly linked list + // of advise packets. The list is ordered by time, with the + // elements that will expire first at the front. + class CAdvisePacket + { + public: + CAdvisePacket() + : m_next(NULL) + , m_rtEventTime(0) + , m_dwAdviseCookie(0) + , m_rtPeriod(0) + , m_hNotify(NULL) + , m_bPeriodic(FALSE) + {} + + CAdvisePacket * m_next; + DWORD_PTR m_dwAdviseCookie; + REFERENCE_TIME m_rtEventTime; // Time at which event should be set + REFERENCE_TIME m_rtPeriod; // Periodic time + HANDLE m_hNotify; // Handle to event or semephore + BOOL m_bPeriodic; // TRUE => Periodic event + + CAdvisePacket( __inout_opt CAdvisePacket * next, LONGLONG time ) + : m_next(next) + , m_rtEventTime(time) + , m_dwAdviseCookie(0) + , m_rtPeriod(0) + , m_hNotify(NULL) + , m_bPeriodic(FALSE) + {} + + void InsertAfter( __inout CAdvisePacket * p ) + { + p->m_next = m_next; + m_next = p; + } + + int IsZ() const // That is, is it the node that represents the end of the list + { return m_next == 0; } + + CAdvisePacket * RemoveNext() + { + CAdvisePacket *const next = m_next; + CAdvisePacket *const new_next = next->m_next; + m_next = new_next; + return next; + } + + void DeleteNext() + { + delete RemoveNext(); + } + + CAdvisePacket * Next() const + { + CAdvisePacket * result = m_next; + if (result->IsZ()) result = 0; + return result; + } + + DWORD_PTR Cookie() const + { return m_dwAdviseCookie; } + }; + + // Structure is: + // head -> elmt1 -> elmt2 -> z -> null + // So an empty list is: head -> z -> null + // Having head & z as links makes insertaion, + // deletion and shunting much easier. + CAdvisePacket head, z; // z is both a tail and a sentry + + volatile DWORD_PTR m_dwNextCookie; // Strictly increasing + volatile DWORD m_dwAdviseCount; // Number of elements on list + + CCritSec m_Serialize; + + // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) + DWORD_PTR AddAdvisePacket( __inout CAdvisePacket * pPacket ); + // Event that we should set if the packed added above will be the next to fire. + const HANDLE m_ev; + + // A Shunt is where we have changed the first element in the + // list and want it re-evaluating (i.e. repositioned) in + // the list. + void ShuntHead(); + + // Rather than delete advise packets, we cache them for future use + CAdvisePacket * m_pAdviseCache; + DWORD m_dwCacheCount; + enum { dwCacheMax = 5 }; // Don't bother caching more than five + + void Delete( __inout CAdvisePacket * pLink );// This "Delete" will cache the Link + +// Attributes and methods for debugging +public: +#ifdef _DEBUG + void DumpLinkedList(); +#else + void DumpLinkedList() {} +#endif + +}; + +#endif // __CAMSchedule__ diff --git a/src/thirdparty/BaseClasses/seekpt.cpp b/src/thirdparty/BaseClasses/seekpt.cpp index e679b253873..0c5ec923eb0 100644 --- a/src/thirdparty/BaseClasses/seekpt.cpp +++ b/src/thirdparty/BaseClasses/seekpt.cpp @@ -1,83 +1,83 @@ -//------------------------------------------------------------------------------ -// File: SeekPT.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "seekpt.h" - -//================================================================== -// CreateInstance -// This goes in the factory template table to create new instances -// If there is already a mapper instance - return that, else make one -// and save it in a static variable so that forever after we can return that. -//================================================================== - -CUnknown * CSeekingPassThru::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) -{ - return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr); -} - - -STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) -{ - if (riid == IID_ISeekingPassThru) { - return GetInterface((ISeekingPassThru *) this, ppv); - } else { - if (m_pPosPassThru && - (riid == IID_IMediaSeeking || - riid == IID_IMediaPosition)) { - return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - } -} - - -CSeekingPassThru::CSeekingPassThru( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr ) - : CUnknown(pName, pUnk, phr), - m_pPosPassThru(NULL) -{ -} - - -CSeekingPassThru::~CSeekingPassThru() -{ - delete m_pPosPassThru; -} - -STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin) -{ - HRESULT hr = NOERROR; - if (m_pPosPassThru) { - hr = E_FAIL; - } else { - m_pPosPassThru = - bRendererSeeking ? - new CRendererPosPassThru( - NAME("Render Seeking COM object"), - (IUnknown *)this, - &hr, - pPin) : - new CPosPassThru( - NAME("Render Seeking COM object"), - (IUnknown *)this, - &hr, - pPin); - if (!m_pPosPassThru) { - hr = E_OUTOFMEMORY; - } else { - if (FAILED(hr)) { - delete m_pPosPassThru; - m_pPosPassThru = NULL; - } - } - } - return hr; -} - +//------------------------------------------------------------------------------ +// File: SeekPT.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "seekpt.h" + +//================================================================== +// CreateInstance +// This goes in the factory template table to create new instances +// If there is already a mapper instance - return that, else make one +// and save it in a static variable so that forever after we can return that. +//================================================================== + +CUnknown * CSeekingPassThru::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) +{ + return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr); +} + + +STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) +{ + if (riid == IID_ISeekingPassThru) { + return GetInterface((ISeekingPassThru *) this, ppv); + } else { + if (m_pPosPassThru && + (riid == IID_IMediaSeeking || + riid == IID_IMediaPosition)) { + return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + } +} + + +CSeekingPassThru::CSeekingPassThru( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr ) + : CUnknown(pName, pUnk, phr), + m_pPosPassThru(NULL) +{ +} + + +CSeekingPassThru::~CSeekingPassThru() +{ + delete m_pPosPassThru; +} + +STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin) +{ + HRESULT hr = NOERROR; + if (m_pPosPassThru) { + hr = E_FAIL; + } else { + m_pPosPassThru = + bRendererSeeking ? + new CRendererPosPassThru( + NAME("Render Seeking COM object"), + (IUnknown *)this, + &hr, + pPin) : + new CPosPassThru( + NAME("Render Seeking COM object"), + (IUnknown *)this, + &hr, + pPin); + if (!m_pPosPassThru) { + hr = E_OUTOFMEMORY; + } else { + if (FAILED(hr)) { + delete m_pPosPassThru; + m_pPosPassThru = NULL; + } + } + } + return hr; +} + diff --git a/src/thirdparty/BaseClasses/seekpt.h b/src/thirdparty/BaseClasses/seekpt.h index 208d418f8f4..26abdf3ecec 100644 --- a/src/thirdparty/BaseClasses/seekpt.h +++ b/src/thirdparty/BaseClasses/seekpt.h @@ -1,30 +1,30 @@ -//------------------------------------------------------------------------------ -// File: SeekPT.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __seekpt_h__ -#define __seekpt_h__ - - -class CSeekingPassThru : public ISeekingPassThru, public CUnknown -{ -public: - static CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); - CSeekingPassThru(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); - ~CSeekingPassThru(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - - STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin); - -private: - CPosPassThru *m_pPosPassThru; -}; - -#endif +//------------------------------------------------------------------------------ +// File: SeekPT.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __seekpt_h__ +#define __seekpt_h__ + + +class CSeekingPassThru : public ISeekingPassThru, public CUnknown +{ +public: + static CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); + CSeekingPassThru(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); + ~CSeekingPassThru(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + + STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin); + +private: + CPosPassThru *m_pPosPassThru; +}; + +#endif diff --git a/src/thirdparty/BaseClasses/source.cpp b/src/thirdparty/BaseClasses/source.cpp index b1cfbe8cb86..79ea4966517 100644 --- a/src/thirdparty/BaseClasses/source.cpp +++ b/src/thirdparty/BaseClasses/source.cpp @@ -1,522 +1,522 @@ -//------------------------------------------------------------------------------ -// File: Source.cpp -// -// Desc: DirectShow base classes - implements CSource, which is a Quartz -// source filter 'template.' -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Locking Strategy. -// -// Hold the filter critical section (m_pFilter->pStateLock()) to serialise -// access to functions. Note that, in general, this lock may be held -// by a function when the worker thread may want to hold it. Therefore -// if you wish to access shared state from the worker thread you will -// need to add another critical section object. The execption is during -// the threads processing loop, when it is safe to get the filter critical -// section from within FillBuffer(). - -#include "streams.h" - - -// -// CSource::Constructor -// -// Initialise the pin count for the filter. The user will create the pins in -// the derived class. -CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ -} - -CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ - UNREFERENCED_PARAMETER(phr); -} - -#ifdef UNICODE -CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ -} - -CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ - UNREFERENCED_PARAMETER(phr); -} -#endif - -// -// CSource::Destructor -// -CSource::~CSource() -{ - /* Free our pins and pin array */ - while (m_iPins != 0) { - // deleting the pins causes them to be removed from the array... - delete m_paStreams[m_iPins - 1]; - } - - ASSERT(m_paStreams == NULL); -} - - -// -// Add a new pin -// -HRESULT CSource::AddPin(__in CSourceStream *pStream) -{ - CAutoLock lock(&m_cStateLock); - - /* Allocate space for this pin and the old ones */ - CSourceStream **paStreams = new CSourceStream *[m_iPins + 1]; - if (paStreams == NULL) { - return E_OUTOFMEMORY; - } - if (m_paStreams != NULL) { - CopyMemory((PVOID)paStreams, (PVOID)m_paStreams, - m_iPins * sizeof(m_paStreams[0])); - paStreams[m_iPins] = pStream; - delete [] m_paStreams; - } - m_paStreams = paStreams; - m_paStreams[m_iPins] = pStream; - m_iPins++; - return S_OK; -} - -// -// Remove a pin - pStream is NOT deleted -// -HRESULT CSource::RemovePin(__in CSourceStream *pStream) -{ - int i; - for (i = 0; i < m_iPins; i++) { - if (m_paStreams[i] == pStream) { - if (m_iPins == 1) { - delete [] m_paStreams; - m_paStreams = NULL; - } else { - /* no need to reallocate */ - while (++i < m_iPins) - m_paStreams[i - 1] = m_paStreams[i]; - } - m_iPins--; - return S_OK; - } - } - return S_FALSE; -} - -// -// FindPin -// -// Set *ppPin to the IPin* that has the id Id. -// or to NULL if the Id cannot be matched. -STDMETHODIMP CSource::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - // The -1 undoes the +1 in QueryId and ensures that totally invalid - // strings (for which WstrToInt delivers 0) give a deliver a NULL pin. - int i = WstrToInt(Id) -1; - *ppPin = GetPin(i); - if (*ppPin!=NULL){ - (*ppPin)->AddRef(); - return NOERROR; - } else { - return VFW_E_NOT_FOUND; - } -} - -// -// FindPinNumber -// -// return the number of the pin with this IPin* or -1 if none -int CSource::FindPinNumber(__in IPin *iPin) { - int i; - for (i=0; in && n>=0 it follows that m_iPins>0 - // which is what used to be checked (i.e. checking that we have a pin) - if ((n >= 0) && (n < m_iPins)) { - - ASSERT(m_paStreams[n]); - return m_paStreams[n]; - } - return NULL; -} - - -// - - -// * -// * --- CSourceStream ---- -// * - -// -// Set Id to point to a CoTaskMemAlloc'd -STDMETHODIMP CSourceStream::QueryId(__deref_out LPWSTR *Id) { - CheckPointer(Id,E_POINTER); - ValidateReadWritePtr(Id,sizeof(LPWSTR)); - - // We give the pins id's which are 1,2,... - // FindPinNumber returns -1 for an invalid pin - int i = 1+ m_pFilter->FindPinNumber(this); - if (i<1) return VFW_E_NOT_FOUND; - *Id = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * 12); - if (*Id==NULL) { - return E_OUTOFMEMORY; - } - IntToWstr(i, *Id); - return NOERROR; -} - - - -// -// CSourceStream::Constructor -// -// increments the number of pins present on the filter -CSourceStream::CSourceStream( - __in_opt LPCTSTR pObjectName, - __inout HRESULT *phr, - __inout CSource *ps, - __in_opt LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), - m_pFilter(ps) { - - *phr = m_pFilter->AddPin(this); -} - -#ifdef UNICODE -CSourceStream::CSourceStream( - __in_opt LPCSTR pObjectName, - __inout HRESULT *phr, - __inout CSource *ps, - __in_opt LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), - m_pFilter(ps) { - - *phr = m_pFilter->AddPin(this); -} -#endif -// -// CSourceStream::Destructor -// -// Decrements the number of pins on this filter -CSourceStream::~CSourceStream(void) { - - m_pFilter->RemovePin(this); -} - - -// -// CheckMediaType -// -// Do we support this type? Provides the default support for 1 type. -HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) { - - CAutoLock lock(m_pFilter->pStateLock()); - - CMediaType mt; - GetMediaType(&mt); - - if (mt == *pMediaType) { - return NOERROR; - } - - return E_FAIL; -} - - -// -// GetMediaType/3 -// -// By default we support only one type -// iPosition indexes are 0-n -HRESULT CSourceStream::GetMediaType(int iPosition, __inout CMediaType *pMediaType) { - - CAutoLock lock(m_pFilter->pStateLock()); - - if (iPosition<0) { - return E_INVALIDARG; - } - if (iPosition>0) { - return VFW_S_NO_MORE_ITEMS; - } - return GetMediaType(pMediaType); -} - - -// -// Active -// -// The pin is active - start up the worker thread -HRESULT CSourceStream::Active(void) { - - CAutoLock lock(m_pFilter->pStateLock()); - - HRESULT hr; - - if (m_pFilter->IsActive()) { - return S_FALSE; // succeeded, but did not allocate resources (they already exist...) - } - - // do nothing if not connected - its ok not to connect to - // all pins of a source filter - if (!IsConnected()) { - return NOERROR; - } - - hr = CBaseOutputPin::Active(); - if (FAILED(hr)) { - return hr; - } - - ASSERT(!ThreadExists()); - - // start the thread - if (!Create()) { - return E_FAIL; - } - - // Tell thread to initialize. If OnThreadCreate Fails, so does this. - hr = Init(); - if (FAILED(hr)) - return hr; - - return Pause(); -} - - -// -// Inactive -// -// Pin is inactive - shut down the worker thread -// Waits for the worker to exit before returning. -HRESULT CSourceStream::Inactive(void) { - - CAutoLock lock(m_pFilter->pStateLock()); - - HRESULT hr; - - // do nothing if not connected - its ok not to connect to - // all pins of a source filter - if (!IsConnected()) { - return NOERROR; - } - - // !!! need to do this before trying to stop the thread, because - // we may be stuck waiting for our own allocator!!! - - hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator - if (FAILED(hr)) { - return hr; - } - - if (ThreadExists()) { - hr = Stop(); - - if (FAILED(hr)) { - return hr; - } - - hr = Exit(); - if (FAILED(hr)) { - return hr; - } - - Close(); // Wait for the thread to exit, then tidy up. - } - - // hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator - //if (FAILED(hr)) { - // return hr; - //} - - return NOERROR; -} - - -// -// ThreadProc -// -// When this returns the thread exits -// Return codes > 0 indicate an error occured -DWORD CSourceStream::ThreadProc(void) { - - HRESULT hr; // the return code from calls - Command com; - - do { - com = GetRequest(); - if (com != CMD_INIT) { - DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command"))); - Reply((DWORD) E_UNEXPECTED); - } - } while (com != CMD_INIT); - - DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing"))); - - hr = OnThreadCreate(); // perform set up tasks - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread."))); - OnThreadDestroy(); - Reply(hr); // send failed return code from OnThreadCreate - return 1; - } - - // Initialisation suceeded - Reply(NOERROR); - - Command cmd; - do { - cmd = GetRequest(); - - switch (cmd) { - - case CMD_EXIT: - Reply(NOERROR); - break; - - case CMD_RUN: - DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???"))); - // !!! fall through??? - - case CMD_PAUSE: - Reply(NOERROR); - DoBufferProcessingLoop(); - break; - - case CMD_STOP: - Reply(NOERROR); - break; - - default: - DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd)); - Reply((DWORD) E_NOTIMPL); - break; - } - } while (cmd != CMD_EXIT); - - hr = OnThreadDestroy(); // tidy up. - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread."))); - return 1; - } - - DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting"))); - return 0; -} - - -// -// DoBufferProcessingLoop -// -// Grabs a buffer and calls the users processing function. -// Overridable, so that different delivery styles can be catered for. -HRESULT CSourceStream::DoBufferProcessingLoop(void) { - - Command com; - - OnThreadStartPlay(); - - do { - while (!CheckRequest(&com)) { - - IMediaSample *pSample; - - HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); - if (FAILED(hr)) { - Sleep(1); - continue; // go round again. Perhaps the error will go away - // or the allocator is decommited & we will be asked to - // exit soon. - } - - // Virtual function user will override. - hr = FillBuffer(pSample); - - if (hr == S_OK) { - hr = Deliver(pSample); - pSample->Release(); - - // downstream filter returns S_FALSE if it wants us to - // stop or an error if it's reporting an error. - if(hr != S_OK) - { - DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); - return S_OK; - } - - } else if (hr == S_FALSE) { - // derived class wants us to stop pushing data - pSample->Release(); - DeliverEndOfStream(); - return S_OK; - } else { - // derived class encountered an error - pSample->Release(); - DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); - DeliverEndOfStream(); - m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); - return hr; - } - - // all paths release the sample - } - - // For all commands sent to us there must be a Reply call! - - if (com == CMD_RUN || com == CMD_PAUSE) { - Reply(NOERROR); - } else if (com != CMD_STOP) { - Reply((DWORD) E_UNEXPECTED); - DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); - } - } while (com != CMD_STOP); - - return S_FALSE; -} - +//------------------------------------------------------------------------------ +// File: Source.cpp +// +// Desc: DirectShow base classes - implements CSource, which is a Quartz +// source filter 'template.' +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Locking Strategy. +// +// Hold the filter critical section (m_pFilter->pStateLock()) to serialise +// access to functions. Note that, in general, this lock may be held +// by a function when the worker thread may want to hold it. Therefore +// if you wish to access shared state from the worker thread you will +// need to add another critical section object. The execption is during +// the threads processing loop, when it is safe to get the filter critical +// section from within FillBuffer(). + +#include "streams.h" + + +// +// CSource::Constructor +// +// Initialise the pin count for the filter. The user will create the pins in +// the derived class. +CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ +} + +CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ + UNREFERENCED_PARAMETER(phr); +} + +#ifdef UNICODE +CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ +} + +CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ + UNREFERENCED_PARAMETER(phr); +} +#endif + +// +// CSource::Destructor +// +CSource::~CSource() +{ + /* Free our pins and pin array */ + while (m_iPins != 0) { + // deleting the pins causes them to be removed from the array... + delete m_paStreams[m_iPins - 1]; + } + + ASSERT(m_paStreams == NULL); +} + + +// +// Add a new pin +// +HRESULT CSource::AddPin(__in CSourceStream *pStream) +{ + CAutoLock lock(&m_cStateLock); + + /* Allocate space for this pin and the old ones */ + CSourceStream **paStreams = new CSourceStream *[m_iPins + 1]; + if (paStreams == NULL) { + return E_OUTOFMEMORY; + } + if (m_paStreams != NULL) { + CopyMemory((PVOID)paStreams, (PVOID)m_paStreams, + m_iPins * sizeof(m_paStreams[0])); + paStreams[m_iPins] = pStream; + delete [] m_paStreams; + } + m_paStreams = paStreams; + m_paStreams[m_iPins] = pStream; + m_iPins++; + return S_OK; +} + +// +// Remove a pin - pStream is NOT deleted +// +HRESULT CSource::RemovePin(__in CSourceStream *pStream) +{ + int i; + for (i = 0; i < m_iPins; i++) { + if (m_paStreams[i] == pStream) { + if (m_iPins == 1) { + delete [] m_paStreams; + m_paStreams = NULL; + } else { + /* no need to reallocate */ + while (++i < m_iPins) + m_paStreams[i - 1] = m_paStreams[i]; + } + m_iPins--; + return S_OK; + } + } + return S_FALSE; +} + +// +// FindPin +// +// Set *ppPin to the IPin* that has the id Id. +// or to NULL if the Id cannot be matched. +STDMETHODIMP CSource::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + // The -1 undoes the +1 in QueryId and ensures that totally invalid + // strings (for which WstrToInt delivers 0) give a deliver a NULL pin. + int i = WstrToInt(Id) -1; + *ppPin = GetPin(i); + if (*ppPin!=NULL){ + (*ppPin)->AddRef(); + return NOERROR; + } else { + return VFW_E_NOT_FOUND; + } +} + +// +// FindPinNumber +// +// return the number of the pin with this IPin* or -1 if none +int CSource::FindPinNumber(__in IPin *iPin) { + int i; + for (i=0; in && n>=0 it follows that m_iPins>0 + // which is what used to be checked (i.e. checking that we have a pin) + if ((n >= 0) && (n < m_iPins)) { + + ASSERT(m_paStreams[n]); + return m_paStreams[n]; + } + return NULL; +} + + +// + + +// * +// * --- CSourceStream ---- +// * + +// +// Set Id to point to a CoTaskMemAlloc'd +STDMETHODIMP CSourceStream::QueryId(__deref_out LPWSTR *Id) { + CheckPointer(Id,E_POINTER); + ValidateReadWritePtr(Id,sizeof(LPWSTR)); + + // We give the pins id's which are 1,2,... + // FindPinNumber returns -1 for an invalid pin + int i = 1+ m_pFilter->FindPinNumber(this); + if (i<1) return VFW_E_NOT_FOUND; + *Id = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * 12); + if (*Id==NULL) { + return E_OUTOFMEMORY; + } + IntToWstr(i, *Id); + return NOERROR; +} + + + +// +// CSourceStream::Constructor +// +// increments the number of pins present on the filter +CSourceStream::CSourceStream( + __in_opt LPCTSTR pObjectName, + __inout HRESULT *phr, + __inout CSource *ps, + __in_opt LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), + m_pFilter(ps) { + + *phr = m_pFilter->AddPin(this); +} + +#ifdef UNICODE +CSourceStream::CSourceStream( + __in_opt LPCSTR pObjectName, + __inout HRESULT *phr, + __inout CSource *ps, + __in_opt LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), + m_pFilter(ps) { + + *phr = m_pFilter->AddPin(this); +} +#endif +// +// CSourceStream::Destructor +// +// Decrements the number of pins on this filter +CSourceStream::~CSourceStream(void) { + + m_pFilter->RemovePin(this); +} + + +// +// CheckMediaType +// +// Do we support this type? Provides the default support for 1 type. +HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) { + + CAutoLock lock(m_pFilter->pStateLock()); + + CMediaType mt; + GetMediaType(&mt); + + if (mt == *pMediaType) { + return NOERROR; + } + + return E_FAIL; +} + + +// +// GetMediaType/3 +// +// By default we support only one type +// iPosition indexes are 0-n +HRESULT CSourceStream::GetMediaType(int iPosition, __inout CMediaType *pMediaType) { + + CAutoLock lock(m_pFilter->pStateLock()); + + if (iPosition<0) { + return E_INVALIDARG; + } + if (iPosition>0) { + return VFW_S_NO_MORE_ITEMS; + } + return GetMediaType(pMediaType); +} + + +// +// Active +// +// The pin is active - start up the worker thread +HRESULT CSourceStream::Active(void) { + + CAutoLock lock(m_pFilter->pStateLock()); + + HRESULT hr; + + if (m_pFilter->IsActive()) { + return S_FALSE; // succeeded, but did not allocate resources (they already exist...) + } + + // do nothing if not connected - its ok not to connect to + // all pins of a source filter + if (!IsConnected()) { + return NOERROR; + } + + hr = CBaseOutputPin::Active(); + if (FAILED(hr)) { + return hr; + } + + ASSERT(!ThreadExists()); + + // start the thread + if (!Create()) { + return E_FAIL; + } + + // Tell thread to initialize. If OnThreadCreate Fails, so does this. + hr = Init(); + if (FAILED(hr)) + return hr; + + return Pause(); +} + + +// +// Inactive +// +// Pin is inactive - shut down the worker thread +// Waits for the worker to exit before returning. +HRESULT CSourceStream::Inactive(void) { + + CAutoLock lock(m_pFilter->pStateLock()); + + HRESULT hr; + + // do nothing if not connected - its ok not to connect to + // all pins of a source filter + if (!IsConnected()) { + return NOERROR; + } + + // !!! need to do this before trying to stop the thread, because + // we may be stuck waiting for our own allocator!!! + + hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator + if (FAILED(hr)) { + return hr; + } + + if (ThreadExists()) { + hr = Stop(); + + if (FAILED(hr)) { + return hr; + } + + hr = Exit(); + if (FAILED(hr)) { + return hr; + } + + Close(); // Wait for the thread to exit, then tidy up. + } + + // hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator + //if (FAILED(hr)) { + // return hr; + //} + + return NOERROR; +} + + +// +// ThreadProc +// +// When this returns the thread exits +// Return codes > 0 indicate an error occured +DWORD CSourceStream::ThreadProc(void) { + + HRESULT hr; // the return code from calls + Command com; + + do { + com = GetRequest(); + if (com != CMD_INIT) { + DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command"))); + Reply((DWORD) E_UNEXPECTED); + } + } while (com != CMD_INIT); + + DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing"))); + + hr = OnThreadCreate(); // perform set up tasks + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread."))); + OnThreadDestroy(); + Reply(hr); // send failed return code from OnThreadCreate + return 1; + } + + // Initialisation suceeded + Reply(NOERROR); + + Command cmd; + do { + cmd = GetRequest(); + + switch (cmd) { + + case CMD_EXIT: + Reply(NOERROR); + break; + + case CMD_RUN: + DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???"))); + // !!! fall through??? + + case CMD_PAUSE: + Reply(NOERROR); + DoBufferProcessingLoop(); + break; + + case CMD_STOP: + Reply(NOERROR); + break; + + default: + DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd)); + Reply((DWORD) E_NOTIMPL); + break; + } + } while (cmd != CMD_EXIT); + + hr = OnThreadDestroy(); // tidy up. + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread."))); + return 1; + } + + DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting"))); + return 0; +} + + +// +// DoBufferProcessingLoop +// +// Grabs a buffer and calls the users processing function. +// Overridable, so that different delivery styles can be catered for. +HRESULT CSourceStream::DoBufferProcessingLoop(void) { + + Command com; + + OnThreadStartPlay(); + + do { + while (!CheckRequest(&com)) { + + IMediaSample *pSample; + + HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); + if (FAILED(hr)) { + Sleep(1); + continue; // go round again. Perhaps the error will go away + // or the allocator is decommited & we will be asked to + // exit soon. + } + + // Virtual function user will override. + hr = FillBuffer(pSample); + + if (hr == S_OK) { + hr = Deliver(pSample); + pSample->Release(); + + // downstream filter returns S_FALSE if it wants us to + // stop or an error if it's reporting an error. + if(hr != S_OK) + { + DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); + return S_OK; + } + + } else if (hr == S_FALSE) { + // derived class wants us to stop pushing data + pSample->Release(); + DeliverEndOfStream(); + return S_OK; + } else { + // derived class encountered an error + pSample->Release(); + DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); + DeliverEndOfStream(); + m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); + return hr; + } + + // all paths release the sample + } + + // For all commands sent to us there must be a Reply call! + + if (com == CMD_RUN || com == CMD_PAUSE) { + Reply(NOERROR); + } else if (com != CMD_STOP) { + Reply((DWORD) E_UNEXPECTED); + DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); + } + } while (com != CMD_STOP); + + return S_FALSE; +} + diff --git a/src/thirdparty/BaseClasses/source.h b/src/thirdparty/BaseClasses/source.h index 528d5bcbf39..e6e451bd057 100644 --- a/src/thirdparty/BaseClasses/source.h +++ b/src/thirdparty/BaseClasses/source.h @@ -1,172 +1,172 @@ -//------------------------------------------------------------------------------ -// File: Source.h -// -// Desc: DirectShow base classes - defines classes to simplify creation of -// ActiveX source filters that support continuous generation of data. -// No support is provided for IMediaControl or IMediaPosition. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// Derive your source filter from CSource. -// During construction either: -// Create some CSourceStream objects to manage your pins -// Provide the user with a means of doing so eg, an IPersistFile interface. -// -// CSource provides: -// IBaseFilter interface management -// IMediaFilter interface management, via CBaseFilter -// Pin counting for CBaseFilter -// -// Derive a class from CSourceStream to manage your output pin types -// Implement GetMediaType/1 to return the type you support. If you support multiple -// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount. -// Implement Fillbuffer() to put data into one buffer. -// -// CSourceStream provides: -// IPin management via CBaseOutputPin -// Worker thread management - -#ifndef __CSOURCE__ -#define __CSOURCE__ - -class CSourceStream; // The class that will handle each pin - - -// -// CSource -// -// Override construction to provide a means of creating -// CSourceStream derived objects - ie a way of creating pins. -class CSource : public CBaseFilter { -public: - - CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr); - CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid); -#ifdef UNICODE - CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr); - CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid); -#endif - ~CSource(); - - int GetPinCount(void); - CBasePin *GetPin(int n); - - // -- Utilities -- - - CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section - - HRESULT AddPin(__in CSourceStream *); - HRESULT RemovePin(__in CSourceStream *); - - STDMETHODIMP FindPin( - LPCWSTR Id, - __deref_out IPin ** ppPin - ); - - int FindPinNumber(__in IPin *iPin); - -protected: - - int m_iPins; // The number of pins on this filter. Updated by CSourceStream - // constructors & destructors. - CSourceStream **m_paStreams; // the pins on this filter. - - CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state - -}; - - -// -// CSourceStream -// -// Use this class to manage a stream of data that comes from a -// pin. -// Uses a worker thread to put data on the pin. -class CSourceStream : public CAMThread, public CBaseOutputPin { -public: - - CSourceStream(__in_opt LPCTSTR pObjectName, - __inout HRESULT *phr, - __inout CSource *pms, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CSourceStream(__in_opt LPCSTR pObjectName, - __inout HRESULT *phr, - __inout CSource *pms, - __in_opt LPCWSTR pName); -#endif - virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too. - -protected: - - CSource *m_pFilter; // The parent of this stream - - // * - // * Data Source - // * - // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are - // * called from within the ThreadProc. They are used in the creation of - // * the media samples this pin will provide - // * - - // Override this to provide the worker thread a means - // of processing a buffer - virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE; - - // Called as the thread is created/destroyed - use to perform - // jobs such as start/stop streaming mode - // If OnThreadCreate returns an error the thread will exit. - virtual HRESULT OnThreadCreate(void) {return NOERROR;}; - virtual HRESULT OnThreadDestroy(void) {return NOERROR;}; - virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}; - - // * - // * Worker Thread - // * - - HRESULT Active(void); // Starts up the worker thread - HRESULT Inactive(void); // Exits the worker thread. - -public: - // thread commands - enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}; - HRESULT Init(void) { return CallWorker(CMD_INIT); } - HRESULT Exit(void) { return CallWorker(CMD_EXIT); } - HRESULT Run(void) { return CallWorker(CMD_RUN); } - HRESULT Pause(void) { return CallWorker(CMD_PAUSE); } - HRESULT Stop(void) { return CallWorker(CMD_STOP); } - -protected: - Command GetRequest(void) { return (Command) CAMThread::GetRequest(); } - BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); } - - // override these if you want to add thread commands - virtual DWORD ThreadProc(void); // the thread function - - virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running - - - // * - // * AM_MEDIA_TYPE support - // * - - // If you support more than one media type then override these 2 functions - virtual HRESULT CheckMediaType(const CMediaType *pMediaType); - virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); // List pos. 0-n - - // If you support only one type then override this fn. - // This will only be called by the default implementations - // of CheckMediaType and GetMediaType(int, CMediaType*) - // You must override this fn. or the above 2! - virtual HRESULT GetMediaType(__inout CMediaType *pMediaType) {return E_UNEXPECTED;} - - STDMETHODIMP QueryId( - __deref_out LPWSTR * Id - ); -}; - -#endif // __CSOURCE__ - +//------------------------------------------------------------------------------ +// File: Source.h +// +// Desc: DirectShow base classes - defines classes to simplify creation of +// ActiveX source filters that support continuous generation of data. +// No support is provided for IMediaControl or IMediaPosition. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// Derive your source filter from CSource. +// During construction either: +// Create some CSourceStream objects to manage your pins +// Provide the user with a means of doing so eg, an IPersistFile interface. +// +// CSource provides: +// IBaseFilter interface management +// IMediaFilter interface management, via CBaseFilter +// Pin counting for CBaseFilter +// +// Derive a class from CSourceStream to manage your output pin types +// Implement GetMediaType/1 to return the type you support. If you support multiple +// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount. +// Implement Fillbuffer() to put data into one buffer. +// +// CSourceStream provides: +// IPin management via CBaseOutputPin +// Worker thread management + +#ifndef __CSOURCE__ +#define __CSOURCE__ + +class CSourceStream; // The class that will handle each pin + + +// +// CSource +// +// Override construction to provide a means of creating +// CSourceStream derived objects - ie a way of creating pins. +class CSource : public CBaseFilter { +public: + + CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr); + CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid); +#ifdef UNICODE + CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr); + CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid); +#endif + ~CSource(); + + int GetPinCount(void); + CBasePin *GetPin(int n); + + // -- Utilities -- + + CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section + + HRESULT AddPin(__in CSourceStream *); + HRESULT RemovePin(__in CSourceStream *); + + STDMETHODIMP FindPin( + LPCWSTR Id, + __deref_out IPin ** ppPin + ); + + int FindPinNumber(__in IPin *iPin); + +protected: + + int m_iPins; // The number of pins on this filter. Updated by CSourceStream + // constructors & destructors. + CSourceStream **m_paStreams; // the pins on this filter. + + CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state + +}; + + +// +// CSourceStream +// +// Use this class to manage a stream of data that comes from a +// pin. +// Uses a worker thread to put data on the pin. +class CSourceStream : public CAMThread, public CBaseOutputPin { +public: + + CSourceStream(__in_opt LPCTSTR pObjectName, + __inout HRESULT *phr, + __inout CSource *pms, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CSourceStream(__in_opt LPCSTR pObjectName, + __inout HRESULT *phr, + __inout CSource *pms, + __in_opt LPCWSTR pName); +#endif + virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too. + +protected: + + CSource *m_pFilter; // The parent of this stream + + // * + // * Data Source + // * + // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are + // * called from within the ThreadProc. They are used in the creation of + // * the media samples this pin will provide + // * + + // Override this to provide the worker thread a means + // of processing a buffer + virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE; + + // Called as the thread is created/destroyed - use to perform + // jobs such as start/stop streaming mode + // If OnThreadCreate returns an error the thread will exit. + virtual HRESULT OnThreadCreate(void) {return NOERROR;}; + virtual HRESULT OnThreadDestroy(void) {return NOERROR;}; + virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}; + + // * + // * Worker Thread + // * + + HRESULT Active(void); // Starts up the worker thread + HRESULT Inactive(void); // Exits the worker thread. + +public: + // thread commands + enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}; + HRESULT Init(void) { return CallWorker(CMD_INIT); } + HRESULT Exit(void) { return CallWorker(CMD_EXIT); } + HRESULT Run(void) { return CallWorker(CMD_RUN); } + HRESULT Pause(void) { return CallWorker(CMD_PAUSE); } + HRESULT Stop(void) { return CallWorker(CMD_STOP); } + +protected: + Command GetRequest(void) { return (Command) CAMThread::GetRequest(); } + BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); } + + // override these if you want to add thread commands + virtual DWORD ThreadProc(void); // the thread function + + virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running + + + // * + // * AM_MEDIA_TYPE support + // * + + // If you support more than one media type then override these 2 functions + virtual HRESULT CheckMediaType(const CMediaType *pMediaType); + virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); // List pos. 0-n + + // If you support only one type then override this fn. + // This will only be called by the default implementations + // of CheckMediaType and GetMediaType(int, CMediaType*) + // You must override this fn. or the above 2! + virtual HRESULT GetMediaType(__inout CMediaType *pMediaType) {return E_UNEXPECTED;} + + STDMETHODIMP QueryId( + __deref_out LPWSTR * Id + ); +}; + +#endif // __CSOURCE__ + diff --git a/src/thirdparty/BaseClasses/stdafx.cpp b/src/thirdparty/BaseClasses/stdafx.cpp index e728f2aafae..a5e9f4e73ff 100644 --- a/src/thirdparty/BaseClasses/stdafx.cpp +++ b/src/thirdparty/BaseClasses/stdafx.cpp @@ -1,23 +1,23 @@ -/* - * (C) 2011-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 . - * - */ - -// precompiled headers support - -#include "streams.h" +/* + * (C) 2011-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 . + * + */ + +// precompiled headers support + +#include "streams.h" diff --git a/src/thirdparty/BaseClasses/streams.h b/src/thirdparty/BaseClasses/streams.h index e91bdf67914..750252c698d 100644 --- a/src/thirdparty/BaseClasses/streams.h +++ b/src/thirdparty/BaseClasses/streams.h @@ -1,190 +1,190 @@ -//------------------------------------------------------------------------------ -// File: Streams.h -// -// Desc: DirectShow base classes - defines overall streams architecture. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __STREAMS__ -#define __STREAMS__ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#ifdef _MSC_VER -// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable -#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter -#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union -#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated -#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated -#pragma warning(disable:4514) // warning C4514: "unreferenced inline function has been removed" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif - -#if _MSC_VER>=1100 -#define AM_NOVTABLE __declspec(novtable) -#else -#define AM_NOVTABLE -#endif -#endif // MSC_VER - - -// Because of differences between Visual C++ and older Microsoft SDKs, -// you may have defined _DEBUG without defining DEBUG. This logic -// ensures that both will be set if Visual C++ sets _DEBUG. -#ifdef _DEBUG -#ifndef DEBUG -#define DEBUG -#endif -#endif - - -#include -#include -#include -#include -#include -#include - - -#ifndef NUMELMS -#if _WIN32_WINNT < 0x0600 - #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) -#else - #define NUMELMS(aa) ARRAYSIZE(aa) -#endif -#endif - -/////////////////////////////////////////////////////////////////////////// -// The following definitions come from the Platform SDK and are required if -// the applicaiton is being compiled with the headers from Visual C++ 6.0. -/////////////////////////////////////////////////// //////////////////////// -#ifndef InterlockedExchangePointer - #define InterlockedExchangePointer(Target, Value) \ - (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) -#endif - -#ifndef _WAVEFORMATEXTENSIBLE_ -#define _WAVEFORMATEXTENSIBLE_ -typedef struct { - WAVEFORMATEX Format; - union { - WORD wValidBitsPerSample; /* bits of precision */ - WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ - WORD wReserved; /* If neither applies, set to zero. */ - } Samples; - DWORD dwChannelMask; /* which channels are */ - /* present in stream */ - GUID SubFormat; -} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; -#endif // !_WAVEFORMATEXTENSIBLE_ - -#if !defined(WAVE_FORMAT_EXTENSIBLE) -#define WAVE_FORMAT_EXTENSIBLE 0xFFFE -#endif // !defined(WAVE_FORMAT_EXTENSIBLE) - -#ifndef GetWindowLongPtr - #define GetWindowLongPtrA GetWindowLongA - #define GetWindowLongPtrW GetWindowLongW - #ifdef UNICODE - #define GetWindowLongPtr GetWindowLongPtrW - #else - #define GetWindowLongPtr GetWindowLongPtrA - #endif // !UNICODE -#endif // !GetWindowLongPtr - -#ifndef SetWindowLongPtr - #define SetWindowLongPtrA SetWindowLongA - #define SetWindowLongPtrW SetWindowLongW - #ifdef UNICODE - #define SetWindowLongPtr SetWindowLongPtrW - #else - #define SetWindowLongPtr SetWindowLongPtrA - #endif // !UNICODE -#endif // !SetWindowLongPtr - -#ifndef GWLP_WNDPROC - #define GWLP_WNDPROC (-4) -#endif -#ifndef GWLP_HINSTANCE - #define GWLP_HINSTANCE (-6) -#endif -#ifndef GWLP_HWNDPARENT - #define GWLP_HWNDPARENT (-8) -#endif -#ifndef GWLP_USERDATA - #define GWLP_USERDATA (-21) -#endif -#ifndef GWLP_ID - #define GWLP_ID (-12) -#endif -#ifndef DWLP_MSGRESULT - #define DWLP_MSGRESULT 0 -#endif -#ifndef DWLP_DLGPROC - #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) -#endif -#ifndef DWLP_USER - #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) -#endif -/////////////////////////////////////////////////////////////////////////// -// End Platform SDK definitions -/////////////////////////////////////////////////////////////////////////// - - -#include // Generated IDL header file for streams interfaces -#include // required by amvideo.h - -#include "reftime.h" // Helper class for REFERENCE_TIME management -#include "wxdebug.h" // Debug support for logging and ASSERTs -#include // ActiveMovie video interfaces and definitions -//include amaudio.h explicitly if you need it. it requires the DX SDK. -//#include // ActiveMovie audio interfaces and definitions -#include "wxutil.h" // General helper classes for threads etc -#include "combase.h" // Base COM classes to support IUnknown -#include "dllsetup.h" // Filter registration support functions -#include "measure.h" // Performance measurement -#include // Light weight com function prototypes - -#include "cache.h" // Simple cache container class -#include "wxlist.h" // Non MFC generic list class -#include "msgthrd.h" // CMsgThread -#include "mtype.h" // Helper class for managing media types -#include "fourcc.h" // conversions between FOURCCs and GUIDs -#include // generated from control.odl -#include "ctlutil.h" // control interface utility classes -#include // event code definitions -#include "amfilter.h" // Main streams architecture class hierachy -#include "transfrm.h" // Generic transform filter -#include "transip.h" // Generic transform-in-place filter -#include // declaration of type GUIDs and well-known clsids -#include "source.h" // Generic source filter -#include "outputq.h" // Output pin queueing -#include // HRESULT status and error definitions -#include "renbase.h" // Base class for writing ActiveX renderers -#include "winutil.h" // Helps with filters that manage windows -#include "winctrl.h" // Implements the IVideoWindow interface -#include "videoctl.h" // Specifically video related classes -#include "refclock.h" // Base clock class -#include "sysclock.h" // System clock -#include "pstream.h" // IPersistStream helper class -#include "vtrans.h" // Video Transform Filter base class -#include "amextra.h" -#include "cprop.h" // Base property page class -#include "strmctl.h" // IAMStreamControl support -#include // External device control interface defines -#include // audio filter device error event codes - - - -#else - #ifdef _DEBUG - #pragma message("STREAMS.H included TWICE") - #endif -#endif // __STREAMS__ - +//------------------------------------------------------------------------------ +// File: Streams.h +// +// Desc: DirectShow base classes - defines overall streams architecture. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __STREAMS__ +#define __STREAMS__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef _MSC_VER +// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable +#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter +#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union +#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated +#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated +#pragma warning(disable:4514) // warning C4514: "unreferenced inline function has been removed" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif + +#if _MSC_VER>=1100 +#define AM_NOVTABLE __declspec(novtable) +#else +#define AM_NOVTABLE +#endif +#endif // MSC_VER + + +// Because of differences between Visual C++ and older Microsoft SDKs, +// you may have defined _DEBUG without defining DEBUG. This logic +// ensures that both will be set if Visual C++ sets _DEBUG. +#ifdef _DEBUG +#ifndef DEBUG +#define DEBUG +#endif +#endif + + +#include +#include +#include +#include +#include +#include + + +#ifndef NUMELMS +#if _WIN32_WINNT < 0x0600 + #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) +#else + #define NUMELMS(aa) ARRAYSIZE(aa) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////// +// The following definitions come from the Platform SDK and are required if +// the applicaiton is being compiled with the headers from Visual C++ 6.0. +/////////////////////////////////////////////////// //////////////////////// +#ifndef InterlockedExchangePointer + #define InterlockedExchangePointer(Target, Value) \ + (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) +#endif + +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct { + WAVEFORMATEX Format; + union { + WORD wValidBitsPerSample; /* bits of precision */ + WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ + WORD wReserved; /* If neither applies, set to zero. */ + } Samples; + DWORD dwChannelMask; /* which channels are */ + /* present in stream */ + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; +#endif // !_WAVEFORMATEXTENSIBLE_ + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif // !defined(WAVE_FORMAT_EXTENSIBLE) + +#ifndef GetWindowLongPtr + #define GetWindowLongPtrA GetWindowLongA + #define GetWindowLongPtrW GetWindowLongW + #ifdef UNICODE + #define GetWindowLongPtr GetWindowLongPtrW + #else + #define GetWindowLongPtr GetWindowLongPtrA + #endif // !UNICODE +#endif // !GetWindowLongPtr + +#ifndef SetWindowLongPtr + #define SetWindowLongPtrA SetWindowLongA + #define SetWindowLongPtrW SetWindowLongW + #ifdef UNICODE + #define SetWindowLongPtr SetWindowLongPtrW + #else + #define SetWindowLongPtr SetWindowLongPtrA + #endif // !UNICODE +#endif // !SetWindowLongPtr + +#ifndef GWLP_WNDPROC + #define GWLP_WNDPROC (-4) +#endif +#ifndef GWLP_HINSTANCE + #define GWLP_HINSTANCE (-6) +#endif +#ifndef GWLP_HWNDPARENT + #define GWLP_HWNDPARENT (-8) +#endif +#ifndef GWLP_USERDATA + #define GWLP_USERDATA (-21) +#endif +#ifndef GWLP_ID + #define GWLP_ID (-12) +#endif +#ifndef DWLP_MSGRESULT + #define DWLP_MSGRESULT 0 +#endif +#ifndef DWLP_DLGPROC + #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) +#endif +#ifndef DWLP_USER + #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) +#endif +/////////////////////////////////////////////////////////////////////////// +// End Platform SDK definitions +/////////////////////////////////////////////////////////////////////////// + + +#include // Generated IDL header file for streams interfaces +#include // required by amvideo.h + +#include "reftime.h" // Helper class for REFERENCE_TIME management +#include "wxdebug.h" // Debug support for logging and ASSERTs +#include // ActiveMovie video interfaces and definitions +//include amaudio.h explicitly if you need it. it requires the DX SDK. +//#include // ActiveMovie audio interfaces and definitions +#include "wxutil.h" // General helper classes for threads etc +#include "combase.h" // Base COM classes to support IUnknown +#include "dllsetup.h" // Filter registration support functions +#include "measure.h" // Performance measurement +#include // Light weight com function prototypes + +#include "cache.h" // Simple cache container class +#include "wxlist.h" // Non MFC generic list class +#include "msgthrd.h" // CMsgThread +#include "mtype.h" // Helper class for managing media types +#include "fourcc.h" // conversions between FOURCCs and GUIDs +#include // generated from control.odl +#include "ctlutil.h" // control interface utility classes +#include // event code definitions +#include "amfilter.h" // Main streams architecture class hierachy +#include "transfrm.h" // Generic transform filter +#include "transip.h" // Generic transform-in-place filter +#include // declaration of type GUIDs and well-known clsids +#include "source.h" // Generic source filter +#include "outputq.h" // Output pin queueing +#include // HRESULT status and error definitions +#include "renbase.h" // Base class for writing ActiveX renderers +#include "winutil.h" // Helps with filters that manage windows +#include "winctrl.h" // Implements the IVideoWindow interface +#include "videoctl.h" // Specifically video related classes +#include "refclock.h" // Base clock class +#include "sysclock.h" // System clock +#include "pstream.h" // IPersistStream helper class +#include "vtrans.h" // Video Transform Filter base class +#include "amextra.h" +#include "cprop.h" // Base property page class +#include "strmctl.h" // IAMStreamControl support +#include // External device control interface defines +#include // audio filter device error event codes + + + +#else + #ifdef _DEBUG + #pragma message("STREAMS.H included TWICE") + #endif +#endif // __STREAMS__ + diff --git a/src/thirdparty/BaseClasses/strmctl.cpp b/src/thirdparty/BaseClasses/strmctl.cpp index 846b0d24319..e2bad28b9c3 100644 --- a/src/thirdparty/BaseClasses/strmctl.cpp +++ b/src/thirdparty/BaseClasses/strmctl.cpp @@ -1,405 +1,405 @@ -//------------------------------------------------------------------------------ -// File: StrmCtl.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "strmctl.h" - -CBaseStreamControl::CBaseStreamControl(__inout HRESULT *phr) -: m_StreamState(STREAM_FLOWING) -, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop -, m_tStartTime(MAX_TIME) -, m_tStopTime(MAX_TIME) -, m_StreamEvent(FALSE, phr) -, m_dwStartCookie(0) -, m_dwStopCookie(0) -, m_pRefClock(NULL) -, m_FilterState(State_Stopped) -, m_bIsFlushing(FALSE) -, m_bStopSendExtra(FALSE) -, m_bStopExtraSent(FALSE) -, m_pSink(NULL) -, m_tRunStart(0) -{} - -CBaseStreamControl::~CBaseStreamControl() -{ - // Make sure we release the clock. - SetSyncSource(NULL); - return; -} - - -STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) -{ - CAutoLock lck(&m_CritSec); - m_bStopSendExtra = FALSE; // reset - m_bStopExtraSent = FALSE; - if (ptStop) - { - if (*ptStop == MAX_TIME) - { - DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop"))); - CancelStop(); - // If there's now a command to start in the future, we assume - // they want to be stopped when the graph is first run - if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) { - m_StreamState = STREAM_DISCARDING; - DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); - } - return NOERROR; - } - DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"), - (int)(*ptStop/10000), bSendExtra)); - // if the first command is to stop in the future, then we assume they - // want to be started when the graph is first run - if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) { - m_StreamState = STREAM_FLOWING; - DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); - } - m_bStopSendExtra = bSendExtra; - m_tStopTime = *ptStop; - m_dwStopCookie = dwCookie; - m_StreamStateOnStop = STREAM_DISCARDING; - } - else - { - DbgLog((LOG_TRACE,2,TEXT("StopAt: now"))); - // sending an extra frame when told to stop now would mess people up - m_bStopSendExtra = FALSE; - m_tStopTime = MAX_TIME; - m_dwStopCookie = 0; - m_StreamState = STREAM_DISCARDING; - m_StreamStateOnStop = STREAM_FLOWING; // no pending stop - } - // we might change our mind what to do with a sample we're blocking - m_StreamEvent.Set(); - return NOERROR; -} - -STDMETHODIMP CBaseStreamControl::StartAt -( const REFERENCE_TIME *ptStart, DWORD dwCookie ) -{ - CAutoLock lck(&m_CritSec); - if (ptStart) - { - if (*ptStart == MAX_TIME) - { - DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start"))); - CancelStart(); - // If there's now a command to stop in the future, we assume - // they want to be started when the graph is first run - if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) { - DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); - m_StreamState = STREAM_FLOWING; - } - return NOERROR; - } - DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000))); - // if the first command is to start in the future, then we assume they - // want to be stopped when the graph is first run - if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) { - DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); - m_StreamState = STREAM_DISCARDING; - } - m_tStartTime = *ptStart; - m_dwStartCookie = dwCookie; - // if (m_tStopTime == m_tStartTime) CancelStop(); - } - else - { - DbgLog((LOG_TRACE,2,TEXT("StartAt: now"))); - m_tStartTime = MAX_TIME; - m_dwStartCookie = 0; - m_StreamState = STREAM_FLOWING; - } - // we might change our mind what to do with a sample we're blocking - m_StreamEvent.Set(); - return NOERROR; -} - -// Retrieve information about current settings -STDMETHODIMP CBaseStreamControl::GetInfo(__out AM_STREAM_INFO *pInfo) -{ - if (pInfo == NULL) - return E_POINTER; - - pInfo->tStart = m_tStartTime; - pInfo->tStop = m_tStopTime; - pInfo->dwStartCookie = m_dwStartCookie; - pInfo->dwStopCookie = m_dwStopCookie; - pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0; - pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED; - pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED; - switch (m_StreamState) { - default: - DbgBreak("Invalid stream state"); - case STREAM_FLOWING: - break; - case STREAM_DISCARDING: - pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING; - break; - } - return S_OK; -} - - -void CBaseStreamControl::ExecuteStop() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_StreamState = m_StreamStateOnStop; - if (m_dwStopCookie && m_pSink) { - DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"), - m_dwStopCookie)); - m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie); - } - CancelStop(); // This will do the tidy up -} - -void CBaseStreamControl::ExecuteStart() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_StreamState = STREAM_FLOWING; - if (m_dwStartCookie) { - DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"), - m_dwStartCookie)); - m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie); - } - CancelStart(); // This will do the tidy up -} - -void CBaseStreamControl::CancelStop() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_tStopTime = MAX_TIME; - m_dwStopCookie = 0; - m_StreamStateOnStop = STREAM_FLOWING; -} - -void CBaseStreamControl::CancelStart() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_tStartTime = MAX_TIME; - m_dwStartCookie = 0; -} - - -// This guy will return one of the three StreamControlState's. Here's what the caller -// should do for each one: -// -// STREAM_FLOWING: Proceed as usual (render or pass the sample on) -// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long -// for the event handle (GetStreamEventHandle()). If the -// wait expires, throw the sample away. If the event -// fires, call me back, I've changed my mind. -// I use pSampleStart (not Stop) so that live sources don't -// block for the duration of their samples, since the clock -// will always read approximately pSampleStart when called - - -// All through this code, you'll notice the following rules: -// - When start and stop time are the same, it's as if start was first -// - An event is considered inside the sample when it's >= sample start time -// but < sample stop time -// - if any part of the sample is supposed to be sent, we'll send the whole -// thing since we don't break it into smaller pieces -// - If we skip over a start or stop without doing it, we still signal the event -// and reset ourselves in case somebody's waiting for the event, and to make -// sure we notice that the event is past and should be forgotten -// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample): -// -// 1. xo<--> start then stop -// 2. ox<--> stop then start -// 3. x start -// 4. o stop then start -// 5. x<-->o start -// 6. o<-->x stop -// 7. o start -// 8. x no change -// 9. start -// 10. stop then start -// 11. <-->xo no change -// 12. <-->ox no change -// 13. x<--> start -// 14. start -// 15. <-->x no change -// 16. o<--> stop -// 17. no change -// 18. <-->o no change -// 19. <--> no change - - -enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes -( __in const REFERENCE_TIME * pSampleStart, __in const REFERENCE_TIME * pSampleStop ) -{ - CAutoLock lck(&m_CritSec); - - ASSERT(!m_bIsFlushing); - ASSERT(pSampleStart && pSampleStop); - - // Don't ask me how I came up with the code below to handle all 19 cases - // - DannyMi - - if (m_tStopTime >= *pSampleStart) - { - if (m_tStartTime >= *pSampleStop) - return m_StreamState; // cases 8 11 12 15 17 18 19 - if (m_tStopTime < m_tStartTime) - ExecuteStop(); // case 10 - ExecuteStart(); // cases 3 5 7 9 13 14 - return m_StreamState; - } - - if (m_tStartTime >= *pSampleStop) - { - ExecuteStop(); // cases 6 16 - return m_StreamState; - } - - if (m_tStartTime <= m_tStopTime) - { - ExecuteStart(); - ExecuteStop(); - return m_StreamState; // case 1 - } - else - { - ExecuteStop(); - ExecuteStart(); - return m_StreamState; // cases 2 4 - } -} - - -enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) -{ - - REFERENCE_TIME rtBufferStart, rtBufferStop; - const BOOL bNoBufferTimes = - pSample == NULL || - FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop)); - - StreamControlState state; - LONG lWait; - - do - { - // something has to break out of the blocking - if (m_bIsFlushing || m_FilterState == State_Stopped) - return STREAM_DISCARDING; - - if (bNoBufferTimes) { - // Can't do anything until we get a time stamp - state = m_StreamState; - break; - } else { - state = CheckSampleTimes( &rtBufferStart, &rtBufferStop ); - if (state == STREAM_FLOWING) - break; - - // we aren't supposed to send this, but we've been - // told to send one more than we were supposed to - // (and the stop isn't still pending and we're streaming) - if (m_bStopSendExtra && !m_bStopExtraSent && - m_tStopTime == MAX_TIME && - m_FilterState != State_Stopped) { - m_bStopExtraSent = TRUE; - DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"), - m_dwStopCookie)); - state = STREAM_FLOWING; - break; - } - } - - // We're in discarding mode - - // If we've no clock, discard as fast as we can - if (!m_pRefClock) { - break; - - // If we're paused, we can't discard in a timely manner because - // there's no such thing as stream times. We must block until - // we run or stop, or we'll end up throwing the whole stream away - // as quickly as possible - } else if (m_FilterState == State_Paused) { - lWait = INFINITE; - - } else { - // wait until it's time for the sample until we say "discard" - // ("discard in a timely fashion") - REFERENCE_TIME rtNow; - EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow))); - rtNow -= m_tRunStart; // Into relative ref-time - lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms - if (lWait < 10) break; // Not worth waiting - discard early - } - - } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT); - - return state; -} - - -void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) -{ - CAutoLock lck(&m_CritSec); - - // or we will get confused - if (m_FilterState == new_state) - return; - - switch (new_state) - { - case State_Stopped: - - DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED"))); - - // execute any pending starts and stops in the right order, - // to make sure all notifications get sent, and we end up - // in the right state to begin next time (??? why not?) - - if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) { - ExecuteStart(); - } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) { - ExecuteStop(); - } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) { - if (m_tStartTime <= m_tStopTime) { - ExecuteStart(); - ExecuteStop(); - } else { - ExecuteStop(); - ExecuteStart(); - } - } - // always start off flowing when the graph starts streaming - // unless told otherwise - m_StreamState = STREAM_FLOWING; - m_FilterState = new_state; - break; - - case State_Running: - - DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING"))); - - m_tRunStart = tStart; - // fall-through - - default: // case State_Paused: - m_FilterState = new_state; - } - // unblock! - m_StreamEvent.Set(); -} - - -void CBaseStreamControl::Flushing(BOOL bInProgress) -{ - CAutoLock lck(&m_CritSec); - m_bIsFlushing = bInProgress; - m_StreamEvent.Set(); -} +//------------------------------------------------------------------------------ +// File: StrmCtl.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "strmctl.h" + +CBaseStreamControl::CBaseStreamControl(__inout HRESULT *phr) +: m_StreamState(STREAM_FLOWING) +, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop +, m_tStartTime(MAX_TIME) +, m_tStopTime(MAX_TIME) +, m_StreamEvent(FALSE, phr) +, m_dwStartCookie(0) +, m_dwStopCookie(0) +, m_pRefClock(NULL) +, m_FilterState(State_Stopped) +, m_bIsFlushing(FALSE) +, m_bStopSendExtra(FALSE) +, m_bStopExtraSent(FALSE) +, m_pSink(NULL) +, m_tRunStart(0) +{} + +CBaseStreamControl::~CBaseStreamControl() +{ + // Make sure we release the clock. + SetSyncSource(NULL); + return; +} + + +STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) +{ + CAutoLock lck(&m_CritSec); + m_bStopSendExtra = FALSE; // reset + m_bStopExtraSent = FALSE; + if (ptStop) + { + if (*ptStop == MAX_TIME) + { + DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop"))); + CancelStop(); + // If there's now a command to start in the future, we assume + // they want to be stopped when the graph is first run + if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) { + m_StreamState = STREAM_DISCARDING; + DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); + } + return NOERROR; + } + DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"), + (int)(*ptStop/10000), bSendExtra)); + // if the first command is to stop in the future, then we assume they + // want to be started when the graph is first run + if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) { + m_StreamState = STREAM_FLOWING; + DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); + } + m_bStopSendExtra = bSendExtra; + m_tStopTime = *ptStop; + m_dwStopCookie = dwCookie; + m_StreamStateOnStop = STREAM_DISCARDING; + } + else + { + DbgLog((LOG_TRACE,2,TEXT("StopAt: now"))); + // sending an extra frame when told to stop now would mess people up + m_bStopSendExtra = FALSE; + m_tStopTime = MAX_TIME; + m_dwStopCookie = 0; + m_StreamState = STREAM_DISCARDING; + m_StreamStateOnStop = STREAM_FLOWING; // no pending stop + } + // we might change our mind what to do with a sample we're blocking + m_StreamEvent.Set(); + return NOERROR; +} + +STDMETHODIMP CBaseStreamControl::StartAt +( const REFERENCE_TIME *ptStart, DWORD dwCookie ) +{ + CAutoLock lck(&m_CritSec); + if (ptStart) + { + if (*ptStart == MAX_TIME) + { + DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start"))); + CancelStart(); + // If there's now a command to stop in the future, we assume + // they want to be started when the graph is first run + if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) { + DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); + m_StreamState = STREAM_FLOWING; + } + return NOERROR; + } + DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000))); + // if the first command is to start in the future, then we assume they + // want to be stopped when the graph is first run + if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) { + DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); + m_StreamState = STREAM_DISCARDING; + } + m_tStartTime = *ptStart; + m_dwStartCookie = dwCookie; + // if (m_tStopTime == m_tStartTime) CancelStop(); + } + else + { + DbgLog((LOG_TRACE,2,TEXT("StartAt: now"))); + m_tStartTime = MAX_TIME; + m_dwStartCookie = 0; + m_StreamState = STREAM_FLOWING; + } + // we might change our mind what to do with a sample we're blocking + m_StreamEvent.Set(); + return NOERROR; +} + +// Retrieve information about current settings +STDMETHODIMP CBaseStreamControl::GetInfo(__out AM_STREAM_INFO *pInfo) +{ + if (pInfo == NULL) + return E_POINTER; + + pInfo->tStart = m_tStartTime; + pInfo->tStop = m_tStopTime; + pInfo->dwStartCookie = m_dwStartCookie; + pInfo->dwStopCookie = m_dwStopCookie; + pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0; + pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED; + pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED; + switch (m_StreamState) { + default: + DbgBreak("Invalid stream state"); + case STREAM_FLOWING: + break; + case STREAM_DISCARDING: + pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING; + break; + } + return S_OK; +} + + +void CBaseStreamControl::ExecuteStop() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_StreamState = m_StreamStateOnStop; + if (m_dwStopCookie && m_pSink) { + DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"), + m_dwStopCookie)); + m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie); + } + CancelStop(); // This will do the tidy up +} + +void CBaseStreamControl::ExecuteStart() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_StreamState = STREAM_FLOWING; + if (m_dwStartCookie) { + DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"), + m_dwStartCookie)); + m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie); + } + CancelStart(); // This will do the tidy up +} + +void CBaseStreamControl::CancelStop() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_tStopTime = MAX_TIME; + m_dwStopCookie = 0; + m_StreamStateOnStop = STREAM_FLOWING; +} + +void CBaseStreamControl::CancelStart() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_tStartTime = MAX_TIME; + m_dwStartCookie = 0; +} + + +// This guy will return one of the three StreamControlState's. Here's what the caller +// should do for each one: +// +// STREAM_FLOWING: Proceed as usual (render or pass the sample on) +// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long +// for the event handle (GetStreamEventHandle()). If the +// wait expires, throw the sample away. If the event +// fires, call me back, I've changed my mind. +// I use pSampleStart (not Stop) so that live sources don't +// block for the duration of their samples, since the clock +// will always read approximately pSampleStart when called + + +// All through this code, you'll notice the following rules: +// - When start and stop time are the same, it's as if start was first +// - An event is considered inside the sample when it's >= sample start time +// but < sample stop time +// - if any part of the sample is supposed to be sent, we'll send the whole +// thing since we don't break it into smaller pieces +// - If we skip over a start or stop without doing it, we still signal the event +// and reset ourselves in case somebody's waiting for the event, and to make +// sure we notice that the event is past and should be forgotten +// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample): +// +// 1. xo<--> start then stop +// 2. ox<--> stop then start +// 3. x start +// 4. o stop then start +// 5. x<-->o start +// 6. o<-->x stop +// 7. o start +// 8. x no change +// 9. start +// 10. stop then start +// 11. <-->xo no change +// 12. <-->ox no change +// 13. x<--> start +// 14. start +// 15. <-->x no change +// 16. o<--> stop +// 17. no change +// 18. <-->o no change +// 19. <--> no change + + +enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes +( __in const REFERENCE_TIME * pSampleStart, __in const REFERENCE_TIME * pSampleStop ) +{ + CAutoLock lck(&m_CritSec); + + ASSERT(!m_bIsFlushing); + ASSERT(pSampleStart && pSampleStop); + + // Don't ask me how I came up with the code below to handle all 19 cases + // - DannyMi + + if (m_tStopTime >= *pSampleStart) + { + if (m_tStartTime >= *pSampleStop) + return m_StreamState; // cases 8 11 12 15 17 18 19 + if (m_tStopTime < m_tStartTime) + ExecuteStop(); // case 10 + ExecuteStart(); // cases 3 5 7 9 13 14 + return m_StreamState; + } + + if (m_tStartTime >= *pSampleStop) + { + ExecuteStop(); // cases 6 16 + return m_StreamState; + } + + if (m_tStartTime <= m_tStopTime) + { + ExecuteStart(); + ExecuteStop(); + return m_StreamState; // case 1 + } + else + { + ExecuteStop(); + ExecuteStart(); + return m_StreamState; // cases 2 4 + } +} + + +enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) +{ + + REFERENCE_TIME rtBufferStart, rtBufferStop; + const BOOL bNoBufferTimes = + pSample == NULL || + FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop)); + + StreamControlState state; + LONG lWait; + + do + { + // something has to break out of the blocking + if (m_bIsFlushing || m_FilterState == State_Stopped) + return STREAM_DISCARDING; + + if (bNoBufferTimes) { + // Can't do anything until we get a time stamp + state = m_StreamState; + break; + } else { + state = CheckSampleTimes( &rtBufferStart, &rtBufferStop ); + if (state == STREAM_FLOWING) + break; + + // we aren't supposed to send this, but we've been + // told to send one more than we were supposed to + // (and the stop isn't still pending and we're streaming) + if (m_bStopSendExtra && !m_bStopExtraSent && + m_tStopTime == MAX_TIME && + m_FilterState != State_Stopped) { + m_bStopExtraSent = TRUE; + DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"), + m_dwStopCookie)); + state = STREAM_FLOWING; + break; + } + } + + // We're in discarding mode + + // If we've no clock, discard as fast as we can + if (!m_pRefClock) { + break; + + // If we're paused, we can't discard in a timely manner because + // there's no such thing as stream times. We must block until + // we run or stop, or we'll end up throwing the whole stream away + // as quickly as possible + } else if (m_FilterState == State_Paused) { + lWait = INFINITE; + + } else { + // wait until it's time for the sample until we say "discard" + // ("discard in a timely fashion") + REFERENCE_TIME rtNow; + EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow))); + rtNow -= m_tRunStart; // Into relative ref-time + lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms + if (lWait < 10) break; // Not worth waiting - discard early + } + + } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT); + + return state; +} + + +void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) +{ + CAutoLock lck(&m_CritSec); + + // or we will get confused + if (m_FilterState == new_state) + return; + + switch (new_state) + { + case State_Stopped: + + DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED"))); + + // execute any pending starts and stops in the right order, + // to make sure all notifications get sent, and we end up + // in the right state to begin next time (??? why not?) + + if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) { + ExecuteStart(); + } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) { + ExecuteStop(); + } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) { + if (m_tStartTime <= m_tStopTime) { + ExecuteStart(); + ExecuteStop(); + } else { + ExecuteStop(); + ExecuteStart(); + } + } + // always start off flowing when the graph starts streaming + // unless told otherwise + m_StreamState = STREAM_FLOWING; + m_FilterState = new_state; + break; + + case State_Running: + + DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING"))); + + m_tRunStart = tStart; + // fall-through + + default: // case State_Paused: + m_FilterState = new_state; + } + // unblock! + m_StreamEvent.Set(); +} + + +void CBaseStreamControl::Flushing(BOOL bInProgress) +{ + CAutoLock lck(&m_CritSec); + m_bIsFlushing = bInProgress; + m_StreamEvent.Set(); +} diff --git a/src/thirdparty/BaseClasses/strmctl.h b/src/thirdparty/BaseClasses/strmctl.h index cb2adf30851..4077e6c3478 100644 --- a/src/thirdparty/BaseClasses/strmctl.h +++ b/src/thirdparty/BaseClasses/strmctl.h @@ -1,157 +1,157 @@ -//------------------------------------------------------------------------------ -// File: StrmCtl.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __strmctl_h__ -#define __strmctl_h__ - -class CBaseStreamControl : public IAMStreamControl -{ -public: - // Used by the implementation - enum StreamControlState - { STREAM_FLOWING = 0x1000, - STREAM_DISCARDING - }; - -private: - enum StreamControlState m_StreamState; // Current stream state - enum StreamControlState m_StreamStateOnStop; // State after next stop - // (i.e.Blocking or Discarding) - - REFERENCE_TIME m_tStartTime; // MAX_TIME implies none - REFERENCE_TIME m_tStopTime; // MAX_TIME implies none - DWORD m_dwStartCookie; // Cookie for notification to app - DWORD m_dwStopCookie; // Cookie for notification to app - volatile BOOL m_bIsFlushing; // No optimization pls! - volatile BOOL m_bStopSendExtra; // bSendExtra was set - volatile BOOL m_bStopExtraSent; // the extra one was sent - - CCritSec m_CritSec; // CritSec to guard above attributes - - // Event to fire when we can come - // out of blocking, or to come out of waiting - // to discard if we change our minds. - // - CAMEvent m_StreamEvent; - - // All of these methods execute immediately. Helpers for others. - // - void ExecuteStop(); - void ExecuteStart(); - void CancelStop(); - void CancelStart(); - - // Some things we need to be told by our owning filter - // Your pin must also expose IAMStreamControl when QI'd for it! - // - IReferenceClock * m_pRefClock; // Need it to set advises - // Filter must tell us via - // SetSyncSource - IMediaEventSink * m_pSink; // Event sink - // Filter must tell us after it - // creates it in JoinFilterGraph() - FILTER_STATE m_FilterState; // Just need it! - // Filter must tell us via - // NotifyFilterState - REFERENCE_TIME m_tRunStart; // Per the Run call to the filter - - // This guy will return one of the three StreamControlState's. Here's what - // the caller should do for each one: - // - // STREAM_FLOWING: Proceed as usual (render or pass the sample on) - // STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait - // that long for the event handle - // (GetStreamEventHandle()). If the wait - // expires, throw the sample away. If the event - // fires, call me back - I've changed my mind. - // - enum StreamControlState CheckSampleTimes( __in const REFERENCE_TIME * pSampleStart, - __in const REFERENCE_TIME * pSampleStop ); - -public: - // You don't have to tell us much when we're created, but there are other - // obligations that must be met. See SetSyncSource & NotifyFilterState - // below. - // - CBaseStreamControl(__inout_opt HRESULT *phr = NULL); - ~CBaseStreamControl(); - - // If you want this class to work properly, there are thing you need to - // (keep) telling it. Filters with pins that use this class - // should ensure that they pass through to this method any calls they - // receive on their SetSyncSource. - - // We need a clock to see what time it is. This is for the - // "discard in a timely fashion" logic. If we discard everything as - // quick as possible, a whole 60 minute file could get discarded in the - // first 10 seconds, and if somebody wants to turn streaming on at 30 - // minutes into the file, and they make the call more than a few seconds - // after the graph is run, it may be too late! - // So we hold every sample until it's time has gone, then we discard it. - // The filter should call this when it gets a SetSyncSource - // - void SetSyncSource( IReferenceClock * pRefClock ) - { - CAutoLock lck(&m_CritSec); - if (m_pRefClock) m_pRefClock->Release(); - m_pRefClock = pRefClock; - if (m_pRefClock) m_pRefClock->AddRef(); - } - - // Set event sink for notifications - // The filter should call this in its JoinFilterGraph after it creates the - // IMediaEventSink - // - void SetFilterGraph( IMediaEventSink *pSink ) { - m_pSink = pSink; - } - - // Since we schedule in stream time, we need the tStart and must track the - // state of our owning filter. - // The app should call this ever state change - // - void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 ); - - // Filter should call Flushing(TRUE) in BeginFlush, - // and Flushing(FALSE) in EndFlush. - // - void Flushing( BOOL bInProgress ); - - - // The two main methods of IAMStreamControl - - // Class adds default values suitable for immediate - // muting and unmuting of the stream. - - STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL, - BOOL bSendExtra = FALSE, - DWORD dwCookie = 0 ); - STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL, - DWORD dwCookie = 0 ); - STDMETHODIMP GetInfo( __out AM_STREAM_INFO *pInfo); - - // Helper function for pin's receive method. Call this with - // the sample and we'll tell you what to do with it. We'll do a - // WaitForSingleObject within this call if one is required. This is - // a "What should I do with this sample?" kind of call. We'll tell the - // caller to either flow it or discard it. - // If pSample is NULL we evaluate based on the current state - // settings - enum StreamControlState CheckStreamState( IMediaSample * pSample ); - -private: - // These don't require locking, but we are relying on the fact that - // m_StreamState can be retrieved with integrity, and is a snap shot that - // may have just been, or may be just about to be, changed. - HANDLE GetStreamEventHandle() const { return m_StreamEvent; } - enum StreamControlState GetStreamState() const { return m_StreamState; } - BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; } -}; - -#endif +//------------------------------------------------------------------------------ +// File: StrmCtl.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __strmctl_h__ +#define __strmctl_h__ + +class CBaseStreamControl : public IAMStreamControl +{ +public: + // Used by the implementation + enum StreamControlState + { STREAM_FLOWING = 0x1000, + STREAM_DISCARDING + }; + +private: + enum StreamControlState m_StreamState; // Current stream state + enum StreamControlState m_StreamStateOnStop; // State after next stop + // (i.e.Blocking or Discarding) + + REFERENCE_TIME m_tStartTime; // MAX_TIME implies none + REFERENCE_TIME m_tStopTime; // MAX_TIME implies none + DWORD m_dwStartCookie; // Cookie for notification to app + DWORD m_dwStopCookie; // Cookie for notification to app + volatile BOOL m_bIsFlushing; // No optimization pls! + volatile BOOL m_bStopSendExtra; // bSendExtra was set + volatile BOOL m_bStopExtraSent; // the extra one was sent + + CCritSec m_CritSec; // CritSec to guard above attributes + + // Event to fire when we can come + // out of blocking, or to come out of waiting + // to discard if we change our minds. + // + CAMEvent m_StreamEvent; + + // All of these methods execute immediately. Helpers for others. + // + void ExecuteStop(); + void ExecuteStart(); + void CancelStop(); + void CancelStart(); + + // Some things we need to be told by our owning filter + // Your pin must also expose IAMStreamControl when QI'd for it! + // + IReferenceClock * m_pRefClock; // Need it to set advises + // Filter must tell us via + // SetSyncSource + IMediaEventSink * m_pSink; // Event sink + // Filter must tell us after it + // creates it in JoinFilterGraph() + FILTER_STATE m_FilterState; // Just need it! + // Filter must tell us via + // NotifyFilterState + REFERENCE_TIME m_tRunStart; // Per the Run call to the filter + + // This guy will return one of the three StreamControlState's. Here's what + // the caller should do for each one: + // + // STREAM_FLOWING: Proceed as usual (render or pass the sample on) + // STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait + // that long for the event handle + // (GetStreamEventHandle()). If the wait + // expires, throw the sample away. If the event + // fires, call me back - I've changed my mind. + // + enum StreamControlState CheckSampleTimes( __in const REFERENCE_TIME * pSampleStart, + __in const REFERENCE_TIME * pSampleStop ); + +public: + // You don't have to tell us much when we're created, but there are other + // obligations that must be met. See SetSyncSource & NotifyFilterState + // below. + // + CBaseStreamControl(__inout_opt HRESULT *phr = NULL); + ~CBaseStreamControl(); + + // If you want this class to work properly, there are thing you need to + // (keep) telling it. Filters with pins that use this class + // should ensure that they pass through to this method any calls they + // receive on their SetSyncSource. + + // We need a clock to see what time it is. This is for the + // "discard in a timely fashion" logic. If we discard everything as + // quick as possible, a whole 60 minute file could get discarded in the + // first 10 seconds, and if somebody wants to turn streaming on at 30 + // minutes into the file, and they make the call more than a few seconds + // after the graph is run, it may be too late! + // So we hold every sample until it's time has gone, then we discard it. + // The filter should call this when it gets a SetSyncSource + // + void SetSyncSource( IReferenceClock * pRefClock ) + { + CAutoLock lck(&m_CritSec); + if (m_pRefClock) m_pRefClock->Release(); + m_pRefClock = pRefClock; + if (m_pRefClock) m_pRefClock->AddRef(); + } + + // Set event sink for notifications + // The filter should call this in its JoinFilterGraph after it creates the + // IMediaEventSink + // + void SetFilterGraph( IMediaEventSink *pSink ) { + m_pSink = pSink; + } + + // Since we schedule in stream time, we need the tStart and must track the + // state of our owning filter. + // The app should call this ever state change + // + void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 ); + + // Filter should call Flushing(TRUE) in BeginFlush, + // and Flushing(FALSE) in EndFlush. + // + void Flushing( BOOL bInProgress ); + + + // The two main methods of IAMStreamControl + + // Class adds default values suitable for immediate + // muting and unmuting of the stream. + + STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL, + BOOL bSendExtra = FALSE, + DWORD dwCookie = 0 ); + STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL, + DWORD dwCookie = 0 ); + STDMETHODIMP GetInfo( __out AM_STREAM_INFO *pInfo); + + // Helper function for pin's receive method. Call this with + // the sample and we'll tell you what to do with it. We'll do a + // WaitForSingleObject within this call if one is required. This is + // a "What should I do with this sample?" kind of call. We'll tell the + // caller to either flow it or discard it. + // If pSample is NULL we evaluate based on the current state + // settings + enum StreamControlState CheckStreamState( IMediaSample * pSample ); + +private: + // These don't require locking, but we are relying on the fact that + // m_StreamState can be retrieved with integrity, and is a snap shot that + // may have just been, or may be just about to be, changed. + HANDLE GetStreamEventHandle() const { return m_StreamEvent; } + enum StreamControlState GetStreamState() const { return m_StreamState; } + BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; } +}; + +#endif diff --git a/src/thirdparty/BaseClasses/sysclock.cpp b/src/thirdparty/BaseClasses/sysclock.cpp index 046ad839348..d671da6fbad 100644 --- a/src/thirdparty/BaseClasses/sysclock.cpp +++ b/src/thirdparty/BaseClasses/sysclock.cpp @@ -1,74 +1,74 @@ -//------------------------------------------------------------------------------ -// File: SysClock.cpp -// -// Desc: DirectShow base classes - implements a system clock based on -// IReferenceClock. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - - -#ifdef FILTER_DLL - -/* List of class IDs and creator functions for the class factory. This - provides the link between the OLE entry point in the DLL and an object - being created. The class factory will call the static CreateInstance - function when it is asked to create a CLSID_SystemClock object */ - -CFactoryTemplate g_Templates[1] = { - {&CLSID_SystemClock, CSystemClock::CreateInstance} -}; - -int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); -#endif - -/* This goes in the factory template table to create new instances */ -CUnknown * WINAPI CSystemClock::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) -{ - return new CSystemClock(NAME("System reference clock"),pUnk, phr); -} - - -CSystemClock::CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) : - CBaseReferenceClock(pName, pUnk, phr) -{ -} - -STDMETHODIMP CSystemClock::NonDelegatingQueryInterface( - REFIID riid, - __deref_out void ** ppv) -{ - if (riid == IID_IPersist) - { - return GetInterface(static_cast(this), ppv); - } - else if (riid == IID_IAMClockAdjust) - { - return GetInterface(static_cast(this), ppv); - } - else - { - return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv); - } -} - -/* Return the clock's clsid */ -STDMETHODIMP -CSystemClock::GetClassID(__out CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = CLSID_SystemClock; - return NOERROR; -} - - -STDMETHODIMP -CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta) -{ - return SetTimeDelta(rtDelta); -} +//------------------------------------------------------------------------------ +// File: SysClock.cpp +// +// Desc: DirectShow base classes - implements a system clock based on +// IReferenceClock. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + + +#ifdef FILTER_DLL + +/* List of class IDs and creator functions for the class factory. This + provides the link between the OLE entry point in the DLL and an object + being created. The class factory will call the static CreateInstance + function when it is asked to create a CLSID_SystemClock object */ + +CFactoryTemplate g_Templates[1] = { + {&CLSID_SystemClock, CSystemClock::CreateInstance} +}; + +int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); +#endif + +/* This goes in the factory template table to create new instances */ +CUnknown * WINAPI CSystemClock::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) +{ + return new CSystemClock(NAME("System reference clock"),pUnk, phr); +} + + +CSystemClock::CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) : + CBaseReferenceClock(pName, pUnk, phr) +{ +} + +STDMETHODIMP CSystemClock::NonDelegatingQueryInterface( + REFIID riid, + __deref_out void ** ppv) +{ + if (riid == IID_IPersist) + { + return GetInterface(static_cast(this), ppv); + } + else if (riid == IID_IAMClockAdjust) + { + return GetInterface(static_cast(this), ppv); + } + else + { + return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv); + } +} + +/* Return the clock's clsid */ +STDMETHODIMP +CSystemClock::GetClassID(__out CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = CLSID_SystemClock; + return NOERROR; +} + + +STDMETHODIMP +CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta) +{ + return SetTimeDelta(rtDelta); +} diff --git a/src/thirdparty/BaseClasses/sysclock.h b/src/thirdparty/BaseClasses/sysclock.h index 3976d34654f..bf9192ce4bf 100644 --- a/src/thirdparty/BaseClasses/sysclock.h +++ b/src/thirdparty/BaseClasses/sysclock.h @@ -1,39 +1,39 @@ -//------------------------------------------------------------------------------ -// File: SysClock.h -// -// Desc: DirectShow base classes - defines a system clock implementation of -// IReferenceClock. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __SYSTEMCLOCK__ -#define __SYSTEMCLOCK__ - -// -// Base clock. Uses timeGetTime ONLY -// Uses most of the code in the base reference clock. -// Provides GetTime -// - -class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist -{ -public: - // We must be able to create an instance of ourselves - static CUnknown * WINAPI CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); - CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); - - DECLARE_IUNKNOWN - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - - // Yield up our class id so that we can be persisted - // Implement required Ipersist method - STDMETHODIMP GetClassID(__out CLSID *pClsID); - - // IAMClockAdjust methods - STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta); -}; //CSystemClock - -#endif /* __SYSTEMCLOCK__ */ +//------------------------------------------------------------------------------ +// File: SysClock.h +// +// Desc: DirectShow base classes - defines a system clock implementation of +// IReferenceClock. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __SYSTEMCLOCK__ +#define __SYSTEMCLOCK__ + +// +// Base clock. Uses timeGetTime ONLY +// Uses most of the code in the base reference clock. +// Provides GetTime +// + +class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist +{ +public: + // We must be able to create an instance of ourselves + static CUnknown * WINAPI CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); + CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); + + DECLARE_IUNKNOWN + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + + // Yield up our class id so that we can be persisted + // Implement required Ipersist method + STDMETHODIMP GetClassID(__out CLSID *pClsID); + + // IAMClockAdjust methods + STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta); +}; //CSystemClock + +#endif /* __SYSTEMCLOCK__ */ diff --git a/src/thirdparty/BaseClasses/transfrm.cpp b/src/thirdparty/BaseClasses/transfrm.cpp index 1c263c247c4..30e8e1879bc 100644 --- a/src/thirdparty/BaseClasses/transfrm.cpp +++ b/src/thirdparty/BaseClasses/transfrm.cpp @@ -1,1016 +1,1016 @@ -//------------------------------------------------------------------------------ -// File: Transfrm.cpp -// -// Desc: DirectShow base classes - implements class for simple transform -// filters such as video decompressors. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "measure.h" - - -// ================================================================= -// Implements the CTransformFilter class -// ================================================================= - -CTransformFilter::CTransformFilter(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - REFCLSID clsid) : - CBaseFilter(pName,pUnk,&m_csFilter, clsid), - m_pInput(NULL), - m_pOutput(NULL), - m_bEOSDelivered(FALSE), - m_bQualityChanged(FALSE), - m_bSampleSkipped(FALSE) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} - -#ifdef UNICODE -CTransformFilter::CTransformFilter(__in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - REFCLSID clsid) : - CBaseFilter(pName,pUnk,&m_csFilter, clsid), - m_pInput(NULL), - m_pOutput(NULL), - m_bEOSDelivered(FALSE), - m_bQualityChanged(FALSE), - m_bSampleSkipped(FALSE) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} -#endif - -// destructor - -CTransformFilter::~CTransformFilter() -{ - // Delete the pins - - delete m_pInput; - delete m_pOutput; -} - - -// Transform place holder - should never be called -HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut) -{ - UNREFERENCED_PARAMETER(pIn); - UNREFERENCED_PARAMETER(pOut); - DbgBreak("CTransformFilter::Transform() should never be called"); - return E_UNEXPECTED; -} - - -// return the number of pins we provide - -int CTransformFilter::GetPinCount() -{ - return 2; -} - - -// return a non-addrefed CBasePin * for the user to addref if he holds onto it -// for longer than his pointer to us. We create the pins dynamically when they -// are asked for rather than in the constructor. This is because we want to -// give the derived class an oppportunity to return different pin objects - -// We return the objects as and when they are needed. If either of these fails -// then we return NULL, the assumption being that the caller will realise the -// whole deal is off and destroy us - which in turn will delete everything. - -CBasePin * -CTransformFilter::GetPin(int n) -{ - HRESULT hr = S_OK; - - // Create an input pin if necessary - - if (m_pInput == NULL) { - - m_pInput = new CTransformInputPin(NAME("Transform input pin"), - this, // Owner filter - &hr, // Result code - L"XForm In"); // Pin name - - - // Can't fail - ASSERT(SUCCEEDED(hr)); - if (m_pInput == NULL) { - return NULL; - } - m_pOutput = (CTransformOutputPin *) - new CTransformOutputPin(NAME("Transform output pin"), - this, // Owner filter - &hr, // Result code - L"XForm Out"); // Pin name - - - // Can't fail - ASSERT(SUCCEEDED(hr)); - if (m_pOutput == NULL) { - delete m_pInput; - m_pInput = NULL; - } - } - - // Return the appropriate pin - - if (n == 0) { - return m_pInput; - } else - if (n == 1) { - return m_pOutput; - } else { - return NULL; - } -} - - -// -// FindPin -// -// If Id is In or Out then return the IPin* for that pin -// creating the pin if need be. Otherwise return NULL with an error. - -STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - - if (0==lstrcmpW(Id,L"In")) { - *ppPin = GetPin(0); - } else if (0==lstrcmpW(Id,L"Out")) { - *ppPin = GetPin(1); - } else { - *ppPin = NULL; - return VFW_E_NOT_FOUND; - } - - HRESULT hr = NOERROR; - // AddRef() returned pointer - but GetPin could fail if memory is low. - if (*ppPin) { - (*ppPin)->AddRef(); - } else { - hr = E_OUTOFMEMORY; // probably. There's no pin anyway. - } - return hr; -} - - -// override these two functions if you want to inform something -// about entry to or exit from streaming state. - -HRESULT -CTransformFilter::StartStreaming() -{ - return NOERROR; -} - - -HRESULT -CTransformFilter::StopStreaming() -{ - return NOERROR; -} - - -// override this to grab extra interfaces on connection - -HRESULT -CTransformFilter::CheckConnect(PIN_DIRECTION dir, IPin *pPin) -{ - UNREFERENCED_PARAMETER(dir); - UNREFERENCED_PARAMETER(pPin); - return NOERROR; -} - - -// place holder to allow derived classes to release any extra interfaces - -HRESULT -CTransformFilter::BreakConnect(PIN_DIRECTION dir) -{ - UNREFERENCED_PARAMETER(dir); - return NOERROR; -} - - -// Let derived classes know about connection completion - -HRESULT -CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(direction); - UNREFERENCED_PARAMETER(pReceivePin); - return NOERROR; -} - - -// override this to know when the media type is really set - -HRESULT -CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt) -{ - UNREFERENCED_PARAMETER(direction); - UNREFERENCED_PARAMETER(pmt); - return NOERROR; -} - - -// Set up our output sample -HRESULT -CTransformFilter::InitializeOutputSample(IMediaSample *pSample, __deref_out IMediaSample **ppOutSample) -{ - IMediaSample *pOutSample; - - // default - times are the same - - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; - - // This will prevent the image renderer from switching us to DirectDraw - // when we can't do it without skipping frames because we're not on a - // keyframe. If it really has to switch us, it still will, but then we - // will have to wait for the next keyframe - if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { - dwFlags |= AM_GBF_NOTASYNCPOINT; - } - - ASSERT(m_pOutput->m_pAllocator != NULL); - HRESULT hr = m_pOutput->m_pAllocator->GetBuffer( - &pOutSample - , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? - &pProps->tStart : NULL - , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? - &pProps->tStop : NULL - , dwFlags - ); - *ppOutSample = pOutSample; - if (FAILED(hr)) { - return hr; - } - - ASSERT(pOutSample); - IMediaSample2 *pOutSample2; - if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, - (void **)&pOutSample2))) { - /* Modify it */ - AM_SAMPLE2_PROPERTIES OutProps; - EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps) - )); - OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - OutProps.dwSampleFlags = - (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | - (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); - OutProps.tStart = pProps->tStart; - OutProps.tStop = pProps->tStop; - OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); - hr = pOutSample2->SetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), - (PBYTE)&OutProps - ); - if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - m_bSampleSkipped = FALSE; - } - pOutSample2->Release(); - } else { - if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { - pOutSample->SetTime(&pProps->tStart, - &pProps->tStop); - } - if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { - pOutSample->SetSyncPoint(TRUE); - } - if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - pOutSample->SetDiscontinuity(TRUE); - m_bSampleSkipped = FALSE; - } - // Copy the media times - - LONGLONG MediaStart, MediaEnd; - if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { - pOutSample->SetMediaTime(&MediaStart,&MediaEnd); - } - } - return S_OK; -} - -// override this to customize the transform process - -HRESULT -CTransformFilter::Receive(IMediaSample *pSample) -{ - /* Check for other streams and pass them on */ - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - if (pProps->dwStreamId != AM_STREAM_MEDIA) { - return m_pOutput->m_pInputPin->Receive(pSample); - } - HRESULT hr; - ASSERT(pSample); - IMediaSample * pOutSample; - - // If no output to deliver to then no point sending us data - - ASSERT (m_pOutput != NULL) ; - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - // Start timing the transform (if PERF is defined) - MSR_START(m_idTransform); - - // have the derived class transform the data - - hr = Transform(pSample, pOutSample); - - // Stop the clock and log it (if PERF is defined) - MSR_STOP(m_idTransform); - - if (FAILED(hr)) { - DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); - } else { - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - if (hr == NOERROR) { - hr = m_pOutput->m_pInputPin->Receive(pOutSample); - m_bSampleSkipped = FALSE; // last thing no longer dropped - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this cause because returning S_FALSE - // from Receive() means that this is the end of the stream and no more data should - // be sent. - if (S_FALSE == hr) { - - // Release the sample before calling notify to avoid - // deadlocks if the sample holds a lock on the system - // such as DirectDraw buffers do - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - NotifyEvent(EC_QUALITY_CHANGE,0,0); - m_bQualityChanged = TRUE; - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - - return hr; -} - - -// Return S_FALSE to mean "pass the note on upstream" -// Return NOERROR (Same as S_OK) -// to mean "I've done something about it, don't pass it on" -HRESULT CTransformFilter::AlterQuality(Quality q) -{ - UNREFERENCED_PARAMETER(q); - return S_FALSE; -} - - -// EndOfStream received. Default behaviour is to deliver straight -// downstream, since we have no queued data. If you overrode Receive -// and have queue data, then you need to handle this and deliver EOS after -// all queued data is sent -HRESULT -CTransformFilter::EndOfStream(void) -{ - HRESULT hr = NOERROR; - if (m_pOutput != NULL) { - hr = m_pOutput->DeliverEndOfStream(); - } - - return hr; -} - - -// enter flush state. Receives already blocked -// must override this if you have queued data or a worker thread -HRESULT -CTransformFilter::BeginFlush(void) -{ - HRESULT hr = NOERROR; - if (m_pOutput != NULL) { - // block receives -- done by caller (CBaseInputPin::BeginFlush) - - // discard queued data -- we have no queued data - - // free anyone blocked on receive - not possible in this filter - - // call downstream - hr = m_pOutput->DeliverBeginFlush(); - } - return hr; -} - - -// leave flush state. must override this if you have queued data -// or a worker thread -HRESULT -CTransformFilter::EndFlush(void) -{ - // sync with pushing thread -- we have no worker thread - - // ensure no more data to go downstream -- we have no queued data - - // call EndFlush on downstream pins - ASSERT (m_pOutput != NULL); - return m_pOutput->DeliverEndFlush(); - - // caller (the input pin's method) will unblock Receives -} - - -// override these so that the derived filter can catch them - -STDMETHODIMP -CTransformFilter::Stop() -{ - CAutoLock lck1(&m_csFilter); - if (m_State == State_Stopped) { - return NOERROR; - } - - // Succeed the Stop if we are not completely connected - - ASSERT(m_pInput == NULL || m_pOutput != NULL); - if (m_pInput == NULL || m_pInput->IsConnected() == FALSE || - m_pOutput->IsConnected() == FALSE) { - m_State = State_Stopped; - m_bEOSDelivered = FALSE; - return NOERROR; - } - - ASSERT(m_pInput); - ASSERT(m_pOutput); - - // decommit the input pin before locking or we can deadlock - m_pInput->Inactive(); - - // synchronize with Receive calls - - CAutoLock lck2(&m_csReceive); - m_pOutput->Inactive(); - - // allow a class derived from CTransformFilter - // to know about starting and stopping streaming - - HRESULT hr = StopStreaming(); - if (SUCCEEDED(hr)) { - // complete the state transition - m_State = State_Stopped; - m_bEOSDelivered = FALSE; - } - return hr; -} - - -STDMETHODIMP -CTransformFilter::Pause() -{ - CAutoLock lck(&m_csFilter); - HRESULT hr = NOERROR; - - if (m_State == State_Paused) { - // (This space left deliberately blank) - } - - // If we have no input pin or it isn't yet connected then when we are - // asked to pause we deliver an end of stream to the downstream filter. - // This makes sure that it doesn't sit there forever waiting for - // samples which we cannot ever deliver without an input connection. - - else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) { - if (m_pOutput && m_bEOSDelivered == FALSE) { - m_pOutput->DeliverEndOfStream(); - m_bEOSDelivered = TRUE; - } - m_State = State_Paused; - } - - // We may have an input connection but no output connection - // However, if we have an input pin we do have an output pin - - else if (m_pOutput->IsConnected() == FALSE) { - m_State = State_Paused; - } - - else { - if (m_State == State_Stopped) { - // allow a class derived from CTransformFilter - // to know about starting and stopping streaming - CAutoLock lck2(&m_csReceive); - hr = StartStreaming(); - } - if (SUCCEEDED(hr)) { - hr = CBaseFilter::Pause(); - } - } - - m_bSampleSkipped = FALSE; - m_bQualityChanged = FALSE; - return hr; -} - -HRESULT -CTransformFilter::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (m_pOutput != NULL) { - return m_pOutput->DeliverNewSegment(tStart, tStop, dRate); - } - return S_OK; -} - -// Check streaming status -HRESULT -CTransformInputPin::CheckStreaming() -{ - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } else { - // Shouldn't be able to get any data if we're not connected! - ASSERT(IsConnected()); - - // we're flushing - if (m_bFlushing) { - return S_FALSE; - } - // Don't process stuff in Stopped state - if (IsStopped()) { - return VFW_E_WRONG_STATE; - } - if (m_bRunTimeError) { - return VFW_E_RUNTIME_ERROR; - } - return S_OK; - } -} - - -// ================================================================= -// Implements the CTransformInputPin class -// ================================================================= - - -// constructor - -CTransformInputPin::CTransformInputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName) - : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); - m_pTransformFilter = pTransformFilter; -} - -#ifdef UNICODE -CTransformInputPin::CTransformInputPin( - __in_opt LPCSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName) - : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); - m_pTransformFilter = pTransformFilter; -} -#endif - -// provides derived filter a chance to grab extra interfaces - -HRESULT -CTransformInputPin::CheckConnect(IPin *pPin) -{ - HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CheckConnect(pPin); -} - - -// provides derived filter a chance to release it's extra interfaces - -HRESULT -CTransformInputPin::BreakConnect() -{ - // Can't disconnect unless stopped - ASSERT(IsStopped()); - m_pTransformFilter->BreakConnect(PINDIR_INPUT); - return CBaseInputPin::BreakConnect(); -} - - -// Let derived class know when the input pin is connected - -HRESULT -CTransformInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CompleteConnect(pReceivePin); -} - - -// check that we can support a given media type - -HRESULT -CTransformInputPin::CheckMediaType(const CMediaType* pmt) -{ - // Check the input type - - HRESULT hr = m_pTransformFilter->CheckInputType(pmt); - if (S_OK != hr) { - return hr; - } - - // if the output pin is still connected, then we have - // to check the transform not just the input format - - if ((m_pTransformFilter->m_pOutput != NULL) && - (m_pTransformFilter->m_pOutput->IsConnected())) { - return m_pTransformFilter->CheckTransform( - pmt, - &m_pTransformFilter->m_pOutput->CurrentMediaType()); - } else { - return hr; - } -} - - -// set the media type for this connection - -HRESULT -CTransformInputPin::SetMediaType(const CMediaType* mtIn) -{ - // Set the base class media type (should always succeed) - HRESULT hr = CBasePin::SetMediaType(mtIn); - if (FAILED(hr)) { - return hr; - } - - // check the transform can be done (should always succeed) - ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn))); - - return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn); -} - - -// ================================================================= -// Implements IMemInputPin interface -// ================================================================= - - -// provide EndOfStream that passes straight downstream -// (there is no queued data) -STDMETHODIMP -CTransformInputPin::EndOfStream(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csReceive); - HRESULT hr = CheckStreaming(); - if (S_OK == hr) { - hr = m_pTransformFilter->EndOfStream(); - } - return hr; -} - - -// enter flushing state. Call default handler to block Receives, then -// pass to overridable method in filter -STDMETHODIMP -CTransformInputPin::BeginFlush(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csFilter); - // Are we actually doing anything? - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!IsConnected() || - !m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - HRESULT hr = CBaseInputPin::BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->BeginFlush(); -} - - -// leave flushing state. -// Pass to overridable method in filter, then call base class -// to unblock receives (finally) -STDMETHODIMP -CTransformInputPin::EndFlush(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csFilter); - // Are we actually doing anything? - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!IsConnected() || - !m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - HRESULT hr = m_pTransformFilter->EndFlush(); - if (FAILED(hr)) { - return hr; - } - - return CBaseInputPin::EndFlush(); -} - - -// here's the next block of data from the stream. -// AddRef it yourself if you need to hold it beyond the end -// of this call. - -HRESULT -CTransformInputPin::Receive(IMediaSample * pSample) -{ - HRESULT hr; - CAutoLock lck(&m_pTransformFilter->m_csReceive); - ASSERT(pSample); - - // check all is well with the base class - hr = CBaseInputPin::Receive(pSample); - if (S_OK == hr) { - hr = m_pTransformFilter->Receive(pSample); - } - return hr; -} - - - - -// override to pass downstream -STDMETHODIMP -CTransformInputPin::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - // Save the values in the pin - CBasePin::NewSegment(tStart, tStop, dRate); - return m_pTransformFilter->NewSegment(tStart, tStop, dRate); -} - - - - -// ================================================================= -// Implements the CTransformOutputPin class -// ================================================================= - - -// constructor - -CTransformOutputPin::CTransformOutputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), - m_pPosition(NULL) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); - m_pTransformFilter = pTransformFilter; - -} - -#ifdef UNICODE -CTransformOutputPin::CTransformOutputPin( - __in_opt LPCSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), - m_pPosition(NULL) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); - m_pTransformFilter = pTransformFilter; - -} -#endif - -// destructor - -CTransformOutputPin::~CTransformOutputPin() -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin"))); - - if (m_pPosition) m_pPosition->Release(); -} - - -// overriden to expose IMediaPosition and IMediaSeeking control interfaces - -STDMETHODIMP -CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - CheckPointer(ppv,E_POINTER); - ValidateReadWritePtr(ppv,sizeof(PVOID)); - *ppv = NULL; - - if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { - - // we should have an input pin by now - - ASSERT(m_pTransformFilter->m_pInput != NULL); - - if (m_pPosition == NULL) { - - HRESULT hr = CreatePosPassThru( - GetOwner(), - FALSE, - (IPin *)m_pTransformFilter->m_pInput, - &m_pPosition); - if (FAILED(hr)) { - return hr; - } - } - return m_pPosition->QueryInterface(riid, ppv); - } else { - return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// provides derived filter a chance to grab extra interfaces - -HRESULT -CTransformOutputPin::CheckConnect(IPin *pPin) -{ - // we should have an input connection first - - ASSERT(m_pTransformFilter->m_pInput != NULL); - if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { - return E_UNEXPECTED; - } - - HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin); - if (FAILED(hr)) { - return hr; - } - return CBaseOutputPin::CheckConnect(pPin); -} - - -// provides derived filter a chance to release it's extra interfaces - -HRESULT -CTransformOutputPin::BreakConnect() -{ - // Can't disconnect unless stopped - ASSERT(IsStopped()); - m_pTransformFilter->BreakConnect(PINDIR_OUTPUT); - return CBaseOutputPin::BreakConnect(); -} - - -// Let derived class know when the output pin is connected - -HRESULT -CTransformOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseOutputPin::CompleteConnect(pReceivePin); -} - - -// check a given transform - must have selected input type first - -HRESULT -CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut) -{ - // must have selected input first - ASSERT(m_pTransformFilter->m_pInput != NULL); - if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { - return E_INVALIDARG; - } - - return m_pTransformFilter->CheckTransform( - &m_pTransformFilter->m_pInput->CurrentMediaType(), - pmtOut); -} - - -// called after we have agreed a media type to actually set it in which case -// we run the CheckTransform function to get the output format type again - -HRESULT -CTransformOutputPin::SetMediaType(const CMediaType* pmtOut) -{ - HRESULT hr = NOERROR; - ASSERT(m_pTransformFilter->m_pInput != NULL); - - ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid()); - - // Set the base class media type (should always succeed) - hr = CBasePin::SetMediaType(pmtOut); - if (FAILED(hr)) { - return hr; - } - -#ifdef _DEBUG - if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter-> - m_pInput->CurrentMediaType(),pmtOut))) { - DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type"))); - DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope"))); - DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input."))); - } -#endif - - return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut); -} - - -// pass the buffer size decision through to the main transform class - -HRESULT -CTransformOutputPin::DecideBufferSize( - IMemAllocator * pAllocator, - __inout ALLOCATOR_PROPERTIES* pProp) -{ - return m_pTransformFilter->DecideBufferSize(pAllocator, pProp); -} - - - -// return a specific media type indexed by iPosition - -HRESULT -CTransformOutputPin::GetMediaType( - int iPosition, - __inout CMediaType *pMediaType) -{ - ASSERT(m_pTransformFilter->m_pInput != NULL); - - // We don't have any media types if our input is not connected - - if (m_pTransformFilter->m_pInput->IsConnected()) { - return m_pTransformFilter->GetMediaType(iPosition,pMediaType); - } else { - return VFW_S_NO_MORE_ITEMS; - } -} - - -// Override this if you can do something constructive to act on the -// quality message. Consider passing it upstream as well - -// Pass the quality mesage on upstream. - -STDMETHODIMP -CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(pSender); - ValidateReadPtr(pSender,sizeof(IBaseFilter)); - - // First see if we want to handle this ourselves - HRESULT hr = m_pTransformFilter->AlterQuality(q); - if (hr!=S_FALSE) { - return hr; // either S_OK or a failure - } - - // S_FALSE means we pass the message on. - // Find the quality sink for our input pin and send it there - - ASSERT(m_pTransformFilter->m_pInput != NULL); - - return m_pTransformFilter->m_pInput->PassNotify(q); - -} // Notify - - -// the following removes a very large number of level 4 warnings from the microsoft -// compiler output, which are not useful at all in this case. -#pragma warning(disable:4514) +//------------------------------------------------------------------------------ +// File: Transfrm.cpp +// +// Desc: DirectShow base classes - implements class for simple transform +// filters such as video decompressors. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "measure.h" + + +// ================================================================= +// Implements the CTransformFilter class +// ================================================================= + +CTransformFilter::CTransformFilter(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + REFCLSID clsid) : + CBaseFilter(pName,pUnk,&m_csFilter, clsid), + m_pInput(NULL), + m_pOutput(NULL), + m_bEOSDelivered(FALSE), + m_bQualityChanged(FALSE), + m_bSampleSkipped(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} + +#ifdef UNICODE +CTransformFilter::CTransformFilter(__in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + REFCLSID clsid) : + CBaseFilter(pName,pUnk,&m_csFilter, clsid), + m_pInput(NULL), + m_pOutput(NULL), + m_bEOSDelivered(FALSE), + m_bQualityChanged(FALSE), + m_bSampleSkipped(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} +#endif + +// destructor + +CTransformFilter::~CTransformFilter() +{ + // Delete the pins + + delete m_pInput; + delete m_pOutput; +} + + +// Transform place holder - should never be called +HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut) +{ + UNREFERENCED_PARAMETER(pIn); + UNREFERENCED_PARAMETER(pOut); + DbgBreak("CTransformFilter::Transform() should never be called"); + return E_UNEXPECTED; +} + + +// return the number of pins we provide + +int CTransformFilter::GetPinCount() +{ + return 2; +} + + +// return a non-addrefed CBasePin * for the user to addref if he holds onto it +// for longer than his pointer to us. We create the pins dynamically when they +// are asked for rather than in the constructor. This is because we want to +// give the derived class an oppportunity to return different pin objects + +// We return the objects as and when they are needed. If either of these fails +// then we return NULL, the assumption being that the caller will realise the +// whole deal is off and destroy us - which in turn will delete everything. + +CBasePin * +CTransformFilter::GetPin(int n) +{ + HRESULT hr = S_OK; + + // Create an input pin if necessary + + if (m_pInput == NULL) { + + m_pInput = new CTransformInputPin(NAME("Transform input pin"), + this, // Owner filter + &hr, // Result code + L"XForm In"); // Pin name + + + // Can't fail + ASSERT(SUCCEEDED(hr)); + if (m_pInput == NULL) { + return NULL; + } + m_pOutput = (CTransformOutputPin *) + new CTransformOutputPin(NAME("Transform output pin"), + this, // Owner filter + &hr, // Result code + L"XForm Out"); // Pin name + + + // Can't fail + ASSERT(SUCCEEDED(hr)); + if (m_pOutput == NULL) { + delete m_pInput; + m_pInput = NULL; + } + } + + // Return the appropriate pin + + if (n == 0) { + return m_pInput; + } else + if (n == 1) { + return m_pOutput; + } else { + return NULL; + } +} + + +// +// FindPin +// +// If Id is In or Out then return the IPin* for that pin +// creating the pin if need be. Otherwise return NULL with an error. + +STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + + if (0==lstrcmpW(Id,L"In")) { + *ppPin = GetPin(0); + } else if (0==lstrcmpW(Id,L"Out")) { + *ppPin = GetPin(1); + } else { + *ppPin = NULL; + return VFW_E_NOT_FOUND; + } + + HRESULT hr = NOERROR; + // AddRef() returned pointer - but GetPin could fail if memory is low. + if (*ppPin) { + (*ppPin)->AddRef(); + } else { + hr = E_OUTOFMEMORY; // probably. There's no pin anyway. + } + return hr; +} + + +// override these two functions if you want to inform something +// about entry to or exit from streaming state. + +HRESULT +CTransformFilter::StartStreaming() +{ + return NOERROR; +} + + +HRESULT +CTransformFilter::StopStreaming() +{ + return NOERROR; +} + + +// override this to grab extra interfaces on connection + +HRESULT +CTransformFilter::CheckConnect(PIN_DIRECTION dir, IPin *pPin) +{ + UNREFERENCED_PARAMETER(dir); + UNREFERENCED_PARAMETER(pPin); + return NOERROR; +} + + +// place holder to allow derived classes to release any extra interfaces + +HRESULT +CTransformFilter::BreakConnect(PIN_DIRECTION dir) +{ + UNREFERENCED_PARAMETER(dir); + return NOERROR; +} + + +// Let derived classes know about connection completion + +HRESULT +CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(direction); + UNREFERENCED_PARAMETER(pReceivePin); + return NOERROR; +} + + +// override this to know when the media type is really set + +HRESULT +CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt) +{ + UNREFERENCED_PARAMETER(direction); + UNREFERENCED_PARAMETER(pmt); + return NOERROR; +} + + +// Set up our output sample +HRESULT +CTransformFilter::InitializeOutputSample(IMediaSample *pSample, __deref_out IMediaSample **ppOutSample) +{ + IMediaSample *pOutSample; + + // default - times are the same + + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; + + // This will prevent the image renderer from switching us to DirectDraw + // when we can't do it without skipping frames because we're not on a + // keyframe. If it really has to switch us, it still will, but then we + // will have to wait for the next keyframe + if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { + dwFlags |= AM_GBF_NOTASYNCPOINT; + } + + ASSERT(m_pOutput->m_pAllocator != NULL); + HRESULT hr = m_pOutput->m_pAllocator->GetBuffer( + &pOutSample + , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? + &pProps->tStart : NULL + , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? + &pProps->tStop : NULL + , dwFlags + ); + *ppOutSample = pOutSample; + if (FAILED(hr)) { + return hr; + } + + ASSERT(pOutSample); + IMediaSample2 *pOutSample2; + if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, + (void **)&pOutSample2))) { + /* Modify it */ + AM_SAMPLE2_PROPERTIES OutProps; + EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps) + )); + OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + OutProps.dwSampleFlags = + (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | + (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); + OutProps.tStart = pProps->tStart; + OutProps.tStop = pProps->tStop; + OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); + hr = pOutSample2->SetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), + (PBYTE)&OutProps + ); + if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + m_bSampleSkipped = FALSE; + } + pOutSample2->Release(); + } else { + if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { + pOutSample->SetTime(&pProps->tStart, + &pProps->tStop); + } + if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { + pOutSample->SetSyncPoint(TRUE); + } + if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + pOutSample->SetDiscontinuity(TRUE); + m_bSampleSkipped = FALSE; + } + // Copy the media times + + LONGLONG MediaStart, MediaEnd; + if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { + pOutSample->SetMediaTime(&MediaStart,&MediaEnd); + } + } + return S_OK; +} + +// override this to customize the transform process + +HRESULT +CTransformFilter::Receive(IMediaSample *pSample) +{ + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->m_pInputPin->Receive(pSample); + } + HRESULT hr; + ASSERT(pSample); + IMediaSample * pOutSample; + + // If no output to deliver to then no point sending us data + + ASSERT (m_pOutput != NULL) ; + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + // Start timing the transform (if PERF is defined) + MSR_START(m_idTransform); + + // have the derived class transform the data + + hr = Transform(pSample, pOutSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransform); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->m_pInputPin->Receive(pOutSample); + m_bSampleSkipped = FALSE; // last thing no longer dropped + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // Release the sample before calling notify to avoid + // deadlocks if the sample holds a lock on the system + // such as DirectDraw buffers do + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE,0,0); + m_bQualityChanged = TRUE; + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + + return hr; +} + + +// Return S_FALSE to mean "pass the note on upstream" +// Return NOERROR (Same as S_OK) +// to mean "I've done something about it, don't pass it on" +HRESULT CTransformFilter::AlterQuality(Quality q) +{ + UNREFERENCED_PARAMETER(q); + return S_FALSE; +} + + +// EndOfStream received. Default behaviour is to deliver straight +// downstream, since we have no queued data. If you overrode Receive +// and have queue data, then you need to handle this and deliver EOS after +// all queued data is sent +HRESULT +CTransformFilter::EndOfStream(void) +{ + HRESULT hr = NOERROR; + if (m_pOutput != NULL) { + hr = m_pOutput->DeliverEndOfStream(); + } + + return hr; +} + + +// enter flush state. Receives already blocked +// must override this if you have queued data or a worker thread +HRESULT +CTransformFilter::BeginFlush(void) +{ + HRESULT hr = NOERROR; + if (m_pOutput != NULL) { + // block receives -- done by caller (CBaseInputPin::BeginFlush) + + // discard queued data -- we have no queued data + + // free anyone blocked on receive - not possible in this filter + + // call downstream + hr = m_pOutput->DeliverBeginFlush(); + } + return hr; +} + + +// leave flush state. must override this if you have queued data +// or a worker thread +HRESULT +CTransformFilter::EndFlush(void) +{ + // sync with pushing thread -- we have no worker thread + + // ensure no more data to go downstream -- we have no queued data + + // call EndFlush on downstream pins + ASSERT (m_pOutput != NULL); + return m_pOutput->DeliverEndFlush(); + + // caller (the input pin's method) will unblock Receives +} + + +// override these so that the derived filter can catch them + +STDMETHODIMP +CTransformFilter::Stop() +{ + CAutoLock lck1(&m_csFilter); + if (m_State == State_Stopped) { + return NOERROR; + } + + // Succeed the Stop if we are not completely connected + + ASSERT(m_pInput == NULL || m_pOutput != NULL); + if (m_pInput == NULL || m_pInput->IsConnected() == FALSE || + m_pOutput->IsConnected() == FALSE) { + m_State = State_Stopped; + m_bEOSDelivered = FALSE; + return NOERROR; + } + + ASSERT(m_pInput); + ASSERT(m_pOutput); + + // decommit the input pin before locking or we can deadlock + m_pInput->Inactive(); + + // synchronize with Receive calls + + CAutoLock lck2(&m_csReceive); + m_pOutput->Inactive(); + + // allow a class derived from CTransformFilter + // to know about starting and stopping streaming + + HRESULT hr = StopStreaming(); + if (SUCCEEDED(hr)) { + // complete the state transition + m_State = State_Stopped; + m_bEOSDelivered = FALSE; + } + return hr; +} + + +STDMETHODIMP +CTransformFilter::Pause() +{ + CAutoLock lck(&m_csFilter); + HRESULT hr = NOERROR; + + if (m_State == State_Paused) { + // (This space left deliberately blank) + } + + // If we have no input pin or it isn't yet connected then when we are + // asked to pause we deliver an end of stream to the downstream filter. + // This makes sure that it doesn't sit there forever waiting for + // samples which we cannot ever deliver without an input connection. + + else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) { + if (m_pOutput && m_bEOSDelivered == FALSE) { + m_pOutput->DeliverEndOfStream(); + m_bEOSDelivered = TRUE; + } + m_State = State_Paused; + } + + // We may have an input connection but no output connection + // However, if we have an input pin we do have an output pin + + else if (m_pOutput->IsConnected() == FALSE) { + m_State = State_Paused; + } + + else { + if (m_State == State_Stopped) { + // allow a class derived from CTransformFilter + // to know about starting and stopping streaming + CAutoLock lck2(&m_csReceive); + hr = StartStreaming(); + } + if (SUCCEEDED(hr)) { + hr = CBaseFilter::Pause(); + } + } + + m_bSampleSkipped = FALSE; + m_bQualityChanged = FALSE; + return hr; +} + +HRESULT +CTransformFilter::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (m_pOutput != NULL) { + return m_pOutput->DeliverNewSegment(tStart, tStop, dRate); + } + return S_OK; +} + +// Check streaming status +HRESULT +CTransformInputPin::CheckStreaming() +{ + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } else { + // Shouldn't be able to get any data if we're not connected! + ASSERT(IsConnected()); + + // we're flushing + if (m_bFlushing) { + return S_FALSE; + } + // Don't process stuff in Stopped state + if (IsStopped()) { + return VFW_E_WRONG_STATE; + } + if (m_bRunTimeError) { + return VFW_E_RUNTIME_ERROR; + } + return S_OK; + } +} + + +// ================================================================= +// Implements the CTransformInputPin class +// ================================================================= + + +// constructor + +CTransformInputPin::CTransformInputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName) + : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); + m_pTransformFilter = pTransformFilter; +} + +#ifdef UNICODE +CTransformInputPin::CTransformInputPin( + __in_opt LPCSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName) + : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); + m_pTransformFilter = pTransformFilter; +} +#endif + +// provides derived filter a chance to grab extra interfaces + +HRESULT +CTransformInputPin::CheckConnect(IPin *pPin) +{ + HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CheckConnect(pPin); +} + + +// provides derived filter a chance to release it's extra interfaces + +HRESULT +CTransformInputPin::BreakConnect() +{ + // Can't disconnect unless stopped + ASSERT(IsStopped()); + m_pTransformFilter->BreakConnect(PINDIR_INPUT); + return CBaseInputPin::BreakConnect(); +} + + +// Let derived class know when the input pin is connected + +HRESULT +CTransformInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CompleteConnect(pReceivePin); +} + + +// check that we can support a given media type + +HRESULT +CTransformInputPin::CheckMediaType(const CMediaType* pmt) +{ + // Check the input type + + HRESULT hr = m_pTransformFilter->CheckInputType(pmt); + if (S_OK != hr) { + return hr; + } + + // if the output pin is still connected, then we have + // to check the transform not just the input format + + if ((m_pTransformFilter->m_pOutput != NULL) && + (m_pTransformFilter->m_pOutput->IsConnected())) { + return m_pTransformFilter->CheckTransform( + pmt, + &m_pTransformFilter->m_pOutput->CurrentMediaType()); + } else { + return hr; + } +} + + +// set the media type for this connection + +HRESULT +CTransformInputPin::SetMediaType(const CMediaType* mtIn) +{ + // Set the base class media type (should always succeed) + HRESULT hr = CBasePin::SetMediaType(mtIn); + if (FAILED(hr)) { + return hr; + } + + // check the transform can be done (should always succeed) + ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn))); + + return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn); +} + + +// ================================================================= +// Implements IMemInputPin interface +// ================================================================= + + +// provide EndOfStream that passes straight downstream +// (there is no queued data) +STDMETHODIMP +CTransformInputPin::EndOfStream(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csReceive); + HRESULT hr = CheckStreaming(); + if (S_OK == hr) { + hr = m_pTransformFilter->EndOfStream(); + } + return hr; +} + + +// enter flushing state. Call default handler to block Receives, then +// pass to overridable method in filter +STDMETHODIMP +CTransformInputPin::BeginFlush(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csFilter); + // Are we actually doing anything? + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!IsConnected() || + !m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + HRESULT hr = CBaseInputPin::BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->BeginFlush(); +} + + +// leave flushing state. +// Pass to overridable method in filter, then call base class +// to unblock receives (finally) +STDMETHODIMP +CTransformInputPin::EndFlush(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csFilter); + // Are we actually doing anything? + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!IsConnected() || + !m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + HRESULT hr = m_pTransformFilter->EndFlush(); + if (FAILED(hr)) { + return hr; + } + + return CBaseInputPin::EndFlush(); +} + + +// here's the next block of data from the stream. +// AddRef it yourself if you need to hold it beyond the end +// of this call. + +HRESULT +CTransformInputPin::Receive(IMediaSample * pSample) +{ + HRESULT hr; + CAutoLock lck(&m_pTransformFilter->m_csReceive); + ASSERT(pSample); + + // check all is well with the base class + hr = CBaseInputPin::Receive(pSample); + if (S_OK == hr) { + hr = m_pTransformFilter->Receive(pSample); + } + return hr; +} + + + + +// override to pass downstream +STDMETHODIMP +CTransformInputPin::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + // Save the values in the pin + CBasePin::NewSegment(tStart, tStop, dRate); + return m_pTransformFilter->NewSegment(tStart, tStop, dRate); +} + + + + +// ================================================================= +// Implements the CTransformOutputPin class +// ================================================================= + + +// constructor + +CTransformOutputPin::CTransformOutputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), + m_pPosition(NULL) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); + m_pTransformFilter = pTransformFilter; + +} + +#ifdef UNICODE +CTransformOutputPin::CTransformOutputPin( + __in_opt LPCSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), + m_pPosition(NULL) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); + m_pTransformFilter = pTransformFilter; + +} +#endif + +// destructor + +CTransformOutputPin::~CTransformOutputPin() +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin"))); + + if (m_pPosition) m_pPosition->Release(); +} + + +// overriden to expose IMediaPosition and IMediaSeeking control interfaces + +STDMETHODIMP +CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + *ppv = NULL; + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + + // we should have an input pin by now + + ASSERT(m_pTransformFilter->m_pInput != NULL); + + if (m_pPosition == NULL) { + + HRESULT hr = CreatePosPassThru( + GetOwner(), + FALSE, + (IPin *)m_pTransformFilter->m_pInput, + &m_pPosition); + if (FAILED(hr)) { + return hr; + } + } + return m_pPosition->QueryInterface(riid, ppv); + } else { + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// provides derived filter a chance to grab extra interfaces + +HRESULT +CTransformOutputPin::CheckConnect(IPin *pPin) +{ + // we should have an input connection first + + ASSERT(m_pTransformFilter->m_pInput != NULL); + if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { + return E_UNEXPECTED; + } + + HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin); + if (FAILED(hr)) { + return hr; + } + return CBaseOutputPin::CheckConnect(pPin); +} + + +// provides derived filter a chance to release it's extra interfaces + +HRESULT +CTransformOutputPin::BreakConnect() +{ + // Can't disconnect unless stopped + ASSERT(IsStopped()); + m_pTransformFilter->BreakConnect(PINDIR_OUTPUT); + return CBaseOutputPin::BreakConnect(); +} + + +// Let derived class know when the output pin is connected + +HRESULT +CTransformOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseOutputPin::CompleteConnect(pReceivePin); +} + + +// check a given transform - must have selected input type first + +HRESULT +CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut) +{ + // must have selected input first + ASSERT(m_pTransformFilter->m_pInput != NULL); + if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { + return E_INVALIDARG; + } + + return m_pTransformFilter->CheckTransform( + &m_pTransformFilter->m_pInput->CurrentMediaType(), + pmtOut); +} + + +// called after we have agreed a media type to actually set it in which case +// we run the CheckTransform function to get the output format type again + +HRESULT +CTransformOutputPin::SetMediaType(const CMediaType* pmtOut) +{ + HRESULT hr = NOERROR; + ASSERT(m_pTransformFilter->m_pInput != NULL); + + ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid()); + + // Set the base class media type (should always succeed) + hr = CBasePin::SetMediaType(pmtOut); + if (FAILED(hr)) { + return hr; + } + +#ifdef _DEBUG + if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter-> + m_pInput->CurrentMediaType(),pmtOut))) { + DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type"))); + DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope"))); + DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input."))); + } +#endif + + return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut); +} + + +// pass the buffer size decision through to the main transform class + +HRESULT +CTransformOutputPin::DecideBufferSize( + IMemAllocator * pAllocator, + __inout ALLOCATOR_PROPERTIES* pProp) +{ + return m_pTransformFilter->DecideBufferSize(pAllocator, pProp); +} + + + +// return a specific media type indexed by iPosition + +HRESULT +CTransformOutputPin::GetMediaType( + int iPosition, + __inout CMediaType *pMediaType) +{ + ASSERT(m_pTransformFilter->m_pInput != NULL); + + // We don't have any media types if our input is not connected + + if (m_pTransformFilter->m_pInput->IsConnected()) { + return m_pTransformFilter->GetMediaType(iPosition,pMediaType); + } else { + return VFW_S_NO_MORE_ITEMS; + } +} + + +// Override this if you can do something constructive to act on the +// quality message. Consider passing it upstream as well + +// Pass the quality mesage on upstream. + +STDMETHODIMP +CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(pSender); + ValidateReadPtr(pSender,sizeof(IBaseFilter)); + + // First see if we want to handle this ourselves + HRESULT hr = m_pTransformFilter->AlterQuality(q); + if (hr!=S_FALSE) { + return hr; // either S_OK or a failure + } + + // S_FALSE means we pass the message on. + // Find the quality sink for our input pin and send it there + + ASSERT(m_pTransformFilter->m_pInput != NULL); + + return m_pTransformFilter->m_pInput->PassNotify(q); + +} // Notify + + +// the following removes a very large number of level 4 warnings from the microsoft +// compiler output, which are not useful at all in this case. +#pragma warning(disable:4514) diff --git a/src/thirdparty/BaseClasses/transfrm.h b/src/thirdparty/BaseClasses/transfrm.h index 9b276471b68..36c2e0d10b7 100644 --- a/src/thirdparty/BaseClasses/transfrm.h +++ b/src/thirdparty/BaseClasses/transfrm.h @@ -1,304 +1,304 @@ -//------------------------------------------------------------------------------ -// File: Transfrm.h -// -// Desc: DirectShow base classes - defines classes from which simple -// transform codecs may be derived. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// It assumes the codec has one input and one output stream, and has no -// interest in memory management, interface negotiation or anything else. -// -// derive your class from this, and supply Transform and the media type/format -// negotiation functions. Implement that class, compile and link and -// you're done. - - -#ifndef __TRANSFRM__ -#define __TRANSFRM__ - -// ====================================================================== -// This is the com object that represents a simple transform filter. It -// supports IBaseFilter, IMediaFilter and two pins through nested interfaces -// ====================================================================== - -class CTransformFilter; - -// ================================================== -// Implements the input pin -// ================================================== - -class CTransformInputPin : public CBaseInputPin -{ - friend class CTransformFilter; - -protected: - CTransformFilter *m_pTransformFilter; - - -public: - - CTransformInputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CTransformInputPin( - __in_opt LPCSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName); -#endif - - STDMETHODIMP QueryId(__deref_out LPWSTR * Id) - { - return AMGetWideString(L"In", Id); - } - - // Grab and release extra interfaces if required - - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - - // check that we can support this output type - HRESULT CheckMediaType(const CMediaType* mtIn); - - // set the connection media type - HRESULT SetMediaType(const CMediaType* mt); - - // --- IMemInputPin ----- - - // here's the next block of data from the stream. - // AddRef it yourself if you need to hold it beyond the end - // of this call. - STDMETHODIMP Receive(IMediaSample * pSample); - - // provide EndOfStream that passes straight downstream - // (there is no queued data) - STDMETHODIMP EndOfStream(void); - - // passes it to CTransformFilter::BeginFlush - STDMETHODIMP BeginFlush(void); - - // passes it to CTransformFilter::EndFlush - STDMETHODIMP EndFlush(void); - - STDMETHODIMP NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - // Check if it's OK to process samples - virtual HRESULT CheckStreaming(); - - // Media type -public: - CMediaType& CurrentMediaType() { return m_mt; }; - -}; - -// ================================================== -// Implements the output pin -// ================================================== - -class CTransformOutputPin : public CBaseOutputPin -{ - friend class CTransformFilter; - -protected: - CTransformFilter *m_pTransformFilter; - -public: - - // implement IMediaPosition by passing upstream - IUnknown * m_pPosition; - - CTransformOutputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CTransformOutputPin( - __in_opt LPCSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName); -#endif - ~CTransformOutputPin(); - - // override to expose IMediaPosition - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - // --- CBaseOutputPin ------------ - - STDMETHODIMP QueryId(__deref_out LPWSTR * Id) - { - return AMGetWideString(L"Out", Id); - } - - // Grab and release extra interfaces if required - - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - - // check that we can support this output type - HRESULT CheckMediaType(const CMediaType* mtOut); - - // set the connection media type - HRESULT SetMediaType(const CMediaType *pmt); - - // called from CBaseOutputPin during connection to ask for - // the count and size of buffers we need. - HRESULT DecideBufferSize( - IMemAllocator * pAlloc, - __inout ALLOCATOR_PROPERTIES *pProp); - - // returns the preferred formats for a pin - HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); - - // inherited from IQualityControl via CBasePin - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - // Media type -public: - CMediaType& CurrentMediaType() { return m_mt; }; -}; - - -class AM_NOVTABLE CTransformFilter : public CBaseFilter -{ - -public: - - // map getpin/getpincount for base enum of pins to owner - // override this to return more specialised pin objects - - virtual int GetPinCount(); - virtual CBasePin * GetPin(int n); - STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin); - - // override state changes to allow derived transform filter - // to control streaming start/stop - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - -public: - - CTransformFilter(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, REFCLSID clsid); -#ifdef UNICODE - CTransformFilter(__in_opt LPCSTR , __inout_opt LPUNKNOWN, REFCLSID clsid); -#endif - ~CTransformFilter(); - - // ================================================================= - // ----- override these bits --------------------------------------- - // ================================================================= - - // These must be supplied in a derived class - - virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); - - // check if you can support mtIn - virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; - - // check if you can support the transform from this input to this output - virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE; - - // this goes in the factory template table to create new instances - // static CCOMObject * CreateInstance(__inout_opt LPUNKNOWN, HRESULT *); - - // call the SetProperties function with appropriate arguments - virtual HRESULT DecideBufferSize( - IMemAllocator * pAllocator, - __inout ALLOCATOR_PROPERTIES *pprop) PURE; - - // override to suggest OUTPUT pin media types - virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType) PURE; - - - - // ================================================================= - // ----- Optional Override Methods ----------------------- - // ================================================================= - - // you can also override these if you want to know about streaming - virtual HRESULT StartStreaming(); - virtual HRESULT StopStreaming(); - - // override if you can do anything constructive with quality notifications - virtual HRESULT AlterQuality(Quality q); - - // override this to know when the media type is actually set - virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); - - // chance to grab extra interfaces on connection - virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); - virtual HRESULT BreakConnect(PIN_DIRECTION dir); - virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); - - // chance to customize the transform process - virtual HRESULT Receive(IMediaSample *pSample); - - // Standard setup for output sample - HRESULT InitializeOutputSample(IMediaSample *pSample, __deref_out IMediaSample **ppOutSample); - - // if you override Receive, you may need to override these three too - virtual HRESULT EndOfStream(void); - virtual HRESULT BeginFlush(void); - virtual HRESULT EndFlush(void); - virtual HRESULT NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - -#ifdef PERF - // Override to register performance measurement with a less generic string - // You should do this to avoid confusion with other filters - virtual void RegisterPerfId() - {m_idTransform = MSR_REGISTER(TEXT("Transform"));} -#endif // PERF - - -// implementation details - -protected: - -#ifdef PERF - int m_idTransform; // performance measuring id -#endif - BOOL m_bEOSDelivered; // have we sent EndOfStream - BOOL m_bSampleSkipped; // Did we just skip a frame - BOOL m_bQualityChanged; // Have we degraded? - - // critical section protecting filter state. - - CCritSec m_csFilter; - - // critical section stopping state changes (ie Stop) while we're - // processing a sample. - // - // This critical section is held when processing - // events that occur on the receive thread - Receive() and EndOfStream(). - // - // If you want to hold both m_csReceive and m_csFilter then grab - // m_csFilter FIRST - like CTransformFilter::Stop() does. - - CCritSec m_csReceive; - - // these hold our input and output pins - - friend class CTransformInputPin; - friend class CTransformOutputPin; - CTransformInputPin *m_pInput; - CTransformOutputPin *m_pOutput; -}; - -#endif /* __TRANSFRM__ */ - - +//------------------------------------------------------------------------------ +// File: Transfrm.h +// +// Desc: DirectShow base classes - defines classes from which simple +// transform codecs may be derived. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// It assumes the codec has one input and one output stream, and has no +// interest in memory management, interface negotiation or anything else. +// +// derive your class from this, and supply Transform and the media type/format +// negotiation functions. Implement that class, compile and link and +// you're done. + + +#ifndef __TRANSFRM__ +#define __TRANSFRM__ + +// ====================================================================== +// This is the com object that represents a simple transform filter. It +// supports IBaseFilter, IMediaFilter and two pins through nested interfaces +// ====================================================================== + +class CTransformFilter; + +// ================================================== +// Implements the input pin +// ================================================== + +class CTransformInputPin : public CBaseInputPin +{ + friend class CTransformFilter; + +protected: + CTransformFilter *m_pTransformFilter; + + +public: + + CTransformInputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CTransformInputPin( + __in_opt LPCSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName); +#endif + + STDMETHODIMP QueryId(__deref_out LPWSTR * Id) + { + return AMGetWideString(L"In", Id); + } + + // Grab and release extra interfaces if required + + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + + // check that we can support this output type + HRESULT CheckMediaType(const CMediaType* mtIn); + + // set the connection media type + HRESULT SetMediaType(const CMediaType* mt); + + // --- IMemInputPin ----- + + // here's the next block of data from the stream. + // AddRef it yourself if you need to hold it beyond the end + // of this call. + STDMETHODIMP Receive(IMediaSample * pSample); + + // provide EndOfStream that passes straight downstream + // (there is no queued data) + STDMETHODIMP EndOfStream(void); + + // passes it to CTransformFilter::BeginFlush + STDMETHODIMP BeginFlush(void); + + // passes it to CTransformFilter::EndFlush + STDMETHODIMP EndFlush(void); + + STDMETHODIMP NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + // Check if it's OK to process samples + virtual HRESULT CheckStreaming(); + + // Media type +public: + CMediaType& CurrentMediaType() { return m_mt; }; + +}; + +// ================================================== +// Implements the output pin +// ================================================== + +class CTransformOutputPin : public CBaseOutputPin +{ + friend class CTransformFilter; + +protected: + CTransformFilter *m_pTransformFilter; + +public: + + // implement IMediaPosition by passing upstream + IUnknown * m_pPosition; + + CTransformOutputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CTransformOutputPin( + __in_opt LPCSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName); +#endif + ~CTransformOutputPin(); + + // override to expose IMediaPosition + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + // --- CBaseOutputPin ------------ + + STDMETHODIMP QueryId(__deref_out LPWSTR * Id) + { + return AMGetWideString(L"Out", Id); + } + + // Grab and release extra interfaces if required + + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + + // check that we can support this output type + HRESULT CheckMediaType(const CMediaType* mtOut); + + // set the connection media type + HRESULT SetMediaType(const CMediaType *pmt); + + // called from CBaseOutputPin during connection to ask for + // the count and size of buffers we need. + HRESULT DecideBufferSize( + IMemAllocator * pAlloc, + __inout ALLOCATOR_PROPERTIES *pProp); + + // returns the preferred formats for a pin + HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); + + // inherited from IQualityControl via CBasePin + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + // Media type +public: + CMediaType& CurrentMediaType() { return m_mt; }; +}; + + +class AM_NOVTABLE CTransformFilter : public CBaseFilter +{ + +public: + + // map getpin/getpincount for base enum of pins to owner + // override this to return more specialised pin objects + + virtual int GetPinCount(); + virtual CBasePin * GetPin(int n); + STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin); + + // override state changes to allow derived transform filter + // to control streaming start/stop + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + +public: + + CTransformFilter(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, REFCLSID clsid); +#ifdef UNICODE + CTransformFilter(__in_opt LPCSTR , __inout_opt LPUNKNOWN, REFCLSID clsid); +#endif + ~CTransformFilter(); + + // ================================================================= + // ----- override these bits --------------------------------------- + // ================================================================= + + // These must be supplied in a derived class + + virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); + + // check if you can support mtIn + virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; + + // check if you can support the transform from this input to this output + virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE; + + // this goes in the factory template table to create new instances + // static CCOMObject * CreateInstance(__inout_opt LPUNKNOWN, HRESULT *); + + // call the SetProperties function with appropriate arguments + virtual HRESULT DecideBufferSize( + IMemAllocator * pAllocator, + __inout ALLOCATOR_PROPERTIES *pprop) PURE; + + // override to suggest OUTPUT pin media types + virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType) PURE; + + + + // ================================================================= + // ----- Optional Override Methods ----------------------- + // ================================================================= + + // you can also override these if you want to know about streaming + virtual HRESULT StartStreaming(); + virtual HRESULT StopStreaming(); + + // override if you can do anything constructive with quality notifications + virtual HRESULT AlterQuality(Quality q); + + // override this to know when the media type is actually set + virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); + + // chance to grab extra interfaces on connection + virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); + virtual HRESULT BreakConnect(PIN_DIRECTION dir); + virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); + + // chance to customize the transform process + virtual HRESULT Receive(IMediaSample *pSample); + + // Standard setup for output sample + HRESULT InitializeOutputSample(IMediaSample *pSample, __deref_out IMediaSample **ppOutSample); + + // if you override Receive, you may need to override these three too + virtual HRESULT EndOfStream(void); + virtual HRESULT BeginFlush(void); + virtual HRESULT EndFlush(void); + virtual HRESULT NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + +#ifdef PERF + // Override to register performance measurement with a less generic string + // You should do this to avoid confusion with other filters + virtual void RegisterPerfId() + {m_idTransform = MSR_REGISTER(TEXT("Transform"));} +#endif // PERF + + +// implementation details + +protected: + +#ifdef PERF + int m_idTransform; // performance measuring id +#endif + BOOL m_bEOSDelivered; // have we sent EndOfStream + BOOL m_bSampleSkipped; // Did we just skip a frame + BOOL m_bQualityChanged; // Have we degraded? + + // critical section protecting filter state. + + CCritSec m_csFilter; + + // critical section stopping state changes (ie Stop) while we're + // processing a sample. + // + // This critical section is held when processing + // events that occur on the receive thread - Receive() and EndOfStream(). + // + // If you want to hold both m_csReceive and m_csFilter then grab + // m_csFilter FIRST - like CTransformFilter::Stop() does. + + CCritSec m_csReceive; + + // these hold our input and output pins + + friend class CTransformInputPin; + friend class CTransformOutputPin; + CTransformInputPin *m_pInput; + CTransformOutputPin *m_pOutput; +}; + +#endif /* __TRANSFRM__ */ + + diff --git a/src/thirdparty/BaseClasses/transip.cpp b/src/thirdparty/BaseClasses/transip.cpp index b8bc7ef541e..374b81a1979 100644 --- a/src/thirdparty/BaseClasses/transip.cpp +++ b/src/thirdparty/BaseClasses/transip.cpp @@ -1,977 +1,977 @@ -//------------------------------------------------------------------------------ -// File: TransIP.cpp -// -// Desc: DirectShow base classes - implements class for simple Transform- -// In-Place filters such as audio. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// How allocators are decided. -// -// An in-place transform tries to do its work in someone else's buffers. -// It tries to persuade the filters on either side to use the same allocator -// (and for that matter the same media type). In desperation, if the downstream -// filter refuses to supply an allocator and the upstream filter offers only -// a read-only one then it will provide an allocator. -// if the upstream filter insists on a read-only allocator then the transform -// filter will (reluctantly) copy the data before transforming it. -// -// In order to pass an allocator through it needs to remember the one it got -// from the first connection to pass it on to the second one. -// -// It is good if we can avoid insisting on a particular order of connection -// (There is a precedent for insisting on the input -// being connected first. Insisting on the output being connected first is -// not allowed. That would break RenderFile.) -// -// The base pin classes (CBaseOutputPin and CBaseInputPin) both have a -// m_pAllocator member which is used in places like -// CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive. -// To avoid lots of extra overriding, we should keep these happy -// by using these pointers. -// -// When each pin is connected, it will set the corresponding m_pAllocator -// and will have a single ref-count on that allocator. -// -// Refcounts are acquired by GetAllocator calls which return AddReffed -// allocators and are released in one of: -// CBaseInputPin::Disconnect -// CBaseOutputPin::BreakConect -// In each case m_pAllocator is set to NULL after the release, so this -// is the last chance to ever release it. If there should ever be -// multiple refcounts associated with the same pointer, this had better -// be cleared up before that happens. To avoid such problems, we'll -// stick with one per pointer. - - - -// RECONNECTING and STATE CHANGES -// -// Each pin could be disconnected, connected with a read-only allocator, -// connected with an upstream read/write allocator, connected with an -// allocator from downstream or connected with its own allocator. -// Five states for each pin gives a data space of 25 states. -// -// Notation: -// -// R/W == read/write -// R-O == read-only -// -// -// -// 00 means an unconnected pin. -// <- means using a R/W allocator from the upstream filter -// <= means using a R-O allocator from an upstream filter -// || means using our own (R/W) allocator. -// -> means using a R/W allocator from a downstream filter -// (a R-O allocator from downstream is nonsense, it can't ever work). -// -// -// That makes 25 possible states. Some states are nonsense (two different -// allocators from the same place). These are just an artifact of the notation. -// <= <- Nonsense. -// <- <= Nonsense -// Some states are illegal (the output pin never accepts a R-O allocator): -// 00 <= !! Error !! -// <= <= !! Error !! -// || <= !! Error !! -// -> <= !! Error !! -// Three states appears to be inaccessible: -// -> || Inaccessible -// || -> Inaccessible -// || <- Inaccessible -// Some states only ever occur as intermediates with a pending reconnect which -// is guaranteed to finish in another state. -// -> 00 ?? unstable goes to || 00 -// 00 <- ?? unstable goes to 00 || -// -> <- ?? unstable goes to -> -> -// <- || ?? unstable goes to <- <- -// <- -> ?? unstable goes to <- <- -// And that leaves 11 possible resting states: -// 1 00 00 Nothing connected. -// 2 <- 00 Input pin connected. -// 3 <= 00 Input pin connected using R-O allocator. -// 4 || 00 Needs several state changes to get here. -// 5 00 || Output pin connected using our allocator -// 6 00 -> Downstream only connected -// 7 || || Undesirable but can be forced upon us. -// 8 <= || Copy forced. <= -> is preferable -// 9 <= -> OK - forced to copy. -// 10 <- <- Transform in place (ideal) -// 11 -> -> Transform in place (ideal) -// -// The object of the exercise is to ensure that we finish up in states -// 10 or 11 whenever possible. State 10 is only possible if the upstream -// filter has a R/W allocator (the AVI splitter notoriously -// doesn't) and state 11 is only possible if the downstream filter does -// offer an allocator. -// -// The transition table (entries marked * go via a reconnect) -// -// There are 8 possible transitions: -// A: Connect upstream to filter with R-O allocator that insists on using it. -// B: Connect upstream to filter with R-O allocator but chooses not to use it. -// C: Connect upstream to filter with R/W allocator and insists on using it. -// D: Connect upstream to filter with R/W allocator but chooses not to use it. -// E: Connect downstream to a filter that offers an allocator -// F: Connect downstream to a filter that does not offer an allocator -// G: disconnect upstream -// H: Disconnect downstream -// -// A B C D E F G H -// --------------------------------------------------------- -// 00 00 1 | 3 3 2 2 6 5 . . |1 00 00 -// <- 00 2 | . . . . *10/11 10 1 . |2 <- 00 -// <= 00 3 | . . . . *9/11 *7/8 1 . |3 <= 00 -// || 00 4 | . . . . *8 *7 1 . |4 || 00 -// 00 || 5 | 8 7 *10 7 . . . 1 |5 00 || -// 00 -> 6 | 9 11 *10 11 . . . 1 |6 00 -> -// || || 7 | . . . . . . 5 4 |7 || || -// <= || 8 | . . . . . . 5 3 |8 <= || -// <= -> 9 | . . . . . . 6 3 |9 <= -> -// <- <- 10| . . . . . . *5/6 2 |10 <- <- -// -> -> 11| . . . . . . 6 *2/3 |11 -> -> -// --------------------------------------------------------- -// A B C D E F G H -// -// All these states are accessible without requiring any filter to -// change its behaviour but not all transitions are accessible, for -// instance a transition from state 4 to anywhere other than -// state 8 requires that the upstream filter first offer a R-O allocator -// and then changes its mind and offer R/W. This is NOT allowable - it -// leads to things like the output pin getting a R/W allocator from -// upstream and then the input pin being told it can only have a R-O one. -// Note that you CAN change (say) the upstream filter for a different one, but -// only as a disconnect / connect, not as a Reconnect. (Exercise for -// the reader is to see how you get into state 4). -// -// The reconnection stuff goes as follows (some of the cases shown here as -// "no reconnect" may get one to finalise media type - an old story). -// If there is a reconnect where it says "no reconnect" here then the -// reconnection must not change the allocator choice. -// -// state 2: <- 00 transition E <- <- case C <- <- (no change) -// case D -> <- and then to -> -> -// -// state 2: <- 00 transition F <- <- (no reconnect) -// -// state 3: <= 00 transition E <= -> case A <= -> (no change) -// case B -> -> -// transition F <= || case A <= || (no change) -// case B || || -// -// state 4: || 00 transition E || || case B -> || and then all cases to -> -> -// F || || case B || || (no change) -// -// state 5: 00 || transition A <= || (no reconnect) -// B || || (no reconnect) -// C <- || all cases <- <- -// D || || (unfortunate, but upstream's choice) -// -// state 6: 00 -> transition A <= -> (no reconnect) -// B -> -> (no reconnect) -// C <- -> all cases <- <- -// D -> -> (no reconnect) -// -// state 10:<- <- transition G 00 <- case E 00 -> -// case F 00 || -// -// state 11:-> -> transition H -> 00 case A <= 00 (schizo) -// case B <= 00 -// case C <- 00 (schizo) -// case D <- 00 -// -// The Rules: -// To sort out media types: -// The input is reconnected -// if the input pin is connected and the output pin connects -// The output is reconnected -// If the output pin is connected -// and the input pin connects to a different media type -// -// To sort out allocators: -// The input is reconnected -// if the output disconnects and the input was using a downstream allocator -// The output pin calls SetAllocator to pass on a new allocator -// if the output is connected and -// if the input disconnects and the output was using an upstream allocator -// if the input acquires an allocator different from the output one -// and that new allocator is not R-O -// -// Data is copied (i.e. call getbuffer and copy the data before transforming it) -// if the two allocators are different. - - - -// CHAINS of filters: -// -// We sit between two filters (call them A and Z). We should finish up -// with the same allocator on both of our pins and that should be the -// same one that A and Z would have agreed on if we hadn't been in the -// way. Furthermore, it should not matter how many in-place transforms -// are in the way. Let B, C, D... be in-place transforms ("us"). -// Here's how it goes: -// -// 1. -// A connects to B. They agree on A's allocator. -// A-a->B -// -// 2. -// B connects to C. Same story. There is no point in a reconnect, but -// B will request an input reconnect anyway. -// A-a->B-a->C -// -// 3. -// C connects to Z. -// C insists on using A's allocator, but compromises by requesting a reconnect. -// of C's input. -// A-a->B-?->C-a->Z -// -// We now have pending reconnects on both A--->B and B--->C -// -// 4. -// The A--->B link is reconnected. -// A asks B for an allocator. B sees that it has a downstream connection so -// asks its downstream input pin i.e. C's input pin for an allocator. C sees -// that it too has a downstream connection so asks Z for an allocator. -// -// Even though Z's input pin is connected, it is being asked for an allocator. -// It could refuse, in which case the chain is done and will use A's allocator -// Alternatively, Z may supply one. A chooses either Z's or A's own one. -// B's input pin gets NotifyAllocator called to tell it the decision and it -// propagates this downstream by calling ReceiveAllocator on its output pin -// which calls NotifyAllocator on the next input pin downstream etc. -// If the choice is Z then it goes: -// A-z->B-a->C-a->Z -// A-z->B-z->C-a->Z -// A-z->B-z->C-z->Z -// -// And that's IT!! Any further (essentially spurious) reconnects peter out -// with no change in the chain. - -#include "streams.h" -#include "measure.h" -#include "transip.h" - - -// ================================================================= -// Implements the CTransInPlaceFilter class -// ================================================================= - -CTransInPlaceFilter::CTransInPlaceFilter - ( __in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - REFCLSID clsid, - __inout HRESULT *phr, - bool bModifiesData - ) - : CTransformFilter(pName, pUnk, clsid), - m_bModifiesData(bModifiesData) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF - -} // constructor - -#ifdef UNICODE -CTransInPlaceFilter::CTransInPlaceFilter - ( __in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - REFCLSID clsid, - __inout HRESULT *phr, - bool bModifiesData - ) - : CTransformFilter(pName, pUnk, clsid), - m_bModifiesData(bModifiesData) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF - -} // constructor -#endif - -// return a non-addrefed CBasePin * for the user to addref if he holds onto it -// for longer than his pointer to us. We create the pins dynamically when they -// are asked for rather than in the constructor. This is because we want to -// give the derived class an oppportunity to return different pin objects - -// As soon as any pin is needed we create both (this is different from the -// usual transform filter) because enumerators, allocators etc are passed -// through from one pin to another and it becomes very painful if the other -// pin isn't there. If we fail to create either pin we ensure we fail both. - -CBasePin * -CTransInPlaceFilter::GetPin(int n) -{ - HRESULT hr = S_OK; - - // Create an input pin if not already done - - if (m_pInput == NULL) { - - m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin") - , this // Owner filter - , &hr // Result code - , L"Input" // Pin name - ); - - // Constructor for CTransInPlaceInputPin can't fail - ASSERT(SUCCEEDED(hr)); - } - - // Create an output pin if not already done - - if (m_pInput!=NULL && m_pOutput == NULL) { - - m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin") - , this // Owner filter - , &hr // Result code - , L"Output" // Pin name - ); - - // a failed return code should delete the object - - ASSERT(SUCCEEDED(hr)); - if (m_pOutput == NULL) { - delete m_pInput; - m_pInput = NULL; - } - } - - // Return the appropriate pin - - ASSERT (n>=0 && n<=1); - if (n == 0) { - return m_pInput; - } else if (n==1) { - return m_pOutput; - } else { - return NULL; - } - -} // GetPin - - - -// dir is the direction of our pin. -// pReceivePin is the pin we are connecting to. -HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir, IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - ASSERT(m_pInput); - ASSERT(m_pOutput); - - // if we are not part of a graph, then don't indirect the pointer - // this probably prevents use of the filter without a filtergraph - if (!m_pGraph) { - return VFW_E_NOT_IN_GRAPH; - } - - // Always reconnect the input to account for buffering changes - // - // Because we don't get to suggest a type on ReceiveConnection - // we need another way of making sure the right type gets used. - // - // One way would be to have our EnumMediaTypes return our output - // connection type first but more deterministic and simple is to - // call ReconnectEx passing the type we want to reconnect with - // via the base class ReconeectPin method. - - if (dir == PINDIR_OUTPUT) { - if( m_pInput->IsConnected() ) { - return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() ); - } - return NOERROR; - } - - ASSERT(dir == PINDIR_INPUT); - - // Reconnect output if necessary - - if( m_pOutput->IsConnected() ) { - - if ( m_pInput->CurrentMediaType() - != m_pOutput->CurrentMediaType() - ) { - return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() ); - } - } - return NOERROR; - -} // ComnpleteConnect - - -// -// DecideBufferSize -// -// Tell the output pin's allocator what size buffers we require. -// *pAlloc will be the allocator our output pin is using. -// - -HRESULT CTransInPlaceFilter::DecideBufferSize - ( IMemAllocator *pAlloc - , __inout ALLOCATOR_PROPERTIES *pProperties - ) -{ - ALLOCATOR_PROPERTIES Request, Actual; - HRESULT hr; - - // If we are connected upstream, get his views - if (m_pInput->IsConnected()) { - // Get the input pin allocator, and get its size and count. - // we don't care about his alignment and prefix. - - hr = InputPin()->PeekAllocator()->GetProperties(&Request); - if (FAILED(hr)) { - // Input connected but with a secretive allocator - enough! - return hr; - } - } else { - // Propose one byte - // If this isn't enough then when the other pin does get connected - // we can revise it. - ZeroMemory(&Request, sizeof(Request)); - Request.cBuffers = 1; - Request.cbBuffer = 1; - } - - - DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); - DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), - Request.cBuffers, Request.cbBuffer)); - - // Pass the allocator requirements to our output side - // but do a little sanity checking first or we'll just hit - // asserts in the allocator. - - pProperties->cBuffers = Request.cBuffers; - pProperties->cbBuffer = Request.cbBuffer; - pProperties->cbAlign = Request.cbAlign; - if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; } - if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; } - hr = pAlloc->SetProperties(pProperties, &Actual); - - if (FAILED(hr)) { - return hr; - } - - DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); - DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), - Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); - - // Make sure we got the right alignment and at least the minimum required - - if ( (Request.cBuffers > Actual.cBuffers) - || (Request.cbBuffer > Actual.cbBuffer) - || (Request.cbAlign > Actual.cbAlign) - ) { - return E_FAIL; - } - return NOERROR; - -} // DecideBufferSize - -// -// Copy -// -// return a pointer to an identical copy of pSample -__out_opt IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) -{ - IMediaSample * pDest; - - HRESULT hr; - REFERENCE_TIME tStart, tStop; - const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); - - // this may block for an indeterminate amount of time - hr = OutputPin()->PeekAllocator()->GetBuffer( - &pDest - , bTime ? &tStart : NULL - , bTime ? &tStop : NULL - , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 - ); - - if (FAILED(hr)) { - return NULL; - } - - ASSERT(pDest); - IMediaSample2 *pSample2; - if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { - HRESULT hrProps = pSample2->SetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), - (PBYTE)m_pInput->SampleProps()); - pSample2->Release(); - if (FAILED(hrProps)) { - pDest->Release(); - return NULL; - } - } else { - if (bTime) { - pDest->SetTime(&tStart, &tStop); - } - - if (S_OK == pSource->IsSyncPoint()) { - pDest->SetSyncPoint(TRUE); - } - if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { - pDest->SetDiscontinuity(TRUE); - } - if (S_OK == pSource->IsPreroll()) { - pDest->SetPreroll(TRUE); - } - - // Copy the media type - AM_MEDIA_TYPE *pMediaType; - if (S_OK == pSource->GetMediaType(&pMediaType)) { - pDest->SetMediaType(pMediaType); - DeleteMediaType( pMediaType ); - } - - } - - m_bSampleSkipped = FALSE; - - // Copy the sample media times - REFERENCE_TIME TimeStart, TimeEnd; - if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { - pDest->SetMediaTime(&TimeStart,&TimeEnd); - } - - // Copy the actual data length and the actual data. - { - const long lDataLength = pSource->GetActualDataLength(); - if (FAILED(pDest->SetActualDataLength(lDataLength))) { - pDest->Release(); - return NULL; - } - - // Copy the sample data - { - BYTE *pSourceBuffer, *pDestBuffer; -#ifdef _DEBUG - long lSourceSize = pSource->GetSize(); -#endif - long lDestSize = pDest->GetSize(); - - ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); - - if (FAILED(pSource->GetPointer(&pSourceBuffer)) || - FAILED(pDest->GetPointer(&pDestBuffer)) || - lDestSize < lDataLength || - lDataLength < 0) { - pDest->Release(); - return NULL; - } - ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); - - CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); - } - } - - return pDest; - -} // Copy - - -// override this to customize the transform process - -HRESULT -CTransInPlaceFilter::Receive(IMediaSample *pSample) -{ - /* Check for other streams and pass them on */ - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - if (pProps->dwStreamId != AM_STREAM_MEDIA) { - return m_pOutput->Deliver(pSample); - } - HRESULT hr; - - // Start timing the TransInPlace (if PERF is defined) - MSR_START(m_idTransInPlace); - - if (UsingDifferentAllocators()) { - - // We have to copy the data. - - pSample = Copy(pSample); - - if (pSample==NULL) { - MSR_STOP(m_idTransInPlace); - return E_UNEXPECTED; - } - } - - // have the derived class transform the data - hr = Transform(pSample); - - // Stop the clock and log it (if PERF is defined) - MSR_STOP(m_idTransInPlace); - - if (FAILED(hr)) { - DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace"))); - if (UsingDifferentAllocators()) { - pSample->Release(); - } - return hr; - } - - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pSample); - } else { - // But it would be an error to return this private workaround - // to the caller ... - if (S_FALSE == hr) { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this cause because - // returning S_FALSE from Receive() means that this is the end - // of the stream and no more data should be sent. - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - NotifyEvent(EC_QUALITY_CHANGE,0,0); - m_bQualityChanged = TRUE; - } - hr = NOERROR; - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - if (UsingDifferentAllocators()) { - pSample->Release(); - } - - return hr; - -} // Receive - - - -// ================================================================= -// Implements the CTransInPlaceInputPin class -// ================================================================= - - -// constructor - -CTransInPlaceInputPin::CTransInPlaceInputPin - ( __in_opt LPCTSTR pObjectName - , __inout CTransInPlaceFilter *pFilter - , __inout HRESULT *phr - , __in_opt LPCWSTR pName - ) - : CTransformInputPin(pObjectName, - pFilter, - phr, - pName) - , m_bReadOnly(FALSE) - , m_pTIPFilter(pFilter) -{ - DbgLog((LOG_TRACE, 2 - , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin"))); - -} // constructor - - -// ================================================================= -// Implements IMemInputPin interface -// ================================================================= - - -// If the downstream filter has one then offer that (even if our own output -// pin is not using it yet. If the upstream filter chooses it then we will -// tell our output pin to ReceiveAllocator). -// Else if our output pin is using an allocator then offer that. -// ( This could mean offering the upstream filter his own allocator, -// it could mean offerring our own -// ) or it could mean offering the one from downstream -// Else fail to offer any allocator at all. - -STDMETHODIMP CTransInPlaceInputPin::GetAllocator(__deref_out IMemAllocator ** ppAllocator) -{ - CheckPointer(ppAllocator,E_POINTER); - ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); - CAutoLock cObjectLock(m_pLock); - - HRESULT hr; - - if ( m_pTIPFilter->m_pOutput->IsConnected() ) { - // Store the allocator we got - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->GetAllocator( ppAllocator ); - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator ); - } - } - else { - // Help upstream filter (eg TIP filter which is having to do a copy) - // by providing a temp allocator here - we'll never use - // this allocator because when our output is connected we'll - // reconnect this pin - hr = CTransformInputPin::GetAllocator( ppAllocator ); - } - return hr; - -} // GetAllocator - - - -/* Get told which allocator the upstream output pin is actually going to use */ - - -STDMETHODIMP -CTransInPlaceInputPin::NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly) -{ - HRESULT hr = S_OK; - CheckPointer(pAllocator,E_POINTER); - ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); - - CAutoLock cObjectLock(m_pLock); - - m_bReadOnly = bReadOnly; - // If we modify data then don't accept the allocator if it's - // the same as the output pin's allocator - - // If our output is not connected just accept the allocator - // We're never going to use this allocator because when our - // output pin is connected we'll reconnect this pin - if (!m_pTIPFilter->OutputPin()->IsConnected()) { - return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly); - } - - // If the allocator is read-only and we're modifying data - // and the allocator is the same as the output pin's - // then reject - if (bReadOnly && m_pTIPFilter->m_bModifiesData) { - IMemAllocator *pOutputAllocator = - m_pTIPFilter->OutputPin()->PeekAllocator(); - - // Make sure we have an output allocator - if (pOutputAllocator == NULL) { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()-> - GetAllocator(&pOutputAllocator); - if(FAILED(hr)) { - hr = CreateMemoryAllocator(&pOutputAllocator); - } - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator); - pOutputAllocator->Release(); - } - } - if (pAllocator == pOutputAllocator) { - hr = E_FAIL; - } else if(SUCCEEDED(hr)) { - // Must copy so set the allocator properties on the output - ALLOCATOR_PROPERTIES Props, Actual; - hr = pAllocator->GetProperties(&Props); - if (SUCCEEDED(hr)) { - hr = pOutputAllocator->SetProperties(&Props, &Actual); - - if (SUCCEEDED(hr)) { - if ( (Props.cBuffers > Actual.cBuffers) - || (Props.cbBuffer > Actual.cbBuffer) - || (Props.cbAlign > Actual.cbAlign) - ) { - hr = E_FAIL; - } - } - } - - // Set the allocator on the output pin - if (SUCCEEDED(hr)) { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->NotifyAllocator( pOutputAllocator, FALSE ); - } - } - } else { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->NotifyAllocator( pAllocator, bReadOnly ); - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator( pAllocator ); - } - } - - if (SUCCEEDED(hr)) { - - // It's possible that the old and the new are the same thing. - // AddRef before release ensures that we don't unload it. - pAllocator->AddRef(); - - if( m_pAllocator != NULL ) - m_pAllocator->Release(); - - m_pAllocator = pAllocator; // We have an allocator for the input pin - } - - return hr; - -} // NotifyAllocator - - -// EnumMediaTypes -// - pass through to our downstream filter -STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ) -{ - // Can only pass through if connected - if( !m_pTIPFilter->m_pOutput->IsConnected() ) - return VFW_E_NOT_CONNECTED; - - return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum ); - -} // EnumMediaTypes - - -// CheckMediaType -// - agree to anything if not connected, -// otherwise pass through to the downstream filter. -// This assumes that the filter does not change the media type. - -HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt ) -{ - HRESULT hr = m_pTIPFilter->CheckInputType(pmt); - if (hr!=S_OK) return hr; - - if( m_pTIPFilter->m_pOutput->IsConnected() ) - return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt ); - else - return S_OK; - -} // CheckMediaType - - -// If upstream asks us what our requirements are, we will try to ask downstream -// if that doesn't work, we'll just take the defaults. -STDMETHODIMP -CTransInPlaceInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps) -{ - - if( m_pTIPFilter->m_pOutput->IsConnected() ) - return m_pTIPFilter->OutputPin() - ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps ); - else - return E_NOTIMPL; - -} // GetAllocatorRequirements - - -// CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect() -// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because -// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not -// want to reconnect a pin if CBaseInputPin::CompleteConnect() fails. -HRESULT -CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); -} // CompleteConnect - - -// ================================================================= -// Implements the CTransInPlaceOutputPin class -// ================================================================= - - -// constructor - -CTransInPlaceOutputPin::CTransInPlaceOutputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransInPlaceFilter *pFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pPinName) - : CTransformOutputPin( pObjectName - , pFilter - , phr - , pPinName), - m_pTIPFilter(pFilter) -{ - DbgLog(( LOG_TRACE, 2 - , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin"))); - -} // constructor - - -// EnumMediaTypes -// - pass through to our upstream filter -STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ) -{ - // Can only pass through if connected. - if( ! m_pTIPFilter->m_pInput->IsConnected() ) - return VFW_E_NOT_CONNECTED; - - return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum ); - -} // EnumMediaTypes - - - -// CheckMediaType -// - agree to anything if not connected, -// otherwise pass through to the upstream filter. - -HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt ) -{ - // Don't accept any output pin type changes if we're copying - // between allocators - it's too late to change the input - // allocator size. - if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) { - if (*pmt == m_mt) { - return S_OK; - } else { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } - - // Assumes the type does not change. That's why we're calling - // CheckINPUTType here on the OUTPUT pin. - HRESULT hr = m_pTIPFilter->CheckInputType(pmt); - if (hr!=S_OK) return hr; - - if( m_pTIPFilter->m_pInput->IsConnected() ) - return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt ); - else - return S_OK; - -} // CheckMediaType - - -/* Save the allocator pointer in the output pin -*/ -void -CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator) -{ - pAllocator->AddRef(); - if (m_pAllocator) { - m_pAllocator->Release(); - } - m_pAllocator = pAllocator; -} // SetAllocator - - -// CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect() -// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because -// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to -// reconnect a pin if CBaseOutputPin::CompleteConnect() fails. -// CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected -// to the Video Mixing Renderer. -HRESULT -CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); -} // CompleteConnect +//------------------------------------------------------------------------------ +// File: TransIP.cpp +// +// Desc: DirectShow base classes - implements class for simple Transform- +// In-Place filters such as audio. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// How allocators are decided. +// +// An in-place transform tries to do its work in someone else's buffers. +// It tries to persuade the filters on either side to use the same allocator +// (and for that matter the same media type). In desperation, if the downstream +// filter refuses to supply an allocator and the upstream filter offers only +// a read-only one then it will provide an allocator. +// if the upstream filter insists on a read-only allocator then the transform +// filter will (reluctantly) copy the data before transforming it. +// +// In order to pass an allocator through it needs to remember the one it got +// from the first connection to pass it on to the second one. +// +// It is good if we can avoid insisting on a particular order of connection +// (There is a precedent for insisting on the input +// being connected first. Insisting on the output being connected first is +// not allowed. That would break RenderFile.) +// +// The base pin classes (CBaseOutputPin and CBaseInputPin) both have a +// m_pAllocator member which is used in places like +// CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive. +// To avoid lots of extra overriding, we should keep these happy +// by using these pointers. +// +// When each pin is connected, it will set the corresponding m_pAllocator +// and will have a single ref-count on that allocator. +// +// Refcounts are acquired by GetAllocator calls which return AddReffed +// allocators and are released in one of: +// CBaseInputPin::Disconnect +// CBaseOutputPin::BreakConect +// In each case m_pAllocator is set to NULL after the release, so this +// is the last chance to ever release it. If there should ever be +// multiple refcounts associated with the same pointer, this had better +// be cleared up before that happens. To avoid such problems, we'll +// stick with one per pointer. + + + +// RECONNECTING and STATE CHANGES +// +// Each pin could be disconnected, connected with a read-only allocator, +// connected with an upstream read/write allocator, connected with an +// allocator from downstream or connected with its own allocator. +// Five states for each pin gives a data space of 25 states. +// +// Notation: +// +// R/W == read/write +// R-O == read-only +// +// +// +// 00 means an unconnected pin. +// <- means using a R/W allocator from the upstream filter +// <= means using a R-O allocator from an upstream filter +// || means using our own (R/W) allocator. +// -> means using a R/W allocator from a downstream filter +// (a R-O allocator from downstream is nonsense, it can't ever work). +// +// +// That makes 25 possible states. Some states are nonsense (two different +// allocators from the same place). These are just an artifact of the notation. +// <= <- Nonsense. +// <- <= Nonsense +// Some states are illegal (the output pin never accepts a R-O allocator): +// 00 <= !! Error !! +// <= <= !! Error !! +// || <= !! Error !! +// -> <= !! Error !! +// Three states appears to be inaccessible: +// -> || Inaccessible +// || -> Inaccessible +// || <- Inaccessible +// Some states only ever occur as intermediates with a pending reconnect which +// is guaranteed to finish in another state. +// -> 00 ?? unstable goes to || 00 +// 00 <- ?? unstable goes to 00 || +// -> <- ?? unstable goes to -> -> +// <- || ?? unstable goes to <- <- +// <- -> ?? unstable goes to <- <- +// And that leaves 11 possible resting states: +// 1 00 00 Nothing connected. +// 2 <- 00 Input pin connected. +// 3 <= 00 Input pin connected using R-O allocator. +// 4 || 00 Needs several state changes to get here. +// 5 00 || Output pin connected using our allocator +// 6 00 -> Downstream only connected +// 7 || || Undesirable but can be forced upon us. +// 8 <= || Copy forced. <= -> is preferable +// 9 <= -> OK - forced to copy. +// 10 <- <- Transform in place (ideal) +// 11 -> -> Transform in place (ideal) +// +// The object of the exercise is to ensure that we finish up in states +// 10 or 11 whenever possible. State 10 is only possible if the upstream +// filter has a R/W allocator (the AVI splitter notoriously +// doesn't) and state 11 is only possible if the downstream filter does +// offer an allocator. +// +// The transition table (entries marked * go via a reconnect) +// +// There are 8 possible transitions: +// A: Connect upstream to filter with R-O allocator that insists on using it. +// B: Connect upstream to filter with R-O allocator but chooses not to use it. +// C: Connect upstream to filter with R/W allocator and insists on using it. +// D: Connect upstream to filter with R/W allocator but chooses not to use it. +// E: Connect downstream to a filter that offers an allocator +// F: Connect downstream to a filter that does not offer an allocator +// G: disconnect upstream +// H: Disconnect downstream +// +// A B C D E F G H +// --------------------------------------------------------- +// 00 00 1 | 3 3 2 2 6 5 . . |1 00 00 +// <- 00 2 | . . . . *10/11 10 1 . |2 <- 00 +// <= 00 3 | . . . . *9/11 *7/8 1 . |3 <= 00 +// || 00 4 | . . . . *8 *7 1 . |4 || 00 +// 00 || 5 | 8 7 *10 7 . . . 1 |5 00 || +// 00 -> 6 | 9 11 *10 11 . . . 1 |6 00 -> +// || || 7 | . . . . . . 5 4 |7 || || +// <= || 8 | . . . . . . 5 3 |8 <= || +// <= -> 9 | . . . . . . 6 3 |9 <= -> +// <- <- 10| . . . . . . *5/6 2 |10 <- <- +// -> -> 11| . . . . . . 6 *2/3 |11 -> -> +// --------------------------------------------------------- +// A B C D E F G H +// +// All these states are accessible without requiring any filter to +// change its behaviour but not all transitions are accessible, for +// instance a transition from state 4 to anywhere other than +// state 8 requires that the upstream filter first offer a R-O allocator +// and then changes its mind and offer R/W. This is NOT allowable - it +// leads to things like the output pin getting a R/W allocator from +// upstream and then the input pin being told it can only have a R-O one. +// Note that you CAN change (say) the upstream filter for a different one, but +// only as a disconnect / connect, not as a Reconnect. (Exercise for +// the reader is to see how you get into state 4). +// +// The reconnection stuff goes as follows (some of the cases shown here as +// "no reconnect" may get one to finalise media type - an old story). +// If there is a reconnect where it says "no reconnect" here then the +// reconnection must not change the allocator choice. +// +// state 2: <- 00 transition E <- <- case C <- <- (no change) +// case D -> <- and then to -> -> +// +// state 2: <- 00 transition F <- <- (no reconnect) +// +// state 3: <= 00 transition E <= -> case A <= -> (no change) +// case B -> -> +// transition F <= || case A <= || (no change) +// case B || || +// +// state 4: || 00 transition E || || case B -> || and then all cases to -> -> +// F || || case B || || (no change) +// +// state 5: 00 || transition A <= || (no reconnect) +// B || || (no reconnect) +// C <- || all cases <- <- +// D || || (unfortunate, but upstream's choice) +// +// state 6: 00 -> transition A <= -> (no reconnect) +// B -> -> (no reconnect) +// C <- -> all cases <- <- +// D -> -> (no reconnect) +// +// state 10:<- <- transition G 00 <- case E 00 -> +// case F 00 || +// +// state 11:-> -> transition H -> 00 case A <= 00 (schizo) +// case B <= 00 +// case C <- 00 (schizo) +// case D <- 00 +// +// The Rules: +// To sort out media types: +// The input is reconnected +// if the input pin is connected and the output pin connects +// The output is reconnected +// If the output pin is connected +// and the input pin connects to a different media type +// +// To sort out allocators: +// The input is reconnected +// if the output disconnects and the input was using a downstream allocator +// The output pin calls SetAllocator to pass on a new allocator +// if the output is connected and +// if the input disconnects and the output was using an upstream allocator +// if the input acquires an allocator different from the output one +// and that new allocator is not R-O +// +// Data is copied (i.e. call getbuffer and copy the data before transforming it) +// if the two allocators are different. + + + +// CHAINS of filters: +// +// We sit between two filters (call them A and Z). We should finish up +// with the same allocator on both of our pins and that should be the +// same one that A and Z would have agreed on if we hadn't been in the +// way. Furthermore, it should not matter how many in-place transforms +// are in the way. Let B, C, D... be in-place transforms ("us"). +// Here's how it goes: +// +// 1. +// A connects to B. They agree on A's allocator. +// A-a->B +// +// 2. +// B connects to C. Same story. There is no point in a reconnect, but +// B will request an input reconnect anyway. +// A-a->B-a->C +// +// 3. +// C connects to Z. +// C insists on using A's allocator, but compromises by requesting a reconnect. +// of C's input. +// A-a->B-?->C-a->Z +// +// We now have pending reconnects on both A--->B and B--->C +// +// 4. +// The A--->B link is reconnected. +// A asks B for an allocator. B sees that it has a downstream connection so +// asks its downstream input pin i.e. C's input pin for an allocator. C sees +// that it too has a downstream connection so asks Z for an allocator. +// +// Even though Z's input pin is connected, it is being asked for an allocator. +// It could refuse, in which case the chain is done and will use A's allocator +// Alternatively, Z may supply one. A chooses either Z's or A's own one. +// B's input pin gets NotifyAllocator called to tell it the decision and it +// propagates this downstream by calling ReceiveAllocator on its output pin +// which calls NotifyAllocator on the next input pin downstream etc. +// If the choice is Z then it goes: +// A-z->B-a->C-a->Z +// A-z->B-z->C-a->Z +// A-z->B-z->C-z->Z +// +// And that's IT!! Any further (essentially spurious) reconnects peter out +// with no change in the chain. + +#include "streams.h" +#include "measure.h" +#include "transip.h" + + +// ================================================================= +// Implements the CTransInPlaceFilter class +// ================================================================= + +CTransInPlaceFilter::CTransInPlaceFilter + ( __in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + REFCLSID clsid, + __inout HRESULT *phr, + bool bModifiesData + ) + : CTransformFilter(pName, pUnk, clsid), + m_bModifiesData(bModifiesData) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF + +} // constructor + +#ifdef UNICODE +CTransInPlaceFilter::CTransInPlaceFilter + ( __in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + REFCLSID clsid, + __inout HRESULT *phr, + bool bModifiesData + ) + : CTransformFilter(pName, pUnk, clsid), + m_bModifiesData(bModifiesData) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF + +} // constructor +#endif + +// return a non-addrefed CBasePin * for the user to addref if he holds onto it +// for longer than his pointer to us. We create the pins dynamically when they +// are asked for rather than in the constructor. This is because we want to +// give the derived class an oppportunity to return different pin objects + +// As soon as any pin is needed we create both (this is different from the +// usual transform filter) because enumerators, allocators etc are passed +// through from one pin to another and it becomes very painful if the other +// pin isn't there. If we fail to create either pin we ensure we fail both. + +CBasePin * +CTransInPlaceFilter::GetPin(int n) +{ + HRESULT hr = S_OK; + + // Create an input pin if not already done + + if (m_pInput == NULL) { + + m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin") + , this // Owner filter + , &hr // Result code + , L"Input" // Pin name + ); + + // Constructor for CTransInPlaceInputPin can't fail + ASSERT(SUCCEEDED(hr)); + } + + // Create an output pin if not already done + + if (m_pInput!=NULL && m_pOutput == NULL) { + + m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin") + , this // Owner filter + , &hr // Result code + , L"Output" // Pin name + ); + + // a failed return code should delete the object + + ASSERT(SUCCEEDED(hr)); + if (m_pOutput == NULL) { + delete m_pInput; + m_pInput = NULL; + } + } + + // Return the appropriate pin + + ASSERT (n>=0 && n<=1); + if (n == 0) { + return m_pInput; + } else if (n==1) { + return m_pOutput; + } else { + return NULL; + } + +} // GetPin + + + +// dir is the direction of our pin. +// pReceivePin is the pin we are connecting to. +HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir, IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + ASSERT(m_pInput); + ASSERT(m_pOutput); + + // if we are not part of a graph, then don't indirect the pointer + // this probably prevents use of the filter without a filtergraph + if (!m_pGraph) { + return VFW_E_NOT_IN_GRAPH; + } + + // Always reconnect the input to account for buffering changes + // + // Because we don't get to suggest a type on ReceiveConnection + // we need another way of making sure the right type gets used. + // + // One way would be to have our EnumMediaTypes return our output + // connection type first but more deterministic and simple is to + // call ReconnectEx passing the type we want to reconnect with + // via the base class ReconeectPin method. + + if (dir == PINDIR_OUTPUT) { + if( m_pInput->IsConnected() ) { + return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() ); + } + return NOERROR; + } + + ASSERT(dir == PINDIR_INPUT); + + // Reconnect output if necessary + + if( m_pOutput->IsConnected() ) { + + if ( m_pInput->CurrentMediaType() + != m_pOutput->CurrentMediaType() + ) { + return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() ); + } + } + return NOERROR; + +} // ComnpleteConnect + + +// +// DecideBufferSize +// +// Tell the output pin's allocator what size buffers we require. +// *pAlloc will be the allocator our output pin is using. +// + +HRESULT CTransInPlaceFilter::DecideBufferSize + ( IMemAllocator *pAlloc + , __inout ALLOCATOR_PROPERTIES *pProperties + ) +{ + ALLOCATOR_PROPERTIES Request, Actual; + HRESULT hr; + + // If we are connected upstream, get his views + if (m_pInput->IsConnected()) { + // Get the input pin allocator, and get its size and count. + // we don't care about his alignment and prefix. + + hr = InputPin()->PeekAllocator()->GetProperties(&Request); + if (FAILED(hr)) { + // Input connected but with a secretive allocator - enough! + return hr; + } + } else { + // Propose one byte + // If this isn't enough then when the other pin does get connected + // we can revise it. + ZeroMemory(&Request, sizeof(Request)); + Request.cBuffers = 1; + Request.cbBuffer = 1; + } + + + DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); + DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), + Request.cBuffers, Request.cbBuffer)); + + // Pass the allocator requirements to our output side + // but do a little sanity checking first or we'll just hit + // asserts in the allocator. + + pProperties->cBuffers = Request.cBuffers; + pProperties->cbBuffer = Request.cbBuffer; + pProperties->cbAlign = Request.cbAlign; + if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; } + if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; } + hr = pAlloc->SetProperties(pProperties, &Actual); + + if (FAILED(hr)) { + return hr; + } + + DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); + DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), + Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); + + // Make sure we got the right alignment and at least the minimum required + + if ( (Request.cBuffers > Actual.cBuffers) + || (Request.cbBuffer > Actual.cbBuffer) + || (Request.cbAlign > Actual.cbAlign) + ) { + return E_FAIL; + } + return NOERROR; + +} // DecideBufferSize + +// +// Copy +// +// return a pointer to an identical copy of pSample +__out_opt IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) +{ + IMediaSample * pDest; + + HRESULT hr; + REFERENCE_TIME tStart, tStop; + const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); + + // this may block for an indeterminate amount of time + hr = OutputPin()->PeekAllocator()->GetBuffer( + &pDest + , bTime ? &tStart : NULL + , bTime ? &tStop : NULL + , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 + ); + + if (FAILED(hr)) { + return NULL; + } + + ASSERT(pDest); + IMediaSample2 *pSample2; + if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { + HRESULT hrProps = pSample2->SetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), + (PBYTE)m_pInput->SampleProps()); + pSample2->Release(); + if (FAILED(hrProps)) { + pDest->Release(); + return NULL; + } + } else { + if (bTime) { + pDest->SetTime(&tStart, &tStop); + } + + if (S_OK == pSource->IsSyncPoint()) { + pDest->SetSyncPoint(TRUE); + } + if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { + pDest->SetDiscontinuity(TRUE); + } + if (S_OK == pSource->IsPreroll()) { + pDest->SetPreroll(TRUE); + } + + // Copy the media type + AM_MEDIA_TYPE *pMediaType; + if (S_OK == pSource->GetMediaType(&pMediaType)) { + pDest->SetMediaType(pMediaType); + DeleteMediaType( pMediaType ); + } + + } + + m_bSampleSkipped = FALSE; + + // Copy the sample media times + REFERENCE_TIME TimeStart, TimeEnd; + if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { + pDest->SetMediaTime(&TimeStart,&TimeEnd); + } + + // Copy the actual data length and the actual data. + { + const long lDataLength = pSource->GetActualDataLength(); + if (FAILED(pDest->SetActualDataLength(lDataLength))) { + pDest->Release(); + return NULL; + } + + // Copy the sample data + { + BYTE *pSourceBuffer, *pDestBuffer; +#ifdef _DEBUG + long lSourceSize = pSource->GetSize(); +#endif + long lDestSize = pDest->GetSize(); + + ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); + + if (FAILED(pSource->GetPointer(&pSourceBuffer)) || + FAILED(pDest->GetPointer(&pDestBuffer)) || + lDestSize < lDataLength || + lDataLength < 0) { + pDest->Release(); + return NULL; + } + ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); + + CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); + } + } + + return pDest; + +} // Copy + + +// override this to customize the transform process + +HRESULT +CTransInPlaceFilter::Receive(IMediaSample *pSample) +{ + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->Deliver(pSample); + } + HRESULT hr; + + // Start timing the TransInPlace (if PERF is defined) + MSR_START(m_idTransInPlace); + + if (UsingDifferentAllocators()) { + + // We have to copy the data. + + pSample = Copy(pSample); + + if (pSample==NULL) { + MSR_STOP(m_idTransInPlace); + return E_UNEXPECTED; + } + } + + // have the derived class transform the data + hr = Transform(pSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransInPlace); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace"))); + if (UsingDifferentAllocators()) { + pSample->Release(); + } + return hr; + } + + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pSample); + } else { + // But it would be an error to return this private workaround + // to the caller ... + if (S_FALSE == hr) { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because + // returning S_FALSE from Receive() means that this is the end + // of the stream and no more data should be sent. + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE,0,0); + m_bQualityChanged = TRUE; + } + hr = NOERROR; + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + if (UsingDifferentAllocators()) { + pSample->Release(); + } + + return hr; + +} // Receive + + + +// ================================================================= +// Implements the CTransInPlaceInputPin class +// ================================================================= + + +// constructor + +CTransInPlaceInputPin::CTransInPlaceInputPin + ( __in_opt LPCTSTR pObjectName + , __inout CTransInPlaceFilter *pFilter + , __inout HRESULT *phr + , __in_opt LPCWSTR pName + ) + : CTransformInputPin(pObjectName, + pFilter, + phr, + pName) + , m_bReadOnly(FALSE) + , m_pTIPFilter(pFilter) +{ + DbgLog((LOG_TRACE, 2 + , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin"))); + +} // constructor + + +// ================================================================= +// Implements IMemInputPin interface +// ================================================================= + + +// If the downstream filter has one then offer that (even if our own output +// pin is not using it yet. If the upstream filter chooses it then we will +// tell our output pin to ReceiveAllocator). +// Else if our output pin is using an allocator then offer that. +// ( This could mean offering the upstream filter his own allocator, +// it could mean offerring our own +// ) or it could mean offering the one from downstream +// Else fail to offer any allocator at all. + +STDMETHODIMP CTransInPlaceInputPin::GetAllocator(__deref_out IMemAllocator ** ppAllocator) +{ + CheckPointer(ppAllocator,E_POINTER); + ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); + CAutoLock cObjectLock(m_pLock); + + HRESULT hr; + + if ( m_pTIPFilter->m_pOutput->IsConnected() ) { + // Store the allocator we got + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->GetAllocator( ppAllocator ); + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator ); + } + } + else { + // Help upstream filter (eg TIP filter which is having to do a copy) + // by providing a temp allocator here - we'll never use + // this allocator because when our output is connected we'll + // reconnect this pin + hr = CTransformInputPin::GetAllocator( ppAllocator ); + } + return hr; + +} // GetAllocator + + + +/* Get told which allocator the upstream output pin is actually going to use */ + + +STDMETHODIMP +CTransInPlaceInputPin::NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly) +{ + HRESULT hr = S_OK; + CheckPointer(pAllocator,E_POINTER); + ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); + + CAutoLock cObjectLock(m_pLock); + + m_bReadOnly = bReadOnly; + // If we modify data then don't accept the allocator if it's + // the same as the output pin's allocator + + // If our output is not connected just accept the allocator + // We're never going to use this allocator because when our + // output pin is connected we'll reconnect this pin + if (!m_pTIPFilter->OutputPin()->IsConnected()) { + return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly); + } + + // If the allocator is read-only and we're modifying data + // and the allocator is the same as the output pin's + // then reject + if (bReadOnly && m_pTIPFilter->m_bModifiesData) { + IMemAllocator *pOutputAllocator = + m_pTIPFilter->OutputPin()->PeekAllocator(); + + // Make sure we have an output allocator + if (pOutputAllocator == NULL) { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()-> + GetAllocator(&pOutputAllocator); + if(FAILED(hr)) { + hr = CreateMemoryAllocator(&pOutputAllocator); + } + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator); + pOutputAllocator->Release(); + } + } + if (pAllocator == pOutputAllocator) { + hr = E_FAIL; + } else if(SUCCEEDED(hr)) { + // Must copy so set the allocator properties on the output + ALLOCATOR_PROPERTIES Props, Actual; + hr = pAllocator->GetProperties(&Props); + if (SUCCEEDED(hr)) { + hr = pOutputAllocator->SetProperties(&Props, &Actual); + + if (SUCCEEDED(hr)) { + if ( (Props.cBuffers > Actual.cBuffers) + || (Props.cbBuffer > Actual.cbBuffer) + || (Props.cbAlign > Actual.cbAlign) + ) { + hr = E_FAIL; + } + } + } + + // Set the allocator on the output pin + if (SUCCEEDED(hr)) { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->NotifyAllocator( pOutputAllocator, FALSE ); + } + } + } else { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->NotifyAllocator( pAllocator, bReadOnly ); + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator( pAllocator ); + } + } + + if (SUCCEEDED(hr)) { + + // It's possible that the old and the new are the same thing. + // AddRef before release ensures that we don't unload it. + pAllocator->AddRef(); + + if( m_pAllocator != NULL ) + m_pAllocator->Release(); + + m_pAllocator = pAllocator; // We have an allocator for the input pin + } + + return hr; + +} // NotifyAllocator + + +// EnumMediaTypes +// - pass through to our downstream filter +STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ) +{ + // Can only pass through if connected + if( !m_pTIPFilter->m_pOutput->IsConnected() ) + return VFW_E_NOT_CONNECTED; + + return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum ); + +} // EnumMediaTypes + + +// CheckMediaType +// - agree to anything if not connected, +// otherwise pass through to the downstream filter. +// This assumes that the filter does not change the media type. + +HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt ) +{ + HRESULT hr = m_pTIPFilter->CheckInputType(pmt); + if (hr!=S_OK) return hr; + + if( m_pTIPFilter->m_pOutput->IsConnected() ) + return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt ); + else + return S_OK; + +} // CheckMediaType + + +// If upstream asks us what our requirements are, we will try to ask downstream +// if that doesn't work, we'll just take the defaults. +STDMETHODIMP +CTransInPlaceInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps) +{ + + if( m_pTIPFilter->m_pOutput->IsConnected() ) + return m_pTIPFilter->OutputPin() + ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps ); + else + return E_NOTIMPL; + +} // GetAllocatorRequirements + + +// CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect() +// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because +// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not +// want to reconnect a pin if CBaseInputPin::CompleteConnect() fails. +HRESULT +CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); +} // CompleteConnect + + +// ================================================================= +// Implements the CTransInPlaceOutputPin class +// ================================================================= + + +// constructor + +CTransInPlaceOutputPin::CTransInPlaceOutputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransInPlaceFilter *pFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pPinName) + : CTransformOutputPin( pObjectName + , pFilter + , phr + , pPinName), + m_pTIPFilter(pFilter) +{ + DbgLog(( LOG_TRACE, 2 + , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin"))); + +} // constructor + + +// EnumMediaTypes +// - pass through to our upstream filter +STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ) +{ + // Can only pass through if connected. + if( ! m_pTIPFilter->m_pInput->IsConnected() ) + return VFW_E_NOT_CONNECTED; + + return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum ); + +} // EnumMediaTypes + + + +// CheckMediaType +// - agree to anything if not connected, +// otherwise pass through to the upstream filter. + +HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt ) +{ + // Don't accept any output pin type changes if we're copying + // between allocators - it's too late to change the input + // allocator size. + if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) { + if (*pmt == m_mt) { + return S_OK; + } else { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } + + // Assumes the type does not change. That's why we're calling + // CheckINPUTType here on the OUTPUT pin. + HRESULT hr = m_pTIPFilter->CheckInputType(pmt); + if (hr!=S_OK) return hr; + + if( m_pTIPFilter->m_pInput->IsConnected() ) + return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt ); + else + return S_OK; + +} // CheckMediaType + + +/* Save the allocator pointer in the output pin +*/ +void +CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator) +{ + pAllocator->AddRef(); + if (m_pAllocator) { + m_pAllocator->Release(); + } + m_pAllocator = pAllocator; +} // SetAllocator + + +// CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect() +// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because +// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to +// reconnect a pin if CBaseOutputPin::CompleteConnect() fails. +// CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected +// to the Video Mixing Renderer. +HRESULT +CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); +} // CompleteConnect diff --git a/src/thirdparty/BaseClasses/transip.h b/src/thirdparty/BaseClasses/transip.h index 687efd99ed2..f65f66b5f61 100644 --- a/src/thirdparty/BaseClasses/transip.h +++ b/src/thirdparty/BaseClasses/transip.h @@ -1,250 +1,250 @@ -//------------------------------------------------------------------------------ -// File: TransIP.h -// -// Desc: DirectShow base classes - defines classes from which simple -// Transform-In-Place filters may be derived. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// The difference between this and Transfrm.h is that Transfrm copies the data. -// -// It assumes the filter has one input and one output stream, and has no -// interest in memory management, interface negotiation or anything else. -// -// Derive your class from this, and supply Transform and the media type/format -// negotiation functions. Implement that class, compile and link and -// you're done. - - -#ifndef __TRANSIP__ -#define __TRANSIP__ - -// ====================================================================== -// This is the com object that represents a simple transform filter. It -// supports IBaseFilter, IMediaFilter and two pins through nested interfaces -// ====================================================================== - -class CTransInPlaceFilter; - -// Several of the pin functions call filter functions to do the work, -// so you can often use the pin classes unaltered, just overriding the -// functions in CTransInPlaceFilter. If that's not enough and you want -// to derive your own pin class, override GetPin in the filter to supply -// your own pin classes to the filter. - -// ================================================== -// Implements the input pin -// ================================================== - -class CTransInPlaceInputPin : public CTransformInputPin -{ - -protected: - CTransInPlaceFilter * const m_pTIPFilter; // our filter - BOOL m_bReadOnly; // incoming stream is read only - -public: - - CTransInPlaceInputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransInPlaceFilter *pFilter, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); - - // --- IMemInputPin ----- - - // Provide an enumerator for media types by getting one from downstream - STDMETHODIMP EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ); - - // Say whether media type is acceptable. - HRESULT CheckMediaType(const CMediaType* pmt); - - // Return our upstream allocator - STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator); - - // get told which allocator the upstream output pin is actually - // going to use. - STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator, - BOOL bReadOnly); - - // Allow the filter to see what allocator we have - // N.B. This does NOT AddRef - __out IMemAllocator * PeekAllocator() const - { return m_pAllocator; } - - // Pass this on downstream if it ever gets called. - STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps); - - HRESULT CompleteConnect(IPin *pReceivePin); - - inline const BOOL ReadOnly() { return m_bReadOnly ; } - -}; // CTransInPlaceInputPin - -// ================================================== -// Implements the output pin -// ================================================== - -class CTransInPlaceOutputPin : public CTransformOutputPin -{ - -protected: - // m_pFilter points to our CBaseFilter - CTransInPlaceFilter * const m_pTIPFilter; - -public: - - CTransInPlaceOutputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransInPlaceFilter *pFilter, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); - - - // --- CBaseOutputPin ------------ - - // negotiate the allocator and its buffer size/count - // Insists on using our own allocator. (Actually the one upstream of us). - // We don't override this - instead we just agree the default - // then let the upstream filter decide for itself on reconnect - // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); - - // Provide a media type enumerator. Get it from upstream. - STDMETHODIMP EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ); - - // Say whether media type is acceptable. - HRESULT CheckMediaType(const CMediaType* pmt); - - // This just saves the allocator being used on the output pin - // Also called by input pin's GetAllocator() - void SetAllocator(IMemAllocator * pAllocator); - - __out_opt IMemInputPin * ConnectedIMemInputPin() - { return m_pInputPin; } - - // Allow the filter to see what allocator we have - // N.B. This does NOT AddRef - __out IMemAllocator * PeekAllocator() const - { return m_pAllocator; } - - HRESULT CompleteConnect(IPin *pReceivePin); - -}; // CTransInPlaceOutputPin - - -class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter -{ - -public: - - // map getpin/getpincount for base enum of pins to owner - // override this to return more specialised pin objects - - virtual CBasePin *GetPin(int n); - -public: - - // Set bModifiesData == false if your derived filter does - // not modify the data samples (for instance it's just copying - // them somewhere else or looking at the timestamps). - - CTransInPlaceFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, - bool bModifiesData = true); -#ifdef UNICODE - CTransInPlaceFilter(__in_opt LPCSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, - bool bModifiesData = true); -#endif - // The following are defined to avoid undefined pure virtuals. - // Even if they are never called, they will give linkage warnings/errors - - // We override EnumMediaTypes to bypass the transform class enumerator - // which would otherwise call this. - HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType) - { DbgBreak("CTransInPlaceFilter::GetMediaType should never be called"); - return E_UNEXPECTED; - } - - // This is called when we actually have to provide our own allocator. - HRESULT DecideBufferSize(IMemAllocator*, __inout ALLOCATOR_PROPERTIES *); - - // The functions which call this in CTransform are overridden in this - // class to call CheckInputType with the assumption that the type - // does not change. In Debug builds some calls will be made and - // we just ensure that they do not assert. - HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) - { - return S_OK; - }; - - - // ================================================================= - // ----- You may want to override this ----------------------------- - // ================================================================= - - HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin); - - // chance to customize the transform process - virtual HRESULT Receive(IMediaSample *pSample); - - // ================================================================= - // ----- You MUST override these ----------------------------------- - // ================================================================= - - virtual HRESULT Transform(IMediaSample *pSample) PURE; - - // this goes in the factory template table to create new instances - // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); - - -#ifdef PERF - // Override to register performance measurement with a less generic string - // You should do this to avoid confusion with other filters - virtual void RegisterPerfId() - {m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));} -#endif // PERF - - -// implementation details - -protected: - - __out_opt IMediaSample * Copy(IMediaSample *pSource); - -#ifdef PERF - int m_idTransInPlace; // performance measuring id -#endif // PERF - bool m_bModifiesData; // Does this filter change the data? - - // these hold our input and output pins - - friend class CTransInPlaceInputPin; - friend class CTransInPlaceOutputPin; - - __out CTransInPlaceInputPin *InputPin() const - { - return (CTransInPlaceInputPin *)m_pInput; - }; - __out CTransInPlaceOutputPin *OutputPin() const - { - return (CTransInPlaceOutputPin *)m_pOutput; - }; - - // Helper to see if the input and output types match - BOOL TypesMatch() - { - return InputPin()->CurrentMediaType() == - OutputPin()->CurrentMediaType(); - } - - // Are the input and output allocators different? - BOOL UsingDifferentAllocators() const - { - return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator(); - } -}; // CTransInPlaceFilter - -#endif /* __TRANSIP__ */ - +//------------------------------------------------------------------------------ +// File: TransIP.h +// +// Desc: DirectShow base classes - defines classes from which simple +// Transform-In-Place filters may be derived. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// The difference between this and Transfrm.h is that Transfrm copies the data. +// +// It assumes the filter has one input and one output stream, and has no +// interest in memory management, interface negotiation or anything else. +// +// Derive your class from this, and supply Transform and the media type/format +// negotiation functions. Implement that class, compile and link and +// you're done. + + +#ifndef __TRANSIP__ +#define __TRANSIP__ + +// ====================================================================== +// This is the com object that represents a simple transform filter. It +// supports IBaseFilter, IMediaFilter and two pins through nested interfaces +// ====================================================================== + +class CTransInPlaceFilter; + +// Several of the pin functions call filter functions to do the work, +// so you can often use the pin classes unaltered, just overriding the +// functions in CTransInPlaceFilter. If that's not enough and you want +// to derive your own pin class, override GetPin in the filter to supply +// your own pin classes to the filter. + +// ================================================== +// Implements the input pin +// ================================================== + +class CTransInPlaceInputPin : public CTransformInputPin +{ + +protected: + CTransInPlaceFilter * const m_pTIPFilter; // our filter + BOOL m_bReadOnly; // incoming stream is read only + +public: + + CTransInPlaceInputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransInPlaceFilter *pFilter, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); + + // --- IMemInputPin ----- + + // Provide an enumerator for media types by getting one from downstream + STDMETHODIMP EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ); + + // Say whether media type is acceptable. + HRESULT CheckMediaType(const CMediaType* pmt); + + // Return our upstream allocator + STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator); + + // get told which allocator the upstream output pin is actually + // going to use. + STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator, + BOOL bReadOnly); + + // Allow the filter to see what allocator we have + // N.B. This does NOT AddRef + __out IMemAllocator * PeekAllocator() const + { return m_pAllocator; } + + // Pass this on downstream if it ever gets called. + STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps); + + HRESULT CompleteConnect(IPin *pReceivePin); + + inline const BOOL ReadOnly() { return m_bReadOnly ; } + +}; // CTransInPlaceInputPin + +// ================================================== +// Implements the output pin +// ================================================== + +class CTransInPlaceOutputPin : public CTransformOutputPin +{ + +protected: + // m_pFilter points to our CBaseFilter + CTransInPlaceFilter * const m_pTIPFilter; + +public: + + CTransInPlaceOutputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransInPlaceFilter *pFilter, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); + + + // --- CBaseOutputPin ------------ + + // negotiate the allocator and its buffer size/count + // Insists on using our own allocator. (Actually the one upstream of us). + // We don't override this - instead we just agree the default + // then let the upstream filter decide for itself on reconnect + // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); + + // Provide a media type enumerator. Get it from upstream. + STDMETHODIMP EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ); + + // Say whether media type is acceptable. + HRESULT CheckMediaType(const CMediaType* pmt); + + // This just saves the allocator being used on the output pin + // Also called by input pin's GetAllocator() + void SetAllocator(IMemAllocator * pAllocator); + + __out_opt IMemInputPin * ConnectedIMemInputPin() + { return m_pInputPin; } + + // Allow the filter to see what allocator we have + // N.B. This does NOT AddRef + __out IMemAllocator * PeekAllocator() const + { return m_pAllocator; } + + HRESULT CompleteConnect(IPin *pReceivePin); + +}; // CTransInPlaceOutputPin + + +class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter +{ + +public: + + // map getpin/getpincount for base enum of pins to owner + // override this to return more specialised pin objects + + virtual CBasePin *GetPin(int n); + +public: + + // Set bModifiesData == false if your derived filter does + // not modify the data samples (for instance it's just copying + // them somewhere else or looking at the timestamps). + + CTransInPlaceFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, + bool bModifiesData = true); +#ifdef UNICODE + CTransInPlaceFilter(__in_opt LPCSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, + bool bModifiesData = true); +#endif + // The following are defined to avoid undefined pure virtuals. + // Even if they are never called, they will give linkage warnings/errors + + // We override EnumMediaTypes to bypass the transform class enumerator + // which would otherwise call this. + HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType) + { DbgBreak("CTransInPlaceFilter::GetMediaType should never be called"); + return E_UNEXPECTED; + } + + // This is called when we actually have to provide our own allocator. + HRESULT DecideBufferSize(IMemAllocator*, __inout ALLOCATOR_PROPERTIES *); + + // The functions which call this in CTransform are overridden in this + // class to call CheckInputType with the assumption that the type + // does not change. In Debug builds some calls will be made and + // we just ensure that they do not assert. + HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) + { + return S_OK; + }; + + + // ================================================================= + // ----- You may want to override this ----------------------------- + // ================================================================= + + HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin); + + // chance to customize the transform process + virtual HRESULT Receive(IMediaSample *pSample); + + // ================================================================= + // ----- You MUST override these ----------------------------------- + // ================================================================= + + virtual HRESULT Transform(IMediaSample *pSample) PURE; + + // this goes in the factory template table to create new instances + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + + +#ifdef PERF + // Override to register performance measurement with a less generic string + // You should do this to avoid confusion with other filters + virtual void RegisterPerfId() + {m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));} +#endif // PERF + + +// implementation details + +protected: + + __out_opt IMediaSample * Copy(IMediaSample *pSource); + +#ifdef PERF + int m_idTransInPlace; // performance measuring id +#endif // PERF + bool m_bModifiesData; // Does this filter change the data? + + // these hold our input and output pins + + friend class CTransInPlaceInputPin; + friend class CTransInPlaceOutputPin; + + __out CTransInPlaceInputPin *InputPin() const + { + return (CTransInPlaceInputPin *)m_pInput; + }; + __out CTransInPlaceOutputPin *OutputPin() const + { + return (CTransInPlaceOutputPin *)m_pOutput; + }; + + // Helper to see if the input and output types match + BOOL TypesMatch() + { + return InputPin()->CurrentMediaType() == + OutputPin()->CurrentMediaType(); + } + + // Are the input and output allocators different? + BOOL UsingDifferentAllocators() const + { + return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator(); + } +}; // CTransInPlaceFilter + +#endif /* __TRANSIP__ */ + diff --git a/src/thirdparty/BaseClasses/videoctl.cpp b/src/thirdparty/BaseClasses/videoctl.cpp index d8e293d322f..974b1dfb9a8 100644 --- a/src/thirdparty/BaseClasses/videoctl.cpp +++ b/src/thirdparty/BaseClasses/videoctl.cpp @@ -1,745 +1,745 @@ -//------------------------------------------------------------------------------ -// File: VideoCtl.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "ddmm.h" - -// Load a string from the resource file string table. The buffer must be at -// least STR_MAX_LENGTH bytes. The easiest way to use this is to declare a -// buffer in the property page class and use it for all string loading. It -// cannot be static as multiple property pages may be active simultaneously - -LPCTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID) -{ - if (LoadString(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { - return TEXT(""); - } - return pBuffer; -} - -#ifdef UNICODE -LPCSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR pBuffer, int iResourceID) -{ - if (LoadStringA(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { - return ""; - } - return pBuffer; -} -#endif - - - -// Property pages typically are called through their OLE interfaces. These -// use UNICODE strings regardless of how the binary is built. So when we -// load strings from the resource file we sometimes want to convert them -// to UNICODE. This method is passed the target UNICODE buffer and does a -// convert after loading the string (if built UNICODE this is not needed) -// On WinNT we can explicitly call LoadStringW which saves two conversions - -#ifndef UNICODE - -LPCWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR pBuffer, int iResourceID) -{ - *pBuffer = 0; - - if (g_amPlatform == VER_PLATFORM_WIN32_NT) { - LoadStringW(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH); - } else { - - CHAR szBuffer[STR_MAX_LENGTH]; - DWORD dwStringLength = LoadString(g_hInst,iResourceID,szBuffer,STR_MAX_LENGTH); - // if we loaded a string convert it to wide characters, ensuring - // that we also null terminate the result. - if (dwStringLength++) { - MultiByteToWideChar(CP_ACP,0,szBuffer,dwStringLength,pBuffer,STR_MAX_LENGTH); - } - } - return pBuffer; -} - -#endif - - -// Helper function to calculate the size of the dialog - -BOOL WINAPI GetDialogSize(int iResourceID, - DLGPROC pDlgProc, - LPARAM lParam, - __out SIZE *pResult) -{ - RECT rc; - HWND hwnd; - - // Create a temporary property page - - hwnd = CreateDialogParam(g_hInst, - MAKEINTRESOURCE(iResourceID), - GetDesktopWindow(), - pDlgProc, - lParam); - if (hwnd == NULL) { - return FALSE; - } - - GetWindowRect(hwnd, &rc); - pResult->cx = rc.right - rc.left; - pResult->cy = rc.bottom - rc.top; - - DestroyWindow(hwnd); - return TRUE; -} - - -// Class that aggregates on the IDirectDraw interface. Although DirectDraw -// has the ability in its interfaces to be aggregated they're not currently -// implemented. This makes it difficult for various parts of Quartz that want -// to aggregate these interfaces. In particular the video renderer passes out -// media samples that expose IDirectDraw and IDirectDrawSurface. The filter -// graph manager also exposes IDirectDraw as a plug in distributor. For these -// objects we provide these aggregation classes that republish the interfaces - -STDMETHODIMP CAggDirectDraw::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ASSERT(m_pDirectDraw); - - // Do we have this interface - - if (riid == IID_IDirectDraw) { - return GetInterface((IDirectDraw *)this,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid,ppv); - } -} - - -STDMETHODIMP CAggDirectDraw::Compact() -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->Compact(); -} - - -STDMETHODIMP CAggDirectDraw::CreateClipper(DWORD dwFlags, __deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper, __inout_opt IUnknown *pUnkOuter) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->CreateClipper(dwFlags,lplpDDClipper,pUnkOuter); -} - - -STDMETHODIMP CAggDirectDraw::CreatePalette(DWORD dwFlags, - __in LPPALETTEENTRY lpColorTable, - __deref_out LPDIRECTDRAWPALETTE *lplpDDPalette, - __inout_opt IUnknown *pUnkOuter) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->CreatePalette(dwFlags,lpColorTable,lplpDDPalette,pUnkOuter); -} - - -STDMETHODIMP CAggDirectDraw::CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc, - __deref_out LPDIRECTDRAWSURFACE *lplpDDSurface, - __inout_opt IUnknown *pUnkOuter) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->CreateSurface(lpDDSurfaceDesc,lplpDDSurface,pUnkOuter); -} - - -STDMETHODIMP CAggDirectDraw::DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface, - __deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->DuplicateSurface(lpDDSurface,lplpDupDDSurface); -} - - -STDMETHODIMP CAggDirectDraw::EnumDisplayModes(DWORD dwSurfaceDescCount, - __in LPDDSURFACEDESC lplpDDSurfaceDescList, - __in LPVOID lpContext, - __in LPDDENUMMODESCALLBACK lpEnumCallback) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->EnumDisplayModes(dwSurfaceDescCount,lplpDDSurfaceDescList,lpContext,lpEnumCallback); -} - - -STDMETHODIMP CAggDirectDraw::EnumSurfaces(DWORD dwFlags, - __in LPDDSURFACEDESC lpDDSD, - __in LPVOID lpContext, - __in LPDDENUMSURFACESCALLBACK lpEnumCallback) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->EnumSurfaces(dwFlags,lpDDSD,lpContext,lpEnumCallback); -} - - -STDMETHODIMP CAggDirectDraw::FlipToGDISurface() -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->FlipToGDISurface(); -} - - -STDMETHODIMP CAggDirectDraw::GetCaps(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetCaps(lpDDDriverCaps,lpDDHELCaps); -} - - -STDMETHODIMP CAggDirectDraw::GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetDisplayMode(lpDDSurfaceDesc); -} - - -STDMETHODIMP CAggDirectDraw::GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetFourCCCodes(lpNumCodes,lpCodes); -} - - -STDMETHODIMP CAggDirectDraw::GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetGDISurface(lplpGDIDDSurface); -} - - -STDMETHODIMP CAggDirectDraw::GetMonitorFrequency(__out LPDWORD lpdwFrequency) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetMonitorFrequency(lpdwFrequency); -} - - -STDMETHODIMP CAggDirectDraw::GetScanLine(__out LPDWORD lpdwScanLine) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetScanLine(lpdwScanLine); -} - - -STDMETHODIMP CAggDirectDraw::GetVerticalBlankStatus(__out LPBOOL lpblsInVB) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetVerticalBlankStatus(lpblsInVB); -} - - -STDMETHODIMP CAggDirectDraw::Initialize(__in GUID *lpGUID) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->Initialize(lpGUID); -} - - -STDMETHODIMP CAggDirectDraw::RestoreDisplayMode() -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->RestoreDisplayMode(); -} - - -STDMETHODIMP CAggDirectDraw::SetCooperativeLevel(HWND hWnd,DWORD dwFlags) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->SetCooperativeLevel(hWnd,dwFlags); -} - - -STDMETHODIMP CAggDirectDraw::SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->SetDisplayMode(dwWidth,dwHeight,dwBpp); -} - - -STDMETHODIMP CAggDirectDraw::WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->WaitForVerticalBlank(dwFlags,hEvent); -} - - -// Class that aggregates an IDirectDrawSurface interface. Although DirectDraw -// has the ability in its interfaces to be aggregated they're not currently -// implemented. This makes it difficult for various parts of Quartz that want -// to aggregate these interfaces. In particular the video renderer passes out -// media samples that expose IDirectDraw and IDirectDrawSurface. The filter -// graph manager also exposes IDirectDraw as a plug in distributor. For these -// objects we provide these aggregation classes that republish the interfaces - -STDMETHODIMP CAggDrawSurface::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ASSERT(m_pDirectDrawSurface); - - // Do we have this interface - - if (riid == IID_IDirectDrawSurface) { - return GetInterface((IDirectDrawSurface *)this,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid,ppv); - } -} - - -STDMETHODIMP CAggDrawSurface::AddAttachedSurface(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->AddAttachedSurface(lpDDSAttachedSurface); -} - - -STDMETHODIMP CAggDrawSurface::AddOverlayDirtyRect(__in LPRECT lpRect) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->AddOverlayDirtyRect(lpRect); -} - - -STDMETHODIMP CAggDrawSurface::Blt(__in LPRECT lpDestRect, - __in LPDIRECTDRAWSURFACE lpDDSrcSurface, - __in LPRECT lpSrcRect, - DWORD dwFlags, - __in LPDDBLTFX lpDDBltFx) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx); -} - - -STDMETHODIMP CAggDrawSurface::BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->BltBatch(lpDDBltBatch,dwCount,dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::BltFast(DWORD dwX,DWORD dwY, - __in LPDIRECTDRAWSURFACE lpDDSrcSurface, - __in LPRECT lpSrcRect, - DWORD dwTrans) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->BltFast(dwX,dwY,lpDDSrcSurface,lpSrcRect,dwTrans); -} - - -STDMETHODIMP CAggDrawSurface::DeleteAttachedSurface(DWORD dwFlags, - __in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->DeleteAttachedSurface(dwFlags,lpDDSAttachedSurface); -} - - -STDMETHODIMP CAggDrawSurface::EnumAttachedSurfaces(__in LPVOID lpContext, - __in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->EnumAttachedSurfaces(lpContext,lpEnumSurfacesCallback); -} - - -STDMETHODIMP CAggDrawSurface::EnumOverlayZOrders(DWORD dwFlags, - __in LPVOID lpContext, - __in LPDDENUMSURFACESCALLBACK lpfnCallback) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->EnumOverlayZOrders(dwFlags,lpContext,lpfnCallback); -} - - -STDMETHODIMP CAggDrawSurface::Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Flip(lpDDSurfaceTargetOverride,dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::GetAttachedSurface(__in LPDDSCAPS lpDDSCaps, - __deref_out LPDIRECTDRAWSURFACE *lplpDDAttachedSurface) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetAttachedSurface(lpDDSCaps,lplpDDAttachedSurface); -} - - -STDMETHODIMP CAggDrawSurface::GetBltStatus(DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetBltStatus(dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::GetCaps(__out LPDDSCAPS lpDDSCaps) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetCaps(lpDDSCaps); -} - - -STDMETHODIMP CAggDrawSurface::GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetClipper(lplpDDClipper); -} - - -STDMETHODIMP CAggDrawSurface::GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetColorKey(dwFlags,lpDDColorKey); -} - - -STDMETHODIMP CAggDrawSurface::GetDC(__out HDC *lphDC) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetDC(lphDC); -} - - -STDMETHODIMP CAggDrawSurface::GetFlipStatus(DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetFlipStatus(dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::GetOverlayPosition(__out LPLONG lpdwX,__out LPLONG lpdwY) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetOverlayPosition(lpdwX,lpdwY); -} - - -STDMETHODIMP CAggDrawSurface::GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetPalette(lplpDDPalette); -} - - -STDMETHODIMP CAggDrawSurface::GetPixelFormat(__out LPDDPIXELFORMAT lpDDPixelFormat) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetPixelFormat(lpDDPixelFormat); -} - - -// A bit of a warning here: Our media samples in DirectShow aggregate on -// IDirectDraw and IDirectDrawSurface (ie are available through IMediaSample -// by QueryInterface). Unfortunately the underlying DirectDraw code cannot -// be aggregated so we have to use these classes. The snag is that when we -// call a different surface and pass in this interface as perhaps the source -// surface the call will fail because DirectDraw dereferences the pointer to -// get at its private data structures. Therefore we supply this workaround to give -// access to the real IDirectDraw surface. A filter can call GetSurfaceDesc -// and we will fill in the lpSurface pointer with the real underlying surface - -STDMETHODIMP CAggDrawSurface::GetSurfaceDesc(__out LPDDSURFACEDESC lpDDSurfaceDesc) -{ - ASSERT(m_pDirectDrawSurface); - - // First call down to the underlying DirectDraw - - HRESULT hr = m_pDirectDrawSurface->GetSurfaceDesc(lpDDSurfaceDesc); - if (FAILED(hr)) { - return hr; - } - - // Store the real DirectDrawSurface interface - lpDDSurfaceDesc->lpSurface = m_pDirectDrawSurface; - return hr; -} - - -STDMETHODIMP CAggDrawSurface::Initialize(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Initialize(lpDD,lpDDSurfaceDesc); -} - - -STDMETHODIMP CAggDrawSurface::IsLost() -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->IsLost(); -} - - -STDMETHODIMP CAggDrawSurface::Lock(__in LPRECT lpDestRect, - __inout LPDDSURFACEDESC lpDDSurfaceDesc, - DWORD dwFlags, - HANDLE hEvent) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Lock(lpDestRect,lpDDSurfaceDesc,dwFlags,hEvent); -} - - -STDMETHODIMP CAggDrawSurface::ReleaseDC(HDC hDC) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->ReleaseDC(hDC); -} - - -STDMETHODIMP CAggDrawSurface::Restore() -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Restore(); -} - - -STDMETHODIMP CAggDrawSurface::SetClipper(__in LPDIRECTDRAWCLIPPER lpDDClipper) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->SetClipper(lpDDClipper); -} - - -STDMETHODIMP CAggDrawSurface::SetColorKey(DWORD dwFlags,__in LPDDCOLORKEY lpDDColorKey) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->SetColorKey(dwFlags,lpDDColorKey); -} - - -STDMETHODIMP CAggDrawSurface::SetOverlayPosition(LONG dwX,LONG dwY) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->SetOverlayPosition(dwX,dwY); -} - - -STDMETHODIMP CAggDrawSurface::SetPalette(__in LPDIRECTDRAWPALETTE lpDDPalette) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->SetPalette(lpDDPalette); -} - - -STDMETHODIMP CAggDrawSurface::Unlock(__in LPVOID lpSurfaceData) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Unlock(lpSurfaceData); -} - - -STDMETHODIMP CAggDrawSurface::UpdateOverlay(__in LPRECT lpSrcRect, - __in LPDIRECTDRAWSURFACE lpDDDestSurface, - __in LPRECT lpDestRect, - DWORD dwFlags, - __in LPDDOVERLAYFX lpDDOverlayFX) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->UpdateOverlay(lpSrcRect,lpDDDestSurface,lpDestRect,dwFlags,lpDDOverlayFX); -} - - -STDMETHODIMP CAggDrawSurface::UpdateOverlayDisplay(DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->UpdateOverlayDisplay(dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::UpdateOverlayZOrder(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSReference) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->UpdateOverlayZOrder(dwFlags,lpDDSReference); -} - - -// DirectShow must work on multiple platforms. In particular, it also runs on -// Windows NT 3.51 which does not have DirectDraw capabilities. The filters -// cannot therefore link statically to the DirectDraw library. To make their -// lives that little bit easier we provide this class that manages loading -// and unloading the library and creating the initial IDirectDraw interface - -CLoadDirectDraw::CLoadDirectDraw() : - m_pDirectDraw(NULL), - m_hDirectDraw(NULL) -{ -} - - -// Destructor forces unload - -CLoadDirectDraw::~CLoadDirectDraw() -{ - ReleaseDirectDraw(); - - if (m_hDirectDraw) { - NOTE("Unloading library"); - FreeLibrary(m_hDirectDraw); - } -} - - -// We can't be sure that DirectDraw is always available so we can't statically -// link to the library. Therefore we load the library, get the function entry -// point addresses and call them to create the driver objects. We return S_OK -// if we manage to load DirectDraw correctly otherwise we return E_NOINTERFACE -// We initialise a DirectDraw instance by explicitely loading the library and -// calling GetProcAddress on the DirectDrawCreate entry point that it exports - -// On a multi monitor system, we can get the DirectDraw object for any -// monitor (device) with the optional szDevice parameter - -HRESULT CLoadDirectDraw::LoadDirectDraw(__in LPSTR szDevice) -{ - PDRAWCREATE pDrawCreate; - PDRAWENUM pDrawEnum; - LPDIRECTDRAWENUMERATEEXA pDrawEnumEx; - - NOTE("Entering DoLoadDirectDraw"); - - // Is DirectDraw already loaded - - if (m_pDirectDraw) { - NOTE("Already loaded"); - ASSERT(m_hDirectDraw); - return NOERROR; - } - - // Make sure the library is available - - if(!m_hDirectDraw) - { - UINT ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX); - m_hDirectDraw = LoadLibrary(TEXT("ddraw.dll")); - SetErrorMode(ErrorMode); - - if (m_hDirectDraw == NULL) { - DbgLog((LOG_ERROR,1,TEXT("Can't load ddraw.dll"))); - NOTE("No library"); - return E_NOINTERFACE; - } - } - - // Get the DLL address for the creator function - - pDrawCreate = (PDRAWCREATE)GetProcAddress(m_hDirectDraw,"DirectDrawCreate"); - // force ANSI, we assume it - pDrawEnum = (PDRAWENUM)GetProcAddress(m_hDirectDraw,"DirectDrawEnumerateA"); - pDrawEnumEx = (LPDIRECTDRAWENUMERATEEXA)GetProcAddress(m_hDirectDraw, - "DirectDrawEnumerateExA"); - - // We don't NEED DirectDrawEnumerateEx, that's just for multimon stuff - if (pDrawCreate == NULL || pDrawEnum == NULL) { - DbgLog((LOG_ERROR,1,TEXT("Can't get functions: Create=%x Enum=%x"), - pDrawCreate, pDrawEnum)); - NOTE("No entry point"); - ReleaseDirectDraw(); - return E_NOINTERFACE; - } - - DbgLog((LOG_TRACE,3,TEXT("Creating DDraw for device %s"), - szDevice ? szDevice : "")); - - // Create a DirectDraw display provider for this device, using the fancy - // multimon-aware version, if it exists - if (pDrawEnumEx) - m_pDirectDraw = DirectDrawCreateFromDeviceEx(szDevice, pDrawCreate, - pDrawEnumEx); - else - m_pDirectDraw = DirectDrawCreateFromDevice(szDevice, pDrawCreate, - pDrawEnum); - - if (m_pDirectDraw == NULL) { - DbgLog((LOG_ERROR,1,TEXT("Can't create DDraw"))); - NOTE("No instance"); - ReleaseDirectDraw(); - return E_NOINTERFACE; - } - return NOERROR; -} - - -// Called to release any DirectDraw provider we previously loaded. We may be -// called at any time especially when something goes horribly wrong and when -// we need to clean up before returning so we can't guarantee that all state -// variables are consistent so free only those really allocated allocated -// This should only be called once all reference counts have been released - -void CLoadDirectDraw::ReleaseDirectDraw() -{ - NOTE("Releasing DirectDraw driver"); - - // Release any DirectDraw provider interface - - if (m_pDirectDraw) { - NOTE("Releasing instance"); - m_pDirectDraw->Release(); - m_pDirectDraw = NULL; - } - -} - - -// Return NOERROR (S_OK) if DirectDraw has been loaded by this object - -HRESULT CLoadDirectDraw::IsDirectDrawLoaded() -{ - NOTE("Entering IsDirectDrawLoaded"); - - if (m_pDirectDraw == NULL) { - NOTE("DirectDraw not loaded"); - return S_FALSE; - } - return NOERROR; -} - - -// Return the IDirectDraw interface we look after - -LPDIRECTDRAW CLoadDirectDraw::GetDirectDraw() -{ - NOTE("Entering GetDirectDraw"); - - if (m_pDirectDraw == NULL) { - NOTE("No DirectDraw"); - return NULL; - } - - NOTE("Returning DirectDraw"); - m_pDirectDraw->AddRef(); - return m_pDirectDraw; -} - - -// Are we running on Direct Draw version 1? We need to find out as -// we rely on specific bug fixes in DirectDraw 2 for fullscreen playback. To -// find out, we simply see if it supports IDirectDraw2. Only version 2 and -// higher support this. - -BOOL CLoadDirectDraw::IsDirectDrawVersion1() -{ - - if (m_pDirectDraw == NULL) - return FALSE; - - IDirectDraw2 *p = NULL; - HRESULT hr = m_pDirectDraw->QueryInterface(IID_IDirectDraw2, (void **)&p); - if (p) - p->Release(); - if (hr == NOERROR) { - DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 2 or greater"))); - return FALSE; - } else { - DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 1"))); - return TRUE; - } -} +//------------------------------------------------------------------------------ +// File: VideoCtl.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "ddmm.h" + +// Load a string from the resource file string table. The buffer must be at +// least STR_MAX_LENGTH bytes. The easiest way to use this is to declare a +// buffer in the property page class and use it for all string loading. It +// cannot be static as multiple property pages may be active simultaneously + +LPCTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID) +{ + if (LoadString(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { + return TEXT(""); + } + return pBuffer; +} + +#ifdef UNICODE +LPCSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR pBuffer, int iResourceID) +{ + if (LoadStringA(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { + return ""; + } + return pBuffer; +} +#endif + + + +// Property pages typically are called through their OLE interfaces. These +// use UNICODE strings regardless of how the binary is built. So when we +// load strings from the resource file we sometimes want to convert them +// to UNICODE. This method is passed the target UNICODE buffer and does a +// convert after loading the string (if built UNICODE this is not needed) +// On WinNT we can explicitly call LoadStringW which saves two conversions + +#ifndef UNICODE + +LPCWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR pBuffer, int iResourceID) +{ + *pBuffer = 0; + + if (g_amPlatform == VER_PLATFORM_WIN32_NT) { + LoadStringW(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH); + } else { + + CHAR szBuffer[STR_MAX_LENGTH]; + DWORD dwStringLength = LoadString(g_hInst,iResourceID,szBuffer,STR_MAX_LENGTH); + // if we loaded a string convert it to wide characters, ensuring + // that we also null terminate the result. + if (dwStringLength++) { + MultiByteToWideChar(CP_ACP,0,szBuffer,dwStringLength,pBuffer,STR_MAX_LENGTH); + } + } + return pBuffer; +} + +#endif + + +// Helper function to calculate the size of the dialog + +BOOL WINAPI GetDialogSize(int iResourceID, + DLGPROC pDlgProc, + LPARAM lParam, + __out SIZE *pResult) +{ + RECT rc; + HWND hwnd; + + // Create a temporary property page + + hwnd = CreateDialogParam(g_hInst, + MAKEINTRESOURCE(iResourceID), + GetDesktopWindow(), + pDlgProc, + lParam); + if (hwnd == NULL) { + return FALSE; + } + + GetWindowRect(hwnd, &rc); + pResult->cx = rc.right - rc.left; + pResult->cy = rc.bottom - rc.top; + + DestroyWindow(hwnd); + return TRUE; +} + + +// Class that aggregates on the IDirectDraw interface. Although DirectDraw +// has the ability in its interfaces to be aggregated they're not currently +// implemented. This makes it difficult for various parts of Quartz that want +// to aggregate these interfaces. In particular the video renderer passes out +// media samples that expose IDirectDraw and IDirectDrawSurface. The filter +// graph manager also exposes IDirectDraw as a plug in distributor. For these +// objects we provide these aggregation classes that republish the interfaces + +STDMETHODIMP CAggDirectDraw::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ASSERT(m_pDirectDraw); + + // Do we have this interface + + if (riid == IID_IDirectDraw) { + return GetInterface((IDirectDraw *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +STDMETHODIMP CAggDirectDraw::Compact() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->Compact(); +} + + +STDMETHODIMP CAggDirectDraw::CreateClipper(DWORD dwFlags, __deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper, __inout_opt IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreateClipper(dwFlags,lplpDDClipper,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::CreatePalette(DWORD dwFlags, + __in LPPALETTEENTRY lpColorTable, + __deref_out LPDIRECTDRAWPALETTE *lplpDDPalette, + __inout_opt IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreatePalette(dwFlags,lpColorTable,lplpDDPalette,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc, + __deref_out LPDIRECTDRAWSURFACE *lplpDDSurface, + __inout_opt IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreateSurface(lpDDSurfaceDesc,lplpDDSurface,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface, + __deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->DuplicateSurface(lpDDSurface,lplpDupDDSurface); +} + + +STDMETHODIMP CAggDirectDraw::EnumDisplayModes(DWORD dwSurfaceDescCount, + __in LPDDSURFACEDESC lplpDDSurfaceDescList, + __in LPVOID lpContext, + __in LPDDENUMMODESCALLBACK lpEnumCallback) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->EnumDisplayModes(dwSurfaceDescCount,lplpDDSurfaceDescList,lpContext,lpEnumCallback); +} + + +STDMETHODIMP CAggDirectDraw::EnumSurfaces(DWORD dwFlags, + __in LPDDSURFACEDESC lpDDSD, + __in LPVOID lpContext, + __in LPDDENUMSURFACESCALLBACK lpEnumCallback) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->EnumSurfaces(dwFlags,lpDDSD,lpContext,lpEnumCallback); +} + + +STDMETHODIMP CAggDirectDraw::FlipToGDISurface() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->FlipToGDISurface(); +} + + +STDMETHODIMP CAggDirectDraw::GetCaps(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetCaps(lpDDDriverCaps,lpDDHELCaps); +} + + +STDMETHODIMP CAggDirectDraw::GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetDisplayMode(lpDDSurfaceDesc); +} + + +STDMETHODIMP CAggDirectDraw::GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetFourCCCodes(lpNumCodes,lpCodes); +} + + +STDMETHODIMP CAggDirectDraw::GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetGDISurface(lplpGDIDDSurface); +} + + +STDMETHODIMP CAggDirectDraw::GetMonitorFrequency(__out LPDWORD lpdwFrequency) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetMonitorFrequency(lpdwFrequency); +} + + +STDMETHODIMP CAggDirectDraw::GetScanLine(__out LPDWORD lpdwScanLine) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetScanLine(lpdwScanLine); +} + + +STDMETHODIMP CAggDirectDraw::GetVerticalBlankStatus(__out LPBOOL lpblsInVB) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetVerticalBlankStatus(lpblsInVB); +} + + +STDMETHODIMP CAggDirectDraw::Initialize(__in GUID *lpGUID) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->Initialize(lpGUID); +} + + +STDMETHODIMP CAggDirectDraw::RestoreDisplayMode() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->RestoreDisplayMode(); +} + + +STDMETHODIMP CAggDirectDraw::SetCooperativeLevel(HWND hWnd,DWORD dwFlags) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->SetCooperativeLevel(hWnd,dwFlags); +} + + +STDMETHODIMP CAggDirectDraw::SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->SetDisplayMode(dwWidth,dwHeight,dwBpp); +} + + +STDMETHODIMP CAggDirectDraw::WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->WaitForVerticalBlank(dwFlags,hEvent); +} + + +// Class that aggregates an IDirectDrawSurface interface. Although DirectDraw +// has the ability in its interfaces to be aggregated they're not currently +// implemented. This makes it difficult for various parts of Quartz that want +// to aggregate these interfaces. In particular the video renderer passes out +// media samples that expose IDirectDraw and IDirectDrawSurface. The filter +// graph manager also exposes IDirectDraw as a plug in distributor. For these +// objects we provide these aggregation classes that republish the interfaces + +STDMETHODIMP CAggDrawSurface::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ASSERT(m_pDirectDrawSurface); + + // Do we have this interface + + if (riid == IID_IDirectDrawSurface) { + return GetInterface((IDirectDrawSurface *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +STDMETHODIMP CAggDrawSurface::AddAttachedSurface(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->AddAttachedSurface(lpDDSAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::AddOverlayDirtyRect(__in LPRECT lpRect) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->AddOverlayDirtyRect(lpRect); +} + + +STDMETHODIMP CAggDrawSurface::Blt(__in LPRECT lpDestRect, + __in LPDIRECTDRAWSURFACE lpDDSrcSurface, + __in LPRECT lpSrcRect, + DWORD dwFlags, + __in LPDDBLTFX lpDDBltFx) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx); +} + + +STDMETHODIMP CAggDrawSurface::BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->BltBatch(lpDDBltBatch,dwCount,dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::BltFast(DWORD dwX,DWORD dwY, + __in LPDIRECTDRAWSURFACE lpDDSrcSurface, + __in LPRECT lpSrcRect, + DWORD dwTrans) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->BltFast(dwX,dwY,lpDDSrcSurface,lpSrcRect,dwTrans); +} + + +STDMETHODIMP CAggDrawSurface::DeleteAttachedSurface(DWORD dwFlags, + __in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->DeleteAttachedSurface(dwFlags,lpDDSAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::EnumAttachedSurfaces(__in LPVOID lpContext, + __in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->EnumAttachedSurfaces(lpContext,lpEnumSurfacesCallback); +} + + +STDMETHODIMP CAggDrawSurface::EnumOverlayZOrders(DWORD dwFlags, + __in LPVOID lpContext, + __in LPDDENUMSURFACESCALLBACK lpfnCallback) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->EnumOverlayZOrders(dwFlags,lpContext,lpfnCallback); +} + + +STDMETHODIMP CAggDrawSurface::Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Flip(lpDDSurfaceTargetOverride,dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetAttachedSurface(__in LPDDSCAPS lpDDSCaps, + __deref_out LPDIRECTDRAWSURFACE *lplpDDAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetAttachedSurface(lpDDSCaps,lplpDDAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::GetBltStatus(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetBltStatus(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetCaps(__out LPDDSCAPS lpDDSCaps) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetCaps(lpDDSCaps); +} + + +STDMETHODIMP CAggDrawSurface::GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetClipper(lplpDDClipper); +} + + +STDMETHODIMP CAggDrawSurface::GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetColorKey(dwFlags,lpDDColorKey); +} + + +STDMETHODIMP CAggDrawSurface::GetDC(__out HDC *lphDC) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetDC(lphDC); +} + + +STDMETHODIMP CAggDrawSurface::GetFlipStatus(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetFlipStatus(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetOverlayPosition(__out LPLONG lpdwX,__out LPLONG lpdwY) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetOverlayPosition(lpdwX,lpdwY); +} + + +STDMETHODIMP CAggDrawSurface::GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetPalette(lplpDDPalette); +} + + +STDMETHODIMP CAggDrawSurface::GetPixelFormat(__out LPDDPIXELFORMAT lpDDPixelFormat) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetPixelFormat(lpDDPixelFormat); +} + + +// A bit of a warning here: Our media samples in DirectShow aggregate on +// IDirectDraw and IDirectDrawSurface (ie are available through IMediaSample +// by QueryInterface). Unfortunately the underlying DirectDraw code cannot +// be aggregated so we have to use these classes. The snag is that when we +// call a different surface and pass in this interface as perhaps the source +// surface the call will fail because DirectDraw dereferences the pointer to +// get at its private data structures. Therefore we supply this workaround to give +// access to the real IDirectDraw surface. A filter can call GetSurfaceDesc +// and we will fill in the lpSurface pointer with the real underlying surface + +STDMETHODIMP CAggDrawSurface::GetSurfaceDesc(__out LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDrawSurface); + + // First call down to the underlying DirectDraw + + HRESULT hr = m_pDirectDrawSurface->GetSurfaceDesc(lpDDSurfaceDesc); + if (FAILED(hr)) { + return hr; + } + + // Store the real DirectDrawSurface interface + lpDDSurfaceDesc->lpSurface = m_pDirectDrawSurface; + return hr; +} + + +STDMETHODIMP CAggDrawSurface::Initialize(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Initialize(lpDD,lpDDSurfaceDesc); +} + + +STDMETHODIMP CAggDrawSurface::IsLost() +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->IsLost(); +} + + +STDMETHODIMP CAggDrawSurface::Lock(__in LPRECT lpDestRect, + __inout LPDDSURFACEDESC lpDDSurfaceDesc, + DWORD dwFlags, + HANDLE hEvent) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Lock(lpDestRect,lpDDSurfaceDesc,dwFlags,hEvent); +} + + +STDMETHODIMP CAggDrawSurface::ReleaseDC(HDC hDC) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->ReleaseDC(hDC); +} + + +STDMETHODIMP CAggDrawSurface::Restore() +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Restore(); +} + + +STDMETHODIMP CAggDrawSurface::SetClipper(__in LPDIRECTDRAWCLIPPER lpDDClipper) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetClipper(lpDDClipper); +} + + +STDMETHODIMP CAggDrawSurface::SetColorKey(DWORD dwFlags,__in LPDDCOLORKEY lpDDColorKey) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetColorKey(dwFlags,lpDDColorKey); +} + + +STDMETHODIMP CAggDrawSurface::SetOverlayPosition(LONG dwX,LONG dwY) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetOverlayPosition(dwX,dwY); +} + + +STDMETHODIMP CAggDrawSurface::SetPalette(__in LPDIRECTDRAWPALETTE lpDDPalette) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetPalette(lpDDPalette); +} + + +STDMETHODIMP CAggDrawSurface::Unlock(__in LPVOID lpSurfaceData) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Unlock(lpSurfaceData); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlay(__in LPRECT lpSrcRect, + __in LPDIRECTDRAWSURFACE lpDDDestSurface, + __in LPRECT lpDestRect, + DWORD dwFlags, + __in LPDDOVERLAYFX lpDDOverlayFX) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlay(lpSrcRect,lpDDDestSurface,lpDestRect,dwFlags,lpDDOverlayFX); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlayDisplay(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlayDisplay(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlayZOrder(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSReference) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlayZOrder(dwFlags,lpDDSReference); +} + + +// DirectShow must work on multiple platforms. In particular, it also runs on +// Windows NT 3.51 which does not have DirectDraw capabilities. The filters +// cannot therefore link statically to the DirectDraw library. To make their +// lives that little bit easier we provide this class that manages loading +// and unloading the library and creating the initial IDirectDraw interface + +CLoadDirectDraw::CLoadDirectDraw() : + m_pDirectDraw(NULL), + m_hDirectDraw(NULL) +{ +} + + +// Destructor forces unload + +CLoadDirectDraw::~CLoadDirectDraw() +{ + ReleaseDirectDraw(); + + if (m_hDirectDraw) { + NOTE("Unloading library"); + FreeLibrary(m_hDirectDraw); + } +} + + +// We can't be sure that DirectDraw is always available so we can't statically +// link to the library. Therefore we load the library, get the function entry +// point addresses and call them to create the driver objects. We return S_OK +// if we manage to load DirectDraw correctly otherwise we return E_NOINTERFACE +// We initialise a DirectDraw instance by explicitely loading the library and +// calling GetProcAddress on the DirectDrawCreate entry point that it exports + +// On a multi monitor system, we can get the DirectDraw object for any +// monitor (device) with the optional szDevice parameter + +HRESULT CLoadDirectDraw::LoadDirectDraw(__in LPSTR szDevice) +{ + PDRAWCREATE pDrawCreate; + PDRAWENUM pDrawEnum; + LPDIRECTDRAWENUMERATEEXA pDrawEnumEx; + + NOTE("Entering DoLoadDirectDraw"); + + // Is DirectDraw already loaded + + if (m_pDirectDraw) { + NOTE("Already loaded"); + ASSERT(m_hDirectDraw); + return NOERROR; + } + + // Make sure the library is available + + if(!m_hDirectDraw) + { + UINT ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX); + m_hDirectDraw = LoadLibrary(TEXT("ddraw.dll")); + SetErrorMode(ErrorMode); + + if (m_hDirectDraw == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't load ddraw.dll"))); + NOTE("No library"); + return E_NOINTERFACE; + } + } + + // Get the DLL address for the creator function + + pDrawCreate = (PDRAWCREATE)GetProcAddress(m_hDirectDraw,"DirectDrawCreate"); + // force ANSI, we assume it + pDrawEnum = (PDRAWENUM)GetProcAddress(m_hDirectDraw,"DirectDrawEnumerateA"); + pDrawEnumEx = (LPDIRECTDRAWENUMERATEEXA)GetProcAddress(m_hDirectDraw, + "DirectDrawEnumerateExA"); + + // We don't NEED DirectDrawEnumerateEx, that's just for multimon stuff + if (pDrawCreate == NULL || pDrawEnum == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't get functions: Create=%x Enum=%x"), + pDrawCreate, pDrawEnum)); + NOTE("No entry point"); + ReleaseDirectDraw(); + return E_NOINTERFACE; + } + + DbgLog((LOG_TRACE,3,TEXT("Creating DDraw for device %s"), + szDevice ? szDevice : "")); + + // Create a DirectDraw display provider for this device, using the fancy + // multimon-aware version, if it exists + if (pDrawEnumEx) + m_pDirectDraw = DirectDrawCreateFromDeviceEx(szDevice, pDrawCreate, + pDrawEnumEx); + else + m_pDirectDraw = DirectDrawCreateFromDevice(szDevice, pDrawCreate, + pDrawEnum); + + if (m_pDirectDraw == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't create DDraw"))); + NOTE("No instance"); + ReleaseDirectDraw(); + return E_NOINTERFACE; + } + return NOERROR; +} + + +// Called to release any DirectDraw provider we previously loaded. We may be +// called at any time especially when something goes horribly wrong and when +// we need to clean up before returning so we can't guarantee that all state +// variables are consistent so free only those really allocated allocated +// This should only be called once all reference counts have been released + +void CLoadDirectDraw::ReleaseDirectDraw() +{ + NOTE("Releasing DirectDraw driver"); + + // Release any DirectDraw provider interface + + if (m_pDirectDraw) { + NOTE("Releasing instance"); + m_pDirectDraw->Release(); + m_pDirectDraw = NULL; + } + +} + + +// Return NOERROR (S_OK) if DirectDraw has been loaded by this object + +HRESULT CLoadDirectDraw::IsDirectDrawLoaded() +{ + NOTE("Entering IsDirectDrawLoaded"); + + if (m_pDirectDraw == NULL) { + NOTE("DirectDraw not loaded"); + return S_FALSE; + } + return NOERROR; +} + + +// Return the IDirectDraw interface we look after + +LPDIRECTDRAW CLoadDirectDraw::GetDirectDraw() +{ + NOTE("Entering GetDirectDraw"); + + if (m_pDirectDraw == NULL) { + NOTE("No DirectDraw"); + return NULL; + } + + NOTE("Returning DirectDraw"); + m_pDirectDraw->AddRef(); + return m_pDirectDraw; +} + + +// Are we running on Direct Draw version 1? We need to find out as +// we rely on specific bug fixes in DirectDraw 2 for fullscreen playback. To +// find out, we simply see if it supports IDirectDraw2. Only version 2 and +// higher support this. + +BOOL CLoadDirectDraw::IsDirectDrawVersion1() +{ + + if (m_pDirectDraw == NULL) + return FALSE; + + IDirectDraw2 *p = NULL; + HRESULT hr = m_pDirectDraw->QueryInterface(IID_IDirectDraw2, (void **)&p); + if (p) + p->Release(); + if (hr == NOERROR) { + DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 2 or greater"))); + return FALSE; + } else { + DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 1"))); + return TRUE; + } +} diff --git a/src/thirdparty/BaseClasses/videoctl.h b/src/thirdparty/BaseClasses/videoctl.h index aa74d79e872..a9713202675 100644 --- a/src/thirdparty/BaseClasses/videoctl.h +++ b/src/thirdparty/BaseClasses/videoctl.h @@ -1,168 +1,168 @@ -//------------------------------------------------------------------------------ -// File: VideoCtl.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __VIDEOCTL__ -#define __VIDEOCTL__ - -// These help with property page implementations. The first can be used to -// load any string from a resource file. The buffer to load into is passed -// as an input parameter. The same buffer is the return value if the string -// was found otherwise it returns TEXT(""). The GetDialogSize is passed the -// resource ID of a dialog box and returns the size of it in screen pixels - -#define STR_MAX_LENGTH 256 -LPCTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID); - -#ifdef UNICODE -#define WideStringFromResource StringFromResource -LPCSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR pBuffer, int iResourceID); -#else -LPCWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR pBuffer, int iResourceID); -#endif - - -BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier - DLGPROC pDlgProc, // Pointer to dialog procedure - LPARAM lParam, // Any user data wanted in pDlgProc - __out SIZE *pResult);// Returns the size of dialog box - -// Class that aggregates an IDirectDraw interface - -class CAggDirectDraw : public IDirectDraw, public CUnknown -{ -protected: - - LPDIRECTDRAW m_pDirectDraw; - -public: - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); - - // Constructor and destructor - - CAggDirectDraw(__in_opt LPCTSTR pName,__inout_opt LPUNKNOWN pUnk) : - CUnknown(pName,pUnk), - m_pDirectDraw(NULL) { }; - - virtual ~CAggDirectDraw() { }; - - // Set the object we should be aggregating - void SetDirectDraw(__inout LPDIRECTDRAW pDirectDraw) { - m_pDirectDraw = pDirectDraw; - } - - // IDirectDraw methods - - STDMETHODIMP Compact(); - STDMETHODIMP CreateClipper(DWORD dwFlags,__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper,__inout_opt IUnknown *pUnkOuter); - STDMETHODIMP CreatePalette(DWORD dwFlags,__in LPPALETTEENTRY lpColorTable,__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette,__inout_opt IUnknown *pUnkOuter); - STDMETHODIMP CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc,__deref_out LPDIRECTDRAWSURFACE *lplpDDSurface,__inout_opt IUnknown *pUnkOuter); - STDMETHODIMP DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface,__deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface); - STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,__in LPDDSURFACEDESC lplpDDSurfaceDescList,__in LPVOID lpContext,__in LPDDENUMMODESCALLBACK lpEnumCallback); - STDMETHODIMP EnumSurfaces(DWORD dwFlags,__in LPDDSURFACEDESC lpDDSD,__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpEnumCallback); - STDMETHODIMP FlipToGDISurface(); - STDMETHODIMP GetCaps(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps); - STDMETHODIMP GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc); - STDMETHODIMP GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes); - STDMETHODIMP GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface); - STDMETHODIMP GetMonitorFrequency(__out LPDWORD lpdwFrequency); - STDMETHODIMP GetScanLine(__out LPDWORD lpdwScanLine); - STDMETHODIMP GetVerticalBlankStatus(__out LPBOOL lpblsInVB); - STDMETHODIMP Initialize(__in GUID *lpGUID); - STDMETHODIMP RestoreDisplayMode(); - STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags); - STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp); - STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent); -}; - - -// Class that aggregates an IDirectDrawSurface interface - -class CAggDrawSurface : public IDirectDrawSurface, public CUnknown -{ -protected: - - LPDIRECTDRAWSURFACE m_pDirectDrawSurface; - -public: - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); - - // Constructor and destructor - - CAggDrawSurface(__in_opt LPCTSTR pName,__inout_opt LPUNKNOWN pUnk) : - CUnknown(pName,pUnk), - m_pDirectDrawSurface(NULL) { }; - - virtual ~CAggDrawSurface() { }; - - // Set the object we should be aggregating - void SetDirectDrawSurface(__inout LPDIRECTDRAWSURFACE pDirectDrawSurface) { - m_pDirectDrawSurface = pDirectDrawSurface; - } - - // IDirectDrawSurface methods - - STDMETHODIMP AddAttachedSurface(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface); - STDMETHODIMP AddOverlayDirtyRect(__in LPRECT lpRect); - STDMETHODIMP Blt(__in LPRECT lpDestRect,__in LPDIRECTDRAWSURFACE lpDDSrcSurface,__in LPRECT lpSrcRect,DWORD dwFlags,__in LPDDBLTFX lpDDBltFx); - STDMETHODIMP BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags); - STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,__in LPDIRECTDRAWSURFACE lpDDSrcSurface,__in LPRECT lpSrcRect,DWORD dwTrans); - STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface); - STDMETHODIMP EnumAttachedSurfaces(__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback); - STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpfnCallback); - STDMETHODIMP Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags); - STDMETHODIMP GetAttachedSurface(__in LPDDSCAPS lpDDSCaps,__deref_out LPDIRECTDRAWSURFACE *lplpDDAttachedSurface); - STDMETHODIMP GetBltStatus(DWORD dwFlags); - STDMETHODIMP GetCaps(__out LPDDSCAPS lpDDSCaps); - STDMETHODIMP GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper); - STDMETHODIMP GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey); - STDMETHODIMP GetDC(__out HDC *lphDC); - STDMETHODIMP GetFlipStatus(DWORD dwFlags); - STDMETHODIMP GetOverlayPosition(__out LPLONG lpdwX,__out LPLONG lpdwY); - STDMETHODIMP GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette); - STDMETHODIMP GetPixelFormat(__out LPDDPIXELFORMAT lpDDPixelFormat); - STDMETHODIMP GetSurfaceDesc(__out LPDDSURFACEDESC lpDDSurfaceDesc); - STDMETHODIMP Initialize(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc); - STDMETHODIMP IsLost(); - STDMETHODIMP Lock(__in LPRECT lpDestRect,__inout LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent); - STDMETHODIMP ReleaseDC(HDC hDC); - STDMETHODIMP Restore(); - STDMETHODIMP SetClipper(__in LPDIRECTDRAWCLIPPER lpDDClipper); - STDMETHODIMP SetColorKey(DWORD dwFlags,__in LPDDCOLORKEY lpDDColorKey); - STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY); - STDMETHODIMP SetPalette(__in LPDIRECTDRAWPALETTE lpDDPalette); - STDMETHODIMP Unlock(__in LPVOID lpSurfaceData); - STDMETHODIMP UpdateOverlay(__in LPRECT lpSrcRect,__in LPDIRECTDRAWSURFACE lpDDDestSurface,__in LPRECT lpDestRect,DWORD dwFlags,__in LPDDOVERLAYFX lpDDOverlayFX); - STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags); - STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSReference); -}; - - -class CLoadDirectDraw -{ - LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance - HINSTANCE m_hDirectDraw; // Handle to the loaded library - -public: - - CLoadDirectDraw(); - ~CLoadDirectDraw(); - - HRESULT LoadDirectDraw(__in LPSTR szDevice); - void ReleaseDirectDraw(); - HRESULT IsDirectDrawLoaded(); - LPDIRECTDRAW GetDirectDraw(); - BOOL IsDirectDrawVersion1(); -}; - -#endif // __VIDEOCTL__ - +//------------------------------------------------------------------------------ +// File: VideoCtl.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __VIDEOCTL__ +#define __VIDEOCTL__ + +// These help with property page implementations. The first can be used to +// load any string from a resource file. The buffer to load into is passed +// as an input parameter. The same buffer is the return value if the string +// was found otherwise it returns TEXT(""). The GetDialogSize is passed the +// resource ID of a dialog box and returns the size of it in screen pixels + +#define STR_MAX_LENGTH 256 +LPCTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID); + +#ifdef UNICODE +#define WideStringFromResource StringFromResource +LPCSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR pBuffer, int iResourceID); +#else +LPCWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR pBuffer, int iResourceID); +#endif + + +BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier + DLGPROC pDlgProc, // Pointer to dialog procedure + LPARAM lParam, // Any user data wanted in pDlgProc + __out SIZE *pResult);// Returns the size of dialog box + +// Class that aggregates an IDirectDraw interface + +class CAggDirectDraw : public IDirectDraw, public CUnknown +{ +protected: + + LPDIRECTDRAW m_pDirectDraw; + +public: + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); + + // Constructor and destructor + + CAggDirectDraw(__in_opt LPCTSTR pName,__inout_opt LPUNKNOWN pUnk) : + CUnknown(pName,pUnk), + m_pDirectDraw(NULL) { }; + + virtual ~CAggDirectDraw() { }; + + // Set the object we should be aggregating + void SetDirectDraw(__inout LPDIRECTDRAW pDirectDraw) { + m_pDirectDraw = pDirectDraw; + } + + // IDirectDraw methods + + STDMETHODIMP Compact(); + STDMETHODIMP CreateClipper(DWORD dwFlags,__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper,__inout_opt IUnknown *pUnkOuter); + STDMETHODIMP CreatePalette(DWORD dwFlags,__in LPPALETTEENTRY lpColorTable,__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette,__inout_opt IUnknown *pUnkOuter); + STDMETHODIMP CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc,__deref_out LPDIRECTDRAWSURFACE *lplpDDSurface,__inout_opt IUnknown *pUnkOuter); + STDMETHODIMP DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface,__deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface); + STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,__in LPDDSURFACEDESC lplpDDSurfaceDescList,__in LPVOID lpContext,__in LPDDENUMMODESCALLBACK lpEnumCallback); + STDMETHODIMP EnumSurfaces(DWORD dwFlags,__in LPDDSURFACEDESC lpDDSD,__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpEnumCallback); + STDMETHODIMP FlipToGDISurface(); + STDMETHODIMP GetCaps(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps); + STDMETHODIMP GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes); + STDMETHODIMP GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface); + STDMETHODIMP GetMonitorFrequency(__out LPDWORD lpdwFrequency); + STDMETHODIMP GetScanLine(__out LPDWORD lpdwScanLine); + STDMETHODIMP GetVerticalBlankStatus(__out LPBOOL lpblsInVB); + STDMETHODIMP Initialize(__in GUID *lpGUID); + STDMETHODIMP RestoreDisplayMode(); + STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags); + STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp); + STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent); +}; + + +// Class that aggregates an IDirectDrawSurface interface + +class CAggDrawSurface : public IDirectDrawSurface, public CUnknown +{ +protected: + + LPDIRECTDRAWSURFACE m_pDirectDrawSurface; + +public: + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); + + // Constructor and destructor + + CAggDrawSurface(__in_opt LPCTSTR pName,__inout_opt LPUNKNOWN pUnk) : + CUnknown(pName,pUnk), + m_pDirectDrawSurface(NULL) { }; + + virtual ~CAggDrawSurface() { }; + + // Set the object we should be aggregating + void SetDirectDrawSurface(__inout LPDIRECTDRAWSURFACE pDirectDrawSurface) { + m_pDirectDrawSurface = pDirectDrawSurface; + } + + // IDirectDrawSurface methods + + STDMETHODIMP AddAttachedSurface(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface); + STDMETHODIMP AddOverlayDirtyRect(__in LPRECT lpRect); + STDMETHODIMP Blt(__in LPRECT lpDestRect,__in LPDIRECTDRAWSURFACE lpDDSrcSurface,__in LPRECT lpSrcRect,DWORD dwFlags,__in LPDDBLTFX lpDDBltFx); + STDMETHODIMP BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags); + STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,__in LPDIRECTDRAWSURFACE lpDDSrcSurface,__in LPRECT lpSrcRect,DWORD dwTrans); + STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface); + STDMETHODIMP EnumAttachedSurfaces(__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback); + STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpfnCallback); + STDMETHODIMP Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags); + STDMETHODIMP GetAttachedSurface(__in LPDDSCAPS lpDDSCaps,__deref_out LPDIRECTDRAWSURFACE *lplpDDAttachedSurface); + STDMETHODIMP GetBltStatus(DWORD dwFlags); + STDMETHODIMP GetCaps(__out LPDDSCAPS lpDDSCaps); + STDMETHODIMP GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper); + STDMETHODIMP GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey); + STDMETHODIMP GetDC(__out HDC *lphDC); + STDMETHODIMP GetFlipStatus(DWORD dwFlags); + STDMETHODIMP GetOverlayPosition(__out LPLONG lpdwX,__out LPLONG lpdwY); + STDMETHODIMP GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette); + STDMETHODIMP GetPixelFormat(__out LPDDPIXELFORMAT lpDDPixelFormat); + STDMETHODIMP GetSurfaceDesc(__out LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP Initialize(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP IsLost(); + STDMETHODIMP Lock(__in LPRECT lpDestRect,__inout LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent); + STDMETHODIMP ReleaseDC(HDC hDC); + STDMETHODIMP Restore(); + STDMETHODIMP SetClipper(__in LPDIRECTDRAWCLIPPER lpDDClipper); + STDMETHODIMP SetColorKey(DWORD dwFlags,__in LPDDCOLORKEY lpDDColorKey); + STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY); + STDMETHODIMP SetPalette(__in LPDIRECTDRAWPALETTE lpDDPalette); + STDMETHODIMP Unlock(__in LPVOID lpSurfaceData); + STDMETHODIMP UpdateOverlay(__in LPRECT lpSrcRect,__in LPDIRECTDRAWSURFACE lpDDDestSurface,__in LPRECT lpDestRect,DWORD dwFlags,__in LPDDOVERLAYFX lpDDOverlayFX); + STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags); + STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSReference); +}; + + +class CLoadDirectDraw +{ + LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance + HINSTANCE m_hDirectDraw; // Handle to the loaded library + +public: + + CLoadDirectDraw(); + ~CLoadDirectDraw(); + + HRESULT LoadDirectDraw(__in LPSTR szDevice); + void ReleaseDirectDraw(); + HRESULT IsDirectDrawLoaded(); + LPDIRECTDRAW GetDirectDraw(); + BOOL IsDirectDrawVersion1(); +}; + +#endif // __VIDEOCTL__ + diff --git a/src/thirdparty/BaseClasses/vtrans.cpp b/src/thirdparty/BaseClasses/vtrans.cpp index e20e4836001..28cd234ea1e 100644 --- a/src/thirdparty/BaseClasses/vtrans.cpp +++ b/src/thirdparty/BaseClasses/vtrans.cpp @@ -1,469 +1,469 @@ -//------------------------------------------------------------------------------ -// File: Vtrans.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "measure.h" -// #include // now in precomp file streams.h - -CVideoTransformFilter::CVideoTransformFilter - ( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, REFCLSID clsid) - : CTransformFilter(pName, pUnk, clsid) - , m_itrLate(0) - , m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames - , m_nFramesSinceKeyFrame(0) - , m_bSkipping(FALSE) - , m_tDecodeStart(0) - , m_itrAvgDecode(300000) // 30mSec - probably allows skipping - , m_bQualityChanged(FALSE) - , m_nWaitForKey(0) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} - - -CVideoTransformFilter::~CVideoTransformFilter() -{ - // nothing to do -} - - -// Reset our quality management state - -HRESULT CVideoTransformFilter::StartStreaming() -{ - m_itrLate = 0; - m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames - m_nFramesSinceKeyFrame = 0; - m_bSkipping = FALSE; - m_tDecodeStart = 0; - m_itrAvgDecode = 300000; // 30mSec - probably allows skipping - m_bQualityChanged = FALSE; - m_bSampleSkipped = FALSE; - return NOERROR; -} - - -// Overriden to reset quality management information - -HRESULT CVideoTransformFilter::EndFlush() -{ - { - // Synchronize - CAutoLock lck(&m_csReceive); - - // Reset our stats - // - // Note - we don't want to call derived classes here, - // we only want to reset our internal variables and this - // is a convenient way to do it - CVideoTransformFilter::StartStreaming(); - } - return CTransformFilter::EndFlush(); -} - - -HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) -{ - NotifyEvent(EC_ERRORABORT, hr, 0); - m_pOutput->DeliverEndOfStream(); - return hr; -} - - -// Receive() -// -// Accept a sample from upstream, decide whether to process it -// or drop it. If we process it then get a buffer from the -// allocator of the downstream connection, transform it into the -// new buffer and deliver it to the downstream filter. -// If we decide not to process it then we do not get a buffer. - -// Remember that although this code will notice format changes coming into -// the input pin, it will NOT change its output format if that results -// in the filter needing to make a corresponding output format change. Your -// derived filter will have to take care of that. (eg. a palette change if -// the input and output is an 8 bit format). If the input sample is discarded -// and nothing is sent out for this Receive, please remember to put the format -// change on the first output sample that you actually do send. -// If your filter will produce the same output type even when the input type -// changes, then this base class code will do everything you need. - -HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) -{ - // If the next filter downstream is the video renderer, then it may - // be able to operate in DirectDraw mode which saves copying the data - // and gives higher performance. In that case the buffer which we - // get from GetDeliveryBuffer will be a DirectDraw buffer, and - // drawing into this buffer draws directly onto the display surface. - // This means that any waiting for the correct time to draw occurs - // during GetDeliveryBuffer, and that once the buffer is given to us - // the video renderer will count it in its statistics as a frame drawn. - // This means that any decision to drop the frame must be taken before - // calling GetDeliveryBuffer. - - ASSERT(CritCheckIn(&m_csReceive)); - AM_MEDIA_TYPE *pmtOut, *pmt; -#ifdef _DEBUG - FOURCCMap fccOut; -#endif - HRESULT hr; - ASSERT(pSample); - IMediaSample * pOutSample; - - // If no output pin to deliver to then no point sending us data - ASSERT (m_pOutput != NULL) ; - - // The source filter may dynamically ask us to start transforming from a - // different media type than the one we're using now. If we don't, we'll - // draw garbage. (typically, this is a palette change in the movie, - // but could be something more sinister like the compression type changing, - // or even the video size changing) - -#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource -#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget - - pSample->GetMediaType(&pmt); - if (pmt != NULL && pmt->pbFormat != NULL) { - - // spew some debug output - ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); -#ifdef _DEBUG - fccOut.SetFOURCC(&pmt->subtype); - LONG lCompression = HEADER(pmt->pbFormat)->biCompression; - LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; - LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; - lStride = (lStride + 3) & ~3; - DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); - DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), - fccOut.GetFOURCC(), lCompression, lBitCount)); - DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), - HEADER(pmt->pbFormat)->biHeight, - rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); - DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), - rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, - lStride)); -#endif - - // now switch to using the new format. I am assuming that the - // derived filter will do the right thing when its media type is - // switched and streaming is restarted. - - StopStreaming(); - m_pInput->CurrentMediaType() = *pmt; - DeleteMediaType(pmt); - // if this fails, playback will stop, so signal an error - hr = StartStreaming(); - if (FAILED(hr)) { - return AbortPlayback(hr); - } - } - - // Now that we have noticed any format changes on the input sample, it's - // OK to discard it. - - if (ShouldSkipFrame(pSample)) { - MSR_NOTE(m_idSkip); - m_bSampleSkipped = TRUE; - return NOERROR; - } - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - m_bSampleSkipped = FALSE; - - // The renderer may ask us to on-the-fly to start transforming to a - // different format. If we don't obey it, we'll draw garbage - -#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource -#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget - - pOutSample->GetMediaType(&pmtOut); - if (pmtOut != NULL && pmtOut->pbFormat != NULL) { - - // spew some debug output - ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); -#ifdef _DEBUG - fccOut.SetFOURCC(&pmtOut->subtype); - LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; - LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; - LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; - lStride = (lStride + 3) & ~3; - DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); - DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), - fccOut.GetFOURCC(), lCompression, lBitCount)); - DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), - HEADER(pmtOut->pbFormat)->biHeight, - rcT.left, rcT.top, rcT.right, rcT.bottom)); - DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), - rcS.left, rcS.top, rcS.right, rcS.bottom, - lStride)); -#endif - - // now switch to using the new format. I am assuming that the - // derived filter will do the right thing when its media type is - // switched and streaming is restarted. - - StopStreaming(); - m_pOutput->CurrentMediaType() = *pmtOut; - DeleteMediaType(pmtOut); - hr = StartStreaming(); - - if (SUCCEEDED(hr)) { - // a new format, means a new empty buffer, so wait for a keyframe - // before passing anything on to the renderer. - // !!! a keyframe may never come, so give up after 30 frames - DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); - m_nWaitForKey = 30; - - // if this fails, playback will stop, so signal an error - } else { - - // Must release the sample before calling AbortPlayback - // because we might be holding the win16 lock or - // ddraw lock - pOutSample->Release(); - AbortPlayback(hr); - return hr; - } - } - - // After a discontinuity, we need to wait for the next key frame - if (pSample->IsDiscontinuity() == S_OK) { - DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); - m_nWaitForKey = 30; - } - - // Start timing the transform (and log it if PERF is defined) - - if (SUCCEEDED(hr)) { - m_tDecodeStart = timeGetTime(); - MSR_START(m_idTransform); - - // have the derived class transform the data - hr = Transform(pSample, pOutSample); - - // Stop the clock (and log it if PERF is defined) - MSR_STOP(m_idTransform); - m_tDecodeStart = timeGetTime()-m_tDecodeStart; - m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); - - // Maybe we're waiting for a keyframe still? - if (m_nWaitForKey) - m_nWaitForKey--; - if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) - m_nWaitForKey = FALSE; - - // if so, then we don't want to pass this on to the renderer - if (m_nWaitForKey && hr == NOERROR) { - DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); - hr = S_FALSE; - } - } - - if (FAILED(hr)) { - DbgLog((LOG_TRACE,1,TEXT("Error from video transform"))); - } else { - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - // Try not to return S_FALSE to a direct draw buffer (it's wasteful) - // Try to take the decision earlier - before you get it. - - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pOutSample); - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this case because returning S_FALSE - // from Receive() means that this is the end of the stream and no more data should - // be sent. - if (S_FALSE == hr) { - - // We must Release() the sample before doing anything - // like calling the filter graph because having the - // sample means we may have the DirectDraw lock - // (== win16 lock on some versions) - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - m_bQualityChanged = TRUE; - NotifyEvent(EC_QUALITY_CHANGE,0,0); - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - ASSERT(CritCheckIn(&m_csReceive)); - - return hr; -} - - - -BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) -{ - REFERENCE_TIME trStart, trStopAt; - HRESULT hr = pIn->GetTime(&trStart, &trStopAt); - - // Don't skip frames with no timestamps - if (hr != S_OK) - return FALSE; - - int itrFrame = (int)(trStopAt - trStart); // frame duration - - if(S_OK==pIn->IsSyncPoint()) { - MSR_INTEGER(m_idFrameType, 1); - if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) { - // record the max - m_nKeyFramePeriod = m_nFramesSinceKeyFrame; - } - m_nFramesSinceKeyFrame = 0; - m_bSkipping = FALSE; - } else { - MSR_INTEGER(m_idFrameType, 2); - if ( m_nFramesSinceKeyFrame>m_nKeyFramePeriod - && m_nKeyFramePeriod>0 - ) { - // We haven't seen the key frame yet, but we were clearly being - // overoptimistic about how frequent they are. - m_nKeyFramePeriod = m_nFramesSinceKeyFrame; - } - } - - - // Whatever we might otherwise decide, - // if we are taking only a small fraction of the required frame time to decode - // then any quality problems are actually coming from somewhere else. - // Could be a net problem at the source for instance. In this case there's - // no point in us skipping frames here. - if (m_itrAvgDecode*4>itrFrame) { - - // Don't skip unless we are at least a whole frame late. - // (We would skip B frames if more than 1/2 frame late, but they're safe). - if ( m_itrLate > itrFrame ) { - - // Don't skip unless the anticipated key frame would be no more than - // 1 frame early. If the renderer has not been waiting (we *guess* - // it hasn't because we're late) then it will allow frames to be - // played early by up to a frame. - - // Let T = Stream time from now to anticipated next key frame - // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame) - // So we skip if T - Late < one frame i.e. - // (duration) * (freq - FramesSince) - Late < duration - // or (duration) * (freq - FramesSince - 1) < Late - - // We don't dare skip until we have seen some key frames and have - // some idea how often they occur and they are reasonably frequent. - if (m_nKeyFramePeriod>0) { - // It would be crazy - but we could have a stream with key frames - // a very long way apart - and if they are further than about - // 3.5 minutes apart then we could get arithmetic overflow in - // reference time units. Therefore we switch to mSec at this point - int it = (itrFrame/10000) - * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1); - MSR_INTEGER(m_idTimeTillKey, it); - - // For debug - might want to see the details - dump them as scratch pad -#ifdef VTRANSPERF - MSR_INTEGER(0, itrFrame); - MSR_INTEGER(0, m_nFramesSinceKeyFrame); - MSR_INTEGER(0, m_nKeyFramePeriod); -#endif - if (m_itrLate/10000 > it) { - m_bSkipping = TRUE; - // Now we are committed. Once we start skipping, we - // cannot stop until we hit a key frame. - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777770); // not near enough to next key -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777771); // Next key not predictable -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777772); // Less than one frame late - MSR_INTEGER(0, m_itrLate); - MSR_INTEGER(0, itrFrame); -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping - MSR_INTEGER(0, m_itrAvgDecode); - MSR_INTEGER(0, itrFrame); -#endif - } - - ++m_nFramesSinceKeyFrame; - - if (m_bSkipping) { - // We will count down the lateness as we skip each frame. - // We re-assess each frame. The key frame might not arrive when expected. - // We reset m_itrLate if we get a new Quality message, but actually that's - // not likely because we're not sending frames on to the Renderer. In - // fact if we DID get another one it would mean that there's a long - // pipe between us and the renderer and we might need an altogether - // better strategy to avoid hunting! - m_itrLate = m_itrLate - itrFrame; - } - - MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are - if (m_bSkipping) { - if (!m_bQualityChanged) { - m_bQualityChanged = TRUE; - NotifyEvent(EC_QUALITY_CHANGE,0,0); - } - } - return m_bSkipping; -} - - -HRESULT CVideoTransformFilter::AlterQuality(Quality q) -{ - // to reduce the amount of 64 bit arithmetic, m_itrLate is an int. - // +, -, >, == etc are not too bad, but * and / are painful. - if (m_itrLate>300000000) { - // Avoid overflow and silliness - more than 30 secs late is already silly - m_itrLate = 300000000; - } else { - m_itrLate = (int)q.Late; - } - // We ignore the other fields - - // We're actually not very good at handling this. In non-direct draw mode - // most of the time can be spent in the renderer which can skip any frame. - // In that case we'd rather the renderer handled things. - // Nevertheless we will keep an eye on it and if we really start getting - // a very long way behind then we will actually skip - but we'll still tell - // the renderer (or whoever is downstream) that they should handle quality. - - return E_FAIL; // Tell the renderer to do his thing. - -} - - - -// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4 -#pragma warning(disable:4514) - +//------------------------------------------------------------------------------ +// File: Vtrans.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "measure.h" +// #include // now in precomp file streams.h + +CVideoTransformFilter::CVideoTransformFilter + ( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, REFCLSID clsid) + : CTransformFilter(pName, pUnk, clsid) + , m_itrLate(0) + , m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames + , m_nFramesSinceKeyFrame(0) + , m_bSkipping(FALSE) + , m_tDecodeStart(0) + , m_itrAvgDecode(300000) // 30mSec - probably allows skipping + , m_bQualityChanged(FALSE) + , m_nWaitForKey(0) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} + + +CVideoTransformFilter::~CVideoTransformFilter() +{ + // nothing to do +} + + +// Reset our quality management state + +HRESULT CVideoTransformFilter::StartStreaming() +{ + m_itrLate = 0; + m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames + m_nFramesSinceKeyFrame = 0; + m_bSkipping = FALSE; + m_tDecodeStart = 0; + m_itrAvgDecode = 300000; // 30mSec - probably allows skipping + m_bQualityChanged = FALSE; + m_bSampleSkipped = FALSE; + return NOERROR; +} + + +// Overriden to reset quality management information + +HRESULT CVideoTransformFilter::EndFlush() +{ + { + // Synchronize + CAutoLock lck(&m_csReceive); + + // Reset our stats + // + // Note - we don't want to call derived classes here, + // we only want to reset our internal variables and this + // is a convenient way to do it + CVideoTransformFilter::StartStreaming(); + } + return CTransformFilter::EndFlush(); +} + + +HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) +{ + NotifyEvent(EC_ERRORABORT, hr, 0); + m_pOutput->DeliverEndOfStream(); + return hr; +} + + +// Receive() +// +// Accept a sample from upstream, decide whether to process it +// or drop it. If we process it then get a buffer from the +// allocator of the downstream connection, transform it into the +// new buffer and deliver it to the downstream filter. +// If we decide not to process it then we do not get a buffer. + +// Remember that although this code will notice format changes coming into +// the input pin, it will NOT change its output format if that results +// in the filter needing to make a corresponding output format change. Your +// derived filter will have to take care of that. (eg. a palette change if +// the input and output is an 8 bit format). If the input sample is discarded +// and nothing is sent out for this Receive, please remember to put the format +// change on the first output sample that you actually do send. +// If your filter will produce the same output type even when the input type +// changes, then this base class code will do everything you need. + +HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) +{ + // If the next filter downstream is the video renderer, then it may + // be able to operate in DirectDraw mode which saves copying the data + // and gives higher performance. In that case the buffer which we + // get from GetDeliveryBuffer will be a DirectDraw buffer, and + // drawing into this buffer draws directly onto the display surface. + // This means that any waiting for the correct time to draw occurs + // during GetDeliveryBuffer, and that once the buffer is given to us + // the video renderer will count it in its statistics as a frame drawn. + // This means that any decision to drop the frame must be taken before + // calling GetDeliveryBuffer. + + ASSERT(CritCheckIn(&m_csReceive)); + AM_MEDIA_TYPE *pmtOut, *pmt; +#ifdef _DEBUG + FOURCCMap fccOut; +#endif + HRESULT hr; + ASSERT(pSample); + IMediaSample * pOutSample; + + // If no output pin to deliver to then no point sending us data + ASSERT (m_pOutput != NULL) ; + + // The source filter may dynamically ask us to start transforming from a + // different media type than the one we're using now. If we don't, we'll + // draw garbage. (typically, this is a palette change in the movie, + // but could be something more sinister like the compression type changing, + // or even the video size changing) + +#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource +#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget + + pSample->GetMediaType(&pmt); + if (pmt != NULL && pmt->pbFormat != NULL) { + + // spew some debug output + ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); +#ifdef _DEBUG + fccOut.SetFOURCC(&pmt->subtype); + LONG lCompression = HEADER(pmt->pbFormat)->biCompression; + LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; + LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; + lStride = (lStride + 3) & ~3; + DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); + DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), + fccOut.GetFOURCC(), lCompression, lBitCount)); + DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), + HEADER(pmt->pbFormat)->biHeight, + rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); + DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), + rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, + lStride)); +#endif + + // now switch to using the new format. I am assuming that the + // derived filter will do the right thing when its media type is + // switched and streaming is restarted. + + StopStreaming(); + m_pInput->CurrentMediaType() = *pmt; + DeleteMediaType(pmt); + // if this fails, playback will stop, so signal an error + hr = StartStreaming(); + if (FAILED(hr)) { + return AbortPlayback(hr); + } + } + + // Now that we have noticed any format changes on the input sample, it's + // OK to discard it. + + if (ShouldSkipFrame(pSample)) { + MSR_NOTE(m_idSkip); + m_bSampleSkipped = TRUE; + return NOERROR; + } + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + m_bSampleSkipped = FALSE; + + // The renderer may ask us to on-the-fly to start transforming to a + // different format. If we don't obey it, we'll draw garbage + +#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource +#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget + + pOutSample->GetMediaType(&pmtOut); + if (pmtOut != NULL && pmtOut->pbFormat != NULL) { + + // spew some debug output + ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); +#ifdef _DEBUG + fccOut.SetFOURCC(&pmtOut->subtype); + LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; + LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; + LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; + lStride = (lStride + 3) & ~3; + DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); + DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), + fccOut.GetFOURCC(), lCompression, lBitCount)); + DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), + HEADER(pmtOut->pbFormat)->biHeight, + rcT.left, rcT.top, rcT.right, rcT.bottom)); + DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), + rcS.left, rcS.top, rcS.right, rcS.bottom, + lStride)); +#endif + + // now switch to using the new format. I am assuming that the + // derived filter will do the right thing when its media type is + // switched and streaming is restarted. + + StopStreaming(); + m_pOutput->CurrentMediaType() = *pmtOut; + DeleteMediaType(pmtOut); + hr = StartStreaming(); + + if (SUCCEEDED(hr)) { + // a new format, means a new empty buffer, so wait for a keyframe + // before passing anything on to the renderer. + // !!! a keyframe may never come, so give up after 30 frames + DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); + m_nWaitForKey = 30; + + // if this fails, playback will stop, so signal an error + } else { + + // Must release the sample before calling AbortPlayback + // because we might be holding the win16 lock or + // ddraw lock + pOutSample->Release(); + AbortPlayback(hr); + return hr; + } + } + + // After a discontinuity, we need to wait for the next key frame + if (pSample->IsDiscontinuity() == S_OK) { + DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); + m_nWaitForKey = 30; + } + + // Start timing the transform (and log it if PERF is defined) + + if (SUCCEEDED(hr)) { + m_tDecodeStart = timeGetTime(); + MSR_START(m_idTransform); + + // have the derived class transform the data + hr = Transform(pSample, pOutSample); + + // Stop the clock (and log it if PERF is defined) + MSR_STOP(m_idTransform); + m_tDecodeStart = timeGetTime()-m_tDecodeStart; + m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); + + // Maybe we're waiting for a keyframe still? + if (m_nWaitForKey) + m_nWaitForKey--; + if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) + m_nWaitForKey = FALSE; + + // if so, then we don't want to pass this on to the renderer + if (m_nWaitForKey && hr == NOERROR) { + DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); + hr = S_FALSE; + } + } + + if (FAILED(hr)) { + DbgLog((LOG_TRACE,1,TEXT("Error from video transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + // Try not to return S_FALSE to a direct draw buffer (it's wasteful) + // Try to take the decision earlier - before you get it. + + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pOutSample); + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this case because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // We must Release() the sample before doing anything + // like calling the filter graph because having the + // sample means we may have the DirectDraw lock + // (== win16 lock on some versions) + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + m_bQualityChanged = TRUE; + NotifyEvent(EC_QUALITY_CHANGE,0,0); + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + ASSERT(CritCheckIn(&m_csReceive)); + + return hr; +} + + + +BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) +{ + REFERENCE_TIME trStart, trStopAt; + HRESULT hr = pIn->GetTime(&trStart, &trStopAt); + + // Don't skip frames with no timestamps + if (hr != S_OK) + return FALSE; + + int itrFrame = (int)(trStopAt - trStart); // frame duration + + if(S_OK==pIn->IsSyncPoint()) { + MSR_INTEGER(m_idFrameType, 1); + if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) { + // record the max + m_nKeyFramePeriod = m_nFramesSinceKeyFrame; + } + m_nFramesSinceKeyFrame = 0; + m_bSkipping = FALSE; + } else { + MSR_INTEGER(m_idFrameType, 2); + if ( m_nFramesSinceKeyFrame>m_nKeyFramePeriod + && m_nKeyFramePeriod>0 + ) { + // We haven't seen the key frame yet, but we were clearly being + // overoptimistic about how frequent they are. + m_nKeyFramePeriod = m_nFramesSinceKeyFrame; + } + } + + + // Whatever we might otherwise decide, + // if we are taking only a small fraction of the required frame time to decode + // then any quality problems are actually coming from somewhere else. + // Could be a net problem at the source for instance. In this case there's + // no point in us skipping frames here. + if (m_itrAvgDecode*4>itrFrame) { + + // Don't skip unless we are at least a whole frame late. + // (We would skip B frames if more than 1/2 frame late, but they're safe). + if ( m_itrLate > itrFrame ) { + + // Don't skip unless the anticipated key frame would be no more than + // 1 frame early. If the renderer has not been waiting (we *guess* + // it hasn't because we're late) then it will allow frames to be + // played early by up to a frame. + + // Let T = Stream time from now to anticipated next key frame + // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame) + // So we skip if T - Late < one frame i.e. + // (duration) * (freq - FramesSince) - Late < duration + // or (duration) * (freq - FramesSince - 1) < Late + + // We don't dare skip until we have seen some key frames and have + // some idea how often they occur and they are reasonably frequent. + if (m_nKeyFramePeriod>0) { + // It would be crazy - but we could have a stream with key frames + // a very long way apart - and if they are further than about + // 3.5 minutes apart then we could get arithmetic overflow in + // reference time units. Therefore we switch to mSec at this point + int it = (itrFrame/10000) + * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1); + MSR_INTEGER(m_idTimeTillKey, it); + + // For debug - might want to see the details - dump them as scratch pad +#ifdef VTRANSPERF + MSR_INTEGER(0, itrFrame); + MSR_INTEGER(0, m_nFramesSinceKeyFrame); + MSR_INTEGER(0, m_nKeyFramePeriod); +#endif + if (m_itrLate/10000 > it) { + m_bSkipping = TRUE; + // Now we are committed. Once we start skipping, we + // cannot stop until we hit a key frame. + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777770); // not near enough to next key +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777771); // Next key not predictable +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777772); // Less than one frame late + MSR_INTEGER(0, m_itrLate); + MSR_INTEGER(0, itrFrame); +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping + MSR_INTEGER(0, m_itrAvgDecode); + MSR_INTEGER(0, itrFrame); +#endif + } + + ++m_nFramesSinceKeyFrame; + + if (m_bSkipping) { + // We will count down the lateness as we skip each frame. + // We re-assess each frame. The key frame might not arrive when expected. + // We reset m_itrLate if we get a new Quality message, but actually that's + // not likely because we're not sending frames on to the Renderer. In + // fact if we DID get another one it would mean that there's a long + // pipe between us and the renderer and we might need an altogether + // better strategy to avoid hunting! + m_itrLate = m_itrLate - itrFrame; + } + + MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are + if (m_bSkipping) { + if (!m_bQualityChanged) { + m_bQualityChanged = TRUE; + NotifyEvent(EC_QUALITY_CHANGE,0,0); + } + } + return m_bSkipping; +} + + +HRESULT CVideoTransformFilter::AlterQuality(Quality q) +{ + // to reduce the amount of 64 bit arithmetic, m_itrLate is an int. + // +, -, >, == etc are not too bad, but * and / are painful. + if (m_itrLate>300000000) { + // Avoid overflow and silliness - more than 30 secs late is already silly + m_itrLate = 300000000; + } else { + m_itrLate = (int)q.Late; + } + // We ignore the other fields + + // We're actually not very good at handling this. In non-direct draw mode + // most of the time can be spent in the renderer which can skip any frame. + // In that case we'd rather the renderer handled things. + // Nevertheless we will keep an eye on it and if we really start getting + // a very long way behind then we will actually skip - but we'll still tell + // the renderer (or whoever is downstream) that they should handle quality. + + return E_FAIL; // Tell the renderer to do his thing. + +} + + + +// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4 +#pragma warning(disable:4514) + diff --git a/src/thirdparty/BaseClasses/vtrans.h b/src/thirdparty/BaseClasses/vtrans.h index 7fda41491ec..0ebace9148b 100644 --- a/src/thirdparty/BaseClasses/vtrans.h +++ b/src/thirdparty/BaseClasses/vtrans.h @@ -1,143 +1,143 @@ -//------------------------------------------------------------------------------ -// File: VTrans.h -// -// Desc: DirectShow base classes - defines a video transform class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// This class is derived from CTransformFilter, but is specialised to handle -// the requirements of video quality control by frame dropping. -// This is a non-in-place transform, (i.e. it copies the data) such as a decoder. - -class CVideoTransformFilter : public CTransformFilter -{ - public: - - CVideoTransformFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid); - ~CVideoTransformFilter(); - HRESULT EndFlush(); - - // ================================================================= - // ----- override these bits --------------------------------------- - // ================================================================= - // The following methods are in CTransformFilter which is inherited. - // They are mentioned here for completeness - // - // These MUST be supplied in a derived class - // - // NOTE: - // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); - // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; - // virtual HRESULT CheckTransform - // (const CMediaType* mtIn, const CMediaType* mtOut) PURE; - // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); - // virtual HRESULT DecideBufferSize - // (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE; - // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; - // - // These MAY also be overridden - // - // virtual HRESULT StopStreaming(); - // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); - // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); - // virtual HRESULT BreakConnect(PIN_DIRECTION dir); - // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); - // virtual HRESULT EndOfStream(void); - // virtual HRESULT BeginFlush(void); - // virtual HRESULT EndFlush(void); - // virtual HRESULT NewSegment - // (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate); -#ifdef PERF - - // If you override this - ensure that you register all these ids - // as well as any of your own, - virtual void RegisterPerfId() { - m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame")); - m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type")); - m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness")); - m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key")); - CTransformFilter::RegisterPerfId(); - } -#endif - - protected: - - // =========== QUALITY MANAGEMENT IMPLEMENTATION ======================== - // Frames are assumed to come in three types: - // Type 1: an AVI key frame or an MPEG I frame. - // This frame can be decoded with no history. - // Dropping this frame means that no further frame can be decoded - // until the next type 1 frame. - // Type 1 frames are sync points. - // Type 2: an AVI non-key frame or an MPEG P frame. - // This frame cannot be decoded unless the previous type 1 frame was - // decoded and all type 2 frames since have been decoded. - // Dropping this frame means that no further frame can be decoded - // until the next type 1 frame. - // Type 3: An MPEG B frame. - // This frame cannot be decoded unless the previous type 1 or 2 frame - // has been decoded AND the subsequent type 1 or 2 frame has also - // been decoded. (This requires decoding the frames out of sequence). - // Dropping this frame affects no other frames. This implementation - // does not allow for these. All non-sync-point frames are treated - // as being type 2. - // - // The spacing of frames of type 1 in a file is not guaranteed. There MUST - // be a type 1 frame at (well, near) the start of the file in order to start - // decoding at all. After that there could be one every half second or so, - // there could be one at the start of each scene (aka "cut", "shot") or - // there could be no more at all. - // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED - // without losing all the rest of the movie. There is no way to tell whether - // this is the case, so we find that we are in the gambling business. - // To try to improve the odds, we record the greatest interval between type 1s - // that we have seen and we bet on things being no worse than this in the - // future. - - // You can tell if it's a type 1 frame by calling IsSyncPoint(). - // there is no architected way to test for a type 3, so you should override - // the quality management here if you have B-frames. - - int m_nKeyFramePeriod; // the largest observed interval between type 1 frames - // 1 means every frame is type 1, 2 means every other. - - int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1. - // becomes the new m_nKeyFramePeriod if greater. - - BOOL m_bSkipping; // we are skipping to the next type 1 frame - -#ifdef PERF - int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key" - int m_idSkip; // MSR id skipping - int m_idLate; // MSR id lateness - int m_idTimeTillKey; // MSR id for guessed time till next key frame. -#endif - - virtual HRESULT StartStreaming(); - - HRESULT AbortPlayback(HRESULT hr); // if something bad happens - - HRESULT Receive(IMediaSample *pSample); - - HRESULT AlterQuality(Quality q); - - BOOL ShouldSkipFrame(IMediaSample * pIn); - - int m_itrLate; // lateness from last Quality message - // (this overflows at 214 secs late). - int m_tDecodeStart; // timeGetTime when decode started. - int m_itrAvgDecode; // Average decode time in reference units. - - //BOOL m_bNoSkip; // debug - no skipping. - - // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade. - // We send one when we start degrading, not one for every frame, this means - // we track whether we've sent one yet. - BOOL m_bQualityChanged; - - // When non-zero, don't pass anything to renderer until next keyframe - // If there are few keys, give up and eventually draw something - int m_nWaitForKey; -}; +//------------------------------------------------------------------------------ +// File: VTrans.h +// +// Desc: DirectShow base classes - defines a video transform class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// This class is derived from CTransformFilter, but is specialised to handle +// the requirements of video quality control by frame dropping. +// This is a non-in-place transform, (i.e. it copies the data) such as a decoder. + +class CVideoTransformFilter : public CTransformFilter +{ + public: + + CVideoTransformFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid); + ~CVideoTransformFilter(); + HRESULT EndFlush(); + + // ================================================================= + // ----- override these bits --------------------------------------- + // ================================================================= + // The following methods are in CTransformFilter which is inherited. + // They are mentioned here for completeness + // + // These MUST be supplied in a derived class + // + // NOTE: + // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); + // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; + // virtual HRESULT CheckTransform + // (const CMediaType* mtIn, const CMediaType* mtOut) PURE; + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + // virtual HRESULT DecideBufferSize + // (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE; + // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; + // + // These MAY also be overridden + // + // virtual HRESULT StopStreaming(); + // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); + // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); + // virtual HRESULT BreakConnect(PIN_DIRECTION dir); + // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); + // virtual HRESULT EndOfStream(void); + // virtual HRESULT BeginFlush(void); + // virtual HRESULT EndFlush(void); + // virtual HRESULT NewSegment + // (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate); +#ifdef PERF + + // If you override this - ensure that you register all these ids + // as well as any of your own, + virtual void RegisterPerfId() { + m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame")); + m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type")); + m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness")); + m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key")); + CTransformFilter::RegisterPerfId(); + } +#endif + + protected: + + // =========== QUALITY MANAGEMENT IMPLEMENTATION ======================== + // Frames are assumed to come in three types: + // Type 1: an AVI key frame or an MPEG I frame. + // This frame can be decoded with no history. + // Dropping this frame means that no further frame can be decoded + // until the next type 1 frame. + // Type 1 frames are sync points. + // Type 2: an AVI non-key frame or an MPEG P frame. + // This frame cannot be decoded unless the previous type 1 frame was + // decoded and all type 2 frames since have been decoded. + // Dropping this frame means that no further frame can be decoded + // until the next type 1 frame. + // Type 3: An MPEG B frame. + // This frame cannot be decoded unless the previous type 1 or 2 frame + // has been decoded AND the subsequent type 1 or 2 frame has also + // been decoded. (This requires decoding the frames out of sequence). + // Dropping this frame affects no other frames. This implementation + // does not allow for these. All non-sync-point frames are treated + // as being type 2. + // + // The spacing of frames of type 1 in a file is not guaranteed. There MUST + // be a type 1 frame at (well, near) the start of the file in order to start + // decoding at all. After that there could be one every half second or so, + // there could be one at the start of each scene (aka "cut", "shot") or + // there could be no more at all. + // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED + // without losing all the rest of the movie. There is no way to tell whether + // this is the case, so we find that we are in the gambling business. + // To try to improve the odds, we record the greatest interval between type 1s + // that we have seen and we bet on things being no worse than this in the + // future. + + // You can tell if it's a type 1 frame by calling IsSyncPoint(). + // there is no architected way to test for a type 3, so you should override + // the quality management here if you have B-frames. + + int m_nKeyFramePeriod; // the largest observed interval between type 1 frames + // 1 means every frame is type 1, 2 means every other. + + int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1. + // becomes the new m_nKeyFramePeriod if greater. + + BOOL m_bSkipping; // we are skipping to the next type 1 frame + +#ifdef PERF + int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key" + int m_idSkip; // MSR id skipping + int m_idLate; // MSR id lateness + int m_idTimeTillKey; // MSR id for guessed time till next key frame. +#endif + + virtual HRESULT StartStreaming(); + + HRESULT AbortPlayback(HRESULT hr); // if something bad happens + + HRESULT Receive(IMediaSample *pSample); + + HRESULT AlterQuality(Quality q); + + BOOL ShouldSkipFrame(IMediaSample * pIn); + + int m_itrLate; // lateness from last Quality message + // (this overflows at 214 secs late). + int m_tDecodeStart; // timeGetTime when decode started. + int m_itrAvgDecode; // Average decode time in reference units. + + //BOOL m_bNoSkip; // debug - no skipping. + + // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade. + // We send one when we start degrading, not one for every frame, this means + // we track whether we've sent one yet. + BOOL m_bQualityChanged; + + // When non-zero, don't pass anything to renderer until next keyframe + // If there are few keys, give up and eventually draw something + int m_nWaitForKey; +}; diff --git a/src/thirdparty/BaseClasses/winctrl.cpp b/src/thirdparty/BaseClasses/winctrl.cpp index a4b0126d3c2..b85d0c22c12 100644 --- a/src/thirdparty/BaseClasses/winctrl.cpp +++ b/src/thirdparty/BaseClasses/winctrl.cpp @@ -1,2081 +1,2081 @@ -//------------------------------------------------------------------------------ -// File: WinCtrl.cpp -// -// Desc: DirectShow base classes - implements video control interface class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include -#include "checkbmi.h" - -// The control interface methods require us to be connected - -#define CheckConnected(pin,code) \ -{ \ - if (pin == NULL) { \ - ASSERT(!TEXT("Pin not set")); \ - } else if (pin->IsConnected() == FALSE) { \ - return (code); \ - } \ -} - -// This checks to see whether the window has a drain. An application can in -// most environments set the owner/parent of windows so that they appear in -// a compound document context (for example). In this case, the application -// would probably like to be told of any keyboard/mouse messages. Therefore -// we pass these messages on untranslated, returning TRUE if we're successful - -BOOL WINAPI PossiblyEatMessage(HWND hwndDrain, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (hwndDrain != NULL && !InSendMessage()) - { - switch (uMsg) - { - case WM_CHAR: - case WM_DEADCHAR: - case WM_KEYDOWN: - case WM_KEYUP: - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONDBLCLK: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_MOUSEACTIVATE: - case WM_MOUSEMOVE: - // If we pass this on we don't get any mouse clicks - //case WM_NCHITTEST: - case WM_NCLBUTTONDBLCLK: - case WM_NCLBUTTONDOWN: - case WM_NCLBUTTONUP: - case WM_NCMBUTTONDBLCLK: - case WM_NCMBUTTONDOWN: - case WM_NCMBUTTONUP: - case WM_NCMOUSEMOVE: - case WM_NCRBUTTONDBLCLK: - case WM_NCRBUTTONDOWN: - case WM_NCRBUTTONUP: - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_SYSCHAR: - case WM_SYSDEADCHAR: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - - DbgLog((LOG_TRACE, 2, TEXT("Forwarding %x to drain"))); - PostMessage(hwndDrain, uMsg, wParam, lParam); - - return TRUE; - } - } - return FALSE; -} - - -// This class implements the IVideoWindow control functions (dual interface) -// we support a large number of properties and methods designed to allow the -// client (whether it be an automation controller or a C/C++ application) to -// set and get a number of window related properties such as it's position. -// We also support some methods that duplicate the properties but provide a -// more direct and efficient mechanism as many values may be changed in one - -CBaseControlWindow::CBaseControlWindow( - __inout CBaseFilter *pFilter, // Owning filter - __in CCritSec *pInterfaceLock, // Locking object - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // Normal COM ownership - __inout HRESULT *phr) : // OLE return code - - CBaseVideoWindow(pName,pUnk), - m_pInterfaceLock(pInterfaceLock), - m_hwndOwner(NULL), - m_hwndDrain(NULL), - m_bAutoShow(TRUE), - m_pFilter(pFilter), - m_bCursorHidden(FALSE), - m_pPin(NULL) -{ - ASSERT(m_pFilter); - ASSERT(m_pInterfaceLock); - ASSERT(phr); - m_BorderColour = VIDEO_COLOUR; -} - - -// Set the title caption on the base window, we don't do any field checking -// as we really don't care what title they intend to have. We can always get -// it back again later with GetWindowText. The only other complication is to -// do the necessary string conversions between ANSI and OLE Unicode strings - -STDMETHODIMP CBaseControlWindow::put_Caption(__in BSTR strCaption) -{ - CheckPointer((PVOID)strCaption,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); -#ifdef UNICODE - SetWindowText(m_hwnd, strCaption); -#else - CHAR Caption[CAPTION]; - - WideCharToMultiByte(CP_ACP,0,strCaption,-1,Caption,CAPTION,NULL,NULL); - SetWindowText(m_hwnd, Caption); -#endif - return NOERROR; -} - - -// Get the current base window title caption, once again we do no real field -// checking. We allocate a string for the window title to be filled in with -// which ensures the interface doesn't fiddle around with getting memory. A -// BSTR is a normal C string with the length at position (-1), we use the -// WriteBSTR helper function to create the caption to try and avoid OLE32 - -STDMETHODIMP CBaseControlWindow::get_Caption(__out BSTR *pstrCaption) -{ - CheckPointer(pstrCaption,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - WCHAR WideCaption[CAPTION]; - -#ifdef UNICODE - GetWindowText(m_hwnd,WideCaption,CAPTION); -#else - // Convert the ASCII caption to a UNICODE string - - TCHAR Caption[CAPTION]; - GetWindowText(m_hwnd,Caption,CAPTION); - MultiByteToWideChar(CP_ACP,0,Caption,-1,WideCaption,CAPTION); -#endif - return WriteBSTR(pstrCaption,WideCaption); -} - - -// Set the window style using GWL_EXSTYLE - -STDMETHODIMP CBaseControlWindow::put_WindowStyleEx(long WindowStyleEx) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Should we be taking off WS_EX_TOPMOST - - if (GetWindowLong(m_hwnd,GWL_EXSTYLE) & WS_EX_TOPMOST) { - if ((WindowStyleEx & WS_EX_TOPMOST) == 0) { - SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) FALSE,(LPARAM) 0); - } - } - - // Likewise should we be adding WS_EX_TOPMOST - - if (WindowStyleEx & WS_EX_TOPMOST) { - SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) TRUE,(LPARAM) 0); - WindowStyleEx &= (~WS_EX_TOPMOST); - if (WindowStyleEx == 0) return NOERROR; - } - return DoSetWindowStyle(WindowStyleEx,GWL_EXSTYLE); -} - - -// Gets the current GWL_EXSTYLE base window style - -STDMETHODIMP CBaseControlWindow::get_WindowStyleEx(__out long *pWindowStyleEx) -{ - CheckPointer(pWindowStyleEx,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - return DoGetWindowStyle(pWindowStyleEx,GWL_EXSTYLE); -} - - -// Set the window style using GWL_STYLE - -STDMETHODIMP CBaseControlWindow::put_WindowStyle(long WindowStyle) -{ - // These styles cannot be changed dynamically - - if ((WindowStyle & WS_DISABLED) || - (WindowStyle & WS_ICONIC) || - (WindowStyle & WS_MAXIMIZE) || - (WindowStyle & WS_MINIMIZE) || - (WindowStyle & WS_HSCROLL) || - (WindowStyle & WS_VSCROLL)) { - - return E_INVALIDARG; - } - - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - return DoSetWindowStyle(WindowStyle,GWL_STYLE); -} - - -// Get the current GWL_STYLE base window style - -STDMETHODIMP CBaseControlWindow::get_WindowStyle(__out long *pWindowStyle) -{ - CheckPointer(pWindowStyle,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - return DoGetWindowStyle(pWindowStyle,GWL_STYLE); -} - - -// Change the base window style or the extended styles depending on whether -// WindowLong is GWL_STYLE or GWL_EXSTYLE. We must call SetWindowPos to have -// the window displayed in it's new style after the change which is a little -// tricky if the window is not currently visible as we realise it offscreen. -// In most cases the client will call get_WindowStyle before they call this -// and then AND and OR in extra bit settings according to the requirements - -HRESULT CBaseControlWindow::DoSetWindowStyle(long Style,long WindowLong) -{ - RECT WindowRect; - - // Get the window's visibility before setting the style - BOOL bVisible = IsWindowVisible(m_hwnd); - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - // Set the new style flags for the window - SetWindowLong(m_hwnd,WindowLong,Style); - UINT WindowFlags = SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE; - WindowFlags |= SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; - - // Show the window again in the current position - - if (bVisible == TRUE) { - - SetWindowPos(m_hwnd, // Base window handle - HWND_TOP, // Just a place holder - 0,0,0,0, // Leave size and position - WindowFlags); // Just draw it again - - return NOERROR; - } - - // Move the window offscreen so the user doesn't see the changes - - MoveWindow((HWND) m_hwnd, // Base window handle - GetSystemMetrics(SM_CXSCREEN), // Current desktop width - GetSystemMetrics(SM_CYSCREEN), // Likewise it's height - WIDTH(&WindowRect), // Use the same width - HEIGHT(&WindowRect), // Keep height same to - TRUE); // May as well repaint - - // Now show the previously hidden window - - SetWindowPos(m_hwnd, // Base window handle - HWND_TOP, // Just a place holder - 0,0,0,0, // Leave size and position - WindowFlags); // Just draw it again - - ShowWindow(m_hwnd,SW_HIDE); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - MoveWindow((HWND) m_hwnd, // Base window handle - WindowRect.left, // Existing x coordinate - WindowRect.top, // Existing y coordinate - WIDTH(&WindowRect), // Use the same width - HEIGHT(&WindowRect), // Keep height same to - TRUE); // May as well repaint - - return NOERROR; -} - - -// Get the current base window style (either GWL_STYLE or GWL_EXSTYLE) - -HRESULT CBaseControlWindow::DoGetWindowStyle(__out long *pStyle,long WindowLong) -{ - *pStyle = GetWindowLong(m_hwnd,WindowLong); - return NOERROR; -} - - -// Change the visibility of the base window, this takes the same parameters -// as the ShowWindow Win32 API does, so the client can have the window hidden -// or shown, minimised to an icon, or maximised to play in full screen mode -// We pass the request on to the base window to actually make the change - -STDMETHODIMP CBaseControlWindow::put_WindowState(long WindowState) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - DoShowWindow(WindowState); - return NOERROR; -} - - -// Get the current window state, this function returns a subset of the SW bit -// settings available in ShowWindow, if the window is visible then SW_SHOW is -// set, if it is hidden then the SW_HIDDEN is set, if it is either minimised -// or maximised then the SW_MINIMIZE or SW_MAXIMIZE is set respectively. The -// other SW bit settings are really set commands not readable output values - -STDMETHODIMP CBaseControlWindow::get_WindowState(__out long *pWindowState) -{ - CheckPointer(pWindowState,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - ASSERT(pWindowState); - *pWindowState = FALSE; - - // Is the window visible, a window is termed visible if it is somewhere on - // the current desktop even if it is completely obscured by other windows - // so the flag is a style for each window set with the WS_VISIBLE bit - - if (IsWindowVisible(m_hwnd) == TRUE) { - - // Is the base window iconic - if (IsIconic(m_hwnd) == TRUE) { - *pWindowState |= SW_MINIMIZE; - } - - // Has the window been maximised - else if (IsZoomed(m_hwnd) == TRUE) { - *pWindowState |= SW_MAXIMIZE; - } - - // Window is normal - else { - *pWindowState |= SW_SHOW; - } - - } else { - *pWindowState |= SW_HIDE; - } - return NOERROR; -} - - -// This makes sure that any palette we realise in the base window (through a -// media type or through the overlay interface) is done in the background and -// is therefore mapped to existing device entries rather than taking it over -// as it will do when we this window gets the keyboard focus. An application -// uses this to make sure it doesn't have it's palette removed by the window - -STDMETHODIMP CBaseControlWindow::put_BackgroundPalette(long BackgroundPalette) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cWindowLock(&m_WindowLock); - - // Check this is a valid automation boolean type - - if (BackgroundPalette != OATRUE) { - if (BackgroundPalette != OAFALSE) { - return E_INVALIDARG; - } - } - - // Make sure the window realises any palette it has again - - m_bBackground = (BackgroundPalette == OATRUE ? TRUE : FALSE); - PostMessage(m_hwnd,m_RealizePalette,0,0); - PaintWindow(FALSE); - - return NOERROR; -} - - -// This returns the current background realisation setting - -STDMETHODIMP -CBaseControlWindow::get_BackgroundPalette(__out long *pBackgroundPalette) -{ - CheckPointer(pBackgroundPalette,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cWindowLock(&m_WindowLock); - - // Get the current background palette setting - - *pBackgroundPalette = (m_bBackground == TRUE ? OATRUE : OAFALSE); - return NOERROR; -} - - -// Change the visibility of the base window - -STDMETHODIMP CBaseControlWindow::put_Visible(long Visible) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Check this is a valid automation boolean type - - if (Visible != OATRUE) { - if (Visible != OAFALSE) { - return E_INVALIDARG; - } - } - - // Convert the boolean visibility into SW_SHOW and SW_HIDE - - INT Mode = (Visible == OATRUE ? SW_SHOWNORMAL : SW_HIDE); - DoShowWindow(Mode); - return NOERROR; -} - - -// Return OATRUE if the window is currently visible otherwise OAFALSE - -STDMETHODIMP CBaseControlWindow::get_Visible(__out long *pVisible) -{ - CheckPointer(pVisible,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // See if the base window has a WS_VISIBLE style - this will return TRUE - // even if the window is completely obscured by other desktop windows, we - // return FALSE if the window is not showing because of earlier calls - - BOOL Mode = IsWindowVisible(m_hwnd); - *pVisible = (Mode == TRUE ? OATRUE : OAFALSE); - return NOERROR; -} - - -// Change the left position of the base window. This keeps the window width -// and height properties the same so it effectively shunts the window left or -// right accordingly - there is the Width property to change that dimension - -STDMETHODIMP CBaseControlWindow::put_Left(long Left) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - RECT WindowRect; - - // Get the current window position in a RECT - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - // Adjust the coordinates ready for SetWindowPos, the window rectangle we - // get back from GetWindowRect is in left,top,right and bottom while the - // coordinates SetWindowPos wants are left,top,width and height values - - WindowRect.bottom = WindowRect.bottom - WindowRect.top; - WindowRect.right = WindowRect.right - WindowRect.left; - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - Left, // New left position - WindowRect.top, // Leave top alone - WindowRect.right, // The WIDTH (not right) - WindowRect.bottom, // The HEIGHT (not bottom) - WindowFlags); // Show window options - - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// Return the current base window left position - -STDMETHODIMP CBaseControlWindow::get_Left(__out long *pLeft) -{ - CheckPointer(pLeft,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - *pLeft = WindowRect.left; - return NOERROR; -} - - -// Change the current width of the base window. This property complements the -// left position property so we must keep the left edge constant and expand or -// contract to the right, the alternative would be to change the left edge so -// keeping the right edge constant but this is maybe a little more intuitive - -STDMETHODIMP CBaseControlWindow::put_Width(long Width) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - RECT WindowRect; - - // Adjust the coordinates ready for SetWindowPos, the window rectangle we - // get back from GetWindowRect is in left,top,right and bottom while the - // coordinates SetWindowPos wants are left,top,width and height values - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - WindowRect.bottom = WindowRect.bottom - WindowRect.top; - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - // This seems to have a bug in that calling SetWindowPos on a window with - // just the width changing causes it to ignore the width that you pass in - // and sets it to a mimimum value of 110 pixels wide (Windows NT 3.51) - - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Leave left alone - WindowRect.top, // Leave top alone - Width, // New WIDTH dimension - WindowRect.bottom, // The HEIGHT (not bottom) - WindowFlags); // Show window options - - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// Return the current base window width - -STDMETHODIMP CBaseControlWindow::get_Width(__out long *pWidth) -{ - CheckPointer(pWidth,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - *pWidth = WindowRect.right - WindowRect.left; - return NOERROR; -} - - -// This allows the client program to change the top position for the window in -// the same way that changing the left position does not affect the width of -// the image so changing the top position does not affect the window height - -STDMETHODIMP CBaseControlWindow::put_Top(long Top) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - RECT WindowRect; - - // Get the current window position in a RECT - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - // Adjust the coordinates ready for SetWindowPos, the window rectangle we - // get back from GetWindowRect is in left,top,right and bottom while the - // coordinates SetWindowPos wants are left,top,width and height values - - WindowRect.bottom = WindowRect.bottom - WindowRect.top; - WindowRect.right = WindowRect.right - WindowRect.left; - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Leave left alone - Top, // New top position - WindowRect.right, // The WIDTH (not right) - WindowRect.bottom, // The HEIGHT (not bottom) - WindowFlags); // Show window flags - - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// Return the current base window top position - -STDMETHODIMP CBaseControlWindow::get_Top(long *pTop) -{ - CheckPointer(pTop,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - *pTop = WindowRect.top; - return NOERROR; -} - - -// Change the height of the window, this complements the top property so when -// we change this we must keep the top position for the base window, as said -// before we could keep the bottom and grow upwards although this is perhaps -// a little more intuitive since we already have a top position property - -STDMETHODIMP CBaseControlWindow::put_Height(long Height) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - RECT WindowRect; - - // Adjust the coordinates ready for SetWindowPos, the window rectangle we - // get back from GetWindowRect is in left,top,right and bottom while the - // coordinates SetWindowPos wants are left,top,width and height values - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - WindowRect.right = WindowRect.right - WindowRect.left; - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Leave left alone - WindowRect.top, // Leave top alone - WindowRect.right, // The WIDTH (not right) - Height, // New height dimension - WindowFlags); // Show window flags - - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// Return the current base window height - -STDMETHODIMP CBaseControlWindow::get_Height(__out long *pHeight) -{ - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - *pHeight = WindowRect.bottom - WindowRect.top; - return NOERROR; -} - - -// This can be called to change the owning window. Setting the owner is done -// through this function, however to make the window a true child window the -// style must also be set to WS_CHILD. After resetting the owner to NULL an -// application should also set the style to WS_OVERLAPPED | WS_CLIPCHILDREN. - -// We cannot lock the object here because the SetParent causes an interthread -// SendMessage to the owner window. If they are in GetState we will sit here -// incomplete with the critical section locked therefore blocking out source -// filter threads from accessing us. Because the source thread can't enter us -// it can't get buffers or call EndOfStream so the GetState will not complete - -STDMETHODIMP CBaseControlWindow::put_Owner(OAHWND Owner) -{ - // Check we are connected otherwise reject the call - - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - m_hwndOwner = (HWND) Owner; - HWND hwndParent = m_hwndOwner; - - // Add or remove WS_CHILD as appropriate - - LONG Style = GetWindowLong(m_hwnd,GWL_STYLE); - if (Owner == NULL) { - Style &= (~WS_CHILD); - } else { - Style |= (WS_CHILD); - } - SetWindowLong(m_hwnd,GWL_STYLE,Style); - - // Don't call this with the filter locked - - SetParent(m_hwnd,hwndParent); - - PaintWindow(TRUE); - NOTE1("Changed parent %lx",hwndParent); - - return NOERROR; -} - - -// This complements the put_Owner to get the current owning window property -// we always return NOERROR although the returned window handle may be NULL -// to indicate no owning window (the desktop window doesn't qualify as one) -// If an application sets the owner we call SetParent, however that returns -// NULL until the WS_CHILD bit is set on, so we store the owner internally - -STDMETHODIMP CBaseControlWindow::get_Owner(__out OAHWND *Owner) -{ - CheckPointer(Owner,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *Owner = (OAHWND) m_hwndOwner; - return NOERROR; -} - - -// And renderer supporting IVideoWindow may have an HWND set who will get any -// keyboard and mouse messages we receive posted on to them. This is separate -// from setting an owning window. By separating the two, applications may get -// messages sent on even when they have set no owner (perhaps it's maximised) - -STDMETHODIMP CBaseControlWindow::put_MessageDrain(OAHWND Drain) -{ - // Check we are connected otherwise reject the call - - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - m_hwndDrain = (HWND) Drain; - return NOERROR; -} - - -// Return the current message drain - -STDMETHODIMP CBaseControlWindow::get_MessageDrain(__out OAHWND *Drain) -{ - CheckPointer(Drain,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *Drain = (OAHWND) m_hwndDrain; - return NOERROR; -} - - -// This is called by the filter graph to inform us of a message we should know -// is being sent to our owning window. We have this because as a child window -// we do not get certain messages that are only sent to top level windows. We -// must see the palette changed/changing/query messages so that we know if we -// have the foreground palette or not. We pass the message on to our window -// using SendMessage - this will cause an interthread send message to occur - -STDMETHODIMP -CBaseControlWindow::NotifyOwnerMessage(OAHWND hwnd, // Window handle - long uMsg, // Message ID - LONG_PTR wParam, // Parameters - LONG_PTR lParam) // for message -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Only interested in these Windows messages - - switch (uMsg) { - - case WM_SYSCOLORCHANGE: - case WM_PALETTECHANGED: - case WM_PALETTEISCHANGING: - case WM_QUERYNEWPALETTE: - case WM_DEVMODECHANGE: - case WM_DISPLAYCHANGE: - case WM_ACTIVATEAPP: - - // If we do not have an owner then ignore - - if (m_hwndOwner == NULL) { - return NOERROR; - } - SendMessage(m_hwnd,uMsg,(WPARAM)wParam,(LPARAM)lParam); - break; - - // do NOT fwd WM_MOVE. the parameters are the location of the parent - // window, NOT what the renderer should be looking at. But we need - // to make sure the overlay is moved with the parent window, so we - // do this. - case WM_MOVE: - PostMessage(m_hwnd,WM_PAINT,0,0); - break; - } - return NOERROR; -} - - -// Allow an application to have us set the base window in the foreground. We -// have this because it is difficult for one thread to do do this to a window -// owned by another thread. We ask the base window class to do the real work - -STDMETHODIMP CBaseControlWindow::SetWindowForeground(long Focus) -{ - // Check this is a valid automation boolean type - - if (Focus != OATRUE) { - if (Focus != OAFALSE) { - return E_INVALIDARG; - } - } - - // We shouldn't lock as this sends a message - - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bFocus = (Focus == OATRUE ? TRUE : FALSE); - DoSetWindowForeground(bFocus); - - return NOERROR; -} - - -// This allows a client to set the complete window size and position in one -// atomic operation. The same affect can be had by changing each dimension -// in turn through their individual properties although some flashing will -// occur as each of them gets updated (they are better set at design time) - -STDMETHODIMP -CBaseControlWindow::SetWindowPosition(long Left,long Top,long Width,long Height) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - - // Set the new size and position - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - ASSERT(IsWindow(m_hwnd)); - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - Left, // Left position - Top, // Top position - Width, // Window width - Height, // Window height - WindowFlags); // Show window flags - ASSERT(bSuccess); -#ifdef _DEBUG - DbgLog((LOG_TRACE, 1, TEXT("SWP failed error %d"), GetLastError())); -#endif - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// This complements the SetWindowPosition to return the current window place -// in device coordinates. As before the same information can be retrived by -// calling the property get functions individually but this is atomic and is -// therefore more suitable to a live environment rather than design time - -STDMETHODIMP -CBaseControlWindow::GetWindowPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) -{ - // Should check the pointers are not NULL - - CheckPointer(pLeft,E_POINTER); - CheckPointer(pTop,E_POINTER); - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - // Get the current window coordinates - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - // Convert the RECT into left,top,width and height values - - *pLeft = WindowRect.left; - *pTop = WindowRect.top; - *pWidth = WindowRect.right - WindowRect.left; - *pHeight = WindowRect.bottom - WindowRect.top; - - return NOERROR; -} - - -// When a window is maximised or iconic calling GetWindowPosition will return -// the current window position (likewise for the properties). However if the -// restored size (ie the size we'll return to when normally shown) is needed -// then this should be used. When in a normal position (neither iconic nor -// maximised) then this returns the same coordinates as GetWindowPosition - -STDMETHODIMP -CBaseControlWindow::GetRestorePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) -{ - // Should check the pointers are not NULL - - CheckPointer(pLeft,E_POINTER); - CheckPointer(pTop,E_POINTER); - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Use GetWindowPlacement to find the restore position - - WINDOWPLACEMENT Place; - Place.length = sizeof(WINDOWPLACEMENT); - EXECUTE_ASSERT(GetWindowPlacement(m_hwnd,&Place)); - - RECT WorkArea; - - // We must take into account any task bar present - - if (SystemParametersInfo(SPI_GETWORKAREA,0,&WorkArea,FALSE) == TRUE) { - if (GetParent(m_hwnd) == NULL) { - Place.rcNormalPosition.top += WorkArea.top; - Place.rcNormalPosition.bottom += WorkArea.top; - Place.rcNormalPosition.left += WorkArea.left; - Place.rcNormalPosition.right += WorkArea.left; - } - } - - // Convert the RECT into left,top,width and height values - - *pLeft = Place.rcNormalPosition.left; - *pTop = Place.rcNormalPosition.top; - *pWidth = Place.rcNormalPosition.right - Place.rcNormalPosition.left; - *pHeight = Place.rcNormalPosition.bottom - Place.rcNormalPosition.top; - - return NOERROR; -} - - -// Return the current border colour, if we are playing something to a subset -// of the base window display there is an outside area exposed. The default -// action is to paint this colour in the Windows background colour (defined -// as value COLOR_WINDOW) We reset to this default when we're disconnected - -STDMETHODIMP CBaseControlWindow::get_BorderColor(__out long *Color) -{ - CheckPointer(Color,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *Color = (long) m_BorderColour; - return NOERROR; -} - - -// This can be called to set the current border colour - -STDMETHODIMP CBaseControlWindow::put_BorderColor(long Color) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Have the window repainted with the new border colour - - m_BorderColour = (COLORREF) Color; - PaintWindow(TRUE); - return NOERROR; -} - - -// Delegate fullscreen handling to plug in distributor - -STDMETHODIMP CBaseControlWindow::get_FullScreenMode(__out long *FullScreenMode) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CheckPointer(FullScreenMode,E_POINTER); - return E_NOTIMPL; -} - - -// Delegate fullscreen handling to plug in distributor - -STDMETHODIMP CBaseControlWindow::put_FullScreenMode(long FullScreenMode) -{ - return E_NOTIMPL; -} - - -// This sets the auto show property, this property causes the base window to -// be displayed whenever we change state. This allows an application to have -// to do nothing to have the window appear but still allow them to change the -// default behaviour if for example they want to keep it hidden for longer - -STDMETHODIMP CBaseControlWindow::put_AutoShow(long AutoShow) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Check this is a valid automation boolean type - - if (AutoShow != OATRUE) { - if (AutoShow != OAFALSE) { - return E_INVALIDARG; - } - } - - m_bAutoShow = (AutoShow == OATRUE ? TRUE : FALSE); - return NOERROR; -} - - -// This can be called to get the current auto show flag. The flag is updated -// when we connect and disconnect and through this interface all of which are -// controlled and serialised by means of the main renderer critical section - -STDMETHODIMP CBaseControlWindow::get_AutoShow(__out long *AutoShow) -{ - CheckPointer(AutoShow,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *AutoShow = (m_bAutoShow == TRUE ? OATRUE : OAFALSE); - return NOERROR; -} - - -// Return the minimum ideal image size for the current video. This may differ -// to the actual video dimensions because we may be using DirectDraw hardware -// that has specific stretching requirements. For example the Cirrus Logic -// cards have a minimum stretch factor depending on the overlay surface size - -STDMETHODIMP -CBaseControlWindow::GetMinIdealImageSize(__out long *pWidth,__out long *pHeight) -{ - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - FILTER_STATE State; - - // Must not be stopped for this to work correctly - - m_pFilter->GetState(0,&State); - if (State == State_Stopped) { - return VFW_E_WRONG_STATE; - } - - RECT DefaultRect = GetDefaultRect(); - *pWidth = WIDTH(&DefaultRect); - *pHeight = HEIGHT(&DefaultRect); - return NOERROR; -} - - -// Return the maximum ideal image size for the current video. This may differ -// to the actual video dimensions because we may be using DirectDraw hardware -// that has specific stretching requirements. For example the Cirrus Logic -// cards have a maximum stretch factor depending on the overlay surface size - -STDMETHODIMP -CBaseControlWindow::GetMaxIdealImageSize(__out long *pWidth,__out long *pHeight) -{ - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - FILTER_STATE State; - - // Must not be stopped for this to work correctly - - m_pFilter->GetState(0,&State); - if (State == State_Stopped) { - return VFW_E_WRONG_STATE; - } - - RECT DefaultRect = GetDefaultRect(); - *pWidth = WIDTH(&DefaultRect); - *pHeight = HEIGHT(&DefaultRect); - return NOERROR; -} - - -// Allow an application to hide the cursor on our window - -STDMETHODIMP -CBaseControlWindow::HideCursor(long HideCursor) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Check this is a valid automation boolean type - - if (HideCursor != OATRUE) { - if (HideCursor != OAFALSE) { - return E_INVALIDARG; - } - } - - m_bCursorHidden = (HideCursor == OATRUE ? TRUE : FALSE); - return NOERROR; -} - - -// Returns whether we have the cursor hidden or not - -STDMETHODIMP CBaseControlWindow::IsCursorHidden(__out long *CursorHidden) -{ - CheckPointer(CursorHidden,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *CursorHidden = (m_bCursorHidden == TRUE ? OATRUE : OAFALSE); - return NOERROR; -} - - -// This class implements the IBasicVideo control functions (dual interface) -// we support a large number of properties and methods designed to allow the -// client (whether it be an automation controller or a C/C++ application) to -// set and get a number of video related properties such as the native video -// size. We support some methods that duplicate the properties but provide a -// more direct and efficient mechanism as many values may be changed in one - -CBaseControlVideo::CBaseControlVideo( - __inout CBaseFilter *pFilter, // Owning filter - __in CCritSec *pInterfaceLock, // Locking object - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // Normal COM ownership - __inout HRESULT *phr) : // OLE return code - - CBaseBasicVideo(pName,pUnk), - m_pFilter(pFilter), - m_pInterfaceLock(pInterfaceLock), - m_pPin(NULL) -{ - ASSERT(m_pFilter); - ASSERT(m_pInterfaceLock); - ASSERT(phr); -} - -// Return an approximate average time per frame - -STDMETHODIMP CBaseControlVideo::get_AvgTimePerFrame(__out REFTIME *pAvgTimePerFrame) -{ - CheckPointer(pAvgTimePerFrame,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - COARefTime AvgTime(pVideoInfo->AvgTimePerFrame); - *pAvgTimePerFrame = (REFTIME) AvgTime; - - return NOERROR; -} - - -// Return an approximate bit rate for the video - -STDMETHODIMP CBaseControlVideo::get_BitRate(__out long *pBitRate) -{ - CheckPointer(pBitRate,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pBitRate = pVideoInfo->dwBitRate; - return NOERROR; -} - - -// Return an approximate bit error rate - -STDMETHODIMP CBaseControlVideo::get_BitErrorRate(__out long *pBitErrorRate) -{ - CheckPointer(pBitErrorRate,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pBitErrorRate = pVideoInfo->dwBitErrorRate; - return NOERROR; -} - - -// This returns the current video width - -STDMETHODIMP CBaseControlVideo::get_VideoWidth(__out long *pVideoWidth) -{ - CheckPointer(pVideoWidth,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pVideoWidth = pVideoInfo->bmiHeader.biWidth; - return NOERROR; -} - - -// This returns the current video height - -STDMETHODIMP CBaseControlVideo::get_VideoHeight(__out long *pVideoHeight) -{ - CheckPointer(pVideoHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pVideoHeight = pVideoInfo->bmiHeader.biHeight; - return NOERROR; -} - - -// This returns the current palette the video is using as an array allocated -// by the user. To remain consistent we use PALETTEENTRY fields to return the -// colours in rather than RGBQUADs that multimedia decided to use. The memory -// is allocated by the user so we simple copy each in turn. We check that the -// number of entries requested and the start position offset are both valid -// If the number of entries evaluates to zero then we return an S_FALSE code - -STDMETHODIMP CBaseControlVideo::GetVideoPaletteEntries(long StartIndex, - long Entries, - __out long *pRetrieved, - __out_ecount_part(Entries, *pRetrieved) long *pPalette) -{ - CheckPointer(pRetrieved,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - CMediaType MediaType; - - // Get the video format from the derived class - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); - - // Is the current format palettised - - if (PALETTISED(pVideoInfo) == FALSE) { - *pRetrieved = 0; - return VFW_E_NO_PALETTE_AVAILABLE; - } - - // Do they just want to know how many are available - - if (pPalette == NULL) { - *pRetrieved = pHeader->biClrUsed; - return NOERROR; - } - - // Make sure the start position is a valid offset - - if (StartIndex >= (LONG) pHeader->biClrUsed || StartIndex < 0) { - *pRetrieved = 0; - return E_INVALIDARG; - } - - // Correct the number we can retrieve - - long Available = (long)pHeader->biClrUsed - StartIndex; - *pRetrieved = std::max(0l, std::min(Available, Entries)); - if (*pRetrieved == 0) { - return S_FALSE; - } - - // Copy the palette entries to the output buffer - - PALETTEENTRY *pEntries = (PALETTEENTRY *) pPalette; - RGBQUAD *pColours = COLORS(pVideoInfo) + StartIndex; - - for (LONG Count = 0;Count < *pRetrieved;Count++) { - pEntries[Count].peRed = pColours[Count].rgbRed; - pEntries[Count].peGreen = pColours[Count].rgbGreen; - pEntries[Count].peBlue = pColours[Count].rgbBlue; - pEntries[Count].peFlags = 0; - } - return NOERROR; -} - - -// This returns the current video dimensions as a method rather than a number -// of individual property get calls. For the same reasons as said before we -// cannot access the renderer media type directly as the window object thread -// may be updating it since dynamic format changes may change these values - -STDMETHODIMP CBaseControlVideo::GetVideoSize(__out long *pWidth,__out long *pHeight) -{ - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - // Get the video format from the derived class - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pWidth = pVideoInfo->bmiHeader.biWidth; - *pHeight = pVideoInfo->bmiHeader.biHeight; - return NOERROR; -} - - -// Set the source video rectangle as left,top,right and bottom coordinates -// rather than left,top,width and height as per OLE automation interfaces -// Then pass the rectangle on to the window object to set the source - -STDMETHODIMP -CBaseControlVideo::SetSourcePosition(long Left,long Top,long Width,long Height) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - SourceRect.left = Left; - SourceRect.top = Top; - SourceRect.right = Left + Width; - SourceRect.bottom = Top + Height; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the source rectangle in left,top,width and height rather than the -// left,top,right and bottom values that RECT uses (and which the window -// object returns through GetSourceRect) which requires a little work - -STDMETHODIMP -CBaseControlVideo::GetSourcePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) -{ - // Should check the pointers are non NULL - - CheckPointer(pLeft,E_POINTER); - CheckPointer(pTop,E_POINTER); - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT SourceRect; - - CAutoLock cInterfaceLock(m_pInterfaceLock); - GetSourceRect(&SourceRect); - - *pLeft = SourceRect.left; - *pTop = SourceRect.top; - *pWidth = WIDTH(&SourceRect); - *pHeight = HEIGHT(&SourceRect); - - return NOERROR; -} - - -// Set the video destination as left,top,right and bottom coordinates rather -// than the left,top,width and height uses as per OLE automation interfaces -// Then pass the rectangle on to the window object to set the destination - -STDMETHODIMP -CBaseControlVideo::SetDestinationPosition(long Left,long Top,long Width,long Height) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - DestinationRect.left = Left; - DestinationRect.top = Top; - DestinationRect.right = Left + Width; - DestinationRect.bottom = Top + Height; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the destination rectangle in left,top,width and height rather than -// the left,top,right and bottom values that RECT uses (and which the window -// object returns through GetDestinationRect) which requires a little work - -STDMETHODIMP -CBaseControlVideo::GetDestinationPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) -{ - // Should check the pointers are not NULL - - CheckPointer(pLeft,E_POINTER); - CheckPointer(pTop,E_POINTER); - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT DestinationRect; - - CAutoLock cInterfaceLock(m_pInterfaceLock); - GetTargetRect(&DestinationRect); - - *pLeft = DestinationRect.left; - *pTop = DestinationRect.top; - *pWidth = WIDTH(&DestinationRect); - *pHeight = HEIGHT(&DestinationRect); - - return NOERROR; -} - - -// Set the source left position, the source rectangle we get back from the -// window object is a true rectangle in left,top,right and bottom positions -// so all we have to do is to update the left position and pass it back. We -// must keep the current width constant when we're updating this property - -STDMETHODIMP CBaseControlVideo::put_SourceLeft(long SourceLeft) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - GetSourceRect(&SourceRect); - SourceRect.right = SourceLeft + WIDTH(&SourceRect); - SourceRect.left = SourceLeft; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the current left source video position - -STDMETHODIMP CBaseControlVideo::get_SourceLeft(__out long *pSourceLeft) -{ - CheckPointer(pSourceLeft,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - - GetSourceRect(&SourceRect); - *pSourceLeft = SourceRect.left; - return NOERROR; -} - - -// Set the source width, we get the current source rectangle and then update -// the right position to be the left position (thereby keeping it constant) -// plus the new source width we are passed in (it expands to the right) - -STDMETHODIMP CBaseControlVideo::put_SourceWidth(long SourceWidth) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - GetSourceRect(&SourceRect); - SourceRect.right = SourceRect.left + SourceWidth; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the current source width - -STDMETHODIMP CBaseControlVideo::get_SourceWidth(__out long *pSourceWidth) -{ - CheckPointer(pSourceWidth,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - - GetSourceRect(&SourceRect); - *pSourceWidth = WIDTH(&SourceRect); - return NOERROR; -} - - -// Set the source top position - changing this property does not affect the -// current source height. So changing this shunts the source rectangle up and -// down appropriately. Changing the height complements this functionality by -// keeping the top position constant and simply changing the source height - -STDMETHODIMP CBaseControlVideo::put_SourceTop(long SourceTop) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - GetSourceRect(&SourceRect); - SourceRect.bottom = SourceTop + HEIGHT(&SourceRect); - SourceRect.top = SourceTop; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the current top position - -STDMETHODIMP CBaseControlVideo::get_SourceTop(__out long *pSourceTop) -{ - CheckPointer(pSourceTop,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - - GetSourceRect(&SourceRect); - *pSourceTop = SourceRect.top; - return NOERROR; -} - - -// Set the source height - -STDMETHODIMP CBaseControlVideo::put_SourceHeight(long SourceHeight) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - GetSourceRect(&SourceRect); - SourceRect.bottom = SourceRect.top + SourceHeight; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the current source height - -STDMETHODIMP CBaseControlVideo::get_SourceHeight(__out long *pSourceHeight) -{ - CheckPointer(pSourceHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - - GetSourceRect(&SourceRect); - *pSourceHeight = HEIGHT(&SourceRect); - return NOERROR; -} - - -// Set the target left position, the target rectangle we get back from the -// window object is a true rectangle in left,top,right and bottom positions -// so all we have to do is to update the left position and pass it back. We -// must keep the current width constant when we're updating this property - -STDMETHODIMP CBaseControlVideo::put_DestinationLeft(long DestinationLeft) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - GetTargetRect(&DestinationRect); - DestinationRect.right = DestinationLeft + WIDTH(&DestinationRect); - DestinationRect.left = DestinationLeft; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the left position for the destination rectangle - -STDMETHODIMP CBaseControlVideo::get_DestinationLeft(__out long *pDestinationLeft) -{ - CheckPointer(pDestinationLeft,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - GetTargetRect(&DestinationRect); - *pDestinationLeft = DestinationRect.left; - return NOERROR; -} - - -// Set the destination width - -STDMETHODIMP CBaseControlVideo::put_DestinationWidth(long DestinationWidth) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - GetTargetRect(&DestinationRect); - DestinationRect.right = DestinationRect.left + DestinationWidth; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the width for the destination rectangle - -STDMETHODIMP CBaseControlVideo::get_DestinationWidth(__out long *pDestinationWidth) -{ - CheckPointer(pDestinationWidth,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - GetTargetRect(&DestinationRect); - *pDestinationWidth = WIDTH(&DestinationRect); - return NOERROR; -} - - -// Set the target top position - changing this property does not affect the -// current target height. So changing this shunts the target rectangle up and -// down appropriately. Changing the height complements this functionality by -// keeping the top position constant and simply changing the target height - -STDMETHODIMP CBaseControlVideo::put_DestinationTop(long DestinationTop) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - GetTargetRect(&DestinationRect); - DestinationRect.bottom = DestinationTop + HEIGHT(&DestinationRect); - DestinationRect.top = DestinationTop; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the top position for the destination rectangle - -STDMETHODIMP CBaseControlVideo::get_DestinationTop(__out long *pDestinationTop) -{ - CheckPointer(pDestinationTop,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - GetTargetRect(&DestinationRect); - *pDestinationTop = DestinationRect.top; - return NOERROR; -} - - -// Set the destination height - -STDMETHODIMP CBaseControlVideo::put_DestinationHeight(long DestinationHeight) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - GetTargetRect(&DestinationRect); - DestinationRect.bottom = DestinationRect.top + DestinationHeight; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the height for the destination rectangle - -STDMETHODIMP CBaseControlVideo::get_DestinationHeight(__out long *pDestinationHeight) -{ - CheckPointer(pDestinationHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - GetTargetRect(&DestinationRect); - *pDestinationHeight = HEIGHT(&DestinationRect); - return NOERROR; -} - - -// Reset the source rectangle to the full video dimensions - -STDMETHODIMP CBaseControlVideo::SetDefaultSourcePosition() -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - HRESULT hr = SetDefaultSourceRect(); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return S_OK if we're using the default source otherwise S_FALSE - -STDMETHODIMP CBaseControlVideo::IsUsingDefaultSource() -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - return IsDefaultSourceRect(); -} - - -// Reset the video renderer to use the entire playback area - -STDMETHODIMP CBaseControlVideo::SetDefaultDestinationPosition() -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - HRESULT hr = SetDefaultTargetRect(); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return S_OK if we're using the default target otherwise S_FALSE - -STDMETHODIMP CBaseControlVideo::IsUsingDefaultDestination() -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - return IsDefaultTargetRect(); -} - - -// Return a copy of the current image in the video renderer - -STDMETHODIMP -CBaseControlVideo::GetCurrentImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pVideoImage) -{ - CheckPointer(pBufferSize,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - FILTER_STATE State; - - // Make sure we are in a paused state - - if (pVideoImage != NULL) { - m_pFilter->GetState(0,&State); - if (State != State_Paused) { - return VFW_E_NOT_PAUSED; - } - return GetStaticImage(pBufferSize,pVideoImage); - } - - // Just return the memory required - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - RECT SourceRect; - GetSourceRect(&SourceRect); - return GetImageSize(pVideoInfo,pBufferSize,&SourceRect); -} - - -// An application has two ways of using GetCurrentImage, one is to pass a real -// buffer which should be filled with the current image. The other is to pass -// a NULL buffer pointer which is interpreted as asking us to return how much -// memory is required for the image. The constraints for when the latter can -// be called are much looser. To calculate the memory required we synthesize -// a VIDEOINFO that takes into account the source rectangle that's being used - -HRESULT CBaseControlVideo::GetImageSize(__in VIDEOINFOHEADER *pVideoInfo, - __out long *pBufferSize, - __in RECT *pSourceRect) -{ - NOTE("Entering GetImageSize"); - ASSERT(pSourceRect); - - // Check we have the correct input parameters - - if (pSourceRect == NULL || - pVideoInfo == NULL || - pBufferSize == NULL) { - - return E_UNEXPECTED; - } - - // Is the data format compatible - - if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { - if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { - return E_INVALIDARG; - } - } - - ASSERT(IsRectEmpty(pSourceRect) == FALSE); - - BITMAPINFOHEADER bih; - bih.biWidth = WIDTH(pSourceRect); - bih.biHeight = HEIGHT(pSourceRect); - bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; - LONG Size = DIBSIZE(bih); - Size += GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; - *pBufferSize = Size; - - return NOERROR; -} - - -// Given an IMediaSample containing a linear buffer with an image and a type -// describing the bitmap make a rendering of the image into the output buffer -// This may be called by derived classes who render typical video images to -// handle the IBasicVideo GetCurrentImage method. The pVideoImage pointer may -// be NULL when passed to GetCurrentImage in which case GetImageSize will be -// called instead, which will just do the calculation of the memory required - -HRESULT CBaseControlVideo::CopyImage(IMediaSample *pMediaSample, - __in VIDEOINFOHEADER *pVideoInfo, - __inout long *pBufferSize, - __out_bcount_part(*pBufferSize, *pBufferSize) BYTE *pVideoImage, - __in RECT *pSourceRect) -{ - NOTE("Entering CopyImage"); - ASSERT(pSourceRect); - BYTE *pCurrentImage; - - // Check we have an image to copy - - if (pMediaSample == NULL || pSourceRect == NULL || - pVideoInfo == NULL || pVideoImage == NULL || - pBufferSize == NULL) { - - return E_UNEXPECTED; - } - - // Is the data format compatible - - if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { - if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { - return E_INVALIDARG; - } - } - - if (*pBufferSize < 0) { - return E_INVALIDARG; - } - - // Arbitrarily large size to prevent integer overflow problems - if (pVideoInfo->bmiHeader.biSize > 4096) - { - return E_INVALIDARG; - } - - ASSERT(IsRectEmpty(pSourceRect) == FALSE); - - BITMAPINFOHEADER bih; - bih.biWidth = WIDTH(pSourceRect); - bih.biHeight = HEIGHT(pSourceRect); - bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; - DWORD Size = GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; - DWORD Total; - DWORD dwDibSize; - - if( !ValidateBitmapInfoHeader( HEADER(pVideoInfo), Size)) { - return E_INVALIDARG; - } - - // ValidateBitmapInfoHeader checks this but for some reason code scanning - // tools aren't picking up the annotation - __analysis_assume(Size >= sizeof(BITMAPINFOHEADER)); - - if (FAILED(SAFE_DIBSIZE(&bih, &dwDibSize))) { - return E_INVALIDARG; - } - - if (FAILED(DWordAdd(Size, dwDibSize, &Total))) { - return E_INVALIDARG; - } - - // Make sure we have a large enough buffer - - if ((DWORD)*pBufferSize < Total) { - return E_OUTOFMEMORY; - } - - // Copy the BITMAPINFO - - CopyMemory((PVOID)pVideoImage, (PVOID)&pVideoInfo->bmiHeader, Size); - ((BITMAPINFOHEADER *)pVideoImage)->biWidth = WIDTH(pSourceRect); - ((BITMAPINFOHEADER *)pVideoImage)->biHeight = HEIGHT(pSourceRect); - ((BITMAPINFOHEADER *)pVideoImage)->biSizeImage = DIBSIZE(bih); - BYTE *pImageData = pVideoImage + Size; - - // Get the pointer to it's image data - - HRESULT hr = pMediaSample->GetPointer(&pCurrentImage); - if (FAILED(hr)) { - return hr; - } - - // Now we are ready to start copying the source scan lines - - LONG ScanLine = (pVideoInfo->bmiHeader.biBitCount / 8) * WIDTH(pSourceRect); - LONG LinesToSkip = pVideoInfo->bmiHeader.biHeight; - LinesToSkip -= pSourceRect->top + HEIGHT(pSourceRect); - pCurrentImage += LinesToSkip * DIBWIDTHBYTES(pVideoInfo->bmiHeader); - pCurrentImage += pSourceRect->left * (pVideoInfo->bmiHeader.biBitCount / 8); - - // Even money on this GP faulting sometime... - - for (LONG Line = 0;Line < HEIGHT(pSourceRect);Line++) { - CopyMemory((PVOID)pImageData, (PVOID)pCurrentImage, ScanLine); - pImageData += DIBWIDTHBYTES(*(BITMAPINFOHEADER *)pVideoImage); - pCurrentImage += DIBWIDTHBYTES(pVideoInfo->bmiHeader); - } - return NOERROR; -} - - -// Called when we change media types either during connection or dynamically -// We inform the filter graph and therefore the application that the video -// size may have changed, we don't bother looking to see if it really has as -// we leave that to the application - the dimensions are the event parameters - -HRESULT CBaseControlVideo::OnVideoSizeChange() -{ - // Get the video format from the derived class - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - WORD Width = (WORD) pVideoInfo->bmiHeader.biWidth; - WORD Height = (WORD) pVideoInfo->bmiHeader.biHeight; - - return m_pFilter->NotifyEvent(EC_VIDEO_SIZE_CHANGED, - MAKELPARAM(Width,Height), - MAKEWPARAM(0,0)); -} - - -// Set the video source rectangle. We must check the source rectangle against -// the actual video dimensions otherwise when we come to draw the pictures we -// get access violations as GDI tries to touch data outside of the image data -// Although we store the rectangle in left, top, right and bottom coordinates -// instead of left, top, width and height as OLE uses we do take into account -// that the rectangle is used up to, but not including, the right column and -// bottom row of pixels, see the Win32 documentation on RECT for more details - -HRESULT CBaseControlVideo::CheckSourceRect(__in RECT *pSourceRect) -{ - CheckPointer(pSourceRect,E_POINTER); - LONG Width,Height; - GetVideoSize(&Width,&Height); - - // Check the coordinates are greater than zero - // and that the rectangle is valid (leftleft >= pSourceRect->right) || - (pSourceRect->left < 0) || - (pSourceRect->top >= pSourceRect->bottom) || - (pSourceRect->top < 0)) { - - return E_INVALIDARG; - } - - // Check the coordinates are less than the extents - - if ((pSourceRect->right > Width) || - (pSourceRect->bottom > Height)) { - - return E_INVALIDARG; - } - return NOERROR; -} - - -// Check the target rectangle has some valid coordinates, which amounts to -// little more than checking the destination rectangle isn't empty. Derived -// classes may call this when they have their SetTargetRect method called to -// check the rectangle validity, we do not update the rectangles passed in -// Although we store the rectangle in left, top, right and bottom coordinates -// instead of left, top, width and height as OLE uses we do take into account -// that the rectangle is used up to, but not including, the right column and -// bottom row of pixels, see the Win32 documentation on RECT for more details - -HRESULT CBaseControlVideo::CheckTargetRect(__in RECT *pTargetRect) -{ - // Check the pointer is valid - - if (pTargetRect == NULL) { - return E_POINTER; - } - - // These overflow the WIDTH and HEIGHT checks - - if (pTargetRect->left > pTargetRect->right || - pTargetRect->top > pTargetRect->bottom) { - return E_INVALIDARG; - } - - // Check the rectangle has valid coordinates - - if (WIDTH(pTargetRect) <= 0 || HEIGHT(pTargetRect) <= 0) { - return E_INVALIDARG; - } - - ASSERT(IsRectEmpty(pTargetRect) == FALSE); - return NOERROR; -} - +//------------------------------------------------------------------------------ +// File: WinCtrl.cpp +// +// Desc: DirectShow base classes - implements video control interface class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include +#include "checkbmi.h" + +// The control interface methods require us to be connected + +#define CheckConnected(pin,code) \ +{ \ + if (pin == NULL) { \ + ASSERT(!TEXT("Pin not set")); \ + } else if (pin->IsConnected() == FALSE) { \ + return (code); \ + } \ +} + +// This checks to see whether the window has a drain. An application can in +// most environments set the owner/parent of windows so that they appear in +// a compound document context (for example). In this case, the application +// would probably like to be told of any keyboard/mouse messages. Therefore +// we pass these messages on untranslated, returning TRUE if we're successful + +BOOL WINAPI PossiblyEatMessage(HWND hwndDrain, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (hwndDrain != NULL && !InSendMessage()) + { + switch (uMsg) + { + case WM_CHAR: + case WM_DEADCHAR: + case WM_KEYDOWN: + case WM_KEYUP: + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEACTIVATE: + case WM_MOUSEMOVE: + // If we pass this on we don't get any mouse clicks + //case WM_NCHITTEST: + case WM_NCLBUTTONDBLCLK: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCMBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMOUSEMOVE: + case WM_NCRBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + + DbgLog((LOG_TRACE, 2, TEXT("Forwarding %x to drain"))); + PostMessage(hwndDrain, uMsg, wParam, lParam); + + return TRUE; + } + } + return FALSE; +} + + +// This class implements the IVideoWindow control functions (dual interface) +// we support a large number of properties and methods designed to allow the +// client (whether it be an automation controller or a C/C++ application) to +// set and get a number of window related properties such as it's position. +// We also support some methods that duplicate the properties but provide a +// more direct and efficient mechanism as many values may be changed in one + +CBaseControlWindow::CBaseControlWindow( + __inout CBaseFilter *pFilter, // Owning filter + __in CCritSec *pInterfaceLock, // Locking object + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // Normal COM ownership + __inout HRESULT *phr) : // OLE return code + + CBaseVideoWindow(pName,pUnk), + m_pInterfaceLock(pInterfaceLock), + m_hwndOwner(NULL), + m_hwndDrain(NULL), + m_bAutoShow(TRUE), + m_pFilter(pFilter), + m_bCursorHidden(FALSE), + m_pPin(NULL) +{ + ASSERT(m_pFilter); + ASSERT(m_pInterfaceLock); + ASSERT(phr); + m_BorderColour = VIDEO_COLOUR; +} + + +// Set the title caption on the base window, we don't do any field checking +// as we really don't care what title they intend to have. We can always get +// it back again later with GetWindowText. The only other complication is to +// do the necessary string conversions between ANSI and OLE Unicode strings + +STDMETHODIMP CBaseControlWindow::put_Caption(__in BSTR strCaption) +{ + CheckPointer((PVOID)strCaption,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); +#ifdef UNICODE + SetWindowText(m_hwnd, strCaption); +#else + CHAR Caption[CAPTION]; + + WideCharToMultiByte(CP_ACP,0,strCaption,-1,Caption,CAPTION,NULL,NULL); + SetWindowText(m_hwnd, Caption); +#endif + return NOERROR; +} + + +// Get the current base window title caption, once again we do no real field +// checking. We allocate a string for the window title to be filled in with +// which ensures the interface doesn't fiddle around with getting memory. A +// BSTR is a normal C string with the length at position (-1), we use the +// WriteBSTR helper function to create the caption to try and avoid OLE32 + +STDMETHODIMP CBaseControlWindow::get_Caption(__out BSTR *pstrCaption) +{ + CheckPointer(pstrCaption,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + WCHAR WideCaption[CAPTION]; + +#ifdef UNICODE + GetWindowText(m_hwnd,WideCaption,CAPTION); +#else + // Convert the ASCII caption to a UNICODE string + + TCHAR Caption[CAPTION]; + GetWindowText(m_hwnd,Caption,CAPTION); + MultiByteToWideChar(CP_ACP,0,Caption,-1,WideCaption,CAPTION); +#endif + return WriteBSTR(pstrCaption,WideCaption); +} + + +// Set the window style using GWL_EXSTYLE + +STDMETHODIMP CBaseControlWindow::put_WindowStyleEx(long WindowStyleEx) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Should we be taking off WS_EX_TOPMOST + + if (GetWindowLong(m_hwnd,GWL_EXSTYLE) & WS_EX_TOPMOST) { + if ((WindowStyleEx & WS_EX_TOPMOST) == 0) { + SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) FALSE,(LPARAM) 0); + } + } + + // Likewise should we be adding WS_EX_TOPMOST + + if (WindowStyleEx & WS_EX_TOPMOST) { + SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) TRUE,(LPARAM) 0); + WindowStyleEx &= (~WS_EX_TOPMOST); + if (WindowStyleEx == 0) return NOERROR; + } + return DoSetWindowStyle(WindowStyleEx,GWL_EXSTYLE); +} + + +// Gets the current GWL_EXSTYLE base window style + +STDMETHODIMP CBaseControlWindow::get_WindowStyleEx(__out long *pWindowStyleEx) +{ + CheckPointer(pWindowStyleEx,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoGetWindowStyle(pWindowStyleEx,GWL_EXSTYLE); +} + + +// Set the window style using GWL_STYLE + +STDMETHODIMP CBaseControlWindow::put_WindowStyle(long WindowStyle) +{ + // These styles cannot be changed dynamically + + if ((WindowStyle & WS_DISABLED) || + (WindowStyle & WS_ICONIC) || + (WindowStyle & WS_MAXIMIZE) || + (WindowStyle & WS_MINIMIZE) || + (WindowStyle & WS_HSCROLL) || + (WindowStyle & WS_VSCROLL)) { + + return E_INVALIDARG; + } + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoSetWindowStyle(WindowStyle,GWL_STYLE); +} + + +// Get the current GWL_STYLE base window style + +STDMETHODIMP CBaseControlWindow::get_WindowStyle(__out long *pWindowStyle) +{ + CheckPointer(pWindowStyle,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoGetWindowStyle(pWindowStyle,GWL_STYLE); +} + + +// Change the base window style or the extended styles depending on whether +// WindowLong is GWL_STYLE or GWL_EXSTYLE. We must call SetWindowPos to have +// the window displayed in it's new style after the change which is a little +// tricky if the window is not currently visible as we realise it offscreen. +// In most cases the client will call get_WindowStyle before they call this +// and then AND and OR in extra bit settings according to the requirements + +HRESULT CBaseControlWindow::DoSetWindowStyle(long Style,long WindowLong) +{ + RECT WindowRect; + + // Get the window's visibility before setting the style + BOOL bVisible = IsWindowVisible(m_hwnd); + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + // Set the new style flags for the window + SetWindowLong(m_hwnd,WindowLong,Style); + UINT WindowFlags = SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE; + WindowFlags |= SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; + + // Show the window again in the current position + + if (bVisible == TRUE) { + + SetWindowPos(m_hwnd, // Base window handle + HWND_TOP, // Just a place holder + 0,0,0,0, // Leave size and position + WindowFlags); // Just draw it again + + return NOERROR; + } + + // Move the window offscreen so the user doesn't see the changes + + MoveWindow((HWND) m_hwnd, // Base window handle + GetSystemMetrics(SM_CXSCREEN), // Current desktop width + GetSystemMetrics(SM_CYSCREEN), // Likewise it's height + WIDTH(&WindowRect), // Use the same width + HEIGHT(&WindowRect), // Keep height same to + TRUE); // May as well repaint + + // Now show the previously hidden window + + SetWindowPos(m_hwnd, // Base window handle + HWND_TOP, // Just a place holder + 0,0,0,0, // Leave size and position + WindowFlags); // Just draw it again + + ShowWindow(m_hwnd,SW_HIDE); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + MoveWindow((HWND) m_hwnd, // Base window handle + WindowRect.left, // Existing x coordinate + WindowRect.top, // Existing y coordinate + WIDTH(&WindowRect), // Use the same width + HEIGHT(&WindowRect), // Keep height same to + TRUE); // May as well repaint + + return NOERROR; +} + + +// Get the current base window style (either GWL_STYLE or GWL_EXSTYLE) + +HRESULT CBaseControlWindow::DoGetWindowStyle(__out long *pStyle,long WindowLong) +{ + *pStyle = GetWindowLong(m_hwnd,WindowLong); + return NOERROR; +} + + +// Change the visibility of the base window, this takes the same parameters +// as the ShowWindow Win32 API does, so the client can have the window hidden +// or shown, minimised to an icon, or maximised to play in full screen mode +// We pass the request on to the base window to actually make the change + +STDMETHODIMP CBaseControlWindow::put_WindowState(long WindowState) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + DoShowWindow(WindowState); + return NOERROR; +} + + +// Get the current window state, this function returns a subset of the SW bit +// settings available in ShowWindow, if the window is visible then SW_SHOW is +// set, if it is hidden then the SW_HIDDEN is set, if it is either minimised +// or maximised then the SW_MINIMIZE or SW_MAXIMIZE is set respectively. The +// other SW bit settings are really set commands not readable output values + +STDMETHODIMP CBaseControlWindow::get_WindowState(__out long *pWindowState) +{ + CheckPointer(pWindowState,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + ASSERT(pWindowState); + *pWindowState = FALSE; + + // Is the window visible, a window is termed visible if it is somewhere on + // the current desktop even if it is completely obscured by other windows + // so the flag is a style for each window set with the WS_VISIBLE bit + + if (IsWindowVisible(m_hwnd) == TRUE) { + + // Is the base window iconic + if (IsIconic(m_hwnd) == TRUE) { + *pWindowState |= SW_MINIMIZE; + } + + // Has the window been maximised + else if (IsZoomed(m_hwnd) == TRUE) { + *pWindowState |= SW_MAXIMIZE; + } + + // Window is normal + else { + *pWindowState |= SW_SHOW; + } + + } else { + *pWindowState |= SW_HIDE; + } + return NOERROR; +} + + +// This makes sure that any palette we realise in the base window (through a +// media type or through the overlay interface) is done in the background and +// is therefore mapped to existing device entries rather than taking it over +// as it will do when we this window gets the keyboard focus. An application +// uses this to make sure it doesn't have it's palette removed by the window + +STDMETHODIMP CBaseControlWindow::put_BackgroundPalette(long BackgroundPalette) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cWindowLock(&m_WindowLock); + + // Check this is a valid automation boolean type + + if (BackgroundPalette != OATRUE) { + if (BackgroundPalette != OAFALSE) { + return E_INVALIDARG; + } + } + + // Make sure the window realises any palette it has again + + m_bBackground = (BackgroundPalette == OATRUE ? TRUE : FALSE); + PostMessage(m_hwnd,m_RealizePalette,0,0); + PaintWindow(FALSE); + + return NOERROR; +} + + +// This returns the current background realisation setting + +STDMETHODIMP +CBaseControlWindow::get_BackgroundPalette(__out long *pBackgroundPalette) +{ + CheckPointer(pBackgroundPalette,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cWindowLock(&m_WindowLock); + + // Get the current background palette setting + + *pBackgroundPalette = (m_bBackground == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Change the visibility of the base window + +STDMETHODIMP CBaseControlWindow::put_Visible(long Visible) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (Visible != OATRUE) { + if (Visible != OAFALSE) { + return E_INVALIDARG; + } + } + + // Convert the boolean visibility into SW_SHOW and SW_HIDE + + INT Mode = (Visible == OATRUE ? SW_SHOWNORMAL : SW_HIDE); + DoShowWindow(Mode); + return NOERROR; +} + + +// Return OATRUE if the window is currently visible otherwise OAFALSE + +STDMETHODIMP CBaseControlWindow::get_Visible(__out long *pVisible) +{ + CheckPointer(pVisible,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // See if the base window has a WS_VISIBLE style - this will return TRUE + // even if the window is completely obscured by other desktop windows, we + // return FALSE if the window is not showing because of earlier calls + + BOOL Mode = IsWindowVisible(m_hwnd); + *pVisible = (Mode == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Change the left position of the base window. This keeps the window width +// and height properties the same so it effectively shunts the window left or +// right accordingly - there is the Width property to change that dimension + +STDMETHODIMP CBaseControlWindow::put_Left(long Left) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Get the current window position in a RECT + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + Left, // New left position + WindowRect.top, // Leave top alone + WindowRect.right, // The WIDTH (not right) + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window options + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window left position + +STDMETHODIMP CBaseControlWindow::get_Left(__out long *pLeft) +{ + CheckPointer(pLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pLeft = WindowRect.left; + return NOERROR; +} + + +// Change the current width of the base window. This property complements the +// left position property so we must keep the left edge constant and expand or +// contract to the right, the alternative would be to change the left edge so +// keeping the right edge constant but this is maybe a little more intuitive + +STDMETHODIMP CBaseControlWindow::put_Width(long Width) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + // This seems to have a bug in that calling SetWindowPos on a window with + // just the width changing causes it to ignore the width that you pass in + // and sets it to a mimimum value of 110 pixels wide (Windows NT 3.51) + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + WindowRect.top, // Leave top alone + Width, // New WIDTH dimension + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window options + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window width + +STDMETHODIMP CBaseControlWindow::get_Width(__out long *pWidth) +{ + CheckPointer(pWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pWidth = WindowRect.right - WindowRect.left; + return NOERROR; +} + + +// This allows the client program to change the top position for the window in +// the same way that changing the left position does not affect the width of +// the image so changing the top position does not affect the window height + +STDMETHODIMP CBaseControlWindow::put_Top(long Top) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Get the current window position in a RECT + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + Top, // New top position + WindowRect.right, // The WIDTH (not right) + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window flags + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window top position + +STDMETHODIMP CBaseControlWindow::get_Top(long *pTop) +{ + CheckPointer(pTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pTop = WindowRect.top; + return NOERROR; +} + + +// Change the height of the window, this complements the top property so when +// we change this we must keep the top position for the base window, as said +// before we could keep the bottom and grow upwards although this is perhaps +// a little more intuitive since we already have a top position property + +STDMETHODIMP CBaseControlWindow::put_Height(long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + WindowRect.top, // Leave top alone + WindowRect.right, // The WIDTH (not right) + Height, // New height dimension + WindowFlags); // Show window flags + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window height + +STDMETHODIMP CBaseControlWindow::get_Height(__out long *pHeight) +{ + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pHeight = WindowRect.bottom - WindowRect.top; + return NOERROR; +} + + +// This can be called to change the owning window. Setting the owner is done +// through this function, however to make the window a true child window the +// style must also be set to WS_CHILD. After resetting the owner to NULL an +// application should also set the style to WS_OVERLAPPED | WS_CLIPCHILDREN. + +// We cannot lock the object here because the SetParent causes an interthread +// SendMessage to the owner window. If they are in GetState we will sit here +// incomplete with the critical section locked therefore blocking out source +// filter threads from accessing us. Because the source thread can't enter us +// it can't get buffers or call EndOfStream so the GetState will not complete + +STDMETHODIMP CBaseControlWindow::put_Owner(OAHWND Owner) +{ + // Check we are connected otherwise reject the call + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + m_hwndOwner = (HWND) Owner; + HWND hwndParent = m_hwndOwner; + + // Add or remove WS_CHILD as appropriate + + LONG Style = GetWindowLong(m_hwnd,GWL_STYLE); + if (Owner == NULL) { + Style &= (~WS_CHILD); + } else { + Style |= (WS_CHILD); + } + SetWindowLong(m_hwnd,GWL_STYLE,Style); + + // Don't call this with the filter locked + + SetParent(m_hwnd,hwndParent); + + PaintWindow(TRUE); + NOTE1("Changed parent %lx",hwndParent); + + return NOERROR; +} + + +// This complements the put_Owner to get the current owning window property +// we always return NOERROR although the returned window handle may be NULL +// to indicate no owning window (the desktop window doesn't qualify as one) +// If an application sets the owner we call SetParent, however that returns +// NULL until the WS_CHILD bit is set on, so we store the owner internally + +STDMETHODIMP CBaseControlWindow::get_Owner(__out OAHWND *Owner) +{ + CheckPointer(Owner,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Owner = (OAHWND) m_hwndOwner; + return NOERROR; +} + + +// And renderer supporting IVideoWindow may have an HWND set who will get any +// keyboard and mouse messages we receive posted on to them. This is separate +// from setting an owning window. By separating the two, applications may get +// messages sent on even when they have set no owner (perhaps it's maximised) + +STDMETHODIMP CBaseControlWindow::put_MessageDrain(OAHWND Drain) +{ + // Check we are connected otherwise reject the call + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + m_hwndDrain = (HWND) Drain; + return NOERROR; +} + + +// Return the current message drain + +STDMETHODIMP CBaseControlWindow::get_MessageDrain(__out OAHWND *Drain) +{ + CheckPointer(Drain,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Drain = (OAHWND) m_hwndDrain; + return NOERROR; +} + + +// This is called by the filter graph to inform us of a message we should know +// is being sent to our owning window. We have this because as a child window +// we do not get certain messages that are only sent to top level windows. We +// must see the palette changed/changing/query messages so that we know if we +// have the foreground palette or not. We pass the message on to our window +// using SendMessage - this will cause an interthread send message to occur + +STDMETHODIMP +CBaseControlWindow::NotifyOwnerMessage(OAHWND hwnd, // Window handle + long uMsg, // Message ID + LONG_PTR wParam, // Parameters + LONG_PTR lParam) // for message +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Only interested in these Windows messages + + switch (uMsg) { + + case WM_SYSCOLORCHANGE: + case WM_PALETTECHANGED: + case WM_PALETTEISCHANGING: + case WM_QUERYNEWPALETTE: + case WM_DEVMODECHANGE: + case WM_DISPLAYCHANGE: + case WM_ACTIVATEAPP: + + // If we do not have an owner then ignore + + if (m_hwndOwner == NULL) { + return NOERROR; + } + SendMessage(m_hwnd,uMsg,(WPARAM)wParam,(LPARAM)lParam); + break; + + // do NOT fwd WM_MOVE. the parameters are the location of the parent + // window, NOT what the renderer should be looking at. But we need + // to make sure the overlay is moved with the parent window, so we + // do this. + case WM_MOVE: + PostMessage(m_hwnd,WM_PAINT,0,0); + break; + } + return NOERROR; +} + + +// Allow an application to have us set the base window in the foreground. We +// have this because it is difficult for one thread to do do this to a window +// owned by another thread. We ask the base window class to do the real work + +STDMETHODIMP CBaseControlWindow::SetWindowForeground(long Focus) +{ + // Check this is a valid automation boolean type + + if (Focus != OATRUE) { + if (Focus != OAFALSE) { + return E_INVALIDARG; + } + } + + // We shouldn't lock as this sends a message + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bFocus = (Focus == OATRUE ? TRUE : FALSE); + DoSetWindowForeground(bFocus); + + return NOERROR; +} + + +// This allows a client to set the complete window size and position in one +// atomic operation. The same affect can be had by changing each dimension +// in turn through their individual properties although some flashing will +// occur as each of them gets updated (they are better set at design time) + +STDMETHODIMP +CBaseControlWindow::SetWindowPosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + + // Set the new size and position + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + ASSERT(IsWindow(m_hwnd)); + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + Left, // Left position + Top, // Top position + Width, // Window width + Height, // Window height + WindowFlags); // Show window flags + ASSERT(bSuccess); +#ifdef _DEBUG + DbgLog((LOG_TRACE, 1, TEXT("SWP failed error %d"), GetLastError())); +#endif + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// This complements the SetWindowPosition to return the current window place +// in device coordinates. As before the same information can be retrived by +// calling the property get functions individually but this is atomic and is +// therefore more suitable to a live environment rather than design time + +STDMETHODIMP +CBaseControlWindow::GetWindowPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + // Get the current window coordinates + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + // Convert the RECT into left,top,width and height values + + *pLeft = WindowRect.left; + *pTop = WindowRect.top; + *pWidth = WindowRect.right - WindowRect.left; + *pHeight = WindowRect.bottom - WindowRect.top; + + return NOERROR; +} + + +// When a window is maximised or iconic calling GetWindowPosition will return +// the current window position (likewise for the properties). However if the +// restored size (ie the size we'll return to when normally shown) is needed +// then this should be used. When in a normal position (neither iconic nor +// maximised) then this returns the same coordinates as GetWindowPosition + +STDMETHODIMP +CBaseControlWindow::GetRestorePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Use GetWindowPlacement to find the restore position + + WINDOWPLACEMENT Place; + Place.length = sizeof(WINDOWPLACEMENT); + EXECUTE_ASSERT(GetWindowPlacement(m_hwnd,&Place)); + + RECT WorkArea; + + // We must take into account any task bar present + + if (SystemParametersInfo(SPI_GETWORKAREA,0,&WorkArea,FALSE) == TRUE) { + if (GetParent(m_hwnd) == NULL) { + Place.rcNormalPosition.top += WorkArea.top; + Place.rcNormalPosition.bottom += WorkArea.top; + Place.rcNormalPosition.left += WorkArea.left; + Place.rcNormalPosition.right += WorkArea.left; + } + } + + // Convert the RECT into left,top,width and height values + + *pLeft = Place.rcNormalPosition.left; + *pTop = Place.rcNormalPosition.top; + *pWidth = Place.rcNormalPosition.right - Place.rcNormalPosition.left; + *pHeight = Place.rcNormalPosition.bottom - Place.rcNormalPosition.top; + + return NOERROR; +} + + +// Return the current border colour, if we are playing something to a subset +// of the base window display there is an outside area exposed. The default +// action is to paint this colour in the Windows background colour (defined +// as value COLOR_WINDOW) We reset to this default when we're disconnected + +STDMETHODIMP CBaseControlWindow::get_BorderColor(__out long *Color) +{ + CheckPointer(Color,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Color = (long) m_BorderColour; + return NOERROR; +} + + +// This can be called to set the current border colour + +STDMETHODIMP CBaseControlWindow::put_BorderColor(long Color) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Have the window repainted with the new border colour + + m_BorderColour = (COLORREF) Color; + PaintWindow(TRUE); + return NOERROR; +} + + +// Delegate fullscreen handling to plug in distributor + +STDMETHODIMP CBaseControlWindow::get_FullScreenMode(__out long *FullScreenMode) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CheckPointer(FullScreenMode,E_POINTER); + return E_NOTIMPL; +} + + +// Delegate fullscreen handling to plug in distributor + +STDMETHODIMP CBaseControlWindow::put_FullScreenMode(long FullScreenMode) +{ + return E_NOTIMPL; +} + + +// This sets the auto show property, this property causes the base window to +// be displayed whenever we change state. This allows an application to have +// to do nothing to have the window appear but still allow them to change the +// default behaviour if for example they want to keep it hidden for longer + +STDMETHODIMP CBaseControlWindow::put_AutoShow(long AutoShow) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (AutoShow != OATRUE) { + if (AutoShow != OAFALSE) { + return E_INVALIDARG; + } + } + + m_bAutoShow = (AutoShow == OATRUE ? TRUE : FALSE); + return NOERROR; +} + + +// This can be called to get the current auto show flag. The flag is updated +// when we connect and disconnect and through this interface all of which are +// controlled and serialised by means of the main renderer critical section + +STDMETHODIMP CBaseControlWindow::get_AutoShow(__out long *AutoShow) +{ + CheckPointer(AutoShow,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *AutoShow = (m_bAutoShow == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Return the minimum ideal image size for the current video. This may differ +// to the actual video dimensions because we may be using DirectDraw hardware +// that has specific stretching requirements. For example the Cirrus Logic +// cards have a minimum stretch factor depending on the overlay surface size + +STDMETHODIMP +CBaseControlWindow::GetMinIdealImageSize(__out long *pWidth,__out long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + FILTER_STATE State; + + // Must not be stopped for this to work correctly + + m_pFilter->GetState(0,&State); + if (State == State_Stopped) { + return VFW_E_WRONG_STATE; + } + + RECT DefaultRect = GetDefaultRect(); + *pWidth = WIDTH(&DefaultRect); + *pHeight = HEIGHT(&DefaultRect); + return NOERROR; +} + + +// Return the maximum ideal image size for the current video. This may differ +// to the actual video dimensions because we may be using DirectDraw hardware +// that has specific stretching requirements. For example the Cirrus Logic +// cards have a maximum stretch factor depending on the overlay surface size + +STDMETHODIMP +CBaseControlWindow::GetMaxIdealImageSize(__out long *pWidth,__out long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + FILTER_STATE State; + + // Must not be stopped for this to work correctly + + m_pFilter->GetState(0,&State); + if (State == State_Stopped) { + return VFW_E_WRONG_STATE; + } + + RECT DefaultRect = GetDefaultRect(); + *pWidth = WIDTH(&DefaultRect); + *pHeight = HEIGHT(&DefaultRect); + return NOERROR; +} + + +// Allow an application to hide the cursor on our window + +STDMETHODIMP +CBaseControlWindow::HideCursor(long HideCursor) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (HideCursor != OATRUE) { + if (HideCursor != OAFALSE) { + return E_INVALIDARG; + } + } + + m_bCursorHidden = (HideCursor == OATRUE ? TRUE : FALSE); + return NOERROR; +} + + +// Returns whether we have the cursor hidden or not + +STDMETHODIMP CBaseControlWindow::IsCursorHidden(__out long *CursorHidden) +{ + CheckPointer(CursorHidden,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *CursorHidden = (m_bCursorHidden == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// This class implements the IBasicVideo control functions (dual interface) +// we support a large number of properties and methods designed to allow the +// client (whether it be an automation controller or a C/C++ application) to +// set and get a number of video related properties such as the native video +// size. We support some methods that duplicate the properties but provide a +// more direct and efficient mechanism as many values may be changed in one + +CBaseControlVideo::CBaseControlVideo( + __inout CBaseFilter *pFilter, // Owning filter + __in CCritSec *pInterfaceLock, // Locking object + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // Normal COM ownership + __inout HRESULT *phr) : // OLE return code + + CBaseBasicVideo(pName,pUnk), + m_pFilter(pFilter), + m_pInterfaceLock(pInterfaceLock), + m_pPin(NULL) +{ + ASSERT(m_pFilter); + ASSERT(m_pInterfaceLock); + ASSERT(phr); +} + +// Return an approximate average time per frame + +STDMETHODIMP CBaseControlVideo::get_AvgTimePerFrame(__out REFTIME *pAvgTimePerFrame) +{ + CheckPointer(pAvgTimePerFrame,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + COARefTime AvgTime(pVideoInfo->AvgTimePerFrame); + *pAvgTimePerFrame = (REFTIME) AvgTime; + + return NOERROR; +} + + +// Return an approximate bit rate for the video + +STDMETHODIMP CBaseControlVideo::get_BitRate(__out long *pBitRate) +{ + CheckPointer(pBitRate,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pBitRate = pVideoInfo->dwBitRate; + return NOERROR; +} + + +// Return an approximate bit error rate + +STDMETHODIMP CBaseControlVideo::get_BitErrorRate(__out long *pBitErrorRate) +{ + CheckPointer(pBitErrorRate,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pBitErrorRate = pVideoInfo->dwBitErrorRate; + return NOERROR; +} + + +// This returns the current video width + +STDMETHODIMP CBaseControlVideo::get_VideoWidth(__out long *pVideoWidth) +{ + CheckPointer(pVideoWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pVideoWidth = pVideoInfo->bmiHeader.biWidth; + return NOERROR; +} + + +// This returns the current video height + +STDMETHODIMP CBaseControlVideo::get_VideoHeight(__out long *pVideoHeight) +{ + CheckPointer(pVideoHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pVideoHeight = pVideoInfo->bmiHeader.biHeight; + return NOERROR; +} + + +// This returns the current palette the video is using as an array allocated +// by the user. To remain consistent we use PALETTEENTRY fields to return the +// colours in rather than RGBQUADs that multimedia decided to use. The memory +// is allocated by the user so we simple copy each in turn. We check that the +// number of entries requested and the start position offset are both valid +// If the number of entries evaluates to zero then we return an S_FALSE code + +STDMETHODIMP CBaseControlVideo::GetVideoPaletteEntries(long StartIndex, + long Entries, + __out long *pRetrieved, + __out_ecount_part(Entries, *pRetrieved) long *pPalette) +{ + CheckPointer(pRetrieved,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + CMediaType MediaType; + + // Get the video format from the derived class + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); + + // Is the current format palettised + + if (PALETTISED(pVideoInfo) == FALSE) { + *pRetrieved = 0; + return VFW_E_NO_PALETTE_AVAILABLE; + } + + // Do they just want to know how many are available + + if (pPalette == NULL) { + *pRetrieved = pHeader->biClrUsed; + return NOERROR; + } + + // Make sure the start position is a valid offset + + if (StartIndex >= (LONG) pHeader->biClrUsed || StartIndex < 0) { + *pRetrieved = 0; + return E_INVALIDARG; + } + + // Correct the number we can retrieve + + long Available = (long)pHeader->biClrUsed - StartIndex; + *pRetrieved = std::max(0l, std::min(Available, Entries)); + if (*pRetrieved == 0) { + return S_FALSE; + } + + // Copy the palette entries to the output buffer + + PALETTEENTRY *pEntries = (PALETTEENTRY *) pPalette; + RGBQUAD *pColours = COLORS(pVideoInfo) + StartIndex; + + for (LONG Count = 0;Count < *pRetrieved;Count++) { + pEntries[Count].peRed = pColours[Count].rgbRed; + pEntries[Count].peGreen = pColours[Count].rgbGreen; + pEntries[Count].peBlue = pColours[Count].rgbBlue; + pEntries[Count].peFlags = 0; + } + return NOERROR; +} + + +// This returns the current video dimensions as a method rather than a number +// of individual property get calls. For the same reasons as said before we +// cannot access the renderer media type directly as the window object thread +// may be updating it since dynamic format changes may change these values + +STDMETHODIMP CBaseControlVideo::GetVideoSize(__out long *pWidth,__out long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + // Get the video format from the derived class + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pWidth = pVideoInfo->bmiHeader.biWidth; + *pHeight = pVideoInfo->bmiHeader.biHeight; + return NOERROR; +} + + +// Set the source video rectangle as left,top,right and bottom coordinates +// rather than left,top,width and height as per OLE automation interfaces +// Then pass the rectangle on to the window object to set the source + +STDMETHODIMP +CBaseControlVideo::SetSourcePosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + SourceRect.left = Left; + SourceRect.top = Top; + SourceRect.right = Left + Width; + SourceRect.bottom = Top + Height; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the source rectangle in left,top,width and height rather than the +// left,top,right and bottom values that RECT uses (and which the window +// object returns through GetSourceRect) which requires a little work + +STDMETHODIMP +CBaseControlVideo::GetSourcePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) +{ + // Should check the pointers are non NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT SourceRect; + + CAutoLock cInterfaceLock(m_pInterfaceLock); + GetSourceRect(&SourceRect); + + *pLeft = SourceRect.left; + *pTop = SourceRect.top; + *pWidth = WIDTH(&SourceRect); + *pHeight = HEIGHT(&SourceRect); + + return NOERROR; +} + + +// Set the video destination as left,top,right and bottom coordinates rather +// than the left,top,width and height uses as per OLE automation interfaces +// Then pass the rectangle on to the window object to set the destination + +STDMETHODIMP +CBaseControlVideo::SetDestinationPosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + DestinationRect.left = Left; + DestinationRect.top = Top; + DestinationRect.right = Left + Width; + DestinationRect.bottom = Top + Height; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the destination rectangle in left,top,width and height rather than +// the left,top,right and bottom values that RECT uses (and which the window +// object returns through GetDestinationRect) which requires a little work + +STDMETHODIMP +CBaseControlVideo::GetDestinationPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT DestinationRect; + + CAutoLock cInterfaceLock(m_pInterfaceLock); + GetTargetRect(&DestinationRect); + + *pLeft = DestinationRect.left; + *pTop = DestinationRect.top; + *pWidth = WIDTH(&DestinationRect); + *pHeight = HEIGHT(&DestinationRect); + + return NOERROR; +} + + +// Set the source left position, the source rectangle we get back from the +// window object is a true rectangle in left,top,right and bottom positions +// so all we have to do is to update the left position and pass it back. We +// must keep the current width constant when we're updating this property + +STDMETHODIMP CBaseControlVideo::put_SourceLeft(long SourceLeft) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.right = SourceLeft + WIDTH(&SourceRect); + SourceRect.left = SourceLeft; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current left source video position + +STDMETHODIMP CBaseControlVideo::get_SourceLeft(__out long *pSourceLeft) +{ + CheckPointer(pSourceLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceLeft = SourceRect.left; + return NOERROR; +} + + +// Set the source width, we get the current source rectangle and then update +// the right position to be the left position (thereby keeping it constant) +// plus the new source width we are passed in (it expands to the right) + +STDMETHODIMP CBaseControlVideo::put_SourceWidth(long SourceWidth) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.right = SourceRect.left + SourceWidth; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current source width + +STDMETHODIMP CBaseControlVideo::get_SourceWidth(__out long *pSourceWidth) +{ + CheckPointer(pSourceWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceWidth = WIDTH(&SourceRect); + return NOERROR; +} + + +// Set the source top position - changing this property does not affect the +// current source height. So changing this shunts the source rectangle up and +// down appropriately. Changing the height complements this functionality by +// keeping the top position constant and simply changing the source height + +STDMETHODIMP CBaseControlVideo::put_SourceTop(long SourceTop) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.bottom = SourceTop + HEIGHT(&SourceRect); + SourceRect.top = SourceTop; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current top position + +STDMETHODIMP CBaseControlVideo::get_SourceTop(__out long *pSourceTop) +{ + CheckPointer(pSourceTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceTop = SourceRect.top; + return NOERROR; +} + + +// Set the source height + +STDMETHODIMP CBaseControlVideo::put_SourceHeight(long SourceHeight) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.bottom = SourceRect.top + SourceHeight; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current source height + +STDMETHODIMP CBaseControlVideo::get_SourceHeight(__out long *pSourceHeight) +{ + CheckPointer(pSourceHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceHeight = HEIGHT(&SourceRect); + return NOERROR; +} + + +// Set the target left position, the target rectangle we get back from the +// window object is a true rectangle in left,top,right and bottom positions +// so all we have to do is to update the left position and pass it back. We +// must keep the current width constant when we're updating this property + +STDMETHODIMP CBaseControlVideo::put_DestinationLeft(long DestinationLeft) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.right = DestinationLeft + WIDTH(&DestinationRect); + DestinationRect.left = DestinationLeft; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the left position for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationLeft(__out long *pDestinationLeft) +{ + CheckPointer(pDestinationLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationLeft = DestinationRect.left; + return NOERROR; +} + + +// Set the destination width + +STDMETHODIMP CBaseControlVideo::put_DestinationWidth(long DestinationWidth) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.right = DestinationRect.left + DestinationWidth; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the width for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationWidth(__out long *pDestinationWidth) +{ + CheckPointer(pDestinationWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationWidth = WIDTH(&DestinationRect); + return NOERROR; +} + + +// Set the target top position - changing this property does not affect the +// current target height. So changing this shunts the target rectangle up and +// down appropriately. Changing the height complements this functionality by +// keeping the top position constant and simply changing the target height + +STDMETHODIMP CBaseControlVideo::put_DestinationTop(long DestinationTop) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.bottom = DestinationTop + HEIGHT(&DestinationRect); + DestinationRect.top = DestinationTop; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the top position for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationTop(__out long *pDestinationTop) +{ + CheckPointer(pDestinationTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationTop = DestinationRect.top; + return NOERROR; +} + + +// Set the destination height + +STDMETHODIMP CBaseControlVideo::put_DestinationHeight(long DestinationHeight) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.bottom = DestinationRect.top + DestinationHeight; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the height for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationHeight(__out long *pDestinationHeight) +{ + CheckPointer(pDestinationHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationHeight = HEIGHT(&DestinationRect); + return NOERROR; +} + + +// Reset the source rectangle to the full video dimensions + +STDMETHODIMP CBaseControlVideo::SetDefaultSourcePosition() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + HRESULT hr = SetDefaultSourceRect(); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return S_OK if we're using the default source otherwise S_FALSE + +STDMETHODIMP CBaseControlVideo::IsUsingDefaultSource() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + return IsDefaultSourceRect(); +} + + +// Reset the video renderer to use the entire playback area + +STDMETHODIMP CBaseControlVideo::SetDefaultDestinationPosition() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + HRESULT hr = SetDefaultTargetRect(); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return S_OK if we're using the default target otherwise S_FALSE + +STDMETHODIMP CBaseControlVideo::IsUsingDefaultDestination() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + return IsDefaultTargetRect(); +} + + +// Return a copy of the current image in the video renderer + +STDMETHODIMP +CBaseControlVideo::GetCurrentImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pVideoImage) +{ + CheckPointer(pBufferSize,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + FILTER_STATE State; + + // Make sure we are in a paused state + + if (pVideoImage != NULL) { + m_pFilter->GetState(0,&State); + if (State != State_Paused) { + return VFW_E_NOT_PAUSED; + } + return GetStaticImage(pBufferSize,pVideoImage); + } + + // Just return the memory required + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + RECT SourceRect; + GetSourceRect(&SourceRect); + return GetImageSize(pVideoInfo,pBufferSize,&SourceRect); +} + + +// An application has two ways of using GetCurrentImage, one is to pass a real +// buffer which should be filled with the current image. The other is to pass +// a NULL buffer pointer which is interpreted as asking us to return how much +// memory is required for the image. The constraints for when the latter can +// be called are much looser. To calculate the memory required we synthesize +// a VIDEOINFO that takes into account the source rectangle that's being used + +HRESULT CBaseControlVideo::GetImageSize(__in VIDEOINFOHEADER *pVideoInfo, + __out long *pBufferSize, + __in RECT *pSourceRect) +{ + NOTE("Entering GetImageSize"); + ASSERT(pSourceRect); + + // Check we have the correct input parameters + + if (pSourceRect == NULL || + pVideoInfo == NULL || + pBufferSize == NULL) { + + return E_UNEXPECTED; + } + + // Is the data format compatible + + if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { + if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { + return E_INVALIDARG; + } + } + + ASSERT(IsRectEmpty(pSourceRect) == FALSE); + + BITMAPINFOHEADER bih; + bih.biWidth = WIDTH(pSourceRect); + bih.biHeight = HEIGHT(pSourceRect); + bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; + LONG Size = DIBSIZE(bih); + Size += GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; + *pBufferSize = Size; + + return NOERROR; +} + + +// Given an IMediaSample containing a linear buffer with an image and a type +// describing the bitmap make a rendering of the image into the output buffer +// This may be called by derived classes who render typical video images to +// handle the IBasicVideo GetCurrentImage method. The pVideoImage pointer may +// be NULL when passed to GetCurrentImage in which case GetImageSize will be +// called instead, which will just do the calculation of the memory required + +HRESULT CBaseControlVideo::CopyImage(IMediaSample *pMediaSample, + __in VIDEOINFOHEADER *pVideoInfo, + __inout long *pBufferSize, + __out_bcount_part(*pBufferSize, *pBufferSize) BYTE *pVideoImage, + __in RECT *pSourceRect) +{ + NOTE("Entering CopyImage"); + ASSERT(pSourceRect); + BYTE *pCurrentImage; + + // Check we have an image to copy + + if (pMediaSample == NULL || pSourceRect == NULL || + pVideoInfo == NULL || pVideoImage == NULL || + pBufferSize == NULL) { + + return E_UNEXPECTED; + } + + // Is the data format compatible + + if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { + if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { + return E_INVALIDARG; + } + } + + if (*pBufferSize < 0) { + return E_INVALIDARG; + } + + // Arbitrarily large size to prevent integer overflow problems + if (pVideoInfo->bmiHeader.biSize > 4096) + { + return E_INVALIDARG; + } + + ASSERT(IsRectEmpty(pSourceRect) == FALSE); + + BITMAPINFOHEADER bih; + bih.biWidth = WIDTH(pSourceRect); + bih.biHeight = HEIGHT(pSourceRect); + bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; + DWORD Size = GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; + DWORD Total; + DWORD dwDibSize; + + if( !ValidateBitmapInfoHeader( HEADER(pVideoInfo), Size)) { + return E_INVALIDARG; + } + + // ValidateBitmapInfoHeader checks this but for some reason code scanning + // tools aren't picking up the annotation + __analysis_assume(Size >= sizeof(BITMAPINFOHEADER)); + + if (FAILED(SAFE_DIBSIZE(&bih, &dwDibSize))) { + return E_INVALIDARG; + } + + if (FAILED(DWordAdd(Size, dwDibSize, &Total))) { + return E_INVALIDARG; + } + + // Make sure we have a large enough buffer + + if ((DWORD)*pBufferSize < Total) { + return E_OUTOFMEMORY; + } + + // Copy the BITMAPINFO + + CopyMemory((PVOID)pVideoImage, (PVOID)&pVideoInfo->bmiHeader, Size); + ((BITMAPINFOHEADER *)pVideoImage)->biWidth = WIDTH(pSourceRect); + ((BITMAPINFOHEADER *)pVideoImage)->biHeight = HEIGHT(pSourceRect); + ((BITMAPINFOHEADER *)pVideoImage)->biSizeImage = DIBSIZE(bih); + BYTE *pImageData = pVideoImage + Size; + + // Get the pointer to it's image data + + HRESULT hr = pMediaSample->GetPointer(&pCurrentImage); + if (FAILED(hr)) { + return hr; + } + + // Now we are ready to start copying the source scan lines + + LONG ScanLine = (pVideoInfo->bmiHeader.biBitCount / 8) * WIDTH(pSourceRect); + LONG LinesToSkip = pVideoInfo->bmiHeader.biHeight; + LinesToSkip -= pSourceRect->top + HEIGHT(pSourceRect); + pCurrentImage += LinesToSkip * DIBWIDTHBYTES(pVideoInfo->bmiHeader); + pCurrentImage += pSourceRect->left * (pVideoInfo->bmiHeader.biBitCount / 8); + + // Even money on this GP faulting sometime... + + for (LONG Line = 0;Line < HEIGHT(pSourceRect);Line++) { + CopyMemory((PVOID)pImageData, (PVOID)pCurrentImage, ScanLine); + pImageData += DIBWIDTHBYTES(*(BITMAPINFOHEADER *)pVideoImage); + pCurrentImage += DIBWIDTHBYTES(pVideoInfo->bmiHeader); + } + return NOERROR; +} + + +// Called when we change media types either during connection or dynamically +// We inform the filter graph and therefore the application that the video +// size may have changed, we don't bother looking to see if it really has as +// we leave that to the application - the dimensions are the event parameters + +HRESULT CBaseControlVideo::OnVideoSizeChange() +{ + // Get the video format from the derived class + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + WORD Width = (WORD) pVideoInfo->bmiHeader.biWidth; + WORD Height = (WORD) pVideoInfo->bmiHeader.biHeight; + + return m_pFilter->NotifyEvent(EC_VIDEO_SIZE_CHANGED, + MAKELPARAM(Width,Height), + MAKEWPARAM(0,0)); +} + + +// Set the video source rectangle. We must check the source rectangle against +// the actual video dimensions otherwise when we come to draw the pictures we +// get access violations as GDI tries to touch data outside of the image data +// Although we store the rectangle in left, top, right and bottom coordinates +// instead of left, top, width and height as OLE uses we do take into account +// that the rectangle is used up to, but not including, the right column and +// bottom row of pixels, see the Win32 documentation on RECT for more details + +HRESULT CBaseControlVideo::CheckSourceRect(__in RECT *pSourceRect) +{ + CheckPointer(pSourceRect,E_POINTER); + LONG Width,Height; + GetVideoSize(&Width,&Height); + + // Check the coordinates are greater than zero + // and that the rectangle is valid (leftleft >= pSourceRect->right) || + (pSourceRect->left < 0) || + (pSourceRect->top >= pSourceRect->bottom) || + (pSourceRect->top < 0)) { + + return E_INVALIDARG; + } + + // Check the coordinates are less than the extents + + if ((pSourceRect->right > Width) || + (pSourceRect->bottom > Height)) { + + return E_INVALIDARG; + } + return NOERROR; +} + + +// Check the target rectangle has some valid coordinates, which amounts to +// little more than checking the destination rectangle isn't empty. Derived +// classes may call this when they have their SetTargetRect method called to +// check the rectangle validity, we do not update the rectangles passed in +// Although we store the rectangle in left, top, right and bottom coordinates +// instead of left, top, width and height as OLE uses we do take into account +// that the rectangle is used up to, but not including, the right column and +// bottom row of pixels, see the Win32 documentation on RECT for more details + +HRESULT CBaseControlVideo::CheckTargetRect(__in RECT *pTargetRect) +{ + // Check the pointer is valid + + if (pTargetRect == NULL) { + return E_POINTER; + } + + // These overflow the WIDTH and HEIGHT checks + + if (pTargetRect->left > pTargetRect->right || + pTargetRect->top > pTargetRect->bottom) { + return E_INVALIDARG; + } + + // Check the rectangle has valid coordinates + + if (WIDTH(pTargetRect) <= 0 || HEIGHT(pTargetRect) <= 0) { + return E_INVALIDARG; + } + + ASSERT(IsRectEmpty(pTargetRect) == FALSE); + return NOERROR; +} + diff --git a/src/thirdparty/BaseClasses/winctrl.h b/src/thirdparty/BaseClasses/winctrl.h index 1080a47c696..f18ba82317c 100644 --- a/src/thirdparty/BaseClasses/winctrl.h +++ b/src/thirdparty/BaseClasses/winctrl.h @@ -1,224 +1,224 @@ -//------------------------------------------------------------------------------ -// File: WinCtrl.h -// -// Desc: DirectShow base classes - defines classes for video control -// interfaces. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __WINCTRL__ -#define __WINCTRL__ - -#define ABSOL(x) (x < 0 ? -x : x) -#define NEGAT(x) (x > 0 ? -x : x) - -// Helper -BOOL WINAPI PossiblyEatMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -class CBaseControlWindow : public CBaseVideoWindow, public CBaseWindow -{ -protected: - - CBaseFilter *m_pFilter; // Pointer to owning media filter - CBasePin *m_pPin; // Controls media types for connection - CCritSec *m_pInterfaceLock; // Externally defined critical section - COLORREF m_BorderColour; // Current window border colour - BOOL m_bAutoShow; // What happens when the state changes - HWND m_hwndOwner; // Owner window that we optionally have - HWND m_hwndDrain; // HWND to post any messages received - BOOL m_bCursorHidden; // Should we hide the window cursor - -public: - - // Internal methods for other objects to get information out - - HRESULT DoSetWindowStyle(long Style,long WindowLong); - HRESULT DoGetWindowStyle(__out long *pStyle,long WindowLong); - BOOL IsAutoShowEnabled() { return m_bAutoShow; }; - COLORREF GetBorderColour() { return m_BorderColour; }; - HWND GetOwnerWindow() { return m_hwndOwner; }; - BOOL IsCursorHidden() { return m_bCursorHidden; }; - - inline BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) - { - return ::PossiblyEatMessage(m_hwndDrain, uMsg, wParam, lParam); - } - - // Derived classes must call this to set the pin the filter is using - // We don't have the pin passed in to the constructor (as we do with - // the CBaseFilter object) because filters typically create the - // pins dynamically when requested in CBaseFilter::GetPin. This can - // not be called from our constructor because is is a virtual method - - void SetControlWindowPin(CBasePin *pPin) { - m_pPin = pPin; - } - -public: - - CBaseControlWindow(__inout CBaseFilter *pFilter, // Owning media filter - __in CCritSec *pInterfaceLock, // Locking object - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // Normal COM ownership - __inout HRESULT *phr); // OLE return code - - // These are the properties we support - - STDMETHODIMP put_Caption(__in BSTR strCaption); - STDMETHODIMP get_Caption(__out BSTR *pstrCaption); - STDMETHODIMP put_AutoShow(long AutoShow); - STDMETHODIMP get_AutoShow(__out long *AutoShow); - STDMETHODIMP put_WindowStyle(long WindowStyle); - STDMETHODIMP get_WindowStyle(__out long *pWindowStyle); - STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); - STDMETHODIMP get_WindowStyleEx(__out long *pWindowStyleEx); - STDMETHODIMP put_WindowState(long WindowState); - STDMETHODIMP get_WindowState(__out long *pWindowState); - STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); - STDMETHODIMP get_BackgroundPalette(__out long *pBackgroundPalette); - STDMETHODIMP put_Visible(long Visible); - STDMETHODIMP get_Visible(__out long *pVisible); - STDMETHODIMP put_Left(long Left); - STDMETHODIMP get_Left(__out long *pLeft); - STDMETHODIMP put_Width(long Width); - STDMETHODIMP get_Width(__out long *pWidth); - STDMETHODIMP put_Top(long Top); - STDMETHODIMP get_Top(__out long *pTop); - STDMETHODIMP put_Height(long Height); - STDMETHODIMP get_Height(__out long *pHeight); - STDMETHODIMP put_Owner(OAHWND Owner); - STDMETHODIMP get_Owner(__out OAHWND *Owner); - STDMETHODIMP put_MessageDrain(OAHWND Drain); - STDMETHODIMP get_MessageDrain(__out OAHWND *Drain); - STDMETHODIMP get_BorderColor(__out long *Color); - STDMETHODIMP put_BorderColor(long Color); - STDMETHODIMP get_FullScreenMode(__out long *FullScreenMode); - STDMETHODIMP put_FullScreenMode(long FullScreenMode); - - // And these are the methods - - STDMETHODIMP SetWindowForeground(long Focus); - STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd,long uMsg,LONG_PTR wParam,LONG_PTR lParam); - STDMETHODIMP GetMinIdealImageSize(__out long *pWidth,__out long *pHeight); - STDMETHODIMP GetMaxIdealImageSize(__out long *pWidth,__out long *pHeight); - STDMETHODIMP SetWindowPosition(long Left,long Top,long Width,long Height); - STDMETHODIMP GetWindowPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); - STDMETHODIMP GetRestorePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); - STDMETHODIMP HideCursor(long HideCursor); - STDMETHODIMP IsCursorHidden(__out long *CursorHidden); -}; - -// This class implements the IBasicVideo interface - -class CBaseControlVideo : public CBaseBasicVideo -{ -protected: - - CBaseFilter *m_pFilter; // Pointer to owning media filter - CBasePin *m_pPin; // Controls media types for connection - CCritSec *m_pInterfaceLock; // Externally defined critical section - -public: - - // Derived classes must provide these for the implementation - - virtual HRESULT IsDefaultTargetRect() PURE; - virtual HRESULT SetDefaultTargetRect() PURE; - virtual HRESULT SetTargetRect(RECT *pTargetRect) PURE; - virtual HRESULT GetTargetRect(RECT *pTargetRect) PURE; - virtual HRESULT IsDefaultSourceRect() PURE; - virtual HRESULT SetDefaultSourceRect() PURE; - virtual HRESULT SetSourceRect(RECT *pSourceRect) PURE; - virtual HRESULT GetSourceRect(RECT *pSourceRect) PURE; - virtual HRESULT GetStaticImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pDIBImage) PURE; - - // Derived classes must override this to return a VIDEOINFO representing - // the video format. We cannot call IPin ConnectionMediaType to get this - // format because various filters dynamically change the type when using - // DirectDraw such that the format shows the position of the logical - // bitmap in a frame buffer surface, so the size might be returned as - // 1024x768 pixels instead of 320x240 which is the real video dimensions - - __out virtual VIDEOINFOHEADER *GetVideoFormat() PURE; - - // Helper functions for creating memory renderings of a DIB image - - HRESULT GetImageSize(__in VIDEOINFOHEADER *pVideoInfo, - __out LONG *pBufferSize, - __in RECT *pSourceRect); - - HRESULT CopyImage(IMediaSample *pMediaSample, - __in VIDEOINFOHEADER *pVideoInfo, - __inout LONG *pBufferSize, - __out_bcount_part(*pBufferSize, *pBufferSize) BYTE *pVideoImage, - __in RECT *pSourceRect); - - // Override this if you want notifying when the rectangles change - virtual HRESULT OnUpdateRectangles() { return NOERROR; }; - virtual HRESULT OnVideoSizeChange(); - - // Derived classes must call this to set the pin the filter is using - // We don't have the pin passed in to the constructor (as we do with - // the CBaseFilter object) because filters typically create the - // pins dynamically when requested in CBaseFilter::GetPin. This can - // not be called from our constructor because is is a virtual method - - void SetControlVideoPin(__inout CBasePin *pPin) { - m_pPin = pPin; - } - - // Helper methods for checking rectangles - virtual HRESULT CheckSourceRect(__in RECT *pSourceRect); - virtual HRESULT CheckTargetRect(__in RECT *pTargetRect); - -public: - - CBaseControlVideo(__inout CBaseFilter *pFilter, // Owning media filter - __in CCritSec *pInterfaceLock, // Serialise interface - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // Normal COM ownership - __inout HRESULT *phr); // OLE return code - - // These are the properties we support - - STDMETHODIMP get_AvgTimePerFrame(__out REFTIME *pAvgTimePerFrame); - STDMETHODIMP get_BitRate(__out long *pBitRate); - STDMETHODIMP get_BitErrorRate(__out long *pBitErrorRate); - STDMETHODIMP get_VideoWidth(__out long *pVideoWidth); - STDMETHODIMP get_VideoHeight(__out long *pVideoHeight); - STDMETHODIMP put_SourceLeft(long SourceLeft); - STDMETHODIMP get_SourceLeft(__out long *pSourceLeft); - STDMETHODIMP put_SourceWidth(long SourceWidth); - STDMETHODIMP get_SourceWidth(__out long *pSourceWidth); - STDMETHODIMP put_SourceTop(long SourceTop); - STDMETHODIMP get_SourceTop(__out long *pSourceTop); - STDMETHODIMP put_SourceHeight(long SourceHeight); - STDMETHODIMP get_SourceHeight(__out long *pSourceHeight); - STDMETHODIMP put_DestinationLeft(long DestinationLeft); - STDMETHODIMP get_DestinationLeft(__out long *pDestinationLeft); - STDMETHODIMP put_DestinationWidth(long DestinationWidth); - STDMETHODIMP get_DestinationWidth(__out long *pDestinationWidth); - STDMETHODIMP put_DestinationTop(long DestinationTop); - STDMETHODIMP get_DestinationTop(__out long *pDestinationTop); - STDMETHODIMP put_DestinationHeight(long DestinationHeight); - STDMETHODIMP get_DestinationHeight(__out long *pDestinationHeight); - - // And these are the methods - - STDMETHODIMP GetVideoSize(__out long *pWidth,__out long *pHeight); - STDMETHODIMP SetSourcePosition(long Left,long Top,long Width,long Height); - STDMETHODIMP GetSourcePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); - STDMETHODIMP GetVideoPaletteEntries(long StartIndex,long Entries,__out long *pRetrieved,__out_ecount_part(Entries, *pRetrieved) long *pPalette); - STDMETHODIMP SetDefaultSourcePosition(); - STDMETHODIMP IsUsingDefaultSource(); - STDMETHODIMP SetDestinationPosition(long Left,long Top,long Width,long Height); - STDMETHODIMP GetDestinationPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); - STDMETHODIMP SetDefaultDestinationPosition(); - STDMETHODIMP IsUsingDefaultDestination(); - STDMETHODIMP GetCurrentImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pVideoImage); -}; - -#endif // __WINCTRL__ - +//------------------------------------------------------------------------------ +// File: WinCtrl.h +// +// Desc: DirectShow base classes - defines classes for video control +// interfaces. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WINCTRL__ +#define __WINCTRL__ + +#define ABSOL(x) (x < 0 ? -x : x) +#define NEGAT(x) (x > 0 ? -x : x) + +// Helper +BOOL WINAPI PossiblyEatMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +class CBaseControlWindow : public CBaseVideoWindow, public CBaseWindow +{ +protected: + + CBaseFilter *m_pFilter; // Pointer to owning media filter + CBasePin *m_pPin; // Controls media types for connection + CCritSec *m_pInterfaceLock; // Externally defined critical section + COLORREF m_BorderColour; // Current window border colour + BOOL m_bAutoShow; // What happens when the state changes + HWND m_hwndOwner; // Owner window that we optionally have + HWND m_hwndDrain; // HWND to post any messages received + BOOL m_bCursorHidden; // Should we hide the window cursor + +public: + + // Internal methods for other objects to get information out + + HRESULT DoSetWindowStyle(long Style,long WindowLong); + HRESULT DoGetWindowStyle(__out long *pStyle,long WindowLong); + BOOL IsAutoShowEnabled() { return m_bAutoShow; }; + COLORREF GetBorderColour() { return m_BorderColour; }; + HWND GetOwnerWindow() { return m_hwndOwner; }; + BOOL IsCursorHidden() { return m_bCursorHidden; }; + + inline BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return ::PossiblyEatMessage(m_hwndDrain, uMsg, wParam, lParam); + } + + // Derived classes must call this to set the pin the filter is using + // We don't have the pin passed in to the constructor (as we do with + // the CBaseFilter object) because filters typically create the + // pins dynamically when requested in CBaseFilter::GetPin. This can + // not be called from our constructor because is is a virtual method + + void SetControlWindowPin(CBasePin *pPin) { + m_pPin = pPin; + } + +public: + + CBaseControlWindow(__inout CBaseFilter *pFilter, // Owning media filter + __in CCritSec *pInterfaceLock, // Locking object + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // Normal COM ownership + __inout HRESULT *phr); // OLE return code + + // These are the properties we support + + STDMETHODIMP put_Caption(__in BSTR strCaption); + STDMETHODIMP get_Caption(__out BSTR *pstrCaption); + STDMETHODIMP put_AutoShow(long AutoShow); + STDMETHODIMP get_AutoShow(__out long *AutoShow); + STDMETHODIMP put_WindowStyle(long WindowStyle); + STDMETHODIMP get_WindowStyle(__out long *pWindowStyle); + STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); + STDMETHODIMP get_WindowStyleEx(__out long *pWindowStyleEx); + STDMETHODIMP put_WindowState(long WindowState); + STDMETHODIMP get_WindowState(__out long *pWindowState); + STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); + STDMETHODIMP get_BackgroundPalette(__out long *pBackgroundPalette); + STDMETHODIMP put_Visible(long Visible); + STDMETHODIMP get_Visible(__out long *pVisible); + STDMETHODIMP put_Left(long Left); + STDMETHODIMP get_Left(__out long *pLeft); + STDMETHODIMP put_Width(long Width); + STDMETHODIMP get_Width(__out long *pWidth); + STDMETHODIMP put_Top(long Top); + STDMETHODIMP get_Top(__out long *pTop); + STDMETHODIMP put_Height(long Height); + STDMETHODIMP get_Height(__out long *pHeight); + STDMETHODIMP put_Owner(OAHWND Owner); + STDMETHODIMP get_Owner(__out OAHWND *Owner); + STDMETHODIMP put_MessageDrain(OAHWND Drain); + STDMETHODIMP get_MessageDrain(__out OAHWND *Drain); + STDMETHODIMP get_BorderColor(__out long *Color); + STDMETHODIMP put_BorderColor(long Color); + STDMETHODIMP get_FullScreenMode(__out long *FullScreenMode); + STDMETHODIMP put_FullScreenMode(long FullScreenMode); + + // And these are the methods + + STDMETHODIMP SetWindowForeground(long Focus); + STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd,long uMsg,LONG_PTR wParam,LONG_PTR lParam); + STDMETHODIMP GetMinIdealImageSize(__out long *pWidth,__out long *pHeight); + STDMETHODIMP GetMaxIdealImageSize(__out long *pWidth,__out long *pHeight); + STDMETHODIMP SetWindowPosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetWindowPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); + STDMETHODIMP GetRestorePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); + STDMETHODIMP HideCursor(long HideCursor); + STDMETHODIMP IsCursorHidden(__out long *CursorHidden); +}; + +// This class implements the IBasicVideo interface + +class CBaseControlVideo : public CBaseBasicVideo +{ +protected: + + CBaseFilter *m_pFilter; // Pointer to owning media filter + CBasePin *m_pPin; // Controls media types for connection + CCritSec *m_pInterfaceLock; // Externally defined critical section + +public: + + // Derived classes must provide these for the implementation + + virtual HRESULT IsDefaultTargetRect() PURE; + virtual HRESULT SetDefaultTargetRect() PURE; + virtual HRESULT SetTargetRect(RECT *pTargetRect) PURE; + virtual HRESULT GetTargetRect(RECT *pTargetRect) PURE; + virtual HRESULT IsDefaultSourceRect() PURE; + virtual HRESULT SetDefaultSourceRect() PURE; + virtual HRESULT SetSourceRect(RECT *pSourceRect) PURE; + virtual HRESULT GetSourceRect(RECT *pSourceRect) PURE; + virtual HRESULT GetStaticImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pDIBImage) PURE; + + // Derived classes must override this to return a VIDEOINFO representing + // the video format. We cannot call IPin ConnectionMediaType to get this + // format because various filters dynamically change the type when using + // DirectDraw such that the format shows the position of the logical + // bitmap in a frame buffer surface, so the size might be returned as + // 1024x768 pixels instead of 320x240 which is the real video dimensions + + __out virtual VIDEOINFOHEADER *GetVideoFormat() PURE; + + // Helper functions for creating memory renderings of a DIB image + + HRESULT GetImageSize(__in VIDEOINFOHEADER *pVideoInfo, + __out LONG *pBufferSize, + __in RECT *pSourceRect); + + HRESULT CopyImage(IMediaSample *pMediaSample, + __in VIDEOINFOHEADER *pVideoInfo, + __inout LONG *pBufferSize, + __out_bcount_part(*pBufferSize, *pBufferSize) BYTE *pVideoImage, + __in RECT *pSourceRect); + + // Override this if you want notifying when the rectangles change + virtual HRESULT OnUpdateRectangles() { return NOERROR; }; + virtual HRESULT OnVideoSizeChange(); + + // Derived classes must call this to set the pin the filter is using + // We don't have the pin passed in to the constructor (as we do with + // the CBaseFilter object) because filters typically create the + // pins dynamically when requested in CBaseFilter::GetPin. This can + // not be called from our constructor because is is a virtual method + + void SetControlVideoPin(__inout CBasePin *pPin) { + m_pPin = pPin; + } + + // Helper methods for checking rectangles + virtual HRESULT CheckSourceRect(__in RECT *pSourceRect); + virtual HRESULT CheckTargetRect(__in RECT *pTargetRect); + +public: + + CBaseControlVideo(__inout CBaseFilter *pFilter, // Owning media filter + __in CCritSec *pInterfaceLock, // Serialise interface + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // Normal COM ownership + __inout HRESULT *phr); // OLE return code + + // These are the properties we support + + STDMETHODIMP get_AvgTimePerFrame(__out REFTIME *pAvgTimePerFrame); + STDMETHODIMP get_BitRate(__out long *pBitRate); + STDMETHODIMP get_BitErrorRate(__out long *pBitErrorRate); + STDMETHODIMP get_VideoWidth(__out long *pVideoWidth); + STDMETHODIMP get_VideoHeight(__out long *pVideoHeight); + STDMETHODIMP put_SourceLeft(long SourceLeft); + STDMETHODIMP get_SourceLeft(__out long *pSourceLeft); + STDMETHODIMP put_SourceWidth(long SourceWidth); + STDMETHODIMP get_SourceWidth(__out long *pSourceWidth); + STDMETHODIMP put_SourceTop(long SourceTop); + STDMETHODIMP get_SourceTop(__out long *pSourceTop); + STDMETHODIMP put_SourceHeight(long SourceHeight); + STDMETHODIMP get_SourceHeight(__out long *pSourceHeight); + STDMETHODIMP put_DestinationLeft(long DestinationLeft); + STDMETHODIMP get_DestinationLeft(__out long *pDestinationLeft); + STDMETHODIMP put_DestinationWidth(long DestinationWidth); + STDMETHODIMP get_DestinationWidth(__out long *pDestinationWidth); + STDMETHODIMP put_DestinationTop(long DestinationTop); + STDMETHODIMP get_DestinationTop(__out long *pDestinationTop); + STDMETHODIMP put_DestinationHeight(long DestinationHeight); + STDMETHODIMP get_DestinationHeight(__out long *pDestinationHeight); + + // And these are the methods + + STDMETHODIMP GetVideoSize(__out long *pWidth,__out long *pHeight); + STDMETHODIMP SetSourcePosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetSourcePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); + STDMETHODIMP GetVideoPaletteEntries(long StartIndex,long Entries,__out long *pRetrieved,__out_ecount_part(Entries, *pRetrieved) long *pPalette); + STDMETHODIMP SetDefaultSourcePosition(); + STDMETHODIMP IsUsingDefaultSource(); + STDMETHODIMP SetDestinationPosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetDestinationPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); + STDMETHODIMP SetDefaultDestinationPosition(); + STDMETHODIMP IsUsingDefaultDestination(); + STDMETHODIMP GetCurrentImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pVideoImage); +}; + +#endif // __WINCTRL__ + diff --git a/src/thirdparty/BaseClasses/winutil.cpp b/src/thirdparty/BaseClasses/winutil.cpp index 205567c6a27..8df3545de93 100644 --- a/src/thirdparty/BaseClasses/winutil.cpp +++ b/src/thirdparty/BaseClasses/winutil.cpp @@ -1,2759 +1,2759 @@ -//------------------------------------------------------------------------------ -// File: WinUtil.cpp -// -// Desc: DirectShow base classes - implements generic window handler class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include -#include -#include -#include "checkbmi.h" - -static UINT MsgDestroy; - -// Constructor - -CBaseWindow::CBaseWindow(BOOL bDoGetDC, bool bDoPostToDestroy) : - m_hInstance(g_hInst), - m_hwnd(NULL), - m_hdc(NULL), - m_bActivated(FALSE), - m_pClassName(NULL), - m_ClassStyles(0), - m_WindowStyles(0), - m_WindowStylesEx(0), - m_ShowStageMessage(0), - m_ShowStageTop(0), - m_MemoryDC(NULL), - m_hPalette(NULL), - m_bBackground(FALSE), -#ifdef _DEBUG - m_bRealizing(FALSE), -#endif - m_bNoRealize(FALSE), - m_bDoPostToDestroy(bDoPostToDestroy), - m_bDoGetDC(bDoGetDC), - m_Width(0), - m_Height(0), - m_RealizePalette(0) -{ -} - - -// Prepare a window by spinning off a worker thread to do the creation and -// also poll the message input queue. We leave this to be called by derived -// classes because they might want to override methods like MessageLoop and -// InitialiseWindow, if we do this during construction they'll ALWAYS call -// this base class methods. We make the worker thread create the window so -// it owns it rather than the filter graph thread which is constructing us - -HRESULT CBaseWindow::PrepareWindow() -{ - if (m_hwnd) return NOERROR; - ASSERT(m_hwnd == NULL); - ASSERT(m_hdc == NULL); - - // Get the derived object's window and class styles - - m_pClassName = GetClassWindowStyles(&m_ClassStyles, - &m_WindowStyles, - &m_WindowStylesEx); - if (m_pClassName == NULL) { - return E_FAIL; - } - - // Register our special private messages - m_ShowStageMessage = RegisterWindowMessage(SHOWSTAGE); - - // RegisterWindowMessage() returns 0 if an error occurs. - if (0 == m_ShowStageMessage) { - return AmGetLastErrorToHResult(); - } - - m_ShowStageTop = RegisterWindowMessage(SHOWSTAGETOP); - if (0 == m_ShowStageTop) { - return AmGetLastErrorToHResult(); - } - - m_RealizePalette = RegisterWindowMessage(REALIZEPALETTE); - if (0 == m_RealizePalette) { - return AmGetLastErrorToHResult(); - } - - MsgDestroy = RegisterWindowMessage(TEXT("AM_DESTROY")); - if (0 == MsgDestroy) { - return AmGetLastErrorToHResult(); - } - - return DoCreateWindow(); -} - - -// Destructor just a placeholder so that we know it becomes virtual -// Derived classes MUST call DoneWithWindow in their destructors so -// that no messages arrive after the derived class constructor ends - -#ifdef _DEBUG -CBaseWindow::~CBaseWindow() -{ - ASSERT(m_hwnd == NULL); - ASSERT(m_hdc == NULL); -} -#endif - - -// We use the sync worker event to have the window destroyed. All we do is -// signal the event and wait on the window thread handle. Trying to send it -// messages causes too many problems, furthermore to be on the safe side we -// just wait on the thread handle while it returns WAIT_TIMEOUT or there is -// a sent message to process on this thread. If the constructor failed to -// create the thread in the first place then the loop will get terminated - -HRESULT CBaseWindow::DoneWithWindow() -{ - if (!IsWindow(m_hwnd) || (GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId())) { - - if (IsWindow(m_hwnd)) { - - // This code should only be executed if the window exists and if the window's - // messages are processed on a different thread. - ASSERT(GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId()); - - if (m_bDoPostToDestroy) { - - HRESULT hr = S_OK; - CAMEvent m_evDone(FALSE, &hr); - if (FAILED(hr)) { - return hr; - } - - // We must post a message to destroy the window - // That way we can't be in the middle of processing a - // message posted to our window when we do go away - // Sending a message gives less synchronization. - PostMessage(m_hwnd, MsgDestroy, (WPARAM)(HANDLE)m_evDone, 0); - WaitDispatchingMessages(m_evDone, INFINITE); - } else { - SendMessage(m_hwnd, MsgDestroy, 0, 0); - } - } - - // - // This is not a leak, the window manager automatically free's - // hdc's that were got via GetDC, which is the case here. - // We set it to NULL so that we don't get any asserts later. - // - m_hdc = NULL; - - // - // We need to free this DC though because USER32 does not know - // anything about it. - // - if (m_MemoryDC) - { - EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); - m_MemoryDC = NULL; - } - - // Reset the window variables - m_hwnd = NULL; - - return NOERROR; - } - const HWND hwnd = m_hwnd; - if (hwnd == NULL) { - return NOERROR; - } - - InactivateWindow(); - NOTE("Inactivated"); - - // Reset the window styles before destruction - - SetWindowLong(hwnd,GWL_STYLE,m_WindowStyles); - ASSERT(GetParent(hwnd) == NULL); - NOTE1("Reset window styles %d",m_WindowStyles); - - // UnintialiseWindow sets m_hwnd to NULL so save a copy - UninitialiseWindow(); - DbgLog((LOG_TRACE, 2, TEXT("Destroying 0x%8.8X"), hwnd)); - if (!DestroyWindow(hwnd)) { - DbgLog((LOG_TRACE, 0, TEXT("DestroyWindow %8.8X failed code %d"), - hwnd, GetLastError())); - DbgBreak(""); - } - - // Reset our state so we can be prepared again - - m_pClassName = NULL; - m_ClassStyles = 0; - m_WindowStyles = 0; - m_WindowStylesEx = 0; - m_ShowStageMessage = 0; - m_ShowStageTop = 0; - - return NOERROR; -} - - -// Called at the end to put the window in an inactive state. The pending list -// will always have been cleared by this time so event if the worker thread -// gets has been signaled and gets in to render something it will find both -// the state has been changed and that there are no available sample images -// Since we wait on the window thread to complete we don't lock the object - -HRESULT CBaseWindow::InactivateWindow() -{ - // Has the window been activated - if (m_bActivated == FALSE) { - return S_FALSE; - } - - m_bActivated = FALSE; - ShowWindow(m_hwnd,SW_HIDE); - return NOERROR; -} - - -HRESULT CBaseWindow::CompleteConnect() -{ - m_bActivated = FALSE; - return NOERROR; -} - -// This displays a normal window. We ask the base window class for default -// sizes which unless overriden will return DEFWIDTH and DEFHEIGHT. We go -// through a couple of extra hoops to get the client area the right size -// as the object specifies which accounts for the AdjustWindowRectEx calls -// We also DWORD align the left and top coordinates of the window here to -// maximise the chance of being able to use DCI/DirectDraw primary surface - -HRESULT CBaseWindow::ActivateWindow() -{ - // Has the window been sized and positioned already - - if (m_bActivated == TRUE || GetParent(m_hwnd) != NULL) { - - SetWindowPos(m_hwnd, // Our window handle - HWND_TOP, // Put it at the top - 0, 0, 0, 0, // Leave in current position - SWP_NOMOVE | // Don't change it's place - SWP_NOSIZE); // Change Z-order only - - m_bActivated = TRUE; - return S_FALSE; - } - - // Calculate the desired client rectangle - - RECT WindowRect, ClientRect = GetDefaultRect(); - GetWindowRect(m_hwnd,&WindowRect); - AdjustWindowRectEx(&ClientRect,GetWindowLong(m_hwnd,GWL_STYLE), - FALSE,GetWindowLong(m_hwnd,GWL_EXSTYLE)); - - // Align left and top edges on DWORD boundaries - - UINT WindowFlags = (SWP_NOACTIVATE | SWP_FRAMECHANGED); - WindowRect.left -= (WindowRect.left & 3); - WindowRect.top -= (WindowRect.top & 3); - - SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Align left edge - WindowRect.top, // And also top place - WIDTH(&ClientRect), // Horizontal size - HEIGHT(&ClientRect), // Vertical size - WindowFlags); // Don't show window - - m_bActivated = TRUE; - return NOERROR; -} - - -// This can be used to DWORD align the window for maximum performance - -HRESULT CBaseWindow::PerformanceAlignWindow() -{ - RECT ClientRect,WindowRect; - GetWindowRect(m_hwnd,&WindowRect); - ASSERT(m_bActivated == TRUE); - - // Don't do this if we're owned - - if (GetParent(m_hwnd)) { - return NOERROR; - } - - // Align left and top edges on DWORD boundaries - - GetClientRect(m_hwnd, &ClientRect); - MapWindowPoints(m_hwnd, HWND_DESKTOP, (LPPOINT) &ClientRect, 2); - WindowRect.left -= (ClientRect.left & 3); - WindowRect.top -= (ClientRect.top & 3); - UINT WindowFlags = (SWP_NOACTIVATE | SWP_NOSIZE); - - SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Align left edge - WindowRect.top, // And also top place - (int) 0,(int) 0, // Ignore these sizes - WindowFlags); // Don't show window - - return NOERROR; -} - - -// Install a palette into the base window - we may be called by a different -// thread to the one that owns the window. We have to be careful how we do -// the palette realisation as we could be a different thread to the window -// which would cause an inter thread send message. Therefore we realise the -// palette by sending it a special message but without the window locked - -HRESULT CBaseWindow::SetPalette(HPALETTE hPalette) -{ - // We must own the window lock during the change - { - CAutoLock cWindowLock(&m_WindowLock); - CAutoLock cPaletteLock(&m_PaletteLock); - ASSERT(hPalette); - m_hPalette = hPalette; - } - return SetPalette(); -} - - -HRESULT CBaseWindow::SetPalette() -{ - if (!m_bNoRealize) { - SendMessage(m_hwnd, m_RealizePalette, 0, 0); - return S_OK; - } else { - // Just select the palette - ASSERT(m_hdc); - ASSERT(m_MemoryDC); - - CAutoLock cPaletteLock(&m_PaletteLock); - SelectPalette(m_hdc,m_hPalette,m_bBackground); - SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); - - return S_OK; - } -} - - -void CBaseWindow::UnsetPalette() -{ - CAutoLock cWindowLock(&m_WindowLock); - CAutoLock cPaletteLock(&m_PaletteLock); - - // Get a standard VGA colour palette - - HPALETTE hPalette = (HPALETTE) GetStockObject(DEFAULT_PALETTE); - ASSERT(hPalette); - - SelectPalette(GetWindowHDC(), hPalette, TRUE); - SelectPalette(GetMemoryHDC(), hPalette, TRUE); - - m_hPalette = NULL; -} - - -void CBaseWindow::LockPaletteLock() -{ - m_PaletteLock.Lock(); -} - - -void CBaseWindow::UnlockPaletteLock() -{ - m_PaletteLock.Unlock(); -} - - -// Realise our palettes in the window and device contexts - -HRESULT CBaseWindow::DoRealisePalette(BOOL bForceBackground) -{ - { - CAutoLock cPaletteLock(&m_PaletteLock); - - if (m_hPalette == NULL) { - return NOERROR; - } - - // Realize the palette on the window thread - ASSERT(m_hdc); - ASSERT(m_MemoryDC); - - SelectPalette(m_hdc,m_hPalette,m_bBackground || bForceBackground); - SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); - } - - // If we grab a critical section here we can deadlock - // with the window thread because one of the side effects - // of RealizePalette is to send a WM_PALETTECHANGED message - // to every window in the system. In our handling - // of WM_PALETTECHANGED we used to grab this CS too. - // The really bad case is when our renderer calls DoRealisePalette() - // while we're in the middle of processing a palette change - // for another window. - // So don't hold the critical section while actually realising - // the palette. In any case USER is meant to manage palette - // handling - we shouldn't have to serialize everything as well - ASSERT(CritCheckOut(&m_WindowLock)); - ASSERT(CritCheckOut(&m_PaletteLock)); - - EXECUTE_ASSERT(RealizePalette(m_hdc) != GDI_ERROR); - EXECUTE_ASSERT(RealizePalette(m_MemoryDC) != GDI_ERROR); - - return (GdiFlush() == FALSE ? S_FALSE : S_OK); -} - - -// This is the global window procedure - -LRESULT CALLBACK WndProc(HWND hwnd, // Window handle - UINT uMsg, // Message ID - WPARAM wParam, // First parameter - LPARAM lParam) // Other parameter -{ - - // Get the window long that holds our window object pointer - // If it is NULL then we are initialising the window in which - // case the object pointer has been passed in the window creation - // structure. IF we get any messages before WM_NCCREATE we will - // pass them to DefWindowProc. - - CBaseWindow *pBaseWindow = (CBaseWindow *)GetWindowLongPtr(hwnd,0); - - if (pBaseWindow == NULL) { - - // Get the structure pointer from the create struct. - // We can only do this for WM_NCCREATE which should be one of - // the first messages we receive. Anything before this will - // have to be passed to DefWindowProc (i.e. WM_GETMINMAXINFO) - - // If the message is WM_NCCREATE we set our pBaseWindow pointer - // and will then place it in the window structure - - // turn off WS_EX_LAYOUTRTL style for quartz windows - if (uMsg == WM_NCCREATE) { - SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~0x400000); - } - - if ((uMsg != WM_NCCREATE) - || (NULL == (pBaseWindow = *(CBaseWindow**) ((LPCREATESTRUCT)lParam)->lpCreateParams))) - { - return(DefWindowProc(hwnd, uMsg, wParam, lParam)); - } - - // Set the window LONG to be the object who created us -#ifdef _DEBUG - SetLastError(0); // because of the way SetWindowLong works -#endif - -#ifdef _DEBUG - LONG_PTR rc = -#endif - SetWindowLongPtr(hwnd, (DWORD) 0, (LONG_PTR)pBaseWindow); - - -#ifdef _DEBUG - if (0 == rc) { - // SetWindowLong MIGHT have failed. (Read the docs which admit - // that it is awkward to work out if you have had an error.) - LONG lasterror = GetLastError(); - ASSERT(0 == lasterror); - // If this is not the case we have not set the pBaseWindow pointer - // into the window structure and we will blow up. - } -#endif - - } - // See if this is the packet of death - if (uMsg == MsgDestroy && uMsg != 0) { - pBaseWindow->DoneWithWindow(); - if (pBaseWindow->m_bDoPostToDestroy) { - EXECUTE_ASSERT(SetEvent((HANDLE)wParam)); - } - return 0; - } - return pBaseWindow->OnReceiveMessage(hwnd,uMsg,wParam,lParam); -} - - -// When the window size changes we adjust our member variables that -// contain the dimensions of the client rectangle for our window so -// that we come to render an image we will know whether to stretch - -BOOL CBaseWindow::OnSize(LONG Width, LONG Height) -{ - m_Width = Width; - m_Height = Height; - return TRUE; -} - - -// This function handles the WM_CLOSE message - -BOOL CBaseWindow::OnClose() -{ - ShowWindow(m_hwnd,SW_HIDE); - return TRUE; -} - - -// This is called by the worker window thread when it receives a terminate -// message from the window object destructor to delete all the resources we -// allocated during initialisation. By the time the worker thread exits all -// processing will have been completed as the source filter disconnection -// flushes the image pending sample, therefore the GdiFlush should succeed - -HRESULT CBaseWindow::UninitialiseWindow() -{ - // Have we already cleaned up - - if (m_hwnd == NULL) { - ASSERT(m_hdc == NULL); - ASSERT(m_MemoryDC == NULL); - return NOERROR; - } - - // Release the window resources - - EXECUTE_ASSERT(GdiFlush()); - - if (m_hdc) - { - EXECUTE_ASSERT(ReleaseDC(m_hwnd,m_hdc)); - m_hdc = NULL; - } - - if (m_MemoryDC) - { - EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); - m_MemoryDC = NULL; - } - - // Reset the window variables - m_hwnd = NULL; - - return NOERROR; -} - - -// This is called by the worker window thread after it has created the main -// window and it wants to initialise the rest of the owner objects window -// variables such as the device contexts. We execute this function with the -// critical section still locked. Nothing in this function must generate any -// SendMessage calls to the window because this is executing on the window -// thread so the message will never be processed and we will deadlock - -HRESULT CBaseWindow::InitialiseWindow(HWND hwnd) -{ - // Initialise the window variables - - ASSERT(IsWindow(hwnd)); - m_hwnd = hwnd; - - if (m_bDoGetDC) - { - m_hdc = GetDC(hwnd); - EXECUTE_ASSERT(m_hdc); - m_MemoryDC = CreateCompatibleDC(m_hdc); - EXECUTE_ASSERT(m_MemoryDC); - - EXECUTE_ASSERT(SetStretchBltMode(m_hdc,COLORONCOLOR)); - EXECUTE_ASSERT(SetStretchBltMode(m_MemoryDC,COLORONCOLOR)); - } - - return NOERROR; -} - -HRESULT CBaseWindow::DoCreateWindow() -{ - WNDCLASS wndclass; // Used to register classes - BOOL bRegistered; // Is this class registered - HWND hwnd; // Handle to our window - - bRegistered = GetClassInfo(m_hInstance, // Module instance - m_pClassName, // Window class - &wndclass); // Info structure - - // if the window is to be used for drawing puposes and we are getting a DC - // for the entire lifetime of the window then changes the class style to do - // say so. If we don't set this flag then the DC comes from the cache and is - // really bad. - if (m_bDoGetDC) - { - m_ClassStyles |= CS_OWNDC; - } - - if (bRegistered == FALSE) { - - // Register the renderer window class - - wndclass.lpszClassName = m_pClassName; - wndclass.style = m_ClassStyles; - wndclass.lpfnWndProc = WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = sizeof(CBaseWindow *); - wndclass.hInstance = m_hInstance; - wndclass.hIcon = NULL; - wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); - wndclass.hbrBackground = (HBRUSH) NULL; - wndclass.lpszMenuName = NULL; - - RegisterClass(&wndclass); - } - - // Create the frame window. Pass the pBaseWindow information in the - // CreateStruct which allows our message handling loop to get hold of - // the pBaseWindow pointer. - - CBaseWindow *pBaseWindow = this; // The owner window object - hwnd = CreateWindowEx(m_WindowStylesEx, // Extended styles - m_pClassName, // Registered name - TEXT("ActiveMovie Window"), // Window title - m_WindowStyles, // Window styles - CW_USEDEFAULT, // Start x position - CW_USEDEFAULT, // Start y position - DEFWIDTH, // Window width - DEFHEIGHT, // Window height - NULL, // Parent handle - NULL, // Menu handle - m_hInstance, // Instance handle - &pBaseWindow); // Creation data - - // If we failed signal an error to the object constructor (based on the - // last Win32 error on this thread) then signal the constructor thread - // to continue, release the mutex to let others have a go and exit - - if (hwnd == NULL) { - DWORD Error = GetLastError(); - return AmHresultFromWin32(Error); - } - - // Check the window LONG is the object who created us - ASSERT(GetWindowLongPtr(hwnd, 0) == (LONG_PTR)this); - - // Initialise the window and then signal the constructor so that it can - // continue and then finally unlock the object's critical section. The - // window class is left registered even after we terminate the thread - // as we don't know when the last window has been closed. So we allow - // the operating system to free the class resources as appropriate - - InitialiseWindow(hwnd); - - DbgLog((LOG_TRACE, 2, TEXT("Created window class (%s) HWND(%8.8X)"), - m_pClassName, hwnd)); - - return S_OK; -} - - -// The base class provides some default handling and calls DefWindowProc - -INT_PTR CBaseWindow::OnReceiveMessage(HWND hwnd, // Window handle - UINT uMsg, // Message ID - WPARAM wParam, // First parameter - LPARAM lParam) // Other parameter -{ - ASSERT(IsWindow(hwnd)); - - if (PossiblyEatMessage(uMsg, wParam, lParam)) - return 0; - - // This is sent by the IVideoWindow SetWindowForeground method. If the - // window is invisible we will show it and make it topmost without the - // foreground focus. If the window is visible it will also be made the - // topmost window without the foreground focus. If wParam is TRUE then - // for both cases the window will be forced into the foreground focus - - if (uMsg == m_ShowStageMessage) { - - BOOL bVisible = IsWindowVisible(hwnd); - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | - (bVisible ? SWP_NOACTIVATE : 0)); - - // Should we bring the window to the foreground - if (wParam == TRUE) { - SetForegroundWindow(hwnd); - } - return (LRESULT) 1; - } - - // When we go fullscreen we have to add the WS_EX_TOPMOST style to the - // video window so that it comes out above any task bar (this is more - // relevant to WindowsNT than Windows95). However the SetWindowPos call - // must be on the same thread as that which created the window. The - // wParam parameter can be TRUE or FALSE to set and reset the topmost - - if (uMsg == m_ShowStageTop) { - HWND HwndTop = (wParam == TRUE ? HWND_TOPMOST : HWND_NOTOPMOST); - BOOL bVisible = IsWindowVisible(hwnd); - SetWindowPos(hwnd, HwndTop, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | - (wParam == TRUE ? SWP_SHOWWINDOW : 0) | - (bVisible ? SWP_NOACTIVATE : 0)); - return (LRESULT) 1; - } - - // New palette stuff - if (uMsg == m_RealizePalette) { - ASSERT(m_hwnd == hwnd); - return OnPaletteChange(m_hwnd,WM_QUERYNEWPALETTE); - } - - switch (uMsg) { - - // Repaint the window if the system colours change - - case WM_SYSCOLORCHANGE: - - InvalidateRect(hwnd,NULL,FALSE); - return (LRESULT) 1; - - // Somebody has changed the palette - case WM_PALETTECHANGED: - - OnPaletteChange((HWND)wParam,uMsg); - return (LRESULT) 0; - - // We are about to receive the keyboard focus so we ask GDI to realise - // our logical palette again and hopefully it will be fully installed - // without any mapping having to be done during any picture rendering - - case WM_QUERYNEWPALETTE: - ASSERT(m_hwnd == hwnd); - return OnPaletteChange(m_hwnd,uMsg); - - // do NOT fwd WM_MOVE. the parameters are the location of the parent - // window, NOT what the renderer should be looking at. But we need - // to make sure the overlay is moved with the parent window, so we - // do this. - case WM_MOVE: - if (IsWindowVisible(m_hwnd)) { - PostMessage(m_hwnd,WM_PAINT,0,0); - } - break; - - // Store the width and height as useful base class members - - case WM_SIZE: - - OnSize(LOWORD(lParam), HIWORD(lParam)); - return (LRESULT) 0; - - // Intercept the WM_CLOSE messages to hide the window - - case WM_CLOSE: - - OnClose(); - return (LRESULT) 0; - } - return DefWindowProc(hwnd,uMsg,wParam,lParam); -} - - -// This handles the Windows palette change messages - if we do realise our -// palette then we return TRUE otherwise we return FALSE. If our window is -// foreground application then we should get first choice of colours in the -// system palette entries. We get best performance when our logical palette -// includes the standard VGA colours (at the beginning and end) otherwise -// GDI may have to map from our palette to the device palette while drawing - -LRESULT CBaseWindow::OnPaletteChange(HWND hwnd,UINT Message) -{ - // First check we are not changing the palette during closedown - - if (m_hwnd == NULL || hwnd == NULL) { - return (LRESULT) 0; - } - ASSERT(!m_bRealizing); - - // Should we realise our palette again - - if ((Message == WM_QUERYNEWPALETTE || hwnd != m_hwnd)) { - // It seems that even if we're invisible that we can get asked - // to realize our palette and this can cause really ugly side-effects - // Seems like there's another bug but this masks it a least for the - // shutting down case. - if (!IsWindowVisible(m_hwnd)) { - DbgLog((LOG_TRACE, 1, TEXT("Realizing when invisible!"))); - return (LRESULT) 0; - } - - // Avoid recursion with multiple graphs in the same app -#ifdef _DEBUG - m_bRealizing = TRUE; -#endif - DoRealisePalette(Message != WM_QUERYNEWPALETTE); -#ifdef _DEBUG - m_bRealizing = FALSE; -#endif - - // Should we redraw the window with the new palette - if (Message == WM_PALETTECHANGED) { - InvalidateRect(m_hwnd,NULL,FALSE); - } - } - - return (LRESULT) 1; -} - - -// Determine if the window exists. - -bool CBaseWindow::WindowExists() -{ - return !!IsWindow(m_hwnd); -} - - -// Return the default window rectangle - -RECT CBaseWindow::GetDefaultRect() -{ - RECT DefaultRect = {0,0,DEFWIDTH,DEFHEIGHT}; - ASSERT(m_hwnd); - // ASSERT(m_hdc); - return DefaultRect; -} - - -// Return the current window width - -LONG CBaseWindow::GetWindowWidth() -{ - ASSERT(m_hwnd); - // ASSERT(m_hdc); - return m_Width; -} - - -// Return the current window height - -LONG CBaseWindow::GetWindowHeight() -{ - ASSERT(m_hwnd); - // ASSERT(m_hdc); - return m_Height; -} - - -// Return the window handle - -HWND CBaseWindow::GetWindowHWND() -{ - ASSERT(m_hwnd); - // ASSERT(m_hdc); - return m_hwnd; -} - - -// Return the window drawing device context - -HDC CBaseWindow::GetWindowHDC() -{ - ASSERT(m_hwnd); - ASSERT(m_hdc); - return m_hdc; -} - - -// Return the offscreen window drawing device context - -HDC CBaseWindow::GetMemoryHDC() -{ - ASSERT(m_hwnd); - ASSERT(m_MemoryDC); - return m_MemoryDC; -} - - -#ifdef _DEBUG -HPALETTE CBaseWindow::GetPalette() -{ - // The palette lock should always be held when accessing - // m_hPalette. - ASSERT(CritCheckIn(&m_PaletteLock)); - return m_hPalette; -} -#endif // DEBUG - - -// This is available to clients who want to change the window visiblity. It's -// little more than an indirection to the Win32 ShowWindow although these is -// some benefit in going through here as this function may change sometime - -HRESULT CBaseWindow::DoShowWindow(LONG ShowCmd) -{ - ShowWindow(m_hwnd,ShowCmd); - return NOERROR; -} - - -// Generate a WM_PAINT message for the video window - -void CBaseWindow::PaintWindow(BOOL bErase) -{ - InvalidateRect(m_hwnd,NULL,bErase); -} - - -// Allow an application to have us set the video window in the foreground. We -// have this because it is difficult for one thread to do do this to a window -// owned by another thread. Rather than expose the message we use to execute -// the inter thread send message we provide the interface function. All we do -// is to SendMessage to the video window renderer thread with a WM_SHOWSTAGE - -void CBaseWindow::DoSetWindowForeground(BOOL bFocus) -{ - SendMessage(m_hwnd,m_ShowStageMessage,(WPARAM) bFocus,(LPARAM) 0); -} - - -// Constructor initialises the owning object pointer. Since we are a worker -// class for the main window object we have relatively few state variables to -// look after. We are given device context handles to use later on as well as -// the source and destination rectangles (but reset them here just in case) - -CDrawImage::CDrawImage(__inout CBaseWindow *pBaseWindow) : - m_pBaseWindow(pBaseWindow), - m_hdc(NULL), - m_MemoryDC(NULL), - m_bStretch(FALSE), - m_pMediaType(NULL), - m_bUsingImageAllocator(FALSE) -{ - ASSERT(pBaseWindow); - ResetPaletteVersion(); - SetRectEmpty(&m_TargetRect); - SetRectEmpty(&m_SourceRect); - - m_perfidRenderTime = MSR_REGISTER(TEXT("Single Blt time")); -} - - -// Overlay the image time stamps on the picture. Access to this method is -// serialised by the caller. We display the sample start and end times on -// top of the video using TextOut on the device context we are handed. If -// there isn't enough room in the window for the times we don't show them - -void CDrawImage::DisplaySampleTimes(IMediaSample *pSample) -{ -#ifdef _DEBUG - // - // Only allow the "annoying" time messages if the users has turned the - // logging "way up" - // - BOOL bAccept = DbgCheckModuleLevel(LOG_TRACE, 5); - if (bAccept == FALSE) { - return; - } -#endif - - TCHAR szTimes[TIMELENGTH]; // Time stamp strings - ASSERT(pSample); // Quick sanity check - RECT ClientRect; // Client window size - SIZE Size; // Size of text output - - // Get the time stamps and window size - - pSample->GetTime((REFERENCE_TIME*)&m_StartSample, (REFERENCE_TIME*)&m_EndSample); - HWND hwnd = m_pBaseWindow->GetWindowHWND(); - EXECUTE_ASSERT(GetClientRect(hwnd,&ClientRect)); - - // Format the sample time stamps - - (void)StringCchPrintf(szTimes,NUMELMS(szTimes),TEXT("%08d : %08d"), - m_StartSample.Millisecs(), - m_EndSample.Millisecs()); - - ASSERT(lstrlen(szTimes) < TIMELENGTH); - - // Put the times in the middle at the bottom of the window - - GetTextExtentPoint32(m_hdc,szTimes,lstrlen(szTimes),&Size); - INT XPos = ((ClientRect.right - ClientRect.left) - Size.cx) / 2; - INT YPos = ((ClientRect.bottom - ClientRect.top) - Size.cy) * 4 / 5; - - // Check the window is big enough to have sample times displayed - - if ((XPos > 0) && (YPos > 0)) { - TextOut(m_hdc,XPos,YPos,szTimes,lstrlen(szTimes)); - } -} - - -// This is called when the drawing code sees that the image has a down level -// palette cookie. We simply call the SetDIBColorTable Windows API with the -// palette that is found after the BITMAPINFOHEADER - we return no errors - -void CDrawImage::UpdateColourTable(HDC hdc,__in BITMAPINFOHEADER *pbmi) -{ - ASSERT(pbmi->biClrUsed); - RGBQUAD *pColourTable = (RGBQUAD *)(pbmi+1); - - // Set the new palette in the device context - - UINT uiReturn = SetDIBColorTable(hdc,(UINT) 0, - pbmi->biClrUsed, - pColourTable); - - // Should always succeed but check in debug builds - ASSERT(uiReturn == pbmi->biClrUsed); - UNREFERENCED_PARAMETER(uiReturn); -} - - -// No source rectangle scaling is done by the base class - -RECT CDrawImage::ScaleSourceRect(const RECT *pSource) -{ - ASSERT(pSource); - return *pSource; -} - - -// This is called when the funky output pin uses our allocator. The samples we -// allocate are special because the memory is shared between us and GDI thus -// removing one copy when we ask for the image to be rendered. The source type -// information is in the main renderer m_mtIn field which is initialised when -// the media type is agreed in SetMediaType, the media type may be changed on -// the fly if, for example, the source filter needs to change the palette - -void CDrawImage::FastRender(IMediaSample *pMediaSample) -{ - BITMAPINFOHEADER *pbmi; // Image format data - DIBDATA *pDibData; // Stores DIB information - BYTE *pImage; // Pointer to image data - HBITMAP hOldBitmap; // Store the old bitmap - CImageSample *pSample; // Pointer to C++ object - - ASSERT(m_pMediaType); - - // From the untyped source format block get the VIDEOINFO and subsequently - // the BITMAPINFOHEADER structure. We can cast the IMediaSample interface - // to a CImageSample object so we can retrieve it's DIBSECTION details - - pbmi = HEADER(m_pMediaType->Format()); - pSample = (CImageSample *) pMediaSample; - pDibData = pSample->GetDIBData(); - hOldBitmap = (HBITMAP) SelectObject(m_MemoryDC,pDibData->hBitmap); - - // Get a pointer to the real image data - - HRESULT hr = pMediaSample->GetPointer(&pImage); - if (FAILED(hr)) { - return; - } - - // Do we need to update the colour table, we increment our palette cookie - // each time we get a dynamic format change. The sample palette cookie is - // stored in the DIBDATA structure so we try to keep the fields in sync - // By the time we get to draw the images the format change will be done - // so all we do is ask the renderer for what it's palette version is - - if (pDibData->PaletteVersion < GetPaletteVersion()) { - ASSERT(pbmi->biBitCount <= iPALETTE); - UpdateColourTable(m_MemoryDC,pbmi); - pDibData->PaletteVersion = GetPaletteVersion(); - } - - // This allows derived classes to change the source rectangle that we do - // the drawing with. For example a renderer may ask a codec to stretch - // the video from 320x240 to 640x480, in which case the source we see in - // here will still be 320x240, although the source we want to draw with - // should be scaled up to 640x480. The base class implementation of this - // method does nothing but return the same rectangle as we are passed in - - RECT SourceRect = ScaleSourceRect(&m_SourceRect); - - // Is the window the same size as the video - - if (m_bStretch == FALSE) { - - // Put the image straight into the window - - BitBlt( - (HDC) m_hdc, // Target device HDC - m_TargetRect.left, // X sink position - m_TargetRect.top, // Y sink position - m_TargetRect.right - m_TargetRect.left, // Destination width - m_TargetRect.bottom - m_TargetRect.top, // Destination height - m_MemoryDC, // Source device context - SourceRect.left, // X source position - SourceRect.top, // Y source position - SRCCOPY); // Simple copy - - } else { - - // Stretch the image when copying to the window - - StretchBlt( - (HDC) m_hdc, // Target device HDC - m_TargetRect.left, // X sink position - m_TargetRect.top, // Y sink position - m_TargetRect.right - m_TargetRect.left, // Destination width - m_TargetRect.bottom - m_TargetRect.top, // Destination height - m_MemoryDC, // Source device HDC - SourceRect.left, // X source position - SourceRect.top, // Y source position - SourceRect.right - SourceRect.left, // Source width - SourceRect.bottom - SourceRect.top, // Source height - SRCCOPY); // Simple copy - } - - // This displays the sample times over the top of the image. This used to - // draw the times into the offscreen device context however that actually - // writes the text into the image data buffer which may not be writable - - #ifdef _DEBUG - DisplaySampleTimes(pMediaSample); - #endif - - // Put the old bitmap back into the device context so we don't leak - SelectObject(m_MemoryDC,hOldBitmap); -} - - -// This is called when there is a sample ready to be drawn, unfortunately the -// output pin was being rotten and didn't choose our super excellent shared -// memory DIB allocator so we have to do this slow render using boring old GDI -// SetDIBitsToDevice and StretchDIBits. The down side of using these GDI -// functions is that the image data has to be copied across from our address -// space into theirs before going to the screen (although in reality the cost -// is small because all they do is to map the buffer into their address space) - -void CDrawImage::SlowRender(IMediaSample *pMediaSample) -{ - // Get the BITMAPINFOHEADER for the connection - - ASSERT(m_pMediaType); - BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); - BYTE *pImage; - - // Get the image data buffer - - HRESULT hr = pMediaSample->GetPointer(&pImage); - if (FAILED(hr)) { - return; - } - - // This allows derived classes to change the source rectangle that we do - // the drawing with. For example a renderer may ask a codec to stretch - // the video from 320x240 to 640x480, in which case the source we see in - // here will still be 320x240, although the source we want to draw with - // should be scaled up to 640x480. The base class implementation of this - // method does nothing but return the same rectangle as we are passed in - - RECT SourceRect = ScaleSourceRect(&m_SourceRect); - - LONG lAdjustedSourceTop = SourceRect.top; - // if the origin of bitmap is bottom-left, adjust soruce_rect_top - // to be the bottom-left corner instead of the top-left. - if (pbmi->biHeight > 0) { - lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; - } - // Is the window the same size as the video - - if (m_bStretch == FALSE) { - - // Put the image straight into the window - - SetDIBitsToDevice( - (HDC) m_hdc, // Target device HDC - m_TargetRect.left, // X sink position - m_TargetRect.top, // Y sink position - m_TargetRect.right - m_TargetRect.left, // Destination width - m_TargetRect.bottom - m_TargetRect.top, // Destination height - SourceRect.left, // X source position - lAdjustedSourceTop, // Adjusted Y source position - (UINT) 0, // Start scan line - pbmi->biHeight, // Scan lines present - pImage, // Image data - (BITMAPINFO *) pbmi, // DIB header - DIB_RGB_COLORS); // Type of palette - - } else { - - // Stretch the image when copying to the window - - StretchDIBits( - (HDC) m_hdc, // Target device HDC - m_TargetRect.left, // X sink position - m_TargetRect.top, // Y sink position - m_TargetRect.right - m_TargetRect.left, // Destination width - m_TargetRect.bottom - m_TargetRect.top, // Destination height - SourceRect.left, // X source position - lAdjustedSourceTop, // Adjusted Y source position - SourceRect.right - SourceRect.left, // Source width - SourceRect.bottom - SourceRect.top, // Source height - pImage, // Image data - (BITMAPINFO *) pbmi, // DIB header - DIB_RGB_COLORS, // Type of palette - SRCCOPY); // Simple image copy - } - - // This shows the sample reference times over the top of the image which - // looks a little flickery. I tried using GdiSetBatchLimit and GdiFlush to - // control the screen updates but it doesn't quite work as expected and - // only partially reduces the flicker. I also tried using a memory context - // and combining the two in that before doing a final BitBlt operation to - // the screen, unfortunately this has considerable performance penalties - // and also means that this code is not executed when compiled retail - - #ifdef _DEBUG - DisplaySampleTimes(pMediaSample); - #endif -} - - -// This is called with an IMediaSample interface on the image to be drawn. We -// decide on the drawing mechanism based on who's allocator we are using. We -// may be called when the window wants an image painted by WM_PAINT messages -// We can't realise the palette here because we have the renderer lock, any -// call to realise may cause an interthread send message to the window thread -// which may in turn be waiting to get the renderer lock before servicing it - -BOOL CDrawImage::DrawImage(IMediaSample *pMediaSample) -{ - ASSERT(m_hdc); - ASSERT(m_MemoryDC); - NotifyStartDraw(); - - // If the output pin used our allocator then the samples passed are in - // fact CVideoSample objects that contain CreateDIBSection data that we - // use to do faster image rendering, they may optionally also contain a - // DirectDraw surface pointer in which case we do not do the drawing - - if (m_bUsingImageAllocator == FALSE) { - SlowRender(pMediaSample); - EXECUTE_ASSERT(GdiFlush()); - NotifyEndDraw(); - return TRUE; - } - - // This is a DIBSECTION buffer - - FastRender(pMediaSample); - EXECUTE_ASSERT(GdiFlush()); - NotifyEndDraw(); - return TRUE; -} - - -BOOL CDrawImage::DrawVideoImageHere( - HDC hdc, - IMediaSample *pMediaSample, - __in LPRECT lprcSrc, - __in LPRECT lprcDst - ) -{ - ASSERT(m_pMediaType); - BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); - BYTE *pImage; - - // Get the image data buffer - - HRESULT hr = pMediaSample->GetPointer(&pImage); - if (FAILED(hr)) { - return FALSE; - } - - RECT SourceRect; - RECT TargetRect; - - if (lprcSrc) { - SourceRect = *lprcSrc; - } - else SourceRect = ScaleSourceRect(&m_SourceRect); - - if (lprcDst) { - TargetRect = *lprcDst; - } - else TargetRect = m_TargetRect; - - LONG lAdjustedSourceTop = SourceRect.top; - // if the origin of bitmap is bottom-left, adjust soruce_rect_top - // to be the bottom-left corner instead of the top-left. - if (pbmi->biHeight > 0) { - lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; - } - - - // Stretch the image when copying to the DC - - BOOL bRet = (0 != StretchDIBits(hdc, - TargetRect.left, - TargetRect.top, - TargetRect.right - TargetRect.left, - TargetRect.bottom - TargetRect.top, - SourceRect.left, - lAdjustedSourceTop, - SourceRect.right - SourceRect.left, - SourceRect.bottom - SourceRect.top, - pImage, - (BITMAPINFO *)pbmi, - DIB_RGB_COLORS, - SRCCOPY)); - return bRet; -} - - -// This is called by the owning window object after it has created the window -// and it's drawing contexts. We are constructed with the base window we'll -// be drawing into so when given the notification we retrive the device HDCs -// to draw with. We cannot call these in our constructor as they are virtual - -void CDrawImage::SetDrawContext() -{ - m_MemoryDC = m_pBaseWindow->GetMemoryHDC(); - m_hdc = m_pBaseWindow->GetWindowHDC(); -} - - -// This is called to set the target rectangle in the video window, it will be -// called whenever a WM_SIZE message is retrieved from the message queue. We -// simply store the rectangle and use it later when we do the drawing calls - -void CDrawImage::SetTargetRect(__in RECT *pTargetRect) -{ - ASSERT(pTargetRect); - m_TargetRect = *pTargetRect; - SetStretchMode(); -} - - -// Return the current target rectangle - -void CDrawImage::GetTargetRect(__out RECT *pTargetRect) -{ - ASSERT(pTargetRect); - *pTargetRect = m_TargetRect; -} - - -// This is called when we want to change the section of the image to draw. We -// use this information in the drawing operation calls later on. We must also -// see if the source and destination rectangles have the same dimensions. If -// not we must stretch during the drawing rather than a direct pixel copy - -void CDrawImage::SetSourceRect(__in RECT *pSourceRect) -{ - ASSERT(pSourceRect); - m_SourceRect = *pSourceRect; - SetStretchMode(); -} - - -// Return the current source rectangle - -void CDrawImage::GetSourceRect(__out RECT *pSourceRect) -{ - ASSERT(pSourceRect); - *pSourceRect = m_SourceRect; -} - - -// This is called when either the source or destination rectanges change so we -// can update the stretch flag. If the rectangles don't match we stretch the -// video during the drawing otherwise we call the fast pixel copy functions -// NOTE the source and/or the destination rectangle may be completely empty - -void CDrawImage::SetStretchMode() -{ - // Calculate the overall rectangle dimensions - - LONG SourceWidth = m_SourceRect.right - m_SourceRect.left; - LONG SinkWidth = m_TargetRect.right - m_TargetRect.left; - LONG SourceHeight = m_SourceRect.bottom - m_SourceRect.top; - LONG SinkHeight = m_TargetRect.bottom - m_TargetRect.top; - - m_bStretch = TRUE; - if (SourceWidth == SinkWidth) { - if (SourceHeight == SinkHeight) { - m_bStretch = FALSE; - } - } -} - - -// Tell us whose allocator we are using. This should be called with TRUE if -// the filter agrees to use an allocator based around the CImageAllocator -// SDK base class - whose image buffers are made through CreateDIBSection. -// Otherwise this should be called with FALSE and we will draw the images -// using SetDIBitsToDevice and StretchDIBitsToDevice. None of these calls -// can handle buffers which have non zero strides (like DirectDraw uses) - -void CDrawImage::NotifyAllocator(BOOL bUsingImageAllocator) -{ - m_bUsingImageAllocator = bUsingImageAllocator; -} - - -// Are we using the image DIBSECTION allocator - -BOOL CDrawImage::UsingImageAllocator() -{ - return m_bUsingImageAllocator; -} - - -// We need the media type of the connection so that we can get the BITMAPINFO -// from it. We use that in the calls to draw the image such as StretchDIBits -// and also when updating the colour table held in shared memory DIBSECTIONs - -void CDrawImage::NotifyMediaType(__in CMediaType *pMediaType) -{ - m_pMediaType = pMediaType; -} - - -// We store in this object a cookie maintaining the current palette version. -// Each time a palettised format is changed we increment this value so that -// when we come to draw the images we look at the colour table value they -// have and if less than the current we know to update it. This version is -// only needed and indeed used when working with shared memory DIBSECTIONs - -LONG CDrawImage::GetPaletteVersion() -{ - return m_PaletteVersion; -} - - -// Resets the current palette version number - -void CDrawImage::ResetPaletteVersion() -{ - m_PaletteVersion = PALETTE_VERSION; -} - - -// Increment the current palette version - -void CDrawImage::IncrementPaletteVersion() -{ - m_PaletteVersion++; -} - - -// Constructor must initialise the base allocator. Each sample we create has a -// palette version cookie on board. When the source filter changes the palette -// during streaming the window object increments an internal cookie counter it -// keeps as well. When it comes to render the samples it looks at the cookie -// values and if they don't match then it knows to update the sample's colour -// table. However we always create samples with a cookie of PALETTE_VERSION -// If there have been multiple format changes and we disconnect and reconnect -// thereby causing the samples to be reallocated we will create them with a -// cookie much lower than the current version, this isn't a problem since it -// will be seen by the window object and the versions will then be updated - -CImageAllocator::CImageAllocator(__inout CBaseFilter *pFilter, - __in_opt LPCTSTR pName, - __inout HRESULT *phr) : - CBaseAllocator(pName,NULL,phr,TRUE,TRUE), - m_pFilter(pFilter), - m_pMediaType(NULL) -{ - ASSERT(phr); - ASSERT(pFilter); -} - - -// Check our DIB buffers have been released - -#ifdef _DEBUG -CImageAllocator::~CImageAllocator() -{ - ASSERT(m_bCommitted == FALSE); -} -#endif - - -// Called from destructor and also from base class to free resources. We work -// our way through the list of media samples deleting the DIBSECTION created -// for each. All samples should be back in our list so there is no chance a -// filter is still using one to write on the display or hold on a pending list - -void CImageAllocator::Free() -{ - ASSERT(m_lAllocated == m_lFree.GetCount()); - EXECUTE_ASSERT(GdiFlush()); - CImageSample *pSample; - DIBDATA *pDibData; - - while (m_lFree.GetCount() != 0) { - pSample = (CImageSample *) m_lFree.RemoveHead(); - pDibData = pSample->GetDIBData(); - EXECUTE_ASSERT(DeleteObject(pDibData->hBitmap)); - EXECUTE_ASSERT(CloseHandle(pDibData->hMapping)); - delete pSample; - } - - m_lAllocated = 0; -} - - -// Prepare the allocator by checking all the input parameters - -STDMETHODIMP CImageAllocator::CheckSizes(__in ALLOCATOR_PROPERTIES *pRequest) -{ - // Check we have a valid connection - - if (m_pMediaType == NULL) { - return VFW_E_NOT_CONNECTED; - } - - // NOTE We always create a DIB section with the source format type which - // may contain a source palette. When we do the BitBlt drawing operation - // the target display device may contain a different palette (we may not - // have the focus) in which case GDI will do after the palette mapping - - VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *) m_pMediaType->Format(); - - // When we call CreateDIBSection it implicitly maps only enough memory - // for the image as defined by thee BITMAPINFOHEADER. If the user asks - // for an image smaller than this then we reject the call, if they ask - // for an image larger than this then we return what they can have - - if ((DWORD) pRequest->cbBuffer < pVideoInfo->bmiHeader.biSizeImage) { - return E_INVALIDARG; - } - - // Reject buffer prefixes - - if (pRequest->cbPrefix > 0) { - return E_INVALIDARG; - } - - pRequest->cbBuffer = pVideoInfo->bmiHeader.biSizeImage; - return NOERROR; -} - - -// Agree the number of media sample buffers and their sizes. The base class -// this allocator is derived from allows samples to be aligned only on byte -// boundaries NOTE the buffers are not allocated until the Commit call - -STDMETHODIMP CImageAllocator::SetProperties( - __in ALLOCATOR_PROPERTIES * pRequest, - __out ALLOCATOR_PROPERTIES * pActual) -{ - ALLOCATOR_PROPERTIES Adjusted = *pRequest; - - // Check the parameters fit with the current connection - - HRESULT hr = CheckSizes(&Adjusted); - if (FAILED(hr)) { - return hr; - } - return CBaseAllocator::SetProperties(&Adjusted, pActual); -} - - -// Commit the memory by allocating the agreed number of media samples. For -// each sample we are committed to creating we have a CImageSample object -// that we use to manage it's resources. This is initialised with a DIBDATA -// structure that contains amongst other things the GDI DIBSECTION handle -// We will access the renderer media type during this so we must have locked -// (to prevent the format changing for example). The class overrides Commit -// and Decommit to do this locking (base class Commit in turn calls Alloc) - -HRESULT CImageAllocator::Alloc(void) -{ - ASSERT(m_pMediaType); - CImageSample *pSample; - DIBDATA DibData; - - // Check the base allocator says it's ok to continue - - HRESULT hr = CBaseAllocator::Alloc(); - if (FAILED(hr)) { - return hr; - } - - // We create a new memory mapped object although we don't map it into our - // address space because GDI does that in CreateDIBSection. It is possible - // that we run out of resources before creating all the samples in which - // case the available sample list is left with those already created - - ASSERT(m_lAllocated == 0); - while (m_lAllocated < m_lCount) { - - // Create and initialise a shared memory GDI buffer - - hr = CreateDIB(m_lSize,DibData); - if (FAILED(hr)) { - return hr; - } - - // Create the sample object and pass it the DIBDATA - - pSample = CreateImageSample(DibData.pBase,m_lSize); - if (pSample == NULL) { - EXECUTE_ASSERT(DeleteObject(DibData.hBitmap)); - EXECUTE_ASSERT(CloseHandle(DibData.hMapping)); - return E_OUTOFMEMORY; - } - - // Add the completed sample to the available list - - pSample->SetDIBData(&DibData); - m_lFree.Add(pSample); - m_lAllocated++; - } - return NOERROR; -} - - -// We have a virtual method that allocates the samples so that a derived class -// may override it and allocate more specialised sample objects. So long as it -// derives its samples from CImageSample then all this code will still work ok - -CImageSample *CImageAllocator::CreateImageSample(__in_bcount(Length) LPBYTE pData,LONG Length) -{ - HRESULT hr = NOERROR; - CImageSample *pSample; - - // Allocate the new sample and check the return codes - - pSample = new CImageSample((CBaseAllocator *) this, // Base class - NAME("Video sample"), // DEBUG name - (HRESULT *) &hr, // Return code - (LPBYTE) pData, // DIB address - (LONG) Length); // Size of DIB - - if (pSample == NULL || FAILED(hr)) { - delete pSample; - return NULL; - } - return pSample; -} - - -// This function allocates a shared memory block for use by the source filter -// generating DIBs for us to render. The memory block is created in shared -// memory so that GDI doesn't have to copy the memory when we do a BitBlt - -HRESULT CImageAllocator::CreateDIB(LONG InSize,DIBDATA &DibData) -{ - BITMAPINFO *pbmi = NULL; // Format information for pin - BYTE *pBase = NULL; // Pointer to the actual image - HANDLE hMapping; // Handle to mapped object - HBITMAP hBitmap = NULL; // DIB section bitmap handle - - // Create a file mapping object and map into our address space - - hMapping = CreateFileMapping(hMEMORY, // Use system page file - NULL, // No security attributes - PAGE_READWRITE, // Full access to memory - (DWORD) 0, // Less than 4Gb in size - InSize, // Size of buffer - NULL); // No name to section - if (hMapping == NULL) { - DWORD Error = GetLastError(); - return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); - } - - // NOTE We always create a DIB section with the source format type which - // may contain a source palette. When we do the BitBlt drawing operation - // the target display device may contain a different palette (we may not - // have the focus) in which case GDI will do after the palette mapping - - if (m_pMediaType) { - pbmi = (BITMAPINFO *)HEADER(m_pMediaType->Format()); - hBitmap = CreateDIBSection((HDC)NULL, // NO device context - pbmi, // Format information - DIB_RGB_COLORS, // Use the palette - (VOID **)&pBase, // Pointer to image data - hMapping, // Mapped memory handle - (DWORD)0); // Offset into memory - } else { - DbgBreak("Invalid media type"); - } - - if (hBitmap == NULL || pBase == NULL) { - EXECUTE_ASSERT(CloseHandle(hMapping)); - DWORD Error = GetLastError(); - return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); - } - - // Initialise the DIB information structure - - DibData.hBitmap = hBitmap; - DibData.hMapping = hMapping; - DibData.pBase = pBase; - DibData.PaletteVersion = PALETTE_VERSION; - GetObject(hBitmap,sizeof(DIBSECTION),(VOID *)&DibData.DibSection); - - return NOERROR; -} - - -// We use the media type during the DIBSECTION creation - -void CImageAllocator::NotifyMediaType(__in CMediaType *pMediaType) -{ - m_pMediaType = pMediaType; -} - - -// Overriden to increment the owning object's reference count - -STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingAddRef() -{ - return m_pFilter->AddRef(); -} - - -// Overriden to decrement the owning object's reference count - -STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingRelease() -{ - return m_pFilter->Release(); -} - - -// If you derive a class from CMediaSample that has to transport specialised -// member variables and entry points then there are three alternate solutions -// The first is to create a memory buffer larger than actually required by the -// sample and store your information either at the beginning of it or at the -// end, the former being moderately safer allowing for misbehaving transform -// filters. You then adjust the buffer address when you create the base media -// sample. This has the disadvantage of breaking up the memory allocated to -// the samples into separate blocks. The second solution is to implement a -// class derived from CMediaSample and support additional interface(s) that -// convey your private data. This means defining a custom interface. The final -// alternative is to create a class that inherits from CMediaSample and adds -// the private data structures, when you get an IMediaSample in your Receive() -// call check to see if your allocator is being used, and if it is then cast -// the IMediaSample into one of your objects. Additional checks can be made -// to ensure the sample's this pointer is known to be one of your own objects - -CImageSample::CImageSample(__inout CBaseAllocator *pAllocator, - __in_opt LPCTSTR pName, - __inout HRESULT *phr, - __in_bcount(length) LPBYTE pBuffer, - LONG length) : - CMediaSample(pName,pAllocator,phr,pBuffer,length), - m_bInit(FALSE) -{ - ZeroMemory(&m_DibData, sizeof(DIBDATA)); - ASSERT(pAllocator); - ASSERT(pBuffer); -} - - -// Set the shared memory DIB information - -void CImageSample::SetDIBData(__in DIBDATA *pDibData) -{ - ASSERT(pDibData); - m_DibData = *pDibData; - m_bInit = TRUE; -} - - -// Retrieve the shared memory DIB data - -__out DIBDATA *CImageSample::GetDIBData() -{ - ASSERT(m_bInit == TRUE); - return &m_DibData; -} - - -// This class handles the creation of a palette. It is fairly specialist and -// is intended to simplify palette management for video renderer filters. It -// is for this reason that the constructor requires three other objects with -// which it interacts, namely a base media filter, a base window and a base -// drawing object although the base window or the draw object may be NULL to -// ignore that part of us. We try not to create and install palettes unless -// absolutely necessary as they typically require WM_PALETTECHANGED messages -// to be sent to every window thread in the system which is very expensive - -CImagePalette::CImagePalette(__inout CBaseFilter *pBaseFilter, - __inout CBaseWindow *pBaseWindow, - __inout CDrawImage *pDrawImage) : - m_pBaseWindow(pBaseWindow), - m_pFilter(pBaseFilter), - m_pDrawImage(pDrawImage), - m_hPalette(NULL) -{ - ASSERT(m_pFilter); -} - - -// Destructor - -#ifdef _DEBUG -CImagePalette::~CImagePalette() -{ - ASSERT(m_hPalette == NULL); -} -#endif - - -// We allow dynamic format changes of the palette but rather than change the -// palette every time we call this to work out whether an update is required. -// If the original type didn't use a palette and the new one does (or vica -// versa) then we return TRUE. If neither formats use a palette we'll return -// FALSE. If both formats use a palette we compare their colours and return -// FALSE if they match. This therefore short circuits palette creation unless -// absolutely necessary since installing palettes is an expensive operation - -BOOL CImagePalette::ShouldUpdate(const VIDEOINFOHEADER *pNewInfo, - const VIDEOINFOHEADER *pOldInfo) -{ - // We may not have a current format yet - - if (pOldInfo == NULL) { - return TRUE; - } - - // Do both formats not require a palette - - if (ContainsPalette(pNewInfo) == FALSE) { - if (ContainsPalette(pOldInfo) == FALSE) { - return FALSE; - } - } - - // Compare the colours to see if they match - - DWORD VideoEntries = pNewInfo->bmiHeader.biClrUsed; - if (ContainsPalette(pNewInfo) == TRUE) - if (ContainsPalette(pOldInfo) == TRUE) - if (pOldInfo->bmiHeader.biClrUsed == VideoEntries) - if (pOldInfo->bmiHeader.biClrUsed > 0) - if (memcmp((PVOID) GetBitmapPalette(pNewInfo), - (PVOID) GetBitmapPalette(pOldInfo), - VideoEntries * sizeof(RGBQUAD)) == 0) { - - return FALSE; - } - return TRUE; -} - - -// This is normally called when the input pin type is set to install a palette -// We will typically be called from two different places. The first is when we -// have negotiated a palettised media type after connection, the other is when -// we receive a new type during processing with an updated palette in which -// case we must remove and release the resources held by the current palette - -// We can be passed an optional device name if we wish to prepare a palette -// for a specific monitor on a multi monitor system - -HRESULT CImagePalette::PreparePalette(const CMediaType *pmtNew, - const CMediaType *pmtOld, - __in LPSTR szDevice) -{ - const VIDEOINFOHEADER *pNewInfo = (VIDEOINFOHEADER *) pmtNew->Format(); - const VIDEOINFOHEADER *pOldInfo = (VIDEOINFOHEADER *) pmtOld->Format(); - ASSERT(pNewInfo); - - // This is an performance optimisation, when we get a media type we check - // to see if the format requires a palette change. If either we need one - // when previously we didn't or vica versa then this returns TRUE, if we - // previously needed a palette and we do now it compares their colours - - if (ShouldUpdate(pNewInfo,pOldInfo) == FALSE) { - NOTE("No update needed"); - return S_FALSE; - } - - // We must notify the filter graph that the application may have changed - // the palette although in practice we don't bother checking to see if it - // is really different. If it tries to get the palette either the window - // or renderer lock will ensure it doesn't get in until we are finished - - RemovePalette(); - m_pFilter->NotifyEvent(EC_PALETTE_CHANGED,0,0); - - // Do we need a palette for the new format - - if (ContainsPalette(pNewInfo) == FALSE) { - NOTE("New has no palette"); - return S_FALSE; - } - - if (m_pBaseWindow) { - m_pBaseWindow->LockPaletteLock(); - } - - // If we're changing the palette on the fly then we increment our palette - // cookie which is compared against the cookie also stored in all of our - // DIBSECTION media samples. If they don't match when we come to draw it - // then we know the sample is out of date and we'll update it's palette - - NOTE("Making new colour palette"); - m_hPalette = MakePalette(pNewInfo, szDevice); - ASSERT(m_hPalette != NULL); - - if (m_pBaseWindow) { - m_pBaseWindow->UnlockPaletteLock(); - } - - // The window in which the new palette is to be realised may be a NULL - // pointer to signal that no window is in use, if so we don't call it - // Some filters just want to use this object to create/manage palettes - - if (m_pBaseWindow) m_pBaseWindow->SetPalette(m_hPalette); - - // This is the only time where we need access to the draw object to say - // to it that a new palette will be arriving on a sample real soon. The - // constructor may take a NULL pointer in which case we don't call this - - if (m_pDrawImage) m_pDrawImage->IncrementPaletteVersion(); - return NOERROR; -} - - -// Helper function to copy a palette out of any kind of VIDEOINFO (ie it may -// be YUV or true colour) into a palettised VIDEOINFO. We use this changing -// palettes on DirectDraw samples as a source filter can attach a palette to -// any buffer (eg YUV) and hand it back. We make a new palette out of that -// format and then copy the palette colours into the current connection type - -HRESULT CImagePalette::CopyPalette(const CMediaType *pSrc,__out CMediaType *pDest) -{ - // Reset the destination palette before starting - - VIDEOINFOHEADER *pDestInfo = (VIDEOINFOHEADER *) pDest->Format(); - pDestInfo->bmiHeader.biClrUsed = 0; - pDestInfo->bmiHeader.biClrImportant = 0; - - // Does the destination have a palette - - if (PALETTISED(pDestInfo) == FALSE) { - NOTE("No destination palette"); - return S_FALSE; - } - - // Does the source contain a palette - - const VIDEOINFOHEADER *pSrcInfo = (VIDEOINFOHEADER *) pSrc->Format(); - if (ContainsPalette(pSrcInfo) == FALSE) { - NOTE("No source palette"); - return S_FALSE; - } - - // The number of colours may be zero filled - - DWORD PaletteEntries = pSrcInfo->bmiHeader.biClrUsed; - if (PaletteEntries == 0) { - DWORD Maximum = (1 << pSrcInfo->bmiHeader.biBitCount); - NOTE1("Setting maximum colours (%d)",Maximum); - PaletteEntries = Maximum; - } - - // Make sure the destination has enough room for the palette - - ASSERT(pSrcInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); - ASSERT(pSrcInfo->bmiHeader.biClrImportant <= PaletteEntries); - ASSERT(COLORS(pDestInfo) == GetBitmapPalette(pDestInfo)); - pDestInfo->bmiHeader.biClrUsed = PaletteEntries; - pDestInfo->bmiHeader.biClrImportant = pSrcInfo->bmiHeader.biClrImportant; - ULONG BitmapSize = GetBitmapFormatSize(HEADER(pSrcInfo)); - - if (pDest->FormatLength() < BitmapSize) { - NOTE("Reallocating destination"); - pDest->ReallocFormatBuffer(BitmapSize); - } - - // Now copy the palette colours across - - CopyMemory((PVOID) COLORS(pDestInfo), - (PVOID) GetBitmapPalette(pSrcInfo), - PaletteEntries * sizeof(RGBQUAD)); - - return NOERROR; -} - - -// This is normally called when the palette is changed (typically during a -// dynamic format change) to remove any palette we previously installed. We -// replace it (if necessary) in the video window with a standard VGA palette -// that should always be available even if this is a true colour display - -HRESULT CImagePalette::RemovePalette() -{ - if (m_pBaseWindow) { - m_pBaseWindow->LockPaletteLock(); - } - - // Do we have a palette to remove - - if (m_hPalette != NULL) { - - if (m_pBaseWindow) { - // Make sure that the window's palette handle matches - // our palette handle. - ASSERT(m_hPalette == m_pBaseWindow->GetPalette()); - - m_pBaseWindow->UnsetPalette(); - } - - EXECUTE_ASSERT(DeleteObject(m_hPalette)); - m_hPalette = NULL; - } - - if (m_pBaseWindow) { - m_pBaseWindow->UnlockPaletteLock(); - } - - return NOERROR; -} - - -// Called to create a palette for the object, the data structure used by GDI -// to describe a palette is a LOGPALETTE, this includes a variable number of -// PALETTEENTRY fields which are the colours, we have to convert the RGBQUAD -// colour fields we are handed in a BITMAPINFO from the media type into these -// This handles extraction of palettes from true colour and YUV media formats - -// We can be passed an optional device name if we wish to prepare a palette -// for a specific monitor on a multi monitor system - -HPALETTE CImagePalette::MakePalette(const VIDEOINFOHEADER *pVideoInfo, __in LPSTR szDevice) -{ - ASSERT(ContainsPalette(pVideoInfo) == TRUE); - ASSERT(pVideoInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); - BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); - - const RGBQUAD *pColours; // Pointer to the palette - LOGPALETTE *lp; // Used to create a palette - HPALETTE hPalette; // Logical palette object - - lp = (LOGPALETTE *) new BYTE[sizeof(LOGPALETTE) + SIZE_PALETTE]; - if (lp == NULL) { - return NULL; - } - - // Unfortunately for some hare brained reason a GDI palette entry (a - // PALETTEENTRY structure) is different to a palette entry from a DIB - // format (a RGBQUAD structure) so we have to do the field conversion - // The VIDEOINFO containing the palette may be a true colour type so - // we use GetBitmapPalette to skip over any bit fields if they exist - - lp->palVersion = PALVERSION; - lp->palNumEntries = (USHORT) pHeader->biClrUsed; - if (lp->palNumEntries == 0) lp->palNumEntries = (1 << pHeader->biBitCount); - pColours = GetBitmapPalette(pVideoInfo); - - for (DWORD dwCount = 0;dwCount < lp->palNumEntries;dwCount++) { - lp->palPalEntry[dwCount].peRed = pColours[dwCount].rgbRed; - lp->palPalEntry[dwCount].peGreen = pColours[dwCount].rgbGreen; - lp->palPalEntry[dwCount].peBlue = pColours[dwCount].rgbBlue; - lp->palPalEntry[dwCount].peFlags = 0; - } - - MakeIdentityPalette(lp->palPalEntry, lp->palNumEntries, szDevice); - - // Create a logical palette - - hPalette = CreatePalette(lp); - ASSERT(hPalette != NULL); - delete[] lp; - return hPalette; -} - - -// GDI does a fair job of compressing the palette entries you give it, so for -// example if you have five entries with an RGB colour (0,0,0) it will remove -// all but one of them. When you subsequently draw an image it will map from -// your logical palette to the compressed device palette. This function looks -// to see if it is trying to be an identity palette and if so sets the flags -// field in the PALETTEENTRYs so they remain expanded to boost performance - -// We can be passed an optional device name if we wish to prepare a palette -// for a specific monitor on a multi monitor system - -HRESULT CImagePalette::MakeIdentityPalette(__inout_ecount_full(iColours) PALETTEENTRY *pEntry,INT iColours, __in LPSTR szDevice) -{ - PALETTEENTRY SystemEntries[10]; // System palette entries - BOOL bIdentityPalette = TRUE; // Is an identity palette - ASSERT(iColours <= iPALETTE_COLORS); // Should have a palette - const int PalLoCount = 10; // First ten reserved colours - const int PalHiStart = 246; // Last VGA palette entries - - // Does this have the full colour range - - if (iColours < 10) { - return S_FALSE; - } - - // Apparently some displays have odd numbers of system colours - - // Get a DC on the right monitor - it's ugly, but this is the way you have - // to do it - HDC hdc; - if (szDevice == NULL || lstrcmpiLocaleIndependentA(szDevice, "DISPLAY") == 0) - hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); - else - hdc = CreateDCA(NULL, szDevice, NULL, NULL); - if (NULL == hdc) { - return E_OUTOFMEMORY; - } - INT Reserved = GetDeviceCaps(hdc,NUMRESERVED); - if (Reserved != 20) { - DeleteDC(hdc); - return S_FALSE; - } - - // Compare our palette against the first ten system entries. The reason I - // don't do a memory compare between our two arrays of colours is because - // I am not sure what will be in the flags fields for the system entries - - UINT Result = GetSystemPaletteEntries(hdc,0,PalLoCount,SystemEntries); - for (UINT Count = 0;Count < Result;Count++) { - if (SystemEntries[Count].peRed != pEntry[Count].peRed || - SystemEntries[Count].peGreen != pEntry[Count].peGreen || - SystemEntries[Count].peBlue != pEntry[Count].peBlue) { - bIdentityPalette = FALSE; - } - } - - // And likewise compare against the last ten entries - - Result = GetSystemPaletteEntries(hdc,PalHiStart,PalLoCount,SystemEntries); - for (UINT Count = 0;Count < Result;Count++) { - if (INT(Count) + PalHiStart < iColours) { - if (SystemEntries[Count].peRed != pEntry[PalHiStart + Count].peRed || - SystemEntries[Count].peGreen != pEntry[PalHiStart + Count].peGreen || - SystemEntries[Count].peBlue != pEntry[PalHiStart + Count].peBlue) { - bIdentityPalette = FALSE; - } - } - } - - // If not an identity palette then return S_FALSE - - DeleteDC(hdc); - if (bIdentityPalette == FALSE) { - return S_FALSE; - } - - // Set the non VGA entries so that GDI doesn't map them - - for (UINT Count = PalLoCount; INT(Count) < std::min(PalHiStart, iColours); Count++) { - pEntry[Count].peFlags = PC_NOCOLLAPSE; - } - return NOERROR; -} - - -// Constructor initialises the VIDEOINFO we keep storing the current display -// format. The format can be changed at any time, to reset the format held -// by us call the RefreshDisplayType directly (it's a public method). Since -// more than one thread will typically call us (ie window threads resetting -// the type and source threads in the type checking methods) we have a lock - -CImageDisplay::CImageDisplay() -{ - RefreshDisplayType(NULL); -} - - - -// This initialises the format we hold which contains the display device type -// We do a conversion on the display device type in here so that when we start -// type checking input formats we can assume that certain fields have been set -// correctly, an example is when we make the 16 bit mask fields explicit. This -// is normally called when we receive WM_DEVMODECHANGED device change messages - -// The optional szDeviceName parameter tells us which monitor we are interested -// in for a multi monitor system - -HRESULT CImageDisplay::RefreshDisplayType(__in_opt LPSTR szDeviceName) -{ - CAutoLock cDisplayLock(this); - - // Set the preferred format type - - ZeroMemory((PVOID)&m_Display,sizeof(VIDEOINFOHEADER)+sizeof(TRUECOLORINFO)); - m_Display.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - m_Display.bmiHeader.biBitCount = FALSE; - - // Get the bit depth of a device compatible bitmap - - // get caps of whichever monitor they are interested in (multi monitor) - HDC hdcDisplay; - // it's ugly, but this is the way you have to do it - if (szDeviceName == NULL || lstrcmpiLocaleIndependentA(szDeviceName, "DISPLAY") == 0) - hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL); - else - hdcDisplay = CreateDCA(NULL, szDeviceName, NULL, NULL); - if (hdcDisplay == NULL) { - ASSERT(FALSE); - DbgLog((LOG_ERROR,1,TEXT("ACK! Can't get a DC for %hs"), - szDeviceName ? szDeviceName : "")); - return E_FAIL; - } else { - DbgLog((LOG_TRACE,3,TEXT("Created a DC for %s"), - szDeviceName ? szDeviceName : "")); - } - HBITMAP hbm = CreateCompatibleBitmap(hdcDisplay,1,1); - if ( hbm ) - { - GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); - - // This call will get the colour table or the proper bitfields - GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); - DeleteObject(hbm); - } - DeleteDC(hdcDisplay); - - // Complete the display type initialisation - - ASSERT(CheckHeaderValidity(&m_Display)); - UpdateFormat(&m_Display); - DbgLog((LOG_TRACE,3,TEXT("New DISPLAY bit depth =%d"), - m_Display.bmiHeader.biBitCount)); - return NOERROR; -} - - -// We assume throughout this code that any bitfields masks are allowed no -// more than eight bits to store a colour component. This checks that the -// bit count assumption is enforced and also makes sure that all the bits -// set are contiguous. We return a boolean TRUE if the field checks out ok - -BOOL CImageDisplay::CheckBitFields(const VIDEOINFO *pInput) -{ - DWORD *pBitFields = (DWORD *) BITMASKS(pInput); - - for (INT iColour = iRED;iColour <= iBLUE;iColour++) { - - // First of all work out how many bits are set - - DWORD SetBits = CountSetBits(pBitFields[iColour]); - if (SetBits > iMAXBITS || SetBits == 0) { - NOTE1("Bit fields for component %d invalid",iColour); - return FALSE; - } - - // Next work out the number of zero bits prefix - DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); - - // This is going to see if all the bits set are contiguous (as they - // should be). We know how much to shift them right by from the - // count of prefix bits. The number of bits set defines a mask, we - // invert this (ones complement) and AND it with the shifted bit - // fields. If the result is NON zero then there are bit(s) sticking - // out the left hand end which means they are not contiguous - - DWORD TestField = pBitFields[iColour] >> PrefixBits; - DWORD Mask = ULONG_MAX << SetBits; - if (TestField & Mask) { - NOTE1("Bit fields for component %d not contiguous",iColour); - return FALSE; - } - } - return TRUE; -} - - -// This counts the number of bits set in the input field - -DWORD CImageDisplay::CountSetBits(DWORD Field) -{ - // This is a relatively well known bit counting algorithm - - DWORD Count = 0; - DWORD init = Field; - - // Until the input is exhausted, count the number of bits - - while (init) { - init = init & (init - 1); // Turn off the bottommost bit - Count++; - } - return Count; -} - - -// This counts the number of zero bits upto the first one set NOTE the input -// field should have been previously checked to ensure there is at least one -// set although if we don't find one set we return the impossible value 32 - -DWORD CImageDisplay::CountPrefixBits(DWORD Field) -{ - DWORD Mask = 1; - DWORD Count = 0; - - for (;;) { - if (Field & Mask) { - return Count; - } - Count++; - - ASSERT(Mask != 0x80000000); - if (Mask == 0x80000000) { - return Count; - } - Mask <<= 1; - } -} - - -// This is called to check the BITMAPINFOHEADER for the input type. There are -// many implicit dependancies between the fields in a header structure which -// if we validate now make for easier manipulation in subsequent handling. We -// also check that the BITMAPINFOHEADER matches it's specification such that -// fields likes the number of planes is one, that it's structure size is set -// correctly and that the bitmap dimensions have not been set as negative - -BOOL CImageDisplay::CheckHeaderValidity(const VIDEOINFO *pInput) -{ - // Check the bitmap width and height are not negative. - - if (pInput->bmiHeader.biWidth <= 0 || - pInput->bmiHeader.biHeight <= 0) { - NOTE("Invalid bitmap dimensions"); - return FALSE; - } - - // Check the compression is either BI_RGB or BI_BITFIELDS - - if (pInput->bmiHeader.biCompression != BI_RGB) { - if (pInput->bmiHeader.biCompression != BI_BITFIELDS) { - NOTE("Invalid compression format"); - return FALSE; - } - } - - // If BI_BITFIELDS compression format check the colour depth - - if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { - if (pInput->bmiHeader.biBitCount != 16) { - if (pInput->bmiHeader.biBitCount != 32) { - NOTE("BI_BITFIELDS not 16/32 bit depth"); - return FALSE; - } - } - } - - // Check the assumptions about the layout of the bit fields - - if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { - if (CheckBitFields(pInput) == FALSE) { - NOTE("Bit fields are not valid"); - return FALSE; - } - } - - // Are the number of planes equal to one - - if (pInput->bmiHeader.biPlanes != 1) { - NOTE("Number of planes not one"); - return FALSE; - } - - // Check the image size is consistent (it can be zero) - - if (pInput->bmiHeader.biSizeImage != GetBitmapSize(&pInput->bmiHeader)) { - if (pInput->bmiHeader.biSizeImage) { - NOTE("Image size incorrectly set"); - return FALSE; - } - } - - // Check the size of the structure - - if (pInput->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) { - NOTE("Size of BITMAPINFOHEADER wrong"); - return FALSE; - } - return CheckPaletteHeader(pInput); -} - - -// This runs a few simple tests against the palette fields in the input to -// see if it looks vaguely correct. The tests look at the number of palette -// colours present, the number considered important and the biCompression -// field which should always be BI_RGB as no other formats are meaningful - -BOOL CImageDisplay::CheckPaletteHeader(const VIDEOINFO *pInput) -{ - // The checks here are for palettised videos only - - if (PALETTISED(pInput) == FALSE) { - if (pInput->bmiHeader.biClrUsed) { - NOTE("Invalid palette entries"); - return FALSE; - } - return TRUE; - } - - // Compression type of BI_BITFIELDS is meaningless for palette video - - if (pInput->bmiHeader.biCompression != BI_RGB) { - NOTE("Palettised video must be BI_RGB"); - return FALSE; - } - - // Check the number of palette colours is correct - - if (pInput->bmiHeader.biClrUsed > PALETTE_ENTRIES(pInput)) { - NOTE("Too many colours in palette"); - return FALSE; - } - - // The number of important colours shouldn't exceed the number used - - if (pInput->bmiHeader.biClrImportant > pInput->bmiHeader.biClrUsed) { - NOTE("Too many important colours"); - return FALSE; - } - return TRUE; -} - - -// Return the format of the video display - -const VIDEOINFO *CImageDisplay::GetDisplayFormat() -{ - return &m_Display; -} - - -// Return TRUE if the display uses a palette - -BOOL CImageDisplay::IsPalettised() -{ - return PALETTISED(&m_Display); -} - - -// Return the bit depth of the current display setting - -WORD CImageDisplay::GetDisplayDepth() -{ - return m_Display.bmiHeader.biBitCount; -} - - -// Initialise the optional fields in a VIDEOINFO. These are mainly to do with -// the source and destination rectangles and palette information such as the -// number of colours present. It simplifies our code just a little if we don't -// have to keep checking for all the different valid permutations in a header -// every time we want to do anything with it (an example would be creating a -// palette). We set the base class media type before calling this function so -// that the media types between the pins match after a connection is made - -HRESULT CImageDisplay::UpdateFormat(__inout VIDEOINFO *pVideoInfo) -{ - ASSERT(pVideoInfo); - - BITMAPINFOHEADER *pbmi = HEADER(pVideoInfo); - UNREFERENCED_PARAMETER(pbmi); - SetRectEmpty(&pVideoInfo->rcSource); - SetRectEmpty(&pVideoInfo->rcTarget); - - // Set the number of colours explicitly - - if (PALETTISED(pVideoInfo)) { - if (pVideoInfo->bmiHeader.biClrUsed == 0) { - pVideoInfo->bmiHeader.biClrUsed = PALETTE_ENTRIES(pVideoInfo); - } - } - - // The number of important colours shouldn't exceed the number used, on - // some displays the number of important colours is not initialised when - // retrieving the display type so we set the colours used correctly - - if (pVideoInfo->bmiHeader.biClrImportant > pVideoInfo->bmiHeader.biClrUsed) { - pVideoInfo->bmiHeader.biClrImportant = PALETTE_ENTRIES(pVideoInfo); - } - - // Change the image size field to be explicit - - if (pVideoInfo->bmiHeader.biSizeImage == 0) { - pVideoInfo->bmiHeader.biSizeImage = GetBitmapSize(&pVideoInfo->bmiHeader); - } - return NOERROR; -} - - -// Lots of video rendering filters want code to check proposed formats are ok -// This checks the VIDEOINFO we are passed as a media type. If the media type -// is a valid media type then we return NOERROR otherwise E_INVALIDARG. Note -// however we only accept formats that can be easily displayed in the display -// so if we are on a 16 bit device we will not accept 24 bit images. The one -// complexity is that most displays draw 8 bit palettised images efficiently -// Also if the input format is less colour bits per pixel then we also accept - -HRESULT CImageDisplay::CheckVideoType(const VIDEOINFO *pInput) -{ - // First of all check the VIDEOINFOHEADER looks correct - - if (CheckHeaderValidity(pInput) == FALSE) { - return E_INVALIDARG; - } - - // Virtually all devices support palettised images efficiently - - if (m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount) { - if (PALETTISED(pInput) == TRUE) { - ASSERT(PALETTISED(&m_Display) == TRUE); - NOTE("(Video) Type connection ACCEPTED"); - return NOERROR; - } - } - - - // Is the display depth greater than the input format - - if (m_Display.bmiHeader.biBitCount > pInput->bmiHeader.biBitCount) { - NOTE("(Video) Mismatch agreed"); - return NOERROR; - } - - // Is the display depth less than the input format - - if (m_Display.bmiHeader.biBitCount < pInput->bmiHeader.biBitCount) { - NOTE("(Video) Format mismatch"); - return E_INVALIDARG; - } - - - // Both input and display formats are either BI_RGB or BI_BITFIELDS - - ASSERT(m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount); - ASSERT(PALETTISED(pInput) == FALSE); - ASSERT(PALETTISED(&m_Display) == FALSE); - - // BI_RGB 16 bit representation is implicitly RGB555, and likewise BI_RGB - // 24 bit representation is RGB888. So we initialise a pointer to the bit - // fields they really mean and check against the display device format - // This is only going to be called when both formats are equal bits pixel - - const DWORD *pInputMask = GetBitMasks(pInput); - const DWORD *pDisplayMask = GetBitMasks((VIDEOINFO *)&m_Display); - - if (pInputMask[iRED] != pDisplayMask[iRED] || - pInputMask[iGREEN] != pDisplayMask[iGREEN] || - pInputMask[iBLUE] != pDisplayMask[iBLUE]) { - - NOTE("(Video) Bit field mismatch"); - return E_INVALIDARG; - } - - NOTE("(Video) Type connection ACCEPTED"); - return NOERROR; -} - - -// Return the bit masks for the true colour VIDEOINFO provided - -const DWORD *CImageDisplay::GetBitMasks(const VIDEOINFO *pVideoInfo) -{ - static const DWORD FailMasks[] = {0,0,0}; - - if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { - return BITMASKS(pVideoInfo); - } - - ASSERT(pVideoInfo->bmiHeader.biCompression == BI_RGB); - - switch (pVideoInfo->bmiHeader.biBitCount) { - case 16: return bits555; - case 24: return bits888; - case 32: return bits888; - default: return FailMasks; - } -} - - -// Check to see if we can support media type pmtIn as proposed by the output -// pin - We first check that the major media type is video and also identify -// the media sub type. Then we thoroughly check the VIDEOINFO type provided -// As well as the contained VIDEOINFO being correct the major type must be -// video, the subtype a recognised video format and the type GUID correct - -HRESULT CImageDisplay::CheckMediaType(const CMediaType *pmtIn) -{ - // Does this have a VIDEOINFOHEADER format block - - const GUID *pFormatType = pmtIn->FormatType(); - if (*pFormatType != FORMAT_VideoInfo) { - NOTE("Format GUID not a VIDEOINFOHEADER"); - return E_INVALIDARG; - } - ASSERT(pmtIn->Format()); - - // Check the format looks reasonably ok - - ULONG Length = pmtIn->FormatLength(); - if (Length < SIZE_VIDEOHEADER) { - NOTE("Format smaller than a VIDEOHEADER"); - return E_FAIL; - } - - VIDEOINFO *pInput = (VIDEOINFO *) pmtIn->Format(); - - // Check the major type is MEDIATYPE_Video - - const GUID *pMajorType = pmtIn->Type(); - if (*pMajorType != MEDIATYPE_Video) { - NOTE("Major type not MEDIATYPE_Video"); - return E_INVALIDARG; - } - - // Check we can identify the media subtype - - const GUID *pSubType = pmtIn->Subtype(); - if (GetBitCount(pSubType) == USHRT_MAX) { - NOTE("Invalid video media subtype"); - return E_INVALIDARG; - } - return CheckVideoType(pInput); -} - - -// Given a video format described by a VIDEOINFO structure we return the mask -// that is used to obtain the range of acceptable colours for this type, for -// example, the mask for a 24 bit true colour format is 0xFF in all cases. A -// 16 bit 5:6:5 display format uses 0xF8, 0xFC and 0xF8, therefore given any -// RGB triplets we can AND them with these fields to find one that is valid - -BOOL CImageDisplay::GetColourMask(__out DWORD *pMaskRed, - __out DWORD *pMaskGreen, - __out DWORD *pMaskBlue) -{ - CAutoLock cDisplayLock(this); - *pMaskRed = 0xFF; - *pMaskGreen = 0xFF; - *pMaskBlue = 0xFF; - - // If this format is palettised then it doesn't have bit fields - - if (m_Display.bmiHeader.biBitCount < 16) { - return FALSE; - } - - // If this is a 24 bit true colour display then it can handle all the - // possible colour component ranges described by a byte. It is never - // allowed for a 24 bit colour depth image to have BI_BITFIELDS set - - if (m_Display.bmiHeader.biBitCount == 24) { - ASSERT(m_Display.bmiHeader.biCompression == BI_RGB); - return TRUE; - } - - // Calculate the mask based on the format's bit fields - - const DWORD *pBitFields = (DWORD *) GetBitMasks((VIDEOINFO *)&m_Display); - DWORD *pOutputMask[] = { pMaskRed, pMaskGreen, pMaskBlue }; - - // We know from earlier testing that there are no more than iMAXBITS - // bits set in the mask and that they are all contiguous. All that - // therefore remains is to shift them into the correct position - - for (INT iColour = iRED;iColour <= iBLUE;iColour++) { - - // This works out how many bits there are and where they live - - DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); - DWORD SetBits = CountSetBits(pBitFields[iColour]); - - // The first shift moves the bit field so that it is right justified - // in the DWORD, after which we then shift it back left which then - // puts the leading bit in the bytes most significant bit position - - *(pOutputMask[iColour]) = pBitFields[iColour] >> PrefixBits; - *(pOutputMask[iColour]) <<= (iMAXBITS - SetBits); - } - return TRUE; -} - - -/* Helper to convert to VIDEOINFOHEADER2 -*/ -STDAPI ConvertVideoInfoToVideoInfo2(__inout AM_MEDIA_TYPE *pmt) -{ - if (pmt->formattype != FORMAT_VideoInfo) { - return E_INVALIDARG; - } - if (NULL == pmt->pbFormat || pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { - return E_INVALIDARG; - } - VIDEOINFO *pVideoInfo = (VIDEOINFO *)pmt->pbFormat; - UNREFERENCED_PARAMETER(pVideoInfo); - DWORD dwNewSize; - HRESULT hr = DWordAdd(pmt->cbFormat, sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER), &dwNewSize); - if (FAILED(hr)) { - return hr; - } - PVOID pvNew = CoTaskMemAlloc(dwNewSize); - if (pvNew == NULL) { - return E_OUTOFMEMORY; - } - CopyMemory(pvNew, pmt->pbFormat, FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); - ZeroMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), - sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER)); - CopyMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader), - pmt->pbFormat + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), - pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); - VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pvNew; - pVideoInfo2->dwPictAspectRatioX = (DWORD)pVideoInfo2->bmiHeader.biWidth; - pVideoInfo2->dwPictAspectRatioY = (DWORD)abs(pVideoInfo2->bmiHeader.biHeight); - pmt->formattype = FORMAT_VideoInfo2; - CoTaskMemFree(pmt->pbFormat); - pmt->pbFormat = (PBYTE)pvNew; - pmt->cbFormat += sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER); - return S_OK; -} - - -// Check a media type containing VIDEOINFOHEADER -STDAPI CheckVideoInfoType(const AM_MEDIA_TYPE *pmt) -{ - if (NULL == pmt || NULL == pmt->pbFormat) { - return E_POINTER; - } - if (pmt->majortype != MEDIATYPE_Video || - pmt->formattype != FORMAT_VideoInfo || - pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - const VIDEOINFOHEADER *pHeader = (const VIDEOINFOHEADER *)pmt->pbFormat; - if (!ValidateBitmapInfoHeader( - &pHeader->bmiHeader, - pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader))) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - - return S_OK; -} - -// Check a media type containing VIDEOINFOHEADER2 -STDAPI CheckVideoInfo2Type(const AM_MEDIA_TYPE *pmt) -{ - if (NULL == pmt || NULL == pmt->pbFormat) { - return E_POINTER; - } - if (pmt->majortype != MEDIATYPE_Video || - pmt->formattype != FORMAT_VideoInfo2 || - pmt->cbFormat < sizeof(VIDEOINFOHEADER2)) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - const VIDEOINFOHEADER2 *pHeader = (const VIDEOINFOHEADER2 *)pmt->pbFormat; - if (!ValidateBitmapInfoHeader( - &pHeader->bmiHeader, - pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader))) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - - return S_OK; -} +//------------------------------------------------------------------------------ +// File: WinUtil.cpp +// +// Desc: DirectShow base classes - implements generic window handler class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include +#include +#include +#include "checkbmi.h" + +static UINT MsgDestroy; + +// Constructor + +CBaseWindow::CBaseWindow(BOOL bDoGetDC, bool bDoPostToDestroy) : + m_hInstance(g_hInst), + m_hwnd(NULL), + m_hdc(NULL), + m_bActivated(FALSE), + m_pClassName(NULL), + m_ClassStyles(0), + m_WindowStyles(0), + m_WindowStylesEx(0), + m_ShowStageMessage(0), + m_ShowStageTop(0), + m_MemoryDC(NULL), + m_hPalette(NULL), + m_bBackground(FALSE), +#ifdef _DEBUG + m_bRealizing(FALSE), +#endif + m_bNoRealize(FALSE), + m_bDoPostToDestroy(bDoPostToDestroy), + m_bDoGetDC(bDoGetDC), + m_Width(0), + m_Height(0), + m_RealizePalette(0) +{ +} + + +// Prepare a window by spinning off a worker thread to do the creation and +// also poll the message input queue. We leave this to be called by derived +// classes because they might want to override methods like MessageLoop and +// InitialiseWindow, if we do this during construction they'll ALWAYS call +// this base class methods. We make the worker thread create the window so +// it owns it rather than the filter graph thread which is constructing us + +HRESULT CBaseWindow::PrepareWindow() +{ + if (m_hwnd) return NOERROR; + ASSERT(m_hwnd == NULL); + ASSERT(m_hdc == NULL); + + // Get the derived object's window and class styles + + m_pClassName = GetClassWindowStyles(&m_ClassStyles, + &m_WindowStyles, + &m_WindowStylesEx); + if (m_pClassName == NULL) { + return E_FAIL; + } + + // Register our special private messages + m_ShowStageMessage = RegisterWindowMessage(SHOWSTAGE); + + // RegisterWindowMessage() returns 0 if an error occurs. + if (0 == m_ShowStageMessage) { + return AmGetLastErrorToHResult(); + } + + m_ShowStageTop = RegisterWindowMessage(SHOWSTAGETOP); + if (0 == m_ShowStageTop) { + return AmGetLastErrorToHResult(); + } + + m_RealizePalette = RegisterWindowMessage(REALIZEPALETTE); + if (0 == m_RealizePalette) { + return AmGetLastErrorToHResult(); + } + + MsgDestroy = RegisterWindowMessage(TEXT("AM_DESTROY")); + if (0 == MsgDestroy) { + return AmGetLastErrorToHResult(); + } + + return DoCreateWindow(); +} + + +// Destructor just a placeholder so that we know it becomes virtual +// Derived classes MUST call DoneWithWindow in their destructors so +// that no messages arrive after the derived class constructor ends + +#ifdef _DEBUG +CBaseWindow::~CBaseWindow() +{ + ASSERT(m_hwnd == NULL); + ASSERT(m_hdc == NULL); +} +#endif + + +// We use the sync worker event to have the window destroyed. All we do is +// signal the event and wait on the window thread handle. Trying to send it +// messages causes too many problems, furthermore to be on the safe side we +// just wait on the thread handle while it returns WAIT_TIMEOUT or there is +// a sent message to process on this thread. If the constructor failed to +// create the thread in the first place then the loop will get terminated + +HRESULT CBaseWindow::DoneWithWindow() +{ + if (!IsWindow(m_hwnd) || (GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId())) { + + if (IsWindow(m_hwnd)) { + + // This code should only be executed if the window exists and if the window's + // messages are processed on a different thread. + ASSERT(GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId()); + + if (m_bDoPostToDestroy) { + + HRESULT hr = S_OK; + CAMEvent m_evDone(FALSE, &hr); + if (FAILED(hr)) { + return hr; + } + + // We must post a message to destroy the window + // That way we can't be in the middle of processing a + // message posted to our window when we do go away + // Sending a message gives less synchronization. + PostMessage(m_hwnd, MsgDestroy, (WPARAM)(HANDLE)m_evDone, 0); + WaitDispatchingMessages(m_evDone, INFINITE); + } else { + SendMessage(m_hwnd, MsgDestroy, 0, 0); + } + } + + // + // This is not a leak, the window manager automatically free's + // hdc's that were got via GetDC, which is the case here. + // We set it to NULL so that we don't get any asserts later. + // + m_hdc = NULL; + + // + // We need to free this DC though because USER32 does not know + // anything about it. + // + if (m_MemoryDC) + { + EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); + m_MemoryDC = NULL; + } + + // Reset the window variables + m_hwnd = NULL; + + return NOERROR; + } + const HWND hwnd = m_hwnd; + if (hwnd == NULL) { + return NOERROR; + } + + InactivateWindow(); + NOTE("Inactivated"); + + // Reset the window styles before destruction + + SetWindowLong(hwnd,GWL_STYLE,m_WindowStyles); + ASSERT(GetParent(hwnd) == NULL); + NOTE1("Reset window styles %d",m_WindowStyles); + + // UnintialiseWindow sets m_hwnd to NULL so save a copy + UninitialiseWindow(); + DbgLog((LOG_TRACE, 2, TEXT("Destroying 0x%8.8X"), hwnd)); + if (!DestroyWindow(hwnd)) { + DbgLog((LOG_TRACE, 0, TEXT("DestroyWindow %8.8X failed code %d"), + hwnd, GetLastError())); + DbgBreak(""); + } + + // Reset our state so we can be prepared again + + m_pClassName = NULL; + m_ClassStyles = 0; + m_WindowStyles = 0; + m_WindowStylesEx = 0; + m_ShowStageMessage = 0; + m_ShowStageTop = 0; + + return NOERROR; +} + + +// Called at the end to put the window in an inactive state. The pending list +// will always have been cleared by this time so event if the worker thread +// gets has been signaled and gets in to render something it will find both +// the state has been changed and that there are no available sample images +// Since we wait on the window thread to complete we don't lock the object + +HRESULT CBaseWindow::InactivateWindow() +{ + // Has the window been activated + if (m_bActivated == FALSE) { + return S_FALSE; + } + + m_bActivated = FALSE; + ShowWindow(m_hwnd,SW_HIDE); + return NOERROR; +} + + +HRESULT CBaseWindow::CompleteConnect() +{ + m_bActivated = FALSE; + return NOERROR; +} + +// This displays a normal window. We ask the base window class for default +// sizes which unless overriden will return DEFWIDTH and DEFHEIGHT. We go +// through a couple of extra hoops to get the client area the right size +// as the object specifies which accounts for the AdjustWindowRectEx calls +// We also DWORD align the left and top coordinates of the window here to +// maximise the chance of being able to use DCI/DirectDraw primary surface + +HRESULT CBaseWindow::ActivateWindow() +{ + // Has the window been sized and positioned already + + if (m_bActivated == TRUE || GetParent(m_hwnd) != NULL) { + + SetWindowPos(m_hwnd, // Our window handle + HWND_TOP, // Put it at the top + 0, 0, 0, 0, // Leave in current position + SWP_NOMOVE | // Don't change it's place + SWP_NOSIZE); // Change Z-order only + + m_bActivated = TRUE; + return S_FALSE; + } + + // Calculate the desired client rectangle + + RECT WindowRect, ClientRect = GetDefaultRect(); + GetWindowRect(m_hwnd,&WindowRect); + AdjustWindowRectEx(&ClientRect,GetWindowLong(m_hwnd,GWL_STYLE), + FALSE,GetWindowLong(m_hwnd,GWL_EXSTYLE)); + + // Align left and top edges on DWORD boundaries + + UINT WindowFlags = (SWP_NOACTIVATE | SWP_FRAMECHANGED); + WindowRect.left -= (WindowRect.left & 3); + WindowRect.top -= (WindowRect.top & 3); + + SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Align left edge + WindowRect.top, // And also top place + WIDTH(&ClientRect), // Horizontal size + HEIGHT(&ClientRect), // Vertical size + WindowFlags); // Don't show window + + m_bActivated = TRUE; + return NOERROR; +} + + +// This can be used to DWORD align the window for maximum performance + +HRESULT CBaseWindow::PerformanceAlignWindow() +{ + RECT ClientRect,WindowRect; + GetWindowRect(m_hwnd,&WindowRect); + ASSERT(m_bActivated == TRUE); + + // Don't do this if we're owned + + if (GetParent(m_hwnd)) { + return NOERROR; + } + + // Align left and top edges on DWORD boundaries + + GetClientRect(m_hwnd, &ClientRect); + MapWindowPoints(m_hwnd, HWND_DESKTOP, (LPPOINT) &ClientRect, 2); + WindowRect.left -= (ClientRect.left & 3); + WindowRect.top -= (ClientRect.top & 3); + UINT WindowFlags = (SWP_NOACTIVATE | SWP_NOSIZE); + + SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Align left edge + WindowRect.top, // And also top place + (int) 0,(int) 0, // Ignore these sizes + WindowFlags); // Don't show window + + return NOERROR; +} + + +// Install a palette into the base window - we may be called by a different +// thread to the one that owns the window. We have to be careful how we do +// the palette realisation as we could be a different thread to the window +// which would cause an inter thread send message. Therefore we realise the +// palette by sending it a special message but without the window locked + +HRESULT CBaseWindow::SetPalette(HPALETTE hPalette) +{ + // We must own the window lock during the change + { + CAutoLock cWindowLock(&m_WindowLock); + CAutoLock cPaletteLock(&m_PaletteLock); + ASSERT(hPalette); + m_hPalette = hPalette; + } + return SetPalette(); +} + + +HRESULT CBaseWindow::SetPalette() +{ + if (!m_bNoRealize) { + SendMessage(m_hwnd, m_RealizePalette, 0, 0); + return S_OK; + } else { + // Just select the palette + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + + CAutoLock cPaletteLock(&m_PaletteLock); + SelectPalette(m_hdc,m_hPalette,m_bBackground); + SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); + + return S_OK; + } +} + + +void CBaseWindow::UnsetPalette() +{ + CAutoLock cWindowLock(&m_WindowLock); + CAutoLock cPaletteLock(&m_PaletteLock); + + // Get a standard VGA colour palette + + HPALETTE hPalette = (HPALETTE) GetStockObject(DEFAULT_PALETTE); + ASSERT(hPalette); + + SelectPalette(GetWindowHDC(), hPalette, TRUE); + SelectPalette(GetMemoryHDC(), hPalette, TRUE); + + m_hPalette = NULL; +} + + +void CBaseWindow::LockPaletteLock() +{ + m_PaletteLock.Lock(); +} + + +void CBaseWindow::UnlockPaletteLock() +{ + m_PaletteLock.Unlock(); +} + + +// Realise our palettes in the window and device contexts + +HRESULT CBaseWindow::DoRealisePalette(BOOL bForceBackground) +{ + { + CAutoLock cPaletteLock(&m_PaletteLock); + + if (m_hPalette == NULL) { + return NOERROR; + } + + // Realize the palette on the window thread + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + + SelectPalette(m_hdc,m_hPalette,m_bBackground || bForceBackground); + SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); + } + + // If we grab a critical section here we can deadlock + // with the window thread because one of the side effects + // of RealizePalette is to send a WM_PALETTECHANGED message + // to every window in the system. In our handling + // of WM_PALETTECHANGED we used to grab this CS too. + // The really bad case is when our renderer calls DoRealisePalette() + // while we're in the middle of processing a palette change + // for another window. + // So don't hold the critical section while actually realising + // the palette. In any case USER is meant to manage palette + // handling - we shouldn't have to serialize everything as well + ASSERT(CritCheckOut(&m_WindowLock)); + ASSERT(CritCheckOut(&m_PaletteLock)); + + EXECUTE_ASSERT(RealizePalette(m_hdc) != GDI_ERROR); + EXECUTE_ASSERT(RealizePalette(m_MemoryDC) != GDI_ERROR); + + return (GdiFlush() == FALSE ? S_FALSE : S_OK); +} + + +// This is the global window procedure + +LRESULT CALLBACK WndProc(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam) // Other parameter +{ + + // Get the window long that holds our window object pointer + // If it is NULL then we are initialising the window in which + // case the object pointer has been passed in the window creation + // structure. IF we get any messages before WM_NCCREATE we will + // pass them to DefWindowProc. + + CBaseWindow *pBaseWindow = (CBaseWindow *)GetWindowLongPtr(hwnd,0); + + if (pBaseWindow == NULL) { + + // Get the structure pointer from the create struct. + // We can only do this for WM_NCCREATE which should be one of + // the first messages we receive. Anything before this will + // have to be passed to DefWindowProc (i.e. WM_GETMINMAXINFO) + + // If the message is WM_NCCREATE we set our pBaseWindow pointer + // and will then place it in the window structure + + // turn off WS_EX_LAYOUTRTL style for quartz windows + if (uMsg == WM_NCCREATE) { + SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~0x400000); + } + + if ((uMsg != WM_NCCREATE) + || (NULL == (pBaseWindow = *(CBaseWindow**) ((LPCREATESTRUCT)lParam)->lpCreateParams))) + { + return(DefWindowProc(hwnd, uMsg, wParam, lParam)); + } + + // Set the window LONG to be the object who created us +#ifdef _DEBUG + SetLastError(0); // because of the way SetWindowLong works +#endif + +#ifdef _DEBUG + LONG_PTR rc = +#endif + SetWindowLongPtr(hwnd, (DWORD) 0, (LONG_PTR)pBaseWindow); + + +#ifdef _DEBUG + if (0 == rc) { + // SetWindowLong MIGHT have failed. (Read the docs which admit + // that it is awkward to work out if you have had an error.) + LONG lasterror = GetLastError(); + ASSERT(0 == lasterror); + // If this is not the case we have not set the pBaseWindow pointer + // into the window structure and we will blow up. + } +#endif + + } + // See if this is the packet of death + if (uMsg == MsgDestroy && uMsg != 0) { + pBaseWindow->DoneWithWindow(); + if (pBaseWindow->m_bDoPostToDestroy) { + EXECUTE_ASSERT(SetEvent((HANDLE)wParam)); + } + return 0; + } + return pBaseWindow->OnReceiveMessage(hwnd,uMsg,wParam,lParam); +} + + +// When the window size changes we adjust our member variables that +// contain the dimensions of the client rectangle for our window so +// that we come to render an image we will know whether to stretch + +BOOL CBaseWindow::OnSize(LONG Width, LONG Height) +{ + m_Width = Width; + m_Height = Height; + return TRUE; +} + + +// This function handles the WM_CLOSE message + +BOOL CBaseWindow::OnClose() +{ + ShowWindow(m_hwnd,SW_HIDE); + return TRUE; +} + + +// This is called by the worker window thread when it receives a terminate +// message from the window object destructor to delete all the resources we +// allocated during initialisation. By the time the worker thread exits all +// processing will have been completed as the source filter disconnection +// flushes the image pending sample, therefore the GdiFlush should succeed + +HRESULT CBaseWindow::UninitialiseWindow() +{ + // Have we already cleaned up + + if (m_hwnd == NULL) { + ASSERT(m_hdc == NULL); + ASSERT(m_MemoryDC == NULL); + return NOERROR; + } + + // Release the window resources + + EXECUTE_ASSERT(GdiFlush()); + + if (m_hdc) + { + EXECUTE_ASSERT(ReleaseDC(m_hwnd,m_hdc)); + m_hdc = NULL; + } + + if (m_MemoryDC) + { + EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); + m_MemoryDC = NULL; + } + + // Reset the window variables + m_hwnd = NULL; + + return NOERROR; +} + + +// This is called by the worker window thread after it has created the main +// window and it wants to initialise the rest of the owner objects window +// variables such as the device contexts. We execute this function with the +// critical section still locked. Nothing in this function must generate any +// SendMessage calls to the window because this is executing on the window +// thread so the message will never be processed and we will deadlock + +HRESULT CBaseWindow::InitialiseWindow(HWND hwnd) +{ + // Initialise the window variables + + ASSERT(IsWindow(hwnd)); + m_hwnd = hwnd; + + if (m_bDoGetDC) + { + m_hdc = GetDC(hwnd); + EXECUTE_ASSERT(m_hdc); + m_MemoryDC = CreateCompatibleDC(m_hdc); + EXECUTE_ASSERT(m_MemoryDC); + + EXECUTE_ASSERT(SetStretchBltMode(m_hdc,COLORONCOLOR)); + EXECUTE_ASSERT(SetStretchBltMode(m_MemoryDC,COLORONCOLOR)); + } + + return NOERROR; +} + +HRESULT CBaseWindow::DoCreateWindow() +{ + WNDCLASS wndclass; // Used to register classes + BOOL bRegistered; // Is this class registered + HWND hwnd; // Handle to our window + + bRegistered = GetClassInfo(m_hInstance, // Module instance + m_pClassName, // Window class + &wndclass); // Info structure + + // if the window is to be used for drawing puposes and we are getting a DC + // for the entire lifetime of the window then changes the class style to do + // say so. If we don't set this flag then the DC comes from the cache and is + // really bad. + if (m_bDoGetDC) + { + m_ClassStyles |= CS_OWNDC; + } + + if (bRegistered == FALSE) { + + // Register the renderer window class + + wndclass.lpszClassName = m_pClassName; + wndclass.style = m_ClassStyles; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = sizeof(CBaseWindow *); + wndclass.hInstance = m_hInstance; + wndclass.hIcon = NULL; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH) NULL; + wndclass.lpszMenuName = NULL; + + RegisterClass(&wndclass); + } + + // Create the frame window. Pass the pBaseWindow information in the + // CreateStruct which allows our message handling loop to get hold of + // the pBaseWindow pointer. + + CBaseWindow *pBaseWindow = this; // The owner window object + hwnd = CreateWindowEx(m_WindowStylesEx, // Extended styles + m_pClassName, // Registered name + TEXT("ActiveMovie Window"), // Window title + m_WindowStyles, // Window styles + CW_USEDEFAULT, // Start x position + CW_USEDEFAULT, // Start y position + DEFWIDTH, // Window width + DEFHEIGHT, // Window height + NULL, // Parent handle + NULL, // Menu handle + m_hInstance, // Instance handle + &pBaseWindow); // Creation data + + // If we failed signal an error to the object constructor (based on the + // last Win32 error on this thread) then signal the constructor thread + // to continue, release the mutex to let others have a go and exit + + if (hwnd == NULL) { + DWORD Error = GetLastError(); + return AmHresultFromWin32(Error); + } + + // Check the window LONG is the object who created us + ASSERT(GetWindowLongPtr(hwnd, 0) == (LONG_PTR)this); + + // Initialise the window and then signal the constructor so that it can + // continue and then finally unlock the object's critical section. The + // window class is left registered even after we terminate the thread + // as we don't know when the last window has been closed. So we allow + // the operating system to free the class resources as appropriate + + InitialiseWindow(hwnd); + + DbgLog((LOG_TRACE, 2, TEXT("Created window class (%s) HWND(%8.8X)"), + m_pClassName, hwnd)); + + return S_OK; +} + + +// The base class provides some default handling and calls DefWindowProc + +INT_PTR CBaseWindow::OnReceiveMessage(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam) // Other parameter +{ + ASSERT(IsWindow(hwnd)); + + if (PossiblyEatMessage(uMsg, wParam, lParam)) + return 0; + + // This is sent by the IVideoWindow SetWindowForeground method. If the + // window is invisible we will show it and make it topmost without the + // foreground focus. If the window is visible it will also be made the + // topmost window without the foreground focus. If wParam is TRUE then + // for both cases the window will be forced into the foreground focus + + if (uMsg == m_ShowStageMessage) { + + BOOL bVisible = IsWindowVisible(hwnd); + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | + (bVisible ? SWP_NOACTIVATE : 0)); + + // Should we bring the window to the foreground + if (wParam == TRUE) { + SetForegroundWindow(hwnd); + } + return (LRESULT) 1; + } + + // When we go fullscreen we have to add the WS_EX_TOPMOST style to the + // video window so that it comes out above any task bar (this is more + // relevant to WindowsNT than Windows95). However the SetWindowPos call + // must be on the same thread as that which created the window. The + // wParam parameter can be TRUE or FALSE to set and reset the topmost + + if (uMsg == m_ShowStageTop) { + HWND HwndTop = (wParam == TRUE ? HWND_TOPMOST : HWND_NOTOPMOST); + BOOL bVisible = IsWindowVisible(hwnd); + SetWindowPos(hwnd, HwndTop, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | + (wParam == TRUE ? SWP_SHOWWINDOW : 0) | + (bVisible ? SWP_NOACTIVATE : 0)); + return (LRESULT) 1; + } + + // New palette stuff + if (uMsg == m_RealizePalette) { + ASSERT(m_hwnd == hwnd); + return OnPaletteChange(m_hwnd,WM_QUERYNEWPALETTE); + } + + switch (uMsg) { + + // Repaint the window if the system colours change + + case WM_SYSCOLORCHANGE: + + InvalidateRect(hwnd,NULL,FALSE); + return (LRESULT) 1; + + // Somebody has changed the palette + case WM_PALETTECHANGED: + + OnPaletteChange((HWND)wParam,uMsg); + return (LRESULT) 0; + + // We are about to receive the keyboard focus so we ask GDI to realise + // our logical palette again and hopefully it will be fully installed + // without any mapping having to be done during any picture rendering + + case WM_QUERYNEWPALETTE: + ASSERT(m_hwnd == hwnd); + return OnPaletteChange(m_hwnd,uMsg); + + // do NOT fwd WM_MOVE. the parameters are the location of the parent + // window, NOT what the renderer should be looking at. But we need + // to make sure the overlay is moved with the parent window, so we + // do this. + case WM_MOVE: + if (IsWindowVisible(m_hwnd)) { + PostMessage(m_hwnd,WM_PAINT,0,0); + } + break; + + // Store the width and height as useful base class members + + case WM_SIZE: + + OnSize(LOWORD(lParam), HIWORD(lParam)); + return (LRESULT) 0; + + // Intercept the WM_CLOSE messages to hide the window + + case WM_CLOSE: + + OnClose(); + return (LRESULT) 0; + } + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + + +// This handles the Windows palette change messages - if we do realise our +// palette then we return TRUE otherwise we return FALSE. If our window is +// foreground application then we should get first choice of colours in the +// system palette entries. We get best performance when our logical palette +// includes the standard VGA colours (at the beginning and end) otherwise +// GDI may have to map from our palette to the device palette while drawing + +LRESULT CBaseWindow::OnPaletteChange(HWND hwnd,UINT Message) +{ + // First check we are not changing the palette during closedown + + if (m_hwnd == NULL || hwnd == NULL) { + return (LRESULT) 0; + } + ASSERT(!m_bRealizing); + + // Should we realise our palette again + + if ((Message == WM_QUERYNEWPALETTE || hwnd != m_hwnd)) { + // It seems that even if we're invisible that we can get asked + // to realize our palette and this can cause really ugly side-effects + // Seems like there's another bug but this masks it a least for the + // shutting down case. + if (!IsWindowVisible(m_hwnd)) { + DbgLog((LOG_TRACE, 1, TEXT("Realizing when invisible!"))); + return (LRESULT) 0; + } + + // Avoid recursion with multiple graphs in the same app +#ifdef _DEBUG + m_bRealizing = TRUE; +#endif + DoRealisePalette(Message != WM_QUERYNEWPALETTE); +#ifdef _DEBUG + m_bRealizing = FALSE; +#endif + + // Should we redraw the window with the new palette + if (Message == WM_PALETTECHANGED) { + InvalidateRect(m_hwnd,NULL,FALSE); + } + } + + return (LRESULT) 1; +} + + +// Determine if the window exists. + +bool CBaseWindow::WindowExists() +{ + return !!IsWindow(m_hwnd); +} + + +// Return the default window rectangle + +RECT CBaseWindow::GetDefaultRect() +{ + RECT DefaultRect = {0,0,DEFWIDTH,DEFHEIGHT}; + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return DefaultRect; +} + + +// Return the current window width + +LONG CBaseWindow::GetWindowWidth() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_Width; +} + + +// Return the current window height + +LONG CBaseWindow::GetWindowHeight() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_Height; +} + + +// Return the window handle + +HWND CBaseWindow::GetWindowHWND() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_hwnd; +} + + +// Return the window drawing device context + +HDC CBaseWindow::GetWindowHDC() +{ + ASSERT(m_hwnd); + ASSERT(m_hdc); + return m_hdc; +} + + +// Return the offscreen window drawing device context + +HDC CBaseWindow::GetMemoryHDC() +{ + ASSERT(m_hwnd); + ASSERT(m_MemoryDC); + return m_MemoryDC; +} + + +#ifdef _DEBUG +HPALETTE CBaseWindow::GetPalette() +{ + // The palette lock should always be held when accessing + // m_hPalette. + ASSERT(CritCheckIn(&m_PaletteLock)); + return m_hPalette; +} +#endif // DEBUG + + +// This is available to clients who want to change the window visiblity. It's +// little more than an indirection to the Win32 ShowWindow although these is +// some benefit in going through here as this function may change sometime + +HRESULT CBaseWindow::DoShowWindow(LONG ShowCmd) +{ + ShowWindow(m_hwnd,ShowCmd); + return NOERROR; +} + + +// Generate a WM_PAINT message for the video window + +void CBaseWindow::PaintWindow(BOOL bErase) +{ + InvalidateRect(m_hwnd,NULL,bErase); +} + + +// Allow an application to have us set the video window in the foreground. We +// have this because it is difficult for one thread to do do this to a window +// owned by another thread. Rather than expose the message we use to execute +// the inter thread send message we provide the interface function. All we do +// is to SendMessage to the video window renderer thread with a WM_SHOWSTAGE + +void CBaseWindow::DoSetWindowForeground(BOOL bFocus) +{ + SendMessage(m_hwnd,m_ShowStageMessage,(WPARAM) bFocus,(LPARAM) 0); +} + + +// Constructor initialises the owning object pointer. Since we are a worker +// class for the main window object we have relatively few state variables to +// look after. We are given device context handles to use later on as well as +// the source and destination rectangles (but reset them here just in case) + +CDrawImage::CDrawImage(__inout CBaseWindow *pBaseWindow) : + m_pBaseWindow(pBaseWindow), + m_hdc(NULL), + m_MemoryDC(NULL), + m_bStretch(FALSE), + m_pMediaType(NULL), + m_bUsingImageAllocator(FALSE) +{ + ASSERT(pBaseWindow); + ResetPaletteVersion(); + SetRectEmpty(&m_TargetRect); + SetRectEmpty(&m_SourceRect); + + m_perfidRenderTime = MSR_REGISTER(TEXT("Single Blt time")); +} + + +// Overlay the image time stamps on the picture. Access to this method is +// serialised by the caller. We display the sample start and end times on +// top of the video using TextOut on the device context we are handed. If +// there isn't enough room in the window for the times we don't show them + +void CDrawImage::DisplaySampleTimes(IMediaSample *pSample) +{ +#ifdef _DEBUG + // + // Only allow the "annoying" time messages if the users has turned the + // logging "way up" + // + BOOL bAccept = DbgCheckModuleLevel(LOG_TRACE, 5); + if (bAccept == FALSE) { + return; + } +#endif + + TCHAR szTimes[TIMELENGTH]; // Time stamp strings + ASSERT(pSample); // Quick sanity check + RECT ClientRect; // Client window size + SIZE Size; // Size of text output + + // Get the time stamps and window size + + pSample->GetTime((REFERENCE_TIME*)&m_StartSample, (REFERENCE_TIME*)&m_EndSample); + HWND hwnd = m_pBaseWindow->GetWindowHWND(); + EXECUTE_ASSERT(GetClientRect(hwnd,&ClientRect)); + + // Format the sample time stamps + + (void)StringCchPrintf(szTimes,NUMELMS(szTimes),TEXT("%08d : %08d"), + m_StartSample.Millisecs(), + m_EndSample.Millisecs()); + + ASSERT(lstrlen(szTimes) < TIMELENGTH); + + // Put the times in the middle at the bottom of the window + + GetTextExtentPoint32(m_hdc,szTimes,lstrlen(szTimes),&Size); + INT XPos = ((ClientRect.right - ClientRect.left) - Size.cx) / 2; + INT YPos = ((ClientRect.bottom - ClientRect.top) - Size.cy) * 4 / 5; + + // Check the window is big enough to have sample times displayed + + if ((XPos > 0) && (YPos > 0)) { + TextOut(m_hdc,XPos,YPos,szTimes,lstrlen(szTimes)); + } +} + + +// This is called when the drawing code sees that the image has a down level +// palette cookie. We simply call the SetDIBColorTable Windows API with the +// palette that is found after the BITMAPINFOHEADER - we return no errors + +void CDrawImage::UpdateColourTable(HDC hdc,__in BITMAPINFOHEADER *pbmi) +{ + ASSERT(pbmi->biClrUsed); + RGBQUAD *pColourTable = (RGBQUAD *)(pbmi+1); + + // Set the new palette in the device context + + UINT uiReturn = SetDIBColorTable(hdc,(UINT) 0, + pbmi->biClrUsed, + pColourTable); + + // Should always succeed but check in debug builds + ASSERT(uiReturn == pbmi->biClrUsed); + UNREFERENCED_PARAMETER(uiReturn); +} + + +// No source rectangle scaling is done by the base class + +RECT CDrawImage::ScaleSourceRect(const RECT *pSource) +{ + ASSERT(pSource); + return *pSource; +} + + +// This is called when the funky output pin uses our allocator. The samples we +// allocate are special because the memory is shared between us and GDI thus +// removing one copy when we ask for the image to be rendered. The source type +// information is in the main renderer m_mtIn field which is initialised when +// the media type is agreed in SetMediaType, the media type may be changed on +// the fly if, for example, the source filter needs to change the palette + +void CDrawImage::FastRender(IMediaSample *pMediaSample) +{ + BITMAPINFOHEADER *pbmi; // Image format data + DIBDATA *pDibData; // Stores DIB information + BYTE *pImage; // Pointer to image data + HBITMAP hOldBitmap; // Store the old bitmap + CImageSample *pSample; // Pointer to C++ object + + ASSERT(m_pMediaType); + + // From the untyped source format block get the VIDEOINFO and subsequently + // the BITMAPINFOHEADER structure. We can cast the IMediaSample interface + // to a CImageSample object so we can retrieve it's DIBSECTION details + + pbmi = HEADER(m_pMediaType->Format()); + pSample = (CImageSample *) pMediaSample; + pDibData = pSample->GetDIBData(); + hOldBitmap = (HBITMAP) SelectObject(m_MemoryDC,pDibData->hBitmap); + + // Get a pointer to the real image data + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return; + } + + // Do we need to update the colour table, we increment our palette cookie + // each time we get a dynamic format change. The sample palette cookie is + // stored in the DIBDATA structure so we try to keep the fields in sync + // By the time we get to draw the images the format change will be done + // so all we do is ask the renderer for what it's palette version is + + if (pDibData->PaletteVersion < GetPaletteVersion()) { + ASSERT(pbmi->biBitCount <= iPALETTE); + UpdateColourTable(m_MemoryDC,pbmi); + pDibData->PaletteVersion = GetPaletteVersion(); + } + + // This allows derived classes to change the source rectangle that we do + // the drawing with. For example a renderer may ask a codec to stretch + // the video from 320x240 to 640x480, in which case the source we see in + // here will still be 320x240, although the source we want to draw with + // should be scaled up to 640x480. The base class implementation of this + // method does nothing but return the same rectangle as we are passed in + + RECT SourceRect = ScaleSourceRect(&m_SourceRect); + + // Is the window the same size as the video + + if (m_bStretch == FALSE) { + + // Put the image straight into the window + + BitBlt( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + m_MemoryDC, // Source device context + SourceRect.left, // X source position + SourceRect.top, // Y source position + SRCCOPY); // Simple copy + + } else { + + // Stretch the image when copying to the window + + StretchBlt( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + m_MemoryDC, // Source device HDC + SourceRect.left, // X source position + SourceRect.top, // Y source position + SourceRect.right - SourceRect.left, // Source width + SourceRect.bottom - SourceRect.top, // Source height + SRCCOPY); // Simple copy + } + + // This displays the sample times over the top of the image. This used to + // draw the times into the offscreen device context however that actually + // writes the text into the image data buffer which may not be writable + + #ifdef _DEBUG + DisplaySampleTimes(pMediaSample); + #endif + + // Put the old bitmap back into the device context so we don't leak + SelectObject(m_MemoryDC,hOldBitmap); +} + + +// This is called when there is a sample ready to be drawn, unfortunately the +// output pin was being rotten and didn't choose our super excellent shared +// memory DIB allocator so we have to do this slow render using boring old GDI +// SetDIBitsToDevice and StretchDIBits. The down side of using these GDI +// functions is that the image data has to be copied across from our address +// space into theirs before going to the screen (although in reality the cost +// is small because all they do is to map the buffer into their address space) + +void CDrawImage::SlowRender(IMediaSample *pMediaSample) +{ + // Get the BITMAPINFOHEADER for the connection + + ASSERT(m_pMediaType); + BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); + BYTE *pImage; + + // Get the image data buffer + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return; + } + + // This allows derived classes to change the source rectangle that we do + // the drawing with. For example a renderer may ask a codec to stretch + // the video from 320x240 to 640x480, in which case the source we see in + // here will still be 320x240, although the source we want to draw with + // should be scaled up to 640x480. The base class implementation of this + // method does nothing but return the same rectangle as we are passed in + + RECT SourceRect = ScaleSourceRect(&m_SourceRect); + + LONG lAdjustedSourceTop = SourceRect.top; + // if the origin of bitmap is bottom-left, adjust soruce_rect_top + // to be the bottom-left corner instead of the top-left. + if (pbmi->biHeight > 0) { + lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; + } + // Is the window the same size as the video + + if (m_bStretch == FALSE) { + + // Put the image straight into the window + + SetDIBitsToDevice( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + SourceRect.left, // X source position + lAdjustedSourceTop, // Adjusted Y source position + (UINT) 0, // Start scan line + pbmi->biHeight, // Scan lines present + pImage, // Image data + (BITMAPINFO *) pbmi, // DIB header + DIB_RGB_COLORS); // Type of palette + + } else { + + // Stretch the image when copying to the window + + StretchDIBits( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + SourceRect.left, // X source position + lAdjustedSourceTop, // Adjusted Y source position + SourceRect.right - SourceRect.left, // Source width + SourceRect.bottom - SourceRect.top, // Source height + pImage, // Image data + (BITMAPINFO *) pbmi, // DIB header + DIB_RGB_COLORS, // Type of palette + SRCCOPY); // Simple image copy + } + + // This shows the sample reference times over the top of the image which + // looks a little flickery. I tried using GdiSetBatchLimit and GdiFlush to + // control the screen updates but it doesn't quite work as expected and + // only partially reduces the flicker. I also tried using a memory context + // and combining the two in that before doing a final BitBlt operation to + // the screen, unfortunately this has considerable performance penalties + // and also means that this code is not executed when compiled retail + + #ifdef _DEBUG + DisplaySampleTimes(pMediaSample); + #endif +} + + +// This is called with an IMediaSample interface on the image to be drawn. We +// decide on the drawing mechanism based on who's allocator we are using. We +// may be called when the window wants an image painted by WM_PAINT messages +// We can't realise the palette here because we have the renderer lock, any +// call to realise may cause an interthread send message to the window thread +// which may in turn be waiting to get the renderer lock before servicing it + +BOOL CDrawImage::DrawImage(IMediaSample *pMediaSample) +{ + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + NotifyStartDraw(); + + // If the output pin used our allocator then the samples passed are in + // fact CVideoSample objects that contain CreateDIBSection data that we + // use to do faster image rendering, they may optionally also contain a + // DirectDraw surface pointer in which case we do not do the drawing + + if (m_bUsingImageAllocator == FALSE) { + SlowRender(pMediaSample); + EXECUTE_ASSERT(GdiFlush()); + NotifyEndDraw(); + return TRUE; + } + + // This is a DIBSECTION buffer + + FastRender(pMediaSample); + EXECUTE_ASSERT(GdiFlush()); + NotifyEndDraw(); + return TRUE; +} + + +BOOL CDrawImage::DrawVideoImageHere( + HDC hdc, + IMediaSample *pMediaSample, + __in LPRECT lprcSrc, + __in LPRECT lprcDst + ) +{ + ASSERT(m_pMediaType); + BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); + BYTE *pImage; + + // Get the image data buffer + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return FALSE; + } + + RECT SourceRect; + RECT TargetRect; + + if (lprcSrc) { + SourceRect = *lprcSrc; + } + else SourceRect = ScaleSourceRect(&m_SourceRect); + + if (lprcDst) { + TargetRect = *lprcDst; + } + else TargetRect = m_TargetRect; + + LONG lAdjustedSourceTop = SourceRect.top; + // if the origin of bitmap is bottom-left, adjust soruce_rect_top + // to be the bottom-left corner instead of the top-left. + if (pbmi->biHeight > 0) { + lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; + } + + + // Stretch the image when copying to the DC + + BOOL bRet = (0 != StretchDIBits(hdc, + TargetRect.left, + TargetRect.top, + TargetRect.right - TargetRect.left, + TargetRect.bottom - TargetRect.top, + SourceRect.left, + lAdjustedSourceTop, + SourceRect.right - SourceRect.left, + SourceRect.bottom - SourceRect.top, + pImage, + (BITMAPINFO *)pbmi, + DIB_RGB_COLORS, + SRCCOPY)); + return bRet; +} + + +// This is called by the owning window object after it has created the window +// and it's drawing contexts. We are constructed with the base window we'll +// be drawing into so when given the notification we retrive the device HDCs +// to draw with. We cannot call these in our constructor as they are virtual + +void CDrawImage::SetDrawContext() +{ + m_MemoryDC = m_pBaseWindow->GetMemoryHDC(); + m_hdc = m_pBaseWindow->GetWindowHDC(); +} + + +// This is called to set the target rectangle in the video window, it will be +// called whenever a WM_SIZE message is retrieved from the message queue. We +// simply store the rectangle and use it later when we do the drawing calls + +void CDrawImage::SetTargetRect(__in RECT *pTargetRect) +{ + ASSERT(pTargetRect); + m_TargetRect = *pTargetRect; + SetStretchMode(); +} + + +// Return the current target rectangle + +void CDrawImage::GetTargetRect(__out RECT *pTargetRect) +{ + ASSERT(pTargetRect); + *pTargetRect = m_TargetRect; +} + + +// This is called when we want to change the section of the image to draw. We +// use this information in the drawing operation calls later on. We must also +// see if the source and destination rectangles have the same dimensions. If +// not we must stretch during the drawing rather than a direct pixel copy + +void CDrawImage::SetSourceRect(__in RECT *pSourceRect) +{ + ASSERT(pSourceRect); + m_SourceRect = *pSourceRect; + SetStretchMode(); +} + + +// Return the current source rectangle + +void CDrawImage::GetSourceRect(__out RECT *pSourceRect) +{ + ASSERT(pSourceRect); + *pSourceRect = m_SourceRect; +} + + +// This is called when either the source or destination rectanges change so we +// can update the stretch flag. If the rectangles don't match we stretch the +// video during the drawing otherwise we call the fast pixel copy functions +// NOTE the source and/or the destination rectangle may be completely empty + +void CDrawImage::SetStretchMode() +{ + // Calculate the overall rectangle dimensions + + LONG SourceWidth = m_SourceRect.right - m_SourceRect.left; + LONG SinkWidth = m_TargetRect.right - m_TargetRect.left; + LONG SourceHeight = m_SourceRect.bottom - m_SourceRect.top; + LONG SinkHeight = m_TargetRect.bottom - m_TargetRect.top; + + m_bStretch = TRUE; + if (SourceWidth == SinkWidth) { + if (SourceHeight == SinkHeight) { + m_bStretch = FALSE; + } + } +} + + +// Tell us whose allocator we are using. This should be called with TRUE if +// the filter agrees to use an allocator based around the CImageAllocator +// SDK base class - whose image buffers are made through CreateDIBSection. +// Otherwise this should be called with FALSE and we will draw the images +// using SetDIBitsToDevice and StretchDIBitsToDevice. None of these calls +// can handle buffers which have non zero strides (like DirectDraw uses) + +void CDrawImage::NotifyAllocator(BOOL bUsingImageAllocator) +{ + m_bUsingImageAllocator = bUsingImageAllocator; +} + + +// Are we using the image DIBSECTION allocator + +BOOL CDrawImage::UsingImageAllocator() +{ + return m_bUsingImageAllocator; +} + + +// We need the media type of the connection so that we can get the BITMAPINFO +// from it. We use that in the calls to draw the image such as StretchDIBits +// and also when updating the colour table held in shared memory DIBSECTIONs + +void CDrawImage::NotifyMediaType(__in CMediaType *pMediaType) +{ + m_pMediaType = pMediaType; +} + + +// We store in this object a cookie maintaining the current palette version. +// Each time a palettised format is changed we increment this value so that +// when we come to draw the images we look at the colour table value they +// have and if less than the current we know to update it. This version is +// only needed and indeed used when working with shared memory DIBSECTIONs + +LONG CDrawImage::GetPaletteVersion() +{ + return m_PaletteVersion; +} + + +// Resets the current palette version number + +void CDrawImage::ResetPaletteVersion() +{ + m_PaletteVersion = PALETTE_VERSION; +} + + +// Increment the current palette version + +void CDrawImage::IncrementPaletteVersion() +{ + m_PaletteVersion++; +} + + +// Constructor must initialise the base allocator. Each sample we create has a +// palette version cookie on board. When the source filter changes the palette +// during streaming the window object increments an internal cookie counter it +// keeps as well. When it comes to render the samples it looks at the cookie +// values and if they don't match then it knows to update the sample's colour +// table. However we always create samples with a cookie of PALETTE_VERSION +// If there have been multiple format changes and we disconnect and reconnect +// thereby causing the samples to be reallocated we will create them with a +// cookie much lower than the current version, this isn't a problem since it +// will be seen by the window object and the versions will then be updated + +CImageAllocator::CImageAllocator(__inout CBaseFilter *pFilter, + __in_opt LPCTSTR pName, + __inout HRESULT *phr) : + CBaseAllocator(pName,NULL,phr,TRUE,TRUE), + m_pFilter(pFilter), + m_pMediaType(NULL) +{ + ASSERT(phr); + ASSERT(pFilter); +} + + +// Check our DIB buffers have been released + +#ifdef _DEBUG +CImageAllocator::~CImageAllocator() +{ + ASSERT(m_bCommitted == FALSE); +} +#endif + + +// Called from destructor and also from base class to free resources. We work +// our way through the list of media samples deleting the DIBSECTION created +// for each. All samples should be back in our list so there is no chance a +// filter is still using one to write on the display or hold on a pending list + +void CImageAllocator::Free() +{ + ASSERT(m_lAllocated == m_lFree.GetCount()); + EXECUTE_ASSERT(GdiFlush()); + CImageSample *pSample; + DIBDATA *pDibData; + + while (m_lFree.GetCount() != 0) { + pSample = (CImageSample *) m_lFree.RemoveHead(); + pDibData = pSample->GetDIBData(); + EXECUTE_ASSERT(DeleteObject(pDibData->hBitmap)); + EXECUTE_ASSERT(CloseHandle(pDibData->hMapping)); + delete pSample; + } + + m_lAllocated = 0; +} + + +// Prepare the allocator by checking all the input parameters + +STDMETHODIMP CImageAllocator::CheckSizes(__in ALLOCATOR_PROPERTIES *pRequest) +{ + // Check we have a valid connection + + if (m_pMediaType == NULL) { + return VFW_E_NOT_CONNECTED; + } + + // NOTE We always create a DIB section with the source format type which + // may contain a source palette. When we do the BitBlt drawing operation + // the target display device may contain a different palette (we may not + // have the focus) in which case GDI will do after the palette mapping + + VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *) m_pMediaType->Format(); + + // When we call CreateDIBSection it implicitly maps only enough memory + // for the image as defined by thee BITMAPINFOHEADER. If the user asks + // for an image smaller than this then we reject the call, if they ask + // for an image larger than this then we return what they can have + + if ((DWORD) pRequest->cbBuffer < pVideoInfo->bmiHeader.biSizeImage) { + return E_INVALIDARG; + } + + // Reject buffer prefixes + + if (pRequest->cbPrefix > 0) { + return E_INVALIDARG; + } + + pRequest->cbBuffer = pVideoInfo->bmiHeader.biSizeImage; + return NOERROR; +} + + +// Agree the number of media sample buffers and their sizes. The base class +// this allocator is derived from allows samples to be aligned only on byte +// boundaries NOTE the buffers are not allocated until the Commit call + +STDMETHODIMP CImageAllocator::SetProperties( + __in ALLOCATOR_PROPERTIES * pRequest, + __out ALLOCATOR_PROPERTIES * pActual) +{ + ALLOCATOR_PROPERTIES Adjusted = *pRequest; + + // Check the parameters fit with the current connection + + HRESULT hr = CheckSizes(&Adjusted); + if (FAILED(hr)) { + return hr; + } + return CBaseAllocator::SetProperties(&Adjusted, pActual); +} + + +// Commit the memory by allocating the agreed number of media samples. For +// each sample we are committed to creating we have a CImageSample object +// that we use to manage it's resources. This is initialised with a DIBDATA +// structure that contains amongst other things the GDI DIBSECTION handle +// We will access the renderer media type during this so we must have locked +// (to prevent the format changing for example). The class overrides Commit +// and Decommit to do this locking (base class Commit in turn calls Alloc) + +HRESULT CImageAllocator::Alloc(void) +{ + ASSERT(m_pMediaType); + CImageSample *pSample; + DIBDATA DibData; + + // Check the base allocator says it's ok to continue + + HRESULT hr = CBaseAllocator::Alloc(); + if (FAILED(hr)) { + return hr; + } + + // We create a new memory mapped object although we don't map it into our + // address space because GDI does that in CreateDIBSection. It is possible + // that we run out of resources before creating all the samples in which + // case the available sample list is left with those already created + + ASSERT(m_lAllocated == 0); + while (m_lAllocated < m_lCount) { + + // Create and initialise a shared memory GDI buffer + + hr = CreateDIB(m_lSize,DibData); + if (FAILED(hr)) { + return hr; + } + + // Create the sample object and pass it the DIBDATA + + pSample = CreateImageSample(DibData.pBase,m_lSize); + if (pSample == NULL) { + EXECUTE_ASSERT(DeleteObject(DibData.hBitmap)); + EXECUTE_ASSERT(CloseHandle(DibData.hMapping)); + return E_OUTOFMEMORY; + } + + // Add the completed sample to the available list + + pSample->SetDIBData(&DibData); + m_lFree.Add(pSample); + m_lAllocated++; + } + return NOERROR; +} + + +// We have a virtual method that allocates the samples so that a derived class +// may override it and allocate more specialised sample objects. So long as it +// derives its samples from CImageSample then all this code will still work ok + +CImageSample *CImageAllocator::CreateImageSample(__in_bcount(Length) LPBYTE pData,LONG Length) +{ + HRESULT hr = NOERROR; + CImageSample *pSample; + + // Allocate the new sample and check the return codes + + pSample = new CImageSample((CBaseAllocator *) this, // Base class + NAME("Video sample"), // DEBUG name + (HRESULT *) &hr, // Return code + (LPBYTE) pData, // DIB address + (LONG) Length); // Size of DIB + + if (pSample == NULL || FAILED(hr)) { + delete pSample; + return NULL; + } + return pSample; +} + + +// This function allocates a shared memory block for use by the source filter +// generating DIBs for us to render. The memory block is created in shared +// memory so that GDI doesn't have to copy the memory when we do a BitBlt + +HRESULT CImageAllocator::CreateDIB(LONG InSize,DIBDATA &DibData) +{ + BITMAPINFO *pbmi = NULL; // Format information for pin + BYTE *pBase = NULL; // Pointer to the actual image + HANDLE hMapping; // Handle to mapped object + HBITMAP hBitmap = NULL; // DIB section bitmap handle + + // Create a file mapping object and map into our address space + + hMapping = CreateFileMapping(hMEMORY, // Use system page file + NULL, // No security attributes + PAGE_READWRITE, // Full access to memory + (DWORD) 0, // Less than 4Gb in size + InSize, // Size of buffer + NULL); // No name to section + if (hMapping == NULL) { + DWORD Error = GetLastError(); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); + } + + // NOTE We always create a DIB section with the source format type which + // may contain a source palette. When we do the BitBlt drawing operation + // the target display device may contain a different palette (we may not + // have the focus) in which case GDI will do after the palette mapping + + if (m_pMediaType) { + pbmi = (BITMAPINFO *)HEADER(m_pMediaType->Format()); + hBitmap = CreateDIBSection((HDC)NULL, // NO device context + pbmi, // Format information + DIB_RGB_COLORS, // Use the palette + (VOID **)&pBase, // Pointer to image data + hMapping, // Mapped memory handle + (DWORD)0); // Offset into memory + } else { + DbgBreak("Invalid media type"); + } + + if (hBitmap == NULL || pBase == NULL) { + EXECUTE_ASSERT(CloseHandle(hMapping)); + DWORD Error = GetLastError(); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); + } + + // Initialise the DIB information structure + + DibData.hBitmap = hBitmap; + DibData.hMapping = hMapping; + DibData.pBase = pBase; + DibData.PaletteVersion = PALETTE_VERSION; + GetObject(hBitmap,sizeof(DIBSECTION),(VOID *)&DibData.DibSection); + + return NOERROR; +} + + +// We use the media type during the DIBSECTION creation + +void CImageAllocator::NotifyMediaType(__in CMediaType *pMediaType) +{ + m_pMediaType = pMediaType; +} + + +// Overriden to increment the owning object's reference count + +STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingAddRef() +{ + return m_pFilter->AddRef(); +} + + +// Overriden to decrement the owning object's reference count + +STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingRelease() +{ + return m_pFilter->Release(); +} + + +// If you derive a class from CMediaSample that has to transport specialised +// member variables and entry points then there are three alternate solutions +// The first is to create a memory buffer larger than actually required by the +// sample and store your information either at the beginning of it or at the +// end, the former being moderately safer allowing for misbehaving transform +// filters. You then adjust the buffer address when you create the base media +// sample. This has the disadvantage of breaking up the memory allocated to +// the samples into separate blocks. The second solution is to implement a +// class derived from CMediaSample and support additional interface(s) that +// convey your private data. This means defining a custom interface. The final +// alternative is to create a class that inherits from CMediaSample and adds +// the private data structures, when you get an IMediaSample in your Receive() +// call check to see if your allocator is being used, and if it is then cast +// the IMediaSample into one of your objects. Additional checks can be made +// to ensure the sample's this pointer is known to be one of your own objects + +CImageSample::CImageSample(__inout CBaseAllocator *pAllocator, + __in_opt LPCTSTR pName, + __inout HRESULT *phr, + __in_bcount(length) LPBYTE pBuffer, + LONG length) : + CMediaSample(pName,pAllocator,phr,pBuffer,length), + m_bInit(FALSE) +{ + ZeroMemory(&m_DibData, sizeof(DIBDATA)); + ASSERT(pAllocator); + ASSERT(pBuffer); +} + + +// Set the shared memory DIB information + +void CImageSample::SetDIBData(__in DIBDATA *pDibData) +{ + ASSERT(pDibData); + m_DibData = *pDibData; + m_bInit = TRUE; +} + + +// Retrieve the shared memory DIB data + +__out DIBDATA *CImageSample::GetDIBData() +{ + ASSERT(m_bInit == TRUE); + return &m_DibData; +} + + +// This class handles the creation of a palette. It is fairly specialist and +// is intended to simplify palette management for video renderer filters. It +// is for this reason that the constructor requires three other objects with +// which it interacts, namely a base media filter, a base window and a base +// drawing object although the base window or the draw object may be NULL to +// ignore that part of us. We try not to create and install palettes unless +// absolutely necessary as they typically require WM_PALETTECHANGED messages +// to be sent to every window thread in the system which is very expensive + +CImagePalette::CImagePalette(__inout CBaseFilter *pBaseFilter, + __inout CBaseWindow *pBaseWindow, + __inout CDrawImage *pDrawImage) : + m_pBaseWindow(pBaseWindow), + m_pFilter(pBaseFilter), + m_pDrawImage(pDrawImage), + m_hPalette(NULL) +{ + ASSERT(m_pFilter); +} + + +// Destructor + +#ifdef _DEBUG +CImagePalette::~CImagePalette() +{ + ASSERT(m_hPalette == NULL); +} +#endif + + +// We allow dynamic format changes of the palette but rather than change the +// palette every time we call this to work out whether an update is required. +// If the original type didn't use a palette and the new one does (or vica +// versa) then we return TRUE. If neither formats use a palette we'll return +// FALSE. If both formats use a palette we compare their colours and return +// FALSE if they match. This therefore short circuits palette creation unless +// absolutely necessary since installing palettes is an expensive operation + +BOOL CImagePalette::ShouldUpdate(const VIDEOINFOHEADER *pNewInfo, + const VIDEOINFOHEADER *pOldInfo) +{ + // We may not have a current format yet + + if (pOldInfo == NULL) { + return TRUE; + } + + // Do both formats not require a palette + + if (ContainsPalette(pNewInfo) == FALSE) { + if (ContainsPalette(pOldInfo) == FALSE) { + return FALSE; + } + } + + // Compare the colours to see if they match + + DWORD VideoEntries = pNewInfo->bmiHeader.biClrUsed; + if (ContainsPalette(pNewInfo) == TRUE) + if (ContainsPalette(pOldInfo) == TRUE) + if (pOldInfo->bmiHeader.biClrUsed == VideoEntries) + if (pOldInfo->bmiHeader.biClrUsed > 0) + if (memcmp((PVOID) GetBitmapPalette(pNewInfo), + (PVOID) GetBitmapPalette(pOldInfo), + VideoEntries * sizeof(RGBQUAD)) == 0) { + + return FALSE; + } + return TRUE; +} + + +// This is normally called when the input pin type is set to install a palette +// We will typically be called from two different places. The first is when we +// have negotiated a palettised media type after connection, the other is when +// we receive a new type during processing with an updated palette in which +// case we must remove and release the resources held by the current palette + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HRESULT CImagePalette::PreparePalette(const CMediaType *pmtNew, + const CMediaType *pmtOld, + __in LPSTR szDevice) +{ + const VIDEOINFOHEADER *pNewInfo = (VIDEOINFOHEADER *) pmtNew->Format(); + const VIDEOINFOHEADER *pOldInfo = (VIDEOINFOHEADER *) pmtOld->Format(); + ASSERT(pNewInfo); + + // This is an performance optimisation, when we get a media type we check + // to see if the format requires a palette change. If either we need one + // when previously we didn't or vica versa then this returns TRUE, if we + // previously needed a palette and we do now it compares their colours + + if (ShouldUpdate(pNewInfo,pOldInfo) == FALSE) { + NOTE("No update needed"); + return S_FALSE; + } + + // We must notify the filter graph that the application may have changed + // the palette although in practice we don't bother checking to see if it + // is really different. If it tries to get the palette either the window + // or renderer lock will ensure it doesn't get in until we are finished + + RemovePalette(); + m_pFilter->NotifyEvent(EC_PALETTE_CHANGED,0,0); + + // Do we need a palette for the new format + + if (ContainsPalette(pNewInfo) == FALSE) { + NOTE("New has no palette"); + return S_FALSE; + } + + if (m_pBaseWindow) { + m_pBaseWindow->LockPaletteLock(); + } + + // If we're changing the palette on the fly then we increment our palette + // cookie which is compared against the cookie also stored in all of our + // DIBSECTION media samples. If they don't match when we come to draw it + // then we know the sample is out of date and we'll update it's palette + + NOTE("Making new colour palette"); + m_hPalette = MakePalette(pNewInfo, szDevice); + ASSERT(m_hPalette != NULL); + + if (m_pBaseWindow) { + m_pBaseWindow->UnlockPaletteLock(); + } + + // The window in which the new palette is to be realised may be a NULL + // pointer to signal that no window is in use, if so we don't call it + // Some filters just want to use this object to create/manage palettes + + if (m_pBaseWindow) m_pBaseWindow->SetPalette(m_hPalette); + + // This is the only time where we need access to the draw object to say + // to it that a new palette will be arriving on a sample real soon. The + // constructor may take a NULL pointer in which case we don't call this + + if (m_pDrawImage) m_pDrawImage->IncrementPaletteVersion(); + return NOERROR; +} + + +// Helper function to copy a palette out of any kind of VIDEOINFO (ie it may +// be YUV or true colour) into a palettised VIDEOINFO. We use this changing +// palettes on DirectDraw samples as a source filter can attach a palette to +// any buffer (eg YUV) and hand it back. We make a new palette out of that +// format and then copy the palette colours into the current connection type + +HRESULT CImagePalette::CopyPalette(const CMediaType *pSrc,__out CMediaType *pDest) +{ + // Reset the destination palette before starting + + VIDEOINFOHEADER *pDestInfo = (VIDEOINFOHEADER *) pDest->Format(); + pDestInfo->bmiHeader.biClrUsed = 0; + pDestInfo->bmiHeader.biClrImportant = 0; + + // Does the destination have a palette + + if (PALETTISED(pDestInfo) == FALSE) { + NOTE("No destination palette"); + return S_FALSE; + } + + // Does the source contain a palette + + const VIDEOINFOHEADER *pSrcInfo = (VIDEOINFOHEADER *) pSrc->Format(); + if (ContainsPalette(pSrcInfo) == FALSE) { + NOTE("No source palette"); + return S_FALSE; + } + + // The number of colours may be zero filled + + DWORD PaletteEntries = pSrcInfo->bmiHeader.biClrUsed; + if (PaletteEntries == 0) { + DWORD Maximum = (1 << pSrcInfo->bmiHeader.biBitCount); + NOTE1("Setting maximum colours (%d)",Maximum); + PaletteEntries = Maximum; + } + + // Make sure the destination has enough room for the palette + + ASSERT(pSrcInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); + ASSERT(pSrcInfo->bmiHeader.biClrImportant <= PaletteEntries); + ASSERT(COLORS(pDestInfo) == GetBitmapPalette(pDestInfo)); + pDestInfo->bmiHeader.biClrUsed = PaletteEntries; + pDestInfo->bmiHeader.biClrImportant = pSrcInfo->bmiHeader.biClrImportant; + ULONG BitmapSize = GetBitmapFormatSize(HEADER(pSrcInfo)); + + if (pDest->FormatLength() < BitmapSize) { + NOTE("Reallocating destination"); + pDest->ReallocFormatBuffer(BitmapSize); + } + + // Now copy the palette colours across + + CopyMemory((PVOID) COLORS(pDestInfo), + (PVOID) GetBitmapPalette(pSrcInfo), + PaletteEntries * sizeof(RGBQUAD)); + + return NOERROR; +} + + +// This is normally called when the palette is changed (typically during a +// dynamic format change) to remove any palette we previously installed. We +// replace it (if necessary) in the video window with a standard VGA palette +// that should always be available even if this is a true colour display + +HRESULT CImagePalette::RemovePalette() +{ + if (m_pBaseWindow) { + m_pBaseWindow->LockPaletteLock(); + } + + // Do we have a palette to remove + + if (m_hPalette != NULL) { + + if (m_pBaseWindow) { + // Make sure that the window's palette handle matches + // our palette handle. + ASSERT(m_hPalette == m_pBaseWindow->GetPalette()); + + m_pBaseWindow->UnsetPalette(); + } + + EXECUTE_ASSERT(DeleteObject(m_hPalette)); + m_hPalette = NULL; + } + + if (m_pBaseWindow) { + m_pBaseWindow->UnlockPaletteLock(); + } + + return NOERROR; +} + + +// Called to create a palette for the object, the data structure used by GDI +// to describe a palette is a LOGPALETTE, this includes a variable number of +// PALETTEENTRY fields which are the colours, we have to convert the RGBQUAD +// colour fields we are handed in a BITMAPINFO from the media type into these +// This handles extraction of palettes from true colour and YUV media formats + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HPALETTE CImagePalette::MakePalette(const VIDEOINFOHEADER *pVideoInfo, __in LPSTR szDevice) +{ + ASSERT(ContainsPalette(pVideoInfo) == TRUE); + ASSERT(pVideoInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); + BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); + + const RGBQUAD *pColours; // Pointer to the palette + LOGPALETTE *lp; // Used to create a palette + HPALETTE hPalette; // Logical palette object + + lp = (LOGPALETTE *) new BYTE[sizeof(LOGPALETTE) + SIZE_PALETTE]; + if (lp == NULL) { + return NULL; + } + + // Unfortunately for some hare brained reason a GDI palette entry (a + // PALETTEENTRY structure) is different to a palette entry from a DIB + // format (a RGBQUAD structure) so we have to do the field conversion + // The VIDEOINFO containing the palette may be a true colour type so + // we use GetBitmapPalette to skip over any bit fields if they exist + + lp->palVersion = PALVERSION; + lp->palNumEntries = (USHORT) pHeader->biClrUsed; + if (lp->palNumEntries == 0) lp->palNumEntries = (1 << pHeader->biBitCount); + pColours = GetBitmapPalette(pVideoInfo); + + for (DWORD dwCount = 0;dwCount < lp->palNumEntries;dwCount++) { + lp->palPalEntry[dwCount].peRed = pColours[dwCount].rgbRed; + lp->palPalEntry[dwCount].peGreen = pColours[dwCount].rgbGreen; + lp->palPalEntry[dwCount].peBlue = pColours[dwCount].rgbBlue; + lp->palPalEntry[dwCount].peFlags = 0; + } + + MakeIdentityPalette(lp->palPalEntry, lp->palNumEntries, szDevice); + + // Create a logical palette + + hPalette = CreatePalette(lp); + ASSERT(hPalette != NULL); + delete[] lp; + return hPalette; +} + + +// GDI does a fair job of compressing the palette entries you give it, so for +// example if you have five entries with an RGB colour (0,0,0) it will remove +// all but one of them. When you subsequently draw an image it will map from +// your logical palette to the compressed device palette. This function looks +// to see if it is trying to be an identity palette and if so sets the flags +// field in the PALETTEENTRYs so they remain expanded to boost performance + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HRESULT CImagePalette::MakeIdentityPalette(__inout_ecount_full(iColours) PALETTEENTRY *pEntry,INT iColours, __in LPSTR szDevice) +{ + PALETTEENTRY SystemEntries[10]; // System palette entries + BOOL bIdentityPalette = TRUE; // Is an identity palette + ASSERT(iColours <= iPALETTE_COLORS); // Should have a palette + const int PalLoCount = 10; // First ten reserved colours + const int PalHiStart = 246; // Last VGA palette entries + + // Does this have the full colour range + + if (iColours < 10) { + return S_FALSE; + } + + // Apparently some displays have odd numbers of system colours + + // Get a DC on the right monitor - it's ugly, but this is the way you have + // to do it + HDC hdc; + if (szDevice == NULL || lstrcmpiLocaleIndependentA(szDevice, "DISPLAY") == 0) + hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); + else + hdc = CreateDCA(NULL, szDevice, NULL, NULL); + if (NULL == hdc) { + return E_OUTOFMEMORY; + } + INT Reserved = GetDeviceCaps(hdc,NUMRESERVED); + if (Reserved != 20) { + DeleteDC(hdc); + return S_FALSE; + } + + // Compare our palette against the first ten system entries. The reason I + // don't do a memory compare between our two arrays of colours is because + // I am not sure what will be in the flags fields for the system entries + + UINT Result = GetSystemPaletteEntries(hdc,0,PalLoCount,SystemEntries); + for (UINT Count = 0;Count < Result;Count++) { + if (SystemEntries[Count].peRed != pEntry[Count].peRed || + SystemEntries[Count].peGreen != pEntry[Count].peGreen || + SystemEntries[Count].peBlue != pEntry[Count].peBlue) { + bIdentityPalette = FALSE; + } + } + + // And likewise compare against the last ten entries + + Result = GetSystemPaletteEntries(hdc,PalHiStart,PalLoCount,SystemEntries); + for (UINT Count = 0;Count < Result;Count++) { + if (INT(Count) + PalHiStart < iColours) { + if (SystemEntries[Count].peRed != pEntry[PalHiStart + Count].peRed || + SystemEntries[Count].peGreen != pEntry[PalHiStart + Count].peGreen || + SystemEntries[Count].peBlue != pEntry[PalHiStart + Count].peBlue) { + bIdentityPalette = FALSE; + } + } + } + + // If not an identity palette then return S_FALSE + + DeleteDC(hdc); + if (bIdentityPalette == FALSE) { + return S_FALSE; + } + + // Set the non VGA entries so that GDI doesn't map them + + for (UINT Count = PalLoCount; INT(Count) < std::min(PalHiStart, iColours); Count++) { + pEntry[Count].peFlags = PC_NOCOLLAPSE; + } + return NOERROR; +} + + +// Constructor initialises the VIDEOINFO we keep storing the current display +// format. The format can be changed at any time, to reset the format held +// by us call the RefreshDisplayType directly (it's a public method). Since +// more than one thread will typically call us (ie window threads resetting +// the type and source threads in the type checking methods) we have a lock + +CImageDisplay::CImageDisplay() +{ + RefreshDisplayType(NULL); +} + + + +// This initialises the format we hold which contains the display device type +// We do a conversion on the display device type in here so that when we start +// type checking input formats we can assume that certain fields have been set +// correctly, an example is when we make the 16 bit mask fields explicit. This +// is normally called when we receive WM_DEVMODECHANGED device change messages + +// The optional szDeviceName parameter tells us which monitor we are interested +// in for a multi monitor system + +HRESULT CImageDisplay::RefreshDisplayType(__in_opt LPSTR szDeviceName) +{ + CAutoLock cDisplayLock(this); + + // Set the preferred format type + + ZeroMemory((PVOID)&m_Display,sizeof(VIDEOINFOHEADER)+sizeof(TRUECOLORINFO)); + m_Display.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + m_Display.bmiHeader.biBitCount = FALSE; + + // Get the bit depth of a device compatible bitmap + + // get caps of whichever monitor they are interested in (multi monitor) + HDC hdcDisplay; + // it's ugly, but this is the way you have to do it + if (szDeviceName == NULL || lstrcmpiLocaleIndependentA(szDeviceName, "DISPLAY") == 0) + hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL); + else + hdcDisplay = CreateDCA(NULL, szDeviceName, NULL, NULL); + if (hdcDisplay == NULL) { + ASSERT(FALSE); + DbgLog((LOG_ERROR,1,TEXT("ACK! Can't get a DC for %hs"), + szDeviceName ? szDeviceName : "")); + return E_FAIL; + } else { + DbgLog((LOG_TRACE,3,TEXT("Created a DC for %s"), + szDeviceName ? szDeviceName : "")); + } + HBITMAP hbm = CreateCompatibleBitmap(hdcDisplay,1,1); + if ( hbm ) + { + GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); + + // This call will get the colour table or the proper bitfields + GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); + DeleteObject(hbm); + } + DeleteDC(hdcDisplay); + + // Complete the display type initialisation + + ASSERT(CheckHeaderValidity(&m_Display)); + UpdateFormat(&m_Display); + DbgLog((LOG_TRACE,3,TEXT("New DISPLAY bit depth =%d"), + m_Display.bmiHeader.biBitCount)); + return NOERROR; +} + + +// We assume throughout this code that any bitfields masks are allowed no +// more than eight bits to store a colour component. This checks that the +// bit count assumption is enforced and also makes sure that all the bits +// set are contiguous. We return a boolean TRUE if the field checks out ok + +BOOL CImageDisplay::CheckBitFields(const VIDEOINFO *pInput) +{ + DWORD *pBitFields = (DWORD *) BITMASKS(pInput); + + for (INT iColour = iRED;iColour <= iBLUE;iColour++) { + + // First of all work out how many bits are set + + DWORD SetBits = CountSetBits(pBitFields[iColour]); + if (SetBits > iMAXBITS || SetBits == 0) { + NOTE1("Bit fields for component %d invalid",iColour); + return FALSE; + } + + // Next work out the number of zero bits prefix + DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); + + // This is going to see if all the bits set are contiguous (as they + // should be). We know how much to shift them right by from the + // count of prefix bits. The number of bits set defines a mask, we + // invert this (ones complement) and AND it with the shifted bit + // fields. If the result is NON zero then there are bit(s) sticking + // out the left hand end which means they are not contiguous + + DWORD TestField = pBitFields[iColour] >> PrefixBits; + DWORD Mask = ULONG_MAX << SetBits; + if (TestField & Mask) { + NOTE1("Bit fields for component %d not contiguous",iColour); + return FALSE; + } + } + return TRUE; +} + + +// This counts the number of bits set in the input field + +DWORD CImageDisplay::CountSetBits(DWORD Field) +{ + // This is a relatively well known bit counting algorithm + + DWORD Count = 0; + DWORD init = Field; + + // Until the input is exhausted, count the number of bits + + while (init) { + init = init & (init - 1); // Turn off the bottommost bit + Count++; + } + return Count; +} + + +// This counts the number of zero bits upto the first one set NOTE the input +// field should have been previously checked to ensure there is at least one +// set although if we don't find one set we return the impossible value 32 + +DWORD CImageDisplay::CountPrefixBits(DWORD Field) +{ + DWORD Mask = 1; + DWORD Count = 0; + + for (;;) { + if (Field & Mask) { + return Count; + } + Count++; + + ASSERT(Mask != 0x80000000); + if (Mask == 0x80000000) { + return Count; + } + Mask <<= 1; + } +} + + +// This is called to check the BITMAPINFOHEADER for the input type. There are +// many implicit dependancies between the fields in a header structure which +// if we validate now make for easier manipulation in subsequent handling. We +// also check that the BITMAPINFOHEADER matches it's specification such that +// fields likes the number of planes is one, that it's structure size is set +// correctly and that the bitmap dimensions have not been set as negative + +BOOL CImageDisplay::CheckHeaderValidity(const VIDEOINFO *pInput) +{ + // Check the bitmap width and height are not negative. + + if (pInput->bmiHeader.biWidth <= 0 || + pInput->bmiHeader.biHeight <= 0) { + NOTE("Invalid bitmap dimensions"); + return FALSE; + } + + // Check the compression is either BI_RGB or BI_BITFIELDS + + if (pInput->bmiHeader.biCompression != BI_RGB) { + if (pInput->bmiHeader.biCompression != BI_BITFIELDS) { + NOTE("Invalid compression format"); + return FALSE; + } + } + + // If BI_BITFIELDS compression format check the colour depth + + if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { + if (pInput->bmiHeader.biBitCount != 16) { + if (pInput->bmiHeader.biBitCount != 32) { + NOTE("BI_BITFIELDS not 16/32 bit depth"); + return FALSE; + } + } + } + + // Check the assumptions about the layout of the bit fields + + if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { + if (CheckBitFields(pInput) == FALSE) { + NOTE("Bit fields are not valid"); + return FALSE; + } + } + + // Are the number of planes equal to one + + if (pInput->bmiHeader.biPlanes != 1) { + NOTE("Number of planes not one"); + return FALSE; + } + + // Check the image size is consistent (it can be zero) + + if (pInput->bmiHeader.biSizeImage != GetBitmapSize(&pInput->bmiHeader)) { + if (pInput->bmiHeader.biSizeImage) { + NOTE("Image size incorrectly set"); + return FALSE; + } + } + + // Check the size of the structure + + if (pInput->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) { + NOTE("Size of BITMAPINFOHEADER wrong"); + return FALSE; + } + return CheckPaletteHeader(pInput); +} + + +// This runs a few simple tests against the palette fields in the input to +// see if it looks vaguely correct. The tests look at the number of palette +// colours present, the number considered important and the biCompression +// field which should always be BI_RGB as no other formats are meaningful + +BOOL CImageDisplay::CheckPaletteHeader(const VIDEOINFO *pInput) +{ + // The checks here are for palettised videos only + + if (PALETTISED(pInput) == FALSE) { + if (pInput->bmiHeader.biClrUsed) { + NOTE("Invalid palette entries"); + return FALSE; + } + return TRUE; + } + + // Compression type of BI_BITFIELDS is meaningless for palette video + + if (pInput->bmiHeader.biCompression != BI_RGB) { + NOTE("Palettised video must be BI_RGB"); + return FALSE; + } + + // Check the number of palette colours is correct + + if (pInput->bmiHeader.biClrUsed > PALETTE_ENTRIES(pInput)) { + NOTE("Too many colours in palette"); + return FALSE; + } + + // The number of important colours shouldn't exceed the number used + + if (pInput->bmiHeader.biClrImportant > pInput->bmiHeader.biClrUsed) { + NOTE("Too many important colours"); + return FALSE; + } + return TRUE; +} + + +// Return the format of the video display + +const VIDEOINFO *CImageDisplay::GetDisplayFormat() +{ + return &m_Display; +} + + +// Return TRUE if the display uses a palette + +BOOL CImageDisplay::IsPalettised() +{ + return PALETTISED(&m_Display); +} + + +// Return the bit depth of the current display setting + +WORD CImageDisplay::GetDisplayDepth() +{ + return m_Display.bmiHeader.biBitCount; +} + + +// Initialise the optional fields in a VIDEOINFO. These are mainly to do with +// the source and destination rectangles and palette information such as the +// number of colours present. It simplifies our code just a little if we don't +// have to keep checking for all the different valid permutations in a header +// every time we want to do anything with it (an example would be creating a +// palette). We set the base class media type before calling this function so +// that the media types between the pins match after a connection is made + +HRESULT CImageDisplay::UpdateFormat(__inout VIDEOINFO *pVideoInfo) +{ + ASSERT(pVideoInfo); + + BITMAPINFOHEADER *pbmi = HEADER(pVideoInfo); + UNREFERENCED_PARAMETER(pbmi); + SetRectEmpty(&pVideoInfo->rcSource); + SetRectEmpty(&pVideoInfo->rcTarget); + + // Set the number of colours explicitly + + if (PALETTISED(pVideoInfo)) { + if (pVideoInfo->bmiHeader.biClrUsed == 0) { + pVideoInfo->bmiHeader.biClrUsed = PALETTE_ENTRIES(pVideoInfo); + } + } + + // The number of important colours shouldn't exceed the number used, on + // some displays the number of important colours is not initialised when + // retrieving the display type so we set the colours used correctly + + if (pVideoInfo->bmiHeader.biClrImportant > pVideoInfo->bmiHeader.biClrUsed) { + pVideoInfo->bmiHeader.biClrImportant = PALETTE_ENTRIES(pVideoInfo); + } + + // Change the image size field to be explicit + + if (pVideoInfo->bmiHeader.biSizeImage == 0) { + pVideoInfo->bmiHeader.biSizeImage = GetBitmapSize(&pVideoInfo->bmiHeader); + } + return NOERROR; +} + + +// Lots of video rendering filters want code to check proposed formats are ok +// This checks the VIDEOINFO we are passed as a media type. If the media type +// is a valid media type then we return NOERROR otherwise E_INVALIDARG. Note +// however we only accept formats that can be easily displayed in the display +// so if we are on a 16 bit device we will not accept 24 bit images. The one +// complexity is that most displays draw 8 bit palettised images efficiently +// Also if the input format is less colour bits per pixel then we also accept + +HRESULT CImageDisplay::CheckVideoType(const VIDEOINFO *pInput) +{ + // First of all check the VIDEOINFOHEADER looks correct + + if (CheckHeaderValidity(pInput) == FALSE) { + return E_INVALIDARG; + } + + // Virtually all devices support palettised images efficiently + + if (m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount) { + if (PALETTISED(pInput) == TRUE) { + ASSERT(PALETTISED(&m_Display) == TRUE); + NOTE("(Video) Type connection ACCEPTED"); + return NOERROR; + } + } + + + // Is the display depth greater than the input format + + if (m_Display.bmiHeader.biBitCount > pInput->bmiHeader.biBitCount) { + NOTE("(Video) Mismatch agreed"); + return NOERROR; + } + + // Is the display depth less than the input format + + if (m_Display.bmiHeader.biBitCount < pInput->bmiHeader.biBitCount) { + NOTE("(Video) Format mismatch"); + return E_INVALIDARG; + } + + + // Both input and display formats are either BI_RGB or BI_BITFIELDS + + ASSERT(m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount); + ASSERT(PALETTISED(pInput) == FALSE); + ASSERT(PALETTISED(&m_Display) == FALSE); + + // BI_RGB 16 bit representation is implicitly RGB555, and likewise BI_RGB + // 24 bit representation is RGB888. So we initialise a pointer to the bit + // fields they really mean and check against the display device format + // This is only going to be called when both formats are equal bits pixel + + const DWORD *pInputMask = GetBitMasks(pInput); + const DWORD *pDisplayMask = GetBitMasks((VIDEOINFO *)&m_Display); + + if (pInputMask[iRED] != pDisplayMask[iRED] || + pInputMask[iGREEN] != pDisplayMask[iGREEN] || + pInputMask[iBLUE] != pDisplayMask[iBLUE]) { + + NOTE("(Video) Bit field mismatch"); + return E_INVALIDARG; + } + + NOTE("(Video) Type connection ACCEPTED"); + return NOERROR; +} + + +// Return the bit masks for the true colour VIDEOINFO provided + +const DWORD *CImageDisplay::GetBitMasks(const VIDEOINFO *pVideoInfo) +{ + static const DWORD FailMasks[] = {0,0,0}; + + if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { + return BITMASKS(pVideoInfo); + } + + ASSERT(pVideoInfo->bmiHeader.biCompression == BI_RGB); + + switch (pVideoInfo->bmiHeader.biBitCount) { + case 16: return bits555; + case 24: return bits888; + case 32: return bits888; + default: return FailMasks; + } +} + + +// Check to see if we can support media type pmtIn as proposed by the output +// pin - We first check that the major media type is video and also identify +// the media sub type. Then we thoroughly check the VIDEOINFO type provided +// As well as the contained VIDEOINFO being correct the major type must be +// video, the subtype a recognised video format and the type GUID correct + +HRESULT CImageDisplay::CheckMediaType(const CMediaType *pmtIn) +{ + // Does this have a VIDEOINFOHEADER format block + + const GUID *pFormatType = pmtIn->FormatType(); + if (*pFormatType != FORMAT_VideoInfo) { + NOTE("Format GUID not a VIDEOINFOHEADER"); + return E_INVALIDARG; + } + ASSERT(pmtIn->Format()); + + // Check the format looks reasonably ok + + ULONG Length = pmtIn->FormatLength(); + if (Length < SIZE_VIDEOHEADER) { + NOTE("Format smaller than a VIDEOHEADER"); + return E_FAIL; + } + + VIDEOINFO *pInput = (VIDEOINFO *) pmtIn->Format(); + + // Check the major type is MEDIATYPE_Video + + const GUID *pMajorType = pmtIn->Type(); + if (*pMajorType != MEDIATYPE_Video) { + NOTE("Major type not MEDIATYPE_Video"); + return E_INVALIDARG; + } + + // Check we can identify the media subtype + + const GUID *pSubType = pmtIn->Subtype(); + if (GetBitCount(pSubType) == USHRT_MAX) { + NOTE("Invalid video media subtype"); + return E_INVALIDARG; + } + return CheckVideoType(pInput); +} + + +// Given a video format described by a VIDEOINFO structure we return the mask +// that is used to obtain the range of acceptable colours for this type, for +// example, the mask for a 24 bit true colour format is 0xFF in all cases. A +// 16 bit 5:6:5 display format uses 0xF8, 0xFC and 0xF8, therefore given any +// RGB triplets we can AND them with these fields to find one that is valid + +BOOL CImageDisplay::GetColourMask(__out DWORD *pMaskRed, + __out DWORD *pMaskGreen, + __out DWORD *pMaskBlue) +{ + CAutoLock cDisplayLock(this); + *pMaskRed = 0xFF; + *pMaskGreen = 0xFF; + *pMaskBlue = 0xFF; + + // If this format is palettised then it doesn't have bit fields + + if (m_Display.bmiHeader.biBitCount < 16) { + return FALSE; + } + + // If this is a 24 bit true colour display then it can handle all the + // possible colour component ranges described by a byte. It is never + // allowed for a 24 bit colour depth image to have BI_BITFIELDS set + + if (m_Display.bmiHeader.biBitCount == 24) { + ASSERT(m_Display.bmiHeader.biCompression == BI_RGB); + return TRUE; + } + + // Calculate the mask based on the format's bit fields + + const DWORD *pBitFields = (DWORD *) GetBitMasks((VIDEOINFO *)&m_Display); + DWORD *pOutputMask[] = { pMaskRed, pMaskGreen, pMaskBlue }; + + // We know from earlier testing that there are no more than iMAXBITS + // bits set in the mask and that they are all contiguous. All that + // therefore remains is to shift them into the correct position + + for (INT iColour = iRED;iColour <= iBLUE;iColour++) { + + // This works out how many bits there are and where they live + + DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); + DWORD SetBits = CountSetBits(pBitFields[iColour]); + + // The first shift moves the bit field so that it is right justified + // in the DWORD, after which we then shift it back left which then + // puts the leading bit in the bytes most significant bit position + + *(pOutputMask[iColour]) = pBitFields[iColour] >> PrefixBits; + *(pOutputMask[iColour]) <<= (iMAXBITS - SetBits); + } + return TRUE; +} + + +/* Helper to convert to VIDEOINFOHEADER2 +*/ +STDAPI ConvertVideoInfoToVideoInfo2(__inout AM_MEDIA_TYPE *pmt) +{ + if (pmt->formattype != FORMAT_VideoInfo) { + return E_INVALIDARG; + } + if (NULL == pmt->pbFormat || pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { + return E_INVALIDARG; + } + VIDEOINFO *pVideoInfo = (VIDEOINFO *)pmt->pbFormat; + UNREFERENCED_PARAMETER(pVideoInfo); + DWORD dwNewSize; + HRESULT hr = DWordAdd(pmt->cbFormat, sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER), &dwNewSize); + if (FAILED(hr)) { + return hr; + } + PVOID pvNew = CoTaskMemAlloc(dwNewSize); + if (pvNew == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(pvNew, pmt->pbFormat, FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); + ZeroMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), + sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER)); + CopyMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader), + pmt->pbFormat + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), + pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); + VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pvNew; + pVideoInfo2->dwPictAspectRatioX = (DWORD)pVideoInfo2->bmiHeader.biWidth; + pVideoInfo2->dwPictAspectRatioY = (DWORD)abs(pVideoInfo2->bmiHeader.biHeight); + pmt->formattype = FORMAT_VideoInfo2; + CoTaskMemFree(pmt->pbFormat); + pmt->pbFormat = (PBYTE)pvNew; + pmt->cbFormat += sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER); + return S_OK; +} + + +// Check a media type containing VIDEOINFOHEADER +STDAPI CheckVideoInfoType(const AM_MEDIA_TYPE *pmt) +{ + if (NULL == pmt || NULL == pmt->pbFormat) { + return E_POINTER; + } + if (pmt->majortype != MEDIATYPE_Video || + pmt->formattype != FORMAT_VideoInfo || + pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + const VIDEOINFOHEADER *pHeader = (const VIDEOINFOHEADER *)pmt->pbFormat; + if (!ValidateBitmapInfoHeader( + &pHeader->bmiHeader, + pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader))) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + + return S_OK; +} + +// Check a media type containing VIDEOINFOHEADER2 +STDAPI CheckVideoInfo2Type(const AM_MEDIA_TYPE *pmt) +{ + if (NULL == pmt || NULL == pmt->pbFormat) { + return E_POINTER; + } + if (pmt->majortype != MEDIATYPE_Video || + pmt->formattype != FORMAT_VideoInfo2 || + pmt->cbFormat < sizeof(VIDEOINFOHEADER2)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + const VIDEOINFOHEADER2 *pHeader = (const VIDEOINFOHEADER2 *)pmt->pbFormat; + if (!ValidateBitmapInfoHeader( + &pHeader->bmiHeader, + pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader))) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + + return S_OK; +} diff --git a/src/thirdparty/BaseClasses/winutil.h b/src/thirdparty/BaseClasses/winutil.h index 79c4642ab44..6f4707e5097 100644 --- a/src/thirdparty/BaseClasses/winutil.h +++ b/src/thirdparty/BaseClasses/winutil.h @@ -1,421 +1,421 @@ -//------------------------------------------------------------------------------ -// File: WinUtil.h -// -// Desc: DirectShow base classes - defines generic handler classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Make sure that you call PrepareWindow to initialise the window after -// the object has been constructed. It is a separate method so that -// derived classes can override useful methods like MessageLoop. Also -// any derived class must call DoneWithWindow in its destructor. If it -// doesn't a message may be retrieved and call a derived class member -// function while a thread is executing the base class destructor code - -#ifndef __WINUTIL__ -#define __WINUTIL__ - -const int DEFWIDTH = 320; // Initial window width -const int DEFHEIGHT = 240; // Initial window height -const int CAPTION = 256; // Maximum length of caption -const int TIMELENGTH = 50; // Maximum length of times -const int PROFILESTR = 128; // Normal profile string -const WORD PALVERSION = 0x300; // GDI palette version -const LONG PALETTE_VERSION = (LONG) 1; // Initial palette version -const COLORREF VIDEO_COLOUR = 0; // Defaults to black background -const HANDLE hMEMORY = (HANDLE) (-1); // Says to open as memory file - -#define WIDTH(x) ((*(x)).right - (*(x)).left) -#define HEIGHT(x) ((*(x)).bottom - (*(x)).top) -#define SHOWSTAGE TEXT("WM_SHOWSTAGE") -#define SHOWSTAGETOP TEXT("WM_SHOWSTAGETOP") -#define REALIZEPALETTE TEXT("WM_REALIZEPALETTE") - -class AM_NOVTABLE CBaseWindow -{ -protected: - - HINSTANCE m_hInstance; // Global module instance handle - HWND m_hwnd; // Handle for our window - HDC m_hdc; // Device context for the window - LONG m_Width; // Client window width - LONG m_Height; // Client window height - BOOL m_bActivated; // Has the window been activated - LPTSTR m_pClassName; // Static string holding class name - DWORD m_ClassStyles; // Passed in to our constructor - DWORD m_WindowStyles; // Likewise the initial window styles - DWORD m_WindowStylesEx; // And the extended window styles - UINT m_ShowStageMessage; // Have the window shown with focus - UINT m_ShowStageTop; // Makes the window WS_EX_TOPMOST - UINT m_RealizePalette; // Makes us realize our new palette - HDC m_MemoryDC; // Used for fast BitBlt operations - HPALETTE m_hPalette; // Handle to any palette we may have - BYTE m_bNoRealize; // Don't realize palette now - BYTE m_bBackground; // Should we realise in background -#ifdef _DEBUG - BYTE m_bRealizing; // already realizing the palette -#endif - CCritSec m_WindowLock; // Serialise window object access - BOOL m_bDoGetDC; // Should this window get a DC - bool m_bDoPostToDestroy; // Use PostMessage to destroy - CCritSec m_PaletteLock; // This lock protects m_hPalette. - // It should be held anytime the - // program use the value of m_hPalette. - - // Maps windows message procedure into C++ methods - friend LRESULT CALLBACK WndProc(HWND hwnd, // Window handle - UINT uMsg, // Message ID - WPARAM wParam, // First parameter - LPARAM lParam); // Other parameter - - virtual LRESULT OnPaletteChange(HWND hwnd, UINT Message); - -public: - - CBaseWindow(BOOL bDoGetDC = TRUE, bool bPostToDestroy = false); - -#ifdef _DEBUG - virtual ~CBaseWindow(); -#endif - - virtual HRESULT DoneWithWindow(); - virtual HRESULT PrepareWindow(); - virtual HRESULT InactivateWindow(); - virtual HRESULT ActivateWindow(); - virtual BOOL OnSize(LONG Width, LONG Height); - virtual BOOL OnClose(); - virtual RECT GetDefaultRect(); - virtual HRESULT UninitialiseWindow(); - virtual HRESULT InitialiseWindow(HWND hwnd); - - HRESULT CompleteConnect(); - HRESULT DoCreateWindow(); - - HRESULT PerformanceAlignWindow(); - HRESULT DoShowWindow(LONG ShowCmd); - void PaintWindow(BOOL bErase); - void DoSetWindowForeground(BOOL bFocus); - virtual HRESULT SetPalette(HPALETTE hPalette); - void SetRealize(BOOL bRealize) - { - m_bNoRealize = !bRealize; - } - - // Jump over to the window thread to set the current palette - HRESULT SetPalette(); - void UnsetPalette(void); - virtual HRESULT DoRealisePalette(BOOL bForceBackground = FALSE); - - void LockPaletteLock(); - void UnlockPaletteLock(); - - virtual BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) - { return FALSE; }; - - // Access our window information - - bool WindowExists(); - LONG GetWindowWidth(); - LONG GetWindowHeight(); - HWND GetWindowHWND(); - HDC GetMemoryHDC(); - HDC GetWindowHDC(); - - #ifdef _DEBUG - HPALETTE GetPalette(); - #endif // DEBUG - - // This is the window procedure the derived object should override - - virtual INT_PTR OnReceiveMessage(HWND hwnd, // Window handle - UINT uMsg, // Message ID - WPARAM wParam, // First parameter - LPARAM lParam); // Other parameter - - // Must be overriden to return class and window styles - - virtual LPTSTR GetClassWindowStyles( - __out DWORD *pClassStyles, // Class styles - __out DWORD *pWindowStyles, // Window styles - __out DWORD *pWindowStylesEx) PURE; // Extended styles -}; - - -// This helper class is entirely subservient to the owning CBaseWindow object -// All this object does is to split out the actual drawing operation from the -// main object (because it was becoming too large). We have a number of entry -// points to set things like the draw device contexts, to implement the actual -// drawing and to set the destination rectangle in the client window. We have -// no critical section locking in this class because we are used exclusively -// by the owning window object which looks after serialising calls into us - -// If you want to use this class make sure you call NotifyAllocator once the -// allocate has been agreed, also call NotifyMediaType with a pointer to a -// NON stack based CMediaType once that has been set (we keep a pointer to -// the original rather than taking a copy). When the palette changes call -// IncrementPaletteVersion (easiest thing to do is to also call this method -// in the SetMediaType method most filters implement). Finally before you -// start rendering anything call SetDrawContext so that we can get the HDCs -// for drawing from the CBaseWindow object we are given during construction - -class CDrawImage -{ -protected: - - CBaseWindow *m_pBaseWindow; // Owning video window object - CRefTime m_StartSample; // Start time for the current sample - CRefTime m_EndSample; // And likewise it's end sample time - HDC m_hdc; // Main window device context - HDC m_MemoryDC; // Offscreen draw device context - RECT m_TargetRect; // Target destination rectangle - RECT m_SourceRect; // Source image rectangle - BOOL m_bStretch; // Do we have to stretch the images - BOOL m_bUsingImageAllocator; // Are the samples shared DIBSECTIONs - CMediaType *m_pMediaType; // Pointer to the current format - int m_perfidRenderTime; // Time taken to render an image - LONG m_PaletteVersion; // Current palette version cookie - - // Draw the video images in the window - - void SlowRender(IMediaSample *pMediaSample); - void FastRender(IMediaSample *pMediaSample); - void DisplaySampleTimes(IMediaSample *pSample); - void UpdateColourTable(HDC hdc,__in BITMAPINFOHEADER *pbmi); - void SetStretchMode(); - -public: - - // Used to control the image drawing - - CDrawImage(__inout CBaseWindow *pBaseWindow); - BOOL DrawImage(IMediaSample *pMediaSample); - BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, - __in LPRECT lprcSrc, __in LPRECT lprcDst); - void SetDrawContext(); - void SetTargetRect(__in RECT *pTargetRect); - void SetSourceRect(__in RECT *pSourceRect); - void GetTargetRect(__out RECT *pTargetRect); - void GetSourceRect(__out RECT *pSourceRect); - virtual RECT ScaleSourceRect(const RECT *pSource); - - // Handle updating palettes as they change - - LONG GetPaletteVersion(); - void ResetPaletteVersion(); - void IncrementPaletteVersion(); - - // Tell us media types and allocator assignments - - void NotifyAllocator(BOOL bUsingImageAllocator); - void NotifyMediaType(__in CMediaType *pMediaType); - BOOL UsingImageAllocator(); - - // Called when we are about to draw an image - - void NotifyStartDraw() { - MSR_START(m_perfidRenderTime); - }; - - // Called when we complete an image rendering - - void NotifyEndDraw() { - MSR_STOP(m_perfidRenderTime); - }; -}; - - -// This is the structure used to keep information about each GDI DIB. All the -// samples we create from our allocator will have a DIBSECTION allocated to -// them. When we receive the sample we know we can BitBlt straight to an HDC - -typedef struct tagDIBDATA { - - LONG PaletteVersion; // Current palette version in use - DIBSECTION DibSection; // Details of DIB section allocated - HBITMAP hBitmap; // Handle to bitmap for drawing - HANDLE hMapping; // Handle to shared memory block - BYTE *pBase; // Pointer to base memory address - -} DIBDATA; - - -// This class inherits from CMediaSample and uses all of it's methods but it -// overrides the constructor to initialise itself with the DIBDATA structure -// When we come to render an IMediaSample we will know if we are using our own -// allocator, and if we are, we can cast the IMediaSample to a pointer to one -// of these are retrieve the DIB section information and hence the HBITMAP - -class CImageSample : public CMediaSample -{ -protected: - - DIBDATA m_DibData; // Information about the DIBSECTION - BOOL m_bInit; // Is the DIB information setup - -public: - - // Constructor - - CImageSample(__inout CBaseAllocator *pAllocator, - __in_opt LPCTSTR pName, - __inout HRESULT *phr, - __in_bcount(length) LPBYTE pBuffer, - LONG length); - - // Maintain the DIB/DirectDraw state - - void SetDIBData(__in DIBDATA *pDibData); - __out DIBDATA *GetDIBData(); -}; - - -// This is an allocator based on the abstract CBaseAllocator base class that -// allocates sample buffers in shared memory. The number and size of these -// are determined when the output pin calls Prepare on us. The shared memory -// blocks are used in subsequent calls to GDI CreateDIBSection, once that -// has been done the output pin can fill the buffers with data which will -// then be handed to GDI through BitBlt calls and thereby remove one copy - -class CImageAllocator : public CBaseAllocator -{ -protected: - - CBaseFilter *m_pFilter; // Delegate reference counts to - CMediaType *m_pMediaType; // Pointer to the current format - - // Used to create and delete samples - - HRESULT Alloc(); - void Free(); - - // Manage the shared DIBSECTION and DCI/DirectDraw buffers - - HRESULT CreateDIB(LONG InSize,DIBDATA &DibData); - STDMETHODIMP CheckSizes(__in ALLOCATOR_PROPERTIES *pRequest); - virtual CImageSample *CreateImageSample(__in_bcount(Length) LPBYTE pData,LONG Length); - -public: - - // Constructor and destructor - - CImageAllocator(__inout CBaseFilter *pFilter,__in_opt LPCTSTR pName,__inout HRESULT *phr); -#ifdef _DEBUG - ~CImageAllocator(); -#endif - - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - void NotifyMediaType(__in CMediaType *pMediaType); - - // Agree the number of buffers to be used and their size - - STDMETHODIMP SetProperties( - __in ALLOCATOR_PROPERTIES *pRequest, - __out ALLOCATOR_PROPERTIES *pActual); -}; - - -// This class is a fairly specialised helper class for image renderers that -// have to create and manage palettes. The CBaseWindow class looks after -// realising palettes once they have been installed. This class can be used -// to create the palette handles from a media format (which must contain a -// VIDEOINFO structure in the format block). We try to make the palette an -// identity palette to maximise performance and also only change palettes -// if actually required to (we compare palette colours before updating). -// All the methods are virtual so that they can be overriden if so required - -class CImagePalette -{ -protected: - - CBaseWindow *m_pBaseWindow; // Window to realise palette in - CBaseFilter *m_pFilter; // Media filter to send events - CDrawImage *m_pDrawImage; // Object who will be drawing - HPALETTE m_hPalette; // The palette handle we own - -public: - - CImagePalette(__inout CBaseFilter *pBaseFilter, - __inout CBaseWindow *pBaseWindow, - __inout CDrawImage *pDrawImage); - -#ifdef _DEBUG - virtual ~CImagePalette(); -#endif - - static HPALETTE MakePalette(const VIDEOINFOHEADER *pVideoInfo, __in LPSTR szDevice); - HRESULT RemovePalette(); - static HRESULT MakeIdentityPalette(__inout_ecount_full(iColours) PALETTEENTRY *pEntry,INT iColours, __in LPSTR szDevice); - HRESULT CopyPalette(const CMediaType *pSrc,__out CMediaType *pDest); - BOOL ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,const VIDEOINFOHEADER *pOldInfo); - HRESULT PreparePalette(const CMediaType *pmtNew,const CMediaType *pmtOld,__in LPSTR szDevice); - - BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, __in LPRECT lprcSrc, __in LPRECT lprcDst) - { - return m_pDrawImage->DrawVideoImageHere(hdc, pMediaSample, lprcSrc,lprcDst); - } -}; - - -// Another helper class really for video based renderers. Most such renderers -// need to know what the display format is to some degree or another. This -// class initialises itself with the display format. The format can be asked -// for through GetDisplayFormat and various other accessor functions. If a -// filter detects a display format change (perhaps it gets a WM_DEVMODECHANGE -// message then it can call RefreshDisplayType to reset that format). Also -// many video renderers will want to check formats as they are proposed by -// source filters. This class provides methods to check formats and only -// accept those video formats that can be efficiently drawn using GDI calls - -class CImageDisplay : public CCritSec -{ -protected: - - // This holds the display format; biSize should not be too big, so we can - // safely use the VIDEOINFO structure - VIDEOINFO m_Display; - - static DWORD CountSetBits(const DWORD Field); - static DWORD CountPrefixBits(const DWORD Field); - static BOOL CheckBitFields(const VIDEOINFO *pInput); - -public: - - // Constructor and destructor - - CImageDisplay(); - - // Used to manage BITMAPINFOHEADERs and the display format - - const VIDEOINFO *GetDisplayFormat(); - HRESULT RefreshDisplayType(__in_opt LPSTR szDeviceName); - static BOOL CheckHeaderValidity(const VIDEOINFO *pInput); - static BOOL CheckPaletteHeader(const VIDEOINFO *pInput); - BOOL IsPalettised(); - WORD GetDisplayDepth(); - - // Provide simple video format type checking - - HRESULT CheckMediaType(const CMediaType *pmtIn); - HRESULT CheckVideoType(const VIDEOINFO *pInput); - HRESULT UpdateFormat(__inout VIDEOINFO *pVideoInfo); - const DWORD *GetBitMasks(const VIDEOINFO *pVideoInfo); - - BOOL GetColourMask(__out DWORD *pMaskRed, - __out DWORD *pMaskGreen, - __out DWORD *pMaskBlue); -}; - -// Convert a FORMAT_VideoInfo to FORMAT_VideoInfo2 -STDAPI ConvertVideoInfoToVideoInfo2(__inout AM_MEDIA_TYPE *pmt); - -// Check a media type containing VIDEOINFOHEADER -STDAPI CheckVideoInfoType(const AM_MEDIA_TYPE *pmt); - -// Check a media type containing VIDEOINFOHEADER -STDAPI CheckVideoInfo2Type(const AM_MEDIA_TYPE *pmt); - -#endif // __WINUTIL__ - +//------------------------------------------------------------------------------ +// File: WinUtil.h +// +// Desc: DirectShow base classes - defines generic handler classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Make sure that you call PrepareWindow to initialise the window after +// the object has been constructed. It is a separate method so that +// derived classes can override useful methods like MessageLoop. Also +// any derived class must call DoneWithWindow in its destructor. If it +// doesn't a message may be retrieved and call a derived class member +// function while a thread is executing the base class destructor code + +#ifndef __WINUTIL__ +#define __WINUTIL__ + +const int DEFWIDTH = 320; // Initial window width +const int DEFHEIGHT = 240; // Initial window height +const int CAPTION = 256; // Maximum length of caption +const int TIMELENGTH = 50; // Maximum length of times +const int PROFILESTR = 128; // Normal profile string +const WORD PALVERSION = 0x300; // GDI palette version +const LONG PALETTE_VERSION = (LONG) 1; // Initial palette version +const COLORREF VIDEO_COLOUR = 0; // Defaults to black background +const HANDLE hMEMORY = (HANDLE) (-1); // Says to open as memory file + +#define WIDTH(x) ((*(x)).right - (*(x)).left) +#define HEIGHT(x) ((*(x)).bottom - (*(x)).top) +#define SHOWSTAGE TEXT("WM_SHOWSTAGE") +#define SHOWSTAGETOP TEXT("WM_SHOWSTAGETOP") +#define REALIZEPALETTE TEXT("WM_REALIZEPALETTE") + +class AM_NOVTABLE CBaseWindow +{ +protected: + + HINSTANCE m_hInstance; // Global module instance handle + HWND m_hwnd; // Handle for our window + HDC m_hdc; // Device context for the window + LONG m_Width; // Client window width + LONG m_Height; // Client window height + BOOL m_bActivated; // Has the window been activated + LPTSTR m_pClassName; // Static string holding class name + DWORD m_ClassStyles; // Passed in to our constructor + DWORD m_WindowStyles; // Likewise the initial window styles + DWORD m_WindowStylesEx; // And the extended window styles + UINT m_ShowStageMessage; // Have the window shown with focus + UINT m_ShowStageTop; // Makes the window WS_EX_TOPMOST + UINT m_RealizePalette; // Makes us realize our new palette + HDC m_MemoryDC; // Used for fast BitBlt operations + HPALETTE m_hPalette; // Handle to any palette we may have + BYTE m_bNoRealize; // Don't realize palette now + BYTE m_bBackground; // Should we realise in background +#ifdef _DEBUG + BYTE m_bRealizing; // already realizing the palette +#endif + CCritSec m_WindowLock; // Serialise window object access + BOOL m_bDoGetDC; // Should this window get a DC + bool m_bDoPostToDestroy; // Use PostMessage to destroy + CCritSec m_PaletteLock; // This lock protects m_hPalette. + // It should be held anytime the + // program use the value of m_hPalette. + + // Maps windows message procedure into C++ methods + friend LRESULT CALLBACK WndProc(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam); // Other parameter + + virtual LRESULT OnPaletteChange(HWND hwnd, UINT Message); + +public: + + CBaseWindow(BOOL bDoGetDC = TRUE, bool bPostToDestroy = false); + +#ifdef _DEBUG + virtual ~CBaseWindow(); +#endif + + virtual HRESULT DoneWithWindow(); + virtual HRESULT PrepareWindow(); + virtual HRESULT InactivateWindow(); + virtual HRESULT ActivateWindow(); + virtual BOOL OnSize(LONG Width, LONG Height); + virtual BOOL OnClose(); + virtual RECT GetDefaultRect(); + virtual HRESULT UninitialiseWindow(); + virtual HRESULT InitialiseWindow(HWND hwnd); + + HRESULT CompleteConnect(); + HRESULT DoCreateWindow(); + + HRESULT PerformanceAlignWindow(); + HRESULT DoShowWindow(LONG ShowCmd); + void PaintWindow(BOOL bErase); + void DoSetWindowForeground(BOOL bFocus); + virtual HRESULT SetPalette(HPALETTE hPalette); + void SetRealize(BOOL bRealize) + { + m_bNoRealize = !bRealize; + } + + // Jump over to the window thread to set the current palette + HRESULT SetPalette(); + void UnsetPalette(void); + virtual HRESULT DoRealisePalette(BOOL bForceBackground = FALSE); + + void LockPaletteLock(); + void UnlockPaletteLock(); + + virtual BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { return FALSE; }; + + // Access our window information + + bool WindowExists(); + LONG GetWindowWidth(); + LONG GetWindowHeight(); + HWND GetWindowHWND(); + HDC GetMemoryHDC(); + HDC GetWindowHDC(); + + #ifdef _DEBUG + HPALETTE GetPalette(); + #endif // DEBUG + + // This is the window procedure the derived object should override + + virtual INT_PTR OnReceiveMessage(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam); // Other parameter + + // Must be overriden to return class and window styles + + virtual LPTSTR GetClassWindowStyles( + __out DWORD *pClassStyles, // Class styles + __out DWORD *pWindowStyles, // Window styles + __out DWORD *pWindowStylesEx) PURE; // Extended styles +}; + + +// This helper class is entirely subservient to the owning CBaseWindow object +// All this object does is to split out the actual drawing operation from the +// main object (because it was becoming too large). We have a number of entry +// points to set things like the draw device contexts, to implement the actual +// drawing and to set the destination rectangle in the client window. We have +// no critical section locking in this class because we are used exclusively +// by the owning window object which looks after serialising calls into us + +// If you want to use this class make sure you call NotifyAllocator once the +// allocate has been agreed, also call NotifyMediaType with a pointer to a +// NON stack based CMediaType once that has been set (we keep a pointer to +// the original rather than taking a copy). When the palette changes call +// IncrementPaletteVersion (easiest thing to do is to also call this method +// in the SetMediaType method most filters implement). Finally before you +// start rendering anything call SetDrawContext so that we can get the HDCs +// for drawing from the CBaseWindow object we are given during construction + +class CDrawImage +{ +protected: + + CBaseWindow *m_pBaseWindow; // Owning video window object + CRefTime m_StartSample; // Start time for the current sample + CRefTime m_EndSample; // And likewise it's end sample time + HDC m_hdc; // Main window device context + HDC m_MemoryDC; // Offscreen draw device context + RECT m_TargetRect; // Target destination rectangle + RECT m_SourceRect; // Source image rectangle + BOOL m_bStretch; // Do we have to stretch the images + BOOL m_bUsingImageAllocator; // Are the samples shared DIBSECTIONs + CMediaType *m_pMediaType; // Pointer to the current format + int m_perfidRenderTime; // Time taken to render an image + LONG m_PaletteVersion; // Current palette version cookie + + // Draw the video images in the window + + void SlowRender(IMediaSample *pMediaSample); + void FastRender(IMediaSample *pMediaSample); + void DisplaySampleTimes(IMediaSample *pSample); + void UpdateColourTable(HDC hdc,__in BITMAPINFOHEADER *pbmi); + void SetStretchMode(); + +public: + + // Used to control the image drawing + + CDrawImage(__inout CBaseWindow *pBaseWindow); + BOOL DrawImage(IMediaSample *pMediaSample); + BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, + __in LPRECT lprcSrc, __in LPRECT lprcDst); + void SetDrawContext(); + void SetTargetRect(__in RECT *pTargetRect); + void SetSourceRect(__in RECT *pSourceRect); + void GetTargetRect(__out RECT *pTargetRect); + void GetSourceRect(__out RECT *pSourceRect); + virtual RECT ScaleSourceRect(const RECT *pSource); + + // Handle updating palettes as they change + + LONG GetPaletteVersion(); + void ResetPaletteVersion(); + void IncrementPaletteVersion(); + + // Tell us media types and allocator assignments + + void NotifyAllocator(BOOL bUsingImageAllocator); + void NotifyMediaType(__in CMediaType *pMediaType); + BOOL UsingImageAllocator(); + + // Called when we are about to draw an image + + void NotifyStartDraw() { + MSR_START(m_perfidRenderTime); + }; + + // Called when we complete an image rendering + + void NotifyEndDraw() { + MSR_STOP(m_perfidRenderTime); + }; +}; + + +// This is the structure used to keep information about each GDI DIB. All the +// samples we create from our allocator will have a DIBSECTION allocated to +// them. When we receive the sample we know we can BitBlt straight to an HDC + +typedef struct tagDIBDATA { + + LONG PaletteVersion; // Current palette version in use + DIBSECTION DibSection; // Details of DIB section allocated + HBITMAP hBitmap; // Handle to bitmap for drawing + HANDLE hMapping; // Handle to shared memory block + BYTE *pBase; // Pointer to base memory address + +} DIBDATA; + + +// This class inherits from CMediaSample and uses all of it's methods but it +// overrides the constructor to initialise itself with the DIBDATA structure +// When we come to render an IMediaSample we will know if we are using our own +// allocator, and if we are, we can cast the IMediaSample to a pointer to one +// of these are retrieve the DIB section information and hence the HBITMAP + +class CImageSample : public CMediaSample +{ +protected: + + DIBDATA m_DibData; // Information about the DIBSECTION + BOOL m_bInit; // Is the DIB information setup + +public: + + // Constructor + + CImageSample(__inout CBaseAllocator *pAllocator, + __in_opt LPCTSTR pName, + __inout HRESULT *phr, + __in_bcount(length) LPBYTE pBuffer, + LONG length); + + // Maintain the DIB/DirectDraw state + + void SetDIBData(__in DIBDATA *pDibData); + __out DIBDATA *GetDIBData(); +}; + + +// This is an allocator based on the abstract CBaseAllocator base class that +// allocates sample buffers in shared memory. The number and size of these +// are determined when the output pin calls Prepare on us. The shared memory +// blocks are used in subsequent calls to GDI CreateDIBSection, once that +// has been done the output pin can fill the buffers with data which will +// then be handed to GDI through BitBlt calls and thereby remove one copy + +class CImageAllocator : public CBaseAllocator +{ +protected: + + CBaseFilter *m_pFilter; // Delegate reference counts to + CMediaType *m_pMediaType; // Pointer to the current format + + // Used to create and delete samples + + HRESULT Alloc(); + void Free(); + + // Manage the shared DIBSECTION and DCI/DirectDraw buffers + + HRESULT CreateDIB(LONG InSize,DIBDATA &DibData); + STDMETHODIMP CheckSizes(__in ALLOCATOR_PROPERTIES *pRequest); + virtual CImageSample *CreateImageSample(__in_bcount(Length) LPBYTE pData,LONG Length); + +public: + + // Constructor and destructor + + CImageAllocator(__inout CBaseFilter *pFilter,__in_opt LPCTSTR pName,__inout HRESULT *phr); +#ifdef _DEBUG + ~CImageAllocator(); +#endif + + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + void NotifyMediaType(__in CMediaType *pMediaType); + + // Agree the number of buffers to be used and their size + + STDMETHODIMP SetProperties( + __in ALLOCATOR_PROPERTIES *pRequest, + __out ALLOCATOR_PROPERTIES *pActual); +}; + + +// This class is a fairly specialised helper class for image renderers that +// have to create and manage palettes. The CBaseWindow class looks after +// realising palettes once they have been installed. This class can be used +// to create the palette handles from a media format (which must contain a +// VIDEOINFO structure in the format block). We try to make the palette an +// identity palette to maximise performance and also only change palettes +// if actually required to (we compare palette colours before updating). +// All the methods are virtual so that they can be overriden if so required + +class CImagePalette +{ +protected: + + CBaseWindow *m_pBaseWindow; // Window to realise palette in + CBaseFilter *m_pFilter; // Media filter to send events + CDrawImage *m_pDrawImage; // Object who will be drawing + HPALETTE m_hPalette; // The palette handle we own + +public: + + CImagePalette(__inout CBaseFilter *pBaseFilter, + __inout CBaseWindow *pBaseWindow, + __inout CDrawImage *pDrawImage); + +#ifdef _DEBUG + virtual ~CImagePalette(); +#endif + + static HPALETTE MakePalette(const VIDEOINFOHEADER *pVideoInfo, __in LPSTR szDevice); + HRESULT RemovePalette(); + static HRESULT MakeIdentityPalette(__inout_ecount_full(iColours) PALETTEENTRY *pEntry,INT iColours, __in LPSTR szDevice); + HRESULT CopyPalette(const CMediaType *pSrc,__out CMediaType *pDest); + BOOL ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,const VIDEOINFOHEADER *pOldInfo); + HRESULT PreparePalette(const CMediaType *pmtNew,const CMediaType *pmtOld,__in LPSTR szDevice); + + BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, __in LPRECT lprcSrc, __in LPRECT lprcDst) + { + return m_pDrawImage->DrawVideoImageHere(hdc, pMediaSample, lprcSrc,lprcDst); + } +}; + + +// Another helper class really for video based renderers. Most such renderers +// need to know what the display format is to some degree or another. This +// class initialises itself with the display format. The format can be asked +// for through GetDisplayFormat and various other accessor functions. If a +// filter detects a display format change (perhaps it gets a WM_DEVMODECHANGE +// message then it can call RefreshDisplayType to reset that format). Also +// many video renderers will want to check formats as they are proposed by +// source filters. This class provides methods to check formats and only +// accept those video formats that can be efficiently drawn using GDI calls + +class CImageDisplay : public CCritSec +{ +protected: + + // This holds the display format; biSize should not be too big, so we can + // safely use the VIDEOINFO structure + VIDEOINFO m_Display; + + static DWORD CountSetBits(const DWORD Field); + static DWORD CountPrefixBits(const DWORD Field); + static BOOL CheckBitFields(const VIDEOINFO *pInput); + +public: + + // Constructor and destructor + + CImageDisplay(); + + // Used to manage BITMAPINFOHEADERs and the display format + + const VIDEOINFO *GetDisplayFormat(); + HRESULT RefreshDisplayType(__in_opt LPSTR szDeviceName); + static BOOL CheckHeaderValidity(const VIDEOINFO *pInput); + static BOOL CheckPaletteHeader(const VIDEOINFO *pInput); + BOOL IsPalettised(); + WORD GetDisplayDepth(); + + // Provide simple video format type checking + + HRESULT CheckMediaType(const CMediaType *pmtIn); + HRESULT CheckVideoType(const VIDEOINFO *pInput); + HRESULT UpdateFormat(__inout VIDEOINFO *pVideoInfo); + const DWORD *GetBitMasks(const VIDEOINFO *pVideoInfo); + + BOOL GetColourMask(__out DWORD *pMaskRed, + __out DWORD *pMaskGreen, + __out DWORD *pMaskBlue); +}; + +// Convert a FORMAT_VideoInfo to FORMAT_VideoInfo2 +STDAPI ConvertVideoInfoToVideoInfo2(__inout AM_MEDIA_TYPE *pmt); + +// Check a media type containing VIDEOINFOHEADER +STDAPI CheckVideoInfoType(const AM_MEDIA_TYPE *pmt); + +// Check a media type containing VIDEOINFOHEADER +STDAPI CheckVideoInfo2Type(const AM_MEDIA_TYPE *pmt); + +#endif // __WINUTIL__ + diff --git a/src/thirdparty/BaseClasses/wxdebug.cpp b/src/thirdparty/BaseClasses/wxdebug.cpp index 410900484fd..7bdfe75055a 100644 --- a/src/thirdparty/BaseClasses/wxdebug.cpp +++ b/src/thirdparty/BaseClasses/wxdebug.cpp @@ -1,1475 +1,1475 @@ -//------------------------------------------------------------------------------ -// File: WXDebug.cpp -// -// Desc: DirectShow base classes - implements ActiveX system debugging -// facilities. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -//#define _WINDLL - -#include "streams.h" -#include -#include -#include - -#ifdef _DEBUG -#ifdef UNICODE -#ifndef _UNICODE -#define _UNICODE -#endif // _UNICODE -#endif // UNICODE -#endif // DEBUG - -#include -#include - -#ifdef _DEBUG -static void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi); -static void DisplayRECT(LPCTSTR szLabel, const RECT& rc); - -// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. -// See the documentation for wsprintf()'s lpOut parameter for more information. -const INT iDEBUGINFO = 1024; // Used to format strings - -/* For every module and executable we store a debugging level for each of - the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy - to isolate and debug individual modules without seeing everybody elses - spurious debug output. The keys are stored in the registry under the - HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\ key values - NOTE these must be in the same order as their enumeration definition */ - -const LPCTSTR pKeyNames[] = { - TEXT("TIMING"), // Timing and performance measurements - TEXT("TRACE"), // General step point call tracing - TEXT("MEMORY"), // Memory and object allocation/destruction - TEXT("LOCKING"), // Locking/unlocking of critical sections - TEXT("ERROR"), // Debug error notification - TEXT("CUSTOM1"), - TEXT("CUSTOM2"), - TEXT("CUSTOM3"), - TEXT("CUSTOM4"), - TEXT("CUSTOM5") - }; - -const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s"); -const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s"); - -const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories - -HINSTANCE m_hInst; // Module instance handle -TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name -DWORD m_Levels[iMAXLEVELS]; // Debug level per category -CRITICAL_SECTION m_CSDebug; // Controls access to list -DWORD m_dwNextCookie; // Next active object ID -ObjectDesc *pListHead = NULL; // First active object -DWORD m_dwObjectCount; // Active object count -BOOL m_bInit = FALSE; // Have we been initialised -HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here -DWORD dwWaitTimeout = INFINITE; // Default timeout value -DWORD dwTimeOffset; // Time of first DbgLog call -bool g_fUseKASSERT = false; // don't create messagebox -bool g_fDbgInDllEntryPoint = false; -bool g_fAutoRefreshLevels = false; - -LPCTSTR pBaseKey = TEXT("SOFTWARE\\Microsoft\\DirectShow\\Debug"); -LPCTSTR pGlobalKey = TEXT("GLOBAL"); -static LPCSTR pUnknownName = "UNKNOWN"; - -LPCTSTR TimeoutName = TEXT("TIMEOUT"); - -/* This sets the instance handle that the debug library uses to find - the module's file name from the Win32 GetModuleFileName function */ - -void WINAPI DbgInitialise(HINSTANCE hInst) -{ - InitializeCriticalSection(&m_CSDebug); - m_bInit = TRUE; - - m_hInst = hInst; - DbgInitModuleName(); - if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0)) - DebugBreak(); - DbgInitModuleSettings(false); - DbgInitGlobalSettings(true); - dwTimeOffset = timeGetTime(); -} - - -/* This is called to clear up any resources the debug library uses - at the - moment we delete our critical section and the object list. The values we - retrieve from the registry are all done during initialisation but we don't - go looking for update notifications while we are running, if the values - are changed then the application has to be restarted to pick them up */ - -void WINAPI DbgTerminate() -{ - if (m_hOutput != INVALID_HANDLE_VALUE) { - EXECUTE_ASSERT(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - DeleteCriticalSection(&m_CSDebug); - m_bInit = FALSE; -} - - -/* This is called by DbgInitLogLevels to read the debug settings - for each logging category for this module from the registry */ - -void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax) -{ - LONG lReturn; // Create key return value - LONG lKeyPos; // Current key category - DWORD dwKeySize; // Size of the key value - DWORD dwKeyType; // Receives it's type - DWORD dwKeyValue; // This fields value - - /* Try and read a value for each key position in turn */ - for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) { - - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[lKeyPos], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) &dwKeyValue, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - /* If either the key was not available or it was not a DWORD value - then we ensure only the high priority debug logging is output - but we try and update the field to a zero filled DWORD value */ - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { - - dwKeyValue = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[lKeyPos], // Address of subkey name - (DWORD) 0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE) &dwKeyValue, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); - dwKeyValue = 0; - } - } - if(fTakeMax) - { - m_Levels[lKeyPos] = std::max(dwKeyValue, m_Levels[lKeyPos]); - } - else - { - if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) { - m_Levels[lKeyPos] = dwKeyValue; - } - } - } - - /* Read the timeout value for catching hangs */ - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - TimeoutName, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) &dwWaitTimeout, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - /* If either the key was not available or it was not a DWORD value - then we ensure only the high priority debug logging is output - but we try and update the field to a zero filled DWORD value */ - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { - - dwWaitTimeout = INFINITE; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - TimeoutName, // Address of subkey name - (DWORD) 0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE) &dwWaitTimeout, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); - dwWaitTimeout = INFINITE; - } - } -} - -void WINAPI DbgOutString(LPCTSTR psz) -{ - if (m_hOutput != INVALID_HANDLE_VALUE) { - UINT cb = lstrlen(psz); - DWORD dw; -#ifdef UNICODE - CHAR szDest[2048]; - WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0); - WriteFile (m_hOutput, szDest, cb, &dw, NULL); -#else - WriteFile (m_hOutput, psz, cb, &dw, NULL); -#endif - } else { - OutputDebugString (psz); - } -} - - - - -HRESULT DbgUniqueProcessName(LPCTSTR inName, LPTSTR outName) -{ - HRESULT hr = S_OK; - const TCHAR *pIn = inName; - int dotPos = -1; - - //scan the input and record the last '.' position - while (*pIn && (pIn - inName) < MAX_PATH) - { - if ( TEXT('.') == *pIn ) - dotPos = (int)(pIn-inName); - ++pIn; - } - - if (*pIn) //input should be zero-terminated within MAX_PATH - return E_INVALIDARG; - - DWORD dwProcessId = GetCurrentProcessId(); - - if (dotPos < 0) - { - //no extension in the input, appending process id to the input - hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d"), inName, dwProcessId); - } - else - { - TCHAR pathAndBasename[MAX_PATH] = {0}; - - //there's an extension - zero-terminate the path and basename first by copying - hr = StringCchCopyN(pathAndBasename, MAX_PATH, inName, (size_t)dotPos); - - //re-combine path, basename and extension with processId appended to a basename - if (SUCCEEDED(hr)) - hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d%s"), pathAndBasename, dwProcessId, inName + dotPos); - } - - return hr; -} - - -/* Called by DbgInitGlobalSettings to setup alternate logging destinations - */ - -void WINAPI DbgInitLogTo ( - HKEY hKey) -{ - LONG lReturn; - DWORD dwKeyType; - DWORD dwKeySize; - TCHAR szFile[MAX_PATH] = {0}; - static const TCHAR cszKey[] = TEXT("LogToFile"); - - dwKeySize = MAX_PATH; - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - cszKey, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) szFile, // Returns the field's value - &dwKeySize); // Number of bytes transferred - - // create an empty key if it does not already exist - // - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) - { - dwKeySize = sizeof(TCHAR); - lReturn = RegSetValueEx( - hKey, // Handle of an open key - cszKey, // Address of subkey name - (DWORD) 0, // Reserved field - REG_SZ, // Type of the key field - (PBYTE)szFile, // Value for the field - dwKeySize); // Size of the field buffer - } - - // if an output-to was specified. try to open it. - // - if (m_hOutput != INVALID_HANDLE_VALUE) { - EXECUTE_ASSERT(CloseHandle (m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - if (szFile[0] != 0) - { - if (!lstrcmpi(szFile, TEXT("Console"))) { - m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); - if (m_hOutput == INVALID_HANDLE_VALUE) { - AllocConsole (); - m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); - } - SetConsoleTitle (TEXT("ActiveX Debug Output")); - } else if (szFile[0] && - lstrcmpi(szFile, TEXT("Debug")) && - lstrcmpi(szFile, TEXT("Debugger")) && - lstrcmpi(szFile, TEXT("Deb"))) - { - m_hOutput = CreateFile(szFile, GENERIC_WRITE, - FILE_SHARE_READ, - NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (INVALID_HANDLE_VALUE == m_hOutput && - GetLastError() == ERROR_SHARING_VIOLATION) - { - TCHAR uniqueName[MAX_PATH] = {0}; - if (SUCCEEDED(DbgUniqueProcessName(szFile, uniqueName))) - { - m_hOutput = CreateFile(uniqueName, GENERIC_WRITE, - FILE_SHARE_READ, - NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - } - } - - if (INVALID_HANDLE_VALUE != m_hOutput) - { - static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); - LARGE_INTEGER zero = {0, 0}; - SetFilePointerEx(m_hOutput, zero, NULL, FILE_END); - DbgOutString (cszBar); - } - } - } -} - - - -/* This is called by DbgInitLogLevels to read the global debug settings for - each logging category for this module from the registry. Normally each - module has it's own values set for it's different debug categories but - setting the global SOFTWARE\Debug\Global applies them to ALL modules */ - -void WINAPI DbgInitGlobalSettings(bool fTakeMax) -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hGlobalKey; // Global override key - - /* Construct the global base key name */ - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey); - - /* Create or open the key for this module */ - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - GENERIC_READ | GENERIC_WRITE, // Desired security access - NULL, // Key security descriptor - &hGlobalKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) { - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - GENERIC_READ, // Desired security access - NULL, // Key security descriptor - &hGlobalKey, // Opened handle buffer - NULL); // What really happened - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,1,TEXT("Could not access GLOBAL module key"))); - } - return; - } - - DbgInitKeyLevels(hGlobalKey, fTakeMax); - RegCloseKey(hGlobalKey); -} - - -/* This sets the debugging log levels for the different categories. We start - by opening (or creating if not already available) the SOFTWARE\Debug key - that all these settings live under. We then look at the global values - set under SOFTWARE\Debug\Global which apply on top of the individual - module settings. We then load the individual module registry settings */ - -void WINAPI DbgInitModuleSettings(bool fTakeMax) -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hModuleKey; // Module key handle - - /* Construct the base key name */ - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,m_ModuleName); - - /* Create or open the key for this module */ - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - GENERIC_READ | GENERIC_WRITE, // Desired security access - NULL, // Key security descriptor - &hModuleKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) { - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - GENERIC_READ, // Desired security access - NULL, // Key security descriptor - &hModuleKey, // Opened handle buffer - NULL); // What really happened - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,1,TEXT("Could not access module key"))); - } - return; - } - - DbgInitLogTo(hModuleKey); - DbgInitKeyLevels(hModuleKey, fTakeMax); - RegCloseKey(hModuleKey); -} - - -/* Initialise the module file name */ - -void WINAPI DbgInitModuleName() -{ - TCHAR FullName[iDEBUGINFO]; // Load the full path and module name - LPTSTR pName; // Searches from the end for a backslash - - GetModuleFileName(m_hInst,FullName,iDEBUGINFO); - pName = _tcsrchr(FullName,'\\'); - if (pName == NULL) { - pName = FullName; - } else { - pName++; - } - (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName); -} - -struct MsgBoxMsg -{ - HWND hwnd; - LPCTSTR szTitle; - LPCTSTR szMessage; - DWORD dwFlags; - INT iResult; -}; - -// -// create a thread to call MessageBox(). calling MessageBox() on -// random threads at bad times can confuse the host (eg IE). -// -DWORD WINAPI MsgBoxThread( - __inout LPVOID lpParameter // thread data - ) -{ - MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter; - pmsg->iResult = MessageBox( - pmsg->hwnd, - pmsg->szTitle, - pmsg->szMessage, - pmsg->dwFlags); - - return 0; -} - -INT MessageBoxOtherThread( - HWND hwnd, - LPCTSTR szTitle, - LPCTSTR szMessage, - DWORD dwFlags) -{ - if(g_fDbgInDllEntryPoint) - { - // can't wait on another thread because we have the loader - // lock held in the dll entry point. - // This can crash sometimes so just skip it - // return MessageBox(hwnd, szTitle, szMessage, dwFlags); - return IDCANCEL; - } - else - { - MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0}; - DWORD dwid; - HANDLE hThread = CreateThread( - 0, // security - 0, // stack size - MsgBoxThread, - (void *)&msg, // arg - 0, // flags - &dwid); - if(hThread) - { - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - return msg.iResult; - } - - // break into debugger on failure. - return IDCANCEL; - } -} - -/* Displays a message box if the condition evaluated to FALSE */ - -void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine) -{ - if(g_fUseKASSERT) - { - DbgKernelAssert(pCondition, pFileName, iLine); - } - else - { - - TCHAR szInfo[iDEBUGINFO]; - - (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), - pCondition, iLine, pFileName); - - INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"), - MB_SYSTEMMODAL | - MB_ICONHAND | - MB_YESNOCANCEL | - MB_SETFOREGROUND); - switch (MsgId) - { - case IDNO: /* Kill the application */ - - FatalAppExit(FALSE, TEXT("Application terminated")); - break; - - case IDCANCEL: /* Break into the debugger */ - - DebugBreak(); - break; - - case IDYES: /* Ignore assertion continue execution */ - break; - } - } -} - -/* Displays a message box at a break point */ - -void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine) -{ - if(g_fUseKASSERT) - { - DbgKernelAssert(pCondition, pFileName, iLine); - } - else - { - TCHAR szInfo[iDEBUGINFO]; - - (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), - pCondition, iLine, pFileName); - - INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"), - MB_SYSTEMMODAL | - MB_ICONHAND | - MB_YESNOCANCEL | - MB_SETFOREGROUND); - switch (MsgId) - { - case IDNO: /* Kill the application */ - - FatalAppExit(FALSE, TEXT("Application terminated")); - break; - - case IDCANCEL: /* Break into the debugger */ - - DebugBreak(); - break; - - case IDYES: /* Ignore break point continue execution */ - break; - } - } -} - -void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...) -{ - // A debug break point message can have at most 2000 characters if - // ANSI or UNICODE characters are being used. A debug break point message - // can have between 1000 and 2000 double byte characters in it. If a - // particular message needs more characters, then the value of this constant - // should be increased. - const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000; - - TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE]; - - va_list va; - va_start( va, szFormatString ); - - HRESULT hr = StringCchVPrintf( szBreakPointMessage, NUMELMS(szBreakPointMessage), szFormatString, va ); - - va_end(va); - - if( FAILED(hr) ) { - DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because StringCchVPrintf() failed." ); - return; - } - - ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine ); -} - - -/* When we initialised the library we stored in the m_Levels array the current - debug output level for this module for each of the five categories. When - some debug logging is sent to us it can be sent with a combination of the - categories (if it is applicable to many for example) in which case we map - the type's categories into their current debug levels and see if any of - them can be accepted. The function looks at each bit position in turn from - the input type field and then compares it's debug level with the modules. - - A level of 0 means that output is always sent to the debugger. This is - due to producing output if the input level is <= m_Levels. -*/ - - -BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level) -{ - if(g_fAutoRefreshLevels) - { - // re-read the registry every second. We cannot use RegNotify() to - // notice registry changes because it's not available on win9x. - static DWORD g_dwLastRefresh = 0; - DWORD dwTime = timeGetTime(); - if(dwTime - g_dwLastRefresh > 1000) { - g_dwLastRefresh = dwTime; - - // there's a race condition: multiple threads could update the - // values. plus read and write not synchronized. no harm - // though. - DbgInitModuleSettings(false); - } - } - - - DWORD Mask = 0x01; - - // If no valid bits are set return FALSE - if ((Type & ((1<m_szName = szObjectName; - pObject->m_wszName = wszObjectName; - pObject->m_dwCookie = ++m_dwNextCookie; - pObject->m_pNext = pListHead; - - pListHead = pObject; - m_dwObjectCount++; - - DWORD ObjectCookie = pObject->m_dwCookie; - ASSERT(ObjectCookie); - - if(wszObjectName) { - DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"), - pObject->m_dwCookie, wszObjectName, m_dwObjectCount)); - } else { - DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"), - pObject->m_dwCookie, szObjectName, m_dwObjectCount)); - } - - LeaveCriticalSection(&m_CSDebug); - return ObjectCookie; -} - - -/* This is called by the CBaseObject destructor when an object is about to be - destroyed, we are passed the cookie we returned during construction that - identifies this object. We scan the object list for a matching cookie and - remove the object if successful. We also update the active object count */ - -BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie) -{ - /* Grab the list critical section */ - EnterCriticalSection(&m_CSDebug); - - ObjectDesc *pObject = pListHead; - ObjectDesc *pPrevious = NULL; - - /* Scan the object list looking for a cookie match */ - - while (pObject) { - if (pObject->m_dwCookie == dwCookie) { - break; - } - pPrevious = pObject; - pObject = pObject->m_pNext; - } - - if (pObject == NULL) { - DbgBreak("Apparently destroying a bogus object"); - LeaveCriticalSection(&m_CSDebug); - return FALSE; - } - - /* Is the object at the head of the list */ - - if (pPrevious == NULL) { - pListHead = pObject->m_pNext; - } else { - pPrevious->m_pNext = pObject->m_pNext; - } - - /* Delete the object and update the housekeeping information */ - - m_dwObjectCount--; - - if(pObject->m_wszName) { - DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"), - pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount)); - } else { - DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"), - pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount)); - } - - delete pObject; - LeaveCriticalSection(&m_CSDebug); - return TRUE; -} - - -/* This runs through the active object list displaying their details */ - -void WINAPI DbgDumpObjectRegister() -{ - TCHAR szInfo[iDEBUGINFO]; - - /* Grab the list critical section */ - - EnterCriticalSection(&m_CSDebug); - ObjectDesc *pObject = pListHead; - - /* Scan the object list displaying the name and cookie */ - - DbgLog((LOG_MEMORY,2,TEXT(""))); - DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description"))); - DbgLog((LOG_MEMORY,2,TEXT(""))); - - while (pObject) { - if(pObject->m_wszName) { - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30ls"),pObject->m_dwCookie, &pObject, pObject->m_wszName); - } else { - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30hs"),pObject->m_dwCookie, &pObject, pObject->m_szName); - } - DbgLog((LOG_MEMORY,2,szInfo)); - pObject = pObject->m_pNext; - } - - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount); - DbgLog((LOG_MEMORY,2,TEXT(""))); - DbgLog((LOG_MEMORY,1,szInfo)); - LeaveCriticalSection(&m_CSDebug); -} - -/* Debug infinite wait stuff */ -DWORD WINAPI DbgWaitForSingleObject(HANDLE h) -{ - DWORD dwWaitResult; - do { - dwWaitResult = WaitForSingleObject(h, dwWaitTimeout); - ASSERT(dwWaitResult == WAIT_OBJECT_0); - } while (dwWaitResult == WAIT_TIMEOUT); - return dwWaitResult; -} -DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, - __in_ecount(nCount) CONST HANDLE *lpHandles, - BOOL bWaitAll) -{ - DWORD dwWaitResult; - do { - dwWaitResult = WaitForMultipleObjects(nCount, - lpHandles, - bWaitAll, - dwWaitTimeout); - ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS); - } while (dwWaitResult == WAIT_TIMEOUT); - return dwWaitResult; -} - -void WINAPI DbgSetWaitTimeout(DWORD dwTimeout) -{ - dwWaitTimeout = dwTimeout; -} - -#endif /* DEBUG */ - -#ifdef _OBJBASE_H_ - - /* Stuff for printing out our GUID names */ - - constexpr GUID_STRING_ENTRY g_GuidNames[] = { - #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } }, - #include - }; - - CGuidNameList GuidNames; - int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]); - - LPCSTR CGuidNameList::operator [] (const GUID &guid) - { - for (int i = 0; i < g_cGuidNames; i++) { - if (g_GuidNames[i].guid == guid) { - return g_GuidNames[i].szName; - } - } - if (guid == GUID_NULL) { - return "GUID_NULL"; - } - - // !!! add something to print FOURCC guids? - - // shouldn't this print the hex CLSID? - return "Unknown GUID Name"; - } - -#endif /* _OBJBASE_H_ */ - -/* CDisp class - display our data types */ - -// clashes with REFERENCE_TIME -CDisp::CDisp(LONGLONG ll, int Format) -{ - // note: this could be combined with CDisp(LONGLONG) by - // introducing a default format of CDISP_REFTIME - LARGE_INTEGER li; - li.QuadPart = ll; - switch (Format) { - case CDISP_DEC: - { - TCHAR temp[20]; - int pos=20; - temp[--pos] = 0; - int digit; - // always output at least one digit - do { - // Get the rightmost digit - we only need the low word - digit = li.LowPart % 10; - li.QuadPart /= 10; - temp[--pos] = (TCHAR) digit+L'0'; - } while (li.QuadPart); - (void)StringCchCopy(m_String, NUMELMS(m_String), temp+pos); - break; - } - case CDISP_HEX: - default: - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart); - } -}; - -CDisp::CDisp(REFCLSID clsid) -{ -#ifdef UNICODE - (void)StringFromGUID2(clsid, m_String, NUMELMS(m_String)); -#else - WCHAR wszTemp[50]; - (void)StringFromGUID2(clsid, wszTemp, NUMELMS(wszTemp)); - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), wszTemp); -#endif -}; - -#ifdef __STREAMS__ -/* Display stuff */ -CDisp::CDisp(CRefTime llTime) -{ - LONGLONG llDiv; - if (llTime < 0) { - llTime = -llTime; - (void)StringCchCopy(m_String, NUMELMS(m_String), TEXT("-")); - } - llDiv = (LONGLONG)24 * 3600 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d days "), (LONG)(llTime / llDiv)); - llTime = llTime % llDiv; - } - llDiv = (LONGLONG)3600 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d hrs "), (LONG)(llTime / llDiv)); - llTime = llTime % llDiv; - } - llDiv = (LONGLONG)60 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d mins "), (LONG)(llTime / llDiv)); - llTime = llTime % llDiv; - } - (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d.%3.3d sec"), - (LONG)llTime / 10000000, - (LONG)((llTime % 10000000) / 10000)); -}; - -#endif // __STREAMS__ - - -/* Display pin */ -CDisp::CDisp(IPin *pPin) -{ - PIN_INFO pi; - TCHAR str[MAX_PIN_NAME]; - CLSID clsid; - - if (pPin) { - pPin->QueryPinInfo(&pi); - pi.pFilter->GetClassID(&clsid); - QueryPinInfoReleaseFilter(pi); - #ifndef UNICODE - WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1, - str, MAX_PIN_NAME, NULL, NULL); - #else - (void)StringCchCopy(str, NUMELMS(str), pi.achName); - #endif - } else { - (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin")); - } - - m_pString = (PTCHAR) new TCHAR[lstrlen(str)+64]; - if (!m_pString) { - return; - } - - (void)StringCchPrintf(m_pString, lstrlen(str) + 64, TEXT("%hs(%s)"), GuidNames[clsid], str); -} - -/* Display filter or pin */ -CDisp::CDisp(IUnknown *pUnk) -{ - IBaseFilter *pf; - HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf); - if(SUCCEEDED(hr)) - { - FILTER_INFO fi; - hr = pf->QueryFilterInfo(&fi); - if(SUCCEEDED(hr)) - { - QueryFilterInfoReleaseGraph(fi); - - size_t len = lstrlenW(fi.achName) + 1; - - m_pString = new TCHAR[len]; - if(m_pString) - { -#ifdef UNICODE - (void)StringCchCopy(m_pString, len, fi.achName); -#else - (void)StringCchPrintf(m_pString, len, "%S", fi.achName); -#endif - } - } - - pf->Release(); - - return; - } - - IPin *pp; - hr = pUnk->QueryInterface(IID_IPin, (void **)&pp); - if(SUCCEEDED(hr)) - { - CDisp::CDisp(pp); - pp->Release(); - return; - } -} - - -CDisp::~CDisp() -{ -} - -CDispBasic::~CDispBasic() -{ - if (m_pString != m_String) { - delete [] m_pString; - } -} - -CDisp::CDisp(double d) -{ - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000)); -} - - -/* If built for debug this will display the media type details. We convert the - major and subtypes into strings and also ask the base classes for a string - description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit - We also display the fields in the BITMAPINFOHEADER structure, this should - succeed as we do not accept input types unless the format is big enough */ - -#ifdef _DEBUG -void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn) -{ - - /* Dump the GUID types and a short description */ - - DbgLog((LOG_TRACE,5,TEXT(""))); - DbgLog((LOG_TRACE,2,TEXT("%s M type %hs S type %hs"), label, - GuidNames[pmtIn->majortype], - GuidNames[pmtIn->subtype])); - DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype))); - - /* Dump the generic media types */ - - if (pmtIn->bTemporalCompression) { - DbgLog((LOG_TRACE,5,TEXT("Temporally compressed"))); - } else { - DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed"))); - } - - if (pmtIn->bFixedSizeSamples) { - DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize)); - } else { - DbgLog((LOG_TRACE,5,TEXT("Variable size samples"))); - } - - if (pmtIn->formattype == FORMAT_VideoInfo) { - - VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat; - - DisplayRECT(TEXT("Source rectangle"),pVideoInfo->rcSource); - DisplayRECT(TEXT("Target rectangle"),pVideoInfo->rcTarget); - DisplayBITMAPINFO(HEADER(pmtIn->pbFormat)); - - } if (pmtIn->formattype == FORMAT_VideoInfo2) { - - VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pmtIn->pbFormat; - - DisplayRECT(TEXT("Source rectangle"),pVideoInfo2->rcSource); - DisplayRECT(TEXT("Target rectangle"),pVideoInfo2->rcTarget); - DbgLog((LOG_TRACE, 5, TEXT("Aspect Ratio: %d:%d"), - pVideoInfo2->dwPictAspectRatioX, - pVideoInfo2->dwPictAspectRatioY)); - DisplayBITMAPINFO(&pVideoInfo2->bmiHeader); - - } else if (pmtIn->majortype == MEDIATYPE_Audio) { - DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), - GuidNames[pmtIn->formattype])); - DbgLog((LOG_TRACE,2,TEXT(" Subtype %hs"), - GuidNames[pmtIn->subtype])); - - if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet) - && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT))) - { - /* Dump the contents of the WAVEFORMATEX type-specific format structure */ - - WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat; - DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag)); - DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels)); - DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec)); - DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec)); - DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign)); - DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample)); - - /* PCM uses a WAVEFORMAT and does not have the extra size field */ - - if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) { - DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize)); - } - } else { - } - - } else { - DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), - GuidNames[pmtIn->formattype])); - } -} - - -void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi) -{ - DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize)); - if (pbmi->biCompression < 256) { - DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit (%d)"), - pbmi->biWidth, pbmi->biHeight, - pbmi->biBitCount, pbmi->biCompression)); - } else { - DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"), - pbmi->biWidth, pbmi->biHeight, - pbmi->biBitCount, &pbmi->biCompression)); - } - - DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage)); - DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes)); - DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter)); - DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter)); - DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed)); -} - - -void DisplayRECT(LPCTSTR szLabel, const RECT& rc) -{ - DbgLog((LOG_TRACE,5,TEXT("%s (Left %d Top %d Right %d Bottom %d)"), - szLabel, - rc.left, - rc.top, - rc.right, - rc.bottom)); -} - - -void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel) -{ - if( !pGraph ) - { - return; - } - - IEnumFilters *pFilters; - - DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph)); - - if (FAILED(pGraph->EnumFilters(&pFilters))) { - DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!"))); - } - - IBaseFilter *pFilter; - ULONG n; - while (pFilters->Next(1, &pFilter, &n) == S_OK) { - FILTER_INFO info; - - if (FAILED(pFilter->QueryFilterInfo(&info))) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] -- failed QueryFilterInfo"), pFilter)); - } else { - QueryFilterInfoReleaseGraph(info); - - // !!! should QueryVendorInfo here! - - DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] '%ls'"), pFilter, info.achName)); - - IEnumPins *pins; - - if (FAILED(pFilter->EnumPins(&pins))) { - DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!"))); - } else { - - IPin *pPin; - while (pins->Next(1, &pPin, &n) == S_OK) { - PIN_INFO pinInfo; - - if (FAILED(pPin->QueryPinInfo(&pinInfo))) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin)); - } else { - QueryPinInfoReleaseFilter(pinInfo); - - IPin *pPinConnected = NULL; - - HRESULT hr = pPin->ConnectedTo(&pPinConnected); - - if (pPinConnected) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%p] '%ls' [%sput]") - TEXT(" Connected to pin [%p]"), - pPin, pinInfo.achName, - pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"), - pPinConnected)); - - pPinConnected->Release(); - - // perhaps we should really dump the type both ways as a sanity - // check? - if (pinInfo.dir == PINDIR_OUTPUT) { - AM_MEDIA_TYPE mt; - - hr = pPin->ConnectionMediaType(&mt); - - if (SUCCEEDED(hr)) { - DisplayType(TEXT("Connection type"), &mt); - - FreeMediaType(mt); - } - } - } else { - DbgLog((LOG_TRACE,dwLevel, - TEXT(" Pin [%x] '%ls' [%sput]"), - pPin, pinInfo.achName, - pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"))); - - } - } - - pPin->Release(); - - } - - pins->Release(); - } - - } - - pFilter->Release(); - } - - pFilters->Release(); - -} - -#endif - +//------------------------------------------------------------------------------ +// File: WXDebug.cpp +// +// Desc: DirectShow base classes - implements ActiveX system debugging +// facilities. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +//#define _WINDLL + +#include "streams.h" +#include +#include +#include + +#ifdef _DEBUG +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif // _UNICODE +#endif // UNICODE +#endif // DEBUG + +#include +#include + +#ifdef _DEBUG +static void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi); +static void DisplayRECT(LPCTSTR szLabel, const RECT& rc); + +// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. +// See the documentation for wsprintf()'s lpOut parameter for more information. +const INT iDEBUGINFO = 1024; // Used to format strings + +/* For every module and executable we store a debugging level for each of + the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy + to isolate and debug individual modules without seeing everybody elses + spurious debug output. The keys are stored in the registry under the + HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\ key values + NOTE these must be in the same order as their enumeration definition */ + +const LPCTSTR pKeyNames[] = { + TEXT("TIMING"), // Timing and performance measurements + TEXT("TRACE"), // General step point call tracing + TEXT("MEMORY"), // Memory and object allocation/destruction + TEXT("LOCKING"), // Locking/unlocking of critical sections + TEXT("ERROR"), // Debug error notification + TEXT("CUSTOM1"), + TEXT("CUSTOM2"), + TEXT("CUSTOM3"), + TEXT("CUSTOM4"), + TEXT("CUSTOM5") + }; + +const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s"); +const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s"); + +const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories + +HINSTANCE m_hInst; // Module instance handle +TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name +DWORD m_Levels[iMAXLEVELS]; // Debug level per category +CRITICAL_SECTION m_CSDebug; // Controls access to list +DWORD m_dwNextCookie; // Next active object ID +ObjectDesc *pListHead = NULL; // First active object +DWORD m_dwObjectCount; // Active object count +BOOL m_bInit = FALSE; // Have we been initialised +HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here +DWORD dwWaitTimeout = INFINITE; // Default timeout value +DWORD dwTimeOffset; // Time of first DbgLog call +bool g_fUseKASSERT = false; // don't create messagebox +bool g_fDbgInDllEntryPoint = false; +bool g_fAutoRefreshLevels = false; + +LPCTSTR pBaseKey = TEXT("SOFTWARE\\Microsoft\\DirectShow\\Debug"); +LPCTSTR pGlobalKey = TEXT("GLOBAL"); +static LPCSTR pUnknownName = "UNKNOWN"; + +LPCTSTR TimeoutName = TEXT("TIMEOUT"); + +/* This sets the instance handle that the debug library uses to find + the module's file name from the Win32 GetModuleFileName function */ + +void WINAPI DbgInitialise(HINSTANCE hInst) +{ + InitializeCriticalSection(&m_CSDebug); + m_bInit = TRUE; + + m_hInst = hInst; + DbgInitModuleName(); + if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0)) + DebugBreak(); + DbgInitModuleSettings(false); + DbgInitGlobalSettings(true); + dwTimeOffset = timeGetTime(); +} + + +/* This is called to clear up any resources the debug library uses - at the + moment we delete our critical section and the object list. The values we + retrieve from the registry are all done during initialisation but we don't + go looking for update notifications while we are running, if the values + are changed then the application has to be restarted to pick them up */ + +void WINAPI DbgTerminate() +{ + if (m_hOutput != INVALID_HANDLE_VALUE) { + EXECUTE_ASSERT(CloseHandle(m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + DeleteCriticalSection(&m_CSDebug); + m_bInit = FALSE; +} + + +/* This is called by DbgInitLogLevels to read the debug settings + for each logging category for this module from the registry */ + +void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax) +{ + LONG lReturn; // Create key return value + LONG lKeyPos; // Current key category + DWORD dwKeySize; // Size of the key value + DWORD dwKeyType; // Receives it's type + DWORD dwKeyValue; // This fields value + + /* Try and read a value for each key position in turn */ + for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) { + + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + pKeyNames[lKeyPos], // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwKeyValue, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + /* If either the key was not available or it was not a DWORD value + then we ensure only the high priority debug logging is output + but we try and update the field to a zero filled DWORD value */ + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { + + dwKeyValue = 0; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + pKeyNames[lKeyPos], // Address of subkey name + (DWORD) 0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE) &dwKeyValue, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); + dwKeyValue = 0; + } + } + if(fTakeMax) + { + m_Levels[lKeyPos] = std::max(dwKeyValue, m_Levels[lKeyPos]); + } + else + { + if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) { + m_Levels[lKeyPos] = dwKeyValue; + } + } + } + + /* Read the timeout value for catching hangs */ + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + TimeoutName, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwWaitTimeout, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + /* If either the key was not available or it was not a DWORD value + then we ensure only the high priority debug logging is output + but we try and update the field to a zero filled DWORD value */ + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { + + dwWaitTimeout = INFINITE; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + TimeoutName, // Address of subkey name + (DWORD) 0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE) &dwWaitTimeout, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); + dwWaitTimeout = INFINITE; + } + } +} + +void WINAPI DbgOutString(LPCTSTR psz) +{ + if (m_hOutput != INVALID_HANDLE_VALUE) { + UINT cb = lstrlen(psz); + DWORD dw; +#ifdef UNICODE + CHAR szDest[2048]; + WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0); + WriteFile (m_hOutput, szDest, cb, &dw, NULL); +#else + WriteFile (m_hOutput, psz, cb, &dw, NULL); +#endif + } else { + OutputDebugString (psz); + } +} + + + + +HRESULT DbgUniqueProcessName(LPCTSTR inName, LPTSTR outName) +{ + HRESULT hr = S_OK; + const TCHAR *pIn = inName; + int dotPos = -1; + + //scan the input and record the last '.' position + while (*pIn && (pIn - inName) < MAX_PATH) + { + if ( TEXT('.') == *pIn ) + dotPos = (int)(pIn-inName); + ++pIn; + } + + if (*pIn) //input should be zero-terminated within MAX_PATH + return E_INVALIDARG; + + DWORD dwProcessId = GetCurrentProcessId(); + + if (dotPos < 0) + { + //no extension in the input, appending process id to the input + hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d"), inName, dwProcessId); + } + else + { + TCHAR pathAndBasename[MAX_PATH] = {0}; + + //there's an extension - zero-terminate the path and basename first by copying + hr = StringCchCopyN(pathAndBasename, MAX_PATH, inName, (size_t)dotPos); + + //re-combine path, basename and extension with processId appended to a basename + if (SUCCEEDED(hr)) + hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d%s"), pathAndBasename, dwProcessId, inName + dotPos); + } + + return hr; +} + + +/* Called by DbgInitGlobalSettings to setup alternate logging destinations + */ + +void WINAPI DbgInitLogTo ( + HKEY hKey) +{ + LONG lReturn; + DWORD dwKeyType; + DWORD dwKeySize; + TCHAR szFile[MAX_PATH] = {0}; + static const TCHAR cszKey[] = TEXT("LogToFile"); + + dwKeySize = MAX_PATH; + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + cszKey, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) szFile, // Returns the field's value + &dwKeySize); // Number of bytes transferred + + // create an empty key if it does not already exist + // + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) + { + dwKeySize = sizeof(TCHAR); + lReturn = RegSetValueEx( + hKey, // Handle of an open key + cszKey, // Address of subkey name + (DWORD) 0, // Reserved field + REG_SZ, // Type of the key field + (PBYTE)szFile, // Value for the field + dwKeySize); // Size of the field buffer + } + + // if an output-to was specified. try to open it. + // + if (m_hOutput != INVALID_HANDLE_VALUE) { + EXECUTE_ASSERT(CloseHandle (m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + if (szFile[0] != 0) + { + if (!lstrcmpi(szFile, TEXT("Console"))) { + m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); + if (m_hOutput == INVALID_HANDLE_VALUE) { + AllocConsole (); + m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); + } + SetConsoleTitle (TEXT("ActiveX Debug Output")); + } else if (szFile[0] && + lstrcmpi(szFile, TEXT("Debug")) && + lstrcmpi(szFile, TEXT("Debugger")) && + lstrcmpi(szFile, TEXT("Deb"))) + { + m_hOutput = CreateFile(szFile, GENERIC_WRITE, + FILE_SHARE_READ, + NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (INVALID_HANDLE_VALUE == m_hOutput && + GetLastError() == ERROR_SHARING_VIOLATION) + { + TCHAR uniqueName[MAX_PATH] = {0}; + if (SUCCEEDED(DbgUniqueProcessName(szFile, uniqueName))) + { + m_hOutput = CreateFile(uniqueName, GENERIC_WRITE, + FILE_SHARE_READ, + NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + } + } + + if (INVALID_HANDLE_VALUE != m_hOutput) + { + static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); + LARGE_INTEGER zero = {0, 0}; + SetFilePointerEx(m_hOutput, zero, NULL, FILE_END); + DbgOutString (cszBar); + } + } + } +} + + + +/* This is called by DbgInitLogLevels to read the global debug settings for + each logging category for this module from the registry. Normally each + module has it's own values set for it's different debug categories but + setting the global SOFTWARE\Debug\Global applies them to ALL modules */ + +void WINAPI DbgInitGlobalSettings(bool fTakeMax) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hGlobalKey; // Global override key + + /* Construct the global base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey); + + /* Create or open the key for this module */ + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + GENERIC_READ | GENERIC_WRITE, // Desired security access + NULL, // Key security descriptor + &hGlobalKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) { + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + GENERIC_READ, // Desired security access + NULL, // Key security descriptor + &hGlobalKey, // Opened handle buffer + NULL); // What really happened + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,1,TEXT("Could not access GLOBAL module key"))); + } + return; + } + + DbgInitKeyLevels(hGlobalKey, fTakeMax); + RegCloseKey(hGlobalKey); +} + + +/* This sets the debugging log levels for the different categories. We start + by opening (or creating if not already available) the SOFTWARE\Debug key + that all these settings live under. We then look at the global values + set under SOFTWARE\Debug\Global which apply on top of the individual + module settings. We then load the individual module registry settings */ + +void WINAPI DbgInitModuleSettings(bool fTakeMax) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hModuleKey; // Module key handle + + /* Construct the base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,m_ModuleName); + + /* Create or open the key for this module */ + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + GENERIC_READ | GENERIC_WRITE, // Desired security access + NULL, // Key security descriptor + &hModuleKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) { + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + GENERIC_READ, // Desired security access + NULL, // Key security descriptor + &hModuleKey, // Opened handle buffer + NULL); // What really happened + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,1,TEXT("Could not access module key"))); + } + return; + } + + DbgInitLogTo(hModuleKey); + DbgInitKeyLevels(hModuleKey, fTakeMax); + RegCloseKey(hModuleKey); +} + + +/* Initialise the module file name */ + +void WINAPI DbgInitModuleName() +{ + TCHAR FullName[iDEBUGINFO]; // Load the full path and module name + LPTSTR pName; // Searches from the end for a backslash + + GetModuleFileName(m_hInst,FullName,iDEBUGINFO); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) { + pName = FullName; + } else { + pName++; + } + (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName); +} + +struct MsgBoxMsg +{ + HWND hwnd; + LPCTSTR szTitle; + LPCTSTR szMessage; + DWORD dwFlags; + INT iResult; +}; + +// +// create a thread to call MessageBox(). calling MessageBox() on +// random threads at bad times can confuse the host (eg IE). +// +DWORD WINAPI MsgBoxThread( + __inout LPVOID lpParameter // thread data + ) +{ + MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter; + pmsg->iResult = MessageBox( + pmsg->hwnd, + pmsg->szTitle, + pmsg->szMessage, + pmsg->dwFlags); + + return 0; +} + +INT MessageBoxOtherThread( + HWND hwnd, + LPCTSTR szTitle, + LPCTSTR szMessage, + DWORD dwFlags) +{ + if(g_fDbgInDllEntryPoint) + { + // can't wait on another thread because we have the loader + // lock held in the dll entry point. + // This can crash sometimes so just skip it + // return MessageBox(hwnd, szTitle, szMessage, dwFlags); + return IDCANCEL; + } + else + { + MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0}; + DWORD dwid; + HANDLE hThread = CreateThread( + 0, // security + 0, // stack size + MsgBoxThread, + (void *)&msg, // arg + 0, // flags + &dwid); + if(hThread) + { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + return msg.iResult; + } + + // break into debugger on failure. + return IDCANCEL; + } +} + +/* Displays a message box if the condition evaluated to FALSE */ + +void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine) +{ + if(g_fUseKASSERT) + { + DbgKernelAssert(pCondition, pFileName, iLine); + } + else + { + + TCHAR szInfo[iDEBUGINFO]; + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), + pCondition, iLine, pFileName); + + INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"), + MB_SYSTEMMODAL | + MB_ICONHAND | + MB_YESNOCANCEL | + MB_SETFOREGROUND); + switch (MsgId) + { + case IDNO: /* Kill the application */ + + FatalAppExit(FALSE, TEXT("Application terminated")); + break; + + case IDCANCEL: /* Break into the debugger */ + + DebugBreak(); + break; + + case IDYES: /* Ignore assertion continue execution */ + break; + } + } +} + +/* Displays a message box at a break point */ + +void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine) +{ + if(g_fUseKASSERT) + { + DbgKernelAssert(pCondition, pFileName, iLine); + } + else + { + TCHAR szInfo[iDEBUGINFO]; + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), + pCondition, iLine, pFileName); + + INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"), + MB_SYSTEMMODAL | + MB_ICONHAND | + MB_YESNOCANCEL | + MB_SETFOREGROUND); + switch (MsgId) + { + case IDNO: /* Kill the application */ + + FatalAppExit(FALSE, TEXT("Application terminated")); + break; + + case IDCANCEL: /* Break into the debugger */ + + DebugBreak(); + break; + + case IDYES: /* Ignore break point continue execution */ + break; + } + } +} + +void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...) +{ + // A debug break point message can have at most 2000 characters if + // ANSI or UNICODE characters are being used. A debug break point message + // can have between 1000 and 2000 double byte characters in it. If a + // particular message needs more characters, then the value of this constant + // should be increased. + const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000; + + TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE]; + + va_list va; + va_start( va, szFormatString ); + + HRESULT hr = StringCchVPrintf( szBreakPointMessage, NUMELMS(szBreakPointMessage), szFormatString, va ); + + va_end(va); + + if( FAILED(hr) ) { + DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because StringCchVPrintf() failed." ); + return; + } + + ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine ); +} + + +/* When we initialised the library we stored in the m_Levels array the current + debug output level for this module for each of the five categories. When + some debug logging is sent to us it can be sent with a combination of the + categories (if it is applicable to many for example) in which case we map + the type's categories into their current debug levels and see if any of + them can be accepted. The function looks at each bit position in turn from + the input type field and then compares it's debug level with the modules. + + A level of 0 means that output is always sent to the debugger. This is + due to producing output if the input level is <= m_Levels. +*/ + + +BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level) +{ + if(g_fAutoRefreshLevels) + { + // re-read the registry every second. We cannot use RegNotify() to + // notice registry changes because it's not available on win9x. + static DWORD g_dwLastRefresh = 0; + DWORD dwTime = timeGetTime(); + if(dwTime - g_dwLastRefresh > 1000) { + g_dwLastRefresh = dwTime; + + // there's a race condition: multiple threads could update the + // values. plus read and write not synchronized. no harm + // though. + DbgInitModuleSettings(false); + } + } + + + DWORD Mask = 0x01; + + // If no valid bits are set return FALSE + if ((Type & ((1<m_szName = szObjectName; + pObject->m_wszName = wszObjectName; + pObject->m_dwCookie = ++m_dwNextCookie; + pObject->m_pNext = pListHead; + + pListHead = pObject; + m_dwObjectCount++; + + DWORD ObjectCookie = pObject->m_dwCookie; + ASSERT(ObjectCookie); + + if(wszObjectName) { + DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"), + pObject->m_dwCookie, wszObjectName, m_dwObjectCount)); + } else { + DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"), + pObject->m_dwCookie, szObjectName, m_dwObjectCount)); + } + + LeaveCriticalSection(&m_CSDebug); + return ObjectCookie; +} + + +/* This is called by the CBaseObject destructor when an object is about to be + destroyed, we are passed the cookie we returned during construction that + identifies this object. We scan the object list for a matching cookie and + remove the object if successful. We also update the active object count */ + +BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie) +{ + /* Grab the list critical section */ + EnterCriticalSection(&m_CSDebug); + + ObjectDesc *pObject = pListHead; + ObjectDesc *pPrevious = NULL; + + /* Scan the object list looking for a cookie match */ + + while (pObject) { + if (pObject->m_dwCookie == dwCookie) { + break; + } + pPrevious = pObject; + pObject = pObject->m_pNext; + } + + if (pObject == NULL) { + DbgBreak("Apparently destroying a bogus object"); + LeaveCriticalSection(&m_CSDebug); + return FALSE; + } + + /* Is the object at the head of the list */ + + if (pPrevious == NULL) { + pListHead = pObject->m_pNext; + } else { + pPrevious->m_pNext = pObject->m_pNext; + } + + /* Delete the object and update the housekeeping information */ + + m_dwObjectCount--; + + if(pObject->m_wszName) { + DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"), + pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount)); + } else { + DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"), + pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount)); + } + + delete pObject; + LeaveCriticalSection(&m_CSDebug); + return TRUE; +} + + +/* This runs through the active object list displaying their details */ + +void WINAPI DbgDumpObjectRegister() +{ + TCHAR szInfo[iDEBUGINFO]; + + /* Grab the list critical section */ + + EnterCriticalSection(&m_CSDebug); + ObjectDesc *pObject = pListHead; + + /* Scan the object list displaying the name and cookie */ + + DbgLog((LOG_MEMORY,2,TEXT(""))); + DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description"))); + DbgLog((LOG_MEMORY,2,TEXT(""))); + + while (pObject) { + if(pObject->m_wszName) { + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30ls"),pObject->m_dwCookie, &pObject, pObject->m_wszName); + } else { + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30hs"),pObject->m_dwCookie, &pObject, pObject->m_szName); + } + DbgLog((LOG_MEMORY,2,szInfo)); + pObject = pObject->m_pNext; + } + + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount); + DbgLog((LOG_MEMORY,2,TEXT(""))); + DbgLog((LOG_MEMORY,1,szInfo)); + LeaveCriticalSection(&m_CSDebug); +} + +/* Debug infinite wait stuff */ +DWORD WINAPI DbgWaitForSingleObject(HANDLE h) +{ + DWORD dwWaitResult; + do { + dwWaitResult = WaitForSingleObject(h, dwWaitTimeout); + ASSERT(dwWaitResult == WAIT_OBJECT_0); + } while (dwWaitResult == WAIT_TIMEOUT); + return dwWaitResult; +} +DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, + __in_ecount(nCount) CONST HANDLE *lpHandles, + BOOL bWaitAll) +{ + DWORD dwWaitResult; + do { + dwWaitResult = WaitForMultipleObjects(nCount, + lpHandles, + bWaitAll, + dwWaitTimeout); + ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS); + } while (dwWaitResult == WAIT_TIMEOUT); + return dwWaitResult; +} + +void WINAPI DbgSetWaitTimeout(DWORD dwTimeout) +{ + dwWaitTimeout = dwTimeout; +} + +#endif /* DEBUG */ + +#ifdef _OBJBASE_H_ + + /* Stuff for printing out our GUID names */ + + constexpr GUID_STRING_ENTRY g_GuidNames[] = { + #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } }, + #include + }; + + CGuidNameList GuidNames; + int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]); + + LPCSTR CGuidNameList::operator [] (const GUID &guid) + { + for (int i = 0; i < g_cGuidNames; i++) { + if (g_GuidNames[i].guid == guid) { + return g_GuidNames[i].szName; + } + } + if (guid == GUID_NULL) { + return "GUID_NULL"; + } + + // !!! add something to print FOURCC guids? + + // shouldn't this print the hex CLSID? + return "Unknown GUID Name"; + } + +#endif /* _OBJBASE_H_ */ + +/* CDisp class - display our data types */ + +// clashes with REFERENCE_TIME +CDisp::CDisp(LONGLONG ll, int Format) +{ + // note: this could be combined with CDisp(LONGLONG) by + // introducing a default format of CDISP_REFTIME + LARGE_INTEGER li; + li.QuadPart = ll; + switch (Format) { + case CDISP_DEC: + { + TCHAR temp[20]; + int pos=20; + temp[--pos] = 0; + int digit; + // always output at least one digit + do { + // Get the rightmost digit - we only need the low word + digit = li.LowPart % 10; + li.QuadPart /= 10; + temp[--pos] = (TCHAR) digit+L'0'; + } while (li.QuadPart); + (void)StringCchCopy(m_String, NUMELMS(m_String), temp+pos); + break; + } + case CDISP_HEX: + default: + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart); + } +}; + +CDisp::CDisp(REFCLSID clsid) +{ +#ifdef UNICODE + (void)StringFromGUID2(clsid, m_String, NUMELMS(m_String)); +#else + WCHAR wszTemp[50]; + (void)StringFromGUID2(clsid, wszTemp, NUMELMS(wszTemp)); + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), wszTemp); +#endif +}; + +#ifdef __STREAMS__ +/* Display stuff */ +CDisp::CDisp(CRefTime llTime) +{ + LONGLONG llDiv; + if (llTime < 0) { + llTime = -llTime; + (void)StringCchCopy(m_String, NUMELMS(m_String), TEXT("-")); + } + llDiv = (LONGLONG)24 * 3600 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d days "), (LONG)(llTime / llDiv)); + llTime = llTime % llDiv; + } + llDiv = (LONGLONG)3600 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d hrs "), (LONG)(llTime / llDiv)); + llTime = llTime % llDiv; + } + llDiv = (LONGLONG)60 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d mins "), (LONG)(llTime / llDiv)); + llTime = llTime % llDiv; + } + (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d.%3.3d sec"), + (LONG)llTime / 10000000, + (LONG)((llTime % 10000000) / 10000)); +}; + +#endif // __STREAMS__ + + +/* Display pin */ +CDisp::CDisp(IPin *pPin) +{ + PIN_INFO pi; + TCHAR str[MAX_PIN_NAME]; + CLSID clsid; + + if (pPin) { + pPin->QueryPinInfo(&pi); + pi.pFilter->GetClassID(&clsid); + QueryPinInfoReleaseFilter(pi); + #ifndef UNICODE + WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1, + str, MAX_PIN_NAME, NULL, NULL); + #else + (void)StringCchCopy(str, NUMELMS(str), pi.achName); + #endif + } else { + (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin")); + } + + m_pString = (PTCHAR) new TCHAR[lstrlen(str)+64]; + if (!m_pString) { + return; + } + + (void)StringCchPrintf(m_pString, lstrlen(str) + 64, TEXT("%hs(%s)"), GuidNames[clsid], str); +} + +/* Display filter or pin */ +CDisp::CDisp(IUnknown *pUnk) +{ + IBaseFilter *pf; + HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf); + if(SUCCEEDED(hr)) + { + FILTER_INFO fi; + hr = pf->QueryFilterInfo(&fi); + if(SUCCEEDED(hr)) + { + QueryFilterInfoReleaseGraph(fi); + + size_t len = lstrlenW(fi.achName) + 1; + + m_pString = new TCHAR[len]; + if(m_pString) + { +#ifdef UNICODE + (void)StringCchCopy(m_pString, len, fi.achName); +#else + (void)StringCchPrintf(m_pString, len, "%S", fi.achName); +#endif + } + } + + pf->Release(); + + return; + } + + IPin *pp; + hr = pUnk->QueryInterface(IID_IPin, (void **)&pp); + if(SUCCEEDED(hr)) + { + CDisp::CDisp(pp); + pp->Release(); + return; + } +} + + +CDisp::~CDisp() +{ +} + +CDispBasic::~CDispBasic() +{ + if (m_pString != m_String) { + delete [] m_pString; + } +} + +CDisp::CDisp(double d) +{ + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000)); +} + + +/* If built for debug this will display the media type details. We convert the + major and subtypes into strings and also ask the base classes for a string + description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit + We also display the fields in the BITMAPINFOHEADER structure, this should + succeed as we do not accept input types unless the format is big enough */ + +#ifdef _DEBUG +void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn) +{ + + /* Dump the GUID types and a short description */ + + DbgLog((LOG_TRACE,5,TEXT(""))); + DbgLog((LOG_TRACE,2,TEXT("%s M type %hs S type %hs"), label, + GuidNames[pmtIn->majortype], + GuidNames[pmtIn->subtype])); + DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype))); + + /* Dump the generic media types */ + + if (pmtIn->bTemporalCompression) { + DbgLog((LOG_TRACE,5,TEXT("Temporally compressed"))); + } else { + DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed"))); + } + + if (pmtIn->bFixedSizeSamples) { + DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize)); + } else { + DbgLog((LOG_TRACE,5,TEXT("Variable size samples"))); + } + + if (pmtIn->formattype == FORMAT_VideoInfo) { + + VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat; + + DisplayRECT(TEXT("Source rectangle"),pVideoInfo->rcSource); + DisplayRECT(TEXT("Target rectangle"),pVideoInfo->rcTarget); + DisplayBITMAPINFO(HEADER(pmtIn->pbFormat)); + + } if (pmtIn->formattype == FORMAT_VideoInfo2) { + + VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pmtIn->pbFormat; + + DisplayRECT(TEXT("Source rectangle"),pVideoInfo2->rcSource); + DisplayRECT(TEXT("Target rectangle"),pVideoInfo2->rcTarget); + DbgLog((LOG_TRACE, 5, TEXT("Aspect Ratio: %d:%d"), + pVideoInfo2->dwPictAspectRatioX, + pVideoInfo2->dwPictAspectRatioY)); + DisplayBITMAPINFO(&pVideoInfo2->bmiHeader); + + } else if (pmtIn->majortype == MEDIATYPE_Audio) { + DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), + GuidNames[pmtIn->formattype])); + DbgLog((LOG_TRACE,2,TEXT(" Subtype %hs"), + GuidNames[pmtIn->subtype])); + + if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet) + && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT))) + { + /* Dump the contents of the WAVEFORMATEX type-specific format structure */ + + WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat; + DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag)); + DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels)); + DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec)); + DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec)); + DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign)); + DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample)); + + /* PCM uses a WAVEFORMAT and does not have the extra size field */ + + if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) { + DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize)); + } + } else { + } + + } else { + DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), + GuidNames[pmtIn->formattype])); + } +} + + +void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi) +{ + DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize)); + if (pbmi->biCompression < 256) { + DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit (%d)"), + pbmi->biWidth, pbmi->biHeight, + pbmi->biBitCount, pbmi->biCompression)); + } else { + DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"), + pbmi->biWidth, pbmi->biHeight, + pbmi->biBitCount, &pbmi->biCompression)); + } + + DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage)); + DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes)); + DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter)); + DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter)); + DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed)); +} + + +void DisplayRECT(LPCTSTR szLabel, const RECT& rc) +{ + DbgLog((LOG_TRACE,5,TEXT("%s (Left %d Top %d Right %d Bottom %d)"), + szLabel, + rc.left, + rc.top, + rc.right, + rc.bottom)); +} + + +void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel) +{ + if( !pGraph ) + { + return; + } + + IEnumFilters *pFilters; + + DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph)); + + if (FAILED(pGraph->EnumFilters(&pFilters))) { + DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!"))); + } + + IBaseFilter *pFilter; + ULONG n; + while (pFilters->Next(1, &pFilter, &n) == S_OK) { + FILTER_INFO info; + + if (FAILED(pFilter->QueryFilterInfo(&info))) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] -- failed QueryFilterInfo"), pFilter)); + } else { + QueryFilterInfoReleaseGraph(info); + + // !!! should QueryVendorInfo here! + + DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] '%ls'"), pFilter, info.achName)); + + IEnumPins *pins; + + if (FAILED(pFilter->EnumPins(&pins))) { + DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!"))); + } else { + + IPin *pPin; + while (pins->Next(1, &pPin, &n) == S_OK) { + PIN_INFO pinInfo; + + if (FAILED(pPin->QueryPinInfo(&pinInfo))) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin)); + } else { + QueryPinInfoReleaseFilter(pinInfo); + + IPin *pPinConnected = NULL; + + HRESULT hr = pPin->ConnectedTo(&pPinConnected); + + if (pPinConnected) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%p] '%ls' [%sput]") + TEXT(" Connected to pin [%p]"), + pPin, pinInfo.achName, + pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"), + pPinConnected)); + + pPinConnected->Release(); + + // perhaps we should really dump the type both ways as a sanity + // check? + if (pinInfo.dir == PINDIR_OUTPUT) { + AM_MEDIA_TYPE mt; + + hr = pPin->ConnectionMediaType(&mt); + + if (SUCCEEDED(hr)) { + DisplayType(TEXT("Connection type"), &mt); + + FreeMediaType(mt); + } + } + } else { + DbgLog((LOG_TRACE,dwLevel, + TEXT(" Pin [%x] '%ls' [%sput]"), + pPin, pinInfo.achName, + pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"))); + + } + } + + pPin->Release(); + + } + + pins->Release(); + } + + } + + pFilter->Release(); + } + + pFilters->Release(); + +} + +#endif + diff --git a/src/thirdparty/BaseClasses/wxdebug.h b/src/thirdparty/BaseClasses/wxdebug.h index be80d128de4..8c537901621 100644 --- a/src/thirdparty/BaseClasses/wxdebug.h +++ b/src/thirdparty/BaseClasses/wxdebug.h @@ -1,359 +1,359 @@ -//------------------------------------------------------------------------------ -// File: WXDebug.h -// -// Desc: DirectShow base classes - provides debugging facilities. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __WXDEBUG__ -#define __WXDEBUG__ - -// This library provides fairly straight forward debugging functionality, this -// is split into two main sections. The first is assertion handling, there are -// three types of assertions provided here. The most commonly used one is the -// ASSERT(condition) macro which will pop up a message box including the file -// and line number if the condition evaluates to FALSE. Then there is the -// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will -// still be executed in NON debug builds. The final type of assertion is the -// KASSERT macro which is more suitable for pure (perhaps kernel) filters as -// the condition is printed onto the debugger rather than in a message box. -// -// The other part of the debug module facilties is general purpose logging. -// This is accessed by calling DbgLog(). The function takes a type and level -// field which define the type of informational string you are presenting and -// it's relative importance. The type field can be a combination (one or more) -// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level -// is a DWORD value where zero defines highest important. Use of zero as the -// debug logging level is to be encouraged ONLY for major errors or events as -// they will ALWAYS be displayed on the debugger. Other debug output has it's -// level matched against the current debug output level stored in the registry -// for this module and if less than the current setting it will be displayed. -// -// Each module or executable has it's own debug output level for each of the -// five types. These are read in when the DbgInitialise function is called -// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL -// is loaded, executables must call it explicitely with the module instance -// handle given to them through the WINMAIN entry point. An executable must -// also call DbgTerminate when they have finished to clean up the resources -// the debug library uses, once again this is done automatically for DLLs - -// These are the five different categories of logging information - -enum { LOG_TIMING = 0x01, // Timing and performance measurements - LOG_TRACE = 0x02, // General step point call tracing - LOG_MEMORY = 0x04, // Memory and object allocation/destruction - LOG_LOCKING = 0x08, // Locking/unlocking of critical sections - LOG_ERROR = 0x10, // Debug error notification - LOG_CUSTOM1 = 0x20, - LOG_CUSTOM2 = 0x40, - LOG_CUSTOM3 = 0x80, - LOG_CUSTOM4 = 0x100, - LOG_CUSTOM5 = 0x200, -}; - -#define LOG_FORCIBLY_SET 0x80000000 - -enum { CDISP_HEX = 0x01, - CDISP_DEC = 0x02}; - -// For each object created derived from CBaseObject (in debug builds) we -// create a descriptor that holds it's name (statically allocated memory) -// and a cookie we assign it. We keep a list of all the active objects -// we have registered so that we can dump a list of remaining objects - -typedef struct tag_ObjectDesc { - LPCSTR m_szName; - LPCWSTR m_wszName; - DWORD m_dwCookie; - tag_ObjectDesc *m_pNext; -} ObjectDesc; - -#define DLLIMPORT __declspec(dllimport) -#define DLLEXPORT __declspec(dllexport) - -#ifdef _DEBUG - - #define NAME(x) TEXT(x) - - // These are used internally by the debug library (PRIVATE) - - void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax); - void WINAPI DbgInitGlobalSettings(bool fTakeMax); - void WINAPI DbgInitModuleSettings(bool fTakeMax); - void WINAPI DbgInitModuleName(); - DWORD WINAPI DbgRegisterObjectCreation( - LPCSTR szObjectName, LPCWSTR wszObjectName); - - BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie); - - // These are the PUBLIC entry points - - BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level); - void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level); - void WINAPI DbgSetAutoRefreshLevels(bool fAuto); - - // Initialise the library with the module handle - - void WINAPI DbgInitialise(HINSTANCE hInst); - void WINAPI DbgTerminate(); - - void WINAPI DbgDumpObjectRegister(); - - // Display error and logging to the user - - void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); - void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); - void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...); - - void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); - void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCTSTR pFormat,...); -#ifdef UNICODE - void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...); - void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); - void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine); - void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); -#endif - void WINAPI DbgOutString(LPCTSTR psz); - - // Debug infinite wait stuff - DWORD WINAPI DbgWaitForSingleObject(HANDLE h); - DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, - __in_ecount(nCount) CONST HANDLE *lpHandles, - BOOL bWaitAll); - void WINAPI DbgSetWaitTimeout(DWORD dwTimeout); - -#ifdef __strmif_h__ - // Display a media type: Terse at level 2, verbose at level 5 - void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn); - - // Dump lots of information about a filter graph - void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel); -#endif - - #define KASSERT(_x_) if (!(_x_)) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - // Break on the debugger without putting up a message box - // message goes to debugger instead - - #define KDbgBreak(_x_) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - // We chose a common name for our ASSERT macro, MFC also uses this name - // So long as the implementation evaluates the condition and handles it - // then we will be ok. Rather than override the behaviour expected we - // will leave whatever first defines ASSERT as the handler (i.e. MFC) - #ifndef ASSERT - #define ASSERT(_x_) if (!(_x_)) \ - DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - #endif - - #define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0) - - // Put up a message box informing the user of a halt - // condition in the program - - #define DbgBreak(_x_) \ - DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - #define EXECUTE_ASSERT(_x_) ASSERT(_x_) - #define DbgLog(_x_) DbgLogInfo _x_ - // MFC style trace macros - - #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))) - #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)) - #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)) - #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)) - #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)) - #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)) - -#else - - // Retail builds make public debug functions inert - WARNING the source - // files do not define or build any of the entry points in debug builds - // (public entry points compile to nothing) so if you go trying to call - // any of the private entry points in your source they won't compile - - #define NAME(_x_) ((LPTSTR) NULL) - - #define DbgInitialise(hInst) - #define DbgTerminate() - #define DbgLog(_x_) 0 - #define DbgOutString(psz) - #define DbgAssertAligned( _ptr_, _alignment_ ) 0 - - #define DbgRegisterObjectCreation(pObjectName) - #define DbgRegisterObjectDestruction(dwCookie) - #define DbgDumpObjectRegister() - - #define DbgCheckModuleLevel(Type,Level) - #define DbgSetModuleLevel(Type,Level) - #define DbgSetAutoRefreshLevels(fAuto) - - #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) - #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ - WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) - #define DbgSetWaitTimeout(dwTimeout) - - #define KDbgBreak(_x_) - #define DbgBreak(_x_) - - #define KASSERT(_x_) ((void)0) - #ifndef ASSERT - #define ASSERT(_x_) ((void)0) - #endif - #define EXECUTE_ASSERT(_x_) ((void)(_x_)) - - // MFC style trace macros - - #define NOTE(_x_) ((void)0) - #define NOTE1(_x_,a) ((void)0) - #define NOTE2(_x_,a,b) ((void)0) - #define NOTE3(_x_,a,b,c) ((void)0) - #define NOTE4(_x_,a,b,c,d) ((void)0) - #define NOTE5(_x_,a,b,c,d,e) ((void)0) - - #define DisplayType(label, pmtIn) ((void)0) - #define DumpGraph(pGraph, label) ((void)0) -#endif - - -// Checks a pointer which should be non NULL - can be used as follows. - -#define CheckPointer(p,ret) {if((p)==NULL) return (ret);} - -// HRESULT Foo(VOID *pBar) -// { -// CheckPointer(pBar,E_INVALIDARG) -// } -// -// Or if the function returns a boolean -// -// BOOL Foo(VOID *pBar) -// { -// CheckPointer(pBar,FALSE) -// } - -#define ValidateReadPtr(p,cb) 0 -#define ValidateWritePtr(p,cb) 0 -#define ValidateReadWritePtr(p,cb) 0 -#define ValidateStringPtr(p) 0 -#define ValidateStringPtrA(p) 0 -#define ValidateStringPtrW(p) 0 - - -#ifdef _OBJBASE_H_ - - // Outputting GUID names. If you want to include the name - // associated with a GUID (eg CLSID_...) then - // - // GuidNames[yourGUID] - // - // Returns the name defined in uuids.h as a string - - typedef struct { - LPCSTR szName; - GUID guid; - } GUID_STRING_ENTRY; - - class CGuidNameList { - public: - LPCSTR operator [] (const GUID& guid); - }; - - extern CGuidNameList GuidNames; - -#endif - -#ifndef REMIND - // REMIND macro - generates warning as reminder to complete coding - // (eg) usage: - // - // #pragma message (REMIND("Add automation support")) - - - #define QUOTE(x) #x - #define QQUOTE(y) QUOTE(y) - #define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str -#endif - -// Method to display objects in a useful format -// -// eg If you want to display a LONGLONG ll in a debug string do (eg) -// -// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); - - -class CDispBasic -{ -public: - CDispBasic() { m_pString = m_String; }; - ~CDispBasic(); -protected: - PTCHAR m_pString; // normally points to m_String... unless too much data - TCHAR m_String[50]; -}; -class CDisp : public CDispBasic -{ -public: - CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form - CDisp(REFCLSID clsid); // Display a GUID - CDisp(double d); // Display a floating point number -#ifdef __strmif_h__ -#ifdef __STREAMS__ - CDisp(CRefTime t); // Display a Reference Time -#endif - CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) - CDisp(IUnknown *pUnk); // Display a filter or pin -#endif // __strmif_h__ - ~CDisp(); - - // Implement cast to (LPCTSTR) as parameter to logger - operator LPCTSTR() - { - return (LPCTSTR)m_pString; - }; -}; - - -#if defined(DEBUG) -class CAutoTrace -{ -private: - LPCTSTR _szBlkName; - const int _level; - static const TCHAR _szEntering[]; - static const TCHAR _szLeaving[]; -public: - CAutoTrace(LPCTSTR szBlkName, const int level = 15) - : _szBlkName(szBlkName), _level(level) - {DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} - - ~CAutoTrace() - {DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} -}; - -#if defined (__FUNCTION__) - -#define AMTRACEFN() CAutoTrace __trace(TEXT(__FUNCTION__)) -#define AMTRACE(_x_) CAutoTrace __trace(TEXT(__FUNCTION__)) - -#else - -#define AMTRACE(_x_) CAutoTrace __trace _x_ -#define AMTRACEFN() - -#endif - -#else - -#define AMTRACE(_x_) -#define AMTRACEFN() - -#endif - -#endif // __WXDEBUG__ - - +//------------------------------------------------------------------------------ +// File: WXDebug.h +// +// Desc: DirectShow base classes - provides debugging facilities. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WXDEBUG__ +#define __WXDEBUG__ + +// This library provides fairly straight forward debugging functionality, this +// is split into two main sections. The first is assertion handling, there are +// three types of assertions provided here. The most commonly used one is the +// ASSERT(condition) macro which will pop up a message box including the file +// and line number if the condition evaluates to FALSE. Then there is the +// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will +// still be executed in NON debug builds. The final type of assertion is the +// KASSERT macro which is more suitable for pure (perhaps kernel) filters as +// the condition is printed onto the debugger rather than in a message box. +// +// The other part of the debug module facilties is general purpose logging. +// This is accessed by calling DbgLog(). The function takes a type and level +// field which define the type of informational string you are presenting and +// it's relative importance. The type field can be a combination (one or more) +// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level +// is a DWORD value where zero defines highest important. Use of zero as the +// debug logging level is to be encouraged ONLY for major errors or events as +// they will ALWAYS be displayed on the debugger. Other debug output has it's +// level matched against the current debug output level stored in the registry +// for this module and if less than the current setting it will be displayed. +// +// Each module or executable has it's own debug output level for each of the +// five types. These are read in when the DbgInitialise function is called +// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL +// is loaded, executables must call it explicitely with the module instance +// handle given to them through the WINMAIN entry point. An executable must +// also call DbgTerminate when they have finished to clean up the resources +// the debug library uses, once again this is done automatically for DLLs + +// These are the five different categories of logging information + +enum { LOG_TIMING = 0x01, // Timing and performance measurements + LOG_TRACE = 0x02, // General step point call tracing + LOG_MEMORY = 0x04, // Memory and object allocation/destruction + LOG_LOCKING = 0x08, // Locking/unlocking of critical sections + LOG_ERROR = 0x10, // Debug error notification + LOG_CUSTOM1 = 0x20, + LOG_CUSTOM2 = 0x40, + LOG_CUSTOM3 = 0x80, + LOG_CUSTOM4 = 0x100, + LOG_CUSTOM5 = 0x200, +}; + +#define LOG_FORCIBLY_SET 0x80000000 + +enum { CDISP_HEX = 0x01, + CDISP_DEC = 0x02}; + +// For each object created derived from CBaseObject (in debug builds) we +// create a descriptor that holds it's name (statically allocated memory) +// and a cookie we assign it. We keep a list of all the active objects +// we have registered so that we can dump a list of remaining objects + +typedef struct tag_ObjectDesc { + LPCSTR m_szName; + LPCWSTR m_wszName; + DWORD m_dwCookie; + tag_ObjectDesc *m_pNext; +} ObjectDesc; + +#define DLLIMPORT __declspec(dllimport) +#define DLLEXPORT __declspec(dllexport) + +#ifdef _DEBUG + + #define NAME(x) TEXT(x) + + // These are used internally by the debug library (PRIVATE) + + void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax); + void WINAPI DbgInitGlobalSettings(bool fTakeMax); + void WINAPI DbgInitModuleSettings(bool fTakeMax); + void WINAPI DbgInitModuleName(); + DWORD WINAPI DbgRegisterObjectCreation( + LPCSTR szObjectName, LPCWSTR wszObjectName); + + BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie); + + // These are the PUBLIC entry points + + BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level); + void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level); + void WINAPI DbgSetAutoRefreshLevels(bool fAuto); + + // Initialise the library with the module handle + + void WINAPI DbgInitialise(HINSTANCE hInst); + void WINAPI DbgTerminate(); + + void WINAPI DbgDumpObjectRegister(); + + // Display error and logging to the user + + void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); + void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); + void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...); + + void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); + void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCTSTR pFormat,...); +#ifdef UNICODE + void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...); + void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); + void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine); + void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); +#endif + void WINAPI DbgOutString(LPCTSTR psz); + + // Debug infinite wait stuff + DWORD WINAPI DbgWaitForSingleObject(HANDLE h); + DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, + __in_ecount(nCount) CONST HANDLE *lpHandles, + BOOL bWaitAll); + void WINAPI DbgSetWaitTimeout(DWORD dwTimeout); + +#ifdef __strmif_h__ + // Display a media type: Terse at level 2, verbose at level 5 + void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn); + + // Dump lots of information about a filter graph + void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel); +#endif + + #define KASSERT(_x_) if (!(_x_)) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // Break on the debugger without putting up a message box + // message goes to debugger instead + + #define KDbgBreak(_x_) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // We chose a common name for our ASSERT macro, MFC also uses this name + // So long as the implementation evaluates the condition and handles it + // then we will be ok. Rather than override the behaviour expected we + // will leave whatever first defines ASSERT as the handler (i.e. MFC) + #ifndef ASSERT + #define ASSERT(_x_) if (!(_x_)) \ + DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + #endif + + #define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0) + + // Put up a message box informing the user of a halt + // condition in the program + + #define DbgBreak(_x_) \ + DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + #define EXECUTE_ASSERT(_x_) ASSERT(_x_) + #define DbgLog(_x_) DbgLogInfo _x_ + // MFC style trace macros + + #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))) + #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)) + #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)) + #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)) + #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)) + #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)) + +#else + + // Retail builds make public debug functions inert - WARNING the source + // files do not define or build any of the entry points in debug builds + // (public entry points compile to nothing) so if you go trying to call + // any of the private entry points in your source they won't compile + + #define NAME(_x_) ((LPTSTR) NULL) + + #define DbgInitialise(hInst) + #define DbgTerminate() + #define DbgLog(_x_) 0 + #define DbgOutString(psz) + #define DbgAssertAligned( _ptr_, _alignment_ ) 0 + + #define DbgRegisterObjectCreation(pObjectName) + #define DbgRegisterObjectDestruction(dwCookie) + #define DbgDumpObjectRegister() + + #define DbgCheckModuleLevel(Type,Level) + #define DbgSetModuleLevel(Type,Level) + #define DbgSetAutoRefreshLevels(fAuto) + + #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) + #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ + WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) + #define DbgSetWaitTimeout(dwTimeout) + + #define KDbgBreak(_x_) + #define DbgBreak(_x_) + + #define KASSERT(_x_) ((void)0) + #ifndef ASSERT + #define ASSERT(_x_) ((void)0) + #endif + #define EXECUTE_ASSERT(_x_) ((void)(_x_)) + + // MFC style trace macros + + #define NOTE(_x_) ((void)0) + #define NOTE1(_x_,a) ((void)0) + #define NOTE2(_x_,a,b) ((void)0) + #define NOTE3(_x_,a,b,c) ((void)0) + #define NOTE4(_x_,a,b,c,d) ((void)0) + #define NOTE5(_x_,a,b,c,d,e) ((void)0) + + #define DisplayType(label, pmtIn) ((void)0) + #define DumpGraph(pGraph, label) ((void)0) +#endif + + +// Checks a pointer which should be non NULL - can be used as follows. + +#define CheckPointer(p,ret) {if((p)==NULL) return (ret);} + +// HRESULT Foo(VOID *pBar) +// { +// CheckPointer(pBar,E_INVALIDARG) +// } +// +// Or if the function returns a boolean +// +// BOOL Foo(VOID *pBar) +// { +// CheckPointer(pBar,FALSE) +// } + +#define ValidateReadPtr(p,cb) 0 +#define ValidateWritePtr(p,cb) 0 +#define ValidateReadWritePtr(p,cb) 0 +#define ValidateStringPtr(p) 0 +#define ValidateStringPtrA(p) 0 +#define ValidateStringPtrW(p) 0 + + +#ifdef _OBJBASE_H_ + + // Outputting GUID names. If you want to include the name + // associated with a GUID (eg CLSID_...) then + // + // GuidNames[yourGUID] + // + // Returns the name defined in uuids.h as a string + + typedef struct { + LPCSTR szName; + GUID guid; + } GUID_STRING_ENTRY; + + class CGuidNameList { + public: + LPCSTR operator [] (const GUID& guid); + }; + + extern CGuidNameList GuidNames; + +#endif + +#ifndef REMIND + // REMIND macro - generates warning as reminder to complete coding + // (eg) usage: + // + // #pragma message (REMIND("Add automation support")) + + + #define QUOTE(x) #x + #define QQUOTE(y) QUOTE(y) + #define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str +#endif + +// Method to display objects in a useful format +// +// eg If you want to display a LONGLONG ll in a debug string do (eg) +// +// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); + + +class CDispBasic +{ +public: + CDispBasic() { m_pString = m_String; }; + ~CDispBasic(); +protected: + PTCHAR m_pString; // normally points to m_String... unless too much data + TCHAR m_String[50]; +}; +class CDisp : public CDispBasic +{ +public: + CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form + CDisp(REFCLSID clsid); // Display a GUID + CDisp(double d); // Display a floating point number +#ifdef __strmif_h__ +#ifdef __STREAMS__ + CDisp(CRefTime t); // Display a Reference Time +#endif + CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) + CDisp(IUnknown *pUnk); // Display a filter or pin +#endif // __strmif_h__ + ~CDisp(); + + // Implement cast to (LPCTSTR) as parameter to logger + operator LPCTSTR() + { + return (LPCTSTR)m_pString; + }; +}; + + +#if defined(DEBUG) +class CAutoTrace +{ +private: + LPCTSTR _szBlkName; + const int _level; + static const TCHAR _szEntering[]; + static const TCHAR _szLeaving[]; +public: + CAutoTrace(LPCTSTR szBlkName, const int level = 15) + : _szBlkName(szBlkName), _level(level) + {DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} + + ~CAutoTrace() + {DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} +}; + +#if defined (__FUNCTION__) + +#define AMTRACEFN() CAutoTrace __trace(TEXT(__FUNCTION__)) +#define AMTRACE(_x_) CAutoTrace __trace(TEXT(__FUNCTION__)) + +#else + +#define AMTRACE(_x_) CAutoTrace __trace _x_ +#define AMTRACEFN() + +#endif + +#else + +#define AMTRACE(_x_) +#define AMTRACEFN() + +#endif + +#endif // __WXDEBUG__ + + diff --git a/src/thirdparty/BaseClasses/wxlist.cpp b/src/thirdparty/BaseClasses/wxlist.cpp index 5b697cdc5f8..cf9631824bf 100644 --- a/src/thirdparty/BaseClasses/wxlist.cpp +++ b/src/thirdparty/BaseClasses/wxlist.cpp @@ -1,891 +1,891 @@ -//------------------------------------------------------------------------------ -// File: WXList.cpp -// -// Desc: DirectShow base classes - implements a non-MFC based generic list -// template class. -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* A generic list of pointers to objects. - Objectives: avoid using MFC libraries in ndm kernel mode and - provide a really useful list type. - - The class is thread safe in that separate threads may add and - delete items in the list concurrently although the application - must ensure that constructor and destructor access is suitably - synchronised. - - The list name must not conflict with MFC classes as an - application may use both - - The nodes form a doubly linked, NULL terminated chain with an anchor - block (the list object per se) holding pointers to the first and last - nodes and a count of the nodes. - There is a node cache to reduce the allocation and freeing overhead. - It optionally (determined at construction time) has an Event which is - set whenever the list becomes non-empty and reset whenever it becomes - empty. - It optionally (determined at construction time) has a Critical Section - which is entered during the important part of each operation. (About - all you can do outside it is some parameter checking). - - The node cache is a repository of nodes that are NOT in the list to speed - up storage allocation. Each list has its own cache to reduce locking and - serialising. The list accesses are serialised anyway for a given list - a - common cache would mean that we would have to separately serialise access - of all lists within the cache. Because the cache only stores nodes that are - not in the list, releasing the cache does not release any list nodes. This - means that list nodes can be copied or rechained from one list to another - without danger of creating a dangling reference if the original cache goes - away. - - Questionable design decisions: - 1. Retaining the warts for compatibility - 2. Keeping an element count -i.e. counting whenever we do anything - instead of only when we want the count. - 3. Making the chain pointers NULL terminated. If the list object - itself looks just like a node and the list is kept as a ring then - it reduces the number of special cases. All inserts look the same. -*/ - - -#include "streams.h" - -/* set cursor to the position of each element of list in turn */ -#define INTERNALTRAVERSELIST(list, cursor) \ -for ( cursor = (list).GetHeadPositionI() \ - ; cursor!=NULL \ - ; cursor = (list).Next(cursor) \ - ) - - -/* set cursor to the position of each element of list in turn - in reverse order -*/ -#define INTERNALREVERSETRAVERSELIST(list, cursor) \ -for ( cursor = (list).GetTailPositionI() \ - ; cursor!=NULL \ - ; cursor = (list).Prev(cursor) \ - ) - -/* Constructor calls a separate initialisation function that - creates a node cache, optionally creates a lock object - and optionally creates a signaling object. - - By default we create a locking object, a DEFAULTCACHE sized - cache but no event object so the list cannot be used in calls - to WaitForSingleObject -*/ -CBaseList::CBaseList(__in_opt LPCTSTR pName, // Descriptive list name - INT iItems) : // Node cache size -#ifdef _DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(iItems) -{ -} // constructor - -CBaseList::CBaseList(__in_opt LPCTSTR pName) : // Descriptive list name -#ifdef _DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(DEFAULTCACHE) -{ -} // constructor - -#ifdef UNICODE -CBaseList::CBaseList(__in_opt LPCSTR pName, // Descriptive list name - INT iItems) : // Node cache size -#ifdef _DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(iItems) -{ -} // constructor - -CBaseList::CBaseList(__in_opt LPCSTR pName) : // Descriptive list name -#ifdef _DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(DEFAULTCACHE) -{ -} // constructor - -#endif - -/* The destructor enumerates all the node objects in the list and - in the cache deleting each in turn. We do not do any processing - on the objects that the list holds (i.e. points to) so if they - represent interfaces for example the creator of the list should - ensure that each of them is released before deleting us -*/ -CBaseList::~CBaseList() -{ - /* Delete all our list nodes */ - - RemoveAll(); - -} // destructor - -/* Remove all the nodes from the list but don't do anything - with the objects that each node looks after (this is the - responsibility of the creator). - Aa a last act we reset the signalling event - (if available) to indicate to clients that the list - does not have any entries in it. -*/ -void CBaseList::RemoveAll() -{ - /* Free up all the CNode objects NOTE we don't bother putting the - deleted nodes into the cache as this method is only really called - in serious times of change such as when we are being deleted at - which point the cache will be deleted anway */ - - CNode *pn = m_pFirst; - while (pn) { - CNode *op = pn; - pn = pn->Next(); - delete op; - } - - /* Reset the object count and the list pointers */ - - m_Count = 0; - m_pFirst = m_pLast = NULL; - -} // RemoveAll - - - -/* Return a position enumerator for the entire list. - A position enumerator is a pointer to a node object cast to a - transparent type so all we do is return the head/tail node - pointer in the list. - WARNING because the position is a pointer to a node there is - an implicit assumption for users a the list class that after - deleting an object from the list that any other position - enumerators that you have may be invalid (since the node - may be gone). -*/ -__out_opt POSITION CBaseList::GetHeadPositionI() const -{ - return (POSITION) m_pFirst; -} // GetHeadPosition - - - -__out_opt POSITION CBaseList::GetTailPositionI() const -{ - return (POSITION) m_pLast; -} // GetTailPosition - - - -/* Get the number of objects in the list, - Get the lock before accessing the count. - Locking may not be entirely necessary but it has the side effect - of making sure that all operations are complete before we get it. - So for example if a list is being added to this list then that - will have completed in full before we continue rather than seeing - an intermediate albeit valid state -*/ -int CBaseList::GetCountI() const -{ - return m_Count; -} // GetCount - - - -/* Return the object at rp, update rp to the next object from - the list or NULL if you have moved over the last object. - You may still call this function once we return NULL but - we will continue to return a NULL position value -*/ -__out void *CBaseList::GetNextI(__inout POSITION& rp) const -{ - /* have we reached the end of the list */ - - if (rp == NULL) { - return NULL; - } - - /* Lock the object before continuing */ - - void *pObject; - - /* Copy the original position then step on */ - - CNode *pn = (CNode *) rp; - ASSERT(pn != NULL); - rp = (POSITION) pn->Next(); - - /* Get the object at the original position from the list */ - - pObject = pn->GetData(); - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - return pObject; -} //GetNext - - - -/* Return the object at p. - Asking for the object at NULL ASSERTs then returns NULL - The object is NOT locked. The list is not being changed - in any way. If another thread is busy deleting the object - then locking would only result in a change from one bad - behaviour to another. -*/ -__out_opt void *CBaseList::GetI(__in_opt POSITION p) const -{ - if (p == NULL) { - return NULL; - } - - CNode * pn = (CNode *) p; - void *pObject = pn->GetData(); - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - return pObject; -} //Get - -__out void *CBaseList::GetValidI(__in POSITION p) const -{ - CNode * pn = (CNode *) p; - void *pObject = pn->GetData(); - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - return pObject; -} //Get - - -/* Return the first position in the list which holds the given pointer. - Return NULL if it's not found. -*/ -__out_opt POSITION CBaseList::FindI( __in void * pObj) const -{ - POSITION pn; - INTERNALTRAVERSELIST(*this, pn){ - if (GetI(pn)==pObj) { - return pn; - } - } - return NULL; -} // Find - - - -/* Remove the first node in the list (deletes the pointer to its object - from the list, does not free the object itself). - Return the pointer to its object or NULL if empty -*/ -__out_opt void *CBaseList::RemoveHeadI() -{ - /* All we do is get the head position and ask for that to be deleted. - We could special case this since some of the code path checking - in Remove() is redundant as we know there is no previous - node for example but it seems to gain little over the - added complexity - */ - - return RemoveI((POSITION)m_pFirst); -} // RemoveHead - - - -/* Remove the last node in the list (deletes the pointer to its object - from the list, does not free the object itself). - Return the pointer to its object or NULL if empty -*/ -__out_opt void *CBaseList::RemoveTailI() -{ - /* All we do is get the tail position and ask for that to be deleted. - We could special case this since some of the code path checking - in Remove() is redundant as we know there is no previous - node for example but it seems to gain little over the - added complexity - */ - - return RemoveI((POSITION)m_pLast); -} // RemoveTail - - - -/* Remove the pointer to the object in this position from the list. - Deal with all the chain pointers - Return a pointer to the object removed from the list. - The node object that is freed as a result - of this operation is added to the node cache where - it can be used again. - Remove(NULL) is a harmless no-op - but probably is a wart. -*/ -__out_opt void *CBaseList::RemoveI(__in_opt POSITION pos) -{ - /* Lock the critical section before continuing */ - - // ASSERT (pos!=NULL); // Removing NULL is to be harmless! - if (pos==NULL) return NULL; - - - CNode *pCurrent = (CNode *) pos; - ASSERT(pCurrent != NULL); - - /* Update the previous node */ - - CNode *pNode = pCurrent->Prev(); - if (pNode == NULL) { - m_pFirst = pCurrent->Next(); - } else { - pNode->SetNext(pCurrent->Next()); - } - - /* Update the following node */ - - pNode = pCurrent->Next(); - if (pNode == NULL) { - m_pLast = pCurrent->Prev(); - } else { - pNode->SetPrev(pCurrent->Prev()); - } - - /* Get the object this node was looking after */ - - void *pObject = pCurrent->GetData(); - - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - - /* Try and add the node object to the cache - - a NULL return code from the cache means we ran out of room. - The cache size is fixed by a constructor argument when the - list is created and defaults to DEFAULTCACHE. - This means that the cache will have room for this many - node objects. So if you have a list of media samples - and you know there will never be more than five active at - any given time of them for example then override the default - constructor - */ - - m_Cache.AddToCache(pCurrent); - - /* If the list is empty then reset the list event */ - - --m_Count; - ASSERT(m_Count >= 0); - return pObject; -} // Remove - - - -/* Add this object to the tail end of our list - Return the new tail position. -*/ - -__out_opt POSITION CBaseList::AddTailI(__in void *pObject) -{ - /* Lock the critical section before continuing */ - - CNode *pNode; - // ASSERT(pObject); // NULL pointers in the list are allowed. - - /* If there is a node objects in the cache then use - that otherwise we will have to create a new one */ - - pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObject); - pNode->SetNext(NULL); - pNode->SetPrev(m_pLast); - - if (m_pLast == NULL) { - m_pFirst = pNode; - } else { - m_pLast->SetNext(pNode); - } - - /* Set the new last node pointer and also increment the number - of list entries, the critical section is unlocked when we - exit the function - */ - - m_pLast = pNode; - ++m_Count; - - return (POSITION) pNode; -} // AddTail(object) - - - -/* Add this object to the head end of our list - Return the new head position. -*/ -__out_opt POSITION CBaseList::AddHeadI(__in void *pObject) -{ - CNode *pNode; - // ASSERT(pObject); // NULL pointers in the list are allowed. - - /* If there is a node objects in the cache then use - that otherwise we will have to create a new one */ - - pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObject); - - /* chain it in (set four pointers) */ - pNode->SetPrev(NULL); - pNode->SetNext(m_pFirst); - - if (m_pFirst == NULL) { - m_pLast = pNode; - } else { - m_pFirst->SetPrev(pNode); - } - m_pFirst = pNode; - - ++m_Count; - - return (POSITION) pNode; -} // AddHead(object) - - - -/* Add all the elements in *pList to the tail of this list. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. -*/ -BOOL CBaseList::AddTail(__in CBaseList *pList) -{ - /* lock the object before starting then enumerate - each entry in the source list and add them one by one to - our list (while still holding the object lock) - Lock the other list too. - */ - POSITION pos = pList->GetHeadPositionI(); - - while (pos) { - if (NULL == AddTailI(pList->GetNextI(pos))) { - return FALSE; - } - } - return TRUE; -} // AddTail(list) - - - -/* Add all the elements in *pList to the head of this list. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. -*/ -BOOL CBaseList::AddHead(__in CBaseList *pList) -{ - /* lock the object before starting then enumerate - each entry in the source list and add them one by one to - our list (while still holding the object lock) - Lock the other list too. - - To avoid reversing the list, traverse it backwards. - */ - - POSITION pos; - - INTERNALREVERSETRAVERSELIST(*pList, pos) { - if (NULL== AddHeadI(pList->GetValidI(pos))){ - return FALSE; - } - } - return TRUE; -} // AddHead(list) - - - -/* Add the object after position p - p is still valid after the operation. - AddAfter(NULL,x) adds x to the start - same as AddHead - Return the position of the new object, NULL if it failed -*/ -__out_opt POSITION CBaseList::AddAfterI(__in_opt POSITION pos, __in void * pObj) -{ - if (pos==NULL) - return AddHeadI(pObj); - - /* As someone else might be furkling with the list - - Lock the critical section before continuing - */ - CNode *pAfter = (CNode *) pos; - ASSERT(pAfter != NULL); - if (pAfter==m_pLast) - return AddTailI(pObj); - - /* set pnode to point to a new node, preferably from the cache */ - - CNode *pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObj); - - /* It is to be added to the middle of the list - there is a before - and after node. Chain it after pAfter, before pBefore. - */ - CNode * pBefore = pAfter->Next(); - ASSERT(pBefore != NULL); - - /* chain it in (set four pointers) */ - pNode->SetPrev(pAfter); - pNode->SetNext(pBefore); - pBefore->SetPrev(pNode); - pAfter->SetNext(pNode); - - ++m_Count; - - return (POSITION) pNode; - -} // AddAfter(object) - - - -BOOL CBaseList::AddAfter(__in_opt POSITION p, __in CBaseList *pList) -{ - POSITION pos; - INTERNALTRAVERSELIST(*pList, pos) { - /* p follows along the elements being added */ - p = AddAfterI(p, pList->GetValidI(pos)); - if (p==NULL) return FALSE; - } - return TRUE; -} // AddAfter(list) - - - -/* Mirror images: - Add the element or list after position p. - p is still valid after the operation. - AddBefore(NULL,x) adds x to the end - same as AddTail -*/ -__out_opt POSITION CBaseList::AddBeforeI(__in_opt POSITION pos, __in void * pObj) -{ - if (pos==NULL) - return AddTailI(pObj); - - /* set pnode to point to a new node, preferably from the cache */ - - CNode *pBefore = (CNode *) pos; - ASSERT(pBefore != NULL); - if (pBefore==m_pFirst) - return AddHeadI(pObj); - - CNode * pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObj); - - /* It is to be added to the middle of the list - there is a before - and after node. Chain it after pAfter, before pBefore. - */ - - CNode * pAfter = pBefore->Prev(); - ASSERT(pAfter != NULL); - - /* chain it in (set four pointers) */ - pNode->SetPrev(pAfter); - pNode->SetNext(pBefore); - pBefore->SetPrev(pNode); - pAfter->SetNext(pNode); - - ++m_Count; - - return (POSITION) pNode; - -} // Addbefore(object) - - - -BOOL CBaseList::AddBefore(__in_opt POSITION p, __in CBaseList *pList) -{ - POSITION pos; - INTERNALREVERSETRAVERSELIST(*pList, pos) { - /* p follows along the elements being added */ - p = AddBeforeI(p, pList->GetValidI(pos)); - if (p==NULL) return FALSE; - } - return TRUE; -} // AddBefore(list) - - - -/* Split *this after position p in *this - Retain as *this the tail portion of the original *this - Add the head portion to the tail end of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToTail(foo->GetHeadPosition(), bar); - moves one element from the head of foo to the tail of bar - foo->MoveToTail(NULL, bar); - is a no-op - foo->MoveToTail(foo->GetTailPosition, bar); - concatenates foo onto the end of bar and empties foo. - - A better, except excessively long name might be - MoveElementsFromHeadThroughPositionToOtherTail -*/ -BOOL CBaseList::MoveToTail - (__in_opt POSITION pos, __in CBaseList *pList) -{ - /* Algorithm: - Note that the elements (including their order) in the concatenation - of *pList to the head of *this is invariant. - 1. Count elements to be moved - 2. Join *pList onto the head of this to make one long chain - 3. Set first/Last pointers in *this and *pList - 4. Break the chain at the new place - 5. Adjust counts - 6. Set/Reset any events - */ - - if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. - - - /* Make cMove the number of nodes to move */ - CNode * p = (CNode *)pos; - int cMove = 0; // number of nodes to move - while(p!=NULL) { - p = p->Prev(); - ++cMove; - } - - - /* Join the two chains together */ - if (pList->m_pLast!=NULL) - pList->m_pLast->SetNext(m_pFirst); - if (m_pFirst!=NULL) - m_pFirst->SetPrev(pList->m_pLast); - - - /* set first and last pointers */ - p = (CNode *)pos; - - if (pList->m_pFirst==NULL) - pList->m_pFirst = m_pFirst; - m_pFirst = p->Next(); - if (m_pFirst==NULL) - m_pLast = NULL; - pList->m_pLast = p; - - - /* Break the chain after p to create the new pieces */ - if (m_pFirst!=NULL) - m_pFirst->SetPrev(NULL); - p->SetNext(NULL); - - - /* Adjust the counts */ - m_Count -= cMove; - pList->m_Count += cMove; - - return TRUE; - -} // MoveToTail - - - -/* Mirror image of MoveToTail: - Split *this before position p in *this. - Retain in *this the head portion of the original *this - Add the tail portion to the start (i.e. head) of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToHead(foo->GetTailPosition(), bar); - moves one element from the tail of foo to the head of bar - foo->MoveToHead(NULL, bar); - is a no-op - foo->MoveToHead(foo->GetHeadPosition, bar); - concatenates foo onto the start of bar and empties foo. -*/ -BOOL CBaseList::MoveToHead - (__in_opt POSITION pos, __in CBaseList *pList) -{ - - /* See the comments on the algorithm in MoveToTail */ - - if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. - - /* Make cMove the number of nodes to move */ - CNode * p = (CNode *)pos; - int cMove = 0; // number of nodes to move - while(p!=NULL) { - p = p->Next(); - ++cMove; - } - - - /* Join the two chains together */ - if (pList->m_pFirst!=NULL) - pList->m_pFirst->SetPrev(m_pLast); - if (m_pLast!=NULL) - m_pLast->SetNext(pList->m_pFirst); - - - /* set first and last pointers */ - p = (CNode *)pos; - - - if (pList->m_pLast==NULL) - pList->m_pLast = m_pLast; - - m_pLast = p->Prev(); - if (m_pLast==NULL) - m_pFirst = NULL; - pList->m_pFirst = p; - - - /* Break the chain after p to create the new pieces */ - if (m_pLast!=NULL) - m_pLast->SetNext(NULL); - p->SetPrev(NULL); - - - /* Adjust the counts */ - m_Count -= cMove; - pList->m_Count += cMove; - - return TRUE; - -} // MoveToHead - - - -/* Reverse the order of the [pointers to] objects in *this -*/ -void CBaseList::Reverse() -{ - /* algorithm: - The obvious booby trap is that you flip pointers around and lose - addressability to the node that you are going to process next. - The easy way to avoid this is do do one chain at a time. - - Run along the forward chain, - For each node, set the reverse pointer to the one ahead of us. - The reverse chain is now a copy of the old forward chain, including - the NULL termination. - - Run along the reverse chain (i.e. old forward chain again) - For each node set the forward pointer of the node ahead to point back - to the one we're standing on. - The first node needs special treatment, - it's new forward pointer is NULL. - Finally set the First/Last pointers - - */ - CNode * p; - - // Yes we COULD use a traverse, but it would look funny! - p = m_pFirst; - while (p!=NULL) { - CNode * q; - q = p->Next(); - p->SetNext(p->Prev()); - p->SetPrev(q); - p = q; - } - - p = m_pFirst; - m_pFirst = m_pLast; - m_pLast = p; - - -#if 0 // old version - - if (m_pFirst==NULL) return; // empty list - if (m_pFirst->Next()==NULL) return; // single node list - - - /* run along forward chain */ - for ( p = m_pFirst - ; p!=NULL - ; p = p->Next() - ){ - p->SetPrev(p->Next()); - } - - - /* special case first element */ - m_pFirst->SetNext(NULL); // fix the old first element - - - /* run along new reverse chain i.e. old forward chain again */ - for ( p = m_pFirst // start at the old first element - ; p->Prev()!=NULL // while there's a node still to be set - ; p = p->Prev() // work in the same direction as before - ){ - p->Prev()->SetNext(p); - } - - - /* fix forward and reverse pointers - - the triple XOR swap would work but all the casts look hideous */ - p = m_pFirst; - m_pFirst = m_pLast; - m_pLast = p; -#endif - -} // Reverse +//------------------------------------------------------------------------------ +// File: WXList.cpp +// +// Desc: DirectShow base classes - implements a non-MFC based generic list +// template class. +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* A generic list of pointers to objects. + Objectives: avoid using MFC libraries in ndm kernel mode and + provide a really useful list type. + + The class is thread safe in that separate threads may add and + delete items in the list concurrently although the application + must ensure that constructor and destructor access is suitably + synchronised. + + The list name must not conflict with MFC classes as an + application may use both + + The nodes form a doubly linked, NULL terminated chain with an anchor + block (the list object per se) holding pointers to the first and last + nodes and a count of the nodes. + There is a node cache to reduce the allocation and freeing overhead. + It optionally (determined at construction time) has an Event which is + set whenever the list becomes non-empty and reset whenever it becomes + empty. + It optionally (determined at construction time) has a Critical Section + which is entered during the important part of each operation. (About + all you can do outside it is some parameter checking). + + The node cache is a repository of nodes that are NOT in the list to speed + up storage allocation. Each list has its own cache to reduce locking and + serialising. The list accesses are serialised anyway for a given list - a + common cache would mean that we would have to separately serialise access + of all lists within the cache. Because the cache only stores nodes that are + not in the list, releasing the cache does not release any list nodes. This + means that list nodes can be copied or rechained from one list to another + without danger of creating a dangling reference if the original cache goes + away. + + Questionable design decisions: + 1. Retaining the warts for compatibility + 2. Keeping an element count -i.e. counting whenever we do anything + instead of only when we want the count. + 3. Making the chain pointers NULL terminated. If the list object + itself looks just like a node and the list is kept as a ring then + it reduces the number of special cases. All inserts look the same. +*/ + + +#include "streams.h" + +/* set cursor to the position of each element of list in turn */ +#define INTERNALTRAVERSELIST(list, cursor) \ +for ( cursor = (list).GetHeadPositionI() \ + ; cursor!=NULL \ + ; cursor = (list).Next(cursor) \ + ) + + +/* set cursor to the position of each element of list in turn + in reverse order +*/ +#define INTERNALREVERSETRAVERSELIST(list, cursor) \ +for ( cursor = (list).GetTailPositionI() \ + ; cursor!=NULL \ + ; cursor = (list).Prev(cursor) \ + ) + +/* Constructor calls a separate initialisation function that + creates a node cache, optionally creates a lock object + and optionally creates a signaling object. + + By default we create a locking object, a DEFAULTCACHE sized + cache but no event object so the list cannot be used in calls + to WaitForSingleObject +*/ +CBaseList::CBaseList(__in_opt LPCTSTR pName, // Descriptive list name + INT iItems) : // Node cache size +#ifdef _DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(iItems) +{ +} // constructor + +CBaseList::CBaseList(__in_opt LPCTSTR pName) : // Descriptive list name +#ifdef _DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(DEFAULTCACHE) +{ +} // constructor + +#ifdef UNICODE +CBaseList::CBaseList(__in_opt LPCSTR pName, // Descriptive list name + INT iItems) : // Node cache size +#ifdef _DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(iItems) +{ +} // constructor + +CBaseList::CBaseList(__in_opt LPCSTR pName) : // Descriptive list name +#ifdef _DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(DEFAULTCACHE) +{ +} // constructor + +#endif + +/* The destructor enumerates all the node objects in the list and + in the cache deleting each in turn. We do not do any processing + on the objects that the list holds (i.e. points to) so if they + represent interfaces for example the creator of the list should + ensure that each of them is released before deleting us +*/ +CBaseList::~CBaseList() +{ + /* Delete all our list nodes */ + + RemoveAll(); + +} // destructor + +/* Remove all the nodes from the list but don't do anything + with the objects that each node looks after (this is the + responsibility of the creator). + Aa a last act we reset the signalling event + (if available) to indicate to clients that the list + does not have any entries in it. +*/ +void CBaseList::RemoveAll() +{ + /* Free up all the CNode objects NOTE we don't bother putting the + deleted nodes into the cache as this method is only really called + in serious times of change such as when we are being deleted at + which point the cache will be deleted anway */ + + CNode *pn = m_pFirst; + while (pn) { + CNode *op = pn; + pn = pn->Next(); + delete op; + } + + /* Reset the object count and the list pointers */ + + m_Count = 0; + m_pFirst = m_pLast = NULL; + +} // RemoveAll + + + +/* Return a position enumerator for the entire list. + A position enumerator is a pointer to a node object cast to a + transparent type so all we do is return the head/tail node + pointer in the list. + WARNING because the position is a pointer to a node there is + an implicit assumption for users a the list class that after + deleting an object from the list that any other position + enumerators that you have may be invalid (since the node + may be gone). +*/ +__out_opt POSITION CBaseList::GetHeadPositionI() const +{ + return (POSITION) m_pFirst; +} // GetHeadPosition + + + +__out_opt POSITION CBaseList::GetTailPositionI() const +{ + return (POSITION) m_pLast; +} // GetTailPosition + + + +/* Get the number of objects in the list, + Get the lock before accessing the count. + Locking may not be entirely necessary but it has the side effect + of making sure that all operations are complete before we get it. + So for example if a list is being added to this list then that + will have completed in full before we continue rather than seeing + an intermediate albeit valid state +*/ +int CBaseList::GetCountI() const +{ + return m_Count; +} // GetCount + + + +/* Return the object at rp, update rp to the next object from + the list or NULL if you have moved over the last object. + You may still call this function once we return NULL but + we will continue to return a NULL position value +*/ +__out void *CBaseList::GetNextI(__inout POSITION& rp) const +{ + /* have we reached the end of the list */ + + if (rp == NULL) { + return NULL; + } + + /* Lock the object before continuing */ + + void *pObject; + + /* Copy the original position then step on */ + + CNode *pn = (CNode *) rp; + ASSERT(pn != NULL); + rp = (POSITION) pn->Next(); + + /* Get the object at the original position from the list */ + + pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //GetNext + + + +/* Return the object at p. + Asking for the object at NULL ASSERTs then returns NULL + The object is NOT locked. The list is not being changed + in any way. If another thread is busy deleting the object + then locking would only result in a change from one bad + behaviour to another. +*/ +__out_opt void *CBaseList::GetI(__in_opt POSITION p) const +{ + if (p == NULL) { + return NULL; + } + + CNode * pn = (CNode *) p; + void *pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //Get + +__out void *CBaseList::GetValidI(__in POSITION p) const +{ + CNode * pn = (CNode *) p; + void *pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //Get + + +/* Return the first position in the list which holds the given pointer. + Return NULL if it's not found. +*/ +__out_opt POSITION CBaseList::FindI( __in void * pObj) const +{ + POSITION pn; + INTERNALTRAVERSELIST(*this, pn){ + if (GetI(pn)==pObj) { + return pn; + } + } + return NULL; +} // Find + + + +/* Remove the first node in the list (deletes the pointer to its object + from the list, does not free the object itself). + Return the pointer to its object or NULL if empty +*/ +__out_opt void *CBaseList::RemoveHeadI() +{ + /* All we do is get the head position and ask for that to be deleted. + We could special case this since some of the code path checking + in Remove() is redundant as we know there is no previous + node for example but it seems to gain little over the + added complexity + */ + + return RemoveI((POSITION)m_pFirst); +} // RemoveHead + + + +/* Remove the last node in the list (deletes the pointer to its object + from the list, does not free the object itself). + Return the pointer to its object or NULL if empty +*/ +__out_opt void *CBaseList::RemoveTailI() +{ + /* All we do is get the tail position and ask for that to be deleted. + We could special case this since some of the code path checking + in Remove() is redundant as we know there is no previous + node for example but it seems to gain little over the + added complexity + */ + + return RemoveI((POSITION)m_pLast); +} // RemoveTail + + + +/* Remove the pointer to the object in this position from the list. + Deal with all the chain pointers + Return a pointer to the object removed from the list. + The node object that is freed as a result + of this operation is added to the node cache where + it can be used again. + Remove(NULL) is a harmless no-op - but probably is a wart. +*/ +__out_opt void *CBaseList::RemoveI(__in_opt POSITION pos) +{ + /* Lock the critical section before continuing */ + + // ASSERT (pos!=NULL); // Removing NULL is to be harmless! + if (pos==NULL) return NULL; + + + CNode *pCurrent = (CNode *) pos; + ASSERT(pCurrent != NULL); + + /* Update the previous node */ + + CNode *pNode = pCurrent->Prev(); + if (pNode == NULL) { + m_pFirst = pCurrent->Next(); + } else { + pNode->SetNext(pCurrent->Next()); + } + + /* Update the following node */ + + pNode = pCurrent->Next(); + if (pNode == NULL) { + m_pLast = pCurrent->Prev(); + } else { + pNode->SetPrev(pCurrent->Prev()); + } + + /* Get the object this node was looking after */ + + void *pObject = pCurrent->GetData(); + + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + + /* Try and add the node object to the cache - + a NULL return code from the cache means we ran out of room. + The cache size is fixed by a constructor argument when the + list is created and defaults to DEFAULTCACHE. + This means that the cache will have room for this many + node objects. So if you have a list of media samples + and you know there will never be more than five active at + any given time of them for example then override the default + constructor + */ + + m_Cache.AddToCache(pCurrent); + + /* If the list is empty then reset the list event */ + + --m_Count; + ASSERT(m_Count >= 0); + return pObject; +} // Remove + + + +/* Add this object to the tail end of our list + Return the new tail position. +*/ + +__out_opt POSITION CBaseList::AddTailI(__in void *pObject) +{ + /* Lock the critical section before continuing */ + + CNode *pNode; + // ASSERT(pObject); // NULL pointers in the list are allowed. + + /* If there is a node objects in the cache then use + that otherwise we will have to create a new one */ + + pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObject); + pNode->SetNext(NULL); + pNode->SetPrev(m_pLast); + + if (m_pLast == NULL) { + m_pFirst = pNode; + } else { + m_pLast->SetNext(pNode); + } + + /* Set the new last node pointer and also increment the number + of list entries, the critical section is unlocked when we + exit the function + */ + + m_pLast = pNode; + ++m_Count; + + return (POSITION) pNode; +} // AddTail(object) + + + +/* Add this object to the head end of our list + Return the new head position. +*/ +__out_opt POSITION CBaseList::AddHeadI(__in void *pObject) +{ + CNode *pNode; + // ASSERT(pObject); // NULL pointers in the list are allowed. + + /* If there is a node objects in the cache then use + that otherwise we will have to create a new one */ + + pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObject); + + /* chain it in (set four pointers) */ + pNode->SetPrev(NULL); + pNode->SetNext(m_pFirst); + + if (m_pFirst == NULL) { + m_pLast = pNode; + } else { + m_pFirst->SetPrev(pNode); + } + m_pFirst = pNode; + + ++m_Count; + + return (POSITION) pNode; +} // AddHead(object) + + + +/* Add all the elements in *pList to the tail of this list. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. +*/ +BOOL CBaseList::AddTail(__in CBaseList *pList) +{ + /* lock the object before starting then enumerate + each entry in the source list and add them one by one to + our list (while still holding the object lock) + Lock the other list too. + */ + POSITION pos = pList->GetHeadPositionI(); + + while (pos) { + if (NULL == AddTailI(pList->GetNextI(pos))) { + return FALSE; + } + } + return TRUE; +} // AddTail(list) + + + +/* Add all the elements in *pList to the head of this list. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. +*/ +BOOL CBaseList::AddHead(__in CBaseList *pList) +{ + /* lock the object before starting then enumerate + each entry in the source list and add them one by one to + our list (while still holding the object lock) + Lock the other list too. + + To avoid reversing the list, traverse it backwards. + */ + + POSITION pos; + + INTERNALREVERSETRAVERSELIST(*pList, pos) { + if (NULL== AddHeadI(pList->GetValidI(pos))){ + return FALSE; + } + } + return TRUE; +} // AddHead(list) + + + +/* Add the object after position p + p is still valid after the operation. + AddAfter(NULL,x) adds x to the start - same as AddHead + Return the position of the new object, NULL if it failed +*/ +__out_opt POSITION CBaseList::AddAfterI(__in_opt POSITION pos, __in void * pObj) +{ + if (pos==NULL) + return AddHeadI(pObj); + + /* As someone else might be furkling with the list - + Lock the critical section before continuing + */ + CNode *pAfter = (CNode *) pos; + ASSERT(pAfter != NULL); + if (pAfter==m_pLast) + return AddTailI(pObj); + + /* set pnode to point to a new node, preferably from the cache */ + + CNode *pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObj); + + /* It is to be added to the middle of the list - there is a before + and after node. Chain it after pAfter, before pBefore. + */ + CNode * pBefore = pAfter->Next(); + ASSERT(pBefore != NULL); + + /* chain it in (set four pointers) */ + pNode->SetPrev(pAfter); + pNode->SetNext(pBefore); + pBefore->SetPrev(pNode); + pAfter->SetNext(pNode); + + ++m_Count; + + return (POSITION) pNode; + +} // AddAfter(object) + + + +BOOL CBaseList::AddAfter(__in_opt POSITION p, __in CBaseList *pList) +{ + POSITION pos; + INTERNALTRAVERSELIST(*pList, pos) { + /* p follows along the elements being added */ + p = AddAfterI(p, pList->GetValidI(pos)); + if (p==NULL) return FALSE; + } + return TRUE; +} // AddAfter(list) + + + +/* Mirror images: + Add the element or list after position p. + p is still valid after the operation. + AddBefore(NULL,x) adds x to the end - same as AddTail +*/ +__out_opt POSITION CBaseList::AddBeforeI(__in_opt POSITION pos, __in void * pObj) +{ + if (pos==NULL) + return AddTailI(pObj); + + /* set pnode to point to a new node, preferably from the cache */ + + CNode *pBefore = (CNode *) pos; + ASSERT(pBefore != NULL); + if (pBefore==m_pFirst) + return AddHeadI(pObj); + + CNode * pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObj); + + /* It is to be added to the middle of the list - there is a before + and after node. Chain it after pAfter, before pBefore. + */ + + CNode * pAfter = pBefore->Prev(); + ASSERT(pAfter != NULL); + + /* chain it in (set four pointers) */ + pNode->SetPrev(pAfter); + pNode->SetNext(pBefore); + pBefore->SetPrev(pNode); + pAfter->SetNext(pNode); + + ++m_Count; + + return (POSITION) pNode; + +} // Addbefore(object) + + + +BOOL CBaseList::AddBefore(__in_opt POSITION p, __in CBaseList *pList) +{ + POSITION pos; + INTERNALREVERSETRAVERSELIST(*pList, pos) { + /* p follows along the elements being added */ + p = AddBeforeI(p, pList->GetValidI(pos)); + if (p==NULL) return FALSE; + } + return TRUE; +} // AddBefore(list) + + + +/* Split *this after position p in *this + Retain as *this the tail portion of the original *this + Add the head portion to the tail end of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToTail(foo->GetHeadPosition(), bar); + moves one element from the head of foo to the tail of bar + foo->MoveToTail(NULL, bar); + is a no-op + foo->MoveToTail(foo->GetTailPosition, bar); + concatenates foo onto the end of bar and empties foo. + + A better, except excessively long name might be + MoveElementsFromHeadThroughPositionToOtherTail +*/ +BOOL CBaseList::MoveToTail + (__in_opt POSITION pos, __in CBaseList *pList) +{ + /* Algorithm: + Note that the elements (including their order) in the concatenation + of *pList to the head of *this is invariant. + 1. Count elements to be moved + 2. Join *pList onto the head of this to make one long chain + 3. Set first/Last pointers in *this and *pList + 4. Break the chain at the new place + 5. Adjust counts + 6. Set/Reset any events + */ + + if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. + + + /* Make cMove the number of nodes to move */ + CNode * p = (CNode *)pos; + int cMove = 0; // number of nodes to move + while(p!=NULL) { + p = p->Prev(); + ++cMove; + } + + + /* Join the two chains together */ + if (pList->m_pLast!=NULL) + pList->m_pLast->SetNext(m_pFirst); + if (m_pFirst!=NULL) + m_pFirst->SetPrev(pList->m_pLast); + + + /* set first and last pointers */ + p = (CNode *)pos; + + if (pList->m_pFirst==NULL) + pList->m_pFirst = m_pFirst; + m_pFirst = p->Next(); + if (m_pFirst==NULL) + m_pLast = NULL; + pList->m_pLast = p; + + + /* Break the chain after p to create the new pieces */ + if (m_pFirst!=NULL) + m_pFirst->SetPrev(NULL); + p->SetNext(NULL); + + + /* Adjust the counts */ + m_Count -= cMove; + pList->m_Count += cMove; + + return TRUE; + +} // MoveToTail + + + +/* Mirror image of MoveToTail: + Split *this before position p in *this. + Retain in *this the head portion of the original *this + Add the tail portion to the start (i.e. head) of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToHead(foo->GetTailPosition(), bar); + moves one element from the tail of foo to the head of bar + foo->MoveToHead(NULL, bar); + is a no-op + foo->MoveToHead(foo->GetHeadPosition, bar); + concatenates foo onto the start of bar and empties foo. +*/ +BOOL CBaseList::MoveToHead + (__in_opt POSITION pos, __in CBaseList *pList) +{ + + /* See the comments on the algorithm in MoveToTail */ + + if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. + + /* Make cMove the number of nodes to move */ + CNode * p = (CNode *)pos; + int cMove = 0; // number of nodes to move + while(p!=NULL) { + p = p->Next(); + ++cMove; + } + + + /* Join the two chains together */ + if (pList->m_pFirst!=NULL) + pList->m_pFirst->SetPrev(m_pLast); + if (m_pLast!=NULL) + m_pLast->SetNext(pList->m_pFirst); + + + /* set first and last pointers */ + p = (CNode *)pos; + + + if (pList->m_pLast==NULL) + pList->m_pLast = m_pLast; + + m_pLast = p->Prev(); + if (m_pLast==NULL) + m_pFirst = NULL; + pList->m_pFirst = p; + + + /* Break the chain after p to create the new pieces */ + if (m_pLast!=NULL) + m_pLast->SetNext(NULL); + p->SetPrev(NULL); + + + /* Adjust the counts */ + m_Count -= cMove; + pList->m_Count += cMove; + + return TRUE; + +} // MoveToHead + + + +/* Reverse the order of the [pointers to] objects in *this +*/ +void CBaseList::Reverse() +{ + /* algorithm: + The obvious booby trap is that you flip pointers around and lose + addressability to the node that you are going to process next. + The easy way to avoid this is do do one chain at a time. + + Run along the forward chain, + For each node, set the reverse pointer to the one ahead of us. + The reverse chain is now a copy of the old forward chain, including + the NULL termination. + + Run along the reverse chain (i.e. old forward chain again) + For each node set the forward pointer of the node ahead to point back + to the one we're standing on. + The first node needs special treatment, + it's new forward pointer is NULL. + Finally set the First/Last pointers + + */ + CNode * p; + + // Yes we COULD use a traverse, but it would look funny! + p = m_pFirst; + while (p!=NULL) { + CNode * q; + q = p->Next(); + p->SetNext(p->Prev()); + p->SetPrev(q); + p = q; + } + + p = m_pFirst; + m_pFirst = m_pLast; + m_pLast = p; + + +#if 0 // old version + + if (m_pFirst==NULL) return; // empty list + if (m_pFirst->Next()==NULL) return; // single node list + + + /* run along forward chain */ + for ( p = m_pFirst + ; p!=NULL + ; p = p->Next() + ){ + p->SetPrev(p->Next()); + } + + + /* special case first element */ + m_pFirst->SetNext(NULL); // fix the old first element + + + /* run along new reverse chain i.e. old forward chain again */ + for ( p = m_pFirst // start at the old first element + ; p->Prev()!=NULL // while there's a node still to be set + ; p = p->Prev() // work in the same direction as before + ){ + p->Prev()->SetNext(p); + } + + + /* fix forward and reverse pointers + - the triple XOR swap would work but all the casts look hideous */ + p = m_pFirst; + m_pFirst = m_pLast; + m_pLast = p; +#endif + +} // Reverse diff --git a/src/thirdparty/BaseClasses/wxlist.h b/src/thirdparty/BaseClasses/wxlist.h index 4cb8194463a..43b3d855531 100644 --- a/src/thirdparty/BaseClasses/wxlist.h +++ b/src/thirdparty/BaseClasses/wxlist.h @@ -1,553 +1,553 @@ -//------------------------------------------------------------------------------ -// File: WXList.h -// -// Desc: DirectShow base classes - defines a non-MFC generic template list -// class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* A generic list of pointers to objects. - No storage management or copying is done on the objects pointed to. - Objectives: avoid using MFC libraries in ndm kernel mode and - provide a really useful list type. - - The class is thread safe in that separate threads may add and - delete items in the list concurrently although the application - must ensure that constructor and destructor access is suitably - synchronised. An application can cause deadlock with operations - which use two lists by simultaneously calling - list1->Operation(list2) and list2->Operation(list1). So don't! - - The names must not conflict with MFC classes as an application - may use both. - */ - -#ifndef __WXLIST__ -#define __WXLIST__ - - /* A POSITION represents (in some fashion that's opaque) a cursor - on the list that can be set to identify any element. NULL is - a valid value and several operations regard NULL as the position - "one step off the end of the list". (In an n element list there - are n+1 places to insert and NULL is that "n+1-th" value). - The POSITION of an element in the list is only invalidated if - that element is deleted. Move operations may mean that what - was a valid POSITION in one list is now a valid POSITION in - a different list. - - Some operations which at first sight are illegal are allowed as - harmless no-ops. For instance RemoveHead is legal on an empty - list and it returns NULL. This allows an atomic way to test if - there is an element there, and if so, get it. The two operations - AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper). - - Single element operations return POSITIONs, non-NULL means it worked. - whole list operations return a BOOL. TRUE means it all worked. - - This definition is the same as the POSITION type for MFCs, so we must - avoid defining it twice. - */ -#ifndef __AFX_H__ -struct __POSITION { int unused; }; -typedef __POSITION* POSITION; -#endif - -const int DEFAULTCACHE = 10; /* Default node object cache size */ - -/* A class representing one node in a list. - Each node knows a pointer to it's adjacent nodes and also a pointer - to the object that it looks after. - All of these pointers can be retrieved or set through member functions. -*/ -class CBaseList -#ifdef _DEBUG - : public CBaseObject -#endif -{ - /* Making these classes inherit from CBaseObject does nothing - functionally but it allows us to check there are no memory - leaks in debug builds. - */ - -public: - -#ifdef _DEBUG - class CNode : public CBaseObject { -#else - class CNode { -#endif - - CNode *m_pPrev = NULL; /* Previous node in the list */ - CNode *m_pNext = NULL; /* Next node in the list */ - void *m_pObject = NULL; /* Pointer to the object */ - - public: - - /* Constructor - initialise the object's pointers */ - CNode() -#ifdef _DEBUG - : CBaseObject(NAME("List node")) -#endif - { - }; - - - /* Return the previous node before this one */ - __out CNode *Prev() const { return m_pPrev; }; - - - /* Return the next node after this one */ - __out CNode *Next() const { return m_pNext; }; - - - /* Set the previous node before this one */ - void SetPrev(__in_opt CNode *p) { m_pPrev = p; }; - - - /* Set the next node after this one */ - void SetNext(__in_opt CNode *p) { m_pNext = p; }; - - - /* Get the pointer to the object for this node */ - __out void *GetData() const { return m_pObject; }; - - - /* Set the pointer to the object for this node */ - void SetData(__in void *p) { m_pObject = p; }; - }; - - class CNodeCache - { - public: - CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize), - m_pHead(NULL), - m_iUsed(0) - {}; - ~CNodeCache() { - CNode *pNode = m_pHead; - while (pNode) { - CNode *pCurrent = pNode; - pNode = pNode->Next(); - delete pCurrent; - } - }; - void AddToCache(__inout CNode *pNode) - { - if (m_iUsed < m_iCacheSize) { - pNode->SetNext(m_pHead); - m_pHead = pNode; - m_iUsed++; - } else { - delete pNode; - } - }; - CNode *RemoveFromCache() - { - CNode *pNode = m_pHead; - if (pNode != NULL) { - m_pHead = pNode->Next(); - m_iUsed--; - ASSERT(m_iUsed >= 0); - } else { - ASSERT(m_iUsed == 0); - } - return pNode; - }; - private: - INT m_iCacheSize; - INT m_iUsed; - CNode *m_pHead; - }; - -protected: - - CNode* m_pFirst; /* Pointer to first node in the list */ - CNode* m_pLast; /* Pointer to the last node in the list */ - LONG m_Count; /* Number of nodes currently in the list */ - -private: - - CNodeCache m_Cache; /* Cache of unused node pointers */ - -private: - - /* These override the default copy constructor and assignment - operator for all list classes. They are in the private class - declaration section so that anybody trying to pass a list - object by value will generate a compile time error of - "cannot access the private member function". If these were - not here then the compiler will create default constructors - and assignment operators which when executed first take a - copy of all member variables and then during destruction - delete them all. This must not be done for any heap - allocated data. - */ - CBaseList(const CBaseList &refList); - CBaseList &operator=(const CBaseList &refList); - -public: - - CBaseList(__in_opt LPCTSTR pName, - INT iItems); - - CBaseList(__in_opt LPCTSTR pName); -#ifdef UNICODE - CBaseList(__in_opt LPCSTR pName, - INT iItems); - - CBaseList(__in_opt LPCSTR pName); -#endif - ~CBaseList(); - - /* Remove all the nodes from *this i.e. make the list empty */ - void RemoveAll(); - - - /* Return a cursor which identifies the first element of *this */ - __out_opt POSITION GetHeadPositionI() const; - - - /* Return a cursor which identifies the last element of *this */ - __out_opt POSITION GetTailPositionI() const; - - - /* Return the number of objects in *this */ - int GetCountI() const; - -protected: - /* Return the pointer to the object at rp, - Update rp to the next node in *this - but make it NULL if it was at the end of *this. - This is a wart retained for backwards compatibility. - GetPrev is not implemented. - Use Next, Prev and Get separately. - */ - __out void *GetNextI(__inout POSITION& rp) const; - - - /* Return a pointer to the object at p - Asking for the object at NULL will return NULL harmlessly. - */ - __out_opt void *GetI(__in_opt POSITION p) const; - __out void *GetValidI(__in POSITION p) const; - -public: - /* return the next / prev position in *this - return NULL when going past the end/start. - Next(NULL) is same as GetHeadPosition() - Prev(NULL) is same as GetTailPosition() - An n element list therefore behaves like a n+1 element - cycle with NULL at the start/end. - - !!WARNING!! - This handling of NULL is DIFFERENT from GetNext. - - Some reasons are: - 1. For a list of n items there are n+1 positions to insert - These are conveniently encoded as the n POSITIONs and NULL. - 2. If you are keeping a list sorted (fairly common) and you - search forward for an element to insert before and don't - find it you finish up with NULL as the element before which - to insert. You then want that NULL to be a valid POSITION - so that you can insert before it and you want that insertion - point to mean the (n+1)-th one that doesn't have a POSITION. - (symmetrically if you are working backwards through the list). - 3. It simplifies the algebra which the methods generate. - e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x) - in ALL cases. All the other arguments probably are reflections - of the algebraic point. - */ - __out_opt POSITION Next(__in_opt POSITION pos) const - { - if (pos == NULL) { - return (POSITION) m_pFirst; - } - CNode *pn = (CNode *) pos; - return (POSITION) pn->Next(); - } //Next - - // See Next - __out_opt POSITION Prev(__in_opt POSITION pos) const - { - if (pos == NULL) { - return (POSITION) m_pLast; - } - CNode *pn = (CNode *) pos; - return (POSITION) pn->Prev(); - } //Prev - - - /* Return the first position in *this which holds the given - pointer. Return NULL if the pointer was not not found. - */ -protected: - __out_opt POSITION FindI( __in void * pObj) const; - - // ??? Should there be (or even should there be only) - // ??? POSITION FindNextAfter(void * pObj, POSITION p) - // ??? And of course FindPrevBefore too. - // ??? List.Find(&Obj) then becomes List.FindNextAfter(&Obj, NULL) - - - /* Remove the first node in *this (deletes the pointer to its - object from the list, does not free the object itself). - Return the pointer to its object. - If *this was already empty it will harmlessly return NULL. - */ - __out_opt void *RemoveHeadI(); - - - /* Remove the last node in *this (deletes the pointer to its - object from the list, does not free the object itself). - Return the pointer to its object. - If *this was already empty it will harmlessly return NULL. - */ - __out_opt void *RemoveTailI(); - - - /* Remove the node identified by p from the list (deletes the pointer - to its object from the list, does not free the object itself). - Asking to Remove the object at NULL will harmlessly return NULL. - Return the pointer to the object removed. - */ - __out_opt void *RemoveI(__in_opt POSITION p); - - /* Add single object *pObj to become a new last element of the list. - Return the new tail position, NULL if it fails. - If you are adding a COM objects, you might want AddRef it first. - Other existing POSITIONs in *this are still valid - */ - __out_opt POSITION AddTailI(__in void * pObj); -public: - - - /* Add all the elements in *pList to the tail of *this. - This duplicates all the nodes in *pList (i.e. duplicates - all its pointers to objects). It does not duplicate the objects. - If you are adding a list of pointers to a COM object into the list - it's a good idea to AddRef them all it when you AddTail it. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. - Existing POSITIONs in *this are still valid - - If you actually want to MOVE the elements, use MoveToTail instead. - */ - BOOL AddTail(__in CBaseList *pList); - - - /* Mirror images of AddHead: */ - - /* Add single object to become a new first element of the list. - Return the new head position, NULL if it fails. - Existing POSITIONs in *this are still valid - */ -protected: - __out_opt POSITION AddHeadI(__in void * pObj); -public: - - /* Add all the elements in *pList to the head of *this. - Same warnings apply as for AddTail. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some of the objects may have been added. - - If you actually want to MOVE the elements, use MoveToHead instead. - */ - BOOL AddHead(__in CBaseList *pList); - - - /* Add the object *pObj to *this after position p in *this. - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return the position of the object added, NULL if it failed. - Existing POSITIONs in *this are undisturbed, including p. - */ -protected: - __out_opt POSITION AddAfterI(__in_opt POSITION p, __in void * pObj); -public: - - /* Add the list *pList to *this after position p in *this - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return TRUE if it all worked, FALSE if it didn't. - If it fails, some of the objects may be added - Existing POSITIONs in *this are undisturbed, including p. - */ - BOOL AddAfter(__in_opt POSITION p, __in CBaseList *pList); - - - /* Mirror images: - Add the object *pObj to this-List after position p in *this. - AddBefore(NULL,x) adds x to the end - equivalent to AddTail - Return the position of the new object, NULL if it fails - Existing POSITIONs in *this are undisturbed, including p. - */ - protected: - __out_opt POSITION AddBeforeI(__in_opt POSITION p, __in void * pObj); - public: - - /* Add the list *pList to *this before position p in *this - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return TRUE if it all worked, FALSE if it didn't. - If it fails, some of the objects may be added - Existing POSITIONs in *this are undisturbed, including p. - */ - BOOL AddBefore(__in_opt POSITION p, __in CBaseList *pList); - - - /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x) - even in cases where p is NULL or Next(p) is NULL. - Similarly for mirror images etc. - This may make it easier to argue about programs. - */ - - - - /* The following operations do not copy any elements. - They move existing blocks of elements around by switching pointers. - They are fairly efficient for long lists as for short lists. - (Alas, the Count slows things down). - - They split the list into two parts. - One part remains as the original list, the other part - is appended to the second list. There are eight possible - variations: - Split the list {after/before} a given element - keep the {head/tail} portion in the original list - append the rest to the {head/tail} of the new list. - - Since After is strictly equivalent to Before Next - we are not in serious need of the Before/After variants. - That leaves only four. - - If you are processing a list left to right and dumping - the bits that you have processed into another list as - you go, the Tail/Tail variant gives the most natural result. - If you are processing in reverse order, Head/Head is best. - - By using NULL positions and empty lists judiciously either - of the other two can be built up in two operations. - - The definition of NULL (see Next/Prev etc) means that - degenerate cases include - "move all elements to new list" - "Split a list into two lists" - "Concatenate two lists" - (and quite a few no-ops) - - !!WARNING!! The type checking won't buy you much if you get list - positions muddled up - e.g. use a POSITION that's in a different - list and see what a mess you get! - */ - - /* Split *this after position p in *this - Retain as *this the tail portion of the original *this - Add the head portion to the tail end of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToTail(foo->GetHeadPosition(), bar); - moves one element from the head of foo to the tail of bar - foo->MoveToTail(NULL, bar); - is a no-op, returns NULL - foo->MoveToTail(foo->GetTailPosition, bar); - concatenates foo onto the end of bar and empties foo. - - A better, except excessively long name might be - MoveElementsFromHeadThroughPositionToOtherTail - */ - BOOL MoveToTail(__in_opt POSITION pos, __in CBaseList *pList); - - - /* Mirror image: - Split *this before position p in *this. - Retain in *this the head portion of the original *this - Add the tail portion to the start (i.e. head) of *pList - - e.g. - foo->MoveToHead(foo->GetTailPosition(), bar); - moves one element from the tail of foo to the head of bar - foo->MoveToHead(NULL, bar); - is a no-op, returns NULL - foo->MoveToHead(foo->GetHeadPosition, bar); - concatenates foo onto the start of bar and empties foo. - */ - BOOL MoveToHead(__in_opt POSITION pos, __in CBaseList *pList); - - - /* Reverse the order of the [pointers to] objects in *this - */ - void Reverse(); - - - /* set cursor to the position of each element of list in turn */ - #define TRAVERSELIST(list, cursor) \ - for ( cursor = (list).GetHeadPosition() \ - ; cursor!=NULL \ - ; cursor = (list).Next(cursor) \ - ) - - - /* set cursor to the position of each element of list in turn - in reverse order - */ - #define REVERSETRAVERSELIST(list, cursor) \ - for ( cursor = (list).GetTailPosition() \ - ; cursor!=NULL \ - ; cursor = (list).Prev(cursor) \ - ) - -}; // end of class declaration - -template class CGenericList : public CBaseList -{ -public: - CGenericList(__in_opt LPCTSTR pName, - INT iItems, - BOOL bLock = TRUE, - BOOL bAlert = FALSE) : - CBaseList(pName, iItems) { - UNREFERENCED_PARAMETER(bAlert); - UNREFERENCED_PARAMETER(bLock); - }; - CGenericList(__in_opt LPCTSTR pName) : - CBaseList(pName) { - }; - - __out_opt POSITION GetHeadPosition() const { return (POSITION)m_pFirst; } - __out_opt POSITION GetTailPosition() const { return (POSITION)m_pLast; } - int GetCount() const { return m_Count; } - - __out OBJECT *GetNext(__inout POSITION& rp) const { return (OBJECT *) GetNextI(rp); } - - __out_opt OBJECT *Get(__in_opt POSITION p) const { return (OBJECT *) GetI(p); } - __out OBJECT *GetValid(__in POSITION p) const { return (OBJECT *) GetValidI(p); } - __out_opt OBJECT *GetHead() const { return Get(GetHeadPosition()); } - - __out_opt OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); } - - __out_opt OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); } - - __out_opt OBJECT *Remove(__in_opt POSITION p) { return (OBJECT *) RemoveI(p); } - __out_opt POSITION AddBefore(__in_opt POSITION p, __in OBJECT * pObj) { return AddBeforeI(p, pObj); } - __out_opt POSITION AddAfter(__in_opt POSITION p, __in OBJECT * pObj) { return AddAfterI(p, pObj); } - __out_opt POSITION AddHead(__in OBJECT * pObj) { return AddHeadI(pObj); } - __out_opt POSITION AddTail(__in OBJECT * pObj) { return AddTailI(pObj); } - BOOL AddTail(__in CGenericList *pList) - { return CBaseList::AddTail((CBaseList *) pList); } - BOOL AddHead(__in CGenericList *pList) - { return CBaseList::AddHead((CBaseList *) pList); } - BOOL AddAfter(__in_opt POSITION p, __in CGenericList *pList) - { return CBaseList::AddAfter(p, (CBaseList *) pList); }; - BOOL AddBefore(__in_opt POSITION p, __in CGenericList *pList) - { return CBaseList::AddBefore(p, (CBaseList *) pList); }; - __out_opt POSITION Find( __in OBJECT * pObj) const { return FindI(pObj); } -}; // end of class declaration - - - -/* These define the standard list types */ - -typedef CGenericList CBaseObjectList; -typedef CGenericList CBaseInterfaceList; - -#endif /* __WXLIST__ */ - +//------------------------------------------------------------------------------ +// File: WXList.h +// +// Desc: DirectShow base classes - defines a non-MFC generic template list +// class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* A generic list of pointers to objects. + No storage management or copying is done on the objects pointed to. + Objectives: avoid using MFC libraries in ndm kernel mode and + provide a really useful list type. + + The class is thread safe in that separate threads may add and + delete items in the list concurrently although the application + must ensure that constructor and destructor access is suitably + synchronised. An application can cause deadlock with operations + which use two lists by simultaneously calling + list1->Operation(list2) and list2->Operation(list1). So don't! + + The names must not conflict with MFC classes as an application + may use both. + */ + +#ifndef __WXLIST__ +#define __WXLIST__ + + /* A POSITION represents (in some fashion that's opaque) a cursor + on the list that can be set to identify any element. NULL is + a valid value and several operations regard NULL as the position + "one step off the end of the list". (In an n element list there + are n+1 places to insert and NULL is that "n+1-th" value). + The POSITION of an element in the list is only invalidated if + that element is deleted. Move operations may mean that what + was a valid POSITION in one list is now a valid POSITION in + a different list. + + Some operations which at first sight are illegal are allowed as + harmless no-ops. For instance RemoveHead is legal on an empty + list and it returns NULL. This allows an atomic way to test if + there is an element there, and if so, get it. The two operations + AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper). + + Single element operations return POSITIONs, non-NULL means it worked. + whole list operations return a BOOL. TRUE means it all worked. + + This definition is the same as the POSITION type for MFCs, so we must + avoid defining it twice. + */ +#ifndef __AFX_H__ +struct __POSITION { int unused; }; +typedef __POSITION* POSITION; +#endif + +const int DEFAULTCACHE = 10; /* Default node object cache size */ + +/* A class representing one node in a list. + Each node knows a pointer to it's adjacent nodes and also a pointer + to the object that it looks after. + All of these pointers can be retrieved or set through member functions. +*/ +class CBaseList +#ifdef _DEBUG + : public CBaseObject +#endif +{ + /* Making these classes inherit from CBaseObject does nothing + functionally but it allows us to check there are no memory + leaks in debug builds. + */ + +public: + +#ifdef _DEBUG + class CNode : public CBaseObject { +#else + class CNode { +#endif + + CNode *m_pPrev = NULL; /* Previous node in the list */ + CNode *m_pNext = NULL; /* Next node in the list */ + void *m_pObject = NULL; /* Pointer to the object */ + + public: + + /* Constructor - initialise the object's pointers */ + CNode() +#ifdef _DEBUG + : CBaseObject(NAME("List node")) +#endif + { + }; + + + /* Return the previous node before this one */ + __out CNode *Prev() const { return m_pPrev; }; + + + /* Return the next node after this one */ + __out CNode *Next() const { return m_pNext; }; + + + /* Set the previous node before this one */ + void SetPrev(__in_opt CNode *p) { m_pPrev = p; }; + + + /* Set the next node after this one */ + void SetNext(__in_opt CNode *p) { m_pNext = p; }; + + + /* Get the pointer to the object for this node */ + __out void *GetData() const { return m_pObject; }; + + + /* Set the pointer to the object for this node */ + void SetData(__in void *p) { m_pObject = p; }; + }; + + class CNodeCache + { + public: + CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize), + m_pHead(NULL), + m_iUsed(0) + {}; + ~CNodeCache() { + CNode *pNode = m_pHead; + while (pNode) { + CNode *pCurrent = pNode; + pNode = pNode->Next(); + delete pCurrent; + } + }; + void AddToCache(__inout CNode *pNode) + { + if (m_iUsed < m_iCacheSize) { + pNode->SetNext(m_pHead); + m_pHead = pNode; + m_iUsed++; + } else { + delete pNode; + } + }; + CNode *RemoveFromCache() + { + CNode *pNode = m_pHead; + if (pNode != NULL) { + m_pHead = pNode->Next(); + m_iUsed--; + ASSERT(m_iUsed >= 0); + } else { + ASSERT(m_iUsed == 0); + } + return pNode; + }; + private: + INT m_iCacheSize; + INT m_iUsed; + CNode *m_pHead; + }; + +protected: + + CNode* m_pFirst; /* Pointer to first node in the list */ + CNode* m_pLast; /* Pointer to the last node in the list */ + LONG m_Count; /* Number of nodes currently in the list */ + +private: + + CNodeCache m_Cache; /* Cache of unused node pointers */ + +private: + + /* These override the default copy constructor and assignment + operator for all list classes. They are in the private class + declaration section so that anybody trying to pass a list + object by value will generate a compile time error of + "cannot access the private member function". If these were + not here then the compiler will create default constructors + and assignment operators which when executed first take a + copy of all member variables and then during destruction + delete them all. This must not be done for any heap + allocated data. + */ + CBaseList(const CBaseList &refList); + CBaseList &operator=(const CBaseList &refList); + +public: + + CBaseList(__in_opt LPCTSTR pName, + INT iItems); + + CBaseList(__in_opt LPCTSTR pName); +#ifdef UNICODE + CBaseList(__in_opt LPCSTR pName, + INT iItems); + + CBaseList(__in_opt LPCSTR pName); +#endif + ~CBaseList(); + + /* Remove all the nodes from *this i.e. make the list empty */ + void RemoveAll(); + + + /* Return a cursor which identifies the first element of *this */ + __out_opt POSITION GetHeadPositionI() const; + + + /* Return a cursor which identifies the last element of *this */ + __out_opt POSITION GetTailPositionI() const; + + + /* Return the number of objects in *this */ + int GetCountI() const; + +protected: + /* Return the pointer to the object at rp, + Update rp to the next node in *this + but make it NULL if it was at the end of *this. + This is a wart retained for backwards compatibility. + GetPrev is not implemented. + Use Next, Prev and Get separately. + */ + __out void *GetNextI(__inout POSITION& rp) const; + + + /* Return a pointer to the object at p + Asking for the object at NULL will return NULL harmlessly. + */ + __out_opt void *GetI(__in_opt POSITION p) const; + __out void *GetValidI(__in POSITION p) const; + +public: + /* return the next / prev position in *this + return NULL when going past the end/start. + Next(NULL) is same as GetHeadPosition() + Prev(NULL) is same as GetTailPosition() + An n element list therefore behaves like a n+1 element + cycle with NULL at the start/end. + + !!WARNING!! - This handling of NULL is DIFFERENT from GetNext. + + Some reasons are: + 1. For a list of n items there are n+1 positions to insert + These are conveniently encoded as the n POSITIONs and NULL. + 2. If you are keeping a list sorted (fairly common) and you + search forward for an element to insert before and don't + find it you finish up with NULL as the element before which + to insert. You then want that NULL to be a valid POSITION + so that you can insert before it and you want that insertion + point to mean the (n+1)-th one that doesn't have a POSITION. + (symmetrically if you are working backwards through the list). + 3. It simplifies the algebra which the methods generate. + e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x) + in ALL cases. All the other arguments probably are reflections + of the algebraic point. + */ + __out_opt POSITION Next(__in_opt POSITION pos) const + { + if (pos == NULL) { + return (POSITION) m_pFirst; + } + CNode *pn = (CNode *) pos; + return (POSITION) pn->Next(); + } //Next + + // See Next + __out_opt POSITION Prev(__in_opt POSITION pos) const + { + if (pos == NULL) { + return (POSITION) m_pLast; + } + CNode *pn = (CNode *) pos; + return (POSITION) pn->Prev(); + } //Prev + + + /* Return the first position in *this which holds the given + pointer. Return NULL if the pointer was not not found. + */ +protected: + __out_opt POSITION FindI( __in void * pObj) const; + + // ??? Should there be (or even should there be only) + // ??? POSITION FindNextAfter(void * pObj, POSITION p) + // ??? And of course FindPrevBefore too. + // ??? List.Find(&Obj) then becomes List.FindNextAfter(&Obj, NULL) + + + /* Remove the first node in *this (deletes the pointer to its + object from the list, does not free the object itself). + Return the pointer to its object. + If *this was already empty it will harmlessly return NULL. + */ + __out_opt void *RemoveHeadI(); + + + /* Remove the last node in *this (deletes the pointer to its + object from the list, does not free the object itself). + Return the pointer to its object. + If *this was already empty it will harmlessly return NULL. + */ + __out_opt void *RemoveTailI(); + + + /* Remove the node identified by p from the list (deletes the pointer + to its object from the list, does not free the object itself). + Asking to Remove the object at NULL will harmlessly return NULL. + Return the pointer to the object removed. + */ + __out_opt void *RemoveI(__in_opt POSITION p); + + /* Add single object *pObj to become a new last element of the list. + Return the new tail position, NULL if it fails. + If you are adding a COM objects, you might want AddRef it first. + Other existing POSITIONs in *this are still valid + */ + __out_opt POSITION AddTailI(__in void * pObj); +public: + + + /* Add all the elements in *pList to the tail of *this. + This duplicates all the nodes in *pList (i.e. duplicates + all its pointers to objects). It does not duplicate the objects. + If you are adding a list of pointers to a COM object into the list + it's a good idea to AddRef them all it when you AddTail it. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. + Existing POSITIONs in *this are still valid + + If you actually want to MOVE the elements, use MoveToTail instead. + */ + BOOL AddTail(__in CBaseList *pList); + + + /* Mirror images of AddHead: */ + + /* Add single object to become a new first element of the list. + Return the new head position, NULL if it fails. + Existing POSITIONs in *this are still valid + */ +protected: + __out_opt POSITION AddHeadI(__in void * pObj); +public: + + /* Add all the elements in *pList to the head of *this. + Same warnings apply as for AddTail. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some of the objects may have been added. + + If you actually want to MOVE the elements, use MoveToHead instead. + */ + BOOL AddHead(__in CBaseList *pList); + + + /* Add the object *pObj to *this after position p in *this. + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return the position of the object added, NULL if it failed. + Existing POSITIONs in *this are undisturbed, including p. + */ +protected: + __out_opt POSITION AddAfterI(__in_opt POSITION p, __in void * pObj); +public: + + /* Add the list *pList to *this after position p in *this + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return TRUE if it all worked, FALSE if it didn't. + If it fails, some of the objects may be added + Existing POSITIONs in *this are undisturbed, including p. + */ + BOOL AddAfter(__in_opt POSITION p, __in CBaseList *pList); + + + /* Mirror images: + Add the object *pObj to this-List after position p in *this. + AddBefore(NULL,x) adds x to the end - equivalent to AddTail + Return the position of the new object, NULL if it fails + Existing POSITIONs in *this are undisturbed, including p. + */ + protected: + __out_opt POSITION AddBeforeI(__in_opt POSITION p, __in void * pObj); + public: + + /* Add the list *pList to *this before position p in *this + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return TRUE if it all worked, FALSE if it didn't. + If it fails, some of the objects may be added + Existing POSITIONs in *this are undisturbed, including p. + */ + BOOL AddBefore(__in_opt POSITION p, __in CBaseList *pList); + + + /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x) + even in cases where p is NULL or Next(p) is NULL. + Similarly for mirror images etc. + This may make it easier to argue about programs. + */ + + + + /* The following operations do not copy any elements. + They move existing blocks of elements around by switching pointers. + They are fairly efficient for long lists as for short lists. + (Alas, the Count slows things down). + + They split the list into two parts. + One part remains as the original list, the other part + is appended to the second list. There are eight possible + variations: + Split the list {after/before} a given element + keep the {head/tail} portion in the original list + append the rest to the {head/tail} of the new list. + + Since After is strictly equivalent to Before Next + we are not in serious need of the Before/After variants. + That leaves only four. + + If you are processing a list left to right and dumping + the bits that you have processed into another list as + you go, the Tail/Tail variant gives the most natural result. + If you are processing in reverse order, Head/Head is best. + + By using NULL positions and empty lists judiciously either + of the other two can be built up in two operations. + + The definition of NULL (see Next/Prev etc) means that + degenerate cases include + "move all elements to new list" + "Split a list into two lists" + "Concatenate two lists" + (and quite a few no-ops) + + !!WARNING!! The type checking won't buy you much if you get list + positions muddled up - e.g. use a POSITION that's in a different + list and see what a mess you get! + */ + + /* Split *this after position p in *this + Retain as *this the tail portion of the original *this + Add the head portion to the tail end of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToTail(foo->GetHeadPosition(), bar); + moves one element from the head of foo to the tail of bar + foo->MoveToTail(NULL, bar); + is a no-op, returns NULL + foo->MoveToTail(foo->GetTailPosition, bar); + concatenates foo onto the end of bar and empties foo. + + A better, except excessively long name might be + MoveElementsFromHeadThroughPositionToOtherTail + */ + BOOL MoveToTail(__in_opt POSITION pos, __in CBaseList *pList); + + + /* Mirror image: + Split *this before position p in *this. + Retain in *this the head portion of the original *this + Add the tail portion to the start (i.e. head) of *pList + + e.g. + foo->MoveToHead(foo->GetTailPosition(), bar); + moves one element from the tail of foo to the head of bar + foo->MoveToHead(NULL, bar); + is a no-op, returns NULL + foo->MoveToHead(foo->GetHeadPosition, bar); + concatenates foo onto the start of bar and empties foo. + */ + BOOL MoveToHead(__in_opt POSITION pos, __in CBaseList *pList); + + + /* Reverse the order of the [pointers to] objects in *this + */ + void Reverse(); + + + /* set cursor to the position of each element of list in turn */ + #define TRAVERSELIST(list, cursor) \ + for ( cursor = (list).GetHeadPosition() \ + ; cursor!=NULL \ + ; cursor = (list).Next(cursor) \ + ) + + + /* set cursor to the position of each element of list in turn + in reverse order + */ + #define REVERSETRAVERSELIST(list, cursor) \ + for ( cursor = (list).GetTailPosition() \ + ; cursor!=NULL \ + ; cursor = (list).Prev(cursor) \ + ) + +}; // end of class declaration + +template class CGenericList : public CBaseList +{ +public: + CGenericList(__in_opt LPCTSTR pName, + INT iItems, + BOOL bLock = TRUE, + BOOL bAlert = FALSE) : + CBaseList(pName, iItems) { + UNREFERENCED_PARAMETER(bAlert); + UNREFERENCED_PARAMETER(bLock); + }; + CGenericList(__in_opt LPCTSTR pName) : + CBaseList(pName) { + }; + + __out_opt POSITION GetHeadPosition() const { return (POSITION)m_pFirst; } + __out_opt POSITION GetTailPosition() const { return (POSITION)m_pLast; } + int GetCount() const { return m_Count; } + + __out OBJECT *GetNext(__inout POSITION& rp) const { return (OBJECT *) GetNextI(rp); } + + __out_opt OBJECT *Get(__in_opt POSITION p) const { return (OBJECT *) GetI(p); } + __out OBJECT *GetValid(__in POSITION p) const { return (OBJECT *) GetValidI(p); } + __out_opt OBJECT *GetHead() const { return Get(GetHeadPosition()); } + + __out_opt OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); } + + __out_opt OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); } + + __out_opt OBJECT *Remove(__in_opt POSITION p) { return (OBJECT *) RemoveI(p); } + __out_opt POSITION AddBefore(__in_opt POSITION p, __in OBJECT * pObj) { return AddBeforeI(p, pObj); } + __out_opt POSITION AddAfter(__in_opt POSITION p, __in OBJECT * pObj) { return AddAfterI(p, pObj); } + __out_opt POSITION AddHead(__in OBJECT * pObj) { return AddHeadI(pObj); } + __out_opt POSITION AddTail(__in OBJECT * pObj) { return AddTailI(pObj); } + BOOL AddTail(__in CGenericList *pList) + { return CBaseList::AddTail((CBaseList *) pList); } + BOOL AddHead(__in CGenericList *pList) + { return CBaseList::AddHead((CBaseList *) pList); } + BOOL AddAfter(__in_opt POSITION p, __in CGenericList *pList) + { return CBaseList::AddAfter(p, (CBaseList *) pList); }; + BOOL AddBefore(__in_opt POSITION p, __in CGenericList *pList) + { return CBaseList::AddBefore(p, (CBaseList *) pList); }; + __out_opt POSITION Find( __in OBJECT * pObj) const { return FindI(pObj); } +}; // end of class declaration + + + +/* These define the standard list types */ + +typedef CGenericList CBaseObjectList; +typedef CGenericList CBaseInterfaceList; + +#endif /* __WXLIST__ */ + diff --git a/src/thirdparty/BaseClasses/wxutil.cpp b/src/thirdparty/BaseClasses/wxutil.cpp index 89333c95382..ff645d09fb2 100644 --- a/src/thirdparty/BaseClasses/wxutil.cpp +++ b/src/thirdparty/BaseClasses/wxutil.cpp @@ -1,772 +1,772 @@ -//------------------------------------------------------------------------------ -// File: WXUtil.cpp -// -// Desc: DirectShow base classes - implements helper classes for building -// multimedia filters. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#define STRSAFE_NO_DEPRECATE -#include -#include //MPC-HC patch - - -// --- CAMEvent ----------------------- -CAMEvent::CAMEvent(BOOL fManualReset, __inout_opt HRESULT *phr) -{ - m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL); - if (NULL == m_hEvent) { - if (NULL != phr && SUCCEEDED(*phr)) { - *phr = E_OUTOFMEMORY; - } - } -} - -CAMEvent::CAMEvent(__inout_opt HRESULT *phr) -{ - m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (NULL == m_hEvent) { - if (NULL != phr && SUCCEEDED(*phr)) { - *phr = E_OUTOFMEMORY; - } - } -} - -CAMEvent::~CAMEvent() -{ - if (m_hEvent) { - EXECUTE_ASSERT(CloseHandle(m_hEvent)); - } -} - - -// --- CAMMsgEvent ----------------------- -// One routine. The rest is handled in CAMEvent - -CAMMsgEvent::CAMMsgEvent(__inout_opt HRESULT *phr) : CAMEvent(FALSE, phr) -{ -} - -BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) -{ - // wait for the event to be signalled, or for the - // timeout (in MS) to expire. allow SENT messages - // to be processed while we wait - DWORD dwWait; - DWORD dwStartTime = 0; - - // set the waiting period. - DWORD dwWaitTime = dwTimeout; - - // the timeout will eventually run down as we iterate - // processing messages. grab the start time so that - // we can calculate elapsed times. - if (dwWaitTime != INFINITE) { - dwStartTime = timeGetTime(); - } - - do { - dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE); - if (dwWait == WAIT_OBJECT_0 + 1) { - MSG Message; - PeekMessage(&Message,NULL,0,0,PM_NOREMOVE); - - // If we have an explicit length of time to wait calculate - // the next wake up point - which might be now. - // If dwTimeout is INFINITE, it stays INFINITE - if (dwWaitTime != INFINITE) { - - DWORD dwElapsed = timeGetTime()-dwStartTime; - - dwWaitTime = - (dwElapsed >= dwTimeout) - ? 0 // wake up with WAIT_TIMEOUT - : dwTimeout-dwElapsed; - } - } - } while (dwWait == WAIT_OBJECT_0 + 1); - - // return TRUE if we woke on the event handle, - // FALSE if we timed out. - return (dwWait == WAIT_OBJECT_0); -} - -// --- CAMThread ---------------------- - - -CAMThread::CAMThread(__inout_opt HRESULT *phr) - : m_EventSend(TRUE, phr), // must be manual-reset for CheckRequest() - m_EventComplete(FALSE, phr), - m_hThread(NULL), - m_dwParam(0), - m_dwReturnVal(0) -{ -} - -CAMThread::~CAMThread() { - Close(); -} - - -// when the thread starts, it calls this function. We unwrap the 'this' -//pointer and call ThreadProc. -unsigned int WINAPI //MPC-HC patch -CAMThread::InitialThreadProc(__inout LPVOID pv) -{ - HRESULT hrCoInit = CAMThread::CoInitializeHelper(); - if(FAILED(hrCoInit)) { - DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed."))); - } - - CAMThread * pThread = (CAMThread *) pv; - - HRESULT hr = pThread->ThreadProc(); - - if(SUCCEEDED(hrCoInit)) { - CoUninitialize(); - } - - return hr; -} - -BOOL -CAMThread::Create() -{ - CAutoLock lock(&m_AccessLock); - - if (ThreadExists()) { - return FALSE; - } - - //MPC-HC patch - m_hThread = (HANDLE)_beginthreadex( NULL, /* Security */ - 0, /* Stack Size */ - CAMThread::InitialThreadProc, /* Thread process */ - (LPVOID)this, /* Arguments */ - 0, /* 0 = Start Immediately */ - NULL /* Thread Address */ - ); - - if (!m_hThread) { - return FALSE; - } - - return TRUE; -} - -DWORD -CAMThread::CallWorker(DWORD dwParam) -{ - // lock access to the worker thread for scope of this object - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return (DWORD) E_FAIL; - } - - // set the parameter - m_dwParam = dwParam; - - // signal the worker thread - m_EventSend.Set(); - - // wait for the completion to be signalled - m_EventComplete.Wait(); - - // done - this is the thread's return value - return m_dwReturnVal; -} - -// Wait for a request from the client -DWORD -CAMThread::GetRequest() -{ - m_EventSend.Wait(); - return m_dwParam; -} - -// is there a request? -BOOL -CAMThread::CheckRequest(__out_opt DWORD * pParam) -{ - if (!m_EventSend.Check()) { - return FALSE; - } else { - if (pParam) { - *pParam = m_dwParam; - } - return TRUE; - } -} - -// reply to the request -void -CAMThread::Reply(DWORD dw) -{ - m_dwReturnVal = dw; - - // The request is now complete so CheckRequest should fail from - // now on - // - // This event should be reset BEFORE we signal the client or - // the client may Set it before we reset it and we'll then - // reset it (!) - - m_EventSend.Reset(); - - // Tell the client we're finished - - m_EventComplete.Set(); -} - -HRESULT CAMThread::CoInitializeHelper() -{ - // call CoInitializeEx and tell OLE not to create a window (this - // thread probably won't dispatch messages and will hang on - // broadcast msgs o/w). - // - // If CoInitEx is not available, threads that don't call CoCreate - // aren't affected. Threads that do will have to handle the - // failure. Perhaps we should fall back to CoInitialize and risk - // hanging? - // - - // older versions of ole32.dll don't have CoInitializeEx - - HRESULT hr = E_FAIL; - HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll")); - if(hOle) - { - typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)( - LPVOID pvReserved, DWORD dwCoInit); - PCoInitializeEx pCoInitializeEx = - (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx")); - if(pCoInitializeEx) - { - hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE ); - } - } - else - { - // caller must load ole32.dll - DbgBreak("couldn't locate ole32.dll"); - } - - return hr; -} - - -// destructor for CMsgThread - cleans up any messages left in the -// queue when the thread exited -CMsgThread::~CMsgThread() -{ - if (m_hThread != NULL) { - WaitForSingleObject(m_hThread, INFINITE); - EXECUTE_ASSERT(CloseHandle(m_hThread)); - } - - POSITION pos = m_ThreadQueue.GetHeadPosition(); - while (pos) { - CMsg * pMsg = m_ThreadQueue.GetNext(pos); - delete pMsg; - } - m_ThreadQueue.RemoveAll(); - - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } -} - -BOOL -CMsgThread::CreateThread( - ) -{ - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - return FALSE; - } - - m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc, - (LPVOID)this, 0, &m_ThreadId); - return m_hThread != NULL; -} - - -// This is the threads message pump. Here we get and dispatch messages to -// clients thread proc until the client refuses to process a message. -// The client returns a non-zero value to stop the message pump, this -// value becomes the threads exit code. - -DWORD WINAPI -CMsgThread::DefaultThreadProc( - __inout LPVOID lpParam - ) -{ - CMsgThread *lpThis = (CMsgThread *)lpParam; - CMsg msg; - LRESULT lResult; - - // !!! - CoInitialize(NULL); - - // allow a derived class to handle thread startup - lpThis->OnThreadInit(); - - do { - lpThis->GetThreadMsg(&msg); - lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags, - msg.lpParam, msg.pEvent); - } while (lResult == 0L); - - // !!! - CoUninitialize(); - - return (DWORD)lResult; -} - - -// Block until the next message is placed on the list m_ThreadQueue. -// copies the message to the message pointed to by *pmsg -void -CMsgThread::GetThreadMsg(__out CMsg *msg) -{ - CMsg * pmsg = NULL; - - // keep trying until a message appears - for (;;) { - { - CAutoLock lck(&m_Lock); - pmsg = m_ThreadQueue.RemoveHead(); - if (pmsg == NULL) { - m_lWaiting++; - } else { - break; - } - } - // the semaphore will be signaled when it is non-empty - WaitForSingleObject(m_hSem, INFINITE); - } - // copy fields to caller's CMsg - *msg = *pmsg; - - // this CMsg was allocated by the 'new' in PutThreadMsg - delete pmsg; - -} - -// Helper function - convert int to WSTR -void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr) -{ -#ifdef UNICODE - if (FAILED(StringCchPrintf(wstr, 12, L"%d", i))) { - wstr[0] = 0; - } -#else - TCHAR temp[12]; - if (FAILED(StringCchPrintf(temp, NUMELMS(temp), "%d", i))) { - wstr[0] = 0; - } else { - MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, 12); - } -#endif -} // IntToWstr - - -#define MEMORY_ALIGNMENT 4 -#define MEMORY_ALIGNMENT_LOG2 2 -#define MEMORY_ALIGNMENT_MASK MEMORY_ALIGNMENT - 1 - -void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) -{ - void * ret = dst; - -#ifdef _X86_ - if (dst <= src || (char *)dst >= ((char *)src + count)) { - - /* - * Non-Overlapping Buffers - * copy from lower addresses to higher addresses - */ - _asm { - mov esi,src - mov edi,dst - mov ecx,count - cld - mov edx,ecx - and edx,MEMORY_ALIGNMENT_MASK - shr ecx,MEMORY_ALIGNMENT_LOG2 - rep movsd - or ecx,edx - jz memmove_done - rep movsb -memmove_done: - } - } - else { - - /* - * Overlapping Buffers - * copy from higher addresses to lower addresses - */ - _asm { - mov esi,src - mov edi,dst - mov ecx,count - std - add esi,ecx - add edi,ecx - dec esi - dec edi - rep movsb - cld - } - } -#else - MoveMemory(dst, src, count); -#endif - - return ret; -} - -HRESULT AMSafeMemMoveOffset( - __in_bcount(dst_size) void * dst, - __in size_t dst_size, - __in DWORD cb_dst_offset, - __in_bcount(src_size) const void * src, - __in size_t src_size, - __in DWORD cb_src_offset, - __in size_t count) -{ - // prevent read overruns - if( count + cb_src_offset < count || // prevent integer overflow - count + cb_src_offset > src_size) // prevent read overrun - { - return E_INVALIDARG; - } - - // prevent write overruns - if( count + cb_dst_offset < count || // prevent integer overflow - count + cb_dst_offset > dst_size) // prevent write overrun - { - return E_INVALIDARG; - } - - memmoveInternal( (BYTE *)dst+cb_dst_offset, (BYTE *)src+cb_src_offset, count); - return S_OK; -} - - -#ifdef _DEBUG -/******************************Public*Routine******************************\ -* Debug CCritSec helpers -* -* We provide debug versions of the Constructor, destructor, Lock and Unlock -* routines. The debug code tracks who owns each critical section by -* maintaining a depth count. -* -* History: -* -\**************************************************************************/ - -CCritSec::CCritSec() -{ - InitializeCriticalSection(&m_CritSec); - m_currentOwner = m_lockCount = 0; - m_fTrace = FALSE; -} - -CCritSec::~CCritSec() -{ - DeleteCriticalSection(&m_CritSec); -} - -void CCritSec::Lock() -{ - UINT tracelevel=3; - DWORD us = GetCurrentThreadId(); - DWORD currentOwner = m_currentOwner; - if (currentOwner && (currentOwner != us)) { - // already owned, but not by us - if (m_fTrace) { - DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"), - GetCurrentThreadId(), &m_CritSec, currentOwner)); - tracelevel=2; - // if we saw the message about waiting for the critical - // section we ensure we see the message when we get the - // critical section - } - } - EnterCriticalSection(&m_CritSec); - if (0 == m_lockCount++) { - // we now own it for the first time. Set owner information - m_currentOwner = us; - - if (m_fTrace) { - DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec)); - } - } -} - -void CCritSec::Unlock() { - if (0 == --m_lockCount) { - // about to be unowned - if (m_fTrace) { - DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec)); - } - - m_currentOwner = 0; - } - LeaveCriticalSection(&m_CritSec); -} - -void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) -{ - pcCrit->m_fTrace = fTrace; -} - -BOOL WINAPI CritCheckIn(CCritSec * pcCrit) -{ - return (GetCurrentThreadId() == pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) -{ - return (GetCurrentThreadId() == pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckOut(CCritSec * pcCrit) -{ - return (GetCurrentThreadId() != pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) -{ - return (GetCurrentThreadId() != pcCrit->m_currentOwner); -} -#endif - - -STDAPI WriteBSTR(__deref_out BSTR *pstrDest, LPCWSTR szSrc) -{ - *pstrDest = SysAllocString( szSrc ); - if( !(*pstrDest) ) return E_OUTOFMEMORY; - return NOERROR; -} - - -STDAPI FreeBSTR(__deref_in BSTR* pstr) -{ - if( (PVOID)*pstr == NULL ) return S_FALSE; - SysFreeString( *pstr ); - *pstr = NULL; - return NOERROR; -} - - -// Return a wide string - allocating memory for it -// Returns: -// S_OK - no error -// E_POINTER - ppszReturn == NULL -// E_OUTOFMEMORY - can't allocate memory for returned string -STDAPI AMGetWideString(LPCWSTR psz, __deref_out LPWSTR *ppszReturn) -{ - CheckPointer(ppszReturn, E_POINTER); - ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR)); - *ppszReturn = NULL; - size_t nameLen; - HRESULT hr = StringCbLengthW(psz, 100000, &nameLen); - if (FAILED(hr)) { - return hr; - } - *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen + sizeof(WCHAR)); - if (*ppszReturn == NULL) { - return E_OUTOFMEMORY; - } - CopyMemory(*ppszReturn, psz, nameLen + sizeof(WCHAR)); - return NOERROR; -} - -// Waits for the HANDLE hObject. While waiting messages sent -// to windows on our thread by SendMessage will be processed. -// Using this function to do waits and mutual exclusion -// avoids some deadlocks in objects with windows. -// Return codes are the same as for WaitForSingleObject -DWORD WINAPI WaitDispatchingMessages( - HANDLE hObject, - DWORD dwWait, - HWND hwnd, - UINT uMsg, - HANDLE hEvent) -{ - BOOL bPeeked = FALSE; - DWORD dwResult; - DWORD dwStart = 0; - DWORD dwThreadPriority = THREAD_PRIORITY_NORMAL; - - static UINT uMsgId = 0; - - HANDLE hObjects[2] = { hObject, hEvent }; - if (dwWait != INFINITE && dwWait != 0) { - dwStart = GetTickCount(); - } - for (; ; ) { - DWORD nCount = NULL != hEvent ? 2 : 1; - - // Minimize the chance of actually dispatching any messages - // by seeing if we can lock immediately. - dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0); - if (dwResult < WAIT_OBJECT_0 + nCount) { - break; - } - - DWORD dwTimeOut = dwWait; - if (dwTimeOut > 10) { - dwTimeOut = 10; - } - dwResult = MsgWaitForMultipleObjects( - nCount, - hObjects, - FALSE, - dwTimeOut, - hwnd == NULL ? QS_SENDMESSAGE : - QS_SENDMESSAGE + QS_POSTMESSAGE); - if (dwResult == WAIT_OBJECT_0 + nCount || - dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) { - MSG msg; - if (hwnd != NULL) { - while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) { - DispatchMessage(&msg); - } - } - // Do this anyway - the previous peek doesn't flush out the - // messages - PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); - - if (dwWait != INFINITE && dwWait != 0) { - DWORD dwNow = GetTickCount(); - - // Working with differences handles wrap-around - DWORD dwDiff = dwNow - dwStart; - if (dwDiff > dwWait) { - dwWait = 0; - } else { - dwWait -= dwDiff; - } - dwStart = dwNow; - } - if (!bPeeked) { - // Raise our priority to prevent our message queue - // building up - dwThreadPriority = GetThreadPriority(GetCurrentThread()); - if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) { - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); - } - bPeeked = TRUE; - } - } else { - break; - } - } - if (bPeeked) { - SetThreadPriority(GetCurrentThread(), dwThreadPriority); - if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { - if (uMsgId == 0) { - uMsgId = RegisterWindowMessage(TEXT("AMUnblock")); - } - if (uMsgId != 0) { - MSG msg; - // Remove old ones - while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) { - } - } - PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0); - } - } - return dwResult; -} - -HRESULT AmGetLastErrorToHResult() -{ - DWORD dwLastError = GetLastError(); - if(dwLastError != 0) - { - return HRESULT_FROM_WIN32(dwLastError); - } - else - { - return E_FAIL; - } -} - -IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp) -{ - if (lp != NULL) - lp->AddRef(); - if (*pp) - (*pp)->Release(); - *pp = lp; - return lp; -} - -/****************************************************************************** - -CompatibleTimeSetEvent - - CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling -timeSetEvent() if the current operating system supports it. TIME_KILL_SYNCHRONOUS -is supported on Windows XP and later operating systems. - -Parameters: -- The same parameters as timeSetEvent(). See timeSetEvent()'s documentation in -the Platform SDK for more information. - -Return Value: -- The same return value as timeSetEvent(). See timeSetEvent()'s documentation in -the Platform SDK for more information. - -******************************************************************************/ -MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) -{ - #if WINVER >= 0x0501 - { - static bool fCheckedVersion = false; - static bool fTimeKillSynchronousFlagAvailable = false; - - if( !fCheckedVersion ) { - fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable(); - fCheckedVersion = true; - } - - if( fTimeKillSynchronousFlagAvailable ) { - fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS; - } - } - #endif // WINVER >= 0x0501 - - return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent ); -} - -bool TimeKillSynchronousFlagAvailable( void ) -{ - OSVERSIONINFO osverinfo; - - osverinfo.dwOSVersionInfoSize = sizeof(osverinfo); - - if( GetVersionEx( &osverinfo ) ) { - - // Windows XP's major version is 5 and its' minor version is 1. - // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag - // in Windows XP. - if( (osverinfo.dwMajorVersion > 5) || - ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) { - return true; - } - } - - return false; -} - - +//------------------------------------------------------------------------------ +// File: WXUtil.cpp +// +// Desc: DirectShow base classes - implements helper classes for building +// multimedia filters. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#define STRSAFE_NO_DEPRECATE +#include +#include //MPC-HC patch + + +// --- CAMEvent ----------------------- +CAMEvent::CAMEvent(BOOL fManualReset, __inout_opt HRESULT *phr) +{ + m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL); + if (NULL == m_hEvent) { + if (NULL != phr && SUCCEEDED(*phr)) { + *phr = E_OUTOFMEMORY; + } + } +} + +CAMEvent::CAMEvent(__inout_opt HRESULT *phr) +{ + m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (NULL == m_hEvent) { + if (NULL != phr && SUCCEEDED(*phr)) { + *phr = E_OUTOFMEMORY; + } + } +} + +CAMEvent::~CAMEvent() +{ + if (m_hEvent) { + EXECUTE_ASSERT(CloseHandle(m_hEvent)); + } +} + + +// --- CAMMsgEvent ----------------------- +// One routine. The rest is handled in CAMEvent + +CAMMsgEvent::CAMMsgEvent(__inout_opt HRESULT *phr) : CAMEvent(FALSE, phr) +{ +} + +BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) +{ + // wait for the event to be signalled, or for the + // timeout (in MS) to expire. allow SENT messages + // to be processed while we wait + DWORD dwWait; + DWORD dwStartTime = 0; + + // set the waiting period. + DWORD dwWaitTime = dwTimeout; + + // the timeout will eventually run down as we iterate + // processing messages. grab the start time so that + // we can calculate elapsed times. + if (dwWaitTime != INFINITE) { + dwStartTime = timeGetTime(); + } + + do { + dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE); + if (dwWait == WAIT_OBJECT_0 + 1) { + MSG Message; + PeekMessage(&Message,NULL,0,0,PM_NOREMOVE); + + // If we have an explicit length of time to wait calculate + // the next wake up point - which might be now. + // If dwTimeout is INFINITE, it stays INFINITE + if (dwWaitTime != INFINITE) { + + DWORD dwElapsed = timeGetTime()-dwStartTime; + + dwWaitTime = + (dwElapsed >= dwTimeout) + ? 0 // wake up with WAIT_TIMEOUT + : dwTimeout-dwElapsed; + } + } + } while (dwWait == WAIT_OBJECT_0 + 1); + + // return TRUE if we woke on the event handle, + // FALSE if we timed out. + return (dwWait == WAIT_OBJECT_0); +} + +// --- CAMThread ---------------------- + + +CAMThread::CAMThread(__inout_opt HRESULT *phr) + : m_EventSend(TRUE, phr), // must be manual-reset for CheckRequest() + m_EventComplete(FALSE, phr), + m_hThread(NULL), + m_dwParam(0), + m_dwReturnVal(0) +{ +} + +CAMThread::~CAMThread() { + Close(); +} + + +// when the thread starts, it calls this function. We unwrap the 'this' +//pointer and call ThreadProc. +unsigned int WINAPI //MPC-HC patch +CAMThread::InitialThreadProc(__inout LPVOID pv) +{ + HRESULT hrCoInit = CAMThread::CoInitializeHelper(); + if(FAILED(hrCoInit)) { + DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed."))); + } + + CAMThread * pThread = (CAMThread *) pv; + + HRESULT hr = pThread->ThreadProc(); + + if(SUCCEEDED(hrCoInit)) { + CoUninitialize(); + } + + return hr; +} + +BOOL +CAMThread::Create() +{ + CAutoLock lock(&m_AccessLock); + + if (ThreadExists()) { + return FALSE; + } + + //MPC-HC patch + m_hThread = (HANDLE)_beginthreadex( NULL, /* Security */ + 0, /* Stack Size */ + CAMThread::InitialThreadProc, /* Thread process */ + (LPVOID)this, /* Arguments */ + 0, /* 0 = Start Immediately */ + NULL /* Thread Address */ + ); + + if (!m_hThread) { + return FALSE; + } + + return TRUE; +} + +DWORD +CAMThread::CallWorker(DWORD dwParam) +{ + // lock access to the worker thread for scope of this object + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return (DWORD) E_FAIL; + } + + // set the parameter + m_dwParam = dwParam; + + // signal the worker thread + m_EventSend.Set(); + + // wait for the completion to be signalled + m_EventComplete.Wait(); + + // done - this is the thread's return value + return m_dwReturnVal; +} + +// Wait for a request from the client +DWORD +CAMThread::GetRequest() +{ + m_EventSend.Wait(); + return m_dwParam; +} + +// is there a request? +BOOL +CAMThread::CheckRequest(__out_opt DWORD * pParam) +{ + if (!m_EventSend.Check()) { + return FALSE; + } else { + if (pParam) { + *pParam = m_dwParam; + } + return TRUE; + } +} + +// reply to the request +void +CAMThread::Reply(DWORD dw) +{ + m_dwReturnVal = dw; + + // The request is now complete so CheckRequest should fail from + // now on + // + // This event should be reset BEFORE we signal the client or + // the client may Set it before we reset it and we'll then + // reset it (!) + + m_EventSend.Reset(); + + // Tell the client we're finished + + m_EventComplete.Set(); +} + +HRESULT CAMThread::CoInitializeHelper() +{ + // call CoInitializeEx and tell OLE not to create a window (this + // thread probably won't dispatch messages and will hang on + // broadcast msgs o/w). + // + // If CoInitEx is not available, threads that don't call CoCreate + // aren't affected. Threads that do will have to handle the + // failure. Perhaps we should fall back to CoInitialize and risk + // hanging? + // + + // older versions of ole32.dll don't have CoInitializeEx + + HRESULT hr = E_FAIL; + HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll")); + if(hOle) + { + typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)( + LPVOID pvReserved, DWORD dwCoInit); + PCoInitializeEx pCoInitializeEx = + (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx")); + if(pCoInitializeEx) + { + hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE ); + } + } + else + { + // caller must load ole32.dll + DbgBreak("couldn't locate ole32.dll"); + } + + return hr; +} + + +// destructor for CMsgThread - cleans up any messages left in the +// queue when the thread exited +CMsgThread::~CMsgThread() +{ + if (m_hThread != NULL) { + WaitForSingleObject(m_hThread, INFINITE); + EXECUTE_ASSERT(CloseHandle(m_hThread)); + } + + POSITION pos = m_ThreadQueue.GetHeadPosition(); + while (pos) { + CMsg * pMsg = m_ThreadQueue.GetNext(pos); + delete pMsg; + } + m_ThreadQueue.RemoveAll(); + + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } +} + +BOOL +CMsgThread::CreateThread( + ) +{ + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + return FALSE; + } + + m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc, + (LPVOID)this, 0, &m_ThreadId); + return m_hThread != NULL; +} + + +// This is the threads message pump. Here we get and dispatch messages to +// clients thread proc until the client refuses to process a message. +// The client returns a non-zero value to stop the message pump, this +// value becomes the threads exit code. + +DWORD WINAPI +CMsgThread::DefaultThreadProc( + __inout LPVOID lpParam + ) +{ + CMsgThread *lpThis = (CMsgThread *)lpParam; + CMsg msg; + LRESULT lResult; + + // !!! + CoInitialize(NULL); + + // allow a derived class to handle thread startup + lpThis->OnThreadInit(); + + do { + lpThis->GetThreadMsg(&msg); + lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags, + msg.lpParam, msg.pEvent); + } while (lResult == 0L); + + // !!! + CoUninitialize(); + + return (DWORD)lResult; +} + + +// Block until the next message is placed on the list m_ThreadQueue. +// copies the message to the message pointed to by *pmsg +void +CMsgThread::GetThreadMsg(__out CMsg *msg) +{ + CMsg * pmsg = NULL; + + // keep trying until a message appears + for (;;) { + { + CAutoLock lck(&m_Lock); + pmsg = m_ThreadQueue.RemoveHead(); + if (pmsg == NULL) { + m_lWaiting++; + } else { + break; + } + } + // the semaphore will be signaled when it is non-empty + WaitForSingleObject(m_hSem, INFINITE); + } + // copy fields to caller's CMsg + *msg = *pmsg; + + // this CMsg was allocated by the 'new' in PutThreadMsg + delete pmsg; + +} + +// Helper function - convert int to WSTR +void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr) +{ +#ifdef UNICODE + if (FAILED(StringCchPrintf(wstr, 12, L"%d", i))) { + wstr[0] = 0; + } +#else + TCHAR temp[12]; + if (FAILED(StringCchPrintf(temp, NUMELMS(temp), "%d", i))) { + wstr[0] = 0; + } else { + MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, 12); + } +#endif +} // IntToWstr + + +#define MEMORY_ALIGNMENT 4 +#define MEMORY_ALIGNMENT_LOG2 2 +#define MEMORY_ALIGNMENT_MASK MEMORY_ALIGNMENT - 1 + +void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) +{ + void * ret = dst; + +#ifdef _X86_ + if (dst <= src || (char *)dst >= ((char *)src + count)) { + + /* + * Non-Overlapping Buffers + * copy from lower addresses to higher addresses + */ + _asm { + mov esi,src + mov edi,dst + mov ecx,count + cld + mov edx,ecx + and edx,MEMORY_ALIGNMENT_MASK + shr ecx,MEMORY_ALIGNMENT_LOG2 + rep movsd + or ecx,edx + jz memmove_done + rep movsb +memmove_done: + } + } + else { + + /* + * Overlapping Buffers + * copy from higher addresses to lower addresses + */ + _asm { + mov esi,src + mov edi,dst + mov ecx,count + std + add esi,ecx + add edi,ecx + dec esi + dec edi + rep movsb + cld + } + } +#else + MoveMemory(dst, src, count); +#endif + + return ret; +} + +HRESULT AMSafeMemMoveOffset( + __in_bcount(dst_size) void * dst, + __in size_t dst_size, + __in DWORD cb_dst_offset, + __in_bcount(src_size) const void * src, + __in size_t src_size, + __in DWORD cb_src_offset, + __in size_t count) +{ + // prevent read overruns + if( count + cb_src_offset < count || // prevent integer overflow + count + cb_src_offset > src_size) // prevent read overrun + { + return E_INVALIDARG; + } + + // prevent write overruns + if( count + cb_dst_offset < count || // prevent integer overflow + count + cb_dst_offset > dst_size) // prevent write overrun + { + return E_INVALIDARG; + } + + memmoveInternal( (BYTE *)dst+cb_dst_offset, (BYTE *)src+cb_src_offset, count); + return S_OK; +} + + +#ifdef _DEBUG +/******************************Public*Routine******************************\ +* Debug CCritSec helpers +* +* We provide debug versions of the Constructor, destructor, Lock and Unlock +* routines. The debug code tracks who owns each critical section by +* maintaining a depth count. +* +* History: +* +\**************************************************************************/ + +CCritSec::CCritSec() +{ + InitializeCriticalSection(&m_CritSec); + m_currentOwner = m_lockCount = 0; + m_fTrace = FALSE; +} + +CCritSec::~CCritSec() +{ + DeleteCriticalSection(&m_CritSec); +} + +void CCritSec::Lock() +{ + UINT tracelevel=3; + DWORD us = GetCurrentThreadId(); + DWORD currentOwner = m_currentOwner; + if (currentOwner && (currentOwner != us)) { + // already owned, but not by us + if (m_fTrace) { + DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"), + GetCurrentThreadId(), &m_CritSec, currentOwner)); + tracelevel=2; + // if we saw the message about waiting for the critical + // section we ensure we see the message when we get the + // critical section + } + } + EnterCriticalSection(&m_CritSec); + if (0 == m_lockCount++) { + // we now own it for the first time. Set owner information + m_currentOwner = us; + + if (m_fTrace) { + DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec)); + } + } +} + +void CCritSec::Unlock() { + if (0 == --m_lockCount) { + // about to be unowned + if (m_fTrace) { + DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec)); + } + + m_currentOwner = 0; + } + LeaveCriticalSection(&m_CritSec); +} + +void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) +{ + pcCrit->m_fTrace = fTrace; +} + +BOOL WINAPI CritCheckIn(CCritSec * pcCrit) +{ + return (GetCurrentThreadId() == pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) +{ + return (GetCurrentThreadId() == pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckOut(CCritSec * pcCrit) +{ + return (GetCurrentThreadId() != pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) +{ + return (GetCurrentThreadId() != pcCrit->m_currentOwner); +} +#endif + + +STDAPI WriteBSTR(__deref_out BSTR *pstrDest, LPCWSTR szSrc) +{ + *pstrDest = SysAllocString( szSrc ); + if( !(*pstrDest) ) return E_OUTOFMEMORY; + return NOERROR; +} + + +STDAPI FreeBSTR(__deref_in BSTR* pstr) +{ + if( (PVOID)*pstr == NULL ) return S_FALSE; + SysFreeString( *pstr ); + *pstr = NULL; + return NOERROR; +} + + +// Return a wide string - allocating memory for it +// Returns: +// S_OK - no error +// E_POINTER - ppszReturn == NULL +// E_OUTOFMEMORY - can't allocate memory for returned string +STDAPI AMGetWideString(LPCWSTR psz, __deref_out LPWSTR *ppszReturn) +{ + CheckPointer(ppszReturn, E_POINTER); + ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR)); + *ppszReturn = NULL; + size_t nameLen; + HRESULT hr = StringCbLengthW(psz, 100000, &nameLen); + if (FAILED(hr)) { + return hr; + } + *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen + sizeof(WCHAR)); + if (*ppszReturn == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(*ppszReturn, psz, nameLen + sizeof(WCHAR)); + return NOERROR; +} + +// Waits for the HANDLE hObject. While waiting messages sent +// to windows on our thread by SendMessage will be processed. +// Using this function to do waits and mutual exclusion +// avoids some deadlocks in objects with windows. +// Return codes are the same as for WaitForSingleObject +DWORD WINAPI WaitDispatchingMessages( + HANDLE hObject, + DWORD dwWait, + HWND hwnd, + UINT uMsg, + HANDLE hEvent) +{ + BOOL bPeeked = FALSE; + DWORD dwResult; + DWORD dwStart = 0; + DWORD dwThreadPriority = THREAD_PRIORITY_NORMAL; + + static UINT uMsgId = 0; + + HANDLE hObjects[2] = { hObject, hEvent }; + if (dwWait != INFINITE && dwWait != 0) { + dwStart = GetTickCount(); + } + for (; ; ) { + DWORD nCount = NULL != hEvent ? 2 : 1; + + // Minimize the chance of actually dispatching any messages + // by seeing if we can lock immediately. + dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0); + if (dwResult < WAIT_OBJECT_0 + nCount) { + break; + } + + DWORD dwTimeOut = dwWait; + if (dwTimeOut > 10) { + dwTimeOut = 10; + } + dwResult = MsgWaitForMultipleObjects( + nCount, + hObjects, + FALSE, + dwTimeOut, + hwnd == NULL ? QS_SENDMESSAGE : + QS_SENDMESSAGE + QS_POSTMESSAGE); + if (dwResult == WAIT_OBJECT_0 + nCount || + dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) { + MSG msg; + if (hwnd != NULL) { + while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) { + DispatchMessage(&msg); + } + } + // Do this anyway - the previous peek doesn't flush out the + // messages + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); + + if (dwWait != INFINITE && dwWait != 0) { + DWORD dwNow = GetTickCount(); + + // Working with differences handles wrap-around + DWORD dwDiff = dwNow - dwStart; + if (dwDiff > dwWait) { + dwWait = 0; + } else { + dwWait -= dwDiff; + } + dwStart = dwNow; + } + if (!bPeeked) { + // Raise our priority to prevent our message queue + // building up + dwThreadPriority = GetThreadPriority(GetCurrentThread()); + if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + } + bPeeked = TRUE; + } + } else { + break; + } + } + if (bPeeked) { + SetThreadPriority(GetCurrentThread(), dwThreadPriority); + if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { + if (uMsgId == 0) { + uMsgId = RegisterWindowMessage(TEXT("AMUnblock")); + } + if (uMsgId != 0) { + MSG msg; + // Remove old ones + while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) { + } + } + PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0); + } + } + return dwResult; +} + +HRESULT AmGetLastErrorToHResult() +{ + DWORD dwLastError = GetLastError(); + if(dwLastError != 0) + { + return HRESULT_FROM_WIN32(dwLastError); + } + else + { + return E_FAIL; + } +} + +IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp) +{ + if (lp != NULL) + lp->AddRef(); + if (*pp) + (*pp)->Release(); + *pp = lp; + return lp; +} + +/****************************************************************************** + +CompatibleTimeSetEvent + + CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling +timeSetEvent() if the current operating system supports it. TIME_KILL_SYNCHRONOUS +is supported on Windows XP and later operating systems. + +Parameters: +- The same parameters as timeSetEvent(). See timeSetEvent()'s documentation in +the Platform SDK for more information. + +Return Value: +- The same return value as timeSetEvent(). See timeSetEvent()'s documentation in +the Platform SDK for more information. + +******************************************************************************/ +MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) +{ + #if WINVER >= 0x0501 + { + static bool fCheckedVersion = false; + static bool fTimeKillSynchronousFlagAvailable = false; + + if( !fCheckedVersion ) { + fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable(); + fCheckedVersion = true; + } + + if( fTimeKillSynchronousFlagAvailable ) { + fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS; + } + } + #endif // WINVER >= 0x0501 + + return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent ); +} + +bool TimeKillSynchronousFlagAvailable( void ) +{ + OSVERSIONINFO osverinfo; + + osverinfo.dwOSVersionInfoSize = sizeof(osverinfo); + + if( GetVersionEx( &osverinfo ) ) { + + // Windows XP's major version is 5 and its' minor version is 1. + // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag + // in Windows XP. + if( (osverinfo.dwMajorVersion > 5) || + ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) { + return true; + } + } + + return false; +} + + diff --git a/src/thirdparty/BaseClasses/wxutil.h b/src/thirdparty/BaseClasses/wxutil.h index a1c1704bfc1..b73a44b36ac 100644 --- a/src/thirdparty/BaseClasses/wxutil.h +++ b/src/thirdparty/BaseClasses/wxutil.h @@ -1,532 +1,532 @@ -//------------------------------------------------------------------------------ -// File: WXUtil.h -// -// Desc: DirectShow base classes - defines helper classes and functions for -// building multimedia filters. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __WXUTIL__ -#define __WXUTIL__ - -// eliminate spurious "statement has no effect" warnings. -#pragma warning(disable: 4705) - -// wrapper for whatever critical section we have -class CCritSec { - - // make copy constructor and assignment operator inaccessible - - CCritSec(const CCritSec &refCritSec); - CCritSec &operator=(const CCritSec &refCritSec); - - CRITICAL_SECTION m_CritSec; - -#ifdef _DEBUG -public: - DWORD m_currentOwner; - DWORD m_lockCount; - BOOL m_fTrace; // Trace this one -public: - CCritSec(); - ~CCritSec(); - void Lock(); - void Unlock(); -#else - -public: - CCritSec() { - InitializeCriticalSection(&m_CritSec); - }; - - ~CCritSec() { - DeleteCriticalSection(&m_CritSec); - }; - - void Lock() { - EnterCriticalSection(&m_CritSec); - }; - - void Unlock() { - LeaveCriticalSection(&m_CritSec); - }; -#endif -}; - -// -// To make deadlocks easier to track it is useful to insert in the -// code an assertion that says whether we own a critical section or -// not. We make the routines that do the checking globals to avoid -// having different numbers of member functions in the debug and -// retail class implementations of CCritSec. In addition we provide -// a routine that allows usage of specific critical sections to be -// traced. This is NOT on by default - there are far too many. -// - -#ifdef _DEBUG - BOOL WINAPI CritCheckIn(CCritSec * pcCrit); - BOOL WINAPI CritCheckIn(const CCritSec * pcCrit); - BOOL WINAPI CritCheckOut(CCritSec * pcCrit); - BOOL WINAPI CritCheckOut(const CCritSec * pcCrit); - void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace); -#else - #define CritCheckIn(x) TRUE - #define CritCheckOut(x) TRUE - #define DbgLockTrace(pc, fT) -#endif - - -// locks a critical section, and unlocks it automatically -// when the lock goes out of scope -class CAutoLock { - - // make copy constructor and assignment operator inaccessible - - CAutoLock(const CAutoLock &refAutoLock); - CAutoLock &operator=(const CAutoLock &refAutoLock); - -protected: - CCritSec * m_pLock; - -public: - CAutoLock(CCritSec * plock) - { - m_pLock = plock; - m_pLock->Lock(); - }; - - ~CAutoLock() { - m_pLock->Unlock(); - }; -}; - - - -// wrapper for event objects -class CAMEvent -{ - - // make copy constructor and assignment operator inaccessible - - CAMEvent(const CAMEvent &refEvent); - CAMEvent &operator=(const CAMEvent &refEvent); - -protected: - HANDLE m_hEvent; -public: - CAMEvent(BOOL fManualReset = FALSE, __inout_opt HRESULT *phr = NULL); - CAMEvent(__inout_opt HRESULT *phr); - ~CAMEvent(); - - // Cast to HANDLE - we don't support this as an lvalue - operator HANDLE () const { return m_hEvent; }; - - void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));}; - BOOL Wait(DWORD dwTimeout = INFINITE) { - return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0); - }; - void Reset() { ResetEvent(m_hEvent); }; - BOOL Check() { return Wait(0); }; -}; - - -// wrapper for event objects that do message processing -// This adds ONE method to the CAMEvent object to allow sent -// messages to be processed while waiting - -class CAMMsgEvent : public CAMEvent -{ - -public: - - CAMMsgEvent(__inout_opt HRESULT *phr = NULL); - - // Allow SEND messages to be processed while waiting - BOOL WaitMsg(DWORD dwTimeout = INFINITE); -}; - -// old name supported for the time being -#define CTimeoutEvent CAMEvent - -// support for a worker thread - -#ifdef AM_NOVTABLE -// simple thread class supports creation of worker thread, synchronization -// and communication. Can be derived to simplify parameter passing -class AM_NOVTABLE CAMThread { - - // make copy constructor and assignment operator inaccessible - - CAMThread(const CAMThread &refThread); - CAMThread &operator=(const CAMThread &refThread); - - CAMEvent m_EventSend; - CAMEvent m_EventComplete; - - DWORD m_dwParam; - DWORD m_dwReturnVal; - -protected: - HANDLE m_hThread; - - // thread will run this function on startup - // must be supplied by derived class - virtual DWORD ThreadProc() = 0; - -public: - CAMThread(__inout_opt HRESULT *phr = NULL); - virtual ~CAMThread(); - - CCritSec m_AccessLock; // locks access by client threads - CCritSec m_WorkerLock; // locks access to shared objects - - // thread initially runs this. param is actually 'this'. function - // just gets this and calls ThreadProc - static unsigned int WINAPI InitialThreadProc(__inout LPVOID pv); // MPC-HC patch - - // start thread running - error if already running - BOOL Create(); - - // signal the thread, and block for a response - // - DWORD CallWorker(DWORD); - - // accessor thread calls this when done with thread (having told thread - // to exit) - void Close() { - - // Disable warning: Conversion from LONG to PVOID of greater size -#pragma warning(push) -#pragma warning(disable: 4312) - HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0); -#pragma warning(pop) - - if (hThread) { - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - } - }; - - // ThreadExists - // Return TRUE if the thread exists. FALSE otherwise - BOOL ThreadExists(void) const - { - if (m_hThread == NULL) { - return FALSE; - } else { - return TRUE; - } - } - - // wait for the next request - DWORD GetRequest(); - - // is there a request? - BOOL CheckRequest(__out_opt DWORD * pParam); - - // reply to the request - void Reply(DWORD); - - // If you want to do WaitForMultipleObjects you'll need to include - // this handle in your wait list or you won't be responsive - HANDLE GetRequestHandle() const { return m_EventSend; }; - - // Find out what the request was - DWORD GetRequestParam() const { return m_dwParam; }; - - // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if - // available. S_FALSE means it's not available. - static HRESULT CoInitializeHelper(); -}; -#endif // AM_NOVTABLE - - -// CQueue -// -// Implements a simple Queue ADT. The queue contains a finite number of -// objects, access to which is controlled by a semaphore. The semaphore -// is created with an initial count (N). Each time an object is added -// a call to WaitForSingleObject is made on the semaphore's handle. When -// this function returns a slot has been reserved in the queue for the new -// object. If no slots are available the function blocks until one becomes -// available. Each time an object is removed from the queue ReleaseSemaphore -// is called on the semaphore's handle, thus freeing a slot in the queue. -// If no objects are present in the queue the function blocks until an -// object has been added. - -#define DEFAULT_QUEUESIZE 2 - -template class CQueue { -private: - HANDLE hSemPut; // Semaphore controlling queue "putting" - HANDLE hSemGet; // Semaphore controlling queue "getting" - CRITICAL_SECTION CritSect; // Thread seriallization - int nMax; // Max objects allowed in queue - int iNextPut; // Array index of next "PutMsg" - int iNextGet; // Array index of next "GetMsg" - T *QueueObjects; // Array of objects (ptr's to void) - - void Initialize(int n) { - iNextPut = iNextGet = 0; - nMax = n; - InitializeCriticalSection(&CritSect); - hSemPut = CreateSemaphore(NULL, n, n, NULL); - hSemGet = CreateSemaphore(NULL, 0, n, NULL); - QueueObjects = new T[n]; - } - - -public: - CQueue(int n) { - Initialize(n); - } - - CQueue() { - Initialize(DEFAULT_QUEUESIZE); - } - - ~CQueue() { - delete [] QueueObjects; - DeleteCriticalSection(&CritSect); - CloseHandle(hSemPut); - CloseHandle(hSemGet); - } - - T GetQueueObject() { - int iSlot; - T Object; - LONG lPrevious; - - // Wait for someone to put something on our queue, returns straight - // away is there is already an object on the queue. - // - WaitForSingleObject(hSemGet, INFINITE); - - EnterCriticalSection(&CritSect); - iSlot = iNextGet++ % nMax; - Object = QueueObjects[iSlot]; - LeaveCriticalSection(&CritSect); - - // Release anyone waiting to put an object onto our queue as there - // is now space available in the queue. - // - ReleaseSemaphore(hSemPut, 1L, &lPrevious); - return Object; - } - - void PutQueueObject(T Object) { - int iSlot; - LONG lPrevious; - - // Wait for someone to get something from our queue, returns straight - // away is there is already an empty slot on the queue. - // - WaitForSingleObject(hSemPut, INFINITE); - - EnterCriticalSection(&CritSect); - iSlot = iNextPut++ % nMax; - QueueObjects[iSlot] = Object; - LeaveCriticalSection(&CritSect); - - // Release anyone waiting to remove an object from our queue as there - // is now an object available to be removed. - // - ReleaseSemaphore(hSemGet, 1L, &lPrevious); - } -}; - -// Ensures that memory is not read past the length source buffer -// and that memory is not written past the length of the dst buffer -// dst - buffer to copy to -// dst_size - total size of destination buffer -// cb_dst_offset - offset, first byte copied to dst+cb_dst_offset -// src - buffer to copy from -// src_size - total size of source buffer -// cb_src_offset - offset, first byte copied from src+cb_src_offset -// count - number of bytes to copy -// -// Returns: -// S_OK - no error -// E_INVALIDARG - values passed would lead to overrun -HRESULT AMSafeMemMoveOffset( - __in_bcount(dst_size) void * dst, - __in size_t dst_size, - __in DWORD cb_dst_offset, - __in_bcount(src_size) const void * src, - __in size_t src_size, - __in DWORD cb_src_offset, - __in size_t count); - -extern "C" -void * __stdcall memmoveInternal(void *, const void *, size_t); - -inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt) -{ -#ifdef _X86_ - void *pRet = NULL; - - _asm { - cld // make sure we get the direction right - mov ecx, cnt // num of bytes to scan - mov edi, buf // pointer byte stream - mov eax, chr // byte to scan for - repne scasb // look for the byte in the byte stream - jnz exit_memchr // Z flag set if byte found - dec edi // scasb always increments edi even when it - // finds the required byte - mov pRet, edi -exit_memchr: - } - return pRet; - -#else - while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) { - buf = (unsigned char *)buf + 1; - cnt--; - } - - return(cnt ? (void *)buf : NULL); -#endif -} - -void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr); - -#define WstrToInt(sz) _wtoi(sz) -#define atoiW(sz) _wtoi(sz) -#define atoiA(sz) atoi(sz) - -// These are available to help managing bitmap VIDEOINFOHEADER media structures - -extern const DWORD bits555[3]; -extern const DWORD bits565[3]; -extern const DWORD bits888[3]; - -// These help convert between VIDEOINFOHEADER and BITMAPINFO structures - -STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader); -STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader); -STDAPI_(WORD) GetBitCount(const GUID *pSubtype); - -// strmbase.lib implements this for compatibility with people who -// managed to link to this directly. we don't want to advertise it. -// -// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype); - -STDAPI_(LPCSTR) GetSubtypeNameA(const GUID *pSubtype); -STDAPI_(LPCWSTR) GetSubtypeNameW(const GUID *pSubtype); - -#ifdef UNICODE -#define GetSubtypeName GetSubtypeNameW -#else -#define GetSubtypeName GetSubtypeNameA -#endif - -STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader); -STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader); - -#ifdef __AMVIDEO__ -STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo); -STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo); -#endif // __AMVIDEO__ - - -// Compares two interfaces and returns TRUE if they are on the same object -BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond); - -// This is for comparing pins -#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2) - - -// Arithmetic helper functions - -// Compute (a * b + rnd) / c -LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd); -LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd); - - -// Avoids us dyna-linking to SysAllocString to copy BSTR strings -STDAPI WriteBSTR(__deref_out BSTR * pstrDest, LPCWSTR szSrc); -STDAPI FreeBSTR(__deref_in BSTR* pstr); - -// Return a wide string - allocating memory for it -// Returns: -// S_OK - no error -// E_POINTER - ppszReturn == NULL -// E_OUTOFMEMORY - can't allocate memory for returned string -STDAPI AMGetWideString(LPCWSTR pszString, __deref_out LPWSTR *ppszReturn); - -// Special wait for objects owning windows -DWORD WINAPI WaitDispatchingMessages( - HANDLE hObject, - DWORD dwWait, - HWND hwnd = NULL, - UINT uMsg = 0, - HANDLE hEvent = NULL); - -// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in -// our use of HRESULT_FROM_WIN32, it typically means a function failed -// to call SetLastError(), and we still want a failure code. -// -#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x)) - -// call GetLastError and return an HRESULT value that will fail the -// SUCCEEDED() macro. -HRESULT AmGetLastErrorToHResult(void); - -// duplicate of ATL's CComPtr to avoid linker conflicts. - -IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp); - -template -class QzCComPtr -{ -public: - typedef T _PtrClass; - QzCComPtr() {p=NULL;} - QzCComPtr(T* lp) - { - if ((p = lp) != NULL) - p->AddRef(); - } - QzCComPtr(const QzCComPtr& lp) - { - if ((p = lp.p) != NULL) - p->AddRef(); - } - ~QzCComPtr() {if (p) p->Release();} - void Release() {if (p) p->Release(); p=NULL;} - operator T*() {return (T*)p;} - T& operator*() {ASSERT(p!=NULL); return *p; } - //The assert on operator& usually indicates a bug. If this is really - //what is needed, however, take the address of the p member explicitly. - T** operator&() { ASSERT(p==NULL); return &p; } - T* operator->() { ASSERT(p!=NULL); return p; } - T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);} - T* operator=(const QzCComPtr& lp) - { - return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p); - } -#if _MSC_VER>1020 - bool operator!(){return (p == NULL);} -#else - BOOL operator!(){return (p == NULL) ? TRUE : FALSE;} -#endif - T* p; -}; - -MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ); -bool TimeKillSynchronousFlagAvailable( void ); - -// Helper to replace lstrcpmi -__inline int lstrcmpiLocaleIndependentW(LPCWSTR lpsz1, LPCWSTR lpsz2) -{ - return CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL; -} -__inline int lstrcmpiLocaleIndependentA(LPCSTR lpsz1, LPCSTR lpsz2) -{ - return CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL; -} - -#endif /* __WXUTIL__ */ +//------------------------------------------------------------------------------ +// File: WXUtil.h +// +// Desc: DirectShow base classes - defines helper classes and functions for +// building multimedia filters. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WXUTIL__ +#define __WXUTIL__ + +// eliminate spurious "statement has no effect" warnings. +#pragma warning(disable: 4705) + +// wrapper for whatever critical section we have +class CCritSec { + + // make copy constructor and assignment operator inaccessible + + CCritSec(const CCritSec &refCritSec); + CCritSec &operator=(const CCritSec &refCritSec); + + CRITICAL_SECTION m_CritSec; + +#ifdef _DEBUG +public: + DWORD m_currentOwner; + DWORD m_lockCount; + BOOL m_fTrace; // Trace this one +public: + CCritSec(); + ~CCritSec(); + void Lock(); + void Unlock(); +#else + +public: + CCritSec() { + InitializeCriticalSection(&m_CritSec); + }; + + ~CCritSec() { + DeleteCriticalSection(&m_CritSec); + }; + + void Lock() { + EnterCriticalSection(&m_CritSec); + }; + + void Unlock() { + LeaveCriticalSection(&m_CritSec); + }; +#endif +}; + +// +// To make deadlocks easier to track it is useful to insert in the +// code an assertion that says whether we own a critical section or +// not. We make the routines that do the checking globals to avoid +// having different numbers of member functions in the debug and +// retail class implementations of CCritSec. In addition we provide +// a routine that allows usage of specific critical sections to be +// traced. This is NOT on by default - there are far too many. +// + +#ifdef _DEBUG + BOOL WINAPI CritCheckIn(CCritSec * pcCrit); + BOOL WINAPI CritCheckIn(const CCritSec * pcCrit); + BOOL WINAPI CritCheckOut(CCritSec * pcCrit); + BOOL WINAPI CritCheckOut(const CCritSec * pcCrit); + void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace); +#else + #define CritCheckIn(x) TRUE + #define CritCheckOut(x) TRUE + #define DbgLockTrace(pc, fT) +#endif + + +// locks a critical section, and unlocks it automatically +// when the lock goes out of scope +class CAutoLock { + + // make copy constructor and assignment operator inaccessible + + CAutoLock(const CAutoLock &refAutoLock); + CAutoLock &operator=(const CAutoLock &refAutoLock); + +protected: + CCritSec * m_pLock; + +public: + CAutoLock(CCritSec * plock) + { + m_pLock = plock; + m_pLock->Lock(); + }; + + ~CAutoLock() { + m_pLock->Unlock(); + }; +}; + + + +// wrapper for event objects +class CAMEvent +{ + + // make copy constructor and assignment operator inaccessible + + CAMEvent(const CAMEvent &refEvent); + CAMEvent &operator=(const CAMEvent &refEvent); + +protected: + HANDLE m_hEvent; +public: + CAMEvent(BOOL fManualReset = FALSE, __inout_opt HRESULT *phr = NULL); + CAMEvent(__inout_opt HRESULT *phr); + ~CAMEvent(); + + // Cast to HANDLE - we don't support this as an lvalue + operator HANDLE () const { return m_hEvent; }; + + void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));}; + BOOL Wait(DWORD dwTimeout = INFINITE) { + return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0); + }; + void Reset() { ResetEvent(m_hEvent); }; + BOOL Check() { return Wait(0); }; +}; + + +// wrapper for event objects that do message processing +// This adds ONE method to the CAMEvent object to allow sent +// messages to be processed while waiting + +class CAMMsgEvent : public CAMEvent +{ + +public: + + CAMMsgEvent(__inout_opt HRESULT *phr = NULL); + + // Allow SEND messages to be processed while waiting + BOOL WaitMsg(DWORD dwTimeout = INFINITE); +}; + +// old name supported for the time being +#define CTimeoutEvent CAMEvent + +// support for a worker thread + +#ifdef AM_NOVTABLE +// simple thread class supports creation of worker thread, synchronization +// and communication. Can be derived to simplify parameter passing +class AM_NOVTABLE CAMThread { + + // make copy constructor and assignment operator inaccessible + + CAMThread(const CAMThread &refThread); + CAMThread &operator=(const CAMThread &refThread); + + CAMEvent m_EventSend; + CAMEvent m_EventComplete; + + DWORD m_dwParam; + DWORD m_dwReturnVal; + +protected: + HANDLE m_hThread; + + // thread will run this function on startup + // must be supplied by derived class + virtual DWORD ThreadProc() = 0; + +public: + CAMThread(__inout_opt HRESULT *phr = NULL); + virtual ~CAMThread(); + + CCritSec m_AccessLock; // locks access by client threads + CCritSec m_WorkerLock; // locks access to shared objects + + // thread initially runs this. param is actually 'this'. function + // just gets this and calls ThreadProc + static unsigned int WINAPI InitialThreadProc(__inout LPVOID pv); // MPC-HC patch + + // start thread running - error if already running + BOOL Create(); + + // signal the thread, and block for a response + // + DWORD CallWorker(DWORD); + + // accessor thread calls this when done with thread (having told thread + // to exit) + void Close() { + + // Disable warning: Conversion from LONG to PVOID of greater size +#pragma warning(push) +#pragma warning(disable: 4312) + HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0); +#pragma warning(pop) + + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + }; + + // ThreadExists + // Return TRUE if the thread exists. FALSE otherwise + BOOL ThreadExists(void) const + { + if (m_hThread == NULL) { + return FALSE; + } else { + return TRUE; + } + } + + // wait for the next request + DWORD GetRequest(); + + // is there a request? + BOOL CheckRequest(__out_opt DWORD * pParam); + + // reply to the request + void Reply(DWORD); + + // If you want to do WaitForMultipleObjects you'll need to include + // this handle in your wait list or you won't be responsive + HANDLE GetRequestHandle() const { return m_EventSend; }; + + // Find out what the request was + DWORD GetRequestParam() const { return m_dwParam; }; + + // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if + // available. S_FALSE means it's not available. + static HRESULT CoInitializeHelper(); +}; +#endif // AM_NOVTABLE + + +// CQueue +// +// Implements a simple Queue ADT. The queue contains a finite number of +// objects, access to which is controlled by a semaphore. The semaphore +// is created with an initial count (N). Each time an object is added +// a call to WaitForSingleObject is made on the semaphore's handle. When +// this function returns a slot has been reserved in the queue for the new +// object. If no slots are available the function blocks until one becomes +// available. Each time an object is removed from the queue ReleaseSemaphore +// is called on the semaphore's handle, thus freeing a slot in the queue. +// If no objects are present in the queue the function blocks until an +// object has been added. + +#define DEFAULT_QUEUESIZE 2 + +template class CQueue { +private: + HANDLE hSemPut; // Semaphore controlling queue "putting" + HANDLE hSemGet; // Semaphore controlling queue "getting" + CRITICAL_SECTION CritSect; // Thread seriallization + int nMax; // Max objects allowed in queue + int iNextPut; // Array index of next "PutMsg" + int iNextGet; // Array index of next "GetMsg" + T *QueueObjects; // Array of objects (ptr's to void) + + void Initialize(int n) { + iNextPut = iNextGet = 0; + nMax = n; + InitializeCriticalSection(&CritSect); + hSemPut = CreateSemaphore(NULL, n, n, NULL); + hSemGet = CreateSemaphore(NULL, 0, n, NULL); + QueueObjects = new T[n]; + } + + +public: + CQueue(int n) { + Initialize(n); + } + + CQueue() { + Initialize(DEFAULT_QUEUESIZE); + } + + ~CQueue() { + delete [] QueueObjects; + DeleteCriticalSection(&CritSect); + CloseHandle(hSemPut); + CloseHandle(hSemGet); + } + + T GetQueueObject() { + int iSlot; + T Object; + LONG lPrevious; + + // Wait for someone to put something on our queue, returns straight + // away is there is already an object on the queue. + // + WaitForSingleObject(hSemGet, INFINITE); + + EnterCriticalSection(&CritSect); + iSlot = iNextGet++ % nMax; + Object = QueueObjects[iSlot]; + LeaveCriticalSection(&CritSect); + + // Release anyone waiting to put an object onto our queue as there + // is now space available in the queue. + // + ReleaseSemaphore(hSemPut, 1L, &lPrevious); + return Object; + } + + void PutQueueObject(T Object) { + int iSlot; + LONG lPrevious; + + // Wait for someone to get something from our queue, returns straight + // away is there is already an empty slot on the queue. + // + WaitForSingleObject(hSemPut, INFINITE); + + EnterCriticalSection(&CritSect); + iSlot = iNextPut++ % nMax; + QueueObjects[iSlot] = Object; + LeaveCriticalSection(&CritSect); + + // Release anyone waiting to remove an object from our queue as there + // is now an object available to be removed. + // + ReleaseSemaphore(hSemGet, 1L, &lPrevious); + } +}; + +// Ensures that memory is not read past the length source buffer +// and that memory is not written past the length of the dst buffer +// dst - buffer to copy to +// dst_size - total size of destination buffer +// cb_dst_offset - offset, first byte copied to dst+cb_dst_offset +// src - buffer to copy from +// src_size - total size of source buffer +// cb_src_offset - offset, first byte copied from src+cb_src_offset +// count - number of bytes to copy +// +// Returns: +// S_OK - no error +// E_INVALIDARG - values passed would lead to overrun +HRESULT AMSafeMemMoveOffset( + __in_bcount(dst_size) void * dst, + __in size_t dst_size, + __in DWORD cb_dst_offset, + __in_bcount(src_size) const void * src, + __in size_t src_size, + __in DWORD cb_src_offset, + __in size_t count); + +extern "C" +void * __stdcall memmoveInternal(void *, const void *, size_t); + +inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt) +{ +#ifdef _X86_ + void *pRet = NULL; + + _asm { + cld // make sure we get the direction right + mov ecx, cnt // num of bytes to scan + mov edi, buf // pointer byte stream + mov eax, chr // byte to scan for + repne scasb // look for the byte in the byte stream + jnz exit_memchr // Z flag set if byte found + dec edi // scasb always increments edi even when it + // finds the required byte + mov pRet, edi +exit_memchr: + } + return pRet; + +#else + while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) { + buf = (unsigned char *)buf + 1; + cnt--; + } + + return(cnt ? (void *)buf : NULL); +#endif +} + +void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr); + +#define WstrToInt(sz) _wtoi(sz) +#define atoiW(sz) _wtoi(sz) +#define atoiA(sz) atoi(sz) + +// These are available to help managing bitmap VIDEOINFOHEADER media structures + +extern const DWORD bits555[3]; +extern const DWORD bits565[3]; +extern const DWORD bits888[3]; + +// These help convert between VIDEOINFOHEADER and BITMAPINFO structures + +STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader); +STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader); +STDAPI_(WORD) GetBitCount(const GUID *pSubtype); + +// strmbase.lib implements this for compatibility with people who +// managed to link to this directly. we don't want to advertise it. +// +// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype); + +STDAPI_(LPCSTR) GetSubtypeNameA(const GUID *pSubtype); +STDAPI_(LPCWSTR) GetSubtypeNameW(const GUID *pSubtype); + +#ifdef UNICODE +#define GetSubtypeName GetSubtypeNameW +#else +#define GetSubtypeName GetSubtypeNameA +#endif + +STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader); +STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader); + +#ifdef __AMVIDEO__ +STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo); +STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo); +#endif // __AMVIDEO__ + + +// Compares two interfaces and returns TRUE if they are on the same object +BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond); + +// This is for comparing pins +#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2) + + +// Arithmetic helper functions + +// Compute (a * b + rnd) / c +LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd); +LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd); + + +// Avoids us dyna-linking to SysAllocString to copy BSTR strings +STDAPI WriteBSTR(__deref_out BSTR * pstrDest, LPCWSTR szSrc); +STDAPI FreeBSTR(__deref_in BSTR* pstr); + +// Return a wide string - allocating memory for it +// Returns: +// S_OK - no error +// E_POINTER - ppszReturn == NULL +// E_OUTOFMEMORY - can't allocate memory for returned string +STDAPI AMGetWideString(LPCWSTR pszString, __deref_out LPWSTR *ppszReturn); + +// Special wait for objects owning windows +DWORD WINAPI WaitDispatchingMessages( + HANDLE hObject, + DWORD dwWait, + HWND hwnd = NULL, + UINT uMsg = 0, + HANDLE hEvent = NULL); + +// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in +// our use of HRESULT_FROM_WIN32, it typically means a function failed +// to call SetLastError(), and we still want a failure code. +// +#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x)) + +// call GetLastError and return an HRESULT value that will fail the +// SUCCEEDED() macro. +HRESULT AmGetLastErrorToHResult(void); + +// duplicate of ATL's CComPtr to avoid linker conflicts. + +IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp); + +template +class QzCComPtr +{ +public: + typedef T _PtrClass; + QzCComPtr() {p=NULL;} + QzCComPtr(T* lp) + { + if ((p = lp) != NULL) + p->AddRef(); + } + QzCComPtr(const QzCComPtr& lp) + { + if ((p = lp.p) != NULL) + p->AddRef(); + } + ~QzCComPtr() {if (p) p->Release();} + void Release() {if (p) p->Release(); p=NULL;} + operator T*() {return (T*)p;} + T& operator*() {ASSERT(p!=NULL); return *p; } + //The assert on operator& usually indicates a bug. If this is really + //what is needed, however, take the address of the p member explicitly. + T** operator&() { ASSERT(p==NULL); return &p; } + T* operator->() { ASSERT(p!=NULL); return p; } + T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);} + T* operator=(const QzCComPtr& lp) + { + return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p); + } +#if _MSC_VER>1020 + bool operator!(){return (p == NULL);} +#else + BOOL operator!(){return (p == NULL) ? TRUE : FALSE;} +#endif + T* p; +}; + +MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ); +bool TimeKillSynchronousFlagAvailable( void ); + +// Helper to replace lstrcpmi +__inline int lstrcmpiLocaleIndependentW(LPCWSTR lpsz1, LPCWSTR lpsz2) +{ + return CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL; +} +__inline int lstrcmpiLocaleIndependentA(LPCSTR lpsz1, LPCSTR lpsz2) +{ + return CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL; +} + +#endif /* __WXUTIL__ */ diff --git a/src/thirdparty/LAVFilters/LAVFilters.vcxproj b/src/thirdparty/LAVFilters/LAVFilters.vcxproj index 096de5fe8d1..cf2306793fe 100644 --- a/src/thirdparty/LAVFilters/LAVFilters.vcxproj +++ b/src/thirdparty/LAVFilters/LAVFilters.vcxproj @@ -1,50 +1,50 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {ED257874-E12E-4143-AF0A-0676DA3BB18C} - LAVFilters - LAVFilters - LAVFilters - - - - 10.0 - v142 - false - Makefile - - - - - - - - - - $(IntDir) - build_lavfilters.bat Build $(Platform) $(Configuration) Silent Nocolors - build_lavfilters.bat Rebuild $(Platform) $(Configuration) Silent Nocolors - build_lavfilters.bat Clean $(Platform) $(Configuration) Silent Nocolors - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {ED257874-E12E-4143-AF0A-0676DA3BB18C} + LAVFilters + LAVFilters + LAVFilters + + + + 10.0 + v142 + false + Makefile + + + + + + + + + + $(IntDir) + build_lavfilters.bat Build $(Platform) $(Configuration) Silent Nocolors + build_lavfilters.bat Rebuild $(Platform) $(Configuration) Silent Nocolors + build_lavfilters.bat Clean $(Platform) $(Configuration) Silent Nocolors + + + + \ No newline at end of file diff --git a/src/thirdparty/LAVFilters/build_lavfilters.bat b/src/thirdparty/LAVFilters/build_lavfilters.bat index 381f3108452..0f9782162ae 100755 --- a/src/thirdparty/LAVFilters/build_lavfilters.bat +++ b/src/thirdparty/LAVFilters/build_lavfilters.bat @@ -1,231 +1,231 @@ -@ECHO OFF -REM (C) 2013-2017 see Authors.txt -REM -REM This file is part of MPC-HC. -REM -REM MPC-HC is free software; you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation; either version 3 of the License, or -REM (at your option) any later version. -REM -REM MPC-HC is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with this program. If not, see . - - -SETLOCAL EnableDelayedExpansion -SET "FILE_DIR=%~dp0" -PUSHD "%FILE_DIR%" - -SET ROOT_DIR=..\..\.. -SET "COMMON=%FILE_DIR%%ROOT_DIR%\common.bat" - -CALL "%COMMON%" :SubSetPath -IF %ERRORLEVEL% NEQ 0 EXIT /B 1 -CALL "%COMMON%" :SubDoesExist gcc.exe -IF %ERRORLEVEL% NEQ 0 ( - ECHO ERROR: gcc.exe not found in your MinGW installation - EXIT /B 1 -) - -SET ARG=/%* -SET ARG=%ARG:/=% -SET ARG=%ARG:-=% -SET ARGB=0 -SET ARGBC=0 -SET ARGCOMP=0 -SET ARGPL=0 -SET INPUT=0 -SET VALID=0 - -IF /I "%ARG%" == "?" GOTO ShowHelp - -FOR %%G IN (%ARG%) DO ( - IF /I "%%G" == "help" GOTO ShowHelp - IF /I "%%G" == "Build" SET "BUILDTYPE=Build" & SET /A ARGB+=1 - IF /I "%%G" == "Clean" SET "BUILDTYPE=Clean" & SET /A ARGB+=1 - IF /I "%%G" == "Rebuild" SET "BUILDTYPE=Rebuild" & SET /A ARGB+=1 - IF /I "%%G" == "Both" SET "ARCH=Both" & SET /A ARGPL+=1 - IF /I "%%G" == "Win32" SET "ARCH=x86" & SET /A ARGPL+=1 - IF /I "%%G" == "x86" SET "ARCH=x86" & SET /A ARGPL+=1 - IF /I "%%G" == "x64" SET "ARCH=x64" & SET /A ARGPL+=1 - IF /I "%%G" == "Debug" SET "RELEASETYPE=Debug" & SET /A ARGBC+=1 - IF /I "%%G" == "Release" SET "RELEASETYPE=Release" & SET /A ARGBC+=1 - IF /I "%%G" == "VS2017" SET "COMPILER=VS2017" & SET /A ARGCOMP+=1 +@ECHO OFF +REM (C) 2013-2017 see Authors.txt +REM +REM This file is part of MPC-HC. +REM +REM MPC-HC is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation; either version 3 of the License, or +REM (at your option) any later version. +REM +REM MPC-HC is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with this program. If not, see . + + +SETLOCAL EnableDelayedExpansion +SET "FILE_DIR=%~dp0" +PUSHD "%FILE_DIR%" + +SET ROOT_DIR=..\..\.. +SET "COMMON=%FILE_DIR%%ROOT_DIR%\common.bat" + +CALL "%COMMON%" :SubSetPath +IF %ERRORLEVEL% NEQ 0 EXIT /B 1 +CALL "%COMMON%" :SubDoesExist gcc.exe +IF %ERRORLEVEL% NEQ 0 ( + ECHO ERROR: gcc.exe not found in your MinGW installation + EXIT /B 1 +) + +SET ARG=/%* +SET ARG=%ARG:/=% +SET ARG=%ARG:-=% +SET ARGB=0 +SET ARGBC=0 +SET ARGCOMP=0 +SET ARGPL=0 +SET INPUT=0 +SET VALID=0 + +IF /I "%ARG%" == "?" GOTO ShowHelp + +FOR %%G IN (%ARG%) DO ( + IF /I "%%G" == "help" GOTO ShowHelp + IF /I "%%G" == "Build" SET "BUILDTYPE=Build" & SET /A ARGB+=1 + IF /I "%%G" == "Clean" SET "BUILDTYPE=Clean" & SET /A ARGB+=1 + IF /I "%%G" == "Rebuild" SET "BUILDTYPE=Rebuild" & SET /A ARGB+=1 + IF /I "%%G" == "Both" SET "ARCH=Both" & SET /A ARGPL+=1 + IF /I "%%G" == "Win32" SET "ARCH=x86" & SET /A ARGPL+=1 + IF /I "%%G" == "x86" SET "ARCH=x86" & SET /A ARGPL+=1 + IF /I "%%G" == "x64" SET "ARCH=x64" & SET /A ARGPL+=1 + IF /I "%%G" == "Debug" SET "RELEASETYPE=Debug" & SET /A ARGBC+=1 + IF /I "%%G" == "Release" SET "RELEASETYPE=Release" & SET /A ARGBC+=1 + IF /I "%%G" == "VS2017" SET "COMPILER=VS2017" & SET /A ARGCOMP+=1 IF /I "%%G" == "VS2019" SET "COMPILER=VS2019" & SET /A ARGCOMP+=1 - IF /I "%%G" == "Silent" SET "SILENT=True" & SET /A VALID+=1 - IF /I "%%G" == "Nocolors" SET "NOCOLORS=True" & SET /A VALID+=1 -) - -FOR %%X IN (%*) DO SET /A INPUT+=1 -SET /A VALID+=%ARGB%+%ARGPL%+%ARGBC%+%ARGCOMP% - -IF %VALID% NEQ %INPUT% GOTO UnsupportedSwitch - -IF %ARGB% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGB% == 0 (SET "BUILDTYPE=Build") -IF %ARGPL% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGPL% == 0 (SET "ARCH=Both") -IF %ARGBC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGBC% == 0 (SET "RELEASETYPE=Release") + IF /I "%%G" == "Silent" SET "SILENT=True" & SET /A VALID+=1 + IF /I "%%G" == "Nocolors" SET "NOCOLORS=True" & SET /A VALID+=1 +) + +FOR %%X IN (%*) DO SET /A INPUT+=1 +SET /A VALID+=%ARGB%+%ARGPL%+%ARGBC%+%ARGCOMP% + +IF %VALID% NEQ %INPUT% GOTO UnsupportedSwitch + +IF %ARGB% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGB% == 0 (SET "BUILDTYPE=Build") +IF %ARGPL% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGPL% == 0 (SET "ARCH=Both") +IF %ARGBC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGBC% == 0 (SET "RELEASETYPE=Release") IF %ARGCOMP% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGCOMP% == 0 (SET "COMPILER=VS2019") IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath -IF NOT EXIST "!MPCHC_VS_PATH!" ( - ECHO ERROR: Visual Studio install path not found or invalid. You should add MPCHC_VS_PATH to build.user.bat - GOTO MissingVar -) +IF NOT EXIST "!MPCHC_VS_PATH!" ( + ECHO ERROR: Visual Studio install path not found or invalid. You should add MPCHC_VS_PATH to build.user.bat + GOTO MissingVar +) SET "TOOLSET=!MPCHC_VS_PATH!\Common7\Tools\vsdevcmd" -IF NOT EXIST "%TOOLSET%" ( - ECHO ERROR: Visual Studio tool path invalid - GOTO MissingVar -) - -SET "BIN_DIR=%ROOT_DIR%\bin" - -CALL "%COMMON%" :SubParseConfig - -IF /I "%ARCH%" == "Both" ( - SET "ARCH=x86" & CALL :Main - SET "ARCH=x64" & CALL :Main -) ELSE ( - CALL :Main -) -GOTO End - - -:Main -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%ARCH%" == "x86" (SET TOOLSETARCH=x86) ELSE (SET TOOLSETARCH=amd64) -CALL "%TOOLSET%" -no_logo -arch=%TOOLSETARCH% - -SET START_TIME=%TIME% -SET START_DATE=%DATE% - -IF /I "%BUILDTYPE%" == "Rebuild" ( - SET "BUILDTYPE=Clean" & CALL :SubMake - SET "BUILDTYPE=Build" & CALL :SubMake - SET "BUILDTYPE=Rebuild" - EXIT /B -) - -IF /I "%BUILDTYPE%" == "Clean" (CALL :SubMake & EXIT /B) - -CALL :SubMake - -EXIT /B - - -:End -IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% -TITLE Compiling LAV Filters %COMPILER% [FINISHED] -SET END_TIME=%TIME% -CALL "%COMMON%" :SubGetDuration -CALL "%COMMON%" :SubMsg "INFO" "LAV Filters compilation started on %START_DATE%-%START_TIME% and completed on %DATE%-%END_TIME% [%DURATION%]" -POPD -ENDLOCAL -EXIT /B - - -:SubMake -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%ARCH%" == "x86" (SET "ARCHVS=Win32") ELSE (SET "ARCHVS=x64") - -REM Build FFmpeg -sh build_ffmpeg.sh %ARCH% %RELEASETYPE% %BUILDTYPE% %COMPILER% -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "'sh build_ffmpeg.sh %ARCH% %RELEASETYPE% %BUILDTYPE% %COMPILER%' failed!" - EXIT /B -) - -PUSHD src - -REM Build LAVFilters -IF /I "%ARCH%" == "x86" (SET "ARCHVS=Win32") ELSE (SET "ARCHVS=x64") - -MSBuild.exe LAVFilters.sln /nologo /consoleloggerparameters:Verbosity=minimal /nodeReuse:true /m /t:%BUILDTYPE% /property:Configuration=%RELEASETYPE%;Platform=%ARCHVS% -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "'MSBuild.exe LAVFilters.sln /nologo /consoleloggerparameters:Verbosity=minimal /nodeReuse:true /m /t:%BUILDTYPE% /property:Configuration=%RELEASETYPE%;Platform=%ARCHVS%' failed!" - EXIT /B -) - -POPD - -IF /I "%RELEASETYPE%" == "Debug" ( - SET "SRCFOLDER=src\bin_%ARCHVS%d" -) ELSE ( - SET "SRCFOLDER=src\bin_%ARCHVS%" -) - -IF /I "%RELEASETYPE%" == "Debug" ( - SET "DESTFOLDER=%BIN_DIR%\mpc-hc_%ARCH%_Debug" -) ELSE ( - SET "DESTFOLDER=%BIN_DIR%\mpc-hc_%ARCH%" -) - -IF /I "%ARCH%" == "x64" ( - SET "DESTFOLDER=%DESTFOLDER%\LAVFilters64" -) ELSE ( - SET "DESTFOLDER=%DESTFOLDER%\LAVFilters" -) - -IF /I "%BUILDTYPE%" == "Build" ( - REM Copy LAVFilters files to MPC-HC output directory - IF NOT EXIST %DESTFOLDER% MD %DESTFOLDER% - - COPY /Y /V %SRCFOLDER%\*.dll %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\*.ax %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\*.manifest %DESTFOLDER% - IF /I "%RELEASETYPE%" == "Release" ( - COPY /Y /V %SRCFOLDER%\IntelQuickSyncDecoder\IntelQuickSyncDecoder.pdb %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\LAVAudio\LAVAudio.pdb %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\LAVSplitter\LAVSplitter.pdb %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\LAVVideo\LAVVideo.pdb %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\libbluray\libbluray.pdb %DESTFOLDER% - ) ELSE ( - COPY /Y /V %SRCFOLDER%\*.pdb %DESTFOLDER% - ) -) ELSE IF /I "%BUILDTYPE%" == "Clean" ( - REM Remove LAVFilters files in MPC-HC output directory - IF EXIST %DESTFOLDER% RD /Q /S %DESTFOLDER% -) - -EXIT /B - - -:MissingVar -ECHO Not all build dependencies were found. -ECHO. -ECHO See "%ROOT_DIR%\docs\Compilation.md" for more information. -CALL "%COMMON%" :SubMsg "ERROR" "LAV Filters compilation failed!" & EXIT /B 1 - - -:UnsupportedSwitch -ECHO. -ECHO Unsupported commandline switch! -ECHO. -ECHO "%~nx0 %*" -ECHO. -ECHO Run "%~nx0 help" for details about the commandline switches. -CALL "%COMMON%" :SubMsg "ERROR" "LAV Filters compilation failed!" & EXIT /B 1 - - -:ShowHelp -TITLE %~nx0 Help -ECHO. -ECHO Usage: +IF NOT EXIST "%TOOLSET%" ( + ECHO ERROR: Visual Studio tool path invalid + GOTO MissingVar +) + +SET "BIN_DIR=%ROOT_DIR%\bin" + +CALL "%COMMON%" :SubParseConfig + +IF /I "%ARCH%" == "Both" ( + SET "ARCH=x86" & CALL :Main + SET "ARCH=x64" & CALL :Main +) ELSE ( + CALL :Main +) +GOTO End + + +:Main +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%ARCH%" == "x86" (SET TOOLSETARCH=x86) ELSE (SET TOOLSETARCH=amd64) +CALL "%TOOLSET%" -no_logo -arch=%TOOLSETARCH% + +SET START_TIME=%TIME% +SET START_DATE=%DATE% + +IF /I "%BUILDTYPE%" == "Rebuild" ( + SET "BUILDTYPE=Clean" & CALL :SubMake + SET "BUILDTYPE=Build" & CALL :SubMake + SET "BUILDTYPE=Rebuild" + EXIT /B +) + +IF /I "%BUILDTYPE%" == "Clean" (CALL :SubMake & EXIT /B) + +CALL :SubMake + +EXIT /B + + +:End +IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% +TITLE Compiling LAV Filters %COMPILER% [FINISHED] +SET END_TIME=%TIME% +CALL "%COMMON%" :SubGetDuration +CALL "%COMMON%" :SubMsg "INFO" "LAV Filters compilation started on %START_DATE%-%START_TIME% and completed on %DATE%-%END_TIME% [%DURATION%]" +POPD +ENDLOCAL +EXIT /B + + +:SubMake +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%ARCH%" == "x86" (SET "ARCHVS=Win32") ELSE (SET "ARCHVS=x64") + +REM Build FFmpeg +sh build_ffmpeg.sh %ARCH% %RELEASETYPE% %BUILDTYPE% %COMPILER% +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "'sh build_ffmpeg.sh %ARCH% %RELEASETYPE% %BUILDTYPE% %COMPILER%' failed!" + EXIT /B +) + +PUSHD src + +REM Build LAVFilters +IF /I "%ARCH%" == "x86" (SET "ARCHVS=Win32") ELSE (SET "ARCHVS=x64") + +MSBuild.exe LAVFilters.sln /nologo /consoleloggerparameters:Verbosity=minimal /nodeReuse:true /m /t:%BUILDTYPE% /property:Configuration=%RELEASETYPE%;Platform=%ARCHVS% +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "'MSBuild.exe LAVFilters.sln /nologo /consoleloggerparameters:Verbosity=minimal /nodeReuse:true /m /t:%BUILDTYPE% /property:Configuration=%RELEASETYPE%;Platform=%ARCHVS%' failed!" + EXIT /B +) + +POPD + +IF /I "%RELEASETYPE%" == "Debug" ( + SET "SRCFOLDER=src\bin_%ARCHVS%d" +) ELSE ( + SET "SRCFOLDER=src\bin_%ARCHVS%" +) + +IF /I "%RELEASETYPE%" == "Debug" ( + SET "DESTFOLDER=%BIN_DIR%\mpc-hc_%ARCH%_Debug" +) ELSE ( + SET "DESTFOLDER=%BIN_DIR%\mpc-hc_%ARCH%" +) + +IF /I "%ARCH%" == "x64" ( + SET "DESTFOLDER=%DESTFOLDER%\LAVFilters64" +) ELSE ( + SET "DESTFOLDER=%DESTFOLDER%\LAVFilters" +) + +IF /I "%BUILDTYPE%" == "Build" ( + REM Copy LAVFilters files to MPC-HC output directory + IF NOT EXIST %DESTFOLDER% MD %DESTFOLDER% + + COPY /Y /V %SRCFOLDER%\*.dll %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\*.ax %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\*.manifest %DESTFOLDER% + IF /I "%RELEASETYPE%" == "Release" ( + COPY /Y /V %SRCFOLDER%\IntelQuickSyncDecoder\IntelQuickSyncDecoder.pdb %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\LAVAudio\LAVAudio.pdb %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\LAVSplitter\LAVSplitter.pdb %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\LAVVideo\LAVVideo.pdb %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\libbluray\libbluray.pdb %DESTFOLDER% + ) ELSE ( + COPY /Y /V %SRCFOLDER%\*.pdb %DESTFOLDER% + ) +) ELSE IF /I "%BUILDTYPE%" == "Clean" ( + REM Remove LAVFilters files in MPC-HC output directory + IF EXIST %DESTFOLDER% RD /Q /S %DESTFOLDER% +) + +EXIT /B + + +:MissingVar +ECHO Not all build dependencies were found. +ECHO. +ECHO See "%ROOT_DIR%\docs\Compilation.md" for more information. +CALL "%COMMON%" :SubMsg "ERROR" "LAV Filters compilation failed!" & EXIT /B 1 + + +:UnsupportedSwitch +ECHO. +ECHO Unsupported commandline switch! +ECHO. +ECHO "%~nx0 %*" +ECHO. +ECHO Run "%~nx0 help" for details about the commandline switches. +CALL "%COMMON%" :SubMsg "ERROR" "LAV Filters compilation failed!" & EXIT /B 1 + + +:ShowHelp +TITLE %~nx0 Help +ECHO. +ECHO Usage: ECHO %~nx0 [Clean^|Build^|Rebuild] [x86^|x64^|Both] [Debug^|Release] [VS2017^|VS2019] -ECHO. -ECHO Notes: You can also prefix the commands with "-", "--" or "/". -ECHO The arguments are not case sensitive and can be ommitted. -ECHO. & ECHO. -ECHO Executing %~nx0 without any arguments will use the default ones: +ECHO. +ECHO Notes: You can also prefix the commands with "-", "--" or "/". +ECHO The arguments are not case sensitive and can be ommitted. +ECHO. & ECHO. +ECHO Executing %~nx0 without any arguments will use the default ones: ECHO "%~nx0 Build Both Release VS2019" -ECHO. -POPD -ENDLOCAL -EXIT /B +ECHO. +POPD +ENDLOCAL +EXIT /B diff --git a/src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp b/src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp index 9eb0b9ebd54..7f4275b35f4 100644 --- a/src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp +++ b/src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp @@ -1,146 +1,146 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDAnimatedBitmap.cpp -// -// The CLCDAnimatedBitmap class draws animated bitmaps onto the LCD. -// An animated bitmap consists of a tiled bitmap representing the -// animation. The tile size is set with the SetSubpicWidth. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDAnimatedBitmap::CLCDAnimatedBitmap -// -//************************************************************************ - -CLCDAnimatedBitmap::CLCDAnimatedBitmap(void) -{ - m_dwCurrSubpic = 0; - m_dwTotalSubpics = 0; -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::CLCDAnimatedBitmap -// -//************************************************************************ - -CLCDAnimatedBitmap::~CLCDAnimatedBitmap(void) -{ - -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::Initialize -// -//************************************************************************ - -HRESULT CLCDAnimatedBitmap::Initialize(void) -{ - m_dwRate = 250; - m_dwElapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - - return S_OK; -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::ResetUpdate -// -//************************************************************************ - -void CLCDAnimatedBitmap::ResetUpdate(void) -{ - m_dwCurrSubpic = 0; - m_dwLastUpdate = GetTickCount(); -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::SetSubpicWidth -// -//************************************************************************ - -void CLCDAnimatedBitmap::SetSubpicWidth(DWORD dwWidth) -{ - m_dwSubpicWidth = dwWidth; - LCDUIASSERT(NULL != m_hBitmap); - LCDUIASSERT(0 != dwWidth); - if((NULL != m_hBitmap) && (0 != dwWidth)) - { - // figure out how many tiles we have - BITMAP bitmap; - if(GetObject(m_hBitmap, sizeof(bitmap), &bitmap)) - { - m_dwTotalSubpics = bitmap.bmWidth / dwWidth; - SetLogicalSize(bitmap.bmWidth, bitmap.bmHeight); - } - else - { - m_dwTotalSubpics = 0; - } - } - else - { - m_dwTotalSubpics = 0; - } -} - -//************************************************************************ -// -// CLCDAnimatedBitmap::SetAnimationRate -// -//************************************************************************ - -void CLCDAnimatedBitmap::SetAnimationRate(DWORD dwRate) -{ - m_dwRate = dwRate; -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::OnUpdate -// -//************************************************************************ - -void CLCDAnimatedBitmap::OnUpdate(DWORD dwTimestamp) -{ - m_dwElapsedTime = (dwTimestamp - m_dwLastUpdate); - - // Just update the logical origin - SetLogicalOrigin(-1 * m_dwSubpicWidth * m_dwCurrSubpic, 0); - - DWORD increment = m_dwElapsedTime / m_dwRate; - if(increment > 0) - { - m_dwCurrSubpic += increment; - m_dwCurrSubpic %= m_dwTotalSubpics; - m_dwElapsedTime %= m_dwRate; - m_dwLastUpdate = GetTickCount(); - } -} - - -//** end of LCDAnimatedBitmap.cpp **************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDAnimatedBitmap.cpp +// +// The CLCDAnimatedBitmap class draws animated bitmaps onto the LCD. +// An animated bitmap consists of a tiled bitmap representing the +// animation. The tile size is set with the SetSubpicWidth. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDAnimatedBitmap::CLCDAnimatedBitmap +// +//************************************************************************ + +CLCDAnimatedBitmap::CLCDAnimatedBitmap(void) +{ + m_dwCurrSubpic = 0; + m_dwTotalSubpics = 0; +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::CLCDAnimatedBitmap +// +//************************************************************************ + +CLCDAnimatedBitmap::~CLCDAnimatedBitmap(void) +{ + +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::Initialize +// +//************************************************************************ + +HRESULT CLCDAnimatedBitmap::Initialize(void) +{ + m_dwRate = 250; + m_dwElapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + + return S_OK; +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::ResetUpdate +// +//************************************************************************ + +void CLCDAnimatedBitmap::ResetUpdate(void) +{ + m_dwCurrSubpic = 0; + m_dwLastUpdate = GetTickCount(); +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::SetSubpicWidth +// +//************************************************************************ + +void CLCDAnimatedBitmap::SetSubpicWidth(DWORD dwWidth) +{ + m_dwSubpicWidth = dwWidth; + LCDUIASSERT(NULL != m_hBitmap); + LCDUIASSERT(0 != dwWidth); + if((NULL != m_hBitmap) && (0 != dwWidth)) + { + // figure out how many tiles we have + BITMAP bitmap; + if(GetObject(m_hBitmap, sizeof(bitmap), &bitmap)) + { + m_dwTotalSubpics = bitmap.bmWidth / dwWidth; + SetLogicalSize(bitmap.bmWidth, bitmap.bmHeight); + } + else + { + m_dwTotalSubpics = 0; + } + } + else + { + m_dwTotalSubpics = 0; + } +} + +//************************************************************************ +// +// CLCDAnimatedBitmap::SetAnimationRate +// +//************************************************************************ + +void CLCDAnimatedBitmap::SetAnimationRate(DWORD dwRate) +{ + m_dwRate = dwRate; +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::OnUpdate +// +//************************************************************************ + +void CLCDAnimatedBitmap::OnUpdate(DWORD dwTimestamp) +{ + m_dwElapsedTime = (dwTimestamp - m_dwLastUpdate); + + // Just update the logical origin + SetLogicalOrigin(-1 * m_dwSubpicWidth * m_dwCurrSubpic, 0); + + DWORD increment = m_dwElapsedTime / m_dwRate; + if(increment > 0) + { + m_dwCurrSubpic += increment; + m_dwCurrSubpic %= m_dwTotalSubpics; + m_dwElapsedTime %= m_dwRate; + m_dwLastUpdate = GetTickCount(); + } +} + + +//** end of LCDAnimatedBitmap.cpp **************************************** diff --git a/src/thirdparty/LCDUI/LCDAnimatedBitmap.h b/src/thirdparty/LCDUI/LCDAnimatedBitmap.h index 42d010ad75f..8fb83b7a9ff 100644 --- a/src/thirdparty/LCDUI/LCDAnimatedBitmap.h +++ b/src/thirdparty/LCDUI/LCDAnimatedBitmap.h @@ -1,57 +1,57 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDAnimatedBitmap.h -// -// The CLCDAnimatedBitmap class draws animated bitmaps onto the LCD. -// An animated bitmap consists of a tiled bitmap representing the -// animation. The tile size is set with the SetSubpicWidth. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - - -#ifndef _LCDANIMATEDBITMAP_H_INCLUDED_ -#define _LCDANIMATEDBITMAP_H_INCLUDED_ - -#include "LCDBase.h" -#include "LCDBitmap.h" - -class CLCDAnimatedBitmap : public CLCDBitmap -{ -public: - CLCDAnimatedBitmap(void); - virtual ~CLCDAnimatedBitmap(void); - - virtual HRESULT Initialize(void); - virtual void ResetUpdate(void); - - void SetSubpicWidth(DWORD dwWidth); - void SetAnimationRate(DWORD dwRate); // milliseconds/subpicture - -protected: - virtual void OnUpdate(DWORD dwTimestamp); - -private: - DWORD m_dwElapsedTime; // elapsed time in state - DWORD m_dwRate; // milliseconds per subpicture - DWORD m_dwLastUpdate; // milliseconds - - DWORD m_dwSubpicWidth; - DWORD m_dwCurrSubpic; - DWORD m_dwTotalSubpics; -}; - - -#endif // !_LCDANIMATEDBITMAP_H_INCLUDED_ - -//** end of LCDBitmap.h ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDAnimatedBitmap.h +// +// The CLCDAnimatedBitmap class draws animated bitmaps onto the LCD. +// An animated bitmap consists of a tiled bitmap representing the +// animation. The tile size is set with the SetSubpicWidth. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + + +#ifndef _LCDANIMATEDBITMAP_H_INCLUDED_ +#define _LCDANIMATEDBITMAP_H_INCLUDED_ + +#include "LCDBase.h" +#include "LCDBitmap.h" + +class CLCDAnimatedBitmap : public CLCDBitmap +{ +public: + CLCDAnimatedBitmap(void); + virtual ~CLCDAnimatedBitmap(void); + + virtual HRESULT Initialize(void); + virtual void ResetUpdate(void); + + void SetSubpicWidth(DWORD dwWidth); + void SetAnimationRate(DWORD dwRate); // milliseconds/subpicture + +protected: + virtual void OnUpdate(DWORD dwTimestamp); + +private: + DWORD m_dwElapsedTime; // elapsed time in state + DWORD m_dwRate; // milliseconds per subpicture + DWORD m_dwLastUpdate; // milliseconds + + DWORD m_dwSubpicWidth; + DWORD m_dwCurrSubpic; + DWORD m_dwTotalSubpics; +}; + + +#endif // !_LCDANIMATEDBITMAP_H_INCLUDED_ + +//** end of LCDBitmap.h ************************************************** diff --git a/src/thirdparty/LCDUI/LCDBase.cpp b/src/thirdparty/LCDUI/LCDBase.cpp index 0b28837c56e..8964f0bf570 100644 --- a/src/thirdparty/LCDUI/LCDBase.cpp +++ b/src/thirdparty/LCDUI/LCDBase.cpp @@ -1,385 +1,385 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDBase.cpp -// -// The CLCDBase class is the generic base class for all lcd ui objects -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDBase::CLCDBase -// -//************************************************************************ - -CLCDBase::CLCDBase(void) -{ - m_Size.cx = 0; - m_Size.cy = 0; - m_Origin.x = 0; - m_Origin.y = 0; - m_bVisible = TRUE; - m_bInverted = FALSE; - ZeroMemory(&m_ptLogical, sizeof(m_ptLogical)); - ZeroMemory(&m_sizeLogical, sizeof(m_sizeLogical)); - m_nBkMode = TRANSPARENT; - m_objectType = LG_UNKNOWN; - m_crBackgroundColor = RGB(0, 0, 0); - m_crForegroundColor = RGB(255, 255, 255); -} - - -//************************************************************************ -// -// CLCDBase::~CLCDBase -// -//************************************************************************ - -CLCDBase::~CLCDBase(void) -{ -} - - -//************************************************************************ -// -// CLCDBase::Initialize -// -//************************************************************************ - -HRESULT CLCDBase::Initialize(void) -{ - return S_OK; -} - - -//************************************************************************ -// -// CLCDBase::Shutdown -// -//************************************************************************ - -void CLCDBase::Shutdown(void) -{ -} - - -//************************************************************************ -// -// CLCDBase::SetOrigin -// -//************************************************************************ - -void CLCDBase::SetOrigin(POINT pt) -{ - m_Origin = pt; -} - - -//************************************************************************ -// -// CLCDBase::SetOrigin -// -//************************************************************************ - -void CLCDBase::SetOrigin(int nX, int nY) -{ - POINT pt = { nX, nY }; - SetOrigin(pt); -} - - -//************************************************************************ -// -// CLCDBase::GetOrigin -// -//************************************************************************ - -POINT& CLCDBase::GetOrigin(void) -{ - return m_Origin; -} - - -//************************************************************************ -// -// CLCDBase::SetSize -// -//************************************************************************ - -void CLCDBase::SetSize(SIZE& size) -{ - m_Size = size; - SetLogicalSize(m_Size); -} - - -//************************************************************************ -// -// CLCDBase::SetSize -// -//************************************************************************ - -void CLCDBase::SetSize(int nCX, int nCY) -{ - SIZE size = { nCX, nCY }; - SetSize(size); -} - - -//************************************************************************ -// -// CLCDBase::GetSize -// -//************************************************************************ - -SIZE& CLCDBase::GetSize(void) -{ - return m_Size; -} - - -//************************************************************************ -// -// CLCDBase::SetLogicalOrigin -// -//************************************************************************ - -void CLCDBase::SetLogicalOrigin(POINT& pt) -{ - m_ptLogical = pt; -} - - -//************************************************************************ -// -// CLCDBase::SetLogicalOrigin -// -//************************************************************************ - -void CLCDBase::SetLogicalOrigin(int nX, int nY) -{ - m_ptLogical.x = nX; - m_ptLogical.y = nY; -} - - -//************************************************************************ -// -// CLCDBase::GetLogicalOrigin -// -//************************************************************************ - -POINT& CLCDBase::GetLogicalOrigin(void) -{ - return m_ptLogical; -} - - -//************************************************************************ -// -// CLCDBase::SetLogicalSize -// -//************************************************************************ - -void CLCDBase::SetLogicalSize(SIZE& size) -{ - m_sizeLogical = size; -} - - -//************************************************************************ -// -// CLCDBase::SetLogicalSize -// -//************************************************************************ - -void CLCDBase::SetLogicalSize(int nCX, int nCY) -{ - m_sizeLogical.cx = nCX; - m_sizeLogical.cy = nCY; -} - - -//************************************************************************ -// -// CLCDBase::GetLogicalSize -// -//************************************************************************ - -SIZE& CLCDBase::GetLogicalSize(void) -{ - return m_sizeLogical; -} - - -//************************************************************************ -// -// CLCDBase::Show -// -//************************************************************************ - -void CLCDBase::Show(BOOL bShow) -{ - m_bVisible = bShow; -} - - -//************************************************************************ -// -// BOOL CLCDBase:: -// -//************************************************************************ - -BOOL CLCDBase::IsVisible(void) -{ - return m_bVisible; -} - - -//************************************************************************ -// -// CLCDBase::Invert -// -//************************************************************************ - -void CLCDBase::Invert(BOOL bEnable) -{ - m_bInverted = bEnable; -} - - -//************************************************************************ -// -// CLCDBase::ResetUpdate -// -//************************************************************************ - -void CLCDBase::ResetUpdate(void) -{ - // do nothing -} - - -//************************************************************************ -// -// CLCDBase::OnUpdate -// -//************************************************************************ - -void CLCDBase::OnUpdate(DWORD dwTimestamp) -{ - UNREFERENCED_PARAMETER(dwTimestamp); -} - - -//************************************************************************ -// -// CLCDBase::OnPrepareDraw -// -//************************************************************************ - -void CLCDBase::OnPrepareDraw(CLCDGfxBase &rGfx) -{ - UNREFERENCED_PARAMETER(rGfx); -} - - -//************************************************************************ -// -// CLCDBase::OnDraw -// -//************************************************************************ - -void CLCDBase::OnDraw(CLCDGfxBase &rGfx) -{ - UNREFERENCED_PARAMETER(rGfx); -} - - -//************************************************************************ -// -// CLCDBase::SetBackgroundMode -// -//************************************************************************ - -void CLCDBase::SetBackgroundMode(int nMode) -{ - m_nBkMode = nMode; -} - - -//************************************************************************ -// -// CLCDBase::GetBackgroundMode -// -//************************************************************************ - -int CLCDBase::GetBackgroundMode() -{ - return m_nBkMode; -} - - -//************************************************************************ -// -// CLCDBase::GetObjectType -// -//************************************************************************ - -const LGObjectType CLCDBase::GetObjectType() -{ - return m_objectType; -} - - -//************************************************************************ -// -// CLCDBase::SetObjectType -// -//************************************************************************ - -void CLCDBase::SetObjectType(const LGObjectType type) -{ - m_objectType = type; -} - - -//************************************************************************ -// -// CLCDBase::SetForegroundColor -// -//************************************************************************ - -void CLCDBase::SetForegroundColor(COLORREF crForeground) -{ - m_crForegroundColor = crForeground; -} - - -//************************************************************************ -// -// CLCDBase::SetBackgroundColor -// -//************************************************************************ - -void CLCDBase::SetBackgroundColor(COLORREF crBackground) -{ - m_crBackgroundColor = crBackground; -} - - -//** end of LCDBase.cpp ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDBase.cpp +// +// The CLCDBase class is the generic base class for all lcd ui objects +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDBase::CLCDBase +// +//************************************************************************ + +CLCDBase::CLCDBase(void) +{ + m_Size.cx = 0; + m_Size.cy = 0; + m_Origin.x = 0; + m_Origin.y = 0; + m_bVisible = TRUE; + m_bInverted = FALSE; + ZeroMemory(&m_ptLogical, sizeof(m_ptLogical)); + ZeroMemory(&m_sizeLogical, sizeof(m_sizeLogical)); + m_nBkMode = TRANSPARENT; + m_objectType = LG_UNKNOWN; + m_crBackgroundColor = RGB(0, 0, 0); + m_crForegroundColor = RGB(255, 255, 255); +} + + +//************************************************************************ +// +// CLCDBase::~CLCDBase +// +//************************************************************************ + +CLCDBase::~CLCDBase(void) +{ +} + + +//************************************************************************ +// +// CLCDBase::Initialize +// +//************************************************************************ + +HRESULT CLCDBase::Initialize(void) +{ + return S_OK; +} + + +//************************************************************************ +// +// CLCDBase::Shutdown +// +//************************************************************************ + +void CLCDBase::Shutdown(void) +{ +} + + +//************************************************************************ +// +// CLCDBase::SetOrigin +// +//************************************************************************ + +void CLCDBase::SetOrigin(POINT pt) +{ + m_Origin = pt; +} + + +//************************************************************************ +// +// CLCDBase::SetOrigin +// +//************************************************************************ + +void CLCDBase::SetOrigin(int nX, int nY) +{ + POINT pt = { nX, nY }; + SetOrigin(pt); +} + + +//************************************************************************ +// +// CLCDBase::GetOrigin +// +//************************************************************************ + +POINT& CLCDBase::GetOrigin(void) +{ + return m_Origin; +} + + +//************************************************************************ +// +// CLCDBase::SetSize +// +//************************************************************************ + +void CLCDBase::SetSize(SIZE& size) +{ + m_Size = size; + SetLogicalSize(m_Size); +} + + +//************************************************************************ +// +// CLCDBase::SetSize +// +//************************************************************************ + +void CLCDBase::SetSize(int nCX, int nCY) +{ + SIZE size = { nCX, nCY }; + SetSize(size); +} + + +//************************************************************************ +// +// CLCDBase::GetSize +// +//************************************************************************ + +SIZE& CLCDBase::GetSize(void) +{ + return m_Size; +} + + +//************************************************************************ +// +// CLCDBase::SetLogicalOrigin +// +//************************************************************************ + +void CLCDBase::SetLogicalOrigin(POINT& pt) +{ + m_ptLogical = pt; +} + + +//************************************************************************ +// +// CLCDBase::SetLogicalOrigin +// +//************************************************************************ + +void CLCDBase::SetLogicalOrigin(int nX, int nY) +{ + m_ptLogical.x = nX; + m_ptLogical.y = nY; +} + + +//************************************************************************ +// +// CLCDBase::GetLogicalOrigin +// +//************************************************************************ + +POINT& CLCDBase::GetLogicalOrigin(void) +{ + return m_ptLogical; +} + + +//************************************************************************ +// +// CLCDBase::SetLogicalSize +// +//************************************************************************ + +void CLCDBase::SetLogicalSize(SIZE& size) +{ + m_sizeLogical = size; +} + + +//************************************************************************ +// +// CLCDBase::SetLogicalSize +// +//************************************************************************ + +void CLCDBase::SetLogicalSize(int nCX, int nCY) +{ + m_sizeLogical.cx = nCX; + m_sizeLogical.cy = nCY; +} + + +//************************************************************************ +// +// CLCDBase::GetLogicalSize +// +//************************************************************************ + +SIZE& CLCDBase::GetLogicalSize(void) +{ + return m_sizeLogical; +} + + +//************************************************************************ +// +// CLCDBase::Show +// +//************************************************************************ + +void CLCDBase::Show(BOOL bShow) +{ + m_bVisible = bShow; +} + + +//************************************************************************ +// +// BOOL CLCDBase:: +// +//************************************************************************ + +BOOL CLCDBase::IsVisible(void) +{ + return m_bVisible; +} + + +//************************************************************************ +// +// CLCDBase::Invert +// +//************************************************************************ + +void CLCDBase::Invert(BOOL bEnable) +{ + m_bInverted = bEnable; +} + + +//************************************************************************ +// +// CLCDBase::ResetUpdate +// +//************************************************************************ + +void CLCDBase::ResetUpdate(void) +{ + // do nothing +} + + +//************************************************************************ +// +// CLCDBase::OnUpdate +// +//************************************************************************ + +void CLCDBase::OnUpdate(DWORD dwTimestamp) +{ + UNREFERENCED_PARAMETER(dwTimestamp); +} + + +//************************************************************************ +// +// CLCDBase::OnPrepareDraw +// +//************************************************************************ + +void CLCDBase::OnPrepareDraw(CLCDGfxBase &rGfx) +{ + UNREFERENCED_PARAMETER(rGfx); +} + + +//************************************************************************ +// +// CLCDBase::OnDraw +// +//************************************************************************ + +void CLCDBase::OnDraw(CLCDGfxBase &rGfx) +{ + UNREFERENCED_PARAMETER(rGfx); +} + + +//************************************************************************ +// +// CLCDBase::SetBackgroundMode +// +//************************************************************************ + +void CLCDBase::SetBackgroundMode(int nMode) +{ + m_nBkMode = nMode; +} + + +//************************************************************************ +// +// CLCDBase::GetBackgroundMode +// +//************************************************************************ + +int CLCDBase::GetBackgroundMode() +{ + return m_nBkMode; +} + + +//************************************************************************ +// +// CLCDBase::GetObjectType +// +//************************************************************************ + +const LGObjectType CLCDBase::GetObjectType() +{ + return m_objectType; +} + + +//************************************************************************ +// +// CLCDBase::SetObjectType +// +//************************************************************************ + +void CLCDBase::SetObjectType(const LGObjectType type) +{ + m_objectType = type; +} + + +//************************************************************************ +// +// CLCDBase::SetForegroundColor +// +//************************************************************************ + +void CLCDBase::SetForegroundColor(COLORREF crForeground) +{ + m_crForegroundColor = crForeground; +} + + +//************************************************************************ +// +// CLCDBase::SetBackgroundColor +// +//************************************************************************ + +void CLCDBase::SetBackgroundColor(COLORREF crBackground) +{ + m_crBackgroundColor = crBackground; +} + + +//** end of LCDBase.cpp ************************************************** diff --git a/src/thirdparty/LCDUI/LCDBase.h b/src/thirdparty/LCDUI/LCDBase.h index 3ca78c9a19a..2913eaba4e0 100644 --- a/src/thirdparty/LCDUI/LCDBase.h +++ b/src/thirdparty/LCDUI/LCDBase.h @@ -1,97 +1,97 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDBase.h -// -// The CLCDBase class is the generic base class for all lcd ui objects -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDBASE_H_INCLUDED_ -#define _LCDBASE_H_INCLUDED_ - -#include "LCDGfxBase.h" - -typedef enum -{ - LG_SCROLLING_TEXT, LG_STATIC_TEXT, LG_ICON, LG_PROGRESS_BAR, LG_UNKNOWN, LG_RIGHTFOCUS_TEXT, LG_BOTTOMFOCUS_TEXT -} LGObjectType; - -class CLCDBase -{ -public: - CLCDBase(void); - virtual ~CLCDBase(void); - -public: - virtual HRESULT Initialize(void); - virtual void Shutdown(void); - - virtual void SetOrigin(POINT pt); - virtual void SetOrigin(int nX, int nY); - virtual POINT& GetOrigin(void); - - virtual void SetSize(SIZE& size); - virtual void SetSize(int nCX, int nCY); - virtual SIZE& GetSize(void); - - virtual int GetWidth(void) { return GetSize().cx; } - virtual int GetHeight(void) { return GetSize().cy; }; - - virtual void Show(BOOL bShow); - virtual BOOL IsVisible(); - - virtual void Invert(BOOL bEnable); - virtual void ResetUpdate(void); - - // local coordinates - virtual void SetLogicalOrigin(POINT& rLogical); - virtual void SetLogicalOrigin(int nX, int nY); - virtual POINT& GetLogicalOrigin(void); - virtual void SetLogicalSize(SIZE& size); - virtual void SetLogicalSize(int nCX, int nCY); - virtual SIZE& GetLogicalSize(void); - - virtual void SetBackgroundMode(int nMode); - virtual int GetBackgroundMode(); - - virtual const LGObjectType GetObjectType(); - virtual void SetObjectType(const LGObjectType type); - - virtual void SetForegroundColor(COLORREF crForeground); - virtual void SetBackgroundColor(COLORREF crBackground); - -public: - virtual void OnPrepareDraw(CLCDGfxBase &rGfx); - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void OnUpdate(DWORD dwTimestamp); - -protected: - SIZE m_Size; - POINT m_Origin; - BOOL m_bVisible; - BOOL m_bInverted; - - POINT m_ptLogical; - SIZE m_sizeLogical; - int m_nBkMode; - - LGObjectType m_objectType; - - COLORREF m_crBackgroundColor, m_crForegroundColor; -}; - - -#endif // !_LCDBASE_H_INCLUDED_ - -//** end of LCDBase.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDBase.h +// +// The CLCDBase class is the generic base class for all lcd ui objects +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDBASE_H_INCLUDED_ +#define _LCDBASE_H_INCLUDED_ + +#include "LCDGfxBase.h" + +typedef enum +{ + LG_SCROLLING_TEXT, LG_STATIC_TEXT, LG_ICON, LG_PROGRESS_BAR, LG_UNKNOWN, LG_RIGHTFOCUS_TEXT, LG_BOTTOMFOCUS_TEXT +} LGObjectType; + +class CLCDBase +{ +public: + CLCDBase(void); + virtual ~CLCDBase(void); + +public: + virtual HRESULT Initialize(void); + virtual void Shutdown(void); + + virtual void SetOrigin(POINT pt); + virtual void SetOrigin(int nX, int nY); + virtual POINT& GetOrigin(void); + + virtual void SetSize(SIZE& size); + virtual void SetSize(int nCX, int nCY); + virtual SIZE& GetSize(void); + + virtual int GetWidth(void) { return GetSize().cx; } + virtual int GetHeight(void) { return GetSize().cy; }; + + virtual void Show(BOOL bShow); + virtual BOOL IsVisible(); + + virtual void Invert(BOOL bEnable); + virtual void ResetUpdate(void); + + // local coordinates + virtual void SetLogicalOrigin(POINT& rLogical); + virtual void SetLogicalOrigin(int nX, int nY); + virtual POINT& GetLogicalOrigin(void); + virtual void SetLogicalSize(SIZE& size); + virtual void SetLogicalSize(int nCX, int nCY); + virtual SIZE& GetLogicalSize(void); + + virtual void SetBackgroundMode(int nMode); + virtual int GetBackgroundMode(); + + virtual const LGObjectType GetObjectType(); + virtual void SetObjectType(const LGObjectType type); + + virtual void SetForegroundColor(COLORREF crForeground); + virtual void SetBackgroundColor(COLORREF crBackground); + +public: + virtual void OnPrepareDraw(CLCDGfxBase &rGfx); + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void OnUpdate(DWORD dwTimestamp); + +protected: + SIZE m_Size; + POINT m_Origin; + BOOL m_bVisible; + BOOL m_bInverted; + + POINT m_ptLogical; + SIZE m_sizeLogical; + int m_nBkMode; + + LGObjectType m_objectType; + + COLORREF m_crBackgroundColor, m_crForegroundColor; +}; + + +#endif // !_LCDBASE_H_INCLUDED_ + +//** end of LCDBase.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDBitmap.cpp b/src/thirdparty/LCDUI/LCDBitmap.cpp index 1b2b54df900..31340e2643c 100644 --- a/src/thirdparty/LCDUI/LCDBitmap.cpp +++ b/src/thirdparty/LCDUI/LCDBitmap.cpp @@ -1,179 +1,179 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDBitmap.cpp -// -// The CLCDBitmap class draws bitmaps onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDBitmap::CLCDBitmap -// -//************************************************************************ - -CLCDBitmap::CLCDBitmap(void) -{ - m_hBitmap = NULL; - m_dwROP = SRCCOPY; - m_fZoom = 1.0f; - m_bAlpha = TRUE; -} - - -//************************************************************************ -// -// CLCDBitmap::CLCDBitmap -// -//************************************************************************ - -CLCDBitmap::~CLCDBitmap(void) -{ - -} - - -//************************************************************************ -// -// CLCDBitmap::SetBitmap -// -//************************************************************************ - -void CLCDBitmap::SetBitmap(HBITMAP hBitmap) -{ - m_hBitmap = hBitmap; -} - - -//************************************************************************ -// -// CLCDBitmap::GetBitmap -// -//************************************************************************ -HBITMAP CLCDBitmap::GetBitmap(void) -{ - return m_hBitmap; -} - - -//************************************************************************ -// -// CLCDBitmap::SetBitmap -// -//************************************************************************ - -void CLCDBitmap::SetROP(DWORD dwROP) -{ - m_dwROP = dwROP; -} - - -//************************************************************************ -// -// CLCDBitmap::SetZoomLevel -// -//************************************************************************ - -void CLCDBitmap::SetZoomLevel(float fzoom) -{ - m_fZoom = fzoom; -} - - -//************************************************************************ -// -// CLCDBitmap::GetZoomLevel -// -//************************************************************************ - -float CLCDBitmap::GetZoomLevel(void) -{ - return m_fZoom; -} - - -//************************************************************************ -// -// CLCDBitmap::SetAlpha -// -//************************************************************************ - -void CLCDBitmap::SetAlpha(BOOL bAlpha) -{ - m_bAlpha = bAlpha; -} - - -//************************************************************************ -// -// CLCDBitmap::OnDraw -// -// The logical size is our 'canvas'. -// The control size is our 'window'. The window size can be smaller than the canvas. -// The assumption is that the bitmap size is the size of the canvas. -//************************************************************************ - -void CLCDBitmap::OnDraw(CLCDGfxBase &rGfx) -{ - if(m_hBitmap) - { - HDC hCompatibleDC = CreateCompatibleDC(rGfx.GetHDC()); - HBITMAP hOldBitmap = (HBITMAP)SelectObject(hCompatibleDC, m_hBitmap); - - // If monochrome output, don't even bother with alpha blend - if (LGLCD_BMP_FORMAT_160x43x1 == rGfx.GetLCDScreen()->hdr.Format) - { - BitBlt(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_dwROP); - } - else - { - if(0.001f > fabs(1.0f - m_fZoom)) - { - BOOL b = FALSE; - if(m_bAlpha) - { - BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - b = AlphaBlend(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); - } - else - { - BitBlt(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_dwROP); - } - } - else - { - if(m_bAlpha) - { - BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - AlphaBlend(rGfx.GetHDC(), 0, 0, (int)(m_fZoom* m_sizeLogical.cx), (int)(m_fZoom*m_sizeLogical.cy), hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); - } - else - { - BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, 0}; - AlphaBlend(rGfx.GetHDC(), 0, 0, (int)(m_fZoom* m_sizeLogical.cx), (int)(m_fZoom*m_sizeLogical.cy), hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); - } - } - } - - // restores - SelectObject(hCompatibleDC, hOldBitmap); - DeleteDC(hCompatibleDC); - } -} - - -//** end of LCDBitmap.cpp ************************************************ +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDBitmap.cpp +// +// The CLCDBitmap class draws bitmaps onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDBitmap::CLCDBitmap +// +//************************************************************************ + +CLCDBitmap::CLCDBitmap(void) +{ + m_hBitmap = NULL; + m_dwROP = SRCCOPY; + m_fZoom = 1.0f; + m_bAlpha = TRUE; +} + + +//************************************************************************ +// +// CLCDBitmap::CLCDBitmap +// +//************************************************************************ + +CLCDBitmap::~CLCDBitmap(void) +{ + +} + + +//************************************************************************ +// +// CLCDBitmap::SetBitmap +// +//************************************************************************ + +void CLCDBitmap::SetBitmap(HBITMAP hBitmap) +{ + m_hBitmap = hBitmap; +} + + +//************************************************************************ +// +// CLCDBitmap::GetBitmap +// +//************************************************************************ +HBITMAP CLCDBitmap::GetBitmap(void) +{ + return m_hBitmap; +} + + +//************************************************************************ +// +// CLCDBitmap::SetBitmap +// +//************************************************************************ + +void CLCDBitmap::SetROP(DWORD dwROP) +{ + m_dwROP = dwROP; +} + + +//************************************************************************ +// +// CLCDBitmap::SetZoomLevel +// +//************************************************************************ + +void CLCDBitmap::SetZoomLevel(float fzoom) +{ + m_fZoom = fzoom; +} + + +//************************************************************************ +// +// CLCDBitmap::GetZoomLevel +// +//************************************************************************ + +float CLCDBitmap::GetZoomLevel(void) +{ + return m_fZoom; +} + + +//************************************************************************ +// +// CLCDBitmap::SetAlpha +// +//************************************************************************ + +void CLCDBitmap::SetAlpha(BOOL bAlpha) +{ + m_bAlpha = bAlpha; +} + + +//************************************************************************ +// +// CLCDBitmap::OnDraw +// +// The logical size is our 'canvas'. +// The control size is our 'window'. The window size can be smaller than the canvas. +// The assumption is that the bitmap size is the size of the canvas. +//************************************************************************ + +void CLCDBitmap::OnDraw(CLCDGfxBase &rGfx) +{ + if(m_hBitmap) + { + HDC hCompatibleDC = CreateCompatibleDC(rGfx.GetHDC()); + HBITMAP hOldBitmap = (HBITMAP)SelectObject(hCompatibleDC, m_hBitmap); + + // If monochrome output, don't even bother with alpha blend + if (LGLCD_BMP_FORMAT_160x43x1 == rGfx.GetLCDScreen()->hdr.Format) + { + BitBlt(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_dwROP); + } + else + { + if(0.001f > fabs(1.0f - m_fZoom)) + { + BOOL b = FALSE; + if(m_bAlpha) + { + BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; + b = AlphaBlend(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); + } + else + { + BitBlt(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_dwROP); + } + } + else + { + if(m_bAlpha) + { + BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; + AlphaBlend(rGfx.GetHDC(), 0, 0, (int)(m_fZoom* m_sizeLogical.cx), (int)(m_fZoom*m_sizeLogical.cy), hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); + } + else + { + BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, 0}; + AlphaBlend(rGfx.GetHDC(), 0, 0, (int)(m_fZoom* m_sizeLogical.cx), (int)(m_fZoom*m_sizeLogical.cy), hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); + } + } + } + + // restores + SelectObject(hCompatibleDC, hOldBitmap); + DeleteDC(hCompatibleDC); + } +} + + +//** end of LCDBitmap.cpp ************************************************ diff --git a/src/thirdparty/LCDUI/LCDBitmap.h b/src/thirdparty/LCDUI/LCDBitmap.h index 2547d8ce239..f79ff85d05d 100644 --- a/src/thirdparty/LCDUI/LCDBitmap.h +++ b/src/thirdparty/LCDUI/LCDBitmap.h @@ -1,54 +1,54 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDBitmap.h -// -// The CLCDBitmap class draws bitmaps onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDBITMAP_H_INCLUDED_ -#define _LCDBITMAP_H_INCLUDED_ - -#include "LCDBase.h" - -class CLCDBitmap : public CLCDBase -{ -public: - CLCDBitmap(); - virtual ~CLCDBitmap(); - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - - void SetBitmap(HBITMAP hBitmap); - HBITMAP GetBitmap(void); - void SetROP(DWORD dwROP); - void SetZoomLevel(float fzoom); - float GetZoomLevel(void); - void SetAlpha(BOOL bAlpha); - -protected: - HBITMAP m_hBitmap; - DWORD m_dwROP; - float m_fZoom; - // this indicates the bitmap has an alpha channel - BOOL m_bAlpha; - -private: -}; - - -#endif // !_LCDBITMAP_H_INCLUDED_ - -//** end of LCDBitmap.h ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDBitmap.h +// +// The CLCDBitmap class draws bitmaps onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDBITMAP_H_INCLUDED_ +#define _LCDBITMAP_H_INCLUDED_ + +#include "LCDBase.h" + +class CLCDBitmap : public CLCDBase +{ +public: + CLCDBitmap(); + virtual ~CLCDBitmap(); + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + + void SetBitmap(HBITMAP hBitmap); + HBITMAP GetBitmap(void); + void SetROP(DWORD dwROP); + void SetZoomLevel(float fzoom); + float GetZoomLevel(void); + void SetAlpha(BOOL bAlpha); + +protected: + HBITMAP m_hBitmap; + DWORD m_dwROP; + float m_fZoom; + // this indicates the bitmap has an alpha channel + BOOL m_bAlpha; + +private: +}; + + +#endif // !_LCDBITMAP_H_INCLUDED_ + +//** end of LCDBitmap.h ************************************************** diff --git a/src/thirdparty/LCDUI/LCDCollection.cpp b/src/thirdparty/LCDUI/LCDCollection.cpp index 2d3dc3a930a..1d3e3ec07ac 100644 --- a/src/thirdparty/LCDUI/LCDCollection.cpp +++ b/src/thirdparty/LCDUI/LCDCollection.cpp @@ -1,233 +1,233 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDCollection.cpp -// -// Holds a collection of base items. Its draw will draw everything -// in its list. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDCollection::CLCDCollection -// -//************************************************************************ - -CLCDCollection::CLCDCollection(void) -{ -} - - -//************************************************************************ -// -// CLCDCollection::~CLCDCollection -// -//************************************************************************ - -CLCDCollection::~CLCDCollection(void) -{ - -} - - -//************************************************************************ -// -// CLCDCollection::GetObjectCount -// -//************************************************************************ - -int CLCDCollection::GetObjectCount(void) -{ - return (int)m_Objects.size(); -} - - -//************************************************************************ -// -// CLCDCollection::AddObject -// -//************************************************************************ - -bool CLCDCollection::AddObject(CLCDBase* pObject) -{ - m_Objects.push_back(pObject); - return true; -} - - -//************************************************************************ -// -// CLCDCollection::RemoveObject -// -//************************************************************************ - -bool CLCDCollection::RemoveObject(CLCDBase* pObject) -{ - LCD_OBJECT_LIST::iterator it = - std::find(m_Objects.begin(), m_Objects.end(), pObject); - if(it != m_Objects.end()) - { - m_Objects.erase(it); - return true; - } - - return false; -} - - -//************************************************************************ -// -// CLCDCollection::RemoveObject -// -//************************************************************************ - -bool CLCDCollection::RemoveObject(int objpos) -{ - if(!m_Objects.empty()) - { - if((0 <= objpos) && (objpos < (int) m_Objects.size())) - { - m_Objects.erase(m_Objects.begin() + objpos); - return true; - } - } - return false; -} - - -//************************************************************************ -// -// CLCDCollection::RemoveAll -// -//************************************************************************ - -void CLCDCollection::RemoveAll() -{ - m_Objects.clear(); -} - - -//************************************************************************ -// -// CLCDCollection::RetrieveObject -// -//************************************************************************ - -CLCDBase* CLCDCollection::RetrieveObject(int objpos) -{ - if(!m_Objects.empty()) - { - if((0 <= objpos) && (objpos < (int) m_Objects.size())) - { - return m_Objects[objpos]; - } - } - return NULL; -} - - -//************************************************************************ -// -// CLCDCollection::OnDraw -// -//************************************************************************ - -void CLCDCollection::OnDraw(CLCDGfxBase &rGfx) -{ - if(!IsVisible()) - { - return; - } - - //iterate through your objects and draw them - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it++; - LCDUIASSERT(NULL != pObject); - - if (pObject->IsVisible()) - { - pObject->OnPrepareDraw(rGfx); - - // create the clip region - HRGN hRgn = CreateRectRgn(pObject->GetOrigin().x, pObject->GetOrigin().y, - pObject->GetOrigin().x + pObject->GetWidth(), - pObject->GetOrigin().y + pObject->GetHeight()); - - // ensure that controls only draw within their specified region - SelectClipRgn(rGfx.GetHDC(), hRgn); - - // free the region (a copy is used in the call above) - DeleteObject(hRgn); - - // offset the control at its origin so controls use (0,0) - POINT ptPrevViewportOrg = { 0, 0 }; - SetViewportOrgEx(rGfx.GetHDC(), - pObject->GetOrigin().x, - pObject->GetOrigin().y, - &ptPrevViewportOrg); - - // allow controls to supply additional translation - // this allows controls to move freely within the confined viewport - OffsetViewportOrgEx(rGfx.GetHDC(), - pObject->GetLogicalOrigin().x, - pObject->GetLogicalOrigin().y, - NULL); - - pObject->OnDraw(rGfx); - - // set the clipping region to nothing - SelectClipRgn(rGfx.GetHDC(), NULL); - - // restore the viewport origin - SetViewportOrgEx(rGfx.GetHDC(), - ptPrevViewportOrg.x, - ptPrevViewportOrg.y, - NULL); - - // restore the viewport origin offset - OffsetViewportOrgEx(rGfx.GetHDC(), 0, 0, NULL); - } - } -} - - -//************************************************************************ -// -// CLCDCollection::OnUpdate -// -//************************************************************************ - -void CLCDCollection::OnUpdate(DWORD dwTimestamp) -{ - //iterate through your objects and update them - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it++; - LCDUIASSERT(NULL != pObject); - - pObject->OnUpdate(dwTimestamp); - } - - //and update yourself - CLCDBase::OnUpdate(dwTimestamp); -} - - -//** end of LCDCollection.cpp ******************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDCollection.cpp +// +// Holds a collection of base items. Its draw will draw everything +// in its list. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDCollection::CLCDCollection +// +//************************************************************************ + +CLCDCollection::CLCDCollection(void) +{ +} + + +//************************************************************************ +// +// CLCDCollection::~CLCDCollection +// +//************************************************************************ + +CLCDCollection::~CLCDCollection(void) +{ + +} + + +//************************************************************************ +// +// CLCDCollection::GetObjectCount +// +//************************************************************************ + +int CLCDCollection::GetObjectCount(void) +{ + return (int)m_Objects.size(); +} + + +//************************************************************************ +// +// CLCDCollection::AddObject +// +//************************************************************************ + +bool CLCDCollection::AddObject(CLCDBase* pObject) +{ + m_Objects.push_back(pObject); + return true; +} + + +//************************************************************************ +// +// CLCDCollection::RemoveObject +// +//************************************************************************ + +bool CLCDCollection::RemoveObject(CLCDBase* pObject) +{ + LCD_OBJECT_LIST::iterator it = + std::find(m_Objects.begin(), m_Objects.end(), pObject); + if(it != m_Objects.end()) + { + m_Objects.erase(it); + return true; + } + + return false; +} + + +//************************************************************************ +// +// CLCDCollection::RemoveObject +// +//************************************************************************ + +bool CLCDCollection::RemoveObject(int objpos) +{ + if(!m_Objects.empty()) + { + if((0 <= objpos) && (objpos < (int) m_Objects.size())) + { + m_Objects.erase(m_Objects.begin() + objpos); + return true; + } + } + return false; +} + + +//************************************************************************ +// +// CLCDCollection::RemoveAll +// +//************************************************************************ + +void CLCDCollection::RemoveAll() +{ + m_Objects.clear(); +} + + +//************************************************************************ +// +// CLCDCollection::RetrieveObject +// +//************************************************************************ + +CLCDBase* CLCDCollection::RetrieveObject(int objpos) +{ + if(!m_Objects.empty()) + { + if((0 <= objpos) && (objpos < (int) m_Objects.size())) + { + return m_Objects[objpos]; + } + } + return NULL; +} + + +//************************************************************************ +// +// CLCDCollection::OnDraw +// +//************************************************************************ + +void CLCDCollection::OnDraw(CLCDGfxBase &rGfx) +{ + if(!IsVisible()) + { + return; + } + + //iterate through your objects and draw them + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it++; + LCDUIASSERT(NULL != pObject); + + if (pObject->IsVisible()) + { + pObject->OnPrepareDraw(rGfx); + + // create the clip region + HRGN hRgn = CreateRectRgn(pObject->GetOrigin().x, pObject->GetOrigin().y, + pObject->GetOrigin().x + pObject->GetWidth(), + pObject->GetOrigin().y + pObject->GetHeight()); + + // ensure that controls only draw within their specified region + SelectClipRgn(rGfx.GetHDC(), hRgn); + + // free the region (a copy is used in the call above) + DeleteObject(hRgn); + + // offset the control at its origin so controls use (0,0) + POINT ptPrevViewportOrg = { 0, 0 }; + SetViewportOrgEx(rGfx.GetHDC(), + pObject->GetOrigin().x, + pObject->GetOrigin().y, + &ptPrevViewportOrg); + + // allow controls to supply additional translation + // this allows controls to move freely within the confined viewport + OffsetViewportOrgEx(rGfx.GetHDC(), + pObject->GetLogicalOrigin().x, + pObject->GetLogicalOrigin().y, + NULL); + + pObject->OnDraw(rGfx); + + // set the clipping region to nothing + SelectClipRgn(rGfx.GetHDC(), NULL); + + // restore the viewport origin + SetViewportOrgEx(rGfx.GetHDC(), + ptPrevViewportOrg.x, + ptPrevViewportOrg.y, + NULL); + + // restore the viewport origin offset + OffsetViewportOrgEx(rGfx.GetHDC(), 0, 0, NULL); + } + } +} + + +//************************************************************************ +// +// CLCDCollection::OnUpdate +// +//************************************************************************ + +void CLCDCollection::OnUpdate(DWORD dwTimestamp) +{ + //iterate through your objects and update them + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it++; + LCDUIASSERT(NULL != pObject); + + pObject->OnUpdate(dwTimestamp); + } + + //and update yourself + CLCDBase::OnUpdate(dwTimestamp); +} + + +//** end of LCDCollection.cpp ******************************************** diff --git a/src/thirdparty/LCDUI/LCDCollection.h b/src/thirdparty/LCDUI/LCDCollection.h index 6c4a2862af4..801a736deba 100644 --- a/src/thirdparty/LCDUI/LCDCollection.h +++ b/src/thirdparty/LCDUI/LCDCollection.h @@ -1,52 +1,52 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDCollection.h -// -// Holds a collection of base items. Its draw will draw everything -// in its list. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDCOLLECTION_H_INCLUDED_ -#define _LCDCOLLECTION_H_INCLUDED_ - -#include "LCDBase.h" -#include - -class CLCDCollection : public CLCDBase -{ -public: - CLCDCollection(); - virtual ~CLCDCollection(); - - bool AddObject(CLCDBase *pObject); - bool RemoveObject(CLCDBase *pObject); - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void OnUpdate(DWORD dwTimestamp); - -protected: - CLCDBase* RetrieveObject(int objpos); - int GetObjectCount(void); - bool RemoveObject(int objnum); - void RemoveAll(void); - -protected: - typedef std::vector LCD_OBJECT_LIST; - - LCD_OBJECT_LIST m_Objects; -}; - +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDCollection.h +// +// Holds a collection of base items. Its draw will draw everything +// in its list. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDCOLLECTION_H_INCLUDED_ +#define _LCDCOLLECTION_H_INCLUDED_ + +#include "LCDBase.h" +#include + +class CLCDCollection : public CLCDBase +{ +public: + CLCDCollection(); + virtual ~CLCDCollection(); + + bool AddObject(CLCDBase *pObject); + bool RemoveObject(CLCDBase *pObject); + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void OnUpdate(DWORD dwTimestamp); + +protected: + CLCDBase* RetrieveObject(int objpos); + int GetObjectCount(void); + bool RemoveObject(int objnum); + void RemoveAll(void); + +protected: + typedef std::vector LCD_OBJECT_LIST; + + LCD_OBJECT_LIST m_Objects; +}; + #endif \ No newline at end of file diff --git a/src/thirdparty/LCDUI/LCDColorProgressBar.cpp b/src/thirdparty/LCDUI/LCDColorProgressBar.cpp index ddf330ff0df..46cdf5809ee 100644 --- a/src/thirdparty/LCDUI/LCDColorProgressBar.cpp +++ b/src/thirdparty/LCDUI/LCDColorProgressBar.cpp @@ -1,203 +1,203 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDColorProgressBar.cpp -// -// The CLCDColorProgressBar class draws a progress bar onto the color LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDColorProgressBar::CLCDColorProgressBar -// -//************************************************************************ - -CLCDColorProgressBar::CLCDColorProgressBar(void) - : CLCDProgressBar() -{ - SetProgressStyle(STYLE_FILLED); - SetCursorWidth(25); - SetBackgroundColor(RGB(0, 255, 100)); - SetBorderThickness(3); - - // Show a border by default - EnableBorder(FALSE); - SetBorderColor(RGB(0, 100, 150)); -} - - -//************************************************************************ -// -// CLCDColorProgressBar::~CLCDColorProgressBar -// -//************************************************************************ - -CLCDColorProgressBar::~CLCDColorProgressBar(void) -{ -} - - -//************************************************************************ -// -// CLCDColorProgressBar::OnDraw -// -//************************************************************************ - -void CLCDColorProgressBar::OnDraw(CLCDGfxBase &rGfx) -{ - HBRUSH hCursorBrush = CreateSolidBrush(m_crForegroundColor); - HBRUSH hBackBrush = CreateSolidBrush(m_crBackgroundColor); - - RECT rBoundary = { 0, 0, GetWidth(), GetHeight() }; - - // Draw the background/border or just background - if (m_bBorderOn && (m_nBorderThickness > 0)) - { - HBRUSH hOldBrush = (HBRUSH)SelectObject(rGfx.GetHDC(), hBackBrush); - HPEN hBorderPen = CreatePen(PS_INSIDEFRAME, m_nBorderThickness, m_crBorderColor); - HPEN hOldPen = (HPEN)SelectObject(rGfx.GetHDC(), hBorderPen); - Rectangle(rGfx.GetHDC(), rBoundary.left, rBoundary.top, rBoundary.right, rBoundary.bottom); - SelectObject(rGfx.GetHDC(), hOldPen); - SelectObject(rGfx.GetHDC(), hOldBrush); - DeleteObject(hBorderPen); - - // adjust the progress boundary by the thickness - rBoundary.top += m_nBorderThickness; - rBoundary.bottom -= m_nBorderThickness; - rBoundary.left += m_nBorderThickness; - rBoundary.right -= m_nBorderThickness; - } - else - { - FillRect(rGfx.GetHDC(), &rBoundary, hBackBrush); - } - - //Drawing the cursor - switch(m_eStyle) - { - case STYLE_CURSOR: - { - RECT r = rBoundary; - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), - m_fPos); - r.left = nCursorPos; - r.right = nCursorPos + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, hCursorBrush); - - break; - } - case STYLE_FILLED: - { - RECT r = rBoundary; - int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right), - m_fPos); - r.right = nBarWidth ? nBarWidth : r.left; - FillRect(rGfx.GetHDC(), &r, hCursorBrush); - - break; - } - case STYLE_DASHED_CURSOR: - { - RECT r = rBoundary; - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), - m_fPos); - r.left = nCursorPos; - r.right = nCursorPos + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, hCursorBrush); - HPEN hCursorPen = ::CreatePen(PS_DOT, 1, m_crForegroundColor); - HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), hCursorPen); - - ::MoveToEx(rGfx.GetHDC(), rBoundary.left, (r.bottom - r.top)/2, NULL); - ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top)/2); - - DeleteObject(hCursorPen); - ::SelectObject(rGfx.GetHDC(), hOldPen); - break; - } - - default: - break; - } - - DeleteObject(hBackBrush); - DeleteObject(hCursorBrush); -} - - -//************************************************************************ -// -// CLCDColorProgressBar::SetCursorColor -// -//************************************************************************ - -void CLCDColorProgressBar::SetCursorColor(COLORREF color) -{ - SetForegroundColor(color); -} - - -//************************************************************************ -// -// CLCDColorProgressBar::EnableBorder -// -//************************************************************************ - -void CLCDColorProgressBar::EnableBorder(BOOL bEnable) -{ - m_bBorderOn = bEnable; -} - - -//************************************************************************ -// -// CLCDColorProgressBar::SetBorderColor -// -//************************************************************************ - -void CLCDColorProgressBar::SetBorderColor(COLORREF color) -{ - m_crBorderColor = color; -} - - -//************************************************************************ -// -// CLCDColorProgressBar::SetBorderThickness -// -//************************************************************************ - -void CLCDColorProgressBar::SetBorderThickness(int thickness) -{ - m_nBorderThickness = thickness; -} - - -//************************************************************************ -// -// CLCDColorProgressBar::SetCursorWidth -// -//************************************************************************ - -void CLCDColorProgressBar::SetCursorWidth(int width) -{ - m_nCursorWidth = width; -} - -//** end of LCDColorProgressBar.cpp ************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDColorProgressBar.cpp +// +// The CLCDColorProgressBar class draws a progress bar onto the color LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDColorProgressBar::CLCDColorProgressBar +// +//************************************************************************ + +CLCDColorProgressBar::CLCDColorProgressBar(void) + : CLCDProgressBar() +{ + SetProgressStyle(STYLE_FILLED); + SetCursorWidth(25); + SetBackgroundColor(RGB(0, 255, 100)); + SetBorderThickness(3); + + // Show a border by default + EnableBorder(FALSE); + SetBorderColor(RGB(0, 100, 150)); +} + + +//************************************************************************ +// +// CLCDColorProgressBar::~CLCDColorProgressBar +// +//************************************************************************ + +CLCDColorProgressBar::~CLCDColorProgressBar(void) +{ +} + + +//************************************************************************ +// +// CLCDColorProgressBar::OnDraw +// +//************************************************************************ + +void CLCDColorProgressBar::OnDraw(CLCDGfxBase &rGfx) +{ + HBRUSH hCursorBrush = CreateSolidBrush(m_crForegroundColor); + HBRUSH hBackBrush = CreateSolidBrush(m_crBackgroundColor); + + RECT rBoundary = { 0, 0, GetWidth(), GetHeight() }; + + // Draw the background/border or just background + if (m_bBorderOn && (m_nBorderThickness > 0)) + { + HBRUSH hOldBrush = (HBRUSH)SelectObject(rGfx.GetHDC(), hBackBrush); + HPEN hBorderPen = CreatePen(PS_INSIDEFRAME, m_nBorderThickness, m_crBorderColor); + HPEN hOldPen = (HPEN)SelectObject(rGfx.GetHDC(), hBorderPen); + Rectangle(rGfx.GetHDC(), rBoundary.left, rBoundary.top, rBoundary.right, rBoundary.bottom); + SelectObject(rGfx.GetHDC(), hOldPen); + SelectObject(rGfx.GetHDC(), hOldBrush); + DeleteObject(hBorderPen); + + // adjust the progress boundary by the thickness + rBoundary.top += m_nBorderThickness; + rBoundary.bottom -= m_nBorderThickness; + rBoundary.left += m_nBorderThickness; + rBoundary.right -= m_nBorderThickness; + } + else + { + FillRect(rGfx.GetHDC(), &rBoundary, hBackBrush); + } + + //Drawing the cursor + switch(m_eStyle) + { + case STYLE_CURSOR: + { + RECT r = rBoundary; + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), + m_fPos); + r.left = nCursorPos; + r.right = nCursorPos + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, hCursorBrush); + + break; + } + case STYLE_FILLED: + { + RECT r = rBoundary; + int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right), + m_fPos); + r.right = nBarWidth ? nBarWidth : r.left; + FillRect(rGfx.GetHDC(), &r, hCursorBrush); + + break; + } + case STYLE_DASHED_CURSOR: + { + RECT r = rBoundary; + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), + m_fPos); + r.left = nCursorPos; + r.right = nCursorPos + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, hCursorBrush); + HPEN hCursorPen = ::CreatePen(PS_DOT, 1, m_crForegroundColor); + HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), hCursorPen); + + ::MoveToEx(rGfx.GetHDC(), rBoundary.left, (r.bottom - r.top)/2, NULL); + ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top)/2); + + DeleteObject(hCursorPen); + ::SelectObject(rGfx.GetHDC(), hOldPen); + break; + } + + default: + break; + } + + DeleteObject(hBackBrush); + DeleteObject(hCursorBrush); +} + + +//************************************************************************ +// +// CLCDColorProgressBar::SetCursorColor +// +//************************************************************************ + +void CLCDColorProgressBar::SetCursorColor(COLORREF color) +{ + SetForegroundColor(color); +} + + +//************************************************************************ +// +// CLCDColorProgressBar::EnableBorder +// +//************************************************************************ + +void CLCDColorProgressBar::EnableBorder(BOOL bEnable) +{ + m_bBorderOn = bEnable; +} + + +//************************************************************************ +// +// CLCDColorProgressBar::SetBorderColor +// +//************************************************************************ + +void CLCDColorProgressBar::SetBorderColor(COLORREF color) +{ + m_crBorderColor = color; +} + + +//************************************************************************ +// +// CLCDColorProgressBar::SetBorderThickness +// +//************************************************************************ + +void CLCDColorProgressBar::SetBorderThickness(int thickness) +{ + m_nBorderThickness = thickness; +} + + +//************************************************************************ +// +// CLCDColorProgressBar::SetCursorWidth +// +//************************************************************************ + +void CLCDColorProgressBar::SetCursorWidth(int width) +{ + m_nCursorWidth = width; +} + +//** end of LCDColorProgressBar.cpp ************************************** diff --git a/src/thirdparty/LCDUI/LCDColorProgressBar.h b/src/thirdparty/LCDUI/LCDColorProgressBar.h index 560bfa7079c..6a620f4e626 100644 --- a/src/thirdparty/LCDUI/LCDColorProgressBar.h +++ b/src/thirdparty/LCDUI/LCDColorProgressBar.h @@ -1,53 +1,53 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDColorProgressBar.h -// -// The CLCDColorProgressBar class draws a progress bar onto the color LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDCOLORPROGRESSBAR_H__ -#define __LCDCOLORPROGRESSBAR_H__ - -#include -#include "LCDProgressBar.h" - - -class CLCDColorProgressBar : public CLCDProgressBar -{ -public: - CLCDColorProgressBar(); - virtual ~CLCDColorProgressBar(); - - //CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - - //Style settings - virtual void SetCursorColor(COLORREF color); - virtual void EnableBorder(BOOL bEnable); - virtual void SetBorderColor(COLORREF color); - virtual void SetBorderThickness(int thickness); - virtual void SetCursorWidth(int width); - -protected: - //Does the actual draw work... - void DoDrawWork(); - - BOOL m_bBorderOn; - int m_nBorderThickness; - - COLORREF m_crBorderColor; -}; - +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDColorProgressBar.h +// +// The CLCDColorProgressBar class draws a progress bar onto the color LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDCOLORPROGRESSBAR_H__ +#define __LCDCOLORPROGRESSBAR_H__ + +#include +#include "LCDProgressBar.h" + + +class CLCDColorProgressBar : public CLCDProgressBar +{ +public: + CLCDColorProgressBar(); + virtual ~CLCDColorProgressBar(); + + //CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + + //Style settings + virtual void SetCursorColor(COLORREF color); + virtual void EnableBorder(BOOL bEnable); + virtual void SetBorderColor(COLORREF color); + virtual void SetBorderThickness(int thickness); + virtual void SetCursorWidth(int width); + +protected: + //Does the actual draw work... + void DoDrawWork(); + + BOOL m_bBorderOn; + int m_nBorderThickness; + + COLORREF m_crBorderColor; +}; + #endif \ No newline at end of file diff --git a/src/thirdparty/LCDUI/LCDColorText.cpp b/src/thirdparty/LCDUI/LCDColorText.cpp index f8e61e14cbf..e9326da2e88 100644 --- a/src/thirdparty/LCDUI/LCDColorText.cpp +++ b/src/thirdparty/LCDUI/LCDColorText.cpp @@ -1,301 +1,301 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// CLCDColorText.cpp -// -// The CLCDColorText class draws scrollable color text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - -//************************************************************************ -// -// CLCDColorText::CLCDColorText -// -//************************************************************************ - -CLCDColorText::CLCDColorText(void) -{ - m_nTextLength = 0; - m_hFont = NULL; - m_sText.erase(m_sText.begin(), m_sText.end()); - SetForegroundColor(RGB(255, 0, 255)); - m_bRecalcExtent = TRUE; - ZeroMemory(&m_dtp, sizeof(DRAWTEXTPARAMS)); - m_dtp.cbSize = sizeof(DRAWTEXTPARAMS); - m_nTextFormat = m_nTextAlignment = (DT_LEFT | DT_NOPREFIX); - m_nTextAlignment = DT_LEFT; - ZeroMemory(&m_sizeVExtent, sizeof(m_sizeVExtent)); - ZeroMemory(&m_sizeHExtent, sizeof(m_sizeHExtent)); - - SetBackgroundMode(TRANSPARENT, RGB(255,255,255)); - - //Default font - LOGFONT lf; - lf.lfCharSet = 0; - lf.lfClipPrecision = 2; - lf.lfEscapement = 0; - lf.lfHeight = -32; - lf.lfItalic = 0; - lf.lfOrientation = 0; - lf.lfOutPrecision = 3; - lf.lfPitchAndFamily = 18; - lf.lfQuality = 1; - lf.lfStrikeOut = 0; - lf.lfUnderline = 0; - lf.lfWeight = 400; - lf.lfWidth = 0; - - wsprintf(lf.lfFaceName, _T("Times New Roman") ); - - m_hFont = CreateFontIndirect(&lf); - - m_StartX = 0; - m_LoopX = 0; - m_ScrollRate = 0; - m_PixelLength = 0; - m_RunningTime = 0; - m_ScrollBuffer = 20; - m_JumpDistance = 0; - - m_bAutoScroll = true; -} - - - -//************************************************************************ -// -// CLCDColorText::~CLCDColorText -// -//************************************************************************ - -CLCDColorText::~CLCDColorText() -{ -} - - -//************************************************************************ -// -// CLCDColorText::SetBackgroundMode -// -//************************************************************************ - -void CLCDColorText::SetBackgroundMode(int nMode, COLORREF color) -{ - m_nBkMode = nMode; - m_backColor = color; -} - - -//************************************************************************ -// -// CLCDColorText::OnDraw -// -//************************************************************************ - -void CLCDColorText::OnDraw(CLCDGfxBase &rGfx) -{ - if(GetBackgroundMode() == OPAQUE) - { - HBRUSH backbrush = CreateSolidBrush(m_backColor); - - // clear the clipped area - RECT rcClp = { 0, 0, m_Size.cx, m_Size.cy }; - FillRect(rGfx.GetHDC(), &rcClp, backbrush); - - // clear the logical area - RECT rcLog = { 0, 0, m_sizeLogical.cx, m_sizeLogical.cy }; - FillRect(rGfx.GetHDC(), &rcLog, backbrush); - - DeleteObject(backbrush); - } - - if(m_nTextLength) - { - - // map mode text, with transparency - int nOldMapMode = SetMapMode(rGfx.GetHDC(), MM_TEXT); - - int nOldBkMode = SetBkMode(rGfx.GetHDC(), TRANSPARENT); - - // select current font - HFONT hOldFont = (HFONT)SelectObject(rGfx.GetHDC(), m_hFont); - - // select color - COLORREF crOldTextColor = SetTextColor(rGfx.GetHDC(), m_crForegroundColor); - - if (m_bRecalcExtent) - { - int nTextFormat; - - RECT rExtent; - // calculate vertical extent with word wrap - nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = GetWidth(); - rExtent.bottom = GetHeight(); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeVExtent.cx = rExtent.right; - m_sizeVExtent.cy = rExtent.bottom; - - // calculate horizontal extent w/o word wrap - nTextFormat = (m_nTextFormat | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = GetWidth(); - rExtent.bottom = GetHeight(); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeHExtent.cx = rExtent.right; - m_sizeHExtent.cy = rExtent.bottom; - - m_bRecalcExtent = FALSE; - - //For scrolling - m_PixelLength = m_sizeHExtent.cx; - m_StartX = 0; - - if( m_bAutoScroll ) - { - if( m_PixelLength > GetWidth() ) - { - m_ScrollRate = -1*GetHeight(); - } - else - { - m_ScrollRate = 0; - } - } - - if( m_ScrollRate > 0 ) - { - if( GetWidth() > m_PixelLength + m_ScrollBuffer ) - { - m_JumpDistance = -1 * GetWidth(); - } - else - { - m_JumpDistance = -1 * (m_PixelLength + m_ScrollBuffer); - } - } - else if( m_ScrollRate < 0 ) - { - if( GetWidth() > m_PixelLength + m_ScrollBuffer ) - { - m_JumpDistance = GetWidth(); - } - else - { - m_JumpDistance = m_PixelLength + m_ScrollBuffer; - } - } - - m_LoopX = m_JumpDistance; - } - - if( IsVisible() ) - { - if( m_ScrollRate == 0 ) - { - RECT rBoundary = { 0, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rBoundary, m_nTextFormat, &m_dtp); - } - else - { - RECT rBoundaryFirst = { m_StartX, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; - RECT rBoundarySecond = { m_LoopX, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; - - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), - &rBoundaryFirst, m_nTextFormat, &m_dtp); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), - &rBoundarySecond, m_nTextFormat, &m_dtp); - } - } - - // restores - SetMapMode(rGfx.GetHDC(), nOldMapMode); - SetTextColor(rGfx.GetHDC(), crOldTextColor); - SetBkMode(rGfx.GetHDC(), nOldBkMode); - SelectObject(rGfx.GetHDC(), hOldFont); - } -} - - -//************************************************************************ -// -// CLCDColorText::OnUpdate -// -//************************************************************************ - -void CLCDColorText::OnUpdate(DWORD timestamp) -{ - if( m_ScrollRate != 0 && m_bRecalcExtent == FALSE ) - { - //How much time has passed? - if( m_RunningTime == 0 ) - m_RunningTime = timestamp; - - //Scrollrate is in pixels per second - DWORD elapsed = timestamp - m_RunningTime; //milliseconds - - //Only update if a full second has passed - if( elapsed < 1000 ) - return; - - float secs = elapsed / 1000.0f; //to seconds - int jump = (int)(secs * m_ScrollRate + 0.5f); //to pixels - - m_StartX += jump; - m_LoopX += jump; - - if( (m_ScrollRate > 0 && m_LoopX >= 0) || - (m_ScrollRate < 0 && m_LoopX <= 0) ) - { - m_StartX = m_LoopX; - m_LoopX += m_JumpDistance; - } - - m_RunningTime = timestamp; - } -} - - -//************************************************************************ -// -// CLCDColorText::SetFontColor -// -//************************************************************************ - -void CLCDColorText::SetFontColor(COLORREF color) -{ - m_crForegroundColor = color; -} - - -//************************************************************************ -// -// CLCDColorText::SetScrollRate -// -//************************************************************************ - -void CLCDColorText::SetScrollRate( int pixelspersec ) -{ - m_ScrollRate = pixelspersec; - - m_StartX = 0; - m_bRecalcExtent = TRUE; -} - -//** end of LCDColorText.cpp ********************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// CLCDColorText.cpp +// +// The CLCDColorText class draws scrollable color text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + +//************************************************************************ +// +// CLCDColorText::CLCDColorText +// +//************************************************************************ + +CLCDColorText::CLCDColorText(void) +{ + m_nTextLength = 0; + m_hFont = NULL; + m_sText.erase(m_sText.begin(), m_sText.end()); + SetForegroundColor(RGB(255, 0, 255)); + m_bRecalcExtent = TRUE; + ZeroMemory(&m_dtp, sizeof(DRAWTEXTPARAMS)); + m_dtp.cbSize = sizeof(DRAWTEXTPARAMS); + m_nTextFormat = m_nTextAlignment = (DT_LEFT | DT_NOPREFIX); + m_nTextAlignment = DT_LEFT; + ZeroMemory(&m_sizeVExtent, sizeof(m_sizeVExtent)); + ZeroMemory(&m_sizeHExtent, sizeof(m_sizeHExtent)); + + SetBackgroundMode(TRANSPARENT, RGB(255,255,255)); + + //Default font + LOGFONT lf; + lf.lfCharSet = 0; + lf.lfClipPrecision = 2; + lf.lfEscapement = 0; + lf.lfHeight = -32; + lf.lfItalic = 0; + lf.lfOrientation = 0; + lf.lfOutPrecision = 3; + lf.lfPitchAndFamily = 18; + lf.lfQuality = 1; + lf.lfStrikeOut = 0; + lf.lfUnderline = 0; + lf.lfWeight = 400; + lf.lfWidth = 0; + + wsprintf(lf.lfFaceName, _T("Times New Roman") ); + + m_hFont = CreateFontIndirect(&lf); + + m_StartX = 0; + m_LoopX = 0; + m_ScrollRate = 0; + m_PixelLength = 0; + m_RunningTime = 0; + m_ScrollBuffer = 20; + m_JumpDistance = 0; + + m_bAutoScroll = true; +} + + + +//************************************************************************ +// +// CLCDColorText::~CLCDColorText +// +//************************************************************************ + +CLCDColorText::~CLCDColorText() +{ +} + + +//************************************************************************ +// +// CLCDColorText::SetBackgroundMode +// +//************************************************************************ + +void CLCDColorText::SetBackgroundMode(int nMode, COLORREF color) +{ + m_nBkMode = nMode; + m_backColor = color; +} + + +//************************************************************************ +// +// CLCDColorText::OnDraw +// +//************************************************************************ + +void CLCDColorText::OnDraw(CLCDGfxBase &rGfx) +{ + if(GetBackgroundMode() == OPAQUE) + { + HBRUSH backbrush = CreateSolidBrush(m_backColor); + + // clear the clipped area + RECT rcClp = { 0, 0, m_Size.cx, m_Size.cy }; + FillRect(rGfx.GetHDC(), &rcClp, backbrush); + + // clear the logical area + RECT rcLog = { 0, 0, m_sizeLogical.cx, m_sizeLogical.cy }; + FillRect(rGfx.GetHDC(), &rcLog, backbrush); + + DeleteObject(backbrush); + } + + if(m_nTextLength) + { + + // map mode text, with transparency + int nOldMapMode = SetMapMode(rGfx.GetHDC(), MM_TEXT); + + int nOldBkMode = SetBkMode(rGfx.GetHDC(), TRANSPARENT); + + // select current font + HFONT hOldFont = (HFONT)SelectObject(rGfx.GetHDC(), m_hFont); + + // select color + COLORREF crOldTextColor = SetTextColor(rGfx.GetHDC(), m_crForegroundColor); + + if (m_bRecalcExtent) + { + int nTextFormat; + + RECT rExtent; + // calculate vertical extent with word wrap + nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = GetWidth(); + rExtent.bottom = GetHeight(); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeVExtent.cx = rExtent.right; + m_sizeVExtent.cy = rExtent.bottom; + + // calculate horizontal extent w/o word wrap + nTextFormat = (m_nTextFormat | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = GetWidth(); + rExtent.bottom = GetHeight(); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeHExtent.cx = rExtent.right; + m_sizeHExtent.cy = rExtent.bottom; + + m_bRecalcExtent = FALSE; + + //For scrolling + m_PixelLength = m_sizeHExtent.cx; + m_StartX = 0; + + if( m_bAutoScroll ) + { + if( m_PixelLength > GetWidth() ) + { + m_ScrollRate = -1*GetHeight(); + } + else + { + m_ScrollRate = 0; + } + } + + if( m_ScrollRate > 0 ) + { + if( GetWidth() > m_PixelLength + m_ScrollBuffer ) + { + m_JumpDistance = -1 * GetWidth(); + } + else + { + m_JumpDistance = -1 * (m_PixelLength + m_ScrollBuffer); + } + } + else if( m_ScrollRate < 0 ) + { + if( GetWidth() > m_PixelLength + m_ScrollBuffer ) + { + m_JumpDistance = GetWidth(); + } + else + { + m_JumpDistance = m_PixelLength + m_ScrollBuffer; + } + } + + m_LoopX = m_JumpDistance; + } + + if( IsVisible() ) + { + if( m_ScrollRate == 0 ) + { + RECT rBoundary = { 0, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rBoundary, m_nTextFormat, &m_dtp); + } + else + { + RECT rBoundaryFirst = { m_StartX, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; + RECT rBoundarySecond = { m_LoopX, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; + + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), + &rBoundaryFirst, m_nTextFormat, &m_dtp); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), + &rBoundarySecond, m_nTextFormat, &m_dtp); + } + } + + // restores + SetMapMode(rGfx.GetHDC(), nOldMapMode); + SetTextColor(rGfx.GetHDC(), crOldTextColor); + SetBkMode(rGfx.GetHDC(), nOldBkMode); + SelectObject(rGfx.GetHDC(), hOldFont); + } +} + + +//************************************************************************ +// +// CLCDColorText::OnUpdate +// +//************************************************************************ + +void CLCDColorText::OnUpdate(DWORD timestamp) +{ + if( m_ScrollRate != 0 && m_bRecalcExtent == FALSE ) + { + //How much time has passed? + if( m_RunningTime == 0 ) + m_RunningTime = timestamp; + + //Scrollrate is in pixels per second + DWORD elapsed = timestamp - m_RunningTime; //milliseconds + + //Only update if a full second has passed + if( elapsed < 1000 ) + return; + + float secs = elapsed / 1000.0f; //to seconds + int jump = (int)(secs * m_ScrollRate + 0.5f); //to pixels + + m_StartX += jump; + m_LoopX += jump; + + if( (m_ScrollRate > 0 && m_LoopX >= 0) || + (m_ScrollRate < 0 && m_LoopX <= 0) ) + { + m_StartX = m_LoopX; + m_LoopX += m_JumpDistance; + } + + m_RunningTime = timestamp; + } +} + + +//************************************************************************ +// +// CLCDColorText::SetFontColor +// +//************************************************************************ + +void CLCDColorText::SetFontColor(COLORREF color) +{ + m_crForegroundColor = color; +} + + +//************************************************************************ +// +// CLCDColorText::SetScrollRate +// +//************************************************************************ + +void CLCDColorText::SetScrollRate( int pixelspersec ) +{ + m_ScrollRate = pixelspersec; + + m_StartX = 0; + m_bRecalcExtent = TRUE; +} + +//** end of LCDColorText.cpp ********************************************* diff --git a/src/thirdparty/LCDUI/LCDColorText.h b/src/thirdparty/LCDUI/LCDColorText.h index 0f88b4d8fa0..30bfeecd160 100644 --- a/src/thirdparty/LCDUI/LCDColorText.h +++ b/src/thirdparty/LCDUI/LCDColorText.h @@ -1,63 +1,63 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDColorText.h -// -// The CLCDText class draws simple text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDCOLORTEXT_H_INCLUDED_ -#define _LCDCOLORTEXT_H_INCLUDED_ - -#include "LCDText.h" - -class CLCDColorText : public CLCDText -{ -public: - CLCDColorText(); - virtual ~CLCDColorText(); - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void OnUpdate(DWORD timestamp); - - virtual void SetFontColor(COLORREF color); - virtual void SetBackgroundMode(int nMode, COLORREF color=RGB(255,255,255)); - void SetScrollRate( int pixelspersec ); - void SetAutoScroll(bool b) - { m_bAutoScroll = b; } - - enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 12 }; - -private: - COLORREF m_backColor; - - //For scrolling - DWORD m_RunningTime; - int m_StartX; - int m_LoopX; - int m_ScrollRate; //pixels per second - int m_PixelLength; - int m_ScrollBuffer; //how many pixels between scrolls - int m_JumpDistance; - - bool m_bAutoScroll; //automatically scroll if text length > draw area -}; - -#endif // !_LCDCOLORTEXT_H_INCLUDED_ - -//** end of LCDColorText.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDColorText.h +// +// The CLCDText class draws simple text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDCOLORTEXT_H_INCLUDED_ +#define _LCDCOLORTEXT_H_INCLUDED_ + +#include "LCDText.h" + +class CLCDColorText : public CLCDText +{ +public: + CLCDColorText(); + virtual ~CLCDColorText(); + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void OnUpdate(DWORD timestamp); + + virtual void SetFontColor(COLORREF color); + virtual void SetBackgroundMode(int nMode, COLORREF color=RGB(255,255,255)); + void SetScrollRate( int pixelspersec ); + void SetAutoScroll(bool b) + { m_bAutoScroll = b; } + + enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 12 }; + +private: + COLORREF m_backColor; + + //For scrolling + DWORD m_RunningTime; + int m_StartX; + int m_LoopX; + int m_ScrollRate; //pixels per second + int m_PixelLength; + int m_ScrollBuffer; //how many pixels between scrolls + int m_JumpDistance; + + bool m_bAutoScroll; //automatically scroll if text length > draw area +}; + +#endif // !_LCDCOLORTEXT_H_INCLUDED_ + +//** end of LCDColorText.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDConnection.cpp b/src/thirdparty/LCDUI/LCDConnection.cpp index b6821b859e1..c33f844abff 100644 --- a/src/thirdparty/LCDUI/LCDConnection.cpp +++ b/src/thirdparty/LCDUI/LCDConnection.cpp @@ -1,723 +1,723 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDConnection.cpp -// -// The CLCDConnection class manages connections to all LCD devices -// including color and monochrome -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - -// Add the lgLcd.lib to the linker - -// #pragma comment(lib, "lgLcd.lib") - -// to keep track of clients that use multiple CLCDOutput instances -// within the same app -LONG CLCDConnection::g_lInitCount = 0; - -//************************************************************************ -// -// CLCDConnection::CLCDConnection -// -//************************************************************************ - -CLCDConnection::CLCDConnection(void) -{ - m_hConnection = LGLCD_INVALID_CONNECTION; - - ZeroMemory(&m_AppletState, sizeof(m_AppletState)); - - m_plcdSoftButtonsChangedCtx = NULL; - - InitializeCriticalSection(&m_csCallback); -} - - -//************************************************************************ -// -// CLCDConnection::~CLCDConnection -// -//************************************************************************ - -CLCDConnection::~CLCDConnection(void) -{ - Disconnect(); - - FreeMonoOutput(); - FreeColorOutput(); - - if (m_AppletState.Mono.pGfx) - { - delete m_AppletState.Mono.pGfx; - m_AppletState.Mono.pGfx = NULL; - } - if (m_AppletState.Color.pGfx) - { - delete m_AppletState.Color.pGfx; - m_AppletState.Color.pGfx = NULL; - } - DeleteCriticalSection(&m_csCallback); -} - - -//************************************************************************ -// -// CLCDConnection::Initialize -// -//************************************************************************ - -BOOL CLCDConnection::Initialize(lgLcdConnectContext & ConnectContext, - lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext) -{ - // Assume only BW is supported - m_AppletState.Mono.pOutput = new CLCDOutput(); - m_AppletState.Mono.pGfx = new CLCDGfxMono(); - m_AppletState.Mono.pGfx->Initialize(); - m_AppletState.Mono.pOutput->SetGfx(m_AppletState.Mono.pGfx); - - lgLcdConnectContextEx ConnectContextEx; - memset(&ConnectContextEx, 0, sizeof(ConnectContextEx)); - ConnectContextEx.appFriendlyName = ConnectContext.appFriendlyName; - ConnectContextEx.isPersistent = ConnectContext.isPersistent; - ConnectContextEx.isAutostartable = ConnectContext.isAutostartable; - ConnectContextEx.connection = LGLCD_INVALID_CONNECTION; - ConnectContextEx.onConfigure = ConnectContext.onConfigure; - ConnectContextEx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BW; - - return Initialize(ConnectContextEx, pSoftButtonChangedContext); -} - - -//************************************************************************ -// -// CLCDConnection::Initialize -// -//************************************************************************ - -BOOL CLCDConnection::Initialize(lgLcdConnectContextEx & ConnectContext, - lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext) -{ - DWORD res = ERROR_SUCCESS; - - if ((LGLCD_APPLET_CAP_BASIC == ConnectContext.dwAppletCapabilitiesSupported) || - ConnectContext.dwAppletCapabilitiesSupported & LGLCD_APPLET_CAP_BW) - { - m_AppletState.Mono.pOutput = AllocMonoOutput(); - m_AppletState.Mono.pGfx = new CLCDGfxMono(); - m_AppletState.Mono.pGfx->Initialize(); - m_AppletState.Mono.pOutput->SetGfx(m_AppletState.Mono.pGfx); - } - - if (ConnectContext.dwAppletCapabilitiesSupported & LGLCD_APPLET_CAP_QVGA) - { - m_AppletState.Color.pOutput = AllocColorOutput(); - m_AppletState.Color.pGfx = new CLCDGfxColor(); - m_AppletState.Color.pGfx->Initialize(); - m_AppletState.Color.pOutput->SetGfx(m_AppletState.Color.pGfx); - } - - //Assure we only call the lib's init once - LCDUIASSERT(g_lInitCount >= 0); - if(1 == InterlockedIncrement(&g_lInitCount)) - { - // need to call lgLcdInit once - res = lgLcdInit(); - if (ERROR_SUCCESS != res) - { - InterlockedDecrement(&g_lInitCount); - LCDUITRACE(_T("WARNING: lgLcdInit failed\n")); - return FALSE; - } - } - - memset(&m_lcdConnectCtxEx, 0, sizeof(m_lcdConnectCtxEx)); - m_lcdConnectCtxEx.appFriendlyName = NULL; - m_lcdConnectCtxEx.isPersistent = FALSE; - m_lcdConnectCtxEx.isAutostartable = FALSE; - m_lcdConnectCtxEx.connection = LGLCD_INVALID_CONNECTION; - - // Initialize the added version 3.0 API fields - m_lcdConnectCtxEx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BASIC; - m_lcdConnectCtxEx.dwReserved1 = 0; - m_lcdConnectCtxEx.onNotify.notificationCallback = NULL; - m_lcdConnectCtxEx.onNotify.notifyContext = NULL; - - memcpy(&m_lcdConnectCtxEx, &ConnectContext, sizeof(lgLcdConnectContextEx)); - - m_plcdSoftButtonsChangedCtx = pSoftButtonChangedContext; - - // Add internal callback handlers if not specified - if (NULL == m_lcdConnectCtxEx.onNotify.notificationCallback) - { - m_lcdConnectCtxEx.onNotify.notificationCallback = _OnNotificationCallback; - m_lcdConnectCtxEx.onNotify.notifyContext = this; - } - - Connect(); - - if (LGLCD_INVALID_CONNECTION != m_hConnection) - { - // At this point, the asynchronous events have already been sent. - // Let's allow a small amount of time for the callback thread to insert the events - // into the shared queue. - // If you don't care about knowing about devices after Initialize - // completes, you can remove these 2 lines - Sleep(50); - Update(); - } - - return TRUE; -} - - -//************************************************************************ -// -// CLCDConnection::Shutdown -// -//************************************************************************ - -void CLCDConnection::Shutdown(void) -{ - Disconnect(); - - if(0 == InterlockedDecrement(&g_lInitCount)) - { - lgLcdDeInit(); - } - - m_plcdSoftButtonsChangedCtx = NULL; -} - - -//************************************************************************ -// -// CLCDConnection::Connect -// -// This will attempt a connection to LCDMon -//************************************************************************ - -void CLCDConnection::Connect(void) -{ - //Close previous connections - Disconnect(); - - if (LGLCD_INVALID_CONNECTION == m_hConnection) - { - DWORD retval = lgLcdConnectEx(&m_lcdConnectCtxEx); - if (ERROR_SUCCESS == retval) - { - m_hConnection = m_lcdConnectCtxEx.connection; - } - else - { - if( ERROR_SERVICE_NOT_ACTIVE == retval ) - { - LCDUITRACE( _T("lgLcdConnectEx ---> ERROR_INVALID_PARAMETER\n") ); - m_hConnection = LGLCD_INVALID_CONNECTION; - } - - m_hConnection = LGLCD_INVALID_CONNECTION; - } - } -} - - -//************************************************************************ -// -// CLCDConnection::Disconnect -// -//************************************************************************ - -void CLCDConnection::Disconnect(void) -{ - //Close your devices, too - if (m_AppletState.Color.pOutput) - { - m_AppletState.Color.pOutput->Close(); - } - if (m_AppletState.Mono.pOutput) - { - m_AppletState.Mono.pOutput->Close(); - } - - if( LGLCD_INVALID_CONNECTION != m_hConnection ) - { - lgLcdDisconnect(m_hConnection); - m_hConnection = LGLCD_INVALID_CONNECTION; - } -} - - -//************************************************************************ -// -// CLCDConnection::IsConnected -// -//************************************************************************ - -BOOL CLCDConnection::IsConnected(void) -{ - return LGLCD_INVALID_CONNECTION != m_hConnection; -} - - -//************************************************************************ -// -// CLCDConnection::GetConnectionId -// -//************************************************************************ - -int CLCDConnection::GetConnectionId(void) -{ - return m_hConnection; -} - - -//************************************************************************ -// -// CLCDConnection::ColorOutput -// -//************************************************************************ - -CLCDOutput *CLCDConnection::ColorOutput(void) -{ - return m_AppletState.Color.pOutput; -} - - -//************************************************************************ -// -// CLCDConnection::MonoOutput -// -//************************************************************************ - -CLCDOutput *CLCDConnection::MonoOutput(void) -{ - return m_AppletState.Mono.pOutput; -} - - -//************************************************************************ -// -// CLCDConnection::_OnNotificationCallback -// -//************************************************************************ - -DWORD CALLBACK CLCDConnection::_OnNotificationCallback( - IN int connection, - IN const PVOID pContext, - IN DWORD notificationCode, - IN DWORD notifyParm1, - IN DWORD notifyParm2, - IN DWORD notifyParm3, - IN DWORD notifyParm4) -{ - - UNREFERENCED_PARAMETER(connection); - UNREFERENCED_PARAMETER(notifyParm3); - UNREFERENCED_PARAMETER(notifyParm4); - - CLCDConnection* pThis = (CLCDConnection*)pContext; - - CB_EVENT Event; - memset(&Event, 0, sizeof(Event)); - EnterCriticalSection(&pThis->m_csCallback); - Event.Type = CBT_NOTIFICATION; - Event.CallbackCode = notificationCode; - Event.CallbackParam1 = notifyParm1; - Event.CallbackParam2 = notifyParm2; - pThis->m_CallbackEventQueue.push(Event); - LeaveCriticalSection(&pThis->m_csCallback); - - pThis->OnCallbackEvent(); - - return 0; -} - - -//************************************************************************ -// -// CLCDConnection::_OnSoftButtonsCallback -// -//************************************************************************ - -DWORD CALLBACK CLCDConnection::_OnSoftButtonsCallback( - IN int device, - IN DWORD dwButtons, - IN const PVOID pContext) -{ - CLCDConnection* pThis = (CLCDConnection*)pContext; - - CB_EVENT Event; - memset(&Event, 0, sizeof(Event)); - EnterCriticalSection(&pThis->m_csCallback); - Event.Type = CBT_BUTTON; - Event.CallbackCode = device; - Event.CallbackParam1 = dwButtons; - pThis->m_CallbackEventQueue.push(Event); - LeaveCriticalSection(&pThis->m_csCallback); - - pThis->OnCallbackEvent(); - - return 0; -} - - -//************************************************************************ -// -// CLCDConnection::_OnConfigureCallback -// -//************************************************************************ - -DWORD CALLBACK CLCDConnection::_OnConfigureCallback( - IN int connection, - IN const PVOID pContext) -{ - UNREFERENCED_PARAMETER(connection); - - CLCDConnection* pThis = (CLCDConnection*)pContext; - - CB_EVENT Event; - memset(&Event, 0, sizeof(Event)); - EnterCriticalSection(&pThis->m_csCallback); - Event.Type = CBT_CONFIG; - pThis->m_CallbackEventQueue.push(Event); - LeaveCriticalSection(&pThis->m_csCallback); - - return 0; -} - - -//************************************************************************ -// -// CLCDConnection::GetNextCallbackEvent -// -//************************************************************************ - -BOOL CLCDConnection::GetNextCallbackEvent(CB_EVENT& rEvent) -{ - memset(&rEvent, 0, sizeof(rEvent)); - EnterCriticalSection(&m_csCallback); - if(0 < m_CallbackEventQueue.size()) - { - std::swap(rEvent, m_CallbackEventQueue.front()); - m_CallbackEventQueue.pop(); - LeaveCriticalSection(&m_csCallback); - return TRUE; - } - LeaveCriticalSection(&m_csCallback); - return FALSE; -} - - -//************************************************************************ -// -// CLCDConnection::Update -// -//************************************************************************ - -void CLCDConnection::Update(void) -{ - // If we're not connected, connect - if (LGLCD_INVALID_CONNECTION == m_hConnection) - { - Connect(); - } - - // Get events - CB_EVENT Event; - while(GetNextCallbackEvent(Event)) - { - switch(Event.Type) - { - case CBT_NOTIFICATION: - OnNotification(Event.CallbackCode, Event.CallbackParam1); - break; - - case CBT_CONFIG: - OnConfigure(); - break; - - case CBT_BUTTON: - OnSoftButtonEvent(Event.CallbackCode, Event.CallbackParam1); - break; - - default: - break; - } - } - - // For each display type - for (int i = 0; i < 2; i++) - { - LCD_DEVICE_STATE* pDevice = (i == 0) ? &m_AppletState.Mono : &m_AppletState.Color; - - if (NULL == pDevice->pOutput) - { - // Output not supported - continue; - } - - if (pDevice->pOutput->IsOpened()) - { - pDevice->pOutput->OnUpdate(GetTickCount()); - pDevice->pOutput->OnDraw(); - } - - // If the device is closed, but it was opened by OpenByType(), - // we can try to open it again... - if (!pDevice->pOutput->IsOpened() && pDevice->pOutput->HasBeenOpenedByDeviceType()) - { - pDevice->pOutput->ReOpenDeviceType(); - } - } -} - - -//************************************************************************ -// -// CLCDConnection::OnConfigure -// -//************************************************************************ - -void CLCDConnection::OnConfigure(void) -{ - LCDUITRACE(_T("OnConfigure\n")); -} - - -//************************************************************************ -// -// CLCDConnection::OnDeviceArrival -// -//************************************************************************ - -void CLCDConnection::OnDeviceArrival(DWORD dwDisplayType) -{ - LCD_DEVICE_STATE* pDevice = NULL; - - switch(dwDisplayType) - { - case LGLCD_DEVICE_BW: - pDevice = &m_AppletState.Mono; - break; - - case LGLCD_DEVICE_QVGA: - pDevice = &m_AppletState.Color; - break; - - default: - LCDUITRACE(_T("Unhandled DisplayType in OnDeviceArrival()!\n")); - return; - } - - // Ensure that we have a valid output - if (NULL == pDevice->pOutput) - { - LCDUITRACE(_T("Device arrival on unsupported device\n")); - return; - } - - lgLcdOpenByTypeContext OpenCtx; - memset(&OpenCtx, 0, sizeof(OpenCtx)); - - OpenCtx.connection = m_hConnection; - OpenCtx.deviceType = dwDisplayType; - OpenCtx.onSoftbuttonsChanged.softbuttonsChangedCallback = _OnSoftButtonsCallback; - OpenCtx.onSoftbuttonsChanged.softbuttonsChangedContext = this; - OpenCtx.device = LGLCD_INVALID_DEVICE; - - // If user has specified the soft button context, allow user to override - if (NULL != m_plcdSoftButtonsChangedCtx) - { - OpenCtx.onSoftbuttonsChanged = *m_plcdSoftButtonsChangedCtx; - } - - pDevice->pOutput->OpenByType(OpenCtx); -} - - -//************************************************************************ -// -// CLCDConnection::OnDeviceRemoval -// -//************************************************************************ - -void CLCDConnection::OnDeviceRemoval(DWORD dwDisplayType) -{ - LCD_DEVICE_STATE* pDevice = NULL; - - switch(dwDisplayType) - { - case LGLCD_DEVICE_BW: - pDevice = &m_AppletState.Mono; - break; - - case LGLCD_DEVICE_QVGA: - pDevice = &m_AppletState.Color; - break; - - default: - LCDUITRACE(_T("Unhandled DisplayType in OnDeviceArrival()!\n")); - return; - } - - if (pDevice->pOutput) - { - pDevice->pOutput->StopOpeningByDeviceType(); - pDevice->pOutput->Close(); - } -} - - -//************************************************************************ -// -// CLCDConnection::OnAppletEnabled -// -//************************************************************************ - -void CLCDConnection::OnAppletEnabled(void) -{ -} - - -//************************************************************************ -// -// CLCDConnection::OnAppletDisabled -// -//************************************************************************ - -void CLCDConnection::OnAppletDisabled(void) -{ -} - - -//************************************************************************ -// -// CLCDConnection::OnNotification -// -//************************************************************************ - -void CLCDConnection::OnNotification(DWORD dwNotification, DWORD dwParam1) -{ - switch(dwNotification) - { - case LGLCD_NOTIFICATION_DEVICE_ARRIVAL: - LCDUITRACE(_T("LGLCD_NOTIFICATION_DEVICE_ARRIVAL\n")); - OnDeviceArrival(dwParam1); - break; - - case LGLCD_NOTIFICATION_DEVICE_REMOVAL: - LCDUITRACE(_T("LGLCD_NOTIFICATION_DEVICE_REMOVAL\n")); - OnDeviceRemoval(dwParam1); - break; - - case LGLCD_NOTIFICATION_CLOSE_CONNECTION: - LCDUITRACE(_T("LGLCD_NOTIFICATION_CLOSE_CONNECTION\n")); - Disconnect(); - break; - - case LGLCD_NOTIFICATION_APPLET_DISABLED: - LCDUITRACE(_T("LGLCD_NOTIFICATION_APPLET_DISABLED\n")); - OnAppletDisabled(); - break; - - case LGLCD_NOTIFICATION_APPLET_ENABLED: - LCDUITRACE(_T("LGLCD_NOTIFICATION_APPLET_ENABLED\n")); - OnAppletEnabled(); - break; - - case LGLCD_NOTIFICATION_TERMINATE_APPLET: - break; - } -} - - -//************************************************************************ -// -// CLCDConnection::OnSoftButtonEvent -// -//************************************************************************ - -void CLCDConnection::OnSoftButtonEvent(int nDeviceId, DWORD dwButtonState) -{ - // Forward this to the appropriate display - if (m_AppletState.Mono.pOutput && (nDeviceId == m_AppletState.Mono.pOutput->GetDeviceId())) - { - m_AppletState.Mono.pOutput->OnSoftButtonEvent(dwButtonState); - } - else if (m_AppletState.Color.pOutput && (nDeviceId == m_AppletState.Color.pOutput->GetDeviceId())) - { - m_AppletState.Color.pOutput->OnSoftButtonEvent(dwButtonState); - } -} - - -//************************************************************************ -// -// CLCDConnection::AllocMonoOutput -// -//************************************************************************ - -CLCDOutput* CLCDConnection::AllocMonoOutput(void) -{ - return new CLCDOutput(); -} - - -//************************************************************************ -// -// CLCDConnection::AllocColorOutput -// -//************************************************************************ - -CLCDOutput* CLCDConnection::AllocColorOutput(void) -{ - return new CLCDOutput(); -} - - -//************************************************************************ -// -// CLCDConnection::FreeMonoOutput -// -//************************************************************************ - -void CLCDConnection::FreeMonoOutput(void) -{ - if (NULL != m_AppletState.Mono.pOutput) - { - delete m_AppletState.Mono.pOutput; - m_AppletState.Mono.pOutput = NULL; - } -} - - -//************************************************************************ -// -// CLCDConnection::FreeColorOutput -// -//************************************************************************ - -void CLCDConnection::FreeColorOutput(void) -{ - if (NULL != m_AppletState.Color.pOutput) - { - delete m_AppletState.Color.pOutput; - m_AppletState.Color.pOutput = NULL; - } -} - -//** end of LCDConnection.cpp ******************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDConnection.cpp +// +// The CLCDConnection class manages connections to all LCD devices +// including color and monochrome +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + +// Add the lgLcd.lib to the linker + +// #pragma comment(lib, "lgLcd.lib") + +// to keep track of clients that use multiple CLCDOutput instances +// within the same app +LONG CLCDConnection::g_lInitCount = 0; + +//************************************************************************ +// +// CLCDConnection::CLCDConnection +// +//************************************************************************ + +CLCDConnection::CLCDConnection(void) +{ + m_hConnection = LGLCD_INVALID_CONNECTION; + + ZeroMemory(&m_AppletState, sizeof(m_AppletState)); + + m_plcdSoftButtonsChangedCtx = NULL; + + InitializeCriticalSection(&m_csCallback); +} + + +//************************************************************************ +// +// CLCDConnection::~CLCDConnection +// +//************************************************************************ + +CLCDConnection::~CLCDConnection(void) +{ + Disconnect(); + + FreeMonoOutput(); + FreeColorOutput(); + + if (m_AppletState.Mono.pGfx) + { + delete m_AppletState.Mono.pGfx; + m_AppletState.Mono.pGfx = NULL; + } + if (m_AppletState.Color.pGfx) + { + delete m_AppletState.Color.pGfx; + m_AppletState.Color.pGfx = NULL; + } + DeleteCriticalSection(&m_csCallback); +} + + +//************************************************************************ +// +// CLCDConnection::Initialize +// +//************************************************************************ + +BOOL CLCDConnection::Initialize(lgLcdConnectContext & ConnectContext, + lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext) +{ + // Assume only BW is supported + m_AppletState.Mono.pOutput = new CLCDOutput(); + m_AppletState.Mono.pGfx = new CLCDGfxMono(); + m_AppletState.Mono.pGfx->Initialize(); + m_AppletState.Mono.pOutput->SetGfx(m_AppletState.Mono.pGfx); + + lgLcdConnectContextEx ConnectContextEx; + memset(&ConnectContextEx, 0, sizeof(ConnectContextEx)); + ConnectContextEx.appFriendlyName = ConnectContext.appFriendlyName; + ConnectContextEx.isPersistent = ConnectContext.isPersistent; + ConnectContextEx.isAutostartable = ConnectContext.isAutostartable; + ConnectContextEx.connection = LGLCD_INVALID_CONNECTION; + ConnectContextEx.onConfigure = ConnectContext.onConfigure; + ConnectContextEx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BW; + + return Initialize(ConnectContextEx, pSoftButtonChangedContext); +} + + +//************************************************************************ +// +// CLCDConnection::Initialize +// +//************************************************************************ + +BOOL CLCDConnection::Initialize(lgLcdConnectContextEx & ConnectContext, + lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext) +{ + DWORD res = ERROR_SUCCESS; + + if ((LGLCD_APPLET_CAP_BASIC == ConnectContext.dwAppletCapabilitiesSupported) || + ConnectContext.dwAppletCapabilitiesSupported & LGLCD_APPLET_CAP_BW) + { + m_AppletState.Mono.pOutput = AllocMonoOutput(); + m_AppletState.Mono.pGfx = new CLCDGfxMono(); + m_AppletState.Mono.pGfx->Initialize(); + m_AppletState.Mono.pOutput->SetGfx(m_AppletState.Mono.pGfx); + } + + if (ConnectContext.dwAppletCapabilitiesSupported & LGLCD_APPLET_CAP_QVGA) + { + m_AppletState.Color.pOutput = AllocColorOutput(); + m_AppletState.Color.pGfx = new CLCDGfxColor(); + m_AppletState.Color.pGfx->Initialize(); + m_AppletState.Color.pOutput->SetGfx(m_AppletState.Color.pGfx); + } + + //Assure we only call the lib's init once + LCDUIASSERT(g_lInitCount >= 0); + if(1 == InterlockedIncrement(&g_lInitCount)) + { + // need to call lgLcdInit once + res = lgLcdInit(); + if (ERROR_SUCCESS != res) + { + InterlockedDecrement(&g_lInitCount); + LCDUITRACE(_T("WARNING: lgLcdInit failed\n")); + return FALSE; + } + } + + memset(&m_lcdConnectCtxEx, 0, sizeof(m_lcdConnectCtxEx)); + m_lcdConnectCtxEx.appFriendlyName = NULL; + m_lcdConnectCtxEx.isPersistent = FALSE; + m_lcdConnectCtxEx.isAutostartable = FALSE; + m_lcdConnectCtxEx.connection = LGLCD_INVALID_CONNECTION; + + // Initialize the added version 3.0 API fields + m_lcdConnectCtxEx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BASIC; + m_lcdConnectCtxEx.dwReserved1 = 0; + m_lcdConnectCtxEx.onNotify.notificationCallback = NULL; + m_lcdConnectCtxEx.onNotify.notifyContext = NULL; + + memcpy(&m_lcdConnectCtxEx, &ConnectContext, sizeof(lgLcdConnectContextEx)); + + m_plcdSoftButtonsChangedCtx = pSoftButtonChangedContext; + + // Add internal callback handlers if not specified + if (NULL == m_lcdConnectCtxEx.onNotify.notificationCallback) + { + m_lcdConnectCtxEx.onNotify.notificationCallback = _OnNotificationCallback; + m_lcdConnectCtxEx.onNotify.notifyContext = this; + } + + Connect(); + + if (LGLCD_INVALID_CONNECTION != m_hConnection) + { + // At this point, the asynchronous events have already been sent. + // Let's allow a small amount of time for the callback thread to insert the events + // into the shared queue. + // If you don't care about knowing about devices after Initialize + // completes, you can remove these 2 lines + Sleep(50); + Update(); + } + + return TRUE; +} + + +//************************************************************************ +// +// CLCDConnection::Shutdown +// +//************************************************************************ + +void CLCDConnection::Shutdown(void) +{ + Disconnect(); + + if(0 == InterlockedDecrement(&g_lInitCount)) + { + lgLcdDeInit(); + } + + m_plcdSoftButtonsChangedCtx = NULL; +} + + +//************************************************************************ +// +// CLCDConnection::Connect +// +// This will attempt a connection to LCDMon +//************************************************************************ + +void CLCDConnection::Connect(void) +{ + //Close previous connections + Disconnect(); + + if (LGLCD_INVALID_CONNECTION == m_hConnection) + { + DWORD retval = lgLcdConnectEx(&m_lcdConnectCtxEx); + if (ERROR_SUCCESS == retval) + { + m_hConnection = m_lcdConnectCtxEx.connection; + } + else + { + if( ERROR_SERVICE_NOT_ACTIVE == retval ) + { + LCDUITRACE( _T("lgLcdConnectEx ---> ERROR_INVALID_PARAMETER\n") ); + m_hConnection = LGLCD_INVALID_CONNECTION; + } + + m_hConnection = LGLCD_INVALID_CONNECTION; + } + } +} + + +//************************************************************************ +// +// CLCDConnection::Disconnect +// +//************************************************************************ + +void CLCDConnection::Disconnect(void) +{ + //Close your devices, too + if (m_AppletState.Color.pOutput) + { + m_AppletState.Color.pOutput->Close(); + } + if (m_AppletState.Mono.pOutput) + { + m_AppletState.Mono.pOutput->Close(); + } + + if( LGLCD_INVALID_CONNECTION != m_hConnection ) + { + lgLcdDisconnect(m_hConnection); + m_hConnection = LGLCD_INVALID_CONNECTION; + } +} + + +//************************************************************************ +// +// CLCDConnection::IsConnected +// +//************************************************************************ + +BOOL CLCDConnection::IsConnected(void) +{ + return LGLCD_INVALID_CONNECTION != m_hConnection; +} + + +//************************************************************************ +// +// CLCDConnection::GetConnectionId +// +//************************************************************************ + +int CLCDConnection::GetConnectionId(void) +{ + return m_hConnection; +} + + +//************************************************************************ +// +// CLCDConnection::ColorOutput +// +//************************************************************************ + +CLCDOutput *CLCDConnection::ColorOutput(void) +{ + return m_AppletState.Color.pOutput; +} + + +//************************************************************************ +// +// CLCDConnection::MonoOutput +// +//************************************************************************ + +CLCDOutput *CLCDConnection::MonoOutput(void) +{ + return m_AppletState.Mono.pOutput; +} + + +//************************************************************************ +// +// CLCDConnection::_OnNotificationCallback +// +//************************************************************************ + +DWORD CALLBACK CLCDConnection::_OnNotificationCallback( + IN int connection, + IN const PVOID pContext, + IN DWORD notificationCode, + IN DWORD notifyParm1, + IN DWORD notifyParm2, + IN DWORD notifyParm3, + IN DWORD notifyParm4) +{ + + UNREFERENCED_PARAMETER(connection); + UNREFERENCED_PARAMETER(notifyParm3); + UNREFERENCED_PARAMETER(notifyParm4); + + CLCDConnection* pThis = (CLCDConnection*)pContext; + + CB_EVENT Event; + memset(&Event, 0, sizeof(Event)); + EnterCriticalSection(&pThis->m_csCallback); + Event.Type = CBT_NOTIFICATION; + Event.CallbackCode = notificationCode; + Event.CallbackParam1 = notifyParm1; + Event.CallbackParam2 = notifyParm2; + pThis->m_CallbackEventQueue.push(Event); + LeaveCriticalSection(&pThis->m_csCallback); + + pThis->OnCallbackEvent(); + + return 0; +} + + +//************************************************************************ +// +// CLCDConnection::_OnSoftButtonsCallback +// +//************************************************************************ + +DWORD CALLBACK CLCDConnection::_OnSoftButtonsCallback( + IN int device, + IN DWORD dwButtons, + IN const PVOID pContext) +{ + CLCDConnection* pThis = (CLCDConnection*)pContext; + + CB_EVENT Event; + memset(&Event, 0, sizeof(Event)); + EnterCriticalSection(&pThis->m_csCallback); + Event.Type = CBT_BUTTON; + Event.CallbackCode = device; + Event.CallbackParam1 = dwButtons; + pThis->m_CallbackEventQueue.push(Event); + LeaveCriticalSection(&pThis->m_csCallback); + + pThis->OnCallbackEvent(); + + return 0; +} + + +//************************************************************************ +// +// CLCDConnection::_OnConfigureCallback +// +//************************************************************************ + +DWORD CALLBACK CLCDConnection::_OnConfigureCallback( + IN int connection, + IN const PVOID pContext) +{ + UNREFERENCED_PARAMETER(connection); + + CLCDConnection* pThis = (CLCDConnection*)pContext; + + CB_EVENT Event; + memset(&Event, 0, sizeof(Event)); + EnterCriticalSection(&pThis->m_csCallback); + Event.Type = CBT_CONFIG; + pThis->m_CallbackEventQueue.push(Event); + LeaveCriticalSection(&pThis->m_csCallback); + + return 0; +} + + +//************************************************************************ +// +// CLCDConnection::GetNextCallbackEvent +// +//************************************************************************ + +BOOL CLCDConnection::GetNextCallbackEvent(CB_EVENT& rEvent) +{ + memset(&rEvent, 0, sizeof(rEvent)); + EnterCriticalSection(&m_csCallback); + if(0 < m_CallbackEventQueue.size()) + { + std::swap(rEvent, m_CallbackEventQueue.front()); + m_CallbackEventQueue.pop(); + LeaveCriticalSection(&m_csCallback); + return TRUE; + } + LeaveCriticalSection(&m_csCallback); + return FALSE; +} + + +//************************************************************************ +// +// CLCDConnection::Update +// +//************************************************************************ + +void CLCDConnection::Update(void) +{ + // If we're not connected, connect + if (LGLCD_INVALID_CONNECTION == m_hConnection) + { + Connect(); + } + + // Get events + CB_EVENT Event; + while(GetNextCallbackEvent(Event)) + { + switch(Event.Type) + { + case CBT_NOTIFICATION: + OnNotification(Event.CallbackCode, Event.CallbackParam1); + break; + + case CBT_CONFIG: + OnConfigure(); + break; + + case CBT_BUTTON: + OnSoftButtonEvent(Event.CallbackCode, Event.CallbackParam1); + break; + + default: + break; + } + } + + // For each display type + for (int i = 0; i < 2; i++) + { + LCD_DEVICE_STATE* pDevice = (i == 0) ? &m_AppletState.Mono : &m_AppletState.Color; + + if (NULL == pDevice->pOutput) + { + // Output not supported + continue; + } + + if (pDevice->pOutput->IsOpened()) + { + pDevice->pOutput->OnUpdate(GetTickCount()); + pDevice->pOutput->OnDraw(); + } + + // If the device is closed, but it was opened by OpenByType(), + // we can try to open it again... + if (!pDevice->pOutput->IsOpened() && pDevice->pOutput->HasBeenOpenedByDeviceType()) + { + pDevice->pOutput->ReOpenDeviceType(); + } + } +} + + +//************************************************************************ +// +// CLCDConnection::OnConfigure +// +//************************************************************************ + +void CLCDConnection::OnConfigure(void) +{ + LCDUITRACE(_T("OnConfigure\n")); +} + + +//************************************************************************ +// +// CLCDConnection::OnDeviceArrival +// +//************************************************************************ + +void CLCDConnection::OnDeviceArrival(DWORD dwDisplayType) +{ + LCD_DEVICE_STATE* pDevice = NULL; + + switch(dwDisplayType) + { + case LGLCD_DEVICE_BW: + pDevice = &m_AppletState.Mono; + break; + + case LGLCD_DEVICE_QVGA: + pDevice = &m_AppletState.Color; + break; + + default: + LCDUITRACE(_T("Unhandled DisplayType in OnDeviceArrival()!\n")); + return; + } + + // Ensure that we have a valid output + if (NULL == pDevice->pOutput) + { + LCDUITRACE(_T("Device arrival on unsupported device\n")); + return; + } + + lgLcdOpenByTypeContext OpenCtx; + memset(&OpenCtx, 0, sizeof(OpenCtx)); + + OpenCtx.connection = m_hConnection; + OpenCtx.deviceType = dwDisplayType; + OpenCtx.onSoftbuttonsChanged.softbuttonsChangedCallback = _OnSoftButtonsCallback; + OpenCtx.onSoftbuttonsChanged.softbuttonsChangedContext = this; + OpenCtx.device = LGLCD_INVALID_DEVICE; + + // If user has specified the soft button context, allow user to override + if (NULL != m_plcdSoftButtonsChangedCtx) + { + OpenCtx.onSoftbuttonsChanged = *m_plcdSoftButtonsChangedCtx; + } + + pDevice->pOutput->OpenByType(OpenCtx); +} + + +//************************************************************************ +// +// CLCDConnection::OnDeviceRemoval +// +//************************************************************************ + +void CLCDConnection::OnDeviceRemoval(DWORD dwDisplayType) +{ + LCD_DEVICE_STATE* pDevice = NULL; + + switch(dwDisplayType) + { + case LGLCD_DEVICE_BW: + pDevice = &m_AppletState.Mono; + break; + + case LGLCD_DEVICE_QVGA: + pDevice = &m_AppletState.Color; + break; + + default: + LCDUITRACE(_T("Unhandled DisplayType in OnDeviceArrival()!\n")); + return; + } + + if (pDevice->pOutput) + { + pDevice->pOutput->StopOpeningByDeviceType(); + pDevice->pOutput->Close(); + } +} + + +//************************************************************************ +// +// CLCDConnection::OnAppletEnabled +// +//************************************************************************ + +void CLCDConnection::OnAppletEnabled(void) +{ +} + + +//************************************************************************ +// +// CLCDConnection::OnAppletDisabled +// +//************************************************************************ + +void CLCDConnection::OnAppletDisabled(void) +{ +} + + +//************************************************************************ +// +// CLCDConnection::OnNotification +// +//************************************************************************ + +void CLCDConnection::OnNotification(DWORD dwNotification, DWORD dwParam1) +{ + switch(dwNotification) + { + case LGLCD_NOTIFICATION_DEVICE_ARRIVAL: + LCDUITRACE(_T("LGLCD_NOTIFICATION_DEVICE_ARRIVAL\n")); + OnDeviceArrival(dwParam1); + break; + + case LGLCD_NOTIFICATION_DEVICE_REMOVAL: + LCDUITRACE(_T("LGLCD_NOTIFICATION_DEVICE_REMOVAL\n")); + OnDeviceRemoval(dwParam1); + break; + + case LGLCD_NOTIFICATION_CLOSE_CONNECTION: + LCDUITRACE(_T("LGLCD_NOTIFICATION_CLOSE_CONNECTION\n")); + Disconnect(); + break; + + case LGLCD_NOTIFICATION_APPLET_DISABLED: + LCDUITRACE(_T("LGLCD_NOTIFICATION_APPLET_DISABLED\n")); + OnAppletDisabled(); + break; + + case LGLCD_NOTIFICATION_APPLET_ENABLED: + LCDUITRACE(_T("LGLCD_NOTIFICATION_APPLET_ENABLED\n")); + OnAppletEnabled(); + break; + + case LGLCD_NOTIFICATION_TERMINATE_APPLET: + break; + } +} + + +//************************************************************************ +// +// CLCDConnection::OnSoftButtonEvent +// +//************************************************************************ + +void CLCDConnection::OnSoftButtonEvent(int nDeviceId, DWORD dwButtonState) +{ + // Forward this to the appropriate display + if (m_AppletState.Mono.pOutput && (nDeviceId == m_AppletState.Mono.pOutput->GetDeviceId())) + { + m_AppletState.Mono.pOutput->OnSoftButtonEvent(dwButtonState); + } + else if (m_AppletState.Color.pOutput && (nDeviceId == m_AppletState.Color.pOutput->GetDeviceId())) + { + m_AppletState.Color.pOutput->OnSoftButtonEvent(dwButtonState); + } +} + + +//************************************************************************ +// +// CLCDConnection::AllocMonoOutput +// +//************************************************************************ + +CLCDOutput* CLCDConnection::AllocMonoOutput(void) +{ + return new CLCDOutput(); +} + + +//************************************************************************ +// +// CLCDConnection::AllocColorOutput +// +//************************************************************************ + +CLCDOutput* CLCDConnection::AllocColorOutput(void) +{ + return new CLCDOutput(); +} + + +//************************************************************************ +// +// CLCDConnection::FreeMonoOutput +// +//************************************************************************ + +void CLCDConnection::FreeMonoOutput(void) +{ + if (NULL != m_AppletState.Mono.pOutput) + { + delete m_AppletState.Mono.pOutput; + m_AppletState.Mono.pOutput = NULL; + } +} + + +//************************************************************************ +// +// CLCDConnection::FreeColorOutput +// +//************************************************************************ + +void CLCDConnection::FreeColorOutput(void) +{ + if (NULL != m_AppletState.Color.pOutput) + { + delete m_AppletState.Color.pOutput; + m_AppletState.Color.pOutput = NULL; + } +} + +//** end of LCDConnection.cpp ******************************************** diff --git a/src/thirdparty/LCDUI/LCDConnection.h b/src/thirdparty/LCDUI/LCDConnection.h index b24e1fe2ade..22bc4ae7c09 100644 --- a/src/thirdparty/LCDUI/LCDConnection.h +++ b/src/thirdparty/LCDUI/LCDConnection.h @@ -1,161 +1,161 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDConnection.h -// -// The CLCDConnection class manages connections to all LCD devices -// including color and monochrome -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDCONNECTION_H__ -#define __LCDCONNECTION_H__ - -#include "LCDOutput.h" -#include "LCDGfxMono.h" -#include "LCDGfxColor.h" -#include - -// LCD device state -typedef struct LCD_DEVICE_STATE -{ - CLCDOutput* pOutput; - CLCDGfxBase* pGfx; - -}LCD_DEVICE_STATE; - -// Applet state -typedef struct APPLET_STATE -{ - LCD_DEVICE_STATE Color; - LCD_DEVICE_STATE Mono; - BOOL isEnabled; - -}APPLET_STATE; - -#define LGLCD_INVALID_DEVICE_COOKIE (0) - - -class CLCDConnection -{ -public: - CLCDConnection(void); - virtual ~CLCDConnection(void); - - //This will attempt to open the library - //Call this function before Connect() - virtual BOOL Initialize(lgLcdConnectContext & ConnectContext, - lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext = NULL); - virtual BOOL Initialize(lgLcdConnectContextEx & ConnectContext, - lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext = NULL); - - //This will close your library - virtual void Shutdown(void); - - //Checks if there is a valid connection - virtual BOOL IsConnected(void); - virtual int GetConnectionId(void); - - // Call this function every game frame - virtual void Update(void); - - // Add your controls to the appropriate display - CLCDOutput *ColorOutput(void); - CLCDOutput *MonoOutput(void); - - BOOL HasColorDevice() { return m_AppletState.Color.pOutput && m_AppletState.Color.pOutput->IsOpened(); } - BOOL HasMonochromeDevice() { return m_AppletState.Mono.pOutput && m_AppletState.Mono.pOutput->IsOpened(); } - -protected: - // dwDisplayType = LGLCD_DEVICE_BW or LGLCD_DEVICE_QVGA - virtual void OnDeviceArrival(DWORD dwDisplayType); - virtual void OnDeviceRemoval(DWORD dwDisplayType); - virtual void OnAppletEnabled(void); - virtual void OnAppletDisabled(void); - virtual void OnNotification(DWORD dwNotification, DWORD dwParam1 = 0); - virtual void OnConfigure(void); - virtual void OnSoftButtonEvent(int nDeviceId, DWORD dwButtonState); - virtual void OnCallbackEvent(void) { } - -protected: - virtual void Connect(void); - virtual void Disconnect(void); - -protected: - // Override only if you need to create custom output classes - virtual CLCDOutput* AllocMonoOutput(void); - virtual CLCDOutput* AllocColorOutput(void); - virtual void FreeMonoOutput(void); - virtual void FreeColorOutput(void); - -protected: - // Internal threaded event handling - enum CB_TYPE { CBT_BUTTON, CBT_CONFIG, CBT_NOTIFICATION }; - typedef struct CB_EVENT - { - CB_TYPE Type; - DWORD CallbackCode; - DWORD CallbackParam1; - DWORD CallbackParam2; - DWORD CallbackParam3; - DWORD CallbackParam; - - } CB_EVENT; - - int m_hConnection; - - APPLET_STATE m_AppletState; - - - BOOL GetNextCallbackEvent(CB_EVENT& rEvent); - -private: - lgLcdConnectContextEx m_lcdConnectCtxEx; - - lgLcdSoftbuttonsChangedContext* m_plcdSoftButtonsChangedCtx; - - - -private: - typedef std::queue LCD_CB_EVENT_QUEUE; - - CRITICAL_SECTION m_csCallback; - LCD_CB_EVENT_QUEUE m_CallbackEventQueue; - - - -private: - static LONG g_lInitCount; - - static DWORD CALLBACK _OnNotificationCallback( - IN int connection, - IN const PVOID pContext, - IN DWORD notificationCode, - IN DWORD notifyParm1, - IN DWORD notifyParm2, - IN DWORD notifyParm3, - IN DWORD notifyParm4); - - static DWORD CALLBACK _OnSoftButtonsCallback( - IN int device, - IN DWORD dwButtons, - IN const PVOID pContext); - - static DWORD CALLBACK _OnConfigureCallback( - IN int connection, - IN const PVOID pContext); -}; - -#endif - -//** end of LCDConnection.h ********************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDConnection.h +// +// The CLCDConnection class manages connections to all LCD devices +// including color and monochrome +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDCONNECTION_H__ +#define __LCDCONNECTION_H__ + +#include "LCDOutput.h" +#include "LCDGfxMono.h" +#include "LCDGfxColor.h" +#include + +// LCD device state +typedef struct LCD_DEVICE_STATE +{ + CLCDOutput* pOutput; + CLCDGfxBase* pGfx; + +}LCD_DEVICE_STATE; + +// Applet state +typedef struct APPLET_STATE +{ + LCD_DEVICE_STATE Color; + LCD_DEVICE_STATE Mono; + BOOL isEnabled; + +}APPLET_STATE; + +#define LGLCD_INVALID_DEVICE_COOKIE (0) + + +class CLCDConnection +{ +public: + CLCDConnection(void); + virtual ~CLCDConnection(void); + + //This will attempt to open the library + //Call this function before Connect() + virtual BOOL Initialize(lgLcdConnectContext & ConnectContext, + lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext = NULL); + virtual BOOL Initialize(lgLcdConnectContextEx & ConnectContext, + lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext = NULL); + + //This will close your library + virtual void Shutdown(void); + + //Checks if there is a valid connection + virtual BOOL IsConnected(void); + virtual int GetConnectionId(void); + + // Call this function every game frame + virtual void Update(void); + + // Add your controls to the appropriate display + CLCDOutput *ColorOutput(void); + CLCDOutput *MonoOutput(void); + + BOOL HasColorDevice() { return m_AppletState.Color.pOutput && m_AppletState.Color.pOutput->IsOpened(); } + BOOL HasMonochromeDevice() { return m_AppletState.Mono.pOutput && m_AppletState.Mono.pOutput->IsOpened(); } + +protected: + // dwDisplayType = LGLCD_DEVICE_BW or LGLCD_DEVICE_QVGA + virtual void OnDeviceArrival(DWORD dwDisplayType); + virtual void OnDeviceRemoval(DWORD dwDisplayType); + virtual void OnAppletEnabled(void); + virtual void OnAppletDisabled(void); + virtual void OnNotification(DWORD dwNotification, DWORD dwParam1 = 0); + virtual void OnConfigure(void); + virtual void OnSoftButtonEvent(int nDeviceId, DWORD dwButtonState); + virtual void OnCallbackEvent(void) { } + +protected: + virtual void Connect(void); + virtual void Disconnect(void); + +protected: + // Override only if you need to create custom output classes + virtual CLCDOutput* AllocMonoOutput(void); + virtual CLCDOutput* AllocColorOutput(void); + virtual void FreeMonoOutput(void); + virtual void FreeColorOutput(void); + +protected: + // Internal threaded event handling + enum CB_TYPE { CBT_BUTTON, CBT_CONFIG, CBT_NOTIFICATION }; + typedef struct CB_EVENT + { + CB_TYPE Type; + DWORD CallbackCode; + DWORD CallbackParam1; + DWORD CallbackParam2; + DWORD CallbackParam3; + DWORD CallbackParam; + + } CB_EVENT; + + int m_hConnection; + + APPLET_STATE m_AppletState; + + + BOOL GetNextCallbackEvent(CB_EVENT& rEvent); + +private: + lgLcdConnectContextEx m_lcdConnectCtxEx; + + lgLcdSoftbuttonsChangedContext* m_plcdSoftButtonsChangedCtx; + + + +private: + typedef std::queue LCD_CB_EVENT_QUEUE; + + CRITICAL_SECTION m_csCallback; + LCD_CB_EVENT_QUEUE m_CallbackEventQueue; + + + +private: + static LONG g_lInitCount; + + static DWORD CALLBACK _OnNotificationCallback( + IN int connection, + IN const PVOID pContext, + IN DWORD notificationCode, + IN DWORD notifyParm1, + IN DWORD notifyParm2, + IN DWORD notifyParm3, + IN DWORD notifyParm4); + + static DWORD CALLBACK _OnSoftButtonsCallback( + IN int device, + IN DWORD dwButtons, + IN const PVOID pContext); + + static DWORD CALLBACK _OnConfigureCallback( + IN int connection, + IN const PVOID pContext); +}; + +#endif + +//** end of LCDConnection.h ********************************************** diff --git a/src/thirdparty/LCDUI/LCDGfxBase.cpp b/src/thirdparty/LCDUI/LCDGfxBase.cpp index f441b4e4e50..bee106659a5 100644 --- a/src/thirdparty/LCDUI/LCDGfxBase.cpp +++ b/src/thirdparty/LCDUI/LCDGfxBase.cpp @@ -1,300 +1,300 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxBase.cpp -// -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDGfxBase::CLCDGfxBase -// -//************************************************************************ - -CLCDGfxBase::CLCDGfxBase(void) -: m_pLCDScreen(NULL), - m_nWidth(0), - m_nHeight(0), - m_pBitmapInfo(NULL), - m_hDC(NULL), - m_hBitmap(NULL), - m_hPrevBitmap(NULL), - m_pBitmapBits(NULL) -{ -} - - -//************************************************************************ -// -// CLCDGfxBase::~CLCDGfxBase -// -//************************************************************************ - -CLCDGfxBase::~CLCDGfxBase(void) -{ - Shutdown(); -} - - -//************************************************************************ -// -// CLCDGfxBase::Initialize -// -//************************************************************************ - -HRESULT CLCDGfxBase::Initialize(void) -{ - m_hDC = CreateCompatibleDC(NULL); - if(NULL == m_hDC) - { - LCDUITRACE(_T("CLCDGfxBase::Initialize(): failed to create compatible DC.\n")); - Shutdown(); - return E_FAIL; - } - - return S_OK; -} - - -//************************************************************************ -// -// CLCDGfxBase::Shutdown -// -//************************************************************************ - -void CLCDGfxBase::Shutdown(void) -{ - if(NULL != m_hBitmap) - { - DeleteObject(m_hBitmap); - m_hBitmap = NULL; - m_pBitmapBits = NULL; - } - - LCDUIASSERT(NULL == m_hPrevBitmap); - m_hPrevBitmap = NULL; - - if(NULL != m_pBitmapInfo) - { - delete [] m_pBitmapInfo; - m_pBitmapInfo = NULL; - } - - if(NULL != m_hDC) - { - DeleteDC(m_hDC); - m_hDC = NULL; - } - - m_nWidth = 0; - m_nHeight = 0; -} - - -//************************************************************************ -// -// CLCDGfxBase::ClearScreen -// -//************************************************************************ - -void CLCDGfxBase::ClearScreen(void) -{ - // this means, we're inside BeginDraw()/EndDraw() - LCDUIASSERT(NULL != m_hPrevBitmap); - RECT rc = { 0, 0, m_nWidth, m_nHeight }; - FillRect(m_hDC, &rc, (HBRUSH) GetStockObject(BLACK_BRUSH)); -} - - -//************************************************************************ -// -// CLCDGfxBase::BeginDraw -// -//************************************************************************ - -void CLCDGfxBase::BeginDraw(void) -{ - LCDUIASSERT(NULL != m_hBitmap); - LCDUIASSERT(NULL == m_hPrevBitmap); - if(NULL == m_hPrevBitmap) - { - m_hPrevBitmap = (HBITMAP) SelectObject(m_hDC, m_hBitmap); - SetTextColor(m_hDC, RGB(255, 255, 255)); - SetBkColor(m_hDC, RGB(0, 0, 0)); - } -} - - -//************************************************************************ -// -// CLCDGfxBase::EndDraw -// -//************************************************************************ - -void CLCDGfxBase::EndDraw(void) -{ - LCDUIASSERT(NULL != m_hPrevBitmap); - if(NULL != m_hPrevBitmap) - { - GdiFlush(); - m_hPrevBitmap = (HBITMAP) SelectObject(m_hDC, m_hPrevBitmap); - LCDUIASSERT(m_hPrevBitmap == m_hBitmap); - m_hPrevBitmap = NULL; - } -} - - -//************************************************************************ -// -// CLCDGfxBase::GetHDC -// -//************************************************************************ - -HDC CLCDGfxBase::GetHDC(void) -{ - LCDUIASSERT(NULL != m_hDC); - return m_hDC; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetLCDScreen -// -//************************************************************************ - -lgLcdBitmap* CLCDGfxBase::GetLCDScreen(void) -{ - LCDUIASSERT(NULL != m_pLCDScreen); - if(NULL != m_pLCDScreen) - { - // monochrome, as well as color pixels start at the same offset... - memcpy(m_pLCDScreen->bmp_mono.pixels, m_pBitmapBits, m_nWidth * m_nHeight * 4); - } - - return m_pLCDScreen; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetBitmapInfo -// -//************************************************************************ - -BITMAPINFO* CLCDGfxBase::GetBitmapInfo(void) -{ - LCDUIASSERT(NULL != m_pBitmapInfo); - return m_pBitmapInfo; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetHBITMAP -// -//************************************************************************ - -HBITMAP CLCDGfxBase::GetHBITMAP(void) -{ - LCDUIASSERT(NULL != m_hBitmap); - return m_hBitmap; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetWidth -// -//************************************************************************ - -int CLCDGfxBase::GetWidth(void) -{ - return m_nWidth; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetHeight -// -//************************************************************************ - -int CLCDGfxBase::GetHeight(void) -{ - return m_nHeight; -} - - -//************************************************************************ -// -// CLCDGfxBase::CreateBitmap -// -//************************************************************************ - -HRESULT CLCDGfxBase::CreateBitmap(WORD wBitCount) -{ - int nBMISize = sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD); - m_pBitmapInfo = (BITMAPINFO *) new BYTE [nBMISize]; - if(NULL == m_pBitmapInfo) - { - LCDUITRACE(_T("CLCDGfxBase::CreateBitmap(): failed to allocate bitmap info.\n")); - Shutdown(); - return E_OUTOFMEMORY; - } - - ZeroMemory(m_pBitmapInfo, nBMISize); - m_pBitmapInfo->bmiHeader.biSize = sizeof(m_pBitmapInfo->bmiHeader); - m_pBitmapInfo->bmiHeader.biWidth = m_nWidth; - m_pBitmapInfo->bmiHeader.biHeight = -m_nHeight; - m_pBitmapInfo->bmiHeader.biPlanes = 1; - m_pBitmapInfo->bmiHeader.biBitCount = wBitCount; - m_pBitmapInfo->bmiHeader.biCompression = BI_RGB; - m_pBitmapInfo->bmiHeader.biSizeImage = - (m_nWidth * - m_nHeight * - m_pBitmapInfo->bmiHeader.biBitCount) / 8; - m_pBitmapInfo->bmiHeader.biXPelsPerMeter = 3200; - m_pBitmapInfo->bmiHeader.biYPelsPerMeter = 3200; - m_pBitmapInfo->bmiHeader.biClrUsed = 256; - m_pBitmapInfo->bmiHeader.biClrImportant = 256; - - for(int nColor = 0; nColor < 256; ++nColor) - { - m_pBitmapInfo->bmiColors[nColor].rgbRed = (BYTE)((nColor > 128) ? 255 : 0); - m_pBitmapInfo->bmiColors[nColor].rgbGreen = (BYTE)((nColor > 128) ? 255 : 0); - m_pBitmapInfo->bmiColors[nColor].rgbBlue = (BYTE)((nColor > 128) ? 255 : 0); - m_pBitmapInfo->bmiColors[nColor].rgbReserved = 0; - } - - m_hBitmap = CreateDIBSection(m_hDC, m_pBitmapInfo, DIB_RGB_COLORS, - (PVOID *) &m_pBitmapBits, NULL, 0); - if(NULL == m_hBitmap) - { - LCDUITRACE(_T("CLCDGfxBase::CreateBitmap(): failed to create bitmap.\n")); - Shutdown(); - return E_FAIL; - } - - return S_OK; -} - - -//** end of LCDGfxBase.cpp *********************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxBase.cpp +// +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDGfxBase::CLCDGfxBase +// +//************************************************************************ + +CLCDGfxBase::CLCDGfxBase(void) +: m_pLCDScreen(NULL), + m_nWidth(0), + m_nHeight(0), + m_pBitmapInfo(NULL), + m_hDC(NULL), + m_hBitmap(NULL), + m_hPrevBitmap(NULL), + m_pBitmapBits(NULL) +{ +} + + +//************************************************************************ +// +// CLCDGfxBase::~CLCDGfxBase +// +//************************************************************************ + +CLCDGfxBase::~CLCDGfxBase(void) +{ + Shutdown(); +} + + +//************************************************************************ +// +// CLCDGfxBase::Initialize +// +//************************************************************************ + +HRESULT CLCDGfxBase::Initialize(void) +{ + m_hDC = CreateCompatibleDC(NULL); + if(NULL == m_hDC) + { + LCDUITRACE(_T("CLCDGfxBase::Initialize(): failed to create compatible DC.\n")); + Shutdown(); + return E_FAIL; + } + + return S_OK; +} + + +//************************************************************************ +// +// CLCDGfxBase::Shutdown +// +//************************************************************************ + +void CLCDGfxBase::Shutdown(void) +{ + if(NULL != m_hBitmap) + { + DeleteObject(m_hBitmap); + m_hBitmap = NULL; + m_pBitmapBits = NULL; + } + + LCDUIASSERT(NULL == m_hPrevBitmap); + m_hPrevBitmap = NULL; + + if(NULL != m_pBitmapInfo) + { + delete [] m_pBitmapInfo; + m_pBitmapInfo = NULL; + } + + if(NULL != m_hDC) + { + DeleteDC(m_hDC); + m_hDC = NULL; + } + + m_nWidth = 0; + m_nHeight = 0; +} + + +//************************************************************************ +// +// CLCDGfxBase::ClearScreen +// +//************************************************************************ + +void CLCDGfxBase::ClearScreen(void) +{ + // this means, we're inside BeginDraw()/EndDraw() + LCDUIASSERT(NULL != m_hPrevBitmap); + RECT rc = { 0, 0, m_nWidth, m_nHeight }; + FillRect(m_hDC, &rc, (HBRUSH) GetStockObject(BLACK_BRUSH)); +} + + +//************************************************************************ +// +// CLCDGfxBase::BeginDraw +// +//************************************************************************ + +void CLCDGfxBase::BeginDraw(void) +{ + LCDUIASSERT(NULL != m_hBitmap); + LCDUIASSERT(NULL == m_hPrevBitmap); + if(NULL == m_hPrevBitmap) + { + m_hPrevBitmap = (HBITMAP) SelectObject(m_hDC, m_hBitmap); + SetTextColor(m_hDC, RGB(255, 255, 255)); + SetBkColor(m_hDC, RGB(0, 0, 0)); + } +} + + +//************************************************************************ +// +// CLCDGfxBase::EndDraw +// +//************************************************************************ + +void CLCDGfxBase::EndDraw(void) +{ + LCDUIASSERT(NULL != m_hPrevBitmap); + if(NULL != m_hPrevBitmap) + { + GdiFlush(); + m_hPrevBitmap = (HBITMAP) SelectObject(m_hDC, m_hPrevBitmap); + LCDUIASSERT(m_hPrevBitmap == m_hBitmap); + m_hPrevBitmap = NULL; + } +} + + +//************************************************************************ +// +// CLCDGfxBase::GetHDC +// +//************************************************************************ + +HDC CLCDGfxBase::GetHDC(void) +{ + LCDUIASSERT(NULL != m_hDC); + return m_hDC; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetLCDScreen +// +//************************************************************************ + +lgLcdBitmap* CLCDGfxBase::GetLCDScreen(void) +{ + LCDUIASSERT(NULL != m_pLCDScreen); + if(NULL != m_pLCDScreen) + { + // monochrome, as well as color pixels start at the same offset... + memcpy(m_pLCDScreen->bmp_mono.pixels, m_pBitmapBits, m_nWidth * m_nHeight * 4); + } + + return m_pLCDScreen; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetBitmapInfo +// +//************************************************************************ + +BITMAPINFO* CLCDGfxBase::GetBitmapInfo(void) +{ + LCDUIASSERT(NULL != m_pBitmapInfo); + return m_pBitmapInfo; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetHBITMAP +// +//************************************************************************ + +HBITMAP CLCDGfxBase::GetHBITMAP(void) +{ + LCDUIASSERT(NULL != m_hBitmap); + return m_hBitmap; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetWidth +// +//************************************************************************ + +int CLCDGfxBase::GetWidth(void) +{ + return m_nWidth; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetHeight +// +//************************************************************************ + +int CLCDGfxBase::GetHeight(void) +{ + return m_nHeight; +} + + +//************************************************************************ +// +// CLCDGfxBase::CreateBitmap +// +//************************************************************************ + +HRESULT CLCDGfxBase::CreateBitmap(WORD wBitCount) +{ + int nBMISize = sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD); + m_pBitmapInfo = (BITMAPINFO *) new BYTE [nBMISize]; + if(NULL == m_pBitmapInfo) + { + LCDUITRACE(_T("CLCDGfxBase::CreateBitmap(): failed to allocate bitmap info.\n")); + Shutdown(); + return E_OUTOFMEMORY; + } + + ZeroMemory(m_pBitmapInfo, nBMISize); + m_pBitmapInfo->bmiHeader.biSize = sizeof(m_pBitmapInfo->bmiHeader); + m_pBitmapInfo->bmiHeader.biWidth = m_nWidth; + m_pBitmapInfo->bmiHeader.biHeight = -m_nHeight; + m_pBitmapInfo->bmiHeader.biPlanes = 1; + m_pBitmapInfo->bmiHeader.biBitCount = wBitCount; + m_pBitmapInfo->bmiHeader.biCompression = BI_RGB; + m_pBitmapInfo->bmiHeader.biSizeImage = + (m_nWidth * + m_nHeight * + m_pBitmapInfo->bmiHeader.biBitCount) / 8; + m_pBitmapInfo->bmiHeader.biXPelsPerMeter = 3200; + m_pBitmapInfo->bmiHeader.biYPelsPerMeter = 3200; + m_pBitmapInfo->bmiHeader.biClrUsed = 256; + m_pBitmapInfo->bmiHeader.biClrImportant = 256; + + for(int nColor = 0; nColor < 256; ++nColor) + { + m_pBitmapInfo->bmiColors[nColor].rgbRed = (BYTE)((nColor > 128) ? 255 : 0); + m_pBitmapInfo->bmiColors[nColor].rgbGreen = (BYTE)((nColor > 128) ? 255 : 0); + m_pBitmapInfo->bmiColors[nColor].rgbBlue = (BYTE)((nColor > 128) ? 255 : 0); + m_pBitmapInfo->bmiColors[nColor].rgbReserved = 0; + } + + m_hBitmap = CreateDIBSection(m_hDC, m_pBitmapInfo, DIB_RGB_COLORS, + (PVOID *) &m_pBitmapBits, NULL, 0); + if(NULL == m_hBitmap) + { + LCDUITRACE(_T("CLCDGfxBase::CreateBitmap(): failed to create bitmap.\n")); + Shutdown(); + return E_FAIL; + } + + return S_OK; +} + + +//** end of LCDGfxBase.cpp *********************************************** diff --git a/src/thirdparty/LCDUI/LCDGfxBase.h b/src/thirdparty/LCDUI/LCDGfxBase.h index 826c6f7b2b6..eee95291215 100644 --- a/src/thirdparty/LCDUI/LCDGfxBase.h +++ b/src/thirdparty/LCDUI/LCDGfxBase.h @@ -1,95 +1,95 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxBase.h -// -// Abstract class for different display types. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDGFXBASE_H__ -#define __LCDGFXBASE_H__ - -#include - - -#if _MSC_VER >= 1400 -#define LCDUI_tcsncpy(x, y, z) _tcsncpy_s(x, _countof(x), y, z) -#define LCDUI_tcscpy(x, y) _tcscpy_s(x, _countof(x), y) -#else -#define LCDUI_tcsncpy(x, y, z) _tcsncpy(x, y, z) -#define LCDUI_tcscpy(x, y) _tcscpy(x, y) -#endif - -#ifndef LCDUITRACE - // .NET compiler uses __noop intrinsic - #if _MSC_VER > 1300 - #define LCDUITRACE __noop - #else - #define LCDUITRACE (void)0 - #endif -#endif - -#ifndef LCDUIASSERT - // .NET compiler uses __noop intrinsic - #if _MSC_VER > 1300 - #define LCDUIASSERT __noop - #else - #define LCDUIASSERT (void)0 - #endif -#endif - - -class CLCDGfxBase -{ -public: - CLCDGfxBase(void); - virtual ~CLCDGfxBase(void); - - virtual HRESULT Initialize(void); - virtual void Shutdown(void); - virtual void ClearScreen(void); - virtual void BeginDraw(void); - virtual void EndDraw(void); - - virtual HDC GetHDC(void); - virtual lgLcdBitmap *GetLCDScreen(void); - virtual BITMAPINFO *GetBitmapInfo(void); - virtual HBITMAP GetHBITMAP(void); - - virtual DWORD GetFamily(void) = 0; - - virtual int GetWidth(void); - virtual int GetHeight(void); - -protected: - HRESULT CreateBitmap(WORD wBitCount); - -protected: - lgLcdBitmap *m_pLCDScreen; - int m_nWidth; - int m_nHeight; - BITMAPINFO *m_pBitmapInfo; - HDC m_hDC; - HBITMAP m_hBitmap; - HBITMAP m_hPrevBitmap; - PBYTE m_pBitmapBits; - -}; - -#endif - -//** end of LCDGfxBase.h ************************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxBase.h +// +// Abstract class for different display types. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDGFXBASE_H__ +#define __LCDGFXBASE_H__ + +#include + + +#if _MSC_VER >= 1400 +#define LCDUI_tcsncpy(x, y, z) _tcsncpy_s(x, _countof(x), y, z) +#define LCDUI_tcscpy(x, y) _tcscpy_s(x, _countof(x), y) +#else +#define LCDUI_tcsncpy(x, y, z) _tcsncpy(x, y, z) +#define LCDUI_tcscpy(x, y) _tcscpy(x, y) +#endif + +#ifndef LCDUITRACE + // .NET compiler uses __noop intrinsic + #if _MSC_VER > 1300 + #define LCDUITRACE __noop + #else + #define LCDUITRACE (void)0 + #endif +#endif + +#ifndef LCDUIASSERT + // .NET compiler uses __noop intrinsic + #if _MSC_VER > 1300 + #define LCDUIASSERT __noop + #else + #define LCDUIASSERT (void)0 + #endif +#endif + + +class CLCDGfxBase +{ +public: + CLCDGfxBase(void); + virtual ~CLCDGfxBase(void); + + virtual HRESULT Initialize(void); + virtual void Shutdown(void); + virtual void ClearScreen(void); + virtual void BeginDraw(void); + virtual void EndDraw(void); + + virtual HDC GetHDC(void); + virtual lgLcdBitmap *GetLCDScreen(void); + virtual BITMAPINFO *GetBitmapInfo(void); + virtual HBITMAP GetHBITMAP(void); + + virtual DWORD GetFamily(void) = 0; + + virtual int GetWidth(void); + virtual int GetHeight(void); + +protected: + HRESULT CreateBitmap(WORD wBitCount); + +protected: + lgLcdBitmap *m_pLCDScreen; + int m_nWidth; + int m_nHeight; + BITMAPINFO *m_pBitmapInfo; + HDC m_hDC; + HBITMAP m_hBitmap; + HBITMAP m_hPrevBitmap; + PBYTE m_pBitmapBits; + +}; + +#endif + +//** end of LCDGfxBase.h ************************************************* diff --git a/src/thirdparty/LCDUI/LCDGfxColor.cpp b/src/thirdparty/LCDUI/LCDGfxColor.cpp index 6b5ff1d3617..5d9d569c63e 100644 --- a/src/thirdparty/LCDUI/LCDGfxColor.cpp +++ b/src/thirdparty/LCDUI/LCDGfxColor.cpp @@ -1,94 +1,94 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxColor.cpp -// -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDGfxColor::CLCDGfxColor -// -//************************************************************************ - -CLCDGfxColor::CLCDGfxColor(void) -{ - m_pLCDScreen = (lgLcdBitmap *) &m_LCDScreen; - m_pLCDScreen->hdr.Format = LGLCD_BMP_FORMAT_QVGAx32; -} - - -//************************************************************************ -// -// CLCDGfxColor::~CLCDGfxColor -// -//************************************************************************ - -CLCDGfxColor::~CLCDGfxColor(void) -{ -} - - -//************************************************************************ -// -// CLCDGfxColor::Initialize -// -//************************************************************************ - -HRESULT CLCDGfxColor::Initialize(void) -{ - //reset everything - Shutdown(); - - m_nWidth = LGLCD_QVGA_BMP_WIDTH; - m_nHeight = LGLCD_QVGA_BMP_HEIGHT; - - HRESULT hRes = CLCDGfxBase::Initialize(); - if(FAILED(hRes)) - { - return hRes; - } - - hRes = CLCDGfxBase::CreateBitmap(32); - if(FAILED(hRes)) - { - return hRes; - } - - return S_OK; -} - - -//************************************************************************ -// -// CLCDGfxColor::GetLCDScreen -// -//************************************************************************ - -lgLcdBitmap* CLCDGfxColor::GetLCDScreen(void) -{ - LCDUIASSERT(m_pLCDScreen == (lgLcdBitmap *) &m_LCDScreen); - m_LCDScreen.hdr.Format = LGLCD_BMP_FORMAT_QVGAx32; - memcpy(m_LCDScreen.pixels, m_pBitmapBits, m_nWidth * m_nHeight * 4); - return m_pLCDScreen; -} - - -//** end of LCDGfxColor.cpp ********************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxColor.cpp +// +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDGfxColor::CLCDGfxColor +// +//************************************************************************ + +CLCDGfxColor::CLCDGfxColor(void) +{ + m_pLCDScreen = (lgLcdBitmap *) &m_LCDScreen; + m_pLCDScreen->hdr.Format = LGLCD_BMP_FORMAT_QVGAx32; +} + + +//************************************************************************ +// +// CLCDGfxColor::~CLCDGfxColor +// +//************************************************************************ + +CLCDGfxColor::~CLCDGfxColor(void) +{ +} + + +//************************************************************************ +// +// CLCDGfxColor::Initialize +// +//************************************************************************ + +HRESULT CLCDGfxColor::Initialize(void) +{ + //reset everything + Shutdown(); + + m_nWidth = LGLCD_QVGA_BMP_WIDTH; + m_nHeight = LGLCD_QVGA_BMP_HEIGHT; + + HRESULT hRes = CLCDGfxBase::Initialize(); + if(FAILED(hRes)) + { + return hRes; + } + + hRes = CLCDGfxBase::CreateBitmap(32); + if(FAILED(hRes)) + { + return hRes; + } + + return S_OK; +} + + +//************************************************************************ +// +// CLCDGfxColor::GetLCDScreen +// +//************************************************************************ + +lgLcdBitmap* CLCDGfxColor::GetLCDScreen(void) +{ + LCDUIASSERT(m_pLCDScreen == (lgLcdBitmap *) &m_LCDScreen); + m_LCDScreen.hdr.Format = LGLCD_BMP_FORMAT_QVGAx32; + memcpy(m_LCDScreen.pixels, m_pBitmapBits, m_nWidth * m_nHeight * 4); + return m_pLCDScreen; +} + + +//** end of LCDGfxColor.cpp ********************************************** diff --git a/src/thirdparty/LCDUI/LCDGfxColor.h b/src/thirdparty/LCDUI/LCDGfxColor.h index 795c60d2bd9..ce6ed05c52a 100644 --- a/src/thirdparty/LCDUI/LCDGfxColor.h +++ b/src/thirdparty/LCDUI/LCDGfxColor.h @@ -1,48 +1,48 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxColor.h -// -// This Gfx object handles drawing to a 320x240 color display. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDGFXCOLOR_H__ -#define __LCDGFXCOLOR_H__ - -#include "LCDGfxBase.h" - -class CLCDGfxColor : public CLCDGfxBase -{ -public: - CLCDGfxColor(void); - virtual ~CLCDGfxColor(void); - - virtual HRESULT Initialize(void); - virtual lgLcdBitmap *GetLCDScreen(void); - - virtual DWORD GetFamily(void) - { - return LGLCD_DEVICE_FAMILY_QVGA_BASIC; - } - -private: - lgLcdBitmapQVGAx32 m_LCDScreen; -}; - -#endif - -//** end of LCDGfxColor.h************************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxColor.h +// +// This Gfx object handles drawing to a 320x240 color display. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDGFXCOLOR_H__ +#define __LCDGFXCOLOR_H__ + +#include "LCDGfxBase.h" + +class CLCDGfxColor : public CLCDGfxBase +{ +public: + CLCDGfxColor(void); + virtual ~CLCDGfxColor(void); + + virtual HRESULT Initialize(void); + virtual lgLcdBitmap *GetLCDScreen(void); + + virtual DWORD GetFamily(void) + { + return LGLCD_DEVICE_FAMILY_QVGA_BASIC; + } + +private: + lgLcdBitmapQVGAx32 m_LCDScreen; +}; + +#endif + +//** end of LCDGfxColor.h************************************************* diff --git a/src/thirdparty/LCDUI/LCDGfxMono.cpp b/src/thirdparty/LCDUI/LCDGfxMono.cpp index ed2938073dc..fa421c66ae2 100644 --- a/src/thirdparty/LCDUI/LCDGfxMono.cpp +++ b/src/thirdparty/LCDUI/LCDGfxMono.cpp @@ -1,108 +1,108 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxMono.cpp -// -// This Gfx object handles drawing to a 160x43 monochrome display. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDGfxMono::CLCDGfxMono -// -//************************************************************************ - -CLCDGfxMono::CLCDGfxMono(void) -{ - m_pLCDScreen = (lgLcdBitmap *) &m_LCDScreen; - m_pLCDScreen->hdr.Format = LGLCD_BMP_FORMAT_160x43x1; -} - - -//************************************************************************ -// -// CLCDGfxMono::~CLCDGfxMono -// -//************************************************************************ - -CLCDGfxMono::~CLCDGfxMono(void) -{ -} - - -//************************************************************************ -// -// CLCDGfxMono::Initialize -// -//************************************************************************ - -HRESULT CLCDGfxMono::Initialize(void) -{ - //reset everything - Shutdown(); - - m_nWidth = LGLCD_BW_BMP_WIDTH; - m_nHeight = LGLCD_BW_BMP_HEIGHT; - - HRESULT hRes = CLCDGfxBase::Initialize(); - if(FAILED(hRes)) - { - return hRes; - } - - hRes = CLCDGfxBase::CreateBitmap(8); - if(FAILED(hRes)) - { - return hRes; - } - - return S_OK; -} - - -//************************************************************************ -// -// CLCDGfxMono::GetLCDScreen -// -//************************************************************************ - -lgLcdBitmap* CLCDGfxMono::GetLCDScreen(void) -{ - LCDUIASSERT(m_pLCDScreen == (lgLcdBitmap *) &m_LCDScreen); - m_LCDScreen.hdr.Format = LGLCD_BMP_FORMAT_160x43x1; - memcpy(m_LCDScreen.pixels, m_pBitmapBits, m_nWidth * m_nHeight); - return m_pLCDScreen; -} - - -//************************************************************************ -// -// CLCDGfxMono::ClearScreen -// -//************************************************************************ - -void CLCDGfxMono::ClearScreen(void) -{ - memset(m_pBitmapBits, 0, m_nWidth * m_nHeight); - - CLCDGfxBase::ClearScreen(); -} - -//** end of LCDGfxMono.cpp *********************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxMono.cpp +// +// This Gfx object handles drawing to a 160x43 monochrome display. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDGfxMono::CLCDGfxMono +// +//************************************************************************ + +CLCDGfxMono::CLCDGfxMono(void) +{ + m_pLCDScreen = (lgLcdBitmap *) &m_LCDScreen; + m_pLCDScreen->hdr.Format = LGLCD_BMP_FORMAT_160x43x1; +} + + +//************************************************************************ +// +// CLCDGfxMono::~CLCDGfxMono +// +//************************************************************************ + +CLCDGfxMono::~CLCDGfxMono(void) +{ +} + + +//************************************************************************ +// +// CLCDGfxMono::Initialize +// +//************************************************************************ + +HRESULT CLCDGfxMono::Initialize(void) +{ + //reset everything + Shutdown(); + + m_nWidth = LGLCD_BW_BMP_WIDTH; + m_nHeight = LGLCD_BW_BMP_HEIGHT; + + HRESULT hRes = CLCDGfxBase::Initialize(); + if(FAILED(hRes)) + { + return hRes; + } + + hRes = CLCDGfxBase::CreateBitmap(8); + if(FAILED(hRes)) + { + return hRes; + } + + return S_OK; +} + + +//************************************************************************ +// +// CLCDGfxMono::GetLCDScreen +// +//************************************************************************ + +lgLcdBitmap* CLCDGfxMono::GetLCDScreen(void) +{ + LCDUIASSERT(m_pLCDScreen == (lgLcdBitmap *) &m_LCDScreen); + m_LCDScreen.hdr.Format = LGLCD_BMP_FORMAT_160x43x1; + memcpy(m_LCDScreen.pixels, m_pBitmapBits, m_nWidth * m_nHeight); + return m_pLCDScreen; +} + + +//************************************************************************ +// +// CLCDGfxMono::ClearScreen +// +//************************************************************************ + +void CLCDGfxMono::ClearScreen(void) +{ + memset(m_pBitmapBits, 0, m_nWidth * m_nHeight); + + CLCDGfxBase::ClearScreen(); +} + +//** end of LCDGfxMono.cpp *********************************************** diff --git a/src/thirdparty/LCDUI/LCDGfxMono.h b/src/thirdparty/LCDUI/LCDGfxMono.h index 49530ea8750..e24e6d515ba 100644 --- a/src/thirdparty/LCDUI/LCDGfxMono.h +++ b/src/thirdparty/LCDUI/LCDGfxMono.h @@ -1,49 +1,49 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxMono.h -// -// This Gfx object handles drawing to a 160x43 monochrome display. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDGFXMONO_H__ -#define __LCDGFXMONO_H__ - -#include "LCDGfxBase.h" - -class CLCDGfxMono : public CLCDGfxBase -{ -public: - CLCDGfxMono(void); - virtual ~CLCDGfxMono(void); - - virtual HRESULT Initialize(void); - virtual lgLcdBitmap *GetLCDScreen(void); - virtual void ClearScreen(void); - - virtual DWORD GetFamily(void) - { - return LGLCD_DEVICE_FAMILY_KEYBOARD_G15; - } - -private: - lgLcdBitmap160x43x1 m_LCDScreen; -}; - -#endif - -//** end of LCDGfxMono.h ************************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxMono.h +// +// This Gfx object handles drawing to a 160x43 monochrome display. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDGFXMONO_H__ +#define __LCDGFXMONO_H__ + +#include "LCDGfxBase.h" + +class CLCDGfxMono : public CLCDGfxBase +{ +public: + CLCDGfxMono(void); + virtual ~CLCDGfxMono(void); + + virtual HRESULT Initialize(void); + virtual lgLcdBitmap *GetLCDScreen(void); + virtual void ClearScreen(void); + + virtual DWORD GetFamily(void) + { + return LGLCD_DEVICE_FAMILY_KEYBOARD_G15; + } + +private: + lgLcdBitmap160x43x1 m_LCDScreen; +}; + +#endif + +//** end of LCDGfxMono.h ************************************************* diff --git a/src/thirdparty/LCDUI/LCDIcon.cpp b/src/thirdparty/LCDUI/LCDIcon.cpp index 65e1f955da5..a5363da8e1d 100644 --- a/src/thirdparty/LCDUI/LCDIcon.cpp +++ b/src/thirdparty/LCDUI/LCDIcon.cpp @@ -1,86 +1,86 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDIcon.cpp -// -// The CLCDIcon class draws icons onto the lcd. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDIcon::CLCDIcon -// -//************************************************************************ - -CLCDIcon::CLCDIcon(void) -: m_hIcon(NULL), - m_nIconWidth(16), - m_nIconHeight(16) -{ -} - - -//************************************************************************ -// -// CLCDIcon::CLCDIcon -// -//************************************************************************ - -CLCDIcon::~CLCDIcon(void) -{ -} - - -//************************************************************************ -// -// CLCDIcon::SetIcon -// -//************************************************************************ - -void CLCDIcon::SetIcon(HICON hIcon, int nWidth /* = 16 */, int nHeight /* = 16 */) -{ - m_hIcon = hIcon; - m_nIconWidth = nWidth; - m_nIconHeight = nHeight; -} - - -//************************************************************************ -// -// CLCDIcon::OnDraw -// -//************************************************************************ - -void CLCDIcon::OnDraw(CLCDGfxBase &rGfx) -{ - if (m_hIcon) - { - int nOldBkMode = SetBkMode(rGfx.GetHDC(), TRANSPARENT); - - DrawIconEx(rGfx.GetHDC(), 0, 0, m_hIcon, - m_nIconWidth, m_nIconHeight, 0, NULL, DI_NORMAL); - if (m_bInverted) - { - RECT rBoundary = { 0, 0, m_nIconWidth, m_nIconHeight}; - InvertRect(rGfx.GetHDC(), &rBoundary); - } - SetBkMode(rGfx.GetHDC(), nOldBkMode); - } -} - - -//** end of LCDIcon.cpp ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDIcon.cpp +// +// The CLCDIcon class draws icons onto the lcd. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDIcon::CLCDIcon +// +//************************************************************************ + +CLCDIcon::CLCDIcon(void) +: m_hIcon(NULL), + m_nIconWidth(16), + m_nIconHeight(16) +{ +} + + +//************************************************************************ +// +// CLCDIcon::CLCDIcon +// +//************************************************************************ + +CLCDIcon::~CLCDIcon(void) +{ +} + + +//************************************************************************ +// +// CLCDIcon::SetIcon +// +//************************************************************************ + +void CLCDIcon::SetIcon(HICON hIcon, int nWidth /* = 16 */, int nHeight /* = 16 */) +{ + m_hIcon = hIcon; + m_nIconWidth = nWidth; + m_nIconHeight = nHeight; +} + + +//************************************************************************ +// +// CLCDIcon::OnDraw +// +//************************************************************************ + +void CLCDIcon::OnDraw(CLCDGfxBase &rGfx) +{ + if (m_hIcon) + { + int nOldBkMode = SetBkMode(rGfx.GetHDC(), TRANSPARENT); + + DrawIconEx(rGfx.GetHDC(), 0, 0, m_hIcon, + m_nIconWidth, m_nIconHeight, 0, NULL, DI_NORMAL); + if (m_bInverted) + { + RECT rBoundary = { 0, 0, m_nIconWidth, m_nIconHeight}; + InvertRect(rGfx.GetHDC(), &rBoundary); + } + SetBkMode(rGfx.GetHDC(), nOldBkMode); + } +} + + +//** end of LCDIcon.cpp ************************************************** diff --git a/src/thirdparty/LCDUI/LCDIcon.h b/src/thirdparty/LCDUI/LCDIcon.h index ad394604a98..1de35c39573 100644 --- a/src/thirdparty/LCDUI/LCDIcon.h +++ b/src/thirdparty/LCDUI/LCDIcon.h @@ -1,50 +1,50 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDIcon.h -// -// The CLCDIcon class draws icons onto the lcd. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDICON_H_INCLUDED_ -#define _LCDICON_H_INCLUDED_ - -#include "LCDBase.h" - -class CLCDIcon : public CLCDBase -{ -public: - CLCDIcon(void); - virtual ~CLCDIcon(void); - - void SetIcon(HICON hIcon, int nWidth = 16, int nHeight = 16); - - HICON GetIcon(void) - { - return m_hIcon; - } - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - -private: - HICON m_hIcon; - int m_nIconWidth; - int m_nIconHeight; -}; - - -#endif // !_LCDICON_H_INCLUDED_ - -//** end of LCDIcon.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDIcon.h +// +// The CLCDIcon class draws icons onto the lcd. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDICON_H_INCLUDED_ +#define _LCDICON_H_INCLUDED_ + +#include "LCDBase.h" + +class CLCDIcon : public CLCDBase +{ +public: + CLCDIcon(void); + virtual ~CLCDIcon(void); + + void SetIcon(HICON hIcon, int nWidth = 16, int nHeight = 16); + + HICON GetIcon(void) + { + return m_hIcon; + } + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + +private: + HICON m_hIcon; + int m_nIconWidth; + int m_nIconHeight; +}; + + +#endif // !_LCDICON_H_INCLUDED_ + +//** end of LCDIcon.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDOutput.cpp b/src/thirdparty/LCDUI/LCDOutput.cpp index 54186973e48..efa4b2593b8 100644 --- a/src/thirdparty/LCDUI/LCDOutput.cpp +++ b/src/thirdparty/LCDUI/LCDOutput.cpp @@ -1,654 +1,654 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDOutput.cpp -// -// The CLCDOutput manages the actual device and the various pages that -// are sent to that device -// -// This class is now managed by CLCDConnection. You no longer need to -// derive or instantiate this class yourself -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDOutput::CLCDOutput -// -//************************************************************************ - -CLCDOutput::CLCDOutput(void) -: m_pActivePage(NULL), - m_hDevice(LGLCD_INVALID_DEVICE), - m_bSetAsForeground(FALSE), - m_dwButtonState(0), - m_nPriority(LGLCD_PRIORITY_NORMAL), - m_pGfx(NULL) -{ - ZeroMemory(&m_OpenByTypeContext, sizeof(m_OpenByTypeContext)); -} - - -//************************************************************************ -// -// CLCDOutput::~CLCDOutput -// -//************************************************************************ - -CLCDOutput::~CLCDOutput(void) -{ - Shutdown(); -} - - -//************************************************************************ -// -// CLCDOutput::SetGfx -// -//************************************************************************ - -void CLCDOutput::SetGfx(CLCDGfxBase *gfx) -{ - m_pGfx = gfx; -} - - -//************************************************************************ -// -// CLCDOutput::Open -// -//************************************************************************ - -BOOL CLCDOutput::Open(lgLcdOpenContext & OpenContext) -{ - //Close the old device if there is one - Close(); - - DWORD res = lgLcdOpen(&OpenContext); - if (ERROR_SUCCESS != res) - { - if( res == ERROR_INVALID_PARAMETER ) - { - LCDUITRACE( _T("Open failed: invalid parameter.\n") ); - return FALSE; - } - else if( res == ERROR_ALREADY_EXISTS ) - { - LCDUITRACE( _T("Open failed: already exists.\n") ); - return FALSE; - } - return FALSE; - } - - m_hDevice = OpenContext.device; - m_dwButtonState = 0; - - // restores - SetAsForeground(m_bSetAsForeground); - - OnOpenedDevice(m_hDevice); - - return TRUE; -} - - -//************************************************************************ -// -// CLCDOutput::OpenByType -// -//************************************************************************ - -BOOL CLCDOutput::OpenByType(lgLcdOpenByTypeContext &OpenContext) -{ - //Close the old device if there is one - Close(); - - DWORD res = lgLcdOpenByType(&OpenContext); - if (ERROR_SUCCESS != res) - { - if( res == ERROR_INVALID_PARAMETER ) - { - LCDUITRACE( _T("Open failed: invalid parameter.\n") ); - return FALSE; - } - else if( res == ERROR_ALREADY_EXISTS ) - { - LCDUITRACE( _T("Open failed: already exists.\n") ); - return FALSE; - } - return FALSE; - } - - m_hDevice = OpenContext.device; - m_dwButtonState = 0; - - // restores - SetAsForeground(m_bSetAsForeground); - - m_OpenByTypeContext = OpenContext; - - OnOpenedDevice(m_hDevice); - - return TRUE; -} - - -//************************************************************************ -// -// CLCDOutput::ReOpenDeviceType -// -//************************************************************************ - -BOOL CLCDOutput::ReOpenDeviceType(void) -{ - // The device type must be active - if (!HasBeenOpenedByDeviceType()) - { - return FALSE; - } - - return OpenByType(m_OpenByTypeContext); -} - - -//************************************************************************ -// -// CLCDOutput::Close -// -//************************************************************************ - -void CLCDOutput::Close(void) -{ - if( LGLCD_INVALID_DEVICE != m_hDevice ) - { - OnClosingDevice(m_hDevice); - lgLcdClose(m_hDevice); - m_hDevice = LGLCD_INVALID_DEVICE; - } -} - - -//************************************************************************ -// -// CLCDOutput::Shutdown -// -//************************************************************************ - -void CLCDOutput::Shutdown(void) -{ - Close(); -} - - -//************************************************************************ -// -// CLCDOutput::AddPage -// -//************************************************************************ - -void CLCDOutput::AddPage(CLCDPage *pPage) -{ - pPage->Initialize(); - AddObject(pPage); -} - - -//************************************************************************ -// -// CLCDOutput::RemovePage -// -//************************************************************************ - -void CLCDOutput::RemovePage(CLCDPage *pPage) -{ - RemoveObject(pPage); -} - - -//************************************************************************ -// -// CLCDOutput::ShowPage -// -//************************************************************************ - -void CLCDOutput::ShowPage(CLCDPage *pPage, BOOL bShow) -{ - LCDUIASSERT(NULL != pPage); - - if (bShow) - { - m_pActivePage = pPage; - - OnPageShown(pPage); - } - else - { - // Expire it and update - pPage->SetExpiration(0); - OnUpdate(GetTickCount()); - } -} - - -//************************************************************************ -// -// CLCDOutput::GetShowingPage -// -//************************************************************************ - -CLCDPage* CLCDOutput::GetShowingPage(void) -{ - return m_pActivePage; -} - - -//************************************************************************ -// -// CLCDOutput::SetScreenPriority -// -//************************************************************************ - -void CLCDOutput::SetScreenPriority(DWORD priority) -{ - // Priority has changed - // If we're going into idle, send an idle frame - if (LGLCD_PRIORITY_IDLE_NO_SHOW == priority) - { - lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr, - LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW)); - } - - m_nPriority = priority; -} - - -//************************************************************************ -// -// CLCDOutput::GetScreenPriority -// -//************************************************************************ - -DWORD CLCDOutput::GetScreenPriority(void) -{ - return m_nPriority; -} - - -//************************************************************************ -// -// CLCDOutput::IsOpened -// -//************************************************************************ - -BOOL CLCDOutput::IsOpened(void) -{ - return (LGLCD_INVALID_DEVICE != m_hDevice); -} - - -//************************************************************************ -// -// CLCDOutput::SetAsForeground -// -//************************************************************************ - -HRESULT CLCDOutput::SetAsForeground(BOOL bSetAsForeground) -{ - m_bSetAsForeground = bSetAsForeground; - if (LGLCD_INVALID_DEVICE != m_hDevice) - { - DWORD dwRes = lgLcdSetAsLCDForegroundApp(m_hDevice, bSetAsForeground); - if(ERROR_SUCCESS != dwRes) - { - return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes); - } - } - return E_FAIL; -} - - -//************************************************************************ -// -// CLCDOutput::OnDraw -// -//************************************************************************ - -BOOL CLCDOutput::OnDraw(void) -{ - DWORD dwPriorityToUse = LGLCD_ASYNC_UPDATE(m_nPriority); - - if ( (NULL == m_pActivePage) || - (LGLCD_INVALID_DEVICE == m_hDevice) || - (LGLCD_PRIORITY_IDLE_NO_SHOW == dwPriorityToUse) ) - { - // don't submit the bitmap - return TRUE; - } - - // Render the active screen - m_pGfx->BeginDraw(); - m_pGfx->ClearScreen(); - m_pActivePage->OnDraw(*m_pGfx); - m_pGfx->EndDraw(); - - // Get the active bitmap - lgLcdBitmap* pBitmap = m_pGfx->GetLCDScreen(); - - // Only submit if the bitmap needs to be updated - // (If the priority or bitmap have changed) - DWORD res = ERROR_SUCCESS; - if (DoesBitmapNeedUpdate(pBitmap)) - { - res = lgLcdUpdateBitmap(m_hDevice, &pBitmap->bmp_mono.hdr, dwPriorityToUse); - HandleErrorFromAPI(res); - } - - return (LGLCD_INVALID_DEVICE != m_hDevice); -} - - -//************************************************************************ -// -// CLCDOutput::OnUpdate -// -//************************************************************************ - -void CLCDOutput::OnUpdate(DWORD dwTimestamp) -{ - if (m_pActivePage) - { - m_pActivePage->OnUpdate(dwTimestamp); - } - - // check for expiration - if (m_pActivePage && m_pActivePage->HasExpired()) - { - m_pActivePage = NULL; - //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a - // program sets priority to LGLCD_PRIORITY_BACKGROUND, that - // priority sticks. - - OnPageExpired(m_pActivePage); - - // find the next active screen - for (size_t i = 0; i < m_Objects.size(); i++) - { - CLCDPage *pPage = dynamic_cast(m_Objects[i]); - LCDUIASSERT(NULL != pPage); - - if (!pPage->HasExpired()) - { - ShowPage(pPage); - //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a - // program sets priority to LGLCD_PRIORITY_BACKGROUND, that - // priority sticks. - break; - } - } - - // if no screen found, empty the screen at idle priority - if (NULL == m_pActivePage) - { - OnEnteringIdle(); - if (LGLCD_INVALID_DEVICE != m_hDevice) - { - m_pGfx->ClearScreen(); - lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr, - LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW)); - } - } - } -} - - -//************************************************************************ -// -// CLCDOutput::GetSoftButtonState -// -//************************************************************************ - -DWORD CLCDOutput::GetSoftButtonState(void) -{ - return IsOpened() ? m_dwButtonState : 0; -} - - -//************************************************************************ -// -// CLCDOutput::HandleErrorFromAPI -// -//************************************************************************ - -HRESULT CLCDOutput::HandleErrorFromAPI(DWORD dwRes) -{ - switch(dwRes) - { - // all is well - case ERROR_SUCCESS: - case RPC_S_PROTOCOL_ERROR: - break; - // we lost our device - case ERROR_DEVICE_NOT_CONNECTED: - LCDUITRACE(_T("lgLcdAPI returned with ERROR_DEVICE_NOT_CONNECTED, closing device\n")); - Close(); - break; - default: - LCDUITRACE(_T("lgLcdAPI returned with other error (0x%08x) closing device\n")); - Close(); - // something else happened, such as LCDMon that was terminated - break; - } - - if(ERROR_SUCCESS != dwRes) - { - return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes); - } - - return S_OK; -} - - -//************************************************************************ -// -// CLCDOutput::DoesBitmapNeedUpdate -// -//************************************************************************ - -BOOL CLCDOutput::DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap) -{ - UNREFERENCED_PARAMETER(pBitmap); - // For now, always update - return TRUE; -} - - -//************************************************************************ -// -// CLCDOutput::OnPageExpired -// -//************************************************************************ - -void CLCDOutput::OnPageExpired(CLCDCollection* pScreen) -{ - UNREFERENCED_PARAMETER(pScreen); -} - - -//************************************************************************ -// -// CLCDOutput::OnPageShown -// -//************************************************************************ - -void CLCDOutput::OnPageShown(CLCDCollection* pScreen) -{ - UNREFERENCED_PARAMETER(pScreen); -} - - -//************************************************************************ -// -// CLCDOutput::OnEnteringIdle -// -//************************************************************************ - -void CLCDOutput::OnEnteringIdle(void) -{ -} - - -//************************************************************************ -// -// CLCDOutput::OnClosingDevice -// -//************************************************************************ - -void CLCDOutput::OnClosingDevice(int hDevice) -{ - UNREFERENCED_PARAMETER(hDevice); -} - - -//************************************************************************ -// -// CLCDOutput::OnOpenedDevice -// -//************************************************************************ - -void CLCDOutput::OnOpenedDevice(int hDevice) -{ - UNREFERENCED_PARAMETER(hDevice); -} - - -//************************************************************************ -// -// CLCDOutput::OnSoftButtonEvent -// -//************************************************************************ - -void CLCDOutput::OnSoftButtonEvent(DWORD dwButtonState) -{ - if (LGLCD_DEVICE_FAMILY_QVGA_BASIC == m_pGfx->GetFamily()) - { - HandleButtonState(dwButtonState, LGLCDBUTTON_LEFT); - HandleButtonState(dwButtonState, LGLCDBUTTON_RIGHT); - HandleButtonState(dwButtonState, LGLCDBUTTON_OK); - HandleButtonState(dwButtonState, LGLCDBUTTON_CANCEL); - HandleButtonState(dwButtonState, LGLCDBUTTON_UP); - HandleButtonState(dwButtonState, LGLCDBUTTON_DOWN); - HandleButtonState(dwButtonState, LGLCDBUTTON_MENU); - } - else - { - HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON0); - HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON1); - HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON2); - HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON3); - } - - m_dwButtonState = dwButtonState; -} - - -//************************************************************************ -// -// CLCDOutput::HandleButtonState -// -//************************************************************************ - -void CLCDOutput::HandleButtonState(DWORD dwButtonState, DWORD dwButton) -{ - if ( (m_dwButtonState & dwButton) && !(dwButtonState & dwButton) ) - { - LCDUITRACE(_T("Button 0x%x released\n"), dwButton); - OnLCDButtonUp(dwButton); - } - if ( !(m_dwButtonState & dwButton) && (dwButtonState & dwButton) ) - { - LCDUITRACE(_T("Button 0x%x pressed\n"), dwButton); - OnLCDButtonDown(dwButton); - } -} - - -//************************************************************************ -// -// CLCDOutput::OnLCDButtonDown -// -//************************************************************************ - -void CLCDOutput::OnLCDButtonDown(int nButton) -{ - if (m_pActivePage) - { - m_pActivePage->OnLCDButtonDown(nButton); - } -} - - -//************************************************************************ -// -// CLCDOutput::OnLCDButtonUp -// -//************************************************************************ - -void CLCDOutput::OnLCDButtonUp(int nButton) -{ - if (m_pActivePage) - { - m_pActivePage->OnLCDButtonUp(nButton); - } -} - - -//************************************************************************ -// -// CLCDOutput::GetDeviceId -// -//************************************************************************ - -int CLCDOutput::GetDeviceId(void) -{ - return m_hDevice; -} - - -//************************************************************************ -// -// CLCDOutput::StopOpeningByDeviceType -// -//************************************************************************ - -void CLCDOutput::StopOpeningByDeviceType(void) -{ - m_OpenByTypeContext.deviceType = 0; -} - - -//************************************************************************ -// -// CLCDOutput::HasBeenOpenedByDeviceType -// -//************************************************************************ - -BOOL CLCDOutput::HasBeenOpenedByDeviceType(void) -{ - return (0 != m_OpenByTypeContext.deviceType); -} - - -//** end of LCDOutput.cpp ************************************************ +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDOutput.cpp +// +// The CLCDOutput manages the actual device and the various pages that +// are sent to that device +// +// This class is now managed by CLCDConnection. You no longer need to +// derive or instantiate this class yourself +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDOutput::CLCDOutput +// +//************************************************************************ + +CLCDOutput::CLCDOutput(void) +: m_pActivePage(NULL), + m_hDevice(LGLCD_INVALID_DEVICE), + m_bSetAsForeground(FALSE), + m_dwButtonState(0), + m_nPriority(LGLCD_PRIORITY_NORMAL), + m_pGfx(NULL) +{ + ZeroMemory(&m_OpenByTypeContext, sizeof(m_OpenByTypeContext)); +} + + +//************************************************************************ +// +// CLCDOutput::~CLCDOutput +// +//************************************************************************ + +CLCDOutput::~CLCDOutput(void) +{ + Shutdown(); +} + + +//************************************************************************ +// +// CLCDOutput::SetGfx +// +//************************************************************************ + +void CLCDOutput::SetGfx(CLCDGfxBase *gfx) +{ + m_pGfx = gfx; +} + + +//************************************************************************ +// +// CLCDOutput::Open +// +//************************************************************************ + +BOOL CLCDOutput::Open(lgLcdOpenContext & OpenContext) +{ + //Close the old device if there is one + Close(); + + DWORD res = lgLcdOpen(&OpenContext); + if (ERROR_SUCCESS != res) + { + if( res == ERROR_INVALID_PARAMETER ) + { + LCDUITRACE( _T("Open failed: invalid parameter.\n") ); + return FALSE; + } + else if( res == ERROR_ALREADY_EXISTS ) + { + LCDUITRACE( _T("Open failed: already exists.\n") ); + return FALSE; + } + return FALSE; + } + + m_hDevice = OpenContext.device; + m_dwButtonState = 0; + + // restores + SetAsForeground(m_bSetAsForeground); + + OnOpenedDevice(m_hDevice); + + return TRUE; +} + + +//************************************************************************ +// +// CLCDOutput::OpenByType +// +//************************************************************************ + +BOOL CLCDOutput::OpenByType(lgLcdOpenByTypeContext &OpenContext) +{ + //Close the old device if there is one + Close(); + + DWORD res = lgLcdOpenByType(&OpenContext); + if (ERROR_SUCCESS != res) + { + if( res == ERROR_INVALID_PARAMETER ) + { + LCDUITRACE( _T("Open failed: invalid parameter.\n") ); + return FALSE; + } + else if( res == ERROR_ALREADY_EXISTS ) + { + LCDUITRACE( _T("Open failed: already exists.\n") ); + return FALSE; + } + return FALSE; + } + + m_hDevice = OpenContext.device; + m_dwButtonState = 0; + + // restores + SetAsForeground(m_bSetAsForeground); + + m_OpenByTypeContext = OpenContext; + + OnOpenedDevice(m_hDevice); + + return TRUE; +} + + +//************************************************************************ +// +// CLCDOutput::ReOpenDeviceType +// +//************************************************************************ + +BOOL CLCDOutput::ReOpenDeviceType(void) +{ + // The device type must be active + if (!HasBeenOpenedByDeviceType()) + { + return FALSE; + } + + return OpenByType(m_OpenByTypeContext); +} + + +//************************************************************************ +// +// CLCDOutput::Close +// +//************************************************************************ + +void CLCDOutput::Close(void) +{ + if( LGLCD_INVALID_DEVICE != m_hDevice ) + { + OnClosingDevice(m_hDevice); + lgLcdClose(m_hDevice); + m_hDevice = LGLCD_INVALID_DEVICE; + } +} + + +//************************************************************************ +// +// CLCDOutput::Shutdown +// +//************************************************************************ + +void CLCDOutput::Shutdown(void) +{ + Close(); +} + + +//************************************************************************ +// +// CLCDOutput::AddPage +// +//************************************************************************ + +void CLCDOutput::AddPage(CLCDPage *pPage) +{ + pPage->Initialize(); + AddObject(pPage); +} + + +//************************************************************************ +// +// CLCDOutput::RemovePage +// +//************************************************************************ + +void CLCDOutput::RemovePage(CLCDPage *pPage) +{ + RemoveObject(pPage); +} + + +//************************************************************************ +// +// CLCDOutput::ShowPage +// +//************************************************************************ + +void CLCDOutput::ShowPage(CLCDPage *pPage, BOOL bShow) +{ + LCDUIASSERT(NULL != pPage); + + if (bShow) + { + m_pActivePage = pPage; + + OnPageShown(pPage); + } + else + { + // Expire it and update + pPage->SetExpiration(0); + OnUpdate(GetTickCount()); + } +} + + +//************************************************************************ +// +// CLCDOutput::GetShowingPage +// +//************************************************************************ + +CLCDPage* CLCDOutput::GetShowingPage(void) +{ + return m_pActivePage; +} + + +//************************************************************************ +// +// CLCDOutput::SetScreenPriority +// +//************************************************************************ + +void CLCDOutput::SetScreenPriority(DWORD priority) +{ + // Priority has changed + // If we're going into idle, send an idle frame + if (LGLCD_PRIORITY_IDLE_NO_SHOW == priority) + { + lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr, + LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW)); + } + + m_nPriority = priority; +} + + +//************************************************************************ +// +// CLCDOutput::GetScreenPriority +// +//************************************************************************ + +DWORD CLCDOutput::GetScreenPriority(void) +{ + return m_nPriority; +} + + +//************************************************************************ +// +// CLCDOutput::IsOpened +// +//************************************************************************ + +BOOL CLCDOutput::IsOpened(void) +{ + return (LGLCD_INVALID_DEVICE != m_hDevice); +} + + +//************************************************************************ +// +// CLCDOutput::SetAsForeground +// +//************************************************************************ + +HRESULT CLCDOutput::SetAsForeground(BOOL bSetAsForeground) +{ + m_bSetAsForeground = bSetAsForeground; + if (LGLCD_INVALID_DEVICE != m_hDevice) + { + DWORD dwRes = lgLcdSetAsLCDForegroundApp(m_hDevice, bSetAsForeground); + if(ERROR_SUCCESS != dwRes) + { + return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes); + } + } + return E_FAIL; +} + + +//************************************************************************ +// +// CLCDOutput::OnDraw +// +//************************************************************************ + +BOOL CLCDOutput::OnDraw(void) +{ + DWORD dwPriorityToUse = LGLCD_ASYNC_UPDATE(m_nPriority); + + if ( (NULL == m_pActivePage) || + (LGLCD_INVALID_DEVICE == m_hDevice) || + (LGLCD_PRIORITY_IDLE_NO_SHOW == dwPriorityToUse) ) + { + // don't submit the bitmap + return TRUE; + } + + // Render the active screen + m_pGfx->BeginDraw(); + m_pGfx->ClearScreen(); + m_pActivePage->OnDraw(*m_pGfx); + m_pGfx->EndDraw(); + + // Get the active bitmap + lgLcdBitmap* pBitmap = m_pGfx->GetLCDScreen(); + + // Only submit if the bitmap needs to be updated + // (If the priority or bitmap have changed) + DWORD res = ERROR_SUCCESS; + if (DoesBitmapNeedUpdate(pBitmap)) + { + res = lgLcdUpdateBitmap(m_hDevice, &pBitmap->bmp_mono.hdr, dwPriorityToUse); + HandleErrorFromAPI(res); + } + + return (LGLCD_INVALID_DEVICE != m_hDevice); +} + + +//************************************************************************ +// +// CLCDOutput::OnUpdate +// +//************************************************************************ + +void CLCDOutput::OnUpdate(DWORD dwTimestamp) +{ + if (m_pActivePage) + { + m_pActivePage->OnUpdate(dwTimestamp); + } + + // check for expiration + if (m_pActivePage && m_pActivePage->HasExpired()) + { + m_pActivePage = NULL; + //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a + // program sets priority to LGLCD_PRIORITY_BACKGROUND, that + // priority sticks. + + OnPageExpired(m_pActivePage); + + // find the next active screen + for (size_t i = 0; i < m_Objects.size(); i++) + { + CLCDPage *pPage = dynamic_cast(m_Objects[i]); + LCDUIASSERT(NULL != pPage); + + if (!pPage->HasExpired()) + { + ShowPage(pPage); + //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a + // program sets priority to LGLCD_PRIORITY_BACKGROUND, that + // priority sticks. + break; + } + } + + // if no screen found, empty the screen at idle priority + if (NULL == m_pActivePage) + { + OnEnteringIdle(); + if (LGLCD_INVALID_DEVICE != m_hDevice) + { + m_pGfx->ClearScreen(); + lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr, + LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW)); + } + } + } +} + + +//************************************************************************ +// +// CLCDOutput::GetSoftButtonState +// +//************************************************************************ + +DWORD CLCDOutput::GetSoftButtonState(void) +{ + return IsOpened() ? m_dwButtonState : 0; +} + + +//************************************************************************ +// +// CLCDOutput::HandleErrorFromAPI +// +//************************************************************************ + +HRESULT CLCDOutput::HandleErrorFromAPI(DWORD dwRes) +{ + switch(dwRes) + { + // all is well + case ERROR_SUCCESS: + case RPC_S_PROTOCOL_ERROR: + break; + // we lost our device + case ERROR_DEVICE_NOT_CONNECTED: + LCDUITRACE(_T("lgLcdAPI returned with ERROR_DEVICE_NOT_CONNECTED, closing device\n")); + Close(); + break; + default: + LCDUITRACE(_T("lgLcdAPI returned with other error (0x%08x) closing device\n")); + Close(); + // something else happened, such as LCDMon that was terminated + break; + } + + if(ERROR_SUCCESS != dwRes) + { + return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes); + } + + return S_OK; +} + + +//************************************************************************ +// +// CLCDOutput::DoesBitmapNeedUpdate +// +//************************************************************************ + +BOOL CLCDOutput::DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap) +{ + UNREFERENCED_PARAMETER(pBitmap); + // For now, always update + return TRUE; +} + + +//************************************************************************ +// +// CLCDOutput::OnPageExpired +// +//************************************************************************ + +void CLCDOutput::OnPageExpired(CLCDCollection* pScreen) +{ + UNREFERENCED_PARAMETER(pScreen); +} + + +//************************************************************************ +// +// CLCDOutput::OnPageShown +// +//************************************************************************ + +void CLCDOutput::OnPageShown(CLCDCollection* pScreen) +{ + UNREFERENCED_PARAMETER(pScreen); +} + + +//************************************************************************ +// +// CLCDOutput::OnEnteringIdle +// +//************************************************************************ + +void CLCDOutput::OnEnteringIdle(void) +{ +} + + +//************************************************************************ +// +// CLCDOutput::OnClosingDevice +// +//************************************************************************ + +void CLCDOutput::OnClosingDevice(int hDevice) +{ + UNREFERENCED_PARAMETER(hDevice); +} + + +//************************************************************************ +// +// CLCDOutput::OnOpenedDevice +// +//************************************************************************ + +void CLCDOutput::OnOpenedDevice(int hDevice) +{ + UNREFERENCED_PARAMETER(hDevice); +} + + +//************************************************************************ +// +// CLCDOutput::OnSoftButtonEvent +// +//************************************************************************ + +void CLCDOutput::OnSoftButtonEvent(DWORD dwButtonState) +{ + if (LGLCD_DEVICE_FAMILY_QVGA_BASIC == m_pGfx->GetFamily()) + { + HandleButtonState(dwButtonState, LGLCDBUTTON_LEFT); + HandleButtonState(dwButtonState, LGLCDBUTTON_RIGHT); + HandleButtonState(dwButtonState, LGLCDBUTTON_OK); + HandleButtonState(dwButtonState, LGLCDBUTTON_CANCEL); + HandleButtonState(dwButtonState, LGLCDBUTTON_UP); + HandleButtonState(dwButtonState, LGLCDBUTTON_DOWN); + HandleButtonState(dwButtonState, LGLCDBUTTON_MENU); + } + else + { + HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON0); + HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON1); + HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON2); + HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON3); + } + + m_dwButtonState = dwButtonState; +} + + +//************************************************************************ +// +// CLCDOutput::HandleButtonState +// +//************************************************************************ + +void CLCDOutput::HandleButtonState(DWORD dwButtonState, DWORD dwButton) +{ + if ( (m_dwButtonState & dwButton) && !(dwButtonState & dwButton) ) + { + LCDUITRACE(_T("Button 0x%x released\n"), dwButton); + OnLCDButtonUp(dwButton); + } + if ( !(m_dwButtonState & dwButton) && (dwButtonState & dwButton) ) + { + LCDUITRACE(_T("Button 0x%x pressed\n"), dwButton); + OnLCDButtonDown(dwButton); + } +} + + +//************************************************************************ +// +// CLCDOutput::OnLCDButtonDown +// +//************************************************************************ + +void CLCDOutput::OnLCDButtonDown(int nButton) +{ + if (m_pActivePage) + { + m_pActivePage->OnLCDButtonDown(nButton); + } +} + + +//************************************************************************ +// +// CLCDOutput::OnLCDButtonUp +// +//************************************************************************ + +void CLCDOutput::OnLCDButtonUp(int nButton) +{ + if (m_pActivePage) + { + m_pActivePage->OnLCDButtonUp(nButton); + } +} + + +//************************************************************************ +// +// CLCDOutput::GetDeviceId +// +//************************************************************************ + +int CLCDOutput::GetDeviceId(void) +{ + return m_hDevice; +} + + +//************************************************************************ +// +// CLCDOutput::StopOpeningByDeviceType +// +//************************************************************************ + +void CLCDOutput::StopOpeningByDeviceType(void) +{ + m_OpenByTypeContext.deviceType = 0; +} + + +//************************************************************************ +// +// CLCDOutput::HasBeenOpenedByDeviceType +// +//************************************************************************ + +BOOL CLCDOutput::HasBeenOpenedByDeviceType(void) +{ + return (0 != m_OpenByTypeContext.deviceType); +} + + +//** end of LCDOutput.cpp ************************************************ diff --git a/src/thirdparty/LCDUI/LCDOutput.h b/src/thirdparty/LCDUI/LCDOutput.h index a11a2e9107a..af857fb5dce 100644 --- a/src/thirdparty/LCDUI/LCDOutput.h +++ b/src/thirdparty/LCDUI/LCDOutput.h @@ -1,107 +1,107 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDOutput.h -// -// The CLCDOutput manages the actual device and the various pages that -// are sent to that device -// -// This class is now managed by CLCDConnection. You no longer need to -// derive or instantiate this class yourself -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _CLCDOUTPUT_H_INCLUDED_ -#define _CLCDOUTPUT_H_INCLUDED_ - -#include "LCDCollection.h" -#include "LCDGfxBase.h" -#include "LCDPage.h" - - -class CLCDOutput : public CLCDCollection -{ -public: - CLCDOutput(void); - virtual ~CLCDOutput(void); - - // Assign the type of graphics this output supports. - // This is set by CLCDConnection. - void SetGfx(CLCDGfxBase *gfx); - - void AddPage(CLCDPage *pPage); - void RemovePage(CLCDPage *pPage); - void ShowPage(CLCDPage *pPage, BOOL bShow = TRUE); - CLCDPage* GetShowingPage(void); - - BOOL Open(lgLcdOpenContext &OpenContext); - BOOL OpenByType(lgLcdOpenByTypeContext &OpenContext); - void Close(void); - void Shutdown(void); - - void SetScreenPriority(DWORD priority); - DWORD GetScreenPriority(void); - - BOOL IsOpened(void); - HRESULT SetAsForeground(BOOL bSetAsForeground); - - virtual BOOL OnDraw(void); - virtual void OnUpdate(DWORD dwTimestamp ); - virtual void OnLCDButtonDown(int nButton); - virtual void OnLCDButtonUp(int nButton); - - virtual void OnSoftButtonEvent(DWORD dwButtonState); - DWORD GetSoftButtonState(void); - - // This returns true, if the device got opened through - // OpenByType(), instead of regular Open(). - BOOL HasBeenOpenedByDeviceType(void); - - // This is being called when we receive a device removal - // notification. After that, we can't reopen devices anymore - // (until the next device arrival comes in) - void StopOpeningByDeviceType(void); - - // This is called, when a device function fails. This can - // sometimes happen during plug/unplug and two same devices - // are present. - BOOL ReOpenDeviceType(void); - - int GetDeviceId(void); - -protected: - virtual BOOL DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap); - virtual void OnPageShown(CLCDCollection* pScreen); - virtual void OnPageExpired(CLCDCollection* pScreen); - virtual void OnEnteringIdle(void); - virtual void OnClosingDevice(int hDevice); - virtual void OnOpenedDevice(int hDevice); - - int m_hDevice; - CLCDPage* m_pActivePage; - DWORD m_nPriority; - CLCDGfxBase* m_pGfx; - -private: - HRESULT HandleErrorFromAPI(DWORD dwRes); - void HandleButtonState(DWORD dwButtonState, DWORD dwButton); - - BOOL m_bSetAsForeground; - DWORD m_dwButtonState; - - lgLcdOpenByTypeContext m_OpenByTypeContext; -}; - -#endif - -//** end of LCDOutput.h ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDOutput.h +// +// The CLCDOutput manages the actual device and the various pages that +// are sent to that device +// +// This class is now managed by CLCDConnection. You no longer need to +// derive or instantiate this class yourself +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _CLCDOUTPUT_H_INCLUDED_ +#define _CLCDOUTPUT_H_INCLUDED_ + +#include "LCDCollection.h" +#include "LCDGfxBase.h" +#include "LCDPage.h" + + +class CLCDOutput : public CLCDCollection +{ +public: + CLCDOutput(void); + virtual ~CLCDOutput(void); + + // Assign the type of graphics this output supports. + // This is set by CLCDConnection. + void SetGfx(CLCDGfxBase *gfx); + + void AddPage(CLCDPage *pPage); + void RemovePage(CLCDPage *pPage); + void ShowPage(CLCDPage *pPage, BOOL bShow = TRUE); + CLCDPage* GetShowingPage(void); + + BOOL Open(lgLcdOpenContext &OpenContext); + BOOL OpenByType(lgLcdOpenByTypeContext &OpenContext); + void Close(void); + void Shutdown(void); + + void SetScreenPriority(DWORD priority); + DWORD GetScreenPriority(void); + + BOOL IsOpened(void); + HRESULT SetAsForeground(BOOL bSetAsForeground); + + virtual BOOL OnDraw(void); + virtual void OnUpdate(DWORD dwTimestamp ); + virtual void OnLCDButtonDown(int nButton); + virtual void OnLCDButtonUp(int nButton); + + virtual void OnSoftButtonEvent(DWORD dwButtonState); + DWORD GetSoftButtonState(void); + + // This returns true, if the device got opened through + // OpenByType(), instead of regular Open(). + BOOL HasBeenOpenedByDeviceType(void); + + // This is being called when we receive a device removal + // notification. After that, we can't reopen devices anymore + // (until the next device arrival comes in) + void StopOpeningByDeviceType(void); + + // This is called, when a device function fails. This can + // sometimes happen during plug/unplug and two same devices + // are present. + BOOL ReOpenDeviceType(void); + + int GetDeviceId(void); + +protected: + virtual BOOL DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap); + virtual void OnPageShown(CLCDCollection* pScreen); + virtual void OnPageExpired(CLCDCollection* pScreen); + virtual void OnEnteringIdle(void); + virtual void OnClosingDevice(int hDevice); + virtual void OnOpenedDevice(int hDevice); + + int m_hDevice; + CLCDPage* m_pActivePage; + DWORD m_nPriority; + CLCDGfxBase* m_pGfx; + +private: + HRESULT HandleErrorFromAPI(DWORD dwRes); + void HandleButtonState(DWORD dwButtonState, DWORD dwButton); + + BOOL m_bSetAsForeground; + DWORD m_dwButtonState; + + lgLcdOpenByTypeContext m_OpenByTypeContext; +}; + +#endif + +//** end of LCDOutput.h ************************************************** diff --git a/src/thirdparty/LCDUI/LCDPage.cpp b/src/thirdparty/LCDUI/LCDPage.cpp index 6e74c189044..4b1da9cee9b 100644 --- a/src/thirdparty/LCDUI/LCDPage.cpp +++ b/src/thirdparty/LCDUI/LCDPage.cpp @@ -1,224 +1,224 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPage.cpp -// -// Collection of items representing a page. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDPage::CLCDPage -// -//************************************************************************ - -CLCDPage::CLCDPage(void) -: m_dwStartTime(0), - m_dwEllapsedTime(0), - m_dwExpirationTime(0) -{ - SetExpiration(INFINITE); - m_bUseBitmapBackground = FALSE; - m_bUseColorBackground = FALSE; -} - - -//************************************************************************ -// -// CLCDPage::~CLCDPage -// -//************************************************************************ - -CLCDPage::~CLCDPage(void) -{ -} - - -//************************************************************************ -// -// CLCDPage::OnDraw -// -//************************************************************************ - -void CLCDPage::OnDraw(CLCDGfxBase &rGfx) -{ - if(!IsVisible()) - { - return; - } - - //Draw the background first - if(m_bUseBitmapBackground) - { - m_Background.OnDraw(rGfx); - } - else if(m_bUseColorBackground) - { - HBRUSH hBackBrush = CreateSolidBrush(m_BackgroundColor); - HBRUSH hOldBrush = (HBRUSH)SelectObject(rGfx.GetHDC(), hBackBrush); - Rectangle(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight()); - SelectObject(rGfx.GetHDC(), hOldBrush); - DeleteObject(hBackBrush); - } - - - //iterate through your objects and draw them - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it++; - LCDUIASSERT(NULL != pObject); - - if (pObject->IsVisible()) - { - // create the clip region - // Note that pages can now be added to pages (GetOrigin of the page is now factored in) - HRGN hRgn = CreateRectRgn(GetOrigin().x + pObject->GetOrigin().x, GetOrigin().y + pObject->GetOrigin().y, - GetOrigin().x + pObject->GetOrigin().x + pObject->GetWidth(), - GetOrigin().y + pObject->GetOrigin().y + pObject->GetHeight()); - - // ensure that controls only draw within their specified region - SelectClipRgn(rGfx.GetHDC(), hRgn); - - // free the region (a copy is used in the call above) - DeleteObject(hRgn); - - // offset the control at its origin so controls use (0,0) - POINT ptPrevViewportOrg = { 0, 0 }; - SetViewportOrgEx(rGfx.GetHDC(), - GetOrigin().x + pObject->GetOrigin().x, - GetOrigin().y + pObject->GetOrigin().y, - &ptPrevViewportOrg); - - // allow controls to supply additional translation - // this allows controls to move freely within the confined viewport - OffsetViewportOrgEx(rGfx.GetHDC(), - pObject->GetLogicalOrigin().x, - pObject->GetLogicalOrigin().y, - NULL); - - pObject->OnDraw(rGfx); - - // set the clipping region to nothing - SelectClipRgn(rGfx.GetHDC(), NULL); - - // restore the viewport origin - SetViewportOrgEx(rGfx.GetHDC(), - ptPrevViewportOrg.x, - ptPrevViewportOrg.y, - NULL); - - // restore the viewport origin offset - OffsetViewportOrgEx(rGfx.GetHDC(), 0, 0, NULL); - } - } -} - - -//************************************************************************ -// -// CLCDPage::OnUpdate -// -//************************************************************************ - -void CLCDPage::OnUpdate(DWORD dwTimestamp) -{ - m_dwEllapsedTime = (dwTimestamp - m_dwStartTime); - - CLCDCollection::OnUpdate(dwTimestamp); -} - - -//************************************************************************ -// -// CLCDPage::OnLCDButtonDown -// -//************************************************************************ - -void CLCDPage::OnLCDButtonDown(int nButton) -{ - UNREFERENCED_PARAMETER(nButton); -} - - -//************************************************************************ -// -// CLCDPage::OnLCDButtonUp -// -//************************************************************************ - -void CLCDPage::OnLCDButtonUp(int nButton) -{ - UNREFERENCED_PARAMETER(nButton); -} - - -//************************************************************************ -// -// CLCDPage::SetExpiration -// -//************************************************************************ - -void CLCDPage::SetExpiration(DWORD dwMilliseconds) -{ - m_dwStartTime = GetTickCount(); - m_dwEllapsedTime = 0; - m_dwExpirationTime = dwMilliseconds; -} - - -//************************************************************************ -// -// CLCDPage::HasExpired -// -//************************************************************************ - -BOOL CLCDPage::HasExpired(void) -{ - return (!m_dwStartTime || !m_dwExpirationTime || (m_dwEllapsedTime >= m_dwExpirationTime)); -} - - -//************************************************************************ -// -// CLCDPage::SetBackground (using a bitmap) -// -//************************************************************************ - -void CLCDPage::SetBackground(HBITMAP hBitmap) -{ - m_Background.SetBitmap(hBitmap); - m_Background.SetSize(320, 240); - m_bUseBitmapBackground = TRUE; - m_bUseColorBackground = FALSE; -} - - -//************************************************************************ -// -// CLCDPage::SetBackground (using a color) -// -//************************************************************************ - -void CLCDPage::SetBackground(COLORREF Color) -{ - m_BackgroundColor = Color; - m_bUseColorBackground = TRUE; - m_bUseBitmapBackground = FALSE; -} - -//** end of LCDPage.cpp ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPage.cpp +// +// Collection of items representing a page. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDPage::CLCDPage +// +//************************************************************************ + +CLCDPage::CLCDPage(void) +: m_dwStartTime(0), + m_dwEllapsedTime(0), + m_dwExpirationTime(0) +{ + SetExpiration(INFINITE); + m_bUseBitmapBackground = FALSE; + m_bUseColorBackground = FALSE; +} + + +//************************************************************************ +// +// CLCDPage::~CLCDPage +// +//************************************************************************ + +CLCDPage::~CLCDPage(void) +{ +} + + +//************************************************************************ +// +// CLCDPage::OnDraw +// +//************************************************************************ + +void CLCDPage::OnDraw(CLCDGfxBase &rGfx) +{ + if(!IsVisible()) + { + return; + } + + //Draw the background first + if(m_bUseBitmapBackground) + { + m_Background.OnDraw(rGfx); + } + else if(m_bUseColorBackground) + { + HBRUSH hBackBrush = CreateSolidBrush(m_BackgroundColor); + HBRUSH hOldBrush = (HBRUSH)SelectObject(rGfx.GetHDC(), hBackBrush); + Rectangle(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight()); + SelectObject(rGfx.GetHDC(), hOldBrush); + DeleteObject(hBackBrush); + } + + + //iterate through your objects and draw them + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it++; + LCDUIASSERT(NULL != pObject); + + if (pObject->IsVisible()) + { + // create the clip region + // Note that pages can now be added to pages (GetOrigin of the page is now factored in) + HRGN hRgn = CreateRectRgn(GetOrigin().x + pObject->GetOrigin().x, GetOrigin().y + pObject->GetOrigin().y, + GetOrigin().x + pObject->GetOrigin().x + pObject->GetWidth(), + GetOrigin().y + pObject->GetOrigin().y + pObject->GetHeight()); + + // ensure that controls only draw within their specified region + SelectClipRgn(rGfx.GetHDC(), hRgn); + + // free the region (a copy is used in the call above) + DeleteObject(hRgn); + + // offset the control at its origin so controls use (0,0) + POINT ptPrevViewportOrg = { 0, 0 }; + SetViewportOrgEx(rGfx.GetHDC(), + GetOrigin().x + pObject->GetOrigin().x, + GetOrigin().y + pObject->GetOrigin().y, + &ptPrevViewportOrg); + + // allow controls to supply additional translation + // this allows controls to move freely within the confined viewport + OffsetViewportOrgEx(rGfx.GetHDC(), + pObject->GetLogicalOrigin().x, + pObject->GetLogicalOrigin().y, + NULL); + + pObject->OnDraw(rGfx); + + // set the clipping region to nothing + SelectClipRgn(rGfx.GetHDC(), NULL); + + // restore the viewport origin + SetViewportOrgEx(rGfx.GetHDC(), + ptPrevViewportOrg.x, + ptPrevViewportOrg.y, + NULL); + + // restore the viewport origin offset + OffsetViewportOrgEx(rGfx.GetHDC(), 0, 0, NULL); + } + } +} + + +//************************************************************************ +// +// CLCDPage::OnUpdate +// +//************************************************************************ + +void CLCDPage::OnUpdate(DWORD dwTimestamp) +{ + m_dwEllapsedTime = (dwTimestamp - m_dwStartTime); + + CLCDCollection::OnUpdate(dwTimestamp); +} + + +//************************************************************************ +// +// CLCDPage::OnLCDButtonDown +// +//************************************************************************ + +void CLCDPage::OnLCDButtonDown(int nButton) +{ + UNREFERENCED_PARAMETER(nButton); +} + + +//************************************************************************ +// +// CLCDPage::OnLCDButtonUp +// +//************************************************************************ + +void CLCDPage::OnLCDButtonUp(int nButton) +{ + UNREFERENCED_PARAMETER(nButton); +} + + +//************************************************************************ +// +// CLCDPage::SetExpiration +// +//************************************************************************ + +void CLCDPage::SetExpiration(DWORD dwMilliseconds) +{ + m_dwStartTime = GetTickCount(); + m_dwEllapsedTime = 0; + m_dwExpirationTime = dwMilliseconds; +} + + +//************************************************************************ +// +// CLCDPage::HasExpired +// +//************************************************************************ + +BOOL CLCDPage::HasExpired(void) +{ + return (!m_dwStartTime || !m_dwExpirationTime || (m_dwEllapsedTime >= m_dwExpirationTime)); +} + + +//************************************************************************ +// +// CLCDPage::SetBackground (using a bitmap) +// +//************************************************************************ + +void CLCDPage::SetBackground(HBITMAP hBitmap) +{ + m_Background.SetBitmap(hBitmap); + m_Background.SetSize(320, 240); + m_bUseBitmapBackground = TRUE; + m_bUseColorBackground = FALSE; +} + + +//************************************************************************ +// +// CLCDPage::SetBackground (using a color) +// +//************************************************************************ + +void CLCDPage::SetBackground(COLORREF Color) +{ + m_BackgroundColor = Color; + m_bUseColorBackground = TRUE; + m_bUseBitmapBackground = FALSE; +} + +//** end of LCDPage.cpp ************************************************** diff --git a/src/thirdparty/LCDUI/LCDPage.h b/src/thirdparty/LCDUI/LCDPage.h index 522b52ebed2..945394d6a31 100644 --- a/src/thirdparty/LCDUI/LCDPage.h +++ b/src/thirdparty/LCDUI/LCDPage.h @@ -1,58 +1,58 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPage.h -// -// Collection of items representing a page. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDPAGE_H_INCLUDED_ -#define _LCDPAGE_H_INCLUDED_ - -#include "LCDCollection.h" -#include "LCDBitmap.h" - -class CLCDPage : public CLCDCollection -{ -public: - CLCDPage(void); - virtual ~CLCDPage(void); - - virtual void SetExpiration(DWORD dwMilliseconds); - virtual BOOL HasExpired(void); - virtual void OnLCDButtonDown(int nButton); - virtual void OnLCDButtonUp(int nButton); - - // CLCDCollection - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void OnUpdate(DWORD dwTimestamp); - - void SetBackground(HBITMAP hBitmap); - void SetBackground(COLORREF Color); - -private: - DWORD m_dwStartTime; - DWORD m_dwEllapsedTime; - DWORD m_dwExpirationTime; - - //Background data - BOOL m_bUseBitmapBackground; - CLCDBitmap m_Background; - BOOL m_bUseColorBackground; - COLORREF m_BackgroundColor; -}; - -#endif - -//** end of LCDPage.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPage.h +// +// Collection of items representing a page. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDPAGE_H_INCLUDED_ +#define _LCDPAGE_H_INCLUDED_ + +#include "LCDCollection.h" +#include "LCDBitmap.h" + +class CLCDPage : public CLCDCollection +{ +public: + CLCDPage(void); + virtual ~CLCDPage(void); + + virtual void SetExpiration(DWORD dwMilliseconds); + virtual BOOL HasExpired(void); + virtual void OnLCDButtonDown(int nButton); + virtual void OnLCDButtonUp(int nButton); + + // CLCDCollection + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void OnUpdate(DWORD dwTimestamp); + + void SetBackground(HBITMAP hBitmap); + void SetBackground(COLORREF Color); + +private: + DWORD m_dwStartTime; + DWORD m_dwEllapsedTime; + DWORD m_dwExpirationTime; + + //Background data + BOOL m_bUseBitmapBackground; + CLCDBitmap m_Background; + BOOL m_bUseColorBackground; + COLORREF m_BackgroundColor; +}; + +#endif + +//** end of LCDPage.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDPaginateText.cpp b/src/thirdparty/LCDUI/LCDPaginateText.cpp index a9ff4e9aa80..1d986390196 100644 --- a/src/thirdparty/LCDUI/LCDPaginateText.cpp +++ b/src/thirdparty/LCDUI/LCDPaginateText.cpp @@ -1,274 +1,274 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPaginateText.h -// -// The CLCDPaginateText class draws text onto the LCD in pages. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDPaginateText::CLCDPaginateText -// -//************************************************************************ - -CLCDPaginateText::CLCDPaginateText(void) -: m_linePerPage(0), - m_totalPageNum(0), - m_iCurPageNum(0) -{ - ZeroMemory(&m_origSize, sizeof(m_origSize)); -} - - -//************************************************************************ -// -// CLCDPaginateText::~CLCDPaginateText -// -//************************************************************************ - -CLCDPaginateText::~CLCDPaginateText(void) -{ -} - - -//************************************************************************ -// -// CLCDPaginateText::SetSize -// -//************************************************************************ - -void CLCDPaginateText::SetSize(SIZE& size) -{ - CLCDBase::SetSize(size); - m_origSize = size; - m_bRecalcExtent = true; -} - - -//************************************************************************ -// -// CLCDPaginateText::SetSize -// -//************************************************************************ - -void CLCDPaginateText::SetSize(int nCX, int nCY) -{ - CLCDBase::SetSize(nCX, nCY); - m_origSize = m_Size; - m_bRecalcExtent = true; -} - - -//************************************************************************ -// -// CLCDPaginateText::DoPaginate -// -// Force the re-pagination, will set the first page to be the current page -// -//************************************************************************ - -void CLCDPaginateText::DoPaginate(void) -{ - // if m_bRecalcExtent is false, nothing affects pagination changes, don't do anything - if(!m_bRecalcExtent) - { - return; - } - // if the page size is 0, set current page, total number of page, and line of text per page as 0 - if(m_origSize.cx == 0 || m_origSize.cy == 0) - { - m_iCurPageNum = 0; - m_totalPageNum = 0; - m_linePerPage = 0; - } - else - { - HDC hdc = CreateCompatibleDC(NULL); - - int nOldMapMode = SetMapMode(hdc, MM_TEXT); - int nOldBkMode = SetBkMode(hdc, GetBackgroundMode()); - // select current font - HFONT hOldFont = (HFONT)SelectObject(hdc, m_hFont); - - RECT rExtent; - - // calculate horizontal extent w/ single line, we can get the line height - int nTextFormat = (m_nTextFormat | DT_SINGLELINE | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = m_origSize.cx; - rExtent.bottom = m_origSize.cy; - DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeHExtent.cx = rExtent.right; - m_sizeHExtent.cy = rExtent.bottom; - - // calculate vertical extent with word wrap - nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = m_origSize.cx; - rExtent.bottom = m_origSize.cy; - DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeVExtent.cx = rExtent.right; - m_sizeVExtent.cy = rExtent.bottom; - - CLCDText::SetLogicalSize(m_sizeVExtent.cx, m_sizeVExtent.cy); - - // restores - SetMapMode(hdc, nOldMapMode); - SetBkMode(hdc, nOldBkMode); - SelectObject(hdc, hOldFont); - - DeleteDC(hdc); - - m_linePerPage = (int)(m_origSize.cy / m_sizeHExtent.cy); - // we re-set the m_Size.cy to show m_linePerPage line of text exactly (no clipping text) - m_Size.cy = m_linePerPage * m_sizeHExtent.cy; - - // if the control size is too small to fit one line of text, the m_Size.cy is set to 0, - // and we also set total number of pages to be 0 - if(m_Size.cy == 0) - { - m_iCurPageNum = 0; - m_totalPageNum = 0; - m_linePerPage = 0; - } - else - { - m_totalPageNum = (int)(m_sizeVExtent.cy / m_Size.cy); - m_totalPageNum += ((m_sizeVExtent.cy % m_Size.cy) > 0) ? 1 : 0; - - m_totalPageNum = (m_totalPageNum > 0) ? m_totalPageNum : 1; - - // after paginate, always set first page to be the current page - m_iCurPageNum = 0; - } - } - // set m_bRecalcExtent to be false to avoid another calculation at Draw time - m_bRecalcExtent = false; - SetLogicalOrigin(0, (int)((-1) * m_iCurPageNum * m_Size.cy)); -} - - -//************************************************************************ -// -// CLCDPaginateText::GetTotalPages -// -//************************************************************************ - -int CLCDPaginateText::GetTotalPages(void) -{ - DoPaginate(); - return m_totalPageNum; -} - - -//************************************************************************ -// -// CLCDPaginateText::SetCurPage -// -//************************************************************************ - -void CLCDPaginateText::SetCurPage(int iPageNum) -{ - DoPaginate(); - - if(iPageNum > m_totalPageNum - 1) - { - iPageNum = m_totalPageNum - 1; - } - if(iPageNum < 0) - { - iPageNum = 0; - } - - m_iCurPageNum = iPageNum; - - SetLogicalOrigin(0, (int)((-1) * m_iCurPageNum * m_Size.cy)); -} - - -//************************************************************************ -// -// CLCDPaginateText::GetCurPage -// -//************************************************************************ - -int CLCDPaginateText::GetCurPage(void) -{ - DoPaginate(); - return m_iCurPageNum; -} - - -//************************************************************************ -// -// CLCDPaginateText::GotoPrevPage -// -// Go to previous page, return false if it is already at the first page. -// Otherwise, return true; -// -//************************************************************************ - -bool CLCDPaginateText::GotoPrevPage(void) -{ - DoPaginate(); - if(m_iCurPageNum > 0) - { - SetCurPage(--m_iCurPageNum); - return true; - } - - return false; -} - - -//************************************************************************ -// -// CLCDPaginateText::GotoNextPage -// -// Go to next page, return false if it is already at the last page. -// Otherwise, return true; -// -//************************************************************************ - -bool CLCDPaginateText::GotoNextPage(void) -{ - DoPaginate(); - if(m_iCurPageNum < m_totalPageNum -1) - { - SetCurPage(++m_iCurPageNum); - return true; - } - - return false; -} - -//************************************************************************ -// -// CLCDPaginateText::OnDraw -// -// Before drawing, make sure we have a updated pagination -// -//************************************************************************ - -void CLCDPaginateText::OnDraw(CLCDGfxBase &rGfx) -{ - DoPaginate(); - CLCDText::OnDraw(rGfx); -} - -//** end of LCDPaginateText.cpp ****************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPaginateText.h +// +// The CLCDPaginateText class draws text onto the LCD in pages. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDPaginateText::CLCDPaginateText +// +//************************************************************************ + +CLCDPaginateText::CLCDPaginateText(void) +: m_linePerPage(0), + m_totalPageNum(0), + m_iCurPageNum(0) +{ + ZeroMemory(&m_origSize, sizeof(m_origSize)); +} + + +//************************************************************************ +// +// CLCDPaginateText::~CLCDPaginateText +// +//************************************************************************ + +CLCDPaginateText::~CLCDPaginateText(void) +{ +} + + +//************************************************************************ +// +// CLCDPaginateText::SetSize +// +//************************************************************************ + +void CLCDPaginateText::SetSize(SIZE& size) +{ + CLCDBase::SetSize(size); + m_origSize = size; + m_bRecalcExtent = true; +} + + +//************************************************************************ +// +// CLCDPaginateText::SetSize +// +//************************************************************************ + +void CLCDPaginateText::SetSize(int nCX, int nCY) +{ + CLCDBase::SetSize(nCX, nCY); + m_origSize = m_Size; + m_bRecalcExtent = true; +} + + +//************************************************************************ +// +// CLCDPaginateText::DoPaginate +// +// Force the re-pagination, will set the first page to be the current page +// +//************************************************************************ + +void CLCDPaginateText::DoPaginate(void) +{ + // if m_bRecalcExtent is false, nothing affects pagination changes, don't do anything + if(!m_bRecalcExtent) + { + return; + } + // if the page size is 0, set current page, total number of page, and line of text per page as 0 + if(m_origSize.cx == 0 || m_origSize.cy == 0) + { + m_iCurPageNum = 0; + m_totalPageNum = 0; + m_linePerPage = 0; + } + else + { + HDC hdc = CreateCompatibleDC(NULL); + + int nOldMapMode = SetMapMode(hdc, MM_TEXT); + int nOldBkMode = SetBkMode(hdc, GetBackgroundMode()); + // select current font + HFONT hOldFont = (HFONT)SelectObject(hdc, m_hFont); + + RECT rExtent; + + // calculate horizontal extent w/ single line, we can get the line height + int nTextFormat = (m_nTextFormat | DT_SINGLELINE | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = m_origSize.cx; + rExtent.bottom = m_origSize.cy; + DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeHExtent.cx = rExtent.right; + m_sizeHExtent.cy = rExtent.bottom; + + // calculate vertical extent with word wrap + nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = m_origSize.cx; + rExtent.bottom = m_origSize.cy; + DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeVExtent.cx = rExtent.right; + m_sizeVExtent.cy = rExtent.bottom; + + CLCDText::SetLogicalSize(m_sizeVExtent.cx, m_sizeVExtent.cy); + + // restores + SetMapMode(hdc, nOldMapMode); + SetBkMode(hdc, nOldBkMode); + SelectObject(hdc, hOldFont); + + DeleteDC(hdc); + + m_linePerPage = (int)(m_origSize.cy / m_sizeHExtent.cy); + // we re-set the m_Size.cy to show m_linePerPage line of text exactly (no clipping text) + m_Size.cy = m_linePerPage * m_sizeHExtent.cy; + + // if the control size is too small to fit one line of text, the m_Size.cy is set to 0, + // and we also set total number of pages to be 0 + if(m_Size.cy == 0) + { + m_iCurPageNum = 0; + m_totalPageNum = 0; + m_linePerPage = 0; + } + else + { + m_totalPageNum = (int)(m_sizeVExtent.cy / m_Size.cy); + m_totalPageNum += ((m_sizeVExtent.cy % m_Size.cy) > 0) ? 1 : 0; + + m_totalPageNum = (m_totalPageNum > 0) ? m_totalPageNum : 1; + + // after paginate, always set first page to be the current page + m_iCurPageNum = 0; + } + } + // set m_bRecalcExtent to be false to avoid another calculation at Draw time + m_bRecalcExtent = false; + SetLogicalOrigin(0, (int)((-1) * m_iCurPageNum * m_Size.cy)); +} + + +//************************************************************************ +// +// CLCDPaginateText::GetTotalPages +// +//************************************************************************ + +int CLCDPaginateText::GetTotalPages(void) +{ + DoPaginate(); + return m_totalPageNum; +} + + +//************************************************************************ +// +// CLCDPaginateText::SetCurPage +// +//************************************************************************ + +void CLCDPaginateText::SetCurPage(int iPageNum) +{ + DoPaginate(); + + if(iPageNum > m_totalPageNum - 1) + { + iPageNum = m_totalPageNum - 1; + } + if(iPageNum < 0) + { + iPageNum = 0; + } + + m_iCurPageNum = iPageNum; + + SetLogicalOrigin(0, (int)((-1) * m_iCurPageNum * m_Size.cy)); +} + + +//************************************************************************ +// +// CLCDPaginateText::GetCurPage +// +//************************************************************************ + +int CLCDPaginateText::GetCurPage(void) +{ + DoPaginate(); + return m_iCurPageNum; +} + + +//************************************************************************ +// +// CLCDPaginateText::GotoPrevPage +// +// Go to previous page, return false if it is already at the first page. +// Otherwise, return true; +// +//************************************************************************ + +bool CLCDPaginateText::GotoPrevPage(void) +{ + DoPaginate(); + if(m_iCurPageNum > 0) + { + SetCurPage(--m_iCurPageNum); + return true; + } + + return false; +} + + +//************************************************************************ +// +// CLCDPaginateText::GotoNextPage +// +// Go to next page, return false if it is already at the last page. +// Otherwise, return true; +// +//************************************************************************ + +bool CLCDPaginateText::GotoNextPage(void) +{ + DoPaginate(); + if(m_iCurPageNum < m_totalPageNum -1) + { + SetCurPage(++m_iCurPageNum); + return true; + } + + return false; +} + +//************************************************************************ +// +// CLCDPaginateText::OnDraw +// +// Before drawing, make sure we have a updated pagination +// +//************************************************************************ + +void CLCDPaginateText::OnDraw(CLCDGfxBase &rGfx) +{ + DoPaginate(); + CLCDText::OnDraw(rGfx); +} + +//** end of LCDPaginateText.cpp ****************************************** diff --git a/src/thirdparty/LCDUI/LCDPaginateText.h b/src/thirdparty/LCDUI/LCDPaginateText.h index e9fda5e49cb..ddea114e10d 100644 --- a/src/thirdparty/LCDUI/LCDPaginateText.h +++ b/src/thirdparty/LCDUI/LCDPaginateText.h @@ -1,63 +1,63 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPaginateText.h -// -// The CLCDPaginateText class draws text onto the LCD in pages. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDPAGINATETEXT_H_INCLUDED_ -#define _LCDPAGINATETEXT_H_INCLUDED_ - -#include "LCDText.h" - -class CLCDPaginateText: public CLCDText -{ - -public: - CLCDPaginateText(void); - virtual ~CLCDPaginateText(void); - - // CLCDText - virtual void SetSize(SIZE& size); - virtual void SetSize(int nCX, int nCY); - virtual void OnDraw(CLCDGfxBase &rGfx); - - // force the re-pagination, will set the first page to be the current page - void DoPaginate(void); - int GetTotalPages(void); - int GetCurPage(void); - void SetCurPage(int iPageNum); - // go to previous page, return false if it is already at the first page. Otherwise, return true; - bool GotoPrevPage(void); - // go to next page, return false if it is already at the last page. Otherwise, return true; - bool GotoNextPage(void); - -private: - // this is the original size for the control. As we try to squeeze text into - // the rectangle, we squeeze the m_Size to show unclipped text. but if the - // user change settings where a recalc is needed to figure out the total page, - // we need the original size for that calculation - SIZE m_origSize; - - // using the current setting, number of lines fit to one page (w/o clipping) - int m_linePerPage; - int m_totalPageNum; - int m_iCurPageNum; -}; - - -#endif // !_LCDPAGINATETEXT_H_INCLUDED_ - -//** end of LCDPaginateText.h ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPaginateText.h +// +// The CLCDPaginateText class draws text onto the LCD in pages. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDPAGINATETEXT_H_INCLUDED_ +#define _LCDPAGINATETEXT_H_INCLUDED_ + +#include "LCDText.h" + +class CLCDPaginateText: public CLCDText +{ + +public: + CLCDPaginateText(void); + virtual ~CLCDPaginateText(void); + + // CLCDText + virtual void SetSize(SIZE& size); + virtual void SetSize(int nCX, int nCY); + virtual void OnDraw(CLCDGfxBase &rGfx); + + // force the re-pagination, will set the first page to be the current page + void DoPaginate(void); + int GetTotalPages(void); + int GetCurPage(void); + void SetCurPage(int iPageNum); + // go to previous page, return false if it is already at the first page. Otherwise, return true; + bool GotoPrevPage(void); + // go to next page, return false if it is already at the last page. Otherwise, return true; + bool GotoNextPage(void); + +private: + // this is the original size for the control. As we try to squeeze text into + // the rectangle, we squeeze the m_Size to show unclipped text. but if the + // user change settings where a recalc is needed to figure out the total page, + // we need the original size for that calculation + SIZE m_origSize; + + // using the current setting, number of lines fit to one page (w/o clipping) + int m_linePerPage; + int m_totalPageNum; + int m_iCurPageNum; +}; + + +#endif // !_LCDPAGINATETEXT_H_INCLUDED_ + +//** end of LCDPaginateText.h ******************************************* diff --git a/src/thirdparty/LCDUI/LCDPopup.cpp b/src/thirdparty/LCDUI/LCDPopup.cpp index 23d89871060..e31cae2bc4c 100644 --- a/src/thirdparty/LCDUI/LCDPopup.cpp +++ b/src/thirdparty/LCDUI/LCDPopup.cpp @@ -1,556 +1,556 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPopup.cpp -// -// Color LCD Popup class -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" -#include "LCDPopup.h" - -// This uses GDI+ -using namespace Gdiplus; - - -//************************************************************************ -// -// CLCDPopupBackground::CLCDPopupBackground -// -//************************************************************************ - -CLCDPopupBackground::CLCDPopupBackground(void) -{ - m_bUseGradient = FALSE; - m_cAlphaStart = 0x9f; - m_cAlphaEnd = m_cAlphaStart/2; - m_cfColor = 0; - m_nRectRadius = 15; - m_pGraphicsPath = NULL; -} - - -//************************************************************************ -// -// CLCDPopupBackground::~CLCDPopupBackground -// -//************************************************************************ - -CLCDPopupBackground::~CLCDPopupBackground(void) -{ - if (m_pGraphicsPath) - { - delete m_pGraphicsPath; - m_pGraphicsPath = NULL; - } -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetSize -// -//************************************************************************ - -void CLCDPopupBackground::SetSize(int nCX, int nCY) -{ - CLCDBase::SetSize(nCX, nCY); - RecalcRoundedRectangle(); -} - - -//************************************************************************ -// -// CLCDPopupBackground::OnDraw -// -//************************************************************************ - -void CLCDPopupBackground::OnDraw(CLCDGfxBase &rGfx) -{ - if (NULL == m_pGraphicsPath) - { - // Size has not been set - return; - } - - // Draw to the extent of the control - Rect r(0, 0, GetWidth(), GetHeight()); - - Graphics gfx(rGfx.GetHDC()); - - if (m_bUseGradient) - { - LinearGradientBrush brush( - r, - Color(Color::MakeARGB(m_cAlphaStart, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))), - Color(Color::MakeARGB(m_cAlphaEnd, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))), - LinearGradientModeVertical - ); // blue - gfx.FillPath(&brush, m_pGraphicsPath); - } - else - { - SolidBrush brush(Color::MakeARGB(m_cAlphaStart, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))); - gfx.FillPath(&brush, m_pGraphicsPath); - } -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetAlphaLevel -// -//************************************************************************ - -void CLCDPopupBackground::SetAlphaLevel(BYTE cAlphaStart, BYTE cAlphaEnd) -{ - m_cAlphaStart = cAlphaStart; - m_cAlphaEnd = cAlphaEnd; -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetGradientMode -// -//************************************************************************ - -void CLCDPopupBackground::SetGradientMode(BOOL bGradient) -{ - m_bUseGradient = bGradient; -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetColor -// -//************************************************************************ - -void CLCDPopupBackground::SetColor(COLORREF cfColor) -{ - m_cfColor = cfColor; -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetRoundedRecteRadius -// -//************************************************************************ - -void CLCDPopupBackground::SetRoundedRecteRadius(int nRadius) -{ - m_nRectRadius = nRadius; - RecalcRoundedRectangle(); -} - - -//************************************************************************ -// -// CLCDPopupBackground::RecalcRoundedRectangle -// -//************************************************************************ - -void CLCDPopupBackground::RecalcRoundedRectangle(void) -{ - if (m_pGraphicsPath) - { - delete m_pGraphicsPath; - m_pGraphicsPath = NULL; - } - - m_pGraphicsPath = new GraphicsPath(); - int l = 0; - int t = 0; - int w = GetWidth(); - int h = GetHeight(); - int d = m_nRectRadius << 1; - m_pGraphicsPath->AddArc(l, t, d, d, 180, 90); - m_pGraphicsPath->AddLine(l + m_nRectRadius, t, l + w - m_nRectRadius, t); - m_pGraphicsPath->AddArc(l + w - d, t, d, d, 270, 90); - m_pGraphicsPath->AddLine(l + w, t + m_nRectRadius, l + w, t + h - m_nRectRadius); - m_pGraphicsPath->AddArc(l + w - d, t + h - d, d, d, 0, 90); - m_pGraphicsPath->AddLine(l + w - m_nRectRadius, t + h, l + m_nRectRadius, t + h); - m_pGraphicsPath->AddArc(l, t + h - d, d, d, 90, 90); - m_pGraphicsPath->AddLine(l, t + h - m_nRectRadius, l, t + m_nRectRadius); - m_pGraphicsPath->CloseFigure(); -} - - - - - - -// Define the maximum popup width as 1/2 of the QVGA width -#define MAX_POPUP_WIDTH (LGLCD_QVGA_BMP_WIDTH / 2) -#define POPUP_MARGIN (12) -#define POPUP_FONT_PT (12) -#define POPUP_FONT_WT FW_BOLD -#define POPUP_FONT_FACE _T("Arial") - -//************************************************************************ -// -// CLCDPopup::CLCDPopup -// -//************************************************************************ - -CLCDPopup::CLCDPopup(void) -{ - m_nMaxPopupWidth = MAX_POPUP_WIDTH; - m_pbType = PB_TEXT; -} - - -//************************************************************************ -// -// CLCDPopup::Initialize -// -//************************************************************************ - -HRESULT CLCDPopup::Initialize(int nMaxPopupWidth /* = 0 */) -{ - if(0 == nMaxPopupWidth) - { - m_nMaxPopupWidth = MAX_POPUP_WIDTH; - } - else - { - m_nMaxPopupWidth = nMaxPopupWidth; - } - // The text gets offset by the margin - m_Background.Initialize(); - m_Background.SetOrigin(0, 0); - - m_MessageText.SetOrigin(POPUP_MARGIN, POPUP_MARGIN); - m_MessageText.SetFontFaceName(POPUP_FONT_FACE); - m_MessageText.SetFontPointSize(POPUP_FONT_PT); - m_MessageText.SetFontWeight(POPUP_FONT_WT); - m_MessageText.SetWordWrap(TRUE); - m_MessageText.SetSize(LGLCD_QVGA_BMP_WIDTH, LGLCD_QVGA_BMP_HEIGHT); - - m_OKText.SetFontFaceName(_T("Arial")); - m_OKText.SetFontPointSize(10); - m_OKText.SetFontWeight(FW_NORMAL); - m_OKText.SetWordWrap(TRUE); - m_OKText.Show(FALSE); - - m_CancelText.SetFontFaceName(_T("Arial")); - m_CancelText.SetFontPointSize(10); - m_CancelText.SetFontWeight(FW_NORMAL); - m_CancelText.SetWordWrap(TRUE); - m_CancelText.Show(FALSE); - - AddObject(&m_Background); - AddObject(&m_MessageText); - AddObject(&m_OKBitmap); - AddObject(&m_CancelBitmap); - AddObject(&m_OKText); - AddObject(&m_CancelText); - - return CLCDBase::Initialize(); -} - - -//************************************************************************ -// -// CLCDPopup::SetPopupType -// -//************************************************************************ - -void CLCDPopup::SetPopupType(PB_TYPE pbType) -{ - m_pbType = pbType; - RecalcLayout(); -} - - -//************************************************************************ -// -// CLCDPopup::SetText -// -//************************************************************************ - -void CLCDPopup::SetText(LPCTSTR szMessage, LPCTSTR szOK, LPCTSTR szCancel) -{ - if (NULL != szMessage) - { - m_MessageText.SetText(szMessage); - } - if (NULL != szOK) - { - m_OKText.SetText(szOK); - } - if (NULL != szCancel) - { - m_CancelText.SetText(szCancel); - } - - RecalcLayout(); -} - - -//************************************************************************ -// -// CLCDPopup::SetSize -// -//************************************************************************ - -void CLCDPopup::SetSize(int nCX, int nCY) -{ - CLCDPage::SetSize(nCX, nCY); -} - - -//************************************************************************ -// -// CLCDPopup::RecalcLayout -// -//************************************************************************ - -void CLCDPopup::RecalcLayout(void) -{ - // First get the size of the text - // If the width > MAX_WIDTH, snap it to the max width - int nTextWidthWithMargin = 2 * POPUP_MARGIN; - int nTextHeightWithMargin = 2 * POPUP_MARGIN; - if(0 < _tcslen(m_MessageText.GetText())) - { - m_MessageText.CalculateExtent(FALSE); - nTextWidthWithMargin = m_MessageText.GetVExtent().cx + 2*POPUP_MARGIN; - nTextHeightWithMargin = m_MessageText.GetVExtent().cy + 2*POPUP_MARGIN; - if(nTextWidthWithMargin > m_nMaxPopupWidth) - { - // Resize the text using a max height - m_MessageText.SetSize(m_nMaxPopupWidth, LGLCD_QVGA_BMP_HEIGHT); - m_MessageText.CalculateExtent(FALSE); - nTextWidthWithMargin = m_MessageText.GetVExtent().cx + 2*POPUP_MARGIN; - nTextHeightWithMargin = m_MessageText.GetVExtent().cy + 2*POPUP_MARGIN; - } - m_MessageText.SetSize(m_MessageText.GetVExtent().cx, m_MessageText.GetVExtent().cy); - } - else - { - nTextHeightWithMargin = POPUP_MARGIN; - nTextWidthWithMargin = 0; - m_MessageText.SetSize(0, 0); - } - - // Determine the size of the popup including.. - // Margin - // Text - // OK Bitmap - // Cancel Bitmap - int nPopupWidth = nTextWidthWithMargin; - int nPopupHeight = nTextHeightWithMargin; - - // Bitmap operations - BITMAP bmOK, bmCancel; - memset(&bmOK, 0, sizeof(bmOK)); - memset(&bmCancel, 0, sizeof(bmCancel)); - - if (NULL != m_OKBitmap.GetBitmap()) - { - GetObject( m_OKBitmap.GetBitmap(), sizeof(BITMAP), &bmOK); - m_OKBitmap.SetSize(bmOK.bmWidth, bmOK.bmHeight); - } - if (NULL != m_CancelBitmap.GetBitmap()) - { - GetObject( m_CancelBitmap.GetBitmap(), sizeof(BITMAP), &bmCancel); - m_CancelBitmap.SetSize(bmCancel.bmWidth, bmCancel.bmHeight); - } - - switch(m_pbType) - { - // Main text block only - case PB_TEXT: - m_OKBitmap.Show(FALSE); - m_CancelBitmap.Show(FALSE); - break; - - // OK is centered against the main text block - case PB_OK: - if (bmOK.bmWidth) - { - // Just factor in a bitmap - // Add the bitmap w/ margin on the bottom - nPopupHeight += bmOK.bmHeight; - nPopupHeight += POPUP_MARGIN; - - // Position the bitmap centered, and vertically after the text+margin - m_OKBitmap.SetOrigin((nPopupWidth-bmOK.bmWidth)/2, nTextHeightWithMargin); - - m_OKBitmap.Show(TRUE); - } - break; - - // OK, Cancel Buttons are aligned on the same row below the text block (like a dialog) - case PB_OKCANCEL: - if (bmOK.bmWidth && bmCancel.bmWidth) - { - // Add the bitmap w/ margin on the bottom - nPopupHeight += bmOK.bmHeight; - nPopupHeight += POPUP_MARGIN; - - // OK is right-aligned with the text - m_OKBitmap.SetOrigin(m_MessageText.GetOrigin().x + m_MessageText.GetSize().cx - bmOK.bmWidth, - nTextHeightWithMargin); - // Cancel is right-aligned with OK (with margin) - m_CancelBitmap.SetOrigin(m_OKBitmap.GetOrigin().x - bmCancel.bmWidth - POPUP_MARGIN, - nTextHeightWithMargin); - - m_OKBitmap.Show(TRUE); - m_CancelBitmap.Show(TRUE); - } - break; - - // OK, Cancel Buttons are on separate rows centered against their own text blocks - case PB_OKCANCEL_TEXT: - { - int nOKTextWithBitmapHeight = 0; - int nMaxOKTextWidth = 0; - m_OKText.SetOrigin(POPUP_MARGIN, nTextHeightWithMargin - POPUP_MARGIN); - - if (bmOK.bmWidth) - { - // OK is left-aligned with the text - m_OKBitmap.SetOrigin(m_MessageText.GetOrigin().x, nTextHeightWithMargin); - - // OK text height is left-aligned with OK bmp and right-aligned with text - // OK bmp is vertically centered against the OK text - nMaxOKTextWidth = m_MessageText.GetWidth() - bmOK.bmWidth - POPUP_MARGIN; - if (nMaxOKTextWidth < 0) - { - nMaxOKTextWidth = LGLCD_QVGA_BMP_WIDTH; - } - m_OKText.SetOrigin(m_OKBitmap.GetOrigin().x + bmOK.bmWidth + POPUP_MARGIN, nTextHeightWithMargin); - m_OKText.SetSize(nMaxOKTextWidth, LGLCD_QVGA_BMP_HEIGHT); - m_OKText.CalculateExtent(FALSE); - m_OKText.SetSize(m_OKText.GetVExtent().cx, m_OKText.GetVExtent().cy); - - // if no main text, figure out required max popup width - int nCalcPopupWidth = POPUP_MARGIN*3 + bmOK.bmWidth + m_OKText.GetSize().cx; - if (nCalcPopupWidth > nPopupWidth) - { - nPopupWidth = nCalcPopupWidth; - } - - // Add the bitmap w/ margin on the bottom - nOKTextWithBitmapHeight = max(bmOK.bmHeight, m_OKText.GetHeight()); - nPopupHeight += nOKTextWithBitmapHeight; - nPopupHeight += POPUP_MARGIN; - - m_OKText.Show(TRUE); - m_OKBitmap.Show(TRUE); - m_OKBitmap.SetOrigin(m_OKBitmap.GetOrigin().x, m_OKText.GetOrigin().y + (m_OKText.GetHeight() - bmOK.bmHeight)/2); - } - - if (bmCancel.bmWidth) - { - // Cancel is left-aligned with the text - m_CancelBitmap.SetOrigin(m_MessageText.GetOrigin().x, m_OKText.GetOrigin().y + nOKTextWithBitmapHeight + POPUP_MARGIN); - - int nMaxCancelTextWidth = m_MessageText.GetWidth() - bmCancel.bmWidth - POPUP_MARGIN; - if (nMaxCancelTextWidth < 0) - { - nMaxCancelTextWidth = LGLCD_QVGA_BMP_WIDTH; - } - m_CancelText.SetOrigin(m_CancelBitmap.GetOrigin().x + bmCancel.bmWidth + POPUP_MARGIN, m_CancelBitmap.GetOrigin().y); - m_CancelText.SetSize(nMaxCancelTextWidth, LGLCD_QVGA_BMP_HEIGHT); - m_CancelText.CalculateExtent(FALSE); - m_CancelText.SetSize(m_CancelText.GetVExtent().cx, m_CancelText.GetVExtent().cy); - - // if no main text, make the - int nCalcPopupWidth = POPUP_MARGIN*3 + bmOK.bmWidth + m_CancelText.GetSize().cx; - if (nCalcPopupWidth > nPopupWidth) - { - nPopupWidth = nCalcPopupWidth; - } - - nPopupHeight += max(bmCancel.bmHeight, m_CancelText.GetHeight()); - nPopupHeight += POPUP_MARGIN; - - // Vertically center the OK and CANCEL bitmaps against their respective texts - m_CancelText.Show(TRUE); - m_CancelBitmap.Show(TRUE); - m_CancelBitmap.SetOrigin(m_CancelBitmap.GetOrigin().x, m_CancelText.GetOrigin().y + (m_CancelText.GetHeight() - bmCancel.bmHeight)/2); - } - } - - break; - } - - // Resize ourself - SetSize(nPopupWidth, nPopupHeight); - - // Center the popup in the middle of the screen - SetOrigin( (LGLCD_QVGA_BMP_WIDTH - nPopupWidth)/2, (LGLCD_QVGA_BMP_HEIGHT - nPopupHeight)/2); - - // Resize the background - m_Background.SetSize(GetWidth(), GetHeight()); -} - - -//************************************************************************ -// -// CLCDPopup::SetBitmaps -// -//************************************************************************ - -void CLCDPopup::SetBitmaps(HBITMAP hbmOK, HBITMAP hbmCancel) -{ - m_OKBitmap.SetBitmap(hbmOK); - m_CancelBitmap.SetBitmap(hbmCancel); - - RecalcLayout(); -} - - -//************************************************************************ -// -// CLCDPopup::SetAlpha -// -//************************************************************************ - -void CLCDPopup::SetAlpha(BYTE bAlphaStart, BYTE bAlphaEnd) -{ - m_Background.SetAlphaLevel(bAlphaStart, bAlphaEnd); -} - - -//************************************************************************ -// -// CLCDPopup::SetGradientMode -// -//************************************************************************ - -void CLCDPopup::SetGradientMode(BOOL bGradient) -{ - m_Background.SetGradientMode(bGradient); -} - - -//************************************************************************ -// -// CLCDPopup::SetColor -// -//************************************************************************ - -void CLCDPopup::SetColor(COLORREF cfColor) -{ - m_Background.SetColor(cfColor); -} - - -//** end of LCDPopup.cpp ************************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPopup.cpp +// +// Color LCD Popup class +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" +#include "LCDPopup.h" + +// This uses GDI+ +using namespace Gdiplus; + + +//************************************************************************ +// +// CLCDPopupBackground::CLCDPopupBackground +// +//************************************************************************ + +CLCDPopupBackground::CLCDPopupBackground(void) +{ + m_bUseGradient = FALSE; + m_cAlphaStart = 0x9f; + m_cAlphaEnd = m_cAlphaStart/2; + m_cfColor = 0; + m_nRectRadius = 15; + m_pGraphicsPath = NULL; +} + + +//************************************************************************ +// +// CLCDPopupBackground::~CLCDPopupBackground +// +//************************************************************************ + +CLCDPopupBackground::~CLCDPopupBackground(void) +{ + if (m_pGraphicsPath) + { + delete m_pGraphicsPath; + m_pGraphicsPath = NULL; + } +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetSize +// +//************************************************************************ + +void CLCDPopupBackground::SetSize(int nCX, int nCY) +{ + CLCDBase::SetSize(nCX, nCY); + RecalcRoundedRectangle(); +} + + +//************************************************************************ +// +// CLCDPopupBackground::OnDraw +// +//************************************************************************ + +void CLCDPopupBackground::OnDraw(CLCDGfxBase &rGfx) +{ + if (NULL == m_pGraphicsPath) + { + // Size has not been set + return; + } + + // Draw to the extent of the control + Rect r(0, 0, GetWidth(), GetHeight()); + + Graphics gfx(rGfx.GetHDC()); + + if (m_bUseGradient) + { + LinearGradientBrush brush( + r, + Color(Color::MakeARGB(m_cAlphaStart, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))), + Color(Color::MakeARGB(m_cAlphaEnd, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))), + LinearGradientModeVertical + ); // blue + gfx.FillPath(&brush, m_pGraphicsPath); + } + else + { + SolidBrush brush(Color::MakeARGB(m_cAlphaStart, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))); + gfx.FillPath(&brush, m_pGraphicsPath); + } +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetAlphaLevel +// +//************************************************************************ + +void CLCDPopupBackground::SetAlphaLevel(BYTE cAlphaStart, BYTE cAlphaEnd) +{ + m_cAlphaStart = cAlphaStart; + m_cAlphaEnd = cAlphaEnd; +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetGradientMode +// +//************************************************************************ + +void CLCDPopupBackground::SetGradientMode(BOOL bGradient) +{ + m_bUseGradient = bGradient; +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetColor +// +//************************************************************************ + +void CLCDPopupBackground::SetColor(COLORREF cfColor) +{ + m_cfColor = cfColor; +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetRoundedRecteRadius +// +//************************************************************************ + +void CLCDPopupBackground::SetRoundedRecteRadius(int nRadius) +{ + m_nRectRadius = nRadius; + RecalcRoundedRectangle(); +} + + +//************************************************************************ +// +// CLCDPopupBackground::RecalcRoundedRectangle +// +//************************************************************************ + +void CLCDPopupBackground::RecalcRoundedRectangle(void) +{ + if (m_pGraphicsPath) + { + delete m_pGraphicsPath; + m_pGraphicsPath = NULL; + } + + m_pGraphicsPath = new GraphicsPath(); + int l = 0; + int t = 0; + int w = GetWidth(); + int h = GetHeight(); + int d = m_nRectRadius << 1; + m_pGraphicsPath->AddArc(l, t, d, d, 180, 90); + m_pGraphicsPath->AddLine(l + m_nRectRadius, t, l + w - m_nRectRadius, t); + m_pGraphicsPath->AddArc(l + w - d, t, d, d, 270, 90); + m_pGraphicsPath->AddLine(l + w, t + m_nRectRadius, l + w, t + h - m_nRectRadius); + m_pGraphicsPath->AddArc(l + w - d, t + h - d, d, d, 0, 90); + m_pGraphicsPath->AddLine(l + w - m_nRectRadius, t + h, l + m_nRectRadius, t + h); + m_pGraphicsPath->AddArc(l, t + h - d, d, d, 90, 90); + m_pGraphicsPath->AddLine(l, t + h - m_nRectRadius, l, t + m_nRectRadius); + m_pGraphicsPath->CloseFigure(); +} + + + + + + +// Define the maximum popup width as 1/2 of the QVGA width +#define MAX_POPUP_WIDTH (LGLCD_QVGA_BMP_WIDTH / 2) +#define POPUP_MARGIN (12) +#define POPUP_FONT_PT (12) +#define POPUP_FONT_WT FW_BOLD +#define POPUP_FONT_FACE _T("Arial") + +//************************************************************************ +// +// CLCDPopup::CLCDPopup +// +//************************************************************************ + +CLCDPopup::CLCDPopup(void) +{ + m_nMaxPopupWidth = MAX_POPUP_WIDTH; + m_pbType = PB_TEXT; +} + + +//************************************************************************ +// +// CLCDPopup::Initialize +// +//************************************************************************ + +HRESULT CLCDPopup::Initialize(int nMaxPopupWidth /* = 0 */) +{ + if(0 == nMaxPopupWidth) + { + m_nMaxPopupWidth = MAX_POPUP_WIDTH; + } + else + { + m_nMaxPopupWidth = nMaxPopupWidth; + } + // The text gets offset by the margin + m_Background.Initialize(); + m_Background.SetOrigin(0, 0); + + m_MessageText.SetOrigin(POPUP_MARGIN, POPUP_MARGIN); + m_MessageText.SetFontFaceName(POPUP_FONT_FACE); + m_MessageText.SetFontPointSize(POPUP_FONT_PT); + m_MessageText.SetFontWeight(POPUP_FONT_WT); + m_MessageText.SetWordWrap(TRUE); + m_MessageText.SetSize(LGLCD_QVGA_BMP_WIDTH, LGLCD_QVGA_BMP_HEIGHT); + + m_OKText.SetFontFaceName(_T("Arial")); + m_OKText.SetFontPointSize(10); + m_OKText.SetFontWeight(FW_NORMAL); + m_OKText.SetWordWrap(TRUE); + m_OKText.Show(FALSE); + + m_CancelText.SetFontFaceName(_T("Arial")); + m_CancelText.SetFontPointSize(10); + m_CancelText.SetFontWeight(FW_NORMAL); + m_CancelText.SetWordWrap(TRUE); + m_CancelText.Show(FALSE); + + AddObject(&m_Background); + AddObject(&m_MessageText); + AddObject(&m_OKBitmap); + AddObject(&m_CancelBitmap); + AddObject(&m_OKText); + AddObject(&m_CancelText); + + return CLCDBase::Initialize(); +} + + +//************************************************************************ +// +// CLCDPopup::SetPopupType +// +//************************************************************************ + +void CLCDPopup::SetPopupType(PB_TYPE pbType) +{ + m_pbType = pbType; + RecalcLayout(); +} + + +//************************************************************************ +// +// CLCDPopup::SetText +// +//************************************************************************ + +void CLCDPopup::SetText(LPCTSTR szMessage, LPCTSTR szOK, LPCTSTR szCancel) +{ + if (NULL != szMessage) + { + m_MessageText.SetText(szMessage); + } + if (NULL != szOK) + { + m_OKText.SetText(szOK); + } + if (NULL != szCancel) + { + m_CancelText.SetText(szCancel); + } + + RecalcLayout(); +} + + +//************************************************************************ +// +// CLCDPopup::SetSize +// +//************************************************************************ + +void CLCDPopup::SetSize(int nCX, int nCY) +{ + CLCDPage::SetSize(nCX, nCY); +} + + +//************************************************************************ +// +// CLCDPopup::RecalcLayout +// +//************************************************************************ + +void CLCDPopup::RecalcLayout(void) +{ + // First get the size of the text + // If the width > MAX_WIDTH, snap it to the max width + int nTextWidthWithMargin = 2 * POPUP_MARGIN; + int nTextHeightWithMargin = 2 * POPUP_MARGIN; + if(0 < _tcslen(m_MessageText.GetText())) + { + m_MessageText.CalculateExtent(FALSE); + nTextWidthWithMargin = m_MessageText.GetVExtent().cx + 2*POPUP_MARGIN; + nTextHeightWithMargin = m_MessageText.GetVExtent().cy + 2*POPUP_MARGIN; + if(nTextWidthWithMargin > m_nMaxPopupWidth) + { + // Resize the text using a max height + m_MessageText.SetSize(m_nMaxPopupWidth, LGLCD_QVGA_BMP_HEIGHT); + m_MessageText.CalculateExtent(FALSE); + nTextWidthWithMargin = m_MessageText.GetVExtent().cx + 2*POPUP_MARGIN; + nTextHeightWithMargin = m_MessageText.GetVExtent().cy + 2*POPUP_MARGIN; + } + m_MessageText.SetSize(m_MessageText.GetVExtent().cx, m_MessageText.GetVExtent().cy); + } + else + { + nTextHeightWithMargin = POPUP_MARGIN; + nTextWidthWithMargin = 0; + m_MessageText.SetSize(0, 0); + } + + // Determine the size of the popup including.. + // Margin + // Text + // OK Bitmap + // Cancel Bitmap + int nPopupWidth = nTextWidthWithMargin; + int nPopupHeight = nTextHeightWithMargin; + + // Bitmap operations + BITMAP bmOK, bmCancel; + memset(&bmOK, 0, sizeof(bmOK)); + memset(&bmCancel, 0, sizeof(bmCancel)); + + if (NULL != m_OKBitmap.GetBitmap()) + { + GetObject( m_OKBitmap.GetBitmap(), sizeof(BITMAP), &bmOK); + m_OKBitmap.SetSize(bmOK.bmWidth, bmOK.bmHeight); + } + if (NULL != m_CancelBitmap.GetBitmap()) + { + GetObject( m_CancelBitmap.GetBitmap(), sizeof(BITMAP), &bmCancel); + m_CancelBitmap.SetSize(bmCancel.bmWidth, bmCancel.bmHeight); + } + + switch(m_pbType) + { + // Main text block only + case PB_TEXT: + m_OKBitmap.Show(FALSE); + m_CancelBitmap.Show(FALSE); + break; + + // OK is centered against the main text block + case PB_OK: + if (bmOK.bmWidth) + { + // Just factor in a bitmap + // Add the bitmap w/ margin on the bottom + nPopupHeight += bmOK.bmHeight; + nPopupHeight += POPUP_MARGIN; + + // Position the bitmap centered, and vertically after the text+margin + m_OKBitmap.SetOrigin((nPopupWidth-bmOK.bmWidth)/2, nTextHeightWithMargin); + + m_OKBitmap.Show(TRUE); + } + break; + + // OK, Cancel Buttons are aligned on the same row below the text block (like a dialog) + case PB_OKCANCEL: + if (bmOK.bmWidth && bmCancel.bmWidth) + { + // Add the bitmap w/ margin on the bottom + nPopupHeight += bmOK.bmHeight; + nPopupHeight += POPUP_MARGIN; + + // OK is right-aligned with the text + m_OKBitmap.SetOrigin(m_MessageText.GetOrigin().x + m_MessageText.GetSize().cx - bmOK.bmWidth, + nTextHeightWithMargin); + // Cancel is right-aligned with OK (with margin) + m_CancelBitmap.SetOrigin(m_OKBitmap.GetOrigin().x - bmCancel.bmWidth - POPUP_MARGIN, + nTextHeightWithMargin); + + m_OKBitmap.Show(TRUE); + m_CancelBitmap.Show(TRUE); + } + break; + + // OK, Cancel Buttons are on separate rows centered against their own text blocks + case PB_OKCANCEL_TEXT: + { + int nOKTextWithBitmapHeight = 0; + int nMaxOKTextWidth = 0; + m_OKText.SetOrigin(POPUP_MARGIN, nTextHeightWithMargin - POPUP_MARGIN); + + if (bmOK.bmWidth) + { + // OK is left-aligned with the text + m_OKBitmap.SetOrigin(m_MessageText.GetOrigin().x, nTextHeightWithMargin); + + // OK text height is left-aligned with OK bmp and right-aligned with text + // OK bmp is vertically centered against the OK text + nMaxOKTextWidth = m_MessageText.GetWidth() - bmOK.bmWidth - POPUP_MARGIN; + if (nMaxOKTextWidth < 0) + { + nMaxOKTextWidth = LGLCD_QVGA_BMP_WIDTH; + } + m_OKText.SetOrigin(m_OKBitmap.GetOrigin().x + bmOK.bmWidth + POPUP_MARGIN, nTextHeightWithMargin); + m_OKText.SetSize(nMaxOKTextWidth, LGLCD_QVGA_BMP_HEIGHT); + m_OKText.CalculateExtent(FALSE); + m_OKText.SetSize(m_OKText.GetVExtent().cx, m_OKText.GetVExtent().cy); + + // if no main text, figure out required max popup width + int nCalcPopupWidth = POPUP_MARGIN*3 + bmOK.bmWidth + m_OKText.GetSize().cx; + if (nCalcPopupWidth > nPopupWidth) + { + nPopupWidth = nCalcPopupWidth; + } + + // Add the bitmap w/ margin on the bottom + nOKTextWithBitmapHeight = max(bmOK.bmHeight, m_OKText.GetHeight()); + nPopupHeight += nOKTextWithBitmapHeight; + nPopupHeight += POPUP_MARGIN; + + m_OKText.Show(TRUE); + m_OKBitmap.Show(TRUE); + m_OKBitmap.SetOrigin(m_OKBitmap.GetOrigin().x, m_OKText.GetOrigin().y + (m_OKText.GetHeight() - bmOK.bmHeight)/2); + } + + if (bmCancel.bmWidth) + { + // Cancel is left-aligned with the text + m_CancelBitmap.SetOrigin(m_MessageText.GetOrigin().x, m_OKText.GetOrigin().y + nOKTextWithBitmapHeight + POPUP_MARGIN); + + int nMaxCancelTextWidth = m_MessageText.GetWidth() - bmCancel.bmWidth - POPUP_MARGIN; + if (nMaxCancelTextWidth < 0) + { + nMaxCancelTextWidth = LGLCD_QVGA_BMP_WIDTH; + } + m_CancelText.SetOrigin(m_CancelBitmap.GetOrigin().x + bmCancel.bmWidth + POPUP_MARGIN, m_CancelBitmap.GetOrigin().y); + m_CancelText.SetSize(nMaxCancelTextWidth, LGLCD_QVGA_BMP_HEIGHT); + m_CancelText.CalculateExtent(FALSE); + m_CancelText.SetSize(m_CancelText.GetVExtent().cx, m_CancelText.GetVExtent().cy); + + // if no main text, make the + int nCalcPopupWidth = POPUP_MARGIN*3 + bmOK.bmWidth + m_CancelText.GetSize().cx; + if (nCalcPopupWidth > nPopupWidth) + { + nPopupWidth = nCalcPopupWidth; + } + + nPopupHeight += max(bmCancel.bmHeight, m_CancelText.GetHeight()); + nPopupHeight += POPUP_MARGIN; + + // Vertically center the OK and CANCEL bitmaps against their respective texts + m_CancelText.Show(TRUE); + m_CancelBitmap.Show(TRUE); + m_CancelBitmap.SetOrigin(m_CancelBitmap.GetOrigin().x, m_CancelText.GetOrigin().y + (m_CancelText.GetHeight() - bmCancel.bmHeight)/2); + } + } + + break; + } + + // Resize ourself + SetSize(nPopupWidth, nPopupHeight); + + // Center the popup in the middle of the screen + SetOrigin( (LGLCD_QVGA_BMP_WIDTH - nPopupWidth)/2, (LGLCD_QVGA_BMP_HEIGHT - nPopupHeight)/2); + + // Resize the background + m_Background.SetSize(GetWidth(), GetHeight()); +} + + +//************************************************************************ +// +// CLCDPopup::SetBitmaps +// +//************************************************************************ + +void CLCDPopup::SetBitmaps(HBITMAP hbmOK, HBITMAP hbmCancel) +{ + m_OKBitmap.SetBitmap(hbmOK); + m_CancelBitmap.SetBitmap(hbmCancel); + + RecalcLayout(); +} + + +//************************************************************************ +// +// CLCDPopup::SetAlpha +// +//************************************************************************ + +void CLCDPopup::SetAlpha(BYTE bAlphaStart, BYTE bAlphaEnd) +{ + m_Background.SetAlphaLevel(bAlphaStart, bAlphaEnd); +} + + +//************************************************************************ +// +// CLCDPopup::SetGradientMode +// +//************************************************************************ + +void CLCDPopup::SetGradientMode(BOOL bGradient) +{ + m_Background.SetGradientMode(bGradient); +} + + +//************************************************************************ +// +// CLCDPopup::SetColor +// +//************************************************************************ + +void CLCDPopup::SetColor(COLORREF cfColor) +{ + m_Background.SetColor(cfColor); +} + + +//** end of LCDPopup.cpp ************************************************* diff --git a/src/thirdparty/LCDUI/LCDPopup.h b/src/thirdparty/LCDUI/LCDPopup.h index 1f5f02296a8..12b3edbecd2 100644 --- a/src/thirdparty/LCDUI/LCDPopup.h +++ b/src/thirdparty/LCDUI/LCDPopup.h @@ -1,100 +1,100 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPopup.h -// -// Color LCD Popup class -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDPOPUP_H_INCLUDED_ -#define _LCDPOPUP_H_INCLUDED_ - -#include "LCDPage.h" -#include "LCDText.h" -#include "LCDBitmap.h" -#include - - -//************************************************************************ -// -// CLCDPopupBackground -// -//************************************************************************ - -class CLCDPopupBackground : public CLCDBase -{ -public: - CLCDPopupBackground(void); - virtual ~CLCDPopupBackground(void); - - void SetAlphaLevel(BYTE cAlphaStart, BYTE cAlphaEnd = 0xff); - void SetGradientMode(BOOL bGradient); - void SetColor(COLORREF cfColor); - void SetRoundedRecteRadius(int nRadius); - -public: - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void SetSize(int nCX, int nCY); - -private: - void RecalcRoundedRectangle(void); - BYTE m_cAlphaStart, m_cAlphaEnd; - COLORREF m_cfColor; - BOOL m_bUseGradient; - int m_nRectRadius; - Gdiplus::GraphicsPath* m_pGraphicsPath; -}; - - - -//************************************************************************ -// -// CLCDPopup -// -//************************************************************************ - -class CLCDPopup : public CLCDPage -{ -public: - enum PB_TYPE { PB_TEXT, PB_OK, PB_OKCANCEL, PB_OKCANCEL_TEXT }; - -public: - CLCDPopup(void); - - virtual HRESULT Initialize(int nMaxPopupWidth = 0); - - void SetText(LPCTSTR szMessage, LPCTSTR szOK = NULL, LPCTSTR szCancel = NULL); - void SetPopupType(PB_TYPE pbType); - void SetBitmaps(HBITMAP hbmOK, HBITMAP hbmCancel = NULL); - void SetAlpha(BYTE cAlphaStart, BYTE cAlphaEnd = 0xff); - void SetGradientMode(BOOL bGradient); - void SetColor(COLORREF cfColor); - -protected: - void RecalcLayout(void); - // Resizes automatically, so this is now private - virtual void SetSize(int nCX, int nCY); - - CLCDText m_MessageText, m_OKText, m_CancelText; - CLCDPopupBackground m_Background; - int m_nMaxPopupWidth; -private: - - CLCDBitmap m_OKBitmap, m_CancelBitmap; - PB_TYPE m_pbType; -}; - -#endif - -//** end of LCDPopup.h *************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPopup.h +// +// Color LCD Popup class +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDPOPUP_H_INCLUDED_ +#define _LCDPOPUP_H_INCLUDED_ + +#include "LCDPage.h" +#include "LCDText.h" +#include "LCDBitmap.h" +#include + + +//************************************************************************ +// +// CLCDPopupBackground +// +//************************************************************************ + +class CLCDPopupBackground : public CLCDBase +{ +public: + CLCDPopupBackground(void); + virtual ~CLCDPopupBackground(void); + + void SetAlphaLevel(BYTE cAlphaStart, BYTE cAlphaEnd = 0xff); + void SetGradientMode(BOOL bGradient); + void SetColor(COLORREF cfColor); + void SetRoundedRecteRadius(int nRadius); + +public: + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void SetSize(int nCX, int nCY); + +private: + void RecalcRoundedRectangle(void); + BYTE m_cAlphaStart, m_cAlphaEnd; + COLORREF m_cfColor; + BOOL m_bUseGradient; + int m_nRectRadius; + Gdiplus::GraphicsPath* m_pGraphicsPath; +}; + + + +//************************************************************************ +// +// CLCDPopup +// +//************************************************************************ + +class CLCDPopup : public CLCDPage +{ +public: + enum PB_TYPE { PB_TEXT, PB_OK, PB_OKCANCEL, PB_OKCANCEL_TEXT }; + +public: + CLCDPopup(void); + + virtual HRESULT Initialize(int nMaxPopupWidth = 0); + + void SetText(LPCTSTR szMessage, LPCTSTR szOK = NULL, LPCTSTR szCancel = NULL); + void SetPopupType(PB_TYPE pbType); + void SetBitmaps(HBITMAP hbmOK, HBITMAP hbmCancel = NULL); + void SetAlpha(BYTE cAlphaStart, BYTE cAlphaEnd = 0xff); + void SetGradientMode(BOOL bGradient); + void SetColor(COLORREF cfColor); + +protected: + void RecalcLayout(void); + // Resizes automatically, so this is now private + virtual void SetSize(int nCX, int nCY); + + CLCDText m_MessageText, m_OKText, m_CancelText; + CLCDPopupBackground m_Background; + int m_nMaxPopupWidth; +private: + + CLCDBitmap m_OKBitmap, m_CancelBitmap; + PB_TYPE m_pbType; +}; + +#endif + +//** end of LCDPopup.h *************************************************** diff --git a/src/thirdparty/LCDUI/LCDProgressBar.cpp b/src/thirdparty/LCDUI/LCDProgressBar.cpp index caeab4e5220..06d61cf0520 100644 --- a/src/thirdparty/LCDUI/LCDProgressBar.cpp +++ b/src/thirdparty/LCDUI/LCDProgressBar.cpp @@ -1,263 +1,263 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDProgressBar.cpp -// -// The CLCDProgressBar class draws a progress bar onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDProgressBar::CLCDProgressBar -// -//************************************************************************ - -CLCDProgressBar::CLCDProgressBar(void) -: m_fPos(0.0f), - m_eStyle(STYLE_CURSOR), - m_hBrush(NULL), - m_hPen(NULL), - m_nCursorWidth(5) -{ - m_Range.nMin = 0; - m_Range.nMax = 100; -} - - -//************************************************************************ -// -// CLCDProgressBar::~CLCDProgressBar -// -//************************************************************************ - -CLCDProgressBar::~CLCDProgressBar(void) -{ - if (m_hPen != NULL) - { - ::DeleteObject(m_hPen); - m_hPen = NULL; - } -} - - -//************************************************************************ -// -// CLCDProgressBar:Initialize -// -//************************************************************************ - -HRESULT CLCDProgressBar::Initialize(void) -{ - m_hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); - m_hPen = ::CreatePen(PS_DOT, 1, RGB(255, 255, 255)); - - return S_OK; -} - - -//************************************************************************ -// -// CLCDProgressBar::OnDraw -// -//************************************************************************ - -void CLCDProgressBar::OnDraw(CLCDGfxBase &rGfx) -{ - // draw the border - RECT r = { 0, 0, GetWidth(), GetHeight() }; - - FrameRect(rGfx.GetHDC(), &r, m_hBrush); - - // draw the progress - switch(m_eStyle) - { - case STYLE_CURSOR: - { - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)1, (float)(GetWidth() - m_nCursorWidth-1), - m_fPos); - r.left = nCursorPos; - r.right = r.left + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - } - break; - case STYLE_FILLED: - { - int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - 0.0f, (float)GetWidth(), - m_fPos); - r.right = nBarWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - } - break; - case STYLE_DASHED_CURSOR: - { - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)1, (float)(GetWidth() - m_nCursorWidth-1), - m_fPos); - r.left = nCursorPos; - r.right = r.left + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), m_hPen); - - ::MoveToEx(rGfx.GetHDC(), 0, (r.bottom - r.top)/2, NULL); - ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top)/2); - ::SelectObject(rGfx.GetHDC(), hOldPen); - } - break; - default: - break; - } -} - - -//************************************************************************ -// -// CLCDProgressBar::ResetUpdate -// -//************************************************************************ - -void CLCDProgressBar::ResetUpdate(void) -{ -} - - -//************************************************************************ -// -// CLCDProgressBar::SetRange -// -//************************************************************************ - -void CLCDProgressBar::SetRange(int nMin, int nMax) -{ - m_Range.nMin = nMin; - m_Range.nMax = nMax; -} - - -//************************************************************************ -// -// CLCDProgressBar::SetRange -// -//************************************************************************ - -void CLCDProgressBar::SetRange(RANGE& Range) -{ - m_Range = Range; -} - - -//************************************************************************ -// -// CLCDProgressBar::GetRange -// -//************************************************************************ - -RANGE& CLCDProgressBar::GetRange(void) -{ - return m_Range; -} - - -//************************************************************************ -// -// CLCDProgressBar::SetPos -// -//************************************************************************ - -float CLCDProgressBar::SetPos(float fPos) -{ - return ( m_fPos = max((float)m_Range.nMin, min(fPos, (float)m_Range.nMax)) ); -} - - -//************************************************************************ -// -// CLCDProgressBar::GetPos -// -//************************************************************************ - -float CLCDProgressBar::GetPos(void) -{ - return m_fPos; -} - - -//************************************************************************ -// -// CLCDProgressBar::EnableCursor -// -//************************************************************************ - -void CLCDProgressBar::EnableCursor(BOOL bEnable) -{ - m_eStyle = bEnable ? STYLE_CURSOR : STYLE_FILLED; -} - - -//************************************************************************ -// -// CLCDProgressBar::SetProgressStyle -// -//************************************************************************ - -void CLCDProgressBar::SetProgressStyle(ePROGRESS_STYLE eStyle) -{ - m_eStyle = eStyle; -} - - -//************************************************************************ -// -// CLCDProgressBar::Scalef -// -//************************************************************************ - -float CLCDProgressBar::Scalef(float fFromMin, float fFromMax, - float fToMin, float fToMax, float fFromValue) -{ - - // normalize the input - float fFromValueN = (fFromValue - fFromMin) / (fFromMax - fFromMin); - - // now scale to the output - float fToRange = fToMax - fToMin; - - return ( fToMin + (fFromValueN * fToRange) ); -} - - -//************************************************************************ -// -// CLCDProgressBar::Scale -// -//************************************************************************ - -int CLCDProgressBar::Scale(int nFromMin, int nFromMax, - int nToMin, int nToMax, int nFromValue) -{ - return (int)Scalef( - (float)nFromMin, - (float)nFromMax, - (float)nToMin, - (float)nToMax, - (float)nFromValue - ); -} - - -//** end of LCDProgressBar.cpp ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDProgressBar.cpp +// +// The CLCDProgressBar class draws a progress bar onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDProgressBar::CLCDProgressBar +// +//************************************************************************ + +CLCDProgressBar::CLCDProgressBar(void) +: m_fPos(0.0f), + m_eStyle(STYLE_CURSOR), + m_hBrush(NULL), + m_hPen(NULL), + m_nCursorWidth(5) +{ + m_Range.nMin = 0; + m_Range.nMax = 100; +} + + +//************************************************************************ +// +// CLCDProgressBar::~CLCDProgressBar +// +//************************************************************************ + +CLCDProgressBar::~CLCDProgressBar(void) +{ + if (m_hPen != NULL) + { + ::DeleteObject(m_hPen); + m_hPen = NULL; + } +} + + +//************************************************************************ +// +// CLCDProgressBar:Initialize +// +//************************************************************************ + +HRESULT CLCDProgressBar::Initialize(void) +{ + m_hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); + m_hPen = ::CreatePen(PS_DOT, 1, RGB(255, 255, 255)); + + return S_OK; +} + + +//************************************************************************ +// +// CLCDProgressBar::OnDraw +// +//************************************************************************ + +void CLCDProgressBar::OnDraw(CLCDGfxBase &rGfx) +{ + // draw the border + RECT r = { 0, 0, GetWidth(), GetHeight() }; + + FrameRect(rGfx.GetHDC(), &r, m_hBrush); + + // draw the progress + switch(m_eStyle) + { + case STYLE_CURSOR: + { + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)1, (float)(GetWidth() - m_nCursorWidth-1), + m_fPos); + r.left = nCursorPos; + r.right = r.left + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + } + break; + case STYLE_FILLED: + { + int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + 0.0f, (float)GetWidth(), + m_fPos); + r.right = nBarWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + } + break; + case STYLE_DASHED_CURSOR: + { + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)1, (float)(GetWidth() - m_nCursorWidth-1), + m_fPos); + r.left = nCursorPos; + r.right = r.left + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), m_hPen); + + ::MoveToEx(rGfx.GetHDC(), 0, (r.bottom - r.top)/2, NULL); + ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top)/2); + ::SelectObject(rGfx.GetHDC(), hOldPen); + } + break; + default: + break; + } +} + + +//************************************************************************ +// +// CLCDProgressBar::ResetUpdate +// +//************************************************************************ + +void CLCDProgressBar::ResetUpdate(void) +{ +} + + +//************************************************************************ +// +// CLCDProgressBar::SetRange +// +//************************************************************************ + +void CLCDProgressBar::SetRange(int nMin, int nMax) +{ + m_Range.nMin = nMin; + m_Range.nMax = nMax; +} + + +//************************************************************************ +// +// CLCDProgressBar::SetRange +// +//************************************************************************ + +void CLCDProgressBar::SetRange(RANGE& Range) +{ + m_Range = Range; +} + + +//************************************************************************ +// +// CLCDProgressBar::GetRange +// +//************************************************************************ + +RANGE& CLCDProgressBar::GetRange(void) +{ + return m_Range; +} + + +//************************************************************************ +// +// CLCDProgressBar::SetPos +// +//************************************************************************ + +float CLCDProgressBar::SetPos(float fPos) +{ + return ( m_fPos = max((float)m_Range.nMin, min(fPos, (float)m_Range.nMax)) ); +} + + +//************************************************************************ +// +// CLCDProgressBar::GetPos +// +//************************************************************************ + +float CLCDProgressBar::GetPos(void) +{ + return m_fPos; +} + + +//************************************************************************ +// +// CLCDProgressBar::EnableCursor +// +//************************************************************************ + +void CLCDProgressBar::EnableCursor(BOOL bEnable) +{ + m_eStyle = bEnable ? STYLE_CURSOR : STYLE_FILLED; +} + + +//************************************************************************ +// +// CLCDProgressBar::SetProgressStyle +// +//************************************************************************ + +void CLCDProgressBar::SetProgressStyle(ePROGRESS_STYLE eStyle) +{ + m_eStyle = eStyle; +} + + +//************************************************************************ +// +// CLCDProgressBar::Scalef +// +//************************************************************************ + +float CLCDProgressBar::Scalef(float fFromMin, float fFromMax, + float fToMin, float fToMax, float fFromValue) +{ + + // normalize the input + float fFromValueN = (fFromValue - fFromMin) / (fFromMax - fFromMin); + + // now scale to the output + float fToRange = fToMax - fToMin; + + return ( fToMin + (fFromValueN * fToRange) ); +} + + +//************************************************************************ +// +// CLCDProgressBar::Scale +// +//************************************************************************ + +int CLCDProgressBar::Scale(int nFromMin, int nFromMax, + int nToMin, int nToMax, int nFromValue) +{ + return (int)Scalef( + (float)nFromMin, + (float)nFromMax, + (float)nToMin, + (float)nToMax, + (float)nFromValue + ); +} + + +//** end of LCDProgressBar.cpp ******************************************* diff --git a/src/thirdparty/LCDUI/LCDProgressBar.h b/src/thirdparty/LCDUI/LCDProgressBar.h index 28766c23630..677816f546b 100644 --- a/src/thirdparty/LCDUI/LCDProgressBar.h +++ b/src/thirdparty/LCDUI/LCDProgressBar.h @@ -1,72 +1,72 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDProgressBar.h -// -// The CLCDProgressBar class draws a progress bar onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDPROGRESSBAR_H_INCLUDED_ -#define _LCDPROGRESSBAR_H_INCLUDED_ - -#include "LCDBase.h" - -typedef struct RANGE -{ - int nMin; - int nMax; - -}RANGE, *LPRANGE; - -class CLCDProgressBar : public CLCDBase -{ -public: - enum ePROGRESS_STYLE { STYLE_FILLED, STYLE_CURSOR, STYLE_DASHED_CURSOR }; - - CLCDProgressBar(void); - virtual ~CLCDProgressBar(void); - - // CLCDBase - virtual HRESULT Initialize(void); - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void ResetUpdate(void); - - // CLCDProgressBar - virtual void SetRange(int nMin, int nMax); - virtual void SetRange(RANGE& Range); - virtual RANGE& GetRange(void); - virtual float SetPos(float fPos); - virtual float GetPos(void); - virtual void EnableCursor(BOOL bEnable); - virtual void SetProgressStyle(ePROGRESS_STYLE eStyle); - -protected: - float Scalef(float fFromMin, float fFromMax, - float fToMin, float fToMax, float fFromValue); - int Scale(int nFromMin, int nFromMax, - int nToMin, int nToMax, int nFromValue); - -protected: - RANGE m_Range; - float m_fPos; - ePROGRESS_STYLE m_eStyle; - HBRUSH m_hBrush; - HPEN m_hPen; - int m_nCursorWidth; -}; - - -#endif // !_LCDPROGRESSBAR_H_INCLUDED_ - -//** end of LCDProgressBar.h ********************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDProgressBar.h +// +// The CLCDProgressBar class draws a progress bar onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDPROGRESSBAR_H_INCLUDED_ +#define _LCDPROGRESSBAR_H_INCLUDED_ + +#include "LCDBase.h" + +typedef struct RANGE +{ + int nMin; + int nMax; + +}RANGE, *LPRANGE; + +class CLCDProgressBar : public CLCDBase +{ +public: + enum ePROGRESS_STYLE { STYLE_FILLED, STYLE_CURSOR, STYLE_DASHED_CURSOR }; + + CLCDProgressBar(void); + virtual ~CLCDProgressBar(void); + + // CLCDBase + virtual HRESULT Initialize(void); + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void ResetUpdate(void); + + // CLCDProgressBar + virtual void SetRange(int nMin, int nMax); + virtual void SetRange(RANGE& Range); + virtual RANGE& GetRange(void); + virtual float SetPos(float fPos); + virtual float GetPos(void); + virtual void EnableCursor(BOOL bEnable); + virtual void SetProgressStyle(ePROGRESS_STYLE eStyle); + +protected: + float Scalef(float fFromMin, float fFromMax, + float fToMin, float fToMax, float fFromValue); + int Scale(int nFromMin, int nFromMax, + int nToMin, int nToMax, int nFromValue); + +protected: + RANGE m_Range; + float m_fPos; + ePROGRESS_STYLE m_eStyle; + HBRUSH m_hBrush; + HPEN m_hPen; + int m_nCursorWidth; +}; + + +#endif // !_LCDPROGRESSBAR_H_INCLUDED_ + +//** end of LCDProgressBar.h ********************************************* diff --git a/src/thirdparty/LCDUI/LCDScrollingText.cpp b/src/thirdparty/LCDUI/LCDScrollingText.cpp index 51889201a0b..5efcfac9428 100644 --- a/src/thirdparty/LCDUI/LCDScrollingText.cpp +++ b/src/thirdparty/LCDUI/LCDScrollingText.cpp @@ -1,306 +1,306 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDScrollingText.cpp -// -// The CLCDScrollingText class draws scrolling text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDScrollingText::CLCDScrollingText -// -//************************************************************************ - -CLCDScrollingText::CLCDScrollingText(void) -{ - m_eState = STATE_START_DELAY; - m_eScrollDir = SCROLL_HORZ; - m_bRepeat = TRUE; -} - - -//************************************************************************ -// -// CLCDScrollingText::~CLCDScrollingText -// -//************************************************************************ - -CLCDScrollingText::~CLCDScrollingText(void) -{ -} - - -//************************************************************************ -// -// CLCDScrollingText::Initialize -// -//************************************************************************ - -HRESULT CLCDScrollingText::Initialize(void) -{ - m_dwStartDelay = 1000; - m_dwSpeed = 20; - m_nScrollingDistance = -1; - m_dwLastUpdate = 0; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_fTotalDistance = 0; - m_eScrollDir = SCROLL_HORZ; - m_dwEndDelay = 1000; - m_bRepeat = TRUE; - - return CLCDText::Initialize(); -} - - -//************************************************************************ -// -// CLCDScrollingText::ResetUpdate -// -//************************************************************************ - -void CLCDScrollingText::ResetUpdate(void) -{ - m_eState = STATE_START_DELAY; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_nScrollingDistance = -1; - m_fTotalDistance = 0; - SetLeftMargin(0); - SetLogicalOrigin(0, 0); - - CLCDText::ResetUpdate(); -} - - -//************************************************************************ -// -// CLCDScrollingText::SetStartDelay -// -//************************************************************************ - -void CLCDScrollingText::SetStartDelay(DWORD dwMilliseconds) -{ - m_dwStartDelay = dwMilliseconds; -} - - -//************************************************************************ -// -// CLCDScrollingText::SetEndDelay -// -//************************************************************************ - -void CLCDScrollingText::SetEndDelay(DWORD dwMilliseconds) -{ - m_dwEndDelay = dwMilliseconds; -} - - -//************************************************************************ -// -// CLCDScrollingText::SetSpeed -// -//************************************************************************ - -void CLCDScrollingText::SetSpeed(DWORD dwSpeed) -{ - m_dwSpeed = dwSpeed; -} - - -//************************************************************************ -// -// CLCDScrollingText::SetScrollDirection -// -//************************************************************************ - -void CLCDScrollingText::SetScrollDirection(eSCROLL_DIR eScrollDir) -{ - m_eScrollDir = eScrollDir; - SetWordWrap(eScrollDir == SCROLL_VERT); - ResetUpdate(); -} - - -//************************************************************************ -// -// CLCDScrollingText::GetScrollDirection -// -//************************************************************************ - -eSCROLL_DIR CLCDScrollingText::GetScrollDirection() -{ - return m_eScrollDir; -} - - -//************************************************************************ -// -// CLCDScrollingText::SetText -// -//************************************************************************ - -void CLCDScrollingText::SetText(LPCTSTR szText) -{ - if (_tcscmp(szText, m_sText.c_str())) - { - ResetUpdate(); - } - - CLCDText::SetText(szText); -} - - -//************************************************************************ -// -// CLCDScrollingText::IsScrollingDone -// -//************************************************************************ - -BOOL CLCDScrollingText::IsScrollingDone() -{ - return (STATE_DONE == m_eState); -} - - -//************************************************************************ -// -// CLCDScrollingText::EnableRepeat -// -//************************************************************************ - -void CLCDScrollingText::EnableRepeat(BOOL bEnable) -{ - m_bRepeat = bEnable; -} - - -//************************************************************************ -// -// CLCDScrollingText::OnUpdate -// -//************************************************************************ - -void CLCDScrollingText::OnUpdate(DWORD dwTimestamp) -{ - m_dwEllapsedTime = (dwTimestamp - m_dwLastUpdate); -} - - -//************************************************************************ -// -// CLCDScrollingText::OnDraw -// -//************************************************************************ - -void CLCDScrollingText::OnDraw(CLCDGfxBase &rGfx) -{ - if (!m_nTextLength) - { - return; - } - - // calculate the scrolling distance - if (-1 == m_nScrollingDistance) - { - CLCDText::OnDraw(rGfx); - - if (SCROLL_VERT == m_eScrollDir) - { - // determine how far we have to travel until scrolling stops - m_nScrollingDistance = ((GetHeight()) >= GetVExtent().cy) ? - 0 : (GetVExtent().cy - GetHeight()); - SetLogicalSize(GetVExtent().cx, GetVExtent().cy); - } - else - { - // determine how far we have to travel until scrolling stops - m_nScrollingDistance = ((GetWidth()) >= GetHExtent().cx) ? - 0 : (GetHExtent().cx - GetWidth()); - SetLogicalSize(max(GetSize().cx, GetHExtent().cx), GetHExtent().cy); - } - } - - switch(m_eState) - { - case STATE_START_DELAY: - if (m_dwEllapsedTime > m_dwStartDelay) - { - m_eState = STATE_SCROLL; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - } - break; - - case STATE_END_DELAY: - if (m_dwEllapsedTime > m_dwEndDelay) - { - if (m_bRepeat) - { - ResetUpdate(); - break; - } - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_eState = STATE_DONE; - } - break; - - case STATE_SCROLL: - { - // TODO: add some anti-aliasing on the movement - - // how much time has ellapsed? - // given the speed, what is the total displacement? - float fDistance = (float)(m_dwSpeed * m_dwEllapsedTime) / 1000.0f; - m_fTotalDistance += fDistance; - - // we dont want the total distnace exceed our scrolling distance - int nTotalOffset = min((int)m_fTotalDistance, m_nScrollingDistance); - - if (SCROLL_VERT == m_eScrollDir) - { - SetLogicalOrigin(GetLogicalOrigin().x, -1 * nTotalOffset); - } - else - { - SetLogicalOrigin(-1 * nTotalOffset, GetLogicalOrigin().y); - } - - m_dwLastUpdate = GetTickCount(); - - if (nTotalOffset == m_nScrollingDistance) - { - m_eState = STATE_END_DELAY; - } - } - break; - - case STATE_DONE: - break; - - default: - break; - } - - CLCDText::OnDraw(rGfx); -} - - -//** end of LCDScrollingText.cpp ***************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDScrollingText.cpp +// +// The CLCDScrollingText class draws scrolling text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDScrollingText::CLCDScrollingText +// +//************************************************************************ + +CLCDScrollingText::CLCDScrollingText(void) +{ + m_eState = STATE_START_DELAY; + m_eScrollDir = SCROLL_HORZ; + m_bRepeat = TRUE; +} + + +//************************************************************************ +// +// CLCDScrollingText::~CLCDScrollingText +// +//************************************************************************ + +CLCDScrollingText::~CLCDScrollingText(void) +{ +} + + +//************************************************************************ +// +// CLCDScrollingText::Initialize +// +//************************************************************************ + +HRESULT CLCDScrollingText::Initialize(void) +{ + m_dwStartDelay = 1000; + m_dwSpeed = 20; + m_nScrollingDistance = -1; + m_dwLastUpdate = 0; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_fTotalDistance = 0; + m_eScrollDir = SCROLL_HORZ; + m_dwEndDelay = 1000; + m_bRepeat = TRUE; + + return CLCDText::Initialize(); +} + + +//************************************************************************ +// +// CLCDScrollingText::ResetUpdate +// +//************************************************************************ + +void CLCDScrollingText::ResetUpdate(void) +{ + m_eState = STATE_START_DELAY; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_nScrollingDistance = -1; + m_fTotalDistance = 0; + SetLeftMargin(0); + SetLogicalOrigin(0, 0); + + CLCDText::ResetUpdate(); +} + + +//************************************************************************ +// +// CLCDScrollingText::SetStartDelay +// +//************************************************************************ + +void CLCDScrollingText::SetStartDelay(DWORD dwMilliseconds) +{ + m_dwStartDelay = dwMilliseconds; +} + + +//************************************************************************ +// +// CLCDScrollingText::SetEndDelay +// +//************************************************************************ + +void CLCDScrollingText::SetEndDelay(DWORD dwMilliseconds) +{ + m_dwEndDelay = dwMilliseconds; +} + + +//************************************************************************ +// +// CLCDScrollingText::SetSpeed +// +//************************************************************************ + +void CLCDScrollingText::SetSpeed(DWORD dwSpeed) +{ + m_dwSpeed = dwSpeed; +} + + +//************************************************************************ +// +// CLCDScrollingText::SetScrollDirection +// +//************************************************************************ + +void CLCDScrollingText::SetScrollDirection(eSCROLL_DIR eScrollDir) +{ + m_eScrollDir = eScrollDir; + SetWordWrap(eScrollDir == SCROLL_VERT); + ResetUpdate(); +} + + +//************************************************************************ +// +// CLCDScrollingText::GetScrollDirection +// +//************************************************************************ + +eSCROLL_DIR CLCDScrollingText::GetScrollDirection() +{ + return m_eScrollDir; +} + + +//************************************************************************ +// +// CLCDScrollingText::SetText +// +//************************************************************************ + +void CLCDScrollingText::SetText(LPCTSTR szText) +{ + if (_tcscmp(szText, m_sText.c_str())) + { + ResetUpdate(); + } + + CLCDText::SetText(szText); +} + + +//************************************************************************ +// +// CLCDScrollingText::IsScrollingDone +// +//************************************************************************ + +BOOL CLCDScrollingText::IsScrollingDone() +{ + return (STATE_DONE == m_eState); +} + + +//************************************************************************ +// +// CLCDScrollingText::EnableRepeat +// +//************************************************************************ + +void CLCDScrollingText::EnableRepeat(BOOL bEnable) +{ + m_bRepeat = bEnable; +} + + +//************************************************************************ +// +// CLCDScrollingText::OnUpdate +// +//************************************************************************ + +void CLCDScrollingText::OnUpdate(DWORD dwTimestamp) +{ + m_dwEllapsedTime = (dwTimestamp - m_dwLastUpdate); +} + + +//************************************************************************ +// +// CLCDScrollingText::OnDraw +// +//************************************************************************ + +void CLCDScrollingText::OnDraw(CLCDGfxBase &rGfx) +{ + if (!m_nTextLength) + { + return; + } + + // calculate the scrolling distance + if (-1 == m_nScrollingDistance) + { + CLCDText::OnDraw(rGfx); + + if (SCROLL_VERT == m_eScrollDir) + { + // determine how far we have to travel until scrolling stops + m_nScrollingDistance = ((GetHeight()) >= GetVExtent().cy) ? + 0 : (GetVExtent().cy - GetHeight()); + SetLogicalSize(GetVExtent().cx, GetVExtent().cy); + } + else + { + // determine how far we have to travel until scrolling stops + m_nScrollingDistance = ((GetWidth()) >= GetHExtent().cx) ? + 0 : (GetHExtent().cx - GetWidth()); + SetLogicalSize(max(GetSize().cx, GetHExtent().cx), GetHExtent().cy); + } + } + + switch(m_eState) + { + case STATE_START_DELAY: + if (m_dwEllapsedTime > m_dwStartDelay) + { + m_eState = STATE_SCROLL; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + } + break; + + case STATE_END_DELAY: + if (m_dwEllapsedTime > m_dwEndDelay) + { + if (m_bRepeat) + { + ResetUpdate(); + break; + } + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_eState = STATE_DONE; + } + break; + + case STATE_SCROLL: + { + // TODO: add some anti-aliasing on the movement + + // how much time has ellapsed? + // given the speed, what is the total displacement? + float fDistance = (float)(m_dwSpeed * m_dwEllapsedTime) / 1000.0f; + m_fTotalDistance += fDistance; + + // we dont want the total distnace exceed our scrolling distance + int nTotalOffset = min((int)m_fTotalDistance, m_nScrollingDistance); + + if (SCROLL_VERT == m_eScrollDir) + { + SetLogicalOrigin(GetLogicalOrigin().x, -1 * nTotalOffset); + } + else + { + SetLogicalOrigin(-1 * nTotalOffset, GetLogicalOrigin().y); + } + + m_dwLastUpdate = GetTickCount(); + + if (nTotalOffset == m_nScrollingDistance) + { + m_eState = STATE_END_DELAY; + } + } + break; + + case STATE_DONE: + break; + + default: + break; + } + + CLCDText::OnDraw(rGfx); +} + + +//** end of LCDScrollingText.cpp ***************************************** diff --git a/src/thirdparty/LCDUI/LCDScrollingText.h b/src/thirdparty/LCDUI/LCDScrollingText.h index c55fb89a2e2..1fe1cf8ca69 100644 --- a/src/thirdparty/LCDUI/LCDScrollingText.h +++ b/src/thirdparty/LCDUI/LCDScrollingText.h @@ -1,75 +1,75 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDScrollingText.h -// -// The CLCDScrollingText class draws scrolling text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - - -#ifndef _LCDSCROLLINGTEXT_H_INCLUDED_ -#define _LCDSCROLLINGTEXT_H_INCLUDED_ - -#include "LCDBase.h" -#include "LCDText.h" - -enum eSCROLL_DIR { SCROLL_HORZ, SCROLL_VERT }; - -class CLCDScrollingText : public CLCDText -{ -public: - CLCDScrollingText(); - virtual ~CLCDScrollingText(); - - // CLCDBase - virtual HRESULT Initialize(void); - virtual void ResetUpdate(void); - - // CLCDText - virtual void SetText(LPCTSTR szText); - - void SetStartDelay(DWORD dwMilliseconds); - void SetEndDelay(DWORD dwMilliseconds); - void EnableRepeat(BOOL bEnable); - void SetSpeed(DWORD dwSpeed); - - void SetScrollDirection(eSCROLL_DIR eScrollDir); - eSCROLL_DIR GetScrollDirection(void); - BOOL IsScrollingDone(void); - -protected: - virtual void OnUpdate(DWORD dwTimestamp); - virtual void OnDraw(CLCDGfxBase &rGfx); - -private: - enum eSCROLL_STATES { STATE_START_DELAY, STATE_SCROLL, STATE_END_DELAY, STATE_DONE}; - - DWORD m_dwEllapsedTime; // ellapsed time in state - DWORD m_dwStartDelay; // milliseconds - DWORD m_dwEndDelay; // milliseconds - DWORD m_dwSpeed; // pixels/second - DWORD m_dwLastUpdate; // milliseconds - BOOL m_bRepeat; // repeat - - int m_nScrollingDistance; - float m_fTotalDistance; - - eSCROLL_DIR m_eScrollDir; - eSCROLL_STATES m_eState; -}; - - -#endif // !_LCDSCROLLINGTEXT_H_INCLUDED_ - -//** end of LCDScrollingText.h ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDScrollingText.h +// +// The CLCDScrollingText class draws scrolling text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + + +#ifndef _LCDSCROLLINGTEXT_H_INCLUDED_ +#define _LCDSCROLLINGTEXT_H_INCLUDED_ + +#include "LCDBase.h" +#include "LCDText.h" + +enum eSCROLL_DIR { SCROLL_HORZ, SCROLL_VERT }; + +class CLCDScrollingText : public CLCDText +{ +public: + CLCDScrollingText(); + virtual ~CLCDScrollingText(); + + // CLCDBase + virtual HRESULT Initialize(void); + virtual void ResetUpdate(void); + + // CLCDText + virtual void SetText(LPCTSTR szText); + + void SetStartDelay(DWORD dwMilliseconds); + void SetEndDelay(DWORD dwMilliseconds); + void EnableRepeat(BOOL bEnable); + void SetSpeed(DWORD dwSpeed); + + void SetScrollDirection(eSCROLL_DIR eScrollDir); + eSCROLL_DIR GetScrollDirection(void); + BOOL IsScrollingDone(void); + +protected: + virtual void OnUpdate(DWORD dwTimestamp); + virtual void OnDraw(CLCDGfxBase &rGfx); + +private: + enum eSCROLL_STATES { STATE_START_DELAY, STATE_SCROLL, STATE_END_DELAY, STATE_DONE}; + + DWORD m_dwEllapsedTime; // ellapsed time in state + DWORD m_dwStartDelay; // milliseconds + DWORD m_dwEndDelay; // milliseconds + DWORD m_dwSpeed; // pixels/second + DWORD m_dwLastUpdate; // milliseconds + BOOL m_bRepeat; // repeat + + int m_nScrollingDistance; + float m_fTotalDistance; + + eSCROLL_DIR m_eScrollDir; + eSCROLL_STATES m_eState; +}; + + +#endif // !_LCDSCROLLINGTEXT_H_INCLUDED_ + +//** end of LCDScrollingText.h ******************************************* diff --git a/src/thirdparty/LCDUI/LCDSkinnedProgressBar.cpp b/src/thirdparty/LCDUI/LCDSkinnedProgressBar.cpp index b53a987aefd..1ead93b07d3 100644 --- a/src/thirdparty/LCDUI/LCDSkinnedProgressBar.cpp +++ b/src/thirdparty/LCDUI/LCDSkinnedProgressBar.cpp @@ -1,323 +1,323 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// CLCDSkinnedProgressBar.cpp -// -// Color LCD Skinned Progress Bar class -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::CLCDSkinnedProgressBar -// -//************************************************************************ - -CLCDSkinnedProgressBar::CLCDSkinnedProgressBar(void) -{ - m_hBackground = NULL; - m_hFiller = NULL; - m_hCursor = NULL; - m_hHighlight = NULL; - m_h3PCursorLeft = NULL; - m_h3PCursorMid = NULL; - m_h3PCursorRight = NULL; - - m_BackgroundHeight = 0; - m_BackgroundWidth = 0; - - m_FillerHeight = 0; - m_FillerWidth = 0; - - m_CursorHeight = 0; - m_CursorWidth = 0; - - m_HighlightHeight = 0; - m_HighlightWidth = 0; - - m_bUse3P = FALSE; - - m_3PCursorLeftHeight = 0; - m_3PCursorLeftWidth = 0; - - m_3PCursorMidHeight = 0; - m_3PCursorMidWidth = 0; - - m_3PCursorRightHeight = 0; - m_3PCursorRightWidth = 0; -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::~CLCDSkinnedProgressBar -// -//************************************************************************ - -CLCDSkinnedProgressBar::~CLCDSkinnedProgressBar(void) -{ -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::SetBackground -// -//************************************************************************ - -void CLCDSkinnedProgressBar::SetBackground(HBITMAP background, int bmpWidth, int bmpHeight) -{ - m_hBackground = background; - m_BackgroundHeight = bmpHeight; - m_BackgroundWidth = bmpWidth; - SetSize(bmpWidth, bmpHeight); -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::SetFiller -// -//************************************************************************ - -void CLCDSkinnedProgressBar::SetFiller(HBITMAP cursor, int bmpWidth, int bmpHeight) -{ - m_bUse3P = FALSE; - m_hFiller = cursor; - m_FillerHeight = bmpHeight; - m_FillerWidth = bmpWidth; - SetSize(bmpWidth, bmpHeight); -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::SetCursor -// -//************************************************************************ - -void CLCDSkinnedProgressBar::SetCursor(HBITMAP cursor, int bmpWidth, int bmpHeight) -{ - m_bUse3P = FALSE; - m_hCursor = cursor; - m_CursorHeight = bmpHeight; - m_CursorWidth = bmpWidth; - m_nCursorWidth = m_CursorWidth; -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::SetThreePieceCursor -// -//************************************************************************ - -void CLCDSkinnedProgressBar::SetThreePieceCursor(HBITMAP left, int bmpLeftWidth, int bmpLeftHeight, - HBITMAP mid, int bmpMidWidth, int bmpMidHeight, - HBITMAP right, int bmpRightWidth, int bmpRightHeight ) -{ - m_bUse3P = TRUE; - - m_h3PCursorLeft = left; - m_3PCursorLeftHeight = bmpLeftHeight; - m_3PCursorLeftWidth = bmpLeftWidth; - - m_h3PCursorMid = mid; - m_3PCursorMidHeight = bmpMidHeight; - m_3PCursorMidWidth = bmpMidWidth; - - m_h3PCursorRight = right; - m_3PCursorRightHeight = bmpRightHeight; - m_3PCursorRightWidth = bmpRightWidth; - - m_nCursorWidth = m_3PCursorLeftWidth + m_3PCursorMidWidth + m_3PCursorRightWidth; -} - -//************************************************************************ -// -// CLCDSkinnedProgressBar::AddHighlight -// -//************************************************************************ - -void CLCDSkinnedProgressBar::AddHighlight(HBITMAP highlight, int bmpWidth, int bmpHeight) -{ - m_hHighlight = highlight; - m_HighlightHeight = bmpHeight; - m_HighlightWidth = bmpWidth; -} - -//************************************************************************ -// -// CLCDSkinnedProgressBar::OnDraw -// -//************************************************************************ - -void CLCDSkinnedProgressBar::OnDraw(CLCDGfxBase &rGfx) -{ - RECT rBoundary = { 0, 0, GetWidth(), GetHeight() }; - - HDC hdcMem = CreateCompatibleDC(rGfx.GetHDC()); - HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, m_hBackground); - - //Draw the background - //BitBlt the background onto the screen - BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - AlphaBlend(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight(), hdcMem, 0, 0, GetWidth(), GetHeight(), opblender); - - SelectObject(hdcMem, hbmOld); - DeleteDC(hdcMem); - - //Drawing the cursor - switch(m_eStyle) - { - case STYLE_FILLED: - { - - - HDC hdcMemCursor = CreateCompatibleDC(rGfx.GetHDC()); - - if(m_bUse3P) - { - RECT r = rBoundary; - r.left = 0; - r.right = GetWidth() - m_3PCursorRightWidth - m_3PCursorLeftWidth; - int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)r.left, (float)r.right, - m_fPos); - - int midstart, midwidth; - midstart = m_3PCursorLeftWidth; - midwidth = nBarWidth; - - //Left - hbmOld = (HBITMAP)SelectObject(hdcMemCursor, m_h3PCursorLeft); - - AlphaBlend(rGfx.GetHDC(), 0, 0, m_3PCursorLeftWidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorLeftWidth, m_3PCursorLeftHeight, opblender); - - //Mid - SelectObject(hdcMemCursor, m_h3PCursorMid); - - AlphaBlend(rGfx.GetHDC(), midstart, 0, midwidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorMidWidth, m_3PCursorMidHeight, opblender); - - //Right - SelectObject(hdcMemCursor, m_h3PCursorRight); - - AlphaBlend(rGfx.GetHDC(), midstart+midwidth, 0, m_3PCursorRightWidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorRightWidth, m_3PCursorRightHeight, opblender); - - // restore previous bitmap - SelectObject(hdcMemCursor, hbmOld); - - } - else - { - RECT r = rBoundary; - int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right), - m_fPos); - r.right = nBarWidth ? nBarWidth : r.left; - - HBITMAP hbmOldCursor = (HBITMAP)SelectObject(hdcMemCursor, m_hFiller); - - BitBlt(rGfx.GetHDC(), 0, 0, nBarWidth, GetHeight(), hdcMemCursor, 0, 0, SRCCOPY); - - SelectObject(hdcMemCursor, hbmOldCursor); - } - - DeleteDC(hdcMemCursor); - - break; - } - //These two cases will be the same - case STYLE_CURSOR: - case STYLE_DASHED_CURSOR: - { - HDC hdcMemCursor = CreateCompatibleDC(rGfx.GetHDC()); - - if(m_bUse3P) - { - RECT r = rBoundary; - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), - m_fPos); - r.left = nCursorPos; - r.right = nCursorPos + m_nCursorWidth; - - int midstart, midwidth; - midstart = r.left+m_3PCursorLeftWidth; - midwidth = m_3PCursorMidWidth; - - //Left - hbmOld = (HBITMAP)SelectObject(hdcMemCursor, m_h3PCursorLeft); - - AlphaBlend(rGfx.GetHDC(), r.left, 0, m_3PCursorLeftWidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorLeftWidth, m_3PCursorLeftHeight, opblender); - - //Mid - SelectObject(hdcMemCursor, m_h3PCursorMid); - - AlphaBlend(rGfx.GetHDC(), midstart, 0, midwidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorMidWidth, m_3PCursorMidHeight, opblender); - - //Right - SelectObject(hdcMemCursor, m_h3PCursorRight); - - AlphaBlend(rGfx.GetHDC(), midstart+midwidth, 0, m_3PCursorRightWidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorRightWidth, m_3PCursorRightHeight, opblender); - - // restore old bitmap - SelectObject(hdcMemCursor, hbmOld); - } - else - { - RECT r = rBoundary; - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), - m_fPos); - r.left = nCursorPos; - r.right = nCursorPos + m_nCursorWidth; - - HBITMAP hbmOldCursor = (HBITMAP)SelectObject(hdcMemCursor, m_hCursor); - - BitBlt(rGfx.GetHDC(), r.left, 0, m_nCursorWidth, GetHeight(), hdcMemCursor, 0, 0, SRCCOPY); - - SelectObject(hdcMemCursor, hbmOldCursor); - } - - DeleteDC(hdcMemCursor); - - break; - } - default: - break; - } - - if( NULL != m_hHighlight ) - { - HDC hdcMemHighlight = CreateCompatibleDC(rGfx.GetHDC()); - HBITMAP hbmOldHighlight = (HBITMAP)SelectObject(hdcMemHighlight, m_hHighlight); - - AlphaBlend(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight(), hdcMemHighlight, 0, 0, m_HighlightWidth, m_HighlightHeight, opblender); - - SelectObject(hdcMemHighlight, hbmOldHighlight); - DeleteDC(hdcMemHighlight); - } -} - - -//** end of LCDSkinnedProgressBar.cpp ************************************ +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// CLCDSkinnedProgressBar.cpp +// +// Color LCD Skinned Progress Bar class +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::CLCDSkinnedProgressBar +// +//************************************************************************ + +CLCDSkinnedProgressBar::CLCDSkinnedProgressBar(void) +{ + m_hBackground = NULL; + m_hFiller = NULL; + m_hCursor = NULL; + m_hHighlight = NULL; + m_h3PCursorLeft = NULL; + m_h3PCursorMid = NULL; + m_h3PCursorRight = NULL; + + m_BackgroundHeight = 0; + m_BackgroundWidth = 0; + + m_FillerHeight = 0; + m_FillerWidth = 0; + + m_CursorHeight = 0; + m_CursorWidth = 0; + + m_HighlightHeight = 0; + m_HighlightWidth = 0; + + m_bUse3P = FALSE; + + m_3PCursorLeftHeight = 0; + m_3PCursorLeftWidth = 0; + + m_3PCursorMidHeight = 0; + m_3PCursorMidWidth = 0; + + m_3PCursorRightHeight = 0; + m_3PCursorRightWidth = 0; +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::~CLCDSkinnedProgressBar +// +//************************************************************************ + +CLCDSkinnedProgressBar::~CLCDSkinnedProgressBar(void) +{ +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::SetBackground +// +//************************************************************************ + +void CLCDSkinnedProgressBar::SetBackground(HBITMAP background, int bmpWidth, int bmpHeight) +{ + m_hBackground = background; + m_BackgroundHeight = bmpHeight; + m_BackgroundWidth = bmpWidth; + SetSize(bmpWidth, bmpHeight); +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::SetFiller +// +//************************************************************************ + +void CLCDSkinnedProgressBar::SetFiller(HBITMAP cursor, int bmpWidth, int bmpHeight) +{ + m_bUse3P = FALSE; + m_hFiller = cursor; + m_FillerHeight = bmpHeight; + m_FillerWidth = bmpWidth; + SetSize(bmpWidth, bmpHeight); +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::SetCursor +// +//************************************************************************ + +void CLCDSkinnedProgressBar::SetCursor(HBITMAP cursor, int bmpWidth, int bmpHeight) +{ + m_bUse3P = FALSE; + m_hCursor = cursor; + m_CursorHeight = bmpHeight; + m_CursorWidth = bmpWidth; + m_nCursorWidth = m_CursorWidth; +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::SetThreePieceCursor +// +//************************************************************************ + +void CLCDSkinnedProgressBar::SetThreePieceCursor(HBITMAP left, int bmpLeftWidth, int bmpLeftHeight, + HBITMAP mid, int bmpMidWidth, int bmpMidHeight, + HBITMAP right, int bmpRightWidth, int bmpRightHeight ) +{ + m_bUse3P = TRUE; + + m_h3PCursorLeft = left; + m_3PCursorLeftHeight = bmpLeftHeight; + m_3PCursorLeftWidth = bmpLeftWidth; + + m_h3PCursorMid = mid; + m_3PCursorMidHeight = bmpMidHeight; + m_3PCursorMidWidth = bmpMidWidth; + + m_h3PCursorRight = right; + m_3PCursorRightHeight = bmpRightHeight; + m_3PCursorRightWidth = bmpRightWidth; + + m_nCursorWidth = m_3PCursorLeftWidth + m_3PCursorMidWidth + m_3PCursorRightWidth; +} + +//************************************************************************ +// +// CLCDSkinnedProgressBar::AddHighlight +// +//************************************************************************ + +void CLCDSkinnedProgressBar::AddHighlight(HBITMAP highlight, int bmpWidth, int bmpHeight) +{ + m_hHighlight = highlight; + m_HighlightHeight = bmpHeight; + m_HighlightWidth = bmpWidth; +} + +//************************************************************************ +// +// CLCDSkinnedProgressBar::OnDraw +// +//************************************************************************ + +void CLCDSkinnedProgressBar::OnDraw(CLCDGfxBase &rGfx) +{ + RECT rBoundary = { 0, 0, GetWidth(), GetHeight() }; + + HDC hdcMem = CreateCompatibleDC(rGfx.GetHDC()); + HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, m_hBackground); + + //Draw the background + //BitBlt the background onto the screen + BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; + AlphaBlend(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight(), hdcMem, 0, 0, GetWidth(), GetHeight(), opblender); + + SelectObject(hdcMem, hbmOld); + DeleteDC(hdcMem); + + //Drawing the cursor + switch(m_eStyle) + { + case STYLE_FILLED: + { + + + HDC hdcMemCursor = CreateCompatibleDC(rGfx.GetHDC()); + + if(m_bUse3P) + { + RECT r = rBoundary; + r.left = 0; + r.right = GetWidth() - m_3PCursorRightWidth - m_3PCursorLeftWidth; + int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)r.left, (float)r.right, + m_fPos); + + int midstart, midwidth; + midstart = m_3PCursorLeftWidth; + midwidth = nBarWidth; + + //Left + hbmOld = (HBITMAP)SelectObject(hdcMemCursor, m_h3PCursorLeft); + + AlphaBlend(rGfx.GetHDC(), 0, 0, m_3PCursorLeftWidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorLeftWidth, m_3PCursorLeftHeight, opblender); + + //Mid + SelectObject(hdcMemCursor, m_h3PCursorMid); + + AlphaBlend(rGfx.GetHDC(), midstart, 0, midwidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorMidWidth, m_3PCursorMidHeight, opblender); + + //Right + SelectObject(hdcMemCursor, m_h3PCursorRight); + + AlphaBlend(rGfx.GetHDC(), midstart+midwidth, 0, m_3PCursorRightWidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorRightWidth, m_3PCursorRightHeight, opblender); + + // restore previous bitmap + SelectObject(hdcMemCursor, hbmOld); + + } + else + { + RECT r = rBoundary; + int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right), + m_fPos); + r.right = nBarWidth ? nBarWidth : r.left; + + HBITMAP hbmOldCursor = (HBITMAP)SelectObject(hdcMemCursor, m_hFiller); + + BitBlt(rGfx.GetHDC(), 0, 0, nBarWidth, GetHeight(), hdcMemCursor, 0, 0, SRCCOPY); + + SelectObject(hdcMemCursor, hbmOldCursor); + } + + DeleteDC(hdcMemCursor); + + break; + } + //These two cases will be the same + case STYLE_CURSOR: + case STYLE_DASHED_CURSOR: + { + HDC hdcMemCursor = CreateCompatibleDC(rGfx.GetHDC()); + + if(m_bUse3P) + { + RECT r = rBoundary; + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), + m_fPos); + r.left = nCursorPos; + r.right = nCursorPos + m_nCursorWidth; + + int midstart, midwidth; + midstart = r.left+m_3PCursorLeftWidth; + midwidth = m_3PCursorMidWidth; + + //Left + hbmOld = (HBITMAP)SelectObject(hdcMemCursor, m_h3PCursorLeft); + + AlphaBlend(rGfx.GetHDC(), r.left, 0, m_3PCursorLeftWidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorLeftWidth, m_3PCursorLeftHeight, opblender); + + //Mid + SelectObject(hdcMemCursor, m_h3PCursorMid); + + AlphaBlend(rGfx.GetHDC(), midstart, 0, midwidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorMidWidth, m_3PCursorMidHeight, opblender); + + //Right + SelectObject(hdcMemCursor, m_h3PCursorRight); + + AlphaBlend(rGfx.GetHDC(), midstart+midwidth, 0, m_3PCursorRightWidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorRightWidth, m_3PCursorRightHeight, opblender); + + // restore old bitmap + SelectObject(hdcMemCursor, hbmOld); + } + else + { + RECT r = rBoundary; + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), + m_fPos); + r.left = nCursorPos; + r.right = nCursorPos + m_nCursorWidth; + + HBITMAP hbmOldCursor = (HBITMAP)SelectObject(hdcMemCursor, m_hCursor); + + BitBlt(rGfx.GetHDC(), r.left, 0, m_nCursorWidth, GetHeight(), hdcMemCursor, 0, 0, SRCCOPY); + + SelectObject(hdcMemCursor, hbmOldCursor); + } + + DeleteDC(hdcMemCursor); + + break; + } + default: + break; + } + + if( NULL != m_hHighlight ) + { + HDC hdcMemHighlight = CreateCompatibleDC(rGfx.GetHDC()); + HBITMAP hbmOldHighlight = (HBITMAP)SelectObject(hdcMemHighlight, m_hHighlight); + + AlphaBlend(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight(), hdcMemHighlight, 0, 0, m_HighlightWidth, m_HighlightHeight, opblender); + + SelectObject(hdcMemHighlight, hbmOldHighlight); + DeleteDC(hdcMemHighlight); + } +} + + +//** end of LCDSkinnedProgressBar.cpp ************************************ diff --git a/src/thirdparty/LCDUI/LCDSkinnedProgressBar.h b/src/thirdparty/LCDUI/LCDSkinnedProgressBar.h index 3a54778ec81..6c1ec25e28a 100644 --- a/src/thirdparty/LCDUI/LCDSkinnedProgressBar.h +++ b/src/thirdparty/LCDUI/LCDSkinnedProgressBar.h @@ -1,83 +1,83 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDSkinnedProgressBar.h -// -// The CLCDSkinnedProgressBar class draws a progress bar onto the color LCD. -// Unlike the other progress bars, this one uses a bitmap resource to draw -// the progress bar. This scrollbar cannot be scaled. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDSKINNEDPROGRESSBAR_H__ -#define __LCDSKINNEDPROGRESSBAR_H__ - -#include "LCDProgressBar.h" - -class CLCDSkinnedProgressBar : public CLCDProgressBar -{ -public: - CLCDSkinnedProgressBar(void); - virtual ~CLCDSkinnedProgressBar(void); - - //See example bitmaps for how to make the images - void SetBackground(HBITMAP background, int bmpWidth, int bmpHeight); - void SetFiller(HBITMAP cursor, int bmpWidth, int bmpHeight); //STYLE_FILLED - void SetCursor(HBITMAP cursor, int bmpWidth, int bmpHeight); //STYLE_CURSOR - void SetThreePieceCursor(HBITMAP left, int bmpLeftWidth, int bmpLeftHeight, - HBITMAP mid, int bmpMidWidth, int bmpMidHeight, - HBITMAP right, int bmpRightWidth, int bmpRightHeight ); - - //optional -- draw a highlight on top of the progress bar - //(for example, something like a glass effect) - void AddHighlight(HBITMAP highlight, int bmpWidth, int bmpHeight); - - //CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - -private: - HBITMAP m_hBackground; - int m_BackgroundHeight; - int m_BackgroundWidth; - - HBITMAP m_hFiller; - int m_FillerHeight; - int m_FillerWidth; - - HBITMAP m_hCursor; - int m_CursorHeight; - int m_CursorWidth; - - HBITMAP m_hHighlight; - int m_HighlightHeight; - int m_HighlightWidth; - - //3 piece bitmaps, if used - BOOL m_bUse3P; - - HBITMAP m_h3PCursorLeft; - int m_3PCursorLeftHeight; - int m_3PCursorLeftWidth; - - HBITMAP m_h3PCursorMid; - int m_3PCursorMidHeight; - int m_3PCursorMidWidth; - - HBITMAP m_h3PCursorRight; - int m_3PCursorRightHeight; - int m_3PCursorRightWidth; -}; - -#endif - -//** end of LCDSkinnedProgressBar.h ************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDSkinnedProgressBar.h +// +// The CLCDSkinnedProgressBar class draws a progress bar onto the color LCD. +// Unlike the other progress bars, this one uses a bitmap resource to draw +// the progress bar. This scrollbar cannot be scaled. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDSKINNEDPROGRESSBAR_H__ +#define __LCDSKINNEDPROGRESSBAR_H__ + +#include "LCDProgressBar.h" + +class CLCDSkinnedProgressBar : public CLCDProgressBar +{ +public: + CLCDSkinnedProgressBar(void); + virtual ~CLCDSkinnedProgressBar(void); + + //See example bitmaps for how to make the images + void SetBackground(HBITMAP background, int bmpWidth, int bmpHeight); + void SetFiller(HBITMAP cursor, int bmpWidth, int bmpHeight); //STYLE_FILLED + void SetCursor(HBITMAP cursor, int bmpWidth, int bmpHeight); //STYLE_CURSOR + void SetThreePieceCursor(HBITMAP left, int bmpLeftWidth, int bmpLeftHeight, + HBITMAP mid, int bmpMidWidth, int bmpMidHeight, + HBITMAP right, int bmpRightWidth, int bmpRightHeight ); + + //optional -- draw a highlight on top of the progress bar + //(for example, something like a glass effect) + void AddHighlight(HBITMAP highlight, int bmpWidth, int bmpHeight); + + //CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + +private: + HBITMAP m_hBackground; + int m_BackgroundHeight; + int m_BackgroundWidth; + + HBITMAP m_hFiller; + int m_FillerHeight; + int m_FillerWidth; + + HBITMAP m_hCursor; + int m_CursorHeight; + int m_CursorWidth; + + HBITMAP m_hHighlight; + int m_HighlightHeight; + int m_HighlightWidth; + + //3 piece bitmaps, if used + BOOL m_bUse3P; + + HBITMAP m_h3PCursorLeft; + int m_3PCursorLeftHeight; + int m_3PCursorLeftWidth; + + HBITMAP m_h3PCursorMid; + int m_3PCursorMidHeight; + int m_3PCursorMidWidth; + + HBITMAP m_h3PCursorRight; + int m_3PCursorRightHeight; + int m_3PCursorRightWidth; +}; + +#endif + +//** end of LCDSkinnedProgressBar.h ************************************** diff --git a/src/thirdparty/LCDUI/LCDStreamingText.cpp b/src/thirdparty/LCDUI/LCDStreamingText.cpp index 3f55e12ae55..e1dee4d4720 100644 --- a/src/thirdparty/LCDUI/LCDStreamingText.cpp +++ b/src/thirdparty/LCDUI/LCDStreamingText.cpp @@ -1,755 +1,755 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDStreamingText.cpp -// -// The CLCDStreamingText class draws streaming text onto the LCD. -// Streaming text is a single line of text that is repeatedly streamed -// horizontally across the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - -//************************************************************************ -// -// CLCDStreamingText::CLCDStreamingText -// -//************************************************************************ - -CLCDStreamingText::CLCDStreamingText() -{ - m_sText.erase(m_sText.begin(), m_sText.end()); - m_sGapText.erase(m_sGapText.begin(), m_sGapText.end()); - - m_sGapText.assign(_T(" ")); - m_hFont = NULL; - m_nTextAlignment = DT_LEFT; - - m_bRedoColors = TRUE; -} - - -//************************************************************************ -// -// CLCDStreamingText::~CLCDStreamingText -// -//************************************************************************ - -CLCDStreamingText::~CLCDStreamingText() -{ - RemoveAllText(); - if (m_hFont) - { - DeleteObject(m_hFont); - m_hFont = NULL; - } -} - - -//************************************************************************ -// -// CLCDStreamingText::Initialize -// -//************************************************************************ - -HRESULT CLCDStreamingText::Initialize(void) -{ - m_eState = STATE_DELAY; - m_dwStartDelay = 2000; - m_dwSpeed = 7; - m_dwStepInPixels = 7; - m_dwLastUpdate = 0; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_bRecalcExtent = FALSE; - m_pQueueHead = NULL; - m_fFractDistance = 0.0f; - - m_hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); - if(NULL != m_hFont) - { - SetFontPointSize(DEFAULT_POINTSIZE); - } - - //return CLCDCollection::Initialize(); - return ERROR_SUCCESS; -} - - -//************************************************************************ -// -// CLCDStreamingText::ResetUpdate -// -//************************************************************************ - -void CLCDStreamingText::ResetUpdate(void) -{ - m_eState = STATE_DELAY; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_pQueueHead = NULL; - m_fFractDistance = 0.0f; - - // remove, re-add, and recalculate the text - m_bRecalcExtent = TRUE; - RemoveAllText(); - AddText(m_sText.c_str()); -} - - -//************************************************************************ -// -// CLCDStreamingText::Show -// -//************************************************************************ - -void CLCDStreamingText::Show(BOOL bShow) -{ - CLCDCollection::Show(bShow); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetText -// -//************************************************************************ - -void CLCDStreamingText::SetText(LPCTSTR szText) -{ - LCDUIASSERT(NULL != szText); - if(szText && _tcscmp(m_sText.c_str(), szText)) - { - m_sText.assign(szText); - m_bRecalcExtent = TRUE; - ResetUpdate(); - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetOrigin -// -//************************************************************************ - -void CLCDStreamingText::SetOrigin(POINT pt) -{ - m_Origin = pt; - SetOrigin(pt.x, pt.y); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetOrigin -// -//************************************************************************ - -void CLCDStreamingText::SetOrigin(int nX, int nY) -{ - m_Origin.x = nX; - m_Origin.y = nY; - - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it++; - LCDUIASSERT(NULL != pObject); - - POINT ptOldOrigin = pObject->GetOrigin(); - pObject->SetOrigin(nX, nY); - - if ( (ptOldOrigin.x != nX) && (ptOldOrigin.y != nY) ) - { - ResetUpdate(); - break; - } - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetSize -// -//************************************************************************ - -void CLCDStreamingText::SetSize(SIZE& size) -{ - CLCDBase::SetSize(size); - - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - if (it != m_Objects.end()) - { - CLCDBase *pObject = *it; - pObject->SetSize(size); - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetSize -// -//************************************************************************ - -void CLCDStreamingText::SetSize(int nCX, int nCY) -{ - SIZE size = { nCX, nCY }; - SetSize(size); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetBackgroundMode -// -//************************************************************************ - -void CLCDStreamingText::SetBackgroundMode(int nMode) -{ - m_bRedoColors = TRUE; - CLCDBase::SetBackgroundMode(nMode); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetForegroundColor -// -//************************************************************************ - -void CLCDStreamingText::SetForegroundColor(COLORREF crForeground) -{ - m_bRedoColors = TRUE; - CLCDBase::SetForegroundColor(crForeground); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetBackgroundColor -// -//************************************************************************ - -void CLCDStreamingText::SetBackgroundColor(COLORREF crBackground) -{ - m_bRedoColors = TRUE; - CLCDBase::SetBackgroundColor(crBackground); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetGapText -// -//************************************************************************ - -void CLCDStreamingText::SetGapText(LPCTSTR szGapText) -{ - LCDUIASSERT(NULL != szGapText); - if(szGapText && _tcscmp(m_sGapText.c_str(), szGapText)) - { - m_sGapText.assign(szGapText); - m_bRecalcExtent = TRUE; - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetFont -// -//************************************************************************ - -void CLCDStreamingText::SetFont(LOGFONT& lf) -{ - if (m_hFont) - { - DeleteObject(m_hFont); - m_hFont = NULL; - } - - m_hFont = CreateFontIndirect(&lf); - m_bRecalcExtent = TRUE; -} - - -//************************************************************************ -// -// CLCDStreamingText::GetFont -// -//************************************************************************ - -HFONT CLCDStreamingText::GetFont() -{ - return m_hFont; -} - - -//************************************************************************ -// -// CLCDText::SetFontFaceName -// -//************************************************************************ - -void CLCDStreamingText::SetFontFaceName(LPCTSTR szFontName) -{ - // if NULL, uses the default gui font - if (NULL == szFontName) - return; - - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - DeleteObject(m_hFont); - m_hFont = NULL; - - LCDUI_tcsncpy(lf.lfFaceName, szFontName, LF_FACESIZE); - - m_hFont = CreateFontIndirect(&lf); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetFontPointSize -// -//************************************************************************ - -void CLCDStreamingText::SetFontPointSize(int nPointSize) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - DeleteObject(m_hFont); - m_hFont = NULL; - - lf.lfHeight = -MulDiv(nPointSize, DEFAULT_DPI, 72); - - m_hFont = CreateFontIndirect(&lf); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetFontWeight -// -//************************************************************************ - -void CLCDStreamingText::SetFontWeight(int nWeight) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - DeleteObject(m_hFont); - m_hFont = NULL; - - lf.lfWeight = nWeight; - - m_hFont = CreateFontIndirect(&lf); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetFontColor -// -//************************************************************************ - -void CLCDStreamingText::SetFontColor(COLORREF color) -{ - SetForegroundColor(color); - - // Apply it to any existing text objects - for (size_t i = 0; i < m_Objects.size(); i++) - { - m_Objects[i]->SetForegroundColor(color); - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetAlignment -// -// only relevant if no streaming -//************************************************************************ - -void CLCDStreamingText::SetAlignment(int nAlignment) -{ - m_nTextAlignment = nAlignment; -} - - -//************************************************************************ -// -// CLCDStreamingText::AddText -// -//************************************************************************ - -int CLCDStreamingText::AddText(LPCTSTR szText) -{ - - CLCDText* pText = new CLCDText; - pText->Initialize(); - pText->SetText(szText); - pText->SetOrigin(GetOrigin().x, GetOrigin().y); - pText->SetLogicalOrigin(GetLogicalOrigin().x, GetLogicalOrigin().y); - pText->SetSize(GetWidth(), GetHeight()); - pText->SetBackgroundMode(m_nBkMode); - pText->SetBackgroundColor(m_crBackgroundColor); - pText->SetFontColor(m_crForegroundColor); - - LOGFONT lf; - GetObject(m_hFont, sizeof(LOGFONT), &lf); - pText->SetFont(lf); - - m_bRecalcExtent = TRUE; - - AddObject(pText); - - - if (NULL == m_pQueueHead) - { - m_pQueueHead = pText; - } - - // return the zero-based index - return (int)(m_Objects.size()-1); -} - - -//************************************************************************ -// -// CLCDStreamingText::RemoveText -// -//************************************************************************ - -void CLCDStreamingText::RemoveText(int nIndex) -{ - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - int i = 0; - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it; - LCDUIASSERT(NULL != pObject); - - if (i == nIndex) - { - m_Objects.erase(it); - if(NULL != pObject) - { - delete pObject; - } - break; - } - - ++it; - ++i; - } -} - - -//************************************************************************ -// -// CLCDStreamingText::RemoveAllText -// -//************************************************************************ - -void CLCDStreamingText::RemoveAllText() -{ - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - // we need to delete all the text objects that were placed in to m_Objects - CLCDBase *pObject = *it; - LCDUIASSERT(NULL != pObject); - - if(NULL != pObject) - { - delete pObject; - } - ++it; - } - m_Objects.erase(m_Objects.begin(), m_Objects.end()); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetStartDelay -// -//************************************************************************ - -void CLCDStreamingText::SetStartDelay(DWORD dwMilliseconds) -{ - m_dwStartDelay = dwMilliseconds; -} - - -//************************************************************************ -// -// CLCDStreamingText::SetSpeed -// -//************************************************************************ - -void CLCDStreamingText::SetSpeed(DWORD dwSpeed) -{ - m_dwSpeed = dwSpeed; -} - -//************************************************************************ -// -// CLCDStreamingText::SetScrollingStep: sets the number of pixels the text -// will jump when it scrolls -// -//************************************************************************ - -void CLCDStreamingText::SetScrollingStep(DWORD dwStepInPixels) -{ - m_dwStepInPixels = dwStepInPixels; -} - -//************************************************************************ -// -// CLCDStreamingText::OnUpdate -// -//************************************************************************ - -void CLCDStreamingText::OnUpdate(DWORD dwTimestamp) -{ - m_dwEllapsedTime = (dwTimestamp - m_dwLastUpdate); -} - - -//************************************************************************ -// -// CLCDStreamingText::OnDraw -// -//************************************************************************ - -void CLCDStreamingText::OnDraw(CLCDGfxBase &rGfx) -{ - - if (m_bRecalcExtent) - { - // this just recalculates the text extents - RecalcTextBoxes(rGfx); - m_bRecalcExtent = FALSE; - return; - } - - switch(m_eState) - { - case STATE_DELAY: - if (m_dwEllapsedTime > m_dwStartDelay) - { - m_eState = STATE_SCROLL; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - } - break; - case STATE_SCROLL: - { - // update the positions - float fDistance = (float)(m_dwSpeed * m_dwEllapsedTime) / 1000.0f; - m_dwLastUpdate = GetTickCount(); - - if (m_Objects.size() > 1) - { - // extract any previous fractional remainder - // and add it to the current distance - float fTotDistance = (fDistance + m_fFractDistance); - m_fFractDistance = (fTotDistance >= (float)m_dwStepInPixels) ? (float)(fTotDistance - (int)fTotDistance) : fTotDistance; - - if (fTotDistance < 0.0f) - fTotDistance = 0.0f; - if (m_fFractDistance < 0.0f) - m_fFractDistance = 0.0f; - - if (fTotDistance >= (float)m_dwStepInPixels) - ApplyOrigins(-1 * (int)fTotDistance); // left - } - } - break; - default: - break; - } - - if( m_bRedoColors ) - { - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - // we need to delete all the text objects that were placed in to m_Objects - CLCDBase *pObject = *it; - LCDUIASSERT(NULL != pObject); - - if(NULL != pObject) - { - pObject->SetBackgroundMode(m_nBkMode); - pObject->SetBackgroundColor(m_crBackgroundColor); - pObject->SetForegroundColor(m_crForegroundColor); - } - ++it; - } - - m_bRedoColors = FALSE; - } - - CLCDCollection::OnDraw(rGfx); -} - - -//************************************************************************ -// -// CLCDStreamingText::C -// -//************************************************************************ - -BOOL CLCDStreamingText::RecalcTextBoxes(CLCDGfxBase &rGfx) -{ - - // check if we need to add another text box - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - - if (it == m_Objects.end()) - return FALSE; - - CLCDBase* pObject = *it; - CLCDText* pText = (CLCDText*)pObject; - LCDUIASSERT(NULL != pObject); - - LOGFONT lf; - GetObject(m_hFont, sizeof(LOGFONT), &lf); - pText->SetFont(lf); - - // this will re-evaluate the main text object - LCDUIASSERT(m_Objects.size() == 1); - pText->CalculateExtent(TRUE); - - if (it != m_Objects.end()) - { - if (pText->GetHExtent().cx > GetWidth()) - { - - pText->SetAlignment(DT_LEFT); - - // add a gap - AddText(m_sGapText.c_str()); - // add another text - AddText(m_sText.c_str()); - // add last gap - AddText(m_sGapText.c_str()); - } - else - { - pText->SetAlignment(m_nTextAlignment); - } - } - - // this will re-evaluate the other text objects - CLCDCollection::OnDraw(rGfx); - RecalcTextBoxOrigins(); - - return TRUE; -} - - -//************************************************************************ -// -// CLCDStreamingText::RecalcTextBoxOrigins -// -// Puts all the text boxes in order next to each other -//************************************************************************ - -void CLCDStreamingText::RecalcTextBoxOrigins() -{ - - if (m_Objects.size() <= 1) - return; - - // draw everyone to the left by the offset - int nOrgOffset = 0; - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase* pObject = *it; - CLCDText* pText = (CLCDText*)pObject; - LCDUIASSERT(NULL != pObject); - - pText->SetLogicalSize(pText->GetHExtent().cx, pText->GetHExtent().cy); - - // string can be empty which generates zero logical space - //LCDUIASSERT(pText->GetLogicalSize().cx); - //LCDUIASSERT(pText->GetLogicalSize().cy); - - POINT& ptOrigin = pText->GetLogicalOrigin(); - - if (nOrgOffset == 0) - { - nOrgOffset = pText->GetLogicalOrigin().x; - } - - pText->SetLogicalOrigin(nOrgOffset, ptOrigin.y); - nOrgOffset += pText->GetHExtent().cx; - - ++it; - } - -} - - -//************************************************************************ -// -// CLCDStreamingText::ApplyOrigins -// -//************************************************************************ - -void CLCDStreamingText::ApplyOrigins(int nOffset) -{ - - // draw everyone to the left by the offset - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase* pObject = *it; - CLCDText* pText = (CLCDText*)pObject; - LCDUIASSERT(NULL != pObject); - - POINT& ptOrigin = pText->GetLogicalOrigin(); - - pText->SetLogicalOrigin(ptOrigin.x + nOffset, ptOrigin.y); - - ++it; - } - - // If the active box is no longer visible, - // pop it off the push it to the end of the list - if (abs(m_pQueueHead->GetLogicalOrigin().x) >= m_pQueueHead->GetHExtent().cx) - { - RemoveObject(0); - AddObject(m_pQueueHead); - RecalcTextBoxOrigins(); - m_pQueueHead = (CLCDText*)RetrieveObject(0); - } -} - - -//** end of LCDStreamingText.cpp ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDStreamingText.cpp +// +// The CLCDStreamingText class draws streaming text onto the LCD. +// Streaming text is a single line of text that is repeatedly streamed +// horizontally across the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + +//************************************************************************ +// +// CLCDStreamingText::CLCDStreamingText +// +//************************************************************************ + +CLCDStreamingText::CLCDStreamingText() +{ + m_sText.erase(m_sText.begin(), m_sText.end()); + m_sGapText.erase(m_sGapText.begin(), m_sGapText.end()); + + m_sGapText.assign(_T(" ")); + m_hFont = NULL; + m_nTextAlignment = DT_LEFT; + + m_bRedoColors = TRUE; +} + + +//************************************************************************ +// +// CLCDStreamingText::~CLCDStreamingText +// +//************************************************************************ + +CLCDStreamingText::~CLCDStreamingText() +{ + RemoveAllText(); + if (m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } +} + + +//************************************************************************ +// +// CLCDStreamingText::Initialize +// +//************************************************************************ + +HRESULT CLCDStreamingText::Initialize(void) +{ + m_eState = STATE_DELAY; + m_dwStartDelay = 2000; + m_dwSpeed = 7; + m_dwStepInPixels = 7; + m_dwLastUpdate = 0; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_bRecalcExtent = FALSE; + m_pQueueHead = NULL; + m_fFractDistance = 0.0f; + + m_hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); + if(NULL != m_hFont) + { + SetFontPointSize(DEFAULT_POINTSIZE); + } + + //return CLCDCollection::Initialize(); + return ERROR_SUCCESS; +} + + +//************************************************************************ +// +// CLCDStreamingText::ResetUpdate +// +//************************************************************************ + +void CLCDStreamingText::ResetUpdate(void) +{ + m_eState = STATE_DELAY; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_pQueueHead = NULL; + m_fFractDistance = 0.0f; + + // remove, re-add, and recalculate the text + m_bRecalcExtent = TRUE; + RemoveAllText(); + AddText(m_sText.c_str()); +} + + +//************************************************************************ +// +// CLCDStreamingText::Show +// +//************************************************************************ + +void CLCDStreamingText::Show(BOOL bShow) +{ + CLCDCollection::Show(bShow); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetText +// +//************************************************************************ + +void CLCDStreamingText::SetText(LPCTSTR szText) +{ + LCDUIASSERT(NULL != szText); + if(szText && _tcscmp(m_sText.c_str(), szText)) + { + m_sText.assign(szText); + m_bRecalcExtent = TRUE; + ResetUpdate(); + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetOrigin +// +//************************************************************************ + +void CLCDStreamingText::SetOrigin(POINT pt) +{ + m_Origin = pt; + SetOrigin(pt.x, pt.y); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetOrigin +// +//************************************************************************ + +void CLCDStreamingText::SetOrigin(int nX, int nY) +{ + m_Origin.x = nX; + m_Origin.y = nY; + + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it++; + LCDUIASSERT(NULL != pObject); + + POINT ptOldOrigin = pObject->GetOrigin(); + pObject->SetOrigin(nX, nY); + + if ( (ptOldOrigin.x != nX) && (ptOldOrigin.y != nY) ) + { + ResetUpdate(); + break; + } + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetSize +// +//************************************************************************ + +void CLCDStreamingText::SetSize(SIZE& size) +{ + CLCDBase::SetSize(size); + + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + if (it != m_Objects.end()) + { + CLCDBase *pObject = *it; + pObject->SetSize(size); + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetSize +// +//************************************************************************ + +void CLCDStreamingText::SetSize(int nCX, int nCY) +{ + SIZE size = { nCX, nCY }; + SetSize(size); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetBackgroundMode +// +//************************************************************************ + +void CLCDStreamingText::SetBackgroundMode(int nMode) +{ + m_bRedoColors = TRUE; + CLCDBase::SetBackgroundMode(nMode); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetForegroundColor +// +//************************************************************************ + +void CLCDStreamingText::SetForegroundColor(COLORREF crForeground) +{ + m_bRedoColors = TRUE; + CLCDBase::SetForegroundColor(crForeground); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetBackgroundColor +// +//************************************************************************ + +void CLCDStreamingText::SetBackgroundColor(COLORREF crBackground) +{ + m_bRedoColors = TRUE; + CLCDBase::SetBackgroundColor(crBackground); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetGapText +// +//************************************************************************ + +void CLCDStreamingText::SetGapText(LPCTSTR szGapText) +{ + LCDUIASSERT(NULL != szGapText); + if(szGapText && _tcscmp(m_sGapText.c_str(), szGapText)) + { + m_sGapText.assign(szGapText); + m_bRecalcExtent = TRUE; + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetFont +// +//************************************************************************ + +void CLCDStreamingText::SetFont(LOGFONT& lf) +{ + if (m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } + + m_hFont = CreateFontIndirect(&lf); + m_bRecalcExtent = TRUE; +} + + +//************************************************************************ +// +// CLCDStreamingText::GetFont +// +//************************************************************************ + +HFONT CLCDStreamingText::GetFont() +{ + return m_hFont; +} + + +//************************************************************************ +// +// CLCDText::SetFontFaceName +// +//************************************************************************ + +void CLCDStreamingText::SetFontFaceName(LPCTSTR szFontName) +{ + // if NULL, uses the default gui font + if (NULL == szFontName) + return; + + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + DeleteObject(m_hFont); + m_hFont = NULL; + + LCDUI_tcsncpy(lf.lfFaceName, szFontName, LF_FACESIZE); + + m_hFont = CreateFontIndirect(&lf); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetFontPointSize +// +//************************************************************************ + +void CLCDStreamingText::SetFontPointSize(int nPointSize) +{ + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + DeleteObject(m_hFont); + m_hFont = NULL; + + lf.lfHeight = -MulDiv(nPointSize, DEFAULT_DPI, 72); + + m_hFont = CreateFontIndirect(&lf); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetFontWeight +// +//************************************************************************ + +void CLCDStreamingText::SetFontWeight(int nWeight) +{ + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + DeleteObject(m_hFont); + m_hFont = NULL; + + lf.lfWeight = nWeight; + + m_hFont = CreateFontIndirect(&lf); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetFontColor +// +//************************************************************************ + +void CLCDStreamingText::SetFontColor(COLORREF color) +{ + SetForegroundColor(color); + + // Apply it to any existing text objects + for (size_t i = 0; i < m_Objects.size(); i++) + { + m_Objects[i]->SetForegroundColor(color); + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetAlignment +// +// only relevant if no streaming +//************************************************************************ + +void CLCDStreamingText::SetAlignment(int nAlignment) +{ + m_nTextAlignment = nAlignment; +} + + +//************************************************************************ +// +// CLCDStreamingText::AddText +// +//************************************************************************ + +int CLCDStreamingText::AddText(LPCTSTR szText) +{ + + CLCDText* pText = new CLCDText; + pText->Initialize(); + pText->SetText(szText); + pText->SetOrigin(GetOrigin().x, GetOrigin().y); + pText->SetLogicalOrigin(GetLogicalOrigin().x, GetLogicalOrigin().y); + pText->SetSize(GetWidth(), GetHeight()); + pText->SetBackgroundMode(m_nBkMode); + pText->SetBackgroundColor(m_crBackgroundColor); + pText->SetFontColor(m_crForegroundColor); + + LOGFONT lf; + GetObject(m_hFont, sizeof(LOGFONT), &lf); + pText->SetFont(lf); + + m_bRecalcExtent = TRUE; + + AddObject(pText); + + + if (NULL == m_pQueueHead) + { + m_pQueueHead = pText; + } + + // return the zero-based index + return (int)(m_Objects.size()-1); +} + + +//************************************************************************ +// +// CLCDStreamingText::RemoveText +// +//************************************************************************ + +void CLCDStreamingText::RemoveText(int nIndex) +{ + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + int i = 0; + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it; + LCDUIASSERT(NULL != pObject); + + if (i == nIndex) + { + m_Objects.erase(it); + if(NULL != pObject) + { + delete pObject; + } + break; + } + + ++it; + ++i; + } +} + + +//************************************************************************ +// +// CLCDStreamingText::RemoveAllText +// +//************************************************************************ + +void CLCDStreamingText::RemoveAllText() +{ + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + // we need to delete all the text objects that were placed in to m_Objects + CLCDBase *pObject = *it; + LCDUIASSERT(NULL != pObject); + + if(NULL != pObject) + { + delete pObject; + } + ++it; + } + m_Objects.erase(m_Objects.begin(), m_Objects.end()); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetStartDelay +// +//************************************************************************ + +void CLCDStreamingText::SetStartDelay(DWORD dwMilliseconds) +{ + m_dwStartDelay = dwMilliseconds; +} + + +//************************************************************************ +// +// CLCDStreamingText::SetSpeed +// +//************************************************************************ + +void CLCDStreamingText::SetSpeed(DWORD dwSpeed) +{ + m_dwSpeed = dwSpeed; +} + +//************************************************************************ +// +// CLCDStreamingText::SetScrollingStep: sets the number of pixels the text +// will jump when it scrolls +// +//************************************************************************ + +void CLCDStreamingText::SetScrollingStep(DWORD dwStepInPixels) +{ + m_dwStepInPixels = dwStepInPixels; +} + +//************************************************************************ +// +// CLCDStreamingText::OnUpdate +// +//************************************************************************ + +void CLCDStreamingText::OnUpdate(DWORD dwTimestamp) +{ + m_dwEllapsedTime = (dwTimestamp - m_dwLastUpdate); +} + + +//************************************************************************ +// +// CLCDStreamingText::OnDraw +// +//************************************************************************ + +void CLCDStreamingText::OnDraw(CLCDGfxBase &rGfx) +{ + + if (m_bRecalcExtent) + { + // this just recalculates the text extents + RecalcTextBoxes(rGfx); + m_bRecalcExtent = FALSE; + return; + } + + switch(m_eState) + { + case STATE_DELAY: + if (m_dwEllapsedTime > m_dwStartDelay) + { + m_eState = STATE_SCROLL; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + } + break; + case STATE_SCROLL: + { + // update the positions + float fDistance = (float)(m_dwSpeed * m_dwEllapsedTime) / 1000.0f; + m_dwLastUpdate = GetTickCount(); + + if (m_Objects.size() > 1) + { + // extract any previous fractional remainder + // and add it to the current distance + float fTotDistance = (fDistance + m_fFractDistance); + m_fFractDistance = (fTotDistance >= (float)m_dwStepInPixels) ? (float)(fTotDistance - (int)fTotDistance) : fTotDistance; + + if (fTotDistance < 0.0f) + fTotDistance = 0.0f; + if (m_fFractDistance < 0.0f) + m_fFractDistance = 0.0f; + + if (fTotDistance >= (float)m_dwStepInPixels) + ApplyOrigins(-1 * (int)fTotDistance); // left + } + } + break; + default: + break; + } + + if( m_bRedoColors ) + { + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + // we need to delete all the text objects that were placed in to m_Objects + CLCDBase *pObject = *it; + LCDUIASSERT(NULL != pObject); + + if(NULL != pObject) + { + pObject->SetBackgroundMode(m_nBkMode); + pObject->SetBackgroundColor(m_crBackgroundColor); + pObject->SetForegroundColor(m_crForegroundColor); + } + ++it; + } + + m_bRedoColors = FALSE; + } + + CLCDCollection::OnDraw(rGfx); +} + + +//************************************************************************ +// +// CLCDStreamingText::C +// +//************************************************************************ + +BOOL CLCDStreamingText::RecalcTextBoxes(CLCDGfxBase &rGfx) +{ + + // check if we need to add another text box + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + + if (it == m_Objects.end()) + return FALSE; + + CLCDBase* pObject = *it; + CLCDText* pText = (CLCDText*)pObject; + LCDUIASSERT(NULL != pObject); + + LOGFONT lf; + GetObject(m_hFont, sizeof(LOGFONT), &lf); + pText->SetFont(lf); + + // this will re-evaluate the main text object + LCDUIASSERT(m_Objects.size() == 1); + pText->CalculateExtent(TRUE); + + if (it != m_Objects.end()) + { + if (pText->GetHExtent().cx > GetWidth()) + { + + pText->SetAlignment(DT_LEFT); + + // add a gap + AddText(m_sGapText.c_str()); + // add another text + AddText(m_sText.c_str()); + // add last gap + AddText(m_sGapText.c_str()); + } + else + { + pText->SetAlignment(m_nTextAlignment); + } + } + + // this will re-evaluate the other text objects + CLCDCollection::OnDraw(rGfx); + RecalcTextBoxOrigins(); + + return TRUE; +} + + +//************************************************************************ +// +// CLCDStreamingText::RecalcTextBoxOrigins +// +// Puts all the text boxes in order next to each other +//************************************************************************ + +void CLCDStreamingText::RecalcTextBoxOrigins() +{ + + if (m_Objects.size() <= 1) + return; + + // draw everyone to the left by the offset + int nOrgOffset = 0; + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase* pObject = *it; + CLCDText* pText = (CLCDText*)pObject; + LCDUIASSERT(NULL != pObject); + + pText->SetLogicalSize(pText->GetHExtent().cx, pText->GetHExtent().cy); + + // string can be empty which generates zero logical space + //LCDUIASSERT(pText->GetLogicalSize().cx); + //LCDUIASSERT(pText->GetLogicalSize().cy); + + POINT& ptOrigin = pText->GetLogicalOrigin(); + + if (nOrgOffset == 0) + { + nOrgOffset = pText->GetLogicalOrigin().x; + } + + pText->SetLogicalOrigin(nOrgOffset, ptOrigin.y); + nOrgOffset += pText->GetHExtent().cx; + + ++it; + } + +} + + +//************************************************************************ +// +// CLCDStreamingText::ApplyOrigins +// +//************************************************************************ + +void CLCDStreamingText::ApplyOrigins(int nOffset) +{ + + // draw everyone to the left by the offset + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase* pObject = *it; + CLCDText* pText = (CLCDText*)pObject; + LCDUIASSERT(NULL != pObject); + + POINT& ptOrigin = pText->GetLogicalOrigin(); + + pText->SetLogicalOrigin(ptOrigin.x + nOffset, ptOrigin.y); + + ++it; + } + + // If the active box is no longer visible, + // pop it off the push it to the end of the list + if (abs(m_pQueueHead->GetLogicalOrigin().x) >= m_pQueueHead->GetHExtent().cx) + { + RemoveObject(0); + AddObject(m_pQueueHead); + RecalcTextBoxOrigins(); + m_pQueueHead = (CLCDText*)RetrieveObject(0); + } +} + + +//** end of LCDStreamingText.cpp ******************************************* diff --git a/src/thirdparty/LCDUI/LCDStreamingText.h b/src/thirdparty/LCDUI/LCDStreamingText.h index d4c9880d758..1848ad364f8 100644 --- a/src/thirdparty/LCDUI/LCDStreamingText.h +++ b/src/thirdparty/LCDUI/LCDStreamingText.h @@ -1,120 +1,120 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDStreamingText.h -// -// The CLCDStreamingText class draws streaming text onto the LCD. -// Streaming text is a single line of text that is repeatedly streamed -// horizontally across the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDSTREAMINGTEXT_H_INCLUDED_ -#define _LCDSTREAMINGTEXT_H_INCLUDED_ - -#include "LCDBase.h" -#include "LCDCollection.h" -#include "LCDText.h" - -#include - -class CLCDStreamingText: public CLCDCollection -{ - -public: - CLCDStreamingText(); - virtual ~CLCDStreamingText(); - - // CLCDBase - virtual HRESULT Initialize(void); - virtual void ResetUpdate(void); - virtual void Show(BOOL bShow); - virtual void SetOrigin(POINT pt); - virtual void SetOrigin(int nX, int nY); - virtual void SetSize(SIZE& size); - virtual void SetSize(int nCX, int nCY); - virtual void SetBackgroundMode(int nMode); - virtual void SetForegroundColor(COLORREF crForeground); - virtual void SetBackgroundColor(COLORREF crBackground); - - void SetText(LPCTSTR szText); - void SetGapText(LPCTSTR szGapText); - void SetStartDelay(DWORD dwMilliseconds); - void SetSpeed(DWORD dwSpeed); - void SetScrollingStep(DWORD dwStepInPixels); - void SetAlignment(int nAlignment = DT_LEFT); - void SetFont(LOGFONT& lf); - void SetFontFaceName(LPCTSTR szFontName); - void SetFontPointSize(int nSize); - void SetFontWeight(int nPointSize); - void SetFontColor(COLORREF color); - HFONT GetFont(void); - - enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 8 }; - -protected: - virtual void OnUpdate(DWORD dwTimestamp); - virtual void OnDraw(CLCDGfxBase &rGfx); - -private: - int AddText(LPCTSTR szText); - void RemoveText(int nIndex); - void RemoveAllText(); - -private: - BOOL RecalcTextBoxes(CLCDGfxBase &rGfx); - void RecalcTextBoxOrigins(); - void ApplyOrigins(int nOffset); - - enum eSCROLL_STATES { STATE_DELAY, STATE_SCROLL}; - - // ellapsed time in state - DWORD m_dwEllapsedTime; - - // milliseconds - DWORD m_dwStartDelay; - - // pixels/second - DWORD m_dwSpeed; - - // Number of pixels to shift - DWORD m_dwStepInPixels; - - // milliseconds - DWORD m_dwLastUpdate; - - eSCROLL_STATES m_eState; - BOOL m_bRecalcExtent; - - CLCDText *m_pQueueHead; - - COLORREF m_crColor; - BOOL m_bRedoColors; - -#ifdef UNICODE - std::wstring m_sText; - std::wstring m_sGapText; -#else - std::string m_sText; - std::string m_sGapText; -#endif - - HFONT m_hFont; - int m_nTextAlignment; - float m_fFractDistance; -}; - - -#endif // !_LCDSTREAMINGTEXT_H_INCLUDED_ - -//** end of LCDStreamingText.h ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDStreamingText.h +// +// The CLCDStreamingText class draws streaming text onto the LCD. +// Streaming text is a single line of text that is repeatedly streamed +// horizontally across the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDSTREAMINGTEXT_H_INCLUDED_ +#define _LCDSTREAMINGTEXT_H_INCLUDED_ + +#include "LCDBase.h" +#include "LCDCollection.h" +#include "LCDText.h" + +#include + +class CLCDStreamingText: public CLCDCollection +{ + +public: + CLCDStreamingText(); + virtual ~CLCDStreamingText(); + + // CLCDBase + virtual HRESULT Initialize(void); + virtual void ResetUpdate(void); + virtual void Show(BOOL bShow); + virtual void SetOrigin(POINT pt); + virtual void SetOrigin(int nX, int nY); + virtual void SetSize(SIZE& size); + virtual void SetSize(int nCX, int nCY); + virtual void SetBackgroundMode(int nMode); + virtual void SetForegroundColor(COLORREF crForeground); + virtual void SetBackgroundColor(COLORREF crBackground); + + void SetText(LPCTSTR szText); + void SetGapText(LPCTSTR szGapText); + void SetStartDelay(DWORD dwMilliseconds); + void SetSpeed(DWORD dwSpeed); + void SetScrollingStep(DWORD dwStepInPixels); + void SetAlignment(int nAlignment = DT_LEFT); + void SetFont(LOGFONT& lf); + void SetFontFaceName(LPCTSTR szFontName); + void SetFontPointSize(int nSize); + void SetFontWeight(int nPointSize); + void SetFontColor(COLORREF color); + HFONT GetFont(void); + + enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 8 }; + +protected: + virtual void OnUpdate(DWORD dwTimestamp); + virtual void OnDraw(CLCDGfxBase &rGfx); + +private: + int AddText(LPCTSTR szText); + void RemoveText(int nIndex); + void RemoveAllText(); + +private: + BOOL RecalcTextBoxes(CLCDGfxBase &rGfx); + void RecalcTextBoxOrigins(); + void ApplyOrigins(int nOffset); + + enum eSCROLL_STATES { STATE_DELAY, STATE_SCROLL}; + + // ellapsed time in state + DWORD m_dwEllapsedTime; + + // milliseconds + DWORD m_dwStartDelay; + + // pixels/second + DWORD m_dwSpeed; + + // Number of pixels to shift + DWORD m_dwStepInPixels; + + // milliseconds + DWORD m_dwLastUpdate; + + eSCROLL_STATES m_eState; + BOOL m_bRecalcExtent; + + CLCDText *m_pQueueHead; + + COLORREF m_crColor; + BOOL m_bRedoColors; + +#ifdef UNICODE + std::wstring m_sText; + std::wstring m_sGapText; +#else + std::string m_sText; + std::string m_sGapText; +#endif + + HFONT m_hFont; + int m_nTextAlignment; + float m_fFractDistance; +}; + + +#endif // !_LCDSTREAMINGTEXT_H_INCLUDED_ + +//** end of LCDStreamingText.h ******************************************* diff --git a/src/thirdparty/LCDUI/LCDText.cpp b/src/thirdparty/LCDUI/LCDText.cpp index 94d9d030c6e..67e8a2da24f 100644 --- a/src/thirdparty/LCDUI/LCDText.cpp +++ b/src/thirdparty/LCDUI/LCDText.cpp @@ -1,467 +1,467 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDText.cpp -// -// The CLCDText class draws simple text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDText::CLCDText -// -//************************************************************************ - -CLCDText::CLCDText(void) -: m_hFont(NULL), - m_nTextLength(0), - m_nTextFormat(DT_LEFT | DT_NOPREFIX), - m_bRecalcExtent(TRUE), - m_nTextAlignment(DT_LEFT) -{ - ZeroMemory(&m_dtp, sizeof(DRAWTEXTPARAMS)); - m_dtp.cbSize = sizeof(DRAWTEXTPARAMS); - ZeroMemory(&m_sizeVExtent, sizeof(m_sizeVExtent)); - ZeroMemory(&m_sizeHExtent, sizeof(m_sizeHExtent)); - SetBackgroundMode(TRANSPARENT); - Initialize(); -} - - -//************************************************************************ -// -// CLCDText::~CLCDText -// -//************************************************************************ - -CLCDText::~CLCDText(void) -{ - if (m_hFont) - { - DeleteObject(m_hFont); - m_hFont = NULL; - } -} - - -//************************************************************************ -// -// CLCDText::Initialize -// -//************************************************************************ - -HRESULT CLCDText::Initialize() -{ - m_hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); - if(NULL != m_hFont) - { - SetFontPointSize(DEFAULT_POINTSIZE); - } - SetForegroundColor(RGB(255, 255, 255)); - return (NULL != m_hFont) ? S_OK : E_OUTOFMEMORY; -} - - -//************************************************************************ -// -// CLCDText::SetFont -// -//************************************************************************ - -void CLCDText::SetFont(LOGFONT& lf) -{ - if (m_hFont) - { - DeleteObject(m_hFont); - m_hFont = NULL; - } - - m_hFont = CreateFontIndirect(&lf); - m_bRecalcExtent = TRUE; -} - - -//************************************************************************ -// -// CLCDText::GetFont -// -//************************************************************************ - -HFONT CLCDText::GetFont() -{ - return m_hFont; -} - - -//************************************************************************ -// -// CLCDText::SetFontFaceName -// -//************************************************************************ - -void CLCDText::SetFontFaceName(LPCTSTR szFontName) -{ - // if NULL, uses the default gui font - if (NULL == szFontName) - { - return; - } - - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - LCDUI_tcsncpy(lf.lfFaceName, szFontName, LF_FACESIZE); - - SetFont(lf); -} - - -//************************************************************************ -// -// CLCDText::SetFontPointSize -// -//************************************************************************ - -void CLCDText::SetFontPointSize(int nPointSize) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - lf.lfHeight = -MulDiv(nPointSize, DEFAULT_DPI, 72); - - SetFont(lf); -} - - -//************************************************************************ -// -// CLCDText::SetFontWeight -// -//************************************************************************ - -void CLCDText::SetFontWeight(int nWeight) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - lf.lfWeight = nWeight; - - SetFont(lf); -} - - -//************************************************************************ -// -// CLCDText::SetFontColor -// -//************************************************************************ - -void CLCDText::SetFontColor(COLORREF color) -{ - SetForegroundColor(color); -} - - -//************************************************************************ -// -// CLCDText::SetText -// -//************************************************************************ - -void CLCDText::SetText(LPCTSTR szText) -{ - LCDUIASSERT(NULL != szText); - if(szText && _tcscmp(m_sText.c_str(), szText)) - { - m_sText.assign(szText); - m_nTextLength = m_sText.size(); - m_dtp.iLeftMargin = 0; - m_dtp.iRightMargin = 0; - m_bRecalcExtent = TRUE; - } -} - - -//************************************************************************ -// -// CLCDText::GetText -// -//************************************************************************ - -LPCTSTR CLCDText::GetText() -{ - return m_sText.c_str(); -} - - -//************************************************************************ -// -// CLCDText::SetWordWrap -// -//************************************************************************ - -void CLCDText::SetWordWrap(BOOL bEnable) -{ - if (bEnable) - { - m_nTextFormat |= DT_WORDBREAK; - } - else - { - m_nTextFormat &= ~DT_WORDBREAK; - } - m_bRecalcExtent = TRUE; -} - - -//************************************************************************ -// -// CLCDText::SetLeftMargin -// -//************************************************************************ - -void CLCDText::SetLeftMargin(int nLeftMargin) -{ - m_dtp.iLeftMargin = nLeftMargin; -} - - -//************************************************************************ -// -// CLCDText::SetRightMargin -// -//************************************************************************ - -void CLCDText::SetRightMargin(int nRightMargin) -{ - m_dtp.iRightMargin = nRightMargin; -} - - -//************************************************************************ -// -// CLCDText::GetLeftMargin -// -//************************************************************************ - -int CLCDText::GetLeftMargin(void) -{ - return m_dtp.iLeftMargin; -} - - -//************************************************************************ -// -// CLCDText::GetRightMargin -// -//************************************************************************ - -int CLCDText::GetRightMargin(void) -{ - return m_dtp.iRightMargin; -} - - -//************************************************************************ -// -// CLCDText::GetVExtent -// -//************************************************************************ - -SIZE& CLCDText::GetVExtent() -{ - return m_sizeVExtent; -} - - -//************************************************************************ -// -// CLCDText::GetHExtent -// -//************************************************************************ - -SIZE& CLCDText::GetHExtent() -{ - return m_sizeHExtent; -} - - -//************************************************************************ -// -// CLCDText::CalculateExtent -// -//************************************************************************ - -void CLCDText::CalculateExtent(BOOL bSingleLine) -{ - HDC hdc = CreateCompatibleDC(NULL); - - int nOldMapMode = SetMapMode(hdc, MM_TEXT); - int nOldBkMode = SetBkMode(hdc, GetBackgroundMode()); - // select current font - HFONT hOldFont = (HFONT)SelectObject(hdc, m_hFont); - - int nTextFormat; - RECT rExtent; - - if(bSingleLine) - { - // calculate horizontal extent w/ single line, we can get the line height - nTextFormat = (m_nTextFormat | DT_SINGLELINE | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = m_Size.cx; - rExtent.bottom = m_Size.cy; - DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeHExtent.cx = rExtent.right; - m_sizeHExtent.cy = rExtent.bottom; - } - else - { - // calculate vertical extent with word wrap - nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = m_Size.cx; - rExtent.bottom = m_Size.cy; - DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeVExtent.cx = rExtent.right; - m_sizeVExtent.cy = rExtent.bottom; - } - - // restores - SetMapMode(hdc, nOldMapMode); - SetBkMode(hdc, nOldBkMode); - SelectObject(hdc, hOldFont); - - DeleteDC(hdc); -} - - -//************************************************************************ -// -// CLCDText::SetAlignment -// -//************************************************************************ - -void CLCDText::SetAlignment(int nAlignment) -{ - m_nTextFormat &= ~m_nTextAlignment; - m_nTextFormat |= nAlignment; - m_nTextAlignment = nAlignment; -} - - -//************************************************************************ -// -// CLCDText::DrawText -// -//************************************************************************ - -void CLCDText::DrawText(CLCDGfxBase &rGfx) -{ - // draw the text - RECT rBoundary = { 0, 0,0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rBoundary, m_nTextFormat, &m_dtp); - - if (m_bInverted) - { - InvertRect(rGfx.GetHDC(), &rBoundary); - } -} - - -//************************************************************************ -// -// CLCDText::OnDraw -// -//************************************************************************ - -void CLCDText::OnDraw(CLCDGfxBase &rGfx) -{ - if (GetBackgroundMode() == OPAQUE) - { - HBRUSH hBackBrush = CreateSolidBrush(m_crBackgroundColor); - - // clear the clipped area - RECT rcClp = { 0, 0, m_Size.cx, m_Size.cy }; - FillRect(rGfx.GetHDC(), &rcClp, (HBRUSH) GetStockObject(BLACK_BRUSH)); - - // clear the logical area - RECT rcLog = { 0, 0, m_sizeLogical.cx, m_sizeLogical.cy }; - FillRect(rGfx.GetHDC(), &rcLog, hBackBrush); - - DeleteObject(hBackBrush); - } - - if (m_nTextLength) - { - - // map mode text, with transparency - int nOldMapMode = SetMapMode(rGfx.GetHDC(), MM_TEXT); - int nOldBkMode = SetBkMode(rGfx.GetHDC(), GetBackgroundMode()); - COLORREF nOldBkColor = SetBkColor(rGfx.GetHDC(), m_crBackgroundColor); - - // select current font - HFONT hOldFont = (HFONT)SelectObject(rGfx.GetHDC(), m_hFont); - - // select color - COLORREF crOldTextColor = SetTextColor(rGfx.GetHDC(), m_crForegroundColor); - - if (m_bRecalcExtent) - { - int nTextFormat; - - RECT rExtent; - // calculate vertical extent with word wrap - nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = GetWidth(); - rExtent.bottom = GetHeight(); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeVExtent.cx = rExtent.right; - m_sizeVExtent.cy = rExtent.bottom; - - // calculate horizontal extent w/o word wrap - nTextFormat = (m_nTextFormat | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = GetWidth(); - rExtent.bottom = GetHeight(); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeHExtent.cx = rExtent.right; - m_sizeHExtent.cy = rExtent.bottom; - - m_bRecalcExtent = FALSE; - } - - if (IsVisible()) - { - DrawText(rGfx); - } - - // restores - SetMapMode(rGfx.GetHDC(), nOldMapMode); - SetTextColor(rGfx.GetHDC(), crOldTextColor); - SetBkMode(rGfx.GetHDC(), nOldBkMode); - SetBkColor(rGfx.GetHDC(), nOldBkColor); - SelectObject(rGfx.GetHDC(), hOldFont); - } -} - -//** end of LCDText.cpp ************************************************** - +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDText.cpp +// +// The CLCDText class draws simple text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDText::CLCDText +// +//************************************************************************ + +CLCDText::CLCDText(void) +: m_hFont(NULL), + m_nTextLength(0), + m_nTextFormat(DT_LEFT | DT_NOPREFIX), + m_bRecalcExtent(TRUE), + m_nTextAlignment(DT_LEFT) +{ + ZeroMemory(&m_dtp, sizeof(DRAWTEXTPARAMS)); + m_dtp.cbSize = sizeof(DRAWTEXTPARAMS); + ZeroMemory(&m_sizeVExtent, sizeof(m_sizeVExtent)); + ZeroMemory(&m_sizeHExtent, sizeof(m_sizeHExtent)); + SetBackgroundMode(TRANSPARENT); + Initialize(); +} + + +//************************************************************************ +// +// CLCDText::~CLCDText +// +//************************************************************************ + +CLCDText::~CLCDText(void) +{ + if (m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } +} + + +//************************************************************************ +// +// CLCDText::Initialize +// +//************************************************************************ + +HRESULT CLCDText::Initialize() +{ + m_hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); + if(NULL != m_hFont) + { + SetFontPointSize(DEFAULT_POINTSIZE); + } + SetForegroundColor(RGB(255, 255, 255)); + return (NULL != m_hFont) ? S_OK : E_OUTOFMEMORY; +} + + +//************************************************************************ +// +// CLCDText::SetFont +// +//************************************************************************ + +void CLCDText::SetFont(LOGFONT& lf) +{ + if (m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } + + m_hFont = CreateFontIndirect(&lf); + m_bRecalcExtent = TRUE; +} + + +//************************************************************************ +// +// CLCDText::GetFont +// +//************************************************************************ + +HFONT CLCDText::GetFont() +{ + return m_hFont; +} + + +//************************************************************************ +// +// CLCDText::SetFontFaceName +// +//************************************************************************ + +void CLCDText::SetFontFaceName(LPCTSTR szFontName) +{ + // if NULL, uses the default gui font + if (NULL == szFontName) + { + return; + } + + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + LCDUI_tcsncpy(lf.lfFaceName, szFontName, LF_FACESIZE); + + SetFont(lf); +} + + +//************************************************************************ +// +// CLCDText::SetFontPointSize +// +//************************************************************************ + +void CLCDText::SetFontPointSize(int nPointSize) +{ + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + lf.lfHeight = -MulDiv(nPointSize, DEFAULT_DPI, 72); + + SetFont(lf); +} + + +//************************************************************************ +// +// CLCDText::SetFontWeight +// +//************************************************************************ + +void CLCDText::SetFontWeight(int nWeight) +{ + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + lf.lfWeight = nWeight; + + SetFont(lf); +} + + +//************************************************************************ +// +// CLCDText::SetFontColor +// +//************************************************************************ + +void CLCDText::SetFontColor(COLORREF color) +{ + SetForegroundColor(color); +} + + +//************************************************************************ +// +// CLCDText::SetText +// +//************************************************************************ + +void CLCDText::SetText(LPCTSTR szText) +{ + LCDUIASSERT(NULL != szText); + if(szText && _tcscmp(m_sText.c_str(), szText)) + { + m_sText.assign(szText); + m_nTextLength = m_sText.size(); + m_dtp.iLeftMargin = 0; + m_dtp.iRightMargin = 0; + m_bRecalcExtent = TRUE; + } +} + + +//************************************************************************ +// +// CLCDText::GetText +// +//************************************************************************ + +LPCTSTR CLCDText::GetText() +{ + return m_sText.c_str(); +} + + +//************************************************************************ +// +// CLCDText::SetWordWrap +// +//************************************************************************ + +void CLCDText::SetWordWrap(BOOL bEnable) +{ + if (bEnable) + { + m_nTextFormat |= DT_WORDBREAK; + } + else + { + m_nTextFormat &= ~DT_WORDBREAK; + } + m_bRecalcExtent = TRUE; +} + + +//************************************************************************ +// +// CLCDText::SetLeftMargin +// +//************************************************************************ + +void CLCDText::SetLeftMargin(int nLeftMargin) +{ + m_dtp.iLeftMargin = nLeftMargin; +} + + +//************************************************************************ +// +// CLCDText::SetRightMargin +// +//************************************************************************ + +void CLCDText::SetRightMargin(int nRightMargin) +{ + m_dtp.iRightMargin = nRightMargin; +} + + +//************************************************************************ +// +// CLCDText::GetLeftMargin +// +//************************************************************************ + +int CLCDText::GetLeftMargin(void) +{ + return m_dtp.iLeftMargin; +} + + +//************************************************************************ +// +// CLCDText::GetRightMargin +// +//************************************************************************ + +int CLCDText::GetRightMargin(void) +{ + return m_dtp.iRightMargin; +} + + +//************************************************************************ +// +// CLCDText::GetVExtent +// +//************************************************************************ + +SIZE& CLCDText::GetVExtent() +{ + return m_sizeVExtent; +} + + +//************************************************************************ +// +// CLCDText::GetHExtent +// +//************************************************************************ + +SIZE& CLCDText::GetHExtent() +{ + return m_sizeHExtent; +} + + +//************************************************************************ +// +// CLCDText::CalculateExtent +// +//************************************************************************ + +void CLCDText::CalculateExtent(BOOL bSingleLine) +{ + HDC hdc = CreateCompatibleDC(NULL); + + int nOldMapMode = SetMapMode(hdc, MM_TEXT); + int nOldBkMode = SetBkMode(hdc, GetBackgroundMode()); + // select current font + HFONT hOldFont = (HFONT)SelectObject(hdc, m_hFont); + + int nTextFormat; + RECT rExtent; + + if(bSingleLine) + { + // calculate horizontal extent w/ single line, we can get the line height + nTextFormat = (m_nTextFormat | DT_SINGLELINE | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = m_Size.cx; + rExtent.bottom = m_Size.cy; + DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeHExtent.cx = rExtent.right; + m_sizeHExtent.cy = rExtent.bottom; + } + else + { + // calculate vertical extent with word wrap + nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = m_Size.cx; + rExtent.bottom = m_Size.cy; + DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeVExtent.cx = rExtent.right; + m_sizeVExtent.cy = rExtent.bottom; + } + + // restores + SetMapMode(hdc, nOldMapMode); + SetBkMode(hdc, nOldBkMode); + SelectObject(hdc, hOldFont); + + DeleteDC(hdc); +} + + +//************************************************************************ +// +// CLCDText::SetAlignment +// +//************************************************************************ + +void CLCDText::SetAlignment(int nAlignment) +{ + m_nTextFormat &= ~m_nTextAlignment; + m_nTextFormat |= nAlignment; + m_nTextAlignment = nAlignment; +} + + +//************************************************************************ +// +// CLCDText::DrawText +// +//************************************************************************ + +void CLCDText::DrawText(CLCDGfxBase &rGfx) +{ + // draw the text + RECT rBoundary = { 0, 0,0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rBoundary, m_nTextFormat, &m_dtp); + + if (m_bInverted) + { + InvertRect(rGfx.GetHDC(), &rBoundary); + } +} + + +//************************************************************************ +// +// CLCDText::OnDraw +// +//************************************************************************ + +void CLCDText::OnDraw(CLCDGfxBase &rGfx) +{ + if (GetBackgroundMode() == OPAQUE) + { + HBRUSH hBackBrush = CreateSolidBrush(m_crBackgroundColor); + + // clear the clipped area + RECT rcClp = { 0, 0, m_Size.cx, m_Size.cy }; + FillRect(rGfx.GetHDC(), &rcClp, (HBRUSH) GetStockObject(BLACK_BRUSH)); + + // clear the logical area + RECT rcLog = { 0, 0, m_sizeLogical.cx, m_sizeLogical.cy }; + FillRect(rGfx.GetHDC(), &rcLog, hBackBrush); + + DeleteObject(hBackBrush); + } + + if (m_nTextLength) + { + + // map mode text, with transparency + int nOldMapMode = SetMapMode(rGfx.GetHDC(), MM_TEXT); + int nOldBkMode = SetBkMode(rGfx.GetHDC(), GetBackgroundMode()); + COLORREF nOldBkColor = SetBkColor(rGfx.GetHDC(), m_crBackgroundColor); + + // select current font + HFONT hOldFont = (HFONT)SelectObject(rGfx.GetHDC(), m_hFont); + + // select color + COLORREF crOldTextColor = SetTextColor(rGfx.GetHDC(), m_crForegroundColor); + + if (m_bRecalcExtent) + { + int nTextFormat; + + RECT rExtent; + // calculate vertical extent with word wrap + nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = GetWidth(); + rExtent.bottom = GetHeight(); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeVExtent.cx = rExtent.right; + m_sizeVExtent.cy = rExtent.bottom; + + // calculate horizontal extent w/o word wrap + nTextFormat = (m_nTextFormat | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = GetWidth(); + rExtent.bottom = GetHeight(); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeHExtent.cx = rExtent.right; + m_sizeHExtent.cy = rExtent.bottom; + + m_bRecalcExtent = FALSE; + } + + if (IsVisible()) + { + DrawText(rGfx); + } + + // restores + SetMapMode(rGfx.GetHDC(), nOldMapMode); + SetTextColor(rGfx.GetHDC(), crOldTextColor); + SetBkMode(rGfx.GetHDC(), nOldBkMode); + SetBkColor(rGfx.GetHDC(), nOldBkColor); + SelectObject(rGfx.GetHDC(), hOldFont); + } +} + +//** end of LCDText.cpp ************************************************** + diff --git a/src/thirdparty/LCDUI/LCDText.h b/src/thirdparty/LCDUI/LCDText.h index 46cd758300c..51ecc06d7d3 100644 --- a/src/thirdparty/LCDUI/LCDText.h +++ b/src/thirdparty/LCDUI/LCDText.h @@ -1,82 +1,82 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDText.h -// -// The CLCDText class draws simple text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDTEXT_H_INCLUDED_ -#define _LCDTEXT_H_INCLUDED_ - - -#include "LCDBase.h" -#include - -class CLCDText : public CLCDBase -{ -public: -#ifdef UNICODE - typedef std::wstring lcdstring; -#else - typedef std::string lcdstring; -#endif - -public: - CLCDText(void); - virtual ~CLCDText(void); - - virtual HRESULT Initialize(void); - - virtual void SetFont(LOGFONT& lf); - virtual void SetFontFaceName(LPCTSTR szFontName); - virtual void SetFontPointSize(int nPointSize); - virtual void SetFontWeight(int nWeight); - virtual void SetFontColor(COLORREF color); - - virtual HFONT GetFont(void); - virtual void SetText(LPCTSTR szText); - virtual LPCTSTR GetText(void); - virtual void SetWordWrap(BOOL bEnable); - virtual SIZE& GetVExtent(void); - virtual SIZE& GetHExtent(void); - virtual void CalculateExtent(BOOL bSingleLine); - virtual void SetLeftMargin(int nLeftMargin); - virtual int GetLeftMargin(void); - virtual void SetRightMargin(int nRightMargin); - virtual int GetRightMargin(void); - virtual void SetAlignment(int nAlignment = DT_LEFT); - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - - enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 8 }; - -protected: - void DrawText(CLCDGfxBase &rGfx); - - lcdstring m_sText; - HFONT m_hFont; - lcdstring::size_type m_nTextLength; - UINT m_nTextFormat; - BOOL m_bRecalcExtent; - DRAWTEXTPARAMS m_dtp; - int m_nTextAlignment; - SIZE m_sizeVExtent, m_sizeHExtent; -}; - - -#endif // !_LCDTEXT_H_INCLUDED_ - -//** end of LCDText.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDText.h +// +// The CLCDText class draws simple text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDTEXT_H_INCLUDED_ +#define _LCDTEXT_H_INCLUDED_ + + +#include "LCDBase.h" +#include + +class CLCDText : public CLCDBase +{ +public: +#ifdef UNICODE + typedef std::wstring lcdstring; +#else + typedef std::string lcdstring; +#endif + +public: + CLCDText(void); + virtual ~CLCDText(void); + + virtual HRESULT Initialize(void); + + virtual void SetFont(LOGFONT& lf); + virtual void SetFontFaceName(LPCTSTR szFontName); + virtual void SetFontPointSize(int nPointSize); + virtual void SetFontWeight(int nWeight); + virtual void SetFontColor(COLORREF color); + + virtual HFONT GetFont(void); + virtual void SetText(LPCTSTR szText); + virtual LPCTSTR GetText(void); + virtual void SetWordWrap(BOOL bEnable); + virtual SIZE& GetVExtent(void); + virtual SIZE& GetHExtent(void); + virtual void CalculateExtent(BOOL bSingleLine); + virtual void SetLeftMargin(int nLeftMargin); + virtual int GetLeftMargin(void); + virtual void SetRightMargin(int nRightMargin); + virtual int GetRightMargin(void); + virtual void SetAlignment(int nAlignment = DT_LEFT); + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + + enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 8 }; + +protected: + void DrawText(CLCDGfxBase &rGfx); + + lcdstring m_sText; + HFONT m_hFont; + lcdstring::size_type m_nTextLength; + UINT m_nTextFormat; + BOOL m_bRecalcExtent; + DRAWTEXTPARAMS m_dtp; + int m_nTextAlignment; + SIZE m_sizeVExtent, m_sizeHExtent; +}; + + +#endif // !_LCDTEXT_H_INCLUDED_ + +//** end of LCDText.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDUI.h b/src/thirdparty/LCDUI/LCDUI.h index 68f95bb6c10..f771b51fced 100644 --- a/src/thirdparty/LCDUI/LCDUI.h +++ b/src/thirdparty/LCDUI/LCDUI.h @@ -1,92 +1,92 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDUI.h -// -// Common header file for all LCDUI source files -// This file can be used to compile with pre-compiled headers -// under Visual Studio -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -// -//************************************************************************ - -#ifndef _LCDUI_H_INCLUDED_ -#define _LCDUI_H_INCLUDED_ - -//************************************************************************ -// all windows header files -//************************************************************************ - -#include -#include -#include -#include -#include -#include - - -//************************************************************************ -// all classes -//************************************************************************ - -class CLCDBase; -class CLCDCollection; -class CLCDPage; -class CLCDPopupBackground; -class CLCDConnection; -class CLCDOutput; -class CLCDGfxBase; -class CLCDGfxMono; -class CLCDGfxColor; -class CLCDText; -class CLCDColorText; -class CLCDScrollingText; -class CLCDStreamingText; -class CLCDPaginateText; -class CLCDIcon; -class CLCDBitmap; -class CLCDAnimatedBitmap; -class CLCDProgressBar; -class CLCDColorProgressBar; -class CLCDSkinnedProgressBar; - - -//************************************************************************ -// all header files -//************************************************************************ - -#include -#include "LCDBase.h" -#include "LCDCollection.h" -#include "LCDPage.h" -#include "LCDConnection.h" -#include "LCDOutput.h" -#include "LCDGfxBase.h" -#include "LCDGfxMono.h" -#include "LCDGfxColor.h" -#include "LCDText.h" -#include "LCDColorText.h" -#include "LCDScrollingText.h" -#include "LCDStreamingText.h" -#include "LCDPaginateText.h" -#include "LCDIcon.h" -#include "LCDBitmap.h" -#include "LCDAnimatedBitmap.h" -#include "LCDProgressBar.h" -#include "LCDColorProgressBar.h" -#include "LCDSkinnedProgressBar.h" - - -#endif //~_LCDUI_H_INCLUDED_ - -//** end of LCDUI.h ****************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDUI.h +// +// Common header file for all LCDUI source files +// This file can be used to compile with pre-compiled headers +// under Visual Studio +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +// +//************************************************************************ + +#ifndef _LCDUI_H_INCLUDED_ +#define _LCDUI_H_INCLUDED_ + +//************************************************************************ +// all windows header files +//************************************************************************ + +#include +#include +#include +#include +#include +#include + + +//************************************************************************ +// all classes +//************************************************************************ + +class CLCDBase; +class CLCDCollection; +class CLCDPage; +class CLCDPopupBackground; +class CLCDConnection; +class CLCDOutput; +class CLCDGfxBase; +class CLCDGfxMono; +class CLCDGfxColor; +class CLCDText; +class CLCDColorText; +class CLCDScrollingText; +class CLCDStreamingText; +class CLCDPaginateText; +class CLCDIcon; +class CLCDBitmap; +class CLCDAnimatedBitmap; +class CLCDProgressBar; +class CLCDColorProgressBar; +class CLCDSkinnedProgressBar; + + +//************************************************************************ +// all header files +//************************************************************************ + +#include +#include "LCDBase.h" +#include "LCDCollection.h" +#include "LCDPage.h" +#include "LCDConnection.h" +#include "LCDOutput.h" +#include "LCDGfxBase.h" +#include "LCDGfxMono.h" +#include "LCDGfxColor.h" +#include "LCDText.h" +#include "LCDColorText.h" +#include "LCDScrollingText.h" +#include "LCDStreamingText.h" +#include "LCDPaginateText.h" +#include "LCDIcon.h" +#include "LCDBitmap.h" +#include "LCDAnimatedBitmap.h" +#include "LCDProgressBar.h" +#include "LCDColorProgressBar.h" +#include "LCDSkinnedProgressBar.h" + + +#endif //~_LCDUI_H_INCLUDED_ + +//** end of LCDUI.h ****************************************************** diff --git a/src/thirdparty/LCDUI/LCDUI.vcxproj b/src/thirdparty/LCDUI/LCDUI.vcxproj index ac7966c494b..b53bea0e7f0 100644 --- a/src/thirdparty/LCDUI/LCDUI.vcxproj +++ b/src/thirdparty/LCDUI/LCDUI.vcxproj @@ -1,107 +1,107 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {476B97B4-F079-4A44-AF89-52CA30C35E28} - LCDUI - Win32Proj - LCDUI - - - - - StaticLibrary - Unicode - - - - - - - - - - - False - - - - ..\..\..\include;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - LCDUI.h - - - lgLcd.lib;%(AdditionalDependencies) - $(SolutionDir)lib;%(AdditionalLibraryDirectories) - $(SolutionDir)lib64;%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {476B97B4-F079-4A44-AF89-52CA30C35E28} + LCDUI + Win32Proj + LCDUI + + + + + StaticLibrary + Unicode + + + + + + + + + + + False + + + + ..\..\..\include;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + LCDUI.h + + + lgLcd.lib;%(AdditionalDependencies) + $(SolutionDir)lib;%(AdditionalLibraryDirectories) + $(SolutionDir)lib64;%(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/LCDUI/LCDUI.vcxproj.filters b/src/thirdparty/LCDUI/LCDUI.vcxproj.filters index f0c9f370976..09f502fd97d 100644 --- a/src/thirdparty/LCDUI/LCDUI.vcxproj.filters +++ b/src/thirdparty/LCDUI/LCDUI.vcxproj.filters @@ -1,143 +1,143 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/LCDUI/stdafx.cpp b/src/thirdparty/LCDUI/stdafx.cpp index 9a097c179fd..aecdbddc5c9 100644 --- a/src/thirdparty/LCDUI/stdafx.cpp +++ b/src/thirdparty/LCDUI/stdafx.cpp @@ -1,21 +1,21 @@ -/* - * (C) 2011-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 . - * - */ - -#include "LCDUI.h" +/* + * (C) 2011-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 . + * + */ + +#include "LCDUI.h" diff --git a/src/thirdparty/MessageBoxDialog/MessageBoxDialog.cpp b/src/thirdparty/MessageBoxDialog/MessageBoxDialog.cpp index c798950f27b..f9931cb7e63 100755 --- a/src/thirdparty/MessageBoxDialog/MessageBoxDialog.cpp +++ b/src/thirdparty/MessageBoxDialog/MessageBoxDialog.cpp @@ -1,1073 +1,1073 @@ -/* - * Extended MFC message boxes -- Version 1.2 Lite - * Copyright (c) 2004 Michael P. Mehl. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1a (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/. - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights - * reserved. The Initial Developer of the Original Code is Michael P. Mehl - * . - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU Lesser General Public License Version 2.1 (the "LGPL License"), - * in which case the provisions of LGPL License are applicable instead of - * those above. If you wish to allow use of your version of this file only - * under the terms of the LGPL License and not to allow others to use your - * version of this file under the MPL, indicate your decision by deleting - * the provisions above and replace them with the notice and other provisions - * required by the LGPL License. If you do not delete the provisions above, - * a recipient may use your version of this file under either the MPL or - * the LGPL License. - */ - -/* -MPC-HC -modified from 1.2lite to include code to emulate afxmessagebox styles -modified to use Theme Font -*/ - -#include "stdafx.h" - -#include "MessageBoxDialog.h" -#include "../mpc-hc/CMPCTheme.h" -#include "../mpc-hc/CMPCThemeUtil.h" -#include - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - -IMPLEMENT_DYNAMIC(CMessageBoxDialog, CDialog) - -////////////////////////////////////////////////////////////////////////////// -// Layout values (in dialog units). - -#define CX_BORDER 8 // Width of the border. -#define CY_BORDER 6 // Height of the border. - -#define CX_BUTTON 35 // Standard width of a button. -#define CY_BUTTON 10 // Standard height of a button. -#define CY_TEXTPADDING 14 // Space before and after message. -#define CX_BUTTON_BORDER 4 // Standard border for a button. -#define CX_WINDOW_PADDING 2 // Padding for right side of dialog - -#define CY_BUTTON_BORDER 1 // Standard border for a button. -#define CX_BUTTON_SPACE 7 // Standard space for a button. - -#define CX_DLGUNIT_BASE 1000 // Values used for converting -#define CY_DLGUNIT_BASE 1000 // dialog units to pixels. - -////////////////////////////////////////////////////////////////////////////// -// Constructors and destructors of the class. - -/** - * Constructor of the class. - * - * This constructor is used to provide the strings directly without providing - * resource IDs from which these strings should be retrieved. If no title is - * given, the application name will be used as the title of the dialog. - */ - CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, CString strMessage, - CString strTitle, UINT nStyle, UINT nHelp ) -{ - // Enable the active accessibility. -#if _MSC_VER >= 1300 - EnableActiveAccessibility(); -#endif - - ASSERT(!strMessage.IsEmpty()); - - // Save the information about the message box. - m_pParent = pParent; - m_strMessage = strMessage; - m_strTitle = strTitle.IsEmpty() ? CString(AfxGetAppName()) : strTitle; - m_nStyle = nStyle; - m_nHelp = nHelp; - - // Do the default initialization. - m_uBeepType = (UINT)-1; - m_hIcon = NULL; - m_nDefaultButton = IDC_STATIC; - m_nEscapeButton = IDC_STATIC; - m_sDialogUnit = CSize(0, 0); - m_sIcon = CSize(0, 0); - m_sMessage = CSize(0, 0); - m_sButton = CSize(0, 0); -} - -/** - * Constructor of the class. - * - * This constructor is used to load the strings for the title and the message - * text from the resources of this project. If no title is given, the - * application name will be used as the title of the dialog. - */ -CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, - UINT nTitleID, UINT nStyle, UINT nHelp ) -{ - // Enable the active accessibility. -#if _MSC_VER >= 1300 - EnableActiveAccessibility(); -#endif - - // Check whether a title was given. - if ( nTitleID == 0 ) - { - // Use the application name. - m_strTitle = AfxGetAppName(); - } - else - { - // Try to load the title from the resources. - VERIFY(m_strTitle.LoadString(nTitleID)); - } - - // Save the information about the message box. - m_pParent = pParent; - VERIFY(m_strMessage.LoadString(nMessageID)); - m_nStyle = nStyle; - m_nHelp = nHelp; - - // Do the default initialization. - m_uBeepType = (UINT)-1; - m_hIcon = NULL; - m_nDefaultButton = IDC_STATIC; - m_nEscapeButton = IDC_STATIC; - m_sDialogUnit = CSize(0, 0); - m_sIcon = CSize(0, 0); - m_sMessage = CSize(0, 0); - m_sButton = CSize(0, 0); -} - -/** - * Destructor of the class. - */ -CMessageBoxDialog::~CMessageBoxDialog ( ) -{ - // Check whether an icon was loaded. - if ( m_hIcon != NULL ) - { - // Free the icon. - DestroyIcon(m_hIcon); - - // Reset the icon handle. - m_hIcon = NULL; - } -} - -////////////////////////////////////////////////////////////////////////////// -// Methods for setting and retrieving dialog options. - -/** - * Method for setting the style of the message box. - */ -inline void CMessageBoxDialog::SetStyle ( UINT nStyle ) -{ - // Set the style of the message box. - m_nStyle = nStyle; -} - -/** - * Method for retrieving the style of the message box. - */ -inline UINT CMessageBoxDialog::GetStyle ( ) -{ - // Return the current style of the message box. - return m_nStyle; -} - -/** - * Method for setting the message to be displayed in the message box. - */ -void CMessageBoxDialog::SetMessage ( CString strMessage ) -{ - ASSERT(!strMessage.IsEmpty()); - - // Save the message text. - m_strMessage = strMessage; -} - -/** - * Methods for setting the message to be displayed in the message box. - */ -void CMessageBoxDialog::SetMessage ( UINT nMessageID ) -{ - // Create a string for storing the message. - CString strMessage = _T(""); - - // Load the message from the resources. - VERIFY(strMessage.LoadString(nMessageID)); - - ASSERT(!strMessage.IsEmpty()); - - // Save the message text. - m_strMessage = strMessage; -} - -/** - * Method for retrieving the message to be displayed in the message box. - */ -CString CMessageBoxDialog::GetMessage ( ) -{ - // Return the message text. - return m_strMessage; -} - -/** - * Method for setting the title to be displayed in the message box. - */ -void CMessageBoxDialog::SetTitle ( CString strTitle ) -{ - // Check whether a title was given. - if ( strTitle.IsEmpty() ) - { - // Use the application name as the title. - strTitle = AfxGetAppName(); - } - - // Save the title. - m_strTitle = strTitle; -} - -/** - * Method for setting the title to be displayed in the message box. - */ -void CMessageBoxDialog::SetTitle ( UINT nTitleID ) -{ - // Create a string for storing the title. - CString strTitle = _T(""); - - // Check whether an ID was given. - if ( nTitleID == 0 ) - { - // Use the application name as the title. - strTitle = AfxGetAppName(); - } - else - { - // Try to load the string from the resources. - VERIFY(strTitle.LoadString(nTitleID)); - - ASSERT(!strTitle.IsEmpty()); - } - - // Save the title. - m_strTitle = strTitle; -} - -/** - * Method for retrieving the title to be displayed in the message box. - */ -CString CMessageBoxDialog::GetTitle ( ) -{ - // Return the title of the message box. - return m_strTitle; -} - -void CMessageBoxDialog::SetMessageBeep(UINT uType) -{ - m_uBeepType = uType; -} - -/** - * Method for setting the icon to be displayed in the message box. - */ -void CMessageBoxDialog::SetMessageIcon ( HICON hIcon ) -{ - ASSERT(hIcon != NULL); - - // Save the icon. - m_hIcon = hIcon; -} - -/** - * Method for setting the icon to be displayed in the message box. - */ -void CMessageBoxDialog::SetMessageIcon ( LPCTSTR lpszIconName, BOOL bStandard ) -{ - // Try to load the given icon. - if (bStandard) - { - if (m_uBeepType==-1) - { - if (lpszIconName==IDI_QUESTION) - m_uBeepType = MB_ICONQUESTION; - else if (lpszIconName==IDI_WARNING || lpszIconName==IDI_EXCLAMATION) - m_uBeepType = MB_ICONWARNING; - else if (lpszIconName==IDI_ERROR || lpszIconName==IDI_HAND) - m_uBeepType = MB_ICONERROR; - else if (lpszIconName==IDI_INFORMATION || lpszIconName==IDI_ASTERISK) - m_uBeepType = MB_ICONINFORMATION; - } - m_hIcon = AfxGetApp()->LoadStandardIcon(lpszIconName); - } - else - m_hIcon = AfxGetApp()->LoadIcon(lpszIconName); - - ASSERT(m_hIcon != NULL); -} - -/** - * Method for retrieving the icon to be displayed in the message box. - */ -HICON CMessageBoxDialog::GetMessageIcon ( ) -{ - // Return the icon for the message box. - return m_hIcon; -} - -////////////////////////////////////////////////////////////////////////////// -// Methods for handling common window functions. - -/** - * Method for displaying the dialog. - * - * If the MB_DONT_DISPLAY_AGAIN or MB_DONT_ASK_AGAIN flag is set, this - * method will check, whether a former result for this dialog was stored - * in the registry. If yes, the former result will be returned without - * displaying the dialog. Otherwise the message box will be displayed in - * the normal way. - */ -INT_PTR CMessageBoxDialog::DoModal ( ) -{ - BYTE abyBuff[512]; - memset(abyBuff, 0, sizeof(abyBuff)); - DLGTEMPLATE* pdlgtmplTemplate = (DLGTEMPLATE*)abyBuff; - pdlgtmplTemplate->x = 0; - pdlgtmplTemplate->y = 0; - pdlgtmplTemplate->cx = 200; - pdlgtmplTemplate->cy = 200; - pdlgtmplTemplate->style = DS_MODALFRAME|WS_CAPTION|WS_VISIBLE|WS_POPUP|WS_SYSMENU|WS_BORDER; - pdlgtmplTemplate->dwExtendedStyle = 0; - pdlgtmplTemplate->cdit = 0; - - //This is the MFC function, which does the job - InitModalIndirect(pdlgtmplTemplate, m_pParent); - - return CDialog::DoModal(); -} - -/** - * Method for initializing the dialog. - * - * This method is used for initializing the dialog. It will create the - * content of the dialog, which means it will create all controls and will - * size the dialog to fit it's content. - */ -BOOL CMessageBoxDialog::OnInitDialog ( ) -{ - // Call the parent method. - if ( !CDialog::OnInitDialog() ) - { - // Return with an error. - return FALSE; - } - - if (!CMPCThemeUtil::getFontByType(messageFont, this, CMPCThemeUtil::MessageFont)) { - return FALSE; - } - - // Set the title of the dialog. - SetWindowText(m_strTitle); - - // Set the help ID of the dialog. - SetHelpID(m_nHelp); - - // Parse the style of the message box. - ParseStyle(); - - // Create the elements of the dialog. - CreateIconControl(); - CreateMessageControl(); - CreateButtonControls(); - - // Define the layout of the dialog. - DefineLayout(); - - // Check whether no sound should be generated. - if ( m_uBeepType != -1 ) - { - // Do a beep. - MessageBeep(m_uBeepType); - } - - // Check whether the window should be system modal. - if ( m_nStyle & MB_SYSTEMMODAL ) - { - // Modify the style of the window. - ModifyStyle(0, DS_SYSMODAL); - } - - // Check whether to bring the window to the foreground. - if ( m_nStyle & MB_SETFOREGROUND ) - { - // Bring the window to the foreground. - SetForegroundWindow(); - } - - // Check whether the window should be the topmost window. - if ( m_nStyle & MB_TOPMOST ) - { - // Modify the style of the window. - ModifyStyleEx(0, WS_EX_TOPMOST); - } - - // Check whether an escape button was defined. - if ( m_nEscapeButton == IDC_STATIC ) - { - // Disable the close item from the system menu. - CMenu* sysmenu = GetSystemMenu(FALSE); - if (sysmenu) - sysmenu->EnableMenuItem(SC_CLOSE, MF_GRAYED); - } - - // Check whether a default button was defined. - if ( m_nDefaultButton != IDC_STATIC ) - { - // Set the focus to the default button. - CWnd* item = GetDlgItem(m_nDefaultButton); - if (item) { - item->SetFocus(); - } - - // Set the default ID of the dialog. - SetDefID(m_nDefaultButton); - - // Return FALSE to set the focus correctly. - return FALSE; - } - - // Everything seems to be done successfully. - return TRUE; -} - -/** - * Method for handling command messages. - * - * This method will handle command messages, which are those messages, which - * are generated, when a user clicks a button of the dialog. - */ -BOOL CMessageBoxDialog::OnCmdMsg ( UINT nID, int nCode, void* pExtra, - AFX_CMDHANDLERINFO* pHandlerInfo ) -{ - // Check whether it's the help button. - if ( ( nID == IDHELP ) && ( nCode == CN_COMMAND ) ) - { - // Display the help for this message box. - OnHelp(); - - // The message has been processed successfully. - return TRUE; - } - - // Check whether the ID of the control element is interesting for us. - if ( ( nID != IDC_STATIC ) && ( nCode == CN_COMMAND ) ) - { - // End the dialog with the given ID. - EndDialog(nID); - - // The message has been processed successfully. - return TRUE; - } - - // Call the parent method. - return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); -} - -/** - * Method for handling messages before dispatching them. - * - * This message will handle message before they get dispatched the normal way - * and will therefore implement the additional behavior of this dialog. - */ -BOOL CMessageBoxDialog::PreTranslateMessage ( MSG* pMsg ) -{ - // Check whether it's a key message and whether it's not a disable timeout. - if ( pMsg->message == WM_KEYDOWN ) - { - // Check whether it's the return key. - if ( pMsg->wParam == VK_RETURN ) - { - // Try to retrieve the current focus. - CWnd* pFocusWnd = GetFocus(); - - // Check whether a handle was retrieved. - if ( pFocusWnd != NULL ) - { - // Try to determine the ID of the element. - int nID = pFocusWnd->GetDlgCtrlID(); - - // Check whether the ID is a button. - if ( m_aButtons.FindKey(nID)!=-1 ) - { - EndDialog(nID); - } - else - { - // End the dialog with the default command. - EndDialog(m_nDefaultButton); - } - - // The message has been processed successfully. - return TRUE; - } - } - - // Check whether it's the escape key. - if ( ( pMsg->wParam == VK_ESCAPE ) || ( pMsg->wParam == VK_CANCEL ) ) - { - // Check whether an escape button was defined. - if ( m_nEscapeButton != IDC_STATIC ) - { - // End the dialog with this ID. - EndDialog(m_nEscapeButton); - } - - // The message has been processed successfully. - return TRUE; - } - } - - // Call the parent method. - return CDialog::PreTranslateMessage(pMsg); -} - -////////////////////////////////////////////////////////////////////////////// -// Other dialog handling methods. - -/** - * Method for handling window messages. - */ -BOOL CMessageBoxDialog::OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam, - LRESULT* pResult ) -{ - // Check whether to close the dialog. - if ( message == WM_CLOSE ) - { - // Check whether an escape button is defined. - if ( m_nEscapeButton != IDC_STATIC ) - { - // End the dialog with this command. - EndDialog(m_nEscapeButton); - } - - // The message was handled successfully. - return TRUE; - } - - // Call the parent method. - return CDialog::OnWndMsg(message, wParam, lParam, pResult); -} - -////////////////////////////////////////////////////////////////////////////// -// Helper methods. - -/** - * Method for adding a button to the list of buttons. - * - * This method adds a button to the list of buttons, which will be created in - * the dialog, but it will not create the button control itself. - */ -void CMessageBoxDialog::AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault, - BOOL bIsEscape ) -{ - CString strButtonTitle; - VERIFY(strButtonTitle.LoadString(nTitle)); - - AddButton(nID, strButtonTitle, bIsDefault, bIsEscape); -} - -/** - * Method for adding a button to the list of buttons. - * - * This method adds a button to the list of buttons, which will be created in - * the dialog, but it will not create the button control itself. - */ -void CMessageBoxDialog::AddButton ( UINT nID, CString strTitle, BOOL bIsDefault, - BOOL bIsEscape ) -{ - // Check if one is trying to add the same ID twice - VERIFY( m_aButtons.FindKey(nID)==-1 ); - - // Add the button to the list of buttons. - VERIFY( m_aButtons.Add(nID, strTitle) ); - - // Check whether this button is the default button. - if ( bIsDefault ) - { - // Save the ID of the button as the ID of the default button. - m_nDefaultButton = nID; - } - - // Check whether this button is the escape button. - if ( bIsEscape ) - { - // Save the ID of the button as the ID of the escape button. - m_nEscapeButton = nID; - } -} - -/** - * Method for converting a dialog unit x value to a pixel value. - */ -int CMessageBoxDialog::XDialogUnitToPixel ( int x ) -{ - // Check whether the dimension of a dialog unit has already been determined. - if ( m_sDialogUnit.cx == 0 ) - { - // Create a rect for mapping it to the dialog rect. - CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE); - - // Map the rect to the dialog. - - //mpc-hc: CDialog without a template does not work well with MapDialogRect--use MapDialogRect2 - //MapDialogRect(rcDialog); - CMPCThemeUtil::MapDialogRect2(this, rcDialog); - - // Save the rect. - m_sDialogUnit = rcDialog.Size(); - } - - // Return the converted value. - return ( MulDiv( x , m_sDialogUnit.cx , CX_DLGUNIT_BASE )); -} - -/** - * Method for converting a dialog unit y value to a pixel value. - */ -int CMessageBoxDialog::YDialogUnitToPixel ( int y ) -{ - // Check whether the dimension of a dialog unit has already been determined. - if ( m_sDialogUnit.cy == 0 ) - { - // Create a rect for mapping it to the dialog rect. - CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE); - - // Map the rect to the dialog. - //mpc-hc: CDialog without a template does not work well with MapDialogRect--use MapDialogRect2 - //MapDialogRect(rcDialog); - CMPCThemeUtil::MapDialogRect2(this, rcDialog); - - // Save the rect. - m_sDialogUnit = rcDialog.Size(); - } - - // Return the converted value. - return ( MulDiv( y , m_sDialogUnit.cy , CY_DLGUNIT_BASE ) ); -} - -/** - * Method for parsing the given style. - * - * This method will parse the given style for the message box and will create - * the elements of the dialog box according to it. If you want to add more - * user defined styles, simply modify this method. - */ -void CMessageBoxDialog::ParseStyle ( ) -{ - switch ( m_nStyle & MB_TYPEMASK ) - { - case MB_OKCANCEL: - AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE); - AddButton(IDCANCEL, IDS_CANCEL, FALSE, TRUE); - break; - case MB_ABORTRETRYIGNORE: - AddButton(IDABORT, IDS_MESSAGEBOX_ABORT, TRUE); - AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY); - AddButton(IDIGNORE, IDS_MESSAGEBOX_IGNORE); - break; - case MB_YESNOCANCEL: - AddButton(IDYES, IDS_SUBRESYNC_YES, TRUE); - AddButton(IDNO, IDS_SUBRESYNC_NO); - AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE); - break; - case MB_YESNO: - AddButton(IDYES, IDS_SUBRESYNC_YES, TRUE); - AddButton(IDNO, IDS_SUBRESYNC_NO); - break; - case MB_RETRYCANCEL: - AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY, TRUE); - AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE); - break; - case MB_CANCELTRYCONTINUE: - AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, TRUE, TRUE); - AddButton(IDTRYAGAIN, IDS_MESSAGEBOX_RETRY); - AddButton(IDCONTINUE, IDS_MESSAGEBOX_CONTINUE); - break; - default: - case MB_OK: - AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE, TRUE); - break; - } - // Check whether a default button was defined. - if ( m_nStyle & MB_DEFMASK ) - { - // Create a variable to store the index of the default button. - int nDefaultIndex = 0; - - // Switch the default button. - switch ( m_nStyle & MB_DEFMASK ) - { - - case MB_DEFBUTTON1: - // Set the index of the default button. - nDefaultIndex = 0; - break; - - case MB_DEFBUTTON2: - // Set the index of the default button. - nDefaultIndex = 1; - break; - - case MB_DEFBUTTON3: - // Set the index of the default button. - nDefaultIndex = 2; - break; - - case MB_DEFBUTTON4: - // Set the index of the default button. - nDefaultIndex = 3; - break; - } - - // Check whether enough buttons are available. - if ( m_aButtons.GetSize() >= ( nDefaultIndex + 1 ) ) - { - // Set the new default button. - m_nDefaultButton = m_aButtons.GetKeyAt(nDefaultIndex); - } - } - - // Check whether an icon was specified. - if ( ( m_nStyle & MB_ICONMASK ) && ( m_hIcon == NULL ) ) - { - // Switch the icon. - switch ( m_nStyle & MB_ICONMASK ) - { - case MB_ICONEXCLAMATION: - // Load the icon with the exclamation mark. - SetMessageIcon(IDI_EXCLAMATION, TRUE); - break; - - case MB_ICONHAND: - // Load the icon with the error symbol. - SetMessageIcon(IDI_HAND, TRUE); - break; - - case MB_ICONQUESTION: - // Load the icon with the question mark. - SetMessageIcon(IDI_QUESTION, TRUE); - break; - - case MB_ICONASTERISK: - // Load the icon with the information symbol. - SetMessageIcon(IDI_ASTERISK, TRUE); - break; - } - } -} - -/** - * Method for creating the icon control. - * - * This method will check whether the handle for an icon was defined and if - * yes it will create an control in the dialog to display that icon. - */ -void CMessageBoxDialog::CreateIconControl ( ) -{ - // Check whether an icon was defined. - if ( m_hIcon != NULL ) - { - // Create a structure to read information about the icon. - ICONINFO iiIconInfo; - - // Retrieve information about the icon. - GetIconInfo(m_hIcon, &iiIconInfo); - - ASSERT(iiIconInfo.fIcon); - - // Create a handle to access the bitmap information of the icon. - BITMAP bmIcon; - - // Retrieve the bitmap information of the icon. - GetObject((HGDIOBJ)iiIconInfo.hbmColor, sizeof(bmIcon), &bmIcon); - - // Save the size of the icon. - m_sIcon.cx = bmIcon.bmWidth; - m_sIcon.cy = bmIcon.bmHeight; - - // Create a dummy rect for the icon control. - CRect rcDummy; - - // Create the control for the icon. - m_stcIcon.Create(NULL, WS_CHILD | WS_VISIBLE | WS_DISABLED | SS_ICON, - rcDummy, this, (UINT)IDC_STATIC); - - // Set the icon of the control. - m_stcIcon.SetIcon(m_hIcon); - //m_stcIcon.UnsubclassWindow(); - } -} - -/** - * Method for creating the text control. - * - * This method create the control displaying the text of the message for the - * message box. It will also try to determine the size required for the - * message. - */ -void CMessageBoxDialog::CreateMessageControl ( ) -{ - ASSERT(!m_strMessage.IsEmpty()); - - // Create a DC for accessing the display driver. - CDC dcDisplay; - dcDisplay.CreateDC(_T("DISPLAY"), NULL, NULL, NULL); - - // Select the new font and store the old one. - //mpc-hc use stored font for metrics - //CFont* pOldFont = dcDisplay.SelectObject(GetFont()); - CFont* pOldFont = dcDisplay.SelectObject(&messageFont); - - // Define the maximum width of the message. - int nMaxWidth = GetSystemMetrics(SM_CXSCREEN) - 2 * XDialogUnitToPixel(CX_BORDER); - int minClientHeightExcludingMessage = 2 * YDialogUnitToPixel(CY_TEXTPADDING) + 2 * YDialogUnitToPixel(CY_BORDER) + YDialogUnitToPixel(CY_BUTTON) + 1; - int yPadding = GetThemeSysSize(NULL, SM_CYSIZE) + GetThemeSysSize(NULL, SM_CXPADDEDBORDER) * 2 + minClientHeightExcludingMessage; - int nMaxHeight = GetSystemMetrics(SM_CYSCREEN) - yPadding; - - // Check whether an icon is displayed. - if ( m_hIcon != NULL ) - { - // Decrease the maximum width. - nMaxWidth -= m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); - } - - // Create a rect with the maximum width. - //mpc-hc try to follow windows guidlines for messagebox sizes per https://devblogs.microsoft.com/oldnewthing/20110624-00/?p=10343 - int bestWidth = 99999; - CRect rcMessage(0, 0, nMaxWidth, nMaxHeight); - m_sMessage = rcMessage.Size(); - - for (int widthType = 0; widthType < 5; widthType++) { - int testWidth; - switch (widthType) { - case 0: - testWidth = GetSystemMetrics(SM_CXSCREEN); - break; - case 1: - testWidth = XDialogUnitToPixel(278); - break; - case 2: - testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 5, 8); - break; - case 3: - testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 3, 4); - break; - case 4: - default: - testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 7, 8); - break; - } - rcMessage = CRect(0, 0, testWidth, nMaxHeight); - dcDisplay.DrawText(m_strMessage, rcMessage, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); - if (rcMessage.Width() <= nMaxWidth && rcMessage.Height() <= nMaxHeight) { - if (testWidth < bestWidth) { - m_sMessage = rcMessage.Size(); - bestWidth = testWidth; - } - } - } - - // Select the old font again. - dcDisplay.SelectObject(pOldFont); - - // Create a dummy rect for the control. - CRect rcDummy; - - // Create a variable with the style of the control. - DWORD dwStyle = WS_CHILD | WS_VISIBLE; - - // Check whether the text should be right aligned. - if ( m_nStyle & MB_RIGHT ) - { - // Align the text to the right. - dwStyle |= SS_RIGHT; - } - else - { - // Align the text to the left. - dwStyle |= SS_LEFT; - } - - // Create the static control for the message. - m_stcMessage.Create(m_strMessage, dwStyle, rcDummy, this, - (UINT)IDC_STATIC); - - // Check whether the text will be read from right to left. - if ( m_nStyle & MB_RTLREADING ) - { - // Change the extended style of the control. - m_stcMessage.ModifyStyleEx(0, WS_EX_RTLREADING); - } - - // Set the font of the dialog. - m_stcMessage.SetFont(&messageFont); -} - -/** - * Method for creating the button controls. - * - * According to the list of buttons, which should be displayed in this - * message box, this method will create them and add them to the dialog. - */ -void CMessageBoxDialog::CreateButtonControls ( ) -{ - // Initialize the control with the size of the button. - m_sButton = CSize(XDialogUnitToPixel(CX_BUTTON) + 1,YDialogUnitToPixel(CY_BUTTON) + 1); - - // Create a handle to access the DC of the dialog. - CClientDC dc(this); - - // Retrieve the font for this dialog and select it. - CFont* pWndFont = GetFont(); - CFont* pOldFont = dc.SelectObject(pWndFont); - - // Create a dummy rect. - CRect rcDummy; - - // Run through all buttons defined in the list of the buttons. - for ( int i = 0; i < m_aButtons.GetSize(); i++ ) - { - // Create a string and load the title of the button. - CString strButtonTitle = m_aButtons.GetValueAt(i); - - // Retrieve the size of the text. - CSize sButtonText = dc.GetTextExtent(strButtonTitle); - - // Resize the button. - m_sButton.cx = std::max(m_sButton.cx, sButtonText.cx); - m_sButton.cy = std::max(m_sButton.cy, sButtonText.cy); - - // Create a new handle for creating a button control. - CButton btnControl; - - // Create the button. - btnControl.Create(strButtonTitle, WS_CHILD | WS_VISIBLE | WS_TABSTOP, - rcDummy, this, m_aButtons.GetKeyAt(i)); - - // Set the font of the control. - btnControl.SetFont(&messageFont); - - // Remove the subclassing again. - btnControl.UnsubclassWindow(); - } - - // Add margins to the button size. - m_sButton.cx += 2 * XDialogUnitToPixel(CX_BUTTON_BORDER); - m_sButton.cy += 2 * XDialogUnitToPixel(CY_BUTTON_BORDER); - - // Select the old font again. - dc.SelectObject(pOldFont); -} - -/** - * Method for defining the layout of the dialog. - * - * This method will define the actual layout of the dialog. This layout is - * based on the created controls for the dialog. - */ -void CMessageBoxDialog::DefineLayout ( ) -{ - // Create a variable for storing the size of the dialog. - CSize sClient = CSize(2 * XDialogUnitToPixel(CX_BORDER), - 2 * YDialogUnitToPixel(CY_BORDER)); - - // Create a variable to store the left position for a control element. - int nXPosition = XDialogUnitToPixel(CX_BORDER); - long messageAreaHeight = m_sMessage.cy + 2 * YDialogUnitToPixel(CY_TEXTPADDING); - int nYPosition = YDialogUnitToPixel(CY_TEXTPADDING); - - // Check whether an icon is defined. - if ( m_hIcon != NULL && ::IsWindow(m_stcIcon)) - { - // Move the icon control. - m_stcIcon.MoveWindow(XDialogUnitToPixel(CX_BORDER), YDialogUnitToPixel(CY_BORDER), m_sIcon.cx, m_sIcon.cy); - - // Add the size of the icon to the size of the dialog. - sClient.cx += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); - sClient.cy += m_sIcon.cy + YDialogUnitToPixel(CY_BORDER); - - // Increase the x position for following control elements. - nXPosition += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); - } - - // Change the size of the dialog according to the size of the message. - sClient.cx += m_sMessage.cx + XDialogUnitToPixel(CX_BORDER); - sClient.cy = std::max(sClient.cy, messageAreaHeight); - - // Set the position of the message text. - m_stcMessage.MoveWindow(nXPosition, nYPosition, m_sMessage.cx, - m_sMessage.cy); - - // Define the new y position. - nYPosition = messageAreaHeight; - - // Calculate the width of the buttons. - int cxButtons = - ( m_aButtons.GetSize() - 1 ) * XDialogUnitToPixel(CX_BUTTON_SPACE) + - m_aButtons.GetSize() * m_sButton.cx; - int cyButtons = m_sButton.cy; - - // Add the size of the buttons to the dialog. - sClient.cx = std::max((LONG)sClient.cx, (LONG)2 * XDialogUnitToPixel(CX_BORDER) + cxButtons); - sClient.cy += cyButtons + 2 * YDialogUnitToPixel(CY_BORDER); - - // Calculate the start y position for the buttons. - //mpc-hc align right instead of center - //int nXButtonPosition = (sClient.cx - cxButtons) / 2; - int nXButtonPosition = sClient.cx - cxButtons - XDialogUnitToPixel(CX_BORDER + CX_WINDOW_PADDING); - int nYButtonPosition = sClient.cy - YDialogUnitToPixel(CY_BORDER) - m_sButton.cy; - - buttonAreaY = nYPosition; - - // Run through all buttons. - for ( int i = 0; i < m_aButtons.GetSize(); i++ ) - { - // Try to retrieve the handle to access the button. - CWnd* pButton = GetDlgItem(m_aButtons.GetKeyAt(i)); - - ASSERT(pButton); - - // Check whether the handle was retrieved successfully. - if ( pButton != NULL ) - { - // Move the button. - pButton->MoveWindow(nXButtonPosition, nYButtonPosition, - m_sButton.cx, m_sButton.cy); - - // Set the new x position of the next button. - nXButtonPosition += m_sButton.cx + - XDialogUnitToPixel(CX_BUTTON_SPACE); - } - } - - // Set the dimensions of the dialog. - CRect rcClient(0, 0, sClient.cx, sClient.cy); - - // Calculate the window rect. - CalcWindowRect(rcClient); - - // Move the window. - MoveWindow(rcClient); - - // Center the window. - CenterWindow(); -} +/* + * Extended MFC message boxes -- Version 1.2 Lite + * Copyright (c) 2004 Michael P. Mehl. All rights reserved. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1a (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights + * reserved. The Initial Developer of the Original Code is Michael P. Mehl + * . + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU Lesser General Public License Version 2.1 (the "LGPL License"), + * in which case the provisions of LGPL License are applicable instead of + * those above. If you wish to allow use of your version of this file only + * under the terms of the LGPL License and not to allow others to use your + * version of this file under the MPL, indicate your decision by deleting + * the provisions above and replace them with the notice and other provisions + * required by the LGPL License. If you do not delete the provisions above, + * a recipient may use your version of this file under either the MPL or + * the LGPL License. + */ + +/* +MPC-HC +modified from 1.2lite to include code to emulate afxmessagebox styles +modified to use Theme Font +*/ + +#include "stdafx.h" + +#include "MessageBoxDialog.h" +#include "../mpc-hc/CMPCTheme.h" +#include "../mpc-hc/CMPCThemeUtil.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +IMPLEMENT_DYNAMIC(CMessageBoxDialog, CDialog) + +////////////////////////////////////////////////////////////////////////////// +// Layout values (in dialog units). + +#define CX_BORDER 8 // Width of the border. +#define CY_BORDER 6 // Height of the border. + +#define CX_BUTTON 35 // Standard width of a button. +#define CY_BUTTON 10 // Standard height of a button. +#define CY_TEXTPADDING 14 // Space before and after message. +#define CX_BUTTON_BORDER 4 // Standard border for a button. +#define CX_WINDOW_PADDING 2 // Padding for right side of dialog + +#define CY_BUTTON_BORDER 1 // Standard border for a button. +#define CX_BUTTON_SPACE 7 // Standard space for a button. + +#define CX_DLGUNIT_BASE 1000 // Values used for converting +#define CY_DLGUNIT_BASE 1000 // dialog units to pixels. + +////////////////////////////////////////////////////////////////////////////// +// Constructors and destructors of the class. + +/** + * Constructor of the class. + * + * This constructor is used to provide the strings directly without providing + * resource IDs from which these strings should be retrieved. If no title is + * given, the application name will be used as the title of the dialog. + */ + CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, CString strMessage, + CString strTitle, UINT nStyle, UINT nHelp ) +{ + // Enable the active accessibility. +#if _MSC_VER >= 1300 + EnableActiveAccessibility(); +#endif + + ASSERT(!strMessage.IsEmpty()); + + // Save the information about the message box. + m_pParent = pParent; + m_strMessage = strMessage; + m_strTitle = strTitle.IsEmpty() ? CString(AfxGetAppName()) : strTitle; + m_nStyle = nStyle; + m_nHelp = nHelp; + + // Do the default initialization. + m_uBeepType = (UINT)-1; + m_hIcon = NULL; + m_nDefaultButton = IDC_STATIC; + m_nEscapeButton = IDC_STATIC; + m_sDialogUnit = CSize(0, 0); + m_sIcon = CSize(0, 0); + m_sMessage = CSize(0, 0); + m_sButton = CSize(0, 0); +} + +/** + * Constructor of the class. + * + * This constructor is used to load the strings for the title and the message + * text from the resources of this project. If no title is given, the + * application name will be used as the title of the dialog. + */ +CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, + UINT nTitleID, UINT nStyle, UINT nHelp ) +{ + // Enable the active accessibility. +#if _MSC_VER >= 1300 + EnableActiveAccessibility(); +#endif + + // Check whether a title was given. + if ( nTitleID == 0 ) + { + // Use the application name. + m_strTitle = AfxGetAppName(); + } + else + { + // Try to load the title from the resources. + VERIFY(m_strTitle.LoadString(nTitleID)); + } + + // Save the information about the message box. + m_pParent = pParent; + VERIFY(m_strMessage.LoadString(nMessageID)); + m_nStyle = nStyle; + m_nHelp = nHelp; + + // Do the default initialization. + m_uBeepType = (UINT)-1; + m_hIcon = NULL; + m_nDefaultButton = IDC_STATIC; + m_nEscapeButton = IDC_STATIC; + m_sDialogUnit = CSize(0, 0); + m_sIcon = CSize(0, 0); + m_sMessage = CSize(0, 0); + m_sButton = CSize(0, 0); +} + +/** + * Destructor of the class. + */ +CMessageBoxDialog::~CMessageBoxDialog ( ) +{ + // Check whether an icon was loaded. + if ( m_hIcon != NULL ) + { + // Free the icon. + DestroyIcon(m_hIcon); + + // Reset the icon handle. + m_hIcon = NULL; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Methods for setting and retrieving dialog options. + +/** + * Method for setting the style of the message box. + */ +inline void CMessageBoxDialog::SetStyle ( UINT nStyle ) +{ + // Set the style of the message box. + m_nStyle = nStyle; +} + +/** + * Method for retrieving the style of the message box. + */ +inline UINT CMessageBoxDialog::GetStyle ( ) +{ + // Return the current style of the message box. + return m_nStyle; +} + +/** + * Method for setting the message to be displayed in the message box. + */ +void CMessageBoxDialog::SetMessage ( CString strMessage ) +{ + ASSERT(!strMessage.IsEmpty()); + + // Save the message text. + m_strMessage = strMessage; +} + +/** + * Methods for setting the message to be displayed in the message box. + */ +void CMessageBoxDialog::SetMessage ( UINT nMessageID ) +{ + // Create a string for storing the message. + CString strMessage = _T(""); + + // Load the message from the resources. + VERIFY(strMessage.LoadString(nMessageID)); + + ASSERT(!strMessage.IsEmpty()); + + // Save the message text. + m_strMessage = strMessage; +} + +/** + * Method for retrieving the message to be displayed in the message box. + */ +CString CMessageBoxDialog::GetMessage ( ) +{ + // Return the message text. + return m_strMessage; +} + +/** + * Method for setting the title to be displayed in the message box. + */ +void CMessageBoxDialog::SetTitle ( CString strTitle ) +{ + // Check whether a title was given. + if ( strTitle.IsEmpty() ) + { + // Use the application name as the title. + strTitle = AfxGetAppName(); + } + + // Save the title. + m_strTitle = strTitle; +} + +/** + * Method for setting the title to be displayed in the message box. + */ +void CMessageBoxDialog::SetTitle ( UINT nTitleID ) +{ + // Create a string for storing the title. + CString strTitle = _T(""); + + // Check whether an ID was given. + if ( nTitleID == 0 ) + { + // Use the application name as the title. + strTitle = AfxGetAppName(); + } + else + { + // Try to load the string from the resources. + VERIFY(strTitle.LoadString(nTitleID)); + + ASSERT(!strTitle.IsEmpty()); + } + + // Save the title. + m_strTitle = strTitle; +} + +/** + * Method for retrieving the title to be displayed in the message box. + */ +CString CMessageBoxDialog::GetTitle ( ) +{ + // Return the title of the message box. + return m_strTitle; +} + +void CMessageBoxDialog::SetMessageBeep(UINT uType) +{ + m_uBeepType = uType; +} + +/** + * Method for setting the icon to be displayed in the message box. + */ +void CMessageBoxDialog::SetMessageIcon ( HICON hIcon ) +{ + ASSERT(hIcon != NULL); + + // Save the icon. + m_hIcon = hIcon; +} + +/** + * Method for setting the icon to be displayed in the message box. + */ +void CMessageBoxDialog::SetMessageIcon ( LPCTSTR lpszIconName, BOOL bStandard ) +{ + // Try to load the given icon. + if (bStandard) + { + if (m_uBeepType==-1) + { + if (lpszIconName==IDI_QUESTION) + m_uBeepType = MB_ICONQUESTION; + else if (lpszIconName==IDI_WARNING || lpszIconName==IDI_EXCLAMATION) + m_uBeepType = MB_ICONWARNING; + else if (lpszIconName==IDI_ERROR || lpszIconName==IDI_HAND) + m_uBeepType = MB_ICONERROR; + else if (lpszIconName==IDI_INFORMATION || lpszIconName==IDI_ASTERISK) + m_uBeepType = MB_ICONINFORMATION; + } + m_hIcon = AfxGetApp()->LoadStandardIcon(lpszIconName); + } + else + m_hIcon = AfxGetApp()->LoadIcon(lpszIconName); + + ASSERT(m_hIcon != NULL); +} + +/** + * Method for retrieving the icon to be displayed in the message box. + */ +HICON CMessageBoxDialog::GetMessageIcon ( ) +{ + // Return the icon for the message box. + return m_hIcon; +} + +////////////////////////////////////////////////////////////////////////////// +// Methods for handling common window functions. + +/** + * Method for displaying the dialog. + * + * If the MB_DONT_DISPLAY_AGAIN or MB_DONT_ASK_AGAIN flag is set, this + * method will check, whether a former result for this dialog was stored + * in the registry. If yes, the former result will be returned without + * displaying the dialog. Otherwise the message box will be displayed in + * the normal way. + */ +INT_PTR CMessageBoxDialog::DoModal ( ) +{ + BYTE abyBuff[512]; + memset(abyBuff, 0, sizeof(abyBuff)); + DLGTEMPLATE* pdlgtmplTemplate = (DLGTEMPLATE*)abyBuff; + pdlgtmplTemplate->x = 0; + pdlgtmplTemplate->y = 0; + pdlgtmplTemplate->cx = 200; + pdlgtmplTemplate->cy = 200; + pdlgtmplTemplate->style = DS_MODALFRAME|WS_CAPTION|WS_VISIBLE|WS_POPUP|WS_SYSMENU|WS_BORDER; + pdlgtmplTemplate->dwExtendedStyle = 0; + pdlgtmplTemplate->cdit = 0; + + //This is the MFC function, which does the job + InitModalIndirect(pdlgtmplTemplate, m_pParent); + + return CDialog::DoModal(); +} + +/** + * Method for initializing the dialog. + * + * This method is used for initializing the dialog. It will create the + * content of the dialog, which means it will create all controls and will + * size the dialog to fit it's content. + */ +BOOL CMessageBoxDialog::OnInitDialog ( ) +{ + // Call the parent method. + if ( !CDialog::OnInitDialog() ) + { + // Return with an error. + return FALSE; + } + + if (!CMPCThemeUtil::getFontByType(messageFont, this, CMPCThemeUtil::MessageFont)) { + return FALSE; + } + + // Set the title of the dialog. + SetWindowText(m_strTitle); + + // Set the help ID of the dialog. + SetHelpID(m_nHelp); + + // Parse the style of the message box. + ParseStyle(); + + // Create the elements of the dialog. + CreateIconControl(); + CreateMessageControl(); + CreateButtonControls(); + + // Define the layout of the dialog. + DefineLayout(); + + // Check whether no sound should be generated. + if ( m_uBeepType != -1 ) + { + // Do a beep. + MessageBeep(m_uBeepType); + } + + // Check whether the window should be system modal. + if ( m_nStyle & MB_SYSTEMMODAL ) + { + // Modify the style of the window. + ModifyStyle(0, DS_SYSMODAL); + } + + // Check whether to bring the window to the foreground. + if ( m_nStyle & MB_SETFOREGROUND ) + { + // Bring the window to the foreground. + SetForegroundWindow(); + } + + // Check whether the window should be the topmost window. + if ( m_nStyle & MB_TOPMOST ) + { + // Modify the style of the window. + ModifyStyleEx(0, WS_EX_TOPMOST); + } + + // Check whether an escape button was defined. + if ( m_nEscapeButton == IDC_STATIC ) + { + // Disable the close item from the system menu. + CMenu* sysmenu = GetSystemMenu(FALSE); + if (sysmenu) + sysmenu->EnableMenuItem(SC_CLOSE, MF_GRAYED); + } + + // Check whether a default button was defined. + if ( m_nDefaultButton != IDC_STATIC ) + { + // Set the focus to the default button. + CWnd* item = GetDlgItem(m_nDefaultButton); + if (item) { + item->SetFocus(); + } + + // Set the default ID of the dialog. + SetDefID(m_nDefaultButton); + + // Return FALSE to set the focus correctly. + return FALSE; + } + + // Everything seems to be done successfully. + return TRUE; +} + +/** + * Method for handling command messages. + * + * This method will handle command messages, which are those messages, which + * are generated, when a user clicks a button of the dialog. + */ +BOOL CMessageBoxDialog::OnCmdMsg ( UINT nID, int nCode, void* pExtra, + AFX_CMDHANDLERINFO* pHandlerInfo ) +{ + // Check whether it's the help button. + if ( ( nID == IDHELP ) && ( nCode == CN_COMMAND ) ) + { + // Display the help for this message box. + OnHelp(); + + // The message has been processed successfully. + return TRUE; + } + + // Check whether the ID of the control element is interesting for us. + if ( ( nID != IDC_STATIC ) && ( nCode == CN_COMMAND ) ) + { + // End the dialog with the given ID. + EndDialog(nID); + + // The message has been processed successfully. + return TRUE; + } + + // Call the parent method. + return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +/** + * Method for handling messages before dispatching them. + * + * This message will handle message before they get dispatched the normal way + * and will therefore implement the additional behavior of this dialog. + */ +BOOL CMessageBoxDialog::PreTranslateMessage ( MSG* pMsg ) +{ + // Check whether it's a key message and whether it's not a disable timeout. + if ( pMsg->message == WM_KEYDOWN ) + { + // Check whether it's the return key. + if ( pMsg->wParam == VK_RETURN ) + { + // Try to retrieve the current focus. + CWnd* pFocusWnd = GetFocus(); + + // Check whether a handle was retrieved. + if ( pFocusWnd != NULL ) + { + // Try to determine the ID of the element. + int nID = pFocusWnd->GetDlgCtrlID(); + + // Check whether the ID is a button. + if ( m_aButtons.FindKey(nID)!=-1 ) + { + EndDialog(nID); + } + else + { + // End the dialog with the default command. + EndDialog(m_nDefaultButton); + } + + // The message has been processed successfully. + return TRUE; + } + } + + // Check whether it's the escape key. + if ( ( pMsg->wParam == VK_ESCAPE ) || ( pMsg->wParam == VK_CANCEL ) ) + { + // Check whether an escape button was defined. + if ( m_nEscapeButton != IDC_STATIC ) + { + // End the dialog with this ID. + EndDialog(m_nEscapeButton); + } + + // The message has been processed successfully. + return TRUE; + } + } + + // Call the parent method. + return CDialog::PreTranslateMessage(pMsg); +} + +////////////////////////////////////////////////////////////////////////////// +// Other dialog handling methods. + +/** + * Method for handling window messages. + */ +BOOL CMessageBoxDialog::OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam, + LRESULT* pResult ) +{ + // Check whether to close the dialog. + if ( message == WM_CLOSE ) + { + // Check whether an escape button is defined. + if ( m_nEscapeButton != IDC_STATIC ) + { + // End the dialog with this command. + EndDialog(m_nEscapeButton); + } + + // The message was handled successfully. + return TRUE; + } + + // Call the parent method. + return CDialog::OnWndMsg(message, wParam, lParam, pResult); +} + +////////////////////////////////////////////////////////////////////////////// +// Helper methods. + +/** + * Method for adding a button to the list of buttons. + * + * This method adds a button to the list of buttons, which will be created in + * the dialog, but it will not create the button control itself. + */ +void CMessageBoxDialog::AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault, + BOOL bIsEscape ) +{ + CString strButtonTitle; + VERIFY(strButtonTitle.LoadString(nTitle)); + + AddButton(nID, strButtonTitle, bIsDefault, bIsEscape); +} + +/** + * Method for adding a button to the list of buttons. + * + * This method adds a button to the list of buttons, which will be created in + * the dialog, but it will not create the button control itself. + */ +void CMessageBoxDialog::AddButton ( UINT nID, CString strTitle, BOOL bIsDefault, + BOOL bIsEscape ) +{ + // Check if one is trying to add the same ID twice + VERIFY( m_aButtons.FindKey(nID)==-1 ); + + // Add the button to the list of buttons. + VERIFY( m_aButtons.Add(nID, strTitle) ); + + // Check whether this button is the default button. + if ( bIsDefault ) + { + // Save the ID of the button as the ID of the default button. + m_nDefaultButton = nID; + } + + // Check whether this button is the escape button. + if ( bIsEscape ) + { + // Save the ID of the button as the ID of the escape button. + m_nEscapeButton = nID; + } +} + +/** + * Method for converting a dialog unit x value to a pixel value. + */ +int CMessageBoxDialog::XDialogUnitToPixel ( int x ) +{ + // Check whether the dimension of a dialog unit has already been determined. + if ( m_sDialogUnit.cx == 0 ) + { + // Create a rect for mapping it to the dialog rect. + CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE); + + // Map the rect to the dialog. + + //mpc-hc: CDialog without a template does not work well with MapDialogRect--use MapDialogRect2 + //MapDialogRect(rcDialog); + CMPCThemeUtil::MapDialogRect2(this, rcDialog); + + // Save the rect. + m_sDialogUnit = rcDialog.Size(); + } + + // Return the converted value. + return ( MulDiv( x , m_sDialogUnit.cx , CX_DLGUNIT_BASE )); +} + +/** + * Method for converting a dialog unit y value to a pixel value. + */ +int CMessageBoxDialog::YDialogUnitToPixel ( int y ) +{ + // Check whether the dimension of a dialog unit has already been determined. + if ( m_sDialogUnit.cy == 0 ) + { + // Create a rect for mapping it to the dialog rect. + CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE); + + // Map the rect to the dialog. + //mpc-hc: CDialog without a template does not work well with MapDialogRect--use MapDialogRect2 + //MapDialogRect(rcDialog); + CMPCThemeUtil::MapDialogRect2(this, rcDialog); + + // Save the rect. + m_sDialogUnit = rcDialog.Size(); + } + + // Return the converted value. + return ( MulDiv( y , m_sDialogUnit.cy , CY_DLGUNIT_BASE ) ); +} + +/** + * Method for parsing the given style. + * + * This method will parse the given style for the message box and will create + * the elements of the dialog box according to it. If you want to add more + * user defined styles, simply modify this method. + */ +void CMessageBoxDialog::ParseStyle ( ) +{ + switch ( m_nStyle & MB_TYPEMASK ) + { + case MB_OKCANCEL: + AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE); + AddButton(IDCANCEL, IDS_CANCEL, FALSE, TRUE); + break; + case MB_ABORTRETRYIGNORE: + AddButton(IDABORT, IDS_MESSAGEBOX_ABORT, TRUE); + AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY); + AddButton(IDIGNORE, IDS_MESSAGEBOX_IGNORE); + break; + case MB_YESNOCANCEL: + AddButton(IDYES, IDS_SUBRESYNC_YES, TRUE); + AddButton(IDNO, IDS_SUBRESYNC_NO); + AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE); + break; + case MB_YESNO: + AddButton(IDYES, IDS_SUBRESYNC_YES, TRUE); + AddButton(IDNO, IDS_SUBRESYNC_NO); + break; + case MB_RETRYCANCEL: + AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY, TRUE); + AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE); + break; + case MB_CANCELTRYCONTINUE: + AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, TRUE, TRUE); + AddButton(IDTRYAGAIN, IDS_MESSAGEBOX_RETRY); + AddButton(IDCONTINUE, IDS_MESSAGEBOX_CONTINUE); + break; + default: + case MB_OK: + AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE, TRUE); + break; + } + // Check whether a default button was defined. + if ( m_nStyle & MB_DEFMASK ) + { + // Create a variable to store the index of the default button. + int nDefaultIndex = 0; + + // Switch the default button. + switch ( m_nStyle & MB_DEFMASK ) + { + + case MB_DEFBUTTON1: + // Set the index of the default button. + nDefaultIndex = 0; + break; + + case MB_DEFBUTTON2: + // Set the index of the default button. + nDefaultIndex = 1; + break; + + case MB_DEFBUTTON3: + // Set the index of the default button. + nDefaultIndex = 2; + break; + + case MB_DEFBUTTON4: + // Set the index of the default button. + nDefaultIndex = 3; + break; + } + + // Check whether enough buttons are available. + if ( m_aButtons.GetSize() >= ( nDefaultIndex + 1 ) ) + { + // Set the new default button. + m_nDefaultButton = m_aButtons.GetKeyAt(nDefaultIndex); + } + } + + // Check whether an icon was specified. + if ( ( m_nStyle & MB_ICONMASK ) && ( m_hIcon == NULL ) ) + { + // Switch the icon. + switch ( m_nStyle & MB_ICONMASK ) + { + case MB_ICONEXCLAMATION: + // Load the icon with the exclamation mark. + SetMessageIcon(IDI_EXCLAMATION, TRUE); + break; + + case MB_ICONHAND: + // Load the icon with the error symbol. + SetMessageIcon(IDI_HAND, TRUE); + break; + + case MB_ICONQUESTION: + // Load the icon with the question mark. + SetMessageIcon(IDI_QUESTION, TRUE); + break; + + case MB_ICONASTERISK: + // Load the icon with the information symbol. + SetMessageIcon(IDI_ASTERISK, TRUE); + break; + } + } +} + +/** + * Method for creating the icon control. + * + * This method will check whether the handle for an icon was defined and if + * yes it will create an control in the dialog to display that icon. + */ +void CMessageBoxDialog::CreateIconControl ( ) +{ + // Check whether an icon was defined. + if ( m_hIcon != NULL ) + { + // Create a structure to read information about the icon. + ICONINFO iiIconInfo; + + // Retrieve information about the icon. + GetIconInfo(m_hIcon, &iiIconInfo); + + ASSERT(iiIconInfo.fIcon); + + // Create a handle to access the bitmap information of the icon. + BITMAP bmIcon; + + // Retrieve the bitmap information of the icon. + GetObject((HGDIOBJ)iiIconInfo.hbmColor, sizeof(bmIcon), &bmIcon); + + // Save the size of the icon. + m_sIcon.cx = bmIcon.bmWidth; + m_sIcon.cy = bmIcon.bmHeight; + + // Create a dummy rect for the icon control. + CRect rcDummy; + + // Create the control for the icon. + m_stcIcon.Create(NULL, WS_CHILD | WS_VISIBLE | WS_DISABLED | SS_ICON, + rcDummy, this, (UINT)IDC_STATIC); + + // Set the icon of the control. + m_stcIcon.SetIcon(m_hIcon); + //m_stcIcon.UnsubclassWindow(); + } +} + +/** + * Method for creating the text control. + * + * This method create the control displaying the text of the message for the + * message box. It will also try to determine the size required for the + * message. + */ +void CMessageBoxDialog::CreateMessageControl ( ) +{ + ASSERT(!m_strMessage.IsEmpty()); + + // Create a DC for accessing the display driver. + CDC dcDisplay; + dcDisplay.CreateDC(_T("DISPLAY"), NULL, NULL, NULL); + + // Select the new font and store the old one. + //mpc-hc use stored font for metrics + //CFont* pOldFont = dcDisplay.SelectObject(GetFont()); + CFont* pOldFont = dcDisplay.SelectObject(&messageFont); + + // Define the maximum width of the message. + int nMaxWidth = GetSystemMetrics(SM_CXSCREEN) - 2 * XDialogUnitToPixel(CX_BORDER); + int minClientHeightExcludingMessage = 2 * YDialogUnitToPixel(CY_TEXTPADDING) + 2 * YDialogUnitToPixel(CY_BORDER) + YDialogUnitToPixel(CY_BUTTON) + 1; + int yPadding = GetThemeSysSize(NULL, SM_CYSIZE) + GetThemeSysSize(NULL, SM_CXPADDEDBORDER) * 2 + minClientHeightExcludingMessage; + int nMaxHeight = GetSystemMetrics(SM_CYSCREEN) - yPadding; + + // Check whether an icon is displayed. + if ( m_hIcon != NULL ) + { + // Decrease the maximum width. + nMaxWidth -= m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); + } + + // Create a rect with the maximum width. + //mpc-hc try to follow windows guidlines for messagebox sizes per https://devblogs.microsoft.com/oldnewthing/20110624-00/?p=10343 + int bestWidth = 99999; + CRect rcMessage(0, 0, nMaxWidth, nMaxHeight); + m_sMessage = rcMessage.Size(); + + for (int widthType = 0; widthType < 5; widthType++) { + int testWidth; + switch (widthType) { + case 0: + testWidth = GetSystemMetrics(SM_CXSCREEN); + break; + case 1: + testWidth = XDialogUnitToPixel(278); + break; + case 2: + testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 5, 8); + break; + case 3: + testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 3, 4); + break; + case 4: + default: + testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 7, 8); + break; + } + rcMessage = CRect(0, 0, testWidth, nMaxHeight); + dcDisplay.DrawText(m_strMessage, rcMessage, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); + if (rcMessage.Width() <= nMaxWidth && rcMessage.Height() <= nMaxHeight) { + if (testWidth < bestWidth) { + m_sMessage = rcMessage.Size(); + bestWidth = testWidth; + } + } + } + + // Select the old font again. + dcDisplay.SelectObject(pOldFont); + + // Create a dummy rect for the control. + CRect rcDummy; + + // Create a variable with the style of the control. + DWORD dwStyle = WS_CHILD | WS_VISIBLE; + + // Check whether the text should be right aligned. + if ( m_nStyle & MB_RIGHT ) + { + // Align the text to the right. + dwStyle |= SS_RIGHT; + } + else + { + // Align the text to the left. + dwStyle |= SS_LEFT; + } + + // Create the static control for the message. + m_stcMessage.Create(m_strMessage, dwStyle, rcDummy, this, + (UINT)IDC_STATIC); + + // Check whether the text will be read from right to left. + if ( m_nStyle & MB_RTLREADING ) + { + // Change the extended style of the control. + m_stcMessage.ModifyStyleEx(0, WS_EX_RTLREADING); + } + + // Set the font of the dialog. + m_stcMessage.SetFont(&messageFont); +} + +/** + * Method for creating the button controls. + * + * According to the list of buttons, which should be displayed in this + * message box, this method will create them and add them to the dialog. + */ +void CMessageBoxDialog::CreateButtonControls ( ) +{ + // Initialize the control with the size of the button. + m_sButton = CSize(XDialogUnitToPixel(CX_BUTTON) + 1,YDialogUnitToPixel(CY_BUTTON) + 1); + + // Create a handle to access the DC of the dialog. + CClientDC dc(this); + + // Retrieve the font for this dialog and select it. + CFont* pWndFont = GetFont(); + CFont* pOldFont = dc.SelectObject(pWndFont); + + // Create a dummy rect. + CRect rcDummy; + + // Run through all buttons defined in the list of the buttons. + for ( int i = 0; i < m_aButtons.GetSize(); i++ ) + { + // Create a string and load the title of the button. + CString strButtonTitle = m_aButtons.GetValueAt(i); + + // Retrieve the size of the text. + CSize sButtonText = dc.GetTextExtent(strButtonTitle); + + // Resize the button. + m_sButton.cx = std::max(m_sButton.cx, sButtonText.cx); + m_sButton.cy = std::max(m_sButton.cy, sButtonText.cy); + + // Create a new handle for creating a button control. + CButton btnControl; + + // Create the button. + btnControl.Create(strButtonTitle, WS_CHILD | WS_VISIBLE | WS_TABSTOP, + rcDummy, this, m_aButtons.GetKeyAt(i)); + + // Set the font of the control. + btnControl.SetFont(&messageFont); + + // Remove the subclassing again. + btnControl.UnsubclassWindow(); + } + + // Add margins to the button size. + m_sButton.cx += 2 * XDialogUnitToPixel(CX_BUTTON_BORDER); + m_sButton.cy += 2 * XDialogUnitToPixel(CY_BUTTON_BORDER); + + // Select the old font again. + dc.SelectObject(pOldFont); +} + +/** + * Method for defining the layout of the dialog. + * + * This method will define the actual layout of the dialog. This layout is + * based on the created controls for the dialog. + */ +void CMessageBoxDialog::DefineLayout ( ) +{ + // Create a variable for storing the size of the dialog. + CSize sClient = CSize(2 * XDialogUnitToPixel(CX_BORDER), + 2 * YDialogUnitToPixel(CY_BORDER)); + + // Create a variable to store the left position for a control element. + int nXPosition = XDialogUnitToPixel(CX_BORDER); + long messageAreaHeight = m_sMessage.cy + 2 * YDialogUnitToPixel(CY_TEXTPADDING); + int nYPosition = YDialogUnitToPixel(CY_TEXTPADDING); + + // Check whether an icon is defined. + if ( m_hIcon != NULL && ::IsWindow(m_stcIcon)) + { + // Move the icon control. + m_stcIcon.MoveWindow(XDialogUnitToPixel(CX_BORDER), YDialogUnitToPixel(CY_BORDER), m_sIcon.cx, m_sIcon.cy); + + // Add the size of the icon to the size of the dialog. + sClient.cx += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); + sClient.cy += m_sIcon.cy + YDialogUnitToPixel(CY_BORDER); + + // Increase the x position for following control elements. + nXPosition += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); + } + + // Change the size of the dialog according to the size of the message. + sClient.cx += m_sMessage.cx + XDialogUnitToPixel(CX_BORDER); + sClient.cy = std::max(sClient.cy, messageAreaHeight); + + // Set the position of the message text. + m_stcMessage.MoveWindow(nXPosition, nYPosition, m_sMessage.cx, + m_sMessage.cy); + + // Define the new y position. + nYPosition = messageAreaHeight; + + // Calculate the width of the buttons. + int cxButtons = + ( m_aButtons.GetSize() - 1 ) * XDialogUnitToPixel(CX_BUTTON_SPACE) + + m_aButtons.GetSize() * m_sButton.cx; + int cyButtons = m_sButton.cy; + + // Add the size of the buttons to the dialog. + sClient.cx = std::max((LONG)sClient.cx, (LONG)2 * XDialogUnitToPixel(CX_BORDER) + cxButtons); + sClient.cy += cyButtons + 2 * YDialogUnitToPixel(CY_BORDER); + + // Calculate the start y position for the buttons. + //mpc-hc align right instead of center + //int nXButtonPosition = (sClient.cx - cxButtons) / 2; + int nXButtonPosition = sClient.cx - cxButtons - XDialogUnitToPixel(CX_BORDER + CX_WINDOW_PADDING); + int nYButtonPosition = sClient.cy - YDialogUnitToPixel(CY_BORDER) - m_sButton.cy; + + buttonAreaY = nYPosition; + + // Run through all buttons. + for ( int i = 0; i < m_aButtons.GetSize(); i++ ) + { + // Try to retrieve the handle to access the button. + CWnd* pButton = GetDlgItem(m_aButtons.GetKeyAt(i)); + + ASSERT(pButton); + + // Check whether the handle was retrieved successfully. + if ( pButton != NULL ) + { + // Move the button. + pButton->MoveWindow(nXButtonPosition, nYButtonPosition, + m_sButton.cx, m_sButton.cy); + + // Set the new x position of the next button. + nXButtonPosition += m_sButton.cx + + XDialogUnitToPixel(CX_BUTTON_SPACE); + } + } + + // Set the dimensions of the dialog. + CRect rcClient(0, 0, sClient.cx, sClient.cy); + + // Calculate the window rect. + CalcWindowRect(rcClient); + + // Move the window. + MoveWindow(rcClient); + + // Center the window. + CenterWindow(); +} diff --git a/src/thirdparty/MessageBoxDialog/MessageBoxDialog.h b/src/thirdparty/MessageBoxDialog/MessageBoxDialog.h index 9d724892e81..0d2fddab46f 100755 --- a/src/thirdparty/MessageBoxDialog/MessageBoxDialog.h +++ b/src/thirdparty/MessageBoxDialog/MessageBoxDialog.h @@ -1,188 +1,188 @@ -/* - * Extended MFC message boxes -- Version 1.2 Lite - * Copyright (c) 2004 Michael P. Mehl. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1a (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/. - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights - * reserved. The Initial Developer of the Original Code is Michael P. Mehl - * . - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU Lesser General Public License Version 2.1 (the "LGPL License"), - * in which case the provisions of LGPL License are applicable instead of - * those above. If you wish to allow use of your version of this file only - * under the terms of the LGPL License and not to allow others to use your - * version of this file under the MPL, indicate your decision by deleting - * the provisions above and replace them with the notice and other provisions - * required by the LGPL License. If you do not delete the provisions above, - * a recipient may use your version of this file under either the MPL or - * the LGPL License. - */ - -#pragma once -#include "../mpc-hc/CMPCThemeStatic.h" -/* mpc-hc modified to use CMPCThemeStatic*/ - -////////////////////////////////////////////////////////////////////////////// -// Class definition. - -class CMessageBoxDialog : public CDialog -{ - - DECLARE_DYNAMIC(CMessageBoxDialog) - -public: - - ////////////////////////////////////////////////////////////////////////// - // Constructors and destructors of the class. - - // Constructor of the class for direct providing of the message strings. - CMessageBoxDialog ( CWnd* pParent, CString strMessage, - CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0 ); - - // Constructor of the class for loading the strings from the resources. - CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, UINT nTitleID = 0, - UINT nStyle = MB_OK, UINT nHelp = 0 ); - - // Default destructor of the class. - virtual ~CMessageBoxDialog ( ); - -public: - - ////////////////////////////////////////////////////////////////////////// - // Method for adding a button to the list of buttons. - void AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault = FALSE, - BOOL bIsEscape = FALSE ); - - // Method for adding a button to the list of buttons. - void AddButton ( UINT nID, CString strTitle, BOOL bIsDefault = FALSE, - BOOL bIsEscape = FALSE ); - - // Method for setting the style of the message box. - void SetStyle ( UINT nStyle ); - - // Method for retrieving the style of the message box. - UINT GetStyle ( ); - - // Methods for setting the message to be displayed in the message box. - void SetMessage ( CString strMessage ); - void SetMessage ( UINT nMessageID ); - - // Method for retrieving the message to be displayed in the message box. - CString GetMessage ( ); - - // Methods for setting the title to be displayed in the message box. - void SetTitle ( CString strTitle ); - void SetTitle ( UINT nTitleID ); - - // Method for retrieving the title to be displayed in the message box. - CString GetTitle ( ); - - // Methods for setting the icon to be displayed in the message box. - void SetMessageIcon ( HICON hIcon ); - void SetMessageIcon ( LPCTSTR lpszIconName, BOOL bStandard = TRUE); - - void SetMessageBeep ( UINT uType ); - - // Method for retrieving the icon to be displayed in the message box. - HICON GetMessageIcon ( ); - -public: - - ////////////////////////////////////////////////////////////////////////// - // Methods for handling common window functions. - - // Method for displaying the dialog. - virtual INT_PTR DoModal ( ); - - // Method for initializing the dialog. - virtual BOOL OnInitDialog ( ); - - // Method for handling command messages. - virtual BOOL OnCmdMsg ( UINT nID, int nCode, void* pExtra, - AFX_CMDHANDLERINFO* pHandlerInfo ); - - // Method for handling messages before dispatching them. - virtual BOOL PreTranslateMessage ( MSG* pMsg ); - -protected: - - ////////////////////////////////////////////////////////////////////////// - // Other methods for handling common window functions. - - // Method for handling window messages. - virtual BOOL OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam, - LRESULT* pResult ); - int buttonAreaY; //mpc-hc used for painting bg -private: - - ////////////////////////////////////////////////////////////////////////// - // Private member variables of this dialog. - - CString m_strMessage; // Message to be displayed. - CString m_strTitle; // Title to be used. - UINT m_nStyle; // Style of the message box. - UINT m_nHelp; // Help context of the message box. - - HICON m_hIcon; // Icon to be displayed in the dialog. - -private: - CSimpleMap m_aButtons; // List of all buttons in the dialog. - - int m_nDefaultButton; // ID of the default button. - int m_nEscapeButton; // ID of the escape button. - - - CStatic m_stcIcon; // Static control for the icon. - //mpc-hc use themed static instead (for message only--themed static has no impl for icons) - CMPCThemeStatic m_stcMessage; // Static control for the message. - CFont messageFont; - - CWnd* m_pParent; - - UINT m_uBeepType; - -private: - - ////////////////////////////////////////////////////////////////////////// - // Size handling variables. - - CSize m_sDialogUnit; // Variable for the size of a dialog unit. - CSize m_sIcon; // Variable for the size of the icon. - CSize m_sMessage; // Variable for the size of the message. - CSize m_sButton; // Variable for the size of a button. - -private: - - ////////////////////////////////////////////////////////////////////////// - // Helper methods. - - // Methods for converting a dialog units to a pixel values. - int XDialogUnitToPixel ( int x ); - int YDialogUnitToPixel ( int y ); - - // Method for parsing the given style. - void ParseStyle ( ); - - // Method for creating the icon control. - void CreateIconControl ( ); - - // Method for creating the message control. - void CreateMessageControl ( ); - - // Method for creating the button controls. - void CreateButtonControls ( ); - - // Method for defining the layout of the dialog. - void DefineLayout ( ); - -}; +/* + * Extended MFC message boxes -- Version 1.2 Lite + * Copyright (c) 2004 Michael P. Mehl. All rights reserved. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1a (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights + * reserved. The Initial Developer of the Original Code is Michael P. Mehl + * . + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU Lesser General Public License Version 2.1 (the "LGPL License"), + * in which case the provisions of LGPL License are applicable instead of + * those above. If you wish to allow use of your version of this file only + * under the terms of the LGPL License and not to allow others to use your + * version of this file under the MPL, indicate your decision by deleting + * the provisions above and replace them with the notice and other provisions + * required by the LGPL License. If you do not delete the provisions above, + * a recipient may use your version of this file under either the MPL or + * the LGPL License. + */ + +#pragma once +#include "../mpc-hc/CMPCThemeStatic.h" +/* mpc-hc modified to use CMPCThemeStatic*/ + +////////////////////////////////////////////////////////////////////////////// +// Class definition. + +class CMessageBoxDialog : public CDialog +{ + + DECLARE_DYNAMIC(CMessageBoxDialog) + +public: + + ////////////////////////////////////////////////////////////////////////// + // Constructors and destructors of the class. + + // Constructor of the class for direct providing of the message strings. + CMessageBoxDialog ( CWnd* pParent, CString strMessage, + CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0 ); + + // Constructor of the class for loading the strings from the resources. + CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, UINT nTitleID = 0, + UINT nStyle = MB_OK, UINT nHelp = 0 ); + + // Default destructor of the class. + virtual ~CMessageBoxDialog ( ); + +public: + + ////////////////////////////////////////////////////////////////////////// + // Method for adding a button to the list of buttons. + void AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault = FALSE, + BOOL bIsEscape = FALSE ); + + // Method for adding a button to the list of buttons. + void AddButton ( UINT nID, CString strTitle, BOOL bIsDefault = FALSE, + BOOL bIsEscape = FALSE ); + + // Method for setting the style of the message box. + void SetStyle ( UINT nStyle ); + + // Method for retrieving the style of the message box. + UINT GetStyle ( ); + + // Methods for setting the message to be displayed in the message box. + void SetMessage ( CString strMessage ); + void SetMessage ( UINT nMessageID ); + + // Method for retrieving the message to be displayed in the message box. + CString GetMessage ( ); + + // Methods for setting the title to be displayed in the message box. + void SetTitle ( CString strTitle ); + void SetTitle ( UINT nTitleID ); + + // Method for retrieving the title to be displayed in the message box. + CString GetTitle ( ); + + // Methods for setting the icon to be displayed in the message box. + void SetMessageIcon ( HICON hIcon ); + void SetMessageIcon ( LPCTSTR lpszIconName, BOOL bStandard = TRUE); + + void SetMessageBeep ( UINT uType ); + + // Method for retrieving the icon to be displayed in the message box. + HICON GetMessageIcon ( ); + +public: + + ////////////////////////////////////////////////////////////////////////// + // Methods for handling common window functions. + + // Method for displaying the dialog. + virtual INT_PTR DoModal ( ); + + // Method for initializing the dialog. + virtual BOOL OnInitDialog ( ); + + // Method for handling command messages. + virtual BOOL OnCmdMsg ( UINT nID, int nCode, void* pExtra, + AFX_CMDHANDLERINFO* pHandlerInfo ); + + // Method for handling messages before dispatching them. + virtual BOOL PreTranslateMessage ( MSG* pMsg ); + +protected: + + ////////////////////////////////////////////////////////////////////////// + // Other methods for handling common window functions. + + // Method for handling window messages. + virtual BOOL OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam, + LRESULT* pResult ); + int buttonAreaY; //mpc-hc used for painting bg +private: + + ////////////////////////////////////////////////////////////////////////// + // Private member variables of this dialog. + + CString m_strMessage; // Message to be displayed. + CString m_strTitle; // Title to be used. + UINT m_nStyle; // Style of the message box. + UINT m_nHelp; // Help context of the message box. + + HICON m_hIcon; // Icon to be displayed in the dialog. + +private: + CSimpleMap m_aButtons; // List of all buttons in the dialog. + + int m_nDefaultButton; // ID of the default button. + int m_nEscapeButton; // ID of the escape button. + + + CStatic m_stcIcon; // Static control for the icon. + //mpc-hc use themed static instead (for message only--themed static has no impl for icons) + CMPCThemeStatic m_stcMessage; // Static control for the message. + CFont messageFont; + + CWnd* m_pParent; + + UINT m_uBeepType; + +private: + + ////////////////////////////////////////////////////////////////////////// + // Size handling variables. + + CSize m_sDialogUnit; // Variable for the size of a dialog unit. + CSize m_sIcon; // Variable for the size of the icon. + CSize m_sMessage; // Variable for the size of the message. + CSize m_sButton; // Variable for the size of a button. + +private: + + ////////////////////////////////////////////////////////////////////////// + // Helper methods. + + // Methods for converting a dialog units to a pixel values. + int XDialogUnitToPixel ( int x ); + int YDialogUnitToPixel ( int y ); + + // Method for parsing the given style. + void ParseStyle ( ); + + // Method for creating the icon control. + void CreateIconControl ( ); + + // Method for creating the message control. + void CreateMessageControl ( ); + + // Method for creating the button controls. + void CreateButtonControls ( ); + + // Method for defining the layout of the dialog. + void DefineLayout ( ); + +}; diff --git a/src/thirdparty/MessageBoxDialog/lgpl-2.1.txt b/src/thirdparty/MessageBoxDialog/lgpl-2.1.txt index dc946ddca28..92b8903ff3f 100755 --- a/src/thirdparty/MessageBoxDialog/lgpl-2.1.txt +++ b/src/thirdparty/MessageBoxDialog/lgpl-2.1.txt @@ -1,481 +1,481 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/src/thirdparty/MessageBoxDialog/mpl-1.1.txt b/src/thirdparty/MessageBoxDialog/mpl-1.1.txt index 7a45bfe8af2..7714141d154 100755 --- a/src/thirdparty/MessageBoxDialog/mpl-1.1.txt +++ b/src/thirdparty/MessageBoxDialog/mpl-1.1.txt @@ -1,470 +1,470 @@ - MOZILLA PUBLIC LICENSE - Version 1.1 - - --------------- - -1. Definitions. - - 1.0.1. "Commercial Use" means distribution or otherwise making the - Covered Code available to a third party. - - 1.1. "Contributor" means each entity that creates or contributes to - the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Code, prior Modifications used by a Contributor, and the Modifications - made by that particular Contributor. - - 1.3. "Covered Code" means the Original Code or Modifications or the - combination of the Original Code and Modifications, in each case - including portions thereof. - - 1.4. "Electronic Distribution Mechanism" means a mechanism generally - accepted in the software development community for the electronic - transfer of data. - - 1.5. "Executable" means Covered Code in any form other than Source - Code. - - 1.6. "Initial Developer" means the individual or entity identified - as the Initial Developer in the Source Code notice required by Exhibit - A. - - 1.7. "Larger Work" means a work which combines Covered Code or - portions thereof with code not governed by the terms of this License. - - 1.8. "License" means this document. - - 1.8.1. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means any addition to or deletion from the - substance or structure of either the Original Code or any previous - Modifications. When Covered Code is released as a series of files, a - Modification is: - A. Any addition to or deletion from the contents of a file - containing Original Code or previous Modifications. - - B. Any new file that contains any part of the Original Code or - previous Modifications. - - 1.10. "Original Code" means Source Code of computer software code - which is described in the Source Code notice required by Exhibit A as - Original Code, and which, at the time of its release under this - License is not already Covered Code governed by this License. - - 1.10.1. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.11. "Source Code" means the preferred form of the Covered Code for - making modifications to it, including all modules it contains, plus - any associated interface definition files, scripts used to control - compilation and installation of an Executable, or source code - differential comparisons against either the Original Code or another - well known, available Covered Code of the Contributor's choice. The - Source Code can be in a compressed or archival form, provided the - appropriate decompression or de-archiving software is widely available - for no charge. - - 1.12. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, this - License or a future version of this License issued under Section 6.1. - For legal entities, "You" includes any entity which controls, is - controlled by, or is under common control with You. For purposes of - this definition, "control" means (a) the power, direct or indirect, - to cause the direction or management of such entity, whether by - contract or otherwise, or (b) ownership of more than fifty percent - (50%) of the outstanding shares or beneficial ownership of such - entity. - -2. Source Code License. - - 2.1. The Initial Developer Grant. - The Initial Developer hereby grants You a world-wide, royalty-free, - non-exclusive license, subject to third party intellectual property - claims: - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Code (or portions thereof) with or without Modifications, and/or - as part of a Larger Work; and - - (b) under Patents Claims infringed by the making, using or - selling of Original Code, to make, have made, use, practice, - sell, and offer for sale, and/or otherwise dispose of the - Original Code (or portions thereof). - - (c) the licenses granted in this Section 2.1(a) and (b) are - effective on the date Initial Developer first distributes - Original Code under the terms of this License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: 1) for code that You delete from the Original Code; 2) - separate from the Original Code; or 3) for infringements caused - by: i) the modification of the Original Code or ii) the - combination of the Original Code with other software or devices. - - 2.2. Contributor Grant. - Subject to third party intellectual property claims, each Contributor - hereby grants You a world-wide, royalty-free, non-exclusive license - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor, to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof) either on an - unmodified basis, with other Modifications, as Covered Code - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either alone - and/or in combination with its Contributor Version (or portions - of such combination), to make, use, sell, offer for sale, have - made, and/or otherwise dispose of: 1) Modifications made by that - Contributor (or portions thereof); and 2) the combination of - Modifications made by that Contributor with its Contributor - Version (or portions of such combination). - - (c) the licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first makes Commercial Use of - the Covered Code. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: 1) for any code that Contributor has deleted from the - Contributor Version; 2) separate from the Contributor Version; - 3) for infringements caused by: i) third party modifications of - Contributor Version or ii) the combination of Modifications made - by that Contributor with other software (except as part of the - Contributor Version) or other devices; or 4) under Patent Claims - infringed by Covered Code in the absence of Modifications made by - that Contributor. - -3. Distribution Obligations. - - 3.1. Application of License. - The Modifications which You create or to which You contribute are - governed by the terms of this License, including without limitation - Section 2.2. The Source Code version of Covered Code may be - distributed only under the terms of this License or a future version - of this License released under Section 6.1, and You must include a - copy of this License with every copy of the Source Code You - distribute. You may not offer or impose any terms on any Source Code - version that alters or restricts the applicable version of this - License or the recipients' rights hereunder. However, You may include - an additional document offering the additional rights described in - Section 3.5. - - 3.2. Availability of Source Code. - Any Modification which You create or to which You contribute must be - made available in Source Code form under the terms of this License - either on the same media as an Executable version or via an accepted - Electronic Distribution Mechanism to anyone to whom you made an - Executable version available; and if made available via Electronic - Distribution Mechanism, must remain available for at least twelve (12) - months after the date it initially became available, or at least six - (6) months after a subsequent version of that particular Modification - has been made available to such recipients. You are responsible for - ensuring that the Source Code version remains available even if the - Electronic Distribution Mechanism is maintained by a third party. - - 3.3. Description of Modifications. - You must cause all Covered Code to which You contribute to contain a - file documenting the changes You made to create that Covered Code and - the date of any change. You must include a prominent statement that - the Modification is derived, directly or indirectly, from Original - Code provided by the Initial Developer and including the name of the - Initial Developer in (a) the Source Code, and (b) in any notice in an - Executable version or related documentation in which You describe the - origin or ownership of the Covered Code. - - 3.4. Intellectual Property Matters - (a) Third Party Claims. - If Contributor has knowledge that a license under a third party's - intellectual property rights is required to exercise the rights - granted by such Contributor under Sections 2.1 or 2.2, - Contributor must include a text file with the Source Code - distribution titled "LEGAL" which describes the claim and the - party making the claim in sufficient detail that a recipient will - know whom to contact. If Contributor obtains such knowledge after - the Modification is made available as described in Section 3.2, - Contributor shall promptly modify the LEGAL file in all copies - Contributor makes available thereafter and shall take other steps - (such as notifying appropriate mailing lists or newsgroups) - reasonably calculated to inform those who received the Covered - Code that new knowledge has been obtained. - - (b) Contributor APIs. - If Contributor's Modifications include an application programming - interface and Contributor has knowledge of patent licenses which - are reasonably necessary to implement that API, Contributor must - also include this information in the LEGAL file. - - (c) Representations. - Contributor represents that, except as disclosed pursuant to - Section 3.4(a) above, Contributor believes that Contributor's - Modifications are Contributor's original creation(s) and/or - Contributor has sufficient rights to grant the rights conveyed by - this License. - - 3.5. Required Notices. - You must duplicate the notice in Exhibit A in each file of the Source - Code. If it is not possible to put such notice in a particular Source - Code file due to its structure, then You must include such notice in a - location (such as a relevant directory) where a user would be likely - to look for such a notice. If You created one or more Modification(s) - You may add your name as a Contributor to the notice described in - Exhibit A. You must also duplicate this License in any documentation - for the Source Code where You describe recipients' rights or ownership - rights relating to Covered Code. You may choose to offer, and to - charge a fee for, warranty, support, indemnity or liability - obligations to one or more recipients of Covered Code. However, You - may do so only on Your own behalf, and not on behalf of the Initial - Developer or any Contributor. You must make it absolutely clear than - any such warranty, support, indemnity or liability obligation is - offered by You alone, and You hereby agree to indemnify the Initial - Developer and every Contributor for any liability incurred by the - Initial Developer or such Contributor as a result of warranty, - support, indemnity or liability terms You offer. - - 3.6. Distribution of Executable Versions. - You may distribute Covered Code in Executable form only if the - requirements of Section 3.1-3.5 have been met for that Covered Code, - and if You include a notice stating that the Source Code version of - the Covered Code is available under the terms of this License, - including a description of how and where You have fulfilled the - obligations of Section 3.2. The notice must be conspicuously included - in any notice in an Executable version, related documentation or - collateral in which You describe recipients' rights relating to the - Covered Code. You may distribute the Executable version of Covered - Code or ownership rights under a license of Your choice, which may - contain terms different from this License, provided that You are in - compliance with the terms of this License and that the license for the - Executable version does not attempt to limit or alter the recipient's - rights in the Source Code version from the rights set forth in this - License. If You distribute the Executable version under a different - license You must make it absolutely clear that any terms which differ - from this License are offered by You alone, not by the Initial - Developer or any Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred by - the Initial Developer or such Contributor as a result of any such - terms You offer. - - 3.7. Larger Works. - You may create a Larger Work by combining Covered Code with other code - not governed by the terms of this License and distribute the Larger - Work as a single product. In such a case, You must make sure the - requirements of this License are fulfilled for the Covered Code. - -4. Inability to Comply Due to Statute or Regulation. - - If it is impossible for You to comply with any of the terms of this - License with respect to some or all of the Covered Code due to - statute, judicial order, or regulation then You must: (a) comply with - the terms of this License to the maximum extent possible; and (b) - describe the limitations and the code they affect. Such description - must be included in the LEGAL file described in Section 3.4 and must - be included with all distributions of the Source Code. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Application of this License. - - This License applies to code to which the Initial Developer has - attached the notice in Exhibit A and to related Covered Code. - -6. Versions of the License. - - 6.1. New Versions. - Netscape Communications Corporation ("Netscape") may publish revised - and/or new versions of the License from time to time. Each version - will be given a distinguishing version number. - - 6.2. Effect of New Versions. - Once Covered Code has been published under a particular version of the - License, You may always continue to use it under the terms of that - version. You may also choose to use such Covered Code under the terms - of any subsequent version of the License published by Netscape. No one - other than Netscape has the right to modify the terms applicable to - Covered Code created under this License. - - 6.3. Derivative Works. - If You create or use a modified version of this License (which you may - only do in order to apply it to code which is not already Covered Code - governed by this License), You must (a) rename Your license so that - the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", - "MPL", "NPL" or any confusingly similar phrase do not appear in your - license (except to note that your license differs from this License) - and (b) otherwise make it clear that Your version of the license - contains terms which differ from the Mozilla Public License and - Netscape Public License. (Filling in the name of the Initial - Developer, Original Code or Contributor in the notice described in - Exhibit A shall not of themselves be deemed to be modifications of - this License.) - -7. DISCLAIMER OF WARRANTY. - - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, - WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF - DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. - THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE - IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, - YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE - COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER - OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -8. TERMINATION. - - 8.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to cure - such breach within 30 days of becoming aware of the breach. All - sublicenses to the Covered Code which are properly granted shall - survive any termination of this License. Provisions which, by their - nature, must remain in effect beyond the termination of this License - shall survive. - - 8.2. If You initiate litigation by asserting a patent infringement - claim (excluding declatory judgment actions) against Initial Developer - or a Contributor (the Initial Developer or Contributor against whom - You file such action is referred to as "Participant") alleging that: - - (a) such Participant's Contributor Version directly or indirectly - infringes any patent, then any and all rights granted by such - Participant to You under Sections 2.1 and/or 2.2 of this License - shall, upon 60 days notice from Participant terminate prospectively, - unless if within 60 days after receipt of notice You either: (i) - agree in writing to pay Participant a mutually agreeable reasonable - royalty for Your past and future use of Modifications made by such - Participant, or (ii) withdraw Your litigation claim with respect to - the Contributor Version against such Participant. If within 60 days - of notice, a reasonable royalty and payment arrangement are not - mutually agreed upon in writing by the parties or the litigation claim - is not withdrawn, the rights granted by Participant to You under - Sections 2.1 and/or 2.2 automatically terminate at the expiration of - the 60 day notice period specified above. - - (b) any software, hardware, or device, other than such Participant's - Contributor Version, directly or indirectly infringes any patent, then - any rights granted to You by such Participant under Sections 2.1(b) - and 2.2(b) are revoked effective as of the date You first made, used, - sold, distributed, or had made, Modifications made by that - Participant. - - 8.3. If You assert a patent infringement claim against Participant - alleging that such Participant's Contributor Version directly or - indirectly infringes any patent where such claim is resolved (such as - by license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 8.4. In the event of termination under Sections 8.1 or 8.2 above, - all end user license agreements (excluding distributors and resellers) - which have been validly granted by You or any distributor hereunder - prior to termination shall survive termination. - -9. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL - DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, - OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR - ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY - CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, - WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY - RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW - PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO - THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - -10. U.S. GOVERNMENT END USERS. - - The Covered Code is a "commercial item," as that term is defined in - 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" and "commercial computer software documentation," as such - terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 - C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), - all U.S. Government End Users acquire Covered Code with only those - rights set forth herein. - -11. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - California law provisions (except to the extent applicable law, if - any, provides otherwise), excluding its conflict-of-law provisions. - With respect to disputes in which at least one party is a citizen of, - or an entity chartered or registered to do business in the United - States of America, any litigation relating to this License shall be - subject to the jurisdiction of the Federal Courts of the Northern - District of California, with venue lying in Santa Clara County, - California, with the losing party responsible for costs, including - without limitation, court costs and reasonable attorneys' fees and - expenses. The application of the United Nations Convention on - Contracts for the International Sale of Goods is expressly excluded. - Any law or regulation which provides that the language of a contract - shall be construed against the drafter shall not apply to this - License. - -12. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - -13. MULTIPLE-LICENSED CODE. - - Initial Developer may designate portions of the Covered Code as - "Multiple-Licensed". "Multiple-Licensed" means that the Initial - Developer permits you to utilize portions of the Covered Code under - Your choice of the NPL or the alternative licenses, if any, specified - by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. - - ``The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is ______________________________________. - - The Initial Developer of the Original Code is ________________________. - Portions created by ______________________ are Copyright (C) ______ - _______________________. All Rights Reserved. - - Contributor(s): ______________________________________. - - Alternatively, the contents of this file may be used under the terms - of the _____ license (the "[___] License"), in which case the - provisions of [______] License are applicable instead of those - above. If you wish to allow use of your version of this file only - under the terms of the [____] License and not to allow others to use - your version of this file under the MPL, indicate your decision by - deleting the provisions above and replace them with the notice and - other provisions required by the [___] License. If you do not delete - the provisions above, a recipient may use your version of this file - under either the MPL or the [___] License." - - [NOTE: The text of this Exhibit A may differ slightly from the text of - the notices in the Source Code files of the Original Code. You should - use the text of this Exhibit A rather than the text found in the - Original Code Source Code for Your Modifications.] - + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + diff --git a/src/thirdparty/RARFileSource/File.h b/src/thirdparty/RARFileSource/File.h index 0547638d4f5..7ee0e0d989e 100644 --- a/src/thirdparty/RARFileSource/File.h +++ b/src/thirdparty/RARFileSource/File.h @@ -36,18 +36,18 @@ class CRFSFile : public CRFSNode delete [] rarFilename; } - class ReadThread { - public: - ReadThread(CRFSFile* file, LONGLONG llPosition, DWORD lLength, BYTE* pBuffer); - DWORD ThreadStart(); - static DWORD WINAPI ThreadStartStatic(void* param); - CRFSFile* file; - LONGLONG llPosition; - DWORD lLength; - BYTE* pBuffer; - LONG read; - }; - static HRESULT SyncRead(void *param); + class ReadThread { + public: + ReadThread(CRFSFile* file, LONGLONG llPosition, DWORD lLength, BYTE* pBuffer); + DWORD ThreadStart(); + static DWORD WINAPI ThreadStartStatic(void* param); + CRFSFile* file; + LONGLONG llPosition; + DWORD lLength; + BYTE* pBuffer; + LONG read; + }; + static HRESULT SyncRead(void *param); HRESULT SyncRead (LONGLONG llPosition, DWORD lLength, BYTE* pBuffer, LONG *cbActual); CMediaType media_type; diff --git a/src/thirdparty/RARFileSource/OutputPin.h b/src/thirdparty/RARFileSource/OutputPin.h index 9e8da66d82e..a6dd5822c08 100644 --- a/src/thirdparty/RARFileSource/OutputPin.h +++ b/src/thirdparty/RARFileSource/OutputPin.h @@ -63,7 +63,7 @@ class CRFSOutputPin : // IAsyncReader interface STDMETHODIMP RequestAllocator (IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual); - STDMETHODIMP Request (IMediaSample* pSample, DWORD_PTR dwUser); + STDMETHODIMP Request (IMediaSample* pSample, DWORD_PTR dwUser); STDMETHODIMP WaitForNext (DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser); STDMETHODIMP SyncReadAligned (IMediaSample *pSample); diff --git a/src/thirdparty/RARFileSource/RARFileSource.vcxproj b/src/thirdparty/RARFileSource/RARFileSource.vcxproj index c328dd132fd..76764dc8bfa 100644 --- a/src/thirdparty/RARFileSource/RARFileSource.vcxproj +++ b/src/thirdparty/RARFileSource/RARFileSource.vcxproj @@ -1,94 +1,94 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {2B7F22D7-1750-47C5-8709-1A3688B62499} - RARFileSource - Win32Proj - RARFileSource - - - - - StaticLibrary - Unicode - - - - - - - - - - - False - - - - ..\..\thirdparty;..\BaseClasses;%(AdditionalIncludeDirectories) - _LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - NotUsing - - - $(OutDir)$(ProjectName).res - - - - - {273b3149-3192-4b75-a791-470320b90812} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {da8461c4-7683-4360-9372-2a9e0f1795c2} - - - - - - - - - - - - - - - - - - - true - true - true - true - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2B7F22D7-1750-47C5-8709-1A3688B62499} + RARFileSource + Win32Proj + RARFileSource + + + + + StaticLibrary + Unicode + + + + + + + + + + + False + + + + ..\..\thirdparty;..\BaseClasses;%(AdditionalIncludeDirectories) + _LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + NotUsing + + + $(OutDir)$(ProjectName).res + + + + + {273b3149-3192-4b75-a791-470320b90812} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {da8461c4-7683-4360-9372-2a9e0f1795c2} + + + + + + + + + + + + + + + + + + + true + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/RARFileSource/RARFileSource.vcxproj.filters b/src/thirdparty/RARFileSource/RARFileSource.vcxproj.filters index 2ded65c9351..4fed9af44e3 100644 --- a/src/thirdparty/RARFileSource/RARFileSource.vcxproj.filters +++ b/src/thirdparty/RARFileSource/RARFileSource.vcxproj.filters @@ -1,68 +1,68 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/src/thirdparty/ResizableLib/ResizableDialog.cpp b/src/thirdparty/ResizableLib/ResizableDialog.cpp index 7c95712be7f..bdb75fe5aaf 100644 --- a/src/thirdparty/ResizableLib/ResizableDialog.cpp +++ b/src/thirdparty/ResizableLib/ResizableDialog.cpp @@ -1,166 +1,166 @@ -// ResizableDialog.cpp : implementation file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "ResizableDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CResizableDialog - -inline void CResizableDialog::PrivateConstruct() -{ - m_bEnableSaveRestore = FALSE; - m_dwGripTempState = 1; - m_bRectOnly = FALSE; -} - -CResizableDialog::CResizableDialog() -{ - PrivateConstruct(); -} - -CResizableDialog::CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd) - : CCmdUIDialog(nIDTemplate, pParentWnd) -{ - PrivateConstruct(); -} - -CResizableDialog::CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) - : CCmdUIDialog(lpszTemplateName, pParentWnd) -{ - PrivateConstruct(); -} - -CResizableDialog::~CResizableDialog() -{ -} - - -BEGIN_MESSAGE_MAP(CResizableDialog, CCmdUIDialog) - //{{AFX_MSG_MAP(CResizableDialog) - ON_WM_GETMINMAXINFO() - ON_WM_SIZE() - ON_WM_DESTROY() - ON_WM_ERASEBKGND() - ON_WM_NCCREATE() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CResizableDialog message handlers - -BOOL CResizableDialog::OnNcCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (!CCmdUIDialog::OnNcCreate(lpCreateStruct)) - return FALSE; - - // child dialogs don't want resizable border or size grip, - // nor they can handle the min/max size constraints - BOOL bChild = lpCreateStruct->style & WS_CHILD; - - // create and init the size-grip - if (!CreateSizeGrip(!bChild)) - return FALSE; - - // Moved from behind if (!bChild) because user could resize the dialog smaller as in resource defined and that causes some static text to be clipped or disappear. - MakeResizable(lpCreateStruct); - - if (!bChild) - { - // set the initial size as the min track size - SetMinTrackSize(CSize(lpCreateStruct->cx, lpCreateStruct->cy)); - } - - return TRUE; -} - -void CResizableDialog::OnDestroy() -{ - if (m_bEnableSaveRestore) - SaveWindowRect(m_sSection, m_bRectOnly); - - // reset instance data - RemoveAllAnchors(); - ResetAllRects(); - PrivateConstruct(); - - __super::OnDestroy(); -} - -void CResizableDialog::OnSize(UINT nType, int cx, int cy) -{ - __super::OnSize(nType, cx, cy); - - if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) - return; // arrangement not needed - - if (nType == SIZE_MAXIMIZED) - HideSizeGrip(&m_dwGripTempState); - else - ShowSizeGrip(&m_dwGripTempState); - - // update grip and layout - UpdateSizeGrip(); - ArrangeLayout(); -} - -void CResizableDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) -{ - MinMaxInfo(lpMMI); -} - -// NOTE: this must be called after setting the layout -// to have the dialog and its controls displayed properly -void CResizableDialog::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly) -{ - m_sSection = pszSection; - - m_bEnableSaveRestore = TRUE; - m_bRectOnly = bRectOnly; - - // restore immediately - LoadWindowRect(pszSection, bRectOnly); -} - -BOOL CResizableDialog::OnEraseBkgnd(CDC* pDC) -{ - ClipChildren(pDC, FALSE); - - BOOL bRet = __super::OnEraseBkgnd(pDC); - - ClipChildren(pDC, TRUE); - - return bRet; -} - -LRESULT CResizableDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message != WM_NCCALCSIZE || wParam == 0) - return __super::WindowProc(message, wParam, lParam); - - LRESULT lResult = 0; - HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - lResult = __super::WindowProc(message, wParam, lParam); - HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - return lResult; -} +// ResizableDialog.cpp : implementation file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ResizableDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CResizableDialog + +inline void CResizableDialog::PrivateConstruct() +{ + m_bEnableSaveRestore = FALSE; + m_dwGripTempState = 1; + m_bRectOnly = FALSE; +} + +CResizableDialog::CResizableDialog() +{ + PrivateConstruct(); +} + +CResizableDialog::CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd) + : CCmdUIDialog(nIDTemplate, pParentWnd) +{ + PrivateConstruct(); +} + +CResizableDialog::CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) + : CCmdUIDialog(lpszTemplateName, pParentWnd) +{ + PrivateConstruct(); +} + +CResizableDialog::~CResizableDialog() +{ +} + + +BEGIN_MESSAGE_MAP(CResizableDialog, CCmdUIDialog) + //{{AFX_MSG_MAP(CResizableDialog) + ON_WM_GETMINMAXINFO() + ON_WM_SIZE() + ON_WM_DESTROY() + ON_WM_ERASEBKGND() + ON_WM_NCCREATE() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CResizableDialog message handlers + +BOOL CResizableDialog::OnNcCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (!CCmdUIDialog::OnNcCreate(lpCreateStruct)) + return FALSE; + + // child dialogs don't want resizable border or size grip, + // nor they can handle the min/max size constraints + BOOL bChild = lpCreateStruct->style & WS_CHILD; + + // create and init the size-grip + if (!CreateSizeGrip(!bChild)) + return FALSE; + + // Moved from behind if (!bChild) because user could resize the dialog smaller as in resource defined and that causes some static text to be clipped or disappear. + MakeResizable(lpCreateStruct); + + if (!bChild) + { + // set the initial size as the min track size + SetMinTrackSize(CSize(lpCreateStruct->cx, lpCreateStruct->cy)); + } + + return TRUE; +} + +void CResizableDialog::OnDestroy() +{ + if (m_bEnableSaveRestore) + SaveWindowRect(m_sSection, m_bRectOnly); + + // reset instance data + RemoveAllAnchors(); + ResetAllRects(); + PrivateConstruct(); + + __super::OnDestroy(); +} + +void CResizableDialog::OnSize(UINT nType, int cx, int cy) +{ + __super::OnSize(nType, cx, cy); + + if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) + return; // arrangement not needed + + if (nType == SIZE_MAXIMIZED) + HideSizeGrip(&m_dwGripTempState); + else + ShowSizeGrip(&m_dwGripTempState); + + // update grip and layout + UpdateSizeGrip(); + ArrangeLayout(); +} + +void CResizableDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + MinMaxInfo(lpMMI); +} + +// NOTE: this must be called after setting the layout +// to have the dialog and its controls displayed properly +void CResizableDialog::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly) +{ + m_sSection = pszSection; + + m_bEnableSaveRestore = TRUE; + m_bRectOnly = bRectOnly; + + // restore immediately + LoadWindowRect(pszSection, bRectOnly); +} + +BOOL CResizableDialog::OnEraseBkgnd(CDC* pDC) +{ + ClipChildren(pDC, FALSE); + + BOOL bRet = __super::OnEraseBkgnd(pDC); + + ClipChildren(pDC, TRUE); + + return bRet; +} + +LRESULT CResizableDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message != WM_NCCALCSIZE || wParam == 0) + return __super::WindowProc(message, wParam, lParam); + + LRESULT lResult = 0; + HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + lResult = __super::WindowProc(message, wParam, lParam); + HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + return lResult; +} diff --git a/src/thirdparty/ResizableLib/ResizableDialog.h b/src/thirdparty/ResizableLib/ResizableDialog.h index da03bc3750c..55882c0079c 100644 --- a/src/thirdparty/ResizableLib/ResizableDialog.h +++ b/src/thirdparty/ResizableLib/ResizableDialog.h @@ -1,103 +1,103 @@ -#if !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_) -#define AFX_RESIZABLEDIALOG_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -// ResizableDialog.h : header file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "ResizableLayout.h" -#include "ResizableGrip.h" -#include "ResizableMinMax.h" -#include "ResizableWndState.h" -#include "../../CmdUI/CmdUI.h" - -///////////////////////////////////////////////////////////////////////////// -// CResizableDialog window - -class CResizableDialog : public CCmdUIDialog, public CResizableLayout, - public CResizableGrip, public CResizableMinMax, - public CResizableWndState -{ - -// Construction -public: - CResizableDialog(); - explicit CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); - explicit CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); - -// Attributes -private: - // support for temporarily hiding the grip - DWORD m_dwGripTempState; - - // flags - BOOL m_bEnableSaveRestore; - BOOL m_bRectOnly; - - // internal status - CString m_sSection; // section name (identifies a parent window) - -// Operations -public: - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CResizableDialog) - protected: - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CResizableDialog(); - -// used internally -private: - void PrivateConstruct(); - -// callable from derived classes -protected: - // section to use in app's profile - void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE); - - virtual CWnd* GetResizableWnd() const - { - // make the layout know its parent window - return CWnd::FromHandle(m_hWnd); - }; - -// Generated message map functions -protected: - //{{AFX_MSG(CResizableDialog) - afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnDestroy(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_) +#if !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_) +#define AFX_RESIZABLEDIALOG_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// ResizableDialog.h : header file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "ResizableLayout.h" +#include "ResizableGrip.h" +#include "ResizableMinMax.h" +#include "ResizableWndState.h" +#include "../../CmdUI/CmdUI.h" + +///////////////////////////////////////////////////////////////////////////// +// CResizableDialog window + +class CResizableDialog : public CCmdUIDialog, public CResizableLayout, + public CResizableGrip, public CResizableMinMax, + public CResizableWndState +{ + +// Construction +public: + CResizableDialog(); + explicit CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); + explicit CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); + +// Attributes +private: + // support for temporarily hiding the grip + DWORD m_dwGripTempState; + + // flags + BOOL m_bEnableSaveRestore; + BOOL m_bRectOnly; + + // internal status + CString m_sSection; // section name (identifies a parent window) + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CResizableDialog) + protected: + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CResizableDialog(); + +// used internally +private: + void PrivateConstruct(); + +// callable from derived classes +protected: + // section to use in app's profile + void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE); + + virtual CWnd* GetResizableWnd() const + { + // make the layout know its parent window + return CWnd::FromHandle(m_hWnd); + }; + +// Generated message map functions +protected: + //{{AFX_MSG(CResizableDialog) + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnDestroy(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableGrip.cpp b/src/thirdparty/ResizableLib/ResizableGrip.cpp index 0071fdb7371..2a777fcdba6 100644 --- a/src/thirdparty/ResizableLib/ResizableGrip.cpp +++ b/src/thirdparty/ResizableLib/ResizableGrip.cpp @@ -1,319 +1,319 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Implementation of the CResizableGrip class. - */ - -#include "stdafx.h" -#include "ResizableGrip.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[]=__FILE__; -#define new DEBUG_NEW -#endif - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResizableGrip::CResizableGrip() -{ - m_nShowCount = 0; -} - -CResizableGrip::~CResizableGrip() -{ - -} - -void CResizableGrip::UpdateSizeGrip() -{ - if (!::IsWindow(m_wndGrip.m_hWnd)) - return; - - // size-grip goes bottom right in the client area - // (any right-to-left adjustment should go here) - - RECT rect; - GetResizableWnd()->GetClientRect(&rect); - - rect.left = rect.right - m_wndGrip.m_size.cx; - rect.top = rect.bottom - m_wndGrip.m_size.cy; - - // must stay below other children - m_wndGrip.SetWindowPos(&CWnd::wndBottom, rect.left, rect.top, 0, 0, - SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION - | (IsSizeGripVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); -} - -// pStatus points to a variable, maintained by the caller, that -// holds its visibility status. Initialize the variable with 1 -// to allow to temporarily hide the grip, 0 to allow to -// temporarily show the grip (with respect to the dwMask bit). - -// NB: visibility is effective only after an update - -void CResizableGrip::ShowSizeGrip(DWORD* pStatus, DWORD dwMask /*= 1*/) -{ - ASSERT(pStatus != NULL); - - if (!(*pStatus & dwMask)) - { - m_nShowCount++; - (*pStatus) |= dwMask; - } -} - -void CResizableGrip::HideSizeGrip(DWORD* pStatus, DWORD dwMask /*= 1*/) -{ - ASSERT(pStatus != NULL); - - if (*pStatus & dwMask) - { - m_nShowCount--; - (*pStatus) &= ~dwMask; - } -} - -BOOL CResizableGrip::IsSizeGripVisible() const -{ - // NB: visibility is effective only after an update - return (m_nShowCount > 0); -} - -void CResizableGrip::SetSizeGripVisibility(BOOL bVisible) -{ - if (bVisible) - m_nShowCount = 1; - else - m_nShowCount = 0; -} - -BOOL CResizableGrip::SetSizeGripBkMode(int nBkMode) -{ - if (::IsWindow(m_wndGrip.m_hWnd)) - { - if (nBkMode == OPAQUE) - m_wndGrip.SetTransparency(FALSE); - else if (nBkMode == TRANSPARENT) - m_wndGrip.SetTransparency(TRUE); - else - return FALSE; - return TRUE; - } - return FALSE; -} - -void CResizableGrip::SetSizeGripShape(BOOL bTriangular) -{ - if (::IsWindow(m_wndGrip.m_hWnd)) - m_wndGrip.SetTriangularShape(bTriangular); -} - -BOOL CResizableGrip::CreateSizeGrip(BOOL bVisible /*= TRUE*/, - BOOL bTriangular /*= TRUE*/, BOOL bTransparent /*= FALSE*/) -{ - // create grip - CRect rect(0 , 0, m_wndGrip.m_size.cx, m_wndGrip.m_size.cy); - BOOL bRet = m_wndGrip.Create(WS_CHILD | WS_CLIPSIBLINGS - | SBS_SIZEGRIP, rect, GetResizableWnd(), 0); - - if (bRet) - { - // set options - m_wndGrip.SetTriangularShape(bTriangular); - m_wndGrip.SetTransparency(bTransparent); - SetSizeGripVisibility(bVisible); - - // update position - UpdateSizeGrip(); - } - - return bRet; -} - -///////////////////////////////////////////////////////////////////////////// -// CSizeGrip implementation - -BOOL CResizableGrip::CSizeGrip::IsRTL() -{ - return GetExStyle() & WS_EX_LAYOUTRTL; -} - -BOOL CResizableGrip::CSizeGrip::PreCreateWindow(CREATESTRUCT& cs) -{ - // set window size - m_size.cx = GetSystemMetrics(SM_CXVSCROLL); - m_size.cy = GetSystemMetrics(SM_CYHSCROLL); - - cs.cx = m_size.cx; - cs.cy = m_size.cy; - - return CScrollBar::PreCreateWindow(cs); -} - -LRESULT CResizableGrip::CSizeGrip::WindowProc(UINT message, - WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_GETDLGCODE: - // fix to prevent the control to gain focus, using arrow keys - // (standard grip returns DLGC_WANTARROWS, like any standard scrollbar) - return DLGC_STATIC; - - case WM_SETFOCUS: - // fix to prevent the control to gain focus, if set directly - // (for example when it's the only one control in a dialog) - return 0; - - case WM_NCHITTEST: - // choose proper cursor shape - return IsRTL() ? HTBOTTOMLEFT : HTBOTTOMRIGHT; - - case WM_SETTINGCHANGE: - { - // update grip's size - CSize sizeOld = m_size; - m_size.cx = GetSystemMetrics(SM_CXVSCROLL); - m_size.cy = GetSystemMetrics(SM_CYHSCROLL); - - // resize transparency bitmaps - if (m_bTransparent) - { - CClientDC dc(this); - - // destroy bitmaps - m_bmGrip.DeleteObject(); - m_bmMask.DeleteObject(); - - // re-create bitmaps - m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy); - m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL); - } - - // re-calc shape - if (m_bTriangular) - SetTriangularShape(m_bTriangular); - - // reposition the grip - CRect rect; - GetWindowRect(rect); - rect.InflateRect(m_size.cx - sizeOld.cx, m_size.cy - sizeOld.cy, 0, 0); - ::MapWindowPoints(NULL, GetParent()->GetSafeHwnd(), (LPPOINT)&rect, 2); - MoveWindow(rect, TRUE); - } - break; - - case WM_DESTROY: - // perform clean up - if (m_bTransparent) - SetTransparency(FALSE); - break; - - case WM_PAINT: - case WM_PRINTCLIENT: - if (m_bTransparent) - { - PAINTSTRUCT ps; - CDC* pDC = (message == WM_PAINT && wParam == 0) ? - BeginPaint(&ps) : CDC::FromHandle((HDC)wParam); - - // select bitmaps - CBitmap *pOldGrip = m_dcGrip.SelectObject(&m_bmGrip); - CBitmap *pOldMask = m_dcMask.SelectObject(&m_bmMask); - - // obtain original grip bitmap, make the mask and prepare masked bitmap - CScrollBar::WindowProc(message, (WPARAM)m_dcGrip.GetSafeHdc(), lParam); - m_dcGrip.SetBkColor(m_dcGrip.GetPixel(0, 0)); - m_dcMask.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCCOPY); - m_dcGrip.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, 0x00220326); - - // draw transparently - pDC->BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, SRCAND); - pDC->BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCPAINT); - - // unselect bitmaps - m_dcGrip.SelectObject(pOldGrip); - m_dcMask.SelectObject(pOldMask); - - if (message == WM_PAINT && wParam == 0) - EndPaint(&ps); - return 0; - } - } - - return CScrollBar::WindowProc(message, wParam, lParam); -} - -void CResizableGrip::CSizeGrip::SetTransparency(BOOL bActivate) -{ - // creates or deletes DCs and Bitmaps used for - // implementing a transparent size grip - - if (bActivate && !m_bTransparent) - { - m_bTransparent = TRUE; - - CClientDC dc(this); - - // create memory DCs and bitmaps - m_dcGrip.CreateCompatibleDC(&dc); - m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy); - - m_dcMask.CreateCompatibleDC(&dc); - m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL); - } - else if (!bActivate && m_bTransparent) - { - m_bTransparent = FALSE; - - // destroy memory DCs and bitmaps - m_dcGrip.DeleteDC(); - m_bmGrip.DeleteObject(); - - m_dcMask.DeleteDC(); - m_bmMask.DeleteObject(); - } -} - -void CResizableGrip::CSizeGrip::SetTriangularShape(BOOL bEnable) -{ - m_bTriangular = bEnable; - - if (bEnable) - { - // set a triangular window region - CRect rect; - GetWindowRect(rect); - rect.OffsetRect(-rect.TopLeft()); - POINT arrPoints[] = - { - { rect.left, rect.bottom }, - { rect.right, rect.bottom }, - { rect.right, rect.top } - }; - CRgn rgnGrip; - rgnGrip.CreatePolygonRgn(arrPoints, 3, WINDING); - SetWindowRgn((HRGN)rgnGrip.Detach(), IsWindowVisible()); - } - else - { - SetWindowRgn((HRGN)NULL, IsWindowVisible()); - } +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Implementation of the CResizableGrip class. + */ + +#include "stdafx.h" +#include "ResizableGrip.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResizableGrip::CResizableGrip() +{ + m_nShowCount = 0; +} + +CResizableGrip::~CResizableGrip() +{ + +} + +void CResizableGrip::UpdateSizeGrip() +{ + if (!::IsWindow(m_wndGrip.m_hWnd)) + return; + + // size-grip goes bottom right in the client area + // (any right-to-left adjustment should go here) + + RECT rect; + GetResizableWnd()->GetClientRect(&rect); + + rect.left = rect.right - m_wndGrip.m_size.cx; + rect.top = rect.bottom - m_wndGrip.m_size.cy; + + // must stay below other children + m_wndGrip.SetWindowPos(&CWnd::wndBottom, rect.left, rect.top, 0, 0, + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION + | (IsSizeGripVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); +} + +// pStatus points to a variable, maintained by the caller, that +// holds its visibility status. Initialize the variable with 1 +// to allow to temporarily hide the grip, 0 to allow to +// temporarily show the grip (with respect to the dwMask bit). + +// NB: visibility is effective only after an update + +void CResizableGrip::ShowSizeGrip(DWORD* pStatus, DWORD dwMask /*= 1*/) +{ + ASSERT(pStatus != NULL); + + if (!(*pStatus & dwMask)) + { + m_nShowCount++; + (*pStatus) |= dwMask; + } +} + +void CResizableGrip::HideSizeGrip(DWORD* pStatus, DWORD dwMask /*= 1*/) +{ + ASSERT(pStatus != NULL); + + if (*pStatus & dwMask) + { + m_nShowCount--; + (*pStatus) &= ~dwMask; + } +} + +BOOL CResizableGrip::IsSizeGripVisible() const +{ + // NB: visibility is effective only after an update + return (m_nShowCount > 0); +} + +void CResizableGrip::SetSizeGripVisibility(BOOL bVisible) +{ + if (bVisible) + m_nShowCount = 1; + else + m_nShowCount = 0; +} + +BOOL CResizableGrip::SetSizeGripBkMode(int nBkMode) +{ + if (::IsWindow(m_wndGrip.m_hWnd)) + { + if (nBkMode == OPAQUE) + m_wndGrip.SetTransparency(FALSE); + else if (nBkMode == TRANSPARENT) + m_wndGrip.SetTransparency(TRUE); + else + return FALSE; + return TRUE; + } + return FALSE; +} + +void CResizableGrip::SetSizeGripShape(BOOL bTriangular) +{ + if (::IsWindow(m_wndGrip.m_hWnd)) + m_wndGrip.SetTriangularShape(bTriangular); +} + +BOOL CResizableGrip::CreateSizeGrip(BOOL bVisible /*= TRUE*/, + BOOL bTriangular /*= TRUE*/, BOOL bTransparent /*= FALSE*/) +{ + // create grip + CRect rect(0 , 0, m_wndGrip.m_size.cx, m_wndGrip.m_size.cy); + BOOL bRet = m_wndGrip.Create(WS_CHILD | WS_CLIPSIBLINGS + | SBS_SIZEGRIP, rect, GetResizableWnd(), 0); + + if (bRet) + { + // set options + m_wndGrip.SetTriangularShape(bTriangular); + m_wndGrip.SetTransparency(bTransparent); + SetSizeGripVisibility(bVisible); + + // update position + UpdateSizeGrip(); + } + + return bRet; +} + +///////////////////////////////////////////////////////////////////////////// +// CSizeGrip implementation + +BOOL CResizableGrip::CSizeGrip::IsRTL() +{ + return GetExStyle() & WS_EX_LAYOUTRTL; +} + +BOOL CResizableGrip::CSizeGrip::PreCreateWindow(CREATESTRUCT& cs) +{ + // set window size + m_size.cx = GetSystemMetrics(SM_CXVSCROLL); + m_size.cy = GetSystemMetrics(SM_CYHSCROLL); + + cs.cx = m_size.cx; + cs.cy = m_size.cy; + + return CScrollBar::PreCreateWindow(cs); +} + +LRESULT CResizableGrip::CSizeGrip::WindowProc(UINT message, + WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_GETDLGCODE: + // fix to prevent the control to gain focus, using arrow keys + // (standard grip returns DLGC_WANTARROWS, like any standard scrollbar) + return DLGC_STATIC; + + case WM_SETFOCUS: + // fix to prevent the control to gain focus, if set directly + // (for example when it's the only one control in a dialog) + return 0; + + case WM_NCHITTEST: + // choose proper cursor shape + return IsRTL() ? HTBOTTOMLEFT : HTBOTTOMRIGHT; + + case WM_SETTINGCHANGE: + { + // update grip's size + CSize sizeOld = m_size; + m_size.cx = GetSystemMetrics(SM_CXVSCROLL); + m_size.cy = GetSystemMetrics(SM_CYHSCROLL); + + // resize transparency bitmaps + if (m_bTransparent) + { + CClientDC dc(this); + + // destroy bitmaps + m_bmGrip.DeleteObject(); + m_bmMask.DeleteObject(); + + // re-create bitmaps + m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy); + m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL); + } + + // re-calc shape + if (m_bTriangular) + SetTriangularShape(m_bTriangular); + + // reposition the grip + CRect rect; + GetWindowRect(rect); + rect.InflateRect(m_size.cx - sizeOld.cx, m_size.cy - sizeOld.cy, 0, 0); + ::MapWindowPoints(NULL, GetParent()->GetSafeHwnd(), (LPPOINT)&rect, 2); + MoveWindow(rect, TRUE); + } + break; + + case WM_DESTROY: + // perform clean up + if (m_bTransparent) + SetTransparency(FALSE); + break; + + case WM_PAINT: + case WM_PRINTCLIENT: + if (m_bTransparent) + { + PAINTSTRUCT ps; + CDC* pDC = (message == WM_PAINT && wParam == 0) ? + BeginPaint(&ps) : CDC::FromHandle((HDC)wParam); + + // select bitmaps + CBitmap *pOldGrip = m_dcGrip.SelectObject(&m_bmGrip); + CBitmap *pOldMask = m_dcMask.SelectObject(&m_bmMask); + + // obtain original grip bitmap, make the mask and prepare masked bitmap + CScrollBar::WindowProc(message, (WPARAM)m_dcGrip.GetSafeHdc(), lParam); + m_dcGrip.SetBkColor(m_dcGrip.GetPixel(0, 0)); + m_dcMask.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCCOPY); + m_dcGrip.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, 0x00220326); + + // draw transparently + pDC->BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, SRCAND); + pDC->BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCPAINT); + + // unselect bitmaps + m_dcGrip.SelectObject(pOldGrip); + m_dcMask.SelectObject(pOldMask); + + if (message == WM_PAINT && wParam == 0) + EndPaint(&ps); + return 0; + } + } + + return CScrollBar::WindowProc(message, wParam, lParam); +} + +void CResizableGrip::CSizeGrip::SetTransparency(BOOL bActivate) +{ + // creates or deletes DCs and Bitmaps used for + // implementing a transparent size grip + + if (bActivate && !m_bTransparent) + { + m_bTransparent = TRUE; + + CClientDC dc(this); + + // create memory DCs and bitmaps + m_dcGrip.CreateCompatibleDC(&dc); + m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy); + + m_dcMask.CreateCompatibleDC(&dc); + m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL); + } + else if (!bActivate && m_bTransparent) + { + m_bTransparent = FALSE; + + // destroy memory DCs and bitmaps + m_dcGrip.DeleteDC(); + m_bmGrip.DeleteObject(); + + m_dcMask.DeleteDC(); + m_bmMask.DeleteObject(); + } +} + +void CResizableGrip::CSizeGrip::SetTriangularShape(BOOL bEnable) +{ + m_bTriangular = bEnable; + + if (bEnable) + { + // set a triangular window region + CRect rect; + GetWindowRect(rect); + rect.OffsetRect(-rect.TopLeft()); + POINT arrPoints[] = + { + { rect.left, rect.bottom }, + { rect.right, rect.bottom }, + { rect.right, rect.top } + }; + CRgn rgnGrip; + rgnGrip.CreatePolygonRgn(arrPoints, 3, WINDING); + SetWindowRgn((HRGN)rgnGrip.Detach(), IsWindowVisible()); + } + else + { + SetWindowRgn((HRGN)NULL, IsWindowVisible()); + } } \ No newline at end of file diff --git a/src/thirdparty/ResizableLib/ResizableGrip.h b/src/thirdparty/ResizableLib/ResizableGrip.h index f0ae37da2ad..7445b7b313e 100644 --- a/src/thirdparty/ResizableLib/ResizableGrip.h +++ b/src/thirdparty/ResizableLib/ResizableGrip.h @@ -1,94 +1,94 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Interface for the CResizableGrip class. - */ - -#if !defined(AFX_RESIZABLEGRIP_H__INCLUDED_) -#define AFX_RESIZABLEGRIP_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -/*! @addtogroup CoreComponents - * @{ - */ - -//! @brief brief_description -/*! - * long_description - */ -class CResizableGrip -{ -private: - class CSizeGrip : public CScrollBar - { - public: - CSizeGrip() - : m_size() - { - m_bTransparent = FALSE; - m_bTriangular = FALSE; - } - - void SetTriangularShape(BOOL bEnable); - void SetTransparency(BOOL bActivate); - - BOOL IsRTL(); // right-to-left layout support - - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - - SIZE m_size; // holds grip size - - protected: - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - - BOOL m_bTriangular; // triangular shape active - BOOL m_bTransparent; // transparency active - - // memory DCs and bitmaps for transparent grip - CDC m_dcGrip, m_dcMask; - CBitmap m_bmGrip, m_bmMask; - }; - - CSizeGrip m_wndGrip; // grip control - int m_nShowCount; // support for hiding the grip - -protected: - // create a size grip, with options - BOOL CreateSizeGrip(BOOL bVisible = TRUE, - BOOL bTriangular = TRUE, BOOL bTransparent = FALSE); - - BOOL IsSizeGripVisible() const; // TRUE if grip is set to be visible - void SetSizeGripVisibility(BOOL bVisible); // set default visibility - void UpdateSizeGrip(); // update the grip's visibility and position - void ShowSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp show the size grip - void HideSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp hide the size grip - BOOL SetSizeGripBkMode(int nBkMode); // like CDC::SetBkMode - void SetSizeGripShape(BOOL bTriangular); - CWnd* GetSizeGripWnd() { return &m_wndGrip; } - - virtual CWnd* GetResizableWnd() const = 0; - -public: - CResizableGrip(); - virtual ~CResizableGrip(); -}; - -// @} -#endif // !defined(AFX_RESIZABLEGRIP_H__INCLUDED_) +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Interface for the CResizableGrip class. + */ + +#if !defined(AFX_RESIZABLEGRIP_H__INCLUDED_) +#define AFX_RESIZABLEGRIP_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/*! @addtogroup CoreComponents + * @{ + */ + +//! @brief brief_description +/*! + * long_description + */ +class CResizableGrip +{ +private: + class CSizeGrip : public CScrollBar + { + public: + CSizeGrip() + : m_size() + { + m_bTransparent = FALSE; + m_bTriangular = FALSE; + } + + void SetTriangularShape(BOOL bEnable); + void SetTransparency(BOOL bActivate); + + BOOL IsRTL(); // right-to-left layout support + + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + + SIZE m_size; // holds grip size + + protected: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + + BOOL m_bTriangular; // triangular shape active + BOOL m_bTransparent; // transparency active + + // memory DCs and bitmaps for transparent grip + CDC m_dcGrip, m_dcMask; + CBitmap m_bmGrip, m_bmMask; + }; + + CSizeGrip m_wndGrip; // grip control + int m_nShowCount; // support for hiding the grip + +protected: + // create a size grip, with options + BOOL CreateSizeGrip(BOOL bVisible = TRUE, + BOOL bTriangular = TRUE, BOOL bTransparent = FALSE); + + BOOL IsSizeGripVisible() const; // TRUE if grip is set to be visible + void SetSizeGripVisibility(BOOL bVisible); // set default visibility + void UpdateSizeGrip(); // update the grip's visibility and position + void ShowSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp show the size grip + void HideSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp hide the size grip + BOOL SetSizeGripBkMode(int nBkMode); // like CDC::SetBkMode + void SetSizeGripShape(BOOL bTriangular); + CWnd* GetSizeGripWnd() { return &m_wndGrip; } + + virtual CWnd* GetResizableWnd() const = 0; + +public: + CResizableGrip(); + virtual ~CResizableGrip(); +}; + +// @} +#endif // !defined(AFX_RESIZABLEGRIP_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableLayout.cpp b/src/thirdparty/ResizableLib/ResizableLayout.cpp index 3d1b7dcbf16..e5dedb0deab 100644 --- a/src/thirdparty/ResizableLib/ResizableLayout.cpp +++ b/src/thirdparty/ResizableLib/ResizableLayout.cpp @@ -1,920 +1,920 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Implementation of the CResizableLayout class. - */ - -#include "stdafx.h" -#include "ResizableLayout.h" -#include "ResizableVersion.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[]=__FILE__; -#define new DEBUG_NEW -#endif - -/*! - * Definition of the standard anchors - */ -const ANCHOR TOP_LEFT(0, 0); -const ANCHOR TOP_CENTER(50, 0); -const ANCHOR TOP_RIGHT(100, 0); -const ANCHOR MIDDLE_LEFT(0, 50); -const ANCHOR MIDDLE_CENTER(50, 50); -const ANCHOR MIDDLE_RIGHT(100, 50); -const ANCHOR BOTTOM_LEFT(0, 100); -const ANCHOR BOTTOM_CENTER(50, 100); -const ANCHOR BOTTOM_RIGHT(100, 100); - -/*! - * @internal Constant used to detect clipping and refresh properties - * - * @note In August 2002 Platform SDK, some guy at MS thought it was time - * to add the missing symbol BS_TYPEMASK, but forgot its original - * meaning and so now he's telling us not to use that symbol because - * its value is likely to change in the future SDK releases, including - * all the BS_* style bits in the mask, not just the button's type - * as the symbol's name suggests. - * @n So now we're forced to define another symbol, great! - */ -#define _BS_TYPEMASK 0x0000000FL - -/*! - * This function adds a new control to the layout manager and sets anchor - * points for its top-left and bottom-right corners. - * - * @param hWnd Window handle to the control to be added - * @param anchorTopLeft Anchor point for the top-left corner - * @param anchorBottomRight Anchor point for the bottom-right corner - * - * @remarks Overlapping controls, like group boxes and the controls inside, - * must be added from the outer controls to the inner ones, to let - * the clipping routines work correctly. - * - * @sa AddAnchorCallback RemoveAnchor - */ -void CResizableLayout::AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) -{ - CWnd* pParent = GetResizableWnd(); - - // child window must be valid - ASSERT(::IsWindow(hWnd)); - // must be child of parent window - ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd)); - - // get parent window's rect - CRect rectParent; - GetTotalClientRect(&rectParent); - // and child control's rect - CRect rectChild; - ::GetWindowRect(hWnd, &rectChild); - ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); - - // adjust position, if client area has been scrolled - rectChild.OffsetRect(-rectParent.TopLeft()); - - // calculate margin for the top-left corner - CSize marginTopLeft(rectChild.left - rectParent.Width() * anchorTopLeft.cx / 100, - rectChild.top - rectParent.Height() * anchorTopLeft.cy / 100); - - // calculate margin for the bottom-right corner - CSize marginBottomRight(rectChild.right - rectParent.Width() * anchorBottomRight.cx / 100, - rectChild.bottom - rectParent.Height() * anchorBottomRight.cy / 100); - - // prepare the structure - LAYOUTINFO layout(hWnd, anchorTopLeft, marginTopLeft, - anchorBottomRight, marginBottomRight); - - // get control's window class - GetClassName(hWnd, layout.sWndClass, MAX_PATH); - - // initialize resize properties (overridable) - InitResizeProperties(layout); - - // must not be already there! - // (this is probably due to a duplicate call to AddAnchor) - POSITION pos; - ASSERT(!m_mapLayout.Lookup(hWnd, pos)); - - // add to the list and the map - pos = m_listLayout.AddTail(layout); - m_mapLayout.SetAt(hWnd, pos); -} - -/*! - * This function adds all the controls not yet added to the layout manager - * and sets anchor points for its top-left and bottom-right corners. - * - * @param anchorTopLeft Anchor point for the top-left corner - * @param anchorBottomRight Anchor point for the bottom-right corner - * @param anchor Anchor point for the top-left and bottom-right corner - * - * @remarks Overlapping controls, like group boxes and the controls inside, - * may not be handled correctly. Use individual @ref AddAnchor calls - * to solve any issues that may arise with clipping. - * - * @sa AddAnchor - */ -void CResizableLayout::AddAllOtherAnchors(ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) -{ - HWND hParent = GetResizableWnd()->GetSafeHwnd(); - ASSERT(::IsWindow(hParent)); - - HWND hWnd = ::GetWindow(hParent, GW_CHILD); - for (; hWnd != NULL; hWnd = ::GetNextWindow(hWnd, GW_HWNDNEXT)) - { - TCHAR szClassName[32]; - if (::GetClassName(hWnd, szClassName, _countof(szClassName))) - { - if (lstrcmp(szClassName, WC_SCROLLBAR) == 0) - { - // skip size grip (which is handled on its own) - DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE); - if ((dwStyle & (WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP)) == (WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP)) - continue; - } - } - - POSITION pos; - if (!m_mapLayout.Lookup(hWnd, pos)) - AddAnchor(hWnd, anchorTopLeft, anchorBottomRight); - } -} - -/*! - * This function adds a placeholder to the layout manager, that will be - * dynamically set by a callback function whenever required. - * - * @return The return value is an integer used to distinguish between - * different placeholders in the callback implementation. - * - * @remarks You must override @ref ArrangeLayoutCallback to provide layout - * information. - * - * @sa AddAnchor ArrangeLayoutCallback ArrangeLayout - */ -LRESULT CResizableLayout::AddAnchorCallback() -{ - // one callback control cannot rely upon another callback control's - // size and/or position (they're updated all together at the end) - // it can however use a non-callback control, calling GetAnchorPosition() - - // add to the list - LAYOUTINFO layout; - layout.nCallbackID = m_listLayoutCB.GetCount() + 1; - m_listLayoutCB.AddTail(layout); - return layout.nCallbackID; -} - -/*! - * This function is called for each placeholder added to the layout manager - * and must be overridden to provide the necessary layout information. - * - * @param layout Reference to a LAYOUTINFO structure to be filled with - * layout information for the specified placeholder. - * On input, nCallbackID is the identification number - * returned by AddAnchorCallback. On output, anchor points and - * the window handle must be set and valid. - * - * @return The return value is @c TRUE if the layout information has been - * provided successfully, @c FALSE to skip this placeholder. - * - * @remarks When implementing this function, unknown placeholders should be - * passed to the base class. Unhandled cases will fire an assertion - * in the debug version. - * - * @sa AddAnchorCallback ArrangeLayout LAYOUTINFO - */ -BOOL CResizableLayout::ArrangeLayoutCallback(LAYOUTINFO& layout) const -{ - UNREFERENCED_PARAMETER(layout); - - ASSERT(FALSE); // must be overridden, if callback is used - - return FALSE; // no useful output data -} - -/*! - * This function should be called in resizable window classes whenever the - * controls layout should be updated, usually after a resize operation. - * - * @remarks All the controls added to the layout are moved and resized at - * once for performance reasons, so all the controls are in their - * old position when AddAnchorCallback is called. - * To know where a control will be placed use GetAnchorPosition. - * - * @sa AddAnchor AddAnchorCallback ArrangeLayoutCallback GetAnchorPosition - */ -void CResizableLayout::ArrangeLayout() const -{ - const INT_PTR count = m_listLayout.GetCount() + m_listLayoutCB.GetCount(); - if (count <= 0) - return; - - CRect rectParent, rectChild; - - // get parent window's rect - GetTotalClientRect(&rectParent); - - // reposition child windows - HDWP hdwp = ::BeginDeferWindowPos(static_cast(count)); - - for (POSITION pos = m_listLayout.GetHeadPosition(); pos != NULL;) - { - // get layout info - const LAYOUTINFO layout = m_listLayout.GetNext(pos); - - UINT uFlags; - // calculate new child's position, size and flags for SetWindowPos - CalcNewChildPosition(layout, rectParent, rectChild, &uFlags); - - // only if size or position changed - if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) - { - hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, - rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); - } - } - - // for callback items you may use GetAnchorPosition to know the - // new position and size of a non-callback item after resizing - - for (POSITION pos = m_listLayoutCB.GetHeadPosition(); pos != NULL;) - { - // get layout info - LAYOUTINFO layout = m_listLayoutCB.GetNext(pos); - // request layout data - if (!ArrangeLayoutCallback(layout)) - continue; - - UINT uFlags; - // calculate new child's position, size and flags for SetWindowPos - CalcNewChildPosition(layout, rectParent, rectChild, &uFlags); - - // only if size or position changed - if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) - { - hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, - rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); - } - } - - // finally move all the windows at once - ::EndDeferWindowPos(hdwp); -} - -/*! - * @internal This function adds or removes a control window region - * to or from the specified clipping region, according to its layout - * properties. - */ -void CResizableLayout::ClipChildWindow(const LAYOUTINFO& layout, - CRgn* pRegion) const -{ - // obtain window position - CRect rect; - ::GetWindowRect(layout.hWnd, &rect); -#if (_WIN32_WINNT >= 0x0501) - //! @todo decide when to clip client only or non-client too (themes?) - //! (leave disabled meanwhile, until I find a good solution) - //! @note wizard97 with watermark bitmap and themes won't look good! - // if (real_WIN32_WINNT >= 0x501) - // ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); -#endif - ::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2); - - // use window region if any - CRgn rgn; - rgn.CreateRectRgn(0,0,0,0); - switch (::GetWindowRgn(layout.hWnd, rgn)) - { - case COMPLEXREGION: - case SIMPLEREGION: - rgn.OffsetRgn(rect.TopLeft()); - break; - - default: - rgn.SetRectRgn(&rect); - } - - // get the clipping property - const BOOL bClipping = layout.properties.bAskClipping ? - LikesClipping(layout) : layout.properties.bCachedLikesClipping; - - // modify region accordingly - if (bClipping) - pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF); - else - pRegion->CombineRgn(pRegion, &rgn, RGN_OR); -} - -/*! - * This function retrieves the clipping region for the current layout. - * It can be used to draw directly inside the region, without applying - * clipping as the ClipChildren function does. - * - * @param pRegion Pointer to a CRegion object that holds the - * calculated clipping region upon return - * - * @deprecated For anti-flickering ClipChildren should be preferred - * as it is more complete for platform compatibility. - * It will probably become a private function. - */ -void CResizableLayout::GetClippingRegion(CRgn* pRegion) const -{ - const CWnd* pWnd = GetResizableWnd(); - - // System's default clipping area is screen's size, - // not enough for max track size, for example: - // if screen is 1024 x 768 and resizing border is 4 pixels, - // maximized size is 1024+4*2=1032 x 768+4*2=776, - // but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!) - // So, if you resize the window to maximum size, the last 4 pixels - // are clipped out by the default clipping region, that gets created - // as soon as you call clipping functions (my guess). - - // reset clipping region to the whole client area - CRect rect; - pWnd->GetClientRect(&rect); - pRegion->CreateRectRgnIndirect(&rect); - - // clip only anchored controls - - for (POSITION pos = m_listLayout.GetHeadPosition(); pos != NULL;) - { - // get layout info - LAYOUTINFO layout = m_listLayout.GetNext(pos); - - if (::IsWindowVisible(layout.hWnd)) - ClipChildWindow(layout, pRegion); - } - - for (POSITION pos = m_listLayoutCB.GetHeadPosition(); pos != NULL;) - { - // get layout info - LAYOUTINFO layout = m_listLayoutCB.GetNext(pos); - // request data - if (ArrangeLayoutCallback(layout) && ::IsWindowVisible(layout.hWnd)) - ClipChildWindow(layout, pRegion); - } -//! @todo Has XP changed this??? It doesn't seem correct anymore! -/* - // fix for RTL layouts (1 pixel of horz offset) - if (pWnd->GetExStyle() & WS_EX_LAYOUTRTL) - pRegion->OffsetRgn(-1,0); -*/ -} - -//! @internal @brief Implements GetAncestor(pWnd->GetSafeHwnd(), GA_ROOT) -inline CWnd* GetRootParentWnd(CWnd* pWnd) -{ - // GetAncestor API not present, emulate - if (!(pWnd->GetStyle() & WS_CHILD)) - return NULL; - while (pWnd->GetStyle() & WS_CHILD) - pWnd = pWnd->GetParent(); - return pWnd; -} - -/*! - * This function enables or restores clipping on the specified DC when - * appropriate. It should be called whenever drawing on the window client - * area to avoid flickering. - * - * @param pDC Pointer to the target device context - * @param bUndo Flag that specifies whether to restore the clipping region - * - * @return The return value is @c TRUE if the clipping region has been - * modified, @c FALSE otherwise - * - * @remarks For anti-flickering to work, you should wrap your - * @c WM_ERASEBKGND message handler inside a pair of calls to - * this function, with the last parameter set to @c FALSE first - * and to @c TRUE at the end. - */ -BOOL CResizableLayout::ClipChildren(const CDC* pDC, BOOL bUndo) -{ -#if (_WIN32_WINNT >= 0x0501 && !defined(RSZLIB_NO_XP_DOUBLE_BUFFER)) - // clipping not necessary when double-buffering enabled - if (real_WIN32_WINNT >= 0x0501) - { - CWnd *pWnd = GetRootParentWnd(GetResizableWnd()); - if (pWnd == NULL) - pWnd = GetResizableWnd(); - if (pWnd->GetExStyle() & WS_EX_COMPOSITED) - return FALSE; - } -#endif - - const HDC hDC = pDC->GetSafeHdc(); - const HWND hWnd = GetResizableWnd()->GetSafeHwnd(); - - // Some controls (such as transparent toolbars and standard controls - // with XP theme enabled) send a WM_ERASEBKGND msg to the parent - // to draw themselves, in which case we must not enable clipping. - - // We check that the window associated with the DC is the - // resizable window and not a child control. - - if (!bUndo) - { - if (hWnd != ::WindowFromDC(hDC)) - m_nOldClipRgn = -1; // invalid region - else - { - // save old DC clipping region - m_nOldClipRgn = ::GetClipRgn(hDC, m_hOldClipRgn); - // clip out supported child windows - CRgn rgnClip; - GetClippingRegion(&rgnClip); - ::ExtSelectClipRgn(hDC, rgnClip, RGN_AND); - } - return (m_nOldClipRgn >= 0) ? TRUE : FALSE; - } - - if (m_nOldClipRgn >= 0) // restore old clipping region, only if modified and valid - { - ::SelectClipRgn(hDC, (m_nOldClipRgn>0 ? m_hOldClipRgn : NULL)); - return TRUE; - } - - return FALSE; -} - -/*! - * This function is used by this class, and should be used by derived - * classes too, in place of the standard GetClientRect. It can be useful - * for windows with scrollbars or expanding windows, to provide the true - * client area, including even those parts which are not visible. - * - * @param lpRect Pointer to the RECT structure that holds the result - * - * @remarks Override this function to provide the client area the class uses - * to perform layout calculations, both when adding controls and - * when rearranging the layout. - * @n The base implementation simply calls @c GetClientRect - */ -void CResizableLayout::GetTotalClientRect(LPRECT lpRect) const -{ - GetResizableWnd()->GetClientRect(lpRect); -} - -/*! - * This function is used to determine if a control needs to be painted when - * it is moved or resized by the layout manager. - * - * @param layout Reference to a @c LAYOUTINFO structure for the control - * @param rectOld Reference to a @c RECT structure that holds the control - * position and size before the layout update - * @param rectNew Reference to a @c RECT structure that holds the control - * position and size after the layout update - * - * @return The return value is @c TRUE if the control should be freshly - * painted after a layout update, @c FALSE if not necessary. - * - * @remarks The default implementation tries to identify windows that - * need refresh by their class name and window style. - * @n Override this function if you need a different behavior or if - * you have custom controls that fail to be identified. - * - * @sa LikesClipping InitResizeProperties - */ -BOOL CResizableLayout::NeedsRefresh(const LAYOUTINFO& layout, - const CRect& rectOld, const CRect& rectNew) const -{ - if (layout.bMsgSupport) - { - REFRESHPROPERTY refresh; - refresh.rcOld = rectOld; - refresh.rcNew = rectNew; - if (Send_NeedsRefresh(layout.hWnd, &refresh)) - return refresh.bNeedsRefresh; - } - - const int nDiffWidth = (rectNew.Width() - rectOld.Width()); - const int nDiffHeight = (rectNew.Height() - rectOld.Height()); - - // is the same size? - if (nDiffWidth == 0 && nDiffHeight == 0) - return FALSE; - - // optimistic, no need to refresh - BOOL bRefresh = FALSE; - - // window classes that need refresh when resized - if (0 == lstrcmp(layout.sWndClass, WC_STATIC)) - { - LONG_PTR style = ::GetWindowLongPtr(layout.hWnd, GWL_STYLE); - - switch (style & SS_TYPEMASK) - { - case SS_LEFT: - case SS_CENTER: - case SS_RIGHT: - // word-wrapped text - bRefresh = bRefresh || (nDiffWidth != 0); - // vertically centered text - if (style & SS_CENTERIMAGE) - bRefresh = bRefresh || (nDiffHeight != 0); - break; - - case SS_LEFTNOWORDWRAP: - // text with ellipsis - if (style & SS_ELLIPSISMASK) - bRefresh = bRefresh || (nDiffWidth != 0); - // vertically centered text - if (style & SS_CENTERIMAGE) - bRefresh = bRefresh || (nDiffHeight != 0); - break; - - case SS_ENHMETAFILE: - case SS_BITMAP: - case SS_ICON: - // images - case SS_BLACKFRAME: - case SS_GRAYFRAME: - case SS_WHITEFRAME: - case SS_ETCHEDFRAME: - // and frames - bRefresh = TRUE; - break; - } - return bRefresh; - } - - // window classes that don't redraw client area correctly - // when the hor scroll pos changes due to a resizing - const BOOL bHScroll = (0 == lstrcmp(layout.sWndClass, WC_LISTBOX)); - - // fix for horizontally scrollable windows, if wider - if (bHScroll && (nDiffWidth > 0)) - { - // get max scroll position - SCROLLINFO info; - info.cbSize = sizeof(SCROLLINFO); - info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; - if (::GetScrollInfo(layout.hWnd, SB_HORZ, &info) && info.nPage > 1) //fix for unsigned subtraction - { - // subtract the page size - info.nMax -= info.nPage-1; //should not use __max() macro - } - - // resizing will cause the text to scroll on the right - // because the scrollbar is going beyond the right limit - if ((info.nMax > 0) && (info.nPos + nDiffWidth > info.nMax)) - { - // needs repainting, due to horiz scrolling - bRefresh = TRUE; - } - } - - return bRefresh; -} - -/*! - * This function is used to determine if a control can be safely clipped - * out of the parent window client area when it is repainted, usually - * after a resize operation. - * - * @param layout Reference to a @c LAYOUTINFO structure for the control - * - * @return The return value is @c TRUE if clipping is supported by the - * control, @c FALSE otherwise. - * - * @remarks The default implementation tries to identify @a clippable - * windows by their class name and window style. - * @n Override this function if you need a different behavior or if - * you have custom controls that fail to be identified. - * - * @sa NeedsRefresh InitResizeProperties - */ -BOOL CResizableLayout::LikesClipping(const LAYOUTINFO& layout) const -{ - if (layout.bMsgSupport) - { - CLIPPINGPROPERTY clipping; - if (Send_LikesClipping(layout.hWnd, &clipping)) - return clipping.bLikesClipping; - } - - const LONG_PTR style = ::GetWindowLongPtr(layout.hWnd, GWL_STYLE); - - // skip windows that wants background repainted - if (0 == lstrcmp(layout.sWndClass, WC_BUTTON)) - { - CRect rect; - switch (style & _BS_TYPEMASK) - { - case BS_GROUPBOX: - return FALSE; - - case BS_OWNERDRAW: - // ownerdraw buttons must return correct hittest code - // to notify their transparency to the system and this library - // or they could use the registered message (more reliable) - ::GetWindowRect(layout.hWnd, &rect); - ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); - if ( HTTRANSPARENT == ::SendMessage(layout.hWnd, - WM_NCHITTEST, 0, MAKELPARAM(rect.left, rect.top)) ) - return FALSE; - break; - } - return TRUE; - } - else if (0 == lstrcmp(layout.sWndClass, WC_STATIC)) - { - switch (style & SS_TYPEMASK) - { - case SS_LEFT: - case SS_CENTER: - case SS_RIGHT: - case SS_LEFTNOWORDWRAP: - // text - case SS_BLACKRECT: - case SS_GRAYRECT: - case SS_WHITERECT: - // filled rects - case SS_ETCHEDHORZ: - case SS_ETCHEDVERT: - // etched lines - case SS_BITMAP: - // bitmaps - return TRUE; - - case SS_ICON: - case SS_ENHMETAFILE: - if (style & SS_CENTERIMAGE) - return FALSE; - return TRUE; - - default: - return FALSE; - } - } - - // assume the others like clipping - return TRUE; -} - - -/*! - * @internal This function calculates the new size and position of a - * control in the layout and flags for @c SetWindowPos - */ -void CResizableLayout::CalcNewChildPosition(const LAYOUTINFO& layout, - const CRect &rectParent, CRect &rectChild, UINT *lpFlags) const -{ - const CWnd* pParent = GetResizableWnd(); - - ::GetWindowRect(layout.hWnd, &rectChild); - ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); - - CRect rectNew; - - // calculate new top-left corner - rectNew.left = layout.marginTopLeft.cx + rectParent.Width() * layout.anchorTopLeft.cx / 100; - rectNew.top = layout.marginTopLeft.cy + rectParent.Height() * layout.anchorTopLeft.cy / 100; - - // calculate new bottom-right corner - rectNew.right = layout.marginBottomRight.cx + rectParent.Width() * layout.anchorBottomRight.cx / 100; - rectNew.bottom = layout.marginBottomRight.cy + rectParent.Height() * layout.anchorBottomRight.cy / 100; - - // adjust position, if client area has been scrolled - rectNew.OffsetRect(rectParent.TopLeft()); - - // get the refresh property - BOOL bRefresh = layout.properties.bAskRefresh ? - NeedsRefresh(layout, rectChild, rectNew) : layout.properties.bCachedNeedsRefresh; - - // set flags - if (lpFlags) - { - *lpFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION; - if (bRefresh) - *lpFlags |= SWP_NOCOPYBITS; - if (rectNew.TopLeft() == rectChild.TopLeft()) - *lpFlags |= SWP_NOMOVE; - if (rectNew.Size() == rectChild.Size()) - *lpFlags |= SWP_NOSIZE; - } - - // update rect - rectChild = rectNew; -} - -/*! - * This function calculates the top, left, bottom, right margins for a - * given size of the specified control. - * - * @param hWnd Window handle to a control in the layout - * @param sizeChild Size of the control to use in calculations - * @param rectMargins Holds the calculated margins - * - * @return The return value is @c TRUE if successful, @c FALSE otherwise - * - * @remarks This function can be used to infer the parent window size - * from the size of one of its child controls. - * It is used to implement cascading of size constraints. - */ -BOOL CResizableLayout::GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const -{ - POSITION pos; - if (!m_mapLayout.Lookup(hWnd, pos)) - return FALSE; - - const LAYOUTINFO& layout = m_listLayout.GetAt(pos); - - // augmented size, relative to anchor points - const CSize size = sizeChild + layout.marginTopLeft - layout.marginBottomRight; - - // percent of parent size occupied by this control - const CSize percent(layout.anchorBottomRight.cx - layout.anchorTopLeft.cx, - layout.anchorBottomRight.cy - layout.anchorTopLeft.cy); - - // calculate total margins - rectMargins.left = size.cx * layout.anchorTopLeft.cx / percent.cx + layout.marginTopLeft.cx; - rectMargins.top = size.cy * layout.anchorTopLeft.cy / percent.cy + layout.marginTopLeft.cy; - rectMargins.right = size.cx * (100 - layout.anchorBottomRight.cx) / percent.cx - layout.marginBottomRight.cx; - rectMargins.bottom = size.cy * (100 - layout.anchorBottomRight.cy) / percent.cy - layout.marginBottomRight.cy; - - return TRUE; -} - -/*! - * This function is used to set the initial resize properties of a control - * in the layout, that are stored in the @c properties member of the - * related @c LAYOUTINFO structure. - * - * @param layout Reference to the @c LAYOUTINFO structure to be set - * - * @remarks The various flags are used to specify whether the resize - * properties (clipping, refresh) can change at run-time, and a new - * call to the property querying functions is needed at every - * layout update, or they are static properties, and the cached - * value is used whenever necessary. - * @n The default implementation sends a registered message to the - * control, giving it the opportunity to specify its resize - * properties, which takes precedence if the message is supported. - * It then sets the @a clipping property as static, calling - * @c LikesClipping only once, and the @a refresh property as - * dynamic, causing @c NeedsRefresh to be called every time. - * @n This should be right for most situations, as the need for - * @a refresh usually depends on the size of the control, while the - * support for @a clipping is usually linked to the specific type - * of control, which is unlikely to change at run-time, but you can - * still override this function if a different behaviour is needed. - * - * @sa LikesClipping NeedsRefresh LAYOUTINFO RESIZEPROPERTIES - */ -void CResizableLayout::InitResizeProperties(LAYOUTINFO &layout) const -{ - // check if custom window supports this library - // (properties must be correctly set by the window) - layout.bMsgSupport = Send_QueryProperties(layout.hWnd, &layout.properties); - - // default properties - if (!layout.bMsgSupport) - { - // clipping property is assumed as static - layout.properties.bAskClipping = FALSE; - layout.properties.bCachedLikesClipping = LikesClipping(layout); - // refresh property is assumed as dynamic - layout.properties.bAskRefresh = TRUE; - } -} - -/*! - * This function modifies a window to enable resizing functionality. - * This affects the window style, size, system menu and appearance. - * - * @param lpCreateStruct Pointer to a @c CREATESTRUCT structure, usually - * passed by the system to the window procedure in a @c WM_CREATE - * or @c WM_NCCREATE - * - * @remarks The function is intended to be called only inside a @c WM_CREATE - * or @c WM_NCCREATE message handler. - */ -void CResizableLayout::MakeResizable(LPCREATESTRUCT lpCreateStruct) const -{ - if (lpCreateStruct->style & WS_CHILD) - return; - - InitThemeSettings(); //! @todo move theme check in more appropriate place - - CWnd* pWnd = GetResizableWnd(); - -#if (_WIN32_WINNT >= 0x0501 && !defined(RSZLIB_NO_XP_DOUBLE_BUFFER)) - // enable double-buffering on supported platforms - pWnd->ModifyStyleEx(0, WS_EX_COMPOSITED); -#endif - - if (!(lpCreateStruct->style & WS_THICKFRAME)) - { - // keep client area - CRect rect(CPoint(lpCreateStruct->x, lpCreateStruct->y), - CSize(lpCreateStruct->cx, lpCreateStruct->cy)); - pWnd->SendMessage(WM_NCCALCSIZE, FALSE, (LPARAM)&rect); - // set resizable style - pWnd->ModifyStyle(DS_MODALFRAME, WS_THICKFRAME); - // adjust size to reflect new style - ::AdjustWindowRectEx(&rect, pWnd->GetStyle(), - ::IsMenu(pWnd->GetMenu()->GetSafeHmenu()), pWnd->GetExStyle()); - pWnd->SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), - SWP_NOSENDCHANGING|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION); - // update dimensions - lpCreateStruct->cx = rect.Width(); - lpCreateStruct->cy = rect.Height(); - } -} - -/*! - * This function should be called inside the parent window @c WM_NCCALCSIZE - * message handler to help eliminate flickering. - * - * @param bAfterDefault Flag that specifies whether the call is made before - * or after the default handler - * @param lpncsp Pointer to the @c NCCALCSIZE_PARAMS structure that is - * passed to the message handler - * @param lResult Reference to the result of the message handler. - * It contains the default handler result on input and the value to - * return from the window procedure on output. - * - * @remarks This function fixes the annoying flickering effect that is - * visible when resizing the top or left edges of the window - * (at least on a "left to right" Windows localized version). - */ -void CResizableLayout::HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT &lResult) -{ - // prevent useless complication when size is not changing - // prevent recursion when resetting the window region (see below) - if ((lpncsp->lppos->flags & SWP_NOSIZE) -#if (_WIN32_WINNT >= 0x0501) - || m_bNoRecursion -#endif - ) - return; - - if (!bAfterDefault) - { - // save a copy before default handler gets called - m_rectClientBefore = lpncsp->rgrc[2]; - } - else // after default WM_NCCALCSIZE msg processing - { - if (lResult != 0) - { - // default handler already uses an advanced validation policy, give up - return; - } - // default calculated client rect - RECT &rectClientAfter = lpncsp->rgrc[0]; - - // intersection between old and new client area is to be preserved - // set source and destination rects to this intersection - RECT &rectPreserve = lpncsp->rgrc[1]; - ::IntersectRect(&rectPreserve, &rectClientAfter, &m_rectClientBefore); - lpncsp->rgrc[2] = rectPreserve; - - lResult = WVR_VALIDRECTS; - - // FIX: window region must be updated before the result of the - // WM_NCCALCSIZE message gets processed by the system, - // otherwise the old window region will clip the client - // area during the preservation process. - // This is especially evident on WinXP when the non-client - // area is rendered with Visual Styles enabled and the - // windows have a non rectangular region. - // NOTE: Implementers of skin systems that modify the window region - // should not rely on this fix and should handle non-client - // window messages themselves, to avoid flickering -#if (_WIN32_WINNT >= 0x0501) - if ((real_WIN32_WINNT >= 0x0501) - && (real_ThemeSettings & STAP_ALLOW_NONCLIENT)) - { - CWnd* pWnd = GetResizableWnd(); - DWORD dwStyle = pWnd->GetStyle(); - if ((dwStyle & (WS_CAPTION|WS_MAXIMIZE)) == WS_CAPTION) - { - m_bNoRecursion = TRUE; - pWnd->SetWindowRgn(NULL, FALSE); - m_bNoRecursion = FALSE; - } - } -#endif - } -} +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Implementation of the CResizableLayout class. + */ + +#include "stdafx.h" +#include "ResizableLayout.h" +#include "ResizableVersion.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +/*! + * Definition of the standard anchors + */ +const ANCHOR TOP_LEFT(0, 0); +const ANCHOR TOP_CENTER(50, 0); +const ANCHOR TOP_RIGHT(100, 0); +const ANCHOR MIDDLE_LEFT(0, 50); +const ANCHOR MIDDLE_CENTER(50, 50); +const ANCHOR MIDDLE_RIGHT(100, 50); +const ANCHOR BOTTOM_LEFT(0, 100); +const ANCHOR BOTTOM_CENTER(50, 100); +const ANCHOR BOTTOM_RIGHT(100, 100); + +/*! + * @internal Constant used to detect clipping and refresh properties + * + * @note In August 2002 Platform SDK, some guy at MS thought it was time + * to add the missing symbol BS_TYPEMASK, but forgot its original + * meaning and so now he's telling us not to use that symbol because + * its value is likely to change in the future SDK releases, including + * all the BS_* style bits in the mask, not just the button's type + * as the symbol's name suggests. + * @n So now we're forced to define another symbol, great! + */ +#define _BS_TYPEMASK 0x0000000FL + +/*! + * This function adds a new control to the layout manager and sets anchor + * points for its top-left and bottom-right corners. + * + * @param hWnd Window handle to the control to be added + * @param anchorTopLeft Anchor point for the top-left corner + * @param anchorBottomRight Anchor point for the bottom-right corner + * + * @remarks Overlapping controls, like group boxes and the controls inside, + * must be added from the outer controls to the inner ones, to let + * the clipping routines work correctly. + * + * @sa AddAnchorCallback RemoveAnchor + */ +void CResizableLayout::AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) +{ + CWnd* pParent = GetResizableWnd(); + + // child window must be valid + ASSERT(::IsWindow(hWnd)); + // must be child of parent window + ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd)); + + // get parent window's rect + CRect rectParent; + GetTotalClientRect(&rectParent); + // and child control's rect + CRect rectChild; + ::GetWindowRect(hWnd, &rectChild); + ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); + + // adjust position, if client area has been scrolled + rectChild.OffsetRect(-rectParent.TopLeft()); + + // calculate margin for the top-left corner + CSize marginTopLeft(rectChild.left - rectParent.Width() * anchorTopLeft.cx / 100, + rectChild.top - rectParent.Height() * anchorTopLeft.cy / 100); + + // calculate margin for the bottom-right corner + CSize marginBottomRight(rectChild.right - rectParent.Width() * anchorBottomRight.cx / 100, + rectChild.bottom - rectParent.Height() * anchorBottomRight.cy / 100); + + // prepare the structure + LAYOUTINFO layout(hWnd, anchorTopLeft, marginTopLeft, + anchorBottomRight, marginBottomRight); + + // get control's window class + GetClassName(hWnd, layout.sWndClass, MAX_PATH); + + // initialize resize properties (overridable) + InitResizeProperties(layout); + + // must not be already there! + // (this is probably due to a duplicate call to AddAnchor) + POSITION pos; + ASSERT(!m_mapLayout.Lookup(hWnd, pos)); + + // add to the list and the map + pos = m_listLayout.AddTail(layout); + m_mapLayout.SetAt(hWnd, pos); +} + +/*! + * This function adds all the controls not yet added to the layout manager + * and sets anchor points for its top-left and bottom-right corners. + * + * @param anchorTopLeft Anchor point for the top-left corner + * @param anchorBottomRight Anchor point for the bottom-right corner + * @param anchor Anchor point for the top-left and bottom-right corner + * + * @remarks Overlapping controls, like group boxes and the controls inside, + * may not be handled correctly. Use individual @ref AddAnchor calls + * to solve any issues that may arise with clipping. + * + * @sa AddAnchor + */ +void CResizableLayout::AddAllOtherAnchors(ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) +{ + HWND hParent = GetResizableWnd()->GetSafeHwnd(); + ASSERT(::IsWindow(hParent)); + + HWND hWnd = ::GetWindow(hParent, GW_CHILD); + for (; hWnd != NULL; hWnd = ::GetNextWindow(hWnd, GW_HWNDNEXT)) + { + TCHAR szClassName[32]; + if (::GetClassName(hWnd, szClassName, _countof(szClassName))) + { + if (lstrcmp(szClassName, WC_SCROLLBAR) == 0) + { + // skip size grip (which is handled on its own) + DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE); + if ((dwStyle & (WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP)) == (WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP)) + continue; + } + } + + POSITION pos; + if (!m_mapLayout.Lookup(hWnd, pos)) + AddAnchor(hWnd, anchorTopLeft, anchorBottomRight); + } +} + +/*! + * This function adds a placeholder to the layout manager, that will be + * dynamically set by a callback function whenever required. + * + * @return The return value is an integer used to distinguish between + * different placeholders in the callback implementation. + * + * @remarks You must override @ref ArrangeLayoutCallback to provide layout + * information. + * + * @sa AddAnchor ArrangeLayoutCallback ArrangeLayout + */ +LRESULT CResizableLayout::AddAnchorCallback() +{ + // one callback control cannot rely upon another callback control's + // size and/or position (they're updated all together at the end) + // it can however use a non-callback control, calling GetAnchorPosition() + + // add to the list + LAYOUTINFO layout; + layout.nCallbackID = m_listLayoutCB.GetCount() + 1; + m_listLayoutCB.AddTail(layout); + return layout.nCallbackID; +} + +/*! + * This function is called for each placeholder added to the layout manager + * and must be overridden to provide the necessary layout information. + * + * @param layout Reference to a LAYOUTINFO structure to be filled with + * layout information for the specified placeholder. + * On input, nCallbackID is the identification number + * returned by AddAnchorCallback. On output, anchor points and + * the window handle must be set and valid. + * + * @return The return value is @c TRUE if the layout information has been + * provided successfully, @c FALSE to skip this placeholder. + * + * @remarks When implementing this function, unknown placeholders should be + * passed to the base class. Unhandled cases will fire an assertion + * in the debug version. + * + * @sa AddAnchorCallback ArrangeLayout LAYOUTINFO + */ +BOOL CResizableLayout::ArrangeLayoutCallback(LAYOUTINFO& layout) const +{ + UNREFERENCED_PARAMETER(layout); + + ASSERT(FALSE); // must be overridden, if callback is used + + return FALSE; // no useful output data +} + +/*! + * This function should be called in resizable window classes whenever the + * controls layout should be updated, usually after a resize operation. + * + * @remarks All the controls added to the layout are moved and resized at + * once for performance reasons, so all the controls are in their + * old position when AddAnchorCallback is called. + * To know where a control will be placed use GetAnchorPosition. + * + * @sa AddAnchor AddAnchorCallback ArrangeLayoutCallback GetAnchorPosition + */ +void CResizableLayout::ArrangeLayout() const +{ + const INT_PTR count = m_listLayout.GetCount() + m_listLayoutCB.GetCount(); + if (count <= 0) + return; + + CRect rectParent, rectChild; + + // get parent window's rect + GetTotalClientRect(&rectParent); + + // reposition child windows + HDWP hdwp = ::BeginDeferWindowPos(static_cast(count)); + + for (POSITION pos = m_listLayout.GetHeadPosition(); pos != NULL;) + { + // get layout info + const LAYOUTINFO layout = m_listLayout.GetNext(pos); + + UINT uFlags; + // calculate new child's position, size and flags for SetWindowPos + CalcNewChildPosition(layout, rectParent, rectChild, &uFlags); + + // only if size or position changed + if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) + { + hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, + rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); + } + } + + // for callback items you may use GetAnchorPosition to know the + // new position and size of a non-callback item after resizing + + for (POSITION pos = m_listLayoutCB.GetHeadPosition(); pos != NULL;) + { + // get layout info + LAYOUTINFO layout = m_listLayoutCB.GetNext(pos); + // request layout data + if (!ArrangeLayoutCallback(layout)) + continue; + + UINT uFlags; + // calculate new child's position, size and flags for SetWindowPos + CalcNewChildPosition(layout, rectParent, rectChild, &uFlags); + + // only if size or position changed + if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) + { + hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, + rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); + } + } + + // finally move all the windows at once + ::EndDeferWindowPos(hdwp); +} + +/*! + * @internal This function adds or removes a control window region + * to or from the specified clipping region, according to its layout + * properties. + */ +void CResizableLayout::ClipChildWindow(const LAYOUTINFO& layout, + CRgn* pRegion) const +{ + // obtain window position + CRect rect; + ::GetWindowRect(layout.hWnd, &rect); +#if (_WIN32_WINNT >= 0x0501) + //! @todo decide when to clip client only or non-client too (themes?) + //! (leave disabled meanwhile, until I find a good solution) + //! @note wizard97 with watermark bitmap and themes won't look good! + // if (real_WIN32_WINNT >= 0x501) + // ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); +#endif + ::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2); + + // use window region if any + CRgn rgn; + rgn.CreateRectRgn(0,0,0,0); + switch (::GetWindowRgn(layout.hWnd, rgn)) + { + case COMPLEXREGION: + case SIMPLEREGION: + rgn.OffsetRgn(rect.TopLeft()); + break; + + default: + rgn.SetRectRgn(&rect); + } + + // get the clipping property + const BOOL bClipping = layout.properties.bAskClipping ? + LikesClipping(layout) : layout.properties.bCachedLikesClipping; + + // modify region accordingly + if (bClipping) + pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF); + else + pRegion->CombineRgn(pRegion, &rgn, RGN_OR); +} + +/*! + * This function retrieves the clipping region for the current layout. + * It can be used to draw directly inside the region, without applying + * clipping as the ClipChildren function does. + * + * @param pRegion Pointer to a CRegion object that holds the + * calculated clipping region upon return + * + * @deprecated For anti-flickering ClipChildren should be preferred + * as it is more complete for platform compatibility. + * It will probably become a private function. + */ +void CResizableLayout::GetClippingRegion(CRgn* pRegion) const +{ + const CWnd* pWnd = GetResizableWnd(); + + // System's default clipping area is screen's size, + // not enough for max track size, for example: + // if screen is 1024 x 768 and resizing border is 4 pixels, + // maximized size is 1024+4*2=1032 x 768+4*2=776, + // but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!) + // So, if you resize the window to maximum size, the last 4 pixels + // are clipped out by the default clipping region, that gets created + // as soon as you call clipping functions (my guess). + + // reset clipping region to the whole client area + CRect rect; + pWnd->GetClientRect(&rect); + pRegion->CreateRectRgnIndirect(&rect); + + // clip only anchored controls + + for (POSITION pos = m_listLayout.GetHeadPosition(); pos != NULL;) + { + // get layout info + LAYOUTINFO layout = m_listLayout.GetNext(pos); + + if (::IsWindowVisible(layout.hWnd)) + ClipChildWindow(layout, pRegion); + } + + for (POSITION pos = m_listLayoutCB.GetHeadPosition(); pos != NULL;) + { + // get layout info + LAYOUTINFO layout = m_listLayoutCB.GetNext(pos); + // request data + if (ArrangeLayoutCallback(layout) && ::IsWindowVisible(layout.hWnd)) + ClipChildWindow(layout, pRegion); + } +//! @todo Has XP changed this??? It doesn't seem correct anymore! +/* + // fix for RTL layouts (1 pixel of horz offset) + if (pWnd->GetExStyle() & WS_EX_LAYOUTRTL) + pRegion->OffsetRgn(-1,0); +*/ +} + +//! @internal @brief Implements GetAncestor(pWnd->GetSafeHwnd(), GA_ROOT) +inline CWnd* GetRootParentWnd(CWnd* pWnd) +{ + // GetAncestor API not present, emulate + if (!(pWnd->GetStyle() & WS_CHILD)) + return NULL; + while (pWnd->GetStyle() & WS_CHILD) + pWnd = pWnd->GetParent(); + return pWnd; +} + +/*! + * This function enables or restores clipping on the specified DC when + * appropriate. It should be called whenever drawing on the window client + * area to avoid flickering. + * + * @param pDC Pointer to the target device context + * @param bUndo Flag that specifies whether to restore the clipping region + * + * @return The return value is @c TRUE if the clipping region has been + * modified, @c FALSE otherwise + * + * @remarks For anti-flickering to work, you should wrap your + * @c WM_ERASEBKGND message handler inside a pair of calls to + * this function, with the last parameter set to @c FALSE first + * and to @c TRUE at the end. + */ +BOOL CResizableLayout::ClipChildren(const CDC* pDC, BOOL bUndo) +{ +#if (_WIN32_WINNT >= 0x0501 && !defined(RSZLIB_NO_XP_DOUBLE_BUFFER)) + // clipping not necessary when double-buffering enabled + if (real_WIN32_WINNT >= 0x0501) + { + CWnd *pWnd = GetRootParentWnd(GetResizableWnd()); + if (pWnd == NULL) + pWnd = GetResizableWnd(); + if (pWnd->GetExStyle() & WS_EX_COMPOSITED) + return FALSE; + } +#endif + + const HDC hDC = pDC->GetSafeHdc(); + const HWND hWnd = GetResizableWnd()->GetSafeHwnd(); + + // Some controls (such as transparent toolbars and standard controls + // with XP theme enabled) send a WM_ERASEBKGND msg to the parent + // to draw themselves, in which case we must not enable clipping. + + // We check that the window associated with the DC is the + // resizable window and not a child control. + + if (!bUndo) + { + if (hWnd != ::WindowFromDC(hDC)) + m_nOldClipRgn = -1; // invalid region + else + { + // save old DC clipping region + m_nOldClipRgn = ::GetClipRgn(hDC, m_hOldClipRgn); + // clip out supported child windows + CRgn rgnClip; + GetClippingRegion(&rgnClip); + ::ExtSelectClipRgn(hDC, rgnClip, RGN_AND); + } + return (m_nOldClipRgn >= 0) ? TRUE : FALSE; + } + + if (m_nOldClipRgn >= 0) // restore old clipping region, only if modified and valid + { + ::SelectClipRgn(hDC, (m_nOldClipRgn>0 ? m_hOldClipRgn : NULL)); + return TRUE; + } + + return FALSE; +} + +/*! + * This function is used by this class, and should be used by derived + * classes too, in place of the standard GetClientRect. It can be useful + * for windows with scrollbars or expanding windows, to provide the true + * client area, including even those parts which are not visible. + * + * @param lpRect Pointer to the RECT structure that holds the result + * + * @remarks Override this function to provide the client area the class uses + * to perform layout calculations, both when adding controls and + * when rearranging the layout. + * @n The base implementation simply calls @c GetClientRect + */ +void CResizableLayout::GetTotalClientRect(LPRECT lpRect) const +{ + GetResizableWnd()->GetClientRect(lpRect); +} + +/*! + * This function is used to determine if a control needs to be painted when + * it is moved or resized by the layout manager. + * + * @param layout Reference to a @c LAYOUTINFO structure for the control + * @param rectOld Reference to a @c RECT structure that holds the control + * position and size before the layout update + * @param rectNew Reference to a @c RECT structure that holds the control + * position and size after the layout update + * + * @return The return value is @c TRUE if the control should be freshly + * painted after a layout update, @c FALSE if not necessary. + * + * @remarks The default implementation tries to identify windows that + * need refresh by their class name and window style. + * @n Override this function if you need a different behavior or if + * you have custom controls that fail to be identified. + * + * @sa LikesClipping InitResizeProperties + */ +BOOL CResizableLayout::NeedsRefresh(const LAYOUTINFO& layout, + const CRect& rectOld, const CRect& rectNew) const +{ + if (layout.bMsgSupport) + { + REFRESHPROPERTY refresh; + refresh.rcOld = rectOld; + refresh.rcNew = rectNew; + if (Send_NeedsRefresh(layout.hWnd, &refresh)) + return refresh.bNeedsRefresh; + } + + const int nDiffWidth = (rectNew.Width() - rectOld.Width()); + const int nDiffHeight = (rectNew.Height() - rectOld.Height()); + + // is the same size? + if (nDiffWidth == 0 && nDiffHeight == 0) + return FALSE; + + // optimistic, no need to refresh + BOOL bRefresh = FALSE; + + // window classes that need refresh when resized + if (0 == lstrcmp(layout.sWndClass, WC_STATIC)) + { + LONG_PTR style = ::GetWindowLongPtr(layout.hWnd, GWL_STYLE); + + switch (style & SS_TYPEMASK) + { + case SS_LEFT: + case SS_CENTER: + case SS_RIGHT: + // word-wrapped text + bRefresh = bRefresh || (nDiffWidth != 0); + // vertically centered text + if (style & SS_CENTERIMAGE) + bRefresh = bRefresh || (nDiffHeight != 0); + break; + + case SS_LEFTNOWORDWRAP: + // text with ellipsis + if (style & SS_ELLIPSISMASK) + bRefresh = bRefresh || (nDiffWidth != 0); + // vertically centered text + if (style & SS_CENTERIMAGE) + bRefresh = bRefresh || (nDiffHeight != 0); + break; + + case SS_ENHMETAFILE: + case SS_BITMAP: + case SS_ICON: + // images + case SS_BLACKFRAME: + case SS_GRAYFRAME: + case SS_WHITEFRAME: + case SS_ETCHEDFRAME: + // and frames + bRefresh = TRUE; + break; + } + return bRefresh; + } + + // window classes that don't redraw client area correctly + // when the hor scroll pos changes due to a resizing + const BOOL bHScroll = (0 == lstrcmp(layout.sWndClass, WC_LISTBOX)); + + // fix for horizontally scrollable windows, if wider + if (bHScroll && (nDiffWidth > 0)) + { + // get max scroll position + SCROLLINFO info; + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + if (::GetScrollInfo(layout.hWnd, SB_HORZ, &info) && info.nPage > 1) //fix for unsigned subtraction + { + // subtract the page size + info.nMax -= info.nPage-1; //should not use __max() macro + } + + // resizing will cause the text to scroll on the right + // because the scrollbar is going beyond the right limit + if ((info.nMax > 0) && (info.nPos + nDiffWidth > info.nMax)) + { + // needs repainting, due to horiz scrolling + bRefresh = TRUE; + } + } + + return bRefresh; +} + +/*! + * This function is used to determine if a control can be safely clipped + * out of the parent window client area when it is repainted, usually + * after a resize operation. + * + * @param layout Reference to a @c LAYOUTINFO structure for the control + * + * @return The return value is @c TRUE if clipping is supported by the + * control, @c FALSE otherwise. + * + * @remarks The default implementation tries to identify @a clippable + * windows by their class name and window style. + * @n Override this function if you need a different behavior or if + * you have custom controls that fail to be identified. + * + * @sa NeedsRefresh InitResizeProperties + */ +BOOL CResizableLayout::LikesClipping(const LAYOUTINFO& layout) const +{ + if (layout.bMsgSupport) + { + CLIPPINGPROPERTY clipping; + if (Send_LikesClipping(layout.hWnd, &clipping)) + return clipping.bLikesClipping; + } + + const LONG_PTR style = ::GetWindowLongPtr(layout.hWnd, GWL_STYLE); + + // skip windows that wants background repainted + if (0 == lstrcmp(layout.sWndClass, WC_BUTTON)) + { + CRect rect; + switch (style & _BS_TYPEMASK) + { + case BS_GROUPBOX: + return FALSE; + + case BS_OWNERDRAW: + // ownerdraw buttons must return correct hittest code + // to notify their transparency to the system and this library + // or they could use the registered message (more reliable) + ::GetWindowRect(layout.hWnd, &rect); + ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); + if ( HTTRANSPARENT == ::SendMessage(layout.hWnd, + WM_NCHITTEST, 0, MAKELPARAM(rect.left, rect.top)) ) + return FALSE; + break; + } + return TRUE; + } + else if (0 == lstrcmp(layout.sWndClass, WC_STATIC)) + { + switch (style & SS_TYPEMASK) + { + case SS_LEFT: + case SS_CENTER: + case SS_RIGHT: + case SS_LEFTNOWORDWRAP: + // text + case SS_BLACKRECT: + case SS_GRAYRECT: + case SS_WHITERECT: + // filled rects + case SS_ETCHEDHORZ: + case SS_ETCHEDVERT: + // etched lines + case SS_BITMAP: + // bitmaps + return TRUE; + + case SS_ICON: + case SS_ENHMETAFILE: + if (style & SS_CENTERIMAGE) + return FALSE; + return TRUE; + + default: + return FALSE; + } + } + + // assume the others like clipping + return TRUE; +} + + +/*! + * @internal This function calculates the new size and position of a + * control in the layout and flags for @c SetWindowPos + */ +void CResizableLayout::CalcNewChildPosition(const LAYOUTINFO& layout, + const CRect &rectParent, CRect &rectChild, UINT *lpFlags) const +{ + const CWnd* pParent = GetResizableWnd(); + + ::GetWindowRect(layout.hWnd, &rectChild); + ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); + + CRect rectNew; + + // calculate new top-left corner + rectNew.left = layout.marginTopLeft.cx + rectParent.Width() * layout.anchorTopLeft.cx / 100; + rectNew.top = layout.marginTopLeft.cy + rectParent.Height() * layout.anchorTopLeft.cy / 100; + + // calculate new bottom-right corner + rectNew.right = layout.marginBottomRight.cx + rectParent.Width() * layout.anchorBottomRight.cx / 100; + rectNew.bottom = layout.marginBottomRight.cy + rectParent.Height() * layout.anchorBottomRight.cy / 100; + + // adjust position, if client area has been scrolled + rectNew.OffsetRect(rectParent.TopLeft()); + + // get the refresh property + BOOL bRefresh = layout.properties.bAskRefresh ? + NeedsRefresh(layout, rectChild, rectNew) : layout.properties.bCachedNeedsRefresh; + + // set flags + if (lpFlags) + { + *lpFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION; + if (bRefresh) + *lpFlags |= SWP_NOCOPYBITS; + if (rectNew.TopLeft() == rectChild.TopLeft()) + *lpFlags |= SWP_NOMOVE; + if (rectNew.Size() == rectChild.Size()) + *lpFlags |= SWP_NOSIZE; + } + + // update rect + rectChild = rectNew; +} + +/*! + * This function calculates the top, left, bottom, right margins for a + * given size of the specified control. + * + * @param hWnd Window handle to a control in the layout + * @param sizeChild Size of the control to use in calculations + * @param rectMargins Holds the calculated margins + * + * @return The return value is @c TRUE if successful, @c FALSE otherwise + * + * @remarks This function can be used to infer the parent window size + * from the size of one of its child controls. + * It is used to implement cascading of size constraints. + */ +BOOL CResizableLayout::GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const +{ + POSITION pos; + if (!m_mapLayout.Lookup(hWnd, pos)) + return FALSE; + + const LAYOUTINFO& layout = m_listLayout.GetAt(pos); + + // augmented size, relative to anchor points + const CSize size = sizeChild + layout.marginTopLeft - layout.marginBottomRight; + + // percent of parent size occupied by this control + const CSize percent(layout.anchorBottomRight.cx - layout.anchorTopLeft.cx, + layout.anchorBottomRight.cy - layout.anchorTopLeft.cy); + + // calculate total margins + rectMargins.left = size.cx * layout.anchorTopLeft.cx / percent.cx + layout.marginTopLeft.cx; + rectMargins.top = size.cy * layout.anchorTopLeft.cy / percent.cy + layout.marginTopLeft.cy; + rectMargins.right = size.cx * (100 - layout.anchorBottomRight.cx) / percent.cx - layout.marginBottomRight.cx; + rectMargins.bottom = size.cy * (100 - layout.anchorBottomRight.cy) / percent.cy - layout.marginBottomRight.cy; + + return TRUE; +} + +/*! + * This function is used to set the initial resize properties of a control + * in the layout, that are stored in the @c properties member of the + * related @c LAYOUTINFO structure. + * + * @param layout Reference to the @c LAYOUTINFO structure to be set + * + * @remarks The various flags are used to specify whether the resize + * properties (clipping, refresh) can change at run-time, and a new + * call to the property querying functions is needed at every + * layout update, or they are static properties, and the cached + * value is used whenever necessary. + * @n The default implementation sends a registered message to the + * control, giving it the opportunity to specify its resize + * properties, which takes precedence if the message is supported. + * It then sets the @a clipping property as static, calling + * @c LikesClipping only once, and the @a refresh property as + * dynamic, causing @c NeedsRefresh to be called every time. + * @n This should be right for most situations, as the need for + * @a refresh usually depends on the size of the control, while the + * support for @a clipping is usually linked to the specific type + * of control, which is unlikely to change at run-time, but you can + * still override this function if a different behaviour is needed. + * + * @sa LikesClipping NeedsRefresh LAYOUTINFO RESIZEPROPERTIES + */ +void CResizableLayout::InitResizeProperties(LAYOUTINFO &layout) const +{ + // check if custom window supports this library + // (properties must be correctly set by the window) + layout.bMsgSupport = Send_QueryProperties(layout.hWnd, &layout.properties); + + // default properties + if (!layout.bMsgSupport) + { + // clipping property is assumed as static + layout.properties.bAskClipping = FALSE; + layout.properties.bCachedLikesClipping = LikesClipping(layout); + // refresh property is assumed as dynamic + layout.properties.bAskRefresh = TRUE; + } +} + +/*! + * This function modifies a window to enable resizing functionality. + * This affects the window style, size, system menu and appearance. + * + * @param lpCreateStruct Pointer to a @c CREATESTRUCT structure, usually + * passed by the system to the window procedure in a @c WM_CREATE + * or @c WM_NCCREATE + * + * @remarks The function is intended to be called only inside a @c WM_CREATE + * or @c WM_NCCREATE message handler. + */ +void CResizableLayout::MakeResizable(LPCREATESTRUCT lpCreateStruct) const +{ + if (lpCreateStruct->style & WS_CHILD) + return; + + InitThemeSettings(); //! @todo move theme check in more appropriate place + + CWnd* pWnd = GetResizableWnd(); + +#if (_WIN32_WINNT >= 0x0501 && !defined(RSZLIB_NO_XP_DOUBLE_BUFFER)) + // enable double-buffering on supported platforms + pWnd->ModifyStyleEx(0, WS_EX_COMPOSITED); +#endif + + if (!(lpCreateStruct->style & WS_THICKFRAME)) + { + // keep client area + CRect rect(CPoint(lpCreateStruct->x, lpCreateStruct->y), + CSize(lpCreateStruct->cx, lpCreateStruct->cy)); + pWnd->SendMessage(WM_NCCALCSIZE, FALSE, (LPARAM)&rect); + // set resizable style + pWnd->ModifyStyle(DS_MODALFRAME, WS_THICKFRAME); + // adjust size to reflect new style + ::AdjustWindowRectEx(&rect, pWnd->GetStyle(), + ::IsMenu(pWnd->GetMenu()->GetSafeHmenu()), pWnd->GetExStyle()); + pWnd->SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), + SWP_NOSENDCHANGING|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION); + // update dimensions + lpCreateStruct->cx = rect.Width(); + lpCreateStruct->cy = rect.Height(); + } +} + +/*! + * This function should be called inside the parent window @c WM_NCCALCSIZE + * message handler to help eliminate flickering. + * + * @param bAfterDefault Flag that specifies whether the call is made before + * or after the default handler + * @param lpncsp Pointer to the @c NCCALCSIZE_PARAMS structure that is + * passed to the message handler + * @param lResult Reference to the result of the message handler. + * It contains the default handler result on input and the value to + * return from the window procedure on output. + * + * @remarks This function fixes the annoying flickering effect that is + * visible when resizing the top or left edges of the window + * (at least on a "left to right" Windows localized version). + */ +void CResizableLayout::HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT &lResult) +{ + // prevent useless complication when size is not changing + // prevent recursion when resetting the window region (see below) + if ((lpncsp->lppos->flags & SWP_NOSIZE) +#if (_WIN32_WINNT >= 0x0501) + || m_bNoRecursion +#endif + ) + return; + + if (!bAfterDefault) + { + // save a copy before default handler gets called + m_rectClientBefore = lpncsp->rgrc[2]; + } + else // after default WM_NCCALCSIZE msg processing + { + if (lResult != 0) + { + // default handler already uses an advanced validation policy, give up + return; + } + // default calculated client rect + RECT &rectClientAfter = lpncsp->rgrc[0]; + + // intersection between old and new client area is to be preserved + // set source and destination rects to this intersection + RECT &rectPreserve = lpncsp->rgrc[1]; + ::IntersectRect(&rectPreserve, &rectClientAfter, &m_rectClientBefore); + lpncsp->rgrc[2] = rectPreserve; + + lResult = WVR_VALIDRECTS; + + // FIX: window region must be updated before the result of the + // WM_NCCALCSIZE message gets processed by the system, + // otherwise the old window region will clip the client + // area during the preservation process. + // This is especially evident on WinXP when the non-client + // area is rendered with Visual Styles enabled and the + // windows have a non rectangular region. + // NOTE: Implementers of skin systems that modify the window region + // should not rely on this fix and should handle non-client + // window messages themselves, to avoid flickering +#if (_WIN32_WINNT >= 0x0501) + if ((real_WIN32_WINNT >= 0x0501) + && (real_ThemeSettings & STAP_ALLOW_NONCLIENT)) + { + CWnd* pWnd = GetResizableWnd(); + DWORD dwStyle = pWnd->GetStyle(); + if ((dwStyle & (WS_CAPTION|WS_MAXIMIZE)) == WS_CAPTION) + { + m_bNoRecursion = TRUE; + pWnd->SetWindowRgn(NULL, FALSE); + m_bNoRecursion = FALSE; + } + } +#endif + } +} diff --git a/src/thirdparty/ResizableLib/ResizableLayout.h b/src/thirdparty/ResizableLib/ResizableLayout.h index 3ebb452063a..a5473b74c96 100644 --- a/src/thirdparty/ResizableLib/ResizableLayout.h +++ b/src/thirdparty/ResizableLib/ResizableLayout.h @@ -1,316 +1,316 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Interface for the CResizableLayout class. - */ - -#if !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_) -#define AFX_RESIZABLELAYOUT_H__INCLUDED_ - -//#include -#include "ResizableMsgSupport.h" - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -/*! @addtogroup CoreComponents - * @{ - */ - -//! @brief Special type for layout alignment -/*! - * Implements anchor points as a percentage of the parent window client area. - * Control corners are always kept at a fixed distance from their anchor points, - * thus allowing a control to resize proportionally as the parent window is resized. - */ -typedef struct tagANCHOR -{ - int cx; //!< horizontal component, in percent - int cy; //!< vertical component, in percent - - tagANCHOR() : cx(0), cy(0) {} - - tagANCHOR(int x, int y) - { - cx = x; - cy = y; - } - -} ANCHOR, *PANCHOR, *LPANCHOR; - -/*! @defgroup ConstAnchors Alignment Constants - * Declare common layout alignment constants for anchor points. - * @{ - */ - //! Anchor to the top-left corner - extern const ANCHOR TOP_LEFT; - //! Anchor to the top edge and center horizontally - extern const ANCHOR TOP_CENTER; - //! Anchor to the top-right corner - extern const ANCHOR TOP_RIGHT; - //! Anchor to the left edge and center vertically - extern const ANCHOR MIDDLE_LEFT; - //! Anchor to the center - extern const ANCHOR MIDDLE_CENTER; - //! Anchor to the right edge and center vertically - extern const ANCHOR MIDDLE_RIGHT; - //! Anchor to the bottom-left corner - extern const ANCHOR BOTTOM_LEFT; - //! Anchor to the bottom edge and center horizontally - extern const ANCHOR BOTTOM_CENTER; - //! Anchor to the bottom-right corner - extern const ANCHOR BOTTOM_RIGHT; -// @} - -//! @brief Holds a control layout settings -/*! - * Layout settings specify how a control must be moved and resized with respect to - * the parent window and how it reacts to dynamic changes to its size when painting - * its client area, with special care for flickering. - */ -typedef struct tagLAYOUTINFO -{ - //! Handle of the window the layout of which is being defined - HWND hWnd; - //! Identification number assigned to the callback slot - LRESULT nCallbackID; - - //! Window class name to identify standard controls - TCHAR sWndClass[MAX_PATH]; - - //! Anchor point for the top-left corner - ANCHOR anchorTopLeft; - //! Fixed distance for the top-left corner - SIZE marginTopLeft; - - //! Anchor point for the bottom-right corner - ANCHOR anchorBottomRight; - //! Fixed distance for the bottom-right corner - SIZE marginBottomRight; - - //! Flag that enables support for custom windows - BOOL bMsgSupport; - //! Redraw settings for anti-flickering and proper painting - RESIZEPROPERTIES properties; - - tagLAYOUTINFO() : hWnd(NULL), nCallbackID(0) - , marginTopLeft(), marginBottomRight(), bMsgSupport(FALSE) - { - sWndClass[0] = 0; - } - - tagLAYOUTINFO(HWND hwnd, ANCHOR tl_type, SIZE tl_margin, - ANCHOR br_type, SIZE br_margin) - : - hWnd(hwnd), nCallbackID(0), - anchorTopLeft(tl_type), marginTopLeft(tl_margin), - anchorBottomRight(br_type), marginBottomRight(br_margin), bMsgSupport(FALSE) - { - sWndClass[0] = 0; - } - -} LAYOUTINFO, *PLAYOUTINFO, *LPLAYOUTINFO; - -//! @brief Layout manager implementation -/*! - * Derive from this class to implement resizable windows, adding the ability - * to dinamically resize and reposition child controls. - * Special care is taken to ensure a smooth animation during the resize - * operations performed by the users, without annoying flickering effects. - */ -class CResizableLayout -{ -private: - //@{ - //! @brief Collection of layout settings for each control - CMap m_mapLayout; - CList m_listLayout; - CList m_listLayoutCB; - //@} - - //@{ - //! @brief Used for clipping implementation - HRGN m_hOldClipRgn; - int m_nOldClipRgn; - //@} - - //@{ - //! @brief Used for advanced anti-flickering - RECT m_rectClientBefore; - BOOL m_bNoRecursion; - //@} - - //! @brief Apply clipping settings for the specified control - void ClipChildWindow(const LAYOUTINFO &layout, CRgn* pRegion) const; - - //! @brief Helper function to calculate new layout - void CalcNewChildPosition(const LAYOUTINFO &layout, - const CRect &rectParent, CRect &rectChild, UINT *lpFlags) const; - -protected: - //! @brief Override to initialize resize properties (clipping, refresh) - virtual void InitResizeProperties(LAYOUTINFO& layout) const; - - //! @brief Override to specify clipping for unsupported windows - virtual BOOL LikesClipping(const LAYOUTINFO &layout) const; - - //! @brief Override to specify refresh for unsupported windows - virtual BOOL NeedsRefresh(const LAYOUTINFO &layout, - const CRect &rectOld, const CRect &rectNew) const; - - //! @brief Clip controls in the layout out of the specified device context - BOOL ClipChildren(const CDC* pDC, BOOL bUndo); - - //! @brief Get the layout clipping region - void GetClippingRegion(CRgn* pRegion) const; - - //! @brief Override for scrollable or expanding parent windows - virtual void GetTotalClientRect(LPRECT lpRect) const; - - //@{ - //! @brief Add anchor points for the specified control to the layout - void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight); - - void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft) - { - AddAnchor(hWnd, anchorTopLeft, anchorTopLeft); - } - - void AddAnchor(UINT nID, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) - { - AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), - anchorTopLeft, anchorBottomRight); - } - - void AddAnchor(UINT nID, ANCHOR anchorTopLeft) - { - AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), - anchorTopLeft, anchorTopLeft); - } - //@} - - //@{ - //! @brief Add anchor points for all the remaining controls to the layout - void AddAllOtherAnchors(ANCHOR anchorTopLeft, ANCHOR anchorBottomRight); - - void AddAllOtherAnchors(ANCHOR anchor) - { - AddAllOtherAnchors(anchor, anchor); - } - - void AddAllOtherAnchors() - { - AddAllOtherAnchors(TOP_LEFT); - } - //@} - - //! @brief Add a callback slot to the layout for dynamic controls or anchor points - LRESULT AddAnchorCallback(); - - //@{ - //! @brief Get position and size of a control in the layout from the parent's client area - BOOL GetAnchorPosition(HWND hWnd, const CRect &rectParent, - CRect &rectChild, UINT* lpFlags = NULL) const - { - POSITION pos; - if (!m_mapLayout.Lookup(hWnd, pos)) - return FALSE; - - CalcNewChildPosition(m_listLayout.GetAt(pos), rectParent, rectChild, lpFlags); - return TRUE; - } - - BOOL GetAnchorPosition(UINT nID, const CRect &rectParent, - CRect &rectChild, UINT* lpFlags = NULL) const - { - return GetAnchorPosition(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), - rectParent, rectChild, lpFlags); - } - //@} - - //@{ - //! @brief Get margins surrounding a control in the layout with the given size - BOOL GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const; - - BOOL GetAnchorMargins(UINT nID, const CSize &sizeChild, CRect &rectMargins) const - { - return GetAnchorMargins(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), - sizeChild, rectMargins); - } - //@} - - //@{ - //! @brief Remove a control from the layout - BOOL RemoveAnchor(HWND hWnd) - { - POSITION pos; - if (!m_mapLayout.Lookup(hWnd, pos)) - return FALSE; - - m_listLayout.RemoveAt(pos); - return m_mapLayout.RemoveKey(hWnd); - } - - BOOL RemoveAnchor(UINT nID) - { - return RemoveAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID)); - } - //@} - - //! @brief Reset the layout content - void RemoveAllAnchors() - { - m_mapLayout.RemoveAll(); - m_listLayout.RemoveAll(); - m_listLayoutCB.RemoveAll(); - } - - //! @brief Reposition and size all the controls in the layout - void ArrangeLayout() const; - - //! @brief Override to provide dynamic control's layout info - virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const; - - //! @brief Override to provide the parent window - virtual CWnd* GetResizableWnd() const = 0; - - //! @brief Enhance anti-flickering - void HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT& lResult); - - //! @brief Enable resizable style for top level parent windows - void MakeResizable(LPCREATESTRUCT lpCreateStruct) const; - -public: - CResizableLayout() - : m_rectClientBefore() - { - m_bNoRecursion = FALSE; - m_hOldClipRgn = ::CreateRectRgn(0,0,0,0); - m_nOldClipRgn = 0; - } - - virtual ~CResizableLayout() - { - ::DeleteObject(m_hOldClipRgn); - // just for safety - RemoveAllAnchors(); - } -}; - -// @} -#endif // !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_) +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Interface for the CResizableLayout class. + */ + +#if !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_) +#define AFX_RESIZABLELAYOUT_H__INCLUDED_ + +//#include +#include "ResizableMsgSupport.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/*! @addtogroup CoreComponents + * @{ + */ + +//! @brief Special type for layout alignment +/*! + * Implements anchor points as a percentage of the parent window client area. + * Control corners are always kept at a fixed distance from their anchor points, + * thus allowing a control to resize proportionally as the parent window is resized. + */ +typedef struct tagANCHOR +{ + int cx; //!< horizontal component, in percent + int cy; //!< vertical component, in percent + + tagANCHOR() : cx(0), cy(0) {} + + tagANCHOR(int x, int y) + { + cx = x; + cy = y; + } + +} ANCHOR, *PANCHOR, *LPANCHOR; + +/*! @defgroup ConstAnchors Alignment Constants + * Declare common layout alignment constants for anchor points. + * @{ + */ + //! Anchor to the top-left corner + extern const ANCHOR TOP_LEFT; + //! Anchor to the top edge and center horizontally + extern const ANCHOR TOP_CENTER; + //! Anchor to the top-right corner + extern const ANCHOR TOP_RIGHT; + //! Anchor to the left edge and center vertically + extern const ANCHOR MIDDLE_LEFT; + //! Anchor to the center + extern const ANCHOR MIDDLE_CENTER; + //! Anchor to the right edge and center vertically + extern const ANCHOR MIDDLE_RIGHT; + //! Anchor to the bottom-left corner + extern const ANCHOR BOTTOM_LEFT; + //! Anchor to the bottom edge and center horizontally + extern const ANCHOR BOTTOM_CENTER; + //! Anchor to the bottom-right corner + extern const ANCHOR BOTTOM_RIGHT; +// @} + +//! @brief Holds a control layout settings +/*! + * Layout settings specify how a control must be moved and resized with respect to + * the parent window and how it reacts to dynamic changes to its size when painting + * its client area, with special care for flickering. + */ +typedef struct tagLAYOUTINFO +{ + //! Handle of the window the layout of which is being defined + HWND hWnd; + //! Identification number assigned to the callback slot + LRESULT nCallbackID; + + //! Window class name to identify standard controls + TCHAR sWndClass[MAX_PATH]; + + //! Anchor point for the top-left corner + ANCHOR anchorTopLeft; + //! Fixed distance for the top-left corner + SIZE marginTopLeft; + + //! Anchor point for the bottom-right corner + ANCHOR anchorBottomRight; + //! Fixed distance for the bottom-right corner + SIZE marginBottomRight; + + //! Flag that enables support for custom windows + BOOL bMsgSupport; + //! Redraw settings for anti-flickering and proper painting + RESIZEPROPERTIES properties; + + tagLAYOUTINFO() : hWnd(NULL), nCallbackID(0) + , marginTopLeft(), marginBottomRight(), bMsgSupport(FALSE) + { + sWndClass[0] = 0; + } + + tagLAYOUTINFO(HWND hwnd, ANCHOR tl_type, SIZE tl_margin, + ANCHOR br_type, SIZE br_margin) + : + hWnd(hwnd), nCallbackID(0), + anchorTopLeft(tl_type), marginTopLeft(tl_margin), + anchorBottomRight(br_type), marginBottomRight(br_margin), bMsgSupport(FALSE) + { + sWndClass[0] = 0; + } + +} LAYOUTINFO, *PLAYOUTINFO, *LPLAYOUTINFO; + +//! @brief Layout manager implementation +/*! + * Derive from this class to implement resizable windows, adding the ability + * to dinamically resize and reposition child controls. + * Special care is taken to ensure a smooth animation during the resize + * operations performed by the users, without annoying flickering effects. + */ +class CResizableLayout +{ +private: + //@{ + //! @brief Collection of layout settings for each control + CMap m_mapLayout; + CList m_listLayout; + CList m_listLayoutCB; + //@} + + //@{ + //! @brief Used for clipping implementation + HRGN m_hOldClipRgn; + int m_nOldClipRgn; + //@} + + //@{ + //! @brief Used for advanced anti-flickering + RECT m_rectClientBefore; + BOOL m_bNoRecursion; + //@} + + //! @brief Apply clipping settings for the specified control + void ClipChildWindow(const LAYOUTINFO &layout, CRgn* pRegion) const; + + //! @brief Helper function to calculate new layout + void CalcNewChildPosition(const LAYOUTINFO &layout, + const CRect &rectParent, CRect &rectChild, UINT *lpFlags) const; + +protected: + //! @brief Override to initialize resize properties (clipping, refresh) + virtual void InitResizeProperties(LAYOUTINFO& layout) const; + + //! @brief Override to specify clipping for unsupported windows + virtual BOOL LikesClipping(const LAYOUTINFO &layout) const; + + //! @brief Override to specify refresh for unsupported windows + virtual BOOL NeedsRefresh(const LAYOUTINFO &layout, + const CRect &rectOld, const CRect &rectNew) const; + + //! @brief Clip controls in the layout out of the specified device context + BOOL ClipChildren(const CDC* pDC, BOOL bUndo); + + //! @brief Get the layout clipping region + void GetClippingRegion(CRgn* pRegion) const; + + //! @brief Override for scrollable or expanding parent windows + virtual void GetTotalClientRect(LPRECT lpRect) const; + + //@{ + //! @brief Add anchor points for the specified control to the layout + void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight); + + void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft) + { + AddAnchor(hWnd, anchorTopLeft, anchorTopLeft); + } + + void AddAnchor(UINT nID, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) + { + AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), + anchorTopLeft, anchorBottomRight); + } + + void AddAnchor(UINT nID, ANCHOR anchorTopLeft) + { + AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), + anchorTopLeft, anchorTopLeft); + } + //@} + + //@{ + //! @brief Add anchor points for all the remaining controls to the layout + void AddAllOtherAnchors(ANCHOR anchorTopLeft, ANCHOR anchorBottomRight); + + void AddAllOtherAnchors(ANCHOR anchor) + { + AddAllOtherAnchors(anchor, anchor); + } + + void AddAllOtherAnchors() + { + AddAllOtherAnchors(TOP_LEFT); + } + //@} + + //! @brief Add a callback slot to the layout for dynamic controls or anchor points + LRESULT AddAnchorCallback(); + + //@{ + //! @brief Get position and size of a control in the layout from the parent's client area + BOOL GetAnchorPosition(HWND hWnd, const CRect &rectParent, + CRect &rectChild, UINT* lpFlags = NULL) const + { + POSITION pos; + if (!m_mapLayout.Lookup(hWnd, pos)) + return FALSE; + + CalcNewChildPosition(m_listLayout.GetAt(pos), rectParent, rectChild, lpFlags); + return TRUE; + } + + BOOL GetAnchorPosition(UINT nID, const CRect &rectParent, + CRect &rectChild, UINT* lpFlags = NULL) const + { + return GetAnchorPosition(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), + rectParent, rectChild, lpFlags); + } + //@} + + //@{ + //! @brief Get margins surrounding a control in the layout with the given size + BOOL GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const; + + BOOL GetAnchorMargins(UINT nID, const CSize &sizeChild, CRect &rectMargins) const + { + return GetAnchorMargins(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), + sizeChild, rectMargins); + } + //@} + + //@{ + //! @brief Remove a control from the layout + BOOL RemoveAnchor(HWND hWnd) + { + POSITION pos; + if (!m_mapLayout.Lookup(hWnd, pos)) + return FALSE; + + m_listLayout.RemoveAt(pos); + return m_mapLayout.RemoveKey(hWnd); + } + + BOOL RemoveAnchor(UINT nID) + { + return RemoveAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID)); + } + //@} + + //! @brief Reset the layout content + void RemoveAllAnchors() + { + m_mapLayout.RemoveAll(); + m_listLayout.RemoveAll(); + m_listLayoutCB.RemoveAll(); + } + + //! @brief Reposition and size all the controls in the layout + void ArrangeLayout() const; + + //! @brief Override to provide dynamic control's layout info + virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const; + + //! @brief Override to provide the parent window + virtual CWnd* GetResizableWnd() const = 0; + + //! @brief Enhance anti-flickering + void HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT& lResult); + + //! @brief Enable resizable style for top level parent windows + void MakeResizable(LPCREATESTRUCT lpCreateStruct) const; + +public: + CResizableLayout() + : m_rectClientBefore() + { + m_bNoRecursion = FALSE; + m_hOldClipRgn = ::CreateRectRgn(0,0,0,0); + m_nOldClipRgn = 0; + } + + virtual ~CResizableLayout() + { + ::DeleteObject(m_hOldClipRgn); + // just for safety + RemoveAllAnchors(); + } +}; + +// @} +#endif // !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableLib.vcxproj b/src/thirdparty/ResizableLib/ResizableLib.vcxproj index f0b2c10f707..3f5991ea4ee 100644 --- a/src/thirdparty/ResizableLib/ResizableLib.vcxproj +++ b/src/thirdparty/ResizableLib/ResizableLib.vcxproj @@ -1,81 +1,81 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {4CC7AE86-3E0A-430A-BFF4-BF00204CAFB0} - ResizableLib - MFCProj - ResizableLib - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4CC7AE86-3E0A-430A-BFF4-BF00204CAFB0} + ResizableLib + MFCProj + ResizableLib + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/ResizableLib/ResizableLib.vcxproj.filters b/src/thirdparty/ResizableLib/ResizableLib.vcxproj.filters index 4591a4c2c53..09004146205 100644 --- a/src/thirdparty/ResizableLib/ResizableLib.vcxproj.filters +++ b/src/thirdparty/ResizableLib/ResizableLib.vcxproj.filters @@ -1,89 +1,89 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/ResizableLib/ResizableMinMax.cpp b/src/thirdparty/ResizableLib/ResizableMinMax.cpp index 59e3ea37786..a9bf852cbbf 100644 --- a/src/thirdparty/ResizableLib/ResizableMinMax.cpp +++ b/src/thirdparty/ResizableLib/ResizableMinMax.cpp @@ -1,211 +1,211 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Implementation of the CResizableMinMax class. - */ - -#include "stdafx.h" -#include "ResizableMinMax.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[]=__FILE__; -#define new DEBUG_NEW -#endif - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResizableMinMax::CResizableMinMax() - : m_ptMinTrackSize(), m_ptMaxTrackSize(), m_ptMaxPos(), m_ptMaxSize() -{ - m_bUseMinTrack = FALSE; - m_bUseMaxTrack = FALSE; - m_bUseMaxRect = FALSE; -} - -CResizableMinMax::~CResizableMinMax() -{ - -} - -void CResizableMinMax::ApplyMinMaxTrackSize(LPMINMAXINFO lpMMI) -{ - lpMMI->ptMaxSize.x = __max(lpMMI->ptMaxSize.x, lpMMI->ptMinTrackSize.x); - lpMMI->ptMaxSize.y = __max(lpMMI->ptMaxSize.y, lpMMI->ptMinTrackSize.y); - - lpMMI->ptMaxSize.x = __min(lpMMI->ptMaxSize.x, lpMMI->ptMaxTrackSize.x); - lpMMI->ptMaxSize.y = __min(lpMMI->ptMaxSize.y, lpMMI->ptMaxTrackSize.y); -} - -void CResizableMinMax::MinMaxInfo(LPMINMAXINFO lpMMI) const -{ - if (m_bUseMinTrack) - lpMMI->ptMinTrackSize = m_ptMinTrackSize; - - if (m_bUseMaxTrack) - lpMMI->ptMaxTrackSize = m_ptMaxTrackSize; - - if (m_bUseMaxRect) - { - lpMMI->ptMaxPosition = m_ptMaxPos; - lpMMI->ptMaxSize = m_ptMaxSize; - } - - ApplyMinMaxTrackSize(lpMMI); -} - -void CResizableMinMax::ChainMinMaxInfo(LPMINMAXINFO lpMMI, CWnd* pParentFrame, const CWnd* pWnd) -{ - // get the extra size from child to parent - CRect rectClient, rectWnd; - if ((pParentFrame->GetStyle() & WS_CHILD) && pParentFrame->IsZoomed()) - pParentFrame->GetClientRect(rectWnd); - else - pParentFrame->GetWindowRect(rectWnd); - pParentFrame->RepositionBars(0, 0xFFFF, - AFX_IDW_PANE_FIRST, CWnd::reposQuery, rectClient); - const CSize sizeExtra = rectWnd.Size() - rectClient.Size(); - - ChainMinMaxInfo(lpMMI, pWnd->GetSafeHwnd(), sizeExtra); -} - -void CResizableMinMax::ChainMinMaxInfo(LPMINMAXINFO lpMMI, HWND hWndChild, const CSize& sizeExtra) -{ - // ask the child window for track size - MINMAXINFO mmiChild = *lpMMI; - ::SendMessage(hWndChild, WM_GETMINMAXINFO, 0, (LPARAM)&mmiChild); - BOOL bRetMax = (lpMMI->ptMaxTrackSize.x != mmiChild.ptMaxTrackSize.x - || lpMMI->ptMaxTrackSize.y != mmiChild.ptMaxTrackSize.y); - BOOL bRetMin = (lpMMI->ptMinTrackSize.x != mmiChild.ptMinTrackSize.x - || lpMMI->ptMinTrackSize.y != mmiChild.ptMinTrackSize.y); - - // add static extra size - mmiChild.ptMaxTrackSize = sizeExtra + mmiChild.ptMaxTrackSize; - mmiChild.ptMinTrackSize = sizeExtra + mmiChild.ptMinTrackSize; - - // min size is the largest - if (bRetMin) - { - lpMMI->ptMinTrackSize.x = __max(lpMMI->ptMinTrackSize.x, - mmiChild.ptMinTrackSize.x); - lpMMI->ptMinTrackSize.y = __max(lpMMI->ptMinTrackSize.y, - mmiChild.ptMinTrackSize.y); - } - // max size is the shortest - if (bRetMax) - { - lpMMI->ptMaxTrackSize.x = __min(lpMMI->ptMaxTrackSize.x, - mmiChild.ptMaxTrackSize.x); - lpMMI->ptMaxTrackSize.y = __min(lpMMI->ptMaxTrackSize.y, - mmiChild.ptMaxTrackSize.y); - } - - ApplyMinMaxTrackSize(lpMMI); -} - -BOOL CResizableMinMax::CalcSizeExtra(HWND /*hWndChild*/, const CSize& /*sizeChild*/, CSize& /*sizeExtra*/) -{ - // should be overridden if you use ChainMinMaxInfoCB - ASSERT(FALSE); - return FALSE; -} - -void CResizableMinMax::ChainMinMaxInfoCB(LPMINMAXINFO lpMMI, HWND hWndChild) -{ - // ask the child window for track size - MINMAXINFO mmiChild = *lpMMI; - ::SendMessage(hWndChild, WM_GETMINMAXINFO, 0, (LPARAM)&mmiChild); - BOOL bRetMax = (lpMMI->ptMaxTrackSize.x != mmiChild.ptMaxTrackSize.x - || lpMMI->ptMaxTrackSize.y != mmiChild.ptMaxTrackSize.y); - BOOL bRetMin = (lpMMI->ptMinTrackSize.x != mmiChild.ptMinTrackSize.x - || lpMMI->ptMinTrackSize.y != mmiChild.ptMinTrackSize.y); - - // use a callback to determine extra size - CSize sizeExtra(0, 0); - bRetMax = bRetMax && CalcSizeExtra(hWndChild, mmiChild.ptMaxTrackSize, sizeExtra); - mmiChild.ptMaxTrackSize = sizeExtra + mmiChild.ptMaxTrackSize; - bRetMin = bRetMin && CalcSizeExtra(hWndChild, mmiChild.ptMinTrackSize, sizeExtra); - mmiChild.ptMinTrackSize = sizeExtra + mmiChild.ptMinTrackSize; - - // min size is the largest - if (bRetMin) - { - lpMMI->ptMinTrackSize.x = __max(lpMMI->ptMinTrackSize.x, - mmiChild.ptMinTrackSize.x); - lpMMI->ptMinTrackSize.y = __max(lpMMI->ptMinTrackSize.y, - mmiChild.ptMinTrackSize.y); - } - // max size is the shortest - if (bRetMax) - { - lpMMI->ptMaxTrackSize.x = __min(lpMMI->ptMaxTrackSize.x, - mmiChild.ptMaxTrackSize.x); - lpMMI->ptMaxTrackSize.y = __min(lpMMI->ptMaxTrackSize.y, - mmiChild.ptMaxTrackSize.y); - } - - ApplyMinMaxTrackSize(lpMMI); -} - -void CResizableMinMax::ResetAllRects() -{ - m_bUseMinTrack = FALSE; - m_bUseMaxTrack = FALSE; - m_bUseMaxRect = FALSE; -} - -void CResizableMinMax::SetMaximizedRect(const CRect& rc) -{ - m_bUseMaxRect = TRUE; - - m_ptMaxPos = rc.TopLeft(); - m_ptMaxSize.x = rc.Width(); - m_ptMaxSize.y = rc.Height(); -} - -void CResizableMinMax::ResetMaximizedRect() -{ - m_bUseMaxRect = FALSE; -} - -void CResizableMinMax::SetMinTrackSize(const CSize& size) -{ - m_bUseMinTrack = TRUE; - - m_ptMinTrackSize.x = size.cx; - m_ptMinTrackSize.y = size.cy; -} - -void CResizableMinMax::ResetMinTrackSize() -{ - m_bUseMinTrack = FALSE; -} - -void CResizableMinMax::SetMaxTrackSize(const CSize& size) -{ - m_bUseMaxTrack = TRUE; - - m_ptMaxTrackSize.x = size.cx; - m_ptMaxTrackSize.y = size.cy; -} - -void CResizableMinMax::ResetMaxTrackSize() -{ - m_bUseMaxTrack = FALSE; -} +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Implementation of the CResizableMinMax class. + */ + +#include "stdafx.h" +#include "ResizableMinMax.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResizableMinMax::CResizableMinMax() + : m_ptMinTrackSize(), m_ptMaxTrackSize(), m_ptMaxPos(), m_ptMaxSize() +{ + m_bUseMinTrack = FALSE; + m_bUseMaxTrack = FALSE; + m_bUseMaxRect = FALSE; +} + +CResizableMinMax::~CResizableMinMax() +{ + +} + +void CResizableMinMax::ApplyMinMaxTrackSize(LPMINMAXINFO lpMMI) +{ + lpMMI->ptMaxSize.x = __max(lpMMI->ptMaxSize.x, lpMMI->ptMinTrackSize.x); + lpMMI->ptMaxSize.y = __max(lpMMI->ptMaxSize.y, lpMMI->ptMinTrackSize.y); + + lpMMI->ptMaxSize.x = __min(lpMMI->ptMaxSize.x, lpMMI->ptMaxTrackSize.x); + lpMMI->ptMaxSize.y = __min(lpMMI->ptMaxSize.y, lpMMI->ptMaxTrackSize.y); +} + +void CResizableMinMax::MinMaxInfo(LPMINMAXINFO lpMMI) const +{ + if (m_bUseMinTrack) + lpMMI->ptMinTrackSize = m_ptMinTrackSize; + + if (m_bUseMaxTrack) + lpMMI->ptMaxTrackSize = m_ptMaxTrackSize; + + if (m_bUseMaxRect) + { + lpMMI->ptMaxPosition = m_ptMaxPos; + lpMMI->ptMaxSize = m_ptMaxSize; + } + + ApplyMinMaxTrackSize(lpMMI); +} + +void CResizableMinMax::ChainMinMaxInfo(LPMINMAXINFO lpMMI, CWnd* pParentFrame, const CWnd* pWnd) +{ + // get the extra size from child to parent + CRect rectClient, rectWnd; + if ((pParentFrame->GetStyle() & WS_CHILD) && pParentFrame->IsZoomed()) + pParentFrame->GetClientRect(rectWnd); + else + pParentFrame->GetWindowRect(rectWnd); + pParentFrame->RepositionBars(0, 0xFFFF, + AFX_IDW_PANE_FIRST, CWnd::reposQuery, rectClient); + const CSize sizeExtra = rectWnd.Size() - rectClient.Size(); + + ChainMinMaxInfo(lpMMI, pWnd->GetSafeHwnd(), sizeExtra); +} + +void CResizableMinMax::ChainMinMaxInfo(LPMINMAXINFO lpMMI, HWND hWndChild, const CSize& sizeExtra) +{ + // ask the child window for track size + MINMAXINFO mmiChild = *lpMMI; + ::SendMessage(hWndChild, WM_GETMINMAXINFO, 0, (LPARAM)&mmiChild); + BOOL bRetMax = (lpMMI->ptMaxTrackSize.x != mmiChild.ptMaxTrackSize.x + || lpMMI->ptMaxTrackSize.y != mmiChild.ptMaxTrackSize.y); + BOOL bRetMin = (lpMMI->ptMinTrackSize.x != mmiChild.ptMinTrackSize.x + || lpMMI->ptMinTrackSize.y != mmiChild.ptMinTrackSize.y); + + // add static extra size + mmiChild.ptMaxTrackSize = sizeExtra + mmiChild.ptMaxTrackSize; + mmiChild.ptMinTrackSize = sizeExtra + mmiChild.ptMinTrackSize; + + // min size is the largest + if (bRetMin) + { + lpMMI->ptMinTrackSize.x = __max(lpMMI->ptMinTrackSize.x, + mmiChild.ptMinTrackSize.x); + lpMMI->ptMinTrackSize.y = __max(lpMMI->ptMinTrackSize.y, + mmiChild.ptMinTrackSize.y); + } + // max size is the shortest + if (bRetMax) + { + lpMMI->ptMaxTrackSize.x = __min(lpMMI->ptMaxTrackSize.x, + mmiChild.ptMaxTrackSize.x); + lpMMI->ptMaxTrackSize.y = __min(lpMMI->ptMaxTrackSize.y, + mmiChild.ptMaxTrackSize.y); + } + + ApplyMinMaxTrackSize(lpMMI); +} + +BOOL CResizableMinMax::CalcSizeExtra(HWND /*hWndChild*/, const CSize& /*sizeChild*/, CSize& /*sizeExtra*/) +{ + // should be overridden if you use ChainMinMaxInfoCB + ASSERT(FALSE); + return FALSE; +} + +void CResizableMinMax::ChainMinMaxInfoCB(LPMINMAXINFO lpMMI, HWND hWndChild) +{ + // ask the child window for track size + MINMAXINFO mmiChild = *lpMMI; + ::SendMessage(hWndChild, WM_GETMINMAXINFO, 0, (LPARAM)&mmiChild); + BOOL bRetMax = (lpMMI->ptMaxTrackSize.x != mmiChild.ptMaxTrackSize.x + || lpMMI->ptMaxTrackSize.y != mmiChild.ptMaxTrackSize.y); + BOOL bRetMin = (lpMMI->ptMinTrackSize.x != mmiChild.ptMinTrackSize.x + || lpMMI->ptMinTrackSize.y != mmiChild.ptMinTrackSize.y); + + // use a callback to determine extra size + CSize sizeExtra(0, 0); + bRetMax = bRetMax && CalcSizeExtra(hWndChild, mmiChild.ptMaxTrackSize, sizeExtra); + mmiChild.ptMaxTrackSize = sizeExtra + mmiChild.ptMaxTrackSize; + bRetMin = bRetMin && CalcSizeExtra(hWndChild, mmiChild.ptMinTrackSize, sizeExtra); + mmiChild.ptMinTrackSize = sizeExtra + mmiChild.ptMinTrackSize; + + // min size is the largest + if (bRetMin) + { + lpMMI->ptMinTrackSize.x = __max(lpMMI->ptMinTrackSize.x, + mmiChild.ptMinTrackSize.x); + lpMMI->ptMinTrackSize.y = __max(lpMMI->ptMinTrackSize.y, + mmiChild.ptMinTrackSize.y); + } + // max size is the shortest + if (bRetMax) + { + lpMMI->ptMaxTrackSize.x = __min(lpMMI->ptMaxTrackSize.x, + mmiChild.ptMaxTrackSize.x); + lpMMI->ptMaxTrackSize.y = __min(lpMMI->ptMaxTrackSize.y, + mmiChild.ptMaxTrackSize.y); + } + + ApplyMinMaxTrackSize(lpMMI); +} + +void CResizableMinMax::ResetAllRects() +{ + m_bUseMinTrack = FALSE; + m_bUseMaxTrack = FALSE; + m_bUseMaxRect = FALSE; +} + +void CResizableMinMax::SetMaximizedRect(const CRect& rc) +{ + m_bUseMaxRect = TRUE; + + m_ptMaxPos = rc.TopLeft(); + m_ptMaxSize.x = rc.Width(); + m_ptMaxSize.y = rc.Height(); +} + +void CResizableMinMax::ResetMaximizedRect() +{ + m_bUseMaxRect = FALSE; +} + +void CResizableMinMax::SetMinTrackSize(const CSize& size) +{ + m_bUseMinTrack = TRUE; + + m_ptMinTrackSize.x = size.cx; + m_ptMinTrackSize.y = size.cy; +} + +void CResizableMinMax::ResetMinTrackSize() +{ + m_bUseMinTrack = FALSE; +} + +void CResizableMinMax::SetMaxTrackSize(const CSize& size) +{ + m_bUseMaxTrack = TRUE; + + m_ptMaxTrackSize.x = size.cx; + m_ptMaxTrackSize.y = size.cy; +} + +void CResizableMinMax::ResetMaxTrackSize() +{ + m_bUseMaxTrack = FALSE; +} diff --git a/src/thirdparty/ResizableLib/ResizableMinMax.h b/src/thirdparty/ResizableLib/ResizableMinMax.h index 74f7a599178..05a4aa19a74 100644 --- a/src/thirdparty/ResizableLib/ResizableMinMax.h +++ b/src/thirdparty/ResizableLib/ResizableMinMax.h @@ -1,82 +1,82 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Interface for the CResizableMinMax class. - */ - -#if !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_) -#define AFX_RESIZABLEMINMAX_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -/*! @addtogroup CoreComponents - * @{ - */ - -//! @brief brief_description -/*! - * long_description - */ -class CResizableMinMax -{ -// Attributes -private: - // flags - BOOL m_bUseMaxTrack; - BOOL m_bUseMinTrack; - BOOL m_bUseMaxRect; - - POINT m_ptMinTrackSize; // min tracking size - POINT m_ptMaxTrackSize; // max tracking size - POINT m_ptMaxPos; // maximized position - POINT m_ptMaxSize; // maximized size - -public: - CResizableMinMax(); - virtual ~CResizableMinMax(); - -protected: - static void ApplyMinMaxTrackSize(LPMINMAXINFO lpMMI); - - void MinMaxInfo(LPMINMAXINFO lpMMI) const; - static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, CWnd* pParentFrame, const CWnd* pWnd); - - static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, HWND hWndChild, const CSize& sizeExtra); - - static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, const CWnd* pParentWnd, UINT nID, const CSize& sizeExtra) - { - ChainMinMaxInfo(lpMMI, - ::GetDlgItem(pParentWnd->GetSafeHwnd(), nID), sizeExtra); - } - - void ChainMinMaxInfoCB(LPMINMAXINFO lpMMI, HWND hWndChild); - virtual BOOL CalcSizeExtra(HWND hWndChild, const CSize& sizeChild, CSize& sizeExtra); - - void ResetAllRects(); - - void SetMaximizedRect(const CRect& rc); // set window rect when maximized - void ResetMaximizedRect(); // reset to default maximized rect - void SetMinTrackSize(const CSize& size); // set minimum tracking size - void ResetMinTrackSize(); // reset to default minimum tracking size - void SetMaxTrackSize(const CSize& size); // set maximum tracking size - void ResetMaxTrackSize(); // reset to default maximum tracking size -}; - -// @} -#endif // !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_) +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Interface for the CResizableMinMax class. + */ + +#if !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_) +#define AFX_RESIZABLEMINMAX_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/*! @addtogroup CoreComponents + * @{ + */ + +//! @brief brief_description +/*! + * long_description + */ +class CResizableMinMax +{ +// Attributes +private: + // flags + BOOL m_bUseMaxTrack; + BOOL m_bUseMinTrack; + BOOL m_bUseMaxRect; + + POINT m_ptMinTrackSize; // min tracking size + POINT m_ptMaxTrackSize; // max tracking size + POINT m_ptMaxPos; // maximized position + POINT m_ptMaxSize; // maximized size + +public: + CResizableMinMax(); + virtual ~CResizableMinMax(); + +protected: + static void ApplyMinMaxTrackSize(LPMINMAXINFO lpMMI); + + void MinMaxInfo(LPMINMAXINFO lpMMI) const; + static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, CWnd* pParentFrame, const CWnd* pWnd); + + static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, HWND hWndChild, const CSize& sizeExtra); + + static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, const CWnd* pParentWnd, UINT nID, const CSize& sizeExtra) + { + ChainMinMaxInfo(lpMMI, + ::GetDlgItem(pParentWnd->GetSafeHwnd(), nID), sizeExtra); + } + + void ChainMinMaxInfoCB(LPMINMAXINFO lpMMI, HWND hWndChild); + virtual BOOL CalcSizeExtra(HWND hWndChild, const CSize& sizeChild, CSize& sizeExtra); + + void ResetAllRects(); + + void SetMaximizedRect(const CRect& rc); // set window rect when maximized + void ResetMaximizedRect(); // reset to default maximized rect + void SetMinTrackSize(const CSize& size); // set minimum tracking size + void ResetMinTrackSize(); // reset to default minimum tracking size + void SetMaxTrackSize(const CSize& size); // set maximum tracking size + void ResetMaxTrackSize(); // reset to default maximum tracking size +}; + +// @} +#endif // !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableMsgSupport.h b/src/thirdparty/ResizableLib/ResizableMsgSupport.h index 009f35b4f58..28c99905639 100644 --- a/src/thirdparty/ResizableLib/ResizableMsgSupport.h +++ b/src/thirdparty/ResizableLib/ResizableMsgSupport.h @@ -1,104 +1,104 @@ -// ResizableMsgSupport.h: some declarations to support custom resizable wnds -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_) -#define AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -typedef struct tagRESIZEPROPERTIES -{ - // whether to ask for resizing properties every time - BOOL bAskClipping; - BOOL bAskRefresh; - // otherwise, use the cached properties - BOOL bCachedLikesClipping; - BOOL bCachedNeedsRefresh; - - // initialize with valid data - tagRESIZEPROPERTIES() : bAskClipping(TRUE), bAskRefresh(TRUE), bCachedLikesClipping(FALSE), bCachedNeedsRefresh(TRUE) {} - -} RESIZEPROPERTIES, *PRESIZEPROPERTIES, *LPRESIZEPROPERTIES; - - -typedef struct tagCLIPPINGPROPERTY -{ - BOOL bLikesClipping; - - // initialize with valid data - tagCLIPPINGPROPERTY() : bLikesClipping(FALSE) {} - -} CLIPPINGPROPERTY, *PCLIPPINGPROPERTY, *LPCLIPPINGPROPERTY; - - -typedef struct tagREFRESHPROPERTY -{ - BOOL bNeedsRefresh; - RECT rcOld; - RECT rcNew; - - // initialize with valid data - tagREFRESHPROPERTY() : bNeedsRefresh(TRUE), rcOld(), rcNew() {} - -} REFRESHPROPERTY, *PREFRESHPROPERTY, *LPREFRESHPROPERTY; - - -// registered message to communicate with the library -extern const UINT WMU_RESIZESUPPORT; - -// if the message is implemented the returned value must be non-zero -// the default window procedure returns zero for unhandled messages - -// wParam is one of the following RSZSUP_* values, lParam as specified -enum ResizeSupport -{ - RSZSUP_QUERYPROPERTIES = 101, // lParam = LPRESIZEPROPERTIES - RSZSUP_LIKESCLIPPING = 102, // lParam = LPCLIPPINGPROPERTY - RSZSUP_NEEDSREFRESH = 103, // lParam = LPREFRESHPROPERTY - RSZSUP_SHEETPAGEEXHACK = 104, // lParam = HWND (source prop.page) -}; - -///////////////////////////////////////////////////////////////////////////// -// utility functions - -inline BOOL Send_QueryProperties(HWND hWnd, LPRESIZEPROPERTIES pResizeProperties) -{ - return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, - RSZSUP_QUERYPROPERTIES, (LPARAM)pResizeProperties)); -} - -inline BOOL Send_LikesClipping(HWND hWnd, LPCLIPPINGPROPERTY pClippingProperty) -{ - return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, - RSZSUP_LIKESCLIPPING, (LPARAM)pClippingProperty)); -} - -inline BOOL Send_NeedsRefresh(HWND hWnd, LPREFRESHPROPERTY pRefreshProperty) -{ - return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, - RSZSUP_NEEDSREFRESH, (LPARAM)pRefreshProperty)); -} - -inline void Post_SheetPageExHack(HWND hWndSheet, HWND hWndPage) -{ - PostMessage(hWndSheet, WMU_RESIZESUPPORT, - RSZSUP_SHEETPAGEEXHACK, (LPARAM)hWndPage); -} - -#endif // !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_) +// ResizableMsgSupport.h: some declarations to support custom resizable wnds +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_) +#define AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +typedef struct tagRESIZEPROPERTIES +{ + // whether to ask for resizing properties every time + BOOL bAskClipping; + BOOL bAskRefresh; + // otherwise, use the cached properties + BOOL bCachedLikesClipping; + BOOL bCachedNeedsRefresh; + + // initialize with valid data + tagRESIZEPROPERTIES() : bAskClipping(TRUE), bAskRefresh(TRUE), bCachedLikesClipping(FALSE), bCachedNeedsRefresh(TRUE) {} + +} RESIZEPROPERTIES, *PRESIZEPROPERTIES, *LPRESIZEPROPERTIES; + + +typedef struct tagCLIPPINGPROPERTY +{ + BOOL bLikesClipping; + + // initialize with valid data + tagCLIPPINGPROPERTY() : bLikesClipping(FALSE) {} + +} CLIPPINGPROPERTY, *PCLIPPINGPROPERTY, *LPCLIPPINGPROPERTY; + + +typedef struct tagREFRESHPROPERTY +{ + BOOL bNeedsRefresh; + RECT rcOld; + RECT rcNew; + + // initialize with valid data + tagREFRESHPROPERTY() : bNeedsRefresh(TRUE), rcOld(), rcNew() {} + +} REFRESHPROPERTY, *PREFRESHPROPERTY, *LPREFRESHPROPERTY; + + +// registered message to communicate with the library +extern const UINT WMU_RESIZESUPPORT; + +// if the message is implemented the returned value must be non-zero +// the default window procedure returns zero for unhandled messages + +// wParam is one of the following RSZSUP_* values, lParam as specified +enum ResizeSupport +{ + RSZSUP_QUERYPROPERTIES = 101, // lParam = LPRESIZEPROPERTIES + RSZSUP_LIKESCLIPPING = 102, // lParam = LPCLIPPINGPROPERTY + RSZSUP_NEEDSREFRESH = 103, // lParam = LPREFRESHPROPERTY + RSZSUP_SHEETPAGEEXHACK = 104, // lParam = HWND (source prop.page) +}; + +///////////////////////////////////////////////////////////////////////////// +// utility functions + +inline BOOL Send_QueryProperties(HWND hWnd, LPRESIZEPROPERTIES pResizeProperties) +{ + return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, + RSZSUP_QUERYPROPERTIES, (LPARAM)pResizeProperties)); +} + +inline BOOL Send_LikesClipping(HWND hWnd, LPCLIPPINGPROPERTY pClippingProperty) +{ + return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, + RSZSUP_LIKESCLIPPING, (LPARAM)pClippingProperty)); +} + +inline BOOL Send_NeedsRefresh(HWND hWnd, LPREFRESHPROPERTY pRefreshProperty) +{ + return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, + RSZSUP_NEEDSREFRESH, (LPARAM)pRefreshProperty)); +} + +inline void Post_SheetPageExHack(HWND hWndSheet, HWND hWndPage) +{ + PostMessage(hWndSheet, WMU_RESIZESUPPORT, + RSZSUP_SHEETPAGEEXHACK, (LPARAM)hWndPage); +} + +#endif // !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizablePage.cpp b/src/thirdparty/ResizableLib/ResizablePage.cpp index 9fd5932ee19..3fcb4027464 100644 --- a/src/thirdparty/ResizableLib/ResizablePage.cpp +++ b/src/thirdparty/ResizableLib/ResizablePage.cpp @@ -1,119 +1,119 @@ -// ResizablePage.cpp : implementation file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "ResizablePage.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CResizablePage - -IMPLEMENT_DYNCREATE(CResizablePage, CPropertyPage) - -CResizablePage::CResizablePage() -{ -} - -CResizablePage::CResizablePage(UINT nIDTemplate, UINT nIDCaption) - : CPropertyPage(nIDTemplate, nIDCaption) -{ -} - -CResizablePage::CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption) - : CPropertyPage(lpszTemplateName, nIDCaption) -{ -} - -CResizablePage::~CResizablePage() -{ -} - - -BEGIN_MESSAGE_MAP(CResizablePage, CPropertyPage) - //{{AFX_MSG_MAP(CResizablePage) - ON_WM_SIZE() - ON_WM_ERASEBKGND() - ON_WM_GETMINMAXINFO() - ON_WM_DESTROY() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - - -///////////////////////////////////////////////////////////////////////////// -// CResizablePage message handlers - -void CResizablePage::OnSize(UINT nType, int cx, int cy) -{ - CWnd::OnSize(nType, cx, cy); - - ArrangeLayout(); -} - -BOOL CResizablePage::OnEraseBkgnd(CDC* pDC) -{ - ClipChildren(pDC, FALSE); - - BOOL bRet = CPropertyPage::OnEraseBkgnd(pDC); - - ClipChildren(pDC, TRUE); - - return bRet; -} - -void CResizablePage::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) -{ - MinMaxInfo(lpMMI); -} - -BOOL CResizablePage::OnInitDialog() -{ - CPropertyPage::OnInitDialog(); - - // set the initial size as the min track size - CRect rc; - GetWindowRect(&rc); - SetMinTrackSize(rc.Size()); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CResizablePage::OnDestroy() -{ - // remove child windows - RemoveAllAnchors(); - ResetAllRects(); - - CPropertyPage::OnDestroy(); -} - -LRESULT CResizablePage::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message != WM_NCCALCSIZE || wParam == 0) - return CPropertyPage::WindowProc(message, wParam, lParam); - - LRESULT lResult = 0; - HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - lResult = CPropertyPage::WindowProc(message, wParam, lParam); - HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - return lResult; -} +// ResizablePage.cpp : implementation file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ResizablePage.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CResizablePage + +IMPLEMENT_DYNCREATE(CResizablePage, CPropertyPage) + +CResizablePage::CResizablePage() +{ +} + +CResizablePage::CResizablePage(UINT nIDTemplate, UINT nIDCaption) + : CPropertyPage(nIDTemplate, nIDCaption) +{ +} + +CResizablePage::CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption) + : CPropertyPage(lpszTemplateName, nIDCaption) +{ +} + +CResizablePage::~CResizablePage() +{ +} + + +BEGIN_MESSAGE_MAP(CResizablePage, CPropertyPage) + //{{AFX_MSG_MAP(CResizablePage) + ON_WM_SIZE() + ON_WM_ERASEBKGND() + ON_WM_GETMINMAXINFO() + ON_WM_DESTROY() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CResizablePage message handlers + +void CResizablePage::OnSize(UINT nType, int cx, int cy) +{ + CWnd::OnSize(nType, cx, cy); + + ArrangeLayout(); +} + +BOOL CResizablePage::OnEraseBkgnd(CDC* pDC) +{ + ClipChildren(pDC, FALSE); + + BOOL bRet = CPropertyPage::OnEraseBkgnd(pDC); + + ClipChildren(pDC, TRUE); + + return bRet; +} + +void CResizablePage::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + MinMaxInfo(lpMMI); +} + +BOOL CResizablePage::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + + // set the initial size as the min track size + CRect rc; + GetWindowRect(&rc); + SetMinTrackSize(rc.Size()); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CResizablePage::OnDestroy() +{ + // remove child windows + RemoveAllAnchors(); + ResetAllRects(); + + CPropertyPage::OnDestroy(); +} + +LRESULT CResizablePage::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message != WM_NCCALCSIZE || wParam == 0) + return CPropertyPage::WindowProc(message, wParam, lParam); + + LRESULT lResult = 0; + HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + lResult = CPropertyPage::WindowProc(message, wParam, lParam); + HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + return lResult; +} diff --git a/src/thirdparty/ResizableLib/ResizablePage.h b/src/thirdparty/ResizableLib/ResizablePage.h index e2133b2ef75..0a950e0f528 100644 --- a/src/thirdparty/ResizableLib/ResizablePage.h +++ b/src/thirdparty/ResizableLib/ResizablePage.h @@ -1,82 +1,82 @@ -#if !defined(AFX_RESIZABLEPAGE_H__INCLUDED_) -#define AFX_RESIZABLEPAGE_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -// ResizablePage.h : header file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "ResizableLayout.h" -#include "ResizableMinMax.h" - -///////////////////////////////////////////////////////////////////////////// -// CResizablePage window - -class CResizablePage : public CPropertyPage, public CResizableLayout, - public CResizableMinMax -{ - DECLARE_DYNCREATE(CResizablePage) - -// Construction -public: - CResizablePage(); - explicit CResizablePage(UINT nIDTemplate, UINT nIDCaption = 0); - explicit CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption = 0); - -// Attributes - -// Operations - -// Overrides - virtual BOOL OnInitDialog(); - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CResizablePage) -protected: - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CResizablePage(); - -// callable from derived classes -protected: - - virtual CWnd* GetResizableWnd() const - { - // make the layout know its parent window - return CWnd::FromHandle(m_hWnd); - }; - -// Generated message map functions - //{{AFX_MSG(CResizablePage) - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); - afx_msg void OnDestroy(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_RESIZABLEPAGE_H__INCLUDED_) +#if !defined(AFX_RESIZABLEPAGE_H__INCLUDED_) +#define AFX_RESIZABLEPAGE_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// ResizablePage.h : header file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "ResizableLayout.h" +#include "ResizableMinMax.h" + +///////////////////////////////////////////////////////////////////////////// +// CResizablePage window + +class CResizablePage : public CPropertyPage, public CResizableLayout, + public CResizableMinMax +{ + DECLARE_DYNCREATE(CResizablePage) + +// Construction +public: + CResizablePage(); + explicit CResizablePage(UINT nIDTemplate, UINT nIDCaption = 0); + explicit CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption = 0); + +// Attributes + +// Operations + +// Overrides + virtual BOOL OnInitDialog(); + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CResizablePage) +protected: + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CResizablePage(); + +// callable from derived classes +protected: + + virtual CWnd* GetResizableWnd() const + { + // make the layout know its parent window + return CWnd::FromHandle(m_hWnd); + }; + +// Generated message map functions + //{{AFX_MSG(CResizablePage) + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnDestroy(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_RESIZABLEPAGE_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableSheet.cpp b/src/thirdparty/ResizableLib/ResizableSheet.cpp index d897101a60a..686cb96cca0 100644 --- a/src/thirdparty/ResizableLib/ResizableSheet.cpp +++ b/src/thirdparty/ResizableLib/ResizableSheet.cpp @@ -1,476 +1,476 @@ -// ResizableSheet.cpp : implementation file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "ResizableSheet.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CResizableSheet - -IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet) - -inline void CResizableSheet::PrivateConstruct() -{ - m_bEnableSaveRestore = FALSE; - m_bSavePage = FALSE; - m_dwGripTempState = 1; - m_bLayoutDone = FALSE; - m_bRectOnly = FALSE; - m_nCallbackID = 0; -} - -inline BOOL CResizableSheet::IsWizard() const -{ - return (m_psh.dwFlags & PSH_WIZARD); -} - -CResizableSheet::CResizableSheet() -{ - PrivateConstruct(); -} - -CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage) - : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) -{ - PrivateConstruct(); -} - -CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage) - : CPropertySheet(pszCaption, pParentWnd, iSelectPage) -{ - PrivateConstruct(); -} - -CResizableSheet::~CResizableSheet() -{ -} - -BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet) - //{{AFX_MSG_MAP(CResizableSheet) - ON_WM_GETMINMAXINFO() - ON_WM_SIZE() - ON_WM_DESTROY() - ON_WM_ERASEBKGND() - ON_WM_NCCREATE() - //}}AFX_MSG_MAP - ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CResizableSheet message handlers - -BOOL CResizableSheet::OnNcCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (!CPropertySheet::OnNcCreate(lpCreateStruct)) - return FALSE; - - // child dialogs don't want resizable border or size grip, - // nor they can handle the min/max size constraints - BOOL bChild = lpCreateStruct->style & WS_CHILD; - - // create and init the size-grip - if (!CreateSizeGrip(!bChild)) - return FALSE; - - MakeResizable(lpCreateStruct); - - return TRUE; -} - -BOOL CResizableSheet::OnInitDialog() -{ - BOOL bResult = CPropertySheet::OnInitDialog(); - - // initialize layout - PresetLayout(); - m_bLayoutDone = TRUE; - - return bResult; -} - -void CResizableSheet::OnDestroy() -{ - if (m_bEnableSaveRestore) - { - SaveWindowRect(m_sSection, m_bRectOnly); - if (m_bSavePage) - SavePage(m_sSection); - } - - // reset instance data - RemoveAllAnchors(); - ResetAllRects(); - PrivateConstruct(); - - CPropertySheet::OnDestroy(); -} - -// maps an index to a button ID and vice-versa -static UINT _propButtons[] = -{ - IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP, - ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH -}; -const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT); - -// horizontal line in wizard mode -#define ID_WIZLINE ID_WIZFINISH+1 - -void CResizableSheet::PresetLayout() -{ - // set the initial size as the min track size - CRect rc; - GetWindowRect(&rc); - SetMinTrackSize(rc.Size()); - - // use *total* parent size to have correct margins - CRect rectPage, rectSheet; - GetTotalClientRect(&rectSheet); - - // get page area - if (IsWizard()) - { - HWND hPage = PropSheet_GetCurrentPageHwnd(m_hWnd); - ::GetWindowRect(hPage, &rectPage); - } - else - { - GetTabControl()->GetWindowRect(&rectPage); - } - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2); - - // calculate margins - CRect rect; - int cxDiff = rectSheet.right - rectPage.right; - int cyDiff = 0; - - // try all possible buttons - for (int i = 0; i < _propButtonsCount; i++) - { - CWnd* pWnd = GetDlgItem(_propButtons[i]); - if (NULL != pWnd) - { - // move buttons if necessary - if (GetStyle() & WS_CHILD) - { - pWnd->GetWindowRect(&rect); - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rect, 2); - - cyDiff = rectSheet.bottom - rect.bottom; - rect.OffsetRect(cxDiff, cyDiff); - - pWnd->MoveWindow(&rect); - } - // add buttons to the layout manager - AddAnchor(_propButtons[i], BOTTOM_RIGHT); - } - } - - // setup pages area - if (IsWizard()) - { - // move line and pages if necessary - if (GetStyle() & WS_CHILD) - { - GetDlgItem(ID_WIZLINE)->GetWindowRect(&rect); - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rect, 2); - - rect.OffsetRect(0, cyDiff); - rect.InflateRect(cxDiff, 0); - - GetDlgItem(ID_WIZLINE)->MoveWindow(&rect); - - rectPage.bottom += cyDiff; - rectPage.left = 0; - rectPage.top = 0; - rectPage.right = rectSheet.right; - } - - AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT); - - // hide tab control - GetTabControl()->ShowWindow(SW_HIDE); - - // pre-calculate margins - m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft(); - m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight(); - } - else - { - // grow tab to the available sheet space - if (cyDiff > 0) - rectSheet.bottom = rectPage.bottom + cyDiff; - - if (GetStyle() & WS_CHILD) - GetTabControl()->MoveWindow(&rectSheet); - - AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT); - } - - // add a callback for active page (which can change at run-time) - m_nCallbackID = AddAnchorCallback(); - - // prevent flickering - GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS); -} - -BOOL CResizableSheet::ArrangeLayoutCallback(LAYOUTINFO &layout) const -{ - if (layout.nCallbackID != m_nCallbackID) // we only added 1 callback - return CResizableLayout::ArrangeLayoutCallback(layout); - - // set layout info for active page - layout.hWnd = PropSheet_GetCurrentPageHwnd(m_hWnd); - if (!::IsWindow(layout.hWnd)) - return FALSE; - - // set margins - if (IsWizard()) // wizard mode - { - // use pre-calculated margins - layout.marginTopLeft = m_sizePageTL; - layout.marginBottomRight = m_sizePageBR; - } - else // tab mode - { - CTabCtrl* pTab = GetTabControl(); - ASSERT(pTab != NULL); - - // get tab position after resizing and calc page rect - CRect rectPage, rectSheet; - GetTotalClientRect(&rectSheet); - - if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)) - return FALSE; // no page yet - - // calculate page size/position from tab rect - AdjustTabRects(rectPage); - - // set margins - layout.marginTopLeft = rectPage.TopLeft() - rectSheet.TopLeft(); - layout.marginBottomRight = rectPage.BottomRight() - rectSheet.BottomRight(); - } - - // set anchor types - layout.anchorTopLeft = TOP_LEFT; - layout.anchorBottomRight = BOTTOM_RIGHT; - - // use this layout info - return TRUE; -} - -void CResizableSheet::OnSize(UINT nType, int cx, int cy) -{ - CWnd::OnSize(nType, cx, cy); - - if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) - return; // arrangement not needed - - if (nType == SIZE_MAXIMIZED) - HideSizeGrip(&m_dwGripTempState); - else - ShowSizeGrip(&m_dwGripTempState); - - // update grip and layout - UpdateSizeGrip(); - ArrangeLayout(); -} - -BOOL CResizableSheet::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/) -{ - // update new wizard page - // active page changes after this notification - PostMessage(WM_SIZE); - - return FALSE; // continue routing -} - -BOOL CResizableSheet::OnEraseBkgnd(CDC* pDC) -{ - ClipChildren(pDC, FALSE); - - BOOL bRet = CPropertySheet::OnEraseBkgnd(pDC); - - ClipChildren(pDC, TRUE); - - return bRet; -} - -BOOL CResizableSheet::CalcSizeExtra(HWND /*hWndChild*/, const CSize& sizeChild, CSize& sizeExtra) -{ - CTabCtrl* pTab = GetTabControl(); - if (!pTab) - return FALSE; - - // get margins of tabcontrol - CRect rectMargins; - if (!GetAnchorMargins(pTab->m_hWnd, sizeChild, rectMargins)) - return FALSE; - - // get tab position after resizing and calc page rect - CRect rectPage, rectSheet; - GetTotalClientRect(&rectSheet); - - if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)) - return FALSE; // no page yet - - // calculate tab margins - CRect rectTabMargins = AdjustTabRects(rectPage); - - // add non-client size - const DWORD dwStyle = GetStyle(); - ::AdjustWindowRectEx(&rectTabMargins, dwStyle, !(dwStyle & WS_CHILD) && - ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle()); - // compute extra size - sizeExtra = rectMargins.TopLeft() + rectMargins.BottomRight() + - rectTabMargins.Size(); - return TRUE; -} - -CRect CResizableSheet::AdjustTabRects(CRect &rectPage) const -{ - CTabCtrl* pTab = GetTabControl(); - CRect rectTabMargins; - if (m_rectLastPage == rectPage) - { - // use cached rects to avoid flickering while moving the window - rectPage = m_rectLastAjustedPage; - rectTabMargins = m_rectLastTabMargins; - } - else - { - m_rectLastPage = rectPage; - - // temporarily resize the tab control to calc page size - CRect rectSave; - pTab->GetWindowRect(rectSave); - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2); - pTab->SetRedraw(FALSE); - pTab->MoveWindow(rectPage, FALSE); - pTab->AdjustRect(FALSE, &rectPage); - pTab->AdjustRect(TRUE, &rectTabMargins); - pTab->MoveWindow(rectSave, FALSE); - pTab->SetRedraw(TRUE); - - m_rectLastAjustedPage = rectPage; - m_rectLastTabMargins = rectTabMargins; - } - return rectTabMargins; -} - -void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) -{ - MinMaxInfo(lpMMI); - - if (!GetTabControl()) - return; - - int idx = GetPageCount(); - if (IsWizard()) // wizard mode - { - CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR)); - const DWORD dwStyle = GetStyle(); - ::AdjustWindowRectEx(&rectExtra, dwStyle, !(dwStyle & WS_CHILD) && - ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle()); - while (--idx >= 0) - ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size()); - } - else // tab mode - { - while (--idx >= 0) - ChainMinMaxInfoCB(lpMMI, *GetPage(idx)); - } -} - -// protected members - -int CResizableSheet::GetMinWidth() -{ - CRect rectWnd, rectSheet; - GetTotalClientRect(&rectSheet); - - int max = 0, min = rectSheet.Width(); - // search for leftmost and rightmost button margins - for (int i = 0; i < 7; ++i) - { - const CWnd* pWnd = GetDlgItem(_propButtons[i]); - // exclude not present or hidden buttons - if (pWnd != NULL && (pWnd->GetStyle() & WS_VISIBLE)) - { - // left position is relative to the right border - // of the parent window (negative value) - pWnd->GetWindowRect(&rectWnd); - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2); - const int left = rectSheet.right - rectWnd.left; - const int right = rectSheet.right - rectWnd.right; - - if (left > max) - max = left; - if (right < min) - min = right; - } - } - - // sizing border width - const int border = GetSystemMetrics(SM_CXSIZEFRAME); - - // compute total width - return max + min + 2*border; -} - - -// NOTE: this must be called after all the other settings -// to have the window and its controls displayed properly -void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage) -{ - m_sSection = pszSection; - m_bSavePage = bWithPage; - - m_bEnableSaveRestore = TRUE; - m_bRectOnly = bRectOnly; - - // restore immediately - LoadWindowRect(pszSection, bRectOnly); - { - LoadPage(pszSection); - ArrangeLayout(); // needs refresh - } -} - -void CResizableSheet::RefreshLayout() -{ - SendMessage(WM_SIZE); -} - -LRESULT CResizableSheet::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message != WM_NCCALCSIZE || wParam == 0 || !m_bLayoutDone) - return CPropertySheet::WindowProc(message, wParam, lParam); - - // specifying valid rects needs controls already anchored - LRESULT lResult = 0; - HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - lResult = CPropertySheet::WindowProc(message, wParam, lParam); - HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - return lResult; -} +// ResizableSheet.cpp : implementation file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ResizableSheet.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CResizableSheet + +IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet) + +inline void CResizableSheet::PrivateConstruct() +{ + m_bEnableSaveRestore = FALSE; + m_bSavePage = FALSE; + m_dwGripTempState = 1; + m_bLayoutDone = FALSE; + m_bRectOnly = FALSE; + m_nCallbackID = 0; +} + +inline BOOL CResizableSheet::IsWizard() const +{ + return (m_psh.dwFlags & PSH_WIZARD); +} + +CResizableSheet::CResizableSheet() +{ + PrivateConstruct(); +} + +CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage) + : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) +{ + PrivateConstruct(); +} + +CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage) + : CPropertySheet(pszCaption, pParentWnd, iSelectPage) +{ + PrivateConstruct(); +} + +CResizableSheet::~CResizableSheet() +{ +} + +BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet) + //{{AFX_MSG_MAP(CResizableSheet) + ON_WM_GETMINMAXINFO() + ON_WM_SIZE() + ON_WM_DESTROY() + ON_WM_ERASEBKGND() + ON_WM_NCCREATE() + //}}AFX_MSG_MAP + ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CResizableSheet message handlers + +BOOL CResizableSheet::OnNcCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (!CPropertySheet::OnNcCreate(lpCreateStruct)) + return FALSE; + + // child dialogs don't want resizable border or size grip, + // nor they can handle the min/max size constraints + BOOL bChild = lpCreateStruct->style & WS_CHILD; + + // create and init the size-grip + if (!CreateSizeGrip(!bChild)) + return FALSE; + + MakeResizable(lpCreateStruct); + + return TRUE; +} + +BOOL CResizableSheet::OnInitDialog() +{ + BOOL bResult = CPropertySheet::OnInitDialog(); + + // initialize layout + PresetLayout(); + m_bLayoutDone = TRUE; + + return bResult; +} + +void CResizableSheet::OnDestroy() +{ + if (m_bEnableSaveRestore) + { + SaveWindowRect(m_sSection, m_bRectOnly); + if (m_bSavePage) + SavePage(m_sSection); + } + + // reset instance data + RemoveAllAnchors(); + ResetAllRects(); + PrivateConstruct(); + + CPropertySheet::OnDestroy(); +} + +// maps an index to a button ID and vice-versa +static UINT _propButtons[] = +{ + IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP, + ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH +}; +const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT); + +// horizontal line in wizard mode +#define ID_WIZLINE ID_WIZFINISH+1 + +void CResizableSheet::PresetLayout() +{ + // set the initial size as the min track size + CRect rc; + GetWindowRect(&rc); + SetMinTrackSize(rc.Size()); + + // use *total* parent size to have correct margins + CRect rectPage, rectSheet; + GetTotalClientRect(&rectSheet); + + // get page area + if (IsWizard()) + { + HWND hPage = PropSheet_GetCurrentPageHwnd(m_hWnd); + ::GetWindowRect(hPage, &rectPage); + } + else + { + GetTabControl()->GetWindowRect(&rectPage); + } + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2); + + // calculate margins + CRect rect; + int cxDiff = rectSheet.right - rectPage.right; + int cyDiff = 0; + + // try all possible buttons + for (int i = 0; i < _propButtonsCount; i++) + { + CWnd* pWnd = GetDlgItem(_propButtons[i]); + if (NULL != pWnd) + { + // move buttons if necessary + if (GetStyle() & WS_CHILD) + { + pWnd->GetWindowRect(&rect); + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rect, 2); + + cyDiff = rectSheet.bottom - rect.bottom; + rect.OffsetRect(cxDiff, cyDiff); + + pWnd->MoveWindow(&rect); + } + // add buttons to the layout manager + AddAnchor(_propButtons[i], BOTTOM_RIGHT); + } + } + + // setup pages area + if (IsWizard()) + { + // move line and pages if necessary + if (GetStyle() & WS_CHILD) + { + GetDlgItem(ID_WIZLINE)->GetWindowRect(&rect); + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rect, 2); + + rect.OffsetRect(0, cyDiff); + rect.InflateRect(cxDiff, 0); + + GetDlgItem(ID_WIZLINE)->MoveWindow(&rect); + + rectPage.bottom += cyDiff; + rectPage.left = 0; + rectPage.top = 0; + rectPage.right = rectSheet.right; + } + + AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT); + + // hide tab control + GetTabControl()->ShowWindow(SW_HIDE); + + // pre-calculate margins + m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft(); + m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight(); + } + else + { + // grow tab to the available sheet space + if (cyDiff > 0) + rectSheet.bottom = rectPage.bottom + cyDiff; + + if (GetStyle() & WS_CHILD) + GetTabControl()->MoveWindow(&rectSheet); + + AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT); + } + + // add a callback for active page (which can change at run-time) + m_nCallbackID = AddAnchorCallback(); + + // prevent flickering + GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS); +} + +BOOL CResizableSheet::ArrangeLayoutCallback(LAYOUTINFO &layout) const +{ + if (layout.nCallbackID != m_nCallbackID) // we only added 1 callback + return CResizableLayout::ArrangeLayoutCallback(layout); + + // set layout info for active page + layout.hWnd = PropSheet_GetCurrentPageHwnd(m_hWnd); + if (!::IsWindow(layout.hWnd)) + return FALSE; + + // set margins + if (IsWizard()) // wizard mode + { + // use pre-calculated margins + layout.marginTopLeft = m_sizePageTL; + layout.marginBottomRight = m_sizePageBR; + } + else // tab mode + { + CTabCtrl* pTab = GetTabControl(); + ASSERT(pTab != NULL); + + // get tab position after resizing and calc page rect + CRect rectPage, rectSheet; + GetTotalClientRect(&rectSheet); + + if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)) + return FALSE; // no page yet + + // calculate page size/position from tab rect + AdjustTabRects(rectPage); + + // set margins + layout.marginTopLeft = rectPage.TopLeft() - rectSheet.TopLeft(); + layout.marginBottomRight = rectPage.BottomRight() - rectSheet.BottomRight(); + } + + // set anchor types + layout.anchorTopLeft = TOP_LEFT; + layout.anchorBottomRight = BOTTOM_RIGHT; + + // use this layout info + return TRUE; +} + +void CResizableSheet::OnSize(UINT nType, int cx, int cy) +{ + CWnd::OnSize(nType, cx, cy); + + if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) + return; // arrangement not needed + + if (nType == SIZE_MAXIMIZED) + HideSizeGrip(&m_dwGripTempState); + else + ShowSizeGrip(&m_dwGripTempState); + + // update grip and layout + UpdateSizeGrip(); + ArrangeLayout(); +} + +BOOL CResizableSheet::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/) +{ + // update new wizard page + // active page changes after this notification + PostMessage(WM_SIZE); + + return FALSE; // continue routing +} + +BOOL CResizableSheet::OnEraseBkgnd(CDC* pDC) +{ + ClipChildren(pDC, FALSE); + + BOOL bRet = CPropertySheet::OnEraseBkgnd(pDC); + + ClipChildren(pDC, TRUE); + + return bRet; +} + +BOOL CResizableSheet::CalcSizeExtra(HWND /*hWndChild*/, const CSize& sizeChild, CSize& sizeExtra) +{ + CTabCtrl* pTab = GetTabControl(); + if (!pTab) + return FALSE; + + // get margins of tabcontrol + CRect rectMargins; + if (!GetAnchorMargins(pTab->m_hWnd, sizeChild, rectMargins)) + return FALSE; + + // get tab position after resizing and calc page rect + CRect rectPage, rectSheet; + GetTotalClientRect(&rectSheet); + + if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)) + return FALSE; // no page yet + + // calculate tab margins + CRect rectTabMargins = AdjustTabRects(rectPage); + + // add non-client size + const DWORD dwStyle = GetStyle(); + ::AdjustWindowRectEx(&rectTabMargins, dwStyle, !(dwStyle & WS_CHILD) && + ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle()); + // compute extra size + sizeExtra = rectMargins.TopLeft() + rectMargins.BottomRight() + + rectTabMargins.Size(); + return TRUE; +} + +CRect CResizableSheet::AdjustTabRects(CRect &rectPage) const +{ + CTabCtrl* pTab = GetTabControl(); + CRect rectTabMargins; + if (m_rectLastPage == rectPage) + { + // use cached rects to avoid flickering while moving the window + rectPage = m_rectLastAjustedPage; + rectTabMargins = m_rectLastTabMargins; + } + else + { + m_rectLastPage = rectPage; + + // temporarily resize the tab control to calc page size + CRect rectSave; + pTab->GetWindowRect(rectSave); + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2); + pTab->SetRedraw(FALSE); + pTab->MoveWindow(rectPage, FALSE); + pTab->AdjustRect(FALSE, &rectPage); + pTab->AdjustRect(TRUE, &rectTabMargins); + pTab->MoveWindow(rectSave, FALSE); + pTab->SetRedraw(TRUE); + + m_rectLastAjustedPage = rectPage; + m_rectLastTabMargins = rectTabMargins; + } + return rectTabMargins; +} + +void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + MinMaxInfo(lpMMI); + + if (!GetTabControl()) + return; + + int idx = GetPageCount(); + if (IsWizard()) // wizard mode + { + CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR)); + const DWORD dwStyle = GetStyle(); + ::AdjustWindowRectEx(&rectExtra, dwStyle, !(dwStyle & WS_CHILD) && + ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle()); + while (--idx >= 0) + ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size()); + } + else // tab mode + { + while (--idx >= 0) + ChainMinMaxInfoCB(lpMMI, *GetPage(idx)); + } +} + +// protected members + +int CResizableSheet::GetMinWidth() +{ + CRect rectWnd, rectSheet; + GetTotalClientRect(&rectSheet); + + int max = 0, min = rectSheet.Width(); + // search for leftmost and rightmost button margins + for (int i = 0; i < 7; ++i) + { + const CWnd* pWnd = GetDlgItem(_propButtons[i]); + // exclude not present or hidden buttons + if (pWnd != NULL && (pWnd->GetStyle() & WS_VISIBLE)) + { + // left position is relative to the right border + // of the parent window (negative value) + pWnd->GetWindowRect(&rectWnd); + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2); + const int left = rectSheet.right - rectWnd.left; + const int right = rectSheet.right - rectWnd.right; + + if (left > max) + max = left; + if (right < min) + min = right; + } + } + + // sizing border width + const int border = GetSystemMetrics(SM_CXSIZEFRAME); + + // compute total width + return max + min + 2*border; +} + + +// NOTE: this must be called after all the other settings +// to have the window and its controls displayed properly +void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage) +{ + m_sSection = pszSection; + m_bSavePage = bWithPage; + + m_bEnableSaveRestore = TRUE; + m_bRectOnly = bRectOnly; + + // restore immediately + LoadWindowRect(pszSection, bRectOnly); + { + LoadPage(pszSection); + ArrangeLayout(); // needs refresh + } +} + +void CResizableSheet::RefreshLayout() +{ + SendMessage(WM_SIZE); +} + +LRESULT CResizableSheet::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message != WM_NCCALCSIZE || wParam == 0 || !m_bLayoutDone) + return CPropertySheet::WindowProc(message, wParam, lParam); + + // specifying valid rects needs controls already anchored + LRESULT lResult = 0; + HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + lResult = CPropertySheet::WindowProc(message, wParam, lParam); + HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + return lResult; +} diff --git a/src/thirdparty/ResizableLib/ResizableSheet.h b/src/thirdparty/ResizableLib/ResizableSheet.h index faede2fb6e2..4ae64421509 100644 --- a/src/thirdparty/ResizableLib/ResizableSheet.h +++ b/src/thirdparty/ResizableLib/ResizableSheet.h @@ -1,121 +1,121 @@ -#if !defined(AFX_RESIZABLESHEET_H__INCLUDED_) -#define AFX_RESIZABLESHEET_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "ResizableLayout.h" -#include "ResizableGrip.h" -#include "ResizableMinMax.h" -#include "ResizableSheetState.h" - -///////////////////////////////////////////////////////////////////////////// -// ResizableSheet.h : header file -// - -class CResizableSheet : public CPropertySheet, public CResizableLayout, - public CResizableGrip, public CResizableMinMax, - public CResizableSheetState -{ - DECLARE_DYNAMIC(CResizableSheet) - -// Construction -public: - CResizableSheet(); - explicit CResizableSheet(UINT nIDCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0); - explicit CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0); - -// Attributes -private: - // support for temporarily hiding the grip - DWORD m_dwGripTempState; - - // flags - BOOL m_bEnableSaveRestore; - BOOL m_bRectOnly; - BOOL m_bSavePage; - - // layout vars - LRESULT m_nCallbackID; - CSize m_sizePageTL, m_sizePageBR; - BOOL m_bLayoutDone; - - // internal status - CString m_sSection; // section name (identifies a parent window) - - // cached tab rects - mutable CRect m_rectLastPage, m_rectLastAjustedPage, m_rectLastTabMargins; - -// Operations -public: - -// Overrides - virtual BOOL OnInitDialog(); - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CResizableSheet) - protected: - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CResizableSheet(); - -// used internally -private: - void PrivateConstruct(); - - BOOL IsWizard() const; - CRect AdjustTabRects(CRect &rectPage) const; - -// callable from derived classes -protected: - void PresetLayout(); - void RefreshLayout(); - - // section to use in app's profile - void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE, - BOOL bWithPage = FALSE); - int GetMinWidth(); // minimum width to display all buttons - - - virtual CWnd* GetResizableWnd() const - { - // make the layout know its parent window - return CWnd::FromHandle(m_hWnd); - }; - -// Generated message map functions -protected: - virtual BOOL CalcSizeExtra(HWND hWndChild, const CSize& sizeChild, CSize& sizeExtra); - virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const; - //{{AFX_MSG(CResizableSheet) - afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnDestroy(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct); - //}}AFX_MSG - afx_msg BOOL OnPageChanging(NMHDR* pNotifyStruct, LRESULT* pResult); - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////////// - -#endif // AFX_RESIZABLESHEET_H__INCLUDED_ +#if !defined(AFX_RESIZABLESHEET_H__INCLUDED_) +#define AFX_RESIZABLESHEET_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "ResizableLayout.h" +#include "ResizableGrip.h" +#include "ResizableMinMax.h" +#include "ResizableSheetState.h" + +///////////////////////////////////////////////////////////////////////////// +// ResizableSheet.h : header file +// + +class CResizableSheet : public CPropertySheet, public CResizableLayout, + public CResizableGrip, public CResizableMinMax, + public CResizableSheetState +{ + DECLARE_DYNAMIC(CResizableSheet) + +// Construction +public: + CResizableSheet(); + explicit CResizableSheet(UINT nIDCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0); + explicit CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0); + +// Attributes +private: + // support for temporarily hiding the grip + DWORD m_dwGripTempState; + + // flags + BOOL m_bEnableSaveRestore; + BOOL m_bRectOnly; + BOOL m_bSavePage; + + // layout vars + LRESULT m_nCallbackID; + CSize m_sizePageTL, m_sizePageBR; + BOOL m_bLayoutDone; + + // internal status + CString m_sSection; // section name (identifies a parent window) + + // cached tab rects + mutable CRect m_rectLastPage, m_rectLastAjustedPage, m_rectLastTabMargins; + +// Operations +public: + +// Overrides + virtual BOOL OnInitDialog(); + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CResizableSheet) + protected: + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CResizableSheet(); + +// used internally +private: + void PrivateConstruct(); + + BOOL IsWizard() const; + CRect AdjustTabRects(CRect &rectPage) const; + +// callable from derived classes +protected: + void PresetLayout(); + void RefreshLayout(); + + // section to use in app's profile + void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE, + BOOL bWithPage = FALSE); + int GetMinWidth(); // minimum width to display all buttons + + + virtual CWnd* GetResizableWnd() const + { + // make the layout know its parent window + return CWnd::FromHandle(m_hWnd); + }; + +// Generated message map functions +protected: + virtual BOOL CalcSizeExtra(HWND hWndChild, const CSize& sizeChild, CSize& sizeExtra); + virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const; + //{{AFX_MSG(CResizableSheet) + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnDestroy(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct); + //}}AFX_MSG + afx_msg BOOL OnPageChanging(NMHDR* pNotifyStruct, LRESULT* pResult); + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +#endif // AFX_RESIZABLESHEET_H__INCLUDED_ diff --git a/src/thirdparty/ResizableLib/ResizableState.cpp b/src/thirdparty/ResizableLib/ResizableState.cpp index f889efdfb28..b9c4bcde043 100644 --- a/src/thirdparty/ResizableLib/ResizableState.cpp +++ b/src/thirdparty/ResizableLib/ResizableState.cpp @@ -1,132 +1,132 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Implementation of the CResizableState class. - */ - -#include "stdafx.h" -#include "ResizableState.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[]=__FILE__; -#define new DEBUG_NEW -#endif - -LPCTSTR CResizableState::m_sDefaultStorePath = _T("ResizableState"); - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResizableState::CResizableState() -{ - m_sStorePath = m_sDefaultStorePath; -} - -CResizableState::~CResizableState() -{ - -} - -/*! - * Static function to set the default path used to store state information. - * This path is used to initialize all the instances of this class. - * @sa GetDefaultStateStore GetStateStore SetStateStore - * - * @param szPath String that specifies the new path to be set - */ -void CResizableState::SetDefaultStateStore(LPCTSTR szPath) -{ - m_sDefaultStorePath = szPath; -} - -/*! - * Static function to retrieve the default path used to store state - * information. - * This path is used to initialize all the instances of this class. - * @sa SetDefaultStateStore GetStateStore SetStateStore - * - * @return The return value is a string that specifies the current path - */ -LPCTSTR CResizableState::GetDefaultStateStore() -{ - return m_sDefaultStorePath; -} - -/*! - * This function sets the path used to store state information by - * the current instance of the class. - * @sa GetStateStore GetDefaultStateStore SetDefaultStateStore - * - * @param szPath String that specifies the new path to be set - */ -void CResizableState::SetStateStore(LPCTSTR szPath) -{ - m_sStorePath = szPath; -} - -/*! - * This function retrieves the path used to store state information by - * the current instance of the class. - * @sa SetStateStore GetDefaultStateStore SetDefaultStateStore - * - * @return The return value is a string that specifies the current path - */ -LPCTSTR CResizableState::GetStateStore() const -{ - return m_sStorePath; -} - -/*! - * This function writes state information and associates it with some - * identification text for later retrieval. - * The base implementation uses the application profile to persist state - * information, but this function can be overridden to implement - * different methods. - * - * @param szId String that identifies the stored settings - * @param szState String that represents the state information to store - * - * @return The return value is @a TRUE if settings have been successfully - * stored, @a FALSE otherwise. - */ -// MPC-HC custom code--adds LPCTSTR szValue -BOOL CResizableState::WriteState(LPCTSTR szId, LPCTSTR szValue, LPCTSTR szState) -{ - return AfxGetApp()->WriteProfileString(szId, szValue, szState); -} - -/*! - * This function reads state information previously associated with some - * identification text. - * The base implementation uses the application profile to persist state - * information, but this function can be overridden to implement - * different methods. - * - * @param szId String that identifies the stored settings - * @param rsState String to be filled with the retrieved state information - * - * @return The return value is @a TRUE if settings have been successfully - * retrieved, @a FALSE otherwise. - */ -// MPC-HC custom code--adds LPCTSTR szValue -BOOL CResizableState::ReadState(LPCTSTR szId, LPCTSTR szValue, CString &rsState) -{ - rsState = AfxGetApp()->GetProfileString(szId, szValue); - return !rsState.IsEmpty(); -} +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Implementation of the CResizableState class. + */ + +#include "stdafx.h" +#include "ResizableState.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +LPCTSTR CResizableState::m_sDefaultStorePath = _T("ResizableState"); + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResizableState::CResizableState() +{ + m_sStorePath = m_sDefaultStorePath; +} + +CResizableState::~CResizableState() +{ + +} + +/*! + * Static function to set the default path used to store state information. + * This path is used to initialize all the instances of this class. + * @sa GetDefaultStateStore GetStateStore SetStateStore + * + * @param szPath String that specifies the new path to be set + */ +void CResizableState::SetDefaultStateStore(LPCTSTR szPath) +{ + m_sDefaultStorePath = szPath; +} + +/*! + * Static function to retrieve the default path used to store state + * information. + * This path is used to initialize all the instances of this class. + * @sa SetDefaultStateStore GetStateStore SetStateStore + * + * @return The return value is a string that specifies the current path + */ +LPCTSTR CResizableState::GetDefaultStateStore() +{ + return m_sDefaultStorePath; +} + +/*! + * This function sets the path used to store state information by + * the current instance of the class. + * @sa GetStateStore GetDefaultStateStore SetDefaultStateStore + * + * @param szPath String that specifies the new path to be set + */ +void CResizableState::SetStateStore(LPCTSTR szPath) +{ + m_sStorePath = szPath; +} + +/*! + * This function retrieves the path used to store state information by + * the current instance of the class. + * @sa SetStateStore GetDefaultStateStore SetDefaultStateStore + * + * @return The return value is a string that specifies the current path + */ +LPCTSTR CResizableState::GetStateStore() const +{ + return m_sStorePath; +} + +/*! + * This function writes state information and associates it with some + * identification text for later retrieval. + * The base implementation uses the application profile to persist state + * information, but this function can be overridden to implement + * different methods. + * + * @param szId String that identifies the stored settings + * @param szState String that represents the state information to store + * + * @return The return value is @a TRUE if settings have been successfully + * stored, @a FALSE otherwise. + */ +// MPC-HC custom code--adds LPCTSTR szValue +BOOL CResizableState::WriteState(LPCTSTR szId, LPCTSTR szValue, LPCTSTR szState) +{ + return AfxGetApp()->WriteProfileString(szId, szValue, szState); +} + +/*! + * This function reads state information previously associated with some + * identification text. + * The base implementation uses the application profile to persist state + * information, but this function can be overridden to implement + * different methods. + * + * @param szId String that identifies the stored settings + * @param rsState String to be filled with the retrieved state information + * + * @return The return value is @a TRUE if settings have been successfully + * retrieved, @a FALSE otherwise. + */ +// MPC-HC custom code--adds LPCTSTR szValue +BOOL CResizableState::ReadState(LPCTSTR szId, LPCTSTR szValue, CString &rsState) +{ + rsState = AfxGetApp()->GetProfileString(szId, szValue); + return !rsState.IsEmpty(); +} diff --git a/src/thirdparty/ResizableLib/ResizableState.h b/src/thirdparty/ResizableLib/ResizableState.h index ba677feecdd..ce08eedb283 100644 --- a/src/thirdparty/ResizableLib/ResizableState.h +++ b/src/thirdparty/ResizableLib/ResizableState.h @@ -1,77 +1,77 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Interface for the CResizableState class. - */ - -#if !defined(AFX_RESIZABLESTATE_H__INCLUDED_) -#define AFX_RESIZABLESTATE_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -/*! @addtogroup CoreComponents - * @{ - */ - -//! @brief Provides basic persisting capabilities -/*! - * Derive from this class to persist user interface settings, or anything - * suitable. The base implementation uses the application profile, which can - * be set to either the Registry or an INI File. Other storing methods - * can be implemented in derived classes. - */ -class CResizableState -{ - static LPCTSTR m_sDefaultStorePath; - CString m_sStorePath; - -protected: - - //! @brief Get default path where state is stored - static LPCTSTR GetDefaultStateStore(); - - //! @brief Set default path where state is stored - static void SetDefaultStateStore(LPCTSTR szPath); - - //! @brief Get current path where state is stored - LPCTSTR GetStateStore() const; - - //! @brief Set current path where state is stored - void SetStateStore(LPCTSTR szPath); - - //! @name Overridables - //@{ - - //! @brief Read state information - // MPC-HC custom code--adds LPCTSTR szValue - virtual BOOL ReadState(LPCTSTR szId, LPCTSTR szValue, CString& rsState); - - //! @brief Write state information - // MPC-HC custom code--adds LPCTSTR szValue - virtual BOOL WriteState(LPCTSTR szId, LPCTSTR szValue, LPCTSTR szState); - - //@} - -public: - CResizableState(); - virtual ~CResizableState(); -}; - -// @} -#endif // !defined(AFX_RESIZABLESTATE_H__INCLUDED_) +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Interface for the CResizableState class. + */ + +#if !defined(AFX_RESIZABLESTATE_H__INCLUDED_) +#define AFX_RESIZABLESTATE_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/*! @addtogroup CoreComponents + * @{ + */ + +//! @brief Provides basic persisting capabilities +/*! + * Derive from this class to persist user interface settings, or anything + * suitable. The base implementation uses the application profile, which can + * be set to either the Registry or an INI File. Other storing methods + * can be implemented in derived classes. + */ +class CResizableState +{ + static LPCTSTR m_sDefaultStorePath; + CString m_sStorePath; + +protected: + + //! @brief Get default path where state is stored + static LPCTSTR GetDefaultStateStore(); + + //! @brief Set default path where state is stored + static void SetDefaultStateStore(LPCTSTR szPath); + + //! @brief Get current path where state is stored + LPCTSTR GetStateStore() const; + + //! @brief Set current path where state is stored + void SetStateStore(LPCTSTR szPath); + + //! @name Overridables + //@{ + + //! @brief Read state information + // MPC-HC custom code--adds LPCTSTR szValue + virtual BOOL ReadState(LPCTSTR szId, LPCTSTR szValue, CString& rsState); + + //! @brief Write state information + // MPC-HC custom code--adds LPCTSTR szValue + virtual BOOL WriteState(LPCTSTR szId, LPCTSTR szValue, LPCTSTR szState); + + //@} + +public: + CResizableState(); + virtual ~CResizableState(); +}; + +// @} +#endif // !defined(AFX_RESIZABLESTATE_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/stdafx.cpp b/src/thirdparty/ResizableLib/stdafx.cpp index e634be5853e..a7c3002e327 100644 --- a/src/thirdparty/ResizableLib/stdafx.cpp +++ b/src/thirdparty/ResizableLib/stdafx.cpp @@ -1,6 +1,6 @@ -// stdafx.cpp : source file that includes just the standard includes -// ResizableLib.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - +// stdafx.cpp : source file that includes just the standard includes +// ResizableLib.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + diff --git a/src/thirdparty/ResizableLib/stdafx.h b/src/thirdparty/ResizableLib/stdafx.h index 335e0acd646..9636e7a68df 100644 --- a/src/thirdparty/ResizableLib/stdafx.h +++ b/src/thirdparty/ResizableLib/stdafx.h @@ -1,68 +1,68 @@ -// stdafx.h : include file for standard system include files, or project -// specific include files that are used frequently, but are changed infrequently -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_RESIZABLESTDAFX_H__INCLUDED_) -#define AFX_RESIZABLESTDAFX_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -// Set max target Windows platform -#define WINVER 0x0501 -#define _WIN32_WINNT 0x0501 - -// Use target Common Controls version for compatibility -// with CPropertyPageEx, CPropertySheetEx -#define _WIN32_IE 0x0500 - -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include // MFC core and standard components -#include // MFC extensions -#include // MFC support for Windows Common Controls -#include // DLL Version support -#if _WIN32_WINNT >= 0x0501 -#include // Windows XP Visual Style API support -#endif - -#ifndef WS_EX_LAYOUTRTL -#pragma message("Please update your Windows header files, get the latest SDK") -#pragma message("WinUser.h is out of date!") - -#define WS_EX_LAYOUTRTL 0x00400000 -#endif - -#ifndef WC_BUTTON -#pragma message("Please update your Windows header files, get the latest SDK") -#pragma message("CommCtrl.h is out of date!") - -#define WC_BUTTON TEXT("Button") -#define WC_STATIC TEXT("Static") -#define WC_EDIT TEXT("Edit") -#define WC_LISTBOX TEXT("ListBox") -#define WC_COMBOBOX TEXT("ComboBox") -#define WC_SCROLLBAR TEXT("ScrollBar") -#endif - -#define RSZLIB_NO_XP_DOUBLE_BUFFER - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_RESIZABLESTDAFX_H__INCLUDED_) +// stdafx.h : include file for standard system include files, or project +// specific include files that are used frequently, but are changed infrequently +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_RESIZABLESTDAFX_H__INCLUDED_) +#define AFX_RESIZABLESTDAFX_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// Set max target Windows platform +#define WINVER 0x0501 +#define _WIN32_WINNT 0x0501 + +// Use target Common Controls version for compatibility +// with CPropertyPageEx, CPropertySheetEx +#define _WIN32_IE 0x0500 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC support for Windows Common Controls +#include // DLL Version support +#if _WIN32_WINNT >= 0x0501 +#include // Windows XP Visual Style API support +#endif + +#ifndef WS_EX_LAYOUTRTL +#pragma message("Please update your Windows header files, get the latest SDK") +#pragma message("WinUser.h is out of date!") + +#define WS_EX_LAYOUTRTL 0x00400000 +#endif + +#ifndef WC_BUTTON +#pragma message("Please update your Windows header files, get the latest SDK") +#pragma message("CommCtrl.h is out of date!") + +#define WC_BUTTON TEXT("Button") +#define WC_STATIC TEXT("Static") +#define WC_EDIT TEXT("Edit") +#define WC_LISTBOX TEXT("ListBox") +#define WC_COMBOBOX TEXT("ComboBox") +#define WC_SCROLLBAR TEXT("ScrollBar") +#endif + +#define RSZLIB_NO_XP_DOUBLE_BUFFER + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_RESIZABLESTDAFX_H__INCLUDED_) diff --git a/src/thirdparty/TreePropSheet/PropPageFrame.cpp b/src/thirdparty/TreePropSheet/PropPageFrame.cpp index 37de78ccf2c..ee367aeb2a7 100644 --- a/src/thirdparty/TreePropSheet/PropPageFrame.cpp +++ b/src/thirdparty/TreePropSheet/PropPageFrame.cpp @@ -1,187 +1,187 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - -#include "stdafx.h" -#include "PropPageFrame.h" - -namespace TreePropSheet -{ - - -//------------------------------------------------------------------- -// class CPropPageFrame -//------------------------------------------------------------------- - -CPropPageFrame::CPropPageFrame() -: m_bShowCaption(FALSE), - m_nCaptionHeight(0), - m_hCaptionIcon(NULL), - m_dwMsgFormat(DT_CENTER|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE) -{ -} - - -CPropPageFrame::~CPropPageFrame() -{ -} - - -///////////////////////////////////////////////////////////////////// -// Operations - - -void CPropPageFrame::ShowCaption(BOOL bEnable) -{ - m_bShowCaption = bEnable; - SafeUpdateWindow(CalcCaptionArea()); -} - - -BOOL CPropPageFrame::GetShowCaption() const -{ - return m_bShowCaption; -} - - -void CPropPageFrame::SetCaption(LPCTSTR lpszCaption, HICON hIcon /*= NULL*/) -{ - m_strCaption = lpszCaption; - m_hCaptionIcon = hIcon; - SafeUpdateWindow(CalcCaptionArea()); -} - - -CString CPropPageFrame::GetCaption(HICON *pIcon /* = NULL */) const -{ - if (pIcon) - *pIcon = m_hCaptionIcon; - return m_strCaption; -} - - -void CPropPageFrame::SetCaptionHeight(int nCaptionHeight) -{ - m_nCaptionHeight = nCaptionHeight; - SafeUpdateWindow(CalcCaptionArea()); -} - - -int CPropPageFrame::GetCaptionHeight() const -{ - return m_nCaptionHeight; -} - - -void CPropPageFrame::SetMsgText(LPCTSTR lpszMsg) -{ - m_strMsg = lpszMsg; - SafeUpdateWindow(CalcMsgArea()); -} - - -CString CPropPageFrame::GetMsgText() const -{ - return m_strMsg; -} - - -void CPropPageFrame::SetMsgFormat(DWORD dwFormat) -{ - m_dwMsgFormat = dwFormat; - SafeUpdateWindow(CalcMsgArea()); -} - - -DWORD CPropPageFrame::GetMsgFormat() const -{ - return m_dwMsgFormat; -} - - -///////////////////////////////////////////////////////////////////// -// Overridable implementation helpers - -void CPropPageFrame::Draw(CDC *pDc) -{ - if (GetShowCaption()) - DrawCaption(pDc, CalcCaptionArea(), m_strCaption, m_hCaptionIcon); - DrawMsg(pDc, CalcMsgArea(), m_strMsg, m_dwMsgFormat); -} - - -CRect CPropPageFrame::CalcMsgArea() -{ - ASSERT(IsWindow(GetWnd()->GetSafeHwnd())); - - CRect rectMsg; - GetWnd()->GetClientRect(rectMsg); - if (GetShowCaption()) - rectMsg.top+= GetCaptionHeight(); - - return rectMsg; -} - - -void CPropPageFrame::DrawMsg(CDC *pDc, CRect rect, LPCTSTR /*lpszMsg*/, DWORD /*dwFormat*/) -{ - CFont *pPrevFont = dynamic_cast(pDc->SelectStockObject(DEFAULT_GUI_FONT)); - int nPrevBkMode = pDc->SetBkMode(TRANSPARENT); - - pDc->DrawText(GetMsgText(), rect, GetMsgFormat()); - - pDc->SetBkMode(nPrevBkMode); - pDc->SelectObject(pPrevFont); -} - - -CRect CPropPageFrame::CalcCaptionArea() -{ - ASSERT(IsWindow(GetWnd()->GetSafeHwnd())); - - CRect rectCaption; - GetWnd()->GetClientRect(rectCaption); - if (!GetShowCaption()) - rectCaption.bottom = rectCaption.top; - else - rectCaption.bottom = rectCaption.top+GetCaptionHeight(); - - return rectCaption; -} - - -void CPropPageFrame::DrawCaption(CDC* /*pDc*/, CRect /*rect*/, LPCTSTR /*lpszCaption*/, HICON /*hIcon*/) -{ - // should be implemented by specialized classes -} - - -///////////////////////////////////////////////////////////////////// -// Implementation helpers - -void CPropPageFrame::SafeUpdateWindow(LPCRECT lpRect /* = NULL */) -{ - if (!IsWindow(GetWnd()->GetSafeHwnd())) - return; - - GetWnd()->InvalidateRect(lpRect, TRUE); -} - - - -} //namespace TreePropSheet +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + +#include "stdafx.h" +#include "PropPageFrame.h" + +namespace TreePropSheet +{ + + +//------------------------------------------------------------------- +// class CPropPageFrame +//------------------------------------------------------------------- + +CPropPageFrame::CPropPageFrame() +: m_bShowCaption(FALSE), + m_nCaptionHeight(0), + m_hCaptionIcon(NULL), + m_dwMsgFormat(DT_CENTER|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE) +{ +} + + +CPropPageFrame::~CPropPageFrame() +{ +} + + +///////////////////////////////////////////////////////////////////// +// Operations + + +void CPropPageFrame::ShowCaption(BOOL bEnable) +{ + m_bShowCaption = bEnable; + SafeUpdateWindow(CalcCaptionArea()); +} + + +BOOL CPropPageFrame::GetShowCaption() const +{ + return m_bShowCaption; +} + + +void CPropPageFrame::SetCaption(LPCTSTR lpszCaption, HICON hIcon /*= NULL*/) +{ + m_strCaption = lpszCaption; + m_hCaptionIcon = hIcon; + SafeUpdateWindow(CalcCaptionArea()); +} + + +CString CPropPageFrame::GetCaption(HICON *pIcon /* = NULL */) const +{ + if (pIcon) + *pIcon = m_hCaptionIcon; + return m_strCaption; +} + + +void CPropPageFrame::SetCaptionHeight(int nCaptionHeight) +{ + m_nCaptionHeight = nCaptionHeight; + SafeUpdateWindow(CalcCaptionArea()); +} + + +int CPropPageFrame::GetCaptionHeight() const +{ + return m_nCaptionHeight; +} + + +void CPropPageFrame::SetMsgText(LPCTSTR lpszMsg) +{ + m_strMsg = lpszMsg; + SafeUpdateWindow(CalcMsgArea()); +} + + +CString CPropPageFrame::GetMsgText() const +{ + return m_strMsg; +} + + +void CPropPageFrame::SetMsgFormat(DWORD dwFormat) +{ + m_dwMsgFormat = dwFormat; + SafeUpdateWindow(CalcMsgArea()); +} + + +DWORD CPropPageFrame::GetMsgFormat() const +{ + return m_dwMsgFormat; +} + + +///////////////////////////////////////////////////////////////////// +// Overridable implementation helpers + +void CPropPageFrame::Draw(CDC *pDc) +{ + if (GetShowCaption()) + DrawCaption(pDc, CalcCaptionArea(), m_strCaption, m_hCaptionIcon); + DrawMsg(pDc, CalcMsgArea(), m_strMsg, m_dwMsgFormat); +} + + +CRect CPropPageFrame::CalcMsgArea() +{ + ASSERT(IsWindow(GetWnd()->GetSafeHwnd())); + + CRect rectMsg; + GetWnd()->GetClientRect(rectMsg); + if (GetShowCaption()) + rectMsg.top+= GetCaptionHeight(); + + return rectMsg; +} + + +void CPropPageFrame::DrawMsg(CDC *pDc, CRect rect, LPCTSTR /*lpszMsg*/, DWORD /*dwFormat*/) +{ + CFont *pPrevFont = dynamic_cast(pDc->SelectStockObject(DEFAULT_GUI_FONT)); + int nPrevBkMode = pDc->SetBkMode(TRANSPARENT); + + pDc->DrawText(GetMsgText(), rect, GetMsgFormat()); + + pDc->SetBkMode(nPrevBkMode); + pDc->SelectObject(pPrevFont); +} + + +CRect CPropPageFrame::CalcCaptionArea() +{ + ASSERT(IsWindow(GetWnd()->GetSafeHwnd())); + + CRect rectCaption; + GetWnd()->GetClientRect(rectCaption); + if (!GetShowCaption()) + rectCaption.bottom = rectCaption.top; + else + rectCaption.bottom = rectCaption.top+GetCaptionHeight(); + + return rectCaption; +} + + +void CPropPageFrame::DrawCaption(CDC* /*pDc*/, CRect /*rect*/, LPCTSTR /*lpszCaption*/, HICON /*hIcon*/) +{ + // should be implemented by specialized classes +} + + +///////////////////////////////////////////////////////////////////// +// Implementation helpers + +void CPropPageFrame::SafeUpdateWindow(LPCRECT lpRect /* = NULL */) +{ + if (!IsWindow(GetWnd()->GetSafeHwnd())) + return; + + GetWnd()->InvalidateRect(lpRect, TRUE); +} + + + +} //namespace TreePropSheet diff --git a/src/thirdparty/TreePropSheet/PropPageFrame.h b/src/thirdparty/TreePropSheet/PropPageFrame.h index 998d30bf4c4..2de997d72d8 100644 --- a/src/thirdparty/TreePropSheet/PropPageFrame.h +++ b/src/thirdparty/TreePropSheet/PropPageFrame.h @@ -1,306 +1,306 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - - -#if !defined(AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_) -#define AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - - -namespace TreePropSheet -{ - - -/** -An object of an CPropertyPageFrame-derived class is used by -CTreePropSheet to display a frame for the property pages. - -Derived classes have to implement at least the Create() and the -GetWnd() method, which -returns a pointer to the CWnd-obect of the window, that has been -created by the call to the Create() method. An implementation can -provide the CWnd-object by using it as a property or by deriving -from CWnd or a more specialiced class. This way has been choosen -instead of deriving CPropPageFrame from CWnd, to allow derived class -to derive from more specialized classes than CWnd -(i.e. CStatic, etc.). From the WM_PAINT-handler of your derived class -you have to call the Draw()-method. - -Most implementations will also implement the DrawCaption() and -DrawMsg() methods, to provide custom drawing functionality. - -@author Sven Wiegand -*/ -class /*AFX_EXT_CLASS*/ CPropPageFrame -{ -// Construction/Destruction -public: - CPropPageFrame(); - virtual ~CPropPageFrame(); - -// Operations -public: - /** - Has to create a window with the specified properties. - - @param dwWindowStyle - Standard window styles, to apply to the window to create. - @param rect - Position and size of the window to create. - @param pwndParent - Parent window. (Never be NULL). - @param nID - Window id. - - @return - TRUE on success, FALSE otherwise. - */ - virtual BOOL Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID) = 0; - - /** - Returns a pointer to the window object, that represents the frame. - */ - virtual CWnd* GetWnd() = 0; - - /** - Enables or disables page caption. - - This default implementation calls the SafeUpdateWindow() method - with the caption rectangle, to force it to be redrawn. - */ - virtual void ShowCaption(BOOL bEnable); - - /** - Returns TRUE if captions are enabled, FALSE otherwise. - */ - BOOL GetShowCaption() const; - - /** - Sets the height of the caption in pixels. This value is ignored - until the caption is enabled by ShowCaption(TRUE). - - This default implementation calls the SafeUpdateWindow() method - with the caption rectangle, to force it to be redrawn. - */ - virtual void SetCaptionHeight(int nCaptionHeight); - - /** - Returns the caption height, that has been most recently set by a - call to the SetCaptionHeight() method. - */ - int GetCaptionHeight() const; - - /** - Sets caption text an icon. - - This default implementation calls the SafeUpdateWindow() method - with the caption rectangle, to force it to be redrawn. - - @param lpszCaption - Text to display for the caption. - @param hIcon - Icon to display for the caption. - */ - virtual void SetCaption(LPCTSTR lpszCaption, HICON hIcon = NULL); - - /** - Returns the caption, that has been set most recently using the - SetCaption() method. - - @param pIcon - Pointer to a HICON variable, that should receive the handle of - the currently set icon or NULL, if there is no icon or a NULL - pointer, if the caller is not interested in the icon. - - @return - The text that has been set most recently using the SetCaption() - method. - */ - CString GetCaption(HICON *pIcon = NULL) const; - - /** - Sets the text to display. - - This default implementation calls the SafeUpdateWindow() method - with the message rectangle, to force it to be redrawn. - */ - virtual void SetMsgText(LPCTSTR lpszMsg); - - /** - Returns the text currently displayed. - */ - CString GetMsgText() const; - - /** - Specifies the format to draw the text with, set by SetMsgText(). - - This default implementation calls the SafeUpdateWindow() method - with the message rectangle, to force it to be redrawn. - - @param dwFormat - Combination of the DT_* flags, specified by the Win32 function - DrawText(). - */ - virtual void SetMsgFormat(DWORD dwFormat); - - /** - Returns the format to draw the text with, set by SetMsgText(). - - @see SetMsgFormat() - */ - DWORD GetMsgFormat() const; - -// Overridable implementation helpers -protected: - /** - Draws the whole frame including caption (if enabled) and message. - - This method calculates the rectangles for the message area and - the caption area using the CalcMsgArea() and the CalcCaptionArea() - methods, draws then the caption calling the DrawCaption() method - (only if caption is enabled) and afterwards the message calling - the DrawMsg() method. - - You should call this method from the WM_PAINT-handler of your - derived class. - - @param pDc - Device context to draw in. - */ - virtual void Draw(CDC *pDc); - - /** - Calculates the area, the message, set by SetMsgText() should be - displayed in. The returned rectangle (client coordinates) will be - passed to DrawMsg(). - - This default implementation calls the CalcCaptionArea() method, - substracts the returned rectangle from the client area and returns - the result. - */ - virtual CRect CalcMsgArea(); - - /** - Draws the message with the specified format. - - This default implementation draws the given msg using the specified - properties. - - @param pDc - Device context to draw in. - @param rect - Rectangle to draw the message in. - @param lpszMsg - Message to draw. - @param dwFormat. - Combination of the DT_* flags, specified by the Win32 function - DrawText() to draw the message with. - */ - virtual void DrawMsg(CDC *pDc, CRect rect, LPCTSTR lpszMsg, DWORD dwFormat); - - /** - Calculates the caption area. The caption area is the rectangular - range, the current page's caption should be drawn in. - - The caption can be enabled or disabled using the ShowCaption() - method. This method should return an empty rect, if the caption - is disabled. If the caption is enabled the height of the rect - should be as large, as specified by the latest call to the - SetCaptionHeight() method. - - The rectangle, returned by this method will be passed to the - DrawCaption() method to draw the caption. - - If the caption is enabled currently, this default implementation - returns a rectangle, that has the width of the client area and - the height, specified by the latest call to SetCaptionHeight(), - starting and y-position 0. If the caption is disabled at the - moment, this method returns an empty rectangle with the width of - the client area. - */ - virtual CRect CalcCaptionArea(); - - /** - Draws the caption. - - This default implementation draws nothing. - - @param pDc - Device context to draw in. - @param rect - Rectangle to draw the caption in. - @param lpszCaption - Text to display in the caption. - @param hIcon - Icon to display in the caption. - */ - virtual void DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); - -// Implementation helpers -protected: - /** - If the m_hWnd property of the CWnd-object returend by GetWnd() - specifies a valid window, this method will invalidate the specified - rectangle, to schedule it for repaint, otherwise the method will - return without doing anything. - - @param lpRect - Pointer to the rectangular area, that should be marked for - repainting or NULL, if the whole client area should be marked - for repainting. - */ - void SafeUpdateWindow(LPCRECT lpRect = NULL); - -// Properties -private: - /** TRUE if the caption should be drawn, FALSE otherwise. */ - BOOL m_bShowCaption; - - /** Height of the caption in pixels, if it is enabled. */ - int m_nCaptionHeight; - - /** Text to display in the caption. */ - CString m_strCaption; - - /** - Icon to display in the caption or NULL if no icon should be - displayed. - */ - HICON m_hCaptionIcon; - - /** Message text to display. */ - CString m_strMsg; - - /** Style to use when drawing the message text m_strMsg. */ - DWORD m_dwMsgFormat; -}; - - -} //namespace TreePropSheet - - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_ +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + + +#if !defined(AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_) +#define AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +namespace TreePropSheet +{ + + +/** +An object of an CPropertyPageFrame-derived class is used by +CTreePropSheet to display a frame for the property pages. + +Derived classes have to implement at least the Create() and the +GetWnd() method, which +returns a pointer to the CWnd-obect of the window, that has been +created by the call to the Create() method. An implementation can +provide the CWnd-object by using it as a property or by deriving +from CWnd or a more specialiced class. This way has been choosen +instead of deriving CPropPageFrame from CWnd, to allow derived class +to derive from more specialized classes than CWnd +(i.e. CStatic, etc.). From the WM_PAINT-handler of your derived class +you have to call the Draw()-method. + +Most implementations will also implement the DrawCaption() and +DrawMsg() methods, to provide custom drawing functionality. + +@author Sven Wiegand +*/ +class /*AFX_EXT_CLASS*/ CPropPageFrame +{ +// Construction/Destruction +public: + CPropPageFrame(); + virtual ~CPropPageFrame(); + +// Operations +public: + /** + Has to create a window with the specified properties. + + @param dwWindowStyle + Standard window styles, to apply to the window to create. + @param rect + Position and size of the window to create. + @param pwndParent + Parent window. (Never be NULL). + @param nID + Window id. + + @return + TRUE on success, FALSE otherwise. + */ + virtual BOOL Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID) = 0; + + /** + Returns a pointer to the window object, that represents the frame. + */ + virtual CWnd* GetWnd() = 0; + + /** + Enables or disables page caption. + + This default implementation calls the SafeUpdateWindow() method + with the caption rectangle, to force it to be redrawn. + */ + virtual void ShowCaption(BOOL bEnable); + + /** + Returns TRUE if captions are enabled, FALSE otherwise. + */ + BOOL GetShowCaption() const; + + /** + Sets the height of the caption in pixels. This value is ignored + until the caption is enabled by ShowCaption(TRUE). + + This default implementation calls the SafeUpdateWindow() method + with the caption rectangle, to force it to be redrawn. + */ + virtual void SetCaptionHeight(int nCaptionHeight); + + /** + Returns the caption height, that has been most recently set by a + call to the SetCaptionHeight() method. + */ + int GetCaptionHeight() const; + + /** + Sets caption text an icon. + + This default implementation calls the SafeUpdateWindow() method + with the caption rectangle, to force it to be redrawn. + + @param lpszCaption + Text to display for the caption. + @param hIcon + Icon to display for the caption. + */ + virtual void SetCaption(LPCTSTR lpszCaption, HICON hIcon = NULL); + + /** + Returns the caption, that has been set most recently using the + SetCaption() method. + + @param pIcon + Pointer to a HICON variable, that should receive the handle of + the currently set icon or NULL, if there is no icon or a NULL + pointer, if the caller is not interested in the icon. + + @return + The text that has been set most recently using the SetCaption() + method. + */ + CString GetCaption(HICON *pIcon = NULL) const; + + /** + Sets the text to display. + + This default implementation calls the SafeUpdateWindow() method + with the message rectangle, to force it to be redrawn. + */ + virtual void SetMsgText(LPCTSTR lpszMsg); + + /** + Returns the text currently displayed. + */ + CString GetMsgText() const; + + /** + Specifies the format to draw the text with, set by SetMsgText(). + + This default implementation calls the SafeUpdateWindow() method + with the message rectangle, to force it to be redrawn. + + @param dwFormat + Combination of the DT_* flags, specified by the Win32 function + DrawText(). + */ + virtual void SetMsgFormat(DWORD dwFormat); + + /** + Returns the format to draw the text with, set by SetMsgText(). + + @see SetMsgFormat() + */ + DWORD GetMsgFormat() const; + +// Overridable implementation helpers +protected: + /** + Draws the whole frame including caption (if enabled) and message. + + This method calculates the rectangles for the message area and + the caption area using the CalcMsgArea() and the CalcCaptionArea() + methods, draws then the caption calling the DrawCaption() method + (only if caption is enabled) and afterwards the message calling + the DrawMsg() method. + + You should call this method from the WM_PAINT-handler of your + derived class. + + @param pDc + Device context to draw in. + */ + virtual void Draw(CDC *pDc); + + /** + Calculates the area, the message, set by SetMsgText() should be + displayed in. The returned rectangle (client coordinates) will be + passed to DrawMsg(). + + This default implementation calls the CalcCaptionArea() method, + substracts the returned rectangle from the client area and returns + the result. + */ + virtual CRect CalcMsgArea(); + + /** + Draws the message with the specified format. + + This default implementation draws the given msg using the specified + properties. + + @param pDc + Device context to draw in. + @param rect + Rectangle to draw the message in. + @param lpszMsg + Message to draw. + @param dwFormat. + Combination of the DT_* flags, specified by the Win32 function + DrawText() to draw the message with. + */ + virtual void DrawMsg(CDC *pDc, CRect rect, LPCTSTR lpszMsg, DWORD dwFormat); + + /** + Calculates the caption area. The caption area is the rectangular + range, the current page's caption should be drawn in. + + The caption can be enabled or disabled using the ShowCaption() + method. This method should return an empty rect, if the caption + is disabled. If the caption is enabled the height of the rect + should be as large, as specified by the latest call to the + SetCaptionHeight() method. + + The rectangle, returned by this method will be passed to the + DrawCaption() method to draw the caption. + + If the caption is enabled currently, this default implementation + returns a rectangle, that has the width of the client area and + the height, specified by the latest call to SetCaptionHeight(), + starting and y-position 0. If the caption is disabled at the + moment, this method returns an empty rectangle with the width of + the client area. + */ + virtual CRect CalcCaptionArea(); + + /** + Draws the caption. + + This default implementation draws nothing. + + @param pDc + Device context to draw in. + @param rect + Rectangle to draw the caption in. + @param lpszCaption + Text to display in the caption. + @param hIcon + Icon to display in the caption. + */ + virtual void DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); + +// Implementation helpers +protected: + /** + If the m_hWnd property of the CWnd-object returend by GetWnd() + specifies a valid window, this method will invalidate the specified + rectangle, to schedule it for repaint, otherwise the method will + return without doing anything. + + @param lpRect + Pointer to the rectangular area, that should be marked for + repainting or NULL, if the whole client area should be marked + for repainting. + */ + void SafeUpdateWindow(LPCRECT lpRect = NULL); + +// Properties +private: + /** TRUE if the caption should be drawn, FALSE otherwise. */ + BOOL m_bShowCaption; + + /** Height of the caption in pixels, if it is enabled. */ + int m_nCaptionHeight; + + /** Text to display in the caption. */ + CString m_strCaption; + + /** + Icon to display in the caption or NULL if no icon should be + displayed. + */ + HICON m_hCaptionIcon; + + /** Message text to display. */ + CString m_strMsg; + + /** Style to use when drawing the message text m_strMsg. */ + DWORD m_dwMsgFormat; +}; + + +} //namespace TreePropSheet + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_ diff --git a/src/thirdparty/TreePropSheet/PropPageFrameDefault.cpp b/src/thirdparty/TreePropSheet/PropPageFrameDefault.cpp index 4b6ca3268c1..37f12acec7d 100644 --- a/src/thirdparty/TreePropSheet/PropPageFrameDefault.cpp +++ b/src/thirdparty/TreePropSheet/PropPageFrameDefault.cpp @@ -1,410 +1,410 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - -#include "stdafx.h" -#include "PropPageFrameDefault.h" -// -#include "../../DSUtil/WinAPIUtils.h" -// - - -namespace TreePropSheet -{ - -#include -#include - -//------------------------------------------------------------------- -// class CThemeLib -//------------------------------------------------------------------- - - -/** -Helper class for loading the uxtheme DLL and providing their -functions. - -One global object of this class exists. - -@author Sven Wiegand -*/ -class CThemeLib -{ -// construction/destruction -public: - CThemeLib(); - ~CThemeLib(); - -// operations -public: - /** - Returns TRUE if the call wrappers are available, FALSE otherwise. - */ - BOOL IsAvailable() const; - -// call wrappers -public: - BOOL IsThemeActive() const - {return (*m_pIsThemeActive)();} - - HTHEME OpenThemeData(HWND hwnd, LPCWSTR pszClassList) const - {return (*m_pOpenThemeData)(hwnd, pszClassList);} - - HRESULT CloseThemeData(HTHEME hTheme) const - {return (*m_pCloseThemeData)(hTheme);} - - HRESULT GetThemeBackgroundContentRect(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, OUT RECT *pContentRect) const - {return (*m_pGetThemeBackgroundContentRect)(hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect);} - - HRESULT DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect) const - {return (*m_pDrawThemeBackground)(hTheme, hdc, iPartId, iStateId, pRect, pClipRect);} - - HRESULT DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, UINT uEdge, UINT uFlags, OPTIONAL const RECT * pContentRect) const - {return (*m_pDrawThemeEdge)(hTheme, hdc, iPartId, iStateId, pRect, uEdge, uFlags, pContentRect);} - -// function pointers -private: - typedef BOOL (__stdcall *_IsThemeActive)(); - _IsThemeActive m_pIsThemeActive; - - typedef HTHEME (__stdcall *_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList); - _OpenThemeData m_pOpenThemeData; - - typedef HRESULT(__stdcall *_CloseThemeData)(HTHEME hTheme); - _CloseThemeData m_pCloseThemeData; - - typedef HRESULT(__stdcall *_GetThemeBackgroundContentRect)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, OUT RECT *pContentRect); - _GetThemeBackgroundContentRect m_pGetThemeBackgroundContentRect; - - typedef HRESULT(__stdcall* _DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, OPTIONAL const RECT* pClipRect); - _DrawThemeBackground m_pDrawThemeBackground; - - typedef HRESULT(__stdcall* _DrawThemeEdge)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, UINT uEdge, UINT uFlags, OPTIONAL const RECT* pContentRect); - _DrawThemeEdge m_pDrawThemeEdge; - -// properties -private: - /** instance handle to the library or NULL. */ - HINSTANCE m_hThemeLib; -}; - -/** -One and only instance of CThemeLib. -*/ -static CThemeLib g_ThemeLib; - - -CThemeLib::CThemeLib() - : m_pIsThemeActive(NULL) - , m_pOpenThemeData(NULL) - , m_pCloseThemeData(NULL) - , m_pGetThemeBackgroundContentRect(NULL) - , m_pDrawThemeBackground(NULL) - , m_hThemeLib(NULL) -{ - m_hThemeLib = LoadLibrary(_T("uxtheme.dll")); - if (!m_hThemeLib) - return; - - m_pIsThemeActive = (_IsThemeActive)GetProcAddress(m_hThemeLib, "IsThemeActive"); - m_pOpenThemeData = (_OpenThemeData)GetProcAddress(m_hThemeLib, "OpenThemeData"); - m_pCloseThemeData = (_CloseThemeData)GetProcAddress(m_hThemeLib, "CloseThemeData"); - m_pGetThemeBackgroundContentRect = (_GetThemeBackgroundContentRect)GetProcAddress(m_hThemeLib, "GetThemeBackgroundContentRect"); - m_pDrawThemeBackground = (_DrawThemeBackground)GetProcAddress(m_hThemeLib, "DrawThemeBackground"); - m_pDrawThemeEdge = (_DrawThemeEdge)GetProcAddress(m_hThemeLib, "DrawThemeEdge"); -} - - -CThemeLib::~CThemeLib() -{ - if (m_hThemeLib) - FreeLibrary(m_hThemeLib); -} - - -BOOL CThemeLib::IsAvailable() const -{ - return m_hThemeLib!=NULL; -} - - -//------------------------------------------------------------------- -// class CPropPageFrameDefault -//------------------------------------------------------------------- - -BEGIN_MESSAGE_MAP(CPropPageFrameDefault, CWnd) - //{{AFX_MSG_MAP(CPropPageFrameDefault) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - - -CPropPageFrameDefault::CPropPageFrameDefault() -{ -} - - -CPropPageFrameDefault::~CPropPageFrameDefault() -{ - if (m_Images.GetSafeHandle()) - m_Images.DeleteImageList(); -} - - -///////////////////////////////////////////////////////////////////// -// Overridings - -BOOL CPropPageFrameDefault::Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID) -{ - return CWnd::Create( - AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), GetSysColorBrush(COLOR_3DFACE)), - _T("Page Frame"), - dwWindowStyle, rect, pwndParent, nID); -} - - -CWnd* CPropPageFrameDefault::GetWnd() -{ - return static_cast(this); -} - - -void CPropPageFrameDefault::SetCaption(LPCTSTR lpszCaption, HICON hIcon /*= NULL*/) -{ - CPropPageFrame::SetCaption(lpszCaption, hIcon); - - // build image list - if (m_Images.GetSafeHandle()) - m_Images.DeleteImageList(); - if (hIcon) - { - ICONINFO ii; - if (!GetIconInfo(hIcon, &ii)) - return; - - CBitmap bmMask; - bmMask.Attach(ii.hbmMask); - if (ii.hbmColor) DeleteObject(ii.hbmColor); - - BITMAP bm; - bmMask.GetBitmap(&bm); - - if (!m_Images.Create(bm.bmWidth, bm.bmHeight, ILC_COLOR32|ILC_MASK, 0, 1)) - return; - - if (m_Images.Add(hIcon) == -1) - m_Images.DeleteImageList(); - } -} - - -CRect CPropPageFrameDefault::CalcMsgArea() -{ - CRect rect; - GetClientRect(rect); - if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) - { - HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); - if (hTheme) - { - CRect rectContent; - CDC *pDc = GetDC(); - g_ThemeLib.GetThemeBackgroundContentRect(hTheme, pDc->m_hDC, TABP_PANE, 0, rect, rectContent); - ReleaseDC(pDc); - g_ThemeLib.CloseThemeData(hTheme); - - if (GetShowCaption()) - rectContent.top = rect.top+GetCaptionHeight()+1; - rect = rectContent; - } - } - else if (GetShowCaption()) - rect.top+= GetCaptionHeight()+1; - - return rect; -} - - -CRect CPropPageFrameDefault::CalcCaptionArea() -{ - CRect rect; - GetClientRect(rect); - if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) - { - HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); - if (hTheme) - { - CRect rectContent; - CDC *pDc = GetDC(); - g_ThemeLib.GetThemeBackgroundContentRect(hTheme, pDc->m_hDC, TABP_PANE, 0, rect, rectContent); - ReleaseDC(pDc); - g_ThemeLib.CloseThemeData(hTheme); - - if (GetShowCaption()) - rectContent.bottom = rect.top+GetCaptionHeight(); - else - rectContent.bottom = rectContent.top; - - rect = rectContent; - } - } - else - { - if (GetShowCaption()) - rect.bottom = rect.top+GetCaptionHeight(); - else - rect.bottom = rect.top; - } - - return rect; -} - -void CPropPageFrameDefault::DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon) -{ - // - COLORREF clrLeft = GetSysColor(COLOR_ACTIVECAPTION); - // - COLORREF clrRight = pDc->GetPixel(rect.right-1, rect.top); - FillGradientRectH(pDc, rect, clrLeft, clrRight); - - // draw icon - if (hIcon && m_Images.GetSafeHandle() && m_Images.GetImageCount() == 1) - { - IMAGEINFO ii; - m_Images.GetImageInfo(0, &ii); - CPoint pt(3, rect.CenterPoint().y - (ii.rcImage.bottom-ii.rcImage.top)/2); - m_Images.Draw(pDc, 0, pt, ILD_TRANSPARENT); - rect.left+= (ii.rcImage.right-ii.rcImage.left) + 3; - } - - // draw text - rect.left+= 2; - - COLORREF clrPrev = pDc->SetTextColor(GetSysColor(COLOR_CAPTIONTEXT)); - int nBkStyle = pDc->SetBkMode(TRANSPARENT); - CFont *pFont = (CFont*)pDc->SelectStockObject(SYSTEM_FONT); - -// - LOGFONT lf; - GetMessageFont(&lf); - lf.lfHeight = static_cast(-.8f * rect.Height()); - lf.lfWeight = FW_BOLD; - CFont f; - f.CreateFontIndirectW(&lf); - pFont = pDc->SelectObject(&f); - - TEXTMETRIC GDIMetrics; - GetTextMetricsW(pDc->GetSafeHdc(), &GDIMetrics); - while (GDIMetrics.tmHeight > rect.Height() && abs(lf.lfHeight) > 10) { - pDc->SelectObject(pFont); - f.DeleteObject(); - lf.lfHeight++; - f.CreateFontIndirectW(&lf); - pDc->SelectObject(&f); - GetTextMetricsW(pDc->GetSafeHdc(), &GDIMetrics); - } - - rect.top -= GDIMetrics.tmDescent - 1; -// CFont f; -// f.CreateFontIndirect(&lf); -// pDc->SelectObject(&f); - pDc->DrawText(lpszCaption, rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); -// - - - pDc->SetTextColor(clrPrev); - pDc->SetBkMode(nBkStyle); - pDc->SelectObject(pFont); -} - - -///////////////////////////////////////////////////////////////////// -// Implementation helpers - -void CPropPageFrameDefault::FillGradientRectH(CDC *pDc, const RECT &rect, COLORREF clrLeft, COLORREF clrRight) -{ - // pre calculation - int nSteps = rect.right-rect.left; - int nRRange = GetRValue(clrRight)-GetRValue(clrLeft); - int nGRange = GetGValue(clrRight)-GetGValue(clrLeft); - int nBRange = GetBValue(clrRight)-GetBValue(clrLeft); - - double dRStep = (double)nRRange/(double)nSteps; - double dGStep = (double)nGRange/(double)nSteps; - double dBStep = (double)nBRange/(double)nSteps; - - double dR = (double)GetRValue(clrLeft); - double dG = (double)GetGValue(clrLeft); - double dB = (double)GetBValue(clrLeft); - - CPen *pPrevPen = NULL; - for (int x = rect.left; x <= rect.right; ++x) - { - CPen Pen(PS_SOLID, 1, RGB((BYTE)dR, (BYTE)dG, (BYTE)dB)); - pPrevPen = pDc->SelectObject(&Pen); - pDc->MoveTo(x, rect.top); - pDc->LineTo(x, rect.bottom); - pDc->SelectObject(pPrevPen); - - dR+= dRStep; - dG+= dGStep; - dB+= dBStep; - } -} - - -///////////////////////////////////////////////////////////////////// -// message handlers - -void CPropPageFrameDefault::OnPaint() -{ - CPaintDC dc(this); - Draw(&dc); -} - - -BOOL CPropPageFrameDefault::OnEraseBkgnd(CDC* pDC) -{ - if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) - { - HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); - if (hTheme) - { - CRect rect; - GetClientRect(rect); - //g_ThemeLib.DrawThemeBackground(hTheme, pDC->m_hDC, TABP_PANE, 0, rect, NULL); - - //mpc-hc: TABP_PANE draws a border 1 pixel short of bottom, and two pixels short of right. - //instead we fill using TABP_BODY and draw the edge separately (using BDR_SUNKENOUTER for 1 pixel only) - g_ThemeLib.DrawThemeBackground(hTheme, pDC->m_hDC, TABP_BODY, 0, rect, NULL); - g_ThemeLib.DrawThemeEdge(hTheme, pDC->m_hDC, TABP_BODY, 0, rect, BDR_SUNKENOUTER, BF_FLAT | BF_RECT, NULL); - - g_ThemeLib.CloseThemeData(hTheme); - } - return TRUE; - } - else - { - return CWnd::OnEraseBkgnd(pDC); - } -} - - - -} //namespace TreePropSheet +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + +#include "stdafx.h" +#include "PropPageFrameDefault.h" +// +#include "../../DSUtil/WinAPIUtils.h" +// + + +namespace TreePropSheet +{ + +#include +#include + +//------------------------------------------------------------------- +// class CThemeLib +//------------------------------------------------------------------- + + +/** +Helper class for loading the uxtheme DLL and providing their +functions. + +One global object of this class exists. + +@author Sven Wiegand +*/ +class CThemeLib +{ +// construction/destruction +public: + CThemeLib(); + ~CThemeLib(); + +// operations +public: + /** + Returns TRUE if the call wrappers are available, FALSE otherwise. + */ + BOOL IsAvailable() const; + +// call wrappers +public: + BOOL IsThemeActive() const + {return (*m_pIsThemeActive)();} + + HTHEME OpenThemeData(HWND hwnd, LPCWSTR pszClassList) const + {return (*m_pOpenThemeData)(hwnd, pszClassList);} + + HRESULT CloseThemeData(HTHEME hTheme) const + {return (*m_pCloseThemeData)(hTheme);} + + HRESULT GetThemeBackgroundContentRect(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, OUT RECT *pContentRect) const + {return (*m_pGetThemeBackgroundContentRect)(hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect);} + + HRESULT DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect) const + {return (*m_pDrawThemeBackground)(hTheme, hdc, iPartId, iStateId, pRect, pClipRect);} + + HRESULT DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, UINT uEdge, UINT uFlags, OPTIONAL const RECT * pContentRect) const + {return (*m_pDrawThemeEdge)(hTheme, hdc, iPartId, iStateId, pRect, uEdge, uFlags, pContentRect);} + +// function pointers +private: + typedef BOOL (__stdcall *_IsThemeActive)(); + _IsThemeActive m_pIsThemeActive; + + typedef HTHEME (__stdcall *_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList); + _OpenThemeData m_pOpenThemeData; + + typedef HRESULT(__stdcall *_CloseThemeData)(HTHEME hTheme); + _CloseThemeData m_pCloseThemeData; + + typedef HRESULT(__stdcall *_GetThemeBackgroundContentRect)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, OUT RECT *pContentRect); + _GetThemeBackgroundContentRect m_pGetThemeBackgroundContentRect; + + typedef HRESULT(__stdcall* _DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, OPTIONAL const RECT* pClipRect); + _DrawThemeBackground m_pDrawThemeBackground; + + typedef HRESULT(__stdcall* _DrawThemeEdge)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, UINT uEdge, UINT uFlags, OPTIONAL const RECT* pContentRect); + _DrawThemeEdge m_pDrawThemeEdge; + +// properties +private: + /** instance handle to the library or NULL. */ + HINSTANCE m_hThemeLib; +}; + +/** +One and only instance of CThemeLib. +*/ +static CThemeLib g_ThemeLib; + + +CThemeLib::CThemeLib() + : m_pIsThemeActive(NULL) + , m_pOpenThemeData(NULL) + , m_pCloseThemeData(NULL) + , m_pGetThemeBackgroundContentRect(NULL) + , m_pDrawThemeBackground(NULL) + , m_hThemeLib(NULL) +{ + m_hThemeLib = LoadLibrary(_T("uxtheme.dll")); + if (!m_hThemeLib) + return; + + m_pIsThemeActive = (_IsThemeActive)GetProcAddress(m_hThemeLib, "IsThemeActive"); + m_pOpenThemeData = (_OpenThemeData)GetProcAddress(m_hThemeLib, "OpenThemeData"); + m_pCloseThemeData = (_CloseThemeData)GetProcAddress(m_hThemeLib, "CloseThemeData"); + m_pGetThemeBackgroundContentRect = (_GetThemeBackgroundContentRect)GetProcAddress(m_hThemeLib, "GetThemeBackgroundContentRect"); + m_pDrawThemeBackground = (_DrawThemeBackground)GetProcAddress(m_hThemeLib, "DrawThemeBackground"); + m_pDrawThemeEdge = (_DrawThemeEdge)GetProcAddress(m_hThemeLib, "DrawThemeEdge"); +} + + +CThemeLib::~CThemeLib() +{ + if (m_hThemeLib) + FreeLibrary(m_hThemeLib); +} + + +BOOL CThemeLib::IsAvailable() const +{ + return m_hThemeLib!=NULL; +} + + +//------------------------------------------------------------------- +// class CPropPageFrameDefault +//------------------------------------------------------------------- + +BEGIN_MESSAGE_MAP(CPropPageFrameDefault, CWnd) + //{{AFX_MSG_MAP(CPropPageFrameDefault) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +CPropPageFrameDefault::CPropPageFrameDefault() +{ +} + + +CPropPageFrameDefault::~CPropPageFrameDefault() +{ + if (m_Images.GetSafeHandle()) + m_Images.DeleteImageList(); +} + + +///////////////////////////////////////////////////////////////////// +// Overridings + +BOOL CPropPageFrameDefault::Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID) +{ + return CWnd::Create( + AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), GetSysColorBrush(COLOR_3DFACE)), + _T("Page Frame"), + dwWindowStyle, rect, pwndParent, nID); +} + + +CWnd* CPropPageFrameDefault::GetWnd() +{ + return static_cast(this); +} + + +void CPropPageFrameDefault::SetCaption(LPCTSTR lpszCaption, HICON hIcon /*= NULL*/) +{ + CPropPageFrame::SetCaption(lpszCaption, hIcon); + + // build image list + if (m_Images.GetSafeHandle()) + m_Images.DeleteImageList(); + if (hIcon) + { + ICONINFO ii; + if (!GetIconInfo(hIcon, &ii)) + return; + + CBitmap bmMask; + bmMask.Attach(ii.hbmMask); + if (ii.hbmColor) DeleteObject(ii.hbmColor); + + BITMAP bm; + bmMask.GetBitmap(&bm); + + if (!m_Images.Create(bm.bmWidth, bm.bmHeight, ILC_COLOR32|ILC_MASK, 0, 1)) + return; + + if (m_Images.Add(hIcon) == -1) + m_Images.DeleteImageList(); + } +} + + +CRect CPropPageFrameDefault::CalcMsgArea() +{ + CRect rect; + GetClientRect(rect); + if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) + { + HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); + if (hTheme) + { + CRect rectContent; + CDC *pDc = GetDC(); + g_ThemeLib.GetThemeBackgroundContentRect(hTheme, pDc->m_hDC, TABP_PANE, 0, rect, rectContent); + ReleaseDC(pDc); + g_ThemeLib.CloseThemeData(hTheme); + + if (GetShowCaption()) + rectContent.top = rect.top+GetCaptionHeight()+1; + rect = rectContent; + } + } + else if (GetShowCaption()) + rect.top+= GetCaptionHeight()+1; + + return rect; +} + + +CRect CPropPageFrameDefault::CalcCaptionArea() +{ + CRect rect; + GetClientRect(rect); + if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) + { + HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); + if (hTheme) + { + CRect rectContent; + CDC *pDc = GetDC(); + g_ThemeLib.GetThemeBackgroundContentRect(hTheme, pDc->m_hDC, TABP_PANE, 0, rect, rectContent); + ReleaseDC(pDc); + g_ThemeLib.CloseThemeData(hTheme); + + if (GetShowCaption()) + rectContent.bottom = rect.top+GetCaptionHeight(); + else + rectContent.bottom = rectContent.top; + + rect = rectContent; + } + } + else + { + if (GetShowCaption()) + rect.bottom = rect.top+GetCaptionHeight(); + else + rect.bottom = rect.top; + } + + return rect; +} + +void CPropPageFrameDefault::DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon) +{ + // + COLORREF clrLeft = GetSysColor(COLOR_ACTIVECAPTION); + // + COLORREF clrRight = pDc->GetPixel(rect.right-1, rect.top); + FillGradientRectH(pDc, rect, clrLeft, clrRight); + + // draw icon + if (hIcon && m_Images.GetSafeHandle() && m_Images.GetImageCount() == 1) + { + IMAGEINFO ii; + m_Images.GetImageInfo(0, &ii); + CPoint pt(3, rect.CenterPoint().y - (ii.rcImage.bottom-ii.rcImage.top)/2); + m_Images.Draw(pDc, 0, pt, ILD_TRANSPARENT); + rect.left+= (ii.rcImage.right-ii.rcImage.left) + 3; + } + + // draw text + rect.left+= 2; + + COLORREF clrPrev = pDc->SetTextColor(GetSysColor(COLOR_CAPTIONTEXT)); + int nBkStyle = pDc->SetBkMode(TRANSPARENT); + CFont *pFont = (CFont*)pDc->SelectStockObject(SYSTEM_FONT); + +// + LOGFONT lf; + GetMessageFont(&lf); + lf.lfHeight = static_cast(-.8f * rect.Height()); + lf.lfWeight = FW_BOLD; + CFont f; + f.CreateFontIndirectW(&lf); + pFont = pDc->SelectObject(&f); + + TEXTMETRIC GDIMetrics; + GetTextMetricsW(pDc->GetSafeHdc(), &GDIMetrics); + while (GDIMetrics.tmHeight > rect.Height() && abs(lf.lfHeight) > 10) { + pDc->SelectObject(pFont); + f.DeleteObject(); + lf.lfHeight++; + f.CreateFontIndirectW(&lf); + pDc->SelectObject(&f); + GetTextMetricsW(pDc->GetSafeHdc(), &GDIMetrics); + } + + rect.top -= GDIMetrics.tmDescent - 1; +// CFont f; +// f.CreateFontIndirect(&lf); +// pDc->SelectObject(&f); + pDc->DrawText(lpszCaption, rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); +// + + + pDc->SetTextColor(clrPrev); + pDc->SetBkMode(nBkStyle); + pDc->SelectObject(pFont); +} + + +///////////////////////////////////////////////////////////////////// +// Implementation helpers + +void CPropPageFrameDefault::FillGradientRectH(CDC *pDc, const RECT &rect, COLORREF clrLeft, COLORREF clrRight) +{ + // pre calculation + int nSteps = rect.right-rect.left; + int nRRange = GetRValue(clrRight)-GetRValue(clrLeft); + int nGRange = GetGValue(clrRight)-GetGValue(clrLeft); + int nBRange = GetBValue(clrRight)-GetBValue(clrLeft); + + double dRStep = (double)nRRange/(double)nSteps; + double dGStep = (double)nGRange/(double)nSteps; + double dBStep = (double)nBRange/(double)nSteps; + + double dR = (double)GetRValue(clrLeft); + double dG = (double)GetGValue(clrLeft); + double dB = (double)GetBValue(clrLeft); + + CPen *pPrevPen = NULL; + for (int x = rect.left; x <= rect.right; ++x) + { + CPen Pen(PS_SOLID, 1, RGB((BYTE)dR, (BYTE)dG, (BYTE)dB)); + pPrevPen = pDc->SelectObject(&Pen); + pDc->MoveTo(x, rect.top); + pDc->LineTo(x, rect.bottom); + pDc->SelectObject(pPrevPen); + + dR+= dRStep; + dG+= dGStep; + dB+= dBStep; + } +} + + +///////////////////////////////////////////////////////////////////// +// message handlers + +void CPropPageFrameDefault::OnPaint() +{ + CPaintDC dc(this); + Draw(&dc); +} + + +BOOL CPropPageFrameDefault::OnEraseBkgnd(CDC* pDC) +{ + if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) + { + HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); + if (hTheme) + { + CRect rect; + GetClientRect(rect); + //g_ThemeLib.DrawThemeBackground(hTheme, pDC->m_hDC, TABP_PANE, 0, rect, NULL); + + //mpc-hc: TABP_PANE draws a border 1 pixel short of bottom, and two pixels short of right. + //instead we fill using TABP_BODY and draw the edge separately (using BDR_SUNKENOUTER for 1 pixel only) + g_ThemeLib.DrawThemeBackground(hTheme, pDC->m_hDC, TABP_BODY, 0, rect, NULL); + g_ThemeLib.DrawThemeEdge(hTheme, pDC->m_hDC, TABP_BODY, 0, rect, BDR_SUNKENOUTER, BF_FLAT | BF_RECT, NULL); + + g_ThemeLib.CloseThemeData(hTheme); + } + return TRUE; + } + else + { + return CWnd::OnEraseBkgnd(pDC); + } +} + + + +} //namespace TreePropSheet diff --git a/src/thirdparty/TreePropSheet/PropPageFrameDefault.h b/src/thirdparty/TreePropSheet/PropPageFrameDefault.h index 883a696ae74..ce9c576f5fb 100644 --- a/src/thirdparty/TreePropSheet/PropPageFrameDefault.h +++ b/src/thirdparty/TreePropSheet/PropPageFrameDefault.h @@ -1,117 +1,117 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - - -#if !defined(AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_) -#define AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include "PropPageFrame.h" - - -namespace TreePropSheet -{ - - -/** -An implementation of CPropPageFrame, that works well for Windows XP -styled systems and older windows versions (without themes). - -@author Sven Wiegand -*/ -class /*AFX_EXT_CLASS*/ CPropPageFrameDefault : public CWnd, - public CPropPageFrame -{ -// construction/destruction -public: - CPropPageFrameDefault(); - virtual ~CPropPageFrameDefault(); - -// operations -public: - -// overridings -public: - virtual BOOL Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID); - virtual CWnd* GetWnd(); - virtual void SetCaption(LPCTSTR lpszCaption, HICON hIcon = NULL); - -protected: - virtual CRect CalcMsgArea(); - virtual CRect CalcCaptionArea(); - virtual void DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); - -// Implementation helpers -protected: - /** - Fills a rectangular area with a gradient color starting at the left - side with the color clrLeft and ending at the right sight with the - color clrRight. - - @param pDc - Device context to draw the rectangle in. - @param rect - Rectangular area to fill. - @param clrLeft - Color on the left side. - @param clrRight - Color on the right side. - */ - void FillGradientRectH(CDC *pDc, const RECT &rect, COLORREF clrLeft, COLORREF clrRight); - - /** - Returns TRUE if Windows XP theme support is available, FALSE - otherwise. - */ - BOOL ThemeSupport() const; - -protected: - //{{AFX_VIRTUAL(CPropPageFrameDefault) - //}}AFX_VIRTUAL - -// message handlers -protected: - //{{AFX_MSG(CPropPageFrameDefault) - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() - -// attributes -protected: - /** - Image list that contains only the current icon or nothing if there - is no icon. - */ - CImageList m_Images; -}; - - -} //namespace TreePropSheet - - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_ +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + + +#if !defined(AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_) +#define AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "PropPageFrame.h" + + +namespace TreePropSheet +{ + + +/** +An implementation of CPropPageFrame, that works well for Windows XP +styled systems and older windows versions (without themes). + +@author Sven Wiegand +*/ +class /*AFX_EXT_CLASS*/ CPropPageFrameDefault : public CWnd, + public CPropPageFrame +{ +// construction/destruction +public: + CPropPageFrameDefault(); + virtual ~CPropPageFrameDefault(); + +// operations +public: + +// overridings +public: + virtual BOOL Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID); + virtual CWnd* GetWnd(); + virtual void SetCaption(LPCTSTR lpszCaption, HICON hIcon = NULL); + +protected: + virtual CRect CalcMsgArea(); + virtual CRect CalcCaptionArea(); + virtual void DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); + +// Implementation helpers +protected: + /** + Fills a rectangular area with a gradient color starting at the left + side with the color clrLeft and ending at the right sight with the + color clrRight. + + @param pDc + Device context to draw the rectangle in. + @param rect + Rectangular area to fill. + @param clrLeft + Color on the left side. + @param clrRight + Color on the right side. + */ + void FillGradientRectH(CDC *pDc, const RECT &rect, COLORREF clrLeft, COLORREF clrRight); + + /** + Returns TRUE if Windows XP theme support is available, FALSE + otherwise. + */ + BOOL ThemeSupport() const; + +protected: + //{{AFX_VIRTUAL(CPropPageFrameDefault) + //}}AFX_VIRTUAL + +// message handlers +protected: + //{{AFX_MSG(CPropPageFrameDefault) + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +// attributes +protected: + /** + Image list that contains only the current icon or nothing if there + is no icon. + */ + CImageList m_Images; +}; + + +} //namespace TreePropSheet + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_ diff --git a/src/thirdparty/TreePropSheet/TreePropSheet.cpp b/src/thirdparty/TreePropSheet/TreePropSheet.cpp index 40d7ba02e8e..0d493646290 100644 --- a/src/thirdparty/TreePropSheet/TreePropSheet.cpp +++ b/src/thirdparty/TreePropSheet/TreePropSheet.cpp @@ -1,1000 +1,1000 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - - -#include "stdafx.h" -#include "TreePropSheet.h" -#include "PropPageFrameDefault.h" -#include "../../../src/mpc-hc/DpiHelper.h" -#include "../../../src/DSUtil/VersionHelpersInternal.h" - -namespace TreePropSheet -{ - -//------------------------------------------------------------------- -// class CTreePropSheet -//------------------------------------------------------------------- - -BEGIN_MESSAGE_MAP(CTreePropSheet, CPropertySheet) - //{{AFX_MSG_MAP(CTreePropSheet) - ON_WM_DESTROY() - //}}AFX_MSG_MAP - ON_MESSAGE(PSM_ADDPAGE, OnAddPage) - ON_MESSAGE(PSM_REMOVEPAGE, OnRemovePage) - ON_MESSAGE(PSM_SETCURSEL, OnSetCurSel) - ON_MESSAGE(PSM_SETCURSELID, OnSetCurSelId) - ON_MESSAGE(PSM_ISDIALOGMESSAGE, OnIsDialogMessage) - - ON_NOTIFY(TVN_SELCHANGINGA, s_unPageTreeId, OnPageTreeSelChanging) - ON_NOTIFY(TVN_SELCHANGINGW, s_unPageTreeId, OnPageTreeSelChanging) - ON_NOTIFY(TVN_SELCHANGEDA, s_unPageTreeId, OnPageTreeSelChanged) - ON_NOTIFY(TVN_SELCHANGEDW, s_unPageTreeId, OnPageTreeSelChanged) -END_MESSAGE_MAP() - -IMPLEMENT_DYNAMIC(CTreePropSheet, CPropertySheet) - -const UINT CTreePropSheet::s_unPageTreeId = 0x7EEE; - -CTreePropSheet::CTreePropSheet() -: CPropertySheet(), - m_bTreeViewMode(TRUE), - m_pwndPageTree(NULL), - m_pFrame(NULL), - m_bPageTreeSelChangedActive(FALSE), - m_bPageCaption(FALSE), - m_bTreeImages(FALSE), - m_nPageTreeWidth(150) -{ -} - - -CTreePropSheet::CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) -: CPropertySheet(nIDCaption, pParentWnd, iSelectPage), - m_bTreeViewMode(TRUE), - m_pwndPageTree(NULL), - m_pFrame(NULL), - m_bPageTreeSelChangedActive(FALSE), - m_bPageCaption(FALSE), - m_bTreeImages(FALSE), - m_nPageTreeWidth(150) -{ -} - - -CTreePropSheet::CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) -: CPropertySheet(pszCaption, pParentWnd, iSelectPage), - m_bTreeViewMode(TRUE), - m_pwndPageTree(NULL), - m_pFrame(NULL), - m_bPageTreeSelChangedActive(FALSE), - m_bPageCaption(FALSE), - m_bTreeImages(FALSE), - m_nPageTreeWidth(150) -{ -} - - -CTreePropSheet::~CTreePropSheet() -{ -} - - -///////////////////////////////////////////////////////////////////// -// Operationen - -BOOL CTreePropSheet::SetTreeViewMode(BOOL bTreeViewMode /* = TRUE */, BOOL bPageCaption /* = FALSE */, BOOL bTreeImages /* = FALSE */) -{ - if (IsWindow(m_hWnd)) - { - // needs to becalled, before the window has been created - ASSERT(FALSE); - return FALSE; - } - - m_bTreeViewMode = bTreeViewMode; - if (m_bTreeViewMode) - { - m_bPageCaption = bPageCaption; - m_bTreeImages = bTreeImages; - } - - return TRUE; -} - - -BOOL CTreePropSheet::SetTreeWidth(int nWidth) -{ - if (IsWindow(m_hWnd)) - { - // needs to be called, before the window is created. - ASSERT(FALSE); - return FALSE; - } - - m_nPageTreeWidth = nWidth; - - return TRUE; -} - - -void CTreePropSheet::SetEmptyPageText(LPCTSTR lpszEmptyPageText) -{ - m_strEmptyPageMessage = lpszEmptyPageText; -} - - -DWORD CTreePropSheet::SetEmptyPageTextFormat(DWORD dwFormat) -{ - DWORD dwPrevFormat = m_pFrame->GetMsgFormat(); - m_pFrame->SetMsgFormat(dwFormat); - return dwPrevFormat; -} - - -BOOL CTreePropSheet::SetTreeDefaultImages(CImageList *pImages) -{ - if (pImages->GetImageCount() != 2) - { - ASSERT(FALSE); - return FALSE; - } - - if (m_DefaultImages.GetSafeHandle()) - m_DefaultImages.DeleteImageList(); - m_DefaultImages.Create(pImages); - - // update, if necessary - if (IsWindow(m_hWnd)) - RefillPageTree(); - - return TRUE; -} - - -BOOL CTreePropSheet::SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask) -{ - if (m_DefaultImages.GetSafeHandle()) - m_DefaultImages.DeleteImageList(); - if (!m_DefaultImages.Create(unBitmapID, cx, 0, crMask)) - return FALSE; - - if (m_DefaultImages.GetImageCount() != 2) - { - m_DefaultImages.DeleteImageList(); - return FALSE; - } - - return TRUE; -} - - -CTreeCtrl* CTreePropSheet::GetPageTreeControl() -{ - return m_pwndPageTree; -} - - -///////////////////////////////////////////////////////////////////// -// public helpers - -BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, HICON hIcon) -{ - pPage->m_psp.dwFlags|= PSP_USEHICON; - pPage->m_psp.hIcon = hIcon; - return TRUE; -} - - -BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, UINT unIconId) -{ - HICON hIcon = AfxGetApp()->LoadIcon(unIconId); - if (!hIcon) - return FALSE; - - return SetPageIcon(pPage, hIcon); -} - - -BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage) -{ - HICON hIcon = Images.ExtractIcon(nImage); - if (!hIcon) - return FALSE; - - return SetPageIcon(pPage, hIcon); -} - - -BOOL CTreePropSheet::DestroyPageIcon(CPropertyPage *pPage) -{ - if (!pPage || !(pPage->m_psp.dwFlags&PSP_USEHICON) || !pPage->m_psp.hIcon) - return FALSE; - - DestroyIcon(pPage->m_psp.hIcon); - pPage->m_psp.dwFlags&= ~PSP_USEHICON; - pPage->m_psp.hIcon = NULL; - - return TRUE; -} - - -///////////////////////////////////////////////////////////////////// -// Overridable implementation helpers - -CString CTreePropSheet::GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption) -{ - CString strMsg; - strMsg.Format(lpszEmptyPageMessage, lpszCaption); - return strMsg; -} - - -CTreeCtrl* CTreePropSheet::CreatePageTreeObject() -{ - return new CTreeCtrl; -} - -//added for mpc-hc theming -void CTreePropSheet::SetTreeCtrlTheme(CTreeCtrl *ctrl) { - SetWindowTheme(ctrl->GetSafeHwnd(), L"Explorer", NULL); -} - - -CPropPageFrame* CTreePropSheet::CreatePageFrame() -{ - return new CPropPageFrameDefault; -} - - -///////////////////////////////////////////////////////////////////// -// Implementation helpers - -void CTreePropSheet::MoveChildWindows(int nDx, int nDy) -{ - CWnd *pWnd = GetWindow(GW_CHILD); - while (pWnd) - { - CRect rect; - pWnd->GetWindowRect(rect); - ScreenToClient(rect); - rect.OffsetRect(nDx, nDy); - pWnd->MoveWindow(rect); - - pWnd = pWnd->GetNextWindow(); - } -} - - -void CTreePropSheet::RefillPageTree() -{ - if (!IsWindow(m_hWnd)) - return; - - m_pwndPageTree->DeleteAllItems(); - - CTabCtrl *pTabCtrl = GetTabControl(); - if (!IsWindow(pTabCtrl->GetSafeHwnd())) - { - ASSERT(FALSE); - return; - } - - const int nPageCount = pTabCtrl->GetItemCount(); - - // rebuild image list - if (m_bTreeImages) - { - for (int i = m_Images.GetImageCount()-1; i >= 0; --i) - m_Images.Remove(i); - - // add page images - CImageList *pPageImages = pTabCtrl->GetImageList(); - if (pPageImages) - { - for (int nImage = 0; nImage < pPageImages->GetImageCount(); ++nImage) - { - HICON hIcon = pPageImages->ExtractIcon(nImage); - m_Images.Add(hIcon); - DestroyIcon(hIcon); - } - } - - // add default images - if (m_DefaultImages.GetSafeHandle()) - { - HICON hIcon; - - // add default images - hIcon = m_DefaultImages.ExtractIcon(0); - if (hIcon) - { - m_Images.Add(hIcon); - DestroyIcon(hIcon); - } - hIcon = m_DefaultImages.ExtractIcon(1); - { - m_Images.Add(hIcon); - DestroyIcon(hIcon); - } - } - } - - // insert tree items - for (int nPage = 0; nPage < nPageCount; ++nPage) - { - // Get title and image of the page - CString strPagePath; - - TCITEM ti; - ZeroMemory(&ti, sizeof(ti)); - ti.mask = TCIF_TEXT|TCIF_IMAGE; - ti.cchTextMax = MAX_PATH; - ti.pszText = strPagePath.GetBuffer(ti.cchTextMax); - ASSERT(ti.pszText); - if (!ti.pszText) - return; - - pTabCtrl->GetItem(nPage, &ti); - strPagePath.ReleaseBuffer(); - - // Create an item in the tree for the page - HTREEITEM hItem = CreatePageTreeItem(ti.pszText); - ASSERT(hItem); - if (hItem) - { - m_pwndPageTree->SetItemData(hItem, nPage); - - // set image - if (m_bTreeImages) - { - int nImage = ti.iImage; - if (nImage < 0 || nImage >= m_Images.GetImageCount()) - nImage = m_DefaultImages.GetSafeHandle()? m_Images.GetImageCount()-1 : -1; - - m_pwndPageTree->SetItemImage(hItem, nImage, nImage); - } - m_pwndPageTree->Expand(m_pwndPageTree->GetParentItem(hItem), TVE_EXPAND); - } - } -} - - -HTREEITEM CTreePropSheet::CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent /* = TVI_ROOT */) -{ - CString strPath(lpszPath); - CString strTopMostItem(SplitPageTreePath(strPath)); - - // Check if an item with the given text does already exist - HTREEITEM hItem = NULL; - HTREEITEM hChild = m_pwndPageTree->GetChildItem(hParent); - while (hChild) - { - if (m_pwndPageTree->GetItemText(hChild) == strTopMostItem) - { - hItem = hChild; - break; - } - hChild = m_pwndPageTree->GetNextItem(hChild, TVGN_NEXT); - } - - // If item with that text does not already exist, create a new one - if (!hItem) - { - hItem = m_pwndPageTree->InsertItem(strTopMostItem, hParent); - m_pwndPageTree->SetItemData(hItem, (DWORD_PTR)-1); - if (!strPath.IsEmpty() && m_bTreeImages && m_DefaultImages.GetSafeHandle()) - // set folder image - m_pwndPageTree->SetItemImage(hItem, m_Images.GetImageCount()-2, m_Images.GetImageCount()-2); - } - if (!hItem) - { - ASSERT(FALSE); - return NULL; - } - - if (strPath.IsEmpty()) - return hItem; - else - return CreatePageTreeItem(strPath, hItem); -} - - -CString CTreePropSheet::SplitPageTreePath(CString &strRest) -{ - int nSeperatorPos = 0; - for (;;) - { - nSeperatorPos = strRest.Find(_T("::"), nSeperatorPos); - if (nSeperatorPos == -1) - { - CString strItem(strRest); - strRest.Empty(); - return strItem; - } - else if (nSeperatorPos>0) - { - // if there is an odd number of backslashes infront of the - // seperator, than do not interpret it as separator - int nBackslashCount = 0; - for (int nPos = nSeperatorPos-1; nPos >= 0 && strRest[nPos]==_T('\\'); --nPos, ++nBackslashCount); - if (nBackslashCount%2 == 0) - break; - else - ++nSeperatorPos; - } - } - - CString strItem(strRest.Left(nSeperatorPos)); - strItem.Replace(_T("\\::"), _T("::")); - strItem.Replace(_T("\\\\"), _T("\\")); - strRest = strRest.Mid(nSeperatorPos+2); - return strItem; -} - - -BOOL CTreePropSheet::KillActiveCurrentPage() -{ - HWND hCurrentPage = PropSheet_GetCurrentPageHwnd(m_hWnd); - if (!IsWindow(hCurrentPage)) - { - ASSERT(FALSE); - return TRUE; - } - - // Check if the current page is really active (if page is invisible - // an virtual empty page is the active one. - if (!::IsWindowVisible(hCurrentPage)) - return TRUE; - - // Try to deactivate current page - PSHNOTIFY pshn; - pshn.hdr.code = PSN_KILLACTIVE; - pshn.hdr.hwndFrom = m_hWnd; - pshn.hdr.idFrom = GetDlgCtrlID(); - pshn.lParam = 0; - if (::SendMessage(hCurrentPage, WM_NOTIFY, pshn.hdr.idFrom, (LPARAM)&pshn)) - // current page does not allow page change - return FALSE; - - // Hide the page - ::ShowWindow(hCurrentPage, SW_HIDE); - - return TRUE; -} - - -HTREEITEM CTreePropSheet::GetPageTreeItem(int nPage, HTREEITEM hRoot /* = TVI_ROOT */) -{ - // Special handling for root case - if (hRoot == TVI_ROOT) - hRoot = m_pwndPageTree->GetNextItem(NULL, TVGN_ROOT); - - // Check parameters - if (nPage < 0 || nPage >= GetPageCount()) - { - ASSERT(FALSE); - return NULL; - } - - if (hRoot == NULL) - { - ASSERT(FALSE); - return NULL; - } - - // we are performing a simple linear search here, because we are - // expecting only little data - HTREEITEM hItem = hRoot; - while (hItem) - { - if ((signed)m_pwndPageTree->GetItemData(hItem) == nPage) - return hItem; - if (m_pwndPageTree->ItemHasChildren(hItem)) - { - HTREEITEM hResult = GetPageTreeItem(nPage, m_pwndPageTree->GetNextItem(hItem, TVGN_CHILD)); - if (hResult) - return hResult; - } - - hItem = m_pwndPageTree->GetNextItem(hItem, TVGN_NEXT); - } - - // we've found nothing, if we arrive here - return hItem; -} - - -BOOL CTreePropSheet::SelectPageTreeItem(int nPage) -{ - HTREEITEM hItem = GetPageTreeItem(nPage); - if (!hItem) - return FALSE; - - return m_pwndPageTree->SelectItem(hItem); -} - - -BOOL CTreePropSheet::SelectCurrentPageTreeItem() -{ - CTabCtrl *pTab = GetTabControl(); - if (!IsWindow(pTab->GetSafeHwnd())) - return FALSE; - - return SelectPageTreeItem(pTab->GetCurSel()); -} - - -void CTreePropSheet::UpdateCaption() -{ - HWND hPage = PropSheet_GetCurrentPageHwnd(GetSafeHwnd()); - BOOL bRealPage = IsWindow(hPage) && ::IsWindowVisible(hPage); - HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); - if (!hItem) - return; - CString strCaption = m_pwndPageTree->GetItemText(hItem); - - // if empty page, then update empty page message - if (!bRealPage) - m_pFrame->SetMsgText(GenerateEmptyPageMessage(m_strEmptyPageMessage, strCaption)); - - // if no captions are displayed, cancel here - if (!m_pFrame->GetShowCaption()) - return; - - // get tab control, to the the images from - CTabCtrl *pTabCtrl = GetTabControl(); - if (!IsWindow(pTabCtrl->GetSafeHwnd())) - { - ASSERT(FALSE); - return; - } - - if (m_bTreeImages) - { - // get image from tree - int nImage; - m_pwndPageTree->GetItemImage(hItem, nImage, nImage); - HICON hIcon = m_Images.ExtractIcon(nImage); - m_pFrame->SetCaption(strCaption, hIcon); - if (hIcon) - DestroyIcon(hIcon); - } - else if (bRealPage) - { - // get image from hidden (original) tab provided by the original - // implementation - CImageList *pImages = pTabCtrl->GetImageList(); - if (pImages) - { - TCITEM ti; - ZeroMemory(&ti, sizeof(ti)); - ti.mask = TCIF_IMAGE; - - HICON hIcon = NULL; - if (pTabCtrl->GetItem((int)m_pwndPageTree->GetItemData(hItem), &ti)) - hIcon = pImages->ExtractIcon(ti.iImage); - - m_pFrame->SetCaption(strCaption, hIcon); - if (hIcon) - DestroyIcon(hIcon); - } - else - m_pFrame->SetCaption(strCaption); - } - else - m_pFrame->SetCaption(strCaption); -} - - -void CTreePropSheet::ActivatePreviousPage() -{ - if (!IsWindow(m_hWnd)) - return; - - if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) - { - // normal tab property sheet. Simply use page index - int nPageIndex = GetActiveIndex(); - if (nPageIndex<0 || nPageIndex>=GetPageCount()) - return; - - int nPrevIndex = (nPageIndex==0)? GetPageCount()-1 : nPageIndex-1; - SetActivePage(nPrevIndex); - } - else - { - // property sheet with page tree. - // we need a more sophisticated handling here, than simply using - // the page index, because we won't skip empty pages. - // so we have to walk the page tree - HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); - ASSERT(hItem); - if (!hItem) - return; - - HTREEITEM hPrevItem = m_pwndPageTree->GetPrevSiblingItem(hItem); - if (hPrevItem) - { - while (m_pwndPageTree->ItemHasChildren(hPrevItem)) - { - hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); - while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) - hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); - } - } - else - hPrevItem = m_pwndPageTree->GetParentItem(hItem); - - if (!hPrevItem) - { - // no prev item, so cycle to the last item - hPrevItem = m_pwndPageTree->GetRootItem(); - - for (;;) - { - while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) - hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); - - if (m_pwndPageTree->ItemHasChildren(hPrevItem)) - hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); - else - break; - } - } - - if (hPrevItem) - m_pwndPageTree->SelectItem(hPrevItem); - } -} - - -void CTreePropSheet::ActivateNextPage() -{ - if (!IsWindow(m_hWnd)) - return; - - if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) - { - // normal tab property sheet. Simply use page index - int nPageIndex = GetActiveIndex(); - if (nPageIndex<0 || nPageIndex>=GetPageCount()) - return; - - int nNextIndex = (nPageIndex==GetPageCount()-1)? 0 : nPageIndex+1; - SetActivePage(nNextIndex); - } - else - { - // property sheet with page tree. - // we need a more sophisticated handling here, than simply using - // the page index, because we won't skip empty pages. - // so we have to walk the page tree - HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); - ASSERT(hItem); - if (!hItem) - return; - - HTREEITEM hNextItem = m_pwndPageTree->GetChildItem(hItem); - if (!hNextItem) - { - hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); - if (!hNextItem && m_pwndPageTree->GetParentItem(hItem)) - { - while (!hNextItem) - { - hItem = m_pwndPageTree->GetParentItem(hItem); - if (!hItem) - break; - - hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); - } - } - } - - if (!hNextItem) - // no next item -- so cycle to the first item - hNextItem = m_pwndPageTree->GetRootItem(); - - if (hNextItem) - m_pwndPageTree->SelectItem(hNextItem); - } -} - - -///////////////////////////////////////////////////////////////////// -// Overridings - -BOOL CTreePropSheet::OnInitDialog() -{ - if (m_bTreeViewMode) - { - // be sure, there are no stacked tabs, because otherwise the - // page caption will be to large in tree view mode - EnableStackedTabs(FALSE); - - // Initialize image list. - if (m_DefaultImages.GetSafeHandle()) - { - IMAGEINFO ii; - m_DefaultImages.GetImageInfo(0, &ii); - if (ii.hbmImage) DeleteObject(ii.hbmImage); - if (ii.hbmMask) DeleteObject(ii.hbmMask); - m_Images.Create(ii.rcImage.right-ii.rcImage.left, ii.rcImage.bottom-ii.rcImage.top, ILC_COLOR32|ILC_MASK, 0, 1); - } - else - m_Images.Create(16, 16, ILC_COLOR32|ILC_MASK, 0, 1); - } - - // perform default implementation - - BOOL bResult = CPropertySheet::OnInitDialog(); - - if (!m_bTreeViewMode) - // stop here, if we would like to use tabs - return bResult; - - // Get tab control... - CTabCtrl *pTab = GetTabControl(); - if (!IsWindow(pTab->GetSafeHwnd())) - { - ASSERT(FALSE); - return bResult; - } - - // ... and hide it - pTab->ShowWindow(SW_HIDE); - pTab->EnableWindow(FALSE); - - // Place another (empty) tab ctrl, to get a frame instead - CRect rectFrame; - pTab->GetWindowRect(rectFrame); - ScreenToClient(rectFrame); - - m_pFrame = CreatePageFrame(); - if (!m_pFrame) - { - ASSERT(FALSE); - AfxThrowMemoryException(); - } - m_pFrame->Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0xFFFF); - m_pFrame->ShowCaption(m_bPageCaption); - - DpiHelper dpiWindow; - dpiWindow.Override(GetParent()->GetSafeHwnd()); - - // Lets make place for the tree ctrl - const int nTreeWidth = dpiWindow.ScaleX(m_nPageTreeWidth); - const int nTreeSpace = dpiWindow.ScaleX(5); - - CRect rectSheet; - GetWindowRect(rectSheet); - rectSheet.right+= nTreeWidth; - SetWindowPos(NULL, -1, -1, rectSheet.Width(), rectSheet.Height(), SWP_NOZORDER|SWP_NOMOVE); - CenterWindow(); - - MoveChildWindows(nTreeWidth, 0); - - // Lets calculate the rectangle for the tree ctrl - CRect rectTree(rectFrame); - rectTree.right = rectTree.left + nTreeWidth - nTreeSpace; - - //originally, using a dummy tabctrl to get a default height for the caption - //tabs do not scale sanely with dpi (96->font 11 height 21, 120-> font 12 height 21), so we will scale manually - int frameCaptionHeight; - if (DpiHelper::CanUsePerMonitorV2()) { - frameCaptionHeight = dpiWindow.ScaleX(21); //hard code 21 as the 96 dpi value and scale - } else { - // calculate caption height - CTabCtrl wndTabCtrl; - wndTabCtrl.Create(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, rectFrame, this, 0x1234); - wndTabCtrl.InsertItem(0, _T("")); - CRect rectFrameCaption; - wndTabCtrl.GetItemRect(0, rectFrameCaption); - wndTabCtrl.DestroyWindow(); - - frameCaptionHeight = rectFrameCaption.Height(); - } - m_pFrame->SetCaptionHeight(frameCaptionHeight); - - // if no caption should be displayed, make the window smaller in - // height - if (!m_bPageCaption) - { - // make frame smaller - m_pFrame->GetWnd()->GetWindowRect(rectFrame); - ScreenToClient(rectFrame); - rectFrame.top+= frameCaptionHeight; - m_pFrame->GetWnd()->MoveWindow(rectFrame); - - // move all child windows up - MoveChildWindows(0, -frameCaptionHeight); - - // modify rectangle for the tree ctrl - rectTree.bottom-= frameCaptionHeight; - - // make us smaller - CRect rect; - GetWindowRect(rect); - rect.top+= frameCaptionHeight/2; - rect.bottom-= frameCaptionHeight-frameCaptionHeight/2; - if (GetParent()) - GetParent()->ScreenToClient(rect); - MoveWindow(rect); - } - - // finally create the tree control - const DWORD dwTreeStyle = TVS_SHOWSELALWAYS|TVS_TRACKSELECT|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS; - m_pwndPageTree = CreatePageTreeObject(); - if (!m_pwndPageTree) - { - ASSERT(FALSE); - AfxThrowMemoryException(); - } - - // MFC7-support here (Thanks to Rainer Wollgarten) - // YT: Cast tree control to CWnd and calls CWnd::CreateEx in all cases (VC 6 and7). - ((CWnd*)m_pwndPageTree)->CreateEx( - WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY|TVS_EX_DOUBLEBUFFER, - _T("SysTreeView32"), _T("PageTree"), - WS_TABSTOP|WS_CHILD|WS_VISIBLE|dwTreeStyle, - rectTree, this, s_unPageTreeId); - - if (m_bTreeImages) - { - m_pwndPageTree->SetImageList(&m_Images, TVSIL_NORMAL); - m_pwndPageTree->SetImageList(&m_Images, TVSIL_STATE); - } - - //SetWindowTheme(m_pwndPageTree->GetSafeHwnd(), L"Explorer", NULL); - SetTreeCtrlTheme(m_pwndPageTree); - - // Fill the tree ctrl - RefillPageTree(); - - // Select item for the current page - if (pTab->GetCurSel() > -1) - SelectPageTreeItem(pTab->GetCurSel()); - - return bResult; -} - - -void CTreePropSheet::OnDestroy() -{ - CPropertySheet::OnDestroy(); - - if (m_Images.GetSafeHandle()) - m_Images.DeleteImageList(); - - delete m_pwndPageTree; - m_pwndPageTree = NULL; - - if (m_pFrame) { - CWnd* frameWnd = m_pFrame->GetWnd(); - if (nullptr != frameWnd && IsWindow(frameWnd->m_hWnd)) frameWnd->DestroyWindow(); //fix memory leak of CWnd - delete m_pFrame; - m_pFrame = NULL; - } -} - - -LRESULT CTreePropSheet::OnAddPage(WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = DefWindowProc(PSM_ADDPAGE, wParam, lParam); - if (!m_bTreeViewMode) - return lResult; - - RefillPageTree(); - SelectCurrentPageTreeItem(); - - return lResult; -} - - -LRESULT CTreePropSheet::OnRemovePage(WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = DefWindowProc(PSM_REMOVEPAGE, wParam, lParam); - if (!m_bTreeViewMode) - return lResult; - - RefillPageTree(); - SelectCurrentPageTreeItem(); - - return lResult; -} - - -LRESULT CTreePropSheet::OnSetCurSel(WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam); - if (!m_bTreeViewMode) - return lResult; - - SelectCurrentPageTreeItem(); - UpdateCaption(); - return lResult; -} - -LRESULT CTreePropSheet::OnSetCurSelId(WPARAM wParam, LPARAM lParam) -{ - return OnSetCurSel(wParam, lParam); -} - - -void CTreePropSheet::OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult) -{ - *plResult = 0; - if (m_bPageTreeSelChangedActive) - return; - else - m_bPageTreeSelChangedActive = TRUE; - - NMTREEVIEW *pTvn = reinterpret_cast(pNotifyStruct); - int nPage = (int)m_pwndPageTree->GetItemData(pTvn->itemNew.hItem); - if (nPage < 0) - { - HTREEITEM nextItem = m_pwndPageTree->GetChildItem(pTvn->itemNew.hItem); - nPage = (int)m_pwndPageTree->GetItemData(nextItem); - } - BOOL bResult; - if (nPage >= (int)m_pwndPageTree->GetCount()) - bResult = KillActiveCurrentPage(); - else - bResult = SetActivePage(nPage); - - if (!bResult) - // prevent selection to change - *plResult = TRUE; - - // Set focus to tree ctrl (I guess that's what the user expects) - m_pwndPageTree->SetFocus(); - - m_bPageTreeSelChangedActive = FALSE; - - return; -} - - -void CTreePropSheet::OnPageTreeSelChanged(NMHDR * /*pNotifyStruct*/, LRESULT *plResult) -{ - *plResult = 0; - - UpdateCaption(); - - return; -} - - -LRESULT CTreePropSheet::OnIsDialogMessage(WPARAM wParam, LPARAM lParam) -{ - MSG *pMsg = reinterpret_cast(lParam); - if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_TAB && GetKeyState(VK_CONTROL)&0x8000) - { - if (GetKeyState(VK_SHIFT)&0x8000) - ActivatePreviousPage(); - else - ActivateNextPage(); - return TRUE; - } - - - return CPropertySheet::DefWindowProc(PSM_ISDIALOGMESSAGE, wParam, lParam); -} - -} //namespace TreePropSheet +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + + +#include "stdafx.h" +#include "TreePropSheet.h" +#include "PropPageFrameDefault.h" +#include "../../../src/mpc-hc/DpiHelper.h" +#include "../../../src/DSUtil/VersionHelpersInternal.h" + +namespace TreePropSheet +{ + +//------------------------------------------------------------------- +// class CTreePropSheet +//------------------------------------------------------------------- + +BEGIN_MESSAGE_MAP(CTreePropSheet, CPropertySheet) + //{{AFX_MSG_MAP(CTreePropSheet) + ON_WM_DESTROY() + //}}AFX_MSG_MAP + ON_MESSAGE(PSM_ADDPAGE, OnAddPage) + ON_MESSAGE(PSM_REMOVEPAGE, OnRemovePage) + ON_MESSAGE(PSM_SETCURSEL, OnSetCurSel) + ON_MESSAGE(PSM_SETCURSELID, OnSetCurSelId) + ON_MESSAGE(PSM_ISDIALOGMESSAGE, OnIsDialogMessage) + + ON_NOTIFY(TVN_SELCHANGINGA, s_unPageTreeId, OnPageTreeSelChanging) + ON_NOTIFY(TVN_SELCHANGINGW, s_unPageTreeId, OnPageTreeSelChanging) + ON_NOTIFY(TVN_SELCHANGEDA, s_unPageTreeId, OnPageTreeSelChanged) + ON_NOTIFY(TVN_SELCHANGEDW, s_unPageTreeId, OnPageTreeSelChanged) +END_MESSAGE_MAP() + +IMPLEMENT_DYNAMIC(CTreePropSheet, CPropertySheet) + +const UINT CTreePropSheet::s_unPageTreeId = 0x7EEE; + +CTreePropSheet::CTreePropSheet() +: CPropertySheet(), + m_bTreeViewMode(TRUE), + m_pwndPageTree(NULL), + m_pFrame(NULL), + m_bPageTreeSelChangedActive(FALSE), + m_bPageCaption(FALSE), + m_bTreeImages(FALSE), + m_nPageTreeWidth(150) +{ +} + + +CTreePropSheet::CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) +: CPropertySheet(nIDCaption, pParentWnd, iSelectPage), + m_bTreeViewMode(TRUE), + m_pwndPageTree(NULL), + m_pFrame(NULL), + m_bPageTreeSelChangedActive(FALSE), + m_bPageCaption(FALSE), + m_bTreeImages(FALSE), + m_nPageTreeWidth(150) +{ +} + + +CTreePropSheet::CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) +: CPropertySheet(pszCaption, pParentWnd, iSelectPage), + m_bTreeViewMode(TRUE), + m_pwndPageTree(NULL), + m_pFrame(NULL), + m_bPageTreeSelChangedActive(FALSE), + m_bPageCaption(FALSE), + m_bTreeImages(FALSE), + m_nPageTreeWidth(150) +{ +} + + +CTreePropSheet::~CTreePropSheet() +{ +} + + +///////////////////////////////////////////////////////////////////// +// Operationen + +BOOL CTreePropSheet::SetTreeViewMode(BOOL bTreeViewMode /* = TRUE */, BOOL bPageCaption /* = FALSE */, BOOL bTreeImages /* = FALSE */) +{ + if (IsWindow(m_hWnd)) + { + // needs to becalled, before the window has been created + ASSERT(FALSE); + return FALSE; + } + + m_bTreeViewMode = bTreeViewMode; + if (m_bTreeViewMode) + { + m_bPageCaption = bPageCaption; + m_bTreeImages = bTreeImages; + } + + return TRUE; +} + + +BOOL CTreePropSheet::SetTreeWidth(int nWidth) +{ + if (IsWindow(m_hWnd)) + { + // needs to be called, before the window is created. + ASSERT(FALSE); + return FALSE; + } + + m_nPageTreeWidth = nWidth; + + return TRUE; +} + + +void CTreePropSheet::SetEmptyPageText(LPCTSTR lpszEmptyPageText) +{ + m_strEmptyPageMessage = lpszEmptyPageText; +} + + +DWORD CTreePropSheet::SetEmptyPageTextFormat(DWORD dwFormat) +{ + DWORD dwPrevFormat = m_pFrame->GetMsgFormat(); + m_pFrame->SetMsgFormat(dwFormat); + return dwPrevFormat; +} + + +BOOL CTreePropSheet::SetTreeDefaultImages(CImageList *pImages) +{ + if (pImages->GetImageCount() != 2) + { + ASSERT(FALSE); + return FALSE; + } + + if (m_DefaultImages.GetSafeHandle()) + m_DefaultImages.DeleteImageList(); + m_DefaultImages.Create(pImages); + + // update, if necessary + if (IsWindow(m_hWnd)) + RefillPageTree(); + + return TRUE; +} + + +BOOL CTreePropSheet::SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask) +{ + if (m_DefaultImages.GetSafeHandle()) + m_DefaultImages.DeleteImageList(); + if (!m_DefaultImages.Create(unBitmapID, cx, 0, crMask)) + return FALSE; + + if (m_DefaultImages.GetImageCount() != 2) + { + m_DefaultImages.DeleteImageList(); + return FALSE; + } + + return TRUE; +} + + +CTreeCtrl* CTreePropSheet::GetPageTreeControl() +{ + return m_pwndPageTree; +} + + +///////////////////////////////////////////////////////////////////// +// public helpers + +BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, HICON hIcon) +{ + pPage->m_psp.dwFlags|= PSP_USEHICON; + pPage->m_psp.hIcon = hIcon; + return TRUE; +} + + +BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, UINT unIconId) +{ + HICON hIcon = AfxGetApp()->LoadIcon(unIconId); + if (!hIcon) + return FALSE; + + return SetPageIcon(pPage, hIcon); +} + + +BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage) +{ + HICON hIcon = Images.ExtractIcon(nImage); + if (!hIcon) + return FALSE; + + return SetPageIcon(pPage, hIcon); +} + + +BOOL CTreePropSheet::DestroyPageIcon(CPropertyPage *pPage) +{ + if (!pPage || !(pPage->m_psp.dwFlags&PSP_USEHICON) || !pPage->m_psp.hIcon) + return FALSE; + + DestroyIcon(pPage->m_psp.hIcon); + pPage->m_psp.dwFlags&= ~PSP_USEHICON; + pPage->m_psp.hIcon = NULL; + + return TRUE; +} + + +///////////////////////////////////////////////////////////////////// +// Overridable implementation helpers + +CString CTreePropSheet::GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption) +{ + CString strMsg; + strMsg.Format(lpszEmptyPageMessage, lpszCaption); + return strMsg; +} + + +CTreeCtrl* CTreePropSheet::CreatePageTreeObject() +{ + return new CTreeCtrl; +} + +//added for mpc-hc theming +void CTreePropSheet::SetTreeCtrlTheme(CTreeCtrl *ctrl) { + SetWindowTheme(ctrl->GetSafeHwnd(), L"Explorer", NULL); +} + + +CPropPageFrame* CTreePropSheet::CreatePageFrame() +{ + return new CPropPageFrameDefault; +} + + +///////////////////////////////////////////////////////////////////// +// Implementation helpers + +void CTreePropSheet::MoveChildWindows(int nDx, int nDy) +{ + CWnd *pWnd = GetWindow(GW_CHILD); + while (pWnd) + { + CRect rect; + pWnd->GetWindowRect(rect); + ScreenToClient(rect); + rect.OffsetRect(nDx, nDy); + pWnd->MoveWindow(rect); + + pWnd = pWnd->GetNextWindow(); + } +} + + +void CTreePropSheet::RefillPageTree() +{ + if (!IsWindow(m_hWnd)) + return; + + m_pwndPageTree->DeleteAllItems(); + + CTabCtrl *pTabCtrl = GetTabControl(); + if (!IsWindow(pTabCtrl->GetSafeHwnd())) + { + ASSERT(FALSE); + return; + } + + const int nPageCount = pTabCtrl->GetItemCount(); + + // rebuild image list + if (m_bTreeImages) + { + for (int i = m_Images.GetImageCount()-1; i >= 0; --i) + m_Images.Remove(i); + + // add page images + CImageList *pPageImages = pTabCtrl->GetImageList(); + if (pPageImages) + { + for (int nImage = 0; nImage < pPageImages->GetImageCount(); ++nImage) + { + HICON hIcon = pPageImages->ExtractIcon(nImage); + m_Images.Add(hIcon); + DestroyIcon(hIcon); + } + } + + // add default images + if (m_DefaultImages.GetSafeHandle()) + { + HICON hIcon; + + // add default images + hIcon = m_DefaultImages.ExtractIcon(0); + if (hIcon) + { + m_Images.Add(hIcon); + DestroyIcon(hIcon); + } + hIcon = m_DefaultImages.ExtractIcon(1); + { + m_Images.Add(hIcon); + DestroyIcon(hIcon); + } + } + } + + // insert tree items + for (int nPage = 0; nPage < nPageCount; ++nPage) + { + // Get title and image of the page + CString strPagePath; + + TCITEM ti; + ZeroMemory(&ti, sizeof(ti)); + ti.mask = TCIF_TEXT|TCIF_IMAGE; + ti.cchTextMax = MAX_PATH; + ti.pszText = strPagePath.GetBuffer(ti.cchTextMax); + ASSERT(ti.pszText); + if (!ti.pszText) + return; + + pTabCtrl->GetItem(nPage, &ti); + strPagePath.ReleaseBuffer(); + + // Create an item in the tree for the page + HTREEITEM hItem = CreatePageTreeItem(ti.pszText); + ASSERT(hItem); + if (hItem) + { + m_pwndPageTree->SetItemData(hItem, nPage); + + // set image + if (m_bTreeImages) + { + int nImage = ti.iImage; + if (nImage < 0 || nImage >= m_Images.GetImageCount()) + nImage = m_DefaultImages.GetSafeHandle()? m_Images.GetImageCount()-1 : -1; + + m_pwndPageTree->SetItemImage(hItem, nImage, nImage); + } + m_pwndPageTree->Expand(m_pwndPageTree->GetParentItem(hItem), TVE_EXPAND); + } + } +} + + +HTREEITEM CTreePropSheet::CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent /* = TVI_ROOT */) +{ + CString strPath(lpszPath); + CString strTopMostItem(SplitPageTreePath(strPath)); + + // Check if an item with the given text does already exist + HTREEITEM hItem = NULL; + HTREEITEM hChild = m_pwndPageTree->GetChildItem(hParent); + while (hChild) + { + if (m_pwndPageTree->GetItemText(hChild) == strTopMostItem) + { + hItem = hChild; + break; + } + hChild = m_pwndPageTree->GetNextItem(hChild, TVGN_NEXT); + } + + // If item with that text does not already exist, create a new one + if (!hItem) + { + hItem = m_pwndPageTree->InsertItem(strTopMostItem, hParent); + m_pwndPageTree->SetItemData(hItem, (DWORD_PTR)-1); + if (!strPath.IsEmpty() && m_bTreeImages && m_DefaultImages.GetSafeHandle()) + // set folder image + m_pwndPageTree->SetItemImage(hItem, m_Images.GetImageCount()-2, m_Images.GetImageCount()-2); + } + if (!hItem) + { + ASSERT(FALSE); + return NULL; + } + + if (strPath.IsEmpty()) + return hItem; + else + return CreatePageTreeItem(strPath, hItem); +} + + +CString CTreePropSheet::SplitPageTreePath(CString &strRest) +{ + int nSeperatorPos = 0; + for (;;) + { + nSeperatorPos = strRest.Find(_T("::"), nSeperatorPos); + if (nSeperatorPos == -1) + { + CString strItem(strRest); + strRest.Empty(); + return strItem; + } + else if (nSeperatorPos>0) + { + // if there is an odd number of backslashes infront of the + // seperator, than do not interpret it as separator + int nBackslashCount = 0; + for (int nPos = nSeperatorPos-1; nPos >= 0 && strRest[nPos]==_T('\\'); --nPos, ++nBackslashCount); + if (nBackslashCount%2 == 0) + break; + else + ++nSeperatorPos; + } + } + + CString strItem(strRest.Left(nSeperatorPos)); + strItem.Replace(_T("\\::"), _T("::")); + strItem.Replace(_T("\\\\"), _T("\\")); + strRest = strRest.Mid(nSeperatorPos+2); + return strItem; +} + + +BOOL CTreePropSheet::KillActiveCurrentPage() +{ + HWND hCurrentPage = PropSheet_GetCurrentPageHwnd(m_hWnd); + if (!IsWindow(hCurrentPage)) + { + ASSERT(FALSE); + return TRUE; + } + + // Check if the current page is really active (if page is invisible + // an virtual empty page is the active one. + if (!::IsWindowVisible(hCurrentPage)) + return TRUE; + + // Try to deactivate current page + PSHNOTIFY pshn; + pshn.hdr.code = PSN_KILLACTIVE; + pshn.hdr.hwndFrom = m_hWnd; + pshn.hdr.idFrom = GetDlgCtrlID(); + pshn.lParam = 0; + if (::SendMessage(hCurrentPage, WM_NOTIFY, pshn.hdr.idFrom, (LPARAM)&pshn)) + // current page does not allow page change + return FALSE; + + // Hide the page + ::ShowWindow(hCurrentPage, SW_HIDE); + + return TRUE; +} + + +HTREEITEM CTreePropSheet::GetPageTreeItem(int nPage, HTREEITEM hRoot /* = TVI_ROOT */) +{ + // Special handling for root case + if (hRoot == TVI_ROOT) + hRoot = m_pwndPageTree->GetNextItem(NULL, TVGN_ROOT); + + // Check parameters + if (nPage < 0 || nPage >= GetPageCount()) + { + ASSERT(FALSE); + return NULL; + } + + if (hRoot == NULL) + { + ASSERT(FALSE); + return NULL; + } + + // we are performing a simple linear search here, because we are + // expecting only little data + HTREEITEM hItem = hRoot; + while (hItem) + { + if ((signed)m_pwndPageTree->GetItemData(hItem) == nPage) + return hItem; + if (m_pwndPageTree->ItemHasChildren(hItem)) + { + HTREEITEM hResult = GetPageTreeItem(nPage, m_pwndPageTree->GetNextItem(hItem, TVGN_CHILD)); + if (hResult) + return hResult; + } + + hItem = m_pwndPageTree->GetNextItem(hItem, TVGN_NEXT); + } + + // we've found nothing, if we arrive here + return hItem; +} + + +BOOL CTreePropSheet::SelectPageTreeItem(int nPage) +{ + HTREEITEM hItem = GetPageTreeItem(nPage); + if (!hItem) + return FALSE; + + return m_pwndPageTree->SelectItem(hItem); +} + + +BOOL CTreePropSheet::SelectCurrentPageTreeItem() +{ + CTabCtrl *pTab = GetTabControl(); + if (!IsWindow(pTab->GetSafeHwnd())) + return FALSE; + + return SelectPageTreeItem(pTab->GetCurSel()); +} + + +void CTreePropSheet::UpdateCaption() +{ + HWND hPage = PropSheet_GetCurrentPageHwnd(GetSafeHwnd()); + BOOL bRealPage = IsWindow(hPage) && ::IsWindowVisible(hPage); + HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); + if (!hItem) + return; + CString strCaption = m_pwndPageTree->GetItemText(hItem); + + // if empty page, then update empty page message + if (!bRealPage) + m_pFrame->SetMsgText(GenerateEmptyPageMessage(m_strEmptyPageMessage, strCaption)); + + // if no captions are displayed, cancel here + if (!m_pFrame->GetShowCaption()) + return; + + // get tab control, to the the images from + CTabCtrl *pTabCtrl = GetTabControl(); + if (!IsWindow(pTabCtrl->GetSafeHwnd())) + { + ASSERT(FALSE); + return; + } + + if (m_bTreeImages) + { + // get image from tree + int nImage; + m_pwndPageTree->GetItemImage(hItem, nImage, nImage); + HICON hIcon = m_Images.ExtractIcon(nImage); + m_pFrame->SetCaption(strCaption, hIcon); + if (hIcon) + DestroyIcon(hIcon); + } + else if (bRealPage) + { + // get image from hidden (original) tab provided by the original + // implementation + CImageList *pImages = pTabCtrl->GetImageList(); + if (pImages) + { + TCITEM ti; + ZeroMemory(&ti, sizeof(ti)); + ti.mask = TCIF_IMAGE; + + HICON hIcon = NULL; + if (pTabCtrl->GetItem((int)m_pwndPageTree->GetItemData(hItem), &ti)) + hIcon = pImages->ExtractIcon(ti.iImage); + + m_pFrame->SetCaption(strCaption, hIcon); + if (hIcon) + DestroyIcon(hIcon); + } + else + m_pFrame->SetCaption(strCaption); + } + else + m_pFrame->SetCaption(strCaption); +} + + +void CTreePropSheet::ActivatePreviousPage() +{ + if (!IsWindow(m_hWnd)) + return; + + if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) + { + // normal tab property sheet. Simply use page index + int nPageIndex = GetActiveIndex(); + if (nPageIndex<0 || nPageIndex>=GetPageCount()) + return; + + int nPrevIndex = (nPageIndex==0)? GetPageCount()-1 : nPageIndex-1; + SetActivePage(nPrevIndex); + } + else + { + // property sheet with page tree. + // we need a more sophisticated handling here, than simply using + // the page index, because we won't skip empty pages. + // so we have to walk the page tree + HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); + ASSERT(hItem); + if (!hItem) + return; + + HTREEITEM hPrevItem = m_pwndPageTree->GetPrevSiblingItem(hItem); + if (hPrevItem) + { + while (m_pwndPageTree->ItemHasChildren(hPrevItem)) + { + hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); + while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) + hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); + } + } + else + hPrevItem = m_pwndPageTree->GetParentItem(hItem); + + if (!hPrevItem) + { + // no prev item, so cycle to the last item + hPrevItem = m_pwndPageTree->GetRootItem(); + + for (;;) + { + while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) + hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); + + if (m_pwndPageTree->ItemHasChildren(hPrevItem)) + hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); + else + break; + } + } + + if (hPrevItem) + m_pwndPageTree->SelectItem(hPrevItem); + } +} + + +void CTreePropSheet::ActivateNextPage() +{ + if (!IsWindow(m_hWnd)) + return; + + if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) + { + // normal tab property sheet. Simply use page index + int nPageIndex = GetActiveIndex(); + if (nPageIndex<0 || nPageIndex>=GetPageCount()) + return; + + int nNextIndex = (nPageIndex==GetPageCount()-1)? 0 : nPageIndex+1; + SetActivePage(nNextIndex); + } + else + { + // property sheet with page tree. + // we need a more sophisticated handling here, than simply using + // the page index, because we won't skip empty pages. + // so we have to walk the page tree + HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); + ASSERT(hItem); + if (!hItem) + return; + + HTREEITEM hNextItem = m_pwndPageTree->GetChildItem(hItem); + if (!hNextItem) + { + hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); + if (!hNextItem && m_pwndPageTree->GetParentItem(hItem)) + { + while (!hNextItem) + { + hItem = m_pwndPageTree->GetParentItem(hItem); + if (!hItem) + break; + + hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); + } + } + } + + if (!hNextItem) + // no next item -- so cycle to the first item + hNextItem = m_pwndPageTree->GetRootItem(); + + if (hNextItem) + m_pwndPageTree->SelectItem(hNextItem); + } +} + + +///////////////////////////////////////////////////////////////////// +// Overridings + +BOOL CTreePropSheet::OnInitDialog() +{ + if (m_bTreeViewMode) + { + // be sure, there are no stacked tabs, because otherwise the + // page caption will be to large in tree view mode + EnableStackedTabs(FALSE); + + // Initialize image list. + if (m_DefaultImages.GetSafeHandle()) + { + IMAGEINFO ii; + m_DefaultImages.GetImageInfo(0, &ii); + if (ii.hbmImage) DeleteObject(ii.hbmImage); + if (ii.hbmMask) DeleteObject(ii.hbmMask); + m_Images.Create(ii.rcImage.right-ii.rcImage.left, ii.rcImage.bottom-ii.rcImage.top, ILC_COLOR32|ILC_MASK, 0, 1); + } + else + m_Images.Create(16, 16, ILC_COLOR32|ILC_MASK, 0, 1); + } + + // perform default implementation + + BOOL bResult = CPropertySheet::OnInitDialog(); + + if (!m_bTreeViewMode) + // stop here, if we would like to use tabs + return bResult; + + // Get tab control... + CTabCtrl *pTab = GetTabControl(); + if (!IsWindow(pTab->GetSafeHwnd())) + { + ASSERT(FALSE); + return bResult; + } + + // ... and hide it + pTab->ShowWindow(SW_HIDE); + pTab->EnableWindow(FALSE); + + // Place another (empty) tab ctrl, to get a frame instead + CRect rectFrame; + pTab->GetWindowRect(rectFrame); + ScreenToClient(rectFrame); + + m_pFrame = CreatePageFrame(); + if (!m_pFrame) + { + ASSERT(FALSE); + AfxThrowMemoryException(); + } + m_pFrame->Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0xFFFF); + m_pFrame->ShowCaption(m_bPageCaption); + + DpiHelper dpiWindow; + dpiWindow.Override(GetParent()->GetSafeHwnd()); + + // Lets make place for the tree ctrl + const int nTreeWidth = dpiWindow.ScaleX(m_nPageTreeWidth); + const int nTreeSpace = dpiWindow.ScaleX(5); + + CRect rectSheet; + GetWindowRect(rectSheet); + rectSheet.right+= nTreeWidth; + SetWindowPos(NULL, -1, -1, rectSheet.Width(), rectSheet.Height(), SWP_NOZORDER|SWP_NOMOVE); + CenterWindow(); + + MoveChildWindows(nTreeWidth, 0); + + // Lets calculate the rectangle for the tree ctrl + CRect rectTree(rectFrame); + rectTree.right = rectTree.left + nTreeWidth - nTreeSpace; + + //originally, using a dummy tabctrl to get a default height for the caption + //tabs do not scale sanely with dpi (96->font 11 height 21, 120-> font 12 height 21), so we will scale manually + int frameCaptionHeight; + if (DpiHelper::CanUsePerMonitorV2()) { + frameCaptionHeight = dpiWindow.ScaleX(21); //hard code 21 as the 96 dpi value and scale + } else { + // calculate caption height + CTabCtrl wndTabCtrl; + wndTabCtrl.Create(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, rectFrame, this, 0x1234); + wndTabCtrl.InsertItem(0, _T("")); + CRect rectFrameCaption; + wndTabCtrl.GetItemRect(0, rectFrameCaption); + wndTabCtrl.DestroyWindow(); + + frameCaptionHeight = rectFrameCaption.Height(); + } + m_pFrame->SetCaptionHeight(frameCaptionHeight); + + // if no caption should be displayed, make the window smaller in + // height + if (!m_bPageCaption) + { + // make frame smaller + m_pFrame->GetWnd()->GetWindowRect(rectFrame); + ScreenToClient(rectFrame); + rectFrame.top+= frameCaptionHeight; + m_pFrame->GetWnd()->MoveWindow(rectFrame); + + // move all child windows up + MoveChildWindows(0, -frameCaptionHeight); + + // modify rectangle for the tree ctrl + rectTree.bottom-= frameCaptionHeight; + + // make us smaller + CRect rect; + GetWindowRect(rect); + rect.top+= frameCaptionHeight/2; + rect.bottom-= frameCaptionHeight-frameCaptionHeight/2; + if (GetParent()) + GetParent()->ScreenToClient(rect); + MoveWindow(rect); + } + + // finally create the tree control + const DWORD dwTreeStyle = TVS_SHOWSELALWAYS|TVS_TRACKSELECT|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS; + m_pwndPageTree = CreatePageTreeObject(); + if (!m_pwndPageTree) + { + ASSERT(FALSE); + AfxThrowMemoryException(); + } + + // MFC7-support here (Thanks to Rainer Wollgarten) + // YT: Cast tree control to CWnd and calls CWnd::CreateEx in all cases (VC 6 and7). + ((CWnd*)m_pwndPageTree)->CreateEx( + WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY|TVS_EX_DOUBLEBUFFER, + _T("SysTreeView32"), _T("PageTree"), + WS_TABSTOP|WS_CHILD|WS_VISIBLE|dwTreeStyle, + rectTree, this, s_unPageTreeId); + + if (m_bTreeImages) + { + m_pwndPageTree->SetImageList(&m_Images, TVSIL_NORMAL); + m_pwndPageTree->SetImageList(&m_Images, TVSIL_STATE); + } + + //SetWindowTheme(m_pwndPageTree->GetSafeHwnd(), L"Explorer", NULL); + SetTreeCtrlTheme(m_pwndPageTree); + + // Fill the tree ctrl + RefillPageTree(); + + // Select item for the current page + if (pTab->GetCurSel() > -1) + SelectPageTreeItem(pTab->GetCurSel()); + + return bResult; +} + + +void CTreePropSheet::OnDestroy() +{ + CPropertySheet::OnDestroy(); + + if (m_Images.GetSafeHandle()) + m_Images.DeleteImageList(); + + delete m_pwndPageTree; + m_pwndPageTree = NULL; + + if (m_pFrame) { + CWnd* frameWnd = m_pFrame->GetWnd(); + if (nullptr != frameWnd && IsWindow(frameWnd->m_hWnd)) frameWnd->DestroyWindow(); //fix memory leak of CWnd + delete m_pFrame; + m_pFrame = NULL; + } +} + + +LRESULT CTreePropSheet::OnAddPage(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = DefWindowProc(PSM_ADDPAGE, wParam, lParam); + if (!m_bTreeViewMode) + return lResult; + + RefillPageTree(); + SelectCurrentPageTreeItem(); + + return lResult; +} + + +LRESULT CTreePropSheet::OnRemovePage(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = DefWindowProc(PSM_REMOVEPAGE, wParam, lParam); + if (!m_bTreeViewMode) + return lResult; + + RefillPageTree(); + SelectCurrentPageTreeItem(); + + return lResult; +} + + +LRESULT CTreePropSheet::OnSetCurSel(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam); + if (!m_bTreeViewMode) + return lResult; + + SelectCurrentPageTreeItem(); + UpdateCaption(); + return lResult; +} + +LRESULT CTreePropSheet::OnSetCurSelId(WPARAM wParam, LPARAM lParam) +{ + return OnSetCurSel(wParam, lParam); +} + + +void CTreePropSheet::OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult) +{ + *plResult = 0; + if (m_bPageTreeSelChangedActive) + return; + else + m_bPageTreeSelChangedActive = TRUE; + + NMTREEVIEW *pTvn = reinterpret_cast(pNotifyStruct); + int nPage = (int)m_pwndPageTree->GetItemData(pTvn->itemNew.hItem); + if (nPage < 0) + { + HTREEITEM nextItem = m_pwndPageTree->GetChildItem(pTvn->itemNew.hItem); + nPage = (int)m_pwndPageTree->GetItemData(nextItem); + } + BOOL bResult; + if (nPage >= (int)m_pwndPageTree->GetCount()) + bResult = KillActiveCurrentPage(); + else + bResult = SetActivePage(nPage); + + if (!bResult) + // prevent selection to change + *plResult = TRUE; + + // Set focus to tree ctrl (I guess that's what the user expects) + m_pwndPageTree->SetFocus(); + + m_bPageTreeSelChangedActive = FALSE; + + return; +} + + +void CTreePropSheet::OnPageTreeSelChanged(NMHDR * /*pNotifyStruct*/, LRESULT *plResult) +{ + *plResult = 0; + + UpdateCaption(); + + return; +} + + +LRESULT CTreePropSheet::OnIsDialogMessage(WPARAM wParam, LPARAM lParam) +{ + MSG *pMsg = reinterpret_cast(lParam); + if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_TAB && GetKeyState(VK_CONTROL)&0x8000) + { + if (GetKeyState(VK_SHIFT)&0x8000) + ActivatePreviousPage(); + else + ActivateNextPage(); + return TRUE; + } + + + return CPropertySheet::DefWindowProc(PSM_ISDIALOGMESSAGE, wParam, lParam); +} + +} //namespace TreePropSheet diff --git a/src/thirdparty/TreePropSheet/TreePropSheet.h b/src/thirdparty/TreePropSheet/TreePropSheet.h index 654c13d720f..99523c1510b 100644 --- a/src/thirdparty/TreePropSheet/TreePropSheet.h +++ b/src/thirdparty/TreePropSheet/TreePropSheet.h @@ -1,487 +1,487 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - - -#if !defined(AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_) -#define AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include "PropPageFrame.h" -#include -#include // Needed for CPropertySheet -#include // Needed for CTreeCtrl - -namespace TreePropSheet -{ - -/** -A property sheet, which can use a tree control instead of a tab -control, to give the user access to the different pages. - -You can use it exactly the same way, as a CPropertySheet object. -Simply create CPropertyPage objects and add them via AddPage() to -the sheet. If you would like to use the tree view mode (default), -you can specify the path of the pages in the tree, by their name: -The names of the pages can contain -double colons ("::"), which will specify the path of that page in the -tree control. I.e. if you have three pages with the following names: -1. _T("Appearance::Toolbars") -2. _T("Appearance::Menus") -3. _T("Directories") -the tree would look as follow: -\verbatim -Appearance -| -+-Toolbars -| -+-Menus - -Directories -\endverbatim -If you would like to use a double colon, which should not be -interpreted as a path seperator, prefix it with a backslash ("\\::"). - -To disable tree view mode and use the standard tabbed mode, call -the SetTreeViewMode() method. This also allows you, to enable page -captions and tree images for tree view mode. If you would like to -have images in the tree, but not all of your pages specify images or -there are tree view items, which are not attached to a page (only -parent items for real page items), you have to set default images -using the SetTreeDefaultImages() method -- otherwise their may appear -display errors. - -If the user selects a tree view item, which does not belong to a page, -because it is just a parent item for real page items, no page will -be displayed, instead a message will be displayed, that can be set -via SetEmptyPageText(). - -@author Sven Wiegand -*/ -class /*AFX_EXT_CLASS*/ CTreePropSheet : public CPropertySheet -{ - DECLARE_DYNAMIC(CTreePropSheet) - -// Construction/Destruction -public: - CTreePropSheet(); - CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); - CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); - virtual ~CTreePropSheet(); - -// Operations -public: - /** - Call this method, if you would like to use a tree control to browse - the pages, instead of the tab control. - - This method needs to becalled, before DoModal() or Create(). If the - window has already been created, the method will fail. - - @param bTreeViewMode - Pass TRUE to provide a tree view control instead of a tab control - to browse the pages, pass FALSE to use the normal tab control. - @param bPageCaption - TRUE if a caption should be displayed for each page. The caption - contains the page title and an icon if specified with the page. - Ignored if bTreeViewMode is FALSE. - @param bTreeImages - TRUE if the page icons should be displayed in the page tree, - FALSE if there should be no icons in the page tree. Ignored if - bTreeViewMode is FALSE. If not all of your pages are containing - icons, or if there will be empty pages (parent nodes without a - related page, you need to call SetTreeDefaultImages() to avoid - display errors. - - @return - TRUE on success or FALSE, if the window has already been created. - */ - BOOL SetTreeViewMode(BOOL bTreeViewMode = TRUE, BOOL bPageCaption = FALSE, BOOL bTreeImages = FALSE); - - /** - Specifies the width of the tree control, when the sheet is in tree - view mode. The default value (if this method is not called) is 150 - pixels. - - This method needs to be called, before DoModeal() or Create(). - Otherwise it will fail. - - @param nWidth - The width in pixels for the page tree. - - @return - TRUE on success, FALSE otherwise (if the window has already been - created). - */ - BOOL SetTreeWidth(int nWidth); - - /** - Specifies the text to be drawn on empty pages (pages for tree view - items, that are not related to a page, because they are only - parents for other items). This is only needed in tree view mode. - - The specified text can contains a single "%s" placeholder which - will be replaced with the title of the empty page. - */ - void SetEmptyPageText(LPCTSTR lpszEmptyPageText); - - /** - Allows you to specify, how the empty page message (see - SetEmptyPageText()) should be drawn. - - @param dwFormat - A combination of the DT_* flags available for the Win32-API - function DrawText(), that should be used to draw the text. - The default value is: - \code - DT_CENTER|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE - \endcode - - @return - The previous format. - */ - DWORD SetEmptyPageTextFormat(DWORD dwFormat); - - //@{ - /** - Defines the images, that should be used for pages without icons and - for empty parent nodes. The list contains exactly to images: - 1. An image that should be used for parent tree nodes, without a - page asignd. - 2. An image that should be used for pages, which are not specifying - any icons. - Standard image size is 16x16 Pixels, but if you call this method - before creating the sheet, the size of image 0 in this list will - be assumed as your preferred image size and all other icons must - have the same size. - - @param pImages - Pointer to an image list with exactly to images, that should be - used as default images. The images are copied to an internal - list, so that the given list can be deleted after this call. - @param unBitmapID - Resource identifier for the bitmap, that contains the default - images. The resource should contain exactly to images. - @param cx - Width of a singe image in pixels. - @param crMask - Color that should be interpreted as transparent. - - @return - TRUE on success, FALSE otherwise. - */ - BOOL SetTreeDefaultImages(CImageList *pImages); - BOOL SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask); - //@} - - /** - Returns a pointer to the tree control, when the sheet is in - tree view mode, NULL otherwise. - */ - CTreeCtrl* GetPageTreeControl(); - -// Public helpers -public: - //@{ - /** - This helper allows you to easily set the icon of a property page. - - This static method does nothing more, than extracting the specified - image as an icon from the given image list and assign the - icon-handle to the hIcon property of the pages PROPSHEETPAGE - structure (m_psp) and modify the structures flags, so that the - image will be recognized. - - You need to call this method for a page, before adding the page - to a property sheet. - - @important - If you are using the CImageList-version, you are responsible for - destroying the extracted icon with DestroyIcon() or the static - DestroyPageIcon() method. - - @see DestroyPageIcon() - - @param pPage - Property page to set the image for. - @param hIcon - Handle to icon that should be set for the page. - @param unIconId - Ressource identifier for the icon to set. - @param Images - Reference of the image list to extract the icon from. - @param nImage - Zero based index of the image in pImages, that should be used - as an icon. - - @return - TRUE on success, FALSE if an error occured. - */ - static BOOL SetPageIcon(CPropertyPage *pPage, HICON hIcon); - static BOOL SetPageIcon(CPropertyPage *pPage, UINT unIconId); - static BOOL SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage); - //@} - - /** - Checks, if the PSP_USEHICON flag is set in the PROPSHEETPAGE struct; - If this is the case, the flag will be removed and the icon - specified by the hIcon attribute of the PROPSHEETPAGE struct will - be destroyed using DestroyIcon(). - - @note - You only have to call DestroyIcon() for icons, that have been - created using CreateIconIndirect() (i.e. used by - CImageList::ExtractIcon()). - - @return - TRUE on success, FALSE if the PSP_USEHICON flag was not set or - if the icon handle was NULL. - */ - static BOOL DestroyPageIcon(CPropertyPage *pPage); - -// Overridable implementation helpers -protected: - /** - Will be called to generate the message, that should be displayed on - an empty page, when the sheet is in tree view mode - - This default implementation simply returns lpszEmptyPageMessage - with the optional "%s" placeholder replaced by lpszCaption. - - @param lpszEmptyPageMessage - The string, set by SetEmptyPageMessage(). This string may contain - a "%s" placeholder. - @param lpszCaption - The title of the empty page. - */ - virtual CString GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption); - - /** - Will be called during creation process, to create the CTreeCtrl - object (the object, not the window!). - - Allows you to inject your own CTreeCtrl-derived classes. - - This default implementation simply creates a CTreeCtrl with new - and returns it. - */ - virtual CTreeCtrl* CreatePageTreeObject(); - - //added for mpc-hc theming - virtual void SetTreeCtrlTheme(CTreeCtrl* ctrl); - - /** - Will be called during creation process, to create the object, that - is responsible for drawing the frame around the pages, drawing the - empty page message and the caption. - - Allows you to inject your own CPropPageFrame-derived classes. - - This default implementation simply creates a CPropPageFrameTab with - new and returns it. - */ - virtual CPropPageFrame* CreatePageFrame(); - -// Implementation helpers -protected: - /** - Moves all childs by the specified amount of pixels. - - @param nDx - Pixels to move the childs in horizontal direction (can be - negative). - @param nDy - Pixels to move the childs in vertical direction (can be - negative). - */ - void MoveChildWindows(int nDx, int nDy); - - /** - Refills the tree that contains the entries for the several pages. - */ - void RefillPageTree(); - - /** - Creates the specified path in the page tree and returns the handle - of the most child item created. - - @param lpszPath - Path of the item to create (see description of this class). - @param hParentItem - Handle of the item under which the path should be created or - TVI_ROOT to start from the root. - */ - HTREEITEM CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent = TVI_ROOT); - - /** - Splits the given path into the topmost item and the rest. See - description of this class for detailed path information. - - I.e. when given the string "Appearance::Toolbars::Customize", the - method will return "Appearance" and after the call strRest will - be "Toolbars::Customize". - */ - CString SplitPageTreePath(CString &strRest); - - /** - Tries to deactivate the current page, and hides it if successfull, - so that an empty page becomes visible. - - @return - TRUE if the current page has been deactivated successfully, - FALSE if the currently active page prevents a page change. - */ - BOOL KillActiveCurrentPage(); - - /** - Returns the page tree item, that representates the specified page - or NULL, if no such icon exists. - - @param nPage - Zero based page index, for which the item to retrieve. - @param hRoot - Item to start the search at or TVI_ROOT to search the whole - tree. - */ - HTREEITEM GetPageTreeItem(int nPage, HTREEITEM hRoot = TVI_ROOT); - - /** - Selects and shows the item, representing the specified page. - - @param nPage - Zero based page index. - - @return - TRUE on success, FALSE if no item does exist for the specified - page. - */ - BOOL SelectPageTreeItem(int nPage); - - /** - Selects and shows the tree item for the currently active page. - - @return - TRUE on success, FALSE if no item exists for the currently active - page or if it was not possible to get information about the - currently active page. - */ - BOOL SelectCurrentPageTreeItem(); - - /** - Updates the caption for the currently selected page (if the caption - is enabled). - */ - void UpdateCaption(); - - /** - Activates the previous page in the page order or the last one, if - the current one is the first. - - This method does never fail. - */ - void ActivatePreviousPage(); - - /** - Activates the next page in the page order or the first one, if the - current one is the last. - - This method does never fail. - */ - void ActivateNextPage(); - -// Overridings -protected: - //{{AFX_VIRTUAL(CTreePropSheet) - public: - virtual BOOL OnInitDialog(); - //}}AFX_VIRTUAL - -// Message handlers -protected: - //{{AFX_MSG(CTreePropSheet) - afx_msg void OnDestroy(); - //}}AFX_MSG - afx_msg LRESULT OnAddPage(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnRemovePage(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnSetCurSel(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnSetCurSelId(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnIsDialogMessage(WPARAM wParam, LPARAM lParam); - - afx_msg void OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult); - afx_msg void OnPageTreeSelChanged(NMHDR *pNotifyStruct, LRESULT *plResult); - DECLARE_MESSAGE_MAP() - -// Properties -private: - /** TRUE if we should use the tree control instead of the tab ctrl. */ - BOOL m_bTreeViewMode; - - /** The tree control */ - CTreeCtrl *m_pwndPageTree; - -protected: - /** The frame around the pages */ - CPropPageFrame *m_pFrame; - -private: - /** - TRUE, if a tree item selection by OnPageTreeSelChanged() is - performed currently. - */ - BOOL m_bPageTreeSelChangedActive; - - /** TRUE if a page caption should be displayed, FALSE otherwise. */ - BOOL m_bPageCaption; - - /** TRUE if images should be displayed in the tree. */ - BOOL m_bTreeImages; - - /** Images to be displayed in the tree control. */ - CImageList m_Images; - - /** Default images. */ - CImageList m_DefaultImages; - - /** - Message to be displayed on empty pages. May contain a "%s" - placeholder which will be replaced by the caption of the empty - page. - */ - CString m_strEmptyPageMessage; - - /** The width of the page tree control in pixels. */ - int m_nPageTreeWidth; - -// Static Properties -private: - /** The id of the tree view control, that shows the pages. */ - static const UINT s_unPageTreeId; -}; - - -} //namespace TreePropSheet - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_ +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + + +#if !defined(AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_) +#define AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "PropPageFrame.h" +#include +#include // Needed for CPropertySheet +#include // Needed for CTreeCtrl + +namespace TreePropSheet +{ + +/** +A property sheet, which can use a tree control instead of a tab +control, to give the user access to the different pages. + +You can use it exactly the same way, as a CPropertySheet object. +Simply create CPropertyPage objects and add them via AddPage() to +the sheet. If you would like to use the tree view mode (default), +you can specify the path of the pages in the tree, by their name: +The names of the pages can contain +double colons ("::"), which will specify the path of that page in the +tree control. I.e. if you have three pages with the following names: +1. _T("Appearance::Toolbars") +2. _T("Appearance::Menus") +3. _T("Directories") +the tree would look as follow: +\verbatim +Appearance +| ++-Toolbars +| ++-Menus + +Directories +\endverbatim +If you would like to use a double colon, which should not be +interpreted as a path seperator, prefix it with a backslash ("\\::"). + +To disable tree view mode and use the standard tabbed mode, call +the SetTreeViewMode() method. This also allows you, to enable page +captions and tree images for tree view mode. If you would like to +have images in the tree, but not all of your pages specify images or +there are tree view items, which are not attached to a page (only +parent items for real page items), you have to set default images +using the SetTreeDefaultImages() method -- otherwise their may appear +display errors. + +If the user selects a tree view item, which does not belong to a page, +because it is just a parent item for real page items, no page will +be displayed, instead a message will be displayed, that can be set +via SetEmptyPageText(). + +@author Sven Wiegand +*/ +class /*AFX_EXT_CLASS*/ CTreePropSheet : public CPropertySheet +{ + DECLARE_DYNAMIC(CTreePropSheet) + +// Construction/Destruction +public: + CTreePropSheet(); + CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); + CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); + virtual ~CTreePropSheet(); + +// Operations +public: + /** + Call this method, if you would like to use a tree control to browse + the pages, instead of the tab control. + + This method needs to becalled, before DoModal() or Create(). If the + window has already been created, the method will fail. + + @param bTreeViewMode + Pass TRUE to provide a tree view control instead of a tab control + to browse the pages, pass FALSE to use the normal tab control. + @param bPageCaption + TRUE if a caption should be displayed for each page. The caption + contains the page title and an icon if specified with the page. + Ignored if bTreeViewMode is FALSE. + @param bTreeImages + TRUE if the page icons should be displayed in the page tree, + FALSE if there should be no icons in the page tree. Ignored if + bTreeViewMode is FALSE. If not all of your pages are containing + icons, or if there will be empty pages (parent nodes without a + related page, you need to call SetTreeDefaultImages() to avoid + display errors. + + @return + TRUE on success or FALSE, if the window has already been created. + */ + BOOL SetTreeViewMode(BOOL bTreeViewMode = TRUE, BOOL bPageCaption = FALSE, BOOL bTreeImages = FALSE); + + /** + Specifies the width of the tree control, when the sheet is in tree + view mode. The default value (if this method is not called) is 150 + pixels. + + This method needs to be called, before DoModeal() or Create(). + Otherwise it will fail. + + @param nWidth + The width in pixels for the page tree. + + @return + TRUE on success, FALSE otherwise (if the window has already been + created). + */ + BOOL SetTreeWidth(int nWidth); + + /** + Specifies the text to be drawn on empty pages (pages for tree view + items, that are not related to a page, because they are only + parents for other items). This is only needed in tree view mode. + + The specified text can contains a single "%s" placeholder which + will be replaced with the title of the empty page. + */ + void SetEmptyPageText(LPCTSTR lpszEmptyPageText); + + /** + Allows you to specify, how the empty page message (see + SetEmptyPageText()) should be drawn. + + @param dwFormat + A combination of the DT_* flags available for the Win32-API + function DrawText(), that should be used to draw the text. + The default value is: + \code + DT_CENTER|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE + \endcode + + @return + The previous format. + */ + DWORD SetEmptyPageTextFormat(DWORD dwFormat); + + //@{ + /** + Defines the images, that should be used for pages without icons and + for empty parent nodes. The list contains exactly to images: + 1. An image that should be used for parent tree nodes, without a + page asignd. + 2. An image that should be used for pages, which are not specifying + any icons. + Standard image size is 16x16 Pixels, but if you call this method + before creating the sheet, the size of image 0 in this list will + be assumed as your preferred image size and all other icons must + have the same size. + + @param pImages + Pointer to an image list with exactly to images, that should be + used as default images. The images are copied to an internal + list, so that the given list can be deleted after this call. + @param unBitmapID + Resource identifier for the bitmap, that contains the default + images. The resource should contain exactly to images. + @param cx + Width of a singe image in pixels. + @param crMask + Color that should be interpreted as transparent. + + @return + TRUE on success, FALSE otherwise. + */ + BOOL SetTreeDefaultImages(CImageList *pImages); + BOOL SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask); + //@} + + /** + Returns a pointer to the tree control, when the sheet is in + tree view mode, NULL otherwise. + */ + CTreeCtrl* GetPageTreeControl(); + +// Public helpers +public: + //@{ + /** + This helper allows you to easily set the icon of a property page. + + This static method does nothing more, than extracting the specified + image as an icon from the given image list and assign the + icon-handle to the hIcon property of the pages PROPSHEETPAGE + structure (m_psp) and modify the structures flags, so that the + image will be recognized. + + You need to call this method for a page, before adding the page + to a property sheet. + + @important + If you are using the CImageList-version, you are responsible for + destroying the extracted icon with DestroyIcon() or the static + DestroyPageIcon() method. + + @see DestroyPageIcon() + + @param pPage + Property page to set the image for. + @param hIcon + Handle to icon that should be set for the page. + @param unIconId + Ressource identifier for the icon to set. + @param Images + Reference of the image list to extract the icon from. + @param nImage + Zero based index of the image in pImages, that should be used + as an icon. + + @return + TRUE on success, FALSE if an error occured. + */ + static BOOL SetPageIcon(CPropertyPage *pPage, HICON hIcon); + static BOOL SetPageIcon(CPropertyPage *pPage, UINT unIconId); + static BOOL SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage); + //@} + + /** + Checks, if the PSP_USEHICON flag is set in the PROPSHEETPAGE struct; + If this is the case, the flag will be removed and the icon + specified by the hIcon attribute of the PROPSHEETPAGE struct will + be destroyed using DestroyIcon(). + + @note + You only have to call DestroyIcon() for icons, that have been + created using CreateIconIndirect() (i.e. used by + CImageList::ExtractIcon()). + + @return + TRUE on success, FALSE if the PSP_USEHICON flag was not set or + if the icon handle was NULL. + */ + static BOOL DestroyPageIcon(CPropertyPage *pPage); + +// Overridable implementation helpers +protected: + /** + Will be called to generate the message, that should be displayed on + an empty page, when the sheet is in tree view mode + + This default implementation simply returns lpszEmptyPageMessage + with the optional "%s" placeholder replaced by lpszCaption. + + @param lpszEmptyPageMessage + The string, set by SetEmptyPageMessage(). This string may contain + a "%s" placeholder. + @param lpszCaption + The title of the empty page. + */ + virtual CString GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption); + + /** + Will be called during creation process, to create the CTreeCtrl + object (the object, not the window!). + + Allows you to inject your own CTreeCtrl-derived classes. + + This default implementation simply creates a CTreeCtrl with new + and returns it. + */ + virtual CTreeCtrl* CreatePageTreeObject(); + + //added for mpc-hc theming + virtual void SetTreeCtrlTheme(CTreeCtrl* ctrl); + + /** + Will be called during creation process, to create the object, that + is responsible for drawing the frame around the pages, drawing the + empty page message and the caption. + + Allows you to inject your own CPropPageFrame-derived classes. + + This default implementation simply creates a CPropPageFrameTab with + new and returns it. + */ + virtual CPropPageFrame* CreatePageFrame(); + +// Implementation helpers +protected: + /** + Moves all childs by the specified amount of pixels. + + @param nDx + Pixels to move the childs in horizontal direction (can be + negative). + @param nDy + Pixels to move the childs in vertical direction (can be + negative). + */ + void MoveChildWindows(int nDx, int nDy); + + /** + Refills the tree that contains the entries for the several pages. + */ + void RefillPageTree(); + + /** + Creates the specified path in the page tree and returns the handle + of the most child item created. + + @param lpszPath + Path of the item to create (see description of this class). + @param hParentItem + Handle of the item under which the path should be created or + TVI_ROOT to start from the root. + */ + HTREEITEM CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent = TVI_ROOT); + + /** + Splits the given path into the topmost item and the rest. See + description of this class for detailed path information. + + I.e. when given the string "Appearance::Toolbars::Customize", the + method will return "Appearance" and after the call strRest will + be "Toolbars::Customize". + */ + CString SplitPageTreePath(CString &strRest); + + /** + Tries to deactivate the current page, and hides it if successfull, + so that an empty page becomes visible. + + @return + TRUE if the current page has been deactivated successfully, + FALSE if the currently active page prevents a page change. + */ + BOOL KillActiveCurrentPage(); + + /** + Returns the page tree item, that representates the specified page + or NULL, if no such icon exists. + + @param nPage + Zero based page index, for which the item to retrieve. + @param hRoot + Item to start the search at or TVI_ROOT to search the whole + tree. + */ + HTREEITEM GetPageTreeItem(int nPage, HTREEITEM hRoot = TVI_ROOT); + + /** + Selects and shows the item, representing the specified page. + + @param nPage + Zero based page index. + + @return + TRUE on success, FALSE if no item does exist for the specified + page. + */ + BOOL SelectPageTreeItem(int nPage); + + /** + Selects and shows the tree item for the currently active page. + + @return + TRUE on success, FALSE if no item exists for the currently active + page or if it was not possible to get information about the + currently active page. + */ + BOOL SelectCurrentPageTreeItem(); + + /** + Updates the caption for the currently selected page (if the caption + is enabled). + */ + void UpdateCaption(); + + /** + Activates the previous page in the page order or the last one, if + the current one is the first. + + This method does never fail. + */ + void ActivatePreviousPage(); + + /** + Activates the next page in the page order or the first one, if the + current one is the last. + + This method does never fail. + */ + void ActivateNextPage(); + +// Overridings +protected: + //{{AFX_VIRTUAL(CTreePropSheet) + public: + virtual BOOL OnInitDialog(); + //}}AFX_VIRTUAL + +// Message handlers +protected: + //{{AFX_MSG(CTreePropSheet) + afx_msg void OnDestroy(); + //}}AFX_MSG + afx_msg LRESULT OnAddPage(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnRemovePage(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnSetCurSel(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnSetCurSelId(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnIsDialogMessage(WPARAM wParam, LPARAM lParam); + + afx_msg void OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult); + afx_msg void OnPageTreeSelChanged(NMHDR *pNotifyStruct, LRESULT *plResult); + DECLARE_MESSAGE_MAP() + +// Properties +private: + /** TRUE if we should use the tree control instead of the tab ctrl. */ + BOOL m_bTreeViewMode; + + /** The tree control */ + CTreeCtrl *m_pwndPageTree; + +protected: + /** The frame around the pages */ + CPropPageFrame *m_pFrame; + +private: + /** + TRUE, if a tree item selection by OnPageTreeSelChanged() is + performed currently. + */ + BOOL m_bPageTreeSelChangedActive; + + /** TRUE if a page caption should be displayed, FALSE otherwise. */ + BOOL m_bPageCaption; + + /** TRUE if images should be displayed in the tree. */ + BOOL m_bTreeImages; + + /** Images to be displayed in the tree control. */ + CImageList m_Images; + + /** Default images. */ + CImageList m_DefaultImages; + + /** + Message to be displayed on empty pages. May contain a "%s" + placeholder which will be replaced by the caption of the empty + page. + */ + CString m_strEmptyPageMessage; + + /** The width of the page tree control in pixels. */ + int m_nPageTreeWidth; + +// Static Properties +private: + /** The id of the tree view control, that shows the pages. */ + static const UINT s_unPageTreeId; +}; + + +} //namespace TreePropSheet + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_ diff --git a/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj b/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj index 1d2ef5681fd..a5037f90b76 100644 --- a/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj +++ b/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj @@ -1,65 +1,65 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {AB494732-EF6D-44D0-BCF8-80FF04858D10} - TreePropSheet - MFCProj - TreePropSheet - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - - - - - - - Create - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {AB494732-EF6D-44D0-BCF8-80FF04858D10} + TreePropSheet + MFCProj + TreePropSheet + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + + + + + + + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj.filters b/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj.filters index 236ef81d662..766b5176dab 100644 --- a/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj.filters +++ b/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj.filters @@ -1,41 +1,41 @@ - - - - - {669fa26f-0c7f-40c4-bc82-db7a76c85378} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {7bde8366-984f-44a0-8338-3a69a9e0511d} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {669fa26f-0c7f-40c4-bc82-db7a76c85378} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {7bde8366-984f-44a0-8338-3a69a9e0511d} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/TreePropSheet/stdafx.cpp b/src/thirdparty/TreePropSheet/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/thirdparty/TreePropSheet/stdafx.cpp +++ b/src/thirdparty/TreePropSheet/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/thirdparty/TreePropSheet/stdafx.h b/src/thirdparty/TreePropSheet/stdafx.h index fbfc4a00442..62396238601 100644 --- a/src/thirdparty/TreePropSheet/stdafx.h +++ b/src/thirdparty/TreePropSheet/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#endif - -#include -#include // MFC core and standard components +/* + * (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 . + * + */ + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +#include +#include // MFC core and standard components diff --git a/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj b/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj index c7dd043a18f..e90487408a8 100644 --- a/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj +++ b/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj @@ -1,200 +1,200 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {0D252872-7542-4232-8D02-53F9182AEE15} - Kasumi - Kasumi - - - - - StaticLibrary - - - - - - - - - - - - - - h;..\h;%(AdditionalIncludeDirectories) - _LIB;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - true - - - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - - - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0D252872-7542-4232-8D02-53F9182AEE15} + Kasumi + Kasumi + + + + + StaticLibrary + + + + + + + + + + + + + + h;..\h;%(AdditionalIncludeDirectories) + _LIB;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + true + + + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + + + + \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj.filters b/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj.filters index 3b185008f63..f3ef6873cf0 100644 --- a/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj.filters +++ b/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj.filters @@ -1,324 +1,324 @@ - - - - - {0ee6e95d-30d8-431b-a0e0-af0605aaaa63} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {e512fbf3-a14d-4853-af1c-c78f14330e75} - h;hpp;hxx;hm;inl - - - {93bf2ee2-032d-4f6c-8392-c34c36b1cebe} - asm - - - {c5b06aa4-1b08-48f7-b9af-c897dc7e5267} - - - {98a60592-632a-4eeb-9953-045c541d14a4} - .asm64 - - - {97dabd7e-4b11-43ae-beee-a7e675367b2e} - - - {b69f77b1-cab6-4c5c-9c28-736eb17ce889} - - - {8d72d2d5-c182-4c11-aa60-d0a265b0f440} - - - {8e7ccb0e-3ac7-4207-9c64-a24b5028014f} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files %28x86%29 - - - Source Files %28x86%29 - - - Source Files %28x86%29 - - - Source Files %28x86%29 - - - Source Files %28x64%29 - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Interface Header Files - - - Interface Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28AMD64%29 - - - - - - Source Data Files - - - Autogenerated Header Files - - + + + + + {0ee6e95d-30d8-431b-a0e0-af0605aaaa63} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {e512fbf3-a14d-4853-af1c-c78f14330e75} + h;hpp;hxx;hm;inl + + + {93bf2ee2-032d-4f6c-8392-c34c36b1cebe} + asm + + + {c5b06aa4-1b08-48f7-b9af-c897dc7e5267} + + + {98a60592-632a-4eeb-9953-045c541d14a4} + .asm64 + + + {97dabd7e-4b11-43ae-beee-a7e675367b2e} + + + {b69f77b1-cab6-4c5c-9c28-736eb17ce889} + + + {8d72d2d5-c182-4c11-aa60-d0a265b0f440} + + + {8e7ccb0e-3ac7-4207-9c64-a24b5028014f} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files %28x86%29 + + + Source Files %28x86%29 + + + Source Files %28x86%29 + + + Source Files %28x86%29 + + + Source Files %28x64%29 + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Interface Header Files + + + Interface Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28AMD64%29 + + + + + + Source Data Files + + + Autogenerated Header Files + + \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/h/bitutils.h b/src/thirdparty/VirtualDub/Kasumi/h/bitutils.h index 8cba85ffda0..7a0c1a359b6 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/bitutils.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/bitutils.h @@ -1,26 +1,26 @@ -#ifndef f_VD2_KASUMI_BITUTILS_H -#define f_VD2_KASUMI_BITUTILS_H - -#include - -namespace nsVDPixmapBitUtils { - inline uint32 avg_8888_11(uint32 x, uint32 y) { - return (x|y) - (((x^y)&0xfefefefe)>>1); - } - - inline uint32 avg_8888_121(uint32 x, uint32 y, uint32 z) { - return avg_8888_11(avg_8888_11(x,z), y); - } - - inline uint32 avg_0808_14641(uint32 a, uint32 b, uint32 c, uint32 d, uint32 e) { - a &= 0xff00ff; - b &= 0xff00ff; - c &= 0xff00ff; - d &= 0xff00ff; - e &= 0xff00ff; - - return (((a+e) + 4*(b+d) + 6*c + 0x080008)&0x0ff00ff0)>>4; - } -}; - -#endif +#ifndef f_VD2_KASUMI_BITUTILS_H +#define f_VD2_KASUMI_BITUTILS_H + +#include + +namespace nsVDPixmapBitUtils { + inline uint32 avg_8888_11(uint32 x, uint32 y) { + return (x|y) - (((x^y)&0xfefefefe)>>1); + } + + inline uint32 avg_8888_121(uint32 x, uint32 y, uint32 z) { + return avg_8888_11(avg_8888_11(x,z), y); + } + + inline uint32 avg_0808_14641(uint32 a, uint32 b, uint32 c, uint32 d, uint32 e) { + a &= 0xff00ff; + b &= 0xff00ff; + c &= 0xff00ff; + d &= 0xff00ff; + e &= 0xff00ff; + + return (((a+e) + 4*(b+d) + 6*c + 0x080008)&0x0ff00ff0)>>4; + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/blt_setup.h b/src/thirdparty/VirtualDub/Kasumi/h/blt_setup.h index 19b7bc62ca1..af0620dd1c6 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/blt_setup.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/blt_setup.h @@ -1,62 +1,62 @@ -#ifndef f_VD2_KASUMI_BLT_SETUP_H -#define f_VD2_KASUMI_BLT_SETUP_H - -#include -#include - -typedef void (*VDPixmapPalettedBlitterFn)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal); -typedef void (*VDPixmapChunkyBlitterFn)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); - -void VDPixmapBltDirectPalettedConversion(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h, VDPixmapPalettedBlitterFn pBlitter); - -template -void VDPixmapBlitterPalettedAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) -{ - if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) - palettedBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h, src.palette); - else - VDPixmapBltDirectPalettedConversion(dst, src, w, h, palettedBlitter); -} - -template -void VDPixmapBlitterChunkyAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) -{ - chunkyBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h); -} - -struct VDPixmapFormatSubset { -public: - VDPixmapFormatSubset() : mFormatCount(0) {} - - VDPixmapFormatSubset& operator=(int format) { - mFormatCount = 0; - mFormats[mFormatCount++] = format; - return *this; - } - - VDPixmapFormatSubset& operator,(int format) { - VDASSERT(mFormatCount < nsVDPixmap::kPixFormat_Max_Standard); - mFormats[mFormatCount++] = format; - return *this; - } - - int mFormatCount; - int mFormats[nsVDPixmap::kPixFormat_Max_Standard]; -}; - -class VDPixmapBlitterTable { -public: - void Clear(); - void AddBlitter(int srcFormat, int dstFormat, VDPixmapBlitterFn blitter); - void AddBlitter(const VDPixmapFormatSubset& srcFormats, VDPixmapFormatSubset& dstFormats, VDPixmapBlitterFn blitter); - - VDPixmapBlitterFn mTable[nsVDPixmap::kPixFormat_Max_Standard][nsVDPixmap::kPixFormat_Max_Standard]; -}; - -inline void VDPixmapBlitterTable::AddBlitter(int srcFormat, int dstFormat, VDPixmapBlitterFn blitter) { - mTable[srcFormat][dstFormat] = blitter; -} - - - -#endif +#ifndef f_VD2_KASUMI_BLT_SETUP_H +#define f_VD2_KASUMI_BLT_SETUP_H + +#include +#include + +typedef void (*VDPixmapPalettedBlitterFn)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal); +typedef void (*VDPixmapChunkyBlitterFn)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); + +void VDPixmapBltDirectPalettedConversion(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h, VDPixmapPalettedBlitterFn pBlitter); + +template +void VDPixmapBlitterPalettedAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) +{ + if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) + palettedBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h, src.palette); + else + VDPixmapBltDirectPalettedConversion(dst, src, w, h, palettedBlitter); +} + +template +void VDPixmapBlitterChunkyAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) +{ + chunkyBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h); +} + +struct VDPixmapFormatSubset { +public: + VDPixmapFormatSubset() : mFormatCount(0) {} + + VDPixmapFormatSubset& operator=(int format) { + mFormatCount = 0; + mFormats[mFormatCount++] = format; + return *this; + } + + VDPixmapFormatSubset& operator,(int format) { + VDASSERT(mFormatCount < nsVDPixmap::kPixFormat_Max_Standard); + mFormats[mFormatCount++] = format; + return *this; + } + + int mFormatCount; + int mFormats[nsVDPixmap::kPixFormat_Max_Standard]; +}; + +class VDPixmapBlitterTable { +public: + void Clear(); + void AddBlitter(int srcFormat, int dstFormat, VDPixmapBlitterFn blitter); + void AddBlitter(const VDPixmapFormatSubset& srcFormats, VDPixmapFormatSubset& dstFormats, VDPixmapBlitterFn blitter); + + VDPixmapBlitterFn mTable[nsVDPixmap::kPixFormat_Max_Standard][nsVDPixmap::kPixFormat_Max_Standard]; +}; + +inline void VDPixmapBlitterTable::AddBlitter(int srcFormat, int dstFormat, VDPixmapBlitterFn blitter) { + mTable[srcFormat][dstFormat] = blitter; +} + + + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils.h b/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils.h index ef723b3f825..ba64df6d8bd 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils.h @@ -1,23 +1,23 @@ -#ifndef f_VD2_KASUMI_BLT_SPANUTILS_H -#define f_VD2_KASUMI_BLT_SPANUTILS_H - -#include - -namespace nsVDPixmapSpanUtils { - void horiz_expand2x_centered (uint8 *dst, const uint8 *src, sint32 w); - void horiz_expand2x_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void horiz_expand4x_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void horiz_compress2x_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void horiz_compress2x_centered (uint8 *dst, const uint8 *src, sint32 w); - void horiz_compress4x_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void horiz_compress4x_centered (uint8 *dst, const uint8 *src, sint32 w); - void horiz_realign_to_centered (uint8 *dst, const uint8 *src, sint32 w); - void horiz_realign_to_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void vert_expand2x_centered (uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); - void vert_expand4x_centered (uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); - void vert_compress2x_centered_fast (uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); - void vert_compress2x_centered (uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); - void vert_compress4x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); -} - -#endif +#ifndef f_VD2_KASUMI_BLT_SPANUTILS_H +#define f_VD2_KASUMI_BLT_SPANUTILS_H + +#include + +namespace nsVDPixmapSpanUtils { + void horiz_expand2x_centered (uint8 *dst, const uint8 *src, sint32 w); + void horiz_expand2x_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void horiz_expand4x_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void horiz_compress2x_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void horiz_compress2x_centered (uint8 *dst, const uint8 *src, sint32 w); + void horiz_compress4x_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void horiz_compress4x_centered (uint8 *dst, const uint8 *src, sint32 w); + void horiz_realign_to_centered (uint8 *dst, const uint8 *src, sint32 w); + void horiz_realign_to_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void vert_expand2x_centered (uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); + void vert_expand4x_centered (uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); + void vert_compress2x_centered_fast (uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); + void vert_compress2x_centered (uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); + void vert_compress4x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); +} + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils_x86.h b/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils_x86.h index d0893558a09..56e3b763d9c 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils_x86.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils_x86.h @@ -1,35 +1,35 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_BLT_SPANUTILS_X86_H -#define f_VD2_KASUMI_BLT_SPANUTILS_X86_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -namespace nsVDPixmapSpanUtils { - void horiz_expand2x_coaligned_ISSE(uint8 *dst, const uint8 *src, sint32 w); - void horiz_expand4x_coaligned_MMX(uint8 *dst, const uint8 *src, sint32 w); - void vert_expand2x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); - void vert_expand4x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); -} - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_BLT_SPANUTILS_X86_H +#define f_VD2_KASUMI_BLT_SPANUTILS_X86_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +namespace nsVDPixmapSpanUtils { + void horiz_expand2x_coaligned_ISSE(uint8 *dst, const uint8 *src, sint32 w); + void horiz_expand4x_coaligned_MMX(uint8 *dst, const uint8 *src, sint32 w); + void vert_expand2x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); + void vert_expand4x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); +} + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages.h b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages.h index 588fda9ad19..2f76d98db4b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages.h @@ -1,80 +1,80 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_H -#define f_VD2_KASUMI_RESAMPLE_STAGES_H - -#include - -class IVDResamplerFilter; -struct VDResamplerAxis; - -class VDSteppedAllocator { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - VDSteppedAllocator(size_t initialSize = 1024); - ~VDSteppedAllocator(); - - void clear(); - void *allocate(size_type n); - -protected: - struct Block { - Block *next; - }; - - Block *mpHead; - char *mpAllocNext; - size_t mAllocLeft; - size_t mAllocNext; - size_t mAllocInit; -}; - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (common) -// -/////////////////////////////////////////////////////////////////////////// - -class IVDResamplerStage { -public: - virtual ~IVDResamplerStage() {} - -#if 0 - void *operator new(size_t n, VDSteppedAllocator& a) { - return a.allocate(n); - } - - void operator delete(void *p, VDSteppedAllocator& a) { - } - -private: - // these should NEVER be called - void operator delete(void *p) {} -#endif -}; - -class IVDResamplerSeparableRowStage2 { -public: - virtual void Init(const VDResamplerAxis& axis, uint32 srcw) = 0; - virtual void Process(void *dst, const void *src, uint32 w) = 0; -}; - -class IVDResamplerSeparableRowStage : public IVDResamplerStage { -public: - virtual IVDResamplerSeparableRowStage2 *AsRowStage2() { return NULL; } - virtual void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) = 0; - virtual int GetWindowSize() const = 0; -}; - -class IVDResamplerSeparableColStage : public IVDResamplerStage { -public: - virtual int GetWindowSize() const = 0; - virtual void Process(void *dst, const void *const *src, uint32 w, sint32 phase) = 0; -}; - -void VDResamplerGenerateTable(sint32 *dst, const IVDResamplerFilter& filter); -void VDResamplerGenerateTableF(float *dst, const IVDResamplerFilter& filter); -void VDResamplerGenerateTable2(sint32 *dst, const IVDResamplerFilter& filter, sint32 count, sint32 u, sint32 dudx); -void VDResamplerSwizzleTable(sint32 *dst, unsigned pairs); - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_H +#define f_VD2_KASUMI_RESAMPLE_STAGES_H + +#include + +class IVDResamplerFilter; +struct VDResamplerAxis; + +class VDSteppedAllocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + VDSteppedAllocator(size_t initialSize = 1024); + ~VDSteppedAllocator(); + + void clear(); + void *allocate(size_type n); + +protected: + struct Block { + Block *next; + }; + + Block *mpHead; + char *mpAllocNext; + size_t mAllocLeft; + size_t mAllocNext; + size_t mAllocInit; +}; + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (common) +// +/////////////////////////////////////////////////////////////////////////// + +class IVDResamplerStage { +public: + virtual ~IVDResamplerStage() {} + +#if 0 + void *operator new(size_t n, VDSteppedAllocator& a) { + return a.allocate(n); + } + + void operator delete(void *p, VDSteppedAllocator& a) { + } + +private: + // these should NEVER be called + void operator delete(void *p) {} +#endif +}; + +class IVDResamplerSeparableRowStage2 { +public: + virtual void Init(const VDResamplerAxis& axis, uint32 srcw) = 0; + virtual void Process(void *dst, const void *src, uint32 w) = 0; +}; + +class IVDResamplerSeparableRowStage : public IVDResamplerStage { +public: + virtual IVDResamplerSeparableRowStage2 *AsRowStage2() { return NULL; } + virtual void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) = 0; + virtual int GetWindowSize() const = 0; +}; + +class IVDResamplerSeparableColStage : public IVDResamplerStage { +public: + virtual int GetWindowSize() const = 0; + virtual void Process(void *dst, const void *const *src, uint32 w, sint32 phase) = 0; +}; + +void VDResamplerGenerateTable(sint32 *dst, const IVDResamplerFilter& filter); +void VDResamplerGenerateTableF(float *dst, const IVDResamplerFilter& filter); +void VDResamplerGenerateTable2(sint32 *dst, const IVDResamplerFilter& filter, sint32 count, sint32 u, sint32 dudx); +void VDResamplerSwizzleTable(sint32 *dst, unsigned pairs); + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_reference.h b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_reference.h index 296882ceb2a..18545c45919 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_reference.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_reference.h @@ -1,156 +1,156 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_REFERENCE_H -#define f_VD2_KASUMI_RESAMPLE_STAGES_REFERENCE_H - -#include -#include "resample_stages.h" - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (portable) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerRowStageSeparablePoint8 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparablePoint16 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparablePoint32 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparableLinear8 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - virtual void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf : public VDResamplerRowStageSeparableLinear8 { -public: - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparableLinear32 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerColStageSeparableLinear8 : public IVDResamplerSeparableColStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); -}; - -class VDResamplerColStageSeparableLinear32 : public IVDResamplerSeparableColStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); -}; - -class VDResamplerRowStageSeparableTable8 : public IVDResamplerSeparableRowStage { -public: - VDResamplerRowStageSeparableTable8(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerRowStageSeparableTable32 : public IVDResamplerSeparableRowStage { -public: - VDResamplerRowStageSeparableTable32(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerRowStageSeparableTable32F : public IVDResamplerSeparableRowStage { -public: - VDResamplerRowStageSeparableTable32F(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerRowStageSeparableTable32Fx4 : public IVDResamplerSeparableRowStage { -public: - VDResamplerRowStageSeparableTable32Fx4(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerColStageSeparableTable8 : public IVDResamplerSeparableColStage { -public: - VDResamplerColStageSeparableTable8(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerColStageSeparableTable32 : public IVDResamplerSeparableColStage { -public: - VDResamplerColStageSeparableTable32(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerColStageSeparableTable32F : public IVDResamplerSeparableColStage { -public: - VDResamplerColStageSeparableTable32F(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerColStageSeparableTable32Fx4 : public IVDResamplerSeparableColStage { -public: - VDResamplerColStageSeparableTable32Fx4(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_REFERENCE_H +#define f_VD2_KASUMI_RESAMPLE_STAGES_REFERENCE_H + +#include +#include "resample_stages.h" + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (portable) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerRowStageSeparablePoint8 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparablePoint16 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparablePoint32 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparableLinear8 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + virtual void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf : public VDResamplerRowStageSeparableLinear8 { +public: + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparableLinear32 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerColStageSeparableLinear8 : public IVDResamplerSeparableColStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); +}; + +class VDResamplerColStageSeparableLinear32 : public IVDResamplerSeparableColStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); +}; + +class VDResamplerRowStageSeparableTable8 : public IVDResamplerSeparableRowStage { +public: + VDResamplerRowStageSeparableTable8(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerRowStageSeparableTable32 : public IVDResamplerSeparableRowStage { +public: + VDResamplerRowStageSeparableTable32(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerRowStageSeparableTable32F : public IVDResamplerSeparableRowStage { +public: + VDResamplerRowStageSeparableTable32F(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerRowStageSeparableTable32Fx4 : public IVDResamplerSeparableRowStage { +public: + VDResamplerRowStageSeparableTable32Fx4(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerColStageSeparableTable8 : public IVDResamplerSeparableColStage { +public: + VDResamplerColStageSeparableTable8(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerColStageSeparableTable32 : public IVDResamplerSeparableColStage { +public: + VDResamplerColStageSeparableTable32(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerColStageSeparableTable32F : public IVDResamplerSeparableColStage { +public: + VDResamplerColStageSeparableTable32F(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerColStageSeparableTable32Fx4 : public IVDResamplerSeparableColStage { +public: + VDResamplerColStageSeparableTable32Fx4(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x64.h b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x64.h index fd719f732d0..814020b693c 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x64.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x64.h @@ -1,26 +1,26 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_X64_H -#define f_VD2_KASUMI_RESAMPLE_STAGES_X64_H - -#include "resample_stages_reference.h" - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE2, AMD64) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerRowStageSeparableTable32 { -public: - VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableTableColStageSSE2 : public VDResamplerColStageSeparableTable32 { -public: - VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_X64_H +#define f_VD2_KASUMI_RESAMPLE_STAGES_X64_H + +#include "resample_stages_reference.h" + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE2, AMD64) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerRowStageSeparableTable32 { +public: + VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableTableColStageSSE2 : public VDResamplerColStageSeparableTable32 { +public: + VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x86.h b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x86.h index 41e16b23d1a..64e3572e1b0 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x86.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x86.h @@ -1,193 +1,193 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_X86 -#define f_VD2_KASUMI_RESAMPLE_STAGES_X86 - -#include "resample_stages_reference.h" - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (scalar, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparablePointRowStageX86 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (MMX, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparablePointRowStageMMX : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableLinearRowStageMMX : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableLinearColStageMMX : public IVDResamplerSeparableColStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); -}; - -class VDResamplerSeparableCubicRowStageMMX : public IVDResamplerSeparableRowStage { -public: - VDResamplerSeparableCubicRowStageMMX(double A); - - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerSeparableCubicColStageMMX : public IVDResamplerSeparableColStage { -public: - VDResamplerSeparableCubicColStageMMX(double A); - - int GetWindowSize() const; - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerSeparableTableRowStage8MMX : public VDResamplerRowStageSeparableTable32, public IVDResamplerSeparableRowStage2 { -public: - VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter); - - IVDResamplerSeparableRowStage2 *AsRowStage2() { return this; } - - void Init(const VDResamplerAxis& axis, uint32 srcw); - void Process(void *dst, const void *src, uint32 w); - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); - -protected: - void RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw); - - int mAlignedKernelWidth; - int mAlignedKernelSize; - ptrdiff_t mRowKernelSize; - uint32 mLastSrcWidth; - uint32 mLastDstWidth; - sint32 mLastU; - sint32 mLastDUDX; - - bool mbQuadOptimizationEnabled[4]; - int mKernelSizeByOffset[4]; - ptrdiff_t mTailOffset[4]; - - vdfastvector > mRowKernels; -}; - -class VDResamplerSeparableTableRowStageMMX : public VDResamplerRowStageSeparableTable32 { -public: - VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableTableColStage8MMX : public VDResamplerColStageSeparableTable8 { -public: - VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -class VDResamplerSeparableTableColStageMMX : public VDResamplerColStageSeparableTable32 { -public: - VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (ISSE, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE : public VDResamplerRowStageSeparableLinear8 { -public: - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE2, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparableCubicColStageSSE2 : public VDResamplerSeparableCubicColStageMMX { -public: - VDResamplerSeparableCubicColStageSSE2(double A); - - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); -}; - -class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerSeparableTableRowStageMMX { -public: - VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableTableColStageSSE2 : public VDResamplerSeparableTableColStageMMX { -public: - VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE4.1, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparableTableRowStage8SSE41 : public VDResamplerRowStageSeparableTable32, public IVDResamplerSeparableRowStage2 { -public: - VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter); - - IVDResamplerSeparableRowStage2 *AsRowStage2() { return this; } - - void Init(const VDResamplerAxis& axis, uint32 srcw); - void Process(void *dst, const void *src, uint32 w); - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); - -protected: - void RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw); - - int mAlignedKernelWidth; - int mAlignedKernelSize; - ptrdiff_t mRowKernelSize; - uint32 mLastSrcWidth; - uint32 mLastDstWidth; - sint32 mLastU; - sint32 mLastDUDX; - - bool mbQuadOptimizationEnabled[8]; - int mKernelSizeByOffset[8]; - ptrdiff_t mTailOffset[8]; - - vdfastvector > mRowKernels; -}; - -class VDResamplerSeparableTableColStage8SSE41 : public VDResamplerColStageSeparableTable8 { -public: - VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_X86 +#define f_VD2_KASUMI_RESAMPLE_STAGES_X86 + +#include "resample_stages_reference.h" + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (scalar, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparablePointRowStageX86 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (MMX, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparablePointRowStageMMX : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableLinearRowStageMMX : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableLinearColStageMMX : public IVDResamplerSeparableColStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); +}; + +class VDResamplerSeparableCubicRowStageMMX : public IVDResamplerSeparableRowStage { +public: + VDResamplerSeparableCubicRowStageMMX(double A); + + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerSeparableCubicColStageMMX : public IVDResamplerSeparableColStage { +public: + VDResamplerSeparableCubicColStageMMX(double A); + + int GetWindowSize() const; + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerSeparableTableRowStage8MMX : public VDResamplerRowStageSeparableTable32, public IVDResamplerSeparableRowStage2 { +public: + VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter); + + IVDResamplerSeparableRowStage2 *AsRowStage2() { return this; } + + void Init(const VDResamplerAxis& axis, uint32 srcw); + void Process(void *dst, const void *src, uint32 w); + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); + +protected: + void RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw); + + int mAlignedKernelWidth; + int mAlignedKernelSize; + ptrdiff_t mRowKernelSize; + uint32 mLastSrcWidth; + uint32 mLastDstWidth; + sint32 mLastU; + sint32 mLastDUDX; + + bool mbQuadOptimizationEnabled[4]; + int mKernelSizeByOffset[4]; + ptrdiff_t mTailOffset[4]; + + vdfastvector > mRowKernels; +}; + +class VDResamplerSeparableTableRowStageMMX : public VDResamplerRowStageSeparableTable32 { +public: + VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableTableColStage8MMX : public VDResamplerColStageSeparableTable8 { +public: + VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +class VDResamplerSeparableTableColStageMMX : public VDResamplerColStageSeparableTable32 { +public: + VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (ISSE, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE : public VDResamplerRowStageSeparableLinear8 { +public: + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE2, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparableCubicColStageSSE2 : public VDResamplerSeparableCubicColStageMMX { +public: + VDResamplerSeparableCubicColStageSSE2(double A); + + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); +}; + +class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerSeparableTableRowStageMMX { +public: + VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableTableColStageSSE2 : public VDResamplerSeparableTableColStageMMX { +public: + VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE4.1, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparableTableRowStage8SSE41 : public VDResamplerRowStageSeparableTable32, public IVDResamplerSeparableRowStage2 { +public: + VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter); + + IVDResamplerSeparableRowStage2 *AsRowStage2() { return this; } + + void Init(const VDResamplerAxis& axis, uint32 srcw); + void Process(void *dst, const void *src, uint32 w); + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); + +protected: + void RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw); + + int mAlignedKernelWidth; + int mAlignedKernelSize; + ptrdiff_t mRowKernelSize; + uint32 mLastSrcWidth; + uint32 mLastDstWidth; + sint32 mLastU; + sint32 mLastDUDX; + + bool mbQuadOptimizationEnabled[8]; + int mKernelSizeByOffset[8]; + ptrdiff_t mTailOffset[8]; + + vdfastvector > mRowKernels; +}; + +class VDResamplerSeparableTableColStage8SSE41 : public VDResamplerColStageSeparableTable8 { +public: + VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/stdafx.h b/src/thirdparty/VirtualDub/Kasumi/h/stdafx.h index 0ba6b7915bb..8cff036ee04 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/stdafx.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/stdafx.h @@ -1,22 +1,22 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include // MPC-HC patch -#include +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include // MPC-HC patch +#include #include \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit.h index 16116609694..e2e00ed8f8c 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit.h @@ -1,95 +1,95 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_H -#define f_VD2_KASUMI_UBERBLIT_H - -#include -#include -#include -#include - -struct VDPixmap; - -enum VDPixmapFormatToken { - kVDPixType_1 = 0x00000001, - kVDPixType_2 = 0x00000002, - kVDPixType_4 = 0x00000003, - kVDPixType_8 = 0x00000004, - kVDPixType_555_LE = 0x00000005, - kVDPixType_565_LE = 0x00000006, - kVDPixType_1555_LE = 0x00000007, - kVDPixType_888 = 0x00000008, - kVDPixType_8888 = 0x00000009, - kVDPixType_16F_LE = 0x0000000A, - kVDPixType_16Fx4_LE = 0x0000000B, - kVDPixType_16F_16F_16F_LE = 0x0000000C, - kVDPixType_32F_LE = 0x0000000D, - kVDPixType_32Fx4_LE = 0x0000000E, - kVDPixType_32F_32F_32F_LE = 0x0000000F, - kVDPixType_8_8_8 = 0x00000010, - kVDPixType_B8G8_R8G8 = 0x00000011, // UYVY - kVDPixType_G8B8_G8R8 = 0x00000012, // YUYV - kVDPixType_V210 = 0x00000013, // v210 (4:2:2 10 bit) - kVDPixType_8_B8R8 = 0x00000014, // NV12 - kVDPixType_B8R8 = 0x00000015, - kVDPixType_Mask = 0x0000003F, - - kVDPixSamp_444 = 0x00000040, - kVDPixSamp_422 = 0x00000080, - kVDPixSamp_422_JPEG = 0x000000C0, - kVDPixSamp_420_MPEG2 = 0x00000100, - kVDPixSamp_420_MPEG2INT = 0x00000140, - kVDPixSamp_420_MPEG2INT1= 0x00000180, // MPEG-2 interlaced, top field - kVDPixSamp_420_MPEG2INT2= 0x000001C0, // MPEG-2 interlaced, bottom field - kVDPixSamp_420_MPEG1 = 0x00000200, - kVDPixSamp_420_DVPAL = 0x00000240, - kVDPixSamp_411 = 0x00000280, - kVDPixSamp_410 = 0x000002C0, - kVDPixSamp_Mask = 0x00000FC0, - kVDPixSamp_Bits = 6, - - kVDPixSpace_Pal = 0x00001000, -// kVDPixSpace_RGB = 0x00002000, - kVDPixSpace_BGR = 0x00003000, - kVDPixSpace_BGR_Studio = 0x00004000, - kVDPixSpace_Y_601 = 0x00005000, - kVDPixSpace_Y_709 = 0x00006000, - kVDPixSpace_Y_601_FR = 0x00007000, - kVDPixSpace_Y_709_FR = 0x00008000, - kVDPixSpace_YCC_601 = 0x0000B000, - kVDPixSpace_YCC_709 = 0x0000C000, - kVDPixSpace_YCC_601_FR = 0x0000D000, - kVDPixSpace_YCC_709_FR = 0x0000E000, - kVDPixSpace_Mask = 0x0003F000, -}; - -struct VDPixmapPlaneSamplingInfo { - int mX; ///< X offset of sample from center location, in 16ths of plane pixels. - int mY; ///< Y offset of sample from center location, in 16ths of plane pixels. - int mXBits; ///< Horizontal subsampling factor in bits. - int mYBits; ///< Vertical subsampling factor in bits. -}; - -struct VDPixmapSamplingInfo { - bool mbInterlaced; - VDPixmapPlaneSamplingInfo mPlane1Cr; - VDPixmapPlaneSamplingInfo mPlane1Cb; - VDPixmapPlaneSamplingInfo mPlane2Cr; - VDPixmapPlaneSamplingInfo mPlane2Cb; -}; - -uint32 VDPixmapGetFormatTokenFromFormat(int format); -const VDPixmapSamplingInfo& VDPixmapGetSamplingInfo(uint32 samplingToken); - -class IVDPixmapGen { -public: - virtual ~IVDPixmapGen() {} - virtual void AddWindowRequest(int minY, int maxY) = 0; - virtual void Start() = 0; - virtual sint32 GetWidth(int srcIndex) const = 0; - virtual sint32 GetHeight(int srcIndex) const = 0; - virtual bool IsStateful() const = 0; - virtual uint32 GetType(uint32 output) const = 0; - virtual const void *GetRow(sint32 y, uint32 output) = 0; - virtual void ProcessRow(void *dst, sint32 y) = 0; -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_H +#define f_VD2_KASUMI_UBERBLIT_H + +#include +#include +#include +#include + +struct VDPixmap; + +enum VDPixmapFormatToken { + kVDPixType_1 = 0x00000001, + kVDPixType_2 = 0x00000002, + kVDPixType_4 = 0x00000003, + kVDPixType_8 = 0x00000004, + kVDPixType_555_LE = 0x00000005, + kVDPixType_565_LE = 0x00000006, + kVDPixType_1555_LE = 0x00000007, + kVDPixType_888 = 0x00000008, + kVDPixType_8888 = 0x00000009, + kVDPixType_16F_LE = 0x0000000A, + kVDPixType_16Fx4_LE = 0x0000000B, + kVDPixType_16F_16F_16F_LE = 0x0000000C, + kVDPixType_32F_LE = 0x0000000D, + kVDPixType_32Fx4_LE = 0x0000000E, + kVDPixType_32F_32F_32F_LE = 0x0000000F, + kVDPixType_8_8_8 = 0x00000010, + kVDPixType_B8G8_R8G8 = 0x00000011, // UYVY + kVDPixType_G8B8_G8R8 = 0x00000012, // YUYV + kVDPixType_V210 = 0x00000013, // v210 (4:2:2 10 bit) + kVDPixType_8_B8R8 = 0x00000014, // NV12 + kVDPixType_B8R8 = 0x00000015, + kVDPixType_Mask = 0x0000003F, + + kVDPixSamp_444 = 0x00000040, + kVDPixSamp_422 = 0x00000080, + kVDPixSamp_422_JPEG = 0x000000C0, + kVDPixSamp_420_MPEG2 = 0x00000100, + kVDPixSamp_420_MPEG2INT = 0x00000140, + kVDPixSamp_420_MPEG2INT1= 0x00000180, // MPEG-2 interlaced, top field + kVDPixSamp_420_MPEG2INT2= 0x000001C0, // MPEG-2 interlaced, bottom field + kVDPixSamp_420_MPEG1 = 0x00000200, + kVDPixSamp_420_DVPAL = 0x00000240, + kVDPixSamp_411 = 0x00000280, + kVDPixSamp_410 = 0x000002C0, + kVDPixSamp_Mask = 0x00000FC0, + kVDPixSamp_Bits = 6, + + kVDPixSpace_Pal = 0x00001000, +// kVDPixSpace_RGB = 0x00002000, + kVDPixSpace_BGR = 0x00003000, + kVDPixSpace_BGR_Studio = 0x00004000, + kVDPixSpace_Y_601 = 0x00005000, + kVDPixSpace_Y_709 = 0x00006000, + kVDPixSpace_Y_601_FR = 0x00007000, + kVDPixSpace_Y_709_FR = 0x00008000, + kVDPixSpace_YCC_601 = 0x0000B000, + kVDPixSpace_YCC_709 = 0x0000C000, + kVDPixSpace_YCC_601_FR = 0x0000D000, + kVDPixSpace_YCC_709_FR = 0x0000E000, + kVDPixSpace_Mask = 0x0003F000, +}; + +struct VDPixmapPlaneSamplingInfo { + int mX; ///< X offset of sample from center location, in 16ths of plane pixels. + int mY; ///< Y offset of sample from center location, in 16ths of plane pixels. + int mXBits; ///< Horizontal subsampling factor in bits. + int mYBits; ///< Vertical subsampling factor in bits. +}; + +struct VDPixmapSamplingInfo { + bool mbInterlaced; + VDPixmapPlaneSamplingInfo mPlane1Cr; + VDPixmapPlaneSamplingInfo mPlane1Cb; + VDPixmapPlaneSamplingInfo mPlane2Cr; + VDPixmapPlaneSamplingInfo mPlane2Cb; +}; + +uint32 VDPixmapGetFormatTokenFromFormat(int format); +const VDPixmapSamplingInfo& VDPixmapGetSamplingInfo(uint32 samplingToken); + +class IVDPixmapGen { +public: + virtual ~IVDPixmapGen() {} + virtual void AddWindowRequest(int minY, int maxY) = 0; + virtual void Start() = 0; + virtual sint32 GetWidth(int srcIndex) const = 0; + virtual sint32 GetHeight(int srcIndex) const = 0; + virtual bool IsStateful() const = 0; + virtual uint32 GetType(uint32 output) const = 0; + virtual const void *GetRow(sint32 y, uint32 output) = 0; + virtual void ProcessRow(void *dst, sint32 y) = 0; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_16f.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_16f.h index 513c4fb4ff3..3ee1e2da8a5 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_16f.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_16f.h @@ -1,39 +1,39 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_16F_H -#define f_VD2_KASUMI_UBERBLIT_16F_H - -#include -#include "uberblit_base.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32F -> 16F -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_32F_To_16F : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start(); - - uint32 GetType(uint32 output) const; - -protected: - void Compute(void *dst0, sint32 y); -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 16F -> 32F -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_16F_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start(); - - uint32 GetType(uint32 output) const; - -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_16F_H +#define f_VD2_KASUMI_UBERBLIT_16F_H + +#include +#include "uberblit_base.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32F -> 16F +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_32F_To_16F : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start(); + + uint32 GetType(uint32 output) const; + +protected: + void Compute(void *dst0, sint32 y); +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 16F -> 32F +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_16F_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start(); + + uint32 GetType(uint32 output) const; + +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_base.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_base.h index e01ef73fea1..487bd3cef7e 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_base.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_base.h @@ -1,129 +1,129 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_BASE_H -#define f_VD2_KASUMI_UBERBLIT_BASE_H - -#include -#include "uberblit.h" - -class VDPixmapGenWindowBased : public IVDPixmapGen { -public: - VDPixmapGenWindowBased() - : mWindowMinDY(0xffff) - , mWindowMaxDY(-0xffff) {} - - void SetOutputSize(sint32 w, sint32 h) { - mWidth = w; - mHeight = h; - } - - void AddWindowRequest(int minDY, int maxDY) { - if (mWindowMinDY > minDY) - mWindowMinDY = minDY; - if (mWindowMaxDY < maxDY) - mWindowMaxDY = maxDY; - } - - void StartWindow(uint32 rowbytes, int outputCount = 1) { - VDASSERT(mWindowMaxDY >= mWindowMinDY); - mWindowSize = mWindowMaxDY + 1 - mWindowMinDY; - - mWindowPitch = (rowbytes + 15) & ~15; - mWindowBuffer.resize(mWindowPitch * mWindowSize * outputCount); - mWindow.resize(mWindowSize * 2); - - for(sint32 i=0; i= mWindowLastY - (sint32)mWindowSize + 1); - - if (tostep >= mWindowSize) { - mWindowLastY = y - 1; - tostep = 1; - } - - while(tostep-- > 0) { - ++mWindowLastY; - Compute(mWindow[mWindowIndex], mWindowLastY); - if (++mWindowIndex >= mWindowSize) - mWindowIndex = 0; - } - - return mWindow[y + mWindowSize - 1 - mWindowLastY + mWindowIndex]; - } - - void ProcessRow(void *dst, sint32 y) { - Compute(dst, y); - } - -protected: - virtual void Compute(void *dst0, sint32 y) = 0; - - vdfastvector mWindowBuffer; - vdfastvector mWindow; - sint32 mWindowPitch; - sint32 mWindowIndex; - sint32 mWindowMinDY; - sint32 mWindowMaxDY; - sint32 mWindowSize; - sint32 mWindowLastY; - sint32 mWidth; - sint32 mHeight; -}; - -class VDPixmapGenWindowBasedOneSource : public VDPixmapGenWindowBased { -public: - void InitSource(IVDPixmapGen *src, uint32 srcindex) { - mpSrc = src; - mSrcIndex = srcindex; - mSrcWidth = src->GetWidth(srcindex); - mSrcHeight = src->GetHeight(srcindex); - mWidth = mSrcWidth; - mHeight = mSrcHeight; - } - - void AddWindowRequest(int minDY, int maxDY) { - VDPixmapGenWindowBased::AddWindowRequest(minDY, maxDY); - mpSrc->AddWindowRequest(minDY, maxDY); - } - - void StartWindow(uint32 rowbytes, int outputCount = 1) { - mpSrc->Start(); - - VDPixmapGenWindowBased::StartWindow(rowbytes, outputCount); - } - - uint32 GetType(uint32 output) const { - return mpSrc->GetType(mSrcIndex); - } - -protected: - virtual void Compute(void *dst0, sint32 y) = 0; - - IVDPixmapGen *mpSrc; - uint32 mSrcIndex; - sint32 mSrcWidth; - sint32 mSrcHeight; -}; - -class VDPixmapGenWindowBasedOneSourceSimple : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcindex) { - InitSource(src, srcindex); - - src->AddWindowRequest(0, 0); - } -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_BASE_H +#define f_VD2_KASUMI_UBERBLIT_BASE_H + +#include +#include "uberblit.h" + +class VDPixmapGenWindowBased : public IVDPixmapGen { +public: + VDPixmapGenWindowBased() + : mWindowMinDY(0xffff) + , mWindowMaxDY(-0xffff) {} + + void SetOutputSize(sint32 w, sint32 h) { + mWidth = w; + mHeight = h; + } + + void AddWindowRequest(int minDY, int maxDY) { + if (mWindowMinDY > minDY) + mWindowMinDY = minDY; + if (mWindowMaxDY < maxDY) + mWindowMaxDY = maxDY; + } + + void StartWindow(uint32 rowbytes, int outputCount = 1) { + VDASSERT(mWindowMaxDY >= mWindowMinDY); + mWindowSize = mWindowMaxDY + 1 - mWindowMinDY; + + mWindowPitch = (rowbytes + 15) & ~15; + mWindowBuffer.resize(mWindowPitch * mWindowSize * outputCount); + mWindow.resize(mWindowSize * 2); + + for(sint32 i=0; i= mWindowLastY - (sint32)mWindowSize + 1); + + if (tostep >= mWindowSize) { + mWindowLastY = y - 1; + tostep = 1; + } + + while(tostep-- > 0) { + ++mWindowLastY; + Compute(mWindow[mWindowIndex], mWindowLastY); + if (++mWindowIndex >= mWindowSize) + mWindowIndex = 0; + } + + return mWindow[y + mWindowSize - 1 - mWindowLastY + mWindowIndex]; + } + + void ProcessRow(void *dst, sint32 y) { + Compute(dst, y); + } + +protected: + virtual void Compute(void *dst0, sint32 y) = 0; + + vdfastvector mWindowBuffer; + vdfastvector mWindow; + sint32 mWindowPitch; + sint32 mWindowIndex; + sint32 mWindowMinDY; + sint32 mWindowMaxDY; + sint32 mWindowSize; + sint32 mWindowLastY; + sint32 mWidth; + sint32 mHeight; +}; + +class VDPixmapGenWindowBasedOneSource : public VDPixmapGenWindowBased { +public: + void InitSource(IVDPixmapGen *src, uint32 srcindex) { + mpSrc = src; + mSrcIndex = srcindex; + mSrcWidth = src->GetWidth(srcindex); + mSrcHeight = src->GetHeight(srcindex); + mWidth = mSrcWidth; + mHeight = mSrcHeight; + } + + void AddWindowRequest(int minDY, int maxDY) { + VDPixmapGenWindowBased::AddWindowRequest(minDY, maxDY); + mpSrc->AddWindowRequest(minDY, maxDY); + } + + void StartWindow(uint32 rowbytes, int outputCount = 1) { + mpSrc->Start(); + + VDPixmapGenWindowBased::StartWindow(rowbytes, outputCount); + } + + uint32 GetType(uint32 output) const { + return mpSrc->GetType(mSrcIndex); + } + +protected: + virtual void Compute(void *dst0, sint32 y) = 0; + + IVDPixmapGen *mpSrc; + uint32 mSrcIndex; + sint32 mSrcWidth; + sint32 mSrcHeight; +}; + +class VDPixmapGenWindowBasedOneSourceSimple : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcindex) { + InitSource(src, srcindex); + + src->AddWindowRequest(0, 0); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_fill.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_fill.h index ba02a287711..7d3f288ebc1 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_fill.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_fill.h @@ -1,55 +1,55 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_FILL_H -#define f_VD2_KASUMI_UBERBLIT_FILL_H - -#include "uberblit.h" -#include "uberblit_base.h" - -class VDPixmapGenFill8 : public IVDPixmapGen { -public: - void Init(uint8 fill, uint32 bpr, sint32 width, sint32 height, uint32 type) { - mRow.resize(bpr, fill); - mWidth = width; - mHeight = height; - mType = type; - } - - void AddWindowRequest(int minY, int maxY) { - } - - void Start() { - } - - sint32 GetWidth(int) const { - return mWidth; - } - - sint32 GetHeight(int) const { - return mHeight; - } - - bool IsStateful() const { - return false; - } - - const void *GetRow(sint32 y, uint32 output) { - return mRow.data(); - } - - void ProcessRow(void *dst, sint32 y) { - if (!mRow.empty()) - memset(dst, mRow[0], mRow.size()); - } - - uint32 GetType(uint32 index) const { - return mType; - } - -protected: - sint32 mWidth; - sint32 mHeight; - uint32 mType; - - vdfastvector mRow; -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_FILL_H +#define f_VD2_KASUMI_UBERBLIT_FILL_H + +#include "uberblit.h" +#include "uberblit_base.h" + +class VDPixmapGenFill8 : public IVDPixmapGen { +public: + void Init(uint8 fill, uint32 bpr, sint32 width, sint32 height, uint32 type) { + mRow.resize(bpr, fill); + mWidth = width; + mHeight = height; + mType = type; + } + + void AddWindowRequest(int minY, int maxY) { + } + + void Start() { + } + + sint32 GetWidth(int) const { + return mWidth; + } + + sint32 GetHeight(int) const { + return mHeight; + } + + bool IsStateful() const { + return false; + } + + const void *GetRow(sint32 y, uint32 output) { + return mRow.data(); + } + + void ProcessRow(void *dst, sint32 y) { + if (!mRow.empty()) + memset(dst, mRow[0], mRow.size()); + } + + uint32 GetType(uint32 index) const { + return mType; + } + +protected: + sint32 mWidth; + sint32 mHeight; + uint32 mType; + + vdfastvector mRow; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_gen.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_gen.h index 20543016134..0a5809b6cab 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_gen.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_gen.h @@ -1,177 +1,177 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_GEN_H -#define f_VD2_KASUMI_UBERBLIT_GEN_H - -#include -#include "uberblit.h" - -class IVDPixmapGenSrc; -struct VDPixmapGenYCbCrBasis; - -class VDPixmapUberBlitterDirectCopy : public IVDPixmapBlitter { -public: - VDPixmapUberBlitterDirectCopy(); - ~VDPixmapUberBlitterDirectCopy(); - - void Blit(const VDPixmap& dst, const VDPixmap& src); - void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src); -}; - -class VDPixmapUberBlitter : public IVDPixmapBlitter { -public: - VDPixmapUberBlitter(); - ~VDPixmapUberBlitter(); - - void Blit(const VDPixmap& dst, const VDPixmap& src); - void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src); - -protected: - void Blit(const VDPixmap& dst, const vdrect32 *rDst); - void Blit3(const VDPixmap& dst, const vdrect32 *rDst); - void Blit3Split(const VDPixmap& dst, const vdrect32 *rDst); - void Blit3Separated(const VDPixmap& px, const vdrect32 *rDst); - void Blit2(const VDPixmap& dst, const vdrect32 *rDst); - void Blit2Separated(const VDPixmap& px, const vdrect32 *rDst); - - friend class VDPixmapUberBlitterGenerator; - - struct OutputEntry { - IVDPixmapGen *mpSrc; - int mSrcIndex; - } mOutputs[3]; - - struct SourceEntry { - IVDPixmapGenSrc *mpSrc; - int mSrcIndex; - int mSrcPlane; - int mSrcX; - int mSrcY; - }; - - typedef vdfastvector Generators; - Generators mGenerators; - - typedef vdfastvector Sources; - Sources mSources; - - bool mbIndependentChromaPlanes; - bool mbIndependentPlanes; -}; - -class VDPixmapUberBlitterGenerator { -public: - VDPixmapUberBlitterGenerator(); - ~VDPixmapUberBlitterGenerator(); - - void swap(int index); - void dup(); - void pop(); - - void ldsrc(int srcIndex, int srcPlane, int x, int y, uint32 w, uint32 h, uint32 type, uint32 bpr); - - void ldconst(uint8 fill, uint32 bpr, uint32 w, uint32 h, uint32 type); - - void extract_8in16(int offset, uint32 w, uint32 h); - void extract_8in32(int offset, uint32 w, uint32 h); - void swap_8in16(uint32 w, uint32 h, uint32 bpr); - - void conv_Pal1_to_8888(int srcIndex); - void conv_Pal2_to_8888(int srcIndex); - void conv_Pal4_to_8888(int srcIndex); - void conv_Pal8_to_8888(int srcIndex); - - void conv_555_to_8888(); - void conv_565_to_8888(); - void conv_888_to_8888(); - void conv_555_to_565(); - void conv_565_to_555(); - void conv_8888_to_X32F(); - void conv_8_to_32F(); - void conv_16F_to_32F(); - void conv_V210_to_32F(); - - void conv_8888_to_555(); - void conv_8888_to_565(); - void conv_8888_to_888(); - void conv_32F_to_8(); - void conv_X32F_to_8888(); - void conv_32F_to_16F(); - void conv_32F_to_V210(); - - void convd_8888_to_555(); - void convd_8888_to_565(); - void convd_32F_to_8(); - void convd_X32F_to_8888(); - - void interleave_B8G8_R8G8(); - void interleave_G8B8_G8R8(); - void interleave_X8R8G8B8(); - void interleave_B8R8(); - - void merge_fields(uint32 w, uint32 h, uint32 bpr); - void split_fields(uint32 bpr); - - void ycbcr601_to_rgb32(); - void ycbcr709_to_rgb32(); - void rgb32_to_ycbcr601(); - void rgb32_to_ycbcr709(); - - void ycbcr601_to_rgb32_32f(); - void ycbcr709_to_rgb32_32f(); - void rgb32_to_ycbcr601_32f(); - void rgb32_to_ycbcr709_32f(); - - void ycbcr601_to_ycbcr709(); - void ycbcr709_to_ycbcr601(); - - void ycbcr_to_rgb32_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB); - void ycbcr_to_rgb32f_generic(const VDPixmapGenYCbCrBasis& basis); - void rgb32_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB, uint32 colorSpace); - void rgb32f_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace); - void ycbcr_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basisDst, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& basisSrc, bool srcLimitedRange, uint32 colorSpace); - - void pointh(float xoffset, float xfactor, uint32 w); - void pointv(float yoffset, float yfactor, uint32 h); - void linearh(float xoffset, float xfactor, uint32 w, bool interpOnly); - void linearv(float yoffset, float yfactor, uint32 h, bool interpOnly); - void linear(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h); - void cubich(float xoffset, float xfactor, uint32 w, float splineFactor, bool interpOnly); - void cubicv(float yoffset, float yfactor, uint32 h, float splineFactor, bool interpOnly); - void cubic(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h, float splineFactor); - void lanczos3h(float xoffset, float xfactor, uint32 w); - void lanczos3v(float yoffset, float yfactor, uint32 h); - void lanczos3(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h); - - IVDPixmapBlitter *create(); - -protected: - void MarkDependency(IVDPixmapGen *dst, IVDPixmapGen *src); - - struct StackEntry { - IVDPixmapGen *mpSrc; - uint32 mSrcIndex; - - StackEntry() {} - StackEntry(IVDPixmapGen *src, uint32 index) : mpSrc(src), mSrcIndex(index) {} - }; - - vdfastvector mStack; - - typedef vdfastvector Generators; - Generators mGenerators; - - struct Dependency { - int mDstIdx; - int mSrcIdx; - }; - - vdfastvector mDependencies; - - typedef VDPixmapUberBlitter::SourceEntry SourceEntry; - vdfastvector mSources; -}; - -void VDPixmapGenerate(void *dst, ptrdiff_t pitch, sint32 bpr, sint32 height, IVDPixmapGen *gen, int genIndex); -IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmap& dst, const VDPixmap& src); -IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmapLayout& dst, const VDPixmapLayout& src); - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_GEN_H +#define f_VD2_KASUMI_UBERBLIT_GEN_H + +#include +#include "uberblit.h" + +class IVDPixmapGenSrc; +struct VDPixmapGenYCbCrBasis; + +class VDPixmapUberBlitterDirectCopy : public IVDPixmapBlitter { +public: + VDPixmapUberBlitterDirectCopy(); + ~VDPixmapUberBlitterDirectCopy(); + + void Blit(const VDPixmap& dst, const VDPixmap& src); + void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src); +}; + +class VDPixmapUberBlitter : public IVDPixmapBlitter { +public: + VDPixmapUberBlitter(); + ~VDPixmapUberBlitter(); + + void Blit(const VDPixmap& dst, const VDPixmap& src); + void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src); + +protected: + void Blit(const VDPixmap& dst, const vdrect32 *rDst); + void Blit3(const VDPixmap& dst, const vdrect32 *rDst); + void Blit3Split(const VDPixmap& dst, const vdrect32 *rDst); + void Blit3Separated(const VDPixmap& px, const vdrect32 *rDst); + void Blit2(const VDPixmap& dst, const vdrect32 *rDst); + void Blit2Separated(const VDPixmap& px, const vdrect32 *rDst); + + friend class VDPixmapUberBlitterGenerator; + + struct OutputEntry { + IVDPixmapGen *mpSrc; + int mSrcIndex; + } mOutputs[3]; + + struct SourceEntry { + IVDPixmapGenSrc *mpSrc; + int mSrcIndex; + int mSrcPlane; + int mSrcX; + int mSrcY; + }; + + typedef vdfastvector Generators; + Generators mGenerators; + + typedef vdfastvector Sources; + Sources mSources; + + bool mbIndependentChromaPlanes; + bool mbIndependentPlanes; +}; + +class VDPixmapUberBlitterGenerator { +public: + VDPixmapUberBlitterGenerator(); + ~VDPixmapUberBlitterGenerator(); + + void swap(int index); + void dup(); + void pop(); + + void ldsrc(int srcIndex, int srcPlane, int x, int y, uint32 w, uint32 h, uint32 type, uint32 bpr); + + void ldconst(uint8 fill, uint32 bpr, uint32 w, uint32 h, uint32 type); + + void extract_8in16(int offset, uint32 w, uint32 h); + void extract_8in32(int offset, uint32 w, uint32 h); + void swap_8in16(uint32 w, uint32 h, uint32 bpr); + + void conv_Pal1_to_8888(int srcIndex); + void conv_Pal2_to_8888(int srcIndex); + void conv_Pal4_to_8888(int srcIndex); + void conv_Pal8_to_8888(int srcIndex); + + void conv_555_to_8888(); + void conv_565_to_8888(); + void conv_888_to_8888(); + void conv_555_to_565(); + void conv_565_to_555(); + void conv_8888_to_X32F(); + void conv_8_to_32F(); + void conv_16F_to_32F(); + void conv_V210_to_32F(); + + void conv_8888_to_555(); + void conv_8888_to_565(); + void conv_8888_to_888(); + void conv_32F_to_8(); + void conv_X32F_to_8888(); + void conv_32F_to_16F(); + void conv_32F_to_V210(); + + void convd_8888_to_555(); + void convd_8888_to_565(); + void convd_32F_to_8(); + void convd_X32F_to_8888(); + + void interleave_B8G8_R8G8(); + void interleave_G8B8_G8R8(); + void interleave_X8R8G8B8(); + void interleave_B8R8(); + + void merge_fields(uint32 w, uint32 h, uint32 bpr); + void split_fields(uint32 bpr); + + void ycbcr601_to_rgb32(); + void ycbcr709_to_rgb32(); + void rgb32_to_ycbcr601(); + void rgb32_to_ycbcr709(); + + void ycbcr601_to_rgb32_32f(); + void ycbcr709_to_rgb32_32f(); + void rgb32_to_ycbcr601_32f(); + void rgb32_to_ycbcr709_32f(); + + void ycbcr601_to_ycbcr709(); + void ycbcr709_to_ycbcr601(); + + void ycbcr_to_rgb32_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB); + void ycbcr_to_rgb32f_generic(const VDPixmapGenYCbCrBasis& basis); + void rgb32_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB, uint32 colorSpace); + void rgb32f_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace); + void ycbcr_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basisDst, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& basisSrc, bool srcLimitedRange, uint32 colorSpace); + + void pointh(float xoffset, float xfactor, uint32 w); + void pointv(float yoffset, float yfactor, uint32 h); + void linearh(float xoffset, float xfactor, uint32 w, bool interpOnly); + void linearv(float yoffset, float yfactor, uint32 h, bool interpOnly); + void linear(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h); + void cubich(float xoffset, float xfactor, uint32 w, float splineFactor, bool interpOnly); + void cubicv(float yoffset, float yfactor, uint32 h, float splineFactor, bool interpOnly); + void cubic(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h, float splineFactor); + void lanczos3h(float xoffset, float xfactor, uint32 w); + void lanczos3v(float yoffset, float yfactor, uint32 h); + void lanczos3(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h); + + IVDPixmapBlitter *create(); + +protected: + void MarkDependency(IVDPixmapGen *dst, IVDPixmapGen *src); + + struct StackEntry { + IVDPixmapGen *mpSrc; + uint32 mSrcIndex; + + StackEntry() {} + StackEntry(IVDPixmapGen *src, uint32 index) : mpSrc(src), mSrcIndex(index) {} + }; + + vdfastvector mStack; + + typedef vdfastvector Generators; + Generators mGenerators; + + struct Dependency { + int mDstIdx; + int mSrcIdx; + }; + + vdfastvector mDependencies; + + typedef VDPixmapUberBlitter::SourceEntry SourceEntry; + vdfastvector mSources; +}; + +void VDPixmapGenerate(void *dst, ptrdiff_t pitch, sint32 bpr, sint32 height, IVDPixmapGen *gen, int genIndex); +IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmap& dst, const VDPixmap& src); +IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmapLayout& dst, const VDPixmapLayout& src); + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_input.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_input.h index bfd5ebad5d5..4fdfdb4f4c9 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_input.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_input.h @@ -1,69 +1,69 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_INPUT_H -#define f_VD2_KASUMI_UBERBLIT_INPUT_H - -#include "uberblit.h" -#include "uberblit_base.h" - -class IVDPixmapGenSrc { -public: - virtual void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) = 0; -}; - -class VDPixmapGenSrc : public IVDPixmapGen, public IVDPixmapGenSrc { -public: - void Init(sint32 width, sint32 height, uint32 type, uint32 bpr) { - mWidth = width; - mHeight = height; - mType = type; - mBpr = bpr; - } - - void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) { - mpSrc = src; - mPitch = pitch; - } - - void AddWindowRequest(int minY, int maxY) { - } - - void Start() { - } - - sint32 GetWidth(int) const { - return mWidth; - } - - sint32 GetHeight(int) const { - return mHeight; - } - - bool IsStateful() const { - return false; - } - - const void *GetRow(sint32 y, uint32 output) { - if (y < 0) - y = 0; - else if (y >= mHeight) - y = mHeight - 1; - return vdptroffset(mpSrc, mPitch*y); - } - - void ProcessRow(void *dst, sint32 y) { - memcpy(dst, GetRow(y, 0), mBpr); - } - - uint32 GetType(uint32 index) const { - return mType; - } - -protected: - const void *mpSrc; - ptrdiff_t mPitch; - size_t mBpr; - sint32 mWidth; - sint32 mHeight; - uint32 mType; -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_INPUT_H +#define f_VD2_KASUMI_UBERBLIT_INPUT_H + +#include "uberblit.h" +#include "uberblit_base.h" + +class IVDPixmapGenSrc { +public: + virtual void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) = 0; +}; + +class VDPixmapGenSrc : public IVDPixmapGen, public IVDPixmapGenSrc { +public: + void Init(sint32 width, sint32 height, uint32 type, uint32 bpr) { + mWidth = width; + mHeight = height; + mType = type; + mBpr = bpr; + } + + void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) { + mpSrc = src; + mPitch = pitch; + } + + void AddWindowRequest(int minY, int maxY) { + } + + void Start() { + } + + sint32 GetWidth(int) const { + return mWidth; + } + + sint32 GetHeight(int) const { + return mHeight; + } + + bool IsStateful() const { + return false; + } + + const void *GetRow(sint32 y, uint32 output) { + if (y < 0) + y = 0; + else if (y >= mHeight) + y = mHeight - 1; + return vdptroffset(mpSrc, mPitch*y); + } + + void ProcessRow(void *dst, sint32 y) { + memcpy(dst, GetRow(y, 0), mBpr); + } + + uint32 GetType(uint32 index) const { + return mType; + } + +protected: + const void *mpSrc; + ptrdiff_t mPitch; + size_t mBpr; + sint32 mWidth; + sint32 mHeight; + uint32 mType; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_interlace.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_interlace.h index 23adaa76b35..d5345639285 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_interlace.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_interlace.h @@ -1,123 +1,123 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_UBERBLIT_INTERLACE_H -#define f_VD2_KASUMI_UBERBLIT_INTERLACE_H - -#include "uberblit_base.h" - -class VDPixmapGen_SplitFields : public IVDPixmapGen { -public: - void AddWindowRequest(int minDY, int maxDY) { - mpSrc->AddWindowRequest(minDY*2, maxDY*2+1); - } - - void Start() { - mpSrc->Start(); - } - - sint32 GetWidth(int) const { return mWidth; } - sint32 GetHeight(int idx) const { return mHeight[idx]; } - - bool IsStateful() const { - return false; - } - - uint32 GetType(uint32 output) const { - return mpSrc->GetType(mSrcIndex); - } - - const void *GetRow(sint32 y, uint32 index) { - return mpSrc->GetRow(y+y+index, mSrcIndex); - } - - void ProcessRow(void *dst, sint32 y) { - memcpy(dst, GetRow(y, 0), mBpr); - } - - void Init(IVDPixmapGen *src, uint32 srcindex, uint32 bpr) { - mpSrc = src; - mSrcIndex = srcindex; - mBpr = bpr; - mWidth = src->GetWidth(srcindex); - - uint32 h = src->GetHeight(srcindex); - mHeight[0] = (h + 1) >> 1; - mHeight[1] = h >> 1; - } - -protected: - IVDPixmapGen *mpSrc; - uint32 mSrcIndex; - sint32 mWidth; - sint32 mHeight[2]; - uint32 mBpr; -}; - -class VDPixmapGen_MergeFields : public IVDPixmapGen { -public: - void AddWindowRequest(int minDY, int maxDY) { - mpSrc[0]->AddWindowRequest(minDY >> 1, maxDY >> 1); - mpSrc[1]->AddWindowRequest(minDY >> 1, maxDY >> 1); - } - - void Start() { - mpSrc[0]->Start(); - mpSrc[1]->Start(); - } - - sint32 GetWidth(int) const { return mWidth; } - sint32 GetHeight(int) const { return mHeight; } - - bool IsStateful() const { - return false; - } - - uint32 GetType(uint32 output) const { - return mpSrc[0]->GetType(mSrcIndex[0]); - } - - const void *GetRow(sint32 y, uint32 index) { - int srcIndex = y & 1; - return mpSrc[srcIndex]->GetRow(y >> 1, mSrcIndex[srcIndex]); - } - - void ProcessRow(void *dst, sint32 y) { - memcpy(dst, GetRow(y, 0), mBpr); - } - - void Init(IVDPixmapGen *src1, uint32 srcindex1, IVDPixmapGen *src2, uint32 srcindex2, uint32 w, uint32 h, uint32 bpr) { - mpSrc[0] = src1; - mpSrc[1] = src2; - mSrcIndex[0] = srcindex1; - mSrcIndex[1] = srcindex2; - - mWidth = w; - mHeight = h; - mBpr = bpr; - } - -protected: - IVDPixmapGen *mpSrc[2]; - uint32 mSrcIndex[2]; - sint32 mWidth; - sint32 mHeight; - uint32 mBpr; -}; - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_UBERBLIT_INTERLACE_H +#define f_VD2_KASUMI_UBERBLIT_INTERLACE_H + +#include "uberblit_base.h" + +class VDPixmapGen_SplitFields : public IVDPixmapGen { +public: + void AddWindowRequest(int minDY, int maxDY) { + mpSrc->AddWindowRequest(minDY*2, maxDY*2+1); + } + + void Start() { + mpSrc->Start(); + } + + sint32 GetWidth(int) const { return mWidth; } + sint32 GetHeight(int idx) const { return mHeight[idx]; } + + bool IsStateful() const { + return false; + } + + uint32 GetType(uint32 output) const { + return mpSrc->GetType(mSrcIndex); + } + + const void *GetRow(sint32 y, uint32 index) { + return mpSrc->GetRow(y+y+index, mSrcIndex); + } + + void ProcessRow(void *dst, sint32 y) { + memcpy(dst, GetRow(y, 0), mBpr); + } + + void Init(IVDPixmapGen *src, uint32 srcindex, uint32 bpr) { + mpSrc = src; + mSrcIndex = srcindex; + mBpr = bpr; + mWidth = src->GetWidth(srcindex); + + uint32 h = src->GetHeight(srcindex); + mHeight[0] = (h + 1) >> 1; + mHeight[1] = h >> 1; + } + +protected: + IVDPixmapGen *mpSrc; + uint32 mSrcIndex; + sint32 mWidth; + sint32 mHeight[2]; + uint32 mBpr; +}; + +class VDPixmapGen_MergeFields : public IVDPixmapGen { +public: + void AddWindowRequest(int minDY, int maxDY) { + mpSrc[0]->AddWindowRequest(minDY >> 1, maxDY >> 1); + mpSrc[1]->AddWindowRequest(minDY >> 1, maxDY >> 1); + } + + void Start() { + mpSrc[0]->Start(); + mpSrc[1]->Start(); + } + + sint32 GetWidth(int) const { return mWidth; } + sint32 GetHeight(int) const { return mHeight; } + + bool IsStateful() const { + return false; + } + + uint32 GetType(uint32 output) const { + return mpSrc[0]->GetType(mSrcIndex[0]); + } + + const void *GetRow(sint32 y, uint32 index) { + int srcIndex = y & 1; + return mpSrc[srcIndex]->GetRow(y >> 1, mSrcIndex[srcIndex]); + } + + void ProcessRow(void *dst, sint32 y) { + memcpy(dst, GetRow(y, 0), mBpr); + } + + void Init(IVDPixmapGen *src1, uint32 srcindex1, IVDPixmapGen *src2, uint32 srcindex2, uint32 w, uint32 h, uint32 bpr) { + mpSrc[0] = src1; + mpSrc[1] = src2; + mSrcIndex[0] = srcindex1; + mSrcIndex[1] = srcindex2; + + mWidth = w; + mHeight = h; + mBpr = bpr; + } + +protected: + IVDPixmapGen *mpSrc[2]; + uint32 mSrcIndex[2]; + sint32 mWidth; + sint32 mHeight; + uint32 mBpr; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_pal.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_pal.h index e3958b45856..dfa1ff7bccf 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_pal.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_pal.h @@ -1,148 +1,148 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_PAL_H -#define f_VD2_KASUMI_UBERBLIT_PAL_H - -#include "uberblit_base.h" -#include "uberblit_input.h" - -class VDPixmapGenBase_Pal_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple, public IVDPixmapGenSrc { -public: - void Start() { - StartWindow(mWidth * 4); - } - - void Init(IVDPixmapGen *src, int srcIndex) { - InitSource(src, srcIndex); - } - - void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) { - mpPal = palette; - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - const uint32 *mpPal; -}; - -class VDPixmapGen_Pal1_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - sint32 h = mHeight; - - const uint32 *pal = mpPal; - - src += (w-1) >> 3; - dst += (w-1) & ~7; - - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - - switch(wt & 7) { - do { - v = src[0]; - - case 0: dst[7] = pal[v&1]; v >>= 1; - case 7: dst[6] = pal[v&1]; v >>= 1; - case 6: dst[5] = pal[v&1]; v >>= 1; - case 5: dst[4] = pal[v&1]; v >>= 1; - case 4: dst[3] = pal[v&1]; v >>= 1; - case 3: dst[2] = pal[v&1]; v >>= 1; - case 2: dst[1] = pal[v&1]; v >>= 1; - case 1: dst[0] = pal[v&1]; v >>= 1; - - dst -= 8; - --src; - } while((wt -= 8) > 0); - } - } -}; - -class VDPixmapGen_Pal2_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - sint32 h = mHeight; - - const uint32 *pal = mpPal; - - src += (w-1) >> 2; - dst += (w-1) & ~3; - - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - - switch(wt & 3) { - do { - v = src[0]; - - case 0: dst[3] = pal[v&3]; v >>= 2; - case 3: dst[2] = pal[v&3]; v >>= 2; - case 2: dst[1] = pal[v&3]; v >>= 2; - case 1: dst[0] = pal[v&3]; v >>= 2; - - dst -= 4; - --src; - } while((wt -= 4) > 0); - } - } -}; - -class VDPixmapGen_Pal4_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - sint32 h = mHeight; - - const uint32 *pal = mpPal; - - src += (w-1) >> 1; - dst += ((w-1) & ~1); - - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - - switch(wt & 1) { - do { - v = src[0]; - - case 0: dst[1] = pal[v&15]; v >>= 4; - case 1: dst[0] = pal[v&15]; v >>= 4; - - dst -= 2; - --src; - } while((wt -= 2) > 0); - } - } -}; - -class VDPixmapGen_Pal8_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - sint32 h = mHeight; - - const uint32 *pal = mpPal; - - int wt = w; - - do { - *dst++ = pal[*src++]; - } while(--wt); - } -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_PAL_H +#define f_VD2_KASUMI_UBERBLIT_PAL_H + +#include "uberblit_base.h" +#include "uberblit_input.h" + +class VDPixmapGenBase_Pal_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple, public IVDPixmapGenSrc { +public: + void Start() { + StartWindow(mWidth * 4); + } + + void Init(IVDPixmapGen *src, int srcIndex) { + InitSource(src, srcIndex); + } + + void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) { + mpPal = palette; + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + const uint32 *mpPal; +}; + +class VDPixmapGen_Pal1_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + sint32 h = mHeight; + + const uint32 *pal = mpPal; + + src += (w-1) >> 3; + dst += (w-1) & ~7; + + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + + switch(wt & 7) { + do { + v = src[0]; + + case 0: dst[7] = pal[v&1]; v >>= 1; + case 7: dst[6] = pal[v&1]; v >>= 1; + case 6: dst[5] = pal[v&1]; v >>= 1; + case 5: dst[4] = pal[v&1]; v >>= 1; + case 4: dst[3] = pal[v&1]; v >>= 1; + case 3: dst[2] = pal[v&1]; v >>= 1; + case 2: dst[1] = pal[v&1]; v >>= 1; + case 1: dst[0] = pal[v&1]; v >>= 1; + + dst -= 8; + --src; + } while((wt -= 8) > 0); + } + } +}; + +class VDPixmapGen_Pal2_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + sint32 h = mHeight; + + const uint32 *pal = mpPal; + + src += (w-1) >> 2; + dst += (w-1) & ~3; + + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + + switch(wt & 3) { + do { + v = src[0]; + + case 0: dst[3] = pal[v&3]; v >>= 2; + case 3: dst[2] = pal[v&3]; v >>= 2; + case 2: dst[1] = pal[v&3]; v >>= 2; + case 1: dst[0] = pal[v&3]; v >>= 2; + + dst -= 4; + --src; + } while((wt -= 4) > 0); + } + } +}; + +class VDPixmapGen_Pal4_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + sint32 h = mHeight; + + const uint32 *pal = mpPal; + + src += (w-1) >> 1; + dst += ((w-1) & ~1); + + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + + switch(wt & 1) { + do { + v = src[0]; + + case 0: dst[1] = pal[v&15]; v >>= 4; + case 1: dst[0] = pal[v&15]; v >>= 4; + + dst -= 2; + --src; + } while((wt -= 2) > 0); + } + } +}; + +class VDPixmapGen_Pal8_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + sint32 h = mHeight; + + const uint32 *pal = mpPal; + + int wt = w; + + do { + *dst++ = pal[*src++]; + } while(--wt); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample.h index a3bb7e70c0e..11bfff99cb7 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample.h @@ -1,83 +1,83 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_H -#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_H - -#include -#include -#include "uberblit.h" -#include "uberblit_base.h" -#include - -class IVDResamplerSeparableRowStage; -class IVDResamplerSeparableRowStage2; -class IVDResamplerSeparableColStage; - -namespace nsVDPixmap { - enum FilterMode { - kFilterPoint, - kFilterLinear, - kFilterCubic, - kFilterLanczos3, - kFilterCount - }; -} - -class VDPixmapGenResampleRow : public VDPixmapGenWindowBasedOneSource { -public: - VDPixmapGenResampleRow(); - ~VDPixmapGenResampleRow(); - - void Init(IVDPixmapGen *src, uint32 srcIndex, uint32 width, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly); - - void Start(); - - uint32 GetType(uint32 output) const { - return mpSrc->GetType(mSrcIndex); - } - -protected: - void Compute(void *dst0, sint32 y); - void Compute8(void *dst0, sint32 y); - void Compute32(void *dst0, sint32 y); - void Compute128(void *dst0, sint32 y); - - IVDResamplerSeparableRowStage *mpRowStage; - IVDResamplerSeparableRowStage2 *mpRowStage2; - - uint32 mRowFiltW; - uint32 mBytesPerSample; - - VDResamplerAxis mAxis; - - vdblock mWindow; - void **mpAllocWindow; - vdblock > mTempSpace; -}; - -class VDPixmapGenResampleCol : public VDPixmapGenWindowBasedOneSource { -public: - VDPixmapGenResampleCol(); - ~VDPixmapGenResampleCol(); - - void Init(IVDPixmapGen *src, uint32 srcIndex, uint32 height, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly); - - void Start(); - - uint32 GetType(uint32 output) const { - return mpSrc->GetType(mSrcIndex); - } - -protected: - void Compute(void *dst0, sint32 y); - - IVDResamplerSeparableColStage *mpColStage; - - uint32 mWinSize; - uint32 mBytesPerSample; - uint32 mBytesPerRow; - - VDResamplerAxis mAxis; - - vdblock mWindow; -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_H +#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_H + +#include +#include +#include "uberblit.h" +#include "uberblit_base.h" +#include + +class IVDResamplerSeparableRowStage; +class IVDResamplerSeparableRowStage2; +class IVDResamplerSeparableColStage; + +namespace nsVDPixmap { + enum FilterMode { + kFilterPoint, + kFilterLinear, + kFilterCubic, + kFilterLanczos3, + kFilterCount + }; +} + +class VDPixmapGenResampleRow : public VDPixmapGenWindowBasedOneSource { +public: + VDPixmapGenResampleRow(); + ~VDPixmapGenResampleRow(); + + void Init(IVDPixmapGen *src, uint32 srcIndex, uint32 width, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly); + + void Start(); + + uint32 GetType(uint32 output) const { + return mpSrc->GetType(mSrcIndex); + } + +protected: + void Compute(void *dst0, sint32 y); + void Compute8(void *dst0, sint32 y); + void Compute32(void *dst0, sint32 y); + void Compute128(void *dst0, sint32 y); + + IVDResamplerSeparableRowStage *mpRowStage; + IVDResamplerSeparableRowStage2 *mpRowStage2; + + uint32 mRowFiltW; + uint32 mBytesPerSample; + + VDResamplerAxis mAxis; + + vdblock mWindow; + void **mpAllocWindow; + vdblock > mTempSpace; +}; + +class VDPixmapGenResampleCol : public VDPixmapGenWindowBasedOneSource { +public: + VDPixmapGenResampleCol(); + ~VDPixmapGenResampleCol(); + + void Init(IVDPixmapGen *src, uint32 srcIndex, uint32 height, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly); + + void Start(); + + uint32 GetType(uint32 output) const { + return mpSrc->GetType(mSrcIndex); + } + +protected: + void Compute(void *dst0, sint32 y); + + IVDResamplerSeparableColStage *mpColStage; + + uint32 mWinSize; + uint32 mBytesPerSample; + uint32 mBytesPerRow; + + VDResamplerAxis mAxis; + + vdblock mWindow; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special.h index 0f97ba1cf6b..f5ffa6c462d 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special.h @@ -1,81 +1,81 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_H -#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_H - -#include -#include -#include "uberblit.h" -#include "uberblit_base.h" - -class VDPixmapGenResampleRow_d2_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleRow_d4_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleRow_x2_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleRow_x4_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_x2_phalf_lin_u8: public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_x4_p1half_lin_u8: public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_d2_pnqrtr_lin_u8: public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_d4_pn38_lin_u8: public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_H +#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_H + +#include +#include +#include "uberblit.h" +#include "uberblit_base.h" + +class VDPixmapGenResampleRow_d2_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleRow_d4_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleRow_x2_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleRow_x4_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_x2_phalf_lin_u8: public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_x4_p1half_lin_u8: public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_d2_pnqrtr_lin_u8: public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_d4_pn38_lin_u8: public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special_x86.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special_x86.h index 6634869aaec..b49629cf24b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special_x86.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special_x86.h @@ -1,26 +1,26 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_X86_H -#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_X86_H - -#include "uberblit_resample_special.h" - -class VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE : public VDPixmapGenResampleRow_x2_p0_lin_u8 { -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleRow_x4_p0_lin_u8_MMX : public VDPixmapGenResampleRow_x4_p0_lin_u8 { -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE: public VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 { -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE: public VDPixmapGenResampleCol_d4_pn38_lin_u8 { -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_X86_H +#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_X86_H + +#include "uberblit_resample_special.h" + +class VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE : public VDPixmapGenResampleRow_x2_p0_lin_u8 { +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleRow_x4_p0_lin_u8_MMX : public VDPixmapGenResampleRow_x4_p0_lin_u8 { +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE: public VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 { +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE: public VDPixmapGenResampleCol_d4_pn38_lin_u8 { +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb.h index 21925af2a20..e1a4c5fe7b5 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb.h @@ -1,552 +1,552 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RGB_H -#define f_VD2_KASUMI_UBERBLIT_RGB_H - -#include -#include "uberblit_base.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 16-bit crossconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X1R5G5B5_To_R5G6B5 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; - } - -protected: - virtual void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 5; - - dst[i] = (uint16)px; - } - } -}; - -class VDPixmapGen_R5G6B5_To_X1R5G5B5 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 1; - - dst[i] = (uint16)px; - } - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32-bit upconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X1R5G5B5_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - virtual void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 5) & 0x070707); - } - } -}; - -class VDPixmapGen_R5G6B5_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 5) + (px_g6 >> 6)) & 0x070307); - } - } -}; - -class VDPixmapGen_R8G8B8_To_A8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_1555_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 9) & 0x7c00) + ((px >> 6) & 0x03e0) + ((px >> 3) & 0x001f); - } - } -}; - -class VDPixmapGen_X8R8G8B8_To_R5G6B5 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 8) & 0xf800) + ((px >> 5) & 0x07e0) + ((px >> 3) & 0x001f); - } - } -}; - -class VDPixmapGen_X8R8G8B8_To_R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 3); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_1555_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - static const uint32 kDitherMatrix[4][4][2]={ - { 0x00000000, 0x00000000, 0x04000400, 0x00040000, 0x01000100, 0x00010000, 0x05000500, 0x00050000 }, - { 0x06000600, 0x00060000, 0x02000200, 0x00020000, 0x07000700, 0x00070000, 0x03000300, 0x00030000 }, - { 0x01800180, 0x00018000, 0x05800580, 0x00058000, 0x00800080, 0x00008000, 0x04800480, 0x00048000 }, - { 0x07800780, 0x00078000, 0x03800380, 0x00038000, 0x06800680, 0x00068000, 0x02800280, 0x00028000 }, - }; - - const uint32 (*drow)[2] = kDitherMatrix[y & 3]; - - for(sint32 i=0; i> 17) & 0x7c00) + ((g >> 14) & 0x03e0) + ((rb >> 11) & 0x001f); - } - } -}; - -class VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - static const uint32 kDitherMatrix[4][4][2]={ - { 0x00000000, 0x00000000, 0x04000400, 0x00020000, 0x01000100, 0x00008000, 0x05000500, 0x00028000 }, - { 0x06000600, 0x00030000, 0x02000200, 0x00010000, 0x07000700, 0x00038000, 0x03000300, 0x00018000 }, - { 0x01800180, 0x0000c000, 0x05800580, 0x0002c000, 0x00800080, 0x00004000, 0x04800480, 0x00024000 }, - { 0x07800780, 0x0003c000, 0x03800380, 0x0001c000, 0x06800680, 0x00034000, 0x02800280, 0x00014000 }, - }; - - const uint32 (*drow)[2] = kDitherMatrix[y & 3]; - - for(sint32 i=0; i> 16) & 0xf800) + ((g >> 13) & 0x07e0) + ((rb >> 11) & 0x001f); - } - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32F upconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_8_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32Fx4_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - VDCPUCleanupExtensions(); - - sint32 w = mWidth; - -#define X(v) ((v) - 0x49400000) - - static const sint32 kDitherMatrix[4][4]={ - { X( 0), X( 8), X( 2), X(10), }, - { X(12), X( 4), X(14), X( 6), }, - { X( 3), X(11), X( 1), X( 9), }, - { X(15), X( 7), X(13), X( 5), }, - }; - -#undef X - - const sint32 *pDitherRow = kDitherMatrix[y & 3]; - - for(sint32 i=0; i> 4; - - if ((uint32)vb >= 0x100) - vb = (uint8)(~vb >> 31); - - dst[i] = (uint8)vb; - } - } -}; - -class VDPixmapGen_X32B32G32R32F_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - sint32 w = mWidth; - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - sint32 w = mWidth; - -#define X(v) ((v) - 0x49400000) - - static const sint32 kDitherMatrix[4][4]={ - { X( 0), X( 8), X( 2), X(10), }, - { X(12), X( 4), X(14), X( 6), }, - { X( 3), X(11), X( 1), X( 9), }, - { X(15), X( 7), X(13), X( 5), }, - }; - -#undef X - - const sint32 *pDitherRow = kDitherMatrix[y & 3]; - - for(sint32 i=0; i> 4; - sint32 vg = ((sint32)cg.i + addend) >> 4; - sint32 vb = ((sint32)cb.i + addend) >> 4; - - if ((uint32)vr >= 0x100) - vr = (uint8)(~vr >> 31); - - if ((uint32)vg >= 0x100) - vg = (uint8)(~vg >> 31); - - if ((uint32)vb >= 0x100) - vb = (uint8)(~vb >> 31); - - dst[i] = (vr << 16) + (vg << 8) + vb; - } - } -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RGB_H +#define f_VD2_KASUMI_UBERBLIT_RGB_H + +#include +#include "uberblit_base.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 16-bit crossconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X1R5G5B5_To_R5G6B5 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; + } + +protected: + virtual void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 5; + + dst[i] = (uint16)px; + } + } +}; + +class VDPixmapGen_R5G6B5_To_X1R5G5B5 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 1; + + dst[i] = (uint16)px; + } + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32-bit upconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X1R5G5B5_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + virtual void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 5) & 0x070707); + } + } +}; + +class VDPixmapGen_R5G6B5_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 5) + (px_g6 >> 6)) & 0x070307); + } + } +}; + +class VDPixmapGen_R8G8B8_To_A8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_1555_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 9) & 0x7c00) + ((px >> 6) & 0x03e0) + ((px >> 3) & 0x001f); + } + } +}; + +class VDPixmapGen_X8R8G8B8_To_R5G6B5 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 8) & 0xf800) + ((px >> 5) & 0x07e0) + ((px >> 3) & 0x001f); + } + } +}; + +class VDPixmapGen_X8R8G8B8_To_R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 3); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_1555_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + static const uint32 kDitherMatrix[4][4][2]={ + { 0x00000000, 0x00000000, 0x04000400, 0x00040000, 0x01000100, 0x00010000, 0x05000500, 0x00050000 }, + { 0x06000600, 0x00060000, 0x02000200, 0x00020000, 0x07000700, 0x00070000, 0x03000300, 0x00030000 }, + { 0x01800180, 0x00018000, 0x05800580, 0x00058000, 0x00800080, 0x00008000, 0x04800480, 0x00048000 }, + { 0x07800780, 0x00078000, 0x03800380, 0x00038000, 0x06800680, 0x00068000, 0x02800280, 0x00028000 }, + }; + + const uint32 (*drow)[2] = kDitherMatrix[y & 3]; + + for(sint32 i=0; i> 17) & 0x7c00) + ((g >> 14) & 0x03e0) + ((rb >> 11) & 0x001f); + } + } +}; + +class VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + static const uint32 kDitherMatrix[4][4][2]={ + { 0x00000000, 0x00000000, 0x04000400, 0x00020000, 0x01000100, 0x00008000, 0x05000500, 0x00028000 }, + { 0x06000600, 0x00030000, 0x02000200, 0x00010000, 0x07000700, 0x00038000, 0x03000300, 0x00018000 }, + { 0x01800180, 0x0000c000, 0x05800580, 0x0002c000, 0x00800080, 0x00004000, 0x04800480, 0x00024000 }, + { 0x07800780, 0x0003c000, 0x03800380, 0x0001c000, 0x06800680, 0x00034000, 0x02800280, 0x00014000 }, + }; + + const uint32 (*drow)[2] = kDitherMatrix[y & 3]; + + for(sint32 i=0; i> 16) & 0xf800) + ((g >> 13) & 0x07e0) + ((rb >> 11) & 0x001f); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32F upconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_8_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32Fx4_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + VDCPUCleanupExtensions(); + + sint32 w = mWidth; + +#define X(v) ((v) - 0x49400000) + + static const sint32 kDitherMatrix[4][4]={ + { X( 0), X( 8), X( 2), X(10), }, + { X(12), X( 4), X(14), X( 6), }, + { X( 3), X(11), X( 1), X( 9), }, + { X(15), X( 7), X(13), X( 5), }, + }; + +#undef X + + const sint32 *pDitherRow = kDitherMatrix[y & 3]; + + for(sint32 i=0; i> 4; + + if ((uint32)vb >= 0x100) + vb = (uint8)(~vb >> 31); + + dst[i] = (uint8)vb; + } + } +}; + +class VDPixmapGen_X32B32G32R32F_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + sint32 w = mWidth; + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + sint32 w = mWidth; + +#define X(v) ((v) - 0x49400000) + + static const sint32 kDitherMatrix[4][4]={ + { X( 0), X( 8), X( 2), X(10), }, + { X(12), X( 4), X(14), X( 6), }, + { X( 3), X(11), X( 1), X( 9), }, + { X(15), X( 7), X(13), X( 5), }, + }; + +#undef X + + const sint32 *pDitherRow = kDitherMatrix[y & 3]; + + for(sint32 i=0; i> 4; + sint32 vg = ((sint32)cg.i + addend) >> 4; + sint32 vb = ((sint32)cb.i + addend) >> 4; + + if ((uint32)vr >= 0x100) + vr = (uint8)(~vr >> 31); + + if ((uint32)vg >= 0x100) + vg = (uint8)(~vg >> 31); + + if ((uint32)vb >= 0x100) + vb = (uint8)(~vb >> 31); + + dst[i] = (vr << 16) + (vg << 8) + vb; + } + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb_x86.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb_x86.h index ececed12042..da78eeb673b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb_x86.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb_x86.h @@ -1,114 +1,114 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RGB_X86_H -#define f_VD2_KASUMI_UBERBLIT_RGB_X86_H - -#include -#include "uberblit_base.h" - -extern "C" void vdasm_pixblt_XRGB1555_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_RGB565_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_RGB565_to_XRGB1555_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_XRGB1555_to_RGB565_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_XRGB8888_to_XRGB1555_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_XRGB8888_to_RGB565_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_XRGB8888_to_RGB888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_RGB888_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 16-bit crossconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X1R5G5B5_To_R5G6B5_MMX : public VDPixmapGen_X1R5G5B5_To_R5G6B5 { -protected: - virtual void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB1555_to_RGB565_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_R5G6B5_To_X1R5G5B5_MMX : public VDPixmapGen_R5G6B5_To_X1R5G5B5 { -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_RGB565_to_XRGB1555_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32-bit upconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X1R5G5B5_To_X8R8G8B8_MMX : public VDPixmapGen_X1R5G5B5_To_X8R8G8B8 { -protected: - virtual void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB1555_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_R5G6B5_To_X8R8G8B8_MMX : public VDPixmapGen_R5G6B5_To_X8R8G8B8 { -protected: - virtual void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_RGB565_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_R8G8B8_To_X8R8G8B8_MMX : public VDPixmapGen_R8G8B8_To_A8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_RGB888_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32-bit downconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X8R8G8B8_To_X1R5G5B5_MMX : public VDPixmapGen_X8R8G8B8_To_X1R5G5B5 { -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB8888_to_XRGB1555_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_X8R8G8B8_To_R5G6B5_MMX : public VDPixmapGen_X8R8G8B8_To_R5G6B5 { -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB8888_to_RGB565_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_X8R8G8B8_To_R8G8B8_MMX : public VDPixmapGen_X8R8G8B8_To_R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB8888_to_RGB888_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RGB_X86_H +#define f_VD2_KASUMI_UBERBLIT_RGB_X86_H + +#include +#include "uberblit_base.h" + +extern "C" void vdasm_pixblt_XRGB1555_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_RGB565_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_RGB565_to_XRGB1555_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_XRGB1555_to_RGB565_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_XRGB8888_to_XRGB1555_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_XRGB8888_to_RGB565_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_XRGB8888_to_RGB888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_RGB888_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 16-bit crossconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X1R5G5B5_To_R5G6B5_MMX : public VDPixmapGen_X1R5G5B5_To_R5G6B5 { +protected: + virtual void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB1555_to_RGB565_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_R5G6B5_To_X1R5G5B5_MMX : public VDPixmapGen_R5G6B5_To_X1R5G5B5 { +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_RGB565_to_XRGB1555_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32-bit upconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X1R5G5B5_To_X8R8G8B8_MMX : public VDPixmapGen_X1R5G5B5_To_X8R8G8B8 { +protected: + virtual void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB1555_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_R5G6B5_To_X8R8G8B8_MMX : public VDPixmapGen_R5G6B5_To_X8R8G8B8 { +protected: + virtual void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_RGB565_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_R8G8B8_To_X8R8G8B8_MMX : public VDPixmapGen_R8G8B8_To_A8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_RGB888_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32-bit downconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X8R8G8B8_To_X1R5G5B5_MMX : public VDPixmapGen_X8R8G8B8_To_X1R5G5B5 { +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB8888_to_XRGB1555_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_X8R8G8B8_To_R5G6B5_MMX : public VDPixmapGen_X8R8G8B8_To_R5G6B5 { +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB8888_to_RGB565_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_X8R8G8B8_To_R8G8B8_MMX : public VDPixmapGen_X8R8G8B8_To_R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB8888_to_RGB888_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_swizzle.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_swizzle.h index a87fe1f5cf9..66aa7b6b87b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_swizzle.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_swizzle.h @@ -1,343 +1,343 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2008 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_UBERBLIT_SWIZZLE_H -#define f_VD2_KASUMI_UBERBLIT_SWIZZLE_H - -#include -#include "uberblit_base.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// generic converters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_Swap8In16 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *gen, int srcIndex, uint32 w, uint32 h, uint32 bpr); - void Start(); - - uint32 GetType(uint32 index) const; - -protected: - void Compute(void *dst0, sint32 y); - - uint32 mRowLength; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32-bit deinterleavers -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_8In16 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *gen, int srcIndex, int offset, uint32 w, uint32 h) { - InitSource(gen, srcIndex); - mOffset = offset; - SetOutputSize(w, h); - gen->AddWindowRequest(0, 0); - } - - void Start() { - StartWindow(mWidth); - } - - uint32 GetType(uint32 index) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; - } - -protected: - void Compute(void *dst0, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex) + mOffset; - uint8 *dst = (uint8 *)dst0; - sint32 w = mWidth; - for(sint32 x=0; xAddWindowRequest(0, 0); - } - - void Start() { - StartWindow(mWidth); - } - - uint32 GetType(uint32 index) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; - } - -protected: - void Compute(void *dst0, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex) + mOffset; - uint8 *dst = (uint8 *)dst0; - sint32 w = mWidth; - for(sint32 x=0; xGetWidth(srcindexY); - mHeight = srcY->GetHeight(srcindexY); - - srcY->AddWindowRequest(0, 0); - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); - } - - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(((mWidth + 1) & ~1) * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_B8G8_R8G8; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *)dst0; - const uint8 *VDRESTRICT srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - sint32 w = mWidth >> 1; - for(sint32 x=0; xGetWidth(srcindexY); - mHeight = srcY->GetHeight(srcindexY); - - srcY->AddWindowRequest(0, 0); - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); - } - - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(((mWidth + 1) & ~1) * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_G8B8_G8R8; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 * VDRESTRICT dst = (uint8 *)dst0; - const uint8 *VDRESTRICT srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - sint32 w2 = mWidth >> 1; - for(sint32 x=0; xGetWidth(srcindexY); - mHeight = srcY->GetHeight(srcindexY); - - srcY->AddWindowRequest(0, 0); - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); - } - - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - for(sint32 x=0; x +#include "uberblit_base.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// generic converters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_Swap8In16 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *gen, int srcIndex, uint32 w, uint32 h, uint32 bpr); + void Start(); + + uint32 GetType(uint32 index) const; + +protected: + void Compute(void *dst0, sint32 y); + + uint32 mRowLength; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32-bit deinterleavers +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_8In16 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *gen, int srcIndex, int offset, uint32 w, uint32 h) { + InitSource(gen, srcIndex); + mOffset = offset; + SetOutputSize(w, h); + gen->AddWindowRequest(0, 0); + } + + void Start() { + StartWindow(mWidth); + } + + uint32 GetType(uint32 index) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; + } + +protected: + void Compute(void *dst0, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex) + mOffset; + uint8 *dst = (uint8 *)dst0; + sint32 w = mWidth; + for(sint32 x=0; xAddWindowRequest(0, 0); + } + + void Start() { + StartWindow(mWidth); + } + + uint32 GetType(uint32 index) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; + } + +protected: + void Compute(void *dst0, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex) + mOffset; + uint8 *dst = (uint8 *)dst0; + sint32 w = mWidth; + for(sint32 x=0; xGetWidth(srcindexY); + mHeight = srcY->GetHeight(srcindexY); + + srcY->AddWindowRequest(0, 0); + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); + } + + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(((mWidth + 1) & ~1) * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_B8G8_R8G8; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *)dst0; + const uint8 *VDRESTRICT srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + sint32 w = mWidth >> 1; + for(sint32 x=0; xGetWidth(srcindexY); + mHeight = srcY->GetHeight(srcindexY); + + srcY->AddWindowRequest(0, 0); + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); + } + + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(((mWidth + 1) & ~1) * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_G8B8_G8R8; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 * VDRESTRICT dst = (uint8 *)dst0; + const uint8 *VDRESTRICT srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + sint32 w2 = mWidth >> 1; + for(sint32 x=0; xGetWidth(srcindexY); + mHeight = srcY->GetHeight(srcindexY); + + srcY->AddWindowRequest(0, 0); + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); + } + + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + for(sint32 x=0; x -#include "uberblit_base.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32F -> V210 -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_32F_To_V210 : public VDPixmapGenWindowBased { -public: - void Init(IVDPixmapGen *srcR, uint32 srcindexR, IVDPixmapGen *srcG, uint32 srcindexG, IVDPixmapGen *srcB, uint32 srcindexB) { - mpSrcR = srcR; - mSrcIndexR = srcindexR; - mpSrcG = srcG; - mSrcIndexG = srcindexG; - mpSrcB = srcB; - mSrcIndexB = srcindexB; - mWidth = srcG->GetWidth(srcindexG); - mHeight = srcG->GetHeight(srcindexG); - - srcR->AddWindowRequest(0, 0); - srcG->AddWindowRequest(0, 0); - srcB->AddWindowRequest(0, 0); - } - - void Start() { - mpSrcR->Start(); - mpSrcG->Start(); - mpSrcB->Start(); - - int qw = (mWidth + 47) / 48; - StartWindow(qw * 128); - } - - uint32 GetType(uint32 output) const { - return (mpSrcG->GetType(mSrcIndexG) & ~kVDPixType_Mask) | kVDPixType_V210; - } - -protected: - void Compute(void *dst0, sint32 y); - - IVDPixmapGen *mpSrcR; - uint32 mSrcIndexR; - IVDPixmapGen *mpSrcG; - uint32 mSrcIndexG; - IVDPixmapGen *mpSrcB; - uint32 mSrcIndexB; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// V210 -> 32F -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_V210_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start(); - const void *GetRow(sint32 y, uint32 index); - - sint32 GetWidth(int index) const; - uint32 GetType(uint32 output) const; - -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif // f_VD2_KASUMI_UBERBLIT_V210_H +#ifndef f_VD2_KASUMI_UBERBLIT_V210_H +#define f_VD2_KASUMI_UBERBLIT_V210_H + +#include +#include "uberblit_base.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32F -> V210 +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_32F_To_V210 : public VDPixmapGenWindowBased { +public: + void Init(IVDPixmapGen *srcR, uint32 srcindexR, IVDPixmapGen *srcG, uint32 srcindexG, IVDPixmapGen *srcB, uint32 srcindexB) { + mpSrcR = srcR; + mSrcIndexR = srcindexR; + mpSrcG = srcG; + mSrcIndexG = srcindexG; + mpSrcB = srcB; + mSrcIndexB = srcindexB; + mWidth = srcG->GetWidth(srcindexG); + mHeight = srcG->GetHeight(srcindexG); + + srcR->AddWindowRequest(0, 0); + srcG->AddWindowRequest(0, 0); + srcB->AddWindowRequest(0, 0); + } + + void Start() { + mpSrcR->Start(); + mpSrcG->Start(); + mpSrcB->Start(); + + int qw = (mWidth + 47) / 48; + StartWindow(qw * 128); + } + + uint32 GetType(uint32 output) const { + return (mpSrcG->GetType(mSrcIndexG) & ~kVDPixType_Mask) | kVDPixType_V210; + } + +protected: + void Compute(void *dst0, sint32 y); + + IVDPixmapGen *mpSrcR; + uint32 mSrcIndexR; + IVDPixmapGen *mpSrcG; + uint32 mSrcIndexG; + IVDPixmapGen *mpSrcB; + uint32 mSrcIndexB; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// V210 -> 32F +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_V210_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start(); + const void *GetRow(sint32 y, uint32 index); + + sint32 GetWidth(int index) const; + uint32 GetType(uint32 output) const; + +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif // f_VD2_KASUMI_UBERBLIT_V210_H diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_ycbcr.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_ycbcr.h index d6ad5a6a7b4..bdd965165ad 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_ycbcr.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_ycbcr.h @@ -1,600 +1,600 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_YCBCR_H -#define f_VD2_KASUMI_UBERBLIT_YCBCR_H - -#include -#include -#include -#include "uberblit.h" -#include "uberblit_base.h" - -class VDPixmapGenYCbCrToRGBBase : public VDPixmapGenWindowBased { -public: - void Init(IVDPixmapGen *srcCr, uint32 srcindexCr, IVDPixmapGen *srcY, uint32 srcindexY, IVDPixmapGen *srcCb, uint32 srcindexCb) { - mpSrcY = srcY; - mSrcIndexY = srcindexY; - mpSrcCb = srcCb; - mSrcIndexCb = srcindexCb; - mpSrcCr = srcCr; - mSrcIndexCr = srcindexCr; - mWidth = srcY->GetWidth(srcindexY); - mHeight = srcY->GetHeight(srcindexY); - - srcY->AddWindowRequest(0, 0); - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); - } - - -protected: - IVDPixmapGen *mpSrcY; - uint32 mSrcIndexY; - IVDPixmapGen *mpSrcCb; - uint32 mSrcIndexCb; - IVDPixmapGen *mpSrcCr; - uint32 mSrcIndexCr; -}; - -class VDPixmapGenYCbCrToRGB32Base : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 4); - } -}; - - -class VDPixmapGenYCbCrToRGB32FBase : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 16); - } -}; - - -class VDPixmapGenRGB32ToYCbCrBase : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcindex) { - InitSource(src, srcindex); - } - - void Start() { - StartWindow(mWidth, 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; - } -}; - -class VDPixmapGenRGB32FToYCbCrBase : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcindex) { - InitSource(src, srcindex); - } - - void Start() { - StartWindow(mWidth * sizeof(float), 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Rec.601 converters -// -// -->Kr=0.299; Kb=0.114; Z=0; S=255; L = [Kr 1-Kr-Kb Kb]; Y = [219*(L-Z)/S 16]; U = [112*([0 0 1]-L)/((1-Kb)*S) 128]; V = -// [112*([1 0 0]-L)/((1-Kr)*S) 128]; M = [Y; U; V; 0 0 0 1]; disp(M); disp(inv(M)); -// -// ! 0.2567882 0.5041294 0.0979059 16. ! -// ! - 0.1482229 - 0.2909928 0.4392157 128. ! -// ! 0.4392157 - 0.3677883 - 0.0714274 128. ! -// ! 0. 0. 0. 1. ! -// -// ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! -// ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! -// ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! -// ! 0. 0. 0. 1. ! -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGenYCbCr601ToRGB32 : public VDPixmapGenYCbCrToRGB32Base { -public: - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; - } - -protected: - virtual void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_601; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - for(sint32 i=0; iround(inv([1 0 0 0; 0 1 0 0; 0 0 1 0; -16 -128 -128 1] * [1.1643828 1.1643828 1.1643828 0; 1.5960273 -0.8129688 0 0; - // 0 -0.3917617 2.0172305 0; 0 0 0 1]) .* 65536) - // ans = - // - // ! 16829. 28784. - 9714. 0. ! - // ! 33039. - 24103. - 19071. 0. ! - // ! 6416. - 4681. 28784. 0. ! - // ! 1048576. 8388608. 8388608. 65536. ! - - *dstCr++ = (28784*r - 24103*g - 4681*b + 8388608 + 32768) >> 16; - *dstY ++ = (16829*r + 33039*g + 6416*b + 1048576 + 32768) >> 16; - *dstCb++ = (-9714*r - 19071*g + 28784*b + 8388608 + 32768) >> 16; - } - } -}; - -class VDPixmapGenRGB32FToYCbCr601 : public VDPixmapGenRGB32FToYCbCrBase { -public: - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_601; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dstCb = (float *)dst0; - float *dstY = dstCb + mWindowPitch; - float *dstCr = dstY + mWindowPitch; - - const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iKr=0.2126; Kb=0.0722; Z=0; S=255; L = [Kr 1-Kr-Kb Kb]; Y = [219*(L-Z)/S 16]; U = [112*([0 0 1]-L)/((1-Kb)*S) 128]; V -// = [112*([1 0 0]-L)/((1-Kr)*S) 128]; M = [Y; U; V; 0 0 0 1]; disp(M); disp(inv(M)); -// -// ! 0.1825859 0.6142306 0.0620071 16. ! -// ! - 0.1006437 - 0.3385720 0.4392157 128. ! -// ! 0.4392157 - 0.3989422 - 0.0402735 128. ! -// ! 0. 0. 0. 1. ! -// -// ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! -// ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! -// ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! -// ! 0. 0. 0. 1. ! -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGenYCbCr709ToRGB32 : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; - } - -protected: - virtual void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iStart(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 16); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - for(sint32 i=0; i> 16; - *dstY ++ = (11966*r + 40254*g + 4064*b + 1048576 + 32768) >> 16; - *dstCb++ = (-6596*r - 22189*g + 28784*b + 8388608 + 32768) >> 16; - } - } -}; - -class VDPixmapGenRGB32FToYCbCr709 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcindex) { - InitSource(src, srcindex); - } - - void Start() { - StartWindow(mWidth * sizeof(float), 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dstCr = (float *)dst0; - float *dstY = dstCr + mWindowPitch; - float *dstCb = dstY + mWindowPitch; - - const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; i Rec.709 converters -// -// Rec.601 to Rec.709: -// -// 1. - 0.1155497 - 0.2079376 41.406386 -// 0 1.0186397 0.1146180 - 17.056983 -// 0 0.0750494 1.0253271 - 12.848195 -// -// Rec.709 to Rec.601: -// -// 1. 0.0993117 0.1916995 - 37.249435 -// 0 0.9898538 - 0.1106525 15.462234 -// 0 - 0.0724530 0.9833978 11.399058 -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGenYCbCr601ToYCbCr709 : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth, 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 ypos) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(ypos, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - for(sint32 i=0; i> 16); - *dstCb++ = (66758*cb + 7512*cr - 1117846 + 32768) >> 16; - *dstCr++ = (4918*cb + 67196*cr - 842019 + 32768) >> 16; - } - } -}; - -class VDPixmapGenYCbCr709ToYCbCr601 : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth, 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 ypos) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(ypos, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - for(sint32 i=0; i> 16); - *dstCb++ = (64871*cb - 7252*cr + 1013376 + 32768) >> 16; - *dstCr++ = (-4748*cb + 64448*cr + 747008 + 32768) >> 16; - } - } -}; - -class VDPixmapGenYCbCr601ToYCbCr709_32F : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * sizeof(float), 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 ypos) { - float *dstCr = (float *)dst0; - float *dstY = vdptroffset(dstCr, mWindowPitch); - float *dstCb = vdptroffset(dstY, mWindowPitch); - - const float *srcY = (const float *)mpSrcY->GetRow(ypos, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iStart(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * sizeof(float), 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 ypos) { - float *dstCr = (float *)dst0; - float *dstY = vdptroffset(dstCr, mWindowPitch); - float *dstCb = vdptroffset(dstY, mWindowPitch); - - const float *srcY = (const float *)mpSrcY->GetRow(ypos, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; i +#include +#include +#include "uberblit.h" +#include "uberblit_base.h" + +class VDPixmapGenYCbCrToRGBBase : public VDPixmapGenWindowBased { +public: + void Init(IVDPixmapGen *srcCr, uint32 srcindexCr, IVDPixmapGen *srcY, uint32 srcindexY, IVDPixmapGen *srcCb, uint32 srcindexCb) { + mpSrcY = srcY; + mSrcIndexY = srcindexY; + mpSrcCb = srcCb; + mSrcIndexCb = srcindexCb; + mpSrcCr = srcCr; + mSrcIndexCr = srcindexCr; + mWidth = srcY->GetWidth(srcindexY); + mHeight = srcY->GetHeight(srcindexY); + + srcY->AddWindowRequest(0, 0); + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); + } + + +protected: + IVDPixmapGen *mpSrcY; + uint32 mSrcIndexY; + IVDPixmapGen *mpSrcCb; + uint32 mSrcIndexCb; + IVDPixmapGen *mpSrcCr; + uint32 mSrcIndexCr; +}; + +class VDPixmapGenYCbCrToRGB32Base : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 4); + } +}; + + +class VDPixmapGenYCbCrToRGB32FBase : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 16); + } +}; + + +class VDPixmapGenRGB32ToYCbCrBase : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcindex) { + InitSource(src, srcindex); + } + + void Start() { + StartWindow(mWidth, 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; + } +}; + +class VDPixmapGenRGB32FToYCbCrBase : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcindex) { + InitSource(src, srcindex); + } + + void Start() { + StartWindow(mWidth * sizeof(float), 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Rec.601 converters +// +// -->Kr=0.299; Kb=0.114; Z=0; S=255; L = [Kr 1-Kr-Kb Kb]; Y = [219*(L-Z)/S 16]; U = [112*([0 0 1]-L)/((1-Kb)*S) 128]; V = +// [112*([1 0 0]-L)/((1-Kr)*S) 128]; M = [Y; U; V; 0 0 0 1]; disp(M); disp(inv(M)); +// +// ! 0.2567882 0.5041294 0.0979059 16. ! +// ! - 0.1482229 - 0.2909928 0.4392157 128. ! +// ! 0.4392157 - 0.3677883 - 0.0714274 128. ! +// ! 0. 0. 0. 1. ! +// +// ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! +// ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! +// ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! +// ! 0. 0. 0. 1. ! +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGenYCbCr601ToRGB32 : public VDPixmapGenYCbCrToRGB32Base { +public: + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; + } + +protected: + virtual void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_601; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + for(sint32 i=0; iround(inv([1 0 0 0; 0 1 0 0; 0 0 1 0; -16 -128 -128 1] * [1.1643828 1.1643828 1.1643828 0; 1.5960273 -0.8129688 0 0; + // 0 -0.3917617 2.0172305 0; 0 0 0 1]) .* 65536) + // ans = + // + // ! 16829. 28784. - 9714. 0. ! + // ! 33039. - 24103. - 19071. 0. ! + // ! 6416. - 4681. 28784. 0. ! + // ! 1048576. 8388608. 8388608. 65536. ! + + *dstCr++ = (28784*r - 24103*g - 4681*b + 8388608 + 32768) >> 16; + *dstY ++ = (16829*r + 33039*g + 6416*b + 1048576 + 32768) >> 16; + *dstCb++ = (-9714*r - 19071*g + 28784*b + 8388608 + 32768) >> 16; + } + } +}; + +class VDPixmapGenRGB32FToYCbCr601 : public VDPixmapGenRGB32FToYCbCrBase { +public: + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_601; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dstCb = (float *)dst0; + float *dstY = dstCb + mWindowPitch; + float *dstCr = dstY + mWindowPitch; + + const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iKr=0.2126; Kb=0.0722; Z=0; S=255; L = [Kr 1-Kr-Kb Kb]; Y = [219*(L-Z)/S 16]; U = [112*([0 0 1]-L)/((1-Kb)*S) 128]; V +// = [112*([1 0 0]-L)/((1-Kr)*S) 128]; M = [Y; U; V; 0 0 0 1]; disp(M); disp(inv(M)); +// +// ! 0.1825859 0.6142306 0.0620071 16. ! +// ! - 0.1006437 - 0.3385720 0.4392157 128. ! +// ! 0.4392157 - 0.3989422 - 0.0402735 128. ! +// ! 0. 0. 0. 1. ! +// +// ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! +// ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! +// ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! +// ! 0. 0. 0. 1. ! +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGenYCbCr709ToRGB32 : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; + } + +protected: + virtual void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iStart(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 16); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + for(sint32 i=0; i> 16; + *dstY ++ = (11966*r + 40254*g + 4064*b + 1048576 + 32768) >> 16; + *dstCb++ = (-6596*r - 22189*g + 28784*b + 8388608 + 32768) >> 16; + } + } +}; + +class VDPixmapGenRGB32FToYCbCr709 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcindex) { + InitSource(src, srcindex); + } + + void Start() { + StartWindow(mWidth * sizeof(float), 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dstCr = (float *)dst0; + float *dstY = dstCr + mWindowPitch; + float *dstCb = dstY + mWindowPitch; + + const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; i Rec.709 converters +// +// Rec.601 to Rec.709: +// +// 1. - 0.1155497 - 0.2079376 41.406386 +// 0 1.0186397 0.1146180 - 17.056983 +// 0 0.0750494 1.0253271 - 12.848195 +// +// Rec.709 to Rec.601: +// +// 1. 0.0993117 0.1916995 - 37.249435 +// 0 0.9898538 - 0.1106525 15.462234 +// 0 - 0.0724530 0.9833978 11.399058 +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGenYCbCr601ToYCbCr709 : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth, 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 ypos) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(ypos, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + for(sint32 i=0; i> 16); + *dstCb++ = (66758*cb + 7512*cr - 1117846 + 32768) >> 16; + *dstCr++ = (4918*cb + 67196*cr - 842019 + 32768) >> 16; + } + } +}; + +class VDPixmapGenYCbCr709ToYCbCr601 : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth, 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 ypos) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(ypos, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + for(sint32 i=0; i> 16); + *dstCb++ = (64871*cb - 7252*cr + 1013376 + 32768) >> 16; + *dstCr++ = (-4748*cb + 64448*cr + 747008 + 32768) >> 16; + } + } +}; + +class VDPixmapGenYCbCr601ToYCbCr709_32F : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * sizeof(float), 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 ypos) { + float *dstCr = (float *)dst0; + float *dstY = vdptroffset(dstCr, mWindowPitch); + float *dstCb = vdptroffset(dstY, mWindowPitch); + + const float *srcY = (const float *)mpSrcY->GetRow(ypos, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iStart(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * sizeof(float), 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 ypos) { + float *dstCr = (float *)dst0; + float *dstY = vdptroffset(dstCr, mWindowPitch); + float *dstCb = vdptroffset(dstY, mWindowPitch); + + const float *srcY = (const float *)mpSrcY->GetRow(ypos, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; i -#include "uberblit.h" -#include "uberblit_ycbcr.h" - -extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); - -class VDPixmapGenYCbCr601ToRGB32_MMX : public VDPixmapGenYCbCr601ToRGB32 { -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(dst, srcY, srcCb, srcCr, mWidth); - } -}; - -class VDPixmapGenRGB32ToYCbCr601_SSE2 : public VDPixmapGenRGB32ToYCbCr601 { -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_YCBCR_X86_H +#define f_VD2_KASUMI_UBERBLIT_YCBCR_X86_H + +#include +#include "uberblit.h" +#include "uberblit_ycbcr.h" + +extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); + +class VDPixmapGenYCbCr601ToRGB32_MMX : public VDPixmapGenYCbCr601ToRGB32 { +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(dst, srcY, srcCb, srcCr, mWidth); + } +}; + +class VDPixmapGenRGB32ToYCbCr601_SSE2 : public VDPixmapGenRGB32ToYCbCr601 { +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a64_resample.asm64 b/src/thirdparty/VirtualDub/Kasumi/source/a64_resample.asm64 index e6de1eabf02..91c676fe220 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a64_resample.asm64 +++ b/src/thirdparty/VirtualDub/Kasumi/source/a64_resample.asm64 @@ -1,620 +1,620 @@ -; VirtualDub - Video processing and capture application -; Graphics support library -; Copyright (C) 1998-2004 Avery Lee -; -; This program 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 2 of the License, or -; (at your option) any later version. -; -; This program 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, write to the Free Software -; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -; - - default rel - - segment .rdata, align=16 - - align 16 -roundval dq 0000200000002000h, 0000200000002000h - - - segment .text - - -%macro VDSAVE 1-* - - %rep %0 - %rotate -1 - push %1 - [pushreg %1] - %endrep - -%endmacro - -%macro VDRESTORE 1-* - - %rep %0 - pop %1 - - %rotate 1 - %endrep - -%endmacro - -%macro VDSAVEXMM128 2 -%assign %%count %2 + 1 - %1 -%assign %%stkoffset 0 -%assign %%reg %1 - - sub rsp, %%count*16+8 - [allocstack %%count*16] - - %rep %%count - movdqa oword [rsp+%%stkoffset], xmm %+ %%reg - [savexmm128 xmm %+ %%reg, %%stkoffset] - - %assign %%stkoffset %%stkoffset + 16 - %assign %%reg %%reg + 1 - %endrep -%endmacro - -%macro VDRESTOREXMM128 2 -%assign %%count %2+1-%1 -%assign %%stkoffset %%count*16 -%assign %%reg %2 - - %rep %%count - %assign %%stkoffset %%stkoffset-16 - movdqa xmm %+ %%reg, oword [rsp+%%stkoffset] - - %assign %%reg %%reg-1 - %endrep - - add rsp, %%count*16+8 -%endmacro - -;------------------------------------------------------------------------- -; -; long vdasm_resize_table_row_SSE2( -; Pixel *out, // rcx -; Pixel *in, // rdx -; int *filter, // r8 -; int filter_width, // r9d -; PixDim w, // [rsp+40] -; long accum, // [rsp+48] -; long frac); // [rsp+56] -; - global vdasm_resize_table_row_SSE2 -proc_frame vdasm_resize_table_row_SSE2 - - VDSAVE rbx, rsi, rdi, rbp, r12, r13, r14, r15 - VDSAVEXMM128 6, 15 -end_prolog - - .parms equ rsp+168+64 - - mov r10d, dword [.parms+40] - shl r10, 2 - add rcx, r10 - neg r10 - shl r9d, 2 ;filter_width <<= 2 - - movaps xmm6, oword [roundval] - pxor xmm5, xmm5 - mov rsi, rdx - shr rsi, 2 - - mov edi, [.parms+48] - mov eax, edi - shl edi, 16 - sar rax, 16 - add rsi, rax - mov ebp, [.parms+56] - movsxd r11, ebp - shl ebp, 16 - sar r11, 16 - - ;register map - ; - ;eax temp coefficient pair counter - ;rbx temp coefficient pointer - ;rcx destination - ;rdx temp source - ;rsi source/4 - ;edi accumulator - ;ebp fractional increment - ;r8 filter - ;r9 filter_width*4 - ;r10 -width*4 - ;r11 integral increment - ;r12 - ;r13 - ;r14 - ;r15 - - cmp r9d, 16 - jz .accel_4coeff - cmp r9d, 24 - jz .accel_6coeff - - test r9d, 8 - jz .pixelloop_even_pairs - cmp r9d, 8 - jnz .pixelloop_odd_pairs - -.pixelloop_single_pairs: - mov eax, edi - shr eax, 24 - imul eax, r9d - - lea rdx, [rsi*4] - - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - punpcklbw xmm0, xmm1 - punpcklbw xmm0, xmm5 - movq xmm1, qword [r8+rax] - pshufd xmm1, xmm1, 01000100b - pmaddwd xmm0, xmm1 - - movdqa xmm4, xmm6 - paddd xmm4, xmm0 - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_single_pairs - jmp .xit - -.pixelloop_odd_pairs: - movdqa xmm4, xmm6 - - mov eax, edi - shr eax, 24 - imul eax, r9d - lea rbx, [r8+rax] - - lea rdx, [rsi*4] - lea rax, [r9-8] -.coeffloop_odd_pairs: - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - movd xmm2, dword [rdx+8] ;xmm2 = p2 - movd xmm3, dword [rdx+12] ;xmm3 = p3 - add rdx, 16 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - movq xmm1, qword [rbx] - movq xmm3, qword [rbx+8] - add rbx, 16 - pshufd xmm1, xmm1, 01000100b - pshufd xmm3, xmm3, 01000100b - pmaddwd xmm0, xmm1 - pmaddwd xmm2, xmm3 - paddd xmm0, xmm2 - paddd xmm4, xmm0 - sub eax, 16 - jnz .coeffloop_odd_pairs - - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - punpcklbw xmm0, xmm1 - punpcklbw xmm0, xmm5 - movq xmm1, qword [rbx] - pshufd xmm1, xmm1, 01000100b - pmaddwd xmm0, xmm1 - paddd xmm4, xmm0 - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_odd_pairs - jmp .xit - -.pixelloop_even_pairs: - movdqa xmm4, xmm6 - - mov eax, edi - shr eax, 24 - imul eax, r9d - lea rbx, [r8+rax] - - lea rdx, [rsi*4] - mov eax, r9d -.coeffloop_even_pairs: - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - movd xmm2, dword [rdx+8] ;xmm2 = p2 - movd xmm3, dword [rdx+12] ;xmm3 = p3 - add rdx, 16 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - movq xmm1, qword [rbx] - movq xmm3, qword [rbx+8] - add rbx, 16 - pshufd xmm1, xmm1, 01000100b - pshufd xmm3, xmm3, 01000100b - pmaddwd xmm0, xmm1 - pmaddwd xmm2, xmm3 - paddd xmm0, xmm2 - paddd xmm4, xmm0 - sub eax, 16 - jnz .coeffloop_even_pairs - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_even_pairs - -.xit: - VDRESTOREXMM128 6, 15 - VDRESTORE rbx, rsi, rdi, rbp, r12, r13, r14, r15 - ret - -.accel_4coeff: -.pixelloop_4coeff: - pxor xmm5, xmm5 - movdqa xmm4, xmm6 - - mov eax, 0ff000000h - lea rdx, [rsi*4] - and eax, edi - shr eax, 20 - lea rbx, [r8+rax] - - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - movd xmm2, dword [rdx+8] ;xmm2 = p2 - movd xmm3, dword [rdx+12] ;xmm3 = p3 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - movq xmm1, qword [rbx] - movq xmm3, qword [rbx+8] - pshufd xmm1, xmm1, 01000100b - pshufd xmm3, xmm3, 01000100b - pmaddwd xmm0, xmm1 - pmaddwd xmm2, xmm3 - paddd xmm0, xmm2 - paddd xmm4, xmm0 - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_4coeff - jmp .xit - -.accel_6coeff: -.pixelloop_6coeff: - pxor xmm5, xmm5 - movdqa xmm4, xmm6 - - lea rdx, [rsi*4] - mov eax, edi - shr eax, 24 - lea rax, [rax+rax*2] - lea rbx, [r8+rax*8] - - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - movd xmm2, dword [rdx+8] ;xmm2 = p2 - movd xmm3, dword [rdx+12] ;xmm3 = p3 - movd xmm8, dword [rdx+16] ;xmm6 = p4 - movd xmm9, dword [rdx+20] ;xmm7 = p5 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm8, xmm9 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - punpcklbw xmm8, xmm5 - movq xmm1, qword [rbx] - movq xmm3, qword [rbx+8] - movq xmm9, qword [rbx+16] - pshufd xmm1, xmm1, 01000100b - pshufd xmm3, xmm3, 01000100b - pshufd xmm9, xmm9, 01000100b - pmaddwd xmm0, xmm1 - pmaddwd xmm2, xmm3 - pmaddwd xmm8, xmm9 - paddd xmm0, xmm2 - paddd xmm4, xmm0 - paddd xmm4, xmm8 - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_6coeff - jmp .xit -endproc_frame - - -;-------------------------------------------------------------------------- -; -; vdasm_resize_table_col_SSE2( -; uint32 *dst, // rcx -; const uint32 *const *srcs, // rdx -; int *filter, // r8 -; int filter_width, // r9d -; PixDim w, // [rsp+40] -> r10d -; ); -; - global vdasm_resize_table_col_SSE2 -proc_frame vdasm_resize_table_col_SSE2 - VDSAVE rbx, rsi, rdi, rbp, r12, r13, r14, r15 - VDSAVEXMM128 6, 15 -end_prolog - - .parms equ rsp+168+64 - - mov r10d, [.parms+40] ;r10d = w - - pxor xmm5, xmm5 - movdqa xmm4, oword [roundval] - xor rbx, rbx ;rbx = source offset - - cmp r9d, 4 - jz .accel_4coeff - cmp r9d, 6 - jz .accel_6coeff - - shr r9d, 1 ;r9d = filter pair count - -.pixelloop: - mov rax, rdx ;rax = row pointer table - mov rdi, r8 ;rdi = filter - mov r11d, r9d ;r11d = filter width counter - movdqa xmm2, xmm4 -.coeffloop: - mov rsi, [rax] - - movd xmm0, dword [rsi+rbx] - - mov rsi, [rax+8] - add rax, 16 - - movd xmm1, dword [rsi+rbx] - punpcklbw xmm0, xmm1 - - punpcklbw xmm0, xmm5 - - movq xmm1, qword [rdi] - pshufd xmm1, xmm1, 01000100b - - pmaddwd xmm0, xmm1 - - paddd xmm2, xmm0 - - add rdi,8 - - sub r11d,1 - jne .coeffloop - - psrad xmm2,14 - packssdw xmm2,xmm2 - add rbx,4 - packuswb xmm2,xmm2 - - movd dword [rcx],xmm2 - add rcx,4 - sub r10d,1 - jne .pixelloop - -.xit: - VDRESTOREXMM128 6, 15 - VDRESTORE rbx, rsi, rdi, rbp, r12, r13, r14, r15 - ret - -.accel_4coeff: - mov r12, [rdx] - mov r13, [rdx+8] - mov r14, [rdx+16] - mov r15, [rdx+24] - movq xmm8, qword [r8] - punpcklqdq xmm8, xmm8 - movq xmm9, qword [r8+8] - punpcklqdq xmm9, xmm9 - - sub r10d, 1 - jc .oddpixel_4coeff -.pixelloop_4coeff: - movq xmm0, qword [r12+rbx] - movq xmm1, qword [r13+rbx] - movq xmm2, qword [r14+rbx] - movq xmm3, qword [r15+rbx] - - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - - punpcklbw xmm0, xmm5 - punpckhbw xmm1, xmm5 - punpcklbw xmm2, xmm5 - punpckhbw xmm3, xmm5 - - pmaddwd xmm0, xmm8 - pmaddwd xmm1, xmm8 - pmaddwd xmm2, xmm9 - pmaddwd xmm3, xmm9 - - paddd xmm0, xmm4 - paddd xmm1, xmm4 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - - psrad xmm0, 14 - psrad xmm1, 14 - packssdw xmm0, xmm1 - packuswb xmm0, xmm0 - - movq qword [rcx], xmm0 - add rcx, 8 - add rbx, 8 - sub r10d, 2 - ja .pixelloop_4coeff - jnz .xit -.oddpixel_4coeff: - movd xmm0, dword [r12+rbx] - movd xmm1, dword [r13+rbx] - movd xmm2, dword [r14+rbx] - movd xmm3, dword [r15+rbx] - - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - - pmaddwd xmm0, xmm8 - pmaddwd xmm2, xmm9 - - paddd xmm0, xmm4 - paddd xmm0, xmm2 - - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - - movd dword [rcx], xmm0 - - jmp .xit - -.accel_6coeff: - mov r12, [rdx] - mov r13, [rdx+8] - mov r14, [rdx+16] - mov r15, [rdx+24] - mov rsi, [rdx+32] - mov rdx, [rdx+40] - movq xmm10, qword [r8] - punpcklqdq xmm10, xmm10 - movq xmm11, qword [r8+8] - punpcklqdq xmm11, xmm11 - movq xmm12, qword [r8+16] - punpcklqdq xmm12, xmm12 - - sub r10d, 1 - jc .oddpixel_6coeff -.pixelloop_6coeff: - movq xmm0, qword [r12+rbx] - movq xmm1, qword [r13+rbx] - movq xmm2, qword [r14+rbx] - movq xmm3, qword [r15+rbx] - movq xmm8, qword [rsi+rbx] - movq xmm9, qword [rdx+rbx] - - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm8, xmm9 - - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - movdqa xmm9, xmm8 - - punpcklbw xmm0, xmm5 - punpckhbw xmm1, xmm5 - punpcklbw xmm2, xmm5 - punpckhbw xmm3, xmm5 - punpcklbw xmm8, xmm5 - punpckhbw xmm9, xmm5 - - pmaddwd xmm0, xmm10 - pmaddwd xmm1, xmm10 - pmaddwd xmm2, xmm11 - pmaddwd xmm3, xmm11 - pmaddwd xmm8, xmm12 - pmaddwd xmm9, xmm12 - - paddd xmm0, xmm4 - paddd xmm1, xmm4 - paddd xmm2, xmm8 - paddd xmm3, xmm9 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - - psrad xmm0, 14 - psrad xmm1, 14 - packssdw xmm0, xmm1 - packuswb xmm0, xmm0 - - movq qword [rcx], xmm0 - add rcx, 8 - add rbx, 8 - sub r10d, 2 - ja .pixelloop_6coeff - jnz .xit -.oddpixel_6coeff: - movd xmm0, dword [r12+rbx] - movd xmm1, dword [r13+rbx] - movd xmm2, dword [r14+rbx] - movd xmm3, dword [r15+rbx] - movd xmm8, dword [rsi+rbx] - movd xmm9, dword [rdx+rbx] - - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm8, xmm9 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - punpcklbw xmm8, xmm5 - - pmaddwd xmm0, xmm10 - pmaddwd xmm2, xmm11 - pmaddwd xmm8, xmm12 - - paddd xmm0, xmm4 - paddd xmm2, xmm8 - paddd xmm0, xmm2 - - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - - movd dword [rcx], xmm0 - - jmp .xit -endproc_frame - - end +; VirtualDub - Video processing and capture application +; Graphics support library +; Copyright (C) 1998-2004 Avery Lee +; +; This program 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 2 of the License, or +; (at your option) any later version. +; +; This program 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, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +; + + default rel + + segment .rdata, align=16 + + align 16 +roundval dq 0000200000002000h, 0000200000002000h + + + segment .text + + +%macro VDSAVE 1-* + + %rep %0 + %rotate -1 + push %1 + [pushreg %1] + %endrep + +%endmacro + +%macro VDRESTORE 1-* + + %rep %0 + pop %1 + + %rotate 1 + %endrep + +%endmacro + +%macro VDSAVEXMM128 2 +%assign %%count %2 + 1 - %1 +%assign %%stkoffset 0 +%assign %%reg %1 + + sub rsp, %%count*16+8 + [allocstack %%count*16] + + %rep %%count + movdqa oword [rsp+%%stkoffset], xmm %+ %%reg + [savexmm128 xmm %+ %%reg, %%stkoffset] + + %assign %%stkoffset %%stkoffset + 16 + %assign %%reg %%reg + 1 + %endrep +%endmacro + +%macro VDRESTOREXMM128 2 +%assign %%count %2+1-%1 +%assign %%stkoffset %%count*16 +%assign %%reg %2 + + %rep %%count + %assign %%stkoffset %%stkoffset-16 + movdqa xmm %+ %%reg, oword [rsp+%%stkoffset] + + %assign %%reg %%reg-1 + %endrep + + add rsp, %%count*16+8 +%endmacro + +;------------------------------------------------------------------------- +; +; long vdasm_resize_table_row_SSE2( +; Pixel *out, // rcx +; Pixel *in, // rdx +; int *filter, // r8 +; int filter_width, // r9d +; PixDim w, // [rsp+40] +; long accum, // [rsp+48] +; long frac); // [rsp+56] +; + global vdasm_resize_table_row_SSE2 +proc_frame vdasm_resize_table_row_SSE2 + + VDSAVE rbx, rsi, rdi, rbp, r12, r13, r14, r15 + VDSAVEXMM128 6, 15 +end_prolog + + .parms equ rsp+168+64 + + mov r10d, dword [.parms+40] + shl r10, 2 + add rcx, r10 + neg r10 + shl r9d, 2 ;filter_width <<= 2 + + movaps xmm6, oword [roundval] + pxor xmm5, xmm5 + mov rsi, rdx + shr rsi, 2 + + mov edi, [.parms+48] + mov eax, edi + shl edi, 16 + sar rax, 16 + add rsi, rax + mov ebp, [.parms+56] + movsxd r11, ebp + shl ebp, 16 + sar r11, 16 + + ;register map + ; + ;eax temp coefficient pair counter + ;rbx temp coefficient pointer + ;rcx destination + ;rdx temp source + ;rsi source/4 + ;edi accumulator + ;ebp fractional increment + ;r8 filter + ;r9 filter_width*4 + ;r10 -width*4 + ;r11 integral increment + ;r12 + ;r13 + ;r14 + ;r15 + + cmp r9d, 16 + jz .accel_4coeff + cmp r9d, 24 + jz .accel_6coeff + + test r9d, 8 + jz .pixelloop_even_pairs + cmp r9d, 8 + jnz .pixelloop_odd_pairs + +.pixelloop_single_pairs: + mov eax, edi + shr eax, 24 + imul eax, r9d + + lea rdx, [rsi*4] + + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + punpcklbw xmm0, xmm1 + punpcklbw xmm0, xmm5 + movq xmm1, qword [r8+rax] + pshufd xmm1, xmm1, 01000100b + pmaddwd xmm0, xmm1 + + movdqa xmm4, xmm6 + paddd xmm4, xmm0 + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_single_pairs + jmp .xit + +.pixelloop_odd_pairs: + movdqa xmm4, xmm6 + + mov eax, edi + shr eax, 24 + imul eax, r9d + lea rbx, [r8+rax] + + lea rdx, [rsi*4] + lea rax, [r9-8] +.coeffloop_odd_pairs: + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + movd xmm2, dword [rdx+8] ;xmm2 = p2 + movd xmm3, dword [rdx+12] ;xmm3 = p3 + add rdx, 16 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + movq xmm1, qword [rbx] + movq xmm3, qword [rbx+8] + add rbx, 16 + pshufd xmm1, xmm1, 01000100b + pshufd xmm3, xmm3, 01000100b + pmaddwd xmm0, xmm1 + pmaddwd xmm2, xmm3 + paddd xmm0, xmm2 + paddd xmm4, xmm0 + sub eax, 16 + jnz .coeffloop_odd_pairs + + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + punpcklbw xmm0, xmm1 + punpcklbw xmm0, xmm5 + movq xmm1, qword [rbx] + pshufd xmm1, xmm1, 01000100b + pmaddwd xmm0, xmm1 + paddd xmm4, xmm0 + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_odd_pairs + jmp .xit + +.pixelloop_even_pairs: + movdqa xmm4, xmm6 + + mov eax, edi + shr eax, 24 + imul eax, r9d + lea rbx, [r8+rax] + + lea rdx, [rsi*4] + mov eax, r9d +.coeffloop_even_pairs: + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + movd xmm2, dword [rdx+8] ;xmm2 = p2 + movd xmm3, dword [rdx+12] ;xmm3 = p3 + add rdx, 16 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + movq xmm1, qword [rbx] + movq xmm3, qword [rbx+8] + add rbx, 16 + pshufd xmm1, xmm1, 01000100b + pshufd xmm3, xmm3, 01000100b + pmaddwd xmm0, xmm1 + pmaddwd xmm2, xmm3 + paddd xmm0, xmm2 + paddd xmm4, xmm0 + sub eax, 16 + jnz .coeffloop_even_pairs + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_even_pairs + +.xit: + VDRESTOREXMM128 6, 15 + VDRESTORE rbx, rsi, rdi, rbp, r12, r13, r14, r15 + ret + +.accel_4coeff: +.pixelloop_4coeff: + pxor xmm5, xmm5 + movdqa xmm4, xmm6 + + mov eax, 0ff000000h + lea rdx, [rsi*4] + and eax, edi + shr eax, 20 + lea rbx, [r8+rax] + + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + movd xmm2, dword [rdx+8] ;xmm2 = p2 + movd xmm3, dword [rdx+12] ;xmm3 = p3 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + movq xmm1, qword [rbx] + movq xmm3, qword [rbx+8] + pshufd xmm1, xmm1, 01000100b + pshufd xmm3, xmm3, 01000100b + pmaddwd xmm0, xmm1 + pmaddwd xmm2, xmm3 + paddd xmm0, xmm2 + paddd xmm4, xmm0 + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_4coeff + jmp .xit + +.accel_6coeff: +.pixelloop_6coeff: + pxor xmm5, xmm5 + movdqa xmm4, xmm6 + + lea rdx, [rsi*4] + mov eax, edi + shr eax, 24 + lea rax, [rax+rax*2] + lea rbx, [r8+rax*8] + + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + movd xmm2, dword [rdx+8] ;xmm2 = p2 + movd xmm3, dword [rdx+12] ;xmm3 = p3 + movd xmm8, dword [rdx+16] ;xmm6 = p4 + movd xmm9, dword [rdx+20] ;xmm7 = p5 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm8, xmm9 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + punpcklbw xmm8, xmm5 + movq xmm1, qword [rbx] + movq xmm3, qword [rbx+8] + movq xmm9, qword [rbx+16] + pshufd xmm1, xmm1, 01000100b + pshufd xmm3, xmm3, 01000100b + pshufd xmm9, xmm9, 01000100b + pmaddwd xmm0, xmm1 + pmaddwd xmm2, xmm3 + pmaddwd xmm8, xmm9 + paddd xmm0, xmm2 + paddd xmm4, xmm0 + paddd xmm4, xmm8 + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_6coeff + jmp .xit +endproc_frame + + +;-------------------------------------------------------------------------- +; +; vdasm_resize_table_col_SSE2( +; uint32 *dst, // rcx +; const uint32 *const *srcs, // rdx +; int *filter, // r8 +; int filter_width, // r9d +; PixDim w, // [rsp+40] -> r10d +; ); +; + global vdasm_resize_table_col_SSE2 +proc_frame vdasm_resize_table_col_SSE2 + VDSAVE rbx, rsi, rdi, rbp, r12, r13, r14, r15 + VDSAVEXMM128 6, 15 +end_prolog + + .parms equ rsp+168+64 + + mov r10d, [.parms+40] ;r10d = w + + pxor xmm5, xmm5 + movdqa xmm4, oword [roundval] + xor rbx, rbx ;rbx = source offset + + cmp r9d, 4 + jz .accel_4coeff + cmp r9d, 6 + jz .accel_6coeff + + shr r9d, 1 ;r9d = filter pair count + +.pixelloop: + mov rax, rdx ;rax = row pointer table + mov rdi, r8 ;rdi = filter + mov r11d, r9d ;r11d = filter width counter + movdqa xmm2, xmm4 +.coeffloop: + mov rsi, [rax] + + movd xmm0, dword [rsi+rbx] + + mov rsi, [rax+8] + add rax, 16 + + movd xmm1, dword [rsi+rbx] + punpcklbw xmm0, xmm1 + + punpcklbw xmm0, xmm5 + + movq xmm1, qword [rdi] + pshufd xmm1, xmm1, 01000100b + + pmaddwd xmm0, xmm1 + + paddd xmm2, xmm0 + + add rdi,8 + + sub r11d,1 + jne .coeffloop + + psrad xmm2,14 + packssdw xmm2,xmm2 + add rbx,4 + packuswb xmm2,xmm2 + + movd dword [rcx],xmm2 + add rcx,4 + sub r10d,1 + jne .pixelloop + +.xit: + VDRESTOREXMM128 6, 15 + VDRESTORE rbx, rsi, rdi, rbp, r12, r13, r14, r15 + ret + +.accel_4coeff: + mov r12, [rdx] + mov r13, [rdx+8] + mov r14, [rdx+16] + mov r15, [rdx+24] + movq xmm8, qword [r8] + punpcklqdq xmm8, xmm8 + movq xmm9, qword [r8+8] + punpcklqdq xmm9, xmm9 + + sub r10d, 1 + jc .oddpixel_4coeff +.pixelloop_4coeff: + movq xmm0, qword [r12+rbx] + movq xmm1, qword [r13+rbx] + movq xmm2, qword [r14+rbx] + movq xmm3, qword [r15+rbx] + + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + + punpcklbw xmm0, xmm5 + punpckhbw xmm1, xmm5 + punpcklbw xmm2, xmm5 + punpckhbw xmm3, xmm5 + + pmaddwd xmm0, xmm8 + pmaddwd xmm1, xmm8 + pmaddwd xmm2, xmm9 + pmaddwd xmm3, xmm9 + + paddd xmm0, xmm4 + paddd xmm1, xmm4 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + + psrad xmm0, 14 + psrad xmm1, 14 + packssdw xmm0, xmm1 + packuswb xmm0, xmm0 + + movq qword [rcx], xmm0 + add rcx, 8 + add rbx, 8 + sub r10d, 2 + ja .pixelloop_4coeff + jnz .xit +.oddpixel_4coeff: + movd xmm0, dword [r12+rbx] + movd xmm1, dword [r13+rbx] + movd xmm2, dword [r14+rbx] + movd xmm3, dword [r15+rbx] + + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + + pmaddwd xmm0, xmm8 + pmaddwd xmm2, xmm9 + + paddd xmm0, xmm4 + paddd xmm0, xmm2 + + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + + movd dword [rcx], xmm0 + + jmp .xit + +.accel_6coeff: + mov r12, [rdx] + mov r13, [rdx+8] + mov r14, [rdx+16] + mov r15, [rdx+24] + mov rsi, [rdx+32] + mov rdx, [rdx+40] + movq xmm10, qword [r8] + punpcklqdq xmm10, xmm10 + movq xmm11, qword [r8+8] + punpcklqdq xmm11, xmm11 + movq xmm12, qword [r8+16] + punpcklqdq xmm12, xmm12 + + sub r10d, 1 + jc .oddpixel_6coeff +.pixelloop_6coeff: + movq xmm0, qword [r12+rbx] + movq xmm1, qword [r13+rbx] + movq xmm2, qword [r14+rbx] + movq xmm3, qword [r15+rbx] + movq xmm8, qword [rsi+rbx] + movq xmm9, qword [rdx+rbx] + + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm8, xmm9 + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm9, xmm8 + + punpcklbw xmm0, xmm5 + punpckhbw xmm1, xmm5 + punpcklbw xmm2, xmm5 + punpckhbw xmm3, xmm5 + punpcklbw xmm8, xmm5 + punpckhbw xmm9, xmm5 + + pmaddwd xmm0, xmm10 + pmaddwd xmm1, xmm10 + pmaddwd xmm2, xmm11 + pmaddwd xmm3, xmm11 + pmaddwd xmm8, xmm12 + pmaddwd xmm9, xmm12 + + paddd xmm0, xmm4 + paddd xmm1, xmm4 + paddd xmm2, xmm8 + paddd xmm3, xmm9 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + + psrad xmm0, 14 + psrad xmm1, 14 + packssdw xmm0, xmm1 + packuswb xmm0, xmm0 + + movq qword [rcx], xmm0 + add rcx, 8 + add rbx, 8 + sub r10d, 2 + ja .pixelloop_6coeff + jnz .xit +.oddpixel_6coeff: + movd xmm0, dword [r12+rbx] + movd xmm1, dword [r13+rbx] + movd xmm2, dword [r14+rbx] + movd xmm3, dword [r15+rbx] + movd xmm8, dword [rsi+rbx] + movd xmm9, dword [rdx+rbx] + + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm8, xmm9 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + punpcklbw xmm8, xmm5 + + pmaddwd xmm0, xmm10 + pmaddwd xmm2, xmm11 + pmaddwd xmm8, xmm12 + + paddd xmm0, xmm4 + paddd xmm2, xmm8 + paddd xmm0, xmm2 + + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + + movd dword [rcx], xmm0 + + jmp .xit +endproc_frame + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb.asm index f3503807e55..9582736901c 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb.asm @@ -1,812 +1,812 @@ - section .text - - global _vdasm_pixblt_RGB565_to_XRGB1555 -_vdasm_pixblt_RGB565_to_XRGB1555: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-2] - lea ecx, [ecx+ebp-2] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp] - mov ebx, 0ffc0ffc0h - - and ebx, eax - and eax, 0001f001fh - - shr ebx, 1 - - add eax, ebx - - mov [edx+ebp], eax - add ebp, 4 - - jnc .xloop - jnz .noodd -.odd: - movzx eax, word [ecx] - mov ebx, 0ffc0ffc0h - and ebx, eax - and eax, 0001f001fh - shr ebx, 1 - add eax, ebx - mov [edx], ax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_pixblt_RGB888_to_XRGB1555 -_vdasm_pixblt_RGB888_to_XRGB1555: - push ebp - push edi - push esi - push ebx - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ebp,[esp+20+16] - lea eax,[ebp+ebp] - lea ebx,[ebp+eax] - sub [esp+8+16],eax - sub [esp+16+16],ebx - - mov edx,[esp+24+16] -.yloop: - mov ebp,[esp+20+16] - push ebp - push edx - shr ebp,1 - jz .checkodd -.xloop: - mov eax,[esi+2] ;u - add esi,6 ;v - - mov ebx,eax ;u - mov ecx,eax ;v - shr ebx,11 ;u - and ecx,00f80000h ;v - shr eax,17 ;u - and ebx,0000001fh ;v - shr ecx,14 ;u - and eax,00007c00h ;v - or ebx,ecx ;u - add edi,4 ;v - or ebx,eax ;u - - mov ecx,[esi-6] ;v - mov edx,ebx ;u - mov eax,ecx ;v - - shl edx,16 ;u - mov ebx,ecx ;v - shr ebx,3 ;u - and ecx,0000f800h ;v - shr eax,9 ;u - and ebx,0000001fh ;v - shr ecx,6 ;u - and eax,00007c00h ;v - or eax,ecx ;u - or edx,ebx ;v - or edx,eax ;u - sub ebp,1 ;v - mov [edi-4],edx ;u - jne .xloop ;v -.checkodd: - pop edx - pop ebp - and ebp,1 - jz .noodd - movzx eax,word [esi] - movzx ebx,byte [esi+2] - shl ebx,16 - add esi,3 - add eax,ebx - - mov ebx,eax - mov ecx,eax - shr ebx,3 - and ecx,0000f800h - shr eax,9 - and ebx,0000001fh - shr ecx,6 - and eax,00007c00h - or ebx,ecx - or ebx,eax - mov [edi+0],bl - mov [edi+1],bh - add edi,2 -.noodd: - - add esi,[esp+16+16] - add edi,[esp+ 8+16] - - sub edx,1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - - ret - - global _vdasm_pixblt_XRGB8888_to_XRGB1555 -_vdasm_pixblt_XRGB8888_to_XRGB1555: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - mov edx, [esp+4+16] - add ebp, ebp - mov ecx, [esp+12+16] - lea edx, [edx+ebp-2] - lea ecx, [ecx+ebp*2-4] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp*2] - mov ebx, 00f80000h - and ebx, eax - mov esi, eax - shr ebx, 9 - and esi, 0000f800h - shr esi, 6 - and eax, 000000f8h - shr eax, 3 - add ebx, esi - mov esi, [ecx+ebp*2+4] - add eax, ebx - mov ebx, esi - and esi, 00f80000h - shl esi, 7 - mov edi, ebx - and edi, 0000f800h - add eax, esi - shl edi, 10 - and ebx, 000000f8h - shl ebx, 13 - add eax, edi - add eax, ebx - mov [edx+ebp], eax - add ebp, 4 - jnc .xloop - jnz .noodd -.odd: - mov eax, [ecx] - mov ebx, 00f80000h - and ebx, eax - mov esi, eax - shr ebx, 9 - and esi, 0000f800h - shr esi, 6 - and eax, 000000f8h - shr eax, 3 - add ebx, esi - add eax, ebx - mov [edx], ax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec dword [esp+24+16] - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_pixblt_XRGB1555_to_RGB565 -_vdasm_pixblt_XRGB1555_to_RGB565: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-2] - lea ecx, [ecx+ebp-2] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp] - mov ebx, 02000200h - - mov esi, eax - and ebx, eax - - shr ebx, 4 - and esi, 0ffe0ffe0h - - add eax, esi - - add eax, ebx - - mov [edx+ebp], eax - add ebp, 4 - - jnc .xloop - jnz .noodd -.odd: - movzx eax, word [ecx] - mov ebx, 02000200h - mov esi, eax - and ebx, eax - shr ebx, 4 - and esi, 0ffe0ffe0h - add eax, esi - add eax, ebx - mov [edx], ax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_pixblt_RGB888_to_RGB565 -_vdasm_pixblt_RGB888_to_RGB565: - push ebp - push edi - push esi - push ebx - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ebp,[esp+20+16] - lea eax,[ebp+ebp] - lea ebx,[ebp+eax] - sub [esp+8+16],eax - sub [esp+16+16],ebx - - mov edx,[esp+24+16] -.yloop: - mov ebp,[esp+20+16] - push ebp - push edx - shr ebp,1 - jz .checkodd -.xloop: - mov eax,[esi+2] ;u - add esi,6 ;v - - mov ebx,eax ;u - mov ecx,eax ;v - shr ebx,11 ;u - and ecx,00fc0000h ;v - shr eax,16 ;u - and ebx,0000001fh ;v - shr ecx,13 ;u - and eax,0000f800h ;v - or ebx,ecx ;u - add edi,4 ;v - or ebx,eax ;u - - mov ecx,[esi-6] ;v - mov edx,ebx ;u - mov eax,ecx ;v - - shl edx,16 ;u - mov ebx,ecx ;v - shr ebx,3 ;u - and ecx,0000fc00h ;v - shr eax,8 ;u - and ebx,0000001fh ;v - shr ecx,5 ;u - and eax,0000f800h ;v - or eax,ecx ;u - or edx,ebx ;v - or edx,eax ;u - sub ebp,1 ;v - mov [edi-4],edx ;u - jne .xloop ;v -.checkodd: - pop edx - pop ebp - and ebp,1 - jz .noodd - movzx eax,word [esi] - movzx ebx,byte [esi+2] - shl ebx,16 - add esi,3 - add eax,ebx - - mov ebx,eax - mov ecx,eax - shr ebx,3 - and ecx,0000fc00h - shr eax,8 - and ebx,0000001fh - shr ecx,5 - and eax,0000f800h - or ebx,ecx - or ebx,eax - mov [edi+0],bl - mov [edi+1],bh - add edi,2 -.noodd: - - add esi,[esp+16+16] - add edi,[esp+ 8+16] - - sub edx,1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - - ret - - global _vdasm_pixblt_XRGB8888_to_RGB565 -_vdasm_pixblt_XRGB8888_to_RGB565: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - mov edx, [esp+4+16] - add ebp, ebp - mov ecx, [esp+12+16] - lea edx, [edx+ebp-2] - lea ecx, [ecx+ebp*2-4] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp*2] - mov ebx, 00f80000h - and ebx, eax - mov esi, eax - shr ebx, 8 - and esi, 0000fc00h - shr esi, 5 - and eax, 000000f8h - shr eax, 3 - add ebx, esi - mov esi, [ecx+ebp*2+4] - add eax, ebx - mov ebx, esi - and esi, 00f80000h - shl esi, 8 - mov edi, ebx - and edi, 0000fc00h - add eax, esi - shl edi, 11 - and ebx, 000000f8h - shl ebx, 13 - add eax, edi - add eax, ebx - mov [edx+ebp], eax - add ebp, 4 - jnc .xloop - jnz .noodd -.odd: - mov eax, [ecx] - mov ebx, 00f80000h - and ebx, eax - mov esi, eax - shr ebx, 8 - and esi, 0000fc00h - shr esi, 5 - and eax, 000000f8h - shr eax, 3 - add ebx, esi - add eax, ebx - mov [edx], ax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec dword [esp+24+16] - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_pixblt_XRGB8888_to_RGB888 -_vdasm_pixblt_XRGB8888_to_RGB888: - push ebp - push edi - push esi - push ebx - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ecx,[esp+20+16] - lea eax,[ecx+ecx*2] - lea ebx,[ecx*4] - sub [esp+8+16],eax - sub [esp+16+16],ebx - - mov edx,[esp+24+16] -.yloop: - mov ecx,[esp+20+16] - push ecx - push edx - shr ecx,2 - jz .checkodd -.xloop: - mov eax,[esi] ;EAX = xxr0g0b0 - mov ebx,[esi+4] ;EBX = xxr1g1b1 - mov edx,ebx ;EDX = xxr1g1b1 - mov ebp,[esi+8] ;EBP = xxr2g2b2 - shl ebx,24 ;EBX = b1000000 - and eax,00ffffffh ;EAX = 00r0g0b0 - shr edx,8 ;EDX = 00xxr1g1 - or eax,ebx ;EAX = b1r0g0b0 - mov [edi],eax - mov ebx,ebp ;EBX = xxr2g2b2 - shl ebp,16 ;EBP = g2b20000 - and edx,0000ffffh ;EDX = 0000r1g1 - or ebp,edx ;EBP = g2b2r1g1 - mov eax,[esi+12] ;EAX = xxr3g3b3 - shr ebx,16 ;EBX = 0000xxr2 - add edi,12 - shl eax,8 ;EAX = r3g3b300 - and ebx,000000ffh ;EBX = 000000r2 - or eax,ebx ;EAX = r3g3b3r2 - mov [edi+4-12],ebp - add esi,16 - mov [edi+8-12],eax - sub ecx,1 - jne .xloop -.checkodd: - pop edx - pop ecx - and ecx,3 - jz .noodd -.oddloop: - mov eax,[esi] - add esi,4 - mov [edi],ax - shr eax,16 - mov [edi+2],al - add edi,3 - sub ecx,1 - jnz .oddloop -.noodd: - add esi,[esp+16+16] - add edi,[esp+ 8+16] - - sub edx,1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_pixblt_XRGB1555_to_XRGB8888 -_vdasm_pixblt_XRGB1555_to_XRGB8888: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp*2-4] - lea ecx, [ecx+ebp-2] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp] - mov ebx, 00007c00h - and ebx, eax - mov esi, eax - shl ebx, 9 - and esi, 000003e0h - shl esi, 6 - mov edi, eax - and eax, 0000001fh - add ebx, esi - shl eax, 3 - mov esi, edi - shr edi, 7 - add eax, ebx - and edi, 00f80000h - mov ebx, esi - shr esi, 13 - and ebx, 03e00000h - shr ebx, 10 - and esi, 000000f8h - add ebx, edi - add ebx, esi - mov edi, eax - and eax, 00e0e0e0h - shr eax, 5 - mov esi, ebx - shr ebx, 5 - add eax, edi - and ebx, 00070707h - add ebx, esi - mov [edx+ebp*2], eax - mov [edx+ebp*2+4], ebx - add ebp, 4 - jnc .xloop - jnz .noodd -.odd: - movzx eax, word [ecx] - mov ebx, 00007c00h - and ebx, eax - mov esi, eax - shl ebx, 9 - and esi, 000003e0h - shl esi, 6 - and eax, 0000001fh - shl eax, 3 - add ebx, esi - add eax, ebx - mov ebx, 00e0e0e0h - and ebx, eax - shr ebx, 5 - add eax, ebx - mov [edx], eax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec dword [esp+24+16] - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_pixblt_RGB565_to_XRGB8888 -_vdasm_pixblt_RGB565_to_XRGB8888: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp*2-4] - lea ecx, [ecx+ebp-2] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - movzx eax, word [ecx+ebp] - mov ebx, 0000f800h - and ebx, eax - mov esi, eax - shl ebx, 8 - mov edi, eax - shl eax, 3 - and esi, 000007e0h - and eax, 000000f8h - add ebx, eax - shl esi, 5 - mov eax, ebx - shr ebx, 5 - and edi, 00000600h - shr edi, 1 - and ebx, 00070007h - add esi, edi - add eax, ebx - add eax, esi - mov [edx+ebp*2], eax - - movzx eax, word [ecx+ebp+2] - mov ebx, 0000f800h - and ebx, eax - mov esi, eax - shl ebx, 8 - mov edi, eax - shl eax, 3 - and esi, 000007e0h - and eax, 000000f8h - add ebx, eax - shl esi, 5 - mov eax, ebx - shr ebx, 5 - and edi, 00000600h - shr edi, 1 - and ebx, 00070007h - add esi, edi - add eax, ebx - add eax, esi - mov [edx+ebp*2+4], eax - - add ebp, 4 - - jnc .xloop - jnz .noodd -.odd: - movzx eax, word [ecx] - mov ebx, 0000f800h - and ebx, eax - mov esi, eax - shl ebx, 8 - mov edi, eax - shl eax, 3 - and esi, 000007e0h - and eax, 000000f8h - add ebx, eax - shl esi, 5 - mov eax, ebx - shr ebx, 5 - and edi, 00000600h - shr edi, 1 - and ebx, 00070007h - add esi, edi - add eax, ebx - add eax, esi - mov [edx], eax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec dword [esp+24+16] - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_pixblt_RGB888_to_XRGB8888 -_vdasm_pixblt_RGB888_to_XRGB8888: - push ebp - push edi - push esi - push ebx - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ecx,[esp+20+16] - lea eax,[ecx+ecx*2] - lea ebx,[ecx*4] - sub [esp+8+16],ebx - sub [esp+16+16],eax - - mov edx,[esp+24+16] -.yloop: - mov ebp,[esp+20+16] - shr ebp,2 - push edx - jz .checkodd -.xloop: - mov eax,[esi] ;EAX: b1r0g0b0 - mov ebx,[esi+4] ;EBX: g2b2r1g1 - - mov [edi],eax - mov ecx,ebx ;ECX: g2b2r1g1 - - shr eax,24 ;EAX: ------b1 - mov edx,[esi+8] ;EDX: r3g3b3r2 - - shr ecx,16 ;ECX: ----g2b2 - add edi,16 - - shl ebx,8 ;EBX: b2r1g1-- - add esi,12 - - or eax,ebx ;EAX: b2r1g1b1 - mov ebx,edx ;EBX: r3g3b3r2 - - shr ebx,8 ;EBX: --r3g3b3 - mov [edi+4-16],eax - - shl edx,16 ;EDX: b3r2---- - mov [edi+12-16],ebx - - or edx,ecx ;EDX: b3r2g2b2 - sub ebp,1 - - mov [edi+8-16],edx - jne .xloop - -.checkodd: - pop edx - mov ebx,[esp+20+16] - and ebx,3 - jz .noodd -.oddloop: - mov ax,[esi] - mov cl,[esi+2] - mov [edi],ax - mov [edi+2],cl - add esi,3 - add edi,4 - sub ebx,1 - jne .oddloop -.noodd: - - add esi,[esp+16+16] - add edi,[esp+ 8+16] - - sub edx,1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - - ret - - end + section .text + + global _vdasm_pixblt_RGB565_to_XRGB1555 +_vdasm_pixblt_RGB565_to_XRGB1555: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-2] + lea ecx, [ecx+ebp-2] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp] + mov ebx, 0ffc0ffc0h + + and ebx, eax + and eax, 0001f001fh + + shr ebx, 1 + + add eax, ebx + + mov [edx+ebp], eax + add ebp, 4 + + jnc .xloop + jnz .noodd +.odd: + movzx eax, word [ecx] + mov ebx, 0ffc0ffc0h + and ebx, eax + and eax, 0001f001fh + shr ebx, 1 + add eax, ebx + mov [edx], ax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_pixblt_RGB888_to_XRGB1555 +_vdasm_pixblt_RGB888_to_XRGB1555: + push ebp + push edi + push esi + push ebx + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ebp,[esp+20+16] + lea eax,[ebp+ebp] + lea ebx,[ebp+eax] + sub [esp+8+16],eax + sub [esp+16+16],ebx + + mov edx,[esp+24+16] +.yloop: + mov ebp,[esp+20+16] + push ebp + push edx + shr ebp,1 + jz .checkodd +.xloop: + mov eax,[esi+2] ;u + add esi,6 ;v + + mov ebx,eax ;u + mov ecx,eax ;v + shr ebx,11 ;u + and ecx,00f80000h ;v + shr eax,17 ;u + and ebx,0000001fh ;v + shr ecx,14 ;u + and eax,00007c00h ;v + or ebx,ecx ;u + add edi,4 ;v + or ebx,eax ;u + + mov ecx,[esi-6] ;v + mov edx,ebx ;u + mov eax,ecx ;v + + shl edx,16 ;u + mov ebx,ecx ;v + shr ebx,3 ;u + and ecx,0000f800h ;v + shr eax,9 ;u + and ebx,0000001fh ;v + shr ecx,6 ;u + and eax,00007c00h ;v + or eax,ecx ;u + or edx,ebx ;v + or edx,eax ;u + sub ebp,1 ;v + mov [edi-4],edx ;u + jne .xloop ;v +.checkodd: + pop edx + pop ebp + and ebp,1 + jz .noodd + movzx eax,word [esi] + movzx ebx,byte [esi+2] + shl ebx,16 + add esi,3 + add eax,ebx + + mov ebx,eax + mov ecx,eax + shr ebx,3 + and ecx,0000f800h + shr eax,9 + and ebx,0000001fh + shr ecx,6 + and eax,00007c00h + or ebx,ecx + or ebx,eax + mov [edi+0],bl + mov [edi+1],bh + add edi,2 +.noodd: + + add esi,[esp+16+16] + add edi,[esp+ 8+16] + + sub edx,1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + + ret + + global _vdasm_pixblt_XRGB8888_to_XRGB1555 +_vdasm_pixblt_XRGB8888_to_XRGB1555: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + mov edx, [esp+4+16] + add ebp, ebp + mov ecx, [esp+12+16] + lea edx, [edx+ebp-2] + lea ecx, [ecx+ebp*2-4] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp*2] + mov ebx, 00f80000h + and ebx, eax + mov esi, eax + shr ebx, 9 + and esi, 0000f800h + shr esi, 6 + and eax, 000000f8h + shr eax, 3 + add ebx, esi + mov esi, [ecx+ebp*2+4] + add eax, ebx + mov ebx, esi + and esi, 00f80000h + shl esi, 7 + mov edi, ebx + and edi, 0000f800h + add eax, esi + shl edi, 10 + and ebx, 000000f8h + shl ebx, 13 + add eax, edi + add eax, ebx + mov [edx+ebp], eax + add ebp, 4 + jnc .xloop + jnz .noodd +.odd: + mov eax, [ecx] + mov ebx, 00f80000h + and ebx, eax + mov esi, eax + shr ebx, 9 + and esi, 0000f800h + shr esi, 6 + and eax, 000000f8h + shr eax, 3 + add ebx, esi + add eax, ebx + mov [edx], ax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec dword [esp+24+16] + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_pixblt_XRGB1555_to_RGB565 +_vdasm_pixblt_XRGB1555_to_RGB565: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-2] + lea ecx, [ecx+ebp-2] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp] + mov ebx, 02000200h + + mov esi, eax + and ebx, eax + + shr ebx, 4 + and esi, 0ffe0ffe0h + + add eax, esi + + add eax, ebx + + mov [edx+ebp], eax + add ebp, 4 + + jnc .xloop + jnz .noodd +.odd: + movzx eax, word [ecx] + mov ebx, 02000200h + mov esi, eax + and ebx, eax + shr ebx, 4 + and esi, 0ffe0ffe0h + add eax, esi + add eax, ebx + mov [edx], ax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_pixblt_RGB888_to_RGB565 +_vdasm_pixblt_RGB888_to_RGB565: + push ebp + push edi + push esi + push ebx + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ebp,[esp+20+16] + lea eax,[ebp+ebp] + lea ebx,[ebp+eax] + sub [esp+8+16],eax + sub [esp+16+16],ebx + + mov edx,[esp+24+16] +.yloop: + mov ebp,[esp+20+16] + push ebp + push edx + shr ebp,1 + jz .checkodd +.xloop: + mov eax,[esi+2] ;u + add esi,6 ;v + + mov ebx,eax ;u + mov ecx,eax ;v + shr ebx,11 ;u + and ecx,00fc0000h ;v + shr eax,16 ;u + and ebx,0000001fh ;v + shr ecx,13 ;u + and eax,0000f800h ;v + or ebx,ecx ;u + add edi,4 ;v + or ebx,eax ;u + + mov ecx,[esi-6] ;v + mov edx,ebx ;u + mov eax,ecx ;v + + shl edx,16 ;u + mov ebx,ecx ;v + shr ebx,3 ;u + and ecx,0000fc00h ;v + shr eax,8 ;u + and ebx,0000001fh ;v + shr ecx,5 ;u + and eax,0000f800h ;v + or eax,ecx ;u + or edx,ebx ;v + or edx,eax ;u + sub ebp,1 ;v + mov [edi-4],edx ;u + jne .xloop ;v +.checkodd: + pop edx + pop ebp + and ebp,1 + jz .noodd + movzx eax,word [esi] + movzx ebx,byte [esi+2] + shl ebx,16 + add esi,3 + add eax,ebx + + mov ebx,eax + mov ecx,eax + shr ebx,3 + and ecx,0000fc00h + shr eax,8 + and ebx,0000001fh + shr ecx,5 + and eax,0000f800h + or ebx,ecx + or ebx,eax + mov [edi+0],bl + mov [edi+1],bh + add edi,2 +.noodd: + + add esi,[esp+16+16] + add edi,[esp+ 8+16] + + sub edx,1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + + ret + + global _vdasm_pixblt_XRGB8888_to_RGB565 +_vdasm_pixblt_XRGB8888_to_RGB565: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + mov edx, [esp+4+16] + add ebp, ebp + mov ecx, [esp+12+16] + lea edx, [edx+ebp-2] + lea ecx, [ecx+ebp*2-4] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp*2] + mov ebx, 00f80000h + and ebx, eax + mov esi, eax + shr ebx, 8 + and esi, 0000fc00h + shr esi, 5 + and eax, 000000f8h + shr eax, 3 + add ebx, esi + mov esi, [ecx+ebp*2+4] + add eax, ebx + mov ebx, esi + and esi, 00f80000h + shl esi, 8 + mov edi, ebx + and edi, 0000fc00h + add eax, esi + shl edi, 11 + and ebx, 000000f8h + shl ebx, 13 + add eax, edi + add eax, ebx + mov [edx+ebp], eax + add ebp, 4 + jnc .xloop + jnz .noodd +.odd: + mov eax, [ecx] + mov ebx, 00f80000h + and ebx, eax + mov esi, eax + shr ebx, 8 + and esi, 0000fc00h + shr esi, 5 + and eax, 000000f8h + shr eax, 3 + add ebx, esi + add eax, ebx + mov [edx], ax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec dword [esp+24+16] + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_pixblt_XRGB8888_to_RGB888 +_vdasm_pixblt_XRGB8888_to_RGB888: + push ebp + push edi + push esi + push ebx + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ecx,[esp+20+16] + lea eax,[ecx+ecx*2] + lea ebx,[ecx*4] + sub [esp+8+16],eax + sub [esp+16+16],ebx + + mov edx,[esp+24+16] +.yloop: + mov ecx,[esp+20+16] + push ecx + push edx + shr ecx,2 + jz .checkodd +.xloop: + mov eax,[esi] ;EAX = xxr0g0b0 + mov ebx,[esi+4] ;EBX = xxr1g1b1 + mov edx,ebx ;EDX = xxr1g1b1 + mov ebp,[esi+8] ;EBP = xxr2g2b2 + shl ebx,24 ;EBX = b1000000 + and eax,00ffffffh ;EAX = 00r0g0b0 + shr edx,8 ;EDX = 00xxr1g1 + or eax,ebx ;EAX = b1r0g0b0 + mov [edi],eax + mov ebx,ebp ;EBX = xxr2g2b2 + shl ebp,16 ;EBP = g2b20000 + and edx,0000ffffh ;EDX = 0000r1g1 + or ebp,edx ;EBP = g2b2r1g1 + mov eax,[esi+12] ;EAX = xxr3g3b3 + shr ebx,16 ;EBX = 0000xxr2 + add edi,12 + shl eax,8 ;EAX = r3g3b300 + and ebx,000000ffh ;EBX = 000000r2 + or eax,ebx ;EAX = r3g3b3r2 + mov [edi+4-12],ebp + add esi,16 + mov [edi+8-12],eax + sub ecx,1 + jne .xloop +.checkodd: + pop edx + pop ecx + and ecx,3 + jz .noodd +.oddloop: + mov eax,[esi] + add esi,4 + mov [edi],ax + shr eax,16 + mov [edi+2],al + add edi,3 + sub ecx,1 + jnz .oddloop +.noodd: + add esi,[esp+16+16] + add edi,[esp+ 8+16] + + sub edx,1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_pixblt_XRGB1555_to_XRGB8888 +_vdasm_pixblt_XRGB1555_to_XRGB8888: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp*2-4] + lea ecx, [ecx+ebp-2] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp] + mov ebx, 00007c00h + and ebx, eax + mov esi, eax + shl ebx, 9 + and esi, 000003e0h + shl esi, 6 + mov edi, eax + and eax, 0000001fh + add ebx, esi + shl eax, 3 + mov esi, edi + shr edi, 7 + add eax, ebx + and edi, 00f80000h + mov ebx, esi + shr esi, 13 + and ebx, 03e00000h + shr ebx, 10 + and esi, 000000f8h + add ebx, edi + add ebx, esi + mov edi, eax + and eax, 00e0e0e0h + shr eax, 5 + mov esi, ebx + shr ebx, 5 + add eax, edi + and ebx, 00070707h + add ebx, esi + mov [edx+ebp*2], eax + mov [edx+ebp*2+4], ebx + add ebp, 4 + jnc .xloop + jnz .noodd +.odd: + movzx eax, word [ecx] + mov ebx, 00007c00h + and ebx, eax + mov esi, eax + shl ebx, 9 + and esi, 000003e0h + shl esi, 6 + and eax, 0000001fh + shl eax, 3 + add ebx, esi + add eax, ebx + mov ebx, 00e0e0e0h + and ebx, eax + shr ebx, 5 + add eax, ebx + mov [edx], eax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec dword [esp+24+16] + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_pixblt_RGB565_to_XRGB8888 +_vdasm_pixblt_RGB565_to_XRGB8888: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp*2-4] + lea ecx, [ecx+ebp-2] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + movzx eax, word [ecx+ebp] + mov ebx, 0000f800h + and ebx, eax + mov esi, eax + shl ebx, 8 + mov edi, eax + shl eax, 3 + and esi, 000007e0h + and eax, 000000f8h + add ebx, eax + shl esi, 5 + mov eax, ebx + shr ebx, 5 + and edi, 00000600h + shr edi, 1 + and ebx, 00070007h + add esi, edi + add eax, ebx + add eax, esi + mov [edx+ebp*2], eax + + movzx eax, word [ecx+ebp+2] + mov ebx, 0000f800h + and ebx, eax + mov esi, eax + shl ebx, 8 + mov edi, eax + shl eax, 3 + and esi, 000007e0h + and eax, 000000f8h + add ebx, eax + shl esi, 5 + mov eax, ebx + shr ebx, 5 + and edi, 00000600h + shr edi, 1 + and ebx, 00070007h + add esi, edi + add eax, ebx + add eax, esi + mov [edx+ebp*2+4], eax + + add ebp, 4 + + jnc .xloop + jnz .noodd +.odd: + movzx eax, word [ecx] + mov ebx, 0000f800h + and ebx, eax + mov esi, eax + shl ebx, 8 + mov edi, eax + shl eax, 3 + and esi, 000007e0h + and eax, 000000f8h + add ebx, eax + shl esi, 5 + mov eax, ebx + shr ebx, 5 + and edi, 00000600h + shr edi, 1 + and ebx, 00070007h + add esi, edi + add eax, ebx + add eax, esi + mov [edx], eax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec dword [esp+24+16] + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_pixblt_RGB888_to_XRGB8888 +_vdasm_pixblt_RGB888_to_XRGB8888: + push ebp + push edi + push esi + push ebx + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ecx,[esp+20+16] + lea eax,[ecx+ecx*2] + lea ebx,[ecx*4] + sub [esp+8+16],ebx + sub [esp+16+16],eax + + mov edx,[esp+24+16] +.yloop: + mov ebp,[esp+20+16] + shr ebp,2 + push edx + jz .checkodd +.xloop: + mov eax,[esi] ;EAX: b1r0g0b0 + mov ebx,[esi+4] ;EBX: g2b2r1g1 + + mov [edi],eax + mov ecx,ebx ;ECX: g2b2r1g1 + + shr eax,24 ;EAX: ------b1 + mov edx,[esi+8] ;EDX: r3g3b3r2 + + shr ecx,16 ;ECX: ----g2b2 + add edi,16 + + shl ebx,8 ;EBX: b2r1g1-- + add esi,12 + + or eax,ebx ;EAX: b2r1g1b1 + mov ebx,edx ;EBX: r3g3b3r2 + + shr ebx,8 ;EBX: --r3g3b3 + mov [edi+4-16],eax + + shl edx,16 ;EDX: b3r2---- + mov [edi+12-16],ebx + + or edx,ecx ;EDX: b3r2g2b2 + sub ebp,1 + + mov [edi+8-16],edx + jne .xloop + +.checkodd: + pop edx + mov ebx,[esp+20+16] + and ebx,3 + jz .noodd +.oddloop: + mov ax,[esi] + mov cl,[esi+2] + mov [edi],ax + mov [edi+2],cl + add esi,3 + add edi,4 + sub ebx,1 + jne .oddloop +.noodd: + + add esi,[esp+16+16] + add edi,[esp+ 8+16] + + sub edx,1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb2yuv_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb2yuv_mmx.asm index 637e7910b3c..2c9286041a0 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb2yuv_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb2yuv_mmx.asm @@ -1,652 +1,652 @@ - section .rdata, rdata - -y_co dq 0004a004a004a004ah -cr_co_r dq 000cc00cc00cc00cch -cb_co_b dq 00081008100810081h ;note: divided by two -cr_co_g dq 0ff98ff98ff98ff98h -cb_co_g dq 0ffceffceffceffceh -y_bias dq 0fb7afb7afb7afb7ah -c_bias dq 0ff80ff80ff80ff80h -interp dq 06000400020000000h -rb_mask_555 dq 07c1f7c1f7c1f7c1fh -g_mask_555 dq 003e003e003e003e0h -rb_mask_565 dq 0f81ff81ff81ff81fh -g_mask_565 dq 007e007e007e007e0h - -cr_coeff dq 000003313e5fc0000h -cb_coeff dq 000000000f377408dh -rgb_bias dq 000007f2180887eebh - -msb_inv dq 08000800080008000h - - section .text - -;============================================================================ - -%macro YUV411PLANAR_TO_RGB_PROLOG 0 - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - mov ecx, [esp+8+16] - mov edx, [esp+12+16] - mov ebx, [esp+16+16] - mov ebp, [esp+20+16] - - pxor mm7, mm7 -%endmacro - -%macro YUV411PLANAR_TO_RGB_CORE_MMX 0 - movd mm0, dword [ecx] ;mm0 = Y3Y2Y1Y0 - add ecx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - movq mm1, mm0 - pmullw mm0, [y_co] - paddw mm1, [y_bias] - paddsw mm0, mm0 - paddsw mm0, mm1 - - movzx esi, word [ebx] - movzx edi, word [edx] - add ebx, 1 - add edx, 1 - - movd mm1, esi - movd mm2, edi - - punpcklbw mm1, mm7 - paddw mm1, [c_bias] - punpcklwd mm1, mm1 - movq mm3, mm1 - punpckldq mm1, mm1 - punpckhdq mm3, mm3 - - punpcklbw mm2, mm7 - paddw mm2, [c_bias] - punpcklwd mm2, mm2 - movq mm4, mm2 - punpckldq mm2, mm2 - punpckhdq mm4, mm4 - - psubw mm3, mm1 - psubw mm4, mm2 - paddw mm3, mm3 - paddw mm4, mm4 - - pmulhw mm3, [interp] - pmulhw mm4, [interp] - - paddw mm1, mm3 - paddw mm2, mm4 - - movq mm3, mm1 - movq mm4, mm2 - - pmullw mm1, [cr_co_r] - pmullw mm2, [cb_co_b] - pmullw mm3, [cr_co_g] - pmullw mm4, [cb_co_g] - - paddsw mm2, mm2 - paddsw mm1, mm0 - paddsw mm3, mm4 - paddsw mm2, mm0 - paddsw mm3, mm0 - - psraw mm1, 7 - psraw mm2, 7 - psraw mm3, 7 - - packuswb mm1, mm1 - packuswb mm2, mm2 - packuswb mm3, mm3 -%endmacro - -%macro YUV411PLANAR_TO_RGB_CORE_ISSE 0 - movd mm0, dword [ecx] ;mm0 = Y3Y2Y1Y0 - add ecx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - movq mm1, mm0 - pmullw mm0, [y_co] - paddw mm1, [y_bias] - paddsw mm0, mm0 - paddsw mm0, mm1 - - movzx esi, word [ebx] - movzx edi, word [edx] - add ebx, 1 - add edx, 1 - - movd mm1, esi - movd mm2, edi - - punpcklbw mm1, mm7 - paddw mm1, [c_bias] - pshufw mm3, mm1, 01010101b - pshufw mm1, mm1, 00000000b - - punpcklbw mm2, mm7 - paddw mm2, [c_bias] - pshufw mm4, mm2, 01010101b - pshufw mm2, mm2, 00000000b - - psubw mm3, mm1 - psubw mm4, mm2 - paddw mm3, mm3 - paddw mm4, mm4 - - pmulhw mm3, [interp] - pmulhw mm4, [interp] - - paddw mm1, mm3 - paddw mm2, mm4 - - psllw mm1, 3 - psllw mm2, 3 - - movq mm3, [cr_co_g] - movq mm4, [cb_co_g] - - pmullw mm3, mm1 - pmullw mm4, mm2 - pmullw mm1, [cr_co_r] - pmullw mm2, [cb_co_b] - - paddsw mm2, mm2 - paddsw mm1, mm0 - paddsw mm3, mm4 - paddsw mm2, mm0 - paddsw mm3, mm0 - - psraw mm1, 7 - psraw mm2, 7 - psraw mm3, 7 - - packuswb mm1, mm1 - packuswb mm2, mm2 - packuswb mm3, mm3 -%endmacro - -%macro YUV411PLANAR_TO_RGB_EPILOG 0 - pop ebx - pop esi - pop edi - pop ebp - ret -%endmacro - - global _vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX -_vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_CORE_MMX - - psrlw mm1, 1 - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 2 - pand mm2, [rb_mask_555] - pand mm3, [g_mask_555] - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX -_vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_CORE_MMX - - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 3 - pand mm2, [rb_mask_565] - pand mm3, [g_mask_565] - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX -_vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_PROLOG - - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - movq mm1, mm2 - punpcklbw mm1, mm3 - punpckhbw mm2, mm3 - - movq [eax], mm1 - movq [eax+8], mm2 - add eax, 16 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE -_vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_CORE_ISSE - - psrlw mm1, 1 - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 2 - pand mm2, [rb_mask_555] - pand mm3, [g_mask_555] - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE -_vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_CORE_ISSE - - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 3 - pand mm2, [rb_mask_565] - pand mm3, [g_mask_565] - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE -_vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - mov ecx, [esp+8+16] - mov edx, [esp+12+16] - mov ebx, [esp+16+16] - mov ebp, [esp+20+16] - - pxor mm7, mm7 - - movzx esi, byte [ebx] - movzx edi, byte [edx] - add ebx, 1 - add edx, 1 - - movd mm1, esi - movd mm2, edi - - psllw mm1, 3 - psllw mm2, 3 - - pshufw mm5, mm1, 0 - pshufw mm6, mm2, 0 - - pmulhw mm5, [cr_coeff] - pmulhw mm6, [cb_coeff] - paddw mm6, mm5 - paddw mm6, [rgb_bias] - -.xloop: - movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 - add ecx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - psllw mm0, 3 - pmulhw mm0, [y_co] - pxor mm0, [msb_inv] - - movzx esi, byte [ebx] - movzx edi, byte [edx] - add ebx, 1 - add edx, 1 - - movd mm1, esi - movd mm2, edi - - psllw mm1, 3 - psllw mm2, 3 - - pshufw mm1, mm1, 0 - pshufw mm2, mm2, 0 - - pmulhw mm1, [cr_coeff] - pmulhw mm2, [cb_coeff] - paddw mm1, mm2 - paddw mm1, [rgb_bias] - - movq mm2, mm1 - pavgw mm2, mm6 ;mm2 = 1/2 - pshufw mm3, mm0, 00000000b - paddw mm3, mm6 - pavgw mm6, mm2 ;mm1 = 1/4 - pshufw mm4, mm0, 01010101b - paddw mm4, mm6 - packuswb mm3, mm4 - movq [eax], mm3 - - pshufw mm3, mm0, 10101010b - paddw mm3, mm2 - pshufw mm0, mm0, 11111111b - pavgw mm2, mm1 ;mm2 = 3/4 - paddw mm2, mm0 - packuswb mm3, mm2 - movq [eax+8], mm3 - - movq mm6, mm1 - - add eax, 16 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;========================================================================== - -%macro YUV444PLANAR_TO_RGB_PROLOG 0 - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - mov ecx, [esp+8+16] - mov edx, [esp+12+16] - mov ebx, [esp+16+16] - mov ebp, [esp+20+16] -%endmacro - -%macro YUV444PLANAR_TO_RGB_CORE 0 - movq mm3, mm0 - pmullw mm0, [y_co] - paddw mm1, [c_bias] - paddw mm2, [c_bias] - paddw mm0, [y_bias] - paddsw mm0, mm0 - paddsw mm0, mm3 - - movq mm3, [cr_co_g] - movq mm4, [cb_co_g] - - pmullw mm3, mm1 - pmullw mm4, mm2 - pmullw mm1, [cr_co_r] - pmullw mm2, [cb_co_b] - - paddsw mm2, mm2 - paddsw mm1, mm0 - paddsw mm3, mm4 - paddsw mm2, mm0 - paddsw mm3, mm0 - - psraw mm1, 7 - psraw mm2, 7 - psraw mm3, 7 - - packuswb mm1, mm1 - packuswb mm2, mm2 - packuswb mm3, mm3 -%endmacro - -%macro YUV444PLANAR_TO_RGB_EPILOG 0 - pop ebx - pop esi - pop edi - pop ebp - ret -%endmacro - -;========================================================================== - - global _vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX -_vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX: - YUV444PLANAR_TO_RGB_PROLOG - - pxor mm7, mm7 - movq mm5, [rb_mask_555] - movq mm6, [g_mask_555] - - sub ebp, 3 - jbe .oddcheck -.xloop4: - movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 - movd mm1, dword [ebx] - movd mm2, dword [edx] - add ecx, 4 - add ebx, 4 - add edx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - punpcklbw mm1, mm7 - punpcklbw mm2, mm7 - - YUV444PLANAR_TO_RGB_CORE - - psrlw mm1, 1 - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 2 - pand mm2, mm5 - pand mm3, mm6 - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 4 - ja .xloop4 -.oddcheck: - add ebp, 3 - jz .noodd -.xloop: - movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 - movd mm0, edi - movzx edi, byte [ebx] - movd mm1, edi - movzx edi, byte [edx] - movd mm2, edi - add ecx, 1 - add ebx, 1 - add edx, 1 - - YUV444PLANAR_TO_RGB_CORE - - psrlw mm1, 1 - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 2 - pand mm2, mm5 - pand mm3, mm6 - por mm2, mm3 - - movd edi, mm2 - mov [eax], di - add eax, 2 - - sub ebp, 1 - jnz .xloop -.noodd: - YUV444PLANAR_TO_RGB_EPILOG - -;========================================================================== - - global _vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX -_vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX: - YUV444PLANAR_TO_RGB_PROLOG - - pxor mm7, mm7 - movq mm5, [rb_mask_565] - movq mm6, [g_mask_565] - - sub ebp, 3 - jbe .oddcheck -.xloop4: - movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 - movd mm1, dword [ebx] - movd mm2, dword [edx] - add ecx, 4 - add ebx, 4 - add edx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - punpcklbw mm1, mm7 - punpcklbw mm2, mm7 - - YUV444PLANAR_TO_RGB_CORE - - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 3 - pand mm2, mm5 - pand mm3, mm6 - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 4 - ja .xloop4 -.oddcheck: - add ebp, 3 - jz .noodd -.xloop: - movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 - movd mm0, edi - movzx edi, byte [ebx] - movd mm1, edi - movzx edi, byte [edx] - movd mm2, edi - add ecx, 1 - add ebx, 1 - add edx, 1 - - YUV444PLANAR_TO_RGB_CORE - - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 3 - pand mm2, mm5 - pand mm3, mm6 - por mm2, mm3 - - movd edi, mm2 - mov [eax], di - add eax, 2 - - sub ebp, 1 - jnz .xloop -.noodd: - YUV444PLANAR_TO_RGB_EPILOG - -;========================================================================== - - global _vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX -_vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX: - YUV444PLANAR_TO_RGB_PROLOG - - pxor mm7, mm7 - - sub ebp, 3 - jbe .oddcheck -.xloop4: - movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 - movd mm1, dword [ebx] - movd mm2, dword [edx] - add ecx, 4 - add ebx, 4 - add edx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - punpcklbw mm1, mm7 - punpcklbw mm2, mm7 - - YUV444PLANAR_TO_RGB_CORE - - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - movq mm1, mm2 - punpcklbw mm1, mm3 - punpckhbw mm2, mm3 - - movq [eax], mm1 - movq [eax+8], mm2 - add eax, 16 - - sub ebp, 4 - ja .xloop4 -.oddcheck: - add ebp, 3 - jz .noodd -.xloop: - movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 - movd mm0, edi - movzx edi, byte [ebx] - movd mm1, edi - movzx edi, byte [edx] - movd mm2, edi - add ecx, 1 - add ebx, 1 - add edx, 1 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - - YUV444PLANAR_TO_RGB_CORE - - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - punpcklbw mm2, mm3 - - movd dword [eax], mm2 - add eax, 4 - - sub ebp, 1 - jnz .xloop -.noodd: - YUV444PLANAR_TO_RGB_EPILOG - + section .rdata, rdata + +y_co dq 0004a004a004a004ah +cr_co_r dq 000cc00cc00cc00cch +cb_co_b dq 00081008100810081h ;note: divided by two +cr_co_g dq 0ff98ff98ff98ff98h +cb_co_g dq 0ffceffceffceffceh +y_bias dq 0fb7afb7afb7afb7ah +c_bias dq 0ff80ff80ff80ff80h +interp dq 06000400020000000h +rb_mask_555 dq 07c1f7c1f7c1f7c1fh +g_mask_555 dq 003e003e003e003e0h +rb_mask_565 dq 0f81ff81ff81ff81fh +g_mask_565 dq 007e007e007e007e0h + +cr_coeff dq 000003313e5fc0000h +cb_coeff dq 000000000f377408dh +rgb_bias dq 000007f2180887eebh + +msb_inv dq 08000800080008000h + + section .text + +;============================================================================ + +%macro YUV411PLANAR_TO_RGB_PROLOG 0 + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + mov ecx, [esp+8+16] + mov edx, [esp+12+16] + mov ebx, [esp+16+16] + mov ebp, [esp+20+16] + + pxor mm7, mm7 +%endmacro + +%macro YUV411PLANAR_TO_RGB_CORE_MMX 0 + movd mm0, dword [ecx] ;mm0 = Y3Y2Y1Y0 + add ecx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + movq mm1, mm0 + pmullw mm0, [y_co] + paddw mm1, [y_bias] + paddsw mm0, mm0 + paddsw mm0, mm1 + + movzx esi, word [ebx] + movzx edi, word [edx] + add ebx, 1 + add edx, 1 + + movd mm1, esi + movd mm2, edi + + punpcklbw mm1, mm7 + paddw mm1, [c_bias] + punpcklwd mm1, mm1 + movq mm3, mm1 + punpckldq mm1, mm1 + punpckhdq mm3, mm3 + + punpcklbw mm2, mm7 + paddw mm2, [c_bias] + punpcklwd mm2, mm2 + movq mm4, mm2 + punpckldq mm2, mm2 + punpckhdq mm4, mm4 + + psubw mm3, mm1 + psubw mm4, mm2 + paddw mm3, mm3 + paddw mm4, mm4 + + pmulhw mm3, [interp] + pmulhw mm4, [interp] + + paddw mm1, mm3 + paddw mm2, mm4 + + movq mm3, mm1 + movq mm4, mm2 + + pmullw mm1, [cr_co_r] + pmullw mm2, [cb_co_b] + pmullw mm3, [cr_co_g] + pmullw mm4, [cb_co_g] + + paddsw mm2, mm2 + paddsw mm1, mm0 + paddsw mm3, mm4 + paddsw mm2, mm0 + paddsw mm3, mm0 + + psraw mm1, 7 + psraw mm2, 7 + psraw mm3, 7 + + packuswb mm1, mm1 + packuswb mm2, mm2 + packuswb mm3, mm3 +%endmacro + +%macro YUV411PLANAR_TO_RGB_CORE_ISSE 0 + movd mm0, dword [ecx] ;mm0 = Y3Y2Y1Y0 + add ecx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + movq mm1, mm0 + pmullw mm0, [y_co] + paddw mm1, [y_bias] + paddsw mm0, mm0 + paddsw mm0, mm1 + + movzx esi, word [ebx] + movzx edi, word [edx] + add ebx, 1 + add edx, 1 + + movd mm1, esi + movd mm2, edi + + punpcklbw mm1, mm7 + paddw mm1, [c_bias] + pshufw mm3, mm1, 01010101b + pshufw mm1, mm1, 00000000b + + punpcklbw mm2, mm7 + paddw mm2, [c_bias] + pshufw mm4, mm2, 01010101b + pshufw mm2, mm2, 00000000b + + psubw mm3, mm1 + psubw mm4, mm2 + paddw mm3, mm3 + paddw mm4, mm4 + + pmulhw mm3, [interp] + pmulhw mm4, [interp] + + paddw mm1, mm3 + paddw mm2, mm4 + + psllw mm1, 3 + psllw mm2, 3 + + movq mm3, [cr_co_g] + movq mm4, [cb_co_g] + + pmullw mm3, mm1 + pmullw mm4, mm2 + pmullw mm1, [cr_co_r] + pmullw mm2, [cb_co_b] + + paddsw mm2, mm2 + paddsw mm1, mm0 + paddsw mm3, mm4 + paddsw mm2, mm0 + paddsw mm3, mm0 + + psraw mm1, 7 + psraw mm2, 7 + psraw mm3, 7 + + packuswb mm1, mm1 + packuswb mm2, mm2 + packuswb mm3, mm3 +%endmacro + +%macro YUV411PLANAR_TO_RGB_EPILOG 0 + pop ebx + pop esi + pop edi + pop ebp + ret +%endmacro + + global _vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX +_vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_CORE_MMX + + psrlw mm1, 1 + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 2 + pand mm2, [rb_mask_555] + pand mm3, [g_mask_555] + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX +_vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_CORE_MMX + + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 3 + pand mm2, [rb_mask_565] + pand mm3, [g_mask_565] + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX +_vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_PROLOG + + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + movq mm1, mm2 + punpcklbw mm1, mm3 + punpckhbw mm2, mm3 + + movq [eax], mm1 + movq [eax+8], mm2 + add eax, 16 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE +_vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_CORE_ISSE + + psrlw mm1, 1 + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 2 + pand mm2, [rb_mask_555] + pand mm3, [g_mask_555] + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE +_vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_CORE_ISSE + + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 3 + pand mm2, [rb_mask_565] + pand mm3, [g_mask_565] + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE +_vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + mov ecx, [esp+8+16] + mov edx, [esp+12+16] + mov ebx, [esp+16+16] + mov ebp, [esp+20+16] + + pxor mm7, mm7 + + movzx esi, byte [ebx] + movzx edi, byte [edx] + add ebx, 1 + add edx, 1 + + movd mm1, esi + movd mm2, edi + + psllw mm1, 3 + psllw mm2, 3 + + pshufw mm5, mm1, 0 + pshufw mm6, mm2, 0 + + pmulhw mm5, [cr_coeff] + pmulhw mm6, [cb_coeff] + paddw mm6, mm5 + paddw mm6, [rgb_bias] + +.xloop: + movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 + add ecx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + psllw mm0, 3 + pmulhw mm0, [y_co] + pxor mm0, [msb_inv] + + movzx esi, byte [ebx] + movzx edi, byte [edx] + add ebx, 1 + add edx, 1 + + movd mm1, esi + movd mm2, edi + + psllw mm1, 3 + psllw mm2, 3 + + pshufw mm1, mm1, 0 + pshufw mm2, mm2, 0 + + pmulhw mm1, [cr_coeff] + pmulhw mm2, [cb_coeff] + paddw mm1, mm2 + paddw mm1, [rgb_bias] + + movq mm2, mm1 + pavgw mm2, mm6 ;mm2 = 1/2 + pshufw mm3, mm0, 00000000b + paddw mm3, mm6 + pavgw mm6, mm2 ;mm1 = 1/4 + pshufw mm4, mm0, 01010101b + paddw mm4, mm6 + packuswb mm3, mm4 + movq [eax], mm3 + + pshufw mm3, mm0, 10101010b + paddw mm3, mm2 + pshufw mm0, mm0, 11111111b + pavgw mm2, mm1 ;mm2 = 3/4 + paddw mm2, mm0 + packuswb mm3, mm2 + movq [eax+8], mm3 + + movq mm6, mm1 + + add eax, 16 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;========================================================================== + +%macro YUV444PLANAR_TO_RGB_PROLOG 0 + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + mov ecx, [esp+8+16] + mov edx, [esp+12+16] + mov ebx, [esp+16+16] + mov ebp, [esp+20+16] +%endmacro + +%macro YUV444PLANAR_TO_RGB_CORE 0 + movq mm3, mm0 + pmullw mm0, [y_co] + paddw mm1, [c_bias] + paddw mm2, [c_bias] + paddw mm0, [y_bias] + paddsw mm0, mm0 + paddsw mm0, mm3 + + movq mm3, [cr_co_g] + movq mm4, [cb_co_g] + + pmullw mm3, mm1 + pmullw mm4, mm2 + pmullw mm1, [cr_co_r] + pmullw mm2, [cb_co_b] + + paddsw mm2, mm2 + paddsw mm1, mm0 + paddsw mm3, mm4 + paddsw mm2, mm0 + paddsw mm3, mm0 + + psraw mm1, 7 + psraw mm2, 7 + psraw mm3, 7 + + packuswb mm1, mm1 + packuswb mm2, mm2 + packuswb mm3, mm3 +%endmacro + +%macro YUV444PLANAR_TO_RGB_EPILOG 0 + pop ebx + pop esi + pop edi + pop ebp + ret +%endmacro + +;========================================================================== + + global _vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX +_vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX: + YUV444PLANAR_TO_RGB_PROLOG + + pxor mm7, mm7 + movq mm5, [rb_mask_555] + movq mm6, [g_mask_555] + + sub ebp, 3 + jbe .oddcheck +.xloop4: + movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 + movd mm1, dword [ebx] + movd mm2, dword [edx] + add ecx, 4 + add ebx, 4 + add edx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + punpcklbw mm1, mm7 + punpcklbw mm2, mm7 + + YUV444PLANAR_TO_RGB_CORE + + psrlw mm1, 1 + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 2 + pand mm2, mm5 + pand mm3, mm6 + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 4 + ja .xloop4 +.oddcheck: + add ebp, 3 + jz .noodd +.xloop: + movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 + movd mm0, edi + movzx edi, byte [ebx] + movd mm1, edi + movzx edi, byte [edx] + movd mm2, edi + add ecx, 1 + add ebx, 1 + add edx, 1 + + YUV444PLANAR_TO_RGB_CORE + + psrlw mm1, 1 + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 2 + pand mm2, mm5 + pand mm3, mm6 + por mm2, mm3 + + movd edi, mm2 + mov [eax], di + add eax, 2 + + sub ebp, 1 + jnz .xloop +.noodd: + YUV444PLANAR_TO_RGB_EPILOG + +;========================================================================== + + global _vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX +_vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX: + YUV444PLANAR_TO_RGB_PROLOG + + pxor mm7, mm7 + movq mm5, [rb_mask_565] + movq mm6, [g_mask_565] + + sub ebp, 3 + jbe .oddcheck +.xloop4: + movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 + movd mm1, dword [ebx] + movd mm2, dword [edx] + add ecx, 4 + add ebx, 4 + add edx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + punpcklbw mm1, mm7 + punpcklbw mm2, mm7 + + YUV444PLANAR_TO_RGB_CORE + + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 3 + pand mm2, mm5 + pand mm3, mm6 + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 4 + ja .xloop4 +.oddcheck: + add ebp, 3 + jz .noodd +.xloop: + movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 + movd mm0, edi + movzx edi, byte [ebx] + movd mm1, edi + movzx edi, byte [edx] + movd mm2, edi + add ecx, 1 + add ebx, 1 + add edx, 1 + + YUV444PLANAR_TO_RGB_CORE + + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 3 + pand mm2, mm5 + pand mm3, mm6 + por mm2, mm3 + + movd edi, mm2 + mov [eax], di + add eax, 2 + + sub ebp, 1 + jnz .xloop +.noodd: + YUV444PLANAR_TO_RGB_EPILOG + +;========================================================================== + + global _vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX +_vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX: + YUV444PLANAR_TO_RGB_PROLOG + + pxor mm7, mm7 + + sub ebp, 3 + jbe .oddcheck +.xloop4: + movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 + movd mm1, dword [ebx] + movd mm2, dword [edx] + add ecx, 4 + add ebx, 4 + add edx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + punpcklbw mm1, mm7 + punpcklbw mm2, mm7 + + YUV444PLANAR_TO_RGB_CORE + + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + movq mm1, mm2 + punpcklbw mm1, mm3 + punpckhbw mm2, mm3 + + movq [eax], mm1 + movq [eax+8], mm2 + add eax, 16 + + sub ebp, 4 + ja .xloop4 +.oddcheck: + add ebp, 3 + jz .noodd +.xloop: + movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 + movd mm0, edi + movzx edi, byte [ebx] + movd mm1, edi + movzx edi, byte [edx] + movd mm2, edi + add ecx, 1 + add ebx, 1 + add edx, 1 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + + YUV444PLANAR_TO_RGB_CORE + + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + punpcklbw mm2, mm3 + + movd dword [eax], mm2 + add eax, 4 + + sub ebp, 1 + jnz .xloop +.noodd: + YUV444PLANAR_TO_RGB_EPILOG + end \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb_mmx.asm index aa0b99987eb..9fccfad4d72 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb_mmx.asm @@ -1,806 +1,806 @@ - section .rdata, rdata - -x07b dq 00707070707070707h -x0200w dq 00200020002000200h -x001fw dq 0001f001f001f001fh -xffc0w dq 0ffc0ffc0ffc0ffc0h -xffe0w dq 0ffe0ffe0ffe0ffe0h -x2080w dq 02080208020802080h -x4200w dq 04200420042004200h -rb_mask5 dq 000f800f800f800f8h -g_mask5 dq 00000f8000000f800h -g_mask6 dq 00000fc000000fc00h -rb_mul_565 dq 02000000420000004h -rb_mul_555 dq 02000000820000008h -r_mask_555 dq 07c007c007c007c00h -g_mask_555 dq 003e003e003e003e0h -b_mask_555 dq 0001f001f001f001fh -r_mask_565 dq 0f800f800f800f800h -g_mask_565 dq 007e007e007e007e0h -b_mask_565 dq 0001f001f001f001fh - -%macro prologue 1 - push ebx - push esi - push edi - push ebp - ;.fpo (0,%1,4,4,1,0) -%endmacro - -%macro epilogue 0 - pop ebp - pop edi - pop esi - pop ebx -%endmacro - - section .text - - global _vdasm_pixblt_RGB565_to_XRGB1555_MMX -_vdasm_pixblt_RGB565_to_XRGB1555_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-6] - lea ecx, [ecx+ebp-6] - neg ebp - mov [esp+20+16], ebp - - movq mm5, [x001fw] - movq mm4, [xffc0w] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 6 - jbe .odd - -.xloop: - movq mm0, [ecx+ebp] - movq mm1, mm5 - pand mm1, mm0 - pand mm0, mm4 - psrlq mm0, 1 - paddw mm0, mm1 - movq [edx+ebp], mm0 - add ebp, 8 - jnc .xloop - - sub ebp, 6 - jz .noodd -.odd: - movzx eax, word [ecx+ebp+6] - mov ebx, 0001f001fh - and ebx, eax - and eax, 0ffc0ffc0h - shr eax, 1 - add eax, ebx - mov [edx+ebp+6], ax - add ebp, 2 - jnz .odd -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - global _vdasm_pixblt_XRGB8888_to_XRGB1555_MMX -_vdasm_pixblt_XRGB8888_to_XRGB1555_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-14] - lea ecx, [ecx+ebp*2-28] - neg ebp - mov [esp+20+16], ebp - - movq mm5,[rb_mul_555] - movq mm6,[rb_mask5] - movq mm7,[g_mask5] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 14 - jbe .odd - - ;This code uses the "pmaddwd" trick for 32->16 conversions from Intel's MMX - ;Application Notes. - - movq mm0,[ecx+ebp*2] ;allocate 0 (0123) - movq mm2,mm0 ;allocate 2 (0 23) - - movq mm1,[ecx+ebp*2+8] ;allocate 1 (0123) - movq mm3,mm1 ;allocate 3 (0123) - pand mm0,mm6 - pmaddwd mm0,mm5 - pand mm1,mm6 - pmaddwd mm1,mm5 - pand mm2,mm7 - pand mm3,mm7 - jmp .xloopstart - - align 16 -.xloop: - movq mm0,[ecx+ebp*2] ;allocate 0 (01234) - por mm4,mm2 ;free 2 (01 34) - - por mm3,mm1 ;free 3 (01 34) - movq mm2,mm0 ;allocate 2 (0 234) - - movq mm1,[ecx+ebp*2+8] ;allocate 1 (01234) - psrld mm4,6 - - psrld mm3,6 - pand mm0,mm6 - - packssdw mm4,mm3 ;free 3 (012 4) - movq mm3,mm1 ;allocate 3 (01234) - - pmaddwd mm0,mm5 - pand mm1,mm6 - - pmaddwd mm1,mm5 - pand mm2,mm7 - - movq [edx+ebp-8],mm4 ;free 4 (0123 ) - pand mm3,mm7 - -.xloopstart: - movq mm4,[ecx+ebp*2+16] ;allocate 4 (01234) - por mm0,mm2 ;free 2 (01 34) - - por mm1,mm3 ;free 3 (01 4) - psrld mm0,6 - - movq mm3,[ecx+ebp*2+24] ;allocate 3 (01 34) - movq mm2,mm4 ;allocate 2 (01234) - - psrld mm1,6 - pand mm4,mm6 - - packssdw mm0,mm1 ;free 1 (0 234) - movq mm1,mm3 ;allocate 1 (01234) - - movq [edx+ebp],mm0 ;free 0 ( 1234) - pand mm3,mm6 - - pmaddwd mm4,mm5 - add ebp,16 - - pmaddwd mm3,mm5 - pand mm2,mm7 - - pand mm1,mm7 - jnc .xloop - - por mm4,mm2 ;free 2 (01 34) - por mm3,mm1 ;free 3 (01 34) - psrld mm4,6 - psrld mm3,6 - packssdw mm4,mm3 ;free 3 (012 4) - movq [edx+ebp-8],mm4 ;free 4 (0123 ) - -.odd: - sub ebp, 14 - jz .noodd -.oddloop: - mov eax, [ecx+ebp*2+28] - mov ebx, 00f80000h - mov esi, eax - and ebx, eax - shr ebx, 9 - and esi, 0000f800h - shr esi, 6 - and eax, 000000f8h - shr eax, 3 - add esi, ebx - add eax, esi - mov [edx+ebp+14], ax - add ebp, 2 - jnz .oddloop -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - global _vdasm_pixblt_XRGB1555_to_RGB565_MMX -_vdasm_pixblt_XRGB1555_to_RGB565_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-6] - lea ecx, [ecx+ebp-6] - neg ebp - mov [esp+20+16], ebp - - movq mm5, [x0200w] - movq mm4, [xffe0w] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 6 - jbe .odd - -.xloop: - movq mm0, [ecx+ebp] - movq mm1, mm4 - movq mm2, mm0 - pand mm1, mm0 - pand mm0, mm5 - paddw mm1, mm2 - psrlq mm0, 4 - paddw mm0, mm1 - movq [edx+ebp], mm0 - add ebp, 8 - jnc .xloop - -.odd: - sub ebp, 6 - jz .noodd -.oddloop: - movzx eax, word [ecx+ebp+6] - mov ebx, 02000200h - mov esi, eax - and ebx, eax - shr ebx, 4 - and esi, 0ffe0ffe0h - add eax, esi - add eax, ebx - mov [edx+ebp+6], ax - add ebp, 2 - jnz .oddloop -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - - global _vdasm_pixblt_XRGB8888_to_RGB565_MMX -_vdasm_pixblt_XRGB8888_to_RGB565_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-14] - lea ecx, [ecx+ebp*2-28] - neg ebp - mov [esp+20+16], ebp - - movq mm5,[rb_mul_565] - movq mm6,[rb_mask5] - movq mm7,[g_mask6] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 14 - jbe .odd - - ;This code uses the "pmaddwd" trick for 32->16 conversions from Intel's MMX - ;Application Notes. - - movq mm0,[ecx+ebp*2] ;allocate 0 (0123) - movq mm2,mm0 ;allocate 2 (0 23) - - movq mm1,[ecx+ebp*2+8] ;allocate 1 (0123) - movq mm3,mm1 ;allocate 3 (0123) - pand mm0,mm6 - pmaddwd mm0,mm5 - pand mm1,mm6 - pmaddwd mm1,mm5 - pand mm2,mm7 - pand mm3,mm7 - jmp .xloopstart - - align 16 -.xloop: - movq mm0,[ecx+ebp*2] ;allocate 0 (01234) - por mm4,mm2 ;free 2 (01 34) - - por mm3,mm1 ;free 3 (01 34) - pslld mm4,16-5 - - pslld mm3,16-5 - movq mm2,mm0 ;allocate 2 (0 234) - - movq mm1,[ecx+ebp*2+8] ;allocate 1 (01234) - psrad mm4,16 - - psrad mm3,16 - pand mm0,mm6 - - packssdw mm4,mm3 ;free 3 (012 4) - movq mm3,mm1 ;allocate 3 (01234) - - pmaddwd mm0,mm5 - pand mm1,mm6 - - pmaddwd mm1,mm5 - pand mm2,mm7 - - movq [edx+ebp-8],mm4 ;free 4 (0123 ) - pand mm3,mm7 - -.xloopstart: - movq mm4,[ecx+ebp*2+16] ;allocate 4 (01234) - por mm0,mm2 ;free 2 (01 34) - - por mm1,mm3 ;free 3 (01 4) - pslld mm0,16-5 - - movq mm3,[ecx+ebp*2+24] ;allocate 3 (01 34) - pslld mm1,16-5 - - psrad mm0,16 - movq mm2,mm4 ;allocate 2 (01234) - - psrad mm1,16 - pand mm4,mm6 - - packssdw mm0,mm1 ;free 1 (0 234) - movq mm1,mm3 ;allocate 1 (01234) - - movq [edx+ebp],mm0 ;free 0 ( 1234) - pand mm3,mm6 - - pmaddwd mm4,mm5 - add ebp,16 - - pmaddwd mm3,mm5 - pand mm2,mm7 - - pand mm1,mm7 - jnc .xloop - - por mm4,mm2 ;free 2 (01 34) - por mm3,mm1 ;free 3 (01 34) - psllq mm4,16-5 - psllq mm3,16-5 - psrad mm4,16 - psrad mm3,16 - packssdw mm4,mm3 ;free 3 (012 4) - movq [edx+ebp-8],mm4 ;free 4 (0123 ) - -.odd: - sub ebp, 14 - jz .noodd -.oddloop: - mov eax, [ecx+ebp*2+28] - mov ebx, 00f80000h - mov esi, eax - and ebx, eax - and eax, 000000f8h - shr eax, 3 - and esi, 0000fc00h - shr ebx, 8 - shr esi, 5 - add eax, ebx - add eax, esi - mov [edx+ebp+14], ax - add ebp, 2 - jnz .oddloop -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - global _vdasm_pixblt_XRGB8888_to_RGB888_MMX -_vdasm_pixblt_XRGB8888_to_RGB888_MMX: - prologue 6 - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ecx,[esp+20+16] - lea eax,[ecx+ecx*2] - lea ebx,[ecx*4] - sub [esp+8+16],eax - sub [esp+16+16],ebx - - pcmpeqb mm7,mm7 - psrld mm7,8 - movq mm6,mm7 - psllq mm7,32 ;mm7 = high rgb mask - psrlq mm6,32 ;mm6 = low rgb mask - - mov ebp,[esp+20+16] - mov edx,[esp+24+16] - mov eax,[esp+16+16] - mov ebx,[esp+ 8+16] -.yloop: - mov ecx,ebp - shr ecx,3 - jz .checkodd -.xloop: - movq mm0,[esi] ;mm0 = a1r1g1b1a0r0g0b0 - movq mm1,mm6 - - movq mm2,[esi+8] ;mm2 = a3r3g3b3a2r2g2b2 - pand mm1,mm0 ;mm1 = ----------r0g0b0 - - movq mm3,mm6 - pand mm0,mm7 ;mm0 = --r1g1b1-------- - - movq mm4,mm2 - pand mm3,mm2 ;mm3 = ----------r2g2b2 - - psrlq mm0,8 ;mm0 = ----r1g1b1------ - pand mm2,mm7 ;mm2 = --r3g3b3-------- - - movq mm5,[esi+16] ;mm5 = a5r5g5b5a4r4g4b4 - psllq mm4,48 ;mm4 = g2b2------------ - - por mm0,mm1 ;mm0 = ----r1g1b1r0g0b0 - psrlq mm3,16 ;mm3 = --------------r2 - - por mm0,mm4 ;mm0 = g2b2r1g1b1r0g0b0 - movq mm1,mm6 - - pand mm1,mm5 ;mm1 = ----------r4g4b4 - psrlq mm2,24 ;mm2 = --------r3g3b3-- - - movq [edi],mm0 - pand mm5,mm7 ;mm5 = --r5g5b5-------- - - psllq mm1,32 ;mm1 = --r4g4b4-------- - movq mm4,mm5 ;mm4 = --r5g5b5-------- - - por mm2,mm3 ;mm2 = --------r3g3b3r2 - psllq mm5,24 ;mm5 = b5-------------- - - movq mm3,[esi+24] ;mm3 = a7r7g7b7a6r6g6b6 - por mm2,mm1 ;mm2 = --r4g4b4r3g3b3r2 - - movq mm1,mm6 - por mm2,mm5 ;mm2 = b5r4g4b4r3g3b3r2 - - psrlq mm4,40 ;mm4 = ------------r5g5 - pand mm1,mm3 ;mm1 = ----------r6g6b6 - - psllq mm1,16 ;mm1 = ------r6g6b6---- - pand mm3,mm7 ;mm3 = --r7g7b7-------- - - por mm4,mm1 ;mm4 = ------r6g6b6r5g5 - psllq mm3,8 ;mm3 = r7g7b7---------- - - movq [edi+8],mm2 - por mm4,mm3 ;mm4 = r7g7b7r6g6b6r5g5 - - add esi,32 - sub ecx,1 - - movq [edi+16],mm4 ;mm3 - - lea edi,[edi+24] - jne .xloop - -.checkodd: - mov ecx,ebp - and ecx,7 - jz .noodd - movd mm0,eax -.oddloop: - mov eax,[esi] - add esi,4 - mov [edi],ax - shr eax,16 - mov [edi+2],al - add edi,3 - sub ecx,1 - jnz .oddloop - movd eax,mm0 -.noodd: - add esi,eax - add edi,ebx - - sub edx,1 - jne .yloop - - emms - - epilogue - ret - - global _vdasm_pixblt_XRGB1555_to_XRGB8888_MMX -_vdasm_pixblt_XRGB1555_to_XRGB8888_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp*2-12] - lea ecx, [ecx+ebp-6] - neg ebp - mov [esp+20+16], ebp - - movq mm5, [r_mask_555] - movq mm6, [g_mask_555] - movq mm7, [b_mask_555] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 6 - jbe .odd - -.xloop: - movq mm0, [ecx+ebp] - movq mm1, mm6 - movq mm2, mm7 - pand mm1, mm0 - pand mm2, mm0 - pand mm0, mm5 - - paddw mm0, mm0 - pmulhw mm1, [x4200w] - psllq mm2, 3 - paddw mm0, mm2 - movq mm2, mm0 - psrlw mm0, 5 - pand mm0, [x07b] - paddw mm0, mm2 - movq mm2, mm0 - punpcklbw mm0, mm1 - punpckhbw mm2, mm1 - - movq [edx+ebp*2], mm0 - movq [edx+ebp*2+8], mm2 - add ebp, 8 - jnc .xloop -.odd: - sub ebp, 6 - jz .noodd -.oddloop: - movzx eax, word [ecx+ebp+6] - mov ebx, 03e0h - mov esi, 001fh - and ebx, eax - and esi, eax - and eax, 07c00h - shl esi, 3 - shl ebx, 6 - shl eax, 9 - add ebx, esi - add eax, ebx - mov ebx, eax - shr eax, 5 - and eax, 070707h - add eax, ebx - mov [edx+ebp*2+12], eax - add ebp, 2 - jnz .oddloop -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - - global _vdasm_pixblt_RGB565_to_XRGB8888_MMX -_vdasm_pixblt_RGB565_to_XRGB8888_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp*2-12] - lea ecx, [ecx+ebp-6] - neg ebp - mov [esp+20+16], ebp - - movq mm5, [r_mask_565] - movq mm6, [g_mask_565] - movq mm7, [b_mask_565] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 6 - jbe .odd - -.xloop: - movq mm0, [ecx+ebp] - movq mm1, mm6 - movq mm2, mm7 - pand mm1, mm0 - pand mm2, mm0 - pand mm0, mm5 - - pmulhw mm1, [x2080w] - psllq mm2, 3 - paddw mm0, mm2 - movq mm2, mm0 - psrlw mm0, 5 - pand mm0, [x07b] - paddw mm0, mm2 - movq mm2, mm0 - punpcklbw mm0, mm1 - punpckhbw mm2, mm1 - - movq [edx+ebp*2], mm0 - movq [edx+ebp*2+8], mm2 - add ebp, 8 - jnc .xloop - -.odd: - sub ebp, 6 - jz .noodd - push edi -.oddloop: - movzx eax, word [ecx+ebp+6] - mov ebx, 0000f800h - and ebx, eax - mov esi, eax - shl ebx, 8 - mov edi, eax - shl eax, 3 - and esi, 000007e0h - and eax, 000000f8h - add ebx, eax - shl esi, 5 - mov eax, ebx - shr ebx, 5 - and edi, 00000600h - shr edi, 1 - and ebx, 00070007h - add esi, edi - add eax, ebx - add eax, esi - mov [edx+ebp*2+12], eax - add ebp, 2 - jnz .oddloop - pop edi -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - - global _vdasm_pixblt_RGB888_to_XRGB8888_MMX -_vdasm_pixblt_RGB888_to_XRGB8888_MMX: - prologue 6 - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ecx,[esp+20+16] - lea eax,[ecx+ecx*2] - lea ebx,[ecx*4] - sub [esp+8+16],ebx - sub [esp+16+16],eax - - mov edx,[esp+24+16] - mov ebx,[esp+20+16] - mov ecx,[esp+16+16] - mov eax,[esp+ 8+16] - - ;ebx horizontal count backup - ;ecx source modulo - ;edx vertical count - ;esi source - ;edi destination - ;ebp horizontal count - -.yloop: - mov ebp,ebx - shr ebp,3 - jz .checkodd -.xloop: - movq mm0,[esi] ;mm0: g2b2r1g1b1r0g0b0 - movq mm1,mm0 ; - - psrlq mm1,24 ;mm1: ------g2b2r1g1b1 - movq mm2,mm0 ; - - movq mm3,[esi+8] ;mm3: b5r4g4b4r3g3b3r2 - punpckldq mm0,mm1 ;mm0: b2r1g1b1b1r0g0b0 [qword 0 ready] - - movq mm4,mm3 ;mm4: b5r4g4b4r3g3b3r2 - psllq mm3,48 ;mm3: b3r2------------ - - movq mm5,mm4 ;mm5: b5r4g4b4r3g3b3r2 - psrlq mm2,16 ;mm2: ----g2b2-------- - - movq mm1,[esi+16] ;mm1: r7g7b7r6g6b6r5g5 - por mm2,mm3 ;mm2: b3r2g2b2-------- - - movq [edi],mm0 ; - psllq mm4,24 ;mm4: b4r3g3b3r2------ - - movq mm3,mm5 ;mm3: b5r4g4b4r3g3b3r2 - psrlq mm5,24 ;mm5: ------b5r4g4b4r3 - - movq mm0,mm1 ;mm0: r7g7b7r6g6b6r5g5 - psllq mm1,40 ;mm1: b6r5g5---------- - - punpckhdq mm2,mm4 ;mm2: b4r3g3b3b3r2g2b2 [qword 1 ready] - por mm1,mm5 ;mm1: b6r5g5b5r4g4b4r3 - - movq mm4,mm0 ;mm4: r7g7b7r6g6b6r5g5 - punpckhdq mm3,mm1 ;mm3: b6r5g5b5b5r4g4b4 [qword 2 ready] - - movq [edi+8],mm2 - psrlq mm0,16 ;mm0: ----r7g7b7r6g6b6 - - movq [edi+16],mm3 - psrlq mm4,40 ;mm4: ----------r7g7b7 - - punpckldq mm0,mm4 ;mm0: --r7g7b7b7r6g6b6 [qword 3 ready] - add esi,24 - - movq [edi+24],mm0 - - add edi,32 - sub ebp,1 - jne .xloop - -.checkodd: - mov ebp,ebx - and ebp,7 - jz .noodd - movd mm7,eax -.oddloop: - mov ax,[esi] - mov [edi],ax - mov al,[esi+2] - mov [edi+2],al - add esi,3 - add edi,4 - sub ebp,1 - jne .oddloop - - movd eax,mm7 -.noodd: - add esi,ecx - add edi,eax - - sub edx,1 - jne .yloop - emms - epilogue - ret - - end + section .rdata, rdata + +x07b dq 00707070707070707h +x0200w dq 00200020002000200h +x001fw dq 0001f001f001f001fh +xffc0w dq 0ffc0ffc0ffc0ffc0h +xffe0w dq 0ffe0ffe0ffe0ffe0h +x2080w dq 02080208020802080h +x4200w dq 04200420042004200h +rb_mask5 dq 000f800f800f800f8h +g_mask5 dq 00000f8000000f800h +g_mask6 dq 00000fc000000fc00h +rb_mul_565 dq 02000000420000004h +rb_mul_555 dq 02000000820000008h +r_mask_555 dq 07c007c007c007c00h +g_mask_555 dq 003e003e003e003e0h +b_mask_555 dq 0001f001f001f001fh +r_mask_565 dq 0f800f800f800f800h +g_mask_565 dq 007e007e007e007e0h +b_mask_565 dq 0001f001f001f001fh + +%macro prologue 1 + push ebx + push esi + push edi + push ebp + ;.fpo (0,%1,4,4,1,0) +%endmacro + +%macro epilogue 0 + pop ebp + pop edi + pop esi + pop ebx +%endmacro + + section .text + + global _vdasm_pixblt_RGB565_to_XRGB1555_MMX +_vdasm_pixblt_RGB565_to_XRGB1555_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-6] + lea ecx, [ecx+ebp-6] + neg ebp + mov [esp+20+16], ebp + + movq mm5, [x001fw] + movq mm4, [xffc0w] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 6 + jbe .odd + +.xloop: + movq mm0, [ecx+ebp] + movq mm1, mm5 + pand mm1, mm0 + pand mm0, mm4 + psrlq mm0, 1 + paddw mm0, mm1 + movq [edx+ebp], mm0 + add ebp, 8 + jnc .xloop + + sub ebp, 6 + jz .noodd +.odd: + movzx eax, word [ecx+ebp+6] + mov ebx, 0001f001fh + and ebx, eax + and eax, 0ffc0ffc0h + shr eax, 1 + add eax, ebx + mov [edx+ebp+6], ax + add ebp, 2 + jnz .odd +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + global _vdasm_pixblt_XRGB8888_to_XRGB1555_MMX +_vdasm_pixblt_XRGB8888_to_XRGB1555_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-14] + lea ecx, [ecx+ebp*2-28] + neg ebp + mov [esp+20+16], ebp + + movq mm5,[rb_mul_555] + movq mm6,[rb_mask5] + movq mm7,[g_mask5] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 14 + jbe .odd + + ;This code uses the "pmaddwd" trick for 32->16 conversions from Intel's MMX + ;Application Notes. + + movq mm0,[ecx+ebp*2] ;allocate 0 (0123) + movq mm2,mm0 ;allocate 2 (0 23) + + movq mm1,[ecx+ebp*2+8] ;allocate 1 (0123) + movq mm3,mm1 ;allocate 3 (0123) + pand mm0,mm6 + pmaddwd mm0,mm5 + pand mm1,mm6 + pmaddwd mm1,mm5 + pand mm2,mm7 + pand mm3,mm7 + jmp .xloopstart + + align 16 +.xloop: + movq mm0,[ecx+ebp*2] ;allocate 0 (01234) + por mm4,mm2 ;free 2 (01 34) + + por mm3,mm1 ;free 3 (01 34) + movq mm2,mm0 ;allocate 2 (0 234) + + movq mm1,[ecx+ebp*2+8] ;allocate 1 (01234) + psrld mm4,6 + + psrld mm3,6 + pand mm0,mm6 + + packssdw mm4,mm3 ;free 3 (012 4) + movq mm3,mm1 ;allocate 3 (01234) + + pmaddwd mm0,mm5 + pand mm1,mm6 + + pmaddwd mm1,mm5 + pand mm2,mm7 + + movq [edx+ebp-8],mm4 ;free 4 (0123 ) + pand mm3,mm7 + +.xloopstart: + movq mm4,[ecx+ebp*2+16] ;allocate 4 (01234) + por mm0,mm2 ;free 2 (01 34) + + por mm1,mm3 ;free 3 (01 4) + psrld mm0,6 + + movq mm3,[ecx+ebp*2+24] ;allocate 3 (01 34) + movq mm2,mm4 ;allocate 2 (01234) + + psrld mm1,6 + pand mm4,mm6 + + packssdw mm0,mm1 ;free 1 (0 234) + movq mm1,mm3 ;allocate 1 (01234) + + movq [edx+ebp],mm0 ;free 0 ( 1234) + pand mm3,mm6 + + pmaddwd mm4,mm5 + add ebp,16 + + pmaddwd mm3,mm5 + pand mm2,mm7 + + pand mm1,mm7 + jnc .xloop + + por mm4,mm2 ;free 2 (01 34) + por mm3,mm1 ;free 3 (01 34) + psrld mm4,6 + psrld mm3,6 + packssdw mm4,mm3 ;free 3 (012 4) + movq [edx+ebp-8],mm4 ;free 4 (0123 ) + +.odd: + sub ebp, 14 + jz .noodd +.oddloop: + mov eax, [ecx+ebp*2+28] + mov ebx, 00f80000h + mov esi, eax + and ebx, eax + shr ebx, 9 + and esi, 0000f800h + shr esi, 6 + and eax, 000000f8h + shr eax, 3 + add esi, ebx + add eax, esi + mov [edx+ebp+14], ax + add ebp, 2 + jnz .oddloop +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + global _vdasm_pixblt_XRGB1555_to_RGB565_MMX +_vdasm_pixblt_XRGB1555_to_RGB565_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-6] + lea ecx, [ecx+ebp-6] + neg ebp + mov [esp+20+16], ebp + + movq mm5, [x0200w] + movq mm4, [xffe0w] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 6 + jbe .odd + +.xloop: + movq mm0, [ecx+ebp] + movq mm1, mm4 + movq mm2, mm0 + pand mm1, mm0 + pand mm0, mm5 + paddw mm1, mm2 + psrlq mm0, 4 + paddw mm0, mm1 + movq [edx+ebp], mm0 + add ebp, 8 + jnc .xloop + +.odd: + sub ebp, 6 + jz .noodd +.oddloop: + movzx eax, word [ecx+ebp+6] + mov ebx, 02000200h + mov esi, eax + and ebx, eax + shr ebx, 4 + and esi, 0ffe0ffe0h + add eax, esi + add eax, ebx + mov [edx+ebp+6], ax + add ebp, 2 + jnz .oddloop +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + + global _vdasm_pixblt_XRGB8888_to_RGB565_MMX +_vdasm_pixblt_XRGB8888_to_RGB565_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-14] + lea ecx, [ecx+ebp*2-28] + neg ebp + mov [esp+20+16], ebp + + movq mm5,[rb_mul_565] + movq mm6,[rb_mask5] + movq mm7,[g_mask6] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 14 + jbe .odd + + ;This code uses the "pmaddwd" trick for 32->16 conversions from Intel's MMX + ;Application Notes. + + movq mm0,[ecx+ebp*2] ;allocate 0 (0123) + movq mm2,mm0 ;allocate 2 (0 23) + + movq mm1,[ecx+ebp*2+8] ;allocate 1 (0123) + movq mm3,mm1 ;allocate 3 (0123) + pand mm0,mm6 + pmaddwd mm0,mm5 + pand mm1,mm6 + pmaddwd mm1,mm5 + pand mm2,mm7 + pand mm3,mm7 + jmp .xloopstart + + align 16 +.xloop: + movq mm0,[ecx+ebp*2] ;allocate 0 (01234) + por mm4,mm2 ;free 2 (01 34) + + por mm3,mm1 ;free 3 (01 34) + pslld mm4,16-5 + + pslld mm3,16-5 + movq mm2,mm0 ;allocate 2 (0 234) + + movq mm1,[ecx+ebp*2+8] ;allocate 1 (01234) + psrad mm4,16 + + psrad mm3,16 + pand mm0,mm6 + + packssdw mm4,mm3 ;free 3 (012 4) + movq mm3,mm1 ;allocate 3 (01234) + + pmaddwd mm0,mm5 + pand mm1,mm6 + + pmaddwd mm1,mm5 + pand mm2,mm7 + + movq [edx+ebp-8],mm4 ;free 4 (0123 ) + pand mm3,mm7 + +.xloopstart: + movq mm4,[ecx+ebp*2+16] ;allocate 4 (01234) + por mm0,mm2 ;free 2 (01 34) + + por mm1,mm3 ;free 3 (01 4) + pslld mm0,16-5 + + movq mm3,[ecx+ebp*2+24] ;allocate 3 (01 34) + pslld mm1,16-5 + + psrad mm0,16 + movq mm2,mm4 ;allocate 2 (01234) + + psrad mm1,16 + pand mm4,mm6 + + packssdw mm0,mm1 ;free 1 (0 234) + movq mm1,mm3 ;allocate 1 (01234) + + movq [edx+ebp],mm0 ;free 0 ( 1234) + pand mm3,mm6 + + pmaddwd mm4,mm5 + add ebp,16 + + pmaddwd mm3,mm5 + pand mm2,mm7 + + pand mm1,mm7 + jnc .xloop + + por mm4,mm2 ;free 2 (01 34) + por mm3,mm1 ;free 3 (01 34) + psllq mm4,16-5 + psllq mm3,16-5 + psrad mm4,16 + psrad mm3,16 + packssdw mm4,mm3 ;free 3 (012 4) + movq [edx+ebp-8],mm4 ;free 4 (0123 ) + +.odd: + sub ebp, 14 + jz .noodd +.oddloop: + mov eax, [ecx+ebp*2+28] + mov ebx, 00f80000h + mov esi, eax + and ebx, eax + and eax, 000000f8h + shr eax, 3 + and esi, 0000fc00h + shr ebx, 8 + shr esi, 5 + add eax, ebx + add eax, esi + mov [edx+ebp+14], ax + add ebp, 2 + jnz .oddloop +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + global _vdasm_pixblt_XRGB8888_to_RGB888_MMX +_vdasm_pixblt_XRGB8888_to_RGB888_MMX: + prologue 6 + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ecx,[esp+20+16] + lea eax,[ecx+ecx*2] + lea ebx,[ecx*4] + sub [esp+8+16],eax + sub [esp+16+16],ebx + + pcmpeqb mm7,mm7 + psrld mm7,8 + movq mm6,mm7 + psllq mm7,32 ;mm7 = high rgb mask + psrlq mm6,32 ;mm6 = low rgb mask + + mov ebp,[esp+20+16] + mov edx,[esp+24+16] + mov eax,[esp+16+16] + mov ebx,[esp+ 8+16] +.yloop: + mov ecx,ebp + shr ecx,3 + jz .checkodd +.xloop: + movq mm0,[esi] ;mm0 = a1r1g1b1a0r0g0b0 + movq mm1,mm6 + + movq mm2,[esi+8] ;mm2 = a3r3g3b3a2r2g2b2 + pand mm1,mm0 ;mm1 = ----------r0g0b0 + + movq mm3,mm6 + pand mm0,mm7 ;mm0 = --r1g1b1-------- + + movq mm4,mm2 + pand mm3,mm2 ;mm3 = ----------r2g2b2 + + psrlq mm0,8 ;mm0 = ----r1g1b1------ + pand mm2,mm7 ;mm2 = --r3g3b3-------- + + movq mm5,[esi+16] ;mm5 = a5r5g5b5a4r4g4b4 + psllq mm4,48 ;mm4 = g2b2------------ + + por mm0,mm1 ;mm0 = ----r1g1b1r0g0b0 + psrlq mm3,16 ;mm3 = --------------r2 + + por mm0,mm4 ;mm0 = g2b2r1g1b1r0g0b0 + movq mm1,mm6 + + pand mm1,mm5 ;mm1 = ----------r4g4b4 + psrlq mm2,24 ;mm2 = --------r3g3b3-- + + movq [edi],mm0 + pand mm5,mm7 ;mm5 = --r5g5b5-------- + + psllq mm1,32 ;mm1 = --r4g4b4-------- + movq mm4,mm5 ;mm4 = --r5g5b5-------- + + por mm2,mm3 ;mm2 = --------r3g3b3r2 + psllq mm5,24 ;mm5 = b5-------------- + + movq mm3,[esi+24] ;mm3 = a7r7g7b7a6r6g6b6 + por mm2,mm1 ;mm2 = --r4g4b4r3g3b3r2 + + movq mm1,mm6 + por mm2,mm5 ;mm2 = b5r4g4b4r3g3b3r2 + + psrlq mm4,40 ;mm4 = ------------r5g5 + pand mm1,mm3 ;mm1 = ----------r6g6b6 + + psllq mm1,16 ;mm1 = ------r6g6b6---- + pand mm3,mm7 ;mm3 = --r7g7b7-------- + + por mm4,mm1 ;mm4 = ------r6g6b6r5g5 + psllq mm3,8 ;mm3 = r7g7b7---------- + + movq [edi+8],mm2 + por mm4,mm3 ;mm4 = r7g7b7r6g6b6r5g5 + + add esi,32 + sub ecx,1 + + movq [edi+16],mm4 ;mm3 + + lea edi,[edi+24] + jne .xloop + +.checkodd: + mov ecx,ebp + and ecx,7 + jz .noodd + movd mm0,eax +.oddloop: + mov eax,[esi] + add esi,4 + mov [edi],ax + shr eax,16 + mov [edi+2],al + add edi,3 + sub ecx,1 + jnz .oddloop + movd eax,mm0 +.noodd: + add esi,eax + add edi,ebx + + sub edx,1 + jne .yloop + + emms + + epilogue + ret + + global _vdasm_pixblt_XRGB1555_to_XRGB8888_MMX +_vdasm_pixblt_XRGB1555_to_XRGB8888_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp*2-12] + lea ecx, [ecx+ebp-6] + neg ebp + mov [esp+20+16], ebp + + movq mm5, [r_mask_555] + movq mm6, [g_mask_555] + movq mm7, [b_mask_555] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 6 + jbe .odd + +.xloop: + movq mm0, [ecx+ebp] + movq mm1, mm6 + movq mm2, mm7 + pand mm1, mm0 + pand mm2, mm0 + pand mm0, mm5 + + paddw mm0, mm0 + pmulhw mm1, [x4200w] + psllq mm2, 3 + paddw mm0, mm2 + movq mm2, mm0 + psrlw mm0, 5 + pand mm0, [x07b] + paddw mm0, mm2 + movq mm2, mm0 + punpcklbw mm0, mm1 + punpckhbw mm2, mm1 + + movq [edx+ebp*2], mm0 + movq [edx+ebp*2+8], mm2 + add ebp, 8 + jnc .xloop +.odd: + sub ebp, 6 + jz .noodd +.oddloop: + movzx eax, word [ecx+ebp+6] + mov ebx, 03e0h + mov esi, 001fh + and ebx, eax + and esi, eax + and eax, 07c00h + shl esi, 3 + shl ebx, 6 + shl eax, 9 + add ebx, esi + add eax, ebx + mov ebx, eax + shr eax, 5 + and eax, 070707h + add eax, ebx + mov [edx+ebp*2+12], eax + add ebp, 2 + jnz .oddloop +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + + global _vdasm_pixblt_RGB565_to_XRGB8888_MMX +_vdasm_pixblt_RGB565_to_XRGB8888_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp*2-12] + lea ecx, [ecx+ebp-6] + neg ebp + mov [esp+20+16], ebp + + movq mm5, [r_mask_565] + movq mm6, [g_mask_565] + movq mm7, [b_mask_565] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 6 + jbe .odd + +.xloop: + movq mm0, [ecx+ebp] + movq mm1, mm6 + movq mm2, mm7 + pand mm1, mm0 + pand mm2, mm0 + pand mm0, mm5 + + pmulhw mm1, [x2080w] + psllq mm2, 3 + paddw mm0, mm2 + movq mm2, mm0 + psrlw mm0, 5 + pand mm0, [x07b] + paddw mm0, mm2 + movq mm2, mm0 + punpcklbw mm0, mm1 + punpckhbw mm2, mm1 + + movq [edx+ebp*2], mm0 + movq [edx+ebp*2+8], mm2 + add ebp, 8 + jnc .xloop + +.odd: + sub ebp, 6 + jz .noodd + push edi +.oddloop: + movzx eax, word [ecx+ebp+6] + mov ebx, 0000f800h + and ebx, eax + mov esi, eax + shl ebx, 8 + mov edi, eax + shl eax, 3 + and esi, 000007e0h + and eax, 000000f8h + add ebx, eax + shl esi, 5 + mov eax, ebx + shr ebx, 5 + and edi, 00000600h + shr edi, 1 + and ebx, 00070007h + add esi, edi + add eax, ebx + add eax, esi + mov [edx+ebp*2+12], eax + add ebp, 2 + jnz .oddloop + pop edi +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + + global _vdasm_pixblt_RGB888_to_XRGB8888_MMX +_vdasm_pixblt_RGB888_to_XRGB8888_MMX: + prologue 6 + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ecx,[esp+20+16] + lea eax,[ecx+ecx*2] + lea ebx,[ecx*4] + sub [esp+8+16],ebx + sub [esp+16+16],eax + + mov edx,[esp+24+16] + mov ebx,[esp+20+16] + mov ecx,[esp+16+16] + mov eax,[esp+ 8+16] + + ;ebx horizontal count backup + ;ecx source modulo + ;edx vertical count + ;esi source + ;edi destination + ;ebp horizontal count + +.yloop: + mov ebp,ebx + shr ebp,3 + jz .checkodd +.xloop: + movq mm0,[esi] ;mm0: g2b2r1g1b1r0g0b0 + movq mm1,mm0 ; + + psrlq mm1,24 ;mm1: ------g2b2r1g1b1 + movq mm2,mm0 ; + + movq mm3,[esi+8] ;mm3: b5r4g4b4r3g3b3r2 + punpckldq mm0,mm1 ;mm0: b2r1g1b1b1r0g0b0 [qword 0 ready] + + movq mm4,mm3 ;mm4: b5r4g4b4r3g3b3r2 + psllq mm3,48 ;mm3: b3r2------------ + + movq mm5,mm4 ;mm5: b5r4g4b4r3g3b3r2 + psrlq mm2,16 ;mm2: ----g2b2-------- + + movq mm1,[esi+16] ;mm1: r7g7b7r6g6b6r5g5 + por mm2,mm3 ;mm2: b3r2g2b2-------- + + movq [edi],mm0 ; + psllq mm4,24 ;mm4: b4r3g3b3r2------ + + movq mm3,mm5 ;mm3: b5r4g4b4r3g3b3r2 + psrlq mm5,24 ;mm5: ------b5r4g4b4r3 + + movq mm0,mm1 ;mm0: r7g7b7r6g6b6r5g5 + psllq mm1,40 ;mm1: b6r5g5---------- + + punpckhdq mm2,mm4 ;mm2: b4r3g3b3b3r2g2b2 [qword 1 ready] + por mm1,mm5 ;mm1: b6r5g5b5r4g4b4r3 + + movq mm4,mm0 ;mm4: r7g7b7r6g6b6r5g5 + punpckhdq mm3,mm1 ;mm3: b6r5g5b5b5r4g4b4 [qword 2 ready] + + movq [edi+8],mm2 + psrlq mm0,16 ;mm0: ----r7g7b7r6g6b6 + + movq [edi+16],mm3 + psrlq mm4,40 ;mm4: ----------r7g7b7 + + punpckldq mm0,mm4 ;mm0: --r7g7b7b7r6g6b6 [qword 3 ready] + add esi,24 + + movq [edi+24],mm0 + + add edi,32 + sub ebp,1 + jne .xloop + +.checkodd: + mov ebp,ebx + and ebp,7 + jz .noodd + movd mm7,eax +.oddloop: + mov ax,[esi] + mov [edi],ax + mov al,[esi+2] + mov [edi+2],al + add esi,3 + add edi,4 + sub ebp,1 + jne .oddloop + + movd eax,mm7 +.noodd: + add esi,ecx + add edi,eax + + sub edx,1 + jne .yloop + emms + epilogue + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_bltyuv2rgb_sse2.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_bltyuv2rgb_sse2.asm index 87ff13b5620..7a1e193766e 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_bltyuv2rgb_sse2.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_bltyuv2rgb_sse2.asm @@ -1,161 +1,161 @@ - section .rdata, rdata - - align 16 - -bytemasks dd 000000ffh, 0000ffffh, 00ffffffh - - section .text - -;============================================================================ - - global _vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2 -_vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2: - push edi - push esi - push ebx - - mov eax, [esp+4+12] - mov ebx, [esp+8+12] - mov ecx, [esp+12+12] - mov edx, [esp+16+12] - mov esi, [esp+20+12] - mov edi, [esp+24+12] - - pcmpeqb xmm6, xmm6 - psrlw xmm6, 8 ;xmm6 = 00FF x 8 - - sub esi, 4 - js .postcheck -.xloop: - movdqu xmm2, [edx] ;xmm0 = X3R3G3B3X2R2G2B2X1R1G1B1X0R0G0B0 - add edx, 16 - movdqa xmm5, xmm2 - pand xmm2, xmm6 ;xmm0 = R3 B3 R2 B2 R1 B1 R0 B0 - psrlw xmm5, 8 ;xmm1 = X3 G3 X2 G2 X1 G1 X0 G0 - movdqa xmm0, [edi+0] ;coeff_rb_to_y - movdqa xmm1, [edi+16] ;coeff_rb_to_u - movdqa xmm3, [edi+32] ;coeff_g_to_y - movdqa xmm4, [edi+48] ;coeff_g_to_u - pmaddwd xmm0, xmm2 - pmaddwd xmm1, xmm2 - pmaddwd xmm2, [edi+64] ;coeff_rb_to_v - pmaddwd xmm3, xmm5 - pmaddwd xmm4, xmm5 - pmaddwd xmm5, [edi+80] ;coeff_g_to_v - paddd xmm0, xmm3 - paddd xmm1, xmm4 - paddd xmm2, xmm5 - paddd xmm0, [edi+96] ;bias_y - paddd xmm1, [edi+112] ;bias_c - paddd xmm2, [edi+112] ;bias_c - psrad xmm0, 15 - psrad xmm1, 15 - psrad xmm2, 15 - packssdw xmm0, xmm0 - packssdw xmm1, xmm1 - packssdw xmm2, xmm2 - packuswb xmm0, xmm0 - packuswb xmm1, xmm1 - packuswb xmm2, xmm2 - movd [eax], xmm0 - movd [ebx], xmm1 - movd [ecx], xmm2 - add eax, 4 - add ebx, 4 - add ecx, 4 - sub esi, 4 - jns .xloop -.postcheck: - jmp dword [.finaltable + esi*4 + 16] -.complete: - pop ebx - pop esi - pop edi - ret - -.finaltable: - dd .complete - dd .do1 - dd .do2 - dd .do3 - -.finaltable2: - dd .fin1 - dd .fin2 - dd .fin3 - -.do1: - movd xmm2, [edx] - jmp short .dofinal -.do2: - movq xmm2, [edx] - jmp short .dofinal -.do3: - movq xmm2, [edx] - movd xmm1, [edx] - movlhps xmm2, xmm1 -.dofinal: - movdqa xmm5, xmm2 - pand xmm2, xmm6 ;xmm0 = R3 B3 R2 B2 R1 B1 R0 B0 - psrlw xmm5, 8 ;xmm1 = X3 G3 X2 G2 X1 G1 X0 G0 - movdqa xmm0, [edi+0] ;coeff_rb_to_y - movdqa xmm1, [edi+16] ;coeff_rb_to_u - movdqa xmm3, [edi+32] ;coeff_g_to_y - movdqa xmm4, [edi+48] ;coeff_g_to_u - pmaddwd xmm0, xmm2 - pmaddwd xmm1, xmm2 - pmaddwd xmm2, [edi+64] ;coeff_rb_to_v - pmaddwd xmm3, xmm5 - pmaddwd xmm4, xmm5 - pmaddwd xmm5, [edi+80] ;coeff_g_to_v - paddd xmm0, xmm3 - paddd xmm1, xmm4 - paddd xmm2, xmm5 - paddd xmm0, [edi+96] ;bias_y - paddd xmm1, [edi+112] ;bias_c - paddd xmm2, [edi+112] ;bias_c - psrad xmm0, 15 - psrad xmm1, 15 - psrad xmm2, 15 - packssdw xmm0, xmm0 - packssdw xmm1, xmm1 - packssdw xmm2, xmm2 - packuswb xmm0, xmm0 - packuswb xmm1, xmm1 - movd xmm7, [bytemasks + esi*4 + 12] - packuswb xmm2, xmm2 - - jmp dword [.finaltable2 + esi*4 + 12] - -.fin1: - movd edx, xmm0 - mov [eax], dl - movd edx, xmm1 - mov [ebx], dl - movd edx, xmm2 - mov [ecx], dl - jmp .complete -.fin2: - movd edx, xmm0 - mov [eax], dx - movd edx, xmm1 - mov [ebx], dx - movd edx, xmm2 - mov [ecx], dx - jmp .complete -.fin3: - movd edx, xmm0 - mov [eax], dx - shr edx, 16 - mov [eax+2], dl - movd edx, xmm1 - mov [ebx], dx - shr edx, 16 - mov [ebx+2], dl - movd edx, xmm2 - mov [ecx], dx - shr edx, 16 - mov [ecx+2], dl - jmp .complete - - end + section .rdata, rdata + + align 16 + +bytemasks dd 000000ffh, 0000ffffh, 00ffffffh + + section .text + +;============================================================================ + + global _vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2 +_vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2: + push edi + push esi + push ebx + + mov eax, [esp+4+12] + mov ebx, [esp+8+12] + mov ecx, [esp+12+12] + mov edx, [esp+16+12] + mov esi, [esp+20+12] + mov edi, [esp+24+12] + + pcmpeqb xmm6, xmm6 + psrlw xmm6, 8 ;xmm6 = 00FF x 8 + + sub esi, 4 + js .postcheck +.xloop: + movdqu xmm2, [edx] ;xmm0 = X3R3G3B3X2R2G2B2X1R1G1B1X0R0G0B0 + add edx, 16 + movdqa xmm5, xmm2 + pand xmm2, xmm6 ;xmm0 = R3 B3 R2 B2 R1 B1 R0 B0 + psrlw xmm5, 8 ;xmm1 = X3 G3 X2 G2 X1 G1 X0 G0 + movdqa xmm0, [edi+0] ;coeff_rb_to_y + movdqa xmm1, [edi+16] ;coeff_rb_to_u + movdqa xmm3, [edi+32] ;coeff_g_to_y + movdqa xmm4, [edi+48] ;coeff_g_to_u + pmaddwd xmm0, xmm2 + pmaddwd xmm1, xmm2 + pmaddwd xmm2, [edi+64] ;coeff_rb_to_v + pmaddwd xmm3, xmm5 + pmaddwd xmm4, xmm5 + pmaddwd xmm5, [edi+80] ;coeff_g_to_v + paddd xmm0, xmm3 + paddd xmm1, xmm4 + paddd xmm2, xmm5 + paddd xmm0, [edi+96] ;bias_y + paddd xmm1, [edi+112] ;bias_c + paddd xmm2, [edi+112] ;bias_c + psrad xmm0, 15 + psrad xmm1, 15 + psrad xmm2, 15 + packssdw xmm0, xmm0 + packssdw xmm1, xmm1 + packssdw xmm2, xmm2 + packuswb xmm0, xmm0 + packuswb xmm1, xmm1 + packuswb xmm2, xmm2 + movd [eax], xmm0 + movd [ebx], xmm1 + movd [ecx], xmm2 + add eax, 4 + add ebx, 4 + add ecx, 4 + sub esi, 4 + jns .xloop +.postcheck: + jmp dword [.finaltable + esi*4 + 16] +.complete: + pop ebx + pop esi + pop edi + ret + +.finaltable: + dd .complete + dd .do1 + dd .do2 + dd .do3 + +.finaltable2: + dd .fin1 + dd .fin2 + dd .fin3 + +.do1: + movd xmm2, [edx] + jmp short .dofinal +.do2: + movq xmm2, [edx] + jmp short .dofinal +.do3: + movq xmm2, [edx] + movd xmm1, [edx] + movlhps xmm2, xmm1 +.dofinal: + movdqa xmm5, xmm2 + pand xmm2, xmm6 ;xmm0 = R3 B3 R2 B2 R1 B1 R0 B0 + psrlw xmm5, 8 ;xmm1 = X3 G3 X2 G2 X1 G1 X0 G0 + movdqa xmm0, [edi+0] ;coeff_rb_to_y + movdqa xmm1, [edi+16] ;coeff_rb_to_u + movdqa xmm3, [edi+32] ;coeff_g_to_y + movdqa xmm4, [edi+48] ;coeff_g_to_u + pmaddwd xmm0, xmm2 + pmaddwd xmm1, xmm2 + pmaddwd xmm2, [edi+64] ;coeff_rb_to_v + pmaddwd xmm3, xmm5 + pmaddwd xmm4, xmm5 + pmaddwd xmm5, [edi+80] ;coeff_g_to_v + paddd xmm0, xmm3 + paddd xmm1, xmm4 + paddd xmm2, xmm5 + paddd xmm0, [edi+96] ;bias_y + paddd xmm1, [edi+112] ;bias_c + paddd xmm2, [edi+112] ;bias_c + psrad xmm0, 15 + psrad xmm1, 15 + psrad xmm2, 15 + packssdw xmm0, xmm0 + packssdw xmm1, xmm1 + packssdw xmm2, xmm2 + packuswb xmm0, xmm0 + packuswb xmm1, xmm1 + movd xmm7, [bytemasks + esi*4 + 12] + packuswb xmm2, xmm2 + + jmp dword [.finaltable2 + esi*4 + 12] + +.fin1: + movd edx, xmm0 + mov [eax], dl + movd edx, xmm1 + mov [ebx], dl + movd edx, xmm2 + mov [ecx], dl + jmp .complete +.fin2: + movd edx, xmm0 + mov [eax], dx + movd edx, xmm1 + mov [ebx], dx + movd edx, xmm2 + mov [ecx], dx + jmp .complete +.fin3: + movd edx, xmm0 + mov [eax], dx + shr edx, 16 + mov [eax+2], dl + movd edx, xmm1 + mov [ebx], dx + shr edx, 16 + mov [ebx+2], dl + movd edx, xmm2 + mov [ecx], dx + shr edx, 16 + mov [ecx+2], dl + jmp .complete + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_resample_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_resample_mmx.asm index 912c655abd0..ff504be2e64 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_resample_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_resample_mmx.asm @@ -1,1559 +1,1559 @@ -; VirtualDub - Video processing and capture application -; Graphics support library -; Copyright (C) 1998-2004 Avery Lee -; -; This program 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 2 of the License, or -; (at your option) any later version. -; -; This program 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, write to the Free Software -; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -; - section .rdata, rdata, align=16 - -x0002000200020002 dq 0002000200020002h -x0004000400040004 dq 0004000400040004h -x0008000800080008 dq 0008000800080008h -x0000200000002000 dq 0000200000002000h - - align 16 -MMX_roundval dq 0000200000002000h, 0000200000002000h - - -;************************************************************************** - -x0000FFFF0000FFFF dq 0000FFFF0000FFFFh -x0000010100000101 dq 0000010100000101h -x0100010001000100 dq 0100010001000100h - - section .text - -;-------------------------------------------------------------------------- -;_vdasm_resize_interp_row_run_MMX( -; [esp+ 4] void *dst, -; [esp+ 8] void *src, -; [esp+12] ulong width, -; [esp+16] __int64 xaccum, -; [esp+24] __int64 x_inc); -; - global _vdasm_resize_interp_row_run_MMX -_vdasm_resize_interp_row_run_MMX: - push ebp - push edi - push esi - push ebx - - mov esi, [esp+8+16] - mov edi, [esp+4+16] - mov ebp, [esp+12+16] - - movd mm4, dword [esp+16+16] - pxor mm7, mm7 - movd mm6, dword [esp+24+16] - punpckldq mm4, mm4 - punpckldq mm6, mm6 - - shr esi, 2 - - mov eax, [esp+16+16] - mov ebx, [esp+20+16] - add esi, ebx - mov ebx, [esp+24+16] - mov ecx, [esp+28+16] - - shl ebp,2 - add edi,ebp - neg ebp - -.colloop: - movd mm1, dword [esi*4+4] - movq mm5, mm4 - - movd mm0, dword [esi*4] - punpcklbw mm1, mm7 - - punpcklbw mm0, mm7 - psrld mm5, 24 - - movq mm3, [x0100010001000100] - packssdw mm5, mm5 - - pmullw mm1, mm5 - psubw mm3, mm5 - - pmullw mm0, mm3 - paddd mm4, mm6 - - ;stall - ;stall - - ;stall - ;stall - - paddw mm0, mm1 - - psrlw mm0, 8 - add eax, ebx - - adc esi, ecx - packuswb mm0, mm0 - - movd dword [edi+ebp],mm0 - - add ebp, 4 - jnz .colloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - -;************************************************************************** - -;vdasm_resize_interp_col_run_MMX( -; [esp+ 4] void *dst, -; [esp+ 8] void *src1, -; [esp+12] void *src2, -; [esp+16] ulong width, -; [esp+20] ulong yaccum); - - - global _vdasm_resize_interp_col_run_MMX -_vdasm_resize_interp_col_run_MMX: - push ebp - push edi - push esi - push ebx - - mov esi, [esp+8+16] - mov edx, [esp+12+16] - mov edi, [esp+4+16] - mov ebp, [esp+16+16] - - movd mm4, dword [esp+20+16] - pxor mm7, mm7 - punpcklwd mm4, mm4 - punpckldq mm4, mm4 - psrlw mm4, 8 - pxor mm4, [x0000FFFF0000FFFF] - paddw mm4, [x0000010100000101] - - shl ebp, 2 - add edi, ebp - add esi, ebp - add edx, ebp - neg ebp - -.colloop: - movd mm0, dword [esi+ebp] - movd mm2, dword [edx+ebp] - - punpcklbw mm0, mm7 - punpcklbw mm2, mm7 - - movq mm1, mm0 - punpcklwd mm0, mm2 - punpckhwd mm1, mm2 - - pmaddwd mm0, mm4 - pmaddwd mm1, mm4 - - psrad mm0, 8 - psrad mm1, 8 - - packssdw mm0, mm1 - packuswb mm0, mm0 - - movd dword [edi+ebp],mm0 - - add ebp, 4 - jnz .colloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - -;-------------------------------------------------------------------------- -;vdasm_resize_ccint_row_MMX(dst, src, count, xaccum, xinc, tbl); - - global _vdasm_resize_ccint_row_MMX -_vdasm_resize_ccint_row_MMX: - push ebx - push esi - push edi - push ebp - - mov ebx, [esp+4+16] ;ebx = dest addr - mov ecx, [esp+12+16] ;ecx = count - - mov ebp, [esp+20+16] ;ebp = increment - mov edi, ebp ;edi = increment - shl ebp, 16 ;ebp = fractional increment - mov esi, [esp+16+16] ;esi = 16:16 position - sar edi, 16 ;edi = integer increment - mov [esp+20+16], ebp ;xinc = fractional increment - mov ebp, esi ;ebp = 16:16 position - shr esi, 16 ;esi = integer position - shl ebp, 16 ;ebp = fraction - mov [esp+16+16], ebp ;xaccum = fraction - - mov eax, [esp+8+16] - - shr ebp, 24 ;ebp = fraction (0...255) - mov [esp+8+16], edi - shl ebp, 4 ;ebp = fraction*16 - mov edi, ebp - mov ebp, [esp+4+16] ;ebp = destination - - shr eax, 2 - add eax, esi - shl ecx, 2 ;ecx = count*4 - lea ebp, [ebp+ecx-4] - neg ecx ;ecx = -count*4 - - movq mm6, [x0000200000002000] - pxor mm7, mm7 - - mov edx,[esp+16+16] ;edx = fractional accumulator - mov esi,[esp+20+16] ;esi = fractional increment - - mov ebx,[esp+24+16] ;ebx = coefficient pointer - - movd mm0,dword [eax*4] - movd mm1,dword [eax*4+4] - punpcklbw mm0,mm7 ;mm0 = [a1][r1][g1][b1] - - ;borrow stack pointer - push 0 ;don't crash - push dword [fs:0] - mov dword [fs:0], esp - mov esp, [esp+8+24] ;esp = integer increment - jmp short ccint_loop_MMX_start - - ;EAX source pointer / 4 - ;EBX coefficient pointer - ;ECX count - ;EDX fractional accumulator - ;ESI fractional increment - ;EDI coefficient offset - ;ESP integer increment - ;EBP destination pointer - - align 16 -ccint_loop_MMX: - movd mm0,dword [eax*4] - packuswb mm2,mm2 ;mm0 = [a][r][g][b][a][r][g][b] - - movd mm1,dword [eax*4+4] - punpcklbw mm0,mm7 ;mm0 = [a1][r1][g1][b1] - - movd dword [ebp+ecx],mm2 -ccint_loop_MMX_start: - movq mm4,mm0 ;mm0 = [a1][r1][g1][b1] - - movd mm2,dword [eax*4+8] - punpcklbw mm1,mm7 ;mm1 = [a2][r2][g2][b2] - - movd mm3,dword [eax*4+12] - punpcklbw mm2,mm7 ;mm2 = [a3][r3][g3][b3] - - punpcklbw mm3,mm7 ;mm3 = [a4][r4][g4][b4] - movq mm5,mm2 ;mm2 = [a3][r3][g3][b3] - - add edx,esi ;add fractional increment - punpcklwd mm0,mm1 ;mm0 = [g2][g1][b2][b1] - - pmaddwd mm0,[ebx+edi] - punpcklwd mm2,mm3 ;mm2 = [g4][g3][b4][b3] - - pmaddwd mm2,[ebx+edi+8] - punpckhwd mm4,mm1 ;mm4 = [a2][a1][r2][r1] - - pmaddwd mm4,[ebx+edi] - punpckhwd mm5,mm3 ;mm5 = [a4][a3][b4][b3] - - pmaddwd mm5,[ebx+edi+8] - paddd mm0,mm6 - - adc eax,esp ;add integer increment and fractional bump to offset - mov edi,0ff000000h - - paddd mm2,mm0 ;mm0 = [ g ][ b ] - paddd mm4,mm6 - - psrad mm2,14 - paddd mm4,mm5 ;mm4 = [ a ][ r ] - - and edi,edx - psrad mm4,14 - - shr edi,20 ;edi = fraction (0...255)*16 - add ecx,4 - - packssdw mm2,mm4 ;mm0 = [ a ][ r ][ g ][ b ] - jnc ccint_loop_MMX - - packuswb mm2,mm2 ;mm0 = [a][r][g][b][a][r][g][b] - movd dword [ebp],mm2 - - mov esp, dword [fs:0] - pop dword [fs:0] - pop eax - - pop ebp - pop edi - pop esi - pop ebx - ret - -;-------------------------------------------------------------------------- -;vdasm_resize_ccint_col_MMX(dst, src1, src2, src3, src4, count, tbl); - - global _vdasm_resize_ccint_col_MMX -_vdasm_resize_ccint_col_MMX: - push ebx - push esi - push edi - push ebp - - mov ebp, [esp+4+16] ;ebp = dest addr - mov esi, [esp+24+16] ;esi = count - add esi, esi - add esi, esi - - mov eax, [esp+8+16] ;eax = row 1 - mov ebx, [esp+12+16] ;ebx = row 2 - mov ecx, [esp+16+16] ;ecx = row 3 - mov edx, [esp+20+16] ;edx = row 4 - mov edi, [esp+28+16] ;edi = coefficient ptr - - add eax, esi - add ebx, esi - add ecx, esi - add edx, esi - add ebp, esi - neg esi - - movq mm4,[edi] - movq mm5,[edi+8] - movq mm6,[x0000200000002000] - pxor mm7,mm7 - - movd mm2,dword [eax+esi] - movd mm1,dword [ebx+esi] ;mm1 = pixel1 - punpcklbw mm2,mm7 - jmp short ccint_col_loop_MMX.entry - - align 16 -ccint_col_loop_MMX: - movd mm2,dword [eax+esi] ;mm2 = pixel0 - packuswb mm0,mm0 - - movd mm1,dword [ebx+esi] ;mm1 = pixel1 - pxor mm7,mm7 - - movd dword [ebp+esi-4],mm0 - punpcklbw mm2,mm7 - -ccint_col_loop_MMX.entry: - punpcklbw mm1,mm7 - movq mm0,mm2 - - movd mm3,dword [edx+esi] ;mm3 = pixel3 - punpcklwd mm0,mm1 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm0,mm4 - punpckhwd mm2,mm1 ;mm2 = [a1][a0][r1][r0] - - movd mm1,dword [ecx+esi] ;mm1 = pixel2 - punpcklbw mm3,mm7 - - pmaddwd mm2,mm4 - punpcklbw mm1,mm7 - - movq mm7,mm1 - punpcklwd mm1,mm3 ;mm1 = [g3][g2][b3][b2] - - punpckhwd mm7,mm3 ;mm7 = [a3][a2][r3][r2] - pmaddwd mm1,mm5 - - pmaddwd mm7,mm5 - paddd mm0,mm6 - - paddd mm2,mm6 - paddd mm0,mm1 - - paddd mm2,mm7 - psrad mm0,14 - - psrad mm2,14 - add esi,4 - - packssdw mm0,mm2 - jne ccint_col_loop_MMX - - packuswb mm0,mm0 - movd dword [ebp-4],mm0 - - pop ebp - pop edi - pop esi - pop ebx - ret - -;-------------------------------------------------------------------------- -;vdasm_resize_ccint_col_SSE2(dst, src1, src2, src3, src4, count, tbl); - - global _vdasm_resize_ccint_col_SSE2 -_vdasm_resize_ccint_col_SSE2: - push ebx - push esi - push edi - push ebp - - mov ebp,[esp + 4 + 16] ;ebp = dest addr - mov esi,[esp + 24 + 16] ;esi = count - add esi,esi - add esi,esi - - mov eax,[esp + 8 + 16] ;eax = row 1 - mov ebx,[esp + 12 + 16] ;ebx = row 2 - mov ecx,[esp + 16 + 16] ;ecx = row 3 - mov edx,[esp + 20 + 16] ;edx = row 4 - mov edi,[esp + 28 + 16] ;edi = coefficient ptr - - neg esi - - add esi,4 - jz ccint_col_SSE2_odd - - movq xmm4,qword [edi] - movq xmm5,qword [edi+8] - punpcklqdq xmm4,xmm4 - punpcklqdq xmm5,xmm5 - movq xmm6,[x0000200000002000] - punpcklqdq xmm6,xmm6 - pxor xmm7,xmm7 - -; jmp short ccint_col_loop_SSE2.entry - -; align 16 -ccint_col_loop_SSE2: - movq xmm0, qword [eax] - add eax, 8 - movq xmm1, qword [ebx] - add ebx, 8 - movq xmm2, qword [ecx] - add ecx, 8 - movq xmm3, qword [edx] - add edx, 8 - punpcklbw xmm0,xmm1 - punpcklbw xmm2,xmm3 - movdqa xmm1,xmm0 - movdqa xmm3,xmm2 - punpcklbw xmm0,xmm7 - punpckhbw xmm1,xmm7 - punpcklbw xmm2,xmm7 - punpckhbw xmm3,xmm7 - pmaddwd xmm0,xmm4 - pmaddwd xmm1,xmm4 - pmaddwd xmm2,xmm5 - pmaddwd xmm3,xmm5 - paddd xmm0,xmm6 - paddd xmm1,xmm6 - paddd xmm0,xmm2 - paddd xmm1,xmm3 - psrad xmm0,14 - psrad xmm1,14 - packssdw xmm0,xmm1 - packuswb xmm0,xmm0 - movdq2q mm0,xmm0 - movntq [ebp],mm0 - add ebp,8 - add esi,8 - jnc ccint_col_loop_SSE2 - jnz ccint_col_SSE2_noodd -ccint_col_SSE2_odd: - movd mm0, dword [eax] - pxor mm7,mm7 - movd mm1, dword [ebx] - movdq2q mm4,xmm4 - movd mm2, dword [ecx] - movdq2q mm5,xmm5 - movd mm3, dword [edx] - movdq2q mm6,xmm6 - punpcklbw mm0,mm1 - punpcklbw mm2,mm3 - movq mm1,mm0 - movq mm3,mm2 - punpcklbw mm0,mm7 - punpckhbw mm1,mm7 - punpcklbw mm2,mm7 - punpckhbw mm3,mm7 - pmaddwd mm0,mm4 - pmaddwd mm1,mm4 - pmaddwd mm2,mm5 - pmaddwd mm3,mm5 - paddd mm0,mm6 - paddd mm2,mm6 - paddd mm0,mm2 - paddd mm1,mm3 - psrad mm0,14 - psrad mm1,14 - packssdw mm0,mm1 - packuswb mm0,mm0 - movd eax,mm0 - movnti [ebp],eax - -ccint_col_SSE2_noodd: - pop ebp - pop edi - pop esi - pop ebx - ret - - - -;------------------------------------------------------------------------- -; -; long resize_table_row_MMX(Pixel *out, Pixel *in, int *filter, int filter_width, PixDim w, long accum, long frac); - - .code - - global _vdasm_resize_table_row_MMX -_vdasm_resize_table_row_MMX: - push ebp - push esi - push edi - push ebx - - cmp dword [esp+16+16], 4 - jz .accel_4coeff - cmp dword [esp+16+16], 6 - jz .accel_6coeff - cmp dword [esp+16+16], 8 - jz .accel_8coeff - - mov eax,[esp + 24 + 16] - mov ebp,[esp + 20 + 16] - mov ebx,[esp + 8 + 16] - mov edi,[esp + 4 + 16] - - mov esi,eax - mov edx,eax - - pxor mm5,mm5 - - mov ecx,[esp + 16 + 16] - shr ecx,1 - mov [esp+16+16],ecx - test ecx,1 - jnz .pixelloop_odd_pairs - -.pixelloop_even_pairs: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - mov ecx,[esp + 16 + 16] - shr edx,5 - add esi,ebx - imul edx,ecx - add eax,[esp + 28 + 16] - add edx,[esp + 12 + 16] - - movq mm6,[MMX_roundval] - pxor mm3,mm3 - movq mm7,mm6 - pxor mm2,mm2 - -.coeffloop_unaligned_even_pairs: - movd mm0,dword [esi+0] - paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) - - punpcklbw mm0,[esi+4] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) - - movd mm2,dword [esi+8] - movq mm1,mm0 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm7,mm0 ;accumulate alpha/red (pixels 0/1) - - paddd mm6,mm1 ;accumulate green/blue (pixels 0/1) - add edx,16 - - add esi,16 - sub ecx,2 - - jne .coeffloop_unaligned_even_pairs - - paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) - - psrad mm7,14 - psrad mm6,14 - - packssdw mm6,mm7 - add edi,4 - - packuswb mm6,mm6 - sub ebp,1 - - mov esi,eax - mov edx,eax - - movd dword [edi-4],mm6 - jne .pixelloop_even_pairs - - pop ebx - pop edi - pop esi - pop ebp - - ret - -;---------------------------------------------------------------- - -.pixelloop_odd_pairs: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - mov ecx,[esp + 16 + 16] - shr edx,5 - add esi,ebx - imul edx,ecx - add eax,[esp + 28 + 16] - sub ecx,1 - add edx,[esp + 12 + 16] - - movq mm6,[MMX_roundval] - pxor mm3,mm3 - pxor mm2,mm2 - movq mm7,mm6 - -.coeffloop_unaligned_odd_pairs: - movd mm0,dword [esi+0] - paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) - - punpcklbw mm0,[esi+4] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) - - movd mm2,dword [esi+8] - movq mm1,mm0 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm7,mm0 ;accumulate alpha/red (pixels 0/1) - - paddd mm6,mm1 ;accumulate green/blue (pixels 0/1) - add edx,16 - - add esi,16 - sub ecx,2 - - jne .coeffloop_unaligned_odd_pairs - - paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) - - ;finish up odd pair - - movd mm0,dword [esi] ;mm0 = [x1][r1][g1][b1] - punpcklbw mm0,[esi+4] ;mm2 = [x0][x1][r0][r1][g0][g1][b0][b1] - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g0][g1][b0][b1] - punpckhbw mm1,mm5 ;mm1 = [x0][x1][r0][r1] - - pmaddwd mm0,[edx] - pmaddwd mm1,[edx] - - paddd mm6,mm0 - paddd mm7,mm1 - - ;combine into pixel - - psrad mm6,14 - - psrad mm7,14 - - packssdw mm6,mm7 - add edi,4 - - packuswb mm6,mm6 - sub ebp,1 - - mov esi,eax - mov edx,eax - - movd dword [edi-4],mm6 - jne .pixelloop_odd_pairs - - pop ebx - pop edi - pop esi - pop ebp - - ret - -;---------------------------------------------------------------- - -.accel_4coeff: - mov eax,[esp + 24 + 16] - mov ebp,[esp + 20 + 16] - add ebp,ebp - add ebp,ebp - mov ebx,[esp + 8 + 16] - mov edi,[esp + 4 + 16] - add edi,ebp - neg ebp - - mov esi,eax - mov edx,eax - - movq mm4,[MMX_roundval] - pxor mm5,mm5 - - mov ecx,[esp+12+16] - -.pixelloop_4coeff: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - shr edx,4 - add esi,ebx - add eax,[esp+28+16] - add edx,ecx - - movd mm0,dword [esi+0] - movd mm2,dword [esi+8] - punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) - - paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) - - psrad mm0,14 - psrad mm1,14 - - packssdw mm1,mm0 - mov esi,eax - - packuswb mm1,mm1 - mov edx,eax - - movd dword [edi+ebp],mm1 - add ebp,4 - jne .pixelloop_4coeff - - pop ebx - pop edi - pop esi - pop ebp - - ret - - -;---------------------------------------------------------------- - -.accel_6coeff: - mov eax,[esp + 24 + 16] - mov ebp,[esp + 20 + 16] - add ebp,ebp - add ebp,ebp - mov ebx,[esp + 8 + 16] - mov edi,[esp + 4 + 16] - add edi,ebp - neg ebp - - mov esi,eax - mov edx,eax - - movq mm4,[MMX_roundval] - pxor mm5,mm5 - - mov ecx,[esp+12+16] - -.pixelloop_6coeff: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - shr edx,5 - lea edx,[edx+edx*2] - add esi,ebx - add eax,[esp+28+16] - add edx,ecx - - movd mm0,dword [esi+0] - movd mm2,dword [esi+8] - punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) - - paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) - - movd mm6,dword [esi+16] - - punpcklbw mm6,[esi+20] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - movq mm7,mm6 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm6,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - - pmaddwd mm6,[edx+16] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm7,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm7,[edx+16] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - paddd mm0,mm6 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm7 ;accumulate green/blue (pixels 0/1) - - - psrad mm0,14 - psrad mm1,14 - - packssdw mm1,mm0 - mov esi,eax - - packuswb mm1,mm1 - mov edx,eax - - movd dword [edi+ebp],mm1 - add ebp,4 - jne .pixelloop_6coeff - - pop ebx - pop edi - pop esi - pop ebp - - ret - -;---------------------------------------------------------------- - -.accel_8coeff: - mov eax,[esp + 24 + 16] - mov ebp,[esp + 20 + 16] - add ebp,ebp - add ebp,ebp - mov ebx,[esp + 8 + 16] - mov edi,[esp + 4 + 16] - add edi,ebp - neg ebp - - mov esi,eax - mov edx,eax - - movq mm4,[MMX_roundval] - pxor mm5,mm5 - - mov ecx,[esp+12+16] - -.pixelloop_8coeff: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - shr edx,3 - add esi,ebx - add eax,[esp+28+16] - add edx,ecx - - movd mm0,dword [esi+0] - movd mm2,dword [esi+8] - punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) - - paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) - - - movd mm6,dword [esi+16] - - punpcklbw mm6,[esi+20] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - movd mm2,dword [esi+24] - - punpcklbw mm2,[esi+28] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - movq mm7,mm6 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm6,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - - pmaddwd mm6,[edx+16] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm7,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm7,[edx+16] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+24] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+24] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm0,mm6 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm7 ;accumulate green/blue (pixels 0/1) - paddd mm0,mm2 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm3 ;accumulate green/blue (pixels 0/1) - - - psrad mm0,14 - psrad mm1,14 - - packssdw mm1,mm0 - mov esi,eax - - packuswb mm1,mm1 - mov edx,eax - - movd dword [edi+ebp],mm1 - add ebp,4 - jne .pixelloop_8coeff - - pop ebx - pop edi - pop esi - pop ebp - - ret - - - - - - - -;------------------------------------------------------------------------- -; -; long resize_table_col_MMX(Pixel *out, Pixel **in_table, int *filter, int filter_width, PixDim w, long frac); - - global _vdasm_resize_table_col_MMX -_vdasm_resize_table_col_MMX: - push ebp - push esi - push edi - push ebx - - mov edx,[esp + 12 + 16] - mov eax,[esp + 24 + 16] - shl eax,2 - imul eax,[esp + 16 + 16] - add edx,eax - mov [esp + 12 + 16], edx ;[esp+12+28] = filter pointer - - mov ebp,[esp + 20 + 16] ;ebp = pixel counter - mov edi,[esp + 4 + 16] ;edi = destination pointer - - pxor mm5,mm5 - - cmp dword [esp+16+16], 4 - jz .accel_4coeff - cmp dword [esp+16+16], 6 - jz .accel_6coeff - - mov ecx,[esp + 16 + 16] - shr ecx,1 - mov [esp + 16 + 16],ecx ;ecx = filter pair count - - xor ebx,ebx ;ebx = source offset - - mov ecx,[esp + 16 + 16] ;ecx = filter width counter -.pixelloop: - mov eax,[esp + 8 + 16] ;esi = row pointer table - movq mm6,[MMX_roundval] - movq mm7,mm6 - pxor mm0,mm0 - pxor mm1,mm1 -.coeffloop: - mov esi,[eax] - paddd mm6,mm0 - - movd mm0,dword [esi+ebx] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - paddd mm7,mm1 - - mov esi,[eax+4] - add eax,8 - - movd mm1,dword [esi+ebx] ;mm1 = [0][0][0][0][x1][r1][g1][b1] - punpcklbw mm0,mm1 ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm0,[edx] - punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] - - pmaddwd mm1,[edx] - add edx,8 - - sub ecx,1 - jne .coeffloop - - paddd mm6,mm0 - paddd mm7,mm1 - - psrad mm6,14 - psrad mm7,14 - add edi,4 - packssdw mm6,mm7 - add ebx,4 - packuswb mm6,mm6 - sub ebp,1 - - mov ecx,[esp + 16 + 16] ;ecx = filter width counter - mov edx,[esp + 12 + 16] ;edx = filter bank pointer - - movd dword [edi-4],mm6 - jne .pixelloop - -.xit: - pop ebx - pop edi - pop esi - pop ebp - ret - - - -.accel_4coeff: - movq mm2,[edx] - movq mm3,[edx+8] - - mov esi,[esp+8+16] ;esi = row pointer table - mov eax,[esi] - add ebp,ebp - mov ebx,[esi+4] - add ebp,ebp - mov ecx,[esi+8] - mov esi,[esi+12] - add eax,ebp - add ebx,ebp - add ecx,ebp - add esi,ebp - add edi,ebp - neg ebp - - ;EAX source 0 - ;EBX source 1 - ;ECX source 2 - ;ESI source 3 - ;EDI destination - ;EBP counter - - movq mm4,[MMX_roundval] - -.pixelloop4: - movd mm6,dword [eax+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - - punpcklbw mm6,[ebx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - - movq mm7,mm6 - punpcklbw mm6,mm5 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm6,mm2 - punpckhbw mm7,mm5 ;mm1 = [x1][x0][r1][r0] - - movd mm0,dword [ecx+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - pmaddwd mm7,mm2 - - punpcklbw mm0,[esi+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - paddd mm6,mm4 - - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm0,mm3 - punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] - - pmaddwd mm1,mm3 - paddd mm7,mm4 - - paddd mm6,mm0 - paddd mm7,mm1 - - psrad mm6,14 - psrad mm7,14 - packssdw mm6,mm7 - packuswb mm6,mm6 - - movd dword [edi+ebp],mm6 - - add ebp,4 - jne .pixelloop4 - jmp .xit - -.accel_6coeff: - movq mm2,[edx] - movq mm3,[edx+8] - movq mm4,[edx+16] - - push 0 - push dword [fs:0] - mov dword [fs:0],esp - - mov esp,[esp+8+24] ;esp = row pointer table - mov eax,[esp] - add ebp,ebp - mov ebx,[esp+4] - add ebp,ebp - mov ecx,[esp+8] - mov edx,[esp+12] - mov esi,[esp+16] - mov esp,[esp+20] - add eax,ebp - add ebx,ebp - add ecx,ebp - add edx,ebp - add esi,ebp - add edi,ebp - add esp,ebp - neg ebp - - ;EAX source 0 - ;EBX source 1 - ;ECX source 2 - ;EDX source 3 - ;ESI source 4 - ;EDI destination - ;ESP source 5 - ;EBP counter - -.pixelloop6: - movd mm6,dword [eax+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - - punpcklbw mm6,[ebx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - - movq mm7,mm6 - punpcklbw mm6,mm5 ;mm0 = [g1][g0][b1][b0] - - movd mm0,dword [ecx+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - punpckhbw mm7,mm5 ;mm1 = [x1][x0][r1][r0] - - punpcklbw mm0,[edx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - pmaddwd mm6,mm2 - - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm7,mm2 - punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] - - paddd mm6,[MMX_roundval] - pmaddwd mm0,mm3 - - paddd mm7,[MMX_roundval] - pmaddwd mm1,mm3 - - paddd mm6,mm0 - - movd mm0,dword [esi+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - paddd mm7,mm1 - - punpcklbw mm0,[esp+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] - punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] - pmaddwd mm0,mm4 - pmaddwd mm1,mm4 - paddd mm6,mm0 - paddd mm7,mm1 - - psrad mm6,14 - psrad mm7,14 - packssdw mm6,mm7 - packuswb mm6,mm6 - - movd dword [edi+ebp],mm6 - - add ebp,4 - jne .pixelloop6 - - mov esp, dword [fs:0] - pop dword [fs:0] - pop eax - - jmp .xit - - - global _vdasm_resize_table_col_SSE2 -_vdasm_resize_table_col_SSE2: - push ebp - push esi - push edi - push ebx - - mov edx,[esp+12+16] - mov eax,[esp+24+16] - shl eax,2 - imul eax,[esp+16+16] - add edx,eax - mov [esp+12+16], edx ;[esp+12+16] = filter pointer - - mov ebp,[esp+20+16] ;ebp = pixel counter - mov edi,[esp+4+16] ;edi = destination pointer - - pxor xmm7, xmm7 - movdqa xmm6, [MMX_roundval] - - cmp dword [esp+16+16], 4 - jz .accel_4coeff - cmp dword [esp+16+16], 6 - jz .accel_6coeff - - mov ecx,[esp+16+16] - shr ecx,1 - mov [esp+16+16],ecx ;ecx = filter pair count - - xor ebx,ebx ;ebx = source offset - - mov ecx,[esp+16+16] ;ecx = filter width counter -.pixelloop: - mov eax, [esp+8+16] ;esi = row pointer table - movdqa xmm4, xmm6 -.coeffloop: - mov esi,[eax] - - movd xmm0, dword [esi+ebx] - - mov esi,[eax+4] - add eax,8 - - movd xmm1, dword [esi+ebx] - punpcklbw xmm0, xmm1 - - punpcklbw xmm0, xmm7 - - movq xmm2, qword [edx] - pshufd xmm2, xmm2, 01000100b - - pmaddwd xmm0, xmm2 - - paddd xmm4, xmm0 - - add edx,8 - - sub ecx,1 - jne .coeffloop - - psrad xmm4,14 - add edi,4 - packssdw xmm4,xmm4 - add ebx,4 - packuswb xmm4,xmm4 - sub ebp,1 - - mov ecx,[esp+16+16] ;ecx = filter width counter - mov edx,[esp+12+16] ;edx = filter bank pointer - - movd dword [edi-4],xmm4 - jne .pixelloop - -.xit: - pop ebx - pop edi - pop esi - pop ebp - ret - -.accel_4coeff: - shl ebp, 2 - mov eax, [esp+8+16] ;eax = row pointer table - mov esi, [eax+12] - mov ecx, [eax+8] - mov ebx, [eax+4] - mov eax, [eax] - lea edi, [edi+ebp-4] - neg ebp - - ;registers: - ; - ;EAX source 0 - ;EBX source 1 - ;ECX source 2 - ;ESI source 3 - ;EDI destination - ;EBP counter - ; - movq xmm4, qword [edx] ;xmm4 = coeff 0/1 - movq xmm5, qword [edx+8] ;xmm5 = coeff 2/3 - punpcklqdq xmm4, xmm4 - punpcklqdq xmm5, xmm5 - - add ebp, 4 - jz .oddpixel_4coeff - -.pixelloop_4coeff_dualpel: - movq xmm0, qword [eax] - movq xmm1, qword [ebx] - movq xmm2, qword [ecx] - movq xmm3, qword [esi] - add eax,8 - add ebx,8 - add ecx,8 - add esi,8 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - punpcklbw xmm0, xmm7 - punpckhbw xmm1, xmm7 - punpcklbw xmm2, xmm7 - punpckhbw xmm3, xmm7 - pmaddwd xmm0, xmm4 - pmaddwd xmm1, xmm4 - pmaddwd xmm2, xmm5 - pmaddwd xmm3, xmm5 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - paddd xmm0, xmm6 - paddd xmm1, xmm6 - psrad xmm0, 14 - psrad xmm1, 14 - packssdw xmm0, xmm1 - packuswb xmm0, xmm0 - movq qword [edi+ebp],xmm0 - add ebp, 8 - jae .pixelloop_4coeff_dualpel - jnz .xit - -.oddpixel_4coeff: - movd xmm0, dword [eax] - movd xmm1, dword [ebx] - movd xmm2, dword [ecx] - movd xmm3, dword [esi] - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm7 - punpcklbw xmm2, xmm7 - pmaddwd xmm0, xmm4 - pmaddwd xmm2, xmm5 - paddd xmm0, xmm2 - paddd xmm0, xmm6 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd dword [edi],xmm0 - jmp .xit - - -.accel_6coeff: - movq xmm4, qword [edx] ;xmm4 = coeff 0/1 - movq xmm5, qword [edx+8] ;xmm5 = coeff 2/3 - movq xmm6, qword [edx+16] ;xmm5 = coeff 4/5 - punpcklqdq xmm4, xmm4 - punpcklqdq xmm5, xmm5 - punpcklqdq xmm6, xmm6 - - push 0 - push dword [fs:0] - mov dword [fs:0],esp - - shl ebp, 2 - mov eax, [esp+8+24] ;eax = row pointer table - mov esp, [eax+20] - mov esi, [eax+16] - mov edx, [eax+12] - mov ecx, [eax+8] - mov ebx, [eax+4] - mov eax, [eax] - lea edi, [edi+ebp-4] - neg ebp - - ;registers: - ; - ;EAX source 0 - ;EBX source 1 - ;ECX source 2 - ;EDX source 3 - ;ESI source 4 - ;EDI destination - ;ESP source 5 - ;EBP counter - ; - - add ebp, 4 - jz .oddpixel_6coeff - -.pixelloop_6coeff_dualpel: - movq xmm0, qword [eax] - movq xmm1, qword [ebx] - movq xmm2, qword [ecx] - movq xmm3, qword [edx] - add eax,8 - add ebx,8 - add ecx,8 - add edx,8 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - punpcklbw xmm0, xmm7 - punpckhbw xmm1, xmm7 - punpcklbw xmm2, xmm7 - punpckhbw xmm3, xmm7 - pmaddwd xmm0, xmm4 - pmaddwd xmm1, xmm4 - pmaddwd xmm2, xmm5 - pmaddwd xmm3, xmm5 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - - movq xmm2, qword [esi] - movq xmm3, qword [esp] - add esi, 8 - add esp, 8 - punpcklbw xmm2, xmm3 - movdqa xmm3, xmm2 - punpcklbw xmm2, xmm7 - punpckhbw xmm3, xmm7 - pmaddwd xmm2, xmm6 - pmaddwd xmm3, xmm6 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - paddd xmm0, [MMX_roundval] - paddd xmm1, [MMX_roundval] - psrad xmm0, 14 - psrad xmm1, 14 - packssdw xmm0, xmm1 - packuswb xmm0, xmm0 - movq qword [edi+ebp],xmm0 - add ebp, 8 - jae .pixelloop_6coeff_dualpel - jnz .xit_6coeff - -.oddpixel_6coeff: - movd xmm0, dword [eax] - movd xmm1, dword [ebx] - movd xmm2, dword [ecx] - movd xmm3, dword [edx] - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - movd xmm1, dword [esi] - movd xmm3, dword [esp] - punpcklbw xmm0, xmm7 - punpcklbw xmm2, xmm7 - pmaddwd xmm0, xmm4 - punpcklbw xmm1, xmm3 - pmaddwd xmm2, xmm5 - punpcklbw xmm1, xmm7 - pmaddwd xmm1, xmm6 - paddd xmm0, xmm2 - paddd xmm1, [MMX_roundval] - paddd xmm0, xmm1 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd dword [edi],xmm0 - -.xit_6coeff: - mov esp, dword [fs:0] - pop dword [fs:0] - pop eax - jmp .xit - - - end +; VirtualDub - Video processing and capture application +; Graphics support library +; Copyright (C) 1998-2004 Avery Lee +; +; This program 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 2 of the License, or +; (at your option) any later version. +; +; This program 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, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +; + section .rdata, rdata, align=16 + +x0002000200020002 dq 0002000200020002h +x0004000400040004 dq 0004000400040004h +x0008000800080008 dq 0008000800080008h +x0000200000002000 dq 0000200000002000h + + align 16 +MMX_roundval dq 0000200000002000h, 0000200000002000h + + +;************************************************************************** + +x0000FFFF0000FFFF dq 0000FFFF0000FFFFh +x0000010100000101 dq 0000010100000101h +x0100010001000100 dq 0100010001000100h + + section .text + +;-------------------------------------------------------------------------- +;_vdasm_resize_interp_row_run_MMX( +; [esp+ 4] void *dst, +; [esp+ 8] void *src, +; [esp+12] ulong width, +; [esp+16] __int64 xaccum, +; [esp+24] __int64 x_inc); +; + global _vdasm_resize_interp_row_run_MMX +_vdasm_resize_interp_row_run_MMX: + push ebp + push edi + push esi + push ebx + + mov esi, [esp+8+16] + mov edi, [esp+4+16] + mov ebp, [esp+12+16] + + movd mm4, dword [esp+16+16] + pxor mm7, mm7 + movd mm6, dword [esp+24+16] + punpckldq mm4, mm4 + punpckldq mm6, mm6 + + shr esi, 2 + + mov eax, [esp+16+16] + mov ebx, [esp+20+16] + add esi, ebx + mov ebx, [esp+24+16] + mov ecx, [esp+28+16] + + shl ebp,2 + add edi,ebp + neg ebp + +.colloop: + movd mm1, dword [esi*4+4] + movq mm5, mm4 + + movd mm0, dword [esi*4] + punpcklbw mm1, mm7 + + punpcklbw mm0, mm7 + psrld mm5, 24 + + movq mm3, [x0100010001000100] + packssdw mm5, mm5 + + pmullw mm1, mm5 + psubw mm3, mm5 + + pmullw mm0, mm3 + paddd mm4, mm6 + + ;stall + ;stall + + ;stall + ;stall + + paddw mm0, mm1 + + psrlw mm0, 8 + add eax, ebx + + adc esi, ecx + packuswb mm0, mm0 + + movd dword [edi+ebp],mm0 + + add ebp, 4 + jnz .colloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + +;************************************************************************** + +;vdasm_resize_interp_col_run_MMX( +; [esp+ 4] void *dst, +; [esp+ 8] void *src1, +; [esp+12] void *src2, +; [esp+16] ulong width, +; [esp+20] ulong yaccum); + + + global _vdasm_resize_interp_col_run_MMX +_vdasm_resize_interp_col_run_MMX: + push ebp + push edi + push esi + push ebx + + mov esi, [esp+8+16] + mov edx, [esp+12+16] + mov edi, [esp+4+16] + mov ebp, [esp+16+16] + + movd mm4, dword [esp+20+16] + pxor mm7, mm7 + punpcklwd mm4, mm4 + punpckldq mm4, mm4 + psrlw mm4, 8 + pxor mm4, [x0000FFFF0000FFFF] + paddw mm4, [x0000010100000101] + + shl ebp, 2 + add edi, ebp + add esi, ebp + add edx, ebp + neg ebp + +.colloop: + movd mm0, dword [esi+ebp] + movd mm2, dword [edx+ebp] + + punpcklbw mm0, mm7 + punpcklbw mm2, mm7 + + movq mm1, mm0 + punpcklwd mm0, mm2 + punpckhwd mm1, mm2 + + pmaddwd mm0, mm4 + pmaddwd mm1, mm4 + + psrad mm0, 8 + psrad mm1, 8 + + packssdw mm0, mm1 + packuswb mm0, mm0 + + movd dword [edi+ebp],mm0 + + add ebp, 4 + jnz .colloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + +;-------------------------------------------------------------------------- +;vdasm_resize_ccint_row_MMX(dst, src, count, xaccum, xinc, tbl); + + global _vdasm_resize_ccint_row_MMX +_vdasm_resize_ccint_row_MMX: + push ebx + push esi + push edi + push ebp + + mov ebx, [esp+4+16] ;ebx = dest addr + mov ecx, [esp+12+16] ;ecx = count + + mov ebp, [esp+20+16] ;ebp = increment + mov edi, ebp ;edi = increment + shl ebp, 16 ;ebp = fractional increment + mov esi, [esp+16+16] ;esi = 16:16 position + sar edi, 16 ;edi = integer increment + mov [esp+20+16], ebp ;xinc = fractional increment + mov ebp, esi ;ebp = 16:16 position + shr esi, 16 ;esi = integer position + shl ebp, 16 ;ebp = fraction + mov [esp+16+16], ebp ;xaccum = fraction + + mov eax, [esp+8+16] + + shr ebp, 24 ;ebp = fraction (0...255) + mov [esp+8+16], edi + shl ebp, 4 ;ebp = fraction*16 + mov edi, ebp + mov ebp, [esp+4+16] ;ebp = destination + + shr eax, 2 + add eax, esi + shl ecx, 2 ;ecx = count*4 + lea ebp, [ebp+ecx-4] + neg ecx ;ecx = -count*4 + + movq mm6, [x0000200000002000] + pxor mm7, mm7 + + mov edx,[esp+16+16] ;edx = fractional accumulator + mov esi,[esp+20+16] ;esi = fractional increment + + mov ebx,[esp+24+16] ;ebx = coefficient pointer + + movd mm0,dword [eax*4] + movd mm1,dword [eax*4+4] + punpcklbw mm0,mm7 ;mm0 = [a1][r1][g1][b1] + + ;borrow stack pointer + push 0 ;don't crash + push dword [fs:0] + mov dword [fs:0], esp + mov esp, [esp+8+24] ;esp = integer increment + jmp short ccint_loop_MMX_start + + ;EAX source pointer / 4 + ;EBX coefficient pointer + ;ECX count + ;EDX fractional accumulator + ;ESI fractional increment + ;EDI coefficient offset + ;ESP integer increment + ;EBP destination pointer + + align 16 +ccint_loop_MMX: + movd mm0,dword [eax*4] + packuswb mm2,mm2 ;mm0 = [a][r][g][b][a][r][g][b] + + movd mm1,dword [eax*4+4] + punpcklbw mm0,mm7 ;mm0 = [a1][r1][g1][b1] + + movd dword [ebp+ecx],mm2 +ccint_loop_MMX_start: + movq mm4,mm0 ;mm0 = [a1][r1][g1][b1] + + movd mm2,dword [eax*4+8] + punpcklbw mm1,mm7 ;mm1 = [a2][r2][g2][b2] + + movd mm3,dword [eax*4+12] + punpcklbw mm2,mm7 ;mm2 = [a3][r3][g3][b3] + + punpcklbw mm3,mm7 ;mm3 = [a4][r4][g4][b4] + movq mm5,mm2 ;mm2 = [a3][r3][g3][b3] + + add edx,esi ;add fractional increment + punpcklwd mm0,mm1 ;mm0 = [g2][g1][b2][b1] + + pmaddwd mm0,[ebx+edi] + punpcklwd mm2,mm3 ;mm2 = [g4][g3][b4][b3] + + pmaddwd mm2,[ebx+edi+8] + punpckhwd mm4,mm1 ;mm4 = [a2][a1][r2][r1] + + pmaddwd mm4,[ebx+edi] + punpckhwd mm5,mm3 ;mm5 = [a4][a3][b4][b3] + + pmaddwd mm5,[ebx+edi+8] + paddd mm0,mm6 + + adc eax,esp ;add integer increment and fractional bump to offset + mov edi,0ff000000h + + paddd mm2,mm0 ;mm0 = [ g ][ b ] + paddd mm4,mm6 + + psrad mm2,14 + paddd mm4,mm5 ;mm4 = [ a ][ r ] + + and edi,edx + psrad mm4,14 + + shr edi,20 ;edi = fraction (0...255)*16 + add ecx,4 + + packssdw mm2,mm4 ;mm0 = [ a ][ r ][ g ][ b ] + jnc ccint_loop_MMX + + packuswb mm2,mm2 ;mm0 = [a][r][g][b][a][r][g][b] + movd dword [ebp],mm2 + + mov esp, dword [fs:0] + pop dword [fs:0] + pop eax + + pop ebp + pop edi + pop esi + pop ebx + ret + +;-------------------------------------------------------------------------- +;vdasm_resize_ccint_col_MMX(dst, src1, src2, src3, src4, count, tbl); + + global _vdasm_resize_ccint_col_MMX +_vdasm_resize_ccint_col_MMX: + push ebx + push esi + push edi + push ebp + + mov ebp, [esp+4+16] ;ebp = dest addr + mov esi, [esp+24+16] ;esi = count + add esi, esi + add esi, esi + + mov eax, [esp+8+16] ;eax = row 1 + mov ebx, [esp+12+16] ;ebx = row 2 + mov ecx, [esp+16+16] ;ecx = row 3 + mov edx, [esp+20+16] ;edx = row 4 + mov edi, [esp+28+16] ;edi = coefficient ptr + + add eax, esi + add ebx, esi + add ecx, esi + add edx, esi + add ebp, esi + neg esi + + movq mm4,[edi] + movq mm5,[edi+8] + movq mm6,[x0000200000002000] + pxor mm7,mm7 + + movd mm2,dword [eax+esi] + movd mm1,dword [ebx+esi] ;mm1 = pixel1 + punpcklbw mm2,mm7 + jmp short ccint_col_loop_MMX.entry + + align 16 +ccint_col_loop_MMX: + movd mm2,dword [eax+esi] ;mm2 = pixel0 + packuswb mm0,mm0 + + movd mm1,dword [ebx+esi] ;mm1 = pixel1 + pxor mm7,mm7 + + movd dword [ebp+esi-4],mm0 + punpcklbw mm2,mm7 + +ccint_col_loop_MMX.entry: + punpcklbw mm1,mm7 + movq mm0,mm2 + + movd mm3,dword [edx+esi] ;mm3 = pixel3 + punpcklwd mm0,mm1 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm0,mm4 + punpckhwd mm2,mm1 ;mm2 = [a1][a0][r1][r0] + + movd mm1,dword [ecx+esi] ;mm1 = pixel2 + punpcklbw mm3,mm7 + + pmaddwd mm2,mm4 + punpcklbw mm1,mm7 + + movq mm7,mm1 + punpcklwd mm1,mm3 ;mm1 = [g3][g2][b3][b2] + + punpckhwd mm7,mm3 ;mm7 = [a3][a2][r3][r2] + pmaddwd mm1,mm5 + + pmaddwd mm7,mm5 + paddd mm0,mm6 + + paddd mm2,mm6 + paddd mm0,mm1 + + paddd mm2,mm7 + psrad mm0,14 + + psrad mm2,14 + add esi,4 + + packssdw mm0,mm2 + jne ccint_col_loop_MMX + + packuswb mm0,mm0 + movd dword [ebp-4],mm0 + + pop ebp + pop edi + pop esi + pop ebx + ret + +;-------------------------------------------------------------------------- +;vdasm_resize_ccint_col_SSE2(dst, src1, src2, src3, src4, count, tbl); + + global _vdasm_resize_ccint_col_SSE2 +_vdasm_resize_ccint_col_SSE2: + push ebx + push esi + push edi + push ebp + + mov ebp,[esp + 4 + 16] ;ebp = dest addr + mov esi,[esp + 24 + 16] ;esi = count + add esi,esi + add esi,esi + + mov eax,[esp + 8 + 16] ;eax = row 1 + mov ebx,[esp + 12 + 16] ;ebx = row 2 + mov ecx,[esp + 16 + 16] ;ecx = row 3 + mov edx,[esp + 20 + 16] ;edx = row 4 + mov edi,[esp + 28 + 16] ;edi = coefficient ptr + + neg esi + + add esi,4 + jz ccint_col_SSE2_odd + + movq xmm4,qword [edi] + movq xmm5,qword [edi+8] + punpcklqdq xmm4,xmm4 + punpcklqdq xmm5,xmm5 + movq xmm6,[x0000200000002000] + punpcklqdq xmm6,xmm6 + pxor xmm7,xmm7 + +; jmp short ccint_col_loop_SSE2.entry + +; align 16 +ccint_col_loop_SSE2: + movq xmm0, qword [eax] + add eax, 8 + movq xmm1, qword [ebx] + add ebx, 8 + movq xmm2, qword [ecx] + add ecx, 8 + movq xmm3, qword [edx] + add edx, 8 + punpcklbw xmm0,xmm1 + punpcklbw xmm2,xmm3 + movdqa xmm1,xmm0 + movdqa xmm3,xmm2 + punpcklbw xmm0,xmm7 + punpckhbw xmm1,xmm7 + punpcklbw xmm2,xmm7 + punpckhbw xmm3,xmm7 + pmaddwd xmm0,xmm4 + pmaddwd xmm1,xmm4 + pmaddwd xmm2,xmm5 + pmaddwd xmm3,xmm5 + paddd xmm0,xmm6 + paddd xmm1,xmm6 + paddd xmm0,xmm2 + paddd xmm1,xmm3 + psrad xmm0,14 + psrad xmm1,14 + packssdw xmm0,xmm1 + packuswb xmm0,xmm0 + movdq2q mm0,xmm0 + movntq [ebp],mm0 + add ebp,8 + add esi,8 + jnc ccint_col_loop_SSE2 + jnz ccint_col_SSE2_noodd +ccint_col_SSE2_odd: + movd mm0, dword [eax] + pxor mm7,mm7 + movd mm1, dword [ebx] + movdq2q mm4,xmm4 + movd mm2, dword [ecx] + movdq2q mm5,xmm5 + movd mm3, dword [edx] + movdq2q mm6,xmm6 + punpcklbw mm0,mm1 + punpcklbw mm2,mm3 + movq mm1,mm0 + movq mm3,mm2 + punpcklbw mm0,mm7 + punpckhbw mm1,mm7 + punpcklbw mm2,mm7 + punpckhbw mm3,mm7 + pmaddwd mm0,mm4 + pmaddwd mm1,mm4 + pmaddwd mm2,mm5 + pmaddwd mm3,mm5 + paddd mm0,mm6 + paddd mm2,mm6 + paddd mm0,mm2 + paddd mm1,mm3 + psrad mm0,14 + psrad mm1,14 + packssdw mm0,mm1 + packuswb mm0,mm0 + movd eax,mm0 + movnti [ebp],eax + +ccint_col_SSE2_noodd: + pop ebp + pop edi + pop esi + pop ebx + ret + + + +;------------------------------------------------------------------------- +; +; long resize_table_row_MMX(Pixel *out, Pixel *in, int *filter, int filter_width, PixDim w, long accum, long frac); + + .code + + global _vdasm_resize_table_row_MMX +_vdasm_resize_table_row_MMX: + push ebp + push esi + push edi + push ebx + + cmp dword [esp+16+16], 4 + jz .accel_4coeff + cmp dword [esp+16+16], 6 + jz .accel_6coeff + cmp dword [esp+16+16], 8 + jz .accel_8coeff + + mov eax,[esp + 24 + 16] + mov ebp,[esp + 20 + 16] + mov ebx,[esp + 8 + 16] + mov edi,[esp + 4 + 16] + + mov esi,eax + mov edx,eax + + pxor mm5,mm5 + + mov ecx,[esp + 16 + 16] + shr ecx,1 + mov [esp+16+16],ecx + test ecx,1 + jnz .pixelloop_odd_pairs + +.pixelloop_even_pairs: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + mov ecx,[esp + 16 + 16] + shr edx,5 + add esi,ebx + imul edx,ecx + add eax,[esp + 28 + 16] + add edx,[esp + 12 + 16] + + movq mm6,[MMX_roundval] + pxor mm3,mm3 + movq mm7,mm6 + pxor mm2,mm2 + +.coeffloop_unaligned_even_pairs: + movd mm0,dword [esi+0] + paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) + + punpcklbw mm0,[esi+4] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) + + movd mm2,dword [esi+8] + movq mm1,mm0 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm7,mm0 ;accumulate alpha/red (pixels 0/1) + + paddd mm6,mm1 ;accumulate green/blue (pixels 0/1) + add edx,16 + + add esi,16 + sub ecx,2 + + jne .coeffloop_unaligned_even_pairs + + paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) + + psrad mm7,14 + psrad mm6,14 + + packssdw mm6,mm7 + add edi,4 + + packuswb mm6,mm6 + sub ebp,1 + + mov esi,eax + mov edx,eax + + movd dword [edi-4],mm6 + jne .pixelloop_even_pairs + + pop ebx + pop edi + pop esi + pop ebp + + ret + +;---------------------------------------------------------------- + +.pixelloop_odd_pairs: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + mov ecx,[esp + 16 + 16] + shr edx,5 + add esi,ebx + imul edx,ecx + add eax,[esp + 28 + 16] + sub ecx,1 + add edx,[esp + 12 + 16] + + movq mm6,[MMX_roundval] + pxor mm3,mm3 + pxor mm2,mm2 + movq mm7,mm6 + +.coeffloop_unaligned_odd_pairs: + movd mm0,dword [esi+0] + paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) + + punpcklbw mm0,[esi+4] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) + + movd mm2,dword [esi+8] + movq mm1,mm0 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm7,mm0 ;accumulate alpha/red (pixels 0/1) + + paddd mm6,mm1 ;accumulate green/blue (pixels 0/1) + add edx,16 + + add esi,16 + sub ecx,2 + + jne .coeffloop_unaligned_odd_pairs + + paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) + + ;finish up odd pair + + movd mm0,dword [esi] ;mm0 = [x1][r1][g1][b1] + punpcklbw mm0,[esi+4] ;mm2 = [x0][x1][r0][r1][g0][g1][b0][b1] + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g0][g1][b0][b1] + punpckhbw mm1,mm5 ;mm1 = [x0][x1][r0][r1] + + pmaddwd mm0,[edx] + pmaddwd mm1,[edx] + + paddd mm6,mm0 + paddd mm7,mm1 + + ;combine into pixel + + psrad mm6,14 + + psrad mm7,14 + + packssdw mm6,mm7 + add edi,4 + + packuswb mm6,mm6 + sub ebp,1 + + mov esi,eax + mov edx,eax + + movd dword [edi-4],mm6 + jne .pixelloop_odd_pairs + + pop ebx + pop edi + pop esi + pop ebp + + ret + +;---------------------------------------------------------------- + +.accel_4coeff: + mov eax,[esp + 24 + 16] + mov ebp,[esp + 20 + 16] + add ebp,ebp + add ebp,ebp + mov ebx,[esp + 8 + 16] + mov edi,[esp + 4 + 16] + add edi,ebp + neg ebp + + mov esi,eax + mov edx,eax + + movq mm4,[MMX_roundval] + pxor mm5,mm5 + + mov ecx,[esp+12+16] + +.pixelloop_4coeff: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + shr edx,4 + add esi,ebx + add eax,[esp+28+16] + add edx,ecx + + movd mm0,dword [esi+0] + movd mm2,dword [esi+8] + punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) + + paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) + + psrad mm0,14 + psrad mm1,14 + + packssdw mm1,mm0 + mov esi,eax + + packuswb mm1,mm1 + mov edx,eax + + movd dword [edi+ebp],mm1 + add ebp,4 + jne .pixelloop_4coeff + + pop ebx + pop edi + pop esi + pop ebp + + ret + + +;---------------------------------------------------------------- + +.accel_6coeff: + mov eax,[esp + 24 + 16] + mov ebp,[esp + 20 + 16] + add ebp,ebp + add ebp,ebp + mov ebx,[esp + 8 + 16] + mov edi,[esp + 4 + 16] + add edi,ebp + neg ebp + + mov esi,eax + mov edx,eax + + movq mm4,[MMX_roundval] + pxor mm5,mm5 + + mov ecx,[esp+12+16] + +.pixelloop_6coeff: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + shr edx,5 + lea edx,[edx+edx*2] + add esi,ebx + add eax,[esp+28+16] + add edx,ecx + + movd mm0,dword [esi+0] + movd mm2,dword [esi+8] + punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) + + paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) + + movd mm6,dword [esi+16] + + punpcklbw mm6,[esi+20] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + movq mm7,mm6 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm6,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + + pmaddwd mm6,[edx+16] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm7,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm7,[edx+16] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + paddd mm0,mm6 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm7 ;accumulate green/blue (pixels 0/1) + + + psrad mm0,14 + psrad mm1,14 + + packssdw mm1,mm0 + mov esi,eax + + packuswb mm1,mm1 + mov edx,eax + + movd dword [edi+ebp],mm1 + add ebp,4 + jne .pixelloop_6coeff + + pop ebx + pop edi + pop esi + pop ebp + + ret + +;---------------------------------------------------------------- + +.accel_8coeff: + mov eax,[esp + 24 + 16] + mov ebp,[esp + 20 + 16] + add ebp,ebp + add ebp,ebp + mov ebx,[esp + 8 + 16] + mov edi,[esp + 4 + 16] + add edi,ebp + neg ebp + + mov esi,eax + mov edx,eax + + movq mm4,[MMX_roundval] + pxor mm5,mm5 + + mov ecx,[esp+12+16] + +.pixelloop_8coeff: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + shr edx,3 + add esi,ebx + add eax,[esp+28+16] + add edx,ecx + + movd mm0,dword [esi+0] + movd mm2,dword [esi+8] + punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) + + paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) + + + movd mm6,dword [esi+16] + + punpcklbw mm6,[esi+20] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + movd mm2,dword [esi+24] + + punpcklbw mm2,[esi+28] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + movq mm7,mm6 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm6,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + + pmaddwd mm6,[edx+16] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm7,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm7,[edx+16] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+24] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+24] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm0,mm6 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm7 ;accumulate green/blue (pixels 0/1) + paddd mm0,mm2 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm3 ;accumulate green/blue (pixels 0/1) + + + psrad mm0,14 + psrad mm1,14 + + packssdw mm1,mm0 + mov esi,eax + + packuswb mm1,mm1 + mov edx,eax + + movd dword [edi+ebp],mm1 + add ebp,4 + jne .pixelloop_8coeff + + pop ebx + pop edi + pop esi + pop ebp + + ret + + + + + + + +;------------------------------------------------------------------------- +; +; long resize_table_col_MMX(Pixel *out, Pixel **in_table, int *filter, int filter_width, PixDim w, long frac); + + global _vdasm_resize_table_col_MMX +_vdasm_resize_table_col_MMX: + push ebp + push esi + push edi + push ebx + + mov edx,[esp + 12 + 16] + mov eax,[esp + 24 + 16] + shl eax,2 + imul eax,[esp + 16 + 16] + add edx,eax + mov [esp + 12 + 16], edx ;[esp+12+28] = filter pointer + + mov ebp,[esp + 20 + 16] ;ebp = pixel counter + mov edi,[esp + 4 + 16] ;edi = destination pointer + + pxor mm5,mm5 + + cmp dword [esp+16+16], 4 + jz .accel_4coeff + cmp dword [esp+16+16], 6 + jz .accel_6coeff + + mov ecx,[esp + 16 + 16] + shr ecx,1 + mov [esp + 16 + 16],ecx ;ecx = filter pair count + + xor ebx,ebx ;ebx = source offset + + mov ecx,[esp + 16 + 16] ;ecx = filter width counter +.pixelloop: + mov eax,[esp + 8 + 16] ;esi = row pointer table + movq mm6,[MMX_roundval] + movq mm7,mm6 + pxor mm0,mm0 + pxor mm1,mm1 +.coeffloop: + mov esi,[eax] + paddd mm6,mm0 + + movd mm0,dword [esi+ebx] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + paddd mm7,mm1 + + mov esi,[eax+4] + add eax,8 + + movd mm1,dword [esi+ebx] ;mm1 = [0][0][0][0][x1][r1][g1][b1] + punpcklbw mm0,mm1 ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm0,[edx] + punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] + + pmaddwd mm1,[edx] + add edx,8 + + sub ecx,1 + jne .coeffloop + + paddd mm6,mm0 + paddd mm7,mm1 + + psrad mm6,14 + psrad mm7,14 + add edi,4 + packssdw mm6,mm7 + add ebx,4 + packuswb mm6,mm6 + sub ebp,1 + + mov ecx,[esp + 16 + 16] ;ecx = filter width counter + mov edx,[esp + 12 + 16] ;edx = filter bank pointer + + movd dword [edi-4],mm6 + jne .pixelloop + +.xit: + pop ebx + pop edi + pop esi + pop ebp + ret + + + +.accel_4coeff: + movq mm2,[edx] + movq mm3,[edx+8] + + mov esi,[esp+8+16] ;esi = row pointer table + mov eax,[esi] + add ebp,ebp + mov ebx,[esi+4] + add ebp,ebp + mov ecx,[esi+8] + mov esi,[esi+12] + add eax,ebp + add ebx,ebp + add ecx,ebp + add esi,ebp + add edi,ebp + neg ebp + + ;EAX source 0 + ;EBX source 1 + ;ECX source 2 + ;ESI source 3 + ;EDI destination + ;EBP counter + + movq mm4,[MMX_roundval] + +.pixelloop4: + movd mm6,dword [eax+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + + punpcklbw mm6,[ebx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + + movq mm7,mm6 + punpcklbw mm6,mm5 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm6,mm2 + punpckhbw mm7,mm5 ;mm1 = [x1][x0][r1][r0] + + movd mm0,dword [ecx+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + pmaddwd mm7,mm2 + + punpcklbw mm0,[esi+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + paddd mm6,mm4 + + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm0,mm3 + punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] + + pmaddwd mm1,mm3 + paddd mm7,mm4 + + paddd mm6,mm0 + paddd mm7,mm1 + + psrad mm6,14 + psrad mm7,14 + packssdw mm6,mm7 + packuswb mm6,mm6 + + movd dword [edi+ebp],mm6 + + add ebp,4 + jne .pixelloop4 + jmp .xit + +.accel_6coeff: + movq mm2,[edx] + movq mm3,[edx+8] + movq mm4,[edx+16] + + push 0 + push dword [fs:0] + mov dword [fs:0],esp + + mov esp,[esp+8+24] ;esp = row pointer table + mov eax,[esp] + add ebp,ebp + mov ebx,[esp+4] + add ebp,ebp + mov ecx,[esp+8] + mov edx,[esp+12] + mov esi,[esp+16] + mov esp,[esp+20] + add eax,ebp + add ebx,ebp + add ecx,ebp + add edx,ebp + add esi,ebp + add edi,ebp + add esp,ebp + neg ebp + + ;EAX source 0 + ;EBX source 1 + ;ECX source 2 + ;EDX source 3 + ;ESI source 4 + ;EDI destination + ;ESP source 5 + ;EBP counter + +.pixelloop6: + movd mm6,dword [eax+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + + punpcklbw mm6,[ebx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + + movq mm7,mm6 + punpcklbw mm6,mm5 ;mm0 = [g1][g0][b1][b0] + + movd mm0,dword [ecx+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + punpckhbw mm7,mm5 ;mm1 = [x1][x0][r1][r0] + + punpcklbw mm0,[edx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + pmaddwd mm6,mm2 + + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm7,mm2 + punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] + + paddd mm6,[MMX_roundval] + pmaddwd mm0,mm3 + + paddd mm7,[MMX_roundval] + pmaddwd mm1,mm3 + + paddd mm6,mm0 + + movd mm0,dword [esi+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + paddd mm7,mm1 + + punpcklbw mm0,[esp+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] + punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] + pmaddwd mm0,mm4 + pmaddwd mm1,mm4 + paddd mm6,mm0 + paddd mm7,mm1 + + psrad mm6,14 + psrad mm7,14 + packssdw mm6,mm7 + packuswb mm6,mm6 + + movd dword [edi+ebp],mm6 + + add ebp,4 + jne .pixelloop6 + + mov esp, dword [fs:0] + pop dword [fs:0] + pop eax + + jmp .xit + + + global _vdasm_resize_table_col_SSE2 +_vdasm_resize_table_col_SSE2: + push ebp + push esi + push edi + push ebx + + mov edx,[esp+12+16] + mov eax,[esp+24+16] + shl eax,2 + imul eax,[esp+16+16] + add edx,eax + mov [esp+12+16], edx ;[esp+12+16] = filter pointer + + mov ebp,[esp+20+16] ;ebp = pixel counter + mov edi,[esp+4+16] ;edi = destination pointer + + pxor xmm7, xmm7 + movdqa xmm6, [MMX_roundval] + + cmp dword [esp+16+16], 4 + jz .accel_4coeff + cmp dword [esp+16+16], 6 + jz .accel_6coeff + + mov ecx,[esp+16+16] + shr ecx,1 + mov [esp+16+16],ecx ;ecx = filter pair count + + xor ebx,ebx ;ebx = source offset + + mov ecx,[esp+16+16] ;ecx = filter width counter +.pixelloop: + mov eax, [esp+8+16] ;esi = row pointer table + movdqa xmm4, xmm6 +.coeffloop: + mov esi,[eax] + + movd xmm0, dword [esi+ebx] + + mov esi,[eax+4] + add eax,8 + + movd xmm1, dword [esi+ebx] + punpcklbw xmm0, xmm1 + + punpcklbw xmm0, xmm7 + + movq xmm2, qword [edx] + pshufd xmm2, xmm2, 01000100b + + pmaddwd xmm0, xmm2 + + paddd xmm4, xmm0 + + add edx,8 + + sub ecx,1 + jne .coeffloop + + psrad xmm4,14 + add edi,4 + packssdw xmm4,xmm4 + add ebx,4 + packuswb xmm4,xmm4 + sub ebp,1 + + mov ecx,[esp+16+16] ;ecx = filter width counter + mov edx,[esp+12+16] ;edx = filter bank pointer + + movd dword [edi-4],xmm4 + jne .pixelloop + +.xit: + pop ebx + pop edi + pop esi + pop ebp + ret + +.accel_4coeff: + shl ebp, 2 + mov eax, [esp+8+16] ;eax = row pointer table + mov esi, [eax+12] + mov ecx, [eax+8] + mov ebx, [eax+4] + mov eax, [eax] + lea edi, [edi+ebp-4] + neg ebp + + ;registers: + ; + ;EAX source 0 + ;EBX source 1 + ;ECX source 2 + ;ESI source 3 + ;EDI destination + ;EBP counter + ; + movq xmm4, qword [edx] ;xmm4 = coeff 0/1 + movq xmm5, qword [edx+8] ;xmm5 = coeff 2/3 + punpcklqdq xmm4, xmm4 + punpcklqdq xmm5, xmm5 + + add ebp, 4 + jz .oddpixel_4coeff + +.pixelloop_4coeff_dualpel: + movq xmm0, qword [eax] + movq xmm1, qword [ebx] + movq xmm2, qword [ecx] + movq xmm3, qword [esi] + add eax,8 + add ebx,8 + add ecx,8 + add esi,8 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + punpcklbw xmm0, xmm7 + punpckhbw xmm1, xmm7 + punpcklbw xmm2, xmm7 + punpckhbw xmm3, xmm7 + pmaddwd xmm0, xmm4 + pmaddwd xmm1, xmm4 + pmaddwd xmm2, xmm5 + pmaddwd xmm3, xmm5 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + paddd xmm0, xmm6 + paddd xmm1, xmm6 + psrad xmm0, 14 + psrad xmm1, 14 + packssdw xmm0, xmm1 + packuswb xmm0, xmm0 + movq qword [edi+ebp],xmm0 + add ebp, 8 + jae .pixelloop_4coeff_dualpel + jnz .xit + +.oddpixel_4coeff: + movd xmm0, dword [eax] + movd xmm1, dword [ebx] + movd xmm2, dword [ecx] + movd xmm3, dword [esi] + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm7 + punpcklbw xmm2, xmm7 + pmaddwd xmm0, xmm4 + pmaddwd xmm2, xmm5 + paddd xmm0, xmm2 + paddd xmm0, xmm6 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd dword [edi],xmm0 + jmp .xit + + +.accel_6coeff: + movq xmm4, qword [edx] ;xmm4 = coeff 0/1 + movq xmm5, qword [edx+8] ;xmm5 = coeff 2/3 + movq xmm6, qword [edx+16] ;xmm5 = coeff 4/5 + punpcklqdq xmm4, xmm4 + punpcklqdq xmm5, xmm5 + punpcklqdq xmm6, xmm6 + + push 0 + push dword [fs:0] + mov dword [fs:0],esp + + shl ebp, 2 + mov eax, [esp+8+24] ;eax = row pointer table + mov esp, [eax+20] + mov esi, [eax+16] + mov edx, [eax+12] + mov ecx, [eax+8] + mov ebx, [eax+4] + mov eax, [eax] + lea edi, [edi+ebp-4] + neg ebp + + ;registers: + ; + ;EAX source 0 + ;EBX source 1 + ;ECX source 2 + ;EDX source 3 + ;ESI source 4 + ;EDI destination + ;ESP source 5 + ;EBP counter + ; + + add ebp, 4 + jz .oddpixel_6coeff + +.pixelloop_6coeff_dualpel: + movq xmm0, qword [eax] + movq xmm1, qword [ebx] + movq xmm2, qword [ecx] + movq xmm3, qword [edx] + add eax,8 + add ebx,8 + add ecx,8 + add edx,8 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + punpcklbw xmm0, xmm7 + punpckhbw xmm1, xmm7 + punpcklbw xmm2, xmm7 + punpckhbw xmm3, xmm7 + pmaddwd xmm0, xmm4 + pmaddwd xmm1, xmm4 + pmaddwd xmm2, xmm5 + pmaddwd xmm3, xmm5 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + + movq xmm2, qword [esi] + movq xmm3, qword [esp] + add esi, 8 + add esp, 8 + punpcklbw xmm2, xmm3 + movdqa xmm3, xmm2 + punpcklbw xmm2, xmm7 + punpckhbw xmm3, xmm7 + pmaddwd xmm2, xmm6 + pmaddwd xmm3, xmm6 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + paddd xmm0, [MMX_roundval] + paddd xmm1, [MMX_roundval] + psrad xmm0, 14 + psrad xmm1, 14 + packssdw xmm0, xmm1 + packuswb xmm0, xmm0 + movq qword [edi+ebp],xmm0 + add ebp, 8 + jae .pixelloop_6coeff_dualpel + jnz .xit_6coeff + +.oddpixel_6coeff: + movd xmm0, dword [eax] + movd xmm1, dword [ebx] + movd xmm2, dword [ecx] + movd xmm3, dword [edx] + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + movd xmm1, dword [esi] + movd xmm3, dword [esp] + punpcklbw xmm0, xmm7 + punpcklbw xmm2, xmm7 + pmaddwd xmm0, xmm4 + punpcklbw xmm1, xmm3 + pmaddwd xmm2, xmm5 + punpcklbw xmm1, xmm7 + pmaddwd xmm1, xmm6 + paddd xmm0, xmm2 + paddd xmm1, [MMX_roundval] + paddd xmm0, xmm1 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd dword [edi],xmm0 + +.xit_6coeff: + mov esp, dword [fs:0] + pop dword [fs:0] + pop eax + jmp .xit + + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_resample_sse41.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_resample_sse41.asm index cf7332cb2bf..0ccc2010a23 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_resample_sse41.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_resample_sse41.asm @@ -1,358 +1,358 @@ - segment .rdata, align=16 - -round dq 0000000000002000h -colround dq 0000200000002000h - - segment .text - - global _vdasm_resize_table_row_8_k8_4x_SSE41 -_vdasm_resize_table_row_8_k8_4x_SSE41: - push ebp - push edi - push esi - push ebx - - movq xmm6, [round] - pshufd xmm6, xmm6, 0 - - mov ebp, [esp + 4 + 16] ;ebp = dst - mov esi, [esp + 12 + 16] ;esi = width - mov edi, [esp + 16 + 16] ;edi = kernel -.yloop: - ;eax = temp - ;ebx = temp - ;ecx = temp - ;edx = temp - ;esi = horiz counter - ;edi = filter list - ;ebp = destination - - mov eax, [edi+0] - mov ebx, [edi+4] - mov ecx, [edi+8] - mov edx, [esp+8+16] - add eax, edx - add ebx, edx - add ecx, edx - add edx, [edi+12] - - pmovzxbw xmm0, [eax] - pmaddwd xmm0, [edi+10h] - pmovzxbw xmm1, [ebx] - pmaddwd xmm1, [edi+20h] - pmovzxbw xmm2, [ecx] - pmaddwd xmm2, [edi+30h] - pmovzxbw xmm3, [edx] - pmaddwd xmm3, [edi+40h] - add edi, 50h - phaddd xmm0, xmm1 - phaddd xmm2, xmm3 - phaddd xmm0, xmm2 - paddd xmm0, xmm6 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd [ebp], xmm0 - - add ebp, 4 - sub esi, 1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_resize_table_row_8_k16_4x_SSE41 -_vdasm_resize_table_row_8_k16_4x_SSE41: - push ebp - push edi - push esi - push ebx - - movq xmm6, [round] - pshufd xmm6, xmm6, 0 - - mov ebp, [esp + 4 + 16] ;ebp = dst - mov esi, [esp + 12 + 16] ;esi = width - mov edi, [esp + 16 + 16] ;edi = kernel -.yloop: - ;eax = temp - ;ebx = temp - ;ecx = temp - ;edx = temp - ;esi = horiz counter - ;edi = filter list - ;ebp = destination - - mov eax, [edi+0] - mov ebx, [edi+4] - mov ecx, [edi+8] - mov edx, [esp+8+16] - add eax, edx - add ebx, edx - add ecx, edx - add edx, [edi+12] - - pmovzxbw xmm0, [eax] - pmaddwd xmm0, [edi+10h] - pmovzxbw xmm1, [ebx] - pmaddwd xmm1, [edi+20h] - pmovzxbw xmm2, [ecx] - pmaddwd xmm2, [edi+30h] - pmovzxbw xmm3, [edx] - pmaddwd xmm3, [edi+40h] - pmovzxbw xmm4, [eax+8] - pmaddwd xmm4, [edi+50h] - pmovzxbw xmm5, [ebx+8] - pmaddwd xmm5, [edi+60h] - paddd xmm0, xmm4 - pmovzxbw xmm4, [ecx+8] - pmaddwd xmm4, [edi+70h] - paddd xmm1, xmm5 - pmovzxbw xmm5, [edx+8] - pmaddwd xmm5, [edi+80h] - paddd xmm2, xmm4 - paddd xmm3, xmm5 - add edi, 90h - phaddd xmm0, xmm1 - phaddd xmm2, xmm3 - phaddd xmm0, xmm2 - paddd xmm0, xmm6 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd [ebp], xmm0 - - add ebp, 4 - sub esi, 1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_resize_table_row_8_SSE41 -_vdasm_resize_table_row_8_SSE41: - push ebp - push edi - push esi - push ebx - - pxor xmm7, xmm7 - movq xmm6, [round] - - mov edi, [esp + 4 + 16] ;edi = dst - mov ebx, [esp + 8 + 16] ;ebx = src - mov ebp, [esp + 12 + 16] ;ebp = width - mov edx, [esp + 16 + 16] ;edx = kernel -.yloop: - ;eax = temp - ;ebx = source base address - ;ecx = (temp) source - ;edx = filter list - ;esi = (temp) kernel width - ;edi = destination - ;ebp = horiz counter - - mov eax, [edx] - add edx, 16 - lea ecx, [ebx + eax] - mov esi, [esp + 20 + 16] ;esi = kernel width - - movq xmm2, xmm6 -.xloop: - pmovzxbw xmm0, [ecx] - add ecx, 8 - pmaddwd xmm0, [edx] - paddd xmm2, xmm0 - add edx, 16 - sub esi, 8 - jne .xloop - - phaddd xmm2, xmm2 - phaddd xmm2, xmm2 - psrad xmm2, 14 - packssdw xmm2, xmm2 - packuswb xmm2, xmm2 - movd eax, xmm2 - mov [edi], al - add edi, 1 - sub ebp, 1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_resize_table_col_8_k2_SSE41 -_vdasm_resize_table_col_8_k2_SSE41: - push ebp - push edi - push esi - push ebx - - movq xmm6, [colround] - pshufd xmm6, xmm6, 0 - - mov esi, [esp + 4 + 16] ;esi = dst - mov edi, [esp + 16 + 16] ;edi = kernel - mov ebp, [esp + 12 + 16] ;ebp = width - - movq xmm7, [edi] - pshufd xmm7, xmm7, 0 - - mov edx, [esp + 8 + 16] ;ebx = srcs - mov eax, [edx+0] - mov ebx, [edx+4] - add eax, ebp - add ebx, ebp - neg ebp - -.yloop: - ;eax = row0 - ;ebx = row1 - ;ecx = - ;edx = - ;edi = kernel - ;esi = dest - ;ebp = width counter - - movd xmm0, [eax+ebp] - movd xmm2, [ebx+ebp] - punpcklbw xmm0, xmm2 - pmovzxbw xmm0, xmm0 - pmaddwd xmm0, xmm7 - - paddd xmm0, xmm6 - - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd [esi], xmm0 - add esi, 4 - add ebp, 4 - jnz .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_resize_table_col_8_k4_SSE41 -_vdasm_resize_table_col_8_k4_SSE41: - push ebp - push edi - push esi - push ebx - - movq xmm7, [colround] - pshufd xmm7, xmm7, 0 - - mov esi, [esp + 4 + 16] ;esi = dst - mov edi, [esp + 16 + 16] ;edi = kernel - - movdqu xmm6, [edi] - pshufd xmm5, xmm6, 0 - pshufd xmm6, xmm6, 0aah - - mov edx, [esp + 8 + 16] ;ebx = srcs - mov ebp, [esp + 12 + 16] - mov eax, [edx+0] - mov ebx, [edx+4] - mov ecx, [edx+8] - mov edx, [edx+12] - lea eax, [eax+ebp-4] - lea ebx, [ebx+ebp-4] - lea ecx, [ecx+ebp-4] - lea edx, [edx+ebp-4] - lea esi, [esi+ebp-4] - neg ebp - add ebp,4 - jz .odd -.yloop: - ;eax = row0 - ;ebx = row1 - ;ecx = row2 - ;edx = row3 - ;edi = kernel - ;esi = dest - ;ebp = width counter - - movd xmm0, [eax+ebp] - movd xmm1, [ebx+ebp] - punpcklbw xmm0, xmm1 - - movd xmm1, [ecx+ebp] - movd xmm2, [edx+ebp] - punpcklbw xmm1, xmm2 - - movd xmm2, [eax+ebp+4] - movd xmm3, [ebx+ebp+4] - punpcklbw xmm2, xmm3 - - movd xmm3, [ecx+ebp+4] - movd xmm4, [edx+ebp+4] - punpcklbw xmm3, xmm4 - - pmovzxbw xmm0, xmm0 - pmaddwd xmm0, xmm5 - - pmovzxbw xmm1, xmm1 - pmaddwd xmm1, xmm6 - - pmovzxbw xmm2, xmm2 - pmaddwd xmm2, xmm5 - - pmovzxbw xmm3, xmm3 - pmaddwd xmm3, xmm6 - - paddd xmm0, xmm1 - paddd xmm2, xmm3 - - paddd xmm0, xmm7 - paddd xmm2, xmm7 - - psrad xmm0, 14 - psrad xmm2, 14 - - packssdw xmm0, xmm2 - packuswb xmm0, xmm0 - movq [esi+ebp], xmm0 - add ebp, 8 - js .yloop - jnz .noodd - -.odd: - movd xmm0, [eax] - movd xmm1, [ebx] - movd xmm2, [ecx] - movd xmm3, [edx] - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - pmovzxbw xmm0, xmm0 - pmovzxbw xmm2, xmm2 - pmaddwd xmm0, xmm5 - pmaddwd xmm2, xmm6 - paddd xmm0, xmm2 - paddd xmm0, xmm7 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd [esi], xmm0 -.noodd: - - pop ebx - pop esi - pop edi - pop ebp - ret - - end + segment .rdata, align=16 + +round dq 0000000000002000h +colround dq 0000200000002000h + + segment .text + + global _vdasm_resize_table_row_8_k8_4x_SSE41 +_vdasm_resize_table_row_8_k8_4x_SSE41: + push ebp + push edi + push esi + push ebx + + movq xmm6, [round] + pshufd xmm6, xmm6, 0 + + mov ebp, [esp + 4 + 16] ;ebp = dst + mov esi, [esp + 12 + 16] ;esi = width + mov edi, [esp + 16 + 16] ;edi = kernel +.yloop: + ;eax = temp + ;ebx = temp + ;ecx = temp + ;edx = temp + ;esi = horiz counter + ;edi = filter list + ;ebp = destination + + mov eax, [edi+0] + mov ebx, [edi+4] + mov ecx, [edi+8] + mov edx, [esp+8+16] + add eax, edx + add ebx, edx + add ecx, edx + add edx, [edi+12] + + pmovzxbw xmm0, [eax] + pmaddwd xmm0, [edi+10h] + pmovzxbw xmm1, [ebx] + pmaddwd xmm1, [edi+20h] + pmovzxbw xmm2, [ecx] + pmaddwd xmm2, [edi+30h] + pmovzxbw xmm3, [edx] + pmaddwd xmm3, [edi+40h] + add edi, 50h + phaddd xmm0, xmm1 + phaddd xmm2, xmm3 + phaddd xmm0, xmm2 + paddd xmm0, xmm6 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd [ebp], xmm0 + + add ebp, 4 + sub esi, 1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_resize_table_row_8_k16_4x_SSE41 +_vdasm_resize_table_row_8_k16_4x_SSE41: + push ebp + push edi + push esi + push ebx + + movq xmm6, [round] + pshufd xmm6, xmm6, 0 + + mov ebp, [esp + 4 + 16] ;ebp = dst + mov esi, [esp + 12 + 16] ;esi = width + mov edi, [esp + 16 + 16] ;edi = kernel +.yloop: + ;eax = temp + ;ebx = temp + ;ecx = temp + ;edx = temp + ;esi = horiz counter + ;edi = filter list + ;ebp = destination + + mov eax, [edi+0] + mov ebx, [edi+4] + mov ecx, [edi+8] + mov edx, [esp+8+16] + add eax, edx + add ebx, edx + add ecx, edx + add edx, [edi+12] + + pmovzxbw xmm0, [eax] + pmaddwd xmm0, [edi+10h] + pmovzxbw xmm1, [ebx] + pmaddwd xmm1, [edi+20h] + pmovzxbw xmm2, [ecx] + pmaddwd xmm2, [edi+30h] + pmovzxbw xmm3, [edx] + pmaddwd xmm3, [edi+40h] + pmovzxbw xmm4, [eax+8] + pmaddwd xmm4, [edi+50h] + pmovzxbw xmm5, [ebx+8] + pmaddwd xmm5, [edi+60h] + paddd xmm0, xmm4 + pmovzxbw xmm4, [ecx+8] + pmaddwd xmm4, [edi+70h] + paddd xmm1, xmm5 + pmovzxbw xmm5, [edx+8] + pmaddwd xmm5, [edi+80h] + paddd xmm2, xmm4 + paddd xmm3, xmm5 + add edi, 90h + phaddd xmm0, xmm1 + phaddd xmm2, xmm3 + phaddd xmm0, xmm2 + paddd xmm0, xmm6 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd [ebp], xmm0 + + add ebp, 4 + sub esi, 1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_resize_table_row_8_SSE41 +_vdasm_resize_table_row_8_SSE41: + push ebp + push edi + push esi + push ebx + + pxor xmm7, xmm7 + movq xmm6, [round] + + mov edi, [esp + 4 + 16] ;edi = dst + mov ebx, [esp + 8 + 16] ;ebx = src + mov ebp, [esp + 12 + 16] ;ebp = width + mov edx, [esp + 16 + 16] ;edx = kernel +.yloop: + ;eax = temp + ;ebx = source base address + ;ecx = (temp) source + ;edx = filter list + ;esi = (temp) kernel width + ;edi = destination + ;ebp = horiz counter + + mov eax, [edx] + add edx, 16 + lea ecx, [ebx + eax] + mov esi, [esp + 20 + 16] ;esi = kernel width + + movq xmm2, xmm6 +.xloop: + pmovzxbw xmm0, [ecx] + add ecx, 8 + pmaddwd xmm0, [edx] + paddd xmm2, xmm0 + add edx, 16 + sub esi, 8 + jne .xloop + + phaddd xmm2, xmm2 + phaddd xmm2, xmm2 + psrad xmm2, 14 + packssdw xmm2, xmm2 + packuswb xmm2, xmm2 + movd eax, xmm2 + mov [edi], al + add edi, 1 + sub ebp, 1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_resize_table_col_8_k2_SSE41 +_vdasm_resize_table_col_8_k2_SSE41: + push ebp + push edi + push esi + push ebx + + movq xmm6, [colround] + pshufd xmm6, xmm6, 0 + + mov esi, [esp + 4 + 16] ;esi = dst + mov edi, [esp + 16 + 16] ;edi = kernel + mov ebp, [esp + 12 + 16] ;ebp = width + + movq xmm7, [edi] + pshufd xmm7, xmm7, 0 + + mov edx, [esp + 8 + 16] ;ebx = srcs + mov eax, [edx+0] + mov ebx, [edx+4] + add eax, ebp + add ebx, ebp + neg ebp + +.yloop: + ;eax = row0 + ;ebx = row1 + ;ecx = + ;edx = + ;edi = kernel + ;esi = dest + ;ebp = width counter + + movd xmm0, [eax+ebp] + movd xmm2, [ebx+ebp] + punpcklbw xmm0, xmm2 + pmovzxbw xmm0, xmm0 + pmaddwd xmm0, xmm7 + + paddd xmm0, xmm6 + + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd [esi], xmm0 + add esi, 4 + add ebp, 4 + jnz .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_resize_table_col_8_k4_SSE41 +_vdasm_resize_table_col_8_k4_SSE41: + push ebp + push edi + push esi + push ebx + + movq xmm7, [colround] + pshufd xmm7, xmm7, 0 + + mov esi, [esp + 4 + 16] ;esi = dst + mov edi, [esp + 16 + 16] ;edi = kernel + + movdqu xmm6, [edi] + pshufd xmm5, xmm6, 0 + pshufd xmm6, xmm6, 0aah + + mov edx, [esp + 8 + 16] ;ebx = srcs + mov ebp, [esp + 12 + 16] + mov eax, [edx+0] + mov ebx, [edx+4] + mov ecx, [edx+8] + mov edx, [edx+12] + lea eax, [eax+ebp-4] + lea ebx, [ebx+ebp-4] + lea ecx, [ecx+ebp-4] + lea edx, [edx+ebp-4] + lea esi, [esi+ebp-4] + neg ebp + add ebp,4 + jz .odd +.yloop: + ;eax = row0 + ;ebx = row1 + ;ecx = row2 + ;edx = row3 + ;edi = kernel + ;esi = dest + ;ebp = width counter + + movd xmm0, [eax+ebp] + movd xmm1, [ebx+ebp] + punpcklbw xmm0, xmm1 + + movd xmm1, [ecx+ebp] + movd xmm2, [edx+ebp] + punpcklbw xmm1, xmm2 + + movd xmm2, [eax+ebp+4] + movd xmm3, [ebx+ebp+4] + punpcklbw xmm2, xmm3 + + movd xmm3, [ecx+ebp+4] + movd xmm4, [edx+ebp+4] + punpcklbw xmm3, xmm4 + + pmovzxbw xmm0, xmm0 + pmaddwd xmm0, xmm5 + + pmovzxbw xmm1, xmm1 + pmaddwd xmm1, xmm6 + + pmovzxbw xmm2, xmm2 + pmaddwd xmm2, xmm5 + + pmovzxbw xmm3, xmm3 + pmaddwd xmm3, xmm6 + + paddd xmm0, xmm1 + paddd xmm2, xmm3 + + paddd xmm0, xmm7 + paddd xmm2, xmm7 + + psrad xmm0, 14 + psrad xmm2, 14 + + packssdw xmm0, xmm2 + packuswb xmm0, xmm0 + movq [esi+ebp], xmm0 + add ebp, 8 + js .yloop + jnz .noodd + +.odd: + movd xmm0, [eax] + movd xmm1, [ebx] + movd xmm2, [ecx] + movd xmm3, [edx] + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + pmovzxbw xmm0, xmm0 + pmovzxbw xmm2, xmm2 + pmaddwd xmm0, xmm5 + pmaddwd xmm2, xmm6 + paddd xmm0, xmm2 + paddd xmm0, xmm7 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd [esi], xmm0 +.noodd: + + pop ebx + pop esi + pop edi + pop ebp + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_spanutils_isse.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_spanutils_isse.asm index 3fe7cedbc59..60200e2159b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_spanutils_isse.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_spanutils_isse.asm @@ -1,193 +1,193 @@ - section .rdata, rdata, align=16 - -xfefefefefefefefe dq 0fefefefefefefefeh -xe0e0e0e0e0e0e0e0 dq 0e0e0e0e0e0e0e0e0h -x0002000200020002 dq 00002000200020002h - - section .text - -;============================================================================== - global _vdasm_horiz_expand2x_coaligned_ISSE -_vdasm_horiz_expand2x_coaligned_ISSE: - mov ecx, [esp+8] - mov edx, [esp+4] - mov eax, [esp+12] -.xloop: - movq mm0, [ecx] - movq mm1, mm0 - pavgb mm0, [ecx+1] - movq mm2, mm1 - punpcklbw mm1, mm0 - punpckhbw mm2, mm0 - - movq [edx], mm1 - movq [edx+8], mm2 - add edx, 16 - add ecx, 8 - - sub eax, 16 - jne .xloop - ret - -;============================================================================== - global _vdasm_vert_average_13_ISSE -_vdasm_vert_average_13_ISSE: - push ebx - mov ebx, [esp+12+4] - mov ecx, [esp+8+4] - mov edx, [esp+4+4] - mov eax, [esp+16+4] - - add ebx, eax - add ecx, eax - add edx, eax - neg eax - - pcmpeqb mm7, mm7 -.xloop: - movq mm0, [ebx+eax] - movq mm1, [ecx+eax] - movq mm2, mm0 - - movq mm3, [ebx+eax+8] - pxor mm0, mm7 - pxor mm1, mm7 - - movq mm4, [ecx+eax+8] - movq mm5, mm3 - pxor mm3, mm7 - - pxor mm4, mm7 - pavgb mm0, mm1 - pavgb mm3, mm4 - - pxor mm0, mm7 - pxor mm3, mm7 - pavgb mm0, mm2 - - movq [edx+eax], mm0 - pavgb mm3, mm5 - - movq [edx+eax+8], mm3 - add eax, 16 - jne .xloop - - pop ebx - ret - -;============================================================================== - global _vdasm_vert_average_17_ISSE -_vdasm_vert_average_17_ISSE: - push ebx - mov ebx, [esp+12+4] - mov ecx, [esp+8+4] - mov edx, [esp+4+4] - mov eax, [esp+16+4] - - add ebx, eax - add ecx, eax - add edx, eax - neg eax - - ;r = avgup(avgdown(avgdown(a, b), a), a) - ; = pavgb(~pavgb(pavgb(~a, ~b), ~a), a) - - pcmpeqb mm7, mm7 -.xloop: - movq mm0, [ecx+eax] - movq mm1, [ebx+eax] - movq mm2, mm0 - pxor mm0, mm7 ;~a - pxor mm1, mm7 ;~b - pavgb mm1, mm0 ;pavgb(~a, ~b) = ~avgdown(a, b) - pavgb mm1, mm0 ;pavgb(~avgdown(a, b), ~a) = ~avgdown(avgdown(a, b), a) - pxor mm1, mm7 ;avgdown(avgdown(a, b), a) - pavgb mm1, mm2 ;pavgb(avgdown(avgdown(a, b), a), a) = round((7*a + b)/8) - movq [edx+eax], mm1 - - add eax, 8 - jne .xloop - - pop ebx - ret - -;============================================================================== - global _vdasm_vert_average_35_ISSE -_vdasm_vert_average_35_ISSE: - push ebx - mov ebx, [esp+12+4] - mov ecx, [esp+8+4] - mov edx, [esp+4+4] - mov eax, [esp+16+4] - - add ebx, eax - add ecx, eax - add edx, eax - neg eax - - ;r = avgup(avgdown(avgdown(a, b), b), a) - ; = pavgb(~pavgb(pavgb(~a, ~b), ~b), a) - - pcmpeqb mm7, mm7 -.xloop: - movq mm0, [ecx+eax] - movq mm1, [ebx+eax] - movq mm2, mm0 - pxor mm0, mm7 ;~a - pxor mm1, mm7 ;~b - pavgb mm0, mm1 ;avgup(~a, ~b) = ~avgdown(a, b) - pavgb mm0, mm1 ;avgup(~avgdown(a, b), ~b) = ~avgdown(avgdown(a, b), b) - pxor mm0, mm7 ;avgdown(avgdown(a, b), b) - pavgb mm0, mm2 ;avgup(avgdown(avgdown(a, b), b), a) = round((5*a + 3*b) / 8) - movq [edx+eax], mm0 - - add eax, 8 - jne .xloop - - pop ebx - ret - -;============================================================================== - global _vdasm_horiz_expand4x_coaligned_MMX -_vdasm_horiz_expand4x_coaligned_MMX: - mov edx, [esp+4] - mov ecx, [esp+8] - mov eax, [esp+12] - movq mm6, qword [x0002000200020002] - pxor mm7, mm7 -.xloop: - movd mm0, [ecx] - movd mm1, [ecx+1] - add ecx, 4 - punpcklbw mm0, mm7 - punpcklbw mm1, mm7 - psubw mm1, mm0 ;x1 - movq mm2, mm1 - paddw mm1, mm6 ;x1 + 2 - movq mm3, mm1 - paddw mm2, mm2 ;x2 - paddw mm3, mm2 ;x3 + 2 - paddw mm2, mm6 ;x2 + 2 - psraw mm1, 2 ;x1/4 - psraw mm2, 2 ;x2/4 - psraw mm3, 2 ;x3/4 - paddw mm1, mm0 - paddw mm2, mm0 - paddw mm3, mm0 - movd mm0, [ecx-4] - packuswb mm1, mm1 - packuswb mm2, mm2 - packuswb mm3, mm3 - punpcklbw mm0, mm1 - punpcklbw mm2, mm3 - movq mm1, mm0 - punpcklwd mm0, mm2 - punpckhwd mm1, mm2 - - movq [edx], mm0 - movq [edx+8], mm1 - add edx, 16 - sub eax, 1 - jne .xloop - - ret + section .rdata, rdata, align=16 + +xfefefefefefefefe dq 0fefefefefefefefeh +xe0e0e0e0e0e0e0e0 dq 0e0e0e0e0e0e0e0e0h +x0002000200020002 dq 00002000200020002h + + section .text + +;============================================================================== + global _vdasm_horiz_expand2x_coaligned_ISSE +_vdasm_horiz_expand2x_coaligned_ISSE: + mov ecx, [esp+8] + mov edx, [esp+4] + mov eax, [esp+12] +.xloop: + movq mm0, [ecx] + movq mm1, mm0 + pavgb mm0, [ecx+1] + movq mm2, mm1 + punpcklbw mm1, mm0 + punpckhbw mm2, mm0 + + movq [edx], mm1 + movq [edx+8], mm2 + add edx, 16 + add ecx, 8 + + sub eax, 16 + jne .xloop + ret + +;============================================================================== + global _vdasm_vert_average_13_ISSE +_vdasm_vert_average_13_ISSE: + push ebx + mov ebx, [esp+12+4] + mov ecx, [esp+8+4] + mov edx, [esp+4+4] + mov eax, [esp+16+4] + + add ebx, eax + add ecx, eax + add edx, eax + neg eax + + pcmpeqb mm7, mm7 +.xloop: + movq mm0, [ebx+eax] + movq mm1, [ecx+eax] + movq mm2, mm0 + + movq mm3, [ebx+eax+8] + pxor mm0, mm7 + pxor mm1, mm7 + + movq mm4, [ecx+eax+8] + movq mm5, mm3 + pxor mm3, mm7 + + pxor mm4, mm7 + pavgb mm0, mm1 + pavgb mm3, mm4 + + pxor mm0, mm7 + pxor mm3, mm7 + pavgb mm0, mm2 + + movq [edx+eax], mm0 + pavgb mm3, mm5 + + movq [edx+eax+8], mm3 + add eax, 16 + jne .xloop + + pop ebx + ret + +;============================================================================== + global _vdasm_vert_average_17_ISSE +_vdasm_vert_average_17_ISSE: + push ebx + mov ebx, [esp+12+4] + mov ecx, [esp+8+4] + mov edx, [esp+4+4] + mov eax, [esp+16+4] + + add ebx, eax + add ecx, eax + add edx, eax + neg eax + + ;r = avgup(avgdown(avgdown(a, b), a), a) + ; = pavgb(~pavgb(pavgb(~a, ~b), ~a), a) + + pcmpeqb mm7, mm7 +.xloop: + movq mm0, [ecx+eax] + movq mm1, [ebx+eax] + movq mm2, mm0 + pxor mm0, mm7 ;~a + pxor mm1, mm7 ;~b + pavgb mm1, mm0 ;pavgb(~a, ~b) = ~avgdown(a, b) + pavgb mm1, mm0 ;pavgb(~avgdown(a, b), ~a) = ~avgdown(avgdown(a, b), a) + pxor mm1, mm7 ;avgdown(avgdown(a, b), a) + pavgb mm1, mm2 ;pavgb(avgdown(avgdown(a, b), a), a) = round((7*a + b)/8) + movq [edx+eax], mm1 + + add eax, 8 + jne .xloop + + pop ebx + ret + +;============================================================================== + global _vdasm_vert_average_35_ISSE +_vdasm_vert_average_35_ISSE: + push ebx + mov ebx, [esp+12+4] + mov ecx, [esp+8+4] + mov edx, [esp+4+4] + mov eax, [esp+16+4] + + add ebx, eax + add ecx, eax + add edx, eax + neg eax + + ;r = avgup(avgdown(avgdown(a, b), b), a) + ; = pavgb(~pavgb(pavgb(~a, ~b), ~b), a) + + pcmpeqb mm7, mm7 +.xloop: + movq mm0, [ecx+eax] + movq mm1, [ebx+eax] + movq mm2, mm0 + pxor mm0, mm7 ;~a + pxor mm1, mm7 ;~b + pavgb mm0, mm1 ;avgup(~a, ~b) = ~avgdown(a, b) + pavgb mm0, mm1 ;avgup(~avgdown(a, b), ~b) = ~avgdown(avgdown(a, b), b) + pxor mm0, mm7 ;avgdown(avgdown(a, b), b) + pavgb mm0, mm2 ;avgup(avgdown(avgdown(a, b), b), a) = round((5*a + 3*b) / 8) + movq [edx+eax], mm0 + + add eax, 8 + jne .xloop + + pop ebx + ret + +;============================================================================== + global _vdasm_horiz_expand4x_coaligned_MMX +_vdasm_horiz_expand4x_coaligned_MMX: + mov edx, [esp+4] + mov ecx, [esp+8] + mov eax, [esp+12] + movq mm6, qword [x0002000200020002] + pxor mm7, mm7 +.xloop: + movd mm0, [ecx] + movd mm1, [ecx+1] + add ecx, 4 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm1, mm0 ;x1 + movq mm2, mm1 + paddw mm1, mm6 ;x1 + 2 + movq mm3, mm1 + paddw mm2, mm2 ;x2 + paddw mm3, mm2 ;x3 + 2 + paddw mm2, mm6 ;x2 + 2 + psraw mm1, 2 ;x1/4 + psraw mm2, 2 ;x2/4 + psraw mm3, 2 ;x3/4 + paddw mm1, mm0 + paddw mm2, mm0 + paddw mm3, mm0 + movd mm0, [ecx-4] + packuswb mm1, mm1 + packuswb mm2, mm2 + packuswb mm3, mm3 + punpcklbw mm0, mm1 + punpcklbw mm2, mm3 + movq mm1, mm0 + punpcklwd mm0, mm2 + punpckhwd mm1, mm2 + + movq [edx], mm0 + movq [edx+8], mm1 + add edx, 16 + sub eax, 1 + jne .xloop + + ret diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_mmx.asm index 3db442fa28f..88e0955c086 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_mmx.asm @@ -1,326 +1,326 @@ - segment .rdata, align=16 - -x0020w dq 00020002000200020h -rb_mask_555 dq 07c1f7c1f7c1f7c1fh -g_mask_555 dq 003e003e003e003e0h -rb_mask_888 dq 000ff00ff00ff00ffh -g_mask_888 dq 00000ff000000ff00h - - segment .text - - struc VDPixmapReferenceStretchBltBilinearParameters -.dst resd 1 -.src resd 1 -.u resd 1 -.uinc resd 1 -.dudx resd 1 - -.xprepos resd 1 -.xpostpos resd 1 -.xprecopy resd 1 -.xpostcopy resd 1 -.xmidsize resd 1 - endstruc - - - - global _vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX -_vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+20+16] - and eax, 0f8000000h - mov ebx, [esp+8+16] - mov ecx, [esp+12+16] - jz .noreverse - xchg ebx, ecx - js .noreverse - neg eax - xchg ebx, ecx -.noreverse: - shr eax, 16 - mov [esp+20+16], eax - mov edx, [esp+4+16] - mov eax, [esp+16+16] - add eax, eax - lea ebx, [ebx+eax-6] - lea ecx, [ecx+eax-6] - lea edx, [edx+eax-6] - neg eax - - movd mm4, dword [esp+20+16] - punpcklwd mm4, mm4 - punpckldq mm4, mm4 - - movq mm6, [rb_mask_555] - movq mm7, [g_mask_555] - -.xstart: - add eax, 6 - jbe .doodd -.xloop: - movq mm0, [ebx+eax] - movq mm1, [ecx+eax] - movq mm2, mm7 - movq mm3, mm7 - - pand mm2, mm0 - pand mm3, mm1 - pand mm0, mm6 - pand mm1, mm6 - - psubw mm3, mm2 - psubw mm1, mm0 - - pmulhw mm3, mm4 - pmulhw mm1, mm4 - - psubw mm0, mm1 - psubw mm2, mm3 - - pand mm0, mm6 - pand mm2, mm7 - - paddw mm0, mm2 - - movq [edx+eax], mm0 - add eax, 8 - jnc .xloop - -.doodd: - sub eax, 6 - jz .noodd -.odd: - movzx esi, word [ebx+eax+6] - movd mm0, esi - movzx esi, word [ecx+eax+6] - movd mm1, esi - movq mm2, mm7 - movq mm3, mm7 - - pand mm2, mm0 - pand mm3, mm1 - pand mm0, mm6 - pand mm1, mm6 - - psubw mm3, mm2 - psubw mm1, mm0 - - pmulhw mm3, mm4 - pmulhw mm1, mm4 - - psubw mm0, mm1 - psubw mm2, mm3 - - pand mm0, mm6 - pand mm2, mm7 - - paddw mm0, mm2 - - movd esi, mm0 - mov [edx+eax+6], si - add eax,2 - jne .odd - -.noodd: - emms - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX -_vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX: - push ebp - push edi - push esi - push ebx - - mov edx, [esp+4+16] - - mov ebx, [edx+VDPixmapReferenceStretchBltBilinearParameters.src] - mov edi, [edx+VDPixmapReferenceStretchBltBilinearParameters.dst] - - mov ecx, [edx+VDPixmapReferenceStretchBltBilinearParameters.xprecopy] - or ecx, ecx - jz .noprecopy - mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.xprepos] - mov eax, [ebx+eax] - lea ebp, [ecx*4] - sub edi, ebp - rep stosd -.noprecopy: - mov ebp, [edx+VDPixmapReferenceStretchBltBilinearParameters.xmidsize] - add ebp, ebp - add ebp, ebp - add edi, ebp - neg ebp - - mov esi, [edx+VDPixmapReferenceStretchBltBilinearParameters.u] - mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.dudx] - mov edx, [edx+VDPixmapReferenceStretchBltBilinearParameters.uinc] - movd mm2, esi - movd mm3, eax - shr ebx, 2 - - movq mm5, mm2 - punpcklwd mm5, mm5 - punpckhdq mm5, mm5 - movq mm4, mm5 - psraw mm4, 15 - -.xloop: - movd mm0, dword [ebx*4] - pxor mm7, mm7 - movd mm1, dword [ebx*4+4] - punpcklbw mm0, mm7 - punpcklbw mm1, mm7 - psubw mm1, mm0 - pand mm4, mm1 - pmulhw mm1, mm5 - paddw mm1, mm4 - paddw mm0, mm1 - packuswb mm0, mm0 - movd dword [edi+ebp], mm0 - - add esi, eax - adc ebx, edx - - paddd mm2, mm3 - movq mm5, mm2 - punpcklwd mm5, mm5 - punpckhdq mm5, mm5 - movq mm4, mm5 - psraw mm4, 15 - add ebp, 4 - jnz .xloop - - mov edx, [esp+4+16] - mov ecx, [edx+VDPixmapReferenceStretchBltBilinearParameters.xpostcopy] - or ecx, ecx - jz .nopostcopy - mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.xpostpos] - add eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.src] - mov eax, [eax] - rep stosd -.nopostcopy: - - emms - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX -_vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+20+16] - and eax, 0ff000000h - mov ebx, [esp+8+16] - mov ecx, [esp+12+16] - jz .noreverse - xchg ebx, ecx - js .noreverse - neg eax - xchg ebx, ecx -.noreverse: - shr eax, 16 - mov [esp+20+16], eax - mov edx, [esp+4+16] - mov eax, [esp+16+16] - add eax, eax - add eax, eax - lea ebx, [ebx+eax-4] - lea ecx, [ecx+eax-4] - lea edx, [edx+eax-4] - neg eax - - movd mm4, dword [esp+20+16] - punpcklwd mm4, mm4 - punpckldq mm4, mm4 - - movq mm6, [rb_mask_888] - movq mm7, [g_mask_888] - -.xstart: - add eax, 4 - jbe .doodd -.xloop: - movq mm0, [ebx+eax] - movq mm1, [ecx+eax] - movq mm2, mm0 - movq mm3, mm1 - psrlw mm2, 8 - psrlw mm3, 8 - pand mm0, mm6 - pand mm1, mm6 - - psubw mm3, mm2 - psubw mm1, mm0 - - pmulhw mm3, mm4 - pmulhw mm1, mm4 - - psubw mm0, mm1 - psubw mm2, mm3 - - pand mm0, mm6 - - psllw mm2, 8 - - paddw mm0, mm2 - - movq qword [edx+eax], mm0 - add eax, 8 - jnc .xloop - -.doodd: - sub eax, 4 - jz .noodd -.odd: - movd mm0, dword [ebx] - movd mm1, dword [ecx] - movq mm2, mm0 - movq mm3, mm1 - psrlw mm2, 8 - psrlw mm3, 8 - pand mm0, mm6 - pand mm1, mm6 - - psubw mm3, mm2 - psubw mm1, mm0 - - pmulhw mm3, mm4 - pmulhw mm1, mm4 - - psubw mm0, mm1 - psubw mm2, mm3 - - pand mm0, mm6 - - psllw mm2, 8 - - paddw mm0, mm2 - - movd dword [edx], mm0 - -.noodd: - emms - pop ebx - pop esi - pop edi - pop ebp - ret - - - end + segment .rdata, align=16 + +x0020w dq 00020002000200020h +rb_mask_555 dq 07c1f7c1f7c1f7c1fh +g_mask_555 dq 003e003e003e003e0h +rb_mask_888 dq 000ff00ff00ff00ffh +g_mask_888 dq 00000ff000000ff00h + + segment .text + + struc VDPixmapReferenceStretchBltBilinearParameters +.dst resd 1 +.src resd 1 +.u resd 1 +.uinc resd 1 +.dudx resd 1 + +.xprepos resd 1 +.xpostpos resd 1 +.xprecopy resd 1 +.xpostcopy resd 1 +.xmidsize resd 1 + endstruc + + + + global _vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX +_vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+20+16] + and eax, 0f8000000h + mov ebx, [esp+8+16] + mov ecx, [esp+12+16] + jz .noreverse + xchg ebx, ecx + js .noreverse + neg eax + xchg ebx, ecx +.noreverse: + shr eax, 16 + mov [esp+20+16], eax + mov edx, [esp+4+16] + mov eax, [esp+16+16] + add eax, eax + lea ebx, [ebx+eax-6] + lea ecx, [ecx+eax-6] + lea edx, [edx+eax-6] + neg eax + + movd mm4, dword [esp+20+16] + punpcklwd mm4, mm4 + punpckldq mm4, mm4 + + movq mm6, [rb_mask_555] + movq mm7, [g_mask_555] + +.xstart: + add eax, 6 + jbe .doodd +.xloop: + movq mm0, [ebx+eax] + movq mm1, [ecx+eax] + movq mm2, mm7 + movq mm3, mm7 + + pand mm2, mm0 + pand mm3, mm1 + pand mm0, mm6 + pand mm1, mm6 + + psubw mm3, mm2 + psubw mm1, mm0 + + pmulhw mm3, mm4 + pmulhw mm1, mm4 + + psubw mm0, mm1 + psubw mm2, mm3 + + pand mm0, mm6 + pand mm2, mm7 + + paddw mm0, mm2 + + movq [edx+eax], mm0 + add eax, 8 + jnc .xloop + +.doodd: + sub eax, 6 + jz .noodd +.odd: + movzx esi, word [ebx+eax+6] + movd mm0, esi + movzx esi, word [ecx+eax+6] + movd mm1, esi + movq mm2, mm7 + movq mm3, mm7 + + pand mm2, mm0 + pand mm3, mm1 + pand mm0, mm6 + pand mm1, mm6 + + psubw mm3, mm2 + psubw mm1, mm0 + + pmulhw mm3, mm4 + pmulhw mm1, mm4 + + psubw mm0, mm1 + psubw mm2, mm3 + + pand mm0, mm6 + pand mm2, mm7 + + paddw mm0, mm2 + + movd esi, mm0 + mov [edx+eax+6], si + add eax,2 + jne .odd + +.noodd: + emms + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX +_vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX: + push ebp + push edi + push esi + push ebx + + mov edx, [esp+4+16] + + mov ebx, [edx+VDPixmapReferenceStretchBltBilinearParameters.src] + mov edi, [edx+VDPixmapReferenceStretchBltBilinearParameters.dst] + + mov ecx, [edx+VDPixmapReferenceStretchBltBilinearParameters.xprecopy] + or ecx, ecx + jz .noprecopy + mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.xprepos] + mov eax, [ebx+eax] + lea ebp, [ecx*4] + sub edi, ebp + rep stosd +.noprecopy: + mov ebp, [edx+VDPixmapReferenceStretchBltBilinearParameters.xmidsize] + add ebp, ebp + add ebp, ebp + add edi, ebp + neg ebp + + mov esi, [edx+VDPixmapReferenceStretchBltBilinearParameters.u] + mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.dudx] + mov edx, [edx+VDPixmapReferenceStretchBltBilinearParameters.uinc] + movd mm2, esi + movd mm3, eax + shr ebx, 2 + + movq mm5, mm2 + punpcklwd mm5, mm5 + punpckhdq mm5, mm5 + movq mm4, mm5 + psraw mm4, 15 + +.xloop: + movd mm0, dword [ebx*4] + pxor mm7, mm7 + movd mm1, dword [ebx*4+4] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm1, mm0 + pand mm4, mm1 + pmulhw mm1, mm5 + paddw mm1, mm4 + paddw mm0, mm1 + packuswb mm0, mm0 + movd dword [edi+ebp], mm0 + + add esi, eax + adc ebx, edx + + paddd mm2, mm3 + movq mm5, mm2 + punpcklwd mm5, mm5 + punpckhdq mm5, mm5 + movq mm4, mm5 + psraw mm4, 15 + add ebp, 4 + jnz .xloop + + mov edx, [esp+4+16] + mov ecx, [edx+VDPixmapReferenceStretchBltBilinearParameters.xpostcopy] + or ecx, ecx + jz .nopostcopy + mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.xpostpos] + add eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.src] + mov eax, [eax] + rep stosd +.nopostcopy: + + emms + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX +_vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+20+16] + and eax, 0ff000000h + mov ebx, [esp+8+16] + mov ecx, [esp+12+16] + jz .noreverse + xchg ebx, ecx + js .noreverse + neg eax + xchg ebx, ecx +.noreverse: + shr eax, 16 + mov [esp+20+16], eax + mov edx, [esp+4+16] + mov eax, [esp+16+16] + add eax, eax + add eax, eax + lea ebx, [ebx+eax-4] + lea ecx, [ecx+eax-4] + lea edx, [edx+eax-4] + neg eax + + movd mm4, dword [esp+20+16] + punpcklwd mm4, mm4 + punpckldq mm4, mm4 + + movq mm6, [rb_mask_888] + movq mm7, [g_mask_888] + +.xstart: + add eax, 4 + jbe .doodd +.xloop: + movq mm0, [ebx+eax] + movq mm1, [ecx+eax] + movq mm2, mm0 + movq mm3, mm1 + psrlw mm2, 8 + psrlw mm3, 8 + pand mm0, mm6 + pand mm1, mm6 + + psubw mm3, mm2 + psubw mm1, mm0 + + pmulhw mm3, mm4 + pmulhw mm1, mm4 + + psubw mm0, mm1 + psubw mm2, mm3 + + pand mm0, mm6 + + psllw mm2, 8 + + paddw mm0, mm2 + + movq qword [edx+eax], mm0 + add eax, 8 + jnc .xloop + +.doodd: + sub eax, 4 + jz .noodd +.odd: + movd mm0, dword [ebx] + movd mm1, dword [ecx] + movq mm2, mm0 + movq mm3, mm1 + psrlw mm2, 8 + psrlw mm3, 8 + pand mm0, mm6 + pand mm1, mm6 + + psubw mm3, mm2 + psubw mm1, mm0 + + pmulhw mm3, mm4 + pmulhw mm1, mm4 + + psubw mm0, mm1 + psubw mm2, mm3 + + pand mm0, mm6 + + psllw mm2, 8 + + paddw mm0, mm2 + + movd dword [edx], mm0 + +.noodd: + emms + pop ebx + pop esi + pop edi + pop ebp + ret + + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_point.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_point.asm index dca765b926f..c00de22cb97 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_point.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_point.asm @@ -1,96 +1,96 @@ - segment .text - - struc scaleinfo -.dst resd 1 -.src resd 1 -.xaccum resd 1 -.xfracinc resd 1 -.xintinc resd 1 -.count resd 1 - endstruc - - global _vdasm_resize_point32 -_vdasm_resize_point32: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - - mov ebx, [eax+scaleinfo.xaccum] - mov ecx, [eax+scaleinfo.xfracinc] - mov edx, [eax+scaleinfo.src] - mov esi, [eax+scaleinfo.xintinc] - mov edi, [eax+scaleinfo.dst] - mov ebp, [eax+scaleinfo.count] -.xloop: - mov eax,[edx*4] - add ebx,ecx - adc edx,esi - mov [edi+ebp],eax - add ebp,4 - jne .xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_resize_point32_MMX -_vdasm_resize_point32_MMX: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - - push 0 - push dword [fs:0] - mov dword [fs:0], esp - - mov ebx, [eax+scaleinfo.xaccum] - mov esp, [eax+scaleinfo.xfracinc] - mov edx, [eax+scaleinfo.src] - mov esi, [eax+scaleinfo.xintinc] - mov edi, [eax+scaleinfo.dst] - mov ebp, [eax+scaleinfo.count] - - mov eax, ebx - mov ecx, edx - add ebx, esp - adc edx, esi - add esp, esp - adc esi, esi - - add ebp, 4 - jz .odd -.dualloop: - movd mm0, dword [ecx*4] - punpckldq mm0,[edx*4] - add eax,esp - adc ecx,esi - add ebx,esp - adc edx,esi - movq [edi+ebp-4],mm0 - - add ebp,8 - jnc .dualloop - jnz .noodd -.odd: - mov eax, [ecx*4] - mov [edi-4], eax -.noodd: - mov esp, dword [fs:0] - pop eax - pop eax - - pop ebx - pop esi - pop edi - pop ebp - ret - - end + segment .text + + struc scaleinfo +.dst resd 1 +.src resd 1 +.xaccum resd 1 +.xfracinc resd 1 +.xintinc resd 1 +.count resd 1 + endstruc + + global _vdasm_resize_point32 +_vdasm_resize_point32: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + + mov ebx, [eax+scaleinfo.xaccum] + mov ecx, [eax+scaleinfo.xfracinc] + mov edx, [eax+scaleinfo.src] + mov esi, [eax+scaleinfo.xintinc] + mov edi, [eax+scaleinfo.dst] + mov ebp, [eax+scaleinfo.count] +.xloop: + mov eax,[edx*4] + add ebx,ecx + adc edx,esi + mov [edi+ebp],eax + add ebp,4 + jne .xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_resize_point32_MMX +_vdasm_resize_point32_MMX: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + + push 0 + push dword [fs:0] + mov dword [fs:0], esp + + mov ebx, [eax+scaleinfo.xaccum] + mov esp, [eax+scaleinfo.xfracinc] + mov edx, [eax+scaleinfo.src] + mov esi, [eax+scaleinfo.xintinc] + mov edi, [eax+scaleinfo.dst] + mov ebp, [eax+scaleinfo.count] + + mov eax, ebx + mov ecx, edx + add ebx, esp + adc edx, esi + add esp, esp + adc esi, esi + + add ebp, 4 + jz .odd +.dualloop: + movd mm0, dword [ecx*4] + punpckldq mm0,[edx*4] + add eax,esp + adc ecx,esi + add ebx,esp + adc edx,esi + movq [edi+ebp-4],mm0 + + add ebp,8 + jnc .dualloop + jnz .noodd +.odd: + mov eax, [ecx*4] + mov [edi-4], eax +.noodd: + mov esp, dword [fs:0] + pop eax + pop eax + + pop ebx + pop esi + pop edi + pop ebp + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt.inc b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt.inc index fb969c56fca..dbeb5505890 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt.inc +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt.inc @@ -1,24 +1,24 @@ - struc span -.u resd 1 -.v resd 1 - endstruc - - struc mipspan -.u resd 1 -.v resd 1 -.lambda resd 1 - endstruc - - struc mipmap -.bits resd 1 -.pitch resd 1 -.uvmul resd 1 - resd 1 - endstruc - - struc texinfo -.mips resd 16*4 -.dst resd 1 -.src resd 1 -.w resd 1 - endstruc + struc span +.u resd 1 +.v resd 1 + endstruc + + struc mipspan +.u resd 1 +.v resd 1 +.lambda resd 1 + endstruc + + struc mipmap +.bits resd 1 +.pitch resd 1 +.uvmul resd 1 + resd 1 + endstruc + + struc texinfo +.mips resd 16*4 +.dst resd 1 +.src resd 1 +.w resd 1 + endstruc diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_mmx.asm index 3836488aa79..82a55d6a484 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_mmx.asm @@ -1,425 +1,425 @@ - segment .rdata, align=16 - -correct dq 0000800000008000h -round dq 0000200000002000h -round1 dq 0000020000000200h -round2 dq 0002000000020000h - - segment .text - - %include "a_triblt.inc" - - extern _kVDCubicInterpTableFX14_075_MMX - -;-------------------------------------------------------------------------- - global _vdasm_triblt_span_bilinear_mmx -_vdasm_triblt_span_bilinear_mmx: - push ebp - push edi - push esi - push ebx - mov edi,[esp+4+16] - mov edx,[edi+texinfo.dst] - mov ebp,[edi+texinfo.w] - shl ebp,2 - mov ebx,[edi+texinfo.mips+mipmap.bits] - add edx,ebp - mov esi,[edi+texinfo.mips+mipmap.pitch] - neg ebp - movd mm6,[edi+texinfo.mips+mipmap.uvmul] - pxor mm7,mm7 - mov edi,[edi+texinfo.src] -.xloop: - movq mm4,[edi] - movq mm0,mm4 - psrld mm0,16 - movq mm5,mm4 - packssdw mm0,mm0 - pmaddwd mm0,mm6 - add edi,8 - punpcklwd mm4,mm4 - punpckldq mm4,mm4 - movd ecx,mm0 - add ecx,ebx - psrlw mm4,1 - movd mm0,dword [ecx] - movd mm1,dword [ecx+4] - punpcklbw mm0,mm7 - movd mm2,dword [ecx+esi] - punpcklbw mm1,mm7 - movd mm3,dword [ecx+esi+4] - punpcklbw mm2,mm7 - punpcklbw mm3,mm7 - psubw mm1,mm0 - psubw mm3,mm2 - paddw mm1,mm1 - paddw mm3,mm3 - pmulhw mm1,mm4 - pmulhw mm3,mm4 - punpckhwd mm5,mm5 - punpckldq mm5,mm5 - paddw mm0,mm1 - psrlw mm5,1 - paddw mm2,mm3 - psubw mm2,mm0 - paddw mm2,mm2 - pmulhw mm2,mm5 - paddw mm0,mm2 - packuswb mm0,mm0 - movd dword [edx+ebp],mm0 - add ebp,4 - jnc .xloop - pop ebx - pop esi - pop edi - pop ebp - emms - ret - -;-------------------------------------------------------------------------- - global _vdasm_triblt_span_trilinear_mmx -_vdasm_triblt_span_trilinear_mmx: - push ebp - push edi - push esi - push ebx - mov esi,[esp+4+16] - mov edx,[esi+texinfo.dst] - mov ebp,[esi+texinfo.w] - shl ebp,2 - add edx,ebp - neg ebp - mov edi,[esi+texinfo.src] - pxor mm7,mm7 -.xloop: - movd mm6,[edi+mipspan.u] - punpckldq mm6,[edi+mipspan.v] - mov eax,[edi+mipspan.lambda] - shr eax,4 - and eax,byte -16 - movd mm2,eax - psrlq mm2,4 - psrld mm6,mm2 - paddd mm6,[correct] - - ;fetch mipmap 1 - mov ebx,[esi+eax+mipmap.pitch] - movd mm1,[esi+eax+mipmap.uvmul] - movq mm4,mm6 - movq mm0,mm6 - psrld mm0,16 - packssdw mm0,mm0 - pmaddwd mm0,mm1 - movq mm5,mm4 - punpcklwd mm4,mm4 - punpckldq mm4,mm4 - punpckhwd mm5,mm5 - punpckldq mm5,mm5 - movd ecx,mm0 - add ecx,[esi+eax+mipmap.bits] - psrlw mm4,1 - movd mm0,dword [ecx] - movd mm1,dword [ecx+4] - punpcklbw mm0,mm7 - movd mm2,dword [ecx+ebx] - punpcklbw mm1,mm7 - movd mm3,dword [ecx+ebx+4] - punpcklbw mm2,mm7 - punpcklbw mm3,mm7 - psubw mm1,mm0 - psubw mm3,mm2 - paddw mm1,mm1 - paddw mm3,mm3 - pmulhw mm1,mm4 - pmulhw mm3,mm4 - paddw mm0,mm1 - psrlw mm5,1 - paddw mm2,mm3 - psubw mm2,mm0 - paddw mm2,mm2 - pmulhw mm2,mm5 - paddw mm0,mm2 - - ;fetch mipmap 2 - mov ebx,[esi+eax+16+mipmap.pitch] - movd mm1,[esi+eax+16+mipmap.uvmul] - paddd mm6,[correct] - psrld mm6,1 - movq mm4,mm6 - psrld mm6,16 - packssdw mm6,mm6 - pmaddwd mm6,mm1 - movq mm5,mm4 - punpcklwd mm4,mm4 - punpckldq mm4,mm4 - punpckhwd mm5,mm5 - punpckldq mm5,mm5 - movd ecx,mm6 - add ecx,[esi+eax+16+mipmap.bits] - psrlw mm4,1 - movd mm6,dword [ecx] - movd mm1,dword [ecx+4] - punpcklbw mm6,mm7 - movd mm2,dword [ecx+ebx] - punpcklbw mm1,mm7 - movd mm3,dword [ecx+ebx+4] - punpcklbw mm2,mm7 - punpcklbw mm3,mm7 - psubw mm1,mm6 - psubw mm3,mm2 - paddw mm1,mm1 - paddw mm3,mm3 - pmulhw mm1,mm4 - pmulhw mm3,mm4 - paddw mm6,mm1 - psrlw mm5,1 - paddw mm2,mm3 - psubw mm2,mm6 - paddw mm2,mm2 - pmulhw mm2,mm5 - paddw mm6,mm2 - - ;blend mips - movd mm1,[edi+mipspan.lambda] - punpcklwd mm1,mm1 - punpckldq mm1,mm1 - psllw mm1,8 - psrlq mm1,1 - psubw mm6,mm0 - paddw mm6,mm6 - pmulhw mm6,mm1 - paddw mm0,mm6 - packuswb mm0,mm0 - - movd dword [edx+ebp],mm0 - add edi, mipspan_size - add ebp,4 - jnc .xloop - pop ebx - pop esi - pop edi - pop ebp - emms - ret - -;-------------------------------------------------------------------------- -%macro .SETUPADDR 1 - ;compute mipmap index and UV - movd mm0, [edi + mipspan.u] - punpckldq mm0, [edi + mipspan.v] - mov ebx, [edi + mipspan.lambda] - shr ebx, 4 - and ebx, byte -16 - - add ebx, mipmap_size*%1 - movd mm2, ebx - add ebx, [esp + .af_mipbase] - psrlq mm2, 4 - psrad mm0, mm2 - paddd mm0, [correct] - movq mm1, mm0 - psrlq mm1, 32 - - ;compute horizontal filters - movd ecx, mm0 - shr ecx, 4 - and ecx, 0ff0h - add ecx, _kVDCubicInterpTableFX14_075_MMX - - ;compute vertical filter - movd edx, mm1 - and edx, 0ff00h - shr edx, 4 - add edx, _kVDCubicInterpTableFX14_075_MMX - - ;compute texel address - movd mm1, [ebx + mipmap.uvmul] - psrld mm0, 16 - packssdw mm0, mm0 - pmaddwd mm0, mm1 - movd eax, mm0 - add eax, [ebx + mipmap.bits] -%endmacro - -%macro .HCUBIC 4 - movd %1, dword [eax] - punpcklbw %1, qword [eax+4] - movd %3, dword [eax+8] - punpcklbw %3, qword [eax+12] - movq %2, %1 - movq %4, %3 - punpcklbw %1, mm7 - pmaddwd %1, [ecx] - punpcklbw %3, mm7 - pmaddwd %3, [ecx+8] - punpckhbw %2, mm7 - pmaddwd %2, [ecx] - punpckhbw %4, mm7 - pmaddwd %4, [ecx+8] - paddd %1, %3 - paddd %2, %4 -%endmacro - -%macro .VCUBIC 1 - .HCUBIC mm0, mm1, mm2, mm3 - add eax, %1 - - .HCUBIC mm4, mm5, mm2, mm3 - add eax, %1 - - movq mm2, [round1] - - paddd mm0, mm2 - paddd mm1, mm2 - paddd mm4, mm2 - paddd mm5, mm2 - - psrad mm0, 10 - psrad mm1, 10 - psrad mm4, 10 - psrad mm5, 10 - - packssdw mm0, mm0 - packssdw mm1, mm1 - packssdw mm4, mm4 - packssdw mm5, mm5 - - punpcklwd mm0, mm4 - punpcklwd mm1, mm5 - - movq mm3, [edx] - - pmaddwd mm0, mm3 - pmaddwd mm1, mm3 - - movq [esp + .af_htemp0], mm0 - movq [esp + .af_htemp1], mm1 - - .HCUBIC mm0, mm1, mm2, mm3 - add eax, %1 - .HCUBIC mm4, mm5, mm2, mm3 - - movq mm2, [round1] - - paddd mm0, mm2 - paddd mm1, mm2 - paddd mm4, mm2 - paddd mm5, mm2 - - psrad mm0, 10 - psrad mm1, 10 - psrad mm4, 10 - psrad mm5, 10 - - packssdw mm0, mm0 - packssdw mm1, mm1 - packssdw mm4, mm4 - packssdw mm5, mm5 - - punpcklwd mm0, mm4 - punpcklwd mm1, mm5 - - movq mm2, [round2] - movq mm3, [edx + 8] - - pmaddwd mm0, mm3 - pmaddwd mm1, mm3 - - paddd mm0, [esp + .af_htemp0] - paddd mm1, [esp + .af_htemp1] - - paddd mm0, mm2 - paddd mm1, mm2 - - psrad mm0, 18 - psrad mm1, 18 - packssdw mm0, mm1 -%endmacro - - global _vdasm_triblt_span_bicubic_mip_linear_mmx -_vdasm_triblt_span_bicubic_mip_linear_mmx: - -;parameters -%define .p_texinfo 20 - -;aligned frame -%define .af_htemp0 0 -%define .af_htemp1 8 -%define .af_vtemp0 16 -%define .af_mipbase 24 -%define .af_prevesp 28 -%define .afsize 32 - - push ebp - lea ebp, [esp-12] - push edi - push esi - push ebx - - sub esp, .afsize - and esp, -8 - - mov [esp + .af_prevesp], ebp - - mov ebx, [ebp + .p_texinfo] - mov ebp, [ebx + texinfo.dst] - mov esi, [ebx + texinfo.w] - shl esi, 2 - add ebp,esi - neg esi - - mov edi, [ebx + texinfo.src] - mov [esp + .af_mipbase], ebx - pxor mm7, mm7 - -.xloop: - - ;registers: - ; eax base texel address - ; ebx first mip info - ; ecx horizontal filter - ; edx vertical filter - ; esi horizontal count - ; edi mipspan - ; ebp destination - - ;fetch mipmap 1 - .SETUPADDR 0 - .VCUBIC [ebx+mipmap.pitch] - - movq [esp + .af_vtemp0], mm0 - - ;fetch mipmap 2 - .SETUPADDR 1 - .VCUBIC [ebx+mipmap.pitch] - - ;blend mips - movq mm1, [esp + .af_vtemp0] - - psubw mm0, mm1 - - movd mm3,[edi+mipspan.lambda] - punpcklwd mm3,mm3 - punpckldq mm3,mm3 - psllw mm3,8 - psrlq mm3,1 - - paddw mm0,mm0 - pmulhw mm0,mm3 - paddw mm0,mm1 - packuswb mm0,mm0 - - movd dword [ebp+esi],mm0 - add edi, mipspan_size - add esi,4 - jnc .xloop - - mov esp, [esp + .af_prevesp] - pop ebx - pop esi - pop edi - pop ebp - emms - ret - - end + segment .rdata, align=16 + +correct dq 0000800000008000h +round dq 0000200000002000h +round1 dq 0000020000000200h +round2 dq 0002000000020000h + + segment .text + + %include "a_triblt.inc" + + extern _kVDCubicInterpTableFX14_075_MMX + +;-------------------------------------------------------------------------- + global _vdasm_triblt_span_bilinear_mmx +_vdasm_triblt_span_bilinear_mmx: + push ebp + push edi + push esi + push ebx + mov edi,[esp+4+16] + mov edx,[edi+texinfo.dst] + mov ebp,[edi+texinfo.w] + shl ebp,2 + mov ebx,[edi+texinfo.mips+mipmap.bits] + add edx,ebp + mov esi,[edi+texinfo.mips+mipmap.pitch] + neg ebp + movd mm6,[edi+texinfo.mips+mipmap.uvmul] + pxor mm7,mm7 + mov edi,[edi+texinfo.src] +.xloop: + movq mm4,[edi] + movq mm0,mm4 + psrld mm0,16 + movq mm5,mm4 + packssdw mm0,mm0 + pmaddwd mm0,mm6 + add edi,8 + punpcklwd mm4,mm4 + punpckldq mm4,mm4 + movd ecx,mm0 + add ecx,ebx + psrlw mm4,1 + movd mm0,dword [ecx] + movd mm1,dword [ecx+4] + punpcklbw mm0,mm7 + movd mm2,dword [ecx+esi] + punpcklbw mm1,mm7 + movd mm3,dword [ecx+esi+4] + punpcklbw mm2,mm7 + punpcklbw mm3,mm7 + psubw mm1,mm0 + psubw mm3,mm2 + paddw mm1,mm1 + paddw mm3,mm3 + pmulhw mm1,mm4 + pmulhw mm3,mm4 + punpckhwd mm5,mm5 + punpckldq mm5,mm5 + paddw mm0,mm1 + psrlw mm5,1 + paddw mm2,mm3 + psubw mm2,mm0 + paddw mm2,mm2 + pmulhw mm2,mm5 + paddw mm0,mm2 + packuswb mm0,mm0 + movd dword [edx+ebp],mm0 + add ebp,4 + jnc .xloop + pop ebx + pop esi + pop edi + pop ebp + emms + ret + +;-------------------------------------------------------------------------- + global _vdasm_triblt_span_trilinear_mmx +_vdasm_triblt_span_trilinear_mmx: + push ebp + push edi + push esi + push ebx + mov esi,[esp+4+16] + mov edx,[esi+texinfo.dst] + mov ebp,[esi+texinfo.w] + shl ebp,2 + add edx,ebp + neg ebp + mov edi,[esi+texinfo.src] + pxor mm7,mm7 +.xloop: + movd mm6,[edi+mipspan.u] + punpckldq mm6,[edi+mipspan.v] + mov eax,[edi+mipspan.lambda] + shr eax,4 + and eax,byte -16 + movd mm2,eax + psrlq mm2,4 + psrld mm6,mm2 + paddd mm6,[correct] + + ;fetch mipmap 1 + mov ebx,[esi+eax+mipmap.pitch] + movd mm1,[esi+eax+mipmap.uvmul] + movq mm4,mm6 + movq mm0,mm6 + psrld mm0,16 + packssdw mm0,mm0 + pmaddwd mm0,mm1 + movq mm5,mm4 + punpcklwd mm4,mm4 + punpckldq mm4,mm4 + punpckhwd mm5,mm5 + punpckldq mm5,mm5 + movd ecx,mm0 + add ecx,[esi+eax+mipmap.bits] + psrlw mm4,1 + movd mm0,dword [ecx] + movd mm1,dword [ecx+4] + punpcklbw mm0,mm7 + movd mm2,dword [ecx+ebx] + punpcklbw mm1,mm7 + movd mm3,dword [ecx+ebx+4] + punpcklbw mm2,mm7 + punpcklbw mm3,mm7 + psubw mm1,mm0 + psubw mm3,mm2 + paddw mm1,mm1 + paddw mm3,mm3 + pmulhw mm1,mm4 + pmulhw mm3,mm4 + paddw mm0,mm1 + psrlw mm5,1 + paddw mm2,mm3 + psubw mm2,mm0 + paddw mm2,mm2 + pmulhw mm2,mm5 + paddw mm0,mm2 + + ;fetch mipmap 2 + mov ebx,[esi+eax+16+mipmap.pitch] + movd mm1,[esi+eax+16+mipmap.uvmul] + paddd mm6,[correct] + psrld mm6,1 + movq mm4,mm6 + psrld mm6,16 + packssdw mm6,mm6 + pmaddwd mm6,mm1 + movq mm5,mm4 + punpcklwd mm4,mm4 + punpckldq mm4,mm4 + punpckhwd mm5,mm5 + punpckldq mm5,mm5 + movd ecx,mm6 + add ecx,[esi+eax+16+mipmap.bits] + psrlw mm4,1 + movd mm6,dword [ecx] + movd mm1,dword [ecx+4] + punpcklbw mm6,mm7 + movd mm2,dword [ecx+ebx] + punpcklbw mm1,mm7 + movd mm3,dword [ecx+ebx+4] + punpcklbw mm2,mm7 + punpcklbw mm3,mm7 + psubw mm1,mm6 + psubw mm3,mm2 + paddw mm1,mm1 + paddw mm3,mm3 + pmulhw mm1,mm4 + pmulhw mm3,mm4 + paddw mm6,mm1 + psrlw mm5,1 + paddw mm2,mm3 + psubw mm2,mm6 + paddw mm2,mm2 + pmulhw mm2,mm5 + paddw mm6,mm2 + + ;blend mips + movd mm1,[edi+mipspan.lambda] + punpcklwd mm1,mm1 + punpckldq mm1,mm1 + psllw mm1,8 + psrlq mm1,1 + psubw mm6,mm0 + paddw mm6,mm6 + pmulhw mm6,mm1 + paddw mm0,mm6 + packuswb mm0,mm0 + + movd dword [edx+ebp],mm0 + add edi, mipspan_size + add ebp,4 + jnc .xloop + pop ebx + pop esi + pop edi + pop ebp + emms + ret + +;-------------------------------------------------------------------------- +%macro .SETUPADDR 1 + ;compute mipmap index and UV + movd mm0, [edi + mipspan.u] + punpckldq mm0, [edi + mipspan.v] + mov ebx, [edi + mipspan.lambda] + shr ebx, 4 + and ebx, byte -16 + + add ebx, mipmap_size*%1 + movd mm2, ebx + add ebx, [esp + .af_mipbase] + psrlq mm2, 4 + psrad mm0, mm2 + paddd mm0, [correct] + movq mm1, mm0 + psrlq mm1, 32 + + ;compute horizontal filters + movd ecx, mm0 + shr ecx, 4 + and ecx, 0ff0h + add ecx, _kVDCubicInterpTableFX14_075_MMX + + ;compute vertical filter + movd edx, mm1 + and edx, 0ff00h + shr edx, 4 + add edx, _kVDCubicInterpTableFX14_075_MMX + + ;compute texel address + movd mm1, [ebx + mipmap.uvmul] + psrld mm0, 16 + packssdw mm0, mm0 + pmaddwd mm0, mm1 + movd eax, mm0 + add eax, [ebx + mipmap.bits] +%endmacro + +%macro .HCUBIC 4 + movd %1, dword [eax] + punpcklbw %1, qword [eax+4] + movd %3, dword [eax+8] + punpcklbw %3, qword [eax+12] + movq %2, %1 + movq %4, %3 + punpcklbw %1, mm7 + pmaddwd %1, [ecx] + punpcklbw %3, mm7 + pmaddwd %3, [ecx+8] + punpckhbw %2, mm7 + pmaddwd %2, [ecx] + punpckhbw %4, mm7 + pmaddwd %4, [ecx+8] + paddd %1, %3 + paddd %2, %4 +%endmacro + +%macro .VCUBIC 1 + .HCUBIC mm0, mm1, mm2, mm3 + add eax, %1 + + .HCUBIC mm4, mm5, mm2, mm3 + add eax, %1 + + movq mm2, [round1] + + paddd mm0, mm2 + paddd mm1, mm2 + paddd mm4, mm2 + paddd mm5, mm2 + + psrad mm0, 10 + psrad mm1, 10 + psrad mm4, 10 + psrad mm5, 10 + + packssdw mm0, mm0 + packssdw mm1, mm1 + packssdw mm4, mm4 + packssdw mm5, mm5 + + punpcklwd mm0, mm4 + punpcklwd mm1, mm5 + + movq mm3, [edx] + + pmaddwd mm0, mm3 + pmaddwd mm1, mm3 + + movq [esp + .af_htemp0], mm0 + movq [esp + .af_htemp1], mm1 + + .HCUBIC mm0, mm1, mm2, mm3 + add eax, %1 + .HCUBIC mm4, mm5, mm2, mm3 + + movq mm2, [round1] + + paddd mm0, mm2 + paddd mm1, mm2 + paddd mm4, mm2 + paddd mm5, mm2 + + psrad mm0, 10 + psrad mm1, 10 + psrad mm4, 10 + psrad mm5, 10 + + packssdw mm0, mm0 + packssdw mm1, mm1 + packssdw mm4, mm4 + packssdw mm5, mm5 + + punpcklwd mm0, mm4 + punpcklwd mm1, mm5 + + movq mm2, [round2] + movq mm3, [edx + 8] + + pmaddwd mm0, mm3 + pmaddwd mm1, mm3 + + paddd mm0, [esp + .af_htemp0] + paddd mm1, [esp + .af_htemp1] + + paddd mm0, mm2 + paddd mm1, mm2 + + psrad mm0, 18 + psrad mm1, 18 + packssdw mm0, mm1 +%endmacro + + global _vdasm_triblt_span_bicubic_mip_linear_mmx +_vdasm_triblt_span_bicubic_mip_linear_mmx: + +;parameters +%define .p_texinfo 20 + +;aligned frame +%define .af_htemp0 0 +%define .af_htemp1 8 +%define .af_vtemp0 16 +%define .af_mipbase 24 +%define .af_prevesp 28 +%define .afsize 32 + + push ebp + lea ebp, [esp-12] + push edi + push esi + push ebx + + sub esp, .afsize + and esp, -8 + + mov [esp + .af_prevesp], ebp + + mov ebx, [ebp + .p_texinfo] + mov ebp, [ebx + texinfo.dst] + mov esi, [ebx + texinfo.w] + shl esi, 2 + add ebp,esi + neg esi + + mov edi, [ebx + texinfo.src] + mov [esp + .af_mipbase], ebx + pxor mm7, mm7 + +.xloop: + + ;registers: + ; eax base texel address + ; ebx first mip info + ; ecx horizontal filter + ; edx vertical filter + ; esi horizontal count + ; edi mipspan + ; ebp destination + + ;fetch mipmap 1 + .SETUPADDR 0 + .VCUBIC [ebx+mipmap.pitch] + + movq [esp + .af_vtemp0], mm0 + + ;fetch mipmap 2 + .SETUPADDR 1 + .VCUBIC [ebx+mipmap.pitch] + + ;blend mips + movq mm1, [esp + .af_vtemp0] + + psubw mm0, mm1 + + movd mm3,[edi+mipspan.lambda] + punpcklwd mm3,mm3 + punpckldq mm3,mm3 + psllw mm3,8 + psrlq mm3,1 + + paddw mm0,mm0 + pmulhw mm0,mm3 + paddw mm0,mm1 + packuswb mm0,mm0 + + movd dword [ebp+esi],mm0 + add edi, mipspan_size + add esi,4 + jnc .xloop + + mov esp, [esp + .af_prevesp] + pop ebx + pop esi + pop edi + pop ebp + emms + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_scalar.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_scalar.asm index 71e17802801..f364aa9e832 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_scalar.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_scalar.asm @@ -1,36 +1,36 @@ - segment .text - - %include "a_triblt.inc" - - global _vdasm_triblt_span_point -_vdasm_triblt_span_point: - push ebp - push edi - push esi - push ebx - mov eax,[esp+4+16] - mov ebp,[eax+texinfo.w] - mov ebx,[eax+texinfo.mips+mipmap.pitch] - shl ebp,2 - mov edi,[eax+texinfo.src] - mov edx,[eax+texinfo.dst] - mov ecx,[eax+texinfo.mips+mipmap.bits] - sar ebx,2 - add edx,ebp - neg ebp -.xloop: - mov eax,[edi+span.v] - imul eax,ebx - add eax,[edi+span.u] - add edi,8 - mov eax,[ecx+eax*4] - mov [edx+ebp],eax - add ebp,4 - jnc .xloop - pop ebx - pop esi - pop edi - pop ebp - ret - + segment .text + + %include "a_triblt.inc" + + global _vdasm_triblt_span_point +_vdasm_triblt_span_point: + push ebp + push edi + push esi + push ebx + mov eax,[esp+4+16] + mov ebp,[eax+texinfo.w] + mov ebx,[eax+texinfo.mips+mipmap.pitch] + shl ebp,2 + mov edi,[eax+texinfo.src] + mov edx,[eax+texinfo.dst] + mov ecx,[eax+texinfo.mips+mipmap.bits] + sar ebx,2 + add edx,ebp + neg ebp +.xloop: + mov eax,[edi+span.v] + imul eax,ebx + add eax,[edi+span.u] + add edi,8 + mov eax,[ecx+eax*4] + mov [edx+ebp],eax + add ebp,4 + jnc .xloop + pop ebx + pop esi + pop edi + pop ebp + ret + end \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_sse2.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_sse2.asm index 54514b31780..94136757f5f 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_sse2.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_sse2.asm @@ -1,197 +1,197 @@ - segment .rdata, align=16 - -correct dq 0000800000008000h, 0000800000008000h -round dq 0000200000002000h, 0000200000002000h -round1 dq 0000020000000200h, 0000020000000200h -round2 dq 0002000000020000h, 0002000000020000h - - segment .text - - %include "a_triblt.inc" - - extern _kVDCubicInterpTableFX14_075_MMX - -;-------------------------------------------------------------------------- - global _vdasm_triblt_span_bicubic_mip_linear_sse2 -_vdasm_triblt_span_bicubic_mip_linear_sse2: - -;parameters -%define .p_texinfo 20 - -;aligned frame -%define .af_vtemp0 0 -%define .af_mipbase 16 -%define .af_prevesp 20 -%define .afsize 24 - - push ebp - lea ebp, [esp-12] - push edi - push esi - push ebx - - sub esp, .afsize - and esp, -16 - - mov [esp + .af_prevesp], ebp - - mov ebx, [ebp + .p_texinfo] - mov ebp, [ebx + texinfo.dst] - mov esi, [ebx + texinfo.w] - shl esi, 2 - add ebp,esi - neg esi - - mov edi, [ebx + texinfo.src] - mov [esp + .af_mipbase], ebx - pxor xmm7, xmm7 - -.xloop: - - ;registers: - ; eax base texel address - ; ebx first mip info - ; ecx horizontal filter - ; edx vertical filter - ; esi horizontal count - ; edi mipspan - ; ebp destination - -%macro .SETUPADDR 1 - ;compute mipmap index and UV - movd xmm0, [edi + mipspan.u] - movd xmm1, [edi + mipspan.v] - punpckldq xmm0, xmm1 - mov ebx, [edi + mipspan.lambda] - shr ebx, 4 - and ebx, byte -16 - - add ebx, mipmap_size*%1 - movd xmm2, ebx - add ebx, [esp + .af_mipbase] - psrlq xmm2, 4 - psrad xmm0, xmm2 - paddd xmm0, [correct] - pshufd xmm1, xmm0, 01010101b - - ;compute horizontal filters - movd ecx, xmm0 - shr ecx, 4 - and ecx, 0ff0h - add ecx, _kVDCubicInterpTableFX14_075_MMX - - ;compute vertical filter - movd edx, xmm1 - and edx, 0ff00h - shr edx, 4 - add edx, _kVDCubicInterpTableFX14_075_MMX - - ;compute texel address - movd xmm1, [ebx + mipmap.uvmul] - psrld xmm0, 16 - packssdw xmm0, xmm0 - pmaddwd xmm0, xmm1 - movd eax, xmm0 - add eax, [ebx + mipmap.bits] -%endmacro - -%macro .HCUBIC 4 - movd %1, dword [eax] - movd %3, dword [eax+4] - movd %2, dword [eax+8] - movd %4, dword [eax+12] - punpcklbw %1, %3 - punpcklbw %2, %4 - punpcklbw %1, xmm7 - punpcklbw %2, xmm7 - movdqa %3, [ecx] - pshufd %4, %3, 11101110b - pshufd %3, %3, 01000100b - pmaddwd %1, %3 - pmaddwd %2, %4 - paddd %1, %2 -%endmacro - -%macro .VCUBIC 1 - .HCUBIC xmm0, xmm4, xmm5, xmm6 - add eax, %1 - .HCUBIC xmm1, xmm4, xmm5, xmm6 - add eax, %1 - .HCUBIC xmm2, xmm4, xmm5, xmm6 - add eax, %1 - .HCUBIC xmm3, xmm4, xmm5, xmm6 - - movq xmm4, [round1] - - paddd xmm0, xmm4 - - paddd xmm1, xmm4 - psrad xmm0, 10 - - paddd xmm2, xmm4 - psrad xmm1, 10 - packssdw xmm0, xmm0 - - paddd xmm3, xmm4 - psrad xmm2, 10 - packssdw xmm1, xmm1 - - movdqa xmm5, [edx] - psrad xmm3, 10 - punpcklwd xmm0, xmm1 - - packssdw xmm2, xmm2 - packssdw xmm3, xmm3 - pshufd xmm4, xmm5, 01000100b - - pmaddwd xmm0, xmm4 - punpcklwd xmm2, xmm3 - - pshufd xmm5, xmm5, 11101110b - - pmaddwd xmm2, xmm5 - paddd xmm0, xmm2 - paddd xmm0, [round2] - psrad xmm0, 18 - - packssdw xmm0, xmm0 -%endmacro - - ;fetch mipmap 1 - .SETUPADDR 0 - .VCUBIC [ebx+mipmap.pitch] - - movq [esp + .af_vtemp0], xmm0 - - ;fetch mipmap 2 - .SETUPADDR 1 - .VCUBIC [ebx+mipmap.pitch] - - ;blend mips - movq xmm1, [esp + .af_vtemp0] - - psubw xmm0, xmm1 - - movd xmm3, [edi+mipspan.lambda] - pshuflw xmm3, xmm3, 0 - psllw xmm3, 8 - psrlq xmm3, 1 - - paddw xmm0, xmm0 - pmulhw xmm0, xmm3 - paddw xmm0, xmm1 - packuswb xmm0, xmm0 - - movd dword [ebp+esi], xmm0 - add edi, mipspan_size - add esi,4 - jnc .xloop - - mov esp, [esp + .af_prevesp] - pop ebx - pop esi - pop edi - pop ebp - ret - - end + segment .rdata, align=16 + +correct dq 0000800000008000h, 0000800000008000h +round dq 0000200000002000h, 0000200000002000h +round1 dq 0000020000000200h, 0000020000000200h +round2 dq 0002000000020000h, 0002000000020000h + + segment .text + + %include "a_triblt.inc" + + extern _kVDCubicInterpTableFX14_075_MMX + +;-------------------------------------------------------------------------- + global _vdasm_triblt_span_bicubic_mip_linear_sse2 +_vdasm_triblt_span_bicubic_mip_linear_sse2: + +;parameters +%define .p_texinfo 20 + +;aligned frame +%define .af_vtemp0 0 +%define .af_mipbase 16 +%define .af_prevesp 20 +%define .afsize 24 + + push ebp + lea ebp, [esp-12] + push edi + push esi + push ebx + + sub esp, .afsize + and esp, -16 + + mov [esp + .af_prevesp], ebp + + mov ebx, [ebp + .p_texinfo] + mov ebp, [ebx + texinfo.dst] + mov esi, [ebx + texinfo.w] + shl esi, 2 + add ebp,esi + neg esi + + mov edi, [ebx + texinfo.src] + mov [esp + .af_mipbase], ebx + pxor xmm7, xmm7 + +.xloop: + + ;registers: + ; eax base texel address + ; ebx first mip info + ; ecx horizontal filter + ; edx vertical filter + ; esi horizontal count + ; edi mipspan + ; ebp destination + +%macro .SETUPADDR 1 + ;compute mipmap index and UV + movd xmm0, [edi + mipspan.u] + movd xmm1, [edi + mipspan.v] + punpckldq xmm0, xmm1 + mov ebx, [edi + mipspan.lambda] + shr ebx, 4 + and ebx, byte -16 + + add ebx, mipmap_size*%1 + movd xmm2, ebx + add ebx, [esp + .af_mipbase] + psrlq xmm2, 4 + psrad xmm0, xmm2 + paddd xmm0, [correct] + pshufd xmm1, xmm0, 01010101b + + ;compute horizontal filters + movd ecx, xmm0 + shr ecx, 4 + and ecx, 0ff0h + add ecx, _kVDCubicInterpTableFX14_075_MMX + + ;compute vertical filter + movd edx, xmm1 + and edx, 0ff00h + shr edx, 4 + add edx, _kVDCubicInterpTableFX14_075_MMX + + ;compute texel address + movd xmm1, [ebx + mipmap.uvmul] + psrld xmm0, 16 + packssdw xmm0, xmm0 + pmaddwd xmm0, xmm1 + movd eax, xmm0 + add eax, [ebx + mipmap.bits] +%endmacro + +%macro .HCUBIC 4 + movd %1, dword [eax] + movd %3, dword [eax+4] + movd %2, dword [eax+8] + movd %4, dword [eax+12] + punpcklbw %1, %3 + punpcklbw %2, %4 + punpcklbw %1, xmm7 + punpcklbw %2, xmm7 + movdqa %3, [ecx] + pshufd %4, %3, 11101110b + pshufd %3, %3, 01000100b + pmaddwd %1, %3 + pmaddwd %2, %4 + paddd %1, %2 +%endmacro + +%macro .VCUBIC 1 + .HCUBIC xmm0, xmm4, xmm5, xmm6 + add eax, %1 + .HCUBIC xmm1, xmm4, xmm5, xmm6 + add eax, %1 + .HCUBIC xmm2, xmm4, xmm5, xmm6 + add eax, %1 + .HCUBIC xmm3, xmm4, xmm5, xmm6 + + movq xmm4, [round1] + + paddd xmm0, xmm4 + + paddd xmm1, xmm4 + psrad xmm0, 10 + + paddd xmm2, xmm4 + psrad xmm1, 10 + packssdw xmm0, xmm0 + + paddd xmm3, xmm4 + psrad xmm2, 10 + packssdw xmm1, xmm1 + + movdqa xmm5, [edx] + psrad xmm3, 10 + punpcklwd xmm0, xmm1 + + packssdw xmm2, xmm2 + packssdw xmm3, xmm3 + pshufd xmm4, xmm5, 01000100b + + pmaddwd xmm0, xmm4 + punpcklwd xmm2, xmm3 + + pshufd xmm5, xmm5, 11101110b + + pmaddwd xmm2, xmm5 + paddd xmm0, xmm2 + paddd xmm0, [round2] + psrad xmm0, 18 + + packssdw xmm0, xmm0 +%endmacro + + ;fetch mipmap 1 + .SETUPADDR 0 + .VCUBIC [ebx+mipmap.pitch] + + movq [esp + .af_vtemp0], xmm0 + + ;fetch mipmap 2 + .SETUPADDR 1 + .VCUBIC [ebx+mipmap.pitch] + + ;blend mips + movq xmm1, [esp + .af_vtemp0] + + psubw xmm0, xmm1 + + movd xmm3, [edi+mipspan.lambda] + pshuflw xmm3, xmm3, 0 + psllw xmm3, 8 + psrlq xmm3, 1 + + paddw xmm0, xmm0 + pmulhw xmm0, xmm3 + paddw xmm0, xmm1 + packuswb xmm0, xmm0 + + movd dword [ebp+esi], xmm0 + add edi, mipspan_size + add esi,4 + jnc .xloop + + mov esp, [esp + .af_prevesp] + pop ebx + pop esi + pop edi + pop ebp + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/alphablt.cpp b/src/thirdparty/VirtualDub/Kasumi/source/alphablt.cpp index 93501ede4f3..0e2e218613b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/alphablt.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/alphablt.cpp @@ -1,95 +1,95 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include - -void VDPixmapBltAlphaConst8(uint8 *dst, ptrdiff_t dstpitch, const uint8 *src, ptrdiff_t srcpitch, uint32 w, uint32 h, uint32 ialpha); - -bool VDPixmapBltAlphaConst(const VDPixmap& dst, const VDPixmap& src, float alpha) { - if (!(alpha >= 0.0f)) - alpha = 0.0f; - else if (!(alpha <= 1.0f)) - alpha = 1.0f; - - uint32 ialpha = VDRoundToInt32(alpha * 256.0f); - - // format check - if (dst.format != src.format || !src.format) - return false; - - // degenerate case check - if (!dst.w || !dst.h) - return false; - - // size check - if (src.w != dst.w || src.h != dst.h) - return false; - - // check for formats that are not 8bpp - switch(src.format) { - case nsVDPixmap::kPixFormat_Pal1: - case nsVDPixmap::kPixFormat_Pal2: - case nsVDPixmap::kPixFormat_Pal4: - case nsVDPixmap::kPixFormat_Pal8: - case nsVDPixmap::kPixFormat_RGB565: - case nsVDPixmap::kPixFormat_XRGB1555: - return false; - } - - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(src.format); - - const int qw = -(-dst.w >> formatInfo.qwbits); - const int qh = -(-dst.h >> formatInfo.qhbits); - const int auxw = -(-dst.w >> formatInfo.auxwbits); - const int auxh = -(-dst.h >> formatInfo.auxhbits); - - switch(formatInfo.auxbufs) { - case 2: - VDPixmapBltAlphaConst8((uint8 *)dst.data3, dst.pitch3, (const uint8 *)src.data3, src.pitch3, auxw, auxh, ialpha); - case 1: - VDPixmapBltAlphaConst8((uint8 *)dst.data2, dst.pitch2, (const uint8 *)src.data2, src.pitch2, auxw, auxh, ialpha); - case 0: - VDPixmapBltAlphaConst8((uint8 *)dst.data, dst.pitch, (const uint8 *)src.data, src.pitch, formatInfo.qsize * qw, qh, ialpha); - } - - return true; -} - -void VDPixmapBltAlphaConst8(uint8 *dst, ptrdiff_t dstpitch, const uint8 *src, ptrdiff_t srcpitch, uint32 w, uint32 h, uint32 ialpha) { - dstpitch -= w; - srcpitch -= w; - do { - uint32 w2 = w; - do { - sint32 sc = *src; - sint32 dc = *dst; - - *dst = dc + (((sc-dc)*ialpha + 128) >> 8); - ++src; - ++dst; - } while(--w2); - - src += srcpitch; - dst += dstpitch; - } while(--h); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include + +void VDPixmapBltAlphaConst8(uint8 *dst, ptrdiff_t dstpitch, const uint8 *src, ptrdiff_t srcpitch, uint32 w, uint32 h, uint32 ialpha); + +bool VDPixmapBltAlphaConst(const VDPixmap& dst, const VDPixmap& src, float alpha) { + if (!(alpha >= 0.0f)) + alpha = 0.0f; + else if (!(alpha <= 1.0f)) + alpha = 1.0f; + + uint32 ialpha = VDRoundToInt32(alpha * 256.0f); + + // format check + if (dst.format != src.format || !src.format) + return false; + + // degenerate case check + if (!dst.w || !dst.h) + return false; + + // size check + if (src.w != dst.w || src.h != dst.h) + return false; + + // check for formats that are not 8bpp + switch(src.format) { + case nsVDPixmap::kPixFormat_Pal1: + case nsVDPixmap::kPixFormat_Pal2: + case nsVDPixmap::kPixFormat_Pal4: + case nsVDPixmap::kPixFormat_Pal8: + case nsVDPixmap::kPixFormat_RGB565: + case nsVDPixmap::kPixFormat_XRGB1555: + return false; + } + + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(src.format); + + const int qw = -(-dst.w >> formatInfo.qwbits); + const int qh = -(-dst.h >> formatInfo.qhbits); + const int auxw = -(-dst.w >> formatInfo.auxwbits); + const int auxh = -(-dst.h >> formatInfo.auxhbits); + + switch(formatInfo.auxbufs) { + case 2: + VDPixmapBltAlphaConst8((uint8 *)dst.data3, dst.pitch3, (const uint8 *)src.data3, src.pitch3, auxw, auxh, ialpha); + case 1: + VDPixmapBltAlphaConst8((uint8 *)dst.data2, dst.pitch2, (const uint8 *)src.data2, src.pitch2, auxw, auxh, ialpha); + case 0: + VDPixmapBltAlphaConst8((uint8 *)dst.data, dst.pitch, (const uint8 *)src.data, src.pitch, formatInfo.qsize * qw, qh, ialpha); + } + + return true; +} + +void VDPixmapBltAlphaConst8(uint8 *dst, ptrdiff_t dstpitch, const uint8 *src, ptrdiff_t srcpitch, uint32 w, uint32 h, uint32 ialpha) { + dstpitch -= w; + srcpitch -= w; + do { + uint32 w2 = w; + do { + sint32 sc = *src; + sint32 dc = *dst; + + *dst = dc + (((sc-dc)*ialpha + 128) >> 8); + ++src; + ++dst; + } while(--w2); + + src += srcpitch; + dst += dstpitch; + } while(--h); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blitter.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blitter.cpp index 0879424d242..a9542e2584d 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blitter.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blitter.cpp @@ -1,52 +1,52 @@ -#include -#include - -VDPixmapCachedBlitter::VDPixmapCachedBlitter() - : mSrcWidth(0) - , mSrcHeight(0) - , mSrcFormat(0) - , mDstWidth(0) - , mDstHeight(0) - , mDstFormat(0) - , mpCachedBlitter(NULL) -{ -} - -VDPixmapCachedBlitter::~VDPixmapCachedBlitter() { - Invalidate(); -} - -void VDPixmapCachedBlitter::Blit(const VDPixmap& dst, const VDPixmap& src) { - VDASSERT(src.w == dst.w && src.h == dst.h); - - if (!mpCachedBlitter || - dst.w != mDstWidth || - dst.h != mDstHeight || - dst.format != mDstFormat || - src.w != mSrcWidth || - src.h != mSrcHeight || - src.format != mSrcFormat) - { - if (mpCachedBlitter) - delete mpCachedBlitter; - mpCachedBlitter = VDPixmapCreateBlitter(dst, src); - if (!mpCachedBlitter) - return; - - mDstWidth = dst.w; - mDstHeight = dst.h; - mDstFormat = dst.format; - mSrcWidth = src.w; - mSrcHeight = src.h; - mSrcFormat = src.format; - } - - mpCachedBlitter->Blit(dst, src); -} - -void VDPixmapCachedBlitter::Invalidate() { - if (mpCachedBlitter) { - delete mpCachedBlitter; - mpCachedBlitter = NULL; - } -} +#include +#include + +VDPixmapCachedBlitter::VDPixmapCachedBlitter() + : mSrcWidth(0) + , mSrcHeight(0) + , mSrcFormat(0) + , mDstWidth(0) + , mDstHeight(0) + , mDstFormat(0) + , mpCachedBlitter(NULL) +{ +} + +VDPixmapCachedBlitter::~VDPixmapCachedBlitter() { + Invalidate(); +} + +void VDPixmapCachedBlitter::Blit(const VDPixmap& dst, const VDPixmap& src) { + VDASSERT(src.w == dst.w && src.h == dst.h); + + if (!mpCachedBlitter || + dst.w != mDstWidth || + dst.h != mDstHeight || + dst.format != mDstFormat || + src.w != mSrcWidth || + src.h != mSrcHeight || + src.format != mSrcFormat) + { + if (mpCachedBlitter) + delete mpCachedBlitter; + mpCachedBlitter = VDPixmapCreateBlitter(dst, src); + if (!mpCachedBlitter) + return; + + mDstWidth = dst.w; + mDstHeight = dst.h; + mDstFormat = dst.format; + mSrcWidth = src.w; + mSrcHeight = src.h; + mSrcFormat = src.format; + } + + mpCachedBlitter->Blit(dst, src); +} + +void VDPixmapCachedBlitter::Invalidate() { + if (mpCachedBlitter) { + delete mpCachedBlitter; + mpCachedBlitter = NULL; + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt.cpp index 7a3fabea006..a003217bb0f 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt.cpp @@ -1,292 +1,292 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace nsVDPixmap; - -namespace { - typedef void (*tpPalettedBlitter)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal); - typedef void (*tpChunkyBlitter)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); - typedef void (*tpPlanarBlitter)(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -} - -bool VDPixmapBltDirect(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); - -void VDPixmapBltDirectPalettedConversion(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h, tpPalettedBlitter pBlitter) { - uint8 palbytes[256 * 3]; - - int palsize; - - switch(src.format) { - case kPixFormat_Pal1: - palsize = 2; - break; - case kPixFormat_Pal2: - palsize = 4; - break; - case kPixFormat_Pal4: - palsize = 16; - break; - case kPixFormat_Pal8: - palsize = 256; - break; - default: - VDNEVERHERE; - } - - VDASSERT(src.palette); - - VDPixmap srcpal = { (void *)src.palette, NULL, palsize, 1, 0, kPixFormat_XRGB8888 }; - VDPixmap dstpal = { palbytes, NULL, palsize, 1, 0, dst.format }; - - VDVERIFY(VDPixmapBltDirect(dstpal, srcpal, palsize, 1)); - - pBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h, palbytes); -} - -tpVDPixBltTable VDPixmapGetBlitterTable() { -#if defined(_WIN32) && defined(_M_IX86) - static tpVDPixBltTable pBltTable; - - if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) { - return VDGetPixBltTableX86MMX(); - } else { - return VDGetPixBltTableX86Scalar(); - } -#else - static tpVDPixBltTable pBltTable = VDGetPixBltTableReference(); - return pBltTable; -#endif -} - -bool VDPixmapBltDirect(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - if ((unsigned)src.format >= kPixFormat_Max_Standard) { - VDASSERT(false); - return false; - } - - if ((unsigned)dst.format >= kPixFormat_Max_Standard) { - VDASSERT(false); - return false; - } - - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); - - if (src.format == dst.format) { - int qw = w; - int qh = h; - - if (srcinfo.qchunky) { - qw = (qw + srcinfo.qw - 1) / srcinfo.qw; - qh = -(-h >> srcinfo.qhbits); - } - - const int auxw = -(-w >> srcinfo.auxwbits); - const int auxh = -(-h >> srcinfo.auxhbits); - - switch(srcinfo.auxbufs) { - case 2: - VDMemcpyRect(dst.data3, dst.pitch3, src.data3, src.pitch3, srcinfo.auxsize * auxw, auxh); - case 1: - VDMemcpyRect(dst.data2, dst.pitch2, src.data2, src.pitch2, srcinfo.auxsize * auxw, auxh); - case 0: - VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, srcinfo.qsize * qw, qh); - } - - return true; - } - - VDPixmapBlitterFn pBlitter = VDPixmapGetBlitterTable()[src.format][dst.format]; - - if (!pBlitter) - return false; - - pBlitter(dst, src, w, h); - return true; -} - -bool VDPixmapIsBltPossible(int dst_format, int src_format) { - if (src_format == dst_format) - return true; - - tpVDPixBltTable tab(VDPixmapGetBlitterTable()); - - if (tab[src_format][dst_format]) - return true; - - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src_format); - const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dst_format); - - if (srcinfo.auxbufs > 0 || dstinfo.auxbufs > 0) - return false; // fail, planar buffers involved (can't do scanlines independently) - - return (tab[src_format][kPixFormat_YUV444_XVYU] && tab[kPixFormat_YUV444_XVYU][dst_format]) - ||(tab[src_format][kPixFormat_XRGB8888] && tab[kPixFormat_XRGB8888][dst_format]); -} - -bool VDNOINLINE VDPixmapBltTwoStage(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); - const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dst.format); - - if (srcinfo.auxbufs > 0 || dstinfo.auxbufs > 0) - return false; // fail, planar buffers involved - - if (srcinfo.qh > 1) - return false; // fail, vertically packed formats involved - - if (srcinfo.palsize) - return false; // fail, paletted formats involved - - // Allocate a 4xW buffer and try round-tripping through either - // RGB32 or XYVU. - vdblock tempBuf; - - tpVDPixBltTable tab(VDPixmapGetBlitterTable()); - - VDPixmap linesrc(src); - VDPixmap linedst(dst); - VDPixmap linetmp = {}; - - if (w < 1024) { - linetmp.data = alloca(sizeof(uint32) * w); - } else { - tempBuf.resize(w + 1); - linetmp.data = tempBuf.data(); - } - linetmp.pitch = 0; - linetmp.format = kPixFormat_YUV444_XVYU; - linetmp.w = w; - linetmp.h = 1; - - VDPixmapBlitterFn pb1 = tab[src.format][kPixFormat_YUV444_XVYU]; - VDPixmapBlitterFn pb2 = tab[kPixFormat_YUV444_XVYU][dst.format]; - if (!pb1 || !pb2) { - pb1 = tab[src.format][kPixFormat_XRGB8888]; - pb2 = tab[kPixFormat_XRGB8888][dst.format]; - if (!pb1 || !pb2) - return false; - - linetmp.format = kPixFormat_XRGB8888; - } - - do { - pb1(linetmp, linesrc, w, 1); - pb2(linedst, linetmp, w, 1); - vdptrstep(linesrc.data, linesrc.pitch); - vdptrstep(linedst.data, linedst.pitch); - } while(--h); - return true; -} - -bool VDPixmapBltFast(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - if (w <= 0 || h <= 0) { - VDASSERT((w|h) >= 0); - return true; - } - - if (VDPixmapBltDirect(dst, src, w, h)) - return true; - - // Oro... let's see if we can do a two-stage conversion. - return VDPixmapBltTwoStage(dst, src, w, h); -} - -bool VDPixmapBlt(const VDPixmap& dst, const VDPixmap& src) { - vdpixsize w = std::min(src.w, dst.w); - vdpixsize h = std::min(src.h, dst.h); - - if (!w || !h) - return true; - - return VDPixmapBltFast(dst, src, w, h); -} - -bool VDPixmapBlt(const VDPixmap& dst, vdpixpos x1, vdpixpos y1, const VDPixmap& src, vdpixpos x2, vdpixpos y2, vdpixsize w, vdpixsize h) { - if (x1 < 0) { - x2 -= x1; - w -= x1; - x1 = 0; - } - - if (y1 < 0) { - y2 -= y1; - h -= y1; - y1 = 0; - } - - if (x2 < 0) { - x1 -= x2; - w -= x2; - x2 = 0; - } - - if (y2 < 0) { - y1 -= y2; - h -= y2; - y2 = 0; - } - - if (w > dst.w - x1) - w = dst.w - x1; - - if (h > dst.h - y1) - h = dst.h - y1; - - if (w > src.w - x2) - w = src.w - x2; - - if (h > src.h - y2) - h = src.h - y2; - - if (w>=0 && h >= 0) { - VDPixmap dst2(VDPixmapOffset(dst, x1, y1)); - VDPixmap src2(VDPixmapOffset(src, x2, y2)); - - return VDPixmapBltFast(dst2, src2, w, h); - } - - return true; -} - -extern bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); -extern bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); - -bool VDPixmapStretchBltNearest(const VDPixmap& dst, const VDPixmap& src) { - return VDPixmapStretchBltNearest(dst, 0, 0, dst.w<<16, dst.h<<16, src, 0, 0, src.w<<16, src.h<<16); -} - -bool VDPixmapStretchBltNearest(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { - return VDPixmapStretchBltNearest_reference(dst, x1, y1, x2, y2, src, u1, v1, u2, v2); -} - -bool VDPixmapStretchBltBilinear(const VDPixmap& dst, const VDPixmap& src) { - return VDPixmapStretchBltBilinear(dst, 0, 0, dst.w<<16, dst.h<<16, src, 0, 0, src.w<<16, src.h<<16); -} - -bool VDPixmapStretchBltBilinear(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { - return VDPixmapStretchBltBilinear_reference(dst, x1, y1, x2, y2, src, u1, v1, u2, v2); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace nsVDPixmap; + +namespace { + typedef void (*tpPalettedBlitter)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal); + typedef void (*tpChunkyBlitter)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); + typedef void (*tpPlanarBlitter)(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +} + +bool VDPixmapBltDirect(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); + +void VDPixmapBltDirectPalettedConversion(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h, tpPalettedBlitter pBlitter) { + uint8 palbytes[256 * 3]; + + int palsize; + + switch(src.format) { + case kPixFormat_Pal1: + palsize = 2; + break; + case kPixFormat_Pal2: + palsize = 4; + break; + case kPixFormat_Pal4: + palsize = 16; + break; + case kPixFormat_Pal8: + palsize = 256; + break; + default: + VDNEVERHERE; + } + + VDASSERT(src.palette); + + VDPixmap srcpal = { (void *)src.palette, NULL, palsize, 1, 0, kPixFormat_XRGB8888 }; + VDPixmap dstpal = { palbytes, NULL, palsize, 1, 0, dst.format }; + + VDVERIFY(VDPixmapBltDirect(dstpal, srcpal, palsize, 1)); + + pBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h, palbytes); +} + +tpVDPixBltTable VDPixmapGetBlitterTable() { +#if defined(_WIN32) && defined(_M_IX86) + static tpVDPixBltTable pBltTable; + + if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) { + return VDGetPixBltTableX86MMX(); + } else { + return VDGetPixBltTableX86Scalar(); + } +#else + static tpVDPixBltTable pBltTable = VDGetPixBltTableReference(); + return pBltTable; +#endif +} + +bool VDPixmapBltDirect(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + if ((unsigned)src.format >= kPixFormat_Max_Standard) { + VDASSERT(false); + return false; + } + + if ((unsigned)dst.format >= kPixFormat_Max_Standard) { + VDASSERT(false); + return false; + } + + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); + + if (src.format == dst.format) { + int qw = w; + int qh = h; + + if (srcinfo.qchunky) { + qw = (qw + srcinfo.qw - 1) / srcinfo.qw; + qh = -(-h >> srcinfo.qhbits); + } + + const int auxw = -(-w >> srcinfo.auxwbits); + const int auxh = -(-h >> srcinfo.auxhbits); + + switch(srcinfo.auxbufs) { + case 2: + VDMemcpyRect(dst.data3, dst.pitch3, src.data3, src.pitch3, srcinfo.auxsize * auxw, auxh); + case 1: + VDMemcpyRect(dst.data2, dst.pitch2, src.data2, src.pitch2, srcinfo.auxsize * auxw, auxh); + case 0: + VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, srcinfo.qsize * qw, qh); + } + + return true; + } + + VDPixmapBlitterFn pBlitter = VDPixmapGetBlitterTable()[src.format][dst.format]; + + if (!pBlitter) + return false; + + pBlitter(dst, src, w, h); + return true; +} + +bool VDPixmapIsBltPossible(int dst_format, int src_format) { + if (src_format == dst_format) + return true; + + tpVDPixBltTable tab(VDPixmapGetBlitterTable()); + + if (tab[src_format][dst_format]) + return true; + + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src_format); + const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dst_format); + + if (srcinfo.auxbufs > 0 || dstinfo.auxbufs > 0) + return false; // fail, planar buffers involved (can't do scanlines independently) + + return (tab[src_format][kPixFormat_YUV444_XVYU] && tab[kPixFormat_YUV444_XVYU][dst_format]) + ||(tab[src_format][kPixFormat_XRGB8888] && tab[kPixFormat_XRGB8888][dst_format]); +} + +bool VDNOINLINE VDPixmapBltTwoStage(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); + const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dst.format); + + if (srcinfo.auxbufs > 0 || dstinfo.auxbufs > 0) + return false; // fail, planar buffers involved + + if (srcinfo.qh > 1) + return false; // fail, vertically packed formats involved + + if (srcinfo.palsize) + return false; // fail, paletted formats involved + + // Allocate a 4xW buffer and try round-tripping through either + // RGB32 or XYVU. + vdblock tempBuf; + + tpVDPixBltTable tab(VDPixmapGetBlitterTable()); + + VDPixmap linesrc(src); + VDPixmap linedst(dst); + VDPixmap linetmp = {}; + + if (w < 1024) { + linetmp.data = alloca(sizeof(uint32) * w); + } else { + tempBuf.resize(w + 1); + linetmp.data = tempBuf.data(); + } + linetmp.pitch = 0; + linetmp.format = kPixFormat_YUV444_XVYU; + linetmp.w = w; + linetmp.h = 1; + + VDPixmapBlitterFn pb1 = tab[src.format][kPixFormat_YUV444_XVYU]; + VDPixmapBlitterFn pb2 = tab[kPixFormat_YUV444_XVYU][dst.format]; + if (!pb1 || !pb2) { + pb1 = tab[src.format][kPixFormat_XRGB8888]; + pb2 = tab[kPixFormat_XRGB8888][dst.format]; + if (!pb1 || !pb2) + return false; + + linetmp.format = kPixFormat_XRGB8888; + } + + do { + pb1(linetmp, linesrc, w, 1); + pb2(linedst, linetmp, w, 1); + vdptrstep(linesrc.data, linesrc.pitch); + vdptrstep(linedst.data, linedst.pitch); + } while(--h); + return true; +} + +bool VDPixmapBltFast(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + if (w <= 0 || h <= 0) { + VDASSERT((w|h) >= 0); + return true; + } + + if (VDPixmapBltDirect(dst, src, w, h)) + return true; + + // Oro... let's see if we can do a two-stage conversion. + return VDPixmapBltTwoStage(dst, src, w, h); +} + +bool VDPixmapBlt(const VDPixmap& dst, const VDPixmap& src) { + vdpixsize w = std::min(src.w, dst.w); + vdpixsize h = std::min(src.h, dst.h); + + if (!w || !h) + return true; + + return VDPixmapBltFast(dst, src, w, h); +} + +bool VDPixmapBlt(const VDPixmap& dst, vdpixpos x1, vdpixpos y1, const VDPixmap& src, vdpixpos x2, vdpixpos y2, vdpixsize w, vdpixsize h) { + if (x1 < 0) { + x2 -= x1; + w -= x1; + x1 = 0; + } + + if (y1 < 0) { + y2 -= y1; + h -= y1; + y1 = 0; + } + + if (x2 < 0) { + x1 -= x2; + w -= x2; + x2 = 0; + } + + if (y2 < 0) { + y1 -= y2; + h -= y2; + y2 = 0; + } + + if (w > dst.w - x1) + w = dst.w - x1; + + if (h > dst.h - y1) + h = dst.h - y1; + + if (w > src.w - x2) + w = src.w - x2; + + if (h > src.h - y2) + h = src.h - y2; + + if (w>=0 && h >= 0) { + VDPixmap dst2(VDPixmapOffset(dst, x1, y1)); + VDPixmap src2(VDPixmapOffset(src, x2, y2)); + + return VDPixmapBltFast(dst2, src2, w, h); + } + + return true; +} + +extern bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); +extern bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); + +bool VDPixmapStretchBltNearest(const VDPixmap& dst, const VDPixmap& src) { + return VDPixmapStretchBltNearest(dst, 0, 0, dst.w<<16, dst.h<<16, src, 0, 0, src.w<<16, src.h<<16); +} + +bool VDPixmapStretchBltNearest(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { + return VDPixmapStretchBltNearest_reference(dst, x1, y1, x2, y2, src, u1, v1, u2, v2); +} + +bool VDPixmapStretchBltBilinear(const VDPixmap& dst, const VDPixmap& src) { + return VDPixmapStretchBltBilinear(dst, 0, 0, dst.w<<16, dst.h<<16, src, 0, 0, src.w<<16, src.h<<16); +} + +bool VDPixmapStretchBltBilinear(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { + return VDPixmapStretchBltBilinear_reference(dst, x1, y1, x2, y2, src, u1, v1, u2, v2); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference.cpp index 4ee033bde02..0c826f18549 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference.cpp @@ -1,344 +1,344 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include "blt_setup.h" - -#define DECLARE_PALETTED(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0) -#define DECLARE_RGB(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV_PLANAR(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) - -DECLARE_RGB(RGB565, XRGB1555); -DECLARE_RGB(RGB888, XRGB1555); -DECLARE_RGB(XRGB8888, XRGB1555); -DECLARE_RGB(XRGB1555, RGB565); -DECLARE_RGB(RGB888, RGB565); -DECLARE_RGB(XRGB8888, RGB565); -DECLARE_RGB(XRGB1555, RGB888); -DECLARE_RGB(RGB565, RGB888); -DECLARE_RGB(XRGB8888, RGB888); -DECLARE_RGB(XRGB1555, XRGB8888); -DECLARE_RGB(RGB565, XRGB8888); -DECLARE_RGB(RGB888, XRGB8888); - -DECLARE_PALETTED(Pal1, Any8); -DECLARE_PALETTED(Pal1, Any16); -DECLARE_PALETTED(Pal1, Any24); -DECLARE_PALETTED(Pal1, Any32); -DECLARE_PALETTED(Pal2, Any8); -DECLARE_PALETTED(Pal2, Any16); -DECLARE_PALETTED(Pal2, Any24); -DECLARE_PALETTED(Pal2, Any32); -DECLARE_PALETTED(Pal4, Any8); -DECLARE_PALETTED(Pal4, Any16); -DECLARE_PALETTED(Pal4, Any24); -DECLARE_PALETTED(Pal4, Any32); -DECLARE_PALETTED(Pal8, Any8); -DECLARE_PALETTED(Pal8, Any16); -DECLARE_PALETTED(Pal8, Any24); -DECLARE_PALETTED(Pal8, Any32); - -DECLARE_YUV(XVYU, UYVY); -DECLARE_YUV(XVYU, YUYV); -DECLARE_YUV(Y8, UYVY); -DECLARE_YUV(Y8, YUYV); -DECLARE_YUV(UYVY, Y8); -DECLARE_YUV(YUYV, Y8); -DECLARE_YUV(UYVY, YUYV); -DECLARE_YUV_PLANAR(YUV411, YV12); - -DECLARE_YUV(UYVY, XRGB1555); -DECLARE_YUV(UYVY, RGB565); -DECLARE_YUV(UYVY, RGB888); -DECLARE_YUV(UYVY, XRGB8888); -DECLARE_YUV(YUYV, XRGB1555); -DECLARE_YUV(YUYV, RGB565); -DECLARE_YUV(YUYV, RGB888); -DECLARE_YUV(YUYV, XRGB8888); -DECLARE_YUV(Y8, XRGB1555); -DECLARE_YUV(Y8, RGB565); -DECLARE_YUV(Y8, RGB888); -DECLARE_YUV(Y8, XRGB8888); - -DECLARE_YUV_REV(XRGB1555, Y8); -DECLARE_YUV_REV(RGB565, Y8); -DECLARE_YUV_REV(RGB888, Y8); -DECLARE_YUV_REV(XRGB8888, Y8); - -DECLARE_YUV_REV(XRGB1555, XVYU); -DECLARE_YUV_REV(RGB565, XVYU); -DECLARE_YUV_REV(RGB888, XVYU); -DECLARE_YUV_REV(XRGB8888, XVYU); - -DECLARE_YUV_PLANAR(YV12, XRGB1555); -DECLARE_YUV_PLANAR(YV12, RGB565); -DECLARE_YUV_PLANAR(YV12, RGB888); -DECLARE_YUV_PLANAR(YV12, XRGB8888); - -DECLARE_YUV_PLANAR(YUV411, XRGB1555); -DECLARE_YUV_PLANAR(YUV411, RGB565); -DECLARE_YUV_PLANAR(YUV411, RGB888); -DECLARE_YUV_PLANAR(YUV411, XRGB8888); - -extern void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_UberblitAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); - -using namespace nsVDPixmap; - -void VDPixmapInitBlittersReference(VDPixmapBlitterTable& table) { - // use uberblit as the baseline - VDPixmapFormatSubset uberblitSrcFormats; - VDPixmapFormatSubset uberblitDstFormats; - - uberblitSrcFormats = - kPixFormat_Pal1, - kPixFormat_Pal2, - kPixFormat_Pal4, - kPixFormat_Pal8, - kPixFormat_XRGB1555, - kPixFormat_RGB565, - kPixFormat_RGB888, - kPixFormat_XRGB8888, - kPixFormat_Y8, - kPixFormat_YUV422_UYVY, - kPixFormat_YUV422_YUYV, - kPixFormat_YUV444_XVYU, - kPixFormat_YUV444_Planar, - kPixFormat_YUV422_Planar, - kPixFormat_YUV422_Planar_16F, - kPixFormat_YUV420_Planar, - kPixFormat_YUV411_Planar, - kPixFormat_YUV410_Planar, - kPixFormat_YUV422_Planar_Centered, - kPixFormat_YUV420_Planar_Centered, - kPixFormat_YUV422_V210, - kPixFormat_YUV422_UYVY_709, - kPixFormat_YUV420_NV12, - kPixFormat_Y8_FR, - kPixFormat_YUV422_YUYV_709, - kPixFormat_YUV444_Planar_709, - kPixFormat_YUV422_Planar_709, - kPixFormat_YUV420_Planar_709, - kPixFormat_YUV411_Planar_709, - kPixFormat_YUV410_Planar_709, - kPixFormat_YUV422_UYVY_FR, - kPixFormat_YUV422_YUYV_FR, - kPixFormat_YUV444_Planar_FR, - kPixFormat_YUV422_Planar_FR, - kPixFormat_YUV420_Planar_FR, - kPixFormat_YUV411_Planar_FR, - kPixFormat_YUV410_Planar_FR, - kPixFormat_YUV422_UYVY_709_FR, - kPixFormat_YUV422_YUYV_709_FR, - kPixFormat_YUV444_Planar_709_FR, - kPixFormat_YUV422_Planar_709_FR, - kPixFormat_YUV420_Planar_709_FR, - kPixFormat_YUV411_Planar_709_FR, - kPixFormat_YUV410_Planar_709_FR, - kPixFormat_YUV420i_Planar, - kPixFormat_YUV420i_Planar_FR, - kPixFormat_YUV420i_Planar_709, - kPixFormat_YUV420i_Planar_709_FR, - kPixFormat_YUV420it_Planar, - kPixFormat_YUV420it_Planar_FR, - kPixFormat_YUV420it_Planar_709, - kPixFormat_YUV420it_Planar_709_FR, - kPixFormat_YUV420ib_Planar, - kPixFormat_YUV420ib_Planar_FR, - kPixFormat_YUV420ib_Planar_709, - kPixFormat_YUV420ib_Planar_709_FR; - - uberblitDstFormats = - kPixFormat_XRGB1555, - kPixFormat_RGB565, - kPixFormat_RGB888, - kPixFormat_XRGB8888, - kPixFormat_Y8, - kPixFormat_YUV422_UYVY, - kPixFormat_YUV422_YUYV, - kPixFormat_YUV444_XVYU, - kPixFormat_YUV444_Planar, - kPixFormat_YUV422_Planar, - kPixFormat_YUV422_Planar_16F, - kPixFormat_YUV420_Planar, - kPixFormat_YUV411_Planar, - kPixFormat_YUV410_Planar, - kPixFormat_YUV422_Planar_Centered, - kPixFormat_YUV420_Planar_Centered, - kPixFormat_YUV422_V210, - kPixFormat_YUV422_UYVY_709, - kPixFormat_YUV420_NV12, - kPixFormat_Y8_FR, - kPixFormat_YUV422_YUYV_709, - kPixFormat_YUV444_Planar_709, - kPixFormat_YUV422_Planar_709, - kPixFormat_YUV420_Planar_709, - kPixFormat_YUV411_Planar_709, - kPixFormat_YUV410_Planar_709, - kPixFormat_YUV422_UYVY_FR, - kPixFormat_YUV422_YUYV_FR, - kPixFormat_YUV444_Planar_FR, - kPixFormat_YUV422_Planar_FR, - kPixFormat_YUV420_Planar_FR, - kPixFormat_YUV411_Planar_FR, - kPixFormat_YUV410_Planar_FR, - kPixFormat_YUV422_UYVY_709_FR, - kPixFormat_YUV422_YUYV_709_FR, - kPixFormat_YUV444_Planar_709_FR, - kPixFormat_YUV422_Planar_709_FR, - kPixFormat_YUV420_Planar_709_FR, - kPixFormat_YUV411_Planar_709_FR, - kPixFormat_YUV410_Planar_709_FR, - kPixFormat_YUV420i_Planar, - kPixFormat_YUV420i_Planar_FR, - kPixFormat_YUV420i_Planar_709, - kPixFormat_YUV420i_Planar_709_FR, - kPixFormat_YUV420it_Planar, - kPixFormat_YUV420it_Planar_FR, - kPixFormat_YUV420it_Planar_709, - kPixFormat_YUV420it_Planar_709_FR, - kPixFormat_YUV420ib_Planar, - kPixFormat_YUV420ib_Planar_FR, - kPixFormat_YUV420ib_Planar_709, - kPixFormat_YUV420ib_Planar_709_FR; - - table.AddBlitter(uberblitSrcFormats, uberblitDstFormats, VDPixmapBlt_UberblitAdapter); - - // standard formats - - table.AddBlitter(kPixFormat_Pal1, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal1, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal1, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal1, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal1, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); - - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_YUV444_XVYU, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV444_XVYU, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_YUV411_Planar, kPixFormat_YUV420_Planar, VDPixmapBlt_YUV411_to_YV12_reference); - - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); // not an error -- same routine - - ////////////////////////////////////////////////////////// - - VDPixmapFormatSubset srcFormats; - VDPixmapFormatSubset dstFormats; - - srcFormats = kPixFormat_YUV444_Planar, - kPixFormat_YUV422_Planar, - kPixFormat_YUV420_Planar, - kPixFormat_YUV411_Planar, - kPixFormat_YUV410_Planar, - kPixFormat_YUV422_Planar_Centered, - kPixFormat_YUV420_Planar_Centered; - - dstFormats = kPixFormat_XRGB1555, kPixFormat_RGB565, kPixFormat_RGB888, kPixFormat_XRGB8888, kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV; - - table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_decode_reference); - - ////////////////////////////////////////////////////////// - - dstFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; - srcFormats = kPixFormat_XRGB1555, kPixFormat_RGB565, kPixFormat_RGB888, kPixFormat_XRGB8888, kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV; - - table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_encode_reference); - - ////////////////////////////////////////////////////////// - - srcFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_Y8, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; - dstFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_Y8, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; - - table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_convert_reference); -} - -tpVDPixBltTable VDGetPixBltTableReferenceInternal() { - static VDPixmapBlitterTable sReferenceTable; - - VDPixmapInitBlittersReference(sReferenceTable); - - return sReferenceTable.mTable; -} - -tpVDPixBltTable VDGetPixBltTableReference() { - static tpVDPixBltTable spTable = VDGetPixBltTableReferenceInternal(); - - return spTable; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include "blt_setup.h" + +#define DECLARE_PALETTED(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0) +#define DECLARE_RGB(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV_PLANAR(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) + +DECLARE_RGB(RGB565, XRGB1555); +DECLARE_RGB(RGB888, XRGB1555); +DECLARE_RGB(XRGB8888, XRGB1555); +DECLARE_RGB(XRGB1555, RGB565); +DECLARE_RGB(RGB888, RGB565); +DECLARE_RGB(XRGB8888, RGB565); +DECLARE_RGB(XRGB1555, RGB888); +DECLARE_RGB(RGB565, RGB888); +DECLARE_RGB(XRGB8888, RGB888); +DECLARE_RGB(XRGB1555, XRGB8888); +DECLARE_RGB(RGB565, XRGB8888); +DECLARE_RGB(RGB888, XRGB8888); + +DECLARE_PALETTED(Pal1, Any8); +DECLARE_PALETTED(Pal1, Any16); +DECLARE_PALETTED(Pal1, Any24); +DECLARE_PALETTED(Pal1, Any32); +DECLARE_PALETTED(Pal2, Any8); +DECLARE_PALETTED(Pal2, Any16); +DECLARE_PALETTED(Pal2, Any24); +DECLARE_PALETTED(Pal2, Any32); +DECLARE_PALETTED(Pal4, Any8); +DECLARE_PALETTED(Pal4, Any16); +DECLARE_PALETTED(Pal4, Any24); +DECLARE_PALETTED(Pal4, Any32); +DECLARE_PALETTED(Pal8, Any8); +DECLARE_PALETTED(Pal8, Any16); +DECLARE_PALETTED(Pal8, Any24); +DECLARE_PALETTED(Pal8, Any32); + +DECLARE_YUV(XVYU, UYVY); +DECLARE_YUV(XVYU, YUYV); +DECLARE_YUV(Y8, UYVY); +DECLARE_YUV(Y8, YUYV); +DECLARE_YUV(UYVY, Y8); +DECLARE_YUV(YUYV, Y8); +DECLARE_YUV(UYVY, YUYV); +DECLARE_YUV_PLANAR(YUV411, YV12); + +DECLARE_YUV(UYVY, XRGB1555); +DECLARE_YUV(UYVY, RGB565); +DECLARE_YUV(UYVY, RGB888); +DECLARE_YUV(UYVY, XRGB8888); +DECLARE_YUV(YUYV, XRGB1555); +DECLARE_YUV(YUYV, RGB565); +DECLARE_YUV(YUYV, RGB888); +DECLARE_YUV(YUYV, XRGB8888); +DECLARE_YUV(Y8, XRGB1555); +DECLARE_YUV(Y8, RGB565); +DECLARE_YUV(Y8, RGB888); +DECLARE_YUV(Y8, XRGB8888); + +DECLARE_YUV_REV(XRGB1555, Y8); +DECLARE_YUV_REV(RGB565, Y8); +DECLARE_YUV_REV(RGB888, Y8); +DECLARE_YUV_REV(XRGB8888, Y8); + +DECLARE_YUV_REV(XRGB1555, XVYU); +DECLARE_YUV_REV(RGB565, XVYU); +DECLARE_YUV_REV(RGB888, XVYU); +DECLARE_YUV_REV(XRGB8888, XVYU); + +DECLARE_YUV_PLANAR(YV12, XRGB1555); +DECLARE_YUV_PLANAR(YV12, RGB565); +DECLARE_YUV_PLANAR(YV12, RGB888); +DECLARE_YUV_PLANAR(YV12, XRGB8888); + +DECLARE_YUV_PLANAR(YUV411, XRGB1555); +DECLARE_YUV_PLANAR(YUV411, RGB565); +DECLARE_YUV_PLANAR(YUV411, RGB888); +DECLARE_YUV_PLANAR(YUV411, XRGB8888); + +extern void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_UberblitAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); + +using namespace nsVDPixmap; + +void VDPixmapInitBlittersReference(VDPixmapBlitterTable& table) { + // use uberblit as the baseline + VDPixmapFormatSubset uberblitSrcFormats; + VDPixmapFormatSubset uberblitDstFormats; + + uberblitSrcFormats = + kPixFormat_Pal1, + kPixFormat_Pal2, + kPixFormat_Pal4, + kPixFormat_Pal8, + kPixFormat_XRGB1555, + kPixFormat_RGB565, + kPixFormat_RGB888, + kPixFormat_XRGB8888, + kPixFormat_Y8, + kPixFormat_YUV422_UYVY, + kPixFormat_YUV422_YUYV, + kPixFormat_YUV444_XVYU, + kPixFormat_YUV444_Planar, + kPixFormat_YUV422_Planar, + kPixFormat_YUV422_Planar_16F, + kPixFormat_YUV420_Planar, + kPixFormat_YUV411_Planar, + kPixFormat_YUV410_Planar, + kPixFormat_YUV422_Planar_Centered, + kPixFormat_YUV420_Planar_Centered, + kPixFormat_YUV422_V210, + kPixFormat_YUV422_UYVY_709, + kPixFormat_YUV420_NV12, + kPixFormat_Y8_FR, + kPixFormat_YUV422_YUYV_709, + kPixFormat_YUV444_Planar_709, + kPixFormat_YUV422_Planar_709, + kPixFormat_YUV420_Planar_709, + kPixFormat_YUV411_Planar_709, + kPixFormat_YUV410_Planar_709, + kPixFormat_YUV422_UYVY_FR, + kPixFormat_YUV422_YUYV_FR, + kPixFormat_YUV444_Planar_FR, + kPixFormat_YUV422_Planar_FR, + kPixFormat_YUV420_Planar_FR, + kPixFormat_YUV411_Planar_FR, + kPixFormat_YUV410_Planar_FR, + kPixFormat_YUV422_UYVY_709_FR, + kPixFormat_YUV422_YUYV_709_FR, + kPixFormat_YUV444_Planar_709_FR, + kPixFormat_YUV422_Planar_709_FR, + kPixFormat_YUV420_Planar_709_FR, + kPixFormat_YUV411_Planar_709_FR, + kPixFormat_YUV410_Planar_709_FR, + kPixFormat_YUV420i_Planar, + kPixFormat_YUV420i_Planar_FR, + kPixFormat_YUV420i_Planar_709, + kPixFormat_YUV420i_Planar_709_FR, + kPixFormat_YUV420it_Planar, + kPixFormat_YUV420it_Planar_FR, + kPixFormat_YUV420it_Planar_709, + kPixFormat_YUV420it_Planar_709_FR, + kPixFormat_YUV420ib_Planar, + kPixFormat_YUV420ib_Planar_FR, + kPixFormat_YUV420ib_Planar_709, + kPixFormat_YUV420ib_Planar_709_FR; + + uberblitDstFormats = + kPixFormat_XRGB1555, + kPixFormat_RGB565, + kPixFormat_RGB888, + kPixFormat_XRGB8888, + kPixFormat_Y8, + kPixFormat_YUV422_UYVY, + kPixFormat_YUV422_YUYV, + kPixFormat_YUV444_XVYU, + kPixFormat_YUV444_Planar, + kPixFormat_YUV422_Planar, + kPixFormat_YUV422_Planar_16F, + kPixFormat_YUV420_Planar, + kPixFormat_YUV411_Planar, + kPixFormat_YUV410_Planar, + kPixFormat_YUV422_Planar_Centered, + kPixFormat_YUV420_Planar_Centered, + kPixFormat_YUV422_V210, + kPixFormat_YUV422_UYVY_709, + kPixFormat_YUV420_NV12, + kPixFormat_Y8_FR, + kPixFormat_YUV422_YUYV_709, + kPixFormat_YUV444_Planar_709, + kPixFormat_YUV422_Planar_709, + kPixFormat_YUV420_Planar_709, + kPixFormat_YUV411_Planar_709, + kPixFormat_YUV410_Planar_709, + kPixFormat_YUV422_UYVY_FR, + kPixFormat_YUV422_YUYV_FR, + kPixFormat_YUV444_Planar_FR, + kPixFormat_YUV422_Planar_FR, + kPixFormat_YUV420_Planar_FR, + kPixFormat_YUV411_Planar_FR, + kPixFormat_YUV410_Planar_FR, + kPixFormat_YUV422_UYVY_709_FR, + kPixFormat_YUV422_YUYV_709_FR, + kPixFormat_YUV444_Planar_709_FR, + kPixFormat_YUV422_Planar_709_FR, + kPixFormat_YUV420_Planar_709_FR, + kPixFormat_YUV411_Planar_709_FR, + kPixFormat_YUV410_Planar_709_FR, + kPixFormat_YUV420i_Planar, + kPixFormat_YUV420i_Planar_FR, + kPixFormat_YUV420i_Planar_709, + kPixFormat_YUV420i_Planar_709_FR, + kPixFormat_YUV420it_Planar, + kPixFormat_YUV420it_Planar_FR, + kPixFormat_YUV420it_Planar_709, + kPixFormat_YUV420it_Planar_709_FR, + kPixFormat_YUV420ib_Planar, + kPixFormat_YUV420ib_Planar_FR, + kPixFormat_YUV420ib_Planar_709, + kPixFormat_YUV420ib_Planar_709_FR; + + table.AddBlitter(uberblitSrcFormats, uberblitDstFormats, VDPixmapBlt_UberblitAdapter); + + // standard formats + + table.AddBlitter(kPixFormat_Pal1, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal1, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal1, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal1, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal1, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); + + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_YUV444_XVYU, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV444_XVYU, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_YUV411_Planar, kPixFormat_YUV420_Planar, VDPixmapBlt_YUV411_to_YV12_reference); + + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); // not an error -- same routine + + ////////////////////////////////////////////////////////// + + VDPixmapFormatSubset srcFormats; + VDPixmapFormatSubset dstFormats; + + srcFormats = kPixFormat_YUV444_Planar, + kPixFormat_YUV422_Planar, + kPixFormat_YUV420_Planar, + kPixFormat_YUV411_Planar, + kPixFormat_YUV410_Planar, + kPixFormat_YUV422_Planar_Centered, + kPixFormat_YUV420_Planar_Centered; + + dstFormats = kPixFormat_XRGB1555, kPixFormat_RGB565, kPixFormat_RGB888, kPixFormat_XRGB8888, kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV; + + table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_decode_reference); + + ////////////////////////////////////////////////////////// + + dstFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; + srcFormats = kPixFormat_XRGB1555, kPixFormat_RGB565, kPixFormat_RGB888, kPixFormat_XRGB8888, kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV; + + table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_encode_reference); + + ////////////////////////////////////////////////////////// + + srcFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_Y8, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; + dstFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_Y8, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; + + table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_convert_reference); +} + +tpVDPixBltTable VDGetPixBltTableReferenceInternal() { + static VDPixmapBlitterTable sReferenceTable; + + VDPixmapInitBlittersReference(sReferenceTable); + + return sReferenceTable.mTable; +} + +tpVDPixBltTable VDGetPixBltTableReference() { + static tpVDPixBltTable spTable = VDGetPixBltTableReferenceInternal(); + + return spTable; +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_pal.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_pal.cpp index 4bf5a5f7156..debf3c253cb 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_pal.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_pal.cpp @@ -1,564 +1,564 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include - -#define DECLARE_PALETTED(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0) - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: Pal1 -> -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_PALETTED(Pal1, Any8) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 3; - dst += (w-1) & ~7; - - srcpitch += (w+7) >> 3; - dstpitch += (w+7) & ~7; - - do { - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - - switch(wt & 7) { - do { - v = src[0]; - - case 0: dst[7] = pal[v&1]; v >>= 1; - case 7: dst[6] = pal[v&1]; v >>= 1; - case 6: dst[5] = pal[v&1]; v >>= 1; - case 5: dst[4] = pal[v&1]; v >>= 1; - case 4: dst[3] = pal[v&1]; v >>= 1; - case 3: dst[2] = pal[v&1]; v >>= 1; - case 2: dst[1] = pal[v&1]; v >>= 1; - case 1: dst[0] = pal[v&1]; v >>= 1; - - dst -= 8; - --src; - } while((wt -= 8) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal1, Any16) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - const uint16 *pal = (const uint16 *)pal0; - - src += (w-1) >> 3; - dst += (w-1) & ~7; - - srcpitch += (w+7) >> 3; - dstpitch += ((w+7) & ~7) * 2; - - do { - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - - switch(wt & 7) { - do { - v = src[0]; - - case 0: dst[7] = pal[v&1]; v >>= 1; - case 7: dst[6] = pal[v&1]; v >>= 1; - case 6: dst[5] = pal[v&1]; v >>= 1; - case 5: dst[4] = pal[v&1]; v >>= 1; - case 4: dst[3] = pal[v&1]; v >>= 1; - case 3: dst[2] = pal[v&1]; v >>= 1; - case 2: dst[1] = pal[v&1]; v >>= 1; - case 1: dst[0] = pal[v&1]; v >>= 1; - - dst -= 8; - --src; - } while((wt -= 8) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal1, Any24) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 3; - dst += ((w-1) & ~7) * 3; - - srcpitch += (w+7) >> 3; - dstpitch += ((w+7) & ~7) * 3; - - do { - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - const uint8 *pe; - - switch(wt & 7) { - do { - v = src[0]; - - case 0: pe = &pal[3*(v&1)]; dst[7*3+0] = pe[0]; dst[7*3+1] = pe[1]; dst[7*3+2] = pe[2]; v >>= 1; - case 7: pe = &pal[3*(v&1)]; dst[6*3+0] = pe[0]; dst[6*3+1] = pe[1]; dst[6*3+2] = pe[2]; v >>= 1; - case 6: pe = &pal[3*(v&1)]; dst[5*3+0] = pe[0]; dst[5*3+1] = pe[1]; dst[5*3+2] = pe[2]; v >>= 1; - case 5: pe = &pal[3*(v&1)]; dst[4*3+0] = pe[0]; dst[4*3+1] = pe[1]; dst[4*3+2] = pe[2]; v >>= 1; - case 4: pe = &pal[3*(v&1)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 1; - case 3: pe = &pal[3*(v&1)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 1; - case 2: pe = &pal[3*(v&1)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 1; - case 1: pe = &pal[3*(v&1)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 1; - - dst -= 24; - --src; - } while((wt -= 8) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal1, Any32) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - const uint32 *pal = (const uint32 *)pal0; - - src += (w-1) >> 3; - dst += (w-1) & ~7; - - srcpitch += (w+7) >> 3; - dstpitch += ((w+7) & ~7) * 4; - - do { - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - - switch(wt & 7) { - do { - v = src[0]; - - case 0: dst[7] = pal[v&1]; v >>= 1; - case 7: dst[6] = pal[v&1]; v >>= 1; - case 6: dst[5] = pal[v&1]; v >>= 1; - case 5: dst[4] = pal[v&1]; v >>= 1; - case 4: dst[3] = pal[v&1]; v >>= 1; - case 3: dst[2] = pal[v&1]; v >>= 1; - case 2: dst[1] = pal[v&1]; v >>= 1; - case 1: dst[0] = pal[v&1]; v >>= 1; - - dst -= 8; - --src; - } while((wt -= 8) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: Pal2 -> -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_PALETTED(Pal2, Any8) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 2; - dst += (w-1) & ~3; - - srcpitch += (w+3) >> 2; - dstpitch += (w+3) & ~3; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - - switch(wt & 3) { - do { - v = src[0]; - - case 0: dst[3] = pal[v&3]; v >>= 2; - case 3: dst[2] = pal[v&3]; v >>= 2; - case 2: dst[1] = pal[v&3]; v >>= 2; - case 1: dst[0] = pal[v&3]; v >>= 2; - - dst -= 4; - --src; - } while((wt -= 4) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal2, Any16) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - const uint16 *pal = (const uint16 *)pal0; - - src += (w-1) >> 2; - dst += (w-1) & ~3; - - srcpitch += (w+3) >> 2; - dstpitch += ((w+3) & ~3) * 2; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - - switch(wt & 3) { - do { - v = src[0]; - - case 0: dst[3] = pal[v&3]; v >>= 2; - case 3: dst[2] = pal[v&3]; v >>= 2; - case 2: dst[1] = pal[v&3]; v >>= 2; - case 1: dst[0] = pal[v&3]; v >>= 2; - - dst -= 4; - --src; - } while((wt -= 4) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal2, Any24) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 2; - dst += ((w-1) & ~3) * 3; - - srcpitch += (w+3) >> 2; - dstpitch += ((w+3) & ~3) * 3; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - const uint8 *pe; - - switch(wt & 3) { - do { - v = src[0]; - - case 0: pe = &pal[3*(v&3)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 2; - case 3: pe = &pal[3*(v&3)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 2; - case 2: pe = &pal[3*(v&3)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 2; - case 1: pe = &pal[3*(v&3)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 2; - - dst -= 12; - --src; - } while((wt -= 4) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal2, Any32) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - const uint32 *pal = (const uint32 *)pal0; - - src += (w-1) >> 2; - dst += (w-1) & ~3; - - srcpitch += (w+3) >> 2; - dstpitch += ((w+3) & ~3) * 4; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - - switch(wt & 3) { - do { - v = src[0]; - - case 0: dst[3] = pal[v&3]; v >>= 2; - case 3: dst[2] = pal[v&3]; v >>= 2; - case 2: dst[1] = pal[v&3]; v >>= 2; - case 1: dst[0] = pal[v&3]; v >>= 2; - - dst -= 4; - --src; - } while((wt -= 4) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: Pal4 -> -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_PALETTED(Pal4, Any8) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 1; - dst += ((w-1) & ~1); - - srcpitch += (w+1) >> 1; - dstpitch += (w+1) & ~1; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - - switch(wt & 1) { - do { - v = src[0]; - - case 0: dst[1] = pal[v&15]; v >>= 4; - case 1: dst[0] = pal[v&15]; v >>= 4; - - dst -= 2; - --src; - } while((wt -= 2) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal4, Any16) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - const uint16 *pal = (const uint16 *)pal0; - - src += (w-1) >> 1; - dst += ((w-1) & ~1); - - srcpitch += (w+1) >> 1; - dstpitch += ((w+1) & ~1) * 2; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - - switch(wt & 1) { - do { - v = src[0]; - - case 0: dst[1] = pal[v&15]; v >>= 4; - case 1: dst[0] = pal[v&15]; v >>= 4; - - dst -= 2; - --src; - } while((wt -= 2) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal4, Any24) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 1; - dst += ((w-1) & ~1) * 3; - - srcpitch += (w+1) >> 1; - dstpitch += ((w+1) & ~1) * 3; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - const uint8 *pe; - - switch(wt & 1) { - do { - v = src[0]; - - case 0: pe = &pal[3*(v&15)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 4; - case 1: pe = &pal[3*(v&15)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 4; - - dst -= 6; - --src; - } while((wt -= 2) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal4, Any32) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - const uint32 *pal = (const uint32 *)pal0; - - src += (w-1) >> 1; - dst += ((w-1) & ~1); - - srcpitch += (w+1) >> 1; - dstpitch += ((w+1) & ~1) * 4; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - - switch(wt & 1) { - do { - v = src[0]; - - case 0: dst[1] = pal[v&15]; v >>= 4; - case 1: dst[0] = pal[v&15]; v >>= 4; - - dst -= 2; - --src; - } while((wt -= 2) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: Pal8 -> -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_PALETTED(Pal8, Any8) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - srcpitch -= w; - dstpitch -= w; - - do { - int wt = w; - - do { - *dst++ = pal[*src++]; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal8, Any16) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - const uint16 *pal = (const uint16 *)pal0; - - srcpitch -= w; - dstpitch -= w*2; - - do { - int wt = w; - - do { - *dst++ = pal[*src++]; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal8, Any24) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - srcpitch -= w; - dstpitch -= w*3; - - do { - int wt = w; - do { - const uint8 *pe = &pal[3**src++]; - - dst[0] = pe[0]; - dst[1] = pe[1]; - dst[2] = pe[2]; - dst += 3; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal8, Any32) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - const uint32 *pal = (const uint32 *)pal0; - - srcpitch -= w; - dstpitch -= w*4; - - do { - int wt = w; - - do { - *dst++ = pal[*src++]; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include + +#define DECLARE_PALETTED(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0) + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: Pal1 -> +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_PALETTED(Pal1, Any8) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 3; + dst += (w-1) & ~7; + + srcpitch += (w+7) >> 3; + dstpitch += (w+7) & ~7; + + do { + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + + switch(wt & 7) { + do { + v = src[0]; + + case 0: dst[7] = pal[v&1]; v >>= 1; + case 7: dst[6] = pal[v&1]; v >>= 1; + case 6: dst[5] = pal[v&1]; v >>= 1; + case 5: dst[4] = pal[v&1]; v >>= 1; + case 4: dst[3] = pal[v&1]; v >>= 1; + case 3: dst[2] = pal[v&1]; v >>= 1; + case 2: dst[1] = pal[v&1]; v >>= 1; + case 1: dst[0] = pal[v&1]; v >>= 1; + + dst -= 8; + --src; + } while((wt -= 8) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal1, Any16) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + const uint16 *pal = (const uint16 *)pal0; + + src += (w-1) >> 3; + dst += (w-1) & ~7; + + srcpitch += (w+7) >> 3; + dstpitch += ((w+7) & ~7) * 2; + + do { + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + + switch(wt & 7) { + do { + v = src[0]; + + case 0: dst[7] = pal[v&1]; v >>= 1; + case 7: dst[6] = pal[v&1]; v >>= 1; + case 6: dst[5] = pal[v&1]; v >>= 1; + case 5: dst[4] = pal[v&1]; v >>= 1; + case 4: dst[3] = pal[v&1]; v >>= 1; + case 3: dst[2] = pal[v&1]; v >>= 1; + case 2: dst[1] = pal[v&1]; v >>= 1; + case 1: dst[0] = pal[v&1]; v >>= 1; + + dst -= 8; + --src; + } while((wt -= 8) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal1, Any24) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 3; + dst += ((w-1) & ~7) * 3; + + srcpitch += (w+7) >> 3; + dstpitch += ((w+7) & ~7) * 3; + + do { + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + const uint8 *pe; + + switch(wt & 7) { + do { + v = src[0]; + + case 0: pe = &pal[3*(v&1)]; dst[7*3+0] = pe[0]; dst[7*3+1] = pe[1]; dst[7*3+2] = pe[2]; v >>= 1; + case 7: pe = &pal[3*(v&1)]; dst[6*3+0] = pe[0]; dst[6*3+1] = pe[1]; dst[6*3+2] = pe[2]; v >>= 1; + case 6: pe = &pal[3*(v&1)]; dst[5*3+0] = pe[0]; dst[5*3+1] = pe[1]; dst[5*3+2] = pe[2]; v >>= 1; + case 5: pe = &pal[3*(v&1)]; dst[4*3+0] = pe[0]; dst[4*3+1] = pe[1]; dst[4*3+2] = pe[2]; v >>= 1; + case 4: pe = &pal[3*(v&1)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 1; + case 3: pe = &pal[3*(v&1)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 1; + case 2: pe = &pal[3*(v&1)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 1; + case 1: pe = &pal[3*(v&1)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 1; + + dst -= 24; + --src; + } while((wt -= 8) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal1, Any32) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + const uint32 *pal = (const uint32 *)pal0; + + src += (w-1) >> 3; + dst += (w-1) & ~7; + + srcpitch += (w+7) >> 3; + dstpitch += ((w+7) & ~7) * 4; + + do { + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + + switch(wt & 7) { + do { + v = src[0]; + + case 0: dst[7] = pal[v&1]; v >>= 1; + case 7: dst[6] = pal[v&1]; v >>= 1; + case 6: dst[5] = pal[v&1]; v >>= 1; + case 5: dst[4] = pal[v&1]; v >>= 1; + case 4: dst[3] = pal[v&1]; v >>= 1; + case 3: dst[2] = pal[v&1]; v >>= 1; + case 2: dst[1] = pal[v&1]; v >>= 1; + case 1: dst[0] = pal[v&1]; v >>= 1; + + dst -= 8; + --src; + } while((wt -= 8) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: Pal2 -> +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_PALETTED(Pal2, Any8) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 2; + dst += (w-1) & ~3; + + srcpitch += (w+3) >> 2; + dstpitch += (w+3) & ~3; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + + switch(wt & 3) { + do { + v = src[0]; + + case 0: dst[3] = pal[v&3]; v >>= 2; + case 3: dst[2] = pal[v&3]; v >>= 2; + case 2: dst[1] = pal[v&3]; v >>= 2; + case 1: dst[0] = pal[v&3]; v >>= 2; + + dst -= 4; + --src; + } while((wt -= 4) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal2, Any16) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + const uint16 *pal = (const uint16 *)pal0; + + src += (w-1) >> 2; + dst += (w-1) & ~3; + + srcpitch += (w+3) >> 2; + dstpitch += ((w+3) & ~3) * 2; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + + switch(wt & 3) { + do { + v = src[0]; + + case 0: dst[3] = pal[v&3]; v >>= 2; + case 3: dst[2] = pal[v&3]; v >>= 2; + case 2: dst[1] = pal[v&3]; v >>= 2; + case 1: dst[0] = pal[v&3]; v >>= 2; + + dst -= 4; + --src; + } while((wt -= 4) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal2, Any24) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 2; + dst += ((w-1) & ~3) * 3; + + srcpitch += (w+3) >> 2; + dstpitch += ((w+3) & ~3) * 3; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + const uint8 *pe; + + switch(wt & 3) { + do { + v = src[0]; + + case 0: pe = &pal[3*(v&3)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 2; + case 3: pe = &pal[3*(v&3)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 2; + case 2: pe = &pal[3*(v&3)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 2; + case 1: pe = &pal[3*(v&3)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 2; + + dst -= 12; + --src; + } while((wt -= 4) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal2, Any32) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + const uint32 *pal = (const uint32 *)pal0; + + src += (w-1) >> 2; + dst += (w-1) & ~3; + + srcpitch += (w+3) >> 2; + dstpitch += ((w+3) & ~3) * 4; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + + switch(wt & 3) { + do { + v = src[0]; + + case 0: dst[3] = pal[v&3]; v >>= 2; + case 3: dst[2] = pal[v&3]; v >>= 2; + case 2: dst[1] = pal[v&3]; v >>= 2; + case 1: dst[0] = pal[v&3]; v >>= 2; + + dst -= 4; + --src; + } while((wt -= 4) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: Pal4 -> +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_PALETTED(Pal4, Any8) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 1; + dst += ((w-1) & ~1); + + srcpitch += (w+1) >> 1; + dstpitch += (w+1) & ~1; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + + switch(wt & 1) { + do { + v = src[0]; + + case 0: dst[1] = pal[v&15]; v >>= 4; + case 1: dst[0] = pal[v&15]; v >>= 4; + + dst -= 2; + --src; + } while((wt -= 2) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal4, Any16) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + const uint16 *pal = (const uint16 *)pal0; + + src += (w-1) >> 1; + dst += ((w-1) & ~1); + + srcpitch += (w+1) >> 1; + dstpitch += ((w+1) & ~1) * 2; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + + switch(wt & 1) { + do { + v = src[0]; + + case 0: dst[1] = pal[v&15]; v >>= 4; + case 1: dst[0] = pal[v&15]; v >>= 4; + + dst -= 2; + --src; + } while((wt -= 2) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal4, Any24) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 1; + dst += ((w-1) & ~1) * 3; + + srcpitch += (w+1) >> 1; + dstpitch += ((w+1) & ~1) * 3; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + const uint8 *pe; + + switch(wt & 1) { + do { + v = src[0]; + + case 0: pe = &pal[3*(v&15)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 4; + case 1: pe = &pal[3*(v&15)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 4; + + dst -= 6; + --src; + } while((wt -= 2) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal4, Any32) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + const uint32 *pal = (const uint32 *)pal0; + + src += (w-1) >> 1; + dst += ((w-1) & ~1); + + srcpitch += (w+1) >> 1; + dstpitch += ((w+1) & ~1) * 4; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + + switch(wt & 1) { + do { + v = src[0]; + + case 0: dst[1] = pal[v&15]; v >>= 4; + case 1: dst[0] = pal[v&15]; v >>= 4; + + dst -= 2; + --src; + } while((wt -= 2) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: Pal8 -> +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_PALETTED(Pal8, Any8) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + srcpitch -= w; + dstpitch -= w; + + do { + int wt = w; + + do { + *dst++ = pal[*src++]; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal8, Any16) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + const uint16 *pal = (const uint16 *)pal0; + + srcpitch -= w; + dstpitch -= w*2; + + do { + int wt = w; + + do { + *dst++ = pal[*src++]; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal8, Any24) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + srcpitch -= w; + dstpitch -= w*3; + + do { + int wt = w; + do { + const uint8 *pe = &pal[3**src++]; + + dst[0] = pe[0]; + dst[1] = pe[1]; + dst[2] = pe[2]; + dst += 3; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal8, Any32) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + const uint32 *pal = (const uint32 *)pal0; + + srcpitch -= w; + dstpitch -= w*4; + + do { + int wt = w; + + do { + *dst++ = pal[*src++]; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_rgb.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_rgb.cpp index 8f7c2df6a18..b3bf695ec8d 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_rgb.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_rgb.cpp @@ -1,329 +1,329 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include - -#define DECLARE_RGB(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: -> XRGB1555 -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_RGB(RGB565, XRGB1555) { - const uint16 *src = (const uint16 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - *dst++ = (px&0x001f) + ((px&0xffc0)>>1); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB888, XRGB1555) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 3*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 r = ((uint32)src[2] & 0xf8) << 7; - const uint32 g = ((uint32)src[1] & 0xf8) << 2; - const uint32 b = (uint32)src[0] >> 3; - src += 3; - - *dst++ = (uint16)(r + g + b); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(XRGB8888, XRGB1555) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 4*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 r = ((uint32)src[2] & 0xf8) << 7; - const uint32 g = ((uint32)src[1] & 0xf8) << 2; - const uint32 b = (uint32)src[0] >> 3; - src += 4; - - *dst++ = (uint16)(r + g + b); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: -> RGB565 -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_RGB(XRGB1555, RGB565) { - const uint16 *src = (const uint16 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - *dst++ = (uint16)(px + (px&0xffe0) + ((px&0x0200)>>4)); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB888, RGB565) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 3*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 r = ((uint32)src[2] & 0xf8) << 8; - const uint32 g = ((uint32)src[1] & 0xfc) << 3; - const uint32 b = (uint32)src[0] >> 3; - src += 3; - - *dst++ = (uint16)(r + g + b); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(XRGB8888, RGB565) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 4*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 r = ((uint32)src[2] & 0xf8) << 8; - const uint32 g = ((uint32)src[1] & 0xfc) << 3; - const uint32 b = (uint32)src[0] >> 3; - src += 4; - - *dst++ = (uint16)(r + g + b); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: -> RGB888 -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_RGB(XRGB1555, RGB888) { - const uint16 *src = (const uint16 *)src0; - uint8 *dst = (uint8 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 3*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - uint32 rb = px & 0x7c1f; - uint32 g = px & 0x03e0; - - rb += rb<<5; - g += g<<5; - - dst[0] = (uint8)(rb>>2); - dst[1] = (uint8)(g>>7); - dst[2] = (uint8)(rb>>12); - dst += 3; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB565, RGB888) { - const uint16 *src = (const uint16 *)src0; - uint8 *dst = (uint8 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 3*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - uint32 rb = px & 0xf81f; - uint32 g = px & 0x07e0; - - rb += rb<<5; - g += g<<6; - - dst[0] = (uint8)(rb>>2); - dst[1] = (uint8)(g>>9); - dst[2] = (uint8)(rb>>13); - dst += 3; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(XRGB8888, RGB888) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - srcpitch -= 4*w; - dstpitch -= 3*w; - - do { - int wt = w; - - do { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst += 3; - src += 4; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: -> XRGB8888 -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_RGB(XRGB1555, XRGB8888) { - const uint16 *src = (const uint16 *)src0; - uint32 *dst = (uint32 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 4*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - const uint32 rgb = ((px & 0x7c00) << 9) + ((px & 0x03e0) << 6) + ((px & 0x001f) << 3); - - *dst++ = rgb + ((rgb & 0xe0e0e0)>>5); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB565, XRGB8888) { - const uint16 *src = (const uint16 *)src0; - uint32 *dst = (uint32 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 4*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - const uint32 rb = ((px & 0xf800) << 8) + ((px & 0x001f) << 3); - const uint32 g = ((px & 0x07e0) << 5) + (px & 0x0300); - - *dst++ = rb + ((rb & 0xe000e0)>>5) + g; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB888, XRGB8888) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - - srcpitch -= 3*w; - dstpitch -= 4*w; - - do { - int wt = w; - - do { - *dst++ = (uint32)src[0] + ((uint32)src[1]<<8) + ((uint32)src[2]<<16); - src += 3; - } while(--wt); - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include + +#define DECLARE_RGB(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: -> XRGB1555 +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_RGB(RGB565, XRGB1555) { + const uint16 *src = (const uint16 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + *dst++ = (px&0x001f) + ((px&0xffc0)>>1); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB888, XRGB1555) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 3*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 r = ((uint32)src[2] & 0xf8) << 7; + const uint32 g = ((uint32)src[1] & 0xf8) << 2; + const uint32 b = (uint32)src[0] >> 3; + src += 3; + + *dst++ = (uint16)(r + g + b); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(XRGB8888, XRGB1555) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 4*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 r = ((uint32)src[2] & 0xf8) << 7; + const uint32 g = ((uint32)src[1] & 0xf8) << 2; + const uint32 b = (uint32)src[0] >> 3; + src += 4; + + *dst++ = (uint16)(r + g + b); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: -> RGB565 +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_RGB(XRGB1555, RGB565) { + const uint16 *src = (const uint16 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + *dst++ = (uint16)(px + (px&0xffe0) + ((px&0x0200)>>4)); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB888, RGB565) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 3*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 r = ((uint32)src[2] & 0xf8) << 8; + const uint32 g = ((uint32)src[1] & 0xfc) << 3; + const uint32 b = (uint32)src[0] >> 3; + src += 3; + + *dst++ = (uint16)(r + g + b); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(XRGB8888, RGB565) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 4*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 r = ((uint32)src[2] & 0xf8) << 8; + const uint32 g = ((uint32)src[1] & 0xfc) << 3; + const uint32 b = (uint32)src[0] >> 3; + src += 4; + + *dst++ = (uint16)(r + g + b); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: -> RGB888 +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_RGB(XRGB1555, RGB888) { + const uint16 *src = (const uint16 *)src0; + uint8 *dst = (uint8 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 3*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + uint32 rb = px & 0x7c1f; + uint32 g = px & 0x03e0; + + rb += rb<<5; + g += g<<5; + + dst[0] = (uint8)(rb>>2); + dst[1] = (uint8)(g>>7); + dst[2] = (uint8)(rb>>12); + dst += 3; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB565, RGB888) { + const uint16 *src = (const uint16 *)src0; + uint8 *dst = (uint8 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 3*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + uint32 rb = px & 0xf81f; + uint32 g = px & 0x07e0; + + rb += rb<<5; + g += g<<6; + + dst[0] = (uint8)(rb>>2); + dst[1] = (uint8)(g>>9); + dst[2] = (uint8)(rb>>13); + dst += 3; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(XRGB8888, RGB888) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + srcpitch -= 4*w; + dstpitch -= 3*w; + + do { + int wt = w; + + do { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst += 3; + src += 4; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: -> XRGB8888 +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_RGB(XRGB1555, XRGB8888) { + const uint16 *src = (const uint16 *)src0; + uint32 *dst = (uint32 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 4*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + const uint32 rgb = ((px & 0x7c00) << 9) + ((px & 0x03e0) << 6) + ((px & 0x001f) << 3); + + *dst++ = rgb + ((rgb & 0xe0e0e0)>>5); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB565, XRGB8888) { + const uint16 *src = (const uint16 *)src0; + uint32 *dst = (uint32 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 4*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + const uint32 rb = ((px & 0xf800) << 8) + ((px & 0x001f) << 3); + const uint32 g = ((px & 0x07e0) << 5) + (px & 0x0300); + + *dst++ = rb + ((rb & 0xe000e0)>>5) + g; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB888, XRGB8888) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + + srcpitch -= 3*w; + dstpitch -= 4*w; + + do { + int wt = w; + + do { + *dst++ = (uint32)src[0] + ((uint32)src[1]<<8) + ((uint32)src[2]<<16); + src += 3; + } while(--wt); + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv.cpp index de6ac77b031..81093f92e7a 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv.cpp @@ -1,1610 +1,1610 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "blt_spanutils.h" - -#ifdef _M_IX86 - #include "blt_spanutils_x86.h" -#endif - -using namespace nsVDPixmapSpanUtils; - -namespace { - struct YCbCrToRGB { - sint16 y_tab[256]; - sint16 r_cr_tab[256]; - sint16 b_cb_tab[256]; - sint16 g_cr_tab[256]; - sint16 g_cb_tab[256]; - uint8 cliptab[277+256+279]; - uint16 cliptab15[277+256+279]; - uint16 cliptab16[277+256+279]; - - YCbCrToRGB() { - int i; - - memset(cliptab, 0, 277); - memset(cliptab+277+256, 255, 279); - - memset(cliptab15, 0, sizeof cliptab15[0] * 277); - memset(cliptab16, 0, sizeof cliptab16[0] * 277); - memset(cliptab15+277+256, 0xff, sizeof cliptab15[0] * 279); - memset(cliptab16+277+256, 0xff, sizeof cliptab16[0] * 279); - - for(i=0; i<256; ++i) { - y_tab[i] = (sint16)(((i-16) * 76309 + 32768) >> 16); - r_cr_tab[i] = (sint16)(((i-128) * 104597 + 32768) >> 16); - b_cb_tab[i] = (sint16)(((i-128) * 132201 + 32768) >> 16); - g_cr_tab[i] = (sint16)(((i-128) * -53279 + 32768) >> 16); - g_cb_tab[i] = (sint16)(((i-128) * -25674 + 32768) >> 16); - cliptab[i+277] = (uint8)i; - cliptab15[i+277] = 0x421 * ((unsigned)i>>3); - cliptab16[i+277] = 0x801 * ((unsigned)i>>3) + 0x20 * ((unsigned)i>>2); - } - } - } static const colorconv; - - struct YCbCrFormatInfo { - ptrdiff_t ystep; - ptrdiff_t cstep; - ptrdiff_t yinc[4]; - ptrdiff_t cinc[4]; - sint8 ypos[4]; - sint8 cbpos[4]; - sint8 crpos[4]; - }; - - YCbCrFormatInfo g_formatInfo_YUV444_Planar = { -4, -4, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,1,2,3}, {0,1,2,3}}; - YCbCrFormatInfo g_formatInfo_YUV422_YUYV = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,2,4,6}, {1,1,5,5}, {3,3,7,7}}; - YCbCrFormatInfo g_formatInfo_YUV422_UYVY = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {1,3,5,7}, {0,0,4,4}, {2,2,6,6}}; - YCbCrFormatInfo g_formatInfo_YUV420_YV12 = { -4, -2, {-1,-1,-1,-1}, { 0,-1, 0,-1}, {0,1,2,3}, {0,0,1,1}, {0,0,1,1}}; - YCbCrFormatInfo g_formatInfo_YUV411_YV12 = { -4, -1, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,0,0,0}, {0,0,0,0}}; - - inline uint16 ycbcr_to_1555(uint8 y, uint8 cb0, uint8 cr0) { - const uint16 *p = &colorconv.cliptab15[277 + colorconv.y_tab[y]]; - uint32 r = 0x7c00 & p[colorconv.r_cr_tab[cr0]]; - uint32 g = 0x03e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; - uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]]; - - return r + g + b; - } - - inline uint16 ycbcr_to_565(uint8 y, uint8 cb0, uint8 cr0) { - const uint16 *p = &colorconv.cliptab16[277 + colorconv.y_tab[y]]; - uint32 r = 0xf800 & p[colorconv.r_cr_tab[cr0]]; - uint32 g = 0x07e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; - uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]]; - - return r + g + b; - } - - inline void ycbcr_to_888(uint8 *dst, uint8 y, uint8 cb0, uint8 cr0) { - const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]]; - uint8 r = p[colorconv.r_cr_tab[cr0]]; - uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; - uint8 b = p[colorconv.b_cb_tab[cb0]]; - - dst[0] = b; - dst[1] = g; - dst[2] = r; - } - - inline uint32 ycbcr_to_8888(uint8 y, uint8 cb0, uint8 cr0) { - const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]]; - uint8 r = p[colorconv.r_cr_tab[cr0]]; - uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; - uint8 b = p[colorconv.b_cb_tab[cb0]]; - - return (r << 16) + (g << 8) + b; - } - - void VDYCbCrToXRGB1555Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint16 *dst = (uint16 *)dst0; - - do { - *dst++ = ycbcr_to_1555(*y++, *cb++, *cr++); - } while(--w); - } - - void VDYCbCrToRGB565Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint16 *dst = (uint16 *)dst0; - - do { - *dst++ = ycbcr_to_565(*y++, *cb++, *cr++); - } while(--w); - } - - void VDYCbCrToRGB888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint8 *dst = (uint8 *)dst0; - - do { - ycbcr_to_888(dst, *y++, *cb++, *cr++); - dst += 3; - } while(--w); - } - - void VDYCbCrToXRGB8888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint32 *dst = (uint32 *)dst0; - - do { - *dst++ = ycbcr_to_8888(*y++, *cb++, *cr++); - } while(--w); - } - - void VDYCbCrToUYVYSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint32 *dst = (uint32 *)dst0; - - if (--w) { - do { - *dst++ = (uint32)*cb++ + ((uint32)y[0] << 8) + ((uint32)*cr++ << 16) + ((uint32)y[1] << 24); - y += 2; - } while((sint32)(w-=2)>0); - } - - if (!(w & 1)) - *dst++ = (uint32)*cb + ((uint32)y[0] << 8) + ((uint32)*cr << 16) + ((uint32)y[0] << 24); - } - - void VDYCbCrToYUYVSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint32 *dst = (uint32 *)dst0; - - if (--w) { - do { - *dst++ = (uint32)y[0] + ((uint32)*cb++ << 8) + ((uint32)y[1] << 16) + ((uint32)*cr++ << 24); - y += 2; - } while((sint32)(w-=2)>0); - } - - if (!(w & 1)) - *dst++ = (uint32)y[0] + ((uint32)*cb << 8) + ((uint32)y[0] << 16) + ((uint32)*cr << 24); - } - - void VDYCbCrToRGB1555Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { - const ptrdiff_t ystep = formatinfo.ystep; - const ptrdiff_t cstep = formatinfo.cstep; - const ptrdiff_t ypos0 = formatinfo.ypos[0]; - const ptrdiff_t ypos1 = formatinfo.ypos[1]; - const ptrdiff_t ypos2 = formatinfo.ypos[2]; - const ptrdiff_t ypos3 = formatinfo.ypos[3]; - const ptrdiff_t crpos0 = formatinfo.crpos[0]; - const ptrdiff_t crpos1 = formatinfo.crpos[1]; - const ptrdiff_t crpos2 = formatinfo.crpos[2]; - const ptrdiff_t crpos3 = formatinfo.crpos[3]; - const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; - const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; - const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; - const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; - - yrow = (char *)yrow - ystep * ((w-1) >> 2); - crrow = (char *)crrow - cstep * ((w-1) >> 2); - cbrow = (char *)cbrow - cstep * ((w-1) >> 2); - dst = (char *)dst + 2*((w-1) & ~3); - - int y = 0; - do { - const uint8 *ysrc = (const uint8 *)yrow; - const uint8 *crsrc = (const uint8 *)crrow; - const uint8 *cbsrc = (const uint8 *)cbrow; - uint16 *out = (uint16 *)dst; - int w2 = -w; - - switch(w2 & 3) { - do { - case 0: out[3] = ycbcr_to_1555(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); - case 1: out[2] = ycbcr_to_1555(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); - case 2: out[1] = ycbcr_to_1555(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); - case 3: out[0] = ycbcr_to_1555(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); - out -= 4; - ysrc += ystep; - crsrc += cstep; - cbsrc += cstep; - } while((w2 += 4) < 0); - } - - dst = (char *)dst + dststride; - yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); - cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); - crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); - } while(++y < h); - } - - void VDYCbCrToRGB565Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { - const ptrdiff_t ystep = formatinfo.ystep; - const ptrdiff_t cstep = formatinfo.cstep; - const ptrdiff_t ypos0 = formatinfo.ypos[0]; - const ptrdiff_t ypos1 = formatinfo.ypos[1]; - const ptrdiff_t ypos2 = formatinfo.ypos[2]; - const ptrdiff_t ypos3 = formatinfo.ypos[3]; - const ptrdiff_t crpos0 = formatinfo.crpos[0]; - const ptrdiff_t crpos1 = formatinfo.crpos[1]; - const ptrdiff_t crpos2 = formatinfo.crpos[2]; - const ptrdiff_t crpos3 = formatinfo.crpos[3]; - const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; - const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; - const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; - const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; - - yrow = (char *)yrow - ystep * ((w-1) >> 2); - crrow = (char *)crrow - cstep * ((w-1) >> 2); - cbrow = (char *)cbrow - cstep * ((w-1) >> 2); - dst = (char *)dst + 2*((w-1) & ~3); - - int y = 0; - do { - const uint8 *ysrc = (const uint8 *)yrow; - const uint8 *crsrc = (const uint8 *)crrow; - const uint8 *cbsrc = (const uint8 *)cbrow; - uint16 *out = (uint16 *)dst; - int w2 = -w; - - switch(w2 & 3) { - do { - case 0: out[3] = ycbcr_to_565(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); - case 1: out[2] = ycbcr_to_565(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); - case 2: out[1] = ycbcr_to_565(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); - case 3: out[0] = ycbcr_to_565(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); - out -= 4; - ysrc += ystep; - crsrc += cstep; - cbsrc += cstep; - } while((w2 += 4) < 0); - } - - dst = (char *)dst + dststride; - yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); - cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); - crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); - } while(++y < h); - } - - void VDYCbCrToRGB888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { - const ptrdiff_t ystep = formatinfo.ystep; - const ptrdiff_t cstep = formatinfo.cstep; - const ptrdiff_t ypos0 = formatinfo.ypos[0]; - const ptrdiff_t ypos1 = formatinfo.ypos[1]; - const ptrdiff_t ypos2 = formatinfo.ypos[2]; - const ptrdiff_t ypos3 = formatinfo.ypos[3]; - const ptrdiff_t crpos0 = formatinfo.crpos[0]; - const ptrdiff_t crpos1 = formatinfo.crpos[1]; - const ptrdiff_t crpos2 = formatinfo.crpos[2]; - const ptrdiff_t crpos3 = formatinfo.crpos[3]; - const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; - const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; - const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; - const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; - - yrow = (char *)yrow - ystep * ((w-1) >> 2); - crrow = (char *)crrow - cstep * ((w-1) >> 2); - cbrow = (char *)cbrow - cstep * ((w-1) >> 2); - dst = (char *)dst + 3*((w-1) & ~3); - - int y = 0; - do { - const uint8 *ysrc = (const uint8 *)yrow; - const uint8 *crsrc = (const uint8 *)crrow; - const uint8 *cbsrc = (const uint8 *)cbrow; - uint8 *out = (uint8 *)dst; - int w2 = -w; - - switch(w2 & 3) { - do { - case 0: ycbcr_to_888(out+9, ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); - case 1: ycbcr_to_888(out+6, ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); - case 2: ycbcr_to_888(out+3, ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); - case 3: ycbcr_to_888(out, ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); - out -= 12; - ysrc += ystep; - crsrc += cstep; - cbsrc += cstep; - } while((w2 += 4) < 0); - } - - dst = (char *)dst + dststride; - yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); - cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); - crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); - } while(++y < h); - } - - void VDYCbCrToRGB8888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { - const ptrdiff_t ystep = formatinfo.ystep; - const ptrdiff_t cstep = formatinfo.cstep; - const ptrdiff_t ypos0 = formatinfo.ypos[0]; - const ptrdiff_t ypos1 = formatinfo.ypos[1]; - const ptrdiff_t ypos2 = formatinfo.ypos[2]; - const ptrdiff_t ypos3 = formatinfo.ypos[3]; - const ptrdiff_t crpos0 = formatinfo.crpos[0]; - const ptrdiff_t crpos1 = formatinfo.crpos[1]; - const ptrdiff_t crpos2 = formatinfo.crpos[2]; - const ptrdiff_t crpos3 = formatinfo.crpos[3]; - const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; - const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; - const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; - const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; - - yrow = (char *)yrow - ystep * ((w-1) >> 2); - crrow = (char *)crrow - cstep * ((w-1) >> 2); - cbrow = (char *)cbrow - cstep * ((w-1) >> 2); - dst = (char *)dst + 4*((w-1) & ~3); - - int y = 0; - do { - const uint8 *ysrc = (const uint8 *)yrow; - const uint8 *crsrc = (const uint8 *)crrow; - const uint8 *cbsrc = (const uint8 *)cbrow; - uint32 *out = (uint32 *)dst; - int w2 = -w; - - switch(w2 & 3) { - do { - case 0: out[3] = ycbcr_to_8888(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); - case 1: out[2] = ycbcr_to_8888(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); - case 2: out[1] = ycbcr_to_8888(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); - case 3: out[0] = ycbcr_to_8888(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); - out -= 4; - ysrc += ystep; - crsrc += cstep; - cbsrc += cstep; - } while((w2 += 4) < 0); - } - - dst = (char *)dst + dststride; - yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); - cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); - crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); - } while(++y < h); - } -} - -#define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) - -DECLARE_YUV(UYVY, XRGB1555) { - do { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint16 *y; - - cb = src[0]; - cr = src[2]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[1]]]; - *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[4]; - cr = src[6]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]]; - dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f); - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[5]]]; - dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - - dst += 2; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]]; - *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, RGB565) { - do { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint16 *y; - - cb = src[0]; - cr = src[2]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[1]]]; - *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[4]; - cr = src[6]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]]; - dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f); - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[5]]]; - dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - - dst += 2; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]]; - *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, RGB888) { - do { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint8 *y; - - cb = src[0]; - cr = src[2]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - dst += 3; - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[4]; - cr = src[6]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; - dst[0] = y[(bc0+bc1+1)>>1]; - dst[1] = y[(gc0+gc1+1)>>1]; - dst[2] = y[(rc0+rc1+1)>>1]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]]; - dst[3] = y[bc1]; - dst[4] = y[gc1]; - dst[5] = y[rc1]; - - dst += 6; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, XRGB8888) { - do { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint8 *y; - - cb = src[0]; - cr = src[2]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - dst += 4; - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[4]; - cr = src[6]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; - dst[0] = y[(bc0+bc1+1)>>1]; - dst[1] = y[(gc0+gc1+1)>>1]; - dst[2] = y[(rc0+rc1+1)>>1]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]]; - dst[4] = y[bc1]; - dst[5] = y[gc1]; - dst[6] = y[rc1]; - - dst += 8; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, XRGB1555) { - do { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint16 *y; - - cb = src[1]; - cr = src[3]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[0]]]; - *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[5]; - cr = src[7]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]]; - dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f); - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[4]]]; - dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - - dst += 2; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]]; - *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, RGB565) { - do { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint16 *y; - - cb = src[1]; - cr = src[3]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[0]]]; - *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[5]; - cr = src[7]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]]; - dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f); - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[4]]]; - dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - - dst += 2; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]]; - *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, RGB888) { - do { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint8 *y; - - cb = src[1]; - cr = src[3]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - dst += 3; - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[5]; - cr = src[7]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; - dst[0] = y[(bc0+bc1+1)>>1]; - dst[1] = y[(gc0+gc1+1)>>1]; - dst[2] = y[(rc0+rc1+1)>>1]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]]; - dst[3] = y[bc1]; - dst[4] = y[gc1]; - dst[5] = y[rc1]; - - dst += 6; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, XRGB8888) { - do { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint8 *y; - - cb = src[1]; - cr = src[3]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - dst += 4; - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[5]; - cr = src[7]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; - dst[0] = y[(bc0+bc1+1)>>1]; - dst[1] = y[(gc0+gc1+1)>>1]; - dst[2] = y[(rc0+rc1+1)>>1]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]]; - dst[4] = y[bc1]; - dst[5] = y[gc1]; - dst[6] = y[rc1]; - - dst += 8; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, XRGB1555) { - uint16 *dst = (uint16 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 2*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = colorconv.cliptab15[colorconv.y_tab[*src++] + 277]; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, RGB565) { - uint16 *dst = (uint16 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 2*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = colorconv.cliptab16[colorconv.y_tab[*src++] + 277]; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, RGB888) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 3*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - dst[0] = dst[1] = dst[2] = colorconv.cliptab[colorconv.y_tab[*src++] + 277]; - dst += 3; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, XRGB8888) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 4*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = 0x010101 * colorconv.cliptab[colorconv.y_tab[*src++] + 277]; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -#define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) - - -namespace { - typedef void (*tpYUVPlanarFinalDecoder)(void *, const uint8 *, const uint8 *, const uint8 *, uint32); - typedef void (*tpYUVPlanarHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w); - typedef void (*tpYUVPlanarVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); -} - -#ifdef _M_IX86 - extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); - extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); - extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); -#endif - - -void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); - int hbits = srcinfo.auxwbits; - int vbits = srcinfo.auxhbits; - - if (src.format == nsVDPixmap::kPixFormat_YUV422_UYVY || src.format == nsVDPixmap::kPixFormat_YUV422_YUYV) - hbits = 1; - - bool h_coaligned = true; - bool v_coaligned = false; - - if (src.format == nsVDPixmap::kPixFormat_YUV422_Planar_Centered || - src.format == nsVDPixmap::kPixFormat_YUV420_Planar_Centered) { - h_coaligned = false; - } - - tpYUVPlanarVertDecoder vfunc = NULL; - tpYUVPlanarHorizDecoder hfunc = NULL; - uint32 horiz_buffer_size = 0; - uint32 vert_buffer_size = 0; - uint32 horiz_count = 0; - sint32 yaccum = 8; - sint32 yinc = 8; - uint32 yleft = h; - - switch(vbits*2+v_coaligned) { - case 0: // 4:4:4, 4:2:2 - case 1: - break; - case 2: // 4:2:0 (centered) - vfunc = vert_expand2x_centered; - vert_buffer_size = w>>1; - yaccum = 6; - yinc = 4; - yleft >>= 1; - break; - case 4: // 4:1:0 (centered) - vfunc = vert_expand4x_centered; - vert_buffer_size = w>>2; - yaccum = 5; - yinc = 2; - yleft >>= 2; - break; - default: - VDNEVERHERE; - return; - } - - --yleft; - - tpYUVPlanarFinalDecoder dfunc = NULL; - -#ifdef _M_IX86 - uint32 cpuflags = CPUGetEnabledExtensions(); - - if (cpuflags & CPUF_SUPPORTS_MMX) { - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (vfunc == vert_expand2x_centered) - vfunc = vert_expand2x_centered_ISSE; - } - - switch(dst.format) { - case nsVDPixmap::kPixFormat_XRGB1555: dfunc = vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX; break; - case nsVDPixmap::kPixFormat_RGB565: dfunc = vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX; break; - case nsVDPixmap::kPixFormat_XRGB8888: dfunc = vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX; break; - } - } -#endif - - bool halfchroma = false; - - if (!dfunc) { - switch(dst.format) { - case nsVDPixmap::kPixFormat_XRGB1555: dfunc = VDYCbCrToXRGB1555Span; break; - case nsVDPixmap::kPixFormat_RGB565: dfunc = VDYCbCrToRGB565Span; break; - case nsVDPixmap::kPixFormat_RGB888: dfunc = VDYCbCrToRGB888Span; break; - case nsVDPixmap::kPixFormat_XRGB8888: dfunc = VDYCbCrToXRGB8888Span; break; - case nsVDPixmap::kPixFormat_YUV422_UYVY: dfunc = VDYCbCrToUYVYSpan; halfchroma = true; break; - case nsVDPixmap::kPixFormat_YUV422_YUYV: dfunc = VDYCbCrToYUYVSpan; halfchroma = true; break; - default: - VDNEVERHERE; - return; - } - } - - switch(hbits*2+h_coaligned) { - case 0: // 4:4:4 - case 1: - if (halfchroma) { - hfunc = horiz_compress2x_coaligned; - horiz_buffer_size = (w + 1) >> 1; - horiz_count = w; - } - break; - case 2: // 4:2:0 MPEG-1 (centered) - if (halfchroma) { - hfunc = horiz_realign_to_coaligned; - horiz_buffer_size = (w + 1) >> 1; - horiz_count = (w + 1) >> 1; - } else { - hfunc = horiz_expand2x_centered; - horiz_buffer_size = w; - horiz_count = w; - } - break; - case 3: // 4:2:0/4:2:2 MPEG-2 (coaligned) - if (!halfchroma) { - hfunc = horiz_expand2x_coaligned; - horiz_buffer_size = w; - horiz_count = w; - } - break; - case 5: // 4:1:1 (coaligned) - if (halfchroma) { - hfunc = horiz_expand2x_coaligned; - horiz_buffer_size = (w + 1) >> 1; - horiz_count = (w + 1) >> 1; - } else { - hfunc = horiz_expand4x_coaligned; - horiz_buffer_size = w; - horiz_count = w; - } - break; - - default: - VDNEVERHERE; - return; - } - -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (hfunc == horiz_expand2x_coaligned) - hfunc = horiz_expand2x_coaligned_ISSE; - } -#endif - - uint32 chroma_srcwidth = -(-w >> srcinfo.auxwbits); - horiz_buffer_size = (horiz_buffer_size + 15) & ~15; - vert_buffer_size = (vert_buffer_size + 15) & ~15; - - // allocate buffers - - vdblock tempbuf((horiz_buffer_size + vert_buffer_size)*2 + 1); - - uint8 *const crbufh = tempbuf.data(); - uint8 *const crbufv = crbufh + horiz_buffer_size; - uint8 *const cbbufh = crbufv + vert_buffer_size; - uint8 *const cbbufv = cbbufh + horiz_buffer_size; - - const uint8 *cb0 = (const uint8*)src.data2; - const uint8 *cr0 = (const uint8*)src.data3; - const uint8 *cb1 = cb0; - const uint8 *cr1 = cr0; - const uint8 *y = (const uint8 *)src.data; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - void *out = dst.data; - ptrdiff_t outpitch = dst.pitch; - - for(;;) { - if (yaccum >= 8) { - yaccum &= 7; - - cb0 = cb1; - cr0 = cr1; - - if (yleft > 0) { - --yleft; - vdptrstep(cb1, cbpitch); - vdptrstep(cr1, crpitch); - } - } - - const uint8 *cr = cr0; - const uint8 *cb = cb0; - - // vertical interpolation: cr - if(yaccum & 7) { - const uint8 *const srcs[2]={cr0, cr1}; - vfunc(crbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5); - cr = crbufv; - } - - // horizontal interpolation: cr - if (hfunc) { - hfunc(crbufh, cr, horiz_count); - cr = crbufh; - } - - // vertical interpolation: cb - if(yaccum & 7) { - const uint8 *const srcs[2]={cb0, cb1}; - vfunc(cbbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5); - cb = cbbufv; - } - - // horizontal interpolation: cb - if (hfunc) { - hfunc(cbbufh, cb, horiz_count); - cb = cbbufh; - } - - dfunc(out, y, cb, cr, w); - vdptrstep(out, outpitch); - vdptrstep(y, ypitch); - - if (!--h) - break; - - yaccum += yinc; - } - -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_MMX) { - _mm_empty(); - } -#endif -} - -namespace { - typedef void (*tpUVBltHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w); - typedef void (*tpUVBltVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); - - void uvplaneblt(uint8 *dst, ptrdiff_t dstpitch, int dstformat, const uint8 *src, ptrdiff_t srcpitch, int srcformat, vdpixsize w, vdpixsize h) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(srcformat); - const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dstformat); - - int xshift = srcinfo.auxwbits - dstinfo.auxwbits; - int yshift = srcinfo.auxhbits - dstinfo.auxhbits; - - tpUVBltHorizDecoder hfunc = NULL; - tpUVBltVertDecoder vfunc = NULL; - - switch(xshift) { - case +2: - hfunc = horiz_expand4x_coaligned; - break; - case +1: - hfunc = horiz_expand2x_coaligned; - break; - case 0: - break; - case -1: - hfunc = horiz_compress2x_coaligned; - break; - case -2: - hfunc = horiz_compress4x_coaligned; - break; - default: - VDNEVERHERE; - return; - } - -#ifdef _M_IX86 - uint32 cpuflags = CPUGetEnabledExtensions(); - - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (hfunc == horiz_expand2x_coaligned) - hfunc = horiz_expand2x_coaligned_ISSE; - } -#endif - - int winsize, winposnext, winstep; - - switch(yshift) { - case +2: - vfunc = vert_expand4x_centered; - winsize = 2; - winposnext = 0xa0; - winstep = 0x40; - break; - case +1: - vfunc = vert_expand2x_centered; - winsize = 2; - winposnext = 0xc0; - winstep = 0x80; - break; - case 0: - winsize = 1; - winposnext = 0; - winstep = 0x100; - break; - case -1: - vfunc = vert_compress2x_centered; - winsize = 4; - winposnext = 0x200; - winstep = 0x200; - break; - case -2: - vfunc = vert_compress4x_centered; - winsize = 8; - winposnext = 0x500; - winstep = 0x400; - break; - default: - VDNEVERHERE; - return; - } - -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (vfunc == vert_expand2x_centered) - vfunc = vert_expand2x_centered_ISSE; - } -#endif - - int dsth = -(-h >> dstinfo.auxhbits); - int srch = -(-h >> srcinfo.auxhbits); - int dstw = -(-w >> dstinfo.auxwbits); - int w2 = -(-w >> std::min(dstinfo.auxwbits, srcinfo.auxwbits)); - - int winpos = (winposnext>>8) - winsize; - - const uint8 *window[16]; - - vdblock tmpbuf; - ptrdiff_t tmppitch = (w+15) & ~15; - - if (vfunc && hfunc) - tmpbuf.resize(tmppitch * winsize); - - do { - int desiredpos = winposnext >> 8; - - while(winpos < desiredpos) { - const uint8 *srcrow = vdptroffset(src, srcpitch * std::max(0, std::min(srch-1, ++winpos))); - int winoffset = (winpos-1) & (winsize-1); - - if (hfunc) { - uint8 *dstrow = vfunc ? tmpbuf.data() + tmppitch * winoffset : dst; - hfunc(dstrow, srcrow, w2); - srcrow = dstrow; - } - - window[winoffset] = window[winoffset + winsize] = srcrow; - } - - if (vfunc) - vfunc(dst, window + (winpos & (winsize-1)), dstw, winposnext & 255); - else if (!hfunc) - memcpy(dst, window[winpos & (winsize-1)], dstw); - - winposnext += winstep; - vdptrstep(dst, dstpitch); - } while(--dsth); - -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_MMX) { - _mm_empty(); - } -#endif - } -} - -void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dstpm, const VDPixmap& srcpm, vdpixsize w, vdpixsize h) { - VDMemcpyRect(dstpm.data, dstpm.pitch, srcpm.data, srcpm.pitch, dstpm.w, dstpm.h); - - if (srcpm.format != nsVDPixmap::kPixFormat_Y8) { - if (dstpm.format != nsVDPixmap::kPixFormat_Y8) { - // YCbCr -> YCbCr - uvplaneblt((uint8 *)dstpm.data2, dstpm.pitch2, dstpm.format, (uint8 *)srcpm.data2, srcpm.pitch2, srcpm.format, w, h); - uvplaneblt((uint8 *)dstpm.data3, dstpm.pitch3, dstpm.format, (uint8 *)srcpm.data3, srcpm.pitch3, srcpm.format, w, h); - } - } else { - if (dstpm.format != nsVDPixmap::kPixFormat_Y8) { - const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstpm.format); - VDMemset8Rect(dstpm.data2, dstpm.pitch2, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits)); - VDMemset8Rect(dstpm.data3, dstpm.pitch3, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits)); - } - } -} - -extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); - -DECLARE_YUV_PLANAR(YUV411, XRGB1555) { - uint16 *out = (uint16 *)dst.data; - const ptrdiff_t opitch = dst.pitch; - const uint8 *yrow = (const uint8 *)src.data; - const uint8 *cbrow = (const uint8 *)src.data2; - const uint8 *crrow = (const uint8 *)src.data3; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - vdpixsize wpairs = (w-1)>>2; - vdpixsize wleft = w - (wpairs<<2); - - do { - uint16 *p = out; - const uint8 *y = yrow; - const uint8 *cb = cbrow; - const uint8 *cr = crrow; - vdpixsize wt; - - if (wpairs > 0) { -#if !defined(VD_CPU_X86) - wt = wpairs; - - do { - const unsigned cb0 = cb[0]; - const unsigned cb1 = cb[1]; - const unsigned cr0 = cr[0]; - const unsigned cr1 = cr[1]; - - p[0] = ycbcr_to_1555(y[0], cb0, cr0); - p[1] = ycbcr_to_1555(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); - p[2] = ycbcr_to_1555(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); - p[3] = ycbcr_to_1555(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); - - y += 4; - p += 4; - ++cb; - ++cr; - } while(--wt); -#else - vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(p, y, cb, cr, wpairs); - y += 4*wpairs; - cr += wpairs; - cb += wpairs; - p += 4*wpairs; -#endif - } - - if (wleft > 0) { - wt = wleft; - - const uint8 cr0 = *cr; - const uint8 cb0 = *cb; - - do { - *p++ = ycbcr_to_1555(*y++, cb0, cr0); - } while(--wt); - } - - vdptrstep(out, opitch); - vdptrstep(yrow, ypitch); - vdptrstep(cbrow, cbpitch); - vdptrstep(crrow, crpitch); - } while(--h); - -#ifdef VD_CPU_X86 - _mm_empty(); -#endif -} - -DECLARE_YUV_PLANAR(YUV411, RGB565) { - uint16 *out = (uint16 *)dst.data; - const ptrdiff_t opitch = dst.pitch; - const uint8 *yrow = (const uint8 *)src.data; - const uint8 *cbrow = (const uint8 *)src.data2; - const uint8 *crrow = (const uint8 *)src.data3; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - vdpixsize wpairs = (w-1)>>2; - vdpixsize wleft = w - (wpairs<<2); - - do { - uint16 *p = out; - const uint8 *y = yrow; - const uint8 *cb = cbrow; - const uint8 *cr = crrow; - vdpixsize wt; - - if (wpairs > 0) { -#if !defined(VD_CPU_X86) - wt = wpairs; - - do { - const unsigned cb0 = cb[0]; - const unsigned cb1 = cb[1]; - const unsigned cr0 = cr[0]; - const unsigned cr1 = cr[1]; - - p[0] = ycbcr_to_565(y[0], cb0, cr0); - p[1] = ycbcr_to_565(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); - p[2] = ycbcr_to_565(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); - p[3] = ycbcr_to_565(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); - - y += 4; - p += 4; - ++cb; - ++cr; - } while(--wt); -#else - vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(p, y, cb, cr, wpairs); -#endif - } - - if (wleft > 0) { - wt = wleft; - - const uint8 cr0 = *cr; - const uint8 cb0 = *cb; - - do { - *p++ = ycbcr_to_565(*y++, cb0, cr0); - } while(--wt); - } - - vdptrstep(out, opitch); - vdptrstep(yrow, ypitch); - vdptrstep(cbrow, cbpitch); - vdptrstep(crrow, crpitch); - } while(--h); - -#ifdef VD_CPU_X86 - _mm_empty(); -#endif -} - -DECLARE_YUV_PLANAR(YUV411, RGB888) { - uint8 *out = (uint8 *)dst.data; - const ptrdiff_t opitch = dst.pitch; - const uint8 *yrow = (const uint8 *)src.data; - const uint8 *cbrow = (const uint8 *)src.data2; - const uint8 *crrow = (const uint8 *)src.data3; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - vdpixsize wpairs = (w-1)>>2; - vdpixsize wleft = w - (wpairs<<2); - - do { - uint8 *p = out; - const uint8 *y = yrow; - const uint8 *cb = cbrow; - const uint8 *cr = crrow; - vdpixsize wt; - - if (wpairs > 0) { - wt = wpairs; - - do { - const unsigned cb0 = cb[0]; - const unsigned cb1 = cb[1]; - const unsigned cr0 = cr[0]; - const unsigned cr1 = cr[1]; - - ycbcr_to_888(p+0, y[0], cb0, cr0); - ycbcr_to_888(p+3, y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); - ycbcr_to_888(p+6, y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); - ycbcr_to_888(p+9, y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); - - y += 4; - p += 12; - ++cb; - ++cr; - } while(--wt); - } - - if (wleft > 0) { - wt = wleft; - - const uint8 cr0 = *cr; - const uint8 cb0 = *cb; - - do { - ycbcr_to_888(p, *y++, cb0, cr0); - p += 4; - } while(--wt); - } - - vdptrstep(out, opitch); - vdptrstep(yrow, ypitch); - vdptrstep(cbrow, cbpitch); - vdptrstep(crrow, crpitch); - } while(--h); -} - -DECLARE_YUV_PLANAR(YUV411, XRGB8888) { - uint32 *out = (uint32 *)dst.data; - const ptrdiff_t opitch = dst.pitch; - const uint8 *yrow = (const uint8 *)src.data; - const uint8 *cbrow = (const uint8 *)src.data2; - const uint8 *crrow = (const uint8 *)src.data3; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - vdpixsize wpairs = (w-1)>>2; - vdpixsize wleft = w - (wpairs<<2); - - do { - uint32 *p = out; - const uint8 *y = yrow; - const uint8 *cb = cbrow; - const uint8 *cr = crrow; - vdpixsize wt; - - if (wpairs > 0) { -#if !defined(VD_CPU_X86) - wt = wpairs; - - do { - const unsigned cb0 = cb[0]; - const unsigned cb1 = cb[1]; - const unsigned cr0 = cr[0]; - const unsigned cr1 = cr[1]; - - p[0] = ycbcr_to_8888(y[0], cb0, cr0); - p[1] = ycbcr_to_8888(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); - p[2] = ycbcr_to_8888(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); - p[3] = ycbcr_to_8888(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); - - y += 4; - p += 4; - ++cb; - ++cr; - } while(--wt); -#else - vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(p, y, cb, cr, wpairs); - y += 4*wpairs; - cr += wpairs; - cb += wpairs; - p += 4*wpairs; -#endif - } - - if (wleft > 0) { - wt = wleft; - - const uint8 cr0 = *cr; - const uint8 cb0 = *cb; - - do { - *p++ = ycbcr_to_8888(*y++, cb0, cr0); - } while(--wt); - } - - vdptrstep(out, opitch); - vdptrstep(yrow, ypitch); - vdptrstep(cbrow, cbpitch); - vdptrstep(crrow, crpitch); - } while(--h); - -#ifdef VD_CPU_X86 - _mm_empty(); -#endif -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "blt_spanutils.h" + +#ifdef _M_IX86 + #include "blt_spanutils_x86.h" +#endif + +using namespace nsVDPixmapSpanUtils; + +namespace { + struct YCbCrToRGB { + sint16 y_tab[256]; + sint16 r_cr_tab[256]; + sint16 b_cb_tab[256]; + sint16 g_cr_tab[256]; + sint16 g_cb_tab[256]; + uint8 cliptab[277+256+279]; + uint16 cliptab15[277+256+279]; + uint16 cliptab16[277+256+279]; + + YCbCrToRGB() { + int i; + + memset(cliptab, 0, 277); + memset(cliptab+277+256, 255, 279); + + memset(cliptab15, 0, sizeof cliptab15[0] * 277); + memset(cliptab16, 0, sizeof cliptab16[0] * 277); + memset(cliptab15+277+256, 0xff, sizeof cliptab15[0] * 279); + memset(cliptab16+277+256, 0xff, sizeof cliptab16[0] * 279); + + for(i=0; i<256; ++i) { + y_tab[i] = (sint16)(((i-16) * 76309 + 32768) >> 16); + r_cr_tab[i] = (sint16)(((i-128) * 104597 + 32768) >> 16); + b_cb_tab[i] = (sint16)(((i-128) * 132201 + 32768) >> 16); + g_cr_tab[i] = (sint16)(((i-128) * -53279 + 32768) >> 16); + g_cb_tab[i] = (sint16)(((i-128) * -25674 + 32768) >> 16); + cliptab[i+277] = (uint8)i; + cliptab15[i+277] = 0x421 * ((unsigned)i>>3); + cliptab16[i+277] = 0x801 * ((unsigned)i>>3) + 0x20 * ((unsigned)i>>2); + } + } + } static const colorconv; + + struct YCbCrFormatInfo { + ptrdiff_t ystep; + ptrdiff_t cstep; + ptrdiff_t yinc[4]; + ptrdiff_t cinc[4]; + sint8 ypos[4]; + sint8 cbpos[4]; + sint8 crpos[4]; + }; + + YCbCrFormatInfo g_formatInfo_YUV444_Planar = { -4, -4, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,1,2,3}, {0,1,2,3}}; + YCbCrFormatInfo g_formatInfo_YUV422_YUYV = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,2,4,6}, {1,1,5,5}, {3,3,7,7}}; + YCbCrFormatInfo g_formatInfo_YUV422_UYVY = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {1,3,5,7}, {0,0,4,4}, {2,2,6,6}}; + YCbCrFormatInfo g_formatInfo_YUV420_YV12 = { -4, -2, {-1,-1,-1,-1}, { 0,-1, 0,-1}, {0,1,2,3}, {0,0,1,1}, {0,0,1,1}}; + YCbCrFormatInfo g_formatInfo_YUV411_YV12 = { -4, -1, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,0,0,0}, {0,0,0,0}}; + + inline uint16 ycbcr_to_1555(uint8 y, uint8 cb0, uint8 cr0) { + const uint16 *p = &colorconv.cliptab15[277 + colorconv.y_tab[y]]; + uint32 r = 0x7c00 & p[colorconv.r_cr_tab[cr0]]; + uint32 g = 0x03e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; + uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]]; + + return r + g + b; + } + + inline uint16 ycbcr_to_565(uint8 y, uint8 cb0, uint8 cr0) { + const uint16 *p = &colorconv.cliptab16[277 + colorconv.y_tab[y]]; + uint32 r = 0xf800 & p[colorconv.r_cr_tab[cr0]]; + uint32 g = 0x07e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; + uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]]; + + return r + g + b; + } + + inline void ycbcr_to_888(uint8 *dst, uint8 y, uint8 cb0, uint8 cr0) { + const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]]; + uint8 r = p[colorconv.r_cr_tab[cr0]]; + uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; + uint8 b = p[colorconv.b_cb_tab[cb0]]; + + dst[0] = b; + dst[1] = g; + dst[2] = r; + } + + inline uint32 ycbcr_to_8888(uint8 y, uint8 cb0, uint8 cr0) { + const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]]; + uint8 r = p[colorconv.r_cr_tab[cr0]]; + uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; + uint8 b = p[colorconv.b_cb_tab[cb0]]; + + return (r << 16) + (g << 8) + b; + } + + void VDYCbCrToXRGB1555Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint16 *dst = (uint16 *)dst0; + + do { + *dst++ = ycbcr_to_1555(*y++, *cb++, *cr++); + } while(--w); + } + + void VDYCbCrToRGB565Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint16 *dst = (uint16 *)dst0; + + do { + *dst++ = ycbcr_to_565(*y++, *cb++, *cr++); + } while(--w); + } + + void VDYCbCrToRGB888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint8 *dst = (uint8 *)dst0; + + do { + ycbcr_to_888(dst, *y++, *cb++, *cr++); + dst += 3; + } while(--w); + } + + void VDYCbCrToXRGB8888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint32 *dst = (uint32 *)dst0; + + do { + *dst++ = ycbcr_to_8888(*y++, *cb++, *cr++); + } while(--w); + } + + void VDYCbCrToUYVYSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint32 *dst = (uint32 *)dst0; + + if (--w) { + do { + *dst++ = (uint32)*cb++ + ((uint32)y[0] << 8) + ((uint32)*cr++ << 16) + ((uint32)y[1] << 24); + y += 2; + } while((sint32)(w-=2)>0); + } + + if (!(w & 1)) + *dst++ = (uint32)*cb + ((uint32)y[0] << 8) + ((uint32)*cr << 16) + ((uint32)y[0] << 24); + } + + void VDYCbCrToYUYVSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint32 *dst = (uint32 *)dst0; + + if (--w) { + do { + *dst++ = (uint32)y[0] + ((uint32)*cb++ << 8) + ((uint32)y[1] << 16) + ((uint32)*cr++ << 24); + y += 2; + } while((sint32)(w-=2)>0); + } + + if (!(w & 1)) + *dst++ = (uint32)y[0] + ((uint32)*cb << 8) + ((uint32)y[0] << 16) + ((uint32)*cr << 24); + } + + void VDYCbCrToRGB1555Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { + const ptrdiff_t ystep = formatinfo.ystep; + const ptrdiff_t cstep = formatinfo.cstep; + const ptrdiff_t ypos0 = formatinfo.ypos[0]; + const ptrdiff_t ypos1 = formatinfo.ypos[1]; + const ptrdiff_t ypos2 = formatinfo.ypos[2]; + const ptrdiff_t ypos3 = formatinfo.ypos[3]; + const ptrdiff_t crpos0 = formatinfo.crpos[0]; + const ptrdiff_t crpos1 = formatinfo.crpos[1]; + const ptrdiff_t crpos2 = formatinfo.crpos[2]; + const ptrdiff_t crpos3 = formatinfo.crpos[3]; + const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; + const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; + const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; + const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; + + yrow = (char *)yrow - ystep * ((w-1) >> 2); + crrow = (char *)crrow - cstep * ((w-1) >> 2); + cbrow = (char *)cbrow - cstep * ((w-1) >> 2); + dst = (char *)dst + 2*((w-1) & ~3); + + int y = 0; + do { + const uint8 *ysrc = (const uint8 *)yrow; + const uint8 *crsrc = (const uint8 *)crrow; + const uint8 *cbsrc = (const uint8 *)cbrow; + uint16 *out = (uint16 *)dst; + int w2 = -w; + + switch(w2 & 3) { + do { + case 0: out[3] = ycbcr_to_1555(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); + case 1: out[2] = ycbcr_to_1555(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); + case 2: out[1] = ycbcr_to_1555(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); + case 3: out[0] = ycbcr_to_1555(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); + out -= 4; + ysrc += ystep; + crsrc += cstep; + cbsrc += cstep; + } while((w2 += 4) < 0); + } + + dst = (char *)dst + dststride; + yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); + cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); + crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); + } while(++y < h); + } + + void VDYCbCrToRGB565Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { + const ptrdiff_t ystep = formatinfo.ystep; + const ptrdiff_t cstep = formatinfo.cstep; + const ptrdiff_t ypos0 = formatinfo.ypos[0]; + const ptrdiff_t ypos1 = formatinfo.ypos[1]; + const ptrdiff_t ypos2 = formatinfo.ypos[2]; + const ptrdiff_t ypos3 = formatinfo.ypos[3]; + const ptrdiff_t crpos0 = formatinfo.crpos[0]; + const ptrdiff_t crpos1 = formatinfo.crpos[1]; + const ptrdiff_t crpos2 = formatinfo.crpos[2]; + const ptrdiff_t crpos3 = formatinfo.crpos[3]; + const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; + const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; + const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; + const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; + + yrow = (char *)yrow - ystep * ((w-1) >> 2); + crrow = (char *)crrow - cstep * ((w-1) >> 2); + cbrow = (char *)cbrow - cstep * ((w-1) >> 2); + dst = (char *)dst + 2*((w-1) & ~3); + + int y = 0; + do { + const uint8 *ysrc = (const uint8 *)yrow; + const uint8 *crsrc = (const uint8 *)crrow; + const uint8 *cbsrc = (const uint8 *)cbrow; + uint16 *out = (uint16 *)dst; + int w2 = -w; + + switch(w2 & 3) { + do { + case 0: out[3] = ycbcr_to_565(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); + case 1: out[2] = ycbcr_to_565(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); + case 2: out[1] = ycbcr_to_565(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); + case 3: out[0] = ycbcr_to_565(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); + out -= 4; + ysrc += ystep; + crsrc += cstep; + cbsrc += cstep; + } while((w2 += 4) < 0); + } + + dst = (char *)dst + dststride; + yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); + cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); + crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); + } while(++y < h); + } + + void VDYCbCrToRGB888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { + const ptrdiff_t ystep = formatinfo.ystep; + const ptrdiff_t cstep = formatinfo.cstep; + const ptrdiff_t ypos0 = formatinfo.ypos[0]; + const ptrdiff_t ypos1 = formatinfo.ypos[1]; + const ptrdiff_t ypos2 = formatinfo.ypos[2]; + const ptrdiff_t ypos3 = formatinfo.ypos[3]; + const ptrdiff_t crpos0 = formatinfo.crpos[0]; + const ptrdiff_t crpos1 = formatinfo.crpos[1]; + const ptrdiff_t crpos2 = formatinfo.crpos[2]; + const ptrdiff_t crpos3 = formatinfo.crpos[3]; + const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; + const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; + const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; + const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; + + yrow = (char *)yrow - ystep * ((w-1) >> 2); + crrow = (char *)crrow - cstep * ((w-1) >> 2); + cbrow = (char *)cbrow - cstep * ((w-1) >> 2); + dst = (char *)dst + 3*((w-1) & ~3); + + int y = 0; + do { + const uint8 *ysrc = (const uint8 *)yrow; + const uint8 *crsrc = (const uint8 *)crrow; + const uint8 *cbsrc = (const uint8 *)cbrow; + uint8 *out = (uint8 *)dst; + int w2 = -w; + + switch(w2 & 3) { + do { + case 0: ycbcr_to_888(out+9, ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); + case 1: ycbcr_to_888(out+6, ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); + case 2: ycbcr_to_888(out+3, ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); + case 3: ycbcr_to_888(out, ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); + out -= 12; + ysrc += ystep; + crsrc += cstep; + cbsrc += cstep; + } while((w2 += 4) < 0); + } + + dst = (char *)dst + dststride; + yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); + cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); + crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); + } while(++y < h); + } + + void VDYCbCrToRGB8888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { + const ptrdiff_t ystep = formatinfo.ystep; + const ptrdiff_t cstep = formatinfo.cstep; + const ptrdiff_t ypos0 = formatinfo.ypos[0]; + const ptrdiff_t ypos1 = formatinfo.ypos[1]; + const ptrdiff_t ypos2 = formatinfo.ypos[2]; + const ptrdiff_t ypos3 = formatinfo.ypos[3]; + const ptrdiff_t crpos0 = formatinfo.crpos[0]; + const ptrdiff_t crpos1 = formatinfo.crpos[1]; + const ptrdiff_t crpos2 = formatinfo.crpos[2]; + const ptrdiff_t crpos3 = formatinfo.crpos[3]; + const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; + const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; + const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; + const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; + + yrow = (char *)yrow - ystep * ((w-1) >> 2); + crrow = (char *)crrow - cstep * ((w-1) >> 2); + cbrow = (char *)cbrow - cstep * ((w-1) >> 2); + dst = (char *)dst + 4*((w-1) & ~3); + + int y = 0; + do { + const uint8 *ysrc = (const uint8 *)yrow; + const uint8 *crsrc = (const uint8 *)crrow; + const uint8 *cbsrc = (const uint8 *)cbrow; + uint32 *out = (uint32 *)dst; + int w2 = -w; + + switch(w2 & 3) { + do { + case 0: out[3] = ycbcr_to_8888(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); + case 1: out[2] = ycbcr_to_8888(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); + case 2: out[1] = ycbcr_to_8888(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); + case 3: out[0] = ycbcr_to_8888(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); + out -= 4; + ysrc += ystep; + crsrc += cstep; + cbsrc += cstep; + } while((w2 += 4) < 0); + } + + dst = (char *)dst + dststride; + yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); + cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); + crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); + } while(++y < h); + } +} + +#define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) + +DECLARE_YUV(UYVY, XRGB1555) { + do { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint16 *y; + + cb = src[0]; + cr = src[2]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[1]]]; + *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[4]; + cr = src[6]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]]; + dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f); + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[5]]]; + dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + + dst += 2; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]]; + *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, RGB565) { + do { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint16 *y; + + cb = src[0]; + cr = src[2]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[1]]]; + *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[4]; + cr = src[6]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]]; + dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f); + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[5]]]; + dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + + dst += 2; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]]; + *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, RGB888) { + do { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint8 *y; + + cb = src[0]; + cr = src[2]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + dst += 3; + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[4]; + cr = src[6]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; + dst[0] = y[(bc0+bc1+1)>>1]; + dst[1] = y[(gc0+gc1+1)>>1]; + dst[2] = y[(rc0+rc1+1)>>1]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]]; + dst[3] = y[bc1]; + dst[4] = y[gc1]; + dst[5] = y[rc1]; + + dst += 6; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, XRGB8888) { + do { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint8 *y; + + cb = src[0]; + cr = src[2]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + dst += 4; + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[4]; + cr = src[6]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; + dst[0] = y[(bc0+bc1+1)>>1]; + dst[1] = y[(gc0+gc1+1)>>1]; + dst[2] = y[(rc0+rc1+1)>>1]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]]; + dst[4] = y[bc1]; + dst[5] = y[gc1]; + dst[6] = y[rc1]; + + dst += 8; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, XRGB1555) { + do { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint16 *y; + + cb = src[1]; + cr = src[3]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[0]]]; + *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[5]; + cr = src[7]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]]; + dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f); + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[4]]]; + dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + + dst += 2; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]]; + *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, RGB565) { + do { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint16 *y; + + cb = src[1]; + cr = src[3]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[0]]]; + *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[5]; + cr = src[7]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]]; + dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f); + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[4]]]; + dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + + dst += 2; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]]; + *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, RGB888) { + do { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint8 *y; + + cb = src[1]; + cr = src[3]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + dst += 3; + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[5]; + cr = src[7]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; + dst[0] = y[(bc0+bc1+1)>>1]; + dst[1] = y[(gc0+gc1+1)>>1]; + dst[2] = y[(rc0+rc1+1)>>1]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]]; + dst[3] = y[bc1]; + dst[4] = y[gc1]; + dst[5] = y[rc1]; + + dst += 6; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, XRGB8888) { + do { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint8 *y; + + cb = src[1]; + cr = src[3]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + dst += 4; + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[5]; + cr = src[7]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; + dst[0] = y[(bc0+bc1+1)>>1]; + dst[1] = y[(gc0+gc1+1)>>1]; + dst[2] = y[(rc0+rc1+1)>>1]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]]; + dst[4] = y[bc1]; + dst[5] = y[gc1]; + dst[6] = y[rc1]; + + dst += 8; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, XRGB1555) { + uint16 *dst = (uint16 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 2*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = colorconv.cliptab15[colorconv.y_tab[*src++] + 277]; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, RGB565) { + uint16 *dst = (uint16 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 2*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = colorconv.cliptab16[colorconv.y_tab[*src++] + 277]; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, RGB888) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 3*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + dst[0] = dst[1] = dst[2] = colorconv.cliptab[colorconv.y_tab[*src++] + 277]; + dst += 3; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, XRGB8888) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 4*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = 0x010101 * colorconv.cliptab[colorconv.y_tab[*src++] + 277]; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +#define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) + + +namespace { + typedef void (*tpYUVPlanarFinalDecoder)(void *, const uint8 *, const uint8 *, const uint8 *, uint32); + typedef void (*tpYUVPlanarHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w); + typedef void (*tpYUVPlanarVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); +} + +#ifdef _M_IX86 + extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); + extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); + extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); +#endif + + +void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); + int hbits = srcinfo.auxwbits; + int vbits = srcinfo.auxhbits; + + if (src.format == nsVDPixmap::kPixFormat_YUV422_UYVY || src.format == nsVDPixmap::kPixFormat_YUV422_YUYV) + hbits = 1; + + bool h_coaligned = true; + bool v_coaligned = false; + + if (src.format == nsVDPixmap::kPixFormat_YUV422_Planar_Centered || + src.format == nsVDPixmap::kPixFormat_YUV420_Planar_Centered) { + h_coaligned = false; + } + + tpYUVPlanarVertDecoder vfunc = NULL; + tpYUVPlanarHorizDecoder hfunc = NULL; + uint32 horiz_buffer_size = 0; + uint32 vert_buffer_size = 0; + uint32 horiz_count = 0; + sint32 yaccum = 8; + sint32 yinc = 8; + uint32 yleft = h; + + switch(vbits*2+v_coaligned) { + case 0: // 4:4:4, 4:2:2 + case 1: + break; + case 2: // 4:2:0 (centered) + vfunc = vert_expand2x_centered; + vert_buffer_size = w>>1; + yaccum = 6; + yinc = 4; + yleft >>= 1; + break; + case 4: // 4:1:0 (centered) + vfunc = vert_expand4x_centered; + vert_buffer_size = w>>2; + yaccum = 5; + yinc = 2; + yleft >>= 2; + break; + default: + VDNEVERHERE; + return; + } + + --yleft; + + tpYUVPlanarFinalDecoder dfunc = NULL; + +#ifdef _M_IX86 + uint32 cpuflags = CPUGetEnabledExtensions(); + + if (cpuflags & CPUF_SUPPORTS_MMX) { + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (vfunc == vert_expand2x_centered) + vfunc = vert_expand2x_centered_ISSE; + } + + switch(dst.format) { + case nsVDPixmap::kPixFormat_XRGB1555: dfunc = vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX; break; + case nsVDPixmap::kPixFormat_RGB565: dfunc = vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX; break; + case nsVDPixmap::kPixFormat_XRGB8888: dfunc = vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX; break; + } + } +#endif + + bool halfchroma = false; + + if (!dfunc) { + switch(dst.format) { + case nsVDPixmap::kPixFormat_XRGB1555: dfunc = VDYCbCrToXRGB1555Span; break; + case nsVDPixmap::kPixFormat_RGB565: dfunc = VDYCbCrToRGB565Span; break; + case nsVDPixmap::kPixFormat_RGB888: dfunc = VDYCbCrToRGB888Span; break; + case nsVDPixmap::kPixFormat_XRGB8888: dfunc = VDYCbCrToXRGB8888Span; break; + case nsVDPixmap::kPixFormat_YUV422_UYVY: dfunc = VDYCbCrToUYVYSpan; halfchroma = true; break; + case nsVDPixmap::kPixFormat_YUV422_YUYV: dfunc = VDYCbCrToYUYVSpan; halfchroma = true; break; + default: + VDNEVERHERE; + return; + } + } + + switch(hbits*2+h_coaligned) { + case 0: // 4:4:4 + case 1: + if (halfchroma) { + hfunc = horiz_compress2x_coaligned; + horiz_buffer_size = (w + 1) >> 1; + horiz_count = w; + } + break; + case 2: // 4:2:0 MPEG-1 (centered) + if (halfchroma) { + hfunc = horiz_realign_to_coaligned; + horiz_buffer_size = (w + 1) >> 1; + horiz_count = (w + 1) >> 1; + } else { + hfunc = horiz_expand2x_centered; + horiz_buffer_size = w; + horiz_count = w; + } + break; + case 3: // 4:2:0/4:2:2 MPEG-2 (coaligned) + if (!halfchroma) { + hfunc = horiz_expand2x_coaligned; + horiz_buffer_size = w; + horiz_count = w; + } + break; + case 5: // 4:1:1 (coaligned) + if (halfchroma) { + hfunc = horiz_expand2x_coaligned; + horiz_buffer_size = (w + 1) >> 1; + horiz_count = (w + 1) >> 1; + } else { + hfunc = horiz_expand4x_coaligned; + horiz_buffer_size = w; + horiz_count = w; + } + break; + + default: + VDNEVERHERE; + return; + } + +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (hfunc == horiz_expand2x_coaligned) + hfunc = horiz_expand2x_coaligned_ISSE; + } +#endif + + uint32 chroma_srcwidth = -(-w >> srcinfo.auxwbits); + horiz_buffer_size = (horiz_buffer_size + 15) & ~15; + vert_buffer_size = (vert_buffer_size + 15) & ~15; + + // allocate buffers + + vdblock tempbuf((horiz_buffer_size + vert_buffer_size)*2 + 1); + + uint8 *const crbufh = tempbuf.data(); + uint8 *const crbufv = crbufh + horiz_buffer_size; + uint8 *const cbbufh = crbufv + vert_buffer_size; + uint8 *const cbbufv = cbbufh + horiz_buffer_size; + + const uint8 *cb0 = (const uint8*)src.data2; + const uint8 *cr0 = (const uint8*)src.data3; + const uint8 *cb1 = cb0; + const uint8 *cr1 = cr0; + const uint8 *y = (const uint8 *)src.data; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + void *out = dst.data; + ptrdiff_t outpitch = dst.pitch; + + for(;;) { + if (yaccum >= 8) { + yaccum &= 7; + + cb0 = cb1; + cr0 = cr1; + + if (yleft > 0) { + --yleft; + vdptrstep(cb1, cbpitch); + vdptrstep(cr1, crpitch); + } + } + + const uint8 *cr = cr0; + const uint8 *cb = cb0; + + // vertical interpolation: cr + if(yaccum & 7) { + const uint8 *const srcs[2]={cr0, cr1}; + vfunc(crbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5); + cr = crbufv; + } + + // horizontal interpolation: cr + if (hfunc) { + hfunc(crbufh, cr, horiz_count); + cr = crbufh; + } + + // vertical interpolation: cb + if(yaccum & 7) { + const uint8 *const srcs[2]={cb0, cb1}; + vfunc(cbbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5); + cb = cbbufv; + } + + // horizontal interpolation: cb + if (hfunc) { + hfunc(cbbufh, cb, horiz_count); + cb = cbbufh; + } + + dfunc(out, y, cb, cr, w); + vdptrstep(out, outpitch); + vdptrstep(y, ypitch); + + if (!--h) + break; + + yaccum += yinc; + } + +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_MMX) { + _mm_empty(); + } +#endif +} + +namespace { + typedef void (*tpUVBltHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w); + typedef void (*tpUVBltVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); + + void uvplaneblt(uint8 *dst, ptrdiff_t dstpitch, int dstformat, const uint8 *src, ptrdiff_t srcpitch, int srcformat, vdpixsize w, vdpixsize h) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(srcformat); + const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dstformat); + + int xshift = srcinfo.auxwbits - dstinfo.auxwbits; + int yshift = srcinfo.auxhbits - dstinfo.auxhbits; + + tpUVBltHorizDecoder hfunc = NULL; + tpUVBltVertDecoder vfunc = NULL; + + switch(xshift) { + case +2: + hfunc = horiz_expand4x_coaligned; + break; + case +1: + hfunc = horiz_expand2x_coaligned; + break; + case 0: + break; + case -1: + hfunc = horiz_compress2x_coaligned; + break; + case -2: + hfunc = horiz_compress4x_coaligned; + break; + default: + VDNEVERHERE; + return; + } + +#ifdef _M_IX86 + uint32 cpuflags = CPUGetEnabledExtensions(); + + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (hfunc == horiz_expand2x_coaligned) + hfunc = horiz_expand2x_coaligned_ISSE; + } +#endif + + int winsize, winposnext, winstep; + + switch(yshift) { + case +2: + vfunc = vert_expand4x_centered; + winsize = 2; + winposnext = 0xa0; + winstep = 0x40; + break; + case +1: + vfunc = vert_expand2x_centered; + winsize = 2; + winposnext = 0xc0; + winstep = 0x80; + break; + case 0: + winsize = 1; + winposnext = 0; + winstep = 0x100; + break; + case -1: + vfunc = vert_compress2x_centered; + winsize = 4; + winposnext = 0x200; + winstep = 0x200; + break; + case -2: + vfunc = vert_compress4x_centered; + winsize = 8; + winposnext = 0x500; + winstep = 0x400; + break; + default: + VDNEVERHERE; + return; + } + +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (vfunc == vert_expand2x_centered) + vfunc = vert_expand2x_centered_ISSE; + } +#endif + + int dsth = -(-h >> dstinfo.auxhbits); + int srch = -(-h >> srcinfo.auxhbits); + int dstw = -(-w >> dstinfo.auxwbits); + int w2 = -(-w >> std::min(dstinfo.auxwbits, srcinfo.auxwbits)); + + int winpos = (winposnext>>8) - winsize; + + const uint8 *window[16]; + + vdblock tmpbuf; + ptrdiff_t tmppitch = (w+15) & ~15; + + if (vfunc && hfunc) + tmpbuf.resize(tmppitch * winsize); + + do { + int desiredpos = winposnext >> 8; + + while(winpos < desiredpos) { + const uint8 *srcrow = vdptroffset(src, srcpitch * std::max(0, std::min(srch-1, ++winpos))); + int winoffset = (winpos-1) & (winsize-1); + + if (hfunc) { + uint8 *dstrow = vfunc ? tmpbuf.data() + tmppitch * winoffset : dst; + hfunc(dstrow, srcrow, w2); + srcrow = dstrow; + } + + window[winoffset] = window[winoffset + winsize] = srcrow; + } + + if (vfunc) + vfunc(dst, window + (winpos & (winsize-1)), dstw, winposnext & 255); + else if (!hfunc) + memcpy(dst, window[winpos & (winsize-1)], dstw); + + winposnext += winstep; + vdptrstep(dst, dstpitch); + } while(--dsth); + +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_MMX) { + _mm_empty(); + } +#endif + } +} + +void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dstpm, const VDPixmap& srcpm, vdpixsize w, vdpixsize h) { + VDMemcpyRect(dstpm.data, dstpm.pitch, srcpm.data, srcpm.pitch, dstpm.w, dstpm.h); + + if (srcpm.format != nsVDPixmap::kPixFormat_Y8) { + if (dstpm.format != nsVDPixmap::kPixFormat_Y8) { + // YCbCr -> YCbCr + uvplaneblt((uint8 *)dstpm.data2, dstpm.pitch2, dstpm.format, (uint8 *)srcpm.data2, srcpm.pitch2, srcpm.format, w, h); + uvplaneblt((uint8 *)dstpm.data3, dstpm.pitch3, dstpm.format, (uint8 *)srcpm.data3, srcpm.pitch3, srcpm.format, w, h); + } + } else { + if (dstpm.format != nsVDPixmap::kPixFormat_Y8) { + const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstpm.format); + VDMemset8Rect(dstpm.data2, dstpm.pitch2, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits)); + VDMemset8Rect(dstpm.data3, dstpm.pitch3, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits)); + } + } +} + +extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); + +DECLARE_YUV_PLANAR(YUV411, XRGB1555) { + uint16 *out = (uint16 *)dst.data; + const ptrdiff_t opitch = dst.pitch; + const uint8 *yrow = (const uint8 *)src.data; + const uint8 *cbrow = (const uint8 *)src.data2; + const uint8 *crrow = (const uint8 *)src.data3; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + vdpixsize wpairs = (w-1)>>2; + vdpixsize wleft = w - (wpairs<<2); + + do { + uint16 *p = out; + const uint8 *y = yrow; + const uint8 *cb = cbrow; + const uint8 *cr = crrow; + vdpixsize wt; + + if (wpairs > 0) { +#if !defined(VD_CPU_X86) + wt = wpairs; + + do { + const unsigned cb0 = cb[0]; + const unsigned cb1 = cb[1]; + const unsigned cr0 = cr[0]; + const unsigned cr1 = cr[1]; + + p[0] = ycbcr_to_1555(y[0], cb0, cr0); + p[1] = ycbcr_to_1555(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); + p[2] = ycbcr_to_1555(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); + p[3] = ycbcr_to_1555(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); + + y += 4; + p += 4; + ++cb; + ++cr; + } while(--wt); +#else + vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(p, y, cb, cr, wpairs); + y += 4*wpairs; + cr += wpairs; + cb += wpairs; + p += 4*wpairs; +#endif + } + + if (wleft > 0) { + wt = wleft; + + const uint8 cr0 = *cr; + const uint8 cb0 = *cb; + + do { + *p++ = ycbcr_to_1555(*y++, cb0, cr0); + } while(--wt); + } + + vdptrstep(out, opitch); + vdptrstep(yrow, ypitch); + vdptrstep(cbrow, cbpitch); + vdptrstep(crrow, crpitch); + } while(--h); + +#ifdef VD_CPU_X86 + _mm_empty(); +#endif +} + +DECLARE_YUV_PLANAR(YUV411, RGB565) { + uint16 *out = (uint16 *)dst.data; + const ptrdiff_t opitch = dst.pitch; + const uint8 *yrow = (const uint8 *)src.data; + const uint8 *cbrow = (const uint8 *)src.data2; + const uint8 *crrow = (const uint8 *)src.data3; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + vdpixsize wpairs = (w-1)>>2; + vdpixsize wleft = w - (wpairs<<2); + + do { + uint16 *p = out; + const uint8 *y = yrow; + const uint8 *cb = cbrow; + const uint8 *cr = crrow; + vdpixsize wt; + + if (wpairs > 0) { +#if !defined(VD_CPU_X86) + wt = wpairs; + + do { + const unsigned cb0 = cb[0]; + const unsigned cb1 = cb[1]; + const unsigned cr0 = cr[0]; + const unsigned cr1 = cr[1]; + + p[0] = ycbcr_to_565(y[0], cb0, cr0); + p[1] = ycbcr_to_565(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); + p[2] = ycbcr_to_565(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); + p[3] = ycbcr_to_565(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); + + y += 4; + p += 4; + ++cb; + ++cr; + } while(--wt); +#else + vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(p, y, cb, cr, wpairs); +#endif + } + + if (wleft > 0) { + wt = wleft; + + const uint8 cr0 = *cr; + const uint8 cb0 = *cb; + + do { + *p++ = ycbcr_to_565(*y++, cb0, cr0); + } while(--wt); + } + + vdptrstep(out, opitch); + vdptrstep(yrow, ypitch); + vdptrstep(cbrow, cbpitch); + vdptrstep(crrow, crpitch); + } while(--h); + +#ifdef VD_CPU_X86 + _mm_empty(); +#endif +} + +DECLARE_YUV_PLANAR(YUV411, RGB888) { + uint8 *out = (uint8 *)dst.data; + const ptrdiff_t opitch = dst.pitch; + const uint8 *yrow = (const uint8 *)src.data; + const uint8 *cbrow = (const uint8 *)src.data2; + const uint8 *crrow = (const uint8 *)src.data3; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + vdpixsize wpairs = (w-1)>>2; + vdpixsize wleft = w - (wpairs<<2); + + do { + uint8 *p = out; + const uint8 *y = yrow; + const uint8 *cb = cbrow; + const uint8 *cr = crrow; + vdpixsize wt; + + if (wpairs > 0) { + wt = wpairs; + + do { + const unsigned cb0 = cb[0]; + const unsigned cb1 = cb[1]; + const unsigned cr0 = cr[0]; + const unsigned cr1 = cr[1]; + + ycbcr_to_888(p+0, y[0], cb0, cr0); + ycbcr_to_888(p+3, y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); + ycbcr_to_888(p+6, y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); + ycbcr_to_888(p+9, y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); + + y += 4; + p += 12; + ++cb; + ++cr; + } while(--wt); + } + + if (wleft > 0) { + wt = wleft; + + const uint8 cr0 = *cr; + const uint8 cb0 = *cb; + + do { + ycbcr_to_888(p, *y++, cb0, cr0); + p += 4; + } while(--wt); + } + + vdptrstep(out, opitch); + vdptrstep(yrow, ypitch); + vdptrstep(cbrow, cbpitch); + vdptrstep(crrow, crpitch); + } while(--h); +} + +DECLARE_YUV_PLANAR(YUV411, XRGB8888) { + uint32 *out = (uint32 *)dst.data; + const ptrdiff_t opitch = dst.pitch; + const uint8 *yrow = (const uint8 *)src.data; + const uint8 *cbrow = (const uint8 *)src.data2; + const uint8 *crrow = (const uint8 *)src.data3; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + vdpixsize wpairs = (w-1)>>2; + vdpixsize wleft = w - (wpairs<<2); + + do { + uint32 *p = out; + const uint8 *y = yrow; + const uint8 *cb = cbrow; + const uint8 *cr = crrow; + vdpixsize wt; + + if (wpairs > 0) { +#if !defined(VD_CPU_X86) + wt = wpairs; + + do { + const unsigned cb0 = cb[0]; + const unsigned cb1 = cb[1]; + const unsigned cr0 = cr[0]; + const unsigned cr1 = cr[1]; + + p[0] = ycbcr_to_8888(y[0], cb0, cr0); + p[1] = ycbcr_to_8888(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); + p[2] = ycbcr_to_8888(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); + p[3] = ycbcr_to_8888(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); + + y += 4; + p += 4; + ++cb; + ++cr; + } while(--wt); +#else + vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(p, y, cb, cr, wpairs); + y += 4*wpairs; + cr += wpairs; + cb += wpairs; + p += 4*wpairs; +#endif + } + + if (wleft > 0) { + wt = wleft; + + const uint8 cr0 = *cr; + const uint8 cb0 = *cb; + + do { + *p++ = ycbcr_to_8888(*y++, cb0, cr0); + } while(--wt); + } + + vdptrstep(out, opitch); + vdptrstep(yrow, ypitch); + vdptrstep(cbrow, cbpitch); + vdptrstep(crrow, crpitch); + } while(--h); + +#ifdef VD_CPU_X86 + _mm_empty(); +#endif +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv2yuv.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv2yuv.cpp index 093ac536033..208d6d35f03 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv2yuv.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv2yuv.cpp @@ -1,279 +1,279 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include - -#include "bitutils.h" -#include "blt_spanutils.h" - -#define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) - -using namespace nsVDPixmapBitUtils; -using namespace nsVDPixmapSpanUtils; - -DECLARE_YUV(XVYU, UYVY) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - srcpitch -= (w&~1)*4; - dstpitch -= (w&~1)*2; - - do { - vdpixsize wt = w; - - wt = -wt; - - if (++wt) { - uint32 a, b, c; - - a = src[0]; - b = src[1]; - *dst++ = (avg_8888_121(a, a, b) & 0xff00ff) + (a & 0xff00) + ((b & 0xff00)<<16); - src += 2; - - if ((wt+=2) < 0) { - do { - a = src[-1]; - b = src[0]; - c = src[1]; - - *dst++ = (avg_8888_121(a, b, c) & 0xff00ff) + (b & 0xff00) + ((c & 0xff00)<<16); - src += 2; - } while((wt+=2) < 0); - } - } - - if (!(wt&1)) - *dst = *src; - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(XVYU, YUYV) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - srcpitch -= (w&~1)*4; - dstpitch -= (w&~1)*2; - - do { - vdpixsize wt = w; - - wt = -wt; - - if (++wt) { - uint32 a, b, c; - - a = src[0]; - b = src[1]; - *dst++ = ((avg_8888_121(a, a, b) & 0xff00ff)<<8) + ((a & 0xff00)>>8) + ((b & 0xff00)<<8); - src += 2; - - if ((wt+=2)<0) { - do { - a = src[-1]; - b = src[0]; - c = src[1]; - - *dst++ = ((avg_8888_121(a, b, c) & 0xff00ff)<<8) + ((b & 0xff00)>>8) + ((c & 0xff00)<<8); - src += 2; - } while((wt+=2) < 0); - } - } - - if (!(wt&1)) { - uint32 v = *src; - *dst = ((v&0xff00ff)<<8) + ((v&0xff00ff00)>>8); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, YUYV) { // also YUYV->UYVY - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - w = (w+1) >> 1; - - dstpitch -= 4*w; - srcpitch -= 4*w; - - do { - vdpixsize w2 = w; - - do { - const uint32 p = *src++; - - *dst++ = ((p & 0xff00ff00)>>8) + ((p & 0x00ff00ff)<<8); - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, Y8) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= w; - srcpitch -= 2*w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = src[1]; - src += 2; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, Y8) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= w; - srcpitch -= 2*w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = src[0]; - src += 2; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, UYVY) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 2*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - dst[0] = 0x80; - dst[1] = *src++; - dst += 2; - } while(--w2); - - if (w & 1) { - dst[0] = 0x80; - dst[1] = dst[-1]; - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, YUYV) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 2*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - dst[0] = *src++; - dst[1] = 0x80; - dst += 2; - } while(--w2); - - if (w & 1) { - dst[0] = dst[-1]; - dst[1] = 0x80; - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV_PLANAR(YUV411, YV12) { - VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, w, h); - - vdblock tmprow(w); - const uint8 *srcp = (const uint8 *)src.data2; - ptrdiff_t srcpitch = src.pitch2; - uint8 *dstp = (uint8 *)dst.data2; - ptrdiff_t dstpitch = dst.pitch2; - const uint8 *src1, *src2; - - vdpixsize h2; - for(h2 = h; h2 > 0; h2 -= 2) { - src1 = srcp; - vdptrstep(srcp, srcpitch); - if (h2 > 1) - src2 = srcp; - else - src2 = src1; - vdptrstep(srcp, srcpitch); - - const uint8 *sources[2] = {src1, src2}; - - vert_compress2x_centered_fast(tmprow.data(), sources, w, 0); - horiz_expand2x_coaligned(dstp, tmprow.data(), w); - - vdptrstep(dstp, dstpitch); - } - - srcp = (const uint8 *)src.data3; - srcpitch = src.pitch3; - dstp = (uint8 *)dst.data3; - dstpitch = dst.pitch3; - for(h2 = h; h2 > 0; h2 -= 2) { - src1 = srcp; - vdptrstep(srcp, srcpitch); - if (h2 > 1) - src2 = srcp; - else - src2 = src1; - vdptrstep(srcp, srcpitch); - - const uint8 *sources[2] = {src1, src2}; - vert_compress2x_centered_fast(tmprow.data(), sources, w, 0); - horiz_expand2x_coaligned(dstp, tmprow.data(), w); - - vdptrstep(dstp, dstpitch); - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include + +#include "bitutils.h" +#include "blt_spanutils.h" + +#define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) + +using namespace nsVDPixmapBitUtils; +using namespace nsVDPixmapSpanUtils; + +DECLARE_YUV(XVYU, UYVY) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + srcpitch -= (w&~1)*4; + dstpitch -= (w&~1)*2; + + do { + vdpixsize wt = w; + + wt = -wt; + + if (++wt) { + uint32 a, b, c; + + a = src[0]; + b = src[1]; + *dst++ = (avg_8888_121(a, a, b) & 0xff00ff) + (a & 0xff00) + ((b & 0xff00)<<16); + src += 2; + + if ((wt+=2) < 0) { + do { + a = src[-1]; + b = src[0]; + c = src[1]; + + *dst++ = (avg_8888_121(a, b, c) & 0xff00ff) + (b & 0xff00) + ((c & 0xff00)<<16); + src += 2; + } while((wt+=2) < 0); + } + } + + if (!(wt&1)) + *dst = *src; + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(XVYU, YUYV) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + srcpitch -= (w&~1)*4; + dstpitch -= (w&~1)*2; + + do { + vdpixsize wt = w; + + wt = -wt; + + if (++wt) { + uint32 a, b, c; + + a = src[0]; + b = src[1]; + *dst++ = ((avg_8888_121(a, a, b) & 0xff00ff)<<8) + ((a & 0xff00)>>8) + ((b & 0xff00)<<8); + src += 2; + + if ((wt+=2)<0) { + do { + a = src[-1]; + b = src[0]; + c = src[1]; + + *dst++ = ((avg_8888_121(a, b, c) & 0xff00ff)<<8) + ((b & 0xff00)>>8) + ((c & 0xff00)<<8); + src += 2; + } while((wt+=2) < 0); + } + } + + if (!(wt&1)) { + uint32 v = *src; + *dst = ((v&0xff00ff)<<8) + ((v&0xff00ff00)>>8); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, YUYV) { // also YUYV->UYVY + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + w = (w+1) >> 1; + + dstpitch -= 4*w; + srcpitch -= 4*w; + + do { + vdpixsize w2 = w; + + do { + const uint32 p = *src++; + + *dst++ = ((p & 0xff00ff00)>>8) + ((p & 0x00ff00ff)<<8); + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, Y8) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= w; + srcpitch -= 2*w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = src[1]; + src += 2; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, Y8) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= w; + srcpitch -= 2*w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = src[0]; + src += 2; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, UYVY) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 2*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + dst[0] = 0x80; + dst[1] = *src++; + dst += 2; + } while(--w2); + + if (w & 1) { + dst[0] = 0x80; + dst[1] = dst[-1]; + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, YUYV) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 2*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + dst[0] = *src++; + dst[1] = 0x80; + dst += 2; + } while(--w2); + + if (w & 1) { + dst[0] = dst[-1]; + dst[1] = 0x80; + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV_PLANAR(YUV411, YV12) { + VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, w, h); + + vdblock tmprow(w); + const uint8 *srcp = (const uint8 *)src.data2; + ptrdiff_t srcpitch = src.pitch2; + uint8 *dstp = (uint8 *)dst.data2; + ptrdiff_t dstpitch = dst.pitch2; + const uint8 *src1, *src2; + + vdpixsize h2; + for(h2 = h; h2 > 0; h2 -= 2) { + src1 = srcp; + vdptrstep(srcp, srcpitch); + if (h2 > 1) + src2 = srcp; + else + src2 = src1; + vdptrstep(srcp, srcpitch); + + const uint8 *sources[2] = {src1, src2}; + + vert_compress2x_centered_fast(tmprow.data(), sources, w, 0); + horiz_expand2x_coaligned(dstp, tmprow.data(), w); + + vdptrstep(dstp, dstpitch); + } + + srcp = (const uint8 *)src.data3; + srcpitch = src.pitch3; + dstp = (uint8 *)dst.data3; + dstpitch = dst.pitch3; + for(h2 = h; h2 > 0; h2 -= 2) { + src1 = srcp; + vdptrstep(srcp, srcpitch); + if (h2 > 1) + src2 = srcp; + else + src2 = src1; + vdptrstep(srcp, srcpitch); + + const uint8 *sources[2] = {src1, src2}; + vert_compress2x_centered_fast(tmprow.data(), sources, w, 0); + horiz_expand2x_coaligned(dstp, tmprow.data(), w); + + vdptrstep(dstp, dstpitch); + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuvrev.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuvrev.cpp index d6f6ce75d91..701c2111123 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuvrev.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuvrev.cpp @@ -1,549 +1,549 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include "blt_spanutils.h" - -#ifdef _M_IX86 - #include "blt_spanutils_x86.h" -#endif - -using namespace nsVDPixmapSpanUtils; - -namespace { - // From Jim Blinn's "Dirty Pixels": - // - // Y = .299R + .587G + .114B - // Cr = 0.713(R-Y) - // Cb = 0.564(B-Y) - // - // IY = 219Y + 16 = ((yt = 1052IR + 2065IG + 401IB) + 67584) >> 12 - // ICr = 224Cr + 128 = (yt*2987 - 10507932IR + 2155872256) >> 24 - // ICb = 224Cb + 128 = (yt*2363 - 8312025IB + 2155872256) >> 24 - - void ConvertRGB32ToXVYU32(uint32 *dst, const uint8 *src, sint32 count) { - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - const sint32 yt = 1052*r + 2065*g + 401*b; - const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift - const sint32 cr = (10507932*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift - const sint32 cb = ( 8312025*b - yt*2363 + 2155872256U) >> 24; - - *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order - src += 4; - } while(--count); - } - - void ConvertRGB24ToXVYU32(uint32 *dst, const uint8 *src, sint32 count) { - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - const sint32 yt = 1052*r + 2065*g + 401*b; - const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift - const sint32 cr = (10507932*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift - const sint32 cb = ( 8312025*b - yt*2363 + 2155872256U) >> 24; - - *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order - src += 3; - } while(--count); - } - - void ConvertRGB16ToXVYU32(uint32 *dst, const uint16 *src, sint32 count) { - do { - const sint16 px = *src++; - const sint32 r = (px & 0xf800) >> 11; - const sint32 g = (px & 0x07e0) >> 5; - const sint32 b = (px & 0x001f); - const sint32 yt = 8652*r + 8358*g + 3299*b; - const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift - const sint32 cr = (86436217*r - yt*2987 + 2155872256U) >> 8; - const sint32 cb = (68373108*b - yt*2363 + 2155872256U) >> 24; // <<16 alignment shift - - *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order - } while(--count); - } - - void ConvertRGB15ToXVYU32(uint32 *dst, const uint16 *src, sint32 count) { - do { - const sint16 px = *src++; - const sint32 r = (px & 0x7c00) >> 10; - const sint32 g = (px & 0x03e0) >> 5; - const sint32 b = (px & 0x001f); - const sint32 yt = 8652*r + 16986*g + 3299*b; - const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift - const sint32 cr = (86436217*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift - const sint32 cb = (68373108*b - yt*2363 + 2155872256U) >> 24; - - *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order - } while(--count); - } - - void ConvertRGB32ToY8(uint8 *dst, const uint8 *src, sint32 count) { - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - *dst++ = (uint8)((1052*r + 2065*g + 401*b + 67584) >> 12); - src += 4; - } while(--count); - } - - void ConvertRGB24ToY8(uint8 *dst, const uint8 *src, sint32 count) { - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - *dst++ = (uint8)((1052*r + 2065*g + 401*b + 67584) >> 12); - src += 3; - } while(--count); - } - - void ConvertRGB16ToY8(uint8 *dst, const uint16 *src, sint32 count) { - do { - const sint16 px = *src++; - const sint32 r = (px & 0xf800) >> 11; - const sint32 g = (px & 0x07e0) >> 5; - const sint32 b = (px & 0x001f); - *dst++ = (uint8)((8652*r + 8358*g + 3299*b + 67584) >> 12); - } while(--count); - } - - void ConvertRGB15ToY8(uint8 *dst, const uint16 *src, sint32 count) { - do { - const sint16 px = *src++; - const sint32 r = (px & 0x7c00) >> 10; - const sint32 g = (px & 0x03e0) >> 5; - const sint32 b = (px & 0x001f); - *dst++ = (uint8)((8652*r + 16986*g + 3299*b + 67584) >> 12); - } while(--count); - } -} - -#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) - -DECLARE_YUV_REV(XRGB1555, XVYU) { - do { - ConvertRGB15ToXVYU32((uint32 *)dst0, (const uint16 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(RGB565, XVYU) { - do { - ConvertRGB16ToXVYU32((uint32 *)dst0, (const uint16 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(RGB888, XVYU) { - do { - ConvertRGB24ToXVYU32((uint32 *)dst0, (const uint8 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(XRGB8888, XVYU) { - do { - ConvertRGB32ToXVYU32((uint32 *)dst0, (const uint8 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(XRGB1555, Y8) { - do { - ConvertRGB15ToY8((uint8 *)dst0, (const uint16 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(RGB565, Y8) { - do { - ConvertRGB16ToY8((uint8 *)dst0, (const uint16 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(RGB888, Y8) { - do { - ConvertRGB24ToY8((uint8 *)dst0, (const uint8 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(XRGB8888, Y8) { - do { - ConvertRGB32ToY8((uint8 *)dst0, (const uint8 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - - - - - -namespace { - void ConvertRGB32ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint8 *src = (const uint8 *)src0; - - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - const sint32 yt = 1052*r + 2065*g + 401*b; - *ydst++ = (yt + 67584) >> 12; - *crdst++ = (10507932*r - yt*2987 + 2155872256U) >> 24; - *cbdst++ = ( 8312025*b - yt*2363 + 2155872256U) >> 24; - src += 4; - } while(--count); - } - - void ConvertRGB24ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint8 *src = (const uint8 *)src0; - - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - const sint32 yt = 1052*r + 2065*g + 401*b; - *ydst++ = (yt + 67584) >> 12; - *crdst++ = (10507932*r - yt*2987 + 2155872256U) >> 24; - *cbdst++ = ( 8312025*b - yt*2363 + 2155872256U) >> 24; - src += 3; - } while(--count); - } - - void ConvertRGB16ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint16 *src = (const uint16 *)src0; - - do { - const sint16 px = *src++; - const sint32 r = (px & 0xf800) >> 11; - const sint32 g = (px & 0x07e0) >> 5; - const sint32 b = (px & 0x001f); - const sint32 yt = 8652*r + 8358*g + 3299*b; - *ydst++ = (yt + 67584) >> 12; - *crdst++ = (86436217*r - yt*2987 + 2155872256U) >> 24; - *cbdst++ = (68373108*b - yt*2363 + 2155872256U) >> 24; - } while(--count); - } - - void ConvertRGB15ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint16 *src = (const uint16 *)src0; - - do { - const sint16 px = *src++; - const sint32 r = (px & 0x7c00) >> 10; - const sint32 g = (px & 0x03e0) >> 5; - const sint32 b = (px & 0x001f); - const sint32 yt = 8652*r + 16986*g + 3299*b; - *ydst++ = (yt + 67584) >> 12; - *crdst++ = (86436217*r - yt*2987 + 2155872256U) >> 24; - *cbdst++ = (68373108*b - yt*2363 + 2155872256U) >> 24; - } while(--count); - } - - void ConvertUYVYToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint8 *src = (const uint8 *)src0; - - do { - *cbdst++ = src[0]; - *ydst++ = src[1]; - *crdst++ = src[2]; - if (!--count) - break; - *ydst++ = src[3]; - src += 4; - } while(--count); - } - - void ConvertYUYVToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint8 *src = (const uint8 *)src0; - - do { - *cbdst++ = src[1]; - *ydst++ = src[0]; - *crdst++ = src[3]; - if (!--count) - break; - *ydst++ = src[2]; - src += 4; - } while(--count); - } -} - -void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dstbm, const VDPixmap& srcbm, vdpixsize w, vdpixsize h) { - void (*cfunc)(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src, sint32 w) = NULL; - void (*hfunc)(uint8 *dst, const uint8 *src, sint32 w) = NULL; - void (*vfunc)(uint8 *dst, const uint8 *const *sources, sint32 w, uint8 phase) = NULL; - - bool halfchroma = false; - - switch(srcbm.format) { - case nsVDPixmap::kPixFormat_XRGB1555: - cfunc = ConvertRGB15ToYUVPlanar; - break; - case nsVDPixmap::kPixFormat_RGB565: - cfunc = ConvertRGB16ToYUVPlanar; - break; - case nsVDPixmap::kPixFormat_RGB888: - cfunc = ConvertRGB24ToYUVPlanar; - break; - case nsVDPixmap::kPixFormat_XRGB8888: - cfunc = ConvertRGB32ToYUVPlanar; - break; - case nsVDPixmap::kPixFormat_YUV422_UYVY: - cfunc = ConvertUYVYToYUVPlanar; - halfchroma = true; - break; - case nsVDPixmap::kPixFormat_YUV422_YUYV: - cfunc = ConvertYUYVToYUVPlanar; - halfchroma = true; - break; - default: - VDNEVERHERE; - return; - } - - vdpixsize w2 = w; - vdpixsize h2 = h; - int winstep = 1; - int winsize = 1; - int winposnext = 0; - vdpixsize chroma_srcw = w; - - switch(dstbm.format) { - - case nsVDPixmap::kPixFormat_YUV444_Planar: - if (halfchroma) - hfunc = horiz_expand2x_coaligned; - break; - - case nsVDPixmap::kPixFormat_YUV422_Planar: - if (halfchroma) - chroma_srcw = (chroma_srcw + 1) >> 1; - else - hfunc = horiz_compress2x_coaligned; - - w2 = (w2+1) >> 1; - break; - - case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: - if (halfchroma) { - chroma_srcw = (chroma_srcw + 1) >> 1; - hfunc = horiz_realign_to_centered; - } else - hfunc = horiz_compress2x_centered; - - w2 = (w2+1) >> 1; - break; - - case nsVDPixmap::kPixFormat_YUV420_Planar: - if (halfchroma) - chroma_srcw = (chroma_srcw + 1) >> 1; - else - hfunc = horiz_compress2x_coaligned; - - vfunc = vert_compress2x_centered; - winstep = 2; - winposnext = 2; - winsize = 4; - h2 = (h+1) >> 1; - w2 = (w2+1) >> 1; - break; - - case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: - if (halfchroma) { - chroma_srcw = (chroma_srcw + 1) >> 1; - hfunc = horiz_realign_to_centered; - } else - hfunc = horiz_compress2x_centered; - - vfunc = vert_compress2x_centered; - winstep = 2; - winposnext = 2; - winsize = 4; - h2 = (h+1) >> 1; - w2 = (w2+1) >> 1; - break; - - case nsVDPixmap::kPixFormat_YUV411_Planar: - if (halfchroma) { - chroma_srcw = (chroma_srcw + 1) >> 1; - hfunc = horiz_compress2x_coaligned; - } else - hfunc = horiz_compress4x_coaligned; - w2 = (w2+1) >> 2; - break; - - case nsVDPixmap::kPixFormat_YUV410_Planar: - if (halfchroma) { - chroma_srcw = (chroma_srcw + 1) >> 1; - hfunc = horiz_compress2x_coaligned; - } else - hfunc = horiz_compress4x_coaligned; - vfunc = vert_compress4x_centered; - winsize = 8; - winposnext = 5; - winstep = 4; - h2 = (h+3) >> 2; - w2 = (w2+3) >> 2; - break; - } - -#ifdef _M_IX86 - uint32 cpuflags = CPUGetEnabledExtensions(); - - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (hfunc == horiz_expand2x_coaligned) - hfunc = horiz_expand2x_coaligned_ISSE; - } -#endif - - const uint8 *src = (const uint8 *)srcbm.data; - const ptrdiff_t srcpitch = srcbm.pitch; - - uint8 *ydst = (uint8 *)dstbm.data; - uint8 *cbdst = (uint8 *)dstbm.data2; - uint8 *crdst = (uint8 *)dstbm.data3; - const ptrdiff_t ydstpitch = dstbm.pitch; - const ptrdiff_t cbdstpitch = dstbm.pitch2; - const ptrdiff_t crdstpitch = dstbm.pitch3; - - if (!vfunc) { - if (hfunc) { - uint32 tmpsize = (w + 15) & ~15; - - vdblock tmp(tmpsize * 2); - uint8 *const cbtmp = tmp.data(); - uint8 *const crtmp = cbtmp + tmpsize; - - do { - cfunc(ydst, cbtmp, crtmp, src, w); - src += srcpitch; - ydst += ydstpitch; - hfunc(cbdst, cbtmp, chroma_srcw); - hfunc(crdst, crtmp, chroma_srcw); - cbdst += cbdstpitch; - crdst += crdstpitch; - } while(--h); - } else if (dstbm.format == nsVDPixmap::kPixFormat_Y8) { - // wasteful, but oh well - uint32 tmpsize = (w2+15)&~15; - vdblock tmp(tmpsize); - - cbdst = tmp.data(); - crdst = cbdst + tmpsize; - - do { - cfunc(ydst, cbdst, crdst, src, w); - src += srcpitch; - ydst += ydstpitch; - } while(--h2); - } else { - do { - cfunc(ydst, cbdst, crdst, src, w); - src += srcpitch; - ydst += ydstpitch; - cbdst += cbdstpitch; - crdst += crdstpitch; - } while(--h2); - } - } else { - const uint32 tmpsize = w2; - - vdblock tmpbuf(tmpsize * (winsize + 1) * 2 + 2 * w); - - uint8 *cbwindow[16]; - uint8 *crwindow[16]; - - uint8 *p = tmpbuf.data(); - for(int i=0; i +#include +#include +#include +#include +#include +#include "blt_spanutils.h" + +#ifdef _M_IX86 + #include "blt_spanutils_x86.h" +#endif + +using namespace nsVDPixmapSpanUtils; + +namespace { + // From Jim Blinn's "Dirty Pixels": + // + // Y = .299R + .587G + .114B + // Cr = 0.713(R-Y) + // Cb = 0.564(B-Y) + // + // IY = 219Y + 16 = ((yt = 1052IR + 2065IG + 401IB) + 67584) >> 12 + // ICr = 224Cr + 128 = (yt*2987 - 10507932IR + 2155872256) >> 24 + // ICb = 224Cb + 128 = (yt*2363 - 8312025IB + 2155872256) >> 24 + + void ConvertRGB32ToXVYU32(uint32 *dst, const uint8 *src, sint32 count) { + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + const sint32 yt = 1052*r + 2065*g + 401*b; + const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift + const sint32 cr = (10507932*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift + const sint32 cb = ( 8312025*b - yt*2363 + 2155872256U) >> 24; + + *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order + src += 4; + } while(--count); + } + + void ConvertRGB24ToXVYU32(uint32 *dst, const uint8 *src, sint32 count) { + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + const sint32 yt = 1052*r + 2065*g + 401*b; + const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift + const sint32 cr = (10507932*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift + const sint32 cb = ( 8312025*b - yt*2363 + 2155872256U) >> 24; + + *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order + src += 3; + } while(--count); + } + + void ConvertRGB16ToXVYU32(uint32 *dst, const uint16 *src, sint32 count) { + do { + const sint16 px = *src++; + const sint32 r = (px & 0xf800) >> 11; + const sint32 g = (px & 0x07e0) >> 5; + const sint32 b = (px & 0x001f); + const sint32 yt = 8652*r + 8358*g + 3299*b; + const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift + const sint32 cr = (86436217*r - yt*2987 + 2155872256U) >> 8; + const sint32 cb = (68373108*b - yt*2363 + 2155872256U) >> 24; // <<16 alignment shift + + *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order + } while(--count); + } + + void ConvertRGB15ToXVYU32(uint32 *dst, const uint16 *src, sint32 count) { + do { + const sint16 px = *src++; + const sint32 r = (px & 0x7c00) >> 10; + const sint32 g = (px & 0x03e0) >> 5; + const sint32 b = (px & 0x001f); + const sint32 yt = 8652*r + 16986*g + 3299*b; + const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift + const sint32 cr = (86436217*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift + const sint32 cb = (68373108*b - yt*2363 + 2155872256U) >> 24; + + *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order + } while(--count); + } + + void ConvertRGB32ToY8(uint8 *dst, const uint8 *src, sint32 count) { + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + *dst++ = (uint8)((1052*r + 2065*g + 401*b + 67584) >> 12); + src += 4; + } while(--count); + } + + void ConvertRGB24ToY8(uint8 *dst, const uint8 *src, sint32 count) { + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + *dst++ = (uint8)((1052*r + 2065*g + 401*b + 67584) >> 12); + src += 3; + } while(--count); + } + + void ConvertRGB16ToY8(uint8 *dst, const uint16 *src, sint32 count) { + do { + const sint16 px = *src++; + const sint32 r = (px & 0xf800) >> 11; + const sint32 g = (px & 0x07e0) >> 5; + const sint32 b = (px & 0x001f); + *dst++ = (uint8)((8652*r + 8358*g + 3299*b + 67584) >> 12); + } while(--count); + } + + void ConvertRGB15ToY8(uint8 *dst, const uint16 *src, sint32 count) { + do { + const sint16 px = *src++; + const sint32 r = (px & 0x7c00) >> 10; + const sint32 g = (px & 0x03e0) >> 5; + const sint32 b = (px & 0x001f); + *dst++ = (uint8)((8652*r + 16986*g + 3299*b + 67584) >> 12); + } while(--count); + } +} + +#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) + +DECLARE_YUV_REV(XRGB1555, XVYU) { + do { + ConvertRGB15ToXVYU32((uint32 *)dst0, (const uint16 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(RGB565, XVYU) { + do { + ConvertRGB16ToXVYU32((uint32 *)dst0, (const uint16 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(RGB888, XVYU) { + do { + ConvertRGB24ToXVYU32((uint32 *)dst0, (const uint8 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(XRGB8888, XVYU) { + do { + ConvertRGB32ToXVYU32((uint32 *)dst0, (const uint8 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(XRGB1555, Y8) { + do { + ConvertRGB15ToY8((uint8 *)dst0, (const uint16 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(RGB565, Y8) { + do { + ConvertRGB16ToY8((uint8 *)dst0, (const uint16 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(RGB888, Y8) { + do { + ConvertRGB24ToY8((uint8 *)dst0, (const uint8 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(XRGB8888, Y8) { + do { + ConvertRGB32ToY8((uint8 *)dst0, (const uint8 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + + + + + +namespace { + void ConvertRGB32ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint8 *src = (const uint8 *)src0; + + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + const sint32 yt = 1052*r + 2065*g + 401*b; + *ydst++ = (yt + 67584) >> 12; + *crdst++ = (10507932*r - yt*2987 + 2155872256U) >> 24; + *cbdst++ = ( 8312025*b - yt*2363 + 2155872256U) >> 24; + src += 4; + } while(--count); + } + + void ConvertRGB24ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint8 *src = (const uint8 *)src0; + + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + const sint32 yt = 1052*r + 2065*g + 401*b; + *ydst++ = (yt + 67584) >> 12; + *crdst++ = (10507932*r - yt*2987 + 2155872256U) >> 24; + *cbdst++ = ( 8312025*b - yt*2363 + 2155872256U) >> 24; + src += 3; + } while(--count); + } + + void ConvertRGB16ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint16 *src = (const uint16 *)src0; + + do { + const sint16 px = *src++; + const sint32 r = (px & 0xf800) >> 11; + const sint32 g = (px & 0x07e0) >> 5; + const sint32 b = (px & 0x001f); + const sint32 yt = 8652*r + 8358*g + 3299*b; + *ydst++ = (yt + 67584) >> 12; + *crdst++ = (86436217*r - yt*2987 + 2155872256U) >> 24; + *cbdst++ = (68373108*b - yt*2363 + 2155872256U) >> 24; + } while(--count); + } + + void ConvertRGB15ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint16 *src = (const uint16 *)src0; + + do { + const sint16 px = *src++; + const sint32 r = (px & 0x7c00) >> 10; + const sint32 g = (px & 0x03e0) >> 5; + const sint32 b = (px & 0x001f); + const sint32 yt = 8652*r + 16986*g + 3299*b; + *ydst++ = (yt + 67584) >> 12; + *crdst++ = (86436217*r - yt*2987 + 2155872256U) >> 24; + *cbdst++ = (68373108*b - yt*2363 + 2155872256U) >> 24; + } while(--count); + } + + void ConvertUYVYToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint8 *src = (const uint8 *)src0; + + do { + *cbdst++ = src[0]; + *ydst++ = src[1]; + *crdst++ = src[2]; + if (!--count) + break; + *ydst++ = src[3]; + src += 4; + } while(--count); + } + + void ConvertYUYVToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint8 *src = (const uint8 *)src0; + + do { + *cbdst++ = src[1]; + *ydst++ = src[0]; + *crdst++ = src[3]; + if (!--count) + break; + *ydst++ = src[2]; + src += 4; + } while(--count); + } +} + +void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dstbm, const VDPixmap& srcbm, vdpixsize w, vdpixsize h) { + void (*cfunc)(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src, sint32 w) = NULL; + void (*hfunc)(uint8 *dst, const uint8 *src, sint32 w) = NULL; + void (*vfunc)(uint8 *dst, const uint8 *const *sources, sint32 w, uint8 phase) = NULL; + + bool halfchroma = false; + + switch(srcbm.format) { + case nsVDPixmap::kPixFormat_XRGB1555: + cfunc = ConvertRGB15ToYUVPlanar; + break; + case nsVDPixmap::kPixFormat_RGB565: + cfunc = ConvertRGB16ToYUVPlanar; + break; + case nsVDPixmap::kPixFormat_RGB888: + cfunc = ConvertRGB24ToYUVPlanar; + break; + case nsVDPixmap::kPixFormat_XRGB8888: + cfunc = ConvertRGB32ToYUVPlanar; + break; + case nsVDPixmap::kPixFormat_YUV422_UYVY: + cfunc = ConvertUYVYToYUVPlanar; + halfchroma = true; + break; + case nsVDPixmap::kPixFormat_YUV422_YUYV: + cfunc = ConvertYUYVToYUVPlanar; + halfchroma = true; + break; + default: + VDNEVERHERE; + return; + } + + vdpixsize w2 = w; + vdpixsize h2 = h; + int winstep = 1; + int winsize = 1; + int winposnext = 0; + vdpixsize chroma_srcw = w; + + switch(dstbm.format) { + + case nsVDPixmap::kPixFormat_YUV444_Planar: + if (halfchroma) + hfunc = horiz_expand2x_coaligned; + break; + + case nsVDPixmap::kPixFormat_YUV422_Planar: + if (halfchroma) + chroma_srcw = (chroma_srcw + 1) >> 1; + else + hfunc = horiz_compress2x_coaligned; + + w2 = (w2+1) >> 1; + break; + + case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: + if (halfchroma) { + chroma_srcw = (chroma_srcw + 1) >> 1; + hfunc = horiz_realign_to_centered; + } else + hfunc = horiz_compress2x_centered; + + w2 = (w2+1) >> 1; + break; + + case nsVDPixmap::kPixFormat_YUV420_Planar: + if (halfchroma) + chroma_srcw = (chroma_srcw + 1) >> 1; + else + hfunc = horiz_compress2x_coaligned; + + vfunc = vert_compress2x_centered; + winstep = 2; + winposnext = 2; + winsize = 4; + h2 = (h+1) >> 1; + w2 = (w2+1) >> 1; + break; + + case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: + if (halfchroma) { + chroma_srcw = (chroma_srcw + 1) >> 1; + hfunc = horiz_realign_to_centered; + } else + hfunc = horiz_compress2x_centered; + + vfunc = vert_compress2x_centered; + winstep = 2; + winposnext = 2; + winsize = 4; + h2 = (h+1) >> 1; + w2 = (w2+1) >> 1; + break; + + case nsVDPixmap::kPixFormat_YUV411_Planar: + if (halfchroma) { + chroma_srcw = (chroma_srcw + 1) >> 1; + hfunc = horiz_compress2x_coaligned; + } else + hfunc = horiz_compress4x_coaligned; + w2 = (w2+1) >> 2; + break; + + case nsVDPixmap::kPixFormat_YUV410_Planar: + if (halfchroma) { + chroma_srcw = (chroma_srcw + 1) >> 1; + hfunc = horiz_compress2x_coaligned; + } else + hfunc = horiz_compress4x_coaligned; + vfunc = vert_compress4x_centered; + winsize = 8; + winposnext = 5; + winstep = 4; + h2 = (h+3) >> 2; + w2 = (w2+3) >> 2; + break; + } + +#ifdef _M_IX86 + uint32 cpuflags = CPUGetEnabledExtensions(); + + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (hfunc == horiz_expand2x_coaligned) + hfunc = horiz_expand2x_coaligned_ISSE; + } +#endif + + const uint8 *src = (const uint8 *)srcbm.data; + const ptrdiff_t srcpitch = srcbm.pitch; + + uint8 *ydst = (uint8 *)dstbm.data; + uint8 *cbdst = (uint8 *)dstbm.data2; + uint8 *crdst = (uint8 *)dstbm.data3; + const ptrdiff_t ydstpitch = dstbm.pitch; + const ptrdiff_t cbdstpitch = dstbm.pitch2; + const ptrdiff_t crdstpitch = dstbm.pitch3; + + if (!vfunc) { + if (hfunc) { + uint32 tmpsize = (w + 15) & ~15; + + vdblock tmp(tmpsize * 2); + uint8 *const cbtmp = tmp.data(); + uint8 *const crtmp = cbtmp + tmpsize; + + do { + cfunc(ydst, cbtmp, crtmp, src, w); + src += srcpitch; + ydst += ydstpitch; + hfunc(cbdst, cbtmp, chroma_srcw); + hfunc(crdst, crtmp, chroma_srcw); + cbdst += cbdstpitch; + crdst += crdstpitch; + } while(--h); + } else if (dstbm.format == nsVDPixmap::kPixFormat_Y8) { + // wasteful, but oh well + uint32 tmpsize = (w2+15)&~15; + vdblock tmp(tmpsize); + + cbdst = tmp.data(); + crdst = cbdst + tmpsize; + + do { + cfunc(ydst, cbdst, crdst, src, w); + src += srcpitch; + ydst += ydstpitch; + } while(--h2); + } else { + do { + cfunc(ydst, cbdst, crdst, src, w); + src += srcpitch; + ydst += ydstpitch; + cbdst += cbdstpitch; + crdst += crdstpitch; + } while(--h2); + } + } else { + const uint32 tmpsize = w2; + + vdblock tmpbuf(tmpsize * (winsize + 1) * 2 + 2 * w); + + uint8 *cbwindow[16]; + uint8 *crwindow[16]; + + uint8 *p = tmpbuf.data(); + for(int i=0; i -#include "blt_setup.h" - -void VDPixmapBlitterTable::Clear() { - memset(mTable, 0, sizeof mTable); -} - -void VDPixmapBlitterTable::AddBlitter(const VDPixmapFormatSubset& srcFormats, VDPixmapFormatSubset& dstFormats, VDPixmapBlitterFn blitter) { - for(int i=0; i +#include "blt_setup.h" + +void VDPixmapBlitterTable::Clear() { + memset(mTable, 0, sizeof mTable); +} + +void VDPixmapBlitterTable::AddBlitter(const VDPixmapFormatSubset& srcFormats, VDPixmapFormatSubset& dstFormats, VDPixmapBlitterFn blitter) { + for(int i=0; i -#include "blt_spanutils.h" -#include "bitutils.h" - -using namespace nsVDPixmapBitUtils; - -namespace nsVDPixmapSpanUtils { - void horiz_expand2x_centered(uint8 *dst, const uint8 *src, sint32 w) { - w = -w; - - *dst++ = *src; - - if (++w) { - if (++w) { - do { - dst[0] = (uint8)((3*src[0] + src[1] + 2)>>2); - dst[1] = (uint8)((src[0] + 3*src[1] + 2)>>2); - dst += 2; - ++src; - } while((w+=2)<0); - } - - if (!(w & 1)) { - *dst = src[0]; - } - } - } - - void horiz_expand2x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - w = -w; - - if ((w+=2) < 0) { - do { - dst[0] = src[0]; - dst[1] = (uint8)((src[0] + src[1] + 1)>>1); - dst += 2; - ++src; - } while((w+=2)<0); - } - - w -= 2; - while(w < 0) { - ++w; - *dst++ = src[0]; - } - } - - void horiz_expand4x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - w = -w; - - if ((w+=4) < 0) { - do { - dst[0] = src[0]; - dst[1] = (uint8)((3*src[0] + src[1] + 2)>>2); - dst[2] = (uint8)((src[0] + src[1] + 1)>>1); - dst[3] = (uint8)((src[0] + 3*src[1] + 2)>>2); - dst += 4; - ++src; - } while((w+=4)<0); - } - - w -= 4; - while(w < 0) { - ++w; - *dst++ = src[0]; - } - } - - void horiz_compress2x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - if (w == 1) { - *dst = *src; - return; - } - - *dst++ = (uint8)((3*src[0] + src[1] + 2) >> 2); - ++src; - --w; - - while(w >= 3) { - w -= 2; - *dst++ = (uint8)((src[0] + 2*src[1] + src[2] + 2) >> 2); - src += 2; - } - - if (w >= 2) - *dst++ = (uint8)((src[0] + 3*src[1] + 2) >> 2); - } - - void horiz_compress2x_centered(uint8 *dst, const uint8 *src, sint32 w) { - if (w == 1) { - *dst = *src; - return; - } - - if (w == 2) { - *dst = (uint8)((src[0] + src[1] + 1) >> 1); - return; - } - - *dst++ = (uint8)((4*src[0] + 3*src[1] + src[2] + 4) >> 3); - --w; - ++src; - - while(w >= 4) { - w -= 2; - *dst++ = (uint8)(((src[0] + src[3]) + 3*(src[1] + src[2]) + 4) >> 3); - src += 2; - } - - switch(w) { - case 3: - *dst++ = (uint8)((src[0] + 3*src[1] + 4*src[2] + 4) >> 3); - break; - case 2: - *dst++ = (uint8)((src[0] + 7*src[1] + 4) >> 3); - break; - } - } - - void horiz_compress4x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - if (w == 1) { - *dst = *src; - return; - } - - if (w == 2) { - *dst++ = (uint8)((11*src[0] + 5*src[1] + 8) >> 4); - return; - } - - *dst++ = (uint8)((11*src[0] + 4*src[1] + src[2] + 8) >> 4); - src += 2; - w -= 2; - - while(w >= 5) { - w -= 4; - *dst++ = (uint8)(((src[0] + src[4]) + 4*(src[1] + src[3]) + 6*src[2] + 8) >> 4); - src += 4; - } - - switch(w) { - case 4: - *dst = (uint8)((src[0] + 4*src[1] + 6*src[2] + 5*src[3] + 8) >> 4); - break; - case 3: - *dst = (uint8)((src[0] + 4*src[1] + 11*src[2] + 8) >> 4); - break; - } - } - - void horiz_compress4x_centered(uint8 *dst, const uint8 *src, sint32 w) { - - switch(w) { - case 1: - *dst = *src; - return; - case 2: // 29 99 - *dst = (uint8)((29*src[0] + 99*src[1] + 64) >> 7); - return; - case 3: // 29 35 64 - *dst = (uint8)((29*src[0] + 35*src[1] + 64*src[1] + 64) >> 7); - return; - case 4: // 29 35 35 29 - *dst = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 29*src[3] + 64) >> 7); - return; - case 5: // 29 35 35 21 8 - // 1 7 120 - dst[0] = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 21*src[3] + 8*src[4] + 64) >> 7); - dst[1] = (uint8)((src[2] + 7*src[3] + 120*src[4] + 64) >> 7); - return; - } - - *dst++ = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 21*src[3] + 7*src[4] + src[5] + 64) >> 7); - src += 2; - w -= 2; - - while(w >= 8) { - w -= 4; - *dst++ = (uint8)(((src[0] + src[7]) + 7*(src[1] + src[6]) + 21*(src[2] + src[5]) + 35*(src[3] + src[4]) + 64) >> 7); - src += 4; - } - - switch(w) { - case 4: // 1 7 21 99 - *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 99*src[3] + 64) >> 7); - break; - case 5: // 1 7 21 35 64 - *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 35*src[3] + 64*src[4] + 64) >> 7); - break; - case 6: // 1 7 21 35 35 29 - *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 29*src[5] + 35*(src[3] + src[4]) + 64) >> 7); - break; - case 7: // 1 7 21 35 35 21 8 - // 1 7 120 - dst[0] = (uint8)((src[0] + 7*src[1] + 8*src[6] + 21*(src[2] + src[5]) + 35*(src[3] + src[4]) + 64) >> 7); - dst[1] = (uint8)((src[4] + 7*src[5] + 120*src[6] + 64) >> 7); - break; - } - } - - void horiz_realign_to_centered(uint8 *dst, const uint8 *src, sint32 w) { - // luma samples: Y Y Y Y Y - // coaligned: C C C - // centered: C C - // - // To realign coaligned samples to centered, we need to shift them - // right by a quarter sample in chroma space. This can be done via - // a [3 1]/4 filter. - - for(sint32 i=1; i> 2); - ++dst; - ++src; - } - - *dst++ = *src++; - } - - void horiz_realign_to_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - // luma samples: Y Y Y Y Y - // coaligned: C C C - // centered: C C - // - // To realign centered samples to coaligned, we need to shift them - // left by a quarter sample in chroma space. This can be done via - // a [1 3]/4 filter. - - *dst++ = *src++; - - for(sint32 i=1; i> 2); - ++dst; - ++src; - } - } - - void vert_expand2x_centered(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { - const uint8 *src3 = srcs[0]; - const uint8 *src1 = srcs[1]; - - if (phase >= 128) - std::swap(src1, src3); - - sint32 w4 = w>>2; - w &= 3; - - if (w4) { - const uint32 *src34 = (const uint32 *)src3; - const uint32 *src14 = (const uint32 *)src1; - uint32 *dst4 = ( uint32 *)dst; - - do { - const uint32 a = *src34++; - const uint32 b = *src14++; - const uint32 ab = (a&b) + (((a^b)&0xfefefefe)>>1); - - *dst4++ = (a|ab) - (((a^ab)&0xfefefefe)>>1); - } while(--w4); - - src3 = (const uint8 *)src34; - src1 = (const uint8 *)src14; - dst = ( uint8 *)dst4; - } - - if (w) { - do { - *dst++ = (uint8)((*src1++ + 3**src3++ + 2) >> 2); - } while(--w); - } - } - - void vert_expand4x_centered(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { - const uint8 *src3 = srcs[0]; - const uint8 *src1 = srcs[1]; - - switch(phase & 0xc0) { - case 0x00: - do { - *dst++ = (uint8)((1**src1++ + 7**src3++ + 4) >> 3); - } while(--w); - break; - case 0x40: - do { - *dst++ = (uint8)((3**src1++ + 5**src3++ + 4) >> 3); - } while(--w); - break; - case 0x80: - do { - *dst++ = (uint8)((5**src1++ + 3**src3++ + 4) >> 3); - } while(--w); - break; - case 0xc0: - do { - *dst++ = (uint8)((7**src1++ + 1**src3++ + 4) >> 3); - } while(--w); - break; - default: - VDNEVERHERE; - } - } - - void vert_compress2x_centered_fast(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { - const uint8 *src1 = srcarray[0]; - const uint8 *src2 = srcarray[1]; - - w = -w; - w += 3; - - while(w < 0) { - *(uint32 *)dst = avg_8888_11(*(uint32 *)src1, *(uint32 *)src2); - dst += 4; - src1 += 4; - src2 += 4; - w += 4; - } - - w -= 3; - - while(w < 0) { - *dst = (uint8)((*src1 + *src2 + 1)>>1); - ++dst; - ++src1; - ++src2; - ++w; - } - } - - void vert_compress2x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { - const uint8 *src1 = srcarray[0]; - const uint8 *src2 = srcarray[1]; - const uint8 *src3 = srcarray[2]; - const uint8 *src4 = srcarray[3]; - - w = -w; - - while(w < 0) { - *dst++ = (uint8)(((*src1++ + *src4++) + 3*(*src2++ + *src3++) + 4)>>3); - ++w; - } - } - - void vert_compress4x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { - const uint8 *src1 = srcarray[0]; - const uint8 *src2 = srcarray[1]; - const uint8 *src3 = srcarray[2]; - const uint8 *src4 = srcarray[3]; - const uint8 *src5 = srcarray[4]; - const uint8 *src6 = srcarray[5]; - const uint8 *src7 = srcarray[6]; - const uint8 *src8 = srcarray[7]; - - w = -w; - - while(w < 0) { - int sum18 = *src1++ + *src8++; - int sum27 = *src2++ + *src7++; - int sum36 = *src3++ + *src6++; - int sum45 = *src4++ + *src5++; - - *dst++ = (uint8)((sum18 + 7*sum27 + 21*sum36 + 35*sum45 + 64) >> 7); - - ++w; - } - } -} - +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "blt_spanutils.h" +#include "bitutils.h" + +using namespace nsVDPixmapBitUtils; + +namespace nsVDPixmapSpanUtils { + void horiz_expand2x_centered(uint8 *dst, const uint8 *src, sint32 w) { + w = -w; + + *dst++ = *src; + + if (++w) { + if (++w) { + do { + dst[0] = (uint8)((3*src[0] + src[1] + 2)>>2); + dst[1] = (uint8)((src[0] + 3*src[1] + 2)>>2); + dst += 2; + ++src; + } while((w+=2)<0); + } + + if (!(w & 1)) { + *dst = src[0]; + } + } + } + + void horiz_expand2x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + w = -w; + + if ((w+=2) < 0) { + do { + dst[0] = src[0]; + dst[1] = (uint8)((src[0] + src[1] + 1)>>1); + dst += 2; + ++src; + } while((w+=2)<0); + } + + w -= 2; + while(w < 0) { + ++w; + *dst++ = src[0]; + } + } + + void horiz_expand4x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + w = -w; + + if ((w+=4) < 0) { + do { + dst[0] = src[0]; + dst[1] = (uint8)((3*src[0] + src[1] + 2)>>2); + dst[2] = (uint8)((src[0] + src[1] + 1)>>1); + dst[3] = (uint8)((src[0] + 3*src[1] + 2)>>2); + dst += 4; + ++src; + } while((w+=4)<0); + } + + w -= 4; + while(w < 0) { + ++w; + *dst++ = src[0]; + } + } + + void horiz_compress2x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + if (w == 1) { + *dst = *src; + return; + } + + *dst++ = (uint8)((3*src[0] + src[1] + 2) >> 2); + ++src; + --w; + + while(w >= 3) { + w -= 2; + *dst++ = (uint8)((src[0] + 2*src[1] + src[2] + 2) >> 2); + src += 2; + } + + if (w >= 2) + *dst++ = (uint8)((src[0] + 3*src[1] + 2) >> 2); + } + + void horiz_compress2x_centered(uint8 *dst, const uint8 *src, sint32 w) { + if (w == 1) { + *dst = *src; + return; + } + + if (w == 2) { + *dst = (uint8)((src[0] + src[1] + 1) >> 1); + return; + } + + *dst++ = (uint8)((4*src[0] + 3*src[1] + src[2] + 4) >> 3); + --w; + ++src; + + while(w >= 4) { + w -= 2; + *dst++ = (uint8)(((src[0] + src[3]) + 3*(src[1] + src[2]) + 4) >> 3); + src += 2; + } + + switch(w) { + case 3: + *dst++ = (uint8)((src[0] + 3*src[1] + 4*src[2] + 4) >> 3); + break; + case 2: + *dst++ = (uint8)((src[0] + 7*src[1] + 4) >> 3); + break; + } + } + + void horiz_compress4x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + if (w == 1) { + *dst = *src; + return; + } + + if (w == 2) { + *dst++ = (uint8)((11*src[0] + 5*src[1] + 8) >> 4); + return; + } + + *dst++ = (uint8)((11*src[0] + 4*src[1] + src[2] + 8) >> 4); + src += 2; + w -= 2; + + while(w >= 5) { + w -= 4; + *dst++ = (uint8)(((src[0] + src[4]) + 4*(src[1] + src[3]) + 6*src[2] + 8) >> 4); + src += 4; + } + + switch(w) { + case 4: + *dst = (uint8)((src[0] + 4*src[1] + 6*src[2] + 5*src[3] + 8) >> 4); + break; + case 3: + *dst = (uint8)((src[0] + 4*src[1] + 11*src[2] + 8) >> 4); + break; + } + } + + void horiz_compress4x_centered(uint8 *dst, const uint8 *src, sint32 w) { + + switch(w) { + case 1: + *dst = *src; + return; + case 2: // 29 99 + *dst = (uint8)((29*src[0] + 99*src[1] + 64) >> 7); + return; + case 3: // 29 35 64 + *dst = (uint8)((29*src[0] + 35*src[1] + 64*src[1] + 64) >> 7); + return; + case 4: // 29 35 35 29 + *dst = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 29*src[3] + 64) >> 7); + return; + case 5: // 29 35 35 21 8 + // 1 7 120 + dst[0] = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 21*src[3] + 8*src[4] + 64) >> 7); + dst[1] = (uint8)((src[2] + 7*src[3] + 120*src[4] + 64) >> 7); + return; + } + + *dst++ = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 21*src[3] + 7*src[4] + src[5] + 64) >> 7); + src += 2; + w -= 2; + + while(w >= 8) { + w -= 4; + *dst++ = (uint8)(((src[0] + src[7]) + 7*(src[1] + src[6]) + 21*(src[2] + src[5]) + 35*(src[3] + src[4]) + 64) >> 7); + src += 4; + } + + switch(w) { + case 4: // 1 7 21 99 + *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 99*src[3] + 64) >> 7); + break; + case 5: // 1 7 21 35 64 + *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 35*src[3] + 64*src[4] + 64) >> 7); + break; + case 6: // 1 7 21 35 35 29 + *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 29*src[5] + 35*(src[3] + src[4]) + 64) >> 7); + break; + case 7: // 1 7 21 35 35 21 8 + // 1 7 120 + dst[0] = (uint8)((src[0] + 7*src[1] + 8*src[6] + 21*(src[2] + src[5]) + 35*(src[3] + src[4]) + 64) >> 7); + dst[1] = (uint8)((src[4] + 7*src[5] + 120*src[6] + 64) >> 7); + break; + } + } + + void horiz_realign_to_centered(uint8 *dst, const uint8 *src, sint32 w) { + // luma samples: Y Y Y Y Y + // coaligned: C C C + // centered: C C + // + // To realign coaligned samples to centered, we need to shift them + // right by a quarter sample in chroma space. This can be done via + // a [3 1]/4 filter. + + for(sint32 i=1; i> 2); + ++dst; + ++src; + } + + *dst++ = *src++; + } + + void horiz_realign_to_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + // luma samples: Y Y Y Y Y + // coaligned: C C C + // centered: C C + // + // To realign centered samples to coaligned, we need to shift them + // left by a quarter sample in chroma space. This can be done via + // a [1 3]/4 filter. + + *dst++ = *src++; + + for(sint32 i=1; i> 2); + ++dst; + ++src; + } + } + + void vert_expand2x_centered(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { + const uint8 *src3 = srcs[0]; + const uint8 *src1 = srcs[1]; + + if (phase >= 128) + std::swap(src1, src3); + + sint32 w4 = w>>2; + w &= 3; + + if (w4) { + const uint32 *src34 = (const uint32 *)src3; + const uint32 *src14 = (const uint32 *)src1; + uint32 *dst4 = ( uint32 *)dst; + + do { + const uint32 a = *src34++; + const uint32 b = *src14++; + const uint32 ab = (a&b) + (((a^b)&0xfefefefe)>>1); + + *dst4++ = (a|ab) - (((a^ab)&0xfefefefe)>>1); + } while(--w4); + + src3 = (const uint8 *)src34; + src1 = (const uint8 *)src14; + dst = ( uint8 *)dst4; + } + + if (w) { + do { + *dst++ = (uint8)((*src1++ + 3**src3++ + 2) >> 2); + } while(--w); + } + } + + void vert_expand4x_centered(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { + const uint8 *src3 = srcs[0]; + const uint8 *src1 = srcs[1]; + + switch(phase & 0xc0) { + case 0x00: + do { + *dst++ = (uint8)((1**src1++ + 7**src3++ + 4) >> 3); + } while(--w); + break; + case 0x40: + do { + *dst++ = (uint8)((3**src1++ + 5**src3++ + 4) >> 3); + } while(--w); + break; + case 0x80: + do { + *dst++ = (uint8)((5**src1++ + 3**src3++ + 4) >> 3); + } while(--w); + break; + case 0xc0: + do { + *dst++ = (uint8)((7**src1++ + 1**src3++ + 4) >> 3); + } while(--w); + break; + default: + VDNEVERHERE; + } + } + + void vert_compress2x_centered_fast(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { + const uint8 *src1 = srcarray[0]; + const uint8 *src2 = srcarray[1]; + + w = -w; + w += 3; + + while(w < 0) { + *(uint32 *)dst = avg_8888_11(*(uint32 *)src1, *(uint32 *)src2); + dst += 4; + src1 += 4; + src2 += 4; + w += 4; + } + + w -= 3; + + while(w < 0) { + *dst = (uint8)((*src1 + *src2 + 1)>>1); + ++dst; + ++src1; + ++src2; + ++w; + } + } + + void vert_compress2x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { + const uint8 *src1 = srcarray[0]; + const uint8 *src2 = srcarray[1]; + const uint8 *src3 = srcarray[2]; + const uint8 *src4 = srcarray[3]; + + w = -w; + + while(w < 0) { + *dst++ = (uint8)(((*src1++ + *src4++) + 3*(*src2++ + *src3++) + 4)>>3); + ++w; + } + } + + void vert_compress4x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { + const uint8 *src1 = srcarray[0]; + const uint8 *src2 = srcarray[1]; + const uint8 *src3 = srcarray[2]; + const uint8 *src4 = srcarray[3]; + const uint8 *src5 = srcarray[4]; + const uint8 *src6 = srcarray[5]; + const uint8 *src7 = srcarray[6]; + const uint8 *src8 = srcarray[7]; + + w = -w; + + while(w < 0) { + int sum18 = *src1++ + *src8++; + int sum27 = *src2++ + *src7++; + int sum36 = *src3++ + *src6++; + int sum45 = *src4++ + *src5++; + + *dst++ = (uint8)((sum18 + 7*sum27 + 21*sum36 + 35*sum45 + 64) >> 7); + + ++w; + } + } +} + diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_spanutils_x86.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_spanutils_x86.cpp index f529444caed..ffe4cafb702 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_spanutils_x86.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_spanutils_x86.cpp @@ -1,171 +1,171 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include "blt_spanutils_x86.h" - -#ifdef _MSC_VER - #pragma warning(disable: 4799) // warning C4799: function 'nsVDPixmapSpanUtils::vdasm_horiz_expand2x_coaligned_ISSE' has no EMMS instruction -#endif - -extern "C" void __cdecl vdasm_horiz_expand2x_coaligned_ISSE(void *dst, const void *src, uint32 count); -extern "C" void __cdecl vdasm_horiz_expand4x_coaligned_MMX(void *dst, const void *src, uint32 count); -extern "C" void __cdecl vdasm_vert_average_13_ISSE(void *dst, const void *src1, const void *src3, uint32 count); -extern "C" void __cdecl vdasm_vert_average_17_ISSE(void *dst, const void *src1, const void *src3, uint32 count); -extern "C" void __cdecl vdasm_vert_average_35_ISSE(void *dst, const void *src1, const void *src3, uint32 count); - -namespace nsVDPixmapSpanUtils { - - void horiz_expand2x_coaligned_ISSE(uint8 *dst, const uint8 *src, sint32 w) { - if (w >= 17) { - uint32 fastcount = (w - 1) & ~15; - - vdasm_horiz_expand2x_coaligned_ISSE(dst, src, fastcount); - dst += fastcount; - src += fastcount >> 1; - w -= fastcount; - } - - w = -w; - if ((w+=2) < 0) { - do { - dst[0] = src[0]; - dst[1] = (uint8)((src[0] + src[1] + 1)>>1); - dst += 2; - ++src; - } while((w+=2)<0); - } - - w -= 2; - while(w < 0) { - ++w; - *dst++ = src[0]; - } - } - - void horiz_expand4x_coaligned_MMX(uint8 *dst, const uint8 *src, sint32 w) { - if (w >= 17) { - uint32 fastcount = (w - 1) >> 4; - - vdasm_horiz_expand4x_coaligned_MMX(dst, src, fastcount); - dst += fastcount << 4; - src += fastcount << 2; - w -= fastcount << 4; - } - - w = -w; - if ((w+=4) < 0) { - do { - dst[0] = src[0]; - dst[1] = (uint8)((3*src[0] + src[1] + 2)>>2); - dst[2] = (uint8)((src[0] + src[1] + 1)>>1); - dst[3] = (uint8)((src[0] + 3*src[1] + 2)>>2); - dst += 4; - ++src; - } while((w+=4)<0); - } - - w -= 4; - while(w < 0) { - ++w; - *dst++ = src[0]; - } - } - - void vert_expand2x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { - const uint8 *src3 = srcs[0]; - const uint8 *src1 = srcs[1]; - - if (phase >= 128) - std::swap(src1, src3); - - uint32 fastcount = w & ~15; - - if (fastcount) { - vdasm_vert_average_13_ISSE(dst, src1, src3, fastcount); - dst += fastcount; - src1 += fastcount; - src3 += fastcount; - w -= fastcount; - } - - if (w) { - do { - *dst++ = (uint8)((*src1++ + 3**src3++ + 2) >> 2); - } while(--w); - } - } - - void vert_average_1_7_ISSE(uint8 *dst, const uint8 *src7, const uint8 *src1, sint32 w) { - uint32 fastcount = w & ~7; - - if (fastcount) { - vdasm_vert_average_17_ISSE(dst, src1, src7, fastcount); - dst += fastcount; - src1 += fastcount; - src7 += fastcount; - w -= fastcount; - } - - if (w) { - do { - *dst++ = (uint8)((*src1++ + 7**src7++ + 4) >> 3); - } while(--w); - } - } - - void vert_average_3_5_ISSE(uint8 *dst, const uint8 *src7, const uint8 *src1, sint32 w) { - uint32 fastcount = w & ~7; - - if (fastcount) { - vdasm_vert_average_35_ISSE(dst, src1, src7, fastcount); - dst += fastcount; - src1 += fastcount; - src7 += fastcount; - w -= fastcount; - } - - if (w) { - do { - *dst++ = (uint8)((3**src1++ + 5**src7++ + 4) >> 3); - } while(--w); - } - } - - void vert_expand4x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { - const uint8 *src1 = srcs[0]; - const uint8 *src2 = srcs[1]; - - switch(phase & 0xc0) { - case 0x00: - vert_average_1_7_ISSE(dst, src2, src1, w); - break; - case 0x40: - vert_average_3_5_ISSE(dst, src2, src1, w); - break; - case 0x80: - vert_average_3_5_ISSE(dst, src1, src2, w); - break; - case 0xc0: - vert_average_1_7_ISSE(dst, src1, src2, w); - break; - default: - VDNEVERHERE; - } - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "blt_spanutils_x86.h" + +#ifdef _MSC_VER + #pragma warning(disable: 4799) // warning C4799: function 'nsVDPixmapSpanUtils::vdasm_horiz_expand2x_coaligned_ISSE' has no EMMS instruction +#endif + +extern "C" void __cdecl vdasm_horiz_expand2x_coaligned_ISSE(void *dst, const void *src, uint32 count); +extern "C" void __cdecl vdasm_horiz_expand4x_coaligned_MMX(void *dst, const void *src, uint32 count); +extern "C" void __cdecl vdasm_vert_average_13_ISSE(void *dst, const void *src1, const void *src3, uint32 count); +extern "C" void __cdecl vdasm_vert_average_17_ISSE(void *dst, const void *src1, const void *src3, uint32 count); +extern "C" void __cdecl vdasm_vert_average_35_ISSE(void *dst, const void *src1, const void *src3, uint32 count); + +namespace nsVDPixmapSpanUtils { + + void horiz_expand2x_coaligned_ISSE(uint8 *dst, const uint8 *src, sint32 w) { + if (w >= 17) { + uint32 fastcount = (w - 1) & ~15; + + vdasm_horiz_expand2x_coaligned_ISSE(dst, src, fastcount); + dst += fastcount; + src += fastcount >> 1; + w -= fastcount; + } + + w = -w; + if ((w+=2) < 0) { + do { + dst[0] = src[0]; + dst[1] = (uint8)((src[0] + src[1] + 1)>>1); + dst += 2; + ++src; + } while((w+=2)<0); + } + + w -= 2; + while(w < 0) { + ++w; + *dst++ = src[0]; + } + } + + void horiz_expand4x_coaligned_MMX(uint8 *dst, const uint8 *src, sint32 w) { + if (w >= 17) { + uint32 fastcount = (w - 1) >> 4; + + vdasm_horiz_expand4x_coaligned_MMX(dst, src, fastcount); + dst += fastcount << 4; + src += fastcount << 2; + w -= fastcount << 4; + } + + w = -w; + if ((w+=4) < 0) { + do { + dst[0] = src[0]; + dst[1] = (uint8)((3*src[0] + src[1] + 2)>>2); + dst[2] = (uint8)((src[0] + src[1] + 1)>>1); + dst[3] = (uint8)((src[0] + 3*src[1] + 2)>>2); + dst += 4; + ++src; + } while((w+=4)<0); + } + + w -= 4; + while(w < 0) { + ++w; + *dst++ = src[0]; + } + } + + void vert_expand2x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { + const uint8 *src3 = srcs[0]; + const uint8 *src1 = srcs[1]; + + if (phase >= 128) + std::swap(src1, src3); + + uint32 fastcount = w & ~15; + + if (fastcount) { + vdasm_vert_average_13_ISSE(dst, src1, src3, fastcount); + dst += fastcount; + src1 += fastcount; + src3 += fastcount; + w -= fastcount; + } + + if (w) { + do { + *dst++ = (uint8)((*src1++ + 3**src3++ + 2) >> 2); + } while(--w); + } + } + + void vert_average_1_7_ISSE(uint8 *dst, const uint8 *src7, const uint8 *src1, sint32 w) { + uint32 fastcount = w & ~7; + + if (fastcount) { + vdasm_vert_average_17_ISSE(dst, src1, src7, fastcount); + dst += fastcount; + src1 += fastcount; + src7 += fastcount; + w -= fastcount; + } + + if (w) { + do { + *dst++ = (uint8)((*src1++ + 7**src7++ + 4) >> 3); + } while(--w); + } + } + + void vert_average_3_5_ISSE(uint8 *dst, const uint8 *src7, const uint8 *src1, sint32 w) { + uint32 fastcount = w & ~7; + + if (fastcount) { + vdasm_vert_average_35_ISSE(dst, src1, src7, fastcount); + dst += fastcount; + src1 += fastcount; + src7 += fastcount; + w -= fastcount; + } + + if (w) { + do { + *dst++ = (uint8)((3**src1++ + 5**src7++ + 4) >> 3); + } while(--w); + } + } + + void vert_expand4x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { + const uint8 *src1 = srcs[0]; + const uint8 *src2 = srcs[1]; + + switch(phase & 0xc0) { + case 0x00: + vert_average_1_7_ISSE(dst, src2, src1, w); + break; + case 0x40: + vert_average_3_5_ISSE(dst, src2, src1, w); + break; + case 0x80: + vert_average_3_5_ISSE(dst, src1, src2, w); + break; + case 0xc0: + vert_average_1_7_ISSE(dst, src1, src2, w); + break; + default: + VDNEVERHERE; + } + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_uberblit.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_uberblit.cpp index 73eb269e8d1..ce654ae310c 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_uberblit.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_uberblit.cpp @@ -1,38 +1,38 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include "uberblit.h" - -void VDPixmapBlt_UberblitAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - vdautoptr blitter(VDPixmapCreateBlitter(dst, src)); - - if (w > src.w) - w = src.w; - if (w > dst.w) - w = dst.w; - if (h > src.h) - h = src.h; - if (h > dst.h) - h = dst.h; - - vdrect32 r(0, 0, w, h); - blitter->Blit(dst, &r, src); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include "uberblit.h" + +void VDPixmapBlt_UberblitAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + vdautoptr blitter(VDPixmapCreateBlitter(dst, src)); + + if (w > src.w) + w = src.w; + if (w > dst.w) + w = dst.w; + if (h > src.h) + h = src.h; + if (h > dst.h) + h = dst.h; + + vdrect32 r(0, 0, w, h); + blitter->Blit(dst, &r, src); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_x86.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_x86.cpp index 29cce407fc5..a37c50a95a6 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_x86.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_x86.cpp @@ -1,163 +1,163 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include "blt_setup.h" - -void VDPixmapInitBlittersReference(VDPixmapBlitterTable& table); - -#define DECLARE_PALETTED(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0); -#define DECLARE_RGB(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -#define DECLARE_RGB_ASM(x, y) extern "C" void vdasm_pixblt_##x##_to_##y(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -#define DECLARE_RGB_ASM_MMX(x, y) extern "C" void vdasm_pixblt_##x##_to_##y##_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -#define DECLARE_YUV(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV_PLANAR(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); - - DECLARE_RGB_ASM(RGB565, XRGB1555); DECLARE_RGB_ASM_MMX(RGB565, XRGB1555); - DECLARE_RGB_ASM(RGB888, XRGB1555); - DECLARE_RGB_ASM(XRGB8888, XRGB1555); DECLARE_RGB_ASM_MMX(XRGB8888, XRGB1555); - DECLARE_RGB_ASM(XRGB1555, RGB565); DECLARE_RGB_ASM_MMX(XRGB1555, RGB565); - DECLARE_RGB_ASM(RGB888, RGB565); - DECLARE_RGB_ASM(XRGB8888, RGB565); DECLARE_RGB_ASM_MMX(XRGB8888, RGB565); -DECLARE_RGB(XRGB1555, RGB888); -DECLARE_RGB(RGB565, RGB888); - DECLARE_RGB_ASM(XRGB8888, RGB888); DECLARE_RGB_ASM_MMX(XRGB8888, RGB888); - DECLARE_RGB_ASM(XRGB1555, XRGB8888); DECLARE_RGB_ASM_MMX(XRGB1555, XRGB8888); - DECLARE_RGB_ASM(RGB565, XRGB8888); DECLARE_RGB_ASM_MMX(RGB565, XRGB8888); - DECLARE_RGB_ASM(RGB888, XRGB8888); DECLARE_RGB_ASM_MMX(RGB888, XRGB8888); - -DECLARE_PALETTED(Pal1, Any8); -DECLARE_PALETTED(Pal1, Any16); -DECLARE_PALETTED(Pal1, Any24); -DECLARE_PALETTED(Pal1, Any32); -DECLARE_PALETTED(Pal2, Any8); -DECLARE_PALETTED(Pal2, Any16); -DECLARE_PALETTED(Pal2, Any24); -DECLARE_PALETTED(Pal2, Any32); -DECLARE_PALETTED(Pal4, Any8); -DECLARE_PALETTED(Pal4, Any16); -DECLARE_PALETTED(Pal4, Any24); -DECLARE_PALETTED(Pal4, Any32); -DECLARE_PALETTED(Pal8, Any8); -DECLARE_PALETTED(Pal8, Any16); -DECLARE_PALETTED(Pal8, Any24); -DECLARE_PALETTED(Pal8, Any32); - -DECLARE_YUV(XVYU, UYVY); -DECLARE_YUV(XVYU, YUYV); -DECLARE_YUV(Y8, UYVY); -DECLARE_YUV(Y8, YUYV); -DECLARE_YUV(UYVY, Y8); -DECLARE_YUV(YUYV, Y8); -DECLARE_YUV(UYVY, YUYV); -DECLARE_YUV_PLANAR(YUV411, YV12); - -DECLARE_YUV(UYVY, XRGB1555); -DECLARE_YUV(UYVY, RGB565); -DECLARE_YUV(UYVY, RGB888); -DECLARE_YUV(UYVY, XRGB8888); -DECLARE_YUV(YUYV, XRGB1555); -DECLARE_YUV(YUYV, RGB565); -DECLARE_YUV(YUYV, RGB888); -DECLARE_YUV(YUYV, XRGB8888); -DECLARE_YUV(Y8, XRGB1555); -DECLARE_YUV(Y8, RGB565); -DECLARE_YUV(Y8, RGB888); -DECLARE_YUV(Y8, XRGB8888); - -DECLARE_YUV_REV(XRGB1555, Y8); -DECLARE_YUV_REV(RGB565, Y8); -DECLARE_YUV_REV(RGB888, Y8); -DECLARE_YUV_REV(XRGB8888, Y8); - -DECLARE_YUV_REV(XRGB1555, XVYU); -DECLARE_YUV_REV(RGB565, XVYU); -DECLARE_YUV_REV(RGB888, XVYU); -DECLARE_YUV_REV(XRGB8888, XVYU); - -DECLARE_YUV_PLANAR(YV12, XRGB1555); -DECLARE_YUV_PLANAR(YV12, RGB565); -DECLARE_YUV_PLANAR(YV12, RGB888); -DECLARE_YUV_PLANAR(YV12, XRGB8888); - -DECLARE_YUV_PLANAR(YUV411, XRGB1555); -DECLARE_YUV_PLANAR(YUV411, RGB565); -DECLARE_YUV_PLANAR(YUV411, RGB888); -DECLARE_YUV_PLANAR(YUV411, XRGB8888); - -extern void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); - -using namespace nsVDPixmap; - -void VDPixmapInitBlittersX86(VDPixmapBlitterTable& table) { - VDPixmapInitBlittersReference(table); - - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); -} - -tpVDPixBltTable VDGetPixBltTableX86ScalarInternal() { - static VDPixmapBlitterTable sReferenceTable; - - VDPixmapInitBlittersX86(sReferenceTable); - - return sReferenceTable.mTable; -} - -tpVDPixBltTable VDGetPixBltTableX86MMXInternal() { - static VDPixmapBlitterTable sReferenceTable; - - VDPixmapInitBlittersX86(sReferenceTable); - - sReferenceTable.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - - return sReferenceTable.mTable; -} - -tpVDPixBltTable VDGetPixBltTableX86Scalar() { - static tpVDPixBltTable spTable = VDGetPixBltTableX86ScalarInternal(); - - return spTable; -} - -tpVDPixBltTable VDGetPixBltTableX86MMX() { - static tpVDPixBltTable spTable = VDGetPixBltTableX86MMXInternal(); - - return spTable; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include "blt_setup.h" + +void VDPixmapInitBlittersReference(VDPixmapBlitterTable& table); + +#define DECLARE_PALETTED(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0); +#define DECLARE_RGB(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +#define DECLARE_RGB_ASM(x, y) extern "C" void vdasm_pixblt_##x##_to_##y(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +#define DECLARE_RGB_ASM_MMX(x, y) extern "C" void vdasm_pixblt_##x##_to_##y##_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +#define DECLARE_YUV(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV_PLANAR(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); + + DECLARE_RGB_ASM(RGB565, XRGB1555); DECLARE_RGB_ASM_MMX(RGB565, XRGB1555); + DECLARE_RGB_ASM(RGB888, XRGB1555); + DECLARE_RGB_ASM(XRGB8888, XRGB1555); DECLARE_RGB_ASM_MMX(XRGB8888, XRGB1555); + DECLARE_RGB_ASM(XRGB1555, RGB565); DECLARE_RGB_ASM_MMX(XRGB1555, RGB565); + DECLARE_RGB_ASM(RGB888, RGB565); + DECLARE_RGB_ASM(XRGB8888, RGB565); DECLARE_RGB_ASM_MMX(XRGB8888, RGB565); +DECLARE_RGB(XRGB1555, RGB888); +DECLARE_RGB(RGB565, RGB888); + DECLARE_RGB_ASM(XRGB8888, RGB888); DECLARE_RGB_ASM_MMX(XRGB8888, RGB888); + DECLARE_RGB_ASM(XRGB1555, XRGB8888); DECLARE_RGB_ASM_MMX(XRGB1555, XRGB8888); + DECLARE_RGB_ASM(RGB565, XRGB8888); DECLARE_RGB_ASM_MMX(RGB565, XRGB8888); + DECLARE_RGB_ASM(RGB888, XRGB8888); DECLARE_RGB_ASM_MMX(RGB888, XRGB8888); + +DECLARE_PALETTED(Pal1, Any8); +DECLARE_PALETTED(Pal1, Any16); +DECLARE_PALETTED(Pal1, Any24); +DECLARE_PALETTED(Pal1, Any32); +DECLARE_PALETTED(Pal2, Any8); +DECLARE_PALETTED(Pal2, Any16); +DECLARE_PALETTED(Pal2, Any24); +DECLARE_PALETTED(Pal2, Any32); +DECLARE_PALETTED(Pal4, Any8); +DECLARE_PALETTED(Pal4, Any16); +DECLARE_PALETTED(Pal4, Any24); +DECLARE_PALETTED(Pal4, Any32); +DECLARE_PALETTED(Pal8, Any8); +DECLARE_PALETTED(Pal8, Any16); +DECLARE_PALETTED(Pal8, Any24); +DECLARE_PALETTED(Pal8, Any32); + +DECLARE_YUV(XVYU, UYVY); +DECLARE_YUV(XVYU, YUYV); +DECLARE_YUV(Y8, UYVY); +DECLARE_YUV(Y8, YUYV); +DECLARE_YUV(UYVY, Y8); +DECLARE_YUV(YUYV, Y8); +DECLARE_YUV(UYVY, YUYV); +DECLARE_YUV_PLANAR(YUV411, YV12); + +DECLARE_YUV(UYVY, XRGB1555); +DECLARE_YUV(UYVY, RGB565); +DECLARE_YUV(UYVY, RGB888); +DECLARE_YUV(UYVY, XRGB8888); +DECLARE_YUV(YUYV, XRGB1555); +DECLARE_YUV(YUYV, RGB565); +DECLARE_YUV(YUYV, RGB888); +DECLARE_YUV(YUYV, XRGB8888); +DECLARE_YUV(Y8, XRGB1555); +DECLARE_YUV(Y8, RGB565); +DECLARE_YUV(Y8, RGB888); +DECLARE_YUV(Y8, XRGB8888); + +DECLARE_YUV_REV(XRGB1555, Y8); +DECLARE_YUV_REV(RGB565, Y8); +DECLARE_YUV_REV(RGB888, Y8); +DECLARE_YUV_REV(XRGB8888, Y8); + +DECLARE_YUV_REV(XRGB1555, XVYU); +DECLARE_YUV_REV(RGB565, XVYU); +DECLARE_YUV_REV(RGB888, XVYU); +DECLARE_YUV_REV(XRGB8888, XVYU); + +DECLARE_YUV_PLANAR(YV12, XRGB1555); +DECLARE_YUV_PLANAR(YV12, RGB565); +DECLARE_YUV_PLANAR(YV12, RGB888); +DECLARE_YUV_PLANAR(YV12, XRGB8888); + +DECLARE_YUV_PLANAR(YUV411, XRGB1555); +DECLARE_YUV_PLANAR(YUV411, RGB565); +DECLARE_YUV_PLANAR(YUV411, RGB888); +DECLARE_YUV_PLANAR(YUV411, XRGB8888); + +extern void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); + +using namespace nsVDPixmap; + +void VDPixmapInitBlittersX86(VDPixmapBlitterTable& table) { + VDPixmapInitBlittersReference(table); + + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); +} + +tpVDPixBltTable VDGetPixBltTableX86ScalarInternal() { + static VDPixmapBlitterTable sReferenceTable; + + VDPixmapInitBlittersX86(sReferenceTable); + + return sReferenceTable.mTable; +} + +tpVDPixBltTable VDGetPixBltTableX86MMXInternal() { + static VDPixmapBlitterTable sReferenceTable; + + VDPixmapInitBlittersX86(sReferenceTable); + + sReferenceTable.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + + return sReferenceTable.mTable; +} + +tpVDPixBltTable VDGetPixBltTableX86Scalar() { + static tpVDPixBltTable spTable = VDGetPixBltTableX86ScalarInternal(); + + return spTable; +} + +tpVDPixBltTable VDGetPixBltTableX86MMX() { + static tpVDPixBltTable spTable = VDGetPixBltTableX86MMXInternal(); + + return spTable; +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/pixel.cpp b/src/thirdparty/VirtualDub/Kasumi/source/pixel.cpp index d8d845f827e..207bd597d16 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/pixel.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/pixel.cpp @@ -1,942 +1,942 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include - -uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y) { - if (x >= px.w) - x = px.w - 1; - if (y >= px.h) - y = px.h - 1; - if (x < 0) - x = 0; - if (y < 0) - y = 0; - - switch(px.format) { - case nsVDPixmap::kPixFormat_Pal1: - { - uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 3]; - - return px.palette[(idx >> (7 - (x & 7))) & 1]; - } - - case nsVDPixmap::kPixFormat_Pal2: - { - uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 2]; - - return px.palette[(idx >> (6 - (x & 3)*2)) & 3]; - } - - case nsVDPixmap::kPixFormat_Pal4: - { - uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 1]; - - if (!(x & 1)) - idx >>= 4; - - return px.palette[idx & 15]; - } - - case nsVDPixmap::kPixFormat_Pal8: - { - uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x]; - - return px.palette[idx]; - } - - case nsVDPixmap::kPixFormat_XRGB1555: - { - uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; - uint32 r = c & 0x7c00; - uint32 g = c & 0x03e0; - uint32 b = c & 0x001f; - uint32 rgb = (r << 9) + (g << 6) + (b << 3); - - return rgb + ((rgb >> 5) & 0x070707); - } - break; - - case nsVDPixmap::kPixFormat_RGB565: - { - uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; - uint32 r = c & 0xf800; - uint32 g = c & 0x07e0; - uint32 b = c & 0x001f; - uint32 rb = (r << 8) + (b << 3); - - return rb + ((rb >> 5) & 0x070007) + (g << 5) + ((g >> 1) & 0x0300); - } - break; - - case nsVDPixmap::kPixFormat_RGB888: - { - const uint8 *src = (const uint8 *)px.data + px.pitch*y + 3*x; - uint32 b = src[0]; - uint32 g = src[1]; - uint32 r = src[2]; - - return (r << 16) + (g << 8) + b; - } - break; - - case nsVDPixmap::kPixFormat_XRGB8888: - return ((const uint32 *)((const uint8 *)px.data + px.pitch*y))[x]; - - case nsVDPixmap::kPixFormat_Y8: - { - uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; - - return ((luma - 16)*255/219) * 0x010101; - } - break; - - case nsVDPixmap::kPixFormat_Y8_FR: - { - uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; - - return (uint32)luma * 0x010101; - } - break; - - case nsVDPixmap::kPixFormat_YUV444_Planar: - return VDConvertYCbCrToRGB(VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapSample8(px.data2, px.pitch2, x, y), VDPixmapSample8(px.data3, px.pitch3, x, y), false, false); - - case nsVDPixmap::kPixFormat_YUV422_Planar: - { - sint32 u = (x << 7) + 128; - sint32 v = (y << 8); - uint32 w2 = px.w >> 1; - uint32 h2 = px.h; - - return VDConvertYCbCrToRGB( - VDPixmapSample8(px.data, px.pitch, x, y), - VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), - VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), - false, false); - } - - case nsVDPixmap::kPixFormat_YUV420_Planar: - { - sint32 u = (x << 7) + 128; - sint32 v = (y << 7); - uint32 w2 = px.w >> 1; - uint32 h2 = px.h >> 1; - - return VDConvertYCbCrToRGB( - VDPixmapSample8(px.data, px.pitch, x, y), - VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), - VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), - false, false); - } - - case nsVDPixmap::kPixFormat_YUV411_Planar: - { - sint32 u = (x << 6) + 128; - sint32 v = (y << 8); - uint32 w2 = px.w >> 2; - uint32 h2 = px.h; - - return VDConvertYCbCrToRGB( - VDPixmapSample8(px.data, px.pitch, x, y), - VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), - VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), - false, false); - } - - case nsVDPixmap::kPixFormat_YUV410_Planar: - { - sint32 u = (x << 6) + 128; - sint32 v = (y << 6); - uint32 w2 = px.w >> 2; - uint32 h2 = px.h >> 2; - - return VDConvertYCbCrToRGB( - VDPixmapSample8(px.data, px.pitch, x, y), - VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), - VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), - false, false); - } - - default: - return VDPixmapInterpolateSampleRGB24(px, (x << 8) + 128, (y << 8) + 128); - } -} - -uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - uint32 w_256 = (w - 1) << 8; - uint32 h_256 = (h - 1) << 8; - x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); - y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); - - const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8); - const uint8 *row1 = row0; - - if ((uint32)y_256 < h_256) - row1 += pitch; - - ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; - sint32 xoffset = x_256 & 255; - sint32 yoffset = y_256 & 255; - sint32 p00 = row0[0]; - sint32 p10 = row0[xstep]; - sint32 p01 = row1[0]; - sint32 p11 = row1[xstep]; - sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; - sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; - sint32 p = ((p0 << 8) + (p1 - p0)*yoffset + 0x8000) >> 16; - - return (uint8)p; -} - -uint32 VDPixmapInterpolateSample8To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - sint32 w_256 = (w - 1) << 8; - sint32 h_256 = (h - 1) << 8; - x_256 += (w_256 - x_256) & ((w_256 - x_256) >> 31); - y_256 += (h_256 - y_256) & ((h_256 - y_256) >> 31); - - const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8); - const uint8 *row1 = row0; - - if (y_256 < h_256) - row1 += pitch; - - ptrdiff_t xstep = x_256 < w_256 ? 1 : 0; - sint32 xoffset = x_256 & 255; - sint32 yoffset = y_256 & 255; - sint32 p00 = row0[0]; - sint32 p10 = row0[xstep]; - sint32 p01 = row1[0]; - sint32 p11 = row1[xstep]; - sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; - sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; - sint32 p = (p0 << 8) + (p1 - p0)*yoffset; - - return p; -} - -uint32 VDPixmapInterpolateSample8x2To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - uint32 w_256 = (w - 1) << 8; - uint32 h_256 = (h - 1) << 8; - x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); - y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); - - const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2; - const uint8 *row1 = row0; - - if ((uint32)y_256 < h_256) - row1 += pitch; - - ptrdiff_t xstep = (uint32)x_256 < w_256 ? 2 : 0; - sint32 xoffset = x_256 & 255; - sint32 yoffset = y_256 & 255; - sint32 p00 = row0[0]; - sint32 p10 = row0[xstep]; - sint32 p01 = row1[0]; - sint32 p11 = row1[xstep]; - sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; - sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; - sint32 p = (p0 << 8) + (p1 - p0)*yoffset; - - return p; -} - -uint32 VDPixmapInterpolateSample8x4To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - uint32 w_256 = (w - 1) << 8; - uint32 h_256 = (h - 1) << 8; - x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); - y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); - - const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*4; - const uint8 *row1 = row0; - - if ((uint32)y_256 < h_256) - row1 += pitch; - - ptrdiff_t xstep = (uint32)x_256 < w_256 ? 4 : 0; - sint32 xoffset = x_256 & 255; - sint32 yoffset = y_256 & 255; - sint32 p00 = row0[0]; - sint32 p10 = row0[xstep]; - sint32 p01 = row1[0]; - sint32 p11 = row1[xstep]; - sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; - sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; - sint32 p = (p0 << 8) + (p1 - p0)*yoffset; - - return p; -} - -float VDPixmapInterpolateSample16F(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - uint32 w_256 = (w - 1) << 8; - uint32 h_256 = (h - 1) << 8; - x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); - y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); - - const uint16 *row0 = (const uint16 *)((const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2); - const uint16 *row1 = row0; - - if ((uint32)y_256 < h_256) - row1 = (const uint16 *)((const char *)row1 + pitch); - - ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; - float xoffset = (float)(x_256 & 255) * (1.0f / 255.0f); - float yoffset = (float)(y_256 & 255) * (1.0f / 255.0f); - - float p00; - float p10; - float p01; - float p11; - VDConvertHalfToFloat(row0[0], &p00); - VDConvertHalfToFloat(row0[xstep], &p10); - VDConvertHalfToFloat(row1[0], &p01); - VDConvertHalfToFloat(row1[xstep], &p11); - - float p0 = p00 + (p10 - p00)*xoffset; - float p1 = p01 + (p11 - p01)*xoffset; - - return p0 + (p1 - p0)*yoffset; -} - -namespace { - uint32 Lerp8888(uint32 p0, uint32 p1, uint32 p2, uint32 p3, uint32 xf, uint32 yf) { - uint32 rb0 = p0 & 0x00ff00ff; - uint32 ag0 = p0 & 0xff00ff00; - uint32 rb1 = p1 & 0x00ff00ff; - uint32 ag1 = p1 & 0xff00ff00; - uint32 rb2 = p2 & 0x00ff00ff; - uint32 ag2 = p2 & 0xff00ff00; - uint32 rb3 = p3 & 0x00ff00ff; - uint32 ag3 = p3 & 0xff00ff00; - - uint32 rbt = (rb0 + ((( rb1 - rb0 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; - uint32 agt = (ag0 + ((((ag1 >> 8) - (ag0 >> 8))*xf + 0x00800080) )) & 0xff00ff00; - uint32 rbb = (rb2 + ((( rb3 - rb2 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; - uint32 agb = (ag2 + ((((ag3 >> 8) - (ag2 >> 8))*xf + 0x00800080) )) & 0xff00ff00; - uint32 rb = (rbt + ((( rbb - rbt )*yf + 0x00800080) >> 8)) & 0x00ff00ff; - uint32 ag = (agt + ((((agb >> 8) - (agt >> 8))*yf + 0x00800080) )) & 0xff00ff00; - - return rb + ag; - } - - uint32 InterpPlanarY8(const VDPixmap& px, sint32 x1, sint32 y1) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - - return VDClampedRoundFixedToUint8Fast((float)(y-0x100000) * (1.1643836f/65536.0f/255.0f))*0x010101; - } - - uint32 ConvertYCC72ToRGB24(sint32 iy, sint32 icb, sint32 icr) { - float y = (float)iy; - float cb = (float)icb; - float cr = (float)icr; - - // ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! - // ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! - // ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! - uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.5960268f/65536.0f/255.0f)*cr - (222.92157f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.3917623f/65536.0f/255.0f)*cb - (0.8129676f/65536.0f/255.0f)*cr + (135.57529f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.0172321f/65536.0f/255.0f)*cb - (276.83585f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - uint32 ConvertYCC72ToRGB24_FR(sint32 iy, sint32 icb, sint32 icr) { - float y = (float)iy; - float cb = (float)icb; - float cr = (float)icr; - - // 1. 0. 1.402 - 179.456 - // 1. - 0.3441363 - 0.7141363 135.45889 - // 1. 1.772 - 2.220D-16 - 226.816 - uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.4020000f/65536.0f/255.0f)*cr - (179.456f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.3441363f/65536.0f/255.0f)*cb - (0.7141363f/65536.0f/255.0f)*cr + (135.45889f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.7720000f/65536.0f/255.0f)*cb - (226.816f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - uint32 ConvertYCC72ToRGB24_709(sint32 iy, sint32 icb, sint32 icr) { - float y = (float)iy; - float cb = (float)icb; - float cr = (float)icr; - - // ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! - // ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! - // ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! - uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.7927411f/65536.0f/255.0f)*cr - (248.10099f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.2132486f/65536.0f/255.0f)*cb - (0.5329093f/65536.0f/255.0f)*cr + (76.87808f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.1124018f/65536.0f/255.0f)*cb - (289.01757f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - uint32 ConvertYCC72ToRGB24_709_FR(sint32 iy, sint32 icb, sint32 icr) { - float y = (float)iy; - float cb = (float)icb; - float cr = (float)icr; - - // 1. 0. 1.5748 - 201.5744 - // 1. - 0.1873243 - 0.4681243 83.897414 - // 1. 1.8556 0. - 237.5168 - uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.5748f/65536.0f/255.0f)*cr - (201.5744f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.1873243f/65536.0f/255.0f)*cb - (0.4681243f/65536.0f/255.0f)*cr + (83.897414f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.8556f/65536.0f/255.0f)*cb - (237.5168f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - uint32 InterpPlanarYCC888(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); - sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); - - return ConvertYCC72ToRGB24(y, cb, cr); - } - - uint32 InterpPlanarYCC888_709(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); - sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); - - return ConvertYCC72ToRGB24_709(y, cb, cr); - } - - uint32 InterpPlanarYCC888_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); - sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); - - return ConvertYCC72ToRGB24_FR(y, cb, cr); - } - - uint32 InterpPlanarYCC888_709_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); - sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); - - return ConvertYCC72ToRGB24_709_FR(y, cb, cr); - } - - template - uint32 InterpPlanarYCC888_420i(const VDPixmap& px, sint32 x1, sint32 y1) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb; - sint32 cr; - - const uint8 *src2 = (const uint8 *)px.data2; - const uint8 *src3 = (const uint8 *)px.data3; - const ptrdiff_t pitch2 = px.pitch2 + px.pitch2; - const ptrdiff_t pitch3 = px.pitch3 + px.pitch3; - const uint32 w23 = (px.w + 1) >> 1; - const uint32 h23 = (px.h + 1) >> 1; - const sint32 xc = (x1 >> 1) + 64; - sint32 yc = (y1 >> 1) + 64; - - if (y1 & 1) { - yc -= 256; - cb = VDPixmapInterpolateSample8To24(src2, pitch2, w23, h23 >> 1, xc, yc); - cr = VDPixmapInterpolateSample8To24(src3, pitch3, w23, h23 >> 1, xc, yc); - } else { - cb = VDPixmapInterpolateSample8To24(src2 + px.pitch2, pitch2, w23, (h23 + 1) >> 1, xc, yc); - cr = VDPixmapInterpolateSample8To24(src3 + px.pitch3, pitch3, w23, (h23 + 1) >> 1, xc, yc); - } - - return ConvFn(y, cb, cr); - } - - uint32 SampleV210_Y(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { - if (x < 0) - x = 0; - if ((uint32)x >= w) - x = w - 1; - if (y < 0) - y = 0; - if ((uint32)y >= h) - y = h - 1; - - const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 6)*4; - - switch((uint32)x % 6) { - default: - case 0: return (p[0] >> 10) & 0x3ff; - case 1: return (p[1] >> 0) & 0x3ff; - case 2: return (p[1] >> 20) & 0x3ff; - case 3: return (p[2] >> 10) & 0x3ff; - case 4: return (p[3] >> 0) & 0x3ff; - case 5: return (p[3] >> 20) & 0x3ff; - } - } - - uint32 SampleV210_Cb(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { - if (x < 0) - x = 0; - if ((uint32)x >= w) - x = w - 1; - if (y < 0) - y = 0; - if ((uint32)y >= h) - y = h - 1; - - const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; - - switch((uint32)x % 3) { - default: - case 0: return (p[0] >> 0) & 0x3ff; - case 1: return (p[1] >> 10) & 0x3ff; - case 2: return (p[2] >> 20) & 0x3ff; - } - } - - uint32 SampleV210_Cr(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { - if (x < 0) - x = 0; - if ((uint32)x >= w) - x = w - 1; - if (y < 0) - y = 0; - if ((uint32)y >= h) - y = h - 1; - - const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; - - switch((uint32)x % 3) { - default: - case 0: return (p[0] >> 20) & 0x3ff; - case 1: return (p[2] >> 0) & 0x3ff; - case 2: return (p[3] >> 10) & 0x3ff; - } - } -} - -uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x_256, sint32 y_256) { - switch(px.format) { - case nsVDPixmap::kPixFormat_Pal1: - case nsVDPixmap::kPixFormat_Pal2: - case nsVDPixmap::kPixFormat_Pal4: - case nsVDPixmap::kPixFormat_Pal8: - case nsVDPixmap::kPixFormat_RGB565: - case nsVDPixmap::kPixFormat_RGB888: - case nsVDPixmap::kPixFormat_XRGB1555: - case nsVDPixmap::kPixFormat_XRGB8888: - { - x_256 -= 128; - y_256 -= 128; - int ix = x_256 >> 8; - int iy = y_256 >> 8; - uint32 p0 = VDPixmapSample(px, ix, iy); - uint32 p1 = VDPixmapSample(px, ix+1, iy); - uint32 p2 = VDPixmapSample(px, ix, iy+1); - uint32 p3 = VDPixmapSample(px, ix+1, iy+1); - - return Lerp8888(p0, p1, p2, p3, x_256 & 255, y_256 & 255); - } - break; - - case nsVDPixmap::kPixFormat_Y8: - return InterpPlanarY8(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV422_UYVY: - return ConvertYCC72ToRGB24( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_YUYV: - return ConvertYCC72ToRGB24( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_UYVY_FR: - return ConvertYCC72ToRGB24_FR( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_YUYV_FR: - return ConvertYCC72ToRGB24_FR( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV444_XVYU: - return ConvertYCC72ToRGB24( - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, px.w, px.h, x_256, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_UYVY_709: - return ConvertYCC72ToRGB24_709( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_YUYV_709: - return ConvertYCC72ToRGB24_709( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_UYVY_709_FR: - return ConvertYCC72ToRGB24_709_FR( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_YUYV_709_FR: - return ConvertYCC72ToRGB24_709_FR( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV420_NV12: - return ConvertYCC72ToRGB24( - VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 0, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1), - VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 1, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1) - ); - - case nsVDPixmap::kPixFormat_YUV444_Planar: - return InterpPlanarYCC888(px, x_256, y_256, x_256, y_256, px.w, px.h); - - case nsVDPixmap::kPixFormat_YUV422_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV411_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); - - case nsVDPixmap::kPixFormat_YUV420_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420it_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420ib_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV410_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); - - case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: - return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: - return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, x_256, y_256, px.w, px.h); - - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); - - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420it_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420ib_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); - - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); - - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); - - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420it_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420ib_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); - - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); - - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); - - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); - - case nsVDPixmap::kPixFormat_YUV420i_Planar: - return InterpPlanarYCC888_420i(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: - return InterpPlanarYCC888_420i(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV420i_Planar_709: - return InterpPlanarYCC888_420i(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: - return InterpPlanarYCC888_420i(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV422_Planar_16F: - { - float y = VDPixmapInterpolateSample16F(px.data, px.pitch, px.w, px.h, x_256, y_256); - float cb = VDPixmapInterpolateSample16F(px.data2, px.pitch2, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); - float cr = VDPixmapInterpolateSample16F(px.data3, px.pitch3, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); - - uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 1.5960268f*cr - (222.92157f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*y - 0.3917623f*cb - 0.8129676f*cr + (135.57529f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 2.0172321f*cb - (276.83585f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - case nsVDPixmap::kPixFormat_YUV422_V210: - { - sint32 luma_x = x_256 - 128; - sint32 luma_y = y_256 - 128; - - if (luma_x < 0) - luma_x = 0; - - if (luma_y < 0) - luma_y = 0; - - if (luma_x > (sint32)((px.w - 1) << 8)) - luma_x = (sint32)((px.w - 1) << 8); - - if (luma_y > (sint32)((px.h - 1) << 8)) - luma_y = (sint32)((px.h - 1) << 8); - - sint32 luma_ix = luma_x >> 8; - sint32 luma_iy = luma_y >> 8; - float luma_fx = (float)(luma_x & 255) * (1.0f / 255.0f); - float luma_fy = (float)(luma_y & 255) * (1.0f / 255.0f); - - float y0 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); - float y1 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); - float y2 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); - float y3 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); - float yt = y0 + (y1 - y0)*luma_fx; - float yb = y2 + (y3 - y2)*luma_fx; - float yr = yt + (yb - yt)*luma_fy; - - uint32 chroma_w = (px.w + 1) >> 1; - uint32 chroma_h = px.h; - sint32 chroma_x = x_256 >> 1; - sint32 chroma_y = y_256 - 128; - - if (chroma_x < 0) - chroma_x = 0; - - if (chroma_y < 0) - chroma_y = 0; - - if (chroma_x > (sint32)((chroma_w - 1) << 8)) - chroma_x = (sint32)((chroma_w - 1) << 8); - - if (chroma_y > (sint32)((chroma_h - 1) << 8)) - chroma_y = (sint32)((chroma_h - 1) << 8); - - sint32 chroma_ix = chroma_x >> 8; - sint32 chroma_iy = chroma_y >> 8; - float chroma_fx = (float)(chroma_x & 255) * (1.0f / 255.0f); - float chroma_fy = (float)(chroma_y & 255) * (1.0f / 255.0f); - - float cb0 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cb1 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cb2 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cb3 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cbt = cb0 + (cb1 - cb0)*chroma_fx; - float cbb = cb2 + (cb3 - cb2)*chroma_fx; - float cbr = cbt + (cbb - cbt)*chroma_fy; - - float cr0 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cr1 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cr2 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cr3 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); - float crt = cr0 + (cr1 - cr0)*chroma_fx; - float crb = cr2 + (cr3 - cr2)*chroma_fx; - float crr = crt + (crb - crt)*chroma_fy; - - uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 1.5960268f*crr - (222.92157f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*yr - 0.3917623f*cbr - 0.8129676f*crr + (135.57529f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 2.0172321f*cbr - (276.83585f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - break; - - default: - return 0; - } -} - -uint32 VDConvertYCbCrToRGB(uint8 y0, uint8 cb0, uint8 cr0, bool use709, bool useFullRange) { - sint32 y = y0; - sint32 cb = cb0 - 128; - sint32 cr = cr0 - 128; - sint32 r; - sint32 g; - sint32 b; - - if (use709) { - if (useFullRange) { - sint32 y2 = (y << 16) + 0x8000; - r = y2 + cr * 103206; - g = y2 + cr * -30679 + cb * -12276; - b = y2 + cb * 121609; - } else { - sint32 y2 = (y - 16) * 76309 + 0x8000; - r = y2 + cr * 117489; - g = y2 + cr * -34925 + cb * -13975; - b = y2 + cb * 138438; - } - } else { - if (useFullRange) { - sint32 y2 = (y << 16) + 0x8000; - r = y2 + cr * 91181; - g = y2 + cr * -46802 + cb * -22554; - b = y2 + cb * 166130; - } else { - sint32 y2 = (y - 16) * 76309 + 0x8000; - r = y2 + cr * 104597; - g = y2 + cr * -53279 + cb * -25674; - b = y2 + cb * 132201; - } - } - - r &= ~(r >> 31); - g &= ~(g >> 31); - b &= ~(b >> 31); - r += (0xffffff - r) & ((0xffffff - r) >> 31); - g += (0xffffff - g) & ((0xffffff - g) >> 31); - b += (0xffffff - b) & ((0xffffff - b) >> 31); - - return (r & 0xff0000) + ((g & 0xff0000) >> 8) + (b >> 16); -} - -uint32 VDConvertRGBToYCbCr(uint32 c) { - return VDConvertRGBToYCbCr((uint8)(c >> 16), (uint8)(c >> 8), (uint8)c, false, false); -} - -uint32 VDConvertRGBToYCbCr(uint8 r8, uint8 g8, uint8 b8, bool use709, bool useFullRange) { - sint32 r = r8; - sint32 g = g8; - sint32 b = b8; - sint32 y; - sint32 cb; - sint32 cr; - - if (use709) { - if (useFullRange) { - y = ( 13933*r + 46871*g + 4732*b + 0x8000) >> 8; - cb = ( -7509*r - 25259*g + 32768*b + 0x808000) >> 16; - cr = ( 32768*r - 29763*g - 3005*b + 0x808000); - } else { - y = ( 11966*r + 40254*g + 4064*b + 0x108000) >> 8; - cb = ( -6596*r - 22189*g + 28784*b + 0x808000) >> 16; - cr = ( 28784*r - 26145*g - 2639*b + 0x808000); - } - } else { - if (useFullRange) { - y = ( 19595*r + 38470*g + 7471*b + 0x8000) >> 8; - cb = (-11058*r - 21710*g + 32768*b + 0x808000) >> 16; - cr = ( 32768*r - 27439*g - 5329*b + 0x808000); - } else { - y = ( 16829*r + 33039*g + 6416*b + 0x108000) >> 8; - cb = ( -9714*r - 19071*g + 28784*b + 0x808000) >> 16; - cr = ( 28784*r - 24103*g - 4681*b + 0x808000); - } - } - - return (uint8)cb + (y & 0xff00) + (cr&0xff0000); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include + +uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y) { + if (x >= px.w) + x = px.w - 1; + if (y >= px.h) + y = px.h - 1; + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + switch(px.format) { + case nsVDPixmap::kPixFormat_Pal1: + { + uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 3]; + + return px.palette[(idx >> (7 - (x & 7))) & 1]; + } + + case nsVDPixmap::kPixFormat_Pal2: + { + uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 2]; + + return px.palette[(idx >> (6 - (x & 3)*2)) & 3]; + } + + case nsVDPixmap::kPixFormat_Pal4: + { + uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 1]; + + if (!(x & 1)) + idx >>= 4; + + return px.palette[idx & 15]; + } + + case nsVDPixmap::kPixFormat_Pal8: + { + uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x]; + + return px.palette[idx]; + } + + case nsVDPixmap::kPixFormat_XRGB1555: + { + uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; + uint32 r = c & 0x7c00; + uint32 g = c & 0x03e0; + uint32 b = c & 0x001f; + uint32 rgb = (r << 9) + (g << 6) + (b << 3); + + return rgb + ((rgb >> 5) & 0x070707); + } + break; + + case nsVDPixmap::kPixFormat_RGB565: + { + uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; + uint32 r = c & 0xf800; + uint32 g = c & 0x07e0; + uint32 b = c & 0x001f; + uint32 rb = (r << 8) + (b << 3); + + return rb + ((rb >> 5) & 0x070007) + (g << 5) + ((g >> 1) & 0x0300); + } + break; + + case nsVDPixmap::kPixFormat_RGB888: + { + const uint8 *src = (const uint8 *)px.data + px.pitch*y + 3*x; + uint32 b = src[0]; + uint32 g = src[1]; + uint32 r = src[2]; + + return (r << 16) + (g << 8) + b; + } + break; + + case nsVDPixmap::kPixFormat_XRGB8888: + return ((const uint32 *)((const uint8 *)px.data + px.pitch*y))[x]; + + case nsVDPixmap::kPixFormat_Y8: + { + uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; + + return ((luma - 16)*255/219) * 0x010101; + } + break; + + case nsVDPixmap::kPixFormat_Y8_FR: + { + uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; + + return (uint32)luma * 0x010101; + } + break; + + case nsVDPixmap::kPixFormat_YUV444_Planar: + return VDConvertYCbCrToRGB(VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapSample8(px.data2, px.pitch2, x, y), VDPixmapSample8(px.data3, px.pitch3, x, y), false, false); + + case nsVDPixmap::kPixFormat_YUV422_Planar: + { + sint32 u = (x << 7) + 128; + sint32 v = (y << 8); + uint32 w2 = px.w >> 1; + uint32 h2 = px.h; + + return VDConvertYCbCrToRGB( + VDPixmapSample8(px.data, px.pitch, x, y), + VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), + VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), + false, false); + } + + case nsVDPixmap::kPixFormat_YUV420_Planar: + { + sint32 u = (x << 7) + 128; + sint32 v = (y << 7); + uint32 w2 = px.w >> 1; + uint32 h2 = px.h >> 1; + + return VDConvertYCbCrToRGB( + VDPixmapSample8(px.data, px.pitch, x, y), + VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), + VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), + false, false); + } + + case nsVDPixmap::kPixFormat_YUV411_Planar: + { + sint32 u = (x << 6) + 128; + sint32 v = (y << 8); + uint32 w2 = px.w >> 2; + uint32 h2 = px.h; + + return VDConvertYCbCrToRGB( + VDPixmapSample8(px.data, px.pitch, x, y), + VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), + VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), + false, false); + } + + case nsVDPixmap::kPixFormat_YUV410_Planar: + { + sint32 u = (x << 6) + 128; + sint32 v = (y << 6); + uint32 w2 = px.w >> 2; + uint32 h2 = px.h >> 2; + + return VDConvertYCbCrToRGB( + VDPixmapSample8(px.data, px.pitch, x, y), + VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), + VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), + false, false); + } + + default: + return VDPixmapInterpolateSampleRGB24(px, (x << 8) + 128, (y << 8) + 128); + } +} + +uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + uint32 w_256 = (w - 1) << 8; + uint32 h_256 = (h - 1) << 8; + x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); + y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); + + const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8); + const uint8 *row1 = row0; + + if ((uint32)y_256 < h_256) + row1 += pitch; + + ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; + sint32 xoffset = x_256 & 255; + sint32 yoffset = y_256 & 255; + sint32 p00 = row0[0]; + sint32 p10 = row0[xstep]; + sint32 p01 = row1[0]; + sint32 p11 = row1[xstep]; + sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; + sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; + sint32 p = ((p0 << 8) + (p1 - p0)*yoffset + 0x8000) >> 16; + + return (uint8)p; +} + +uint32 VDPixmapInterpolateSample8To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + sint32 w_256 = (w - 1) << 8; + sint32 h_256 = (h - 1) << 8; + x_256 += (w_256 - x_256) & ((w_256 - x_256) >> 31); + y_256 += (h_256 - y_256) & ((h_256 - y_256) >> 31); + + const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8); + const uint8 *row1 = row0; + + if (y_256 < h_256) + row1 += pitch; + + ptrdiff_t xstep = x_256 < w_256 ? 1 : 0; + sint32 xoffset = x_256 & 255; + sint32 yoffset = y_256 & 255; + sint32 p00 = row0[0]; + sint32 p10 = row0[xstep]; + sint32 p01 = row1[0]; + sint32 p11 = row1[xstep]; + sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; + sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; + sint32 p = (p0 << 8) + (p1 - p0)*yoffset; + + return p; +} + +uint32 VDPixmapInterpolateSample8x2To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + uint32 w_256 = (w - 1) << 8; + uint32 h_256 = (h - 1) << 8; + x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); + y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); + + const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2; + const uint8 *row1 = row0; + + if ((uint32)y_256 < h_256) + row1 += pitch; + + ptrdiff_t xstep = (uint32)x_256 < w_256 ? 2 : 0; + sint32 xoffset = x_256 & 255; + sint32 yoffset = y_256 & 255; + sint32 p00 = row0[0]; + sint32 p10 = row0[xstep]; + sint32 p01 = row1[0]; + sint32 p11 = row1[xstep]; + sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; + sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; + sint32 p = (p0 << 8) + (p1 - p0)*yoffset; + + return p; +} + +uint32 VDPixmapInterpolateSample8x4To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + uint32 w_256 = (w - 1) << 8; + uint32 h_256 = (h - 1) << 8; + x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); + y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); + + const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*4; + const uint8 *row1 = row0; + + if ((uint32)y_256 < h_256) + row1 += pitch; + + ptrdiff_t xstep = (uint32)x_256 < w_256 ? 4 : 0; + sint32 xoffset = x_256 & 255; + sint32 yoffset = y_256 & 255; + sint32 p00 = row0[0]; + sint32 p10 = row0[xstep]; + sint32 p01 = row1[0]; + sint32 p11 = row1[xstep]; + sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; + sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; + sint32 p = (p0 << 8) + (p1 - p0)*yoffset; + + return p; +} + +float VDPixmapInterpolateSample16F(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + uint32 w_256 = (w - 1) << 8; + uint32 h_256 = (h - 1) << 8; + x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); + y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); + + const uint16 *row0 = (const uint16 *)((const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2); + const uint16 *row1 = row0; + + if ((uint32)y_256 < h_256) + row1 = (const uint16 *)((const char *)row1 + pitch); + + ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; + float xoffset = (float)(x_256 & 255) * (1.0f / 255.0f); + float yoffset = (float)(y_256 & 255) * (1.0f / 255.0f); + + float p00; + float p10; + float p01; + float p11; + VDConvertHalfToFloat(row0[0], &p00); + VDConvertHalfToFloat(row0[xstep], &p10); + VDConvertHalfToFloat(row1[0], &p01); + VDConvertHalfToFloat(row1[xstep], &p11); + + float p0 = p00 + (p10 - p00)*xoffset; + float p1 = p01 + (p11 - p01)*xoffset; + + return p0 + (p1 - p0)*yoffset; +} + +namespace { + uint32 Lerp8888(uint32 p0, uint32 p1, uint32 p2, uint32 p3, uint32 xf, uint32 yf) { + uint32 rb0 = p0 & 0x00ff00ff; + uint32 ag0 = p0 & 0xff00ff00; + uint32 rb1 = p1 & 0x00ff00ff; + uint32 ag1 = p1 & 0xff00ff00; + uint32 rb2 = p2 & 0x00ff00ff; + uint32 ag2 = p2 & 0xff00ff00; + uint32 rb3 = p3 & 0x00ff00ff; + uint32 ag3 = p3 & 0xff00ff00; + + uint32 rbt = (rb0 + ((( rb1 - rb0 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; + uint32 agt = (ag0 + ((((ag1 >> 8) - (ag0 >> 8))*xf + 0x00800080) )) & 0xff00ff00; + uint32 rbb = (rb2 + ((( rb3 - rb2 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; + uint32 agb = (ag2 + ((((ag3 >> 8) - (ag2 >> 8))*xf + 0x00800080) )) & 0xff00ff00; + uint32 rb = (rbt + ((( rbb - rbt )*yf + 0x00800080) >> 8)) & 0x00ff00ff; + uint32 ag = (agt + ((((agb >> 8) - (agt >> 8))*yf + 0x00800080) )) & 0xff00ff00; + + return rb + ag; + } + + uint32 InterpPlanarY8(const VDPixmap& px, sint32 x1, sint32 y1) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + + return VDClampedRoundFixedToUint8Fast((float)(y-0x100000) * (1.1643836f/65536.0f/255.0f))*0x010101; + } + + uint32 ConvertYCC72ToRGB24(sint32 iy, sint32 icb, sint32 icr) { + float y = (float)iy; + float cb = (float)icb; + float cr = (float)icr; + + // ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! + // ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! + // ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! + uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.5960268f/65536.0f/255.0f)*cr - (222.92157f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.3917623f/65536.0f/255.0f)*cb - (0.8129676f/65536.0f/255.0f)*cr + (135.57529f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.0172321f/65536.0f/255.0f)*cb - (276.83585f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + uint32 ConvertYCC72ToRGB24_FR(sint32 iy, sint32 icb, sint32 icr) { + float y = (float)iy; + float cb = (float)icb; + float cr = (float)icr; + + // 1. 0. 1.402 - 179.456 + // 1. - 0.3441363 - 0.7141363 135.45889 + // 1. 1.772 - 2.220D-16 - 226.816 + uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.4020000f/65536.0f/255.0f)*cr - (179.456f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.3441363f/65536.0f/255.0f)*cb - (0.7141363f/65536.0f/255.0f)*cr + (135.45889f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.7720000f/65536.0f/255.0f)*cb - (226.816f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + uint32 ConvertYCC72ToRGB24_709(sint32 iy, sint32 icb, sint32 icr) { + float y = (float)iy; + float cb = (float)icb; + float cr = (float)icr; + + // ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! + // ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! + // ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! + uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.7927411f/65536.0f/255.0f)*cr - (248.10099f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.2132486f/65536.0f/255.0f)*cb - (0.5329093f/65536.0f/255.0f)*cr + (76.87808f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.1124018f/65536.0f/255.0f)*cb - (289.01757f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + uint32 ConvertYCC72ToRGB24_709_FR(sint32 iy, sint32 icb, sint32 icr) { + float y = (float)iy; + float cb = (float)icb; + float cr = (float)icr; + + // 1. 0. 1.5748 - 201.5744 + // 1. - 0.1873243 - 0.4681243 83.897414 + // 1. 1.8556 0. - 237.5168 + uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.5748f/65536.0f/255.0f)*cr - (201.5744f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.1873243f/65536.0f/255.0f)*cb - (0.4681243f/65536.0f/255.0f)*cr + (83.897414f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.8556f/65536.0f/255.0f)*cb - (237.5168f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + uint32 InterpPlanarYCC888(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); + sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); + + return ConvertYCC72ToRGB24(y, cb, cr); + } + + uint32 InterpPlanarYCC888_709(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); + sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); + + return ConvertYCC72ToRGB24_709(y, cb, cr); + } + + uint32 InterpPlanarYCC888_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); + sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); + + return ConvertYCC72ToRGB24_FR(y, cb, cr); + } + + uint32 InterpPlanarYCC888_709_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); + sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); + + return ConvertYCC72ToRGB24_709_FR(y, cb, cr); + } + + template + uint32 InterpPlanarYCC888_420i(const VDPixmap& px, sint32 x1, sint32 y1) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb; + sint32 cr; + + const uint8 *src2 = (const uint8 *)px.data2; + const uint8 *src3 = (const uint8 *)px.data3; + const ptrdiff_t pitch2 = px.pitch2 + px.pitch2; + const ptrdiff_t pitch3 = px.pitch3 + px.pitch3; + const uint32 w23 = (px.w + 1) >> 1; + const uint32 h23 = (px.h + 1) >> 1; + const sint32 xc = (x1 >> 1) + 64; + sint32 yc = (y1 >> 1) + 64; + + if (y1 & 1) { + yc -= 256; + cb = VDPixmapInterpolateSample8To24(src2, pitch2, w23, h23 >> 1, xc, yc); + cr = VDPixmapInterpolateSample8To24(src3, pitch3, w23, h23 >> 1, xc, yc); + } else { + cb = VDPixmapInterpolateSample8To24(src2 + px.pitch2, pitch2, w23, (h23 + 1) >> 1, xc, yc); + cr = VDPixmapInterpolateSample8To24(src3 + px.pitch3, pitch3, w23, (h23 + 1) >> 1, xc, yc); + } + + return ConvFn(y, cb, cr); + } + + uint32 SampleV210_Y(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { + if (x < 0) + x = 0; + if ((uint32)x >= w) + x = w - 1; + if (y < 0) + y = 0; + if ((uint32)y >= h) + y = h - 1; + + const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 6)*4; + + switch((uint32)x % 6) { + default: + case 0: return (p[0] >> 10) & 0x3ff; + case 1: return (p[1] >> 0) & 0x3ff; + case 2: return (p[1] >> 20) & 0x3ff; + case 3: return (p[2] >> 10) & 0x3ff; + case 4: return (p[3] >> 0) & 0x3ff; + case 5: return (p[3] >> 20) & 0x3ff; + } + } + + uint32 SampleV210_Cb(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { + if (x < 0) + x = 0; + if ((uint32)x >= w) + x = w - 1; + if (y < 0) + y = 0; + if ((uint32)y >= h) + y = h - 1; + + const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; + + switch((uint32)x % 3) { + default: + case 0: return (p[0] >> 0) & 0x3ff; + case 1: return (p[1] >> 10) & 0x3ff; + case 2: return (p[2] >> 20) & 0x3ff; + } + } + + uint32 SampleV210_Cr(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { + if (x < 0) + x = 0; + if ((uint32)x >= w) + x = w - 1; + if (y < 0) + y = 0; + if ((uint32)y >= h) + y = h - 1; + + const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; + + switch((uint32)x % 3) { + default: + case 0: return (p[0] >> 20) & 0x3ff; + case 1: return (p[2] >> 0) & 0x3ff; + case 2: return (p[3] >> 10) & 0x3ff; + } + } +} + +uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x_256, sint32 y_256) { + switch(px.format) { + case nsVDPixmap::kPixFormat_Pal1: + case nsVDPixmap::kPixFormat_Pal2: + case nsVDPixmap::kPixFormat_Pal4: + case nsVDPixmap::kPixFormat_Pal8: + case nsVDPixmap::kPixFormat_RGB565: + case nsVDPixmap::kPixFormat_RGB888: + case nsVDPixmap::kPixFormat_XRGB1555: + case nsVDPixmap::kPixFormat_XRGB8888: + { + x_256 -= 128; + y_256 -= 128; + int ix = x_256 >> 8; + int iy = y_256 >> 8; + uint32 p0 = VDPixmapSample(px, ix, iy); + uint32 p1 = VDPixmapSample(px, ix+1, iy); + uint32 p2 = VDPixmapSample(px, ix, iy+1); + uint32 p3 = VDPixmapSample(px, ix+1, iy+1); + + return Lerp8888(p0, p1, p2, p3, x_256 & 255, y_256 & 255); + } + break; + + case nsVDPixmap::kPixFormat_Y8: + return InterpPlanarY8(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV422_UYVY: + return ConvertYCC72ToRGB24( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_YUYV: + return ConvertYCC72ToRGB24( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_UYVY_FR: + return ConvertYCC72ToRGB24_FR( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_YUYV_FR: + return ConvertYCC72ToRGB24_FR( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV444_XVYU: + return ConvertYCC72ToRGB24( + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, px.w, px.h, x_256, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_UYVY_709: + return ConvertYCC72ToRGB24_709( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_YUYV_709: + return ConvertYCC72ToRGB24_709( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_UYVY_709_FR: + return ConvertYCC72ToRGB24_709_FR( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_YUYV_709_FR: + return ConvertYCC72ToRGB24_709_FR( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV420_NV12: + return ConvertYCC72ToRGB24( + VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 0, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1), + VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 1, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1) + ); + + case nsVDPixmap::kPixFormat_YUV444_Planar: + return InterpPlanarYCC888(px, x_256, y_256, x_256, y_256, px.w, px.h); + + case nsVDPixmap::kPixFormat_YUV422_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV411_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); + + case nsVDPixmap::kPixFormat_YUV420_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420it_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420ib_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV410_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); + + case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: + return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: + return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, x_256, y_256, px.w, px.h); + + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); + + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420it_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420ib_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); + + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); + + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); + + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420it_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420ib_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); + + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); + + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); + + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); + + case nsVDPixmap::kPixFormat_YUV420i_Planar: + return InterpPlanarYCC888_420i(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: + return InterpPlanarYCC888_420i(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV420i_Planar_709: + return InterpPlanarYCC888_420i(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: + return InterpPlanarYCC888_420i(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV422_Planar_16F: + { + float y = VDPixmapInterpolateSample16F(px.data, px.pitch, px.w, px.h, x_256, y_256); + float cb = VDPixmapInterpolateSample16F(px.data2, px.pitch2, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); + float cr = VDPixmapInterpolateSample16F(px.data3, px.pitch3, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); + + uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 1.5960268f*cr - (222.92157f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*y - 0.3917623f*cb - 0.8129676f*cr + (135.57529f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 2.0172321f*cb - (276.83585f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + case nsVDPixmap::kPixFormat_YUV422_V210: + { + sint32 luma_x = x_256 - 128; + sint32 luma_y = y_256 - 128; + + if (luma_x < 0) + luma_x = 0; + + if (luma_y < 0) + luma_y = 0; + + if (luma_x > (sint32)((px.w - 1) << 8)) + luma_x = (sint32)((px.w - 1) << 8); + + if (luma_y > (sint32)((px.h - 1) << 8)) + luma_y = (sint32)((px.h - 1) << 8); + + sint32 luma_ix = luma_x >> 8; + sint32 luma_iy = luma_y >> 8; + float luma_fx = (float)(luma_x & 255) * (1.0f / 255.0f); + float luma_fy = (float)(luma_y & 255) * (1.0f / 255.0f); + + float y0 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); + float y1 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); + float y2 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); + float y3 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); + float yt = y0 + (y1 - y0)*luma_fx; + float yb = y2 + (y3 - y2)*luma_fx; + float yr = yt + (yb - yt)*luma_fy; + + uint32 chroma_w = (px.w + 1) >> 1; + uint32 chroma_h = px.h; + sint32 chroma_x = x_256 >> 1; + sint32 chroma_y = y_256 - 128; + + if (chroma_x < 0) + chroma_x = 0; + + if (chroma_y < 0) + chroma_y = 0; + + if (chroma_x > (sint32)((chroma_w - 1) << 8)) + chroma_x = (sint32)((chroma_w - 1) << 8); + + if (chroma_y > (sint32)((chroma_h - 1) << 8)) + chroma_y = (sint32)((chroma_h - 1) << 8); + + sint32 chroma_ix = chroma_x >> 8; + sint32 chroma_iy = chroma_y >> 8; + float chroma_fx = (float)(chroma_x & 255) * (1.0f / 255.0f); + float chroma_fy = (float)(chroma_y & 255) * (1.0f / 255.0f); + + float cb0 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cb1 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cb2 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cb3 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cbt = cb0 + (cb1 - cb0)*chroma_fx; + float cbb = cb2 + (cb3 - cb2)*chroma_fx; + float cbr = cbt + (cbb - cbt)*chroma_fy; + + float cr0 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cr1 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cr2 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cr3 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); + float crt = cr0 + (cr1 - cr0)*chroma_fx; + float crb = cr2 + (cr3 - cr2)*chroma_fx; + float crr = crt + (crb - crt)*chroma_fy; + + uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 1.5960268f*crr - (222.92157f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*yr - 0.3917623f*cbr - 0.8129676f*crr + (135.57529f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 2.0172321f*cbr - (276.83585f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + break; + + default: + return 0; + } +} + +uint32 VDConvertYCbCrToRGB(uint8 y0, uint8 cb0, uint8 cr0, bool use709, bool useFullRange) { + sint32 y = y0; + sint32 cb = cb0 - 128; + sint32 cr = cr0 - 128; + sint32 r; + sint32 g; + sint32 b; + + if (use709) { + if (useFullRange) { + sint32 y2 = (y << 16) + 0x8000; + r = y2 + cr * 103206; + g = y2 + cr * -30679 + cb * -12276; + b = y2 + cb * 121609; + } else { + sint32 y2 = (y - 16) * 76309 + 0x8000; + r = y2 + cr * 117489; + g = y2 + cr * -34925 + cb * -13975; + b = y2 + cb * 138438; + } + } else { + if (useFullRange) { + sint32 y2 = (y << 16) + 0x8000; + r = y2 + cr * 91181; + g = y2 + cr * -46802 + cb * -22554; + b = y2 + cb * 166130; + } else { + sint32 y2 = (y - 16) * 76309 + 0x8000; + r = y2 + cr * 104597; + g = y2 + cr * -53279 + cb * -25674; + b = y2 + cb * 132201; + } + } + + r &= ~(r >> 31); + g &= ~(g >> 31); + b &= ~(b >> 31); + r += (0xffffff - r) & ((0xffffff - r) >> 31); + g += (0xffffff - g) & ((0xffffff - g) >> 31); + b += (0xffffff - b) & ((0xffffff - b) >> 31); + + return (r & 0xff0000) + ((g & 0xff0000) >> 8) + (b >> 16); +} + +uint32 VDConvertRGBToYCbCr(uint32 c) { + return VDConvertRGBToYCbCr((uint8)(c >> 16), (uint8)(c >> 8), (uint8)c, false, false); +} + +uint32 VDConvertRGBToYCbCr(uint8 r8, uint8 g8, uint8 b8, bool use709, bool useFullRange) { + sint32 r = r8; + sint32 g = g8; + sint32 b = b8; + sint32 y; + sint32 cb; + sint32 cr; + + if (use709) { + if (useFullRange) { + y = ( 13933*r + 46871*g + 4732*b + 0x8000) >> 8; + cb = ( -7509*r - 25259*g + 32768*b + 0x808000) >> 16; + cr = ( 32768*r - 29763*g - 3005*b + 0x808000); + } else { + y = ( 11966*r + 40254*g + 4064*b + 0x108000) >> 8; + cb = ( -6596*r - 22189*g + 28784*b + 0x808000) >> 16; + cr = ( 28784*r - 26145*g - 2639*b + 0x808000); + } + } else { + if (useFullRange) { + y = ( 19595*r + 38470*g + 7471*b + 0x8000) >> 8; + cb = (-11058*r - 21710*g + 32768*b + 0x808000) >> 16; + cr = ( 32768*r - 27439*g - 5329*b + 0x808000); + } else { + y = ( 16829*r + 33039*g + 6416*b + 0x108000) >> 8; + cb = ( -9714*r - 19071*g + 28784*b + 0x808000) >> 16; + cr = ( 28784*r - 24103*g - 4681*b + 0x808000); + } + } + + return (uint8)cb + (y & 0xff00) + (cr&0xff0000); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/pixmaputils.cpp b/src/thirdparty/VirtualDub/Kasumi/source/pixmaputils.cpp index c16e7bbc13b..d1b74672cb6 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/pixmaputils.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/pixmaputils.cpp @@ -1,633 +1,633 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include - -extern VDPixmapFormatInfo const g_vdPixmapFormats[] = { - // name qchnk qw qh qwb qhb qs ab aw ah as ps - /* Null */ { "null", false, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* Pal1 */ { "Pal1", true, 8, 1, 3, 0, 1, 0, 0, 0, 0, 2 }, - /* Pal2 */ { "Pal2", true, 4, 1, 2, 0, 1, 0, 0, 0, 0, 4 }, - /* Pal4 */ { "Pal4", true, 2, 1, 1, 0, 1, 0, 0, 0, 0, 16 }, - /* Pal8 */ { "Pal8", false, 1, 1, 0, 0, 1, 0, 0, 0, 0, 256 }, - /* RGB16_555 */ { "XRGB1555", false, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0 }, - /* RGB16_565 */ { "RGB565", false, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0 }, - /* RGB24 */ { "RGB888", false, 1, 1, 0, 0, 3, 0, 0, 0, 0, 0 }, - /* RGB32 */ { "XRGB8888", false, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0 }, - /* Y8 */ { "Y8", false, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, - /* YUV422_UYVY */ { "UYVY", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV422_YUYV */ { "YUYV", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_XVYU */ { "XVYU", false, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_Planar */ { "YUV444", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, - /* YUV422_Planar */ { "YUV422", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar */ { "YUV420", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV411_Planar */ { "YUV411", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, - /* YUV410_Planar */ { "YUV410", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, - /* YUV422_Planar_Centered */ { "YUV422C", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar_Centered */ { "YUV420C", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV422_Planar_16F */ { "YUV422_16F", false, 1, 1, 0, 0, 2, 2, 1, 0, 2, 0 }, - /* V210 */ { "v210", true,24, 1, 2, 0, 64, 0, 0, 0, 1, 0 }, - /* YUV422_UYVY_709 */ { "UYVY-709", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* NV12 */ { "NV12", false, 1, 1, 0, 0, 1, 1, 1, 1, 2, 0 }, - /* Y8-FR */ { "I8", false, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0 }, - /* YUV422_YUYV_709 */ { "YUYV-709", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_Planar_709 */ { "YUV444-709", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, - /* YUV422_Planar_709 */ { "YUV422-709", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar_709 */ { "YUV420-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV411_Planar_709 */ { "YUV411-709", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, - /* YUV410_Planar_709 */ { "YUV410-709", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, - /* YUV422_UYVY_FR */ { "UYVY-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV422_YUYV_FR */ { "YUYV-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_Planar_FR */ { "YUV444-FR", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, - /* YUV422_Planar_FR */ { "YUV422-FR", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar_FR */ { "YUV420-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV411_Planar_FR */ { "YUV411-FR", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, - /* YUV410_Planar_FR */ { "YUV410-FR", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, - /* YUV422_UYVY_FR_709 */ { "UYVY-709-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV422_YUYV_FR_709 */ { "YUYV-709-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_Planar_FR_709 */ { "YUV444-709-FR", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, - /* YUV422_Planar_FR_709 */ { "YUV422-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar_FR_709 */ { "YUV420-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV411_Planar_FR_709 */ { "YUV411-709-FR", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, - /* YUV410_Planar_FR_709 */ { "YUV410-709-FR", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, - /* YUV420i_Planar */ { "YUV420i", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420i_Planar_FR */ { "YUV420i-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420i_Planar_709 */ { "YUV420i-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420i_Planar_709_FR */ { "YUV420i-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420it_Planar */ { "YUV420it", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420it_Planar_FR */ { "YUV420it-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420it_Planar_709 */ { "YUV420it-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420it_Planar_709_FR */ { "YUV420it-709-FR",false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420ib_Planar */ { "YUV420ib", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420ib_Planar_FR */ { "YUV420ib-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420ib_Planar_709 */ { "YUV420ib-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420ib_Planar_709_FR */ { "YUV420ib-709-FR",false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, -}; - -namespace { - void check() { - VDASSERTCT(sizeof(g_vdPixmapFormats)/sizeof(g_vdPixmapFormats[0]) == nsVDPixmap::kPixFormat_Max_Standard); - } -} - -#ifdef _DEBUG - bool VDIsValidPixmapPlane(const void *p, ptrdiff_t pitch, vdpixsize w, vdpixsize h) { - bool isvalid; - - if (pitch < 0) - isvalid = VDIsValidReadRegion((const char *)p + pitch*(h-1), (-pitch)*(h-1)+w); - else - isvalid = VDIsValidReadRegion(p, pitch*(h-1)+w); - - if (!isvalid) { - VDDEBUG("Kasumi: Invalid pixmap plane detected.\n" - " Base=%p, pitch=%d, size=%dx%d (bytes)\n", p, (int)pitch, w, h); - } - - return isvalid; - } - - bool VDAssertValidPixmap(const VDPixmap& px) { - const VDPixmapFormatInfo& info = VDPixmapGetInfo(px.format); - - if (px.format) { - if (!VDIsValidPixmapPlane(px.data, px.pitch, -(-px.w / info.qw)*info.qsize, -(-px.h >> info.qhbits))) { - VDDEBUG("Kasumi: Invalid primary plane detected in pixmap.\n" - " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); - VDASSERT(!"Kasumi: Invalid primary plane detected in pixmap.\n"); - return false; - } - - if (info.palsize) - if (!VDIsValidReadRegion(px.palette, sizeof(uint32) * info.palsize)) { - VDDEBUG("Kasumi: Invalid palette detected in pixmap.\n" - " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); - VDASSERT(!"Kasumi: Invalid palette detected in pixmap.\n"); - return false; - } - - if (info.auxbufs) { - const vdpixsize auxw = -(-px.w >> info.auxwbits); - const vdpixsize auxh = -(-px.h >> info.auxhbits); - - if (!VDIsValidPixmapPlane(px.data2, px.pitch2, auxw * info.auxsize, auxh)) { - VDDEBUG("Kasumi: Invalid Cb plane detected in pixmap.\n" - " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); - VDASSERT(!"Kasumi: Invalid Cb plane detected in pixmap.\n"); - return false; - } - - if (info.auxbufs > 2) { - if (!VDIsValidPixmapPlane(px.data3, px.pitch3, auxw * info.auxsize, auxh)) { - VDDEBUG("Kasumi: Invalid Cr plane detected in pixmap.\n" - " Pixmap info: format=%d, dimensions=%dx%d\n", px.format, px.w, px.h); - VDASSERT(!"Kasumi: Invalid Cr plane detected in pixmap.\n"); - return false; - } - } - } - } - - return true; - } -#endif - -VDPixmap VDPixmapOffset(const VDPixmap& src, vdpixpos x, vdpixpos y) { - VDPixmap temp(src); - const VDPixmapFormatInfo& info = VDPixmapGetInfo(temp.format); - - if (info.qchunky) { - x = (x + info.qw - 1) / info.qw; - y >>= info.qhbits; - } - - switch(info.auxbufs) { - case 2: - temp.data3 = (char *)temp.data3 + (x >> info.auxwbits)*info.auxsize + (y >> info.auxhbits)*temp.pitch3; - case 1: - temp.data2 = (char *)temp.data2 + (x >> info.auxwbits)*info.auxsize + (y >> info.auxhbits)*temp.pitch2; - case 0: - temp.data = (char *)temp.data + x*info.qsize + y*temp.pitch; - } - - return temp; -} - -VDPixmapLayout VDPixmapLayoutOffset(const VDPixmapLayout& src, vdpixpos x, vdpixpos y) { - VDPixmapLayout temp(src); - const VDPixmapFormatInfo& info = VDPixmapGetInfo(temp.format); - - if (info.qchunky) { - x = (x + info.qw - 1) / info.qw; - y = -(-y >> info.qhbits); - } - - switch(info.auxbufs) { - case 2: - temp.data3 += -(-x >> info.auxwbits)*info.auxsize + -(-y >> info.auxhbits)*temp.pitch3; - case 1: - temp.data2 += -(-x >> info.auxwbits)*info.auxsize + -(-y >> info.auxhbits)*temp.pitch2; - case 0: - temp.data += x*info.qsize + y*temp.pitch; - } - - return temp; -} - -uint32 VDPixmapCreateLinearLayout(VDPixmapLayout& layout, int format, vdpixsize w, vdpixsize h, int alignment) { - const ptrdiff_t alignmask = alignment - 1; - - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(format); - sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-h >> srcinfo.qhbits); - sint32 subw = -(-w >> srcinfo.auxwbits); - sint32 subh = -(-h >> srcinfo.auxhbits); - sint32 auxsize = srcinfo.auxsize; - - ptrdiff_t mainpitch = (srcinfo.qsize * qw + alignmask) & ~alignmask; - size_t mainsize = mainpitch * qh; - - layout.data = 0; - layout.pitch = mainpitch; - layout.palette = NULL; - layout.data2 = 0; - layout.pitch2 = 0; - layout.data3 = 0; - layout.pitch3 = 0; - layout.w = w; - layout.h = h; - layout.format = format; - - if (srcinfo.auxbufs >= 1) { - ptrdiff_t subpitch = (subw * auxsize + alignmask) & ~alignmask; - size_t subsize = subpitch * subh; - - layout.data2 = mainsize; - layout.pitch2 = subpitch; - mainsize += subsize; - - if (srcinfo.auxbufs >= 2) { - layout.data3 = mainsize; - layout.pitch3 = subpitch; - mainsize += subsize; - } - } - - return mainsize; -} - -void VDPixmapFlipV(VDPixmap& px) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(px.format); - sint32 w = px.w; - sint32 h = px.h; - sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-h >> srcinfo.qhbits); - sint32 subh = -(-h >> srcinfo.auxhbits); - - vdptrstep(px.data, px.pitch * (qh - 1)); - px.pitch = -px.pitch; - - if (srcinfo.auxbufs >= 1) { - vdptrstep(px.data2, px.pitch2 * (subh - 1)); - px.pitch2 = -px.pitch2; - - if (srcinfo.auxbufs >= 2) { - vdptrstep(px.data3, px.pitch3 * (subh - 1)); - px.pitch3 = -px.pitch3; - } - } -} - -void VDPixmapLayoutFlipV(VDPixmapLayout& layout) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); - sint32 w = layout.w; - sint32 h = layout.h; - sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-h >> srcinfo.qhbits); - sint32 subh = -(-h >> srcinfo.auxhbits); - - layout.data += layout.pitch * (qh - 1); - layout.pitch = -layout.pitch; - - if (srcinfo.auxbufs >= 1) { - layout.data2 += layout.pitch2 * (subh - 1); - layout.pitch2 = -layout.pitch2; - - if (srcinfo.auxbufs >= 2) { - layout.data3 += layout.pitch3 * (subh - 1); - layout.pitch3 = -layout.pitch3; - } - } -} - -uint32 VDPixmapLayoutGetMinSize(const VDPixmapLayout& layout) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); - sint32 w = layout.w; - sint32 h = layout.h; - sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-h >> srcinfo.qhbits); - sint32 subh = -(-h >> srcinfo.auxhbits); - - uint32 limit = layout.data; - if (layout.pitch >= 0) - limit += layout.pitch * qh; - else - limit -= layout.pitch; - - if (srcinfo.auxbufs >= 1) { - uint32 limit2 = layout.data2; - - if (layout.pitch2 >= 0) - limit2 += layout.pitch2 * subh; - else - limit2 -= layout.pitch2; - - if (limit < limit2) - limit = limit2; - - if (srcinfo.auxbufs >= 2) { - uint32 limit3 = layout.data3; - - if (layout.pitch3 >= 0) - limit3 += layout.pitch3 * subh; - else - limit3 -= layout.pitch3; - - if (limit < limit3) - limit = limit3; - } - } - - return limit; -} - -VDPixmap VDPixmapExtractField(const VDPixmap& src, bool field2) { - VDPixmap px(src); - - if (field2) { - const VDPixmapFormatInfo& info = VDPixmapGetInfo(px.format); - - if (px.data) { - if (info.qh == 1) - vdptrstep(px.data, px.pitch); - - if (!info.auxhbits || - src.format == nsVDPixmap::kPixFormat_YUV420i_Planar || - src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_FR || - src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_709 || - src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR) { - - vdptrstep(px.data2, px.pitch2); - vdptrstep(px.data3, px.pitch3); - } - } - } - - switch(src.format) { - case nsVDPixmap::kPixFormat_YUV420i_Planar: - if (field2) - px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar; - else - px.format = nsVDPixmap::kPixFormat_YUV420it_Planar; - break; - - case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: - if (field2) - px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_FR; - else - px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_FR; - break; - - case nsVDPixmap::kPixFormat_YUV420i_Planar_709: - if (field2) - px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_709; - else - px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_709; - break; - - case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: - if (field2) - px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR; - else - px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR; - break; - } - - px.h >>= 1; - px.pitch += px.pitch; - px.pitch2 += px.pitch2; - px.pitch3 += px.pitch3; - return px; -} - -/////////////////////////////////////////////////////////////////////////// - -VDPixmapBuffer::VDPixmapBuffer(const VDPixmap& src) - : mpBuffer(NULL) - , mLinearSize(0) -{ - assign(src); -} - -VDPixmapBuffer::VDPixmapBuffer(const VDPixmapBuffer& src) - : mpBuffer(NULL) - , mLinearSize(0) -{ - assign(src); -} - -VDPixmapBuffer::VDPixmapBuffer(const VDPixmapLayout& layout) { - init(layout); -} - -VDPixmapBuffer::~VDPixmapBuffer() { -#ifdef _DEBUG - validate(); -#endif - - delete[] mpBuffer; -} - -void VDPixmapBuffer::init(sint32 width, sint32 height, int f) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(f); - sint32 qw = (width + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-height >> srcinfo.qhbits); - sint32 subw = -(-width >> srcinfo.auxwbits); - sint32 subh = -(-height >> srcinfo.auxhbits); - ptrdiff_t mainpitch = (srcinfo.qsize * qw + 15) & ~15; - ptrdiff_t subpitch = (srcinfo.auxsize * subw + 15) & ~15; - uint64 mainsize = (uint64)mainpitch * qh; - uint64 subsize = (uint64)subpitch * subh; - uint64 totalsize64 = mainsize + subsize*srcinfo.auxbufs + 4 * srcinfo.palsize; - -#ifdef _DEBUG - totalsize64 += 28; -#endif - - // reject huge allocations - if (totalsize64 > (size_t)-1 - 4096) - throw MyMemoryError(); - - size_t totalsize = (uint32)totalsize64; - - if (mLinearSize != totalsize) { - clear(); - mpBuffer = new_nothrow char[totalsize + 15]; - if (!mpBuffer) - throw MyMemoryError(totalsize + 15); - mLinearSize = totalsize; - } - - char *p = mpBuffer + (-(int)(uintptr)mpBuffer & 15); - -#ifdef _DEBUG - *(uint32 *)p = totalsize; - for(int i=0; i<12; ++i) - p[4+i] = (char)(0xa0 + i); - - p += 16; -#endif - - data = p; - pitch = mainpitch; - p += mainsize; - - palette = NULL; - data2 = NULL; - pitch2 = NULL; - data3 = NULL; - pitch3 = NULL; - w = width; - h = height; - format = f; - - if (srcinfo.auxbufs >= 1) { - data2 = p; - pitch2 = subpitch; - p += subsize; - } - - if (srcinfo.auxbufs >= 2) { - data3 = p; - pitch3 = subpitch; - p += subsize; - } - - if (srcinfo.palsize) { - palette = (const uint32 *)p; - p += srcinfo.palsize * 4; - } - -#ifdef _DEBUG - for(int j=0; j<12; ++j) - p[j] = (char)(0xb0 + j); -#endif -} - -void VDPixmapBuffer::init(const VDPixmapLayout& layout, uint32 additionalPadding) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); - sint32 qw = (layout.w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-layout.h >> srcinfo.qhbits); - sint32 subw = -(-layout.w >> srcinfo.auxwbits); - sint32 subh = -(-layout.h >> srcinfo.auxhbits); - - sint64 mino=0, maxo=0; - - if (layout.pitch < 0) { - mino = std::min(mino, layout.data + (sint64)layout.pitch * (qh-1)); - maxo = std::max(maxo, layout.data - (sint64)layout.pitch); - } else { - mino = std::min(mino, layout.data); - maxo = std::max(maxo, layout.data + (sint64)layout.pitch*qh); - } - - if (srcinfo.auxbufs >= 1) { - if (layout.pitch2 < 0) { - mino = std::min(mino, layout.data2 + (sint64)layout.pitch2 * (subh-1)); - maxo = std::max(maxo, layout.data2 - (sint64)layout.pitch2); - } else { - mino = std::min(mino, layout.data2); - maxo = std::max(maxo, layout.data2 + (sint64)layout.pitch2*subh); - } - - if (srcinfo.auxbufs >= 2) { - if (layout.pitch3 < 0) { - mino = std::min(mino, layout.data3 + (sint64)layout.pitch3 * (subh-1)); - maxo = std::max(maxo, layout.data3 - (sint64)layout.pitch3); - } else { - mino = std::min(mino, layout.data3); - maxo = std::max(maxo, layout.data3 + (sint64)layout.pitch3*subh); - } - } - } - - sint64 linsize64 = ((maxo - mino + 3) & ~(uint64)3); - - sint64 totalsize64 = linsize64 + 4*srcinfo.palsize + additionalPadding; - -#ifdef _DEBUG - totalsize64 += 28; -#endif - - // reject huge allocations - if (totalsize64 > (size_t)-1 - 4096) - throw MyMemoryError(); - - size_t totalsize = (uint32)totalsize64; - ptrdiff_t linsize = (uint32)linsize64; - - if (mLinearSize != totalsize) { - clear(); - mpBuffer = new_nothrow char[totalsize + 15]; - if (!mpBuffer) - throw MyMemoryError(totalsize + 15); - mLinearSize = totalsize; - } - - char *p = mpBuffer + (-(int)(uintptr)mpBuffer & 15); - -#ifdef _DEBUG - *(uint32 *)p = totalsize - 28; - for(int i=0; i<12; ++i) - p[4+i] = (char)(0xa0 + i); - - p += 16; -#endif - - w = layout.w; - h = layout.h; - format = layout.format; - data = p + layout.data - mino; - data2 = p + layout.data2 - mino; - data3 = p + layout.data3 - mino; - pitch = layout.pitch; - pitch2 = layout.pitch2; - pitch3 = layout.pitch3; - palette = NULL; - - if (srcinfo.palsize) { - palette = (const uint32 *)(p + linsize); - - if (layout.palette) - memcpy((void *)palette, layout.palette, 4*srcinfo.palsize); - } - -#ifdef _DEBUG - for(int j=0; j<12; ++j) - p[totalsize + j - 28] = (char)(0xb0 + j); -#endif - - VDAssertValidPixmap(*this); -} - -void VDPixmapBuffer::assign(const VDPixmap& src) { - if (!src.format) { - delete[] mpBuffer; - mpBuffer = NULL; - data = NULL; - format = 0; - } else { - init(src.w, src.h, src.format); - - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); - int qw = (src.w + srcinfo.qw - 1) / srcinfo.qw; - int qh = -(-src.h >> srcinfo.qhbits); - int subw = -(-src.w >> srcinfo.auxwbits); - int subh = -(-src.h >> srcinfo.auxhbits); - - if (srcinfo.palsize) - memcpy((void *)palette, src.palette, 4 * srcinfo.palsize); - - switch(srcinfo.auxbufs) { - case 2: - VDMemcpyRect(data3, pitch3, src.data3, src.pitch3, subw, subh); - case 1: - VDMemcpyRect(data2, pitch2, src.data2, src.pitch2, subw, subh); - case 0: - VDMemcpyRect(data, pitch, src.data, src.pitch, qw * srcinfo.qsize, qh); - } - } -} - -void VDPixmapBuffer::swap(VDPixmapBuffer& dst) { - std::swap(mpBuffer, dst.mpBuffer); - std::swap(mLinearSize, dst.mLinearSize); - std::swap(static_cast(*this), static_cast(dst)); -} - -#ifdef _DEBUG -void VDPixmapBuffer::validate() { - if (mpBuffer) { - char *p = (char *)(((uintptr)mpBuffer + 15) & ~(uintptr)15); - - // verify head bytes - for(int i=0; i<12; ++i) - if (p[i+4] != (char)(0xa0 + i)) - VDASSERT(!"VDPixmapBuffer: Buffer underflow detected.\n"); - - // verify tail bytes - for(int j=0; j<12; ++j) - if (p[mLinearSize - 12 + j] != (char)(0xb0 + j)) - VDASSERT(!"VDPixmapBuffer: Buffer overflow detected.\n"); - } -} -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include + +extern VDPixmapFormatInfo const g_vdPixmapFormats[] = { + // name qchnk qw qh qwb qhb qs ab aw ah as ps + /* Null */ { "null", false, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* Pal1 */ { "Pal1", true, 8, 1, 3, 0, 1, 0, 0, 0, 0, 2 }, + /* Pal2 */ { "Pal2", true, 4, 1, 2, 0, 1, 0, 0, 0, 0, 4 }, + /* Pal4 */ { "Pal4", true, 2, 1, 1, 0, 1, 0, 0, 0, 0, 16 }, + /* Pal8 */ { "Pal8", false, 1, 1, 0, 0, 1, 0, 0, 0, 0, 256 }, + /* RGB16_555 */ { "XRGB1555", false, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0 }, + /* RGB16_565 */ { "RGB565", false, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0 }, + /* RGB24 */ { "RGB888", false, 1, 1, 0, 0, 3, 0, 0, 0, 0, 0 }, + /* RGB32 */ { "XRGB8888", false, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0 }, + /* Y8 */ { "Y8", false, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, + /* YUV422_UYVY */ { "UYVY", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV422_YUYV */ { "YUYV", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_XVYU */ { "XVYU", false, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_Planar */ { "YUV444", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, + /* YUV422_Planar */ { "YUV422", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar */ { "YUV420", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV411_Planar */ { "YUV411", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, + /* YUV410_Planar */ { "YUV410", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, + /* YUV422_Planar_Centered */ { "YUV422C", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar_Centered */ { "YUV420C", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV422_Planar_16F */ { "YUV422_16F", false, 1, 1, 0, 0, 2, 2, 1, 0, 2, 0 }, + /* V210 */ { "v210", true,24, 1, 2, 0, 64, 0, 0, 0, 1, 0 }, + /* YUV422_UYVY_709 */ { "UYVY-709", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* NV12 */ { "NV12", false, 1, 1, 0, 0, 1, 1, 1, 1, 2, 0 }, + /* Y8-FR */ { "I8", false, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0 }, + /* YUV422_YUYV_709 */ { "YUYV-709", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_Planar_709 */ { "YUV444-709", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, + /* YUV422_Planar_709 */ { "YUV422-709", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar_709 */ { "YUV420-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV411_Planar_709 */ { "YUV411-709", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, + /* YUV410_Planar_709 */ { "YUV410-709", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, + /* YUV422_UYVY_FR */ { "UYVY-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV422_YUYV_FR */ { "YUYV-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_Planar_FR */ { "YUV444-FR", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, + /* YUV422_Planar_FR */ { "YUV422-FR", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar_FR */ { "YUV420-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV411_Planar_FR */ { "YUV411-FR", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, + /* YUV410_Planar_FR */ { "YUV410-FR", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, + /* YUV422_UYVY_FR_709 */ { "UYVY-709-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV422_YUYV_FR_709 */ { "YUYV-709-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_Planar_FR_709 */ { "YUV444-709-FR", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, + /* YUV422_Planar_FR_709 */ { "YUV422-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar_FR_709 */ { "YUV420-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV411_Planar_FR_709 */ { "YUV411-709-FR", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, + /* YUV410_Planar_FR_709 */ { "YUV410-709-FR", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, + /* YUV420i_Planar */ { "YUV420i", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420i_Planar_FR */ { "YUV420i-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420i_Planar_709 */ { "YUV420i-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420i_Planar_709_FR */ { "YUV420i-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420it_Planar */ { "YUV420it", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420it_Planar_FR */ { "YUV420it-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420it_Planar_709 */ { "YUV420it-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420it_Planar_709_FR */ { "YUV420it-709-FR",false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420ib_Planar */ { "YUV420ib", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420ib_Planar_FR */ { "YUV420ib-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420ib_Planar_709 */ { "YUV420ib-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420ib_Planar_709_FR */ { "YUV420ib-709-FR",false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, +}; + +namespace { + void check() { + VDASSERTCT(sizeof(g_vdPixmapFormats)/sizeof(g_vdPixmapFormats[0]) == nsVDPixmap::kPixFormat_Max_Standard); + } +} + +#ifdef _DEBUG + bool VDIsValidPixmapPlane(const void *p, ptrdiff_t pitch, vdpixsize w, vdpixsize h) { + bool isvalid; + + if (pitch < 0) + isvalid = VDIsValidReadRegion((const char *)p + pitch*(h-1), (-pitch)*(h-1)+w); + else + isvalid = VDIsValidReadRegion(p, pitch*(h-1)+w); + + if (!isvalid) { + VDDEBUG("Kasumi: Invalid pixmap plane detected.\n" + " Base=%p, pitch=%d, size=%dx%d (bytes)\n", p, (int)pitch, w, h); + } + + return isvalid; + } + + bool VDAssertValidPixmap(const VDPixmap& px) { + const VDPixmapFormatInfo& info = VDPixmapGetInfo(px.format); + + if (px.format) { + if (!VDIsValidPixmapPlane(px.data, px.pitch, -(-px.w / info.qw)*info.qsize, -(-px.h >> info.qhbits))) { + VDDEBUG("Kasumi: Invalid primary plane detected in pixmap.\n" + " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); + VDASSERT(!"Kasumi: Invalid primary plane detected in pixmap.\n"); + return false; + } + + if (info.palsize) + if (!VDIsValidReadRegion(px.palette, sizeof(uint32) * info.palsize)) { + VDDEBUG("Kasumi: Invalid palette detected in pixmap.\n" + " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); + VDASSERT(!"Kasumi: Invalid palette detected in pixmap.\n"); + return false; + } + + if (info.auxbufs) { + const vdpixsize auxw = -(-px.w >> info.auxwbits); + const vdpixsize auxh = -(-px.h >> info.auxhbits); + + if (!VDIsValidPixmapPlane(px.data2, px.pitch2, auxw * info.auxsize, auxh)) { + VDDEBUG("Kasumi: Invalid Cb plane detected in pixmap.\n" + " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); + VDASSERT(!"Kasumi: Invalid Cb plane detected in pixmap.\n"); + return false; + } + + if (info.auxbufs > 2) { + if (!VDIsValidPixmapPlane(px.data3, px.pitch3, auxw * info.auxsize, auxh)) { + VDDEBUG("Kasumi: Invalid Cr plane detected in pixmap.\n" + " Pixmap info: format=%d, dimensions=%dx%d\n", px.format, px.w, px.h); + VDASSERT(!"Kasumi: Invalid Cr plane detected in pixmap.\n"); + return false; + } + } + } + } + + return true; + } +#endif + +VDPixmap VDPixmapOffset(const VDPixmap& src, vdpixpos x, vdpixpos y) { + VDPixmap temp(src); + const VDPixmapFormatInfo& info = VDPixmapGetInfo(temp.format); + + if (info.qchunky) { + x = (x + info.qw - 1) / info.qw; + y >>= info.qhbits; + } + + switch(info.auxbufs) { + case 2: + temp.data3 = (char *)temp.data3 + (x >> info.auxwbits)*info.auxsize + (y >> info.auxhbits)*temp.pitch3; + case 1: + temp.data2 = (char *)temp.data2 + (x >> info.auxwbits)*info.auxsize + (y >> info.auxhbits)*temp.pitch2; + case 0: + temp.data = (char *)temp.data + x*info.qsize + y*temp.pitch; + } + + return temp; +} + +VDPixmapLayout VDPixmapLayoutOffset(const VDPixmapLayout& src, vdpixpos x, vdpixpos y) { + VDPixmapLayout temp(src); + const VDPixmapFormatInfo& info = VDPixmapGetInfo(temp.format); + + if (info.qchunky) { + x = (x + info.qw - 1) / info.qw; + y = -(-y >> info.qhbits); + } + + switch(info.auxbufs) { + case 2: + temp.data3 += -(-x >> info.auxwbits)*info.auxsize + -(-y >> info.auxhbits)*temp.pitch3; + case 1: + temp.data2 += -(-x >> info.auxwbits)*info.auxsize + -(-y >> info.auxhbits)*temp.pitch2; + case 0: + temp.data += x*info.qsize + y*temp.pitch; + } + + return temp; +} + +uint32 VDPixmapCreateLinearLayout(VDPixmapLayout& layout, int format, vdpixsize w, vdpixsize h, int alignment) { + const ptrdiff_t alignmask = alignment - 1; + + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(format); + sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-h >> srcinfo.qhbits); + sint32 subw = -(-w >> srcinfo.auxwbits); + sint32 subh = -(-h >> srcinfo.auxhbits); + sint32 auxsize = srcinfo.auxsize; + + ptrdiff_t mainpitch = (srcinfo.qsize * qw + alignmask) & ~alignmask; + size_t mainsize = mainpitch * qh; + + layout.data = 0; + layout.pitch = mainpitch; + layout.palette = NULL; + layout.data2 = 0; + layout.pitch2 = 0; + layout.data3 = 0; + layout.pitch3 = 0; + layout.w = w; + layout.h = h; + layout.format = format; + + if (srcinfo.auxbufs >= 1) { + ptrdiff_t subpitch = (subw * auxsize + alignmask) & ~alignmask; + size_t subsize = subpitch * subh; + + layout.data2 = mainsize; + layout.pitch2 = subpitch; + mainsize += subsize; + + if (srcinfo.auxbufs >= 2) { + layout.data3 = mainsize; + layout.pitch3 = subpitch; + mainsize += subsize; + } + } + + return mainsize; +} + +void VDPixmapFlipV(VDPixmap& px) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(px.format); + sint32 w = px.w; + sint32 h = px.h; + sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-h >> srcinfo.qhbits); + sint32 subh = -(-h >> srcinfo.auxhbits); + + vdptrstep(px.data, px.pitch * (qh - 1)); + px.pitch = -px.pitch; + + if (srcinfo.auxbufs >= 1) { + vdptrstep(px.data2, px.pitch2 * (subh - 1)); + px.pitch2 = -px.pitch2; + + if (srcinfo.auxbufs >= 2) { + vdptrstep(px.data3, px.pitch3 * (subh - 1)); + px.pitch3 = -px.pitch3; + } + } +} + +void VDPixmapLayoutFlipV(VDPixmapLayout& layout) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); + sint32 w = layout.w; + sint32 h = layout.h; + sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-h >> srcinfo.qhbits); + sint32 subh = -(-h >> srcinfo.auxhbits); + + layout.data += layout.pitch * (qh - 1); + layout.pitch = -layout.pitch; + + if (srcinfo.auxbufs >= 1) { + layout.data2 += layout.pitch2 * (subh - 1); + layout.pitch2 = -layout.pitch2; + + if (srcinfo.auxbufs >= 2) { + layout.data3 += layout.pitch3 * (subh - 1); + layout.pitch3 = -layout.pitch3; + } + } +} + +uint32 VDPixmapLayoutGetMinSize(const VDPixmapLayout& layout) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); + sint32 w = layout.w; + sint32 h = layout.h; + sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-h >> srcinfo.qhbits); + sint32 subh = -(-h >> srcinfo.auxhbits); + + uint32 limit = layout.data; + if (layout.pitch >= 0) + limit += layout.pitch * qh; + else + limit -= layout.pitch; + + if (srcinfo.auxbufs >= 1) { + uint32 limit2 = layout.data2; + + if (layout.pitch2 >= 0) + limit2 += layout.pitch2 * subh; + else + limit2 -= layout.pitch2; + + if (limit < limit2) + limit = limit2; + + if (srcinfo.auxbufs >= 2) { + uint32 limit3 = layout.data3; + + if (layout.pitch3 >= 0) + limit3 += layout.pitch3 * subh; + else + limit3 -= layout.pitch3; + + if (limit < limit3) + limit = limit3; + } + } + + return limit; +} + +VDPixmap VDPixmapExtractField(const VDPixmap& src, bool field2) { + VDPixmap px(src); + + if (field2) { + const VDPixmapFormatInfo& info = VDPixmapGetInfo(px.format); + + if (px.data) { + if (info.qh == 1) + vdptrstep(px.data, px.pitch); + + if (!info.auxhbits || + src.format == nsVDPixmap::kPixFormat_YUV420i_Planar || + src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_FR || + src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_709 || + src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR) { + + vdptrstep(px.data2, px.pitch2); + vdptrstep(px.data3, px.pitch3); + } + } + } + + switch(src.format) { + case nsVDPixmap::kPixFormat_YUV420i_Planar: + if (field2) + px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar; + else + px.format = nsVDPixmap::kPixFormat_YUV420it_Planar; + break; + + case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: + if (field2) + px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_FR; + else + px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_FR; + break; + + case nsVDPixmap::kPixFormat_YUV420i_Planar_709: + if (field2) + px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_709; + else + px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_709; + break; + + case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: + if (field2) + px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR; + else + px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR; + break; + } + + px.h >>= 1; + px.pitch += px.pitch; + px.pitch2 += px.pitch2; + px.pitch3 += px.pitch3; + return px; +} + +/////////////////////////////////////////////////////////////////////////// + +VDPixmapBuffer::VDPixmapBuffer(const VDPixmap& src) + : mpBuffer(NULL) + , mLinearSize(0) +{ + assign(src); +} + +VDPixmapBuffer::VDPixmapBuffer(const VDPixmapBuffer& src) + : mpBuffer(NULL) + , mLinearSize(0) +{ + assign(src); +} + +VDPixmapBuffer::VDPixmapBuffer(const VDPixmapLayout& layout) { + init(layout); +} + +VDPixmapBuffer::~VDPixmapBuffer() { +#ifdef _DEBUG + validate(); +#endif + + delete[] mpBuffer; +} + +void VDPixmapBuffer::init(sint32 width, sint32 height, int f) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(f); + sint32 qw = (width + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-height >> srcinfo.qhbits); + sint32 subw = -(-width >> srcinfo.auxwbits); + sint32 subh = -(-height >> srcinfo.auxhbits); + ptrdiff_t mainpitch = (srcinfo.qsize * qw + 15) & ~15; + ptrdiff_t subpitch = (srcinfo.auxsize * subw + 15) & ~15; + uint64 mainsize = (uint64)mainpitch * qh; + uint64 subsize = (uint64)subpitch * subh; + uint64 totalsize64 = mainsize + subsize*srcinfo.auxbufs + 4 * srcinfo.palsize; + +#ifdef _DEBUG + totalsize64 += 28; +#endif + + // reject huge allocations + if (totalsize64 > (size_t)-1 - 4096) + throw MyMemoryError(); + + size_t totalsize = (uint32)totalsize64; + + if (mLinearSize != totalsize) { + clear(); + mpBuffer = new_nothrow char[totalsize + 15]; + if (!mpBuffer) + throw MyMemoryError(totalsize + 15); + mLinearSize = totalsize; + } + + char *p = mpBuffer + (-(int)(uintptr)mpBuffer & 15); + +#ifdef _DEBUG + *(uint32 *)p = totalsize; + for(int i=0; i<12; ++i) + p[4+i] = (char)(0xa0 + i); + + p += 16; +#endif + + data = p; + pitch = mainpitch; + p += mainsize; + + palette = NULL; + data2 = NULL; + pitch2 = NULL; + data3 = NULL; + pitch3 = NULL; + w = width; + h = height; + format = f; + + if (srcinfo.auxbufs >= 1) { + data2 = p; + pitch2 = subpitch; + p += subsize; + } + + if (srcinfo.auxbufs >= 2) { + data3 = p; + pitch3 = subpitch; + p += subsize; + } + + if (srcinfo.palsize) { + palette = (const uint32 *)p; + p += srcinfo.palsize * 4; + } + +#ifdef _DEBUG + for(int j=0; j<12; ++j) + p[j] = (char)(0xb0 + j); +#endif +} + +void VDPixmapBuffer::init(const VDPixmapLayout& layout, uint32 additionalPadding) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); + sint32 qw = (layout.w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-layout.h >> srcinfo.qhbits); + sint32 subw = -(-layout.w >> srcinfo.auxwbits); + sint32 subh = -(-layout.h >> srcinfo.auxhbits); + + sint64 mino=0, maxo=0; + + if (layout.pitch < 0) { + mino = std::min(mino, layout.data + (sint64)layout.pitch * (qh-1)); + maxo = std::max(maxo, layout.data - (sint64)layout.pitch); + } else { + mino = std::min(mino, layout.data); + maxo = std::max(maxo, layout.data + (sint64)layout.pitch*qh); + } + + if (srcinfo.auxbufs >= 1) { + if (layout.pitch2 < 0) { + mino = std::min(mino, layout.data2 + (sint64)layout.pitch2 * (subh-1)); + maxo = std::max(maxo, layout.data2 - (sint64)layout.pitch2); + } else { + mino = std::min(mino, layout.data2); + maxo = std::max(maxo, layout.data2 + (sint64)layout.pitch2*subh); + } + + if (srcinfo.auxbufs >= 2) { + if (layout.pitch3 < 0) { + mino = std::min(mino, layout.data3 + (sint64)layout.pitch3 * (subh-1)); + maxo = std::max(maxo, layout.data3 - (sint64)layout.pitch3); + } else { + mino = std::min(mino, layout.data3); + maxo = std::max(maxo, layout.data3 + (sint64)layout.pitch3*subh); + } + } + } + + sint64 linsize64 = ((maxo - mino + 3) & ~(uint64)3); + + sint64 totalsize64 = linsize64 + 4*srcinfo.palsize + additionalPadding; + +#ifdef _DEBUG + totalsize64 += 28; +#endif + + // reject huge allocations + if (totalsize64 > (size_t)-1 - 4096) + throw MyMemoryError(); + + size_t totalsize = (uint32)totalsize64; + ptrdiff_t linsize = (uint32)linsize64; + + if (mLinearSize != totalsize) { + clear(); + mpBuffer = new_nothrow char[totalsize + 15]; + if (!mpBuffer) + throw MyMemoryError(totalsize + 15); + mLinearSize = totalsize; + } + + char *p = mpBuffer + (-(int)(uintptr)mpBuffer & 15); + +#ifdef _DEBUG + *(uint32 *)p = totalsize - 28; + for(int i=0; i<12; ++i) + p[4+i] = (char)(0xa0 + i); + + p += 16; +#endif + + w = layout.w; + h = layout.h; + format = layout.format; + data = p + layout.data - mino; + data2 = p + layout.data2 - mino; + data3 = p + layout.data3 - mino; + pitch = layout.pitch; + pitch2 = layout.pitch2; + pitch3 = layout.pitch3; + palette = NULL; + + if (srcinfo.palsize) { + palette = (const uint32 *)(p + linsize); + + if (layout.palette) + memcpy((void *)palette, layout.palette, 4*srcinfo.palsize); + } + +#ifdef _DEBUG + for(int j=0; j<12; ++j) + p[totalsize + j - 28] = (char)(0xb0 + j); +#endif + + VDAssertValidPixmap(*this); +} + +void VDPixmapBuffer::assign(const VDPixmap& src) { + if (!src.format) { + delete[] mpBuffer; + mpBuffer = NULL; + data = NULL; + format = 0; + } else { + init(src.w, src.h, src.format); + + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); + int qw = (src.w + srcinfo.qw - 1) / srcinfo.qw; + int qh = -(-src.h >> srcinfo.qhbits); + int subw = -(-src.w >> srcinfo.auxwbits); + int subh = -(-src.h >> srcinfo.auxhbits); + + if (srcinfo.palsize) + memcpy((void *)palette, src.palette, 4 * srcinfo.palsize); + + switch(srcinfo.auxbufs) { + case 2: + VDMemcpyRect(data3, pitch3, src.data3, src.pitch3, subw, subh); + case 1: + VDMemcpyRect(data2, pitch2, src.data2, src.pitch2, subw, subh); + case 0: + VDMemcpyRect(data, pitch, src.data, src.pitch, qw * srcinfo.qsize, qh); + } + } +} + +void VDPixmapBuffer::swap(VDPixmapBuffer& dst) { + std::swap(mpBuffer, dst.mpBuffer); + std::swap(mLinearSize, dst.mLinearSize); + std::swap(static_cast(*this), static_cast(dst)); +} + +#ifdef _DEBUG +void VDPixmapBuffer::validate() { + if (mpBuffer) { + char *p = (char *)(((uintptr)mpBuffer + 15) & ~(uintptr)15); + + // verify head bytes + for(int i=0; i<12; ++i) + if (p[i+4] != (char)(0xa0 + i)) + VDASSERT(!"VDPixmapBuffer: Buffer underflow detected.\n"); + + // verify tail bytes + for(int j=0; j<12; ++j) + if (p[mLinearSize - 12 + j] != (char)(0xb0 + j)) + VDASSERT(!"VDPixmapBuffer: Buffer overflow detected.\n"); + } +} +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/source/region.cpp b/src/thirdparty/VirtualDub/Kasumi/source/region.cpp index b8b607ef079..ea6cd638050 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/region.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/region.cpp @@ -1,1375 +1,1375 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include - -void VDPixmapRegion::clear() { - mSpans.clear(); -} - -void VDPixmapRegion::swap(VDPixmapRegion& x) { - mSpans.swap(x.mSpans); - std::swap(mBounds, x.mBounds); -} - -VDPixmapPathRasterizer::VDPixmapPathRasterizer() - : mpEdgeBlocks(NULL) - , mpFreeEdgeBlocks(NULL) - , mEdgeBlockIdx(kEdgeBlockMax) - , mpScanBuffer(NULL) -{ - ClearScanBuffer(); -} - -VDPixmapPathRasterizer::VDPixmapPathRasterizer(const VDPixmapPathRasterizer&) - : mpEdgeBlocks(NULL) - , mpFreeEdgeBlocks(NULL) - , mEdgeBlockIdx(kEdgeBlockMax) - , mpScanBuffer(NULL) -{ - ClearScanBuffer(); -} - -VDPixmapPathRasterizer::~VDPixmapPathRasterizer() { - Clear(); - FreeEdgeLists(); -} - -VDPixmapPathRasterizer& VDPixmapPathRasterizer::operator=(const VDPixmapPathRasterizer&) { - return *this; -} - -void VDPixmapPathRasterizer::Clear() { - ClearEdgeList(); - ClearScanBuffer(); -} - -void VDPixmapPathRasterizer::QuadraticBezier(const vdint2 *pts) { - int x0 = pts[0].x; - int x1 = pts[1].x; - int x2 = pts[2].x; - int y0 = pts[0].y; - int y1 = pts[1].y; - int y2 = pts[2].y; - - // P = (1-t)^2*P0 + 2t(1-t)*P1 + t^2*P2 - // P = (1-2t+t^2)P0 + 2(t-t^2)P1 + t^2*P2 - // P = (P0-2P1+P2)t^2 + 2(P1-P0)t + P0 - - int cx2 = x0-2*x1+x2; - int cx1 = -2*x0+2*x1; - int cx0 = x0; - - int cy2 = y0-2*y1+y2; - int cy1 = -2*y0+2*y1; - int cy0 = y0; - - // This equation is from Graphics Gems I. - // - // The idea is that since we're approximating a cubic curve with lines, - // any error we incur is due to the curvature of the line, which we can - // estimate by calculating the maximum acceleration of the curve. For - // a cubic, the acceleration (second derivative) is a line, meaning that - // the absolute maximum acceleration must occur at either the beginning - // (|c2|) or the end (|c2+c3|). Our bounds here are a little more - // conservative than that, but that's okay. - // - // If the acceleration of the parametric formula is zero (c2 = c3 = 0), - // that component of the curve is linear and does not incur any error. - // If a=0 for both X and Y, the curve is a line segment and we can - // use a step size of 1. - - int maxaccel1 = abs(cy2); - int maxaccel2 = abs(cx2); - - int maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; - int h = 1; - - while(maxaccel > 8 && h < 1024) { - maxaccel >>= 2; - h += h; - } - - int lastx = x0; - int lasty = y0; - - // compute forward differences - sint64 h1 = (sint64)(0x40000000 / h) << 2; - sint64 h2 = h1/h; - - sint64 ax0 = (sint64)cx0 << 32; - sint64 ax1 = h1*(sint64)cx1 + h2*(sint64)cx2; - sint64 ax2 = 2*h2*(sint64)cx2; - - sint64 ay0 = (sint64)cy0 << 32; - sint64 ay1 = h1*(sint64)cy1 + h2*(sint64)cy2; - sint64 ay2 = 2*h2*(sint64)cy2; - - // round, not truncate - ax0 += 0x80000000; - ay0 += 0x80000000; - - do { - ax0 += ax1; - ax1 += ax2; - ay0 += ay1; - ay1 += ay2; - - int xi = (int)((uint64)ax0 >> 32); - int yi = (int)((uint64)ay0 >> 32); - - FastLine(lastx, lasty, xi, yi); - lastx = xi; - lasty = yi; - } while(--h); -} - -void VDPixmapPathRasterizer::CubicBezier(const vdint2 *pts) { - int x0 = pts[0].x; - int x1 = pts[1].x; - int x2 = pts[2].x; - int x3 = pts[3].x; - int y0 = pts[0].y; - int y1 = pts[1].y; - int y2 = pts[2].y; - int y3 = pts[3].y; - - int cx3 = - x0+3*x1-3*x2+x3; - int cx2 = 3*x0-6*x1+3*x2; - int cx1 = -3*x0+3*x1; - int cx0 = x0; - - int cy3 = - y0+3*y1-3*y2+y3; - int cy2 = 3*y0-6*y1+3*y2; - int cy1 = -3*y0+3*y1; - int cy0 = y0; - - // This equation is from Graphics Gems I. - // - // The idea is that since we're approximating a cubic curve with lines, - // any error we incur is due to the curvature of the line, which we can - // estimate by calculating the maximum acceleration of the curve. For - // a cubic, the acceleration (second derivative) is a line, meaning that - // the absolute maximum acceleration must occur at either the beginning - // (|c2|) or the end (|c2+c3|). Our bounds here are a little more - // conservative than that, but that's okay. - // - // If the acceleration of the parametric formula is zero (c2 = c3 = 0), - // that component of the curve is linear and does not incur any error. - // If a=0 for both X and Y, the curve is a line segment and we can - // use a step size of 1. - - int maxaccel1 = abs(2*cy2) + abs(6*cy3); - int maxaccel2 = abs(2*cx2) + abs(6*cx3); - - int maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; - int h = 1; - - while(maxaccel > 8 && h < 1024) { - maxaccel >>= 2; - h += h; - } - - int lastx = x0; - int lasty = y0; - - // compute forward differences - sint64 h1 = (sint64)(0x40000000 / h) << 2; - sint64 h2 = h1/h; - sint64 h3 = h2/h; - - sint64 ax0 = (sint64)cx0 << 32; - sint64 ax1 = h1*(sint64)cx1 + h2*(sint64)cx2 + h3*(sint64)cx3; - sint64 ax2 = 2*h2*(sint64)cx2 + 6*h3*(sint64)cx3; - sint64 ax3 = 6*h3*(sint64)cx3; - - sint64 ay0 = (sint64)cy0 << 32; - sint64 ay1 = h1*(sint64)cy1 + h2*(sint64)cy2 + h3*(sint64)cy3; - sint64 ay2 = 2*h2*(sint64)cy2 + 6*h3*(sint64)cy3; - sint64 ay3 = 6*h3*(sint64)cy3; - - // round, not truncate - ax0 += 0x80000000; - ay0 += 0x80000000; - - do { - ax0 += ax1; - ax1 += ax2; - ax2 += ax3; - ay0 += ay1; - ay1 += ay2; - ay2 += ay3; - - int xi = (int)((uint64)ax0 >> 32); - int yi = (int)((uint64)ay0 >> 32); - - FastLine(lastx, lasty, xi, yi); - lastx = xi; - lasty = yi; - } while(--h); -} - -void VDPixmapPathRasterizer::Line(const vdint2& pt1, const vdint2& pt2) { - FastLine(pt1.x, pt1.y, pt2.x, pt2.y); -} - -void VDPixmapPathRasterizer::FastLine(int x0, int y0, int x1, int y1) { - int flag = 1; - - if (y1 == y0) - return; - - if (y1 < y0) { - int t; - - t=x0; x0=x1; x1=t; - t=y0; y0=y1; y1=t; - flag = 0; - } - - int dy = y1-y0; - int xacc = x0<<13; - - // prestep y0 down - int iy0 = (y0+3) >> 3; - int iy1 = (y1+3) >> 3; - - if (iy0 < iy1) { - int invslope = (x1-x0)*65536/dy; - - int prestep = (4-y0) & 7; - xacc += (invslope * prestep)>>3; - - if (iy0 < mScanYMin || iy1 > mScanYMax) { - ReallocateScanBuffer(iy0, iy1); - VDASSERT(iy0 >= mScanYMin && iy1 <= mScanYMax); - } - - while(iy0 < iy1) { - int ix = (xacc+32767)>>16; - - if (mEdgeBlockIdx >= kEdgeBlockMax) { - if (mpFreeEdgeBlocks) { - EdgeBlock *newBlock = mpFreeEdgeBlocks; - mpFreeEdgeBlocks = mpFreeEdgeBlocks->next; - newBlock->next = mpEdgeBlocks; - mpEdgeBlocks = newBlock; - } else { - mpEdgeBlocks = new EdgeBlock(mpEdgeBlocks); - } - - mEdgeBlockIdx = 0; - } - - Edge& e = mpEdgeBlocks->edges[mEdgeBlockIdx]; - Scan& s = mpScanBufferBiased[iy0]; - VDASSERT(iy0 >= mScanYMin && iy0 < mScanYMax); - ++mEdgeBlockIdx; - - e.posandflag = ix*2+flag; - e.next = s.chain; - s.chain = &e; - ++s.count; - - ++iy0; - xacc += invslope; - } - } -} - -void VDPixmapPathRasterizer::ScanConvert(VDPixmapRegion& region) { - // Convert the edges to spans. We couldn't do this before because some of - // the regions may have winding numbers >+1 and it would have been a pain - // to try to adjust the spans on the fly. We use one heap to detangle - // a scanline's worth of edges from the singly-linked lists, and another - // to collect the actual scans. - vdfastvector heap; - - region.mSpans.clear(); - int xmin = INT_MAX; - int xmax = INT_MIN; - int ymin = INT_MAX; - int ymax = INT_MIN; - - for(int y=mScanYMin; ynext) - *heap1++ = ptr->posandflag; - - VDASSERT(heap1 - heap0 == flipcount); - - // Sort edge heap. Note that we conveniently made the opening edges - // one more than closing edges at the same spot, so we won't have any - // problems with abutting spans. - - std::sort(heap0, heap1); - -#if 0 - while(heap0 != heap1) { - int x = *heap0++ >> 1; - region.mSpans.push_back((y<<16) + x + 0x80008000); - region.mSpans.push_back((y<<16) + x + 0x80008001); - } - continue; -#endif - - // Trim any odd edges off, since we can never close on one. - if (flipcount & 1) - --heap1; - - // Process edges and add spans. Since we only check for a non-zero - // winding number, it doesn't matter which way the outlines go. Also, since - // the parity always flips after each edge regardless of direction, we can - // process the edges in pairs. - - size_t spanstart = region.mSpans.size(); - - int x_left; - int count = 0; - while(heap0 != heap1) { - int x = *heap0++; - - if (!count) - x_left = (x>>1); - - count += (x&1); - - x = *heap0++; - - count += (x&1); - - if (!--count) { - int x_right = (x>>1); - - if (x_right > x_left) { - region.mSpans.push_back((y<<16) + x_left + 0x80008000); - region.mSpans.push_back((y<<16) + x_right + 0x80008000); - - } - } - } - - size_t spanend = region.mSpans.size(); - - if (spanend > spanstart) { - if (ymin > y) - ymin = y; - - if (ymax < y) - ymax = y; - - int x1 = (region.mSpans[spanstart] & 0xffff) - 0x8000; - int x2 = (region.mSpans[spanend-1] & 0xffff) - 0x8000; - - if (xmin > x1) - xmin = x1; - - if (xmax < x2) - xmax = x2; - } - } - - if (xmax > xmin) { - region.mBounds.set(xmin, ymin, xmax, ymax); - } else { - region.mBounds.set(0, 0, 0, 0); - } - - // Dump the edge and scan buffers, since we no longer need them. - ClearEdgeList(); - ClearScanBuffer(); -} - -void VDPixmapPathRasterizer::ClearEdgeList() { - if (mpEdgeBlocks) { - EdgeBlock *block = mpEdgeBlocks; - - while(EdgeBlock *next = block->next) - block = next; - - block->next = mpFreeEdgeBlocks; - mpFreeEdgeBlocks = mpEdgeBlocks; - mpEdgeBlocks = NULL; - } - - mEdgeBlockIdx = kEdgeBlockMax; -} - -void VDPixmapPathRasterizer::FreeEdgeLists() { - ClearEdgeList(); - - while(EdgeBlock *block = mpFreeEdgeBlocks) { - mpFreeEdgeBlocks = block->next; - - delete block; - } -} - -void VDPixmapPathRasterizer::ClearScanBuffer() { - delete[] mpScanBuffer; - mpScanBuffer = mpScanBufferBiased = NULL; - mScanYMin = 0; - mScanYMax = 0; -} - -void VDPixmapPathRasterizer::ReallocateScanBuffer(int ymin, int ymax) { - // - // check if there actually is a scan buffer to avoid unintentionally pinning at zero - if (mpScanBuffer) { - int nicedelta = (mScanYMax - mScanYMin); - - if (ymin < mScanYMin) { - int yminnice = mScanYMin - nicedelta; - if (ymin > yminnice) - ymin = yminnice; - - ymin &= ~31; - } else - ymin = mScanYMin; - - if (ymax > mScanYMax) { - int ymaxnice = mScanYMax + nicedelta; - if (ymax < ymaxnice) - ymax = ymaxnice; - - ymax = (ymax + 31) & ~31; - } else - ymax = mScanYMax; - - VDASSERT(ymin <= mScanYMin && ymax >= mScanYMax); - } - - // reallocate scan buffer - Scan *pNewBuffer = new Scan[ymax - ymin]; - Scan *pNewBufferBiased = pNewBuffer - ymin; - - if (mpScanBuffer) { - memcpy(pNewBufferBiased + mScanYMin, mpScanBufferBiased + mScanYMin, (mScanYMax - mScanYMin) * sizeof(Scan)); - delete[] mpScanBuffer; - - // zero new areas of scan buffer - for(int y=ymin; y> 1) & ~1; - - if (region.mSpans[mid + 1] < spanmin) - lo = mid + 2; - else - hi = mid; - } - - start = lo; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w - x) + ((dst.h - y - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // compute bottom clip - int lo = start; - int hi = n; - - while(lo < hi) { - int mid = ((lo + hi) >> 1) & ~1; - - if (region.mSpans[mid] >= spanlimit) - hi = mid; - else - lo = mid+2; - } - - end = lo; - - // check for total bottom clip - if (start >= end) - return true; - } - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - uint32 *dstp; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - uint32 py = (span0 >> 16) - 0x8000 + y; - uint32 px = (span0 & 0xffff) - 0x8000 + x; - uint32 w = span1-span0; - - VDASSERT(py < (uint32)dst.h); - VDASSERT(px < (uint32)dst.w); - VDASSERT(dst.w - (int)px >= (int)w); - - if (lasty != py) - dstp = (uint32 *)vdptroffset(dst.data, dst.pitch * py); - - uint32 *p = dstp + px; - do { - *p++ = color; - } while(--w); - } - - return true; -} - -namespace { - void RenderABuffer32(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint32 *dstp = (uint32 *)vdptroffset(dst.data, dst.pitch * y); - - const uint32 color_rb = color & 0x00FF00FF; - const uint32 color_g = color & 0x0000FF00; - do { - const uint32 px = *dstp; - const uint32 px_rb = px & 0x00FF00FF; - const uint32 px_g = px & 0x0000FF00; - const sint32 a = *alpha++; - - const uint32 result_rb = (((px_rb << 6) + ((sint32)(color_rb - px_rb)*a + 0x00200020)) & 0x3FC03FC0); - const uint32 result_g = (((px_g << 6) + ((sint32)(color_g - px_g )*a + 0x00002000)) & 0x003FC000); - - *dstp++ = (result_rb + result_g) >> 6; - } while(--w); - } - - void RenderABuffer8(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); - - do { - const uint8 px = *dstp; - const sint8 a = *alpha++; - - *dstp++ = px + (((sint32)(color - px) * a + 32) >> 6); - } while(--w); - } - - void RenderABuffer8_128(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); - - do { - const uint8 px = *dstp; - const sint16 a = *alpha++; - - *dstp++ = px + (((sint32)(color - px) * a + 64) >> 7); - } while(--w); - } - - void RenderABuffer8_256(const VDPixmap& dst, int y, const uint16 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); - - do { - const uint8 px = *dstp; - const sint32 a = *alpha++; - - *dstp++ = px + (((sint32)(color - px) * a + 128) >> 8); - } while(--w); - } - - void RenderABuffer8_1024(const VDPixmap& dst, int y, const uint16 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); - - do { - const uint8 px = *dstp; - const sint32 a = *alpha++; - - *dstp++ = px + (((sint32)(color - px) * a + 512) >> 10); - } while(--w); - } -} - -bool VDPixmapFillRegionAntialiased_32x_32x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { - if (dst.format != nsVDPixmap::kPixFormat_Y8) - return false; - - // fast out - if (region.mSpans.empty()) - return true; - - // check if vertical clipping is required - const size_t n = region.mSpans.size(); - uint32 start = 0; - uint32 end = n; - - uint32 spanmin = -x + (-y << 16) + 0x80008000; - - if (region.mSpans.front() < spanmin) { - // find first span : x2 > spanmin - start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); - start &= ~1; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w*32 - x) + (((dst.h*32 - y) - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // find last span : x1 < spanlimit - end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); - - end = (end + 1) & ~1; - - // check for total bottom clip - if (start >= end) - return true; - } - - // allocate A-buffer - vdfastvector abuffer(dst.w, 0); - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - - sint32 dstw32 = dst.w * 32; - sint32 dsth32 = dst.h * 32; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - sint32 py = (span0 >> 16) - 0x8000 + y; - - if ((uint32)py >= (uint32)dsth32) - continue; - - sint32 px1 = (span0 & 0xffff) - 0x8000 + x; - sint32 px2 = (span1 & 0xffff) - 0x8000 + x; - sint32 w = span1-span0; - - if (lasty != py) { - if (((lasty ^ py) & 0xFFFFFFE0)) { - if (lasty >= 0) { - // flush scanline - - RenderABuffer8_1024(dst, lasty >> 5, abuffer.data(), dst.w, color); - } - - memset(abuffer.data(), 0, abuffer.size() * sizeof(abuffer[0])); - } - lasty = py; - } - - if (px1 < 0) - px1 = 0; - if (px2 > dstw32) - px2 = dstw32; - - if (px1 >= px2) - continue; - - uint32 ix1 = px1 >> 5; - uint32 ix2 = px2 >> 5; - uint16 *p1 = abuffer.data() + ix1; - uint16 *p2 = abuffer.data() + ix2; - - if (p1 == p2) { - p1[0] += (px2 - px1); - } else { - if (px1 & 31) { - p1[0] += 32 - (px1 & 31); - ++p1; - } - - while(p1 != p2) { - p1[0] += 32; - ++p1; - } - - if (px2 & 31) - p1[0] += px2 & 32; - } - } - - if (lasty >= 0) - RenderABuffer8_1024(dst, lasty >> 5, abuffer.data(), dst.w, color); - - return true; -} - -bool VDPixmapFillRegionAntialiased_16x_16x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { - if (dst.format != nsVDPixmap::kPixFormat_Y8) - return false; - - // fast out - if (region.mSpans.empty()) - return true; - - // check if vertical clipping is required - const size_t n = region.mSpans.size(); - uint32 start = 0; - uint32 end = n; - - uint32 spanmin = -x + (-y << 16) + 0x80008000; - - if (region.mSpans.front() < spanmin) { - // find first span : x2 > spanmin - start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); - start &= ~1; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w*16 - x) + (((dst.h*16 - y) - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // find last span : x1 < spanlimit - end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); - - end = (end + 1) & ~1; - - // check for total bottom clip - if (start >= end) - return true; - } - - // allocate A-buffer - vdfastvector abuffer(dst.w, 0); - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - - sint32 dstw16 = dst.w * 16; - sint32 dsth16 = dst.h * 16; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - sint32 py = (span0 >> 16) - 0x8000 + y; - - if ((uint32)py >= (uint32)dsth16) - continue; - - sint32 px1 = (span0 & 0xffff) - 0x8000 + x; - sint32 px2 = (span1 & 0xffff) - 0x8000 + x; - sint32 w = span1-span0; - - if (lasty != py) { - if (((lasty ^ py) & 0xFFFFFFF0)) { - if (lasty >= 0) { - // flush scanline - - RenderABuffer8_256(dst, lasty >> 4, abuffer.data(), dst.w, color); - } - - memset(abuffer.data(), 0, abuffer.size() * sizeof(abuffer[0])); - } - lasty = py; - } - - if (px1 < 0) - px1 = 0; - if (px2 > dstw16) - px2 = dstw16; - - if (px1 >= px2) - continue; - - uint32 ix1 = px1 >> 4; - uint32 ix2 = px2 >> 4; - uint16 *p1 = abuffer.data() + ix1; - uint16 *p2 = abuffer.data() + ix2; - - if (p1 == p2) { - p1[0] += (px2 - px1); - } else { - if (px1 & 15) { - p1[0] += 16 - (px1 & 15); - ++p1; - } - - while(p1 != p2) { - p1[0] += 16; - ++p1; - } - - if (px2 & 15) - p1[0] += px2 & 15; - } - } - - if (lasty >= 0) - RenderABuffer8_256(dst, lasty >> 4, abuffer.data(), dst.w, color); - - return true; -} - -bool VDPixmapFillRegionAntialiased_16x_8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { - if (dst.format != nsVDPixmap::kPixFormat_XRGB8888 && dst.format != nsVDPixmap::kPixFormat_Y8) - return false; - - // fast out - if (region.mSpans.empty()) - return true; - - // check if vertical clipping is required - const size_t n = region.mSpans.size(); - uint32 start = 0; - uint32 end = n; - - uint32 spanmin = -x + (-y << 16) + 0x80008000; - - if (region.mSpans.front() < spanmin) { - // find first span : x2 > spanmin - start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); - start &= ~1; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w*16 - x) + (((dst.h*8 - y) - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // find last span : x1 < spanlimit - end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); - - end = (end + 1) & ~1; - - // check for total bottom clip - if (start >= end) - return true; - } - - // allocate A-buffer - vdfastvector abuffer(dst.w, 0); - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - - sint32 dstw16 = dst.w * 16; - sint32 dsth8 = dst.h * 8; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - sint32 py = (span0 >> 16) - 0x8000 + y; - - if ((uint32)py >= (uint32)dsth8) - continue; - - sint32 px1 = (span0 & 0xffff) - 0x8000 + x; - sint32 px2 = (span1 & 0xffff) - 0x8000 + x; - sint32 w = span1-span0; - - if (lasty != py) { - if (((lasty ^ py) & 0xFFFFFFF8)) { - if (lasty >= 0) { - // flush scanline - - RenderABuffer8_128(dst, lasty >> 3, abuffer.data(), dst.w, color); - } - - memset(abuffer.data(), 0, abuffer.size()); - } - lasty = py; - } - - if (px1 < 0) - px1 = 0; - if (px2 > dstw16) - px2 = dstw16; - - if (px1 >= px2) - continue; - - uint32 ix1 = px1 >> 4; - uint32 ix2 = px2 >> 4; - uint8 *p1 = abuffer.data() + ix1; - uint8 *p2 = abuffer.data() + ix2; - - if (p1 == p2) { - p1[0] += (px2 - px1); - } else { - if (px1 & 15) { - p1[0] += 16 - (px1 & 15); - ++p1; - } - - while(p1 != p2) { - p1[0] += 16; - ++p1; - } - - if (px2 & 15) - p1[0] += px2 & 15; - } - } - - if (lasty >= 0) - RenderABuffer8_128(dst, lasty >> 3, abuffer.data(), dst.w, color); - - return true; -} - -bool VDPixmapFillRegionAntialiased8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { - switch(dst.format) { - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - { - VDPixmap pxY; - VDPixmap pxCb; - VDPixmap pxCr; - - pxY.format = nsVDPixmap::kPixFormat_Y8; - pxY.data = dst.data; - pxY.pitch = dst.pitch; - pxY.w = dst.w; - pxY.h = dst.h; - - pxCb.format = nsVDPixmap::kPixFormat_Y8; - pxCb.data = dst.data2; - pxCb.pitch = dst.pitch2; - pxCb.w = dst.w; - pxCb.h = dst.h; - - pxCr.format = nsVDPixmap::kPixFormat_Y8; - pxCr.data = dst.data3; - pxCr.pitch = dst.pitch3; - pxCr.w = dst.w; - pxCr.h = dst.h; - - uint32 colorY = (color >> 8) & 0xff; - uint32 colorCb = (color >> 0) & 0xff; - uint32 colorCr = (color >> 16) & 0xff; - - VDPixmapFillRegionAntialiased8x(pxY, region, x, y, colorY); - - switch(dst.format) { - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 2; - pxCr.h = pxCb.h = dst.h >> 2; - x >>= 2; - y >>= 2; - VDPixmapFillRegionAntialiased_32x_32x(pxCb, region, x, y, colorCb); - VDPixmapFillRegionAntialiased_32x_32x(pxCr, region, x, y, colorCr); - return true; - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 1; - pxCr.h = pxCb.h = dst.h >> 1; - x >>= 1; - y >>= 1; - x += 2; - VDPixmapFillRegionAntialiased_16x_16x(pxCb, region, x, y, colorCb); - VDPixmapFillRegionAntialiased_16x_16x(pxCr, region, x, y, colorCr); - return true; - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 1; - x >>= 1; - x += 2; - VDPixmapFillRegionAntialiased_16x_8x(pxCb, region, x, y, colorCb); - VDPixmapFillRegionAntialiased_16x_8x(pxCr, region, x, y, colorCr); - return true; - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - VDPixmapFillRegionAntialiased8x(pxCb, region, x, y, colorCb); - VDPixmapFillRegionAntialiased8x(pxCr, region, x, y, colorCr); - return true; - } - } - } - - if (dst.format != nsVDPixmap::kPixFormat_XRGB8888 && dst.format != nsVDPixmap::kPixFormat_Y8) - return false; - - // fast out - if (region.mSpans.empty()) - return true; - - // check if vertical clipping is required - const size_t n = region.mSpans.size(); - uint32 start = 0; - uint32 end = n; - - uint32 spanmin = -x + (-y << 16) + 0x80008000; - - if (region.mSpans.front() < spanmin) { - // find first span : x2 > spanmin - start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); - start &= ~1; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w*8 - x) + (((dst.h*8 - y) - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // find last span : x1 < spanlimit - end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); - - end = (end + 1) & ~1; - - // check for total bottom clip - if (start >= end) - return true; - } - - // allocate A-buffer - vdfastvector abuffer(dst.w, 0); - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - - sint32 dstw8 = dst.w * 8; - sint32 dsth8 = dst.h * 8; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - sint32 py = (span0 >> 16) - 0x8000 + y; - - if ((uint32)py >= (uint32)dsth8) - continue; - - sint32 px1 = (span0 & 0xffff) - 0x8000 + x; - sint32 px2 = (span1 & 0xffff) - 0x8000 + x; - sint32 w = span1-span0; - - if (lasty != py) { - if (((lasty ^ py) & 0xFFFFFFF8)) { - if (lasty >= 0) { - // flush scanline - - if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) - RenderABuffer32(dst, lasty >> 3, abuffer.data(), dst.w, color); - else - RenderABuffer8(dst, lasty >> 3, abuffer.data(), dst.w, color); - } - - memset(abuffer.data(), 0, abuffer.size()); - } - lasty = py; - } - - if (px1 < 0) - px1 = 0; - if (px2 > dstw8) - px2 = dstw8; - - if (px1 >= px2) - continue; - - uint32 ix1 = px1 >> 3; - uint32 ix2 = px2 >> 3; - uint8 *p1 = abuffer.data() + ix1; - uint8 *p2 = abuffer.data() + ix2; - - if (p1 == p2) { - p1[0] += (px2 - px1); - } else { - if (px1 & 7) { - p1[0] += 8 - (px1 & 7); - ++p1; - } - - while(p1 != p2) { - p1[0] += 8; - ++p1; - } - - if (px2 & 7) - p1[0] += px2 & 7; - } - } - - if (lasty >= 0) { - if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) - RenderABuffer32(dst, lasty >> 3, abuffer.data(), dst.w, color); - else - RenderABuffer8(dst, lasty >> 3, abuffer.data(), dst.w, color); - } - - return true; -} - -void VDPixmapCreateRoundRegion(VDPixmapRegion& dst, float r) { - int ir = VDCeilToInt(r); - float r2 = r*r; - - dst.mSpans.clear(); - dst.mBounds.set(-ir, 0, ir+1, 0); - - for(int y = -ir; y <= ir; ++y) { - int dx = VDCeilToInt(sqrtf(r2 - y*y)); - - if (dx > 0) { - dst.mSpans.push_back(0x80008000 + (y << 16) - dx); - dst.mSpans.push_back(0x80008001 + (y << 16) + dx); - if (dst.mBounds.top > y) - dst.mBounds.top = y; - if (dst.mBounds.bottom < y) - dst.mBounds.bottom = y; - } - } -} - -void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, int dx1, int dx2, int dy) { - dst.mSpans.clear(); - dst.mSpans.resize(r1.mSpans.size()+r2.mSpans.size()); - - const uint32 *itA = r1.mSpans.data(); - const uint32 *itAE = itA + r1.mSpans.size(); - const uint32 *itB = r2.mSpans.data(); - const uint32 *itBE = itB + r2.mSpans.size(); - uint32 *dstp0 = dst.mSpans.data(); - uint32 *dstp = dst.mSpans.data(); - - uint32 offset1 = (dy<<16) + dx1; - uint32 offset2 = (dy<<16) + dx2; - - while(itA != itAE && itB != itBE) { - uint32 x1; - uint32 x2; - - if (itB[0] + offset1 < itA[0]) { - // B span is earlier. Use it. - x1 = itB[0] + offset1; - x2 = itB[1] + offset2; - itB += 2; - - // B spans *can* overlap, due to the widening. - while(itB != itBE && itB[0]+offset1 <= x2) { - uint32 bx2 = itB[1] + offset2; - if (x2 < bx2) - x2 = bx2; - - itB += 2; - } - - goto a_start; - } else { - // A span is earlier. Use it. - x1 = itA[0]; - x2 = itA[1]; - itA += 2; - - // A spans don't overlap, so begin merge loop with B first. - } - - for(;;) { - // If we run out of B spans or the B span doesn't overlap, - // then the next A span can't either (because A spans don't - // overlap) and we exit. - - if (itB == itBE || itB[0]+offset1 > x2) - break; - - do { - uint32 bx2 = itB[1] + offset2; - if (x2 < bx2) - x2 = bx2; - - itB += 2; - } while(itB != itBE && itB[0]+offset1 <= x2); - - // If we run out of A spans or the A span doesn't overlap, - // then the next B span can't either, because we would have - // consumed all overlapping B spans in the above loop. -a_start: - if (itA == itAE || itA[0] > x2) - break; - - do { - uint32 ax2 = itA[1]; - if (x2 < ax2) - x2 = ax2; - - itA += 2; - } while(itA != itAE && itA[0] <= x2); - } - - // Flush span. - dstp[0] = x1; - dstp[1] = x2; - dstp += 2; - } - - // Copy over leftover spans. - memcpy(dstp, itA, sizeof(uint32)*(itAE - itA)); - dstp += itAE - itA; - - while(itB != itBE) { - // B span is earlier. Use it. - uint32 x1 = itB[0] + offset1; - uint32 x2 = itB[1] + offset2; - itB += 2; - - // B spans *can* overlap, due to the widening. - while(itB != itBE && itB[0]+offset1 <= x2) { - uint32 bx2 = itB[1] + offset2; - if (x2 < bx2) - x2 = bx2; - - itB += 2; - } - - dstp[0] = x1; - dstp[1] = x2; - dstp += 2; - } - - dst.mSpans.resize(dstp - dst.mSpans.data()); -} - -void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, VDPixmapRegion *tempCache) { - VDPixmapRegion temp; - - if (tempCache) { - tempCache->swap(temp); - - temp.clear(); - } - - const uint32 *src1 = r2.mSpans.data(); - const uint32 *src2 = src1 + r2.mSpans.size(); - - dst.mSpans.clear(); - while(src1 != src2) { - uint32 p1 = src1[0]; - uint32 p2 = src1[1]; - src1 += 2; - - temp.mSpans.swap(dst.mSpans); - VDPixmapConvolveRegion(dst, temp, r1, (p1 & 0xffff) - 0x8000, (p2 & 0xffff) - 0x8000, (p1 >> 16) - 0x8000); - } - - if (tempCache) - tempCache->swap(temp); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include + +void VDPixmapRegion::clear() { + mSpans.clear(); +} + +void VDPixmapRegion::swap(VDPixmapRegion& x) { + mSpans.swap(x.mSpans); + std::swap(mBounds, x.mBounds); +} + +VDPixmapPathRasterizer::VDPixmapPathRasterizer() + : mpEdgeBlocks(NULL) + , mpFreeEdgeBlocks(NULL) + , mEdgeBlockIdx(kEdgeBlockMax) + , mpScanBuffer(NULL) +{ + ClearScanBuffer(); +} + +VDPixmapPathRasterizer::VDPixmapPathRasterizer(const VDPixmapPathRasterizer&) + : mpEdgeBlocks(NULL) + , mpFreeEdgeBlocks(NULL) + , mEdgeBlockIdx(kEdgeBlockMax) + , mpScanBuffer(NULL) +{ + ClearScanBuffer(); +} + +VDPixmapPathRasterizer::~VDPixmapPathRasterizer() { + Clear(); + FreeEdgeLists(); +} + +VDPixmapPathRasterizer& VDPixmapPathRasterizer::operator=(const VDPixmapPathRasterizer&) { + return *this; +} + +void VDPixmapPathRasterizer::Clear() { + ClearEdgeList(); + ClearScanBuffer(); +} + +void VDPixmapPathRasterizer::QuadraticBezier(const vdint2 *pts) { + int x0 = pts[0].x; + int x1 = pts[1].x; + int x2 = pts[2].x; + int y0 = pts[0].y; + int y1 = pts[1].y; + int y2 = pts[2].y; + + // P = (1-t)^2*P0 + 2t(1-t)*P1 + t^2*P2 + // P = (1-2t+t^2)P0 + 2(t-t^2)P1 + t^2*P2 + // P = (P0-2P1+P2)t^2 + 2(P1-P0)t + P0 + + int cx2 = x0-2*x1+x2; + int cx1 = -2*x0+2*x1; + int cx0 = x0; + + int cy2 = y0-2*y1+y2; + int cy1 = -2*y0+2*y1; + int cy0 = y0; + + // This equation is from Graphics Gems I. + // + // The idea is that since we're approximating a cubic curve with lines, + // any error we incur is due to the curvature of the line, which we can + // estimate by calculating the maximum acceleration of the curve. For + // a cubic, the acceleration (second derivative) is a line, meaning that + // the absolute maximum acceleration must occur at either the beginning + // (|c2|) or the end (|c2+c3|). Our bounds here are a little more + // conservative than that, but that's okay. + // + // If the acceleration of the parametric formula is zero (c2 = c3 = 0), + // that component of the curve is linear and does not incur any error. + // If a=0 for both X and Y, the curve is a line segment and we can + // use a step size of 1. + + int maxaccel1 = abs(cy2); + int maxaccel2 = abs(cx2); + + int maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; + int h = 1; + + while(maxaccel > 8 && h < 1024) { + maxaccel >>= 2; + h += h; + } + + int lastx = x0; + int lasty = y0; + + // compute forward differences + sint64 h1 = (sint64)(0x40000000 / h) << 2; + sint64 h2 = h1/h; + + sint64 ax0 = (sint64)cx0 << 32; + sint64 ax1 = h1*(sint64)cx1 + h2*(sint64)cx2; + sint64 ax2 = 2*h2*(sint64)cx2; + + sint64 ay0 = (sint64)cy0 << 32; + sint64 ay1 = h1*(sint64)cy1 + h2*(sint64)cy2; + sint64 ay2 = 2*h2*(sint64)cy2; + + // round, not truncate + ax0 += 0x80000000; + ay0 += 0x80000000; + + do { + ax0 += ax1; + ax1 += ax2; + ay0 += ay1; + ay1 += ay2; + + int xi = (int)((uint64)ax0 >> 32); + int yi = (int)((uint64)ay0 >> 32); + + FastLine(lastx, lasty, xi, yi); + lastx = xi; + lasty = yi; + } while(--h); +} + +void VDPixmapPathRasterizer::CubicBezier(const vdint2 *pts) { + int x0 = pts[0].x; + int x1 = pts[1].x; + int x2 = pts[2].x; + int x3 = pts[3].x; + int y0 = pts[0].y; + int y1 = pts[1].y; + int y2 = pts[2].y; + int y3 = pts[3].y; + + int cx3 = - x0+3*x1-3*x2+x3; + int cx2 = 3*x0-6*x1+3*x2; + int cx1 = -3*x0+3*x1; + int cx0 = x0; + + int cy3 = - y0+3*y1-3*y2+y3; + int cy2 = 3*y0-6*y1+3*y2; + int cy1 = -3*y0+3*y1; + int cy0 = y0; + + // This equation is from Graphics Gems I. + // + // The idea is that since we're approximating a cubic curve with lines, + // any error we incur is due to the curvature of the line, which we can + // estimate by calculating the maximum acceleration of the curve. For + // a cubic, the acceleration (second derivative) is a line, meaning that + // the absolute maximum acceleration must occur at either the beginning + // (|c2|) or the end (|c2+c3|). Our bounds here are a little more + // conservative than that, but that's okay. + // + // If the acceleration of the parametric formula is zero (c2 = c3 = 0), + // that component of the curve is linear and does not incur any error. + // If a=0 for both X and Y, the curve is a line segment and we can + // use a step size of 1. + + int maxaccel1 = abs(2*cy2) + abs(6*cy3); + int maxaccel2 = abs(2*cx2) + abs(6*cx3); + + int maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; + int h = 1; + + while(maxaccel > 8 && h < 1024) { + maxaccel >>= 2; + h += h; + } + + int lastx = x0; + int lasty = y0; + + // compute forward differences + sint64 h1 = (sint64)(0x40000000 / h) << 2; + sint64 h2 = h1/h; + sint64 h3 = h2/h; + + sint64 ax0 = (sint64)cx0 << 32; + sint64 ax1 = h1*(sint64)cx1 + h2*(sint64)cx2 + h3*(sint64)cx3; + sint64 ax2 = 2*h2*(sint64)cx2 + 6*h3*(sint64)cx3; + sint64 ax3 = 6*h3*(sint64)cx3; + + sint64 ay0 = (sint64)cy0 << 32; + sint64 ay1 = h1*(sint64)cy1 + h2*(sint64)cy2 + h3*(sint64)cy3; + sint64 ay2 = 2*h2*(sint64)cy2 + 6*h3*(sint64)cy3; + sint64 ay3 = 6*h3*(sint64)cy3; + + // round, not truncate + ax0 += 0x80000000; + ay0 += 0x80000000; + + do { + ax0 += ax1; + ax1 += ax2; + ax2 += ax3; + ay0 += ay1; + ay1 += ay2; + ay2 += ay3; + + int xi = (int)((uint64)ax0 >> 32); + int yi = (int)((uint64)ay0 >> 32); + + FastLine(lastx, lasty, xi, yi); + lastx = xi; + lasty = yi; + } while(--h); +} + +void VDPixmapPathRasterizer::Line(const vdint2& pt1, const vdint2& pt2) { + FastLine(pt1.x, pt1.y, pt2.x, pt2.y); +} + +void VDPixmapPathRasterizer::FastLine(int x0, int y0, int x1, int y1) { + int flag = 1; + + if (y1 == y0) + return; + + if (y1 < y0) { + int t; + + t=x0; x0=x1; x1=t; + t=y0; y0=y1; y1=t; + flag = 0; + } + + int dy = y1-y0; + int xacc = x0<<13; + + // prestep y0 down + int iy0 = (y0+3) >> 3; + int iy1 = (y1+3) >> 3; + + if (iy0 < iy1) { + int invslope = (x1-x0)*65536/dy; + + int prestep = (4-y0) & 7; + xacc += (invslope * prestep)>>3; + + if (iy0 < mScanYMin || iy1 > mScanYMax) { + ReallocateScanBuffer(iy0, iy1); + VDASSERT(iy0 >= mScanYMin && iy1 <= mScanYMax); + } + + while(iy0 < iy1) { + int ix = (xacc+32767)>>16; + + if (mEdgeBlockIdx >= kEdgeBlockMax) { + if (mpFreeEdgeBlocks) { + EdgeBlock *newBlock = mpFreeEdgeBlocks; + mpFreeEdgeBlocks = mpFreeEdgeBlocks->next; + newBlock->next = mpEdgeBlocks; + mpEdgeBlocks = newBlock; + } else { + mpEdgeBlocks = new EdgeBlock(mpEdgeBlocks); + } + + mEdgeBlockIdx = 0; + } + + Edge& e = mpEdgeBlocks->edges[mEdgeBlockIdx]; + Scan& s = mpScanBufferBiased[iy0]; + VDASSERT(iy0 >= mScanYMin && iy0 < mScanYMax); + ++mEdgeBlockIdx; + + e.posandflag = ix*2+flag; + e.next = s.chain; + s.chain = &e; + ++s.count; + + ++iy0; + xacc += invslope; + } + } +} + +void VDPixmapPathRasterizer::ScanConvert(VDPixmapRegion& region) { + // Convert the edges to spans. We couldn't do this before because some of + // the regions may have winding numbers >+1 and it would have been a pain + // to try to adjust the spans on the fly. We use one heap to detangle + // a scanline's worth of edges from the singly-linked lists, and another + // to collect the actual scans. + vdfastvector heap; + + region.mSpans.clear(); + int xmin = INT_MAX; + int xmax = INT_MIN; + int ymin = INT_MAX; + int ymax = INT_MIN; + + for(int y=mScanYMin; ynext) + *heap1++ = ptr->posandflag; + + VDASSERT(heap1 - heap0 == flipcount); + + // Sort edge heap. Note that we conveniently made the opening edges + // one more than closing edges at the same spot, so we won't have any + // problems with abutting spans. + + std::sort(heap0, heap1); + +#if 0 + while(heap0 != heap1) { + int x = *heap0++ >> 1; + region.mSpans.push_back((y<<16) + x + 0x80008000); + region.mSpans.push_back((y<<16) + x + 0x80008001); + } + continue; +#endif + + // Trim any odd edges off, since we can never close on one. + if (flipcount & 1) + --heap1; + + // Process edges and add spans. Since we only check for a non-zero + // winding number, it doesn't matter which way the outlines go. Also, since + // the parity always flips after each edge regardless of direction, we can + // process the edges in pairs. + + size_t spanstart = region.mSpans.size(); + + int x_left; + int count = 0; + while(heap0 != heap1) { + int x = *heap0++; + + if (!count) + x_left = (x>>1); + + count += (x&1); + + x = *heap0++; + + count += (x&1); + + if (!--count) { + int x_right = (x>>1); + + if (x_right > x_left) { + region.mSpans.push_back((y<<16) + x_left + 0x80008000); + region.mSpans.push_back((y<<16) + x_right + 0x80008000); + + } + } + } + + size_t spanend = region.mSpans.size(); + + if (spanend > spanstart) { + if (ymin > y) + ymin = y; + + if (ymax < y) + ymax = y; + + int x1 = (region.mSpans[spanstart] & 0xffff) - 0x8000; + int x2 = (region.mSpans[spanend-1] & 0xffff) - 0x8000; + + if (xmin > x1) + xmin = x1; + + if (xmax < x2) + xmax = x2; + } + } + + if (xmax > xmin) { + region.mBounds.set(xmin, ymin, xmax, ymax); + } else { + region.mBounds.set(0, 0, 0, 0); + } + + // Dump the edge and scan buffers, since we no longer need them. + ClearEdgeList(); + ClearScanBuffer(); +} + +void VDPixmapPathRasterizer::ClearEdgeList() { + if (mpEdgeBlocks) { + EdgeBlock *block = mpEdgeBlocks; + + while(EdgeBlock *next = block->next) + block = next; + + block->next = mpFreeEdgeBlocks; + mpFreeEdgeBlocks = mpEdgeBlocks; + mpEdgeBlocks = NULL; + } + + mEdgeBlockIdx = kEdgeBlockMax; +} + +void VDPixmapPathRasterizer::FreeEdgeLists() { + ClearEdgeList(); + + while(EdgeBlock *block = mpFreeEdgeBlocks) { + mpFreeEdgeBlocks = block->next; + + delete block; + } +} + +void VDPixmapPathRasterizer::ClearScanBuffer() { + delete[] mpScanBuffer; + mpScanBuffer = mpScanBufferBiased = NULL; + mScanYMin = 0; + mScanYMax = 0; +} + +void VDPixmapPathRasterizer::ReallocateScanBuffer(int ymin, int ymax) { + // + // check if there actually is a scan buffer to avoid unintentionally pinning at zero + if (mpScanBuffer) { + int nicedelta = (mScanYMax - mScanYMin); + + if (ymin < mScanYMin) { + int yminnice = mScanYMin - nicedelta; + if (ymin > yminnice) + ymin = yminnice; + + ymin &= ~31; + } else + ymin = mScanYMin; + + if (ymax > mScanYMax) { + int ymaxnice = mScanYMax + nicedelta; + if (ymax < ymaxnice) + ymax = ymaxnice; + + ymax = (ymax + 31) & ~31; + } else + ymax = mScanYMax; + + VDASSERT(ymin <= mScanYMin && ymax >= mScanYMax); + } + + // reallocate scan buffer + Scan *pNewBuffer = new Scan[ymax - ymin]; + Scan *pNewBufferBiased = pNewBuffer - ymin; + + if (mpScanBuffer) { + memcpy(pNewBufferBiased + mScanYMin, mpScanBufferBiased + mScanYMin, (mScanYMax - mScanYMin) * sizeof(Scan)); + delete[] mpScanBuffer; + + // zero new areas of scan buffer + for(int y=ymin; y> 1) & ~1; + + if (region.mSpans[mid + 1] < spanmin) + lo = mid + 2; + else + hi = mid; + } + + start = lo; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w - x) + ((dst.h - y - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // compute bottom clip + int lo = start; + int hi = n; + + while(lo < hi) { + int mid = ((lo + hi) >> 1) & ~1; + + if (region.mSpans[mid] >= spanlimit) + hi = mid; + else + lo = mid+2; + } + + end = lo; + + // check for total bottom clip + if (start >= end) + return true; + } + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + uint32 *dstp; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + uint32 py = (span0 >> 16) - 0x8000 + y; + uint32 px = (span0 & 0xffff) - 0x8000 + x; + uint32 w = span1-span0; + + VDASSERT(py < (uint32)dst.h); + VDASSERT(px < (uint32)dst.w); + VDASSERT(dst.w - (int)px >= (int)w); + + if (lasty != py) + dstp = (uint32 *)vdptroffset(dst.data, dst.pitch * py); + + uint32 *p = dstp + px; + do { + *p++ = color; + } while(--w); + } + + return true; +} + +namespace { + void RenderABuffer32(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint32 *dstp = (uint32 *)vdptroffset(dst.data, dst.pitch * y); + + const uint32 color_rb = color & 0x00FF00FF; + const uint32 color_g = color & 0x0000FF00; + do { + const uint32 px = *dstp; + const uint32 px_rb = px & 0x00FF00FF; + const uint32 px_g = px & 0x0000FF00; + const sint32 a = *alpha++; + + const uint32 result_rb = (((px_rb << 6) + ((sint32)(color_rb - px_rb)*a + 0x00200020)) & 0x3FC03FC0); + const uint32 result_g = (((px_g << 6) + ((sint32)(color_g - px_g )*a + 0x00002000)) & 0x003FC000); + + *dstp++ = (result_rb + result_g) >> 6; + } while(--w); + } + + void RenderABuffer8(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); + + do { + const uint8 px = *dstp; + const sint8 a = *alpha++; + + *dstp++ = px + (((sint32)(color - px) * a + 32) >> 6); + } while(--w); + } + + void RenderABuffer8_128(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); + + do { + const uint8 px = *dstp; + const sint16 a = *alpha++; + + *dstp++ = px + (((sint32)(color - px) * a + 64) >> 7); + } while(--w); + } + + void RenderABuffer8_256(const VDPixmap& dst, int y, const uint16 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); + + do { + const uint8 px = *dstp; + const sint32 a = *alpha++; + + *dstp++ = px + (((sint32)(color - px) * a + 128) >> 8); + } while(--w); + } + + void RenderABuffer8_1024(const VDPixmap& dst, int y, const uint16 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); + + do { + const uint8 px = *dstp; + const sint32 a = *alpha++; + + *dstp++ = px + (((sint32)(color - px) * a + 512) >> 10); + } while(--w); + } +} + +bool VDPixmapFillRegionAntialiased_32x_32x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { + if (dst.format != nsVDPixmap::kPixFormat_Y8) + return false; + + // fast out + if (region.mSpans.empty()) + return true; + + // check if vertical clipping is required + const size_t n = region.mSpans.size(); + uint32 start = 0; + uint32 end = n; + + uint32 spanmin = -x + (-y << 16) + 0x80008000; + + if (region.mSpans.front() < spanmin) { + // find first span : x2 > spanmin + start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); + start &= ~1; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w*32 - x) + (((dst.h*32 - y) - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // find last span : x1 < spanlimit + end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); + + end = (end + 1) & ~1; + + // check for total bottom clip + if (start >= end) + return true; + } + + // allocate A-buffer + vdfastvector abuffer(dst.w, 0); + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + + sint32 dstw32 = dst.w * 32; + sint32 dsth32 = dst.h * 32; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + sint32 py = (span0 >> 16) - 0x8000 + y; + + if ((uint32)py >= (uint32)dsth32) + continue; + + sint32 px1 = (span0 & 0xffff) - 0x8000 + x; + sint32 px2 = (span1 & 0xffff) - 0x8000 + x; + sint32 w = span1-span0; + + if (lasty != py) { + if (((lasty ^ py) & 0xFFFFFFE0)) { + if (lasty >= 0) { + // flush scanline + + RenderABuffer8_1024(dst, lasty >> 5, abuffer.data(), dst.w, color); + } + + memset(abuffer.data(), 0, abuffer.size() * sizeof(abuffer[0])); + } + lasty = py; + } + + if (px1 < 0) + px1 = 0; + if (px2 > dstw32) + px2 = dstw32; + + if (px1 >= px2) + continue; + + uint32 ix1 = px1 >> 5; + uint32 ix2 = px2 >> 5; + uint16 *p1 = abuffer.data() + ix1; + uint16 *p2 = abuffer.data() + ix2; + + if (p1 == p2) { + p1[0] += (px2 - px1); + } else { + if (px1 & 31) { + p1[0] += 32 - (px1 & 31); + ++p1; + } + + while(p1 != p2) { + p1[0] += 32; + ++p1; + } + + if (px2 & 31) + p1[0] += px2 & 32; + } + } + + if (lasty >= 0) + RenderABuffer8_1024(dst, lasty >> 5, abuffer.data(), dst.w, color); + + return true; +} + +bool VDPixmapFillRegionAntialiased_16x_16x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { + if (dst.format != nsVDPixmap::kPixFormat_Y8) + return false; + + // fast out + if (region.mSpans.empty()) + return true; + + // check if vertical clipping is required + const size_t n = region.mSpans.size(); + uint32 start = 0; + uint32 end = n; + + uint32 spanmin = -x + (-y << 16) + 0x80008000; + + if (region.mSpans.front() < spanmin) { + // find first span : x2 > spanmin + start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); + start &= ~1; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w*16 - x) + (((dst.h*16 - y) - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // find last span : x1 < spanlimit + end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); + + end = (end + 1) & ~1; + + // check for total bottom clip + if (start >= end) + return true; + } + + // allocate A-buffer + vdfastvector abuffer(dst.w, 0); + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + + sint32 dstw16 = dst.w * 16; + sint32 dsth16 = dst.h * 16; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + sint32 py = (span0 >> 16) - 0x8000 + y; + + if ((uint32)py >= (uint32)dsth16) + continue; + + sint32 px1 = (span0 & 0xffff) - 0x8000 + x; + sint32 px2 = (span1 & 0xffff) - 0x8000 + x; + sint32 w = span1-span0; + + if (lasty != py) { + if (((lasty ^ py) & 0xFFFFFFF0)) { + if (lasty >= 0) { + // flush scanline + + RenderABuffer8_256(dst, lasty >> 4, abuffer.data(), dst.w, color); + } + + memset(abuffer.data(), 0, abuffer.size() * sizeof(abuffer[0])); + } + lasty = py; + } + + if (px1 < 0) + px1 = 0; + if (px2 > dstw16) + px2 = dstw16; + + if (px1 >= px2) + continue; + + uint32 ix1 = px1 >> 4; + uint32 ix2 = px2 >> 4; + uint16 *p1 = abuffer.data() + ix1; + uint16 *p2 = abuffer.data() + ix2; + + if (p1 == p2) { + p1[0] += (px2 - px1); + } else { + if (px1 & 15) { + p1[0] += 16 - (px1 & 15); + ++p1; + } + + while(p1 != p2) { + p1[0] += 16; + ++p1; + } + + if (px2 & 15) + p1[0] += px2 & 15; + } + } + + if (lasty >= 0) + RenderABuffer8_256(dst, lasty >> 4, abuffer.data(), dst.w, color); + + return true; +} + +bool VDPixmapFillRegionAntialiased_16x_8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { + if (dst.format != nsVDPixmap::kPixFormat_XRGB8888 && dst.format != nsVDPixmap::kPixFormat_Y8) + return false; + + // fast out + if (region.mSpans.empty()) + return true; + + // check if vertical clipping is required + const size_t n = region.mSpans.size(); + uint32 start = 0; + uint32 end = n; + + uint32 spanmin = -x + (-y << 16) + 0x80008000; + + if (region.mSpans.front() < spanmin) { + // find first span : x2 > spanmin + start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); + start &= ~1; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w*16 - x) + (((dst.h*8 - y) - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // find last span : x1 < spanlimit + end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); + + end = (end + 1) & ~1; + + // check for total bottom clip + if (start >= end) + return true; + } + + // allocate A-buffer + vdfastvector abuffer(dst.w, 0); + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + + sint32 dstw16 = dst.w * 16; + sint32 dsth8 = dst.h * 8; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + sint32 py = (span0 >> 16) - 0x8000 + y; + + if ((uint32)py >= (uint32)dsth8) + continue; + + sint32 px1 = (span0 & 0xffff) - 0x8000 + x; + sint32 px2 = (span1 & 0xffff) - 0x8000 + x; + sint32 w = span1-span0; + + if (lasty != py) { + if (((lasty ^ py) & 0xFFFFFFF8)) { + if (lasty >= 0) { + // flush scanline + + RenderABuffer8_128(dst, lasty >> 3, abuffer.data(), dst.w, color); + } + + memset(abuffer.data(), 0, abuffer.size()); + } + lasty = py; + } + + if (px1 < 0) + px1 = 0; + if (px2 > dstw16) + px2 = dstw16; + + if (px1 >= px2) + continue; + + uint32 ix1 = px1 >> 4; + uint32 ix2 = px2 >> 4; + uint8 *p1 = abuffer.data() + ix1; + uint8 *p2 = abuffer.data() + ix2; + + if (p1 == p2) { + p1[0] += (px2 - px1); + } else { + if (px1 & 15) { + p1[0] += 16 - (px1 & 15); + ++p1; + } + + while(p1 != p2) { + p1[0] += 16; + ++p1; + } + + if (px2 & 15) + p1[0] += px2 & 15; + } + } + + if (lasty >= 0) + RenderABuffer8_128(dst, lasty >> 3, abuffer.data(), dst.w, color); + + return true; +} + +bool VDPixmapFillRegionAntialiased8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { + switch(dst.format) { + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + { + VDPixmap pxY; + VDPixmap pxCb; + VDPixmap pxCr; + + pxY.format = nsVDPixmap::kPixFormat_Y8; + pxY.data = dst.data; + pxY.pitch = dst.pitch; + pxY.w = dst.w; + pxY.h = dst.h; + + pxCb.format = nsVDPixmap::kPixFormat_Y8; + pxCb.data = dst.data2; + pxCb.pitch = dst.pitch2; + pxCb.w = dst.w; + pxCb.h = dst.h; + + pxCr.format = nsVDPixmap::kPixFormat_Y8; + pxCr.data = dst.data3; + pxCr.pitch = dst.pitch3; + pxCr.w = dst.w; + pxCr.h = dst.h; + + uint32 colorY = (color >> 8) & 0xff; + uint32 colorCb = (color >> 0) & 0xff; + uint32 colorCr = (color >> 16) & 0xff; + + VDPixmapFillRegionAntialiased8x(pxY, region, x, y, colorY); + + switch(dst.format) { + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 2; + pxCr.h = pxCb.h = dst.h >> 2; + x >>= 2; + y >>= 2; + VDPixmapFillRegionAntialiased_32x_32x(pxCb, region, x, y, colorCb); + VDPixmapFillRegionAntialiased_32x_32x(pxCr, region, x, y, colorCr); + return true; + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 1; + pxCr.h = pxCb.h = dst.h >> 1; + x >>= 1; + y >>= 1; + x += 2; + VDPixmapFillRegionAntialiased_16x_16x(pxCb, region, x, y, colorCb); + VDPixmapFillRegionAntialiased_16x_16x(pxCr, region, x, y, colorCr); + return true; + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 1; + x >>= 1; + x += 2; + VDPixmapFillRegionAntialiased_16x_8x(pxCb, region, x, y, colorCb); + VDPixmapFillRegionAntialiased_16x_8x(pxCr, region, x, y, colorCr); + return true; + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + VDPixmapFillRegionAntialiased8x(pxCb, region, x, y, colorCb); + VDPixmapFillRegionAntialiased8x(pxCr, region, x, y, colorCr); + return true; + } + } + } + + if (dst.format != nsVDPixmap::kPixFormat_XRGB8888 && dst.format != nsVDPixmap::kPixFormat_Y8) + return false; + + // fast out + if (region.mSpans.empty()) + return true; + + // check if vertical clipping is required + const size_t n = region.mSpans.size(); + uint32 start = 0; + uint32 end = n; + + uint32 spanmin = -x + (-y << 16) + 0x80008000; + + if (region.mSpans.front() < spanmin) { + // find first span : x2 > spanmin + start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); + start &= ~1; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w*8 - x) + (((dst.h*8 - y) - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // find last span : x1 < spanlimit + end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); + + end = (end + 1) & ~1; + + // check for total bottom clip + if (start >= end) + return true; + } + + // allocate A-buffer + vdfastvector abuffer(dst.w, 0); + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + + sint32 dstw8 = dst.w * 8; + sint32 dsth8 = dst.h * 8; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + sint32 py = (span0 >> 16) - 0x8000 + y; + + if ((uint32)py >= (uint32)dsth8) + continue; + + sint32 px1 = (span0 & 0xffff) - 0x8000 + x; + sint32 px2 = (span1 & 0xffff) - 0x8000 + x; + sint32 w = span1-span0; + + if (lasty != py) { + if (((lasty ^ py) & 0xFFFFFFF8)) { + if (lasty >= 0) { + // flush scanline + + if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) + RenderABuffer32(dst, lasty >> 3, abuffer.data(), dst.w, color); + else + RenderABuffer8(dst, lasty >> 3, abuffer.data(), dst.w, color); + } + + memset(abuffer.data(), 0, abuffer.size()); + } + lasty = py; + } + + if (px1 < 0) + px1 = 0; + if (px2 > dstw8) + px2 = dstw8; + + if (px1 >= px2) + continue; + + uint32 ix1 = px1 >> 3; + uint32 ix2 = px2 >> 3; + uint8 *p1 = abuffer.data() + ix1; + uint8 *p2 = abuffer.data() + ix2; + + if (p1 == p2) { + p1[0] += (px2 - px1); + } else { + if (px1 & 7) { + p1[0] += 8 - (px1 & 7); + ++p1; + } + + while(p1 != p2) { + p1[0] += 8; + ++p1; + } + + if (px2 & 7) + p1[0] += px2 & 7; + } + } + + if (lasty >= 0) { + if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) + RenderABuffer32(dst, lasty >> 3, abuffer.data(), dst.w, color); + else + RenderABuffer8(dst, lasty >> 3, abuffer.data(), dst.w, color); + } + + return true; +} + +void VDPixmapCreateRoundRegion(VDPixmapRegion& dst, float r) { + int ir = VDCeilToInt(r); + float r2 = r*r; + + dst.mSpans.clear(); + dst.mBounds.set(-ir, 0, ir+1, 0); + + for(int y = -ir; y <= ir; ++y) { + int dx = VDCeilToInt(sqrtf(r2 - y*y)); + + if (dx > 0) { + dst.mSpans.push_back(0x80008000 + (y << 16) - dx); + dst.mSpans.push_back(0x80008001 + (y << 16) + dx); + if (dst.mBounds.top > y) + dst.mBounds.top = y; + if (dst.mBounds.bottom < y) + dst.mBounds.bottom = y; + } + } +} + +void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, int dx1, int dx2, int dy) { + dst.mSpans.clear(); + dst.mSpans.resize(r1.mSpans.size()+r2.mSpans.size()); + + const uint32 *itA = r1.mSpans.data(); + const uint32 *itAE = itA + r1.mSpans.size(); + const uint32 *itB = r2.mSpans.data(); + const uint32 *itBE = itB + r2.mSpans.size(); + uint32 *dstp0 = dst.mSpans.data(); + uint32 *dstp = dst.mSpans.data(); + + uint32 offset1 = (dy<<16) + dx1; + uint32 offset2 = (dy<<16) + dx2; + + while(itA != itAE && itB != itBE) { + uint32 x1; + uint32 x2; + + if (itB[0] + offset1 < itA[0]) { + // B span is earlier. Use it. + x1 = itB[0] + offset1; + x2 = itB[1] + offset2; + itB += 2; + + // B spans *can* overlap, due to the widening. + while(itB != itBE && itB[0]+offset1 <= x2) { + uint32 bx2 = itB[1] + offset2; + if (x2 < bx2) + x2 = bx2; + + itB += 2; + } + + goto a_start; + } else { + // A span is earlier. Use it. + x1 = itA[0]; + x2 = itA[1]; + itA += 2; + + // A spans don't overlap, so begin merge loop with B first. + } + + for(;;) { + // If we run out of B spans or the B span doesn't overlap, + // then the next A span can't either (because A spans don't + // overlap) and we exit. + + if (itB == itBE || itB[0]+offset1 > x2) + break; + + do { + uint32 bx2 = itB[1] + offset2; + if (x2 < bx2) + x2 = bx2; + + itB += 2; + } while(itB != itBE && itB[0]+offset1 <= x2); + + // If we run out of A spans or the A span doesn't overlap, + // then the next B span can't either, because we would have + // consumed all overlapping B spans in the above loop. +a_start: + if (itA == itAE || itA[0] > x2) + break; + + do { + uint32 ax2 = itA[1]; + if (x2 < ax2) + x2 = ax2; + + itA += 2; + } while(itA != itAE && itA[0] <= x2); + } + + // Flush span. + dstp[0] = x1; + dstp[1] = x2; + dstp += 2; + } + + // Copy over leftover spans. + memcpy(dstp, itA, sizeof(uint32)*(itAE - itA)); + dstp += itAE - itA; + + while(itB != itBE) { + // B span is earlier. Use it. + uint32 x1 = itB[0] + offset1; + uint32 x2 = itB[1] + offset2; + itB += 2; + + // B spans *can* overlap, due to the widening. + while(itB != itBE && itB[0]+offset1 <= x2) { + uint32 bx2 = itB[1] + offset2; + if (x2 < bx2) + x2 = bx2; + + itB += 2; + } + + dstp[0] = x1; + dstp[1] = x2; + dstp += 2; + } + + dst.mSpans.resize(dstp - dst.mSpans.data()); +} + +void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, VDPixmapRegion *tempCache) { + VDPixmapRegion temp; + + if (tempCache) { + tempCache->swap(temp); + + temp.clear(); + } + + const uint32 *src1 = r2.mSpans.data(); + const uint32 *src2 = src1 + r2.mSpans.size(); + + dst.mSpans.clear(); + while(src1 != src2) { + uint32 p1 = src1[0]; + uint32 p2 = src1[1]; + src1 += 2; + + temp.mSpans.swap(dst.mSpans); + VDPixmapConvolveRegion(dst, temp, r1, (p1 & 0xffff) - 0x8000, (p2 & 0xffff) - 0x8000, (p1 >> 16) - 0x8000); + } + + if (tempCache) + tempCache->swap(temp); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/resample.cpp b/src/thirdparty/VirtualDub/Kasumi/source/resample.cpp index 8a57be9e3a2..e4705517e4c 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/resample.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/resample.cpp @@ -1,416 +1,416 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "uberblit_gen.h" - -/////////////////////////////////////////////////////////////////////////// -// -// the resampler (finally) -// -/////////////////////////////////////////////////////////////////////////// - -class VDPixmapResampler : public IVDPixmapResampler { -public: - VDPixmapResampler(); - ~VDPixmapResampler(); - - void SetSplineFactor(double A) { mSplineFactor = A; } - void SetFilters(FilterMode h, FilterMode v, bool interpolationOnly); - bool Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat); - bool Init(const vdrect32f& dstrect, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect, uint32 sw, uint32 sh, int srcformat); - void Shutdown(); - - void Process(const VDPixmap& dst, const VDPixmap& src); - -protected: - void ApplyFilters(VDPixmapUberBlitterGenerator& gen, uint32 dw, uint32 dh, float xoffset, float yoffset, float xfactor, float yfactor); - - vdautoptr mpBlitter; - vdautoptr mpBlitter2; - double mSplineFactor; - FilterMode mFilterH; - FilterMode mFilterV; - bool mbInterpOnly; - - vdrect32 mDstRectPlane0; - vdrect32 mDstRectPlane12; -}; - -IVDPixmapResampler *VDCreatePixmapResampler() { return new VDPixmapResampler; } - -VDPixmapResampler::VDPixmapResampler() - : mSplineFactor(-0.6) - , mFilterH(kFilterCubic) - , mFilterV(kFilterCubic) - , mbInterpOnly(false) -{ -} - -VDPixmapResampler::~VDPixmapResampler() { - Shutdown(); -} - -void VDPixmapResampler::SetFilters(FilterMode h, FilterMode v, bool interpolationOnly) { - mFilterH = h; - mFilterV = v; - mbInterpOnly = interpolationOnly; -} - -bool VDPixmapResampler::Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat) { - vdrect32f rSrc(0.0f, 0.0f, (float)sw, (float)sh); - vdrect32f rDst(0.0f, 0.0f, (float)dw, (float)dh); - return Init(rDst, dw, dh, dstformat, rSrc, sw, sh, srcformat); -} - -bool VDPixmapResampler::Init(const vdrect32f& dstrect0, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect0, uint32 sw, uint32 sh, int srcformat) { - Shutdown(); - - if (dstformat != srcformat) - return false; - - switch(srcformat) { - case nsVDPixmap::kPixFormat_XRGB8888: - case nsVDPixmap::kPixFormat_Y8: - case nsVDPixmap::kPixFormat_Y8_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar: - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - break; - - default: - return false; - } - - // convert destination flips to source flips - vdrect32f dstrect(dstrect0); - vdrect32f srcrect(srcrect0); - - if (dstrect.left > dstrect.right) { - std::swap(dstrect.left, dstrect.right); - std::swap(srcrect.left, srcrect.right); - } - - if (dstrect.top > dstrect.bottom) { - std::swap(dstrect.top, dstrect.bottom); - std::swap(srcrect.top, srcrect.bottom); - } - - // compute source step factors - float xfactor = (float)srcrect.width() / (float)dstrect.width(); - float yfactor = (float)srcrect.height() / (float)dstrect.height(); - - // clip destination rect - if (dstrect.left < 0) { - float clipx1 = -dstrect.left; - srcrect.left += xfactor * clipx1; - dstrect.left = 0.0f; - } - - if (dstrect.top < 0) { - float clipy1 = -dstrect.top; - srcrect.top += yfactor * clipy1; - dstrect.top = 0.0f; - } - - float clipx2 = dstrect.right - (float)dw; - if (clipx2 > 0) { - srcrect.right -= xfactor * clipx2; - dstrect.right = (float)dw; - } - - float clipy2 = dstrect.bottom - (float)dh; - if (clipy2 > 0) { - srcrect.bottom -= yfactor * clipy2; - dstrect.bottom = (float)dh; - } - - // compute plane 0 dest rect in integral quanta - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dstformat); - mDstRectPlane0.left = VDCeilToInt(dstrect.left - 0.5f); - mDstRectPlane0.top = VDCeilToInt(dstrect.top - 0.5f); - mDstRectPlane0.right = VDCeilToInt(dstrect.right - 0.5f); - mDstRectPlane0.bottom = VDCeilToInt(dstrect.bottom - 0.5f); - - // compute plane 0 stepping parameters - float xoffset = (((float)mDstRectPlane0.left + 0.5f) - dstrect.left) * xfactor + srcrect.left; - float yoffset = (((float)mDstRectPlane0.top + 0.5f) - dstrect.top ) * yfactor + srcrect.top; - - // compute plane 1/2 dest rect and stepping parameters - float xoffset2 = 0.0f; - float yoffset2 = 0.0f; - - if (formatInfo.auxbufs > 0) { - float xf2 = (float)(1 << formatInfo.auxwbits); - float yf2 = (float)(1 << formatInfo.auxhbits); - float invxf2 = 1.0f / xf2; - float invyf2 = 1.0f / yf2; - - // convert source and dest rects to plane 1/2 space - vdrect32f srcrect2(srcrect); - vdrect32f dstrect2(dstrect); - - srcrect2.scale(invxf2, invyf2); - dstrect2.scale(invxf2, invyf2); - - switch(srcformat) { - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - break; - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - srcrect2.translate(0.25f, 0.0f); - dstrect2.translate(0.25f, 0.0f); - break; - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - srcrect2.translate(0.25f, 0.0f); - dstrect2.translate(0.25f, 0.0f); - break; - case nsVDPixmap::kPixFormat_YUV411_Planar: - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - srcrect2.translate(0.375f, 0.0f); - dstrect2.translate(0.375f, 0.0f); - break; - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - break; - default: - VDASSERT(false); - } - - mDstRectPlane12.left = VDCeilToInt(dstrect2.left - 0.5f); - mDstRectPlane12.top = VDCeilToInt(dstrect2.top - 0.5f); - mDstRectPlane12.right = VDCeilToInt(dstrect2.right - 0.5f); - mDstRectPlane12.bottom = VDCeilToInt(dstrect2.bottom - 0.5f); - - xoffset2 = (((float)mDstRectPlane12.left + 0.5f) - dstrect2.left) * xfactor + srcrect2.left; - yoffset2 = (((float)mDstRectPlane12.top + 0.5f) - dstrect2.top ) * yfactor + srcrect2.top; - } - - VDPixmapUberBlitterGenerator gen; - - switch(srcformat) { - case nsVDPixmap::kPixFormat_XRGB8888: - gen.ldsrc(0, 0, 0, 0, sw, sh, VDPixmapGetFormatTokenFromFormat(srcformat), sw*4); - ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); - break; - - case nsVDPixmap::kPixFormat_Y8: - gen.ldsrc(0, 0, 0, 0, sw, sh, kVDPixType_8, sw); - ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); - break; - - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV411_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - gen.ldsrc(0, 0, 0, 0, sw, sh, kVDPixType_8, sw); - ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); - - { - const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstformat); - uint32 subsw = -(-(sint32)sw >> info.auxwbits); - uint32 subsh = -(-(sint32)sh >> info.auxhbits); - - VDPixmapUberBlitterGenerator gen2; - gen2.ldsrc(0, 0, 0, 0, subsw, subsh, kVDPixType_8, subsw); - ApplyFilters(gen2, mDstRectPlane12.width(), mDstRectPlane12.height(), xoffset2, yoffset2, xfactor, yfactor); - mpBlitter2 = gen2.create(); - if (!mpBlitter2) - return false; - } - break; - } - - mpBlitter = gen.create(); - if (!mpBlitter) - return false; - - return true; -} - -void VDPixmapResampler::Shutdown() { - mpBlitter = NULL; - mpBlitter2 = NULL; -} - -void VDPixmapResampler::Process(const VDPixmap& dst, const VDPixmap& src) { - if (!mpBlitter) - return; - - switch(dst.format) { - case nsVDPixmap::kPixFormat_XRGB8888: - case nsVDPixmap::kPixFormat_Y8: - mpBlitter->Blit(dst, &mDstRectPlane0, src); - break; - - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV411_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - // blit primary plane - mpBlitter->Blit(dst, &mDstRectPlane0, src); - - // slice and blit secondary planes - { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); - VDPixmap pxdst; - pxdst.format = nsVDPixmap::kPixFormat_Y8; - pxdst.w = -(-dst.w >> formatInfo.auxwbits); - pxdst.h = -(-dst.h >> formatInfo.auxhbits); - pxdst.pitch = dst.pitch2; - pxdst.data = dst.data2; - - VDPixmap pxsrc; - pxsrc.format = nsVDPixmap::kPixFormat_Y8; - pxsrc.w = -(-src.w >> formatInfo.auxwbits); - pxsrc.h = -(-src.h >> formatInfo.auxhbits); - pxsrc.pitch = src.pitch2; - pxsrc.data = src.data2; - - mpBlitter2->Blit(pxdst, &mDstRectPlane12, pxsrc); - - pxdst.pitch = dst.pitch3; - pxdst.data = dst.data3; - pxsrc.pitch = src.pitch3; - pxsrc.data = src.data3; - mpBlitter2->Blit(pxdst, &mDstRectPlane12, pxsrc); - } - break; - } -} - -void VDPixmapResampler::ApplyFilters(VDPixmapUberBlitterGenerator& gen, uint32 dw, uint32 dh, float xoffset, float yoffset, float xfactor, float yfactor) { - switch(mFilterH) { - case kFilterPoint: - gen.pointh(xoffset, xfactor, dw); - break; - - case kFilterLinear: - gen.linearh(xoffset, xfactor, dw, mbInterpOnly); - break; - - case kFilterCubic: - gen.cubich(xoffset, xfactor, dw, (float)mSplineFactor, mbInterpOnly); - break; - - case kFilterLanczos3: - gen.lanczos3h(xoffset, xfactor, dw); - break; - } - - switch(mFilterV) { - case kFilterPoint: - gen.pointv(yoffset, yfactor, dh); - break; - - case kFilterLinear: - gen.linearv(yoffset, yfactor, dh, mbInterpOnly); - break; - - case kFilterCubic: - gen.cubicv(yoffset, yfactor, dh, (float)mSplineFactor, mbInterpOnly); - break; - - case kFilterLanczos3: - gen.lanczos3v(yoffset, yfactor, dh); - break; - } -} - -bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter) { - VDPixmapResampler r; - - r.SetFilters(filter, filter, false); - - if (!r.Init(dst.w, dst.h, dst.format, src.w, src.h, src.format)) - return false; - - r.Process(dst, src); - return true; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uberblit_gen.h" + +/////////////////////////////////////////////////////////////////////////// +// +// the resampler (finally) +// +/////////////////////////////////////////////////////////////////////////// + +class VDPixmapResampler : public IVDPixmapResampler { +public: + VDPixmapResampler(); + ~VDPixmapResampler(); + + void SetSplineFactor(double A) { mSplineFactor = A; } + void SetFilters(FilterMode h, FilterMode v, bool interpolationOnly); + bool Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat); + bool Init(const vdrect32f& dstrect, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect, uint32 sw, uint32 sh, int srcformat); + void Shutdown(); + + void Process(const VDPixmap& dst, const VDPixmap& src); + +protected: + void ApplyFilters(VDPixmapUberBlitterGenerator& gen, uint32 dw, uint32 dh, float xoffset, float yoffset, float xfactor, float yfactor); + + vdautoptr mpBlitter; + vdautoptr mpBlitter2; + double mSplineFactor; + FilterMode mFilterH; + FilterMode mFilterV; + bool mbInterpOnly; + + vdrect32 mDstRectPlane0; + vdrect32 mDstRectPlane12; +}; + +IVDPixmapResampler *VDCreatePixmapResampler() { return new VDPixmapResampler; } + +VDPixmapResampler::VDPixmapResampler() + : mSplineFactor(-0.6) + , mFilterH(kFilterCubic) + , mFilterV(kFilterCubic) + , mbInterpOnly(false) +{ +} + +VDPixmapResampler::~VDPixmapResampler() { + Shutdown(); +} + +void VDPixmapResampler::SetFilters(FilterMode h, FilterMode v, bool interpolationOnly) { + mFilterH = h; + mFilterV = v; + mbInterpOnly = interpolationOnly; +} + +bool VDPixmapResampler::Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat) { + vdrect32f rSrc(0.0f, 0.0f, (float)sw, (float)sh); + vdrect32f rDst(0.0f, 0.0f, (float)dw, (float)dh); + return Init(rDst, dw, dh, dstformat, rSrc, sw, sh, srcformat); +} + +bool VDPixmapResampler::Init(const vdrect32f& dstrect0, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect0, uint32 sw, uint32 sh, int srcformat) { + Shutdown(); + + if (dstformat != srcformat) + return false; + + switch(srcformat) { + case nsVDPixmap::kPixFormat_XRGB8888: + case nsVDPixmap::kPixFormat_Y8: + case nsVDPixmap::kPixFormat_Y8_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar: + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + break; + + default: + return false; + } + + // convert destination flips to source flips + vdrect32f dstrect(dstrect0); + vdrect32f srcrect(srcrect0); + + if (dstrect.left > dstrect.right) { + std::swap(dstrect.left, dstrect.right); + std::swap(srcrect.left, srcrect.right); + } + + if (dstrect.top > dstrect.bottom) { + std::swap(dstrect.top, dstrect.bottom); + std::swap(srcrect.top, srcrect.bottom); + } + + // compute source step factors + float xfactor = (float)srcrect.width() / (float)dstrect.width(); + float yfactor = (float)srcrect.height() / (float)dstrect.height(); + + // clip destination rect + if (dstrect.left < 0) { + float clipx1 = -dstrect.left; + srcrect.left += xfactor * clipx1; + dstrect.left = 0.0f; + } + + if (dstrect.top < 0) { + float clipy1 = -dstrect.top; + srcrect.top += yfactor * clipy1; + dstrect.top = 0.0f; + } + + float clipx2 = dstrect.right - (float)dw; + if (clipx2 > 0) { + srcrect.right -= xfactor * clipx2; + dstrect.right = (float)dw; + } + + float clipy2 = dstrect.bottom - (float)dh; + if (clipy2 > 0) { + srcrect.bottom -= yfactor * clipy2; + dstrect.bottom = (float)dh; + } + + // compute plane 0 dest rect in integral quanta + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dstformat); + mDstRectPlane0.left = VDCeilToInt(dstrect.left - 0.5f); + mDstRectPlane0.top = VDCeilToInt(dstrect.top - 0.5f); + mDstRectPlane0.right = VDCeilToInt(dstrect.right - 0.5f); + mDstRectPlane0.bottom = VDCeilToInt(dstrect.bottom - 0.5f); + + // compute plane 0 stepping parameters + float xoffset = (((float)mDstRectPlane0.left + 0.5f) - dstrect.left) * xfactor + srcrect.left; + float yoffset = (((float)mDstRectPlane0.top + 0.5f) - dstrect.top ) * yfactor + srcrect.top; + + // compute plane 1/2 dest rect and stepping parameters + float xoffset2 = 0.0f; + float yoffset2 = 0.0f; + + if (formatInfo.auxbufs > 0) { + float xf2 = (float)(1 << formatInfo.auxwbits); + float yf2 = (float)(1 << formatInfo.auxhbits); + float invxf2 = 1.0f / xf2; + float invyf2 = 1.0f / yf2; + + // convert source and dest rects to plane 1/2 space + vdrect32f srcrect2(srcrect); + vdrect32f dstrect2(dstrect); + + srcrect2.scale(invxf2, invyf2); + dstrect2.scale(invxf2, invyf2); + + switch(srcformat) { + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + break; + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + srcrect2.translate(0.25f, 0.0f); + dstrect2.translate(0.25f, 0.0f); + break; + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + srcrect2.translate(0.25f, 0.0f); + dstrect2.translate(0.25f, 0.0f); + break; + case nsVDPixmap::kPixFormat_YUV411_Planar: + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + srcrect2.translate(0.375f, 0.0f); + dstrect2.translate(0.375f, 0.0f); + break; + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + break; + default: + VDASSERT(false); + } + + mDstRectPlane12.left = VDCeilToInt(dstrect2.left - 0.5f); + mDstRectPlane12.top = VDCeilToInt(dstrect2.top - 0.5f); + mDstRectPlane12.right = VDCeilToInt(dstrect2.right - 0.5f); + mDstRectPlane12.bottom = VDCeilToInt(dstrect2.bottom - 0.5f); + + xoffset2 = (((float)mDstRectPlane12.left + 0.5f) - dstrect2.left) * xfactor + srcrect2.left; + yoffset2 = (((float)mDstRectPlane12.top + 0.5f) - dstrect2.top ) * yfactor + srcrect2.top; + } + + VDPixmapUberBlitterGenerator gen; + + switch(srcformat) { + case nsVDPixmap::kPixFormat_XRGB8888: + gen.ldsrc(0, 0, 0, 0, sw, sh, VDPixmapGetFormatTokenFromFormat(srcformat), sw*4); + ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); + break; + + case nsVDPixmap::kPixFormat_Y8: + gen.ldsrc(0, 0, 0, 0, sw, sh, kVDPixType_8, sw); + ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); + break; + + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV411_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + gen.ldsrc(0, 0, 0, 0, sw, sh, kVDPixType_8, sw); + ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); + + { + const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstformat); + uint32 subsw = -(-(sint32)sw >> info.auxwbits); + uint32 subsh = -(-(sint32)sh >> info.auxhbits); + + VDPixmapUberBlitterGenerator gen2; + gen2.ldsrc(0, 0, 0, 0, subsw, subsh, kVDPixType_8, subsw); + ApplyFilters(gen2, mDstRectPlane12.width(), mDstRectPlane12.height(), xoffset2, yoffset2, xfactor, yfactor); + mpBlitter2 = gen2.create(); + if (!mpBlitter2) + return false; + } + break; + } + + mpBlitter = gen.create(); + if (!mpBlitter) + return false; + + return true; +} + +void VDPixmapResampler::Shutdown() { + mpBlitter = NULL; + mpBlitter2 = NULL; +} + +void VDPixmapResampler::Process(const VDPixmap& dst, const VDPixmap& src) { + if (!mpBlitter) + return; + + switch(dst.format) { + case nsVDPixmap::kPixFormat_XRGB8888: + case nsVDPixmap::kPixFormat_Y8: + mpBlitter->Blit(dst, &mDstRectPlane0, src); + break; + + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV411_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + // blit primary plane + mpBlitter->Blit(dst, &mDstRectPlane0, src); + + // slice and blit secondary planes + { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); + VDPixmap pxdst; + pxdst.format = nsVDPixmap::kPixFormat_Y8; + pxdst.w = -(-dst.w >> formatInfo.auxwbits); + pxdst.h = -(-dst.h >> formatInfo.auxhbits); + pxdst.pitch = dst.pitch2; + pxdst.data = dst.data2; + + VDPixmap pxsrc; + pxsrc.format = nsVDPixmap::kPixFormat_Y8; + pxsrc.w = -(-src.w >> formatInfo.auxwbits); + pxsrc.h = -(-src.h >> formatInfo.auxhbits); + pxsrc.pitch = src.pitch2; + pxsrc.data = src.data2; + + mpBlitter2->Blit(pxdst, &mDstRectPlane12, pxsrc); + + pxdst.pitch = dst.pitch3; + pxdst.data = dst.data3; + pxsrc.pitch = src.pitch3; + pxsrc.data = src.data3; + mpBlitter2->Blit(pxdst, &mDstRectPlane12, pxsrc); + } + break; + } +} + +void VDPixmapResampler::ApplyFilters(VDPixmapUberBlitterGenerator& gen, uint32 dw, uint32 dh, float xoffset, float yoffset, float xfactor, float yfactor) { + switch(mFilterH) { + case kFilterPoint: + gen.pointh(xoffset, xfactor, dw); + break; + + case kFilterLinear: + gen.linearh(xoffset, xfactor, dw, mbInterpOnly); + break; + + case kFilterCubic: + gen.cubich(xoffset, xfactor, dw, (float)mSplineFactor, mbInterpOnly); + break; + + case kFilterLanczos3: + gen.lanczos3h(xoffset, xfactor, dw); + break; + } + + switch(mFilterV) { + case kFilterPoint: + gen.pointv(yoffset, yfactor, dh); + break; + + case kFilterLinear: + gen.linearv(yoffset, yfactor, dh, mbInterpOnly); + break; + + case kFilterCubic: + gen.cubicv(yoffset, yfactor, dh, (float)mSplineFactor, mbInterpOnly); + break; + + case kFilterLanczos3: + gen.lanczos3v(yoffset, yfactor, dh); + break; + } +} + +bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter) { + VDPixmapResampler r; + + r.SetFilters(filter, filter, false); + + if (!r.Init(dst.w, dst.h, dst.format, src.w, src.h, src.format)) + return false; + + r.Process(dst, src); + return true; +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/resample_kernels.cpp b/src/thirdparty/VirtualDub/Kasumi/source/resample_kernels.cpp index 86911b3256e..2307f703237 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/resample_kernels.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/resample_kernels.cpp @@ -1,292 +1,292 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// -// utility functions -// -/////////////////////////////////////////////////////////////////////////// - -namespace { - inline sint32 scale32x32_fp16(sint32 x, sint32 y) { - return (sint32)(((sint64)x * y + 0x8000) >> 16); - } - - inline double sinc(double x) { - return fabs(x) < 1e-9 ? 1.0 : sin(x) / x; - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDResamplerAxis -// -/////////////////////////////////////////////////////////////////////////// - -void VDResamplerAxis::Init(sint32 dudx) { - this->dudx = dudx; -} - -void VDResamplerAxis::Compute(sint32 count, sint32 u0, sint32 w, sint32 kernel_width) { - u = u0; - dx = count; - - sint32 du_kern = (kernel_width-1) << 16; - sint32 u2 = u + dudx*(dx-1); - sint32 u_limit = w << 16; - - dx_precopy = 0; - dx_preclip = 0; - dx_active = 0; - dx_postclip = 0; - dx_postcopy = 0; - dx_dualclip = 0; - - if (dudx == 0) { - if (u < -du_kern) - dx_precopy = w; - else if (u >= u_limit) - dx_postcopy = w; - else if (u < 0) { - if (u + du_kern < u_limit) - dx_preclip = w; - else - dx_dualclip = w; - } else if (u + du_kern >= u_limit) - dx_postclip = w; - else - dx_active = w; - - return; - } - - sint32 dx_temp = dx; - sint32 u_start = u; - - // (desired - u0 + (dudx-1)) / dudx : first pixel >= desired - - sint32 dudx_m1_mu0 = dudx - 1 - u; - sint32 first_preclip = (dudx_m1_mu0 + 0x10000 - du_kern) / dudx; - sint32 first_active = (dudx_m1_mu0 ) / dudx; - sint32 first_postclip = (dudx_m1_mu0 + u_limit - du_kern) / dudx; - sint32 first_postcopy = (dudx_m1_mu0 + u_limit - 0x10000) / dudx; - - // clamp - if (first_preclip < 0) - first_preclip = 0; - if (first_active < first_preclip) - first_active = first_preclip; - if (first_postclip < first_active) - first_postclip = first_active; - if (first_postcopy < first_postclip) - first_postcopy = first_postclip; - if (first_preclip > dx) - first_preclip = dx; - if (first_active > dx) - first_active = dx; - if (first_postclip > dx) - first_postclip = dx; - if (first_postcopy > dx) - first_postcopy = dx; - - // determine widths - - dx_precopy = first_preclip; - dx_preclip = first_active - first_preclip; - dx_active = first_postclip - first_active; - dx_postclip = first_postcopy - first_postclip; - dx_postcopy = dx - first_postcopy; - - // sanity checks - sint32 pos0 = dx_precopy; - sint32 pos1 = pos0 + dx_preclip; - sint32 pos2 = pos1 + dx_active; - sint32 pos3 = pos2 + dx_postclip; - - VDASSERT(!((dx_precopy|dx_preclip|dx_active|dx_postcopy|dx_postclip) & 0x80000000)); - VDASSERT(dx_precopy + dx_preclip + dx_active + dx_postcopy + dx_postclip == dx); - - VDASSERT(!pos0 || u_start + dudx*(pos0 - 1) < 0x10000 - du_kern); // precopy -> preclip - VDASSERT( pos0 >= pos1 || u_start + dudx*(pos0 ) >= 0x10000 - du_kern); - VDASSERT( pos1 <= pos0 || u_start + dudx*(pos1 - 1) < 0); // preclip -> active - VDASSERT( pos1 >= pos2 || u_start + dudx*(pos1 ) >= 0 || !dx_active); - VDASSERT( pos2 <= pos1 || u_start + dudx*(pos2 - 1) < u_limit - du_kern || !dx_active); // active -> postclip - VDASSERT( pos2 >= pos3 || u_start + dudx*(pos2 ) >= u_limit - du_kern); - VDASSERT( pos3 <= pos2 || u_start + dudx*(pos3 - 1) < u_limit - 0x10000); // postclip -> postcopy - VDASSERT( pos3 >= dx || u_start + dudx*(pos3 ) >= u_limit - 0x10000); - - u += dx_precopy * dudx; - - // test for overlapping clipping regions - if (!dx_active && kernel_width > w) { - dx_dualclip = dx_preclip + dx_postclip; - dx_preclip = dx_postclip = 0; - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDResamplerLinearFilter -// -/////////////////////////////////////////////////////////////////////////// - -VDResamplerLinearFilter::VDResamplerLinearFilter(double twofc) - : mScale(twofc) - , mTaps((int)ceil(1.0 / twofc) * 2) -{ -} - -int VDResamplerLinearFilter::GetFilterWidth() const { - return mTaps; -} - -double VDResamplerLinearFilter::EvaluateFilter(double t) const { - t = 1.0f - fabs(t)*mScale; - - return t + fabs(t); -} - -void VDResamplerLinearFilter::GenerateFilter(float *dst, double offset) const { - double pos = -((double)((mTaps>>1)-1) + offset) * mScale; - - for(unsigned i=0; i>1)-1) + offset) * mScale; - - for(unsigned i=0; i>1)-1) + offset) * mScale); - - for(unsigned i=0; i +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// +// utility functions +// +/////////////////////////////////////////////////////////////////////////// + +namespace { + inline sint32 scale32x32_fp16(sint32 x, sint32 y) { + return (sint32)(((sint64)x * y + 0x8000) >> 16); + } + + inline double sinc(double x) { + return fabs(x) < 1e-9 ? 1.0 : sin(x) / x; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDResamplerAxis +// +/////////////////////////////////////////////////////////////////////////// + +void VDResamplerAxis::Init(sint32 dudx) { + this->dudx = dudx; +} + +void VDResamplerAxis::Compute(sint32 count, sint32 u0, sint32 w, sint32 kernel_width) { + u = u0; + dx = count; + + sint32 du_kern = (kernel_width-1) << 16; + sint32 u2 = u + dudx*(dx-1); + sint32 u_limit = w << 16; + + dx_precopy = 0; + dx_preclip = 0; + dx_active = 0; + dx_postclip = 0; + dx_postcopy = 0; + dx_dualclip = 0; + + if (dudx == 0) { + if (u < -du_kern) + dx_precopy = w; + else if (u >= u_limit) + dx_postcopy = w; + else if (u < 0) { + if (u + du_kern < u_limit) + dx_preclip = w; + else + dx_dualclip = w; + } else if (u + du_kern >= u_limit) + dx_postclip = w; + else + dx_active = w; + + return; + } + + sint32 dx_temp = dx; + sint32 u_start = u; + + // (desired - u0 + (dudx-1)) / dudx : first pixel >= desired + + sint32 dudx_m1_mu0 = dudx - 1 - u; + sint32 first_preclip = (dudx_m1_mu0 + 0x10000 - du_kern) / dudx; + sint32 first_active = (dudx_m1_mu0 ) / dudx; + sint32 first_postclip = (dudx_m1_mu0 + u_limit - du_kern) / dudx; + sint32 first_postcopy = (dudx_m1_mu0 + u_limit - 0x10000) / dudx; + + // clamp + if (first_preclip < 0) + first_preclip = 0; + if (first_active < first_preclip) + first_active = first_preclip; + if (first_postclip < first_active) + first_postclip = first_active; + if (first_postcopy < first_postclip) + first_postcopy = first_postclip; + if (first_preclip > dx) + first_preclip = dx; + if (first_active > dx) + first_active = dx; + if (first_postclip > dx) + first_postclip = dx; + if (first_postcopy > dx) + first_postcopy = dx; + + // determine widths + + dx_precopy = first_preclip; + dx_preclip = first_active - first_preclip; + dx_active = first_postclip - first_active; + dx_postclip = first_postcopy - first_postclip; + dx_postcopy = dx - first_postcopy; + + // sanity checks + sint32 pos0 = dx_precopy; + sint32 pos1 = pos0 + dx_preclip; + sint32 pos2 = pos1 + dx_active; + sint32 pos3 = pos2 + dx_postclip; + + VDASSERT(!((dx_precopy|dx_preclip|dx_active|dx_postcopy|dx_postclip) & 0x80000000)); + VDASSERT(dx_precopy + dx_preclip + dx_active + dx_postcopy + dx_postclip == dx); + + VDASSERT(!pos0 || u_start + dudx*(pos0 - 1) < 0x10000 - du_kern); // precopy -> preclip + VDASSERT( pos0 >= pos1 || u_start + dudx*(pos0 ) >= 0x10000 - du_kern); + VDASSERT( pos1 <= pos0 || u_start + dudx*(pos1 - 1) < 0); // preclip -> active + VDASSERT( pos1 >= pos2 || u_start + dudx*(pos1 ) >= 0 || !dx_active); + VDASSERT( pos2 <= pos1 || u_start + dudx*(pos2 - 1) < u_limit - du_kern || !dx_active); // active -> postclip + VDASSERT( pos2 >= pos3 || u_start + dudx*(pos2 ) >= u_limit - du_kern); + VDASSERT( pos3 <= pos2 || u_start + dudx*(pos3 - 1) < u_limit - 0x10000); // postclip -> postcopy + VDASSERT( pos3 >= dx || u_start + dudx*(pos3 ) >= u_limit - 0x10000); + + u += dx_precopy * dudx; + + // test for overlapping clipping regions + if (!dx_active && kernel_width > w) { + dx_dualclip = dx_preclip + dx_postclip; + dx_preclip = dx_postclip = 0; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDResamplerLinearFilter +// +/////////////////////////////////////////////////////////////////////////// + +VDResamplerLinearFilter::VDResamplerLinearFilter(double twofc) + : mScale(twofc) + , mTaps((int)ceil(1.0 / twofc) * 2) +{ +} + +int VDResamplerLinearFilter::GetFilterWidth() const { + return mTaps; +} + +double VDResamplerLinearFilter::EvaluateFilter(double t) const { + t = 1.0f - fabs(t)*mScale; + + return t + fabs(t); +} + +void VDResamplerLinearFilter::GenerateFilter(float *dst, double offset) const { + double pos = -((double)((mTaps>>1)-1) + offset) * mScale; + + for(unsigned i=0; i>1)-1) + offset) * mScale; + + for(unsigned i=0; i>1)-1) + offset) * mScale); + + for(unsigned i=0; i -#include -#include -#include -#include "resample_stages.h" - -VDSteppedAllocator::VDSteppedAllocator(size_t initialSize) - : mpHead(NULL) - , mpAllocNext(NULL) - , mAllocLeft(0) - , mAllocNext(initialSize) - , mAllocInit(initialSize) -{ -} - -VDSteppedAllocator::~VDSteppedAllocator() { - clear(); -} - -void VDSteppedAllocator::clear() { - while(Block *p = mpHead) { - mpHead = mpHead->next; - free(p); - } - mAllocLeft = 0; - mAllocNext = mAllocInit; -} - -void *VDSteppedAllocator::allocate(size_type n) { - n = (n+15) & ~15; - if (mAllocLeft < n) { - mAllocLeft = mAllocNext; - mAllocNext += (mAllocNext >> 1); - if (mAllocLeft < n) - mAllocLeft = n; - - Block *t = (Block *)malloc(sizeof(Block) + mAllocLeft); - - if (mpHead) - mpHead->next = t; - - mpHead = t; - mpHead->next = NULL; - - mpAllocNext = (char *)(mpHead + 1); - } - - void *p = mpAllocNext; - mpAllocNext += n; - mAllocLeft -= n; - return p; -} - -void VDResamplerGenerateTable(sint32 *dst, const IVDResamplerFilter& filter) { - const unsigned width = filter.GetFilterWidth(); - vdblock filters(width * 256); - float *src = filters.data(); - - filter.GenerateFilterBank(src); - - for(unsigned phase=0; phase < 256; ++phase) { - float sum = 0; - - for(unsigned i=0; i filters(width); - float *src = filters.data(); - - filter.GenerateFilterBank(src); - - for(sint32 i=0; i> 16; - filter.GenerateFilter(src, (double)(u & 0xffff) / 65536.0); - - float sum = 0; - for(uint32 j=0; j> 31) - 1; - while(ierr) { - for(uint32 j=0; j +#include +#include +#include +#include "resample_stages.h" + +VDSteppedAllocator::VDSteppedAllocator(size_t initialSize) + : mpHead(NULL) + , mpAllocNext(NULL) + , mAllocLeft(0) + , mAllocNext(initialSize) + , mAllocInit(initialSize) +{ +} + +VDSteppedAllocator::~VDSteppedAllocator() { + clear(); +} + +void VDSteppedAllocator::clear() { + while(Block *p = mpHead) { + mpHead = mpHead->next; + free(p); + } + mAllocLeft = 0; + mAllocNext = mAllocInit; +} + +void *VDSteppedAllocator::allocate(size_type n) { + n = (n+15) & ~15; + if (mAllocLeft < n) { + mAllocLeft = mAllocNext; + mAllocNext += (mAllocNext >> 1); + if (mAllocLeft < n) + mAllocLeft = n; + + Block *t = (Block *)malloc(sizeof(Block) + mAllocLeft); + + if (mpHead) + mpHead->next = t; + + mpHead = t; + mpHead->next = NULL; + + mpAllocNext = (char *)(mpHead + 1); + } + + void *p = mpAllocNext; + mpAllocNext += n; + mAllocLeft -= n; + return p; +} + +void VDResamplerGenerateTable(sint32 *dst, const IVDResamplerFilter& filter) { + const unsigned width = filter.GetFilterWidth(); + vdblock filters(width * 256); + float *src = filters.data(); + + filter.GenerateFilterBank(src); + + for(unsigned phase=0; phase < 256; ++phase) { + float sum = 0; + + for(unsigned i=0; i filters(width); + float *src = filters.data(); + + filter.GenerateFilterBank(src); + + for(sint32 i=0; i> 16; + filter.GenerateFilter(src, (double)(u & 0xffff) / 65536.0); + + float sum = 0; + for(uint32 j=0; j> 31) - 1; + while(ierr) { + for(uint32 j=0; j -#include -#include -#include -#include "resample_stages_reference.h" -#include -#include "blt_spanutils.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -int VDResamplerRowStageSeparablePoint8::GetWindowSize() const { - return 1; -} - -void VDResamplerRowStageSeparablePoint8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - do { - *dst++ = src[u>>16]; - u += dudx; - } while(--w); -} - -int VDResamplerRowStageSeparablePoint16::GetWindowSize() const { - return 1; -} - -void VDResamplerRowStageSeparablePoint16::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)src0; - - do { - *dst++ = src[u>>16]; - u += dudx; - } while(--w); -} - -int VDResamplerRowStageSeparablePoint32::GetWindowSize() const { - return 1; -} - -void VDResamplerRowStageSeparablePoint32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - do { - *dst++ = src[u>>16]; - u += dudx; - } while(--w); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -int VDResamplerRowStageSeparableLinear8::GetWindowSize() const {return 2;} -void VDResamplerRowStageSeparableLinear8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - do { - const sint32 iu = u>>16; - const uint32 p0 = src[iu]; - const uint32 p1 = src[iu+1]; - const uint32 f = (u >> 8) & 0xff; - - *dst++ = (uint8)(p0 + (((sint32)(p1 - p0)*f + 0x80)>>8)); - u += dudx; - } while(--w); -} - -void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - VDASSERT(!u && dudx == 0x8000); - - nsVDPixmapSpanUtils::horiz_expand2x_coaligned(dst, src, w); -} - -int VDResamplerRowStageSeparableLinear32::GetWindowSize() const {return 2;} -void VDResamplerRowStageSeparableLinear32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - do { - const sint32 iu = u>>16; - const uint32 p0 = src[iu]; - const uint32 p1 = src[iu+1]; - const uint32 f = (u >> 8) & 0xff; - - const uint32 p0_rb = p0 & 0xff00ff; - const uint32 p1_rb = p1 & 0xff00ff; - const uint32 p0_g = p0 & 0xff00; - const uint32 p1_g = p1 & 0xff00; - - *dst++ = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff) - + ((p0_g + (((p1_g - p0_g )*f + 0x008000)>>8)) & 0x00ff00); - u += dudx; - } while(--w); -} - -int VDResamplerColStageSeparableLinear8::GetWindowSize() const {return 2;} -void VDResamplerColStageSeparableLinear8::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src0 = (const uint8 *)srcarray[0]; - const uint8 *src1 = (const uint8 *)srcarray[1]; - const uint32 f = (phase >> 8) & 0xff; - - do { - const uint32 p0 = *src0++; - const uint32 p1 = *src1++; - - *dst++ = (uint8)(p0 + (((p1 - p0)*f + 0x80)>>8)); - } while(--w); -} - -int VDResamplerColStageSeparableLinear32::GetWindowSize() const {return 2;} -void VDResamplerColStageSeparableLinear32::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src0 = (const uint32 *)srcarray[0]; - const uint32 *src1 = (const uint32 *)srcarray[1]; - const uint32 f = (phase >> 8) & 0xff; - - do { - const uint32 p0 = *src0++; - const uint32 p1 = *src1++; - - const uint32 p0_rb = p0 & 0xff00ff; - const uint32 p1_rb = p1 & 0xff00ff; - const uint32 p0_g = p0 & 0xff00; - const uint32 p1_g = p1 & 0xff00; - - *dst++ = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff) - + ((p0_g + (((p1_g - p0_g )*f + 0x008000)>>8)) & 0x00ff00); - } while(--w); -} - -VDResamplerRowStageSeparableTable8::VDResamplerRowStageSeparableTable8(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTable(mFilterBank.data(), filter); -} - -int VDResamplerRowStageSeparableTable8::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerRowStageSeparableTable8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - const unsigned ksize = (int)mFilterBank.size() >> 8; - const sint32 *filterBase = mFilterBank.data(); - - do { - const uint8 *src2 = src + (u>>16); - const sint32 *filter = filterBase + ksize*((u>>8)&0xff); - u += dudx; - - int b = 0x2000; - for(unsigned i = ksize; i; --i) { - uint8 p = *src2++; - sint32 coeff = *filter++; - - b += (sint32)p*coeff; - } - - b >>= 14; - - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - *dst++ = (uint8)b; - } while(--w); -} - -VDResamplerRowStageSeparableTable32::VDResamplerRowStageSeparableTable32(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTable(mFilterBank.data(), filter); -} - -int VDResamplerRowStageSeparableTable32::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerRowStageSeparableTable32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - const unsigned ksize = (int)mFilterBank.size() >> 8; - const sint32 *filterBase = mFilterBank.data(); - - do { - const uint32 *src2 = src + (u>>16); - const sint32 *filter = filterBase + ksize*((u>>8)&0xff); - u += dudx; - - int r = 0x2000, g = 0x2000, b = 0x2000; - for(unsigned i = ksize; i; --i) { - uint32 p = *src2++; - sint32 coeff = *filter++; - - r += ((p>>16)&0xff)*coeff; - g += ((p>> 8)&0xff)*coeff; - b += ((p )&0xff)*coeff; - } - - r <<= 2; - g >>= 6; - b >>= 14; - - if ((uint32)r >= 0x01000000) - r = ~r >> 31; - if ((uint32)g >= 0x00010000) - g = ~g >> 31; - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff); - } while(--w); -} - -VDResamplerRowStageSeparableTable32Fx4::VDResamplerRowStageSeparableTable32Fx4(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTableF(mFilterBank.data(), filter); -} - -int VDResamplerRowStageSeparableTable32Fx4::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerRowStageSeparableTable32Fx4::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - float *dst = (float *)dst0; - const float *src = (const float *)src0; - const unsigned ksize = (int)mFilterBank.size() >> 8; - const float *filterBase = mFilterBank.data(); - - do { - const float *src2 = src + (u>>16)*4; - const float *filter = filterBase + ksize*((u>>8)&0xff); - u += dudx; - - float r = 0, g = 0, b = 0, a = 0; - for(unsigned i = ksize; i; --i) { - float coeff = *filter++; - - r += coeff * src2[0]; - g += coeff * src2[1]; - b += coeff * src2[2]; - a += coeff * src2[3]; - src2 += 4; - } - - dst[0] = r; - dst[1] = g; - dst[2] = b; - dst[3] = a; - dst += 4; - } while(--w); -} - -VDResamplerRowStageSeparableTable32F::VDResamplerRowStageSeparableTable32F(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTableF(mFilterBank.data(), filter); -} - -int VDResamplerRowStageSeparableTable32F::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerRowStageSeparableTable32F::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - float *dst = (float *)dst0; - const float *src = (const float *)src0; - const unsigned ksize = (int)mFilterBank.size() >> 8; - const float *filterBase = mFilterBank.data(); - - VDCPUCleanupExtensions(); - - do { - const float *src2 = src + (u>>16); - const float *filter = filterBase + ksize*((u>>8)&0xff); - u += dudx; - - float r = 0; - for(unsigned i = ksize; i; --i) { - float coeff = *filter++; - - r += coeff * src2[0]; - ++src2; - } - - dst[0] = r; - ++dst; - } while(--w); -} - -VDResamplerColStageSeparableTable8::VDResamplerColStageSeparableTable8(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTable(mFilterBank.data(), filter); -} - -int VDResamplerColStageSeparableTable8::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerColStageSeparableTable8::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - uint8 *dst = (uint8 *)dst0; - const uint8 *const *src = (const uint8 *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; - - for(uint32 i=0; i>= 14; - - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - *dst++ = (uint8)b; - } -} - -VDResamplerColStageSeparableTable32::VDResamplerColStageSeparableTable32(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTable(mFilterBank.data(), filter); -} - -int VDResamplerColStageSeparableTable32::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerColStageSeparableTable32::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - uint32 *dst = (uint32 *)dst0; - const uint32 *const *src = (const uint32 *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; - - for(uint32 i=0; i>16)&0xff)*coeff; - g += ((p>> 8)&0xff)*coeff; - b += ((p )&0xff)*coeff; - } - - r <<= 2; - g >>= 6; - b >>= 14; - - if ((uint32)r >= 0x01000000) - r = ~r >> 31; - if ((uint32)g >= 0x00010000) - g = ~g >> 31; - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff); - } -} - -VDResamplerColStageSeparableTable32F::VDResamplerColStageSeparableTable32F(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTableF(mFilterBank.data(), filter); -} - -int VDResamplerColStageSeparableTable32F::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerColStageSeparableTable32F::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - float *dst = (float *)dst0; - const float *const *src = (const float *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const float *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; - - for(uint32 i=0; i> 8;} - -void VDResamplerColStageSeparableTable32Fx4::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - float *dst = (float *)dst0; - const float *const *src = (const float *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const float *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; - - for(uint32 i=0; i +#include +#include +#include +#include "resample_stages_reference.h" +#include +#include "blt_spanutils.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +int VDResamplerRowStageSeparablePoint8::GetWindowSize() const { + return 1; +} + +void VDResamplerRowStageSeparablePoint8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + do { + *dst++ = src[u>>16]; + u += dudx; + } while(--w); +} + +int VDResamplerRowStageSeparablePoint16::GetWindowSize() const { + return 1; +} + +void VDResamplerRowStageSeparablePoint16::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)src0; + + do { + *dst++ = src[u>>16]; + u += dudx; + } while(--w); +} + +int VDResamplerRowStageSeparablePoint32::GetWindowSize() const { + return 1; +} + +void VDResamplerRowStageSeparablePoint32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + do { + *dst++ = src[u>>16]; + u += dudx; + } while(--w); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +int VDResamplerRowStageSeparableLinear8::GetWindowSize() const {return 2;} +void VDResamplerRowStageSeparableLinear8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + do { + const sint32 iu = u>>16; + const uint32 p0 = src[iu]; + const uint32 p1 = src[iu+1]; + const uint32 f = (u >> 8) & 0xff; + + *dst++ = (uint8)(p0 + (((sint32)(p1 - p0)*f + 0x80)>>8)); + u += dudx; + } while(--w); +} + +void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + VDASSERT(!u && dudx == 0x8000); + + nsVDPixmapSpanUtils::horiz_expand2x_coaligned(dst, src, w); +} + +int VDResamplerRowStageSeparableLinear32::GetWindowSize() const {return 2;} +void VDResamplerRowStageSeparableLinear32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + do { + const sint32 iu = u>>16; + const uint32 p0 = src[iu]; + const uint32 p1 = src[iu+1]; + const uint32 f = (u >> 8) & 0xff; + + const uint32 p0_rb = p0 & 0xff00ff; + const uint32 p1_rb = p1 & 0xff00ff; + const uint32 p0_g = p0 & 0xff00; + const uint32 p1_g = p1 & 0xff00; + + *dst++ = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff) + + ((p0_g + (((p1_g - p0_g )*f + 0x008000)>>8)) & 0x00ff00); + u += dudx; + } while(--w); +} + +int VDResamplerColStageSeparableLinear8::GetWindowSize() const {return 2;} +void VDResamplerColStageSeparableLinear8::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src0 = (const uint8 *)srcarray[0]; + const uint8 *src1 = (const uint8 *)srcarray[1]; + const uint32 f = (phase >> 8) & 0xff; + + do { + const uint32 p0 = *src0++; + const uint32 p1 = *src1++; + + *dst++ = (uint8)(p0 + (((p1 - p0)*f + 0x80)>>8)); + } while(--w); +} + +int VDResamplerColStageSeparableLinear32::GetWindowSize() const {return 2;} +void VDResamplerColStageSeparableLinear32::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src0 = (const uint32 *)srcarray[0]; + const uint32 *src1 = (const uint32 *)srcarray[1]; + const uint32 f = (phase >> 8) & 0xff; + + do { + const uint32 p0 = *src0++; + const uint32 p1 = *src1++; + + const uint32 p0_rb = p0 & 0xff00ff; + const uint32 p1_rb = p1 & 0xff00ff; + const uint32 p0_g = p0 & 0xff00; + const uint32 p1_g = p1 & 0xff00; + + *dst++ = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff) + + ((p0_g + (((p1_g - p0_g )*f + 0x008000)>>8)) & 0x00ff00); + } while(--w); +} + +VDResamplerRowStageSeparableTable8::VDResamplerRowStageSeparableTable8(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTable(mFilterBank.data(), filter); +} + +int VDResamplerRowStageSeparableTable8::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerRowStageSeparableTable8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + const unsigned ksize = (int)mFilterBank.size() >> 8; + const sint32 *filterBase = mFilterBank.data(); + + do { + const uint8 *src2 = src + (u>>16); + const sint32 *filter = filterBase + ksize*((u>>8)&0xff); + u += dudx; + + int b = 0x2000; + for(unsigned i = ksize; i; --i) { + uint8 p = *src2++; + sint32 coeff = *filter++; + + b += (sint32)p*coeff; + } + + b >>= 14; + + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + *dst++ = (uint8)b; + } while(--w); +} + +VDResamplerRowStageSeparableTable32::VDResamplerRowStageSeparableTable32(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTable(mFilterBank.data(), filter); +} + +int VDResamplerRowStageSeparableTable32::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerRowStageSeparableTable32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + const unsigned ksize = (int)mFilterBank.size() >> 8; + const sint32 *filterBase = mFilterBank.data(); + + do { + const uint32 *src2 = src + (u>>16); + const sint32 *filter = filterBase + ksize*((u>>8)&0xff); + u += dudx; + + int r = 0x2000, g = 0x2000, b = 0x2000; + for(unsigned i = ksize; i; --i) { + uint32 p = *src2++; + sint32 coeff = *filter++; + + r += ((p>>16)&0xff)*coeff; + g += ((p>> 8)&0xff)*coeff; + b += ((p )&0xff)*coeff; + } + + r <<= 2; + g >>= 6; + b >>= 14; + + if ((uint32)r >= 0x01000000) + r = ~r >> 31; + if ((uint32)g >= 0x00010000) + g = ~g >> 31; + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff); + } while(--w); +} + +VDResamplerRowStageSeparableTable32Fx4::VDResamplerRowStageSeparableTable32Fx4(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTableF(mFilterBank.data(), filter); +} + +int VDResamplerRowStageSeparableTable32Fx4::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerRowStageSeparableTable32Fx4::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + float *dst = (float *)dst0; + const float *src = (const float *)src0; + const unsigned ksize = (int)mFilterBank.size() >> 8; + const float *filterBase = mFilterBank.data(); + + do { + const float *src2 = src + (u>>16)*4; + const float *filter = filterBase + ksize*((u>>8)&0xff); + u += dudx; + + float r = 0, g = 0, b = 0, a = 0; + for(unsigned i = ksize; i; --i) { + float coeff = *filter++; + + r += coeff * src2[0]; + g += coeff * src2[1]; + b += coeff * src2[2]; + a += coeff * src2[3]; + src2 += 4; + } + + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + dst += 4; + } while(--w); +} + +VDResamplerRowStageSeparableTable32F::VDResamplerRowStageSeparableTable32F(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTableF(mFilterBank.data(), filter); +} + +int VDResamplerRowStageSeparableTable32F::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerRowStageSeparableTable32F::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + float *dst = (float *)dst0; + const float *src = (const float *)src0; + const unsigned ksize = (int)mFilterBank.size() >> 8; + const float *filterBase = mFilterBank.data(); + + VDCPUCleanupExtensions(); + + do { + const float *src2 = src + (u>>16); + const float *filter = filterBase + ksize*((u>>8)&0xff); + u += dudx; + + float r = 0; + for(unsigned i = ksize; i; --i) { + float coeff = *filter++; + + r += coeff * src2[0]; + ++src2; + } + + dst[0] = r; + ++dst; + } while(--w); +} + +VDResamplerColStageSeparableTable8::VDResamplerColStageSeparableTable8(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTable(mFilterBank.data(), filter); +} + +int VDResamplerColStageSeparableTable8::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerColStageSeparableTable8::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + uint8 *dst = (uint8 *)dst0; + const uint8 *const *src = (const uint8 *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; + + for(uint32 i=0; i>= 14; + + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + *dst++ = (uint8)b; + } +} + +VDResamplerColStageSeparableTable32::VDResamplerColStageSeparableTable32(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTable(mFilterBank.data(), filter); +} + +int VDResamplerColStageSeparableTable32::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerColStageSeparableTable32::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + uint32 *dst = (uint32 *)dst0; + const uint32 *const *src = (const uint32 *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; + + for(uint32 i=0; i>16)&0xff)*coeff; + g += ((p>> 8)&0xff)*coeff; + b += ((p )&0xff)*coeff; + } + + r <<= 2; + g >>= 6; + b >>= 14; + + if ((uint32)r >= 0x01000000) + r = ~r >> 31; + if ((uint32)g >= 0x00010000) + g = ~g >> 31; + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff); + } +} + +VDResamplerColStageSeparableTable32F::VDResamplerColStageSeparableTable32F(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTableF(mFilterBank.data(), filter); +} + +int VDResamplerColStageSeparableTable32F::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerColStageSeparableTable32F::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + float *dst = (float *)dst0; + const float *const *src = (const float *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const float *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; + + for(uint32 i=0; i> 8;} + +void VDResamplerColStageSeparableTable32Fx4::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + float *dst = (float *)dst0; + const float *const *src = (const float *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const float *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; + + for(uint32 i=0; i> 1); -} - -void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_SSE2((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) - : VDResamplerColStageSeparableTable32(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (uint32)mFilterBank.size() >> 1); -} - -void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { - const unsigned filtSize = (unsigned)mFilterBank.size() >> 8; - - vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data() + filtSize*((phase >> 8) & 0xff), filtSize, w); -} +#include "stdafx.h" // MPC-HC patch +#include "resample_stages_x64.h" + +extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w); +extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); + +VDResamplerSeparableTableRowStageSSE2::VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter) + : VDResamplerRowStageSeparableTable32(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (uint32)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_SSE2((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) + : VDResamplerColStageSeparableTable32(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (uint32)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { + const unsigned filtSize = (unsigned)mFilterBank.size() >> 8; + + vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data() + filtSize*((phase >> 8) & 0xff), filtSize, w); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/resample_stages_x86.cpp b/src/thirdparty/VirtualDub/Kasumi/source/resample_stages_x86.cpp index 123fa17c41f..ff5ffb11f76 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/resample_stages_x86.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/resample_stages_x86.cpp @@ -1,1296 +1,1296 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include "blt_spanutils_x86.h" -#include "resample_stages_x86.h" -#include - -#ifdef _MSC_VER - #pragma warning(disable: 4799) // warning C4799: function 'vdasm_resize_table_row_8_k8_4x_MMX' has no EMMS instruction -#endif - -/////////////////////////////////////////////////////////////////////////////// - -extern "C" void vdasm_resize_table_row_8_k8_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); -extern "C" void vdasm_resize_table_row_8_k16_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); -extern "C" void vdasm_resize_table_row_8_SSE41(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth); -extern "C" void vdasm_resize_table_col_8_k2_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); -extern "C" void vdasm_resize_table_col_8_k4_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); - -/////////////////////////////////////////////////////////////////////////////// - -namespace { - struct ScaleInfo { - void *dst; - uintptr src; - uint32 accum; - uint32 fracinc; - sint32 intinc; - uint32 count; - }; - - extern "C" void vdasm_resize_point32(const ScaleInfo *); -} - -int VDResamplerSeparablePointRowStageX86::GetWindowSize() const {return 1;} -void VDResamplerSeparablePointRowStageX86::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - ScaleInfo info; - - info.dst = (uint32 *)dst + w; - info.src = ((uintptr)src >> 2) + (u>>16); - info.accum = u<<16; - info.fracinc = dudx << 16; - info.intinc = (sint32)dudx >> 16; - info.count = -(sint32)w*4; - - vdasm_resize_point32(&info); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE(dst, src, w); -} - -/////////////////////////////////////////////////////////////////////////////// - -extern "C" void vdasm_resize_point32_MMX(const ScaleInfo *); -extern "C" void vdasm_resize_interp_row_run_MMX(void *dst, const void *src, uint32 width, sint64 xaccum, sint64 x_inc); -extern "C" void vdasm_resize_interp_col_run_MMX(void *dst, const void *src1, const void *src2, uint32 width, uint32 yaccum); -extern "C" void vdasm_resize_ccint_row_MMX(void *dst, const void *src, uint32 count, uint32 xaccum, sint32 xinc, const void *tbl); -extern "C" void vdasm_resize_ccint_col_MMX(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); -extern "C" long vdasm_resize_table_col_MMX(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); -extern "C" long vdasm_resize_table_row_MMX(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); - -int VDResamplerSeparablePointRowStageMMX::GetWindowSize() const {return 1;} -void VDResamplerSeparablePointRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - ScaleInfo info; - - info.dst = (uint32 *)dst + w; - info.src = ((uintptr)src >> 2) + (u>>16); - info.accum = u<<16; - info.fracinc = dudx << 16; - info.intinc = (sint32)dudx >> 16; - info.count = -(sint32)w*4; - - vdasm_resize_point32_MMX(&info); -} - -int VDResamplerSeparableLinearRowStageMMX::GetWindowSize() const {return 2;} -void VDResamplerSeparableLinearRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_interp_row_run_MMX(dst0, src0, w, (sint64)u << 16, (sint64)dudx << 16); -} - -int VDResamplerSeparableLinearColStageMMX::GetWindowSize() const {return 2;} -void VDResamplerSeparableLinearColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - vdasm_resize_interp_col_run_MMX(dst0, srcarray[0], srcarray[1], w, phase); -} - -VDResamplerSeparableCubicRowStageMMX::VDResamplerSeparableCubicRowStageMMX(double A) - : mFilterBank(1024) -{ - sint32 *p = mFilterBank.data(); - VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); - VDResamplerSwizzleTable(p, 512); -} - -int VDResamplerSeparableCubicRowStageMMX::GetWindowSize() const {return 4;} -void VDResamplerSeparableCubicRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_ccint_row_MMX(dst0, src0, w, u, dudx, mFilterBank.data()); -} - -VDResamplerSeparableCubicColStageMMX::VDResamplerSeparableCubicColStageMMX(double A) - : mFilterBank(1024) -{ - sint32 *p = mFilterBank.data(); - VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); - VDResamplerSwizzleTable(p, 512); -} - -int VDResamplerSeparableCubicColStageMMX::GetWindowSize() const {return 4;} -void VDResamplerSeparableCubicColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - vdasm_resize_ccint_col_MMX(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); -} - -VDResamplerSeparableTableRowStage8MMX::VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter) - : VDResamplerRowStageSeparableTable32(filter) - , mLastSrcWidth(0) - , mLastDstWidth(0) - , mLastU(0) - , mLastDUDX(0) -{ - mAlignedKernelWidth = (GetWindowSize() + 6) & ~3; - mAlignedKernelSize = mAlignedKernelWidth + 4; -} - -void VDResamplerSeparableTableRowStage8MMX::Init(const VDResamplerAxis& axis, uint32 srcw) { - uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; - - if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { - mLastSrcWidth = srcw; - mLastDstWidth = w; - mLastU = axis.u; - mLastDUDX = axis.dudx; - - RedoRowFilters(axis, w, srcw); - } -} - -void VDResamplerSeparableTableRowStage8MMX::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { - int kstride = mFilterBank.size() >> 8; - int ksize = mAlignedKernelWidth; - int kesize = mAlignedKernelSize; - - mRowKernels.clear(); - mRowKernelSize = w * kesize; - - mRowKernels.resize(mRowKernelSize * 4, 0); - - for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { - sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; - int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 3) & ~3); - - mKernelSizeByOffset[byteOffset] = ksizeThisOffset; - - sint32 u = axis.u; - sint32 uoffmin = -byteOffset; - sint32 uoffmax = ((srcw + byteOffset + 3) & ~3) - byteOffset - ksizeThisOffset; - for(uint32 i=0; i> 16; - sint32 uoffset2 = ((uoffset + byteOffset) & ~3) - byteOffset; - - if (uoffset2 < uoffmin) - uoffset2 = uoffmin; - - if (uoffset2 > uoffmax) - uoffset2 = uoffmax; - - VDASSERT(uoffset2 + ksizeThisOffset <= (((sint32)srcw + byteOffset + 3) & ~3)); - - *(sint32 *)dst = uoffset2; - dst += 2; - *dst++ = 0; - *dst++ = 0; - - uint32 phase = (u >> 8) & 255; - const sint32 *src = &mFilterBank[kstride * phase]; - - sint32 start = 0; - sint32 end = kstride; - - int dstoffset = uoffset - uoffset2; - - // check for filter kernel overlapping left source boundary - if (uoffset < 0) - start = -uoffset; - - // check for filter kernel overlapping right source boundary - if (uoffset + end > (sint32)srcw) - end = srcw - uoffset; - - VDASSERT(dstoffset + start >= 0); - VDASSERT(dstoffset + end <= ksizeThisOffset); - - sint16 *dst2 = dst + dstoffset; - dst += ksizeThisOffset; - - for(int j=start; j 0) - dst2[start] = std::accumulate(src, src+start, dst2[start]); - - if (end < kstride) - dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); - - u += axis.dudx; - } - } - - // swizzle rows where optimization is possible - vdfastvector temp; - - int quads = w >> 2; - int quadRemainder = w & 3; - - for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { - int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; - int kpairs = ksizeThisOffset >> 2; - - if (ksizeThisOffset < 8 || ksizeThisOffset > 12) { - mbQuadOptimizationEnabled[byteOffset] = false; - } else { - ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 2; - - mbQuadOptimizationEnabled[byteOffset] = true; - mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); - - uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; - temp.resize(mRowKernelSize); - memcpy(temp.data(), dst, mRowKernelSize*2); - - const uint32 *src0 = (const uint32 *)temp.data(); - const uint32 *src1 = src0 + unswizzledStride; - const uint32 *src2 = src1 + unswizzledStride; - const uint32 *src3 = src2 + unswizzledStride; - ptrdiff_t srcskip = unswizzledStride * 3; - - for(int q = 0; q < quads; ++q) { - dst[0] = src0[0]; - dst[1] = src1[0]; - dst[2] = src2[0]; - dst[3] = src3[0]; - src0 += 2; - src1 += 2; - src2 += 2; - src3 += 2; - dst += 4; - - for(int p = 0; p < kpairs; ++p) { - dst[0] = src0[0]; - dst[1] = src0[1]; - dst[2] = src1[0]; - dst[3] = src1[1]; - dst[4] = src2[0]; - dst[5] = src2[1]; - dst[6] = src3[0]; - dst[7] = src3[1]; - dst += 8; - src0 += 2; - src1 += 2; - src2 += 2; - src3 += 2; - } - - src0 += srcskip; - src1 += srcskip; - src2 += srcskip; - src3 += srcskip; - } - - memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); - - VDASSERT(dst + unswizzledStride * quadRemainder <= (void *)(mRowKernels.data() + (mRowKernelSize * (byteOffset + 1)))); - } - } -} - -void __declspec(naked) vdasm_resize_table_row_8_k8_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { - static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov ebp, [esp + 4 + 16] ;ebp = dst - mov esi, [esp + 12 + 16] ;esi = width - mov edi, [esp + 16 + 16] ;edi = kernel -yloop: - ;eax = temp - ;ebx = temp - ;ecx = temp - ;edx = temp - ;esi = horiz counter - ;edi = filter list - ;ebp = destination - - mov eax, [edi+0] - mov ebx, [edi+4] - mov ecx, [edi+8] - mov edx, [esp+8+16] - add eax, edx - add ebx, edx - add ecx, edx - add edx, [edi+12] - - movd mm0, [eax] - punpcklbw mm0, mm7 - - pmaddwd mm0, [edi+16] - movd mm1, [ebx] - punpcklbw mm1, mm7 - - pmaddwd mm1, [edi+24] - movd mm2, [ecx] - punpcklbw mm2, mm7 - - pmaddwd mm2, [edi+32] - movd mm3, [edx] - punpcklbw mm3, mm7 - - pmaddwd mm3, [edi+40] - movd mm4, [eax+4] - paddd mm0, mm6 - - movd mm5, [ebx+4] - punpcklbw mm4, mm7 - paddd mm1, mm6 - - pmaddwd mm4, [edi+48] - punpcklbw mm5, mm7 - paddd mm2, mm6 - - pmaddwd mm5, [edi+56] - paddd mm3, mm6 - paddd mm0, mm4 - - paddd mm1, mm5 - movd mm4, [ecx+4] - punpcklbw mm4, mm7 - - pmaddwd mm4, [edi+64] - movd mm5, [edx+4] - punpcklbw mm5, mm7 - - pmaddwd mm5, [edi+72] - paddd mm2, mm4 - paddd mm3, mm5 - - movq mm4, mm0 - punpckldq mm0, mm1 - movq mm5, mm2 - punpckldq mm2, mm3 - punpckhdq mm4, mm1 - punpckhdq mm5, mm3 - paddd mm0, mm4 - paddd mm2, mm5 - psrad mm0, 14 - psrad mm2, 14 - - packssdw mm0, mm2 - packuswb mm0, mm0 - - add edi, 80 - - movd [ebp], mm0 - add ebp, 4 - sub esi, 1 - jne yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void __declspec(naked) vdasm_resize_table_row_8_k12_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { - static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov ebp, [esp + 4 + 16] ;ebp = dst - mov esi, [esp + 12 + 16] ;esi = width - mov edi, [esp + 16 + 16] ;edi = kernel -yloop: - ;eax = temp - ;ebx = temp - ;ecx = temp - ;edx = temp - ;esi = horiz counter - ;edi = filter list - ;ebp = destination - - mov eax, [edi+0] - mov ebx, [edi+4] - mov ecx, [edi+8] - mov edx, [esp+8+16] - add eax, edx - add ebx, edx - add ecx, edx - add edx, [edi+12] - - movd mm0, [eax] - punpcklbw mm0, mm7 - - pmaddwd mm0, [edi+16] - movd mm1, [ebx] - punpcklbw mm1, mm7 - - pmaddwd mm1, [edi+24] - movd mm2, [ecx] - punpcklbw mm2, mm7 - - pmaddwd mm2, [edi+32] - movd mm3, [edx] - punpcklbw mm3, mm7 - - pmaddwd mm3, [edi+40] - movd mm4, [eax+4] - punpcklbw mm4, mm7 - - pmaddwd mm4, [edi+48] - movd mm5, [ebx+4] - punpcklbw mm5, mm7 - - pmaddwd mm5, [edi+56] - paddd mm0, mm4 - paddd mm1, mm5 - - movd mm4, [ecx+4] - punpcklbw mm4, mm7 - movd mm5, [edx+4] - - pmaddwd mm4, [edi+64] - punpcklbw mm5, mm7 - paddd mm2, mm4 - - pmaddwd mm5, [edi+72] - movd mm4, [eax+8] - punpcklbw mm4, mm7 - - paddd mm3, mm5 - movd mm5, [ebx+8] - punpcklbw mm5, mm7 - - pmaddwd mm4, [edi+80] - paddd mm0, mm4 - movd mm4, [ecx+8] - - pmaddwd mm5, [edi+88] - paddd mm1, mm5 - punpcklbw mm4, mm7 - - pmaddwd mm4, [edi+96] - movd mm5, [edx+8] - punpcklbw mm5, mm7 - - pmaddwd mm5, [edi+104] - paddd mm2, mm4 - paddd mm3, mm5 - - movq mm4, mm0 - punpckldq mm0, mm1 - movq mm5, mm2 - punpckldq mm2, mm3 - punpckhdq mm4, mm1 - punpckhdq mm5, mm3 - paddd mm0, mm4 - paddd mm2, mm5 - paddd mm0, mm6 - paddd mm2, mm6 - psrad mm0, 14 - psrad mm2, 14 - - packssdw mm0, mm2 - packuswb mm0, mm0 - - add edi, 112 - - movd [ebp], mm0 - add ebp, 4 - sub esi, 1 - jne yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void __declspec(naked) vdasm_resize_table_row_8_MMX(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth) { - static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov edi, [esp + 4 + 16] ;edi = dst - mov ebx, [esp + 8 + 16] ;ebx = src - mov ebp, [esp + 12 + 16] ;ebp = width - mov edx, [esp + 16 + 16] ;edx = kernel -yloop: - ;eax = temp - ;ebx = source base address - ;ecx = (temp) source - ;edx = filter list - ;esi = (temp) kernel width - ;edi = destination - ;ebp = horiz counter - - mov eax, [edx] - add edx, 8 - lea ecx, [ebx + eax] - mov esi, [esp + 20 + 16] ;esi = kernel width - - movq mm2, mm6 -xloop: - movd mm0, [ecx] - punpcklbw mm0, mm7 - add ecx, 4 - pmaddwd mm0, [edx] - paddd mm2, mm0 - add edx, 8 - sub esi, 4 - jne xloop - - punpckldq mm0, mm2 - paddd mm0, mm2 - psrad mm0, 14 - psrlq mm0, 32 - packssdw mm0, mm0 - packuswb mm0, mm0 - movd eax, mm0 - mov [edi], al - add edi, 1 - sub ebp, 1 - jne yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w) { - int byteOffset = (int)(ptrdiff_t)src & 3; - const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); -#if 0 - int kwidth = mAlignedKernelWidth; - uint8 *dst2 = (uint8 *)dst; - - do { - int offset = ksrc[0]; - ksrc += 4; - - const uint8 *src2 = (const uint8 *)src + offset; - sint32 accum = 0x8000; - for(int i=0; i>= 14; - - accum &= ~(accum >> 31); - accum |= (255 - accum) >> 31; - - *dst2++ = (uint8)accum; - - } while(--w); -#else - int ksize = mKernelSizeByOffset[byteOffset]; - if (mbQuadOptimizationEnabled[byteOffset]) { - if (w >= 4) { - if (ksize == 12) { - vdasm_resize_table_row_8_k12_4x_MMX(dst, src, w >> 2, ksrc); - -#if 0 - int w4 = w >> 2; - uint8 *dst2 = (uint8 *)dst; - const uint8 *src2 = (const uint8 *)src; - const sint16 *ksrc2 = ksrc; - - do { - int off0 = ksrc2[0]; - int off1 = ksrc2[2]; - int off2 = ksrc2[4]; - int off3 = ksrc2[6]; - const uint8 *d0 = src2 + off0; - const uint8 *d1 = src2 + off1; - const uint8 *d2 = src2 + off2; - const uint8 *d3 = src2 + off3; - - int acc0 = 0; - int acc1 = 0; - int acc2 = 0; - int acc3 = 0; - - acc0 += d0[ 0]*ksrc2[ 8] - + d0[ 1]*ksrc2[ 9] - + d0[ 2]*ksrc2[ 10] - + d0[ 3]*ksrc2[ 11] - + d0[ 4]*ksrc2[ 24] - + d0[ 5]*ksrc2[ 25] - + d0[ 6]*ksrc2[ 26] - + d0[ 7]*ksrc2[ 27] - + d0[ 8]*ksrc2[ 40] - + d0[ 9]*ksrc2[ 41] - + d0[10]*ksrc2[ 42] - + d0[11]*ksrc2[ 43]; - - acc0 = (acc0 + 0x2000) >> 14; - if (acc0 < 0) acc0 = 0; else if (acc0 > 255) acc0 = 255; - - acc1 += d1[ 0]*ksrc2[ 12] - + d1[ 1]*ksrc2[ 13] - + d1[ 2]*ksrc2[ 14] - + d1[ 3]*ksrc2[ 15] - + d1[ 4]*ksrc2[ 28] - + d1[ 5]*ksrc2[ 29] - + d1[ 6]*ksrc2[ 30] - + d1[ 7]*ksrc2[ 31] - + d1[ 8]*ksrc2[ 44] - + d1[ 9]*ksrc2[ 45] - + d1[10]*ksrc2[ 46] - + d1[11]*ksrc2[ 47]; - - acc1 = (acc1 + 0x2000) >> 14; - if (acc1 < 0) acc1 = 0; else if (acc1 > 255) acc1 = 255; - - acc2 += d2[ 0]*ksrc2[ 16] - + d2[ 1]*ksrc2[ 17] - + d2[ 2]*ksrc2[ 18] - + d2[ 3]*ksrc2[ 19] - + d2[ 4]*ksrc2[ 32] - + d2[ 5]*ksrc2[ 33] - + d2[ 6]*ksrc2[ 34] - + d2[ 7]*ksrc2[ 35] - + d2[ 8]*ksrc2[ 48] - + d2[ 9]*ksrc2[ 49] - + d2[10]*ksrc2[ 50] - + d2[11]*ksrc2[ 51]; - - acc2 = (acc2 + 0x2000) >> 14; - if (acc2 < 0) acc2 = 0; else if (acc2 > 255) acc2 = 255; - - acc3 += d3[ 0]*ksrc2[ 20] - + d3[ 1]*ksrc2[ 21] - + d3[ 2]*ksrc2[ 22] - + d3[ 3]*ksrc2[ 23] - + d3[ 4]*ksrc2[ 36] - + d3[ 5]*ksrc2[ 37] - + d3[ 6]*ksrc2[ 38] - + d3[ 7]*ksrc2[ 39] - + d3[ 8]*ksrc2[ 52] - + d3[ 9]*ksrc2[ 53] - + d3[10]*ksrc2[ 54] - + d3[11]*ksrc2[ 55]; - - acc3 = (acc3 + 0x2000) >> 14; - if (acc3 < 0) acc3 = 0; else if (acc3 > 255) acc3 = 255; - - ksrc2 += 56; - - dst2[0] = (uint8)acc0; - dst2[1] = (uint8)acc1; - dst2[2] = (uint8)acc2; - dst2[3] = (uint8)acc3; - dst2 += 4; - } while(--w4); -#endif - } else - vdasm_resize_table_row_8_k8_4x_MMX(dst, src, w >> 2, ksrc); - } - - if (w & 3) - vdasm_resize_table_row_8_MMX((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); - } else if (w) { - vdasm_resize_table_row_8_MMX(dst, src, w, ksrc, ksize); - } -#endif -} - -void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -VDResamplerSeparableTableRowStageMMX::VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter) - : VDResamplerRowStageSeparableTable32(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); -} - -void VDResamplerSeparableTableRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -/////////////////////////////////////////////////////////////////////////// - -VDResamplerSeparableTableColStage8MMX::VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter) - : VDResamplerColStageSeparableTable8(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); -} - -void __declspec(naked) vdasm_resize_table_col_8_k2_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { - static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; - - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov esi, [esp + 4 + 16] ;esi = dst - mov edi, [esp + 16 + 16] ;edi = kernel - mov ebp, [esp + 12 + 16] ;ebp = width - - movq mm5, [edi] - - mov edx, [esp + 8 + 16] ;ebx = srcs - mov eax, [edx+0] - mov ebx, [edx+4] - add eax, ebp - add ebx, ebp - neg ebp -yloop: - ;eax = row0 - ;ebx = row1 - ;ecx = - ;edx = - ;edi = kernel - ;esi = dest - ;ebp = width counter - - movd mm0, [eax+ebp] - punpcklbw mm0, mm7 - movd mm2, [ebx+ebp] - punpcklbw mm2, mm7 - movq mm1, mm0 - punpcklwd mm0, mm2 - punpckhwd mm1, mm2 - pmaddwd mm0, mm5 - pmaddwd mm1, mm5 - - paddd mm0, mm6 - paddd mm1, mm6 - - psrad mm0, 14 - psrad mm1, 14 - packssdw mm0, mm1 - packuswb mm0, mm0 - movd [esi], mm0 - add esi, 4 - add ebp, 4 - jne yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void __declspec(naked) vdasm_resize_table_col_8_k4_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { - static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; - - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov esi, [esp + 4 + 16] ;esi = dst - mov edi, [esp + 16 + 16] ;edi = kernel - xor ebp, ebp - - mov edx, [esp + 8 + 16] ;ebx = srcs - mov eax, [edx+0] - mov ebx, [edx+4] - mov ecx, [edx+8] - mov edx, [edx+12] -yloop: - ;eax = row0 - ;ebx = row1 - ;ecx = row2 - ;edx = row3 - ;edi = kernel - ;esi = dest - ;ebp = width counter - - movd mm0, [eax+ebp] - punpcklbw mm0, mm7 - movd mm2, [ebx+ebp] - punpcklbw mm2, mm7 - movq mm1, mm0 - punpcklwd mm0, mm2 - movq mm5, [edi] - punpckhwd mm1, mm2 - pmaddwd mm0, mm5 - pmaddwd mm1, mm5 - - paddd mm0, mm6 - paddd mm1, mm6 - - movd mm3, [ecx+ebp] - punpcklbw mm3, mm7 - movd mm2, [edx+ebp] - punpcklbw mm2, mm7 - movq mm4, mm3 - punpcklwd mm3, mm2 - movq mm5, [edi+8] - punpckhwd mm4, mm2 - pmaddwd mm3, mm5 - pmaddwd mm4, mm5 - - paddd mm0, mm3 - paddd mm1, mm4 - - psrad mm0, 14 - psrad mm1, 14 - packssdw mm0, mm1 - packuswb mm0, mm0 - add ebp, 4 - movd [esi], mm0 - add esi, 4 - cmp ebp, [esp + 12 + 16] - jb yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void __declspec(naked) vdasm_resize_table_col_8_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel, uint32 kwidth) { - static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; - - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov edi, [esp + 4 + 16] ;edi = dst - xor ebp, ebp -yloop: - mov edx, [esp + 16 + 16] ;edx = kernel - mov ebx, [esp + 8 + 16] ;ebx = srcs - mov esi, [esp + 20 + 16] ;esi = kwidth - movq mm3, mm6 - movq mm4, mm6 -xloop: - mov ecx, [ebx] - movd mm0, [ecx+ebp] - punpcklbw mm0, mm7 - mov ecx, [ebx+4] - movd mm2, [ecx+ebp] - punpcklbw mm2, mm7 - movq mm1, mm0 - punpcklwd mm0, mm2 - punpckhwd mm1, mm2 - movq mm5, [edx] - pmaddwd mm0, mm5 - pmaddwd mm1, mm5 - - paddd mm3, mm0 - paddd mm4, mm1 - add ebx, 8 - add edx, 8 - sub esi, 2 - jne xloop - - psrad mm3, 14 - psrad mm4, 14 - packssdw mm3, mm4 - packuswb mm3, mm3 - movd [edi], mm3 - add edi, 4 - add ebp, 4 - cmp ebp, [esp + 12 + 16] - jb yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void VDResamplerSeparableTableColStage8MMX::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - uint8 *dst = (uint8 *)dst0; - const uint8 *const *src = (const uint8 *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; - - int w4 = w & ~3; - - if (w4) { - switch(ksize) { - case 2: - vdasm_resize_table_col_8_k2_MMX(dst, (const void *const *)src, w4, filter); - break; - - case 4: - vdasm_resize_table_col_8_k4_MMX(dst, (const void *const *)src, w4, filter); - break; - - default: - vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); - break; - } - } - - for(uint32 i=w4; i>= 14; - - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - dst[i] = (uint8)b; - } -} - -/////////////////////////////////////////////////////////////////////////// - -VDResamplerSeparableTableColStageMMX::VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter) - : VDResamplerColStageSeparableTable32(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); -} - -void VDResamplerSeparableTableColStageMMX::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { - vdasm_resize_table_col_MMX((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); -} - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE2, x86) -// -/////////////////////////////////////////////////////////////////////////// - -extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); -extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); -extern "C" void vdasm_resize_ccint_col_SSE2(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); - -VDResamplerSeparableCubicColStageSSE2::VDResamplerSeparableCubicColStageSSE2(double A) - : VDResamplerSeparableCubicColStageMMX(A) -{ -} - -void VDResamplerSeparableCubicColStageSSE2::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - vdasm_resize_ccint_col_SSE2(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); -} - -VDResamplerSeparableTableRowStageSSE2::VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter) - : VDResamplerSeparableTableRowStageMMX(filter) -{ -} - -void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) - : VDResamplerSeparableTableColStageMMX(filter) -{ -} - -void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { - vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); -} - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE4.1, x86) -// -/////////////////////////////////////////////////////////////////////////// - -VDResamplerSeparableTableRowStage8SSE41::VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter) - : VDResamplerRowStageSeparableTable32(filter) - , mLastSrcWidth(0) - , mLastDstWidth(0) - , mLastU(0) - , mLastDUDX(0) -{ - mAlignedKernelWidth = (GetWindowSize() + 15) & ~7; - mAlignedKernelSize = mAlignedKernelWidth + 16; -} - -void VDResamplerSeparableTableRowStage8SSE41::Init(const VDResamplerAxis& axis, uint32 srcw) { - uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; - - if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { - mLastSrcWidth = srcw; - mLastDstWidth = w; - mLastU = axis.u; - mLastDUDX = axis.dudx; - - RedoRowFilters(axis, w, srcw); - } -} - -void VDResamplerSeparableTableRowStage8SSE41::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { - int kstride = mFilterBank.size() >> 8; - int ksize = mAlignedKernelWidth; - int kesize = mAlignedKernelSize; - - mRowKernels.clear(); - mRowKernelSize = w * kesize; - - mRowKernels.resize(mRowKernelSize * 8, 0); - - for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { - sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; - int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 7) & ~7); - - mKernelSizeByOffset[byteOffset] = ksizeThisOffset; - - sint32 u = axis.u; - sint32 uoffmin = -byteOffset; - sint32 uoffmax = ((srcw + byteOffset + 7) & ~7) - byteOffset - ksizeThisOffset; - for(uint32 i=0; i> 16; - sint32 uoffset2 = ((uoffset + byteOffset) & ~7) - byteOffset; - - if (uoffset2 < uoffmin) - uoffset2 = uoffmin; - - if (uoffset2 > uoffmax) - uoffset2 = uoffmax; - - *(sint32 *)dst = uoffset2; - dst += 2; - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - - uint32 phase = (u >> 8) & 255; - const sint32 *src = &mFilterBank[kstride * phase]; - - sint32 start = 0; - sint32 end = kstride; - - int dstoffset = uoffset - uoffset2; - - // check for filter kernel overlapping left source boundary - if (uoffset < 0) - start = -uoffset; - - // check for filter kernel overlapping right source boundary - if (uoffset + end > (sint32)srcw) - end = srcw - uoffset; - - VDASSERT(dstoffset + start >= 0); - VDASSERT(dstoffset + end <= ksizeThisOffset); - - sint16 *dst2 = dst + dstoffset; - dst += ksizeThisOffset; - - for(int j=start; j 0) - dst2[start] = std::accumulate(src, src+start, dst2[start]); - - if (end < kstride) - dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); - - u += axis.dudx; - } - } - - // swizzle rows where optimization is possible - vdfastvector temp; - - int quads = w >> 2; - int quadRemainder = w & 3; - - for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { - int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; - int kpairs = ksizeThisOffset >> 3; - - if (ksizeThisOffset < 8 || ksizeThisOffset > 16) { - mbQuadOptimizationEnabled[byteOffset] = false; - } else { - ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 4; - - mbQuadOptimizationEnabled[byteOffset] = true; - mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); - - uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; - temp.resize(mRowKernelSize); - memcpy(temp.data(), dst, mRowKernelSize*2); - - const uint32 *src0 = (const uint32 *)temp.data(); - const uint32 *src1 = src0 + unswizzledStride; - const uint32 *src2 = src1 + unswizzledStride; - const uint32 *src3 = src2 + unswizzledStride; - ptrdiff_t srcskip = unswizzledStride * 3; - - for(int q = 0; q < quads; ++q) { - dst[0] = src0[0]; - dst[1] = src1[0]; - dst[2] = src2[0]; - dst[3] = src3[0]; - src0 += 4; - src1 += 4; - src2 += 4; - src3 += 4; - dst += 4; - - for(int p = 0; p < kpairs; ++p) { - dst[ 0] = src0[0]; - dst[ 1] = src0[1]; - dst[ 2] = src0[2]; - dst[ 3] = src0[3]; - dst[ 4] = src1[0]; - dst[ 5] = src1[1]; - dst[ 6] = src1[2]; - dst[ 7] = src1[3]; - dst[ 8] = src2[0]; - dst[ 9] = src2[1]; - dst[10] = src2[2]; - dst[11] = src2[3]; - dst[12] = src3[0]; - dst[13] = src3[1]; - dst[14] = src3[2]; - dst[15] = src3[3]; - dst += 16; - src0 += 4; - src1 += 4; - src2 += 4; - src3 += 4; - } - - src0 += srcskip; - src1 += srcskip; - src2 += srcskip; - src3 += srcskip; - } - - memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); - } - } -} - -void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w) { - int byteOffset = (int)(ptrdiff_t)src & 7; - const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); - - int ksize = mKernelSizeByOffset[byteOffset]; - if (mbQuadOptimizationEnabled[byteOffset]) { - if (w >= 4) { - if (ksize == 16) - vdasm_resize_table_row_8_k16_4x_SSE41(dst, src, w >> 2, ksrc); - else - vdasm_resize_table_row_8_k8_4x_SSE41(dst, src, w >> 2, ksrc); - } - - if (w & 3) - vdasm_resize_table_row_8_SSE41((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); - } else if (w) { - vdasm_resize_table_row_8_SSE41(dst, src, w, ksrc, ksize); - } -} - -void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -/////////////////////////////////////////////////////////////////////////// - -VDResamplerSeparableTableColStage8SSE41::VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter) - : VDResamplerColStageSeparableTable8(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); -} - -void VDResamplerSeparableTableColStage8SSE41::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - uint8 *dst = (uint8 *)dst0; - const uint8 *const *src = (const uint8 *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; - - int w4 = w & ~3; - - if (w4) { - switch(ksize) { - case 2: - vdasm_resize_table_col_8_k2_SSE41(dst, (const void *const *)src, w4, filter); - break; - - case 4: - vdasm_resize_table_col_8_k4_SSE41(dst, (const void *const *)src, w4, filter); - break; - - default: - vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); - break; - } - } - - for(uint32 i=w4; i>= 14; - - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - dst[i] = (uint8)b; - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include "blt_spanutils_x86.h" +#include "resample_stages_x86.h" +#include + +#ifdef _MSC_VER + #pragma warning(disable: 4799) // warning C4799: function 'vdasm_resize_table_row_8_k8_4x_MMX' has no EMMS instruction +#endif + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" void vdasm_resize_table_row_8_k8_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); +extern "C" void vdasm_resize_table_row_8_k16_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); +extern "C" void vdasm_resize_table_row_8_SSE41(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth); +extern "C" void vdasm_resize_table_col_8_k2_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); +extern "C" void vdasm_resize_table_col_8_k4_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + struct ScaleInfo { + void *dst; + uintptr src; + uint32 accum; + uint32 fracinc; + sint32 intinc; + uint32 count; + }; + + extern "C" void vdasm_resize_point32(const ScaleInfo *); +} + +int VDResamplerSeparablePointRowStageX86::GetWindowSize() const {return 1;} +void VDResamplerSeparablePointRowStageX86::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + ScaleInfo info; + + info.dst = (uint32 *)dst + w; + info.src = ((uintptr)src >> 2) + (u>>16); + info.accum = u<<16; + info.fracinc = dudx << 16; + info.intinc = (sint32)dudx >> 16; + info.count = -(sint32)w*4; + + vdasm_resize_point32(&info); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE(dst, src, w); +} + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" void vdasm_resize_point32_MMX(const ScaleInfo *); +extern "C" void vdasm_resize_interp_row_run_MMX(void *dst, const void *src, uint32 width, sint64 xaccum, sint64 x_inc); +extern "C" void vdasm_resize_interp_col_run_MMX(void *dst, const void *src1, const void *src2, uint32 width, uint32 yaccum); +extern "C" void vdasm_resize_ccint_row_MMX(void *dst, const void *src, uint32 count, uint32 xaccum, sint32 xinc, const void *tbl); +extern "C" void vdasm_resize_ccint_col_MMX(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); +extern "C" long vdasm_resize_table_col_MMX(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); +extern "C" long vdasm_resize_table_row_MMX(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); + +int VDResamplerSeparablePointRowStageMMX::GetWindowSize() const {return 1;} +void VDResamplerSeparablePointRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + ScaleInfo info; + + info.dst = (uint32 *)dst + w; + info.src = ((uintptr)src >> 2) + (u>>16); + info.accum = u<<16; + info.fracinc = dudx << 16; + info.intinc = (sint32)dudx >> 16; + info.count = -(sint32)w*4; + + vdasm_resize_point32_MMX(&info); +} + +int VDResamplerSeparableLinearRowStageMMX::GetWindowSize() const {return 2;} +void VDResamplerSeparableLinearRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_interp_row_run_MMX(dst0, src0, w, (sint64)u << 16, (sint64)dudx << 16); +} + +int VDResamplerSeparableLinearColStageMMX::GetWindowSize() const {return 2;} +void VDResamplerSeparableLinearColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + vdasm_resize_interp_col_run_MMX(dst0, srcarray[0], srcarray[1], w, phase); +} + +VDResamplerSeparableCubicRowStageMMX::VDResamplerSeparableCubicRowStageMMX(double A) + : mFilterBank(1024) +{ + sint32 *p = mFilterBank.data(); + VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); + VDResamplerSwizzleTable(p, 512); +} + +int VDResamplerSeparableCubicRowStageMMX::GetWindowSize() const {return 4;} +void VDResamplerSeparableCubicRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_ccint_row_MMX(dst0, src0, w, u, dudx, mFilterBank.data()); +} + +VDResamplerSeparableCubicColStageMMX::VDResamplerSeparableCubicColStageMMX(double A) + : mFilterBank(1024) +{ + sint32 *p = mFilterBank.data(); + VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); + VDResamplerSwizzleTable(p, 512); +} + +int VDResamplerSeparableCubicColStageMMX::GetWindowSize() const {return 4;} +void VDResamplerSeparableCubicColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + vdasm_resize_ccint_col_MMX(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); +} + +VDResamplerSeparableTableRowStage8MMX::VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter) + : VDResamplerRowStageSeparableTable32(filter) + , mLastSrcWidth(0) + , mLastDstWidth(0) + , mLastU(0) + , mLastDUDX(0) +{ + mAlignedKernelWidth = (GetWindowSize() + 6) & ~3; + mAlignedKernelSize = mAlignedKernelWidth + 4; +} + +void VDResamplerSeparableTableRowStage8MMX::Init(const VDResamplerAxis& axis, uint32 srcw) { + uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; + + if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { + mLastSrcWidth = srcw; + mLastDstWidth = w; + mLastU = axis.u; + mLastDUDX = axis.dudx; + + RedoRowFilters(axis, w, srcw); + } +} + +void VDResamplerSeparableTableRowStage8MMX::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { + int kstride = mFilterBank.size() >> 8; + int ksize = mAlignedKernelWidth; + int kesize = mAlignedKernelSize; + + mRowKernels.clear(); + mRowKernelSize = w * kesize; + + mRowKernels.resize(mRowKernelSize * 4, 0); + + for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { + sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; + int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 3) & ~3); + + mKernelSizeByOffset[byteOffset] = ksizeThisOffset; + + sint32 u = axis.u; + sint32 uoffmin = -byteOffset; + sint32 uoffmax = ((srcw + byteOffset + 3) & ~3) - byteOffset - ksizeThisOffset; + for(uint32 i=0; i> 16; + sint32 uoffset2 = ((uoffset + byteOffset) & ~3) - byteOffset; + + if (uoffset2 < uoffmin) + uoffset2 = uoffmin; + + if (uoffset2 > uoffmax) + uoffset2 = uoffmax; + + VDASSERT(uoffset2 + ksizeThisOffset <= (((sint32)srcw + byteOffset + 3) & ~3)); + + *(sint32 *)dst = uoffset2; + dst += 2; + *dst++ = 0; + *dst++ = 0; + + uint32 phase = (u >> 8) & 255; + const sint32 *src = &mFilterBank[kstride * phase]; + + sint32 start = 0; + sint32 end = kstride; + + int dstoffset = uoffset - uoffset2; + + // check for filter kernel overlapping left source boundary + if (uoffset < 0) + start = -uoffset; + + // check for filter kernel overlapping right source boundary + if (uoffset + end > (sint32)srcw) + end = srcw - uoffset; + + VDASSERT(dstoffset + start >= 0); + VDASSERT(dstoffset + end <= ksizeThisOffset); + + sint16 *dst2 = dst + dstoffset; + dst += ksizeThisOffset; + + for(int j=start; j 0) + dst2[start] = std::accumulate(src, src+start, dst2[start]); + + if (end < kstride) + dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); + + u += axis.dudx; + } + } + + // swizzle rows where optimization is possible + vdfastvector temp; + + int quads = w >> 2; + int quadRemainder = w & 3; + + for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { + int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; + int kpairs = ksizeThisOffset >> 2; + + if (ksizeThisOffset < 8 || ksizeThisOffset > 12) { + mbQuadOptimizationEnabled[byteOffset] = false; + } else { + ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 2; + + mbQuadOptimizationEnabled[byteOffset] = true; + mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); + + uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; + temp.resize(mRowKernelSize); + memcpy(temp.data(), dst, mRowKernelSize*2); + + const uint32 *src0 = (const uint32 *)temp.data(); + const uint32 *src1 = src0 + unswizzledStride; + const uint32 *src2 = src1 + unswizzledStride; + const uint32 *src3 = src2 + unswizzledStride; + ptrdiff_t srcskip = unswizzledStride * 3; + + for(int q = 0; q < quads; ++q) { + dst[0] = src0[0]; + dst[1] = src1[0]; + dst[2] = src2[0]; + dst[3] = src3[0]; + src0 += 2; + src1 += 2; + src2 += 2; + src3 += 2; + dst += 4; + + for(int p = 0; p < kpairs; ++p) { + dst[0] = src0[0]; + dst[1] = src0[1]; + dst[2] = src1[0]; + dst[3] = src1[1]; + dst[4] = src2[0]; + dst[5] = src2[1]; + dst[6] = src3[0]; + dst[7] = src3[1]; + dst += 8; + src0 += 2; + src1 += 2; + src2 += 2; + src3 += 2; + } + + src0 += srcskip; + src1 += srcskip; + src2 += srcskip; + src3 += srcskip; + } + + memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); + + VDASSERT(dst + unswizzledStride * quadRemainder <= (void *)(mRowKernels.data() + (mRowKernelSize * (byteOffset + 1)))); + } + } +} + +void __declspec(naked) vdasm_resize_table_row_8_k8_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { + static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov ebp, [esp + 4 + 16] ;ebp = dst + mov esi, [esp + 12 + 16] ;esi = width + mov edi, [esp + 16 + 16] ;edi = kernel +yloop: + ;eax = temp + ;ebx = temp + ;ecx = temp + ;edx = temp + ;esi = horiz counter + ;edi = filter list + ;ebp = destination + + mov eax, [edi+0] + mov ebx, [edi+4] + mov ecx, [edi+8] + mov edx, [esp+8+16] + add eax, edx + add ebx, edx + add ecx, edx + add edx, [edi+12] + + movd mm0, [eax] + punpcklbw mm0, mm7 + + pmaddwd mm0, [edi+16] + movd mm1, [ebx] + punpcklbw mm1, mm7 + + pmaddwd mm1, [edi+24] + movd mm2, [ecx] + punpcklbw mm2, mm7 + + pmaddwd mm2, [edi+32] + movd mm3, [edx] + punpcklbw mm3, mm7 + + pmaddwd mm3, [edi+40] + movd mm4, [eax+4] + paddd mm0, mm6 + + movd mm5, [ebx+4] + punpcklbw mm4, mm7 + paddd mm1, mm6 + + pmaddwd mm4, [edi+48] + punpcklbw mm5, mm7 + paddd mm2, mm6 + + pmaddwd mm5, [edi+56] + paddd mm3, mm6 + paddd mm0, mm4 + + paddd mm1, mm5 + movd mm4, [ecx+4] + punpcklbw mm4, mm7 + + pmaddwd mm4, [edi+64] + movd mm5, [edx+4] + punpcklbw mm5, mm7 + + pmaddwd mm5, [edi+72] + paddd mm2, mm4 + paddd mm3, mm5 + + movq mm4, mm0 + punpckldq mm0, mm1 + movq mm5, mm2 + punpckldq mm2, mm3 + punpckhdq mm4, mm1 + punpckhdq mm5, mm3 + paddd mm0, mm4 + paddd mm2, mm5 + psrad mm0, 14 + psrad mm2, 14 + + packssdw mm0, mm2 + packuswb mm0, mm0 + + add edi, 80 + + movd [ebp], mm0 + add ebp, 4 + sub esi, 1 + jne yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void __declspec(naked) vdasm_resize_table_row_8_k12_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { + static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov ebp, [esp + 4 + 16] ;ebp = dst + mov esi, [esp + 12 + 16] ;esi = width + mov edi, [esp + 16 + 16] ;edi = kernel +yloop: + ;eax = temp + ;ebx = temp + ;ecx = temp + ;edx = temp + ;esi = horiz counter + ;edi = filter list + ;ebp = destination + + mov eax, [edi+0] + mov ebx, [edi+4] + mov ecx, [edi+8] + mov edx, [esp+8+16] + add eax, edx + add ebx, edx + add ecx, edx + add edx, [edi+12] + + movd mm0, [eax] + punpcklbw mm0, mm7 + + pmaddwd mm0, [edi+16] + movd mm1, [ebx] + punpcklbw mm1, mm7 + + pmaddwd mm1, [edi+24] + movd mm2, [ecx] + punpcklbw mm2, mm7 + + pmaddwd mm2, [edi+32] + movd mm3, [edx] + punpcklbw mm3, mm7 + + pmaddwd mm3, [edi+40] + movd mm4, [eax+4] + punpcklbw mm4, mm7 + + pmaddwd mm4, [edi+48] + movd mm5, [ebx+4] + punpcklbw mm5, mm7 + + pmaddwd mm5, [edi+56] + paddd mm0, mm4 + paddd mm1, mm5 + + movd mm4, [ecx+4] + punpcklbw mm4, mm7 + movd mm5, [edx+4] + + pmaddwd mm4, [edi+64] + punpcklbw mm5, mm7 + paddd mm2, mm4 + + pmaddwd mm5, [edi+72] + movd mm4, [eax+8] + punpcklbw mm4, mm7 + + paddd mm3, mm5 + movd mm5, [ebx+8] + punpcklbw mm5, mm7 + + pmaddwd mm4, [edi+80] + paddd mm0, mm4 + movd mm4, [ecx+8] + + pmaddwd mm5, [edi+88] + paddd mm1, mm5 + punpcklbw mm4, mm7 + + pmaddwd mm4, [edi+96] + movd mm5, [edx+8] + punpcklbw mm5, mm7 + + pmaddwd mm5, [edi+104] + paddd mm2, mm4 + paddd mm3, mm5 + + movq mm4, mm0 + punpckldq mm0, mm1 + movq mm5, mm2 + punpckldq mm2, mm3 + punpckhdq mm4, mm1 + punpckhdq mm5, mm3 + paddd mm0, mm4 + paddd mm2, mm5 + paddd mm0, mm6 + paddd mm2, mm6 + psrad mm0, 14 + psrad mm2, 14 + + packssdw mm0, mm2 + packuswb mm0, mm0 + + add edi, 112 + + movd [ebp], mm0 + add ebp, 4 + sub esi, 1 + jne yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void __declspec(naked) vdasm_resize_table_row_8_MMX(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth) { + static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov edi, [esp + 4 + 16] ;edi = dst + mov ebx, [esp + 8 + 16] ;ebx = src + mov ebp, [esp + 12 + 16] ;ebp = width + mov edx, [esp + 16 + 16] ;edx = kernel +yloop: + ;eax = temp + ;ebx = source base address + ;ecx = (temp) source + ;edx = filter list + ;esi = (temp) kernel width + ;edi = destination + ;ebp = horiz counter + + mov eax, [edx] + add edx, 8 + lea ecx, [ebx + eax] + mov esi, [esp + 20 + 16] ;esi = kernel width + + movq mm2, mm6 +xloop: + movd mm0, [ecx] + punpcklbw mm0, mm7 + add ecx, 4 + pmaddwd mm0, [edx] + paddd mm2, mm0 + add edx, 8 + sub esi, 4 + jne xloop + + punpckldq mm0, mm2 + paddd mm0, mm2 + psrad mm0, 14 + psrlq mm0, 32 + packssdw mm0, mm0 + packuswb mm0, mm0 + movd eax, mm0 + mov [edi], al + add edi, 1 + sub ebp, 1 + jne yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w) { + int byteOffset = (int)(ptrdiff_t)src & 3; + const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); +#if 0 + int kwidth = mAlignedKernelWidth; + uint8 *dst2 = (uint8 *)dst; + + do { + int offset = ksrc[0]; + ksrc += 4; + + const uint8 *src2 = (const uint8 *)src + offset; + sint32 accum = 0x8000; + for(int i=0; i>= 14; + + accum &= ~(accum >> 31); + accum |= (255 - accum) >> 31; + + *dst2++ = (uint8)accum; + + } while(--w); +#else + int ksize = mKernelSizeByOffset[byteOffset]; + if (mbQuadOptimizationEnabled[byteOffset]) { + if (w >= 4) { + if (ksize == 12) { + vdasm_resize_table_row_8_k12_4x_MMX(dst, src, w >> 2, ksrc); + +#if 0 + int w4 = w >> 2; + uint8 *dst2 = (uint8 *)dst; + const uint8 *src2 = (const uint8 *)src; + const sint16 *ksrc2 = ksrc; + + do { + int off0 = ksrc2[0]; + int off1 = ksrc2[2]; + int off2 = ksrc2[4]; + int off3 = ksrc2[6]; + const uint8 *d0 = src2 + off0; + const uint8 *d1 = src2 + off1; + const uint8 *d2 = src2 + off2; + const uint8 *d3 = src2 + off3; + + int acc0 = 0; + int acc1 = 0; + int acc2 = 0; + int acc3 = 0; + + acc0 += d0[ 0]*ksrc2[ 8] + + d0[ 1]*ksrc2[ 9] + + d0[ 2]*ksrc2[ 10] + + d0[ 3]*ksrc2[ 11] + + d0[ 4]*ksrc2[ 24] + + d0[ 5]*ksrc2[ 25] + + d0[ 6]*ksrc2[ 26] + + d0[ 7]*ksrc2[ 27] + + d0[ 8]*ksrc2[ 40] + + d0[ 9]*ksrc2[ 41] + + d0[10]*ksrc2[ 42] + + d0[11]*ksrc2[ 43]; + + acc0 = (acc0 + 0x2000) >> 14; + if (acc0 < 0) acc0 = 0; else if (acc0 > 255) acc0 = 255; + + acc1 += d1[ 0]*ksrc2[ 12] + + d1[ 1]*ksrc2[ 13] + + d1[ 2]*ksrc2[ 14] + + d1[ 3]*ksrc2[ 15] + + d1[ 4]*ksrc2[ 28] + + d1[ 5]*ksrc2[ 29] + + d1[ 6]*ksrc2[ 30] + + d1[ 7]*ksrc2[ 31] + + d1[ 8]*ksrc2[ 44] + + d1[ 9]*ksrc2[ 45] + + d1[10]*ksrc2[ 46] + + d1[11]*ksrc2[ 47]; + + acc1 = (acc1 + 0x2000) >> 14; + if (acc1 < 0) acc1 = 0; else if (acc1 > 255) acc1 = 255; + + acc2 += d2[ 0]*ksrc2[ 16] + + d2[ 1]*ksrc2[ 17] + + d2[ 2]*ksrc2[ 18] + + d2[ 3]*ksrc2[ 19] + + d2[ 4]*ksrc2[ 32] + + d2[ 5]*ksrc2[ 33] + + d2[ 6]*ksrc2[ 34] + + d2[ 7]*ksrc2[ 35] + + d2[ 8]*ksrc2[ 48] + + d2[ 9]*ksrc2[ 49] + + d2[10]*ksrc2[ 50] + + d2[11]*ksrc2[ 51]; + + acc2 = (acc2 + 0x2000) >> 14; + if (acc2 < 0) acc2 = 0; else if (acc2 > 255) acc2 = 255; + + acc3 += d3[ 0]*ksrc2[ 20] + + d3[ 1]*ksrc2[ 21] + + d3[ 2]*ksrc2[ 22] + + d3[ 3]*ksrc2[ 23] + + d3[ 4]*ksrc2[ 36] + + d3[ 5]*ksrc2[ 37] + + d3[ 6]*ksrc2[ 38] + + d3[ 7]*ksrc2[ 39] + + d3[ 8]*ksrc2[ 52] + + d3[ 9]*ksrc2[ 53] + + d3[10]*ksrc2[ 54] + + d3[11]*ksrc2[ 55]; + + acc3 = (acc3 + 0x2000) >> 14; + if (acc3 < 0) acc3 = 0; else if (acc3 > 255) acc3 = 255; + + ksrc2 += 56; + + dst2[0] = (uint8)acc0; + dst2[1] = (uint8)acc1; + dst2[2] = (uint8)acc2; + dst2[3] = (uint8)acc3; + dst2 += 4; + } while(--w4); +#endif + } else + vdasm_resize_table_row_8_k8_4x_MMX(dst, src, w >> 2, ksrc); + } + + if (w & 3) + vdasm_resize_table_row_8_MMX((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); + } else if (w) { + vdasm_resize_table_row_8_MMX(dst, src, w, ksrc, ksize); + } +#endif +} + +void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +VDResamplerSeparableTableRowStageMMX::VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter) + : VDResamplerRowStageSeparableTable32(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +/////////////////////////////////////////////////////////////////////////// + +VDResamplerSeparableTableColStage8MMX::VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter) + : VDResamplerColStageSeparableTable8(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); +} + +void __declspec(naked) vdasm_resize_table_col_8_k2_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { + static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; + + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov esi, [esp + 4 + 16] ;esi = dst + mov edi, [esp + 16 + 16] ;edi = kernel + mov ebp, [esp + 12 + 16] ;ebp = width + + movq mm5, [edi] + + mov edx, [esp + 8 + 16] ;ebx = srcs + mov eax, [edx+0] + mov ebx, [edx+4] + add eax, ebp + add ebx, ebp + neg ebp +yloop: + ;eax = row0 + ;ebx = row1 + ;ecx = + ;edx = + ;edi = kernel + ;esi = dest + ;ebp = width counter + + movd mm0, [eax+ebp] + punpcklbw mm0, mm7 + movd mm2, [ebx+ebp] + punpcklbw mm2, mm7 + movq mm1, mm0 + punpcklwd mm0, mm2 + punpckhwd mm1, mm2 + pmaddwd mm0, mm5 + pmaddwd mm1, mm5 + + paddd mm0, mm6 + paddd mm1, mm6 + + psrad mm0, 14 + psrad mm1, 14 + packssdw mm0, mm1 + packuswb mm0, mm0 + movd [esi], mm0 + add esi, 4 + add ebp, 4 + jne yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void __declspec(naked) vdasm_resize_table_col_8_k4_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { + static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; + + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov esi, [esp + 4 + 16] ;esi = dst + mov edi, [esp + 16 + 16] ;edi = kernel + xor ebp, ebp + + mov edx, [esp + 8 + 16] ;ebx = srcs + mov eax, [edx+0] + mov ebx, [edx+4] + mov ecx, [edx+8] + mov edx, [edx+12] +yloop: + ;eax = row0 + ;ebx = row1 + ;ecx = row2 + ;edx = row3 + ;edi = kernel + ;esi = dest + ;ebp = width counter + + movd mm0, [eax+ebp] + punpcklbw mm0, mm7 + movd mm2, [ebx+ebp] + punpcklbw mm2, mm7 + movq mm1, mm0 + punpcklwd mm0, mm2 + movq mm5, [edi] + punpckhwd mm1, mm2 + pmaddwd mm0, mm5 + pmaddwd mm1, mm5 + + paddd mm0, mm6 + paddd mm1, mm6 + + movd mm3, [ecx+ebp] + punpcklbw mm3, mm7 + movd mm2, [edx+ebp] + punpcklbw mm2, mm7 + movq mm4, mm3 + punpcklwd mm3, mm2 + movq mm5, [edi+8] + punpckhwd mm4, mm2 + pmaddwd mm3, mm5 + pmaddwd mm4, mm5 + + paddd mm0, mm3 + paddd mm1, mm4 + + psrad mm0, 14 + psrad mm1, 14 + packssdw mm0, mm1 + packuswb mm0, mm0 + add ebp, 4 + movd [esi], mm0 + add esi, 4 + cmp ebp, [esp + 12 + 16] + jb yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void __declspec(naked) vdasm_resize_table_col_8_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel, uint32 kwidth) { + static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; + + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov edi, [esp + 4 + 16] ;edi = dst + xor ebp, ebp +yloop: + mov edx, [esp + 16 + 16] ;edx = kernel + mov ebx, [esp + 8 + 16] ;ebx = srcs + mov esi, [esp + 20 + 16] ;esi = kwidth + movq mm3, mm6 + movq mm4, mm6 +xloop: + mov ecx, [ebx] + movd mm0, [ecx+ebp] + punpcklbw mm0, mm7 + mov ecx, [ebx+4] + movd mm2, [ecx+ebp] + punpcklbw mm2, mm7 + movq mm1, mm0 + punpcklwd mm0, mm2 + punpckhwd mm1, mm2 + movq mm5, [edx] + pmaddwd mm0, mm5 + pmaddwd mm1, mm5 + + paddd mm3, mm0 + paddd mm4, mm1 + add ebx, 8 + add edx, 8 + sub esi, 2 + jne xloop + + psrad mm3, 14 + psrad mm4, 14 + packssdw mm3, mm4 + packuswb mm3, mm3 + movd [edi], mm3 + add edi, 4 + add ebp, 4 + cmp ebp, [esp + 12 + 16] + jb yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void VDResamplerSeparableTableColStage8MMX::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + uint8 *dst = (uint8 *)dst0; + const uint8 *const *src = (const uint8 *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; + + int w4 = w & ~3; + + if (w4) { + switch(ksize) { + case 2: + vdasm_resize_table_col_8_k2_MMX(dst, (const void *const *)src, w4, filter); + break; + + case 4: + vdasm_resize_table_col_8_k4_MMX(dst, (const void *const *)src, w4, filter); + break; + + default: + vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); + break; + } + } + + for(uint32 i=w4; i>= 14; + + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + dst[i] = (uint8)b; + } +} + +/////////////////////////////////////////////////////////////////////////// + +VDResamplerSeparableTableColStageMMX::VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter) + : VDResamplerColStageSeparableTable32(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableColStageMMX::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { + vdasm_resize_table_col_MMX((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); +} + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE2, x86) +// +/////////////////////////////////////////////////////////////////////////// + +extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); +extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); +extern "C" void vdasm_resize_ccint_col_SSE2(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); + +VDResamplerSeparableCubicColStageSSE2::VDResamplerSeparableCubicColStageSSE2(double A) + : VDResamplerSeparableCubicColStageMMX(A) +{ +} + +void VDResamplerSeparableCubicColStageSSE2::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + vdasm_resize_ccint_col_SSE2(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); +} + +VDResamplerSeparableTableRowStageSSE2::VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter) + : VDResamplerSeparableTableRowStageMMX(filter) +{ +} + +void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) + : VDResamplerSeparableTableColStageMMX(filter) +{ +} + +void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { + vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); +} + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE4.1, x86) +// +/////////////////////////////////////////////////////////////////////////// + +VDResamplerSeparableTableRowStage8SSE41::VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter) + : VDResamplerRowStageSeparableTable32(filter) + , mLastSrcWidth(0) + , mLastDstWidth(0) + , mLastU(0) + , mLastDUDX(0) +{ + mAlignedKernelWidth = (GetWindowSize() + 15) & ~7; + mAlignedKernelSize = mAlignedKernelWidth + 16; +} + +void VDResamplerSeparableTableRowStage8SSE41::Init(const VDResamplerAxis& axis, uint32 srcw) { + uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; + + if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { + mLastSrcWidth = srcw; + mLastDstWidth = w; + mLastU = axis.u; + mLastDUDX = axis.dudx; + + RedoRowFilters(axis, w, srcw); + } +} + +void VDResamplerSeparableTableRowStage8SSE41::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { + int kstride = mFilterBank.size() >> 8; + int ksize = mAlignedKernelWidth; + int kesize = mAlignedKernelSize; + + mRowKernels.clear(); + mRowKernelSize = w * kesize; + + mRowKernels.resize(mRowKernelSize * 8, 0); + + for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { + sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; + int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 7) & ~7); + + mKernelSizeByOffset[byteOffset] = ksizeThisOffset; + + sint32 u = axis.u; + sint32 uoffmin = -byteOffset; + sint32 uoffmax = ((srcw + byteOffset + 7) & ~7) - byteOffset - ksizeThisOffset; + for(uint32 i=0; i> 16; + sint32 uoffset2 = ((uoffset + byteOffset) & ~7) - byteOffset; + + if (uoffset2 < uoffmin) + uoffset2 = uoffmin; + + if (uoffset2 > uoffmax) + uoffset2 = uoffmax; + + *(sint32 *)dst = uoffset2; + dst += 2; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + + uint32 phase = (u >> 8) & 255; + const sint32 *src = &mFilterBank[kstride * phase]; + + sint32 start = 0; + sint32 end = kstride; + + int dstoffset = uoffset - uoffset2; + + // check for filter kernel overlapping left source boundary + if (uoffset < 0) + start = -uoffset; + + // check for filter kernel overlapping right source boundary + if (uoffset + end > (sint32)srcw) + end = srcw - uoffset; + + VDASSERT(dstoffset + start >= 0); + VDASSERT(dstoffset + end <= ksizeThisOffset); + + sint16 *dst2 = dst + dstoffset; + dst += ksizeThisOffset; + + for(int j=start; j 0) + dst2[start] = std::accumulate(src, src+start, dst2[start]); + + if (end < kstride) + dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); + + u += axis.dudx; + } + } + + // swizzle rows where optimization is possible + vdfastvector temp; + + int quads = w >> 2; + int quadRemainder = w & 3; + + for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { + int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; + int kpairs = ksizeThisOffset >> 3; + + if (ksizeThisOffset < 8 || ksizeThisOffset > 16) { + mbQuadOptimizationEnabled[byteOffset] = false; + } else { + ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 4; + + mbQuadOptimizationEnabled[byteOffset] = true; + mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); + + uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; + temp.resize(mRowKernelSize); + memcpy(temp.data(), dst, mRowKernelSize*2); + + const uint32 *src0 = (const uint32 *)temp.data(); + const uint32 *src1 = src0 + unswizzledStride; + const uint32 *src2 = src1 + unswizzledStride; + const uint32 *src3 = src2 + unswizzledStride; + ptrdiff_t srcskip = unswizzledStride * 3; + + for(int q = 0; q < quads; ++q) { + dst[0] = src0[0]; + dst[1] = src1[0]; + dst[2] = src2[0]; + dst[3] = src3[0]; + src0 += 4; + src1 += 4; + src2 += 4; + src3 += 4; + dst += 4; + + for(int p = 0; p < kpairs; ++p) { + dst[ 0] = src0[0]; + dst[ 1] = src0[1]; + dst[ 2] = src0[2]; + dst[ 3] = src0[3]; + dst[ 4] = src1[0]; + dst[ 5] = src1[1]; + dst[ 6] = src1[2]; + dst[ 7] = src1[3]; + dst[ 8] = src2[0]; + dst[ 9] = src2[1]; + dst[10] = src2[2]; + dst[11] = src2[3]; + dst[12] = src3[0]; + dst[13] = src3[1]; + dst[14] = src3[2]; + dst[15] = src3[3]; + dst += 16; + src0 += 4; + src1 += 4; + src2 += 4; + src3 += 4; + } + + src0 += srcskip; + src1 += srcskip; + src2 += srcskip; + src3 += srcskip; + } + + memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); + } + } +} + +void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w) { + int byteOffset = (int)(ptrdiff_t)src & 7; + const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); + + int ksize = mKernelSizeByOffset[byteOffset]; + if (mbQuadOptimizationEnabled[byteOffset]) { + if (w >= 4) { + if (ksize == 16) + vdasm_resize_table_row_8_k16_4x_SSE41(dst, src, w >> 2, ksrc); + else + vdasm_resize_table_row_8_k8_4x_SSE41(dst, src, w >> 2, ksrc); + } + + if (w & 3) + vdasm_resize_table_row_8_SSE41((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); + } else if (w) { + vdasm_resize_table_row_8_SSE41(dst, src, w, ksrc, ksize); + } +} + +void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +/////////////////////////////////////////////////////////////////////////// + +VDResamplerSeparableTableColStage8SSE41::VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter) + : VDResamplerColStageSeparableTable8(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableColStage8SSE41::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + uint8 *dst = (uint8 *)dst0; + const uint8 *const *src = (const uint8 *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; + + int w4 = w & ~3; + + if (w4) { + switch(ksize) { + case 2: + vdasm_resize_table_col_8_k2_SSE41(dst, (const void *const *)src, w4, filter); + break; + + case 4: + vdasm_resize_table_col_8_k4_SSE41(dst, (const void *const *)src, w4, filter); + break; + + default: + vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); + break; + } + } + + for(uint32 i=w4; i>= 14; + + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + dst[i] = (uint8)b; + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/stdafx.cpp b/src/thirdparty/VirtualDub/Kasumi/source/stdafx.cpp index 13d8f13506c..5b3adc67f38 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/stdafx.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/stdafx.cpp @@ -1,19 +1,19 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + #include "stdafx.h" \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/source/stretchblt_reference.cpp b/src/thirdparty/VirtualDub/Kasumi/source/stretchblt_reference.cpp index 19d140ee610..1774cdfdf3b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/stretchblt_reference.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/stretchblt_reference.cpp @@ -1,835 +1,835 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include - -namespace { - struct VDPixmapReferenceStretchBltParameters { - void *dst; - ptrdiff_t dstpitch; - const void *src; - ptrdiff_t srcpitch; - ptrdiff_t srcinc; - sint32 dx; - sint32 dy; - uint32 u; - uint32 uinc; - uint32 dudx; - uint32 v; - uint32 dvdy; - sint32 xprecopy; - sint32 xpostcopy; - ptrdiff_t xprepos; - ptrdiff_t xpostpos; - - void advance() { - dst = (char *)dst + dstpitch; - src = (char *)src + srcinc; - - uint32 vt = v + dvdy; - - if (vt < v) - src = (char *)src + srcpitch; - - v = vt; - } - }; -} - -void VDPixmapStretchBlt_Any8_nearest_reference(VDPixmapReferenceStretchBltParameters params) { - do { - uint8 *dstp = (uint8 *)params.dst; - const uint8 *srcp = (const uint8 *)params.src; - uint32 u = params.u; - - if (params.xprecopy) { - VDMemset8(dstp, *(const uint8 *)((const char *)params.src + params.xprepos), params.xprecopy); - dstp += params.xprecopy; - } - - sint32 wt = params.dx; - - if (wt > 0) - do { - *dstp++ = *srcp; - - uint32 ut = u + params.dudx; - srcp += ut 0) - do { - *dstp++ = *srcp; - - uint32 ut = u + params.dudx; - srcp += ut 0) - do { - dstp[0] = srcp[0]; - dstp[1] = srcp[1]; - dstp[2] = srcp[2]; - dstp += 3; - - uint32 ut = u + params.dudx; - srcp += (ut 0) - do { - *dstp++ = *srcp; - - uint32 ut = u + params.dudx; - srcp += ut= ulimit) - xprecopy = dx; - else - xmain = dx; - } else { - if (tdudx < 0) { - std::swap(ulo, uhi); - tdudx = -tdudx; - } - - if (ulo < 0) { - if (uhi < 0) - xprecopy = dx; - else - xprecopy = (sint32)((-ulo-1) / tdudx) + 1; - - VDASSERT(xprecopy <= 0 || (uint64)ulo >= (uint64)ulimit); - VDASSERT(xprecopy <= 0 || (uint64)(ulo + tdudx * (xprecopy-1)) >= (uint64)ulimit); - } - - if (uhi >= ulimit) { - if (ulo >= ulimit) - xpostcopy = dx; - else - xpostcopy = (sint32)((uhi - ulimit) / tdudx) + 1; - - VDASSERT(xpostcopy <= 0 || (uint64)uhi >= (uint64)ulimit); - VDASSERT(xpostcopy <= 0 || (uint64)(uhi - tdudx * (xpostcopy - 1)) >= (uint64)ulimit); - } - - if (dudx < 0) { - std::swap(xprecopy, xpostcopy); - std::swap(xprepos, xpostpos); - } - - xmain = dx - (xprecopy + xpostcopy); - } - - // sanity-check parameters - - VDASSERT(xprecopy>=0 && xprecopy <= dx); - VDASSERT(xpostcopy>=0 && xpostcopy <= dx); - VDASSERT(xmain>=0 && xmain <= dx); - - VDASSERT(xprecopy <= 0 || (uint64)u64 >= (uint64)ulimit); - VDASSERT(xprecopy <= 0 || (uint64)(u64 + dudx * (xprecopy-1)) >= (uint64)ulimit); - VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * xprecopy) < (uint64)ulimit); - VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * (xprecopy+xmain-1)) < (uint64)ulimit); - VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain)) >= (uint64)ulimit); - VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain + xpostcopy - 1)) >= (uint64)ulimit); - - u64 += dudx * xprecopy; - } -} - -bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { - // we don't support format conversion - if (dst.format != src.format) - return false; - - void (*pBlitter)(VDPixmapReferenceStretchBltParameters); - int bpp; - - switch(src.format) { - case nsVDPixmap::kPixFormat_Pal8: - pBlitter = VDPixmapStretchBlt_Any8_nearest_reference; - bpp = 1; - break; - case nsVDPixmap::kPixFormat_XRGB1555: - case nsVDPixmap::kPixFormat_RGB565: - pBlitter = VDPixmapStretchBlt_Any16_nearest_reference; - bpp = 2; - break; - case nsVDPixmap::kPixFormat_RGB888: - pBlitter = VDPixmapStretchBlt_Any24_nearest_reference; - bpp = 3; - break; - case nsVDPixmap::kPixFormat_XRGB8888: - pBlitter = VDPixmapStretchBlt_Any32_nearest_reference; - bpp = 4; - break; - default: - return false; - } - - // preemptive clip to prevent gradient calculations from crashing - if (x2 == x1 || y2 == y1) - return true; - - // translate destination flips into source flips - if (x1 > x2) { - std::swap(x1, x2); - std::swap(u1, u2); - } - - if (y1 > y2) { - std::swap(y1, y2); - std::swap(v1, v2); - } - - // compute gradients - sint32 dx = x2 - x1; - sint32 dy = y2 - y1; - sint32 du = u2 - u1; - sint32 dv = v2 - v1; - sint64 dudx = ((sint64)du << 32) / dx; // must truncate toward zero to prevent overflow - sint64 dvdy = ((sint64)dv << 32) / dy; - - // prestep top-left point to pixel center and convert destination coordinates to integer - sint64 u64 = (sint64)u1 << 16; - sint64 v64 = (sint64)v1 << 16; - sint32 prestepx = (0x8000 - x1) & 0xffff; - sint32 prestepy = (0x8000 - y1) & 0xffff; - - u64 += (dudx * prestepx) >> 16; - v64 += (dvdy * prestepy) >> 16; - - sint32 x1i = (x1 + 0x8000) >> 16; - sint32 y1i = (y1 + 0x8000) >> 16; - sint32 x2i = (x2 + 0x8000) >> 16; - sint32 y2i = (y2 + 0x8000) >> 16; - - // destination clipping - if (x1i < 0) { - u64 -= dudx * x1i; - x1i = 0; - } - - if (y1i < 0) { - v64 -= dvdy * y1i; - y1i = 0; - } - - if (x2i > dst.w) - x2i = dst.w; - - if (y2i > dst.h) - y2i = dst.h; - - if (x1i >= x2i || y1i >= y2i) - return true; - - // Calculate horizontal clip parameters - sint32 xprecopy = 0, xpostcopy = 0; - int xprepos = 0; - int xpostpos = src.w-1; - int xmain = 0; - - VDSetupNearestSamplingParameters(u64, dudx, x2i-x1i, src.w, xprecopy, xprepos, xmain, xpostcopy, xpostpos); - - // Calculate vertical clip parameters - sint32 yprecopy = 0, ypostcopy = 0; - int yprepos = 0; - int ypostpos = src.h-1; - int ymain = 0; - - VDSetupNearestSamplingParameters(v64, dvdy, y2i-y1i, src.h, yprecopy, yprepos, ymain, ypostcopy, ypostpos); - - // set up parameter block - VDPixmapReferenceStretchBltParameters params; - - char *srcbase = (char *)src.data + (sint32)(u64 >> 32) * bpp; - - params.dst = (char *)dst.data + y1i * dst.pitch + x1i * bpp; - params.dstpitch = dst.pitch; - params.src = srcbase + (sint32)(v64 >> 32) * src.pitch; - params.srcpitch = src.pitch; - params.srcinc = (sint32)(dvdy >> 32) * src.pitch; - params.dx = xmain; - params.dy = ymain; - params.u = (uint32)u64; - params.uinc = (uint32)(dudx >> 32); - params.dudx = (uint32)dudx; - params.v = (uint32)v64; - params.dvdy = (uint32)dvdy; - params.xprecopy = xprecopy; - params.xprepos = (xprepos - (sint32)(u64 >> 32)) * bpp; - params.xpostcopy = xpostcopy; - params.xpostpos = (xpostpos - (sint32)(u64 >> 32)) * bpp; - - if (yprecopy > 0) { - VDPixmapReferenceStretchBltParameters preparams(params); - - preparams.src = srcbase + yprepos * src.pitch; - preparams.srcinc = 0; - preparams.dy = yprecopy; - preparams.v = 0; - preparams.dvdy = 0; - - pBlitter(preparams); - - params.dst = (char *)params.dst + params.dstpitch * yprecopy; - } - - if (ymain > 0) - pBlitter(params); - - if (ypostcopy > 0) { - VDPixmapReferenceStretchBltParameters postparams(params); - - postparams.dst = (char *)params.dst + params.dstpitch * params.dy; - postparams.src = srcbase + ypostpos * src.pitch; - postparams.srcpitch = 0; - postparams.srcinc = 0; - postparams.dy = ypostcopy; - postparams.v = 0; - postparams.dvdy = 0; - - pBlitter(postparams); - } - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////// - -namespace { - uint32 lerp_XRGB1555(sint32 a, sint32 b, sint32 f) { - sint32 a_rb = a & 0x7c1f; - sint32 a_g = a & 0x03e0; - sint32 b_rb = b & 0x7c1f; - sint32 b_g = b & 0x03e0; - - const sint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x4010) >> 5)) & 0x7c1f; - const sint32 g = (a_g + (((b_g - a_g )*f + 0x0200) >> 5)) & 0x03e0; - - return rb + g; - } - - uint32 lerp_XRGB8888(sint32 a, sint32 b, sint32 f) { - sint32 a_rb = a & 0xff00ff; - sint32 a_g = a & 0x00ff00; - sint32 b_rb = b & 0xff00ff; - sint32 b_g = b & 0x00ff00; - - const uint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x00800080) >> 8)) & 0xff00ff; - const uint32 g = (a_g + (((b_g - a_g )*f + 0x00008000) >> 8)) & 0x00ff00; - - return rb + g; - } - - uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { - sint32 a_rb = a & 0xff00ff; - sint32 a_g = a & 0x00ff00; - sint32 b_rb = b & 0xff00ff; - sint32 b_g = b & 0x00ff00; - sint32 c_rb = c & 0xff00ff; - sint32 c_g = c & 0x00ff00; - sint32 d_rb = d & 0xff00ff; - sint32 d_g = d & 0x00ff00; - - const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; - const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 bot_g = (c_g + (((d_g - c_g )*x + 0x00008000) >> 8)) & 0x00ff00; - - const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff; - const uint32 final_g = (top_g + (((bot_g - top_g )*y) >> 8)) & 0x00ff00; - - return final_rb + final_g; - } - - uint32 bilerp_XRGB1555(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { - sint32 a_rb = a & 0x7c1f; - sint32 a_g = a & 0x03e0; - sint32 b_rb = b & 0x7c1f; - sint32 b_g = b & 0x03e0; - sint32 c_rb = c & 0x7c1f; - sint32 c_g = c & 0x03e0; - sint32 d_rb = d & 0x7c1f; - sint32 d_g = d & 0x03e0; - - const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x4010) >> 5)) & 0x7c1f; - const sint32 top_g = (a_g + (((b_g - a_g )*x + 0x0200) >> 5)) & 0x03e0; - const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x4010) >> 5)) & 0x7c1f; - const sint32 bot_g = (c_g + (((d_g - c_g )*x + 0x0200) >> 5)) & 0x03e0; - - const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x4010) >> 5)) & 0x7c1f; - const sint32 final_g = (top_g + (((bot_g - top_g )*y + 0x0200) >> 5)) & 0x03e0; - - return final_rb + final_g; - } - - uint32 bilerp_RGB565(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { - sint32 a_rb = a & 0xf81f; - sint32 a_g = a & 0x07e0; - sint32 b_rb = b & 0xf81f; - sint32 b_g = b & 0x07e0; - sint32 c_rb = c & 0xf81f; - sint32 c_g = c & 0x07e0; - sint32 d_rb = d & 0xf81f; - sint32 d_g = d & 0x07e0; - - const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x8010) >> 6)) & 0xf81f; - const sint32 top_g = (a_g + (((b_g - a_g )*x + 0x0400) >> 6)) & 0x07e0; - const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x8010) >> 6)) & 0xf81f; - const sint32 bot_g = (c_g + (((d_g - c_g )*x + 0x0400) >> 6)) & 0x07e0; - - const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x8010) >> 6)) & 0xf81f; - const sint32 final_g = (top_g + (((bot_g - top_g )*y + 0x0400) >> 6)) & 0x07e0; - - return final_rb + final_g; - } -} - -/////////////////////////////////////////////////////////////////////////// - -namespace { - struct VDPixmapReferenceStretchBltBilinearParameters { - void *dst; - const void *src; - uint32 u; - uint32 uinc; - uint32 dudx; - - ptrdiff_t xprepos; - ptrdiff_t xpostpos; - sint32 xprecopy; - sint32 xpostcopy; - sint32 xmidsize; - }; - - void VDPixmapStretchBiH_XRGB1555_to_XRGB1555(const VDPixmapReferenceStretchBltBilinearParameters& params) { - uint16 *dst = (uint16 *)params.dst; - const uint16 *src = (const uint16 *)params.src; - - if (params.xprecopy) - VDMemset16(dst - params.xprecopy, *(const uint16 *)((const char *)params.src + params.xprepos), params.xprecopy); - - if (params.xmidsize) { - sint32 w = params.xmidsize; - uint32 u = params.u; - const uint32 dudx = params.dudx; - const ptrdiff_t uinc = params.uinc; - - do { - *dst++ = lerp_XRGB1555(src[0], src[1], u >> 27); - - const uint32 ut = u + dudx; - src += uinc + (ut < u); - u = ut; - } while(--w); - } - - if (params.xpostcopy) - VDMemset16(dst, *(const uint16 *)((const char *)params.src + params.xpostpos), params.xpostcopy); - } - - void VDPixmapStretchBiH_XRGB8888_to_XRGB8888(const VDPixmapReferenceStretchBltBilinearParameters& params) { - uint32 *dst = (uint32 *)params.dst; - const uint32 *src = (const uint32 *)params.src; - - if (params.xprecopy) - VDMemset32(dst - params.xprecopy, *(const uint32 *)((const char *)params.src + params.xprepos), params.xprecopy); - - if (params.xmidsize) { - sint32 w = params.xmidsize; - uint32 u = params.u; - const uint32 dudx = params.dudx; - const ptrdiff_t uinc = params.uinc; - - do { - *dst++ = lerp_XRGB8888(src[0], src[1], u >> 24); - - const uint32 ut = u + dudx; - src += uinc + (ut < u); - u = ut; - } while(--w); - } - - if (params.xpostcopy) - VDMemset32(dst, *(const uint32 *)((const char *)params.src + params.xpostpos), params.xpostcopy); - } - - void VDPixmapStretchBiV_XRGB1555_to_XRGB1555(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) { - uint16 *dst = (uint16 *)dstv; - const uint16 *src1 = (const uint16 *)src1v; - const uint16 *src2 = (const uint16 *)src2v; - - f >>= 27; - - do { - *dst++ = lerp_XRGB1555(*src1++, *src2++, f); - } while(--w); - } - - void VDPixmapStretchBiV_XRGB8888_to_XRGB8888(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) { - uint32 *dst = (uint32 *)dstv; - const uint32 *src1 = (const uint32 *)src1v; - const uint32 *src2 = (const uint32 *)src2v; - - f >>= 24; - - do { - *dst++ = lerp_XRGB8888(*src1++, *src2++, f); - } while(--w); - } -} - -#ifdef _M_IX86 -extern "C" void vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX(const VDPixmapReferenceStretchBltBilinearParameters&); - -extern "C" void vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); -extern "C" void vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); -#endif - -bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { - // preemptive clip to prevent gradient calculations from crashing - if (x2 == x1 || y2 == y1) - return true; - - // we don't support source clipping - if ((uint32)u1 > (uint32)(src.w << 16) || (uint32)v1 > (uint32)(src.h << 16)) - return false; - - if ((uint32)u2 > (uint32)(src.w << 16) || (uint32)v2 > (uint32)(src.h << 16)) - return false; - - // we don't support format changes (yet) - if (dst.format != src.format) - return false; - - // format determination - void (*pHorizontalFilter)(const VDPixmapReferenceStretchBltBilinearParameters& params); - void (*pVerticalFilter)(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); - int bpp; - -#pragma vdpragma_TODO("fixme this is b0rken") - switch(src.format) { - case nsVDPixmap::kPixFormat_XRGB1555: - pHorizontalFilter = VDPixmapStretchBiH_XRGB1555_to_XRGB1555; -#ifdef _M_IX86 - if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) - pVerticalFilter = vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX; - else -#endif - pVerticalFilter = VDPixmapStretchBiV_XRGB1555_to_XRGB1555; - bpp = 2; - break; - case nsVDPixmap::kPixFormat_XRGB8888: -#ifdef _M_IX86 - if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) { - pHorizontalFilter = vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX; - pVerticalFilter = vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX; - } else -#endif - { - pHorizontalFilter = VDPixmapStretchBiH_XRGB8888_to_XRGB8888; - pVerticalFilter = VDPixmapStretchBiV_XRGB8888_to_XRGB8888; - } - bpp = 4; - break; - default: - return false; - } - - // translate destination flips into source flips - if (x1 > x2) { - std::swap(x1, x2); - std::swap(u1, u2); - } - - if (y1 > y2) { - std::swap(y1, y2); - std::swap(v1, v2); - } - - // compute gradients - sint32 dx = x2 - x1; - sint32 dy = y2 - y1; - sint32 du = u2 - u1; - sint32 dv = v2 - v1; - sint64 dudx = ((sint64)du << 32) / dx; // must truncate toward zero to prevent overflow - sint64 dvdy = ((sint64)dv << 32) / dy; - - // prestep top-left point to pixel center and convert destination coordinates to integer - sint64 u64 = (sint64)u1 << 16; - sint64 v64 = (sint64)v1 << 16; - sint32 prestepx = (0x8000 - x1) & 0xffff; - sint32 prestepy = (0x8000 - y1) & 0xffff; - - u64 += (dudx * prestepx) >> 16; - v64 += (dvdy * prestepy) >> 16; - - sint32 x1i = (x1 + 0x8000) >> 16; - sint32 y1i = (y1 + 0x8000) >> 16; - sint32 x2i = (x2 + 0x8000) >> 16; - sint32 y2i = (y2 + 0x8000) >> 16; - - // destination clipping - if (x1i < 0) { - u64 -= dudx * x1i; - x1i = 0; - } - - if (y1i < 0) { - v64 -= dvdy * y1i; - y1i = 0; - } - - if (x2i > dst.w) - x2i = dst.w; - - if (y2i > dst.h) - y2i = dst.h; - - if (x1i >= x2i || y1i >= y2i) - return true; - - u64 -= 0x80000000; - v64 -= 0x80000000; - - int xprepos = 0; - int xpostpos = src.w-1; - - sint64 ulo = u64; - sint64 uhi = u64 + dudx * (x2i - x1i - 1); - sint64 tdudx = dudx; - - if (ulo > uhi) { - std::swap(ulo, uhi); - tdudx = -tdudx; - } - - int xprecopy = 0; - int xpostcopy = 0; - - if (ulo < 0) { - xprecopy = (int)((1 - ulo) / tdudx) + 1; - } - - const sint64 ulimit = ((sint64)(src.w-1) << 32); - - if (uhi >= ulimit) - xpostcopy = (int)((uhi - ulimit - 1) / tdudx) + 1; - - if (dudx < 0) { - std::swap(xprecopy, xpostcopy); - std::swap(xprepos, xpostpos); - } - - u64 += dudx * xprecopy; - const int xtotal = x2i - x1i; - int xmidcopy = (x2i - x1i) - (xprecopy + xpostcopy); - const sint32 ui = (sint32)(u64 >> 32); - - // set up parameter block - - VDPixmapReferenceStretchBltBilinearParameters params; - - params.u = (uint32)u64; - params.uinc = (sint32)(dudx >> 32); - params.dudx = (sint32)dudx; - params.xprecopy = xprecopy; - params.xprepos = (xprepos - ui) * bpp; - params.xpostcopy = xpostcopy; - params.xpostpos = (xpostpos - ui) * bpp; - params.xmidsize = xmidcopy; - - void *dstp = (char *)dst.data + y1i * dst.pitch + x1i * bpp; - const void *srcp = (char *)src.data + ui * bpp; - - VDPixmapBuffer window(xtotal, 2, src.format); - - void *pTempRow1 = window.data; - void *pTempRow2 = (char *)window.data + window.pitch; - int windowbottom = dvdy > 0 ? -0x7fffffff : 0x7fffffff; - - do { - sint32 iv = (sint32)(v64 >> 32); - sint32 iv_bottom = iv + 1; - - if (iv < 0) - iv = iv_bottom = 0; - - if (iv >= src.h-1) - iv = iv_bottom = src.h-1; - - if (dvdy < 0) { - if (windowbottom > iv_bottom+1) - windowbottom = iv_bottom+1; - - while(windowbottom > iv) { - std::swap(pTempRow1, pTempRow2); - - --windowbottom; - - params.dst = (char *)pTempRow1 + bpp * params.xprecopy; - params.src = vdptroffset(srcp, windowbottom * src.pitch); - - pHorizontalFilter(params); - } - } else { - if (windowbottom < iv-1) - windowbottom = iv-1; - - while(windowbottom < iv_bottom) { - std::swap(pTempRow1, pTempRow2); - - ++windowbottom; - - params.dst = (char *)pTempRow2 + bpp * params.xprecopy; - params.src = vdptroffset(srcp, windowbottom * src.pitch); - - pHorizontalFilter(params); - } - } - - if (iv == iv_bottom) - if (dvdy < 0) - pVerticalFilter(dstp, pTempRow1, pTempRow1, xtotal, 0); - else - pVerticalFilter(dstp, pTempRow2, pTempRow2, xtotal, 0); - else - pVerticalFilter(dstp, pTempRow1, pTempRow2, xtotal, (uint32)v64); - - v64 += dvdy; - dstp = (char *)dstp + dst.pitch; - } while(++y1i < y2i); - - return true; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include + +namespace { + struct VDPixmapReferenceStretchBltParameters { + void *dst; + ptrdiff_t dstpitch; + const void *src; + ptrdiff_t srcpitch; + ptrdiff_t srcinc; + sint32 dx; + sint32 dy; + uint32 u; + uint32 uinc; + uint32 dudx; + uint32 v; + uint32 dvdy; + sint32 xprecopy; + sint32 xpostcopy; + ptrdiff_t xprepos; + ptrdiff_t xpostpos; + + void advance() { + dst = (char *)dst + dstpitch; + src = (char *)src + srcinc; + + uint32 vt = v + dvdy; + + if (vt < v) + src = (char *)src + srcpitch; + + v = vt; + } + }; +} + +void VDPixmapStretchBlt_Any8_nearest_reference(VDPixmapReferenceStretchBltParameters params) { + do { + uint8 *dstp = (uint8 *)params.dst; + const uint8 *srcp = (const uint8 *)params.src; + uint32 u = params.u; + + if (params.xprecopy) { + VDMemset8(dstp, *(const uint8 *)((const char *)params.src + params.xprepos), params.xprecopy); + dstp += params.xprecopy; + } + + sint32 wt = params.dx; + + if (wt > 0) + do { + *dstp++ = *srcp; + + uint32 ut = u + params.dudx; + srcp += ut 0) + do { + *dstp++ = *srcp; + + uint32 ut = u + params.dudx; + srcp += ut 0) + do { + dstp[0] = srcp[0]; + dstp[1] = srcp[1]; + dstp[2] = srcp[2]; + dstp += 3; + + uint32 ut = u + params.dudx; + srcp += (ut 0) + do { + *dstp++ = *srcp; + + uint32 ut = u + params.dudx; + srcp += ut= ulimit) + xprecopy = dx; + else + xmain = dx; + } else { + if (tdudx < 0) { + std::swap(ulo, uhi); + tdudx = -tdudx; + } + + if (ulo < 0) { + if (uhi < 0) + xprecopy = dx; + else + xprecopy = (sint32)((-ulo-1) / tdudx) + 1; + + VDASSERT(xprecopy <= 0 || (uint64)ulo >= (uint64)ulimit); + VDASSERT(xprecopy <= 0 || (uint64)(ulo + tdudx * (xprecopy-1)) >= (uint64)ulimit); + } + + if (uhi >= ulimit) { + if (ulo >= ulimit) + xpostcopy = dx; + else + xpostcopy = (sint32)((uhi - ulimit) / tdudx) + 1; + + VDASSERT(xpostcopy <= 0 || (uint64)uhi >= (uint64)ulimit); + VDASSERT(xpostcopy <= 0 || (uint64)(uhi - tdudx * (xpostcopy - 1)) >= (uint64)ulimit); + } + + if (dudx < 0) { + std::swap(xprecopy, xpostcopy); + std::swap(xprepos, xpostpos); + } + + xmain = dx - (xprecopy + xpostcopy); + } + + // sanity-check parameters + + VDASSERT(xprecopy>=0 && xprecopy <= dx); + VDASSERT(xpostcopy>=0 && xpostcopy <= dx); + VDASSERT(xmain>=0 && xmain <= dx); + + VDASSERT(xprecopy <= 0 || (uint64)u64 >= (uint64)ulimit); + VDASSERT(xprecopy <= 0 || (uint64)(u64 + dudx * (xprecopy-1)) >= (uint64)ulimit); + VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * xprecopy) < (uint64)ulimit); + VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * (xprecopy+xmain-1)) < (uint64)ulimit); + VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain)) >= (uint64)ulimit); + VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain + xpostcopy - 1)) >= (uint64)ulimit); + + u64 += dudx * xprecopy; + } +} + +bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { + // we don't support format conversion + if (dst.format != src.format) + return false; + + void (*pBlitter)(VDPixmapReferenceStretchBltParameters); + int bpp; + + switch(src.format) { + case nsVDPixmap::kPixFormat_Pal8: + pBlitter = VDPixmapStretchBlt_Any8_nearest_reference; + bpp = 1; + break; + case nsVDPixmap::kPixFormat_XRGB1555: + case nsVDPixmap::kPixFormat_RGB565: + pBlitter = VDPixmapStretchBlt_Any16_nearest_reference; + bpp = 2; + break; + case nsVDPixmap::kPixFormat_RGB888: + pBlitter = VDPixmapStretchBlt_Any24_nearest_reference; + bpp = 3; + break; + case nsVDPixmap::kPixFormat_XRGB8888: + pBlitter = VDPixmapStretchBlt_Any32_nearest_reference; + bpp = 4; + break; + default: + return false; + } + + // preemptive clip to prevent gradient calculations from crashing + if (x2 == x1 || y2 == y1) + return true; + + // translate destination flips into source flips + if (x1 > x2) { + std::swap(x1, x2); + std::swap(u1, u2); + } + + if (y1 > y2) { + std::swap(y1, y2); + std::swap(v1, v2); + } + + // compute gradients + sint32 dx = x2 - x1; + sint32 dy = y2 - y1; + sint32 du = u2 - u1; + sint32 dv = v2 - v1; + sint64 dudx = ((sint64)du << 32) / dx; // must truncate toward zero to prevent overflow + sint64 dvdy = ((sint64)dv << 32) / dy; + + // prestep top-left point to pixel center and convert destination coordinates to integer + sint64 u64 = (sint64)u1 << 16; + sint64 v64 = (sint64)v1 << 16; + sint32 prestepx = (0x8000 - x1) & 0xffff; + sint32 prestepy = (0x8000 - y1) & 0xffff; + + u64 += (dudx * prestepx) >> 16; + v64 += (dvdy * prestepy) >> 16; + + sint32 x1i = (x1 + 0x8000) >> 16; + sint32 y1i = (y1 + 0x8000) >> 16; + sint32 x2i = (x2 + 0x8000) >> 16; + sint32 y2i = (y2 + 0x8000) >> 16; + + // destination clipping + if (x1i < 0) { + u64 -= dudx * x1i; + x1i = 0; + } + + if (y1i < 0) { + v64 -= dvdy * y1i; + y1i = 0; + } + + if (x2i > dst.w) + x2i = dst.w; + + if (y2i > dst.h) + y2i = dst.h; + + if (x1i >= x2i || y1i >= y2i) + return true; + + // Calculate horizontal clip parameters + sint32 xprecopy = 0, xpostcopy = 0; + int xprepos = 0; + int xpostpos = src.w-1; + int xmain = 0; + + VDSetupNearestSamplingParameters(u64, dudx, x2i-x1i, src.w, xprecopy, xprepos, xmain, xpostcopy, xpostpos); + + // Calculate vertical clip parameters + sint32 yprecopy = 0, ypostcopy = 0; + int yprepos = 0; + int ypostpos = src.h-1; + int ymain = 0; + + VDSetupNearestSamplingParameters(v64, dvdy, y2i-y1i, src.h, yprecopy, yprepos, ymain, ypostcopy, ypostpos); + + // set up parameter block + VDPixmapReferenceStretchBltParameters params; + + char *srcbase = (char *)src.data + (sint32)(u64 >> 32) * bpp; + + params.dst = (char *)dst.data + y1i * dst.pitch + x1i * bpp; + params.dstpitch = dst.pitch; + params.src = srcbase + (sint32)(v64 >> 32) * src.pitch; + params.srcpitch = src.pitch; + params.srcinc = (sint32)(dvdy >> 32) * src.pitch; + params.dx = xmain; + params.dy = ymain; + params.u = (uint32)u64; + params.uinc = (uint32)(dudx >> 32); + params.dudx = (uint32)dudx; + params.v = (uint32)v64; + params.dvdy = (uint32)dvdy; + params.xprecopy = xprecopy; + params.xprepos = (xprepos - (sint32)(u64 >> 32)) * bpp; + params.xpostcopy = xpostcopy; + params.xpostpos = (xpostpos - (sint32)(u64 >> 32)) * bpp; + + if (yprecopy > 0) { + VDPixmapReferenceStretchBltParameters preparams(params); + + preparams.src = srcbase + yprepos * src.pitch; + preparams.srcinc = 0; + preparams.dy = yprecopy; + preparams.v = 0; + preparams.dvdy = 0; + + pBlitter(preparams); + + params.dst = (char *)params.dst + params.dstpitch * yprecopy; + } + + if (ymain > 0) + pBlitter(params); + + if (ypostcopy > 0) { + VDPixmapReferenceStretchBltParameters postparams(params); + + postparams.dst = (char *)params.dst + params.dstpitch * params.dy; + postparams.src = srcbase + ypostpos * src.pitch; + postparams.srcpitch = 0; + postparams.srcinc = 0; + postparams.dy = ypostcopy; + postparams.v = 0; + postparams.dvdy = 0; + + pBlitter(postparams); + } + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace { + uint32 lerp_XRGB1555(sint32 a, sint32 b, sint32 f) { + sint32 a_rb = a & 0x7c1f; + sint32 a_g = a & 0x03e0; + sint32 b_rb = b & 0x7c1f; + sint32 b_g = b & 0x03e0; + + const sint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x4010) >> 5)) & 0x7c1f; + const sint32 g = (a_g + (((b_g - a_g )*f + 0x0200) >> 5)) & 0x03e0; + + return rb + g; + } + + uint32 lerp_XRGB8888(sint32 a, sint32 b, sint32 f) { + sint32 a_rb = a & 0xff00ff; + sint32 a_g = a & 0x00ff00; + sint32 b_rb = b & 0xff00ff; + sint32 b_g = b & 0x00ff00; + + const uint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x00800080) >> 8)) & 0xff00ff; + const uint32 g = (a_g + (((b_g - a_g )*f + 0x00008000) >> 8)) & 0x00ff00; + + return rb + g; + } + + uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { + sint32 a_rb = a & 0xff00ff; + sint32 a_g = a & 0x00ff00; + sint32 b_rb = b & 0xff00ff; + sint32 b_g = b & 0x00ff00; + sint32 c_rb = c & 0xff00ff; + sint32 c_g = c & 0x00ff00; + sint32 d_rb = d & 0xff00ff; + sint32 d_g = d & 0x00ff00; + + const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; + const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 bot_g = (c_g + (((d_g - c_g )*x + 0x00008000) >> 8)) & 0x00ff00; + + const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff; + const uint32 final_g = (top_g + (((bot_g - top_g )*y) >> 8)) & 0x00ff00; + + return final_rb + final_g; + } + + uint32 bilerp_XRGB1555(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { + sint32 a_rb = a & 0x7c1f; + sint32 a_g = a & 0x03e0; + sint32 b_rb = b & 0x7c1f; + sint32 b_g = b & 0x03e0; + sint32 c_rb = c & 0x7c1f; + sint32 c_g = c & 0x03e0; + sint32 d_rb = d & 0x7c1f; + sint32 d_g = d & 0x03e0; + + const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x4010) >> 5)) & 0x7c1f; + const sint32 top_g = (a_g + (((b_g - a_g )*x + 0x0200) >> 5)) & 0x03e0; + const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x4010) >> 5)) & 0x7c1f; + const sint32 bot_g = (c_g + (((d_g - c_g )*x + 0x0200) >> 5)) & 0x03e0; + + const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x4010) >> 5)) & 0x7c1f; + const sint32 final_g = (top_g + (((bot_g - top_g )*y + 0x0200) >> 5)) & 0x03e0; + + return final_rb + final_g; + } + + uint32 bilerp_RGB565(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { + sint32 a_rb = a & 0xf81f; + sint32 a_g = a & 0x07e0; + sint32 b_rb = b & 0xf81f; + sint32 b_g = b & 0x07e0; + sint32 c_rb = c & 0xf81f; + sint32 c_g = c & 0x07e0; + sint32 d_rb = d & 0xf81f; + sint32 d_g = d & 0x07e0; + + const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x8010) >> 6)) & 0xf81f; + const sint32 top_g = (a_g + (((b_g - a_g )*x + 0x0400) >> 6)) & 0x07e0; + const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x8010) >> 6)) & 0xf81f; + const sint32 bot_g = (c_g + (((d_g - c_g )*x + 0x0400) >> 6)) & 0x07e0; + + const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x8010) >> 6)) & 0xf81f; + const sint32 final_g = (top_g + (((bot_g - top_g )*y + 0x0400) >> 6)) & 0x07e0; + + return final_rb + final_g; + } +} + +/////////////////////////////////////////////////////////////////////////// + +namespace { + struct VDPixmapReferenceStretchBltBilinearParameters { + void *dst; + const void *src; + uint32 u; + uint32 uinc; + uint32 dudx; + + ptrdiff_t xprepos; + ptrdiff_t xpostpos; + sint32 xprecopy; + sint32 xpostcopy; + sint32 xmidsize; + }; + + void VDPixmapStretchBiH_XRGB1555_to_XRGB1555(const VDPixmapReferenceStretchBltBilinearParameters& params) { + uint16 *dst = (uint16 *)params.dst; + const uint16 *src = (const uint16 *)params.src; + + if (params.xprecopy) + VDMemset16(dst - params.xprecopy, *(const uint16 *)((const char *)params.src + params.xprepos), params.xprecopy); + + if (params.xmidsize) { + sint32 w = params.xmidsize; + uint32 u = params.u; + const uint32 dudx = params.dudx; + const ptrdiff_t uinc = params.uinc; + + do { + *dst++ = lerp_XRGB1555(src[0], src[1], u >> 27); + + const uint32 ut = u + dudx; + src += uinc + (ut < u); + u = ut; + } while(--w); + } + + if (params.xpostcopy) + VDMemset16(dst, *(const uint16 *)((const char *)params.src + params.xpostpos), params.xpostcopy); + } + + void VDPixmapStretchBiH_XRGB8888_to_XRGB8888(const VDPixmapReferenceStretchBltBilinearParameters& params) { + uint32 *dst = (uint32 *)params.dst; + const uint32 *src = (const uint32 *)params.src; + + if (params.xprecopy) + VDMemset32(dst - params.xprecopy, *(const uint32 *)((const char *)params.src + params.xprepos), params.xprecopy); + + if (params.xmidsize) { + sint32 w = params.xmidsize; + uint32 u = params.u; + const uint32 dudx = params.dudx; + const ptrdiff_t uinc = params.uinc; + + do { + *dst++ = lerp_XRGB8888(src[0], src[1], u >> 24); + + const uint32 ut = u + dudx; + src += uinc + (ut < u); + u = ut; + } while(--w); + } + + if (params.xpostcopy) + VDMemset32(dst, *(const uint32 *)((const char *)params.src + params.xpostpos), params.xpostcopy); + } + + void VDPixmapStretchBiV_XRGB1555_to_XRGB1555(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) { + uint16 *dst = (uint16 *)dstv; + const uint16 *src1 = (const uint16 *)src1v; + const uint16 *src2 = (const uint16 *)src2v; + + f >>= 27; + + do { + *dst++ = lerp_XRGB1555(*src1++, *src2++, f); + } while(--w); + } + + void VDPixmapStretchBiV_XRGB8888_to_XRGB8888(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) { + uint32 *dst = (uint32 *)dstv; + const uint32 *src1 = (const uint32 *)src1v; + const uint32 *src2 = (const uint32 *)src2v; + + f >>= 24; + + do { + *dst++ = lerp_XRGB8888(*src1++, *src2++, f); + } while(--w); + } +} + +#ifdef _M_IX86 +extern "C" void vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX(const VDPixmapReferenceStretchBltBilinearParameters&); + +extern "C" void vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); +extern "C" void vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); +#endif + +bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { + // preemptive clip to prevent gradient calculations from crashing + if (x2 == x1 || y2 == y1) + return true; + + // we don't support source clipping + if ((uint32)u1 > (uint32)(src.w << 16) || (uint32)v1 > (uint32)(src.h << 16)) + return false; + + if ((uint32)u2 > (uint32)(src.w << 16) || (uint32)v2 > (uint32)(src.h << 16)) + return false; + + // we don't support format changes (yet) + if (dst.format != src.format) + return false; + + // format determination + void (*pHorizontalFilter)(const VDPixmapReferenceStretchBltBilinearParameters& params); + void (*pVerticalFilter)(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); + int bpp; + +#pragma vdpragma_TODO("fixme this is b0rken") + switch(src.format) { + case nsVDPixmap::kPixFormat_XRGB1555: + pHorizontalFilter = VDPixmapStretchBiH_XRGB1555_to_XRGB1555; +#ifdef _M_IX86 + if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) + pVerticalFilter = vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX; + else +#endif + pVerticalFilter = VDPixmapStretchBiV_XRGB1555_to_XRGB1555; + bpp = 2; + break; + case nsVDPixmap::kPixFormat_XRGB8888: +#ifdef _M_IX86 + if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) { + pHorizontalFilter = vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX; + pVerticalFilter = vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX; + } else +#endif + { + pHorizontalFilter = VDPixmapStretchBiH_XRGB8888_to_XRGB8888; + pVerticalFilter = VDPixmapStretchBiV_XRGB8888_to_XRGB8888; + } + bpp = 4; + break; + default: + return false; + } + + // translate destination flips into source flips + if (x1 > x2) { + std::swap(x1, x2); + std::swap(u1, u2); + } + + if (y1 > y2) { + std::swap(y1, y2); + std::swap(v1, v2); + } + + // compute gradients + sint32 dx = x2 - x1; + sint32 dy = y2 - y1; + sint32 du = u2 - u1; + sint32 dv = v2 - v1; + sint64 dudx = ((sint64)du << 32) / dx; // must truncate toward zero to prevent overflow + sint64 dvdy = ((sint64)dv << 32) / dy; + + // prestep top-left point to pixel center and convert destination coordinates to integer + sint64 u64 = (sint64)u1 << 16; + sint64 v64 = (sint64)v1 << 16; + sint32 prestepx = (0x8000 - x1) & 0xffff; + sint32 prestepy = (0x8000 - y1) & 0xffff; + + u64 += (dudx * prestepx) >> 16; + v64 += (dvdy * prestepy) >> 16; + + sint32 x1i = (x1 + 0x8000) >> 16; + sint32 y1i = (y1 + 0x8000) >> 16; + sint32 x2i = (x2 + 0x8000) >> 16; + sint32 y2i = (y2 + 0x8000) >> 16; + + // destination clipping + if (x1i < 0) { + u64 -= dudx * x1i; + x1i = 0; + } + + if (y1i < 0) { + v64 -= dvdy * y1i; + y1i = 0; + } + + if (x2i > dst.w) + x2i = dst.w; + + if (y2i > dst.h) + y2i = dst.h; + + if (x1i >= x2i || y1i >= y2i) + return true; + + u64 -= 0x80000000; + v64 -= 0x80000000; + + int xprepos = 0; + int xpostpos = src.w-1; + + sint64 ulo = u64; + sint64 uhi = u64 + dudx * (x2i - x1i - 1); + sint64 tdudx = dudx; + + if (ulo > uhi) { + std::swap(ulo, uhi); + tdudx = -tdudx; + } + + int xprecopy = 0; + int xpostcopy = 0; + + if (ulo < 0) { + xprecopy = (int)((1 - ulo) / tdudx) + 1; + } + + const sint64 ulimit = ((sint64)(src.w-1) << 32); + + if (uhi >= ulimit) + xpostcopy = (int)((uhi - ulimit - 1) / tdudx) + 1; + + if (dudx < 0) { + std::swap(xprecopy, xpostcopy); + std::swap(xprepos, xpostpos); + } + + u64 += dudx * xprecopy; + const int xtotal = x2i - x1i; + int xmidcopy = (x2i - x1i) - (xprecopy + xpostcopy); + const sint32 ui = (sint32)(u64 >> 32); + + // set up parameter block + + VDPixmapReferenceStretchBltBilinearParameters params; + + params.u = (uint32)u64; + params.uinc = (sint32)(dudx >> 32); + params.dudx = (sint32)dudx; + params.xprecopy = xprecopy; + params.xprepos = (xprepos - ui) * bpp; + params.xpostcopy = xpostcopy; + params.xpostpos = (xpostpos - ui) * bpp; + params.xmidsize = xmidcopy; + + void *dstp = (char *)dst.data + y1i * dst.pitch + x1i * bpp; + const void *srcp = (char *)src.data + ui * bpp; + + VDPixmapBuffer window(xtotal, 2, src.format); + + void *pTempRow1 = window.data; + void *pTempRow2 = (char *)window.data + window.pitch; + int windowbottom = dvdy > 0 ? -0x7fffffff : 0x7fffffff; + + do { + sint32 iv = (sint32)(v64 >> 32); + sint32 iv_bottom = iv + 1; + + if (iv < 0) + iv = iv_bottom = 0; + + if (iv >= src.h-1) + iv = iv_bottom = src.h-1; + + if (dvdy < 0) { + if (windowbottom > iv_bottom+1) + windowbottom = iv_bottom+1; + + while(windowbottom > iv) { + std::swap(pTempRow1, pTempRow2); + + --windowbottom; + + params.dst = (char *)pTempRow1 + bpp * params.xprecopy; + params.src = vdptroffset(srcp, windowbottom * src.pitch); + + pHorizontalFilter(params); + } + } else { + if (windowbottom < iv-1) + windowbottom = iv-1; + + while(windowbottom < iv_bottom) { + std::swap(pTempRow1, pTempRow2); + + ++windowbottom; + + params.dst = (char *)pTempRow2 + bpp * params.xprecopy; + params.src = vdptroffset(srcp, windowbottom * src.pitch); + + pHorizontalFilter(params); + } + } + + if (iv == iv_bottom) + if (dvdy < 0) + pVerticalFilter(dstp, pTempRow1, pTempRow1, xtotal, 0); + else + pVerticalFilter(dstp, pTempRow2, pTempRow2, xtotal, 0); + else + pVerticalFilter(dstp, pTempRow1, pTempRow2, xtotal, (uint32)v64); + + v64 += dvdy; + dstp = (char *)dstp + dst.pitch; + } while(++y1i < y2i); + + return true; +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/tables.cpp b/src/thirdparty/VirtualDub/Kasumi/source/tables.cpp index 4107ded9541..0d872aab354 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/tables.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/tables.cpp @@ -1,205 +1,205 @@ -// Automatically generated by Asuka 'maketables.'" DO NOT EDIT! - -#include -#include - -extern "C" const sint32 kVDCubicInterpTableFX14_075[256][4]={ - { 0, 16384, 0, 0 }, { -48, 16384, 48, 0 }, { -95, 16383, 97, -1 }, { -141, 16380, 147, -2 }, - { -186, 16375, 198, -3 }, { -231, 16371, 249, -5 }, { -275, 16365, 301, -7 }, { -318, 16357, 354, -9 }, - { -360, 16349, 407, -12 }, { -402, 16340, 461, -15 }, { -443, 16329, 516, -18 }, { -484, 16318, 572, -22 }, - { -523, 16305, 628, -26 }, { -562, 16291, 685, -30 }, { -601, 16278, 742, -35 }, { -638, 16262, 800, -40 }, - { -675, 16245, 859, -45 }, { -711, 16228, 918, -51 }, { -747, 16209, 978, -56 }, { -782, 16190, 1039, -63 }, - { -816, 16169, 1100, -69 }, { -849, 16147, 1162, -76 }, { -882, 16124, 1225, -83 }, { -915, 16101, 1288, -90 }, - { -946, 16077, 1351, -98 }, { -977, 16052, 1415, -106 }, { -1007, 16025, 1480, -114 }, { -1037, 15998, 1545, -122 }, - { -1066, 15970, 1611, -131 }, { -1094, 15940, 1678, -140 }, { -1122, 15910, 1745, -149 }, { -1149, 15879, 1812, -158 }, - { -1176, 15848, 1880, -168 }, { -1202, 15815, 1949, -178 }, { -1227, 15781, 2018, -188 }, { -1252, 15747, 2087, -198 }, - { -1276, 15712, 2157, -209 }, { -1300, 15676, 2228, -220 }, { -1323, 15639, 2299, -231 }, { -1345, 15601, 2370, -242 }, - { -1367, 15562, 2442, -253 }, { -1388, 15523, 2514, -265 }, { -1409, 15482, 2587, -276 }, { -1429, 15441, 2660, -288 }, - { -1448, 15399, 2734, -301 }, { -1467, 15356, 2808, -313 }, { -1486, 15312, 2883, -325 }, { -1504, 15268, 2958, -338 }, - { -1521, 15223, 3033, -351 }, { -1538, 15177, 3109, -364 }, { -1554, 15130, 3185, -377 }, { -1570, 15084, 3261, -391 }, - { -1585, 15035, 3338, -404 }, { -1600, 14986, 3416, -418 }, { -1614, 14936, 3493, -431 }, { -1627, 14885, 3571, -445 }, - { -1641, 14834, 3650, -459 }, { -1653, 14783, 3728, -474 }, { -1665, 14730, 3807, -488 }, { -1677, 14676, 3887, -502 }, - { -1688, 14623, 3966, -517 }, { -1699, 14568, 4046, -531 }, { -1709, 14512, 4127, -546 }, { -1719, 14457, 4207, -561 }, - { -1728, 14400, 4288, -576 }, { -1737, 14343, 4369, -591 }, { -1745, 14284, 4451, -606 }, { -1753, 14226, 4532, -621 }, - { -1760, 14167, 4614, -637 }, { -1767, 14107, 4696, -652 }, { -1774, 14047, 4779, -668 }, { -1780, 13986, 4861, -683 }, - { -1785, 13924, 4944, -699 }, { -1791, 13861, 5028, -714 }, { -1795, 13798, 5111, -730 }, { -1800, 13736, 5194, -746 }, - { -1804, 13671, 5278, -761 }, { -1807, 13606, 5362, -777 }, { -1810, 13541, 5446, -793 }, { -1813, 13475, 5531, -809 }, - { -1815, 13409, 5615, -825 }, { -1817, 13342, 5700, -841 }, { -1818, 13275, 5784, -857 }, { -1819, 13207, 5869, -873 }, - { -1820, 13139, 5954, -889 }, { -1820, 13069, 6040, -905 }, { -1820, 13000, 6125, -921 }, { -1820, 12930, 6211, -937 }, - { -1819, 12860, 6296, -953 }, { -1818, 12789, 6382, -969 }, { -1816, 12717, 6468, -985 }, { -1815, 12647, 6553, -1001 }, - { -1812, 12574, 6639, -1017 }, { -1810, 12502, 6725, -1033 }, { -1807, 12427, 6812, -1048 }, { -1804, 12354, 6898, -1064 }, - { -1800, 12280, 6984, -1080 }, { -1796, 12206, 7070, -1096 }, { -1792, 12130, 7157, -1111 }, { -1787, 12055, 7243, -1127 }, - { -1782, 11980, 7329, -1143 }, { -1777, 11903, 7416, -1158 }, { -1772, 11827, 7502, -1173 }, { -1766, 11751, 7588, -1189 }, - { -1760, 11673, 7675, -1204 }, { -1753, 11595, 7761, -1219 }, { -1747, 11517, 7848, -1234 }, { -1740, 11439, 7934, -1249 }, - { -1733, 11361, 8020, -1264 }, { -1725, 11281, 8107, -1279 }, { -1717, 11202, 8193, -1294 }, { -1709, 11123, 8279, -1309 }, - { -1701, 11043, 8365, -1323 }, { -1692, 10962, 8451, -1337 }, { -1684, 10883, 8537, -1352 }, { -1675, 10802, 8623, -1366 }, - { -1665, 10720, 8709, -1380 }, { -1656, 10640, 8794, -1394 }, { -1646, 10557, 8880, -1407 }, { -1636, 10476, 8965, -1421 }, - { -1626, 10393, 9051, -1434 }, { -1615, 10311, 9136, -1448 }, { -1604, 10228, 9221, -1461 }, { -1594, 10146, 9306, -1474 }, - { -1582, 10062, 9391, -1487 }, { -1571, 9979, 9475, -1499 }, { -1560, 9896, 9560, -1512 }, { -1548, 9812, 9644, -1524 }, - { -1536, 9728, 9728, -1536 }, { -1524, 9644, 9812, -1548 }, { -1512, 9560, 9896, -1560 }, { -1499, 9475, 9979, -1571 }, - { -1487, 9391, 10062, -1582 }, { -1474, 9306, 10146, -1594 }, { -1461, 9221, 10228, -1604 }, { -1448, 9136, 10311, -1615 }, - { -1434, 9051, 10393, -1626 }, { -1421, 8965, 10476, -1636 }, { -1407, 8880, 10557, -1646 }, { -1394, 8795, 10639, -1656 }, - { -1380, 8709, 10720, -1665 }, { -1366, 8624, 10801, -1675 }, { -1352, 8538, 10882, -1684 }, { -1337, 8450, 10963, -1692 }, - { -1323, 8365, 11043, -1701 }, { -1309, 8279, 11123, -1709 }, { -1294, 8192, 11203, -1717 }, { -1279, 8106, 11282, -1725 }, - { -1264, 8020, 11361, -1733 }, { -1249, 7934, 11439, -1740 }, { -1234, 7847, 11518, -1747 }, { -1219, 7760, 11596, -1753 }, - { -1204, 7675, 11673, -1760 }, { -1189, 7589, 11750, -1766 }, { -1173, 7502, 11827, -1772 }, { -1158, 7415, 11904, -1777 }, - { -1143, 7329, 11980, -1782 }, { -1127, 7243, 12055, -1787 }, { -1111, 7156, 12131, -1792 }, { -1096, 7070, 12206, -1796 }, - { -1080, 6984, 12280, -1800 }, { -1064, 6898, 12354, -1804 }, { -1048, 6811, 12428, -1807 }, { -1033, 6726, 12501, -1810 }, - { -1017, 6639, 12574, -1812 }, { -1001, 6554, 12646, -1815 }, { -985, 6467, 12718, -1816 }, { -969, 6382, 12789, -1818 }, - { -953, 6296, 12860, -1819 }, { -937, 6211, 12930, -1820 }, { -921, 6125, 13000, -1820 }, { -905, 6039, 13070, -1820 }, - { -889, 5954, 13139, -1820 }, { -873, 5869, 13207, -1819 }, { -857, 5784, 13275, -1818 }, { -841, 5700, 13342, -1817 }, - { -825, 5615, 13409, -1815 }, { -809, 5531, 13475, -1813 }, { -793, 5446, 13541, -1810 }, { -777, 5362, 13606, -1807 }, - { -761, 5278, 13671, -1804 }, { -746, 5195, 13735, -1800 }, { -730, 5111, 13798, -1795 }, { -714, 5028, 13861, -1791 }, - { -699, 4944, 13924, -1785 }, { -683, 4862, 13985, -1780 }, { -668, 4780, 14046, -1774 }, { -652, 4696, 14107, -1767 }, - { -637, 4614, 14167, -1760 }, { -621, 4532, 14226, -1753 }, { -606, 4450, 14285, -1745 }, { -591, 4369, 14343, -1737 }, - { -576, 4288, 14400, -1728 }, { -561, 4207, 14457, -1719 }, { -546, 4126, 14513, -1709 }, { -531, 4046, 14568, -1699 }, - { -517, 3966, 14623, -1688 }, { -502, 3886, 14677, -1677 }, { -488, 3807, 14730, -1665 }, { -474, 3728, 14783, -1653 }, - { -459, 3650, 14834, -1641 }, { -445, 3570, 14886, -1627 }, { -431, 3493, 14936, -1614 }, { -418, 3416, 14986, -1600 }, - { -404, 3338, 15035, -1585 }, { -391, 3262, 15083, -1570 }, { -377, 3185, 15130, -1554 }, { -364, 3109, 15177, -1538 }, - { -351, 3033, 15223, -1521 }, { -338, 2958, 15268, -1504 }, { -325, 2882, 15313, -1486 }, { -313, 2808, 15356, -1467 }, - { -301, 2734, 15399, -1448 }, { -288, 2660, 15441, -1429 }, { -276, 2587, 15482, -1409 }, { -265, 2514, 15523, -1388 }, - { -253, 2442, 15562, -1367 }, { -242, 2370, 15601, -1345 }, { -231, 2299, 15639, -1323 }, { -220, 2228, 15676, -1300 }, - { -209, 2157, 15712, -1276 }, { -198, 2087, 15747, -1252 }, { -188, 2017, 15782, -1227 }, { -178, 1949, 15815, -1202 }, - { -168, 1880, 15848, -1176 }, { -158, 1811, 15880, -1149 }, { -149, 1744, 15911, -1122 }, { -140, 1677, 15941, -1094 }, - { -131, 1611, 15970, -1066 }, { -122, 1545, 15998, -1037 }, { -114, 1480, 16025, -1007 }, { -106, 1415, 16052, -977 }, - { -98, 1351, 16077, -946 }, { -90, 1288, 16101, -915 }, { -83, 1224, 16125, -882 }, { -76, 1162, 16147, -849 }, - { -69, 1100, 16169, -816 }, { -63, 1040, 16189, -782 }, { -56, 978, 16209, -747 }, { -51, 919, 16227, -711 }, - { -45, 859, 16245, -675 }, { -40, 800, 16262, -638 }, { -35, 743, 16277, -601 }, { -30, 684, 16292, -562 }, - { -26, 628, 16305, -523 }, { -22, 572, 16318, -484 }, { -18, 516, 16329, -443 }, { -15, 462, 16339, -402 }, - { -12, 407, 16349, -360 }, { -9, 354, 16357, -318 }, { -7, 302, 16364, -275 }, { -5, 250, 16370, -231 }, - { -3, 198, 16375, -186 }, { -2, 148, 16379, -141 }, { -1, 98, 16382, -95 }, { 0, 49, 16383, -48 }, -}; - -#ifdef _M_IX86 -extern "C" const __declspec(align(16)) sint16 kVDCubicInterpTableFX14_075_MMX[256][8]={ - { 0, 16384, 0, 16384, 0, 0, 0, 0 }, { -48, 16384, -48, 16384, 48, 0, 48, 0 }, - { -95, 16383, -95, 16383, 97, -1, 97, -1 }, { -141, 16380, -141, 16380, 147, -2, 147, -2 }, - { -186, 16375, -186, 16375, 198, -3, 198, -3 }, { -231, 16371, -231, 16371, 249, -5, 249, -5 }, - { -275, 16365, -275, 16365, 301, -7, 301, -7 }, { -318, 16357, -318, 16357, 354, -9, 354, -9 }, - { -360, 16349, -360, 16349, 407, -12, 407, -12 }, { -402, 16340, -402, 16340, 461, -15, 461, -15 }, - { -443, 16329, -443, 16329, 516, -18, 516, -18 }, { -484, 16318, -484, 16318, 572, -22, 572, -22 }, - { -523, 16305, -523, 16305, 628, -26, 628, -26 }, { -562, 16291, -562, 16291, 685, -30, 685, -30 }, - { -601, 16278, -601, 16278, 742, -35, 742, -35 }, { -638, 16262, -638, 16262, 800, -40, 800, -40 }, - { -675, 16245, -675, 16245, 859, -45, 859, -45 }, { -711, 16228, -711, 16228, 918, -51, 918, -51 }, - { -747, 16209, -747, 16209, 978, -56, 978, -56 }, { -782, 16190, -782, 16190, 1039, -63, 1039, -63 }, - { -816, 16169, -816, 16169, 1100, -69, 1100, -69 }, { -849, 16147, -849, 16147, 1162, -76, 1162, -76 }, - { -882, 16124, -882, 16124, 1225, -83, 1225, -83 }, { -915, 16101, -915, 16101, 1288, -90, 1288, -90 }, - { -946, 16077, -946, 16077, 1351, -98, 1351, -98 }, { -977, 16052, -977, 16052, 1415, -106, 1415, -106 }, - { -1007, 16025, -1007, 16025, 1480, -114, 1480, -114 }, { -1037, 15998, -1037, 15998, 1545, -122, 1545, -122 }, - { -1066, 15970, -1066, 15970, 1611, -131, 1611, -131 }, { -1094, 15940, -1094, 15940, 1678, -140, 1678, -140 }, - { -1122, 15910, -1122, 15910, 1745, -149, 1745, -149 }, { -1149, 15879, -1149, 15879, 1812, -158, 1812, -158 }, - { -1176, 15848, -1176, 15848, 1880, -168, 1880, -168 }, { -1202, 15815, -1202, 15815, 1949, -178, 1949, -178 }, - { -1227, 15781, -1227, 15781, 2018, -188, 2018, -188 }, { -1252, 15747, -1252, 15747, 2087, -198, 2087, -198 }, - { -1276, 15712, -1276, 15712, 2157, -209, 2157, -209 }, { -1300, 15676, -1300, 15676, 2228, -220, 2228, -220 }, - { -1323, 15639, -1323, 15639, 2299, -231, 2299, -231 }, { -1345, 15601, -1345, 15601, 2370, -242, 2370, -242 }, - { -1367, 15562, -1367, 15562, 2442, -253, 2442, -253 }, { -1388, 15523, -1388, 15523, 2514, -265, 2514, -265 }, - { -1409, 15482, -1409, 15482, 2587, -276, 2587, -276 }, { -1429, 15441, -1429, 15441, 2660, -288, 2660, -288 }, - { -1448, 15399, -1448, 15399, 2734, -301, 2734, -301 }, { -1467, 15356, -1467, 15356, 2808, -313, 2808, -313 }, - { -1486, 15312, -1486, 15312, 2883, -325, 2883, -325 }, { -1504, 15268, -1504, 15268, 2958, -338, 2958, -338 }, - { -1521, 15223, -1521, 15223, 3033, -351, 3033, -351 }, { -1538, 15177, -1538, 15177, 3109, -364, 3109, -364 }, - { -1554, 15130, -1554, 15130, 3185, -377, 3185, -377 }, { -1570, 15084, -1570, 15084, 3261, -391, 3261, -391 }, - { -1585, 15035, -1585, 15035, 3338, -404, 3338, -404 }, { -1600, 14986, -1600, 14986, 3416, -418, 3416, -418 }, - { -1614, 14936, -1614, 14936, 3493, -431, 3493, -431 }, { -1627, 14885, -1627, 14885, 3571, -445, 3571, -445 }, - { -1641, 14834, -1641, 14834, 3650, -459, 3650, -459 }, { -1653, 14783, -1653, 14783, 3728, -474, 3728, -474 }, - { -1665, 14730, -1665, 14730, 3807, -488, 3807, -488 }, { -1677, 14676, -1677, 14676, 3887, -502, 3887, -502 }, - { -1688, 14623, -1688, 14623, 3966, -517, 3966, -517 }, { -1699, 14568, -1699, 14568, 4046, -531, 4046, -531 }, - { -1709, 14512, -1709, 14512, 4127, -546, 4127, -546 }, { -1719, 14457, -1719, 14457, 4207, -561, 4207, -561 }, - { -1728, 14400, -1728, 14400, 4288, -576, 4288, -576 }, { -1737, 14343, -1737, 14343, 4369, -591, 4369, -591 }, - { -1745, 14284, -1745, 14284, 4451, -606, 4451, -606 }, { -1753, 14226, -1753, 14226, 4532, -621, 4532, -621 }, - { -1760, 14167, -1760, 14167, 4614, -637, 4614, -637 }, { -1767, 14107, -1767, 14107, 4696, -652, 4696, -652 }, - { -1774, 14047, -1774, 14047, 4779, -668, 4779, -668 }, { -1780, 13986, -1780, 13986, 4861, -683, 4861, -683 }, - { -1785, 13924, -1785, 13924, 4944, -699, 4944, -699 }, { -1791, 13861, -1791, 13861, 5028, -714, 5028, -714 }, - { -1795, 13798, -1795, 13798, 5111, -730, 5111, -730 }, { -1800, 13736, -1800, 13736, 5194, -746, 5194, -746 }, - { -1804, 13671, -1804, 13671, 5278, -761, 5278, -761 }, { -1807, 13606, -1807, 13606, 5362, -777, 5362, -777 }, - { -1810, 13541, -1810, 13541, 5446, -793, 5446, -793 }, { -1813, 13475, -1813, 13475, 5531, -809, 5531, -809 }, - { -1815, 13409, -1815, 13409, 5615, -825, 5615, -825 }, { -1817, 13342, -1817, 13342, 5700, -841, 5700, -841 }, - { -1818, 13275, -1818, 13275, 5784, -857, 5784, -857 }, { -1819, 13207, -1819, 13207, 5869, -873, 5869, -873 }, - { -1820, 13139, -1820, 13139, 5954, -889, 5954, -889 }, { -1820, 13069, -1820, 13069, 6040, -905, 6040, -905 }, - { -1820, 13000, -1820, 13000, 6125, -921, 6125, -921 }, { -1820, 12930, -1820, 12930, 6211, -937, 6211, -937 }, - { -1819, 12860, -1819, 12860, 6296, -953, 6296, -953 }, { -1818, 12789, -1818, 12789, 6382, -969, 6382, -969 }, - { -1816, 12717, -1816, 12717, 6468, -985, 6468, -985 }, { -1815, 12647, -1815, 12647, 6553, -1001, 6553, -1001 }, - { -1812, 12574, -1812, 12574, 6639, -1017, 6639, -1017 }, { -1810, 12502, -1810, 12502, 6725, -1033, 6725, -1033 }, - { -1807, 12427, -1807, 12427, 6812, -1048, 6812, -1048 }, { -1804, 12354, -1804, 12354, 6898, -1064, 6898, -1064 }, - { -1800, 12280, -1800, 12280, 6984, -1080, 6984, -1080 }, { -1796, 12206, -1796, 12206, 7070, -1096, 7070, -1096 }, - { -1792, 12130, -1792, 12130, 7157, -1111, 7157, -1111 }, { -1787, 12055, -1787, 12055, 7243, -1127, 7243, -1127 }, - { -1782, 11980, -1782, 11980, 7329, -1143, 7329, -1143 }, { -1777, 11903, -1777, 11903, 7416, -1158, 7416, -1158 }, - { -1772, 11827, -1772, 11827, 7502, -1173, 7502, -1173 }, { -1766, 11751, -1766, 11751, 7588, -1189, 7588, -1189 }, - { -1760, 11673, -1760, 11673, 7675, -1204, 7675, -1204 }, { -1753, 11595, -1753, 11595, 7761, -1219, 7761, -1219 }, - { -1747, 11517, -1747, 11517, 7848, -1234, 7848, -1234 }, { -1740, 11439, -1740, 11439, 7934, -1249, 7934, -1249 }, - { -1733, 11361, -1733, 11361, 8020, -1264, 8020, -1264 }, { -1725, 11281, -1725, 11281, 8107, -1279, 8107, -1279 }, - { -1717, 11202, -1717, 11202, 8193, -1294, 8193, -1294 }, { -1709, 11123, -1709, 11123, 8279, -1309, 8279, -1309 }, - { -1701, 11043, -1701, 11043, 8365, -1323, 8365, -1323 }, { -1692, 10962, -1692, 10962, 8451, -1337, 8451, -1337 }, - { -1684, 10883, -1684, 10883, 8537, -1352, 8537, -1352 }, { -1675, 10802, -1675, 10802, 8623, -1366, 8623, -1366 }, - { -1665, 10720, -1665, 10720, 8709, -1380, 8709, -1380 }, { -1656, 10640, -1656, 10640, 8794, -1394, 8794, -1394 }, - { -1646, 10557, -1646, 10557, 8880, -1407, 8880, -1407 }, { -1636, 10476, -1636, 10476, 8965, -1421, 8965, -1421 }, - { -1626, 10393, -1626, 10393, 9051, -1434, 9051, -1434 }, { -1615, 10311, -1615, 10311, 9136, -1448, 9136, -1448 }, - { -1604, 10228, -1604, 10228, 9221, -1461, 9221, -1461 }, { -1594, 10146, -1594, 10146, 9306, -1474, 9306, -1474 }, - { -1582, 10062, -1582, 10062, 9391, -1487, 9391, -1487 }, { -1571, 9979, -1571, 9979, 9475, -1499, 9475, -1499 }, - { -1560, 9896, -1560, 9896, 9560, -1512, 9560, -1512 }, { -1548, 9812, -1548, 9812, 9644, -1524, 9644, -1524 }, - { -1536, 9728, -1536, 9728, 9728, -1536, 9728, -1536 }, { -1524, 9644, -1524, 9644, 9812, -1548, 9812, -1548 }, - { -1512, 9560, -1512, 9560, 9896, -1560, 9896, -1560 }, { -1499, 9475, -1499, 9475, 9979, -1571, 9979, -1571 }, - { -1487, 9391, -1487, 9391, 10062, -1582, 10062, -1582 }, { -1474, 9306, -1474, 9306, 10146, -1594, 10146, -1594 }, - { -1461, 9221, -1461, 9221, 10228, -1604, 10228, -1604 }, { -1448, 9136, -1448, 9136, 10311, -1615, 10311, -1615 }, - { -1434, 9051, -1434, 9051, 10393, -1626, 10393, -1626 }, { -1421, 8965, -1421, 8965, 10476, -1636, 10476, -1636 }, - { -1407, 8880, -1407, 8880, 10557, -1646, 10557, -1646 }, { -1394, 8795, -1394, 8795, 10639, -1656, 10639, -1656 }, - { -1380, 8709, -1380, 8709, 10720, -1665, 10720, -1665 }, { -1366, 8624, -1366, 8624, 10801, -1675, 10801, -1675 }, - { -1352, 8538, -1352, 8538, 10882, -1684, 10882, -1684 }, { -1337, 8450, -1337, 8450, 10963, -1692, 10963, -1692 }, - { -1323, 8365, -1323, 8365, 11043, -1701, 11043, -1701 }, { -1309, 8279, -1309, 8279, 11123, -1709, 11123, -1709 }, - { -1294, 8192, -1294, 8192, 11203, -1717, 11203, -1717 }, { -1279, 8106, -1279, 8106, 11282, -1725, 11282, -1725 }, - { -1264, 8020, -1264, 8020, 11361, -1733, 11361, -1733 }, { -1249, 7934, -1249, 7934, 11439, -1740, 11439, -1740 }, - { -1234, 7847, -1234, 7847, 11518, -1747, 11518, -1747 }, { -1219, 7760, -1219, 7760, 11596, -1753, 11596, -1753 }, - { -1204, 7675, -1204, 7675, 11673, -1760, 11673, -1760 }, { -1189, 7589, -1189, 7589, 11750, -1766, 11750, -1766 }, - { -1173, 7502, -1173, 7502, 11827, -1772, 11827, -1772 }, { -1158, 7415, -1158, 7415, 11904, -1777, 11904, -1777 }, - { -1143, 7329, -1143, 7329, 11980, -1782, 11980, -1782 }, { -1127, 7243, -1127, 7243, 12055, -1787, 12055, -1787 }, - { -1111, 7156, -1111, 7156, 12131, -1792, 12131, -1792 }, { -1096, 7070, -1096, 7070, 12206, -1796, 12206, -1796 }, - { -1080, 6984, -1080, 6984, 12280, -1800, 12280, -1800 }, { -1064, 6898, -1064, 6898, 12354, -1804, 12354, -1804 }, - { -1048, 6811, -1048, 6811, 12428, -1807, 12428, -1807 }, { -1033, 6726, -1033, 6726, 12501, -1810, 12501, -1810 }, - { -1017, 6639, -1017, 6639, 12574, -1812, 12574, -1812 }, { -1001, 6554, -1001, 6554, 12646, -1815, 12646, -1815 }, - { -985, 6467, -985, 6467, 12718, -1816, 12718, -1816 }, { -969, 6382, -969, 6382, 12789, -1818, 12789, -1818 }, - { -953, 6296, -953, 6296, 12860, -1819, 12860, -1819 }, { -937, 6211, -937, 6211, 12930, -1820, 12930, -1820 }, - { -921, 6125, -921, 6125, 13000, -1820, 13000, -1820 }, { -905, 6039, -905, 6039, 13070, -1820, 13070, -1820 }, - { -889, 5954, -889, 5954, 13139, -1820, 13139, -1820 }, { -873, 5869, -873, 5869, 13207, -1819, 13207, -1819 }, - { -857, 5784, -857, 5784, 13275, -1818, 13275, -1818 }, { -841, 5700, -841, 5700, 13342, -1817, 13342, -1817 }, - { -825, 5615, -825, 5615, 13409, -1815, 13409, -1815 }, { -809, 5531, -809, 5531, 13475, -1813, 13475, -1813 }, - { -793, 5446, -793, 5446, 13541, -1810, 13541, -1810 }, { -777, 5362, -777, 5362, 13606, -1807, 13606, -1807 }, - { -761, 5278, -761, 5278, 13671, -1804, 13671, -1804 }, { -746, 5195, -746, 5195, 13735, -1800, 13735, -1800 }, - { -730, 5111, -730, 5111, 13798, -1795, 13798, -1795 }, { -714, 5028, -714, 5028, 13861, -1791, 13861, -1791 }, - { -699, 4944, -699, 4944, 13924, -1785, 13924, -1785 }, { -683, 4862, -683, 4862, 13985, -1780, 13985, -1780 }, - { -668, 4780, -668, 4780, 14046, -1774, 14046, -1774 }, { -652, 4696, -652, 4696, 14107, -1767, 14107, -1767 }, - { -637, 4614, -637, 4614, 14167, -1760, 14167, -1760 }, { -621, 4532, -621, 4532, 14226, -1753, 14226, -1753 }, - { -606, 4450, -606, 4450, 14285, -1745, 14285, -1745 }, { -591, 4369, -591, 4369, 14343, -1737, 14343, -1737 }, - { -576, 4288, -576, 4288, 14400, -1728, 14400, -1728 }, { -561, 4207, -561, 4207, 14457, -1719, 14457, -1719 }, - { -546, 4126, -546, 4126, 14513, -1709, 14513, -1709 }, { -531, 4046, -531, 4046, 14568, -1699, 14568, -1699 }, - { -517, 3966, -517, 3966, 14623, -1688, 14623, -1688 }, { -502, 3886, -502, 3886, 14677, -1677, 14677, -1677 }, - { -488, 3807, -488, 3807, 14730, -1665, 14730, -1665 }, { -474, 3728, -474, 3728, 14783, -1653, 14783, -1653 }, - { -459, 3650, -459, 3650, 14834, -1641, 14834, -1641 }, { -445, 3570, -445, 3570, 14886, -1627, 14886, -1627 }, - { -431, 3493, -431, 3493, 14936, -1614, 14936, -1614 }, { -418, 3416, -418, 3416, 14986, -1600, 14986, -1600 }, - { -404, 3338, -404, 3338, 15035, -1585, 15035, -1585 }, { -391, 3262, -391, 3262, 15083, -1570, 15083, -1570 }, - { -377, 3185, -377, 3185, 15130, -1554, 15130, -1554 }, { -364, 3109, -364, 3109, 15177, -1538, 15177, -1538 }, - { -351, 3033, -351, 3033, 15223, -1521, 15223, -1521 }, { -338, 2958, -338, 2958, 15268, -1504, 15268, -1504 }, - { -325, 2882, -325, 2882, 15313, -1486, 15313, -1486 }, { -313, 2808, -313, 2808, 15356, -1467, 15356, -1467 }, - { -301, 2734, -301, 2734, 15399, -1448, 15399, -1448 }, { -288, 2660, -288, 2660, 15441, -1429, 15441, -1429 }, - { -276, 2587, -276, 2587, 15482, -1409, 15482, -1409 }, { -265, 2514, -265, 2514, 15523, -1388, 15523, -1388 }, - { -253, 2442, -253, 2442, 15562, -1367, 15562, -1367 }, { -242, 2370, -242, 2370, 15601, -1345, 15601, -1345 }, - { -231, 2299, -231, 2299, 15639, -1323, 15639, -1323 }, { -220, 2228, -220, 2228, 15676, -1300, 15676, -1300 }, - { -209, 2157, -209, 2157, 15712, -1276, 15712, -1276 }, { -198, 2087, -198, 2087, 15747, -1252, 15747, -1252 }, - { -188, 2017, -188, 2017, 15782, -1227, 15782, -1227 }, { -178, 1949, -178, 1949, 15815, -1202, 15815, -1202 }, - { -168, 1880, -168, 1880, 15848, -1176, 15848, -1176 }, { -158, 1811, -158, 1811, 15880, -1149, 15880, -1149 }, - { -149, 1744, -149, 1744, 15911, -1122, 15911, -1122 }, { -140, 1677, -140, 1677, 15941, -1094, 15941, -1094 }, - { -131, 1611, -131, 1611, 15970, -1066, 15970, -1066 }, { -122, 1545, -122, 1545, 15998, -1037, 15998, -1037 }, - { -114, 1480, -114, 1480, 16025, -1007, 16025, -1007 }, { -106, 1415, -106, 1415, 16052, -977, 16052, -977 }, - { -98, 1351, -98, 1351, 16077, -946, 16077, -946 }, { -90, 1288, -90, 1288, 16101, -915, 16101, -915 }, - { -83, 1224, -83, 1224, 16125, -882, 16125, -882 }, { -76, 1162, -76, 1162, 16147, -849, 16147, -849 }, - { -69, 1100, -69, 1100, 16169, -816, 16169, -816 }, { -63, 1040, -63, 1040, 16189, -782, 16189, -782 }, - { -56, 978, -56, 978, 16209, -747, 16209, -747 }, { -51, 919, -51, 919, 16227, -711, 16227, -711 }, - { -45, 859, -45, 859, 16245, -675, 16245, -675 }, { -40, 800, -40, 800, 16262, -638, 16262, -638 }, - { -35, 743, -35, 743, 16277, -601, 16277, -601 }, { -30, 684, -30, 684, 16292, -562, 16292, -562 }, - { -26, 628, -26, 628, 16305, -523, 16305, -523 }, { -22, 572, -22, 572, 16318, -484, 16318, -484 }, - { -18, 516, -18, 516, 16329, -443, 16329, -443 }, { -15, 462, -15, 462, 16339, -402, 16339, -402 }, - { -12, 407, -12, 407, 16349, -360, 16349, -360 }, { -9, 354, -9, 354, 16357, -318, 16357, -318 }, - { -7, 302, -7, 302, 16364, -275, 16364, -275 }, { -5, 250, -5, 250, 16370, -231, 16370, -231 }, - { -3, 198, -3, 198, 16375, -186, 16375, -186 }, { -2, 148, -2, 148, 16379, -141, 16379, -141 }, - { -1, 98, -1, 98, 16382, -95, 16382, -95 }, { 0, 49, 0, 49, 16383, -48, 16383, -48 }, -}; - -#endif +// Automatically generated by Asuka 'maketables.'" DO NOT EDIT! + +#include +#include + +extern "C" const sint32 kVDCubicInterpTableFX14_075[256][4]={ + { 0, 16384, 0, 0 }, { -48, 16384, 48, 0 }, { -95, 16383, 97, -1 }, { -141, 16380, 147, -2 }, + { -186, 16375, 198, -3 }, { -231, 16371, 249, -5 }, { -275, 16365, 301, -7 }, { -318, 16357, 354, -9 }, + { -360, 16349, 407, -12 }, { -402, 16340, 461, -15 }, { -443, 16329, 516, -18 }, { -484, 16318, 572, -22 }, + { -523, 16305, 628, -26 }, { -562, 16291, 685, -30 }, { -601, 16278, 742, -35 }, { -638, 16262, 800, -40 }, + { -675, 16245, 859, -45 }, { -711, 16228, 918, -51 }, { -747, 16209, 978, -56 }, { -782, 16190, 1039, -63 }, + { -816, 16169, 1100, -69 }, { -849, 16147, 1162, -76 }, { -882, 16124, 1225, -83 }, { -915, 16101, 1288, -90 }, + { -946, 16077, 1351, -98 }, { -977, 16052, 1415, -106 }, { -1007, 16025, 1480, -114 }, { -1037, 15998, 1545, -122 }, + { -1066, 15970, 1611, -131 }, { -1094, 15940, 1678, -140 }, { -1122, 15910, 1745, -149 }, { -1149, 15879, 1812, -158 }, + { -1176, 15848, 1880, -168 }, { -1202, 15815, 1949, -178 }, { -1227, 15781, 2018, -188 }, { -1252, 15747, 2087, -198 }, + { -1276, 15712, 2157, -209 }, { -1300, 15676, 2228, -220 }, { -1323, 15639, 2299, -231 }, { -1345, 15601, 2370, -242 }, + { -1367, 15562, 2442, -253 }, { -1388, 15523, 2514, -265 }, { -1409, 15482, 2587, -276 }, { -1429, 15441, 2660, -288 }, + { -1448, 15399, 2734, -301 }, { -1467, 15356, 2808, -313 }, { -1486, 15312, 2883, -325 }, { -1504, 15268, 2958, -338 }, + { -1521, 15223, 3033, -351 }, { -1538, 15177, 3109, -364 }, { -1554, 15130, 3185, -377 }, { -1570, 15084, 3261, -391 }, + { -1585, 15035, 3338, -404 }, { -1600, 14986, 3416, -418 }, { -1614, 14936, 3493, -431 }, { -1627, 14885, 3571, -445 }, + { -1641, 14834, 3650, -459 }, { -1653, 14783, 3728, -474 }, { -1665, 14730, 3807, -488 }, { -1677, 14676, 3887, -502 }, + { -1688, 14623, 3966, -517 }, { -1699, 14568, 4046, -531 }, { -1709, 14512, 4127, -546 }, { -1719, 14457, 4207, -561 }, + { -1728, 14400, 4288, -576 }, { -1737, 14343, 4369, -591 }, { -1745, 14284, 4451, -606 }, { -1753, 14226, 4532, -621 }, + { -1760, 14167, 4614, -637 }, { -1767, 14107, 4696, -652 }, { -1774, 14047, 4779, -668 }, { -1780, 13986, 4861, -683 }, + { -1785, 13924, 4944, -699 }, { -1791, 13861, 5028, -714 }, { -1795, 13798, 5111, -730 }, { -1800, 13736, 5194, -746 }, + { -1804, 13671, 5278, -761 }, { -1807, 13606, 5362, -777 }, { -1810, 13541, 5446, -793 }, { -1813, 13475, 5531, -809 }, + { -1815, 13409, 5615, -825 }, { -1817, 13342, 5700, -841 }, { -1818, 13275, 5784, -857 }, { -1819, 13207, 5869, -873 }, + { -1820, 13139, 5954, -889 }, { -1820, 13069, 6040, -905 }, { -1820, 13000, 6125, -921 }, { -1820, 12930, 6211, -937 }, + { -1819, 12860, 6296, -953 }, { -1818, 12789, 6382, -969 }, { -1816, 12717, 6468, -985 }, { -1815, 12647, 6553, -1001 }, + { -1812, 12574, 6639, -1017 }, { -1810, 12502, 6725, -1033 }, { -1807, 12427, 6812, -1048 }, { -1804, 12354, 6898, -1064 }, + { -1800, 12280, 6984, -1080 }, { -1796, 12206, 7070, -1096 }, { -1792, 12130, 7157, -1111 }, { -1787, 12055, 7243, -1127 }, + { -1782, 11980, 7329, -1143 }, { -1777, 11903, 7416, -1158 }, { -1772, 11827, 7502, -1173 }, { -1766, 11751, 7588, -1189 }, + { -1760, 11673, 7675, -1204 }, { -1753, 11595, 7761, -1219 }, { -1747, 11517, 7848, -1234 }, { -1740, 11439, 7934, -1249 }, + { -1733, 11361, 8020, -1264 }, { -1725, 11281, 8107, -1279 }, { -1717, 11202, 8193, -1294 }, { -1709, 11123, 8279, -1309 }, + { -1701, 11043, 8365, -1323 }, { -1692, 10962, 8451, -1337 }, { -1684, 10883, 8537, -1352 }, { -1675, 10802, 8623, -1366 }, + { -1665, 10720, 8709, -1380 }, { -1656, 10640, 8794, -1394 }, { -1646, 10557, 8880, -1407 }, { -1636, 10476, 8965, -1421 }, + { -1626, 10393, 9051, -1434 }, { -1615, 10311, 9136, -1448 }, { -1604, 10228, 9221, -1461 }, { -1594, 10146, 9306, -1474 }, + { -1582, 10062, 9391, -1487 }, { -1571, 9979, 9475, -1499 }, { -1560, 9896, 9560, -1512 }, { -1548, 9812, 9644, -1524 }, + { -1536, 9728, 9728, -1536 }, { -1524, 9644, 9812, -1548 }, { -1512, 9560, 9896, -1560 }, { -1499, 9475, 9979, -1571 }, + { -1487, 9391, 10062, -1582 }, { -1474, 9306, 10146, -1594 }, { -1461, 9221, 10228, -1604 }, { -1448, 9136, 10311, -1615 }, + { -1434, 9051, 10393, -1626 }, { -1421, 8965, 10476, -1636 }, { -1407, 8880, 10557, -1646 }, { -1394, 8795, 10639, -1656 }, + { -1380, 8709, 10720, -1665 }, { -1366, 8624, 10801, -1675 }, { -1352, 8538, 10882, -1684 }, { -1337, 8450, 10963, -1692 }, + { -1323, 8365, 11043, -1701 }, { -1309, 8279, 11123, -1709 }, { -1294, 8192, 11203, -1717 }, { -1279, 8106, 11282, -1725 }, + { -1264, 8020, 11361, -1733 }, { -1249, 7934, 11439, -1740 }, { -1234, 7847, 11518, -1747 }, { -1219, 7760, 11596, -1753 }, + { -1204, 7675, 11673, -1760 }, { -1189, 7589, 11750, -1766 }, { -1173, 7502, 11827, -1772 }, { -1158, 7415, 11904, -1777 }, + { -1143, 7329, 11980, -1782 }, { -1127, 7243, 12055, -1787 }, { -1111, 7156, 12131, -1792 }, { -1096, 7070, 12206, -1796 }, + { -1080, 6984, 12280, -1800 }, { -1064, 6898, 12354, -1804 }, { -1048, 6811, 12428, -1807 }, { -1033, 6726, 12501, -1810 }, + { -1017, 6639, 12574, -1812 }, { -1001, 6554, 12646, -1815 }, { -985, 6467, 12718, -1816 }, { -969, 6382, 12789, -1818 }, + { -953, 6296, 12860, -1819 }, { -937, 6211, 12930, -1820 }, { -921, 6125, 13000, -1820 }, { -905, 6039, 13070, -1820 }, + { -889, 5954, 13139, -1820 }, { -873, 5869, 13207, -1819 }, { -857, 5784, 13275, -1818 }, { -841, 5700, 13342, -1817 }, + { -825, 5615, 13409, -1815 }, { -809, 5531, 13475, -1813 }, { -793, 5446, 13541, -1810 }, { -777, 5362, 13606, -1807 }, + { -761, 5278, 13671, -1804 }, { -746, 5195, 13735, -1800 }, { -730, 5111, 13798, -1795 }, { -714, 5028, 13861, -1791 }, + { -699, 4944, 13924, -1785 }, { -683, 4862, 13985, -1780 }, { -668, 4780, 14046, -1774 }, { -652, 4696, 14107, -1767 }, + { -637, 4614, 14167, -1760 }, { -621, 4532, 14226, -1753 }, { -606, 4450, 14285, -1745 }, { -591, 4369, 14343, -1737 }, + { -576, 4288, 14400, -1728 }, { -561, 4207, 14457, -1719 }, { -546, 4126, 14513, -1709 }, { -531, 4046, 14568, -1699 }, + { -517, 3966, 14623, -1688 }, { -502, 3886, 14677, -1677 }, { -488, 3807, 14730, -1665 }, { -474, 3728, 14783, -1653 }, + { -459, 3650, 14834, -1641 }, { -445, 3570, 14886, -1627 }, { -431, 3493, 14936, -1614 }, { -418, 3416, 14986, -1600 }, + { -404, 3338, 15035, -1585 }, { -391, 3262, 15083, -1570 }, { -377, 3185, 15130, -1554 }, { -364, 3109, 15177, -1538 }, + { -351, 3033, 15223, -1521 }, { -338, 2958, 15268, -1504 }, { -325, 2882, 15313, -1486 }, { -313, 2808, 15356, -1467 }, + { -301, 2734, 15399, -1448 }, { -288, 2660, 15441, -1429 }, { -276, 2587, 15482, -1409 }, { -265, 2514, 15523, -1388 }, + { -253, 2442, 15562, -1367 }, { -242, 2370, 15601, -1345 }, { -231, 2299, 15639, -1323 }, { -220, 2228, 15676, -1300 }, + { -209, 2157, 15712, -1276 }, { -198, 2087, 15747, -1252 }, { -188, 2017, 15782, -1227 }, { -178, 1949, 15815, -1202 }, + { -168, 1880, 15848, -1176 }, { -158, 1811, 15880, -1149 }, { -149, 1744, 15911, -1122 }, { -140, 1677, 15941, -1094 }, + { -131, 1611, 15970, -1066 }, { -122, 1545, 15998, -1037 }, { -114, 1480, 16025, -1007 }, { -106, 1415, 16052, -977 }, + { -98, 1351, 16077, -946 }, { -90, 1288, 16101, -915 }, { -83, 1224, 16125, -882 }, { -76, 1162, 16147, -849 }, + { -69, 1100, 16169, -816 }, { -63, 1040, 16189, -782 }, { -56, 978, 16209, -747 }, { -51, 919, 16227, -711 }, + { -45, 859, 16245, -675 }, { -40, 800, 16262, -638 }, { -35, 743, 16277, -601 }, { -30, 684, 16292, -562 }, + { -26, 628, 16305, -523 }, { -22, 572, 16318, -484 }, { -18, 516, 16329, -443 }, { -15, 462, 16339, -402 }, + { -12, 407, 16349, -360 }, { -9, 354, 16357, -318 }, { -7, 302, 16364, -275 }, { -5, 250, 16370, -231 }, + { -3, 198, 16375, -186 }, { -2, 148, 16379, -141 }, { -1, 98, 16382, -95 }, { 0, 49, 16383, -48 }, +}; + +#ifdef _M_IX86 +extern "C" const __declspec(align(16)) sint16 kVDCubicInterpTableFX14_075_MMX[256][8]={ + { 0, 16384, 0, 16384, 0, 0, 0, 0 }, { -48, 16384, -48, 16384, 48, 0, 48, 0 }, + { -95, 16383, -95, 16383, 97, -1, 97, -1 }, { -141, 16380, -141, 16380, 147, -2, 147, -2 }, + { -186, 16375, -186, 16375, 198, -3, 198, -3 }, { -231, 16371, -231, 16371, 249, -5, 249, -5 }, + { -275, 16365, -275, 16365, 301, -7, 301, -7 }, { -318, 16357, -318, 16357, 354, -9, 354, -9 }, + { -360, 16349, -360, 16349, 407, -12, 407, -12 }, { -402, 16340, -402, 16340, 461, -15, 461, -15 }, + { -443, 16329, -443, 16329, 516, -18, 516, -18 }, { -484, 16318, -484, 16318, 572, -22, 572, -22 }, + { -523, 16305, -523, 16305, 628, -26, 628, -26 }, { -562, 16291, -562, 16291, 685, -30, 685, -30 }, + { -601, 16278, -601, 16278, 742, -35, 742, -35 }, { -638, 16262, -638, 16262, 800, -40, 800, -40 }, + { -675, 16245, -675, 16245, 859, -45, 859, -45 }, { -711, 16228, -711, 16228, 918, -51, 918, -51 }, + { -747, 16209, -747, 16209, 978, -56, 978, -56 }, { -782, 16190, -782, 16190, 1039, -63, 1039, -63 }, + { -816, 16169, -816, 16169, 1100, -69, 1100, -69 }, { -849, 16147, -849, 16147, 1162, -76, 1162, -76 }, + { -882, 16124, -882, 16124, 1225, -83, 1225, -83 }, { -915, 16101, -915, 16101, 1288, -90, 1288, -90 }, + { -946, 16077, -946, 16077, 1351, -98, 1351, -98 }, { -977, 16052, -977, 16052, 1415, -106, 1415, -106 }, + { -1007, 16025, -1007, 16025, 1480, -114, 1480, -114 }, { -1037, 15998, -1037, 15998, 1545, -122, 1545, -122 }, + { -1066, 15970, -1066, 15970, 1611, -131, 1611, -131 }, { -1094, 15940, -1094, 15940, 1678, -140, 1678, -140 }, + { -1122, 15910, -1122, 15910, 1745, -149, 1745, -149 }, { -1149, 15879, -1149, 15879, 1812, -158, 1812, -158 }, + { -1176, 15848, -1176, 15848, 1880, -168, 1880, -168 }, { -1202, 15815, -1202, 15815, 1949, -178, 1949, -178 }, + { -1227, 15781, -1227, 15781, 2018, -188, 2018, -188 }, { -1252, 15747, -1252, 15747, 2087, -198, 2087, -198 }, + { -1276, 15712, -1276, 15712, 2157, -209, 2157, -209 }, { -1300, 15676, -1300, 15676, 2228, -220, 2228, -220 }, + { -1323, 15639, -1323, 15639, 2299, -231, 2299, -231 }, { -1345, 15601, -1345, 15601, 2370, -242, 2370, -242 }, + { -1367, 15562, -1367, 15562, 2442, -253, 2442, -253 }, { -1388, 15523, -1388, 15523, 2514, -265, 2514, -265 }, + { -1409, 15482, -1409, 15482, 2587, -276, 2587, -276 }, { -1429, 15441, -1429, 15441, 2660, -288, 2660, -288 }, + { -1448, 15399, -1448, 15399, 2734, -301, 2734, -301 }, { -1467, 15356, -1467, 15356, 2808, -313, 2808, -313 }, + { -1486, 15312, -1486, 15312, 2883, -325, 2883, -325 }, { -1504, 15268, -1504, 15268, 2958, -338, 2958, -338 }, + { -1521, 15223, -1521, 15223, 3033, -351, 3033, -351 }, { -1538, 15177, -1538, 15177, 3109, -364, 3109, -364 }, + { -1554, 15130, -1554, 15130, 3185, -377, 3185, -377 }, { -1570, 15084, -1570, 15084, 3261, -391, 3261, -391 }, + { -1585, 15035, -1585, 15035, 3338, -404, 3338, -404 }, { -1600, 14986, -1600, 14986, 3416, -418, 3416, -418 }, + { -1614, 14936, -1614, 14936, 3493, -431, 3493, -431 }, { -1627, 14885, -1627, 14885, 3571, -445, 3571, -445 }, + { -1641, 14834, -1641, 14834, 3650, -459, 3650, -459 }, { -1653, 14783, -1653, 14783, 3728, -474, 3728, -474 }, + { -1665, 14730, -1665, 14730, 3807, -488, 3807, -488 }, { -1677, 14676, -1677, 14676, 3887, -502, 3887, -502 }, + { -1688, 14623, -1688, 14623, 3966, -517, 3966, -517 }, { -1699, 14568, -1699, 14568, 4046, -531, 4046, -531 }, + { -1709, 14512, -1709, 14512, 4127, -546, 4127, -546 }, { -1719, 14457, -1719, 14457, 4207, -561, 4207, -561 }, + { -1728, 14400, -1728, 14400, 4288, -576, 4288, -576 }, { -1737, 14343, -1737, 14343, 4369, -591, 4369, -591 }, + { -1745, 14284, -1745, 14284, 4451, -606, 4451, -606 }, { -1753, 14226, -1753, 14226, 4532, -621, 4532, -621 }, + { -1760, 14167, -1760, 14167, 4614, -637, 4614, -637 }, { -1767, 14107, -1767, 14107, 4696, -652, 4696, -652 }, + { -1774, 14047, -1774, 14047, 4779, -668, 4779, -668 }, { -1780, 13986, -1780, 13986, 4861, -683, 4861, -683 }, + { -1785, 13924, -1785, 13924, 4944, -699, 4944, -699 }, { -1791, 13861, -1791, 13861, 5028, -714, 5028, -714 }, + { -1795, 13798, -1795, 13798, 5111, -730, 5111, -730 }, { -1800, 13736, -1800, 13736, 5194, -746, 5194, -746 }, + { -1804, 13671, -1804, 13671, 5278, -761, 5278, -761 }, { -1807, 13606, -1807, 13606, 5362, -777, 5362, -777 }, + { -1810, 13541, -1810, 13541, 5446, -793, 5446, -793 }, { -1813, 13475, -1813, 13475, 5531, -809, 5531, -809 }, + { -1815, 13409, -1815, 13409, 5615, -825, 5615, -825 }, { -1817, 13342, -1817, 13342, 5700, -841, 5700, -841 }, + { -1818, 13275, -1818, 13275, 5784, -857, 5784, -857 }, { -1819, 13207, -1819, 13207, 5869, -873, 5869, -873 }, + { -1820, 13139, -1820, 13139, 5954, -889, 5954, -889 }, { -1820, 13069, -1820, 13069, 6040, -905, 6040, -905 }, + { -1820, 13000, -1820, 13000, 6125, -921, 6125, -921 }, { -1820, 12930, -1820, 12930, 6211, -937, 6211, -937 }, + { -1819, 12860, -1819, 12860, 6296, -953, 6296, -953 }, { -1818, 12789, -1818, 12789, 6382, -969, 6382, -969 }, + { -1816, 12717, -1816, 12717, 6468, -985, 6468, -985 }, { -1815, 12647, -1815, 12647, 6553, -1001, 6553, -1001 }, + { -1812, 12574, -1812, 12574, 6639, -1017, 6639, -1017 }, { -1810, 12502, -1810, 12502, 6725, -1033, 6725, -1033 }, + { -1807, 12427, -1807, 12427, 6812, -1048, 6812, -1048 }, { -1804, 12354, -1804, 12354, 6898, -1064, 6898, -1064 }, + { -1800, 12280, -1800, 12280, 6984, -1080, 6984, -1080 }, { -1796, 12206, -1796, 12206, 7070, -1096, 7070, -1096 }, + { -1792, 12130, -1792, 12130, 7157, -1111, 7157, -1111 }, { -1787, 12055, -1787, 12055, 7243, -1127, 7243, -1127 }, + { -1782, 11980, -1782, 11980, 7329, -1143, 7329, -1143 }, { -1777, 11903, -1777, 11903, 7416, -1158, 7416, -1158 }, + { -1772, 11827, -1772, 11827, 7502, -1173, 7502, -1173 }, { -1766, 11751, -1766, 11751, 7588, -1189, 7588, -1189 }, + { -1760, 11673, -1760, 11673, 7675, -1204, 7675, -1204 }, { -1753, 11595, -1753, 11595, 7761, -1219, 7761, -1219 }, + { -1747, 11517, -1747, 11517, 7848, -1234, 7848, -1234 }, { -1740, 11439, -1740, 11439, 7934, -1249, 7934, -1249 }, + { -1733, 11361, -1733, 11361, 8020, -1264, 8020, -1264 }, { -1725, 11281, -1725, 11281, 8107, -1279, 8107, -1279 }, + { -1717, 11202, -1717, 11202, 8193, -1294, 8193, -1294 }, { -1709, 11123, -1709, 11123, 8279, -1309, 8279, -1309 }, + { -1701, 11043, -1701, 11043, 8365, -1323, 8365, -1323 }, { -1692, 10962, -1692, 10962, 8451, -1337, 8451, -1337 }, + { -1684, 10883, -1684, 10883, 8537, -1352, 8537, -1352 }, { -1675, 10802, -1675, 10802, 8623, -1366, 8623, -1366 }, + { -1665, 10720, -1665, 10720, 8709, -1380, 8709, -1380 }, { -1656, 10640, -1656, 10640, 8794, -1394, 8794, -1394 }, + { -1646, 10557, -1646, 10557, 8880, -1407, 8880, -1407 }, { -1636, 10476, -1636, 10476, 8965, -1421, 8965, -1421 }, + { -1626, 10393, -1626, 10393, 9051, -1434, 9051, -1434 }, { -1615, 10311, -1615, 10311, 9136, -1448, 9136, -1448 }, + { -1604, 10228, -1604, 10228, 9221, -1461, 9221, -1461 }, { -1594, 10146, -1594, 10146, 9306, -1474, 9306, -1474 }, + { -1582, 10062, -1582, 10062, 9391, -1487, 9391, -1487 }, { -1571, 9979, -1571, 9979, 9475, -1499, 9475, -1499 }, + { -1560, 9896, -1560, 9896, 9560, -1512, 9560, -1512 }, { -1548, 9812, -1548, 9812, 9644, -1524, 9644, -1524 }, + { -1536, 9728, -1536, 9728, 9728, -1536, 9728, -1536 }, { -1524, 9644, -1524, 9644, 9812, -1548, 9812, -1548 }, + { -1512, 9560, -1512, 9560, 9896, -1560, 9896, -1560 }, { -1499, 9475, -1499, 9475, 9979, -1571, 9979, -1571 }, + { -1487, 9391, -1487, 9391, 10062, -1582, 10062, -1582 }, { -1474, 9306, -1474, 9306, 10146, -1594, 10146, -1594 }, + { -1461, 9221, -1461, 9221, 10228, -1604, 10228, -1604 }, { -1448, 9136, -1448, 9136, 10311, -1615, 10311, -1615 }, + { -1434, 9051, -1434, 9051, 10393, -1626, 10393, -1626 }, { -1421, 8965, -1421, 8965, 10476, -1636, 10476, -1636 }, + { -1407, 8880, -1407, 8880, 10557, -1646, 10557, -1646 }, { -1394, 8795, -1394, 8795, 10639, -1656, 10639, -1656 }, + { -1380, 8709, -1380, 8709, 10720, -1665, 10720, -1665 }, { -1366, 8624, -1366, 8624, 10801, -1675, 10801, -1675 }, + { -1352, 8538, -1352, 8538, 10882, -1684, 10882, -1684 }, { -1337, 8450, -1337, 8450, 10963, -1692, 10963, -1692 }, + { -1323, 8365, -1323, 8365, 11043, -1701, 11043, -1701 }, { -1309, 8279, -1309, 8279, 11123, -1709, 11123, -1709 }, + { -1294, 8192, -1294, 8192, 11203, -1717, 11203, -1717 }, { -1279, 8106, -1279, 8106, 11282, -1725, 11282, -1725 }, + { -1264, 8020, -1264, 8020, 11361, -1733, 11361, -1733 }, { -1249, 7934, -1249, 7934, 11439, -1740, 11439, -1740 }, + { -1234, 7847, -1234, 7847, 11518, -1747, 11518, -1747 }, { -1219, 7760, -1219, 7760, 11596, -1753, 11596, -1753 }, + { -1204, 7675, -1204, 7675, 11673, -1760, 11673, -1760 }, { -1189, 7589, -1189, 7589, 11750, -1766, 11750, -1766 }, + { -1173, 7502, -1173, 7502, 11827, -1772, 11827, -1772 }, { -1158, 7415, -1158, 7415, 11904, -1777, 11904, -1777 }, + { -1143, 7329, -1143, 7329, 11980, -1782, 11980, -1782 }, { -1127, 7243, -1127, 7243, 12055, -1787, 12055, -1787 }, + { -1111, 7156, -1111, 7156, 12131, -1792, 12131, -1792 }, { -1096, 7070, -1096, 7070, 12206, -1796, 12206, -1796 }, + { -1080, 6984, -1080, 6984, 12280, -1800, 12280, -1800 }, { -1064, 6898, -1064, 6898, 12354, -1804, 12354, -1804 }, + { -1048, 6811, -1048, 6811, 12428, -1807, 12428, -1807 }, { -1033, 6726, -1033, 6726, 12501, -1810, 12501, -1810 }, + { -1017, 6639, -1017, 6639, 12574, -1812, 12574, -1812 }, { -1001, 6554, -1001, 6554, 12646, -1815, 12646, -1815 }, + { -985, 6467, -985, 6467, 12718, -1816, 12718, -1816 }, { -969, 6382, -969, 6382, 12789, -1818, 12789, -1818 }, + { -953, 6296, -953, 6296, 12860, -1819, 12860, -1819 }, { -937, 6211, -937, 6211, 12930, -1820, 12930, -1820 }, + { -921, 6125, -921, 6125, 13000, -1820, 13000, -1820 }, { -905, 6039, -905, 6039, 13070, -1820, 13070, -1820 }, + { -889, 5954, -889, 5954, 13139, -1820, 13139, -1820 }, { -873, 5869, -873, 5869, 13207, -1819, 13207, -1819 }, + { -857, 5784, -857, 5784, 13275, -1818, 13275, -1818 }, { -841, 5700, -841, 5700, 13342, -1817, 13342, -1817 }, + { -825, 5615, -825, 5615, 13409, -1815, 13409, -1815 }, { -809, 5531, -809, 5531, 13475, -1813, 13475, -1813 }, + { -793, 5446, -793, 5446, 13541, -1810, 13541, -1810 }, { -777, 5362, -777, 5362, 13606, -1807, 13606, -1807 }, + { -761, 5278, -761, 5278, 13671, -1804, 13671, -1804 }, { -746, 5195, -746, 5195, 13735, -1800, 13735, -1800 }, + { -730, 5111, -730, 5111, 13798, -1795, 13798, -1795 }, { -714, 5028, -714, 5028, 13861, -1791, 13861, -1791 }, + { -699, 4944, -699, 4944, 13924, -1785, 13924, -1785 }, { -683, 4862, -683, 4862, 13985, -1780, 13985, -1780 }, + { -668, 4780, -668, 4780, 14046, -1774, 14046, -1774 }, { -652, 4696, -652, 4696, 14107, -1767, 14107, -1767 }, + { -637, 4614, -637, 4614, 14167, -1760, 14167, -1760 }, { -621, 4532, -621, 4532, 14226, -1753, 14226, -1753 }, + { -606, 4450, -606, 4450, 14285, -1745, 14285, -1745 }, { -591, 4369, -591, 4369, 14343, -1737, 14343, -1737 }, + { -576, 4288, -576, 4288, 14400, -1728, 14400, -1728 }, { -561, 4207, -561, 4207, 14457, -1719, 14457, -1719 }, + { -546, 4126, -546, 4126, 14513, -1709, 14513, -1709 }, { -531, 4046, -531, 4046, 14568, -1699, 14568, -1699 }, + { -517, 3966, -517, 3966, 14623, -1688, 14623, -1688 }, { -502, 3886, -502, 3886, 14677, -1677, 14677, -1677 }, + { -488, 3807, -488, 3807, 14730, -1665, 14730, -1665 }, { -474, 3728, -474, 3728, 14783, -1653, 14783, -1653 }, + { -459, 3650, -459, 3650, 14834, -1641, 14834, -1641 }, { -445, 3570, -445, 3570, 14886, -1627, 14886, -1627 }, + { -431, 3493, -431, 3493, 14936, -1614, 14936, -1614 }, { -418, 3416, -418, 3416, 14986, -1600, 14986, -1600 }, + { -404, 3338, -404, 3338, 15035, -1585, 15035, -1585 }, { -391, 3262, -391, 3262, 15083, -1570, 15083, -1570 }, + { -377, 3185, -377, 3185, 15130, -1554, 15130, -1554 }, { -364, 3109, -364, 3109, 15177, -1538, 15177, -1538 }, + { -351, 3033, -351, 3033, 15223, -1521, 15223, -1521 }, { -338, 2958, -338, 2958, 15268, -1504, 15268, -1504 }, + { -325, 2882, -325, 2882, 15313, -1486, 15313, -1486 }, { -313, 2808, -313, 2808, 15356, -1467, 15356, -1467 }, + { -301, 2734, -301, 2734, 15399, -1448, 15399, -1448 }, { -288, 2660, -288, 2660, 15441, -1429, 15441, -1429 }, + { -276, 2587, -276, 2587, 15482, -1409, 15482, -1409 }, { -265, 2514, -265, 2514, 15523, -1388, 15523, -1388 }, + { -253, 2442, -253, 2442, 15562, -1367, 15562, -1367 }, { -242, 2370, -242, 2370, 15601, -1345, 15601, -1345 }, + { -231, 2299, -231, 2299, 15639, -1323, 15639, -1323 }, { -220, 2228, -220, 2228, 15676, -1300, 15676, -1300 }, + { -209, 2157, -209, 2157, 15712, -1276, 15712, -1276 }, { -198, 2087, -198, 2087, 15747, -1252, 15747, -1252 }, + { -188, 2017, -188, 2017, 15782, -1227, 15782, -1227 }, { -178, 1949, -178, 1949, 15815, -1202, 15815, -1202 }, + { -168, 1880, -168, 1880, 15848, -1176, 15848, -1176 }, { -158, 1811, -158, 1811, 15880, -1149, 15880, -1149 }, + { -149, 1744, -149, 1744, 15911, -1122, 15911, -1122 }, { -140, 1677, -140, 1677, 15941, -1094, 15941, -1094 }, + { -131, 1611, -131, 1611, 15970, -1066, 15970, -1066 }, { -122, 1545, -122, 1545, 15998, -1037, 15998, -1037 }, + { -114, 1480, -114, 1480, 16025, -1007, 16025, -1007 }, { -106, 1415, -106, 1415, 16052, -977, 16052, -977 }, + { -98, 1351, -98, 1351, 16077, -946, 16077, -946 }, { -90, 1288, -90, 1288, 16101, -915, 16101, -915 }, + { -83, 1224, -83, 1224, 16125, -882, 16125, -882 }, { -76, 1162, -76, 1162, 16147, -849, 16147, -849 }, + { -69, 1100, -69, 1100, 16169, -816, 16169, -816 }, { -63, 1040, -63, 1040, 16189, -782, 16189, -782 }, + { -56, 978, -56, 978, 16209, -747, 16209, -747 }, { -51, 919, -51, 919, 16227, -711, 16227, -711 }, + { -45, 859, -45, 859, 16245, -675, 16245, -675 }, { -40, 800, -40, 800, 16262, -638, 16262, -638 }, + { -35, 743, -35, 743, 16277, -601, 16277, -601 }, { -30, 684, -30, 684, 16292, -562, 16292, -562 }, + { -26, 628, -26, 628, 16305, -523, 16305, -523 }, { -22, 572, -22, 572, 16318, -484, 16318, -484 }, + { -18, 516, -18, 516, 16329, -443, 16329, -443 }, { -15, 462, -15, 462, 16339, -402, 16339, -402 }, + { -12, 407, -12, 407, 16349, -360, 16349, -360 }, { -9, 354, -9, 354, 16357, -318, 16357, -318 }, + { -7, 302, -7, 302, 16364, -275, 16364, -275 }, { -5, 250, -5, 250, 16370, -231, 16370, -231 }, + { -3, 198, -3, 198, 16375, -186, 16375, -186 }, { -2, 148, -2, 148, 16379, -141, 16379, -141 }, + { -1, 98, -1, 98, 16382, -95, 16382, -95 }, { 0, 49, 0, 49, 16383, -48, 16383, -48 }, +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/source/triblt.cpp b/src/thirdparty/VirtualDub/Kasumi/source/triblt.cpp index bf0752353a2..ffcff760ac8 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/triblt.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/triblt.cpp @@ -1,1760 +1,1760 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - uint32 lerp_RGB888(sint32 a, sint32 b, sint32 x) { - sint32 a_rb = a & 0xff00ff; - sint32 a_g = a & 0x00ff00; - sint32 b_rb = b & 0xff00ff; - sint32 b_g = b & 0x00ff00; - - const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; - - return top_rb + top_g; - } - - uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { - sint32 a_rb = a & 0xff00ff; - sint32 a_g = a & 0x00ff00; - sint32 b_rb = b & 0xff00ff; - sint32 b_g = b & 0x00ff00; - sint32 c_rb = c & 0xff00ff; - sint32 c_g = c & 0x00ff00; - sint32 d_rb = d & 0xff00ff; - sint32 d_g = d & 0x00ff00; - - const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; - const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 bot_g = (c_g + (((d_g - c_g )*x + 0x00008000) >> 8)) & 0x00ff00; - - const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff; - const uint32 final_g = (top_g + (((bot_g - top_g )*y) >> 8)) & 0x00ff00; - - return final_rb + final_g; - } - - uint32 bicubic_RGB888(const uint32 *src0, const uint32 *src1, const uint32 *src2, const uint32 *src3, sint32 x, sint32 y) { - const uint32 p00 = src0[0]; - const uint32 p01 = src0[1]; - const uint32 p02 = src0[2]; - const uint32 p03 = src0[3]; - const uint32 p10 = src1[0]; - const uint32 p11 = src1[1]; - const uint32 p12 = src1[2]; - const uint32 p13 = src1[3]; - const uint32 p20 = src2[0]; - const uint32 p21 = src2[1]; - const uint32 p22 = src2[2]; - const uint32 p23 = src2[3]; - const uint32 p30 = src3[0]; - const uint32 p31 = src3[1]; - const uint32 p32 = src3[2]; - const uint32 p33 = src3[3]; - - const sint32 *htab = kVDCubicInterpTableFX14_075[x]; - const sint32 *vtab = kVDCubicInterpTableFX14_075[y]; - - const int ch0 = htab[0]; - const int ch1 = htab[1]; - const int ch2 = htab[2]; - const int ch3 = htab[3]; - const int cv0 = vtab[0]; - const int cv1 = vtab[1]; - const int cv2 = vtab[2]; - const int cv3 = vtab[3]; - - int r0 = ((int)((p00>>16)&0xff) * ch0 + (int)((p01>>16)&0xff) * ch1 + (int)((p02>>16)&0xff) * ch2 + (int)((p03>>16)&0xff) * ch3 + 128) >> 8; - int g0 = ((int)((p00>> 8)&0xff) * ch0 + (int)((p01>> 8)&0xff) * ch1 + (int)((p02>> 8)&0xff) * ch2 + (int)((p03>> 8)&0xff) * ch3 + 128) >> 8; - int b0 = ((int)((p00 )&0xff) * ch0 + (int)((p01 )&0xff) * ch1 + (int)((p02 )&0xff) * ch2 + (int)((p03 )&0xff) * ch3 + 128) >> 8; - int r1 = ((int)((p10>>16)&0xff) * ch0 + (int)((p11>>16)&0xff) * ch1 + (int)((p12>>16)&0xff) * ch2 + (int)((p13>>16)&0xff) * ch3 + 128) >> 8; - int g1 = ((int)((p10>> 8)&0xff) * ch0 + (int)((p11>> 8)&0xff) * ch1 + (int)((p12>> 8)&0xff) * ch2 + (int)((p13>> 8)&0xff) * ch3 + 128) >> 8; - int b1 = ((int)((p10 )&0xff) * ch0 + (int)((p11 )&0xff) * ch1 + (int)((p12 )&0xff) * ch2 + (int)((p13 )&0xff) * ch3 + 128) >> 8; - int r2 = ((int)((p20>>16)&0xff) * ch0 + (int)((p21>>16)&0xff) * ch1 + (int)((p22>>16)&0xff) * ch2 + (int)((p23>>16)&0xff) * ch3 + 128) >> 8; - int g2 = ((int)((p20>> 8)&0xff) * ch0 + (int)((p21>> 8)&0xff) * ch1 + (int)((p22>> 8)&0xff) * ch2 + (int)((p23>> 8)&0xff) * ch3 + 128) >> 8; - int b2 = ((int)((p20 )&0xff) * ch0 + (int)((p21 )&0xff) * ch1 + (int)((p22 )&0xff) * ch2 + (int)((p23 )&0xff) * ch3 + 128) >> 8; - int r3 = ((int)((p30>>16)&0xff) * ch0 + (int)((p31>>16)&0xff) * ch1 + (int)((p32>>16)&0xff) * ch2 + (int)((p33>>16)&0xff) * ch3 + 128) >> 8; - int g3 = ((int)((p30>> 8)&0xff) * ch0 + (int)((p31>> 8)&0xff) * ch1 + (int)((p32>> 8)&0xff) * ch2 + (int)((p33>> 8)&0xff) * ch3 + 128) >> 8; - int b3 = ((int)((p30 )&0xff) * ch0 + (int)((p31 )&0xff) * ch1 + (int)((p32 )&0xff) * ch2 + (int)((p33 )&0xff) * ch3 + 128) >> 8; - - int r = (r0 * cv0 + r1 * cv1 + r2 * cv2 + r3 * cv3 + (1<<19)) >> 20; - int g = (g0 * cv0 + g1 * cv1 + g2 * cv2 + g3 * cv3 + (1<<19)) >> 20; - int b = (b0 * cv0 + b1 * cv1 + b2 * cv2 + b3 * cv3 + (1<<19)) >> 20; - - if (r<0) r=0; else if (r>255) r=255; - if (g<0) g=0; else if (g>255) g=255; - if (b<0) b=0; else if (b>255) b=255; - - return (r<<16) + (g<<8) + b; - } -} - -namespace { - enum { - kTop = 1, - kBottom = 2, - kLeft = 4, - kRight = 8, - kNear = 16, - kFar = 32 - }; - - struct VDTriBltMipInfo { - const uint32 *mip; - ptrdiff_t pitch; - uint32 uvmul, _pad; - }; - - struct VDTriBltInfo { - VDTriBltMipInfo mips[16]; - uint32 *dst; - const uint32 *src; - sint32 width; - const int *cubictab; - }; - - struct VDTriBltGenInfo { - float u; - float v; - float rhw; - float dudx; - float dvdx; - float drhwdx; - }; - - typedef void (*VDTriBltSpanFunction)(const VDTriBltInfo *); - typedef void (*VDTriBltGenFunction)(const VDTriBltGenInfo *); - - void vd_triblt_span_point(const VDTriBltInfo *pInfo) { - sint32 w = -pInfo->width; - uint32 *dst = pInfo->dst + pInfo->width; - const uint32 *src = pInfo->src; - const uint32 *texture = pInfo->mips[0].mip; - const ptrdiff_t texpitch = pInfo->mips[0].pitch; - - do { - dst[w] = vdptroffset(texture, texpitch * src[1])[src[0]]; - src += 2; - } while(++w); - } - - void vd_triblt_span_bilinear(const VDTriBltInfo *pInfo) { - sint32 w = -pInfo->width; - uint32 *dst = pInfo->dst + pInfo->width; - const uint32 *src = pInfo->src; - const uint32 *texture = pInfo->mips[0].mip; - const ptrdiff_t texpitch = pInfo->mips[0].pitch; - - do { - const sint32 u = src[0]; - const sint32 v = src[1]; - src += 2; - const uint32 *src1 = vdptroffset(texture, texpitch * (v>>8)) + (u>>8); - const uint32 *src2 = vdptroffset(src1, texpitch); - - dst[w] = bilerp_RGB888(src1[0], src1[1], src2[0], src2[1], u&255, v&255); - } while(++w); - } - - void vd_triblt_span_trilinear(const VDTriBltInfo *pInfo) { - sint32 w = -pInfo->width; - uint32 *dst = pInfo->dst + pInfo->width; - const uint32 *src = pInfo->src; - - do { - sint32 u = src[0]; - sint32 v = src[1]; - const sint32 lambda = src[2]; - src += 3; - - const sint32 lod = lambda >> 8; - - const uint32 *texture1 = pInfo->mips[lod].mip; - const ptrdiff_t texpitch1 = pInfo->mips[lod].pitch; - const uint32 *texture2 = pInfo->mips[lod+1].mip; - const ptrdiff_t texpitch2 = pInfo->mips[lod+1].pitch; - - u >>= lod; - v >>= lod; - - u += 128; - v += 128; - - const uint32 *src1 = vdptroffset(texture1, texpitch1 * (v>>8)) + (u>>8); - const uint32 *src2 = vdptroffset(src1, texpitch1); - const uint32 p1 = bilerp_RGB888(src1[0], src1[1], src2[0], src2[1], u&255, v&255); - - u += 128; - v += 128; - - const uint32 *src3 = vdptroffset(texture2, texpitch2 * (v>>9)) + (u>>9); - const uint32 *src4 = vdptroffset(src3, texpitch2); - const uint32 p2 = bilerp_RGB888(src3[0], src3[1], src4[0], src4[1], (u>>1)&255, (v>>1)&255); - - dst[w] = lerp_RGB888(p1, p2, lambda & 255); - } while(++w); - } - - void vd_triblt_span_bicubic_mip_linear(const VDTriBltInfo *pInfo) { - sint32 w = -pInfo->width; - uint32 *dst = pInfo->dst + pInfo->width; - const uint32 *src = pInfo->src; - - do { - sint32 u = src[0]; - sint32 v = src[1]; - const sint32 lambda = src[2]; - src += 3; - - const sint32 lod = lambda >> 8; - - const uint32 *texture1 = pInfo->mips[lod].mip; - const ptrdiff_t texpitch1 = pInfo->mips[lod].pitch; - const uint32 *texture2 = pInfo->mips[lod+1].mip; - const ptrdiff_t texpitch2 = pInfo->mips[lod+1].pitch; - - u >>= lod; - v >>= lod; - - u += 128; - v += 128; - - const uint32 *src1 = vdptroffset(texture1, texpitch1 * (v>>8)) + (u>>8); - const uint32 *src2 = vdptroffset(src1, texpitch1); - const uint32 *src3 = vdptroffset(src2, texpitch1); - const uint32 *src4 = vdptroffset(src3, texpitch1); - const uint32 p1 = bicubic_RGB888(src1, src2, src3, src4, u&255, v&255); - - u += 128; - v += 128; - - const uint32 *src5 = vdptroffset(texture2, texpitch2 * (v>>9)) + (u>>9); - const uint32 *src6 = vdptroffset(src5, texpitch2); - const uint32 *src7 = vdptroffset(src6, texpitch2); - const uint32 *src8 = vdptroffset(src7, texpitch2); - const uint32 p2 = bicubic_RGB888(src5, src6, src7, src8, (u>>1)&255, (v>>1)&255); - - dst[w] = lerp_RGB888(p1, p2, lambda & 255); - } while(++w); - } - -#ifdef _M_IX86 - extern "C" void vdasm_triblt_span_bilinear_mmx(const VDTriBltInfo *pInfo); - extern "C" void vdasm_triblt_span_trilinear_mmx(const VDTriBltInfo *pInfo); - extern "C" void vdasm_triblt_span_bicubic_mip_linear_mmx(const VDTriBltInfo *pInfo); - extern "C" void vdasm_triblt_span_bicubic_mip_linear_sse2(const VDTriBltInfo *pInfo); - extern "C" void vdasm_triblt_span_point(const VDTriBltInfo *pInfo); -#endif - - struct VDTriBltTransformedVertex { - float x, y, z; - union { - float w; - float rhw; - }; - float r, g, b, a; - float u, v; - int outcode; - - void interp(const VDTriBltTransformedVertex *v1, const VDTriBltTransformedVertex *v2, float alpha) { - x = v1->x + alpha * (v2->x - v1->x); - y = v1->y + alpha * (v2->y - v1->y); - z = v1->z + alpha * (v2->z - v1->z); - w = v1->w + alpha * (v2->w - v1->w); - - r = v1->r + alpha * (v2->r - v1->r); - g = v1->g + alpha * (v2->g - v1->g); - b = v1->b + alpha * (v2->b - v1->b); - a = v1->a + alpha * (v2->a - v1->a); - - u = v1->u + alpha * (v2->u - v1->u); - v = v1->v + alpha * (v2->v - v1->v); - - outcode = (x < -w ? kLeft : 0) - + (x > +w ? kRight : 0) - + (y < -w ? kTop : 0) - + (y > +w ? kBottom : 0) - + (z < -w ? kNear : 0) - + (z > +w ? kFar : 0); - } - }; - - void TransformVerts(VDTriBltTransformedVertex *dst, const VDTriBltVertex *src, int nVerts, const float xform[16]) { - const float xflocal[16]={ - xform[ 0], xform[ 1], xform[ 2], xform[ 3], - xform[ 4], xform[ 5], xform[ 6], xform[ 7], - xform[ 8], xform[ 9], xform[10], xform[11], - xform[12], xform[13], xform[14], xform[15], - }; - - if (nVerts <= 0) - return; - - do { - const float x0 = src->x; - const float y0 = src->y; - const float z0 = src->z; - - const float w = x0*xflocal[12] + y0*xflocal[13] + z0*xflocal[14] + xflocal[15]; - const float x = x0*xflocal[ 0] + y0*xflocal[ 1] + z0*xflocal[ 2] + xflocal[ 3]; - const float y = x0*xflocal[ 4] + y0*xflocal[ 5] + z0*xflocal[ 6] + xflocal[ 7]; - const float z = x0*xflocal[ 8] + y0*xflocal[ 9] + z0*xflocal[10] + xflocal[11]; - - int outcode = 0; - - if (x < -w) outcode += kLeft; - if (x > w) outcode += kRight; - if (y < -w) outcode += kTop; - if (y > w) outcode += kBottom; - if (z < -w) outcode += kNear; - if (z > w) outcode += kFar; - - dst->x = x; - dst->y = y; - dst->z = z; - dst->w = w; - dst->u = src->u; - dst->v = src->v; - dst->r = 1.0f; - dst->g = 1.0f; - dst->b = 1.0f; - dst->a = 1.0f; - dst->outcode = outcode; - - ++src; - ++dst; - } while(--nVerts); - } - - void TransformVerts(VDTriBltTransformedVertex *dst, const VDTriColorVertex *src, int nVerts, const float xform[16]) { - const float xflocal[16]={ - xform[ 0], xform[ 1], xform[ 2], xform[ 3], - xform[ 4], xform[ 5], xform[ 6], xform[ 7], - xform[ 8], xform[ 9], xform[10], xform[11], - xform[12], xform[13], xform[14], xform[15], - }; - - if (nVerts <= 0) - return; - - do { - const float x0 = src->x; - const float y0 = src->y; - const float z0 = src->z; - - const float w = x0*xflocal[12] + y0*xflocal[13] + z0*xflocal[14] + xflocal[15]; - const float x = x0*xflocal[ 0] + y0*xflocal[ 1] + z0*xflocal[ 2] + xflocal[ 3]; - const float y = x0*xflocal[ 4] + y0*xflocal[ 5] + z0*xflocal[ 6] + xflocal[ 7]; - const float z = x0*xflocal[ 8] + y0*xflocal[ 9] + z0*xflocal[10] + xflocal[11]; - - int outcode = 0; - - if (x < -w) outcode += kLeft; - if (x > w) outcode += kRight; - if (y < -w) outcode += kTop; - if (y > w) outcode += kBottom; - if (z < -w) outcode += kNear; - if (z > w) outcode += kFar; - - dst->x = x; - dst->y = y; - dst->z = z; - dst->w = w; - dst->u = 0.0f; - dst->v = 0.0f; - dst->r = src->r; - dst->g = src->g; - dst->b = src->b; - dst->a = src->a; - dst->outcode = outcode; - - ++src; - ++dst; - } while(--nVerts); - } - - struct VDTriangleSetupInfo { - const VDTriBltTransformedVertex *pt, *pr, *pl; - VDTriBltTransformedVertex tmp0, tmp1, tmp2; - }; - - void SetupTri( - VDTriangleSetupInfo& setup, - VDPixmap& dst, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2, - const VDTriBltFilterMode *filterMode - ) - { - setup.tmp0 = *vx0; - setup.tmp1 = *vx1; - setup.tmp2 = *vx2; - - // adjust UVs for filter mode - if (filterMode) { - switch(*filterMode) { - case kTriBltFilterBilinear: - setup.tmp0.u += 0.5f; - setup.tmp0.v += 0.5f; - setup.tmp1.u += 0.5f; - setup.tmp1.v += 0.5f; - setup.tmp2.u += 0.5f; - setup.tmp2.v += 0.5f; - case kTriBltFilterTrilinear: - case kTriBltFilterBicubicMipLinear: - setup.tmp0.u *= 256.0f; - setup.tmp0.v *= 256.0f; - setup.tmp1.u *= 256.0f; - setup.tmp1.v *= 256.0f; - setup.tmp2.u *= 256.0f; - setup.tmp2.v *= 256.0f; - break; - case kTriBltFilterPoint: - setup.tmp0.u += 1.0f; - setup.tmp0.v += 1.0f; - setup.tmp1.u += 1.0f; - setup.tmp1.v += 1.0f; - setup.tmp2.u += 1.0f; - setup.tmp2.v += 1.0f; - break; - } - } - - // do perspective divide and NDC space conversion - const float xscale = dst.w * 0.5f; - const float yscale = dst.h * 0.5f; - - setup.tmp0.rhw = 1.0f / setup.tmp0.w; - setup.tmp0.x = (1.0f+setup.tmp0.x*setup.tmp0.rhw)*xscale; - setup.tmp0.y = (1.0f+setup.tmp0.y*setup.tmp0.rhw)*yscale; - setup.tmp0.u *= setup.tmp0.rhw; - setup.tmp0.v *= setup.tmp0.rhw; - setup.tmp0.r *= setup.tmp0.rhw; - setup.tmp0.g *= setup.tmp0.rhw; - setup.tmp0.b *= setup.tmp0.rhw; - setup.tmp0.a *= setup.tmp0.rhw; - setup.tmp1.rhw = 1.0f / setup.tmp1.w; - setup.tmp1.x = (1.0f+setup.tmp1.x*setup.tmp1.rhw)*xscale; - setup.tmp1.y = (1.0f+setup.tmp1.y*setup.tmp1.rhw)*yscale; - setup.tmp1.u *= setup.tmp1.rhw; - setup.tmp1.v *= setup.tmp1.rhw; - setup.tmp1.r *= setup.tmp1.rhw; - setup.tmp1.g *= setup.tmp1.rhw; - setup.tmp1.b *= setup.tmp1.rhw; - setup.tmp1.a *= setup.tmp1.rhw; - setup.tmp2.rhw = 1.0f / setup.tmp2.w; - setup.tmp2.x = (1.0f+setup.tmp2.x*setup.tmp2.rhw)*xscale; - setup.tmp2.y = (1.0f+setup.tmp2.y*setup.tmp2.rhw)*yscale; - setup.tmp2.u *= setup.tmp2.rhw; - setup.tmp2.v *= setup.tmp2.rhw; - setup.tmp2.r *= setup.tmp2.rhw; - setup.tmp2.g *= setup.tmp2.rhw; - setup.tmp2.b *= setup.tmp2.rhw; - setup.tmp2.a *= setup.tmp2.rhw; - - // verify clipping - VDASSERT(setup.tmp0.x >= 0 && setup.tmp0.x <= dst.w); - VDASSERT(setup.tmp1.x >= 0 && setup.tmp1.x <= dst.w); - VDASSERT(setup.tmp2.x >= 0 && setup.tmp2.x <= dst.w); - VDASSERT(setup.tmp0.y >= 0 && setup.tmp0.y <= dst.h); - VDASSERT(setup.tmp1.y >= 0 && setup.tmp1.y <= dst.h); - VDASSERT(setup.tmp2.y >= 0 && setup.tmp2.y <= dst.h); - - vx0 = &setup.tmp0; - vx1 = &setup.tmp1; - vx2 = &setup.tmp2; - - const VDTriBltTransformedVertex *pt, *pl, *pr; - - // sort points - if (vx0->y < vx1->y) // 1 < 2 - if (vx0->y < vx2->y) { // 1 < 2,3 - pt = vx0; - pr = vx1; - pl = vx2; - } else { // 3 < 1 < 2 - pt = vx2; - pr = vx0; - pl = vx1; - } - else // 2 < 1 - if (vx1->y < vx2->y) { // 2 < 1,3 - pt = vx1; - pr = vx2; - pl = vx0; - } else { // 3 < 2 < 1 - pt = vx2; - pr = vx0; - pl = vx1; - } - - setup.pl = pl; - setup.pt = pt; - setup.pr = pr; - } - - void RenderTri(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2, - VDTriBltFilterMode filterMode, - float mipMapLODBias) - { - VDTriangleSetupInfo setup; - - SetupTri(setup, dst, vx0, vx1, vx2, &filterMode); - - const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; - - const float x10 = pl->x - pt->x; - const float x20 = pr->x - pt->x; - const float y10 = pl->y - pt->y; - const float y20 = pr->y - pt->y; - const float A = x20*y10 - x10*y20; - - if (A <= 0.f) - return; - - float invA = 0.f; - if (A >= 1e-5f) - invA = 1.0f / A; - - float x10_A = x10 * invA; - float x20_A = x20 * invA; - float y10_A = y10 * invA; - float y20_A = y20 * invA; - - float u10 = pl->u - pt->u; - float u20 = pr->u - pt->u; - float v10 = pl->v - pt->v; - float v20 = pr->v - pt->v; - float rhw10 = pl->rhw - pt->rhw; - float rhw20 = pr->rhw - pt->rhw; - - float dudx = u20*y10_A - u10*y20_A; - float dudy = u10*x20_A - u20*x10_A; - float dvdx = v20*y10_A - v10*y20_A; - float dvdy = v10*x20_A - v20*x10_A; - float drhwdx = rhw20*y10_A - rhw10*y20_A; - float drhwdy = rhw10*x20_A - rhw20*x10_A; - - // Compute edge walking parameters - - float dxl1=0, dxr1=0, dul1=0, dvl1=0, drhwl1=0; - float dxl2=0, dxr2=0, dul2=0, dvl2=0, drhwl2=0; - - // Compute left-edge interpolation parameters for first half. - - if (pl->y != pt->y) { - dxl1 = (pl->x - pt->x) / (pl->y - pt->y); - - dul1 = dudy + dxl1 * dudx; - dvl1 = dvdy + dxl1 * dvdx; - drhwl1 = drhwdy + dxl1 * drhwdx; - } - - // Compute right-edge interpolation parameters for first half. - - if (pr->y != pt->y) { - dxr1 = (pr->x - pt->x) / (pr->y - pt->y); - } - - // Compute third-edge interpolation parameters. - - if (pr->y != pl->y) { - dxl2 = (pr->x - pl->x) / (pr->y - pl->y); - - dul2 = dudy + dxl2 * dudx; - dvl2 = dvdy + dxl2 * dvdx; - drhwl2 = drhwdy + dxl2 * drhwdx; - - dxr2 = dxl2; - } - - // Initialize parameters for first half. - // - // We place pixel centers at (x+0.5, y+0.5). - - double xl, xr, ul, vl, rhwl, yf; - int y, y1, y2; - - // y_start < y+0.5 to include pixel y. - - y = (int)floor(pt->y + 0.5); - yf = (y+0.5) - pt->y; - - xl = pt->x + dxl1 * yf; - xr = pt->x + dxr1 * yf; - ul = pt->u + dul1 * yf; - vl = pt->v + dvl1 * yf; - rhwl = pt->rhw + drhwl1 * yf; - - // Initialize parameters for second half. - - double xl2, xr2, ul2, vl2, rhwl2; - - if (pl->y > pr->y) { // Left edge is long side - dxl2 = dxl1; - dul2 = dul1; - dvl2 = dvl1; - drhwl2 = drhwl1; - - y1 = (int)floor(pr->y + 0.5); - y2 = (int)floor(pl->y + 0.5); - - yf = (y1+0.5) - pr->y; - - // Step left edge. - - xl2 = xl + dxl1 * (y1 - y); - ul2 = ul + dul1 * (y1 - y); - vl2 = vl + dvl1 * (y1 - y); - rhwl2 = rhwl + drhwl1 * (y1 - y); - - // Prestep right edge. - - xr2 = pr->x + dxr2 * yf; - } else { // Right edge is long side - dxr2 = dxr1; - - y1 = (int)floor(pl->y + 0.5); - y2 = (int)floor(pr->y + 0.5); - - yf = (y1+0.5) - pl->y; - - // Prestep left edge. - - xl2 = pl->x + dxl2 * yf; - ul2 = pl->u + dul2 * yf; - vl2 = pl->v + dvl2 * yf; - rhwl2 = pl->rhw + drhwl2 * yf; - - // Step right edge. - - xr2 = xr + dxr1 * (y1 - y); - } - - // rasterize - const ptrdiff_t dstpitch = dst.pitch; - uint32 *dstp = (uint32 *)((char *)dst.data + dstpitch * y); - - VDTriBltInfo texinfo; - VDTriBltSpanFunction drawSpan; - uint32 cpuflags = CPUGetEnabledExtensions(); - - bool triBlt16 = false; - - switch(filterMode) { - case kTriBltFilterBicubicMipLinear: -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_SSE2) { - drawSpan = vdasm_triblt_span_bicubic_mip_linear_sse2; - triBlt16 = true; - } else if (cpuflags & CPUF_SUPPORTS_MMX) { - drawSpan = vdasm_triblt_span_bicubic_mip_linear_mmx; - triBlt16 = true; - } else -#endif - drawSpan = vd_triblt_span_bicubic_mip_linear; - break; - case kTriBltFilterTrilinear: -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_MMX) { - drawSpan = vdasm_triblt_span_trilinear_mmx; - triBlt16 = true; - } else -#endif - drawSpan = vd_triblt_span_trilinear; - break; - case kTriBltFilterBilinear: -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_MMX) { - drawSpan = vdasm_triblt_span_bilinear_mmx; - triBlt16 = true; - } else -#endif - drawSpan = vd_triblt_span_bilinear; - break; - case kTriBltFilterPoint: - drawSpan = vd_triblt_span_point; - break; - } - - float rhobase = sqrtf(std::max(dudx*dudx + dvdx*dvdx, dudy*dudy + dvdy*dvdy) * (1.0f / 65536.0f)) * powf(2.0f, mipMapLODBias); - - if (triBlt16) { - ul *= 256.0f; - vl *= 256.0f; - ul2 *= 256.0f; - vl2 *= 256.0f; - dul1 *= 256.0f; - dvl1 *= 256.0f; - dul2 *= 256.0f; - dvl2 *= 256.0f; - dudx *= 256.0f; - dvdx *= 256.0f; - dudy *= 256.0f; - dvdy *= 256.0f; - } - - int minx1 = (int)floor(std::min(std::min(pl->x, pr->x), pt->x) + 0.5); - int maxx2 = (int)floor(std::max(std::max(pl->x, pr->x), pt->x) + 0.5); - - uint32 *const spanptr = new uint32[3 * (maxx2 - minx1)]; - - while(y < y2) { - if (y == y1) { - xl = xl2; - xr = xr2; - ul = ul2; - vl = vl2; - rhwl = rhwl2; - dxl1 = dxl2; - dxr1 = dxr2; - dul1 = dul2; - dvl1 = dvl2; - drhwl1 = drhwl2; - } - - int x1, x2; - double xf; - double u, v, rhw; - - // x_left must be less than (x+0.5) to include pixel x. - - x1 = (int)floor(xl + 0.5); - x2 = (int)floor(xr + 0.5); - xf = (x1+0.5) - xl; - - u = ul + xf * dudx; - v = vl + xf * dvdx; - rhw = rhwl + xf * drhwdx; - - int x = x1; - uint32 *spanp = spanptr; - - float w = 1.0f / (float)rhw; - - if (x < x2) { - if (filterMode >= kTriBltFilterTrilinear) { - do { - int utexel = VDRoundToIntFastFullRange(u * w); - int vtexel = VDRoundToIntFastFullRange(v * w); - union{ float f; sint32 i; } rho = {rhobase * w}; - - int lambda = ((rho.i - 0x3F800000) >> (23-8)); - if (lambda < 0) - lambda = 0; - if (lambda >= (nMipmaps<<8)-256) - lambda = (nMipmaps<<8)-257; - - spanp[0] = utexel; - spanp[1] = vtexel; - spanp[2] = lambda; - spanp += 3; - - u += dudx; - v += dvdx; - rhw += drhwdx; - - w *= (2.0f - w*(float)rhw); - } while(++x < x2); - } else { - do { - int utexel = VDFloorToInt(u * w); - int vtexel = VDFloorToInt(v * w); - - spanp[0] = utexel; - spanp[1] = vtexel; - spanp += 2; - - u += dudx; - v += dvdx; - rhw += drhwdx; - - w *= (2.0f - w*(float)rhw); - } while(++x < x2); - } - } - - for(int i=0; idata; - texinfo.mips[i].pitch = pSources[i]->pitch; - texinfo.mips[i].uvmul = (pSources[i]->pitch << 16) + 4; - } - texinfo.dst = dstp+x1; - texinfo.src = spanptr; - texinfo.width = x2-x1; - - if (texinfo.width>0) - drawSpan(&texinfo); - - dstp = vdptroffset(dstp, dstpitch); - xl += dxl1; - xr += dxr1; - ul += dul1; - vl += dvl1; - rhwl += drhwl1; - - ++y; - } - - delete[] spanptr; - } - - void FillTri(VDPixmap& dst, uint32 c, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2 - ) - { - - VDTriangleSetupInfo setup; - - SetupTri(setup, dst, vx0, vx1, vx2, NULL); - - const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; - - // Compute edge walking parameters - float dxl1=0, dxr1=0; - float dxl2=0, dxr2=0; - - float x_lt = pl->x - pt->x; - float x_rt = pr->x - pt->x; - float x_rl = pr->x - pl->x; - float y_lt = pl->y - pt->y; - float y_rt = pr->y - pt->y; - float y_rl = pr->y - pl->y; - - // reject backfaces - if (x_lt*y_rt >= x_rt*y_lt) - return; - - // Compute left-edge interpolation parameters for first half. - if (pl->y != pt->y) - dxl1 = x_lt / y_lt; - - // Compute right-edge interpolation parameters for first half. - if (pr->y != pt->y) - dxr1 = x_rt / y_rt; - - // Compute third-edge interpolation parameters. - if (pr->y != pl->y) { - dxl2 = x_rl / y_rl; - - dxr2 = dxl2; - } - - // Initialize parameters for first half. - // - // We place pixel centers at (x+0.5, y+0.5). - - double xl, xr, yf; - int y, y1, y2; - - // y_start < y+0.5 to include pixel y. - - y = (int)floor(pt->y + 0.5); - yf = (y+0.5) - pt->y; - - xl = pt->x + dxl1 * yf; - xr = pt->x + dxr1 * yf; - - // Initialize parameters for second half. - double xl2, xr2; - - if (pl->y > pr->y) { // Left edge is long side - dxl2 = dxl1; - - y1 = (int)floor(pr->y + 0.5); - y2 = (int)floor(pl->y + 0.5); - - yf = (y1+0.5) - pr->y; - - // Prestep right edge. - xr2 = pr->x + dxr2 * yf; - - // Step left edge. - xl2 = xl + dxl1 * (y1 - y); - } else { // Right edge is long side - dxr2 = dxr1; - - y1 = (int)floor(pl->y + 0.5); - y2 = (int)floor(pr->y + 0.5); - - yf = (y1+0.5) - pl->y; - - // Prestep left edge. - xl2 = pl->x + dxl2 * yf; - - // Step right edge. - xr2 = xr + dxr1 * (y1 - y); - } - - // rasterize - const ptrdiff_t dstpitch = dst.pitch; - uint32 *dstp = (uint32 *)((char *)dst.data + dstpitch * y); - - while(y < y2) { - if (y == y1) { - xl = xl2; - xr = xr2; - dxl1 = dxl2; - dxr1 = dxr2; - } - - int x1, x2; - double xf; - - // x_left must be less than (x+0.5) to include pixel x. - - x1 = (int)floor(xl + 0.5); - x2 = (int)floor(xr + 0.5); - xf = (x1+0.5) - xl; - - while(x1 < x2) - dstp[x1++] = c; - - dstp = vdptroffset(dstp, dstpitch); - xl += dxl1; - xr += dxr1; - ++y; - } - } - - void FillTriGrad(VDPixmap& dst, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2 - ) - { - - VDTriangleSetupInfo setup; - - SetupTri(setup, dst, vx0, vx1, vx2, NULL); - - const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; - const float x10 = pl->x - pt->x; - const float x20 = pr->x - pt->x; - const float y10 = pl->y - pt->y; - const float y20 = pr->y - pt->y; - const float A = x20*y10 - x10*y20; - - if (A <= 0.f) - return; - - float invA = 0.f; - if (A >= 1e-5f) - invA = 1.0f / A; - - float x10_A = x10 * invA; - float x20_A = x20 * invA; - float y10_A = y10 * invA; - float y20_A = y20 * invA; - - float r10 = pl->r - pt->r; - float r20 = pr->r - pt->r; - float g10 = pl->g - pt->g; - float g20 = pr->g - pt->g; - float b10 = pl->b - pt->b; - float b20 = pr->b - pt->b; - float a10 = pl->a - pt->a; - float a20 = pr->a - pt->a; - float rhw10 = pl->rhw - pt->rhw; - float rhw20 = pr->rhw - pt->rhw; - - float drdx = r20*y10_A - r10*y20_A; - float drdy = r10*x20_A - r20*x10_A; - float dgdx = g20*y10_A - g10*y20_A; - float dgdy = g10*x20_A - g20*x10_A; - float dbdx = b20*y10_A - b10*y20_A; - float dbdy = b10*x20_A - b20*x10_A; - float dadx = a20*y10_A - a10*y20_A; - float dady = a10*x20_A - a20*x10_A; - float drhwdx = rhw20*y10_A - rhw10*y20_A; - float drhwdy = rhw10*x20_A - rhw20*x10_A; - - // Compute edge walking parameters - float dxl1=0; - float drl1=0; - float dgl1=0; - float dbl1=0; - float dal1=0; - float drhwl1=0; - float dxr1=0; - float dxl2=0; - float drl2=0; - float dgl2=0; - float dbl2=0; - float dal2=0; - float drhwl2=0; - float dxr2=0; - - float x_lt = pl->x - pt->x; - float x_rt = pr->x - pt->x; - float x_rl = pr->x - pl->x; - float y_lt = pl->y - pt->y; - float y_rt = pr->y - pt->y; - float y_rl = pr->y - pl->y; - - // Compute left-edge interpolation parameters for first half. - if (pl->y != pt->y) { - dxl1 = x_lt / y_lt; - drl1 = drdy + dxl1 * drdx; - dgl1 = dgdy + dxl1 * dgdx; - dbl1 = dbdy + dxl1 * dbdx; - dal1 = dady + dxl1 * dadx; - drhwl1 = drhwdy + dxl1 * drhwdx; - } - - // Compute right-edge interpolation parameters for first half. - if (pr->y != pt->y) - dxr1 = x_rt / y_rt; - - // Compute third-edge interpolation parameters. - if (pr->y != pl->y) { - dxl2 = x_rl / y_rl; - - drl2 = drdy + dxl2 * drdx; - dgl2 = dgdy + dxl2 * dgdx; - dbl2 = dbdy + dxl2 * dbdx; - dal2 = dady + dxl2 * dadx; - drhwl2 = drhwdy + dxl2 * drhwdx; - - dxr2 = dxl2; - } - - // Initialize parameters for first half. - // - // We place pixel centers at (x+0.5, y+0.5). - - double xl, xr, yf; - double rl, gl, bl, al, rhwl; - double rl2, gl2, bl2, al2, rhwl2; - int y, y1, y2; - - // y_start < y+0.5 to include pixel y. - - y = (int)floor(pt->y + 0.5); - yf = (y+0.5) - pt->y; - - xl = pt->x + dxl1 * yf; - xr = pt->x + dxr1 * yf; - rl = pt->r + drl1 * yf; - gl = pt->g + dgl1 * yf; - bl = pt->b + dbl1 * yf; - al = pt->a + dal1 * yf; - rhwl = pt->rhw + drhwl1 * yf; - - // Initialize parameters for second half. - double xl2, xr2; - - if (pl->y > pr->y) { // Left edge is long side - dxl2 = dxl1; - drl2 = drl1; - dgl2 = dgl1; - dbl2 = dbl1; - dal2 = dal1; - drhwl2 = drhwl1; - - y1 = (int)floor(pr->y + 0.5); - y2 = (int)floor(pl->y + 0.5); - - yf = (y1+0.5) - pr->y; - - // Step left edge. - xl2 = xl + dxl1 * (y1 - y); - rl2 = rl + drl1 * (y1 - y); - gl2 = gl + dgl1 * (y1 - y); - bl2 = bl + dbl1 * (y1 - y); - al2 = al + dal1 * (y1 - y); - rhwl2 = rhwl + drhwl1 * (y1 - y); - - // Prestep right edge. - xr2 = pr->x + dxr2 * yf; - } else { // Right edge is long side - dxr2 = dxr1; - - y1 = (int)floor(pl->y + 0.5); - y2 = (int)floor(pr->y + 0.5); - - yf = (y1+0.5) - pl->y; - - // Prestep left edge. - xl2 = pl->x + dxl2 * yf; - rl2 = pl->r + drl2 * yf; - gl2 = pl->g + dgl2 * yf; - bl2 = pl->b + dbl2 * yf; - al2 = pl->a + dal2 * yf; - rhwl2 = pl->rhw + drhwl2 * yf; - - // Step right edge. - xr2 = xr + dxr2 * (y1 - y); - } - - // rasterize - const ptrdiff_t dstpitch = dst.pitch; - char *dstp0 = (char *)dst.data + dstpitch * y; - - while(y < y2) { - if (y == y1) { - xl = xl2; - xr = xr2; - rl = rl2; - gl = gl2; - bl = bl2; - al = al2; - rhwl = rhwl2; - dxl1 = dxl2; - drl1 = drl2; - dgl1 = dgl2; - dbl1 = dbl2; - dal1 = dal2; - drhwl1 = drhwl2; - dxr1 = dxr2; - } - - int x1, x2; - double xf; - double r, g, b, a, rhw; - - // x_left must be less than (x+0.5) to include pixel x. - - x1 = (int)floor(xl + 0.5); - x2 = (int)floor(xr + 0.5); - xf = (x1+0.5) - xl; - - r = rl + xf * drdx; - g = gl + xf * dgdx; - b = bl + xf * dbdx; - a = al + xf * dadx; - rhw = rhwl + xf * drhwdx; - - float w = 1.0f / (float)rhw; - - if (x1 < x2) { - if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) { - uint32 *dstp = (uint32 *)dstp0; - - do { - float sr = (float)(r * w); - float sg = (float)(g * w); - float sb = (float)(b * w); - float sa = (float)(a * w); - - uint8 ir = VDClampedRoundFixedToUint8Fast(sr); - uint8 ig = VDClampedRoundFixedToUint8Fast(sg); - uint8 ib = VDClampedRoundFixedToUint8Fast(sb); - uint8 ia = VDClampedRoundFixedToUint8Fast(sa); - - dstp[x1] = ((uint32)ia << 24) + ((uint32)ir << 16) + ((uint32)ig << 8) + ib; - - r += drdx; - g += dgdx; - b += dbdx; - a += dadx; - rhw += drhwdx; - - w *= (2.0f - w*(float)rhw); - } while(++x1 < x2); - } else { - uint8 *dstp = (uint8 *)dstp0; - - do { - float sg = (float)(g * w); - - uint8 ig = VDClampedRoundFixedToUint8Fast(sg); - - dstp[x1] = ig; - - g += dgdx; - rhw += drhwdx; - - w *= (2.0f - w*(float)rhw); - } while(++x1 < x2); - } - } - - dstp0 = vdptroffset(dstp0, dstpitch); - xl += dxl1; - rl += drl1; - gl += dgl1; - bl += dbl1; - al += dal1; - rhwl += drhwl1; - xr += dxr1; - ++y; - } - } - - struct VDTriClipWorkspace { - VDTriBltTransformedVertex *vxheapptr[2][19]; - VDTriBltTransformedVertex vxheap[21]; - }; - - VDTriBltTransformedVertex **VDClipTriangle(VDTriClipWorkspace& ws, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2, - int orflags) { - // Each line segment can intersect all six planes, meaning the maximum bound is - // 18 vertices. Add 3 for the original. - - VDTriBltTransformedVertex *vxheapnext; - VDTriBltTransformedVertex **vxlastheap = ws.vxheapptr[0], **vxnextheap = ws.vxheapptr[1]; - - ws.vxheap[0] = *vx0; - ws.vxheap[1] = *vx1; - ws.vxheap[2] = *vx2; - - vxlastheap[0] = &ws.vxheap[0]; - vxlastheap[1] = &ws.vxheap[1]; - vxlastheap[2] = &ws.vxheap[2]; - vxlastheap[3] = NULL; - - vxheapnext = ws.vxheap + 3; - - // Current Next Action - // ------- ---- ------ - // Unclipped Unclipped Copy vertex - // Unclipped Clipped Copy vertex and add intersection - // Clipped Unclipped Add intersection - // Clipped Clipped No action - -#define DOCLIP(cliptype, _sign_, cliparg) \ - if (orflags & k##cliptype) { \ - VDTriBltTransformedVertex **src = vxlastheap; \ - VDTriBltTransformedVertex **dst = vxnextheap; \ - \ - while(*src) { \ - VDTriBltTransformedVertex *cur = *src; \ - VDTriBltTransformedVertex *next = src[1]; \ - \ - if (!next) \ - next = vxlastheap[0]; \ - \ - if (!(cur->outcode & k##cliptype)) \ - *dst++ = cur; \ - \ - if ((cur->outcode ^ next->outcode) & k##cliptype) { \ - double alpha = (cur->w _sign_ cur->cliparg) / ((cur->w _sign_ cur->cliparg) - (next->w _sign_ next->cliparg)); \ - \ - if (alpha >= 0.0 && alpha <= 1.0) { \ - vxheapnext->interp(cur, next, (float)alpha); \ - vxheapnext->cliparg = -(_sign_ vxheapnext->w); \ - *dst++ = vxheapnext++; \ - } \ - } \ - ++src; \ - } \ - *dst = NULL; \ - if (dst < vxnextheap+3) return NULL; \ - src = vxlastheap; vxlastheap = vxnextheap; vxnextheap = src; \ - } - - - DOCLIP(Far, -, z); - DOCLIP(Near, +, z); - DOCLIP(Bottom, -, y); - DOCLIP(Top, +, y); - DOCLIP(Right, -, x); - DOCLIP(Left, +, x); - -#undef DOCLIP - - return vxlastheap; - } - - void RenderClippedTri(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2, - VDTriBltFilterMode filterMode, - float mipMapLODBias, - int orflags) - { - - VDTriBltTransformedVertex *vxheapnext; - VDTriBltTransformedVertex vxheap[21]; - - VDTriBltTransformedVertex *vxheapptr[2][19]; - VDTriBltTransformedVertex **vxlastheap = vxheapptr[0], **vxnextheap = vxheapptr[1]; - - vxheap[0] = *vx0; - vxheap[1] = *vx1; - vxheap[2] = *vx2; - - vxlastheap[0] = &vxheap[0]; - vxlastheap[1] = &vxheap[1]; - vxlastheap[2] = &vxheap[2]; - vxlastheap[3] = NULL; - - vxheapnext = vxheap + 3; - - // Current Next Action - // ------- ---- ------ - // Unclipped Unclipped Copy vertex - // Unclipped Clipped Copy vertex and add intersection - // Clipped Unclipped Add intersection - // Clipped Clipped No action - -#define DOCLIP(cliptype, _sign_, cliparg) \ - if (orflags & k##cliptype) { \ - VDTriBltTransformedVertex **src = vxlastheap; \ - VDTriBltTransformedVertex **dst = vxnextheap; \ - \ - while(*src) { \ - VDTriBltTransformedVertex *cur = *src; \ - VDTriBltTransformedVertex *next = src[1]; \ - \ - if (!next) \ - next = vxlastheap[0]; \ - \ - if (!(cur->outcode & k##cliptype)) \ - *dst++ = cur; \ - \ - if ((cur->outcode ^ next->outcode) & k##cliptype) { \ - double alpha = (cur->w _sign_ cur->cliparg) / ((cur->w _sign_ cur->cliparg) - (next->w _sign_ next->cliparg)); \ - \ - if (alpha >= 0.0 && alpha <= 1.0) { \ - vxheapnext->interp(cur, next, (float)alpha); \ - vxheapnext->cliparg = -(_sign_ vxheapnext->w); \ - *dst++ = vxheapnext++; \ - } \ - } \ - ++src; \ - } \ - *dst = NULL; \ - if (dst < vxnextheap+3) return; \ - src = vxlastheap; vxlastheap = vxnextheap; vxnextheap = src; \ - } - - - DOCLIP(Far, -, z); - DOCLIP(Near, +, z); - DOCLIP(Bottom, -, y); - DOCLIP(Top, +, y); - DOCLIP(Right, -, x); - DOCLIP(Left, +, x); - -#undef DOCLIP - - VDTriBltTransformedVertex **src = vxlastheap+1; - - while(src[1]) { - RenderTri(dst, pSources, nMipmaps, vxlastheap[0], src[0], src[1], filterMode, mipMapLODBias); - ++src; - } - } - -} - -bool VDPixmapTriFill(VDPixmap& dst, const uint32 c, const VDTriBltVertex *pVertices, int nVertices, const int *pIndices, int nIndices, const float pTransform[16]) { - if (dst.format != nsVDPixmap::kPixFormat_XRGB8888) - return false; - - static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; - vdfastvector xverts(nVertices); - - if (!pTransform) - pTransform = xf_ident; - - TransformVerts(xverts.data(), pVertices, nVertices, pTransform); - - const VDTriBltTransformedVertex *xsrc = xverts.data(); - - VDTriClipWorkspace clipws; - - while(nIndices >= 3) { - const int idx0 = pIndices[0]; - const int idx1 = pIndices[1]; - const int idx2 = pIndices[2]; - const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; - const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; - const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; - const int kode0 = xv0->outcode; - const int kode1 = xv1->outcode; - const int kode2 = xv2->outcode; - - if (!(kode0 & kode1 & kode2)) { - if (int orflags = kode0 | kode1 | kode2) { - VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); - - if (src) { - VDTriBltTransformedVertex *src0 = *src++; - - // fan out triangles - while(src[1]) { - FillTri(dst, c, src0, src[0], src[1]); - ++src; - } - } - } else - FillTri(dst, c, xv0, xv1, xv2); - } - - pIndices += 3; - nIndices -= 3; - } - - return true; -} - -bool VDPixmapTriFill(VDPixmap& dst, const VDTriColorVertex *pVertices, int nVertices, const int *pIndices, int nIndices, const float pTransform[16], const float *chroma_yoffset) { - VDPixmap pxY; - VDPixmap pxCb; - VDPixmap pxCr; - bool ycbcr = false; - float ycbcr_xoffset = 0; - - switch(dst.format) { - case nsVDPixmap::kPixFormat_XRGB8888: - case nsVDPixmap::kPixFormat_Y8: - break; - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - pxY.format = nsVDPixmap::kPixFormat_Y8; - pxY.data = dst.data; - pxY.pitch = dst.pitch; - pxY.w = dst.w; - pxY.h = dst.h; - - pxCb.format = nsVDPixmap::kPixFormat_Y8; - pxCb.data = dst.data2; - pxCb.pitch = dst.pitch2; - pxCb.w = dst.w; - pxCb.h = dst.h; - - pxCr.format = nsVDPixmap::kPixFormat_Y8; - pxCr.data = dst.data3; - pxCr.pitch = dst.pitch3; - pxCr.w = dst.w; - pxCr.h = dst.h; - - switch(dst.format) { - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 2; - pxCr.h = pxCb.h = dst.h >> 2; - ycbcr_xoffset = 0.75f / (float)pxCr.w; - break; - - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 1; - pxCr.h = pxCb.h = dst.h >> 1; - ycbcr_xoffset = 0.5f / (float)pxCr.w; - break; - - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 1; - ycbcr_xoffset = 0.5f / (float)pxCr.w; - break; - - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - pxCr.w = pxCb.w = dst.w; - ycbcr_xoffset = 0.0f; - break; - } - - ycbcr = true; - break; - default: - return false; - } - - VDTriBltTransformedVertex fastxverts[64]; - vdfastvector xverts; - - VDTriBltTransformedVertex *xsrc; - if (nVertices <= 64) { - xsrc = fastxverts; - } else { - xverts.resize(nVertices); - xsrc = xverts.data(); - } - - static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; - if (!pTransform) - pTransform = xf_ident; - - VDTriClipWorkspace clipws; - for(int plane=0; plane<(ycbcr?3:1); ++plane) { - VDPixmap& pxPlane = ycbcr ? plane == 0 ? pxY : plane == 1 ? pxCb : pxCr : dst; - - if (ycbcr && plane) { - float xf_ycbcr[16]; - memcpy(xf_ycbcr, pTransform, sizeof(float) * 16); - - // translate in x by ycbcr_xoffset - xf_ycbcr[0] += xf_ycbcr[12]*ycbcr_xoffset; - xf_ycbcr[1] += xf_ycbcr[13]*ycbcr_xoffset; - xf_ycbcr[2] += xf_ycbcr[14]*ycbcr_xoffset; - xf_ycbcr[3] += xf_ycbcr[15]*ycbcr_xoffset; - - // translate in y by chroma_yoffset - if (chroma_yoffset) { - xf_ycbcr[4] += xf_ycbcr[12]*(*chroma_yoffset); - xf_ycbcr[5] += xf_ycbcr[13]*(*chroma_yoffset); - xf_ycbcr[6] += xf_ycbcr[14]*(*chroma_yoffset); - xf_ycbcr[7] += xf_ycbcr[15]*(*chroma_yoffset); - } - - TransformVerts(xsrc, pVertices, nVertices, xf_ycbcr); - - switch(plane) { - case 1: - for(int i=0; i= 3) { - const int idx0 = nextIndex[0]; - const int idx1 = nextIndex[1]; - const int idx2 = nextIndex[2]; - const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; - const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; - const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; - const int kode0 = xv0->outcode; - const int kode1 = xv1->outcode; - const int kode2 = xv2->outcode; - - if (!(kode0 & kode1 & kode2)) { - if (int orflags = kode0 | kode1 | kode2) { - VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); - - if (src) { - VDTriBltTransformedVertex *src0 = *src++; - - // fan out triangles - while(src[1]) { - FillTriGrad(pxPlane, src0, src[0], src[1]); - ++src; - } - } - } else { - FillTriGrad(pxPlane, xv0, xv1, xv2); - } - } - - nextIndex += 3; - indicesLeft -= 3; - } - } - - return true; -} - -bool VDPixmapTriBlt(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, - const VDTriBltVertex *pVertices, int nVertices, - const int *pIndices, int nIndices, - VDTriBltFilterMode filterMode, - float mipMapLODBias, - const float pTransform[16]) -{ - if (dst.format != nsVDPixmap::kPixFormat_XRGB8888) - return false; - - static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; - vdfastvector xverts(nVertices); - - if (!pTransform) - pTransform = xf_ident; - - TransformVerts(xverts.data(), pVertices, nVertices, pTransform); - - const VDTriBltTransformedVertex *xsrc = xverts.data(); - - VDTriClipWorkspace clipws; - - while(nIndices >= 3) { - const int idx0 = pIndices[0]; - const int idx1 = pIndices[1]; - const int idx2 = pIndices[2]; - const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; - const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; - const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; - const int kode0 = xv0->outcode; - const int kode1 = xv1->outcode; - const int kode2 = xv2->outcode; - - if (!(kode0 & kode1 & kode2)) { - if (int orflags = kode0 | kode1 | kode2) { - VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); - - if (src) { - VDTriBltTransformedVertex *src0 = *src++; - - // fan out triangles - while(src[1]) { - RenderTri(dst, pSources, nMipmaps, src0, src[0], src[1], filterMode, mipMapLODBias); - ++src; - } - } - } else - RenderTri(dst, pSources, nMipmaps, xv0, xv1, xv2, filterMode, mipMapLODBias); - } - - pIndices += 3; - nIndices -= 3; - } - - return true; -} - -/////////////////////////////////////////////////////////////////////////// - -void VDPixmapSetTextureBorders(VDPixmap& px, bool wrap) { - const int w = px.w; - const int h = px.h; - - VDPixmapBlt(px, 0, 1, px, wrap ? w-2 : 1, 1, 1, h-2); - VDPixmapBlt(px, w-1, 1, px, wrap ? 1 : w-2, 1, 1, h-2); - - VDPixmapBlt(px, 0, 0, px, 0, wrap ? h-2 : 1, w, 1); - VDPixmapBlt(px, 0, h-1, px, 0, wrap ? 1 : h-2, w, 1); -} - -void VDPixmapSetTextureBordersCubic(VDPixmap& px) { - const int w = px.w; - const int h = px.h; - - VDPixmapBlt(px, 0, 1, px, 2, 1, 1, h-2); - VDPixmapBlt(px, 1, 1, px, 2, 1, 1, h-2); - VDPixmapBlt(px, w-2, 1, px, w-3, 1, 1, h-2); - VDPixmapBlt(px, w-1, 1, px, w-3, 1, 1, h-2); - - VDPixmapBlt(px, 0, 0, px, 0, 2, w, 1); - VDPixmapBlt(px, 0, 1, px, 0, 2, w, 1); - VDPixmapBlt(px, 0, h-2, px, 0, h-3, w, 1); - VDPixmapBlt(px, 0, h-1, px, 0, h-3, w, 1); -} - -/////////////////////////////////////////////////////////////////////////// - -VDPixmapTextureMipmapChain::VDPixmapTextureMipmapChain(const VDPixmap& src, bool wrap, bool cubic, int maxlevels) { - int w = src.w; - int h = src.h; - int mipcount = 0; - - while((w>1 || h>1) && maxlevels--) { - ++mipcount; - w >>= 1; - h >>= 1; - } - - mBuffers.resize(mipcount); - mMipMaps.resize(mipcount); - - vdautoptr r(VDCreatePixmapResampler()); - r->SetFilters(IVDPixmapResampler::kFilterLinear, IVDPixmapResampler::kFilterLinear, false); - - float fw = (float)src.w; - float fh = (float)src.h; - for(int mip=0; mipInit(rdst, curmip.w, curmip.h, curmip.format, rsrc, prevmip.w, prevmip.h, prevmip.format); - r->Process(curmip, prevmip); - } - } else { - mBuffers[mip].init(mipw+2, miph+2, nsVDPixmap::kPixFormat_XRGB8888); - - if (!mip) { - VDPixmapBlt(mBuffers[0], 1, 1, src, 0, 0, src.w, src.h); - VDPixmapSetTextureBorders(mBuffers[0], wrap); - } else { - const VDPixmap& curmip = mBuffers[mip]; - const VDPixmap& prevmip = mBuffers[mip-1]; - - vdrect32f rdst( 0.0f, 0.0f, (float)curmip.w , (float)curmip.h ); - vdrect32f rsrc(-1.0f, -1.0f, 2.0f*(float)curmip.w - 1.0f, 2.0f*(float)curmip.h - 1.0f); - r->Init(rdst, curmip.w, curmip.h, curmip.format, rsrc, prevmip.w, prevmip.h, prevmip.format); - r->Process(curmip, prevmip); - } - } - - fw *= 0.5f; - fh *= 0.5f; - } -} - +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + uint32 lerp_RGB888(sint32 a, sint32 b, sint32 x) { + sint32 a_rb = a & 0xff00ff; + sint32 a_g = a & 0x00ff00; + sint32 b_rb = b & 0xff00ff; + sint32 b_g = b & 0x00ff00; + + const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; + + return top_rb + top_g; + } + + uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { + sint32 a_rb = a & 0xff00ff; + sint32 a_g = a & 0x00ff00; + sint32 b_rb = b & 0xff00ff; + sint32 b_g = b & 0x00ff00; + sint32 c_rb = c & 0xff00ff; + sint32 c_g = c & 0x00ff00; + sint32 d_rb = d & 0xff00ff; + sint32 d_g = d & 0x00ff00; + + const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; + const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 bot_g = (c_g + (((d_g - c_g )*x + 0x00008000) >> 8)) & 0x00ff00; + + const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff; + const uint32 final_g = (top_g + (((bot_g - top_g )*y) >> 8)) & 0x00ff00; + + return final_rb + final_g; + } + + uint32 bicubic_RGB888(const uint32 *src0, const uint32 *src1, const uint32 *src2, const uint32 *src3, sint32 x, sint32 y) { + const uint32 p00 = src0[0]; + const uint32 p01 = src0[1]; + const uint32 p02 = src0[2]; + const uint32 p03 = src0[3]; + const uint32 p10 = src1[0]; + const uint32 p11 = src1[1]; + const uint32 p12 = src1[2]; + const uint32 p13 = src1[3]; + const uint32 p20 = src2[0]; + const uint32 p21 = src2[1]; + const uint32 p22 = src2[2]; + const uint32 p23 = src2[3]; + const uint32 p30 = src3[0]; + const uint32 p31 = src3[1]; + const uint32 p32 = src3[2]; + const uint32 p33 = src3[3]; + + const sint32 *htab = kVDCubicInterpTableFX14_075[x]; + const sint32 *vtab = kVDCubicInterpTableFX14_075[y]; + + const int ch0 = htab[0]; + const int ch1 = htab[1]; + const int ch2 = htab[2]; + const int ch3 = htab[3]; + const int cv0 = vtab[0]; + const int cv1 = vtab[1]; + const int cv2 = vtab[2]; + const int cv3 = vtab[3]; + + int r0 = ((int)((p00>>16)&0xff) * ch0 + (int)((p01>>16)&0xff) * ch1 + (int)((p02>>16)&0xff) * ch2 + (int)((p03>>16)&0xff) * ch3 + 128) >> 8; + int g0 = ((int)((p00>> 8)&0xff) * ch0 + (int)((p01>> 8)&0xff) * ch1 + (int)((p02>> 8)&0xff) * ch2 + (int)((p03>> 8)&0xff) * ch3 + 128) >> 8; + int b0 = ((int)((p00 )&0xff) * ch0 + (int)((p01 )&0xff) * ch1 + (int)((p02 )&0xff) * ch2 + (int)((p03 )&0xff) * ch3 + 128) >> 8; + int r1 = ((int)((p10>>16)&0xff) * ch0 + (int)((p11>>16)&0xff) * ch1 + (int)((p12>>16)&0xff) * ch2 + (int)((p13>>16)&0xff) * ch3 + 128) >> 8; + int g1 = ((int)((p10>> 8)&0xff) * ch0 + (int)((p11>> 8)&0xff) * ch1 + (int)((p12>> 8)&0xff) * ch2 + (int)((p13>> 8)&0xff) * ch3 + 128) >> 8; + int b1 = ((int)((p10 )&0xff) * ch0 + (int)((p11 )&0xff) * ch1 + (int)((p12 )&0xff) * ch2 + (int)((p13 )&0xff) * ch3 + 128) >> 8; + int r2 = ((int)((p20>>16)&0xff) * ch0 + (int)((p21>>16)&0xff) * ch1 + (int)((p22>>16)&0xff) * ch2 + (int)((p23>>16)&0xff) * ch3 + 128) >> 8; + int g2 = ((int)((p20>> 8)&0xff) * ch0 + (int)((p21>> 8)&0xff) * ch1 + (int)((p22>> 8)&0xff) * ch2 + (int)((p23>> 8)&0xff) * ch3 + 128) >> 8; + int b2 = ((int)((p20 )&0xff) * ch0 + (int)((p21 )&0xff) * ch1 + (int)((p22 )&0xff) * ch2 + (int)((p23 )&0xff) * ch3 + 128) >> 8; + int r3 = ((int)((p30>>16)&0xff) * ch0 + (int)((p31>>16)&0xff) * ch1 + (int)((p32>>16)&0xff) * ch2 + (int)((p33>>16)&0xff) * ch3 + 128) >> 8; + int g3 = ((int)((p30>> 8)&0xff) * ch0 + (int)((p31>> 8)&0xff) * ch1 + (int)((p32>> 8)&0xff) * ch2 + (int)((p33>> 8)&0xff) * ch3 + 128) >> 8; + int b3 = ((int)((p30 )&0xff) * ch0 + (int)((p31 )&0xff) * ch1 + (int)((p32 )&0xff) * ch2 + (int)((p33 )&0xff) * ch3 + 128) >> 8; + + int r = (r0 * cv0 + r1 * cv1 + r2 * cv2 + r3 * cv3 + (1<<19)) >> 20; + int g = (g0 * cv0 + g1 * cv1 + g2 * cv2 + g3 * cv3 + (1<<19)) >> 20; + int b = (b0 * cv0 + b1 * cv1 + b2 * cv2 + b3 * cv3 + (1<<19)) >> 20; + + if (r<0) r=0; else if (r>255) r=255; + if (g<0) g=0; else if (g>255) g=255; + if (b<0) b=0; else if (b>255) b=255; + + return (r<<16) + (g<<8) + b; + } +} + +namespace { + enum { + kTop = 1, + kBottom = 2, + kLeft = 4, + kRight = 8, + kNear = 16, + kFar = 32 + }; + + struct VDTriBltMipInfo { + const uint32 *mip; + ptrdiff_t pitch; + uint32 uvmul, _pad; + }; + + struct VDTriBltInfo { + VDTriBltMipInfo mips[16]; + uint32 *dst; + const uint32 *src; + sint32 width; + const int *cubictab; + }; + + struct VDTriBltGenInfo { + float u; + float v; + float rhw; + float dudx; + float dvdx; + float drhwdx; + }; + + typedef void (*VDTriBltSpanFunction)(const VDTriBltInfo *); + typedef void (*VDTriBltGenFunction)(const VDTriBltGenInfo *); + + void vd_triblt_span_point(const VDTriBltInfo *pInfo) { + sint32 w = -pInfo->width; + uint32 *dst = pInfo->dst + pInfo->width; + const uint32 *src = pInfo->src; + const uint32 *texture = pInfo->mips[0].mip; + const ptrdiff_t texpitch = pInfo->mips[0].pitch; + + do { + dst[w] = vdptroffset(texture, texpitch * src[1])[src[0]]; + src += 2; + } while(++w); + } + + void vd_triblt_span_bilinear(const VDTriBltInfo *pInfo) { + sint32 w = -pInfo->width; + uint32 *dst = pInfo->dst + pInfo->width; + const uint32 *src = pInfo->src; + const uint32 *texture = pInfo->mips[0].mip; + const ptrdiff_t texpitch = pInfo->mips[0].pitch; + + do { + const sint32 u = src[0]; + const sint32 v = src[1]; + src += 2; + const uint32 *src1 = vdptroffset(texture, texpitch * (v>>8)) + (u>>8); + const uint32 *src2 = vdptroffset(src1, texpitch); + + dst[w] = bilerp_RGB888(src1[0], src1[1], src2[0], src2[1], u&255, v&255); + } while(++w); + } + + void vd_triblt_span_trilinear(const VDTriBltInfo *pInfo) { + sint32 w = -pInfo->width; + uint32 *dst = pInfo->dst + pInfo->width; + const uint32 *src = pInfo->src; + + do { + sint32 u = src[0]; + sint32 v = src[1]; + const sint32 lambda = src[2]; + src += 3; + + const sint32 lod = lambda >> 8; + + const uint32 *texture1 = pInfo->mips[lod].mip; + const ptrdiff_t texpitch1 = pInfo->mips[lod].pitch; + const uint32 *texture2 = pInfo->mips[lod+1].mip; + const ptrdiff_t texpitch2 = pInfo->mips[lod+1].pitch; + + u >>= lod; + v >>= lod; + + u += 128; + v += 128; + + const uint32 *src1 = vdptroffset(texture1, texpitch1 * (v>>8)) + (u>>8); + const uint32 *src2 = vdptroffset(src1, texpitch1); + const uint32 p1 = bilerp_RGB888(src1[0], src1[1], src2[0], src2[1], u&255, v&255); + + u += 128; + v += 128; + + const uint32 *src3 = vdptroffset(texture2, texpitch2 * (v>>9)) + (u>>9); + const uint32 *src4 = vdptroffset(src3, texpitch2); + const uint32 p2 = bilerp_RGB888(src3[0], src3[1], src4[0], src4[1], (u>>1)&255, (v>>1)&255); + + dst[w] = lerp_RGB888(p1, p2, lambda & 255); + } while(++w); + } + + void vd_triblt_span_bicubic_mip_linear(const VDTriBltInfo *pInfo) { + sint32 w = -pInfo->width; + uint32 *dst = pInfo->dst + pInfo->width; + const uint32 *src = pInfo->src; + + do { + sint32 u = src[0]; + sint32 v = src[1]; + const sint32 lambda = src[2]; + src += 3; + + const sint32 lod = lambda >> 8; + + const uint32 *texture1 = pInfo->mips[lod].mip; + const ptrdiff_t texpitch1 = pInfo->mips[lod].pitch; + const uint32 *texture2 = pInfo->mips[lod+1].mip; + const ptrdiff_t texpitch2 = pInfo->mips[lod+1].pitch; + + u >>= lod; + v >>= lod; + + u += 128; + v += 128; + + const uint32 *src1 = vdptroffset(texture1, texpitch1 * (v>>8)) + (u>>8); + const uint32 *src2 = vdptroffset(src1, texpitch1); + const uint32 *src3 = vdptroffset(src2, texpitch1); + const uint32 *src4 = vdptroffset(src3, texpitch1); + const uint32 p1 = bicubic_RGB888(src1, src2, src3, src4, u&255, v&255); + + u += 128; + v += 128; + + const uint32 *src5 = vdptroffset(texture2, texpitch2 * (v>>9)) + (u>>9); + const uint32 *src6 = vdptroffset(src5, texpitch2); + const uint32 *src7 = vdptroffset(src6, texpitch2); + const uint32 *src8 = vdptroffset(src7, texpitch2); + const uint32 p2 = bicubic_RGB888(src5, src6, src7, src8, (u>>1)&255, (v>>1)&255); + + dst[w] = lerp_RGB888(p1, p2, lambda & 255); + } while(++w); + } + +#ifdef _M_IX86 + extern "C" void vdasm_triblt_span_bilinear_mmx(const VDTriBltInfo *pInfo); + extern "C" void vdasm_triblt_span_trilinear_mmx(const VDTriBltInfo *pInfo); + extern "C" void vdasm_triblt_span_bicubic_mip_linear_mmx(const VDTriBltInfo *pInfo); + extern "C" void vdasm_triblt_span_bicubic_mip_linear_sse2(const VDTriBltInfo *pInfo); + extern "C" void vdasm_triblt_span_point(const VDTriBltInfo *pInfo); +#endif + + struct VDTriBltTransformedVertex { + float x, y, z; + union { + float w; + float rhw; + }; + float r, g, b, a; + float u, v; + int outcode; + + void interp(const VDTriBltTransformedVertex *v1, const VDTriBltTransformedVertex *v2, float alpha) { + x = v1->x + alpha * (v2->x - v1->x); + y = v1->y + alpha * (v2->y - v1->y); + z = v1->z + alpha * (v2->z - v1->z); + w = v1->w + alpha * (v2->w - v1->w); + + r = v1->r + alpha * (v2->r - v1->r); + g = v1->g + alpha * (v2->g - v1->g); + b = v1->b + alpha * (v2->b - v1->b); + a = v1->a + alpha * (v2->a - v1->a); + + u = v1->u + alpha * (v2->u - v1->u); + v = v1->v + alpha * (v2->v - v1->v); + + outcode = (x < -w ? kLeft : 0) + + (x > +w ? kRight : 0) + + (y < -w ? kTop : 0) + + (y > +w ? kBottom : 0) + + (z < -w ? kNear : 0) + + (z > +w ? kFar : 0); + } + }; + + void TransformVerts(VDTriBltTransformedVertex *dst, const VDTriBltVertex *src, int nVerts, const float xform[16]) { + const float xflocal[16]={ + xform[ 0], xform[ 1], xform[ 2], xform[ 3], + xform[ 4], xform[ 5], xform[ 6], xform[ 7], + xform[ 8], xform[ 9], xform[10], xform[11], + xform[12], xform[13], xform[14], xform[15], + }; + + if (nVerts <= 0) + return; + + do { + const float x0 = src->x; + const float y0 = src->y; + const float z0 = src->z; + + const float w = x0*xflocal[12] + y0*xflocal[13] + z0*xflocal[14] + xflocal[15]; + const float x = x0*xflocal[ 0] + y0*xflocal[ 1] + z0*xflocal[ 2] + xflocal[ 3]; + const float y = x0*xflocal[ 4] + y0*xflocal[ 5] + z0*xflocal[ 6] + xflocal[ 7]; + const float z = x0*xflocal[ 8] + y0*xflocal[ 9] + z0*xflocal[10] + xflocal[11]; + + int outcode = 0; + + if (x < -w) outcode += kLeft; + if (x > w) outcode += kRight; + if (y < -w) outcode += kTop; + if (y > w) outcode += kBottom; + if (z < -w) outcode += kNear; + if (z > w) outcode += kFar; + + dst->x = x; + dst->y = y; + dst->z = z; + dst->w = w; + dst->u = src->u; + dst->v = src->v; + dst->r = 1.0f; + dst->g = 1.0f; + dst->b = 1.0f; + dst->a = 1.0f; + dst->outcode = outcode; + + ++src; + ++dst; + } while(--nVerts); + } + + void TransformVerts(VDTriBltTransformedVertex *dst, const VDTriColorVertex *src, int nVerts, const float xform[16]) { + const float xflocal[16]={ + xform[ 0], xform[ 1], xform[ 2], xform[ 3], + xform[ 4], xform[ 5], xform[ 6], xform[ 7], + xform[ 8], xform[ 9], xform[10], xform[11], + xform[12], xform[13], xform[14], xform[15], + }; + + if (nVerts <= 0) + return; + + do { + const float x0 = src->x; + const float y0 = src->y; + const float z0 = src->z; + + const float w = x0*xflocal[12] + y0*xflocal[13] + z0*xflocal[14] + xflocal[15]; + const float x = x0*xflocal[ 0] + y0*xflocal[ 1] + z0*xflocal[ 2] + xflocal[ 3]; + const float y = x0*xflocal[ 4] + y0*xflocal[ 5] + z0*xflocal[ 6] + xflocal[ 7]; + const float z = x0*xflocal[ 8] + y0*xflocal[ 9] + z0*xflocal[10] + xflocal[11]; + + int outcode = 0; + + if (x < -w) outcode += kLeft; + if (x > w) outcode += kRight; + if (y < -w) outcode += kTop; + if (y > w) outcode += kBottom; + if (z < -w) outcode += kNear; + if (z > w) outcode += kFar; + + dst->x = x; + dst->y = y; + dst->z = z; + dst->w = w; + dst->u = 0.0f; + dst->v = 0.0f; + dst->r = src->r; + dst->g = src->g; + dst->b = src->b; + dst->a = src->a; + dst->outcode = outcode; + + ++src; + ++dst; + } while(--nVerts); + } + + struct VDTriangleSetupInfo { + const VDTriBltTransformedVertex *pt, *pr, *pl; + VDTriBltTransformedVertex tmp0, tmp1, tmp2; + }; + + void SetupTri( + VDTriangleSetupInfo& setup, + VDPixmap& dst, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2, + const VDTriBltFilterMode *filterMode + ) + { + setup.tmp0 = *vx0; + setup.tmp1 = *vx1; + setup.tmp2 = *vx2; + + // adjust UVs for filter mode + if (filterMode) { + switch(*filterMode) { + case kTriBltFilterBilinear: + setup.tmp0.u += 0.5f; + setup.tmp0.v += 0.5f; + setup.tmp1.u += 0.5f; + setup.tmp1.v += 0.5f; + setup.tmp2.u += 0.5f; + setup.tmp2.v += 0.5f; + case kTriBltFilterTrilinear: + case kTriBltFilterBicubicMipLinear: + setup.tmp0.u *= 256.0f; + setup.tmp0.v *= 256.0f; + setup.tmp1.u *= 256.0f; + setup.tmp1.v *= 256.0f; + setup.tmp2.u *= 256.0f; + setup.tmp2.v *= 256.0f; + break; + case kTriBltFilterPoint: + setup.tmp0.u += 1.0f; + setup.tmp0.v += 1.0f; + setup.tmp1.u += 1.0f; + setup.tmp1.v += 1.0f; + setup.tmp2.u += 1.0f; + setup.tmp2.v += 1.0f; + break; + } + } + + // do perspective divide and NDC space conversion + const float xscale = dst.w * 0.5f; + const float yscale = dst.h * 0.5f; + + setup.tmp0.rhw = 1.0f / setup.tmp0.w; + setup.tmp0.x = (1.0f+setup.tmp0.x*setup.tmp0.rhw)*xscale; + setup.tmp0.y = (1.0f+setup.tmp0.y*setup.tmp0.rhw)*yscale; + setup.tmp0.u *= setup.tmp0.rhw; + setup.tmp0.v *= setup.tmp0.rhw; + setup.tmp0.r *= setup.tmp0.rhw; + setup.tmp0.g *= setup.tmp0.rhw; + setup.tmp0.b *= setup.tmp0.rhw; + setup.tmp0.a *= setup.tmp0.rhw; + setup.tmp1.rhw = 1.0f / setup.tmp1.w; + setup.tmp1.x = (1.0f+setup.tmp1.x*setup.tmp1.rhw)*xscale; + setup.tmp1.y = (1.0f+setup.tmp1.y*setup.tmp1.rhw)*yscale; + setup.tmp1.u *= setup.tmp1.rhw; + setup.tmp1.v *= setup.tmp1.rhw; + setup.tmp1.r *= setup.tmp1.rhw; + setup.tmp1.g *= setup.tmp1.rhw; + setup.tmp1.b *= setup.tmp1.rhw; + setup.tmp1.a *= setup.tmp1.rhw; + setup.tmp2.rhw = 1.0f / setup.tmp2.w; + setup.tmp2.x = (1.0f+setup.tmp2.x*setup.tmp2.rhw)*xscale; + setup.tmp2.y = (1.0f+setup.tmp2.y*setup.tmp2.rhw)*yscale; + setup.tmp2.u *= setup.tmp2.rhw; + setup.tmp2.v *= setup.tmp2.rhw; + setup.tmp2.r *= setup.tmp2.rhw; + setup.tmp2.g *= setup.tmp2.rhw; + setup.tmp2.b *= setup.tmp2.rhw; + setup.tmp2.a *= setup.tmp2.rhw; + + // verify clipping + VDASSERT(setup.tmp0.x >= 0 && setup.tmp0.x <= dst.w); + VDASSERT(setup.tmp1.x >= 0 && setup.tmp1.x <= dst.w); + VDASSERT(setup.tmp2.x >= 0 && setup.tmp2.x <= dst.w); + VDASSERT(setup.tmp0.y >= 0 && setup.tmp0.y <= dst.h); + VDASSERT(setup.tmp1.y >= 0 && setup.tmp1.y <= dst.h); + VDASSERT(setup.tmp2.y >= 0 && setup.tmp2.y <= dst.h); + + vx0 = &setup.tmp0; + vx1 = &setup.tmp1; + vx2 = &setup.tmp2; + + const VDTriBltTransformedVertex *pt, *pl, *pr; + + // sort points + if (vx0->y < vx1->y) // 1 < 2 + if (vx0->y < vx2->y) { // 1 < 2,3 + pt = vx0; + pr = vx1; + pl = vx2; + } else { // 3 < 1 < 2 + pt = vx2; + pr = vx0; + pl = vx1; + } + else // 2 < 1 + if (vx1->y < vx2->y) { // 2 < 1,3 + pt = vx1; + pr = vx2; + pl = vx0; + } else { // 3 < 2 < 1 + pt = vx2; + pr = vx0; + pl = vx1; + } + + setup.pl = pl; + setup.pt = pt; + setup.pr = pr; + } + + void RenderTri(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2, + VDTriBltFilterMode filterMode, + float mipMapLODBias) + { + VDTriangleSetupInfo setup; + + SetupTri(setup, dst, vx0, vx1, vx2, &filterMode); + + const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; + + const float x10 = pl->x - pt->x; + const float x20 = pr->x - pt->x; + const float y10 = pl->y - pt->y; + const float y20 = pr->y - pt->y; + const float A = x20*y10 - x10*y20; + + if (A <= 0.f) + return; + + float invA = 0.f; + if (A >= 1e-5f) + invA = 1.0f / A; + + float x10_A = x10 * invA; + float x20_A = x20 * invA; + float y10_A = y10 * invA; + float y20_A = y20 * invA; + + float u10 = pl->u - pt->u; + float u20 = pr->u - pt->u; + float v10 = pl->v - pt->v; + float v20 = pr->v - pt->v; + float rhw10 = pl->rhw - pt->rhw; + float rhw20 = pr->rhw - pt->rhw; + + float dudx = u20*y10_A - u10*y20_A; + float dudy = u10*x20_A - u20*x10_A; + float dvdx = v20*y10_A - v10*y20_A; + float dvdy = v10*x20_A - v20*x10_A; + float drhwdx = rhw20*y10_A - rhw10*y20_A; + float drhwdy = rhw10*x20_A - rhw20*x10_A; + + // Compute edge walking parameters + + float dxl1=0, dxr1=0, dul1=0, dvl1=0, drhwl1=0; + float dxl2=0, dxr2=0, dul2=0, dvl2=0, drhwl2=0; + + // Compute left-edge interpolation parameters for first half. + + if (pl->y != pt->y) { + dxl1 = (pl->x - pt->x) / (pl->y - pt->y); + + dul1 = dudy + dxl1 * dudx; + dvl1 = dvdy + dxl1 * dvdx; + drhwl1 = drhwdy + dxl1 * drhwdx; + } + + // Compute right-edge interpolation parameters for first half. + + if (pr->y != pt->y) { + dxr1 = (pr->x - pt->x) / (pr->y - pt->y); + } + + // Compute third-edge interpolation parameters. + + if (pr->y != pl->y) { + dxl2 = (pr->x - pl->x) / (pr->y - pl->y); + + dul2 = dudy + dxl2 * dudx; + dvl2 = dvdy + dxl2 * dvdx; + drhwl2 = drhwdy + dxl2 * drhwdx; + + dxr2 = dxl2; + } + + // Initialize parameters for first half. + // + // We place pixel centers at (x+0.5, y+0.5). + + double xl, xr, ul, vl, rhwl, yf; + int y, y1, y2; + + // y_start < y+0.5 to include pixel y. + + y = (int)floor(pt->y + 0.5); + yf = (y+0.5) - pt->y; + + xl = pt->x + dxl1 * yf; + xr = pt->x + dxr1 * yf; + ul = pt->u + dul1 * yf; + vl = pt->v + dvl1 * yf; + rhwl = pt->rhw + drhwl1 * yf; + + // Initialize parameters for second half. + + double xl2, xr2, ul2, vl2, rhwl2; + + if (pl->y > pr->y) { // Left edge is long side + dxl2 = dxl1; + dul2 = dul1; + dvl2 = dvl1; + drhwl2 = drhwl1; + + y1 = (int)floor(pr->y + 0.5); + y2 = (int)floor(pl->y + 0.5); + + yf = (y1+0.5) - pr->y; + + // Step left edge. + + xl2 = xl + dxl1 * (y1 - y); + ul2 = ul + dul1 * (y1 - y); + vl2 = vl + dvl1 * (y1 - y); + rhwl2 = rhwl + drhwl1 * (y1 - y); + + // Prestep right edge. + + xr2 = pr->x + dxr2 * yf; + } else { // Right edge is long side + dxr2 = dxr1; + + y1 = (int)floor(pl->y + 0.5); + y2 = (int)floor(pr->y + 0.5); + + yf = (y1+0.5) - pl->y; + + // Prestep left edge. + + xl2 = pl->x + dxl2 * yf; + ul2 = pl->u + dul2 * yf; + vl2 = pl->v + dvl2 * yf; + rhwl2 = pl->rhw + drhwl2 * yf; + + // Step right edge. + + xr2 = xr + dxr1 * (y1 - y); + } + + // rasterize + const ptrdiff_t dstpitch = dst.pitch; + uint32 *dstp = (uint32 *)((char *)dst.data + dstpitch * y); + + VDTriBltInfo texinfo; + VDTriBltSpanFunction drawSpan; + uint32 cpuflags = CPUGetEnabledExtensions(); + + bool triBlt16 = false; + + switch(filterMode) { + case kTriBltFilterBicubicMipLinear: +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_SSE2) { + drawSpan = vdasm_triblt_span_bicubic_mip_linear_sse2; + triBlt16 = true; + } else if (cpuflags & CPUF_SUPPORTS_MMX) { + drawSpan = vdasm_triblt_span_bicubic_mip_linear_mmx; + triBlt16 = true; + } else +#endif + drawSpan = vd_triblt_span_bicubic_mip_linear; + break; + case kTriBltFilterTrilinear: +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_MMX) { + drawSpan = vdasm_triblt_span_trilinear_mmx; + triBlt16 = true; + } else +#endif + drawSpan = vd_triblt_span_trilinear; + break; + case kTriBltFilterBilinear: +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_MMX) { + drawSpan = vdasm_triblt_span_bilinear_mmx; + triBlt16 = true; + } else +#endif + drawSpan = vd_triblt_span_bilinear; + break; + case kTriBltFilterPoint: + drawSpan = vd_triblt_span_point; + break; + } + + float rhobase = sqrtf(std::max(dudx*dudx + dvdx*dvdx, dudy*dudy + dvdy*dvdy) * (1.0f / 65536.0f)) * powf(2.0f, mipMapLODBias); + + if (triBlt16) { + ul *= 256.0f; + vl *= 256.0f; + ul2 *= 256.0f; + vl2 *= 256.0f; + dul1 *= 256.0f; + dvl1 *= 256.0f; + dul2 *= 256.0f; + dvl2 *= 256.0f; + dudx *= 256.0f; + dvdx *= 256.0f; + dudy *= 256.0f; + dvdy *= 256.0f; + } + + int minx1 = (int)floor(std::min(std::min(pl->x, pr->x), pt->x) + 0.5); + int maxx2 = (int)floor(std::max(std::max(pl->x, pr->x), pt->x) + 0.5); + + uint32 *const spanptr = new uint32[3 * (maxx2 - minx1)]; + + while(y < y2) { + if (y == y1) { + xl = xl2; + xr = xr2; + ul = ul2; + vl = vl2; + rhwl = rhwl2; + dxl1 = dxl2; + dxr1 = dxr2; + dul1 = dul2; + dvl1 = dvl2; + drhwl1 = drhwl2; + } + + int x1, x2; + double xf; + double u, v, rhw; + + // x_left must be less than (x+0.5) to include pixel x. + + x1 = (int)floor(xl + 0.5); + x2 = (int)floor(xr + 0.5); + xf = (x1+0.5) - xl; + + u = ul + xf * dudx; + v = vl + xf * dvdx; + rhw = rhwl + xf * drhwdx; + + int x = x1; + uint32 *spanp = spanptr; + + float w = 1.0f / (float)rhw; + + if (x < x2) { + if (filterMode >= kTriBltFilterTrilinear) { + do { + int utexel = VDRoundToIntFastFullRange(u * w); + int vtexel = VDRoundToIntFastFullRange(v * w); + union{ float f; sint32 i; } rho = {rhobase * w}; + + int lambda = ((rho.i - 0x3F800000) >> (23-8)); + if (lambda < 0) + lambda = 0; + if (lambda >= (nMipmaps<<8)-256) + lambda = (nMipmaps<<8)-257; + + spanp[0] = utexel; + spanp[1] = vtexel; + spanp[2] = lambda; + spanp += 3; + + u += dudx; + v += dvdx; + rhw += drhwdx; + + w *= (2.0f - w*(float)rhw); + } while(++x < x2); + } else { + do { + int utexel = VDFloorToInt(u * w); + int vtexel = VDFloorToInt(v * w); + + spanp[0] = utexel; + spanp[1] = vtexel; + spanp += 2; + + u += dudx; + v += dvdx; + rhw += drhwdx; + + w *= (2.0f - w*(float)rhw); + } while(++x < x2); + } + } + + for(int i=0; idata; + texinfo.mips[i].pitch = pSources[i]->pitch; + texinfo.mips[i].uvmul = (pSources[i]->pitch << 16) + 4; + } + texinfo.dst = dstp+x1; + texinfo.src = spanptr; + texinfo.width = x2-x1; + + if (texinfo.width>0) + drawSpan(&texinfo); + + dstp = vdptroffset(dstp, dstpitch); + xl += dxl1; + xr += dxr1; + ul += dul1; + vl += dvl1; + rhwl += drhwl1; + + ++y; + } + + delete[] spanptr; + } + + void FillTri(VDPixmap& dst, uint32 c, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2 + ) + { + + VDTriangleSetupInfo setup; + + SetupTri(setup, dst, vx0, vx1, vx2, NULL); + + const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; + + // Compute edge walking parameters + float dxl1=0, dxr1=0; + float dxl2=0, dxr2=0; + + float x_lt = pl->x - pt->x; + float x_rt = pr->x - pt->x; + float x_rl = pr->x - pl->x; + float y_lt = pl->y - pt->y; + float y_rt = pr->y - pt->y; + float y_rl = pr->y - pl->y; + + // reject backfaces + if (x_lt*y_rt >= x_rt*y_lt) + return; + + // Compute left-edge interpolation parameters for first half. + if (pl->y != pt->y) + dxl1 = x_lt / y_lt; + + // Compute right-edge interpolation parameters for first half. + if (pr->y != pt->y) + dxr1 = x_rt / y_rt; + + // Compute third-edge interpolation parameters. + if (pr->y != pl->y) { + dxl2 = x_rl / y_rl; + + dxr2 = dxl2; + } + + // Initialize parameters for first half. + // + // We place pixel centers at (x+0.5, y+0.5). + + double xl, xr, yf; + int y, y1, y2; + + // y_start < y+0.5 to include pixel y. + + y = (int)floor(pt->y + 0.5); + yf = (y+0.5) - pt->y; + + xl = pt->x + dxl1 * yf; + xr = pt->x + dxr1 * yf; + + // Initialize parameters for second half. + double xl2, xr2; + + if (pl->y > pr->y) { // Left edge is long side + dxl2 = dxl1; + + y1 = (int)floor(pr->y + 0.5); + y2 = (int)floor(pl->y + 0.5); + + yf = (y1+0.5) - pr->y; + + // Prestep right edge. + xr2 = pr->x + dxr2 * yf; + + // Step left edge. + xl2 = xl + dxl1 * (y1 - y); + } else { // Right edge is long side + dxr2 = dxr1; + + y1 = (int)floor(pl->y + 0.5); + y2 = (int)floor(pr->y + 0.5); + + yf = (y1+0.5) - pl->y; + + // Prestep left edge. + xl2 = pl->x + dxl2 * yf; + + // Step right edge. + xr2 = xr + dxr1 * (y1 - y); + } + + // rasterize + const ptrdiff_t dstpitch = dst.pitch; + uint32 *dstp = (uint32 *)((char *)dst.data + dstpitch * y); + + while(y < y2) { + if (y == y1) { + xl = xl2; + xr = xr2; + dxl1 = dxl2; + dxr1 = dxr2; + } + + int x1, x2; + double xf; + + // x_left must be less than (x+0.5) to include pixel x. + + x1 = (int)floor(xl + 0.5); + x2 = (int)floor(xr + 0.5); + xf = (x1+0.5) - xl; + + while(x1 < x2) + dstp[x1++] = c; + + dstp = vdptroffset(dstp, dstpitch); + xl += dxl1; + xr += dxr1; + ++y; + } + } + + void FillTriGrad(VDPixmap& dst, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2 + ) + { + + VDTriangleSetupInfo setup; + + SetupTri(setup, dst, vx0, vx1, vx2, NULL); + + const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; + const float x10 = pl->x - pt->x; + const float x20 = pr->x - pt->x; + const float y10 = pl->y - pt->y; + const float y20 = pr->y - pt->y; + const float A = x20*y10 - x10*y20; + + if (A <= 0.f) + return; + + float invA = 0.f; + if (A >= 1e-5f) + invA = 1.0f / A; + + float x10_A = x10 * invA; + float x20_A = x20 * invA; + float y10_A = y10 * invA; + float y20_A = y20 * invA; + + float r10 = pl->r - pt->r; + float r20 = pr->r - pt->r; + float g10 = pl->g - pt->g; + float g20 = pr->g - pt->g; + float b10 = pl->b - pt->b; + float b20 = pr->b - pt->b; + float a10 = pl->a - pt->a; + float a20 = pr->a - pt->a; + float rhw10 = pl->rhw - pt->rhw; + float rhw20 = pr->rhw - pt->rhw; + + float drdx = r20*y10_A - r10*y20_A; + float drdy = r10*x20_A - r20*x10_A; + float dgdx = g20*y10_A - g10*y20_A; + float dgdy = g10*x20_A - g20*x10_A; + float dbdx = b20*y10_A - b10*y20_A; + float dbdy = b10*x20_A - b20*x10_A; + float dadx = a20*y10_A - a10*y20_A; + float dady = a10*x20_A - a20*x10_A; + float drhwdx = rhw20*y10_A - rhw10*y20_A; + float drhwdy = rhw10*x20_A - rhw20*x10_A; + + // Compute edge walking parameters + float dxl1=0; + float drl1=0; + float dgl1=0; + float dbl1=0; + float dal1=0; + float drhwl1=0; + float dxr1=0; + float dxl2=0; + float drl2=0; + float dgl2=0; + float dbl2=0; + float dal2=0; + float drhwl2=0; + float dxr2=0; + + float x_lt = pl->x - pt->x; + float x_rt = pr->x - pt->x; + float x_rl = pr->x - pl->x; + float y_lt = pl->y - pt->y; + float y_rt = pr->y - pt->y; + float y_rl = pr->y - pl->y; + + // Compute left-edge interpolation parameters for first half. + if (pl->y != pt->y) { + dxl1 = x_lt / y_lt; + drl1 = drdy + dxl1 * drdx; + dgl1 = dgdy + dxl1 * dgdx; + dbl1 = dbdy + dxl1 * dbdx; + dal1 = dady + dxl1 * dadx; + drhwl1 = drhwdy + dxl1 * drhwdx; + } + + // Compute right-edge interpolation parameters for first half. + if (pr->y != pt->y) + dxr1 = x_rt / y_rt; + + // Compute third-edge interpolation parameters. + if (pr->y != pl->y) { + dxl2 = x_rl / y_rl; + + drl2 = drdy + dxl2 * drdx; + dgl2 = dgdy + dxl2 * dgdx; + dbl2 = dbdy + dxl2 * dbdx; + dal2 = dady + dxl2 * dadx; + drhwl2 = drhwdy + dxl2 * drhwdx; + + dxr2 = dxl2; + } + + // Initialize parameters for first half. + // + // We place pixel centers at (x+0.5, y+0.5). + + double xl, xr, yf; + double rl, gl, bl, al, rhwl; + double rl2, gl2, bl2, al2, rhwl2; + int y, y1, y2; + + // y_start < y+0.5 to include pixel y. + + y = (int)floor(pt->y + 0.5); + yf = (y+0.5) - pt->y; + + xl = pt->x + dxl1 * yf; + xr = pt->x + dxr1 * yf; + rl = pt->r + drl1 * yf; + gl = pt->g + dgl1 * yf; + bl = pt->b + dbl1 * yf; + al = pt->a + dal1 * yf; + rhwl = pt->rhw + drhwl1 * yf; + + // Initialize parameters for second half. + double xl2, xr2; + + if (pl->y > pr->y) { // Left edge is long side + dxl2 = dxl1; + drl2 = drl1; + dgl2 = dgl1; + dbl2 = dbl1; + dal2 = dal1; + drhwl2 = drhwl1; + + y1 = (int)floor(pr->y + 0.5); + y2 = (int)floor(pl->y + 0.5); + + yf = (y1+0.5) - pr->y; + + // Step left edge. + xl2 = xl + dxl1 * (y1 - y); + rl2 = rl + drl1 * (y1 - y); + gl2 = gl + dgl1 * (y1 - y); + bl2 = bl + dbl1 * (y1 - y); + al2 = al + dal1 * (y1 - y); + rhwl2 = rhwl + drhwl1 * (y1 - y); + + // Prestep right edge. + xr2 = pr->x + dxr2 * yf; + } else { // Right edge is long side + dxr2 = dxr1; + + y1 = (int)floor(pl->y + 0.5); + y2 = (int)floor(pr->y + 0.5); + + yf = (y1+0.5) - pl->y; + + // Prestep left edge. + xl2 = pl->x + dxl2 * yf; + rl2 = pl->r + drl2 * yf; + gl2 = pl->g + dgl2 * yf; + bl2 = pl->b + dbl2 * yf; + al2 = pl->a + dal2 * yf; + rhwl2 = pl->rhw + drhwl2 * yf; + + // Step right edge. + xr2 = xr + dxr2 * (y1 - y); + } + + // rasterize + const ptrdiff_t dstpitch = dst.pitch; + char *dstp0 = (char *)dst.data + dstpitch * y; + + while(y < y2) { + if (y == y1) { + xl = xl2; + xr = xr2; + rl = rl2; + gl = gl2; + bl = bl2; + al = al2; + rhwl = rhwl2; + dxl1 = dxl2; + drl1 = drl2; + dgl1 = dgl2; + dbl1 = dbl2; + dal1 = dal2; + drhwl1 = drhwl2; + dxr1 = dxr2; + } + + int x1, x2; + double xf; + double r, g, b, a, rhw; + + // x_left must be less than (x+0.5) to include pixel x. + + x1 = (int)floor(xl + 0.5); + x2 = (int)floor(xr + 0.5); + xf = (x1+0.5) - xl; + + r = rl + xf * drdx; + g = gl + xf * dgdx; + b = bl + xf * dbdx; + a = al + xf * dadx; + rhw = rhwl + xf * drhwdx; + + float w = 1.0f / (float)rhw; + + if (x1 < x2) { + if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) { + uint32 *dstp = (uint32 *)dstp0; + + do { + float sr = (float)(r * w); + float sg = (float)(g * w); + float sb = (float)(b * w); + float sa = (float)(a * w); + + uint8 ir = VDClampedRoundFixedToUint8Fast(sr); + uint8 ig = VDClampedRoundFixedToUint8Fast(sg); + uint8 ib = VDClampedRoundFixedToUint8Fast(sb); + uint8 ia = VDClampedRoundFixedToUint8Fast(sa); + + dstp[x1] = ((uint32)ia << 24) + ((uint32)ir << 16) + ((uint32)ig << 8) + ib; + + r += drdx; + g += dgdx; + b += dbdx; + a += dadx; + rhw += drhwdx; + + w *= (2.0f - w*(float)rhw); + } while(++x1 < x2); + } else { + uint8 *dstp = (uint8 *)dstp0; + + do { + float sg = (float)(g * w); + + uint8 ig = VDClampedRoundFixedToUint8Fast(sg); + + dstp[x1] = ig; + + g += dgdx; + rhw += drhwdx; + + w *= (2.0f - w*(float)rhw); + } while(++x1 < x2); + } + } + + dstp0 = vdptroffset(dstp0, dstpitch); + xl += dxl1; + rl += drl1; + gl += dgl1; + bl += dbl1; + al += dal1; + rhwl += drhwl1; + xr += dxr1; + ++y; + } + } + + struct VDTriClipWorkspace { + VDTriBltTransformedVertex *vxheapptr[2][19]; + VDTriBltTransformedVertex vxheap[21]; + }; + + VDTriBltTransformedVertex **VDClipTriangle(VDTriClipWorkspace& ws, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2, + int orflags) { + // Each line segment can intersect all six planes, meaning the maximum bound is + // 18 vertices. Add 3 for the original. + + VDTriBltTransformedVertex *vxheapnext; + VDTriBltTransformedVertex **vxlastheap = ws.vxheapptr[0], **vxnextheap = ws.vxheapptr[1]; + + ws.vxheap[0] = *vx0; + ws.vxheap[1] = *vx1; + ws.vxheap[2] = *vx2; + + vxlastheap[0] = &ws.vxheap[0]; + vxlastheap[1] = &ws.vxheap[1]; + vxlastheap[2] = &ws.vxheap[2]; + vxlastheap[3] = NULL; + + vxheapnext = ws.vxheap + 3; + + // Current Next Action + // ------- ---- ------ + // Unclipped Unclipped Copy vertex + // Unclipped Clipped Copy vertex and add intersection + // Clipped Unclipped Add intersection + // Clipped Clipped No action + +#define DOCLIP(cliptype, _sign_, cliparg) \ + if (orflags & k##cliptype) { \ + VDTriBltTransformedVertex **src = vxlastheap; \ + VDTriBltTransformedVertex **dst = vxnextheap; \ + \ + while(*src) { \ + VDTriBltTransformedVertex *cur = *src; \ + VDTriBltTransformedVertex *next = src[1]; \ + \ + if (!next) \ + next = vxlastheap[0]; \ + \ + if (!(cur->outcode & k##cliptype)) \ + *dst++ = cur; \ + \ + if ((cur->outcode ^ next->outcode) & k##cliptype) { \ + double alpha = (cur->w _sign_ cur->cliparg) / ((cur->w _sign_ cur->cliparg) - (next->w _sign_ next->cliparg)); \ + \ + if (alpha >= 0.0 && alpha <= 1.0) { \ + vxheapnext->interp(cur, next, (float)alpha); \ + vxheapnext->cliparg = -(_sign_ vxheapnext->w); \ + *dst++ = vxheapnext++; \ + } \ + } \ + ++src; \ + } \ + *dst = NULL; \ + if (dst < vxnextheap+3) return NULL; \ + src = vxlastheap; vxlastheap = vxnextheap; vxnextheap = src; \ + } + + + DOCLIP(Far, -, z); + DOCLIP(Near, +, z); + DOCLIP(Bottom, -, y); + DOCLIP(Top, +, y); + DOCLIP(Right, -, x); + DOCLIP(Left, +, x); + +#undef DOCLIP + + return vxlastheap; + } + + void RenderClippedTri(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2, + VDTriBltFilterMode filterMode, + float mipMapLODBias, + int orflags) + { + + VDTriBltTransformedVertex *vxheapnext; + VDTriBltTransformedVertex vxheap[21]; + + VDTriBltTransformedVertex *vxheapptr[2][19]; + VDTriBltTransformedVertex **vxlastheap = vxheapptr[0], **vxnextheap = vxheapptr[1]; + + vxheap[0] = *vx0; + vxheap[1] = *vx1; + vxheap[2] = *vx2; + + vxlastheap[0] = &vxheap[0]; + vxlastheap[1] = &vxheap[1]; + vxlastheap[2] = &vxheap[2]; + vxlastheap[3] = NULL; + + vxheapnext = vxheap + 3; + + // Current Next Action + // ------- ---- ------ + // Unclipped Unclipped Copy vertex + // Unclipped Clipped Copy vertex and add intersection + // Clipped Unclipped Add intersection + // Clipped Clipped No action + +#define DOCLIP(cliptype, _sign_, cliparg) \ + if (orflags & k##cliptype) { \ + VDTriBltTransformedVertex **src = vxlastheap; \ + VDTriBltTransformedVertex **dst = vxnextheap; \ + \ + while(*src) { \ + VDTriBltTransformedVertex *cur = *src; \ + VDTriBltTransformedVertex *next = src[1]; \ + \ + if (!next) \ + next = vxlastheap[0]; \ + \ + if (!(cur->outcode & k##cliptype)) \ + *dst++ = cur; \ + \ + if ((cur->outcode ^ next->outcode) & k##cliptype) { \ + double alpha = (cur->w _sign_ cur->cliparg) / ((cur->w _sign_ cur->cliparg) - (next->w _sign_ next->cliparg)); \ + \ + if (alpha >= 0.0 && alpha <= 1.0) { \ + vxheapnext->interp(cur, next, (float)alpha); \ + vxheapnext->cliparg = -(_sign_ vxheapnext->w); \ + *dst++ = vxheapnext++; \ + } \ + } \ + ++src; \ + } \ + *dst = NULL; \ + if (dst < vxnextheap+3) return; \ + src = vxlastheap; vxlastheap = vxnextheap; vxnextheap = src; \ + } + + + DOCLIP(Far, -, z); + DOCLIP(Near, +, z); + DOCLIP(Bottom, -, y); + DOCLIP(Top, +, y); + DOCLIP(Right, -, x); + DOCLIP(Left, +, x); + +#undef DOCLIP + + VDTriBltTransformedVertex **src = vxlastheap+1; + + while(src[1]) { + RenderTri(dst, pSources, nMipmaps, vxlastheap[0], src[0], src[1], filterMode, mipMapLODBias); + ++src; + } + } + +} + +bool VDPixmapTriFill(VDPixmap& dst, const uint32 c, const VDTriBltVertex *pVertices, int nVertices, const int *pIndices, int nIndices, const float pTransform[16]) { + if (dst.format != nsVDPixmap::kPixFormat_XRGB8888) + return false; + + static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; + vdfastvector xverts(nVertices); + + if (!pTransform) + pTransform = xf_ident; + + TransformVerts(xverts.data(), pVertices, nVertices, pTransform); + + const VDTriBltTransformedVertex *xsrc = xverts.data(); + + VDTriClipWorkspace clipws; + + while(nIndices >= 3) { + const int idx0 = pIndices[0]; + const int idx1 = pIndices[1]; + const int idx2 = pIndices[2]; + const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; + const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; + const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; + const int kode0 = xv0->outcode; + const int kode1 = xv1->outcode; + const int kode2 = xv2->outcode; + + if (!(kode0 & kode1 & kode2)) { + if (int orflags = kode0 | kode1 | kode2) { + VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); + + if (src) { + VDTriBltTransformedVertex *src0 = *src++; + + // fan out triangles + while(src[1]) { + FillTri(dst, c, src0, src[0], src[1]); + ++src; + } + } + } else + FillTri(dst, c, xv0, xv1, xv2); + } + + pIndices += 3; + nIndices -= 3; + } + + return true; +} + +bool VDPixmapTriFill(VDPixmap& dst, const VDTriColorVertex *pVertices, int nVertices, const int *pIndices, int nIndices, const float pTransform[16], const float *chroma_yoffset) { + VDPixmap pxY; + VDPixmap pxCb; + VDPixmap pxCr; + bool ycbcr = false; + float ycbcr_xoffset = 0; + + switch(dst.format) { + case nsVDPixmap::kPixFormat_XRGB8888: + case nsVDPixmap::kPixFormat_Y8: + break; + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + pxY.format = nsVDPixmap::kPixFormat_Y8; + pxY.data = dst.data; + pxY.pitch = dst.pitch; + pxY.w = dst.w; + pxY.h = dst.h; + + pxCb.format = nsVDPixmap::kPixFormat_Y8; + pxCb.data = dst.data2; + pxCb.pitch = dst.pitch2; + pxCb.w = dst.w; + pxCb.h = dst.h; + + pxCr.format = nsVDPixmap::kPixFormat_Y8; + pxCr.data = dst.data3; + pxCr.pitch = dst.pitch3; + pxCr.w = dst.w; + pxCr.h = dst.h; + + switch(dst.format) { + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 2; + pxCr.h = pxCb.h = dst.h >> 2; + ycbcr_xoffset = 0.75f / (float)pxCr.w; + break; + + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 1; + pxCr.h = pxCb.h = dst.h >> 1; + ycbcr_xoffset = 0.5f / (float)pxCr.w; + break; + + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 1; + ycbcr_xoffset = 0.5f / (float)pxCr.w; + break; + + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + pxCr.w = pxCb.w = dst.w; + ycbcr_xoffset = 0.0f; + break; + } + + ycbcr = true; + break; + default: + return false; + } + + VDTriBltTransformedVertex fastxverts[64]; + vdfastvector xverts; + + VDTriBltTransformedVertex *xsrc; + if (nVertices <= 64) { + xsrc = fastxverts; + } else { + xverts.resize(nVertices); + xsrc = xverts.data(); + } + + static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; + if (!pTransform) + pTransform = xf_ident; + + VDTriClipWorkspace clipws; + for(int plane=0; plane<(ycbcr?3:1); ++plane) { + VDPixmap& pxPlane = ycbcr ? plane == 0 ? pxY : plane == 1 ? pxCb : pxCr : dst; + + if (ycbcr && plane) { + float xf_ycbcr[16]; + memcpy(xf_ycbcr, pTransform, sizeof(float) * 16); + + // translate in x by ycbcr_xoffset + xf_ycbcr[0] += xf_ycbcr[12]*ycbcr_xoffset; + xf_ycbcr[1] += xf_ycbcr[13]*ycbcr_xoffset; + xf_ycbcr[2] += xf_ycbcr[14]*ycbcr_xoffset; + xf_ycbcr[3] += xf_ycbcr[15]*ycbcr_xoffset; + + // translate in y by chroma_yoffset + if (chroma_yoffset) { + xf_ycbcr[4] += xf_ycbcr[12]*(*chroma_yoffset); + xf_ycbcr[5] += xf_ycbcr[13]*(*chroma_yoffset); + xf_ycbcr[6] += xf_ycbcr[14]*(*chroma_yoffset); + xf_ycbcr[7] += xf_ycbcr[15]*(*chroma_yoffset); + } + + TransformVerts(xsrc, pVertices, nVertices, xf_ycbcr); + + switch(plane) { + case 1: + for(int i=0; i= 3) { + const int idx0 = nextIndex[0]; + const int idx1 = nextIndex[1]; + const int idx2 = nextIndex[2]; + const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; + const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; + const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; + const int kode0 = xv0->outcode; + const int kode1 = xv1->outcode; + const int kode2 = xv2->outcode; + + if (!(kode0 & kode1 & kode2)) { + if (int orflags = kode0 | kode1 | kode2) { + VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); + + if (src) { + VDTriBltTransformedVertex *src0 = *src++; + + // fan out triangles + while(src[1]) { + FillTriGrad(pxPlane, src0, src[0], src[1]); + ++src; + } + } + } else { + FillTriGrad(pxPlane, xv0, xv1, xv2); + } + } + + nextIndex += 3; + indicesLeft -= 3; + } + } + + return true; +} + +bool VDPixmapTriBlt(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, + const VDTriBltVertex *pVertices, int nVertices, + const int *pIndices, int nIndices, + VDTriBltFilterMode filterMode, + float mipMapLODBias, + const float pTransform[16]) +{ + if (dst.format != nsVDPixmap::kPixFormat_XRGB8888) + return false; + + static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; + vdfastvector xverts(nVertices); + + if (!pTransform) + pTransform = xf_ident; + + TransformVerts(xverts.data(), pVertices, nVertices, pTransform); + + const VDTriBltTransformedVertex *xsrc = xverts.data(); + + VDTriClipWorkspace clipws; + + while(nIndices >= 3) { + const int idx0 = pIndices[0]; + const int idx1 = pIndices[1]; + const int idx2 = pIndices[2]; + const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; + const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; + const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; + const int kode0 = xv0->outcode; + const int kode1 = xv1->outcode; + const int kode2 = xv2->outcode; + + if (!(kode0 & kode1 & kode2)) { + if (int orflags = kode0 | kode1 | kode2) { + VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); + + if (src) { + VDTriBltTransformedVertex *src0 = *src++; + + // fan out triangles + while(src[1]) { + RenderTri(dst, pSources, nMipmaps, src0, src[0], src[1], filterMode, mipMapLODBias); + ++src; + } + } + } else + RenderTri(dst, pSources, nMipmaps, xv0, xv1, xv2, filterMode, mipMapLODBias); + } + + pIndices += 3; + nIndices -= 3; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////// + +void VDPixmapSetTextureBorders(VDPixmap& px, bool wrap) { + const int w = px.w; + const int h = px.h; + + VDPixmapBlt(px, 0, 1, px, wrap ? w-2 : 1, 1, 1, h-2); + VDPixmapBlt(px, w-1, 1, px, wrap ? 1 : w-2, 1, 1, h-2); + + VDPixmapBlt(px, 0, 0, px, 0, wrap ? h-2 : 1, w, 1); + VDPixmapBlt(px, 0, h-1, px, 0, wrap ? 1 : h-2, w, 1); +} + +void VDPixmapSetTextureBordersCubic(VDPixmap& px) { + const int w = px.w; + const int h = px.h; + + VDPixmapBlt(px, 0, 1, px, 2, 1, 1, h-2); + VDPixmapBlt(px, 1, 1, px, 2, 1, 1, h-2); + VDPixmapBlt(px, w-2, 1, px, w-3, 1, 1, h-2); + VDPixmapBlt(px, w-1, 1, px, w-3, 1, 1, h-2); + + VDPixmapBlt(px, 0, 0, px, 0, 2, w, 1); + VDPixmapBlt(px, 0, 1, px, 0, 2, w, 1); + VDPixmapBlt(px, 0, h-2, px, 0, h-3, w, 1); + VDPixmapBlt(px, 0, h-1, px, 0, h-3, w, 1); +} + +/////////////////////////////////////////////////////////////////////////// + +VDPixmapTextureMipmapChain::VDPixmapTextureMipmapChain(const VDPixmap& src, bool wrap, bool cubic, int maxlevels) { + int w = src.w; + int h = src.h; + int mipcount = 0; + + while((w>1 || h>1) && maxlevels--) { + ++mipcount; + w >>= 1; + h >>= 1; + } + + mBuffers.resize(mipcount); + mMipMaps.resize(mipcount); + + vdautoptr r(VDCreatePixmapResampler()); + r->SetFilters(IVDPixmapResampler::kFilterLinear, IVDPixmapResampler::kFilterLinear, false); + + float fw = (float)src.w; + float fh = (float)src.h; + for(int mip=0; mipInit(rdst, curmip.w, curmip.h, curmip.format, rsrc, prevmip.w, prevmip.h, prevmip.format); + r->Process(curmip, prevmip); + } + } else { + mBuffers[mip].init(mipw+2, miph+2, nsVDPixmap::kPixFormat_XRGB8888); + + if (!mip) { + VDPixmapBlt(mBuffers[0], 1, 1, src, 0, 0, src.w, src.h); + VDPixmapSetTextureBorders(mBuffers[0], wrap); + } else { + const VDPixmap& curmip = mBuffers[mip]; + const VDPixmap& prevmip = mBuffers[mip-1]; + + vdrect32f rdst( 0.0f, 0.0f, (float)curmip.w , (float)curmip.h ); + vdrect32f rsrc(-1.0f, -1.0f, 2.0f*(float)curmip.w - 1.0f, 2.0f*(float)curmip.h - 1.0f); + r->Init(rdst, curmip.w, curmip.h, curmip.format, rsrc, prevmip.w, prevmip.h, prevmip.format); + r->Process(curmip, prevmip); + } + } + + fw *= 0.5f; + fh *= 0.5f; + } +} + diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit.cpp index d6caf3707fc..7381a7d4746 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit.cpp @@ -1,1416 +1,1416 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include "uberblit.h" -#include "uberblit_gen.h" -#include "uberblit_ycbcr_generic.h" - -uint32 VDPixmapGetFormatTokenFromFormat(int format) { - using namespace nsVDPixmap; - switch(format) { - case kPixFormat_Pal1: return kVDPixType_1 | kVDPixSamp_444 | kVDPixSpace_Pal; - case kPixFormat_Pal2: return kVDPixType_2 | kVDPixSamp_444 | kVDPixSpace_Pal; - case kPixFormat_Pal4: return kVDPixType_4 | kVDPixSamp_444 | kVDPixSpace_Pal; - case kPixFormat_Pal8: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Pal; - case kPixFormat_XRGB1555: return kVDPixType_1555_LE | kVDPixSamp_444 | kVDPixSpace_BGR; - case kPixFormat_RGB565: return kVDPixType_565_LE | kVDPixSamp_444 | kVDPixSpace_BGR; - case kPixFormat_RGB888: return kVDPixType_888 | kVDPixSamp_444 | kVDPixSpace_BGR; - case kPixFormat_XRGB8888: return kVDPixType_8888 | kVDPixSamp_444 | kVDPixSpace_BGR; - case kPixFormat_Y8: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Y_601; - case kPixFormat_YUV422_UYVY: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_YUYV: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV444_XVYU: return kVDPixType_8888 | kVDPixSamp_444 | kVDPixSpace_YCC_601; - case kPixFormat_YUV444_Planar: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_Planar: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_Planar_16F: return kVDPixType_16F_16F_16F_LE | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV420_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601; - case kPixFormat_YUV411_Planar: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_601; - case kPixFormat_YUV410_Planar: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_Planar_Centered: return kVDPixType_8_8_8 | kVDPixSamp_422_JPEG | kVDPixSpace_YCC_601; - case kPixFormat_YUV420_Planar_Centered: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG1 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_V210: return kVDPixType_V210 | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_UYVY_709: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; - case kPixFormat_YUV420_NV12: return kVDPixType_8_B8R8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601; - case kPixFormat_Y8_FR: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Y_601_FR; - case kPixFormat_YUV422_YUYV_709: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; - case kPixFormat_YUV444_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_709; - case kPixFormat_YUV422_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; - case kPixFormat_YUV420_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_709; - case kPixFormat_YUV411_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_709; - case kPixFormat_YUV410_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_709; - case kPixFormat_YUV422_UYVY_FR: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV422_YUYV_FR: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV444_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV422_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV420_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV411_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV410_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV422_UYVY_709_FR: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV422_YUYV_709_FR: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV444_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV422_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV420_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV411_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV410_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV420i_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_601; - case kPixFormat_YUV420i_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV420i_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_709; - case kPixFormat_YUV420i_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV420it_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_601; - case kPixFormat_YUV420it_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV420it_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_709; - case kPixFormat_YUV420it_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV420ib_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_601; - case kPixFormat_YUV420ib_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV420ib_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_709; - case kPixFormat_YUV420ib_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_709_FR; - default: - VDASSERT(false); - return 0; - } -} - -const VDPixmapSamplingInfo& VDPixmapGetSamplingInfo(uint32 samplingToken) { - static const VDPixmapSamplingInfo kPixmapSamplingInfo[]={ - /* Null */ { false, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, - /* 444 */ { false, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, - /* 422 */ { false, { -4, 0, 1, 0 }, { -4, 0, 1, 0 } }, - /* 422_JPEG */ { false, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } }, - /* 420_MPEG2 */ { false, { -4, 0, 1, 1 }, { -4, 0, 1, 1 } }, - /* 420_MPEG2INT */ { true , { -4, -2, 1, 1 }, { -4, -2, 1, 1 }, { -4, +2, 1, 1 }, { -4, +2, 1, 1 } }, - /* 420_MPEG2INT1*/ { false, { -4, -2, 1, 1 }, { -4, -2, 1, 1 } }, - /* 420_MPEG2INT2*/ { false, { -4, +2, 1, 1 }, { -4, +2, 1, 1 } }, - /* 420_MPEG1 */ { false, { 0, 0, 1, 1 }, { 0, 0, 1, 1 } }, - /* 420_DVPAL */ { true , { -4, 0, 1, 1 }, { -4, 0, 1, 1 } }, - /* 411 */ { false, { -6, 0, 2, 0 }, { -6, 0, 2, 0 } }, - /* 410 */ { false, { -6, 0, 2, 2 }, { -6, 0, 2, 2 } }, - }; - - uint32 index = (samplingToken & kVDPixSamp_Mask) >> kVDPixSamp_Bits; - - return index >= sizeof(kPixmapSamplingInfo)/sizeof(kPixmapSamplingInfo[0]) ? kPixmapSamplingInfo[0] : kPixmapSamplingInfo[index]; -} - -namespace { - uint32 GetChromaPlaneBpr(uint32 w, uint32 srcToken) { - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_1: - case kVDPixType_2: - case kVDPixType_4: - case kVDPixType_8: - case kVDPixType_555_LE: - case kVDPixType_565_LE: - case kVDPixType_1555_LE: - case kVDPixType_16F_LE: - case kVDPixType_888: - case kVDPixType_8888: - case kVDPixType_16Fx4_LE: - case kVDPixType_32F_LE: - case kVDPixType_32Fx4_LE: - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - case kVDPixType_V210: - case kVDPixType_8_B8R8: - case kVDPixType_B8R8: - default: - return 0; - - case kVDPixType_8_8_8: - return w; - - case kVDPixType_16F_16F_16F_LE: - return w*2; - - case kVDPixType_32F_32F_32F_LE: - return w*4; - } - } - - void BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapSamplingInfo& dstInfo, const VDPixmapSamplingInfo& srcInfo, sint32 cw, sint32 ch); - void BlitterConvertPlaneSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapPlaneSamplingInfo& dstInfo, const VDPixmapPlaneSamplingInfo& srcInfo, sint32 cw, sint32 ch); - - uint32 BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, uint32 srcToken, uint32 dstSamplingToken, sint32 w, sint32 h) { - // if the source type is 16F, we have to convert to 32F - if ((srcToken & kVDPixType_Mask) == kVDPixType_16F_16F_16F_LE) { - // 0 1 2 - gen.conv_16F_to_32F(); - gen.swap(1); - // 1 0 2 - gen.conv_16F_to_32F(); - gen.swap(2); - // 2 0 1 - gen.conv_16F_to_32F(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - } - - // look up sampling info - const VDPixmapSamplingInfo& srcInfo = VDPixmapGetSamplingInfo(srcToken); - const VDPixmapSamplingInfo& dstInfo = VDPixmapGetSamplingInfo(dstSamplingToken); - - // Check if we have an interlacing mismatch. If so, then we have to convert up to - // full resolution vertically in order to split or merge fields. - const sint32 cw = -(-w >> dstInfo.mPlane1Cr.mXBits); - const sint32 ch = -(-h >> dstInfo.mPlane1Cr.mYBits); - const uint32 cbpr = GetChromaPlaneBpr(cw, srcToken); - - if (dstInfo.mbInterlaced || srcInfo.mbInterlaced) { - const sint32 src_cw = -(-w >> srcInfo.mPlane1Cr.mXBits); - - const sint32 ch1 = (ch + 1) >> 1; - const sint32 ch2 = ch >> 1; - - if (dstInfo.mbInterlaced) { - if (srcInfo.mbInterlaced) { - // interlaced -> interlaced: split fields, resample, merge fields - // - // cr y cb - gen.split_fields(cbpr); - - // cr-odd cr-even y cb - BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cr, srcInfo.mPlane2Cr, cw, ch2); - - // cr-odd' cr-even y cb - gen.swap(1); - - // cr-even cr-odd' y cb - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, srcInfo.mPlane1Cr, cw, ch1); - - // cr-even' cr-odd' y cb - gen.swap(1); - - // cr-odd' cr-even' y cb - gen.merge_fields(cw, ch, cbpr); - - // cr' y cb - gen.swap(2); - - // cb' y cr' - gen.split_fields(cbpr); - - // cb-odd cb-even y cr' - BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cb, srcInfo.mPlane2Cb, cw, ch2); - - // cb-odd' cb-even y cr' - gen.swap(1); - - // cb-even cb-odd' y cr' - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, srcInfo.mPlane1Cb, cw, ch1); - - // cb-even' cb-odd' y cr' - gen.swap(1); - - // cb-odd' cb-even' y cr' - gen.merge_fields(cw, ch, cbpr); - - // cb' y cr' - gen.swap(2); - - // cr' y cb' - } else { - // non-interlaced -> interlaced - VDPixmapPlaneSamplingInfo crPlaneInt(srcInfo.mPlane1Cr); - VDPixmapPlaneSamplingInfo crPlaneFieldInt(srcInfo.mPlane1Cr); - VDPixmapPlaneSamplingInfo cbPlaneInt(srcInfo.mPlane1Cb); - VDPixmapPlaneSamplingInfo cbPlaneFieldInt(srcInfo.mPlane1Cb); - - crPlaneInt.mX = dstInfo.mPlane1Cr.mX; - crPlaneInt.mXBits = dstInfo.mPlane1Cr.mXBits; - crPlaneInt.mY = 0; - crPlaneInt.mYBits = 0; - crPlaneFieldInt.mX = dstInfo.mPlane1Cr.mX; - crPlaneFieldInt.mXBits = dstInfo.mPlane1Cr.mXBits; - crPlaneFieldInt.mY = 0; - crPlaneFieldInt.mYBits = 0; - - cbPlaneInt.mX = dstInfo.mPlane1Cb.mX; - cbPlaneInt.mXBits = dstInfo.mPlane1Cb.mXBits; - cbPlaneFieldInt.mX = dstInfo.mPlane1Cb.mX; - cbPlaneFieldInt.mXBits = dstInfo.mPlane1Cb.mXBits; - cbPlaneFieldInt.mY = 0; - cbPlaneFieldInt.mYBits = 0; - - // cr y cb - BlitterConvertPlaneSampling(gen, crPlaneInt, srcInfo.mPlane1Cr, cw, h); - - // cr' y cb - gen.split_fields(cbpr); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, crPlaneFieldInt, cw, ch1); - gen.swap(1); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cr, crPlaneFieldInt, cw, ch2); - gen.swap(1); - gen.merge_fields(cw, ch, cbpr); - - gen.swap(2); - BlitterConvertPlaneSampling(gen, cbPlaneInt, srcInfo.mPlane1Cb, cw, h); - gen.split_fields(cbpr); - gen.swap(1); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneFieldInt, cw, ch1); - gen.swap(1); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneFieldInt, cw, ch2); - gen.merge_fields(cw, ch, cbpr); - gen.swap(2); - } - } else { - sint32 src_cbpr = src_cw; - - // interlaced -> non-interlaced - VDPixmapPlaneSamplingInfo crPlaneFieldInt(srcInfo.mPlane1Cr); - VDPixmapPlaneSamplingInfo crPlaneInt(srcInfo.mPlane1Cr); - VDPixmapPlaneSamplingInfo cbPlaneFieldInt(srcInfo.mPlane1Cb); - VDPixmapPlaneSamplingInfo cbPlaneInt(srcInfo.mPlane1Cb); - - crPlaneFieldInt.mY = 0; - crPlaneFieldInt.mYBits = 0; - crPlaneInt.mY = 0; - crPlaneInt.mYBits = 0; - cbPlaneFieldInt.mY = 0; - cbPlaneFieldInt.mYBits = 0; - cbPlaneInt.mY = 0; - cbPlaneInt.mYBits = 0; - - // cr y cb - gen.split_fields(src_cbpr); - BlitterConvertPlaneSampling(gen, crPlaneFieldInt, srcInfo.mPlane1Cr, src_cw, (h + 1) >> 1); - gen.swap(1); - BlitterConvertPlaneSampling(gen, crPlaneFieldInt, srcInfo.mPlane2Cr, src_cw, h >> 1); - gen.swap(1); - gen.merge_fields(src_cw, h, src_cbpr); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, crPlaneInt, cw, ch); - gen.swap(2); - - // cr' y cb - gen.split_fields(src_cbpr); - BlitterConvertPlaneSampling(gen, cbPlaneFieldInt, srcInfo.mPlane1Cb, src_cw, (h + 1) >> 1); - gen.swap(1); - BlitterConvertPlaneSampling(gen, cbPlaneFieldInt, srcInfo.mPlane2Cb, src_cw, h >> 1); - gen.swap(1); - gen.merge_fields(src_cw, h, src_cbpr); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneInt, cw, ch); - gen.swap(2); - } - } else { - // non-interlaced -> non-interlaced - BlitterConvertSampling(gen, dstInfo, srcInfo, cw, ch); - } - - return (srcToken & ~kVDPixSamp_Mask) | (dstSamplingToken & kVDPixSamp_Mask); - } - - void BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapSamplingInfo& dstInfo, const VDPixmapSamplingInfo& srcInfo, sint32 cw, sint32 ch) { - gen.swap(2); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, srcInfo.mPlane1Cb, cw, ch); - gen.swap(2); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, srcInfo.mPlane1Cr, cw, ch); - } - - void BlitterConvertPlaneSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapPlaneSamplingInfo& dstInfo, const VDPixmapPlaneSamplingInfo& srcInfo, sint32 cw, sint32 ch) { - // convert destination chroma origin to luma space - int c_x = ((8 + dstInfo.mX) << dstInfo.mXBits) - 8; - int c_y = ((8 + dstInfo.mY) << dstInfo.mYBits) - 8; - - // convert luma chroma location to source chroma space - c_x = ((8 + c_x) >> srcInfo.mXBits) - 8 - srcInfo.mX; - c_y = ((8 + c_y) >> srcInfo.mYBits) - 8 - srcInfo.mY; - - float cxo = c_x / 16.0f + 0.5f; - float cxf = ((16 << dstInfo.mXBits) >> srcInfo.mXBits) / 16.0f; - float cyf = ((16 << dstInfo.mYBits) >> srcInfo.mYBits) / 16.0f; - - gen.linear(cxo, cxf, cw, c_y / 16.0f + 0.5f, cyf, ch); - } - - uint32 BlitterConvertType(VDPixmapUberBlitterGenerator& gen, uint32 srcToken, uint32 dstToken, sint32 w, sint32 h) { - uint32 dstType = dstToken & kVDPixType_Mask; - - while((srcToken ^ dstToken) & kVDPixType_Mask) { - uint32 srcType = srcToken & kVDPixType_Mask; - uint32 targetType = dstType; - - type_reconvert: - switch(targetType) { - case kVDPixType_1555_LE: - switch(srcType) { - case kVDPixType_565_LE: - gen.conv_565_to_555(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_1555_LE; - break; - - case kVDPixType_8888: - gen.conv_8888_to_555(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_1555_LE; - break; - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - default: - targetType = kVDPixType_8888; - goto type_reconvert; - } - break; - - case kVDPixType_565_LE: - switch(srcType) { - case kVDPixType_1555_LE: - gen.conv_555_to_565(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_565_LE; - break; - case kVDPixType_8888: - gen.conv_8888_to_565(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_565_LE; - break; - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - default: - targetType = kVDPixType_8888; - goto type_reconvert; - } - break; - - case kVDPixType_888: - switch(srcType) { - case kVDPixType_8888: - gen.conv_8888_to_888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_888; - break; - default: - targetType = kVDPixType_8888; - goto type_reconvert; - } - break; - - case kVDPixType_8888: - switch(srcType) { - case kVDPixType_1555_LE: - gen.conv_555_to_8888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - case kVDPixType_565_LE: - gen.conv_565_to_8888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - case kVDPixType_888: - gen.conv_888_to_8888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - case kVDPixType_32Fx4_LE: - gen.conv_X32F_to_8888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - case kVDPixType_8_8_8: - if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_444) - srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_444, w, h); - gen.interleave_X8R8G8B8(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - default: - VDASSERT(false); - break; - } - break; - - case kVDPixType_8: - switch(srcType) { - case kVDPixType_8_8_8: - gen.pop(); - gen.swap(1); - gen.pop(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - break; - - case kVDPixType_16F_LE: - targetType = kVDPixType_32F_LE; - goto type_reconvert; - - case kVDPixType_32F_LE: - gen.conv_32F_to_8(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - break; - - default: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - } - break; - - case kVDPixType_8_8_8: - switch(srcType) { - case kVDPixType_B8G8_R8G8: - gen.dup(); - gen.dup(); - gen.extract_8in32(2, (w + 1) >> 1, h); - gen.swap(2); - gen.extract_8in16(1, w, h); - gen.swap(1); - gen.extract_8in32(0, (w + 1) >> 1, h); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_8_8_8 | kVDPixSamp_422; - break; - case kVDPixType_G8B8_G8R8: - gen.dup(); - gen.dup(); - gen.extract_8in32(3, (w + 1) >> 1, h); - gen.swap(2); - gen.extract_8in16(0, w, h); - gen.swap(1); - gen.extract_8in32(1, (w + 1) >> 1, h); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_8_8_8 | kVDPixSamp_422; - break; - case kVDPixType_16F_16F_16F_LE: - case kVDPixType_V210: - targetType = kVDPixType_32F_32F_32F_LE; - goto type_reconvert; - case kVDPixType_32F_32F_32F_LE: - // 0 1 2 - gen.conv_32F_to_8(); - gen.swap(1); - // 1 0 2 - gen.conv_32F_to_8(); - gen.swap(2); - // 2 0 1 - gen.conv_32F_to_8(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - case kVDPixType_8_B8R8: - { - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - int cw = -(-w >> sampInfo.mPlane1Cr.mXBits); - int ch = -(-h >> sampInfo.mPlane1Cr.mYBits); - - gen.dup(); - gen.extract_8in16(1, cw, ch); - gen.swap(2); - gen.swap(1); - gen.extract_8in16(0, cw, ch); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - } - break; - default: - VDASSERT(false); - break; - } - break; - - case kVDPixType_B8G8_R8G8: - switch(srcType) { - case kVDPixType_8_8_8: - if ((srcToken ^ dstToken) & kVDPixSamp_Mask) - srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); - - gen.interleave_B8G8_R8G8(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_B8G8_R8G8; - break; - case kVDPixType_G8B8_G8R8: - gen.swap_8in16(w, h, ((w + 1) & ~1)*2); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_B8G8_R8G8; - break; - default: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - } - break; - - case kVDPixType_G8B8_G8R8: - switch(srcType) { - case kVDPixType_8_8_8: - if ((srcToken ^ dstToken) & kVDPixSamp_Mask) - srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); - - gen.interleave_G8B8_G8R8(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_G8B8_G8R8; - break; - case kVDPixType_B8G8_R8G8: - gen.swap_8in16(w, h, ((w + 1) & ~1)*2); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_G8B8_G8R8; - break; - default: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - } - break; - - case kVDPixType_16F_16F_16F_LE: - switch(srcType) { - case kVDPixType_32F_32F_32F_LE: - // 0 1 2 - gen.conv_32F_to_16F(); - gen.swap(1); - // 1 0 2 - gen.conv_32F_to_16F(); - gen.swap(2); - // 2 0 1 - gen.conv_32F_to_16F(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_16F_16F_LE; - break; - - default: - targetType = kVDPixType_32F_32F_32F_LE; - goto type_reconvert; - } - break; - - case kVDPixType_32F_32F_32F_LE: - switch(srcType) { - case kVDPixType_8_8_8: - // 0 1 2 - gen.conv_8_to_32F(); - gen.swap(1); - // 1 0 2 - gen.conv_8_to_32F(); - gen.swap(2); - // 2 0 1 - gen.conv_8_to_32F(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - break; - - case kVDPixType_16F_16F_16F_LE: - // 0 1 2 - gen.conv_16F_to_32F(); - gen.swap(1); - // 1 0 2 - gen.conv_16F_to_32F(); - gen.swap(2); - // 2 0 1 - gen.conv_16F_to_32F(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - break; - - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - case kVDPixType_8_B8R8: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - - case kVDPixType_V210: - gen.conv_V210_to_32F(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - break; - - default: - VDASSERT(false); - } - break; - - case kVDPixType_V210: - switch(srcType) { - case kVDPixType_32F_32F_32F_LE: - if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_422) - srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_422, w, h); - - gen.conv_32F_to_V210(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_V210; - break; - - case kVDPixType_16F_16F_16F_LE: - targetType = kVDPixType_32F_32F_32F_LE; - goto type_reconvert; - - case kVDPixType_8_8_8: - if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_422) - srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_422, w, h); - - targetType = kVDPixType_32F_32F_32F_LE; - goto type_reconvert; - - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - case kVDPixType_8_B8R8: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - - default: - VDASSERT(false); - } - break; - - case kVDPixType_32F_LE: - switch(srcType) { - case kVDPixType_8: - gen.conv_8_to_32F(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - break; - case kVDPixType_16F_LE: - gen.conv_16F_to_32F(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - break; - default: - VDASSERT(false); - } - break; - - case kVDPixType_8_B8R8: - switch(srcType) { - case kVDPixType_8_8_8: - gen.swap(1); - gen.swap(2); - gen.interleave_B8R8(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_B8R8; - break; - default: - VDASSERT(false); - break; - } - break; - - default: - VDASSERT(false); - break; - } - } - - return srcToken; - } -} - -IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmap& dst, const VDPixmap& src) { - const VDPixmapLayout& dstlayout = VDPixmapToLayoutFromBase(dst, dst.data); - const VDPixmapLayout& srclayout = VDPixmapToLayoutFromBase(src, src.data); - - return VDPixmapCreateBlitter(dstlayout, srclayout); -} - -IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmapLayout& dst, const VDPixmapLayout& src) { - if (src.format == dst.format) { - return VDCreatePixmapUberBlitterDirectCopy(dst, src); - } - - uint32 srcToken = VDPixmapGetFormatTokenFromFormat(src.format); - uint32 dstToken = VDPixmapGetFormatTokenFromFormat(dst.format); - - VDPixmapUberBlitterGenerator gen; - - // load source channels - int w = src.w; - int h = src.h; - - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_1: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 7) >> 3); - break; - - case kVDPixType_2: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 3) >> 2); - break; - - case kVDPixType_4: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 1) >> 1); - break; - - case kVDPixType_8: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w); - break; - - case kVDPixType_555_LE: - case kVDPixType_565_LE: - case kVDPixType_1555_LE: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*2); - break; - - case kVDPixType_888: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*3); - break; - - case kVDPixType_8888: - case kVDPixType_32F_LE: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*4); - break; - - case kVDPixType_32Fx4_LE: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*16); - break; - - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, ((w + 1) & ~1)*2); - break; - - case kVDPixType_8_8_8: - { - uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - - int cxbits = sampInfo.mPlane1Cb.mXBits; - int cybits = sampInfo.mPlane1Cb.mYBits; - int w2 = -(-w >> cxbits); - int h2 = -(-h >> cybits); - gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2); - gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w); - gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2); - } - break; - - case kVDPixType_16F_16F_16F_LE: - { - uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; - uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; - uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; - - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - - int cxbits = sampInfo.mPlane1Cb.mXBits; - int cybits = sampInfo.mPlane1Cb.mYBits; - int w2 = -(-w >> cxbits); - int h2 = -(-h >> cybits); - gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2 * 2); - gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w*2); - gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2 * 2); - } - break; - - case kVDPixType_32F_32F_32F_LE: - { - uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - - int cxbits = sampInfo.mPlane1Cb.mXBits; - int cybits = sampInfo.mPlane1Cb.mYBits; - int w2 = -(-w >> cxbits); - int h2 = -(-h >> cybits); - gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2 * 4); - gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w*4); - gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2 * 4); - } - break; - - case kVDPixType_V210: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, ((w + 5) / 6) * 4); - break; - - case kVDPixType_8_B8R8: - { - uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - uint32 ctoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_B8R8; - - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - - int cxbits = sampInfo.mPlane1Cb.mXBits; - int cybits = sampInfo.mPlane1Cb.mYBits; - int w2 = -(-w >> cxbits); - int h2 = -(-h >> cybits); - gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w); - gen.ldsrc(0, 1, 0, 0, w2, h2, ctoken, w2*2); - } - break; - - default: - VDASSERT(false); - } - - // check if we need a color space change - if ((srcToken ^ dstToken) & kVDPixSpace_Mask) { - // first, if we're dealing with an interleaved format, deinterleave it - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_B8G8_R8G8: - gen.dup(); - gen.dup(); - gen.extract_8in32(2, (w + 1) >> 1, h); - gen.swap(2); - gen.extract_8in16(1, w, h); - gen.swap(1); - gen.extract_8in32(0, (w + 1) >> 1, h); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - - case kVDPixType_G8B8_G8R8: - gen.dup(); - gen.dup(); - gen.extract_8in32(3, (w + 1) >> 1, h); - gen.swap(2); - gen.extract_8in16(0, w, h); - gen.swap(1); - gen.extract_8in32(1, (w + 1) >> 1, h); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - - case kVDPixType_8_B8R8: - gen.dup(); - gen.extract_8in16(1, (w + 1) >> 1, (h + 1) >> 1); - gen.swap(2); - gen.swap(1); - gen.extract_8in16(0, (w + 1) >> 1, (h + 1) >> 1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - - case kVDPixType_V210: - gen.conv_V210_to_32F(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - break; - } - - // if the source is subsampled, converge on 4:4:4 subsampling, but only if we actually need - // the auxiliary channels - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - -#if 0 - // This check is currently disabled because we currently do need the chroma planes - // if we're doing a color space conversion, even if we are going to Y-only. - switch(dstToken & kVDPixSpace_Mask) { -// case kVDPixSpace_Y_601: -// case kVDPixSpace_Y_709: -// case kVDPixSpace_Y_601_FR: -// case kVDPixSpace_Y_709_FR: -// break; - - default: -#endif - if (sampInfo.mPlane1Cb.mXBits | - sampInfo.mPlane1Cb.mYBits | - sampInfo.mPlane1Cb.mX | - sampInfo.mPlane1Cb.mY | - sampInfo.mPlane1Cr.mX | - sampInfo.mPlane1Cr.mY) - srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_444, w, h); -#if 0 - break; - } -#endif - - // change color spaces - uint32 dstSpace = dstToken & kVDPixSpace_Mask; - while((srcToken ^ dstToken) & kVDPixSpace_Mask) { - uint32 srcSpace = srcToken & kVDPixSpace_Mask; - uint32 targetSpace = dstSpace; - -space_reconvert: - switch(targetSpace) { - case kVDPixSpace_BGR: - switch(srcSpace) { - case kVDPixSpace_YCC_709: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - gen.ycbcr709_to_rgb32(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_16F_16F_16F_LE: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_32F_32F_32F_LE, w, h); - gen.ycbcr709_to_rgb32_32f(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; - break; - - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr709_to_rgb32_32f(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_601: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - gen.ycbcr601_to_rgb32(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_16F_16F_16F_LE: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_32F_32F_32F_LE, w, h); - gen.ycbcr601_to_rgb32_32f(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; - break; - - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr601_to_rgb32_32f(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_709_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - gen.ycbcr_to_rgb32_generic(g_VDPixmapGenYCbCrBasis_709, false); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_601_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - gen.ycbcr_to_rgb32_generic(g_VDPixmapGenYCbCrBasis_601, false); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_Y_601: - targetSpace = kVDPixSpace_YCC_601; - goto space_reconvert; - - case kVDPixSpace_Y_709: - targetSpace = kVDPixSpace_YCC_709; - goto space_reconvert; - - case kVDPixSpace_Y_601_FR: - targetSpace = kVDPixSpace_YCC_601_FR; - goto space_reconvert; - - case kVDPixSpace_Y_709_FR: - targetSpace = kVDPixSpace_YCC_709_FR; - goto space_reconvert; - - case kVDPixSpace_Pal: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_1: - gen.conv_Pal1_to_8888(0); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_2: - gen.conv_Pal2_to_8888(0); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_4: - gen.conv_Pal4_to_8888(0); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_8: - gen.conv_Pal8_to_8888(0); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - default: - VDASSERT(false); - break; - } - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_Y_601: - switch(srcSpace) { - case kVDPixSpace_YCC_601: - gen.pop(); - gen.swap(1); - gen.pop(); - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_32F_32F_32F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; - break; - case kVDPixType_16F_16F_16F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; - break; - case kVDPixType_8_8_8: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - break; - - default: - VDASSERT(false); - } - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); - break; - - default: - targetSpace = kVDPixSpace_YCC_601; - goto space_reconvert; - } - break; - - case kVDPixSpace_Y_601_FR: - switch(srcSpace) { - case kVDPixSpace_YCC_601_FR: - gen.pop(); - gen.swap(1); - gen.pop(); - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_32F_32F_32F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; - break; - case kVDPixType_16F_16F_16F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; - break; - case kVDPixType_8_8_8: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - break; - - default: - VDASSERT(false); - } - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); - break; - - default: - targetSpace = kVDPixSpace_YCC_601_FR; - goto space_reconvert; - } - break; - - case kVDPixSpace_Y_709: - switch(srcSpace) { - case kVDPixSpace_YCC_709: - gen.pop(); - gen.swap(1); - gen.pop(); - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_32F_32F_32F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; - break; - case kVDPixType_16F_16F_16F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; - break; - case kVDPixType_8_8_8: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - break; - - default: - VDASSERT(false); - } - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); - break; - - default: - targetSpace = kVDPixSpace_YCC_709; - goto space_reconvert; - } - break; - - case kVDPixSpace_Y_709_FR: - switch(srcSpace) { - case kVDPixSpace_YCC_709_FR: - gen.pop(); - gen.swap(1); - gen.pop(); - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_32F_32F_32F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; - break; - case kVDPixType_16F_16F_16F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; - break; - case kVDPixType_8_8_8: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - break; - - default: - VDASSERT(false); - } - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); - break; - - default: - targetSpace = kVDPixSpace_YCC_709_FR; - goto space_reconvert; - } - break; - - case kVDPixSpace_YCC_601: - switch(srcSpace) { - case kVDPixSpace_BGR: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); - gen.rgb32_to_ycbcr601(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_601 | kVDPixType_8_8_8; - break; - case kVDPixSpace_Y_601: - case kVDPixSpace_Y_709: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_601 | kVDPixType_8; - - { - const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); - int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; - int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; - - gen.ldconst(0x80, cw, cw, ch, srcToken); - } - - gen.dup(); - gen.swap(2); - gen.swap(1); - srcToken = kVDPixSpace_YCC_601 | kVDPixType_8_8_8 | (srcToken & kVDPixSamp_Mask); - break; - - case kVDPixSpace_Y_601_FR: - targetSpace = kVDPixSpace_YCC_601_FR; - goto space_reconvert; - - case kVDPixSpace_Y_709_FR: - targetSpace = kVDPixSpace_YCC_709_FR; - goto space_reconvert; - - case kVDPixSpace_YCC_709: - VDASSERT((srcToken & kVDPixType_Mask) == kVDPixType_8_8_8); - gen.ycbcr709_to_ycbcr601(); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; - break; - - case kVDPixSpace_YCC_601_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_601, true, g_VDPixmapGenYCbCrBasis_601, false, kVDPixSpace_YCC_601); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_709_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_601, true, g_VDPixmapGenYCbCrBasis_709, false, kVDPixSpace_YCC_601); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_Pal: - targetSpace = kVDPixSpace_BGR; - goto space_reconvert; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_709: - switch(srcSpace) { - case kVDPixSpace_BGR: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); - gen.rgb32_to_ycbcr709(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_709 | kVDPixType_8_8_8; - break; - case kVDPixSpace_Y_601: - case kVDPixSpace_Y_709: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_709 | kVDPixType_8; - - { - const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); - int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; - int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; - - gen.ldconst(0x80, cw, cw, ch, srcToken); - } - - gen.dup(); - gen.swap(2); - gen.swap(1); - srcToken = kVDPixSpace_YCC_709 | kVDPixType_8_8_8 | (srcToken & kVDPixSamp_Mask); - break; - case kVDPixSpace_YCC_601: - if ((srcToken & kVDPixType_Mask) == kVDPixType_8_8_8) - gen.ycbcr601_to_ycbcr709(); - else - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_601, true, kVDPixSpace_YCC_709); - - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; - break; - - case kVDPixSpace_YCC_601_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_601, false, kVDPixSpace_YCC_709); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_709_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_709, false, kVDPixSpace_YCC_709); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_Y_601_FR: - targetSpace = kVDPixSpace_YCC_601_FR; - goto space_reconvert; - - case kVDPixSpace_Y_709_FR: - targetSpace = kVDPixSpace_YCC_709_FR; - goto space_reconvert; - - case kVDPixSpace_Pal: - targetSpace = kVDPixSpace_BGR; - goto space_reconvert; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_601_FR: - case kVDPixSpace_YCC_709_FR: - { - const VDPixmapGenYCbCrBasis& dstBasis = *(targetSpace == kVDPixSpace_YCC_601_FR ? &g_VDPixmapGenYCbCrBasis_601 : &g_VDPixmapGenYCbCrBasis_709); - - switch(srcSpace) { - case kVDPixSpace_BGR: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); - gen.rgb32_to_ycbcr_generic(dstBasis, false, targetSpace); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8_8_8; - break; - case kVDPixSpace_Y_601_FR: - case kVDPixSpace_Y_709_FR: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - - { - const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); - int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; - int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; - - gen.ldconst(0x80, cw, cw, ch, srcToken); - } - - gen.dup(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - case kVDPixSpace_YCC_601: - gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_601, true, targetSpace); - srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; - break; - case kVDPixSpace_YCC_709: - gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_709, true, targetSpace); - srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; - break; - case kVDPixSpace_YCC_601_FR: - gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_601, false, targetSpace); - srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; - break; - case kVDPixSpace_YCC_709_FR: - gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_709, false, targetSpace); - srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; - break; - case kVDPixSpace_Pal: - targetSpace = kVDPixSpace_BGR; - goto space_reconvert; - - case kVDPixSpace_Y_601: - targetSpace = kVDPixSpace_YCC_601; - goto space_reconvert; - - case kVDPixSpace_Y_709: - targetSpace = kVDPixSpace_YCC_709; - goto space_reconvert; - - default: - VDASSERT(false); - break; - } - } - break; - - default: - VDASSERT(false); - break; - } - } - } - - // check if we need a type change - // - // Note: If the sampling is also different, we have to be careful about what types we - // target. The type conversion may itself involve a sampling conversion, so things get - // VERY tricky here. - if ((srcToken ^ dstToken) & kVDPixType_Mask) { - bool samplingDifferent = 0 != ((srcToken ^ dstToken) & kVDPixSamp_Mask); - uint32 intermediateTypeToken = dstToken & kVDPixType_Mask; - - if (samplingDifferent) { - switch(dstToken & kVDPixType_Mask) { - case kVDPixType_16F_16F_16F_LE: - intermediateTypeToken = kVDPixType_32F_32F_32F_LE; - break; - case kVDPixType_8_B8R8: - intermediateTypeToken = kVDPixType_8_8_8; - break; - } - } - - srcToken = BlitterConvertType(gen, srcToken, (dstToken & ~kVDPixType_Mask) | intermediateTypeToken, w, h); - } - - // convert subsampling if necessary - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_16F_16F_16F_LE: - case kVDPixType_32F_32F_32F_LE: - if ((srcToken ^ dstToken) & kVDPixSamp_Mask) - srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); - break; - } - - // check if we need a type change (possible with 16F) - srcToken = BlitterConvertType(gen, srcToken, dstToken, w, h); - - return gen.create(); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include "uberblit.h" +#include "uberblit_gen.h" +#include "uberblit_ycbcr_generic.h" + +uint32 VDPixmapGetFormatTokenFromFormat(int format) { + using namespace nsVDPixmap; + switch(format) { + case kPixFormat_Pal1: return kVDPixType_1 | kVDPixSamp_444 | kVDPixSpace_Pal; + case kPixFormat_Pal2: return kVDPixType_2 | kVDPixSamp_444 | kVDPixSpace_Pal; + case kPixFormat_Pal4: return kVDPixType_4 | kVDPixSamp_444 | kVDPixSpace_Pal; + case kPixFormat_Pal8: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Pal; + case kPixFormat_XRGB1555: return kVDPixType_1555_LE | kVDPixSamp_444 | kVDPixSpace_BGR; + case kPixFormat_RGB565: return kVDPixType_565_LE | kVDPixSamp_444 | kVDPixSpace_BGR; + case kPixFormat_RGB888: return kVDPixType_888 | kVDPixSamp_444 | kVDPixSpace_BGR; + case kPixFormat_XRGB8888: return kVDPixType_8888 | kVDPixSamp_444 | kVDPixSpace_BGR; + case kPixFormat_Y8: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Y_601; + case kPixFormat_YUV422_UYVY: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_YUYV: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV444_XVYU: return kVDPixType_8888 | kVDPixSamp_444 | kVDPixSpace_YCC_601; + case kPixFormat_YUV444_Planar: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_Planar: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_Planar_16F: return kVDPixType_16F_16F_16F_LE | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV420_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601; + case kPixFormat_YUV411_Planar: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_601; + case kPixFormat_YUV410_Planar: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_Planar_Centered: return kVDPixType_8_8_8 | kVDPixSamp_422_JPEG | kVDPixSpace_YCC_601; + case kPixFormat_YUV420_Planar_Centered: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG1 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_V210: return kVDPixType_V210 | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_UYVY_709: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; + case kPixFormat_YUV420_NV12: return kVDPixType_8_B8R8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601; + case kPixFormat_Y8_FR: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Y_601_FR; + case kPixFormat_YUV422_YUYV_709: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; + case kPixFormat_YUV444_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_709; + case kPixFormat_YUV422_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; + case kPixFormat_YUV420_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_709; + case kPixFormat_YUV411_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_709; + case kPixFormat_YUV410_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_709; + case kPixFormat_YUV422_UYVY_FR: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV422_YUYV_FR: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV444_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV422_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV420_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV411_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV410_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV422_UYVY_709_FR: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV422_YUYV_709_FR: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV444_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV422_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV420_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV411_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV410_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV420i_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_601; + case kPixFormat_YUV420i_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV420i_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_709; + case kPixFormat_YUV420i_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV420it_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_601; + case kPixFormat_YUV420it_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV420it_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_709; + case kPixFormat_YUV420it_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV420ib_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_601; + case kPixFormat_YUV420ib_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV420ib_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_709; + case kPixFormat_YUV420ib_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_709_FR; + default: + VDASSERT(false); + return 0; + } +} + +const VDPixmapSamplingInfo& VDPixmapGetSamplingInfo(uint32 samplingToken) { + static const VDPixmapSamplingInfo kPixmapSamplingInfo[]={ + /* Null */ { false, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, + /* 444 */ { false, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, + /* 422 */ { false, { -4, 0, 1, 0 }, { -4, 0, 1, 0 } }, + /* 422_JPEG */ { false, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } }, + /* 420_MPEG2 */ { false, { -4, 0, 1, 1 }, { -4, 0, 1, 1 } }, + /* 420_MPEG2INT */ { true , { -4, -2, 1, 1 }, { -4, -2, 1, 1 }, { -4, +2, 1, 1 }, { -4, +2, 1, 1 } }, + /* 420_MPEG2INT1*/ { false, { -4, -2, 1, 1 }, { -4, -2, 1, 1 } }, + /* 420_MPEG2INT2*/ { false, { -4, +2, 1, 1 }, { -4, +2, 1, 1 } }, + /* 420_MPEG1 */ { false, { 0, 0, 1, 1 }, { 0, 0, 1, 1 } }, + /* 420_DVPAL */ { true , { -4, 0, 1, 1 }, { -4, 0, 1, 1 } }, + /* 411 */ { false, { -6, 0, 2, 0 }, { -6, 0, 2, 0 } }, + /* 410 */ { false, { -6, 0, 2, 2 }, { -6, 0, 2, 2 } }, + }; + + uint32 index = (samplingToken & kVDPixSamp_Mask) >> kVDPixSamp_Bits; + + return index >= sizeof(kPixmapSamplingInfo)/sizeof(kPixmapSamplingInfo[0]) ? kPixmapSamplingInfo[0] : kPixmapSamplingInfo[index]; +} + +namespace { + uint32 GetChromaPlaneBpr(uint32 w, uint32 srcToken) { + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_1: + case kVDPixType_2: + case kVDPixType_4: + case kVDPixType_8: + case kVDPixType_555_LE: + case kVDPixType_565_LE: + case kVDPixType_1555_LE: + case kVDPixType_16F_LE: + case kVDPixType_888: + case kVDPixType_8888: + case kVDPixType_16Fx4_LE: + case kVDPixType_32F_LE: + case kVDPixType_32Fx4_LE: + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + case kVDPixType_V210: + case kVDPixType_8_B8R8: + case kVDPixType_B8R8: + default: + return 0; + + case kVDPixType_8_8_8: + return w; + + case kVDPixType_16F_16F_16F_LE: + return w*2; + + case kVDPixType_32F_32F_32F_LE: + return w*4; + } + } + + void BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapSamplingInfo& dstInfo, const VDPixmapSamplingInfo& srcInfo, sint32 cw, sint32 ch); + void BlitterConvertPlaneSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapPlaneSamplingInfo& dstInfo, const VDPixmapPlaneSamplingInfo& srcInfo, sint32 cw, sint32 ch); + + uint32 BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, uint32 srcToken, uint32 dstSamplingToken, sint32 w, sint32 h) { + // if the source type is 16F, we have to convert to 32F + if ((srcToken & kVDPixType_Mask) == kVDPixType_16F_16F_16F_LE) { + // 0 1 2 + gen.conv_16F_to_32F(); + gen.swap(1); + // 1 0 2 + gen.conv_16F_to_32F(); + gen.swap(2); + // 2 0 1 + gen.conv_16F_to_32F(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + } + + // look up sampling info + const VDPixmapSamplingInfo& srcInfo = VDPixmapGetSamplingInfo(srcToken); + const VDPixmapSamplingInfo& dstInfo = VDPixmapGetSamplingInfo(dstSamplingToken); + + // Check if we have an interlacing mismatch. If so, then we have to convert up to + // full resolution vertically in order to split or merge fields. + const sint32 cw = -(-w >> dstInfo.mPlane1Cr.mXBits); + const sint32 ch = -(-h >> dstInfo.mPlane1Cr.mYBits); + const uint32 cbpr = GetChromaPlaneBpr(cw, srcToken); + + if (dstInfo.mbInterlaced || srcInfo.mbInterlaced) { + const sint32 src_cw = -(-w >> srcInfo.mPlane1Cr.mXBits); + + const sint32 ch1 = (ch + 1) >> 1; + const sint32 ch2 = ch >> 1; + + if (dstInfo.mbInterlaced) { + if (srcInfo.mbInterlaced) { + // interlaced -> interlaced: split fields, resample, merge fields + // + // cr y cb + gen.split_fields(cbpr); + + // cr-odd cr-even y cb + BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cr, srcInfo.mPlane2Cr, cw, ch2); + + // cr-odd' cr-even y cb + gen.swap(1); + + // cr-even cr-odd' y cb + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, srcInfo.mPlane1Cr, cw, ch1); + + // cr-even' cr-odd' y cb + gen.swap(1); + + // cr-odd' cr-even' y cb + gen.merge_fields(cw, ch, cbpr); + + // cr' y cb + gen.swap(2); + + // cb' y cr' + gen.split_fields(cbpr); + + // cb-odd cb-even y cr' + BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cb, srcInfo.mPlane2Cb, cw, ch2); + + // cb-odd' cb-even y cr' + gen.swap(1); + + // cb-even cb-odd' y cr' + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, srcInfo.mPlane1Cb, cw, ch1); + + // cb-even' cb-odd' y cr' + gen.swap(1); + + // cb-odd' cb-even' y cr' + gen.merge_fields(cw, ch, cbpr); + + // cb' y cr' + gen.swap(2); + + // cr' y cb' + } else { + // non-interlaced -> interlaced + VDPixmapPlaneSamplingInfo crPlaneInt(srcInfo.mPlane1Cr); + VDPixmapPlaneSamplingInfo crPlaneFieldInt(srcInfo.mPlane1Cr); + VDPixmapPlaneSamplingInfo cbPlaneInt(srcInfo.mPlane1Cb); + VDPixmapPlaneSamplingInfo cbPlaneFieldInt(srcInfo.mPlane1Cb); + + crPlaneInt.mX = dstInfo.mPlane1Cr.mX; + crPlaneInt.mXBits = dstInfo.mPlane1Cr.mXBits; + crPlaneInt.mY = 0; + crPlaneInt.mYBits = 0; + crPlaneFieldInt.mX = dstInfo.mPlane1Cr.mX; + crPlaneFieldInt.mXBits = dstInfo.mPlane1Cr.mXBits; + crPlaneFieldInt.mY = 0; + crPlaneFieldInt.mYBits = 0; + + cbPlaneInt.mX = dstInfo.mPlane1Cb.mX; + cbPlaneInt.mXBits = dstInfo.mPlane1Cb.mXBits; + cbPlaneFieldInt.mX = dstInfo.mPlane1Cb.mX; + cbPlaneFieldInt.mXBits = dstInfo.mPlane1Cb.mXBits; + cbPlaneFieldInt.mY = 0; + cbPlaneFieldInt.mYBits = 0; + + // cr y cb + BlitterConvertPlaneSampling(gen, crPlaneInt, srcInfo.mPlane1Cr, cw, h); + + // cr' y cb + gen.split_fields(cbpr); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, crPlaneFieldInt, cw, ch1); + gen.swap(1); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cr, crPlaneFieldInt, cw, ch2); + gen.swap(1); + gen.merge_fields(cw, ch, cbpr); + + gen.swap(2); + BlitterConvertPlaneSampling(gen, cbPlaneInt, srcInfo.mPlane1Cb, cw, h); + gen.split_fields(cbpr); + gen.swap(1); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneFieldInt, cw, ch1); + gen.swap(1); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneFieldInt, cw, ch2); + gen.merge_fields(cw, ch, cbpr); + gen.swap(2); + } + } else { + sint32 src_cbpr = src_cw; + + // interlaced -> non-interlaced + VDPixmapPlaneSamplingInfo crPlaneFieldInt(srcInfo.mPlane1Cr); + VDPixmapPlaneSamplingInfo crPlaneInt(srcInfo.mPlane1Cr); + VDPixmapPlaneSamplingInfo cbPlaneFieldInt(srcInfo.mPlane1Cb); + VDPixmapPlaneSamplingInfo cbPlaneInt(srcInfo.mPlane1Cb); + + crPlaneFieldInt.mY = 0; + crPlaneFieldInt.mYBits = 0; + crPlaneInt.mY = 0; + crPlaneInt.mYBits = 0; + cbPlaneFieldInt.mY = 0; + cbPlaneFieldInt.mYBits = 0; + cbPlaneInt.mY = 0; + cbPlaneInt.mYBits = 0; + + // cr y cb + gen.split_fields(src_cbpr); + BlitterConvertPlaneSampling(gen, crPlaneFieldInt, srcInfo.mPlane1Cr, src_cw, (h + 1) >> 1); + gen.swap(1); + BlitterConvertPlaneSampling(gen, crPlaneFieldInt, srcInfo.mPlane2Cr, src_cw, h >> 1); + gen.swap(1); + gen.merge_fields(src_cw, h, src_cbpr); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, crPlaneInt, cw, ch); + gen.swap(2); + + // cr' y cb + gen.split_fields(src_cbpr); + BlitterConvertPlaneSampling(gen, cbPlaneFieldInt, srcInfo.mPlane1Cb, src_cw, (h + 1) >> 1); + gen.swap(1); + BlitterConvertPlaneSampling(gen, cbPlaneFieldInt, srcInfo.mPlane2Cb, src_cw, h >> 1); + gen.swap(1); + gen.merge_fields(src_cw, h, src_cbpr); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneInt, cw, ch); + gen.swap(2); + } + } else { + // non-interlaced -> non-interlaced + BlitterConvertSampling(gen, dstInfo, srcInfo, cw, ch); + } + + return (srcToken & ~kVDPixSamp_Mask) | (dstSamplingToken & kVDPixSamp_Mask); + } + + void BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapSamplingInfo& dstInfo, const VDPixmapSamplingInfo& srcInfo, sint32 cw, sint32 ch) { + gen.swap(2); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, srcInfo.mPlane1Cb, cw, ch); + gen.swap(2); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, srcInfo.mPlane1Cr, cw, ch); + } + + void BlitterConvertPlaneSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapPlaneSamplingInfo& dstInfo, const VDPixmapPlaneSamplingInfo& srcInfo, sint32 cw, sint32 ch) { + // convert destination chroma origin to luma space + int c_x = ((8 + dstInfo.mX) << dstInfo.mXBits) - 8; + int c_y = ((8 + dstInfo.mY) << dstInfo.mYBits) - 8; + + // convert luma chroma location to source chroma space + c_x = ((8 + c_x) >> srcInfo.mXBits) - 8 - srcInfo.mX; + c_y = ((8 + c_y) >> srcInfo.mYBits) - 8 - srcInfo.mY; + + float cxo = c_x / 16.0f + 0.5f; + float cxf = ((16 << dstInfo.mXBits) >> srcInfo.mXBits) / 16.0f; + float cyf = ((16 << dstInfo.mYBits) >> srcInfo.mYBits) / 16.0f; + + gen.linear(cxo, cxf, cw, c_y / 16.0f + 0.5f, cyf, ch); + } + + uint32 BlitterConvertType(VDPixmapUberBlitterGenerator& gen, uint32 srcToken, uint32 dstToken, sint32 w, sint32 h) { + uint32 dstType = dstToken & kVDPixType_Mask; + + while((srcToken ^ dstToken) & kVDPixType_Mask) { + uint32 srcType = srcToken & kVDPixType_Mask; + uint32 targetType = dstType; + + type_reconvert: + switch(targetType) { + case kVDPixType_1555_LE: + switch(srcType) { + case kVDPixType_565_LE: + gen.conv_565_to_555(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_1555_LE; + break; + + case kVDPixType_8888: + gen.conv_8888_to_555(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_1555_LE; + break; + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + default: + targetType = kVDPixType_8888; + goto type_reconvert; + } + break; + + case kVDPixType_565_LE: + switch(srcType) { + case kVDPixType_1555_LE: + gen.conv_555_to_565(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_565_LE; + break; + case kVDPixType_8888: + gen.conv_8888_to_565(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_565_LE; + break; + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + default: + targetType = kVDPixType_8888; + goto type_reconvert; + } + break; + + case kVDPixType_888: + switch(srcType) { + case kVDPixType_8888: + gen.conv_8888_to_888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_888; + break; + default: + targetType = kVDPixType_8888; + goto type_reconvert; + } + break; + + case kVDPixType_8888: + switch(srcType) { + case kVDPixType_1555_LE: + gen.conv_555_to_8888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + case kVDPixType_565_LE: + gen.conv_565_to_8888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + case kVDPixType_888: + gen.conv_888_to_8888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + case kVDPixType_32Fx4_LE: + gen.conv_X32F_to_8888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + case kVDPixType_8_8_8: + if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_444) + srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_444, w, h); + gen.interleave_X8R8G8B8(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + default: + VDASSERT(false); + break; + } + break; + + case kVDPixType_8: + switch(srcType) { + case kVDPixType_8_8_8: + gen.pop(); + gen.swap(1); + gen.pop(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + break; + + case kVDPixType_16F_LE: + targetType = kVDPixType_32F_LE; + goto type_reconvert; + + case kVDPixType_32F_LE: + gen.conv_32F_to_8(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + break; + + default: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + } + break; + + case kVDPixType_8_8_8: + switch(srcType) { + case kVDPixType_B8G8_R8G8: + gen.dup(); + gen.dup(); + gen.extract_8in32(2, (w + 1) >> 1, h); + gen.swap(2); + gen.extract_8in16(1, w, h); + gen.swap(1); + gen.extract_8in32(0, (w + 1) >> 1, h); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_8_8_8 | kVDPixSamp_422; + break; + case kVDPixType_G8B8_G8R8: + gen.dup(); + gen.dup(); + gen.extract_8in32(3, (w + 1) >> 1, h); + gen.swap(2); + gen.extract_8in16(0, w, h); + gen.swap(1); + gen.extract_8in32(1, (w + 1) >> 1, h); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_8_8_8 | kVDPixSamp_422; + break; + case kVDPixType_16F_16F_16F_LE: + case kVDPixType_V210: + targetType = kVDPixType_32F_32F_32F_LE; + goto type_reconvert; + case kVDPixType_32F_32F_32F_LE: + // 0 1 2 + gen.conv_32F_to_8(); + gen.swap(1); + // 1 0 2 + gen.conv_32F_to_8(); + gen.swap(2); + // 2 0 1 + gen.conv_32F_to_8(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + case kVDPixType_8_B8R8: + { + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + int cw = -(-w >> sampInfo.mPlane1Cr.mXBits); + int ch = -(-h >> sampInfo.mPlane1Cr.mYBits); + + gen.dup(); + gen.extract_8in16(1, cw, ch); + gen.swap(2); + gen.swap(1); + gen.extract_8in16(0, cw, ch); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + } + break; + default: + VDASSERT(false); + break; + } + break; + + case kVDPixType_B8G8_R8G8: + switch(srcType) { + case kVDPixType_8_8_8: + if ((srcToken ^ dstToken) & kVDPixSamp_Mask) + srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); + + gen.interleave_B8G8_R8G8(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_B8G8_R8G8; + break; + case kVDPixType_G8B8_G8R8: + gen.swap_8in16(w, h, ((w + 1) & ~1)*2); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_B8G8_R8G8; + break; + default: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + } + break; + + case kVDPixType_G8B8_G8R8: + switch(srcType) { + case kVDPixType_8_8_8: + if ((srcToken ^ dstToken) & kVDPixSamp_Mask) + srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); + + gen.interleave_G8B8_G8R8(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_G8B8_G8R8; + break; + case kVDPixType_B8G8_R8G8: + gen.swap_8in16(w, h, ((w + 1) & ~1)*2); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_G8B8_G8R8; + break; + default: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + } + break; + + case kVDPixType_16F_16F_16F_LE: + switch(srcType) { + case kVDPixType_32F_32F_32F_LE: + // 0 1 2 + gen.conv_32F_to_16F(); + gen.swap(1); + // 1 0 2 + gen.conv_32F_to_16F(); + gen.swap(2); + // 2 0 1 + gen.conv_32F_to_16F(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_16F_16F_LE; + break; + + default: + targetType = kVDPixType_32F_32F_32F_LE; + goto type_reconvert; + } + break; + + case kVDPixType_32F_32F_32F_LE: + switch(srcType) { + case kVDPixType_8_8_8: + // 0 1 2 + gen.conv_8_to_32F(); + gen.swap(1); + // 1 0 2 + gen.conv_8_to_32F(); + gen.swap(2); + // 2 0 1 + gen.conv_8_to_32F(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + break; + + case kVDPixType_16F_16F_16F_LE: + // 0 1 2 + gen.conv_16F_to_32F(); + gen.swap(1); + // 1 0 2 + gen.conv_16F_to_32F(); + gen.swap(2); + // 2 0 1 + gen.conv_16F_to_32F(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + break; + + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + case kVDPixType_8_B8R8: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + + case kVDPixType_V210: + gen.conv_V210_to_32F(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + break; + + default: + VDASSERT(false); + } + break; + + case kVDPixType_V210: + switch(srcType) { + case kVDPixType_32F_32F_32F_LE: + if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_422) + srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_422, w, h); + + gen.conv_32F_to_V210(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_V210; + break; + + case kVDPixType_16F_16F_16F_LE: + targetType = kVDPixType_32F_32F_32F_LE; + goto type_reconvert; + + case kVDPixType_8_8_8: + if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_422) + srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_422, w, h); + + targetType = kVDPixType_32F_32F_32F_LE; + goto type_reconvert; + + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + case kVDPixType_8_B8R8: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + + default: + VDASSERT(false); + } + break; + + case kVDPixType_32F_LE: + switch(srcType) { + case kVDPixType_8: + gen.conv_8_to_32F(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + break; + case kVDPixType_16F_LE: + gen.conv_16F_to_32F(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + break; + default: + VDASSERT(false); + } + break; + + case kVDPixType_8_B8R8: + switch(srcType) { + case kVDPixType_8_8_8: + gen.swap(1); + gen.swap(2); + gen.interleave_B8R8(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_B8R8; + break; + default: + VDASSERT(false); + break; + } + break; + + default: + VDASSERT(false); + break; + } + } + + return srcToken; + } +} + +IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmap& dst, const VDPixmap& src) { + const VDPixmapLayout& dstlayout = VDPixmapToLayoutFromBase(dst, dst.data); + const VDPixmapLayout& srclayout = VDPixmapToLayoutFromBase(src, src.data); + + return VDPixmapCreateBlitter(dstlayout, srclayout); +} + +IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmapLayout& dst, const VDPixmapLayout& src) { + if (src.format == dst.format) { + return VDCreatePixmapUberBlitterDirectCopy(dst, src); + } + + uint32 srcToken = VDPixmapGetFormatTokenFromFormat(src.format); + uint32 dstToken = VDPixmapGetFormatTokenFromFormat(dst.format); + + VDPixmapUberBlitterGenerator gen; + + // load source channels + int w = src.w; + int h = src.h; + + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_1: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 7) >> 3); + break; + + case kVDPixType_2: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 3) >> 2); + break; + + case kVDPixType_4: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 1) >> 1); + break; + + case kVDPixType_8: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w); + break; + + case kVDPixType_555_LE: + case kVDPixType_565_LE: + case kVDPixType_1555_LE: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*2); + break; + + case kVDPixType_888: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*3); + break; + + case kVDPixType_8888: + case kVDPixType_32F_LE: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*4); + break; + + case kVDPixType_32Fx4_LE: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*16); + break; + + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, ((w + 1) & ~1)*2); + break; + + case kVDPixType_8_8_8: + { + uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + + int cxbits = sampInfo.mPlane1Cb.mXBits; + int cybits = sampInfo.mPlane1Cb.mYBits; + int w2 = -(-w >> cxbits); + int h2 = -(-h >> cybits); + gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2); + gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w); + gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2); + } + break; + + case kVDPixType_16F_16F_16F_LE: + { + uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; + uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; + uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; + + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + + int cxbits = sampInfo.mPlane1Cb.mXBits; + int cybits = sampInfo.mPlane1Cb.mYBits; + int w2 = -(-w >> cxbits); + int h2 = -(-h >> cybits); + gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2 * 2); + gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w*2); + gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2 * 2); + } + break; + + case kVDPixType_32F_32F_32F_LE: + { + uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + + int cxbits = sampInfo.mPlane1Cb.mXBits; + int cybits = sampInfo.mPlane1Cb.mYBits; + int w2 = -(-w >> cxbits); + int h2 = -(-h >> cybits); + gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2 * 4); + gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w*4); + gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2 * 4); + } + break; + + case kVDPixType_V210: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, ((w + 5) / 6) * 4); + break; + + case kVDPixType_8_B8R8: + { + uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + uint32 ctoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_B8R8; + + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + + int cxbits = sampInfo.mPlane1Cb.mXBits; + int cybits = sampInfo.mPlane1Cb.mYBits; + int w2 = -(-w >> cxbits); + int h2 = -(-h >> cybits); + gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w); + gen.ldsrc(0, 1, 0, 0, w2, h2, ctoken, w2*2); + } + break; + + default: + VDASSERT(false); + } + + // check if we need a color space change + if ((srcToken ^ dstToken) & kVDPixSpace_Mask) { + // first, if we're dealing with an interleaved format, deinterleave it + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_B8G8_R8G8: + gen.dup(); + gen.dup(); + gen.extract_8in32(2, (w + 1) >> 1, h); + gen.swap(2); + gen.extract_8in16(1, w, h); + gen.swap(1); + gen.extract_8in32(0, (w + 1) >> 1, h); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + + case kVDPixType_G8B8_G8R8: + gen.dup(); + gen.dup(); + gen.extract_8in32(3, (w + 1) >> 1, h); + gen.swap(2); + gen.extract_8in16(0, w, h); + gen.swap(1); + gen.extract_8in32(1, (w + 1) >> 1, h); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + + case kVDPixType_8_B8R8: + gen.dup(); + gen.extract_8in16(1, (w + 1) >> 1, (h + 1) >> 1); + gen.swap(2); + gen.swap(1); + gen.extract_8in16(0, (w + 1) >> 1, (h + 1) >> 1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + + case kVDPixType_V210: + gen.conv_V210_to_32F(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + break; + } + + // if the source is subsampled, converge on 4:4:4 subsampling, but only if we actually need + // the auxiliary channels + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + +#if 0 + // This check is currently disabled because we currently do need the chroma planes + // if we're doing a color space conversion, even if we are going to Y-only. + switch(dstToken & kVDPixSpace_Mask) { +// case kVDPixSpace_Y_601: +// case kVDPixSpace_Y_709: +// case kVDPixSpace_Y_601_FR: +// case kVDPixSpace_Y_709_FR: +// break; + + default: +#endif + if (sampInfo.mPlane1Cb.mXBits | + sampInfo.mPlane1Cb.mYBits | + sampInfo.mPlane1Cb.mX | + sampInfo.mPlane1Cb.mY | + sampInfo.mPlane1Cr.mX | + sampInfo.mPlane1Cr.mY) + srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_444, w, h); +#if 0 + break; + } +#endif + + // change color spaces + uint32 dstSpace = dstToken & kVDPixSpace_Mask; + while((srcToken ^ dstToken) & kVDPixSpace_Mask) { + uint32 srcSpace = srcToken & kVDPixSpace_Mask; + uint32 targetSpace = dstSpace; + +space_reconvert: + switch(targetSpace) { + case kVDPixSpace_BGR: + switch(srcSpace) { + case kVDPixSpace_YCC_709: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + gen.ycbcr709_to_rgb32(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_16F_16F_16F_LE: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_32F_32F_32F_LE, w, h); + gen.ycbcr709_to_rgb32_32f(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; + break; + + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr709_to_rgb32_32f(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_601: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + gen.ycbcr601_to_rgb32(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_16F_16F_16F_LE: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_32F_32F_32F_LE, w, h); + gen.ycbcr601_to_rgb32_32f(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; + break; + + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr601_to_rgb32_32f(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_709_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + gen.ycbcr_to_rgb32_generic(g_VDPixmapGenYCbCrBasis_709, false); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_601_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + gen.ycbcr_to_rgb32_generic(g_VDPixmapGenYCbCrBasis_601, false); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_Y_601: + targetSpace = kVDPixSpace_YCC_601; + goto space_reconvert; + + case kVDPixSpace_Y_709: + targetSpace = kVDPixSpace_YCC_709; + goto space_reconvert; + + case kVDPixSpace_Y_601_FR: + targetSpace = kVDPixSpace_YCC_601_FR; + goto space_reconvert; + + case kVDPixSpace_Y_709_FR: + targetSpace = kVDPixSpace_YCC_709_FR; + goto space_reconvert; + + case kVDPixSpace_Pal: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_1: + gen.conv_Pal1_to_8888(0); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_2: + gen.conv_Pal2_to_8888(0); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_4: + gen.conv_Pal4_to_8888(0); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_8: + gen.conv_Pal8_to_8888(0); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + default: + VDASSERT(false); + break; + } + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_Y_601: + switch(srcSpace) { + case kVDPixSpace_YCC_601: + gen.pop(); + gen.swap(1); + gen.pop(); + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_32F_32F_32F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; + break; + case kVDPixType_16F_16F_16F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; + break; + case kVDPixType_8_8_8: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + break; + + default: + VDASSERT(false); + } + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); + break; + + default: + targetSpace = kVDPixSpace_YCC_601; + goto space_reconvert; + } + break; + + case kVDPixSpace_Y_601_FR: + switch(srcSpace) { + case kVDPixSpace_YCC_601_FR: + gen.pop(); + gen.swap(1); + gen.pop(); + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_32F_32F_32F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; + break; + case kVDPixType_16F_16F_16F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; + break; + case kVDPixType_8_8_8: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + break; + + default: + VDASSERT(false); + } + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); + break; + + default: + targetSpace = kVDPixSpace_YCC_601_FR; + goto space_reconvert; + } + break; + + case kVDPixSpace_Y_709: + switch(srcSpace) { + case kVDPixSpace_YCC_709: + gen.pop(); + gen.swap(1); + gen.pop(); + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_32F_32F_32F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; + break; + case kVDPixType_16F_16F_16F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; + break; + case kVDPixType_8_8_8: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + break; + + default: + VDASSERT(false); + } + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); + break; + + default: + targetSpace = kVDPixSpace_YCC_709; + goto space_reconvert; + } + break; + + case kVDPixSpace_Y_709_FR: + switch(srcSpace) { + case kVDPixSpace_YCC_709_FR: + gen.pop(); + gen.swap(1); + gen.pop(); + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_32F_32F_32F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; + break; + case kVDPixType_16F_16F_16F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; + break; + case kVDPixType_8_8_8: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + break; + + default: + VDASSERT(false); + } + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); + break; + + default: + targetSpace = kVDPixSpace_YCC_709_FR; + goto space_reconvert; + } + break; + + case kVDPixSpace_YCC_601: + switch(srcSpace) { + case kVDPixSpace_BGR: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); + gen.rgb32_to_ycbcr601(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_601 | kVDPixType_8_8_8; + break; + case kVDPixSpace_Y_601: + case kVDPixSpace_Y_709: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_601 | kVDPixType_8; + + { + const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); + int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; + int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; + + gen.ldconst(0x80, cw, cw, ch, srcToken); + } + + gen.dup(); + gen.swap(2); + gen.swap(1); + srcToken = kVDPixSpace_YCC_601 | kVDPixType_8_8_8 | (srcToken & kVDPixSamp_Mask); + break; + + case kVDPixSpace_Y_601_FR: + targetSpace = kVDPixSpace_YCC_601_FR; + goto space_reconvert; + + case kVDPixSpace_Y_709_FR: + targetSpace = kVDPixSpace_YCC_709_FR; + goto space_reconvert; + + case kVDPixSpace_YCC_709: + VDASSERT((srcToken & kVDPixType_Mask) == kVDPixType_8_8_8); + gen.ycbcr709_to_ycbcr601(); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; + break; + + case kVDPixSpace_YCC_601_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_601, true, g_VDPixmapGenYCbCrBasis_601, false, kVDPixSpace_YCC_601); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_709_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_601, true, g_VDPixmapGenYCbCrBasis_709, false, kVDPixSpace_YCC_601); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_Pal: + targetSpace = kVDPixSpace_BGR; + goto space_reconvert; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_709: + switch(srcSpace) { + case kVDPixSpace_BGR: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); + gen.rgb32_to_ycbcr709(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_709 | kVDPixType_8_8_8; + break; + case kVDPixSpace_Y_601: + case kVDPixSpace_Y_709: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_709 | kVDPixType_8; + + { + const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); + int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; + int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; + + gen.ldconst(0x80, cw, cw, ch, srcToken); + } + + gen.dup(); + gen.swap(2); + gen.swap(1); + srcToken = kVDPixSpace_YCC_709 | kVDPixType_8_8_8 | (srcToken & kVDPixSamp_Mask); + break; + case kVDPixSpace_YCC_601: + if ((srcToken & kVDPixType_Mask) == kVDPixType_8_8_8) + gen.ycbcr601_to_ycbcr709(); + else + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_601, true, kVDPixSpace_YCC_709); + + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; + break; + + case kVDPixSpace_YCC_601_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_601, false, kVDPixSpace_YCC_709); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_709_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_709, false, kVDPixSpace_YCC_709); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_Y_601_FR: + targetSpace = kVDPixSpace_YCC_601_FR; + goto space_reconvert; + + case kVDPixSpace_Y_709_FR: + targetSpace = kVDPixSpace_YCC_709_FR; + goto space_reconvert; + + case kVDPixSpace_Pal: + targetSpace = kVDPixSpace_BGR; + goto space_reconvert; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_601_FR: + case kVDPixSpace_YCC_709_FR: + { + const VDPixmapGenYCbCrBasis& dstBasis = *(targetSpace == kVDPixSpace_YCC_601_FR ? &g_VDPixmapGenYCbCrBasis_601 : &g_VDPixmapGenYCbCrBasis_709); + + switch(srcSpace) { + case kVDPixSpace_BGR: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); + gen.rgb32_to_ycbcr_generic(dstBasis, false, targetSpace); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8_8_8; + break; + case kVDPixSpace_Y_601_FR: + case kVDPixSpace_Y_709_FR: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + + { + const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); + int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; + int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; + + gen.ldconst(0x80, cw, cw, ch, srcToken); + } + + gen.dup(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + case kVDPixSpace_YCC_601: + gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_601, true, targetSpace); + srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; + break; + case kVDPixSpace_YCC_709: + gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_709, true, targetSpace); + srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; + break; + case kVDPixSpace_YCC_601_FR: + gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_601, false, targetSpace); + srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; + break; + case kVDPixSpace_YCC_709_FR: + gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_709, false, targetSpace); + srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; + break; + case kVDPixSpace_Pal: + targetSpace = kVDPixSpace_BGR; + goto space_reconvert; + + case kVDPixSpace_Y_601: + targetSpace = kVDPixSpace_YCC_601; + goto space_reconvert; + + case kVDPixSpace_Y_709: + targetSpace = kVDPixSpace_YCC_709; + goto space_reconvert; + + default: + VDASSERT(false); + break; + } + } + break; + + default: + VDASSERT(false); + break; + } + } + } + + // check if we need a type change + // + // Note: If the sampling is also different, we have to be careful about what types we + // target. The type conversion may itself involve a sampling conversion, so things get + // VERY tricky here. + if ((srcToken ^ dstToken) & kVDPixType_Mask) { + bool samplingDifferent = 0 != ((srcToken ^ dstToken) & kVDPixSamp_Mask); + uint32 intermediateTypeToken = dstToken & kVDPixType_Mask; + + if (samplingDifferent) { + switch(dstToken & kVDPixType_Mask) { + case kVDPixType_16F_16F_16F_LE: + intermediateTypeToken = kVDPixType_32F_32F_32F_LE; + break; + case kVDPixType_8_B8R8: + intermediateTypeToken = kVDPixType_8_8_8; + break; + } + } + + srcToken = BlitterConvertType(gen, srcToken, (dstToken & ~kVDPixType_Mask) | intermediateTypeToken, w, h); + } + + // convert subsampling if necessary + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_16F_16F_16F_LE: + case kVDPixType_32F_32F_32F_LE: + if ((srcToken ^ dstToken) & kVDPixSamp_Mask) + srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); + break; + } + + // check if we need a type change (possible with 16F) + srcToken = BlitterConvertType(gen, srcToken, dstToken, w, h); + + return gen.create(); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_16f.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_16f.cpp index 34422884b0d..be71be8232b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_16f.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_16f.cpp @@ -1,59 +1,59 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include "uberblit_16f.h" - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_32F_To_16F::Start() { - StartWindow(mWidth * sizeof(uint16)); -} - -uint32 VDPixmapGen_32F_To_16F::GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_16F_LE; -} - -void VDPixmapGen_32F_To_16F::Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - uint32 w = mWidth; - - for(uint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; -} - -void VDPixmapGen_16F_To_32F::Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - uint32 w = mWidth; - - for(uint32 i=0; i +#include +#include "uberblit_16f.h" + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_32F_To_16F::Start() { + StartWindow(mWidth * sizeof(uint16)); +} + +uint32 VDPixmapGen_32F_To_16F::GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_16F_LE; +} + +void VDPixmapGen_32F_To_16F::Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + uint32 w = mWidth; + + for(uint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; +} + +void VDPixmapGen_16F_To_32F::Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + uint32 w = mWidth; + + for(uint32 i=0; i -#include -#include -#include "uberblit.h" -#include "uberblit_gen.h" -#include "uberblit_fill.h" -#include "uberblit_input.h" -#include "uberblit_resample.h" -#include "uberblit_resample_special.h" -#include "uberblit_ycbcr.h" -#include "uberblit_ycbcr_generic.h" -#include "uberblit_rgb.h" -#include "uberblit_swizzle.h" -#include "uberblit_pal.h" -#include "uberblit_16f.h" -#include "uberblit_v210.h" -#include "uberblit_interlace.h" - -#ifdef VD_CPU_X86 - #include "uberblit_swizzle_x86.h" - #include "uberblit_ycbcr_x86.h" - #include "uberblit_rgb_x86.h" - #include "uberblit_resample_special_x86.h" -#endif - -void VDPixmapGenerate(void *dst, ptrdiff_t pitch, sint32 bpr, sint32 height, IVDPixmapGen *gen, int genIndex) { - for(sint32 y=0; yGetRow(y, genIndex), bpr); - vdptrstep(dst, pitch); - } - VDCPUCleanupExtensions(); -} - -void VDPixmapGenerateFast(void *dst, ptrdiff_t pitch, sint32 height, IVDPixmapGen *gen) { - for(sint32 y=0; yProcessRow(dst, y); - vdptrstep(dst, pitch); - } - VDCPUCleanupExtensions(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmap& dst, const VDPixmap& src) { - return new VDPixmapUberBlitterDirectCopy; -} - -IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmapLayout& dst, const VDPixmapLayout& src) { - return new VDPixmapUberBlitterDirectCopy; -} - -VDPixmapUberBlitterDirectCopy::VDPixmapUberBlitterDirectCopy() { -} - -VDPixmapUberBlitterDirectCopy::~VDPixmapUberBlitterDirectCopy() { -} - -void VDPixmapUberBlitterDirectCopy::Blit(const VDPixmap& dst, const VDPixmap& src) { - Blit(dst, NULL, src); -} - -void VDPixmapUberBlitterDirectCopy::Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) { - VDASSERT(dst.format == src.format); - - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); - - void *p = dst.data; - void *p2 = dst.data2; - void *p3 = dst.data3; - int w = std::min(dst.w, src.w); - int h = std::min(dst.h, src.h); - - if (formatInfo.qchunky) { - w = (w + formatInfo.qw - 1) / formatInfo.qw; - h = -(-h >> formatInfo.qhbits); - } - - int w2 = -(-dst.w >> formatInfo.auxwbits); - int h2 = -(-dst.h >> formatInfo.auxhbits); - - if (rDst) { - int x1 = rDst->left; - int y1 = rDst->top; - int x2 = rDst->right; - int y2 = rDst->bottom; - - VDASSERT(x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h && x2 >= x1 && y2 >= y1); - - if (x2 < x1 || y2 < y1) - return; - - p = vdptroffset(dst.data, dst.pitch * y1 + x1 * formatInfo.qsize); - w = x2 - x1; - h = y2 - y1; - - if (formatInfo.auxbufs >= 1) { - VDASSERT(!((x1|x2) & ((1 << formatInfo.auxwbits) - 1))); - VDASSERT(!((y1|y2) & ((1 << formatInfo.auxhbits) - 1))); - - int ax1 = x1 >> formatInfo.auxwbits; - int ay1 = y1 >> formatInfo.auxhbits; - int ax2 = x2 >> formatInfo.auxwbits; - int ay2 = y2 >> formatInfo.auxhbits; - - p2 = vdptroffset(dst.data2, dst.pitch2 * ay1 + ax1); - w2 = ax2 - ax1; - h2 = ay2 - ay1; - - if (formatInfo.auxbufs >= 2) - p3 = vdptroffset(dst.data3, dst.pitch3 * ay1 + ax1); - } - } - - uint32 bpr = formatInfo.qsize * w; - - VDMemcpyRect(p, dst.pitch, src.data, src.pitch, bpr, h); - - if (formatInfo.auxbufs >= 1) { - VDMemcpyRect(p2, dst.pitch2, src.data2, src.pitch2, w2 * formatInfo.auxsize, h2); - - if (formatInfo.auxbufs >= 2) - VDMemcpyRect(p3, dst.pitch3, src.data3, src.pitch3, w2 * formatInfo.auxsize, h2); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -VDPixmapUberBlitter::VDPixmapUberBlitter() { -} - -VDPixmapUberBlitter::~VDPixmapUberBlitter() { - while(!mGenerators.empty()) { - delete mGenerators.back(); - mGenerators.pop_back(); - } -} - -void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const VDPixmap& src) { - Blit(dst, NULL, src); -} - -void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) { - for(Sources::const_iterator it(mSources.begin()), itEnd(mSources.end()); it!=itEnd; ++it) { - const SourceEntry& se = *it; - const void *p; - ptrdiff_t pitch; - - switch(se.mSrcPlane) { - case 0: - p = src.data; - pitch = src.pitch; - break; - case 1: - p = src.data2; - pitch = src.pitch2; - break; - case 2: - p = src.data3; - pitch = src.pitch3; - break; - default: - VDASSERT(false); - break; - } - - se.mpSrc->SetSource((const char *)p + pitch*se.mSrcY + se.mSrcX, pitch, src.palette); - } - - if (mOutputs[2].mpSrc) { - if (mbIndependentPlanes) - Blit3Separated(dst, rDst); - else if (mbIndependentChromaPlanes) - Blit3Split(dst, rDst); - else - Blit3(dst, rDst); - } else if (mOutputs[1].mpSrc) { - if (mbIndependentPlanes) - Blit2Separated(dst, rDst); - else - Blit2(dst, rDst); - } else - Blit(dst, rDst); -} - -void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); - - mOutputs[0].mpSrc->AddWindowRequest(0, 0); - mOutputs[0].mpSrc->Start(); - - void *p = dst.data; - int w = dst.w; - int h = dst.h; - - if (formatInfo.qchunky) { - w = (w + formatInfo.qw - 1) / formatInfo.qw; - h = -(-h >> formatInfo.qhbits); - } - - if (rDst) { - int x1 = rDst->left; - int y1 = rDst->top; - int x2 = rDst->right; - int y2 = rDst->bottom; - - if (formatInfo.qchunky) { - x1 = x1 / formatInfo.qw; - y1 = y1 / formatInfo.qh; - x2 = (x2 + formatInfo.qw - 1) / formatInfo.qw; - y2 = (y2 + formatInfo.qh - 1) / formatInfo.qh; - } - - VDASSERT(x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h && x2 >= x1 && y2 >= y1); - - if (x2 < x1 || y2 < y1) - return; - - p = vdptroffset(dst.data, dst.pitch * y1 + x1 * formatInfo.qsize); - w = x2 - x1; - h = y2 - y1; - } - - uint32 bpr = formatInfo.qsize * w; - - if (mOutputs[0].mSrcIndex == 0) - VDPixmapGenerateFast(p, dst.pitch, h, mOutputs[0].mpSrc); - else - VDPixmapGenerate(p, dst.pitch, bpr, h, mOutputs[0].mpSrc, mOutputs[0].mSrcIndex); -} - -void VDPixmapUberBlitter::Blit3(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[1].mpSrc; - int idx = mOutputs[1].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[2].mpSrc; - int idx1 = mOutputs[2].mSrcIndex; - IVDPixmapGen *gen2 = mOutputs[0].mpSrc; - int idx2 = mOutputs[0].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - gen2->AddWindowRequest(0, 0); - gen2->Start(); - - uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; - uint32 auxaccum = 0; - - auxstep += auxstep; - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint32 bpr2 = formatInfo.auxsize * -(-px.w >> formatInfo.auxwbits); - uint8 *dst = (uint8 *)px.data; - uint8 *dst2 = (uint8 *)px.data2; - uint8 *dst3 = (uint8 *)px.data3; - ptrdiff_t pitch = px.pitch; - ptrdiff_t pitch2 = px.pitch2; - ptrdiff_t pitch3 = px.pitch3; - uint32 y2 = 0; - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - - if (!auxaccum) { - memcpy(dst2, gen1->GetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - memcpy(dst3, gen2->GetRow(y2, idx2), bpr2); - vdptrstep(dst3, pitch3); - ++y2; - } - - auxaccum += auxstep; - } - - VDCPUCleanupExtensions(); -} - -void VDPixmapUberBlitter::Blit3Split(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[1].mpSrc; - int idx = mOutputs[1].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[2].mpSrc; - int idx1 = mOutputs[2].mSrcIndex; - IVDPixmapGen *gen2 = mOutputs[0].mpSrc; - int idx2 = mOutputs[0].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - gen2->AddWindowRequest(0, 0); - gen2->Start(); - - uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; - uint32 auxaccum = 0; - - auxstep += auxstep; - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint8 *dst = (uint8 *)px.data; - ptrdiff_t pitch = px.pitch; - - if (idx == 0) { - for(uint32 y=0; yProcessRow(dst, y); - vdptrstep(dst, pitch); - } - } else { - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - } - } - - uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; - uint8 *dst2 = (uint8 *)px.data2; - uint8 *dst3 = (uint8 *)px.data3; - ptrdiff_t pitch2 = px.pitch2; - ptrdiff_t pitch3 = px.pitch3; - uint32 y2 = 0; - for(uint32 y=0; yGetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - memcpy(dst3, gen2->GetRow(y2, idx2), bpr2); - vdptrstep(dst3, pitch3); - ++y2; - } - - auxaccum += auxstep; - } - - VDCPUCleanupExtensions(); -} - -void VDPixmapUberBlitter::Blit3Separated(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[1].mpSrc; - int idx = mOutputs[1].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[2].mpSrc; - int idx1 = mOutputs[2].mSrcIndex; - IVDPixmapGen *gen2 = mOutputs[0].mpSrc; - int idx2 = mOutputs[0].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - gen2->AddWindowRequest(0, 0); - gen2->Start(); - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint8 *dst = (uint8 *)px.data; - ptrdiff_t pitch = px.pitch; - - if (idx == 0) { - for(uint32 y=0; yProcessRow(dst, y); - vdptrstep(dst, pitch); - } - } else { - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - } - } - - uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; - uint32 h2 = -(-px.h >> formatInfo.auxhbits); - uint8 *dst2 = (uint8 *)px.data2; - ptrdiff_t pitch2 = px.pitch2; - if (idx1 == 0) { - for(uint32 y2=0; y2ProcessRow(dst2, y2); - vdptrstep(dst2, pitch2); - } - } else { - for(uint32 y2=0; y2GetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - } - } - - uint8 *dst3 = (uint8 *)px.data3; - ptrdiff_t pitch3 = px.pitch3; - if (idx2 == 0) { - for(uint32 y2=0; y2ProcessRow(dst3, y2); - vdptrstep(dst3, pitch3); - } - } else { - for(uint32 y2=0; y2GetRow(y2, idx2), bpr2); - vdptrstep(dst3, pitch3); - } - } - - VDCPUCleanupExtensions(); -} - -void VDPixmapUberBlitter::Blit2(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[0].mpSrc; - int idx = mOutputs[0].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[1].mpSrc; - int idx1 = mOutputs[1].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - - uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; - uint32 auxaccum = 0; - - auxstep += auxstep; - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint32 bpr2 = formatInfo.auxsize * -(-px.w >> formatInfo.auxwbits); - uint8 *dst = (uint8 *)px.data; - uint8 *dst2 = (uint8 *)px.data2; - ptrdiff_t pitch = px.pitch; - ptrdiff_t pitch2 = px.pitch2; - uint32 y2 = 0; - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - - if (!auxaccum) { - memcpy(dst2, gen1->GetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - ++y2; - } - - auxaccum += auxstep; - } - - VDCPUCleanupExtensions(); -} - -void VDPixmapUberBlitter::Blit2Separated(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[0].mpSrc; - int idx = mOutputs[0].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[1].mpSrc; - int idx1 = mOutputs[1].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint8 *dst = (uint8 *)px.data; - ptrdiff_t pitch = px.pitch; - - if (idx == 0) { - for(uint32 y=0; yProcessRow(dst, y); - vdptrstep(dst, pitch); - } - } else { - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - } - } - - uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; - uint32 h2 = -(-px.h >> formatInfo.auxhbits); - uint8 *dst2 = (uint8 *)px.data2; - ptrdiff_t pitch2 = px.pitch2; - if (idx1 == 0) { - for(uint32 y2=0; y2ProcessRow(dst2, y2); - vdptrstep(dst2, pitch2); - } - } else { - for(uint32 y2=0; y2GetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - } - } - - VDCPUCleanupExtensions(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -VDPixmapUberBlitterGenerator::VDPixmapUberBlitterGenerator() { -} - -VDPixmapUberBlitterGenerator::~VDPixmapUberBlitterGenerator() { - while(!mGenerators.empty()) { - delete mGenerators.back(); - mGenerators.pop_back(); - } -} - -void VDPixmapUberBlitterGenerator::swap(int index) { - std::swap(mStack.back(), (&mStack.back())[-index]); -} - -void VDPixmapUberBlitterGenerator::dup() { - mStack.push_back(mStack.back()); -} - -void VDPixmapUberBlitterGenerator::pop() { - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::ldsrc(int srcIndex, int srcPlane, int x, int y, uint32 w, uint32 h, uint32 type, uint32 bpr) { - VDPixmapGenSrc *src = new VDPixmapGenSrc; - - src->Init(w, h, type, bpr); - - mGenerators.push_back(src); - mStack.push_back(StackEntry(src, 0)); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = srcPlane; - se.mSrcX = x; - se.mSrcY = y; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::ldconst(uint8 fill, uint32 bpr, uint32 w, uint32 h, uint32 type) { - VDPixmapGenFill8 *src = new VDPixmapGenFill8; - - src->Init(fill, bpr, w, h, type); - - mGenerators.push_back(src); - mStack.push_back(StackEntry(src, 0)); -} - -void VDPixmapUberBlitterGenerator::extract_8in16(int offset, uint32 w, uint32 h) { - StackEntry *args = &mStack.back(); - VDPixmapGen_8In16 *src = NULL; - -#if VD_CPU_X86 - if (MMX_enabled) { - if (offset == 0) - src = new VDPixmapGen_8In16_Even_MMX; - else if (offset == 1) - src = new VDPixmapGen_8In16_Odd_MMX; - } -#endif - if (!src) - src = new VDPixmapGen_8In16; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, offset, w, h); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::extract_8in32(int offset, uint32 w, uint32 h) { - StackEntry *args = &mStack.back(); - VDPixmapGen_8In32 *src = NULL; - -#if VD_CPU_X86 - if (MMX_enabled) { - if ((unsigned)offset < 4) - src = new VDPixmapGen_8In32_MMX; - } -#endif - - if (!src) - src = new VDPixmapGen_8In32; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, offset, w, h); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::swap_8in16(uint32 w, uint32 h, uint32 bpr) { - StackEntry *args = &mStack.back(); - -#if VD_CPU_X86 - VDPixmapGen_Swap8In16 *src = MMX_enabled ? new VDPixmapGen_Swap8In16_MMX : new VDPixmapGen_Swap8In16; -#else - VDPixmapGen_Swap8In16 *src = new VDPixmapGen_Swap8In16; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex, w, h, bpr); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_Pal1_to_8888(int srcIndex) { - StackEntry *args = &mStack.back(); - VDPixmapGen_Pal1_To_X8R8G8B8 *src = new VDPixmapGen_Pal1_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = 0; - se.mSrcX = 0; - se.mSrcY = 0; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::conv_Pal2_to_8888(int srcIndex) { - StackEntry *args = &mStack.back(); - VDPixmapGen_Pal2_To_X8R8G8B8 *src = new VDPixmapGen_Pal2_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = 0; - se.mSrcX = 0; - se.mSrcY = 0; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::conv_Pal4_to_8888(int srcIndex) { - StackEntry *args = &mStack.back(); - VDPixmapGen_Pal4_To_X8R8G8B8 *src = new VDPixmapGen_Pal4_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = 0; - se.mSrcX = 0; - se.mSrcY = 0; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::conv_Pal8_to_8888(int srcIndex) { - StackEntry *args = &mStack.back(); - VDPixmapGen_Pal8_To_X8R8G8B8 *src = new VDPixmapGen_Pal8_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = 0; - se.mSrcX = 0; - se.mSrcY = 0; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::pointh(float xoffset, float xfactor, uint32 w) { - StackEntry *args = &mStack.back(); - - if (xoffset != 0.5f || xfactor != 1.0f) { - VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterPoint, 0, false); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::pointv(float yoffset, float yfactor, uint32 h) { - StackEntry *args = &mStack.back(); - - if (yoffset != 0.5f || yfactor != 1.0f) { - VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterPoint, 0, false); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::linearh(float xoffset, float xfactor, uint32 w, bool interpOnly) { - StackEntry *args = &mStack.back(); - IVDPixmapGen *src = args[0].mpSrc; - int srcIndex = args[0].mSrcIndex; - - sint32 srcw = src->GetWidth(srcIndex); - if (xoffset == 0.5f && xfactor == 1.0f && srcw == w) - return; - - if (xoffset == 0.5f && (src->GetType(srcIndex) & kVDPixType_Mask) == kVDPixType_8) { - if (xfactor == 2.0f && w == ((srcw + 1) >> 1)) { - VDPixmapGenResampleRow_d2_p0_lin_u8 *out = new VDPixmapGenResampleRow_d2_p0_lin_u8; - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (xfactor == 4.0f && w == ((srcw + 3) >> 2)) { - VDPixmapGenResampleRow_d4_p0_lin_u8 *out = new VDPixmapGenResampleRow_d4_p0_lin_u8; - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (xfactor == 0.5f && w == srcw*2) { -#if VD_CPU_X86 - VDPixmapGenResampleRow_x2_p0_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE : new VDPixmapGenResampleRow_x2_p0_lin_u8; -#else - VDPixmapGenResampleRow_x2_p0_lin_u8 *out = new VDPixmapGenResampleRow_x2_p0_lin_u8; -#endif - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (xfactor == 0.25f && w == srcw*4) { -#if VD_CPU_X86 - VDPixmapGenResampleRow_x4_p0_lin_u8 *out = MMX_enabled ? new VDPixmapGenResampleRow_x4_p0_lin_u8_MMX : new VDPixmapGenResampleRow_x4_p0_lin_u8; -#else - VDPixmapGenResampleRow_x4_p0_lin_u8 *out = new VDPixmapGenResampleRow_x4_p0_lin_u8; -#endif - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - } - - VDPixmapGenResampleRow *out = new VDPixmapGenResampleRow; - - out->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterLinear, 0, interpOnly); - - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); -} - -void VDPixmapUberBlitterGenerator::linearv(float yoffset, float yfactor, uint32 h, bool interpOnly) { - StackEntry *args = &mStack.back(); - IVDPixmapGen *src = args[0].mpSrc; - int srcIndex = args[0].mSrcIndex; - - sint32 srch = src->GetHeight(srcIndex); - if (yoffset == 0.5f && yfactor == 1.0f && srch == h) - return; - - if ((src->GetType(srcIndex) & kVDPixType_Mask) == kVDPixType_8) { - if (yoffset == 1.0f && yfactor == 2.0f && h == ((srch + 1) >> 1)) { - VDPixmapGenResampleCol_x2_phalf_lin_u8 *out = new VDPixmapGenResampleCol_x2_phalf_lin_u8; - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (yoffset == 2.0f && yfactor == 4.0f && h == ((srch + 2) >> 2)) { - VDPixmapGenResampleCol_x4_p1half_lin_u8 *out = new VDPixmapGenResampleCol_x4_p1half_lin_u8; - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (yoffset == 0.25f && yfactor == 0.5f && h == srch*2) { -#if VD_CPU_X86 - VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE : new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8; -#else - VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 *out = new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8; -#endif - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (yoffset == 0.125f && yfactor == 0.25f && h == srch*4) { -#if VD_CPU_X86 - VDPixmapGenResampleCol_d4_pn38_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE : new VDPixmapGenResampleCol_d4_pn38_lin_u8; -#else - VDPixmapGenResampleCol_d4_pn38_lin_u8 *out = new VDPixmapGenResampleCol_d4_pn38_lin_u8; -#endif - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - } - - VDPixmapGenResampleCol *out = new VDPixmapGenResampleCol; - - out->Init(src, srcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterLinear, 0, interpOnly); - - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); -} - -void VDPixmapUberBlitterGenerator::linear(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h) { - linearh(xoffset, xfactor, w, false); - linearv(yoffset, yfactor, h, false); -} - -void VDPixmapUberBlitterGenerator::cubich(float xoffset, float xfactor, uint32 w, float splineFactor, bool interpOnly) { - StackEntry *args = &mStack.back(); - - if (xoffset != 0.5f || xfactor != 1.0f) { - VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterCubic, splineFactor, interpOnly); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::cubicv(float yoffset, float yfactor, uint32 h, float splineFactor, bool interpOnly) { - StackEntry *args = &mStack.back(); - - if (yoffset != 0.5f || yfactor != 1.0f) { - VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterCubic, splineFactor, interpOnly); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::cubic(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h, float splineFactor) { - cubich(xoffset, xfactor, w, splineFactor, false); - cubicv(yoffset, yfactor, h, splineFactor, false); -} - -void VDPixmapUberBlitterGenerator::lanczos3h(float xoffset, float xfactor, uint32 w) { - StackEntry *args = &mStack.back(); - - if (xoffset != 0.5f || xfactor != 1.0f) { - VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterLanczos3, 0, false); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::lanczos3v(float yoffset, float yfactor, uint32 h) { - StackEntry *args = &mStack.back(); - - if (yoffset != 0.5f || yfactor != 1.0f) { - VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterLanczos3, 0, false); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::lanczos3(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h) { - lanczos3h(xoffset, xfactor, w); - lanczos3v(yoffset, yfactor, h); -} - -void VDPixmapUberBlitterGenerator::conv_555_to_8888() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X1R5G5B5_To_X8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_X1R5G5B5_To_X8R8G8B8_MMX : new VDPixmapGen_X1R5G5B5_To_X8R8G8B8; -#else - VDPixmapGen_X1R5G5B5_To_X8R8G8B8 *src = new VDPixmapGen_X1R5G5B5_To_X8R8G8B8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_565_to_8888() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_R5G6B5_To_X8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_R5G6B5_To_X8R8G8B8_MMX : new VDPixmapGen_R5G6B5_To_X8R8G8B8; -#else - VDPixmapGen_R5G6B5_To_X8R8G8B8 *src = new VDPixmapGen_R5G6B5_To_X8R8G8B8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_888_to_8888() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_R8G8B8_To_A8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_R8G8B8_To_X8R8G8B8_MMX : new VDPixmapGen_R8G8B8_To_A8R8G8B8; -#else - VDPixmapGen_R8G8B8_To_A8R8G8B8 *src = new VDPixmapGen_R8G8B8_To_A8R8G8B8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_8_to_32F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_8_To_32F *src = new VDPixmapGen_8_To_32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_16F_to_32F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_16F_To_32F *src = new VDPixmapGen_16F_To_32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_V210_to_32F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_V210_To_32F *src = new VDPixmapGen_V210_To_32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::conv_8888_to_X32F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X8R8G8B8_To_X32B32G32R32F *src = new VDPixmapGen_X8R8G8B8_To_X32B32G32R32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_8888_to_555() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X8R8G8B8_To_X1R5G5B5 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_X1R5G5B5_MMX : new VDPixmapGen_X8R8G8B8_To_X1R5G5B5; -#else - VDPixmapGen_X8R8G8B8_To_X1R5G5B5 *src = new VDPixmapGen_X8R8G8B8_To_X1R5G5B5; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_555_to_565() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X1R5G5B5_To_R5G6B5 *src = MMX_enabled ? new VDPixmapGen_X1R5G5B5_To_R5G6B5_MMX : new VDPixmapGen_X1R5G5B5_To_R5G6B5; -#else - VDPixmapGen_X1R5G5B5_To_R5G6B5 *src = new VDPixmapGen_X1R5G5B5_To_R5G6B5; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_565_to_555() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_R5G6B5_To_X1R5G5B5 *src = MMX_enabled ? new VDPixmapGen_R5G6B5_To_X1R5G5B5_MMX : new VDPixmapGen_R5G6B5_To_X1R5G5B5; -#else - VDPixmapGen_R5G6B5_To_X1R5G5B5 *src = new VDPixmapGen_R5G6B5_To_X1R5G5B5; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_8888_to_565() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X8R8G8B8_To_R5G6B5 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_R5G6B5_MMX : new VDPixmapGen_X8R8G8B8_To_R5G6B5; -#else - VDPixmapGen_X8R8G8B8_To_R5G6B5 *src = new VDPixmapGen_X8R8G8B8_To_R5G6B5; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_8888_to_888() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X8R8G8B8_To_R8G8B8 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_R8G8B8_MMX : new VDPixmapGen_X8R8G8B8_To_R8G8B8; -#else - VDPixmapGen_X8R8G8B8_To_R8G8B8 *src = new VDPixmapGen_X8R8G8B8_To_R8G8B8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_32F_to_8() { - StackEntry *args = &mStack.back(); - VDPixmapGen_32F_To_8 *src = new VDPixmapGen_32F_To_8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_X32F_to_8888() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X32B32G32R32F_To_X8R8G8B8 *src = new VDPixmapGen_X32B32G32R32F_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_32F_to_16F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_32F_To_16F *src = new VDPixmapGen_32F_To_16F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_32F_to_V210() { - StackEntry *args = &*(mStack.end() - 3); - VDPixmapGen_32F_To_V210 *src = new VDPixmapGen_32F_To_V210; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::convd_8888_to_555() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X8R8G8B8_To_X1R5G5B5_Dithered *src = new VDPixmapGen_X8R8G8B8_To_X1R5G5B5_Dithered; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::convd_8888_to_565() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered *src = new VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::convd_32F_to_8() { - StackEntry *args = &mStack.back(); - VDPixmapGen_32F_To_8_Dithered *src = new VDPixmapGen_32F_To_8_Dithered; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::convd_X32F_to_8888() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X32B32G32R32F_To_X8R8G8B8_Dithered *src = new VDPixmapGen_X32B32G32R32F_To_X8R8G8B8_Dithered; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::interleave_B8G8_R8G8() { - StackEntry *args = &mStack.back() - 2; - VDPixmapGen_B8x3_To_B8G8_R8G8 *src = NULL; - -#if VD_CPU_X86 - if (MMX_enabled) - src = new VDPixmapGen_B8x3_To_B8G8_R8G8_MMX; -#endif - - if (!src) - src = new VDPixmapGen_B8x3_To_B8G8_R8G8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::interleave_G8B8_G8R8() { - StackEntry *args = &mStack.back() - 2; - VDPixmapGen_B8x3_To_G8B8_G8R8 *src = NULL; - -#if VD_CPU_X86 - if (MMX_enabled) - src = new VDPixmapGen_B8x3_To_G8B8_G8R8_MMX; -#endif - - if (!src) - src = new VDPixmapGen_B8x3_To_G8B8_G8R8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::interleave_X8R8G8B8() { - StackEntry *args = &mStack.back() - 2; - VDPixmapGen_B8x3_To_X8R8G8B8 *src = new VDPixmapGen_B8x3_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::interleave_B8R8() { - StackEntry *args = &mStack.back() - 1; - -#if VD_CPU_X86 - VDPixmapGen_B8x2_To_B8R8 *src = MMX_enabled ? new VDPixmapGen_B8x2_To_B8R8_MMX : new VDPixmapGen_B8x2_To_B8R8; -#else - VDPixmapGen_B8x2_To_B8R8 *src = new VDPixmapGen_B8x2_To_B8R8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::merge_fields(uint32 w, uint32 h, uint32 bpr) { - StackEntry *args = &mStack.back() - 1; - - VDPixmapGen_MergeFields *src = new VDPixmapGen_MergeFields; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, w, h, bpr); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::split_fields(uint32 bpr) { - StackEntry *args = &mStack.back(); - - VDPixmapGen_SplitFields *src = new VDPixmapGen_SplitFields; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, bpr); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); -} - -void VDPixmapUberBlitterGenerator::ycbcr601_to_rgb32() { - StackEntry *args = &mStack.back() - 2; - -#ifdef VD_CPU_X86 - VDPixmapGenYCbCr601ToRGB32 *src = MMX_enabled ? new VDPixmapGenYCbCr601ToRGB32_MMX : new VDPixmapGenYCbCr601ToRGB32; -#else - VDPixmapGenYCbCr601ToRGB32 *src = new VDPixmapGenYCbCr601ToRGB32; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::ycbcr709_to_rgb32() { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCr709ToRGB32 *src = new VDPixmapGenYCbCr709ToRGB32; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr601() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGenRGB32ToYCbCr601 *src = SSE2_enabled ? new VDPixmapGenRGB32ToYCbCr601_SSE2 : new VDPixmapGenRGB32ToYCbCr601; -#else - VDPixmapGenRGB32ToYCbCr601 *src = new VDPixmapGenRGB32ToYCbCr601; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr709() { - StackEntry *args = &mStack.back(); - VDPixmapGenRGB32ToYCbCr709 *src = new VDPixmapGenRGB32ToYCbCr709; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::ycbcr601_to_rgb32_32f() { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCr601ToRGB32F *src = new VDPixmapGenYCbCr601ToRGB32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::ycbcr709_to_rgb32_32f() { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCr709ToRGB32F *src = new VDPixmapGenYCbCr709ToRGB32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr601_32f() { - StackEntry *args = &mStack.back(); - VDPixmapGenRGB32FToYCbCr601 *src = new VDPixmapGenRGB32FToYCbCr601; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr709_32f() { - StackEntry *args = &mStack.back(); - VDPixmapGenRGB32FToYCbCr709 *src = new VDPixmapGenRGB32FToYCbCr709; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::ycbcr601_to_ycbcr709() { - StackEntry *args = &mStack.back() - 2; - - IVDPixmapGen *src; - if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { - VDPixmapGenYCbCr601ToYCbCr709_32F *src2 = new VDPixmapGenYCbCr601ToYCbCr709_32F; - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } else { - VDPixmapGenYCbCr601ToYCbCr709 *src2 = new VDPixmapGenYCbCr601ToYCbCr709; - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - args[1] = StackEntry(src, 1); - args[2] = StackEntry(src, 2); -} - -void VDPixmapUberBlitterGenerator::ycbcr709_to_ycbcr601() { - StackEntry *args = &mStack.back() - 2; - - IVDPixmapGen *src; - if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { - VDPixmapGenYCbCr709ToYCbCr601_32F *src2 = new VDPixmapGenYCbCr709ToYCbCr601_32F; - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } else { - VDPixmapGenYCbCr709ToYCbCr601 *src2 = new VDPixmapGenYCbCr709ToYCbCr601; - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - args[1] = StackEntry(src, 1); - args[2] = StackEntry(src, 2); -} - -void VDPixmapUberBlitterGenerator::ycbcr_to_rgb32_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB) { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCrToRGB32Generic *src = new VDPixmapGenYCbCrToRGB32Generic(basis, studioRGB); - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::ycbcr_to_rgb32f_generic(const VDPixmapGenYCbCrBasis& basis) { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCrToRGB32FGeneric *src = new VDPixmapGenYCbCrToRGB32FGeneric(basis); - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB, uint32 colorSpace) { - StackEntry *args = &mStack.back(); - - VDPixmapGenRGB32ToYCbCrGeneric *src = new VDPixmapGenRGB32ToYCbCrGeneric(basis, studioRGB, colorSpace); - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::rgb32f_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace) { - StackEntry *args = &mStack.back(); - - VDPixmapGenRGB32FToYCbCrGeneric *src = new VDPixmapGenRGB32FToYCbCrGeneric(basis, colorSpace); - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::ycbcr_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basisDst, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& basisSrc, bool srcLimitedRange, uint32 colorSpace) { - StackEntry *args = &mStack.back() - 2; - - IVDPixmapGen *src; - if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { - VDPixmapGenYCbCrToYCbCrGeneric_32F *src2 = new VDPixmapGenYCbCrToYCbCrGeneric_32F(basisDst, dstLimitedRange, basisSrc, srcLimitedRange, colorSpace); - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } else { - VDPixmapGenYCbCrToYCbCrGeneric *src2 = new VDPixmapGenYCbCrToYCbCrGeneric(basisDst, dstLimitedRange, basisSrc, srcLimitedRange, colorSpace); - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - args[1] = StackEntry(src, 1); - args[2] = StackEntry(src, 2); -} - -IVDPixmapBlitter *VDPixmapUberBlitterGenerator::create() { - vdautoptr blitter(new VDPixmapUberBlitter); - - int numStackEntries = (int)mStack.size(); - - for(int i=0; i<3; ++i) { - if (i < numStackEntries) { - blitter->mOutputs[i].mpSrc = mStack[i].mpSrc; - blitter->mOutputs[i].mSrcIndex = mStack[i].mSrcIndex; - } else { - blitter->mOutputs[i].mpSrc = NULL; - blitter->mOutputs[i].mSrcIndex = 0; - } - } - - mStack.clear(); - - // If this blitter has three outputs, determine if outputs 1 and 2 are independent - // from output 0. - blitter->mbIndependentChromaPlanes = true; - blitter->mbIndependentPlanes = true; - if (numStackEntries >= 3) { - int numGens = mGenerators.size(); - vdfastvector genflags(numGens, 0); - - enum { - kFlagStateful = 0x80, - kFlagY = 0x01, - kFlagCb = 0x02, - kFlagCr = 0x04, - kFlagYCbCr = 0x07 - }; - - for(int i=0; i<3; ++i) - genflags[std::find(mGenerators.begin(), mGenerators.end(), blitter->mOutputs[i].mpSrc) - mGenerators.begin()] |= (1 << i); - - for(int i=0; iIsStateful()) - genflags[i] |= kFlagStateful; - } - - while(!mDependencies.empty()) { - const Dependency& dep = mDependencies.back(); - - genflags[dep.mSrcIdx] |= (genflags[dep.mDstIdx] & ~kFlagStateful); - - mDependencies.pop_back(); - } - - for(int i=0; imbIndependentPlanes = false; - break; - case kFlagCb | kFlagY: - case kFlagCr | kFlagY: - case kFlagCr | kFlagCb | kFlagY: - blitter->mbIndependentPlanes = false; - blitter->mbIndependentChromaPlanes = false; - break; - } - } - } else if (numStackEntries >= 2) { - int numGens = mGenerators.size(); - vdfastvector genflags(numGens, 0); - - enum { - kFlagStateful = 0x80, - kFlagY = 0x01, - kFlagC = 0x02, - kFlagYC = 0x03 - }; - - for(int i=0; i<2; ++i) - genflags[std::find(mGenerators.begin(), mGenerators.end(), blitter->mOutputs[i].mpSrc) - mGenerators.begin()] |= (1 << i); - - for(int i=0; iIsStateful()) - genflags[i] |= kFlagStateful; - } - - while(!mDependencies.empty()) { - const Dependency& dep = mDependencies.back(); - - genflags[dep.mSrcIdx] |= (genflags[dep.mDstIdx] & ~kFlagStateful); - - mDependencies.pop_back(); - } - - for(int i=0; imbIndependentPlanes = false; - blitter->mbIndependentChromaPlanes = false; - break; - } - } - } - - blitter->mGenerators.swap(mGenerators); - blitter->mSources.swap(mSources); - return blitter.release(); -} - -void VDPixmapUberBlitterGenerator::MarkDependency(IVDPixmapGen *dst, IVDPixmapGen *src) { - Generators::const_iterator it1(std::find(mGenerators.begin(), mGenerators.end(), dst)); - Generators::const_iterator it2(std::find(mGenerators.begin(), mGenerators.end(), src)); - - VDASSERT(it1 != mGenerators.end()); - VDASSERT(it2 != mGenerators.end()); - - int idx1 = it1 - mGenerators.begin(); - int idx2 = it2 - mGenerators.begin(); - - Dependency dep = { idx1, idx2 }; - - mDependencies.push_back(dep); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include "uberblit.h" +#include "uberblit_gen.h" +#include "uberblit_fill.h" +#include "uberblit_input.h" +#include "uberblit_resample.h" +#include "uberblit_resample_special.h" +#include "uberblit_ycbcr.h" +#include "uberblit_ycbcr_generic.h" +#include "uberblit_rgb.h" +#include "uberblit_swizzle.h" +#include "uberblit_pal.h" +#include "uberblit_16f.h" +#include "uberblit_v210.h" +#include "uberblit_interlace.h" + +#ifdef VD_CPU_X86 + #include "uberblit_swizzle_x86.h" + #include "uberblit_ycbcr_x86.h" + #include "uberblit_rgb_x86.h" + #include "uberblit_resample_special_x86.h" +#endif + +void VDPixmapGenerate(void *dst, ptrdiff_t pitch, sint32 bpr, sint32 height, IVDPixmapGen *gen, int genIndex) { + for(sint32 y=0; yGetRow(y, genIndex), bpr); + vdptrstep(dst, pitch); + } + VDCPUCleanupExtensions(); +} + +void VDPixmapGenerateFast(void *dst, ptrdiff_t pitch, sint32 height, IVDPixmapGen *gen) { + for(sint32 y=0; yProcessRow(dst, y); + vdptrstep(dst, pitch); + } + VDCPUCleanupExtensions(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmap& dst, const VDPixmap& src) { + return new VDPixmapUberBlitterDirectCopy; +} + +IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmapLayout& dst, const VDPixmapLayout& src) { + return new VDPixmapUberBlitterDirectCopy; +} + +VDPixmapUberBlitterDirectCopy::VDPixmapUberBlitterDirectCopy() { +} + +VDPixmapUberBlitterDirectCopy::~VDPixmapUberBlitterDirectCopy() { +} + +void VDPixmapUberBlitterDirectCopy::Blit(const VDPixmap& dst, const VDPixmap& src) { + Blit(dst, NULL, src); +} + +void VDPixmapUberBlitterDirectCopy::Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) { + VDASSERT(dst.format == src.format); + + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); + + void *p = dst.data; + void *p2 = dst.data2; + void *p3 = dst.data3; + int w = std::min(dst.w, src.w); + int h = std::min(dst.h, src.h); + + if (formatInfo.qchunky) { + w = (w + formatInfo.qw - 1) / formatInfo.qw; + h = -(-h >> formatInfo.qhbits); + } + + int w2 = -(-dst.w >> formatInfo.auxwbits); + int h2 = -(-dst.h >> formatInfo.auxhbits); + + if (rDst) { + int x1 = rDst->left; + int y1 = rDst->top; + int x2 = rDst->right; + int y2 = rDst->bottom; + + VDASSERT(x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h && x2 >= x1 && y2 >= y1); + + if (x2 < x1 || y2 < y1) + return; + + p = vdptroffset(dst.data, dst.pitch * y1 + x1 * formatInfo.qsize); + w = x2 - x1; + h = y2 - y1; + + if (formatInfo.auxbufs >= 1) { + VDASSERT(!((x1|x2) & ((1 << formatInfo.auxwbits) - 1))); + VDASSERT(!((y1|y2) & ((1 << formatInfo.auxhbits) - 1))); + + int ax1 = x1 >> formatInfo.auxwbits; + int ay1 = y1 >> formatInfo.auxhbits; + int ax2 = x2 >> formatInfo.auxwbits; + int ay2 = y2 >> formatInfo.auxhbits; + + p2 = vdptroffset(dst.data2, dst.pitch2 * ay1 + ax1); + w2 = ax2 - ax1; + h2 = ay2 - ay1; + + if (formatInfo.auxbufs >= 2) + p3 = vdptroffset(dst.data3, dst.pitch3 * ay1 + ax1); + } + } + + uint32 bpr = formatInfo.qsize * w; + + VDMemcpyRect(p, dst.pitch, src.data, src.pitch, bpr, h); + + if (formatInfo.auxbufs >= 1) { + VDMemcpyRect(p2, dst.pitch2, src.data2, src.pitch2, w2 * formatInfo.auxsize, h2); + + if (formatInfo.auxbufs >= 2) + VDMemcpyRect(p3, dst.pitch3, src.data3, src.pitch3, w2 * formatInfo.auxsize, h2); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +VDPixmapUberBlitter::VDPixmapUberBlitter() { +} + +VDPixmapUberBlitter::~VDPixmapUberBlitter() { + while(!mGenerators.empty()) { + delete mGenerators.back(); + mGenerators.pop_back(); + } +} + +void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const VDPixmap& src) { + Blit(dst, NULL, src); +} + +void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) { + for(Sources::const_iterator it(mSources.begin()), itEnd(mSources.end()); it!=itEnd; ++it) { + const SourceEntry& se = *it; + const void *p; + ptrdiff_t pitch; + + switch(se.mSrcPlane) { + case 0: + p = src.data; + pitch = src.pitch; + break; + case 1: + p = src.data2; + pitch = src.pitch2; + break; + case 2: + p = src.data3; + pitch = src.pitch3; + break; + default: + VDASSERT(false); + break; + } + + se.mpSrc->SetSource((const char *)p + pitch*se.mSrcY + se.mSrcX, pitch, src.palette); + } + + if (mOutputs[2].mpSrc) { + if (mbIndependentPlanes) + Blit3Separated(dst, rDst); + else if (mbIndependentChromaPlanes) + Blit3Split(dst, rDst); + else + Blit3(dst, rDst); + } else if (mOutputs[1].mpSrc) { + if (mbIndependentPlanes) + Blit2Separated(dst, rDst); + else + Blit2(dst, rDst); + } else + Blit(dst, rDst); +} + +void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); + + mOutputs[0].mpSrc->AddWindowRequest(0, 0); + mOutputs[0].mpSrc->Start(); + + void *p = dst.data; + int w = dst.w; + int h = dst.h; + + if (formatInfo.qchunky) { + w = (w + formatInfo.qw - 1) / formatInfo.qw; + h = -(-h >> formatInfo.qhbits); + } + + if (rDst) { + int x1 = rDst->left; + int y1 = rDst->top; + int x2 = rDst->right; + int y2 = rDst->bottom; + + if (formatInfo.qchunky) { + x1 = x1 / formatInfo.qw; + y1 = y1 / formatInfo.qh; + x2 = (x2 + formatInfo.qw - 1) / formatInfo.qw; + y2 = (y2 + formatInfo.qh - 1) / formatInfo.qh; + } + + VDASSERT(x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h && x2 >= x1 && y2 >= y1); + + if (x2 < x1 || y2 < y1) + return; + + p = vdptroffset(dst.data, dst.pitch * y1 + x1 * formatInfo.qsize); + w = x2 - x1; + h = y2 - y1; + } + + uint32 bpr = formatInfo.qsize * w; + + if (mOutputs[0].mSrcIndex == 0) + VDPixmapGenerateFast(p, dst.pitch, h, mOutputs[0].mpSrc); + else + VDPixmapGenerate(p, dst.pitch, bpr, h, mOutputs[0].mpSrc, mOutputs[0].mSrcIndex); +} + +void VDPixmapUberBlitter::Blit3(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[1].mpSrc; + int idx = mOutputs[1].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[2].mpSrc; + int idx1 = mOutputs[2].mSrcIndex; + IVDPixmapGen *gen2 = mOutputs[0].mpSrc; + int idx2 = mOutputs[0].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + gen2->AddWindowRequest(0, 0); + gen2->Start(); + + uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; + uint32 auxaccum = 0; + + auxstep += auxstep; + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint32 bpr2 = formatInfo.auxsize * -(-px.w >> formatInfo.auxwbits); + uint8 *dst = (uint8 *)px.data; + uint8 *dst2 = (uint8 *)px.data2; + uint8 *dst3 = (uint8 *)px.data3; + ptrdiff_t pitch = px.pitch; + ptrdiff_t pitch2 = px.pitch2; + ptrdiff_t pitch3 = px.pitch3; + uint32 y2 = 0; + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + + if (!auxaccum) { + memcpy(dst2, gen1->GetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + memcpy(dst3, gen2->GetRow(y2, idx2), bpr2); + vdptrstep(dst3, pitch3); + ++y2; + } + + auxaccum += auxstep; + } + + VDCPUCleanupExtensions(); +} + +void VDPixmapUberBlitter::Blit3Split(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[1].mpSrc; + int idx = mOutputs[1].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[2].mpSrc; + int idx1 = mOutputs[2].mSrcIndex; + IVDPixmapGen *gen2 = mOutputs[0].mpSrc; + int idx2 = mOutputs[0].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + gen2->AddWindowRequest(0, 0); + gen2->Start(); + + uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; + uint32 auxaccum = 0; + + auxstep += auxstep; + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint8 *dst = (uint8 *)px.data; + ptrdiff_t pitch = px.pitch; + + if (idx == 0) { + for(uint32 y=0; yProcessRow(dst, y); + vdptrstep(dst, pitch); + } + } else { + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + } + } + + uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; + uint8 *dst2 = (uint8 *)px.data2; + uint8 *dst3 = (uint8 *)px.data3; + ptrdiff_t pitch2 = px.pitch2; + ptrdiff_t pitch3 = px.pitch3; + uint32 y2 = 0; + for(uint32 y=0; yGetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + memcpy(dst3, gen2->GetRow(y2, idx2), bpr2); + vdptrstep(dst3, pitch3); + ++y2; + } + + auxaccum += auxstep; + } + + VDCPUCleanupExtensions(); +} + +void VDPixmapUberBlitter::Blit3Separated(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[1].mpSrc; + int idx = mOutputs[1].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[2].mpSrc; + int idx1 = mOutputs[2].mSrcIndex; + IVDPixmapGen *gen2 = mOutputs[0].mpSrc; + int idx2 = mOutputs[0].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + gen2->AddWindowRequest(0, 0); + gen2->Start(); + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint8 *dst = (uint8 *)px.data; + ptrdiff_t pitch = px.pitch; + + if (idx == 0) { + for(uint32 y=0; yProcessRow(dst, y); + vdptrstep(dst, pitch); + } + } else { + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + } + } + + uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; + uint32 h2 = -(-px.h >> formatInfo.auxhbits); + uint8 *dst2 = (uint8 *)px.data2; + ptrdiff_t pitch2 = px.pitch2; + if (idx1 == 0) { + for(uint32 y2=0; y2ProcessRow(dst2, y2); + vdptrstep(dst2, pitch2); + } + } else { + for(uint32 y2=0; y2GetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + } + } + + uint8 *dst3 = (uint8 *)px.data3; + ptrdiff_t pitch3 = px.pitch3; + if (idx2 == 0) { + for(uint32 y2=0; y2ProcessRow(dst3, y2); + vdptrstep(dst3, pitch3); + } + } else { + for(uint32 y2=0; y2GetRow(y2, idx2), bpr2); + vdptrstep(dst3, pitch3); + } + } + + VDCPUCleanupExtensions(); +} + +void VDPixmapUberBlitter::Blit2(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[0].mpSrc; + int idx = mOutputs[0].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[1].mpSrc; + int idx1 = mOutputs[1].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + + uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; + uint32 auxaccum = 0; + + auxstep += auxstep; + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint32 bpr2 = formatInfo.auxsize * -(-px.w >> formatInfo.auxwbits); + uint8 *dst = (uint8 *)px.data; + uint8 *dst2 = (uint8 *)px.data2; + ptrdiff_t pitch = px.pitch; + ptrdiff_t pitch2 = px.pitch2; + uint32 y2 = 0; + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + + if (!auxaccum) { + memcpy(dst2, gen1->GetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + ++y2; + } + + auxaccum += auxstep; + } + + VDCPUCleanupExtensions(); +} + +void VDPixmapUberBlitter::Blit2Separated(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[0].mpSrc; + int idx = mOutputs[0].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[1].mpSrc; + int idx1 = mOutputs[1].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint8 *dst = (uint8 *)px.data; + ptrdiff_t pitch = px.pitch; + + if (idx == 0) { + for(uint32 y=0; yProcessRow(dst, y); + vdptrstep(dst, pitch); + } + } else { + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + } + } + + uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; + uint32 h2 = -(-px.h >> formatInfo.auxhbits); + uint8 *dst2 = (uint8 *)px.data2; + ptrdiff_t pitch2 = px.pitch2; + if (idx1 == 0) { + for(uint32 y2=0; y2ProcessRow(dst2, y2); + vdptrstep(dst2, pitch2); + } + } else { + for(uint32 y2=0; y2GetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + } + } + + VDCPUCleanupExtensions(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +VDPixmapUberBlitterGenerator::VDPixmapUberBlitterGenerator() { +} + +VDPixmapUberBlitterGenerator::~VDPixmapUberBlitterGenerator() { + while(!mGenerators.empty()) { + delete mGenerators.back(); + mGenerators.pop_back(); + } +} + +void VDPixmapUberBlitterGenerator::swap(int index) { + std::swap(mStack.back(), (&mStack.back())[-index]); +} + +void VDPixmapUberBlitterGenerator::dup() { + mStack.push_back(mStack.back()); +} + +void VDPixmapUberBlitterGenerator::pop() { + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::ldsrc(int srcIndex, int srcPlane, int x, int y, uint32 w, uint32 h, uint32 type, uint32 bpr) { + VDPixmapGenSrc *src = new VDPixmapGenSrc; + + src->Init(w, h, type, bpr); + + mGenerators.push_back(src); + mStack.push_back(StackEntry(src, 0)); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = srcPlane; + se.mSrcX = x; + se.mSrcY = y; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::ldconst(uint8 fill, uint32 bpr, uint32 w, uint32 h, uint32 type) { + VDPixmapGenFill8 *src = new VDPixmapGenFill8; + + src->Init(fill, bpr, w, h, type); + + mGenerators.push_back(src); + mStack.push_back(StackEntry(src, 0)); +} + +void VDPixmapUberBlitterGenerator::extract_8in16(int offset, uint32 w, uint32 h) { + StackEntry *args = &mStack.back(); + VDPixmapGen_8In16 *src = NULL; + +#if VD_CPU_X86 + if (MMX_enabled) { + if (offset == 0) + src = new VDPixmapGen_8In16_Even_MMX; + else if (offset == 1) + src = new VDPixmapGen_8In16_Odd_MMX; + } +#endif + if (!src) + src = new VDPixmapGen_8In16; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, offset, w, h); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::extract_8in32(int offset, uint32 w, uint32 h) { + StackEntry *args = &mStack.back(); + VDPixmapGen_8In32 *src = NULL; + +#if VD_CPU_X86 + if (MMX_enabled) { + if ((unsigned)offset < 4) + src = new VDPixmapGen_8In32_MMX; + } +#endif + + if (!src) + src = new VDPixmapGen_8In32; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, offset, w, h); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::swap_8in16(uint32 w, uint32 h, uint32 bpr) { + StackEntry *args = &mStack.back(); + +#if VD_CPU_X86 + VDPixmapGen_Swap8In16 *src = MMX_enabled ? new VDPixmapGen_Swap8In16_MMX : new VDPixmapGen_Swap8In16; +#else + VDPixmapGen_Swap8In16 *src = new VDPixmapGen_Swap8In16; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex, w, h, bpr); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_Pal1_to_8888(int srcIndex) { + StackEntry *args = &mStack.back(); + VDPixmapGen_Pal1_To_X8R8G8B8 *src = new VDPixmapGen_Pal1_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = 0; + se.mSrcX = 0; + se.mSrcY = 0; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::conv_Pal2_to_8888(int srcIndex) { + StackEntry *args = &mStack.back(); + VDPixmapGen_Pal2_To_X8R8G8B8 *src = new VDPixmapGen_Pal2_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = 0; + se.mSrcX = 0; + se.mSrcY = 0; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::conv_Pal4_to_8888(int srcIndex) { + StackEntry *args = &mStack.back(); + VDPixmapGen_Pal4_To_X8R8G8B8 *src = new VDPixmapGen_Pal4_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = 0; + se.mSrcX = 0; + se.mSrcY = 0; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::conv_Pal8_to_8888(int srcIndex) { + StackEntry *args = &mStack.back(); + VDPixmapGen_Pal8_To_X8R8G8B8 *src = new VDPixmapGen_Pal8_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = 0; + se.mSrcX = 0; + se.mSrcY = 0; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::pointh(float xoffset, float xfactor, uint32 w) { + StackEntry *args = &mStack.back(); + + if (xoffset != 0.5f || xfactor != 1.0f) { + VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterPoint, 0, false); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::pointv(float yoffset, float yfactor, uint32 h) { + StackEntry *args = &mStack.back(); + + if (yoffset != 0.5f || yfactor != 1.0f) { + VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterPoint, 0, false); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::linearh(float xoffset, float xfactor, uint32 w, bool interpOnly) { + StackEntry *args = &mStack.back(); + IVDPixmapGen *src = args[0].mpSrc; + int srcIndex = args[0].mSrcIndex; + + sint32 srcw = src->GetWidth(srcIndex); + if (xoffset == 0.5f && xfactor == 1.0f && srcw == w) + return; + + if (xoffset == 0.5f && (src->GetType(srcIndex) & kVDPixType_Mask) == kVDPixType_8) { + if (xfactor == 2.0f && w == ((srcw + 1) >> 1)) { + VDPixmapGenResampleRow_d2_p0_lin_u8 *out = new VDPixmapGenResampleRow_d2_p0_lin_u8; + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (xfactor == 4.0f && w == ((srcw + 3) >> 2)) { + VDPixmapGenResampleRow_d4_p0_lin_u8 *out = new VDPixmapGenResampleRow_d4_p0_lin_u8; + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (xfactor == 0.5f && w == srcw*2) { +#if VD_CPU_X86 + VDPixmapGenResampleRow_x2_p0_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE : new VDPixmapGenResampleRow_x2_p0_lin_u8; +#else + VDPixmapGenResampleRow_x2_p0_lin_u8 *out = new VDPixmapGenResampleRow_x2_p0_lin_u8; +#endif + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (xfactor == 0.25f && w == srcw*4) { +#if VD_CPU_X86 + VDPixmapGenResampleRow_x4_p0_lin_u8 *out = MMX_enabled ? new VDPixmapGenResampleRow_x4_p0_lin_u8_MMX : new VDPixmapGenResampleRow_x4_p0_lin_u8; +#else + VDPixmapGenResampleRow_x4_p0_lin_u8 *out = new VDPixmapGenResampleRow_x4_p0_lin_u8; +#endif + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + } + + VDPixmapGenResampleRow *out = new VDPixmapGenResampleRow; + + out->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterLinear, 0, interpOnly); + + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); +} + +void VDPixmapUberBlitterGenerator::linearv(float yoffset, float yfactor, uint32 h, bool interpOnly) { + StackEntry *args = &mStack.back(); + IVDPixmapGen *src = args[0].mpSrc; + int srcIndex = args[0].mSrcIndex; + + sint32 srch = src->GetHeight(srcIndex); + if (yoffset == 0.5f && yfactor == 1.0f && srch == h) + return; + + if ((src->GetType(srcIndex) & kVDPixType_Mask) == kVDPixType_8) { + if (yoffset == 1.0f && yfactor == 2.0f && h == ((srch + 1) >> 1)) { + VDPixmapGenResampleCol_x2_phalf_lin_u8 *out = new VDPixmapGenResampleCol_x2_phalf_lin_u8; + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (yoffset == 2.0f && yfactor == 4.0f && h == ((srch + 2) >> 2)) { + VDPixmapGenResampleCol_x4_p1half_lin_u8 *out = new VDPixmapGenResampleCol_x4_p1half_lin_u8; + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (yoffset == 0.25f && yfactor == 0.5f && h == srch*2) { +#if VD_CPU_X86 + VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE : new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8; +#else + VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 *out = new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8; +#endif + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (yoffset == 0.125f && yfactor == 0.25f && h == srch*4) { +#if VD_CPU_X86 + VDPixmapGenResampleCol_d4_pn38_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE : new VDPixmapGenResampleCol_d4_pn38_lin_u8; +#else + VDPixmapGenResampleCol_d4_pn38_lin_u8 *out = new VDPixmapGenResampleCol_d4_pn38_lin_u8; +#endif + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + } + + VDPixmapGenResampleCol *out = new VDPixmapGenResampleCol; + + out->Init(src, srcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterLinear, 0, interpOnly); + + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); +} + +void VDPixmapUberBlitterGenerator::linear(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h) { + linearh(xoffset, xfactor, w, false); + linearv(yoffset, yfactor, h, false); +} + +void VDPixmapUberBlitterGenerator::cubich(float xoffset, float xfactor, uint32 w, float splineFactor, bool interpOnly) { + StackEntry *args = &mStack.back(); + + if (xoffset != 0.5f || xfactor != 1.0f) { + VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterCubic, splineFactor, interpOnly); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::cubicv(float yoffset, float yfactor, uint32 h, float splineFactor, bool interpOnly) { + StackEntry *args = &mStack.back(); + + if (yoffset != 0.5f || yfactor != 1.0f) { + VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterCubic, splineFactor, interpOnly); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::cubic(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h, float splineFactor) { + cubich(xoffset, xfactor, w, splineFactor, false); + cubicv(yoffset, yfactor, h, splineFactor, false); +} + +void VDPixmapUberBlitterGenerator::lanczos3h(float xoffset, float xfactor, uint32 w) { + StackEntry *args = &mStack.back(); + + if (xoffset != 0.5f || xfactor != 1.0f) { + VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterLanczos3, 0, false); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::lanczos3v(float yoffset, float yfactor, uint32 h) { + StackEntry *args = &mStack.back(); + + if (yoffset != 0.5f || yfactor != 1.0f) { + VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterLanczos3, 0, false); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::lanczos3(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h) { + lanczos3h(xoffset, xfactor, w); + lanczos3v(yoffset, yfactor, h); +} + +void VDPixmapUberBlitterGenerator::conv_555_to_8888() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X1R5G5B5_To_X8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_X1R5G5B5_To_X8R8G8B8_MMX : new VDPixmapGen_X1R5G5B5_To_X8R8G8B8; +#else + VDPixmapGen_X1R5G5B5_To_X8R8G8B8 *src = new VDPixmapGen_X1R5G5B5_To_X8R8G8B8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_565_to_8888() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_R5G6B5_To_X8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_R5G6B5_To_X8R8G8B8_MMX : new VDPixmapGen_R5G6B5_To_X8R8G8B8; +#else + VDPixmapGen_R5G6B5_To_X8R8G8B8 *src = new VDPixmapGen_R5G6B5_To_X8R8G8B8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_888_to_8888() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_R8G8B8_To_A8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_R8G8B8_To_X8R8G8B8_MMX : new VDPixmapGen_R8G8B8_To_A8R8G8B8; +#else + VDPixmapGen_R8G8B8_To_A8R8G8B8 *src = new VDPixmapGen_R8G8B8_To_A8R8G8B8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_8_to_32F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_8_To_32F *src = new VDPixmapGen_8_To_32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_16F_to_32F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_16F_To_32F *src = new VDPixmapGen_16F_To_32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_V210_to_32F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_V210_To_32F *src = new VDPixmapGen_V210_To_32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::conv_8888_to_X32F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X8R8G8B8_To_X32B32G32R32F *src = new VDPixmapGen_X8R8G8B8_To_X32B32G32R32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_8888_to_555() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X8R8G8B8_To_X1R5G5B5 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_X1R5G5B5_MMX : new VDPixmapGen_X8R8G8B8_To_X1R5G5B5; +#else + VDPixmapGen_X8R8G8B8_To_X1R5G5B5 *src = new VDPixmapGen_X8R8G8B8_To_X1R5G5B5; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_555_to_565() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X1R5G5B5_To_R5G6B5 *src = MMX_enabled ? new VDPixmapGen_X1R5G5B5_To_R5G6B5_MMX : new VDPixmapGen_X1R5G5B5_To_R5G6B5; +#else + VDPixmapGen_X1R5G5B5_To_R5G6B5 *src = new VDPixmapGen_X1R5G5B5_To_R5G6B5; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_565_to_555() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_R5G6B5_To_X1R5G5B5 *src = MMX_enabled ? new VDPixmapGen_R5G6B5_To_X1R5G5B5_MMX : new VDPixmapGen_R5G6B5_To_X1R5G5B5; +#else + VDPixmapGen_R5G6B5_To_X1R5G5B5 *src = new VDPixmapGen_R5G6B5_To_X1R5G5B5; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_8888_to_565() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X8R8G8B8_To_R5G6B5 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_R5G6B5_MMX : new VDPixmapGen_X8R8G8B8_To_R5G6B5; +#else + VDPixmapGen_X8R8G8B8_To_R5G6B5 *src = new VDPixmapGen_X8R8G8B8_To_R5G6B5; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_8888_to_888() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X8R8G8B8_To_R8G8B8 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_R8G8B8_MMX : new VDPixmapGen_X8R8G8B8_To_R8G8B8; +#else + VDPixmapGen_X8R8G8B8_To_R8G8B8 *src = new VDPixmapGen_X8R8G8B8_To_R8G8B8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_32F_to_8() { + StackEntry *args = &mStack.back(); + VDPixmapGen_32F_To_8 *src = new VDPixmapGen_32F_To_8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_X32F_to_8888() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X32B32G32R32F_To_X8R8G8B8 *src = new VDPixmapGen_X32B32G32R32F_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_32F_to_16F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_32F_To_16F *src = new VDPixmapGen_32F_To_16F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_32F_to_V210() { + StackEntry *args = &*(mStack.end() - 3); + VDPixmapGen_32F_To_V210 *src = new VDPixmapGen_32F_To_V210; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::convd_8888_to_555() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X8R8G8B8_To_X1R5G5B5_Dithered *src = new VDPixmapGen_X8R8G8B8_To_X1R5G5B5_Dithered; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::convd_8888_to_565() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered *src = new VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::convd_32F_to_8() { + StackEntry *args = &mStack.back(); + VDPixmapGen_32F_To_8_Dithered *src = new VDPixmapGen_32F_To_8_Dithered; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::convd_X32F_to_8888() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X32B32G32R32F_To_X8R8G8B8_Dithered *src = new VDPixmapGen_X32B32G32R32F_To_X8R8G8B8_Dithered; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::interleave_B8G8_R8G8() { + StackEntry *args = &mStack.back() - 2; + VDPixmapGen_B8x3_To_B8G8_R8G8 *src = NULL; + +#if VD_CPU_X86 + if (MMX_enabled) + src = new VDPixmapGen_B8x3_To_B8G8_R8G8_MMX; +#endif + + if (!src) + src = new VDPixmapGen_B8x3_To_B8G8_R8G8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::interleave_G8B8_G8R8() { + StackEntry *args = &mStack.back() - 2; + VDPixmapGen_B8x3_To_G8B8_G8R8 *src = NULL; + +#if VD_CPU_X86 + if (MMX_enabled) + src = new VDPixmapGen_B8x3_To_G8B8_G8R8_MMX; +#endif + + if (!src) + src = new VDPixmapGen_B8x3_To_G8B8_G8R8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::interleave_X8R8G8B8() { + StackEntry *args = &mStack.back() - 2; + VDPixmapGen_B8x3_To_X8R8G8B8 *src = new VDPixmapGen_B8x3_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::interleave_B8R8() { + StackEntry *args = &mStack.back() - 1; + +#if VD_CPU_X86 + VDPixmapGen_B8x2_To_B8R8 *src = MMX_enabled ? new VDPixmapGen_B8x2_To_B8R8_MMX : new VDPixmapGen_B8x2_To_B8R8; +#else + VDPixmapGen_B8x2_To_B8R8 *src = new VDPixmapGen_B8x2_To_B8R8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::merge_fields(uint32 w, uint32 h, uint32 bpr) { + StackEntry *args = &mStack.back() - 1; + + VDPixmapGen_MergeFields *src = new VDPixmapGen_MergeFields; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, w, h, bpr); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::split_fields(uint32 bpr) { + StackEntry *args = &mStack.back(); + + VDPixmapGen_SplitFields *src = new VDPixmapGen_SplitFields; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, bpr); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); +} + +void VDPixmapUberBlitterGenerator::ycbcr601_to_rgb32() { + StackEntry *args = &mStack.back() - 2; + +#ifdef VD_CPU_X86 + VDPixmapGenYCbCr601ToRGB32 *src = MMX_enabled ? new VDPixmapGenYCbCr601ToRGB32_MMX : new VDPixmapGenYCbCr601ToRGB32; +#else + VDPixmapGenYCbCr601ToRGB32 *src = new VDPixmapGenYCbCr601ToRGB32; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::ycbcr709_to_rgb32() { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCr709ToRGB32 *src = new VDPixmapGenYCbCr709ToRGB32; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr601() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGenRGB32ToYCbCr601 *src = SSE2_enabled ? new VDPixmapGenRGB32ToYCbCr601_SSE2 : new VDPixmapGenRGB32ToYCbCr601; +#else + VDPixmapGenRGB32ToYCbCr601 *src = new VDPixmapGenRGB32ToYCbCr601; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr709() { + StackEntry *args = &mStack.back(); + VDPixmapGenRGB32ToYCbCr709 *src = new VDPixmapGenRGB32ToYCbCr709; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::ycbcr601_to_rgb32_32f() { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCr601ToRGB32F *src = new VDPixmapGenYCbCr601ToRGB32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::ycbcr709_to_rgb32_32f() { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCr709ToRGB32F *src = new VDPixmapGenYCbCr709ToRGB32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr601_32f() { + StackEntry *args = &mStack.back(); + VDPixmapGenRGB32FToYCbCr601 *src = new VDPixmapGenRGB32FToYCbCr601; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr709_32f() { + StackEntry *args = &mStack.back(); + VDPixmapGenRGB32FToYCbCr709 *src = new VDPixmapGenRGB32FToYCbCr709; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::ycbcr601_to_ycbcr709() { + StackEntry *args = &mStack.back() - 2; + + IVDPixmapGen *src; + if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { + VDPixmapGenYCbCr601ToYCbCr709_32F *src2 = new VDPixmapGenYCbCr601ToYCbCr709_32F; + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } else { + VDPixmapGenYCbCr601ToYCbCr709 *src2 = new VDPixmapGenYCbCr601ToYCbCr709; + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + args[1] = StackEntry(src, 1); + args[2] = StackEntry(src, 2); +} + +void VDPixmapUberBlitterGenerator::ycbcr709_to_ycbcr601() { + StackEntry *args = &mStack.back() - 2; + + IVDPixmapGen *src; + if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { + VDPixmapGenYCbCr709ToYCbCr601_32F *src2 = new VDPixmapGenYCbCr709ToYCbCr601_32F; + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } else { + VDPixmapGenYCbCr709ToYCbCr601 *src2 = new VDPixmapGenYCbCr709ToYCbCr601; + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + args[1] = StackEntry(src, 1); + args[2] = StackEntry(src, 2); +} + +void VDPixmapUberBlitterGenerator::ycbcr_to_rgb32_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB) { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCrToRGB32Generic *src = new VDPixmapGenYCbCrToRGB32Generic(basis, studioRGB); + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::ycbcr_to_rgb32f_generic(const VDPixmapGenYCbCrBasis& basis) { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCrToRGB32FGeneric *src = new VDPixmapGenYCbCrToRGB32FGeneric(basis); + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB, uint32 colorSpace) { + StackEntry *args = &mStack.back(); + + VDPixmapGenRGB32ToYCbCrGeneric *src = new VDPixmapGenRGB32ToYCbCrGeneric(basis, studioRGB, colorSpace); + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::rgb32f_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace) { + StackEntry *args = &mStack.back(); + + VDPixmapGenRGB32FToYCbCrGeneric *src = new VDPixmapGenRGB32FToYCbCrGeneric(basis, colorSpace); + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::ycbcr_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basisDst, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& basisSrc, bool srcLimitedRange, uint32 colorSpace) { + StackEntry *args = &mStack.back() - 2; + + IVDPixmapGen *src; + if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { + VDPixmapGenYCbCrToYCbCrGeneric_32F *src2 = new VDPixmapGenYCbCrToYCbCrGeneric_32F(basisDst, dstLimitedRange, basisSrc, srcLimitedRange, colorSpace); + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } else { + VDPixmapGenYCbCrToYCbCrGeneric *src2 = new VDPixmapGenYCbCrToYCbCrGeneric(basisDst, dstLimitedRange, basisSrc, srcLimitedRange, colorSpace); + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + args[1] = StackEntry(src, 1); + args[2] = StackEntry(src, 2); +} + +IVDPixmapBlitter *VDPixmapUberBlitterGenerator::create() { + vdautoptr blitter(new VDPixmapUberBlitter); + + int numStackEntries = (int)mStack.size(); + + for(int i=0; i<3; ++i) { + if (i < numStackEntries) { + blitter->mOutputs[i].mpSrc = mStack[i].mpSrc; + blitter->mOutputs[i].mSrcIndex = mStack[i].mSrcIndex; + } else { + blitter->mOutputs[i].mpSrc = NULL; + blitter->mOutputs[i].mSrcIndex = 0; + } + } + + mStack.clear(); + + // If this blitter has three outputs, determine if outputs 1 and 2 are independent + // from output 0. + blitter->mbIndependentChromaPlanes = true; + blitter->mbIndependentPlanes = true; + if (numStackEntries >= 3) { + int numGens = mGenerators.size(); + vdfastvector genflags(numGens, 0); + + enum { + kFlagStateful = 0x80, + kFlagY = 0x01, + kFlagCb = 0x02, + kFlagCr = 0x04, + kFlagYCbCr = 0x07 + }; + + for(int i=0; i<3; ++i) + genflags[std::find(mGenerators.begin(), mGenerators.end(), blitter->mOutputs[i].mpSrc) - mGenerators.begin()] |= (1 << i); + + for(int i=0; iIsStateful()) + genflags[i] |= kFlagStateful; + } + + while(!mDependencies.empty()) { + const Dependency& dep = mDependencies.back(); + + genflags[dep.mSrcIdx] |= (genflags[dep.mDstIdx] & ~kFlagStateful); + + mDependencies.pop_back(); + } + + for(int i=0; imbIndependentPlanes = false; + break; + case kFlagCb | kFlagY: + case kFlagCr | kFlagY: + case kFlagCr | kFlagCb | kFlagY: + blitter->mbIndependentPlanes = false; + blitter->mbIndependentChromaPlanes = false; + break; + } + } + } else if (numStackEntries >= 2) { + int numGens = mGenerators.size(); + vdfastvector genflags(numGens, 0); + + enum { + kFlagStateful = 0x80, + kFlagY = 0x01, + kFlagC = 0x02, + kFlagYC = 0x03 + }; + + for(int i=0; i<2; ++i) + genflags[std::find(mGenerators.begin(), mGenerators.end(), blitter->mOutputs[i].mpSrc) - mGenerators.begin()] |= (1 << i); + + for(int i=0; iIsStateful()) + genflags[i] |= kFlagStateful; + } + + while(!mDependencies.empty()) { + const Dependency& dep = mDependencies.back(); + + genflags[dep.mSrcIdx] |= (genflags[dep.mDstIdx] & ~kFlagStateful); + + mDependencies.pop_back(); + } + + for(int i=0; imbIndependentPlanes = false; + blitter->mbIndependentChromaPlanes = false; + break; + } + } + } + + blitter->mGenerators.swap(mGenerators); + blitter->mSources.swap(mSources); + return blitter.release(); +} + +void VDPixmapUberBlitterGenerator::MarkDependency(IVDPixmapGen *dst, IVDPixmapGen *src) { + Generators::const_iterator it1(std::find(mGenerators.begin(), mGenerators.end(), dst)); + Generators::const_iterator it2(std::find(mGenerators.begin(), mGenerators.end(), src)); + + VDASSERT(it1 != mGenerators.end()); + VDASSERT(it2 != mGenerators.end()); + + int idx1 = it1 - mGenerators.begin(); + int idx2 = it2 - mGenerators.begin(); + + Dependency dep = { idx1, idx2 }; + + mDependencies.push_back(dep); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample.cpp index 8174d67219e..6918efed975 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample.cpp @@ -1,642 +1,642 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "resample_stages_x86.h" -#include "uberblit_resample.h" - -namespace { - sint32 scale32x32_fp16(sint32 x, sint32 y) { - return (sint32)(((sint64)x * y + 0x8000) >> 16); - } - - template - IVDResamplerSeparableRowStage *RowFactory(double cutoff, float filterFactor) { - return new T; - } - - template - IVDResamplerSeparableRowStage *RowFactoryLinear(double cutoff, float filterFactor) { - return new T(VDResamplerLinearFilter(cutoff)); - } - - template - IVDResamplerSeparableRowStage *RowFactoryCubic(double cutoff, float filterFactor) { - return new T(VDResamplerCubicFilter(cutoff, filterFactor)); - } - - template - IVDResamplerSeparableRowStage *RowFactoryCubic2(double cutoff, float filterFactor) { - return new T(filterFactor); - } - - template - IVDResamplerSeparableRowStage *RowFactoryLanczos3(double cutoff, float filterFactor) { - return new T(VDResamplerLanczos3Filter(cutoff)); - } - - template - IVDResamplerSeparableColStage *ColFactory(double cutoff, float filterFactor) { - return new T; - } - - template - IVDResamplerSeparableColStage *ColFactoryLinear(double cutoff, float filterFactor) { - return new T(VDResamplerLinearFilter(cutoff)); - } - - template - IVDResamplerSeparableColStage *ColFactoryCubic(double cutoff, float filterFactor) { - return new T(VDResamplerCubicFilter(cutoff, filterFactor)); - } - - template - IVDResamplerSeparableColStage *ColFactoryCubic2(double cutoff, float filterFactor) { - return new T(filterFactor); - } - - template - IVDResamplerSeparableColStage *ColFactoryLanczos3(double cutoff, float filterFactor) { - return new T(VDResamplerLanczos3Filter(cutoff)); - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDPixmapGenResampleRow -// -/////////////////////////////////////////////////////////////////////////// - -VDPixmapGenResampleRow::VDPixmapGenResampleRow() - : mpRowStage(NULL) - , mpRowStage2(NULL) -{ -} - -VDPixmapGenResampleRow::~VDPixmapGenResampleRow() { - if (mpRowStage) - delete mpRowStage; -} - -void VDPixmapGenResampleRow::Init(IVDPixmapGen *src, uint32 srcIndex, uint32 width, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly) { - InitSource(src, srcIndex); - - sint32 u0 = (sint32)(offset * 65536.0); - sint32 dudx = (sint32)(step * 65536.0); - - mAxis.Init(dudx); - - double x_2fc = 1.0; - if (!interpolationOnly && step > 1.0f) - x_2fc = 1.0 / step; - - struct SpecialCaseSpanRoutine { - sint32 mPhase; - sint32 mStep; - uint32 mType; - nsVDPixmap::FilterMode mFilterMode; - uint32 mCPUFlags; - IVDResamplerSeparableRowStage *(*mpClassFactory)(double filterCutoff, float filterFactor); - }; - - static const SpecialCaseSpanRoutine kSpecialCaseSpanRoutines[]={ - // Generic -#if defined _M_IX86 - { +0x0000, 0x008000, kVDPixType_8, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_INTEGER_SSE, RowFactory }, -#endif - - { +0x0000, 0x008000, kVDPixType_8, nsVDPixmap::kFilterLinear, 0, RowFactory }, - }; - - long flags = CPUGetEnabledExtensions(); - uint32 type = mpSrc->GetType(mSrcIndex) & kVDPixType_Mask; - - for(int i=0; iAsRowStage2(); - break; - } - - if (!mpRowStage) { - struct SpanRoutine { - uint32 mType; - bool mbInterpOnly; - nsVDPixmap::FilterMode mFilterMode; - uint32 mCPUFlags; - IVDResamplerSeparableRowStage *(*mpClassFactory)(double filterCutoff, float filterFactor); - }; - - static const SpanRoutine kSpanRoutines[]={ -#if defined _M_IX86 - // X86 - { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, CPUF_SUPPORTS_MMX, RowFactory }, - { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE41, RowFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactoryLinear }, - { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactory }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, RowFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE41, RowFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic }, - { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic2 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, RowFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE41, RowFactoryLanczos3 }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, RowFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, RowFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, RowFactoryLanczos3 }, -#elif defined _M_AMD64 - // AMD64 - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, RowFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, RowFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, RowFactoryLanczos3 }, -#endif - // Generic - { kVDPixType_8, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, - { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, - { kVDPixType_8, true, nsVDPixmap::kFilterLinear, 0, RowFactory }, - { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, 0, RowFactory }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, - }; - - for(int i=0; iAsRowStage2(); - break; - } - } - - VDASSERT(mpRowStage); - - mRowFiltW = mpRowStage->GetWindowSize(); - - mpSrc->AddWindowRequest(0, 0); - - sint32 fsx1 = (sint32)(offset * 65536.0) - ((mRowFiltW-1) << 15); - mAxis.Compute(width, fsx1, mSrcWidth, mRowFiltW); - mWidth = width; - - switch(type) { - case kVDPixType_8: - mBytesPerSample = 1; - break; - case kVDPixType_8888: - case kVDPixType_32F_LE: - mBytesPerSample = 4; - break; - case kVDPixType_32Fx4_LE: - mBytesPerSample = 16; - break; - - default: - VDASSERT(false); - } -} - -void VDPixmapGenResampleRow::Start() { - StartWindow(mWidth * mBytesPerSample); - - uint32 clipSpace = ((mRowFiltW*3*mBytesPerSample + 15) >> 4) << 2; - mTempSpace.resize(clipSpace); - - if (mpRowStage2) - mpRowStage2->Init(mAxis, mSrcWidth); -} - -void VDPixmapGenResampleRow::Compute(void *dst0, sint32 y) { - switch(mBytesPerSample) { - case 1: - Compute8(dst0, y); - break; - case 4: - Compute32(dst0, y); - break; - case 16: - Compute128(dst0, y); - break; - } -} - -void VDPixmapGenResampleRow::Compute8(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - uint8 *dst = (uint8 *)dst0; - - // process pre-copy region - if (uint32 count = mAxis.dx_precopy) { - VDMemset8(dst, src[0], count); - dst += count; - } - - uint8 *p = (uint8*)mTempSpace.data(); - sint32 u = mAxis.u; - const sint32 dudx = mAxis.dudx; - - // process dual-clip region - if (mpRowStage2) { - uint32 count = mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip + mAxis.dx_dualclip; - mpRowStage2->Process(dst, src, count); - dst += count; - } else if (uint32 count = mAxis.dx_dualclip) { - VDMemset8(p, src[0], mRowFiltW); - memcpy(p + mRowFiltW, src+1, (mSrcWidth-2)); - VDMemset8(p + mRowFiltW + (mSrcWidth-2), src[mSrcWidth-1], mRowFiltW); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count; - } else { - // process pre-clip region - if (uint32 count = mAxis.dx_preclip) { - VDMemset8(p, src[0], mRowFiltW); - memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count; - } - - // process active region - if (uint32 count = mAxis.dx_active) { - mpRowStage->Process(dst, src, count, u, dudx); - u += dudx*count; - dst += count; - } - - // process post-clip region - if (uint32 count = mAxis.dx_postclip) { - uint32 offset = mSrcWidth + 1 - mRowFiltW; - - memcpy(p, src+offset, (mRowFiltW-1)); - VDMemset8(p + (mRowFiltW-1), src[mSrcWidth-1], mRowFiltW); - - mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); - dst += count; - } - } - - // process post-copy region - if (uint32 count = mAxis.dx_postcopy) { - VDMemset8(dst, src[mSrcWidth-1], count); - } -} - -void VDPixmapGenResampleRow::Compute32(void *dst0, sint32 y) { - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - uint32 *dst = (uint32 *)dst0; - - // process pre-copy region - if (uint32 count = mAxis.dx_precopy) { - VDMemset32(dst, src[0], count); - dst += count; - } - - uint32 *p = mTempSpace.data(); - sint32 u = mAxis.u; - const sint32 dudx = mAxis.dudx; - - // process dual-clip region - if (uint32 count = mAxis.dx_dualclip) { - VDMemset32(p, src[0], mRowFiltW); - memcpy(p + mRowFiltW, src+1, (mSrcWidth-2)*sizeof(uint32)); - VDMemset32(p + mRowFiltW + (mSrcWidth-2), src[mSrcWidth-1], mRowFiltW); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count; - } else if (mpRowStage2) { - mpRowStage2->Process(dst, p, mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip); - } else { - // process pre-clip region - if (uint32 count = mAxis.dx_preclip) { - VDMemset32(p, src[0], mRowFiltW); - memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32)); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count; - } - - // process active region - if (uint32 count = mAxis.dx_active) { - mpRowStage->Process(dst, src, count, u, dudx); - u += dudx*count; - dst += count; - } - - // process post-clip region - if (uint32 count = mAxis.dx_postclip) { - uint32 offset = mSrcWidth + 1 - mRowFiltW; - - memcpy(p, src+offset, (mRowFiltW-1)*sizeof(uint32)); - VDMemset32(p + (mRowFiltW-1), src[mSrcWidth-1], mRowFiltW); - - mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); - dst += count; - } - } - - // process post-copy region - if (uint32 count = mAxis.dx_postcopy) { - VDMemset32(dst, src[mSrcWidth-1], count); - } -} - -void VDPixmapGenResampleRow::Compute128(void *dst0, sint32 y) { - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - uint32 *dst = (uint32 *)dst0; - - // process pre-copy region - if (uint32 count = mAxis.dx_precopy) { - VDMemset128(dst, src, count); - dst += 4*count; - } - - uint32 *p = mTempSpace.data(); - sint32 u = mAxis.u; - const sint32 dudx = mAxis.dudx; - - // process dual-clip region - if (uint32 count = mAxis.dx_dualclip) { - VDMemset128(p, src, mRowFiltW); - memcpy(p + 4*mRowFiltW, src+1, (mSrcWidth-2)*sizeof(uint32)*4); - VDMemset128(p + 4*(mRowFiltW + (mSrcWidth-2)), src + 4*(mSrcWidth-1), mRowFiltW); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count * 4; - } else if (mpRowStage2) { - mpRowStage2->Process(dst, p, mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip); - } else { - // process pre-clip region - if (uint32 count = mAxis.dx_preclip) { - VDMemset128(p, src, mRowFiltW); - memcpy(p + 4*mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32)*4); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count*4; - } - - // process active region - if (uint32 count = mAxis.dx_active) { - mpRowStage->Process(dst, src, count, u, dudx); - u += dudx*count; - dst += count*4; - } - - // process post-clip region - if (uint32 count = mAxis.dx_postclip) { - uint32 offset = mSrcWidth + 1 - mRowFiltW; - - memcpy(p, src+offset*4, (mRowFiltW-1)*sizeof(uint32)*4); - VDMemset128(p + 4*(mRowFiltW-1), src + 4*(mSrcWidth-1), mRowFiltW); - - mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); - dst += count*4; - } - } - - // process post-copy region - if (uint32 count = mAxis.dx_postcopy) { - VDMemset128(dst, src + 4*(mSrcWidth-1), count); - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDPixmapGenResampleCol -// -/////////////////////////////////////////////////////////////////////////// - -VDPixmapGenResampleCol::VDPixmapGenResampleCol() - : mpColStage(NULL) -{ -} - -VDPixmapGenResampleCol::~VDPixmapGenResampleCol() { - if (mpColStage) - delete mpColStage; -} - -void VDPixmapGenResampleCol::Init(IVDPixmapGen *src, uint32 srcIndex, uint32 height, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly) { - InitSource(src, srcIndex); - - sint32 dvdy = (sint32)(step * 65536.0); - - mAxis.Init(dvdy); - - // construct stages - double y_2fc = 1.0; - if (!interpolationOnly && step > 1.0f) - y_2fc = 1.0 / step; - - struct SpanRoutine { - uint32 mType; - bool mbInterpOnly; - nsVDPixmap::FilterMode mFilterMode; - uint32 mCPUFlags; - IVDResamplerSeparableColStage *(*mpClassFactory)(double filterCutoff, float filterFactor); - }; - - static const SpanRoutine kSpanRoutines[]={ -#if defined _M_IX86 - // X86 - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE41, ColFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactoryLinear }, - { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactory }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, ColFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE41, ColFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic }, - { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic2 }, - { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic2 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE41, ColFactoryLanczos3 }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, ColFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, ColFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, ColFactoryLanczos3 }, -#elif defined _M_AMD64 - // AMD64 - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, ColFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, ColFactoryLanczos3 }, -#endif - // Generic - { kVDPixType_8, true, nsVDPixmap::kFilterLinear, 0, ColFactory }, - { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, 0, ColFactory }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, - }; - - long flags = CPUGetEnabledExtensions(); - uint32 type = src->GetType(srcIndex) & kVDPixType_Mask; - for(int i=0; iGetWindowSize() : 1; - mWindow.resize(mWinSize); - - int delta = (mWinSize + 1) >> 1; - mpSrc->AddWindowRequest(-delta, delta); - - sint32 fsy1 = (sint32)(offset * 65536.0) - ((mWinSize-1)<<15); - mAxis.Compute(height, fsy1, mSrcHeight, mWinSize); - mHeight = height; - - switch(type) { - case kVDPixType_8: - mBytesPerSample = 1; - break; - case kVDPixType_8888: - case kVDPixType_32F_LE: - mBytesPerSample = 4; - break; - case kVDPixType_32Fx4_LE: - mBytesPerSample = 16; - break; - - default: - VDASSERT(false); - } -} - -void VDPixmapGenResampleCol::Start() { - mBytesPerRow = mWidth * mBytesPerSample; - StartWindow(mBytesPerRow); -} - -void VDPixmapGenResampleCol::Compute(void *dst0, sint32 y) { - const uint32 winsize = mWinSize; - const uint32 dx = mSrcWidth; - - y -= (sint32)mAxis.dx_precopy; - - if (y < 0) { - const void *srcrow0 = mpSrc->GetRow(0, mSrcIndex); - memcpy(dst0, srcrow0, mBytesPerRow); - return; - } - - uint32 midrange = mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip + mAxis.dx_dualclip; - - if (y < (sint32)midrange) { - sint32 v = mAxis.u + mAxis.dudx * y; - - if (mpColStage) { - for(uint32 i=0; i> 16) + i; - - if ((unsigned)sy >= (unsigned)mSrcHeight) - sy = (~sy >> 31) & (mSrcHeight - 1); - - mWindow[i] = mpSrc->GetRow(sy, mSrcIndex); - } - - mpColStage->Process(dst0, mWindow.data(), dx, v); - } else - memcpy(dst0, mpSrc->GetRow(v >> 16, mSrcIndex), mBytesPerRow); - return; - } - - const void *p = mpSrc->GetRow(mSrcHeight - 1, mSrcIndex); - - memcpy(dst0, p, mBytesPerRow); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "resample_stages_x86.h" +#include "uberblit_resample.h" + +namespace { + sint32 scale32x32_fp16(sint32 x, sint32 y) { + return (sint32)(((sint64)x * y + 0x8000) >> 16); + } + + template + IVDResamplerSeparableRowStage *RowFactory(double cutoff, float filterFactor) { + return new T; + } + + template + IVDResamplerSeparableRowStage *RowFactoryLinear(double cutoff, float filterFactor) { + return new T(VDResamplerLinearFilter(cutoff)); + } + + template + IVDResamplerSeparableRowStage *RowFactoryCubic(double cutoff, float filterFactor) { + return new T(VDResamplerCubicFilter(cutoff, filterFactor)); + } + + template + IVDResamplerSeparableRowStage *RowFactoryCubic2(double cutoff, float filterFactor) { + return new T(filterFactor); + } + + template + IVDResamplerSeparableRowStage *RowFactoryLanczos3(double cutoff, float filterFactor) { + return new T(VDResamplerLanczos3Filter(cutoff)); + } + + template + IVDResamplerSeparableColStage *ColFactory(double cutoff, float filterFactor) { + return new T; + } + + template + IVDResamplerSeparableColStage *ColFactoryLinear(double cutoff, float filterFactor) { + return new T(VDResamplerLinearFilter(cutoff)); + } + + template + IVDResamplerSeparableColStage *ColFactoryCubic(double cutoff, float filterFactor) { + return new T(VDResamplerCubicFilter(cutoff, filterFactor)); + } + + template + IVDResamplerSeparableColStage *ColFactoryCubic2(double cutoff, float filterFactor) { + return new T(filterFactor); + } + + template + IVDResamplerSeparableColStage *ColFactoryLanczos3(double cutoff, float filterFactor) { + return new T(VDResamplerLanczos3Filter(cutoff)); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDPixmapGenResampleRow +// +/////////////////////////////////////////////////////////////////////////// + +VDPixmapGenResampleRow::VDPixmapGenResampleRow() + : mpRowStage(NULL) + , mpRowStage2(NULL) +{ +} + +VDPixmapGenResampleRow::~VDPixmapGenResampleRow() { + if (mpRowStage) + delete mpRowStage; +} + +void VDPixmapGenResampleRow::Init(IVDPixmapGen *src, uint32 srcIndex, uint32 width, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly) { + InitSource(src, srcIndex); + + sint32 u0 = (sint32)(offset * 65536.0); + sint32 dudx = (sint32)(step * 65536.0); + + mAxis.Init(dudx); + + double x_2fc = 1.0; + if (!interpolationOnly && step > 1.0f) + x_2fc = 1.0 / step; + + struct SpecialCaseSpanRoutine { + sint32 mPhase; + sint32 mStep; + uint32 mType; + nsVDPixmap::FilterMode mFilterMode; + uint32 mCPUFlags; + IVDResamplerSeparableRowStage *(*mpClassFactory)(double filterCutoff, float filterFactor); + }; + + static const SpecialCaseSpanRoutine kSpecialCaseSpanRoutines[]={ + // Generic +#if defined _M_IX86 + { +0x0000, 0x008000, kVDPixType_8, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_INTEGER_SSE, RowFactory }, +#endif + + { +0x0000, 0x008000, kVDPixType_8, nsVDPixmap::kFilterLinear, 0, RowFactory }, + }; + + long flags = CPUGetEnabledExtensions(); + uint32 type = mpSrc->GetType(mSrcIndex) & kVDPixType_Mask; + + for(int i=0; iAsRowStage2(); + break; + } + + if (!mpRowStage) { + struct SpanRoutine { + uint32 mType; + bool mbInterpOnly; + nsVDPixmap::FilterMode mFilterMode; + uint32 mCPUFlags; + IVDResamplerSeparableRowStage *(*mpClassFactory)(double filterCutoff, float filterFactor); + }; + + static const SpanRoutine kSpanRoutines[]={ +#if defined _M_IX86 + // X86 + { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, CPUF_SUPPORTS_MMX, RowFactory }, + { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE41, RowFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactoryLinear }, + { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactory }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, RowFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE41, RowFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic }, + { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic2 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, RowFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE41, RowFactoryLanczos3 }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, RowFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, RowFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, RowFactoryLanczos3 }, +#elif defined _M_AMD64 + // AMD64 + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, RowFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, RowFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, RowFactoryLanczos3 }, +#endif + // Generic + { kVDPixType_8, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, + { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, + { kVDPixType_8, true, nsVDPixmap::kFilterLinear, 0, RowFactory }, + { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, 0, RowFactory }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, + }; + + for(int i=0; iAsRowStage2(); + break; + } + } + + VDASSERT(mpRowStage); + + mRowFiltW = mpRowStage->GetWindowSize(); + + mpSrc->AddWindowRequest(0, 0); + + sint32 fsx1 = (sint32)(offset * 65536.0) - ((mRowFiltW-1) << 15); + mAxis.Compute(width, fsx1, mSrcWidth, mRowFiltW); + mWidth = width; + + switch(type) { + case kVDPixType_8: + mBytesPerSample = 1; + break; + case kVDPixType_8888: + case kVDPixType_32F_LE: + mBytesPerSample = 4; + break; + case kVDPixType_32Fx4_LE: + mBytesPerSample = 16; + break; + + default: + VDASSERT(false); + } +} + +void VDPixmapGenResampleRow::Start() { + StartWindow(mWidth * mBytesPerSample); + + uint32 clipSpace = ((mRowFiltW*3*mBytesPerSample + 15) >> 4) << 2; + mTempSpace.resize(clipSpace); + + if (mpRowStage2) + mpRowStage2->Init(mAxis, mSrcWidth); +} + +void VDPixmapGenResampleRow::Compute(void *dst0, sint32 y) { + switch(mBytesPerSample) { + case 1: + Compute8(dst0, y); + break; + case 4: + Compute32(dst0, y); + break; + case 16: + Compute128(dst0, y); + break; + } +} + +void VDPixmapGenResampleRow::Compute8(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + uint8 *dst = (uint8 *)dst0; + + // process pre-copy region + if (uint32 count = mAxis.dx_precopy) { + VDMemset8(dst, src[0], count); + dst += count; + } + + uint8 *p = (uint8*)mTempSpace.data(); + sint32 u = mAxis.u; + const sint32 dudx = mAxis.dudx; + + // process dual-clip region + if (mpRowStage2) { + uint32 count = mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip + mAxis.dx_dualclip; + mpRowStage2->Process(dst, src, count); + dst += count; + } else if (uint32 count = mAxis.dx_dualclip) { + VDMemset8(p, src[0], mRowFiltW); + memcpy(p + mRowFiltW, src+1, (mSrcWidth-2)); + VDMemset8(p + mRowFiltW + (mSrcWidth-2), src[mSrcWidth-1], mRowFiltW); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count; + } else { + // process pre-clip region + if (uint32 count = mAxis.dx_preclip) { + VDMemset8(p, src[0], mRowFiltW); + memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count; + } + + // process active region + if (uint32 count = mAxis.dx_active) { + mpRowStage->Process(dst, src, count, u, dudx); + u += dudx*count; + dst += count; + } + + // process post-clip region + if (uint32 count = mAxis.dx_postclip) { + uint32 offset = mSrcWidth + 1 - mRowFiltW; + + memcpy(p, src+offset, (mRowFiltW-1)); + VDMemset8(p + (mRowFiltW-1), src[mSrcWidth-1], mRowFiltW); + + mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); + dst += count; + } + } + + // process post-copy region + if (uint32 count = mAxis.dx_postcopy) { + VDMemset8(dst, src[mSrcWidth-1], count); + } +} + +void VDPixmapGenResampleRow::Compute32(void *dst0, sint32 y) { + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + uint32 *dst = (uint32 *)dst0; + + // process pre-copy region + if (uint32 count = mAxis.dx_precopy) { + VDMemset32(dst, src[0], count); + dst += count; + } + + uint32 *p = mTempSpace.data(); + sint32 u = mAxis.u; + const sint32 dudx = mAxis.dudx; + + // process dual-clip region + if (uint32 count = mAxis.dx_dualclip) { + VDMemset32(p, src[0], mRowFiltW); + memcpy(p + mRowFiltW, src+1, (mSrcWidth-2)*sizeof(uint32)); + VDMemset32(p + mRowFiltW + (mSrcWidth-2), src[mSrcWidth-1], mRowFiltW); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count; + } else if (mpRowStage2) { + mpRowStage2->Process(dst, p, mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip); + } else { + // process pre-clip region + if (uint32 count = mAxis.dx_preclip) { + VDMemset32(p, src[0], mRowFiltW); + memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32)); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count; + } + + // process active region + if (uint32 count = mAxis.dx_active) { + mpRowStage->Process(dst, src, count, u, dudx); + u += dudx*count; + dst += count; + } + + // process post-clip region + if (uint32 count = mAxis.dx_postclip) { + uint32 offset = mSrcWidth + 1 - mRowFiltW; + + memcpy(p, src+offset, (mRowFiltW-1)*sizeof(uint32)); + VDMemset32(p + (mRowFiltW-1), src[mSrcWidth-1], mRowFiltW); + + mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); + dst += count; + } + } + + // process post-copy region + if (uint32 count = mAxis.dx_postcopy) { + VDMemset32(dst, src[mSrcWidth-1], count); + } +} + +void VDPixmapGenResampleRow::Compute128(void *dst0, sint32 y) { + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + uint32 *dst = (uint32 *)dst0; + + // process pre-copy region + if (uint32 count = mAxis.dx_precopy) { + VDMemset128(dst, src, count); + dst += 4*count; + } + + uint32 *p = mTempSpace.data(); + sint32 u = mAxis.u; + const sint32 dudx = mAxis.dudx; + + // process dual-clip region + if (uint32 count = mAxis.dx_dualclip) { + VDMemset128(p, src, mRowFiltW); + memcpy(p + 4*mRowFiltW, src+1, (mSrcWidth-2)*sizeof(uint32)*4); + VDMemset128(p + 4*(mRowFiltW + (mSrcWidth-2)), src + 4*(mSrcWidth-1), mRowFiltW); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count * 4; + } else if (mpRowStage2) { + mpRowStage2->Process(dst, p, mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip); + } else { + // process pre-clip region + if (uint32 count = mAxis.dx_preclip) { + VDMemset128(p, src, mRowFiltW); + memcpy(p + 4*mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32)*4); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count*4; + } + + // process active region + if (uint32 count = mAxis.dx_active) { + mpRowStage->Process(dst, src, count, u, dudx); + u += dudx*count; + dst += count*4; + } + + // process post-clip region + if (uint32 count = mAxis.dx_postclip) { + uint32 offset = mSrcWidth + 1 - mRowFiltW; + + memcpy(p, src+offset*4, (mRowFiltW-1)*sizeof(uint32)*4); + VDMemset128(p + 4*(mRowFiltW-1), src + 4*(mSrcWidth-1), mRowFiltW); + + mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); + dst += count*4; + } + } + + // process post-copy region + if (uint32 count = mAxis.dx_postcopy) { + VDMemset128(dst, src + 4*(mSrcWidth-1), count); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDPixmapGenResampleCol +// +/////////////////////////////////////////////////////////////////////////// + +VDPixmapGenResampleCol::VDPixmapGenResampleCol() + : mpColStage(NULL) +{ +} + +VDPixmapGenResampleCol::~VDPixmapGenResampleCol() { + if (mpColStage) + delete mpColStage; +} + +void VDPixmapGenResampleCol::Init(IVDPixmapGen *src, uint32 srcIndex, uint32 height, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly) { + InitSource(src, srcIndex); + + sint32 dvdy = (sint32)(step * 65536.0); + + mAxis.Init(dvdy); + + // construct stages + double y_2fc = 1.0; + if (!interpolationOnly && step > 1.0f) + y_2fc = 1.0 / step; + + struct SpanRoutine { + uint32 mType; + bool mbInterpOnly; + nsVDPixmap::FilterMode mFilterMode; + uint32 mCPUFlags; + IVDResamplerSeparableColStage *(*mpClassFactory)(double filterCutoff, float filterFactor); + }; + + static const SpanRoutine kSpanRoutines[]={ +#if defined _M_IX86 + // X86 + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE41, ColFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactoryLinear }, + { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactory }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, ColFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE41, ColFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic }, + { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic2 }, + { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic2 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE41, ColFactoryLanczos3 }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, ColFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, ColFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, ColFactoryLanczos3 }, +#elif defined _M_AMD64 + // AMD64 + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, ColFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, ColFactoryLanczos3 }, +#endif + // Generic + { kVDPixType_8, true, nsVDPixmap::kFilterLinear, 0, ColFactory }, + { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, 0, ColFactory }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, + }; + + long flags = CPUGetEnabledExtensions(); + uint32 type = src->GetType(srcIndex) & kVDPixType_Mask; + for(int i=0; iGetWindowSize() : 1; + mWindow.resize(mWinSize); + + int delta = (mWinSize + 1) >> 1; + mpSrc->AddWindowRequest(-delta, delta); + + sint32 fsy1 = (sint32)(offset * 65536.0) - ((mWinSize-1)<<15); + mAxis.Compute(height, fsy1, mSrcHeight, mWinSize); + mHeight = height; + + switch(type) { + case kVDPixType_8: + mBytesPerSample = 1; + break; + case kVDPixType_8888: + case kVDPixType_32F_LE: + mBytesPerSample = 4; + break; + case kVDPixType_32Fx4_LE: + mBytesPerSample = 16; + break; + + default: + VDASSERT(false); + } +} + +void VDPixmapGenResampleCol::Start() { + mBytesPerRow = mWidth * mBytesPerSample; + StartWindow(mBytesPerRow); +} + +void VDPixmapGenResampleCol::Compute(void *dst0, sint32 y) { + const uint32 winsize = mWinSize; + const uint32 dx = mSrcWidth; + + y -= (sint32)mAxis.dx_precopy; + + if (y < 0) { + const void *srcrow0 = mpSrc->GetRow(0, mSrcIndex); + memcpy(dst0, srcrow0, mBytesPerRow); + return; + } + + uint32 midrange = mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip + mAxis.dx_dualclip; + + if (y < (sint32)midrange) { + sint32 v = mAxis.u + mAxis.dudx * y; + + if (mpColStage) { + for(uint32 i=0; i> 16) + i; + + if ((unsigned)sy >= (unsigned)mSrcHeight) + sy = (~sy >> 31) & (mSrcHeight - 1); + + mWindow[i] = mpSrc->GetRow(sy, mSrcIndex); + } + + mpColStage->Process(dst0, mWindow.data(), dx, v); + } else + memcpy(dst0, mpSrc->GetRow(v >> 16, mSrcIndex), mBytesPerRow); + return; + } + + const void *p = mpSrc->GetRow(mSrcHeight - 1, mSrcIndex); + + memcpy(dst0, p, mBytesPerRow); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special.cpp index b162dbcc035..a962dd4a02b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special.cpp @@ -1,205 +1,205 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include "uberblit_resample_special.h" -#include "blt_spanutils.h" - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleRow_d2_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(0, 0); - - mWidth = (mSrcWidth + 1) >> 1; -} - -void VDPixmapGenResampleRow_d2_p0_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleRow_d2_p0_lin_u8::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_compress2x_coaligned((uint8 *)dst0, src, mSrcWidth); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleRow_d4_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(0, 0); - - mWidth = (mSrcWidth + 3) >> 2; -} - -void VDPixmapGenResampleRow_d4_p0_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleRow_d4_p0_lin_u8::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_compress4x_coaligned((uint8 *)dst0, src, mSrcWidth); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleRow_x2_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(0, 0); - - mWidth = mSrcWidth * 2; -} - -void VDPixmapGenResampleRow_x2_p0_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleRow_x2_p0_lin_u8::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_expand2x_coaligned((uint8 *)dst0, src, mWidth); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleRow_x4_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(0, 0); - - mWidth = mSrcWidth * 4; -} - -void VDPixmapGenResampleRow_x4_p0_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleRow_x4_p0_lin_u8::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_expand4x_coaligned((uint8 *)dst0, src, mWidth); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleCol_x2_phalf_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(-2, 2); - - mHeight = (mSrcHeight + 1) >> 1; -} - -void VDPixmapGenResampleCol_x2_phalf_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleCol_x2_phalf_lin_u8::Compute(void *dst0, sint32 y) { - sint32 y2 = y+y; - const uint8 *src[4] = { - (const uint8 *)mpSrc->GetRow(y2 > 0 ? y2-1 : 0, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2 , mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+2, mSrcIndex) - }; - - nsVDPixmapSpanUtils::vert_compress2x_centered((uint8 *)dst0, src, mWidth, 0); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleCol_x4_p1half_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(-4, 4); - - mHeight = (mSrcHeight + 2) >> 2; -} - -void VDPixmapGenResampleCol_x4_p1half_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleCol_x4_p1half_lin_u8::Compute(void *dst0, sint32 y) { - sint32 y4 = y*4; - const uint8 *src[8] = { - (const uint8 *)mpSrc->GetRow(y4 > 2 ? y4-2 : 0, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4 > 1 ? y4-1 : 0, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4 , mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+1, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+3, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+4, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+5, mSrcIndex) - }; - - nsVDPixmapSpanUtils::vert_compress4x_centered((uint8 *)dst0, src, mWidth, 0); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(-1, 1); - - mHeight = mSrcHeight * 2; -} - -void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Compute(void *dst0, sint32 y) { - sint32 y2 = (y - 1) >> 1; - const uint8 *src[2] = { - (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - }; - - nsVDPixmapSpanUtils::vert_expand2x_centered((uint8 *)dst0, src, mWidth, ~y << 7); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleCol_d4_pn38_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(-1, 1); - - mHeight = mSrcHeight * 4; -} - -void VDPixmapGenResampleCol_d4_pn38_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleCol_d4_pn38_lin_u8::Compute(void *dst0, sint32 y) { - sint32 y2 = (y - 2) >> 2; - const uint8 *src[2] = { - (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - }; - - nsVDPixmapSpanUtils::vert_expand4x_centered((uint8 *)dst0, src, mWidth, (y - 2) << 6); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "uberblit_resample_special.h" +#include "blt_spanutils.h" + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleRow_d2_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(0, 0); + + mWidth = (mSrcWidth + 1) >> 1; +} + +void VDPixmapGenResampleRow_d2_p0_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleRow_d2_p0_lin_u8::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_compress2x_coaligned((uint8 *)dst0, src, mSrcWidth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleRow_d4_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(0, 0); + + mWidth = (mSrcWidth + 3) >> 2; +} + +void VDPixmapGenResampleRow_d4_p0_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleRow_d4_p0_lin_u8::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_compress4x_coaligned((uint8 *)dst0, src, mSrcWidth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleRow_x2_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(0, 0); + + mWidth = mSrcWidth * 2; +} + +void VDPixmapGenResampleRow_x2_p0_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleRow_x2_p0_lin_u8::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_expand2x_coaligned((uint8 *)dst0, src, mWidth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleRow_x4_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(0, 0); + + mWidth = mSrcWidth * 4; +} + +void VDPixmapGenResampleRow_x4_p0_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleRow_x4_p0_lin_u8::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_expand4x_coaligned((uint8 *)dst0, src, mWidth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleCol_x2_phalf_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(-2, 2); + + mHeight = (mSrcHeight + 1) >> 1; +} + +void VDPixmapGenResampleCol_x2_phalf_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleCol_x2_phalf_lin_u8::Compute(void *dst0, sint32 y) { + sint32 y2 = y+y; + const uint8 *src[4] = { + (const uint8 *)mpSrc->GetRow(y2 > 0 ? y2-1 : 0, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2 , mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+2, mSrcIndex) + }; + + nsVDPixmapSpanUtils::vert_compress2x_centered((uint8 *)dst0, src, mWidth, 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleCol_x4_p1half_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(-4, 4); + + mHeight = (mSrcHeight + 2) >> 2; +} + +void VDPixmapGenResampleCol_x4_p1half_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleCol_x4_p1half_lin_u8::Compute(void *dst0, sint32 y) { + sint32 y4 = y*4; + const uint8 *src[8] = { + (const uint8 *)mpSrc->GetRow(y4 > 2 ? y4-2 : 0, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4 > 1 ? y4-1 : 0, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4 , mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+1, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+3, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+4, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+5, mSrcIndex) + }; + + nsVDPixmapSpanUtils::vert_compress4x_centered((uint8 *)dst0, src, mWidth, 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(-1, 1); + + mHeight = mSrcHeight * 2; +} + +void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Compute(void *dst0, sint32 y) { + sint32 y2 = (y - 1) >> 1; + const uint8 *src[2] = { + (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + }; + + nsVDPixmapSpanUtils::vert_expand2x_centered((uint8 *)dst0, src, mWidth, ~y << 7); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleCol_d4_pn38_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(-1, 1); + + mHeight = mSrcHeight * 4; +} + +void VDPixmapGenResampleCol_d4_pn38_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleCol_d4_pn38_lin_u8::Compute(void *dst0, sint32 y) { + sint32 y2 = (y - 2) >> 2; + const uint8 *src[2] = { + (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + }; + + nsVDPixmapSpanUtils::vert_expand4x_centered((uint8 *)dst0, src, mWidth, (y - 2) << 6); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special_x86.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special_x86.cpp index 990e0520ed3..dcb650513a9 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special_x86.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special_x86.cpp @@ -1,54 +1,54 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include "uberblit_resample_special_x86.h" -#include "blt_spanutils.h" -#include "blt_spanutils_x86.h" - -void VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE((uint8 *)dst0, src, mWidth); -} - -void VDPixmapGenResampleRow_x4_p0_lin_u8_MMX::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_expand4x_coaligned_MMX((uint8 *)dst0, src, mWidth); -} - -void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE::Compute(void *dst0, sint32 y) { - sint32 y2 = (y - 1) >> 1; - const uint8 *src[2] = { - (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - }; - - nsVDPixmapSpanUtils::vert_expand2x_centered_ISSE((uint8 *)dst0, src, mWidth, ~y << 7); -} - -void VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE::Compute(void *dst0, sint32 y) { - sint32 y2 = (y - 2) >> 2; - const uint8 *src[2] = { - (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - }; - - nsVDPixmapSpanUtils::vert_expand4x_centered_ISSE((uint8 *)dst0, src, mWidth, (y - 2) << 6); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "uberblit_resample_special_x86.h" +#include "blt_spanutils.h" +#include "blt_spanutils_x86.h" + +void VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE((uint8 *)dst0, src, mWidth); +} + +void VDPixmapGenResampleRow_x4_p0_lin_u8_MMX::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_expand4x_coaligned_MMX((uint8 *)dst0, src, mWidth); +} + +void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE::Compute(void *dst0, sint32 y) { + sint32 y2 = (y - 1) >> 1; + const uint8 *src[2] = { + (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + }; + + nsVDPixmapSpanUtils::vert_expand2x_centered_ISSE((uint8 *)dst0, src, mWidth, ~y << 7); +} + +void VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE::Compute(void *dst0, sint32 y) { + sint32 y2 = (y - 2) >> 2; + const uint8 *src[2] = { + (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + }; + + nsVDPixmapSpanUtils::vert_expand4x_centered_ISSE((uint8 *)dst0, src, mWidth, (y - 2) << 6); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_swizzle.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_swizzle.cpp index d65c317a242..7376692eafa 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_swizzle.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_swizzle.cpp @@ -1,108 +1,108 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include "uberblit_swizzle.h" - -void VDPixmapGen_Swap8In16::Init(IVDPixmapGen *gen, int srcIndex, uint32 w, uint32 h, uint32 bpr) { - InitSource(gen, srcIndex); - mRowLength = bpr; - SetOutputSize(w, h); - gen->AddWindowRequest(0, 0); -} - -void VDPixmapGen_Swap8In16::Start() { - StartWindow(mRowLength); -} - -uint32 VDPixmapGen_Swap8In16::GetType(uint32 index) const { - return mpSrc->GetType(mSrcIndex); -} - -void VDPixmapGen_Swap8In16::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - uint8 *dst = (uint8 *)dst0; - sint32 w = mRowLength; - - uint32 n4 = w >> 2; - - for(uint32 i=0; i> 8) + ((p & 0x00ff00ff) << 8); - - *(uint32 *)dst = r; - dst += 4; - } - - if (w & 2) { - dst[0] = src[1]; - dst[1] = src[0]; - dst += 2; - src += 2; - } - - if (w & 1) { - *dst = *src; - } -} - -///////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_B8x2_To_B8R8::Init(IVDPixmapGen *srcCb, uint32 srcindexCb, IVDPixmapGen *srcCr, uint32 srcindexCr) { - mpSrcCb = srcCb; - mSrcIndexCb = srcindexCb; - mpSrcCr = srcCr; - mSrcIndexCr = srcindexCr; - mWidth = srcCb->GetWidth(srcindexCb); - mHeight = srcCb->GetHeight(srcindexCb); - - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); -} - -void VDPixmapGen_B8x2_To_B8R8::Start() { - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 2); -} - -uint32 VDPixmapGen_B8x2_To_B8R8::GetType(uint32 output) const { - return (mpSrcCb->GetType(mSrcIndexCb) & ~kVDPixType_Mask) | kVDPixType_B8R8; -} - -void VDPixmapGen_B8x2_To_B8R8::Compute(void *dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *)dst0; - const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - sint32 w = mWidth; - for(sint32 x=0; x +#include "uberblit_swizzle.h" + +void VDPixmapGen_Swap8In16::Init(IVDPixmapGen *gen, int srcIndex, uint32 w, uint32 h, uint32 bpr) { + InitSource(gen, srcIndex); + mRowLength = bpr; + SetOutputSize(w, h); + gen->AddWindowRequest(0, 0); +} + +void VDPixmapGen_Swap8In16::Start() { + StartWindow(mRowLength); +} + +uint32 VDPixmapGen_Swap8In16::GetType(uint32 index) const { + return mpSrc->GetType(mSrcIndex); +} + +void VDPixmapGen_Swap8In16::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + uint8 *dst = (uint8 *)dst0; + sint32 w = mRowLength; + + uint32 n4 = w >> 2; + + for(uint32 i=0; i> 8) + ((p & 0x00ff00ff) << 8); + + *(uint32 *)dst = r; + dst += 4; + } + + if (w & 2) { + dst[0] = src[1]; + dst[1] = src[0]; + dst += 2; + src += 2; + } + + if (w & 1) { + *dst = *src; + } +} + +///////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_B8x2_To_B8R8::Init(IVDPixmapGen *srcCb, uint32 srcindexCb, IVDPixmapGen *srcCr, uint32 srcindexCr) { + mpSrcCb = srcCb; + mSrcIndexCb = srcindexCb; + mpSrcCr = srcCr; + mSrcIndexCr = srcindexCr; + mWidth = srcCb->GetWidth(srcindexCb); + mHeight = srcCb->GetHeight(srcindexCb); + + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); +} + +void VDPixmapGen_B8x2_To_B8R8::Start() { + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 2); +} + +uint32 VDPixmapGen_B8x2_To_B8R8::GetType(uint32 output) const { + return (mpSrcCb->GetType(mSrcIndexCb) & ~kVDPixType_Mask) | kVDPixType_B8R8; +} + +void VDPixmapGen_B8x2_To_B8R8::Compute(void *dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *)dst0; + const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + sint32 w = mWidth; + for(sint32 x=0; x -#include "uberblit_swizzle_x86.h" - -#ifdef VD_COMPILER_MSVC - #pragma warning(disable: 4799) // warning C4799: function 'vdasm_extract_8in16_even_MMX' has no EMMS instruction -#endif - -void __declspec(naked) __fastcall vdasm_extract_8in16_even_MMX(void *dst, const void *src, uint32 count) { - __asm { - mov eax, [esp+4] - pcmpeqb mm2, mm2 - psrlw mm2, 8 - sub eax, 8 - jc xtra -xloop: - movq mm0, [edx] - movq mm1, [edx+8] - pand mm0, mm2 - pand mm1, mm2 - packuswb mm0, mm1 - add edx, 16 - movq [ecx], mm0 - add ecx, 8 - sub eax, 8 - jns xloop -xtra: - add eax, 8 - jz fin - push ebx -xtraloop: - mov bl, [edx] - add edx, 2 - mov [ecx], bl - add ecx, 1 - sub eax, 1 - jnz xtraloop - - pop ebx -fin: - ret 4 - } -} - -void __declspec(naked) __fastcall vdasm_extract_8in16_odd_MMX(void *dst, const void *src, uint32 count) { - __asm { - mov eax, [esp+4] - sub eax, 8 - jc xtra -xloop: - movq mm0, [edx] - movq mm1, [edx+8] - psrlw mm0, 8 - psrlw mm1, 8 - add edx, 16 - packuswb mm0, mm1 - movq [ecx], mm0 - add ecx, 8 - sub eax, 8 - jns xloop -xtra: - add eax, 8 - jz fin - push ebx -xtraloop: - mov bl, [edx+1] - add edx, 2 - mov [ecx], bl - add ecx, 1 - sub eax, 1 - jnz xtraloop - - pop ebx -fin: - ret 4 - } -} - -void __declspec(naked) __fastcall vdasm_extract_8in32_MMX(void *dst, const void *src, uint32 count, int byteshift) { - __asm { - movd mm4, [esp+8] - pcmpeqb mm5, mm5 - pslld mm4, 3 - mov eax, [esp+4] - psrld mm5, 24 - sub eax, 8 - jc xtra -xloop: - movq mm0, [edx] - movq mm1, [edx+8] - psrld mm0, mm4 - movq mm2, [edx+16] - psrld mm1, mm4 - pand mm0, mm5 - movq mm3, [edx+24] - psrld mm2, mm4 - pand mm1, mm5 - packssdw mm0, mm1 - psrld mm3, mm4 - pand mm2, mm5 - pand mm3, mm5 - add edx, 32 - packssdw mm2, mm3 - packuswb mm0, mm2 - movq [ecx], mm0 - add ecx, 8 - sub eax, 8 - jns xloop -xtra: - add eax, 8 - jz fin - add edx, dword ptr [esp+8] - push ebx -xtraloop: - mov bl, [edx] - add edx, 4 - mov [ecx], bl - add ecx, 1 - sub eax, 1 - jnz xtraloop - - pop ebx -fin: - ret 8 - } -} - -void __declspec(naked) __fastcall vdasm_swap_8in16_MMX(void *dst, const void *src, uint32 count) { - __asm { - mov eax, [esp+4] - sub eax, 8 - js xtra -xloop: - movq mm0, [edx] - add edx, 8 - movq mm1, mm0 - psllw mm0, 8 - psrlw mm1, 8 - paddb mm0, mm1 - movq [ecx], mm0 - add ecx, 8 - sub eax, 8 - jns xloop -xtra: - add eax, 6 - js nopairs - push ebx -pairloop: - mov bl, [edx] - mov bh, [edx+1] - add edx, 2 - mov [ecx], bh - mov [ecx+1], bl - add ecx, 2 - sub eax, 2 - jns pairloop - pop ebx -nopairs: - add eax, 2 - jz noodd - mov al, [edx] - mov [ecx], al -noodd: - ret 4 - } -} - -void __declspec(naked) __fastcall vdasm_interleave_BGRG_MMX(void *dst, const void *srcR, const void *srcG, const void *srcB, uint32 count) { - __asm { - push edi - push esi - push ebx - mov esi, [esp+12+12] - mov edi, [esp+8+12] - mov ebx, [esp+4+12] - sub esi, 4 - jc xtra - ; ecx = dst - ; edx = srcR - ; ebx = srcG - ; edi = srcB -xloop: - movd mm0, [edi] - movd mm1, [edx] - punpcklbw mm0, mm1 - movq mm1, [ebx] - movq mm2, mm0 - punpcklbw mm0, mm1 - add edx, 4 - punpckhbw mm2, mm1 - add edi, 4 - movq [ecx], mm0 - add ebx, 8 - movq [ecx+8], mm2 - add ecx, 16 - sub esi, 4 - jns xloop -xtra: - add esi, 4 - jz fin -xtraloop: - mov al, [edi] - mov [ecx], al - mov al, [ebx] - mov [ecx+1], al - mov al, [edx] - mov [ecx+2], al - mov al, [ebx+1] - mov [ecx+3], al - add ebx, 2 - add edx, 1 - add edi, 1 - add ecx, 4 - sub esi, 1 - jnz xtraloop -fin: - pop ebx - pop esi - pop edi - ret 12 - } -} - -void __declspec(naked) __fastcall vdasm_interleave_GBGR_MMX(void *dst, const void *srcR, const void *srcG, const void *srcB, uint32 count) { - __asm { - push edi - push esi - push ebx - mov esi, [esp+12+12] - mov edi, [esp+8+12] - mov ebx, [esp+4+12] - sub esi, 4 - jc xtra - ; ecx = dst - ; edx = srcR - ; ebx = srcG - ; edi = srcB -xloop: - movd mm0, [edi] - movd mm1, [edx] - punpcklbw mm0, mm1 - movq mm2, [ebx] - movq mm1, mm2 - punpcklbw mm2, mm0 - add edx, 4 - punpckhbw mm1, mm0 - add edi, 4 - movq [ecx], mm2 - add ebx, 8 - movq [ecx+8], mm1 - add ecx, 16 - sub esi, 4 - jns xloop -xtra: - add esi, 4 - jz fin -xtraloop: - mov al, [ebx] - mov [ecx], al - mov al, [edi] - mov [ecx+1], al - mov al, [ebx+1] - mov [ecx+2], al - mov al, [edx] - mov [ecx+3], al - add ebx, 2 - add edx, 1 - add edi, 1 - add ecx, 4 - sub esi, 1 - jnz xtraloop -fin: - pop ebx - pop esi - pop edi - ret 12 - } -} - -void __declspec(naked) __fastcall vdasm_interleave_BR_MMX(void *dst, const void *srcB, const void *srcR, uint32 count) { - __asm { - push edi - push esi - push ebx - mov esi, [esp+8+12] - mov ebx, [esp+4+12] - sub esi, 8 - jc xtra - ; ecx = dst - ; edx = srcB - ; ebx = srcG -xloop: - movq mm0, [edx] - movq mm1, [ebx] - movq mm2, mm0 - punpcklbw mm0, mm1 - punpckhbw mm2, mm1 - add edx, 8 - movq [ecx], mm0 - add ebx, 8 - movq [ecx+8], mm2 - add ecx, 16 - sub esi, 8 - jns xloop -xtra: - add esi, 8 - jz fin -xtraloop: - mov al, [edx] - mov [ecx], al - mov al, [ebx] - mov [ecx+1], al - add ebx, 1 - add edx, 1 - add ecx, 2 - sub esi, 1 - jnz xtraloop -fin: - pop ebx - pop esi - pop edi - ret 8 - } -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_8In16_Even_MMX::Compute(void *dst, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_extract_8in16_even_MMX(dst, srcp, mWidth); -} - -void VDPixmapGen_8In16_Odd_MMX::Compute(void *dst, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_extract_8in16_odd_MMX(dst, srcp, mWidth); -} - -void VDPixmapGen_8In32_MMX::Compute(void *dst, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_extract_8in32_MMX(dst, srcp, mWidth, mOffset); -} - -void VDPixmapGen_Swap8In16_MMX::Compute(void *dst, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_swap_8in16_MMX(dst, src, mRowLength); -} - -void VDPixmapGen_B8x2_To_B8R8_MMX::Compute(void *dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; - const uint8 *VDRESTRICT srcCb = (const uint8 *VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); - - vdasm_interleave_BR_MMX(dst, srcCb, srcCr, mWidth); -} - -void VDPixmapGen_B8x3_To_G8B8_G8R8_MMX::Compute(void *VDRESTRICT dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; - const uint8 *VDRESTRICT srcY = (const uint8 *VDRESTRICT)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *VDRESTRICT srcCb = (const uint8 *VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); - - vdasm_interleave_GBGR_MMX(dst, srcCr, srcY, srcCb, mWidth >> 1); - - if (mWidth & 1) { - int w2 = mWidth >> 1; - srcY += mWidth; - srcCb += w2; - srcCr += w2; - dst += mWidth * 2; - - dst[-2] = srcY[-1]; - dst[-1] = srcCb[0]; - dst[ 0] = 0; // must be zero for QuickTime compatibility - dst[ 1] = srcCr[0]; - } -} - -void VDPixmapGen_B8x3_To_B8G8_R8G8_MMX::Compute(void *VDRESTRICT dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; - const uint8 *VDRESTRICT srcY = (const uint8 * VDRESTRICT)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *VDRESTRICT srcCb = (const uint8 * VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 * VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); - - vdasm_interleave_BGRG_MMX(dst, srcCr, srcY, srcCb, mWidth >> 1); - - if (mWidth & 1) { - int w2 = mWidth >> 1; - srcY += mWidth; - srcCb += w2; - srcCr += w2; - dst += mWidth * 2; - - dst[-2] = srcCb[0]; - dst[-1] = srcY[-1]; - dst[ 0] = srcCr[0]; - dst[ 1] = 0; // must be zero for QuickTime compatibility - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "uberblit_swizzle_x86.h" + +#ifdef VD_COMPILER_MSVC + #pragma warning(disable: 4799) // warning C4799: function 'vdasm_extract_8in16_even_MMX' has no EMMS instruction +#endif + +void __declspec(naked) __fastcall vdasm_extract_8in16_even_MMX(void *dst, const void *src, uint32 count) { + __asm { + mov eax, [esp+4] + pcmpeqb mm2, mm2 + psrlw mm2, 8 + sub eax, 8 + jc xtra +xloop: + movq mm0, [edx] + movq mm1, [edx+8] + pand mm0, mm2 + pand mm1, mm2 + packuswb mm0, mm1 + add edx, 16 + movq [ecx], mm0 + add ecx, 8 + sub eax, 8 + jns xloop +xtra: + add eax, 8 + jz fin + push ebx +xtraloop: + mov bl, [edx] + add edx, 2 + mov [ecx], bl + add ecx, 1 + sub eax, 1 + jnz xtraloop + + pop ebx +fin: + ret 4 + } +} + +void __declspec(naked) __fastcall vdasm_extract_8in16_odd_MMX(void *dst, const void *src, uint32 count) { + __asm { + mov eax, [esp+4] + sub eax, 8 + jc xtra +xloop: + movq mm0, [edx] + movq mm1, [edx+8] + psrlw mm0, 8 + psrlw mm1, 8 + add edx, 16 + packuswb mm0, mm1 + movq [ecx], mm0 + add ecx, 8 + sub eax, 8 + jns xloop +xtra: + add eax, 8 + jz fin + push ebx +xtraloop: + mov bl, [edx+1] + add edx, 2 + mov [ecx], bl + add ecx, 1 + sub eax, 1 + jnz xtraloop + + pop ebx +fin: + ret 4 + } +} + +void __declspec(naked) __fastcall vdasm_extract_8in32_MMX(void *dst, const void *src, uint32 count, int byteshift) { + __asm { + movd mm4, [esp+8] + pcmpeqb mm5, mm5 + pslld mm4, 3 + mov eax, [esp+4] + psrld mm5, 24 + sub eax, 8 + jc xtra +xloop: + movq mm0, [edx] + movq mm1, [edx+8] + psrld mm0, mm4 + movq mm2, [edx+16] + psrld mm1, mm4 + pand mm0, mm5 + movq mm3, [edx+24] + psrld mm2, mm4 + pand mm1, mm5 + packssdw mm0, mm1 + psrld mm3, mm4 + pand mm2, mm5 + pand mm3, mm5 + add edx, 32 + packssdw mm2, mm3 + packuswb mm0, mm2 + movq [ecx], mm0 + add ecx, 8 + sub eax, 8 + jns xloop +xtra: + add eax, 8 + jz fin + add edx, dword ptr [esp+8] + push ebx +xtraloop: + mov bl, [edx] + add edx, 4 + mov [ecx], bl + add ecx, 1 + sub eax, 1 + jnz xtraloop + + pop ebx +fin: + ret 8 + } +} + +void __declspec(naked) __fastcall vdasm_swap_8in16_MMX(void *dst, const void *src, uint32 count) { + __asm { + mov eax, [esp+4] + sub eax, 8 + js xtra +xloop: + movq mm0, [edx] + add edx, 8 + movq mm1, mm0 + psllw mm0, 8 + psrlw mm1, 8 + paddb mm0, mm1 + movq [ecx], mm0 + add ecx, 8 + sub eax, 8 + jns xloop +xtra: + add eax, 6 + js nopairs + push ebx +pairloop: + mov bl, [edx] + mov bh, [edx+1] + add edx, 2 + mov [ecx], bh + mov [ecx+1], bl + add ecx, 2 + sub eax, 2 + jns pairloop + pop ebx +nopairs: + add eax, 2 + jz noodd + mov al, [edx] + mov [ecx], al +noodd: + ret 4 + } +} + +void __declspec(naked) __fastcall vdasm_interleave_BGRG_MMX(void *dst, const void *srcR, const void *srcG, const void *srcB, uint32 count) { + __asm { + push edi + push esi + push ebx + mov esi, [esp+12+12] + mov edi, [esp+8+12] + mov ebx, [esp+4+12] + sub esi, 4 + jc xtra + ; ecx = dst + ; edx = srcR + ; ebx = srcG + ; edi = srcB +xloop: + movd mm0, [edi] + movd mm1, [edx] + punpcklbw mm0, mm1 + movq mm1, [ebx] + movq mm2, mm0 + punpcklbw mm0, mm1 + add edx, 4 + punpckhbw mm2, mm1 + add edi, 4 + movq [ecx], mm0 + add ebx, 8 + movq [ecx+8], mm2 + add ecx, 16 + sub esi, 4 + jns xloop +xtra: + add esi, 4 + jz fin +xtraloop: + mov al, [edi] + mov [ecx], al + mov al, [ebx] + mov [ecx+1], al + mov al, [edx] + mov [ecx+2], al + mov al, [ebx+1] + mov [ecx+3], al + add ebx, 2 + add edx, 1 + add edi, 1 + add ecx, 4 + sub esi, 1 + jnz xtraloop +fin: + pop ebx + pop esi + pop edi + ret 12 + } +} + +void __declspec(naked) __fastcall vdasm_interleave_GBGR_MMX(void *dst, const void *srcR, const void *srcG, const void *srcB, uint32 count) { + __asm { + push edi + push esi + push ebx + mov esi, [esp+12+12] + mov edi, [esp+8+12] + mov ebx, [esp+4+12] + sub esi, 4 + jc xtra + ; ecx = dst + ; edx = srcR + ; ebx = srcG + ; edi = srcB +xloop: + movd mm0, [edi] + movd mm1, [edx] + punpcklbw mm0, mm1 + movq mm2, [ebx] + movq mm1, mm2 + punpcklbw mm2, mm0 + add edx, 4 + punpckhbw mm1, mm0 + add edi, 4 + movq [ecx], mm2 + add ebx, 8 + movq [ecx+8], mm1 + add ecx, 16 + sub esi, 4 + jns xloop +xtra: + add esi, 4 + jz fin +xtraloop: + mov al, [ebx] + mov [ecx], al + mov al, [edi] + mov [ecx+1], al + mov al, [ebx+1] + mov [ecx+2], al + mov al, [edx] + mov [ecx+3], al + add ebx, 2 + add edx, 1 + add edi, 1 + add ecx, 4 + sub esi, 1 + jnz xtraloop +fin: + pop ebx + pop esi + pop edi + ret 12 + } +} + +void __declspec(naked) __fastcall vdasm_interleave_BR_MMX(void *dst, const void *srcB, const void *srcR, uint32 count) { + __asm { + push edi + push esi + push ebx + mov esi, [esp+8+12] + mov ebx, [esp+4+12] + sub esi, 8 + jc xtra + ; ecx = dst + ; edx = srcB + ; ebx = srcG +xloop: + movq mm0, [edx] + movq mm1, [ebx] + movq mm2, mm0 + punpcklbw mm0, mm1 + punpckhbw mm2, mm1 + add edx, 8 + movq [ecx], mm0 + add ebx, 8 + movq [ecx+8], mm2 + add ecx, 16 + sub esi, 8 + jns xloop +xtra: + add esi, 8 + jz fin +xtraloop: + mov al, [edx] + mov [ecx], al + mov al, [ebx] + mov [ecx+1], al + add ebx, 1 + add edx, 1 + add ecx, 2 + sub esi, 1 + jnz xtraloop +fin: + pop ebx + pop esi + pop edi + ret 8 + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_8In16_Even_MMX::Compute(void *dst, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_extract_8in16_even_MMX(dst, srcp, mWidth); +} + +void VDPixmapGen_8In16_Odd_MMX::Compute(void *dst, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_extract_8in16_odd_MMX(dst, srcp, mWidth); +} + +void VDPixmapGen_8In32_MMX::Compute(void *dst, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_extract_8in32_MMX(dst, srcp, mWidth, mOffset); +} + +void VDPixmapGen_Swap8In16_MMX::Compute(void *dst, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_swap_8in16_MMX(dst, src, mRowLength); +} + +void VDPixmapGen_B8x2_To_B8R8_MMX::Compute(void *dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; + const uint8 *VDRESTRICT srcCb = (const uint8 *VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); + + vdasm_interleave_BR_MMX(dst, srcCb, srcCr, mWidth); +} + +void VDPixmapGen_B8x3_To_G8B8_G8R8_MMX::Compute(void *VDRESTRICT dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; + const uint8 *VDRESTRICT srcY = (const uint8 *VDRESTRICT)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *VDRESTRICT srcCb = (const uint8 *VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); + + vdasm_interleave_GBGR_MMX(dst, srcCr, srcY, srcCb, mWidth >> 1); + + if (mWidth & 1) { + int w2 = mWidth >> 1; + srcY += mWidth; + srcCb += w2; + srcCr += w2; + dst += mWidth * 2; + + dst[-2] = srcY[-1]; + dst[-1] = srcCb[0]; + dst[ 0] = 0; // must be zero for QuickTime compatibility + dst[ 1] = srcCr[0]; + } +} + +void VDPixmapGen_B8x3_To_B8G8_R8G8_MMX::Compute(void *VDRESTRICT dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; + const uint8 *VDRESTRICT srcY = (const uint8 * VDRESTRICT)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *VDRESTRICT srcCb = (const uint8 * VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 * VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); + + vdasm_interleave_BGRG_MMX(dst, srcCr, srcY, srcCb, mWidth >> 1); + + if (mWidth & 1) { + int w2 = mWidth >> 1; + srcY += mWidth; + srcCb += w2; + srcCr += w2; + dst += mWidth * 2; + + dst[-2] = srcCb[0]; + dst[-1] = srcY[-1]; + dst[ 0] = srcCr[0]; + dst[ 1] = 0; // must be zero for QuickTime compatibility + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_v210.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_v210.cpp index 1e558aabd77..073bd1af0d9 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_v210.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_v210.cpp @@ -1,218 +1,218 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include "uberblit_v210.h" - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_32F_To_V210::Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const float *srcR = (const float *)mpSrcR->GetRow(y, mSrcIndexR); - const float *srcG = (const float *)mpSrcG->GetRow(y, mSrcIndexG); - const float *srcB = (const float *)mpSrcB->GetRow(y, mSrcIndexB); - - VDCPUCleanupExtensions(); - - int w6 = mWidth / 6; - for(sint32 i=0; i 1.0f) r0 = 1.0f; - if (r1 < 0.0f) r1 = 0.0f; else if (r1 > 1.0f) r1 = 1.0f; - if (r2 < 0.0f) r2 = 0.0f; else if (r2 > 1.0f) r2 = 1.0f; - if (g0 < 0.0f) g0 = 0.0f; else if (g0 > 1.0f) g0 = 1.0f; - if (g1 < 0.0f) g1 = 0.0f; else if (g1 > 1.0f) g1 = 1.0f; - if (g2 < 0.0f) g2 = 0.0f; else if (g2 > 1.0f) g2 = 1.0f; - if (g3 < 0.0f) g3 = 0.0f; else if (g3 > 1.0f) g3 = 1.0f; - if (g4 < 0.0f) g4 = 0.0f; else if (g4 > 1.0f) g4 = 1.0f; - if (g5 < 0.0f) g5 = 0.0f; else if (g5 > 1.0f) g5 = 1.0f; - if (b0 < 0.0f) b0 = 0.0f; else if (b0 > 1.0f) b0 = 1.0f; - if (b1 < 0.0f) b1 = 0.0f; else if (b1 > 1.0f) b1 = 1.0f; - if (b2 < 0.0f) b2 = 0.0f; else if (b2 > 1.0f) b2 = 1.0f; - - uint32 ir0 = (uint32)VDRoundToIntFast(r0 * 1024.0f); - uint32 ir1 = (uint32)VDRoundToIntFast(r1 * 1024.0f); - uint32 ir2 = (uint32)VDRoundToIntFast(r2 * 1024.0f); - uint32 ib0 = (uint32)VDRoundToIntFast(b0 * 1024.0f); - uint32 ib1 = (uint32)VDRoundToIntFast(b1 * 1024.0f); - uint32 ib2 = (uint32)VDRoundToIntFast(b2 * 1024.0f); - uint32 ig0 = (uint32)VDRoundToIntFast(g0 * 1024.0f); - uint32 ig1 = (uint32)VDRoundToIntFast(g1 * 1024.0f); - uint32 ig2 = (uint32)VDRoundToIntFast(g2 * 1024.0f); - uint32 ig3 = (uint32)VDRoundToIntFast(g3 * 1024.0f); - uint32 ig4 = (uint32)VDRoundToIntFast(g4 * 1024.0f); - uint32 ig5 = (uint32)VDRoundToIntFast(g5 * 1024.0f); - - // dword 0: XX Cr0 Y0 Cb0 - // dword 1: XX Y2 Cb1 Y1 - // dword 2: XX Cb2 Y3 Cr1 - // dword 3: XX Y5 Cr2 Y4 - dst[0] = (ir0 << 20) + (ig0 << 10) + ib0; - dst[1] = (ig2 << 20) + (ib1 << 10) + ig1; - dst[2] = (ib2 << 20) + (ig3 << 10) + ir1; - dst[3] = (ig5 << 20) + (ir2 << 10) + ig4; - - dst += 4; - } - - int leftovers = mWidth - w6*6; - if (leftovers) { - float g0 = 0; - float g1 = 0; - float g2 = 0; - float g3 = 0; - float g4 = 0; - float r0 = 0; - float r1 = 0; - float r2 = 0; - float b0 = 0; - float b1 = 0; - float b2 = 0; - - switch(leftovers) { - case 5: r2 = srcR[2]; - b2 = srcB[2]; - g4 = srcG[4]; - case 4: g3 = srcG[3]; - case 3: r1 = srcR[1]; - b1 = srcB[1]; - g2 = srcG[2]; - case 2: g1 = srcG[1]; - case 1: r0 = srcR[0]; - b0 = srcB[0]; - g0 = srcG[0]; - } - - if (r0 < 0.0f) r0 = 0.0f; else if (r0 > 1.0f) r0 = 1.0f; - if (r1 < 0.0f) r1 = 0.0f; else if (r1 > 1.0f) r1 = 1.0f; - if (r2 < 0.0f) r2 = 0.0f; else if (r2 > 1.0f) r2 = 1.0f; - if (g0 < 0.0f) g0 = 0.0f; else if (g0 > 1.0f) g0 = 1.0f; - if (g1 < 0.0f) g1 = 0.0f; else if (g1 > 1.0f) g1 = 1.0f; - if (g2 < 0.0f) g2 = 0.0f; else if (g2 > 1.0f) g2 = 1.0f; - if (g3 < 0.0f) g3 = 0.0f; else if (g3 > 1.0f) g3 = 1.0f; - if (g4 < 0.0f) g4 = 0.0f; else if (g4 > 1.0f) g4 = 1.0f; - if (b0 < 0.0f) b0 = 0.0f; else if (b0 > 1.0f) b0 = 1.0f; - if (b1 < 0.0f) b1 = 0.0f; else if (b1 > 1.0f) b1 = 1.0f; - if (b2 < 0.0f) b2 = 0.0f; else if (b2 > 1.0f) b2 = 1.0f; - - uint32 ir0 = (uint32)VDRoundToIntFast(r0 * 1024.0f); - uint32 ir1 = (uint32)VDRoundToIntFast(r1 * 1024.0f); - uint32 ir2 = (uint32)VDRoundToIntFast(r2 * 1024.0f); - uint32 ib0 = (uint32)VDRoundToIntFast(b0 * 1024.0f); - uint32 ib1 = (uint32)VDRoundToIntFast(b1 * 1024.0f); - uint32 ib2 = (uint32)VDRoundToIntFast(b2 * 1024.0f); - uint32 ig0 = (uint32)VDRoundToIntFast(g0 * 1024.0f); - uint32 ig1 = (uint32)VDRoundToIntFast(g1 * 1024.0f); - uint32 ig2 = (uint32)VDRoundToIntFast(g2 * 1024.0f); - uint32 ig3 = (uint32)VDRoundToIntFast(g3 * 1024.0f); - uint32 ig4 = (uint32)VDRoundToIntFast(g4 * 1024.0f); - - // dword 0: XX Cr0 Y0 Cb0 - // dword 1: XX Y2 Cb1 Y1 - // dword 2: XX Cb2 Y3 Cr1 - // dword 3: XX Y5 Cr2 Y4 - dst[0] = (ir0 << 20) + (ig0 << 10) + ib0; - dst[1] = (ig2 << 20) + (ib1 << 10) + ig1; - dst[2] = (ib2 << 20) + (ig3 << 10) + ir1; - dst[3] = (ir2 << 10) + ig4; - dst += 4; - } - - // QuickTime defines the v210 format and requires zero padding in all unused samples. - int w48up = (mWidth + 23) / 24; - int w6up = (mWidth + 5) / 6; - int zeropad = w48up * 16 - w6up * 4; - memset(dst, 0, zeropad * 4); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_V210_To_32F::Start() { - StartWindow(((mWidth + 5) / 6) * 6 * sizeof(float), 3); -} - -const void *VDPixmapGen_V210_To_32F::GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; -} - -sint32 VDPixmapGen_V210_To_32F::GetWidth(int index) const { - return index == 1 ? mWidth : (mWidth + 1) >> 1; -} - -uint32 VDPixmapGen_V210_To_32F::GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; -} - -void VDPixmapGen_V210_To_32F::Compute(void *dst0, sint32 y) { - float *dstR = (float *)dst0; - float *dstG = (float *)((char *)dstR + mWindowPitch); - float *dstB = (float *)((char *)dstG + mWindowPitch); - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - uint32 w = (mWidth + 5) / 6; - - VDCPUCleanupExtensions(); - - // dword 0: XX Cr0 Y0 Cb0 - // dword 1: XX Y2 Cb1 Y1 - // dword 2: XX Cb2 Y3 Cr1 - // dword 3: XX Y5 Cr2 Y4 - - for(uint32 i=0; i> 10) & 0x3ff) / 1023.0f; - dstR[0] = (float)((w0 >> 20) & 0x3ff) / 1023.0f; - dstG[1] = (float)( w1 & 0x3ff) / 1023.0f; - dstB[1] = (float)((w1 >> 10) & 0x3ff) / 1023.0f; - dstG[2] = (float)((w1 >> 20) & 0x3ff) / 1023.0f; - dstR[1] = (float)( w2 & 0x3ff) / 1023.0f; - dstG[3] = (float)((w2 >> 10) & 0x3ff) / 1023.0f; - dstB[2] = (float)((w2 >> 20) & 0x3ff) / 1023.0f; - dstG[4] = (float)( w3 & 0x3ff) / 1023.0f; - dstR[2] = (float)((w3 >> 10) & 0x3ff) / 1023.0f; - dstG[5] = (float)((w3 >> 20) & 0x3ff) / 1023.0f; - - dstR += 3; - dstG += 6; - dstB += 3; - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include "uberblit_v210.h" + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_32F_To_V210::Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const float *srcR = (const float *)mpSrcR->GetRow(y, mSrcIndexR); + const float *srcG = (const float *)mpSrcG->GetRow(y, mSrcIndexG); + const float *srcB = (const float *)mpSrcB->GetRow(y, mSrcIndexB); + + VDCPUCleanupExtensions(); + + int w6 = mWidth / 6; + for(sint32 i=0; i 1.0f) r0 = 1.0f; + if (r1 < 0.0f) r1 = 0.0f; else if (r1 > 1.0f) r1 = 1.0f; + if (r2 < 0.0f) r2 = 0.0f; else if (r2 > 1.0f) r2 = 1.0f; + if (g0 < 0.0f) g0 = 0.0f; else if (g0 > 1.0f) g0 = 1.0f; + if (g1 < 0.0f) g1 = 0.0f; else if (g1 > 1.0f) g1 = 1.0f; + if (g2 < 0.0f) g2 = 0.0f; else if (g2 > 1.0f) g2 = 1.0f; + if (g3 < 0.0f) g3 = 0.0f; else if (g3 > 1.0f) g3 = 1.0f; + if (g4 < 0.0f) g4 = 0.0f; else if (g4 > 1.0f) g4 = 1.0f; + if (g5 < 0.0f) g5 = 0.0f; else if (g5 > 1.0f) g5 = 1.0f; + if (b0 < 0.0f) b0 = 0.0f; else if (b0 > 1.0f) b0 = 1.0f; + if (b1 < 0.0f) b1 = 0.0f; else if (b1 > 1.0f) b1 = 1.0f; + if (b2 < 0.0f) b2 = 0.0f; else if (b2 > 1.0f) b2 = 1.0f; + + uint32 ir0 = (uint32)VDRoundToIntFast(r0 * 1024.0f); + uint32 ir1 = (uint32)VDRoundToIntFast(r1 * 1024.0f); + uint32 ir2 = (uint32)VDRoundToIntFast(r2 * 1024.0f); + uint32 ib0 = (uint32)VDRoundToIntFast(b0 * 1024.0f); + uint32 ib1 = (uint32)VDRoundToIntFast(b1 * 1024.0f); + uint32 ib2 = (uint32)VDRoundToIntFast(b2 * 1024.0f); + uint32 ig0 = (uint32)VDRoundToIntFast(g0 * 1024.0f); + uint32 ig1 = (uint32)VDRoundToIntFast(g1 * 1024.0f); + uint32 ig2 = (uint32)VDRoundToIntFast(g2 * 1024.0f); + uint32 ig3 = (uint32)VDRoundToIntFast(g3 * 1024.0f); + uint32 ig4 = (uint32)VDRoundToIntFast(g4 * 1024.0f); + uint32 ig5 = (uint32)VDRoundToIntFast(g5 * 1024.0f); + + // dword 0: XX Cr0 Y0 Cb0 + // dword 1: XX Y2 Cb1 Y1 + // dword 2: XX Cb2 Y3 Cr1 + // dword 3: XX Y5 Cr2 Y4 + dst[0] = (ir0 << 20) + (ig0 << 10) + ib0; + dst[1] = (ig2 << 20) + (ib1 << 10) + ig1; + dst[2] = (ib2 << 20) + (ig3 << 10) + ir1; + dst[3] = (ig5 << 20) + (ir2 << 10) + ig4; + + dst += 4; + } + + int leftovers = mWidth - w6*6; + if (leftovers) { + float g0 = 0; + float g1 = 0; + float g2 = 0; + float g3 = 0; + float g4 = 0; + float r0 = 0; + float r1 = 0; + float r2 = 0; + float b0 = 0; + float b1 = 0; + float b2 = 0; + + switch(leftovers) { + case 5: r2 = srcR[2]; + b2 = srcB[2]; + g4 = srcG[4]; + case 4: g3 = srcG[3]; + case 3: r1 = srcR[1]; + b1 = srcB[1]; + g2 = srcG[2]; + case 2: g1 = srcG[1]; + case 1: r0 = srcR[0]; + b0 = srcB[0]; + g0 = srcG[0]; + } + + if (r0 < 0.0f) r0 = 0.0f; else if (r0 > 1.0f) r0 = 1.0f; + if (r1 < 0.0f) r1 = 0.0f; else if (r1 > 1.0f) r1 = 1.0f; + if (r2 < 0.0f) r2 = 0.0f; else if (r2 > 1.0f) r2 = 1.0f; + if (g0 < 0.0f) g0 = 0.0f; else if (g0 > 1.0f) g0 = 1.0f; + if (g1 < 0.0f) g1 = 0.0f; else if (g1 > 1.0f) g1 = 1.0f; + if (g2 < 0.0f) g2 = 0.0f; else if (g2 > 1.0f) g2 = 1.0f; + if (g3 < 0.0f) g3 = 0.0f; else if (g3 > 1.0f) g3 = 1.0f; + if (g4 < 0.0f) g4 = 0.0f; else if (g4 > 1.0f) g4 = 1.0f; + if (b0 < 0.0f) b0 = 0.0f; else if (b0 > 1.0f) b0 = 1.0f; + if (b1 < 0.0f) b1 = 0.0f; else if (b1 > 1.0f) b1 = 1.0f; + if (b2 < 0.0f) b2 = 0.0f; else if (b2 > 1.0f) b2 = 1.0f; + + uint32 ir0 = (uint32)VDRoundToIntFast(r0 * 1024.0f); + uint32 ir1 = (uint32)VDRoundToIntFast(r1 * 1024.0f); + uint32 ir2 = (uint32)VDRoundToIntFast(r2 * 1024.0f); + uint32 ib0 = (uint32)VDRoundToIntFast(b0 * 1024.0f); + uint32 ib1 = (uint32)VDRoundToIntFast(b1 * 1024.0f); + uint32 ib2 = (uint32)VDRoundToIntFast(b2 * 1024.0f); + uint32 ig0 = (uint32)VDRoundToIntFast(g0 * 1024.0f); + uint32 ig1 = (uint32)VDRoundToIntFast(g1 * 1024.0f); + uint32 ig2 = (uint32)VDRoundToIntFast(g2 * 1024.0f); + uint32 ig3 = (uint32)VDRoundToIntFast(g3 * 1024.0f); + uint32 ig4 = (uint32)VDRoundToIntFast(g4 * 1024.0f); + + // dword 0: XX Cr0 Y0 Cb0 + // dword 1: XX Y2 Cb1 Y1 + // dword 2: XX Cb2 Y3 Cr1 + // dword 3: XX Y5 Cr2 Y4 + dst[0] = (ir0 << 20) + (ig0 << 10) + ib0; + dst[1] = (ig2 << 20) + (ib1 << 10) + ig1; + dst[2] = (ib2 << 20) + (ig3 << 10) + ir1; + dst[3] = (ir2 << 10) + ig4; + dst += 4; + } + + // QuickTime defines the v210 format and requires zero padding in all unused samples. + int w48up = (mWidth + 23) / 24; + int w6up = (mWidth + 5) / 6; + int zeropad = w48up * 16 - w6up * 4; + memset(dst, 0, zeropad * 4); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_V210_To_32F::Start() { + StartWindow(((mWidth + 5) / 6) * 6 * sizeof(float), 3); +} + +const void *VDPixmapGen_V210_To_32F::GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; +} + +sint32 VDPixmapGen_V210_To_32F::GetWidth(int index) const { + return index == 1 ? mWidth : (mWidth + 1) >> 1; +} + +uint32 VDPixmapGen_V210_To_32F::GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; +} + +void VDPixmapGen_V210_To_32F::Compute(void *dst0, sint32 y) { + float *dstR = (float *)dst0; + float *dstG = (float *)((char *)dstR + mWindowPitch); + float *dstB = (float *)((char *)dstG + mWindowPitch); + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + uint32 w = (mWidth + 5) / 6; + + VDCPUCleanupExtensions(); + + // dword 0: XX Cr0 Y0 Cb0 + // dword 1: XX Y2 Cb1 Y1 + // dword 2: XX Cb2 Y3 Cr1 + // dword 3: XX Y5 Cr2 Y4 + + for(uint32 i=0; i> 10) & 0x3ff) / 1023.0f; + dstR[0] = (float)((w0 >> 20) & 0x3ff) / 1023.0f; + dstG[1] = (float)( w1 & 0x3ff) / 1023.0f; + dstB[1] = (float)((w1 >> 10) & 0x3ff) / 1023.0f; + dstG[2] = (float)((w1 >> 20) & 0x3ff) / 1023.0f; + dstR[1] = (float)( w2 & 0x3ff) / 1023.0f; + dstG[3] = (float)((w2 >> 10) & 0x3ff) / 1023.0f; + dstB[2] = (float)((w2 >> 20) & 0x3ff) / 1023.0f; + dstG[4] = (float)( w3 & 0x3ff) / 1023.0f; + dstR[2] = (float)((w3 >> 10) & 0x3ff) / 1023.0f; + dstG[5] = (float)((w3 >> 20) & 0x3ff) / 1023.0f; + + dstR += 3; + dstG += 6; + dstB += 3; + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_ycbcr_generic.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_ycbcr_generic.cpp index 3820c7254c0..b60a6452e36 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_ycbcr_generic.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_ycbcr_generic.cpp @@ -1,545 +1,545 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include "uberblit_ycbcr_generic.h" - -extern const VDPixmapGenYCbCrBasis g_VDPixmapGenYCbCrBasis_601 = { - 0.299f, - 0.114f, - { - 0.0f, -0.3441363f, 1.772f, - 1.402f, -0.7141363f, 0.0f, - } -}; - -extern const VDPixmapGenYCbCrBasis g_VDPixmapGenYCbCrBasis_709 = { - 0.2126f, - 0.0722f, - { - 0.0f, -0.1873243f, 1.8556f, - 1.5748f, -0.4681243f, 0.0f, - } -}; - -//////////////////////////////////////////////////////////////////////////// - -VDPixmapGenYCbCrToRGB32Generic::VDPixmapGenYCbCrToRGB32Generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB) { - float scale; - float bias; - - if (studioRGB) { - scale = 65536.0f * (219.0f / 255.0f); - bias = 65536.0f * (16.0f / 255.0f + 0.5f); - } else { - scale = 65536.0f; - bias = 32768.0f; - } - - float scale255 = scale * 255.0f; - - mCoY = VDRoundToInt32(scale); - mCoRCr = VDRoundToInt32(basis.mToRGB[1][0] * scale); - mCoGCr = VDRoundToInt32(basis.mToRGB[1][1] * scale); - mCoGCb = VDRoundToInt32(basis.mToRGB[0][1] * scale); - mCoBCb = VDRoundToInt32(basis.mToRGB[0][2] * scale); - mBiasR = VDRoundToInt32(bias) - 128*mCoRCr; - mBiasG = VDRoundToInt32(bias) - 128*(mCoGCr + mCoGCb); - mBiasB = VDRoundToInt32(bias) - 128*mCoBCb; -} - -uint32 VDPixmapGenYCbCrToRGB32Generic::GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; -} - -void VDPixmapGenYCbCrToRGB32Generic::Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - const sint32 coY = mCoY; - const sint32 coRCr = mCoRCr; - const sint32 coGCr = mCoGCr; - const sint32 coGCb = mCoGCb; - const sint32 coBCb = mCoBCb; - const sint32 biasR = mBiasR; - const sint32 biasG = mBiasG; - const sint32 biasB = mBiasB; - - const sint32 w = mWidth; - for(sint32 i=0; i> 31; - g &= ~g >> 31; - b &= ~b >> 31; - - // clip high - sint32 clipR = 0xffffff - r; - sint32 clipG = 0xffffff - g; - sint32 clipB = 0xffffff - b; - r |= clipR >> 31; - g |= clipG >> 31; - b |= clipB >> 31; - - dst[0] = (uint8)(b >> 16); - dst[1] = (uint8)(g >> 16); - dst[2] = (uint8)(r >> 16); - dst[3] = 0xff; - - dst += 4; - } -} - -//////////////////////////////////////////////////////////////////////////// - -VDPixmapGenYCbCrToRGB32FGeneric::VDPixmapGenYCbCrToRGB32FGeneric(const VDPixmapGenYCbCrBasis& basis) { - mCoRCr = basis.mToRGB[1][0]; - mCoGCr = basis.mToRGB[1][1]; - mCoGCb = basis.mToRGB[0][1]; - mCoBCb = basis.mToRGB[0][2]; -} - -uint32 VDPixmapGenYCbCrToRGB32FGeneric::GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; -} - -void VDPixmapGenYCbCrToRGB32FGeneric::Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - const float coRCr = mCoRCr; - const float coGCr = mCoGCr; - const float coGCb = mCoGCb; - const float coBCb = mCoBCb; - - for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | mColorSpace; -} - -void VDPixmapGenRGB32ToYCbCrGeneric::Compute(void *dst0, sint32 y) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - const sint32 coYR = mCoYR; - const sint32 coYG = mCoYG; - const sint32 coYB = mCoYB; - const sint32 coCbR = mCoCbR; - const sint32 coCbG = mCoCbG; - const sint32 coCbB = mCoCbB; - const sint32 coCrR = mCoCrR; - const sint32 coCrG = mCoCrG; - const sint32 coCrB = mCoCrB; - const sint32 coYA = mCoYA; - const sint32 coCbA = mCoCbA; - const sint32 coCrA = mCoCrA; - - const sint32 w = mWidth; - for(sint32 i=0; i> 31; - cr16 |= (0xffffff - cr16) >> 31; - - *dstCb++ = (uint8)(cb16 >> 16); - *dstY ++ = (uint8)( y16 >> 16); - *dstCr++ = (uint8)(cr16 >> 16); - } -} - -//////////////////////////////////////////////////////////////////////////// - -VDPixmapGenRGB32FToYCbCrGeneric::VDPixmapGenRGB32FToYCbCrGeneric(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace) - : mColorSpace(colorSpace) -{ - mCoYR = basis.mKr; - mCoYG = 1.0f - basis.mKr - basis.mKb; - mCoYB = basis.mKb; - - // Cb = 0.5 * (B-Y) / (1-Kb) - mCoCb = 0.5f / (1.0f - basis.mKb); - - // Cr = 0.5 * (R-Y) / (1-Kr) - mCoCr = 0.5f / (1.0f - basis.mKr); -} - -uint32 VDPixmapGenRGB32FToYCbCrGeneric::GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | mColorSpace; -} - -void VDPixmapGenRGB32FToYCbCrGeneric::Compute(void *dst0, sint32 y) { - float *dstCr = (float *)dst0; - float *dstY = dstCr + mWindowPitch; - float *dstCb = dstY + mWindowPitch; - - const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - const float coYR = mCoYR; - const float coYG = mCoYG; - const float coYB = mCoYB; - const float coCb = mCoCb; - const float coCr = mCoCr; - - const sint32 w = mWidth; - for(sint32 i=0; iStart(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth, 3); -} - -const void *VDPixmapGenYCbCrToYCbCrGeneric::GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; -} - -uint32 VDPixmapGenYCbCrToYCbCrGeneric::GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixSpace_Mask) | mColorSpace; -} - -void VDPixmapGenYCbCrToYCbCrGeneric::Compute(void *dst0, sint32 ypos) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcY = (const uint8 *)mpSrcY ->GetRow(ypos, mSrcIndexY ); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - const sint32 coYY = mCoYY; - const sint32 coYCb = mCoYCb; - const sint32 coYCr = mCoYCr; - const sint32 coYA = mCoYA; - const sint32 coCbCb = mCoCbCb; - const sint32 coCbCr = mCoCbCr; - const sint32 coCbA = mCoCbA; - const sint32 coCrCb = mCoCrCb; - const sint32 coCrCr = mCoCrCr; - const sint32 coCrA = mCoCrA; - - for(sint32 i=0; i> 31; - cb2 &= ~cb2 >> 31; - cr2 &= ~cr2 >> 31; - - y2 |= (0xffffff - y2) >> 31; - cb2 |= (0xffffff - cb2) >> 31; - cr2 |= (0xffffff - cr2) >> 31; - - *dstY++ = (uint8)(y2 >> 16); - *dstCb++ = (uint8)(cb2 >> 16); - *dstCr++ = (uint8)(cr2 >> 16); - } -} - -//////////////////////////////////////////////////////////////////////////// - -VDPixmapGenYCbCrToYCbCrGeneric_32F::VDPixmapGenYCbCrToYCbCrGeneric_32F(const VDPixmapGenYCbCrBasis& dstBasis, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& srcBasis, bool srcLimitedRange, uint32 colorSpace) - : mColorSpace(colorSpace) -{ - vdfloat3x3 dstToRGB; - dstToRGB.m[0] = vdfloat3c(1, 1, 1); - dstToRGB.m[1] = vdfloat3c(dstBasis.mToRGB[0]); - dstToRGB.m[2] = vdfloat3c(dstBasis.mToRGB[1]); - - if (dstLimitedRange) { - dstToRGB.m[0] *= (255.0f / 219.0f); - dstToRGB.m[1] *= (255.0f / 224.0f); - dstToRGB.m[2] *= (255.0f / 224.0f); - } - - vdfloat3x3 srcToRGB; - srcToRGB.m[0] = vdfloat3c(1, 1, 1); - srcToRGB.m[1] = vdfloat3c(srcBasis.mToRGB[0]); - srcToRGB.m[2] = vdfloat3c(srcBasis.mToRGB[1]); - - if (srcLimitedRange) { - srcToRGB.m[0] *= (255.0f / 219.0f); - srcToRGB.m[1] *= (255.0f / 224.0f); - srcToRGB.m[2] *= (255.0f / 224.0f); - } - - vdfloat3x3 xf(srcToRGB * ~dstToRGB); - - // We should get a transform that looks like this: - // - // |k 0 0| - // [y cb cr 1] |a c e| = [y' cb' cr] - // |b d f| - // |x y z| - - VDASSERT(fabsf(xf.m[0].v[1]) < 1e-5f); - VDASSERT(fabsf(xf.m[0].v[2]) < 1e-5f); - - mCoYY = xf.m[0].v[0]; - mCoYCb = xf.m[1].v[0]; - mCoYCr = xf.m[2].v[0]; - mCoCbCb = xf.m[1].v[1]; - mCoCbCr = xf.m[2].v[1]; - mCoCrCb = xf.m[1].v[2]; - mCoCrCr = xf.m[2].v[2]; - - vdfloat3c srcBias(0, 128.0f/255.0f, 128.0f/255.0f); - if (srcLimitedRange) - srcBias.set(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f); - - vdfloat3c dstBias(0, 128.0f/255.0f, 128.0f/255.0f); - if (dstLimitedRange) - dstBias.set(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f); - - vdfloat3 bias = -srcBias * xf + dstBias; - - mCoYA = bias.x; - mCoCbA = bias.y; - mCoCrA = bias.z; -} - -void VDPixmapGenYCbCrToYCbCrGeneric_32F::Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * sizeof(float), 3); -} - -const void *VDPixmapGenYCbCrToYCbCrGeneric_32F::GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; -} - -uint32 VDPixmapGenYCbCrToYCbCrGeneric_32F::GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixSpace_Mask) | mColorSpace; -} - -void VDPixmapGenYCbCrToYCbCrGeneric_32F::Compute(void *dst0, sint32 ypos) { - float *dstCr = (float *)dst0; - float *dstY = vdptroffset(dstCr, mWindowPitch); - float *dstCb = vdptroffset(dstY, mWindowPitch); - - const float *srcY = (const float *)mpSrcY ->GetRow(ypos, mSrcIndexY ); - const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - const float coYY = mCoYY; - const float coYCb = mCoYCb; - const float coYCr = mCoYCr; - const float coYA = mCoYA; - const float coCbCb = mCoCbCb; - const float coCbCr = mCoCbCr; - const float coCbA = mCoCbA; - const float coCrCb = mCoCrCb; - const float coCrCr = mCoCrCr; - const float coCrA = mCoCrA; - - for(sint32 i=0; i +#include +#include "uberblit_ycbcr_generic.h" + +extern const VDPixmapGenYCbCrBasis g_VDPixmapGenYCbCrBasis_601 = { + 0.299f, + 0.114f, + { + 0.0f, -0.3441363f, 1.772f, + 1.402f, -0.7141363f, 0.0f, + } +}; + +extern const VDPixmapGenYCbCrBasis g_VDPixmapGenYCbCrBasis_709 = { + 0.2126f, + 0.0722f, + { + 0.0f, -0.1873243f, 1.8556f, + 1.5748f, -0.4681243f, 0.0f, + } +}; + +//////////////////////////////////////////////////////////////////////////// + +VDPixmapGenYCbCrToRGB32Generic::VDPixmapGenYCbCrToRGB32Generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB) { + float scale; + float bias; + + if (studioRGB) { + scale = 65536.0f * (219.0f / 255.0f); + bias = 65536.0f * (16.0f / 255.0f + 0.5f); + } else { + scale = 65536.0f; + bias = 32768.0f; + } + + float scale255 = scale * 255.0f; + + mCoY = VDRoundToInt32(scale); + mCoRCr = VDRoundToInt32(basis.mToRGB[1][0] * scale); + mCoGCr = VDRoundToInt32(basis.mToRGB[1][1] * scale); + mCoGCb = VDRoundToInt32(basis.mToRGB[0][1] * scale); + mCoBCb = VDRoundToInt32(basis.mToRGB[0][2] * scale); + mBiasR = VDRoundToInt32(bias) - 128*mCoRCr; + mBiasG = VDRoundToInt32(bias) - 128*(mCoGCr + mCoGCb); + mBiasB = VDRoundToInt32(bias) - 128*mCoBCb; +} + +uint32 VDPixmapGenYCbCrToRGB32Generic::GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; +} + +void VDPixmapGenYCbCrToRGB32Generic::Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + const sint32 coY = mCoY; + const sint32 coRCr = mCoRCr; + const sint32 coGCr = mCoGCr; + const sint32 coGCb = mCoGCb; + const sint32 coBCb = mCoBCb; + const sint32 biasR = mBiasR; + const sint32 biasG = mBiasG; + const sint32 biasB = mBiasB; + + const sint32 w = mWidth; + for(sint32 i=0; i> 31; + g &= ~g >> 31; + b &= ~b >> 31; + + // clip high + sint32 clipR = 0xffffff - r; + sint32 clipG = 0xffffff - g; + sint32 clipB = 0xffffff - b; + r |= clipR >> 31; + g |= clipG >> 31; + b |= clipB >> 31; + + dst[0] = (uint8)(b >> 16); + dst[1] = (uint8)(g >> 16); + dst[2] = (uint8)(r >> 16); + dst[3] = 0xff; + + dst += 4; + } +} + +//////////////////////////////////////////////////////////////////////////// + +VDPixmapGenYCbCrToRGB32FGeneric::VDPixmapGenYCbCrToRGB32FGeneric(const VDPixmapGenYCbCrBasis& basis) { + mCoRCr = basis.mToRGB[1][0]; + mCoGCr = basis.mToRGB[1][1]; + mCoGCb = basis.mToRGB[0][1]; + mCoBCb = basis.mToRGB[0][2]; +} + +uint32 VDPixmapGenYCbCrToRGB32FGeneric::GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; +} + +void VDPixmapGenYCbCrToRGB32FGeneric::Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + const float coRCr = mCoRCr; + const float coGCr = mCoGCr; + const float coGCb = mCoGCb; + const float coBCb = mCoBCb; + + for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | mColorSpace; +} + +void VDPixmapGenRGB32ToYCbCrGeneric::Compute(void *dst0, sint32 y) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + const sint32 coYR = mCoYR; + const sint32 coYG = mCoYG; + const sint32 coYB = mCoYB; + const sint32 coCbR = mCoCbR; + const sint32 coCbG = mCoCbG; + const sint32 coCbB = mCoCbB; + const sint32 coCrR = mCoCrR; + const sint32 coCrG = mCoCrG; + const sint32 coCrB = mCoCrB; + const sint32 coYA = mCoYA; + const sint32 coCbA = mCoCbA; + const sint32 coCrA = mCoCrA; + + const sint32 w = mWidth; + for(sint32 i=0; i> 31; + cr16 |= (0xffffff - cr16) >> 31; + + *dstCb++ = (uint8)(cb16 >> 16); + *dstY ++ = (uint8)( y16 >> 16); + *dstCr++ = (uint8)(cr16 >> 16); + } +} + +//////////////////////////////////////////////////////////////////////////// + +VDPixmapGenRGB32FToYCbCrGeneric::VDPixmapGenRGB32FToYCbCrGeneric(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace) + : mColorSpace(colorSpace) +{ + mCoYR = basis.mKr; + mCoYG = 1.0f - basis.mKr - basis.mKb; + mCoYB = basis.mKb; + + // Cb = 0.5 * (B-Y) / (1-Kb) + mCoCb = 0.5f / (1.0f - basis.mKb); + + // Cr = 0.5 * (R-Y) / (1-Kr) + mCoCr = 0.5f / (1.0f - basis.mKr); +} + +uint32 VDPixmapGenRGB32FToYCbCrGeneric::GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | mColorSpace; +} + +void VDPixmapGenRGB32FToYCbCrGeneric::Compute(void *dst0, sint32 y) { + float *dstCr = (float *)dst0; + float *dstY = dstCr + mWindowPitch; + float *dstCb = dstY + mWindowPitch; + + const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + const float coYR = mCoYR; + const float coYG = mCoYG; + const float coYB = mCoYB; + const float coCb = mCoCb; + const float coCr = mCoCr; + + const sint32 w = mWidth; + for(sint32 i=0; iStart(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth, 3); +} + +const void *VDPixmapGenYCbCrToYCbCrGeneric::GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; +} + +uint32 VDPixmapGenYCbCrToYCbCrGeneric::GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixSpace_Mask) | mColorSpace; +} + +void VDPixmapGenYCbCrToYCbCrGeneric::Compute(void *dst0, sint32 ypos) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcY = (const uint8 *)mpSrcY ->GetRow(ypos, mSrcIndexY ); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + const sint32 coYY = mCoYY; + const sint32 coYCb = mCoYCb; + const sint32 coYCr = mCoYCr; + const sint32 coYA = mCoYA; + const sint32 coCbCb = mCoCbCb; + const sint32 coCbCr = mCoCbCr; + const sint32 coCbA = mCoCbA; + const sint32 coCrCb = mCoCrCb; + const sint32 coCrCr = mCoCrCr; + const sint32 coCrA = mCoCrA; + + for(sint32 i=0; i> 31; + cb2 &= ~cb2 >> 31; + cr2 &= ~cr2 >> 31; + + y2 |= (0xffffff - y2) >> 31; + cb2 |= (0xffffff - cb2) >> 31; + cr2 |= (0xffffff - cr2) >> 31; + + *dstY++ = (uint8)(y2 >> 16); + *dstCb++ = (uint8)(cb2 >> 16); + *dstCr++ = (uint8)(cr2 >> 16); + } +} + +//////////////////////////////////////////////////////////////////////////// + +VDPixmapGenYCbCrToYCbCrGeneric_32F::VDPixmapGenYCbCrToYCbCrGeneric_32F(const VDPixmapGenYCbCrBasis& dstBasis, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& srcBasis, bool srcLimitedRange, uint32 colorSpace) + : mColorSpace(colorSpace) +{ + vdfloat3x3 dstToRGB; + dstToRGB.m[0] = vdfloat3c(1, 1, 1); + dstToRGB.m[1] = vdfloat3c(dstBasis.mToRGB[0]); + dstToRGB.m[2] = vdfloat3c(dstBasis.mToRGB[1]); + + if (dstLimitedRange) { + dstToRGB.m[0] *= (255.0f / 219.0f); + dstToRGB.m[1] *= (255.0f / 224.0f); + dstToRGB.m[2] *= (255.0f / 224.0f); + } + + vdfloat3x3 srcToRGB; + srcToRGB.m[0] = vdfloat3c(1, 1, 1); + srcToRGB.m[1] = vdfloat3c(srcBasis.mToRGB[0]); + srcToRGB.m[2] = vdfloat3c(srcBasis.mToRGB[1]); + + if (srcLimitedRange) { + srcToRGB.m[0] *= (255.0f / 219.0f); + srcToRGB.m[1] *= (255.0f / 224.0f); + srcToRGB.m[2] *= (255.0f / 224.0f); + } + + vdfloat3x3 xf(srcToRGB * ~dstToRGB); + + // We should get a transform that looks like this: + // + // |k 0 0| + // [y cb cr 1] |a c e| = [y' cb' cr] + // |b d f| + // |x y z| + + VDASSERT(fabsf(xf.m[0].v[1]) < 1e-5f); + VDASSERT(fabsf(xf.m[0].v[2]) < 1e-5f); + + mCoYY = xf.m[0].v[0]; + mCoYCb = xf.m[1].v[0]; + mCoYCr = xf.m[2].v[0]; + mCoCbCb = xf.m[1].v[1]; + mCoCbCr = xf.m[2].v[1]; + mCoCrCb = xf.m[1].v[2]; + mCoCrCr = xf.m[2].v[2]; + + vdfloat3c srcBias(0, 128.0f/255.0f, 128.0f/255.0f); + if (srcLimitedRange) + srcBias.set(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f); + + vdfloat3c dstBias(0, 128.0f/255.0f, 128.0f/255.0f); + if (dstLimitedRange) + dstBias.set(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f); + + vdfloat3 bias = -srcBias * xf + dstBias; + + mCoYA = bias.x; + mCoCbA = bias.y; + mCoCrA = bias.z; +} + +void VDPixmapGenYCbCrToYCbCrGeneric_32F::Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * sizeof(float), 3); +} + +const void *VDPixmapGenYCbCrToYCbCrGeneric_32F::GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; +} + +uint32 VDPixmapGenYCbCrToYCbCrGeneric_32F::GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixSpace_Mask) | mColorSpace; +} + +void VDPixmapGenYCbCrToYCbCrGeneric_32F::Compute(void *dst0, sint32 ypos) { + float *dstCr = (float *)dst0; + float *dstY = vdptroffset(dstCr, mWindowPitch); + float *dstCb = vdptroffset(dstY, mWindowPitch); + + const float *srcY = (const float *)mpSrcY ->GetRow(ypos, mSrcIndexY ); + const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + const float coYY = mCoYY; + const float coYCb = mCoYCb; + const float coYCr = mCoYCr; + const float coYA = mCoYA; + const float coCbCb = mCoCbCb; + const float coCbCr = mCoCbCr; + const float coCbA = mCoCbA; + const float coCrCb = mCoCrCb; + const float coCrCr = mCoCrCr; + const float coCrA = mCoCrA; + + for(sint32 i=0; i -#include "uberblit_ycbcr_x86.h" - -extern "C" void vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2(void *dstY, void *dstCb, void *dstCr, const void *srcRGB, uint32 count, const void *coeffs); - -void VDPixmapGenRGB32ToYCbCr601_SSE2::Compute(void *dst0, sint32 y) { - uint8 *dstCb = (uint8 *)dst0; - uint8 *dstY = dstCb + mWindowPitch; - uint8 *dstCr = dstY + mWindowPitch; - const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - static const __declspec(align(16)) struct { - sint16 rb_to_y[8]; - sint16 rb_to_cb[8]; - sint16 rb_to_cr[8]; - sint16 g_to_y[8]; - sint16 g_to_cb[8]; - sint16 g_to_cr[8]; - sint32 y_bias[4]; - sint32 c_bias[4]; - } kCoeffs={ - // Cb = (28784*r - 24103*g - 4681*b + 8388608 + 32768) >> 16; - // Y = (16829*r + 33039*g + 6416*b + 1048576 + 32768) >> 16; - // Cr = (-9714*r - 19071*g + 28784*b + 8388608 + 32768) >> 16; - { 3208, 8414, 3208, 8414, 3208, 8414, 3208, 8414, }, // rb to y - { -2340, 14392, -2340, 14392, -2340, 14392, -2340, 14392, }, // rb to cb - { 16519, 0, 16519, 0, 16519, 0, 16519, 0, }, // g to y - { -12050, 0, -12050, 0, -12050, 0, -12050, 0, }, // g to cb - { 14392, -4857, 14392, -4857, 14392, -4857, 14392, -4857, }, // rb to cr - { -9535, 0, -9535, 0, -9535, 0, -9535, 0, }, // g to cr - { 0x084000, 0x084000, 0x084000, 0x084000, }, // y bias - { 0x404000, 0x404000, 0x404000, 0x404000, }, // c bias - }; - - vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2(dstY, dstCb, dstCr, srcRGB, mWidth, &kCoeffs); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "uberblit_ycbcr_x86.h" + +extern "C" void vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2(void *dstY, void *dstCb, void *dstCr, const void *srcRGB, uint32 count, const void *coeffs); + +void VDPixmapGenRGB32ToYCbCr601_SSE2::Compute(void *dst0, sint32 y) { + uint8 *dstCb = (uint8 *)dst0; + uint8 *dstY = dstCb + mWindowPitch; + uint8 *dstCr = dstY + mWindowPitch; + const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + static const __declspec(align(16)) struct { + sint16 rb_to_y[8]; + sint16 rb_to_cb[8]; + sint16 rb_to_cr[8]; + sint16 g_to_y[8]; + sint16 g_to_cb[8]; + sint16 g_to_cr[8]; + sint32 y_bias[4]; + sint32 c_bias[4]; + } kCoeffs={ + // Cb = (28784*r - 24103*g - 4681*b + 8388608 + 32768) >> 16; + // Y = (16829*r + 33039*g + 6416*b + 1048576 + 32768) >> 16; + // Cr = (-9714*r - 19071*g + 28784*b + 8388608 + 32768) >> 16; + { 3208, 8414, 3208, 8414, 3208, 8414, 3208, 8414, }, // rb to y + { -2340, 14392, -2340, 14392, -2340, 14392, -2340, 14392, }, // rb to cb + { 16519, 0, 16519, 0, 16519, 0, 16519, 0, }, // g to y + { -12050, 0, -12050, 0, -12050, 0, -12050, 0, }, // g to cb + { 14392, -4857, 14392, -4857, 14392, -4857, 14392, -4857, }, // rb to cr + { -9535, 0, -9535, 0, -9535, 0, -9535, 0, }, // g to cr + { 0x084000, 0x084000, 0x084000, 0x084000, }, // y bias + { 0x404000, 0x404000, 0x404000, 0x404000, }, // c bias + }; + + vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2(dstY, dstCb, dstCr, srcRGB, mWidth, &kCoeffs); +} diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/blitter.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/blitter.h index d930f0d6432..4ced35dc449 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/blitter.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/blitter.h @@ -1,39 +1,39 @@ -#ifndef f_VD2_KASUMI_BLITTER_H -#define f_VD2_KASUMI_BLITTER_H - -#include - -struct VDPixmap; -struct VDPixmapLayout; - -class IVDPixmapBlitter { -public: - virtual ~IVDPixmapBlitter() {} - virtual void Blit(const VDPixmap& dst, const VDPixmap& src) = 0; - virtual void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) = 0; -}; - -IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmap& dst, const VDPixmap& src); -IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmapLayout& dst, const VDPixmapLayout& src); - -class VDPixmapCachedBlitter { - VDPixmapCachedBlitter(const VDPixmapCachedBlitter&); - VDPixmapCachedBlitter& operator=(const VDPixmapCachedBlitter&); -public: - VDPixmapCachedBlitter(); - ~VDPixmapCachedBlitter(); - - void Blit(const VDPixmap& dst, const VDPixmap& src); - void Invalidate(); - -protected: - sint32 mSrcWidth; - sint32 mSrcHeight; - int mSrcFormat; - sint32 mDstWidth; - sint32 mDstHeight; - int mDstFormat; - IVDPixmapBlitter *mpCachedBlitter; -}; - -#endif +#ifndef f_VD2_KASUMI_BLITTER_H +#define f_VD2_KASUMI_BLITTER_H + +#include + +struct VDPixmap; +struct VDPixmapLayout; + +class IVDPixmapBlitter { +public: + virtual ~IVDPixmapBlitter() {} + virtual void Blit(const VDPixmap& dst, const VDPixmap& src) = 0; + virtual void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) = 0; +}; + +IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmap& dst, const VDPixmap& src); +IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmapLayout& dst, const VDPixmapLayout& src); + +class VDPixmapCachedBlitter { + VDPixmapCachedBlitter(const VDPixmapCachedBlitter&); + VDPixmapCachedBlitter& operator=(const VDPixmapCachedBlitter&); +public: + VDPixmapCachedBlitter(); + ~VDPixmapCachedBlitter(); + + void Blit(const VDPixmap& dst, const VDPixmap& src); + void Invalidate(); + +protected: + sint32 mSrcWidth; + sint32 mSrcHeight; + int mSrcFormat; + sint32 mDstWidth; + sint32 mDstHeight; + int mDstFormat; + IVDPixmapBlitter *mpCachedBlitter; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixel.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixel.h index 3c65ac1cced..149a7da91d5 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixel.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixel.h @@ -1,40 +1,40 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_PIXEL_H -#define f_VD2_KASUMI_PIXEL_H - -#ifndef f_VD2_SYSTEM_VDTYPES_H - #include -#endif - -struct VDPixmap; - -uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y); -uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x, sint32 y); - -inline uint8 VDPixmapSample8(const void *data, ptrdiff_t pitch, sint32 x, sint32 y) { - return ((const uint8 *)data)[pitch*y + x]; -} - -uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256); -uint32 VDConvertYCbCrToRGB(uint8 y, uint8 cb, uint8 cr, bool use709, bool useFullRange); -uint32 VDConvertRGBToYCbCr(uint32 c); -uint32 VDConvertRGBToYCbCr(uint8 r, uint8 g, uint8 b, bool use709, bool useFullRange); - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_PIXEL_H +#define f_VD2_KASUMI_PIXEL_H + +#ifndef f_VD2_SYSTEM_VDTYPES_H + #include +#endif + +struct VDPixmap; + +uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y); +uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x, sint32 y); + +inline uint8 VDPixmapSample8(const void *data, ptrdiff_t pitch, sint32 x, sint32 y) { + return ((const uint8 *)data)[pitch*y + x]; +} + +uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256); +uint32 VDConvertYCbCrToRGB(uint8 y, uint8 cb, uint8 cr, bool use709, bool useFullRange); +uint32 VDConvertRGBToYCbCr(uint32 c); +uint32 VDConvertRGBToYCbCr(uint8 r, uint8 g, uint8 b, bool use709, bool useFullRange); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmap.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmap.h index 33e36f67bf8..58c64d73d65 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmap.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmap.h @@ -1,109 +1,109 @@ -#ifndef f_VD2_KASUMI_PIXMAP_H -#define f_VD2_KASUMI_PIXMAP_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -namespace nsVDPixmap { - enum VDPixmapFormat { - kPixFormat_Null, - kPixFormat_Pal1, - kPixFormat_Pal2, - kPixFormat_Pal4, - kPixFormat_Pal8, - kPixFormat_XRGB1555, - kPixFormat_RGB565, - kPixFormat_RGB888, - kPixFormat_XRGB8888, - kPixFormat_Y8, - kPixFormat_YUV422_UYVY, - kPixFormat_YUV422_YUYV, - kPixFormat_YUV444_XVYU, // The reason for the strange VYU ordering is to make it easier to convert to UYVY/YUY2. - kPixFormat_YUV444_Planar, - kPixFormat_YUV422_Planar, - kPixFormat_YUV420_Planar, - kPixFormat_YUV411_Planar, - kPixFormat_YUV410_Planar, - kPixFormat_YUV422_Planar_Centered, // MPEG-1/MJPEG chroma alignment - kPixFormat_YUV420_Planar_Centered, // MPEG-1/MJPEG chroma alignment - kPixFormat_YUV422_Planar_16F, - kPixFormat_YUV422_V210, - kPixFormat_YUV422_UYVY_709, // Also known as HDYC. - kPixFormat_YUV420_NV12, - kPixFormat_Y8_FR, - kPixFormat_YUV422_YUYV_709, - kPixFormat_YUV444_Planar_709, - kPixFormat_YUV422_Planar_709, - kPixFormat_YUV420_Planar_709, - kPixFormat_YUV411_Planar_709, - kPixFormat_YUV410_Planar_709, - kPixFormat_YUV422_UYVY_FR, - kPixFormat_YUV422_YUYV_FR, - kPixFormat_YUV444_Planar_FR, - kPixFormat_YUV422_Planar_FR, - kPixFormat_YUV420_Planar_FR, - kPixFormat_YUV411_Planar_FR, - kPixFormat_YUV410_Planar_FR, - kPixFormat_YUV422_UYVY_709_FR, - kPixFormat_YUV422_YUYV_709_FR, - kPixFormat_YUV444_Planar_709_FR, - kPixFormat_YUV422_Planar_709_FR, - kPixFormat_YUV420_Planar_709_FR, - kPixFormat_YUV411_Planar_709_FR, - kPixFormat_YUV410_Planar_709_FR, - kPixFormat_YUV420i_Planar, - kPixFormat_YUV420i_Planar_FR, - kPixFormat_YUV420i_Planar_709, - kPixFormat_YUV420i_Planar_709_FR, - kPixFormat_YUV420it_Planar, - kPixFormat_YUV420it_Planar_FR, - kPixFormat_YUV420it_Planar_709, - kPixFormat_YUV420it_Planar_709_FR, - kPixFormat_YUV420ib_Planar, - kPixFormat_YUV420ib_Planar_FR, - kPixFormat_YUV420ib_Planar_709, - kPixFormat_YUV420ib_Planar_709_FR, - kPixFormat_Max_Standard - }; -} - -typedef sint32 vdpixpos; -typedef sint32 vdpixsize; -typedef ptrdiff_t vdpixoffset; - -struct VDPixmap { - void *data; - const uint32 *palette; - vdpixsize w; - vdpixsize h; - vdpixoffset pitch; - sint32 format; - - // Auxiliary planes are always byte-per-pixel. - - void *data2; // Cb (U) for YCbCr - vdpixoffset pitch2; - void *data3; // Cr (V) for YCbCr - vdpixoffset pitch3; -}; - -struct VDPixmapLayout { - ptrdiff_t data; - const uint32 *palette; - vdpixsize w; - vdpixsize h; - vdpixoffset pitch; - sint32 format; - - // Auxiliary planes are always byte-per-pixel. - - ptrdiff_t data2; // Cb (U) for YCbCr - vdpixoffset pitch2; - ptrdiff_t data3; // Cr (V) for YCbCr - vdpixoffset pitch3; -}; - -#endif +#ifndef f_VD2_KASUMI_PIXMAP_H +#define f_VD2_KASUMI_PIXMAP_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +namespace nsVDPixmap { + enum VDPixmapFormat { + kPixFormat_Null, + kPixFormat_Pal1, + kPixFormat_Pal2, + kPixFormat_Pal4, + kPixFormat_Pal8, + kPixFormat_XRGB1555, + kPixFormat_RGB565, + kPixFormat_RGB888, + kPixFormat_XRGB8888, + kPixFormat_Y8, + kPixFormat_YUV422_UYVY, + kPixFormat_YUV422_YUYV, + kPixFormat_YUV444_XVYU, // The reason for the strange VYU ordering is to make it easier to convert to UYVY/YUY2. + kPixFormat_YUV444_Planar, + kPixFormat_YUV422_Planar, + kPixFormat_YUV420_Planar, + kPixFormat_YUV411_Planar, + kPixFormat_YUV410_Planar, + kPixFormat_YUV422_Planar_Centered, // MPEG-1/MJPEG chroma alignment + kPixFormat_YUV420_Planar_Centered, // MPEG-1/MJPEG chroma alignment + kPixFormat_YUV422_Planar_16F, + kPixFormat_YUV422_V210, + kPixFormat_YUV422_UYVY_709, // Also known as HDYC. + kPixFormat_YUV420_NV12, + kPixFormat_Y8_FR, + kPixFormat_YUV422_YUYV_709, + kPixFormat_YUV444_Planar_709, + kPixFormat_YUV422_Planar_709, + kPixFormat_YUV420_Planar_709, + kPixFormat_YUV411_Planar_709, + kPixFormat_YUV410_Planar_709, + kPixFormat_YUV422_UYVY_FR, + kPixFormat_YUV422_YUYV_FR, + kPixFormat_YUV444_Planar_FR, + kPixFormat_YUV422_Planar_FR, + kPixFormat_YUV420_Planar_FR, + kPixFormat_YUV411_Planar_FR, + kPixFormat_YUV410_Planar_FR, + kPixFormat_YUV422_UYVY_709_FR, + kPixFormat_YUV422_YUYV_709_FR, + kPixFormat_YUV444_Planar_709_FR, + kPixFormat_YUV422_Planar_709_FR, + kPixFormat_YUV420_Planar_709_FR, + kPixFormat_YUV411_Planar_709_FR, + kPixFormat_YUV410_Planar_709_FR, + kPixFormat_YUV420i_Planar, + kPixFormat_YUV420i_Planar_FR, + kPixFormat_YUV420i_Planar_709, + kPixFormat_YUV420i_Planar_709_FR, + kPixFormat_YUV420it_Planar, + kPixFormat_YUV420it_Planar_FR, + kPixFormat_YUV420it_Planar_709, + kPixFormat_YUV420it_Planar_709_FR, + kPixFormat_YUV420ib_Planar, + kPixFormat_YUV420ib_Planar_FR, + kPixFormat_YUV420ib_Planar_709, + kPixFormat_YUV420ib_Planar_709_FR, + kPixFormat_Max_Standard + }; +} + +typedef sint32 vdpixpos; +typedef sint32 vdpixsize; +typedef ptrdiff_t vdpixoffset; + +struct VDPixmap { + void *data; + const uint32 *palette; + vdpixsize w; + vdpixsize h; + vdpixoffset pitch; + sint32 format; + + // Auxiliary planes are always byte-per-pixel. + + void *data2; // Cb (U) for YCbCr + vdpixoffset pitch2; + void *data3; // Cr (V) for YCbCr + vdpixoffset pitch3; +}; + +struct VDPixmapLayout { + ptrdiff_t data; + const uint32 *palette; + vdpixsize w; + vdpixsize h; + vdpixoffset pitch; + sint32 format; + + // Auxiliary planes are always byte-per-pixel. + + ptrdiff_t data2; // Cb (U) for YCbCr + vdpixoffset pitch2; + ptrdiff_t data3; // Cr (V) for YCbCr + vdpixoffset pitch3; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmapops.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmapops.h index 6dce3a858cc..150437052b2 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmapops.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmapops.h @@ -1,20 +1,20 @@ -#ifndef f_VD2_KASUMI_PIXMAPOPS_H -#define f_VD2_KASUMI_PIXMAPOPS_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -bool VDPixmapIsBltPossible(int dst_format, int src_format); -bool VDPixmapBlt(const VDPixmap& dst, const VDPixmap& src); -bool VDPixmapBlt(const VDPixmap& dst, vdpixpos x1, vdpixpos y1, const VDPixmap& src, vdpixpos x2, vdpixpos y2, vdpixsize w, vdpixsize h); -bool VDPixmapStretchBltNearest(const VDPixmap& dst, const VDPixmap& src); -bool VDPixmapStretchBltNearest(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); -bool VDPixmapStretchBltBilinear(const VDPixmap& dst, const VDPixmap& src); -bool VDPixmapStretchBltBilinear(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); - -bool VDPixmapBltAlphaConst(const VDPixmap& dst, const VDPixmap& src, float alpha); - -#endif +#ifndef f_VD2_KASUMI_PIXMAPOPS_H +#define f_VD2_KASUMI_PIXMAPOPS_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +bool VDPixmapIsBltPossible(int dst_format, int src_format); +bool VDPixmapBlt(const VDPixmap& dst, const VDPixmap& src); +bool VDPixmapBlt(const VDPixmap& dst, vdpixpos x1, vdpixpos y1, const VDPixmap& src, vdpixpos x2, vdpixpos y2, vdpixsize w, vdpixsize h); +bool VDPixmapStretchBltNearest(const VDPixmap& dst, const VDPixmap& src); +bool VDPixmapStretchBltNearest(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); +bool VDPixmapStretchBltBilinear(const VDPixmap& dst, const VDPixmap& src); +bool VDPixmapStretchBltBilinear(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); + +bool VDPixmapBltAlphaConst(const VDPixmap& dst, const VDPixmap& src, float alpha); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmaputils.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmaputils.h index c572b52ae53..9eb04706241 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmaputils.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmaputils.h @@ -1,171 +1,171 @@ -#ifndef f_VD2_KASUMI_PIXMAPUTILS_H -#define f_VD2_KASUMI_PIXMAPUTILS_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -struct VDPixmapFormatInfo { - const char *name; // debugging name - bool qchunky; // quantums are chunky (not 1x1 pixels) - int qw, qh; // width, height of a quantum - int qwbits, qhbits; // width and height of a quantum as shifts - int qsize; // size of a pixel in bytes - int auxbufs; // number of auxiliary buffers (0 for chunky formats, usually 2 for planar) - int auxwbits, auxhbits; // subsampling factors for auxiliary buffers in shifts - int auxsize; // size of an aux sample in bytes - int palsize; // entries in palette - int subformats; // number of subformats for this format -}; - -extern const VDPixmapFormatInfo g_vdPixmapFormats[]; - -inline const VDPixmapFormatInfo& VDPixmapGetInfo(sint32 format) { - VDASSERT((uint32)format < nsVDPixmap::kPixFormat_Max_Standard); - return g_vdPixmapFormats[(uint32)format < nsVDPixmap::kPixFormat_Max_Standard ? format : 0]; -} - -#ifdef _DEBUG - bool VDAssertValidPixmap(const VDPixmap& px); -#else - inline bool VDAssertValidPixmap(const VDPixmap& px) { return true; } -#endif - -inline VDPixmap VDPixmapFromLayout(const VDPixmapLayout& layout, void *p) { - VDPixmap px; - - px.data = (char *)p + layout.data; - px.data2 = (char *)p + layout.data2; - px.data3 = (char *)p + layout.data3; - px.format = layout.format; - px.w = layout.w; - px.h = layout.h; - px.palette = layout.palette; - px.pitch = layout.pitch; - px.pitch2 = layout.pitch2; - px.pitch3 = layout.pitch3; - - return px; -} - -inline VDPixmapLayout VDPixmapToLayoutFromBase(const VDPixmap& px, void *p) { - VDPixmapLayout layout; - layout.data = (char *)px.data - (char *)p; - layout.data2 = (char *)px.data2 - (char *)p; - layout.data3 = (char *)px.data3 - (char *)p; - layout.format = px.format; - layout.w = px.w; - layout.h = px.h; - layout.palette = px.palette; - layout.pitch = px.pitch; - layout.pitch2 = px.pitch2; - layout.pitch3 = px.pitch3; - return layout; -} - -inline VDPixmapLayout VDPixmapToLayout(const VDPixmap& px, void *&p) { - VDPixmapLayout layout; - p = px.data; - layout.data = 0; - layout.data2 = (char *)px.data2 - (char *)px.data; - layout.data3 = (char *)px.data3 - (char *)px.data; - layout.format = px.format; - layout.w = px.w; - layout.h = px.h; - layout.palette = px.palette; - layout.pitch = px.pitch; - layout.pitch2 = px.pitch2; - layout.pitch3 = px.pitch3; - return layout; -} - -uint32 VDPixmapCreateLinearLayout(VDPixmapLayout& layout, int format, vdpixsize w, vdpixsize h, int alignment); - -VDPixmap VDPixmapOffset(const VDPixmap& src, vdpixpos x, vdpixpos y); -VDPixmapLayout VDPixmapLayoutOffset(const VDPixmapLayout& src, vdpixpos x, vdpixpos y); - -void VDPixmapFlipV(VDPixmap& layout); -void VDPixmapLayoutFlipV(VDPixmapLayout& layout); - -uint32 VDPixmapLayoutGetMinSize(const VDPixmapLayout& layout); - -VDPixmap VDPixmapExtractField(const VDPixmap& src, bool field2); - -#ifndef VDPTRSTEP_DECLARED - template - inline void vdptrstep(T *&p, ptrdiff_t offset) { - p = (T *)((char *)p + offset); - } -#endif -#ifndef VDPTROFFSET_DECLARED - template - inline T *vdptroffset(T *p, ptrdiff_t offset) { - return (T *)((char *)p + offset); - } -#endif -#ifndef VDPTRDIFFABS_DECLARED - inline ptrdiff_t vdptrdiffabs(ptrdiff_t x) { - return x<0 ? -x : x; - } -#endif - - -typedef void (*VDPixmapBlitterFn)(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -typedef VDPixmapBlitterFn (*tpVDPixBltTable)[nsVDPixmap::kPixFormat_Max_Standard]; - -tpVDPixBltTable VDGetPixBltTableReference(); -tpVDPixBltTable VDGetPixBltTableX86Scalar(); -tpVDPixBltTable VDGetPixBltTableX86MMX(); - - - -class VDPixmapBuffer : public VDPixmap { -public: - VDPixmapBuffer() : mpBuffer(NULL), mLinearSize(0) { data = NULL; format = 0; } - explicit VDPixmapBuffer(const VDPixmap& src); - VDPixmapBuffer(const VDPixmapBuffer& src); - VDPixmapBuffer(sint32 w, sint32 h, int format) : mpBuffer(NULL), mLinearSize(0) { - init(w, h, format); - } - explicit VDPixmapBuffer(const VDPixmapLayout& layout); - - ~VDPixmapBuffer(); - - void clear() { - if (mpBuffer) // to reduce debug checks - delete[] mpBuffer; - mpBuffer = NULL; - mLinearSize = 0; - format = nsVDPixmap::kPixFormat_Null; - } - -#ifdef _DEBUG - void *base() { return mpBuffer + (-(int)(uintptr)mpBuffer & 15) + 16; } - const void *base() const { return mpBuffer + (-(int)(uintptr)mpBuffer & 15) + 16; } - size_t size() const { return mLinearSize - 28; } - - void validate(); -#else - void *base() { return mpBuffer + (-(int)(uintptr)mpBuffer & 15); } - const void *base() const { return mpBuffer + (-(int)(uintptr)mpBuffer & 15); } - size_t size() const { return mLinearSize; } - - void validate() {} -#endif - - void init(sint32 w, sint32 h, int format); - void init(const VDPixmapLayout&, uint32 additionalPadding = 0); - - void assign(const VDPixmap& src); - - void swap(VDPixmapBuffer&); - -protected: - char *mpBuffer; - size_t mLinearSize; -}; - - -#endif +#ifndef f_VD2_KASUMI_PIXMAPUTILS_H +#define f_VD2_KASUMI_PIXMAPUTILS_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +struct VDPixmapFormatInfo { + const char *name; // debugging name + bool qchunky; // quantums are chunky (not 1x1 pixels) + int qw, qh; // width, height of a quantum + int qwbits, qhbits; // width and height of a quantum as shifts + int qsize; // size of a pixel in bytes + int auxbufs; // number of auxiliary buffers (0 for chunky formats, usually 2 for planar) + int auxwbits, auxhbits; // subsampling factors for auxiliary buffers in shifts + int auxsize; // size of an aux sample in bytes + int palsize; // entries in palette + int subformats; // number of subformats for this format +}; + +extern const VDPixmapFormatInfo g_vdPixmapFormats[]; + +inline const VDPixmapFormatInfo& VDPixmapGetInfo(sint32 format) { + VDASSERT((uint32)format < nsVDPixmap::kPixFormat_Max_Standard); + return g_vdPixmapFormats[(uint32)format < nsVDPixmap::kPixFormat_Max_Standard ? format : 0]; +} + +#ifdef _DEBUG + bool VDAssertValidPixmap(const VDPixmap& px); +#else + inline bool VDAssertValidPixmap(const VDPixmap& px) { return true; } +#endif + +inline VDPixmap VDPixmapFromLayout(const VDPixmapLayout& layout, void *p) { + VDPixmap px; + + px.data = (char *)p + layout.data; + px.data2 = (char *)p + layout.data2; + px.data3 = (char *)p + layout.data3; + px.format = layout.format; + px.w = layout.w; + px.h = layout.h; + px.palette = layout.palette; + px.pitch = layout.pitch; + px.pitch2 = layout.pitch2; + px.pitch3 = layout.pitch3; + + return px; +} + +inline VDPixmapLayout VDPixmapToLayoutFromBase(const VDPixmap& px, void *p) { + VDPixmapLayout layout; + layout.data = (char *)px.data - (char *)p; + layout.data2 = (char *)px.data2 - (char *)p; + layout.data3 = (char *)px.data3 - (char *)p; + layout.format = px.format; + layout.w = px.w; + layout.h = px.h; + layout.palette = px.palette; + layout.pitch = px.pitch; + layout.pitch2 = px.pitch2; + layout.pitch3 = px.pitch3; + return layout; +} + +inline VDPixmapLayout VDPixmapToLayout(const VDPixmap& px, void *&p) { + VDPixmapLayout layout; + p = px.data; + layout.data = 0; + layout.data2 = (char *)px.data2 - (char *)px.data; + layout.data3 = (char *)px.data3 - (char *)px.data; + layout.format = px.format; + layout.w = px.w; + layout.h = px.h; + layout.palette = px.palette; + layout.pitch = px.pitch; + layout.pitch2 = px.pitch2; + layout.pitch3 = px.pitch3; + return layout; +} + +uint32 VDPixmapCreateLinearLayout(VDPixmapLayout& layout, int format, vdpixsize w, vdpixsize h, int alignment); + +VDPixmap VDPixmapOffset(const VDPixmap& src, vdpixpos x, vdpixpos y); +VDPixmapLayout VDPixmapLayoutOffset(const VDPixmapLayout& src, vdpixpos x, vdpixpos y); + +void VDPixmapFlipV(VDPixmap& layout); +void VDPixmapLayoutFlipV(VDPixmapLayout& layout); + +uint32 VDPixmapLayoutGetMinSize(const VDPixmapLayout& layout); + +VDPixmap VDPixmapExtractField(const VDPixmap& src, bool field2); + +#ifndef VDPTRSTEP_DECLARED + template + inline void vdptrstep(T *&p, ptrdiff_t offset) { + p = (T *)((char *)p + offset); + } +#endif +#ifndef VDPTROFFSET_DECLARED + template + inline T *vdptroffset(T *p, ptrdiff_t offset) { + return (T *)((char *)p + offset); + } +#endif +#ifndef VDPTRDIFFABS_DECLARED + inline ptrdiff_t vdptrdiffabs(ptrdiff_t x) { + return x<0 ? -x : x; + } +#endif + + +typedef void (*VDPixmapBlitterFn)(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +typedef VDPixmapBlitterFn (*tpVDPixBltTable)[nsVDPixmap::kPixFormat_Max_Standard]; + +tpVDPixBltTable VDGetPixBltTableReference(); +tpVDPixBltTable VDGetPixBltTableX86Scalar(); +tpVDPixBltTable VDGetPixBltTableX86MMX(); + + + +class VDPixmapBuffer : public VDPixmap { +public: + VDPixmapBuffer() : mpBuffer(NULL), mLinearSize(0) { data = NULL; format = 0; } + explicit VDPixmapBuffer(const VDPixmap& src); + VDPixmapBuffer(const VDPixmapBuffer& src); + VDPixmapBuffer(sint32 w, sint32 h, int format) : mpBuffer(NULL), mLinearSize(0) { + init(w, h, format); + } + explicit VDPixmapBuffer(const VDPixmapLayout& layout); + + ~VDPixmapBuffer(); + + void clear() { + if (mpBuffer) // to reduce debug checks + delete[] mpBuffer; + mpBuffer = NULL; + mLinearSize = 0; + format = nsVDPixmap::kPixFormat_Null; + } + +#ifdef _DEBUG + void *base() { return mpBuffer + (-(int)(uintptr)mpBuffer & 15) + 16; } + const void *base() const { return mpBuffer + (-(int)(uintptr)mpBuffer & 15) + 16; } + size_t size() const { return mLinearSize - 28; } + + void validate(); +#else + void *base() { return mpBuffer + (-(int)(uintptr)mpBuffer & 15); } + const void *base() const { return mpBuffer + (-(int)(uintptr)mpBuffer & 15); } + size_t size() const { return mLinearSize; } + + void validate() {} +#endif + + void init(sint32 w, sint32 h, int format); + void init(const VDPixmapLayout&, uint32 additionalPadding = 0); + + void assign(const VDPixmap& src); + + void swap(VDPixmapBuffer&); + +protected: + char *mpBuffer; + size_t mLinearSize; +}; + + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/region.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/region.h index b063221cb0e..8e5093b2bcc 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/region.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/region.h @@ -1,93 +1,93 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_REGION_H -#define f_VD2_KASUMI_REGION_H - -struct VDPixmap; - -#include -#include - -class VDPixmapRegion { -public: - void swap(VDPixmapRegion& x); - void clear(); - -public: - vdfastvector mSpans; - vdrect32 mBounds; -}; - -class VDPixmapPathRasterizer { -public: - VDPixmapPathRasterizer(); - VDPixmapPathRasterizer(const VDPixmapPathRasterizer&); // no-op - ~VDPixmapPathRasterizer(); - - VDPixmapPathRasterizer& operator=(const VDPixmapPathRasterizer&); // no-op - - void Clear(); - void QuadraticBezier(const vdint2 pts[4]); - void CubicBezier(const vdint2 pts[4]); - void Line(const vdint2& pt1, const vdint2& pt2); - void FastLine(int x0, int y0, int x1, int y1); - - void ScanConvert(VDPixmapRegion& region); - -protected: - void ClearEdgeList(); - void FreeEdgeLists(); - void ClearScanBuffer(); - void ReallocateScanBuffer(int ymin, int ymax); - - struct Edge { - Edge *next; - int posandflag; - }; - - enum { kEdgeBlockMax = 1024 }; - - struct EdgeBlock { - EdgeBlock *next; - Edge edges[1024]; - - EdgeBlock(EdgeBlock *p) : next(p) {} - }; - - struct Scan { - Edge *chain; - uint32 count; - }; - - EdgeBlock *mpEdgeBlocks; - EdgeBlock *mpFreeEdgeBlocks; - int mEdgeBlockIdx; - Scan *mpScanBuffer; - Scan *mpScanBufferBiased; - int mScanYMin; - int mScanYMax; -}; - -bool VDPixmapFillRegion(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color); -bool VDPixmapFillRegionAntialiased8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color); - -void VDPixmapCreateRoundRegion(VDPixmapRegion& dst, float r); -void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, VDPixmapRegion *tempCache = NULL); - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_REGION_H +#define f_VD2_KASUMI_REGION_H + +struct VDPixmap; + +#include +#include + +class VDPixmapRegion { +public: + void swap(VDPixmapRegion& x); + void clear(); + +public: + vdfastvector mSpans; + vdrect32 mBounds; +}; + +class VDPixmapPathRasterizer { +public: + VDPixmapPathRasterizer(); + VDPixmapPathRasterizer(const VDPixmapPathRasterizer&); // no-op + ~VDPixmapPathRasterizer(); + + VDPixmapPathRasterizer& operator=(const VDPixmapPathRasterizer&); // no-op + + void Clear(); + void QuadraticBezier(const vdint2 pts[4]); + void CubicBezier(const vdint2 pts[4]); + void Line(const vdint2& pt1, const vdint2& pt2); + void FastLine(int x0, int y0, int x1, int y1); + + void ScanConvert(VDPixmapRegion& region); + +protected: + void ClearEdgeList(); + void FreeEdgeLists(); + void ClearScanBuffer(); + void ReallocateScanBuffer(int ymin, int ymax); + + struct Edge { + Edge *next; + int posandflag; + }; + + enum { kEdgeBlockMax = 1024 }; + + struct EdgeBlock { + EdgeBlock *next; + Edge edges[1024]; + + EdgeBlock(EdgeBlock *p) : next(p) {} + }; + + struct Scan { + Edge *chain; + uint32 count; + }; + + EdgeBlock *mpEdgeBlocks; + EdgeBlock *mpFreeEdgeBlocks; + int mEdgeBlockIdx; + Scan *mpScanBuffer; + Scan *mpScanBufferBiased; + int mScanYMin; + int mScanYMax; +}; + +bool VDPixmapFillRegion(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color); +bool VDPixmapFillRegionAntialiased8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color); + +void VDPixmapCreateRoundRegion(VDPixmapRegion& dst, float r); +void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, VDPixmapRegion *tempCache = NULL); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample.h index 12c6f01a288..ba79bf1add4 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample.h @@ -1,31 +1,31 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_H -#define f_VD2_KASUMI_RESAMPLE_H - -#include - -struct VDPixmap; - -class IVDPixmapResampler { -public: - enum FilterMode { - kFilterPoint, - kFilterLinear, - kFilterCubic, - kFilterLanczos3, - kFilterCount - }; - - virtual ~IVDPixmapResampler() {} - virtual void SetSplineFactor(double A) = 0; - virtual void SetFilters(FilterMode h, FilterMode v, bool interpolationOnly) = 0; - virtual bool Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat) = 0; - virtual bool Init(const vdrect32f& dstrect, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect, uint32 sw, uint32 sh, int srcformat) = 0; - virtual void Shutdown() = 0; - - virtual void Process(const VDPixmap& dst, const VDPixmap& src) = 0; -}; - -IVDPixmapResampler *VDCreatePixmapResampler(); -bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter); - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_H +#define f_VD2_KASUMI_RESAMPLE_H + +#include + +struct VDPixmap; + +class IVDPixmapResampler { +public: + enum FilterMode { + kFilterPoint, + kFilterLinear, + kFilterCubic, + kFilterLanczos3, + kFilterCount + }; + + virtual ~IVDPixmapResampler() {} + virtual void SetSplineFactor(double A) = 0; + virtual void SetFilters(FilterMode h, FilterMode v, bool interpolationOnly) = 0; + virtual bool Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat) = 0; + virtual bool Init(const vdrect32f& dstrect, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect, uint32 sw, uint32 sh, int srcformat) = 0; + virtual void Shutdown() = 0; + + virtual void Process(const VDPixmap& dst, const VDPixmap& src) = 0; +}; + +IVDPixmapResampler *VDCreatePixmapResampler(); +bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample_kernels.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample_kernels.h index a95e9b02892..54be5827e3e 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample_kernels.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample_kernels.h @@ -1,91 +1,91 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_KERNELS_H -#define f_VD2_KASUMI_RESAMPLE_KERNELS_H - -#include -#include - -struct VDResamplerAxis { - sint32 dx; - sint32 u; - sint32 dudx; - uint32 dx_precopy; - uint32 dx_preclip; - uint32 dx_active; - uint32 dx_postclip; - uint32 dx_postcopy; - uint32 dx_dualclip; - - void Init(sint32 dudx); - void Compute(sint32 count, sint32 u0, sint32 w, sint32 kernel_width); -}; - - -/////////////////////////////////////////////////////////////////////////// -// -// filter kernels -// -/////////////////////////////////////////////////////////////////////////// - -class IVDResamplerFilter { -public: - virtual ~IVDResamplerFilter() {} - - virtual int GetFilterWidth() const = 0; - virtual double EvaluateFilter(double offset) const = 0; - virtual void GenerateFilter(float *dst, double offset) const = 0; - virtual void GenerateFilterBank(float *dst) const = 0; -}; - -class VDResamplerLinearFilter : public IVDResamplerFilter { -public: - VDResamplerLinearFilter(double twofc); - - int GetFilterWidth() const; - - double EvaluateFilter(double offset) const; - void GenerateFilter(float *dst, double offset) const; - void GenerateFilterBank(float *dst) const; - -protected: - double mScale; - unsigned mTaps; -}; - -class VDResamplerCubicFilter : public IVDResamplerFilter { -public: - VDResamplerCubicFilter(double twofc, double A); - - int GetFilterWidth() const; - - double EvaluateFilter(double offset) const; - void GenerateFilter(float *dst, double offset) const; - void GenerateFilterBank(float *dst) const; - -protected: - double mScale; - double mA0; - double mA2; - double mA3; - double mB0; - double mB1; - double mB2; - double mB3; - unsigned mTaps; -}; - -class VDResamplerLanczos3Filter : public IVDResamplerFilter { -public: - VDResamplerLanczos3Filter(double twofc); - - int GetFilterWidth() const; - - double EvaluateFilter(double offset) const; - void GenerateFilter(float *dst, double offset) const; - void GenerateFilterBank(float *dst) const; - -protected: - double mScale; - unsigned mTaps; -}; - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_KERNELS_H +#define f_VD2_KASUMI_RESAMPLE_KERNELS_H + +#include +#include + +struct VDResamplerAxis { + sint32 dx; + sint32 u; + sint32 dudx; + uint32 dx_precopy; + uint32 dx_preclip; + uint32 dx_active; + uint32 dx_postclip; + uint32 dx_postcopy; + uint32 dx_dualclip; + + void Init(sint32 dudx); + void Compute(sint32 count, sint32 u0, sint32 w, sint32 kernel_width); +}; + + +/////////////////////////////////////////////////////////////////////////// +// +// filter kernels +// +/////////////////////////////////////////////////////////////////////////// + +class IVDResamplerFilter { +public: + virtual ~IVDResamplerFilter() {} + + virtual int GetFilterWidth() const = 0; + virtual double EvaluateFilter(double offset) const = 0; + virtual void GenerateFilter(float *dst, double offset) const = 0; + virtual void GenerateFilterBank(float *dst) const = 0; +}; + +class VDResamplerLinearFilter : public IVDResamplerFilter { +public: + VDResamplerLinearFilter(double twofc); + + int GetFilterWidth() const; + + double EvaluateFilter(double offset) const; + void GenerateFilter(float *dst, double offset) const; + void GenerateFilterBank(float *dst) const; + +protected: + double mScale; + unsigned mTaps; +}; + +class VDResamplerCubicFilter : public IVDResamplerFilter { +public: + VDResamplerCubicFilter(double twofc, double A); + + int GetFilterWidth() const; + + double EvaluateFilter(double offset) const; + void GenerateFilter(float *dst, double offset) const; + void GenerateFilterBank(float *dst) const; + +protected: + double mScale; + double mA0; + double mA2; + double mA3; + double mB0; + double mB1; + double mB2; + double mB3; + unsigned mTaps; +}; + +class VDResamplerLanczos3Filter : public IVDResamplerFilter { +public: + VDResamplerLanczos3Filter(double twofc); + + int GetFilterWidth() const; + + double EvaluateFilter(double offset) const; + void GenerateFilter(float *dst, double offset) const; + void GenerateFilterBank(float *dst) const; + +protected: + double mScale; + unsigned mTaps; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/tables.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/tables.h index 972f3703672..1ff663df9d2 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/tables.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/tables.h @@ -1,41 +1,41 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2008 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_TABLES_H -#define f_VD2_KASUMI_TABLES_H - -/////////////////////////////////////////////////////////////////////////////// -// Cubic interpolation tables -// -// These tables give coefficients for 1-D cubic interpolation with 8-bit -// subunit precision. The [0] entry is positioned exactly on top of the -// second sample, and the [255] entry is 255/256th of the way to the third -// sample. The cardinal spline constant is -0.75 and the output range is -// [-0.1875, 1.1875], where the maximum overshoot and undershoot occur at -// the midpoint. -// -// The first and fourth coefficients are always negative; the second and -// third coefficients are always positive. -// -extern "C" const sint32 kVDCubicInterpTableFX14_075[256][4]; - -#ifdef _M_IX86 - extern "C" const sint16 kVDCubicInterpTableFX14_075_MMX[256][8]; -#endif - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2008 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_TABLES_H +#define f_VD2_KASUMI_TABLES_H + +/////////////////////////////////////////////////////////////////////////////// +// Cubic interpolation tables +// +// These tables give coefficients for 1-D cubic interpolation with 8-bit +// subunit precision. The [0] entry is positioned exactly on top of the +// second sample, and the [255] entry is 255/256th of the way to the third +// sample. The cardinal spline constant is -0.75 and the output range is +// [-0.1875, 1.1875], where the maximum overshoot and undershoot occur at +// the midpoint. +// +// The first and fourth coefficients are always negative; the second and +// third coefficients are always positive. +// +extern "C" const sint32 kVDCubicInterpTableFX14_075[256][4]; + +#ifdef _M_IX86 + extern "C" const sint16 kVDCubicInterpTableFX14_075_MMX[256][8]; +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h index f4dba2796ca..70452b66f15 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h @@ -1,76 +1,76 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_TEXT_H -#define f_VD2_KASUMI_TEXT_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -class VDPixmapPathRasterizer; - -struct VDOutlineFontGlyphInfo { - uint16 mPointArrayStart; // start of points (encoded as 8:8) - uint16 mCommandArrayStart; // start of commands (encoded as 6:2 RLE). - sint16 mAWidth; // advance from start to character cell - sint16 mBWidth; // width of character cell - sint16 mCWidth; // advance from character cell to end -}; - -struct VDOutlineFontInfo { - const uint16 *mpPointArray; - const uint8 *mpCommandArray; - const VDOutlineFontGlyphInfo *mpGlyphArray; - int mStartGlyph; - int mEndGlyph; - int mMinX; - int mMinY; - int mMaxX; - int mMaxY; - int mEmSquare; - int mAscent; - int mDescent; - int mLineGap; -}; - -struct VDTextLayoutMetrics { - vdrect32f mExtents; - float mAdvance; -}; - -void VDPixmapGetTextExtents(const VDOutlineFontInfo *font, float size, const char *pText, VDTextLayoutMetrics& out_Metrics); -void VDPixmapConvertTextToPath(VDPixmapPathRasterizer& rast, const VDOutlineFontInfo *font, float size, float x, float y, const char *pText, const float transform[2][2] = NULL); - -struct VDBitmapFontInfo { - const uint8 *mpBitsArray; - const uint16 *mpPosArray; - uint8 mStartChar; - uint8 mEndChar; - int mCellWidth; - int mCellHeight; - int mCellAscent; - int mCellAdvance; - int mLineGap; -}; - -void VDPixmapDrawText(const VDPixmap& pxdst, const VDBitmapFontInfo *font, int x, int y, uint32 fore, uint32 back, const char *pText); - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_TEXT_H +#define f_VD2_KASUMI_TEXT_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +class VDPixmapPathRasterizer; + +struct VDOutlineFontGlyphInfo { + uint16 mPointArrayStart; // start of points (encoded as 8:8) + uint16 mCommandArrayStart; // start of commands (encoded as 6:2 RLE). + sint16 mAWidth; // advance from start to character cell + sint16 mBWidth; // width of character cell + sint16 mCWidth; // advance from character cell to end +}; + +struct VDOutlineFontInfo { + const uint16 *mpPointArray; + const uint8 *mpCommandArray; + const VDOutlineFontGlyphInfo *mpGlyphArray; + int mStartGlyph; + int mEndGlyph; + int mMinX; + int mMinY; + int mMaxX; + int mMaxY; + int mEmSquare; + int mAscent; + int mDescent; + int mLineGap; +}; + +struct VDTextLayoutMetrics { + vdrect32f mExtents; + float mAdvance; +}; + +void VDPixmapGetTextExtents(const VDOutlineFontInfo *font, float size, const char *pText, VDTextLayoutMetrics& out_Metrics); +void VDPixmapConvertTextToPath(VDPixmapPathRasterizer& rast, const VDOutlineFontInfo *font, float size, float x, float y, const char *pText, const float transform[2][2] = NULL); + +struct VDBitmapFontInfo { + const uint8 *mpBitsArray; + const uint16 *mpPosArray; + uint8 mStartChar; + uint8 mEndChar; + int mCellWidth; + int mCellHeight; + int mCellAscent; + int mCellAdvance; + int mLineGap; +}; + +void VDPixmapDrawText(const VDPixmap& pxdst, const VDBitmapFontInfo *font, int x, int y, uint32 fore, uint32 back, const char *pText); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/triblt.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/triblt.h index 9765f8e4165..c564ebbb0af 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/triblt.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/triblt.h @@ -1,72 +1,72 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2008 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_TRIBLT_H -#define f_VD2_KASUMI_TRIBLT_H - -#include -#include -#include - -struct VDTriBltVertex { - float x, y, z, u, v; -}; - -struct VDTriColorVertex { - float x, y, z, r, g, b, a; -}; - -enum VDTriBltFilterMode { - kTriBltFilterPoint, - kTriBltFilterBilinear, - kTriBltFilterTrilinear, - kTriBltFilterBicubicMipLinear, - kTriBltFilterCount -}; - -bool VDPixmapTriFill(VDPixmap& dst, uint32 c, - const VDTriBltVertex *pVertices, int nVertices, - const int *pIndices, const int nIndices, - const float pTransform[16] = NULL); - -bool VDPixmapTriFill(VDPixmap& dst, - const VDTriColorVertex *pVertices, int nVertices, - const int *pIndices, const int nIndices, - const float pTransform[16] = NULL, - const float *chroma_yoffset = NULL); - -bool VDPixmapTriBlt(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, - const VDTriBltVertex *pVertices, int nVertices, - const int *pIndices, const int nIndices, - VDTriBltFilterMode filterMode, - float mipMapLODBias, - const float pTransform[16] = NULL); - -class VDPixmapTextureMipmapChain { -public: - VDPixmapTextureMipmapChain(const VDPixmap& src, bool wrap=false, bool cubic = false, int maxlevels = 16); - - const VDPixmap *const *Mips() const { return mMipMaps.data(); } - int Levels() const { return mMipMaps.size(); } - -protected: - std::vector mBuffers; - vdfastvector mMipMaps; -}; - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2008 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_TRIBLT_H +#define f_VD2_KASUMI_TRIBLT_H + +#include +#include +#include + +struct VDTriBltVertex { + float x, y, z, u, v; +}; + +struct VDTriColorVertex { + float x, y, z, r, g, b, a; +}; + +enum VDTriBltFilterMode { + kTriBltFilterPoint, + kTriBltFilterBilinear, + kTriBltFilterTrilinear, + kTriBltFilterBicubicMipLinear, + kTriBltFilterCount +}; + +bool VDPixmapTriFill(VDPixmap& dst, uint32 c, + const VDTriBltVertex *pVertices, int nVertices, + const int *pIndices, const int nIndices, + const float pTransform[16] = NULL); + +bool VDPixmapTriFill(VDPixmap& dst, + const VDTriColorVertex *pVertices, int nVertices, + const int *pIndices, const int nIndices, + const float pTransform[16] = NULL, + const float *chroma_yoffset = NULL); + +bool VDPixmapTriBlt(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, + const VDTriBltVertex *pVertices, int nVertices, + const int *pIndices, const int nIndices, + VDTriBltFilterMode filterMode, + float mipMapLODBias, + const float pTransform[16] = NULL); + +class VDPixmapTextureMipmapChain { +public: + VDPixmapTextureMipmapChain(const VDPixmap& src, bool wrap=false, bool cubic = false, int maxlevels = 16); + + const VDPixmap *const *Mips() const { return mMipMaps.data(); } + int Levels() const { return mMipMaps.size(); } + +protected: + std::vector mBuffers; + vdfastvector mMipMaps; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/Error.h b/src/thirdparty/VirtualDub/h/vd2/system/Error.h index 519d7faf64e..9b4d79c50ab 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/Error.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/Error.h @@ -1,125 +1,125 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_ERROR_H -#define f_VD2_ERROR_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -class MyError; - -/////////////////////////////////////////////////////////////////////////// -// IVDAsyncErrorCallback -// -class IVDAsyncErrorCallback { -public: - virtual bool OnAsyncError(MyError& e) = 0; -}; - -/////////////////////////////////////////////////////////////////////////// -// MyError -// -class MyError { -private: - const MyError& operator=(const MyError&); // protect against accidents - -protected: - char *buf; - -public: - MyError(); - MyError(const MyError& err); - MyError(const char *f, ...); - ~MyError(); - void clear(); - void assign(const MyError& e); - void assign(const char *s); - void setf(const char *f, ...); - void vsetf(const char *f, va_list val); - void post(struct HWND__ *hWndParent, const char *title) const; - char *gets() const { - return buf; - } - char *c_str() const { - return buf; - } - bool empty() const { return !buf; } - void discard(); - void swap(MyError& err); - void TransferFrom(MyError& err); -}; - -class MyICError : public MyError { -public: - MyICError(const char *s, uint32 icErr); - MyICError(uint32 icErr, const char *format, ...); -}; - -class MyMMIOError : public MyError { -public: - MyMMIOError(const char *s, uint32 icErr); -}; - -class MyAVIError : public MyError { -public: - MyAVIError(const char *s, uint32 aviErr); -}; - -class MyMemoryError : public MyError { -public: - MyMemoryError(); - MyMemoryError(size_t attemptedSize); -}; - -class MyWin32Error : public MyError { -public: - MyWin32Error(const char *format, uint32 err, ...); - - uint32 GetWin32Error() const { return mWin32Error; } - -protected: - const uint32 mWin32Error; -}; - -class MyCrashError : public MyError { -public: - MyCrashError(const char *format, uint32 dwExceptionCode); -}; - -class MyUserAbortError : public MyError { -public: - MyUserAbortError(); -}; - -class MyInternalError : public MyError { -public: - MyInternalError(const char *format, ...); -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_ERROR_H +#define f_VD2_ERROR_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +class MyError; + +/////////////////////////////////////////////////////////////////////////// +// IVDAsyncErrorCallback +// +class IVDAsyncErrorCallback { +public: + virtual bool OnAsyncError(MyError& e) = 0; +}; + +/////////////////////////////////////////////////////////////////////////// +// MyError +// +class MyError { +private: + const MyError& operator=(const MyError&); // protect against accidents + +protected: + char *buf; + +public: + MyError(); + MyError(const MyError& err); + MyError(const char *f, ...); + ~MyError(); + void clear(); + void assign(const MyError& e); + void assign(const char *s); + void setf(const char *f, ...); + void vsetf(const char *f, va_list val); + void post(struct HWND__ *hWndParent, const char *title) const; + char *gets() const { + return buf; + } + char *c_str() const { + return buf; + } + bool empty() const { return !buf; } + void discard(); + void swap(MyError& err); + void TransferFrom(MyError& err); +}; + +class MyICError : public MyError { +public: + MyICError(const char *s, uint32 icErr); + MyICError(uint32 icErr, const char *format, ...); +}; + +class MyMMIOError : public MyError { +public: + MyMMIOError(const char *s, uint32 icErr); +}; + +class MyAVIError : public MyError { +public: + MyAVIError(const char *s, uint32 aviErr); +}; + +class MyMemoryError : public MyError { +public: + MyMemoryError(); + MyMemoryError(size_t attemptedSize); +}; + +class MyWin32Error : public MyError { +public: + MyWin32Error(const char *format, uint32 err, ...); + + uint32 GetWin32Error() const { return mWin32Error; } + +protected: + const uint32 mWin32Error; +}; + +class MyCrashError : public MyError { +public: + MyCrashError(const char *format, uint32 dwExceptionCode); +}; + +class MyUserAbortError : public MyError { +public: + MyUserAbortError(); +}; + +class MyInternalError : public MyError { +public: + MyInternalError(const char *format, ...); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/Fraction.h b/src/thirdparty/VirtualDub/h/vd2/system/Fraction.h index 74253363522..f7aa17ea60c 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/Fraction.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/Fraction.h @@ -1,95 +1,95 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_FRACTION_H -#define f_VD2_SYSTEM_FRACTION_H - -#include - -class VDFraction { -friend VDFraction operator*(unsigned long b, const VDFraction f); -friend VDFraction operator*(int b, const VDFraction f); -private: - unsigned long hi, lo; - - static VDFraction reduce(uint64 hi, uint64 lo); - -public: - VDFraction() {} - explicit VDFraction(int i) : hi(i), lo(1) {} - explicit VDFraction(unsigned long i) : hi(i), lo(1) { } - explicit VDFraction(unsigned long i, unsigned long j) : hi(i), lo(j) {} - explicit VDFraction(double d); - - bool operator<(VDFraction b) const; - bool operator<=(VDFraction b) const; - bool operator>(VDFraction b) const; - bool operator>=(VDFraction b) const; - bool operator==(VDFraction b) const; - bool operator!=(VDFraction b) const; - - VDFraction operator*(VDFraction b) const; - VDFraction operator/(VDFraction b) const; - - VDFraction operator*(unsigned long b) const; - VDFraction operator/(unsigned long b) const; - - VDFraction& operator*=(VDFraction b); - VDFraction& operator/=(VDFraction b); - VDFraction& operator*=(unsigned long b); - VDFraction& operator/=(unsigned long b); - - void Assign(unsigned long n, unsigned long d) { - hi = n; - lo = d; - } - - sint64 scale64t(sint64) const; - sint64 scale64r(sint64) const; - sint64 scale64u(sint64) const; - sint64 scale64it(sint64) const; - sint64 scale64ir(sint64) const; - sint64 scale64iu(sint64) const; - - double asDouble() const; - double AsInverseDouble() const; - - unsigned long roundup32ul() const; - - unsigned long getHi() const { return hi; } - unsigned long getLo() const { return lo; } - - VDFraction reduce() const { return reduce(hi, lo); } - - bool Parse(const char *s); - - static inline VDFraction reduce64(sint64 hi, sint64 lo) { return reduce(hi, lo); } -}; - -inline VDFraction operator*(unsigned long b, const VDFraction f) { return f*b; } - -typedef VDFraction Fraction; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_FRACTION_H +#define f_VD2_SYSTEM_FRACTION_H + +#include + +class VDFraction { +friend VDFraction operator*(unsigned long b, const VDFraction f); +friend VDFraction operator*(int b, const VDFraction f); +private: + unsigned long hi, lo; + + static VDFraction reduce(uint64 hi, uint64 lo); + +public: + VDFraction() {} + explicit VDFraction(int i) : hi(i), lo(1) {} + explicit VDFraction(unsigned long i) : hi(i), lo(1) { } + explicit VDFraction(unsigned long i, unsigned long j) : hi(i), lo(j) {} + explicit VDFraction(double d); + + bool operator<(VDFraction b) const; + bool operator<=(VDFraction b) const; + bool operator>(VDFraction b) const; + bool operator>=(VDFraction b) const; + bool operator==(VDFraction b) const; + bool operator!=(VDFraction b) const; + + VDFraction operator*(VDFraction b) const; + VDFraction operator/(VDFraction b) const; + + VDFraction operator*(unsigned long b) const; + VDFraction operator/(unsigned long b) const; + + VDFraction& operator*=(VDFraction b); + VDFraction& operator/=(VDFraction b); + VDFraction& operator*=(unsigned long b); + VDFraction& operator/=(unsigned long b); + + void Assign(unsigned long n, unsigned long d) { + hi = n; + lo = d; + } + + sint64 scale64t(sint64) const; + sint64 scale64r(sint64) const; + sint64 scale64u(sint64) const; + sint64 scale64it(sint64) const; + sint64 scale64ir(sint64) const; + sint64 scale64iu(sint64) const; + + double asDouble() const; + double AsInverseDouble() const; + + unsigned long roundup32ul() const; + + unsigned long getHi() const { return hi; } + unsigned long getLo() const { return lo; } + + VDFraction reduce() const { return reduce(hi, lo); } + + bool Parse(const char *s); + + static inline VDFraction reduce64(sint64 hi, sint64 lo) { return reduce(hi, lo); } +}; + +inline VDFraction operator*(unsigned long b, const VDFraction f) { return f*b; } + +typedef VDFraction Fraction; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDNamespace.h b/src/thirdparty/VirtualDub/h/vd2/system/VDNamespace.h index c0f0d41413b..31baa28b69d 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDNamespace.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDNamespace.h @@ -1,157 +1,157 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. -#ifndef f_SYSTEM_VDNAMESPACE_H -#define f_SYSTEM_VDNAMESPACE_H - -#include - -class VDNamespaceNode; -class VDNamespaceGroup; -class VDNamespaceItem; -class VDNamespace; -template class VDNamespace2; - -/////////////////////////////////////////////////////////////////////////// -// -// Node: Any item in the namespace. -// -/////////////////////////////////////////////////////////////////////////// - -class VDNamespaceNode { -public: - const char *pszName; - VDNamespaceGroup *const pParent; - - VDNamespaceNode(const char *name, VDNamespaceGroup *parent) : pszName(name), pParent(parent) { } -}; - -/////////////////////////////////////////////////////////////////////////// -// -// Group: Holds items. -// -/////////////////////////////////////////////////////////////////////////// - -class VDNamespaceGroup : public VDNamespaceNode, public ListNode2 { -public: - ListAlloc listItems; - ListAlloc listGroups; - - const char *namedup(const char *s); - - VDNamespaceGroup(const char *_pszName, VDNamespaceGroup *parent); - ~VDNamespaceGroup(); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// Item class -// -/////////////////////////////////////////////////////////////////////////// - -class VDNamespaceItem : public VDNamespaceNode, public ListNode2 { -public: - const void *object; - - VDNamespaceItem(const char *_pszName, VDNamespaceGroup *parent, const void *src); - ~VDNamespaceItem(); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// Namespace class -// -/////////////////////////////////////////////////////////////////////////// - -class VDNamespace { -protected: - VDNamespaceGroup root; - - VDNamespaceGroup *_lookupGroup(const char *pszName, bool fCreate, bool fIsFilter); - VDNamespaceItem *_findItemByObject(const VDNamespaceGroup *pGroup, const void *pObj); - bool _getPathByItem(const VDNamespaceNode *pEntry, char *buf, int maxlen); - -public: - - VDNamespace(); - ~VDNamespace(); - - typedef bool (*tGroupEnumerator)(VDNamespace *pThis, const char *pszName, const VDNamespaceGroup *pGroup, void *pvData); - typedef bool (*tItemEnumerator)(VDNamespace *pThis, const char *pszName, const void *pItem, void *pvData); - - void clear(); - void add(const char *pszGroup, const char *pszName, const void *pDef); - const void *lookup(const char *pszName); - - bool enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData); - bool enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData); - - bool getPathByItem(const void *pObj, char *buf, int maxlen); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// Templated Namespace class -// -/////////////////////////////////////////////////////////////////////////// - -template -class VDNamespace2 : public VDNamespace { -public: - VDNamespace2() {} - ~VDNamespace2() {} - - typedef bool (*tGroupEnumerator)(VDNamespace2 *pThis, const char *pszName, const VDNamespaceGroup *pGroup, void *pvData); - typedef bool (*tItemEnumerator)(VDNamespace2 *pThis, const char *pszName, const T *pItem, void *pvData); - - void add(const char *pszGroup, const char *pszName, const T *pDef) { - VDNamespace::add(pszGroup, pszName, pDef); - } - - const T *lookup(const char *pszName) { - return static_cast(VDNamespace::lookup(pszName)); - } - - bool enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData) { - for(ListAlloc::fwit it = (pGroupRoot ? pGroupRoot : &root)->listGroups.begin(); it; ++it) - if (!pEnum(this, it->pszName, it, pvData)) - return false; - - return true; - } - - bool enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData) { - for(ListAlloc::fwit it = (pGroupRoot ? pGroupRoot : &root)->listItems.begin(); it; ++it) - if (!pEnum(this, it->pszName, static_cast(it->object), pvData)) - return false; - - return true; - } - - bool getPathByItem(const T *pObj, char *buf, int maxlen) { - return VDNamespace::getPathByItem(pObj, buf, maxlen); - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. +#ifndef f_SYSTEM_VDNAMESPACE_H +#define f_SYSTEM_VDNAMESPACE_H + +#include + +class VDNamespaceNode; +class VDNamespaceGroup; +class VDNamespaceItem; +class VDNamespace; +template class VDNamespace2; + +/////////////////////////////////////////////////////////////////////////// +// +// Node: Any item in the namespace. +// +/////////////////////////////////////////////////////////////////////////// + +class VDNamespaceNode { +public: + const char *pszName; + VDNamespaceGroup *const pParent; + + VDNamespaceNode(const char *name, VDNamespaceGroup *parent) : pszName(name), pParent(parent) { } +}; + +/////////////////////////////////////////////////////////////////////////// +// +// Group: Holds items. +// +/////////////////////////////////////////////////////////////////////////// + +class VDNamespaceGroup : public VDNamespaceNode, public ListNode2 { +public: + ListAlloc listItems; + ListAlloc listGroups; + + const char *namedup(const char *s); + + VDNamespaceGroup(const char *_pszName, VDNamespaceGroup *parent); + ~VDNamespaceGroup(); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// Item class +// +/////////////////////////////////////////////////////////////////////////// + +class VDNamespaceItem : public VDNamespaceNode, public ListNode2 { +public: + const void *object; + + VDNamespaceItem(const char *_pszName, VDNamespaceGroup *parent, const void *src); + ~VDNamespaceItem(); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// Namespace class +// +/////////////////////////////////////////////////////////////////////////// + +class VDNamespace { +protected: + VDNamespaceGroup root; + + VDNamespaceGroup *_lookupGroup(const char *pszName, bool fCreate, bool fIsFilter); + VDNamespaceItem *_findItemByObject(const VDNamespaceGroup *pGroup, const void *pObj); + bool _getPathByItem(const VDNamespaceNode *pEntry, char *buf, int maxlen); + +public: + + VDNamespace(); + ~VDNamespace(); + + typedef bool (*tGroupEnumerator)(VDNamespace *pThis, const char *pszName, const VDNamespaceGroup *pGroup, void *pvData); + typedef bool (*tItemEnumerator)(VDNamespace *pThis, const char *pszName, const void *pItem, void *pvData); + + void clear(); + void add(const char *pszGroup, const char *pszName, const void *pDef); + const void *lookup(const char *pszName); + + bool enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData); + bool enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData); + + bool getPathByItem(const void *pObj, char *buf, int maxlen); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// Templated Namespace class +// +/////////////////////////////////////////////////////////////////////////// + +template +class VDNamespace2 : public VDNamespace { +public: + VDNamespace2() {} + ~VDNamespace2() {} + + typedef bool (*tGroupEnumerator)(VDNamespace2 *pThis, const char *pszName, const VDNamespaceGroup *pGroup, void *pvData); + typedef bool (*tItemEnumerator)(VDNamespace2 *pThis, const char *pszName, const T *pItem, void *pvData); + + void add(const char *pszGroup, const char *pszName, const T *pDef) { + VDNamespace::add(pszGroup, pszName, pDef); + } + + const T *lookup(const char *pszName) { + return static_cast(VDNamespace::lookup(pszName)); + } + + bool enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData) { + for(ListAlloc::fwit it = (pGroupRoot ? pGroupRoot : &root)->listGroups.begin(); it; ++it) + if (!pEnum(this, it->pszName, it, pvData)) + return false; + + return true; + } + + bool enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData) { + for(ListAlloc::fwit it = (pGroupRoot ? pGroupRoot : &root)->listItems.begin(); it; ++it) + if (!pEnum(this, it->pszName, static_cast(it->object), pvData)) + return false; + + return true; + } + + bool getPathByItem(const T *pObj, char *buf, int maxlen) { + return VDNamespace::getPathByItem(pObj, buf, maxlen); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDQueue.h b/src/thirdparty/VirtualDub/h/vd2/system/VDQueue.h index 43367d287ae..ace02ae4e86 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDQueue.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDQueue.h @@ -1,90 +1,90 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDQUEUE_H -#define f_VD2_SYSTEM_VDQUEUE_H - -#include - -template -class VDQueueNode : public ListNode2< VDQueueNode > { -public: - T t; - VDQueueNode(const T& t2) : t(t2) {} -}; - -template -class VDQueue { -public: - ListAlloc< VDQueueNode > list; - - VDQueue(); - ~VDQueue(); - T Pop(); - T Peek(); - void Push(const T&); - bool isEmpty() { return list.IsEmpty(); } -}; - -template -VDQueue::VDQueue() { -} - -template -VDQueue::~VDQueue() { - while(!list.IsEmpty()) - delete list.RemoveTail(); -} - -template -T VDQueue::Peek() { - return list.AtHead()->t; -} - -template -T VDQueue::Pop() { - return list.RemoveHead()->t; -} - -template -void VDQueue::Push(const T& t) { - list.AddTail(new VDQueueNode(t)); -} - -///////////// - -template -class VDQueueAlloc : public VDQueue { -public: - ~VDQueueAlloc(); -}; - -template -VDQueueAlloc::~VDQueueAlloc() { - for(ListAlloc< VDQueueNode >::fwit it = list.begin(); it; ++it) - delete &*it; -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDQUEUE_H +#define f_VD2_SYSTEM_VDQUEUE_H + +#include + +template +class VDQueueNode : public ListNode2< VDQueueNode > { +public: + T t; + VDQueueNode(const T& t2) : t(t2) {} +}; + +template +class VDQueue { +public: + ListAlloc< VDQueueNode > list; + + VDQueue(); + ~VDQueue(); + T Pop(); + T Peek(); + void Push(const T&); + bool isEmpty() { return list.IsEmpty(); } +}; + +template +VDQueue::VDQueue() { +} + +template +VDQueue::~VDQueue() { + while(!list.IsEmpty()) + delete list.RemoveTail(); +} + +template +T VDQueue::Peek() { + return list.AtHead()->t; +} + +template +T VDQueue::Pop() { + return list.RemoveHead()->t; +} + +template +void VDQueue::Push(const T& t) { + list.AddTail(new VDQueueNode(t)); +} + +///////////// + +template +class VDQueueAlloc : public VDQueue { +public: + ~VDQueueAlloc(); +}; + +template +VDQueueAlloc::~VDQueueAlloc() { + for(ListAlloc< VDQueueNode >::fwit it = list.begin(); it; ++it) + delete &*it; +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDRingBuffer.h b/src/thirdparty/VirtualDub/h/vd2/system/VDRingBuffer.h index c564cd7f9c8..cd05ff1690f 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDRingBuffer.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDRingBuffer.h @@ -1,301 +1,301 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_SYSTEM_VDRINGBUFFER_H -#define f_SYSTEM_VDRINGBUFFER_H - -#include -#include - -#include - -class VDRingBufferBase { -public: - VDRingBufferBase() - : nSize(0) - , nReadPoint(0) - , nWritePoint(0) - { - } - - int getSize() const { return nSize; } - int getReadOffset() const { return nReadPoint; } - int getWriteOffset() const { return nWritePoint; } - -protected: - int nSize; - int nReadPoint; - int nWritePoint; -}; - -template > -class VDRingBuffer : public VDRingBufferBase, private Allocator { -protected: - T *pBuffer; - VDAtomicInt nLevel; - -public: - VDRingBuffer(); - VDRingBuffer(int size); - ~VDRingBuffer(); - - void Init(int size); - void Shutdown(); - - int getLevel() const { return nLevel; } - int getSpace() const { return nSize - nLevel; } - int getWriteSpace() const; - T * getWritePtr() const { return pBuffer+nWritePoint; } - - int size() const { return nSize; } - bool empty() const { return !nLevel; } - bool full() const { return nLevel == nSize; } - - void Flush() { nReadPoint = nWritePoint = nLevel = 0; } - - int Read(T *pBuffer, int bytes); - const T *LockRead(int requested, int& actual); - const T *LockReadAll(int& actual); - const T *LockReadWrapped(int requested, int& actual, int& nReadPoint); - const T *LockReadAllWrapped(int& actual, int& nReadPoint); - int UnlockRead(int actual); - - int Write(const T *pData, int bytes); - T *LockWrite(int requested, int& actual); - T *LockWriteAll(int& actual); - int UnlockWrite(int actual); -}; - -template -VDRingBuffer::VDRingBuffer(int size) - : pBuffer(NULL) -{ - Init(size); -} - -template -VDRingBuffer::VDRingBuffer() - : pBuffer(NULL) - , nLevel(0) -{ -} - -template -VDRingBuffer::~VDRingBuffer() { - Shutdown(); -} - -template -void VDRingBuffer::Init(int size) { - Shutdown(); - pBuffer = Allocator::allocate(nSize = size, 0); - nLevel = 0; - nReadPoint = 0; - nWritePoint = 0; -} - -template -void VDRingBuffer::Shutdown() { - if (pBuffer) { - Allocator::deallocate(pBuffer, nSize); - pBuffer = NULL; - } -} - -template -int VDRingBuffer::getWriteSpace() const { - volatile int tc = nSize - nWritePoint; - volatile int space = nSize - nLevel; - - if (tc > space) - tc = space; - - return tc; -} - -template -int VDRingBuffer::Read(T *pBuffer, int units) { - VDASSERT(units >= 0); - - int actual = 0; - const T *pSrc; - - while(units) { - int tc; - - pSrc = LockRead(units, tc); - - if (!tc) - break; - - memcpy(pBuffer, pSrc, tc * sizeof(T)); - - UnlockRead(tc); - - actual += tc; - units -= tc; - pBuffer += tc; - } - - return actual; -} - -template -const T *VDRingBuffer::LockRead(int requested, int& actual) { - VDASSERT(requested >= 0); - - int nLevelNow = nLevel; - - if (requested > nLevelNow) - requested = nLevelNow; - - if (requested + nReadPoint > nSize) - requested = nSize - nReadPoint; - - actual = requested; - - return pBuffer + nReadPoint; -} - -template -const T *VDRingBuffer::LockReadAll(int& actual) { - int requested = nLevel; - - if (requested + nReadPoint > nSize) - requested = nSize - nReadPoint; - - actual = requested; - - return pBuffer + nReadPoint; -} - -template -const T *VDRingBuffer::LockReadWrapped(int requested, int& actual, int& readpt) { - int nLevelNow = nLevel; - - if (requested > nLevelNow) - requested = nLevelNow; - - actual = requested; - readpt = nReadPoint; - - return pBuffer; -} - -template -const T *VDRingBuffer::LockReadAllWrapped(int& actual, int& readpt) { - int requested = nLevel; - - actual = requested; - readpt = nReadPoint; - - return pBuffer; -} - -template -int VDRingBuffer::UnlockRead(int actual) { - VDASSERT(actual >= 0); - VDASSERT(nLevel >= actual); - - int newpt = nReadPoint + actual; - - if (newpt >= nSize) - newpt -= nSize; - - nReadPoint = newpt; - - return nLevel.add(-actual); -} - -template -int VDRingBuffer::Write(const T *src, int elements) { - VDASSERT(elements >= 0); - - int actual = 0; - while(elements) { - int tc; - void *dst = LockWrite(elements, tc); - - if (!tc) - break; - - memcpy(dst, src, tc*sizeof(T)); - - UnlockWrite(tc); - - actual += tc; - elements -= tc; - src += tc; - } - - return actual; -} - -template -T *VDRingBuffer::LockWrite(int requested, int& actual) { - VDASSERT(requested >= 0); - int nLevelNow = nSize - nLevel; - - if (requested > nLevelNow) - requested = nLevelNow; - - if (requested + nWritePoint > nSize) - requested = nSize - nWritePoint; - - actual = requested; - - return pBuffer + nWritePoint; -} - -template -T *VDRingBuffer::LockWriteAll(int& actual) { - int requested = nSize - nLevel; - - if (requested + nWritePoint > nSize) - requested = nSize - nWritePoint; - - actual = requested; - - return pBuffer + nWritePoint; -} - -template -int VDRingBuffer::UnlockWrite(int actual) { - VDASSERT(actual >= 0); - VDASSERT(nLevel + actual <= nSize); - - int newpt = nWritePoint + actual; - - if (newpt >= nSize) - newpt = 0; - - nWritePoint = newpt; - - return nLevel.add(actual); -} - - - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_SYSTEM_VDRINGBUFFER_H +#define f_SYSTEM_VDRINGBUFFER_H + +#include +#include + +#include + +class VDRingBufferBase { +public: + VDRingBufferBase() + : nSize(0) + , nReadPoint(0) + , nWritePoint(0) + { + } + + int getSize() const { return nSize; } + int getReadOffset() const { return nReadPoint; } + int getWriteOffset() const { return nWritePoint; } + +protected: + int nSize; + int nReadPoint; + int nWritePoint; +}; + +template > +class VDRingBuffer : public VDRingBufferBase, private Allocator { +protected: + T *pBuffer; + VDAtomicInt nLevel; + +public: + VDRingBuffer(); + VDRingBuffer(int size); + ~VDRingBuffer(); + + void Init(int size); + void Shutdown(); + + int getLevel() const { return nLevel; } + int getSpace() const { return nSize - nLevel; } + int getWriteSpace() const; + T * getWritePtr() const { return pBuffer+nWritePoint; } + + int size() const { return nSize; } + bool empty() const { return !nLevel; } + bool full() const { return nLevel == nSize; } + + void Flush() { nReadPoint = nWritePoint = nLevel = 0; } + + int Read(T *pBuffer, int bytes); + const T *LockRead(int requested, int& actual); + const T *LockReadAll(int& actual); + const T *LockReadWrapped(int requested, int& actual, int& nReadPoint); + const T *LockReadAllWrapped(int& actual, int& nReadPoint); + int UnlockRead(int actual); + + int Write(const T *pData, int bytes); + T *LockWrite(int requested, int& actual); + T *LockWriteAll(int& actual); + int UnlockWrite(int actual); +}; + +template +VDRingBuffer::VDRingBuffer(int size) + : pBuffer(NULL) +{ + Init(size); +} + +template +VDRingBuffer::VDRingBuffer() + : pBuffer(NULL) + , nLevel(0) +{ +} + +template +VDRingBuffer::~VDRingBuffer() { + Shutdown(); +} + +template +void VDRingBuffer::Init(int size) { + Shutdown(); + pBuffer = Allocator::allocate(nSize = size, 0); + nLevel = 0; + nReadPoint = 0; + nWritePoint = 0; +} + +template +void VDRingBuffer::Shutdown() { + if (pBuffer) { + Allocator::deallocate(pBuffer, nSize); + pBuffer = NULL; + } +} + +template +int VDRingBuffer::getWriteSpace() const { + volatile int tc = nSize - nWritePoint; + volatile int space = nSize - nLevel; + + if (tc > space) + tc = space; + + return tc; +} + +template +int VDRingBuffer::Read(T *pBuffer, int units) { + VDASSERT(units >= 0); + + int actual = 0; + const T *pSrc; + + while(units) { + int tc; + + pSrc = LockRead(units, tc); + + if (!tc) + break; + + memcpy(pBuffer, pSrc, tc * sizeof(T)); + + UnlockRead(tc); + + actual += tc; + units -= tc; + pBuffer += tc; + } + + return actual; +} + +template +const T *VDRingBuffer::LockRead(int requested, int& actual) { + VDASSERT(requested >= 0); + + int nLevelNow = nLevel; + + if (requested > nLevelNow) + requested = nLevelNow; + + if (requested + nReadPoint > nSize) + requested = nSize - nReadPoint; + + actual = requested; + + return pBuffer + nReadPoint; +} + +template +const T *VDRingBuffer::LockReadAll(int& actual) { + int requested = nLevel; + + if (requested + nReadPoint > nSize) + requested = nSize - nReadPoint; + + actual = requested; + + return pBuffer + nReadPoint; +} + +template +const T *VDRingBuffer::LockReadWrapped(int requested, int& actual, int& readpt) { + int nLevelNow = nLevel; + + if (requested > nLevelNow) + requested = nLevelNow; + + actual = requested; + readpt = nReadPoint; + + return pBuffer; +} + +template +const T *VDRingBuffer::LockReadAllWrapped(int& actual, int& readpt) { + int requested = nLevel; + + actual = requested; + readpt = nReadPoint; + + return pBuffer; +} + +template +int VDRingBuffer::UnlockRead(int actual) { + VDASSERT(actual >= 0); + VDASSERT(nLevel >= actual); + + int newpt = nReadPoint + actual; + + if (newpt >= nSize) + newpt -= nSize; + + nReadPoint = newpt; + + return nLevel.add(-actual); +} + +template +int VDRingBuffer::Write(const T *src, int elements) { + VDASSERT(elements >= 0); + + int actual = 0; + while(elements) { + int tc; + void *dst = LockWrite(elements, tc); + + if (!tc) + break; + + memcpy(dst, src, tc*sizeof(T)); + + UnlockWrite(tc); + + actual += tc; + elements -= tc; + src += tc; + } + + return actual; +} + +template +T *VDRingBuffer::LockWrite(int requested, int& actual) { + VDASSERT(requested >= 0); + int nLevelNow = nSize - nLevel; + + if (requested > nLevelNow) + requested = nLevelNow; + + if (requested + nWritePoint > nSize) + requested = nSize - nWritePoint; + + actual = requested; + + return pBuffer + nWritePoint; +} + +template +T *VDRingBuffer::LockWriteAll(int& actual) { + int requested = nSize - nLevel; + + if (requested + nWritePoint > nSize) + requested = nSize - nWritePoint; + + actual = requested; + + return pBuffer + nWritePoint; +} + +template +int VDRingBuffer::UnlockWrite(int actual) { + VDASSERT(actual >= 0); + VDASSERT(nLevel + actual <= nSize); + + int newpt = nWritePoint + actual; + + if (newpt >= nSize) + newpt = 0; + + nWritePoint = newpt; + + return nLevel.add(actual); +} + + + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDScheduler.h b/src/thirdparty/VirtualDub/h/vd2/system/VDScheduler.h index 4a685e25a68..cd2674aaab0 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDScheduler.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDScheduler.h @@ -1,147 +1,147 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSCHEDULER_H -#define f_VD2_SYSTEM_VDSCHEDULER_H - -#include -#include -#include - -class VDSchedulerNode; -class VDSchedulerSuspendNode; -class VDSignal; -class IVDAsyncErrorCallback; - -class VDScheduler { -public: - VDScheduler(); - ~VDScheduler(); - - void setSignal(VDSignal *); - VDSignal *getSignal() { return pWakeupSignal; } - void setSchedulerNode(VDSchedulerNode *pSchedulerNode); - - IVDAsyncErrorCallback *getErrorCallback() const { return mpErrorCB; } - void setErrorCallback(IVDAsyncErrorCallback *pCB) { mpErrorCB = pCB; } - - bool isShuttingDown() const { return mbExitThreads; } - - void BeginShutdown(); ///< Start signaling scheduling threads to exit. - - bool Run(); - bool IdleWait(); ///< Wait because no nodes are ready. Returns false if a thread should exit immediately. - void Ping(); ///< Restart a scheduler thread. This is required when a scheduler thread leaves. - void Lock(); - void Unlock(); - void Reschedule(VDSchedulerNode *); ///< Move node to Ready if Waiting. - void RescheduleFast(VDSchedulerNode *); ///< Same as Reschedule(), but assumes the scheduler is already locked. - void Add(VDSchedulerNode *pNode); ///< Add node to scheduler. - void Remove(VDSchedulerNode *pNode); ///< Remove node from scheduler. - void DumpStatus(); - -protected: - void Repost(VDSchedulerNode *, bool); - - VDCriticalSection csScheduler; - IVDAsyncErrorCallback *mpErrorCB; - VDSignal *pWakeupSignal; - volatile bool mbExitThreads; - VDSchedulerNode *pParentSchedulerNode; - - typedef vdlist tNodeList; - tNodeList listWaiting, listReady; - - typedef vdlist tSuspendList; - tSuspendList listSuspends; -}; - -class VDSchedulerNode : public vdlist::node { -friend class VDScheduler; -public: - int nPriority; - - VDSchedulerNode() : nPriority(0), mpScheduler(NULL) {} - - virtual bool Service()=0; - - virtual void DumpStatus(); - - void Reschedule() { mpScheduler->Reschedule(this); } - void RemoveFromScheduler() { mpScheduler->Remove(this); } - -protected: - VDScheduler *mpScheduler; - volatile bool bRunning; - volatile bool bReschedule; - volatile bool bReady; - volatile bool bCondemned; -}; - -class VDSchedulerSuspendNode : public vdlist::node { -public: - VDSchedulerSuspendNode(VDSchedulerNode *pNode) : mpNode(pNode) {} - - VDSchedulerNode *mpNode; - VDSignal mSignal; -}; - -class VDSchedulerThread : public VDThread { - VDSchedulerThread(const VDSchedulerThread&); - VDSchedulerThread& operator=(const VDSchedulerThread&); -public: - VDSchedulerThread(); - ~VDSchedulerThread(); - - bool Start(VDScheduler *pScheduler); - -protected: - void ThreadRun(); - - VDScheduler *mpScheduler; - uint32 mAffinity; -}; - -class VDSchedulerThreadPool { - VDSchedulerThreadPool(const VDSchedulerThreadPool&); - VDSchedulerThreadPool& operator=(const VDSchedulerThreadPool&); -public: - VDSchedulerThreadPool(); - ~VDSchedulerThreadPool(); - - uint32 GetThreadCount() const { return mThreadCount; } - - void SetPriority(int priority); - - bool Start(VDScheduler *pScheduler); - bool Start(VDScheduler *pScheduler, uint32 threadCount); - -protected: - VDSchedulerThread *mpThreads; - uint32 mThreadCount; - int mThreadPriority; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSCHEDULER_H +#define f_VD2_SYSTEM_VDSCHEDULER_H + +#include +#include +#include + +class VDSchedulerNode; +class VDSchedulerSuspendNode; +class VDSignal; +class IVDAsyncErrorCallback; + +class VDScheduler { +public: + VDScheduler(); + ~VDScheduler(); + + void setSignal(VDSignal *); + VDSignal *getSignal() { return pWakeupSignal; } + void setSchedulerNode(VDSchedulerNode *pSchedulerNode); + + IVDAsyncErrorCallback *getErrorCallback() const { return mpErrorCB; } + void setErrorCallback(IVDAsyncErrorCallback *pCB) { mpErrorCB = pCB; } + + bool isShuttingDown() const { return mbExitThreads; } + + void BeginShutdown(); ///< Start signaling scheduling threads to exit. + + bool Run(); + bool IdleWait(); ///< Wait because no nodes are ready. Returns false if a thread should exit immediately. + void Ping(); ///< Restart a scheduler thread. This is required when a scheduler thread leaves. + void Lock(); + void Unlock(); + void Reschedule(VDSchedulerNode *); ///< Move node to Ready if Waiting. + void RescheduleFast(VDSchedulerNode *); ///< Same as Reschedule(), but assumes the scheduler is already locked. + void Add(VDSchedulerNode *pNode); ///< Add node to scheduler. + void Remove(VDSchedulerNode *pNode); ///< Remove node from scheduler. + void DumpStatus(); + +protected: + void Repost(VDSchedulerNode *, bool); + + VDCriticalSection csScheduler; + IVDAsyncErrorCallback *mpErrorCB; + VDSignal *pWakeupSignal; + volatile bool mbExitThreads; + VDSchedulerNode *pParentSchedulerNode; + + typedef vdlist tNodeList; + tNodeList listWaiting, listReady; + + typedef vdlist tSuspendList; + tSuspendList listSuspends; +}; + +class VDSchedulerNode : public vdlist::node { +friend class VDScheduler; +public: + int nPriority; + + VDSchedulerNode() : nPriority(0), mpScheduler(NULL) {} + + virtual bool Service()=0; + + virtual void DumpStatus(); + + void Reschedule() { mpScheduler->Reschedule(this); } + void RemoveFromScheduler() { mpScheduler->Remove(this); } + +protected: + VDScheduler *mpScheduler; + volatile bool bRunning; + volatile bool bReschedule; + volatile bool bReady; + volatile bool bCondemned; +}; + +class VDSchedulerSuspendNode : public vdlist::node { +public: + VDSchedulerSuspendNode(VDSchedulerNode *pNode) : mpNode(pNode) {} + + VDSchedulerNode *mpNode; + VDSignal mSignal; +}; + +class VDSchedulerThread : public VDThread { + VDSchedulerThread(const VDSchedulerThread&); + VDSchedulerThread& operator=(const VDSchedulerThread&); +public: + VDSchedulerThread(); + ~VDSchedulerThread(); + + bool Start(VDScheduler *pScheduler); + +protected: + void ThreadRun(); + + VDScheduler *mpScheduler; + uint32 mAffinity; +}; + +class VDSchedulerThreadPool { + VDSchedulerThreadPool(const VDSchedulerThreadPool&); + VDSchedulerThreadPool& operator=(const VDSchedulerThreadPool&); +public: + VDSchedulerThreadPool(); + ~VDSchedulerThreadPool(); + + uint32 GetThreadCount() const { return mThreadCount; } + + void SetPriority(int priority); + + bool Start(VDScheduler *pScheduler); + bool Start(VDScheduler *pScheduler, uint32 threadCount); + +protected: + VDSchedulerThread *mpThreads; + uint32 mThreadCount; + int mThreadPriority; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDString.h b/src/thirdparty/VirtualDub/h/vd2/system/VDString.h index 997b3964221..01ec217df69 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDString.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDString.h @@ -1,1264 +1,1264 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTRING_H -#define f_VD2_SYSTEM_VDSTRING_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -class VDStringSpanA { -public: - typedef char value_type; - typedef uint32 size_type; - typedef ptrdiff_t difference_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type * pointer; - typedef const value_type * const_pointer; - typedef pointer iterator; - typedef const_pointer const_iterator; - - static const size_type npos = (size_type)-1; - - VDStringSpanA() - : mpBegin(const_cast(sNull)) - , mpEnd(const_cast(sNull)) - { - } - - explicit VDStringSpanA(const value_type *s) - : mpBegin(const_cast(s)) - , mpEnd(const_cast(s) + strlen(s)) - { - } - - VDStringSpanA(const value_type *s, const value_type *t) - : mpBegin(const_cast(s)) - , mpEnd(const_cast(t)) - { - } - - // 21.3.2 iterators - const_iterator begin() const { return mpBegin; } - const_iterator end() const { return mpEnd; } - - // 21.3.3 capacity - size_type size() const { return (size_type)(mpEnd - mpBegin); } - size_type length() const { return (size_type)(mpEnd - mpBegin); } - bool empty() const { return mpBegin == mpEnd; } - - // 21.3.4 element access - const_reference operator[](size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - const_reference at(size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - - const_reference front() const { VDASSERT(mpBegin != mpEnd); return *mpBegin; } - const_reference back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } - - // 21.3.6 string operations - const_pointer data() const { return mpBegin; } - - size_type copy(value_type *dst, size_type n, size_type pos = 0) const { - size_type len = (size_type)(mpEnd - mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - memcpy(dst, mpBegin + pos, n*sizeof(value_type)); - return n; - } - - size_type find(value_type c, size_type pos = 0) const { - VDASSERT(pos <= (size_type)(mpEnd - mpBegin)); - const void *p = memchr(mpBegin + pos, c, mpEnd - (mpBegin + pos)); - - return p ? (size_type)((const value_type *)p - mpBegin) : npos; - } - - size_type find_last_of(value_type c) const { - const value_type *s = mpEnd; - - while(s != mpBegin) { - --s; - - if (*s == c) - return (size_type)(s - mpBegin); - } - - return npos; - } - - int compare(const VDStringSpanA& s) const { - size_type l1 = (size_type)(mpEnd - mpBegin); - size_type l2 = (size_type)(s.mpEnd - s.mpBegin); - size_type lm = l1 < l2 ? l1 : l2; - - int r = memcmp(mpBegin, s.mpBegin, lm); - - if (!r && l1 != l2) - r = (int)mpBegin[lm] - (int)s.mpBegin[lm]; - - return r; - } - - int comparei(const char *s) const { - return comparei(VDStringSpanA(s)); - } - - int comparei(const VDStringSpanA& s) const { - size_type l1 = (size_type)(mpEnd - mpBegin); - size_type l2 = (size_type)(s.mpEnd - s.mpBegin); - size_type lm = l1 < l2 ? l1 : l2; - - const char *p = mpBegin; - const char *q = s.mpBegin; - - while(lm--) { - const unsigned char c = tolower((unsigned char)*p++); - const unsigned char d = tolower((unsigned char)*q++); - - if (c != d) - return (int)c - (int)d; - } - - return (int)l1 - (int)l2; - } - - const VDStringSpanA trim(const value_type *s) const { - bool flags[256]={false}; - - while(value_type c = *s++) - flags[(unsigned char)c] = true; - - const value_type *p = mpBegin; - const value_type *q = mpEnd; - - while(p != q && flags[*p]) - ++p; - - while(p != q && flags[q[-1]]) - --q; - - return VDStringSpanA(p, q); - } - - const VDStringSpanA subspan(size_type pos = 0, size_type n = npos) const { - - size_type len = (size_type)(mpEnd - mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - value_type *p = mpBegin + pos; - return VDStringSpanA(p, p+n); - } - -protected: - friend bool operator==(const VDStringSpanA& x, const VDStringSpanA& y); - friend bool operator==(const VDStringSpanA& x, const char *y); - - value_type *mpBegin; - value_type *mpEnd; - - static const value_type sNull[1]; -}; - -inline bool operator==(const VDStringSpanA& x, const VDStringSpanA& y) { VDStringSpanA::size_type len = (VDStringSpanA::size_type)(x.mpEnd - x.mpBegin); return len == (VDStringSpanA::size_type)(y.mpEnd - y.mpBegin) && !memcmp(x.mpBegin, y.mpBegin, len*sizeof(char)); } -inline bool operator==(const VDStringSpanA& x, const char *y) { size_t len = strlen(y); return len == (size_t)(x.mpEnd - x.mpBegin) && !memcmp(x.mpBegin, y, len*sizeof(char)); } -inline bool operator==(const char *x, const VDStringSpanA& y) { return y == x; } - -inline bool operator!=(const VDStringSpanA& x, const VDStringSpanA& y) { return !(x == y); } -inline bool operator!=(const VDStringSpanA& x, const char *y) { return !(x == y); } -inline bool operator!=(const char *x, const VDStringSpanA& y) { return !(y == x); } - -inline bool operator<(const VDStringSpanA& x, const VDStringSpanA& y) { - return x.compare(y) < 0; -} - -inline bool operator>(const VDStringSpanA& x, const VDStringSpanA& y) { - return x.compare(y) > 0; -} - -inline bool operator<=(const VDStringSpanA& x, const VDStringSpanA& y) { - return x.compare(y) <= 0; -} - -inline bool operator>=(const VDStringSpanA& x, const VDStringSpanA& y) { - return x.compare(y) >= 0; -} - -class VDStringRefA : public VDStringSpanA { -public: - typedef VDStringRefA this_type; - - VDStringRefA() { - } - - explicit VDStringRefA(const value_type *s) - : VDStringSpanA(s) - { - } - - explicit VDStringRefA(const VDStringSpanA& s) - : VDStringSpanA(s) - { - } - - VDStringRefA(const value_type *s, const value_type *t) - : VDStringSpanA(s, t) - { - } - - this_type& operator=(const value_type *s) { - assign(s); - return *this; - } - - this_type& operator=(const VDStringSpanA& str) { - assign(str); - return *this; - } - - void assign(const value_type *s) { - static_cast(*this) = VDStringSpanA(s); - } - - void assign(const value_type *s, const value_type *t) { - static_cast(*this) = VDStringSpanA(s, t); - } - - void assign(const VDStringSpanA& s) { - static_cast(*this) = s; - } - - void clear() { - mpBegin = mpEnd = NULL; - } - - bool split(value_type c, VDStringRefA& token) { - size_type pos = find(c); - - if (pos == npos) - return false; - - token = subspan(0, pos); - mpBegin += pos+1; - return true; - } -}; - -class VDStringA : public VDStringSpanA { -public: - typedef VDStringA this_type; - - // 21.3.1 construct/copy/destroy - - VDStringA() - : mpEOS(const_cast(sNull)) - { - } - - VDStringA(const VDStringSpanA& x) - : mpEOS(const_cast(sNull)) - { - assign(x.begin(), x.end()); - } - - VDStringA(const this_type& x) - : mpEOS(const_cast(sNull)) - { - assign(x); - } - - explicit VDStringA(const value_type *s) - : mpEOS(const_cast(sNull)) - { - assign(s); - } - - explicit VDStringA(size_type n) - : mpEOS(const_cast(sNull)) - { - resize(n); - } - - VDStringA(const value_type *s, size_type n) - : mpEOS(const_cast(sNull)) - { - assign(s, n); - } - - VDStringA(const value_type *s, const value_type *t) - : mpEOS(const_cast(sNull)) - { - assign(s, t); - } - - ~VDStringA() { - if (mpBegin != sNull) - delete[] mpBegin; - } - - this_type& operator=(const value_type *s) { - assign(s); - return *this; - } - - this_type& operator=(const this_type& str) { - assign(str); - return *this; - } - - this_type& operator=(const VDStringSpanA& str) { - assign(str); - return *this; - } - - // 21.3.2 iterators - using VDStringSpanA::begin; - using VDStringSpanA::end; - - iterator begin() { return mpBegin; } - iterator end() { return mpEnd; } - - // 21.3.3 capacity (COMPLETE) - void resize(size_type n) { - size_type current = (size_type)(mpEnd - mpBegin); - - if (n < current) { - mpEnd = mpBegin + n; - mpEnd[0] = 0; - } else if (n > current) - resize_slow(n, current); - } - - void resize(size_type n, value_type v) { - size_type current = (size_type)(mpEnd - mpBegin); - - if (n < current) { - mpEnd = mpBegin + n; - mpEnd[0] = 0; - } else if (n > current) - resize_slow(n, current, v); - } - - size_type capacity() const { return (size_type)(mpEOS - mpBegin); } - - void reserve(size_type n) { - size_type current = (size_type)(mpEOS - mpBegin); - - if (n > current) - reserve_slow(n, current); - } - - void clear() { - if (mpEnd != mpBegin) { - mpEnd = mpBegin; - mpEnd[0] = 0; - } - } - - // 21.3.4 element access - using VDStringSpanA::operator[]; - using VDStringSpanA::at; - using VDStringSpanA::front; - using VDStringSpanA::back; - - reference operator[](size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - reference at(size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - reference front() { VDASSERT(mpBegin != mpEnd); return *mpBegin; } - reference back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } - - // 21.3.5 modifiers - this_type& operator+=(const this_type& str) { - return append(str.mpBegin, str.mpEnd); - } - - this_type& operator+=(const value_type *s) { - return append(s, s+strlen(s)); - } - - this_type& operator+=(value_type c) { - if (mpEnd == mpEOS) - push_back_extend(); - - *mpEnd++ = c; - *mpEnd = 0; - return *this; - } - - this_type& append(const this_type& str) { - return append(str.mpBegin, str.mpEnd); - } - - this_type& append(const this_type& str, size_type pos, size_type n) { - size_type len = (size_type)(str.mpEnd - str.mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - return append(str.mpBegin + pos, str.mpBegin + pos + n); - } - - this_type& append(const value_type *s, size_type n) { - return append(s, s+n); - } - - this_type& append(const value_type *s) { - return append(s, s+strlen(s)); - } - - this_type& append(const value_type *s, const value_type *t) { - if (s != t) { - size_type current_size = (size_type)(mpEnd - mpBegin); - size_type current_capacity = (size_type)(mpEOS - mpBegin); - size_type n = (size_type)(t - s); - - if (current_capacity - current_size < n) - reserve_amortized_slow(n, current_size, current_capacity); - - memcpy(mpBegin + current_size, s, n*sizeof(value_type)); - mpEnd += n; - *mpEnd = 0; - } - return *this; - } - - void push_back(const value_type c) { - if (mpEnd == mpEOS) - push_back_extend(); - - *mpEnd++ = c; - *mpEnd = 0; - } - - void pop_back() { - --mpEnd; - *mpEnd = 0; - } - - this_type& assign(const VDStringSpanA& str) { - return assign(str.begin(), str.end()); - } - - this_type& assign(const this_type& str) { - return assign(str.mpBegin, str.mpEnd); - } - - this_type& assign(const this_type& str, size_type pos, size_type n) { - size_type len = (size_type)(str.mpEnd - str.mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - return assign(str.mpBegin + pos, str.mpBegin + pos + n); - } - - this_type& assign(const value_type *s, size_type n) { - return assign(s, s+n); - } - - this_type& assign(const value_type *s) { - return assign(s, s+strlen(s)); - } - - this_type& assign(size_type n, value_type c) { - size_type current_capacity = (size_type)(mpEOS - mpBegin); - - if (current_capacity < n) - reserve_slow(n, current_capacity); - - if (mpBegin != sNull) { - mpEnd = mpBegin; - while(n--) - *mpEnd++ = c; - } - - return *this; - } - - this_type& assign(const value_type *s, const value_type *t) { - size_type current_capacity = (size_type)(mpEOS - mpBegin); - size_type n = (size_type)(t - s); - - if (current_capacity < n) - reserve_slow(n, current_capacity); - - if (mpBegin != sNull) { - memcpy(mpBegin, s, sizeof(value_type)*n); - mpEnd = mpBegin + n; - *mpEnd = 0; - } - - return *this; - } - - this_type& insert(iterator it, value_type c) { - if (mpEnd == mpEOS) { - size_type pos = (size_type)(it - mpBegin); - push_back_extend(); - it = mpBegin + pos; - } - - memmove(it + 1, it, (mpEnd - it + 1)*sizeof(value_type)); - *it = c; - ++mpEnd; - return *this; - } - - this_type& erase(size_type pos = 0, size_type n = npos) { - size_type len = (size_type)(mpEnd - mpBegin); - - VDASSERT(pos <= len); - len -= pos; - if (n > len) - n = len; - - if (n) { - size_type pos2 = pos + n; - memmove(mpBegin + pos, mpBegin + pos2, (len + 1 - n)*sizeof(value_type)); - mpEnd -= n; - } - - return *this; - } - - iterator erase(iterator x) { - VDASSERT(x != mpEnd); - - memmove(x, x+1, (mpEnd - x)*sizeof(value_type)); - --mpEnd; - return x; - } - - iterator erase(iterator first, iterator last) { - VDASSERT(last >= first); - - memmove(first, last, ((mpEnd - last) + 1)*sizeof(value_type)); - mpEnd -= (last - first); - return first; - } - - this_type& replace(size_type pos, size_type n1, const value_type *s, size_type n2) { - size_type len = (size_type)(mpEnd - mpBegin); - - VDASSERT(pos <= len); - size_type limit = len - pos; - if (n1 > limit) - n1 = limit; - - size_type len2 = len - n1 + n2; - size_type current_capacity = (size_type)(mpEOS - mpBegin); - - if (current_capacity < len2) - reserve_slow(len2, current_capacity); - - memmove(mpBegin + pos + n2, mpBegin + pos + n1, (limit - n1 + 1) * sizeof(value_type)); - memcpy(mpBegin + pos, s, n2*sizeof(value_type)); - mpEnd = mpBegin + len2; - return *this; - } - - void swap(this_type& x) { - value_type *p; - - p = mpBegin; mpBegin = x.mpBegin; x.mpBegin = p; - p = mpEnd; mpEnd = x.mpEnd; x.mpEnd = p; - p = mpEOS; mpEOS = x.mpEOS; x.mpEOS = p; - } - - // 21.3.6 string operations - const_pointer c_str() const { return mpBegin; } - - this_type& sprintf(const value_type *format, ...); - this_type& append_sprintf(const value_type *format, ...); - this_type& append_vsprintf(const value_type *format, va_list val); - - void move_from(VDStringA& src); - -protected: - void push_back_extend(); - void resize_slow(size_type n, size_type current_size); - void resize_slow(size_type n, size_type current_size, value_type c); - void reserve_slow(size_type n, size_type current_capacity); - void reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity); - - char *mpEOS; -}; - -/////////////////////////////////////////////////////////////////////////// - -inline VDStringA operator+(const VDStringA& str, const VDStringA& s) { - VDStringA result; - result.reserve((VDStringA::size_type)(str.size() + s.size())); - result.assign(str); - result.append(s); - return result; -} - -inline VDStringA operator+(const VDStringA& str, const char *s) { - VDStringA result; - result.reserve((VDStringA::size_type)(str.size() + strlen(s))); - result.assign(str); - result.append(s); - return result; -} - -inline VDStringA operator+(const VDStringA& str, char c) { - VDStringA result; - result.reserve(str.size() + 1); - result.assign(str); - result += c; - return result; -} - -// Start patch MPC-HC -/* -namespace std { - template<> - struct less : binary_function { - bool operator()(const VDStringA& x, const VDStringA& y) const { - return x.compare(y) < 0; - } - }; -} -*/ -// End patch MPC-HC - -/////////////////////////////////////////////////////////////////////////// - -class VDStringSpanW { -public: - typedef wchar_t value_type; - typedef uint32 size_type; - typedef ptrdiff_t difference_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type * pointer; - typedef const value_type * const_pointer; - typedef pointer iterator; - typedef const_pointer const_iterator; - - static const size_type npos = (size_type)-1; - - VDStringSpanW() - : mpBegin(const_cast(sNull)) - , mpEnd(const_cast(sNull)) - { - } - - explicit VDStringSpanW(const value_type *s) - : mpBegin(const_cast(s)) - , mpEnd(const_cast(s) + wcslen(s)) - { - } - - VDStringSpanW(const value_type *s, const value_type *t) - : mpBegin(const_cast(s)) - , mpEnd(const_cast(t)) - { - } - - // 21.3.2 iterators - const_iterator begin() const { return mpBegin; } - const_iterator end() const { return mpEnd; } - - // 21.3.3 capacity - size_type size() const { return (size_type)(mpEnd - mpBegin); } - size_type length() const { return (size_type)(mpEnd - mpBegin); } - bool empty() const { return mpBegin == mpEnd; } - - // 21.3.4 element access - const_reference operator[](size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - const_reference at(size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - - const_reference front() const { VDASSERT(mpBegin != mpEnd); return *mpBegin; } - const_reference back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } - - // 21.3.6 string operations - const_pointer data() const { return mpBegin; } - - size_type copy(value_type *dst, size_type n, size_type pos = 0) const { - size_type len = (size_type)(mpEnd - mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - memcpy(dst, mpBegin + pos, n*sizeof(value_type)); - return n; - } - - size_type find(value_type c, size_type pos = 0) const { - VDASSERT(pos <= (size_type)(mpEnd - mpBegin)); - const void *p = wmemchr(mpBegin + pos, c, mpEnd - (mpBegin + pos)); - - return p ? (size_type)((const value_type *)p - mpBegin) : npos; - } - - int compare(const VDStringSpanW& s) const { - size_type l1 = (size_type)(mpEnd - mpBegin); - size_type l2 = (size_type)(s.mpEnd - s.mpBegin); - size_type lm = l1 < l2 ? l1 : l2; - - for(size_type i = 0; i < lm; ++i) { - if (mpBegin[i] != s.mpBegin[i]) - return mpBegin[i] < s.mpBegin[i] ? -1 : +1; - } - - if (l1 == l2) - return 0; - - return l1 < l2 ? -1 : +1; - } - - int comparei(const wchar_t *s) const { - return comparei(VDStringSpanW(s)); - } - - int comparei(const VDStringSpanW& s) const { - size_type l1 = (size_type)(mpEnd - mpBegin); - size_type l2 = (size_type)(s.mpEnd - s.mpBegin); - size_type lm = l1 < l2 ? l1 : l2; - - for(size_type i = 0; i < lm; ++i) { - wint_t c = towlower(mpBegin[i]); - wint_t d = towlower(s.mpBegin[i]); - - if (c != d) - return c < d ? -1 : +1; - } - - if (l1 == l2) - return 0; - - return l1 < l2 ? -1 : +1; - } - - // extensions - const VDStringSpanW subspan(size_type pos, size_type n) const { - size_type len = (size_type)(mpEnd - mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - value_type *p = mpBegin + pos; - return VDStringSpanW(p, p+n); - } - -protected: - friend class VDStringW; - friend bool operator==(const VDStringSpanW& x, const VDStringSpanW& y); - friend bool operator==(const VDStringSpanW& x, const wchar_t *y); - - value_type *mpBegin; - value_type *mpEnd; - - static const value_type sNull[1]; -}; - -inline bool operator==(const VDStringSpanW& x, const VDStringSpanW& y) { VDStringA::size_type len = (VDStringSpanW::size_type)(x.mpEnd - x.mpBegin); return len == (VDStringSpanW::size_type)(y.mpEnd - y.mpBegin) && !memcmp(x.mpBegin, y.mpBegin, len*sizeof(wchar_t)); } -inline bool operator==(const VDStringSpanW& x, const wchar_t *y) { size_t len = wcslen(y); return len == (size_t)(x.mpEnd - x.mpBegin) && !memcmp(x.mpBegin, y, len*sizeof(wchar_t)); } -inline bool operator==(const wchar_t *x, const VDStringSpanW& y) { return y == x; } - -inline bool operator!=(const VDStringSpanW& x, const VDStringSpanW& y) { return !(x == y); } -inline bool operator!=(const VDStringSpanW& x, const wchar_t *y) { return !(x == y); } -inline bool operator!=(const wchar_t *x, const VDStringSpanW& y) { return !(y == x); } - -inline bool operator<(const VDStringSpanW& x, const VDStringSpanW& y) { - return x.compare(y) < 0; -} - -inline bool operator>(const VDStringSpanW& x, const VDStringSpanW& y) { - return x.compare(y) > 0; -} - -inline bool operator<=(const VDStringSpanW& x, const VDStringSpanW& y) { - return x.compare(y) <= 0; -} - -inline bool operator>=(const VDStringSpanW& x, const VDStringSpanW& y) { - return x.compare(y) >= 0; -} - -class VDStringRefW : public VDStringSpanW { -public: - typedef VDStringRefW this_type; - - VDStringRefW() { - } - - explicit VDStringRefW(const value_type *s) - : VDStringSpanW(s) - { - } - - explicit VDStringRefW(const VDStringSpanW& s) - : VDStringSpanW(s) - { - } - - VDStringRefW(const value_type *s, const value_type *t) - : VDStringSpanW(s, t) - { - } - - this_type& operator=(const value_type *s) { - assign(s); - return *this; - } - - this_type& operator=(const VDStringSpanW& str) { - assign(str); - return *this; - } - - void assign(const value_type *s) { - static_cast(*this) = VDStringSpanW(s); - } - - void assign(const value_type *s, const value_type *t) { - static_cast(*this) = VDStringSpanW(s, t); - } - - void assign(const VDStringSpanW& s) { - static_cast(*this) = s; - } - - void clear() { - mpBegin = mpEnd = NULL; - } - - bool split(value_type c, VDStringRefW& token) { - size_type pos = find(c); - - if (pos == npos) - return false; - - token = subspan(0, pos); - mpBegin += pos+1; - return true; - } -}; - -class VDStringW : public VDStringSpanW { -public: - typedef VDStringW this_type; - - // 21.3.1 construct/copy/destroy - - VDStringW() - : mpEOS(const_cast(sNull)) - { - } - - VDStringW(const VDStringSpanW& x) - : mpEOS(const_cast(sNull)) - { - assign(x.begin(), x.end()); - } - - VDStringW(const this_type& x) - : mpEOS(const_cast(sNull)) - { - assign(x); - } - - explicit VDStringW(const value_type *s) - : mpEOS(const_cast(sNull)) - { - assign(s); - } - - explicit VDStringW(size_type n) - : mpEOS(const_cast(sNull)) - { - resize(n); - } - - VDStringW(const value_type *s, size_type n) - : mpEOS(const_cast(sNull)) - { - assign(s, n); - } - - VDStringW(const value_type *s, const value_type *t) - : mpEOS(const_cast(sNull)) - { - assign(s, t); - } - - ~VDStringW() { - if (mpBegin != sNull) - delete[] mpBegin; - } - - this_type& operator=(const wchar_t *s) { - assign(s); - return *this; - } - - this_type& operator=(const this_type& str) { - assign(str); - return *this; - } - - // 21.3.2 iterators - using VDStringSpanW::begin; - using VDStringSpanW::end; - iterator begin() { return mpBegin; } - iterator end() { return mpEnd; } - - // 21.3.3 capacity (COMPLETE) - void resize(size_type n) { - size_type current = (size_type)(mpEnd - mpBegin); - - if (n < current) { - mpEnd = mpBegin + n; - mpEnd[0] = 0; - } else if (n > current) - resize_slow(n, current); - } - - void resize(size_type n, value_type v) { - size_type current = (size_type)(mpEnd - mpBegin); - - if (n < current) { - mpEnd = mpBegin + n; - mpEnd[0] = 0; - } else if (n > current) - resize_slow(n, current); - wmemset(mpBegin, v, n); - } - - size_type capacity() const { return (size_type)(mpEOS - mpBegin); } - - void reserve(size_type n) { - size_type current = (size_type)(mpEOS - mpBegin); - - if (n > current) - reserve_slow(n, current); - } - - void clear() { - if (mpEnd != mpBegin) { - mpEnd = mpBegin; - mpEnd[0] = 0; - } - } - - // 21.3.4 element access - using VDStringSpanW::operator[]; - using VDStringSpanW::at; - using VDStringSpanW::front; - using VDStringSpanW::back; - reference operator[](size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - reference at(size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - reference front() { VDASSERT(mpBegin != mpEnd); return *mpBegin; } - reference back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } - - // 21.3.5 modifiers - this_type& operator+=(const this_type& str) { - return append(str.mpBegin, str.mpEnd); - } - - this_type& operator+=(const value_type *s) { - return append(s, s+wcslen(s)); - } - - this_type& operator+=(value_type c) { - if (mpEnd == mpEOS) - push_back_extend(); - - *mpEnd++ = c; - *mpEnd = 0; - return *this; - } - - this_type& append(const this_type& str) { - return append(str.mpBegin, str.mpEnd); - } - - this_type& append(const this_type& str, size_type pos, size_type n) { - size_type len = (size_type)(str.mpEnd - str.mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - return append(str.mpBegin + pos, str.mpBegin + pos + n); - } - - this_type& append(const value_type *s, size_type n) { - return append(s, s+n); - } - - this_type& append(const value_type *s) { - return append(s, s+wcslen(s)); - } - - this_type& append(const value_type *s, const value_type *t) { - if (s != t) { - size_type current_size = (size_type)(mpEnd - mpBegin); - size_type current_capacity = (size_type)(mpEOS - mpBegin); - size_type n = (size_type)(t - s); - - if (current_capacity - current_size < n) - reserve_amortized_slow(n, current_size, current_capacity); - - memcpy(mpBegin + current_size, s, n*sizeof(value_type)); - mpEnd += n; - *mpEnd = 0; - } - return *this; - } - - void push_back(const value_type c) { - if (mpEnd == mpEOS) - push_back_extend(); - - *mpEnd++ = c; - *mpEnd = 0; - } - - void pop_back() { - --mpEnd; - *mpEnd = 0; - } - - this_type& assign(const VDStringSpanW& str) { - return assign(str.mpBegin, str.mpEnd); - } - - this_type& assign(const VDStringSpanW& str, size_type pos, size_type n) { - size_type len = (size_type)(str.mpEnd - str.mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - return assign(str.mpBegin + pos, str.mpBegin + pos + n); - } - - this_type& assign(const value_type *s, size_type n) { - return assign(s, s+n); - } - - this_type& assign(const value_type *s) { - return assign(s, s+wcslen(s)); - } - - this_type& assign(size_type n, value_type c) { - size_type current_capacity = (size_type)(mpEOS - mpBegin); - - if (current_capacity < n) - reserve_slow(n, current_capacity); - - if (mpBegin != sNull) { - mpEnd = mpBegin; - while(n--) - *mpEnd++ = c; - } - - return *this; - } - - this_type& assign(const value_type *s, const value_type *t) { - size_type current_capacity = (size_type)(mpEOS - mpBegin); - size_type n = (size_type)(t - s); - - if (current_capacity < n) - reserve_slow(n, current_capacity); - - if (mpBegin != sNull) { - memcpy(mpBegin, s, sizeof(value_type)*n); - mpEnd = mpBegin + n; - *mpEnd = 0; - } - - return *this; - } - - this_type& insert(iterator it, value_type c) { - if (mpEnd == mpEOS) { - size_type pos = (size_type)(it - mpBegin); - push_back_extend(); - it = mpBegin + pos; - } - - memmove(it + 1, it, (mpEnd - it + 1)*sizeof(value_type)); - *it = c; - ++mpEnd; - return *this; - } - - this_type& erase(size_type pos = 0, size_type n = npos) { - size_type len = (size_type)(mpEnd - mpBegin); - - VDASSERT(pos <= len); - len -= pos; - if (n > len) - n = len; - - if (n) { - size_type pos2 = pos + n; - memmove(mpBegin + pos, mpBegin + pos2, (len + 1 - n)*sizeof(value_type)); - mpEnd -= n; - } - - return *this; - } - - iterator erase(iterator x) { - VDASSERT(x != mpEnd); - - memmove(x, x+1, (mpEnd - x)*sizeof(value_type)); - --mpEnd; - return x; - } - - iterator erase(iterator first, iterator last) { - VDASSERT(last >= first); - - memmove(first, last, ((mpEnd - last) + 1)*sizeof(value_type)); - mpEnd -= (last - first); - return first; - } - - this_type& replace(size_type pos, size_type n1, const value_type *s, size_type n2) { - size_type len = (size_type)(mpEnd - mpBegin); - - VDASSERT(pos <= len); - size_type limit = len - pos; - if (n1 > limit) - n1 = limit; - - size_type len2 = len - n1 + n2; - size_type current_capacity = (size_type)(mpEOS - mpBegin); - - if (current_capacity < len2) - reserve_slow(len2, current_capacity); - - memmove(mpBegin + pos + n2, mpBegin + pos + n1, (limit - n1 + 1) * sizeof(value_type)); - memcpy(mpBegin + pos, s, n2*sizeof(value_type)); - mpEnd = mpBegin + len2; - return *this; - } - - void swap(this_type& x) { - std::swap(mpBegin, x.mpBegin); - std::swap(mpEnd, x.mpEnd); - std::swap(mpEOS, x.mpEOS); - } - - void swap(this_type&& x) { - std::swap(mpBegin, x.mpBegin); - std::swap(mpEnd, x.mpEnd); - std::swap(mpEOS, x.mpEOS); - } - - // 21.3.6 string operations - const_pointer c_str() const { return mpBegin; } - - this_type& sprintf(const value_type *format, ...); - this_type& append_sprintf(const value_type *format, ...); - this_type& append_vsprintf(const value_type *format, va_list val); - - void move_from(VDStringW& src); - -protected: - void push_back_extend(); - void resize_slow(size_type n, size_type current_size); - void reserve_slow(size_type n, size_type current_capacity); - void reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity); - - value_type *mpEOS; -}; - -/////////////////////////////////////////////////////////////////////////// - -inline VDStringW operator+(const VDStringW& str, const VDStringW& s) { - VDStringW result; - result.reserve((VDStringA::size_type)(str.size() + s.size())); - result.assign(str); - result.append(s); - return result; -} - -inline VDStringW operator+(const VDStringW& str, const wchar_t *s) { - VDStringW result; - result.reserve((VDStringA::size_type)(str.size() + wcslen(s))); - result.assign(str); - result.append(s); - return result; -} - -inline VDStringW operator+(const VDStringW& str, wchar_t c) { - VDStringW result; - result.reserve(str.size() + 1); - result.assign(str); - result += c; - return result; -} - -/////////////////////////////////////////////////////////////////////////// - -typedef VDStringA VDString; - -template<> VDStringA *vdmove_forward(VDStringA *src1, VDStringA *src2, VDStringA *dst); -template<> VDStringW *vdmove_forward(VDStringW *src1, VDStringW *src2, VDStringW *dst); -template<> VDStringA *vdmove_backward(VDStringA *src1, VDStringA *src2, VDStringA *dst); -template<> VDStringW *vdmove_backward(VDStringW *src1, VDStringW *src2, VDStringW *dst); - -VDMOVE_CAPABLE(VDStringA); -VDMOVE_CAPABLE(VDStringW); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTRING_H +#define f_VD2_SYSTEM_VDSTRING_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +class VDStringSpanA { +public: + typedef char value_type; + typedef uint32 size_type; + typedef ptrdiff_t difference_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type * pointer; + typedef const value_type * const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + + static const size_type npos = (size_type)-1; + + VDStringSpanA() + : mpBegin(const_cast(sNull)) + , mpEnd(const_cast(sNull)) + { + } + + explicit VDStringSpanA(const value_type *s) + : mpBegin(const_cast(s)) + , mpEnd(const_cast(s) + strlen(s)) + { + } + + VDStringSpanA(const value_type *s, const value_type *t) + : mpBegin(const_cast(s)) + , mpEnd(const_cast(t)) + { + } + + // 21.3.2 iterators + const_iterator begin() const { return mpBegin; } + const_iterator end() const { return mpEnd; } + + // 21.3.3 capacity + size_type size() const { return (size_type)(mpEnd - mpBegin); } + size_type length() const { return (size_type)(mpEnd - mpBegin); } + bool empty() const { return mpBegin == mpEnd; } + + // 21.3.4 element access + const_reference operator[](size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + const_reference at(size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + + const_reference front() const { VDASSERT(mpBegin != mpEnd); return *mpBegin; } + const_reference back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } + + // 21.3.6 string operations + const_pointer data() const { return mpBegin; } + + size_type copy(value_type *dst, size_type n, size_type pos = 0) const { + size_type len = (size_type)(mpEnd - mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + memcpy(dst, mpBegin + pos, n*sizeof(value_type)); + return n; + } + + size_type find(value_type c, size_type pos = 0) const { + VDASSERT(pos <= (size_type)(mpEnd - mpBegin)); + const void *p = memchr(mpBegin + pos, c, mpEnd - (mpBegin + pos)); + + return p ? (size_type)((const value_type *)p - mpBegin) : npos; + } + + size_type find_last_of(value_type c) const { + const value_type *s = mpEnd; + + while(s != mpBegin) { + --s; + + if (*s == c) + return (size_type)(s - mpBegin); + } + + return npos; + } + + int compare(const VDStringSpanA& s) const { + size_type l1 = (size_type)(mpEnd - mpBegin); + size_type l2 = (size_type)(s.mpEnd - s.mpBegin); + size_type lm = l1 < l2 ? l1 : l2; + + int r = memcmp(mpBegin, s.mpBegin, lm); + + if (!r && l1 != l2) + r = (int)mpBegin[lm] - (int)s.mpBegin[lm]; + + return r; + } + + int comparei(const char *s) const { + return comparei(VDStringSpanA(s)); + } + + int comparei(const VDStringSpanA& s) const { + size_type l1 = (size_type)(mpEnd - mpBegin); + size_type l2 = (size_type)(s.mpEnd - s.mpBegin); + size_type lm = l1 < l2 ? l1 : l2; + + const char *p = mpBegin; + const char *q = s.mpBegin; + + while(lm--) { + const unsigned char c = tolower((unsigned char)*p++); + const unsigned char d = tolower((unsigned char)*q++); + + if (c != d) + return (int)c - (int)d; + } + + return (int)l1 - (int)l2; + } + + const VDStringSpanA trim(const value_type *s) const { + bool flags[256]={false}; + + while(value_type c = *s++) + flags[(unsigned char)c] = true; + + const value_type *p = mpBegin; + const value_type *q = mpEnd; + + while(p != q && flags[*p]) + ++p; + + while(p != q && flags[q[-1]]) + --q; + + return VDStringSpanA(p, q); + } + + const VDStringSpanA subspan(size_type pos = 0, size_type n = npos) const { + + size_type len = (size_type)(mpEnd - mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + value_type *p = mpBegin + pos; + return VDStringSpanA(p, p+n); + } + +protected: + friend bool operator==(const VDStringSpanA& x, const VDStringSpanA& y); + friend bool operator==(const VDStringSpanA& x, const char *y); + + value_type *mpBegin; + value_type *mpEnd; + + static const value_type sNull[1]; +}; + +inline bool operator==(const VDStringSpanA& x, const VDStringSpanA& y) { VDStringSpanA::size_type len = (VDStringSpanA::size_type)(x.mpEnd - x.mpBegin); return len == (VDStringSpanA::size_type)(y.mpEnd - y.mpBegin) && !memcmp(x.mpBegin, y.mpBegin, len*sizeof(char)); } +inline bool operator==(const VDStringSpanA& x, const char *y) { size_t len = strlen(y); return len == (size_t)(x.mpEnd - x.mpBegin) && !memcmp(x.mpBegin, y, len*sizeof(char)); } +inline bool operator==(const char *x, const VDStringSpanA& y) { return y == x; } + +inline bool operator!=(const VDStringSpanA& x, const VDStringSpanA& y) { return !(x == y); } +inline bool operator!=(const VDStringSpanA& x, const char *y) { return !(x == y); } +inline bool operator!=(const char *x, const VDStringSpanA& y) { return !(y == x); } + +inline bool operator<(const VDStringSpanA& x, const VDStringSpanA& y) { + return x.compare(y) < 0; +} + +inline bool operator>(const VDStringSpanA& x, const VDStringSpanA& y) { + return x.compare(y) > 0; +} + +inline bool operator<=(const VDStringSpanA& x, const VDStringSpanA& y) { + return x.compare(y) <= 0; +} + +inline bool operator>=(const VDStringSpanA& x, const VDStringSpanA& y) { + return x.compare(y) >= 0; +} + +class VDStringRefA : public VDStringSpanA { +public: + typedef VDStringRefA this_type; + + VDStringRefA() { + } + + explicit VDStringRefA(const value_type *s) + : VDStringSpanA(s) + { + } + + explicit VDStringRefA(const VDStringSpanA& s) + : VDStringSpanA(s) + { + } + + VDStringRefA(const value_type *s, const value_type *t) + : VDStringSpanA(s, t) + { + } + + this_type& operator=(const value_type *s) { + assign(s); + return *this; + } + + this_type& operator=(const VDStringSpanA& str) { + assign(str); + return *this; + } + + void assign(const value_type *s) { + static_cast(*this) = VDStringSpanA(s); + } + + void assign(const value_type *s, const value_type *t) { + static_cast(*this) = VDStringSpanA(s, t); + } + + void assign(const VDStringSpanA& s) { + static_cast(*this) = s; + } + + void clear() { + mpBegin = mpEnd = NULL; + } + + bool split(value_type c, VDStringRefA& token) { + size_type pos = find(c); + + if (pos == npos) + return false; + + token = subspan(0, pos); + mpBegin += pos+1; + return true; + } +}; + +class VDStringA : public VDStringSpanA { +public: + typedef VDStringA this_type; + + // 21.3.1 construct/copy/destroy + + VDStringA() + : mpEOS(const_cast(sNull)) + { + } + + VDStringA(const VDStringSpanA& x) + : mpEOS(const_cast(sNull)) + { + assign(x.begin(), x.end()); + } + + VDStringA(const this_type& x) + : mpEOS(const_cast(sNull)) + { + assign(x); + } + + explicit VDStringA(const value_type *s) + : mpEOS(const_cast(sNull)) + { + assign(s); + } + + explicit VDStringA(size_type n) + : mpEOS(const_cast(sNull)) + { + resize(n); + } + + VDStringA(const value_type *s, size_type n) + : mpEOS(const_cast(sNull)) + { + assign(s, n); + } + + VDStringA(const value_type *s, const value_type *t) + : mpEOS(const_cast(sNull)) + { + assign(s, t); + } + + ~VDStringA() { + if (mpBegin != sNull) + delete[] mpBegin; + } + + this_type& operator=(const value_type *s) { + assign(s); + return *this; + } + + this_type& operator=(const this_type& str) { + assign(str); + return *this; + } + + this_type& operator=(const VDStringSpanA& str) { + assign(str); + return *this; + } + + // 21.3.2 iterators + using VDStringSpanA::begin; + using VDStringSpanA::end; + + iterator begin() { return mpBegin; } + iterator end() { return mpEnd; } + + // 21.3.3 capacity (COMPLETE) + void resize(size_type n) { + size_type current = (size_type)(mpEnd - mpBegin); + + if (n < current) { + mpEnd = mpBegin + n; + mpEnd[0] = 0; + } else if (n > current) + resize_slow(n, current); + } + + void resize(size_type n, value_type v) { + size_type current = (size_type)(mpEnd - mpBegin); + + if (n < current) { + mpEnd = mpBegin + n; + mpEnd[0] = 0; + } else if (n > current) + resize_slow(n, current, v); + } + + size_type capacity() const { return (size_type)(mpEOS - mpBegin); } + + void reserve(size_type n) { + size_type current = (size_type)(mpEOS - mpBegin); + + if (n > current) + reserve_slow(n, current); + } + + void clear() { + if (mpEnd != mpBegin) { + mpEnd = mpBegin; + mpEnd[0] = 0; + } + } + + // 21.3.4 element access + using VDStringSpanA::operator[]; + using VDStringSpanA::at; + using VDStringSpanA::front; + using VDStringSpanA::back; + + reference operator[](size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + reference at(size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + reference front() { VDASSERT(mpBegin != mpEnd); return *mpBegin; } + reference back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } + + // 21.3.5 modifiers + this_type& operator+=(const this_type& str) { + return append(str.mpBegin, str.mpEnd); + } + + this_type& operator+=(const value_type *s) { + return append(s, s+strlen(s)); + } + + this_type& operator+=(value_type c) { + if (mpEnd == mpEOS) + push_back_extend(); + + *mpEnd++ = c; + *mpEnd = 0; + return *this; + } + + this_type& append(const this_type& str) { + return append(str.mpBegin, str.mpEnd); + } + + this_type& append(const this_type& str, size_type pos, size_type n) { + size_type len = (size_type)(str.mpEnd - str.mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + return append(str.mpBegin + pos, str.mpBegin + pos + n); + } + + this_type& append(const value_type *s, size_type n) { + return append(s, s+n); + } + + this_type& append(const value_type *s) { + return append(s, s+strlen(s)); + } + + this_type& append(const value_type *s, const value_type *t) { + if (s != t) { + size_type current_size = (size_type)(mpEnd - mpBegin); + size_type current_capacity = (size_type)(mpEOS - mpBegin); + size_type n = (size_type)(t - s); + + if (current_capacity - current_size < n) + reserve_amortized_slow(n, current_size, current_capacity); + + memcpy(mpBegin + current_size, s, n*sizeof(value_type)); + mpEnd += n; + *mpEnd = 0; + } + return *this; + } + + void push_back(const value_type c) { + if (mpEnd == mpEOS) + push_back_extend(); + + *mpEnd++ = c; + *mpEnd = 0; + } + + void pop_back() { + --mpEnd; + *mpEnd = 0; + } + + this_type& assign(const VDStringSpanA& str) { + return assign(str.begin(), str.end()); + } + + this_type& assign(const this_type& str) { + return assign(str.mpBegin, str.mpEnd); + } + + this_type& assign(const this_type& str, size_type pos, size_type n) { + size_type len = (size_type)(str.mpEnd - str.mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + return assign(str.mpBegin + pos, str.mpBegin + pos + n); + } + + this_type& assign(const value_type *s, size_type n) { + return assign(s, s+n); + } + + this_type& assign(const value_type *s) { + return assign(s, s+strlen(s)); + } + + this_type& assign(size_type n, value_type c) { + size_type current_capacity = (size_type)(mpEOS - mpBegin); + + if (current_capacity < n) + reserve_slow(n, current_capacity); + + if (mpBegin != sNull) { + mpEnd = mpBegin; + while(n--) + *mpEnd++ = c; + } + + return *this; + } + + this_type& assign(const value_type *s, const value_type *t) { + size_type current_capacity = (size_type)(mpEOS - mpBegin); + size_type n = (size_type)(t - s); + + if (current_capacity < n) + reserve_slow(n, current_capacity); + + if (mpBegin != sNull) { + memcpy(mpBegin, s, sizeof(value_type)*n); + mpEnd = mpBegin + n; + *mpEnd = 0; + } + + return *this; + } + + this_type& insert(iterator it, value_type c) { + if (mpEnd == mpEOS) { + size_type pos = (size_type)(it - mpBegin); + push_back_extend(); + it = mpBegin + pos; + } + + memmove(it + 1, it, (mpEnd - it + 1)*sizeof(value_type)); + *it = c; + ++mpEnd; + return *this; + } + + this_type& erase(size_type pos = 0, size_type n = npos) { + size_type len = (size_type)(mpEnd - mpBegin); + + VDASSERT(pos <= len); + len -= pos; + if (n > len) + n = len; + + if (n) { + size_type pos2 = pos + n; + memmove(mpBegin + pos, mpBegin + pos2, (len + 1 - n)*sizeof(value_type)); + mpEnd -= n; + } + + return *this; + } + + iterator erase(iterator x) { + VDASSERT(x != mpEnd); + + memmove(x, x+1, (mpEnd - x)*sizeof(value_type)); + --mpEnd; + return x; + } + + iterator erase(iterator first, iterator last) { + VDASSERT(last >= first); + + memmove(first, last, ((mpEnd - last) + 1)*sizeof(value_type)); + mpEnd -= (last - first); + return first; + } + + this_type& replace(size_type pos, size_type n1, const value_type *s, size_type n2) { + size_type len = (size_type)(mpEnd - mpBegin); + + VDASSERT(pos <= len); + size_type limit = len - pos; + if (n1 > limit) + n1 = limit; + + size_type len2 = len - n1 + n2; + size_type current_capacity = (size_type)(mpEOS - mpBegin); + + if (current_capacity < len2) + reserve_slow(len2, current_capacity); + + memmove(mpBegin + pos + n2, mpBegin + pos + n1, (limit - n1 + 1) * sizeof(value_type)); + memcpy(mpBegin + pos, s, n2*sizeof(value_type)); + mpEnd = mpBegin + len2; + return *this; + } + + void swap(this_type& x) { + value_type *p; + + p = mpBegin; mpBegin = x.mpBegin; x.mpBegin = p; + p = mpEnd; mpEnd = x.mpEnd; x.mpEnd = p; + p = mpEOS; mpEOS = x.mpEOS; x.mpEOS = p; + } + + // 21.3.6 string operations + const_pointer c_str() const { return mpBegin; } + + this_type& sprintf(const value_type *format, ...); + this_type& append_sprintf(const value_type *format, ...); + this_type& append_vsprintf(const value_type *format, va_list val); + + void move_from(VDStringA& src); + +protected: + void push_back_extend(); + void resize_slow(size_type n, size_type current_size); + void resize_slow(size_type n, size_type current_size, value_type c); + void reserve_slow(size_type n, size_type current_capacity); + void reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity); + + char *mpEOS; +}; + +/////////////////////////////////////////////////////////////////////////// + +inline VDStringA operator+(const VDStringA& str, const VDStringA& s) { + VDStringA result; + result.reserve((VDStringA::size_type)(str.size() + s.size())); + result.assign(str); + result.append(s); + return result; +} + +inline VDStringA operator+(const VDStringA& str, const char *s) { + VDStringA result; + result.reserve((VDStringA::size_type)(str.size() + strlen(s))); + result.assign(str); + result.append(s); + return result; +} + +inline VDStringA operator+(const VDStringA& str, char c) { + VDStringA result; + result.reserve(str.size() + 1); + result.assign(str); + result += c; + return result; +} + +// Start patch MPC-HC +/* +namespace std { + template<> + struct less : binary_function { + bool operator()(const VDStringA& x, const VDStringA& y) const { + return x.compare(y) < 0; + } + }; +} +*/ +// End patch MPC-HC + +/////////////////////////////////////////////////////////////////////////// + +class VDStringSpanW { +public: + typedef wchar_t value_type; + typedef uint32 size_type; + typedef ptrdiff_t difference_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type * pointer; + typedef const value_type * const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + + static const size_type npos = (size_type)-1; + + VDStringSpanW() + : mpBegin(const_cast(sNull)) + , mpEnd(const_cast(sNull)) + { + } + + explicit VDStringSpanW(const value_type *s) + : mpBegin(const_cast(s)) + , mpEnd(const_cast(s) + wcslen(s)) + { + } + + VDStringSpanW(const value_type *s, const value_type *t) + : mpBegin(const_cast(s)) + , mpEnd(const_cast(t)) + { + } + + // 21.3.2 iterators + const_iterator begin() const { return mpBegin; } + const_iterator end() const { return mpEnd; } + + // 21.3.3 capacity + size_type size() const { return (size_type)(mpEnd - mpBegin); } + size_type length() const { return (size_type)(mpEnd - mpBegin); } + bool empty() const { return mpBegin == mpEnd; } + + // 21.3.4 element access + const_reference operator[](size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + const_reference at(size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + + const_reference front() const { VDASSERT(mpBegin != mpEnd); return *mpBegin; } + const_reference back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } + + // 21.3.6 string operations + const_pointer data() const { return mpBegin; } + + size_type copy(value_type *dst, size_type n, size_type pos = 0) const { + size_type len = (size_type)(mpEnd - mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + memcpy(dst, mpBegin + pos, n*sizeof(value_type)); + return n; + } + + size_type find(value_type c, size_type pos = 0) const { + VDASSERT(pos <= (size_type)(mpEnd - mpBegin)); + const void *p = wmemchr(mpBegin + pos, c, mpEnd - (mpBegin + pos)); + + return p ? (size_type)((const value_type *)p - mpBegin) : npos; + } + + int compare(const VDStringSpanW& s) const { + size_type l1 = (size_type)(mpEnd - mpBegin); + size_type l2 = (size_type)(s.mpEnd - s.mpBegin); + size_type lm = l1 < l2 ? l1 : l2; + + for(size_type i = 0; i < lm; ++i) { + if (mpBegin[i] != s.mpBegin[i]) + return mpBegin[i] < s.mpBegin[i] ? -1 : +1; + } + + if (l1 == l2) + return 0; + + return l1 < l2 ? -1 : +1; + } + + int comparei(const wchar_t *s) const { + return comparei(VDStringSpanW(s)); + } + + int comparei(const VDStringSpanW& s) const { + size_type l1 = (size_type)(mpEnd - mpBegin); + size_type l2 = (size_type)(s.mpEnd - s.mpBegin); + size_type lm = l1 < l2 ? l1 : l2; + + for(size_type i = 0; i < lm; ++i) { + wint_t c = towlower(mpBegin[i]); + wint_t d = towlower(s.mpBegin[i]); + + if (c != d) + return c < d ? -1 : +1; + } + + if (l1 == l2) + return 0; + + return l1 < l2 ? -1 : +1; + } + + // extensions + const VDStringSpanW subspan(size_type pos, size_type n) const { + size_type len = (size_type)(mpEnd - mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + value_type *p = mpBegin + pos; + return VDStringSpanW(p, p+n); + } + +protected: + friend class VDStringW; + friend bool operator==(const VDStringSpanW& x, const VDStringSpanW& y); + friend bool operator==(const VDStringSpanW& x, const wchar_t *y); + + value_type *mpBegin; + value_type *mpEnd; + + static const value_type sNull[1]; +}; + +inline bool operator==(const VDStringSpanW& x, const VDStringSpanW& y) { VDStringA::size_type len = (VDStringSpanW::size_type)(x.mpEnd - x.mpBegin); return len == (VDStringSpanW::size_type)(y.mpEnd - y.mpBegin) && !memcmp(x.mpBegin, y.mpBegin, len*sizeof(wchar_t)); } +inline bool operator==(const VDStringSpanW& x, const wchar_t *y) { size_t len = wcslen(y); return len == (size_t)(x.mpEnd - x.mpBegin) && !memcmp(x.mpBegin, y, len*sizeof(wchar_t)); } +inline bool operator==(const wchar_t *x, const VDStringSpanW& y) { return y == x; } + +inline bool operator!=(const VDStringSpanW& x, const VDStringSpanW& y) { return !(x == y); } +inline bool operator!=(const VDStringSpanW& x, const wchar_t *y) { return !(x == y); } +inline bool operator!=(const wchar_t *x, const VDStringSpanW& y) { return !(y == x); } + +inline bool operator<(const VDStringSpanW& x, const VDStringSpanW& y) { + return x.compare(y) < 0; +} + +inline bool operator>(const VDStringSpanW& x, const VDStringSpanW& y) { + return x.compare(y) > 0; +} + +inline bool operator<=(const VDStringSpanW& x, const VDStringSpanW& y) { + return x.compare(y) <= 0; +} + +inline bool operator>=(const VDStringSpanW& x, const VDStringSpanW& y) { + return x.compare(y) >= 0; +} + +class VDStringRefW : public VDStringSpanW { +public: + typedef VDStringRefW this_type; + + VDStringRefW() { + } + + explicit VDStringRefW(const value_type *s) + : VDStringSpanW(s) + { + } + + explicit VDStringRefW(const VDStringSpanW& s) + : VDStringSpanW(s) + { + } + + VDStringRefW(const value_type *s, const value_type *t) + : VDStringSpanW(s, t) + { + } + + this_type& operator=(const value_type *s) { + assign(s); + return *this; + } + + this_type& operator=(const VDStringSpanW& str) { + assign(str); + return *this; + } + + void assign(const value_type *s) { + static_cast(*this) = VDStringSpanW(s); + } + + void assign(const value_type *s, const value_type *t) { + static_cast(*this) = VDStringSpanW(s, t); + } + + void assign(const VDStringSpanW& s) { + static_cast(*this) = s; + } + + void clear() { + mpBegin = mpEnd = NULL; + } + + bool split(value_type c, VDStringRefW& token) { + size_type pos = find(c); + + if (pos == npos) + return false; + + token = subspan(0, pos); + mpBegin += pos+1; + return true; + } +}; + +class VDStringW : public VDStringSpanW { +public: + typedef VDStringW this_type; + + // 21.3.1 construct/copy/destroy + + VDStringW() + : mpEOS(const_cast(sNull)) + { + } + + VDStringW(const VDStringSpanW& x) + : mpEOS(const_cast(sNull)) + { + assign(x.begin(), x.end()); + } + + VDStringW(const this_type& x) + : mpEOS(const_cast(sNull)) + { + assign(x); + } + + explicit VDStringW(const value_type *s) + : mpEOS(const_cast(sNull)) + { + assign(s); + } + + explicit VDStringW(size_type n) + : mpEOS(const_cast(sNull)) + { + resize(n); + } + + VDStringW(const value_type *s, size_type n) + : mpEOS(const_cast(sNull)) + { + assign(s, n); + } + + VDStringW(const value_type *s, const value_type *t) + : mpEOS(const_cast(sNull)) + { + assign(s, t); + } + + ~VDStringW() { + if (mpBegin != sNull) + delete[] mpBegin; + } + + this_type& operator=(const wchar_t *s) { + assign(s); + return *this; + } + + this_type& operator=(const this_type& str) { + assign(str); + return *this; + } + + // 21.3.2 iterators + using VDStringSpanW::begin; + using VDStringSpanW::end; + iterator begin() { return mpBegin; } + iterator end() { return mpEnd; } + + // 21.3.3 capacity (COMPLETE) + void resize(size_type n) { + size_type current = (size_type)(mpEnd - mpBegin); + + if (n < current) { + mpEnd = mpBegin + n; + mpEnd[0] = 0; + } else if (n > current) + resize_slow(n, current); + } + + void resize(size_type n, value_type v) { + size_type current = (size_type)(mpEnd - mpBegin); + + if (n < current) { + mpEnd = mpBegin + n; + mpEnd[0] = 0; + } else if (n > current) + resize_slow(n, current); + wmemset(mpBegin, v, n); + } + + size_type capacity() const { return (size_type)(mpEOS - mpBegin); } + + void reserve(size_type n) { + size_type current = (size_type)(mpEOS - mpBegin); + + if (n > current) + reserve_slow(n, current); + } + + void clear() { + if (mpEnd != mpBegin) { + mpEnd = mpBegin; + mpEnd[0] = 0; + } + } + + // 21.3.4 element access + using VDStringSpanW::operator[]; + using VDStringSpanW::at; + using VDStringSpanW::front; + using VDStringSpanW::back; + reference operator[](size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + reference at(size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + reference front() { VDASSERT(mpBegin != mpEnd); return *mpBegin; } + reference back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } + + // 21.3.5 modifiers + this_type& operator+=(const this_type& str) { + return append(str.mpBegin, str.mpEnd); + } + + this_type& operator+=(const value_type *s) { + return append(s, s+wcslen(s)); + } + + this_type& operator+=(value_type c) { + if (mpEnd == mpEOS) + push_back_extend(); + + *mpEnd++ = c; + *mpEnd = 0; + return *this; + } + + this_type& append(const this_type& str) { + return append(str.mpBegin, str.mpEnd); + } + + this_type& append(const this_type& str, size_type pos, size_type n) { + size_type len = (size_type)(str.mpEnd - str.mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + return append(str.mpBegin + pos, str.mpBegin + pos + n); + } + + this_type& append(const value_type *s, size_type n) { + return append(s, s+n); + } + + this_type& append(const value_type *s) { + return append(s, s+wcslen(s)); + } + + this_type& append(const value_type *s, const value_type *t) { + if (s != t) { + size_type current_size = (size_type)(mpEnd - mpBegin); + size_type current_capacity = (size_type)(mpEOS - mpBegin); + size_type n = (size_type)(t - s); + + if (current_capacity - current_size < n) + reserve_amortized_slow(n, current_size, current_capacity); + + memcpy(mpBegin + current_size, s, n*sizeof(value_type)); + mpEnd += n; + *mpEnd = 0; + } + return *this; + } + + void push_back(const value_type c) { + if (mpEnd == mpEOS) + push_back_extend(); + + *mpEnd++ = c; + *mpEnd = 0; + } + + void pop_back() { + --mpEnd; + *mpEnd = 0; + } + + this_type& assign(const VDStringSpanW& str) { + return assign(str.mpBegin, str.mpEnd); + } + + this_type& assign(const VDStringSpanW& str, size_type pos, size_type n) { + size_type len = (size_type)(str.mpEnd - str.mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + return assign(str.mpBegin + pos, str.mpBegin + pos + n); + } + + this_type& assign(const value_type *s, size_type n) { + return assign(s, s+n); + } + + this_type& assign(const value_type *s) { + return assign(s, s+wcslen(s)); + } + + this_type& assign(size_type n, value_type c) { + size_type current_capacity = (size_type)(mpEOS - mpBegin); + + if (current_capacity < n) + reserve_slow(n, current_capacity); + + if (mpBegin != sNull) { + mpEnd = mpBegin; + while(n--) + *mpEnd++ = c; + } + + return *this; + } + + this_type& assign(const value_type *s, const value_type *t) { + size_type current_capacity = (size_type)(mpEOS - mpBegin); + size_type n = (size_type)(t - s); + + if (current_capacity < n) + reserve_slow(n, current_capacity); + + if (mpBegin != sNull) { + memcpy(mpBegin, s, sizeof(value_type)*n); + mpEnd = mpBegin + n; + *mpEnd = 0; + } + + return *this; + } + + this_type& insert(iterator it, value_type c) { + if (mpEnd == mpEOS) { + size_type pos = (size_type)(it - mpBegin); + push_back_extend(); + it = mpBegin + pos; + } + + memmove(it + 1, it, (mpEnd - it + 1)*sizeof(value_type)); + *it = c; + ++mpEnd; + return *this; + } + + this_type& erase(size_type pos = 0, size_type n = npos) { + size_type len = (size_type)(mpEnd - mpBegin); + + VDASSERT(pos <= len); + len -= pos; + if (n > len) + n = len; + + if (n) { + size_type pos2 = pos + n; + memmove(mpBegin + pos, mpBegin + pos2, (len + 1 - n)*sizeof(value_type)); + mpEnd -= n; + } + + return *this; + } + + iterator erase(iterator x) { + VDASSERT(x != mpEnd); + + memmove(x, x+1, (mpEnd - x)*sizeof(value_type)); + --mpEnd; + return x; + } + + iterator erase(iterator first, iterator last) { + VDASSERT(last >= first); + + memmove(first, last, ((mpEnd - last) + 1)*sizeof(value_type)); + mpEnd -= (last - first); + return first; + } + + this_type& replace(size_type pos, size_type n1, const value_type *s, size_type n2) { + size_type len = (size_type)(mpEnd - mpBegin); + + VDASSERT(pos <= len); + size_type limit = len - pos; + if (n1 > limit) + n1 = limit; + + size_type len2 = len - n1 + n2; + size_type current_capacity = (size_type)(mpEOS - mpBegin); + + if (current_capacity < len2) + reserve_slow(len2, current_capacity); + + memmove(mpBegin + pos + n2, mpBegin + pos + n1, (limit - n1 + 1) * sizeof(value_type)); + memcpy(mpBegin + pos, s, n2*sizeof(value_type)); + mpEnd = mpBegin + len2; + return *this; + } + + void swap(this_type& x) { + std::swap(mpBegin, x.mpBegin); + std::swap(mpEnd, x.mpEnd); + std::swap(mpEOS, x.mpEOS); + } + + void swap(this_type&& x) { + std::swap(mpBegin, x.mpBegin); + std::swap(mpEnd, x.mpEnd); + std::swap(mpEOS, x.mpEOS); + } + + // 21.3.6 string operations + const_pointer c_str() const { return mpBegin; } + + this_type& sprintf(const value_type *format, ...); + this_type& append_sprintf(const value_type *format, ...); + this_type& append_vsprintf(const value_type *format, va_list val); + + void move_from(VDStringW& src); + +protected: + void push_back_extend(); + void resize_slow(size_type n, size_type current_size); + void reserve_slow(size_type n, size_type current_capacity); + void reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity); + + value_type *mpEOS; +}; + +/////////////////////////////////////////////////////////////////////////// + +inline VDStringW operator+(const VDStringW& str, const VDStringW& s) { + VDStringW result; + result.reserve((VDStringA::size_type)(str.size() + s.size())); + result.assign(str); + result.append(s); + return result; +} + +inline VDStringW operator+(const VDStringW& str, const wchar_t *s) { + VDStringW result; + result.reserve((VDStringA::size_type)(str.size() + wcslen(s))); + result.assign(str); + result.append(s); + return result; +} + +inline VDStringW operator+(const VDStringW& str, wchar_t c) { + VDStringW result; + result.reserve(str.size() + 1); + result.assign(str); + result += c; + return result; +} + +/////////////////////////////////////////////////////////////////////////// + +typedef VDStringA VDString; + +template<> VDStringA *vdmove_forward(VDStringA *src1, VDStringA *src2, VDStringA *dst); +template<> VDStringW *vdmove_forward(VDStringW *src1, VDStringW *src2, VDStringW *dst); +template<> VDStringA *vdmove_backward(VDStringA *src1, VDStringA *src2, VDStringA *dst); +template<> VDStringW *vdmove_backward(VDStringW *src1, VDStringW *src2, VDStringW *dst); + +VDMOVE_CAPABLE(VDStringA); +VDMOVE_CAPABLE(VDStringW); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/atomic.h b/src/thirdparty/VirtualDub/h/vd2/system/atomic.h index 1e82c87aa6c..f00330a44fd 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/atomic.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/atomic.h @@ -1,376 +1,376 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_ATOMIC_H -#define f_VD2_SYSTEM_ATOMIC_H - -#include - -#ifdef VD_COMPILER_MSVC - // Intrinsics available in VC6.0 - extern "C" long __cdecl _InterlockedDecrement(volatile long *p); - extern "C" long __cdecl _InterlockedIncrement(volatile long *p); - extern "C" long __cdecl _InterlockedCompareExchange(volatile long *p, long n, long p_compare); - extern "C" long __cdecl _InterlockedExchange(volatile long *p, long n); - extern "C" long __cdecl _InterlockedExchangeAdd(volatile long *p, long n); - - #pragma intrinsic(_InterlockedDecrement) - #pragma intrinsic(_InterlockedIncrement) - #pragma intrinsic(_InterlockedCompareExchange) - #pragma intrinsic(_InterlockedExchange) - #pragma intrinsic(_InterlockedExchangeAdd) - - // Intrinsics available in VC7.1. Note that the compiler is smart enough to - // use straight LOCK AND/OR/XOR if the return value is not needed; otherwise - // it uses a LOCK CMPXCHG loop. - #if _MSC_VER >= 1310 - extern "C" long __cdecl _InterlockedAnd(volatile long *p, long n); - extern "C" long __cdecl _InterlockedOr(volatile long *p, long n); - extern "C" long __cdecl _InterlockedXor(volatile long *p, long n); - - #pragma intrinsic(_InterlockedAnd) - #pragma intrinsic(_InterlockedOr) - #pragma intrinsic(_InterlockedXor) - #endif - - // Intrinsics available with AMD64 - #ifdef VD_CPU_AMD64 - extern "C" void *__cdecl _InterlockedExchangePointer(void *volatile *pp, void *p); - #pragma intrinsic(_InterlockedExchangePointer) - extern "C" void *__cdecl _InterlockedCompareExchangePointer(void *volatile *pp, void *p, void *compare); - #pragma intrinsic(_InterlockedCompareExchangePointer) - #endif -#endif - -inline void *VDAtomicCompareExchangePointer(void *volatile *pp, void *p, void *compare) { -#if defined(VD_COMPILER_MSVC) - #ifdef _M_AMD64 - return _InterlockedCompareExchangePointer(pp, p, compare); - #else - return (void *)(sintptr)_InterlockedCompareExchange((volatile long *)(volatile sintptr *)pp, (long)(sintptr)p, (long)(sintptr)compare); - #endif -#elif defined(VD_COMPILER_GCC) - return __sync_val_compare_and_swap(pp, compare, p); -#endif -} - -/////////////////////////////////////////////////////////////////////////// -/// \class VDAtomicInt -/// \brief Wrapped integer supporting thread-safe atomic operations. -/// -/// VDAtomicInt allows integer values shared between threads to be -/// modified with several common operations in a lock-less manner and -/// without the need for explicit barriers. This is particularly useful -/// for thread-safe reference counting. -/// -class VDAtomicInt { -protected: - volatile int n; - -public: - VDAtomicInt() {} - VDAtomicInt(int v) : n(v) {} - - bool operator!() const { return !n; } - bool operator!=(volatile int v) const { return n!=v; } - bool operator==(volatile int v) const { return n==v; } - bool operator<=(volatile int v) const { return n<=v; } - bool operator>=(volatile int v) const { return n>=v; } - bool operator<(volatile int v) const { return n(volatile int v) const { return n>v; } - - /////////////////////////////// - - /// Atomically exchanges a value with an integer in memory. - static inline int staticExchange(volatile int *dst, int v) { - #if defined(VD_COMPILER_MSVC) - return (int)_InterlockedExchange((volatile long *)dst, v); - #elif defined(VD_COMPILER_GCC) - return __sync_lock_test_and_set((int *)&dst, v); - #endif - } - - /// Atomically adds one to an integer in memory. - static inline void staticIncrement(volatile int *dst) { - #if defined(VD_COMPILER_MSVC) - _InterlockedExchangeAdd((volatile long *)dst, 1); - #elif defined(VD_COMPILER_GCC) - __sync_fetch_and_add(&dst, 1); - #endif - } - - /// Atomically subtracts one from an integer in memory. - static inline void staticDecrement(volatile int *dst) { - #if defined(VD_COMPILER_MSVC) - _InterlockedExchangeAdd((volatile long *)dst, -1); - #elif defined(VD_COMPILER_GCC) - __sync_fetch_and_sub(&dst, 1); - #endif - } - - /// Atomically subtracts one from an integer in memory and returns - /// true if the result is zero. - static inline bool staticDecrementTestZero(volatile int *dst) { - #if defined(VD_COMPILER_MSVC) - return 1 == _InterlockedExchangeAdd((volatile long *)dst, -1); - #elif defined(VD_COMPILER_GCC) - return 1 == __sync_fetch_and_sub((int *)&dst, 1); - #endif - } - - /// Atomically adds a value to an integer in memory and returns the - /// result. - static inline int staticAdd(volatile int *dst, int v) { - #if defined(VD_COMPILER_MSVC) - return (int)_InterlockedExchangeAdd((volatile long *)dst, v) + v; - #elif defined(VD_COMPILER_GCC) - return __sync_fetch_and_add((int *)&dst, v) + v; - #endif - } - - /// Atomically adds a value to an integer in memory and returns the - /// old result (post-add). - static inline int staticExchangeAdd(volatile int *dst, int v) { - #if defined(VD_COMPILER_MSVC) - return _InterlockedExchangeAdd((volatile long *)dst, v); - #elif defined(VD_COMPILER_GCC) - return __sync_fetch_and_add((int *)&dst, v); - #endif - } - - /// Atomically compares an integer in memory to a compare value and - /// swaps the memory location with a second value if the compare - /// succeeds. The return value is the memory value prior to the swap. - static inline int staticCompareExchange(volatile int *dst, int v, int compare) { - #if defined(VD_COMPILER_MSVC) - return _InterlockedCompareExchange((volatile long *)dst, v, compare); - #elif defined(VD_COMPILER_GCC) - return __sync_val_compare_and_swap((int *)&dst, compare, v); - #endif - } - - /////////////////////////////// - - int operator=(int v) { return n = v; } - - int operator++() { return staticAdd(&n, 1); } - int operator--() { return staticAdd(&n, -1); } - int operator++(int) { return staticExchangeAdd(&n, 1); } - int operator--(int) { return staticExchangeAdd(&n, -1); } - int operator+=(int v) { return staticAdd(&n, v); } - int operator-=(int v) { return staticAdd(&n, -v); } - -#if _MSC_VER >= 1310 - - void operator&=(int v) { _InterlockedAnd((volatile long *)&n, v); } ///< Atomic bitwise AND. - void operator|=(int v) { _InterlockedOr((volatile long *)&n, v); } ///< Atomic bitwise OR. - void operator^=(int v) { _InterlockedXor((volatile long *)&n, v); } ///< Atomic bitwise XOR. - -#elif defined(VD_COMPILER_GCC) - - void operator&=(int v) { - __sync_fetch_and_and(&n, v); - } - - void operator|=(int v) { - __sync_fetch_and_or(&n, v); - } - - void operator^=(int v) { - __sync_fetch_and_xor(&n, v); - } - -#else - /// Atomic bitwise AND. - void operator&=(int v) { - __asm mov eax,v - __asm mov ecx,this - __asm lock and dword ptr [ecx],eax - } - - /// Atomic bitwise OR. - void operator|=(int v) { - __asm mov eax,v - __asm mov ecx,this - __asm lock or dword ptr [ecx],eax - } - - /// Atomic bitwise XOR. - void operator^=(int v) { - __asm mov eax,v - __asm mov ecx,this - __asm lock xor dword ptr [ecx],eax - } -#endif - - operator int() const { - return n; - } - - /// Atomic exchange. - int xchg(int v) { - return staticExchange(&n, v); - } - - /// Compare/exchange (486+). - int compareExchange(int newValue, int oldValue) { - return staticCompareExchange(&n, newValue, oldValue); - } - - // 486 only, but much nicer. They return the actual result. - - int inc() { return operator++(); } ///< Atomic increment. - int dec() { return operator--(); } ///< Atomic decrement. - int add(int v) { return operator+=(v); } ///< Atomic add. - - // These return the result before the operation, which is more inline with - // what XADD allows us to do. - - int postinc() { return operator++(0); } ///< Atomic post-increment. - int postdec() { return operator--(0); } ///< Atomic post-decrement. - int postadd(int v) { return staticExchangeAdd(&n, v); } ///< Atomic post-add. - -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDAtomicFloat { -protected: - volatile float n; - -public: - VDAtomicFloat() {} - VDAtomicFloat(float v) : n(v) {} - - bool operator!=(float v) const { return n!=v; } - bool operator==(float v) const { return n==v; } - bool operator<=(float v) const { return n<=v; } - bool operator>=(float v) const { return n>=v; } - bool operator<(float v) const { return n(float v) const { return n>v; } - - float operator=(float v) { return n = v; } - - operator float() const { - return n; - } - - /// Atomic exchange. - float xchg(float v) { - union { int i; float f; } converter = {VDAtomicInt::staticExchange((volatile int *)&n, *(const int *)&v)}; - - return converter.f; - } -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDAtomicBool { -protected: - volatile char n; - -public: - VDAtomicBool() {} - VDAtomicBool(bool v) : n(v) {} - - bool operator!=(bool v) const { return (n != 0) != v; } - bool operator==(bool v) const { return (n != 0) == v; } - - bool operator=(bool v) { return n = v; } - - operator bool() const { - return n != 0; - } - - /// Atomic exchange. - bool xchg(bool v) { - const uint32 mask = ((uint32)0xFF << (int)((size_t)&n & 3)); - const int andval = (int)~mask; - const int orval = (int)(mask & 0x01010101); - volatile int *p = (volatile int *)((uintptr)&n & ~(uintptr)3); - - for(;;) { - const uint32 prevval = *p; - const uint32 newval = (prevval & andval) + orval; - - if (prevval == VDAtomicInt::staticCompareExchange(p, newval, prevval)) - return (prevval & mask) != 0; - } - } -}; - -/////////////////////////////////////////////////////////////////////////// -/// \class VDAtomicPtr -/// \brief Wrapped pointer supporting thread-safe atomic operations. -/// -/// VDAtomicPtr allows a shared pointer to be safely manipulated by -/// multiple threads without locks. Note that atomicity is only guaranteed -/// for the pointer itself, so any operations on the object must be dealt -/// with in other manners, such as an inner lock or other atomic -/// operations. An atomic pointer can serve as a single entry queue. -/// -template -class VDAtomicPtr { -protected: - T *volatile ptr; - -public: - VDAtomicPtr() {} - VDAtomicPtr(T *p) : ptr(p) { } - - operator T*() const { return ptr; } - T* operator->() const { return ptr; } - - T* operator=(T* p) { - return ptr = p; - } - - /// Atomic pointer exchange. - T *xchg(T* p) { - #if defined(VD_COMPILER_MSVC) - #ifdef _M_AMD64 - return ptr == p ? p : (T *)_InterlockedExchangePointer((void *volatile *)&ptr, p); - #else - return ptr == p ? p : (T *)_InterlockedExchange((volatile long *)&ptr, (long)p); - #endif - #elif defined(VD_COMPILER_GCC) - return __sync_lock_test_and_set(&ptr, p); - #endif - } - - T *compareExchange(T *newValue, T *oldValue) { - #if defined(VD_COMPILER_MSVC) - #ifdef _M_AMD64 - return (T *)_InterlockedCompareExchangePointer((void *volatile *)&ptr, (void *)newValue, (void *)oldValue); - #else - return (T *)_InterlockedCompareExchange((volatile long *)&ptr, (long)(size_t)newValue, (long)(size_t)oldValue); - #endif - #elif defined(VD_COMPILER_GCC) - return __sync_val_compare_and_swap(&ptr, oldValue, newValue); - #endif - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_ATOMIC_H +#define f_VD2_SYSTEM_ATOMIC_H + +#include + +#ifdef VD_COMPILER_MSVC + // Intrinsics available in VC6.0 + extern "C" long __cdecl _InterlockedDecrement(volatile long *p); + extern "C" long __cdecl _InterlockedIncrement(volatile long *p); + extern "C" long __cdecl _InterlockedCompareExchange(volatile long *p, long n, long p_compare); + extern "C" long __cdecl _InterlockedExchange(volatile long *p, long n); + extern "C" long __cdecl _InterlockedExchangeAdd(volatile long *p, long n); + + #pragma intrinsic(_InterlockedDecrement) + #pragma intrinsic(_InterlockedIncrement) + #pragma intrinsic(_InterlockedCompareExchange) + #pragma intrinsic(_InterlockedExchange) + #pragma intrinsic(_InterlockedExchangeAdd) + + // Intrinsics available in VC7.1. Note that the compiler is smart enough to + // use straight LOCK AND/OR/XOR if the return value is not needed; otherwise + // it uses a LOCK CMPXCHG loop. + #if _MSC_VER >= 1310 + extern "C" long __cdecl _InterlockedAnd(volatile long *p, long n); + extern "C" long __cdecl _InterlockedOr(volatile long *p, long n); + extern "C" long __cdecl _InterlockedXor(volatile long *p, long n); + + #pragma intrinsic(_InterlockedAnd) + #pragma intrinsic(_InterlockedOr) + #pragma intrinsic(_InterlockedXor) + #endif + + // Intrinsics available with AMD64 + #ifdef VD_CPU_AMD64 + extern "C" void *__cdecl _InterlockedExchangePointer(void *volatile *pp, void *p); + #pragma intrinsic(_InterlockedExchangePointer) + extern "C" void *__cdecl _InterlockedCompareExchangePointer(void *volatile *pp, void *p, void *compare); + #pragma intrinsic(_InterlockedCompareExchangePointer) + #endif +#endif + +inline void *VDAtomicCompareExchangePointer(void *volatile *pp, void *p, void *compare) { +#if defined(VD_COMPILER_MSVC) + #ifdef _M_AMD64 + return _InterlockedCompareExchangePointer(pp, p, compare); + #else + return (void *)(sintptr)_InterlockedCompareExchange((volatile long *)(volatile sintptr *)pp, (long)(sintptr)p, (long)(sintptr)compare); + #endif +#elif defined(VD_COMPILER_GCC) + return __sync_val_compare_and_swap(pp, compare, p); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +/// \class VDAtomicInt +/// \brief Wrapped integer supporting thread-safe atomic operations. +/// +/// VDAtomicInt allows integer values shared between threads to be +/// modified with several common operations in a lock-less manner and +/// without the need for explicit barriers. This is particularly useful +/// for thread-safe reference counting. +/// +class VDAtomicInt { +protected: + volatile int n; + +public: + VDAtomicInt() {} + VDAtomicInt(int v) : n(v) {} + + bool operator!() const { return !n; } + bool operator!=(volatile int v) const { return n!=v; } + bool operator==(volatile int v) const { return n==v; } + bool operator<=(volatile int v) const { return n<=v; } + bool operator>=(volatile int v) const { return n>=v; } + bool operator<(volatile int v) const { return n(volatile int v) const { return n>v; } + + /////////////////////////////// + + /// Atomically exchanges a value with an integer in memory. + static inline int staticExchange(volatile int *dst, int v) { + #if defined(VD_COMPILER_MSVC) + return (int)_InterlockedExchange((volatile long *)dst, v); + #elif defined(VD_COMPILER_GCC) + return __sync_lock_test_and_set((int *)&dst, v); + #endif + } + + /// Atomically adds one to an integer in memory. + static inline void staticIncrement(volatile int *dst) { + #if defined(VD_COMPILER_MSVC) + _InterlockedExchangeAdd((volatile long *)dst, 1); + #elif defined(VD_COMPILER_GCC) + __sync_fetch_and_add(&dst, 1); + #endif + } + + /// Atomically subtracts one from an integer in memory. + static inline void staticDecrement(volatile int *dst) { + #if defined(VD_COMPILER_MSVC) + _InterlockedExchangeAdd((volatile long *)dst, -1); + #elif defined(VD_COMPILER_GCC) + __sync_fetch_and_sub(&dst, 1); + #endif + } + + /// Atomically subtracts one from an integer in memory and returns + /// true if the result is zero. + static inline bool staticDecrementTestZero(volatile int *dst) { + #if defined(VD_COMPILER_MSVC) + return 1 == _InterlockedExchangeAdd((volatile long *)dst, -1); + #elif defined(VD_COMPILER_GCC) + return 1 == __sync_fetch_and_sub((int *)&dst, 1); + #endif + } + + /// Atomically adds a value to an integer in memory and returns the + /// result. + static inline int staticAdd(volatile int *dst, int v) { + #if defined(VD_COMPILER_MSVC) + return (int)_InterlockedExchangeAdd((volatile long *)dst, v) + v; + #elif defined(VD_COMPILER_GCC) + return __sync_fetch_and_add((int *)&dst, v) + v; + #endif + } + + /// Atomically adds a value to an integer in memory and returns the + /// old result (post-add). + static inline int staticExchangeAdd(volatile int *dst, int v) { + #if defined(VD_COMPILER_MSVC) + return _InterlockedExchangeAdd((volatile long *)dst, v); + #elif defined(VD_COMPILER_GCC) + return __sync_fetch_and_add((int *)&dst, v); + #endif + } + + /// Atomically compares an integer in memory to a compare value and + /// swaps the memory location with a second value if the compare + /// succeeds. The return value is the memory value prior to the swap. + static inline int staticCompareExchange(volatile int *dst, int v, int compare) { + #if defined(VD_COMPILER_MSVC) + return _InterlockedCompareExchange((volatile long *)dst, v, compare); + #elif defined(VD_COMPILER_GCC) + return __sync_val_compare_and_swap((int *)&dst, compare, v); + #endif + } + + /////////////////////////////// + + int operator=(int v) { return n = v; } + + int operator++() { return staticAdd(&n, 1); } + int operator--() { return staticAdd(&n, -1); } + int operator++(int) { return staticExchangeAdd(&n, 1); } + int operator--(int) { return staticExchangeAdd(&n, -1); } + int operator+=(int v) { return staticAdd(&n, v); } + int operator-=(int v) { return staticAdd(&n, -v); } + +#if _MSC_VER >= 1310 + + void operator&=(int v) { _InterlockedAnd((volatile long *)&n, v); } ///< Atomic bitwise AND. + void operator|=(int v) { _InterlockedOr((volatile long *)&n, v); } ///< Atomic bitwise OR. + void operator^=(int v) { _InterlockedXor((volatile long *)&n, v); } ///< Atomic bitwise XOR. + +#elif defined(VD_COMPILER_GCC) + + void operator&=(int v) { + __sync_fetch_and_and(&n, v); + } + + void operator|=(int v) { + __sync_fetch_and_or(&n, v); + } + + void operator^=(int v) { + __sync_fetch_and_xor(&n, v); + } + +#else + /// Atomic bitwise AND. + void operator&=(int v) { + __asm mov eax,v + __asm mov ecx,this + __asm lock and dword ptr [ecx],eax + } + + /// Atomic bitwise OR. + void operator|=(int v) { + __asm mov eax,v + __asm mov ecx,this + __asm lock or dword ptr [ecx],eax + } + + /// Atomic bitwise XOR. + void operator^=(int v) { + __asm mov eax,v + __asm mov ecx,this + __asm lock xor dword ptr [ecx],eax + } +#endif + + operator int() const { + return n; + } + + /// Atomic exchange. + int xchg(int v) { + return staticExchange(&n, v); + } + + /// Compare/exchange (486+). + int compareExchange(int newValue, int oldValue) { + return staticCompareExchange(&n, newValue, oldValue); + } + + // 486 only, but much nicer. They return the actual result. + + int inc() { return operator++(); } ///< Atomic increment. + int dec() { return operator--(); } ///< Atomic decrement. + int add(int v) { return operator+=(v); } ///< Atomic add. + + // These return the result before the operation, which is more inline with + // what XADD allows us to do. + + int postinc() { return operator++(0); } ///< Atomic post-increment. + int postdec() { return operator--(0); } ///< Atomic post-decrement. + int postadd(int v) { return staticExchangeAdd(&n, v); } ///< Atomic post-add. + +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDAtomicFloat { +protected: + volatile float n; + +public: + VDAtomicFloat() {} + VDAtomicFloat(float v) : n(v) {} + + bool operator!=(float v) const { return n!=v; } + bool operator==(float v) const { return n==v; } + bool operator<=(float v) const { return n<=v; } + bool operator>=(float v) const { return n>=v; } + bool operator<(float v) const { return n(float v) const { return n>v; } + + float operator=(float v) { return n = v; } + + operator float() const { + return n; + } + + /// Atomic exchange. + float xchg(float v) { + union { int i; float f; } converter = {VDAtomicInt::staticExchange((volatile int *)&n, *(const int *)&v)}; + + return converter.f; + } +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDAtomicBool { +protected: + volatile char n; + +public: + VDAtomicBool() {} + VDAtomicBool(bool v) : n(v) {} + + bool operator!=(bool v) const { return (n != 0) != v; } + bool operator==(bool v) const { return (n != 0) == v; } + + bool operator=(bool v) { return n = v; } + + operator bool() const { + return n != 0; + } + + /// Atomic exchange. + bool xchg(bool v) { + const uint32 mask = ((uint32)0xFF << (int)((size_t)&n & 3)); + const int andval = (int)~mask; + const int orval = (int)(mask & 0x01010101); + volatile int *p = (volatile int *)((uintptr)&n & ~(uintptr)3); + + for(;;) { + const uint32 prevval = *p; + const uint32 newval = (prevval & andval) + orval; + + if (prevval == VDAtomicInt::staticCompareExchange(p, newval, prevval)) + return (prevval & mask) != 0; + } + } +}; + +/////////////////////////////////////////////////////////////////////////// +/// \class VDAtomicPtr +/// \brief Wrapped pointer supporting thread-safe atomic operations. +/// +/// VDAtomicPtr allows a shared pointer to be safely manipulated by +/// multiple threads without locks. Note that atomicity is only guaranteed +/// for the pointer itself, so any operations on the object must be dealt +/// with in other manners, such as an inner lock or other atomic +/// operations. An atomic pointer can serve as a single entry queue. +/// +template +class VDAtomicPtr { +protected: + T *volatile ptr; + +public: + VDAtomicPtr() {} + VDAtomicPtr(T *p) : ptr(p) { } + + operator T*() const { return ptr; } + T* operator->() const { return ptr; } + + T* operator=(T* p) { + return ptr = p; + } + + /// Atomic pointer exchange. + T *xchg(T* p) { + #if defined(VD_COMPILER_MSVC) + #ifdef _M_AMD64 + return ptr == p ? p : (T *)_InterlockedExchangePointer((void *volatile *)&ptr, p); + #else + return ptr == p ? p : (T *)_InterlockedExchange((volatile long *)&ptr, (long)p); + #endif + #elif defined(VD_COMPILER_GCC) + return __sync_lock_test_and_set(&ptr, p); + #endif + } + + T *compareExchange(T *newValue, T *oldValue) { + #if defined(VD_COMPILER_MSVC) + #ifdef _M_AMD64 + return (T *)_InterlockedCompareExchangePointer((void *volatile *)&ptr, (void *)newValue, (void *)oldValue); + #else + return (T *)_InterlockedCompareExchange((volatile long *)&ptr, (long)(size_t)newValue, (long)(size_t)oldValue); + #endif + #elif defined(VD_COMPILER_GCC) + return __sync_val_compare_and_swap(&ptr, oldValue, newValue); + #endif + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/binary.h b/src/thirdparty/VirtualDub/h/vd2/system/binary.h index 8ab90be3eaf..207333010e8 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/binary.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/binary.h @@ -1,181 +1,181 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_BINARY_H -#define f_VD2_SYSTEM_BINARY_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -#define VDMAKEFOURCC(byte1, byte2, byte3, byte4) (((uint8)byte1) + (((uint8)byte2) << 8) + (((uint8)byte3) << 16) + (((uint8)byte4) << 24)) - -#ifdef _MSC_VER - #include - - inline uint16 VDSwizzleU16(uint16 value) { return (uint16)_byteswap_ushort((unsigned short)value); } - inline sint16 VDSwizzleS16(sint16 value) { return (sint16)_byteswap_ushort((unsigned short)value); } - inline uint32 VDSwizzleU32(uint32 value) { return (uint32)_byteswap_ulong((unsigned long)value); } - inline sint32 VDSwizzleS32(sint32 value) { return (sint32)_byteswap_ulong((unsigned long)value); } - inline uint64 VDSwizzleU64(uint64 value) { return (uint64)_byteswap_uint64((unsigned __int64)value); } - inline sint64 VDSwizzleS64(sint64 value) { return (sint64)_byteswap_uint64((unsigned __int64)value); } - - inline uint32 VDRotateLeftU32(uint32 value, int bits) { return (uint32)_rotl((unsigned int)value, bits); } - inline uint32 VDRotateRightU32(uint32 value, int bits) { return (uint32)_rotr((unsigned int)value, bits); } -#else - inline uint16 VDSwizzleU16(uint16 value) { - return (value >> 8) + (value << 8); - } - - inline sint16 VDSwizzleS16(sint16 value) { - return (sint16)(((uint16)value >> 8) + ((uint16)value << 8)); - } - - inline uint32 VDSwizzleU32(uint32 value) { - return (value >> 24) + (value << 24) + ((value&0xff00)<<8) + ((value&0xff0000)>>8); - } - - inline sint32 VDSwizzleS32(sint32 value) { - return (sint32)(((uint32)value >> 24) + ((uint32)value << 24) + (((uint32)value&0xff00)<<8) + (((uint32)value&0xff0000)>>8)); - } - - inline uint64 VDSwizzleU64(uint64 value) { - return ((value & 0xFF00000000000000) >> 56) + - ((value & 0x00FF000000000000) >> 40) + - ((value & 0x0000FF0000000000) >> 24) + - ((value & 0x000000FF00000000) >> 8) + - ((value & 0x00000000FF000000) << 8) + - ((value & 0x0000000000FF0000) << 24) + - ((value & 0x000000000000FF00) << 40) + - ((value & 0x00000000000000FF) << 56); - } - - inline sint64 VDSwizzleS64(sint64 value) { - return (sint64)((((uint64)value & 0xFF00000000000000) >> 56) + - (((uint64)value & 0x00FF000000000000) >> 40) + - (((uint64)value & 0x0000FF0000000000) >> 24) + - (((uint64)value & 0x000000FF00000000) >> 8) + - (((uint64)value & 0x00000000FF000000) << 8) + - (((uint64)value & 0x0000000000FF0000) << 24) + - (((uint64)value & 0x000000000000FF00) << 40) + - (((uint64)value & 0x00000000000000FF) << 56)); - } -#endif - -inline uint16 VDReadUnalignedU16(const void *p) { return *(uint16 *)p; } -inline sint16 VDReadUnalignedS16(const void *p) { return *(sint16 *)p; } -inline uint32 VDReadUnalignedU32(const void *p) { return *(uint32 *)p; } -inline sint32 VDReadUnalignedS32(const void *p) { return *(sint32 *)p; } -inline uint64 VDReadUnalignedU64(const void *p) { return *(uint64 *)p; } -inline sint64 VDReadUnalignedS64(const void *p) { return *(sint64 *)p; } -inline float VDReadUnalignedF(const void *p) { return *(float *)p; } -inline double VDReadUnalignedD(const void *p) { return *(double *)p; } - -inline uint16 VDReadUnalignedLEU16(const void *p) { return *(uint16 *)p; } -inline sint16 VDReadUnalignedLES16(const void *p) { return *(sint16 *)p; } -inline uint32 VDReadUnalignedLEU32(const void *p) { return *(uint32 *)p; } -inline sint32 VDReadUnalignedLES32(const void *p) { return *(sint32 *)p; } -inline uint64 VDReadUnalignedLEU64(const void *p) { return *(uint64 *)p; } -inline sint64 VDReadUnalignedLES64(const void *p) { return *(sint64 *)p; } -inline float VDReadUnalignedLEF(const void *p) { return *(float *)p; } -inline double VDReadUnalignedLED(const void *p) { return *(double *)p; } - -inline uint16 VDReadUnalignedBEU16(const void *p) { return VDSwizzleU16(*(uint16 *)p); } -inline sint16 VDReadUnalignedBES16(const void *p) { return VDSwizzleS16(*(sint16 *)p); } -inline uint32 VDReadUnalignedBEU32(const void *p) { return VDSwizzleU32(*(uint32 *)p); } -inline sint32 VDReadUnalignedBES32(const void *p) { return VDSwizzleS32(*(sint32 *)p); } -inline uint64 VDReadUnalignedBEU64(const void *p) { return VDSwizzleU64(*(uint64 *)p); } -inline sint64 VDReadUnalignedBES64(const void *p) { return VDSwizzleS64(*(sint64 *)p); } -inline float VDReadUnalignedBEF(const void *p) { - union { - uint32 i; - float f; - } conv = {VDSwizzleU32(*(const uint32 *)p)}; - return conv.f; -} -inline double VDReadUnalignedBED(const void *p) { - union { - uint64 i; - double d; - } conv = {VDSwizzleU64(*(const uint32 *)p)}; - return conv.d; -} - -inline void VDWriteUnalignedU16 (void *p, uint16 v) { *(uint16 *)p = v; } -inline void VDWriteUnalignedS16 (void *p, sint16 v) { *(sint16 *)p = v; } -inline void VDWriteUnalignedU32 (void *p, uint32 v) { *(uint32 *)p = v; } -inline void VDWriteUnalignedS32 (void *p, sint32 v) { *(sint32 *)p = v; } -inline void VDWriteUnalignedU64 (void *p, uint64 v) { *(uint64 *)p = v; } -inline void VDWriteUnalignedS64 (void *p, sint64 v) { *(sint64 *)p = v; } -inline void VDWriteUnalignedF (void *p, float v) { *(float *)p = v; } -inline void VDWriteUnalignedD (void *p, double v) { *(double *)p = v; } - -inline void VDWriteUnalignedLEU16(void *p, uint16 v) { *(uint16 *)p = v; } -inline void VDWriteUnalignedLES16(void *p, sint16 v) { *(sint16 *)p = v; } -inline void VDWriteUnalignedLEU32(void *p, uint32 v) { *(uint32 *)p = v; } -inline void VDWriteUnalignedLES32(void *p, sint32 v) { *(sint32 *)p = v; } -inline void VDWriteUnalignedLEU64(void *p, uint64 v) { *(uint64 *)p = v; } -inline void VDWriteUnalignedLES64(void *p, sint64 v) { *(sint64 *)p = v; } -inline void VDWriteUnalignedLEF (void *p, float v) { *(float *)p = v; } -inline void VDWriteUnalignedLED (void *p, double v) { *(double *)p = v; } - -inline void VDWriteUnalignedBEU16(void *p, uint16 v) { *(uint16 *)p = VDSwizzleU16(v); } -inline void VDWriteUnalignedBES16(void *p, sint16 v) { *(sint16 *)p = VDSwizzleS16(v); } -inline void VDWriteUnalignedBEU32(void *p, uint32 v) { *(uint32 *)p = VDSwizzleU32(v); } -inline void VDWriteUnalignedBES32(void *p, sint32 v) { *(sint32 *)p = VDSwizzleS32(v); } -inline void VDWriteUnalignedBEU64(void *p, uint64 v) { *(uint64 *)p = VDSwizzleU64(v); } -inline void VDWriteUnalignedBES64(void *p, sint64 v) { *(sint64 *)p = VDSwizzleS64(v); } -inline void VDReadUnalignedBEF(void *p, float v) { - union { - float f; - uint32 i; - } conv = {v}; - *(uint32 *)p = VDSwizzleU32(conv.i); -} -inline double VDReadUnalignedBED(void *p, double v) { - union { - double f; - uint64 i; - } conv = {v}; - *(uint64 *)p = VDSwizzleU64(conv.i); -} - -#define VDFromLE8(x) (x) -#define VDFromLE16(x) (x) -#define VDFromLE32(x) (x) -#define VDFromBE8(x) VDSwizzleU8(x) -#define VDFromBE16(x) VDSwizzleU16(x) -#define VDFromBE32(x) VDSwizzleU32(x) - -#define VDToLE8(x) (x) -#define VDToLE16(x) (x) -#define VDToLE32(x) (x) -#define VDToBE8(x) VDSwizzleU8(x) -#define VDToBE16(x) VDSwizzleU16(x) -#define VDToBE32(x) VDSwizzleU32(x) - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_BINARY_H +#define f_VD2_SYSTEM_BINARY_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +#define VDMAKEFOURCC(byte1, byte2, byte3, byte4) (((uint8)byte1) + (((uint8)byte2) << 8) + (((uint8)byte3) << 16) + (((uint8)byte4) << 24)) + +#ifdef _MSC_VER + #include + + inline uint16 VDSwizzleU16(uint16 value) { return (uint16)_byteswap_ushort((unsigned short)value); } + inline sint16 VDSwizzleS16(sint16 value) { return (sint16)_byteswap_ushort((unsigned short)value); } + inline uint32 VDSwizzleU32(uint32 value) { return (uint32)_byteswap_ulong((unsigned long)value); } + inline sint32 VDSwizzleS32(sint32 value) { return (sint32)_byteswap_ulong((unsigned long)value); } + inline uint64 VDSwizzleU64(uint64 value) { return (uint64)_byteswap_uint64((unsigned __int64)value); } + inline sint64 VDSwizzleS64(sint64 value) { return (sint64)_byteswap_uint64((unsigned __int64)value); } + + inline uint32 VDRotateLeftU32(uint32 value, int bits) { return (uint32)_rotl((unsigned int)value, bits); } + inline uint32 VDRotateRightU32(uint32 value, int bits) { return (uint32)_rotr((unsigned int)value, bits); } +#else + inline uint16 VDSwizzleU16(uint16 value) { + return (value >> 8) + (value << 8); + } + + inline sint16 VDSwizzleS16(sint16 value) { + return (sint16)(((uint16)value >> 8) + ((uint16)value << 8)); + } + + inline uint32 VDSwizzleU32(uint32 value) { + return (value >> 24) + (value << 24) + ((value&0xff00)<<8) + ((value&0xff0000)>>8); + } + + inline sint32 VDSwizzleS32(sint32 value) { + return (sint32)(((uint32)value >> 24) + ((uint32)value << 24) + (((uint32)value&0xff00)<<8) + (((uint32)value&0xff0000)>>8)); + } + + inline uint64 VDSwizzleU64(uint64 value) { + return ((value & 0xFF00000000000000) >> 56) + + ((value & 0x00FF000000000000) >> 40) + + ((value & 0x0000FF0000000000) >> 24) + + ((value & 0x000000FF00000000) >> 8) + + ((value & 0x00000000FF000000) << 8) + + ((value & 0x0000000000FF0000) << 24) + + ((value & 0x000000000000FF00) << 40) + + ((value & 0x00000000000000FF) << 56); + } + + inline sint64 VDSwizzleS64(sint64 value) { + return (sint64)((((uint64)value & 0xFF00000000000000) >> 56) + + (((uint64)value & 0x00FF000000000000) >> 40) + + (((uint64)value & 0x0000FF0000000000) >> 24) + + (((uint64)value & 0x000000FF00000000) >> 8) + + (((uint64)value & 0x00000000FF000000) << 8) + + (((uint64)value & 0x0000000000FF0000) << 24) + + (((uint64)value & 0x000000000000FF00) << 40) + + (((uint64)value & 0x00000000000000FF) << 56)); + } +#endif + +inline uint16 VDReadUnalignedU16(const void *p) { return *(uint16 *)p; } +inline sint16 VDReadUnalignedS16(const void *p) { return *(sint16 *)p; } +inline uint32 VDReadUnalignedU32(const void *p) { return *(uint32 *)p; } +inline sint32 VDReadUnalignedS32(const void *p) { return *(sint32 *)p; } +inline uint64 VDReadUnalignedU64(const void *p) { return *(uint64 *)p; } +inline sint64 VDReadUnalignedS64(const void *p) { return *(sint64 *)p; } +inline float VDReadUnalignedF(const void *p) { return *(float *)p; } +inline double VDReadUnalignedD(const void *p) { return *(double *)p; } + +inline uint16 VDReadUnalignedLEU16(const void *p) { return *(uint16 *)p; } +inline sint16 VDReadUnalignedLES16(const void *p) { return *(sint16 *)p; } +inline uint32 VDReadUnalignedLEU32(const void *p) { return *(uint32 *)p; } +inline sint32 VDReadUnalignedLES32(const void *p) { return *(sint32 *)p; } +inline uint64 VDReadUnalignedLEU64(const void *p) { return *(uint64 *)p; } +inline sint64 VDReadUnalignedLES64(const void *p) { return *(sint64 *)p; } +inline float VDReadUnalignedLEF(const void *p) { return *(float *)p; } +inline double VDReadUnalignedLED(const void *p) { return *(double *)p; } + +inline uint16 VDReadUnalignedBEU16(const void *p) { return VDSwizzleU16(*(uint16 *)p); } +inline sint16 VDReadUnalignedBES16(const void *p) { return VDSwizzleS16(*(sint16 *)p); } +inline uint32 VDReadUnalignedBEU32(const void *p) { return VDSwizzleU32(*(uint32 *)p); } +inline sint32 VDReadUnalignedBES32(const void *p) { return VDSwizzleS32(*(sint32 *)p); } +inline uint64 VDReadUnalignedBEU64(const void *p) { return VDSwizzleU64(*(uint64 *)p); } +inline sint64 VDReadUnalignedBES64(const void *p) { return VDSwizzleS64(*(sint64 *)p); } +inline float VDReadUnalignedBEF(const void *p) { + union { + uint32 i; + float f; + } conv = {VDSwizzleU32(*(const uint32 *)p)}; + return conv.f; +} +inline double VDReadUnalignedBED(const void *p) { + union { + uint64 i; + double d; + } conv = {VDSwizzleU64(*(const uint32 *)p)}; + return conv.d; +} + +inline void VDWriteUnalignedU16 (void *p, uint16 v) { *(uint16 *)p = v; } +inline void VDWriteUnalignedS16 (void *p, sint16 v) { *(sint16 *)p = v; } +inline void VDWriteUnalignedU32 (void *p, uint32 v) { *(uint32 *)p = v; } +inline void VDWriteUnalignedS32 (void *p, sint32 v) { *(sint32 *)p = v; } +inline void VDWriteUnalignedU64 (void *p, uint64 v) { *(uint64 *)p = v; } +inline void VDWriteUnalignedS64 (void *p, sint64 v) { *(sint64 *)p = v; } +inline void VDWriteUnalignedF (void *p, float v) { *(float *)p = v; } +inline void VDWriteUnalignedD (void *p, double v) { *(double *)p = v; } + +inline void VDWriteUnalignedLEU16(void *p, uint16 v) { *(uint16 *)p = v; } +inline void VDWriteUnalignedLES16(void *p, sint16 v) { *(sint16 *)p = v; } +inline void VDWriteUnalignedLEU32(void *p, uint32 v) { *(uint32 *)p = v; } +inline void VDWriteUnalignedLES32(void *p, sint32 v) { *(sint32 *)p = v; } +inline void VDWriteUnalignedLEU64(void *p, uint64 v) { *(uint64 *)p = v; } +inline void VDWriteUnalignedLES64(void *p, sint64 v) { *(sint64 *)p = v; } +inline void VDWriteUnalignedLEF (void *p, float v) { *(float *)p = v; } +inline void VDWriteUnalignedLED (void *p, double v) { *(double *)p = v; } + +inline void VDWriteUnalignedBEU16(void *p, uint16 v) { *(uint16 *)p = VDSwizzleU16(v); } +inline void VDWriteUnalignedBES16(void *p, sint16 v) { *(sint16 *)p = VDSwizzleS16(v); } +inline void VDWriteUnalignedBEU32(void *p, uint32 v) { *(uint32 *)p = VDSwizzleU32(v); } +inline void VDWriteUnalignedBES32(void *p, sint32 v) { *(sint32 *)p = VDSwizzleS32(v); } +inline void VDWriteUnalignedBEU64(void *p, uint64 v) { *(uint64 *)p = VDSwizzleU64(v); } +inline void VDWriteUnalignedBES64(void *p, sint64 v) { *(sint64 *)p = VDSwizzleS64(v); } +inline void VDReadUnalignedBEF(void *p, float v) { + union { + float f; + uint32 i; + } conv = {v}; + *(uint32 *)p = VDSwizzleU32(conv.i); +} +inline double VDReadUnalignedBED(void *p, double v) { + union { + double f; + uint64 i; + } conv = {v}; + *(uint64 *)p = VDSwizzleU64(conv.i); +} + +#define VDFromLE8(x) (x) +#define VDFromLE16(x) (x) +#define VDFromLE32(x) (x) +#define VDFromBE8(x) VDSwizzleU8(x) +#define VDFromBE16(x) VDSwizzleU16(x) +#define VDFromBE32(x) VDSwizzleU32(x) + +#define VDToLE8(x) (x) +#define VDToLE16(x) (x) +#define VDToLE32(x) (x) +#define VDToBE8(x) VDSwizzleU8(x) +#define VDToBE16(x) VDSwizzleU16(x) +#define VDToBE32(x) VDSwizzleU32(x) + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/bitmath.h b/src/thirdparty/VirtualDub/h/vd2/system/bitmath.h index c6bd7607801..308ac6202aa 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/bitmath.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/bitmath.h @@ -1,95 +1,95 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_BITMATH_H -#define f_VD2_SYSTEM_BITMATH_H - -#ifdef _MSC_VER - #pragma once -#endif - -#ifndef f_VD2_SYSTEM_VDTYPES_H - #include -#endif - -int VDCountBits(uint32 v); -int VDFindLowestSetBit(uint32 v); -int VDFindHighestSetBit(uint32 v); -uint32 VDCeilToPow2(uint32 v); - -union VDFloatAsInt { - float f; - sint32 i; -}; - -union VDIntAsFloat { - sint32 i; - float f; -}; - -inline sint32 VDGetFloatAsInt(float f) { - const VDFloatAsInt conv = { f }; - return conv.i; -} - -inline float VDGetIntAsFloat(sint32 i) { - const VDIntAsFloat conv = { i }; - return conv.f; -} - -/////////////////////////////////////////////////////////////////////////////// - -#ifdef VD_COMPILER_MSVC_VC8_OR_LATER - #include - #pragma intrinsic(_BitScanForward) - #pragma intrinsic(_BitScanReverse) - - inline int VDFindLowestSetBit(uint32 v) { - unsigned long index; - return _BitScanForward(&index, v) ? index : 32; - } - - inline int VDFindHighestSetBit(uint32 v) { - unsigned long index; - return _BitScanReverse(&index, v) ? index : -1; - } - - inline int VDFindLowestSetBitFast(uint32 v) { - unsigned long index; - _BitScanForward(&index, v); - return index; - } - - inline int VDFindHighestSetBitFast(uint32 v) { - unsigned long index; - _BitScanReverse(&index, v); - return index; - } -#else - #define VDFindLowestSetBitFast VDFindLowestSetBit - #define VDFindHighestSetBitFast VDFindHighestSetBit -#endif - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_BITMATH_H +#define f_VD2_SYSTEM_BITMATH_H + +#ifdef _MSC_VER + #pragma once +#endif + +#ifndef f_VD2_SYSTEM_VDTYPES_H + #include +#endif + +int VDCountBits(uint32 v); +int VDFindLowestSetBit(uint32 v); +int VDFindHighestSetBit(uint32 v); +uint32 VDCeilToPow2(uint32 v); + +union VDFloatAsInt { + float f; + sint32 i; +}; + +union VDIntAsFloat { + sint32 i; + float f; +}; + +inline sint32 VDGetFloatAsInt(float f) { + const VDFloatAsInt conv = { f }; + return conv.i; +} + +inline float VDGetIntAsFloat(sint32 i) { + const VDIntAsFloat conv = { i }; + return conv.f; +} + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef VD_COMPILER_MSVC_VC8_OR_LATER + #include + #pragma intrinsic(_BitScanForward) + #pragma intrinsic(_BitScanReverse) + + inline int VDFindLowestSetBit(uint32 v) { + unsigned long index; + return _BitScanForward(&index, v) ? index : 32; + } + + inline int VDFindHighestSetBit(uint32 v) { + unsigned long index; + return _BitScanReverse(&index, v) ? index : -1; + } + + inline int VDFindLowestSetBitFast(uint32 v) { + unsigned long index; + _BitScanForward(&index, v); + return index; + } + + inline int VDFindHighestSetBitFast(uint32 v) { + unsigned long index; + _BitScanReverse(&index, v); + return index; + } +#else + #define VDFindLowestSetBitFast VDFindLowestSetBit + #define VDFindHighestSetBitFast VDFindHighestSetBit +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/cache.h b/src/thirdparty/VirtualDub/h/vd2/system/cache.h index e4d45eb152f..599d979fafd 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/cache.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/cache.h @@ -1,325 +1,325 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_CACHE_H -#define f_VD2_SYSTEM_CACHE_H - -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -struct vdfixedhashmap_node { - vdfixedhashmap_node *mpHashPrev; - vdfixedhashmap_node *mpHashNext; -}; - -template -struct vdhash { - size_t operator()(const K key) const { - return (size_t)key; - } -}; - -template, int N = 256> -class vdfixedhashmap_iterator { -public: - typedef vdfixedhashmap_node node; - - bool operator==(vdfixedhashmap_iterator& x) const { return mpNode == x.mpNode; } - bool operator!=(vdfixedhashmap_iterator& x) const { return mpNode != x.mpNode; } - - V& operator*() const { return *static_cast((node *)mpNode); } - V *operator->() const { return static_cast((node *)mpNode); } - - vdfixedhashmap_iterator& operator++() { - do { - mpNode = ((node *)mpNode)->mpHashNext; - if (mpNode != mpTableNode) - break; - - ++mpTableNode; - mpNode = mpTableNode->mpHashNext; - } while(mpNode); - - return *this; - } - - vdfixedhashmap_iterator operator++(int) { - vdfixedhashmap_iterator it(*this); - ++*this; - return it; - } - -public: - vdfixedhashmap_node *mpNode; - vdfixedhashmap_node *mpTableNode; -}; - -template, int N = 256> -class vdfixedhashmap { -public: - typedef K key_type; - typedef V value_type; - typedef Hash hash_type; - typedef vdfixedhashmap_node node; - typedef vdfixedhashmap_iterator iterator; - - vdfixedhashmap() { - for(int i=0; impHashNext; p != r; p = p->mpHashNext) { - if (static_cast(p)->mHashKey == key) - return static_cast(p); - } - - return NULL; - } - - iterator find(const K& key) { - const size_t htidx = m(key) % N; - - node *r = &m.mpTable[htidx]; - for(node *p = r->mpHashNext; p != r; p = p->mpHashNext) { - if (static_cast(p)->mHashKey == key) { - iterator it = { p, &m.mpTable[htidx] }; - return it; - } - } - - return end(); - } - - iterator insert(V *p) { - const size_t htidx = m(p->mHashKey) % N; - - node *r = &m.mpTable[htidx]; - node *n = r->mpHashNext; - r->mpHashNext = p; - p->mpHashPrev = &m.mpTable[htidx]; - p->mpHashNext = n; - n->mpHashPrev = p; - - iterator it = { p, &m.mpTable[htidx] }; - return it; - } - - void erase(V *x) { - node *p = x->mpHashPrev; - node *n = x->mpHashNext; - - p->mpHashNext = n; - n->mpHashPrev = p; - } - - void erase(iterator it) { - erase(it.mpNode); - } - -protected: - struct Data : public Hash { - vdfixedhashmap_node mpTable[N]; - } m; -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDCachedObject; - -class IVDCacheAllocator { -public: - virtual VDCachedObject *OnCacheAllocate() = 0; -}; - -/////////////////////////////////////////////////////////////////////////// - -enum VDCacheState { - kVDCacheStateFree, - kVDCacheStatePending, - kVDCacheStateReady, - kVDCacheStateActive, - kVDCacheStateComplete, - kVDCacheStateIdle, - kVDCacheStateAborting, - kVDCacheStateCount -}; - -struct VDCachedObjectNodes : public vdlist_node, public vdfixedhashmap_node { - sint64 mHashKey; -}; - -class VDCache { -public: - VDCache(IVDCacheAllocator *pAllocator); - ~VDCache(); - - void Shutdown(); - - int GetStateCount(int state); - - void DumpListStatus(int state); - - VDCachedObject *Create(sint64 key, bool& is_new); - - VDCachedObject *Allocate(sint64 key); - void Schedule(VDCachedObject *); // Moves a Pending or Active object to Ready. - VDCachedObject *GetNextReady(); // Selects a Ready object and moves it to Active. - void MarkCompleted(VDCachedObject *); // Marks an object as completed. - -public: - void NotifyFree(VDCachedObject *pObject); - -protected: - void Evict(uint32 level); - -protected: - VDCriticalSection mLock; - - IVDCacheAllocator *mpAllocator; - uint32 mObjectCount; - uint32 mObjectLimit; - - typedef vdlist ObjectList; - ObjectList mLists[kVDCacheStateCount]; - - vdfixedhashmap mHash; -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDCachedObject : private VDCachedObjectNodes { - friend class VDCache; -public: - VDCachedObject(); - virtual ~VDCachedObject() {} - - int AddRef(); - int Release(); - - void WeakAddRef(); - void WeakRelease(); - -protected: - virtual void OnCacheEvict() {} - virtual void OnCacheAbortPending() {} - virtual void DumpStatus() {} - -protected: - int GetRefCount() const { return mRefCount; } - void SetCache(VDCache *pCache); - - VDCacheState GetState() const { return mState; } - void SetState(VDCacheState state) { mState = state; } - - sint64 GetCacheKey() const { return mHashKey; } - - virtual bool IsValid() const { return true; } - -protected: - VDCache *mpCache; - VDAtomicInt mRefCount; - VDCacheState mState; -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDPooledObject; - -class IVDPoolAllocator { -public: - virtual VDPooledObject *OnPoolAllocate() = 0; -}; - -/////////////////////////////////////////////////////////////////////////// - -enum VDPoolState { - kVDPoolStateFree, - kVDPoolStateActive, - kVDPoolStateCount -}; - -struct VDPooledObjectNodes : public vdlist_node {}; - -class VDPool { -public: - VDPool(IVDPoolAllocator *pAllocator); - ~VDPool(); - - void Shutdown(); - - VDPooledObject *Allocate(); - -public: - void NotifyFree(VDPooledObject *pObject); - -protected: - VDCriticalSection mLock; - - IVDPoolAllocator *mpAllocator; - uint32 mObjectCount; - uint32 mObjectLimit; - - typedef vdlist ObjectList; - ObjectList mLists[kVDPoolStateCount]; -}; - -class VDPooledObject : private VDPooledObjectNodes { - friend class VDPool; -public: - VDPooledObject(); - virtual ~VDPooledObject() {} - - int AddRef(); - int Release(); - -protected: - int GetRefCount() const { return mRefCount; } - void SetPool(VDPool *pPool); - -protected: - VDPool *mpPool; - VDAtomicInt mRefCount; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_CACHE_H +#define f_VD2_SYSTEM_CACHE_H + +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +struct vdfixedhashmap_node { + vdfixedhashmap_node *mpHashPrev; + vdfixedhashmap_node *mpHashNext; +}; + +template +struct vdhash { + size_t operator()(const K key) const { + return (size_t)key; + } +}; + +template, int N = 256> +class vdfixedhashmap_iterator { +public: + typedef vdfixedhashmap_node node; + + bool operator==(vdfixedhashmap_iterator& x) const { return mpNode == x.mpNode; } + bool operator!=(vdfixedhashmap_iterator& x) const { return mpNode != x.mpNode; } + + V& operator*() const { return *static_cast((node *)mpNode); } + V *operator->() const { return static_cast((node *)mpNode); } + + vdfixedhashmap_iterator& operator++() { + do { + mpNode = ((node *)mpNode)->mpHashNext; + if (mpNode != mpTableNode) + break; + + ++mpTableNode; + mpNode = mpTableNode->mpHashNext; + } while(mpNode); + + return *this; + } + + vdfixedhashmap_iterator operator++(int) { + vdfixedhashmap_iterator it(*this); + ++*this; + return it; + } + +public: + vdfixedhashmap_node *mpNode; + vdfixedhashmap_node *mpTableNode; +}; + +template, int N = 256> +class vdfixedhashmap { +public: + typedef K key_type; + typedef V value_type; + typedef Hash hash_type; + typedef vdfixedhashmap_node node; + typedef vdfixedhashmap_iterator iterator; + + vdfixedhashmap() { + for(int i=0; impHashNext; p != r; p = p->mpHashNext) { + if (static_cast(p)->mHashKey == key) + return static_cast(p); + } + + return NULL; + } + + iterator find(const K& key) { + const size_t htidx = m(key) % N; + + node *r = &m.mpTable[htidx]; + for(node *p = r->mpHashNext; p != r; p = p->mpHashNext) { + if (static_cast(p)->mHashKey == key) { + iterator it = { p, &m.mpTable[htidx] }; + return it; + } + } + + return end(); + } + + iterator insert(V *p) { + const size_t htidx = m(p->mHashKey) % N; + + node *r = &m.mpTable[htidx]; + node *n = r->mpHashNext; + r->mpHashNext = p; + p->mpHashPrev = &m.mpTable[htidx]; + p->mpHashNext = n; + n->mpHashPrev = p; + + iterator it = { p, &m.mpTable[htidx] }; + return it; + } + + void erase(V *x) { + node *p = x->mpHashPrev; + node *n = x->mpHashNext; + + p->mpHashNext = n; + n->mpHashPrev = p; + } + + void erase(iterator it) { + erase(it.mpNode); + } + +protected: + struct Data : public Hash { + vdfixedhashmap_node mpTable[N]; + } m; +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDCachedObject; + +class IVDCacheAllocator { +public: + virtual VDCachedObject *OnCacheAllocate() = 0; +}; + +/////////////////////////////////////////////////////////////////////////// + +enum VDCacheState { + kVDCacheStateFree, + kVDCacheStatePending, + kVDCacheStateReady, + kVDCacheStateActive, + kVDCacheStateComplete, + kVDCacheStateIdle, + kVDCacheStateAborting, + kVDCacheStateCount +}; + +struct VDCachedObjectNodes : public vdlist_node, public vdfixedhashmap_node { + sint64 mHashKey; +}; + +class VDCache { +public: + VDCache(IVDCacheAllocator *pAllocator); + ~VDCache(); + + void Shutdown(); + + int GetStateCount(int state); + + void DumpListStatus(int state); + + VDCachedObject *Create(sint64 key, bool& is_new); + + VDCachedObject *Allocate(sint64 key); + void Schedule(VDCachedObject *); // Moves a Pending or Active object to Ready. + VDCachedObject *GetNextReady(); // Selects a Ready object and moves it to Active. + void MarkCompleted(VDCachedObject *); // Marks an object as completed. + +public: + void NotifyFree(VDCachedObject *pObject); + +protected: + void Evict(uint32 level); + +protected: + VDCriticalSection mLock; + + IVDCacheAllocator *mpAllocator; + uint32 mObjectCount; + uint32 mObjectLimit; + + typedef vdlist ObjectList; + ObjectList mLists[kVDCacheStateCount]; + + vdfixedhashmap mHash; +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDCachedObject : private VDCachedObjectNodes { + friend class VDCache; +public: + VDCachedObject(); + virtual ~VDCachedObject() {} + + int AddRef(); + int Release(); + + void WeakAddRef(); + void WeakRelease(); + +protected: + virtual void OnCacheEvict() {} + virtual void OnCacheAbortPending() {} + virtual void DumpStatus() {} + +protected: + int GetRefCount() const { return mRefCount; } + void SetCache(VDCache *pCache); + + VDCacheState GetState() const { return mState; } + void SetState(VDCacheState state) { mState = state; } + + sint64 GetCacheKey() const { return mHashKey; } + + virtual bool IsValid() const { return true; } + +protected: + VDCache *mpCache; + VDAtomicInt mRefCount; + VDCacheState mState; +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDPooledObject; + +class IVDPoolAllocator { +public: + virtual VDPooledObject *OnPoolAllocate() = 0; +}; + +/////////////////////////////////////////////////////////////////////////// + +enum VDPoolState { + kVDPoolStateFree, + kVDPoolStateActive, + kVDPoolStateCount +}; + +struct VDPooledObjectNodes : public vdlist_node {}; + +class VDPool { +public: + VDPool(IVDPoolAllocator *pAllocator); + ~VDPool(); + + void Shutdown(); + + VDPooledObject *Allocate(); + +public: + void NotifyFree(VDPooledObject *pObject); + +protected: + VDCriticalSection mLock; + + IVDPoolAllocator *mpAllocator; + uint32 mObjectCount; + uint32 mObjectLimit; + + typedef vdlist ObjectList; + ObjectList mLists[kVDPoolStateCount]; +}; + +class VDPooledObject : private VDPooledObjectNodes { + friend class VDPool; +public: + VDPooledObject(); + virtual ~VDPooledObject() {} + + int AddRef(); + int Release(); + +protected: + int GetRefCount() const { return mRefCount; } + void SetPool(VDPool *pPool); + +protected: + VDPool *mpPool; + VDAtomicInt mRefCount; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/cmdline.h b/src/thirdparty/VirtualDub/h/vd2/system/cmdline.h index f4f217dd54b..5194cae99ff 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/cmdline.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/cmdline.h @@ -1,84 +1,84 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_CMDLINE_H -#define f_VD2_SYSTEM_CMDLINE_H - -#include - -class VDStringSpanW; - -class VDCommandLineIterator { - friend class VDCommandLine; -public: - VDCommandLineIterator() : mIndex(1) {} - -private: - int mIndex; -}; - -class VDCommandLine { -public: - VDCommandLine(); - VDCommandLine(const wchar_t *s); - ~VDCommandLine(); - - void Init(const wchar_t *s); - - // This splits the cmdline using rules that are closer to Visual C++'s: - // - 2N+1 backslashes followed by a quote inserts a literal quote. - // - 2N backslashes followed by a quote toggles the quote state. - // - Outside of a quote, spaces, tabs, and forward slashes delimit parameters. - // - // We still have special switch processing: - // - A parameter starting with a forward slash followed by a ? or an alphanumeric - // char is a switch. A switch is terminated by a non-alphanumeric character or - // a colon. - void InitAlt(const wchar_t *s); - - uint32 GetCount() const; - const wchar_t *operator[](int index) const; - const VDStringSpanW operator()(int index) const; - - bool GetNextArgument(VDCommandLineIterator& index, const wchar_t *& token, bool& isSwitch) const; - bool GetNextNonSwitchArgument(VDCommandLineIterator& index, const wchar_t *& token) const; - bool GetNextSwitchArgument(VDCommandLineIterator& index, const wchar_t *& token) const; - bool FindAndRemoveSwitch(const wchar_t *name); - bool FindAndRemoveSwitch(const wchar_t *name, const wchar_t *& token); - -protected: - void RemoveArgument(int index); - - vdfastvector mLine; - - struct Token { - int mTokenIndex; - bool mbIsSwitch; - }; - - vdfastvector mTokens; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_CMDLINE_H +#define f_VD2_SYSTEM_CMDLINE_H + +#include + +class VDStringSpanW; + +class VDCommandLineIterator { + friend class VDCommandLine; +public: + VDCommandLineIterator() : mIndex(1) {} + +private: + int mIndex; +}; + +class VDCommandLine { +public: + VDCommandLine(); + VDCommandLine(const wchar_t *s); + ~VDCommandLine(); + + void Init(const wchar_t *s); + + // This splits the cmdline using rules that are closer to Visual C++'s: + // - 2N+1 backslashes followed by a quote inserts a literal quote. + // - 2N backslashes followed by a quote toggles the quote state. + // - Outside of a quote, spaces, tabs, and forward slashes delimit parameters. + // + // We still have special switch processing: + // - A parameter starting with a forward slash followed by a ? or an alphanumeric + // char is a switch. A switch is terminated by a non-alphanumeric character or + // a colon. + void InitAlt(const wchar_t *s); + + uint32 GetCount() const; + const wchar_t *operator[](int index) const; + const VDStringSpanW operator()(int index) const; + + bool GetNextArgument(VDCommandLineIterator& index, const wchar_t *& token, bool& isSwitch) const; + bool GetNextNonSwitchArgument(VDCommandLineIterator& index, const wchar_t *& token) const; + bool GetNextSwitchArgument(VDCommandLineIterator& index, const wchar_t *& token) const; + bool FindAndRemoveSwitch(const wchar_t *name); + bool FindAndRemoveSwitch(const wchar_t *name, const wchar_t *& token); + +protected: + void RemoveArgument(int index); + + vdfastvector mLine; + + struct Token { + int mTokenIndex; + bool mbIsSwitch; + }; + + vdfastvector mTokens; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/cpuaccel.h b/src/thirdparty/VirtualDub/h/vd2/system/cpuaccel.h index 829de1c81c8..ff34c2eda74 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/cpuaccel.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/cpuaccel.h @@ -1,51 +1,51 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VIRTUALDUB_CPUACCEL_H -#define f_VIRTUALDUB_CPUACCEL_H - -#define CPUF_SUPPORTS_CPUID (0x00000001L) -#define CPUF_SUPPORTS_FPU (0x00000002L) -#define CPUF_SUPPORTS_MMX (0x00000004L) -#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) -#define CPUF_SUPPORTS_SSE (0x00000010L) -#define CPUF_SUPPORTS_SSE2 (0x00000020L) -#define CPUF_SUPPORTS_3DNOW (0x00000040L) -#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) -#define CPUF_SUPPORTS_SSE3 (0x00000100L) -#define CPUF_SUPPORTS_SSSE3 (0x00000200L) -#define CPUF_SUPPORTS_SSE41 (0x00000400L) -#define CPUF_SUPPORTS_AVX (0x00000800L) -#define CPUF_SUPPORTS_SSE42 (0x00001000L) -#define CPUF_SUPPORTS_MASK (0x00001FFFL) - -long CPUCheckForExtensions(); -long CPUEnableExtensions(long lEnableFlags); -long CPUGetEnabledExtensions(); -void VDCPUCleanupExtensions(); - -extern "C" bool FPU_enabled, MMX_enabled, SSE_enabled, ISSE_enabled, SSE2_enabled; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VIRTUALDUB_CPUACCEL_H +#define f_VIRTUALDUB_CPUACCEL_H + +#define CPUF_SUPPORTS_CPUID (0x00000001L) +#define CPUF_SUPPORTS_FPU (0x00000002L) +#define CPUF_SUPPORTS_MMX (0x00000004L) +#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) +#define CPUF_SUPPORTS_SSE (0x00000010L) +#define CPUF_SUPPORTS_SSE2 (0x00000020L) +#define CPUF_SUPPORTS_3DNOW (0x00000040L) +#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) +#define CPUF_SUPPORTS_SSE3 (0x00000100L) +#define CPUF_SUPPORTS_SSSE3 (0x00000200L) +#define CPUF_SUPPORTS_SSE41 (0x00000400L) +#define CPUF_SUPPORTS_AVX (0x00000800L) +#define CPUF_SUPPORTS_SSE42 (0x00001000L) +#define CPUF_SUPPORTS_MASK (0x00001FFFL) + +long CPUCheckForExtensions(); +long CPUEnableExtensions(long lEnableFlags); +long CPUGetEnabledExtensions(); +void VDCPUCleanupExtensions(); + +extern "C" bool FPU_enabled, MMX_enabled, SSE_enabled, ISSE_enabled, SSE2_enabled; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/debug.h b/src/thirdparty/VirtualDub/h/vd2/system/debug.h index a4eb59e60f2..6ce397361a1 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/debug.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/debug.h @@ -1,96 +1,96 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_DEBUG_H -#define f_VD2_SYSTEM_DEBUG_H - -#include - -class IVDExternalCallTrap { -public: - virtual void OnMMXTrap(const wchar_t *context, const char *file, int line) = 0; - virtual void OnFPUTrap(const wchar_t *context, const char *file, int line, uint16 fpucw) = 0; - virtual void OnSSETrap(const wchar_t *context, const char *file, int line, uint32 mxcsr) = 0; -}; - -void VDSetExternalCallTrap(IVDExternalCallTrap *); - -bool IsMMXState(); -void ClearMMXState(); -void VDClearEvilCPUStates(); -void VDPreCheckExternalCodeCall(const char *file, int line); -void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine); - -struct VDSilentExternalCodeBracket { - VDSilentExternalCodeBracket() { - VDClearEvilCPUStates(); - } - - ~VDSilentExternalCodeBracket() { - VDClearEvilCPUStates(); - } -}; - -struct VDExternalCodeBracketLocation { - VDExternalCodeBracketLocation(const wchar_t *pContext, const char *file, const int line) - : mpContext(pContext) - , mpFile(file) - , mLine(line) - { - } - - const wchar_t *mpContext; - const char *mpFile; - const int mLine; -}; - -struct VDExternalCodeBracket { - VDExternalCodeBracket(const wchar_t *pContext, const char *file, const int line) - : mpContext(pContext) - , mpFile(file) - , mLine(line) - { - VDPreCheckExternalCodeCall(file, line); - } - - VDExternalCodeBracket(const VDExternalCodeBracketLocation& loc) - : mpContext(loc.mpContext) - , mpFile(loc.mpFile) - , mLine(loc.mLine) - { - } - - ~VDExternalCodeBracket() { - VDPostCheckExternalCodeCall(mpContext, mpFile, mLine); - } - - operator bool() const { return false; } - - const wchar_t *mpContext; - const char *mpFile; - const int mLine; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_DEBUG_H +#define f_VD2_SYSTEM_DEBUG_H + +#include + +class IVDExternalCallTrap { +public: + virtual void OnMMXTrap(const wchar_t *context, const char *file, int line) = 0; + virtual void OnFPUTrap(const wchar_t *context, const char *file, int line, uint16 fpucw) = 0; + virtual void OnSSETrap(const wchar_t *context, const char *file, int line, uint32 mxcsr) = 0; +}; + +void VDSetExternalCallTrap(IVDExternalCallTrap *); + +bool IsMMXState(); +void ClearMMXState(); +void VDClearEvilCPUStates(); +void VDPreCheckExternalCodeCall(const char *file, int line); +void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine); + +struct VDSilentExternalCodeBracket { + VDSilentExternalCodeBracket() { + VDClearEvilCPUStates(); + } + + ~VDSilentExternalCodeBracket() { + VDClearEvilCPUStates(); + } +}; + +struct VDExternalCodeBracketLocation { + VDExternalCodeBracketLocation(const wchar_t *pContext, const char *file, const int line) + : mpContext(pContext) + , mpFile(file) + , mLine(line) + { + } + + const wchar_t *mpContext; + const char *mpFile; + const int mLine; +}; + +struct VDExternalCodeBracket { + VDExternalCodeBracket(const wchar_t *pContext, const char *file, const int line) + : mpContext(pContext) + , mpFile(file) + , mLine(line) + { + VDPreCheckExternalCodeCall(file, line); + } + + VDExternalCodeBracket(const VDExternalCodeBracketLocation& loc) + : mpContext(loc.mpContext) + , mpFile(loc.mpFile) + , mLine(loc.mLine) + { + } + + ~VDExternalCodeBracket() { + VDPostCheckExternalCodeCall(mpContext, mpFile, mLine); + } + + operator bool() const { return false; } + + const wchar_t *mpContext; + const char *mpFile; + const int mLine; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/debugx86.h b/src/thirdparty/VirtualDub/h/vd2/system/debugx86.h index 03a4f29a33c..06e1d711cb6 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/debugx86.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/debugx86.h @@ -1,37 +1,37 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -enum VDInstructionTypeX86 { - kX86InstUnknown, - kX86InstP6, - kX86InstMMX, - kX86InstMMX2, - kX86InstSSE, - kX86InstSSE2, - kX86Inst3DNow -}; - -bool VDIsValidCallX86(const char *buf, int len); -VDInstructionTypeX86 VDGetInstructionTypeX86(const void *p); +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +enum VDInstructionTypeX86 { + kX86InstUnknown, + kX86InstP6, + kX86InstMMX, + kX86InstMMX2, + kX86InstSSE, + kX86InstSSE2, + kX86Inst3DNow +}; + +bool VDIsValidCallX86(const char *buf, int len); +VDInstructionTypeX86 VDGetInstructionTypeX86(const void *p); diff --git a/src/thirdparty/VirtualDub/h/vd2/system/event.h b/src/thirdparty/VirtualDub/h/vd2/system/event.h index 66e5394feb4..0af4c436d50 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/event.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/event.h @@ -1,199 +1,199 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_EVENT_H -#define f_VD2_SYSTEM_EVENT_H - -// Because Visual C++ uses different pointer-to-member representations for -// different inheritance regimes, we have to include a whole lot of stupid -// logic to detect and switch code paths based on the inheritance used. -// We detect the inheritance by the size of the member function pointer. -// -// Some have managed to make faster and more compact delegates by hacking -// into the PMT representation and pre-folding the this pointer adjustment. -// I'm avoiding this for now because (a) it's even less portable than what -// we have here, and (b) that fails if the object undergoes a change in -// virtual table status while the delegate is alive (which is possible -// during construction/destruction). -// -// Note: We can't handle virtual inheritance here because on X64, MSVC uses -// 16 bytes for both multiple and virtual inheritance cases. - -#ifdef _MSC_VER - class __single_inheritance VDDelegateHolderS; - class __multiple_inheritance VDDelegateHolderM; -#else - class VDDelegateHolderS; -#endif - -class VDDelegate; - -struct VDDelegateNode { - VDDelegateNode *mpNext, *mpPrev; - - void (*mpCallback)(void *src, const void *info, VDDelegateNode&); - void *mpObj; - -#ifdef _MSC_VER - union { - void (VDDelegateHolderS::*mpFnS)(); - void (VDDelegateHolderM::*mpFnM)(); - }; -#else - void (VDDelegateHolderS::*mpFnS)(); -#endif -}; - -class VDEventBase { -protected: - VDEventBase(); - ~VDEventBase(); - - void Add(VDDelegate&); - void Remove(VDDelegate&); - void Raise(void *src, const void *info); - - VDDelegateNode mAnchor; -}; - -template -class VDDelegateBinding { -public: - VDDelegate *mpBoundDelegate; -}; - -template -struct VDDelegateAdapterS { - typedef void (T::*T_Fn)(Source *, const ArgType&); - typedef void (T::*T_Fn2)(Source *, ArgType); - - static void Init(VDDelegateNode& dst, T_Fn fn) { - dst.mpCallback = Fn; - dst.mpFnS = reinterpret_cast(fn); - } - - static void Init(VDDelegateNode& dst, T_Fn2 fn) { - dst.mpCallback = Fn2; - dst.mpFnS = reinterpret_cast(fn); - } - - static void Fn(void *src, const void *info, VDDelegateNode& del) { - return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnS))(static_cast(src), *static_cast(info)); - } - - static void Fn2(void *src, const void *info, VDDelegateNode& del) { - return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnS))(static_cast(src), *static_cast(info)); - } -}; - -template -class VDDelegateAdapter { -public: - template - struct AdapterLookup { - typedef VDDelegateAdapterS result; - }; -}; - -#ifdef _MSC_VER -template -struct VDDelegateAdapterM { - typedef void (T::*T_Fn)(Source *, const ArgType&); - typedef void (T::*T_Fn2)(Source *, ArgType); - - static void Init(VDDelegateNode& dst, T_Fn fn) { - dst.mpCallback = Fn; - dst.mpFnM = reinterpret_cast(fn); - } - - static void Init(VDDelegateNode& dst, T_Fn2 fn) { - dst.mpCallback = Fn2; - dst.mpFnM = reinterpret_cast(fn); - } - - static void Fn(void *src, const void *info, VDDelegateNode& del) { - return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnM))(static_cast(src), *static_cast(info)); - } - - static void Fn2(void *src, const void *info, VDDelegateNode& del) { - return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnM))(static_cast(src), *static_cast(info)); - } -}; - - -template<> -class VDDelegateAdapter { -public: - template - struct AdapterLookup { - typedef VDDelegateAdapterM result; - }; -}; -#endif - -class VDDelegate : public VDDelegateNode { - friend class VDEventBase; -public: - VDDelegate(); - ~VDDelegate(); - - template - VDDelegateBinding operator()(T *obj, void (T::*fn)(Source *, const ArgType&)) { - mpObj = obj; - - VDDelegateAdapter::template AdapterLookup::result::Init(*this, fn); - - VDDelegateBinding binding = {this}; - return binding; - } - - template - VDDelegateBinding Bind(T *obj, void (T::*fn)(Source *, ArgType)) { - mpObj = obj; - - VDDelegateAdapter::template AdapterLookup::result::Init(*this, fn); - - VDDelegateBinding binding = {this}; - return binding; - } -}; - -template -class VDEvent : public VDEventBase { -public: - void operator+=(const VDDelegateBinding& binding) { - Add(*binding.mpBoundDelegate); - } - - void operator-=(VDDelegate& del) { - Remove(del); - } - - void Raise(Source *src, const ArgType& args) { - VDEventBase::Raise(src, &args); - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_EVENT_H +#define f_VD2_SYSTEM_EVENT_H + +// Because Visual C++ uses different pointer-to-member representations for +// different inheritance regimes, we have to include a whole lot of stupid +// logic to detect and switch code paths based on the inheritance used. +// We detect the inheritance by the size of the member function pointer. +// +// Some have managed to make faster and more compact delegates by hacking +// into the PMT representation and pre-folding the this pointer adjustment. +// I'm avoiding this for now because (a) it's even less portable than what +// we have here, and (b) that fails if the object undergoes a change in +// virtual table status while the delegate is alive (which is possible +// during construction/destruction). +// +// Note: We can't handle virtual inheritance here because on X64, MSVC uses +// 16 bytes for both multiple and virtual inheritance cases. + +#ifdef _MSC_VER + class __single_inheritance VDDelegateHolderS; + class __multiple_inheritance VDDelegateHolderM; +#else + class VDDelegateHolderS; +#endif + +class VDDelegate; + +struct VDDelegateNode { + VDDelegateNode *mpNext, *mpPrev; + + void (*mpCallback)(void *src, const void *info, VDDelegateNode&); + void *mpObj; + +#ifdef _MSC_VER + union { + void (VDDelegateHolderS::*mpFnS)(); + void (VDDelegateHolderM::*mpFnM)(); + }; +#else + void (VDDelegateHolderS::*mpFnS)(); +#endif +}; + +class VDEventBase { +protected: + VDEventBase(); + ~VDEventBase(); + + void Add(VDDelegate&); + void Remove(VDDelegate&); + void Raise(void *src, const void *info); + + VDDelegateNode mAnchor; +}; + +template +class VDDelegateBinding { +public: + VDDelegate *mpBoundDelegate; +}; + +template +struct VDDelegateAdapterS { + typedef void (T::*T_Fn)(Source *, const ArgType&); + typedef void (T::*T_Fn2)(Source *, ArgType); + + static void Init(VDDelegateNode& dst, T_Fn fn) { + dst.mpCallback = Fn; + dst.mpFnS = reinterpret_cast(fn); + } + + static void Init(VDDelegateNode& dst, T_Fn2 fn) { + dst.mpCallback = Fn2; + dst.mpFnS = reinterpret_cast(fn); + } + + static void Fn(void *src, const void *info, VDDelegateNode& del) { + return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnS))(static_cast(src), *static_cast(info)); + } + + static void Fn2(void *src, const void *info, VDDelegateNode& del) { + return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnS))(static_cast(src), *static_cast(info)); + } +}; + +template +class VDDelegateAdapter { +public: + template + struct AdapterLookup { + typedef VDDelegateAdapterS result; + }; +}; + +#ifdef _MSC_VER +template +struct VDDelegateAdapterM { + typedef void (T::*T_Fn)(Source *, const ArgType&); + typedef void (T::*T_Fn2)(Source *, ArgType); + + static void Init(VDDelegateNode& dst, T_Fn fn) { + dst.mpCallback = Fn; + dst.mpFnM = reinterpret_cast(fn); + } + + static void Init(VDDelegateNode& dst, T_Fn2 fn) { + dst.mpCallback = Fn2; + dst.mpFnM = reinterpret_cast(fn); + } + + static void Fn(void *src, const void *info, VDDelegateNode& del) { + return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnM))(static_cast(src), *static_cast(info)); + } + + static void Fn2(void *src, const void *info, VDDelegateNode& del) { + return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnM))(static_cast(src), *static_cast(info)); + } +}; + + +template<> +class VDDelegateAdapter { +public: + template + struct AdapterLookup { + typedef VDDelegateAdapterM result; + }; +}; +#endif + +class VDDelegate : public VDDelegateNode { + friend class VDEventBase; +public: + VDDelegate(); + ~VDDelegate(); + + template + VDDelegateBinding operator()(T *obj, void (T::*fn)(Source *, const ArgType&)) { + mpObj = obj; + + VDDelegateAdapter::template AdapterLookup::result::Init(*this, fn); + + VDDelegateBinding binding = {this}; + return binding; + } + + template + VDDelegateBinding Bind(T *obj, void (T::*fn)(Source *, ArgType)) { + mpObj = obj; + + VDDelegateAdapter::template AdapterLookup::result::Init(*this, fn); + + VDDelegateBinding binding = {this}; + return binding; + } +}; + +template +class VDEvent : public VDEventBase { +public: + void operator+=(const VDDelegateBinding& binding) { + Add(*binding.mpBoundDelegate); + } + + void operator-=(VDDelegate& del) { + Remove(del); + } + + void Raise(Source *src, const ArgType& args) { + VDEventBase::Raise(src, &args); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/file.h b/src/thirdparty/VirtualDub/h/vd2/system/file.h index 4ee3d77a062..53aeae75800 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/file.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/file.h @@ -1,327 +1,327 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_FILE_H -#define f_VD2_SYSTEM_FILE_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include -#include -#include -#include - -#ifdef WIN32 - typedef void *VDFileHandle; // this needs to match wtypes.h definition for HANDLE -#else - #error No operating system target declared?? -#endif - -namespace nsVDFile { - enum eSeekMode { - kSeekStart=0, kSeekCur, kSeekEnd - }; - - enum eFlags { - kRead = 0x00000001, - kWrite = 0x00000002, - kReadWrite = kRead | kWrite, - - kDenyNone = 0x00000000, - kDenyRead = 0x00000010, - kDenyWrite = 0x00000020, - kDenyAll = kDenyRead | kDenyWrite, - - kOpenExisting = 0x00000100, - kOpenAlways = 0x00000200, - kCreateAlways = 0x00000300, - kCreateNew = 0x00000400, - kTruncateExisting = 0x00000500, // not particularly useful, really - kCreationMask = 0x0000FF00, - - kSequential = 0x00010000, - kRandomAccess = 0x00020000, - kUnbuffered = 0x00040000, // much faster on Win32 thanks to the crappy cache, but possibly bad in Unix? - kWriteThrough = 0x00080000, - - kAllFileFlags = 0xFFFFFFFF - }; -}; - -class VDFile { -protected: - VDFileHandle mhFile; - vdautoptr2 mpFilename; - sint64 mFilePosition; - -private: - VDFile(const VDFile&); - const VDFile& operator=(const VDFile& f); - -public: - VDFile() : mhFile(NULL) {} - VDFile(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - VDFile(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - VDFile(VDFileHandle h); - ~VDFile(); - - // The "NT" functions are non-throwing and return success/failure; the regular functions throw exceptions - // when something bad happens. - - void open(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - void open(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - - bool openNT(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - - bool closeNT(); - void close(); - bool truncateNT(); - void truncate(); - - // extendValid() pushes the valid threshold of a file out, so that the system allocates - // space for a file without ensuring that it is cleared. It is mainly useful for - // preallocating a file without waiting for the system to clear all of it. The caveats: - // - // - only required on NTFS - // - requires Windows XP or Windows Server 2003 - // - does not work on compressed or sparse files - // - // As such, it shouldn't normally be relied upon, and extendValidNT() should be the call - // of choice. - // - // enableExtendValid() must be called beforehand, as SeVolumeNamePrivilege must be - // enabled on the process before the file is opened! - - bool extendValidNT(sint64 pos); - void extendValid(sint64 pos); - static bool enableExtendValid(); - - sint64 size(); - void read(void *buffer, long length); - long readData(void *buffer, long length); - void write(const void *buffer, long length); - long writeData(const void *buffer, long length); - bool seekNT(sint64 newPos, nsVDFile::eSeekMode mode = nsVDFile::kSeekStart); - void seek(sint64 newPos, nsVDFile::eSeekMode mode = nsVDFile::kSeekStart); - bool skipNT(sint64 delta); - void skip(sint64 delta); - sint64 tell(); - - bool flushNT(); - void flush(); - - bool isOpen(); - VDFileHandle getRawHandle(); - - const wchar_t *getFilenameForError() const { return mpFilename; } - - // unbuffered I/O requires aligned buffers ("unbuffers") - static void *AllocUnbuffer(size_t nBytes); - static void FreeUnbuffer(void *p); - -protected: - bool open_internal(const char *pszFilename, const wchar_t *pwszFilename, uint32 flags, bool throwOnError); -}; - -/////////////////////////////////////////////////////////////////////////// - -template -class VDFileUnbufferAllocator { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template struct rebind { typedef VDFileUnbufferAllocator other; }; - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, void *p = 0) { return (pointer)VDFile::AllocUnbuffer(n * sizeof(T)); } - void deallocate(pointer p, size_type n) { VDFile::FreeUnbuffer(p); } - size_type max_size() const throw() { return INT_MAX; } - - void construct(pointer p, const T& val) { new((void *)p) T(val); } - void destroy(pointer p) { ((T*)p)->~T(); } - -#if defined(_MSC_VER) && _MSC_VER < 1300 - char * _Charalloc(size_type n) { return (char *)allocate((n + sizeof(T) - 1) / sizeof(T)); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////// - -class IVDStream { -public: - virtual const wchar_t *GetNameForError() = 0; - virtual sint64 Pos() = 0; - virtual void Read(void *buffer, sint32 bytes) = 0; - virtual sint32 ReadData(void *buffer, sint32 bytes) = 0; - virtual void Write(const void *buffer, sint32 bytes) = 0; -}; - -class IVDRandomAccessStream : public IVDStream { -public: - virtual sint64 Length() = 0; - virtual void Seek(sint64 offset) = 0; -}; - -class VDFileStream : public VDFile, public IVDRandomAccessStream { -private: - VDFileStream(const VDFile&); - const VDFileStream& operator=(const VDFileStream& f); - -public: - VDFileStream() {} - VDFileStream(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting) - : VDFile(pszFileName, flags) {} - VDFileStream(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting) - : VDFile(pwszFileName, flags) {} - VDFileStream(VDFileHandle h) : VDFile(h) {} - ~VDFileStream(); - - const wchar_t *GetNameForError(); - sint64 Pos(); - void Read(void *buffer, sint32 bytes); - sint32 ReadData(void *buffer, sint32 bytes); - void Write(const void *buffer, sint32 bytes); - sint64 Length(); - void Seek(sint64 offset); -}; - -class VDMemoryStream : public IVDRandomAccessStream { -public: - VDMemoryStream(const void *pSrc, uint32 len); - - const wchar_t *GetNameForError(); - sint64 Pos(); - void Read(void *buffer, sint32 bytes); - sint32 ReadData(void *buffer, sint32 bytes); - void Write(const void *buffer, sint32 bytes); - sint64 Length(); - void Seek(sint64 offset); - -protected: - const char *mpSrc; - const uint32 mLength; - uint32 mPos; -}; - -class VDBufferedStream : public IVDRandomAccessStream { -public: - VDBufferedStream(IVDRandomAccessStream *pSrc, uint32 bufferSize); - ~VDBufferedStream(); - - const wchar_t *GetNameForError(); - sint64 Pos(); - void Read(void *buffer, sint32 bytes); - sint32 ReadData(void *buffer, sint32 bytes); - void Write(const void *buffer, sint32 bytes); - - sint64 Length(); - void Seek(sint64 offset); - - void Skip(sint64 size); - -protected: - IVDRandomAccessStream *mpSrc; - vdblock mBuffer; - sint64 mBasePosition; - uint32 mBufferOffset; - uint32 mBufferValidSize; -}; - -class VDTextStream { -public: - VDTextStream(IVDStream *pSrc); - ~VDTextStream(); - - const char *GetNextLine(); - -protected: - IVDStream *mpSrc; - uint32 mBufferPos; - uint32 mBufferLimit; - enum { - kFetchLine, - kEatNextIfCR, - kEatNextIfLF - } mState; - - enum { - kFileBufferSize = 4096 - }; - - vdfastvector mLineBuffer; - vdblock mFileBuffer; -}; - -class VDTextInputFile { -public: - VDTextInputFile(const wchar_t *filename, uint32 flags = nsVDFile::kOpenExisting); - ~VDTextInputFile(); - - inline const char *GetNextLine() { - return mTextStream.GetNextLine(); - } - -protected: - VDFileStream mFileStream; - VDTextStream mTextStream; -}; - -class VDTextOutputStream { -public: - VDTextOutputStream(IVDStream *stream); - ~VDTextOutputStream(); - - void Flush(); - - void Write(const char *s); - void Write(const char *s, int len); - void PutLine(); - void PutLine(const char *s); - void Format(const char *format, ...); - void FormatLine(const char *format, ...); - -protected: - void Format2(const char *format, va_list val); - void PutData(const char *s, int len); - - enum { kBufSize = 4096 }; - - int mLevel; - IVDStream *mpDst; - char mBuf[kBufSize]; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_FILE_H +#define f_VD2_SYSTEM_FILE_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include +#include +#include + +#ifdef WIN32 + typedef void *VDFileHandle; // this needs to match wtypes.h definition for HANDLE +#else + #error No operating system target declared?? +#endif + +namespace nsVDFile { + enum eSeekMode { + kSeekStart=0, kSeekCur, kSeekEnd + }; + + enum eFlags { + kRead = 0x00000001, + kWrite = 0x00000002, + kReadWrite = kRead | kWrite, + + kDenyNone = 0x00000000, + kDenyRead = 0x00000010, + kDenyWrite = 0x00000020, + kDenyAll = kDenyRead | kDenyWrite, + + kOpenExisting = 0x00000100, + kOpenAlways = 0x00000200, + kCreateAlways = 0x00000300, + kCreateNew = 0x00000400, + kTruncateExisting = 0x00000500, // not particularly useful, really + kCreationMask = 0x0000FF00, + + kSequential = 0x00010000, + kRandomAccess = 0x00020000, + kUnbuffered = 0x00040000, // much faster on Win32 thanks to the crappy cache, but possibly bad in Unix? + kWriteThrough = 0x00080000, + + kAllFileFlags = 0xFFFFFFFF + }; +}; + +class VDFile { +protected: + VDFileHandle mhFile; + vdautoptr2 mpFilename; + sint64 mFilePosition; + +private: + VDFile(const VDFile&); + const VDFile& operator=(const VDFile& f); + +public: + VDFile() : mhFile(NULL) {} + VDFile(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + VDFile(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + VDFile(VDFileHandle h); + ~VDFile(); + + // The "NT" functions are non-throwing and return success/failure; the regular functions throw exceptions + // when something bad happens. + + void open(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + void open(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + + bool openNT(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + + bool closeNT(); + void close(); + bool truncateNT(); + void truncate(); + + // extendValid() pushes the valid threshold of a file out, so that the system allocates + // space for a file without ensuring that it is cleared. It is mainly useful for + // preallocating a file without waiting for the system to clear all of it. The caveats: + // + // - only required on NTFS + // - requires Windows XP or Windows Server 2003 + // - does not work on compressed or sparse files + // + // As such, it shouldn't normally be relied upon, and extendValidNT() should be the call + // of choice. + // + // enableExtendValid() must be called beforehand, as SeVolumeNamePrivilege must be + // enabled on the process before the file is opened! + + bool extendValidNT(sint64 pos); + void extendValid(sint64 pos); + static bool enableExtendValid(); + + sint64 size(); + void read(void *buffer, long length); + long readData(void *buffer, long length); + void write(const void *buffer, long length); + long writeData(const void *buffer, long length); + bool seekNT(sint64 newPos, nsVDFile::eSeekMode mode = nsVDFile::kSeekStart); + void seek(sint64 newPos, nsVDFile::eSeekMode mode = nsVDFile::kSeekStart); + bool skipNT(sint64 delta); + void skip(sint64 delta); + sint64 tell(); + + bool flushNT(); + void flush(); + + bool isOpen(); + VDFileHandle getRawHandle(); + + const wchar_t *getFilenameForError() const { return mpFilename; } + + // unbuffered I/O requires aligned buffers ("unbuffers") + static void *AllocUnbuffer(size_t nBytes); + static void FreeUnbuffer(void *p); + +protected: + bool open_internal(const char *pszFilename, const wchar_t *pwszFilename, uint32 flags, bool throwOnError); +}; + +/////////////////////////////////////////////////////////////////////////// + +template +class VDFileUnbufferAllocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template struct rebind { typedef VDFileUnbufferAllocator other; }; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, void *p = 0) { return (pointer)VDFile::AllocUnbuffer(n * sizeof(T)); } + void deallocate(pointer p, size_type n) { VDFile::FreeUnbuffer(p); } + size_type max_size() const throw() { return INT_MAX; } + + void construct(pointer p, const T& val) { new((void *)p) T(val); } + void destroy(pointer p) { ((T*)p)->~T(); } + +#if defined(_MSC_VER) && _MSC_VER < 1300 + char * _Charalloc(size_type n) { return (char *)allocate((n + sizeof(T) - 1) / sizeof(T)); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////// + +class IVDStream { +public: + virtual const wchar_t *GetNameForError() = 0; + virtual sint64 Pos() = 0; + virtual void Read(void *buffer, sint32 bytes) = 0; + virtual sint32 ReadData(void *buffer, sint32 bytes) = 0; + virtual void Write(const void *buffer, sint32 bytes) = 0; +}; + +class IVDRandomAccessStream : public IVDStream { +public: + virtual sint64 Length() = 0; + virtual void Seek(sint64 offset) = 0; +}; + +class VDFileStream : public VDFile, public IVDRandomAccessStream { +private: + VDFileStream(const VDFile&); + const VDFileStream& operator=(const VDFileStream& f); + +public: + VDFileStream() {} + VDFileStream(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting) + : VDFile(pszFileName, flags) {} + VDFileStream(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting) + : VDFile(pwszFileName, flags) {} + VDFileStream(VDFileHandle h) : VDFile(h) {} + ~VDFileStream(); + + const wchar_t *GetNameForError(); + sint64 Pos(); + void Read(void *buffer, sint32 bytes); + sint32 ReadData(void *buffer, sint32 bytes); + void Write(const void *buffer, sint32 bytes); + sint64 Length(); + void Seek(sint64 offset); +}; + +class VDMemoryStream : public IVDRandomAccessStream { +public: + VDMemoryStream(const void *pSrc, uint32 len); + + const wchar_t *GetNameForError(); + sint64 Pos(); + void Read(void *buffer, sint32 bytes); + sint32 ReadData(void *buffer, sint32 bytes); + void Write(const void *buffer, sint32 bytes); + sint64 Length(); + void Seek(sint64 offset); + +protected: + const char *mpSrc; + const uint32 mLength; + uint32 mPos; +}; + +class VDBufferedStream : public IVDRandomAccessStream { +public: + VDBufferedStream(IVDRandomAccessStream *pSrc, uint32 bufferSize); + ~VDBufferedStream(); + + const wchar_t *GetNameForError(); + sint64 Pos(); + void Read(void *buffer, sint32 bytes); + sint32 ReadData(void *buffer, sint32 bytes); + void Write(const void *buffer, sint32 bytes); + + sint64 Length(); + void Seek(sint64 offset); + + void Skip(sint64 size); + +protected: + IVDRandomAccessStream *mpSrc; + vdblock mBuffer; + sint64 mBasePosition; + uint32 mBufferOffset; + uint32 mBufferValidSize; +}; + +class VDTextStream { +public: + VDTextStream(IVDStream *pSrc); + ~VDTextStream(); + + const char *GetNextLine(); + +protected: + IVDStream *mpSrc; + uint32 mBufferPos; + uint32 mBufferLimit; + enum { + kFetchLine, + kEatNextIfCR, + kEatNextIfLF + } mState; + + enum { + kFileBufferSize = 4096 + }; + + vdfastvector mLineBuffer; + vdblock mFileBuffer; +}; + +class VDTextInputFile { +public: + VDTextInputFile(const wchar_t *filename, uint32 flags = nsVDFile::kOpenExisting); + ~VDTextInputFile(); + + inline const char *GetNextLine() { + return mTextStream.GetNextLine(); + } + +protected: + VDFileStream mFileStream; + VDTextStream mTextStream; +}; + +class VDTextOutputStream { +public: + VDTextOutputStream(IVDStream *stream); + ~VDTextOutputStream(); + + void Flush(); + + void Write(const char *s); + void Write(const char *s, int len); + void PutLine(); + void PutLine(const char *s); + void Format(const char *format, ...); + void FormatLine(const char *format, ...); + +protected: + void Format2(const char *format, va_list val); + void PutData(const char *s, int len); + + enum { kBufSize = 4096 }; + + int mLevel; + IVDStream *mpDst; + char mBuf[kBufSize]; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/fileasync.h b/src/thirdparty/VirtualDub/h/vd2/system/fileasync.h index 753d3488f39..de0ed37a501 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/fileasync.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/fileasync.h @@ -1,67 +1,67 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_FILEASYNC_H -#define f_VD2_SYSTEM_FILEASYNC_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include - -class VDRTProfileChannel; - -class IVDFileAsync { -public: - enum Mode { - kModeSynchronous, ///< Use synchronous I/O. - kModeThreaded, ///< Use multithreaded I/O. - kModeAsynchronous, ///< Use true asynchronous I/O (Windows NT only). - kModeBuffered, ///< Use regular buffered synchronous I/O - kModeCount - }; - - virtual ~IVDFileAsync() {} - virtual void SetPreemptiveExtend(bool b) = 0; - virtual bool IsPreemptiveExtendActive() = 0; - virtual bool IsOpen() = 0; - virtual void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) = 0; - virtual void Open(VDFileHandle h, uint32 count, uint32 bufferSize) = 0; - virtual void Close() = 0; - virtual void FastWrite(const void *pData, uint32 bytes) = 0; - virtual void FastWriteEnd() = 0; - virtual void Write(sint64 pos, const void *pData, uint32 bytes) = 0; - virtual bool Extend(sint64 pos) = 0; - virtual void Truncate(sint64 pos) = 0; - virtual void SafeTruncateAndClose(sint64 pos) = 0; - virtual sint64 GetFastWritePos() = 0; - virtual sint64 GetSize() = 0; -}; - -IVDFileAsync *VDCreateFileAsync(IVDFileAsync::Mode); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_FILEASYNC_H +#define f_VD2_SYSTEM_FILEASYNC_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include + +class VDRTProfileChannel; + +class IVDFileAsync { +public: + enum Mode { + kModeSynchronous, ///< Use synchronous I/O. + kModeThreaded, ///< Use multithreaded I/O. + kModeAsynchronous, ///< Use true asynchronous I/O (Windows NT only). + kModeBuffered, ///< Use regular buffered synchronous I/O + kModeCount + }; + + virtual ~IVDFileAsync() {} + virtual void SetPreemptiveExtend(bool b) = 0; + virtual bool IsPreemptiveExtendActive() = 0; + virtual bool IsOpen() = 0; + virtual void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) = 0; + virtual void Open(VDFileHandle h, uint32 count, uint32 bufferSize) = 0; + virtual void Close() = 0; + virtual void FastWrite(const void *pData, uint32 bytes) = 0; + virtual void FastWriteEnd() = 0; + virtual void Write(sint64 pos, const void *pData, uint32 bytes) = 0; + virtual bool Extend(sint64 pos) = 0; + virtual void Truncate(sint64 pos) = 0; + virtual void SafeTruncateAndClose(sint64 pos) = 0; + virtual sint64 GetFastWritePos() = 0; + virtual sint64 GetSize() = 0; +}; + +IVDFileAsync *VDCreateFileAsync(IVDFileAsync::Mode); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/halffloat.h b/src/thirdparty/VirtualDub/h/vd2/system/halffloat.h index e65a4109c53..df7ab9483ab 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/halffloat.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/halffloat.h @@ -1,9 +1,9 @@ -#ifndef f_VD2_SYSTEM_HALFFLOAT_H -#define f_VD2_SYSTEM_HALFFLOAT_H - -#include - -uint16 VDConvertFloatToHalf(const void *f); -void VDConvertHalfToFloat(uint16 h, void *dst); - -#endif // f_VD2_SYSTEM_HALFFLOAT_H +#ifndef f_VD2_SYSTEM_HALFFLOAT_H +#define f_VD2_SYSTEM_HALFFLOAT_H + +#include + +uint16 VDConvertFloatToHalf(const void *f); +void VDConvertHalfToFloat(uint16 h, void *dst); + +#endif // f_VD2_SYSTEM_HALFFLOAT_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/hash.h b/src/thirdparty/VirtualDub/h/vd2/system/hash.h index 9b93f3e2c75..a26c1ead760 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/hash.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/hash.h @@ -1,51 +1,51 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_HASH_H -#define f_VD2_SYSTEM_HASH_H - -#ifdef _MSC_VER - #pragma once -#endif - -#ifndef f_VD2_SYSTEM_VDTYPES_H - #include -#endif - -// Case-sensitive string hashes - -uint32 VDHashString32(const char *s); -uint32 VDHashString32(const char *s, uint32 len); -uint32 VDHashString32(const wchar_t *s); -uint32 VDHashString32(const wchar_t *s, uint32 len); - -// Case-insensitive, culture-invariant string hashes - -uint32 VDHashString32I(const char *s); -uint32 VDHashString32I(const char *s, uint32 len); -uint32 VDHashString32I(const wchar_t *s); -uint32 VDHashString32I(const wchar_t *s, uint32 len); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_HASH_H +#define f_VD2_SYSTEM_HASH_H + +#ifdef _MSC_VER + #pragma once +#endif + +#ifndef f_VD2_SYSTEM_VDTYPES_H + #include +#endif + +// Case-sensitive string hashes + +uint32 VDHashString32(const char *s); +uint32 VDHashString32(const char *s, uint32 len); +uint32 VDHashString32(const wchar_t *s); +uint32 VDHashString32(const wchar_t *s, uint32 len); + +// Case-insensitive, culture-invariant string hashes + +uint32 VDHashString32I(const char *s); +uint32 VDHashString32I(const char *s, uint32 len); +uint32 VDHashString32I(const wchar_t *s); +uint32 VDHashString32I(const wchar_t *s, uint32 len); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/int128.h b/src/thirdparty/VirtualDub/h/vd2/system/int128.h index ebef416cc89..b89cb179c6d 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/int128.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/int128.h @@ -1,375 +1,375 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_INT128_H -#define f_VD2_SYSTEM_INT128_H - -#include - -struct vdint128; -struct vduint128; - -#ifdef _M_AMD64 - extern "C" __int64 _mul128(__int64 x, __int64 y, __int64 *hiresult); - extern "C" unsigned __int64 _umul128(unsigned __int64 x, unsigned __int64 y, unsigned __int64 *hiresult); - extern "C" unsigned __int64 __shiftleft128(unsigned __int64 low, unsigned __int64 high, unsigned char shift); - extern "C" unsigned __int64 __shiftright128(unsigned __int64 low, unsigned __int64 high, unsigned char shift); - - #pragma intrinsic(_mul128) - #pragma intrinsic(_umul128) - #pragma intrinsic(__shiftleft128) - #pragma intrinsic(__shiftright128) - - extern "C" { - void vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - void vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - void vdasm_uint128_mul(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - } -#else - extern "C" { - void __cdecl vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - void __cdecl vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - } -#endif - -struct vdint128 { -public: - union { - sint32 d[4]; - sint64 q[2]; - }; - - vdint128() {} - - vdint128(sint64 x) { - q[0] = x; - q[1] = x>>63; - } - - vdint128(uint64 x) { - q[0] = (sint64)x; - q[1] = 0; - } - - vdint128(int x) { - q[0] = x; - q[1] = (sint64)x >> 63; - } - - vdint128(unsigned int x) { - q[0] = x; - q[1] = 0; - } - - vdint128(unsigned long x) { - q[0] = x; - q[1] = 0; - } - - vdint128(sint64 hi, uint64 lo) { - q[0] = lo; - q[1] = hi; - } - - explicit inline vdint128(const vduint128& x); - - sint64 getHi() const { return q[1]; } - uint64 getLo() const { return q[0]; } - - operator double() const; - operator sint64() const { - return (sint64)q[0]; - } - operator uint64() const { - return (uint64)q[0]; - } - - bool operator==(const vdint128& x) const { - return q[1] == x.q[1] && q[0] == x.q[0]; - } - - bool operator!=(const vdint128& x) const { - return q[1] != x.q[1] || q[0] != x.q[0]; - } - - bool operator<(const vdint128& x) const { - return q[1] < x.q[1] || (q[1] == x.q[1] && (uint64)q[0] < (uint64)x.q[0]); - } - - bool operator<=(const vdint128& x) const { - return q[1] < x.q[1] || (q[1] == x.q[1] && (uint64)q[0] <= (uint64)x.q[0]); - } - - bool operator>(const vdint128& x) const { - return q[1] > x.q[1] || (q[1] == x.q[1] && (uint64)q[0] > (uint64)x.q[0]); - } - - bool operator>=(const vdint128& x) const { - return q[1] > x.q[1] || (q[1] == x.q[1] && (uint64)q[0] >= (uint64)x.q[0]); - } - - const vdint128 operator+(const vdint128& x) const { - vdint128 t; - vdasm_uint128_add((uint64 *)t.q, (const uint64 *)q, (const uint64 *)x.q); - return t; - } - - const vdint128 operator-(const vdint128& x) const { - vdint128 t; - vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)q, (const uint64 *)x.q); - return t; - } - - const vdint128& operator+=(const vdint128& x) { - vdasm_uint128_add((uint64 *)q, (const uint64 *)q, (const uint64 *)x.q); - return *this; - } - - const vdint128& operator-=(const vdint128& x) { - vdasm_uint128_sub((uint64 *)q, (const uint64 *)q, (const uint64 *)x.q); - return *this; - } - - const vdint128 operator*(const vdint128& x) const; - - const vdint128 operator/(int x) const; - - const vdint128 operator-() const { - vdint128 t(0); - vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)t.q, (const uint64 *)q); - return t; - } - - const vdint128 abs() const { - return q[1] < 0 ? -*this : *this; - } - -#ifdef _M_AMD64 - void setSquare(sint64 v) { - const vdint128 v128(v); - operator=(v128*v128); - } - - const vdint128 operator<<(int count) const { - vdint128 t; - - if (count >= 64) { - t.q[0] = 0; - t.q[1] = q[0] << (count-64); - } else { - t.q[0] = q[0] << count; - t.q[1] = __shiftleft128(q[0], q[1], count); - } - - return t; - } - - const vdint128 operator>>(int count) const { - vdint128 t; - - if (count >= 64) { - t.q[0] = q[1] >> (count-64); - t.q[1] = q[1] >> 63; - } else { - t.q[0] = __shiftright128(q[0], q[1], count); - t.q[1] = q[1] >> count; - } - - return t; - } -#else - void setSquare(sint64 v); - - const vdint128 operator<<(int v) const; - const vdint128 operator>>(int v) const; -#endif -}; - -struct vduint128 { -public: - union { - uint32 d[4]; - uint64 q[2]; - }; - - vduint128() {} - - vduint128(sint64 x) { - q[0] = (sint64)x; - q[1] = 0; - } - - vduint128(uint64 x) { - q[0] = x; - q[1] = 0; - } - - vduint128(int x) { - q[0] = (uint64)x; - q[1] = 0; - } - - vduint128(unsigned x) { - q[0] = x; - q[1] = 0; - } - - vduint128(uint64 hi, uint64 lo) { - q[0] = lo; - q[1] = hi; - } - - explicit inline vduint128(const vdint128& x); - - uint64 getHi() const { return q[1]; } - uint64 getLo() const { return q[0]; } - - operator sint64() const { - return (sint64)q[0]; - } - - operator uint64() const { - return (uint64)q[0]; - } - - bool operator==(const vduint128& x) const { - return q[1] == x.q[1] && q[0] == x.q[0]; - } - - bool operator!=(const vduint128& x) const { - return q[1] != x.q[1] || q[0] != x.q[0]; - } - - bool operator<(const vduint128& x) const { - return q[1] < x.q[1] || (q[1] == x.q[1] && q[0] < x.q[0]); - } - - bool operator<=(const vduint128& x) const { - return q[1] < x.q[1] || (q[1] == x.q[1] && q[0] <= x.q[0]); - } - - bool operator>(const vduint128& x) const { - return q[1] > x.q[1] || (q[1] == x.q[1] && q[0] > x.q[0]); - } - - bool operator>=(const vduint128& x) const { - return q[1] > x.q[1] || (q[1] == x.q[1] && q[0] >= x.q[0]); - } - - const vduint128 operator+(const vduint128& x) const { - vduint128 t; - vdasm_uint128_add(t.q, q, x.q); - return t; - } - - const vduint128 operator-(const vduint128& x) const { - vduint128 t; - vdasm_uint128_sub(t.q, q, x.q); - return t; - } - - const vduint128& operator+=(const vduint128& x) { - vdasm_uint128_add(q, q, x.q); - return *this; - } - - const vduint128& operator-=(const vduint128& x) { - vdasm_uint128_sub(q, q, x.q); - return *this; - } - - const vduint128 operator*(const vduint128& x) const; - - const vduint128 operator-() const { - vduint128 t(0U); - vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)t.q, (const uint64 *)q); - return t; - } - - vduint128& operator<<=(int count) { - return operator=(operator<<(count)); - } - - vduint128& operator>>=(int count) { - return operator=(operator>>(count)); - } - -#ifdef _M_AMD64 - const vduint128 operator<<(int count) const { - vduint128 t; - - if (count >= 64) { - t.q[0] = 0; - t.q[1] = q[0] << (count-64); - } else { - t.q[0] = q[0] << count; - t.q[1] = __shiftleft128(q[0], q[1], count); - } - - return t; - } - - const vduint128 operator>>(int count) const { - vduint128 t; - - if (count >= 64) { - t.q[0] = q[1] >> (count-64); - t.q[1] = 0; - } else { - t.q[0] = __shiftright128(q[0], q[1], count); - t.q[1] = q[1] >> count; - } - - return t; - } -#else - const vduint128 operator<<(int v) const; - const vduint128 operator>>(int v) const; -#endif -}; - -inline vdint128::vdint128(const vduint128& x) { - q[0] = x.q[0]; - q[1] = x.q[1]; -} - -inline vduint128::vduint128(const vdint128& x) { - q[0] = x.q[0]; - q[1] = x.q[1]; -} - -#ifdef _M_AMD64 - inline vduint128 VDUMul64x64To128(uint64 x, uint64 y) { - vduint128 result; - result.q[0] = _umul128(x, y, &result.q[1]); - return result; - } - uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder); -#else - vduint128 VDUMul64x64To128(uint64 x, uint64 y); - uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder); -#endif - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_INT128_H +#define f_VD2_SYSTEM_INT128_H + +#include + +struct vdint128; +struct vduint128; + +#ifdef _M_AMD64 + extern "C" __int64 _mul128(__int64 x, __int64 y, __int64 *hiresult); + extern "C" unsigned __int64 _umul128(unsigned __int64 x, unsigned __int64 y, unsigned __int64 *hiresult); + extern "C" unsigned __int64 __shiftleft128(unsigned __int64 low, unsigned __int64 high, unsigned char shift); + extern "C" unsigned __int64 __shiftright128(unsigned __int64 low, unsigned __int64 high, unsigned char shift); + + #pragma intrinsic(_mul128) + #pragma intrinsic(_umul128) + #pragma intrinsic(__shiftleft128) + #pragma intrinsic(__shiftright128) + + extern "C" { + void vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + void vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + void vdasm_uint128_mul(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + } +#else + extern "C" { + void __cdecl vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + void __cdecl vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + } +#endif + +struct vdint128 { +public: + union { + sint32 d[4]; + sint64 q[2]; + }; + + vdint128() {} + + vdint128(sint64 x) { + q[0] = x; + q[1] = x>>63; + } + + vdint128(uint64 x) { + q[0] = (sint64)x; + q[1] = 0; + } + + vdint128(int x) { + q[0] = x; + q[1] = (sint64)x >> 63; + } + + vdint128(unsigned int x) { + q[0] = x; + q[1] = 0; + } + + vdint128(unsigned long x) { + q[0] = x; + q[1] = 0; + } + + vdint128(sint64 hi, uint64 lo) { + q[0] = lo; + q[1] = hi; + } + + explicit inline vdint128(const vduint128& x); + + sint64 getHi() const { return q[1]; } + uint64 getLo() const { return q[0]; } + + operator double() const; + operator sint64() const { + return (sint64)q[0]; + } + operator uint64() const { + return (uint64)q[0]; + } + + bool operator==(const vdint128& x) const { + return q[1] == x.q[1] && q[0] == x.q[0]; + } + + bool operator!=(const vdint128& x) const { + return q[1] != x.q[1] || q[0] != x.q[0]; + } + + bool operator<(const vdint128& x) const { + return q[1] < x.q[1] || (q[1] == x.q[1] && (uint64)q[0] < (uint64)x.q[0]); + } + + bool operator<=(const vdint128& x) const { + return q[1] < x.q[1] || (q[1] == x.q[1] && (uint64)q[0] <= (uint64)x.q[0]); + } + + bool operator>(const vdint128& x) const { + return q[1] > x.q[1] || (q[1] == x.q[1] && (uint64)q[0] > (uint64)x.q[0]); + } + + bool operator>=(const vdint128& x) const { + return q[1] > x.q[1] || (q[1] == x.q[1] && (uint64)q[0] >= (uint64)x.q[0]); + } + + const vdint128 operator+(const vdint128& x) const { + vdint128 t; + vdasm_uint128_add((uint64 *)t.q, (const uint64 *)q, (const uint64 *)x.q); + return t; + } + + const vdint128 operator-(const vdint128& x) const { + vdint128 t; + vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)q, (const uint64 *)x.q); + return t; + } + + const vdint128& operator+=(const vdint128& x) { + vdasm_uint128_add((uint64 *)q, (const uint64 *)q, (const uint64 *)x.q); + return *this; + } + + const vdint128& operator-=(const vdint128& x) { + vdasm_uint128_sub((uint64 *)q, (const uint64 *)q, (const uint64 *)x.q); + return *this; + } + + const vdint128 operator*(const vdint128& x) const; + + const vdint128 operator/(int x) const; + + const vdint128 operator-() const { + vdint128 t(0); + vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)t.q, (const uint64 *)q); + return t; + } + + const vdint128 abs() const { + return q[1] < 0 ? -*this : *this; + } + +#ifdef _M_AMD64 + void setSquare(sint64 v) { + const vdint128 v128(v); + operator=(v128*v128); + } + + const vdint128 operator<<(int count) const { + vdint128 t; + + if (count >= 64) { + t.q[0] = 0; + t.q[1] = q[0] << (count-64); + } else { + t.q[0] = q[0] << count; + t.q[1] = __shiftleft128(q[0], q[1], count); + } + + return t; + } + + const vdint128 operator>>(int count) const { + vdint128 t; + + if (count >= 64) { + t.q[0] = q[1] >> (count-64); + t.q[1] = q[1] >> 63; + } else { + t.q[0] = __shiftright128(q[0], q[1], count); + t.q[1] = q[1] >> count; + } + + return t; + } +#else + void setSquare(sint64 v); + + const vdint128 operator<<(int v) const; + const vdint128 operator>>(int v) const; +#endif +}; + +struct vduint128 { +public: + union { + uint32 d[4]; + uint64 q[2]; + }; + + vduint128() {} + + vduint128(sint64 x) { + q[0] = (sint64)x; + q[1] = 0; + } + + vduint128(uint64 x) { + q[0] = x; + q[1] = 0; + } + + vduint128(int x) { + q[0] = (uint64)x; + q[1] = 0; + } + + vduint128(unsigned x) { + q[0] = x; + q[1] = 0; + } + + vduint128(uint64 hi, uint64 lo) { + q[0] = lo; + q[1] = hi; + } + + explicit inline vduint128(const vdint128& x); + + uint64 getHi() const { return q[1]; } + uint64 getLo() const { return q[0]; } + + operator sint64() const { + return (sint64)q[0]; + } + + operator uint64() const { + return (uint64)q[0]; + } + + bool operator==(const vduint128& x) const { + return q[1] == x.q[1] && q[0] == x.q[0]; + } + + bool operator!=(const vduint128& x) const { + return q[1] != x.q[1] || q[0] != x.q[0]; + } + + bool operator<(const vduint128& x) const { + return q[1] < x.q[1] || (q[1] == x.q[1] && q[0] < x.q[0]); + } + + bool operator<=(const vduint128& x) const { + return q[1] < x.q[1] || (q[1] == x.q[1] && q[0] <= x.q[0]); + } + + bool operator>(const vduint128& x) const { + return q[1] > x.q[1] || (q[1] == x.q[1] && q[0] > x.q[0]); + } + + bool operator>=(const vduint128& x) const { + return q[1] > x.q[1] || (q[1] == x.q[1] && q[0] >= x.q[0]); + } + + const vduint128 operator+(const vduint128& x) const { + vduint128 t; + vdasm_uint128_add(t.q, q, x.q); + return t; + } + + const vduint128 operator-(const vduint128& x) const { + vduint128 t; + vdasm_uint128_sub(t.q, q, x.q); + return t; + } + + const vduint128& operator+=(const vduint128& x) { + vdasm_uint128_add(q, q, x.q); + return *this; + } + + const vduint128& operator-=(const vduint128& x) { + vdasm_uint128_sub(q, q, x.q); + return *this; + } + + const vduint128 operator*(const vduint128& x) const; + + const vduint128 operator-() const { + vduint128 t(0U); + vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)t.q, (const uint64 *)q); + return t; + } + + vduint128& operator<<=(int count) { + return operator=(operator<<(count)); + } + + vduint128& operator>>=(int count) { + return operator=(operator>>(count)); + } + +#ifdef _M_AMD64 + const vduint128 operator<<(int count) const { + vduint128 t; + + if (count >= 64) { + t.q[0] = 0; + t.q[1] = q[0] << (count-64); + } else { + t.q[0] = q[0] << count; + t.q[1] = __shiftleft128(q[0], q[1], count); + } + + return t; + } + + const vduint128 operator>>(int count) const { + vduint128 t; + + if (count >= 64) { + t.q[0] = q[1] >> (count-64); + t.q[1] = 0; + } else { + t.q[0] = __shiftright128(q[0], q[1], count); + t.q[1] = q[1] >> count; + } + + return t; + } +#else + const vduint128 operator<<(int v) const; + const vduint128 operator>>(int v) const; +#endif +}; + +inline vdint128::vdint128(const vduint128& x) { + q[0] = x.q[0]; + q[1] = x.q[1]; +} + +inline vduint128::vduint128(const vdint128& x) { + q[0] = x.q[0]; + q[1] = x.q[1]; +} + +#ifdef _M_AMD64 + inline vduint128 VDUMul64x64To128(uint64 x, uint64 y) { + vduint128 result; + result.q[0] = _umul128(x, y, &result.q[1]); + return result; + } + uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder); +#else + vduint128 VDUMul64x64To128(uint64 x, uint64 y); + uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder); +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/linearalloc.h b/src/thirdparty/VirtualDub/h/vd2/system/linearalloc.h index 08a35dc3abf..9a9ef4cba6d 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/linearalloc.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/linearalloc.h @@ -1,88 +1,88 @@ -#ifndef f_VD2_SYSTEM_LINEARALLOC_H -#define f_VD2_SYSTEM_LINEARALLOC_H - -#include - -class VDLinearAllocator { -public: - explicit VDLinearAllocator(uint32 blockSize = 4096); - ~VDLinearAllocator(); - - void Clear(); - - void *Allocate(size_t bytes) { - void *p = mpAllocPtr; - - bytes = (bytes + sizeof(void *) - 1) & ((size_t)0 - (size_t)sizeof(void *)); - - if (mAllocLeft < bytes) - p = AllocateSlow(bytes); - else { - mAllocLeft -= bytes; - mpAllocPtr += bytes; - } - - return p; - } - - template - T *Allocate() { - return new(Allocate(sizeof(T))) T; - } - - template - T *Allocate(const A1& a1) { - return new(Allocate(sizeof(T))) T(a1); - } - - template - T *Allocate(const A1& a1, const A2& a2) { - return new(Allocate(sizeof(T))) T(a1, a2); - } - - template - T *Allocate(const A1& a1, const A2& a2, const A3& a3) { - return new(Allocate(sizeof(T))) T(a1, a2, a3); - } - -protected: - void *AllocateSlow(size_t bytes); - - union Block { - Block *mpNext; - double mAlign; - }; - - Block *mpBlocks; - char *mpAllocPtr; - size_t mAllocLeft; - size_t mBlockSize; -}; - -class VDFixedLinearAllocator { -public: - VDFixedLinearAllocator(void *mem, size_t size) - : mpAllocPtr((char *)mem) - , mAllocLeft(size) - { - } - - void *Allocate(size_t bytes) { - void *p = mpAllocPtr; - - if (mAllocLeft < bytes) - ThrowException(); - - mAllocLeft -= bytes; - mpAllocPtr += bytes; - return p; - } - -protected: - void ThrowException(); - - char *mpAllocPtr; - size_t mAllocLeft; -}; - -#endif +#ifndef f_VD2_SYSTEM_LINEARALLOC_H +#define f_VD2_SYSTEM_LINEARALLOC_H + +#include + +class VDLinearAllocator { +public: + explicit VDLinearAllocator(uint32 blockSize = 4096); + ~VDLinearAllocator(); + + void Clear(); + + void *Allocate(size_t bytes) { + void *p = mpAllocPtr; + + bytes = (bytes + sizeof(void *) - 1) & ((size_t)0 - (size_t)sizeof(void *)); + + if (mAllocLeft < bytes) + p = AllocateSlow(bytes); + else { + mAllocLeft -= bytes; + mpAllocPtr += bytes; + } + + return p; + } + + template + T *Allocate() { + return new(Allocate(sizeof(T))) T; + } + + template + T *Allocate(const A1& a1) { + return new(Allocate(sizeof(T))) T(a1); + } + + template + T *Allocate(const A1& a1, const A2& a2) { + return new(Allocate(sizeof(T))) T(a1, a2); + } + + template + T *Allocate(const A1& a1, const A2& a2, const A3& a3) { + return new(Allocate(sizeof(T))) T(a1, a2, a3); + } + +protected: + void *AllocateSlow(size_t bytes); + + union Block { + Block *mpNext; + double mAlign; + }; + + Block *mpBlocks; + char *mpAllocPtr; + size_t mAllocLeft; + size_t mBlockSize; +}; + +class VDFixedLinearAllocator { +public: + VDFixedLinearAllocator(void *mem, size_t size) + : mpAllocPtr((char *)mem) + , mAllocLeft(size) + { + } + + void *Allocate(size_t bytes) { + void *p = mpAllocPtr; + + if (mAllocLeft < bytes) + ThrowException(); + + mAllocLeft -= bytes; + mpAllocPtr += bytes; + return p; + } + +protected: + void ThrowException(); + + char *mpAllocPtr; + size_t mAllocLeft; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/list.h b/src/thirdparty/VirtualDub/h/vd2/system/list.h index 103c9a49eef..42a81ae8e12 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/list.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/list.h @@ -1,275 +1,275 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_LIST_H -#define f_LIST_H - -class ListNode { -public: - ListNode *next, *prev; - - void Remove() { - next->prev = prev; - prev->next = next; -#ifdef _DEBUG - prev = next = 0; -#endif - } - - void InsertAfter(ListNode *node) { - next = node; - prev = node->prev; - if (node->prev) node->prev->next = this; - node->prev = this; - } - - void InsertBefore(ListNode *node) { - next = node->next; - prev = node; - if (node->next) node->next->prev = this; - node->next = this; - } - - ListNode *NextFromHead() const { - return prev; - } - - ListNode *NextFromTail() const { - return next; - } -}; - -class List { -private: -public: - ListNode head, tail; - - // <--- next prev ---> - // - // head <-> node <-> node <-> tail - - List(); - List(int) {} - - void Init(); - - void AddHead(ListNode *node) { - node->InsertAfter(&head); - } - - void AddTail(ListNode *node) { - node->InsertBefore(&tail); - } - - ListNode *RemoveHead(); - ListNode *RemoveTail(); - - bool IsEmpty() const { - return !head.prev->prev; - } - - ListNode *AtHead() const { - return head.prev; - } - - ListNode *AtTail() const { - return tail.next; - } - - void Take(List& from); - void Swap(List& with); -}; - -// Templated classes... templated classes good. - -template class List2; - -template -class ListNode2 : public ListNode { -friend class List2; -public: - void InsertBefore(ListNode2 *node) { ListNode::InsertBefore(node); } - void InsertAfter(ListNode2 *node) { ListNode::InsertAfter(node); } - - void Remove() { ListNode::Remove(); } - T *NextFromHead() const { return static_cast(static_cast*>(ListNode::NextFromHead())); } - T *NextFromTail() const { return static_cast(static_cast*>(ListNode::NextFromTail())); } -}; - -template -class List2 : public List { -public: - List2() {} - - // This is a really lame, stupid way to postpone initialization of the - // list. - - List2(int v) : List(v) {} - - void AddHead(ListNode2 *node) { List::AddHead(node); } - void AddTail(ListNode2 *node) { List::AddTail(node); } - T *RemoveHead() { return static_cast(static_cast*>(List::RemoveHead())); } - T *RemoveTail() { return static_cast(static_cast*>(List::RemoveTail())); } - T *AtHead() const { return static_cast(static_cast*>(List::AtHead())); } - T *AtTail() const { return static_cast(static_cast*>(List::AtTail())); } - - // I must admit to being pampered by STL (end is different though!!) - - T *begin() const { return AtHead(); } - T *end() const { return AtTail(); } - - void take(List2& from) { List::Take(from); } - - class iterator { - protected: - ListNode2 *node; - ListNode2 *next; - - public: - iterator() {} - iterator(const iterator& src) throw() : node(src.node), next(src.next) {} - - bool operator!() const throw() { return 0 == next; } - T *operator->() const throw() { return (T *)node; } - operator bool() const throw() { return 0 != next; } - operator T *() const throw() { return (T *)node; } - T& operator *() const throw() { return *(T *)node; } - }; - - // fwit: forward iterator (SAFE if node disappears) - // rvit: reverse iterator (SAFE if node disappears) - - class fwit : public iterator { - public: - fwit() throw() {} - fwit(const fwit& src) throw() : iterator(src) {} - fwit(ListNode2 *start) throw() { - this->node = start; - this->next = start->NextFromHead(); - } - - const fwit& operator=(ListNode2 *start) throw() { - this->node = start; - this->next = start->NextFromHead(); - - return *this; - } - - fwit& operator++() throw() { - this->node = this->next; - this->next = this->node->NextFromHead(); - - return *this; - } - - const fwit& operator+=(int v) throw() { - while(this->next && v--) { - this->node = this->next; - this->next = this->node->NextFromHead(); - } - - return *this; - } - - fwit operator+(int v) const throw() { - fwit t(*this); - - t += v; - - return t; - } - - // This one's for my sanity. - - void operator++(int) throw() { - ++*this; - } - }; - - class rvit : public iterator { - public: - rvit() throw() {} - - rvit(ListNode2 *start) throw() { - this->node = start; - this->next = start->NextFromTail(); - } - - const rvit& operator=(ListNode2 *start) throw() { - this->node = start; - this->next = start->NextFromTail(); - - return *this; - } - - rvit& operator--() throw() { - this->node = this->next; - this->next = this->node->NextFromTail(); - - return *this; - } - - const rvit& operator-=(int v) throw() { - while(this->next && v--) { - this->node = this->next; - this->next = this->node->NextFromTail(); - } - - return *this; - } - - rvit operator-(int v) const throw() { - rvit t(*this); - - t -= v; - - return t; - } - - // This one's for my sanity. - - void operator--(int) throw() { - --*this; - } - }; -}; - -template -class ListAlloc : public List2 { -public: - ListAlloc() {} - ~ListAlloc() { - dispose(); - } - - void dispose() { - T *node; - - while(node = this->RemoveHead()) - delete node; - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_LIST_H +#define f_LIST_H + +class ListNode { +public: + ListNode *next, *prev; + + void Remove() { + next->prev = prev; + prev->next = next; +#ifdef _DEBUG + prev = next = 0; +#endif + } + + void InsertAfter(ListNode *node) { + next = node; + prev = node->prev; + if (node->prev) node->prev->next = this; + node->prev = this; + } + + void InsertBefore(ListNode *node) { + next = node->next; + prev = node; + if (node->next) node->next->prev = this; + node->next = this; + } + + ListNode *NextFromHead() const { + return prev; + } + + ListNode *NextFromTail() const { + return next; + } +}; + +class List { +private: +public: + ListNode head, tail; + + // <--- next prev ---> + // + // head <-> node <-> node <-> tail + + List(); + List(int) {} + + void Init(); + + void AddHead(ListNode *node) { + node->InsertAfter(&head); + } + + void AddTail(ListNode *node) { + node->InsertBefore(&tail); + } + + ListNode *RemoveHead(); + ListNode *RemoveTail(); + + bool IsEmpty() const { + return !head.prev->prev; + } + + ListNode *AtHead() const { + return head.prev; + } + + ListNode *AtTail() const { + return tail.next; + } + + void Take(List& from); + void Swap(List& with); +}; + +// Templated classes... templated classes good. + +template class List2; + +template +class ListNode2 : public ListNode { +friend class List2; +public: + void InsertBefore(ListNode2 *node) { ListNode::InsertBefore(node); } + void InsertAfter(ListNode2 *node) { ListNode::InsertAfter(node); } + + void Remove() { ListNode::Remove(); } + T *NextFromHead() const { return static_cast(static_cast*>(ListNode::NextFromHead())); } + T *NextFromTail() const { return static_cast(static_cast*>(ListNode::NextFromTail())); } +}; + +template +class List2 : public List { +public: + List2() {} + + // This is a really lame, stupid way to postpone initialization of the + // list. + + List2(int v) : List(v) {} + + void AddHead(ListNode2 *node) { List::AddHead(node); } + void AddTail(ListNode2 *node) { List::AddTail(node); } + T *RemoveHead() { return static_cast(static_cast*>(List::RemoveHead())); } + T *RemoveTail() { return static_cast(static_cast*>(List::RemoveTail())); } + T *AtHead() const { return static_cast(static_cast*>(List::AtHead())); } + T *AtTail() const { return static_cast(static_cast*>(List::AtTail())); } + + // I must admit to being pampered by STL (end is different though!!) + + T *begin() const { return AtHead(); } + T *end() const { return AtTail(); } + + void take(List2& from) { List::Take(from); } + + class iterator { + protected: + ListNode2 *node; + ListNode2 *next; + + public: + iterator() {} + iterator(const iterator& src) throw() : node(src.node), next(src.next) {} + + bool operator!() const throw() { return 0 == next; } + T *operator->() const throw() { return (T *)node; } + operator bool() const throw() { return 0 != next; } + operator T *() const throw() { return (T *)node; } + T& operator *() const throw() { return *(T *)node; } + }; + + // fwit: forward iterator (SAFE if node disappears) + // rvit: reverse iterator (SAFE if node disappears) + + class fwit : public iterator { + public: + fwit() throw() {} + fwit(const fwit& src) throw() : iterator(src) {} + fwit(ListNode2 *start) throw() { + this->node = start; + this->next = start->NextFromHead(); + } + + const fwit& operator=(ListNode2 *start) throw() { + this->node = start; + this->next = start->NextFromHead(); + + return *this; + } + + fwit& operator++() throw() { + this->node = this->next; + this->next = this->node->NextFromHead(); + + return *this; + } + + const fwit& operator+=(int v) throw() { + while(this->next && v--) { + this->node = this->next; + this->next = this->node->NextFromHead(); + } + + return *this; + } + + fwit operator+(int v) const throw() { + fwit t(*this); + + t += v; + + return t; + } + + // This one's for my sanity. + + void operator++(int) throw() { + ++*this; + } + }; + + class rvit : public iterator { + public: + rvit() throw() {} + + rvit(ListNode2 *start) throw() { + this->node = start; + this->next = start->NextFromTail(); + } + + const rvit& operator=(ListNode2 *start) throw() { + this->node = start; + this->next = start->NextFromTail(); + + return *this; + } + + rvit& operator--() throw() { + this->node = this->next; + this->next = this->node->NextFromTail(); + + return *this; + } + + const rvit& operator-=(int v) throw() { + while(this->next && v--) { + this->node = this->next; + this->next = this->node->NextFromTail(); + } + + return *this; + } + + rvit operator-(int v) const throw() { + rvit t(*this); + + t -= v; + + return t; + } + + // This one's for my sanity. + + void operator--(int) throw() { + --*this; + } + }; +}; + +template +class ListAlloc : public List2 { +public: + ListAlloc() {} + ~ListAlloc() { + dispose(); + } + + void dispose() { + T *node; + + while(node = this->RemoveHead()) + delete node; + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/math.h b/src/thirdparty/VirtualDub/h/vd2/system/math.h index 221035bb8e0..d251de61ddd 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/math.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/math.h @@ -1,269 +1,269 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_MATH_H -#define f_VD2_SYSTEM_MATH_H - -#include -#include - -// Constants -namespace nsVDMath { - static const float kfPi = 3.1415926535897932384626433832795f; - static const double krPi = 3.1415926535897932384626433832795; - static const float kfTwoPi = 6.283185307179586476925286766559f; - static const double krTwoPi = 6.283185307179586476925286766559; - static const float kfLn2 = 0.69314718055994530941723212145818f; - static const double krLn2 = 0.69314718055994530941723212145818; - static const float kfLn10 = 2.3025850929940456840179914546844f; - static const double krLn10 = 2.3025850929940456840179914546844; - static const float kfOneOverLn10 = 0.43429448190325182765112891891661f; - static const double krOneOverLn10 = 0.43429448190325182765112891891661; -}; - -/////////////////////////////////////////////////////////////////////////// -// Integer clamping functions -// -#ifdef _M_IX86 - inline uint32 VDClampToUint32(uint64 v) { - return v >= 0x100000000UL ? 0xFFFFFFFFUL : (uint32)v; - } - - inline uint32 VDClampToUint32(sint64 v) { - union U { - __int64 v64; - struct { - unsigned lo; - int hi; - } v32; - }; - - return ((U *)&v)->v32.hi ? ~(((U *)&v)->v32.hi >> 31) : ((U *)&v)->v32.lo; - } - - inline uint32 VDClampToUint32(sint32 v) { - return v < 0 ? 0 : (uint32)v; - } -#else - inline uint32 VDClampToUint32(sint64 v) { - uint32 r = (uint32)v; - return r == v ? r : (uint32)~(sint32)(v>>63); - } -#endif - -inline sint32 VDClampToSint32(uint32 v) { - return (v | ((sint32)v >> 31)) & 0x7FFFFFFF; -} - -inline sint32 VDClampToSint32(sint64 v) { - sint32 r = (sint32)v; - return r == v ? r : (sint32)(v >> 63) ^ 0x7FFFFFFF; -} - -inline uint16 VDClampToUint16(uint32 v) { - if (v > 0xffff) - v = 0xffff; - return (uint16)v; -} - -/////////////////////////////////////////////////////////////////////////// -// Absolute value functions -inline sint64 VDAbs64(sint64 v) { - return v<0 ? -v : v; -} - -inline ptrdiff_t VDAbsPtrdiff(ptrdiff_t v) { - return v<0 ? -v : v; -} - -// Rounding functions -// -// Round a double to an int or a long. Behavior is not specified at -// int(y)+0.5, if x is NaN or Inf, or if x is out of range. - -int VDRoundToInt(double x); -long VDRoundToLong(double x); -sint32 VDRoundToInt32(double x); -sint64 VDRoundToInt64(double x); - -inline sint32 VDRoundToIntFast(float x) { - union { - float f; - sint32 i; - } u = {x + 12582912.0f}; // 2^22+2^23 - - return (sint32)u.i - 0x4B400000; -} - -inline sint32 VDRoundToIntFastFullRange(double x) { - union { - double f; - sint32 i[2]; - } u = {x + 6755399441055744.0f}; // 2^51+2^52 - - return (sint32)u.i[0]; -} - -#if !defined(VD_CPU_X86) || !defined(VD_COMPILER_MSVC) - inline sint32 VDFloorToInt(double x) { - return (sint32)floor(x); - } - - inline sint64 VDFloorToInt64(double x) { - return (sint64)floor(x); - } -#else - #pragma warning(push) - #pragma warning(disable: 4035) // warning C4035: 'VDFloorToInt' : no return value - inline sint32 VDFloorToInt(double x) { - sint32 temp; - - __asm { - fld x - fist temp - fild temp - mov eax, temp - fsub - fstp temp - cmp temp, 80000001h - adc eax, -1 - } - } - inline sint64 VDFloorToInt64(double x) { - sint64 temp; - sint32 temp2; - - __asm { - fld x - fld st(0) - fistp qword ptr temp - fild qword ptr temp - mov eax, dword ptr temp - mov edx, dword ptr temp+4 - fsub - fstp dword ptr temp2 - cmp dword ptr temp2, 80000001h - adc eax, -1 - adc edx, -1 - } - } - #pragma warning(pop) -#endif - -#if !defined(VD_CPU_X86) || !defined(VD_COMPILER_MSVC) - inline sint32 VDCeilToInt(double x) { - return (sint32)ceil(x); - } - - inline sint64 VDCeilToInt64(double x) { - return (sint64)ceil(x); - } -#else - #pragma warning(push) - #pragma warning(disable: 4035) // warning C4035: 'VDCeilToInt' : no return value - inline sint32 VDCeilToInt(double x) { - sint32 temp; - - __asm { - fld x - fist temp - fild temp - mov eax, temp - fsubr - fstp temp - cmp temp, 80000001h - sbb eax, -1 - } - } - - inline sint32 VDCeilToInt64(double x) { - sint64 temp; - sint32 temp2; - - __asm { - fld x - fld st(0) - fistp temp - fild temp - mov eax, dword ptr temp - mov edx, dword ptr temp+4 - fsubr - fstp temp2 - cmp temp2, 80000001h - sbb eax, -1 - sbb edx, -1 - } - } - #pragma warning(pop) -#endif - -/////////////////////////////////////////////////////////////////////////// -/// Convert a value from [-~1..1] to [-32768, 32767] with clamping. -inline sint16 VDClampedRoundFixedToInt16Fast(float x) { - union { - float f; - sint32 i; - } u = {x * 65535.0f + 12582912.0f}; // 2^22+2^23 - - sint32 v = (sint32)u.i - 0x4B3F8000; - - if ((uint32)v >= 0x10000) - v = ~v >> 31; - - return (sint16)(v - 0x8000); -} - -/// Convert a value from [0..1] to [0..255] with clamping. -inline uint8 VDClampedRoundFixedToUint8Fast(float x) { - union { - float f; - sint32 i; - } u = {x * 255.0f + 12582912.0f}; // 2^22+2^23 - - sint32 v = (sint32)u.i - 0x4B400000; - - if ((uint32)v >= 0x100) - v = ~v >> 31; - - return (uint8)v; -} - -/////////////////////////////////////////////////////////////////////////// - -#ifdef _M_IX86 - sint64 __stdcall VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder); - uint64 __stdcall VDUMulDiv64x32(uint64 a, uint32 b, uint32 c); -#else - extern "C" sint64 VDFractionScale64(uint64 a, uint64 b, uint64 c, uint32& remainder); - extern "C" uint64 VDUMulDiv64x32(uint64 a, uint32 b, uint32 c); -#endif - -sint64 VDMulDiv64(sint64 a, sint64 b, sint64 c); - -/////////////////////////////////////////////////////////////////////////// - -bool VDVerifyFiniteFloats(const float *p, uint32 n); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_MATH_H +#define f_VD2_SYSTEM_MATH_H + +#include +#include + +// Constants +namespace nsVDMath { + static const float kfPi = 3.1415926535897932384626433832795f; + static const double krPi = 3.1415926535897932384626433832795; + static const float kfTwoPi = 6.283185307179586476925286766559f; + static const double krTwoPi = 6.283185307179586476925286766559; + static const float kfLn2 = 0.69314718055994530941723212145818f; + static const double krLn2 = 0.69314718055994530941723212145818; + static const float kfLn10 = 2.3025850929940456840179914546844f; + static const double krLn10 = 2.3025850929940456840179914546844; + static const float kfOneOverLn10 = 0.43429448190325182765112891891661f; + static const double krOneOverLn10 = 0.43429448190325182765112891891661; +}; + +/////////////////////////////////////////////////////////////////////////// +// Integer clamping functions +// +#ifdef _M_IX86 + inline uint32 VDClampToUint32(uint64 v) { + return v >= 0x100000000UL ? 0xFFFFFFFFUL : (uint32)v; + } + + inline uint32 VDClampToUint32(sint64 v) { + union U { + __int64 v64; + struct { + unsigned lo; + int hi; + } v32; + }; + + return ((U *)&v)->v32.hi ? ~(((U *)&v)->v32.hi >> 31) : ((U *)&v)->v32.lo; + } + + inline uint32 VDClampToUint32(sint32 v) { + return v < 0 ? 0 : (uint32)v; + } +#else + inline uint32 VDClampToUint32(sint64 v) { + uint32 r = (uint32)v; + return r == v ? r : (uint32)~(sint32)(v>>63); + } +#endif + +inline sint32 VDClampToSint32(uint32 v) { + return (v | ((sint32)v >> 31)) & 0x7FFFFFFF; +} + +inline sint32 VDClampToSint32(sint64 v) { + sint32 r = (sint32)v; + return r == v ? r : (sint32)(v >> 63) ^ 0x7FFFFFFF; +} + +inline uint16 VDClampToUint16(uint32 v) { + if (v > 0xffff) + v = 0xffff; + return (uint16)v; +} + +/////////////////////////////////////////////////////////////////////////// +// Absolute value functions +inline sint64 VDAbs64(sint64 v) { + return v<0 ? -v : v; +} + +inline ptrdiff_t VDAbsPtrdiff(ptrdiff_t v) { + return v<0 ? -v : v; +} + +// Rounding functions +// +// Round a double to an int or a long. Behavior is not specified at +// int(y)+0.5, if x is NaN or Inf, or if x is out of range. + +int VDRoundToInt(double x); +long VDRoundToLong(double x); +sint32 VDRoundToInt32(double x); +sint64 VDRoundToInt64(double x); + +inline sint32 VDRoundToIntFast(float x) { + union { + float f; + sint32 i; + } u = {x + 12582912.0f}; // 2^22+2^23 + + return (sint32)u.i - 0x4B400000; +} + +inline sint32 VDRoundToIntFastFullRange(double x) { + union { + double f; + sint32 i[2]; + } u = {x + 6755399441055744.0f}; // 2^51+2^52 + + return (sint32)u.i[0]; +} + +#if !defined(VD_CPU_X86) || !defined(VD_COMPILER_MSVC) + inline sint32 VDFloorToInt(double x) { + return (sint32)floor(x); + } + + inline sint64 VDFloorToInt64(double x) { + return (sint64)floor(x); + } +#else + #pragma warning(push) + #pragma warning(disable: 4035) // warning C4035: 'VDFloorToInt' : no return value + inline sint32 VDFloorToInt(double x) { + sint32 temp; + + __asm { + fld x + fist temp + fild temp + mov eax, temp + fsub + fstp temp + cmp temp, 80000001h + adc eax, -1 + } + } + inline sint64 VDFloorToInt64(double x) { + sint64 temp; + sint32 temp2; + + __asm { + fld x + fld st(0) + fistp qword ptr temp + fild qword ptr temp + mov eax, dword ptr temp + mov edx, dword ptr temp+4 + fsub + fstp dword ptr temp2 + cmp dword ptr temp2, 80000001h + adc eax, -1 + adc edx, -1 + } + } + #pragma warning(pop) +#endif + +#if !defined(VD_CPU_X86) || !defined(VD_COMPILER_MSVC) + inline sint32 VDCeilToInt(double x) { + return (sint32)ceil(x); + } + + inline sint64 VDCeilToInt64(double x) { + return (sint64)ceil(x); + } +#else + #pragma warning(push) + #pragma warning(disable: 4035) // warning C4035: 'VDCeilToInt' : no return value + inline sint32 VDCeilToInt(double x) { + sint32 temp; + + __asm { + fld x + fist temp + fild temp + mov eax, temp + fsubr + fstp temp + cmp temp, 80000001h + sbb eax, -1 + } + } + + inline sint32 VDCeilToInt64(double x) { + sint64 temp; + sint32 temp2; + + __asm { + fld x + fld st(0) + fistp temp + fild temp + mov eax, dword ptr temp + mov edx, dword ptr temp+4 + fsubr + fstp temp2 + cmp temp2, 80000001h + sbb eax, -1 + sbb edx, -1 + } + } + #pragma warning(pop) +#endif + +/////////////////////////////////////////////////////////////////////////// +/// Convert a value from [-~1..1] to [-32768, 32767] with clamping. +inline sint16 VDClampedRoundFixedToInt16Fast(float x) { + union { + float f; + sint32 i; + } u = {x * 65535.0f + 12582912.0f}; // 2^22+2^23 + + sint32 v = (sint32)u.i - 0x4B3F8000; + + if ((uint32)v >= 0x10000) + v = ~v >> 31; + + return (sint16)(v - 0x8000); +} + +/// Convert a value from [0..1] to [0..255] with clamping. +inline uint8 VDClampedRoundFixedToUint8Fast(float x) { + union { + float f; + sint32 i; + } u = {x * 255.0f + 12582912.0f}; // 2^22+2^23 + + sint32 v = (sint32)u.i - 0x4B400000; + + if ((uint32)v >= 0x100) + v = ~v >> 31; + + return (uint8)v; +} + +/////////////////////////////////////////////////////////////////////////// + +#ifdef _M_IX86 + sint64 __stdcall VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder); + uint64 __stdcall VDUMulDiv64x32(uint64 a, uint32 b, uint32 c); +#else + extern "C" sint64 VDFractionScale64(uint64 a, uint64 b, uint64 c, uint32& remainder); + extern "C" uint64 VDUMulDiv64x32(uint64 a, uint32 b, uint32 c); +#endif + +sint64 VDMulDiv64(sint64 a, sint64 b, sint64 c); + +/////////////////////////////////////////////////////////////////////////// + +bool VDVerifyFiniteFloats(const float *p, uint32 n); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/memory.h b/src/thirdparty/VirtualDub/h/vd2/system/memory.h index 52dbb432703..3a7a63f4771 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/memory.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/memory.h @@ -1,84 +1,84 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_MEMORY_H -#define f_VD2_SYSTEM_MEMORY_H - -#include - -void *VDAlignedMalloc(size_t n, unsigned alignment); -void VDAlignedFree(void *p); - -template -struct VDAlignedObject { - inline void *operator new(size_t n) { return VDAlignedMalloc(n, alignment); } - inline void operator delete(void *p) { VDAlignedFree(p); } -}; - -void *VDAlignedVirtualAlloc(size_t n); -void VDAlignedVirtualFree(void *p); - -extern void (__cdecl *VDSwapMemory)(void *p0, void *p1, size_t bytes); - -void VDInvertMemory(void *p, unsigned bytes); - -bool VDIsValidReadRegion(const void *p, size_t bytes); -bool VDIsValidWriteRegion(void *p, size_t bytes); - -bool VDCompareRect(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, size_t w, size_t h); - -const void *VDMemCheck8(const void *src, uint8 value, size_t count); - -void VDMemset8(void *dst, uint8 value, size_t count); -void VDMemset16(void *dst, uint16 value, size_t count); -void VDMemset24(void *dst, uint32 value, size_t count); -void VDMemset32(void *dst, uint32 value, size_t count); -void VDMemset64(void *dst, uint64 value, size_t count); -void VDMemset128(void *dst, const void *value, size_t count); -void VDMemsetPointer(void *dst, const void *value, size_t count); - -void VDMemset8Rect(void *dst, ptrdiff_t pitch, uint8 value, size_t w, size_t h); -void VDMemset16Rect(void *dst, ptrdiff_t pitch, uint16 value, size_t w, size_t h); -void VDMemset24Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h); -void VDMemset32Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h); - -#if defined(_WIN32) && defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - extern void (__cdecl *VDFastMemcpyPartial)(void *dst, const void *src, size_t bytes); - extern void (__cdecl *VDFastMemcpyFinish)(); - void VDFastMemcpyAutodetect(); -#else - void VDFastMemcpyPartial(void *dst, const void *src, size_t bytes); - void VDFastMemcpyFinish(); - void VDFastMemcpyAutodetect(); -#endif - - -void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h); - -/// Copy a region of memory with an access violation guard; used in cases where a sporadic -/// AV is unavoidable (dynamic Direct3D VB under XP). The regions must not overlap. -bool VDMemcpyGuarded(void *dst, const void *src, size_t bytes); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_MEMORY_H +#define f_VD2_SYSTEM_MEMORY_H + +#include + +void *VDAlignedMalloc(size_t n, unsigned alignment); +void VDAlignedFree(void *p); + +template +struct VDAlignedObject { + inline void *operator new(size_t n) { return VDAlignedMalloc(n, alignment); } + inline void operator delete(void *p) { VDAlignedFree(p); } +}; + +void *VDAlignedVirtualAlloc(size_t n); +void VDAlignedVirtualFree(void *p); + +extern void (__cdecl *VDSwapMemory)(void *p0, void *p1, size_t bytes); + +void VDInvertMemory(void *p, unsigned bytes); + +bool VDIsValidReadRegion(const void *p, size_t bytes); +bool VDIsValidWriteRegion(void *p, size_t bytes); + +bool VDCompareRect(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, size_t w, size_t h); + +const void *VDMemCheck8(const void *src, uint8 value, size_t count); + +void VDMemset8(void *dst, uint8 value, size_t count); +void VDMemset16(void *dst, uint16 value, size_t count); +void VDMemset24(void *dst, uint32 value, size_t count); +void VDMemset32(void *dst, uint32 value, size_t count); +void VDMemset64(void *dst, uint64 value, size_t count); +void VDMemset128(void *dst, const void *value, size_t count); +void VDMemsetPointer(void *dst, const void *value, size_t count); + +void VDMemset8Rect(void *dst, ptrdiff_t pitch, uint8 value, size_t w, size_t h); +void VDMemset16Rect(void *dst, ptrdiff_t pitch, uint16 value, size_t w, size_t h); +void VDMemset24Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h); +void VDMemset32Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h); + +#if defined(_WIN32) && defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + extern void (__cdecl *VDFastMemcpyPartial)(void *dst, const void *src, size_t bytes); + extern void (__cdecl *VDFastMemcpyFinish)(); + void VDFastMemcpyAutodetect(); +#else + void VDFastMemcpyPartial(void *dst, const void *src, size_t bytes); + void VDFastMemcpyFinish(); + void VDFastMemcpyAutodetect(); +#endif + + +void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h); + +/// Copy a region of memory with an access violation guard; used in cases where a sporadic +/// AV is unavoidable (dynamic Direct3D VB under XP). The regions must not overlap. +bool VDMemcpyGuarded(void *dst, const void *src, size_t bytes); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/progress.h b/src/thirdparty/VirtualDub/h/vd2/system/progress.h index 976e3c6e382..82368e5e129 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/progress.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/progress.h @@ -1,96 +1,96 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_SYSTEM_PROGRESS_H -#define f_SYSTEM_PROGRESS_H - -#include - -class VDAtomicInt; -class VDSignalPersistent; - -class IProgress { -public: - virtual void Error(const char *)=0; - virtual void Warning(const char *)=0; - virtual bool Query(const char *query, bool fDefault)=0; - virtual void ProgressStart(const char *text, const char *caption, const char *progtext, long lMax)=0; - virtual void ProgressAdvance(long)=0; - virtual void ProgressEnd()=0; - virtual void Output(const char *text)=0; - virtual VDAtomicInt *ProgressGetAbortFlag()=0; - virtual VDSignalPersistent *ProgressGetAbortSignal()=0; -}; - - -void ProgressSetHandler(IProgress *pp); -IProgress *ProgressGetHandler(); - -bool ProgressCheckAbort(); -void ProgressSetAbort(bool bNewValue); -VDSignalPersistent *ProgressGetAbortSignal(); -void ProgressError(const class MyError&); -void ProgressWarning(const char *format, ...); -void ProgressOutput(const char *format, ...); -bool ProgressQuery(bool fDefault, const char *format, ...); -void ProgressStart(long lMax, const char *caption, const char *progresstext, const char *format, ...); -void ProgressAdvance(long lNewValue); -void ProgressEnd(); - - -class VDProgress { -public: - VDProgress(long lMax, const char *caption, const char *progresstext, const char *format, ...) { - ProgressStart(lMax, caption, progresstext, format); - } - - ~VDProgress() { - ProgressEnd(); - } - - void advance(long v) { - ProgressAdvance(v); - } -}; - -class VDProgressAbortable { -public: - VDProgressAbortable(long lMax, const char *caption, const char *progresstext, const char *format, ...) { - ProgressStart(lMax, caption, progresstext, format); - ProgressSetAbort(false); - } - - ~VDProgressAbortable() { - ProgressEnd(); - } - - void advance(long v) { - if (ProgressCheckAbort()) - throw MyUserAbortError(); - ProgressAdvance(v); - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_SYSTEM_PROGRESS_H +#define f_SYSTEM_PROGRESS_H + +#include + +class VDAtomicInt; +class VDSignalPersistent; + +class IProgress { +public: + virtual void Error(const char *)=0; + virtual void Warning(const char *)=0; + virtual bool Query(const char *query, bool fDefault)=0; + virtual void ProgressStart(const char *text, const char *caption, const char *progtext, long lMax)=0; + virtual void ProgressAdvance(long)=0; + virtual void ProgressEnd()=0; + virtual void Output(const char *text)=0; + virtual VDAtomicInt *ProgressGetAbortFlag()=0; + virtual VDSignalPersistent *ProgressGetAbortSignal()=0; +}; + + +void ProgressSetHandler(IProgress *pp); +IProgress *ProgressGetHandler(); + +bool ProgressCheckAbort(); +void ProgressSetAbort(bool bNewValue); +VDSignalPersistent *ProgressGetAbortSignal(); +void ProgressError(const class MyError&); +void ProgressWarning(const char *format, ...); +void ProgressOutput(const char *format, ...); +bool ProgressQuery(bool fDefault, const char *format, ...); +void ProgressStart(long lMax, const char *caption, const char *progresstext, const char *format, ...); +void ProgressAdvance(long lNewValue); +void ProgressEnd(); + + +class VDProgress { +public: + VDProgress(long lMax, const char *caption, const char *progresstext, const char *format, ...) { + ProgressStart(lMax, caption, progresstext, format); + } + + ~VDProgress() { + ProgressEnd(); + } + + void advance(long v) { + ProgressAdvance(v); + } +}; + +class VDProgressAbortable { +public: + VDProgressAbortable(long lMax, const char *caption, const char *progresstext, const char *format, ...) { + ProgressStart(lMax, caption, progresstext, format); + ProgressSetAbort(false); + } + + ~VDProgressAbortable() { + ProgressEnd(); + } + + void advance(long v) { + if (ProgressCheckAbort()) + throw MyUserAbortError(); + ProgressAdvance(v); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/protscope.h b/src/thirdparty/VirtualDub/h/vd2/system/protscope.h index 6c22a54ad1f..2832271c4e2 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/protscope.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/protscope.h @@ -1,245 +1,245 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_PROTSCOPE_H -#define f_VD2_SYSTEM_PROTSCOPE_H - -#ifdef _MSC_VER - #pragma once -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// Protected scope macros -// -// These macros allow you to define a scope which is known to the crash -// handler -- that is, if the application crashes within a protected scope -// the handler will report the scope information in the crash output. -// - -class VDProtectedAutoScope; - -typedef VDProtectedAutoScope *(*tpVDGetProtectedScopeLink)(); -typedef void (*tpVDSetProtectedScopeLink)(VDProtectedAutoScope *); - -extern tpVDGetProtectedScopeLink g_pVDGetProtectedScopeLink; -extern tpVDSetProtectedScopeLink g_pVDSetProtectedScopeLink; - -// The reason for this function is a bug in the Intel compiler regarding -// construction optimization -- it stores VDProtectedAutoScope::'vtable' -// in the vtable slot instead of VDProtectedAutoScope1::'vtable', thus -// killing the printf()s. "volatile" doesn't work to fix the problem, but -// calling an opaque global function does. Oh well. - -#ifdef __INTEL_COMPILER -void VDProtectedAutoScopeICLWorkaround(); -#endif - -class IVDProtectedScopeOutput { -public: - virtual void write(const char *s) = 0; - virtual void writef(const char *s, ...) = 0; -}; - -class VDProtectedAutoScope { -public: - VDProtectedAutoScope(const char *file, int line, const char *action) : mpFile(file), mLine(line), mpAction(action), mpLink(g_pVDGetProtectedScopeLink()) { - // Note that the assignment to g_protectedScopeLink cannot occur here, as the - // derived class has not been constructed yet. Uninitialized objects in - // the debugging chain are *bad*. - } - - ~VDProtectedAutoScope() { - g_pVDSetProtectedScopeLink(mpLink); - } - - operator bool() const { return false; } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.write(mpAction); - } - - VDProtectedAutoScope *mpLink; - const char *const mpFile; - const int mLine; - const char *const mpAction; -}; - -class VDProtectedAutoScopeData0 { -public: - VDProtectedAutoScopeData0(const char *file, int line, const char *action) : mpFile(file), mLine(line), mpAction(action) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; -}; - -template -class VDProtectedAutoScopeData1 { -public: - VDProtectedAutoScopeData1(const char *file, int line, const char *action, const T1 a1) : mpFile(file), mLine(line), mpAction(action), mArg1(a1) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; - const T1 mArg1; -}; - -template -class VDProtectedAutoScopeData2 { -public: - VDProtectedAutoScopeData2(const char *file, int line, const char *action, const T1 a1, const T2 a2) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; - const T1 mArg1; - const T2 mArg2; -}; - -template -class VDProtectedAutoScopeData3 { -public: - VDProtectedAutoScopeData3(const char *file, int line, const char *action, const T1 a1, const T2 a2, const T3 a3) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2), mArg3(a3) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; - const T1 mArg1; - const T2 mArg2; - const T3 mArg3; -}; - -template -class VDProtectedAutoScopeData4 { -public: - VDProtectedAutoScopeData4(const char *file, int line, const char *action, const T1 a1, const T2 a2, const T3 a3, const T4 a4) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2), mArg3(a3), mArg4(a4) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; - const T1 mArg1; - const T2 mArg2; - const T3 mArg3; - const T4 mArg4; -}; - -class VDProtectedAutoScope0 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope0(const VDProtectedAutoScopeData0& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } -}; - -template -class VDProtectedAutoScope1 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope1(const VDProtectedAutoScopeData1& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.writef(mpAction, mArg1); - } - - const T1 mArg1; -}; - -template -class VDProtectedAutoScope2 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope2(const VDProtectedAutoScopeData2& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.writef(mpAction, mArg1, mArg2); - } - - const T1 mArg1; - const T2 mArg2; -}; - -template -class VDProtectedAutoScope3 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope3(const VDProtectedAutoScopeData3& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2), mArg3(data.mArg3) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.writef(mpAction, mArg1, mArg2, mArg3); - } - - const T1 mArg1; - const T2 mArg2; - const T3 mArg3; -}; - -template -class VDProtectedAutoScope4 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope4(const VDProtectedAutoScopeData4& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2), mArg3(data.mArg3), mArg4(data.mArg4) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.writef(mpAction, mArg1, mArg2, mArg3, mArg4); - } - - const T1 mArg1; - const T2 mArg2; - const T3 mArg3; - const T4 mArg4; -}; - - -#define vdprotected(action) vdobjectscope(VDProtectedAutoScope0 autoscope = VDProtectedAutoScopeData0(__FILE__, __LINE__, action)) -#define vdprotected1(actionf, type1, arg1) vdobjectscope(VDProtectedAutoScope1 autoscope = VDProtectedAutoScopeData1(__FILE__, __LINE__, actionf, arg1)) - -// @&#(* preprocessor doesn't view template brackets as escaping commas, so we have a slight -// problem.... - -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || defined(VD_COMPILER_MSVC_VC8_DDK)) -#define vdprotected2(actionf, type1, arg1, type2, arg2) if(VDProtectedAutoScope2 autoscope = VDProtectedAutoScopeData2(__FILE__, __LINE__, actionf, arg1, arg2)) VDNEVERHERE; else -#define vdprotected3(actionf, type1, arg1, type2, arg2, type3, arg3) if(VDProtectedAutoScope3 autoscope = VDProtectedAutoScopeData3(__FILE__, __LINE__, actionf, arg1, arg2, arg3)) VDNEVERHERE; else -#define vdprotected4(actionf, type1, arg1, type2, arg2, type3, arg3, type4, arg4) if(VDProtectedAutoScope4 autoscope = VDProtectedAutoScopeData4(__FILE__, __LINE__, actionf, arg1, arg2, arg3, arg4)) VDNEVERHERE; else -#else -#define vdprotected2(actionf, type1, arg1, type2, arg2) switch(VDProtectedAutoScope2 autoscope = VDProtectedAutoScopeData2(__FILE__, __LINE__, actionf, arg1, arg2)) case 0: default: -#define vdprotected3(actionf, type1, arg1, type2, arg2, type3, arg3) switch(VDProtectedAutoScope3 autoscope = VDProtectedAutoScopeData3(__FILE__, __LINE__, actionf, arg1, arg2, arg3)) case 0: default: -#define vdprotected4(actionf, type1, arg1, type2, arg2, type3, arg3, type4, arg4) switch(VDProtectedAutoScope4 autoscope = VDProtectedAutoScopeData4(__FILE__, __LINE__, actionf, arg1, arg2, arg3, arg4)) case 0: default: -#endif - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_PROTSCOPE_H +#define f_VD2_SYSTEM_PROTSCOPE_H + +#ifdef _MSC_VER + #pragma once +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// Protected scope macros +// +// These macros allow you to define a scope which is known to the crash +// handler -- that is, if the application crashes within a protected scope +// the handler will report the scope information in the crash output. +// + +class VDProtectedAutoScope; + +typedef VDProtectedAutoScope *(*tpVDGetProtectedScopeLink)(); +typedef void (*tpVDSetProtectedScopeLink)(VDProtectedAutoScope *); + +extern tpVDGetProtectedScopeLink g_pVDGetProtectedScopeLink; +extern tpVDSetProtectedScopeLink g_pVDSetProtectedScopeLink; + +// The reason for this function is a bug in the Intel compiler regarding +// construction optimization -- it stores VDProtectedAutoScope::'vtable' +// in the vtable slot instead of VDProtectedAutoScope1::'vtable', thus +// killing the printf()s. "volatile" doesn't work to fix the problem, but +// calling an opaque global function does. Oh well. + +#ifdef __INTEL_COMPILER +void VDProtectedAutoScopeICLWorkaround(); +#endif + +class IVDProtectedScopeOutput { +public: + virtual void write(const char *s) = 0; + virtual void writef(const char *s, ...) = 0; +}; + +class VDProtectedAutoScope { +public: + VDProtectedAutoScope(const char *file, int line, const char *action) : mpFile(file), mLine(line), mpAction(action), mpLink(g_pVDGetProtectedScopeLink()) { + // Note that the assignment to g_protectedScopeLink cannot occur here, as the + // derived class has not been constructed yet. Uninitialized objects in + // the debugging chain are *bad*. + } + + ~VDProtectedAutoScope() { + g_pVDSetProtectedScopeLink(mpLink); + } + + operator bool() const { return false; } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.write(mpAction); + } + + VDProtectedAutoScope *mpLink; + const char *const mpFile; + const int mLine; + const char *const mpAction; +}; + +class VDProtectedAutoScopeData0 { +public: + VDProtectedAutoScopeData0(const char *file, int line, const char *action) : mpFile(file), mLine(line), mpAction(action) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; +}; + +template +class VDProtectedAutoScopeData1 { +public: + VDProtectedAutoScopeData1(const char *file, int line, const char *action, const T1 a1) : mpFile(file), mLine(line), mpAction(action), mArg1(a1) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; + const T1 mArg1; +}; + +template +class VDProtectedAutoScopeData2 { +public: + VDProtectedAutoScopeData2(const char *file, int line, const char *action, const T1 a1, const T2 a2) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; + const T1 mArg1; + const T2 mArg2; +}; + +template +class VDProtectedAutoScopeData3 { +public: + VDProtectedAutoScopeData3(const char *file, int line, const char *action, const T1 a1, const T2 a2, const T3 a3) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2), mArg3(a3) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; + const T1 mArg1; + const T2 mArg2; + const T3 mArg3; +}; + +template +class VDProtectedAutoScopeData4 { +public: + VDProtectedAutoScopeData4(const char *file, int line, const char *action, const T1 a1, const T2 a2, const T3 a3, const T4 a4) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2), mArg3(a3), mArg4(a4) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; + const T1 mArg1; + const T2 mArg2; + const T3 mArg3; + const T4 mArg4; +}; + +class VDProtectedAutoScope0 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope0(const VDProtectedAutoScopeData0& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } +}; + +template +class VDProtectedAutoScope1 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope1(const VDProtectedAutoScopeData1& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.writef(mpAction, mArg1); + } + + const T1 mArg1; +}; + +template +class VDProtectedAutoScope2 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope2(const VDProtectedAutoScopeData2& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.writef(mpAction, mArg1, mArg2); + } + + const T1 mArg1; + const T2 mArg2; +}; + +template +class VDProtectedAutoScope3 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope3(const VDProtectedAutoScopeData3& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2), mArg3(data.mArg3) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.writef(mpAction, mArg1, mArg2, mArg3); + } + + const T1 mArg1; + const T2 mArg2; + const T3 mArg3; +}; + +template +class VDProtectedAutoScope4 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope4(const VDProtectedAutoScopeData4& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2), mArg3(data.mArg3), mArg4(data.mArg4) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.writef(mpAction, mArg1, mArg2, mArg3, mArg4); + } + + const T1 mArg1; + const T2 mArg2; + const T3 mArg3; + const T4 mArg4; +}; + + +#define vdprotected(action) vdobjectscope(VDProtectedAutoScope0 autoscope = VDProtectedAutoScopeData0(__FILE__, __LINE__, action)) +#define vdprotected1(actionf, type1, arg1) vdobjectscope(VDProtectedAutoScope1 autoscope = VDProtectedAutoScopeData1(__FILE__, __LINE__, actionf, arg1)) + +// @&#(* preprocessor doesn't view template brackets as escaping commas, so we have a slight +// problem.... + +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || defined(VD_COMPILER_MSVC_VC8_DDK)) +#define vdprotected2(actionf, type1, arg1, type2, arg2) if(VDProtectedAutoScope2 autoscope = VDProtectedAutoScopeData2(__FILE__, __LINE__, actionf, arg1, arg2)) VDNEVERHERE; else +#define vdprotected3(actionf, type1, arg1, type2, arg2, type3, arg3) if(VDProtectedAutoScope3 autoscope = VDProtectedAutoScopeData3(__FILE__, __LINE__, actionf, arg1, arg2, arg3)) VDNEVERHERE; else +#define vdprotected4(actionf, type1, arg1, type2, arg2, type3, arg3, type4, arg4) if(VDProtectedAutoScope4 autoscope = VDProtectedAutoScopeData4(__FILE__, __LINE__, actionf, arg1, arg2, arg3, arg4)) VDNEVERHERE; else +#else +#define vdprotected2(actionf, type1, arg1, type2, arg2) switch(VDProtectedAutoScope2 autoscope = VDProtectedAutoScopeData2(__FILE__, __LINE__, actionf, arg1, arg2)) case 0: default: +#define vdprotected3(actionf, type1, arg1, type2, arg2, type3, arg3) switch(VDProtectedAutoScope3 autoscope = VDProtectedAutoScopeData3(__FILE__, __LINE__, actionf, arg1, arg2, arg3)) case 0: default: +#define vdprotected4(actionf, type1, arg1, type2, arg2, type3, arg3, type4, arg4) switch(VDProtectedAutoScope4 autoscope = VDProtectedAutoScopeData4(__FILE__, __LINE__, actionf, arg1, arg2, arg3, arg4)) case 0: default: +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/refcount.h b/src/thirdparty/VirtualDub/h/vd2/system/refcount.h index 346595eff67..2e56682ac0d 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/refcount.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/refcount.h @@ -1,347 +1,347 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_REFCOUNT_H -#define f_VD2_SYSTEM_REFCOUNT_H - -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// IVDRefCount -/// Base interface for reference-counted objects. -/// -/// Reference counting is a relatively straightforward and simple method -/// of garbage collection. The rules are: -/// -/// 1) Objects increment their reference count on an AddRef() and -/// decrement it on a Release(). -/// 2) Objects destroy themselves when their reference count is dropped -/// to zero. -/// 3) Clients create references with AddRef() and destroy them with -/// Release(). -/// -/// One way to interact with refcounted objects is to call AddRef() -/// whenever a pointer is created, and Release() when the pointer is -/// nulled or changed. The vdrefptr template does this automatically. -/// Reference counting may be "combined" between pointers for optimization -/// reasons, such that fewer reference counts are outstanding than actual -/// pointers; this requires weak (non-refcounted) pointers and explicit -/// refcount management. -/// -/// Reference counting has two issues: -/// -/// A) It is expensive. VirtualDub uses it somewhat sparingly. -/// -/// B) Reference counting cannot cope with cycles. This issue is -/// avoided by arranging objects in a clearly ordered tree, such that -/// no class ever holds a pointer to another object of the same class -/// or to a parent in the reference hierarchy. vdrefptr can -/// implicitly create cycles if you are not careful. -/// -/// In VirtualDub, reference counting must be multithread safe, so atomic -/// increment/decrement should be used. vdrefcounted handles this -/// automatically for the template type class. -/// -/// Two final implementation details: -/// -/// - Little or no code should be executed after the reference count -/// drops to zero, preferably nothing more than the destructor implicitly -/// generated by the compiler. The reason is that otherwise there is the -/// potential for an object to be resurrected past its final release by -/// temporarily creating a new reference on the object. -/// -/// - AddRef() and Release() traditionally return the reference count on -/// the object after increment or decrement, but this is not required. -/// For Release builds, it is only required that the value for Release() -/// be zero iff the object is destroyed. (The same applies for AddRef(), -/// but since the result of AddRef() is always non-zero, the return of -/// AddRef() is of no use unless it is the actual count.) -/// -class VDINTERFACE IVDRefCount { -public: - virtual int AddRef()=0; - virtual int Release()=0; -}; - -/////////////////////////////////////////////////////////////////////////// -class vdrefcount { -public: - vdrefcount() : mRefCount(0) {} - vdrefcount(const vdrefcount& src) : mRefCount(0) {} // do not copy the refcount - virtual ~vdrefcount() {} - - vdrefcount& operator=(const vdrefcount&) {} // do not copy the refcount - - int AddRef() { - return mRefCount.inc(); - } - - int Release() { - int rc = --mRefCount; - - if (!rc) { - delete this; - return 0; - } - - VDASSERT(rc > 0); - return rc; - } - -protected: - VDAtomicInt mRefCount; -}; - -/////////////////////////////////////////////////////////////////////////// -// vdrefcounted -/// Implements thread-safe reference counting on top of a base class. -/// -/// vdrefcounted is used to either add reference counting to a base -/// class or to implement it on an interface. Use it by deriving your -/// class from it. -/// -template class vdrefcounted : public T { -public: - vdrefcounted() : mRefCount(0) {} - vdrefcounted(const vdrefcounted& src) : mRefCount(0) {} // do not copy the refcount - virtual ~vdrefcounted() {} - - vdrefcounted& operator=(const vdrefcounted&) {} // do not copy the refcount - - inline virtual int AddRef() { - return mRefCount.inc(); - } - - inline virtual int Release() { - int rc = --mRefCount; - - if (!rc) { - delete this; - return 0; - } - - VDASSERT(rc > 0); - - return rc; - } - -protected: - VDAtomicInt mRefCount; -}; - -/////////////////////////////////////////////////////////////////////////// -// vdrefptr -/// Reference-counting smart pointer. -/// -/// Maintains a strong reference on any object that supports AddRef/Release -/// semantics. This includes any interface including IVDRefCount, -/// IVDRefUnknown, or the IUnknown interface in Microsoft COM. Because -/// references are automatically traded as necessary, smart pointers are -/// very useful for maintaining exception safety. -/// -template class vdrefptr { -protected: - T *ptr; - -public: - typedef vdrefptr self_type; - typedef T element_type; - - /// Creates a new smart pointer and obtains a new reference on the - /// specified object. - explicit vdrefptr(T *p = 0) : ptr(p) { - if (p) - p->AddRef(); - } - - /// Clones a smart pointer, duplicating any held reference. - vdrefptr(const self_type& src) { - ptr = src.ptr; - if (ptr) - ptr->AddRef(); - } - - /// Destroys the smart pointer, releasing any held reference. - ~vdrefptr() { - if (ptr) - ptr->Release(); - } - - /// Assigns a new object to a smart pointer. Any old object is released - /// and the new object is addrefed. - inline self_type& operator=(T *src) { - if (src) - src->AddRef(); - if (ptr) - ptr->Release(); - ptr = src; - return *this; - } - - /// Assigns a new object to a smart pointer. Any old object is released - /// and the new object is addrefed. - inline self_type& operator=(const vdrefptr& src) { - if (src.ptr) - src.ptr->AddRef(); - if (ptr) - ptr->Release(); - ptr = src.ptr; - return *this; - } - - operator T*() const { return ptr; } - T& operator*() const { return *ptr; } - T *operator->() const { return ptr; } - - /// Removes any old reference and returns a double-pointer to the nulled - /// internal pointer. This is useful for passing to IUnknown-derived - /// interfaces that accept (T **) parameters, like QueryInterface(). - T** operator~() { - if (ptr) { - ptr->Release(); - ptr = NULL; - } - return &ptr; - } - - /// Removes any held reference. - inline void clear() { - if (ptr) - ptr->Release(); - ptr = NULL; - } - - /// Removes any existing reference and moves a reference from another - /// smart pointer. The source pointer is cleared afterward. - inline void from(vdrefptr& src) { - if (ptr) - ptr->Release(); - ptr = src.ptr; - src.ptr = NULL; - } - - /// Removes any existing reference and accepts a reference to a new - /// object without actually obtaining one. This is useful if someone - /// has already addrefed an object for you. - inline void set(T* src) { - if (ptr) - ptr->Release(); - - ptr = src; - } - - /// Returns the held reference and clears the smart pointer without - /// releasing the reference. This is useful for holding onto a reference - /// in an exception-safe manner up until the last moment. - inline T *release() { - T *p = ptr; - ptr = NULL; - return p; - } - - /// Swaps the references between two smart pointers. - void swap(vdrefptr& r) { - T *p = ptr; - ptr = r.ptr; - r.ptr = p; - } -}; - -/////////////////////////////////////////////////////////////////////////// - -template -bool VDRefCountObjectFactory(U **pp) { - T *p = new_nothrow T; - if (!p) - return false; - - *pp = static_cast(p); - p->AddRef(); - return true; -} - -/////////////////////////////////////////////////////////////////////////// - -struct vdsaferelease_t {}; -extern vdsaferelease_t vdsaferelease; - -template -inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *& p) { - if (p) { - p->Release(); - p = 0; - } - - return x; -} - -template -inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *& p) { - if (p) { - p->Release(); - p = 0; - } - - return x; -} - -template -inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *(&p)[N]) { - for(size_t i=0; iRelease(); - p[i] = 0; - } - } - - return x; -} - -template -inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *(&p)[N]) { - for(size_t i=0; iRelease(); - p[i] = 0; - } - } - - return x; -} - -/////////////////////////////////////////////////////////////////////////// - -template -void VDReleaseObjects(const T& container) { - for(typename T::const_iterator it(container.begin()), itEnd(container.end()); - it != itEnd; - ++it) - { - (*it)->Release(); - } -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_REFCOUNT_H +#define f_VD2_SYSTEM_REFCOUNT_H + +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// IVDRefCount +/// Base interface for reference-counted objects. +/// +/// Reference counting is a relatively straightforward and simple method +/// of garbage collection. The rules are: +/// +/// 1) Objects increment their reference count on an AddRef() and +/// decrement it on a Release(). +/// 2) Objects destroy themselves when their reference count is dropped +/// to zero. +/// 3) Clients create references with AddRef() and destroy them with +/// Release(). +/// +/// One way to interact with refcounted objects is to call AddRef() +/// whenever a pointer is created, and Release() when the pointer is +/// nulled or changed. The vdrefptr template does this automatically. +/// Reference counting may be "combined" between pointers for optimization +/// reasons, such that fewer reference counts are outstanding than actual +/// pointers; this requires weak (non-refcounted) pointers and explicit +/// refcount management. +/// +/// Reference counting has two issues: +/// +/// A) It is expensive. VirtualDub uses it somewhat sparingly. +/// +/// B) Reference counting cannot cope with cycles. This issue is +/// avoided by arranging objects in a clearly ordered tree, such that +/// no class ever holds a pointer to another object of the same class +/// or to a parent in the reference hierarchy. vdrefptr can +/// implicitly create cycles if you are not careful. +/// +/// In VirtualDub, reference counting must be multithread safe, so atomic +/// increment/decrement should be used. vdrefcounted handles this +/// automatically for the template type class. +/// +/// Two final implementation details: +/// +/// - Little or no code should be executed after the reference count +/// drops to zero, preferably nothing more than the destructor implicitly +/// generated by the compiler. The reason is that otherwise there is the +/// potential for an object to be resurrected past its final release by +/// temporarily creating a new reference on the object. +/// +/// - AddRef() and Release() traditionally return the reference count on +/// the object after increment or decrement, but this is not required. +/// For Release builds, it is only required that the value for Release() +/// be zero iff the object is destroyed. (The same applies for AddRef(), +/// but since the result of AddRef() is always non-zero, the return of +/// AddRef() is of no use unless it is the actual count.) +/// +class VDINTERFACE IVDRefCount { +public: + virtual int AddRef()=0; + virtual int Release()=0; +}; + +/////////////////////////////////////////////////////////////////////////// +class vdrefcount { +public: + vdrefcount() : mRefCount(0) {} + vdrefcount(const vdrefcount& src) : mRefCount(0) {} // do not copy the refcount + virtual ~vdrefcount() {} + + vdrefcount& operator=(const vdrefcount&) {} // do not copy the refcount + + int AddRef() { + return mRefCount.inc(); + } + + int Release() { + int rc = --mRefCount; + + if (!rc) { + delete this; + return 0; + } + + VDASSERT(rc > 0); + return rc; + } + +protected: + VDAtomicInt mRefCount; +}; + +/////////////////////////////////////////////////////////////////////////// +// vdrefcounted +/// Implements thread-safe reference counting on top of a base class. +/// +/// vdrefcounted is used to either add reference counting to a base +/// class or to implement it on an interface. Use it by deriving your +/// class from it. +/// +template class vdrefcounted : public T { +public: + vdrefcounted() : mRefCount(0) {} + vdrefcounted(const vdrefcounted& src) : mRefCount(0) {} // do not copy the refcount + virtual ~vdrefcounted() {} + + vdrefcounted& operator=(const vdrefcounted&) {} // do not copy the refcount + + inline virtual int AddRef() { + return mRefCount.inc(); + } + + inline virtual int Release() { + int rc = --mRefCount; + + if (!rc) { + delete this; + return 0; + } + + VDASSERT(rc > 0); + + return rc; + } + +protected: + VDAtomicInt mRefCount; +}; + +/////////////////////////////////////////////////////////////////////////// +// vdrefptr +/// Reference-counting smart pointer. +/// +/// Maintains a strong reference on any object that supports AddRef/Release +/// semantics. This includes any interface including IVDRefCount, +/// IVDRefUnknown, or the IUnknown interface in Microsoft COM. Because +/// references are automatically traded as necessary, smart pointers are +/// very useful for maintaining exception safety. +/// +template class vdrefptr { +protected: + T *ptr; + +public: + typedef vdrefptr self_type; + typedef T element_type; + + /// Creates a new smart pointer and obtains a new reference on the + /// specified object. + explicit vdrefptr(T *p = 0) : ptr(p) { + if (p) + p->AddRef(); + } + + /// Clones a smart pointer, duplicating any held reference. + vdrefptr(const self_type& src) { + ptr = src.ptr; + if (ptr) + ptr->AddRef(); + } + + /// Destroys the smart pointer, releasing any held reference. + ~vdrefptr() { + if (ptr) + ptr->Release(); + } + + /// Assigns a new object to a smart pointer. Any old object is released + /// and the new object is addrefed. + inline self_type& operator=(T *src) { + if (src) + src->AddRef(); + if (ptr) + ptr->Release(); + ptr = src; + return *this; + } + + /// Assigns a new object to a smart pointer. Any old object is released + /// and the new object is addrefed. + inline self_type& operator=(const vdrefptr& src) { + if (src.ptr) + src.ptr->AddRef(); + if (ptr) + ptr->Release(); + ptr = src.ptr; + return *this; + } + + operator T*() const { return ptr; } + T& operator*() const { return *ptr; } + T *operator->() const { return ptr; } + + /// Removes any old reference and returns a double-pointer to the nulled + /// internal pointer. This is useful for passing to IUnknown-derived + /// interfaces that accept (T **) parameters, like QueryInterface(). + T** operator~() { + if (ptr) { + ptr->Release(); + ptr = NULL; + } + return &ptr; + } + + /// Removes any held reference. + inline void clear() { + if (ptr) + ptr->Release(); + ptr = NULL; + } + + /// Removes any existing reference and moves a reference from another + /// smart pointer. The source pointer is cleared afterward. + inline void from(vdrefptr& src) { + if (ptr) + ptr->Release(); + ptr = src.ptr; + src.ptr = NULL; + } + + /// Removes any existing reference and accepts a reference to a new + /// object without actually obtaining one. This is useful if someone + /// has already addrefed an object for you. + inline void set(T* src) { + if (ptr) + ptr->Release(); + + ptr = src; + } + + /// Returns the held reference and clears the smart pointer without + /// releasing the reference. This is useful for holding onto a reference + /// in an exception-safe manner up until the last moment. + inline T *release() { + T *p = ptr; + ptr = NULL; + return p; + } + + /// Swaps the references between two smart pointers. + void swap(vdrefptr& r) { + T *p = ptr; + ptr = r.ptr; + r.ptr = p; + } +}; + +/////////////////////////////////////////////////////////////////////////// + +template +bool VDRefCountObjectFactory(U **pp) { + T *p = new_nothrow T; + if (!p) + return false; + + *pp = static_cast(p); + p->AddRef(); + return true; +} + +/////////////////////////////////////////////////////////////////////////// + +struct vdsaferelease_t {}; +extern vdsaferelease_t vdsaferelease; + +template +inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *& p) { + if (p) { + p->Release(); + p = 0; + } + + return x; +} + +template +inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *& p) { + if (p) { + p->Release(); + p = 0; + } + + return x; +} + +template +inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *(&p)[N]) { + for(size_t i=0; iRelease(); + p[i] = 0; + } + } + + return x; +} + +template +inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *(&p)[N]) { + for(size_t i=0; iRelease(); + p[i] = 0; + } + } + + return x; +} + +/////////////////////////////////////////////////////////////////////////// + +template +void VDReleaseObjects(const T& container) { + for(typename T::const_iterator it(container.begin()), itEnd(container.end()); + it != itEnd; + ++it) + { + (*it)->Release(); + } +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/registry.h b/src/thirdparty/VirtualDub/h/vd2/system/registry.h index 426f2c48582..b741ff4f2b0 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/registry.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/registry.h @@ -1,155 +1,155 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_REGISTRY_H -#define f_VD2_SYSTEM_REGISTRY_H - -#include - -class IVDRegistryProvider { -public: - enum Type { - kTypeUnknown, - kTypeInt, - kTypeString, - kTypeBinary - }; - - virtual void *GetMachineKey() = 0; - virtual void *GetUserKey() = 0; - virtual void *CreateKey(void *key, const char *path, bool write) = 0; - virtual void CloseKey(void *key) = 0; - - virtual bool SetBool(void *key, const char *name, bool) = 0; - virtual bool SetInt(void *key, const char *name, int) = 0; - virtual bool SetString(void *key, const char *name, const char *pszString) = 0; - virtual bool SetString(void *key, const char *name, const wchar_t *pszString) = 0; - virtual bool SetBinary(void *key, const char *name, const char *data, int len) = 0; - - virtual Type GetType(void *key, const char *name) = 0; - virtual bool GetBool(void *key, const char *name, bool& val) = 0; - virtual bool GetInt(void *key, const char *name, int& val) = 0; - virtual bool GetString(void *key, const char *name, VDStringA& s) = 0; - virtual bool GetString(void *key, const char *name, VDStringW& s) = 0; - - virtual int GetBinaryLength(void *key, const char *name) = 0; - virtual bool GetBinary(void *key, const char *name, char *buf, int maxlen) = 0; - - virtual bool RemoveValue(void *key, const char *name) = 0; - virtual bool RemoveKey(void *key, const char *name) = 0; - - virtual void *EnumKeysBegin(void *key) = 0; - virtual const char *EnumKeysNext(void *enumerator) = 0; - virtual void EnumKeysClose(void *enumerator) = 0; - - virtual void *EnumValuesBegin(void *key) = 0; - virtual const char *EnumValuesNext(void *enumerator) = 0; - virtual void EnumValuesClose(void *enumerator) = 0; -}; - -IVDRegistryProvider *VDGetRegistryProvider(); -void VDSetRegistryProvider(IVDRegistryProvider *provider); - -/////////////////////////////////////////////////////////////////////////// - -class VDRegistryKey { -public: - enum Type { - kTypeUnknown, - kTypeInt, - kTypeString, - kTypeBinary - }; - - VDRegistryKey(const char *pszKey, bool global = false, bool write = true); - VDRegistryKey(VDRegistryKey& baseKey, const char *name, bool write = true); - ~VDRegistryKey(); - - void *getRawHandle() const { return mKey; } - - bool isReady() const { return mKey != 0; } - - bool setBool(const char *name, bool) const; - bool setInt(const char *name, int) const; - bool setString(const char *name, const char *pszString) const; - bool setString(const char *name, const wchar_t *pszString) const; - bool setBinary(const char *name, const char *data, int len) const; - - Type getValueType(const char *name) const; - - bool getBool(const char *name, bool def=false) const; - int getInt(const char *name, int def=0) const; - int getEnumInt(const char *name, int maxVal, int def=0) const; - bool getString(const char *name, VDStringA& s) const; - bool getString(const char *name, VDStringW& s) const; - - int getBinaryLength(const char *name) const; - bool getBinary(const char *name, char *buf, int maxlen) const; - - bool removeValue(const char *); - bool removeKey(const char *); - -private: - void *mKey; -}; - -class VDRegistryValueIterator { - VDRegistryValueIterator(const VDRegistryValueIterator&); - VDRegistryValueIterator& operator=(const VDRegistryValueIterator&); -public: - VDRegistryValueIterator(const VDRegistryKey& key); - ~VDRegistryValueIterator(); - - const char *Next(); - -protected: - void *mEnumerator; -}; - -class VDRegistryKeyIterator { - VDRegistryKeyIterator(const VDRegistryKeyIterator& key); - VDRegistryKeyIterator& operator=(const VDRegistryKeyIterator& key); -public: - VDRegistryKeyIterator(const VDRegistryKey& key); - ~VDRegistryKeyIterator(); - - const char *Next(); - -protected: - void *mEnumerator; -}; - -class VDRegistryAppKey : public VDRegistryKey { -private: - static VDString s_appbase; - -public: - VDRegistryAppKey(); - VDRegistryAppKey(const char *pszKey, bool write = true, bool global = false); - - static void setDefaultKey(const char *pszAppName); -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_REGISTRY_H +#define f_VD2_SYSTEM_REGISTRY_H + +#include + +class IVDRegistryProvider { +public: + enum Type { + kTypeUnknown, + kTypeInt, + kTypeString, + kTypeBinary + }; + + virtual void *GetMachineKey() = 0; + virtual void *GetUserKey() = 0; + virtual void *CreateKey(void *key, const char *path, bool write) = 0; + virtual void CloseKey(void *key) = 0; + + virtual bool SetBool(void *key, const char *name, bool) = 0; + virtual bool SetInt(void *key, const char *name, int) = 0; + virtual bool SetString(void *key, const char *name, const char *pszString) = 0; + virtual bool SetString(void *key, const char *name, const wchar_t *pszString) = 0; + virtual bool SetBinary(void *key, const char *name, const char *data, int len) = 0; + + virtual Type GetType(void *key, const char *name) = 0; + virtual bool GetBool(void *key, const char *name, bool& val) = 0; + virtual bool GetInt(void *key, const char *name, int& val) = 0; + virtual bool GetString(void *key, const char *name, VDStringA& s) = 0; + virtual bool GetString(void *key, const char *name, VDStringW& s) = 0; + + virtual int GetBinaryLength(void *key, const char *name) = 0; + virtual bool GetBinary(void *key, const char *name, char *buf, int maxlen) = 0; + + virtual bool RemoveValue(void *key, const char *name) = 0; + virtual bool RemoveKey(void *key, const char *name) = 0; + + virtual void *EnumKeysBegin(void *key) = 0; + virtual const char *EnumKeysNext(void *enumerator) = 0; + virtual void EnumKeysClose(void *enumerator) = 0; + + virtual void *EnumValuesBegin(void *key) = 0; + virtual const char *EnumValuesNext(void *enumerator) = 0; + virtual void EnumValuesClose(void *enumerator) = 0; +}; + +IVDRegistryProvider *VDGetRegistryProvider(); +void VDSetRegistryProvider(IVDRegistryProvider *provider); + +/////////////////////////////////////////////////////////////////////////// + +class VDRegistryKey { +public: + enum Type { + kTypeUnknown, + kTypeInt, + kTypeString, + kTypeBinary + }; + + VDRegistryKey(const char *pszKey, bool global = false, bool write = true); + VDRegistryKey(VDRegistryKey& baseKey, const char *name, bool write = true); + ~VDRegistryKey(); + + void *getRawHandle() const { return mKey; } + + bool isReady() const { return mKey != 0; } + + bool setBool(const char *name, bool) const; + bool setInt(const char *name, int) const; + bool setString(const char *name, const char *pszString) const; + bool setString(const char *name, const wchar_t *pszString) const; + bool setBinary(const char *name, const char *data, int len) const; + + Type getValueType(const char *name) const; + + bool getBool(const char *name, bool def=false) const; + int getInt(const char *name, int def=0) const; + int getEnumInt(const char *name, int maxVal, int def=0) const; + bool getString(const char *name, VDStringA& s) const; + bool getString(const char *name, VDStringW& s) const; + + int getBinaryLength(const char *name) const; + bool getBinary(const char *name, char *buf, int maxlen) const; + + bool removeValue(const char *); + bool removeKey(const char *); + +private: + void *mKey; +}; + +class VDRegistryValueIterator { + VDRegistryValueIterator(const VDRegistryValueIterator&); + VDRegistryValueIterator& operator=(const VDRegistryValueIterator&); +public: + VDRegistryValueIterator(const VDRegistryKey& key); + ~VDRegistryValueIterator(); + + const char *Next(); + +protected: + void *mEnumerator; +}; + +class VDRegistryKeyIterator { + VDRegistryKeyIterator(const VDRegistryKeyIterator& key); + VDRegistryKeyIterator& operator=(const VDRegistryKeyIterator& key); +public: + VDRegistryKeyIterator(const VDRegistryKey& key); + ~VDRegistryKeyIterator(); + + const char *Next(); + +protected: + void *mEnumerator; +}; + +class VDRegistryAppKey : public VDRegistryKey { +private: + static VDString s_appbase; + +public: + VDRegistryAppKey(); + VDRegistryAppKey(const char *pszKey, bool write = true, bool global = false); + + static void setDefaultKey(const char *pszAppName); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/registrymemory.h b/src/thirdparty/VirtualDub/h/vd2/system/registrymemory.h index 38e2a9c452e..9a2d98daa6c 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/registrymemory.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/registrymemory.h @@ -1,81 +1,81 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_REGISTRYMEMORY_H -#define f_VD2_SYSTEM_REGISTRYMEMORY_H - -#include -#include -#include -#include - -class VDRegistryProviderMemory : public IVDRegistryProvider { -public: - VDRegistryProviderMemory(); - ~VDRegistryProviderMemory(); - - void *GetMachineKey(); - void *GetUserKey(); - void *CreateKey(void *key, const char *path, bool write); - void CloseKey(void *key); - - bool SetBool(void *key, const char *name, bool); - bool SetInt(void *key, const char *name, int); - bool SetString(void *key, const char *name, const char *str); - bool SetString(void *key, const char *name, const wchar_t *str); - bool SetBinary(void *key, const char *name, const char *data, int len); - - Type GetType(void *key, const char *name); - bool GetBool(void *key, const char *name, bool& val); - bool GetInt(void *key, const char *name, int& val); - bool GetString(void *key, const char *name, VDStringA& s); - bool GetString(void *key, const char *name, VDStringW& s); - - int GetBinaryLength(void *key, const char *name); - bool GetBinary(void *key, const char *name, char *buf, int maxlen); - - bool RemoveValue(void *key, const char *name); - bool RemoveKey(void *key, const char *name); - - void *EnumKeysBegin(void *key); - const char *EnumKeysNext(void *enumerator); - void EnumKeysClose(void *enumerator); - - void *EnumValuesBegin(void *key); - const char *EnumValuesNext(void *enumerator); - void EnumValuesClose(void *enumerator); - -protected: - class Key; - class Value; - struct Enumerator; - - Key *mpUserKey; - Key *mpMachineKey; - - VDCriticalSection mMutex; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_REGISTRYMEMORY_H +#define f_VD2_SYSTEM_REGISTRYMEMORY_H + +#include +#include +#include +#include + +class VDRegistryProviderMemory : public IVDRegistryProvider { +public: + VDRegistryProviderMemory(); + ~VDRegistryProviderMemory(); + + void *GetMachineKey(); + void *GetUserKey(); + void *CreateKey(void *key, const char *path, bool write); + void CloseKey(void *key); + + bool SetBool(void *key, const char *name, bool); + bool SetInt(void *key, const char *name, int); + bool SetString(void *key, const char *name, const char *str); + bool SetString(void *key, const char *name, const wchar_t *str); + bool SetBinary(void *key, const char *name, const char *data, int len); + + Type GetType(void *key, const char *name); + bool GetBool(void *key, const char *name, bool& val); + bool GetInt(void *key, const char *name, int& val); + bool GetString(void *key, const char *name, VDStringA& s); + bool GetString(void *key, const char *name, VDStringW& s); + + int GetBinaryLength(void *key, const char *name); + bool GetBinary(void *key, const char *name, char *buf, int maxlen); + + bool RemoveValue(void *key, const char *name); + bool RemoveKey(void *key, const char *name); + + void *EnumKeysBegin(void *key); + const char *EnumKeysNext(void *enumerator); + void EnumKeysClose(void *enumerator); + + void *EnumValuesBegin(void *key); + const char *EnumValuesNext(void *enumerator); + void EnumValuesClose(void *enumerator); + +protected: + class Key; + class Value; + struct Enumerator; + + Key *mpUserKey; + Key *mpMachineKey; + + VDCriticalSection mMutex; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/source/registrymemory.cpp b/src/thirdparty/VirtualDub/h/vd2/system/source/registrymemory.cpp index 020e7d66833..8e50463d18d 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/source/registrymemory.cpp +++ b/src/thirdparty/VirtualDub/h/vd2/system/source/registrymemory.cpp @@ -1,669 +1,669 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include - -class VDRegistryProviderMemory::Value : public vdhashtable_base_node { -public: - enum Type { - kTypeInt, - kTypeString, - kTypeBinary - }; - - Value(); - - void SetInt(sint32 v); - void SetString(const wchar_t *str); - void SetBinary(const void *p, size_t len); - - Type GetType() const { return mType; } - - bool GetInt(sint32& v) const; - bool GetString(const wchar_t *&s) const; - bool GetBinary(const void *&p, size_t& len) const; - -protected: - Type mType; - - // we're being lazy for now - sint32 mInt; - VDStringW mString; - vdfastvector mRawData; -}; - -VDRegistryProviderMemory::Value::Value() - : mType(kTypeInt) - , mInt(0) -{ -} - -void VDRegistryProviderMemory::Value::SetInt(sint32 v) { - if (mType != kTypeInt) { - mString.swap(VDStringW()); - mRawData.swap(vdfastvector()); - mType = kTypeInt; - } - - mInt = v; -} - -void VDRegistryProviderMemory::Value::SetString(const wchar_t *str) { - if (mType != kTypeString) { - mRawData.swap(vdfastvector()); - mType = kTypeString; - } - - mString = str; -} - -void VDRegistryProviderMemory::Value::SetBinary(const void *p, size_t len) { - if (mType != kTypeBinary) { - mString.swap(VDStringW()); - mType = kTypeBinary; - } - - mRawData.assign((char *)p, (char *)p + len); -} - -bool VDRegistryProviderMemory::Value::GetInt(sint32& v) const { - if (mType != kTypeInt) - return false; - - v = mInt; - return true; -} - -bool VDRegistryProviderMemory::Value::GetString(const wchar_t *&s) const { - if (mType != kTypeString) - return false; - - s = mString.c_str(); - return true; -} - -bool VDRegistryProviderMemory::Value::GetBinary(const void *&p, size_t& len) const { - if (mType != kTypeBinary) - return false; - - p = mRawData.data(); - len = mRawData.size(); - return true; -} - -class VDRegistryProviderMemory::Key { -public: - Key(); - ~Key(); - - void AddRef(); - void Release(); - - bool Add(const VDStringA& name, VDRegistryProviderMemory::Value *value); - void Remove(VDRegistryProviderMemory::Key *key); - bool RemoveKey(const char *name); - bool RemoveValue(const char *name); - - const char *GetKeyName(size_t index) const { - if (index >= mKeyList.size()) - return NULL; - - return mKeyList[index]->first.c_str(); - } - - const char *GetValueName(size_t index) const { - if (index >= mValueList.size()) - return NULL; - - return mValueList[index]->first.c_str(); - } - - Value *OpenValue(const char *name, bool create); - Key *OpenKey(const VDStringSpanA& name, bool create); - - int mRefCount; - bool mbCondemned; - - Key *mpParent; - - struct KeyHash { - size_t operator()(const VDStringA& s) const; - size_t operator()(const char *s) const; - }; - - struct KeyPred { - bool operator()(const VDStringA& s, const VDStringA& t) const; - bool operator()(const VDStringA& s, const VDStringSpanA& t) const; - bool operator()(const VDStringA& s, const char *t) const; - }; - - typedef vdhashmap KeyMap; - KeyMap mKeyMap; - - typedef vdfastvector KeyList; - KeyList mKeyList; - - typedef vdhashmap ValueMap; - ValueMap mValueMap; - - typedef vdfastvector ValueList; - ValueList mValueList; -}; - -size_t VDRegistryProviderMemory::Key::KeyHash::operator()(const VDStringA& s) const { - return VDHashString32I(s.data(), s.size()); -} - -size_t VDRegistryProviderMemory::Key::KeyHash::operator()(const char *s) const { - return VDHashString32I(s); -} - -bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const VDStringA& t) const { - return s.comparei(t) == 0; -} - -bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const VDStringSpanA& t) const { - return s.comparei(t) == 0; -} - -bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const char *t) const { - return s.comparei(t) == 0; -} - -VDRegistryProviderMemory::Key::Key() - : mRefCount(0) - , mbCondemned(false) - , mpParent(NULL) -{ -} - -VDRegistryProviderMemory::Key::~Key() { - VDASSERT(!mRefCount); -} - -void VDRegistryProviderMemory::Key::AddRef() { - ++mRefCount; -} - -void VDRegistryProviderMemory::Key::Release() { - if (!--mRefCount && mbCondemned) - mpParent->Remove(this); -} - -bool VDRegistryProviderMemory::Key::Add(const VDStringA& name, VDRegistryProviderMemory::Value *value) { - ValueMap::insert_return_type r(mValueMap.insert(name)); - if (!r.second) - return false; - - mValueList.push_back(&*r.first); - return true; -} - -void VDRegistryProviderMemory::Key::Remove(VDRegistryProviderMemory::Key *key) { - VDASSERT(key->mRefCount == 0); - - for(KeyList::iterator it(mKeyList.begin()), itEnd(mKeyList.end()); it != itEnd; ++it) { - const KeyMap::value_type *e = *it; - - if (&e->second == key) { - mKeyMap.erase(e->first); - mKeyList.erase(it); - break; - } - } -} - -bool VDRegistryProviderMemory::Key::RemoveKey(const char *name) { - if (!name) - name = ""; - - // look up the subkey - KeyMap::iterator it(mKeyMap.find_as(name)); - - // fail if not found - if (it != mKeyMap.end()) - return false; - - // can't delete key if it has subkeys - Key& key = it->second; - if (!key.mKeyList.empty()) - return false; - - // if the key is open, we have to condemn it and delete it later - if (key.mRefCount) { - key.mbCondemned = true; - return true; - } - - // delete the key - mKeyMap.erase(it); - - KeyList::iterator it2(std::find(mKeyList.begin(), mKeyList.end(), &*it)); - VDASSERT(it2 != mKeyList.end()); - - mKeyList.erase(it2); - return true; -} - -bool VDRegistryProviderMemory::Key::RemoveValue(const char *name) { - if (!name) - name = ""; - - ValueMap::iterator it(mValueMap.find_as(name)); - - if (it == mValueMap.end()) - return false; - - ValueList::iterator it2(std::find(mValueList.begin(), mValueList.end(), &*it)); - VDASSERT(it2 != mValueList.end()); - - mValueList.erase(it2); - mValueMap.erase(it); - return true; -} - -VDRegistryProviderMemory::Value *VDRegistryProviderMemory::Key::OpenValue(const char *name, bool create) { - if (!name) - name = ""; - - ValueMap::iterator it(mValueMap.find_as(name)); - - if (it != mValueMap.end()) - return &it->second; - - if (!create) - return NULL; - - ValueMap::insert_return_type r(mValueMap.insert(VDStringA(name))); - mValueList.push_back(&*r.first); - - return &r.first->second; -} - -VDRegistryProviderMemory::Key *VDRegistryProviderMemory::Key::OpenKey(const VDStringSpanA& name, bool create) { - KeyMap::iterator it(mKeyMap.find_as(name)); - - if (it != mKeyMap.end()) - return &it->second; - - if (!create) - return NULL; - - KeyMap::insert_return_type r(mKeyMap.insert(VDStringA(name))); - mKeyList.push_back(&*r.first); - - Key *key = &r.first->second; - - key->mpParent = this; - - return key; -} - -/////////////////////////////////////////////////////////////////////// - -VDRegistryProviderMemory::VDRegistryProviderMemory() { - vdautoptr machineKey(new Key); - vdautoptr userKey(new Key); - - mpMachineKey = machineKey.release(); - mpUserKey = userKey.release(); -} - -VDRegistryProviderMemory::~VDRegistryProviderMemory() { - delete mpMachineKey; - delete mpUserKey; -} - -void *VDRegistryProviderMemory::GetMachineKey() { - return mpMachineKey; -} - -void *VDRegistryProviderMemory::GetUserKey() { - return mpUserKey; -} - -void *VDRegistryProviderMemory::CreateKey(void *key0, const char *path, bool write) { - Key *key = (Key *)key0; - - vdsynchronized(mMutex) { - // check for root specifier - if (*path == '\\') { - do { - ++path; - } while(*path == '\\'); - - while(key->mpParent) - key = key->mpParent; - } - - // parse out a component at a time - for(;;) { - const char *split = strchr(path, '\\'); - if (!split) - split = path + strlen(path); - - if (path == split) - break; - - VDStringSpanA component(path, split); - - // lookup component - key = key->OpenKey(component, write); - if (!key) - return NULL; - - // skip path specifier - if (!*split) - break; - - path = split; - do { - ++path; - } while(*path == L'\\'); - } - - key->AddRef(); - } - - return key; -} - -void VDRegistryProviderMemory::CloseKey(void *key0) { - Key *key = (Key *)key0; - - vdsynchronized(mMutex) { - key->Release(); - } -} - -bool VDRegistryProviderMemory::SetBool(void *key0, const char *name, bool v) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetInt(v); - } - return true; -} - -bool VDRegistryProviderMemory::SetInt(void *key0, const char *name, int v) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetInt(v); - } - return true; -} - -bool VDRegistryProviderMemory::SetString(void *key0, const char *name, const char *str) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetString(VDTextAToW(str).c_str()); - } - return true; -} - -bool VDRegistryProviderMemory::SetString(void *key0, const char *name, const wchar_t *str) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetString(str); - } - return true; -} - -bool VDRegistryProviderMemory::SetBinary(void *key0, const char *name, const char *data, int len) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetBinary(data, len); - } - return true; -} - -IVDRegistryProvider::Type VDRegistryProviderMemory::GetType(void *key0, const char *name) { - Type type = kTypeUnknown; - - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (value) { - switch(value->GetType()) { - case Value::kTypeInt: - type = kTypeInt; - break; - - case Value::kTypeString: - type = kTypeString; - break; - - case Value::kTypeBinary: - type = kTypeBinary; - break; - } - } - } - - return type; -} - -bool VDRegistryProviderMemory::GetBool(void *key0, const char *name, bool& val) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - sint32 v32; - if (!value || !value->GetInt(v32)) - return false; - - val = v32 != 0; - } - return true; -} - -bool VDRegistryProviderMemory::GetInt(void *key0, const char *name, int& val) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - sint32 v32; - if (!value || !value->GetInt(v32)) - return false; - - val = v32; - } - return true; -} - -bool VDRegistryProviderMemory::GetString(void *key0, const char *name, VDStringA& s) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - const wchar_t *raws; - if (!value || !value->GetString(raws)) - return false; - - s = VDTextWToA(raws); - } - return true; -} - -bool VDRegistryProviderMemory::GetString(void *key0, const char *name, VDStringW& s) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - const wchar_t *raws; - if (!value || !value->GetString(raws)) - return false; - - s = raws; - } - return true; -} - -int VDRegistryProviderMemory::GetBinaryLength(void *key0, const char *name) { - size_t len; - - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - const void *p; - if (!value || !value->GetBinary(p, len)) - return -1; - } - return len; -} - -bool VDRegistryProviderMemory::GetBinary(void *key0, const char *name, char *buf, int maxlen) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - const void *p; - size_t len; - if (!value || !value->GetBinary(p, len) || (int)len > maxlen) - return false; - - memcpy(buf, p, len); - } - - return true; -} - -bool VDRegistryProviderMemory::RemoveValue(void *key0, const char *name) { - bool success; - - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - - success = key->RemoveValue(name); - } - - return true; -} - -bool VDRegistryProviderMemory::RemoveKey(void *key0, const char *name) { - bool success; - - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - - // if the key is a root key, silently ignore the request - if (!key->mpParent) - return true; - - success = key->RemoveKey(name); - } - - return true; -} - -struct VDRegistryProviderMemory::Enumerator { - Enumerator(Key *key) : mKey(key), mIndex(0) {} - - Key *mKey; - size_t mIndex; - VDStringA mName; -}; - -void *VDRegistryProviderMemory::EnumKeysBegin(void *key) { - return new Enumerator((Key *)key); -} - -const char *VDRegistryProviderMemory::EnumKeysNext(void *enumerator) { - Enumerator *en = (Enumerator *)enumerator; - - vdsynchronized(mMutex) { - const char *s = en->mKey->GetKeyName(en->mIndex); - if (!s) - return NULL; - - ++en->mIndex; - en->mName = s; - } - - return en->mName.c_str(); -} - -void VDRegistryProviderMemory::EnumKeysClose(void *enumerator) { - Enumerator *en = (Enumerator *)enumerator; - - delete en; -} - -void *VDRegistryProviderMemory::EnumValuesBegin(void *key) { - return new Enumerator((Key *)key); -} - -const char *VDRegistryProviderMemory::EnumValuesNext(void *enumerator) { - Enumerator *en = (Enumerator *)enumerator; - - if (!en->mKey) - return NULL; - - vdsynchronized(mMutex) { - const char *s = en->mKey->GetValueName(en->mIndex); - if (!s) - return NULL; - - ++en->mIndex; - en->mName = s; - } - - return en->mName.c_str(); -} - -void VDRegistryProviderMemory::EnumValuesClose(void *enumerator) { - Enumerator *en = (Enumerator *)enumerator; - - delete en; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include + +class VDRegistryProviderMemory::Value : public vdhashtable_base_node { +public: + enum Type { + kTypeInt, + kTypeString, + kTypeBinary + }; + + Value(); + + void SetInt(sint32 v); + void SetString(const wchar_t *str); + void SetBinary(const void *p, size_t len); + + Type GetType() const { return mType; } + + bool GetInt(sint32& v) const; + bool GetString(const wchar_t *&s) const; + bool GetBinary(const void *&p, size_t& len) const; + +protected: + Type mType; + + // we're being lazy for now + sint32 mInt; + VDStringW mString; + vdfastvector mRawData; +}; + +VDRegistryProviderMemory::Value::Value() + : mType(kTypeInt) + , mInt(0) +{ +} + +void VDRegistryProviderMemory::Value::SetInt(sint32 v) { + if (mType != kTypeInt) { + mString.swap(VDStringW()); + mRawData.swap(vdfastvector()); + mType = kTypeInt; + } + + mInt = v; +} + +void VDRegistryProviderMemory::Value::SetString(const wchar_t *str) { + if (mType != kTypeString) { + mRawData.swap(vdfastvector()); + mType = kTypeString; + } + + mString = str; +} + +void VDRegistryProviderMemory::Value::SetBinary(const void *p, size_t len) { + if (mType != kTypeBinary) { + mString.swap(VDStringW()); + mType = kTypeBinary; + } + + mRawData.assign((char *)p, (char *)p + len); +} + +bool VDRegistryProviderMemory::Value::GetInt(sint32& v) const { + if (mType != kTypeInt) + return false; + + v = mInt; + return true; +} + +bool VDRegistryProviderMemory::Value::GetString(const wchar_t *&s) const { + if (mType != kTypeString) + return false; + + s = mString.c_str(); + return true; +} + +bool VDRegistryProviderMemory::Value::GetBinary(const void *&p, size_t& len) const { + if (mType != kTypeBinary) + return false; + + p = mRawData.data(); + len = mRawData.size(); + return true; +} + +class VDRegistryProviderMemory::Key { +public: + Key(); + ~Key(); + + void AddRef(); + void Release(); + + bool Add(const VDStringA& name, VDRegistryProviderMemory::Value *value); + void Remove(VDRegistryProviderMemory::Key *key); + bool RemoveKey(const char *name); + bool RemoveValue(const char *name); + + const char *GetKeyName(size_t index) const { + if (index >= mKeyList.size()) + return NULL; + + return mKeyList[index]->first.c_str(); + } + + const char *GetValueName(size_t index) const { + if (index >= mValueList.size()) + return NULL; + + return mValueList[index]->first.c_str(); + } + + Value *OpenValue(const char *name, bool create); + Key *OpenKey(const VDStringSpanA& name, bool create); + + int mRefCount; + bool mbCondemned; + + Key *mpParent; + + struct KeyHash { + size_t operator()(const VDStringA& s) const; + size_t operator()(const char *s) const; + }; + + struct KeyPred { + bool operator()(const VDStringA& s, const VDStringA& t) const; + bool operator()(const VDStringA& s, const VDStringSpanA& t) const; + bool operator()(const VDStringA& s, const char *t) const; + }; + + typedef vdhashmap KeyMap; + KeyMap mKeyMap; + + typedef vdfastvector KeyList; + KeyList mKeyList; + + typedef vdhashmap ValueMap; + ValueMap mValueMap; + + typedef vdfastvector ValueList; + ValueList mValueList; +}; + +size_t VDRegistryProviderMemory::Key::KeyHash::operator()(const VDStringA& s) const { + return VDHashString32I(s.data(), s.size()); +} + +size_t VDRegistryProviderMemory::Key::KeyHash::operator()(const char *s) const { + return VDHashString32I(s); +} + +bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const VDStringA& t) const { + return s.comparei(t) == 0; +} + +bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const VDStringSpanA& t) const { + return s.comparei(t) == 0; +} + +bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const char *t) const { + return s.comparei(t) == 0; +} + +VDRegistryProviderMemory::Key::Key() + : mRefCount(0) + , mbCondemned(false) + , mpParent(NULL) +{ +} + +VDRegistryProviderMemory::Key::~Key() { + VDASSERT(!mRefCount); +} + +void VDRegistryProviderMemory::Key::AddRef() { + ++mRefCount; +} + +void VDRegistryProviderMemory::Key::Release() { + if (!--mRefCount && mbCondemned) + mpParent->Remove(this); +} + +bool VDRegistryProviderMemory::Key::Add(const VDStringA& name, VDRegistryProviderMemory::Value *value) { + ValueMap::insert_return_type r(mValueMap.insert(name)); + if (!r.second) + return false; + + mValueList.push_back(&*r.first); + return true; +} + +void VDRegistryProviderMemory::Key::Remove(VDRegistryProviderMemory::Key *key) { + VDASSERT(key->mRefCount == 0); + + for(KeyList::iterator it(mKeyList.begin()), itEnd(mKeyList.end()); it != itEnd; ++it) { + const KeyMap::value_type *e = *it; + + if (&e->second == key) { + mKeyMap.erase(e->first); + mKeyList.erase(it); + break; + } + } +} + +bool VDRegistryProviderMemory::Key::RemoveKey(const char *name) { + if (!name) + name = ""; + + // look up the subkey + KeyMap::iterator it(mKeyMap.find_as(name)); + + // fail if not found + if (it != mKeyMap.end()) + return false; + + // can't delete key if it has subkeys + Key& key = it->second; + if (!key.mKeyList.empty()) + return false; + + // if the key is open, we have to condemn it and delete it later + if (key.mRefCount) { + key.mbCondemned = true; + return true; + } + + // delete the key + mKeyMap.erase(it); + + KeyList::iterator it2(std::find(mKeyList.begin(), mKeyList.end(), &*it)); + VDASSERT(it2 != mKeyList.end()); + + mKeyList.erase(it2); + return true; +} + +bool VDRegistryProviderMemory::Key::RemoveValue(const char *name) { + if (!name) + name = ""; + + ValueMap::iterator it(mValueMap.find_as(name)); + + if (it == mValueMap.end()) + return false; + + ValueList::iterator it2(std::find(mValueList.begin(), mValueList.end(), &*it)); + VDASSERT(it2 != mValueList.end()); + + mValueList.erase(it2); + mValueMap.erase(it); + return true; +} + +VDRegistryProviderMemory::Value *VDRegistryProviderMemory::Key::OpenValue(const char *name, bool create) { + if (!name) + name = ""; + + ValueMap::iterator it(mValueMap.find_as(name)); + + if (it != mValueMap.end()) + return &it->second; + + if (!create) + return NULL; + + ValueMap::insert_return_type r(mValueMap.insert(VDStringA(name))); + mValueList.push_back(&*r.first); + + return &r.first->second; +} + +VDRegistryProviderMemory::Key *VDRegistryProviderMemory::Key::OpenKey(const VDStringSpanA& name, bool create) { + KeyMap::iterator it(mKeyMap.find_as(name)); + + if (it != mKeyMap.end()) + return &it->second; + + if (!create) + return NULL; + + KeyMap::insert_return_type r(mKeyMap.insert(VDStringA(name))); + mKeyList.push_back(&*r.first); + + Key *key = &r.first->second; + + key->mpParent = this; + + return key; +} + +/////////////////////////////////////////////////////////////////////// + +VDRegistryProviderMemory::VDRegistryProviderMemory() { + vdautoptr machineKey(new Key); + vdautoptr userKey(new Key); + + mpMachineKey = machineKey.release(); + mpUserKey = userKey.release(); +} + +VDRegistryProviderMemory::~VDRegistryProviderMemory() { + delete mpMachineKey; + delete mpUserKey; +} + +void *VDRegistryProviderMemory::GetMachineKey() { + return mpMachineKey; +} + +void *VDRegistryProviderMemory::GetUserKey() { + return mpUserKey; +} + +void *VDRegistryProviderMemory::CreateKey(void *key0, const char *path, bool write) { + Key *key = (Key *)key0; + + vdsynchronized(mMutex) { + // check for root specifier + if (*path == '\\') { + do { + ++path; + } while(*path == '\\'); + + while(key->mpParent) + key = key->mpParent; + } + + // parse out a component at a time + for(;;) { + const char *split = strchr(path, '\\'); + if (!split) + split = path + strlen(path); + + if (path == split) + break; + + VDStringSpanA component(path, split); + + // lookup component + key = key->OpenKey(component, write); + if (!key) + return NULL; + + // skip path specifier + if (!*split) + break; + + path = split; + do { + ++path; + } while(*path == L'\\'); + } + + key->AddRef(); + } + + return key; +} + +void VDRegistryProviderMemory::CloseKey(void *key0) { + Key *key = (Key *)key0; + + vdsynchronized(mMutex) { + key->Release(); + } +} + +bool VDRegistryProviderMemory::SetBool(void *key0, const char *name, bool v) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetInt(v); + } + return true; +} + +bool VDRegistryProviderMemory::SetInt(void *key0, const char *name, int v) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetInt(v); + } + return true; +} + +bool VDRegistryProviderMemory::SetString(void *key0, const char *name, const char *str) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetString(VDTextAToW(str).c_str()); + } + return true; +} + +bool VDRegistryProviderMemory::SetString(void *key0, const char *name, const wchar_t *str) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetString(str); + } + return true; +} + +bool VDRegistryProviderMemory::SetBinary(void *key0, const char *name, const char *data, int len) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetBinary(data, len); + } + return true; +} + +IVDRegistryProvider::Type VDRegistryProviderMemory::GetType(void *key0, const char *name) { + Type type = kTypeUnknown; + + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (value) { + switch(value->GetType()) { + case Value::kTypeInt: + type = kTypeInt; + break; + + case Value::kTypeString: + type = kTypeString; + break; + + case Value::kTypeBinary: + type = kTypeBinary; + break; + } + } + } + + return type; +} + +bool VDRegistryProviderMemory::GetBool(void *key0, const char *name, bool& val) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + sint32 v32; + if (!value || !value->GetInt(v32)) + return false; + + val = v32 != 0; + } + return true; +} + +bool VDRegistryProviderMemory::GetInt(void *key0, const char *name, int& val) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + sint32 v32; + if (!value || !value->GetInt(v32)) + return false; + + val = v32; + } + return true; +} + +bool VDRegistryProviderMemory::GetString(void *key0, const char *name, VDStringA& s) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + const wchar_t *raws; + if (!value || !value->GetString(raws)) + return false; + + s = VDTextWToA(raws); + } + return true; +} + +bool VDRegistryProviderMemory::GetString(void *key0, const char *name, VDStringW& s) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + const wchar_t *raws; + if (!value || !value->GetString(raws)) + return false; + + s = raws; + } + return true; +} + +int VDRegistryProviderMemory::GetBinaryLength(void *key0, const char *name) { + size_t len; + + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + const void *p; + if (!value || !value->GetBinary(p, len)) + return -1; + } + return len; +} + +bool VDRegistryProviderMemory::GetBinary(void *key0, const char *name, char *buf, int maxlen) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + const void *p; + size_t len; + if (!value || !value->GetBinary(p, len) || (int)len > maxlen) + return false; + + memcpy(buf, p, len); + } + + return true; +} + +bool VDRegistryProviderMemory::RemoveValue(void *key0, const char *name) { + bool success; + + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + + success = key->RemoveValue(name); + } + + return true; +} + +bool VDRegistryProviderMemory::RemoveKey(void *key0, const char *name) { + bool success; + + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + + // if the key is a root key, silently ignore the request + if (!key->mpParent) + return true; + + success = key->RemoveKey(name); + } + + return true; +} + +struct VDRegistryProviderMemory::Enumerator { + Enumerator(Key *key) : mKey(key), mIndex(0) {} + + Key *mKey; + size_t mIndex; + VDStringA mName; +}; + +void *VDRegistryProviderMemory::EnumKeysBegin(void *key) { + return new Enumerator((Key *)key); +} + +const char *VDRegistryProviderMemory::EnumKeysNext(void *enumerator) { + Enumerator *en = (Enumerator *)enumerator; + + vdsynchronized(mMutex) { + const char *s = en->mKey->GetKeyName(en->mIndex); + if (!s) + return NULL; + + ++en->mIndex; + en->mName = s; + } + + return en->mName.c_str(); +} + +void VDRegistryProviderMemory::EnumKeysClose(void *enumerator) { + Enumerator *en = (Enumerator *)enumerator; + + delete en; +} + +void *VDRegistryProviderMemory::EnumValuesBegin(void *key) { + return new Enumerator((Key *)key); +} + +const char *VDRegistryProviderMemory::EnumValuesNext(void *enumerator) { + Enumerator *en = (Enumerator *)enumerator; + + if (!en->mKey) + return NULL; + + vdsynchronized(mMutex) { + const char *s = en->mKey->GetValueName(en->mIndex); + if (!s) + return NULL; + + ++en->mIndex; + en->mName = s; + } + + return en->mName.c_str(); +} + +void VDRegistryProviderMemory::EnumValuesClose(void *enumerator) { + Enumerator *en = (Enumerator *)enumerator; + + delete en; +} diff --git a/src/thirdparty/VirtualDub/h/vd2/system/strutil.h b/src/thirdparty/VirtualDub/h/vd2/system/strutil.h index 89d1f9f3f57..1beb3bb239b 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/strutil.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/strutil.h @@ -1,60 +1,60 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. -#ifndef f_VD2_SYSTEM_STRUTIL_H -#define f_VD2_SYSTEM_STRUTIL_H - -#include -#include - -char *strncpyz(char *strDest, const char *strSource, size_t count); -wchar_t *wcsncpyz(wchar_t *strDest, const wchar_t *strSource, size_t count); -const char *strskipspace(const char *s); - -inline char *strskipspace(char *s) { - return const_cast(strskipspace(s)); -} - -size_t vdstrlcpy(char *dst, const char *src, size_t sizeChars); -size_t vdwcslcpy(wchar_t *dst, const wchar_t *src, size_t sizeChars); - -size_t vdstrlcat(char *dst, const char *src, size_t sizeChars); - -inline int vdstricmp(const char *s, const char *t) { - return _stricmp(s, t); -} - -inline int vdstricmp(const char *s, const char *t, size_t maxlen) { - return _strnicmp(s, t, maxlen); -} - -inline int vdwcsicmp(const wchar_t *s, const wchar_t *t) { - return _wcsicmp(s, t); -} - -inline int vdwcsnicmp(const wchar_t *s, const wchar_t *t, size_t maxlen) { - return _wcsnicmp(s, t, maxlen); -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. +#ifndef f_VD2_SYSTEM_STRUTIL_H +#define f_VD2_SYSTEM_STRUTIL_H + +#include +#include + +char *strncpyz(char *strDest, const char *strSource, size_t count); +wchar_t *wcsncpyz(wchar_t *strDest, const wchar_t *strSource, size_t count); +const char *strskipspace(const char *s); + +inline char *strskipspace(char *s) { + return const_cast(strskipspace(s)); +} + +size_t vdstrlcpy(char *dst, const char *src, size_t sizeChars); +size_t vdwcslcpy(wchar_t *dst, const wchar_t *src, size_t sizeChars); + +size_t vdstrlcat(char *dst, const char *src, size_t sizeChars); + +inline int vdstricmp(const char *s, const char *t) { + return _stricmp(s, t); +} + +inline int vdstricmp(const char *s, const char *t, size_t maxlen) { + return _strnicmp(s, t, maxlen); +} + +inline int vdwcsicmp(const wchar_t *s, const wchar_t *t) { + return _wcsicmp(s, t); +} + +inline int vdwcsnicmp(const wchar_t *s, const wchar_t *t, size_t maxlen) { + return _wcsnicmp(s, t, maxlen); +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/text.h b/src/thirdparty/VirtualDub/h/vd2/system/text.h index bc8ea93f386..b0e4b88e752 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/text.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/text.h @@ -1,60 +1,60 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_TEXT_H -#define f_VD2_SYSTEM_TEXT_H - -#include -#include - -class VDStringA; -class VDStringW; - -// The max_dst value needs to include space for the NULL as well. The number -// of characters produced is returned, minus the null terminator. - -int VDTextWToA(char *dst, int max_dst, const wchar_t *src, int max_src = -1); -int VDTextAToW(wchar_t *dst, int max_dst, const char *src, int max_src = -1); - -VDStringA VDTextWToA(const wchar_t *src, int length = -1); -VDStringA VDTextWToA(const VDStringW& sw); -VDStringW VDTextAToW(const char *src, int length = -1); -VDStringW VDTextAToW(const VDStringA& sw); - -VDStringA VDTextWToU8(const VDStringW& s); -VDStringA VDTextWToU8(const wchar_t *s, int length); -VDStringW VDTextU8ToW(const VDStringA& s); -VDStringW VDTextU8ToW(const char *s, int length); - -// The terminating NULL character is not included in these. - -int VDTextWToALength(const wchar_t *s, int length=-1); -int VDTextAToWLength(const char *s, int length=-1); - -VDStringW VDaswprintf(const wchar_t *format, int args, const void *const *argv); -VDStringW VDvswprintf(const wchar_t *format, int args, va_list val); -VDStringW VDswprintf(const wchar_t *format, int args, ...); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_TEXT_H +#define f_VD2_SYSTEM_TEXT_H + +#include +#include + +class VDStringA; +class VDStringW; + +// The max_dst value needs to include space for the NULL as well. The number +// of characters produced is returned, minus the null terminator. + +int VDTextWToA(char *dst, int max_dst, const wchar_t *src, int max_src = -1); +int VDTextAToW(wchar_t *dst, int max_dst, const char *src, int max_src = -1); + +VDStringA VDTextWToA(const wchar_t *src, int length = -1); +VDStringA VDTextWToA(const VDStringW& sw); +VDStringW VDTextAToW(const char *src, int length = -1); +VDStringW VDTextAToW(const VDStringA& sw); + +VDStringA VDTextWToU8(const VDStringW& s); +VDStringA VDTextWToU8(const wchar_t *s, int length); +VDStringW VDTextU8ToW(const VDStringA& s); +VDStringW VDTextU8ToW(const char *s, int length); + +// The terminating NULL character is not included in these. + +int VDTextWToALength(const wchar_t *s, int length=-1); +int VDTextAToWLength(const char *s, int length=-1); + +VDStringW VDaswprintf(const wchar_t *format, int args, const void *const *argv); +VDStringW VDvswprintf(const wchar_t *format, int args, va_list val); +VDStringW VDswprintf(const wchar_t *format, int args, ...); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/thread.h b/src/thirdparty/VirtualDub/h/vd2/system/thread.h index 2d7d7074bc3..61a016f7230 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/thread.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/thread.h @@ -1,285 +1,285 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_THREAD_H -#define f_VD2_SYSTEM_THREAD_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include - -typedef void *VDThreadHandle; -typedef uint32 VDThreadID; -typedef uint32 VDThreadId; -typedef uint32 VDProcessId; - -#if defined(__MINGW32__) || defined(__MINGW64__) - struct _CRITICAL_SECTION; - typedef _CRITICAL_SECTION VDCriticalSectionW32; -#else - struct _RTL_CRITICAL_SECTION; - typedef _RTL_CRITICAL_SECTION VDCriticalSectionW32; -#endif - -extern "C" void __declspec(dllimport) __stdcall InitializeCriticalSection(VDCriticalSectionW32 *lpCriticalSection); -extern "C" void __declspec(dllimport) __stdcall LeaveCriticalSection(VDCriticalSectionW32 *lpCriticalSection); -extern "C" void __declspec(dllimport) __stdcall EnterCriticalSection(VDCriticalSectionW32 *lpCriticalSection); -extern "C" void __declspec(dllimport) __stdcall DeleteCriticalSection(VDCriticalSectionW32 *lpCriticalSection); -extern "C" unsigned long __declspec(dllimport) __stdcall WaitForSingleObject(void *hHandle, unsigned long dwMilliseconds); -extern "C" int __declspec(dllimport) __stdcall ReleaseSemaphore(void *hSemaphore, long lReleaseCount, long *lpPreviousCount); - -VDThreadID VDGetCurrentThreadID(); -VDProcessId VDGetCurrentProcessId(); -uint32 VDGetLogicalProcessorCount(); - -void VDSetThreadDebugName(VDThreadID tid, const char *name); -void VDThreadSleep(int milliseconds); - -/////////////////////////////////////////////////////////////////////////// -// -// VDThread -// -// VDThread is a quick way to portably create threads -- to use it, -// derive a subclass from it that implements the ThreadRun() function. -// -// Win32 notes: -// -// The thread startup code will attempt to notify the VC++ debugger of -// the debug name of the thread. Only the first 9 characters are used -// by Visual C 6.0; Visual Studio .NET will accept a few dozen. -// -// VDThread objects must not be WaitThread()ed or destructed from a -// DllMain() function, TLS callback for an executable, or static -// destructor unless the thread has been detached from the object. -// The reason is that Win32 serializes calls to DllMain() functions. -// If you attempt to do so, you will cause a deadlock when Win32 -// attempts to fire thread detach notifications. -// -/////////////////////////////////////////////////////////////////////////// - -class VDThread { -public: - enum { - kPriorityDefault = INT_MIN - }; - - VDThread(const char *pszDebugName = NULL); // NOTE: pszDebugName must have static duration - ~VDThread() throw(); - - // external functions - - bool ThreadStart(); // start thread - void ThreadDetach(); // detach thread (wait() won't be called) - void ThreadWait(); // wait for thread to finish - void ThreadSetPriority(int priority); - - bool isThreadActive(); - - bool isThreadAttached() const { // NOTE: Will return true if thread started, even if thread has since exited - return mhThread != 0; - } - - VDThreadHandle getThreadHandle() const { // get handle to thread (Win32: HANDLE) - return mhThread; - } - - VDThreadID getThreadID() const { // get ID of thread (Win32: DWORD) - return mThreadID; - } - - void *ThreadLocation() const; // retrieve current EIP of thread (use only for debug purposes -- may not return reliable information on syscall, etc.) - - // thread-local functions - - virtual void ThreadRun() = 0; // thread, come to life - void ThreadFinish(); // exit thread - -private: - static unsigned __stdcall StaticThreadStart(void *pThis); - - const char *mpszDebugName; - VDThreadHandle mhThread; - VDThreadID mThreadID; - int mThreadPriority; -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDCriticalSection { -private: - struct CritSec { // This is a clone of CRITICAL_SECTION. - void *DebugInfo; - sint32 LockCount; - sint32 RecursionCount; - void *OwningThread; - void *LockSemaphore; - uint32 SpinCount; - } csect; - - VDCriticalSection(const VDCriticalSection&); - const VDCriticalSection& operator=(const VDCriticalSection&); - static void StructCheck(); -public: - class AutoLock { - private: - VDCriticalSection& cs; - public: - AutoLock(VDCriticalSection& csect) : cs(csect) { cs.Lock(); } - ~AutoLock() { cs.Unlock(); } - - inline operator bool() const { return false; } - }; - - VDCriticalSection() { - InitializeCriticalSection((VDCriticalSectionW32 *)&csect); - } - - ~VDCriticalSection() { - DeleteCriticalSection((VDCriticalSectionW32 *)&csect); - } - - void operator++() { - EnterCriticalSection((VDCriticalSectionW32 *)&csect); - } - - void operator--() { - LeaveCriticalSection((VDCriticalSectionW32 *)&csect); - } - - void Lock() { - EnterCriticalSection((VDCriticalSectionW32 *)&csect); - } - - void Unlock() { - LeaveCriticalSection((VDCriticalSectionW32 *)&csect); - } -}; - -// 'vdsynchronized' keyword -// -// The vdsynchronized(lock) keyword emulates Java's 'synchronized' keyword, which -// protects the following statement or block from race conditions by obtaining a -// lock during its execution: -// -// vdsynchronized(list_lock) { -// mList.pop_back(); -// if (mList.empty()) -// return false; -// } -// -// The construct is exception safe and will release the lock even if a return, -// continue, break, or thrown exception exits the block. However, hardware -// exceptions (access violations) may not work due to synchronous model -// exception handling. -// -// There are two Visual C++ bugs we need to work around here (both are in VC6 and VC7). -// -// 1) Declaring an object with a non-trivial destructor in a switch() condition -// causes a C1001 INTERNAL COMPILER ERROR. -// -// 2) Using __LINE__ in a macro expanded in a function with Edit and Continue (/ZI) -// breaks the preprocessor (KB article Q199057). Shame, too, because without it -// all the autolocks look the same. - -#define vdsynchronized2(lock) if(VDCriticalSection::AutoLock vd__lock=(lock))VDNEVERHERE;else -#define vdsynchronized1(lock) vdsynchronized2(lock) -#define vdsynchronized(lock) vdsynchronized1(lock) - -/////////////////////////////////////////////////////////////////////////// - -class VDSignalBase { -protected: - void *hEvent; - -public: - ~VDSignalBase(); - - void signal(); - bool check(); - void wait(); - int wait(VDSignalBase *second); - int wait(VDSignalBase *second, VDSignalBase *third); - static int waitMultiple(const VDSignalBase **signals, int count); - - bool tryWait(uint32 timeoutMillisec); - - void *getHandle() { return hEvent; } - - void operator()() { signal(); } -}; - -class VDSignal : public VDSignalBase { - VDSignal(const VDSignal&); - VDSignal& operator=(const VDSignal&); -public: - VDSignal(); -}; - -class VDSignalPersistent : public VDSignalBase { - VDSignalPersistent(const VDSignalPersistent&); - VDSignalPersistent& operator=(const VDSignalPersistent&); -public: - VDSignalPersistent(); - - void unsignal(); -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDSemaphore { -public: - VDSemaphore(int initial); - ~VDSemaphore(); - - void *GetHandle() const { - return mKernelSema; - } - - void Reset(int count); - - void Wait() { - WaitForSingleObject(mKernelSema, 0xFFFFFFFFU); - } - - bool Wait(int timeout) { - return 0 == WaitForSingleObject(mKernelSema, timeout); - } - - bool TryWait() { - return 0 == WaitForSingleObject(mKernelSema, 0); - } - - void Post() { - ReleaseSemaphore(mKernelSema, 1, NULL); - } - -private: - void *mKernelSema; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_THREAD_H +#define f_VD2_SYSTEM_THREAD_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include + +typedef void *VDThreadHandle; +typedef uint32 VDThreadID; +typedef uint32 VDThreadId; +typedef uint32 VDProcessId; + +#if defined(__MINGW32__) || defined(__MINGW64__) + struct _CRITICAL_SECTION; + typedef _CRITICAL_SECTION VDCriticalSectionW32; +#else + struct _RTL_CRITICAL_SECTION; + typedef _RTL_CRITICAL_SECTION VDCriticalSectionW32; +#endif + +extern "C" void __declspec(dllimport) __stdcall InitializeCriticalSection(VDCriticalSectionW32 *lpCriticalSection); +extern "C" void __declspec(dllimport) __stdcall LeaveCriticalSection(VDCriticalSectionW32 *lpCriticalSection); +extern "C" void __declspec(dllimport) __stdcall EnterCriticalSection(VDCriticalSectionW32 *lpCriticalSection); +extern "C" void __declspec(dllimport) __stdcall DeleteCriticalSection(VDCriticalSectionW32 *lpCriticalSection); +extern "C" unsigned long __declspec(dllimport) __stdcall WaitForSingleObject(void *hHandle, unsigned long dwMilliseconds); +extern "C" int __declspec(dllimport) __stdcall ReleaseSemaphore(void *hSemaphore, long lReleaseCount, long *lpPreviousCount); + +VDThreadID VDGetCurrentThreadID(); +VDProcessId VDGetCurrentProcessId(); +uint32 VDGetLogicalProcessorCount(); + +void VDSetThreadDebugName(VDThreadID tid, const char *name); +void VDThreadSleep(int milliseconds); + +/////////////////////////////////////////////////////////////////////////// +// +// VDThread +// +// VDThread is a quick way to portably create threads -- to use it, +// derive a subclass from it that implements the ThreadRun() function. +// +// Win32 notes: +// +// The thread startup code will attempt to notify the VC++ debugger of +// the debug name of the thread. Only the first 9 characters are used +// by Visual C 6.0; Visual Studio .NET will accept a few dozen. +// +// VDThread objects must not be WaitThread()ed or destructed from a +// DllMain() function, TLS callback for an executable, or static +// destructor unless the thread has been detached from the object. +// The reason is that Win32 serializes calls to DllMain() functions. +// If you attempt to do so, you will cause a deadlock when Win32 +// attempts to fire thread detach notifications. +// +/////////////////////////////////////////////////////////////////////////// + +class VDThread { +public: + enum { + kPriorityDefault = INT_MIN + }; + + VDThread(const char *pszDebugName = NULL); // NOTE: pszDebugName must have static duration + ~VDThread() throw(); + + // external functions + + bool ThreadStart(); // start thread + void ThreadDetach(); // detach thread (wait() won't be called) + void ThreadWait(); // wait for thread to finish + void ThreadSetPriority(int priority); + + bool isThreadActive(); + + bool isThreadAttached() const { // NOTE: Will return true if thread started, even if thread has since exited + return mhThread != 0; + } + + VDThreadHandle getThreadHandle() const { // get handle to thread (Win32: HANDLE) + return mhThread; + } + + VDThreadID getThreadID() const { // get ID of thread (Win32: DWORD) + return mThreadID; + } + + void *ThreadLocation() const; // retrieve current EIP of thread (use only for debug purposes -- may not return reliable information on syscall, etc.) + + // thread-local functions + + virtual void ThreadRun() = 0; // thread, come to life + void ThreadFinish(); // exit thread + +private: + static unsigned __stdcall StaticThreadStart(void *pThis); + + const char *mpszDebugName; + VDThreadHandle mhThread; + VDThreadID mThreadID; + int mThreadPriority; +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDCriticalSection { +private: + struct CritSec { // This is a clone of CRITICAL_SECTION. + void *DebugInfo; + sint32 LockCount; + sint32 RecursionCount; + void *OwningThread; + void *LockSemaphore; + uint32 SpinCount; + } csect; + + VDCriticalSection(const VDCriticalSection&); + const VDCriticalSection& operator=(const VDCriticalSection&); + static void StructCheck(); +public: + class AutoLock { + private: + VDCriticalSection& cs; + public: + AutoLock(VDCriticalSection& csect) : cs(csect) { cs.Lock(); } + ~AutoLock() { cs.Unlock(); } + + inline operator bool() const { return false; } + }; + + VDCriticalSection() { + InitializeCriticalSection((VDCriticalSectionW32 *)&csect); + } + + ~VDCriticalSection() { + DeleteCriticalSection((VDCriticalSectionW32 *)&csect); + } + + void operator++() { + EnterCriticalSection((VDCriticalSectionW32 *)&csect); + } + + void operator--() { + LeaveCriticalSection((VDCriticalSectionW32 *)&csect); + } + + void Lock() { + EnterCriticalSection((VDCriticalSectionW32 *)&csect); + } + + void Unlock() { + LeaveCriticalSection((VDCriticalSectionW32 *)&csect); + } +}; + +// 'vdsynchronized' keyword +// +// The vdsynchronized(lock) keyword emulates Java's 'synchronized' keyword, which +// protects the following statement or block from race conditions by obtaining a +// lock during its execution: +// +// vdsynchronized(list_lock) { +// mList.pop_back(); +// if (mList.empty()) +// return false; +// } +// +// The construct is exception safe and will release the lock even if a return, +// continue, break, or thrown exception exits the block. However, hardware +// exceptions (access violations) may not work due to synchronous model +// exception handling. +// +// There are two Visual C++ bugs we need to work around here (both are in VC6 and VC7). +// +// 1) Declaring an object with a non-trivial destructor in a switch() condition +// causes a C1001 INTERNAL COMPILER ERROR. +// +// 2) Using __LINE__ in a macro expanded in a function with Edit and Continue (/ZI) +// breaks the preprocessor (KB article Q199057). Shame, too, because without it +// all the autolocks look the same. + +#define vdsynchronized2(lock) if(VDCriticalSection::AutoLock vd__lock=(lock))VDNEVERHERE;else +#define vdsynchronized1(lock) vdsynchronized2(lock) +#define vdsynchronized(lock) vdsynchronized1(lock) + +/////////////////////////////////////////////////////////////////////////// + +class VDSignalBase { +protected: + void *hEvent; + +public: + ~VDSignalBase(); + + void signal(); + bool check(); + void wait(); + int wait(VDSignalBase *second); + int wait(VDSignalBase *second, VDSignalBase *third); + static int waitMultiple(const VDSignalBase **signals, int count); + + bool tryWait(uint32 timeoutMillisec); + + void *getHandle() { return hEvent; } + + void operator()() { signal(); } +}; + +class VDSignal : public VDSignalBase { + VDSignal(const VDSignal&); + VDSignal& operator=(const VDSignal&); +public: + VDSignal(); +}; + +class VDSignalPersistent : public VDSignalBase { + VDSignalPersistent(const VDSignalPersistent&); + VDSignalPersistent& operator=(const VDSignalPersistent&); +public: + VDSignalPersistent(); + + void unsignal(); +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDSemaphore { +public: + VDSemaphore(int initial); + ~VDSemaphore(); + + void *GetHandle() const { + return mKernelSema; + } + + void Reset(int count); + + void Wait() { + WaitForSingleObject(mKernelSema, 0xFFFFFFFFU); + } + + bool Wait(int timeout) { + return 0 == WaitForSingleObject(mKernelSema, timeout); + } + + bool TryWait() { + return 0 == WaitForSingleObject(mKernelSema, 0); + } + + void Post() { + ReleaseSemaphore(mKernelSema, 1, NULL); + } + +private: + void *mKernelSema; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/thunk.h b/src/thirdparty/VirtualDub/h/vd2/system/thunk.h index cf92407acd2..3e1b2e1b856 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/thunk.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/thunk.h @@ -1,76 +1,76 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_THUNK_H -#define f_VD2_SYSTEM_THUNK_H - -#ifdef _MSC_VER - #pragma once -#endif - -bool VDInitThunkAllocator(); -void VDShutdownThunkAllocator(); - -void *VDAllocateThunkMemory(size_t len); -void VDFreeThunkMemory(void *p, size_t len); -void VDSetThunkMemory(void *p, const void *src, size_t len); -void VDFlushThunkMemory(void *p, size_t len); - -class VDFunctionThunk; - -VDFunctionThunk *VDCreateFunctionThunkFromMethod(void *method, void *pThis, size_t argbytes, bool stdcall_thunk); -void VDDestroyFunctionThunk(VDFunctionThunk *pFnThunk); - -/////////////////////////////////////////////////////////////////////////////// - -template struct VDMetaSizeofArg { enum { value = (sizeof(T) + sizeof(void *) - 1) & ~(sizeof(void *) - 1) }; }; - -// This doesn't work for references. Sadly, these seem to get stripped during template matching. -template -char (&VDMetaGetMethodArgBytes(R (T::*method)()))[1]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1)))[1 + VDMetaSizeofArg::value]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3, A4)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3, A4)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; - -/////////////////////////////////////////////////////////////////////////////// - -template -VDFunctionThunk *VDCreateFunctionThunkFromMethod(T *pThis, T_Method method, bool stdcall_thunk) { - return VDCreateFunctionThunkFromMethod(*(void **)&method, pThis, sizeof VDMetaGetMethodArgBytes(method) - 1, stdcall_thunk); -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_THUNK_H +#define f_VD2_SYSTEM_THUNK_H + +#ifdef _MSC_VER + #pragma once +#endif + +bool VDInitThunkAllocator(); +void VDShutdownThunkAllocator(); + +void *VDAllocateThunkMemory(size_t len); +void VDFreeThunkMemory(void *p, size_t len); +void VDSetThunkMemory(void *p, const void *src, size_t len); +void VDFlushThunkMemory(void *p, size_t len); + +class VDFunctionThunk; + +VDFunctionThunk *VDCreateFunctionThunkFromMethod(void *method, void *pThis, size_t argbytes, bool stdcall_thunk); +void VDDestroyFunctionThunk(VDFunctionThunk *pFnThunk); + +/////////////////////////////////////////////////////////////////////////////// + +template struct VDMetaSizeofArg { enum { value = (sizeof(T) + sizeof(void *) - 1) & ~(sizeof(void *) - 1) }; }; + +// This doesn't work for references. Sadly, these seem to get stripped during template matching. +template +char (&VDMetaGetMethodArgBytes(R (T::*method)()))[1]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1)))[1 + VDMetaSizeofArg::value]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3, A4)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3, A4)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; + +/////////////////////////////////////////////////////////////////////////////// + +template +VDFunctionThunk *VDCreateFunctionThunkFromMethod(T *pThis, T_Method method, bool stdcall_thunk) { + return VDCreateFunctionThunkFromMethod(*(void **)&method, pThis, sizeof VDMetaGetMethodArgBytes(method) - 1, stdcall_thunk); +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/tls.h b/src/thirdparty/VirtualDub/h/vd2/system/tls.h index 2cd2ecc70e1..87b44643692 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/tls.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/tls.h @@ -1,38 +1,38 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_SYSTEM_TLS_H -#define f_SYSTEM_TLS_H - -#include - -void VDInitThreadData(const char *pszThreadName); -void VDDeinitThreadData(); - -typedef void (*VDThreadInitHook)(bool init, const char *threadName); - -void VDSetThreadInitHook(VDThreadInitHook pHook); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_SYSTEM_TLS_H +#define f_SYSTEM_TLS_H + +#include + +void VDInitThreadData(const char *pszThreadName); +void VDDeinitThreadData(); + +typedef void (*VDThreadInitHook)(bool init, const char *threadName); + +void VDSetThreadInitHook(VDThreadInitHook pHook); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/unknown.h b/src/thirdparty/VirtualDub/h/vd2/system/unknown.h index 1a3efb71b79..69b008864e6 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/unknown.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/unknown.h @@ -1,77 +1,77 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_UNKNOWN_H -#define f_VD2_SYSTEM_UNKNOWN_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -/////////////////////////////////////////////////////////////////////////// -// IVDUnknown -/// Base interface for runtime type discovery. -class IVDUnknown { -public: - /// Attempt to cast to another type. Returns NULL if interface is unsupported. - virtual void *AsInterface(uint32 id) = 0; - - inline const void *AsInterface(uint32 id) const { - return const_cast(this)->AsInterface(id); - } -}; - -/////////////////////////////////////////////////////////////////////////// -// IVDUnknown -/// Base interface for runtime type discovery with reference counting. -class IVDRefUnknown : public IVDUnknown { -public: - virtual int AddRef() = 0; ///< Add strong reference to object. Returns new reference count (debug builds only). - virtual int Release() = 0; ///< Remove strong refence from object, and destroy it if the refcount drops to zero. Returns zero if object was destroyed. -}; - -template -inline uint32 vdpoly_id_from_ptr(T *p) { - return T::kTypeID; -} - -/////////////////////////////////////////////////////////////////////////// -// vdpoly_cast -/// Performs a runtime polymorphic cast on an IUnknown-based object. -/// -/// \param pUnk Pointer to cast. May be NULL. -/// -/// Attempts to cast a pointer to a different type using the -/// \c AsInterface() method. The destination type must support the -/// \c kTypeID convention for returning the type ID. -/// -template -T vdpoly_cast(IVDUnknown *pUnk) { - return pUnk ? (T)pUnk->AsInterface(vdpoly_id_from_ptr(T(NULL))) : NULL; -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_UNKNOWN_H +#define f_VD2_SYSTEM_UNKNOWN_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +/////////////////////////////////////////////////////////////////////////// +// IVDUnknown +/// Base interface for runtime type discovery. +class IVDUnknown { +public: + /// Attempt to cast to another type. Returns NULL if interface is unsupported. + virtual void *AsInterface(uint32 id) = 0; + + inline const void *AsInterface(uint32 id) const { + return const_cast(this)->AsInterface(id); + } +}; + +/////////////////////////////////////////////////////////////////////////// +// IVDUnknown +/// Base interface for runtime type discovery with reference counting. +class IVDRefUnknown : public IVDUnknown { +public: + virtual int AddRef() = 0; ///< Add strong reference to object. Returns new reference count (debug builds only). + virtual int Release() = 0; ///< Remove strong refence from object, and destroy it if the refcount drops to zero. Returns zero if object was destroyed. +}; + +template +inline uint32 vdpoly_id_from_ptr(T *p) { + return T::kTypeID; +} + +/////////////////////////////////////////////////////////////////////////// +// vdpoly_cast +/// Performs a runtime polymorphic cast on an IUnknown-based object. +/// +/// \param pUnk Pointer to cast. May be NULL. +/// +/// Attempts to cast a pointer to a different type using the +/// \c AsInterface() method. The destination type must support the +/// \c kTypeID convention for returning the type ID. +/// +template +T vdpoly_cast(IVDUnknown *pUnk) { + return pUnk ? (T)pUnk->AsInterface(vdpoly_id_from_ptr(T(NULL))) : NULL; +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdalloc.h b/src/thirdparty/VirtualDub/h/vd2/system/vdalloc.h index ad866ebfa6b..3dab889a498 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdalloc.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdalloc.h @@ -1,190 +1,190 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDALLOC_H -#define f_VD2_SYSTEM_VDALLOC_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -// Why don't I use STL auto_ptr? Two reasons. First, auto_ptr has -// the overhead of an ownership flag, and second, auto_ptr can't -// be used with malloc() blocks. So think of these as auto_ptr -// objects, but not quite.... - -#pragma warning(push) -#pragma warning(disable: 4284) // operator-> must return pointer to UDT - -class vdautoblockptr { -protected: - void *ptr; - -public: - explicit vdautoblockptr(void *p = 0) : ptr(p) {} - ~vdautoblockptr() { free(ptr); } - - vdautoblockptr& operator=(void *src) { free(ptr); ptr = src; return *this; } - - operator void*() const { return ptr; } - - void from(vdautoblockptr& src) { free(ptr); ptr=src.ptr; src.ptr=0; } - void *get() const { return ptr; } - void *release() { void *v = ptr; ptr = NULL; return v; } -}; - -template class vdautoptr2 { -protected: - T *ptr; - -public: - explicit vdautoptr2(T *p = 0) : ptr(p) {} - ~vdautoptr2() { free((void *)ptr); } - - vdautoptr2& operator=(T *src) { free((void *)ptr); ptr = src; return *this; } - - operator T*() const { return ptr; } - T& operator*() const { return *ptr; } - T *operator->() const { return ptr; } - - vdautoptr2& from(vdautoptr2& src) { free((void *)ptr); ptr=src.ptr; src.ptr=0; } - T *get() const { return ptr; } - T *release() { T *v = ptr; ptr = NULL; return v; } -}; - -template class vdautoptr { -protected: - T *ptr; - -public: - explicit vdautoptr(T *p = 0) : ptr(p) {} - ~vdautoptr() { delete ptr; } - - vdautoptr& operator=(T *src) { delete ptr; ptr = src; return *this; } - - operator T*() const { return ptr; } - T& operator*() const { return *ptr; } - T *operator->() const { return ptr; } - - T** operator~() { - if (ptr) { - delete ptr; - ptr = NULL; - } - - return &ptr; - } - - void from(vdautoptr& src) { delete ptr; ptr=src.ptr; src.ptr=0; } - T *get() const { return ptr; } - T *release() { T *v = ptr; ptr = NULL; return v; } - - void reset() { - if (ptr) { - delete ptr; - ptr = NULL; - } - } - - void swap(vdautoptr& other) { - T *p = other.ptr; - other.ptr = ptr; - ptr = p; - } -}; - -template class vdautoarrayptr { -protected: - T *ptr; - -public: - explicit vdautoarrayptr(T *p = 0) : ptr(p) {} - ~vdautoarrayptr() { delete[] ptr; } - - vdautoarrayptr& operator=(T *src) { delete[] ptr; ptr = src; return *this; } - - T& operator[](int offset) const { return ptr[offset]; } - - void from(vdautoarrayptr& src) { delete[] ptr; ptr=src.ptr; src.ptr=0; } - T *get() const { return ptr; } - T *release() { T *v = ptr; ptr = NULL; return v; } -}; - -/////////////////////////////////////////////////////////////////////////// - -struct vdsafedelete_t {}; -extern vdsafedelete_t vdsafedelete; - -template -inline vdsafedelete_t& operator<<=(vdsafedelete_t& x, T *& p) { - if (p) { - delete p; - p = 0; - } - - return x; -} - -template -inline vdsafedelete_t& operator,(vdsafedelete_t& x, T *& p) { - if (p) { - delete p; - p = 0; - } - - return x; -} - -template -inline vdsafedelete_t& operator<<=(vdsafedelete_t& x, T *(&p)[N]) { - for(size_t i=0; i -inline vdsafedelete_t& operator,(vdsafedelete_t& x, T *(&p)[N]) { - for(size_t i=0; i + +// Why don't I use STL auto_ptr? Two reasons. First, auto_ptr has +// the overhead of an ownership flag, and second, auto_ptr can't +// be used with malloc() blocks. So think of these as auto_ptr +// objects, but not quite.... + +#pragma warning(push) +#pragma warning(disable: 4284) // operator-> must return pointer to UDT + +class vdautoblockptr { +protected: + void *ptr; + +public: + explicit vdautoblockptr(void *p = 0) : ptr(p) {} + ~vdautoblockptr() { free(ptr); } + + vdautoblockptr& operator=(void *src) { free(ptr); ptr = src; return *this; } + + operator void*() const { return ptr; } + + void from(vdautoblockptr& src) { free(ptr); ptr=src.ptr; src.ptr=0; } + void *get() const { return ptr; } + void *release() { void *v = ptr; ptr = NULL; return v; } +}; + +template class vdautoptr2 { +protected: + T *ptr; + +public: + explicit vdautoptr2(T *p = 0) : ptr(p) {} + ~vdautoptr2() { free((void *)ptr); } + + vdautoptr2& operator=(T *src) { free((void *)ptr); ptr = src; return *this; } + + operator T*() const { return ptr; } + T& operator*() const { return *ptr; } + T *operator->() const { return ptr; } + + vdautoptr2& from(vdautoptr2& src) { free((void *)ptr); ptr=src.ptr; src.ptr=0; } + T *get() const { return ptr; } + T *release() { T *v = ptr; ptr = NULL; return v; } +}; + +template class vdautoptr { +protected: + T *ptr; + +public: + explicit vdautoptr(T *p = 0) : ptr(p) {} + ~vdautoptr() { delete ptr; } + + vdautoptr& operator=(T *src) { delete ptr; ptr = src; return *this; } + + operator T*() const { return ptr; } + T& operator*() const { return *ptr; } + T *operator->() const { return ptr; } + + T** operator~() { + if (ptr) { + delete ptr; + ptr = NULL; + } + + return &ptr; + } + + void from(vdautoptr& src) { delete ptr; ptr=src.ptr; src.ptr=0; } + T *get() const { return ptr; } + T *release() { T *v = ptr; ptr = NULL; return v; } + + void reset() { + if (ptr) { + delete ptr; + ptr = NULL; + } + } + + void swap(vdautoptr& other) { + T *p = other.ptr; + other.ptr = ptr; + ptr = p; + } +}; + +template class vdautoarrayptr { +protected: + T *ptr; + +public: + explicit vdautoarrayptr(T *p = 0) : ptr(p) {} + ~vdautoarrayptr() { delete[] ptr; } + + vdautoarrayptr& operator=(T *src) { delete[] ptr; ptr = src; return *this; } + + T& operator[](int offset) const { return ptr[offset]; } + + void from(vdautoarrayptr& src) { delete[] ptr; ptr=src.ptr; src.ptr=0; } + T *get() const { return ptr; } + T *release() { T *v = ptr; ptr = NULL; return v; } +}; + +/////////////////////////////////////////////////////////////////////////// + +struct vdsafedelete_t {}; +extern vdsafedelete_t vdsafedelete; + +template +inline vdsafedelete_t& operator<<=(vdsafedelete_t& x, T *& p) { + if (p) { + delete p; + p = 0; + } + + return x; +} + +template +inline vdsafedelete_t& operator,(vdsafedelete_t& x, T *& p) { + if (p) { + delete p; + p = 0; + } + + return x; +} + +template +inline vdsafedelete_t& operator<<=(vdsafedelete_t& x, T *(&p)[N]) { + for(size_t i=0; i +inline vdsafedelete_t& operator,(vdsafedelete_t& x, T *(&p)[N]) { + for(size_t i=0; i -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// -// glue -// -/////////////////////////////////////////////////////////////////////////// - -template -struct vdreverse_iterator { -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1310 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) - typedef std::reverse_iterator type; -#else - typedef std::reverse_iterator type; -#endif -}; - -/////////////////////////////////////////////////////////////////////////// - -struct vdfalse_type { }; -struct vdtrue_type { }; - -struct vdfalse_result { typedef vdfalse_type result; }; -struct vdtrue_result { typedef vdtrue_type result; }; - -template void vdmove(T& dst, T& src); -template struct vdmove_capable : public vdfalse_result {}; - -template -T *vdmove_forward_impl(T *src1, T *src2, T *dst, vdfalse_type) { - T *p = src1; - while(p != src2) { - *dst = *p; - ++dst; - ++p; - } - - return dst; -} - -template -T *vdmove_backward_impl(T *src1, T *src2, T *dst, vdfalse_type) { - T *p = src2; - while(p != src1) { - --dst; - --p; - *dst = *p; - } - - return dst; -} - -template -T *vdmove_forward_impl(T *src1, T *src2, T *dst, vdtrue_type) { - T *p = src1; - while(p != src2) { - vdmove(*dst, *p); - ++dst; - ++p; - } - - return dst; -} - -template -T *vdmove_backward_impl(T *src1, T *src2, T *dst, vdtrue_type) { - T *p = src2; - while(p != src1) { - --dst; - --p; - vdmove(*dst, *p); - } - - return dst; -} - -template -T *vdmove_forward(T *src1, T *src2, T *dst) { - return vdmove_forward_impl(src1, src2, dst, vdmove_capable::result()); -} - -template -T *vdmove_backward(T *src1, T *src2, T *dst) { - return vdmove_backward_impl(src1, src2, dst, vdmove_capable::result()); -} - -#define VDMOVE_CAPABLE(type) \ - template<> struct vdmove_capable : public vdtrue_result {}; \ - template<> void vdmove(type& dst, type& src) - -/////////////////////////////////////////////////////////////////////////// - -template char (&VDCountOfHelper(const T(&)[N]))[N]; - -#define vdcountof(array) (sizeof(VDCountOfHelper(array))) - -/////////////////////////////////////////////////////////////////////////// - -class vdallocator_base { -protected: - void VDNORETURN throw_oom(size_t n, size_t elsize); -}; - -template -class vdallocator : public vdallocator_base { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template struct rebind { typedef vdallocator other; }; - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, void *p_close = 0) { - if (n > ((~(size_type)0) >> 1) / sizeof(T)) - throw_oom(n, sizeof(T)); - - pointer p = (pointer)malloc(n*sizeof(T)); - - if (!p) - throw_oom(n, sizeof(T)); - - return p; - } - - void deallocate(pointer p, size_type n) { - free(p); - } - - size_type max_size() const throw() { return ((~(size_type)0) >> 1) / sizeof(T); } - - void construct(pointer p, const T& val) { new((void *)p) T(val); } - void destroy(pointer p) { ((T*)p)->~T(); } - -#if defined(_MSC_VER) && _MSC_VER < 1300 - char * _Charalloc(size_type n) { return rebind::other::allocate(n); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////// - -template -class vddebug_alloc { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template struct rebind { typedef vddebug_alloc other; }; - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, void *p_close = 0) { - pointer p = (pointer)VDAlignedMalloc(n*sizeof(T) + 2*kDeadZone, 16); - - if (!p) - return p; - - memset((char *)p, 0xa9, kDeadZone); - memset((char *)p + kDeadZone + n*sizeof(T), 0xa9, kDeadZone); - - return (pointer)((char *)p + kDeadZone); - } - - void deallocate(pointer p, size_type n) { - char *p1 = (char *)p - kDeadZone; - char *p2 = (char *)p + n*sizeof(T); - - for(uint32 i=0; i~T(); } - -#if defined(_MSC_VER) && _MSC_VER < 1300 - char * _Charalloc(size_type n) { return rebind::other::allocate(n); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////// - -template -class vdaligned_alloc { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - vdaligned_alloc() {} - - template - vdaligned_alloc(const vdaligned_alloc&) {} - - template struct rebind { typedef vdaligned_alloc other; }; - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, void *p = 0) { return (pointer)VDAlignedMalloc(n*sizeof(T), kAlignment); } - void deallocate(pointer p, size_type n) { VDAlignedFree(p); } - size_type max_size() const throw() { return INT_MAX; } - - void construct(pointer p, const T& val) { new((void *)p) T(val); } - void destroy(pointer p) { ((T*)p)->~T(); } - -#if defined(_MSC_VER) && _MSC_VER < 1300 - char * _Charalloc(size_type n) { return rebind::other::allocate(n); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////// -// -// vdblock -// -// vdblock is similar to vector, except: -// -// 1) May only be used with POD types. -// 2) No construction or destruction of elements is performed. -// 3) Capacity is always equal to size, and reallocation is performed -// whenever the size changes. -// 4) Contents are undefined after a reallocation. -// 5) No insertion or deletion operations are provided. -// -/////////////////////////////////////////////////////////////////////////// - -template > -class vdblock : protected A { -public: - typedef T value_type; - typedef typename A::pointer pointer; - typedef typename A::const_pointer const_pointer; - typedef typename A::reference reference; - typedef typename A::const_reference const_reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef pointer iterator; - typedef const_pointer const_iterator; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - vdblock(const A& alloc = A()) : A(alloc), mpBlock(NULL), mSize(0) {} - vdblock(size_type s, const A& alloc = A()) : A(alloc), mpBlock(A::allocate(s, 0)), mSize(s) {} - ~vdblock() { - if (mpBlock) - A::deallocate(mpBlock, mSize); - } - - reference operator[](size_type n) { return mpBlock[n]; } - const_reference operator[](size_type n) const { return mpBlock[n]; } - reference at(size_type n) { return n < mSize ? mpBlock[n] : throw std::length_error("n"); } - const_reference at(size_type n) const { return n < mSize ? mpBlock[n] : throw std::length_error("n"); } - reference front() { return *mpBlock; } - const_reference front() const { return *mpBlock; } - reference back() { return mpBlock[mSize-1]; } - const_reference back() const { return mpBlock[mSize-1]; } - - const_pointer data() const { return mpBlock; } - pointer data() { return mpBlock; } - - const_iterator begin() const { return mpBlock; } - iterator begin() { return mpBlock; } - const_iterator end() const { return mpBlock + mSize; } - iterator end() { return mpBlock + mSize; } - - const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } - reverse_iterator rbegin() { return reverse_iterator(end()); } - const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - - bool empty() const { return !mSize; } - size_type size() const { return mSize; } - size_type capacity() const { return mSize; } - - void clear() { - if (mpBlock) - A::deallocate(mpBlock, mSize); - mpBlock = NULL; - mSize = 0; - } - - void resize(size_type s) { - if (s != mSize) { - if (mpBlock) { - A::deallocate(mpBlock, mSize); - mpBlock = NULL; - mSize = 0; - } - if (s) - mpBlock = A::allocate(s, 0); - mSize = s; - } - } - - void resize(size_type s, const T& value) { - if (s != mSize) { - if (mpBlock) { - A::deallocate(mpBlock, mSize); - mpBlock = NULL; - mSize = 0; - } - if (s) { - mpBlock = A::allocate(s, 0); - std::fill(mpBlock, mpBlock+s, value); - } - mSize = s; - } - } - - void swap(vdblock& x) { - std::swap(mpBlock, x.mpBlock); - std::swap(mSize, x.mSize); - } - -protected: - typename A::pointer mpBlock; - typename A::size_type mSize; - - union PODType { - T x; - }; -}; - -/////////////////////////////////////////////////////////////////////////// -// -// vdstructex -// -// vdstructex describes an extensible format structure, such as -// BITMAPINFOHEADER or WAVEFORMATEX, without the pain-in-the-butt -// casting normally associated with one. -// -/////////////////////////////////////////////////////////////////////////// - -template -class vdstructex { -public: - typedef size_t size_type; - typedef T value_type; - - vdstructex() : mpMemory(NULL), mSize(0) {} - - explicit vdstructex(size_t len) : mpMemory(NULL), mSize(0) { - resize(len); - } - - vdstructex(const T *pStruct, size_t len) : mSize(len), mpMemory((T*)malloc(len)) { - memcpy(mpMemory, pStruct, len); - } - - vdstructex(const vdstructex& src) : mSize(src.mSize), mpMemory((T*)malloc(src.mSize)) { - memcpy(mpMemory, src.mpMemory, mSize); - } - - ~vdstructex() { - free(mpMemory); - } - - bool empty() const { return !mpMemory; } - size_type size() const { return mSize; } - T* data() const { return mpMemory; } - - T& operator *() const { return *(T *)mpMemory; } - T* operator->() const { return (T *)mpMemory; } - - bool operator==(const vdstructex& x) const { - return mSize == x.mSize && (!mSize || !memcmp(mpMemory, x.mpMemory, mSize)); - } - - bool operator!=(const vdstructex& x) const { - return mSize != x.mSize || (mSize && memcmp(mpMemory, x.mpMemory, mSize)); - } - - vdstructex& operator=(const vdstructex& src) { - assign(src.mpMemory, src.mSize); - return *this; - } - - void assign(const T *pStruct, size_type len) { - if (mSize != len) - resize(len); - - memcpy(mpMemory, pStruct, len); - } - - void clear() { - free(mpMemory); - mpMemory = NULL; - mSize = 0; - } - - void resize(size_type len) { - if (mSize != len) - mpMemory = (T *)realloc(mpMemory, mSize = len); - } - -protected: - size_type mSize; - T *mpMemory; -}; - -/////////////////////////////////////////////////////////////////////////// -// -// vdlist -// -// vdlist is similar to list, except: -// -// 1) The node structure must be embedded as a superclass of T. -// Thus, the client is in full control of allocation. -// 2) Node pointers may be converted back into iterators in O(1). -// -/////////////////////////////////////////////////////////////////////////// - -struct vdlist_node { - vdlist_node *mListNodeNext, *mListNodePrev; -}; - -template -class vdlist_iterator { -public: - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef T *pointer_type; - typedef T& reference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - vdlist_iterator() {} - vdlist_iterator(T *p) : mp(p) {} - vdlist_iterator(const vdlist_iterator& src) : mp(src.mp) {} - - T* operator *() const { - return static_cast(mp); - } - - bool operator==(const vdlist_iterator& x) const { - return mp == x.mp; - } - - bool operator!=(const vdlist_iterator& x) const { - return mp != x.mp; - } - - vdlist_iterator& operator++() { - mp = mp->mListNodeNext; - return *this; - } - - vdlist_iterator& operator--() { - mp = mp->mListNodePrev; - return *this; - } - - vdlist_iterator operator++(int) { - vdlist_iterator tmp(*this); - mp = mp->mListNodeNext; - return tmp; - } - - vdlist_iterator& operator--(int) { - vdlist_iterator tmp(*this); - mp = mp->mListNodePrev; - return tmp; - } - - vdlist_node *mp; -}; - -class vdlist_base { -public: - typedef vdlist_node node; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - bool empty() const { - return mAnchor.mListNodeNext == &mAnchor; - } - - size_type size() const { - node *p = { mAnchor.mListNodeNext }; - size_type s = 0; - - if (p != &mAnchor) - do { - ++s; - p = p->mListNodeNext; - } while(p != &mAnchor); - - return s; - } - - void clear() { - mAnchor.mListNodePrev = &mAnchor; - mAnchor.mListNodeNext = &mAnchor; - } - - void pop_front() { - mAnchor.mListNodeNext = mAnchor.mListNodeNext->mListNodeNext; - mAnchor.mListNodeNext->mListNodePrev = &mAnchor; - } - - void pop_back() { - mAnchor.mListNodePrev = mAnchor.mListNodePrev->mListNodePrev; - mAnchor.mListNodePrev->mListNodeNext = &mAnchor; - } - - static void unlink(vdlist_node& node) { - vdlist_node& n1 = *node.mListNodePrev; - vdlist_node& n2 = *node.mListNodeNext; - - n1.mListNodeNext = &n2; - n2.mListNodePrev = &n1; - } - -protected: - node mAnchor; -}; - -template -class vdlist : public vdlist_base { -public: - typedef T* value_type; - typedef T** pointer; - typedef const T** const_pointer; - typedef T*& reference; - typedef const T*& const_reference; - typedef vdlist_iterator iterator; - typedef vdlist_iterator const_iterator; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - vdlist() { - mAnchor.mListNodePrev = &mAnchor; - mAnchor.mListNodeNext = &mAnchor; - } - - iterator begin() { - iterator it; - it.mp = mAnchor.mListNodeNext; - return it; - } - - const_iterator begin() const { - const_iterator it; - it.mp = mAnchor.mListNodeNext; - return it; - } - - iterator end() { - iterator it; - it.mp = &mAnchor; - return it; - } - - const_iterator end() const { - const_iterator it; - it.mp = &mAnchor; - return it; - } - - reverse_iterator rbegin() { - return reverse_iterator(begin()); - } - - const_reverse_iterator rbegin() const { - return const_reverse_iterator(begin()); - } - - reverse_iterator rend() { - return reverse_iterator(end); - } - - const_reverse_iterator rend() const { - return const_reverse_iterator(end()); - } - - const value_type front() const { - return static_cast(mAnchor.mListNodeNext); - } - - const value_type back() const { - return static_cast(mAnchor.mListNodePrev); - } - - iterator find(T *p) { - iterator it; - it.mp = mAnchor.mListNodeNext; - - if (it.mp != &mAnchor) - do { - if (it.mp == static_cast(p)) - break; - - it.mp = it.mp->mListNodeNext; - } while(it.mp != &mAnchor); - - return it; - } - - const_iterator find(T *p) const { - const_iterator it; - it.mp = mAnchor.mListNodeNext; - - if (it.mp != &mAnchor) - do { - if (it.mp == static_cast(p)) - break; - - it.mp = it.mp->mListNodeNext; - } while(it.mp != &mAnchor); - - return it; - } - - iterator fast_find(T *p) { - iterator it(p); - return it; - } - - const_iterator fast_find(T *p) const { - iterator it(p); - } - - void push_front(T *p) { - node& n = *p; - n.mListNodePrev = &mAnchor; - n.mListNodeNext = mAnchor.mListNodeNext; - n.mListNodeNext->mListNodePrev = &n; - mAnchor.mListNodeNext = &n; - } - - void push_back(T *p) { - node& n = *p; - n.mListNodeNext = &mAnchor; - n.mListNodePrev = mAnchor.mListNodePrev; - n.mListNodePrev->mListNodeNext = &n; - mAnchor.mListNodePrev = &n; - } - - iterator erase(T *p) { - return erase(fast_find(p)); - } - - iterator erase(iterator it) { - node& n = *it.mp; - - n.mListNodePrev->mListNodeNext = n.mListNodeNext; - n.mListNodeNext->mListNodePrev = n.mListNodePrev; - - it.mp = n.mListNodeNext; - return it; - } - - iterator erase(iterator i1, iterator i2) { - node& np = *i1.mp->mListNodePrev; - node& nn = *i2.mp; - - np.mListNodeNext = &nn; - nn.mListNodePrev = &np; - - return i2; - } - - void insert(iterator dst, T *src) { - node& ns = *src; - node& nd = *dst.mp; - - ns.mListNodeNext = &nd; - ns.mListNodePrev = nd.mListNodePrev; - nd.mListNodePrev->mListNodeNext = &ns; - nd.mListNodePrev = &ns; - } - - void insert(iterator dst, iterator i1, iterator i2) { - if (i1 != i2) { - node& np = *dst.mp->mListNodePrev; - node& nn = *dst.mp; - node& n1 = *i1.mp; - node& n2 = *i2.mp->mListNodePrev; - - np.mListNodeNext = &n1; - n1.mListNodePrev = &np; - n2.mListNodeNext = &nn; - nn.mListNodePrev = &n2; - } - } - - void splice(iterator dst, vdlist& srclist) { - insert(dst, srclist.begin(), srclist.end()); - srclist.clear(); - } - - void splice(iterator dst, vdlist& srclist, iterator src) { - T *v = *src; - srclist.erase(src); - insert(dst, v); - } - - void splice(iterator dst, vdlist& srclist, iterator i1, iterator i2) { - if (dst.mp != i1.mp && dst.mp != i2.mp) { - srclist.erase(i1, i2); - insert(dst, i1, i2); - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -#if defined(_DEBUG) && defined(_MSC_VER) - #define VD_ACCELERATE_TEMPLATES -#endif - -#ifndef VDTINLINE - #ifdef VD_ACCELERATE_TEMPLATES - #ifndef VDTEXTERN - #define VDTEXTERN extern - #endif - - #define VDTINLINE - #else - #define VDTINLINE inline - #endif -#endif - -/////////////////////////////////////////////////////////////////////////////// - -template -class vdspan { -public: - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef pointer iterator; - typedef const_pointer const_iterator; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - VDTINLINE vdspan(); - - template - VDTINLINE vdspan(T (&arr)[N]); - - VDTINLINE vdspan(T *p1, T *p2); - VDTINLINE vdspan(T *p1, size_type len); - -public: - VDTINLINE bool empty() const; - VDTINLINE size_type size() const; - - VDTINLINE pointer data(); - VDTINLINE const_pointer data() const; - - VDTINLINE iterator begin(); - VDTINLINE const_iterator begin() const; - VDTINLINE iterator end(); - VDTINLINE const_iterator end() const; - - VDTINLINE reverse_iterator rbegin(); - VDTINLINE const_reverse_iterator rbegin() const; - VDTINLINE reverse_iterator rend(); - VDTINLINE const_reverse_iterator rend() const; - - VDTINLINE reference front(); - VDTINLINE const_reference front() const; - VDTINLINE reference back(); - VDTINLINE const_reference back() const; - - VDTINLINE reference operator[](size_type n); - VDTINLINE const_reference operator[](size_type n) const; - -protected: - T *mpBegin; - T *mpEnd; -}; - -#ifdef VD_ACCELERATE_TEMPLATES - #pragma warning(push) - #pragma warning(disable: 4231) // warning C4231: nonstandard extension used : 'extern' before template explicit instantiation - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - #pragma warning(pop) -#endif - -template VDTINLINE vdspan::vdspan() : mpBegin(NULL), mpEnd(NULL) {} -template template VDTINLINE vdspan::vdspan(T (&arr)[N]) : mpBegin(&arr[0]), mpEnd(&arr[N]) {} -template VDTINLINE vdspan::vdspan(T *p1, T *p2) : mpBegin(p1), mpEnd(p2) {} -template VDTINLINE vdspan::vdspan(T *p, size_type len) : mpBegin(p), mpEnd(p+len) {} -template VDTINLINE bool vdspan::empty() const { return mpBegin == mpEnd; } -template VDTINLINE typename vdspan::size_type vdspan::size() const { return size_type(mpEnd - mpBegin); } -template VDTINLINE typename vdspan::pointer vdspan::data() { return mpBegin; } -template VDTINLINE typename vdspan::const_pointer vdspan::data() const { return mpBegin; } -template VDTINLINE typename vdspan::iterator vdspan::begin() { return mpBegin; } -template VDTINLINE typename vdspan::const_iterator vdspan::begin() const { return mpBegin; } -template VDTINLINE typename vdspan::iterator vdspan::end() { return mpEnd; } -template VDTINLINE typename vdspan::const_iterator vdspan::end() const { return mpEnd; } -template VDTINLINE typename vdspan::reverse_iterator vdspan::rbegin() { return reverse_iterator(mpEnd); } -template VDTINLINE typename vdspan::const_reverse_iterator vdspan::rbegin() const { return const_reverse_iterator(mpEnd); } -template VDTINLINE typename vdspan::reverse_iterator vdspan::rend() { return reverse_iterator(mpBegin); } -template VDTINLINE typename vdspan::const_reverse_iterator vdspan::rend() const { return const_reverse_iterator(mpBegin); } -template VDTINLINE typename vdspan::reference vdspan::front() { return *mpBegin; } -template VDTINLINE typename vdspan::const_reference vdspan::front() const { return *mpBegin; } -template VDTINLINE typename vdspan::reference vdspan::back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } -template VDTINLINE typename vdspan::const_reference vdspan::back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } -template VDTINLINE typename vdspan::reference vdspan::operator[](size_type n) { VDASSERT(n < size_type(mpEnd - mpBegin)); return mpBegin[n]; } -template VDTINLINE typename vdspan::const_reference vdspan::operator[](size_type n) const { VDASSERT(n < size_type(mpEnd - mpBegin)); return mpBegin[n]; } - -/////////////////////////////////////////////////////////////////////////////// - -template -bool operator==(const vdspan& x, const vdspan& y) { - uint32 len = x.size(); - if (len != y.size()) - return false; - - const T *px = x.data(); - const T *py = y.data(); - - for(uint32 i=0; i -inline bool operator!=(const vdspan& x, const vdspan& y) { return !(x == y); } - -/////////////////////////////////////////////////////////////////////////////// - -template > -class vdfastvector_base : public vdspan { -protected: - using vdspan::mpBegin; - using vdspan::mpEnd; - -public: - typedef typename vdspan::value_type value_type; - typedef typename vdspan::pointer pointer; - typedef typename vdspan::const_pointer const_pointer; - typedef typename vdspan::reference reference; - typedef typename vdspan::const_reference const_reference; - typedef typename vdspan::size_type size_type; - typedef typename vdspan::difference_type difference_type; - typedef typename vdspan::iterator iterator; - typedef typename vdspan::const_iterator const_iterator; - typedef typename vdspan::reverse_iterator reverse_iterator; - typedef typename vdspan::const_reverse_iterator const_reverse_iterator; - - ~vdfastvector_base() { - if (static_cast(m).is_deallocatable_storage(mpBegin)) - m.deallocate(mpBegin, m.eos - mpBegin); - } - - size_type capacity() const { return size_type(m.eos - mpBegin); } - -public: - T *alloc(size_type n) { - size_type offset = (size_type)(mpEnd - mpBegin); - resize(offset + n); - return mpBegin + offset; - } - - void assign(const T *p1, const T *p2) { - resize(p2 - p1); - memcpy(mpBegin, p1, (char *)p2 - (char *)p1); - } - - void clear() { - mpEnd = mpBegin; - } - - iterator erase(iterator it) { - VDASSERT(it - mpBegin < mpEnd - mpBegin); - - memmove(it, it+1, (char *)mpEnd - (char *)(it+1)); - - --mpEnd; - - return it; - } - - iterator erase(iterator it1, iterator it2) { - VDASSERT(it1 - mpBegin <= mpEnd - mpBegin); - VDASSERT(it2 - mpBegin <= mpEnd - mpBegin); - VDASSERT(it1 <= it2); - - memmove(it1, it2, (char *)mpEnd - (char *)it2); - - mpEnd -= (it2 - it1); - - return it1; - } - - iterator insert(iterator it, const T& value) { - const T temp(value); // copy in case value is inside container. - - if (mpEnd == m.eos) { - difference_type delta = it - mpBegin; - _reserve_always_add_one(); - it = mpBegin + delta; - } - - memmove(it+1, it, sizeof(T) * (mpEnd - it)); - *it = temp; - ++mpEnd; - VDASSERT(mpEnd <= m.eos); - - return it; - } - - iterator insert(iterator it, size_type n, const T& value) { - const T temp(value); // copy in case value is inside container. - - ptrdiff_t bytesToInsert = n * sizeof(T); - - if ((char *)m.eos - (char *)mpEnd < bytesToInsert) { - difference_type delta = it - mpBegin; - _reserve_always_add(bytesToInsert); - it = mpBegin + delta; - } - - memmove((char *)it + bytesToInsert, it, (char *)mpEnd - (char *)it); - for(size_t i=0; i size_type((char *)m.eos - (char *)mpBegin)) - _reserve_always_amortized(n); - - mpEnd = mpBegin + n; - } - - void resize(size_type n, const T& value) { - const T temp(value); - - if (n*sizeof(T) > size_type((char *)m.eos - (char *)mpBegin)) { - _reserve_always_amortized(n); - } - - const iterator newEnd(mpBegin + n); - if (newEnd > mpEnd) - std::fill(mpEnd, newEnd, temp); - mpEnd = newEnd; - } - - void reserve(size_type n) { - if (n*sizeof(T) > size_type((char *)m.eos - (char *)mpBegin)) - _reserve_always(n); - } - -protected: -#ifdef _MSC_VER - __declspec(noinline) -#endif - void _reserve_always_add_one() { - _reserve_always((m.eos - mpBegin) * 2 + 1); - } - -#ifdef _MSC_VER - __declspec(noinline) -#endif - void _reserve_always_add(size_type n) { - _reserve_always((m.eos - mpBegin) * 2 + n); - } - -#ifdef _MSC_VER - __declspec(noinline) -#endif - void _reserve_always(size_type n) { - size_type oldSize = mpEnd - mpBegin; - T *oldStorage = mpBegin; - T *newStorage = m.allocate(n, NULL); - - memcpy(newStorage, mpBegin, (char *)mpEnd - (char *)mpBegin); - if (static_cast(m).is_deallocatable_storage(oldStorage)) - m.deallocate(oldStorage, m.eos - mpBegin); - mpBegin = newStorage; - mpEnd = newStorage + oldSize; - m.eos = newStorage + n; - } - -#ifdef _MSC_VER - __declspec(noinline) -#endif - void _reserve_always_amortized(size_type n) { - size_type nextCapacity = (size_type)((m.eos - mpBegin)*2); - - if (nextCapacity < n) - nextCapacity = n; - - _reserve_always(nextCapacity); - } - - struct : A, S { - T *eos; - } m; - - union TrivialObjectConstraint { - T m; - }; -}; - -/////////////////////////////////////////////////////////////////////////////// - -struct vdfastvector_storage { - bool is_deallocatable_storage(void *p) const { - return p != 0; - } -}; - -template > -class vdfastvector : public vdfastvector_base { -protected: - using vdfastvector_base::m; - using vdfastvector_base::mpBegin; - using vdfastvector_base::mpEnd; - -public: - typedef typename vdfastvector_base::value_type value_type; - typedef typename vdfastvector_base::pointer pointer; - typedef typename vdfastvector_base::const_pointer const_pointer; - typedef typename vdfastvector_base::reference reference; - typedef typename vdfastvector_base::const_reference const_reference; - typedef typename vdfastvector_base::size_type size_type; - typedef typename vdfastvector_base::difference_type difference_type; - typedef typename vdfastvector_base::iterator iterator; - typedef typename vdfastvector_base::const_iterator const_iterator; - typedef typename vdfastvector_base::reverse_iterator reverse_iterator; - typedef typename vdfastvector_base::const_reverse_iterator const_reverse_iterator; - - vdfastvector() { - m.eos = NULL; - } - - vdfastvector(size_type len) { - mpBegin = m.allocate(len, NULL); - mpEnd = mpBegin + len; - m.eos = mpEnd; - } - - vdfastvector(size_type len, const T& fill) { - mpBegin = m.allocate(len, NULL); - mpEnd = mpBegin + len; - m.eos = mpEnd; - - std::fill(mpBegin, mpEnd, fill); - } - - vdfastvector(const vdfastvector& x) { - size_type n = x.mpEnd - x.mpBegin; - mpBegin = m.allocate(n, NULL); - mpEnd = mpBegin + n; - m.eos = mpEnd; - memcpy(mpBegin, x.mpBegin, sizeof(T) * n); - } - - vdfastvector(const value_type *p, const value_type *q) { - m.eos = NULL; - - assign(p, q); - } - - vdfastvector& operator=(const vdfastvector& x) { - if (this != &x) - vdfastvector::assign(x.mpBegin, x.mpEnd); - - return *this; - } - - void swap(vdfastvector& x) { - std::swap(mpBegin, x.mpBegin); - std::swap(mpEnd, x.mpEnd); - std::swap(m.eos, x.m.eos); - } - - void swap(vdfastvector&& x) { - std::swap(mpBegin, x.mpBegin); - std::swap(mpEnd, x.mpEnd); - std::swap(m.eos, x.m.eos); - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -template -struct vdfastfixedvector_storage { - T mArray[N]; - - bool is_deallocatable_storage(void *p) const { - return p != mArray; - } -}; - -template > -class vdfastfixedvector : public vdfastvector_base, A> { -protected: - using vdfastvector_base, A>::mpBegin; - using vdfastvector_base, A>::mpEnd; - using vdfastvector_base, A>::m; - -public: - typedef typename vdfastvector_base, A>::value_type value_type; - typedef typename vdfastvector_base, A>::pointer pointer; - typedef typename vdfastvector_base, A>::const_pointer const_pointer; - typedef typename vdfastvector_base, A>::reference reference; - typedef typename vdfastvector_base, A>::const_reference const_reference; - typedef typename vdfastvector_base, A>::size_type size_type; - typedef typename vdfastvector_base, A>::difference_type difference_type; - typedef typename vdfastvector_base, A>::iterator iterator; - typedef typename vdfastvector_base, A>::const_iterator const_iterator; - typedef typename vdfastvector_base, A>::reverse_iterator reverse_iterator; - typedef typename vdfastvector_base, A>::const_reverse_iterator const_reverse_iterator; - - vdfastfixedvector() { - mpBegin = m.mArray; - mpEnd = m.mArray; - m.eos = m.mArray + N; - } - - vdfastfixedvector(size_type len) { - if (len <= N) { - mpBegin = m.mArray; - mpEnd = m.mArray + len; - m.eos = m.mArray + N; - } else { - mpBegin = m.allocate(len, NULL); - mpEnd = mpBegin + len; - m.eos = mpEnd; - } - } - - vdfastfixedvector(size_type len, const T& fill) { - mpBegin = m.allocate(len, NULL); - mpEnd = mpBegin + len; - m.eos = mpEnd; - - std::fill(mpBegin, mpEnd, fill); - } - - vdfastfixedvector(const vdfastfixedvector& x) { - size_type n = x.mpEnd - x.mpBegin; - - if (n <= N) { - mpBegin = m.mArray; - mpEnd = m.mArray + n; - m.eos = m.mArray + N; - } else { - mpBegin = m.allocate(n, NULL); - mpEnd = mpBegin + n; - m.eos = mpEnd; - } - - memcpy(mpBegin, x.mpBegin, sizeof(T) * n); - } - - vdfastfixedvector(const value_type *p, const value_type *q) { - mpBegin = m.mArray; - mpEnd = m.mArray; - m.eos = m.mArray + N; - - assign(p, q); - } - - vdfastfixedvector& operator=(const vdfastfixedvector& x) { - if (this != &x) - assign(x.mpBegin, x.mpEnd); - - return *this; - } - - void swap(vdfastfixedvector& x) { - size_t this_bytes = (char *)mpEnd - (char *)mpBegin; - size_t other_bytes = (char *)x.mpEnd - (char *)x.mpBegin; - - T *p; - - if (mpBegin == m.mArray) { - if (x.mpBegin == x.m.mArray) { - if (this_bytes < other_bytes) { - VDSwapMemory(m.mArray, x.m.mArray, this_bytes); - memcpy((char *)m.mArray + this_bytes, (char *)x.m.mArray + this_bytes, other_bytes - this_bytes); - } else { - VDSwapMemory(m.mArray, x.m.mArray, other_bytes); - memcpy((char *)m.mArray + other_bytes, (char *)x.m.mArray + other_bytes, this_bytes - other_bytes); - } - - mpEnd = (T *)((char *)mpBegin + other_bytes); - x.mpEnd = (T *)((char *)x.mpBegin + this_bytes); - } else { - memcpy(x.m.mArray, mpBegin, this_bytes); - - mpBegin = x.mpBegin; - mpEnd = x.mpEnd; - m.eos = x.m.eos; - - x.mpBegin = x.m.mArray; - x.mpEnd = (T *)((char *)x.m.mArray + this_bytes); - x.m.eos = x.m.mArray + N; - } - } else { - if (x.mpBegin == x.m.mArray) { - memcpy(x.m.mArray, mpBegin, other_bytes); - - x.mpBegin = mpBegin; - x.mpEnd = mpEnd; - x.m.eos = m.eos; - - mpBegin = m.mArray; - mpEnd = (T *)((char *)m.mArray + other_bytes); - m.eos = m.mArray + N; - } else { - p = mpBegin; mpBegin = x.mpBegin; x.mpBegin = p; - p = mpEnd; mpEnd = x.mpEnd; x.mpEnd = p; - p = m.eos; m.eos = x.m.eos; x.m.eos = p; - } - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -template -struct vdfastdeque_block { - enum { - kBlockSize = 32, - kBlockSizeBits = 5 - }; - - T data[kBlockSize]; -}; - -template -class vdfastdeque_iterator { -public: - typedef T value_type; - typedef T* pointer; - typedef T& reference; - typedef ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - vdfastdeque_iterator(const vdfastdeque_iterator&); - vdfastdeque_iterator(vdfastdeque_block **pMapEntry, uint32 index); - - T& operator *() const; - T& operator ->() const; - vdfastdeque_iterator& operator++(); - vdfastdeque_iterator operator++(int); - vdfastdeque_iterator& operator--(); - vdfastdeque_iterator operator--(int); - -public: - vdfastdeque_block **mpMap; - vdfastdeque_block *mpBlock; - uint32 mIndex; -}; - -template -vdfastdeque_iterator::vdfastdeque_iterator(const vdfastdeque_iterator& x) - : mpMap(x.mpMap) - , mpBlock(x.mpBlock) - , mIndex(x.mIndex) -{ -} - -template -vdfastdeque_iterator::vdfastdeque_iterator(vdfastdeque_block **pMapEntry, uint32 index) - : mpMap(pMapEntry) - , mpBlock(mpMap ? *mpMap : NULL) - , mIndex(index) -{ -} - -template -T& vdfastdeque_iterator::operator *() const { - return mpBlock->data[mIndex]; -} - -template -T& vdfastdeque_iterator::operator ->() const { - return mpBlock->data[mIndex]; -} - -template -vdfastdeque_iterator& vdfastdeque_iterator::operator++() { - if (++mIndex >= vdfastdeque_block::kBlockSize) { - mIndex = 0; - mpBlock = *++mpMap; - } - return *this; -} - -template -vdfastdeque_iterator vdfastdeque_iterator::operator++(int) { - vdfastdeque_iterator r(*this); - operator++(); - return r; -} - -template -vdfastdeque_iterator& vdfastdeque_iterator::operator--() { - if (mIndex-- == 0) { - mIndex = vdfastdeque_block::kBlockSize - 1; - mpBlock = *--mpMap; - } - return *this; -} - -template -vdfastdeque_iterator vdfastdeque_iterator::operator--(int) { - vdfastdeque_iterator r(*this); - operator--(); - return r; -} - -template -bool operator==(const vdfastdeque_iterator& x,const vdfastdeque_iterator& y) { - return x.mpBlock == y.mpBlock && x.mIndex == y.mIndex; -} - -template -bool operator!=(const vdfastdeque_iterator& x,const vdfastdeque_iterator& y) { - return x.mpBlock != y.mpBlock || x.mIndex != y.mIndex; -} - -/////////////////////////////////////////////////////////////////////////////// - -template > -class vdfastdeque { -public: - typedef typename A::reference reference; - typedef typename A::const_reference const_reference; - typedef typename A::pointer pointer; - typedef typename A::const_pointer const_pointer; - typedef T value_type; - typedef A allocator_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef vdfastdeque_iterator iterator; - typedef vdfastdeque_iterator const_iterator; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - vdfastdeque(); - ~vdfastdeque(); - - bool empty() const; - size_type size() const; - - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; - - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - - reference operator[](size_type n); - const_reference operator[](size_type n) const; - - void clear(); - - reference push_back(); - void push_back(const_reference x); - - void pop_front(); - void pop_back(); - - void swap(vdfastdeque& x); - -protected: - void push_back_extend(); - void validate(); - - typedef vdfastdeque_block Block; - - enum { - kBlockSize = Block::kBlockSize, - kBlockSizeBits = Block::kBlockSizeBits - }; - - struct M1 : public A::template rebind::other { - Block **mapStartAlloc; // start of map - Block **mapStartCommit; // start of range of allocated blocks - Block **mapStart; // start of range of active blocks - Block **mapEnd; // end of range of active blocks - Block **mapEndCommit; // end of range of allocated blocks - Block **mapEndAlloc; // end of map - } m; - - struct M2 : public A::template rebind::other { - int startIndex; - int endIndex; - } mTails; - - union TrivialObjectConstraint { - T obj; - }; -}; - -template -vdfastdeque::vdfastdeque() { - m.mapStartAlloc = NULL; - m.mapStartCommit = NULL; - m.mapStart = NULL; - m.mapEnd = NULL; - m.mapEndCommit = NULL; - m.mapEndAlloc = NULL; - mTails.startIndex = 0; - mTails.endIndex = kBlockSize - 1; -} - -template -vdfastdeque::~vdfastdeque() { - while(m.mapStartCommit != m.mapEndCommit) { - mTails.deallocate(*m.mapStartCommit++, 1); - } - - if (m.mapStartAlloc) - m.deallocate(m.mapStartAlloc, m.mapEndAlloc - m.mapStartAlloc); -} - -template -bool vdfastdeque::empty() const { - return size() == 0; -} - -template -typename vdfastdeque::size_type vdfastdeque::size() const { - if (m.mapEnd == m.mapStart) - return 0; - - return kBlockSize * ((m.mapEnd - m.mapStart) - 1) + (mTails.endIndex + 1) - mTails.startIndex; -} - -template -typename vdfastdeque::reference vdfastdeque::front() { - VDASSERT(m.mapStart != m.mapEnd); - return (*m.mapStart)->data[mTails.startIndex]; -} - -template -typename vdfastdeque::const_reference vdfastdeque::front() const { - VDASSERT(m.mapStart != m.mapEnd); - return (*m.mapStart)->data[mTails.startIndex]; -} - -template -typename vdfastdeque::reference vdfastdeque::back() { - VDASSERT(m.mapStart != m.mapEnd); - return m.mapEnd[-1]->data[mTails.endIndex]; -} - -template -typename vdfastdeque::const_reference vdfastdeque::back() const { - VDASSERT(m.mapStart != m.mapEnd); - return m.mapEnd[-1]->data[mTails.endIndex]; -} - -template -typename vdfastdeque::iterator vdfastdeque::begin() { - return iterator(m.mapStart, mTails.startIndex); -} - -template -typename vdfastdeque::const_iterator vdfastdeque::begin() const { - return const_iterator(m.mapStart, mTails.startIndex); -} - -template -typename vdfastdeque::iterator vdfastdeque::end() { - if (mTails.endIndex == kBlockSize - 1) - return iterator(m.mapEnd, 0); - else - return iterator(m.mapEnd - 1, mTails.endIndex + 1); -} - -template -typename vdfastdeque::const_iterator vdfastdeque::end() const { - if (mTails.endIndex == kBlockSize - 1) - return const_iterator(m.mapEnd, 0); - else - return const_iterator(m.mapEnd - 1, mTails.endIndex + 1); -} - -template -typename vdfastdeque::reference vdfastdeque::operator[](size_type n) { - n += mTails.startIndex; - return m.mapStart[n >> kBlockSizeBits]->data[n & (kBlockSize - 1)]; -} - -template -typename vdfastdeque::const_reference vdfastdeque::operator[](size_type n) const { - n += mTails.startIndex; - return m.mapStart[n >> kBlockSizeBits]->data[n & (kBlockSize - 1)]; -} - -template -void vdfastdeque::clear() { - m.mapEnd = m.mapStart; - mTails.startIndex = 0; - mTails.endIndex = kBlockSize - 1; -} - -template -typename vdfastdeque::reference vdfastdeque::push_back() { - if (mTails.endIndex >= kBlockSize - 1) { - push_back_extend(); - - mTails.endIndex = -1; - } - - ++mTails.endIndex; - - VDASSERT(m.mapEnd[-1]); - reference r = m.mapEnd[-1]->data[mTails.endIndex]; - return r; -} - -template -void vdfastdeque::push_back(const_reference x) { - const T x2(x); - push_back() = x2; -} - -template -void vdfastdeque::pop_front() { - if (++mTails.startIndex >= kBlockSize) { - VDASSERT(m.mapEnd != m.mapStart); - mTails.startIndex = 0; - ++m.mapStart; - } -} - -template -void vdfastdeque::pop_back() { - if (--mTails.endIndex < 0) { - VDASSERT(m.mapEnd != m.mapStart); - mTails.endIndex = kBlockSize - 1; - --m.mapEnd; - } -} - -template -void vdfastdeque::swap(vdfastdeque& x) { - std::swap(m.mapStartAlloc, x.m.mapStartAlloc); - std::swap(m.mapStartCommit, x.m.mapStartCommit); - std::swap(m.mapStart, x.m.mapStart); - std::swap(m.mapEnd, x.m.mapEnd); - std::swap(m.mapEndCommit, x.m.mapEndCommit); - std::swap(m.mapEndAlloc, x.m.mapEndAlloc); - std::swap(mTails.startIndex, x.mTails.startIndex); - std::swap(mTails.endIndex, x.mTails.endIndex); -} - -///////////////////////////////// - -template -void vdfastdeque::push_back_extend() { - validate(); - - // check if we need to extend the map itself - if (m.mapEnd == m.mapEndAlloc) { - // can we just shift the map? - size_type currentMapSize = m.mapEndAlloc - m.mapStartAlloc; - size_type freeAtStart = m.mapStartCommit - m.mapStartAlloc; - - if (freeAtStart >= 2 && (freeAtStart + freeAtStart) >= currentMapSize) { - size_type shiftDistance = freeAtStart >> 1; - - VDASSERT(!m.mapStartAlloc[0]); - memmove(m.mapStartAlloc, m.mapStartAlloc + shiftDistance, sizeof(Block *) * (currentMapSize - shiftDistance)); - memset(m.mapStartAlloc + (currentMapSize - shiftDistance), 0, shiftDistance * sizeof(Block *)); - - // relocate pointers - m.mapEndCommit -= shiftDistance; - m.mapEnd -= shiftDistance; - m.mapStart -= shiftDistance; - m.mapStartCommit -= shiftDistance; - validate(); - } else { - size_type newMapSize = currentMapSize*2+1; - - Block **newMap = m.allocate(newMapSize); - - memcpy(newMap, m.mapStartAlloc, currentMapSize * sizeof(Block *)); - memset(newMap + currentMapSize, 0, (newMapSize - currentMapSize) * sizeof(Block *)); - - // relocate pointers - m.mapEndAlloc = newMap + newMapSize; - m.mapEndCommit = newMap + (m.mapEndCommit - m.mapStartAlloc); - m.mapEnd = newMap + (m.mapEnd - m.mapStartAlloc); - m.mapStart = newMap + (m.mapStart - m.mapStartAlloc); - m.mapStartCommit = newMap + (m.mapStartCommit - m.mapStartAlloc); - - m.deallocate(m.mapStartAlloc, currentMapSize); - m.mapStartAlloc = newMap; - validate(); - } - } - - VDASSERT(m.mapEnd != m.mapEndAlloc); - - // check if we already have a block we can use - if (*m.mapEnd) { - ++m.mapEnd; - validate(); - return; - } - - // check if we can steal a block from the beginning - if (m.mapStartCommit != m.mapStart) { - VDASSERT(*m.mapStartCommit); - if (m.mapStartCommit != m.mapEnd) { - *m.mapEnd = *m.mapStartCommit; - *m.mapStartCommit = NULL; - ++m.mapStartCommit; - } - ++m.mapEnd; - m.mapEndCommit = m.mapEnd; - validate(); - return; - } - - // allocate a new block - *m.mapEnd = mTails.allocate(1); - ++m.mapEnd; - m.mapEndCommit = m.mapEnd; - validate(); -} - -template -void vdfastdeque::validate() { - VDASSERT(m.mapStartAlloc <= m.mapStartCommit); - VDASSERT(m.mapStartCommit <= m.mapStart); - VDASSERT(m.mapStart <= m.mapEnd); - VDASSERT(m.mapEnd <= m.mapEndCommit); - VDASSERT(m.mapEndCommit <= m.mapEndAlloc); - - VDASSERT(m.mapStartAlloc == m.mapStartCommit || !*m.mapStartAlloc); - VDASSERT(m.mapStartCommit == m.mapEndCommit || m.mapStartCommit[0]); - VDASSERT(m.mapStart == m.mapEnd || (m.mapStart[0] && m.mapEnd[-1])); - VDASSERT(m.mapEndCommit == m.mapEndAlloc || !m.mapEndCommit[0]); -} - -#include -#include -#include - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef VD2_SYSTEM_VDSTL_H +#define VD2_SYSTEM_VDSTL_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// +// glue +// +/////////////////////////////////////////////////////////////////////////// + +template +struct vdreverse_iterator { +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1310 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) + typedef std::reverse_iterator type; +#else + typedef std::reverse_iterator type; +#endif +}; + +/////////////////////////////////////////////////////////////////////////// + +struct vdfalse_type { }; +struct vdtrue_type { }; + +struct vdfalse_result { typedef vdfalse_type result; }; +struct vdtrue_result { typedef vdtrue_type result; }; + +template void vdmove(T& dst, T& src); +template struct vdmove_capable : public vdfalse_result {}; + +template +T *vdmove_forward_impl(T *src1, T *src2, T *dst, vdfalse_type) { + T *p = src1; + while(p != src2) { + *dst = *p; + ++dst; + ++p; + } + + return dst; +} + +template +T *vdmove_backward_impl(T *src1, T *src2, T *dst, vdfalse_type) { + T *p = src2; + while(p != src1) { + --dst; + --p; + *dst = *p; + } + + return dst; +} + +template +T *vdmove_forward_impl(T *src1, T *src2, T *dst, vdtrue_type) { + T *p = src1; + while(p != src2) { + vdmove(*dst, *p); + ++dst; + ++p; + } + + return dst; +} + +template +T *vdmove_backward_impl(T *src1, T *src2, T *dst, vdtrue_type) { + T *p = src2; + while(p != src1) { + --dst; + --p; + vdmove(*dst, *p); + } + + return dst; +} + +template +T *vdmove_forward(T *src1, T *src2, T *dst) { + return vdmove_forward_impl(src1, src2, dst, vdmove_capable::result()); +} + +template +T *vdmove_backward(T *src1, T *src2, T *dst) { + return vdmove_backward_impl(src1, src2, dst, vdmove_capable::result()); +} + +#define VDMOVE_CAPABLE(type) \ + template<> struct vdmove_capable : public vdtrue_result {}; \ + template<> void vdmove(type& dst, type& src) + +/////////////////////////////////////////////////////////////////////////// + +template char (&VDCountOfHelper(const T(&)[N]))[N]; + +#define vdcountof(array) (sizeof(VDCountOfHelper(array))) + +/////////////////////////////////////////////////////////////////////////// + +class vdallocator_base { +protected: + void VDNORETURN throw_oom(size_t n, size_t elsize); +}; + +template +class vdallocator : public vdallocator_base { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template struct rebind { typedef vdallocator other; }; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, void *p_close = 0) { + if (n > ((~(size_type)0) >> 1) / sizeof(T)) + throw_oom(n, sizeof(T)); + + pointer p = (pointer)malloc(n*sizeof(T)); + + if (!p) + throw_oom(n, sizeof(T)); + + return p; + } + + void deallocate(pointer p, size_type n) { + free(p); + } + + size_type max_size() const throw() { return ((~(size_type)0) >> 1) / sizeof(T); } + + void construct(pointer p, const T& val) { new((void *)p) T(val); } + void destroy(pointer p) { ((T*)p)->~T(); } + +#if defined(_MSC_VER) && _MSC_VER < 1300 + char * _Charalloc(size_type n) { return rebind::other::allocate(n); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////// + +template +class vddebug_alloc { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template struct rebind { typedef vddebug_alloc other; }; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, void *p_close = 0) { + pointer p = (pointer)VDAlignedMalloc(n*sizeof(T) + 2*kDeadZone, 16); + + if (!p) + return p; + + memset((char *)p, 0xa9, kDeadZone); + memset((char *)p + kDeadZone + n*sizeof(T), 0xa9, kDeadZone); + + return (pointer)((char *)p + kDeadZone); + } + + void deallocate(pointer p, size_type n) { + char *p1 = (char *)p - kDeadZone; + char *p2 = (char *)p + n*sizeof(T); + + for(uint32 i=0; i~T(); } + +#if defined(_MSC_VER) && _MSC_VER < 1300 + char * _Charalloc(size_type n) { return rebind::other::allocate(n); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////// + +template +class vdaligned_alloc { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + vdaligned_alloc() {} + + template + vdaligned_alloc(const vdaligned_alloc&) {} + + template struct rebind { typedef vdaligned_alloc other; }; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, void *p = 0) { return (pointer)VDAlignedMalloc(n*sizeof(T), kAlignment); } + void deallocate(pointer p, size_type n) { VDAlignedFree(p); } + size_type max_size() const throw() { return INT_MAX; } + + void construct(pointer p, const T& val) { new((void *)p) T(val); } + void destroy(pointer p) { ((T*)p)->~T(); } + +#if defined(_MSC_VER) && _MSC_VER < 1300 + char * _Charalloc(size_type n) { return rebind::other::allocate(n); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////// +// +// vdblock +// +// vdblock is similar to vector, except: +// +// 1) May only be used with POD types. +// 2) No construction or destruction of elements is performed. +// 3) Capacity is always equal to size, and reallocation is performed +// whenever the size changes. +// 4) Contents are undefined after a reallocation. +// 5) No insertion or deletion operations are provided. +// +/////////////////////////////////////////////////////////////////////////// + +template > +class vdblock : protected A { +public: + typedef T value_type; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + vdblock(const A& alloc = A()) : A(alloc), mpBlock(NULL), mSize(0) {} + vdblock(size_type s, const A& alloc = A()) : A(alloc), mpBlock(A::allocate(s, 0)), mSize(s) {} + ~vdblock() { + if (mpBlock) + A::deallocate(mpBlock, mSize); + } + + reference operator[](size_type n) { return mpBlock[n]; } + const_reference operator[](size_type n) const { return mpBlock[n]; } + reference at(size_type n) { return n < mSize ? mpBlock[n] : throw std::length_error("n"); } + const_reference at(size_type n) const { return n < mSize ? mpBlock[n] : throw std::length_error("n"); } + reference front() { return *mpBlock; } + const_reference front() const { return *mpBlock; } + reference back() { return mpBlock[mSize-1]; } + const_reference back() const { return mpBlock[mSize-1]; } + + const_pointer data() const { return mpBlock; } + pointer data() { return mpBlock; } + + const_iterator begin() const { return mpBlock; } + iterator begin() { return mpBlock; } + const_iterator end() const { return mpBlock + mSize; } + iterator end() { return mpBlock + mSize; } + + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + + bool empty() const { return !mSize; } + size_type size() const { return mSize; } + size_type capacity() const { return mSize; } + + void clear() { + if (mpBlock) + A::deallocate(mpBlock, mSize); + mpBlock = NULL; + mSize = 0; + } + + void resize(size_type s) { + if (s != mSize) { + if (mpBlock) { + A::deallocate(mpBlock, mSize); + mpBlock = NULL; + mSize = 0; + } + if (s) + mpBlock = A::allocate(s, 0); + mSize = s; + } + } + + void resize(size_type s, const T& value) { + if (s != mSize) { + if (mpBlock) { + A::deallocate(mpBlock, mSize); + mpBlock = NULL; + mSize = 0; + } + if (s) { + mpBlock = A::allocate(s, 0); + std::fill(mpBlock, mpBlock+s, value); + } + mSize = s; + } + } + + void swap(vdblock& x) { + std::swap(mpBlock, x.mpBlock); + std::swap(mSize, x.mSize); + } + +protected: + typename A::pointer mpBlock; + typename A::size_type mSize; + + union PODType { + T x; + }; +}; + +/////////////////////////////////////////////////////////////////////////// +// +// vdstructex +// +// vdstructex describes an extensible format structure, such as +// BITMAPINFOHEADER or WAVEFORMATEX, without the pain-in-the-butt +// casting normally associated with one. +// +/////////////////////////////////////////////////////////////////////////// + +template +class vdstructex { +public: + typedef size_t size_type; + typedef T value_type; + + vdstructex() : mpMemory(NULL), mSize(0) {} + + explicit vdstructex(size_t len) : mpMemory(NULL), mSize(0) { + resize(len); + } + + vdstructex(const T *pStruct, size_t len) : mSize(len), mpMemory((T*)malloc(len)) { + memcpy(mpMemory, pStruct, len); + } + + vdstructex(const vdstructex& src) : mSize(src.mSize), mpMemory((T*)malloc(src.mSize)) { + memcpy(mpMemory, src.mpMemory, mSize); + } + + ~vdstructex() { + free(mpMemory); + } + + bool empty() const { return !mpMemory; } + size_type size() const { return mSize; } + T* data() const { return mpMemory; } + + T& operator *() const { return *(T *)mpMemory; } + T* operator->() const { return (T *)mpMemory; } + + bool operator==(const vdstructex& x) const { + return mSize == x.mSize && (!mSize || !memcmp(mpMemory, x.mpMemory, mSize)); + } + + bool operator!=(const vdstructex& x) const { + return mSize != x.mSize || (mSize && memcmp(mpMemory, x.mpMemory, mSize)); + } + + vdstructex& operator=(const vdstructex& src) { + assign(src.mpMemory, src.mSize); + return *this; + } + + void assign(const T *pStruct, size_type len) { + if (mSize != len) + resize(len); + + memcpy(mpMemory, pStruct, len); + } + + void clear() { + free(mpMemory); + mpMemory = NULL; + mSize = 0; + } + + void resize(size_type len) { + if (mSize != len) + mpMemory = (T *)realloc(mpMemory, mSize = len); + } + +protected: + size_type mSize; + T *mpMemory; +}; + +/////////////////////////////////////////////////////////////////////////// +// +// vdlist +// +// vdlist is similar to list, except: +// +// 1) The node structure must be embedded as a superclass of T. +// Thus, the client is in full control of allocation. +// 2) Node pointers may be converted back into iterators in O(1). +// +/////////////////////////////////////////////////////////////////////////// + +struct vdlist_node { + vdlist_node *mListNodeNext, *mListNodePrev; +}; + +template +class vdlist_iterator { +public: + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T *pointer_type; + typedef T& reference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + vdlist_iterator() {} + vdlist_iterator(T *p) : mp(p) {} + vdlist_iterator(const vdlist_iterator& src) : mp(src.mp) {} + + T* operator *() const { + return static_cast(mp); + } + + bool operator==(const vdlist_iterator& x) const { + return mp == x.mp; + } + + bool operator!=(const vdlist_iterator& x) const { + return mp != x.mp; + } + + vdlist_iterator& operator++() { + mp = mp->mListNodeNext; + return *this; + } + + vdlist_iterator& operator--() { + mp = mp->mListNodePrev; + return *this; + } + + vdlist_iterator operator++(int) { + vdlist_iterator tmp(*this); + mp = mp->mListNodeNext; + return tmp; + } + + vdlist_iterator& operator--(int) { + vdlist_iterator tmp(*this); + mp = mp->mListNodePrev; + return tmp; + } + + vdlist_node *mp; +}; + +class vdlist_base { +public: + typedef vdlist_node node; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + bool empty() const { + return mAnchor.mListNodeNext == &mAnchor; + } + + size_type size() const { + node *p = { mAnchor.mListNodeNext }; + size_type s = 0; + + if (p != &mAnchor) + do { + ++s; + p = p->mListNodeNext; + } while(p != &mAnchor); + + return s; + } + + void clear() { + mAnchor.mListNodePrev = &mAnchor; + mAnchor.mListNodeNext = &mAnchor; + } + + void pop_front() { + mAnchor.mListNodeNext = mAnchor.mListNodeNext->mListNodeNext; + mAnchor.mListNodeNext->mListNodePrev = &mAnchor; + } + + void pop_back() { + mAnchor.mListNodePrev = mAnchor.mListNodePrev->mListNodePrev; + mAnchor.mListNodePrev->mListNodeNext = &mAnchor; + } + + static void unlink(vdlist_node& node) { + vdlist_node& n1 = *node.mListNodePrev; + vdlist_node& n2 = *node.mListNodeNext; + + n1.mListNodeNext = &n2; + n2.mListNodePrev = &n1; + } + +protected: + node mAnchor; +}; + +template +class vdlist : public vdlist_base { +public: + typedef T* value_type; + typedef T** pointer; + typedef const T** const_pointer; + typedef T*& reference; + typedef const T*& const_reference; + typedef vdlist_iterator iterator; + typedef vdlist_iterator const_iterator; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + vdlist() { + mAnchor.mListNodePrev = &mAnchor; + mAnchor.mListNodeNext = &mAnchor; + } + + iterator begin() { + iterator it; + it.mp = mAnchor.mListNodeNext; + return it; + } + + const_iterator begin() const { + const_iterator it; + it.mp = mAnchor.mListNodeNext; + return it; + } + + iterator end() { + iterator it; + it.mp = &mAnchor; + return it; + } + + const_iterator end() const { + const_iterator it; + it.mp = &mAnchor; + return it; + } + + reverse_iterator rbegin() { + return reverse_iterator(begin()); + } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(begin()); + } + + reverse_iterator rend() { + return reverse_iterator(end); + } + + const_reverse_iterator rend() const { + return const_reverse_iterator(end()); + } + + const value_type front() const { + return static_cast(mAnchor.mListNodeNext); + } + + const value_type back() const { + return static_cast(mAnchor.mListNodePrev); + } + + iterator find(T *p) { + iterator it; + it.mp = mAnchor.mListNodeNext; + + if (it.mp != &mAnchor) + do { + if (it.mp == static_cast(p)) + break; + + it.mp = it.mp->mListNodeNext; + } while(it.mp != &mAnchor); + + return it; + } + + const_iterator find(T *p) const { + const_iterator it; + it.mp = mAnchor.mListNodeNext; + + if (it.mp != &mAnchor) + do { + if (it.mp == static_cast(p)) + break; + + it.mp = it.mp->mListNodeNext; + } while(it.mp != &mAnchor); + + return it; + } + + iterator fast_find(T *p) { + iterator it(p); + return it; + } + + const_iterator fast_find(T *p) const { + iterator it(p); + } + + void push_front(T *p) { + node& n = *p; + n.mListNodePrev = &mAnchor; + n.mListNodeNext = mAnchor.mListNodeNext; + n.mListNodeNext->mListNodePrev = &n; + mAnchor.mListNodeNext = &n; + } + + void push_back(T *p) { + node& n = *p; + n.mListNodeNext = &mAnchor; + n.mListNodePrev = mAnchor.mListNodePrev; + n.mListNodePrev->mListNodeNext = &n; + mAnchor.mListNodePrev = &n; + } + + iterator erase(T *p) { + return erase(fast_find(p)); + } + + iterator erase(iterator it) { + node& n = *it.mp; + + n.mListNodePrev->mListNodeNext = n.mListNodeNext; + n.mListNodeNext->mListNodePrev = n.mListNodePrev; + + it.mp = n.mListNodeNext; + return it; + } + + iterator erase(iterator i1, iterator i2) { + node& np = *i1.mp->mListNodePrev; + node& nn = *i2.mp; + + np.mListNodeNext = &nn; + nn.mListNodePrev = &np; + + return i2; + } + + void insert(iterator dst, T *src) { + node& ns = *src; + node& nd = *dst.mp; + + ns.mListNodeNext = &nd; + ns.mListNodePrev = nd.mListNodePrev; + nd.mListNodePrev->mListNodeNext = &ns; + nd.mListNodePrev = &ns; + } + + void insert(iterator dst, iterator i1, iterator i2) { + if (i1 != i2) { + node& np = *dst.mp->mListNodePrev; + node& nn = *dst.mp; + node& n1 = *i1.mp; + node& n2 = *i2.mp->mListNodePrev; + + np.mListNodeNext = &n1; + n1.mListNodePrev = &np; + n2.mListNodeNext = &nn; + nn.mListNodePrev = &n2; + } + } + + void splice(iterator dst, vdlist& srclist) { + insert(dst, srclist.begin(), srclist.end()); + srclist.clear(); + } + + void splice(iterator dst, vdlist& srclist, iterator src) { + T *v = *src; + srclist.erase(src); + insert(dst, v); + } + + void splice(iterator dst, vdlist& srclist, iterator i1, iterator i2) { + if (dst.mp != i1.mp && dst.mp != i2.mp) { + srclist.erase(i1, i2); + insert(dst, i1, i2); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +#if defined(_DEBUG) && defined(_MSC_VER) + #define VD_ACCELERATE_TEMPLATES +#endif + +#ifndef VDTINLINE + #ifdef VD_ACCELERATE_TEMPLATES + #ifndef VDTEXTERN + #define VDTEXTERN extern + #endif + + #define VDTINLINE + #else + #define VDTINLINE inline + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// + +template +class vdspan { +public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + VDTINLINE vdspan(); + + template + VDTINLINE vdspan(T (&arr)[N]); + + VDTINLINE vdspan(T *p1, T *p2); + VDTINLINE vdspan(T *p1, size_type len); + +public: + VDTINLINE bool empty() const; + VDTINLINE size_type size() const; + + VDTINLINE pointer data(); + VDTINLINE const_pointer data() const; + + VDTINLINE iterator begin(); + VDTINLINE const_iterator begin() const; + VDTINLINE iterator end(); + VDTINLINE const_iterator end() const; + + VDTINLINE reverse_iterator rbegin(); + VDTINLINE const_reverse_iterator rbegin() const; + VDTINLINE reverse_iterator rend(); + VDTINLINE const_reverse_iterator rend() const; + + VDTINLINE reference front(); + VDTINLINE const_reference front() const; + VDTINLINE reference back(); + VDTINLINE const_reference back() const; + + VDTINLINE reference operator[](size_type n); + VDTINLINE const_reference operator[](size_type n) const; + +protected: + T *mpBegin; + T *mpEnd; +}; + +#ifdef VD_ACCELERATE_TEMPLATES + #pragma warning(push) + #pragma warning(disable: 4231) // warning C4231: nonstandard extension used : 'extern' before template explicit instantiation + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + #pragma warning(pop) +#endif + +template VDTINLINE vdspan::vdspan() : mpBegin(NULL), mpEnd(NULL) {} +template template VDTINLINE vdspan::vdspan(T (&arr)[N]) : mpBegin(&arr[0]), mpEnd(&arr[N]) {} +template VDTINLINE vdspan::vdspan(T *p1, T *p2) : mpBegin(p1), mpEnd(p2) {} +template VDTINLINE vdspan::vdspan(T *p, size_type len) : mpBegin(p), mpEnd(p+len) {} +template VDTINLINE bool vdspan::empty() const { return mpBegin == mpEnd; } +template VDTINLINE typename vdspan::size_type vdspan::size() const { return size_type(mpEnd - mpBegin); } +template VDTINLINE typename vdspan::pointer vdspan::data() { return mpBegin; } +template VDTINLINE typename vdspan::const_pointer vdspan::data() const { return mpBegin; } +template VDTINLINE typename vdspan::iterator vdspan::begin() { return mpBegin; } +template VDTINLINE typename vdspan::const_iterator vdspan::begin() const { return mpBegin; } +template VDTINLINE typename vdspan::iterator vdspan::end() { return mpEnd; } +template VDTINLINE typename vdspan::const_iterator vdspan::end() const { return mpEnd; } +template VDTINLINE typename vdspan::reverse_iterator vdspan::rbegin() { return reverse_iterator(mpEnd); } +template VDTINLINE typename vdspan::const_reverse_iterator vdspan::rbegin() const { return const_reverse_iterator(mpEnd); } +template VDTINLINE typename vdspan::reverse_iterator vdspan::rend() { return reverse_iterator(mpBegin); } +template VDTINLINE typename vdspan::const_reverse_iterator vdspan::rend() const { return const_reverse_iterator(mpBegin); } +template VDTINLINE typename vdspan::reference vdspan::front() { return *mpBegin; } +template VDTINLINE typename vdspan::const_reference vdspan::front() const { return *mpBegin; } +template VDTINLINE typename vdspan::reference vdspan::back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } +template VDTINLINE typename vdspan::const_reference vdspan::back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } +template VDTINLINE typename vdspan::reference vdspan::operator[](size_type n) { VDASSERT(n < size_type(mpEnd - mpBegin)); return mpBegin[n]; } +template VDTINLINE typename vdspan::const_reference vdspan::operator[](size_type n) const { VDASSERT(n < size_type(mpEnd - mpBegin)); return mpBegin[n]; } + +/////////////////////////////////////////////////////////////////////////////// + +template +bool operator==(const vdspan& x, const vdspan& y) { + uint32 len = x.size(); + if (len != y.size()) + return false; + + const T *px = x.data(); + const T *py = y.data(); + + for(uint32 i=0; i +inline bool operator!=(const vdspan& x, const vdspan& y) { return !(x == y); } + +/////////////////////////////////////////////////////////////////////////////// + +template > +class vdfastvector_base : public vdspan { +protected: + using vdspan::mpBegin; + using vdspan::mpEnd; + +public: + typedef typename vdspan::value_type value_type; + typedef typename vdspan::pointer pointer; + typedef typename vdspan::const_pointer const_pointer; + typedef typename vdspan::reference reference; + typedef typename vdspan::const_reference const_reference; + typedef typename vdspan::size_type size_type; + typedef typename vdspan::difference_type difference_type; + typedef typename vdspan::iterator iterator; + typedef typename vdspan::const_iterator const_iterator; + typedef typename vdspan::reverse_iterator reverse_iterator; + typedef typename vdspan::const_reverse_iterator const_reverse_iterator; + + ~vdfastvector_base() { + if (static_cast(m).is_deallocatable_storage(mpBegin)) + m.deallocate(mpBegin, m.eos - mpBegin); + } + + size_type capacity() const { return size_type(m.eos - mpBegin); } + +public: + T *alloc(size_type n) { + size_type offset = (size_type)(mpEnd - mpBegin); + resize(offset + n); + return mpBegin + offset; + } + + void assign(const T *p1, const T *p2) { + resize(p2 - p1); + memcpy(mpBegin, p1, (char *)p2 - (char *)p1); + } + + void clear() { + mpEnd = mpBegin; + } + + iterator erase(iterator it) { + VDASSERT(it - mpBegin < mpEnd - mpBegin); + + memmove(it, it+1, (char *)mpEnd - (char *)(it+1)); + + --mpEnd; + + return it; + } + + iterator erase(iterator it1, iterator it2) { + VDASSERT(it1 - mpBegin <= mpEnd - mpBegin); + VDASSERT(it2 - mpBegin <= mpEnd - mpBegin); + VDASSERT(it1 <= it2); + + memmove(it1, it2, (char *)mpEnd - (char *)it2); + + mpEnd -= (it2 - it1); + + return it1; + } + + iterator insert(iterator it, const T& value) { + const T temp(value); // copy in case value is inside container. + + if (mpEnd == m.eos) { + difference_type delta = it - mpBegin; + _reserve_always_add_one(); + it = mpBegin + delta; + } + + memmove(it+1, it, sizeof(T) * (mpEnd - it)); + *it = temp; + ++mpEnd; + VDASSERT(mpEnd <= m.eos); + + return it; + } + + iterator insert(iterator it, size_type n, const T& value) { + const T temp(value); // copy in case value is inside container. + + ptrdiff_t bytesToInsert = n * sizeof(T); + + if ((char *)m.eos - (char *)mpEnd < bytesToInsert) { + difference_type delta = it - mpBegin; + _reserve_always_add(bytesToInsert); + it = mpBegin + delta; + } + + memmove((char *)it + bytesToInsert, it, (char *)mpEnd - (char *)it); + for(size_t i=0; i size_type((char *)m.eos - (char *)mpBegin)) + _reserve_always_amortized(n); + + mpEnd = mpBegin + n; + } + + void resize(size_type n, const T& value) { + const T temp(value); + + if (n*sizeof(T) > size_type((char *)m.eos - (char *)mpBegin)) { + _reserve_always_amortized(n); + } + + const iterator newEnd(mpBegin + n); + if (newEnd > mpEnd) + std::fill(mpEnd, newEnd, temp); + mpEnd = newEnd; + } + + void reserve(size_type n) { + if (n*sizeof(T) > size_type((char *)m.eos - (char *)mpBegin)) + _reserve_always(n); + } + +protected: +#ifdef _MSC_VER + __declspec(noinline) +#endif + void _reserve_always_add_one() { + _reserve_always((m.eos - mpBegin) * 2 + 1); + } + +#ifdef _MSC_VER + __declspec(noinline) +#endif + void _reserve_always_add(size_type n) { + _reserve_always((m.eos - mpBegin) * 2 + n); + } + +#ifdef _MSC_VER + __declspec(noinline) +#endif + void _reserve_always(size_type n) { + size_type oldSize = mpEnd - mpBegin; + T *oldStorage = mpBegin; + T *newStorage = m.allocate(n, NULL); + + memcpy(newStorage, mpBegin, (char *)mpEnd - (char *)mpBegin); + if (static_cast(m).is_deallocatable_storage(oldStorage)) + m.deallocate(oldStorage, m.eos - mpBegin); + mpBegin = newStorage; + mpEnd = newStorage + oldSize; + m.eos = newStorage + n; + } + +#ifdef _MSC_VER + __declspec(noinline) +#endif + void _reserve_always_amortized(size_type n) { + size_type nextCapacity = (size_type)((m.eos - mpBegin)*2); + + if (nextCapacity < n) + nextCapacity = n; + + _reserve_always(nextCapacity); + } + + struct : A, S { + T *eos; + } m; + + union TrivialObjectConstraint { + T m; + }; +}; + +/////////////////////////////////////////////////////////////////////////////// + +struct vdfastvector_storage { + bool is_deallocatable_storage(void *p) const { + return p != 0; + } +}; + +template > +class vdfastvector : public vdfastvector_base { +protected: + using vdfastvector_base::m; + using vdfastvector_base::mpBegin; + using vdfastvector_base::mpEnd; + +public: + typedef typename vdfastvector_base::value_type value_type; + typedef typename vdfastvector_base::pointer pointer; + typedef typename vdfastvector_base::const_pointer const_pointer; + typedef typename vdfastvector_base::reference reference; + typedef typename vdfastvector_base::const_reference const_reference; + typedef typename vdfastvector_base::size_type size_type; + typedef typename vdfastvector_base::difference_type difference_type; + typedef typename vdfastvector_base::iterator iterator; + typedef typename vdfastvector_base::const_iterator const_iterator; + typedef typename vdfastvector_base::reverse_iterator reverse_iterator; + typedef typename vdfastvector_base::const_reverse_iterator const_reverse_iterator; + + vdfastvector() { + m.eos = NULL; + } + + vdfastvector(size_type len) { + mpBegin = m.allocate(len, NULL); + mpEnd = mpBegin + len; + m.eos = mpEnd; + } + + vdfastvector(size_type len, const T& fill) { + mpBegin = m.allocate(len, NULL); + mpEnd = mpBegin + len; + m.eos = mpEnd; + + std::fill(mpBegin, mpEnd, fill); + } + + vdfastvector(const vdfastvector& x) { + size_type n = x.mpEnd - x.mpBegin; + mpBegin = m.allocate(n, NULL); + mpEnd = mpBegin + n; + m.eos = mpEnd; + memcpy(mpBegin, x.mpBegin, sizeof(T) * n); + } + + vdfastvector(const value_type *p, const value_type *q) { + m.eos = NULL; + + assign(p, q); + } + + vdfastvector& operator=(const vdfastvector& x) { + if (this != &x) + vdfastvector::assign(x.mpBegin, x.mpEnd); + + return *this; + } + + void swap(vdfastvector& x) { + std::swap(mpBegin, x.mpBegin); + std::swap(mpEnd, x.mpEnd); + std::swap(m.eos, x.m.eos); + } + + void swap(vdfastvector&& x) { + std::swap(mpBegin, x.mpBegin); + std::swap(mpEnd, x.mpEnd); + std::swap(m.eos, x.m.eos); + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +struct vdfastfixedvector_storage { + T mArray[N]; + + bool is_deallocatable_storage(void *p) const { + return p != mArray; + } +}; + +template > +class vdfastfixedvector : public vdfastvector_base, A> { +protected: + using vdfastvector_base, A>::mpBegin; + using vdfastvector_base, A>::mpEnd; + using vdfastvector_base, A>::m; + +public: + typedef typename vdfastvector_base, A>::value_type value_type; + typedef typename vdfastvector_base, A>::pointer pointer; + typedef typename vdfastvector_base, A>::const_pointer const_pointer; + typedef typename vdfastvector_base, A>::reference reference; + typedef typename vdfastvector_base, A>::const_reference const_reference; + typedef typename vdfastvector_base, A>::size_type size_type; + typedef typename vdfastvector_base, A>::difference_type difference_type; + typedef typename vdfastvector_base, A>::iterator iterator; + typedef typename vdfastvector_base, A>::const_iterator const_iterator; + typedef typename vdfastvector_base, A>::reverse_iterator reverse_iterator; + typedef typename vdfastvector_base, A>::const_reverse_iterator const_reverse_iterator; + + vdfastfixedvector() { + mpBegin = m.mArray; + mpEnd = m.mArray; + m.eos = m.mArray + N; + } + + vdfastfixedvector(size_type len) { + if (len <= N) { + mpBegin = m.mArray; + mpEnd = m.mArray + len; + m.eos = m.mArray + N; + } else { + mpBegin = m.allocate(len, NULL); + mpEnd = mpBegin + len; + m.eos = mpEnd; + } + } + + vdfastfixedvector(size_type len, const T& fill) { + mpBegin = m.allocate(len, NULL); + mpEnd = mpBegin + len; + m.eos = mpEnd; + + std::fill(mpBegin, mpEnd, fill); + } + + vdfastfixedvector(const vdfastfixedvector& x) { + size_type n = x.mpEnd - x.mpBegin; + + if (n <= N) { + mpBegin = m.mArray; + mpEnd = m.mArray + n; + m.eos = m.mArray + N; + } else { + mpBegin = m.allocate(n, NULL); + mpEnd = mpBegin + n; + m.eos = mpEnd; + } + + memcpy(mpBegin, x.mpBegin, sizeof(T) * n); + } + + vdfastfixedvector(const value_type *p, const value_type *q) { + mpBegin = m.mArray; + mpEnd = m.mArray; + m.eos = m.mArray + N; + + assign(p, q); + } + + vdfastfixedvector& operator=(const vdfastfixedvector& x) { + if (this != &x) + assign(x.mpBegin, x.mpEnd); + + return *this; + } + + void swap(vdfastfixedvector& x) { + size_t this_bytes = (char *)mpEnd - (char *)mpBegin; + size_t other_bytes = (char *)x.mpEnd - (char *)x.mpBegin; + + T *p; + + if (mpBegin == m.mArray) { + if (x.mpBegin == x.m.mArray) { + if (this_bytes < other_bytes) { + VDSwapMemory(m.mArray, x.m.mArray, this_bytes); + memcpy((char *)m.mArray + this_bytes, (char *)x.m.mArray + this_bytes, other_bytes - this_bytes); + } else { + VDSwapMemory(m.mArray, x.m.mArray, other_bytes); + memcpy((char *)m.mArray + other_bytes, (char *)x.m.mArray + other_bytes, this_bytes - other_bytes); + } + + mpEnd = (T *)((char *)mpBegin + other_bytes); + x.mpEnd = (T *)((char *)x.mpBegin + this_bytes); + } else { + memcpy(x.m.mArray, mpBegin, this_bytes); + + mpBegin = x.mpBegin; + mpEnd = x.mpEnd; + m.eos = x.m.eos; + + x.mpBegin = x.m.mArray; + x.mpEnd = (T *)((char *)x.m.mArray + this_bytes); + x.m.eos = x.m.mArray + N; + } + } else { + if (x.mpBegin == x.m.mArray) { + memcpy(x.m.mArray, mpBegin, other_bytes); + + x.mpBegin = mpBegin; + x.mpEnd = mpEnd; + x.m.eos = m.eos; + + mpBegin = m.mArray; + mpEnd = (T *)((char *)m.mArray + other_bytes); + m.eos = m.mArray + N; + } else { + p = mpBegin; mpBegin = x.mpBegin; x.mpBegin = p; + p = mpEnd; mpEnd = x.mpEnd; x.mpEnd = p; + p = m.eos; m.eos = x.m.eos; x.m.eos = p; + } + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +struct vdfastdeque_block { + enum { + kBlockSize = 32, + kBlockSizeBits = 5 + }; + + T data[kBlockSize]; +}; + +template +class vdfastdeque_iterator { +public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + vdfastdeque_iterator(const vdfastdeque_iterator&); + vdfastdeque_iterator(vdfastdeque_block **pMapEntry, uint32 index); + + T& operator *() const; + T& operator ->() const; + vdfastdeque_iterator& operator++(); + vdfastdeque_iterator operator++(int); + vdfastdeque_iterator& operator--(); + vdfastdeque_iterator operator--(int); + +public: + vdfastdeque_block **mpMap; + vdfastdeque_block *mpBlock; + uint32 mIndex; +}; + +template +vdfastdeque_iterator::vdfastdeque_iterator(const vdfastdeque_iterator& x) + : mpMap(x.mpMap) + , mpBlock(x.mpBlock) + , mIndex(x.mIndex) +{ +} + +template +vdfastdeque_iterator::vdfastdeque_iterator(vdfastdeque_block **pMapEntry, uint32 index) + : mpMap(pMapEntry) + , mpBlock(mpMap ? *mpMap : NULL) + , mIndex(index) +{ +} + +template +T& vdfastdeque_iterator::operator *() const { + return mpBlock->data[mIndex]; +} + +template +T& vdfastdeque_iterator::operator ->() const { + return mpBlock->data[mIndex]; +} + +template +vdfastdeque_iterator& vdfastdeque_iterator::operator++() { + if (++mIndex >= vdfastdeque_block::kBlockSize) { + mIndex = 0; + mpBlock = *++mpMap; + } + return *this; +} + +template +vdfastdeque_iterator vdfastdeque_iterator::operator++(int) { + vdfastdeque_iterator r(*this); + operator++(); + return r; +} + +template +vdfastdeque_iterator& vdfastdeque_iterator::operator--() { + if (mIndex-- == 0) { + mIndex = vdfastdeque_block::kBlockSize - 1; + mpBlock = *--mpMap; + } + return *this; +} + +template +vdfastdeque_iterator vdfastdeque_iterator::operator--(int) { + vdfastdeque_iterator r(*this); + operator--(); + return r; +} + +template +bool operator==(const vdfastdeque_iterator& x,const vdfastdeque_iterator& y) { + return x.mpBlock == y.mpBlock && x.mIndex == y.mIndex; +} + +template +bool operator!=(const vdfastdeque_iterator& x,const vdfastdeque_iterator& y) { + return x.mpBlock != y.mpBlock || x.mIndex != y.mIndex; +} + +/////////////////////////////////////////////////////////////////////////////// + +template > +class vdfastdeque { +public: + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef T value_type; + typedef A allocator_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef vdfastdeque_iterator iterator; + typedef vdfastdeque_iterator const_iterator; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + vdfastdeque(); + ~vdfastdeque(); + + bool empty() const; + size_type size() const; + + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + reference operator[](size_type n); + const_reference operator[](size_type n) const; + + void clear(); + + reference push_back(); + void push_back(const_reference x); + + void pop_front(); + void pop_back(); + + void swap(vdfastdeque& x); + +protected: + void push_back_extend(); + void validate(); + + typedef vdfastdeque_block Block; + + enum { + kBlockSize = Block::kBlockSize, + kBlockSizeBits = Block::kBlockSizeBits + }; + + struct M1 : public A::template rebind::other { + Block **mapStartAlloc; // start of map + Block **mapStartCommit; // start of range of allocated blocks + Block **mapStart; // start of range of active blocks + Block **mapEnd; // end of range of active blocks + Block **mapEndCommit; // end of range of allocated blocks + Block **mapEndAlloc; // end of map + } m; + + struct M2 : public A::template rebind::other { + int startIndex; + int endIndex; + } mTails; + + union TrivialObjectConstraint { + T obj; + }; +}; + +template +vdfastdeque::vdfastdeque() { + m.mapStartAlloc = NULL; + m.mapStartCommit = NULL; + m.mapStart = NULL; + m.mapEnd = NULL; + m.mapEndCommit = NULL; + m.mapEndAlloc = NULL; + mTails.startIndex = 0; + mTails.endIndex = kBlockSize - 1; +} + +template +vdfastdeque::~vdfastdeque() { + while(m.mapStartCommit != m.mapEndCommit) { + mTails.deallocate(*m.mapStartCommit++, 1); + } + + if (m.mapStartAlloc) + m.deallocate(m.mapStartAlloc, m.mapEndAlloc - m.mapStartAlloc); +} + +template +bool vdfastdeque::empty() const { + return size() == 0; +} + +template +typename vdfastdeque::size_type vdfastdeque::size() const { + if (m.mapEnd == m.mapStart) + return 0; + + return kBlockSize * ((m.mapEnd - m.mapStart) - 1) + (mTails.endIndex + 1) - mTails.startIndex; +} + +template +typename vdfastdeque::reference vdfastdeque::front() { + VDASSERT(m.mapStart != m.mapEnd); + return (*m.mapStart)->data[mTails.startIndex]; +} + +template +typename vdfastdeque::const_reference vdfastdeque::front() const { + VDASSERT(m.mapStart != m.mapEnd); + return (*m.mapStart)->data[mTails.startIndex]; +} + +template +typename vdfastdeque::reference vdfastdeque::back() { + VDASSERT(m.mapStart != m.mapEnd); + return m.mapEnd[-1]->data[mTails.endIndex]; +} + +template +typename vdfastdeque::const_reference vdfastdeque::back() const { + VDASSERT(m.mapStart != m.mapEnd); + return m.mapEnd[-1]->data[mTails.endIndex]; +} + +template +typename vdfastdeque::iterator vdfastdeque::begin() { + return iterator(m.mapStart, mTails.startIndex); +} + +template +typename vdfastdeque::const_iterator vdfastdeque::begin() const { + return const_iterator(m.mapStart, mTails.startIndex); +} + +template +typename vdfastdeque::iterator vdfastdeque::end() { + if (mTails.endIndex == kBlockSize - 1) + return iterator(m.mapEnd, 0); + else + return iterator(m.mapEnd - 1, mTails.endIndex + 1); +} + +template +typename vdfastdeque::const_iterator vdfastdeque::end() const { + if (mTails.endIndex == kBlockSize - 1) + return const_iterator(m.mapEnd, 0); + else + return const_iterator(m.mapEnd - 1, mTails.endIndex + 1); +} + +template +typename vdfastdeque::reference vdfastdeque::operator[](size_type n) { + n += mTails.startIndex; + return m.mapStart[n >> kBlockSizeBits]->data[n & (kBlockSize - 1)]; +} + +template +typename vdfastdeque::const_reference vdfastdeque::operator[](size_type n) const { + n += mTails.startIndex; + return m.mapStart[n >> kBlockSizeBits]->data[n & (kBlockSize - 1)]; +} + +template +void vdfastdeque::clear() { + m.mapEnd = m.mapStart; + mTails.startIndex = 0; + mTails.endIndex = kBlockSize - 1; +} + +template +typename vdfastdeque::reference vdfastdeque::push_back() { + if (mTails.endIndex >= kBlockSize - 1) { + push_back_extend(); + + mTails.endIndex = -1; + } + + ++mTails.endIndex; + + VDASSERT(m.mapEnd[-1]); + reference r = m.mapEnd[-1]->data[mTails.endIndex]; + return r; +} + +template +void vdfastdeque::push_back(const_reference x) { + const T x2(x); + push_back() = x2; +} + +template +void vdfastdeque::pop_front() { + if (++mTails.startIndex >= kBlockSize) { + VDASSERT(m.mapEnd != m.mapStart); + mTails.startIndex = 0; + ++m.mapStart; + } +} + +template +void vdfastdeque::pop_back() { + if (--mTails.endIndex < 0) { + VDASSERT(m.mapEnd != m.mapStart); + mTails.endIndex = kBlockSize - 1; + --m.mapEnd; + } +} + +template +void vdfastdeque::swap(vdfastdeque& x) { + std::swap(m.mapStartAlloc, x.m.mapStartAlloc); + std::swap(m.mapStartCommit, x.m.mapStartCommit); + std::swap(m.mapStart, x.m.mapStart); + std::swap(m.mapEnd, x.m.mapEnd); + std::swap(m.mapEndCommit, x.m.mapEndCommit); + std::swap(m.mapEndAlloc, x.m.mapEndAlloc); + std::swap(mTails.startIndex, x.mTails.startIndex); + std::swap(mTails.endIndex, x.mTails.endIndex); +} + +///////////////////////////////// + +template +void vdfastdeque::push_back_extend() { + validate(); + + // check if we need to extend the map itself + if (m.mapEnd == m.mapEndAlloc) { + // can we just shift the map? + size_type currentMapSize = m.mapEndAlloc - m.mapStartAlloc; + size_type freeAtStart = m.mapStartCommit - m.mapStartAlloc; + + if (freeAtStart >= 2 && (freeAtStart + freeAtStart) >= currentMapSize) { + size_type shiftDistance = freeAtStart >> 1; + + VDASSERT(!m.mapStartAlloc[0]); + memmove(m.mapStartAlloc, m.mapStartAlloc + shiftDistance, sizeof(Block *) * (currentMapSize - shiftDistance)); + memset(m.mapStartAlloc + (currentMapSize - shiftDistance), 0, shiftDistance * sizeof(Block *)); + + // relocate pointers + m.mapEndCommit -= shiftDistance; + m.mapEnd -= shiftDistance; + m.mapStart -= shiftDistance; + m.mapStartCommit -= shiftDistance; + validate(); + } else { + size_type newMapSize = currentMapSize*2+1; + + Block **newMap = m.allocate(newMapSize); + + memcpy(newMap, m.mapStartAlloc, currentMapSize * sizeof(Block *)); + memset(newMap + currentMapSize, 0, (newMapSize - currentMapSize) * sizeof(Block *)); + + // relocate pointers + m.mapEndAlloc = newMap + newMapSize; + m.mapEndCommit = newMap + (m.mapEndCommit - m.mapStartAlloc); + m.mapEnd = newMap + (m.mapEnd - m.mapStartAlloc); + m.mapStart = newMap + (m.mapStart - m.mapStartAlloc); + m.mapStartCommit = newMap + (m.mapStartCommit - m.mapStartAlloc); + + m.deallocate(m.mapStartAlloc, currentMapSize); + m.mapStartAlloc = newMap; + validate(); + } + } + + VDASSERT(m.mapEnd != m.mapEndAlloc); + + // check if we already have a block we can use + if (*m.mapEnd) { + ++m.mapEnd; + validate(); + return; + } + + // check if we can steal a block from the beginning + if (m.mapStartCommit != m.mapStart) { + VDASSERT(*m.mapStartCommit); + if (m.mapStartCommit != m.mapEnd) { + *m.mapEnd = *m.mapStartCommit; + *m.mapStartCommit = NULL; + ++m.mapStartCommit; + } + ++m.mapEnd; + m.mapEndCommit = m.mapEnd; + validate(); + return; + } + + // allocate a new block + *m.mapEnd = mTails.allocate(1); + ++m.mapEnd; + m.mapEndCommit = m.mapEnd; + validate(); +} + +template +void vdfastdeque::validate() { + VDASSERT(m.mapStartAlloc <= m.mapStartCommit); + VDASSERT(m.mapStartCommit <= m.mapStart); + VDASSERT(m.mapStart <= m.mapEnd); + VDASSERT(m.mapEnd <= m.mapEndCommit); + VDASSERT(m.mapEndCommit <= m.mapEndAlloc); + + VDASSERT(m.mapStartAlloc == m.mapStartCommit || !*m.mapStartAlloc); + VDASSERT(m.mapStartCommit == m.mapEndCommit || m.mapStartCommit[0]); + VDASSERT(m.mapStart == m.mapEnd || (m.mapStart[0] && m.mapEnd[-1])); + VDASSERT(m.mapEndCommit == m.mapEndAlloc || !m.mapEndCommit[0]); +} + +#include +#include +#include + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hash.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hash.h index e7ad59dd54e..1f18c7470ca 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hash.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hash.h @@ -1,140 +1,140 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_HASH_H -#define f_VD2_SYSTEM_VDSTL_HASH_H - -#include - -/////////////////////////////////////////////////////////////////////////////// -// vdhash -// -// Differences from TR1: -// -// - We omit the hash for long double, as that's not really useful, esp. on -// Windows. - -template struct vdhash; - -#define VDSTL_DECLARE_STANDARD_HASH(T) \ - template<> struct vdhash { \ - size_t operator()(T val) const { return (size_t)val; } \ - }; - -VDSTL_DECLARE_STANDARD_HASH(char); -VDSTL_DECLARE_STANDARD_HASH(signed char); -VDSTL_DECLARE_STANDARD_HASH(unsigned char); -VDSTL_DECLARE_STANDARD_HASH(wchar_t); -VDSTL_DECLARE_STANDARD_HASH(short); -VDSTL_DECLARE_STANDARD_HASH(unsigned short); -VDSTL_DECLARE_STANDARD_HASH(int); -VDSTL_DECLARE_STANDARD_HASH(unsigned int); -VDSTL_DECLARE_STANDARD_HASH(long); -VDSTL_DECLARE_STANDARD_HASH(unsigned long); -VDSTL_DECLARE_STANDARD_HASH(long long); -VDSTL_DECLARE_STANDARD_HASH(unsigned long long); - -template<> struct vdhash { - size_t operator()(float v) const { - const union { float f; sint32 i; } conv = {v}; - - uint32 i = conv.i; - - // Denormals and infinities are unique encodings and work as-is. NaNs work - // because they never compare equal to anything else, so their hash value - // can be arbitrary. Zero and negative zero, however, compare equal. - if (i == 0x80000000) - i = 0; - - return i; - } -}; - -template<> struct vdhash { - size_t operator()(double v) const { - const union conv { double f; sint64 i; } conv = {v}; - - uint64 i = conv.i; - - // Denormals and infinities are unique encodings and work as-is. NaNs work - // because they never compare equal to anything else, so their hash value - // can be arbitrary. Zero and negative zero, however, compare equal. - if (i == 0x8000000000000000ULL) - i = 0; - - if constexpr (sizeof(size_t) < 8) - return (size_t)((i >> 32) ^ i); - else - return (size_t)i; - } -}; - -#undef VDSTL_DECLARE_STANDARD_HASH - -class VDStringA; -class VDStringSpanA; -class VDStringW; -class VDStringSpanW; - -template<> struct vdhash { - size_t operator()(const VDStringA& s) const; - size_t operator()(const char *s) const; -}; - -template<> struct vdhash { - size_t operator()(const VDStringW& s) const; - size_t operator()(const wchar_t *s) const; -}; - -template struct vdhash { - size_t operator()(T *val) const { return (size_t)val; } -}; - -struct vdstringhashi { - size_t operator()(const VDStringA& s) const; - size_t operator()(const char *s) const; - size_t operator()(const VDStringW& s) const; - size_t operator()(const wchar_t *s) const; -}; - -struct vdstringpred { - bool operator()(const VDStringA& s, const VDStringA& t) const; - bool operator()(const VDStringA& s, const VDStringSpanA& t) const; - bool operator()(const VDStringA& s, const char *t) const; - bool operator()(const VDStringW& s, const VDStringW& t) const; - bool operator()(const VDStringW& s, const VDStringSpanW& t) const; - bool operator()(const VDStringW& s, const wchar_t *t) const; -}; - -struct vdstringpredi { - bool operator()(const VDStringA& s, const VDStringA& t) const; - bool operator()(const VDStringA& s, const VDStringSpanA& t) const; - bool operator()(const VDStringA& s, const char *t) const; - bool operator()(const VDStringW& s, const VDStringW& t) const; - bool operator()(const VDStringW& s, const VDStringSpanW& t) const; - bool operator()(const VDStringW& s, const wchar_t *t) const; -}; - -#endif // f_VD2_SYSTEM_VDSTL_HASH_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_HASH_H +#define f_VD2_SYSTEM_VDSTL_HASH_H + +#include + +/////////////////////////////////////////////////////////////////////////////// +// vdhash +// +// Differences from TR1: +// +// - We omit the hash for long double, as that's not really useful, esp. on +// Windows. + +template struct vdhash; + +#define VDSTL_DECLARE_STANDARD_HASH(T) \ + template<> struct vdhash { \ + size_t operator()(T val) const { return (size_t)val; } \ + }; + +VDSTL_DECLARE_STANDARD_HASH(char); +VDSTL_DECLARE_STANDARD_HASH(signed char); +VDSTL_DECLARE_STANDARD_HASH(unsigned char); +VDSTL_DECLARE_STANDARD_HASH(wchar_t); +VDSTL_DECLARE_STANDARD_HASH(short); +VDSTL_DECLARE_STANDARD_HASH(unsigned short); +VDSTL_DECLARE_STANDARD_HASH(int); +VDSTL_DECLARE_STANDARD_HASH(unsigned int); +VDSTL_DECLARE_STANDARD_HASH(long); +VDSTL_DECLARE_STANDARD_HASH(unsigned long); +VDSTL_DECLARE_STANDARD_HASH(long long); +VDSTL_DECLARE_STANDARD_HASH(unsigned long long); + +template<> struct vdhash { + size_t operator()(float v) const { + const union { float f; sint32 i; } conv = {v}; + + uint32 i = conv.i; + + // Denormals and infinities are unique encodings and work as-is. NaNs work + // because they never compare equal to anything else, so their hash value + // can be arbitrary. Zero and negative zero, however, compare equal. + if (i == 0x80000000) + i = 0; + + return i; + } +}; + +template<> struct vdhash { + size_t operator()(double v) const { + const union conv { double f; sint64 i; } conv = {v}; + + uint64 i = conv.i; + + // Denormals and infinities are unique encodings and work as-is. NaNs work + // because they never compare equal to anything else, so their hash value + // can be arbitrary. Zero and negative zero, however, compare equal. + if (i == 0x8000000000000000ULL) + i = 0; + + if constexpr (sizeof(size_t) < 8) + return (size_t)((i >> 32) ^ i); + else + return (size_t)i; + } +}; + +#undef VDSTL_DECLARE_STANDARD_HASH + +class VDStringA; +class VDStringSpanA; +class VDStringW; +class VDStringSpanW; + +template<> struct vdhash { + size_t operator()(const VDStringA& s) const; + size_t operator()(const char *s) const; +}; + +template<> struct vdhash { + size_t operator()(const VDStringW& s) const; + size_t operator()(const wchar_t *s) const; +}; + +template struct vdhash { + size_t operator()(T *val) const { return (size_t)val; } +}; + +struct vdstringhashi { + size_t operator()(const VDStringA& s) const; + size_t operator()(const char *s) const; + size_t operator()(const VDStringW& s) const; + size_t operator()(const wchar_t *s) const; +}; + +struct vdstringpred { + bool operator()(const VDStringA& s, const VDStringA& t) const; + bool operator()(const VDStringA& s, const VDStringSpanA& t) const; + bool operator()(const VDStringA& s, const char *t) const; + bool operator()(const VDStringW& s, const VDStringW& t) const; + bool operator()(const VDStringW& s, const VDStringSpanW& t) const; + bool operator()(const VDStringW& s, const wchar_t *t) const; +}; + +struct vdstringpredi { + bool operator()(const VDStringA& s, const VDStringA& t) const; + bool operator()(const VDStringA& s, const VDStringSpanA& t) const; + bool operator()(const VDStringA& s, const char *t) const; + bool operator()(const VDStringW& s, const VDStringW& t) const; + bool operator()(const VDStringW& s, const VDStringSpanW& t) const; + bool operator()(const VDStringW& s, const wchar_t *t) const; +}; + +#endif // f_VD2_SYSTEM_VDSTL_HASH_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashmap.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashmap.h index 9bcf1c60fd2..6a7ae900c20 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashmap.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashmap.h @@ -1,604 +1,604 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_HASHMAP_H -#define f_VD2_SYSTEM_VDSTL_HASHMAP_H - -#include -#include -#include - -template, class Pred = std::equal_to, class A = std::allocator > > > -class vdhashmap : public vdhashtable > { -protected: - using vdhashtable >::mpBucketStart; - using vdhashtable >::mpBucketEnd; - using vdhashtable >::mBucketCount; - using vdhashtable >::mElementCount; - using vdhashtable >::sEmptyBucket; - -public: - typedef typename vdhashtable >::node_type node_type; - typedef typename vdhashtable >::value_type value_type; - typedef typename vdhashtable >::size_type size_type; - typedef typename vdhashtable >::difference_type difference_type; - typedef typename vdhashtable >::pointer pointer; - typedef typename vdhashtable >::const_pointer const_pointer; - typedef typename vdhashtable >::reference reference; - typedef typename vdhashtable >::const_reference const_reference; - typedef typename vdhashtable >::iterator iterator; - typedef typename vdhashtable >::const_iterator const_iterator; - typedef typename vdhashtable >::local_iterator local_iterator; - typedef typename vdhashtable >::const_local_iterator const_local_iterator; - typedef K key_type; - typedef V mapped_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef A allocator_type; - typedef std::pair insert_return_type; - - vdhashmap(); - vdhashmap(const vdhashmap&); - ~vdhashmap(); - - vdhashmap& operator=(const vdhashmap&); - - mapped_type& operator[](const K& key); - - allocator_type get_allocator() const; - - // iterators - using vdhashtable::begin; - using vdhashtable::end; -// iterator begin(); Inherited. -// const_iterator begin() const; Inherited. -// iterator end(); Inherited. -// const_iterator end() const; Inherited. - - // modifiers - insert_return_type insert(const key_type& key); - insert_return_type insert(const std::pair& obj); -// iterator insert(iterator hint, const value_type& obj); // TODO -// const_iterator insert(const_iterator hint, const value_type& obj); // TODO - - template - insert_return_type insert_as(const U& k); // extension - - iterator erase(iterator position); - const_iterator erase(const_iterator position); - size_type erase(const key_type& k); -// iterator erase(iterator first, iterator last); // TODO -// const_iterator erase(const_iterator first, const_iterator last); // TODO - void clear(); - - // observers - hasher hash_function() const; - key_equal key_eq() const; - - // lookup - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; - size_type count(const key_type& k) const; - std::pair equal_range(const key_type& k); - std::pair equal_range(const key_type& k) const; - - // lookup (extensions) - template - iterator find_as(const U& k); - - template - const_iterator find_as(const U& k) const; - - // bucket interface -// size_type bucket_count() const; Inherited. -// size_type max_bucket_count() const; Inherited. -// size_type bucket_size(size_type n) const; Inherited. - size_type bucket(const key_type& k) const; - local_iterator begin(size_type n); - const_local_iterator begin(size_type n) const; - local_iterator end(size_type n); - const_local_iterator end(size_type n) const; - - // hash policy -// float load_factor() const; // TODO -// float max_load_factor() const; // TODO -// void max_load_factor(float z); // TODO - void rehash(size_type n); - -protected: - void rehash_to_size(size_type n); - void reset(); - - A mAllocator; - typename A::template rebind::other mBucketAllocator; - Hash mHasher; - Pred mPred; -}; - -template -vdhashmap::vdhashmap() { -} - -template -vdhashmap::vdhashmap(const vdhashmap& src) - : mHasher(src.mHasher) - , mPred(src.mPred) -{ - rehash_to_size(src.mElementCount); - - try { - for(vdhashtable_base_node **bucket = mpBucketStart; bucket != mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - insert(node->mData); - - p = next; - } - - *bucket = NULL; - } - } catch(...) { - reset(); - throw; - } -} - -template -vdhashmap::~vdhashmap() { - reset(); -} - -template -vdhashmap& vdhashmap::operator=(const vdhashmap& src) { - if (&src != this) { - clear(); - - mHasher = src.mHasher; - mPred = src.mPred; - - for(vdhashtable_base_node **bucket = src.mpBucketStart; bucket != src.mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - insert(node->mData); - - p = next; - } - - *bucket = NULL; - } - } - - return *this; -} - -template -typename vdhashmap::mapped_type& vdhashmap::operator[](const K& key) { - return insert(key).first->second; -} - -template -typename vdhashmap::allocator_type vdhashmap::get_allocator() const { - return A(); -} - -// modifiers -template -typename vdhashmap::insert_return_type vdhashmap::insert(const key_type& key) { - if (mElementCount >= mBucketCount) - rehash_to_size(mElementCount + 1); - - size_type bucket = mHasher(key) % mBucketCount; - - for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { - if (mPred(p->mData.first, key)) - return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); - } - - node_type *node = mAllocator.allocate(1); - try { - new(node) node_type(static_cast(mpBucketStart[bucket]), value_type(key, V())); - } catch(...) { - mAllocator.deallocate(node, 1); - throw; - } - - mpBucketStart[bucket] = node; - ++mElementCount; - - return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); -} - -template -typename vdhashmap::insert_return_type vdhashmap::insert(const std::pair& obj) { - if (mElementCount >= mBucketCount) - rehash_to_size(mElementCount + 1); - - size_type bucket = mHasher(obj.first) % mBucketCount; - - for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { - if (mPred(p->mData.first, obj.first)) - return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); - } - - node_type *node = mAllocator.allocate(1); - try { - new(node) node_type(static_cast(mpBucketStart[bucket]), obj); - } catch(...) { - mAllocator.deallocate(node, 1); - throw; - } - - mpBucketStart[bucket] = node; - ++mElementCount; - - return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); -} - -template -template -typename vdhashmap::insert_return_type vdhashmap::insert_as(const U& key) { - if (mElementCount >= mBucketCount) - rehash_to_size(mElementCount + 1); - - size_type bucket = mHasher(key) % mBucketCount; - - for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { - if (mPred(p->mData.first, key)) - return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); - } - - node_type *node = mAllocator.allocate(1); - try { - new(node) node_type(static_cast(mpBucketStart[bucket])); - - try { - node->mData.first = key; - } catch(...) { - node->~node_type(); - } - - } catch(...) { - mAllocator.deallocate(node, 1); - throw; - } - - mpBucketStart[bucket] = node; - ++mElementCount; - - return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); -} - -template -typename vdhashmap::iterator vdhashmap::erase(iterator position) { - size_type bucket = mHasher(position->first) % mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = mpBucketStart[bucket]; - - while(&static_cast(p)->mData != &*position) { - prev = p; - p = p->mpHashNext; - } - - vdhashtable_base_node *next = p->mpHashNext; - if (prev) - prev->mpHashNext = next; - else - mpBucketStart[bucket] = next; - - node_type *node = static_cast(p); - node->~node_type(); - mAllocator.deallocate(node, 1); - --mElementCount; - - return iterator(next, &mpBucketStart[bucket], mpBucketEnd); -} - -template -typename vdhashmap::const_iterator vdhashmap::erase(const_iterator position) { - size_type bucket = mHasher(position->first) % mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = mpBucketStart[bucket]; - - while(&static_cast(p)->mData != &*position) { - prev = p; - p = p->mpHashNext; - } - - vdhashtable_base_node *next = p->mpHashNext; - if (prev) - prev->mpHashNext = next; - else - mpBucketStart[bucket] = next; - - node_type *node = static_cast(p); - node->~node_type(); - mAllocator.deallocate(node, 1); - --mElementCount; - - return const_iterator(next, &mpBucketStart[bucket], mpBucketEnd); -} - -template -typename vdhashmap::size_type vdhashmap::erase(const key_type& k) { - if (!mBucketCount) - return 0; - - size_type bucket = mHasher(k) % mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = mpBucketStart[bucket]; - - while(p) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) { - vdhashtable_base_node *next = p->mpHashNext; - - if (prev) - prev->mpHashNext = next; - else - mpBucketStart[bucket] = next; - - node->~node_type(); - mAllocator.deallocate(node, 1); - --mElementCount; - return 1; - } - - prev = p; - p = p->mpHashNext; - } - - return 0; -} - -template -void vdhashmap::clear() { - for(vdhashtable_base_node **bucket = mpBucketStart; bucket != mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - node->~node_type(); - - mAllocator.deallocate(node, 1); - - p = next; - } - - *bucket = NULL; - } - - mElementCount = 0; -} - -// observers -template -typename vdhashmap::hasher vdhashmap::hash_function() const { - return mHasher; -} - -template -typename vdhashmap::key_equal vdhashmap::key_eq() const { - return mPred; -} - -// lookup -template -typename vdhashmap::iterator vdhashmap::find(const key_type& k) { - if (!mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % mBucketCount; - - for(vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return iterator(node, &mpBucketStart[bucket], mpBucketEnd); - } - - return iterator(); -} - -template -typename vdhashmap::const_iterator vdhashmap::find(const key_type& k) const { - if (!mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % mBucketCount; - - for(const vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { - const node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return const_iterator(const_cast(static_cast(node)), &mpBucketStart[bucket], mpBucketEnd); - } - - return iterator(); -} - -template -typename vdhashmap::size_type vdhashmap::count(const key_type& k) const { - return find(k) != end() ? 1 : 0; -} - -template -std::pair::iterator, typename vdhashmap::iterator> vdhashmap::equal_range(const key_type& k) { - iterator it = find(k); - iterator itEnd; - - if (it == itEnd) - return std::make_pair(itEnd, itEnd); - - itEnd = it; - ++itEnd; - - return std::make_pair(); -} - -template -std::pair::const_iterator, typename vdhashmap::const_iterator> vdhashmap::equal_range(const key_type& k) const { - const_iterator it = find(k); - const_iterator itEnd; - - if (it == itEnd) - return std::make_pair(itEnd, itEnd); - - itEnd = it; - ++itEnd; - - return std::make_pair(it, itEnd); -} - -template -template -typename vdhashmap::iterator vdhashmap::find_as(const U& k) { - if (!mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % mBucketCount; - - for(vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return iterator(node, &mpBucketStart[bucket], mpBucketEnd); - } - - return iterator(); -} - -template -template -typename vdhashmap::const_iterator vdhashmap::find_as(const U& k) const { - if (!mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % mBucketCount; - - for(const vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { - const node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return const_iterator(const_cast(static_cast(node)), &mpBucketStart[bucket], mpBucketEnd); - } - - return iterator(); -} - -// bucket interface -template -typename vdhashmap::size_type vdhashmap::bucket(const key_type& k) const { - size_type bucket = 0; - - if (mBucketCount) - bucket = mHasher(k) % mBucketCount; - - return bucket; -} - -template -typename vdhashmap::local_iterator vdhashmap::begin(size_type n) { - return local_iterator(mpBucketStart[n]); -} - -template -typename vdhashmap::const_local_iterator vdhashmap::begin(size_type n) const { - return const_local_iterator(mpBucketStart[n]); -} - -template -typename vdhashmap::local_iterator vdhashmap::end(size_type n) { - return local_iterator(NULL); -} - -template -typename vdhashmap::const_local_iterator vdhashmap::end(size_type n) const { - return const_local_iterator(NULL); -} - -// hash policy -template -void vdhashmap::rehash(size_type n) { - if (!n) - n = 1; - - if (mBucketCount == n) - return; - - vdhashtable_base_node **newBuckets = mBucketAllocator.allocate(n + 1); - - for(size_type i=0; i<=n; ++i) - newBuckets[i] = NULL; - - const size_type m = mBucketCount; - for(size_type i=0; impHashNext; - const value_type& vt = static_cast *>(p)->mData; - size_t bucket = mHasher(vt.first) % n; - - vdhashtable_base_node *head = newBuckets[bucket]; - - p->mpHashNext = head; - newBuckets[bucket] = p; - - p = next; - } - } - - if (mpBucketStart != &sEmptyBucket) - mBucketAllocator.deallocate(mpBucketStart, (mpBucketEnd - mpBucketStart) + 1); - - mpBucketStart = newBuckets; - mpBucketEnd = newBuckets + n; - mBucketCount = n; -} - -template -void vdhashmap::rehash_to_size(size_type n) { - size_type buckets = vdhashtable_base::compute_bucket_count(n); - rehash(buckets); -} - -template -void vdhashmap::reset() { - clear(); - - if (mpBucketStart != &sEmptyBucket) - mBucketAllocator.deallocate(mpBucketStart, (mpBucketEnd - mpBucketStart) + 1); -} - -#endif // f_VD2_SYSTEM_VDSTL_HASHMAP_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_HASHMAP_H +#define f_VD2_SYSTEM_VDSTL_HASHMAP_H + +#include +#include +#include + +template, class Pred = std::equal_to, class A = std::allocator > > > +class vdhashmap : public vdhashtable > { +protected: + using vdhashtable >::mpBucketStart; + using vdhashtable >::mpBucketEnd; + using vdhashtable >::mBucketCount; + using vdhashtable >::mElementCount; + using vdhashtable >::sEmptyBucket; + +public: + typedef typename vdhashtable >::node_type node_type; + typedef typename vdhashtable >::value_type value_type; + typedef typename vdhashtable >::size_type size_type; + typedef typename vdhashtable >::difference_type difference_type; + typedef typename vdhashtable >::pointer pointer; + typedef typename vdhashtable >::const_pointer const_pointer; + typedef typename vdhashtable >::reference reference; + typedef typename vdhashtable >::const_reference const_reference; + typedef typename vdhashtable >::iterator iterator; + typedef typename vdhashtable >::const_iterator const_iterator; + typedef typename vdhashtable >::local_iterator local_iterator; + typedef typename vdhashtable >::const_local_iterator const_local_iterator; + typedef K key_type; + typedef V mapped_type; + typedef Hash hasher; + typedef Pred key_equal; + typedef A allocator_type; + typedef std::pair insert_return_type; + + vdhashmap(); + vdhashmap(const vdhashmap&); + ~vdhashmap(); + + vdhashmap& operator=(const vdhashmap&); + + mapped_type& operator[](const K& key); + + allocator_type get_allocator() const; + + // iterators + using vdhashtable::begin; + using vdhashtable::end; +// iterator begin(); Inherited. +// const_iterator begin() const; Inherited. +// iterator end(); Inherited. +// const_iterator end() const; Inherited. + + // modifiers + insert_return_type insert(const key_type& key); + insert_return_type insert(const std::pair& obj); +// iterator insert(iterator hint, const value_type& obj); // TODO +// const_iterator insert(const_iterator hint, const value_type& obj); // TODO + + template + insert_return_type insert_as(const U& k); // extension + + iterator erase(iterator position); + const_iterator erase(const_iterator position); + size_type erase(const key_type& k); +// iterator erase(iterator first, iterator last); // TODO +// const_iterator erase(const_iterator first, const_iterator last); // TODO + void clear(); + + // observers + hasher hash_function() const; + key_equal key_eq() const; + + // lookup + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + size_type count(const key_type& k) const; + std::pair equal_range(const key_type& k); + std::pair equal_range(const key_type& k) const; + + // lookup (extensions) + template + iterator find_as(const U& k); + + template + const_iterator find_as(const U& k) const; + + // bucket interface +// size_type bucket_count() const; Inherited. +// size_type max_bucket_count() const; Inherited. +// size_type bucket_size(size_type n) const; Inherited. + size_type bucket(const key_type& k) const; + local_iterator begin(size_type n); + const_local_iterator begin(size_type n) const; + local_iterator end(size_type n); + const_local_iterator end(size_type n) const; + + // hash policy +// float load_factor() const; // TODO +// float max_load_factor() const; // TODO +// void max_load_factor(float z); // TODO + void rehash(size_type n); + +protected: + void rehash_to_size(size_type n); + void reset(); + + A mAllocator; + typename A::template rebind::other mBucketAllocator; + Hash mHasher; + Pred mPred; +}; + +template +vdhashmap::vdhashmap() { +} + +template +vdhashmap::vdhashmap(const vdhashmap& src) + : mHasher(src.mHasher) + , mPred(src.mPred) +{ + rehash_to_size(src.mElementCount); + + try { + for(vdhashtable_base_node **bucket = mpBucketStart; bucket != mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + insert(node->mData); + + p = next; + } + + *bucket = NULL; + } + } catch(...) { + reset(); + throw; + } +} + +template +vdhashmap::~vdhashmap() { + reset(); +} + +template +vdhashmap& vdhashmap::operator=(const vdhashmap& src) { + if (&src != this) { + clear(); + + mHasher = src.mHasher; + mPred = src.mPred; + + for(vdhashtable_base_node **bucket = src.mpBucketStart; bucket != src.mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + insert(node->mData); + + p = next; + } + + *bucket = NULL; + } + } + + return *this; +} + +template +typename vdhashmap::mapped_type& vdhashmap::operator[](const K& key) { + return insert(key).first->second; +} + +template +typename vdhashmap::allocator_type vdhashmap::get_allocator() const { + return A(); +} + +// modifiers +template +typename vdhashmap::insert_return_type vdhashmap::insert(const key_type& key) { + if (mElementCount >= mBucketCount) + rehash_to_size(mElementCount + 1); + + size_type bucket = mHasher(key) % mBucketCount; + + for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { + if (mPred(p->mData.first, key)) + return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); + } + + node_type *node = mAllocator.allocate(1); + try { + new(node) node_type(static_cast(mpBucketStart[bucket]), value_type(key, V())); + } catch(...) { + mAllocator.deallocate(node, 1); + throw; + } + + mpBucketStart[bucket] = node; + ++mElementCount; + + return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); +} + +template +typename vdhashmap::insert_return_type vdhashmap::insert(const std::pair& obj) { + if (mElementCount >= mBucketCount) + rehash_to_size(mElementCount + 1); + + size_type bucket = mHasher(obj.first) % mBucketCount; + + for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { + if (mPred(p->mData.first, obj.first)) + return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); + } + + node_type *node = mAllocator.allocate(1); + try { + new(node) node_type(static_cast(mpBucketStart[bucket]), obj); + } catch(...) { + mAllocator.deallocate(node, 1); + throw; + } + + mpBucketStart[bucket] = node; + ++mElementCount; + + return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); +} + +template +template +typename vdhashmap::insert_return_type vdhashmap::insert_as(const U& key) { + if (mElementCount >= mBucketCount) + rehash_to_size(mElementCount + 1); + + size_type bucket = mHasher(key) % mBucketCount; + + for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { + if (mPred(p->mData.first, key)) + return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); + } + + node_type *node = mAllocator.allocate(1); + try { + new(node) node_type(static_cast(mpBucketStart[bucket])); + + try { + node->mData.first = key; + } catch(...) { + node->~node_type(); + } + + } catch(...) { + mAllocator.deallocate(node, 1); + throw; + } + + mpBucketStart[bucket] = node; + ++mElementCount; + + return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); +} + +template +typename vdhashmap::iterator vdhashmap::erase(iterator position) { + size_type bucket = mHasher(position->first) % mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = mpBucketStart[bucket]; + + while(&static_cast(p)->mData != &*position) { + prev = p; + p = p->mpHashNext; + } + + vdhashtable_base_node *next = p->mpHashNext; + if (prev) + prev->mpHashNext = next; + else + mpBucketStart[bucket] = next; + + node_type *node = static_cast(p); + node->~node_type(); + mAllocator.deallocate(node, 1); + --mElementCount; + + return iterator(next, &mpBucketStart[bucket], mpBucketEnd); +} + +template +typename vdhashmap::const_iterator vdhashmap::erase(const_iterator position) { + size_type bucket = mHasher(position->first) % mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = mpBucketStart[bucket]; + + while(&static_cast(p)->mData != &*position) { + prev = p; + p = p->mpHashNext; + } + + vdhashtable_base_node *next = p->mpHashNext; + if (prev) + prev->mpHashNext = next; + else + mpBucketStart[bucket] = next; + + node_type *node = static_cast(p); + node->~node_type(); + mAllocator.deallocate(node, 1); + --mElementCount; + + return const_iterator(next, &mpBucketStart[bucket], mpBucketEnd); +} + +template +typename vdhashmap::size_type vdhashmap::erase(const key_type& k) { + if (!mBucketCount) + return 0; + + size_type bucket = mHasher(k) % mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = mpBucketStart[bucket]; + + while(p) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) { + vdhashtable_base_node *next = p->mpHashNext; + + if (prev) + prev->mpHashNext = next; + else + mpBucketStart[bucket] = next; + + node->~node_type(); + mAllocator.deallocate(node, 1); + --mElementCount; + return 1; + } + + prev = p; + p = p->mpHashNext; + } + + return 0; +} + +template +void vdhashmap::clear() { + for(vdhashtable_base_node **bucket = mpBucketStart; bucket != mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + node->~node_type(); + + mAllocator.deallocate(node, 1); + + p = next; + } + + *bucket = NULL; + } + + mElementCount = 0; +} + +// observers +template +typename vdhashmap::hasher vdhashmap::hash_function() const { + return mHasher; +} + +template +typename vdhashmap::key_equal vdhashmap::key_eq() const { + return mPred; +} + +// lookup +template +typename vdhashmap::iterator vdhashmap::find(const key_type& k) { + if (!mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % mBucketCount; + + for(vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return iterator(node, &mpBucketStart[bucket], mpBucketEnd); + } + + return iterator(); +} + +template +typename vdhashmap::const_iterator vdhashmap::find(const key_type& k) const { + if (!mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % mBucketCount; + + for(const vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { + const node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return const_iterator(const_cast(static_cast(node)), &mpBucketStart[bucket], mpBucketEnd); + } + + return iterator(); +} + +template +typename vdhashmap::size_type vdhashmap::count(const key_type& k) const { + return find(k) != end() ? 1 : 0; +} + +template +std::pair::iterator, typename vdhashmap::iterator> vdhashmap::equal_range(const key_type& k) { + iterator it = find(k); + iterator itEnd; + + if (it == itEnd) + return std::make_pair(itEnd, itEnd); + + itEnd = it; + ++itEnd; + + return std::make_pair(); +} + +template +std::pair::const_iterator, typename vdhashmap::const_iterator> vdhashmap::equal_range(const key_type& k) const { + const_iterator it = find(k); + const_iterator itEnd; + + if (it == itEnd) + return std::make_pair(itEnd, itEnd); + + itEnd = it; + ++itEnd; + + return std::make_pair(it, itEnd); +} + +template +template +typename vdhashmap::iterator vdhashmap::find_as(const U& k) { + if (!mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % mBucketCount; + + for(vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return iterator(node, &mpBucketStart[bucket], mpBucketEnd); + } + + return iterator(); +} + +template +template +typename vdhashmap::const_iterator vdhashmap::find_as(const U& k) const { + if (!mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % mBucketCount; + + for(const vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { + const node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return const_iterator(const_cast(static_cast(node)), &mpBucketStart[bucket], mpBucketEnd); + } + + return iterator(); +} + +// bucket interface +template +typename vdhashmap::size_type vdhashmap::bucket(const key_type& k) const { + size_type bucket = 0; + + if (mBucketCount) + bucket = mHasher(k) % mBucketCount; + + return bucket; +} + +template +typename vdhashmap::local_iterator vdhashmap::begin(size_type n) { + return local_iterator(mpBucketStart[n]); +} + +template +typename vdhashmap::const_local_iterator vdhashmap::begin(size_type n) const { + return const_local_iterator(mpBucketStart[n]); +} + +template +typename vdhashmap::local_iterator vdhashmap::end(size_type n) { + return local_iterator(NULL); +} + +template +typename vdhashmap::const_local_iterator vdhashmap::end(size_type n) const { + return const_local_iterator(NULL); +} + +// hash policy +template +void vdhashmap::rehash(size_type n) { + if (!n) + n = 1; + + if (mBucketCount == n) + return; + + vdhashtable_base_node **newBuckets = mBucketAllocator.allocate(n + 1); + + for(size_type i=0; i<=n; ++i) + newBuckets[i] = NULL; + + const size_type m = mBucketCount; + for(size_type i=0; impHashNext; + const value_type& vt = static_cast *>(p)->mData; + size_t bucket = mHasher(vt.first) % n; + + vdhashtable_base_node *head = newBuckets[bucket]; + + p->mpHashNext = head; + newBuckets[bucket] = p; + + p = next; + } + } + + if (mpBucketStart != &sEmptyBucket) + mBucketAllocator.deallocate(mpBucketStart, (mpBucketEnd - mpBucketStart) + 1); + + mpBucketStart = newBuckets; + mpBucketEnd = newBuckets + n; + mBucketCount = n; +} + +template +void vdhashmap::rehash_to_size(size_type n) { + size_type buckets = vdhashtable_base::compute_bucket_count(n); + rehash(buckets); +} + +template +void vdhashmap::reset() { + clear(); + + if (mpBucketStart != &sEmptyBucket) + mBucketAllocator.deallocate(mpBucketStart, (mpBucketEnd - mpBucketStart) + 1); +} + +#endif // f_VD2_SYSTEM_VDSTL_HASHMAP_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashset.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashset.h index 81f4ef7e31f..31d5fe8485e 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashset.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashset.h @@ -1,526 +1,526 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_HASHSET_H -#define f_VD2_SYSTEM_VDSTL_HASHSET_H - -#include -#include -#include - -template, class Pred = std::equal_to, class A = std::allocator > > -class vdhashset : public vdhashtable { -public: - typedef typename vdhashtable::node_type node_type; - typedef typename vdhashtable::value_type value_type; - typedef typename vdhashtable::size_type size_type; - typedef typename vdhashtable::difference_type difference_type; - typedef typename vdhashtable::pointer pointer; - typedef typename vdhashtable::const_pointer const_pointer; - typedef typename vdhashtable::reference reference; - typedef typename vdhashtable::const_reference const_reference; - typedef typename vdhashtable::iterator iterator; - typedef typename vdhashtable::const_iterator const_iterator; - typedef typename vdhashtable::local_iterator local_iterator; - typedef typename vdhashtable::const_local_iterator const_local_iterator; - - typedef K key_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef A allocator_type; - typedef std::pair insert_return_type; - - vdhashset(); - vdhashset(const vdhashset&); - ~vdhashset(); - - vdhashset& operator=(const vdhashset&); - - allocator_type get_allocator() const; - - // iterators - using vdhashtable::begin; - using vdhashtable::end; -// iterator begin(); Inherited. -// const_iterator begin() const; Inherited. -// iterator end(); Inherited. -// const_iterator end() const; Inherited. - - // modifiers - insert_return_type insert(const key_type& key); -// iterator insert(iterator hint, const value_type& obj); // TODO -// const_iterator insert(const_iterator hint, const value_type& obj); // TODO - - iterator erase(iterator position); - const_iterator erase(const_iterator position); - size_type erase(const key_type& k); -// iterator erase(iterator first, iterator last); // TODO -// const_iterator erase(const_iterator first, const_iterator last); // TODO - void clear(); - - // observers - hasher hash_function() const; - key_equal key_eq() const; - - // lookup - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; - size_type count(const key_type& k) const; - std::pair equal_range(const key_type& k); - std::pair equal_range(const key_type& k) const; - - // lookup (extensions) - template - iterator find_as(const U& k); - - template - const_iterator find_as(const U& k) const; - - // bucket interface -// size_type bucket_count() const; Inherited. -// size_type max_bucket_count() const; Inherited. -// size_type bucket_size(size_type n) const; Inherited. - size_type bucket(const key_type& k) const; - local_iterator begin(size_type n); - const_local_iterator begin(size_type n) const; - local_iterator end(size_type n); - const_local_iterator end(size_type n) const; - - // hash policy -// float load_factor() const; // TODO -// float max_load_factor() const; // TODO -// void max_load_factor(float z); // TODO - void rehash(size_type n); - -protected: - void rehash_to_size(size_type n); - void reset(); - - A mAllocator; - typename A::template rebind::other mBucketAllocator; - Hash mHasher; - Pred mPred; -}; - -template -vdhashset::vdhashset() { -} - -template -vdhashset::vdhashset(const vdhashset& src) - : mHasher(src.mHasher) - , mPred(src.mPred) -{ - rehash_to_size(src.mElementCount); - - try { - for(vdhashtable_base_node **bucket = this->mpBucketStart; bucket != this->mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - insert(node->mData); - - p = next; - } - - *bucket = NULL; - } - } catch(...) { - reset(); - throw; - } -} - -template -vdhashset::~vdhashset() { - reset(); -} - -template -vdhashset& vdhashset::operator=(const vdhashset& src) { - if (&src != this) { - clear(); - - mHasher = src.mHasher; - mPred = src.mPred; - - for(vdhashtable_base_node **bucket = src.mpBucketStart; bucket != src.mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - insert(node->mData); - - p = next; - } - - *bucket = NULL; - } - } - - return *this; -} - -template -typename vdhashset::allocator_type vdhashset::get_allocator() const { - return A(); -} - -// modifiers -template -typename vdhashset::insert_return_type vdhashset::insert(const key_type& key) { - if (this->mElementCount >= this->mBucketCount) - rehash_to_size(this->mElementCount + 1); - - size_type bucket = mHasher(key) % this->mBucketCount; - - for(node_type *p = static_cast(this->mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { - if (mPred(p->mData, key)) - return std::pair(iterator(p, &this->mpBucketStart[bucket], this->mpBucketEnd), false); - } - - node_type *node = mAllocator.allocate(1); - try { - new(node) node_type(static_cast(this->mpBucketStart[bucket]), key); - } catch(...) { - mAllocator.deallocate(node, 1); - throw; - } - - this->mpBucketStart[bucket] = node; - ++this->mElementCount; - - return std::pair(iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd), true); -} - -template -typename vdhashset::iterator vdhashset::erase(iterator position) { - size_type bucket = mHasher(position->first) % this->mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = this->mpBucketStart[bucket]; - - while(&static_cast(p)->mData != &*position) { - prev = p; - p = p->mpHashNext; - } - - vdhashtable_base_node *next = p->mpHashNext; - if (prev) - prev->mpHashNext = next; - else - this->mpBucketStart[bucket] = next; - - node_type *node = static_cast(p); - node->~node_type(); - mAllocator.deallocate(node, 1); - --this->mElementCount; - - return iterator(next, &this->mpBucketStart[bucket], this->mpBucketEnd); -} - -template -typename vdhashset::const_iterator vdhashset::erase(const_iterator position) { - size_type bucket = mHasher(position->first) % this->mBucketCount; - const vdhashtable_base_node *prev = NULL; - const vdhashtable_base_node *p = this->mpBucketStart[bucket]; - - while(&static_cast(p)->mData != &*position) { - prev = p; - p = p->mpHashNext; - } - - const vdhashtable_base_node *next = p->mpHashNext; - if (prev) - prev->mpHashNext = next; - else - this->mpBucketStart[bucket] = next; - - node_type *node = static_cast(p); - node->~node_type(); - mAllocator.deallocate(node, 1); - --this->mElementCount; - - return const_iterator(next, &this->mpBucketStart[bucket], this->mpBucketEnd); -} - -template -typename vdhashset::size_type vdhashset::erase(const key_type& k) { - if (!this->mBucketCount) - return 0; - - size_type bucket = mHasher(k) % this->mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = this->mpBucketStart[bucket]; - - while(p) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) { - vdhashtable_base_node *next = p->mpHashNext; - - if (prev) - prev->mpHashNext = next; - else - this->mpBucketStart[bucket] = next; - - node->~node_type(); - mAllocator.deallocate(node, 1); - --this->mElementCount; - return 1; - } - - prev = p; - p = p->mpHashNext; - } - - return 0; -} - -template -void vdhashset::clear() { - for(vdhashtable_base_node **bucket = this->mpBucketStart; bucket != this->mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - node->~node_type(); - - mAllocator.deallocate(node, 1); - - p = next; - } - - *bucket = NULL; - } - - this->mElementCount = 0; -} - -// observers -template -typename vdhashset::hasher vdhashset::hash_function() const { - return mHasher; -} - -template -typename vdhashset::key_equal vdhashset::key_eq() const { - return mPred; -} - -// lookup -template -typename vdhashset::iterator vdhashset::find(const key_type& k) { - if (!this->mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % this->mBucketCount; - - for(vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd); - } - - return iterator(); -} - -template -typename vdhashset::const_iterator vdhashset::find(const key_type& k) const { - if (!this->mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % this->mBucketCount; - - for(const vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { - const node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return const_iterator(const_cast(static_cast(node)), &this->mpBucketStart[bucket], this->mpBucketEnd); - } - - return iterator(); -} - -template -typename vdhashset::size_type vdhashset::count(const key_type& k) const { - return find(k) != end() ? 1 : 0; -} - -template -std::pair::iterator, typename vdhashset::iterator> vdhashset::equal_range(const key_type& k) { - iterator it = find(k); - iterator itEnd; - - if (it == itEnd) - return std::make_pair(itEnd, itEnd); - - itEnd = it; - ++itEnd; - - return std::make_pair(it, itEnd); -} - -template -std::pair::const_iterator, typename vdhashset::const_iterator> vdhashset::equal_range(const key_type& k) const { - const_iterator it = find(k); - const_iterator itEnd; - - if (it == itEnd) - return std::make_pair(itEnd, itEnd); - - itEnd = it; - ++itEnd; - - return std::make_pair(it, itEnd); -} - -template -template -typename vdhashset::iterator vdhashset::find_as(const U& k) { - if (!this->mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % this->mBucketCount; - - for(vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd); - } - - return iterator(); -} - -template -template -typename vdhashset::const_iterator vdhashset::find_as(const U& k) const { - if (!this->mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % this->mBucketCount; - - for(const vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { - const node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return const_iterator(const_cast(static_cast(node)), &this->mpBucketStart[bucket], this->mpBucketEnd); - } - - return iterator(); -} - -// bucket interface -template -typename vdhashset::size_type vdhashset::bucket(const key_type& k) const { - size_type bucket = 0; - - if (this->mBucketCount) - bucket = mHasher(k) % this->mBucketCount; - - return bucket; -} - -template -typename vdhashset::local_iterator vdhashset::begin(size_type n) { - return local_iterator(this->mpBucketStart[n]); -} - -template -typename vdhashset::const_local_iterator vdhashset::begin(size_type n) const { - return const_local_iterator(this->mpBucketStart[n]); -} - -template -typename vdhashset::local_iterator vdhashset::end(size_type n) { - return local_iterator(NULL); -} - -template -typename vdhashset::const_local_iterator vdhashset::end(size_type n) const { - return const_local_iterator(NULL); -} - -// hash policy -template -void vdhashset::rehash(size_type n) { - if (!n) - n = 1; - - if (this->mBucketCount == n) - return; - - vdhashtable_base_node **newBuckets = mBucketAllocator.allocate(n + 1); - - for(size_type i=0; i<=n; ++i) - newBuckets[i] = NULL; - - const size_type m = this->mBucketCount; - for(size_type i=0; impBucketStart[i]; p;) { - vdhashtable_base_node *next = p->mpHashNext; - const value_type& vt = static_cast *>(p)->mData; - size_t bucket = mHasher(vt) % n; - - vdhashtable_base_node *head = newBuckets[bucket]; - - p->mpHashNext = head; - newBuckets[bucket] = p; - - p = next; - } - } - - if (this->mpBucketStart != &vdhashtable::sEmptyBucket) - mBucketAllocator.deallocate(this->mpBucketStart, (this->mpBucketEnd - this->mpBucketStart) + 1); - - this->mpBucketStart = newBuckets; - this->mpBucketEnd = newBuckets + n; - this->mBucketCount = n; -} - -template -void vdhashset::rehash_to_size(size_type n) { - size_type buckets = compute_bucket_count(n); - rehash(buckets); -} - -template -void vdhashset::reset() { - clear(); - - if (this->mpBucketStart != &vdhashtable::sEmptyBucket) - mBucketAllocator.deallocate(this->mpBucketStart, (this->mpBucketEnd - this->mpBucketStart) + 1); -} - -#endif // f_VD2_SYSTEM_VDSTL_HASHSET_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_HASHSET_H +#define f_VD2_SYSTEM_VDSTL_HASHSET_H + +#include +#include +#include + +template, class Pred = std::equal_to, class A = std::allocator > > +class vdhashset : public vdhashtable { +public: + typedef typename vdhashtable::node_type node_type; + typedef typename vdhashtable::value_type value_type; + typedef typename vdhashtable::size_type size_type; + typedef typename vdhashtable::difference_type difference_type; + typedef typename vdhashtable::pointer pointer; + typedef typename vdhashtable::const_pointer const_pointer; + typedef typename vdhashtable::reference reference; + typedef typename vdhashtable::const_reference const_reference; + typedef typename vdhashtable::iterator iterator; + typedef typename vdhashtable::const_iterator const_iterator; + typedef typename vdhashtable::local_iterator local_iterator; + typedef typename vdhashtable::const_local_iterator const_local_iterator; + + typedef K key_type; + typedef Hash hasher; + typedef Pred key_equal; + typedef A allocator_type; + typedef std::pair insert_return_type; + + vdhashset(); + vdhashset(const vdhashset&); + ~vdhashset(); + + vdhashset& operator=(const vdhashset&); + + allocator_type get_allocator() const; + + // iterators + using vdhashtable::begin; + using vdhashtable::end; +// iterator begin(); Inherited. +// const_iterator begin() const; Inherited. +// iterator end(); Inherited. +// const_iterator end() const; Inherited. + + // modifiers + insert_return_type insert(const key_type& key); +// iterator insert(iterator hint, const value_type& obj); // TODO +// const_iterator insert(const_iterator hint, const value_type& obj); // TODO + + iterator erase(iterator position); + const_iterator erase(const_iterator position); + size_type erase(const key_type& k); +// iterator erase(iterator first, iterator last); // TODO +// const_iterator erase(const_iterator first, const_iterator last); // TODO + void clear(); + + // observers + hasher hash_function() const; + key_equal key_eq() const; + + // lookup + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + size_type count(const key_type& k) const; + std::pair equal_range(const key_type& k); + std::pair equal_range(const key_type& k) const; + + // lookup (extensions) + template + iterator find_as(const U& k); + + template + const_iterator find_as(const U& k) const; + + // bucket interface +// size_type bucket_count() const; Inherited. +// size_type max_bucket_count() const; Inherited. +// size_type bucket_size(size_type n) const; Inherited. + size_type bucket(const key_type& k) const; + local_iterator begin(size_type n); + const_local_iterator begin(size_type n) const; + local_iterator end(size_type n); + const_local_iterator end(size_type n) const; + + // hash policy +// float load_factor() const; // TODO +// float max_load_factor() const; // TODO +// void max_load_factor(float z); // TODO + void rehash(size_type n); + +protected: + void rehash_to_size(size_type n); + void reset(); + + A mAllocator; + typename A::template rebind::other mBucketAllocator; + Hash mHasher; + Pred mPred; +}; + +template +vdhashset::vdhashset() { +} + +template +vdhashset::vdhashset(const vdhashset& src) + : mHasher(src.mHasher) + , mPred(src.mPred) +{ + rehash_to_size(src.mElementCount); + + try { + for(vdhashtable_base_node **bucket = this->mpBucketStart; bucket != this->mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + insert(node->mData); + + p = next; + } + + *bucket = NULL; + } + } catch(...) { + reset(); + throw; + } +} + +template +vdhashset::~vdhashset() { + reset(); +} + +template +vdhashset& vdhashset::operator=(const vdhashset& src) { + if (&src != this) { + clear(); + + mHasher = src.mHasher; + mPred = src.mPred; + + for(vdhashtable_base_node **bucket = src.mpBucketStart; bucket != src.mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + insert(node->mData); + + p = next; + } + + *bucket = NULL; + } + } + + return *this; +} + +template +typename vdhashset::allocator_type vdhashset::get_allocator() const { + return A(); +} + +// modifiers +template +typename vdhashset::insert_return_type vdhashset::insert(const key_type& key) { + if (this->mElementCount >= this->mBucketCount) + rehash_to_size(this->mElementCount + 1); + + size_type bucket = mHasher(key) % this->mBucketCount; + + for(node_type *p = static_cast(this->mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { + if (mPred(p->mData, key)) + return std::pair(iterator(p, &this->mpBucketStart[bucket], this->mpBucketEnd), false); + } + + node_type *node = mAllocator.allocate(1); + try { + new(node) node_type(static_cast(this->mpBucketStart[bucket]), key); + } catch(...) { + mAllocator.deallocate(node, 1); + throw; + } + + this->mpBucketStart[bucket] = node; + ++this->mElementCount; + + return std::pair(iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd), true); +} + +template +typename vdhashset::iterator vdhashset::erase(iterator position) { + size_type bucket = mHasher(position->first) % this->mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = this->mpBucketStart[bucket]; + + while(&static_cast(p)->mData != &*position) { + prev = p; + p = p->mpHashNext; + } + + vdhashtable_base_node *next = p->mpHashNext; + if (prev) + prev->mpHashNext = next; + else + this->mpBucketStart[bucket] = next; + + node_type *node = static_cast(p); + node->~node_type(); + mAllocator.deallocate(node, 1); + --this->mElementCount; + + return iterator(next, &this->mpBucketStart[bucket], this->mpBucketEnd); +} + +template +typename vdhashset::const_iterator vdhashset::erase(const_iterator position) { + size_type bucket = mHasher(position->first) % this->mBucketCount; + const vdhashtable_base_node *prev = NULL; + const vdhashtable_base_node *p = this->mpBucketStart[bucket]; + + while(&static_cast(p)->mData != &*position) { + prev = p; + p = p->mpHashNext; + } + + const vdhashtable_base_node *next = p->mpHashNext; + if (prev) + prev->mpHashNext = next; + else + this->mpBucketStart[bucket] = next; + + node_type *node = static_cast(p); + node->~node_type(); + mAllocator.deallocate(node, 1); + --this->mElementCount; + + return const_iterator(next, &this->mpBucketStart[bucket], this->mpBucketEnd); +} + +template +typename vdhashset::size_type vdhashset::erase(const key_type& k) { + if (!this->mBucketCount) + return 0; + + size_type bucket = mHasher(k) % this->mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = this->mpBucketStart[bucket]; + + while(p) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) { + vdhashtable_base_node *next = p->mpHashNext; + + if (prev) + prev->mpHashNext = next; + else + this->mpBucketStart[bucket] = next; + + node->~node_type(); + mAllocator.deallocate(node, 1); + --this->mElementCount; + return 1; + } + + prev = p; + p = p->mpHashNext; + } + + return 0; +} + +template +void vdhashset::clear() { + for(vdhashtable_base_node **bucket = this->mpBucketStart; bucket != this->mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + node->~node_type(); + + mAllocator.deallocate(node, 1); + + p = next; + } + + *bucket = NULL; + } + + this->mElementCount = 0; +} + +// observers +template +typename vdhashset::hasher vdhashset::hash_function() const { + return mHasher; +} + +template +typename vdhashset::key_equal vdhashset::key_eq() const { + return mPred; +} + +// lookup +template +typename vdhashset::iterator vdhashset::find(const key_type& k) { + if (!this->mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % this->mBucketCount; + + for(vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd); + } + + return iterator(); +} + +template +typename vdhashset::const_iterator vdhashset::find(const key_type& k) const { + if (!this->mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % this->mBucketCount; + + for(const vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { + const node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return const_iterator(const_cast(static_cast(node)), &this->mpBucketStart[bucket], this->mpBucketEnd); + } + + return iterator(); +} + +template +typename vdhashset::size_type vdhashset::count(const key_type& k) const { + return find(k) != end() ? 1 : 0; +} + +template +std::pair::iterator, typename vdhashset::iterator> vdhashset::equal_range(const key_type& k) { + iterator it = find(k); + iterator itEnd; + + if (it == itEnd) + return std::make_pair(itEnd, itEnd); + + itEnd = it; + ++itEnd; + + return std::make_pair(it, itEnd); +} + +template +std::pair::const_iterator, typename vdhashset::const_iterator> vdhashset::equal_range(const key_type& k) const { + const_iterator it = find(k); + const_iterator itEnd; + + if (it == itEnd) + return std::make_pair(itEnd, itEnd); + + itEnd = it; + ++itEnd; + + return std::make_pair(it, itEnd); +} + +template +template +typename vdhashset::iterator vdhashset::find_as(const U& k) { + if (!this->mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % this->mBucketCount; + + for(vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd); + } + + return iterator(); +} + +template +template +typename vdhashset::const_iterator vdhashset::find_as(const U& k) const { + if (!this->mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % this->mBucketCount; + + for(const vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { + const node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return const_iterator(const_cast(static_cast(node)), &this->mpBucketStart[bucket], this->mpBucketEnd); + } + + return iterator(); +} + +// bucket interface +template +typename vdhashset::size_type vdhashset::bucket(const key_type& k) const { + size_type bucket = 0; + + if (this->mBucketCount) + bucket = mHasher(k) % this->mBucketCount; + + return bucket; +} + +template +typename vdhashset::local_iterator vdhashset::begin(size_type n) { + return local_iterator(this->mpBucketStart[n]); +} + +template +typename vdhashset::const_local_iterator vdhashset::begin(size_type n) const { + return const_local_iterator(this->mpBucketStart[n]); +} + +template +typename vdhashset::local_iterator vdhashset::end(size_type n) { + return local_iterator(NULL); +} + +template +typename vdhashset::const_local_iterator vdhashset::end(size_type n) const { + return const_local_iterator(NULL); +} + +// hash policy +template +void vdhashset::rehash(size_type n) { + if (!n) + n = 1; + + if (this->mBucketCount == n) + return; + + vdhashtable_base_node **newBuckets = mBucketAllocator.allocate(n + 1); + + for(size_type i=0; i<=n; ++i) + newBuckets[i] = NULL; + + const size_type m = this->mBucketCount; + for(size_type i=0; impBucketStart[i]; p;) { + vdhashtable_base_node *next = p->mpHashNext; + const value_type& vt = static_cast *>(p)->mData; + size_t bucket = mHasher(vt) % n; + + vdhashtable_base_node *head = newBuckets[bucket]; + + p->mpHashNext = head; + newBuckets[bucket] = p; + + p = next; + } + } + + if (this->mpBucketStart != &vdhashtable::sEmptyBucket) + mBucketAllocator.deallocate(this->mpBucketStart, (this->mpBucketEnd - this->mpBucketStart) + 1); + + this->mpBucketStart = newBuckets; + this->mpBucketEnd = newBuckets + n; + this->mBucketCount = n; +} + +template +void vdhashset::rehash_to_size(size_type n) { + size_type buckets = compute_bucket_count(n); + rehash(buckets); +} + +template +void vdhashset::reset() { + clear(); + + if (this->mpBucketStart != &vdhashtable::sEmptyBucket) + mBucketAllocator.deallocate(this->mpBucketStart, (this->mpBucketEnd - this->mpBucketStart) + 1); +} + +#endif // f_VD2_SYSTEM_VDSTL_HASHSET_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashtable.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashtable.h index 9cecbde653c..353aa986d74 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashtable.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashtable.h @@ -1,365 +1,365 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_HASHTABLE_H -#define f_VD2_SYSTEM_VDSTL_HASHTABLE_H - -/////////////////////////////////////////////////////////////////////////////// -// vdhashtable_base_node -// -struct vdhashtable_base_node { - vdhashtable_base_node *mpHashNext; -}; - -/////////////////////////////////////////////////////////////////////////////// -// vdhashtable_base -// -class vdhashtable_base { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - vdhashtable_base(); - - // size and capacity - bool empty() const { return mElementCount == 0; } - size_type size() const { return mElementCount; } - size_type max_size() const { return (size_type)-1 >> 1; } - - // bucket interface - size_type bucket_count() const; - size_type max_bucket_count() const; - size_type bucket_size(size_type n) const; - -protected: - static size_type compute_bucket_count(size_type n); - - size_type mBucketCount; - size_type mElementCount; - vdhashtable_base_node **mpBucketStart; - vdhashtable_base_node **mpBucketEnd; - - static vdhashtable_base_node *const sEmptyBucket; -}; - -/////////////////////////////////////////////////////////////////////////// - -template -struct vdhashtable_node : public vdhashtable_base_node { - T mData; - - vdhashtable_node() {} - vdhashtable_node(vdhashtable_node *next) : mData() { - mpHashNext = next; - } - - vdhashtable_node(vdhashtable_node *next, const T& val) : mData(val) { - mpHashNext = next; - } -}; - -/////////////////////////////////////////////////////////////////////////// - -template -class vdhashtable_local_iterator { -public: - typedef std::forward_iterator_tag iterator_category; - typedef T value_type; - typedef T* pointer; - typedef T& reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - vdhashtable_local_iterator(vdhashtable_base_node *node); - - vdhashtable_local_iterator& operator++(); - vdhashtable_local_iterator operator++(int); - - T& operator*() const; - T* operator->() const; - -private: - template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - - vdhashtable_base_node *mpNode; -}; - -template -vdhashtable_local_iterator::vdhashtable_local_iterator(vdhashtable_base_node *node) - : mpNode(node) -{ -} - -template -vdhashtable_local_iterator& vdhashtable_local_iterator::operator++() { - mpNode = mpNode->mpHashNext; - return *this; -} - -template -vdhashtable_local_iterator vdhashtable_local_iterator::operator++(int) { - vdhashtable_local_iterator prev(*this); - mpNode = mpNode->mpHashNext; - return prev; -} - -template -T& vdhashtable_local_iterator::operator*() const { - return static_cast *>(mpNode)->mData; -} - -template -T* vdhashtable_local_iterator::operator->() const { - return &static_cast *>(mpNode)->mData; -} - -template -bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode != y.mpNode; -} - -template -bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode != y.mpNode; -} - -template -bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode != y.mpNode; -} - -/////////////////////////////////////////////////////////////////////////// - -template struct vdhashtable_iterator_nonconst { - typedef T result; -}; - -template struct vdhashtable_iterator_nonconst { - typedef T result; -}; - -template -class vdhashtable_iterator { - typedef typename vdhashtable_iterator_nonconst::result T_NonConst; -public: - typedef std::forward_iterator_tag iterator_category; - typedef T value_type; - typedef T* pointer; - typedef T& reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - vdhashtable_iterator(); - vdhashtable_iterator(vdhashtable_base_node *node, vdhashtable_base_node **bucket, vdhashtable_base_node **bucketEnd); - vdhashtable_iterator(const vdhashtable_iterator& src); - - vdhashtable_iterator& operator++(); - vdhashtable_iterator operator++(int); - - T& operator*() const; - T* operator->() const; - -private: - friend class vdhashtable_iterator; - template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - - vdhashtable_base_node *mpNode; - vdhashtable_base_node **mpBucket; - vdhashtable_base_node **mpBucketEnd; -}; - -template -vdhashtable_iterator::vdhashtable_iterator() - : mpNode(NULL) - , mpBucket(NULL) - , mpBucketEnd(NULL) -{ -} - -template -vdhashtable_iterator::vdhashtable_iterator(vdhashtable_base_node *node, vdhashtable_base_node **bucket, vdhashtable_base_node **bucketEnd) - : mpNode(node) - , mpBucket(bucket) - , mpBucketEnd(bucketEnd) -{ -} - -template -vdhashtable_iterator::vdhashtable_iterator(const vdhashtable_iterator& src) - : mpNode(src.mpNode) - , mpBucket(src.mpBucket) - , mpBucketEnd(src.mpBucketEnd) -{ -} - -template -vdhashtable_iterator& vdhashtable_iterator::operator++() { - mpNode = mpNode->mpHashNext; - - while(!mpNode && ++mpBucket != mpBucketEnd) - mpNode = static_cast *>(*mpBucket); - - return *this; -} - -template -vdhashtable_iterator vdhashtable_iterator::operator++(int) { - vdhashtable_iterator prev(*this); - mpNode = mpNode->mpHashNext; - return prev; -} - -template -T& vdhashtable_iterator::operator*() const { - return static_cast *>(mpNode)->mData; -} - -template -T* vdhashtable_iterator::operator->() const { - return &static_cast *>(mpNode)->mData; -} - -template -bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode != y.mpNode; -} - -template -bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode != y.mpNode; -} - -template -bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode != y.mpNode; -} - -/////////////////////////////////////////////////////////////////////////// - -template -class vdhashtable : public vdhashtable_base { -public: - typedef T value_type; - typedef vdhashtable_node node_type; - typedef value_type *pointer; - typedef const value_type *const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef vdhashtable_iterator iterator; - typedef vdhashtable_iterator const_iterator; - typedef vdhashtable_local_iterator local_iterator; - typedef vdhashtable_local_iterator const_local_iterator; - - // iterators - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; -}; - -// iterators -template -typename vdhashtable::iterator vdhashtable::begin() { - vdhashtable_base_node **bucket = mpBucketStart; - vdhashtable_base_node *p = NULL; - - while(bucket != mpBucketEnd) { - p = *bucket; - if (p) - break; - - ++bucket; - } - - return iterator(static_cast(p), bucket, mpBucketEnd); -} - -template -typename vdhashtable::const_iterator vdhashtable::begin() const { - vdhashtable_base_node **bucket = mpBucketStart; - vdhashtable_base_node *p = NULL; - - while(bucket != mpBucketEnd) { - p = *bucket; - if (p) - break; - - ++bucket; - } - - return const_iterator(static_cast(p), bucket, mpBucketEnd); -} - -template -typename vdhashtable::iterator vdhashtable::end() { - return iterator(NULL, NULL, NULL); -} - -template -typename vdhashtable::const_iterator vdhashtable::end() const { - return const_iterator(NULL, NULL, NULL); -} - -#endif // f_VD2_SYSTEM_VDSTL_HASHTABLE_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_HASHTABLE_H +#define f_VD2_SYSTEM_VDSTL_HASHTABLE_H + +/////////////////////////////////////////////////////////////////////////////// +// vdhashtable_base_node +// +struct vdhashtable_base_node { + vdhashtable_base_node *mpHashNext; +}; + +/////////////////////////////////////////////////////////////////////////////// +// vdhashtable_base +// +class vdhashtable_base { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + vdhashtable_base(); + + // size and capacity + bool empty() const { return mElementCount == 0; } + size_type size() const { return mElementCount; } + size_type max_size() const { return (size_type)-1 >> 1; } + + // bucket interface + size_type bucket_count() const; + size_type max_bucket_count() const; + size_type bucket_size(size_type n) const; + +protected: + static size_type compute_bucket_count(size_type n); + + size_type mBucketCount; + size_type mElementCount; + vdhashtable_base_node **mpBucketStart; + vdhashtable_base_node **mpBucketEnd; + + static vdhashtable_base_node *const sEmptyBucket; +}; + +/////////////////////////////////////////////////////////////////////////// + +template +struct vdhashtable_node : public vdhashtable_base_node { + T mData; + + vdhashtable_node() {} + vdhashtable_node(vdhashtable_node *next) : mData() { + mpHashNext = next; + } + + vdhashtable_node(vdhashtable_node *next, const T& val) : mData(val) { + mpHashNext = next; + } +}; + +/////////////////////////////////////////////////////////////////////////// + +template +class vdhashtable_local_iterator { +public: + typedef std::forward_iterator_tag iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + vdhashtable_local_iterator(vdhashtable_base_node *node); + + vdhashtable_local_iterator& operator++(); + vdhashtable_local_iterator operator++(int); + + T& operator*() const; + T* operator->() const; + +private: + template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + + vdhashtable_base_node *mpNode; +}; + +template +vdhashtable_local_iterator::vdhashtable_local_iterator(vdhashtable_base_node *node) + : mpNode(node) +{ +} + +template +vdhashtable_local_iterator& vdhashtable_local_iterator::operator++() { + mpNode = mpNode->mpHashNext; + return *this; +} + +template +vdhashtable_local_iterator vdhashtable_local_iterator::operator++(int) { + vdhashtable_local_iterator prev(*this); + mpNode = mpNode->mpHashNext; + return prev; +} + +template +T& vdhashtable_local_iterator::operator*() const { + return static_cast *>(mpNode)->mData; +} + +template +T* vdhashtable_local_iterator::operator->() const { + return &static_cast *>(mpNode)->mData; +} + +template +bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode != y.mpNode; +} + +template +bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode != y.mpNode; +} + +template +bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode != y.mpNode; +} + +/////////////////////////////////////////////////////////////////////////// + +template struct vdhashtable_iterator_nonconst { + typedef T result; +}; + +template struct vdhashtable_iterator_nonconst { + typedef T result; +}; + +template +class vdhashtable_iterator { + typedef typename vdhashtable_iterator_nonconst::result T_NonConst; +public: + typedef std::forward_iterator_tag iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + vdhashtable_iterator(); + vdhashtable_iterator(vdhashtable_base_node *node, vdhashtable_base_node **bucket, vdhashtable_base_node **bucketEnd); + vdhashtable_iterator(const vdhashtable_iterator& src); + + vdhashtable_iterator& operator++(); + vdhashtable_iterator operator++(int); + + T& operator*() const; + T* operator->() const; + +private: + friend class vdhashtable_iterator; + template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + + vdhashtable_base_node *mpNode; + vdhashtable_base_node **mpBucket; + vdhashtable_base_node **mpBucketEnd; +}; + +template +vdhashtable_iterator::vdhashtable_iterator() + : mpNode(NULL) + , mpBucket(NULL) + , mpBucketEnd(NULL) +{ +} + +template +vdhashtable_iterator::vdhashtable_iterator(vdhashtable_base_node *node, vdhashtable_base_node **bucket, vdhashtable_base_node **bucketEnd) + : mpNode(node) + , mpBucket(bucket) + , mpBucketEnd(bucketEnd) +{ +} + +template +vdhashtable_iterator::vdhashtable_iterator(const vdhashtable_iterator& src) + : mpNode(src.mpNode) + , mpBucket(src.mpBucket) + , mpBucketEnd(src.mpBucketEnd) +{ +} + +template +vdhashtable_iterator& vdhashtable_iterator::operator++() { + mpNode = mpNode->mpHashNext; + + while(!mpNode && ++mpBucket != mpBucketEnd) + mpNode = static_cast *>(*mpBucket); + + return *this; +} + +template +vdhashtable_iterator vdhashtable_iterator::operator++(int) { + vdhashtable_iterator prev(*this); + mpNode = mpNode->mpHashNext; + return prev; +} + +template +T& vdhashtable_iterator::operator*() const { + return static_cast *>(mpNode)->mData; +} + +template +T* vdhashtable_iterator::operator->() const { + return &static_cast *>(mpNode)->mData; +} + +template +bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode != y.mpNode; +} + +template +bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode != y.mpNode; +} + +template +bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode != y.mpNode; +} + +/////////////////////////////////////////////////////////////////////////// + +template +class vdhashtable : public vdhashtable_base { +public: + typedef T value_type; + typedef vdhashtable_node node_type; + typedef value_type *pointer; + typedef const value_type *const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef vdhashtable_iterator iterator; + typedef vdhashtable_iterator const_iterator; + typedef vdhashtable_local_iterator local_iterator; + typedef vdhashtable_local_iterator const_local_iterator; + + // iterators + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; +}; + +// iterators +template +typename vdhashtable::iterator vdhashtable::begin() { + vdhashtable_base_node **bucket = mpBucketStart; + vdhashtable_base_node *p = NULL; + + while(bucket != mpBucketEnd) { + p = *bucket; + if (p) + break; + + ++bucket; + } + + return iterator(static_cast(p), bucket, mpBucketEnd); +} + +template +typename vdhashtable::const_iterator vdhashtable::begin() const { + vdhashtable_base_node **bucket = mpBucketStart; + vdhashtable_base_node *p = NULL; + + while(bucket != mpBucketEnd) { + p = *bucket; + if (p) + break; + + ++bucket; + } + + return const_iterator(static_cast(p), bucket, mpBucketEnd); +} + +template +typename vdhashtable::iterator vdhashtable::end() { + return iterator(NULL, NULL, NULL); +} + +template +typename vdhashtable::const_iterator vdhashtable::end() const { + return const_iterator(NULL, NULL, NULL); +} + +#endif // f_VD2_SYSTEM_VDSTL_HASHTABLE_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_vector.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_vector.h index 10183a88b69..e39989bb4f6 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_vector.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_vector.h @@ -1,606 +1,606 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2009 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_VECTOR_H -#define f_VD2_SYSTEM_VDSTL_VECTOR_H - -#ifdef _MSC_VER -#pragma once -#endif - -template > -class vdvector { -public: - typedef typename A::reference reference; - typedef typename A::const_reference const_reference; - typedef T *iterator; - typedef const T *const_iterator; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef A allocator_type; - typedef typename A::pointer pointer; - typedef typename A::const_pointer const_pointer; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - // 23.2.4.1 construct/copy/destroy: - explicit vdvector(); - explicit vdvector(const A&); - explicit vdvector(size_type n); - explicit vdvector(size_type n, const T& value, const A& = A()); - template - vdvector(InputIterator first, InputIterator last, const A& = A()); - vdvector(const vdvector& x); - ~vdvector(); - vdvector& operator=(const vdvector& x); - template - void assign(InputIterator first, InputIterator last); - void assign(size_type n, const T& u); - allocator_type get_allocator() const; - - // iterators: - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - reverse_iterator rbegin(); - const_reverse_iterator rbegin() const; - reverse_iterator rend(); - const_reverse_iterator rend() const; - pointer data(); - const_pointer data() const; - - // 23.2.4.2 capacity: - size_type size() const; - size_type max_size() const; - size_type capacity() const; - bool empty() const; - - // element access: - reference operator[](size_type n); - const_reference operator[](size_type n) const; - const_reference at(size_type n) const; - reference at(size_type n); - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; - - void resize(size_type sz, T c = T()); - void reserve(size_type n); - - template - void push_back_as(const U& x); - - reference push_back(); - void push_back(const T& x); - void pop_back(); - iterator insert(iterator position, const T& x); - - template - iterator insert_as(iterator position, const U& x); - - void insert(iterator position, size_type n, const T& x); - template - void insert(iterator position, InputIterator first, InputIterator last); - iterator erase(iterator position); - iterator erase(iterator first, iterator last); - void swap(vdvector&); - void clear(); - -private: - void free_storage(); - - struct Data : public A { - pointer mpBegin; - pointer mpEnd; - pointer mpEOS; - - Data() : A(), mpBegin(NULL), mpEnd(NULL), mpEOS(NULL) {} - Data(const A& alloc) : A(alloc), mpBegin(NULL), mpEnd(NULL), mpEOS(NULL) {} - } m; -}; - -template -vdvector::vdvector() { -} - -template -vdvector::vdvector(const A& a) - : m(a) -{ -} - -template -vdvector::vdvector(size_type n) { - resize(n); -} - -template -vdvector::vdvector(size_type n, const T& value, const A& a) - : m(a) -{ - resize(n, value); -} - -template -template -vdvector::vdvector(InputIterator first, InputIterator last, const A& a) - : m(a) -{ - assign(first, last); -} - -template -vdvector::vdvector(const vdvector& x) - : m(static_cast(x.m)) -{ - assign(x.m.mpBegin, x.m.mpEnd); -} - -template -vdvector::~vdvector() { - clear(); - - if (m.mpBegin) - m.deallocate(m.mpBegin, m.mpEOS - m.mpBegin); -} - -template -vdvector& vdvector::operator=(const vdvector& x) { - if (&x != this) { - vdvector tmp(x); - - swap(tmp); - } - - return *this; -} - -template -template -void vdvector::assign(InputIterator first, InputIterator last) { - clear(); - insert(m.mpBegin, first, last); -} - -template -void vdvector::assign(size_type n, const T& u) { - clear(); - insert(m.mpBegin, n, u); -} - -template typename vdvector::allocator_type vdvector::get_allocator() const { return m; } -template typename vdvector::iterator vdvector::begin() { return m.mpBegin; } -template typename vdvector::const_iterator vdvector::begin() const { return m.mpBegin; } -template typename vdvector::iterator vdvector::end() { return m.mpEnd; } -template typename vdvector::const_iterator vdvector::end() const { return m.mpEnd; } -template typename vdvector::reverse_iterator vdvector::rbegin() { return reverse_iterator(m.mpEnd); } -template typename vdvector::const_reverse_iterator vdvector::rbegin() const { return const_reverse_iterator(m.mpEnd); } -template typename vdvector::reverse_iterator vdvector::rend() { return reverse_iterator(m.mpBegin); } -template typename vdvector::const_reverse_iterator vdvector::rend() const { return const_reverse_iterator(m.mpBegin); } -template typename vdvector::pointer vdvector::data() { return m.mpBegin; } -template typename vdvector::const_pointer vdvector::data() const { return m.mpBegin; } - -template typename vdvector::size_type vdvector::size() const { return m.mpEnd - m.mpBegin; } -template typename vdvector::size_type vdvector::max_size() const { return m.max_size(); } -template typename vdvector::size_type vdvector::capacity() const { return m.mpEOS - m.mpBegin; } -template bool vdvector::empty() const { return m.mpBegin == m.mpEnd; } - -template typename vdvector::reference vdvector::operator[](size_type n) { return m.mpBegin[n]; } -template typename vdvector::const_reference vdvector::operator[](size_type n) const { return m.mpBegin[n]; } -template typename vdvector::const_reference vdvector::at(size_type n) const { if (n >= (size_type)(m.mpEnd - m.mpBegin)) throw std::out_of_range("The index is out of range."); return m.mpBegin[n]; } -template typename vdvector::reference vdvector::at(size_type n) { if (n >= (size_type)(m.mpEnd - m.mpBegin)) throw std::out_of_range("The index is out of range."); return m.mpBegin[n]; } -template typename vdvector::reference vdvector::front() { return *m.mpBegin; } -template typename vdvector::const_reference vdvector::front() const { return *m.mpBegin; } -template typename vdvector::reference vdvector::back() { return m.mpEnd[-1]; } -template typename vdvector::const_reference vdvector::back() const { return m.mpEnd[-1]; } - -template -void vdvector::resize(size_type sz, T c) { - const size_type currSize = m.mpEnd - m.mpBegin; - - if (sz < currSize) { - T *p = m.mpBegin + sz; - while(m.mpEnd != p) { - --m.mpEnd; - m.mpEnd->~T(); - } - } else if (sz > currSize) { - const size_type currCapacity = m.mpEOS - m.mpBegin; - - if (sz > currCapacity) { - pointer p0 = m.allocate(sz); - - try { - pointer p1 = std::uninitialized_copy(m.mpBegin, m.mpEnd, p0); - pointer p2 = p0 + sz; - - T *prev0 = m.mpBegin; - T *prev1 = m.mpEnd; - T *prev2 = m.mpEOS; - try { - std::uninitialized_fill(p1, p2, c); - - // destroy old range - while(prev1 != prev0) { - --prev1; - prev0->~T(); - } - - m.mpBegin = p0; - m.mpEnd = p2; - m.mpEOS = p2; - } catch(...) { - while(p2 != p1) { - --p2; - p2->~T(); - } - m.deallocate(p0, sz); - throw; - } - - m.deallocate(prev0, prev2 - prev0); - } catch(...) { - m.deallocate(p0, sz); - throw; - } - } else { - pointer newEnd = m.mpBegin + sz; - std::uninitialized_fill(m.mpEnd, newEnd, c); - m.mpEnd = newEnd; - } - } -} - -template -void vdvector::reserve(size_type n) { - const size_type currCapacity = m.mpEOS - m.mpBegin; - - if (n <= currCapacity) - return; - - pointer p0 = m.allocate(n); - - try { - pointer p1 = std::uninitialized_copy(m.mpBegin, m.mpEnd, p0); - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = p1; - m.mpEOS = p0 + n; - } catch(...) { - m.deallocate(p0, n); - throw; - } -} - -template -template -void vdvector::push_back_as(const U& x) { - if (m.mpEnd != m.mpEOS) { - new(m.mpEnd) T(x); - ++m.mpEnd; - } else { - insert_as(m.mpEnd, x); - } -} - -template -typename vdvector::reference vdvector::push_back() { - if (m.mpEnd != m.mpEOS) { - new(m.mpEnd) T(); - return *m.mpEnd++; - } else { - return *insert(m.mpEnd, T()); - } -} - -template -void vdvector::push_back(const T& x) { - VDASSERT(m.mpEnd >= m.mpBegin && m.mpEnd <= m.mpEOS); - if (m.mpEnd != m.mpEOS) { - new(m.mpEnd) T(x); - ++m.mpEnd; - } else { - insert(m.mpEnd, x); - } -} - -template -void vdvector::pop_back() { - --m.mpEnd; - m.mpEnd->~T(); -} - -template -template -typename vdvector::iterator vdvector::insert_as(iterator position, const U& x) { - if (m.mpEnd == m.mpEOS) { - const size_type currSize = m.mpEnd - m.mpBegin; - const size_type newCapacity = currSize + 1; - - const pointer p0 = m.allocate(newCapacity); - pointer pe = p0; - try { - const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); - pe = p1; - - new(pe) T(x); - ++pe; - - const pointer p3 = std::uninitialized_copy(position, m.mpEnd, pe); - pe = p3; - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = pe; - m.mpEOS = p0 + newCapacity; - - return p1; - } catch(...) { - while(pe != p0) { - --pe; - pe->~T(); - } - - m.deallocate(p0, newCapacity); - throw; - } - } else if (position != m.mpEnd) { - T tmp(*position); - - *position = x; - - new(m.mpEnd) T(); - - try { - vdmove_backward(position + 1, m.mpEnd, m.mpEnd + 1); - position[1] = tmp; - ++m.mpEnd; - } catch(...) { - m.mpEnd->~T(); - throw; - } - - return position; - } else { - new(m.mpEnd) T(x); - ++m.mpEnd; - - return position; - } -} - -template -typename vdvector::iterator vdvector::insert(iterator position, const T& x) { - if (m.mpEnd == m.mpEOS) { - const size_type currSize = m.mpEnd - m.mpBegin; - const size_type newCapacity = currSize + 1; - - const pointer p0 = m.allocate(newCapacity); - pointer pe = p0; - try { - const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); - pe = p1; - - new(pe) T(x); - ++pe; - - const pointer p3 = std::uninitialized_copy(position, m.mpEnd, pe); - pe = p3; - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = pe; - m.mpEOS = p0 + newCapacity; - - return p1; - } catch(...) { - while(pe != p0) { - --pe; - pe->~T(); - } - - m.deallocate(p0, newCapacity); - throw; - } - } else if (position != m.mpEnd) { - T tmp(*position); - - *position = x; - - new(m.mpEnd) T(); - - try { - vdmove_backward(position + 1, m.mpEnd, m.mpEnd + 1); - position[1] = tmp; - ++m.mpEnd; - } catch(...) { - m.mpEnd->~T(); - throw; - } - - return position; - } else { - new(m.mpEnd) T(x); - ++m.mpEnd; - - return position; - } -} - -template -void vdvector::insert(iterator position, size_type n, const T& x) { - if ((size_type)(m.mpEOS - m.mpEnd) < n) { - const size_type currSize = m.mpEnd - m.mpBegin; - const size_type newCapacity = currSize + n; - - const pointer p0 = m.allocate(newCapacity); - pointer pe = p0; - try { - const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); - pe = p1; - - const pointer p2 = p1 + n; - std::uninitialized_fill(p1, p2, x); - pe = p2; - - const pointer p3 = std::uninitialized_copy(position, m.mpEnd, p2); - pe = p3; - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = pe; - m.mpEOS = p0 + newCapacity; - } catch(...) { - while(pe != p0) { - --pe; - pe->~T(); - } - - m.deallocate(p0, newCapacity); - throw; - } - } else if (n) { - pointer newEnd = m.mpEnd + n; - pointer insEnd = std::copy_backward(position, m.mpEnd, newEnd); - - try { - std::uninitialized_fill(position, m.mpEnd, x); - m.mpEnd = newEnd; - } catch(...) { - std::copy(insEnd, newEnd, position); - throw; - } - } -} - -template -template -void vdvector::insert(iterator position, InputIterator first, InputIterator last) { - const size_type n = last - first; - - if ((size_type)(m.mpEOS - m.mpEnd) < n) { - const size_type currSize = m.mpEnd - m.mpBegin; - const size_type newCapacity = currSize + n; - - const pointer p0 = m.allocate(newCapacity); - pointer pe = p0; - try { - const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); - pe = p1; - - const pointer p2 = p1 + n; - std::uninitialized_copy(first, last, p1); - pe = p2; - - const pointer p3 = std::uninitialized_copy(position, m.mpEnd, p2); - pe = p3; - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = pe; - m.mpEOS = p0 + newCapacity; - } catch(...) { - while(pe != p0) { - --pe; - pe->~T(); - } - - m.deallocate(p0, newCapacity); - throw; - } - } else if (n) { - pointer newEnd = m.mpEnd + n; - pointer insEnd = std::copy_backward(position, m.mpEnd, newEnd); - - try { - std::uninitialized_copy(first, last, position); - m.mpEnd = newEnd; - } catch(...) { - std::copy(insEnd, newEnd, position); - throw; - } - } -} - -template -typename vdvector::iterator vdvector::erase(iterator position) { - m.mpEnd = vdmove_forward(position + 1, m.mpEnd, position); - m.mpEnd->~T(); - - return position; -} - -template -typename vdvector::iterator vdvector::erase(iterator first, iterator last) { - if (first != last) { - pointer p = vdmove_forward(last, m.mpEnd, first); - - for(pointer q = p; q != m.mpEnd; ++q) - q->~T(); - - m.mpEnd = p; - } - - return first; -} - -template -void vdvector::swap(vdvector& x) { - std::swap(m.mpBegin, x.m.mpBegin); - std::swap(m.mpEnd, x.m.mpEnd); - std::swap(m.mpEOS, x.m.mpEOS); -} - -template -void vdvector::clear() { - while(m.mpEnd != m.mpBegin) { - --m.mpEnd; - m.mpEnd->~T(); - } -} - -template -void vdvector::free_storage() { - pointer b = m.mpBegin; - pointer p = m.mpEnd; - - while(p != b) { - --p; - p->~T(); - } - - m.deallocate(b, m.mpEOS - b); -} - -#endif // f_VD2_SYSTEM_VDSTL_VECTOR_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2009 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_VECTOR_H +#define f_VD2_SYSTEM_VDSTL_VECTOR_H + +#ifdef _MSC_VER +#pragma once +#endif + +template > +class vdvector { +public: + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef T *iterator; + typedef const T *const_iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef A allocator_type; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + // 23.2.4.1 construct/copy/destroy: + explicit vdvector(); + explicit vdvector(const A&); + explicit vdvector(size_type n); + explicit vdvector(size_type n, const T& value, const A& = A()); + template + vdvector(InputIterator first, InputIterator last, const A& = A()); + vdvector(const vdvector& x); + ~vdvector(); + vdvector& operator=(const vdvector& x); + template + void assign(InputIterator first, InputIterator last); + void assign(size_type n, const T& u); + allocator_type get_allocator() const; + + // iterators: + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + reverse_iterator rend(); + const_reverse_iterator rend() const; + pointer data(); + const_pointer data() const; + + // 23.2.4.2 capacity: + size_type size() const; + size_type max_size() const; + size_type capacity() const; + bool empty() const; + + // element access: + reference operator[](size_type n); + const_reference operator[](size_type n) const; + const_reference at(size_type n) const; + reference at(size_type n); + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + void resize(size_type sz, T c = T()); + void reserve(size_type n); + + template + void push_back_as(const U& x); + + reference push_back(); + void push_back(const T& x); + void pop_back(); + iterator insert(iterator position, const T& x); + + template + iterator insert_as(iterator position, const U& x); + + void insert(iterator position, size_type n, const T& x); + template + void insert(iterator position, InputIterator first, InputIterator last); + iterator erase(iterator position); + iterator erase(iterator first, iterator last); + void swap(vdvector&); + void clear(); + +private: + void free_storage(); + + struct Data : public A { + pointer mpBegin; + pointer mpEnd; + pointer mpEOS; + + Data() : A(), mpBegin(NULL), mpEnd(NULL), mpEOS(NULL) {} + Data(const A& alloc) : A(alloc), mpBegin(NULL), mpEnd(NULL), mpEOS(NULL) {} + } m; +}; + +template +vdvector::vdvector() { +} + +template +vdvector::vdvector(const A& a) + : m(a) +{ +} + +template +vdvector::vdvector(size_type n) { + resize(n); +} + +template +vdvector::vdvector(size_type n, const T& value, const A& a) + : m(a) +{ + resize(n, value); +} + +template +template +vdvector::vdvector(InputIterator first, InputIterator last, const A& a) + : m(a) +{ + assign(first, last); +} + +template +vdvector::vdvector(const vdvector& x) + : m(static_cast(x.m)) +{ + assign(x.m.mpBegin, x.m.mpEnd); +} + +template +vdvector::~vdvector() { + clear(); + + if (m.mpBegin) + m.deallocate(m.mpBegin, m.mpEOS - m.mpBegin); +} + +template +vdvector& vdvector::operator=(const vdvector& x) { + if (&x != this) { + vdvector tmp(x); + + swap(tmp); + } + + return *this; +} + +template +template +void vdvector::assign(InputIterator first, InputIterator last) { + clear(); + insert(m.mpBegin, first, last); +} + +template +void vdvector::assign(size_type n, const T& u) { + clear(); + insert(m.mpBegin, n, u); +} + +template typename vdvector::allocator_type vdvector::get_allocator() const { return m; } +template typename vdvector::iterator vdvector::begin() { return m.mpBegin; } +template typename vdvector::const_iterator vdvector::begin() const { return m.mpBegin; } +template typename vdvector::iterator vdvector::end() { return m.mpEnd; } +template typename vdvector::const_iterator vdvector::end() const { return m.mpEnd; } +template typename vdvector::reverse_iterator vdvector::rbegin() { return reverse_iterator(m.mpEnd); } +template typename vdvector::const_reverse_iterator vdvector::rbegin() const { return const_reverse_iterator(m.mpEnd); } +template typename vdvector::reverse_iterator vdvector::rend() { return reverse_iterator(m.mpBegin); } +template typename vdvector::const_reverse_iterator vdvector::rend() const { return const_reverse_iterator(m.mpBegin); } +template typename vdvector::pointer vdvector::data() { return m.mpBegin; } +template typename vdvector::const_pointer vdvector::data() const { return m.mpBegin; } + +template typename vdvector::size_type vdvector::size() const { return m.mpEnd - m.mpBegin; } +template typename vdvector::size_type vdvector::max_size() const { return m.max_size(); } +template typename vdvector::size_type vdvector::capacity() const { return m.mpEOS - m.mpBegin; } +template bool vdvector::empty() const { return m.mpBegin == m.mpEnd; } + +template typename vdvector::reference vdvector::operator[](size_type n) { return m.mpBegin[n]; } +template typename vdvector::const_reference vdvector::operator[](size_type n) const { return m.mpBegin[n]; } +template typename vdvector::const_reference vdvector::at(size_type n) const { if (n >= (size_type)(m.mpEnd - m.mpBegin)) throw std::out_of_range("The index is out of range."); return m.mpBegin[n]; } +template typename vdvector::reference vdvector::at(size_type n) { if (n >= (size_type)(m.mpEnd - m.mpBegin)) throw std::out_of_range("The index is out of range."); return m.mpBegin[n]; } +template typename vdvector::reference vdvector::front() { return *m.mpBegin; } +template typename vdvector::const_reference vdvector::front() const { return *m.mpBegin; } +template typename vdvector::reference vdvector::back() { return m.mpEnd[-1]; } +template typename vdvector::const_reference vdvector::back() const { return m.mpEnd[-1]; } + +template +void vdvector::resize(size_type sz, T c) { + const size_type currSize = m.mpEnd - m.mpBegin; + + if (sz < currSize) { + T *p = m.mpBegin + sz; + while(m.mpEnd != p) { + --m.mpEnd; + m.mpEnd->~T(); + } + } else if (sz > currSize) { + const size_type currCapacity = m.mpEOS - m.mpBegin; + + if (sz > currCapacity) { + pointer p0 = m.allocate(sz); + + try { + pointer p1 = std::uninitialized_copy(m.mpBegin, m.mpEnd, p0); + pointer p2 = p0 + sz; + + T *prev0 = m.mpBegin; + T *prev1 = m.mpEnd; + T *prev2 = m.mpEOS; + try { + std::uninitialized_fill(p1, p2, c); + + // destroy old range + while(prev1 != prev0) { + --prev1; + prev0->~T(); + } + + m.mpBegin = p0; + m.mpEnd = p2; + m.mpEOS = p2; + } catch(...) { + while(p2 != p1) { + --p2; + p2->~T(); + } + m.deallocate(p0, sz); + throw; + } + + m.deallocate(prev0, prev2 - prev0); + } catch(...) { + m.deallocate(p0, sz); + throw; + } + } else { + pointer newEnd = m.mpBegin + sz; + std::uninitialized_fill(m.mpEnd, newEnd, c); + m.mpEnd = newEnd; + } + } +} + +template +void vdvector::reserve(size_type n) { + const size_type currCapacity = m.mpEOS - m.mpBegin; + + if (n <= currCapacity) + return; + + pointer p0 = m.allocate(n); + + try { + pointer p1 = std::uninitialized_copy(m.mpBegin, m.mpEnd, p0); + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = p1; + m.mpEOS = p0 + n; + } catch(...) { + m.deallocate(p0, n); + throw; + } +} + +template +template +void vdvector::push_back_as(const U& x) { + if (m.mpEnd != m.mpEOS) { + new(m.mpEnd) T(x); + ++m.mpEnd; + } else { + insert_as(m.mpEnd, x); + } +} + +template +typename vdvector::reference vdvector::push_back() { + if (m.mpEnd != m.mpEOS) { + new(m.mpEnd) T(); + return *m.mpEnd++; + } else { + return *insert(m.mpEnd, T()); + } +} + +template +void vdvector::push_back(const T& x) { + VDASSERT(m.mpEnd >= m.mpBegin && m.mpEnd <= m.mpEOS); + if (m.mpEnd != m.mpEOS) { + new(m.mpEnd) T(x); + ++m.mpEnd; + } else { + insert(m.mpEnd, x); + } +} + +template +void vdvector::pop_back() { + --m.mpEnd; + m.mpEnd->~T(); +} + +template +template +typename vdvector::iterator vdvector::insert_as(iterator position, const U& x) { + if (m.mpEnd == m.mpEOS) { + const size_type currSize = m.mpEnd - m.mpBegin; + const size_type newCapacity = currSize + 1; + + const pointer p0 = m.allocate(newCapacity); + pointer pe = p0; + try { + const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); + pe = p1; + + new(pe) T(x); + ++pe; + + const pointer p3 = std::uninitialized_copy(position, m.mpEnd, pe); + pe = p3; + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = pe; + m.mpEOS = p0 + newCapacity; + + return p1; + } catch(...) { + while(pe != p0) { + --pe; + pe->~T(); + } + + m.deallocate(p0, newCapacity); + throw; + } + } else if (position != m.mpEnd) { + T tmp(*position); + + *position = x; + + new(m.mpEnd) T(); + + try { + vdmove_backward(position + 1, m.mpEnd, m.mpEnd + 1); + position[1] = tmp; + ++m.mpEnd; + } catch(...) { + m.mpEnd->~T(); + throw; + } + + return position; + } else { + new(m.mpEnd) T(x); + ++m.mpEnd; + + return position; + } +} + +template +typename vdvector::iterator vdvector::insert(iterator position, const T& x) { + if (m.mpEnd == m.mpEOS) { + const size_type currSize = m.mpEnd - m.mpBegin; + const size_type newCapacity = currSize + 1; + + const pointer p0 = m.allocate(newCapacity); + pointer pe = p0; + try { + const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); + pe = p1; + + new(pe) T(x); + ++pe; + + const pointer p3 = std::uninitialized_copy(position, m.mpEnd, pe); + pe = p3; + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = pe; + m.mpEOS = p0 + newCapacity; + + return p1; + } catch(...) { + while(pe != p0) { + --pe; + pe->~T(); + } + + m.deallocate(p0, newCapacity); + throw; + } + } else if (position != m.mpEnd) { + T tmp(*position); + + *position = x; + + new(m.mpEnd) T(); + + try { + vdmove_backward(position + 1, m.mpEnd, m.mpEnd + 1); + position[1] = tmp; + ++m.mpEnd; + } catch(...) { + m.mpEnd->~T(); + throw; + } + + return position; + } else { + new(m.mpEnd) T(x); + ++m.mpEnd; + + return position; + } +} + +template +void vdvector::insert(iterator position, size_type n, const T& x) { + if ((size_type)(m.mpEOS - m.mpEnd) < n) { + const size_type currSize = m.mpEnd - m.mpBegin; + const size_type newCapacity = currSize + n; + + const pointer p0 = m.allocate(newCapacity); + pointer pe = p0; + try { + const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); + pe = p1; + + const pointer p2 = p1 + n; + std::uninitialized_fill(p1, p2, x); + pe = p2; + + const pointer p3 = std::uninitialized_copy(position, m.mpEnd, p2); + pe = p3; + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = pe; + m.mpEOS = p0 + newCapacity; + } catch(...) { + while(pe != p0) { + --pe; + pe->~T(); + } + + m.deallocate(p0, newCapacity); + throw; + } + } else if (n) { + pointer newEnd = m.mpEnd + n; + pointer insEnd = std::copy_backward(position, m.mpEnd, newEnd); + + try { + std::uninitialized_fill(position, m.mpEnd, x); + m.mpEnd = newEnd; + } catch(...) { + std::copy(insEnd, newEnd, position); + throw; + } + } +} + +template +template +void vdvector::insert(iterator position, InputIterator first, InputIterator last) { + const size_type n = last - first; + + if ((size_type)(m.mpEOS - m.mpEnd) < n) { + const size_type currSize = m.mpEnd - m.mpBegin; + const size_type newCapacity = currSize + n; + + const pointer p0 = m.allocate(newCapacity); + pointer pe = p0; + try { + const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); + pe = p1; + + const pointer p2 = p1 + n; + std::uninitialized_copy(first, last, p1); + pe = p2; + + const pointer p3 = std::uninitialized_copy(position, m.mpEnd, p2); + pe = p3; + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = pe; + m.mpEOS = p0 + newCapacity; + } catch(...) { + while(pe != p0) { + --pe; + pe->~T(); + } + + m.deallocate(p0, newCapacity); + throw; + } + } else if (n) { + pointer newEnd = m.mpEnd + n; + pointer insEnd = std::copy_backward(position, m.mpEnd, newEnd); + + try { + std::uninitialized_copy(first, last, position); + m.mpEnd = newEnd; + } catch(...) { + std::copy(insEnd, newEnd, position); + throw; + } + } +} + +template +typename vdvector::iterator vdvector::erase(iterator position) { + m.mpEnd = vdmove_forward(position + 1, m.mpEnd, position); + m.mpEnd->~T(); + + return position; +} + +template +typename vdvector::iterator vdvector::erase(iterator first, iterator last) { + if (first != last) { + pointer p = vdmove_forward(last, m.mpEnd, first); + + for(pointer q = p; q != m.mpEnd; ++q) + q->~T(); + + m.mpEnd = p; + } + + return first; +} + +template +void vdvector::swap(vdvector& x) { + std::swap(m.mpBegin, x.m.mpBegin); + std::swap(m.mpEnd, x.m.mpEnd); + std::swap(m.mpEOS, x.m.mpEOS); +} + +template +void vdvector::clear() { + while(m.mpEnd != m.mpBegin) { + --m.mpEnd; + m.mpEnd->~T(); + } +} + +template +void vdvector::free_storage() { + pointer b = m.mpBegin; + pointer p = m.mpEnd; + + while(p != b) { + --p; + p->~T(); + } + + m.deallocate(b, m.mpEOS - b); +} + +#endif // f_VD2_SYSTEM_VDSTL_VECTOR_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdtypes.h b/src/thirdparty/VirtualDub/h/vd2/system/vdtypes.h index 3bcf227f323..98bfde66558 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdtypes.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdtypes.h @@ -1,449 +1,449 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDTYPES_H -#define f_VD2_SYSTEM_VDTYPES_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include -#include -#include - -#ifndef NULL -#define NULL 0 -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// compiler detection -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef VD_COMPILER_DETECTED - #define VD_COMPILER_DETECTED - - #if defined(_MSC_VER) - #define VD_COMPILER_MSVC _MSC_VER - - #if _MSC_VER >= 1400 - #define VD_COMPILER_MSVC_VC8 1 - #define VD_COMPILER_MSVC_VC8_OR_LATER 1 - - #if _MSC_FULL_VER == 140040310 - #define VD_COMPILER_MSVC_VC8_PSDK 1 - #elif _MSC_FULL_VER == 14002207 - #define VD_COMPILER_MSVC_VC8_DDK 1 - #endif - - #elif _MSC_VER >= 1310 - #define VD_COMPILER_MSVC_VC71 1 - #elif _MSC_VER >= 1300 - #define VD_COMPILER_MSVC_VC7 1 - #elif _MSC_VER >= 1200 - #define VD_COMPILER_MSVC_VC6 1 - #endif - #elif defined(__GNUC__) - #define VD_COMPILER_GCC - #if defined(__MINGW32__) || defined(__MINGW64__) - #define VD_COMPILER_GCC_MINGW - #endif - #endif -#endif - -#ifndef VD_CPU_DETECTED - #define VD_CPU_DETECTED - - #if defined(_M_AMD64) - #define VD_CPU_AMD64 1 - #elif defined(_M_IX86) || defined(__i386__) - #define VD_CPU_X86 1 - #elif defined(_M_ARM) - #define VD_CPU_ARM - #endif -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// types -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef VD_STANDARD_TYPES_DECLARED - #if defined(_MSC_VER) - typedef signed __int64 sint64; - typedef unsigned __int64 uint64; - #elif defined(__GNUC__) - typedef signed long long sint64; - typedef unsigned long long uint64; - #endif - typedef signed int sint32; - typedef unsigned int uint32; - typedef signed short sint16; - typedef unsigned short uint16; - typedef signed char sint8; - typedef unsigned char uint8; - - typedef sint64 int64; - typedef sint32 int32; - typedef sint16 int16; - typedef sint8 int8; - - #ifdef _M_AMD64 - typedef sint64 sintptr; - typedef uint64 uintptr; - #else - #if _MSC_VER >= 1310 - typedef __w64 sint32 sintptr; - typedef __w64 uint32 uintptr; - #else - typedef sint32 sintptr; - typedef uint32 uintptr; - #endif - #endif -#endif - -#if defined(_MSC_VER) - #define VD64(x) x##i64 -#elif defined(__GNUC__) - #define VD64(x) x##ll -#else - #error Please add an entry for your compiler for 64-bit constant literals. -#endif - - -#define VDAPIENTRY __cdecl - -typedef int64 VDTime; -typedef int64 VDPosition; -typedef struct __VDGUIHandle *VDGUIHandle; - -// enforce wchar_t under Visual C++ - -#if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) - #include -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// allocation -// -/////////////////////////////////////////////////////////////////////////// - -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1300 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) -#define new_nothrow new -#else -#define new_nothrow new(std::nothrow) -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// STL fixes -// -/////////////////////////////////////////////////////////////////////////// - -#if defined(VD_COMPILER_MSVC_VC6) || defined(VD_COMPILER_MSVC_VC8_DDK) || defined(VD_COMPILER_MSVC_VC8_PSDK) - // The VC6 STL was deliberately borked to avoid conflicting with - // Windows min/max macros. We work around this bogosity here. Note - // that NOMINMAX must be defined for these to compile properly. Also, - // there is a bug in the VC6 compiler that sometimes causes long - // lvalues to "promote" to int, causing ambiguous override errors. - // To avoid this, always explicitly declare which type you are using, - // i.e. min(x,0). None of this is a problem with VC7 or later. - namespace std { - template - inline const T& min(const T& x, const T& y) { - return _cpp_min(x, y); - } - - template - inline const T& max(const T& x, const T& y) { - return _cpp_max(x, y); - } - }; -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// compiler fixes -// -/////////////////////////////////////////////////////////////////////////// - -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) - inline int vswprintf(wchar_t *dst, size_t bufsize, const wchar_t *format, va_list val) { - return _vsnwprintf(dst, bufsize, format, val); - } - - inline int swprintf(wchar_t *dst, size_t bufsize, const wchar_t *format, ...) { - va_list val; - - va_start(val, format); - int r = vswprintf(dst, bufsize, format, val); - va_end(val); - - return r; - } - - #define _strdup strdup - #define _stricmp stricmp - #define _strnicmp strnicmp - #define _wcsdup wcsdup - #define _wcsicmp wcsicmp - #define _wcsnicmp wcsnicmp -#endif - -#if defined(VD_COMPILER_MSVC) && VD_COMPILER_MSVC < 1400 - #define vdfor if(0);else for -#else - #define vdfor for -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// attribute support -// -/////////////////////////////////////////////////////////////////////////// - -#if defined(VD_COMPILER_MSVC) - #define VDINTERFACE __declspec(novtable) - #define VDNORETURN __declspec(noreturn) - #define VDPUREFUNC - - #if VD_COMPILER_MSVC >= 1400 - #define VDRESTRICT __restrict - #else - #define VDRESTRICT - #endif - - #define VDNOINLINE __declspec(noinline) - #define VDFORCEINLINE __forceinline - #define VDALIGN(alignment) __declspec(align(alignment)) -#elif defined(VD_COMPILER_GCC) - #define VDINTERFACE - #define VDNORETURN __attribute__((noreturn)) - #define VDPUREFUNC __attribute__((pure)) - #define VDRESTRICT __restrict - #define VDNOINLINE __attribute__((noinline)) - #define VDFORCEINLINE inline __attribute__((always_inline)) - #define VDALIGN(alignment) __attribute__((aligned(alignment))) -#else - #define VDINTERFACE - #define VDNORETURN - #define VDPUREFUNC - #define VDRESTRICT - #define VDFORCEINLINE - #define VDALIGN(alignment) -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// debug support -// -/////////////////////////////////////////////////////////////////////////// - -enum VDAssertResult { - kVDAssertBreak, - kVDAssertContinue, - kVDAssertIgnore -}; - -extern VDAssertResult VDAssert(const char *exp, const char *file, int line); -extern VDAssertResult VDAssertPtr(const char *exp, const char *file, int line); -extern void VDDebugPrint(const char *format, ...); - -#if defined(_MSC_VER) - #if _MSC_VER >= 1300 - #define VDBREAK __debugbreak() - #else - #define VDBREAK __asm { int 3 } - #endif -#elif defined(__GNUC__) - #define VDBREAK __asm__ volatile ("int3" : : ) -#else - #define VDBREAK *(volatile char *)0 = *(volatile char *)0 -#endif - - -#ifdef _DEBUG - - namespace { - template - struct VDAssertHelper { - VDAssertHelper(const char *exp, const char *file) { - if (!sbAssertDisabled) - switch(VDAssert(exp, file, line)) { - case kVDAssertBreak: - VDBREAK; - break; - case kVDAssertIgnore: - sbAssertDisabled = true; - break; - } - } - - static bool sbAssertDisabled; - }; - - template - bool VDAssertHelper::sbAssertDisabled; - - template - struct VDAssertHelper2 { static bool sDisabled; }; - - template - bool VDAssertHelper2::sDisabled; - } - -// MPC-HC custom code start -// We use the old code since the new templated code isn't compatible with MSVC "Edit and continue" feature -// because __LINE__ can't be known at compile time. -#if !defined(VD_COMPILER_MSVC) || defined(__INTEL_COMPILER) - #define VDASSERT(exp) if (!VDAssertHelper2<__LINE__>::sDisabled) if (exp); else switch(VDAssert (#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) - #define VDASSERTPTR(exp) if (!VDAssertHelper2<__LINE__>::sDisabled) if (exp); else switch(VDAssertPtr(#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) - #define VDVERIFY(exp) if (exp); else if (!VDAssertHelper2<__LINE__>::sDisabled) switch(VDAssert (#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) - #define VDVERIFYPTR(exp) if (exp); else if (!VDAssertHelper2<__LINE__>::sDisabled) switch(VDAssertPtr(#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) -#else - #define VDASSERT(exp) do { } while (0) - #define VDASSERTPTR(exp) do { } while (0) - #define VDVERIFY(exp) do { } while (0) - #define VDVERIFYPTR(exp) do { } while (0) -#endif -// MPC-HC custom code end - #define VDASSERTCT(exp) (void)sizeof(int[(exp)?1:-1]) - - #define VDINLINEASSERT(exp) ((exp)||(VDAssertHelper<__LINE__>(#exp, __FILE__),false)) - #define VDINLINEASSERTFALSE(exp) ((exp)&&(VDAssertHelper<__LINE__>("!("#exp")", __FILE__),true)) - - #define NEVER_HERE do { if (VDAssert( "[never here]", __FILE__, __LINE__ )) VDBREAK; __assume(false); } while(false) - #define VDNEVERHERE do { if (VDAssert( "[never here]", __FILE__, __LINE__ )) VDBREAK; __assume(false); } while(false) - - #define VDDEBUG VDDebugPrint - -#else - - #if defined(_MSC_VER) - #ifndef _M_AMD64 - #define VDASSERT(exp) __assume(!!(exp)) - #define VDASSERTPTR(exp) __assume(!!(exp)) - #else - #define VDASSERT(exp) __noop(exp) - #define VDASSERTPTR(exp) __noop(exp) - #endif - #elif defined(__GNUC__) - #define VDASSERT(exp) __builtin_expect(0 != (exp), 1) - #define VDASSERTPTR(exp) __builtin_expect(0 != (exp), 1) - #endif - - #define VDVERIFY(exp) (exp) - #define VDVERIFYPTR(exp) (exp) - #define VDASSERTCT(exp) - - #define VDINLINEASSERT(exp) (exp) - #define VDINLINEASSERTFALSE(exp) (exp) - - #if defined(VD_COMPILER_MSVC) - #define NEVER_HERE __assume(false) - #define VDNEVERHERE __assume(false) - #else - #define NEVER_HERE VDASSERT(false) - #define VDNEVERHERE VDASSERT(false) - #endif - - extern int VDDEBUG_Helper(const char *, ...); - #define VDDEBUG (void)sizeof VDDEBUG_Helper - -#endif - -#define VDDEBUG2 VDDebugPrint - -// TODO macros -// -// These produce a diagnostic during compilation that indicate a TODO for -// later: -// -// #pragma message(__TODO__ "Fix this.) -// #vdpragma_TODO("Fix this.") - -#define vdpragma_TODO2(x) #x -#define vdpragma_TODO1(x) vdpragma_TODO2(x) -#define vdpragma_TODO0 __FILE__ "(" vdpragma_TODO1(__LINE__) ") : TODO: " - -#ifdef _MSC_VER -#define vdpragma_TODO(x) message(vdpragma_TODO0 x) -#else -#define vdpragma_TODO(x) -#endif - -// BS macros -// -// These tag code that is not meant to go into a final build. - -#define vdpragma_BS2(x) #x -#define vdpragma_BS1(x) vdpragma_BS2(x) -#define vdpragma_BS0 __FILE__ "(" vdpragma_BS1(__LINE__) ") : BS: " - -#ifdef _MSC_VER -#define vdpragma_BS(x) message(vdpragma_BS0 x) -#else -#define vdpragma_BS(x) -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// Object scope macros -// -// vdobjectscope() allows you to define a construct where an object is -// constructed and live only within the controlled statement. This is -// used for vdsynchronized (thread.h) and protected scopes below. -// It relies on a strange quirk of C++ regarding initialized objects -// in the condition of a selection statement and also horribly abuses -// the switch statement, generating rather good code in release builds. -// The catch is that the controlled object must implement a conversion to -// bool returning false and must only be initialized with one argument (C -// syntax). -// -// Unfortunately, handy as this macro is, it is also damned good at -// breaking compilers. For a start, declaring an object with a non- -// trivial destructor in a switch() kills both VC6 and VC7 with a C1001. -// The bug is fixed in VC8 (MSC 14.00). -// -// A somewhat safer alternative is the for() statement, along the lines -// of: -// -// switch(bool v=false) case 0: default: for(object_def; !v; v=true) -// -// This avoids the conversion operator but unfortunately usually generates -// an actual loop in the output. - -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || defined(VD_COMPILER_MSVC_VC8_DDK)) -#define vdobjectscope(object_def) if(object_def) VDNEVERHERE; else -#else -#define vdobjectscope(object_def) switch(object_def) case 0: default: -#endif - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDTYPES_H +#define f_VD2_SYSTEM_VDTYPES_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// compiler detection +// +/////////////////////////////////////////////////////////////////////////// + +#ifndef VD_COMPILER_DETECTED + #define VD_COMPILER_DETECTED + + #if defined(_MSC_VER) + #define VD_COMPILER_MSVC _MSC_VER + + #if _MSC_VER >= 1400 + #define VD_COMPILER_MSVC_VC8 1 + #define VD_COMPILER_MSVC_VC8_OR_LATER 1 + + #if _MSC_FULL_VER == 140040310 + #define VD_COMPILER_MSVC_VC8_PSDK 1 + #elif _MSC_FULL_VER == 14002207 + #define VD_COMPILER_MSVC_VC8_DDK 1 + #endif + + #elif _MSC_VER >= 1310 + #define VD_COMPILER_MSVC_VC71 1 + #elif _MSC_VER >= 1300 + #define VD_COMPILER_MSVC_VC7 1 + #elif _MSC_VER >= 1200 + #define VD_COMPILER_MSVC_VC6 1 + #endif + #elif defined(__GNUC__) + #define VD_COMPILER_GCC + #if defined(__MINGW32__) || defined(__MINGW64__) + #define VD_COMPILER_GCC_MINGW + #endif + #endif +#endif + +#ifndef VD_CPU_DETECTED + #define VD_CPU_DETECTED + + #if defined(_M_AMD64) + #define VD_CPU_AMD64 1 + #elif defined(_M_IX86) || defined(__i386__) + #define VD_CPU_X86 1 + #elif defined(_M_ARM) + #define VD_CPU_ARM + #endif +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// types +// +/////////////////////////////////////////////////////////////////////////// + +#ifndef VD_STANDARD_TYPES_DECLARED + #if defined(_MSC_VER) + typedef signed __int64 sint64; + typedef unsigned __int64 uint64; + #elif defined(__GNUC__) + typedef signed long long sint64; + typedef unsigned long long uint64; + #endif + typedef signed int sint32; + typedef unsigned int uint32; + typedef signed short sint16; + typedef unsigned short uint16; + typedef signed char sint8; + typedef unsigned char uint8; + + typedef sint64 int64; + typedef sint32 int32; + typedef sint16 int16; + typedef sint8 int8; + + #ifdef _M_AMD64 + typedef sint64 sintptr; + typedef uint64 uintptr; + #else + #if _MSC_VER >= 1310 + typedef __w64 sint32 sintptr; + typedef __w64 uint32 uintptr; + #else + typedef sint32 sintptr; + typedef uint32 uintptr; + #endif + #endif +#endif + +#if defined(_MSC_VER) + #define VD64(x) x##i64 +#elif defined(__GNUC__) + #define VD64(x) x##ll +#else + #error Please add an entry for your compiler for 64-bit constant literals. +#endif + + +#define VDAPIENTRY __cdecl + +typedef int64 VDTime; +typedef int64 VDPosition; +typedef struct __VDGUIHandle *VDGUIHandle; + +// enforce wchar_t under Visual C++ + +#if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) + #include +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// allocation +// +/////////////////////////////////////////////////////////////////////////// + +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1300 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) +#define new_nothrow new +#else +#define new_nothrow new(std::nothrow) +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// STL fixes +// +/////////////////////////////////////////////////////////////////////////// + +#if defined(VD_COMPILER_MSVC_VC6) || defined(VD_COMPILER_MSVC_VC8_DDK) || defined(VD_COMPILER_MSVC_VC8_PSDK) + // The VC6 STL was deliberately borked to avoid conflicting with + // Windows min/max macros. We work around this bogosity here. Note + // that NOMINMAX must be defined for these to compile properly. Also, + // there is a bug in the VC6 compiler that sometimes causes long + // lvalues to "promote" to int, causing ambiguous override errors. + // To avoid this, always explicitly declare which type you are using, + // i.e. min(x,0). None of this is a problem with VC7 or later. + namespace std { + template + inline const T& min(const T& x, const T& y) { + return _cpp_min(x, y); + } + + template + inline const T& max(const T& x, const T& y) { + return _cpp_max(x, y); + } + }; +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// compiler fixes +// +/////////////////////////////////////////////////////////////////////////// + +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) + inline int vswprintf(wchar_t *dst, size_t bufsize, const wchar_t *format, va_list val) { + return _vsnwprintf(dst, bufsize, format, val); + } + + inline int swprintf(wchar_t *dst, size_t bufsize, const wchar_t *format, ...) { + va_list val; + + va_start(val, format); + int r = vswprintf(dst, bufsize, format, val); + va_end(val); + + return r; + } + + #define _strdup strdup + #define _stricmp stricmp + #define _strnicmp strnicmp + #define _wcsdup wcsdup + #define _wcsicmp wcsicmp + #define _wcsnicmp wcsnicmp +#endif + +#if defined(VD_COMPILER_MSVC) && VD_COMPILER_MSVC < 1400 + #define vdfor if(0);else for +#else + #define vdfor for +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// attribute support +// +/////////////////////////////////////////////////////////////////////////// + +#if defined(VD_COMPILER_MSVC) + #define VDINTERFACE __declspec(novtable) + #define VDNORETURN __declspec(noreturn) + #define VDPUREFUNC + + #if VD_COMPILER_MSVC >= 1400 + #define VDRESTRICT __restrict + #else + #define VDRESTRICT + #endif + + #define VDNOINLINE __declspec(noinline) + #define VDFORCEINLINE __forceinline + #define VDALIGN(alignment) __declspec(align(alignment)) +#elif defined(VD_COMPILER_GCC) + #define VDINTERFACE + #define VDNORETURN __attribute__((noreturn)) + #define VDPUREFUNC __attribute__((pure)) + #define VDRESTRICT __restrict + #define VDNOINLINE __attribute__((noinline)) + #define VDFORCEINLINE inline __attribute__((always_inline)) + #define VDALIGN(alignment) __attribute__((aligned(alignment))) +#else + #define VDINTERFACE + #define VDNORETURN + #define VDPUREFUNC + #define VDRESTRICT + #define VDFORCEINLINE + #define VDALIGN(alignment) +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// debug support +// +/////////////////////////////////////////////////////////////////////////// + +enum VDAssertResult { + kVDAssertBreak, + kVDAssertContinue, + kVDAssertIgnore +}; + +extern VDAssertResult VDAssert(const char *exp, const char *file, int line); +extern VDAssertResult VDAssertPtr(const char *exp, const char *file, int line); +extern void VDDebugPrint(const char *format, ...); + +#if defined(_MSC_VER) + #if _MSC_VER >= 1300 + #define VDBREAK __debugbreak() + #else + #define VDBREAK __asm { int 3 } + #endif +#elif defined(__GNUC__) + #define VDBREAK __asm__ volatile ("int3" : : ) +#else + #define VDBREAK *(volatile char *)0 = *(volatile char *)0 +#endif + + +#ifdef _DEBUG + + namespace { + template + struct VDAssertHelper { + VDAssertHelper(const char *exp, const char *file) { + if (!sbAssertDisabled) + switch(VDAssert(exp, file, line)) { + case kVDAssertBreak: + VDBREAK; + break; + case kVDAssertIgnore: + sbAssertDisabled = true; + break; + } + } + + static bool sbAssertDisabled; + }; + + template + bool VDAssertHelper::sbAssertDisabled; + + template + struct VDAssertHelper2 { static bool sDisabled; }; + + template + bool VDAssertHelper2::sDisabled; + } + +// MPC-HC custom code start +// We use the old code since the new templated code isn't compatible with MSVC "Edit and continue" feature +// because __LINE__ can't be known at compile time. +#if !defined(VD_COMPILER_MSVC) || defined(__INTEL_COMPILER) + #define VDASSERT(exp) if (!VDAssertHelper2<__LINE__>::sDisabled) if (exp); else switch(VDAssert (#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) + #define VDASSERTPTR(exp) if (!VDAssertHelper2<__LINE__>::sDisabled) if (exp); else switch(VDAssertPtr(#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) + #define VDVERIFY(exp) if (exp); else if (!VDAssertHelper2<__LINE__>::sDisabled) switch(VDAssert (#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) + #define VDVERIFYPTR(exp) if (exp); else if (!VDAssertHelper2<__LINE__>::sDisabled) switch(VDAssertPtr(#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) +#else + #define VDASSERT(exp) do { } while (0) + #define VDASSERTPTR(exp) do { } while (0) + #define VDVERIFY(exp) do { } while (0) + #define VDVERIFYPTR(exp) do { } while (0) +#endif +// MPC-HC custom code end + #define VDASSERTCT(exp) (void)sizeof(int[(exp)?1:-1]) + + #define VDINLINEASSERT(exp) ((exp)||(VDAssertHelper<__LINE__>(#exp, __FILE__),false)) + #define VDINLINEASSERTFALSE(exp) ((exp)&&(VDAssertHelper<__LINE__>("!("#exp")", __FILE__),true)) + + #define NEVER_HERE do { if (VDAssert( "[never here]", __FILE__, __LINE__ )) VDBREAK; __assume(false); } while(false) + #define VDNEVERHERE do { if (VDAssert( "[never here]", __FILE__, __LINE__ )) VDBREAK; __assume(false); } while(false) + + #define VDDEBUG VDDebugPrint + +#else + + #if defined(_MSC_VER) + #ifndef _M_AMD64 + #define VDASSERT(exp) __assume(!!(exp)) + #define VDASSERTPTR(exp) __assume(!!(exp)) + #else + #define VDASSERT(exp) __noop(exp) + #define VDASSERTPTR(exp) __noop(exp) + #endif + #elif defined(__GNUC__) + #define VDASSERT(exp) __builtin_expect(0 != (exp), 1) + #define VDASSERTPTR(exp) __builtin_expect(0 != (exp), 1) + #endif + + #define VDVERIFY(exp) (exp) + #define VDVERIFYPTR(exp) (exp) + #define VDASSERTCT(exp) + + #define VDINLINEASSERT(exp) (exp) + #define VDINLINEASSERTFALSE(exp) (exp) + + #if defined(VD_COMPILER_MSVC) + #define NEVER_HERE __assume(false) + #define VDNEVERHERE __assume(false) + #else + #define NEVER_HERE VDASSERT(false) + #define VDNEVERHERE VDASSERT(false) + #endif + + extern int VDDEBUG_Helper(const char *, ...); + #define VDDEBUG (void)sizeof VDDEBUG_Helper + +#endif + +#define VDDEBUG2 VDDebugPrint + +// TODO macros +// +// These produce a diagnostic during compilation that indicate a TODO for +// later: +// +// #pragma message(__TODO__ "Fix this.) +// #vdpragma_TODO("Fix this.") + +#define vdpragma_TODO2(x) #x +#define vdpragma_TODO1(x) vdpragma_TODO2(x) +#define vdpragma_TODO0 __FILE__ "(" vdpragma_TODO1(__LINE__) ") : TODO: " + +#ifdef _MSC_VER +#define vdpragma_TODO(x) message(vdpragma_TODO0 x) +#else +#define vdpragma_TODO(x) +#endif + +// BS macros +// +// These tag code that is not meant to go into a final build. + +#define vdpragma_BS2(x) #x +#define vdpragma_BS1(x) vdpragma_BS2(x) +#define vdpragma_BS0 __FILE__ "(" vdpragma_BS1(__LINE__) ") : BS: " + +#ifdef _MSC_VER +#define vdpragma_BS(x) message(vdpragma_BS0 x) +#else +#define vdpragma_BS(x) +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// Object scope macros +// +// vdobjectscope() allows you to define a construct where an object is +// constructed and live only within the controlled statement. This is +// used for vdsynchronized (thread.h) and protected scopes below. +// It relies on a strange quirk of C++ regarding initialized objects +// in the condition of a selection statement and also horribly abuses +// the switch statement, generating rather good code in release builds. +// The catch is that the controlled object must implement a conversion to +// bool returning false and must only be initialized with one argument (C +// syntax). +// +// Unfortunately, handy as this macro is, it is also damned good at +// breaking compilers. For a start, declaring an object with a non- +// trivial destructor in a switch() kills both VC6 and VC7 with a C1001. +// The bug is fixed in VC8 (MSC 14.00). +// +// A somewhat safer alternative is the for() statement, along the lines +// of: +// +// switch(bool v=false) case 0: default: for(object_def; !v; v=true) +// +// This avoids the conversion operator but unfortunately usually generates +// an actual loop in the output. + +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || defined(VD_COMPILER_MSVC_VC8_DDK)) +#define vdobjectscope(object_def) if(object_def) VDNEVERHERE; else +#else +#define vdobjectscope(object_def) switch(object_def) case 0: default: +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vectors.h b/src/thirdparty/VirtualDub/h/vd2/system/vectors.h index a7957a4d185..df411757b12 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vectors.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vectors.h @@ -1,616 +1,616 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VECTORS_H -#define f_VD2_SYSTEM_VECTORS_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -bool VDSolveLinearEquation(double *src, int n, ptrdiff_t stride_elements, double *b, double tolerance = 1e-5); - -/////////////////////////////////////////////////////////////////////////// - -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -class vdfloat2x2 { -public: - enum zero_type { zero }; - enum identity_type { identity }; - - typedef float value_type; - typedef vdfloat2 vector_type; - typedef vdfloat2c vector_ctor_type; - typedef vdfloat2x2 self_type; - - vdfloat2x2() {} - vdfloat2x2(zero_type) { m[0] = m[1] = vector_ctor_type(0, 0); } - vdfloat2x2(identity_type) { - m[0] = vector_ctor_type(1, 0); - m[1] = vector_ctor_type(0, 1); - } - - vector_type& operator[](int k) { return m[k]; } - const vector_type& operator[](int k) const { return m[k]; } - - self_type operator*(const self_type& v) const { - self_type result; - -#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] - DO(0,0); - DO(0,1); - DO(1,0); - DO(1,1); -#undef DO - - return result; - } - - vector_type operator*(const vector_type& r) const { - return vector_ctor_type( - m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1], - m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1]); - } - - self_type transpose() const { - self_type res; - - res.m[0].v[0] = m[0].v[0]; - res.m[0].v[1] = m[1].v[0]; - res.m[1].v[0] = m[0].v[1]; - res.m[1].v[1] = m[1].v[1]; - - return res; - } - - self_type adjunct() const { - self_type res; - - res.m[0].set(m[1].v[1], -m[0].v[1]); - res.m[1].set(-m[1].v[0], -m[0].v[0]); - - return res; - } - - value_type det() const { - return m[0].v[0]*m[1].v[1] - m[1].v[0]*m[0].v[1]; - } - - self_type operator~() const { - return adjunct() / det(); - } - - self_type& operator*=(const value_type factor) { - m[0] *= factor; - m[1] *= factor; - - return *this; - } - - self_type& operator/=(const value_type factor) { - return operator*=(value_type(1)/factor); - } - - self_type operator*(const value_type factor) const { - return self_type(*this) *= factor; - } - - self_type operator/(const value_type factor) const { - return self_type(*this) /= factor; - } - - vector_type m[2]; -}; - -class vdfloat3x3 { -public: - enum zero_type { zero }; - enum identity_type { identity }; - enum rotation_x_type { rotation_x }; - enum rotation_y_type { rotation_y }; - enum rotation_z_type { rotation_z }; - - typedef float value_type; - typedef vdfloat3 vector_type; - typedef vdfloat3c vector_ctor_type; - typedef vdfloat3x3 self_type; - - vdfloat3x3() {} - vdfloat3x3(zero_type) { m[0] = m[1] = m[2] = vector_ctor_type(0, 0, 0); } - vdfloat3x3(identity_type) { - m[0].set(1, 0, 0); - m[1].set(0, 1, 0); - m[2].set(0, 0, 1); - } - vdfloat3x3(rotation_x_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( 1, 0, 0); - m[1].set( 0, c,-s); - m[2].set( 0, s, c); - } - - vdfloat3x3(rotation_y_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( c, 0, s); - m[1].set( 0, 1, 0); - m[2].set(-s, 0, c); - } - vdfloat3x3(rotation_z_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( c,-s, 0); - m[1].set( s, c, 0); - m[2].set( 0, 0, 1); - } - - vector_type& operator[](int k) { return m[k]; } - const vector_type& operator[](int k) const { return m[k]; } - - self_type operator*(const self_type& v) const { - self_type result; - -#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + m[i].v[2]*v.m[2].v[j] - DO(0,0); - DO(0,1); - DO(0,2); - DO(1,0); - DO(1,1); - DO(1,2); - DO(2,0); - DO(2,1); - DO(2,2); -#undef DO - - return result; - } - - vector_type operator*(const vector_type& r) const { - return vector_ctor_type( - m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2], - m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2], - m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2]); - } - - self_type transpose() const { - self_type res; - - res.m[0].v[0] = m[0].v[0]; - res.m[0].v[1] = m[1].v[0]; - res.m[0].v[2] = m[2].v[0]; - res.m[1].v[0] = m[0].v[1]; - res.m[1].v[1] = m[1].v[1]; - res.m[1].v[2] = m[2].v[1]; - res.m[2].v[0] = m[0].v[2]; - res.m[2].v[1] = m[1].v[2]; - res.m[2].v[2] = m[2].v[2]; - - return res; - } - - self_type adjunct() const { - using namespace nsVDMath; - - self_type res; - - res.m[0] = cross(m[1], m[2]); - res.m[1] = cross(m[2], m[0]); - res.m[2] = cross(m[0], m[1]); - - return res.transpose(); - } - - value_type det() const { - return + m[0].v[0] * m[1].v[1] * m[2].v[2] - + m[1].v[0] * m[2].v[1] * m[0].v[2] - + m[2].v[0] * m[0].v[1] * m[1].v[2] - - m[0].v[0] * m[2].v[1] * m[1].v[2] - - m[1].v[0] * m[0].v[1] * m[2].v[2] - - m[2].v[0] * m[1].v[1] * m[0].v[2]; - } - - self_type operator~() const { - return adjunct() / det(); - } - - self_type& operator*=(const value_type factor) { - m[0] *= factor; - m[1] *= factor; - m[2] *= factor; - - return *this; - } - - self_type& operator/=(const value_type factor) { - return operator*=(value_type(1)/factor); - } - - self_type operator*(const value_type factor) const { - return self_type(*this) *= factor; - } - - self_type operator/(const value_type factor) const { - return self_type(*this) /= factor; - } - - vector_type m[3]; -}; - -inline vdfloat3 operator*(const vdfloat3& v, const vdfloat3x3& m) { - return v.x * m.m[0] + v.y * m.m[1] + v.z * m.m[2]; -} - -class vdfloat4x4 { -public: - enum zero_type { zero }; - enum identity_type { identity }; - enum rotation_x_type { rotation_x }; - enum rotation_y_type { rotation_y }; - enum rotation_z_type { rotation_z }; - - typedef float value_type; - typedef vdfloat4 vector_type; - typedef vdfloat4c vector_ctor_type; - - vdfloat4x4() {} - vdfloat4x4(const vdfloat3x3& v) { - m[0].set(v.m[0].x, v.m[0].y, v.m[0].z, 0.0f); - m[1].set(v.m[1].x, v.m[1].y, v.m[1].z, 0.0f); - m[2].set(v.m[2].x, v.m[2].y, v.m[2].z, 0.0f); - m[3].set(0, 0, 0, 1); - } - - vdfloat4x4(zero_type) { - m[0].setzero(); - m[1].setzero(); - m[2].setzero(); - m[3].setzero(); - } - - vdfloat4x4(identity_type) { - m[0].set(1, 0, 0, 0); - m[1].set(0, 1, 0, 0); - m[2].set(0, 0, 1, 0); - m[3].set(0, 0, 0, 1); - } - vdfloat4x4(rotation_x_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( 1, 0, 0, 0); - m[1].set( 0, c,-s, 0); - m[2].set( 0, s, c, 0); - m[3].set( 0, 0, 0, 1); - } - vdfloat4x4(rotation_y_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( c, 0, s, 0); - m[1].set( 0, 1, 0, 0); - m[2].set(-s, 0, c, 0); - m[3].set( 0, 0, 0, 1); - } - vdfloat4x4(rotation_z_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( c,-s, 0, 0); - m[1].set( s, c, 0, 0); - m[2].set( 0, 0, 1, 0); - m[3].set( 0, 0, 0, 1); - } - - const value_type *data() const { return &m[0][0]; } - - vector_type& operator[](int n) { return m[n]; } - const vector_type& operator[](int n) const { return m[n]; } - - vdfloat4x4 operator*(const vdfloat4x4& v) const { - vdfloat4x4 result; - -#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + m[i].v[2]*v.m[2].v[j] + m[i].v[3]*v.m[3].v[j] - DO(0,0); - DO(0,1); - DO(0,2); - DO(0,3); - DO(1,0); - DO(1,1); - DO(1,2); - DO(1,3); - DO(2,0); - DO(2,1); - DO(2,2); - DO(2,3); - DO(3,0); - DO(3,1); - DO(3,2); - DO(3,3); -#undef DO - - return result; - } - - vdfloat4x4& operator*=(const vdfloat4x4& v) { - return operator=(operator*(v)); - } - - vector_type operator*(const vdfloat3& r) const { - return vector_ctor_type( - m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2] + m[0].v[3], - m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2] + m[1].v[3], - m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2] + m[2].v[3], - m[3].v[0]*r.v[0] + m[3].v[1]*r.v[1] + m[3].v[2]*r.v[2] + m[3].v[3]); - } - - vector_type operator*(const vector_type& r) const { - return vector_ctor_type( - m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2] + m[0].v[3]*r.v[3], - m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2] + m[1].v[3]*r.v[3], - m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2] + m[2].v[3]*r.v[3], - m[3].v[0]*r.v[0] + m[3].v[1]*r.v[1] + m[3].v[2]*r.v[2] + m[3].v[3]*r.v[3]); - } - - vector_type m[4]; -}; - -template -struct VDSize { - typedef T value_type; - - int w, h; - - VDSize() {} - VDSize(int _w, int _h) : w(_w), h(_h) {} - - bool operator==(const VDSize& s) const { return w==s.w && h==s.h; } - bool operator!=(const VDSize& s) const { return w!=s.w || h!=s.h; } - - VDSize& operator+=(const VDSize& s) { - w += s.w; - h += s.h; - return *this; - } - - T area() const { return w*h; } - - void include(const VDSize& s) { - if (w < s.w) - w = s.w; - if (h < s.h) - h = s.h; - } -}; - -template -class VDPoint { -public: - VDPoint(); - VDPoint(T x_, T y_); - - T x; - T y; -}; - -template -VDPoint::VDPoint() { -} - -template -VDPoint::VDPoint(T x_, T y_) - : x(x_), y(y_) -{ -} - -template -class VDRect { -public: - typedef T value_type; - - VDRect(); - VDRect(T left_, T top_, T right_, T bottom_); - - bool empty() const; - bool valid() const; - - void clear(); - void invalidate(); - void set(T l, T t, T r, T b); - - void add(T x, T y); - void add(const VDRect& r); - void translate(T x, T y); - void scale(T x, T y); - void transform(T scaleX, T scaleY, T offsetX, T offsety); - void resize(T w, T h); - - bool operator==(const VDRect& r) const; - bool operator!=(const VDRect& r) const; - - T width() const; - T height() const; - T area() const; - VDSize size() const; - VDPoint top_left() const; - VDPoint bottom_right() const; - - bool contains(const VDPoint& pt) const; - -public: - T left, top, right, bottom; -}; - -template -VDRect::VDRect() { -} - -template -VDRect::VDRect(T left_, T top_, T right_, T bottom_) - : left(left_) - , top(top_) - , right(right_) - , bottom(bottom_) -{ -} - -template -bool VDRect::empty() const { - return left >= right || top >= bottom; -} - -template -bool VDRect::valid() const { - return left <= right; -} - -template -void VDRect::clear() { - left = top = right = bottom = 0; -} - -template -void VDRect::invalidate() { - left = top = (std::numeric_limits::max)(); - right = bottom = std::numeric_limits::is_signed ? -(std::numeric_limits::max)() : T(0); -} - -template -void VDRect::set(T l, T t, T r, T b) { - left = l; - top = t; - right = r; - bottom = b; -} - -template -void VDRect::add(T x, T y) { - if (left > x) - left = x; - if (top > y) - top = y; - if (right < x) - right = x; - if (bottom < y) - bottom = y; -} - -template -void VDRect::add(const VDRect& src) { - if (left > src.left) - left = src.left; - if (top > src.top) - top = src.top; - if (right < src.right) - right = src.right; - if (bottom < src.bottom) - bottom = src.bottom; -} - -template -void VDRect::translate(T x, T y) { - left += x; - top += y; - right += x; - bottom += y; -} - -template -void VDRect::scale(T x, T y) { - left *= x; - top *= y; - right *= x; - bottom *= y; -} - -template -void VDRect::transform(T scaleX, T scaleY, T offsetX, T offsetY) { - left = left * scaleX + offsetX; - top = top * scaleY + offsetY; - right = right * scaleX + offsetX; - bottom = bottom * scaleY + offsetY; -} - -template -void VDRect::resize(T w, T h) { - right = left + w; - bottom = top + h; -} - -template -bool VDRect::operator==(const VDRect& r) const { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } - -template -bool VDRect::operator!=(const VDRect& r) const { return left!=r.left || top!=r.top || right!=r.right || bottom!=r.bottom; } - -template -T VDRect::width() const { return right-left; } - -template -T VDRect::height() const { return bottom-top; } - -template -T VDRect::area() const { return (right-left)*(bottom-top); } - -template -VDPoint VDRect::top_left() const { return VDPoint(left, top); } - -template -VDPoint VDRect::bottom_right() const { return VDPoint(right, bottom); } - -template -VDSize VDRect::size() const { return VDSize(right-left, bottom-top); } - -template -bool VDRect::contains(const VDPoint& pt) const { - return pt.x >= left - && pt.x < right - && pt.y >= top - && pt.y < bottom; -} - -/////////////////////////////////////////////////////////////////////////////// -typedef VDPoint vdpoint32; -typedef VDSize vdsize32; -typedef VDSize vdsize32f; -typedef VDRect vdrect32; -typedef VDRect vdrect32f; - -template<> bool vdrect32::contains(const vdpoint32& pt) const; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VECTORS_H +#define f_VD2_SYSTEM_VECTORS_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +bool VDSolveLinearEquation(double *src, int n, ptrdiff_t stride_elements, double *b, double tolerance = 1e-5); + +/////////////////////////////////////////////////////////////////////////// + +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +class vdfloat2x2 { +public: + enum zero_type { zero }; + enum identity_type { identity }; + + typedef float value_type; + typedef vdfloat2 vector_type; + typedef vdfloat2c vector_ctor_type; + typedef vdfloat2x2 self_type; + + vdfloat2x2() {} + vdfloat2x2(zero_type) { m[0] = m[1] = vector_ctor_type(0, 0); } + vdfloat2x2(identity_type) { + m[0] = vector_ctor_type(1, 0); + m[1] = vector_ctor_type(0, 1); + } + + vector_type& operator[](int k) { return m[k]; } + const vector_type& operator[](int k) const { return m[k]; } + + self_type operator*(const self_type& v) const { + self_type result; + +#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + DO(0,0); + DO(0,1); + DO(1,0); + DO(1,1); +#undef DO + + return result; + } + + vector_type operator*(const vector_type& r) const { + return vector_ctor_type( + m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1], + m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1]); + } + + self_type transpose() const { + self_type res; + + res.m[0].v[0] = m[0].v[0]; + res.m[0].v[1] = m[1].v[0]; + res.m[1].v[0] = m[0].v[1]; + res.m[1].v[1] = m[1].v[1]; + + return res; + } + + self_type adjunct() const { + self_type res; + + res.m[0].set(m[1].v[1], -m[0].v[1]); + res.m[1].set(-m[1].v[0], -m[0].v[0]); + + return res; + } + + value_type det() const { + return m[0].v[0]*m[1].v[1] - m[1].v[0]*m[0].v[1]; + } + + self_type operator~() const { + return adjunct() / det(); + } + + self_type& operator*=(const value_type factor) { + m[0] *= factor; + m[1] *= factor; + + return *this; + } + + self_type& operator/=(const value_type factor) { + return operator*=(value_type(1)/factor); + } + + self_type operator*(const value_type factor) const { + return self_type(*this) *= factor; + } + + self_type operator/(const value_type factor) const { + return self_type(*this) /= factor; + } + + vector_type m[2]; +}; + +class vdfloat3x3 { +public: + enum zero_type { zero }; + enum identity_type { identity }; + enum rotation_x_type { rotation_x }; + enum rotation_y_type { rotation_y }; + enum rotation_z_type { rotation_z }; + + typedef float value_type; + typedef vdfloat3 vector_type; + typedef vdfloat3c vector_ctor_type; + typedef vdfloat3x3 self_type; + + vdfloat3x3() {} + vdfloat3x3(zero_type) { m[0] = m[1] = m[2] = vector_ctor_type(0, 0, 0); } + vdfloat3x3(identity_type) { + m[0].set(1, 0, 0); + m[1].set(0, 1, 0); + m[2].set(0, 0, 1); + } + vdfloat3x3(rotation_x_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( 1, 0, 0); + m[1].set( 0, c,-s); + m[2].set( 0, s, c); + } + + vdfloat3x3(rotation_y_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( c, 0, s); + m[1].set( 0, 1, 0); + m[2].set(-s, 0, c); + } + vdfloat3x3(rotation_z_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( c,-s, 0); + m[1].set( s, c, 0); + m[2].set( 0, 0, 1); + } + + vector_type& operator[](int k) { return m[k]; } + const vector_type& operator[](int k) const { return m[k]; } + + self_type operator*(const self_type& v) const { + self_type result; + +#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + m[i].v[2]*v.m[2].v[j] + DO(0,0); + DO(0,1); + DO(0,2); + DO(1,0); + DO(1,1); + DO(1,2); + DO(2,0); + DO(2,1); + DO(2,2); +#undef DO + + return result; + } + + vector_type operator*(const vector_type& r) const { + return vector_ctor_type( + m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2], + m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2], + m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2]); + } + + self_type transpose() const { + self_type res; + + res.m[0].v[0] = m[0].v[0]; + res.m[0].v[1] = m[1].v[0]; + res.m[0].v[2] = m[2].v[0]; + res.m[1].v[0] = m[0].v[1]; + res.m[1].v[1] = m[1].v[1]; + res.m[1].v[2] = m[2].v[1]; + res.m[2].v[0] = m[0].v[2]; + res.m[2].v[1] = m[1].v[2]; + res.m[2].v[2] = m[2].v[2]; + + return res; + } + + self_type adjunct() const { + using namespace nsVDMath; + + self_type res; + + res.m[0] = cross(m[1], m[2]); + res.m[1] = cross(m[2], m[0]); + res.m[2] = cross(m[0], m[1]); + + return res.transpose(); + } + + value_type det() const { + return + m[0].v[0] * m[1].v[1] * m[2].v[2] + + m[1].v[0] * m[2].v[1] * m[0].v[2] + + m[2].v[0] * m[0].v[1] * m[1].v[2] + - m[0].v[0] * m[2].v[1] * m[1].v[2] + - m[1].v[0] * m[0].v[1] * m[2].v[2] + - m[2].v[0] * m[1].v[1] * m[0].v[2]; + } + + self_type operator~() const { + return adjunct() / det(); + } + + self_type& operator*=(const value_type factor) { + m[0] *= factor; + m[1] *= factor; + m[2] *= factor; + + return *this; + } + + self_type& operator/=(const value_type factor) { + return operator*=(value_type(1)/factor); + } + + self_type operator*(const value_type factor) const { + return self_type(*this) *= factor; + } + + self_type operator/(const value_type factor) const { + return self_type(*this) /= factor; + } + + vector_type m[3]; +}; + +inline vdfloat3 operator*(const vdfloat3& v, const vdfloat3x3& m) { + return v.x * m.m[0] + v.y * m.m[1] + v.z * m.m[2]; +} + +class vdfloat4x4 { +public: + enum zero_type { zero }; + enum identity_type { identity }; + enum rotation_x_type { rotation_x }; + enum rotation_y_type { rotation_y }; + enum rotation_z_type { rotation_z }; + + typedef float value_type; + typedef vdfloat4 vector_type; + typedef vdfloat4c vector_ctor_type; + + vdfloat4x4() {} + vdfloat4x4(const vdfloat3x3& v) { + m[0].set(v.m[0].x, v.m[0].y, v.m[0].z, 0.0f); + m[1].set(v.m[1].x, v.m[1].y, v.m[1].z, 0.0f); + m[2].set(v.m[2].x, v.m[2].y, v.m[2].z, 0.0f); + m[3].set(0, 0, 0, 1); + } + + vdfloat4x4(zero_type) { + m[0].setzero(); + m[1].setzero(); + m[2].setzero(); + m[3].setzero(); + } + + vdfloat4x4(identity_type) { + m[0].set(1, 0, 0, 0); + m[1].set(0, 1, 0, 0); + m[2].set(0, 0, 1, 0); + m[3].set(0, 0, 0, 1); + } + vdfloat4x4(rotation_x_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( 1, 0, 0, 0); + m[1].set( 0, c,-s, 0); + m[2].set( 0, s, c, 0); + m[3].set( 0, 0, 0, 1); + } + vdfloat4x4(rotation_y_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( c, 0, s, 0); + m[1].set( 0, 1, 0, 0); + m[2].set(-s, 0, c, 0); + m[3].set( 0, 0, 0, 1); + } + vdfloat4x4(rotation_z_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( c,-s, 0, 0); + m[1].set( s, c, 0, 0); + m[2].set( 0, 0, 1, 0); + m[3].set( 0, 0, 0, 1); + } + + const value_type *data() const { return &m[0][0]; } + + vector_type& operator[](int n) { return m[n]; } + const vector_type& operator[](int n) const { return m[n]; } + + vdfloat4x4 operator*(const vdfloat4x4& v) const { + vdfloat4x4 result; + +#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + m[i].v[2]*v.m[2].v[j] + m[i].v[3]*v.m[3].v[j] + DO(0,0); + DO(0,1); + DO(0,2); + DO(0,3); + DO(1,0); + DO(1,1); + DO(1,2); + DO(1,3); + DO(2,0); + DO(2,1); + DO(2,2); + DO(2,3); + DO(3,0); + DO(3,1); + DO(3,2); + DO(3,3); +#undef DO + + return result; + } + + vdfloat4x4& operator*=(const vdfloat4x4& v) { + return operator=(operator*(v)); + } + + vector_type operator*(const vdfloat3& r) const { + return vector_ctor_type( + m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2] + m[0].v[3], + m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2] + m[1].v[3], + m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2] + m[2].v[3], + m[3].v[0]*r.v[0] + m[3].v[1]*r.v[1] + m[3].v[2]*r.v[2] + m[3].v[3]); + } + + vector_type operator*(const vector_type& r) const { + return vector_ctor_type( + m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2] + m[0].v[3]*r.v[3], + m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2] + m[1].v[3]*r.v[3], + m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2] + m[2].v[3]*r.v[3], + m[3].v[0]*r.v[0] + m[3].v[1]*r.v[1] + m[3].v[2]*r.v[2] + m[3].v[3]*r.v[3]); + } + + vector_type m[4]; +}; + +template +struct VDSize { + typedef T value_type; + + int w, h; + + VDSize() {} + VDSize(int _w, int _h) : w(_w), h(_h) {} + + bool operator==(const VDSize& s) const { return w==s.w && h==s.h; } + bool operator!=(const VDSize& s) const { return w!=s.w || h!=s.h; } + + VDSize& operator+=(const VDSize& s) { + w += s.w; + h += s.h; + return *this; + } + + T area() const { return w*h; } + + void include(const VDSize& s) { + if (w < s.w) + w = s.w; + if (h < s.h) + h = s.h; + } +}; + +template +class VDPoint { +public: + VDPoint(); + VDPoint(T x_, T y_); + + T x; + T y; +}; + +template +VDPoint::VDPoint() { +} + +template +VDPoint::VDPoint(T x_, T y_) + : x(x_), y(y_) +{ +} + +template +class VDRect { +public: + typedef T value_type; + + VDRect(); + VDRect(T left_, T top_, T right_, T bottom_); + + bool empty() const; + bool valid() const; + + void clear(); + void invalidate(); + void set(T l, T t, T r, T b); + + void add(T x, T y); + void add(const VDRect& r); + void translate(T x, T y); + void scale(T x, T y); + void transform(T scaleX, T scaleY, T offsetX, T offsety); + void resize(T w, T h); + + bool operator==(const VDRect& r) const; + bool operator!=(const VDRect& r) const; + + T width() const; + T height() const; + T area() const; + VDSize size() const; + VDPoint top_left() const; + VDPoint bottom_right() const; + + bool contains(const VDPoint& pt) const; + +public: + T left, top, right, bottom; +}; + +template +VDRect::VDRect() { +} + +template +VDRect::VDRect(T left_, T top_, T right_, T bottom_) + : left(left_) + , top(top_) + , right(right_) + , bottom(bottom_) +{ +} + +template +bool VDRect::empty() const { + return left >= right || top >= bottom; +} + +template +bool VDRect::valid() const { + return left <= right; +} + +template +void VDRect::clear() { + left = top = right = bottom = 0; +} + +template +void VDRect::invalidate() { + left = top = (std::numeric_limits::max)(); + right = bottom = std::numeric_limits::is_signed ? -(std::numeric_limits::max)() : T(0); +} + +template +void VDRect::set(T l, T t, T r, T b) { + left = l; + top = t; + right = r; + bottom = b; +} + +template +void VDRect::add(T x, T y) { + if (left > x) + left = x; + if (top > y) + top = y; + if (right < x) + right = x; + if (bottom < y) + bottom = y; +} + +template +void VDRect::add(const VDRect& src) { + if (left > src.left) + left = src.left; + if (top > src.top) + top = src.top; + if (right < src.right) + right = src.right; + if (bottom < src.bottom) + bottom = src.bottom; +} + +template +void VDRect::translate(T x, T y) { + left += x; + top += y; + right += x; + bottom += y; +} + +template +void VDRect::scale(T x, T y) { + left *= x; + top *= y; + right *= x; + bottom *= y; +} + +template +void VDRect::transform(T scaleX, T scaleY, T offsetX, T offsetY) { + left = left * scaleX + offsetX; + top = top * scaleY + offsetY; + right = right * scaleX + offsetX; + bottom = bottom * scaleY + offsetY; +} + +template +void VDRect::resize(T w, T h) { + right = left + w; + bottom = top + h; +} + +template +bool VDRect::operator==(const VDRect& r) const { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } + +template +bool VDRect::operator!=(const VDRect& r) const { return left!=r.left || top!=r.top || right!=r.right || bottom!=r.bottom; } + +template +T VDRect::width() const { return right-left; } + +template +T VDRect::height() const { return bottom-top; } + +template +T VDRect::area() const { return (right-left)*(bottom-top); } + +template +VDPoint VDRect::top_left() const { return VDPoint(left, top); } + +template +VDPoint VDRect::bottom_right() const { return VDPoint(right, bottom); } + +template +VDSize VDRect::size() const { return VDSize(right-left, bottom-top); } + +template +bool VDRect::contains(const VDPoint& pt) const { + return pt.x >= left + && pt.x < right + && pt.y >= top + && pt.y < bottom; +} + +/////////////////////////////////////////////////////////////////////////////// +typedef VDPoint vdpoint32; +typedef VDSize vdsize32; +typedef VDSize vdsize32f; +typedef VDRect vdrect32; +typedef VDRect vdrect32f; + +template<> bool vdrect32::contains(const vdpoint32& pt) const; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vectors_float.h b/src/thirdparty/VirtualDub/h/vd2/system/vectors_float.h index 3be7fb4ac97..5af26dbc199 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vectors_float.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vectors_float.h @@ -1,207 +1,207 @@ -class vdfloat2 { -public: - typedef vdfloat2 self_type; - typedef float value_type; - - void set(float x2, float y2) { x=x2; y=y2; } - - float& operator[](int k) { return v[k]; } - const float& operator[](int k) const { return v[k]; } - - float lensq() const { return x*x + y*y; } - - self_type operator-() const { self_type a = {-x, -y}; return a; } - - self_type operator+(const self_type& r) const { self_type a = {x+r.x, y+r.y}; return a; } - self_type operator-(const self_type& r) const { self_type a = {x-r.x, y-r.y}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; return *this; } - - self_type operator*(const float s) const { self_type a = {x*s, x*s}; return a; } - self_type& operator*=(const float s) { x*=s; y*=s; return *this; } - - self_type operator/(const float s) const { const float inv(float(1)/s); self_type a = {x*inv, y*inv}; return a; } - self_type& operator/=(const float s) { const float inv(float(1)/s); x*=inv; y*=inv; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; return *this; } - - union { - struct { - float x; - float y; - }; - float v[2]; - }; -}; - -VDFORCEINLINE vdfloat2 operator*(const float s, const vdfloat2& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdfloat3 { -public: - typedef vdfloat3 self_type; - typedef float value_type; - - void set(float x2, float y2, float z2) { x=x2; y=y2; z=z2; } - - float& operator[](int k) { return v[k]; } - const float& operator[](int k) const { return v[k]; } - - float lensq() const { return x*x + y*y + z*z; } - - vdfloat2 project() const { const float inv(float(1)/z); const vdfloat2 a = {x*inv, y*inv}; return a; } - vdfloat2 as2d() const { const vdfloat2 a = {x, y}; return a; } - - self_type operator-() const { const self_type a = {-x, -y, -z}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; return *this; } - - self_type operator*(const float s) const { const self_type a = {x*s, y*s, z*s}; return a; } - self_type& operator*=(const float s) { x*=s; y*=s; z*=s; return *this; } - - self_type operator/(const float s) const { const float inv(float(1)/s); const self_type a = {x*inv, y*inv, z*inv}; return a; } - self_type& operator/=(const float s) { const float inv(float(1)/s); x*=inv; y*=inv; z*=inv; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; return *this; } - - union { - struct { - float x; - float y; - float z; - }; - float v[3]; - }; -}; - -VDFORCEINLINE vdfloat3 operator*(const float s, const vdfloat3& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdfloat4 { -public: - typedef vdfloat4 self_type; - typedef float value_type; - - void setzero() { x=y=z=w = 0; } - void set(float x2, float y2, float z2, float w2) { x=x2; y=y2; z=z2; w=w2; } - - float& operator[](int i) { return v[i]; } - const float& operator[](int i) const { return v[i]; } - - float lensq() const { return x*x + y*y + z*z + w*w; } - - vdfloat3 project() const { const float inv(float(1)/w); const vdfloat3 a = {x*inv, y*inv, z*inv}; return a; } - - self_type operator-() const { const self_type a = {-x, -y, -z, -w}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z, w+r.w}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z, w-r.w}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; w+=r.w; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; w-=r.w; return *this; } - - self_type operator*(const float factor) const { const self_type a = {x*factor, y*factor, z*factor, w*factor}; return a; } - self_type operator/(const float factor) const { const float inv(float(1) / factor); const self_type a = {x*inv, y*inv, z*inv, w*inv}; return a; } - - self_type& operator*=(const float factor) { x *= factor; y *= factor; z *= factor; w *= factor; return *this; } - self_type& operator/=(const float factor) { const float inv(float(1) / factor); x *= inv; y *= inv; z *= inv; w *= inv; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z, w*r.w}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; w*=r.w; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z, w*r.w}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; w/=r.w; return *this; } - - union { - struct { - float x; - float y; - float z; - float w; - }; - float v[4]; - }; -}; - -VDFORCEINLINE vdfloat4 operator*(const float s, const vdfloat4& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdfloat2c : public vdfloat2 { -public: - VDFORCEINLINE vdfloat2c(float x2, float y2) {x=x2; y=y2;} - VDFORCEINLINE vdfloat2c(const float src[2]) {x=src[0]; y=src[1];} -}; - -class vdfloat3c : public vdfloat3 { -public: - VDFORCEINLINE vdfloat3c(float x2, float y2, float z2) { x=x2; y=y2; z=z2; } - VDFORCEINLINE vdfloat3c(const float src[3]) { x=src[0]; y=src[1]; z=src[2]; } -}; - -class vdfloat4c : public vdfloat4 { -public: - VDFORCEINLINE vdfloat4c(float x2, float y2, float z2, float w2) { x=x2; y=y2; z=z2; w=w2; } - VDFORCEINLINE vdfloat4c(const float src[4]) { x=src[0]; y=src[1]; z=src[2]; w=src[3]; } -}; - - -/////////////////////////////////////////////////////////////////////////// - -namespace nsVDMath { - VDFORCEINLINE float length(const vdfloat2& a) { - return sqrtf(a.x*a.x + a.y*a.y); - } - - VDFORCEINLINE float length(const vdfloat3& a) { - return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z); - } - - VDFORCEINLINE float length(const vdfloat4& a) { - return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w); - } - - VDFORCEINLINE vdfloat2 normalize(const vdfloat2& a) { - return a / length(a); - } - - VDFORCEINLINE vdfloat3 normalize(const vdfloat3& a) { - return a / length(a); - } - - VDFORCEINLINE vdfloat4 normalize(const vdfloat4& a) { - return a / length(a); - } - - VDFORCEINLINE float dot(const vdfloat2& a, const vdfloat2& b) { - return a.x*b.x + a.y*b.y; - } - - VDFORCEINLINE float dot(const vdfloat3& a, const vdfloat3& b) { - return a.x*b.x + a.y*b.y + a.z*b.z; - } - - VDFORCEINLINE float dot(const vdfloat4& a, const vdfloat4& b) { - return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; - } - - VDFORCEINLINE vdfloat3 cross(const vdfloat3& a, const vdfloat3& b) { - const vdfloat3 r = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; - return r; - } -}; +class vdfloat2 { +public: + typedef vdfloat2 self_type; + typedef float value_type; + + void set(float x2, float y2) { x=x2; y=y2; } + + float& operator[](int k) { return v[k]; } + const float& operator[](int k) const { return v[k]; } + + float lensq() const { return x*x + y*y; } + + self_type operator-() const { self_type a = {-x, -y}; return a; } + + self_type operator+(const self_type& r) const { self_type a = {x+r.x, y+r.y}; return a; } + self_type operator-(const self_type& r) const { self_type a = {x-r.x, y-r.y}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; return *this; } + + self_type operator*(const float s) const { self_type a = {x*s, x*s}; return a; } + self_type& operator*=(const float s) { x*=s; y*=s; return *this; } + + self_type operator/(const float s) const { const float inv(float(1)/s); self_type a = {x*inv, y*inv}; return a; } + self_type& operator/=(const float s) { const float inv(float(1)/s); x*=inv; y*=inv; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; return *this; } + + union { + struct { + float x; + float y; + }; + float v[2]; + }; +}; + +VDFORCEINLINE vdfloat2 operator*(const float s, const vdfloat2& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdfloat3 { +public: + typedef vdfloat3 self_type; + typedef float value_type; + + void set(float x2, float y2, float z2) { x=x2; y=y2; z=z2; } + + float& operator[](int k) { return v[k]; } + const float& operator[](int k) const { return v[k]; } + + float lensq() const { return x*x + y*y + z*z; } + + vdfloat2 project() const { const float inv(float(1)/z); const vdfloat2 a = {x*inv, y*inv}; return a; } + vdfloat2 as2d() const { const vdfloat2 a = {x, y}; return a; } + + self_type operator-() const { const self_type a = {-x, -y, -z}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; return *this; } + + self_type operator*(const float s) const { const self_type a = {x*s, y*s, z*s}; return a; } + self_type& operator*=(const float s) { x*=s; y*=s; z*=s; return *this; } + + self_type operator/(const float s) const { const float inv(float(1)/s); const self_type a = {x*inv, y*inv, z*inv}; return a; } + self_type& operator/=(const float s) { const float inv(float(1)/s); x*=inv; y*=inv; z*=inv; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; return *this; } + + union { + struct { + float x; + float y; + float z; + }; + float v[3]; + }; +}; + +VDFORCEINLINE vdfloat3 operator*(const float s, const vdfloat3& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdfloat4 { +public: + typedef vdfloat4 self_type; + typedef float value_type; + + void setzero() { x=y=z=w = 0; } + void set(float x2, float y2, float z2, float w2) { x=x2; y=y2; z=z2; w=w2; } + + float& operator[](int i) { return v[i]; } + const float& operator[](int i) const { return v[i]; } + + float lensq() const { return x*x + y*y + z*z + w*w; } + + vdfloat3 project() const { const float inv(float(1)/w); const vdfloat3 a = {x*inv, y*inv, z*inv}; return a; } + + self_type operator-() const { const self_type a = {-x, -y, -z, -w}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z, w+r.w}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z, w-r.w}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; w+=r.w; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; w-=r.w; return *this; } + + self_type operator*(const float factor) const { const self_type a = {x*factor, y*factor, z*factor, w*factor}; return a; } + self_type operator/(const float factor) const { const float inv(float(1) / factor); const self_type a = {x*inv, y*inv, z*inv, w*inv}; return a; } + + self_type& operator*=(const float factor) { x *= factor; y *= factor; z *= factor; w *= factor; return *this; } + self_type& operator/=(const float factor) { const float inv(float(1) / factor); x *= inv; y *= inv; z *= inv; w *= inv; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z, w*r.w}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; w*=r.w; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z, w*r.w}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; w/=r.w; return *this; } + + union { + struct { + float x; + float y; + float z; + float w; + }; + float v[4]; + }; +}; + +VDFORCEINLINE vdfloat4 operator*(const float s, const vdfloat4& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdfloat2c : public vdfloat2 { +public: + VDFORCEINLINE vdfloat2c(float x2, float y2) {x=x2; y=y2;} + VDFORCEINLINE vdfloat2c(const float src[2]) {x=src[0]; y=src[1];} +}; + +class vdfloat3c : public vdfloat3 { +public: + VDFORCEINLINE vdfloat3c(float x2, float y2, float z2) { x=x2; y=y2; z=z2; } + VDFORCEINLINE vdfloat3c(const float src[3]) { x=src[0]; y=src[1]; z=src[2]; } +}; + +class vdfloat4c : public vdfloat4 { +public: + VDFORCEINLINE vdfloat4c(float x2, float y2, float z2, float w2) { x=x2; y=y2; z=z2; w=w2; } + VDFORCEINLINE vdfloat4c(const float src[4]) { x=src[0]; y=src[1]; z=src[2]; w=src[3]; } +}; + + +/////////////////////////////////////////////////////////////////////////// + +namespace nsVDMath { + VDFORCEINLINE float length(const vdfloat2& a) { + return sqrtf(a.x*a.x + a.y*a.y); + } + + VDFORCEINLINE float length(const vdfloat3& a) { + return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z); + } + + VDFORCEINLINE float length(const vdfloat4& a) { + return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w); + } + + VDFORCEINLINE vdfloat2 normalize(const vdfloat2& a) { + return a / length(a); + } + + VDFORCEINLINE vdfloat3 normalize(const vdfloat3& a) { + return a / length(a); + } + + VDFORCEINLINE vdfloat4 normalize(const vdfloat4& a) { + return a / length(a); + } + + VDFORCEINLINE float dot(const vdfloat2& a, const vdfloat2& b) { + return a.x*b.x + a.y*b.y; + } + + VDFORCEINLINE float dot(const vdfloat3& a, const vdfloat3& b) { + return a.x*b.x + a.y*b.y + a.z*b.z; + } + + VDFORCEINLINE float dot(const vdfloat4& a, const vdfloat4& b) { + return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; + } + + VDFORCEINLINE vdfloat3 cross(const vdfloat3& a, const vdfloat3& b) { + const vdfloat3 r = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; + return r; + } +}; diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vectors_int.h b/src/thirdparty/VirtualDub/h/vd2/system/vectors_int.h index 78c79676171..72a3478c644 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vectors_int.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vectors_int.h @@ -1,183 +1,183 @@ -class vdint2 { -public: - typedef vdint2 self_type; - typedef int value_type; - - void set(int x2, int y2) { x=x2; y=y2; } - - int& operator[](int k) { return v[k]; } - const int& operator[](int k) const { return v[k]; } - - int lensq() const { return x*x + y*y; } - int len() const { return (int)sqrtf((float)(x*x + y*y)); } - self_type normalized() const { return *this / len(); } - - self_type operator-() const { const self_type a = {-x, -y}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; return *this; } - - self_type operator*(const int s) const { const self_type a = {x*s, x*s}; return a; } - self_type& operator*=(const int s) { x*=s; y*=s; return *this; } - - self_type operator/(const int s) const { const self_type a = {x/s, y/s}; return a; } - self_type& operator/=(const int s) { x/=s; y/=s; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; return *this; } - - union { - struct { - int x; - int y; - }; - int v[2]; - }; -}; - -VDFORCEINLINE vdint2 operator*(const int s, const vdint2& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdint3 { -public: - typedef vdint3 self_type; - typedef int value_type; - - int& operator[](int k) { return v[k]; } - const int& operator[](int k) const { return v[k]; } - - int lensq() const { return x*x + y*y + z*z; } - int len() const { return (int)sqrtf((float)(x*x + y*y + z*z)); } - self_type normalized() const { return *this / len(); } - - vdint2 project() const { const int inv(int(1)/z); const vdint2 a = {x*inv, y*inv}; return a; } - vdint2 as2d() const { const vdint2 a = {x, y}; return a; } - - self_type operator-() const { const self_type a = {-x, -y, -z}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; return *this; } - - self_type operator*(const int s) const { const self_type a = {x*s, y*s, z*s}; return a; } - self_type& operator*=(const int s) { x*=s; y*=s; z*=s; return *this; } - - self_type operator/(const int s) const { const self_type a = {x/s, y/s, z/s}; return a; } - self_type& operator/=(const int s) { x /= s; y /= s; z /= s; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; return *this; } - - union { - struct { - int x; - int y; - int z; - }; - int v[3]; - }; -}; - -VDFORCEINLINE vdint3 operator*(const int s, const vdint3& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdint4 { -public: - typedef vdint4 self_type; - typedef int value_type; - - int& operator[](int i) { return v[i]; } - const int& operator[](int i) const { return v[i]; } - - int lensq() const { return x*x + y*y + z*z + w*w; } - int len() const { return (int)sqrtf((float)(x*x + y*y + z*z + w*w)); } - self_type normalized() const { return *this / len(); } - - vdint3 project() const { const int inv(int(1)/w); const vdint3 a = {x*inv, y*inv, z*inv}; return a; } - - self_type operator-() const { const self_type a = {-x, -y, -z, -w}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z, w+r.w}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z, w-r.w}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; w+=r.w; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; w-=r.w; return *this; } - - self_type operator*(const int factor) const { const self_type a = {x*factor, y*factor, z*factor, w*factor}; return a; } - self_type operator/(const int factor) const { const self_type a = {x/factor, y/factor, z/factor, w/factor}; return a; } - - self_type& operator*=(const int factor) { x *= factor; y *= factor; z *= factor; w *= factor; return *this; } - self_type& operator/=(const int factor) { x /= factor; y /= factor; z /= factor; w /= factor; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z, w*r.w}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; w*=r.w; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z, w*r.w}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; w/=r.w; return *this; } - - union { - struct { - int x; - int y; - int z; - int w; - }; - int v[4]; - }; -}; - -VDFORCEINLINE vdint4 operator*(const int s, const vdint4& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdint2c : vdint2 { -public: - VDFORCEINLINE vdint2c(int x2, int y2) {x=x2; y=y2;} - VDFORCEINLINE vdint2c(const int src[2]) {x=src[0]; y=src[1];} -}; - -class vdint3c : vdint3 { -public: - VDFORCEINLINE vdint3c(int x2, int y2, int z2) { x=x2; y=y2; z=z2; } - VDFORCEINLINE vdint3c(const int src[3]) { x=src[0]; y=src[1]; z=src[2]; } -}; - -class vdint4c : vdint4 { -public: - VDFORCEINLINE vdint4c(int x2, int y2, int z2, int w2) { x=x2; y=y2; z=z2; w=w2; } - VDFORCEINLINE vdint4c(const int src[4]) { x=src[0]; y=src[1]; z=src[2]; w=src[3]; } -}; - -/////////////////////////////////////////////////////////////////////////// - -namespace nsVDMath { - VDFORCEINLINE int dot(const vdint2& a, const vdint2& b) { - return a.x*b.x + a.y*b.y; - } - - VDFORCEINLINE int dot(const vdint3& a, const vdint3& b) { - return a.x*b.x + a.y*b.y + a.z*b.z; - } - - VDFORCEINLINE int dot(const vdint4& a, const vdint4& b) { - return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; - } - - VDFORCEINLINE vdint3 cross(const vdint3& a, const vdint3& b) { - const vdint3 r = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; - return r; - } -}; +class vdint2 { +public: + typedef vdint2 self_type; + typedef int value_type; + + void set(int x2, int y2) { x=x2; y=y2; } + + int& operator[](int k) { return v[k]; } + const int& operator[](int k) const { return v[k]; } + + int lensq() const { return x*x + y*y; } + int len() const { return (int)sqrtf((float)(x*x + y*y)); } + self_type normalized() const { return *this / len(); } + + self_type operator-() const { const self_type a = {-x, -y}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; return *this; } + + self_type operator*(const int s) const { const self_type a = {x*s, x*s}; return a; } + self_type& operator*=(const int s) { x*=s; y*=s; return *this; } + + self_type operator/(const int s) const { const self_type a = {x/s, y/s}; return a; } + self_type& operator/=(const int s) { x/=s; y/=s; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; return *this; } + + union { + struct { + int x; + int y; + }; + int v[2]; + }; +}; + +VDFORCEINLINE vdint2 operator*(const int s, const vdint2& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdint3 { +public: + typedef vdint3 self_type; + typedef int value_type; + + int& operator[](int k) { return v[k]; } + const int& operator[](int k) const { return v[k]; } + + int lensq() const { return x*x + y*y + z*z; } + int len() const { return (int)sqrtf((float)(x*x + y*y + z*z)); } + self_type normalized() const { return *this / len(); } + + vdint2 project() const { const int inv(int(1)/z); const vdint2 a = {x*inv, y*inv}; return a; } + vdint2 as2d() const { const vdint2 a = {x, y}; return a; } + + self_type operator-() const { const self_type a = {-x, -y, -z}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; return *this; } + + self_type operator*(const int s) const { const self_type a = {x*s, y*s, z*s}; return a; } + self_type& operator*=(const int s) { x*=s; y*=s; z*=s; return *this; } + + self_type operator/(const int s) const { const self_type a = {x/s, y/s, z/s}; return a; } + self_type& operator/=(const int s) { x /= s; y /= s; z /= s; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; return *this; } + + union { + struct { + int x; + int y; + int z; + }; + int v[3]; + }; +}; + +VDFORCEINLINE vdint3 operator*(const int s, const vdint3& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdint4 { +public: + typedef vdint4 self_type; + typedef int value_type; + + int& operator[](int i) { return v[i]; } + const int& operator[](int i) const { return v[i]; } + + int lensq() const { return x*x + y*y + z*z + w*w; } + int len() const { return (int)sqrtf((float)(x*x + y*y + z*z + w*w)); } + self_type normalized() const { return *this / len(); } + + vdint3 project() const { const int inv(int(1)/w); const vdint3 a = {x*inv, y*inv, z*inv}; return a; } + + self_type operator-() const { const self_type a = {-x, -y, -z, -w}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z, w+r.w}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z, w-r.w}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; w+=r.w; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; w-=r.w; return *this; } + + self_type operator*(const int factor) const { const self_type a = {x*factor, y*factor, z*factor, w*factor}; return a; } + self_type operator/(const int factor) const { const self_type a = {x/factor, y/factor, z/factor, w/factor}; return a; } + + self_type& operator*=(const int factor) { x *= factor; y *= factor; z *= factor; w *= factor; return *this; } + self_type& operator/=(const int factor) { x /= factor; y /= factor; z /= factor; w /= factor; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z, w*r.w}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; w*=r.w; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z, w*r.w}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; w/=r.w; return *this; } + + union { + struct { + int x; + int y; + int z; + int w; + }; + int v[4]; + }; +}; + +VDFORCEINLINE vdint4 operator*(const int s, const vdint4& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdint2c : vdint2 { +public: + VDFORCEINLINE vdint2c(int x2, int y2) {x=x2; y=y2;} + VDFORCEINLINE vdint2c(const int src[2]) {x=src[0]; y=src[1];} +}; + +class vdint3c : vdint3 { +public: + VDFORCEINLINE vdint3c(int x2, int y2, int z2) { x=x2; y=y2; z=z2; } + VDFORCEINLINE vdint3c(const int src[3]) { x=src[0]; y=src[1]; z=src[2]; } +}; + +class vdint4c : vdint4 { +public: + VDFORCEINLINE vdint4c(int x2, int y2, int z2, int w2) { x=x2; y=y2; z=z2; w=w2; } + VDFORCEINLINE vdint4c(const int src[4]) { x=src[0]; y=src[1]; z=src[2]; w=src[3]; } +}; + +/////////////////////////////////////////////////////////////////////////// + +namespace nsVDMath { + VDFORCEINLINE int dot(const vdint2& a, const vdint2& b) { + return a.x*b.x + a.y*b.y; + } + + VDFORCEINLINE int dot(const vdint3& a, const vdint3& b) { + return a.x*b.x + a.y*b.y + a.z*b.z; + } + + VDFORCEINLINE int dot(const vdint4& a, const vdint4& b) { + return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; + } + + VDFORCEINLINE vdint3 cross(const vdint3& a, const vdint3& b) { + const vdint3 r = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; + return r; + } +}; diff --git a/src/thirdparty/VirtualDub/h/vd2/system/w32assist.h b/src/thirdparty/VirtualDub/h/vd2/system/w32assist.h index a92da8723b9..a7b1cb2a2db 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/w32assist.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/w32assist.h @@ -1,107 +1,107 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_W32ASSIST_H -#define f_VD2_SYSTEM_W32ASSIST_H - -#include - -#include - -inline bool VDIsWindowsNT() { -#ifdef _M_AMD64 - return true; -#else - static bool is_nt = !(GetVersion() & 0x80000000); - - return is_nt; -#endif -} - -inline bool VDIsAtLeastVistaW32() { - return (sint32)(::GetVersion() & 0x800000FF) >= 6; -} - -// useful constants missing from the Platform SDK - -enum { -#ifdef _M_AMD64 - MENUITEMINFO_SIZE_VERSION_400A = sizeof(MENUITEMINFOA), - MENUITEMINFO_SIZE_VERSION_400W = sizeof(MENUITEMINFOW) -#else - MENUITEMINFO_SIZE_VERSION_400A = (offsetof(MENUITEMINFOA, cch) + sizeof(UINT)), - MENUITEMINFO_SIZE_VERSION_400W = (offsetof(MENUITEMINFOW, cch) + sizeof(UINT)) -#endif -}; - -// helper functions - -bool VDIsForegroundTaskW32(); - -LPVOID VDConvertThreadToFiberW32(LPVOID parm); -void VDSwitchToFiberW32(LPVOID fiber); - -int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr); -void VDSetWindowTextW32(HWND hwnd, const wchar_t *s); -void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...); -VDStringA VDGetWindowTextAW32(HWND hwnd); -VDStringW VDGetWindowTextW32(HWND hwnd); -void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text); -bool VDAppendPopupMenuW32(HMENU hmenu, UINT flags, HMENU hmenuPopup, const wchar_t *text); -void VDAppendMenuSeparatorW32(HMENU hmenu); -void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked); -void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); -void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked); -void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); -void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); -VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd); -void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text); - -LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - -EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags); - -bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod); -bool VDGetFileSizeW32(HANDLE h, sint64& size); - -#if !defined(_MSC_VER) || _MSC_VER < 1300 - HMODULE VDGetLocalModuleHandleW32(); -#else - extern "C" IMAGE_DOS_HEADER __ImageBase; - inline HMODULE VDGetLocalModuleHandleW32() { - return (HINSTANCE)&__ImageBase; - } -#endif - -bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat); - -bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue); -bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue); - -/// Load a library from the Windows system directory. -HMODULE VDLoadSystemLibraryW32(const char *name); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_W32ASSIST_H +#define f_VD2_SYSTEM_W32ASSIST_H + +#include + +#include + +inline bool VDIsWindowsNT() { +#ifdef _M_AMD64 + return true; +#else + static bool is_nt = !(GetVersion() & 0x80000000); + + return is_nt; +#endif +} + +inline bool VDIsAtLeastVistaW32() { + return (sint32)(::GetVersion() & 0x800000FF) >= 6; +} + +// useful constants missing from the Platform SDK + +enum { +#ifdef _M_AMD64 + MENUITEMINFO_SIZE_VERSION_400A = sizeof(MENUITEMINFOA), + MENUITEMINFO_SIZE_VERSION_400W = sizeof(MENUITEMINFOW) +#else + MENUITEMINFO_SIZE_VERSION_400A = (offsetof(MENUITEMINFOA, cch) + sizeof(UINT)), + MENUITEMINFO_SIZE_VERSION_400W = (offsetof(MENUITEMINFOW, cch) + sizeof(UINT)) +#endif +}; + +// helper functions + +bool VDIsForegroundTaskW32(); + +LPVOID VDConvertThreadToFiberW32(LPVOID parm); +void VDSwitchToFiberW32(LPVOID fiber); + +int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr); +void VDSetWindowTextW32(HWND hwnd, const wchar_t *s); +void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...); +VDStringA VDGetWindowTextAW32(HWND hwnd); +VDStringW VDGetWindowTextW32(HWND hwnd); +void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text); +bool VDAppendPopupMenuW32(HMENU hmenu, UINT flags, HMENU hmenuPopup, const wchar_t *text); +void VDAppendMenuSeparatorW32(HMENU hmenu); +void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked); +void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); +void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked); +void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); +void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); +VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd); +void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text); + +LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags); + +bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod); +bool VDGetFileSizeW32(HANDLE h, sint64& size); + +#if !defined(_MSC_VER) || _MSC_VER < 1300 + HMODULE VDGetLocalModuleHandleW32(); +#else + extern "C" IMAGE_DOS_HEADER __ImageBase; + inline HMODULE VDGetLocalModuleHandleW32() { + return (HINSTANCE)&__ImageBase; + } +#endif + +bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat); + +bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue); +bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue); + +/// Load a library from the Windows system directory. +HMODULE VDLoadSystemLibraryW32(const char *name); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/win32/intrin.h b/src/thirdparty/VirtualDub/h/vd2/system/win32/intrin.h index d0597a24544..0566fa5ce52 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/win32/intrin.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/win32/intrin.h @@ -1,56 +1,56 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2011 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_WIN32_INTRIN_H -#define f_VD2_SYSTEM_WIN32_INTRIN_H - -#pragma once - -// The Windows SDK conflicts with the VS2005 declaration of a couple -// of intrinsics starting with the Vista SDK. The conflict is between -// intrin.h and winnt.h. To work around this, we wrap intrin.h and -// rename its declaration. -#pragma push_macro("_interlockedbittestandset") -#pragma push_macro("_interlockedbittestandreset") -#pragma push_macro("_interlockedbittestandset64") -#pragma push_macro("_interlockedbittestandreset64") - -#define _interlockedbittestandset _interlockedbittestandset_vc -#define _interlockedbittestandreset _interlockedbittestandreset_vc -#define _interlockedbittestandset64 _interlockedbittestandset64_vc -#define _interlockedbittestandreset64 _interlockedbittestandreset64_vc - -#ifdef _MSC_VER - #include -#else - #include -#endif - -#pragma pop_macro("_interlockedbittestandreset64") -#pragma pop_macro("_interlockedbittestandset64") -#pragma pop_macro("_interlockedbittestandreset") -#pragma pop_macro("_interlockedbittestandset") - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2011 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_WIN32_INTRIN_H +#define f_VD2_SYSTEM_WIN32_INTRIN_H + +#pragma once + +// The Windows SDK conflicts with the VS2005 declaration of a couple +// of intrinsics starting with the Vista SDK. The conflict is between +// intrin.h and winnt.h. To work around this, we wrap intrin.h and +// rename its declaration. +#pragma push_macro("_interlockedbittestandset") +#pragma push_macro("_interlockedbittestandreset") +#pragma push_macro("_interlockedbittestandset64") +#pragma push_macro("_interlockedbittestandreset64") + +#define _interlockedbittestandset _interlockedbittestandset_vc +#define _interlockedbittestandreset _interlockedbittestandreset_vc +#define _interlockedbittestandset64 _interlockedbittestandset64_vc +#define _interlockedbittestandreset64 _interlockedbittestandreset64_vc + +#ifdef _MSC_VER + #include +#else + #include +#endif + +#pragma pop_macro("_interlockedbittestandreset64") +#pragma pop_macro("_interlockedbittestandset64") +#pragma pop_macro("_interlockedbittestandreset") +#pragma pop_macro("_interlockedbittestandset") + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/win32/miniwindows.h b/src/thirdparty/VirtualDub/h/vd2/system/win32/miniwindows.h index fb8f8a667d3..c5426049965 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/win32/miniwindows.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/win32/miniwindows.h @@ -1,61 +1,61 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_WIN32_MINIWINDOWS_H -#define f_VD2_SYSTEM_WIN32_MINIWINDOWS_H - -#define VDZCALLBACK __stdcall - -#ifndef _WIN64 - #ifdef VD_COMPILER_MSVC - typedef __w64 int VDZINT_PTR; - typedef __w64 unsigned VDZUINT_PTR; - typedef __w64 long VDZLONG_PTR; - #else - typedef int VDZINT_PTR; - typedef unsigned VDZUINT_PTR; - typedef long VDZLONG_PTR; - #endif -#else - typedef __int64 VDZINT_PTR; - typedef unsigned __int64 VDZUINT_PTR; - typedef __int64 VDZLONG_PTR; -#endif - -typedef struct HWND__ *VDZHWND; -typedef struct HDC__ *VDZHDC; -typedef struct HKEY__ *VDZHKEY; -typedef unsigned VDZUINT; -typedef unsigned short VDZWORD; -typedef unsigned long VDZDWORD; -typedef VDZUINT_PTR VDZWPARAM; -typedef VDZLONG_PTR VDZLPARAM; -typedef VDZLONG_PTR VDZLRESULT; -typedef struct HDROP__ *VDZHDROP; -typedef struct HACCEL__ *VDZHACCEL; - -typedef VDZWORD VDZATOM; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_WIN32_MINIWINDOWS_H +#define f_VD2_SYSTEM_WIN32_MINIWINDOWS_H + +#define VDZCALLBACK __stdcall + +#ifndef _WIN64 + #ifdef VD_COMPILER_MSVC + typedef __w64 int VDZINT_PTR; + typedef __w64 unsigned VDZUINT_PTR; + typedef __w64 long VDZLONG_PTR; + #else + typedef int VDZINT_PTR; + typedef unsigned VDZUINT_PTR; + typedef long VDZLONG_PTR; + #endif +#else + typedef __int64 VDZINT_PTR; + typedef unsigned __int64 VDZUINT_PTR; + typedef __int64 VDZLONG_PTR; +#endif + +typedef struct HWND__ *VDZHWND; +typedef struct HDC__ *VDZHDC; +typedef struct HKEY__ *VDZHKEY; +typedef unsigned VDZUINT; +typedef unsigned short VDZWORD; +typedef unsigned long VDZDWORD; +typedef VDZUINT_PTR VDZWPARAM; +typedef VDZLONG_PTR VDZLPARAM; +typedef VDZLONG_PTR VDZLRESULT; +typedef struct HDROP__ *VDZHDROP; +typedef struct HACCEL__ *VDZHACCEL; + +typedef VDZWORD VDZATOM; + +#endif diff --git a/src/thirdparty/VirtualDub/system/h/stdafx.h b/src/thirdparty/VirtualDub/system/h/stdafx.h index 24638d54925..1af05fa819f 100644 --- a/src/thirdparty/VirtualDub/system/h/stdafx.h +++ b/src/thirdparty/VirtualDub/system/h/stdafx.h @@ -1,36 +1,36 @@ -// Force C locale to avoid this warning: -// -// mmreg.h : warning C4819: The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss -#pragma setlocale("C") - -/* MPC-HC comment out -// Detect the Windows SDK in use and select Windows 2000 baseline -// if the Vista SDK, else Windows 98 baseline. -#ifdef _MSC_VER -#include -#else -#define VER_PRODUCTBUILD 6001 -#endif -#if VER_PRODUCTBUILD > 6000 -#define _WIN32_WINNT 0x0500 -#else -#define _WIN32_WINNT 0x0410 -#endif -*/ - -// Start patch MPC-HC -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif -// End patch MPC-HC - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +// Force C locale to avoid this warning: +// +// mmreg.h : warning C4819: The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss +#pragma setlocale("C") + +/* MPC-HC comment out +// Detect the Windows SDK in use and select Windows 2000 baseline +// if the Vista SDK, else Windows 98 baseline. +#ifdef _MSC_VER +#include +#else +#define VER_PRODUCTBUILD 6001 +#endif +#if VER_PRODUCTBUILD > 6000 +#define _WIN32_WINNT 0x0500 +#else +#define _WIN32_WINNT 0x0410 +#endif +*/ + +// Start patch MPC-HC +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +// End patch MPC-HC + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/thirdparty/VirtualDub/system/source/Error.cpp b/src/thirdparty/VirtualDub/system/source/Error.cpp index 17f856a46f3..2b379d59fc9 100644 --- a/src/thirdparty/VirtualDub/system/source/Error.cpp +++ b/src/thirdparty/VirtualDub/system/source/Error.cpp @@ -1,149 +1,149 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include -#include - -MyError::MyError() { - buf = NULL; -} - -MyError::MyError(const MyError& err) { - buf = _strdup(err.buf); -} - -MyError::MyError(const char *f, ...) - : buf(NULL) -{ - va_list val; - - va_start(val, f); - vsetf(f, val); - va_end(val); -} - -MyError::~MyError() { - free(buf); -} - -void MyError::clear() { - if (buf) // we do this check because debug free() always does a heapchk even if buf==NULL - free(buf); - buf = NULL; -} - -void MyError::assign(const MyError& e) { - if (buf) - free(buf); - buf = _strdup(e.buf); -} - -void MyError::assign(const char *s) { - if (buf) - free(buf); - buf = _strdup(s); -} - -void MyError::setf(const char *f, ...) { - va_list val; - - va_start(val, f); - vsetf(f,val); - va_end(val); -} - -void MyError::vsetf(const char *f, va_list val) { - for(int size = 1024; size <= 32768; size += size) { - free(buf); - buf = NULL; - - buf = (char *)malloc(size); - if (!buf) - return; - - if ((unsigned)_vsnprintf(buf, size, f, val) < (unsigned)size) - return; - } - - free(buf); - buf = NULL; -} - -void MyError::post(HWND hWndParent, const char *title) const { - if (!buf || !*buf) - return; - - VDDEBUG("*** %s: %s\n", title, buf); - //VDLog(kVDLogError, VDswprintf(L"Error: %hs", 1, &buf)); - - MessageBox(hWndParent, buf, title, MB_OK | MB_ICONERROR | MB_SETFOREGROUND); -} - -void MyError::discard() { - free(buf); - buf = NULL; -} - -void MyError::swap(MyError& err) { - char *s = err.buf; - err.buf = buf; - buf = s; -} - -void MyError::TransferFrom(MyError& err) { - if (buf) - free(buf); - - buf = err.buf; - err.buf = NULL; -} - -MyMemoryError::MyMemoryError() { - setf("Out of memory"); -} - -MyMemoryError::MyMemoryError(size_t requestedSize) { - setf("Out of memory (unable to allocate %llu bytes)", (unsigned long long)requestedSize); -} - -MyUserAbortError::MyUserAbortError() { - buf = _strdup(""); -} - -MyInternalError::MyInternalError(const char *format, ...) { - char buf[1024]; - va_list val; - - va_start(val, format); - _vsnprintf(buf, (sizeof buf) - 1, format, val); - buf[1023] = 0; - va_end(val); - - setf("Internal error: %s", buf); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +#include +#include + +MyError::MyError() { + buf = NULL; +} + +MyError::MyError(const MyError& err) { + buf = _strdup(err.buf); +} + +MyError::MyError(const char *f, ...) + : buf(NULL) +{ + va_list val; + + va_start(val, f); + vsetf(f, val); + va_end(val); +} + +MyError::~MyError() { + free(buf); +} + +void MyError::clear() { + if (buf) // we do this check because debug free() always does a heapchk even if buf==NULL + free(buf); + buf = NULL; +} + +void MyError::assign(const MyError& e) { + if (buf) + free(buf); + buf = _strdup(e.buf); +} + +void MyError::assign(const char *s) { + if (buf) + free(buf); + buf = _strdup(s); +} + +void MyError::setf(const char *f, ...) { + va_list val; + + va_start(val, f); + vsetf(f,val); + va_end(val); +} + +void MyError::vsetf(const char *f, va_list val) { + for(int size = 1024; size <= 32768; size += size) { + free(buf); + buf = NULL; + + buf = (char *)malloc(size); + if (!buf) + return; + + if ((unsigned)_vsnprintf(buf, size, f, val) < (unsigned)size) + return; + } + + free(buf); + buf = NULL; +} + +void MyError::post(HWND hWndParent, const char *title) const { + if (!buf || !*buf) + return; + + VDDEBUG("*** %s: %s\n", title, buf); + //VDLog(kVDLogError, VDswprintf(L"Error: %hs", 1, &buf)); + + MessageBox(hWndParent, buf, title, MB_OK | MB_ICONERROR | MB_SETFOREGROUND); +} + +void MyError::discard() { + free(buf); + buf = NULL; +} + +void MyError::swap(MyError& err) { + char *s = err.buf; + err.buf = buf; + buf = s; +} + +void MyError::TransferFrom(MyError& err) { + if (buf) + free(buf); + + buf = err.buf; + err.buf = NULL; +} + +MyMemoryError::MyMemoryError() { + setf("Out of memory"); +} + +MyMemoryError::MyMemoryError(size_t requestedSize) { + setf("Out of memory (unable to allocate %llu bytes)", (unsigned long long)requestedSize); +} + +MyUserAbortError::MyUserAbortError() { + buf = _strdup(""); +} + +MyInternalError::MyInternalError(const char *format, ...) { + char buf[1024]; + va_list val; + + va_start(val, format); + _vsnprintf(buf, (sizeof buf) - 1, format, val); + buf[1023] = 0; + va_end(val); + + setf("Internal error: %s", buf); +} diff --git a/src/thirdparty/VirtualDub/system/source/Fraction.cpp b/src/thirdparty/VirtualDub/system/source/Fraction.cpp index cac7da91d10..be7c1e7e065 100644 --- a/src/thirdparty/VirtualDub/system/source/Fraction.cpp +++ b/src/thirdparty/VirtualDub/system/source/Fraction.cpp @@ -1,327 +1,327 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -#include -#include -#include - -VDFraction::VDFraction(double d) { - int xp; - double mant = frexp(d, &xp); - - if (xp >= 33) { - hi = 0xFFFFFFFF; - lo = 1; - } else if (xp < -31) { - hi = 0; - lo = 1; - } else if (xp >= 0) { - *this = reduce((uint64)(0.5 + ldexp(mant, 62)), 1ll<<(62-xp)); - } else { - // This is not quite accurate for very tiny numbers. - VDFraction t(1.0 / d); - lo = t.hi; - hi = t.lo; - } -} - -VDFraction VDFraction::reduce(uint64 hi, uint64 lo) { - - // Check for undefined. - - if (!lo) - return VDFraction(0,0); - - // Check for zero. - - if (!hi) { - return VDFraction(0,1); - } - - // Check for infinity. - - if (!((uint64)lo>>32) && (uint64)hi > ((uint64)lo<<32)-lo) - return VDFraction(0xFFFFFFFFUL, 1); - - // Algorithm from Wikipedia, Continued Fractions: - uint64 n0 = 0; - uint64 d0 = 1; - uint32 n1 = 1; - uint32 d1 = 0; - uint64 fp = 0; - - uint32 n_best; - uint32 d_best; - - for(;;) { - uint64 a = hi/lo; // next continued fraction term - uint64 f = hi%lo; // remainder - - uint64 n2 = n0 + n1*a; // next convergent numerator - uint64 d2 = d0 + d1*a; // next convergent denominator - - uint32 n_overflow = (uint32)(n2 >> 32); - uint32 d_overflow = (uint32)(d2 >> 32); - - if (n_overflow | d_overflow) { - uint64 a2 = a; - - // reduce last component until numerator and denominator are within range - if (n_overflow) - a2 = (0xFFFFFFFF - n0) / n1; - - if (d_overflow) { - uint64 a3 = (0xFFFFFFFF - d0) / d1; - if (a2 > a3) - a2 = a3; - } - - // check if new term is better - // 1/2a_k admissibility test - if (a2*2 < a || (a2*2 == a && d0*fp <= f*d1)) - return VDFraction((uint32)n_best, (uint32)d_best); - - return VDFraction((uint32)(n0 + n1*a2), (uint32)(d0 + d1*a2)); - } - - n_best = (uint32)n2; - d_best = (uint32)d2; - - // if fraction is exact, we're done. - if (!f) - return VDFraction((uint32)n_best, (uint32)d_best); - - n0 = n1; - n1 = (uint32)n2; - d0 = d1; - d1 = (uint32)d2; - fp = f; - - hi = lo; - lo = f; - } -} - -// a (cond) b -// a-b (cond) 0 -// aH*bL - aL*bh (cond) 0 -// aH*bL (cond) aL*bH - -bool VDFraction::operator==(VDFraction b) const { - return (uint64)hi * b.lo == (uint64)lo * b.hi; -} - -bool VDFraction::operator!=(VDFraction b) const { - return (uint64)hi * b.lo != (uint64)lo * b.hi; -} - -bool VDFraction::operator< (VDFraction b) const { - return (uint64)hi * b.lo < (uint64)lo * b.hi; -} - -bool VDFraction::operator<=(VDFraction b) const { - return (uint64)hi * b.lo <= (uint64)lo * b.hi; -} - -bool VDFraction::operator> (VDFraction b) const { - return (uint64)hi * b.lo > (uint64)lo * b.hi; -} - -bool VDFraction::operator>=(VDFraction b) const { - return (uint64)hi * b.lo >= (uint64)lo * b.hi; -} - -VDFraction VDFraction::operator*(VDFraction b) const { - return reduce((uint64)hi * b.hi, (uint64)lo * b.lo); -} - -VDFraction VDFraction::operator/(VDFraction b) const { - return reduce((uint64)hi * b.lo, (uint64)lo * b.hi); -} - -VDFraction VDFraction::operator*(unsigned long b) const { - return reduce((uint64)hi * b, lo); -} - -VDFraction VDFraction::operator/(unsigned long b) const { - return reduce(hi, (uint64)lo * b); -} - -VDFraction& VDFraction::operator*=(VDFraction b) { - return *this = reduce((uint64)hi * b.hi, (uint64)lo * b.lo); -} - -VDFraction& VDFraction::operator/=(VDFraction b) { - return *this = reduce((uint64)hi * b.lo, (uint64)lo * b.hi); -} - -VDFraction& VDFraction::operator*=(unsigned long b) { - return *this = reduce((uint64)hi * b, lo); -} - -VDFraction& VDFraction::operator/=(unsigned long b) { - return *this = reduce(hi, (uint64)lo * b); -} - -/////////////////////////////////////////////////////////////////////////// - -sint64 VDFraction::scale64t(sint64 v) const { - uint32 r; - return v<0 ? -VDFractionScale64(-v, hi, lo, r) : VDFractionScale64(v, hi, lo, r); -} - -sint64 VDFraction::scale64u(sint64 v) const { - uint32 r; - if (v<0) { - v = -VDFractionScale64(-v, hi, lo, r); - return v; - } else { - v = +VDFractionScale64(+v, hi, lo, r); - return v + (r > 0); - } -} - -sint64 VDFraction::scale64r(sint64 v) const { - uint32 r; - if (v<0) { - v = -VDFractionScale64(-v, hi, lo, r); - return v - (r >= (lo>>1) + (lo&1)); - } else { - v = +VDFractionScale64(+v, hi, lo, r); - return v + (r >= (lo>>1) + (lo&1)); - } -} - -sint64 VDFraction::scale64it(sint64 v) const { - uint32 r; - return v<0 ? -VDFractionScale64(-v, lo, hi, r) : +VDFractionScale64(+v, lo, hi, r); -} - -sint64 VDFraction::scale64ir(sint64 v) const { - uint32 r; - if (v<0) { - v = -VDFractionScale64(-v, lo, hi, r); - return v - (r >= (hi>>1) + (hi&1)); - } else { - v = +VDFractionScale64(+v, lo, hi, r); - return v + (r >= (hi>>1) + (hi&1)); - } -} - -sint64 VDFraction::scale64iu(sint64 v) const { - uint32 r; - if (v<0) { - v = -VDFractionScale64(-v, lo, hi, r); - return v; - } else { - v = +VDFractionScale64(+v, lo, hi, r); - return v + (r > 0); - } -} - -/////////////////////////////////////////////////////////////////////////// - -double VDFraction::asDouble() const { - return (double)hi / (double)lo; -} - -double VDFraction::AsInverseDouble() const { - return (double)lo / (double)hi; -} - -unsigned long VDFraction::roundup32ul() const { - return (hi + (lo-1)) / lo; -} - -/////////////////////////////////////////////////////////////////////////// - -bool VDFraction::Parse(const char *s) { - char c; - - // skip whitespace - while((c = *s) && (c == ' ' || c == '\t')) - ++s; - - // accumulate integer digits - uint64 x = 0; - uint64 y = 1; - - while(c = *s) { - uint32 offset = (uint32)c - '0'; - - if (offset >= 10) - break; - - x = (x * 10) + offset; - - // check for overflow - if (x >> 32) - return false; - - ++s; - } - - if (c == '.') { - ++s; - - while(c = *s) { - uint32 offset = (uint32)c - '0'; - - if (offset >= 10) - break; - - if (x >= 100000000000000000 || - y >= 100000000000000000) { - if (offset >= 5) - ++x; - while((c = *s) && (unsigned)(c - '0') < 10) - ++s; - break; - } - - x = (x * 10) + offset; - y *= 10; - ++s; - } - } - - while(c == ' ' || c == '\t') - c = *++s; - - // check for trailing garbage - if (c) - return false; - - // check for overflow - if (!(y >> 32) && ((uint64)(uint32)y << 32) <= x) - return false; - - // reduce fraction and return success - *this = reduce(x, y); - return true; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include +#include +#include + +VDFraction::VDFraction(double d) { + int xp; + double mant = frexp(d, &xp); + + if (xp >= 33) { + hi = 0xFFFFFFFF; + lo = 1; + } else if (xp < -31) { + hi = 0; + lo = 1; + } else if (xp >= 0) { + *this = reduce((uint64)(0.5 + ldexp(mant, 62)), 1ll<<(62-xp)); + } else { + // This is not quite accurate for very tiny numbers. + VDFraction t(1.0 / d); + lo = t.hi; + hi = t.lo; + } +} + +VDFraction VDFraction::reduce(uint64 hi, uint64 lo) { + + // Check for undefined. + + if (!lo) + return VDFraction(0,0); + + // Check for zero. + + if (!hi) { + return VDFraction(0,1); + } + + // Check for infinity. + + if (!((uint64)lo>>32) && (uint64)hi > ((uint64)lo<<32)-lo) + return VDFraction(0xFFFFFFFFUL, 1); + + // Algorithm from Wikipedia, Continued Fractions: + uint64 n0 = 0; + uint64 d0 = 1; + uint32 n1 = 1; + uint32 d1 = 0; + uint64 fp = 0; + + uint32 n_best; + uint32 d_best; + + for(;;) { + uint64 a = hi/lo; // next continued fraction term + uint64 f = hi%lo; // remainder + + uint64 n2 = n0 + n1*a; // next convergent numerator + uint64 d2 = d0 + d1*a; // next convergent denominator + + uint32 n_overflow = (uint32)(n2 >> 32); + uint32 d_overflow = (uint32)(d2 >> 32); + + if (n_overflow | d_overflow) { + uint64 a2 = a; + + // reduce last component until numerator and denominator are within range + if (n_overflow) + a2 = (0xFFFFFFFF - n0) / n1; + + if (d_overflow) { + uint64 a3 = (0xFFFFFFFF - d0) / d1; + if (a2 > a3) + a2 = a3; + } + + // check if new term is better + // 1/2a_k admissibility test + if (a2*2 < a || (a2*2 == a && d0*fp <= f*d1)) + return VDFraction((uint32)n_best, (uint32)d_best); + + return VDFraction((uint32)(n0 + n1*a2), (uint32)(d0 + d1*a2)); + } + + n_best = (uint32)n2; + d_best = (uint32)d2; + + // if fraction is exact, we're done. + if (!f) + return VDFraction((uint32)n_best, (uint32)d_best); + + n0 = n1; + n1 = (uint32)n2; + d0 = d1; + d1 = (uint32)d2; + fp = f; + + hi = lo; + lo = f; + } +} + +// a (cond) b +// a-b (cond) 0 +// aH*bL - aL*bh (cond) 0 +// aH*bL (cond) aL*bH + +bool VDFraction::operator==(VDFraction b) const { + return (uint64)hi * b.lo == (uint64)lo * b.hi; +} + +bool VDFraction::operator!=(VDFraction b) const { + return (uint64)hi * b.lo != (uint64)lo * b.hi; +} + +bool VDFraction::operator< (VDFraction b) const { + return (uint64)hi * b.lo < (uint64)lo * b.hi; +} + +bool VDFraction::operator<=(VDFraction b) const { + return (uint64)hi * b.lo <= (uint64)lo * b.hi; +} + +bool VDFraction::operator> (VDFraction b) const { + return (uint64)hi * b.lo > (uint64)lo * b.hi; +} + +bool VDFraction::operator>=(VDFraction b) const { + return (uint64)hi * b.lo >= (uint64)lo * b.hi; +} + +VDFraction VDFraction::operator*(VDFraction b) const { + return reduce((uint64)hi * b.hi, (uint64)lo * b.lo); +} + +VDFraction VDFraction::operator/(VDFraction b) const { + return reduce((uint64)hi * b.lo, (uint64)lo * b.hi); +} + +VDFraction VDFraction::operator*(unsigned long b) const { + return reduce((uint64)hi * b, lo); +} + +VDFraction VDFraction::operator/(unsigned long b) const { + return reduce(hi, (uint64)lo * b); +} + +VDFraction& VDFraction::operator*=(VDFraction b) { + return *this = reduce((uint64)hi * b.hi, (uint64)lo * b.lo); +} + +VDFraction& VDFraction::operator/=(VDFraction b) { + return *this = reduce((uint64)hi * b.lo, (uint64)lo * b.hi); +} + +VDFraction& VDFraction::operator*=(unsigned long b) { + return *this = reduce((uint64)hi * b, lo); +} + +VDFraction& VDFraction::operator/=(unsigned long b) { + return *this = reduce(hi, (uint64)lo * b); +} + +/////////////////////////////////////////////////////////////////////////// + +sint64 VDFraction::scale64t(sint64 v) const { + uint32 r; + return v<0 ? -VDFractionScale64(-v, hi, lo, r) : VDFractionScale64(v, hi, lo, r); +} + +sint64 VDFraction::scale64u(sint64 v) const { + uint32 r; + if (v<0) { + v = -VDFractionScale64(-v, hi, lo, r); + return v; + } else { + v = +VDFractionScale64(+v, hi, lo, r); + return v + (r > 0); + } +} + +sint64 VDFraction::scale64r(sint64 v) const { + uint32 r; + if (v<0) { + v = -VDFractionScale64(-v, hi, lo, r); + return v - (r >= (lo>>1) + (lo&1)); + } else { + v = +VDFractionScale64(+v, hi, lo, r); + return v + (r >= (lo>>1) + (lo&1)); + } +} + +sint64 VDFraction::scale64it(sint64 v) const { + uint32 r; + return v<0 ? -VDFractionScale64(-v, lo, hi, r) : +VDFractionScale64(+v, lo, hi, r); +} + +sint64 VDFraction::scale64ir(sint64 v) const { + uint32 r; + if (v<0) { + v = -VDFractionScale64(-v, lo, hi, r); + return v - (r >= (hi>>1) + (hi&1)); + } else { + v = +VDFractionScale64(+v, lo, hi, r); + return v + (r >= (hi>>1) + (hi&1)); + } +} + +sint64 VDFraction::scale64iu(sint64 v) const { + uint32 r; + if (v<0) { + v = -VDFractionScale64(-v, lo, hi, r); + return v; + } else { + v = +VDFractionScale64(+v, lo, hi, r); + return v + (r > 0); + } +} + +/////////////////////////////////////////////////////////////////////////// + +double VDFraction::asDouble() const { + return (double)hi / (double)lo; +} + +double VDFraction::AsInverseDouble() const { + return (double)lo / (double)hi; +} + +unsigned long VDFraction::roundup32ul() const { + return (hi + (lo-1)) / lo; +} + +/////////////////////////////////////////////////////////////////////////// + +bool VDFraction::Parse(const char *s) { + char c; + + // skip whitespace + while((c = *s) && (c == ' ' || c == '\t')) + ++s; + + // accumulate integer digits + uint64 x = 0; + uint64 y = 1; + + while(c = *s) { + uint32 offset = (uint32)c - '0'; + + if (offset >= 10) + break; + + x = (x * 10) + offset; + + // check for overflow + if (x >> 32) + return false; + + ++s; + } + + if (c == '.') { + ++s; + + while(c = *s) { + uint32 offset = (uint32)c - '0'; + + if (offset >= 10) + break; + + if (x >= 100000000000000000 || + y >= 100000000000000000) { + if (offset >= 5) + ++x; + while((c = *s) && (unsigned)(c - '0') < 10) + ++s; + break; + } + + x = (x * 10) + offset; + y *= 10; + ++s; + } + } + + while(c == ' ' || c == '\t') + c = *++s; + + // check for trailing garbage + if (c) + return false; + + // check for overflow + if (!(y >> 32) && ((uint64)(uint32)y << 32) <= x) + return false; + + // reduce fraction and return success + *this = reduce(x, y); + return true; +} diff --git a/src/thirdparty/VirtualDub/system/source/VDNamespace.cpp b/src/thirdparty/VirtualDub/system/source/VDNamespace.cpp index 6098dc77d90..91b7c8dd250 100644 --- a/src/thirdparty/VirtualDub/system/source/VDNamespace.cpp +++ b/src/thirdparty/VirtualDub/system/source/VDNamespace.cpp @@ -1,253 +1,253 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// -// Group -// -/////////////////////////////////////////////////////////////////////////// - -VDNamespaceGroup::VDNamespaceGroup(const char *_pszName, VDNamespaceGroup *parent) -: VDNamespaceNode(namedup(_pszName),parent) -{ - const char *t = strchr(_pszName,'/'); - - if (t) { - - } else - strcpy((char *)pszName, _pszName); -} - -VDNamespaceGroup::~VDNamespaceGroup() { - delete[] (char *)pszName; -} - -const char *VDNamespaceGroup::namedup(const char *s) { - const char *t = strchr(s,'/'); - char *mem; - - if (t) { - mem = new char[(t-s)+1]; - - memcpy(mem, s, (t-s)); - mem[t-s] = 0; - - return mem; - } else { - mem = new char[strlen(s)+1]; - - return strcpy(mem, s); - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// Item -// -/////////////////////////////////////////////////////////////////////////// - -VDNamespaceItem::VDNamespaceItem(const char *_pszName, VDNamespaceGroup *parent, const void *src) -: VDNamespaceNode(_pszName,parent), object(src) -{} - -VDNamespaceItem::~VDNamespaceItem() {} - -/////////////////////////////////////////////////////////////////////////// -// -// VDNamespace -// -/////////////////////////////////////////////////////////////////////////// - -bool VDNamespaceCompare(const char *psz1, const char *psz2) { - char c, d; - - while((!!(c=toupper(*psz1++)) & !!(d=toupper(*psz2++))) && c!='/' && d!='/' && c==d) - ; - - if (c=='/') c=0; - if (d=='/') d=0; - - return c==d; -} - -VDNamespace::VDNamespace() : root("", NULL) { -} - -VDNamespace::~VDNamespace() { -} - -VDNamespaceGroup *VDNamespace::_lookupGroup(const char *pszName, bool fCreate, bool fIsFilter) { - const char *pszNameLimit = pszName; - const char *slash = NULL; - VDNamespaceGroup *pGroup = &root, *pGroupNext; - - while(*pszNameLimit) { - if (*pszNameLimit++ == '/') - slash = pszNameLimit - 1; - } - - if (fIsFilter) - pszNameLimit = slash; - - while(pszName < pszNameLimit) { - VDNamespaceGroup *pGroupParent = pGroup; - - pGroup = pGroup->listGroups.AtHead(); - - while(pGroupNext = pGroup->NextFromHead()) { - if (VDNamespaceCompare(pszName, pGroup->pszName)) - break; - - pGroup = pGroupNext; - } - - if (!pGroupNext && fCreate) { - pGroupNext = pGroup = new VDNamespaceGroup(pszName, pGroupParent); - - pGroupParent->listGroups.AddTail(pGroup); - } - - // group not found? - - if (!pGroupNext) { - return NULL; - } - - // advance to next slash - - while(*pszName && *pszName++!='/') - ; - } - - return pGroup; -} - -void VDNamespace::clear() { - root.listGroups.dispose(); - root.listItems.dispose(); -} - -void VDNamespace::add(const char *pszGroup, const char *pszName, const void *pDef) { - VDNamespaceGroup *pGroup = _lookupGroup(pszGroup, true, false); - - pGroup->listItems.AddTail(new VDNamespaceItem(pszName, pGroup, pDef)); -} - -const void *VDNamespace::lookup(const char *pszName) { - VDNamespaceGroup *pGroup = _lookupGroup(pszName, false, true); - - if (!pGroup) - return NULL; - - const char *pszNameBase = pszName; - - while(*pszName++) - if (pszName[-1]=='/') - pszNameBase = pszName; - - for(ListAlloc::fwit it = pGroup->listItems.begin(); it; ++it) - if (!_stricmp(it->pszName, pszNameBase)) - return it->object; - - return NULL; -} - -bool VDNamespace::enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData) { - VDNamespaceGroup *pGroup, *pGroupNext; - - pGroup = (pGroupRoot ? pGroupRoot : &root)->listGroups.AtHead(); - while(pGroupNext = pGroup->NextFromHead()) { - if (!pEnum(this, pGroup->pszName, pGroup, pvData)) - return false; - - pGroup = pGroupNext; - } - - return true; -} - -bool VDNamespace::enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData) { - VDNamespaceItem *pEntry, *pEntryNext; - - pEntry = pGroupRoot->listItems.AtHead(); - while(pEntryNext = pEntry->NextFromHead()) { - if (!pEnum(this, pEntry->pszName, pEntry->object, pvData)) - return false; - - pEntry = pEntryNext; - } - - return true; -} - -VDNamespaceItem *VDNamespace::_findItemByObject(const VDNamespaceGroup *pGroup, const void *pObj) { - for(ListAlloc::fwit it=pGroup->listItems.begin(); it; ++it) { - if (it->object == pObj) { - return it; - } - } - - for(ListAlloc::fwit it2=pGroup->listGroups.begin(); it2; ++it2) { - VDNamespaceItem *v; - - if (v = _findItemByObject(it2, pObj)) - return v; - } - - return NULL; -} - -bool VDNamespace::_getPathByItem(const VDNamespaceNode *pEntry, char *buf, int maxlen) { - if (!pEntry) - return false; - - if (maxlen < (int)strlen(pEntry->pszName)+2) - return false; - - if (pEntry->pParent && pEntry->pParent->pParent) { - if (!_getPathByItem(pEntry->pParent, buf, maxlen)) - return false; - - while(*buf) - ++buf, --maxlen; - - *buf++ = '/'; - } - - strcpy(buf, pEntry->pszName); - - return true; -} - -bool VDNamespace::getPathByItem(const void *pObj, char *buf, int maxlen) { - return _getPathByItem(_findItemByObject(&root, pObj), buf, maxlen); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// +// Group +// +/////////////////////////////////////////////////////////////////////////// + +VDNamespaceGroup::VDNamespaceGroup(const char *_pszName, VDNamespaceGroup *parent) +: VDNamespaceNode(namedup(_pszName),parent) +{ + const char *t = strchr(_pszName,'/'); + + if (t) { + + } else + strcpy((char *)pszName, _pszName); +} + +VDNamespaceGroup::~VDNamespaceGroup() { + delete[] (char *)pszName; +} + +const char *VDNamespaceGroup::namedup(const char *s) { + const char *t = strchr(s,'/'); + char *mem; + + if (t) { + mem = new char[(t-s)+1]; + + memcpy(mem, s, (t-s)); + mem[t-s] = 0; + + return mem; + } else { + mem = new char[strlen(s)+1]; + + return strcpy(mem, s); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// Item +// +/////////////////////////////////////////////////////////////////////////// + +VDNamespaceItem::VDNamespaceItem(const char *_pszName, VDNamespaceGroup *parent, const void *src) +: VDNamespaceNode(_pszName,parent), object(src) +{} + +VDNamespaceItem::~VDNamespaceItem() {} + +/////////////////////////////////////////////////////////////////////////// +// +// VDNamespace +// +/////////////////////////////////////////////////////////////////////////// + +bool VDNamespaceCompare(const char *psz1, const char *psz2) { + char c, d; + + while((!!(c=toupper(*psz1++)) & !!(d=toupper(*psz2++))) && c!='/' && d!='/' && c==d) + ; + + if (c=='/') c=0; + if (d=='/') d=0; + + return c==d; +} + +VDNamespace::VDNamespace() : root("", NULL) { +} + +VDNamespace::~VDNamespace() { +} + +VDNamespaceGroup *VDNamespace::_lookupGroup(const char *pszName, bool fCreate, bool fIsFilter) { + const char *pszNameLimit = pszName; + const char *slash = NULL; + VDNamespaceGroup *pGroup = &root, *pGroupNext; + + while(*pszNameLimit) { + if (*pszNameLimit++ == '/') + slash = pszNameLimit - 1; + } + + if (fIsFilter) + pszNameLimit = slash; + + while(pszName < pszNameLimit) { + VDNamespaceGroup *pGroupParent = pGroup; + + pGroup = pGroup->listGroups.AtHead(); + + while(pGroupNext = pGroup->NextFromHead()) { + if (VDNamespaceCompare(pszName, pGroup->pszName)) + break; + + pGroup = pGroupNext; + } + + if (!pGroupNext && fCreate) { + pGroupNext = pGroup = new VDNamespaceGroup(pszName, pGroupParent); + + pGroupParent->listGroups.AddTail(pGroup); + } + + // group not found? + + if (!pGroupNext) { + return NULL; + } + + // advance to next slash + + while(*pszName && *pszName++!='/') + ; + } + + return pGroup; +} + +void VDNamespace::clear() { + root.listGroups.dispose(); + root.listItems.dispose(); +} + +void VDNamespace::add(const char *pszGroup, const char *pszName, const void *pDef) { + VDNamespaceGroup *pGroup = _lookupGroup(pszGroup, true, false); + + pGroup->listItems.AddTail(new VDNamespaceItem(pszName, pGroup, pDef)); +} + +const void *VDNamespace::lookup(const char *pszName) { + VDNamespaceGroup *pGroup = _lookupGroup(pszName, false, true); + + if (!pGroup) + return NULL; + + const char *pszNameBase = pszName; + + while(*pszName++) + if (pszName[-1]=='/') + pszNameBase = pszName; + + for(ListAlloc::fwit it = pGroup->listItems.begin(); it; ++it) + if (!_stricmp(it->pszName, pszNameBase)) + return it->object; + + return NULL; +} + +bool VDNamespace::enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData) { + VDNamespaceGroup *pGroup, *pGroupNext; + + pGroup = (pGroupRoot ? pGroupRoot : &root)->listGroups.AtHead(); + while(pGroupNext = pGroup->NextFromHead()) { + if (!pEnum(this, pGroup->pszName, pGroup, pvData)) + return false; + + pGroup = pGroupNext; + } + + return true; +} + +bool VDNamespace::enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData) { + VDNamespaceItem *pEntry, *pEntryNext; + + pEntry = pGroupRoot->listItems.AtHead(); + while(pEntryNext = pEntry->NextFromHead()) { + if (!pEnum(this, pEntry->pszName, pEntry->object, pvData)) + return false; + + pEntry = pEntryNext; + } + + return true; +} + +VDNamespaceItem *VDNamespace::_findItemByObject(const VDNamespaceGroup *pGroup, const void *pObj) { + for(ListAlloc::fwit it=pGroup->listItems.begin(); it; ++it) { + if (it->object == pObj) { + return it; + } + } + + for(ListAlloc::fwit it2=pGroup->listGroups.begin(); it2; ++it2) { + VDNamespaceItem *v; + + if (v = _findItemByObject(it2, pObj)) + return v; + } + + return NULL; +} + +bool VDNamespace::_getPathByItem(const VDNamespaceNode *pEntry, char *buf, int maxlen) { + if (!pEntry) + return false; + + if (maxlen < (int)strlen(pEntry->pszName)+2) + return false; + + if (pEntry->pParent && pEntry->pParent->pParent) { + if (!_getPathByItem(pEntry->pParent, buf, maxlen)) + return false; + + while(*buf) + ++buf, --maxlen; + + *buf++ = '/'; + } + + strcpy(buf, pEntry->pszName); + + return true; +} + +bool VDNamespace::getPathByItem(const void *pObj, char *buf, int maxlen) { + return _getPathByItem(_findItemByObject(&root, pObj), buf, maxlen); +} diff --git a/src/thirdparty/VirtualDub/system/source/VDScheduler.cpp b/src/thirdparty/VirtualDub/system/source/VDScheduler.cpp index caa0c6134d1..e4bdcafa517 100644 --- a/src/thirdparty/VirtualDub/system/source/VDScheduler.cpp +++ b/src/thirdparty/VirtualDub/system/source/VDScheduler.cpp @@ -1,322 +1,322 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include -#include -#include - -VDScheduler::VDScheduler() - : mpErrorCB(NULL) - , pWakeupSignal(NULL) - , pParentSchedulerNode(NULL) - , mbExitThreads(false) -{ -} - -VDScheduler::~VDScheduler() { -} - -void VDScheduler::setSignal(VDSignal *pSignal) { - pWakeupSignal = pSignal; -} - -void VDScheduler::setSchedulerNode(VDSchedulerNode *pSchedulerNode) { - pParentSchedulerNode = pSchedulerNode; -} - -void VDScheduler::BeginShutdown() { - mbExitThreads = true; - Ping(); -} - -void VDScheduler::Repost(VDSchedulerNode *pNode, bool bReschedule) { - vdsynchronized(csScheduler) { - if (pNode->bCondemned) { - tSuspendList::iterator it(listSuspends.begin()), itEnd(listSuspends.end()); - - while(it!=itEnd) { - VDSchedulerSuspendNode *pSuspendNode = *it; - - if (pSuspendNode->mpNode == pNode) { - it = listSuspends.erase(it); - pSuspendNode->mSignal.signal(); - } else - ++it; - } - } else { - pNode->bRunning = false; - if (bReschedule || pNode->bReschedule) { - pNode->bReschedule = false; - pNode->bReady = true; - listReady.push_back(pNode); - } else - listWaiting.push_back(pNode); - } - } -} - -bool VDScheduler::Run() { - VDSchedulerNode *pNode = NULL; - vdsynchronized(csScheduler) { - if (!listReady.empty()) { - pNode = listReady.front(); - listReady.pop_front(); - pNode->bRunning = true; - pNode->bReady = false; - } - } - - if (!pNode) - return false; - - bool bReschedule; - try { - bReschedule = pNode->Service(); - } catch(MyError& e) { - Repost(pNode, false); - - vdsynchronized(csScheduler) { - if (mpErrorCB) { - if (!mpErrorCB->OnAsyncError(e)) - throw; - } - } - - return true; - } catch(...) { - Repost(pNode, false); - throw; - } - - Repost(pNode, bReschedule); - - return true; -} - -bool VDScheduler::IdleWait() { - if (mbExitThreads) - return false; - - if (pWakeupSignal) { -#if 0 - while(WAIT_TIMEOUT == WaitForSingleObject(pWakeupSignal->getHandle(), 1000)) - DumpStatus(); -#else - pWakeupSignal->wait(); -#endif - } - - return true; -} - -void VDScheduler::Ping() { - if (pWakeupSignal) - pWakeupSignal->signal(); -} - -void VDScheduler::Lock() { - ++csScheduler; -} - -void VDScheduler::Unlock() { - --csScheduler; -} - -void VDScheduler::Reschedule(VDSchedulerNode *pNode) { - VDCriticalSection::AutoLock lock(csScheduler); - - RescheduleFast(pNode); -} - -void VDScheduler::RescheduleFast(VDSchedulerNode *pNode) { - if (pNode->bReady) - return; - - pNode->bReady = true; - - if (pNode->bRunning) - pNode->bReschedule = true; - else { - if (pWakeupSignal) - pWakeupSignal->signal(); - - if (pParentSchedulerNode) - pParentSchedulerNode->Reschedule(); - - listWaiting.erase(pNode); - listReady.push_back(pNode); - } -} - -void VDScheduler::Add(VDSchedulerNode *pNode) { - VDASSERT(pNode); - - pNode->mpScheduler = this; - pNode->bRunning = false; - pNode->bReschedule = false; - pNode->bReady = true; - pNode->bCondemned = false; - - vdsynchronized(csScheduler) { - tNodeList::iterator it(listReady.begin()), itEnd(listReady.end()); - - while(it != itEnd && (*it)->nPriority <= pNode->nPriority) - ++it; - - listReady.insert(it, pNode); - } - - if (pWakeupSignal) - pWakeupSignal->signal(); - - if (pParentSchedulerNode) - pParentSchedulerNode->Reschedule(); -} - -void VDScheduler::Remove(VDSchedulerNode *pNode) { - VDASSERT(pNode); - - VDSchedulerSuspendNode suspendNode(pNode); - bool running = false; - - vdsynchronized(csScheduler) { - pNode->bCondemned = true; - if (pNode->bRunning) { - running = true; - listSuspends.push_back(&suspendNode); - } else if (pNode->bReady) - listReady.erase(pNode); - else - listWaiting.erase(pNode); - } - - if (running) - suspendNode.mSignal.wait(); -} - -void VDScheduler::DumpStatus() { - vdsynchronized(csScheduler) { - VDDEBUG2("\n Waiting nodes:\n"); - for(tNodeList::iterator it(listWaiting.begin()), itEnd(listWaiting.end()); it!=itEnd; ++it) - (*it)->DumpStatus(); - VDDEBUG2("\n Ready nodes:\n"); - for(tNodeList::iterator it2(listReady.begin()), it2End(listReady.end()); it2!=it2End; ++it2) - (*it2)->DumpStatus(); - } -} - -void VDSchedulerNode::DumpStatus() { - VDDEBUG2(" anonymous %p\n", this); -} - -/////////////////////////////////////////////////////////////////////////// - -VDSchedulerThread::VDSchedulerThread() - : VDThread("Scheduler thread") - , mpScheduler(NULL) -{ -} - -VDSchedulerThread::~VDSchedulerThread() { -} - -bool VDSchedulerThread::Start(VDScheduler *pScheduler) { - mpScheduler = pScheduler; - return VDThread::ThreadStart(); -} - -void VDSchedulerThread::ThreadRun() { - VDScheduler& scheduler = *mpScheduler; - - do { - while(scheduler.Run()) - ; - } while(scheduler.IdleWait()); - - scheduler.Ping(); -} - -/////////////////////////////////////////////////////////////////////////// - -VDSchedulerThreadPool::VDSchedulerThreadPool() - : mpThreads(NULL) - , mThreadCount(0) - , mThreadPriority(VDThread::kPriorityDefault) -{ -} - -VDSchedulerThreadPool::~VDSchedulerThreadPool() { - if (mpThreads) { - for(uint32 i=0; i +#include +#include +#include +#include + +VDScheduler::VDScheduler() + : mpErrorCB(NULL) + , pWakeupSignal(NULL) + , pParentSchedulerNode(NULL) + , mbExitThreads(false) +{ +} + +VDScheduler::~VDScheduler() { +} + +void VDScheduler::setSignal(VDSignal *pSignal) { + pWakeupSignal = pSignal; +} + +void VDScheduler::setSchedulerNode(VDSchedulerNode *pSchedulerNode) { + pParentSchedulerNode = pSchedulerNode; +} + +void VDScheduler::BeginShutdown() { + mbExitThreads = true; + Ping(); +} + +void VDScheduler::Repost(VDSchedulerNode *pNode, bool bReschedule) { + vdsynchronized(csScheduler) { + if (pNode->bCondemned) { + tSuspendList::iterator it(listSuspends.begin()), itEnd(listSuspends.end()); + + while(it!=itEnd) { + VDSchedulerSuspendNode *pSuspendNode = *it; + + if (pSuspendNode->mpNode == pNode) { + it = listSuspends.erase(it); + pSuspendNode->mSignal.signal(); + } else + ++it; + } + } else { + pNode->bRunning = false; + if (bReschedule || pNode->bReschedule) { + pNode->bReschedule = false; + pNode->bReady = true; + listReady.push_back(pNode); + } else + listWaiting.push_back(pNode); + } + } +} + +bool VDScheduler::Run() { + VDSchedulerNode *pNode = NULL; + vdsynchronized(csScheduler) { + if (!listReady.empty()) { + pNode = listReady.front(); + listReady.pop_front(); + pNode->bRunning = true; + pNode->bReady = false; + } + } + + if (!pNode) + return false; + + bool bReschedule; + try { + bReschedule = pNode->Service(); + } catch(MyError& e) { + Repost(pNode, false); + + vdsynchronized(csScheduler) { + if (mpErrorCB) { + if (!mpErrorCB->OnAsyncError(e)) + throw; + } + } + + return true; + } catch(...) { + Repost(pNode, false); + throw; + } + + Repost(pNode, bReschedule); + + return true; +} + +bool VDScheduler::IdleWait() { + if (mbExitThreads) + return false; + + if (pWakeupSignal) { +#if 0 + while(WAIT_TIMEOUT == WaitForSingleObject(pWakeupSignal->getHandle(), 1000)) + DumpStatus(); +#else + pWakeupSignal->wait(); +#endif + } + + return true; +} + +void VDScheduler::Ping() { + if (pWakeupSignal) + pWakeupSignal->signal(); +} + +void VDScheduler::Lock() { + ++csScheduler; +} + +void VDScheduler::Unlock() { + --csScheduler; +} + +void VDScheduler::Reschedule(VDSchedulerNode *pNode) { + VDCriticalSection::AutoLock lock(csScheduler); + + RescheduleFast(pNode); +} + +void VDScheduler::RescheduleFast(VDSchedulerNode *pNode) { + if (pNode->bReady) + return; + + pNode->bReady = true; + + if (pNode->bRunning) + pNode->bReschedule = true; + else { + if (pWakeupSignal) + pWakeupSignal->signal(); + + if (pParentSchedulerNode) + pParentSchedulerNode->Reschedule(); + + listWaiting.erase(pNode); + listReady.push_back(pNode); + } +} + +void VDScheduler::Add(VDSchedulerNode *pNode) { + VDASSERT(pNode); + + pNode->mpScheduler = this; + pNode->bRunning = false; + pNode->bReschedule = false; + pNode->bReady = true; + pNode->bCondemned = false; + + vdsynchronized(csScheduler) { + tNodeList::iterator it(listReady.begin()), itEnd(listReady.end()); + + while(it != itEnd && (*it)->nPriority <= pNode->nPriority) + ++it; + + listReady.insert(it, pNode); + } + + if (pWakeupSignal) + pWakeupSignal->signal(); + + if (pParentSchedulerNode) + pParentSchedulerNode->Reschedule(); +} + +void VDScheduler::Remove(VDSchedulerNode *pNode) { + VDASSERT(pNode); + + VDSchedulerSuspendNode suspendNode(pNode); + bool running = false; + + vdsynchronized(csScheduler) { + pNode->bCondemned = true; + if (pNode->bRunning) { + running = true; + listSuspends.push_back(&suspendNode); + } else if (pNode->bReady) + listReady.erase(pNode); + else + listWaiting.erase(pNode); + } + + if (running) + suspendNode.mSignal.wait(); +} + +void VDScheduler::DumpStatus() { + vdsynchronized(csScheduler) { + VDDEBUG2("\n Waiting nodes:\n"); + for(tNodeList::iterator it(listWaiting.begin()), itEnd(listWaiting.end()); it!=itEnd; ++it) + (*it)->DumpStatus(); + VDDEBUG2("\n Ready nodes:\n"); + for(tNodeList::iterator it2(listReady.begin()), it2End(listReady.end()); it2!=it2End; ++it2) + (*it2)->DumpStatus(); + } +} + +void VDSchedulerNode::DumpStatus() { + VDDEBUG2(" anonymous %p\n", this); +} + +/////////////////////////////////////////////////////////////////////////// + +VDSchedulerThread::VDSchedulerThread() + : VDThread("Scheduler thread") + , mpScheduler(NULL) +{ +} + +VDSchedulerThread::~VDSchedulerThread() { +} + +bool VDSchedulerThread::Start(VDScheduler *pScheduler) { + mpScheduler = pScheduler; + return VDThread::ThreadStart(); +} + +void VDSchedulerThread::ThreadRun() { + VDScheduler& scheduler = *mpScheduler; + + do { + while(scheduler.Run()) + ; + } while(scheduler.IdleWait()); + + scheduler.Ping(); +} + +/////////////////////////////////////////////////////////////////////////// + +VDSchedulerThreadPool::VDSchedulerThreadPool() + : mpThreads(NULL) + , mThreadCount(0) + , mThreadPriority(VDThread::kPriorityDefault) +{ +} + +VDSchedulerThreadPool::~VDSchedulerThreadPool() { + if (mpThreads) { + for(uint32 i=0; i -#include -#include - -const VDStringSpanA::value_type VDStringSpanA::sNull[1] = {0}; - -void VDStringA::push_back_extend() { - VDASSERT(mpEOS == mpEnd); - size_type current_size = (size_type)(mpEnd - mpBegin); - - reserve_slow(current_size * 2 + 1, current_size); -} - -void VDStringA::resize_slow(size_type n, size_type current_size) { - resize_slow(n, current_size, 0); -} - -void VDStringA::resize_slow(size_type n, size_type current_size, value_type c) { - VDASSERT(n > current_size); - - size_type current_capacity = (size_type)(mpEOS - mpBegin); - if (n > current_capacity) - reserve_slow(n, current_capacity); - - memset(mpBegin + current_size, c, n - current_size); - mpEnd = mpBegin + n; - *mpEnd = 0; -} - -void VDStringA::reserve_slow(size_type n, size_type current_capacity) { - VDASSERT(n > current_capacity); - - size_type current_size = (size_type)(mpEnd - mpBegin); - value_type *s = new value_type[n + 1]; - memcpy(s, mpBegin, (current_size + 1) * sizeof(value_type)); - if (mpBegin != sNull) - delete[] mpBegin; - - mpBegin = s; - mpEnd = s + current_size; - mpEOS = s + n; -} - -void VDStringA::reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity) { - n += current_size; - - size_type doublesize = current_size * 2; - if (n < doublesize) - n = doublesize; - - reserve_slow(n, current_capacity); -} - -VDStringA& VDStringA::sprintf(const value_type *format, ...) { - clear(); - va_list val; - va_start(val, format); - append_vsprintf(format, val); - va_end(val); - return *this; -} - -VDStringA& VDStringA::append_sprintf(const value_type *format, ...) { - va_list val; - va_start(val, format); - append_vsprintf(format, val); - va_end(val); - return *this; -} - -VDStringA& VDStringA::append_vsprintf(const value_type *format, va_list val) { - char buf[2048]; - - int len = vdvsnprintf(buf, 2048, format, val); - if (len >= 0) - append(buf, buf+len); - else { - int len; - - vdfastvector tmp; - for(int siz = 8192; siz <= 65536; siz += siz) { - tmp.resize(siz); - - char *tmpp = tmp.data(); - len = vdvsnprintf(tmp.data(), siz, format, val); - if (len >= 0) { - append(tmpp, tmpp+len); - break; - } - } - } - - return *this; -} - -void VDStringA::move_from(VDStringA& src) { - if (mpBegin != sNull) - delete[] mpBegin; - - mpBegin = src.mpBegin; - mpEnd = src.mpEnd; - mpEOS = src.mpEOS; - - src.mpBegin = NULL; - src.mpEnd = NULL; - src.mpEOS = NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -const VDStringSpanW::value_type VDStringSpanW::sNull[1] = {0}; - -void VDStringW::push_back_extend() { - VDASSERT(mpEOS == mpEnd); - size_type current_size = (size_type)(mpEnd - mpBegin); - - reserve_slow(current_size * 2 + 1, current_size); -} - -void VDStringW::resize_slow(size_type n, size_type current_size) { - VDASSERT(n > current_size); - - size_type current_capacity = (size_type)(mpEOS - mpBegin); - if (n > current_capacity) - reserve_slow(n, current_capacity); - - mpEnd = mpBegin + n; - *mpEnd = 0; -} - -void VDStringW::reserve_slow(size_type n, size_type current_capacity) { - VDASSERT(current_capacity == (size_type)(mpEOS - mpBegin)); - VDASSERT(n > current_capacity); - - size_type current_size = (size_type)(mpEnd - mpBegin); - value_type *s = new value_type[n + 1]; - memcpy(s, mpBegin, (current_size + 1) * sizeof(value_type)); - if (mpBegin != sNull) - delete[] mpBegin; - - mpBegin = s; - mpEnd = s + current_size; - mpEOS = s + n; -} - -void VDStringW::reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity) { - n += current_size; - - size_type doublesize = current_size * 2; - if (n < doublesize) - n = doublesize; - - reserve_slow(n, current_capacity); -} - -VDStringW& VDStringW::sprintf(const value_type *format, ...) { - clear(); - va_list val; - va_start(val, format); - append_vsprintf(format, val); - va_end(val); - return *this; -} - -VDStringW& VDStringW::append_sprintf(const value_type *format, ...) { - va_list val; - va_start(val, format); - append_vsprintf(format, val); - va_end(val); - return *this; -} - -VDStringW& VDStringW::append_vsprintf(const value_type *format, va_list val) { - wchar_t buf[1024]; - - int len = vdvswprintf(buf, 1024, format, val); - if (len >= 0) - append(buf, buf+len); - else { - int len; - - vdfastvector tmp; - for(int siz = 4096; siz <= 65536; siz += siz) { - tmp.resize(siz); - - wchar_t *tmpp = tmp.data(); - len = vdvswprintf(tmpp, siz, format, val); - if (len >= 0) { - append(tmpp, tmpp+len); - break; - } - } - } - - va_end(val); - return *this; -} - -void VDStringW::move_from(VDStringW& src) { - if (mpBegin != sNull) - delete[] mpBegin; - - mpBegin = src.mpBegin; - mpEnd = src.mpEnd; - mpEOS = src.mpEOS; - - src.mpBegin = NULL; - src.mpEnd = NULL; - src.mpEOS = NULL; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -VDStringA *vdmove_forward(VDStringA *src1, VDStringA *src2, VDStringA *dst) { - VDStringA *p = src1; - while(p != src2) { - dst->move_from(*p); - ++dst; - ++p; - } - - return dst; -} - -template<> -VDStringW *vdmove_forward(VDStringW *src1, VDStringW *src2, VDStringW *dst) { - VDStringW *p = src1; - while(p != src2) { - dst->move_from(*p); - ++dst; - ++p; - } - - return dst; -} - -template<> -VDStringA *vdmove_backward(VDStringA *src1, VDStringA *src2, VDStringA *dst) { - VDStringA *p = src2; - while(p != src1) { - --dst; - --p; - dst->move_from(*p); - } - - return dst; -} - -template<> -VDStringW *vdmove_backward(VDStringW *src1, VDStringW *src2, VDStringW *dst) { - VDStringW *p = src2; - while(p != src1) { - --dst; - --p; - dst->move_from(*p); - } - - return dst; -} - -template<> -void vdmove(VDStringA& dst, VDStringA& src) { - dst.move_from(src); -} - -template<> -void vdmove(VDStringW& dst, VDStringW& src) { - dst.move_from(src); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include + +const VDStringSpanA::value_type VDStringSpanA::sNull[1] = {0}; + +void VDStringA::push_back_extend() { + VDASSERT(mpEOS == mpEnd); + size_type current_size = (size_type)(mpEnd - mpBegin); + + reserve_slow(current_size * 2 + 1, current_size); +} + +void VDStringA::resize_slow(size_type n, size_type current_size) { + resize_slow(n, current_size, 0); +} + +void VDStringA::resize_slow(size_type n, size_type current_size, value_type c) { + VDASSERT(n > current_size); + + size_type current_capacity = (size_type)(mpEOS - mpBegin); + if (n > current_capacity) + reserve_slow(n, current_capacity); + + memset(mpBegin + current_size, c, n - current_size); + mpEnd = mpBegin + n; + *mpEnd = 0; +} + +void VDStringA::reserve_slow(size_type n, size_type current_capacity) { + VDASSERT(n > current_capacity); + + size_type current_size = (size_type)(mpEnd - mpBegin); + value_type *s = new value_type[n + 1]; + memcpy(s, mpBegin, (current_size + 1) * sizeof(value_type)); + if (mpBegin != sNull) + delete[] mpBegin; + + mpBegin = s; + mpEnd = s + current_size; + mpEOS = s + n; +} + +void VDStringA::reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity) { + n += current_size; + + size_type doublesize = current_size * 2; + if (n < doublesize) + n = doublesize; + + reserve_slow(n, current_capacity); +} + +VDStringA& VDStringA::sprintf(const value_type *format, ...) { + clear(); + va_list val; + va_start(val, format); + append_vsprintf(format, val); + va_end(val); + return *this; +} + +VDStringA& VDStringA::append_sprintf(const value_type *format, ...) { + va_list val; + va_start(val, format); + append_vsprintf(format, val); + va_end(val); + return *this; +} + +VDStringA& VDStringA::append_vsprintf(const value_type *format, va_list val) { + char buf[2048]; + + int len = vdvsnprintf(buf, 2048, format, val); + if (len >= 0) + append(buf, buf+len); + else { + int len; + + vdfastvector tmp; + for(int siz = 8192; siz <= 65536; siz += siz) { + tmp.resize(siz); + + char *tmpp = tmp.data(); + len = vdvsnprintf(tmp.data(), siz, format, val); + if (len >= 0) { + append(tmpp, tmpp+len); + break; + } + } + } + + return *this; +} + +void VDStringA::move_from(VDStringA& src) { + if (mpBegin != sNull) + delete[] mpBegin; + + mpBegin = src.mpBegin; + mpEnd = src.mpEnd; + mpEOS = src.mpEOS; + + src.mpBegin = NULL; + src.mpEnd = NULL; + src.mpEOS = NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +const VDStringSpanW::value_type VDStringSpanW::sNull[1] = {0}; + +void VDStringW::push_back_extend() { + VDASSERT(mpEOS == mpEnd); + size_type current_size = (size_type)(mpEnd - mpBegin); + + reserve_slow(current_size * 2 + 1, current_size); +} + +void VDStringW::resize_slow(size_type n, size_type current_size) { + VDASSERT(n > current_size); + + size_type current_capacity = (size_type)(mpEOS - mpBegin); + if (n > current_capacity) + reserve_slow(n, current_capacity); + + mpEnd = mpBegin + n; + *mpEnd = 0; +} + +void VDStringW::reserve_slow(size_type n, size_type current_capacity) { + VDASSERT(current_capacity == (size_type)(mpEOS - mpBegin)); + VDASSERT(n > current_capacity); + + size_type current_size = (size_type)(mpEnd - mpBegin); + value_type *s = new value_type[n + 1]; + memcpy(s, mpBegin, (current_size + 1) * sizeof(value_type)); + if (mpBegin != sNull) + delete[] mpBegin; + + mpBegin = s; + mpEnd = s + current_size; + mpEOS = s + n; +} + +void VDStringW::reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity) { + n += current_size; + + size_type doublesize = current_size * 2; + if (n < doublesize) + n = doublesize; + + reserve_slow(n, current_capacity); +} + +VDStringW& VDStringW::sprintf(const value_type *format, ...) { + clear(); + va_list val; + va_start(val, format); + append_vsprintf(format, val); + va_end(val); + return *this; +} + +VDStringW& VDStringW::append_sprintf(const value_type *format, ...) { + va_list val; + va_start(val, format); + append_vsprintf(format, val); + va_end(val); + return *this; +} + +VDStringW& VDStringW::append_vsprintf(const value_type *format, va_list val) { + wchar_t buf[1024]; + + int len = vdvswprintf(buf, 1024, format, val); + if (len >= 0) + append(buf, buf+len); + else { + int len; + + vdfastvector tmp; + for(int siz = 4096; siz <= 65536; siz += siz) { + tmp.resize(siz); + + wchar_t *tmpp = tmp.data(); + len = vdvswprintf(tmpp, siz, format, val); + if (len >= 0) { + append(tmpp, tmpp+len); + break; + } + } + } + + va_end(val); + return *this; +} + +void VDStringW::move_from(VDStringW& src) { + if (mpBegin != sNull) + delete[] mpBegin; + + mpBegin = src.mpBegin; + mpEnd = src.mpEnd; + mpEOS = src.mpEOS; + + src.mpBegin = NULL; + src.mpEnd = NULL; + src.mpEOS = NULL; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template<> +VDStringA *vdmove_forward(VDStringA *src1, VDStringA *src2, VDStringA *dst) { + VDStringA *p = src1; + while(p != src2) { + dst->move_from(*p); + ++dst; + ++p; + } + + return dst; +} + +template<> +VDStringW *vdmove_forward(VDStringW *src1, VDStringW *src2, VDStringW *dst) { + VDStringW *p = src1; + while(p != src2) { + dst->move_from(*p); + ++dst; + ++p; + } + + return dst; +} + +template<> +VDStringA *vdmove_backward(VDStringA *src1, VDStringA *src2, VDStringA *dst) { + VDStringA *p = src2; + while(p != src1) { + --dst; + --p; + dst->move_from(*p); + } + + return dst; +} + +template<> +VDStringW *vdmove_backward(VDStringW *src1, VDStringW *src2, VDStringW *dst) { + VDStringW *p = src2; + while(p != src1) { + --dst; + --p; + dst->move_from(*p); + } + + return dst; +} + +template<> +void vdmove(VDStringA& dst, VDStringA& src) { + dst.move_from(src); +} + +template<> +void vdmove(VDStringW& dst, VDStringW& src) { + dst.move_from(src); +} diff --git a/src/thirdparty/VirtualDub/system/source/a64_cpuaccel.asm b/src/thirdparty/VirtualDub/system/source/a64_cpuaccel.asm index 278754c4edc..248a6918911 100644 --- a/src/thirdparty/VirtualDub/system/source/a64_cpuaccel.asm +++ b/src/thirdparty/VirtualDub/system/source/a64_cpuaccel.asm @@ -1,42 +1,42 @@ -; VirtualDub - Video processing and capture application -; System library component -; Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -; -; Beginning with 1.6.0, the VirtualDub system library is licensed -; differently than the remainder of VirtualDub. This particular file is -; thus licensed as follows (the "zlib" license): -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any purpose, -; including commercial applications, and to alter it and redistribute it -; freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you must -; not claim that you wrote the original software. If you use this -; software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; 2. Altered source versions must be plainly marked as such, and must -; not be misrepresented as being the original software. -; 3. This notice may not be removed or altered from any source -; distribution. - - segment .text - -;-------------------------------------------------------------------------- - global VDIsAVXSupportedByOS -VDIsAVXSupportedByOS: - xor ecx, ecx - xgetbv - and al, 6 - cmp al, 6 - jnz .notsupported - mov eax, 1 - ret -.notsupported: - xor eax, eax - ret - - end +; VirtualDub - Video processing and capture application +; System library component +; Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +; +; Beginning with 1.6.0, the VirtualDub system library is licensed +; differently than the remainder of VirtualDub. This particular file is +; thus licensed as follows (the "zlib" license): +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must +; not claim that you wrote the original software. If you use this +; software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must +; not be misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source +; distribution. + + segment .text + +;-------------------------------------------------------------------------- + global VDIsAVXSupportedByOS +VDIsAVXSupportedByOS: + xor ecx, ecx + xgetbv + and al, 6 + cmp al, 6 + jnz .notsupported + mov eax, 1 + ret +.notsupported: + xor eax, eax + ret + + end diff --git a/src/thirdparty/VirtualDub/system/source/a64_fraction.asm b/src/thirdparty/VirtualDub/system/source/a64_fraction.asm index 43b0baddfd4..39f6666f261 100644 --- a/src/thirdparty/VirtualDub/system/source/a64_fraction.asm +++ b/src/thirdparty/VirtualDub/system/source/a64_fraction.asm @@ -1,58 +1,58 @@ -; VirtualDub - Video processing and capture application -; System library component -; Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -; -; Beginning with 1.6.0, the VirtualDub system library is licensed -; differently than the remainder of VirtualDub. This particular file is -; thus licensed as follows (the "zlib" license): -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any purpose, -; including commercial applications, and to alter it and redistribute it -; freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you must -; not claim that you wrote the original software. If you use this -; software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; 2. Altered source versions must be plainly marked as such, and must -; not be misrepresented as being the original software. -; 3. This notice may not be removed or altered from any source -; distribution. - - segment .text - -;-------------------------------------------------------------------------- -; VDFractionScale64( -; [rcx] uint64 a, -; [rdx] uint64 b, -; [r8] uint64 c, -; [r9] uint32& remainder); -; -; - global VDFractionScale64 -VDFractionScale64: - mov rax, rcx - mul rdx - div r8 - mov [r9], edx - ret - -;-------------------------------------------------------------------------- -; VDUMulDiv64x32( -; [rcx] uint64 a, -; [rdx] uint64 b, -; [r8] uint64 c); -; -; - global VDUMulDiv64x32 -VDUMulDiv64x32: - mov rax, rcx - mul rdx - div r8 - ret - - end +; VirtualDub - Video processing and capture application +; System library component +; Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +; +; Beginning with 1.6.0, the VirtualDub system library is licensed +; differently than the remainder of VirtualDub. This particular file is +; thus licensed as follows (the "zlib" license): +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must +; not claim that you wrote the original software. If you use this +; software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must +; not be misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source +; distribution. + + segment .text + +;-------------------------------------------------------------------------- +; VDFractionScale64( +; [rcx] uint64 a, +; [rdx] uint64 b, +; [r8] uint64 c, +; [r9] uint32& remainder); +; +; + global VDFractionScale64 +VDFractionScale64: + mov rax, rcx + mul rdx + div r8 + mov [r9], edx + ret + +;-------------------------------------------------------------------------- +; VDUMulDiv64x32( +; [rcx] uint64 a, +; [rdx] uint64 b, +; [r8] uint64 c); +; +; + global VDUMulDiv64x32 +VDUMulDiv64x32: + mov rax, rcx + mul rdx + div r8 + ret + + end diff --git a/src/thirdparty/VirtualDub/system/source/a64_int128.asm b/src/thirdparty/VirtualDub/system/source/a64_int128.asm index 706e298f629..99cfb8d8749 100644 --- a/src/thirdparty/VirtualDub/system/source/a64_int128.asm +++ b/src/thirdparty/VirtualDub/system/source/a64_int128.asm @@ -1,73 +1,73 @@ -; VirtualDub - Video processing and capture application -; System library component -; Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -; -; Beginning with 1.6.0, the VirtualDub system library is licensed -; differently than the remainder of VirtualDub. This particular file is -; thus licensed as follows (the "zlib" license): -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any purpose, -; including commercial applications, and to alter it and redistribute it -; freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you must -; not claim that you wrote the original software. If you use this -; software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; 2. Altered source versions must be plainly marked as such, and must -; not be misrepresented as being the original software. -; 3. This notice may not be removed or altered from any source -; distribution. - - segment .text - - global vdasm_uint128_add -vdasm_uint128_add: - mov rax, [rdx] - add rax, [r8] - mov [rcx], rax - mov rax, [rdx+8] - adc rax, [r8+8] - mov [rcx+8], rax - ret - - global vdasm_uint128_sub -vdasm_uint128_sub: - mov rax, [rdx] - sub rax, [r8] - mov [rcx], rax - mov rax, [rdx+8] - sbb rax, [r8+8] - mov [rcx+8], rax - ret - -proc_frame vdasm_uint128_mul - mov [esp+8], rbx - [savereg rbx, 8] - mov [esp+16], rsi - [savereg rsi, 16] -end_prolog - - mov rbx, rdx ;rbx = src1 - mov rax, [rdx] ;rax = src1a - mov rsi, [r8] ;rsi = src2a - mul rsi ;rdx:rax = src1a*src2a - mov [rcx], rax ;write low result - mov r9, rdx ;r9 = (src1a*src2a).hi - mov rax, [rbx+8] ;rax = src1b - mul rsi ;rdx:rax = src1b*src2a - add r9, rax ;r9 = (src1a*src2a).hi + (src1b*src2a).lo - mov rax, [rbx] ;rax = src1a - mul qword [r8+8] ;rdx:rax = src1a*src2b - add rax, r9 ;rax = (src1a*src2b).lo + (src1b*src2a).lo + (src1a*src2a).hi - mov [rcx+8], rax ;write high result - mov rsi, [esp+16] - mov rbx, [esp+8] - ret -endproc_frame - - end +; VirtualDub - Video processing and capture application +; System library component +; Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +; +; Beginning with 1.6.0, the VirtualDub system library is licensed +; differently than the remainder of VirtualDub. This particular file is +; thus licensed as follows (the "zlib" license): +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must +; not claim that you wrote the original software. If you use this +; software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must +; not be misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source +; distribution. + + segment .text + + global vdasm_uint128_add +vdasm_uint128_add: + mov rax, [rdx] + add rax, [r8] + mov [rcx], rax + mov rax, [rdx+8] + adc rax, [r8+8] + mov [rcx+8], rax + ret + + global vdasm_uint128_sub +vdasm_uint128_sub: + mov rax, [rdx] + sub rax, [r8] + mov [rcx], rax + mov rax, [rdx+8] + sbb rax, [r8+8] + mov [rcx+8], rax + ret + +proc_frame vdasm_uint128_mul + mov [esp+8], rbx + [savereg rbx, 8] + mov [esp+16], rsi + [savereg rsi, 16] +end_prolog + + mov rbx, rdx ;rbx = src1 + mov rax, [rdx] ;rax = src1a + mov rsi, [r8] ;rsi = src2a + mul rsi ;rdx:rax = src1a*src2a + mov [rcx], rax ;write low result + mov r9, rdx ;r9 = (src1a*src2a).hi + mov rax, [rbx+8] ;rax = src1b + mul rsi ;rdx:rax = src1b*src2a + add r9, rax ;r9 = (src1a*src2a).hi + (src1b*src2a).lo + mov rax, [rbx] ;rax = src1a + mul qword [r8+8] ;rdx:rax = src1a*src2b + add rax, r9 ;rax = (src1a*src2b).lo + (src1b*src2a).lo + (src1a*src2a).hi + mov [rcx+8], rax ;write high result + mov rsi, [esp+16] + mov rbx, [esp+8] + ret +endproc_frame + + end diff --git a/src/thirdparty/VirtualDub/system/source/a64_thunk.asm b/src/thirdparty/VirtualDub/system/source/a64_thunk.asm index 72745606dda..fdf1986bfcd 100644 --- a/src/thirdparty/VirtualDub/system/source/a64_thunk.asm +++ b/src/thirdparty/VirtualDub/system/source/a64_thunk.asm @@ -1,58 +1,58 @@ - segment .text - - global VDMethodToFunctionThunk64 -proc_frame VDMethodToFunctionThunk64 - ;prolog - db 48h ;emit REX prefix -- first instruction must be two bytes for hot patching - push rbp - [pushreg rbp] - - mov rbp, rsp ;create stack pointer - [setframe rbp, 0] - - mov [rbp+16], rcx ;save arg1 - [savereg rcx, 0] - - mov [rbp+24], rdx ;save arg2 - [savereg rcx, 8] - - mov [rbp+32], r8 ;save arg3 - [savereg rcx, 16] - - mov [rbp+40], r9 ;save arg4 - [savereg rcx, 24] - - [endprolog] - - ;re-copy arguments 4 and up - mov ecx, [rax+24] - or ecx, ecx - jz .argsdone - lea rdx, [rcx+32] -.argsloop: - push qword [rsp+rdx] - sub ecx, 8 - jnz .argsloop -.argsdone: - - ;load 'this' pointer - mov rcx, [rax+16] - - ;reload arguments 1-3 - mov rdx, [rbp+16] - mov r8, [rbp+24] - mov r9, [rbp+32] - - ;reserve argument 1-4 space on stack - sub rsp, 32 - - ;call function - call qword [rax+8] - - ;epilog - lea rsp, [rbp] ;pop off stack frame and any additional arg space - pop rbp ;restore base pointer - ret ;all done -endproc_frame - - end + segment .text + + global VDMethodToFunctionThunk64 +proc_frame VDMethodToFunctionThunk64 + ;prolog + db 48h ;emit REX prefix -- first instruction must be two bytes for hot patching + push rbp + [pushreg rbp] + + mov rbp, rsp ;create stack pointer + [setframe rbp, 0] + + mov [rbp+16], rcx ;save arg1 + [savereg rcx, 0] + + mov [rbp+24], rdx ;save arg2 + [savereg rcx, 8] + + mov [rbp+32], r8 ;save arg3 + [savereg rcx, 16] + + mov [rbp+40], r9 ;save arg4 + [savereg rcx, 24] + + [endprolog] + + ;re-copy arguments 4 and up + mov ecx, [rax+24] + or ecx, ecx + jz .argsdone + lea rdx, [rcx+32] +.argsloop: + push qword [rsp+rdx] + sub ecx, 8 + jnz .argsloop +.argsdone: + + ;load 'this' pointer + mov rcx, [rax+16] + + ;reload arguments 1-3 + mov rdx, [rbp+16] + mov r8, [rbp+24] + mov r9, [rbp+32] + + ;reserve argument 1-4 space on stack + sub rsp, 32 + + ;call function + call qword [rax+8] + + ;epilog + lea rsp, [rbp] ;pop off stack frame and any additional arg space + pop rbp ;restore base pointer + ret ;all done +endproc_frame + + end diff --git a/src/thirdparty/VirtualDub/system/source/a_memory.asm b/src/thirdparty/VirtualDub/system/source/a_memory.asm index 226be080143..54844bce18d 100644 --- a/src/thirdparty/VirtualDub/system/source/a_memory.asm +++ b/src/thirdparty/VirtualDub/system/source/a_memory.asm @@ -1,197 +1,197 @@ -; VirtualDub - Video processing and capture application -; System library component -; Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -; -; Beginning with 1.6.0, the VirtualDub system library is licensed -; differently than the remainder of VirtualDub. This particular file is -; thus licensed as follows (the "zlib" license): -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any purpose, -; including commercial applications, and to alter it and redistribute it -; freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you must -; not claim that you wrote the original software. If you use this -; software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; 2. Altered source versions must be plainly marked as such, and must -; not be misrepresented as being the original software. -; 3. This notice may not be removed or altered from any source -; distribution. - - segment .text - - global _VDFastMemcpyPartialScalarAligned8 -_VDFastMemcpyPartialScalarAligned8: - mov eax, [esp+12] - mov edx, [esp+4] - mov ecx, [esp+8] - add ecx, eax - add edx, eax - neg eax - jz .nobytes - add eax, 8 - jz .doodd - jmp short .xloop - align 16 -.xloop: - fild qword [ecx+eax-8] - fild qword [ecx+eax] - fxch - fistp qword [edx+eax-8] - fistp qword [edx+eax] - add eax,16 - jnc .xloop - jnz .nobytes -.doodd: - fild qword [ecx-8] - fistp qword [edx-8] -.nobytes: - ret - - global _VDFastMemcpyPartialMMX -_VDFastMemcpyPartialMMX: - push edi - push esi - - mov edi, [esp+4+8] - mov esi, [esp+8+8] - mov ecx, [esp+12+8] - mov edx, ecx - shr ecx, 2 - and edx, 3 - rep movsd - mov ecx, edx - rep movsb - pop esi - pop edi - ret - -; MPC custom code start - global _VDFastMemcpyPartialSSE2 -_VDFastMemcpyPartialSSE2: - push ebp - push edi - push esi - push ebx - - mov ecx, [esp+12+16] - cmp ecx, 128 - jb _VDFastMemcpyPartialMMX2.MMX2 - mov edi, [esp+4+16] - mov esi, [esp+8+16] - mov eax, edi - or eax, esi - test al, 15 - jne SHORT _VDFastMemcpyPartialMMX2.MMX2 - - shr ecx, 7 -.loop128: - prefetchnta [esi+16*8] - movaps xmm0, [esi] - movaps xmm1, [esi+16*1] - movaps xmm2, [esi+16*2] - movaps xmm3, [esi+16*3] - movaps xmm4, [esi+16*4] - movaps xmm5, [esi+16*5] - movaps xmm6, [esi+16*6] - movaps xmm7, [esi+16*7] - movntps [edi], xmm0 - movntps [edi+16*1], xmm1 - movntps [edi+16*2], xmm2 - movntps [edi+16*3], xmm3 - movntps [edi+16*4], xmm4 - movntps [edi+16*5], xmm5 - movntps [edi+16*6], xmm6 - movntps [edi+16*7], xmm7 - add esi, 128 - add edi, 128 - dec ecx - jne .loop128 -.skiploop128: - mov ecx, [esp+12+16] - and ecx, 127 - cmp ecx, 0 - je .nooddballs -.loop: - mov dl, [esi] - mov [edi], dl - inc esi - inc edi - dec ecx - jne .loop -.nooddballs: - pop ebx - pop esi - pop edi - pop ebp - ret -; MPC custom code end - - global _VDFastMemcpyPartialMMX2 -_VDFastMemcpyPartialMMX2: - push ebp - push edi - push esi - push ebx - -.MMX2 ; MPC custom code - mov ebx, [esp+4+16] - mov edx, [esp+8+16] - mov eax, [esp+12+16] - neg eax - add eax, 63 - jbe .skipblastloop -.blastloop: - movq mm0, [edx] - movq mm1, [edx+8] - movq mm2, [edx+16] - movq mm3, [edx+24] - movq mm4, [edx+32] - movq mm5, [edx+40] - movq mm6, [edx+48] - movq mm7, [edx+56] - movntq [ebx], mm0 - movntq [ebx+8], mm1 - movntq [ebx+16], mm2 - movntq [ebx+24], mm3 - movntq [ebx+32], mm4 - movntq [ebx+40], mm5 - movntq [ebx+48], mm6 - movntq [ebx+56], mm7 - add ebx, 64 - add edx, 64 - add eax, 64 - jnc .blastloop -.skipblastloop: - sub eax, 63-7 - jns .noextras -.quadloop: - movq mm0, [edx] - movntq [ebx], mm0 - add edx, 8 - add ebx, 8 - add eax, 8 - jnc .quadloop -.noextras: - sub eax, 7 - jz .nooddballs - mov ecx, eax - neg ecx - mov esi, edx - mov edi, ebx - rep movsb -.nooddballs: - pop ebx - pop esi - pop edi - pop ebp - ret - - - end - +; VirtualDub - Video processing and capture application +; System library component +; Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +; +; Beginning with 1.6.0, the VirtualDub system library is licensed +; differently than the remainder of VirtualDub. This particular file is +; thus licensed as follows (the "zlib" license): +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must +; not claim that you wrote the original software. If you use this +; software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must +; not be misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source +; distribution. + + segment .text + + global _VDFastMemcpyPartialScalarAligned8 +_VDFastMemcpyPartialScalarAligned8: + mov eax, [esp+12] + mov edx, [esp+4] + mov ecx, [esp+8] + add ecx, eax + add edx, eax + neg eax + jz .nobytes + add eax, 8 + jz .doodd + jmp short .xloop + align 16 +.xloop: + fild qword [ecx+eax-8] + fild qword [ecx+eax] + fxch + fistp qword [edx+eax-8] + fistp qword [edx+eax] + add eax,16 + jnc .xloop + jnz .nobytes +.doodd: + fild qword [ecx-8] + fistp qword [edx-8] +.nobytes: + ret + + global _VDFastMemcpyPartialMMX +_VDFastMemcpyPartialMMX: + push edi + push esi + + mov edi, [esp+4+8] + mov esi, [esp+8+8] + mov ecx, [esp+12+8] + mov edx, ecx + shr ecx, 2 + and edx, 3 + rep movsd + mov ecx, edx + rep movsb + pop esi + pop edi + ret + +; MPC custom code start + global _VDFastMemcpyPartialSSE2 +_VDFastMemcpyPartialSSE2: + push ebp + push edi + push esi + push ebx + + mov ecx, [esp+12+16] + cmp ecx, 128 + jb _VDFastMemcpyPartialMMX2.MMX2 + mov edi, [esp+4+16] + mov esi, [esp+8+16] + mov eax, edi + or eax, esi + test al, 15 + jne SHORT _VDFastMemcpyPartialMMX2.MMX2 + + shr ecx, 7 +.loop128: + prefetchnta [esi+16*8] + movaps xmm0, [esi] + movaps xmm1, [esi+16*1] + movaps xmm2, [esi+16*2] + movaps xmm3, [esi+16*3] + movaps xmm4, [esi+16*4] + movaps xmm5, [esi+16*5] + movaps xmm6, [esi+16*6] + movaps xmm7, [esi+16*7] + movntps [edi], xmm0 + movntps [edi+16*1], xmm1 + movntps [edi+16*2], xmm2 + movntps [edi+16*3], xmm3 + movntps [edi+16*4], xmm4 + movntps [edi+16*5], xmm5 + movntps [edi+16*6], xmm6 + movntps [edi+16*7], xmm7 + add esi, 128 + add edi, 128 + dec ecx + jne .loop128 +.skiploop128: + mov ecx, [esp+12+16] + and ecx, 127 + cmp ecx, 0 + je .nooddballs +.loop: + mov dl, [esi] + mov [edi], dl + inc esi + inc edi + dec ecx + jne .loop +.nooddballs: + pop ebx + pop esi + pop edi + pop ebp + ret +; MPC custom code end + + global _VDFastMemcpyPartialMMX2 +_VDFastMemcpyPartialMMX2: + push ebp + push edi + push esi + push ebx + +.MMX2 ; MPC custom code + mov ebx, [esp+4+16] + mov edx, [esp+8+16] + mov eax, [esp+12+16] + neg eax + add eax, 63 + jbe .skipblastloop +.blastloop: + movq mm0, [edx] + movq mm1, [edx+8] + movq mm2, [edx+16] + movq mm3, [edx+24] + movq mm4, [edx+32] + movq mm5, [edx+40] + movq mm6, [edx+48] + movq mm7, [edx+56] + movntq [ebx], mm0 + movntq [ebx+8], mm1 + movntq [ebx+16], mm2 + movntq [ebx+24], mm3 + movntq [ebx+32], mm4 + movntq [ebx+40], mm5 + movntq [ebx+48], mm6 + movntq [ebx+56], mm7 + add ebx, 64 + add edx, 64 + add eax, 64 + jnc .blastloop +.skipblastloop: + sub eax, 63-7 + jns .noextras +.quadloop: + movq mm0, [edx] + movntq [ebx], mm0 + add edx, 8 + add ebx, 8 + add eax, 8 + jnc .quadloop +.noextras: + sub eax, 7 + jz .nooddballs + mov ecx, eax + neg ecx + mov esi, edx + mov edi, ebx + rep movsb +.nooddballs: + pop ebx + pop esi + pop edi + pop ebp + ret + + + end + diff --git a/src/thirdparty/VirtualDub/system/source/a_thunk.asm b/src/thirdparty/VirtualDub/system/source/a_thunk.asm index 5dcdecbbe01..ad2efb7b4c9 100644 --- a/src/thirdparty/VirtualDub/system/source/a_thunk.asm +++ b/src/thirdparty/VirtualDub/system/source/a_thunk.asm @@ -1,63 +1,63 @@ - segment .text - - align 16 - global _VDMethodToFunctionThunk32 -_VDMethodToFunctionThunk32: - pop eax ;get return address in thunk - - ;re-copy arguments - movzx ecx, byte [eax+1] - mov edx, ecx -argsloop: - push dword [esp+edx] - sub ecx, 4 - jnz argsloop - - push eax ;replace thunk return address - - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - align 16 - global _VDMethodToFunctionThunk32_4 -_VDMethodToFunctionThunk32_4: - pop eax ;get return address in thunk - push dword [esp+4] ;replicate 1st argument - push eax ;replace thunk return address - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - align 16 - global _VDMethodToFunctionThunk32_8 -_VDMethodToFunctionThunk32_8: - pop eax ;get return address in thunk - push dword [esp+8] ;replicate 2nd argument - push dword [esp+8] ;replicate 1st argument - push eax ;replace thunk return address - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - align 16 - global _VDMethodToFunctionThunk32_12 -_VDMethodToFunctionThunk32_12: - pop eax ;get return address in thunk - push dword [esp+12] ;replicate 3rd argument - push dword [esp+12] ;replicate 2nd argument - push dword [esp+12] ;replicate 1st argument - push eax ;replace thunk return address - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - align 16 - global _VDMethodToFunctionThunk32_16 -_VDMethodToFunctionThunk32_16: - pop eax ;get return address in thunk - push dword [esp+16] ;replicate 4th argument - push dword [esp+16] ;replicate 3rd argument - push dword [esp+16] ;replicate 2nd argument - push dword [esp+16] ;replicate 1st argument - push eax ;replace thunk return address - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - end + segment .text + + align 16 + global _VDMethodToFunctionThunk32 +_VDMethodToFunctionThunk32: + pop eax ;get return address in thunk + + ;re-copy arguments + movzx ecx, byte [eax+1] + mov edx, ecx +argsloop: + push dword [esp+edx] + sub ecx, 4 + jnz argsloop + + push eax ;replace thunk return address + + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + align 16 + global _VDMethodToFunctionThunk32_4 +_VDMethodToFunctionThunk32_4: + pop eax ;get return address in thunk + push dword [esp+4] ;replicate 1st argument + push eax ;replace thunk return address + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + align 16 + global _VDMethodToFunctionThunk32_8 +_VDMethodToFunctionThunk32_8: + pop eax ;get return address in thunk + push dword [esp+8] ;replicate 2nd argument + push dword [esp+8] ;replicate 1st argument + push eax ;replace thunk return address + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + align 16 + global _VDMethodToFunctionThunk32_12 +_VDMethodToFunctionThunk32_12: + pop eax ;get return address in thunk + push dword [esp+12] ;replicate 3rd argument + push dword [esp+12] ;replicate 2nd argument + push dword [esp+12] ;replicate 1st argument + push eax ;replace thunk return address + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + align 16 + global _VDMethodToFunctionThunk32_16 +_VDMethodToFunctionThunk32_16: + pop eax ;get return address in thunk + push dword [esp+16] ;replicate 4th argument + push dword [esp+16] ;replicate 3rd argument + push dword [esp+16] ;replicate 2nd argument + push dword [esp+16] ;replicate 1st argument + push eax ;replace thunk return address + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + end diff --git a/src/thirdparty/VirtualDub/system/source/cache.cpp b/src/thirdparty/VirtualDub/system/source/cache.cpp index 5da77d089b6..dc2788b104e 100644 --- a/src/thirdparty/VirtualDub/system/source/cache.cpp +++ b/src/thirdparty/VirtualDub/system/source/cache.cpp @@ -1,422 +1,422 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -/////////////////////////////////////////////////////////////////////////// - -VDCache::VDCache(IVDCacheAllocator *pAllocator) - : mpAllocator(pAllocator) - , mObjectCount(0) - , mObjectLimit(16) -{ -} - -VDCache::~VDCache() { - Shutdown(); -} - -void VDCache::Shutdown() { - for(int i=0; i(ol.back()); - ol.pop_back(); - - pObject->OnCacheEvict(); - pObject->SetCache(NULL); // will release object - - if (i != kVDCacheStateFree) { - VDASSERT((int)--mObjectCount >= 0); - } - } - } -} - -int VDCache::GetStateCount(int state) { - vdsynchronized(mLock) { - return mLists[state].size(); - } -} - -void VDCache::DumpListStatus(int state) { - vdsynchronized(mLock) { - ObjectList& ol = mLists[state]; - - for(ObjectList::iterator it(ol.begin()), itEnd(ol.end()); it!=itEnd; ++it) { - VDCachedObject *pObj = static_cast(*it); - - pObj->DumpStatus(); - } - } -} - -VDCachedObject *VDCache::Allocate(sint64 key) { - VDCachedObject *pObj = NULL; - - vdsynchronized(mLock) { - if (mObjectCount >= mObjectLimit - 1) - Evict(mObjectLimit - 1); - - ObjectList& fl = mLists[kVDCacheStateFree]; - ObjectList& pl = mLists[kVDCacheStatePending]; - - if (fl.empty()) { - VDCachedObject *pNewObject = mpAllocator->OnCacheAllocate(); - - pNewObject->SetCache(this); - pNewObject->SetState(kVDCacheStateFree); - - fl.push_front(pNewObject); - } - - ++mObjectCount; - - pObj = static_cast(fl.front()); - VDASSERT(pObj->GetState() == kVDCacheStateFree); - pObj->AddRef(); - pObj->SetState(kVDCacheStatePending); - pObj->mHashKey = key; - pl.splice(pl.begin(), fl, fl.fast_find(pObj)); - mHash.insert(pObj); - } - - return pObj; -} - -VDCachedObject *VDCache::Create(sint64 key, bool& is_new) { - // The pending, ready, active, and complete lists are eligible for lookup. - // The free and aborted lists are not. - - VDCachedObject *pObj = NULL; - - is_new = false; - - vdsynchronized(mLock) { - pObj = static_cast(mHash[key]); - - if (pObj) { - pObj->AddRef(); - - VDASSERT(pObj->GetState() != kVDCacheStateFree); - - if (pObj->GetState() == kVDCacheStateIdle) { - pObj->SetState(kVDCacheStateComplete); - - ObjectList& il = mLists[kVDCacheStateIdle]; - ObjectList& cl = mLists[kVDCacheStateComplete]; - - cl.splice(cl.begin(), il, il.fast_find(pObj)); - } - } - - if (!pObj) { - is_new = true; - pObj = Allocate(key); - } - } - - return pObj; -} - -void VDCache::Evict(uint32 level) { - if (mObjectCount <= level) - return; - - int maxfree = mObjectCount - level; - - ObjectList& il = mLists[kVDCacheStateIdle]; - ObjectList& al = mLists[kVDCacheStateAborting]; - - while(maxfree-- > 0 && mObjectCount >= level && !il.empty()) { - VDCachedObject *pObject = static_cast(il.back()); - VDASSERT(pObject->GetState() == kVDCacheStateIdle); - - pObject->SetState(kVDCacheStateAborting); - al.splice(al.begin(), il, pObject); - - pObject->WeakAddRef(); - - mLock.Unlock(); - - pObject->OnCacheEvict(); - pObject->WeakRelease(); // Will move to free list. - - mLock.Lock(); - } -} - -void VDCache::NotifyFree(VDCachedObject *pObject) { - vdsynchronized(mLock) { - int rc = pObject->GetRefCount(); - - // This check is required because it is possible for a call to - // Allocate() to sneak in before we acquire the lock. - if (rc < 0x10000) { - VDCacheState oldState = pObject->GetState(); - VDCacheState newState = oldState; - - if (rc & 0xfffe) - newState = kVDCacheStateAborting; - else if (pObject->IsValid()) - newState = kVDCacheStateIdle; - else { - VDVERIFY((int)--mObjectCount >= 0); - newState = kVDCacheStateFree; - mHash.erase(pObject); - } - - if (newState != oldState) { - pObject->SetState(newState); - - ObjectList& nl = mLists[newState]; - ObjectList& ol = mLists[oldState]; - nl.splice(nl.begin(), ol, ol.fast_find(pObject)); - } - - if (oldState == kVDCacheStatePending || oldState == kVDCacheStateReady) - pObject->OnCacheAbortPending(); - } - } -} - -void VDCache::Schedule(VDCachedObject *pObject) { - vdsynchronized(mLock) { - VDCacheState oldState = pObject->GetState(); - - VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive); - - ObjectList& ol = mLists[oldState]; - ObjectList& nl = mLists[kVDCacheStateReady]; - - nl.splice(nl.back(), ol, ol.fast_find(pObject)); - pObject->SetState(kVDCacheStateReady); - } -} - -VDCachedObject *VDCache::GetNextReady() { - VDCachedObject *pObject = NULL; - - vdsynchronized(mLock) { - ObjectList& rl = mLists[kVDCacheStateReady]; - ObjectList& al = mLists[kVDCacheStateActive]; - - if (!rl.empty()) { - pObject = static_cast(rl.front()); - VDASSERT(pObject->GetState() == kVDCacheStateReady); - - al.splice(al.end(), rl, rl.begin()); - - pObject->SetState(kVDCacheStateActive); - pObject->AddRef(); - } - } - - return pObject; -} - -void VDCache::MarkCompleted(VDCachedObject *pObject) { - vdsynchronized(mLock) { - VDCacheState oldState = pObject->GetState(); - VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive); - - ObjectList& al = mLists[oldState]; - ObjectList& cl = mLists[kVDCacheStateComplete]; - - if (!al.empty()) { - cl.splice(cl.end(), al, al.fast_find(pObject)); - - pObject = static_cast(cl.back()); - pObject->SetState(kVDCacheStateComplete); - } - } -} - -/////////////////////////////////////////////////////////////////////////// - -VDCachedObject::VDCachedObject() - : mRefCount(0) - , mpCache(NULL) -{ -} - -int VDCachedObject::AddRef() { - int rv = (mRefCount += 0x10000); - - return rv >> 16; -} - -int VDCachedObject::Release() { - int rv = (mRefCount -= 0x10000); - - VDASSERT(rv >= 0); - - if (rv < 0x10000) { - if (!rv) - delete this; - else if (mpCache) - mpCache->NotifyFree(this); - } - - return rv >> 16; -} - -void VDCachedObject::WeakAddRef() { - mRefCount += 2; -} - -void VDCachedObject::WeakRelease() { - int rv = (mRefCount -= 2); - - VDASSERT((rv & 0xffff) < 0x8000); - - if (rv < 2) { - if (!rv) - delete this; - else - mpCache->NotifyFree(this); - } -} - -void VDCachedObject::SetCache(VDCache *pCache) { - mpCache = pCache; - if (pCache) - ++mRefCount; - else { - if (!--mRefCount) - delete this; - } -} - -/////////////////////////////////////////////////////////////////////////// - -VDPool::VDPool(IVDPoolAllocator *pAllocator) - : mpAllocator(pAllocator) - , mObjectCount(0) - , mObjectLimit(16) -{ -} - -VDPool::~VDPool() { - Shutdown(); -} - -void VDPool::Shutdown() { - for(int i=0; i(ol.back()); - ol.pop_back(); - - pObject->SetPool(NULL); // will release object - - VDASSERT((int)--mObjectCount >= 0); - } - } -} - -VDPooledObject *VDPool::Allocate() { - VDPooledObject *pObj = NULL; - - vdsynchronized(mLock) { - ObjectList& fl = mLists[kVDPoolStateFree]; - ObjectList& pl = mLists[kVDPoolStateActive]; - - if (fl.empty()) { - VDPooledObject *pNewObject = mpAllocator->OnPoolAllocate(); - - pNewObject->SetPool(this); - - fl.push_front(pNewObject); - ++mObjectCount; - } - - pObj = static_cast(fl.front()); - pObj->AddRef(); - pl.splice(pl.begin(), fl, fl.fast_find(pObj)); - } - - return pObj; -} - -void VDPool::NotifyFree(VDPooledObject *pObject) { - vdsynchronized(mLock) { - // This check is required because it is possible for a call to - // Allocate() to sneak in before we acquire the lock. - - if (pObject->GetRefCount() < 2) { - VDPoolState oldState = kVDPoolStateActive; - VDPoolState newState = kVDPoolStateFree; - - mLists[kVDPoolStateActive].erase(pObject); - - if (mObjectCount > mObjectLimit) { - delete pObject; - --mObjectCount; - } else - mLists[kVDPoolStateFree].push_back(pObject); - } - } -} - -/////////////////////////////////////////////////////////////////////////// - -VDPooledObject::VDPooledObject() - : mRefCount(0) - , mpPool(NULL) -{ -} - -int VDPooledObject::AddRef() { - return (mRefCount += 2) >> 1; -} - -int VDPooledObject::Release() { - int rv = (mRefCount -= 2); - - VDASSERT(rv >= 0); - - if (rv < 2) { - if (!rv) - delete this; - else if (mpPool) - mpPool->NotifyFree(this); - } - - return rv >> 1; -} - -void VDPooledObject::SetPool(VDPool *pPool) { - mpPool = pPool; - if (pPool) - ++mRefCount; - else { - if (!--mRefCount) - delete this; - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +/////////////////////////////////////////////////////////////////////////// + +VDCache::VDCache(IVDCacheAllocator *pAllocator) + : mpAllocator(pAllocator) + , mObjectCount(0) + , mObjectLimit(16) +{ +} + +VDCache::~VDCache() { + Shutdown(); +} + +void VDCache::Shutdown() { + for(int i=0; i(ol.back()); + ol.pop_back(); + + pObject->OnCacheEvict(); + pObject->SetCache(NULL); // will release object + + if (i != kVDCacheStateFree) { + VDASSERT((int)--mObjectCount >= 0); + } + } + } +} + +int VDCache::GetStateCount(int state) { + vdsynchronized(mLock) { + return mLists[state].size(); + } +} + +void VDCache::DumpListStatus(int state) { + vdsynchronized(mLock) { + ObjectList& ol = mLists[state]; + + for(ObjectList::iterator it(ol.begin()), itEnd(ol.end()); it!=itEnd; ++it) { + VDCachedObject *pObj = static_cast(*it); + + pObj->DumpStatus(); + } + } +} + +VDCachedObject *VDCache::Allocate(sint64 key) { + VDCachedObject *pObj = NULL; + + vdsynchronized(mLock) { + if (mObjectCount >= mObjectLimit - 1) + Evict(mObjectLimit - 1); + + ObjectList& fl = mLists[kVDCacheStateFree]; + ObjectList& pl = mLists[kVDCacheStatePending]; + + if (fl.empty()) { + VDCachedObject *pNewObject = mpAllocator->OnCacheAllocate(); + + pNewObject->SetCache(this); + pNewObject->SetState(kVDCacheStateFree); + + fl.push_front(pNewObject); + } + + ++mObjectCount; + + pObj = static_cast(fl.front()); + VDASSERT(pObj->GetState() == kVDCacheStateFree); + pObj->AddRef(); + pObj->SetState(kVDCacheStatePending); + pObj->mHashKey = key; + pl.splice(pl.begin(), fl, fl.fast_find(pObj)); + mHash.insert(pObj); + } + + return pObj; +} + +VDCachedObject *VDCache::Create(sint64 key, bool& is_new) { + // The pending, ready, active, and complete lists are eligible for lookup. + // The free and aborted lists are not. + + VDCachedObject *pObj = NULL; + + is_new = false; + + vdsynchronized(mLock) { + pObj = static_cast(mHash[key]); + + if (pObj) { + pObj->AddRef(); + + VDASSERT(pObj->GetState() != kVDCacheStateFree); + + if (pObj->GetState() == kVDCacheStateIdle) { + pObj->SetState(kVDCacheStateComplete); + + ObjectList& il = mLists[kVDCacheStateIdle]; + ObjectList& cl = mLists[kVDCacheStateComplete]; + + cl.splice(cl.begin(), il, il.fast_find(pObj)); + } + } + + if (!pObj) { + is_new = true; + pObj = Allocate(key); + } + } + + return pObj; +} + +void VDCache::Evict(uint32 level) { + if (mObjectCount <= level) + return; + + int maxfree = mObjectCount - level; + + ObjectList& il = mLists[kVDCacheStateIdle]; + ObjectList& al = mLists[kVDCacheStateAborting]; + + while(maxfree-- > 0 && mObjectCount >= level && !il.empty()) { + VDCachedObject *pObject = static_cast(il.back()); + VDASSERT(pObject->GetState() == kVDCacheStateIdle); + + pObject->SetState(kVDCacheStateAborting); + al.splice(al.begin(), il, pObject); + + pObject->WeakAddRef(); + + mLock.Unlock(); + + pObject->OnCacheEvict(); + pObject->WeakRelease(); // Will move to free list. + + mLock.Lock(); + } +} + +void VDCache::NotifyFree(VDCachedObject *pObject) { + vdsynchronized(mLock) { + int rc = pObject->GetRefCount(); + + // This check is required because it is possible for a call to + // Allocate() to sneak in before we acquire the lock. + if (rc < 0x10000) { + VDCacheState oldState = pObject->GetState(); + VDCacheState newState = oldState; + + if (rc & 0xfffe) + newState = kVDCacheStateAborting; + else if (pObject->IsValid()) + newState = kVDCacheStateIdle; + else { + VDVERIFY((int)--mObjectCount >= 0); + newState = kVDCacheStateFree; + mHash.erase(pObject); + } + + if (newState != oldState) { + pObject->SetState(newState); + + ObjectList& nl = mLists[newState]; + ObjectList& ol = mLists[oldState]; + nl.splice(nl.begin(), ol, ol.fast_find(pObject)); + } + + if (oldState == kVDCacheStatePending || oldState == kVDCacheStateReady) + pObject->OnCacheAbortPending(); + } + } +} + +void VDCache::Schedule(VDCachedObject *pObject) { + vdsynchronized(mLock) { + VDCacheState oldState = pObject->GetState(); + + VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive); + + ObjectList& ol = mLists[oldState]; + ObjectList& nl = mLists[kVDCacheStateReady]; + + nl.splice(nl.back(), ol, ol.fast_find(pObject)); + pObject->SetState(kVDCacheStateReady); + } +} + +VDCachedObject *VDCache::GetNextReady() { + VDCachedObject *pObject = NULL; + + vdsynchronized(mLock) { + ObjectList& rl = mLists[kVDCacheStateReady]; + ObjectList& al = mLists[kVDCacheStateActive]; + + if (!rl.empty()) { + pObject = static_cast(rl.front()); + VDASSERT(pObject->GetState() == kVDCacheStateReady); + + al.splice(al.end(), rl, rl.begin()); + + pObject->SetState(kVDCacheStateActive); + pObject->AddRef(); + } + } + + return pObject; +} + +void VDCache::MarkCompleted(VDCachedObject *pObject) { + vdsynchronized(mLock) { + VDCacheState oldState = pObject->GetState(); + VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive); + + ObjectList& al = mLists[oldState]; + ObjectList& cl = mLists[kVDCacheStateComplete]; + + if (!al.empty()) { + cl.splice(cl.end(), al, al.fast_find(pObject)); + + pObject = static_cast(cl.back()); + pObject->SetState(kVDCacheStateComplete); + } + } +} + +/////////////////////////////////////////////////////////////////////////// + +VDCachedObject::VDCachedObject() + : mRefCount(0) + , mpCache(NULL) +{ +} + +int VDCachedObject::AddRef() { + int rv = (mRefCount += 0x10000); + + return rv >> 16; +} + +int VDCachedObject::Release() { + int rv = (mRefCount -= 0x10000); + + VDASSERT(rv >= 0); + + if (rv < 0x10000) { + if (!rv) + delete this; + else if (mpCache) + mpCache->NotifyFree(this); + } + + return rv >> 16; +} + +void VDCachedObject::WeakAddRef() { + mRefCount += 2; +} + +void VDCachedObject::WeakRelease() { + int rv = (mRefCount -= 2); + + VDASSERT((rv & 0xffff) < 0x8000); + + if (rv < 2) { + if (!rv) + delete this; + else + mpCache->NotifyFree(this); + } +} + +void VDCachedObject::SetCache(VDCache *pCache) { + mpCache = pCache; + if (pCache) + ++mRefCount; + else { + if (!--mRefCount) + delete this; + } +} + +/////////////////////////////////////////////////////////////////////////// + +VDPool::VDPool(IVDPoolAllocator *pAllocator) + : mpAllocator(pAllocator) + , mObjectCount(0) + , mObjectLimit(16) +{ +} + +VDPool::~VDPool() { + Shutdown(); +} + +void VDPool::Shutdown() { + for(int i=0; i(ol.back()); + ol.pop_back(); + + pObject->SetPool(NULL); // will release object + + VDASSERT((int)--mObjectCount >= 0); + } + } +} + +VDPooledObject *VDPool::Allocate() { + VDPooledObject *pObj = NULL; + + vdsynchronized(mLock) { + ObjectList& fl = mLists[kVDPoolStateFree]; + ObjectList& pl = mLists[kVDPoolStateActive]; + + if (fl.empty()) { + VDPooledObject *pNewObject = mpAllocator->OnPoolAllocate(); + + pNewObject->SetPool(this); + + fl.push_front(pNewObject); + ++mObjectCount; + } + + pObj = static_cast(fl.front()); + pObj->AddRef(); + pl.splice(pl.begin(), fl, fl.fast_find(pObj)); + } + + return pObj; +} + +void VDPool::NotifyFree(VDPooledObject *pObject) { + vdsynchronized(mLock) { + // This check is required because it is possible for a call to + // Allocate() to sneak in before we acquire the lock. + + if (pObject->GetRefCount() < 2) { + VDPoolState oldState = kVDPoolStateActive; + VDPoolState newState = kVDPoolStateFree; + + mLists[kVDPoolStateActive].erase(pObject); + + if (mObjectCount > mObjectLimit) { + delete pObject; + --mObjectCount; + } else + mLists[kVDPoolStateFree].push_back(pObject); + } + } +} + +/////////////////////////////////////////////////////////////////////////// + +VDPooledObject::VDPooledObject() + : mRefCount(0) + , mpPool(NULL) +{ +} + +int VDPooledObject::AddRef() { + return (mRefCount += 2) >> 1; +} + +int VDPooledObject::Release() { + int rv = (mRefCount -= 2); + + VDASSERT(rv >= 0); + + if (rv < 2) { + if (!rv) + delete this; + else if (mpPool) + mpPool->NotifyFree(this); + } + + return rv >> 1; +} + +void VDPooledObject::SetPool(VDPool *pPool) { + mpPool = pPool; + if (pPool) + ++mRefCount; + else { + if (!--mRefCount) + delete this; + } +} diff --git a/src/thirdparty/VirtualDub/system/source/cmdline.cpp b/src/thirdparty/VirtualDub/system/source/cmdline.cpp index 2c7fdd66e3d..51b7658c344 100644 --- a/src/thirdparty/VirtualDub/system/source/cmdline.cpp +++ b/src/thirdparty/VirtualDub/system/source/cmdline.cpp @@ -1,274 +1,274 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -VDCommandLine::VDCommandLine() { -} - -VDCommandLine::VDCommandLine(const wchar_t *s) { - Init(s); -} - -VDCommandLine::~VDCommandLine() { -} - -void VDCommandLine::Init(const wchar_t *s) { - mTokens.clear(); - mLine.clear(); - - for(;;) { - while(iswspace(*s)) - ++s; - - if (!*s) - break; - - Token te = { (int)mLine.size(), *s == L'/' }; - - if (te.mbIsSwitch) { - mLine.push_back(L'/'); - ++s; - } - - mTokens.push_back(te); - - // special case for /? - if (te.mbIsSwitch && *s == L'?') { - mLine.push_back(L'?'); - ++s; - } - - while(*s && *s != L' ' && *s != L'/') { - if (te.mbIsSwitch) { - if (!isalnum((unsigned char)*s)) { - if (*s == L':') - ++s; - break; - } - - mLine.push_back(*s++); - } else if (*s == L'"') { - ++s; - while(*s && *s != L'"') - mLine.push_back(*s++); - - if (*s) { - ++s; - - if (*s == ',') { - ++s; - break; - } - } - } else - mLine.push_back(*s++); - } - - mLine.push_back(0); - } -} - -void VDCommandLine::InitAlt(const wchar_t *s) { - mTokens.clear(); - mLine.clear(); - - for(;;) { - while(*s == L' ' || *s == L'\t') - ++s; - - if (!*s) - break; - - Token te = { (int)mLine.size(), *s == L'/' }; - - if (te.mbIsSwitch) { - mLine.push_back(L'/'); - ++s; - } - - mTokens.push_back(te); - - // special case for /? - if (te.mbIsSwitch && *s == L'?') { - mLine.push_back(L'?'); - ++s; - } - - bool inquote = false; - for(;;) { - wchar_t c = *s; - - if (!c) - break; - - if (!inquote && (c == L' ' || c == L'\t' || c == L'/')) - break; - - if (te.mbIsSwitch) { - if (!isalnum((unsigned char)*s)) { - if (*s == L':') - ++s; - break; - } - - mLine.push_back(c); - ++s; - } else { - if (c == L'\\') { - uint32 backslashes = 0; - - do { - ++backslashes; - c = *++s; - } while(c == L'\\'); - - bool postquote = false; - if (c == L'"') { - if (backslashes & 1) - postquote = true; - else - inquote = !inquote; - - backslashes >>= 1; - ++s; - } - - while(backslashes--) - mLine.push_back(L'\\'); - - if (postquote) - mLine.push_back(L'"'); - } else { - if (c == L'"') - inquote = !inquote; - else - mLine.push_back(c); - - ++s; - } - } - } - - mLine.push_back(0); - } -} - -uint32 VDCommandLine::GetCount() const { - return mTokens.size(); -} - -const wchar_t *VDCommandLine::operator[](int index) const { - return (uint32)index < mTokens.size() ? mLine.data() + mTokens[index].mTokenIndex : NULL; -} - -const VDStringSpanW VDCommandLine::operator()(int index) const { - if ((uint32)index >= mTokens.size()) - return VDStringSpanW(); - - const wchar_t *s = mLine.data() + mTokens[index].mTokenIndex; - - return VDStringSpanW(s); -} - -bool VDCommandLine::GetNextArgument(VDCommandLineIterator& it, const wchar_t *& token, bool& isSwitch) const { - int count = (int)mTokens.size(); - - if (it.mIndex >= count) - return false; - - token = mLine.data() + mTokens[it.mIndex].mTokenIndex; - isSwitch = mTokens[it.mIndex].mbIsSwitch; - - ++it.mIndex; - return true; -} - -bool VDCommandLine::GetNextNonSwitchArgument(VDCommandLineIterator& it, const wchar_t *& token) const { - int count = (int)mTokens.size(); - - if (it.mIndex >= count) - return false; - - if (mTokens[it.mIndex].mbIsSwitch) - return false; - - token = mLine.data() + mTokens[it.mIndex++].mTokenIndex; - return true; -} - -bool VDCommandLine::GetNextSwitchArgument(VDCommandLineIterator& it, const wchar_t *& token) const { - int count = (int)mTokens.size(); - - if (it.mIndex >= count) - return false; - - if (!mTokens[it.mIndex].mbIsSwitch) - return false; - - token = mLine.data() + mTokens[it.mIndex++].mTokenIndex; - return true; -} - -bool VDCommandLine::FindAndRemoveSwitch(const wchar_t *name) { - int count = (int)mTokens.size(); - - for(int i=1; i +#include + +VDCommandLine::VDCommandLine() { +} + +VDCommandLine::VDCommandLine(const wchar_t *s) { + Init(s); +} + +VDCommandLine::~VDCommandLine() { +} + +void VDCommandLine::Init(const wchar_t *s) { + mTokens.clear(); + mLine.clear(); + + for(;;) { + while(iswspace(*s)) + ++s; + + if (!*s) + break; + + Token te = { (int)mLine.size(), *s == L'/' }; + + if (te.mbIsSwitch) { + mLine.push_back(L'/'); + ++s; + } + + mTokens.push_back(te); + + // special case for /? + if (te.mbIsSwitch && *s == L'?') { + mLine.push_back(L'?'); + ++s; + } + + while(*s && *s != L' ' && *s != L'/') { + if (te.mbIsSwitch) { + if (!isalnum((unsigned char)*s)) { + if (*s == L':') + ++s; + break; + } + + mLine.push_back(*s++); + } else if (*s == L'"') { + ++s; + while(*s && *s != L'"') + mLine.push_back(*s++); + + if (*s) { + ++s; + + if (*s == ',') { + ++s; + break; + } + } + } else + mLine.push_back(*s++); + } + + mLine.push_back(0); + } +} + +void VDCommandLine::InitAlt(const wchar_t *s) { + mTokens.clear(); + mLine.clear(); + + for(;;) { + while(*s == L' ' || *s == L'\t') + ++s; + + if (!*s) + break; + + Token te = { (int)mLine.size(), *s == L'/' }; + + if (te.mbIsSwitch) { + mLine.push_back(L'/'); + ++s; + } + + mTokens.push_back(te); + + // special case for /? + if (te.mbIsSwitch && *s == L'?') { + mLine.push_back(L'?'); + ++s; + } + + bool inquote = false; + for(;;) { + wchar_t c = *s; + + if (!c) + break; + + if (!inquote && (c == L' ' || c == L'\t' || c == L'/')) + break; + + if (te.mbIsSwitch) { + if (!isalnum((unsigned char)*s)) { + if (*s == L':') + ++s; + break; + } + + mLine.push_back(c); + ++s; + } else { + if (c == L'\\') { + uint32 backslashes = 0; + + do { + ++backslashes; + c = *++s; + } while(c == L'\\'); + + bool postquote = false; + if (c == L'"') { + if (backslashes & 1) + postquote = true; + else + inquote = !inquote; + + backslashes >>= 1; + ++s; + } + + while(backslashes--) + mLine.push_back(L'\\'); + + if (postquote) + mLine.push_back(L'"'); + } else { + if (c == L'"') + inquote = !inquote; + else + mLine.push_back(c); + + ++s; + } + } + } + + mLine.push_back(0); + } +} + +uint32 VDCommandLine::GetCount() const { + return mTokens.size(); +} + +const wchar_t *VDCommandLine::operator[](int index) const { + return (uint32)index < mTokens.size() ? mLine.data() + mTokens[index].mTokenIndex : NULL; +} + +const VDStringSpanW VDCommandLine::operator()(int index) const { + if ((uint32)index >= mTokens.size()) + return VDStringSpanW(); + + const wchar_t *s = mLine.data() + mTokens[index].mTokenIndex; + + return VDStringSpanW(s); +} + +bool VDCommandLine::GetNextArgument(VDCommandLineIterator& it, const wchar_t *& token, bool& isSwitch) const { + int count = (int)mTokens.size(); + + if (it.mIndex >= count) + return false; + + token = mLine.data() + mTokens[it.mIndex].mTokenIndex; + isSwitch = mTokens[it.mIndex].mbIsSwitch; + + ++it.mIndex; + return true; +} + +bool VDCommandLine::GetNextNonSwitchArgument(VDCommandLineIterator& it, const wchar_t *& token) const { + int count = (int)mTokens.size(); + + if (it.mIndex >= count) + return false; + + if (mTokens[it.mIndex].mbIsSwitch) + return false; + + token = mLine.data() + mTokens[it.mIndex++].mTokenIndex; + return true; +} + +bool VDCommandLine::GetNextSwitchArgument(VDCommandLineIterator& it, const wchar_t *& token) const { + int count = (int)mTokens.size(); + + if (it.mIndex >= count) + return false; + + if (!mTokens[it.mIndex].mbIsSwitch) + return false; + + token = mLine.data() + mTokens[it.mIndex++].mTokenIndex; + return true; +} + +bool VDCommandLine::FindAndRemoveSwitch(const wchar_t *name) { + int count = (int)mTokens.size(); + + for(int i=1; i -#include -#include -#include - -static long g_lCPUExtensionsEnabled; -static long g_lCPUExtensionsAvailable; - -extern "C" { - bool FPU_enabled, MMX_enabled, SSE_enabled, ISSE_enabled, SSE2_enabled; -}; - -#if (!defined(VD_CPU_X86) && !defined(VD_CPU_AMD64)) || defined(__MINGW32__) -long CPUCheckForExtensions() { - return 0; -} -#else - -namespace { -#ifdef _M_IX86 - bool VDIsAVXSupportedByOS() { - uint32 xfeature_enabled_mask; - - __asm { - xor ecx, ecx - __emit 0x0f ;xgetbv - __emit 0x01 - __emit 0xd0 - mov dword ptr xfeature_enabled_mask, eax - } - - return (xfeature_enabled_mask & 0x06) == 0x06; - } -#else - extern "C" bool VDIsAVXSupportedByOS(); -#endif -} - -// This code used to use IsProcessorFeaturePresent(), but this function is somewhat -// suboptimal in Win64 -- for one thing, it doesn't return true for MMX, at least -// on Vista 64. -long CPUCheckForExtensions() { - // check for CPUID (x86 only) -#ifdef _M_IX86 - uint32 id; - __asm { - pushfd - or dword ptr [esp], 00200000h ;set the ID bit - popfd - pushfd ;flags -> EAX - pop dword ptr id - } - - if (!(id & 0x00200000)) { - // if we don't have CPUID, we probably won't want to try FPU optimizations - // (80486). - return 0; - } -#endif - - // check for features register - long flags = CPUF_SUPPORTS_FPU | CPUF_SUPPORTS_CPUID; - - int cpuInfo[4]; - __cpuid(cpuInfo, 0); - if (cpuInfo[0] == 0) - return flags; - - __cpuid(cpuInfo, 1); - - if (cpuInfo[3] & (1 << 23)) - flags |= CPUF_SUPPORTS_MMX; - - if (cpuInfo[3] & (1 << 25)) { - // Check if SSE is actually supported. - bool sseSupported = true; - -#ifdef _M_IX86 - __try { - __asm andps xmm0,xmm0 - } __except(EXCEPTION_EXECUTE_HANDLER) { - if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) - sseSupported = false; - } -#endif - - if (sseSupported) { - flags |= CPUF_SUPPORTS_SSE | CPUF_SUPPORTS_INTEGER_SSE; - - if (cpuInfo[3] & (1 << 26)) - flags |= CPUF_SUPPORTS_SSE2; - - if (cpuInfo[2] & 0x00000001) - flags |= CPUF_SUPPORTS_SSE3; - - if (cpuInfo[2] & 0x00000200) - flags |= CPUF_SUPPORTS_SSSE3; - - if (cpuInfo[2] & 0x00080000) - flags |= CPUF_SUPPORTS_SSE41; - - if (cpuInfo[2] & 0x00100000) - flags |= CPUF_SUPPORTS_SSE42; - - // check OSXSAVE and AVX bits - if ((cpuInfo[2] & ((1 << 27) | (1 << 28))) == ((1 << 27) | (1 << 28))) { - if (VDIsAVXSupportedByOS()) - flags |= CPUF_SUPPORTS_AVX; - } - } - } - - // check for 3DNow!, 3DNow! extensions - __cpuid(cpuInfo, 0x80000000); - if ((unsigned)cpuInfo[0] >= 0x80000001U) { - __cpuid(cpuInfo, 0x80000001); - - if (cpuInfo[3] & (1 << 31)) - flags |= CPUF_SUPPORTS_3DNOW; - - if (cpuInfo[3] & (1 << 30)) - flags |= CPUF_SUPPORTS_3DNOW_EXT; - - if (cpuInfo[3] & (1 << 22)) - flags |= CPUF_SUPPORTS_INTEGER_SSE; - } - - return flags; -} -#endif - -long CPUEnableExtensions(long lEnableFlags) { - g_lCPUExtensionsEnabled = lEnableFlags; - - MMX_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_MMX); - FPU_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_FPU); - SSE_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_SSE); - ISSE_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_INTEGER_SSE); - SSE2_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_SSE2); - - return g_lCPUExtensionsEnabled; -} - -long CPUGetAvailableExtensions() { - return g_lCPUExtensionsAvailable; -} - -long CPUGetEnabledExtensions() { - return g_lCPUExtensionsEnabled; -} - -void VDCPUCleanupExtensions() { -#if defined(VD_CPU_X86) - if (ISSE_enabled) - _mm_sfence(); - - if (MMX_enabled) - _mm_empty(); -#elif defined(VD_CPU_AMD64) - _mm_sfence(); -#endif -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include +#include + +static long g_lCPUExtensionsEnabled; +static long g_lCPUExtensionsAvailable; + +extern "C" { + bool FPU_enabled, MMX_enabled, SSE_enabled, ISSE_enabled, SSE2_enabled; +}; + +#if (!defined(VD_CPU_X86) && !defined(VD_CPU_AMD64)) || defined(__MINGW32__) +long CPUCheckForExtensions() { + return 0; +} +#else + +namespace { +#ifdef _M_IX86 + bool VDIsAVXSupportedByOS() { + uint32 xfeature_enabled_mask; + + __asm { + xor ecx, ecx + __emit 0x0f ;xgetbv + __emit 0x01 + __emit 0xd0 + mov dword ptr xfeature_enabled_mask, eax + } + + return (xfeature_enabled_mask & 0x06) == 0x06; + } +#else + extern "C" bool VDIsAVXSupportedByOS(); +#endif +} + +// This code used to use IsProcessorFeaturePresent(), but this function is somewhat +// suboptimal in Win64 -- for one thing, it doesn't return true for MMX, at least +// on Vista 64. +long CPUCheckForExtensions() { + // check for CPUID (x86 only) +#ifdef _M_IX86 + uint32 id; + __asm { + pushfd + or dword ptr [esp], 00200000h ;set the ID bit + popfd + pushfd ;flags -> EAX + pop dword ptr id + } + + if (!(id & 0x00200000)) { + // if we don't have CPUID, we probably won't want to try FPU optimizations + // (80486). + return 0; + } +#endif + + // check for features register + long flags = CPUF_SUPPORTS_FPU | CPUF_SUPPORTS_CPUID; + + int cpuInfo[4]; + __cpuid(cpuInfo, 0); + if (cpuInfo[0] == 0) + return flags; + + __cpuid(cpuInfo, 1); + + if (cpuInfo[3] & (1 << 23)) + flags |= CPUF_SUPPORTS_MMX; + + if (cpuInfo[3] & (1 << 25)) { + // Check if SSE is actually supported. + bool sseSupported = true; + +#ifdef _M_IX86 + __try { + __asm andps xmm0,xmm0 + } __except(EXCEPTION_EXECUTE_HANDLER) { + if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) + sseSupported = false; + } +#endif + + if (sseSupported) { + flags |= CPUF_SUPPORTS_SSE | CPUF_SUPPORTS_INTEGER_SSE; + + if (cpuInfo[3] & (1 << 26)) + flags |= CPUF_SUPPORTS_SSE2; + + if (cpuInfo[2] & 0x00000001) + flags |= CPUF_SUPPORTS_SSE3; + + if (cpuInfo[2] & 0x00000200) + flags |= CPUF_SUPPORTS_SSSE3; + + if (cpuInfo[2] & 0x00080000) + flags |= CPUF_SUPPORTS_SSE41; + + if (cpuInfo[2] & 0x00100000) + flags |= CPUF_SUPPORTS_SSE42; + + // check OSXSAVE and AVX bits + if ((cpuInfo[2] & ((1 << 27) | (1 << 28))) == ((1 << 27) | (1 << 28))) { + if (VDIsAVXSupportedByOS()) + flags |= CPUF_SUPPORTS_AVX; + } + } + } + + // check for 3DNow!, 3DNow! extensions + __cpuid(cpuInfo, 0x80000000); + if ((unsigned)cpuInfo[0] >= 0x80000001U) { + __cpuid(cpuInfo, 0x80000001); + + if (cpuInfo[3] & (1 << 31)) + flags |= CPUF_SUPPORTS_3DNOW; + + if (cpuInfo[3] & (1 << 30)) + flags |= CPUF_SUPPORTS_3DNOW_EXT; + + if (cpuInfo[3] & (1 << 22)) + flags |= CPUF_SUPPORTS_INTEGER_SSE; + } + + return flags; +} +#endif + +long CPUEnableExtensions(long lEnableFlags) { + g_lCPUExtensionsEnabled = lEnableFlags; + + MMX_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_MMX); + FPU_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_FPU); + SSE_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_SSE); + ISSE_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_INTEGER_SSE); + SSE2_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_SSE2); + + return g_lCPUExtensionsEnabled; +} + +long CPUGetAvailableExtensions() { + return g_lCPUExtensionsAvailable; +} + +long CPUGetEnabledExtensions() { + return g_lCPUExtensionsEnabled; +} + +void VDCPUCleanupExtensions() { +#if defined(VD_CPU_X86) + if (ISSE_enabled) + _mm_sfence(); + + if (MMX_enabled) + _mm_empty(); +#elif defined(VD_CPU_AMD64) + _mm_sfence(); +#endif +} diff --git a/src/thirdparty/VirtualDub/system/source/debug.cpp b/src/thirdparty/VirtualDub/system/source/debug.cpp index 66ff40a8eef..d0173e497b3 100644 --- a/src/thirdparty/VirtualDub/system/source/debug.cpp +++ b/src/thirdparty/VirtualDub/system/source/debug.cpp @@ -1,290 +1,290 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -#include -#include - -#include -#include -#include -#include - -#ifdef _DEBUG - -class VDSafeMessageBoxThreadW32 : public VDThread { -public: - VDSafeMessageBoxThreadW32(HWND hwndParent, const char *pszText, const char *pszCaption, DWORD dwFlags) - : mhwndParent(hwndParent) - , mpszText(pszText) - , mpszCaption(pszCaption) - , mdwFlags(dwFlags) - { - } - - DWORD GetResult() const { return mdwResult; } - -protected: - void ThreadRun() { - mdwResult = MessageBox(mhwndParent, mpszText, mpszCaption, mdwFlags); - } - - HWND mhwndParent; - const char *const mpszText; - const char *const mpszCaption; - const DWORD mdwFlags; - DWORD mdwResult; -}; - -UINT VDSafeMessageBoxW32(HWND hwndParent, const char *pszText, const char *pszCaption, DWORD dwFlags) { - VDSafeMessageBoxThreadW32 mbox(hwndParent, pszText, pszCaption, dwFlags); - - mbox.ThreadStart(); - mbox.ThreadWait(); - return mbox.GetResult(); -} - -VDAssertResult VDAssert(const char *exp, const char *file, int line) { - DWORD dwOldError = GetLastError(); - char szText[1024]; - - VDDEBUG("%s(%d): Assert failed: %s\n", file, line, exp); - - wsprintf(szText, - "Assert failed in module %s, line %d:\n" - "\n" - "\t%s\n" - "\n" - "Break into debugger?", file, line, exp); - - UINT result = VDSafeMessageBoxW32(NULL, szText, "Assert failure", MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_TASKMODAL); - - SetLastError(dwOldError); - - switch(result) { - case IDABORT: - ::Sleep(250); // Pause for a moment so the VC6 debugger doesn't freeze. - return kVDAssertBreak; - case IDRETRY: - return kVDAssertContinue; - default: - VDNEVERHERE; - case IDIGNORE: - return kVDAssertIgnore; - } -} - -VDAssertResult VDAssertPtr(const char *exp, const char *file, int line) { - DWORD dwOldError = GetLastError(); - char szText[1024]; - - VDDEBUG("%s(%d): Assert failed: %s is not a valid pointer\n", file, line, exp); - - wsprintf(szText, - "Assert failed in module %s, line %d:\n" - "\n" - "\t(%s) not a valid pointer\n" - "\n" - "Break into debugger?", file, line, exp); - - UINT result = VDSafeMessageBoxW32(NULL, szText, "Assert failure", MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_TASKMODAL); - - SetLastError(dwOldError); - - switch(result) { - case IDABORT: - return kVDAssertBreak; - case IDRETRY: - return kVDAssertContinue; - default: - VDNEVERHERE; - case IDIGNORE: - return kVDAssertIgnore; - } -} - -#endif - -void VDProtectedAutoScopeICLWorkaround() {} - -void VDDebugPrint(const char *format, ...) { - char buf[4096]; - - va_list val; - va_start(val, format); - _vsnprintf(buf, sizeof buf, format, val); - va_end(val); - Sleep(0); - OutputDebugString(buf); -} - -/////////////////////////////////////////////////////////////////////////// - -namespace { - IVDExternalCallTrap *g_pExCallTrap; -} - -void VDSetExternalCallTrap(IVDExternalCallTrap *trap) { - g_pExCallTrap = trap; -} - -#if defined(WIN32) && defined(_M_IX86) && defined(__MSC_VER) - namespace { - bool IsFPUStateOK(unsigned& ctlword) { - ctlword = 0; - - __asm mov eax, ctlword - __asm fnstcw [eax] - - ctlword &= 0x0f3f; - - return ctlword == 0x023f; - } - - void ResetFPUState() { - static const unsigned ctlword = 0x027f; - - __asm fnclex - __asm fldcw ctlword - } - - bool IsSSEStateOK(uint32& ctlword) { - ctlword = _mm_getcsr(); - - // Intel C/C++ flips FTZ and DAZ. :( - return (ctlword & 0x7f80) == 0x1f80; - } - - void ResetSSEState() { - _mm_setcsr(0x1f80); - } - } - - bool IsMMXState() { - char buf[28]; - unsigned short tagword; - - __asm fnstenv buf // this resets the FPU control word somehow!? - - tagword = *(unsigned short *)(buf + 8); - - return (tagword != 0xffff); - } - void ClearMMXState() { - if (MMX_enabled) - __asm emms - else { - __asm { - ffree st(0) - ffree st(1) - ffree st(2) - ffree st(3) - ffree st(4) - ffree st(5) - ffree st(6) - ffree st(7) - } - } - } - - void VDClearEvilCPUStates() { - ResetFPUState(); - ClearMMXState(); - } - - void VDPreCheckExternalCodeCall(const char *file, int line) { - unsigned fpucw; - uint32 mxcsr; - bool bFPUStateBad = !IsFPUStateOK(fpucw); - bool bSSEStateBad = SSE_enabled && !IsSSEStateOK(mxcsr); - bool bMMXStateBad = IsMMXState(); - - if (bMMXStateBad || bFPUStateBad || bSSEStateBad) { - ClearMMXState(); - ResetFPUState(); - if (SSE_enabled) - ResetSSEState(); - } - - if (g_pExCallTrap) { - if (bMMXStateBad) - g_pExCallTrap->OnMMXTrap(NULL, file, line); - - if (bFPUStateBad) - g_pExCallTrap->OnFPUTrap(NULL, file, line, fpucw); - - if (bSSEStateBad) - g_pExCallTrap->OnSSETrap(NULL, file, line, mxcsr); - } - } - - void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine) { - unsigned fpucw; - uint32 mxcsr; - bool bFPUStateBad = !IsFPUStateOK(fpucw); - bool bSSEStateBad = SSE_enabled && !IsSSEStateOK(mxcsr); - bool bMMXStateBad = IsMMXState(); - bool bBadState = bMMXStateBad || bFPUStateBad || bSSEStateBad; - - if (bBadState) { - ClearMMXState(); - ResetFPUState(); - if (SSE_enabled) - ResetSSEState(); - } - - if (g_pExCallTrap) { - if (bMMXStateBad) - g_pExCallTrap->OnMMXTrap(mpContext, mpFile, mLine); - - if (bFPUStateBad) - g_pExCallTrap->OnFPUTrap(mpContext, mpFile, mLine, fpucw); - - if (bSSEStateBad) - g_pExCallTrap->OnSSETrap(mpContext, mpFile, mLine, mxcsr); - } - } - -#else - - bool IsMMXState() { - return false; - } - - void ClearMMXState() { - } - - void VDClearEvilCPUStates() { - } - - void VDPreCheckExternalCodeCall(const char *file, int line) { - } - - void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine) { - } - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef _DEBUG + +class VDSafeMessageBoxThreadW32 : public VDThread { +public: + VDSafeMessageBoxThreadW32(HWND hwndParent, const char *pszText, const char *pszCaption, DWORD dwFlags) + : mhwndParent(hwndParent) + , mpszText(pszText) + , mpszCaption(pszCaption) + , mdwFlags(dwFlags) + { + } + + DWORD GetResult() const { return mdwResult; } + +protected: + void ThreadRun() { + mdwResult = MessageBox(mhwndParent, mpszText, mpszCaption, mdwFlags); + } + + HWND mhwndParent; + const char *const mpszText; + const char *const mpszCaption; + const DWORD mdwFlags; + DWORD mdwResult; +}; + +UINT VDSafeMessageBoxW32(HWND hwndParent, const char *pszText, const char *pszCaption, DWORD dwFlags) { + VDSafeMessageBoxThreadW32 mbox(hwndParent, pszText, pszCaption, dwFlags); + + mbox.ThreadStart(); + mbox.ThreadWait(); + return mbox.GetResult(); +} + +VDAssertResult VDAssert(const char *exp, const char *file, int line) { + DWORD dwOldError = GetLastError(); + char szText[1024]; + + VDDEBUG("%s(%d): Assert failed: %s\n", file, line, exp); + + wsprintf(szText, + "Assert failed in module %s, line %d:\n" + "\n" + "\t%s\n" + "\n" + "Break into debugger?", file, line, exp); + + UINT result = VDSafeMessageBoxW32(NULL, szText, "Assert failure", MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_TASKMODAL); + + SetLastError(dwOldError); + + switch(result) { + case IDABORT: + ::Sleep(250); // Pause for a moment so the VC6 debugger doesn't freeze. + return kVDAssertBreak; + case IDRETRY: + return kVDAssertContinue; + default: + VDNEVERHERE; + case IDIGNORE: + return kVDAssertIgnore; + } +} + +VDAssertResult VDAssertPtr(const char *exp, const char *file, int line) { + DWORD dwOldError = GetLastError(); + char szText[1024]; + + VDDEBUG("%s(%d): Assert failed: %s is not a valid pointer\n", file, line, exp); + + wsprintf(szText, + "Assert failed in module %s, line %d:\n" + "\n" + "\t(%s) not a valid pointer\n" + "\n" + "Break into debugger?", file, line, exp); + + UINT result = VDSafeMessageBoxW32(NULL, szText, "Assert failure", MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_TASKMODAL); + + SetLastError(dwOldError); + + switch(result) { + case IDABORT: + return kVDAssertBreak; + case IDRETRY: + return kVDAssertContinue; + default: + VDNEVERHERE; + case IDIGNORE: + return kVDAssertIgnore; + } +} + +#endif + +void VDProtectedAutoScopeICLWorkaround() {} + +void VDDebugPrint(const char *format, ...) { + char buf[4096]; + + va_list val; + va_start(val, format); + _vsnprintf(buf, sizeof buf, format, val); + va_end(val); + Sleep(0); + OutputDebugString(buf); +} + +/////////////////////////////////////////////////////////////////////////// + +namespace { + IVDExternalCallTrap *g_pExCallTrap; +} + +void VDSetExternalCallTrap(IVDExternalCallTrap *trap) { + g_pExCallTrap = trap; +} + +#if defined(WIN32) && defined(_M_IX86) && defined(__MSC_VER) + namespace { + bool IsFPUStateOK(unsigned& ctlword) { + ctlword = 0; + + __asm mov eax, ctlword + __asm fnstcw [eax] + + ctlword &= 0x0f3f; + + return ctlword == 0x023f; + } + + void ResetFPUState() { + static const unsigned ctlword = 0x027f; + + __asm fnclex + __asm fldcw ctlword + } + + bool IsSSEStateOK(uint32& ctlword) { + ctlword = _mm_getcsr(); + + // Intel C/C++ flips FTZ and DAZ. :( + return (ctlword & 0x7f80) == 0x1f80; + } + + void ResetSSEState() { + _mm_setcsr(0x1f80); + } + } + + bool IsMMXState() { + char buf[28]; + unsigned short tagword; + + __asm fnstenv buf // this resets the FPU control word somehow!? + + tagword = *(unsigned short *)(buf + 8); + + return (tagword != 0xffff); + } + void ClearMMXState() { + if (MMX_enabled) + __asm emms + else { + __asm { + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + ffree st(7) + } + } + } + + void VDClearEvilCPUStates() { + ResetFPUState(); + ClearMMXState(); + } + + void VDPreCheckExternalCodeCall(const char *file, int line) { + unsigned fpucw; + uint32 mxcsr; + bool bFPUStateBad = !IsFPUStateOK(fpucw); + bool bSSEStateBad = SSE_enabled && !IsSSEStateOK(mxcsr); + bool bMMXStateBad = IsMMXState(); + + if (bMMXStateBad || bFPUStateBad || bSSEStateBad) { + ClearMMXState(); + ResetFPUState(); + if (SSE_enabled) + ResetSSEState(); + } + + if (g_pExCallTrap) { + if (bMMXStateBad) + g_pExCallTrap->OnMMXTrap(NULL, file, line); + + if (bFPUStateBad) + g_pExCallTrap->OnFPUTrap(NULL, file, line, fpucw); + + if (bSSEStateBad) + g_pExCallTrap->OnSSETrap(NULL, file, line, mxcsr); + } + } + + void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine) { + unsigned fpucw; + uint32 mxcsr; + bool bFPUStateBad = !IsFPUStateOK(fpucw); + bool bSSEStateBad = SSE_enabled && !IsSSEStateOK(mxcsr); + bool bMMXStateBad = IsMMXState(); + bool bBadState = bMMXStateBad || bFPUStateBad || bSSEStateBad; + + if (bBadState) { + ClearMMXState(); + ResetFPUState(); + if (SSE_enabled) + ResetSSEState(); + } + + if (g_pExCallTrap) { + if (bMMXStateBad) + g_pExCallTrap->OnMMXTrap(mpContext, mpFile, mLine); + + if (bFPUStateBad) + g_pExCallTrap->OnFPUTrap(mpContext, mpFile, mLine, fpucw); + + if (bSSEStateBad) + g_pExCallTrap->OnSSETrap(mpContext, mpFile, mLine, mxcsr); + } + } + +#else + + bool IsMMXState() { + return false; + } + + void ClearMMXState() { + } + + void VDClearEvilCPUStates() { + } + + void VDPreCheckExternalCodeCall(const char *file, int line) { + } + + void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine) { + } + +#endif diff --git a/src/thirdparty/VirtualDub/system/source/debugx86.cpp b/src/thirdparty/VirtualDub/system/source/debugx86.cpp index 6784d8d4434..f89fe560b04 100644 --- a/src/thirdparty/VirtualDub/system/source/debugx86.cpp +++ b/src/thirdparty/VirtualDub/system/source/debugx86.cpp @@ -1,156 +1,156 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include - -bool VDIsValidCallX86(const char *buf, int len) { - // Permissible CALL sequences that we care about: - // - // E8 xx xx xx xx CALL near relative - // FF (group 2) CALL near absolute indirect - // - // Minimum sequence is 2 bytes (call eax). - // Maximum sequence is 7 bytes (call dword ptr [eax+disp32]). - - if (len >= 5 && buf[-5] == (char)0xE8) - return true; - - // FF 14 xx CALL [reg32+reg32*scale] - - if (len >= 3 && buf[-3] == (char)0xFF && buf[-2]==0x14) - return true; - - // FF 15 xx xx xx xx CALL disp32 - - if (len >= 6 && buf[-6] == (char)0xFF && buf[-5]==0x15) - return true; - - // FF 00-3F(!14/15) CALL [reg32] - - if (len >= 2 && buf[-2] == (char)0xFF && (unsigned char)buf[-1] < 0x40) - return true; - - // FF D0-D7 CALL reg32 - - if (len >= 2 && buf[-2] == (char)0xFF && (buf[-1]&0xF8) == 0xD0) - return true; - - // FF 50-57 xx CALL [reg32+reg32*scale+disp8] - - if (len >= 3 && buf[-3] == (char)0xFF && (buf[-2]&0xF8) == 0x50) - return true; - - // FF 90-97 xx xx xx xx xx CALL [reg32+reg32*scale+disp32] - - if (len >= 7 && buf[-7] == (char)0xFF && (buf[-6]&0xF8) == 0x90) - return true; - - return false; -} - -VDInstructionTypeX86 VDGetInstructionTypeX86(const void *p) { - struct local { - static bool RangeHitTest(const uint8 *range, uint8 c) { - while(*range) { - if (c>=range[0] && c<=range[1]) - return true; - range += 2; - } - - return false; - } - }; - - VDInstructionTypeX86 type = kX86InstUnknown; - - vd_seh_guard_try { - unsigned char buf[8]; - - memcpy(buf, p, 8); - - if (buf[0] == 0x0f && buf[1] == 0x0f) - type = kX86Inst3DNow; // Conveniently, all 3DNow! instructions begin 0F 0F - else if ((buf[0] == 0xdb || buf[0] == 0xdf) && (buf[1]>=0xe8 && buf[1]<=0xf7)) - type = kX86InstP6; // DB/DF E8-F7: FCOMI/FCOMIP/FUCOMI/FUCOMIP (P6) - else if ((buf[0]&0xfe)==0xda && (buf[1]&0xe0)==0xc0) - type = kX86InstP6; // DA/DB C0-DF: FCMOVcc (P6) - else if (buf[0] == 0x0f && (buf[1]&0xf0)==0x40) - type = kX86InstP6; // 0F 40-4F: CMOVcc (P6) - else { - const unsigned char *s = buf; - bool bWide = false; - bool bRepF2 = false; - bool bRepF3 = false; - - // At this point we're down to MMX, SSE, SSE2 -- which makes things simpler - // as we must see F2 0F, F3 0F, or 0F next. MMX ops use 0F exclusively, - // some SSE ops use F2, and a few SSE2 ones use F3. If we see 66 on an - // MMX or SSE op it's automatically SSE2 as it's either a 128-bit MMX op - // or a double-precision version of an SSE one. - - if (*s == 0x66) { // 66h override used by SSE2 and is supposed to be ahead of F2/F3 in encodings - ++s; - bWide = true; - } - - if (*s == 0xf2) { - ++s; - bRepF2 = true; - } - - if (*s == 0xf3) { - ++s; - bRepF3 = true; - } - - if (*s++ == 0x0f) { - // SSE - 1x, 28-2F, 5x, C2, AE - // MMX2 - 70, C4-C6, D7, DA, DE, E0, E3, E4, E7, EA, EE, F6, F7 - // MMX - 6x, 7x, Dx, Ex, and Fx except for MMX2 - // SSE2 - C3, SSE ops with 66 or F2, MMX/MMX2 ops with 66/F2/F3 - - static const uint8 sse_ranges[]={0x10,0x1f,0x28,0x2f,0x50,0x5f,0xc2,0xc2,0xae,0xae,0}; - static const uint8 sse2_ranges[]={0xc3,0xc3,0}; - static const uint8 mmx2_ranges[]={0x70,0x70,0xc4,0xc6,0xd7,0xd7,0xda,0xda,0xde,0xde,0xe0,0xe0,0xe3,0xe4,0xe7,0xe7,0xea,0xea,0xee,0xee,0xf6,0xf7,0}; - static const uint8 mmx_ranges[]={0x60,0x7f,0xd0,0xff,0}; - - if (local::RangeHitTest(sse_ranges, *s)) - type = (bWide||bRepF2) ? kX86InstSSE2 : kX86InstSSE; - else if (local::RangeHitTest(sse2_ranges, *s)) - type = kX86InstSSE2; - else if (local::RangeHitTest(mmx2_ranges, *s)) - type = (bWide||bRepF2||bRepF3) ? kX86InstSSE2 : kX86InstMMX2; - else if (local::RangeHitTest(mmx_ranges, *s)) - type = (bWide||bRepF2||bRepF3) ? kX86InstSSE2 : kX86InstMMX; - } - } - } vd_seh_guard_except { - } - - return type; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include + +bool VDIsValidCallX86(const char *buf, int len) { + // Permissible CALL sequences that we care about: + // + // E8 xx xx xx xx CALL near relative + // FF (group 2) CALL near absolute indirect + // + // Minimum sequence is 2 bytes (call eax). + // Maximum sequence is 7 bytes (call dword ptr [eax+disp32]). + + if (len >= 5 && buf[-5] == (char)0xE8) + return true; + + // FF 14 xx CALL [reg32+reg32*scale] + + if (len >= 3 && buf[-3] == (char)0xFF && buf[-2]==0x14) + return true; + + // FF 15 xx xx xx xx CALL disp32 + + if (len >= 6 && buf[-6] == (char)0xFF && buf[-5]==0x15) + return true; + + // FF 00-3F(!14/15) CALL [reg32] + + if (len >= 2 && buf[-2] == (char)0xFF && (unsigned char)buf[-1] < 0x40) + return true; + + // FF D0-D7 CALL reg32 + + if (len >= 2 && buf[-2] == (char)0xFF && (buf[-1]&0xF8) == 0xD0) + return true; + + // FF 50-57 xx CALL [reg32+reg32*scale+disp8] + + if (len >= 3 && buf[-3] == (char)0xFF && (buf[-2]&0xF8) == 0x50) + return true; + + // FF 90-97 xx xx xx xx xx CALL [reg32+reg32*scale+disp32] + + if (len >= 7 && buf[-7] == (char)0xFF && (buf[-6]&0xF8) == 0x90) + return true; + + return false; +} + +VDInstructionTypeX86 VDGetInstructionTypeX86(const void *p) { + struct local { + static bool RangeHitTest(const uint8 *range, uint8 c) { + while(*range) { + if (c>=range[0] && c<=range[1]) + return true; + range += 2; + } + + return false; + } + }; + + VDInstructionTypeX86 type = kX86InstUnknown; + + vd_seh_guard_try { + unsigned char buf[8]; + + memcpy(buf, p, 8); + + if (buf[0] == 0x0f && buf[1] == 0x0f) + type = kX86Inst3DNow; // Conveniently, all 3DNow! instructions begin 0F 0F + else if ((buf[0] == 0xdb || buf[0] == 0xdf) && (buf[1]>=0xe8 && buf[1]<=0xf7)) + type = kX86InstP6; // DB/DF E8-F7: FCOMI/FCOMIP/FUCOMI/FUCOMIP (P6) + else if ((buf[0]&0xfe)==0xda && (buf[1]&0xe0)==0xc0) + type = kX86InstP6; // DA/DB C0-DF: FCMOVcc (P6) + else if (buf[0] == 0x0f && (buf[1]&0xf0)==0x40) + type = kX86InstP6; // 0F 40-4F: CMOVcc (P6) + else { + const unsigned char *s = buf; + bool bWide = false; + bool bRepF2 = false; + bool bRepF3 = false; + + // At this point we're down to MMX, SSE, SSE2 -- which makes things simpler + // as we must see F2 0F, F3 0F, or 0F next. MMX ops use 0F exclusively, + // some SSE ops use F2, and a few SSE2 ones use F3. If we see 66 on an + // MMX or SSE op it's automatically SSE2 as it's either a 128-bit MMX op + // or a double-precision version of an SSE one. + + if (*s == 0x66) { // 66h override used by SSE2 and is supposed to be ahead of F2/F3 in encodings + ++s; + bWide = true; + } + + if (*s == 0xf2) { + ++s; + bRepF2 = true; + } + + if (*s == 0xf3) { + ++s; + bRepF3 = true; + } + + if (*s++ == 0x0f) { + // SSE - 1x, 28-2F, 5x, C2, AE + // MMX2 - 70, C4-C6, D7, DA, DE, E0, E3, E4, E7, EA, EE, F6, F7 + // MMX - 6x, 7x, Dx, Ex, and Fx except for MMX2 + // SSE2 - C3, SSE ops with 66 or F2, MMX/MMX2 ops with 66/F2/F3 + + static const uint8 sse_ranges[]={0x10,0x1f,0x28,0x2f,0x50,0x5f,0xc2,0xc2,0xae,0xae,0}; + static const uint8 sse2_ranges[]={0xc3,0xc3,0}; + static const uint8 mmx2_ranges[]={0x70,0x70,0xc4,0xc6,0xd7,0xd7,0xda,0xda,0xde,0xde,0xe0,0xe0,0xe3,0xe4,0xe7,0xe7,0xea,0xea,0xee,0xee,0xf6,0xf7,0}; + static const uint8 mmx_ranges[]={0x60,0x7f,0xd0,0xff,0}; + + if (local::RangeHitTest(sse_ranges, *s)) + type = (bWide||bRepF2) ? kX86InstSSE2 : kX86InstSSE; + else if (local::RangeHitTest(sse2_ranges, *s)) + type = kX86InstSSE2; + else if (local::RangeHitTest(mmx2_ranges, *s)) + type = (bWide||bRepF2||bRepF3) ? kX86InstSSE2 : kX86InstMMX2; + else if (local::RangeHitTest(mmx_ranges, *s)) + type = (bWide||bRepF2||bRepF3) ? kX86InstSSE2 : kX86InstMMX; + } + } + } vd_seh_guard_except { + } + + return type; +} diff --git a/src/thirdparty/VirtualDub/system/source/event.cpp b/src/thirdparty/VirtualDub/system/source/event.cpp index 70e8e853426..db1a5f8dc82 100644 --- a/src/thirdparty/VirtualDub/system/source/event.cpp +++ b/src/thirdparty/VirtualDub/system/source/event.cpp @@ -1,88 +1,88 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -VDDelegate::VDDelegate() { - mpPrev = mpNext = this; -} - -VDDelegate::~VDDelegate() { - VDDelegateNode *next = mpNext; - VDDelegateNode *prev = mpPrev; - prev->mpNext = next; - next->mpPrev = prev; -} - -/////////////////////////////////////////////////////////////////////////////// - -VDEventBase::VDEventBase() { - mAnchor.mpPrev = mAnchor.mpNext = &mAnchor; -} - -VDEventBase::~VDEventBase() { - while(mAnchor.mpPrev != &mAnchor) - Remove(static_cast(*mAnchor.mpPrev)); -} - -void VDEventBase::Add(VDDelegate& dbase) { - VDDelegateNode *next = mAnchor.mpNext; - - VDASSERT(dbase.mpPrev == &dbase); - - mAnchor.mpNext = &dbase; - dbase.mpPrev = &mAnchor; - dbase.mpNext = next; - next->mpPrev = &dbase; -} - -void VDEventBase::Remove(VDDelegate& dbase) { - VDASSERT(dbase.mpPrev != &dbase); - - VDDelegateNode *next = dbase.mpNext; - VDDelegateNode *prev = dbase.mpPrev; - prev->mpNext = next; - next->mpPrev = prev; - dbase.mpPrev = dbase.mpNext = &dbase; -} - -void VDEventBase::Raise(void *src, const void *info) { - // We allow the specific case of removing the delegate that's being removed. - VDDelegateNode *node = mAnchor.mpNext; - - while(node != &mAnchor) { - VDDelegateNode *next = node->mpNext; - - VDDelegate& dbase = static_cast(*node); - - dbase.mpCallback(src, info, dbase); - - node = next; - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +/////////////////////////////////////////////////////////////////////////////// + +VDDelegate::VDDelegate() { + mpPrev = mpNext = this; +} + +VDDelegate::~VDDelegate() { + VDDelegateNode *next = mpNext; + VDDelegateNode *prev = mpPrev; + prev->mpNext = next; + next->mpPrev = prev; +} + +/////////////////////////////////////////////////////////////////////////////// + +VDEventBase::VDEventBase() { + mAnchor.mpPrev = mAnchor.mpNext = &mAnchor; +} + +VDEventBase::~VDEventBase() { + while(mAnchor.mpPrev != &mAnchor) + Remove(static_cast(*mAnchor.mpPrev)); +} + +void VDEventBase::Add(VDDelegate& dbase) { + VDDelegateNode *next = mAnchor.mpNext; + + VDASSERT(dbase.mpPrev == &dbase); + + mAnchor.mpNext = &dbase; + dbase.mpPrev = &mAnchor; + dbase.mpNext = next; + next->mpPrev = &dbase; +} + +void VDEventBase::Remove(VDDelegate& dbase) { + VDASSERT(dbase.mpPrev != &dbase); + + VDDelegateNode *next = dbase.mpNext; + VDDelegateNode *prev = dbase.mpPrev; + prev->mpNext = next; + next->mpPrev = prev; + dbase.mpPrev = dbase.mpNext = &dbase; +} + +void VDEventBase::Raise(void *src, const void *info) { + // We allow the specific case of removing the delegate that's being removed. + VDDelegateNode *node = mAnchor.mpNext; + + while(node != &mAnchor) { + VDDelegateNode *next = node->mpNext; + + VDDelegate& dbase = static_cast(*node); + + dbase.mpCallback(src, info, dbase); + + node = next; + } +} diff --git a/src/thirdparty/VirtualDub/system/source/file.cpp b/src/thirdparty/VirtualDub/system/source/file.cpp index c7530445cbb..49415289e12 100644 --- a/src/thirdparty/VirtualDub/system/source/file.cpp +++ b/src/thirdparty/VirtualDub/system/source/file.cpp @@ -1,430 +1,430 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -#include -#include -#include -#include - -namespace { - bool IsWindowsNT() { - static bool sbIsNT = (LONG)GetVersion()>=0; - return sbIsNT; - } - - bool IsHardDrivePath(const wchar_t *path) { - const VDStringW rootPath(VDFileGetRootPath(path)); - - UINT type = GetDriveTypeW(rootPath.c_str()); - - return type == DRIVE_FIXED || type == DRIVE_UNKNOWN || type == DRIVE_REMOVABLE; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// -// VDFile -// -/////////////////////////////////////////////////////////////////////////////// - -using namespace nsVDFile; - -VDFile::VDFile(const char *pszFileName, uint32 flags) - : mhFile(NULL) -{ - open_internal(pszFileName, NULL, flags, true); -} - -VDFile::VDFile(const wchar_t *pwszFileName, uint32 flags) - : mhFile(NULL) -{ - open_internal(NULL, pwszFileName, flags, true); -} - -VDFile::VDFile(HANDLE h) - : mhFile(h) -{ - LONG lo, hi = 0; - - lo = SetFilePointer(h, 0, &hi, FILE_CURRENT); - - mFilePosition = (uint32)lo + ((uint64)(uint32)hi << 32); -} - -VDFile::~VDFile() { - closeNT(); -} - -void VDFile::open(const char *pszFilename, uint32 flags) { - open_internal(pszFilename, NULL, flags, true); -} - -void VDFile::open(const wchar_t *pwszFilename, uint32 flags) { - open_internal(NULL, pwszFilename, flags, true); -} - -bool VDFile::openNT(const wchar_t *pwszFilename, uint32 flags) { - return open_internal(NULL, pwszFilename, flags, false); -} - -bool VDFile::open_internal(const char *pszFilename, const wchar_t *pwszFilename, uint32 flags, bool throwOnError) { - close(); - - mpFilename = _wcsdup(VDFileSplitPath(pszFilename ? VDTextAToW(pszFilename).c_str() : pwszFilename)); - if (!mpFilename) { - if (!throwOnError) - return false; - throw MyMemoryError(); - } - - // At least one of the read/write flags must be set. - VDASSERT(flags & (kRead | kWrite)); - - DWORD dwDesiredAccess = 0; - - if (flags & kRead) dwDesiredAccess = GENERIC_READ; - if (flags & kWrite) dwDesiredAccess |= GENERIC_WRITE; - - // Win32 docs are screwed here -- FILE_SHARE_xxx is the inverse of a deny flag. - - DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; - if (flags & kDenyRead) dwShareMode = FILE_SHARE_WRITE; - if (flags & kDenyWrite) dwShareMode &= ~FILE_SHARE_WRITE; - - // One of the creation flags must be set. - VDASSERT(flags & kCreationMask); - - DWORD dwCreationDisposition; - - uint32 creationType = flags & kCreationMask; - - switch(creationType) { - case kOpenExisting: dwCreationDisposition = OPEN_EXISTING; break; - case kOpenAlways: dwCreationDisposition = OPEN_ALWAYS; break; - case kCreateAlways: dwCreationDisposition = CREATE_ALWAYS; break; - case kCreateNew: dwCreationDisposition = CREATE_NEW; break; - case kTruncateExisting: dwCreationDisposition = TRUNCATE_EXISTING; break; - default: - VDNEVERHERE; - return false; - } - - VDASSERT((flags & (kSequential | kRandomAccess)) != (kSequential | kRandomAccess)); - - DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL; - - if (flags & kSequential) dwAttributes |= FILE_FLAG_SEQUENTIAL_SCAN; - if (flags & kRandomAccess) dwAttributes |= FILE_FLAG_RANDOM_ACCESS; - if (flags & kWriteThrough) dwAttributes |= FILE_FLAG_WRITE_THROUGH; - if (flags & kUnbuffered) dwAttributes |= FILE_FLAG_NO_BUFFERING; - - VDStringA tempFilenameA; - VDStringW tempFilenameW; - - if (IsWindowsNT()) { - if (pszFilename) { - tempFilenameW = VDTextAToW(pszFilename); - pwszFilename = tempFilenameW.c_str(); - pszFilename = NULL; - } - } else { - if (pwszFilename) { - tempFilenameA = VDTextWToA(pwszFilename); - pszFilename = tempFilenameA.c_str(); - pwszFilename = NULL; - } - } - - if (pszFilename) - mhFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); - else { - if (!IsHardDrivePath(pwszFilename)) - flags &= ~FILE_FLAG_NO_BUFFERING; - - mhFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); - } - - DWORD err = GetLastError(); - - // If we failed and FILE_FLAG_NO_BUFFERING was set, strip it and try again. - // VPC and Novell shares sometimes do this.... - if (mhFile == INVALID_HANDLE_VALUE && err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) { - if (dwAttributes & FILE_FLAG_NO_BUFFERING) { - dwAttributes &= ~FILE_FLAG_NO_BUFFERING; - dwAttributes |= FILE_FLAG_WRITE_THROUGH; - - if (pszFilename) - mhFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); - else - mhFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); - - err = GetLastError(); - } - } - - // INVALID_HANDLE_VALUE isn't NULL. *sigh* - - if (mhFile == INVALID_HANDLE_VALUE) { - mhFile = NULL; - - if (!throwOnError) - return false; - - throw MyWin32Error("Cannot open file \"%ls\":\n%%s", err, mpFilename.get()); - } - - mFilePosition = 0; - return true; -} - -bool VDFile::closeNT() { - if (mhFile) { - HANDLE h = mhFile; - mhFile = NULL; - if (!CloseHandle(h)) - return false; - } - - return true; -} - -void VDFile::close() { - if (!closeNT()) - throw MyWin32Error("Cannot complete file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::truncateNT() { - return 0 != SetEndOfFile(mhFile); -} - -void VDFile::truncate() { - if (!truncateNT()) - throw MyWin32Error("Cannot truncate file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::extendValidNT(sint64 pos) { - if (GetVersion() & 0x80000000) - return true; // No need, Windows 95/98/ME do this automatically anyway. - - // The SetFileValidData() API is only available on XP and Server 2003. - - typedef BOOL (APIENTRY *tpSetFileValidData)(HANDLE hFile, LONGLONG ValidDataLength); // Windows XP, Server 2003 - static tpSetFileValidData pSetFileValidData = (tpSetFileValidData)GetProcAddress(GetModuleHandle("kernel32"), "SetFileValidData"); - - if (!pSetFileValidData) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; - } - - return 0 != pSetFileValidData(mhFile, pos); -} - -void VDFile::extendValid(sint64 pos) { - if (!extendValidNT(pos)) - throw MyWin32Error("Cannot extend file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::enableExtendValid() { - if (GetVersion() & 0x80000000) - return true; // Not Windows NT, no privileges involved - - // SetFileValidData() requires the SE_MANAGE_VOLUME_NAME privilege, so we must enable it - // on the process token. We don't attempt to strip the privilege afterward as that would - // introduce race conditions. - bool bSuccessful = false; - DWORD err = 0; - - SetLastError(0); - - HANDLE h; - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &h)) { - LUID luid; - - if (LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &luid)) { - TOKEN_PRIVILEGES tp; - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - if (AdjustTokenPrivileges(h, FALSE, &tp, 0, NULL, NULL)) - bSuccessful = true; - else - err = GetLastError(); - } - - CloseHandle(h); - } - - if (!bSuccessful && err) - SetLastError(err); - - return bSuccessful; -} - -long VDFile::readData(void *buffer, long length) { - DWORD dwActual; - - if (!ReadFile(mhFile, buffer, (DWORD)length, &dwActual, NULL)) - throw MyWin32Error("Cannot read from file \"%ls\": %%s", GetLastError(), mpFilename.get()); - - mFilePosition += dwActual; - - return dwActual; -} - -void VDFile::read(void *buffer, long length) { - if (length != readData(buffer, length)) - throw MyWin32Error("Cannot read from file \"%ls\": Premature end of file.", GetLastError(), mpFilename.get()); -} - -long VDFile::writeData(const void *buffer, long length) { - DWORD dwActual; - bool success = false; - - if (!WriteFile(mhFile, buffer, (DWORD)length, &dwActual, NULL) || dwActual != (DWORD)length) - goto found_error; - - mFilePosition += dwActual; - - return dwActual; - -found_error: - throw MyWin32Error("Cannot write to file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -void VDFile::write(const void *buffer, long length) { - if (length != writeData(buffer, length)) - throw MyWin32Error("Cannot write to file \"%ls\": Unable to write all data.", GetLastError(), mpFilename.get()); -} - -bool VDFile::seekNT(sint64 newPos, eSeekMode mode) { - DWORD dwMode; - - switch(mode) { - case kSeekStart: - dwMode = FILE_BEGIN; - break; - case kSeekCur: - dwMode = FILE_CURRENT; - break; - case kSeekEnd: - dwMode = FILE_END; - break; - default: - VDNEVERHERE; - return false; - } - - union { - sint64 pos; - LONG l[2]; - } u = { newPos }; - - u.l[0] = SetFilePointer(mhFile, u.l[0], &u.l[1], dwMode); - - if (u.l[0] == -1 && GetLastError() != NO_ERROR) - return false; - - mFilePosition = u.pos; - return true; -} - -void VDFile::seek(sint64 newPos, eSeekMode mode) { - if (!seekNT(newPos, mode)) - throw MyWin32Error("Cannot seek within file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::skipNT(sint64 delta) { - if (!delta) - return true; - - char buf[1024]; - - if (delta <= sizeof buf) { - return (long)delta == readData(buf, (long)delta); - } else - return seekNT(delta, kSeekCur); -} - -void VDFile::skip(sint64 delta) { - if (!delta) - return; - - char buf[1024]; - - if (delta > 0 && delta <= sizeof buf) { - if ((long)delta != readData(buf, (long)delta)) - throw MyWin32Error("Cannot seek within file \"%ls\": %%s", GetLastError(), mpFilename.get()); - } else - seek(delta, kSeekCur); -} - -sint64 VDFile::size() { - union { - uint64 siz; - DWORD l[2]; - } u; - - u.l[0] = GetFileSize(mhFile, &u.l[1]); - - DWORD err; - - if (u.l[0] == (DWORD)-1L && (err = GetLastError()) != NO_ERROR) - throw MyWin32Error("Cannot retrieve size of file \"%ls\": %%s", GetLastError(), mpFilename.get()); - - return (sint64)u.siz; -} - -sint64 VDFile::tell() { - return mFilePosition; -} - -bool VDFile::flushNT() { - return 0 != FlushFileBuffers(mhFile); -} - -void VDFile::flush() { - if (!flushNT()) - throw MyWin32Error("Cannot flush file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::isOpen() { - return mhFile != 0; -} - -VDFileHandle VDFile::getRawHandle() { - return mhFile; -} - -void *VDFile::AllocUnbuffer(size_t nBytes) { - return VirtualAlloc(NULL, nBytes, MEM_COMMIT, PAGE_READWRITE); -} - -void VDFile::FreeUnbuffer(void *p) { - VirtualFree(p, 0, MEM_RELEASE); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include +#include +#include +#include + +namespace { + bool IsWindowsNT() { + static bool sbIsNT = (LONG)GetVersion()>=0; + return sbIsNT; + } + + bool IsHardDrivePath(const wchar_t *path) { + const VDStringW rootPath(VDFileGetRootPath(path)); + + UINT type = GetDriveTypeW(rootPath.c_str()); + + return type == DRIVE_FIXED || type == DRIVE_UNKNOWN || type == DRIVE_REMOVABLE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// VDFile +// +/////////////////////////////////////////////////////////////////////////////// + +using namespace nsVDFile; + +VDFile::VDFile(const char *pszFileName, uint32 flags) + : mhFile(NULL) +{ + open_internal(pszFileName, NULL, flags, true); +} + +VDFile::VDFile(const wchar_t *pwszFileName, uint32 flags) + : mhFile(NULL) +{ + open_internal(NULL, pwszFileName, flags, true); +} + +VDFile::VDFile(HANDLE h) + : mhFile(h) +{ + LONG lo, hi = 0; + + lo = SetFilePointer(h, 0, &hi, FILE_CURRENT); + + mFilePosition = (uint32)lo + ((uint64)(uint32)hi << 32); +} + +VDFile::~VDFile() { + closeNT(); +} + +void VDFile::open(const char *pszFilename, uint32 flags) { + open_internal(pszFilename, NULL, flags, true); +} + +void VDFile::open(const wchar_t *pwszFilename, uint32 flags) { + open_internal(NULL, pwszFilename, flags, true); +} + +bool VDFile::openNT(const wchar_t *pwszFilename, uint32 flags) { + return open_internal(NULL, pwszFilename, flags, false); +} + +bool VDFile::open_internal(const char *pszFilename, const wchar_t *pwszFilename, uint32 flags, bool throwOnError) { + close(); + + mpFilename = _wcsdup(VDFileSplitPath(pszFilename ? VDTextAToW(pszFilename).c_str() : pwszFilename)); + if (!mpFilename) { + if (!throwOnError) + return false; + throw MyMemoryError(); + } + + // At least one of the read/write flags must be set. + VDASSERT(flags & (kRead | kWrite)); + + DWORD dwDesiredAccess = 0; + + if (flags & kRead) dwDesiredAccess = GENERIC_READ; + if (flags & kWrite) dwDesiredAccess |= GENERIC_WRITE; + + // Win32 docs are screwed here -- FILE_SHARE_xxx is the inverse of a deny flag. + + DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + if (flags & kDenyRead) dwShareMode = FILE_SHARE_WRITE; + if (flags & kDenyWrite) dwShareMode &= ~FILE_SHARE_WRITE; + + // One of the creation flags must be set. + VDASSERT(flags & kCreationMask); + + DWORD dwCreationDisposition; + + uint32 creationType = flags & kCreationMask; + + switch(creationType) { + case kOpenExisting: dwCreationDisposition = OPEN_EXISTING; break; + case kOpenAlways: dwCreationDisposition = OPEN_ALWAYS; break; + case kCreateAlways: dwCreationDisposition = CREATE_ALWAYS; break; + case kCreateNew: dwCreationDisposition = CREATE_NEW; break; + case kTruncateExisting: dwCreationDisposition = TRUNCATE_EXISTING; break; + default: + VDNEVERHERE; + return false; + } + + VDASSERT((flags & (kSequential | kRandomAccess)) != (kSequential | kRandomAccess)); + + DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL; + + if (flags & kSequential) dwAttributes |= FILE_FLAG_SEQUENTIAL_SCAN; + if (flags & kRandomAccess) dwAttributes |= FILE_FLAG_RANDOM_ACCESS; + if (flags & kWriteThrough) dwAttributes |= FILE_FLAG_WRITE_THROUGH; + if (flags & kUnbuffered) dwAttributes |= FILE_FLAG_NO_BUFFERING; + + VDStringA tempFilenameA; + VDStringW tempFilenameW; + + if (IsWindowsNT()) { + if (pszFilename) { + tempFilenameW = VDTextAToW(pszFilename); + pwszFilename = tempFilenameW.c_str(); + pszFilename = NULL; + } + } else { + if (pwszFilename) { + tempFilenameA = VDTextWToA(pwszFilename); + pszFilename = tempFilenameA.c_str(); + pwszFilename = NULL; + } + } + + if (pszFilename) + mhFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); + else { + if (!IsHardDrivePath(pwszFilename)) + flags &= ~FILE_FLAG_NO_BUFFERING; + + mhFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); + } + + DWORD err = GetLastError(); + + // If we failed and FILE_FLAG_NO_BUFFERING was set, strip it and try again. + // VPC and Novell shares sometimes do this.... + if (mhFile == INVALID_HANDLE_VALUE && err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) { + if (dwAttributes & FILE_FLAG_NO_BUFFERING) { + dwAttributes &= ~FILE_FLAG_NO_BUFFERING; + dwAttributes |= FILE_FLAG_WRITE_THROUGH; + + if (pszFilename) + mhFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); + else + mhFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); + + err = GetLastError(); + } + } + + // INVALID_HANDLE_VALUE isn't NULL. *sigh* + + if (mhFile == INVALID_HANDLE_VALUE) { + mhFile = NULL; + + if (!throwOnError) + return false; + + throw MyWin32Error("Cannot open file \"%ls\":\n%%s", err, mpFilename.get()); + } + + mFilePosition = 0; + return true; +} + +bool VDFile::closeNT() { + if (mhFile) { + HANDLE h = mhFile; + mhFile = NULL; + if (!CloseHandle(h)) + return false; + } + + return true; +} + +void VDFile::close() { + if (!closeNT()) + throw MyWin32Error("Cannot complete file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::truncateNT() { + return 0 != SetEndOfFile(mhFile); +} + +void VDFile::truncate() { + if (!truncateNT()) + throw MyWin32Error("Cannot truncate file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::extendValidNT(sint64 pos) { + if (GetVersion() & 0x80000000) + return true; // No need, Windows 95/98/ME do this automatically anyway. + + // The SetFileValidData() API is only available on XP and Server 2003. + + typedef BOOL (APIENTRY *tpSetFileValidData)(HANDLE hFile, LONGLONG ValidDataLength); // Windows XP, Server 2003 + static tpSetFileValidData pSetFileValidData = (tpSetFileValidData)GetProcAddress(GetModuleHandle("kernel32"), "SetFileValidData"); + + if (!pSetFileValidData) { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return false; + } + + return 0 != pSetFileValidData(mhFile, pos); +} + +void VDFile::extendValid(sint64 pos) { + if (!extendValidNT(pos)) + throw MyWin32Error("Cannot extend file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::enableExtendValid() { + if (GetVersion() & 0x80000000) + return true; // Not Windows NT, no privileges involved + + // SetFileValidData() requires the SE_MANAGE_VOLUME_NAME privilege, so we must enable it + // on the process token. We don't attempt to strip the privilege afterward as that would + // introduce race conditions. + bool bSuccessful = false; + DWORD err = 0; + + SetLastError(0); + + HANDLE h; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &h)) { + LUID luid; + + if (LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &luid)) { + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (AdjustTokenPrivileges(h, FALSE, &tp, 0, NULL, NULL)) + bSuccessful = true; + else + err = GetLastError(); + } + + CloseHandle(h); + } + + if (!bSuccessful && err) + SetLastError(err); + + return bSuccessful; +} + +long VDFile::readData(void *buffer, long length) { + DWORD dwActual; + + if (!ReadFile(mhFile, buffer, (DWORD)length, &dwActual, NULL)) + throw MyWin32Error("Cannot read from file \"%ls\": %%s", GetLastError(), mpFilename.get()); + + mFilePosition += dwActual; + + return dwActual; +} + +void VDFile::read(void *buffer, long length) { + if (length != readData(buffer, length)) + throw MyWin32Error("Cannot read from file \"%ls\": Premature end of file.", GetLastError(), mpFilename.get()); +} + +long VDFile::writeData(const void *buffer, long length) { + DWORD dwActual; + bool success = false; + + if (!WriteFile(mhFile, buffer, (DWORD)length, &dwActual, NULL) || dwActual != (DWORD)length) + goto found_error; + + mFilePosition += dwActual; + + return dwActual; + +found_error: + throw MyWin32Error("Cannot write to file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +void VDFile::write(const void *buffer, long length) { + if (length != writeData(buffer, length)) + throw MyWin32Error("Cannot write to file \"%ls\": Unable to write all data.", GetLastError(), mpFilename.get()); +} + +bool VDFile::seekNT(sint64 newPos, eSeekMode mode) { + DWORD dwMode; + + switch(mode) { + case kSeekStart: + dwMode = FILE_BEGIN; + break; + case kSeekCur: + dwMode = FILE_CURRENT; + break; + case kSeekEnd: + dwMode = FILE_END; + break; + default: + VDNEVERHERE; + return false; + } + + union { + sint64 pos; + LONG l[2]; + } u = { newPos }; + + u.l[0] = SetFilePointer(mhFile, u.l[0], &u.l[1], dwMode); + + if (u.l[0] == -1 && GetLastError() != NO_ERROR) + return false; + + mFilePosition = u.pos; + return true; +} + +void VDFile::seek(sint64 newPos, eSeekMode mode) { + if (!seekNT(newPos, mode)) + throw MyWin32Error("Cannot seek within file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::skipNT(sint64 delta) { + if (!delta) + return true; + + char buf[1024]; + + if (delta <= sizeof buf) { + return (long)delta == readData(buf, (long)delta); + } else + return seekNT(delta, kSeekCur); +} + +void VDFile::skip(sint64 delta) { + if (!delta) + return; + + char buf[1024]; + + if (delta > 0 && delta <= sizeof buf) { + if ((long)delta != readData(buf, (long)delta)) + throw MyWin32Error("Cannot seek within file \"%ls\": %%s", GetLastError(), mpFilename.get()); + } else + seek(delta, kSeekCur); +} + +sint64 VDFile::size() { + union { + uint64 siz; + DWORD l[2]; + } u; + + u.l[0] = GetFileSize(mhFile, &u.l[1]); + + DWORD err; + + if (u.l[0] == (DWORD)-1L && (err = GetLastError()) != NO_ERROR) + throw MyWin32Error("Cannot retrieve size of file \"%ls\": %%s", GetLastError(), mpFilename.get()); + + return (sint64)u.siz; +} + +sint64 VDFile::tell() { + return mFilePosition; +} + +bool VDFile::flushNT() { + return 0 != FlushFileBuffers(mhFile); +} + +void VDFile::flush() { + if (!flushNT()) + throw MyWin32Error("Cannot flush file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::isOpen() { + return mhFile != 0; +} + +VDFileHandle VDFile::getRawHandle() { + return mhFile; +} + +void *VDFile::AllocUnbuffer(size_t nBytes) { + return VirtualAlloc(NULL, nBytes, MEM_COMMIT, PAGE_READWRITE); +} + +void VDFile::FreeUnbuffer(void *p) { + VirtualFree(p, 0, MEM_RELEASE); +} diff --git a/src/thirdparty/VirtualDub/system/source/fileasync.cpp b/src/thirdparty/VirtualDub/system/source/fileasync.cpp index a5e1734509d..b9d65b88ab9 100644 --- a/src/thirdparty/VirtualDub/system/source/fileasync.cpp +++ b/src/thirdparty/VirtualDub/system/source/fileasync.cpp @@ -1,925 +1,925 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// -// VDFileAsync - Windows 9x implementation -// -/////////////////////////////////////////////////////////////////////////// - -class VDFileAsync9x : public IVDFileAsync, protected VDThread { -public: - VDFileAsync9x(bool useFastMode, bool writeThrough); - ~VDFileAsync9x(); - - void SetPreemptiveExtend(bool b) { mbPreemptiveExtend = b; } - bool IsPreemptiveExtendActive() { return mbPreemptiveExtend; } - - bool IsOpen() { return mhFileSlow != INVALID_HANDLE_VALUE; } - - void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize); - void Open(VDFileHandle h, uint32 count, uint32 bufferSize); - void Close(); - void FastWrite(const void *pData, uint32 bytes); - void FastWriteEnd(); - void Write(sint64 pos, const void *pData, uint32 bytes); - bool Extend(sint64 pos); - void Truncate(sint64 pos); - void SafeTruncateAndClose(sint64 pos); - sint64 GetSize(); - sint64 GetFastWritePos() { return mClientFastPointer; } - -protected: - void WriteZero(sint64 pos, uint32 bytes); - void Seek(sint64 pos); - bool SeekNT(sint64 pos); - void ThrowError(); - void ThreadRun(); - - HANDLE mhFileSlow; - HANDLE mhFileFast; - uint32 mBlockSize; - uint32 mBlockCount; - uint32 mSectorSize; - sint64 mClientSlowPointer; - sint64 mClientFastPointer; - - const bool mbUseFastMode; - const bool mbWriteThrough; - - volatile bool mbPreemptiveExtend; - - enum { - kStateNormal, - kStateFlush, - kStateAbort - }; - VDAtomicInt mState; - - VDSignal mReadOccurred; - VDSignal mWriteOccurred; - - VDRingBuffer > mBuffer; - - VDStringA mFilename; - VDAtomicPtr mpError; -}; - -/////////////////////////////////////////////////////////////////////////// - -VDFileAsync9x::VDFileAsync9x(bool useFastMode, bool writeThrough) - : mhFileSlow(INVALID_HANDLE_VALUE) - , mhFileFast(INVALID_HANDLE_VALUE) - , mClientSlowPointer(0) - , mClientFastPointer(0) - , mbUseFastMode(useFastMode) - , mbWriteThrough(writeThrough) - , mbPreemptiveExtend(false) - , mpError(NULL) -{ -} - -VDFileAsync9x::~VDFileAsync9x() { - Close(); -} - -void VDFileAsync9x::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { - try { - mFilename = VDTextWToA(pszFilename); - - const DWORD slowFlags = mbWriteThrough ? FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH : FILE_ATTRIBUTE_NORMAL; - - mhFileSlow = CreateFile(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, slowFlags, NULL); - if (mhFileSlow == INVALID_HANDLE_VALUE) - throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); - - if (mbUseFastMode) - mhFileFast = CreateFile(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); - - mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). - - mBlockSize = bufferSize; - mBlockCount = count; - mBuffer.Init(count * bufferSize); - - mState = kStateNormal; - } catch(const MyError&) { - Close(); - throw; - } - - ThreadStart(); -} - -void VDFileAsync9x::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { - try { - mFilename = ""; - - HANDLE hProcess = GetCurrentProcess(); - if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) - throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); - - mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). - - mBlockSize = bufferSize; - mBlockCount = count; - mBuffer.Init(count * bufferSize); - - mState = kStateNormal; - } catch(const MyError&) { - Close(); - throw; - } - - ThreadStart(); -} - -void VDFileAsync9x::Close() { - mState = kStateAbort; - mWriteOccurred.signal(); - ThreadWait(); - - if (mhFileSlow != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileSlow); - mhFileSlow = INVALID_HANDLE_VALUE; - } - if (mhFileFast != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileFast); - mhFileFast = INVALID_HANDLE_VALUE; - } -} - -void VDFileAsync9x::FastWrite(const void *pData, uint32 bytes) { - if (mhFileFast == INVALID_HANDLE_VALUE) { - if (pData) - Write(mClientFastPointer, pData, bytes); - else - WriteZero(mClientFastPointer, bytes); - } else { - if (mpError) - ThrowError(); - - uint32 bytesLeft = bytes; - while(bytesLeft) { - int actual; - void *p = mBuffer.LockWrite(bytesLeft, actual); - - if (!actual) { - mReadOccurred.wait(); - if (mpError) - ThrowError(); - continue; - } - - if (pData) { - memcpy(p, pData, actual); - pData = (const char *)pData + actual; - } else { - memset(p, 0, actual); - } - mBuffer.UnlockWrite(actual); - mWriteOccurred.signal(); - bytesLeft -= actual; - } - } - - mClientFastPointer += bytes; -} - -void VDFileAsync9x::FastWriteEnd() { - FastWrite(NULL, mSectorSize - 1); - - mState = kStateFlush; - mWriteOccurred.signal(); - ThreadWait(); - - if (mpError) - ThrowError(); -} - -void VDFileAsync9x::Write(sint64 pos, const void *p, uint32 bytes) { - Seek(pos); - - DWORD dwActual; - if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || dwActual != bytes) { - mClientSlowPointer = -1; - throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); - } - - mClientSlowPointer += bytes; -} - -void VDFileAsync9x::WriteZero(sint64 pos, uint32 bytes) { - uint32 bufsize = bytes > 2048 ? 2048 : bytes; - void *p = _alloca(bufsize); - memset(p, 0, bufsize); - - while(bytes > 0) { - uint32 tc = bytes > 2048 ? 2048 : bytes; - - Write(pos, p, tc); - pos += tc; - bytes -= tc; - } -} - -bool VDFileAsync9x::Extend(sint64 pos) { - return SeekNT(pos) && SetEndOfFile(mhFileSlow); -} - -void VDFileAsync9x::Truncate(sint64 pos) { - Seek(pos); - if (!SetEndOfFile(mhFileSlow)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -void VDFileAsync9x::SafeTruncateAndClose(sint64 pos) { - if (mhFileSlow != INVALID_HANDLE_VALUE) { - FastWrite(NULL, mSectorSize - 1); - - mState = kStateFlush; - mWriteOccurred.signal(); - ThreadWait(); - - Extend(pos); - Close(); - } -} - -sint64 VDFileAsync9x::GetSize() { - DWORD dwSizeHigh; - DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); - - if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - return dwSizeLow + ((sint64)dwSizeHigh << 32); -} - -void VDFileAsync9x::Seek(sint64 pos) { - if (!SeekNT(pos)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -bool VDFileAsync9x::SeekNT(sint64 pos) { - if (mClientSlowPointer == pos) - return true; - - LONG posHi = (LONG)(pos >> 32); - DWORD result = SetFilePointer(mhFileSlow, (LONG)pos, &posHi, FILE_BEGIN); - - if (result == INVALID_SET_FILE_POINTER) { - DWORD dwError = GetLastError(); - - if (dwError != NO_ERROR) { - mClientSlowPointer = -1; - return false; - } - } - - mClientSlowPointer = pos; - - return true; -} - -void VDFileAsync9x::ThrowError() { - MyError *e = mpError.xchg(NULL); - - if (e) { - if (mhFileFast != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileFast); - mhFileFast = INVALID_HANDLE_VALUE; - } - - MyError tmp; - tmp.TransferFrom(*e); - delete e; - throw tmp; - } -} - -void VDFileAsync9x::ThreadRun() { - bool bPreemptiveExtend = mbPreemptiveExtend; - sint64 currentSize; - sint64 pos = 0; - uint32 bufferSize = mBlockCount * mBlockSize; - HANDLE hFile = mhFileFast != INVALID_HANDLE_VALUE ? mhFileFast : mhFileSlow; - - try { - if (bPreemptiveExtend && !VDGetFileSizeW32(hFile, currentSize)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - for(;;) { - int state = mState; - - if (state == kStateAbort) - break; - - int actual; - const void *p = mBuffer.LockRead(mBlockSize, actual); - - if ((uint32)actual < mBlockSize) { - if (state == kStateNormal) { - mWriteOccurred.wait(); - continue; - } - - VDASSERT(state == kStateFlush); - - actual &= ~(mSectorSize-1); - if (!actual) - break; - } else { - if (bPreemptiveExtend) { - sint64 checkpt = pos + mBlockSize + bufferSize; - - if (checkpt > currentSize) { - currentSize += bufferSize; - if (currentSize < checkpt) - currentSize = checkpt; - - if (!VDSetFilePointerW32(hFile, currentSize, FILE_BEGIN) - || !SetEndOfFile(hFile)) - mbPreemptiveExtend = bPreemptiveExtend = false; - - if (!VDSetFilePointerW32(hFile, pos, FILE_BEGIN)) - throw MyWin32Error("Seek error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); - } - } - } - - DWORD dwActual; - if (!WriteFile(hFile, p, actual, &dwActual, NULL) || dwActual != actual) { - DWORD dwError = GetLastError(); - throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", dwError, mFilename.c_str()); - } - - pos += actual; - - mBuffer.UnlockRead(actual); - - mReadOccurred.signal(); - } - } catch(MyError& e) { - MyError *p = new MyError; - - p->TransferFrom(e); - delete mpError.xchg(p); - mReadOccurred.signal(); - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDFileAsync - Windows NT implementation -// -/////////////////////////////////////////////////////////////////////////// - -struct VDFileAsyncNTBuffer : public OVERLAPPED { - bool mbActive; - bool mbPending; - uint32 mLength; - - VDFileAsyncNTBuffer() : mbActive(false), mbPending(false) { hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } - ~VDFileAsyncNTBuffer() { if (hEvent) CloseHandle(hEvent); } -}; - -class VDFileAsyncNT : public IVDFileAsync, private VDThread { -public: - VDFileAsyncNT(); - ~VDFileAsyncNT(); - - void SetPreemptiveExtend(bool b) { mbPreemptiveExtend = b; } - bool IsPreemptiveExtendActive() { return mbPreemptiveExtend; } - - bool IsOpen() { return mhFileSlow != INVALID_HANDLE_VALUE; } - - void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize); - void Open(VDFileHandle h, uint32 count, uint32 bufferSize); - void Close(); - void FastWrite(const void *pData, uint32 bytes); - void FastWriteEnd(); - void Write(sint64 pos, const void *pData, uint32 bytes); - bool Extend(sint64 pos); - void Truncate(sint64 pos); - void SafeTruncateAndClose(sint64 pos); - sint64 GetSize(); - sint64 GetFastWritePos() { return mClientFastPointer; } - -protected: - void WriteZero(sint64 pos, uint32 bytes); - void Seek(sint64 pos); - bool SeekNT(sint64 pos); - void ThrowError(); - void ThreadRun(); - - HANDLE mhFileSlow; - HANDLE mhFileFast; - uint32 mBlockSize; - uint32 mBlockCount; - uint32 mBufferSize; - uint32 mSectorSize; - - enum { - kStateNormal, - kStateFlush, - kStateAbort - }; - VDAtomicInt mState; - - VDSignal mReadOccurred; - VDSignal mWriteOccurred; - - uint32 mWriteOffset; - VDAtomicInt mBufferLevel; - sint64 mClientSlowPointer; - sint64 mClientFastPointer; - sint64 mFastPointer; - - volatile bool mbPreemptiveExtend; - - vdautoarrayptr mpBlocks; - - vdblock > mBuffer; - - VDAtomicPtr mpError; - VDStringA mFilename; -}; - -VDFileAsyncNT::VDFileAsyncNT() - : mhFileSlow(INVALID_HANDLE_VALUE) - , mhFileFast(INVALID_HANDLE_VALUE) - , mFastPointer(0) - , mClientSlowPointer(0) - , mClientFastPointer(0) - , mbPreemptiveExtend(false) - , mpError(NULL) -{ -} - -VDFileAsyncNT::~VDFileAsyncNT() { - Close(); -} - -void VDFileAsyncNT::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { - try { - mFilename = VDTextWToA(pszFilename); - - mhFileSlow = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (mhFileSlow == INVALID_HANDLE_VALUE) - throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); - - mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); - if (mhFileFast == INVALID_HANDLE_VALUE) - mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL); - - mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). - - mBlockSize = bufferSize; - mBlockCount = count; - mBufferSize = mBlockSize * mBlockCount; - - mWriteOffset = 0; - mBufferLevel = 0; - - mState = kStateNormal; - - if (mhFileFast != INVALID_HANDLE_VALUE) { - mpBlocks = new VDFileAsyncNTBuffer[count]; - mBuffer.resize(count * bufferSize); - ThreadStart(); - } - } catch(const MyError&) { - Close(); - throw; - } -} - -void VDFileAsyncNT::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { - try { - mFilename = ""; - - HANDLE hProcess = GetCurrentProcess(); - if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) - throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); - - mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). - - mBlockSize = bufferSize; - mBlockCount = count; - mBufferSize = mBlockSize * mBlockCount; - - mWriteOffset = 0; - mBufferLevel = 0; - - mState = kStateNormal; - - if (mhFileFast != INVALID_HANDLE_VALUE) { - mpBlocks = new VDFileAsyncNTBuffer[count]; - mBuffer.resize(count * bufferSize); - ThreadStart(); - } - } catch(const MyError&) { - Close(); - throw; - } -} - -void VDFileAsyncNT::Close() { - mState = kStateAbort; - mWriteOccurred.signal(); - ThreadWait(); - - if (mpError) { - delete mpError; - mpError = NULL; - } - - if (mhFileSlow != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileSlow); - mhFileSlow = INVALID_HANDLE_VALUE; - } - if (mhFileFast != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileFast); - mhFileFast = INVALID_HANDLE_VALUE; - } - - mpBlocks = NULL; -} - -void VDFileAsyncNT::FastWrite(const void *pData, uint32 bytes) { - if (mhFileFast == INVALID_HANDLE_VALUE) { - if (pData) - Write(mClientFastPointer, pData, bytes); - else - WriteZero(mClientFastPointer, bytes); - } else { - if (mpError) - ThrowError(); - - uint32 bytesLeft = bytes; - while(bytesLeft) { - uint32 actual = mBufferSize - mBufferLevel; - - if (actual > bytesLeft) - actual = bytesLeft; - - if (mWriteOffset + actual > mBufferSize) - actual = mBufferSize - mWriteOffset; - - if (!actual) { - mReadOccurred.wait(); - if (mpError) - ThrowError(); - continue; - } - - if (pData) { - memcpy(&mBuffer[mWriteOffset], pData, actual); - pData = (const char *)pData + actual; - } else { - memset(&mBuffer[mWriteOffset], 0, actual); - } - - uint32 oldWriteOffset = mWriteOffset; - mWriteOffset += actual; - if (mWriteOffset >= mBufferSize) - mWriteOffset = 0; - mBufferLevel += actual; - - // only bother signaling if the write offset crossed a block boundary - if (oldWriteOffset % mBlockSize + actual >= mBlockSize) { - mWriteOccurred.signal(); - if (mpError) - ThrowError(); - } - - bytesLeft -= actual; - } - } - - mClientFastPointer += bytes; -} - -void VDFileAsyncNT::FastWriteEnd() { - if (mhFileFast != INVALID_HANDLE_VALUE) { - FastWrite(NULL, mSectorSize - 1); - mState = kStateFlush; - mWriteOccurred.signal(); - ThreadWait(); - } - - if (mpError) - ThrowError(); -} - -void VDFileAsyncNT::Write(sint64 pos, const void *p, uint32 bytes) { - Seek(pos); - - DWORD dwActual; - if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || (mClientSlowPointer += dwActual),(dwActual != bytes)) - throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -void VDFileAsyncNT::WriteZero(sint64 pos, uint32 bytes) { - uint32 bufsize = bytes > 2048 ? 2048 : bytes; - void *p = _alloca(bufsize); - memset(p, 0, bufsize); - - while(bytes > 0) { - uint32 tc = bytes > 2048 ? 2048 : bytes; - - Write(pos, p, tc); - pos += tc; - bytes -= tc; - } -} - -bool VDFileAsyncNT::Extend(sint64 pos) { - return SeekNT(pos) && SetEndOfFile(mhFileSlow); -} - -void VDFileAsyncNT::Truncate(sint64 pos) { - Seek(pos); - if (!SetEndOfFile(mhFileSlow)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -void VDFileAsyncNT::SafeTruncateAndClose(sint64 pos) { - if (isThreadAttached()) { - mState = kStateAbort; - mWriteOccurred.signal(); - ThreadWait(); - - if (mpError) { - delete mpError; - mpError = NULL; - } - } - - if (mhFileSlow != INVALID_HANDLE_VALUE) { - Extend(pos); - Close(); - } -} - -sint64 VDFileAsyncNT::GetSize() { - DWORD dwSizeHigh; - DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); - - if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - return dwSizeLow + ((sint64)dwSizeHigh << 32); -} - -void VDFileAsyncNT::Seek(sint64 pos) { - if (!SeekNT(pos)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -bool VDFileAsyncNT::SeekNT(sint64 pos) { - if (mClientSlowPointer == pos) - return true; - - LONG posHi = (LONG)(pos >> 32); - DWORD result = SetFilePointer(mhFileSlow, (LONG)pos, &posHi, FILE_BEGIN); - - if (result == INVALID_SET_FILE_POINTER) { - DWORD dwError = GetLastError(); - - if (dwError != NO_ERROR) - return false; - } - - mClientSlowPointer = pos; - return true; -} - -void VDFileAsyncNT::ThrowError() { - MyError *e = mpError.xchg(NULL); - - if (e) { - if (mhFileFast != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileFast); - mhFileFast = INVALID_HANDLE_VALUE; - } - - MyError tmp; - tmp.TransferFrom(*e); - delete e; - throw tmp; - } -} - -void VDFileAsyncNT::ThreadRun() { - int requestHead = 0; - int requestTail = 0; - int requestCount = mBlockCount; - uint32 pendingLevel = 0; - uint32 readOffset = 0; - bool bPreemptiveExtend = mbPreemptiveExtend; - sint64 currentSize; - - try { - if (!VDGetFileSizeW32(mhFileFast, currentSize)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - for(;;) { - int state = mState; - - if (state == kStateAbort) { - typedef BOOL (WINAPI *tpCancelIo)(HANDLE); - static const tpCancelIo pCancelIo = (tpCancelIo)GetProcAddress(GetModuleHandle("kernel32"), "CancelIo"); - pCancelIo(mhFileFast); - - // Wait for any pending blocks to complete. - for(int i=0; i= 0); - if (readOffset + actual > mBufferSize) - actual = mBufferSize - readOffset; - - if (actual < mBlockSize) { - if (state == kStateNormal || actual < mSectorSize) { - // check for blocks that have completed - bool blocksCompleted = false; - for(;;) { - VDFileAsyncNTBuffer& buf = mpBlocks[requestTail]; - - if (!buf.mbActive) { - if (state == kStateFlush) - goto all_done; - - if (!blocksCompleted) { - // wait for further writes - mWriteOccurred.wait(); - } - break; - } - - if (buf.mbPending) { - HANDLE h[2] = {buf.hEvent, mWriteOccurred.getHandle()}; - DWORD waitResult = WaitForMultipleObjects(2, h, FALSE, INFINITE); - - if (waitResult == WAIT_OBJECT_0+1) // write pending - break; - - DWORD dwActual; - if (!GetOverlappedResult(mhFileFast, &buf, &dwActual, TRUE)) - throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - } - - buf.mbActive = false; - - blocksCompleted = true; - - if (++requestTail >= requestCount) - requestTail = 0; - - mBufferLevel -= buf.mLength; - pendingLevel -= buf.mLength; - VDASSERT((int)mBufferLevel >= 0); - VDASSERT((int)pendingLevel >= 0); - - mReadOccurred.signal(); - - } - - continue; - } - - VDASSERT(state == kStateFlush); - - actual &= ~(mSectorSize-1); - - VDASSERT(actual > 0); - } else { - actual = mBlockSize; - - if (bPreemptiveExtend) { - sint64 checkpt = mFastPointer + mBlockSize + mBufferSize; - - if (checkpt > currentSize) { - currentSize += mBufferSize; - if (currentSize < checkpt) - currentSize = checkpt; - - if (!VDSetFilePointerW32(mhFileFast, currentSize, FILE_BEGIN) - || !SetEndOfFile(mhFileFast)) - mbPreemptiveExtend = bPreemptiveExtend = false; - } - } - } - - // Issue a write to OS - VDFileAsyncNTBuffer& buf = mpBlocks[requestHead]; - - VDASSERT(!buf.mbActive); - - DWORD dwActual; - - buf.Offset = (DWORD)mFastPointer; - buf.OffsetHigh = (DWORD)((uint64)mFastPointer >> 32); - buf.Internal = 0; - buf.InternalHigh = 0; - buf.mLength = actual; - buf.mbPending = false; - - if (!WriteFile(mhFileFast, &mBuffer[readOffset], actual, &dwActual, &buf)) { - if (GetLastError() != ERROR_IO_PENDING) - throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - buf.mbPending = true; - } - - buf.mbActive = true; - - pendingLevel += actual; - VDASSERT(pendingLevel <= (uint32)mBufferLevel); - - readOffset += actual; - VDASSERT(readOffset <= mBufferSize); - if (readOffset >= mBufferSize) - readOffset = 0; - - mFastPointer += actual; - - if (++requestHead >= requestCount) - requestHead = 0; - } -all_done: - ; - - } catch(MyError& e) { - MyError *p = new MyError; - - p->TransferFrom(e); - delete mpError.xchg(p); - mReadOccurred.signal(); - } -} - -/////////////////////////////////////////////////////////////////////////// - -IVDFileAsync *VDCreateFileAsync(IVDFileAsync::Mode mode) { - switch(mode) { - - case IVDFileAsync::kModeAsynchronous: - if (VDIsWindowsNT()) - return new VDFileAsyncNT; - // Can't do async I/O. Fall-through to 9x method. - case IVDFileAsync::kModeThreaded: - return new VDFileAsync9x(true, true); - - default: - return new VDFileAsync9x(false, true); - - case IVDFileAsync::kModeBuffered: - return new VDFileAsync9x(false, false); - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// +// VDFileAsync - Windows 9x implementation +// +/////////////////////////////////////////////////////////////////////////// + +class VDFileAsync9x : public IVDFileAsync, protected VDThread { +public: + VDFileAsync9x(bool useFastMode, bool writeThrough); + ~VDFileAsync9x(); + + void SetPreemptiveExtend(bool b) { mbPreemptiveExtend = b; } + bool IsPreemptiveExtendActive() { return mbPreemptiveExtend; } + + bool IsOpen() { return mhFileSlow != INVALID_HANDLE_VALUE; } + + void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize); + void Open(VDFileHandle h, uint32 count, uint32 bufferSize); + void Close(); + void FastWrite(const void *pData, uint32 bytes); + void FastWriteEnd(); + void Write(sint64 pos, const void *pData, uint32 bytes); + bool Extend(sint64 pos); + void Truncate(sint64 pos); + void SafeTruncateAndClose(sint64 pos); + sint64 GetSize(); + sint64 GetFastWritePos() { return mClientFastPointer; } + +protected: + void WriteZero(sint64 pos, uint32 bytes); + void Seek(sint64 pos); + bool SeekNT(sint64 pos); + void ThrowError(); + void ThreadRun(); + + HANDLE mhFileSlow; + HANDLE mhFileFast; + uint32 mBlockSize; + uint32 mBlockCount; + uint32 mSectorSize; + sint64 mClientSlowPointer; + sint64 mClientFastPointer; + + const bool mbUseFastMode; + const bool mbWriteThrough; + + volatile bool mbPreemptiveExtend; + + enum { + kStateNormal, + kStateFlush, + kStateAbort + }; + VDAtomicInt mState; + + VDSignal mReadOccurred; + VDSignal mWriteOccurred; + + VDRingBuffer > mBuffer; + + VDStringA mFilename; + VDAtomicPtr mpError; +}; + +/////////////////////////////////////////////////////////////////////////// + +VDFileAsync9x::VDFileAsync9x(bool useFastMode, bool writeThrough) + : mhFileSlow(INVALID_HANDLE_VALUE) + , mhFileFast(INVALID_HANDLE_VALUE) + , mClientSlowPointer(0) + , mClientFastPointer(0) + , mbUseFastMode(useFastMode) + , mbWriteThrough(writeThrough) + , mbPreemptiveExtend(false) + , mpError(NULL) +{ +} + +VDFileAsync9x::~VDFileAsync9x() { + Close(); +} + +void VDFileAsync9x::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { + try { + mFilename = VDTextWToA(pszFilename); + + const DWORD slowFlags = mbWriteThrough ? FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH : FILE_ATTRIBUTE_NORMAL; + + mhFileSlow = CreateFile(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, slowFlags, NULL); + if (mhFileSlow == INVALID_HANDLE_VALUE) + throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); + + if (mbUseFastMode) + mhFileFast = CreateFile(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); + + mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). + + mBlockSize = bufferSize; + mBlockCount = count; + mBuffer.Init(count * bufferSize); + + mState = kStateNormal; + } catch(const MyError&) { + Close(); + throw; + } + + ThreadStart(); +} + +void VDFileAsync9x::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { + try { + mFilename = ""; + + HANDLE hProcess = GetCurrentProcess(); + if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) + throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); + + mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). + + mBlockSize = bufferSize; + mBlockCount = count; + mBuffer.Init(count * bufferSize); + + mState = kStateNormal; + } catch(const MyError&) { + Close(); + throw; + } + + ThreadStart(); +} + +void VDFileAsync9x::Close() { + mState = kStateAbort; + mWriteOccurred.signal(); + ThreadWait(); + + if (mhFileSlow != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileSlow); + mhFileSlow = INVALID_HANDLE_VALUE; + } + if (mhFileFast != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileFast); + mhFileFast = INVALID_HANDLE_VALUE; + } +} + +void VDFileAsync9x::FastWrite(const void *pData, uint32 bytes) { + if (mhFileFast == INVALID_HANDLE_VALUE) { + if (pData) + Write(mClientFastPointer, pData, bytes); + else + WriteZero(mClientFastPointer, bytes); + } else { + if (mpError) + ThrowError(); + + uint32 bytesLeft = bytes; + while(bytesLeft) { + int actual; + void *p = mBuffer.LockWrite(bytesLeft, actual); + + if (!actual) { + mReadOccurred.wait(); + if (mpError) + ThrowError(); + continue; + } + + if (pData) { + memcpy(p, pData, actual); + pData = (const char *)pData + actual; + } else { + memset(p, 0, actual); + } + mBuffer.UnlockWrite(actual); + mWriteOccurred.signal(); + bytesLeft -= actual; + } + } + + mClientFastPointer += bytes; +} + +void VDFileAsync9x::FastWriteEnd() { + FastWrite(NULL, mSectorSize - 1); + + mState = kStateFlush; + mWriteOccurred.signal(); + ThreadWait(); + + if (mpError) + ThrowError(); +} + +void VDFileAsync9x::Write(sint64 pos, const void *p, uint32 bytes) { + Seek(pos); + + DWORD dwActual; + if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || dwActual != bytes) { + mClientSlowPointer = -1; + throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); + } + + mClientSlowPointer += bytes; +} + +void VDFileAsync9x::WriteZero(sint64 pos, uint32 bytes) { + uint32 bufsize = bytes > 2048 ? 2048 : bytes; + void *p = _alloca(bufsize); + memset(p, 0, bufsize); + + while(bytes > 0) { + uint32 tc = bytes > 2048 ? 2048 : bytes; + + Write(pos, p, tc); + pos += tc; + bytes -= tc; + } +} + +bool VDFileAsync9x::Extend(sint64 pos) { + return SeekNT(pos) && SetEndOfFile(mhFileSlow); +} + +void VDFileAsync9x::Truncate(sint64 pos) { + Seek(pos); + if (!SetEndOfFile(mhFileSlow)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +void VDFileAsync9x::SafeTruncateAndClose(sint64 pos) { + if (mhFileSlow != INVALID_HANDLE_VALUE) { + FastWrite(NULL, mSectorSize - 1); + + mState = kStateFlush; + mWriteOccurred.signal(); + ThreadWait(); + + Extend(pos); + Close(); + } +} + +sint64 VDFileAsync9x::GetSize() { + DWORD dwSizeHigh; + DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); + + if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + return dwSizeLow + ((sint64)dwSizeHigh << 32); +} + +void VDFileAsync9x::Seek(sint64 pos) { + if (!SeekNT(pos)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +bool VDFileAsync9x::SeekNT(sint64 pos) { + if (mClientSlowPointer == pos) + return true; + + LONG posHi = (LONG)(pos >> 32); + DWORD result = SetFilePointer(mhFileSlow, (LONG)pos, &posHi, FILE_BEGIN); + + if (result == INVALID_SET_FILE_POINTER) { + DWORD dwError = GetLastError(); + + if (dwError != NO_ERROR) { + mClientSlowPointer = -1; + return false; + } + } + + mClientSlowPointer = pos; + + return true; +} + +void VDFileAsync9x::ThrowError() { + MyError *e = mpError.xchg(NULL); + + if (e) { + if (mhFileFast != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileFast); + mhFileFast = INVALID_HANDLE_VALUE; + } + + MyError tmp; + tmp.TransferFrom(*e); + delete e; + throw tmp; + } +} + +void VDFileAsync9x::ThreadRun() { + bool bPreemptiveExtend = mbPreemptiveExtend; + sint64 currentSize; + sint64 pos = 0; + uint32 bufferSize = mBlockCount * mBlockSize; + HANDLE hFile = mhFileFast != INVALID_HANDLE_VALUE ? mhFileFast : mhFileSlow; + + try { + if (bPreemptiveExtend && !VDGetFileSizeW32(hFile, currentSize)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + for(;;) { + int state = mState; + + if (state == kStateAbort) + break; + + int actual; + const void *p = mBuffer.LockRead(mBlockSize, actual); + + if ((uint32)actual < mBlockSize) { + if (state == kStateNormal) { + mWriteOccurred.wait(); + continue; + } + + VDASSERT(state == kStateFlush); + + actual &= ~(mSectorSize-1); + if (!actual) + break; + } else { + if (bPreemptiveExtend) { + sint64 checkpt = pos + mBlockSize + bufferSize; + + if (checkpt > currentSize) { + currentSize += bufferSize; + if (currentSize < checkpt) + currentSize = checkpt; + + if (!VDSetFilePointerW32(hFile, currentSize, FILE_BEGIN) + || !SetEndOfFile(hFile)) + mbPreemptiveExtend = bPreemptiveExtend = false; + + if (!VDSetFilePointerW32(hFile, pos, FILE_BEGIN)) + throw MyWin32Error("Seek error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); + } + } + } + + DWORD dwActual; + if (!WriteFile(hFile, p, actual, &dwActual, NULL) || dwActual != actual) { + DWORD dwError = GetLastError(); + throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", dwError, mFilename.c_str()); + } + + pos += actual; + + mBuffer.UnlockRead(actual); + + mReadOccurred.signal(); + } + } catch(MyError& e) { + MyError *p = new MyError; + + p->TransferFrom(e); + delete mpError.xchg(p); + mReadOccurred.signal(); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDFileAsync - Windows NT implementation +// +/////////////////////////////////////////////////////////////////////////// + +struct VDFileAsyncNTBuffer : public OVERLAPPED { + bool mbActive; + bool mbPending; + uint32 mLength; + + VDFileAsyncNTBuffer() : mbActive(false), mbPending(false) { hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } + ~VDFileAsyncNTBuffer() { if (hEvent) CloseHandle(hEvent); } +}; + +class VDFileAsyncNT : public IVDFileAsync, private VDThread { +public: + VDFileAsyncNT(); + ~VDFileAsyncNT(); + + void SetPreemptiveExtend(bool b) { mbPreemptiveExtend = b; } + bool IsPreemptiveExtendActive() { return mbPreemptiveExtend; } + + bool IsOpen() { return mhFileSlow != INVALID_HANDLE_VALUE; } + + void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize); + void Open(VDFileHandle h, uint32 count, uint32 bufferSize); + void Close(); + void FastWrite(const void *pData, uint32 bytes); + void FastWriteEnd(); + void Write(sint64 pos, const void *pData, uint32 bytes); + bool Extend(sint64 pos); + void Truncate(sint64 pos); + void SafeTruncateAndClose(sint64 pos); + sint64 GetSize(); + sint64 GetFastWritePos() { return mClientFastPointer; } + +protected: + void WriteZero(sint64 pos, uint32 bytes); + void Seek(sint64 pos); + bool SeekNT(sint64 pos); + void ThrowError(); + void ThreadRun(); + + HANDLE mhFileSlow; + HANDLE mhFileFast; + uint32 mBlockSize; + uint32 mBlockCount; + uint32 mBufferSize; + uint32 mSectorSize; + + enum { + kStateNormal, + kStateFlush, + kStateAbort + }; + VDAtomicInt mState; + + VDSignal mReadOccurred; + VDSignal mWriteOccurred; + + uint32 mWriteOffset; + VDAtomicInt mBufferLevel; + sint64 mClientSlowPointer; + sint64 mClientFastPointer; + sint64 mFastPointer; + + volatile bool mbPreemptiveExtend; + + vdautoarrayptr mpBlocks; + + vdblock > mBuffer; + + VDAtomicPtr mpError; + VDStringA mFilename; +}; + +VDFileAsyncNT::VDFileAsyncNT() + : mhFileSlow(INVALID_HANDLE_VALUE) + , mhFileFast(INVALID_HANDLE_VALUE) + , mFastPointer(0) + , mClientSlowPointer(0) + , mClientFastPointer(0) + , mbPreemptiveExtend(false) + , mpError(NULL) +{ +} + +VDFileAsyncNT::~VDFileAsyncNT() { + Close(); +} + +void VDFileAsyncNT::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { + try { + mFilename = VDTextWToA(pszFilename); + + mhFileSlow = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (mhFileSlow == INVALID_HANDLE_VALUE) + throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); + + mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); + if (mhFileFast == INVALID_HANDLE_VALUE) + mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL); + + mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). + + mBlockSize = bufferSize; + mBlockCount = count; + mBufferSize = mBlockSize * mBlockCount; + + mWriteOffset = 0; + mBufferLevel = 0; + + mState = kStateNormal; + + if (mhFileFast != INVALID_HANDLE_VALUE) { + mpBlocks = new VDFileAsyncNTBuffer[count]; + mBuffer.resize(count * bufferSize); + ThreadStart(); + } + } catch(const MyError&) { + Close(); + throw; + } +} + +void VDFileAsyncNT::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { + try { + mFilename = ""; + + HANDLE hProcess = GetCurrentProcess(); + if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) + throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); + + mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). + + mBlockSize = bufferSize; + mBlockCount = count; + mBufferSize = mBlockSize * mBlockCount; + + mWriteOffset = 0; + mBufferLevel = 0; + + mState = kStateNormal; + + if (mhFileFast != INVALID_HANDLE_VALUE) { + mpBlocks = new VDFileAsyncNTBuffer[count]; + mBuffer.resize(count * bufferSize); + ThreadStart(); + } + } catch(const MyError&) { + Close(); + throw; + } +} + +void VDFileAsyncNT::Close() { + mState = kStateAbort; + mWriteOccurred.signal(); + ThreadWait(); + + if (mpError) { + delete mpError; + mpError = NULL; + } + + if (mhFileSlow != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileSlow); + mhFileSlow = INVALID_HANDLE_VALUE; + } + if (mhFileFast != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileFast); + mhFileFast = INVALID_HANDLE_VALUE; + } + + mpBlocks = NULL; +} + +void VDFileAsyncNT::FastWrite(const void *pData, uint32 bytes) { + if (mhFileFast == INVALID_HANDLE_VALUE) { + if (pData) + Write(mClientFastPointer, pData, bytes); + else + WriteZero(mClientFastPointer, bytes); + } else { + if (mpError) + ThrowError(); + + uint32 bytesLeft = bytes; + while(bytesLeft) { + uint32 actual = mBufferSize - mBufferLevel; + + if (actual > bytesLeft) + actual = bytesLeft; + + if (mWriteOffset + actual > mBufferSize) + actual = mBufferSize - mWriteOffset; + + if (!actual) { + mReadOccurred.wait(); + if (mpError) + ThrowError(); + continue; + } + + if (pData) { + memcpy(&mBuffer[mWriteOffset], pData, actual); + pData = (const char *)pData + actual; + } else { + memset(&mBuffer[mWriteOffset], 0, actual); + } + + uint32 oldWriteOffset = mWriteOffset; + mWriteOffset += actual; + if (mWriteOffset >= mBufferSize) + mWriteOffset = 0; + mBufferLevel += actual; + + // only bother signaling if the write offset crossed a block boundary + if (oldWriteOffset % mBlockSize + actual >= mBlockSize) { + mWriteOccurred.signal(); + if (mpError) + ThrowError(); + } + + bytesLeft -= actual; + } + } + + mClientFastPointer += bytes; +} + +void VDFileAsyncNT::FastWriteEnd() { + if (mhFileFast != INVALID_HANDLE_VALUE) { + FastWrite(NULL, mSectorSize - 1); + mState = kStateFlush; + mWriteOccurred.signal(); + ThreadWait(); + } + + if (mpError) + ThrowError(); +} + +void VDFileAsyncNT::Write(sint64 pos, const void *p, uint32 bytes) { + Seek(pos); + + DWORD dwActual; + if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || (mClientSlowPointer += dwActual),(dwActual != bytes)) + throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +void VDFileAsyncNT::WriteZero(sint64 pos, uint32 bytes) { + uint32 bufsize = bytes > 2048 ? 2048 : bytes; + void *p = _alloca(bufsize); + memset(p, 0, bufsize); + + while(bytes > 0) { + uint32 tc = bytes > 2048 ? 2048 : bytes; + + Write(pos, p, tc); + pos += tc; + bytes -= tc; + } +} + +bool VDFileAsyncNT::Extend(sint64 pos) { + return SeekNT(pos) && SetEndOfFile(mhFileSlow); +} + +void VDFileAsyncNT::Truncate(sint64 pos) { + Seek(pos); + if (!SetEndOfFile(mhFileSlow)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +void VDFileAsyncNT::SafeTruncateAndClose(sint64 pos) { + if (isThreadAttached()) { + mState = kStateAbort; + mWriteOccurred.signal(); + ThreadWait(); + + if (mpError) { + delete mpError; + mpError = NULL; + } + } + + if (mhFileSlow != INVALID_HANDLE_VALUE) { + Extend(pos); + Close(); + } +} + +sint64 VDFileAsyncNT::GetSize() { + DWORD dwSizeHigh; + DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); + + if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + return dwSizeLow + ((sint64)dwSizeHigh << 32); +} + +void VDFileAsyncNT::Seek(sint64 pos) { + if (!SeekNT(pos)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +bool VDFileAsyncNT::SeekNT(sint64 pos) { + if (mClientSlowPointer == pos) + return true; + + LONG posHi = (LONG)(pos >> 32); + DWORD result = SetFilePointer(mhFileSlow, (LONG)pos, &posHi, FILE_BEGIN); + + if (result == INVALID_SET_FILE_POINTER) { + DWORD dwError = GetLastError(); + + if (dwError != NO_ERROR) + return false; + } + + mClientSlowPointer = pos; + return true; +} + +void VDFileAsyncNT::ThrowError() { + MyError *e = mpError.xchg(NULL); + + if (e) { + if (mhFileFast != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileFast); + mhFileFast = INVALID_HANDLE_VALUE; + } + + MyError tmp; + tmp.TransferFrom(*e); + delete e; + throw tmp; + } +} + +void VDFileAsyncNT::ThreadRun() { + int requestHead = 0; + int requestTail = 0; + int requestCount = mBlockCount; + uint32 pendingLevel = 0; + uint32 readOffset = 0; + bool bPreemptiveExtend = mbPreemptiveExtend; + sint64 currentSize; + + try { + if (!VDGetFileSizeW32(mhFileFast, currentSize)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + for(;;) { + int state = mState; + + if (state == kStateAbort) { + typedef BOOL (WINAPI *tpCancelIo)(HANDLE); + static const tpCancelIo pCancelIo = (tpCancelIo)GetProcAddress(GetModuleHandle("kernel32"), "CancelIo"); + pCancelIo(mhFileFast); + + // Wait for any pending blocks to complete. + for(int i=0; i= 0); + if (readOffset + actual > mBufferSize) + actual = mBufferSize - readOffset; + + if (actual < mBlockSize) { + if (state == kStateNormal || actual < mSectorSize) { + // check for blocks that have completed + bool blocksCompleted = false; + for(;;) { + VDFileAsyncNTBuffer& buf = mpBlocks[requestTail]; + + if (!buf.mbActive) { + if (state == kStateFlush) + goto all_done; + + if (!blocksCompleted) { + // wait for further writes + mWriteOccurred.wait(); + } + break; + } + + if (buf.mbPending) { + HANDLE h[2] = {buf.hEvent, mWriteOccurred.getHandle()}; + DWORD waitResult = WaitForMultipleObjects(2, h, FALSE, INFINITE); + + if (waitResult == WAIT_OBJECT_0+1) // write pending + break; + + DWORD dwActual; + if (!GetOverlappedResult(mhFileFast, &buf, &dwActual, TRUE)) + throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + } + + buf.mbActive = false; + + blocksCompleted = true; + + if (++requestTail >= requestCount) + requestTail = 0; + + mBufferLevel -= buf.mLength; + pendingLevel -= buf.mLength; + VDASSERT((int)mBufferLevel >= 0); + VDASSERT((int)pendingLevel >= 0); + + mReadOccurred.signal(); + + } + + continue; + } + + VDASSERT(state == kStateFlush); + + actual &= ~(mSectorSize-1); + + VDASSERT(actual > 0); + } else { + actual = mBlockSize; + + if (bPreemptiveExtend) { + sint64 checkpt = mFastPointer + mBlockSize + mBufferSize; + + if (checkpt > currentSize) { + currentSize += mBufferSize; + if (currentSize < checkpt) + currentSize = checkpt; + + if (!VDSetFilePointerW32(mhFileFast, currentSize, FILE_BEGIN) + || !SetEndOfFile(mhFileFast)) + mbPreemptiveExtend = bPreemptiveExtend = false; + } + } + } + + // Issue a write to OS + VDFileAsyncNTBuffer& buf = mpBlocks[requestHead]; + + VDASSERT(!buf.mbActive); + + DWORD dwActual; + + buf.Offset = (DWORD)mFastPointer; + buf.OffsetHigh = (DWORD)((uint64)mFastPointer >> 32); + buf.Internal = 0; + buf.InternalHigh = 0; + buf.mLength = actual; + buf.mbPending = false; + + if (!WriteFile(mhFileFast, &mBuffer[readOffset], actual, &dwActual, &buf)) { + if (GetLastError() != ERROR_IO_PENDING) + throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + buf.mbPending = true; + } + + buf.mbActive = true; + + pendingLevel += actual; + VDASSERT(pendingLevel <= (uint32)mBufferLevel); + + readOffset += actual; + VDASSERT(readOffset <= mBufferSize); + if (readOffset >= mBufferSize) + readOffset = 0; + + mFastPointer += actual; + + if (++requestHead >= requestCount) + requestHead = 0; + } +all_done: + ; + + } catch(MyError& e) { + MyError *p = new MyError; + + p->TransferFrom(e); + delete mpError.xchg(p); + mReadOccurred.signal(); + } +} + +/////////////////////////////////////////////////////////////////////////// + +IVDFileAsync *VDCreateFileAsync(IVDFileAsync::Mode mode) { + switch(mode) { + + case IVDFileAsync::kModeAsynchronous: + if (VDIsWindowsNT()) + return new VDFileAsyncNT; + // Can't do async I/O. Fall-through to 9x method. + case IVDFileAsync::kModeThreaded: + return new VDFileAsync9x(true, true); + + default: + return new VDFileAsync9x(false, true); + + case IVDFileAsync::kModeBuffered: + return new VDFileAsync9x(false, false); + } +} diff --git a/src/thirdparty/VirtualDub/system/source/filewatcher.cpp b/src/thirdparty/VirtualDub/system/source/filewatcher.cpp index f09c8dcf38e..72053740b1c 100644 --- a/src/thirdparty/VirtualDub/system/source/filewatcher.cpp +++ b/src/thirdparty/VirtualDub/system/source/filewatcher.cpp @@ -1,157 +1,157 @@ -#include "stdafx.h" -#include -#include -#include -#include -#include - -VDFileWatcher::VDFileWatcher() - : mChangeHandle(INVALID_HANDLE_VALUE) - , mLastWriteTime(0) - , mbWatchDir(false) - , mbRepeatRequested(false) - , mbThunksInited(false) - , mpThunk(NULL) - , mTimerId(0) -{ -} - -VDFileWatcher::~VDFileWatcher() { - Shutdown(); -} - -bool VDFileWatcher::IsActive() const { - return mChangeHandle != INVALID_HANDLE_VALUE; -} - -void VDFileWatcher::Init(const wchar_t *file, IVDFileWatcherCallback *callback) { - Shutdown(); - - const wchar_t *pathEnd = VDFileSplitPath(file); - - VDStringW basePath(file, pathEnd); - - if (basePath.empty()) - basePath = L"."; - - if (VDIsWindowsNT()) - mChangeHandle = FindFirstChangeNotificationW(basePath.c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); - else - mChangeHandle = FindFirstChangeNotificationA(VDTextWToA(basePath).c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); - - if (mChangeHandle == INVALID_HANDLE_VALUE) - throw MyError("Unable to monitor file: %ls", file); - - mPath = file; - mLastWriteTime = VDFileGetLastWriteTime(mPath.c_str()); - mpCB = callback; - mbRepeatRequested = false; - mbWatchDir = false; - - if (callback) { - if (!mbThunksInited) - mbThunksInited = VDInitThunkAllocator(); - - if (mbThunksInited) { - mpThunk = VDCreateFunctionThunkFromMethod(this, &VDFileWatcher::StaticTimerCallback, true); - - if (mpThunk) { - mTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)mpThunk); - } - } - } -} - -void VDFileWatcher::InitDir(const wchar_t *path, bool subdirs, IVDFileWatcherCallback *callback) { - Shutdown(); - - const DWORD flags - = FILE_NOTIFY_CHANGE_SIZE - | FILE_NOTIFY_CHANGE_ATTRIBUTES - | FILE_NOTIFY_CHANGE_LAST_WRITE - | FILE_NOTIFY_CHANGE_FILE_NAME - | FILE_NOTIFY_CHANGE_CREATION; - if (VDIsWindowsNT()) - mChangeHandle = FindFirstChangeNotificationW(path, subdirs, flags); - else - mChangeHandle = FindFirstChangeNotificationA(VDTextWToA(path).c_str(), subdirs, flags); - - if (mChangeHandle == INVALID_HANDLE_VALUE) - throw MyError("Unable to monitor path: %ls", path); - - mPath = path; - mpCB = callback; - mbRepeatRequested = false; - mbWatchDir = true; - - if (callback) { - if (!mbThunksInited) - mbThunksInited = VDInitThunkAllocator(); - - if (mbThunksInited) { - mpThunk = VDCreateFunctionThunkFromMethod(this, &VDFileWatcher::StaticTimerCallback, true); - - if (mpThunk) { - mTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)mpThunk); - } - } - } -} - -void VDFileWatcher::Shutdown() { - if (mChangeHandle != INVALID_HANDLE_VALUE) { - FindCloseChangeNotification(mChangeHandle); - mChangeHandle = INVALID_HANDLE_VALUE; - } - - if (mTimerId) { - KillTimer(NULL, mTimerId); - mTimerId = 0; - } - - if (mpThunk) { - VDDestroyFunctionThunk(mpThunk); - mpThunk = NULL; - } - - if (mbThunksInited) { - mbThunksInited = false; - - VDShutdownThunkAllocator(); - } -} - -bool VDFileWatcher::Wait(uint32 delay) { - if (mChangeHandle == INVALID_HANDLE_VALUE) - return false; - - if (WAIT_OBJECT_0 != WaitForSingleObject(mChangeHandle, delay)) - return false; - - FindNextChangeNotification(mChangeHandle); - - if (!mbWatchDir) { - uint64 t = VDFileGetLastWriteTime(mPath.c_str()); - - if (mLastWriteTime == t) - return false; - - mLastWriteTime = t; - } - return true; -} - -void VDFileWatcher::StaticTimerCallback(void *, unsigned, unsigned, unsigned long) { - if (mbRepeatRequested) { - if (mpCB) - mbRepeatRequested = !mpCB->OnFileUpdated(mPath.c_str()); - else - mbRepeatRequested = false; - return; - } - - if (Wait(0)) { - if (mpCB) - mbRepeatRequested = !mpCB->OnFileUpdated(mPath.c_str()); - } -} +#include "stdafx.h" +#include +#include +#include +#include +#include + +VDFileWatcher::VDFileWatcher() + : mChangeHandle(INVALID_HANDLE_VALUE) + , mLastWriteTime(0) + , mbWatchDir(false) + , mbRepeatRequested(false) + , mbThunksInited(false) + , mpThunk(NULL) + , mTimerId(0) +{ +} + +VDFileWatcher::~VDFileWatcher() { + Shutdown(); +} + +bool VDFileWatcher::IsActive() const { + return mChangeHandle != INVALID_HANDLE_VALUE; +} + +void VDFileWatcher::Init(const wchar_t *file, IVDFileWatcherCallback *callback) { + Shutdown(); + + const wchar_t *pathEnd = VDFileSplitPath(file); + + VDStringW basePath(file, pathEnd); + + if (basePath.empty()) + basePath = L"."; + + if (VDIsWindowsNT()) + mChangeHandle = FindFirstChangeNotificationW(basePath.c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); + else + mChangeHandle = FindFirstChangeNotificationA(VDTextWToA(basePath).c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); + + if (mChangeHandle == INVALID_HANDLE_VALUE) + throw MyError("Unable to monitor file: %ls", file); + + mPath = file; + mLastWriteTime = VDFileGetLastWriteTime(mPath.c_str()); + mpCB = callback; + mbRepeatRequested = false; + mbWatchDir = false; + + if (callback) { + if (!mbThunksInited) + mbThunksInited = VDInitThunkAllocator(); + + if (mbThunksInited) { + mpThunk = VDCreateFunctionThunkFromMethod(this, &VDFileWatcher::StaticTimerCallback, true); + + if (mpThunk) { + mTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)mpThunk); + } + } + } +} + +void VDFileWatcher::InitDir(const wchar_t *path, bool subdirs, IVDFileWatcherCallback *callback) { + Shutdown(); + + const DWORD flags + = FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_ATTRIBUTES + | FILE_NOTIFY_CHANGE_LAST_WRITE + | FILE_NOTIFY_CHANGE_FILE_NAME + | FILE_NOTIFY_CHANGE_CREATION; + if (VDIsWindowsNT()) + mChangeHandle = FindFirstChangeNotificationW(path, subdirs, flags); + else + mChangeHandle = FindFirstChangeNotificationA(VDTextWToA(path).c_str(), subdirs, flags); + + if (mChangeHandle == INVALID_HANDLE_VALUE) + throw MyError("Unable to monitor path: %ls", path); + + mPath = path; + mpCB = callback; + mbRepeatRequested = false; + mbWatchDir = true; + + if (callback) { + if (!mbThunksInited) + mbThunksInited = VDInitThunkAllocator(); + + if (mbThunksInited) { + mpThunk = VDCreateFunctionThunkFromMethod(this, &VDFileWatcher::StaticTimerCallback, true); + + if (mpThunk) { + mTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)mpThunk); + } + } + } +} + +void VDFileWatcher::Shutdown() { + if (mChangeHandle != INVALID_HANDLE_VALUE) { + FindCloseChangeNotification(mChangeHandle); + mChangeHandle = INVALID_HANDLE_VALUE; + } + + if (mTimerId) { + KillTimer(NULL, mTimerId); + mTimerId = 0; + } + + if (mpThunk) { + VDDestroyFunctionThunk(mpThunk); + mpThunk = NULL; + } + + if (mbThunksInited) { + mbThunksInited = false; + + VDShutdownThunkAllocator(); + } +} + +bool VDFileWatcher::Wait(uint32 delay) { + if (mChangeHandle == INVALID_HANDLE_VALUE) + return false; + + if (WAIT_OBJECT_0 != WaitForSingleObject(mChangeHandle, delay)) + return false; + + FindNextChangeNotification(mChangeHandle); + + if (!mbWatchDir) { + uint64 t = VDFileGetLastWriteTime(mPath.c_str()); + + if (mLastWriteTime == t) + return false; + + mLastWriteTime = t; + } + return true; +} + +void VDFileWatcher::StaticTimerCallback(void *, unsigned, unsigned, unsigned long) { + if (mbRepeatRequested) { + if (mpCB) + mbRepeatRequested = !mpCB->OnFileUpdated(mPath.c_str()); + else + mbRepeatRequested = false; + return; + } + + if (Wait(0)) { + if (mpCB) + mbRepeatRequested = !mpCB->OnFileUpdated(mPath.c_str()); + } +} diff --git a/src/thirdparty/VirtualDub/system/source/halffloat.cpp b/src/thirdparty/VirtualDub/system/source/halffloat.cpp index 9875a3003b8..f9620e5ae15 100644 --- a/src/thirdparty/VirtualDub/system/source/halffloat.cpp +++ b/src/thirdparty/VirtualDub/system/source/halffloat.cpp @@ -1,79 +1,79 @@ -#include "stdafx.h" -#include - -uint16 VDConvertFloatToHalf(const void *f) { - uint32 v = *(const uint32 *)f; - - uint32 sign = (v >> 16) & 0x8000; - sint32 exmant = v & 0x7fffffff; - - if (exmant > 0x7f800000) { - // convert NaNs directly - exmant = (exmant & 0x00400000) + 0x47a00000; - } else if (exmant > 0x47800000) { - // clamp large numbers to infinity - exmant = 0x47800000; - } else if (exmant < 0x33800000) { - // clamp very tiny numbers to zero - exmant = 0x38000000; - } else if (exmant < 0x38800000) { - // normalized finite converting to denormal - uint32 ex = exmant & 0x7f800000; - uint32 mant = (exmant & 0x007fffff) | 0x800000; - uint32 sticky = 0; - - while(ex < 0x38800000) { - ex += 0x00800000; - sticky |= mant; - mant >>= 1; - } - - // round to nearest even - sticky |= mant >> 13; - - // round up with sticky bits - mant += (sticky & 1); - - // round up with round bit - mant += 0x0fff; - - exmant = ex + mant - 0x800000; - } else { - // round normal numbers using round to nearest even - exmant |= (exmant & 0x00002000) >> 13; - exmant += 0x00000fff; - } - - // shift and rebias exponent - exmant -= 0x38000000; - exmant >>= 13; - - return (uint16)(sign + exmant); -} - -void VDConvertHalfToFloat(uint16 h, void *dst) { - uint32 sign = ((uint32)h << 16) & 0x80000000; - uint32 exmant = (uint32)h & 0x7fff; - uint32 v = 0; - - if (exmant >= 0x7c00) { - // infinity or NaN - v = (exmant << 13) + 0x70000000; - } else if (exmant >= 0x0400) { - // normalized finite - v = (exmant << 13) + 0x38000000; - } else if (exmant) { - // denormal - uint32 ex32 = 0x38000000; - uint32 mant32 = (exmant & 0x3ff) << 13; - - while(!(mant32 & 0x800000)) { - mant32 <<= 1; - ex32 -= 0x800000; - } - - v = ex32 + mant32; - } - - *(uint32 *)dst = v + sign; -} +#include "stdafx.h" +#include + +uint16 VDConvertFloatToHalf(const void *f) { + uint32 v = *(const uint32 *)f; + + uint32 sign = (v >> 16) & 0x8000; + sint32 exmant = v & 0x7fffffff; + + if (exmant > 0x7f800000) { + // convert NaNs directly + exmant = (exmant & 0x00400000) + 0x47a00000; + } else if (exmant > 0x47800000) { + // clamp large numbers to infinity + exmant = 0x47800000; + } else if (exmant < 0x33800000) { + // clamp very tiny numbers to zero + exmant = 0x38000000; + } else if (exmant < 0x38800000) { + // normalized finite converting to denormal + uint32 ex = exmant & 0x7f800000; + uint32 mant = (exmant & 0x007fffff) | 0x800000; + uint32 sticky = 0; + + while(ex < 0x38800000) { + ex += 0x00800000; + sticky |= mant; + mant >>= 1; + } + + // round to nearest even + sticky |= mant >> 13; + + // round up with sticky bits + mant += (sticky & 1); + + // round up with round bit + mant += 0x0fff; + + exmant = ex + mant - 0x800000; + } else { + // round normal numbers using round to nearest even + exmant |= (exmant & 0x00002000) >> 13; + exmant += 0x00000fff; + } + + // shift and rebias exponent + exmant -= 0x38000000; + exmant >>= 13; + + return (uint16)(sign + exmant); +} + +void VDConvertHalfToFloat(uint16 h, void *dst) { + uint32 sign = ((uint32)h << 16) & 0x80000000; + uint32 exmant = (uint32)h & 0x7fff; + uint32 v = 0; + + if (exmant >= 0x7c00) { + // infinity or NaN + v = (exmant << 13) + 0x70000000; + } else if (exmant >= 0x0400) { + // normalized finite + v = (exmant << 13) + 0x38000000; + } else if (exmant) { + // denormal + uint32 ex32 = 0x38000000; + uint32 mant32 = (exmant & 0x3ff) << 13; + + while(!(mant32 & 0x800000)) { + mant32 <<= 1; + ex32 -= 0x800000; + } + + v = ex32 + mant32; + } + + *(uint32 *)dst = v + sign; +} diff --git a/src/thirdparty/VirtualDub/system/source/hash.cpp b/src/thirdparty/VirtualDub/system/source/hash.cpp index c9665f9cbdc..8d80ba59779 100644 --- a/src/thirdparty/VirtualDub/system/source/hash.cpp +++ b/src/thirdparty/VirtualDub/system/source/hash.cpp @@ -1,123 +1,123 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -// Based on: SuperFastHash by Paul Hsieh -// http://www.azillionmonkeys.com/qed/hash.html - -uint32 VDHashString32(const char *s) { - uint32 len = (uint32)strlen(s); - - return VDHashString32(s, len); -} - -uint32 VDHashString32(const char *s, uint32 len) { - uint32 hash = len; - - uint32 rem = len & 3; - len >>= 2; - - uint32 tmp; - for(uint32 i=0; i> 11; - } - - switch(rem) { - case 3: - hash += VDReadUnalignedU16(s); - hash ^= hash << 16; - hash ^= (uint32)(uint8)s[2] << 18; - hash += hash >> 11; - break; - case 2: - hash += VDReadUnalignedU16(s); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: - hash += (uint8)s[0]; - hash ^= hash << 10; - hash += hash >> 1; - break; - } - - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -uint32 VDHashString32(const wchar_t *s) { - return VDHashString32((const char *)s, wcslen(s) * sizeof(wchar_t)); -} - -uint32 VDHashString32(const wchar_t *s, uint32 len) { - return VDHashString32((const char *)s, len * sizeof(wchar_t)); -} - -uint32 VDHashString32I(const char *s) { - uint32 len = (uint32)strlen(s); - - return VDHashString32I(s, len); -} - -uint32 VDHashString32I(const char *s, uint32 len) { - uint32 hash = 2166136261U; - - for(uint32 i=0; i +#include + +// Based on: SuperFastHash by Paul Hsieh +// http://www.azillionmonkeys.com/qed/hash.html + +uint32 VDHashString32(const char *s) { + uint32 len = (uint32)strlen(s); + + return VDHashString32(s, len); +} + +uint32 VDHashString32(const char *s, uint32 len) { + uint32 hash = len; + + uint32 rem = len & 3; + len >>= 2; + + uint32 tmp; + for(uint32 i=0; i> 11; + } + + switch(rem) { + case 3: + hash += VDReadUnalignedU16(s); + hash ^= hash << 16; + hash ^= (uint32)(uint8)s[2] << 18; + hash += hash >> 11; + break; + case 2: + hash += VDReadUnalignedU16(s); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: + hash += (uint8)s[0]; + hash ^= hash << 10; + hash += hash >> 1; + break; + } + + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +uint32 VDHashString32(const wchar_t *s) { + return VDHashString32((const char *)s, wcslen(s) * sizeof(wchar_t)); +} + +uint32 VDHashString32(const wchar_t *s, uint32 len) { + return VDHashString32((const char *)s, len * sizeof(wchar_t)); +} + +uint32 VDHashString32I(const char *s) { + uint32 len = (uint32)strlen(s); + + return VDHashString32I(s, len); +} + +uint32 VDHashString32I(const char *s, uint32 len) { + uint32 hash = 2166136261U; + + for(uint32 i=0; i - -#include - -#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - void __declspec(naked) __cdecl vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { - __asm { - push ebx - - mov ebx, [esp+16] - mov ecx, [esp+12] - mov edx, [esp+8] - - mov eax, [ecx+0] - add eax, [ebx+0] - mov [edx+0],eax - mov eax, [ecx+4] - adc eax, [ebx+4] - mov [edx+4],eax - mov eax, [ecx+8] - adc eax, [ebx+8] - mov [edx+8],eax - mov eax, [ecx+12] - adc eax, [ebx+12] - mov [edx+12],eax - - pop ebx - ret - } - } - - void __declspec(naked) __cdecl vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { - __asm { - push ebx - - mov ebx, [esp+16] - mov ecx, [esp+12] - mov edx, [esp+8] - - mov eax, [ecx+0] - sub eax, [ebx+0] - mov [edx+0],eax - mov eax, [ecx+4] - sbb eax, [ebx+4] - mov [edx+4],eax - mov eax, [ecx+8] - sbb eax, [ebx+8] - mov [edx+8],eax - mov eax, [ecx+12] - sbb eax, [ebx+12] - mov [edx+12],eax - - pop ebx - ret - } - } - - void __declspec(naked) vdint128::setSquare(sint64 v) { - __asm { - push edi - push esi - push ebx - mov eax, [esp+20] - cdq - mov esi, eax - mov eax, [esp+16] - xor eax, edx - xor esi, edx - sub eax, edx - sbb esi, edx - mov ebx, eax - mul eax - mov [ecx], eax - mov edi, edx - mov eax, ebx - mul esi - mov ebx, 0 - add eax, eax - adc edx, edx - add eax, edi - adc edx, 0 - mov edi, edx - adc ebx, 0 - mov [ecx+4], eax - mov eax, esi - mul esi - add eax, edi - adc edx, ebx - mov [ecx+8], eax - mov [ecx+12], edx - pop ebx - pop esi - pop edi - ret 8 - } - } - - const vdint128 __declspec(naked) vdint128::operator<<(int v) const { - __asm { - push ebp - push ebx - push esi - push edi - - mov esi,ecx - mov edx,[esp+20] - - mov ecx,[esp+24] - cmp ecx,128 - jae zeroit - - mov eax,[esi+12] - mov ebx,[esi+8] - mov edi,[esi+4] - mov ebp,[esi] - - dwordloop: - cmp ecx,32 - jb bits - - mov eax,ebx - mov ebx,edi - mov edi,ebp - xor ebp,ebp - sub ecx,32 - jmp short dwordloop - - bits: - shld eax,ebx,cl - shld ebx,edi,cl - mov [edx+12],eax - mov [edx+8],ebx - shld edi,ebp,cl - - shl ebp,cl - mov [edx+4],edi - mov [edx],ebp - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - - zeroit: - xor eax,eax - mov [edx+0],eax - mov [edx+4],eax - mov [edx+8],eax - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - } - } - - const vdint128 __declspec(naked) vdint128::operator>>(int v) const { - __asm { - push ebp - push ebx - push esi - push edi - - mov esi,ecx - mov edx,[esp+20] - - mov eax,[esi+12] - mov ecx,[esp+24] - cmp ecx,127 - jae clearit - - mov ebx,[esi+8] - mov edi,[esi+4] - mov ebp,[esi] - - dwordloop: - cmp ecx,32 - jb bits - - mov ebp,edi - mov edi,ebx - mov ebx,eax - sar eax,31 - sub ecx,32 - jmp short dwordloop - - bits: - shrd ebp,edi,cl - shrd edi,ebx,cl - mov [edx],ebp - mov [edx+4],edi - shrd ebx,eax,cl - - sar eax,cl - mov [edx+8],ebx - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - - clearit: - sar eax, 31 - mov [edx+0],eax - mov [edx+4],eax - mov [edx+8],eax - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - } - } - - const vduint128 __declspec(naked) vduint128::operator<<(int v) const { - __asm { - push ebp - push ebx - push esi - push edi - - mov esi,ecx - mov edx,[esp+20] - - mov ecx,[esp+24] - cmp ecx,128 - jae zeroit - - mov eax,[esi+12] - mov ebx,[esi+8] - mov edi,[esi+4] - mov ebp,[esi] - - dwordloop: - cmp ecx,32 - jb bits - - mov eax,ebx - mov ebx,edi - mov edi,ebp - xor ebp,ebp - sub ecx,32 - jmp short dwordloop - - bits: - shld eax,ebx,cl - shld ebx,edi,cl - mov [edx+12],eax - mov [edx+8],ebx - shld edi,ebp,cl - - shl ebp,cl - mov [edx+4],edi - mov [edx],ebp - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - - zeroit: - xor eax,eax - mov [edx+0],eax - mov [edx+4],eax - mov [edx+8],eax - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - } - } - - const vduint128 __declspec(naked) vduint128::operator>>(int v) const { - __asm { - push ebp - push ebx - push esi - push edi - - mov esi,ecx - mov edx,[esp+20] - - mov eax,[esi+12] - mov ecx,[esp+24] - cmp ecx,127 - jae clearit - - mov ebx,[esi+8] - mov edi,[esi+4] - mov ebp,[esi] - - dwordloop: - cmp ecx,32 - jb bits - - mov ebp,edi - mov edi,ebx - mov ebx,eax - xor eax,eax - sub ecx,32 - jmp short dwordloop - - bits: - shrd ebp,edi,cl - shrd edi,ebx,cl - mov [edx],ebp - mov [edx+4],edi - shrd ebx,eax,cl - - shr eax,cl - mov [edx+8],ebx - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - - clearit: - sar eax, 31 - mov [edx+0],eax - mov [edx+4],eax - mov [edx+8],eax - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - } - } - -#elif !defined(VD_CPU_AMD64) - - // These aren't really assembly routines, but we define them so we aren't asm dependent. - - void vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { - dst[0] = x[0] + y[0]; - dst[1] = x[1] + y[1] + (dst[0] < x[0]); - } - - void vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { - dst[0] = x[0] - y[0]; - dst[1] = x[1] - y[1] - (dst[0] > x[0]); - } - - void vdint128::setSquare(sint64 v) { - vdint128 r; - - uint32 u0 = (uint32)v; - uint32 u1 = (uint32)(v >> 32); - uint64 m0 = u0*u0; - uint64 m1 = u0*u1; // added twice - uint64 m2 = u1*u1; - uint32 s0 = (uint32)m0; - uint32 s1a = (uint32)(m0 >> 32); - uint32 s1b = (uint32)m1; - uint32 s2a = (uint32)(m1 >> 32); - - q[1] = m2 + s2a; - - d[0] = s0; - - d[1] = s1a + s1b; - if (d[1] < s1b) - ++q[1]; - - d[1] += s1b; - if (d[1] < s1b) - ++q[1]; - } - - const vdint128 vdint128::operator<<(int v) const { - vdint128 r; - - r.q[0] = q[0]; - r.q[1] = q[1]; - - if (v >= 64) { - if (v >= 128) { - r.q[0] = 0; - r.q[1] = 0; - return r; - } - - r.q[1] = r.q[0]; - r.q[0] = 0; - - v -= 64; - } - - if (v) { - r.q[1] = (r.q[1] << v) + ((uint64)r.q[0] >> (64 - v)); - r.q[0] <<= v; - } - - return r; - } - - const vdint128 vdint128::operator>>(int v) const { - vdint128 r; - - r.q[0] = q[0]; - r.q[1] = q[1]; - - if (v >= 64) { - sint64 sign = q[1] >> 63; - - if (v >= 128) { - r.q[0] = sign; - r.q[1] = sign; - return r; - } - - r.q[0] = r.q[1]; - r.q[1] = sign; - - v -= 64; - } - - if (v) { - r.q[0] = ((uint64)r.q[0] >> v) + (r.q[1] << (64 - v)); - r.q[1] >>= v; - } - - return r; - } - - const vduint128 vduint128::operator<<(int v) const { - vduint128 r; - - r.q[0] = q[0]; - r.q[1] = q[1]; - - if (v >= 64) { - if (v >= 128) { - r.q[0] = 0; - r.q[1] = 0; - return r; - } - - r.q[1] = r.q[0]; - r.q[0] = 0; - - v -= 64; - } - - if (v) { - r.q[1] = (r.q[1] << v) + (r.q[0] >> (64 - v)); - r.q[0] <<= v; - } - - return r; - } - - const vduint128 vduint128::operator>>(int v) const { - vduint128 r; - - r.q[0] = q[0]; - r.q[1] = q[1]; - - if (v >= 64) { - if (v >= 128) { - r.q[0] = 0; - r.q[1] = 0; - return r; - } - - r.q[0] = r.q[1]; - r.q[1] = 0; - - v -= 64; - } - - if (v) { - r.q[0] = (r.q[0] >> v) + (r.q[1] << (64 - v)); - r.q[1] >>= v; - } - - return r; - } -#endif - -const vdint128 vdint128::operator*(const vdint128& x) const { - vdint128 X = x.abs(); - vdint128 Y = abs(); - - vduint128 bd(VDUMul64x64To128(X.q[0], Y.q[0])); - - bd.q[1] += X.q[0]*Y.q[1] + X.q[1]*Y.q[0]; - - return (q[1]^x.q[1])<0 ? -vdint128(bd) : vdint128(bd); -} - -const vdint128 vdint128::operator/(int x) const { - vdint128 r; - sint64 accum; - - r.d[3] = d[3] / x; - - accum = ((sint64)(d[3] % x) << 32) + d[2]; - r.d[2] = (sint32)(accum / x); - - accum = ((accum % x) << 32) + d[1]; - r.d[1] = (sint32)(accum / x); - - accum = ((accum % x) << 32) + d[0]; - r.d[0] = (sint32)(accum / x); - - return r; -} - -vdint128::operator double() const { - return (double)(unsigned long)q[0] - + ldexp((double)(unsigned long)((unsigned __int64)q[0]>>32), 32) - + ldexp((double)q[1], 64); -} - -///////////////////////////////////////////////////////////////////////////// - -const vduint128 vduint128::operator*(const vduint128& x) const { - vduint128 result(VDUMul64x64To128(q[0], x.q[0])); - - result.q[1] += q[0]*x.q[1] + q[1]*x.q[0]; - - return result; -} - -#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - vduint128 __declspec(naked) __cdecl VDUMul64x64To128(uint64 x, uint64 y) { - __asm { - mov ecx,[esp+4] - - mov eax,[esp+8] - mul dword ptr [esp+16] ;EDX:EAX = BD - mov [ecx+0],eax - mov [ecx+4],edx - - mov eax,[esp+12] - mul dword ptr [esp+20] ;EDX:EAX = AC - mov [ecx+8],eax - mov [ecx+12],edx - - mov eax,[esp+8] - mul dword ptr [esp+20] ;EDX:EAX = BC - add [ecx+4],eax - adc [ecx+8],edx - adc dword ptr [ecx+12], 0 - - mov eax,[esp+12] - mul dword ptr [esp+16] ;EDX:EAX = AD - add [ecx+4],eax - adc [ecx+8],edx - adc dword ptr [ecx+12], 0 - - mov eax, ecx - ret - } - } -#elif !defined(VD_CPU_AMD64) - vduint128 VDUMul64x64To128(uint64 x, uint64 y) { - uint32 x0 = (uint32)x; - uint32 x1 = (uint32)(x >> 32); - uint32 y0 = (uint32)y; - uint32 y1 = (uint32)(y >> 32); - - uint64 m0 = (uint64)x0*y0; - uint64 m1a = (uint64)x1*y0; - uint64 m1b = (uint64)x0*y1; - uint64 m2 = (uint64)x1*y1; - - uint32 s0 = (uint32)m0; - uint32 s1a = (uint32)(m0 >> 32); - uint32 s1b = (uint32)m1a; - uint32 s1c = (uint32)m1b; - uint32 s2a = (uint32)(m1a >> 32); - uint32 s2b = (uint32)(m1b >> 32); - uint32 s2c = (uint32)m2; - uint32 s3 = (uint32)(m2 >> 32); - - vduint128 r; - r.d[0] = s0; - r.d[1] = s1a + s1b; - r.d[2] = r.d[1] < s1b; - r.d[1] += s1c; - r.d[2] += r.d[1] < s1c; - r.d[2] += s2a; - r.d[3] = r.d[2] < s2a; - r.d[2] += s2b; - r.d[3] += r.d[2] < s2b; - r.d[2] += s2c; - r.d[3] += r.d[2] < s2c; - r.d[3] += s3; - - return r; - } -#endif - -uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder) { - vduint128 temp(dividend); - vduint128 divisor2(divisor); - - divisor2 <<= 63; - - uint64 result = 0; - for(int i=0; i<64; ++i) { - result += result; - if (temp >= divisor2) { - temp -= divisor2; - ++result; - } - temp += temp; - } - - remainder = temp.q[1]; - - return result; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include + +#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + void __declspec(naked) __cdecl vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { + __asm { + push ebx + + mov ebx, [esp+16] + mov ecx, [esp+12] + mov edx, [esp+8] + + mov eax, [ecx+0] + add eax, [ebx+0] + mov [edx+0],eax + mov eax, [ecx+4] + adc eax, [ebx+4] + mov [edx+4],eax + mov eax, [ecx+8] + adc eax, [ebx+8] + mov [edx+8],eax + mov eax, [ecx+12] + adc eax, [ebx+12] + mov [edx+12],eax + + pop ebx + ret + } + } + + void __declspec(naked) __cdecl vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { + __asm { + push ebx + + mov ebx, [esp+16] + mov ecx, [esp+12] + mov edx, [esp+8] + + mov eax, [ecx+0] + sub eax, [ebx+0] + mov [edx+0],eax + mov eax, [ecx+4] + sbb eax, [ebx+4] + mov [edx+4],eax + mov eax, [ecx+8] + sbb eax, [ebx+8] + mov [edx+8],eax + mov eax, [ecx+12] + sbb eax, [ebx+12] + mov [edx+12],eax + + pop ebx + ret + } + } + + void __declspec(naked) vdint128::setSquare(sint64 v) { + __asm { + push edi + push esi + push ebx + mov eax, [esp+20] + cdq + mov esi, eax + mov eax, [esp+16] + xor eax, edx + xor esi, edx + sub eax, edx + sbb esi, edx + mov ebx, eax + mul eax + mov [ecx], eax + mov edi, edx + mov eax, ebx + mul esi + mov ebx, 0 + add eax, eax + adc edx, edx + add eax, edi + adc edx, 0 + mov edi, edx + adc ebx, 0 + mov [ecx+4], eax + mov eax, esi + mul esi + add eax, edi + adc edx, ebx + mov [ecx+8], eax + mov [ecx+12], edx + pop ebx + pop esi + pop edi + ret 8 + } + } + + const vdint128 __declspec(naked) vdint128::operator<<(int v) const { + __asm { + push ebp + push ebx + push esi + push edi + + mov esi,ecx + mov edx,[esp+20] + + mov ecx,[esp+24] + cmp ecx,128 + jae zeroit + + mov eax,[esi+12] + mov ebx,[esi+8] + mov edi,[esi+4] + mov ebp,[esi] + + dwordloop: + cmp ecx,32 + jb bits + + mov eax,ebx + mov ebx,edi + mov edi,ebp + xor ebp,ebp + sub ecx,32 + jmp short dwordloop + + bits: + shld eax,ebx,cl + shld ebx,edi,cl + mov [edx+12],eax + mov [edx+8],ebx + shld edi,ebp,cl + + shl ebp,cl + mov [edx+4],edi + mov [edx],ebp + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + + zeroit: + xor eax,eax + mov [edx+0],eax + mov [edx+4],eax + mov [edx+8],eax + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + } + } + + const vdint128 __declspec(naked) vdint128::operator>>(int v) const { + __asm { + push ebp + push ebx + push esi + push edi + + mov esi,ecx + mov edx,[esp+20] + + mov eax,[esi+12] + mov ecx,[esp+24] + cmp ecx,127 + jae clearit + + mov ebx,[esi+8] + mov edi,[esi+4] + mov ebp,[esi] + + dwordloop: + cmp ecx,32 + jb bits + + mov ebp,edi + mov edi,ebx + mov ebx,eax + sar eax,31 + sub ecx,32 + jmp short dwordloop + + bits: + shrd ebp,edi,cl + shrd edi,ebx,cl + mov [edx],ebp + mov [edx+4],edi + shrd ebx,eax,cl + + sar eax,cl + mov [edx+8],ebx + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + + clearit: + sar eax, 31 + mov [edx+0],eax + mov [edx+4],eax + mov [edx+8],eax + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + } + } + + const vduint128 __declspec(naked) vduint128::operator<<(int v) const { + __asm { + push ebp + push ebx + push esi + push edi + + mov esi,ecx + mov edx,[esp+20] + + mov ecx,[esp+24] + cmp ecx,128 + jae zeroit + + mov eax,[esi+12] + mov ebx,[esi+8] + mov edi,[esi+4] + mov ebp,[esi] + + dwordloop: + cmp ecx,32 + jb bits + + mov eax,ebx + mov ebx,edi + mov edi,ebp + xor ebp,ebp + sub ecx,32 + jmp short dwordloop + + bits: + shld eax,ebx,cl + shld ebx,edi,cl + mov [edx+12],eax + mov [edx+8],ebx + shld edi,ebp,cl + + shl ebp,cl + mov [edx+4],edi + mov [edx],ebp + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + + zeroit: + xor eax,eax + mov [edx+0],eax + mov [edx+4],eax + mov [edx+8],eax + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + } + } + + const vduint128 __declspec(naked) vduint128::operator>>(int v) const { + __asm { + push ebp + push ebx + push esi + push edi + + mov esi,ecx + mov edx,[esp+20] + + mov eax,[esi+12] + mov ecx,[esp+24] + cmp ecx,127 + jae clearit + + mov ebx,[esi+8] + mov edi,[esi+4] + mov ebp,[esi] + + dwordloop: + cmp ecx,32 + jb bits + + mov ebp,edi + mov edi,ebx + mov ebx,eax + xor eax,eax + sub ecx,32 + jmp short dwordloop + + bits: + shrd ebp,edi,cl + shrd edi,ebx,cl + mov [edx],ebp + mov [edx+4],edi + shrd ebx,eax,cl + + shr eax,cl + mov [edx+8],ebx + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + + clearit: + sar eax, 31 + mov [edx+0],eax + mov [edx+4],eax + mov [edx+8],eax + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + } + } + +#elif !defined(VD_CPU_AMD64) + + // These aren't really assembly routines, but we define them so we aren't asm dependent. + + void vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { + dst[0] = x[0] + y[0]; + dst[1] = x[1] + y[1] + (dst[0] < x[0]); + } + + void vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { + dst[0] = x[0] - y[0]; + dst[1] = x[1] - y[1] - (dst[0] > x[0]); + } + + void vdint128::setSquare(sint64 v) { + vdint128 r; + + uint32 u0 = (uint32)v; + uint32 u1 = (uint32)(v >> 32); + uint64 m0 = u0*u0; + uint64 m1 = u0*u1; // added twice + uint64 m2 = u1*u1; + uint32 s0 = (uint32)m0; + uint32 s1a = (uint32)(m0 >> 32); + uint32 s1b = (uint32)m1; + uint32 s2a = (uint32)(m1 >> 32); + + q[1] = m2 + s2a; + + d[0] = s0; + + d[1] = s1a + s1b; + if (d[1] < s1b) + ++q[1]; + + d[1] += s1b; + if (d[1] < s1b) + ++q[1]; + } + + const vdint128 vdint128::operator<<(int v) const { + vdint128 r; + + r.q[0] = q[0]; + r.q[1] = q[1]; + + if (v >= 64) { + if (v >= 128) { + r.q[0] = 0; + r.q[1] = 0; + return r; + } + + r.q[1] = r.q[0]; + r.q[0] = 0; + + v -= 64; + } + + if (v) { + r.q[1] = (r.q[1] << v) + ((uint64)r.q[0] >> (64 - v)); + r.q[0] <<= v; + } + + return r; + } + + const vdint128 vdint128::operator>>(int v) const { + vdint128 r; + + r.q[0] = q[0]; + r.q[1] = q[1]; + + if (v >= 64) { + sint64 sign = q[1] >> 63; + + if (v >= 128) { + r.q[0] = sign; + r.q[1] = sign; + return r; + } + + r.q[0] = r.q[1]; + r.q[1] = sign; + + v -= 64; + } + + if (v) { + r.q[0] = ((uint64)r.q[0] >> v) + (r.q[1] << (64 - v)); + r.q[1] >>= v; + } + + return r; + } + + const vduint128 vduint128::operator<<(int v) const { + vduint128 r; + + r.q[0] = q[0]; + r.q[1] = q[1]; + + if (v >= 64) { + if (v >= 128) { + r.q[0] = 0; + r.q[1] = 0; + return r; + } + + r.q[1] = r.q[0]; + r.q[0] = 0; + + v -= 64; + } + + if (v) { + r.q[1] = (r.q[1] << v) + (r.q[0] >> (64 - v)); + r.q[0] <<= v; + } + + return r; + } + + const vduint128 vduint128::operator>>(int v) const { + vduint128 r; + + r.q[0] = q[0]; + r.q[1] = q[1]; + + if (v >= 64) { + if (v >= 128) { + r.q[0] = 0; + r.q[1] = 0; + return r; + } + + r.q[0] = r.q[1]; + r.q[1] = 0; + + v -= 64; + } + + if (v) { + r.q[0] = (r.q[0] >> v) + (r.q[1] << (64 - v)); + r.q[1] >>= v; + } + + return r; + } +#endif + +const vdint128 vdint128::operator*(const vdint128& x) const { + vdint128 X = x.abs(); + vdint128 Y = abs(); + + vduint128 bd(VDUMul64x64To128(X.q[0], Y.q[0])); + + bd.q[1] += X.q[0]*Y.q[1] + X.q[1]*Y.q[0]; + + return (q[1]^x.q[1])<0 ? -vdint128(bd) : vdint128(bd); +} + +const vdint128 vdint128::operator/(int x) const { + vdint128 r; + sint64 accum; + + r.d[3] = d[3] / x; + + accum = ((sint64)(d[3] % x) << 32) + d[2]; + r.d[2] = (sint32)(accum / x); + + accum = ((accum % x) << 32) + d[1]; + r.d[1] = (sint32)(accum / x); + + accum = ((accum % x) << 32) + d[0]; + r.d[0] = (sint32)(accum / x); + + return r; +} + +vdint128::operator double() const { + return (double)(unsigned long)q[0] + + ldexp((double)(unsigned long)((unsigned __int64)q[0]>>32), 32) + + ldexp((double)q[1], 64); +} + +///////////////////////////////////////////////////////////////////////////// + +const vduint128 vduint128::operator*(const vduint128& x) const { + vduint128 result(VDUMul64x64To128(q[0], x.q[0])); + + result.q[1] += q[0]*x.q[1] + q[1]*x.q[0]; + + return result; +} + +#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + vduint128 __declspec(naked) __cdecl VDUMul64x64To128(uint64 x, uint64 y) { + __asm { + mov ecx,[esp+4] + + mov eax,[esp+8] + mul dword ptr [esp+16] ;EDX:EAX = BD + mov [ecx+0],eax + mov [ecx+4],edx + + mov eax,[esp+12] + mul dword ptr [esp+20] ;EDX:EAX = AC + mov [ecx+8],eax + mov [ecx+12],edx + + mov eax,[esp+8] + mul dword ptr [esp+20] ;EDX:EAX = BC + add [ecx+4],eax + adc [ecx+8],edx + adc dword ptr [ecx+12], 0 + + mov eax,[esp+12] + mul dword ptr [esp+16] ;EDX:EAX = AD + add [ecx+4],eax + adc [ecx+8],edx + adc dword ptr [ecx+12], 0 + + mov eax, ecx + ret + } + } +#elif !defined(VD_CPU_AMD64) + vduint128 VDUMul64x64To128(uint64 x, uint64 y) { + uint32 x0 = (uint32)x; + uint32 x1 = (uint32)(x >> 32); + uint32 y0 = (uint32)y; + uint32 y1 = (uint32)(y >> 32); + + uint64 m0 = (uint64)x0*y0; + uint64 m1a = (uint64)x1*y0; + uint64 m1b = (uint64)x0*y1; + uint64 m2 = (uint64)x1*y1; + + uint32 s0 = (uint32)m0; + uint32 s1a = (uint32)(m0 >> 32); + uint32 s1b = (uint32)m1a; + uint32 s1c = (uint32)m1b; + uint32 s2a = (uint32)(m1a >> 32); + uint32 s2b = (uint32)(m1b >> 32); + uint32 s2c = (uint32)m2; + uint32 s3 = (uint32)(m2 >> 32); + + vduint128 r; + r.d[0] = s0; + r.d[1] = s1a + s1b; + r.d[2] = r.d[1] < s1b; + r.d[1] += s1c; + r.d[2] += r.d[1] < s1c; + r.d[2] += s2a; + r.d[3] = r.d[2] < s2a; + r.d[2] += s2b; + r.d[3] += r.d[2] < s2b; + r.d[2] += s2c; + r.d[3] += r.d[2] < s2c; + r.d[3] += s3; + + return r; + } +#endif + +uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder) { + vduint128 temp(dividend); + vduint128 divisor2(divisor); + + divisor2 <<= 63; + + uint64 result = 0; + for(int i=0; i<64; ++i) { + result += result; + if (temp >= divisor2) { + temp -= divisor2; + ++result; + } + temp += temp; + } + + remainder = temp.q[1]; + + return result; +} diff --git a/src/thirdparty/VirtualDub/system/source/list.cpp b/src/thirdparty/VirtualDub/system/source/list.cpp index bf443b6a6e7..91912c551de 100644 --- a/src/thirdparty/VirtualDub/system/source/list.cpp +++ b/src/thirdparty/VirtualDub/system/source/list.cpp @@ -1,97 +1,97 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -/////////////////////////////////////////////////////////////////////////// -// -// For those of you who say this looks familiar... it should. This is -// the same linked-list style that the Amiga Exec uses, with dummy head -// and tail nodes. It's really a very convienent way to implement -// doubly-linked lists. -// - -#include "stdafx.h" -#include -#include - -List::List() { - Init(); -} - -void List::Init() { - head.next = tail.prev = 0; - head.prev = &tail; - tail.next = &head; -} - -ListNode *List::RemoveHead() { - if (head.prev->prev) { - ListNode *t = head.prev; - - head.prev->Remove(); - return t; - } - - return 0; -} - -ListNode *List::RemoveTail() { - if (tail.next->next) { - ListNode *t = tail.next; - - tail.next->Remove(); - return t; - } - - return 0; -} - -void List::Take(List &from) { - if (from.IsEmpty()) - return; - - head.prev = from.head.prev; - tail.next = from.tail.next; - head.prev->next = &head; - tail.next->prev = &tail; - - from.Init(); -} - -void List::Swap(List &dst) { - if (IsEmpty()) - Take(dst); - else if (dst.IsEmpty()) - dst.Take(*this); - else { - std::swap(head.prev, dst.head.prev); - std::swap(tail.next, dst.tail.next); - - head.prev->next = &head; - tail.next->prev = &tail; - - dst.head.prev->next = &dst.head; - dst.tail.next->prev = &dst.tail; - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +/////////////////////////////////////////////////////////////////////////// +// +// For those of you who say this looks familiar... it should. This is +// the same linked-list style that the Amiga Exec uses, with dummy head +// and tail nodes. It's really a very convienent way to implement +// doubly-linked lists. +// + +#include "stdafx.h" +#include +#include + +List::List() { + Init(); +} + +void List::Init() { + head.next = tail.prev = 0; + head.prev = &tail; + tail.next = &head; +} + +ListNode *List::RemoveHead() { + if (head.prev->prev) { + ListNode *t = head.prev; + + head.prev->Remove(); + return t; + } + + return 0; +} + +ListNode *List::RemoveTail() { + if (tail.next->next) { + ListNode *t = tail.next; + + tail.next->Remove(); + return t; + } + + return 0; +} + +void List::Take(List &from) { + if (from.IsEmpty()) + return; + + head.prev = from.head.prev; + tail.next = from.tail.next; + head.prev->next = &head; + tail.next->prev = &tail; + + from.Init(); +} + +void List::Swap(List &dst) { + if (IsEmpty()) + Take(dst); + else if (dst.IsEmpty()) + dst.Take(*this); + else { + std::swap(head.prev, dst.head.prev); + std::swap(tail.next, dst.tail.next); + + head.prev->next = &head; + tail.next->prev = &tail; + + dst.head.prev->next = &dst.head; + dst.tail.next->prev = &dst.tail; + } +} diff --git a/src/thirdparty/VirtualDub/system/source/math.cpp b/src/thirdparty/VirtualDub/system/source/math.cpp index b3852cb1145..53bde234a14 100644 --- a/src/thirdparty/VirtualDub/system/source/math.cpp +++ b/src/thirdparty/VirtualDub/system/source/math.cpp @@ -1,185 +1,185 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include - -int VDRoundToInt(double x) { - return (int)floor(x + 0.5); -} - -long VDRoundToLong(double x) { - return (long)floor(x + 0.5); -} - -sint32 VDRoundToInt32(double x) { - return (sint32)floor(x + 0.5); -} - -sint64 VDRoundToInt64(double x) { - return (sint64)floor(x + 0.5); -} - -#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - sint64 __declspec(naked) __stdcall VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder) { - __asm { - push edi - push ebx - mov edi, [esp+12+8] ;edi = b - mov eax, [esp+4+8] ;eax = a[lo] - mul edi ;edx:eax = a[lo]*b - mov ecx, eax ;ecx = (a*b)[lo] - mov eax, [esp+8+8] ;eax = a[hi] - mov ebx, edx ;ebx = (a*b)[mid] - mul edi ;edx:eax = a[hi]*b - add eax, ebx - mov ebx, [esp+16+8] ;ebx = c - adc edx, 0 - div ebx ;eax = (a*b)/c [hi], edx = (a[hi]*b)%c - mov edi, eax ;edi = (a[hi]*b)/c - mov eax, ecx ;eax = (a*b)[lo] - mov ecx, [esp+20+8] - div ebx ;eax = (a*b)/c [lo], edx = (a*b)%c - mov [ecx], edx - mov edx, edi - pop ebx - pop edi - ret 20 - } - } - - uint64 __declspec(naked) __stdcall VDUMulDiv64x32(uint64 a, uint32 b, uint32 c) { - __asm { - mov eax, [esp+4] ;eax = a0 - mul dword ptr [esp+12] ;edx:eax = a0*b - mov dword ptr [esp+4], eax ;tmp = a0*b[0:31] - mov ecx, edx ;ecx = a0*b[32:63] - mov eax, [esp+8] ;eax = a1 - mul dword ptr [esp+12] ;edx:eax = a1*b - add eax, ecx ;edx:eax += a0*b[32:95] - adc edx, 0 ;(cont.) - cmp edx, [esp+16] ;test if a*b[64:95] >= c; equiv to a*b >= (c<<64) - jae invalid ;abort if so (overflow) - div dword ptr [esp+16] ;edx,eax = ((a*b)[32:95]/c, (a*b)[32:95]%c) - mov ecx, eax - mov eax, [esp+4] - div dword ptr [esp+16] - mov edx, ecx - ret 16 -invalid: - mov eax, -1 ;return FFFFFFFFFFFFFFFF - mov edx, -1 - ret 16 - } - } -#elif !defined(VD_CPU_AMD64) - sint64 VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder) { - uint32 a0 = (uint32)a; - uint32 a1 = (uint32)(a >> 32); - - uint64 m0 = (uint64)a0*b; - uint64 m1 = (uint64)a1*b; - - // collect all multiplier terms - uint32 s0 = (uint32)m0; - uint32 s1a = (uint32)(m0 >> 32); - uint32 s1b = (uint32)m1; - uint32 s2 = (uint32)(m1 >> 32); - - // form 96-bit intermediate product - uint32 acc0 = s0; - uint32 acc1 = s1a + s1b; - uint32 acc2 = s2 + (acc1 < s1b); - - // check for overflow (or divide by zero) - if (acc2 >= c) - return 0xFFFFFFFFFFFFFFFFULL; - - // do divide - uint64 div1 = ((uint64)acc2 << 32) + acc1; - uint64 q1 = div1 / c; - uint64 div0 = ((div1 % c) << 32) + acc0; - uint32 q0 = (uint32)(div0 / c); - - remainder = (uint32)(div0 % c); - - return (q1 << 32) + q0; - } - - uint64 VDUMulDiv64x32(uint64 a, uint32 b, uint32 c) { - uint32 r; - - return VDFractionScale64(a, b, c, r); - } -#endif - -sint64 VDMulDiv64(sint64 a, sint64 b, sint64 c) { - bool flip = false; - - if (a < 0) { - a = -a; - flip = true; - } - - if (b < 0) { - b = -b; - flip = !flip; - } - - if (c < 0) { - c = -c; - flip = !flip; - } - - uint64 rem; - uint64 v = VDUDiv128x64To64(VDUMul64x64To128((uint64)a, (uint64)b), (uint64)c, rem); - - if ((rem+rem) >= (uint64)c) - ++v; - - return flip ? -(sint64)v : (sint64)v; -} - -bool VDVerifyFiniteFloats(const float *p0, uint32 n) { - const uint32 *p = (const uint32 *)p0; - - while(n--) { - uint32 v = *p++; - - // 00000000 zero - // 00000001-007FFFFF denormal - // 00800000-7F7FFFFF finite - // 7F800000 infinity - // 7F800001-7FBFFFFF SNaN - // 7FC00000-7FFFFFFF QNaN - - if ((v & 0x7FFFFFFF) >= 0x7F800000) - return false; - } - - return true; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include + +int VDRoundToInt(double x) { + return (int)floor(x + 0.5); +} + +long VDRoundToLong(double x) { + return (long)floor(x + 0.5); +} + +sint32 VDRoundToInt32(double x) { + return (sint32)floor(x + 0.5); +} + +sint64 VDRoundToInt64(double x) { + return (sint64)floor(x + 0.5); +} + +#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + sint64 __declspec(naked) __stdcall VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder) { + __asm { + push edi + push ebx + mov edi, [esp+12+8] ;edi = b + mov eax, [esp+4+8] ;eax = a[lo] + mul edi ;edx:eax = a[lo]*b + mov ecx, eax ;ecx = (a*b)[lo] + mov eax, [esp+8+8] ;eax = a[hi] + mov ebx, edx ;ebx = (a*b)[mid] + mul edi ;edx:eax = a[hi]*b + add eax, ebx + mov ebx, [esp+16+8] ;ebx = c + adc edx, 0 + div ebx ;eax = (a*b)/c [hi], edx = (a[hi]*b)%c + mov edi, eax ;edi = (a[hi]*b)/c + mov eax, ecx ;eax = (a*b)[lo] + mov ecx, [esp+20+8] + div ebx ;eax = (a*b)/c [lo], edx = (a*b)%c + mov [ecx], edx + mov edx, edi + pop ebx + pop edi + ret 20 + } + } + + uint64 __declspec(naked) __stdcall VDUMulDiv64x32(uint64 a, uint32 b, uint32 c) { + __asm { + mov eax, [esp+4] ;eax = a0 + mul dword ptr [esp+12] ;edx:eax = a0*b + mov dword ptr [esp+4], eax ;tmp = a0*b[0:31] + mov ecx, edx ;ecx = a0*b[32:63] + mov eax, [esp+8] ;eax = a1 + mul dword ptr [esp+12] ;edx:eax = a1*b + add eax, ecx ;edx:eax += a0*b[32:95] + adc edx, 0 ;(cont.) + cmp edx, [esp+16] ;test if a*b[64:95] >= c; equiv to a*b >= (c<<64) + jae invalid ;abort if so (overflow) + div dword ptr [esp+16] ;edx,eax = ((a*b)[32:95]/c, (a*b)[32:95]%c) + mov ecx, eax + mov eax, [esp+4] + div dword ptr [esp+16] + mov edx, ecx + ret 16 +invalid: + mov eax, -1 ;return FFFFFFFFFFFFFFFF + mov edx, -1 + ret 16 + } + } +#elif !defined(VD_CPU_AMD64) + sint64 VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder) { + uint32 a0 = (uint32)a; + uint32 a1 = (uint32)(a >> 32); + + uint64 m0 = (uint64)a0*b; + uint64 m1 = (uint64)a1*b; + + // collect all multiplier terms + uint32 s0 = (uint32)m0; + uint32 s1a = (uint32)(m0 >> 32); + uint32 s1b = (uint32)m1; + uint32 s2 = (uint32)(m1 >> 32); + + // form 96-bit intermediate product + uint32 acc0 = s0; + uint32 acc1 = s1a + s1b; + uint32 acc2 = s2 + (acc1 < s1b); + + // check for overflow (or divide by zero) + if (acc2 >= c) + return 0xFFFFFFFFFFFFFFFFULL; + + // do divide + uint64 div1 = ((uint64)acc2 << 32) + acc1; + uint64 q1 = div1 / c; + uint64 div0 = ((div1 % c) << 32) + acc0; + uint32 q0 = (uint32)(div0 / c); + + remainder = (uint32)(div0 % c); + + return (q1 << 32) + q0; + } + + uint64 VDUMulDiv64x32(uint64 a, uint32 b, uint32 c) { + uint32 r; + + return VDFractionScale64(a, b, c, r); + } +#endif + +sint64 VDMulDiv64(sint64 a, sint64 b, sint64 c) { + bool flip = false; + + if (a < 0) { + a = -a; + flip = true; + } + + if (b < 0) { + b = -b; + flip = !flip; + } + + if (c < 0) { + c = -c; + flip = !flip; + } + + uint64 rem; + uint64 v = VDUDiv128x64To64(VDUMul64x64To128((uint64)a, (uint64)b), (uint64)c, rem); + + if ((rem+rem) >= (uint64)c) + ++v; + + return flip ? -(sint64)v : (sint64)v; +} + +bool VDVerifyFiniteFloats(const float *p0, uint32 n) { + const uint32 *p = (const uint32 *)p0; + + while(n--) { + uint32 v = *p++; + + // 00000000 zero + // 00000001-007FFFFF denormal + // 00800000-7F7FFFFF finite + // 7F800000 infinity + // 7F800001-7FBFFFFF SNaN + // 7FC00000-7FFFFFFF QNaN + + if ((v & 0x7FFFFFFF) >= 0x7F800000) + return false; + } + + return true; +} diff --git a/src/thirdparty/VirtualDub/system/source/memory.cpp b/src/thirdparty/VirtualDub/system/source/memory.cpp index 911d3f4b128..5143bddefa0 100644 --- a/src/thirdparty/VirtualDub/system/source/memory.cpp +++ b/src/thirdparty/VirtualDub/system/source/memory.cpp @@ -1,472 +1,472 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include -#include -#include -#include - -void *VDAlignedMalloc(size_t n, unsigned alignment) { -#ifdef VD_COMPILER_MSVC - return _aligned_malloc(n, alignment); -#else - void *p = malloc(n + sizeof(void *) + alignment - 1); - - if (p) { - void *alignedp = (void *)(((uintptr)p + sizeof(void *) + alignment - 1) & ~((uintptr)alignment - 1)); - - ((void **)alignedp)[-1] = p; - p = alignedp; - } - - return p; -#endif -} - -void VDAlignedFree(void *p) { -#ifdef VD_COMPILER_MSVC - _aligned_free(p); -#else - free(((void **)p)[-1]); -#endif -} - -void *VDAlignedVirtualAlloc(size_t n) { - return VirtualAlloc(NULL, n, MEM_COMMIT, PAGE_READWRITE); -} - -void VDAlignedVirtualFree(void *p) { - VirtualFree(p, 0, MEM_RELEASE); -} - -void VDSwapMemoryScalar(void *p0, void *p1, size_t bytes) { - uint32 *dst0 = (uint32 *)p0; - uint32 *dst1 = (uint32 *)p1; - - while(bytes >= 4) { - uint32 a = *dst0; - uint32 b = *dst1; - - *dst0++ = b; - *dst1++ = a; - - bytes -= 4; - } - - char *dstb0 = (char *)dst0; - char *dstb1 = (char *)dst1; - - while(bytes--) { - char a = *dstb0; - char b = *dstb1; - - *dstb0++ = b; - *dstb1++ = a; - } -} - -#if defined(VD_CPU_AMD64) || defined(VD_CPU_X86) - void VDSwapMemorySSE(void *p0, void *p1, size_t bytes) { - if (((uint32)(size_t)p0 | (uint32)(size_t)p1) & 15) - return VDSwapMemoryScalar(p0, p1, bytes); - - __m128 *pv0 = (__m128 *)p0; - __m128 *pv1 = (__m128 *)p1; - - size_t veccount = bytes >> 4; - if (veccount) { - do { - __m128 v0 = *pv0; - __m128 v1 = *pv1; - - *pv0++ = v1; - *pv1++ = v0; - } while(--veccount); - } - - uint32 left = bytes & 15; - if (left) { - uint8 *pb0 = (uint8 *)pv0; - uint8 *pb1 = (uint8 *)pv1; - do { - uint8 b0 = *pb0; - uint8 b1 = *pb1; - - *pb0++ = b1; - *pb1++ = b0; - } while(--left); - } - } -#endif - -void (__cdecl *VDSwapMemory)(void *p0, void *p1, size_t bytes) = VDSwapMemoryScalar; - -void VDInvertMemory(void *p, unsigned bytes) { - char *dst = (char *)p; - - if (!bytes) - return; - - while((int)dst & 3) { - *dst = ~*dst; - ++dst; - - if (!--bytes) - return; - } - - unsigned lcount = bytes >> 2; - - if (lcount) - do { - *(long *)dst = ~*(long *)dst; - dst += 4; - } while(--lcount); - - bytes &= 3; - - while(bytes--) { - *dst = ~*dst; - ++dst; - } -} - -namespace { - uintptr VDGetSystemPageSizeW32() { - SYSTEM_INFO sysInfo; - GetSystemInfo(&sysInfo); - - return sysInfo.dwPageSize; - } - - uintptr VDGetSystemPageSize() { - static uintptr pageSize = VDGetSystemPageSizeW32(); - - return pageSize; - } -} - -bool VDIsValidReadRegion(const void *p0, size_t bytes) { - if (!bytes) - return true; - - if (!p0) - return false; - - uintptr pageSize = VDGetSystemPageSize(); - uintptr p = (uintptr)p0; - uintptr pLimit = p + (bytes-1); - - vd_seh_guard_try { - for(;;) { - *(volatile char *)p; - - if (pLimit - p < pageSize) - break; - - p += pageSize; - } - } vd_seh_guard_except { - return false; - } - - return true; -} - -bool VDIsValidWriteRegion(void *p0, size_t bytes) { - if (!bytes) - return true; - - if (!p0) - return false; - - // Note: Unlike IsValidWritePtr(), this is threadsafe. - - uintptr pageSize = VDGetSystemPageSize(); - uintptr p = (uintptr)p0; - uintptr pLimit = p + (bytes-1); - p &= ~(uintptr)3; - - vd_seh_guard_try { - - for(;;) { - VDAtomicInt::staticCompareExchange((volatile int *)p, 0xa5, 0xa5); - - if (pLimit - p < pageSize) - break; - - p += pageSize; - } - } vd_seh_guard_except { - return false; - } - - return true; -} - -bool VDCompareRect(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, size_t w, size_t h) { - if (!w || !h) - return false; - - do { - if (memcmp(dst, src, w)) - return true; - - dst = (char *)dst + dstpitch; - src = (const char *)src + srcpitch; - } while(--h); - - return false; -} - -const void *VDMemCheck8(const void *src, uint8 value, size_t count) { - if (count) { - const uint8 *src8 = (const uint8 *)src; - - do { - if (*src8 != value) - return src8; - - ++src8; - } while(--count); - } - - return NULL; -} - -void VDMemset8(void *dst, uint8 value, size_t count) { - if (count) { - uint8 *dst2 = (uint8 *)dst; - - do { - *dst2++ = value; - } while(--count); - } -} - -void VDMemset16(void *dst, uint16 value, size_t count) { - if (count) { - uint16 *dst2 = (uint16 *)dst; - - do { - *dst2++ = value; - } while(--count); - } -} - -void VDMemset24(void *dst, uint32 value, size_t count) { - if (count) { - uint8 *dst2 = (uint8 *)dst; - uint8 c0 = (uint8)value; - uint8 c1 = (uint8)(value >> 8); - uint8 c2 = (uint8)(value >> 16); - - do { - *dst2++ = c0; - *dst2++ = c1; - *dst2++ = c2; - } while(--count); - } -} - -void VDMemset32(void *dst, uint32 value, size_t count) { - if (count) { - uint32 *dst2 = (uint32 *)dst; - - do { - *dst2++ = value; - } while(--count); - } -} - -void VDMemset64(void *dst, uint64 value, size_t count) { - if (count) { - uint64 *dst2 = (uint64 *)dst; - - do { - *dst2++ = value; - } while(--count); - } -} - -void VDMemset128(void *dst, const void *src0, size_t count) { - if (count) { - const uint32 *src = (const uint32 *)src0; - uint32 a0 = src[0]; - uint32 a1 = src[1]; - uint32 a2 = src[2]; - uint32 a3 = src[3]; - - uint32 *dst2 = (uint32 *)dst; - - do { - dst2[0] = a0; - dst2[1] = a1; - dst2[2] = a2; - dst2[3] = a3; - dst2 += 4; - } while(--count); - } -} - -void VDMemsetPointer(void *dst, const void *value, size_t count) { -#if defined(VD_CPU_X86) || defined(VD_CPU_ARM) - VDMemset32(dst, (uint32)(size_t)value, count); -#elif defined(VD_CPU_AMD64) - VDMemset64(dst, (uint64)(size_t)value, count); -#else - #error Unknown pointer size -#endif -} - -void VDMemset8Rect(void *dst, ptrdiff_t pitch, uint8 value, size_t w, size_t h) { - if (w>0 && h>0) { - do { - memset(dst, value, w); - dst = (char *)dst + pitch; - } while(--h); - } -} - -void VDMemset16Rect(void *dst, ptrdiff_t pitch, uint16 value, size_t w, size_t h) { - if (w>0 && h>0) { - do { - VDMemset16(dst, value, w); - dst = (char *)dst + pitch; - } while(--h); - } -} - -void VDMemset24Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h) { - if (w>0 && h>0) { - do { - VDMemset24(dst, value, w); - dst = (char *)dst + pitch; - } while(--h); - } -} - -void VDMemset32Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h) { - if (w>0 && h>0) { - do { - VDMemset32(dst, value, w); - dst = (char *)dst + pitch; - } while(--h); - } -} - -#if defined(_WIN32) && defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - extern "C" void __cdecl VDFastMemcpyPartialScalarAligned8(void *dst, const void *src, size_t bytes); - extern "C" void __cdecl VDFastMemcpyPartialMMX(void *dst, const void *src, size_t bytes); - extern "C" void __cdecl VDFastMemcpyPartialMMX2(void *dst, const void *src, size_t bytes); - extern "C" void __cdecl VDFastMemcpyPartialSSE2(void *dst, const void *src, size_t bytes); //MPC custom code - - void VDFastMemcpyPartialScalar(void *dst, const void *src, size_t bytes) { - if (!(((int)dst | (int)src | bytes) & 7)) - VDFastMemcpyPartialScalarAligned8(dst, src, bytes); - else - memcpy(dst, src, bytes); - } - - void VDFastMemcpyFinishScalar() { - } - - void __cdecl VDFastMemcpyFinishMMX() { - _mm_empty(); - } - - void __cdecl VDFastMemcpyFinishMMX2() { - _mm_empty(); - _mm_sfence(); - } - - void (__cdecl *VDFastMemcpyPartial)(void *dst, const void *src, size_t bytes) = VDFastMemcpyPartialScalar; - void (__cdecl *VDFastMemcpyFinish)() = VDFastMemcpyFinishScalar; - - void VDFastMemcpyAutodetect() { - long exts = CPUGetEnabledExtensions(); - - if (exts & CPUF_SUPPORTS_SSE) { - VDFastMemcpyPartial = VDFastMemcpyPartialMMX2; - VDFastMemcpyFinish = VDFastMemcpyFinishMMX2; - VDSwapMemory = VDSwapMemorySSE; - } else if (exts & CPUF_SUPPORTS_INTEGER_SSE) { - VDFastMemcpyPartial = VDFastMemcpyPartialMMX2; - VDFastMemcpyFinish = VDFastMemcpyFinishMMX2; - VDSwapMemory = VDSwapMemoryScalar; - } else if (exts & CPUF_SUPPORTS_MMX) { - VDFastMemcpyPartial = VDFastMemcpyPartialMMX; - VDFastMemcpyFinish = VDFastMemcpyFinishMMX; - VDSwapMemory = VDSwapMemoryScalar; - } else { - VDFastMemcpyPartial = VDFastMemcpyPartialScalar; - VDFastMemcpyFinish = VDFastMemcpyFinishScalar; - VDSwapMemory = VDSwapMemoryScalar; - } - } - -#else - void VDFastMemcpyPartial(void *dst, const void *src, size_t bytes) { - memcpy(dst, src, bytes); - } - - void VDFastMemcpyFinish() { - } - - void VDFastMemcpyAutodetect() { - } -#endif - -void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h) { - if (w <= 0 || h <= 0) - return; - - if (w == srcstride && w == dststride) - VDFastMemcpyPartial(dst, src, w*h); - else { - char *dst2 = (char *)dst; - const char *src2 = (const char *)src; - - do { - VDFastMemcpyPartial(dst2, src2, w); - dst2 += dststride; - src2 += srcstride; - } while(--h); - } - VDFastMemcpyFinish(); -} - -bool VDMemcpyGuarded(void *dst, const void *src, size_t bytes) { - vd_seh_guard_try { - memcpy(dst, src, bytes); - } vd_seh_guard_except { - return false; - } - - return true; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include + +void *VDAlignedMalloc(size_t n, unsigned alignment) { +#ifdef VD_COMPILER_MSVC + return _aligned_malloc(n, alignment); +#else + void *p = malloc(n + sizeof(void *) + alignment - 1); + + if (p) { + void *alignedp = (void *)(((uintptr)p + sizeof(void *) + alignment - 1) & ~((uintptr)alignment - 1)); + + ((void **)alignedp)[-1] = p; + p = alignedp; + } + + return p; +#endif +} + +void VDAlignedFree(void *p) { +#ifdef VD_COMPILER_MSVC + _aligned_free(p); +#else + free(((void **)p)[-1]); +#endif +} + +void *VDAlignedVirtualAlloc(size_t n) { + return VirtualAlloc(NULL, n, MEM_COMMIT, PAGE_READWRITE); +} + +void VDAlignedVirtualFree(void *p) { + VirtualFree(p, 0, MEM_RELEASE); +} + +void VDSwapMemoryScalar(void *p0, void *p1, size_t bytes) { + uint32 *dst0 = (uint32 *)p0; + uint32 *dst1 = (uint32 *)p1; + + while(bytes >= 4) { + uint32 a = *dst0; + uint32 b = *dst1; + + *dst0++ = b; + *dst1++ = a; + + bytes -= 4; + } + + char *dstb0 = (char *)dst0; + char *dstb1 = (char *)dst1; + + while(bytes--) { + char a = *dstb0; + char b = *dstb1; + + *dstb0++ = b; + *dstb1++ = a; + } +} + +#if defined(VD_CPU_AMD64) || defined(VD_CPU_X86) + void VDSwapMemorySSE(void *p0, void *p1, size_t bytes) { + if (((uint32)(size_t)p0 | (uint32)(size_t)p1) & 15) + return VDSwapMemoryScalar(p0, p1, bytes); + + __m128 *pv0 = (__m128 *)p0; + __m128 *pv1 = (__m128 *)p1; + + size_t veccount = bytes >> 4; + if (veccount) { + do { + __m128 v0 = *pv0; + __m128 v1 = *pv1; + + *pv0++ = v1; + *pv1++ = v0; + } while(--veccount); + } + + uint32 left = bytes & 15; + if (left) { + uint8 *pb0 = (uint8 *)pv0; + uint8 *pb1 = (uint8 *)pv1; + do { + uint8 b0 = *pb0; + uint8 b1 = *pb1; + + *pb0++ = b1; + *pb1++ = b0; + } while(--left); + } + } +#endif + +void (__cdecl *VDSwapMemory)(void *p0, void *p1, size_t bytes) = VDSwapMemoryScalar; + +void VDInvertMemory(void *p, unsigned bytes) { + char *dst = (char *)p; + + if (!bytes) + return; + + while((int)dst & 3) { + *dst = ~*dst; + ++dst; + + if (!--bytes) + return; + } + + unsigned lcount = bytes >> 2; + + if (lcount) + do { + *(long *)dst = ~*(long *)dst; + dst += 4; + } while(--lcount); + + bytes &= 3; + + while(bytes--) { + *dst = ~*dst; + ++dst; + } +} + +namespace { + uintptr VDGetSystemPageSizeW32() { + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + + return sysInfo.dwPageSize; + } + + uintptr VDGetSystemPageSize() { + static uintptr pageSize = VDGetSystemPageSizeW32(); + + return pageSize; + } +} + +bool VDIsValidReadRegion(const void *p0, size_t bytes) { + if (!bytes) + return true; + + if (!p0) + return false; + + uintptr pageSize = VDGetSystemPageSize(); + uintptr p = (uintptr)p0; + uintptr pLimit = p + (bytes-1); + + vd_seh_guard_try { + for(;;) { + *(volatile char *)p; + + if (pLimit - p < pageSize) + break; + + p += pageSize; + } + } vd_seh_guard_except { + return false; + } + + return true; +} + +bool VDIsValidWriteRegion(void *p0, size_t bytes) { + if (!bytes) + return true; + + if (!p0) + return false; + + // Note: Unlike IsValidWritePtr(), this is threadsafe. + + uintptr pageSize = VDGetSystemPageSize(); + uintptr p = (uintptr)p0; + uintptr pLimit = p + (bytes-1); + p &= ~(uintptr)3; + + vd_seh_guard_try { + + for(;;) { + VDAtomicInt::staticCompareExchange((volatile int *)p, 0xa5, 0xa5); + + if (pLimit - p < pageSize) + break; + + p += pageSize; + } + } vd_seh_guard_except { + return false; + } + + return true; +} + +bool VDCompareRect(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, size_t w, size_t h) { + if (!w || !h) + return false; + + do { + if (memcmp(dst, src, w)) + return true; + + dst = (char *)dst + dstpitch; + src = (const char *)src + srcpitch; + } while(--h); + + return false; +} + +const void *VDMemCheck8(const void *src, uint8 value, size_t count) { + if (count) { + const uint8 *src8 = (const uint8 *)src; + + do { + if (*src8 != value) + return src8; + + ++src8; + } while(--count); + } + + return NULL; +} + +void VDMemset8(void *dst, uint8 value, size_t count) { + if (count) { + uint8 *dst2 = (uint8 *)dst; + + do { + *dst2++ = value; + } while(--count); + } +} + +void VDMemset16(void *dst, uint16 value, size_t count) { + if (count) { + uint16 *dst2 = (uint16 *)dst; + + do { + *dst2++ = value; + } while(--count); + } +} + +void VDMemset24(void *dst, uint32 value, size_t count) { + if (count) { + uint8 *dst2 = (uint8 *)dst; + uint8 c0 = (uint8)value; + uint8 c1 = (uint8)(value >> 8); + uint8 c2 = (uint8)(value >> 16); + + do { + *dst2++ = c0; + *dst2++ = c1; + *dst2++ = c2; + } while(--count); + } +} + +void VDMemset32(void *dst, uint32 value, size_t count) { + if (count) { + uint32 *dst2 = (uint32 *)dst; + + do { + *dst2++ = value; + } while(--count); + } +} + +void VDMemset64(void *dst, uint64 value, size_t count) { + if (count) { + uint64 *dst2 = (uint64 *)dst; + + do { + *dst2++ = value; + } while(--count); + } +} + +void VDMemset128(void *dst, const void *src0, size_t count) { + if (count) { + const uint32 *src = (const uint32 *)src0; + uint32 a0 = src[0]; + uint32 a1 = src[1]; + uint32 a2 = src[2]; + uint32 a3 = src[3]; + + uint32 *dst2 = (uint32 *)dst; + + do { + dst2[0] = a0; + dst2[1] = a1; + dst2[2] = a2; + dst2[3] = a3; + dst2 += 4; + } while(--count); + } +} + +void VDMemsetPointer(void *dst, const void *value, size_t count) { +#if defined(VD_CPU_X86) || defined(VD_CPU_ARM) + VDMemset32(dst, (uint32)(size_t)value, count); +#elif defined(VD_CPU_AMD64) + VDMemset64(dst, (uint64)(size_t)value, count); +#else + #error Unknown pointer size +#endif +} + +void VDMemset8Rect(void *dst, ptrdiff_t pitch, uint8 value, size_t w, size_t h) { + if (w>0 && h>0) { + do { + memset(dst, value, w); + dst = (char *)dst + pitch; + } while(--h); + } +} + +void VDMemset16Rect(void *dst, ptrdiff_t pitch, uint16 value, size_t w, size_t h) { + if (w>0 && h>0) { + do { + VDMemset16(dst, value, w); + dst = (char *)dst + pitch; + } while(--h); + } +} + +void VDMemset24Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h) { + if (w>0 && h>0) { + do { + VDMemset24(dst, value, w); + dst = (char *)dst + pitch; + } while(--h); + } +} + +void VDMemset32Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h) { + if (w>0 && h>0) { + do { + VDMemset32(dst, value, w); + dst = (char *)dst + pitch; + } while(--h); + } +} + +#if defined(_WIN32) && defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + extern "C" void __cdecl VDFastMemcpyPartialScalarAligned8(void *dst, const void *src, size_t bytes); + extern "C" void __cdecl VDFastMemcpyPartialMMX(void *dst, const void *src, size_t bytes); + extern "C" void __cdecl VDFastMemcpyPartialMMX2(void *dst, const void *src, size_t bytes); + extern "C" void __cdecl VDFastMemcpyPartialSSE2(void *dst, const void *src, size_t bytes); //MPC custom code + + void VDFastMemcpyPartialScalar(void *dst, const void *src, size_t bytes) { + if (!(((int)dst | (int)src | bytes) & 7)) + VDFastMemcpyPartialScalarAligned8(dst, src, bytes); + else + memcpy(dst, src, bytes); + } + + void VDFastMemcpyFinishScalar() { + } + + void __cdecl VDFastMemcpyFinishMMX() { + _mm_empty(); + } + + void __cdecl VDFastMemcpyFinishMMX2() { + _mm_empty(); + _mm_sfence(); + } + + void (__cdecl *VDFastMemcpyPartial)(void *dst, const void *src, size_t bytes) = VDFastMemcpyPartialScalar; + void (__cdecl *VDFastMemcpyFinish)() = VDFastMemcpyFinishScalar; + + void VDFastMemcpyAutodetect() { + long exts = CPUGetEnabledExtensions(); + + if (exts & CPUF_SUPPORTS_SSE) { + VDFastMemcpyPartial = VDFastMemcpyPartialMMX2; + VDFastMemcpyFinish = VDFastMemcpyFinishMMX2; + VDSwapMemory = VDSwapMemorySSE; + } else if (exts & CPUF_SUPPORTS_INTEGER_SSE) { + VDFastMemcpyPartial = VDFastMemcpyPartialMMX2; + VDFastMemcpyFinish = VDFastMemcpyFinishMMX2; + VDSwapMemory = VDSwapMemoryScalar; + } else if (exts & CPUF_SUPPORTS_MMX) { + VDFastMemcpyPartial = VDFastMemcpyPartialMMX; + VDFastMemcpyFinish = VDFastMemcpyFinishMMX; + VDSwapMemory = VDSwapMemoryScalar; + } else { + VDFastMemcpyPartial = VDFastMemcpyPartialScalar; + VDFastMemcpyFinish = VDFastMemcpyFinishScalar; + VDSwapMemory = VDSwapMemoryScalar; + } + } + +#else + void VDFastMemcpyPartial(void *dst, const void *src, size_t bytes) { + memcpy(dst, src, bytes); + } + + void VDFastMemcpyFinish() { + } + + void VDFastMemcpyAutodetect() { + } +#endif + +void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h) { + if (w <= 0 || h <= 0) + return; + + if (w == srcstride && w == dststride) + VDFastMemcpyPartial(dst, src, w*h); + else { + char *dst2 = (char *)dst; + const char *src2 = (const char *)src; + + do { + VDFastMemcpyPartial(dst2, src2, w); + dst2 += dststride; + src2 += srcstride; + } while(--h); + } + VDFastMemcpyFinish(); +} + +bool VDMemcpyGuarded(void *dst, const void *src, size_t bytes) { + vd_seh_guard_try { + memcpy(dst, src, bytes); + } vd_seh_guard_except { + return false; + } + + return true; +} diff --git a/src/thirdparty/VirtualDub/system/source/progress.cpp b/src/thirdparty/VirtualDub/system/source/progress.cpp index 1ac26a0f65f..64075f40314 100644 --- a/src/thirdparty/VirtualDub/system/source/progress.cpp +++ b/src/thirdparty/VirtualDub/system/source/progress.cpp @@ -1,35 +1,35 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include -#include -#include -#include -#include - +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +#include +#include +#include +#include +#include + diff --git a/src/thirdparty/VirtualDub/system/source/protscope.cpp b/src/thirdparty/VirtualDub/system/source/protscope.cpp index 61208282418..cc7092c3a4a 100644 --- a/src/thirdparty/VirtualDub/system/source/protscope.cpp +++ b/src/thirdparty/VirtualDub/system/source/protscope.cpp @@ -1,37 +1,37 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -VDProtectedAutoScope *VDGetProtectedScopeLinkNull() { - return NULL; -} - -void VDSetProtectedScopeLinkNull(VDProtectedAutoScope *) { -} - -tpVDGetProtectedScopeLink g_pVDGetProtectedScopeLink = VDGetProtectedScopeLinkNull; -tpVDSetProtectedScopeLink g_pVDSetProtectedScopeLink = VDSetProtectedScopeLinkNull; +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +VDProtectedAutoScope *VDGetProtectedScopeLinkNull() { + return NULL; +} + +void VDSetProtectedScopeLinkNull(VDProtectedAutoScope *) { +} + +tpVDGetProtectedScopeLink g_pVDGetProtectedScopeLink = VDGetProtectedScopeLinkNull; +tpVDSetProtectedScopeLink g_pVDSetProtectedScopeLink = VDSetProtectedScopeLinkNull; diff --git a/src/thirdparty/VirtualDub/system/source/refcount.cpp b/src/thirdparty/VirtualDub/system/source/refcount.cpp index f0d82760a81..4dcf5d08cd7 100644 --- a/src/thirdparty/VirtualDub/system/source/refcount.cpp +++ b/src/thirdparty/VirtualDub/system/source/refcount.cpp @@ -1,29 +1,29 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2009 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -vdsaferelease_t vdsaferelease; +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2009 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +vdsaferelease_t vdsaferelease; diff --git a/src/thirdparty/VirtualDub/system/source/registry.cpp b/src/thirdparty/VirtualDub/system/source/registry.cpp index ef8059a61e2..d36202e970f 100644 --- a/src/thirdparty/VirtualDub/system/source/registry.cpp +++ b/src/thirdparty/VirtualDub/system/source/registry.cpp @@ -1,480 +1,480 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -class VDRegistryProviderW32 : public IVDRegistryProvider { -public: - void *GetUserKey(); - void *GetMachineKey(); - void *CreateKey(void *key, const char *path, bool write); - void CloseKey(void *key); - - bool SetBool(void *key, const char *pszName, bool); - bool SetInt(void *key, const char *pszName, int); - bool SetString(void *key, const char *pszName, const char *pszString); - bool SetString(void *key, const char *pszName, const wchar_t *pszString); - bool SetBinary(void *key, const char *pszName, const char *data, int len); - - Type GetType(void *key, const char *name); - bool GetBool(void *key, const char *pszName, bool& val); - bool GetInt(void *key, const char *pszName, int& val); - bool GetString(void *key, const char *pszName, VDStringA& s); - bool GetString(void *key, const char *pszName, VDStringW& s); - - int GetBinaryLength(void *key, const char *pszName); - bool GetBinary(void *key, const char *pszName, char *buf, int maxlen); - - bool RemoveValue(void *key, const char *name); - bool RemoveKey(void *key, const char *name); - - void *EnumKeysBegin(void *key); - const char *EnumKeysNext(void *enumerator); - void EnumKeysClose(void *enumerator); - - void *EnumValuesBegin(void *key); - const char *EnumValuesNext(void *enumerator); - void EnumValuesClose(void *enumerator); - -protected: - struct KeyEnumerator { - void *mKey; - uint32 mIndex; - char mName[256]; - }; - - struct ValueEnumerator { - void *mKey; - uint32 mIndex; - char mName[256]; - }; -}; - -void *VDRegistryProviderW32::GetUserKey() { - return HKEY_CURRENT_USER; -} - -void *VDRegistryProviderW32::GetMachineKey() { - return HKEY_LOCAL_MACHINE; -} - -void *VDRegistryProviderW32::CreateKey(void *key, const char *path, bool write) { - HKEY newKey; - - if (write) { - if (RegCreateKeyEx((HKEY)key, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newKey, NULL)) - return NULL; - } else { - if (RegOpenKeyEx((HKEY)key, path, 0, KEY_READ, &newKey)) - return NULL; - } - - return newKey; -} - -void VDRegistryProviderW32::CloseKey(void *key) { - RegCloseKey((HKEY)key); -} - -bool VDRegistryProviderW32::SetBool(void *key, const char *pszName, bool val) { - DWORD dw = val; - - return !RegSetValueEx((HKEY)key, pszName, 0, REG_DWORD, (const BYTE *)&dw, sizeof dw); -} - -bool VDRegistryProviderW32::SetInt(void *key, const char *pszName, int val) { - DWORD dw = val; - - return !RegSetValueEx((HKEY)key, pszName, 0, REG_DWORD, (const BYTE *)&dw, sizeof dw); -} - -bool VDRegistryProviderW32::SetString(void *key, const char *pszName, const char *pszString) { - return !RegSetValueEx((HKEY)key, pszName, 0, REG_SZ, (const BYTE *)pszString, strlen(pszString)); -} - -bool VDRegistryProviderW32::SetString(void *key, const char *pszName, const wchar_t *pszString) { - if (!VDIsWindowsNT()) { - VDStringA s(VDTextWToA(pszString)); - - if (RegSetValueEx((HKEY)key, pszName, 0, REG_SZ, (const BYTE *)s.data(), s.size())) - return false; - } else { - if (RegSetValueExW((HKEY)key, VDTextAToW(pszName).c_str(), 0, REG_SZ, (const BYTE *)pszString, sizeof(wchar_t) * wcslen(pszString))) - return false; - } - - return true; -} - -bool VDRegistryProviderW32::SetBinary(void *key, const char *pszName, const char *data, int len) { - return !RegSetValueEx((HKEY)key, pszName, 0, REG_BINARY, (const BYTE *)data, len); -} - -IVDRegistryProvider::Type VDRegistryProviderW32::GetType(void *key, const char *name) { - DWORD type; - - if (RegQueryValueEx((HKEY)key, name, 0, &type, NULL, NULL)) - return kTypeUnknown; - - switch(type) { - case REG_SZ: - return kTypeString; - - case REG_BINARY: - return kTypeBinary; - - case REG_DWORD: - return kTypeInt; - - default: - return kTypeUnknown; - } -} - -bool VDRegistryProviderW32::GetBool(void *key, const char *pszName, bool& val) { - DWORD type; - DWORD v; - DWORD len = sizeof(DWORD); - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)&v, &len) || type != REG_DWORD) - return false; - - val = (v != 0); - return true; -} - -bool VDRegistryProviderW32::GetInt(void *key, const char *pszName, int& val) { - DWORD type; - DWORD v; - DWORD len = sizeof(DWORD); - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)&v, &len) || type != REG_DWORD) - return false; - - val = v; - return true; -} - -bool VDRegistryProviderW32::GetString(void *key, const char *pszName, VDStringA& str) { - DWORD type; - DWORD s = sizeof(DWORD); - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, NULL, &s) || type != REG_SZ) - return false; - - str.resize(s); - if (RegQueryValueEx((HKEY)key, pszName, 0, NULL, (BYTE *)str.data(), &s)) - return false; - - if (!s) - str.clear(); - else - str.resize(strlen(str.c_str())); // Trim off pesky terminating NULLs. - - return true; -} - -bool VDRegistryProviderW32::GetString(void *key, const char *pszName, VDStringW& str) { - if (!VDIsWindowsNT()) { - VDStringA v; - if (!GetString(key, pszName, v)) - return false; - str = VDTextAToW(v); - return true; - } - - const VDStringW wsName(VDTextAToW(pszName)); - DWORD type; - DWORD s = sizeof(DWORD); - - if (RegQueryValueExW((HKEY)key, wsName.c_str(), 0, &type, NULL, &s) || type != REG_SZ) - return false; - - if (s <= 0) - str.clear(); - else { - str.resize((s + sizeof(wchar_t) - 1) / sizeof(wchar_t)); - - if (RegQueryValueExW((HKEY)key, wsName.c_str(), 0, NULL, (BYTE *)&str[0], &s)) - return false; - - str.resize(wcslen(str.c_str())); // Trim off pesky terminating NULLs. - } - - return true; -} - -int VDRegistryProviderW32::GetBinaryLength(void *key, const char *pszName) { - DWORD type; - DWORD s = sizeof(DWORD); - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, NULL, &s) || type != REG_BINARY) - return -1; - - return s; -} - -bool VDRegistryProviderW32::GetBinary(void *key, const char *pszName, char *buf, int maxlen) { - DWORD type; - DWORD s = maxlen; - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)buf, &s) || maxlen < (int)s || type != REG_BINARY) - return false; - - return true; -} - -bool VDRegistryProviderW32::RemoveValue(void *key, const char *name) { - return 0 != RegDeleteValue((HKEY)key, name); -} - -bool VDRegistryProviderW32::RemoveKey(void *key, const char *name) { - return 0 != RegDeleteKey((HKEY)key, name); -} - -void *VDRegistryProviderW32::EnumKeysBegin(void *key) { - KeyEnumerator *ke = new KeyEnumerator; - - ke->mKey = key; - ke->mIndex = 0; - - return ke; -} - -const char *VDRegistryProviderW32::EnumKeysNext(void *enumerator) { - KeyEnumerator *ke = (KeyEnumerator *)enumerator; - - DWORD len = sizeof(ke->mName)/sizeof(ke->mName[0]); - FILETIME ft; - LONG error = RegEnumKeyExA((HKEY)ke->mKey, ke->mIndex, ke->mName, &len, NULL, NULL, NULL, &ft); - - if (error) - return NULL; - - ++ke->mIndex; - return ke->mName; -} - -void VDRegistryProviderW32::EnumKeysClose(void *enumerator) { - delete (KeyEnumerator *)enumerator; -} - -void *VDRegistryProviderW32::EnumValuesBegin(void *key) { - ValueEnumerator *ve = new ValueEnumerator; - - ve->mKey = key; - ve->mIndex = 0; - - return ve; -} - -const char *VDRegistryProviderW32::EnumValuesNext(void *enumerator) { - ValueEnumerator *ve = (ValueEnumerator *)enumerator; - - DWORD len = sizeof(ve->mName)/sizeof(ve->mName[0]); - LONG error = RegEnumValueA((HKEY)ve->mKey, ve->mIndex, ve->mName, &len, NULL, NULL, NULL, NULL); - - if (error) - return NULL; - - ++ve->mIndex; - return ve->mName; -} - -void VDRegistryProviderW32::EnumValuesClose(void *enumerator) { - delete (ValueEnumerator *)enumerator; -} - -/////////////////////////////////////////////////////////////////////////// - -VDRegistryProviderW32 g_VDRegistryProviderW32; -IVDRegistryProvider *g_pVDRegistryProvider = &g_VDRegistryProviderW32; - -IVDRegistryProvider *VDGetRegistryProvider() { - return g_pVDRegistryProvider; -} - -void VDSetRegistryProvider(IVDRegistryProvider *provider) { - g_pVDRegistryProvider = provider; -} - -/////////////////////////////////////////////////////////////////////////// - -VDRegistryKey::VDRegistryKey(const char *keyName, bool global, bool write) { - IVDRegistryProvider *provider = VDGetRegistryProvider(); - void *rootKey = global ? provider->GetMachineKey() : provider->GetUserKey(); - - mKey = provider->CreateKey(rootKey, keyName, write); -} - -VDRegistryKey::VDRegistryKey(VDRegistryKey& baseKey, const char *name, bool write) { - IVDRegistryProvider *provider = VDGetRegistryProvider(); - void *rootKey = baseKey.getRawHandle(); - - mKey = rootKey ? provider->CreateKey(rootKey, name, write) : NULL; -} - -VDRegistryKey::~VDRegistryKey() { - if (mKey) - VDGetRegistryProvider()->CloseKey(mKey); -} - -bool VDRegistryKey::setBool(const char *name, bool v) const { - return mKey && VDGetRegistryProvider()->SetBool(mKey, name, v); -} - -bool VDRegistryKey::setInt(const char *name, int i) const { - return mKey && VDGetRegistryProvider()->SetInt(mKey, name, i); -} - -bool VDRegistryKey::setString(const char *name, const char *s) const { - return mKey && VDGetRegistryProvider()->SetString(mKey, name, s); -} - -bool VDRegistryKey::setString(const char *name, const wchar_t *s) const { - return mKey && VDGetRegistryProvider()->SetString(mKey, name, s); -} - -bool VDRegistryKey::setBinary(const char *name, const char *data, int len) const { - return mKey && VDGetRegistryProvider()->SetBinary(mKey, name, data, len); -} - -VDRegistryKey::Type VDRegistryKey::getValueType(const char *name) const { - Type type = kTypeUnknown; - - if (mKey) { - switch(VDGetRegistryProvider()->GetType(mKey, name)) { - case IVDRegistryProvider::kTypeInt: - type = kTypeInt; - break; - - case IVDRegistryProvider::kTypeString: - type = kTypeString; - break; - - case IVDRegistryProvider::kTypeBinary: - type = kTypeBinary; - break; - } - } - - return type; -} - -bool VDRegistryKey::getBool(const char *name, bool def) const { - bool v; - return mKey && VDGetRegistryProvider()->GetBool(mKey, name, v) ? v : def; -} - -int VDRegistryKey::getInt(const char *name, int def) const { - int v; - return mKey && VDGetRegistryProvider()->GetInt(mKey, name, v) ? v : def; -} - -int VDRegistryKey::getEnumInt(const char *pszName, int maxVal, int def) const { - int v = getInt(pszName, def); - - if (v<0 || v>=maxVal) - v = def; - - return v; -} - -bool VDRegistryKey::getString(const char *name, VDStringA& str) const { - return mKey && VDGetRegistryProvider()->GetString(mKey, name, str); -} - -bool VDRegistryKey::getString(const char *name, VDStringW& str) const { - return mKey && VDGetRegistryProvider()->GetString(mKey, name, str); -} - -int VDRegistryKey::getBinaryLength(const char *name) const { - return mKey ? VDGetRegistryProvider()->GetBinaryLength(mKey, name) : -1; -} - -bool VDRegistryKey::getBinary(const char *name, char *buf, int maxlen) const { - return mKey && VDGetRegistryProvider()->GetBinary(mKey, name, buf, maxlen); -} - -bool VDRegistryKey::removeValue(const char *name) { - return mKey && VDGetRegistryProvider()->RemoveValue(mKey, name); -} - -bool VDRegistryKey::removeKey(const char *name) { - return mKey && VDGetRegistryProvider()->RemoveKey(mKey, name); -} - -/////////////////////////////////////////////////////////////////////////////// - -VDRegistryValueIterator::VDRegistryValueIterator(const VDRegistryKey& key) - : mEnumerator(VDGetRegistryProvider()->EnumValuesBegin(key.getRawHandle())) -{ -} - -VDRegistryValueIterator::~VDRegistryValueIterator() { - VDGetRegistryProvider()->EnumValuesClose(mEnumerator); -} - -const char *VDRegistryValueIterator::Next() { - return mEnumerator ? VDGetRegistryProvider()->EnumValuesNext(mEnumerator) : NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -VDRegistryKeyIterator::VDRegistryKeyIterator(const VDRegistryKey& key) - : mEnumerator(VDGetRegistryProvider()->EnumKeysBegin(key.getRawHandle())) -{ -} - -VDRegistryKeyIterator::~VDRegistryKeyIterator() { - VDGetRegistryProvider()->EnumKeysClose(mEnumerator); -} - -const char *VDRegistryKeyIterator::Next() { - return mEnumerator ? VDGetRegistryProvider()->EnumKeysNext(mEnumerator) : NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -VDString VDRegistryAppKey::s_appbase; - -VDRegistryAppKey::VDRegistryAppKey() : VDRegistryKey(s_appbase.c_str()) { -} - -VDRegistryAppKey::VDRegistryAppKey(const char *pszKey, bool write, bool global) - : VDRegistryKey((s_appbase + pszKey).c_str(), global, write) -{ -} - -void VDRegistryAppKey::setDefaultKey(const char *pszAppName) { - s_appbase = pszAppName; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +class VDRegistryProviderW32 : public IVDRegistryProvider { +public: + void *GetUserKey(); + void *GetMachineKey(); + void *CreateKey(void *key, const char *path, bool write); + void CloseKey(void *key); + + bool SetBool(void *key, const char *pszName, bool); + bool SetInt(void *key, const char *pszName, int); + bool SetString(void *key, const char *pszName, const char *pszString); + bool SetString(void *key, const char *pszName, const wchar_t *pszString); + bool SetBinary(void *key, const char *pszName, const char *data, int len); + + Type GetType(void *key, const char *name); + bool GetBool(void *key, const char *pszName, bool& val); + bool GetInt(void *key, const char *pszName, int& val); + bool GetString(void *key, const char *pszName, VDStringA& s); + bool GetString(void *key, const char *pszName, VDStringW& s); + + int GetBinaryLength(void *key, const char *pszName); + bool GetBinary(void *key, const char *pszName, char *buf, int maxlen); + + bool RemoveValue(void *key, const char *name); + bool RemoveKey(void *key, const char *name); + + void *EnumKeysBegin(void *key); + const char *EnumKeysNext(void *enumerator); + void EnumKeysClose(void *enumerator); + + void *EnumValuesBegin(void *key); + const char *EnumValuesNext(void *enumerator); + void EnumValuesClose(void *enumerator); + +protected: + struct KeyEnumerator { + void *mKey; + uint32 mIndex; + char mName[256]; + }; + + struct ValueEnumerator { + void *mKey; + uint32 mIndex; + char mName[256]; + }; +}; + +void *VDRegistryProviderW32::GetUserKey() { + return HKEY_CURRENT_USER; +} + +void *VDRegistryProviderW32::GetMachineKey() { + return HKEY_LOCAL_MACHINE; +} + +void *VDRegistryProviderW32::CreateKey(void *key, const char *path, bool write) { + HKEY newKey; + + if (write) { + if (RegCreateKeyEx((HKEY)key, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newKey, NULL)) + return NULL; + } else { + if (RegOpenKeyEx((HKEY)key, path, 0, KEY_READ, &newKey)) + return NULL; + } + + return newKey; +} + +void VDRegistryProviderW32::CloseKey(void *key) { + RegCloseKey((HKEY)key); +} + +bool VDRegistryProviderW32::SetBool(void *key, const char *pszName, bool val) { + DWORD dw = val; + + return !RegSetValueEx((HKEY)key, pszName, 0, REG_DWORD, (const BYTE *)&dw, sizeof dw); +} + +bool VDRegistryProviderW32::SetInt(void *key, const char *pszName, int val) { + DWORD dw = val; + + return !RegSetValueEx((HKEY)key, pszName, 0, REG_DWORD, (const BYTE *)&dw, sizeof dw); +} + +bool VDRegistryProviderW32::SetString(void *key, const char *pszName, const char *pszString) { + return !RegSetValueEx((HKEY)key, pszName, 0, REG_SZ, (const BYTE *)pszString, strlen(pszString)); +} + +bool VDRegistryProviderW32::SetString(void *key, const char *pszName, const wchar_t *pszString) { + if (!VDIsWindowsNT()) { + VDStringA s(VDTextWToA(pszString)); + + if (RegSetValueEx((HKEY)key, pszName, 0, REG_SZ, (const BYTE *)s.data(), s.size())) + return false; + } else { + if (RegSetValueExW((HKEY)key, VDTextAToW(pszName).c_str(), 0, REG_SZ, (const BYTE *)pszString, sizeof(wchar_t) * wcslen(pszString))) + return false; + } + + return true; +} + +bool VDRegistryProviderW32::SetBinary(void *key, const char *pszName, const char *data, int len) { + return !RegSetValueEx((HKEY)key, pszName, 0, REG_BINARY, (const BYTE *)data, len); +} + +IVDRegistryProvider::Type VDRegistryProviderW32::GetType(void *key, const char *name) { + DWORD type; + + if (RegQueryValueEx((HKEY)key, name, 0, &type, NULL, NULL)) + return kTypeUnknown; + + switch(type) { + case REG_SZ: + return kTypeString; + + case REG_BINARY: + return kTypeBinary; + + case REG_DWORD: + return kTypeInt; + + default: + return kTypeUnknown; + } +} + +bool VDRegistryProviderW32::GetBool(void *key, const char *pszName, bool& val) { + DWORD type; + DWORD v; + DWORD len = sizeof(DWORD); + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)&v, &len) || type != REG_DWORD) + return false; + + val = (v != 0); + return true; +} + +bool VDRegistryProviderW32::GetInt(void *key, const char *pszName, int& val) { + DWORD type; + DWORD v; + DWORD len = sizeof(DWORD); + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)&v, &len) || type != REG_DWORD) + return false; + + val = v; + return true; +} + +bool VDRegistryProviderW32::GetString(void *key, const char *pszName, VDStringA& str) { + DWORD type; + DWORD s = sizeof(DWORD); + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, NULL, &s) || type != REG_SZ) + return false; + + str.resize(s); + if (RegQueryValueEx((HKEY)key, pszName, 0, NULL, (BYTE *)str.data(), &s)) + return false; + + if (!s) + str.clear(); + else + str.resize(strlen(str.c_str())); // Trim off pesky terminating NULLs. + + return true; +} + +bool VDRegistryProviderW32::GetString(void *key, const char *pszName, VDStringW& str) { + if (!VDIsWindowsNT()) { + VDStringA v; + if (!GetString(key, pszName, v)) + return false; + str = VDTextAToW(v); + return true; + } + + const VDStringW wsName(VDTextAToW(pszName)); + DWORD type; + DWORD s = sizeof(DWORD); + + if (RegQueryValueExW((HKEY)key, wsName.c_str(), 0, &type, NULL, &s) || type != REG_SZ) + return false; + + if (s <= 0) + str.clear(); + else { + str.resize((s + sizeof(wchar_t) - 1) / sizeof(wchar_t)); + + if (RegQueryValueExW((HKEY)key, wsName.c_str(), 0, NULL, (BYTE *)&str[0], &s)) + return false; + + str.resize(wcslen(str.c_str())); // Trim off pesky terminating NULLs. + } + + return true; +} + +int VDRegistryProviderW32::GetBinaryLength(void *key, const char *pszName) { + DWORD type; + DWORD s = sizeof(DWORD); + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, NULL, &s) || type != REG_BINARY) + return -1; + + return s; +} + +bool VDRegistryProviderW32::GetBinary(void *key, const char *pszName, char *buf, int maxlen) { + DWORD type; + DWORD s = maxlen; + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)buf, &s) || maxlen < (int)s || type != REG_BINARY) + return false; + + return true; +} + +bool VDRegistryProviderW32::RemoveValue(void *key, const char *name) { + return 0 != RegDeleteValue((HKEY)key, name); +} + +bool VDRegistryProviderW32::RemoveKey(void *key, const char *name) { + return 0 != RegDeleteKey((HKEY)key, name); +} + +void *VDRegistryProviderW32::EnumKeysBegin(void *key) { + KeyEnumerator *ke = new KeyEnumerator; + + ke->mKey = key; + ke->mIndex = 0; + + return ke; +} + +const char *VDRegistryProviderW32::EnumKeysNext(void *enumerator) { + KeyEnumerator *ke = (KeyEnumerator *)enumerator; + + DWORD len = sizeof(ke->mName)/sizeof(ke->mName[0]); + FILETIME ft; + LONG error = RegEnumKeyExA((HKEY)ke->mKey, ke->mIndex, ke->mName, &len, NULL, NULL, NULL, &ft); + + if (error) + return NULL; + + ++ke->mIndex; + return ke->mName; +} + +void VDRegistryProviderW32::EnumKeysClose(void *enumerator) { + delete (KeyEnumerator *)enumerator; +} + +void *VDRegistryProviderW32::EnumValuesBegin(void *key) { + ValueEnumerator *ve = new ValueEnumerator; + + ve->mKey = key; + ve->mIndex = 0; + + return ve; +} + +const char *VDRegistryProviderW32::EnumValuesNext(void *enumerator) { + ValueEnumerator *ve = (ValueEnumerator *)enumerator; + + DWORD len = sizeof(ve->mName)/sizeof(ve->mName[0]); + LONG error = RegEnumValueA((HKEY)ve->mKey, ve->mIndex, ve->mName, &len, NULL, NULL, NULL, NULL); + + if (error) + return NULL; + + ++ve->mIndex; + return ve->mName; +} + +void VDRegistryProviderW32::EnumValuesClose(void *enumerator) { + delete (ValueEnumerator *)enumerator; +} + +/////////////////////////////////////////////////////////////////////////// + +VDRegistryProviderW32 g_VDRegistryProviderW32; +IVDRegistryProvider *g_pVDRegistryProvider = &g_VDRegistryProviderW32; + +IVDRegistryProvider *VDGetRegistryProvider() { + return g_pVDRegistryProvider; +} + +void VDSetRegistryProvider(IVDRegistryProvider *provider) { + g_pVDRegistryProvider = provider; +} + +/////////////////////////////////////////////////////////////////////////// + +VDRegistryKey::VDRegistryKey(const char *keyName, bool global, bool write) { + IVDRegistryProvider *provider = VDGetRegistryProvider(); + void *rootKey = global ? provider->GetMachineKey() : provider->GetUserKey(); + + mKey = provider->CreateKey(rootKey, keyName, write); +} + +VDRegistryKey::VDRegistryKey(VDRegistryKey& baseKey, const char *name, bool write) { + IVDRegistryProvider *provider = VDGetRegistryProvider(); + void *rootKey = baseKey.getRawHandle(); + + mKey = rootKey ? provider->CreateKey(rootKey, name, write) : NULL; +} + +VDRegistryKey::~VDRegistryKey() { + if (mKey) + VDGetRegistryProvider()->CloseKey(mKey); +} + +bool VDRegistryKey::setBool(const char *name, bool v) const { + return mKey && VDGetRegistryProvider()->SetBool(mKey, name, v); +} + +bool VDRegistryKey::setInt(const char *name, int i) const { + return mKey && VDGetRegistryProvider()->SetInt(mKey, name, i); +} + +bool VDRegistryKey::setString(const char *name, const char *s) const { + return mKey && VDGetRegistryProvider()->SetString(mKey, name, s); +} + +bool VDRegistryKey::setString(const char *name, const wchar_t *s) const { + return mKey && VDGetRegistryProvider()->SetString(mKey, name, s); +} + +bool VDRegistryKey::setBinary(const char *name, const char *data, int len) const { + return mKey && VDGetRegistryProvider()->SetBinary(mKey, name, data, len); +} + +VDRegistryKey::Type VDRegistryKey::getValueType(const char *name) const { + Type type = kTypeUnknown; + + if (mKey) { + switch(VDGetRegistryProvider()->GetType(mKey, name)) { + case IVDRegistryProvider::kTypeInt: + type = kTypeInt; + break; + + case IVDRegistryProvider::kTypeString: + type = kTypeString; + break; + + case IVDRegistryProvider::kTypeBinary: + type = kTypeBinary; + break; + } + } + + return type; +} + +bool VDRegistryKey::getBool(const char *name, bool def) const { + bool v; + return mKey && VDGetRegistryProvider()->GetBool(mKey, name, v) ? v : def; +} + +int VDRegistryKey::getInt(const char *name, int def) const { + int v; + return mKey && VDGetRegistryProvider()->GetInt(mKey, name, v) ? v : def; +} + +int VDRegistryKey::getEnumInt(const char *pszName, int maxVal, int def) const { + int v = getInt(pszName, def); + + if (v<0 || v>=maxVal) + v = def; + + return v; +} + +bool VDRegistryKey::getString(const char *name, VDStringA& str) const { + return mKey && VDGetRegistryProvider()->GetString(mKey, name, str); +} + +bool VDRegistryKey::getString(const char *name, VDStringW& str) const { + return mKey && VDGetRegistryProvider()->GetString(mKey, name, str); +} + +int VDRegistryKey::getBinaryLength(const char *name) const { + return mKey ? VDGetRegistryProvider()->GetBinaryLength(mKey, name) : -1; +} + +bool VDRegistryKey::getBinary(const char *name, char *buf, int maxlen) const { + return mKey && VDGetRegistryProvider()->GetBinary(mKey, name, buf, maxlen); +} + +bool VDRegistryKey::removeValue(const char *name) { + return mKey && VDGetRegistryProvider()->RemoveValue(mKey, name); +} + +bool VDRegistryKey::removeKey(const char *name) { + return mKey && VDGetRegistryProvider()->RemoveKey(mKey, name); +} + +/////////////////////////////////////////////////////////////////////////////// + +VDRegistryValueIterator::VDRegistryValueIterator(const VDRegistryKey& key) + : mEnumerator(VDGetRegistryProvider()->EnumValuesBegin(key.getRawHandle())) +{ +} + +VDRegistryValueIterator::~VDRegistryValueIterator() { + VDGetRegistryProvider()->EnumValuesClose(mEnumerator); +} + +const char *VDRegistryValueIterator::Next() { + return mEnumerator ? VDGetRegistryProvider()->EnumValuesNext(mEnumerator) : NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +VDRegistryKeyIterator::VDRegistryKeyIterator(const VDRegistryKey& key) + : mEnumerator(VDGetRegistryProvider()->EnumKeysBegin(key.getRawHandle())) +{ +} + +VDRegistryKeyIterator::~VDRegistryKeyIterator() { + VDGetRegistryProvider()->EnumKeysClose(mEnumerator); +} + +const char *VDRegistryKeyIterator::Next() { + return mEnumerator ? VDGetRegistryProvider()->EnumKeysNext(mEnumerator) : NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +VDString VDRegistryAppKey::s_appbase; + +VDRegistryAppKey::VDRegistryAppKey() : VDRegistryKey(s_appbase.c_str()) { +} + +VDRegistryAppKey::VDRegistryAppKey(const char *pszKey, bool write, bool global) + : VDRegistryKey((s_appbase + pszKey).c_str(), global, write) +{ +} + +void VDRegistryAppKey::setDefaultKey(const char *pszAppName) { + s_appbase = pszAppName; +} diff --git a/src/thirdparty/VirtualDub/system/source/stdaccel.cpp b/src/thirdparty/VirtualDub/system/source/stdaccel.cpp index 4acad27fdc9..7214797b13d 100644 --- a/src/thirdparty/VirtualDub/system/source/stdaccel.cpp +++ b/src/thirdparty/VirtualDub/system/source/stdaccel.cpp @@ -1,42 +1,42 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#define VDTEXTERN - -#include -#include - -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#define VDTEXTERN + +#include +#include + +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; diff --git a/src/thirdparty/VirtualDub/system/source/stdafx.cpp b/src/thirdparty/VirtualDub/system/source/stdafx.cpp index acf0b47e42b..92339e1d947 100644 --- a/src/thirdparty/VirtualDub/system/source/stdafx.cpp +++ b/src/thirdparty/VirtualDub/system/source/stdafx.cpp @@ -1,46 +1,46 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include - -#ifdef _MSC_VER - #pragma hdrstop -#endif - -// compiler/setup checks - -#if defined(_MSC_VER) - #if _MSC_VER < 1300 - #include - - #line 1 " \n \n \n***** You do not have the correct version of the Microsoft Platform SDK installed *****\nPlease see Docs\\index.html for details.\n \n \n" - namespace { const DWORD PlatformSDKTest = INVALID_SET_FILE_POINTER; } - #line 1 "" - - #line 1 " \n \n \n***** You do not have the Visual C++ Processor Pack installed *****\nPlease see Docs\\index.html for details.\n \n \n" - namespace { void VCPPCheck() { __asm { sfence } } } - #line 1 "" - #endif -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include + +#ifdef _MSC_VER + #pragma hdrstop +#endif + +// compiler/setup checks + +#if defined(_MSC_VER) + #if _MSC_VER < 1300 + #include + + #line 1 " \n \n \n***** You do not have the correct version of the Microsoft Platform SDK installed *****\nPlease see Docs\\index.html for details.\n \n \n" + namespace { const DWORD PlatformSDKTest = INVALID_SET_FILE_POINTER; } + #line 1 "" + + #line 1 " \n \n \n***** You do not have the Visual C++ Processor Pack installed *****\nPlease see Docs\\index.html for details.\n \n \n" + namespace { void VCPPCheck() { __asm { sfence } } } + #line 1 "" + #endif +#endif diff --git a/src/thirdparty/VirtualDub/system/source/strutil.cpp b/src/thirdparty/VirtualDub/system/source/strutil.cpp index 2d9becc857d..31f4e985994 100644 --- a/src/thirdparty/VirtualDub/system/source/strutil.cpp +++ b/src/thirdparty/VirtualDub/system/source/strutil.cpp @@ -1,99 +1,99 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include - -char *strncpyz(char *strDest, const char *strSource, size_t count) { - char *s; - - s = strncpy(strDest, strSource, count); - strDest[count-1] = 0; - - return s; -} - -wchar_t *wcsncpyz(wchar_t *strDest, const wchar_t *strSource, size_t count) { - wchar_t *s; - - s = wcsncpy(strDest, strSource, count); - strDest[count-1] = 0; - - return s; -} - -const char *strskipspace(const char *s) { - while(isspace((unsigned char)*s++)) - ; - - return s-1; -} - -size_t vdstrlcpy(char *dst, const char *src, size_t size) { - size_t len = strlen(src); - - if (size) { - if (size > len) - size = len; - - memcpy(dst, src, size); - dst[size] = 0; - } - return len; -} - -size_t vdwcslcpy(wchar_t *dst, const wchar_t *src, size_t size) { - size_t len = wcslen(src); - - if (size) { - if (size > len) - size = len; - - memcpy(dst, src, size * sizeof(wchar_t)); - dst[size] = 0; - } - return len; -} - -size_t vdstrlcat(char *dst, const char *src, size_t size) { - size_t dlen = strlen(dst); - size_t slen = strlen(src); - - if (dlen < size) { - size_t maxappend = size - dlen - 1; - if (maxappend > slen) - maxappend = slen; - - if (maxappend) { - memcpy(dst + dlen, src, maxappend); - dst[dlen+maxappend] = 0; - } - } - - return dlen+slen; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +#include + +char *strncpyz(char *strDest, const char *strSource, size_t count) { + char *s; + + s = strncpy(strDest, strSource, count); + strDest[count-1] = 0; + + return s; +} + +wchar_t *wcsncpyz(wchar_t *strDest, const wchar_t *strSource, size_t count) { + wchar_t *s; + + s = wcsncpy(strDest, strSource, count); + strDest[count-1] = 0; + + return s; +} + +const char *strskipspace(const char *s) { + while(isspace((unsigned char)*s++)) + ; + + return s-1; +} + +size_t vdstrlcpy(char *dst, const char *src, size_t size) { + size_t len = strlen(src); + + if (size) { + if (size > len) + size = len; + + memcpy(dst, src, size); + dst[size] = 0; + } + return len; +} + +size_t vdwcslcpy(wchar_t *dst, const wchar_t *src, size_t size) { + size_t len = wcslen(src); + + if (size) { + if (size > len) + size = len; + + memcpy(dst, src, size * sizeof(wchar_t)); + dst[size] = 0; + } + return len; +} + +size_t vdstrlcat(char *dst, const char *src, size_t size) { + size_t dlen = strlen(dst); + size_t slen = strlen(src); + + if (dlen < size) { + size_t maxappend = size - dlen - 1; + if (maxappend > slen) + maxappend = slen; + + if (maxappend) { + memcpy(dst + dlen, src, maxappend); + dst[dlen+maxappend] = 0; + } + } + + return dlen+slen; +} diff --git a/src/thirdparty/VirtualDub/system/source/text.cpp b/src/thirdparty/VirtualDub/system/source/text.cpp index c87e3155845..508a871287b 100644 --- a/src/thirdparty/VirtualDub/system/source/text.cpp +++ b/src/thirdparty/VirtualDub/system/source/text.cpp @@ -1,653 +1,653 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -int VDTextWToA(char *dst, int max_dst, const wchar_t *src, int max_src) { - VDASSERTPTR(dst); - VDASSERTPTR(src); - VDASSERT(max_dst>0); - - *dst = 0; - - int len = WideCharToMultiByte(CP_ACP, 0, src, max_src, dst, max_dst, NULL, NULL); - - // remove null terminator if source was null-terminated (source - // length was provided) - return max_src<0 && len>0 ? len-1 : len; -} - -int VDTextAToW(wchar_t *dst, int max_dst, const char *src, int max_src) { - VDASSERTPTR(dst); - VDASSERTPTR(src); - VDASSERT(max_dst>0); - - *dst = 0; - - int len = MultiByteToWideChar(CP_ACP, 0, src, max_src, dst, max_dst); - - // remove null terminator if source was null-terminated (source - // length was provided) - return max_src<0 && len>0 ? len-1 : len; -} - -VDStringA VDTextWToA(const VDStringW& sw) { - return VDTextWToA(sw.data(), sw.length()); -} - -VDStringA VDTextWToA(const wchar_t *src, int srclen) { - VDStringA s; - - if (src) { - int l = VDTextWToALength(src, srclen); - - if (l) { - s.resize(l); - VDTextWToA((char *)s.data(), l+1, src, srclen); - } - } - - return s; -} - -VDStringW VDTextAToW(const VDStringA& s) { - return VDTextAToW(s.data(), s.length()); -} - -VDStringW VDTextAToW(const char *src, int srclen) { - VDStringW sw; - - if (src) { - int l = VDTextAToWLength(src, srclen); - - if (l) { - sw.resize(l); - VDTextAToW(&sw[0], sw.length()+1, src, srclen); - } - } - - return sw; -} - -int VDTextWToALength(const wchar_t *s, int length) { - SetLastError(0); - int rv = WideCharToMultiByte(CP_ACP, 0, s, length, NULL, 0, NULL, 0); - - if (length < 0 && rv>0) - --rv; - - return rv; -} - -int VDTextAToWLength(const char *s, int length) { - SetLastError(0); - int rv = MultiByteToWideChar(CP_ACP, 0, s, length, NULL, 0); - - if (length < 0 && rv > 0) - --rv; - - return rv; -} - -namespace { - // UTF8: - // 000000000xxxxxxx -> 0xxxxxxx - // 00000yyyyyxxxxxx -> 110yyyyy 10xxxxxx - // zzzzyyyyyyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx - // uuuuuzzzzyyyyyyxxxxxx -> 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx - // (UTF16) -> 110110wwwwzzzzyy (uuuuu = wwww+1) - // 110111yyyyxxxxxx - int VDGetCharLengthInUTF8(wchar_t c) { - if (c < 0x0080) // 7 bits - return 1; - else if (c < 0x0800) // 11 bits - return 2; - else if (c < 0x10000) // 16 bits - return 3; - else if (c < 0x200000) // 21 bits - return 4; - else { - VDASSERT(false); - return 1; // Uh oh. Well, we're screwed. - } - } - - bool VDIsUnicodeSurrogateFirst(wchar_t c) { - return (c >= 0xD800 && c < 0xDC00); - } - - bool VDIsUnicodeSurrogateSecond(wchar_t c) { - return (c >= 0xDC00 && c < 0xE000); - } -}; - -VDStringA VDTextWToU8(const VDStringW& s) { - return VDTextWToU8(s.data(), s.length()); -} - -VDStringA VDTextWToU8(const wchar_t *s, int length) { - vdfastvector temp; - - if (length<0) { - const wchar_t *t = s; - do { - ++length; - } while(*t++); - } - - while(length--) { - uint32 c = *s++; - - if (VDIsUnicodeSurrogateFirst(c)) { - if (!length || !VDIsUnicodeSurrogateSecond(*s)) { - VDASSERT(false); - c = '?'; - } else { - c = 0x10000 + ((c & 0x3ff)<<10) + (*s++ & 0x3ff); - --length; - } - } - - if (c < 0x0080) { - temp.push_back((char)c); - } else { - if (c < 0x0800) - temp.push_back((char)(0xc0 + (c>>6))); - else { - if (c < 0x10000) - temp.push_back((char)(0xe0 + (c>>12))); - else { - temp.push_back((char)(0xf0 + ((c>>18) & 0x07))); - temp.push_back((char)(0x80 + ((c>>12) & 0x3f))); - } - temp.push_back((char)(0x80 + ((c>>6) & 0x3f))); - } - temp.push_back((char)(0x80 + (c & 0x3f))); - } - } - - VDStringA a(temp.data(), temp.size()); - - return a; -} - -VDStringW VDTextU8ToW(const VDStringA& s) { - return VDTextU8ToW(s.data(), s.length()); -} - -VDStringW VDTextU8ToW(const char *s, int length) { - vdfastvector temp; - - if (length<0) { - const char *t = s; - VDASSERT(length == -1); - do { - ++length; - } while(*t++); - } - - while(length--) { - unsigned char c = (char)*s++; - uint32 wc = c; // we reconstruct UTF-32 first and then split to UTF-16 if necessary - - if (c >= 0x80) { - int required_extra = 0; - - if (c < 0xc0 || c >= 0xf7) { - VDASSERT(false); - break; - } - - while(c >= 0xc0) { - c <<= 1; - ++required_extra; - } - - wc = (c&0x3f) >> required_extra; - - do { - char d; - - if (!length-- || (((d=*s++)&0xc0)!=0x80)) - goto bad_sequence_exit; - - wc = (wc<<6) + (d&0x3f); - } while(--required_extra); - } - - // Two cases here. If we are using UTF-16, surrogates need to be split in half. If we are using - // UTF-32, surrogates need to be combined. - - if (sizeof(wchar_t) > 2) { - if (VDIsUnicodeSurrogateSecond(wc)) { - if (temp.empty() || !VDIsUnicodeSurrogateFirst(temp.back())) { - VDASSERT(false); - break; - } - - temp.back() = 0x10000 + ((temp.back()&0x3ff) << 10) + (wc & 0x3ff); - continue; - } - } else { - if (wc >= 0x10000) { - wc -= 0x10000; - temp.push_back(0xD800 + ((wc & 0x3ff) >> 10)); - wc = 0xDC00 + (wc&0x3ff); - } - } - temp.push_back(wc); - } -bad_sequence_exit: - - VDStringW w(temp.data(), temp.size()); - - return w; -} - -/////////////////////////////////////////////////////////////////////////// -// -// VirtualDub's very own printf() functions. -// -// VD[v|a]swprintf() differs from wsprintf() in the following ways: -// -// * The output is a string. -// * All parameters must be passed by pointer instead of by value. -// * The 'll' modifier permits long long / __int64 integers. -// * [n] allows picking parameters out of order. -// * %lc/%ls forces Unicode; %hc/%hs forces ANSI. - -VDStringW VDaswprintf(const wchar_t *format, int args, const void *const *argv) { - const void *const *argv0 = argv; - vdfastfixedvector out; - wchar_t c; - - VDStringW tempConv; - - while(c = *format) { - if (c != L'%') { - const wchar_t *s = format; - - while(*s && *s != L'%') - ++s; - - int len = s - format; - int clen = out.size(); - - out.resize(clen + len); - - std::copy(format, s, &out[clen]); - - format = s; - } else { - ++format; - - // check for %% - - if (*format == L'%') { - ++format; - out.push_back(L'%'); - continue; - } - - // Check for a renumbering identifier. - - if (*format == L'[') { - ++format; - - int newid = wcstol(format, const_cast(&format), 0); - - VDASSERT(newid >= 0 && newid < args); - - argv = argv0 + newid; - - VDVERIFY(*format++ == L']'); - } - - // process flags - - struct { - bool bLeftAlign:1, // pad right with spaces (priority over zero pad) - bZeroPad:1, // pad left with zeroes - bPositiveSign:1, // prefix with + or -; priority over bPositiveBlank - bPositiveBlank:1, // prefix with space for nonnegative - bPrefix:1; // prefix with 0, 0x, 0X, or force decimal point - } flags={false}; - int width = 0; - int precision = -1; - - for(;;) { - c = *format; - - if (c == L'0') - flags.bZeroPad = true; - else if (c == L' ') - flags.bPositiveBlank = true; - else if (c == L'#') - flags.bPrefix = true; - else if (c == L'-') - flags.bLeftAlign = true; - else if (c == L'+') - flags.bPositiveSign = true; - else - break; - - ++format; - } - - // process width - - c = *format; - if (c == L'*') { - ++format; - width = *(int *)*argv++; - } else if (iswdigit(c)) - width = (int)wcstol(format, const_cast(&format), 0); - - // process precision - - if (*format == L'.') { - c = *++format; - - if (c == L'*') { - ++format; - precision = *(int *)*argv++; - } else if (iswdigit(c)) - precision = (int)wcstol(format, const_cast(&format), 0); - } - - // process flags - - enum { kDefault, kLong, kLongLong, kShort } size = kDefault; - - c = *format; - - if (c == L'l') { - ++format; - size = kLong; - - if (*format == L'l') { - ++format; - size = kLongLong; - } - - } else if (c == L'h') { - ++format; - size = kShort; - } - - // process format character - - wchar_t xf[32], buf[32], *pxf = xf, *pbuf0 = buf, *pbuf = buf; - int zero_pad = 0; - - switch(*format++) { - case L'd': - case L'i': - case L'o': - case L'u': - case L'x': - case L'X': - *pxf++ = '%'; - if (flags.bPrefix) - *pxf++ = '#'; - if (flags.bPositiveBlank) - *pxf++ = ' '; - if (flags.bPositiveSign) - *pxf++ = '+'; - - switch(size) { - case kShort: - *pxf++ = 'h'; - *pxf++ = format[-1]; - *pxf = 0; - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const short *)*argv++); - break; - case kDefault: - *pxf++ = format[-1]; - *pxf = 0; - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const int *)*argv++); - break; - case kLong: - *pxf++ = 'l'; - *pxf++ = format[-1]; - *pxf = 0; - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const long *)*argv++); - break; - case kLongLong: -#if defined(_MSC_VER) - *pxf++ = 'I'; - *pxf++ = '6'; - *pxf++ = '4'; -#elif defined(__GNUC__) - *pxf++ = 'l'; - *pxf++ = 'l'; -#else -#error Please insert the appropriate 64-bit printf format for your platform. -#endif - *pxf++ = format[-1]; - *pxf = 0; - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const int64 *)*argv++); - break; - default: - VDNEVERHERE; - } - - if (pbuf - pbuf0 < precision) - zero_pad = precision - (pbuf - pbuf0); - - break; - - case L'c': - if (size == kShort) { - char buf[2] = {*(const char *)*argv++, 0}; - pbuf += VDTextAToW(pbuf, 4, buf); - } else - *pbuf++ = *(const wchar_t *)*argv++; - break; - - case L's': - if (size == kShort) { - const char *s = *(const char *const *)*argv++; - int maxsrc = strlen(s); - - if (precision >= 0 && precision < maxsrc) - maxsrc = precision; - - tempConv = VDTextAToW(s, maxsrc); - pbuf0 = const_cast(tempConv.c_str()); - - pbuf = pbuf0 + tempConv.size(); - } else { - pbuf = pbuf0 = *(wchar_t *const *)*argv++; - - while(*pbuf && precision) { - ++pbuf; - --precision; - } - } - break; - - case L'e': - case L'E': - case L'f': - case L'F': - case L'g': - case L'G': - // We place an artificial limit of 256 characters on the precision value. - { - if (precision > 256) - precision = 256; - - tempConv.resize(256); - pbuf0 = pbuf = const_cast(tempConv.data()); - - *pxf++ = '%'; - if (flags.bPrefix) - *pxf++ = '#'; - if (flags.bPositiveBlank) - *pxf++ = ' '; - if (flags.bPositiveSign) - *pxf++ = '+'; - if (precision>=0) { - *pxf++ = '.'; - *pxf++ = '*'; - } - *pxf++ = format[-1]; - *pxf = 0; - - if (precision >= 0) - pbuf += vdswprintf(pbuf, 256, xf, precision, *(const double *)*argv++); - else - pbuf += vdswprintf(pbuf, 256, xf, *(const double *)*argv++); - } - break; - - case L'n': // no flags honored; precision ignored - *(int *)(*argv++) = out.size(); - continue; - case L'p': // no flags honored; precision ignored - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], L"%p", *(void *const *)*argv++); - break; - - case L'z': - switch(*format++) { - case L's': - { - int64 value; - - switch(size) { - case kShort: value = *(const short *)*argv++; break; - case kDefault: value = *(const int *)*argv++; break; - case kLong: value = *(const long *)*argv++; break; - case kLongLong: value = *(const int64 *)*argv++; break; - break; - default: - VDNEVERHERE; - } - - if (value < 0) - *pbuf++ = L'-'; - else if (flags.bPositiveSign) - *pbuf++ = L'+'; - else if (flags.bPositiveBlank) - *pbuf++ = L' '; - - if (value < (VD64(10) << 10)) - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d bytes", (int)value); - else if (value < (VD64(10) << 20)) - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d KB", (int)((sint32)value >> 10)); - else if (value < (VD64(10) << 30)) - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d MB", (int)((sint32)value >> 20)); - else if (value < (VD64(10) << 40)) - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d GB", (int)(value >> 30)); - else - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d TB", (int)(value >> 40)); - } - - break; - } - break; - - } - - int string_width = (pbuf - pbuf0) + zero_pad; - int string_delta = width - string_width; - - if (!flags.bLeftAlign && string_delta > 0) { - int siz = out.size(); - out.resize(siz + string_delta, flags.bZeroPad ? L'0' : L' '); - } - - if (zero_pad) { - int siz = out.size(); - out.resize(siz + zero_pad); - std::fill(&out[siz], &out[siz+zero_pad], L'0'); - } - - if (pbuf != pbuf0) { - int siz = out.size(); - out.resize(siz + (pbuf - pbuf0)); - - std::copy(pbuf0, pbuf, &out[siz]); - } - - if (flags.bLeftAlign && string_delta > 0) { - int siz = out.size(); - out.resize(siz + string_delta); - std::fill(&out[siz], &out[siz+string_delta], L' '); - } - } - } - - out.push_back(0); - - return VDStringW(out.data()); -} - -VDStringW VDvswprintf(const wchar_t *format, int args, va_list val) { - if (args < 16) { - const void *argv[16]; - - for(int i=0; i argv(args); - - for(int i=0; i +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +int VDTextWToA(char *dst, int max_dst, const wchar_t *src, int max_src) { + VDASSERTPTR(dst); + VDASSERTPTR(src); + VDASSERT(max_dst>0); + + *dst = 0; + + int len = WideCharToMultiByte(CP_ACP, 0, src, max_src, dst, max_dst, NULL, NULL); + + // remove null terminator if source was null-terminated (source + // length was provided) + return max_src<0 && len>0 ? len-1 : len; +} + +int VDTextAToW(wchar_t *dst, int max_dst, const char *src, int max_src) { + VDASSERTPTR(dst); + VDASSERTPTR(src); + VDASSERT(max_dst>0); + + *dst = 0; + + int len = MultiByteToWideChar(CP_ACP, 0, src, max_src, dst, max_dst); + + // remove null terminator if source was null-terminated (source + // length was provided) + return max_src<0 && len>0 ? len-1 : len; +} + +VDStringA VDTextWToA(const VDStringW& sw) { + return VDTextWToA(sw.data(), sw.length()); +} + +VDStringA VDTextWToA(const wchar_t *src, int srclen) { + VDStringA s; + + if (src) { + int l = VDTextWToALength(src, srclen); + + if (l) { + s.resize(l); + VDTextWToA((char *)s.data(), l+1, src, srclen); + } + } + + return s; +} + +VDStringW VDTextAToW(const VDStringA& s) { + return VDTextAToW(s.data(), s.length()); +} + +VDStringW VDTextAToW(const char *src, int srclen) { + VDStringW sw; + + if (src) { + int l = VDTextAToWLength(src, srclen); + + if (l) { + sw.resize(l); + VDTextAToW(&sw[0], sw.length()+1, src, srclen); + } + } + + return sw; +} + +int VDTextWToALength(const wchar_t *s, int length) { + SetLastError(0); + int rv = WideCharToMultiByte(CP_ACP, 0, s, length, NULL, 0, NULL, 0); + + if (length < 0 && rv>0) + --rv; + + return rv; +} + +int VDTextAToWLength(const char *s, int length) { + SetLastError(0); + int rv = MultiByteToWideChar(CP_ACP, 0, s, length, NULL, 0); + + if (length < 0 && rv > 0) + --rv; + + return rv; +} + +namespace { + // UTF8: + // 000000000xxxxxxx -> 0xxxxxxx + // 00000yyyyyxxxxxx -> 110yyyyy 10xxxxxx + // zzzzyyyyyyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx + // uuuuuzzzzyyyyyyxxxxxx -> 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (UTF16) -> 110110wwwwzzzzyy (uuuuu = wwww+1) + // 110111yyyyxxxxxx + int VDGetCharLengthInUTF8(wchar_t c) { + if (c < 0x0080) // 7 bits + return 1; + else if (c < 0x0800) // 11 bits + return 2; + else if (c < 0x10000) // 16 bits + return 3; + else if (c < 0x200000) // 21 bits + return 4; + else { + VDASSERT(false); + return 1; // Uh oh. Well, we're screwed. + } + } + + bool VDIsUnicodeSurrogateFirst(wchar_t c) { + return (c >= 0xD800 && c < 0xDC00); + } + + bool VDIsUnicodeSurrogateSecond(wchar_t c) { + return (c >= 0xDC00 && c < 0xE000); + } +}; + +VDStringA VDTextWToU8(const VDStringW& s) { + return VDTextWToU8(s.data(), s.length()); +} + +VDStringA VDTextWToU8(const wchar_t *s, int length) { + vdfastvector temp; + + if (length<0) { + const wchar_t *t = s; + do { + ++length; + } while(*t++); + } + + while(length--) { + uint32 c = *s++; + + if (VDIsUnicodeSurrogateFirst(c)) { + if (!length || !VDIsUnicodeSurrogateSecond(*s)) { + VDASSERT(false); + c = '?'; + } else { + c = 0x10000 + ((c & 0x3ff)<<10) + (*s++ & 0x3ff); + --length; + } + } + + if (c < 0x0080) { + temp.push_back((char)c); + } else { + if (c < 0x0800) + temp.push_back((char)(0xc0 + (c>>6))); + else { + if (c < 0x10000) + temp.push_back((char)(0xe0 + (c>>12))); + else { + temp.push_back((char)(0xf0 + ((c>>18) & 0x07))); + temp.push_back((char)(0x80 + ((c>>12) & 0x3f))); + } + temp.push_back((char)(0x80 + ((c>>6) & 0x3f))); + } + temp.push_back((char)(0x80 + (c & 0x3f))); + } + } + + VDStringA a(temp.data(), temp.size()); + + return a; +} + +VDStringW VDTextU8ToW(const VDStringA& s) { + return VDTextU8ToW(s.data(), s.length()); +} + +VDStringW VDTextU8ToW(const char *s, int length) { + vdfastvector temp; + + if (length<0) { + const char *t = s; + VDASSERT(length == -1); + do { + ++length; + } while(*t++); + } + + while(length--) { + unsigned char c = (char)*s++; + uint32 wc = c; // we reconstruct UTF-32 first and then split to UTF-16 if necessary + + if (c >= 0x80) { + int required_extra = 0; + + if (c < 0xc0 || c >= 0xf7) { + VDASSERT(false); + break; + } + + while(c >= 0xc0) { + c <<= 1; + ++required_extra; + } + + wc = (c&0x3f) >> required_extra; + + do { + char d; + + if (!length-- || (((d=*s++)&0xc0)!=0x80)) + goto bad_sequence_exit; + + wc = (wc<<6) + (d&0x3f); + } while(--required_extra); + } + + // Two cases here. If we are using UTF-16, surrogates need to be split in half. If we are using + // UTF-32, surrogates need to be combined. + + if (sizeof(wchar_t) > 2) { + if (VDIsUnicodeSurrogateSecond(wc)) { + if (temp.empty() || !VDIsUnicodeSurrogateFirst(temp.back())) { + VDASSERT(false); + break; + } + + temp.back() = 0x10000 + ((temp.back()&0x3ff) << 10) + (wc & 0x3ff); + continue; + } + } else { + if (wc >= 0x10000) { + wc -= 0x10000; + temp.push_back(0xD800 + ((wc & 0x3ff) >> 10)); + wc = 0xDC00 + (wc&0x3ff); + } + } + temp.push_back(wc); + } +bad_sequence_exit: + + VDStringW w(temp.data(), temp.size()); + + return w; +} + +/////////////////////////////////////////////////////////////////////////// +// +// VirtualDub's very own printf() functions. +// +// VD[v|a]swprintf() differs from wsprintf() in the following ways: +// +// * The output is a string. +// * All parameters must be passed by pointer instead of by value. +// * The 'll' modifier permits long long / __int64 integers. +// * [n] allows picking parameters out of order. +// * %lc/%ls forces Unicode; %hc/%hs forces ANSI. + +VDStringW VDaswprintf(const wchar_t *format, int args, const void *const *argv) { + const void *const *argv0 = argv; + vdfastfixedvector out; + wchar_t c; + + VDStringW tempConv; + + while(c = *format) { + if (c != L'%') { + const wchar_t *s = format; + + while(*s && *s != L'%') + ++s; + + int len = s - format; + int clen = out.size(); + + out.resize(clen + len); + + std::copy(format, s, &out[clen]); + + format = s; + } else { + ++format; + + // check for %% + + if (*format == L'%') { + ++format; + out.push_back(L'%'); + continue; + } + + // Check for a renumbering identifier. + + if (*format == L'[') { + ++format; + + int newid = wcstol(format, const_cast(&format), 0); + + VDASSERT(newid >= 0 && newid < args); + + argv = argv0 + newid; + + VDVERIFY(*format++ == L']'); + } + + // process flags + + struct { + bool bLeftAlign:1, // pad right with spaces (priority over zero pad) + bZeroPad:1, // pad left with zeroes + bPositiveSign:1, // prefix with + or -; priority over bPositiveBlank + bPositiveBlank:1, // prefix with space for nonnegative + bPrefix:1; // prefix with 0, 0x, 0X, or force decimal point + } flags={false}; + int width = 0; + int precision = -1; + + for(;;) { + c = *format; + + if (c == L'0') + flags.bZeroPad = true; + else if (c == L' ') + flags.bPositiveBlank = true; + else if (c == L'#') + flags.bPrefix = true; + else if (c == L'-') + flags.bLeftAlign = true; + else if (c == L'+') + flags.bPositiveSign = true; + else + break; + + ++format; + } + + // process width + + c = *format; + if (c == L'*') { + ++format; + width = *(int *)*argv++; + } else if (iswdigit(c)) + width = (int)wcstol(format, const_cast(&format), 0); + + // process precision + + if (*format == L'.') { + c = *++format; + + if (c == L'*') { + ++format; + precision = *(int *)*argv++; + } else if (iswdigit(c)) + precision = (int)wcstol(format, const_cast(&format), 0); + } + + // process flags + + enum { kDefault, kLong, kLongLong, kShort } size = kDefault; + + c = *format; + + if (c == L'l') { + ++format; + size = kLong; + + if (*format == L'l') { + ++format; + size = kLongLong; + } + + } else if (c == L'h') { + ++format; + size = kShort; + } + + // process format character + + wchar_t xf[32], buf[32], *pxf = xf, *pbuf0 = buf, *pbuf = buf; + int zero_pad = 0; + + switch(*format++) { + case L'd': + case L'i': + case L'o': + case L'u': + case L'x': + case L'X': + *pxf++ = '%'; + if (flags.bPrefix) + *pxf++ = '#'; + if (flags.bPositiveBlank) + *pxf++ = ' '; + if (flags.bPositiveSign) + *pxf++ = '+'; + + switch(size) { + case kShort: + *pxf++ = 'h'; + *pxf++ = format[-1]; + *pxf = 0; + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const short *)*argv++); + break; + case kDefault: + *pxf++ = format[-1]; + *pxf = 0; + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const int *)*argv++); + break; + case kLong: + *pxf++ = 'l'; + *pxf++ = format[-1]; + *pxf = 0; + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const long *)*argv++); + break; + case kLongLong: +#if defined(_MSC_VER) + *pxf++ = 'I'; + *pxf++ = '6'; + *pxf++ = '4'; +#elif defined(__GNUC__) + *pxf++ = 'l'; + *pxf++ = 'l'; +#else +#error Please insert the appropriate 64-bit printf format for your platform. +#endif + *pxf++ = format[-1]; + *pxf = 0; + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const int64 *)*argv++); + break; + default: + VDNEVERHERE; + } + + if (pbuf - pbuf0 < precision) + zero_pad = precision - (pbuf - pbuf0); + + break; + + case L'c': + if (size == kShort) { + char buf[2] = {*(const char *)*argv++, 0}; + pbuf += VDTextAToW(pbuf, 4, buf); + } else + *pbuf++ = *(const wchar_t *)*argv++; + break; + + case L's': + if (size == kShort) { + const char *s = *(const char *const *)*argv++; + int maxsrc = strlen(s); + + if (precision >= 0 && precision < maxsrc) + maxsrc = precision; + + tempConv = VDTextAToW(s, maxsrc); + pbuf0 = const_cast(tempConv.c_str()); + + pbuf = pbuf0 + tempConv.size(); + } else { + pbuf = pbuf0 = *(wchar_t *const *)*argv++; + + while(*pbuf && precision) { + ++pbuf; + --precision; + } + } + break; + + case L'e': + case L'E': + case L'f': + case L'F': + case L'g': + case L'G': + // We place an artificial limit of 256 characters on the precision value. + { + if (precision > 256) + precision = 256; + + tempConv.resize(256); + pbuf0 = pbuf = const_cast(tempConv.data()); + + *pxf++ = '%'; + if (flags.bPrefix) + *pxf++ = '#'; + if (flags.bPositiveBlank) + *pxf++ = ' '; + if (flags.bPositiveSign) + *pxf++ = '+'; + if (precision>=0) { + *pxf++ = '.'; + *pxf++ = '*'; + } + *pxf++ = format[-1]; + *pxf = 0; + + if (precision >= 0) + pbuf += vdswprintf(pbuf, 256, xf, precision, *(const double *)*argv++); + else + pbuf += vdswprintf(pbuf, 256, xf, *(const double *)*argv++); + } + break; + + case L'n': // no flags honored; precision ignored + *(int *)(*argv++) = out.size(); + continue; + case L'p': // no flags honored; precision ignored + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], L"%p", *(void *const *)*argv++); + break; + + case L'z': + switch(*format++) { + case L's': + { + int64 value; + + switch(size) { + case kShort: value = *(const short *)*argv++; break; + case kDefault: value = *(const int *)*argv++; break; + case kLong: value = *(const long *)*argv++; break; + case kLongLong: value = *(const int64 *)*argv++; break; + break; + default: + VDNEVERHERE; + } + + if (value < 0) + *pbuf++ = L'-'; + else if (flags.bPositiveSign) + *pbuf++ = L'+'; + else if (flags.bPositiveBlank) + *pbuf++ = L' '; + + if (value < (VD64(10) << 10)) + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d bytes", (int)value); + else if (value < (VD64(10) << 20)) + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d KB", (int)((sint32)value >> 10)); + else if (value < (VD64(10) << 30)) + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d MB", (int)((sint32)value >> 20)); + else if (value < (VD64(10) << 40)) + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d GB", (int)(value >> 30)); + else + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d TB", (int)(value >> 40)); + } + + break; + } + break; + + } + + int string_width = (pbuf - pbuf0) + zero_pad; + int string_delta = width - string_width; + + if (!flags.bLeftAlign && string_delta > 0) { + int siz = out.size(); + out.resize(siz + string_delta, flags.bZeroPad ? L'0' : L' '); + } + + if (zero_pad) { + int siz = out.size(); + out.resize(siz + zero_pad); + std::fill(&out[siz], &out[siz+zero_pad], L'0'); + } + + if (pbuf != pbuf0) { + int siz = out.size(); + out.resize(siz + (pbuf - pbuf0)); + + std::copy(pbuf0, pbuf, &out[siz]); + } + + if (flags.bLeftAlign && string_delta > 0) { + int siz = out.size(); + out.resize(siz + string_delta); + std::fill(&out[siz], &out[siz+string_delta], L' '); + } + } + } + + out.push_back(0); + + return VDStringW(out.data()); +} + +VDStringW VDvswprintf(const wchar_t *format, int args, va_list val) { + if (args < 16) { + const void *argv[16]; + + for(int i=0; i argv(args); + + for(int i=0; i - -#include - -#include -#include -#include -#include -#include - -namespace { - // - // This apparently came from one a talk by one of the Visual Studio - // developers, i.e. I didn't write it. - // - #define MS_VC_EXCEPTION 0x406d1388 - - typedef struct tagTHREADNAME_INFO - { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in same addr space) - DWORD dwThreadID; // thread ID (-1 caller thread) - DWORD dwFlags; // reserved for future use, most be zero - } THREADNAME_INFO; -} - -VDThreadID VDGetCurrentThreadID() { - return (VDThreadID)GetCurrentThreadId(); -} - -VDProcessId VDGetCurrentProcessId() { - return (VDProcessId)GetCurrentProcessId(); -} - -uint32 VDGetLogicalProcessorCount() { - DWORD_PTR processAffinityMask; - DWORD_PTR systemAffinityMask; - if (!::GetProcessAffinityMask(::GetCurrentProcess(), &processAffinityMask, &systemAffinityMask)) - return 1; - - // avoid unnecessary WTFs - if (!processAffinityMask) - return 1; - - // We use the process affinity mask as that's the number of logical processors we'll - // actually be working with. - return VDCountBits(processAffinityMask); -} - -void VDSetThreadDebugName(VDThreadID tid, const char *name) { - #ifdef VD_COMPILER_MSVC - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = name; - info.dwThreadID = tid; - info.dwFlags = 0; - - __try { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info); - } __except (EXCEPTION_CONTINUE_EXECUTION) { - } - #endif -} - -void VDThreadSleep(int milliseconds) { - if (milliseconds > 0) - ::Sleep(milliseconds); -} - -/////////////////////////////////////////////////////////////////////////// - -VDThread::VDThread(const char *pszDebugName) - : mpszDebugName(pszDebugName) - , mhThread(0) - , mThreadID(0) - , mThreadPriority(INT_MIN) -{ -} - -VDThread::~VDThread() throw() { - if (isThreadAttached()) - ThreadWait(); -} - -bool VDThread::ThreadStart() { - VDASSERT(!isThreadAttached()); - - if (!isThreadAttached()) { - mhThread = (void *)_beginthreadex(NULL, 0, StaticThreadStart, this, 0, &mThreadID); - - if (mhThread && mThreadPriority != INT_MIN) - ::SetThreadPriority(mhThread, mThreadPriority); - } - - return mhThread != 0; -} - -void VDThread::ThreadDetach() { - if (isThreadAttached()) { - CloseHandle((HANDLE)mhThread); - mhThread = NULL; - mThreadID = 0; - } -} - -void VDThread::ThreadWait() { - if (isThreadAttached()) { - WaitForSingleObject((HANDLE)mhThread, INFINITE); - ThreadDetach(); - mThreadID = 0; - } -} - -void VDThread::ThreadSetPriority(int priority) { - if (mThreadPriority != priority) { - mThreadPriority = priority; - - if (mhThread && priority != INT_MIN) - ::SetThreadPriority(mhThread, priority); - } -} - -bool VDThread::isThreadActive() { - if (isThreadAttached()) { - if (WAIT_TIMEOUT == WaitForSingleObject((HANDLE)mhThread, 0)) - return true; - - ThreadDetach(); - mThreadID = 0; - } - return false; -} - -void VDThread::ThreadFinish() { - _endthreadex(0); -} - -void *VDThread::ThreadLocation() const { - if (!isThreadAttached()) - return NULL; - - CONTEXT ctx; - - ctx.ContextFlags = CONTEXT_CONTROL; - - SuspendThread(mhThread); - GetThreadContext(mhThread, &ctx); - ResumeThread(mhThread); - -#if defined(VD_CPU_AMD64) - return (void *)ctx.Rip; -#elif defined(VD_CPU_X86) - return (void *)ctx.Eip; -#elif defined(VD_CPU_ARM) - return (void *)ctx.Pc; -#endif -} - -/////////////////////////////////////////////////////////////////////////// - -unsigned __stdcall VDThread::StaticThreadStart(void *pThisAsVoid) { - VDThread *pThis = static_cast(pThisAsVoid); - - // We cannot use mThreadID here because it might already have been - // invalidated by a detach in the main thread. - if (pThis->mpszDebugName) - VDSetThreadDebugName(GetCurrentThreadId(), pThis->mpszDebugName); - - VDInitThreadData(pThis->mpszDebugName); - - vdprotected1("running thread \"%.64s\"", const char *, pThis->mpszDebugName) { - pThis->ThreadRun(); - } - - // NOTE: Do not put anything referencing this here, since our object - // may have been destroyed by the threaded code. - - VDDeinitThreadData(); - - return 0; -} - -/////////////////////////////////////////////////////////////////////////// - -void VDCriticalSection::StructCheck() { - VDASSERTCT(sizeof(CritSec) == sizeof(CRITICAL_SECTION)); -} - -/////////////////////////////////////////////////////////////////////////// - -VDSignal::VDSignal() { - hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); -} - -VDSignalPersistent::VDSignalPersistent() { - hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); -} - -VDSignalBase::~VDSignalBase() { - CloseHandle(hEvent); -} - -void VDSignalBase::signal() { - SetEvent(hEvent); -} - -void VDSignalBase::wait() { - WaitForSingleObject(hEvent, INFINITE); -} - -bool VDSignalBase::check() { - return WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0); -} - -int VDSignalBase::wait(VDSignalBase *second) { - HANDLE hArray[16]; - DWORD dwRet; - - hArray[0] = hEvent; - hArray[1] = second->hEvent; - - dwRet = WaitForMultipleObjects(2, hArray, FALSE, INFINITE); - - return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; -} - -int VDSignalBase::wait(VDSignalBase *second, VDSignalBase *third) { - HANDLE hArray[3]; - DWORD dwRet; - - hArray[0] = hEvent; - hArray[1] = second->hEvent; - hArray[2] = third->hEvent; - - dwRet = WaitForMultipleObjects(3, hArray, FALSE, INFINITE); - - return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; -} - -int VDSignalBase::waitMultiple(const VDSignalBase **signals, int count) { - VDASSERT(count <= 16); - - HANDLE handles[16]; - int active = 0; - - for(int i=0; ihEvent; - - if (h) - handles[active++] = h; - } - - if (!active) - return -1; - - DWORD dwRet = WaitForMultipleObjects(active, handles, FALSE, INFINITE); - - return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; -} - -bool VDSignalBase::tryWait(uint32 timeoutMillisec) { - return WAIT_OBJECT_0 == WaitForSingleObject(hEvent, timeoutMillisec); -} - -void VDSignalPersistent::unsignal() { - ResetEvent(hEvent); -} - -VDSemaphore::VDSemaphore(int initial) - : mKernelSema(CreateSemaphore(NULL, initial, 0x0fffffff, NULL)) -{ -} - -VDSemaphore::~VDSemaphore() { - if (mKernelSema) - CloseHandle(mKernelSema); -} - -void VDSemaphore::Reset(int count) { - // reset semaphore to zero - while(WAIT_OBJECT_0 == WaitForSingleObject(mKernelSema, 0)) - ; - - if (count) - ReleaseSemaphore(mKernelSema, count, NULL); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include + +#include +#include +#include +#include +#include + +namespace { + // + // This apparently came from one a talk by one of the Visual Studio + // developers, i.e. I didn't write it. + // + #define MS_VC_EXCEPTION 0x406d1388 + + typedef struct tagTHREADNAME_INFO + { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in same addr space) + DWORD dwThreadID; // thread ID (-1 caller thread) + DWORD dwFlags; // reserved for future use, most be zero + } THREADNAME_INFO; +} + +VDThreadID VDGetCurrentThreadID() { + return (VDThreadID)GetCurrentThreadId(); +} + +VDProcessId VDGetCurrentProcessId() { + return (VDProcessId)GetCurrentProcessId(); +} + +uint32 VDGetLogicalProcessorCount() { + DWORD_PTR processAffinityMask; + DWORD_PTR systemAffinityMask; + if (!::GetProcessAffinityMask(::GetCurrentProcess(), &processAffinityMask, &systemAffinityMask)) + return 1; + + // avoid unnecessary WTFs + if (!processAffinityMask) + return 1; + + // We use the process affinity mask as that's the number of logical processors we'll + // actually be working with. + return VDCountBits(processAffinityMask); +} + +void VDSetThreadDebugName(VDThreadID tid, const char *name) { + #ifdef VD_COMPILER_MSVC + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = tid; + info.dwFlags = 0; + + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info); + } __except (EXCEPTION_CONTINUE_EXECUTION) { + } + #endif +} + +void VDThreadSleep(int milliseconds) { + if (milliseconds > 0) + ::Sleep(milliseconds); +} + +/////////////////////////////////////////////////////////////////////////// + +VDThread::VDThread(const char *pszDebugName) + : mpszDebugName(pszDebugName) + , mhThread(0) + , mThreadID(0) + , mThreadPriority(INT_MIN) +{ +} + +VDThread::~VDThread() throw() { + if (isThreadAttached()) + ThreadWait(); +} + +bool VDThread::ThreadStart() { + VDASSERT(!isThreadAttached()); + + if (!isThreadAttached()) { + mhThread = (void *)_beginthreadex(NULL, 0, StaticThreadStart, this, 0, &mThreadID); + + if (mhThread && mThreadPriority != INT_MIN) + ::SetThreadPriority(mhThread, mThreadPriority); + } + + return mhThread != 0; +} + +void VDThread::ThreadDetach() { + if (isThreadAttached()) { + CloseHandle((HANDLE)mhThread); + mhThread = NULL; + mThreadID = 0; + } +} + +void VDThread::ThreadWait() { + if (isThreadAttached()) { + WaitForSingleObject((HANDLE)mhThread, INFINITE); + ThreadDetach(); + mThreadID = 0; + } +} + +void VDThread::ThreadSetPriority(int priority) { + if (mThreadPriority != priority) { + mThreadPriority = priority; + + if (mhThread && priority != INT_MIN) + ::SetThreadPriority(mhThread, priority); + } +} + +bool VDThread::isThreadActive() { + if (isThreadAttached()) { + if (WAIT_TIMEOUT == WaitForSingleObject((HANDLE)mhThread, 0)) + return true; + + ThreadDetach(); + mThreadID = 0; + } + return false; +} + +void VDThread::ThreadFinish() { + _endthreadex(0); +} + +void *VDThread::ThreadLocation() const { + if (!isThreadAttached()) + return NULL; + + CONTEXT ctx; + + ctx.ContextFlags = CONTEXT_CONTROL; + + SuspendThread(mhThread); + GetThreadContext(mhThread, &ctx); + ResumeThread(mhThread); + +#if defined(VD_CPU_AMD64) + return (void *)ctx.Rip; +#elif defined(VD_CPU_X86) + return (void *)ctx.Eip; +#elif defined(VD_CPU_ARM) + return (void *)ctx.Pc; +#endif +} + +/////////////////////////////////////////////////////////////////////////// + +unsigned __stdcall VDThread::StaticThreadStart(void *pThisAsVoid) { + VDThread *pThis = static_cast(pThisAsVoid); + + // We cannot use mThreadID here because it might already have been + // invalidated by a detach in the main thread. + if (pThis->mpszDebugName) + VDSetThreadDebugName(GetCurrentThreadId(), pThis->mpszDebugName); + + VDInitThreadData(pThis->mpszDebugName); + + vdprotected1("running thread \"%.64s\"", const char *, pThis->mpszDebugName) { + pThis->ThreadRun(); + } + + // NOTE: Do not put anything referencing this here, since our object + // may have been destroyed by the threaded code. + + VDDeinitThreadData(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// + +void VDCriticalSection::StructCheck() { + VDASSERTCT(sizeof(CritSec) == sizeof(CRITICAL_SECTION)); +} + +/////////////////////////////////////////////////////////////////////////// + +VDSignal::VDSignal() { + hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); +} + +VDSignalPersistent::VDSignalPersistent() { + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); +} + +VDSignalBase::~VDSignalBase() { + CloseHandle(hEvent); +} + +void VDSignalBase::signal() { + SetEvent(hEvent); +} + +void VDSignalBase::wait() { + WaitForSingleObject(hEvent, INFINITE); +} + +bool VDSignalBase::check() { + return WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0); +} + +int VDSignalBase::wait(VDSignalBase *second) { + HANDLE hArray[16]; + DWORD dwRet; + + hArray[0] = hEvent; + hArray[1] = second->hEvent; + + dwRet = WaitForMultipleObjects(2, hArray, FALSE, INFINITE); + + return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; +} + +int VDSignalBase::wait(VDSignalBase *second, VDSignalBase *third) { + HANDLE hArray[3]; + DWORD dwRet; + + hArray[0] = hEvent; + hArray[1] = second->hEvent; + hArray[2] = third->hEvent; + + dwRet = WaitForMultipleObjects(3, hArray, FALSE, INFINITE); + + return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; +} + +int VDSignalBase::waitMultiple(const VDSignalBase **signals, int count) { + VDASSERT(count <= 16); + + HANDLE handles[16]; + int active = 0; + + for(int i=0; ihEvent; + + if (h) + handles[active++] = h; + } + + if (!active) + return -1; + + DWORD dwRet = WaitForMultipleObjects(active, handles, FALSE, INFINITE); + + return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; +} + +bool VDSignalBase::tryWait(uint32 timeoutMillisec) { + return WAIT_OBJECT_0 == WaitForSingleObject(hEvent, timeoutMillisec); +} + +void VDSignalPersistent::unsignal() { + ResetEvent(hEvent); +} + +VDSemaphore::VDSemaphore(int initial) + : mKernelSema(CreateSemaphore(NULL, initial, 0x0fffffff, NULL)) +{ +} + +VDSemaphore::~VDSemaphore() { + if (mKernelSema) + CloseHandle(mKernelSema); +} + +void VDSemaphore::Reset(int count) { + // reset semaphore to zero + while(WAIT_OBJECT_0 == WaitForSingleObject(mKernelSema, 0)) + ; + + if (count) + ReleaseSemaphore(mKernelSema, count, NULL); +} diff --git a/src/thirdparty/VirtualDub/system/source/thunk.cpp b/src/thirdparty/VirtualDub/system/source/thunk.cpp index 698510bc5e6..6bfddddfaed 100644 --- a/src/thirdparty/VirtualDub/system/source/thunk.cpp +++ b/src/thirdparty/VirtualDub/system/source/thunk.cpp @@ -1,308 +1,308 @@ -#include "stdafx.h" -#include -#include -#include -#include -#include -#include - -class IVDJITAllocator {}; - -class VDJITAllocator : public vdrefcounted { -public: - VDJITAllocator(); - ~VDJITAllocator(); - - void *Allocate(size_t len); - void Free(void *p, size_t len); - - void EndUpdate(void *p, size_t len); - -protected: - typedef std::map FreeChunks; - FreeChunks mFreeChunks; - FreeChunks::iterator mNextChunk; - - typedef std::map Allocations; - Allocations mAllocations; - - uintptr mAllocationGranularity; -}; - -VDJITAllocator::VDJITAllocator() - : mNextChunk(mFreeChunks.end()) -{ - SYSTEM_INFO si; - GetSystemInfo(&si); - - mAllocationGranularity = si.dwAllocationGranularity; -} - -VDJITAllocator::~VDJITAllocator() { - for(Allocations::iterator it(mAllocations.begin()), itEnd(mAllocations.end()); it!=itEnd; ++it) { - VirtualFree(it->first, 0, MEM_RELEASE); - } -} - -void *VDJITAllocator::Allocate(size_t len) { - len = (len + 15) & ~(size_t)15; - - FreeChunks::iterator itMark(mNextChunk), itEnd(mFreeChunks.end()), it(itMark); - - if (it == itEnd) - it = mFreeChunks.begin(); - - for(;;) { - for(; it!=itEnd; ++it) { - if (it->second >= len) { - it->second -= len; - - void *p = (char *)it->first + it->second; - - if (!it->second) { - if (mNextChunk == it) - ++mNextChunk; - - mFreeChunks.erase(it); - } - - return p; - } - } - - if (itEnd == itMark) - break; - - it = mFreeChunks.begin(); - itEnd = itMark; - } - - size_t alloclen = (len + mAllocationGranularity - 1) & ~(mAllocationGranularity - 1); - - void *p = VirtualAlloc(NULL, alloclen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (p) { - try { - Allocations::iterator itA(mAllocations.insert(Allocations::value_type(p, alloclen)).first); - - try { - if (len < alloclen) - mFreeChunks.insert(FreeChunks::value_type((char *)p + len, alloclen - len)); - - } catch(...) { - mAllocations.erase(itA); - throw; - } - } catch(...) { - VirtualFree(p, 0, MEM_RELEASE); - p = NULL; - } - } - - return p; -} - -void VDJITAllocator::Free(void *p, size_t len) { - VDASSERT(p); - VDASSERT(len < 0x10000); - - FreeChunks::iterator cur(mFreeChunks.lower_bound(p)); - if (cur != mFreeChunks.end() && (char *)p + len == cur->first) { - len += cur->second; - if (mNextChunk == cur) - ++mNextChunk; - - mFreeChunks.erase(cur++); - } - - if (cur != mFreeChunks.begin()) { - FreeChunks::iterator prev(cur); - - --prev; - if ((char *)prev->first + prev->second == p) { - p = prev->first; - len += prev->second; - if (mNextChunk == prev) - ++mNextChunk; - mFreeChunks.erase(prev); - } - } - - uintptr start = (size_t)p; - uintptr end = start + len; - - if (!((start | end) & (mAllocationGranularity - 1))) { - Allocations::iterator it(mAllocations.find(p)); - - if (it != mAllocations.end()) { - VirtualFree((void *)start, 0, MEM_RELEASE); - mAllocations.erase(it); - return; - } - } - - mFreeChunks.insert(FreeChunks::value_type((void *)start, end-start)); -} - -void VDJITAllocator::EndUpdate(void *p, size_t len) { - FlushInstructionCache(GetCurrentProcess(), p, len); -} - -/////////////////////////////////////////////////////////////////////////// - -VDJITAllocator *g_pVDJITAllocator; -VDAtomicInt g_VDJITAllocatorLock; - -bool VDInitThunkAllocator() { - bool success = true; - - while(g_VDJITAllocatorLock.xchg(1)) - ::Sleep(1); - - if (!g_pVDJITAllocator) { - g_pVDJITAllocator = new_nothrow VDJITAllocator; - if (!g_pVDJITAllocator) - success = false; - } - - if (success) - g_pVDJITAllocator->AddRef(); - - VDVERIFY(1 == g_VDJITAllocatorLock.xchg(0)); - - return success; -} - -void VDShutdownThunkAllocator() { - while(g_VDJITAllocatorLock.xchg(1)) - ::Sleep(1); - - VDASSERT(g_pVDJITAllocator); - - if (!g_pVDJITAllocator->Release()) - g_pVDJITAllocator = NULL; - - VDVERIFY(1 == g_VDJITAllocatorLock.xchg(0)); -} - -void *VDAllocateThunkMemory(size_t len) { - return g_pVDJITAllocator->Allocate(len); -} - -void VDFreeThunkMemory(void *p, size_t len) { - g_pVDJITAllocator->Free(p, len); -} - -void VDSetThunkMemory(void *p, const void *src, size_t len) { - memcpy(p, src, len); - g_pVDJITAllocator->EndUpdate(p, len); -} - -void VDFlushThunkMemory(void *p, size_t len) { - g_pVDJITAllocator->EndUpdate(p, len); -} - -/////////////////////////////////////////////////////////////////////////// - -#ifdef _M_AMD64 - extern "C" void VDMethodToFunctionThunk64(); -#else - extern "C" void VDMethodToFunctionThunk32(); - extern "C" void VDMethodToFunctionThunk32_4(); - extern "C" void VDMethodToFunctionThunk32_8(); - extern "C" void VDMethodToFunctionThunk32_12(); - extern "C" void VDMethodToFunctionThunk32_16(); -#endif - -VDFunctionThunk *VDCreateFunctionThunkFromMethod(void *method, void *pThis, size_t argbytes, bool stdcall_thunk) { -#if defined(_M_IX86) - void *pThunk = VDAllocateThunkMemory(16); - - if (!pThunk) - return NULL; - - if (stdcall_thunk || !argbytes) { // thiscall -> stdcall (easy case) - uint8 thunkbytes[16]={ - 0xB9, 0x00, 0x00, 0x00, 0x00, // mov ecx, this - 0xE9, 0x00, 0x00, 0x00, 0x00 // jmp fn - }; - - - VDWriteUnalignedLEU32(thunkbytes+1, (uint32)(uintptr)pThis); - VDWriteUnalignedLEU32(thunkbytes+6, (uint32)method - ((uint32)pThunk + 10)); - - VDSetThunkMemory(pThunk, thunkbytes, 15); - } else { // thiscall -> cdecl (hard case) - uint8 thunkbytes[16]={ - 0xE8, 0x00, 0x00, 0x00, 0x00, // call VDFunctionThunk32 - 0xC3, // ret - argbytes, // db argbytes - 0, // db 0 - 0x00, 0x00, 0x00, 0x00, // dd method - 0x00, 0x00, 0x00, 0x00, // dd this - }; - - void (*adapter)(); - - switch(argbytes) { - case 4: adapter = VDMethodToFunctionThunk32_4; break; - case 8: adapter = VDMethodToFunctionThunk32_8; break; - case 12: adapter = VDMethodToFunctionThunk32_12; break; - case 16: adapter = VDMethodToFunctionThunk32_16; break; - default: adapter = VDMethodToFunctionThunk32; break; - } - - VDWriteUnalignedLEU32(thunkbytes+1, (uint32)(uintptr)adapter - ((uint32)pThunk + 5)); - VDWriteUnalignedLEU32(thunkbytes+8, (uint32)(uintptr)method); - VDWriteUnalignedLEU32(thunkbytes+12, (uint32)(uintptr)pThis); - - VDSetThunkMemory(pThunk, thunkbytes, 16); - } - - return (VDFunctionThunk *)pThunk; -#elif defined(_M_AMD64) - void *pThunk = VDAllocateThunkMemory(44); - if (!pThunk) - return NULL; - - uint8 thunkbytes[44]={ - 0x48, 0x8D, 0x05, 0x09, 0x00, 0x00, 0x00, // lea rax, [rip+9] - 0xFF, 0x25, 0x03, 0x00, 0x00, 0x00, // jmp qword ptr [rip+3] - 0x90, // nop - 0x90, // nop - 0x90, // nop - 0, 0, 0, 0, 0, 0, 0, 0, // dq VDFunctionThunk64 - 0, 0, 0, 0, 0, 0, 0, 0, // dq method - 0, 0, 0, 0, 0, 0, 0, 0, // dq this - 0, 0, 0, 0 // dd argspillbytes - }; - - VDWriteUnalignedLEU64(thunkbytes+16, (uint64)(uintptr)VDMethodToFunctionThunk64); - VDWriteUnalignedLEU64(thunkbytes+24, (uint64)(uintptr)method); - VDWriteUnalignedLEU64(thunkbytes+32, (uint64)(uintptr)pThis); - - // The stack must be aligned to a 16 byte boundary when the CALL - // instruction occurs. On entry to VDFunctionThunk64(), the stack is misaligned - // to 16n+8. Therefore, the number of argbytes must be 16m+8 and the number of - // argspillbytes must be 16m+8-24. - VDWriteUnalignedLEU32(thunkbytes+40, argbytes < 32 ? 0 : ((argbytes - 16 + 15) & ~15)); - - VDSetThunkMemory(pThunk, thunkbytes, 44); - - return (VDFunctionThunk *)pThunk; -#else - return NULL; -#endif -} - -void VDDestroyFunctionThunk(VDFunctionThunk *pFnThunk) { - // validate thunk -#if defined(_M_IX86) - VDASSERT(((const uint8 *)pFnThunk)[0] == 0xB9 || ((const uint8 *)pFnThunk)[0] == 0xE8); - VDFreeThunkMemory(pFnThunk, 16); -#elif defined(_M_AMD64) - VDFreeThunkMemory(pFnThunk, 44); -#else - VDASSERT(false); -#endif - -} +#include "stdafx.h" +#include +#include +#include +#include +#include +#include + +class IVDJITAllocator {}; + +class VDJITAllocator : public vdrefcounted { +public: + VDJITAllocator(); + ~VDJITAllocator(); + + void *Allocate(size_t len); + void Free(void *p, size_t len); + + void EndUpdate(void *p, size_t len); + +protected: + typedef std::map FreeChunks; + FreeChunks mFreeChunks; + FreeChunks::iterator mNextChunk; + + typedef std::map Allocations; + Allocations mAllocations; + + uintptr mAllocationGranularity; +}; + +VDJITAllocator::VDJITAllocator() + : mNextChunk(mFreeChunks.end()) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + + mAllocationGranularity = si.dwAllocationGranularity; +} + +VDJITAllocator::~VDJITAllocator() { + for(Allocations::iterator it(mAllocations.begin()), itEnd(mAllocations.end()); it!=itEnd; ++it) { + VirtualFree(it->first, 0, MEM_RELEASE); + } +} + +void *VDJITAllocator::Allocate(size_t len) { + len = (len + 15) & ~(size_t)15; + + FreeChunks::iterator itMark(mNextChunk), itEnd(mFreeChunks.end()), it(itMark); + + if (it == itEnd) + it = mFreeChunks.begin(); + + for(;;) { + for(; it!=itEnd; ++it) { + if (it->second >= len) { + it->second -= len; + + void *p = (char *)it->first + it->second; + + if (!it->second) { + if (mNextChunk == it) + ++mNextChunk; + + mFreeChunks.erase(it); + } + + return p; + } + } + + if (itEnd == itMark) + break; + + it = mFreeChunks.begin(); + itEnd = itMark; + } + + size_t alloclen = (len + mAllocationGranularity - 1) & ~(mAllocationGranularity - 1); + + void *p = VirtualAlloc(NULL, alloclen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (p) { + try { + Allocations::iterator itA(mAllocations.insert(Allocations::value_type(p, alloclen)).first); + + try { + if (len < alloclen) + mFreeChunks.insert(FreeChunks::value_type((char *)p + len, alloclen - len)); + + } catch(...) { + mAllocations.erase(itA); + throw; + } + } catch(...) { + VirtualFree(p, 0, MEM_RELEASE); + p = NULL; + } + } + + return p; +} + +void VDJITAllocator::Free(void *p, size_t len) { + VDASSERT(p); + VDASSERT(len < 0x10000); + + FreeChunks::iterator cur(mFreeChunks.lower_bound(p)); + if (cur != mFreeChunks.end() && (char *)p + len == cur->first) { + len += cur->second; + if (mNextChunk == cur) + ++mNextChunk; + + mFreeChunks.erase(cur++); + } + + if (cur != mFreeChunks.begin()) { + FreeChunks::iterator prev(cur); + + --prev; + if ((char *)prev->first + prev->second == p) { + p = prev->first; + len += prev->second; + if (mNextChunk == prev) + ++mNextChunk; + mFreeChunks.erase(prev); + } + } + + uintptr start = (size_t)p; + uintptr end = start + len; + + if (!((start | end) & (mAllocationGranularity - 1))) { + Allocations::iterator it(mAllocations.find(p)); + + if (it != mAllocations.end()) { + VirtualFree((void *)start, 0, MEM_RELEASE); + mAllocations.erase(it); + return; + } + } + + mFreeChunks.insert(FreeChunks::value_type((void *)start, end-start)); +} + +void VDJITAllocator::EndUpdate(void *p, size_t len) { + FlushInstructionCache(GetCurrentProcess(), p, len); +} + +/////////////////////////////////////////////////////////////////////////// + +VDJITAllocator *g_pVDJITAllocator; +VDAtomicInt g_VDJITAllocatorLock; + +bool VDInitThunkAllocator() { + bool success = true; + + while(g_VDJITAllocatorLock.xchg(1)) + ::Sleep(1); + + if (!g_pVDJITAllocator) { + g_pVDJITAllocator = new_nothrow VDJITAllocator; + if (!g_pVDJITAllocator) + success = false; + } + + if (success) + g_pVDJITAllocator->AddRef(); + + VDVERIFY(1 == g_VDJITAllocatorLock.xchg(0)); + + return success; +} + +void VDShutdownThunkAllocator() { + while(g_VDJITAllocatorLock.xchg(1)) + ::Sleep(1); + + VDASSERT(g_pVDJITAllocator); + + if (!g_pVDJITAllocator->Release()) + g_pVDJITAllocator = NULL; + + VDVERIFY(1 == g_VDJITAllocatorLock.xchg(0)); +} + +void *VDAllocateThunkMemory(size_t len) { + return g_pVDJITAllocator->Allocate(len); +} + +void VDFreeThunkMemory(void *p, size_t len) { + g_pVDJITAllocator->Free(p, len); +} + +void VDSetThunkMemory(void *p, const void *src, size_t len) { + memcpy(p, src, len); + g_pVDJITAllocator->EndUpdate(p, len); +} + +void VDFlushThunkMemory(void *p, size_t len) { + g_pVDJITAllocator->EndUpdate(p, len); +} + +/////////////////////////////////////////////////////////////////////////// + +#ifdef _M_AMD64 + extern "C" void VDMethodToFunctionThunk64(); +#else + extern "C" void VDMethodToFunctionThunk32(); + extern "C" void VDMethodToFunctionThunk32_4(); + extern "C" void VDMethodToFunctionThunk32_8(); + extern "C" void VDMethodToFunctionThunk32_12(); + extern "C" void VDMethodToFunctionThunk32_16(); +#endif + +VDFunctionThunk *VDCreateFunctionThunkFromMethod(void *method, void *pThis, size_t argbytes, bool stdcall_thunk) { +#if defined(_M_IX86) + void *pThunk = VDAllocateThunkMemory(16); + + if (!pThunk) + return NULL; + + if (stdcall_thunk || !argbytes) { // thiscall -> stdcall (easy case) + uint8 thunkbytes[16]={ + 0xB9, 0x00, 0x00, 0x00, 0x00, // mov ecx, this + 0xE9, 0x00, 0x00, 0x00, 0x00 // jmp fn + }; + + + VDWriteUnalignedLEU32(thunkbytes+1, (uint32)(uintptr)pThis); + VDWriteUnalignedLEU32(thunkbytes+6, (uint32)method - ((uint32)pThunk + 10)); + + VDSetThunkMemory(pThunk, thunkbytes, 15); + } else { // thiscall -> cdecl (hard case) + uint8 thunkbytes[16]={ + 0xE8, 0x00, 0x00, 0x00, 0x00, // call VDFunctionThunk32 + 0xC3, // ret + argbytes, // db argbytes + 0, // db 0 + 0x00, 0x00, 0x00, 0x00, // dd method + 0x00, 0x00, 0x00, 0x00, // dd this + }; + + void (*adapter)(); + + switch(argbytes) { + case 4: adapter = VDMethodToFunctionThunk32_4; break; + case 8: adapter = VDMethodToFunctionThunk32_8; break; + case 12: adapter = VDMethodToFunctionThunk32_12; break; + case 16: adapter = VDMethodToFunctionThunk32_16; break; + default: adapter = VDMethodToFunctionThunk32; break; + } + + VDWriteUnalignedLEU32(thunkbytes+1, (uint32)(uintptr)adapter - ((uint32)pThunk + 5)); + VDWriteUnalignedLEU32(thunkbytes+8, (uint32)(uintptr)method); + VDWriteUnalignedLEU32(thunkbytes+12, (uint32)(uintptr)pThis); + + VDSetThunkMemory(pThunk, thunkbytes, 16); + } + + return (VDFunctionThunk *)pThunk; +#elif defined(_M_AMD64) + void *pThunk = VDAllocateThunkMemory(44); + if (!pThunk) + return NULL; + + uint8 thunkbytes[44]={ + 0x48, 0x8D, 0x05, 0x09, 0x00, 0x00, 0x00, // lea rax, [rip+9] + 0xFF, 0x25, 0x03, 0x00, 0x00, 0x00, // jmp qword ptr [rip+3] + 0x90, // nop + 0x90, // nop + 0x90, // nop + 0, 0, 0, 0, 0, 0, 0, 0, // dq VDFunctionThunk64 + 0, 0, 0, 0, 0, 0, 0, 0, // dq method + 0, 0, 0, 0, 0, 0, 0, 0, // dq this + 0, 0, 0, 0 // dd argspillbytes + }; + + VDWriteUnalignedLEU64(thunkbytes+16, (uint64)(uintptr)VDMethodToFunctionThunk64); + VDWriteUnalignedLEU64(thunkbytes+24, (uint64)(uintptr)method); + VDWriteUnalignedLEU64(thunkbytes+32, (uint64)(uintptr)pThis); + + // The stack must be aligned to a 16 byte boundary when the CALL + // instruction occurs. On entry to VDFunctionThunk64(), the stack is misaligned + // to 16n+8. Therefore, the number of argbytes must be 16m+8 and the number of + // argspillbytes must be 16m+8-24. + VDWriteUnalignedLEU32(thunkbytes+40, argbytes < 32 ? 0 : ((argbytes - 16 + 15) & ~15)); + + VDSetThunkMemory(pThunk, thunkbytes, 44); + + return (VDFunctionThunk *)pThunk; +#else + return NULL; +#endif +} + +void VDDestroyFunctionThunk(VDFunctionThunk *pFnThunk) { + // validate thunk +#if defined(_M_IX86) + VDASSERT(((const uint8 *)pFnThunk)[0] == 0xB9 || ((const uint8 *)pFnThunk)[0] == 0xE8); + VDFreeThunkMemory(pFnThunk, 16); +#elif defined(_M_AMD64) + VDFreeThunkMemory(pFnThunk, 44); +#else + VDASSERT(false); +#endif + +} diff --git a/src/thirdparty/VirtualDub/system/source/tls.cpp b/src/thirdparty/VirtualDub/system/source/tls.cpp index 71044d1e50f..e5411b9b584 100644 --- a/src/thirdparty/VirtualDub/system/source/tls.cpp +++ b/src/thirdparty/VirtualDub/system/source/tls.cpp @@ -1,43 +1,43 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -VDThreadInitHook g_pInitHook; - -void VDInitThreadData(const char *pszThreadName) { - if (g_pInitHook) - g_pInitHook(true, pszThreadName); -} - -void VDDeinitThreadData() { - if (g_pInitHook) - g_pInitHook(false, NULL); -} - -void VDSetThreadInitHook(VDThreadInitHook pHook) { - g_pInitHook = pHook; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +VDThreadInitHook g_pInitHook; + +void VDInitThreadData(const char *pszThreadName) { + if (g_pInitHook) + g_pInitHook(true, pszThreadName); +} + +void VDDeinitThreadData() { + if (g_pInitHook) + g_pInitHook(false, NULL); +} + +void VDSetThreadInitHook(VDThreadInitHook pHook) { + g_pInitHook = pHook; +} diff --git a/src/thirdparty/VirtualDub/system/source/vdstl.cpp b/src/thirdparty/VirtualDub/system/source/vdstl.cpp index 819ecd15b41..48edd6883da 100644 --- a/src/thirdparty/VirtualDub/system/source/vdstl.cpp +++ b/src/thirdparty/VirtualDub/system/source/vdstl.cpp @@ -1,37 +1,37 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2008 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -void VDNORETURN vdallocator_base::throw_oom(size_t n, size_t elsize) { - size_t nbytes = ~(size_t)0; - - if (n <= nbytes / elsize) - nbytes = n * elsize; - - throw MyMemoryError(nbytes); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2008 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +void VDNORETURN vdallocator_base::throw_oom(size_t n, size_t elsize) { + size_t nbytes = ~(size_t)0; + + if (n <= nbytes / elsize) + nbytes = n * elsize; + + throw MyMemoryError(nbytes); +} diff --git a/src/thirdparty/VirtualDub/system/source/vdstl_hash.cpp b/src/thirdparty/VirtualDub/system/source/vdstl_hash.cpp index 8e842eadaa0..660d9359af4 100644 --- a/src/thirdparty/VirtualDub/system/source/vdstl_hash.cpp +++ b/src/thirdparty/VirtualDub/system/source/vdstl_hash.cpp @@ -1,109 +1,109 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include -#include -#include -#include - -size_t vdhash::operator()(const VDStringA& s) const { - return VDHashString32(s.data(), s.length()); -} - -size_t vdhash::operator()(const char *s) const { - return VDHashString32(s, strlen(s)); -} - -size_t vdhash::operator()(const VDStringW& s) const { - return VDHashString32(s.data(), s.length()); -} - -size_t vdhash::operator()(const wchar_t *s) const { - return VDHashString32(s, wcslen(s)); -} - -size_t vdstringhashi::operator()(const VDStringA& s) const { - return VDHashString32I(s.data(), s.length()); -} - -size_t vdstringhashi::operator()(const char *s) const { - return VDHashString32I(s); -} - -size_t vdstringhashi::operator()(const VDStringW& s) const { - return VDHashString32I(s.data(), s.length()); -} - -size_t vdstringhashi::operator()(const wchar_t *s) const { - return VDHashString32I(s); -} - -bool vdstringpred::operator()(const VDStringA& s, const VDStringA& t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringA& s, const VDStringSpanA& t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringA& s, const char *t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringW& s, const VDStringW& t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringW& s, const VDStringSpanW& t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringW& s, const wchar_t *t) const { - return s == t; -} - -bool vdstringpredi::operator()(const VDStringA& s, const VDStringA& t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringA& s, const VDStringSpanA& t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringA& s, const char *t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringW& s, const VDStringW& t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringW& s, const VDStringSpanW& t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringW& s, const wchar_t *t) const { - return s.comparei(t) == 0; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include +#include +#include +#include + +size_t vdhash::operator()(const VDStringA& s) const { + return VDHashString32(s.data(), s.length()); +} + +size_t vdhash::operator()(const char *s) const { + return VDHashString32(s, strlen(s)); +} + +size_t vdhash::operator()(const VDStringW& s) const { + return VDHashString32(s.data(), s.length()); +} + +size_t vdhash::operator()(const wchar_t *s) const { + return VDHashString32(s, wcslen(s)); +} + +size_t vdstringhashi::operator()(const VDStringA& s) const { + return VDHashString32I(s.data(), s.length()); +} + +size_t vdstringhashi::operator()(const char *s) const { + return VDHashString32I(s); +} + +size_t vdstringhashi::operator()(const VDStringW& s) const { + return VDHashString32I(s.data(), s.length()); +} + +size_t vdstringhashi::operator()(const wchar_t *s) const { + return VDHashString32I(s); +} + +bool vdstringpred::operator()(const VDStringA& s, const VDStringA& t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringA& s, const VDStringSpanA& t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringA& s, const char *t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringW& s, const VDStringW& t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringW& s, const VDStringSpanW& t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringW& s, const wchar_t *t) const { + return s == t; +} + +bool vdstringpredi::operator()(const VDStringA& s, const VDStringA& t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringA& s, const VDStringSpanA& t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringA& s, const char *t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringW& s, const VDStringW& t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringW& s, const VDStringSpanW& t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringW& s, const wchar_t *t) const { + return s.comparei(t) == 0; +} diff --git a/src/thirdparty/VirtualDub/system/source/vdstl_hashtable.cpp b/src/thirdparty/VirtualDub/system/source/vdstl_hashtable.cpp index 9b1c277fe97..13234f3307d 100644 --- a/src/thirdparty/VirtualDub/system/source/vdstl_hashtable.cpp +++ b/src/thirdparty/VirtualDub/system/source/vdstl_hashtable.cpp @@ -1,82 +1,82 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include -#include - -vdhashtable_base_node *const vdhashtable_base::sEmptyBucket = {NULL}; - -vdhashtable_base::vdhashtable_base() - : mBucketCount(0) - , mElementCount(0) - , mpBucketStart(const_cast(&sEmptyBucket)) - , mpBucketEnd(const_cast(&sEmptyBucket)) -{ -} - -vdhashtable_base::size_type vdhashtable_base::bucket_count() const { - return mpBucketEnd - mpBucketStart; -} - -vdhashtable_base::size_type vdhashtable_base::max_bucket_count() const { - return (size_type)-1 >> 1; -} - -vdhashtable_base::size_type vdhashtable_base::bucket_size(size_type n) const { - VDASSERT(n < (size_type)(mpBucketEnd - mpBucketStart)); - - size_type len = 0; - for(vdhashtable_base_node *p = mpBucketStart[n]; p; p = p->mpHashNext) - ++len; - - return len; -} - -vdhashtable_base::size_type vdhashtable_base::compute_bucket_count(size_type n) { - static const size_t kBucketSizes[]={ - 11, - 17, 37, 67, 131, - 257, 521, 1031, 2049, - 4099, 8209, 16411, 32771, - 65537, 131101, 262147, 524309, - 1048583, 2097169, 4194319, 8388617, - 16777259, 33554467, 67108879, 134217757, - 268435459, 536870923, 1073741827 - }; - - int i = 0; - size_type buckets; - - while(i < sizeof(kBucketSizes)/sizeof(kBucketSizes[0])) { - buckets = kBucketSizes[i]; - - if (n <= buckets) - break; - - ++i; - } - - return buckets; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include +#include + +vdhashtable_base_node *const vdhashtable_base::sEmptyBucket = {NULL}; + +vdhashtable_base::vdhashtable_base() + : mBucketCount(0) + , mElementCount(0) + , mpBucketStart(const_cast(&sEmptyBucket)) + , mpBucketEnd(const_cast(&sEmptyBucket)) +{ +} + +vdhashtable_base::size_type vdhashtable_base::bucket_count() const { + return mpBucketEnd - mpBucketStart; +} + +vdhashtable_base::size_type vdhashtable_base::max_bucket_count() const { + return (size_type)-1 >> 1; +} + +vdhashtable_base::size_type vdhashtable_base::bucket_size(size_type n) const { + VDASSERT(n < (size_type)(mpBucketEnd - mpBucketStart)); + + size_type len = 0; + for(vdhashtable_base_node *p = mpBucketStart[n]; p; p = p->mpHashNext) + ++len; + + return len; +} + +vdhashtable_base::size_type vdhashtable_base::compute_bucket_count(size_type n) { + static const size_t kBucketSizes[]={ + 11, + 17, 37, 67, 131, + 257, 521, 1031, 2049, + 4099, 8209, 16411, 32771, + 65537, 131101, 262147, 524309, + 1048583, 2097169, 4194319, 8388617, + 16777259, 33554467, 67108879, 134217757, + 268435459, 536870923, 1073741827 + }; + + int i = 0; + size_type buckets; + + while(i < sizeof(kBucketSizes)/sizeof(kBucketSizes[0])) { + buckets = kBucketSizes[i]; + + if (n <= buckets) + break; + + ++i; + } + + return buckets; +} diff --git a/src/thirdparty/VirtualDub/system/source/vectors.cpp b/src/thirdparty/VirtualDub/system/source/vectors.cpp index 3a6b91c434c..4dfed053111 100644 --- a/src/thirdparty/VirtualDub/system/source/vectors.cpp +++ b/src/thirdparty/VirtualDub/system/source/vectors.cpp @@ -1,83 +1,83 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -bool VDSolveLinearEquation(double *src, int n, ptrdiff_t stride_elements, double *b, double tolerance) { - vdfastvector array(n); - double **m = &array[0]; - int i, j, k; - - for(i=0; i=i; --k) - m[j][k] -= m[i][k] * m[j][i]; - } - } - - // factor L - for(i=n-1; i>=0; --i) - for(j=i-1; j>=0; --j) - b[j] -= b[i] * m[j][i]; - - return true; -} - -template<> -bool vdrect32::contains(const vdpoint32& pt) const { - return ((uint32)pt.x - (uint32)left) < (uint32)right - (uint32)left - && ((uint32)pt.y - (uint32)top) < (uint32)bottom - (uint32)top; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +bool VDSolveLinearEquation(double *src, int n, ptrdiff_t stride_elements, double *b, double tolerance) { + vdfastvector array(n); + double **m = &array[0]; + int i, j, k; + + for(i=0; i=i; --k) + m[j][k] -= m[i][k] * m[j][i]; + } + } + + // factor L + for(i=n-1; i>=0; --i) + for(j=i-1; j>=0; --j) + b[j] -= b[i] * m[j][i]; + + return true; +} + +template<> +bool vdrect32::contains(const vdpoint32& pt) const { + return ((uint32)pt.x - (uint32)left) < (uint32)right - (uint32)left + && ((uint32)pt.y - (uint32)top) < (uint32)bottom - (uint32)top; +} diff --git a/src/thirdparty/VirtualDub/system/source/w32assist.cpp b/src/thirdparty/VirtualDub/system/source/w32assist.cpp index 311810dc5c6..659aee6e9bb 100644 --- a/src/thirdparty/VirtualDub/system/source/w32assist.cpp +++ b/src/thirdparty/VirtualDub/system/source/w32assist.cpp @@ -1,710 +1,710 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include -#include -#include - -bool VDIsForegroundTaskW32() { - HWND hwndFore = GetForegroundWindow(); - - if (!hwndFore) - return false; - - DWORD dwProcessId = 0; - GetWindowThreadProcessId(hwndFore, &dwProcessId); - - return dwProcessId == GetCurrentProcessId(); -} - -LPVOID VDConvertThreadToFiberW32(LPVOID parm) { - typedef LPVOID (WINAPI *tpConvertThreadToFiber)(LPVOID p); - static tpConvertThreadToFiber ctof = (tpConvertThreadToFiber)GetProcAddress(GetModuleHandle("kernel32"), "ConvertThreadToFiber"); - - if (!ctof) - return NULL; - - return ctof(parm); -} - -void VDSwitchToFiberW32(LPVOID fiber) { - typedef void (WINAPI *tpSwitchToFiber)(LPVOID p); - static tpSwitchToFiber stof = (tpSwitchToFiber)GetProcAddress(GetModuleHandle("kernel32"), "SwitchToFiber"); - - if (stof) - stof(fiber); -} - -int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr) { - int palents = 0; - - if ((pHdr->biCompression == BI_RGB || pHdr->biCompression == BI_RLE4 || pHdr->biCompression == BI_RLE8) && pHdr->biBitCount <= 8) { - palents = pHdr->biClrUsed; - if (!palents) - palents = 1 << pHdr->biBitCount; - } - int size = pHdr->biSize + palents * sizeof(RGBQUAD); - - if (pHdr->biSize < sizeof(BITMAPV4HEADER) && pHdr->biCompression == BI_BITFIELDS) - size += sizeof(DWORD) * 3; - - return size; -} - -void VDSetWindowTextW32(HWND hwnd, const wchar_t *s) { - if (VDIsWindowsNT()) { - SetWindowTextW(hwnd, s); - } else { - SetWindowTextA(hwnd, VDTextWToA(s).c_str()); - } -} - -void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...) { - va_list val; - - va_start(val, format); - { - wchar_t buf[512]; - int r = vdvswprintf(buf, 512, format, val); - - if ((unsigned)r < 512) { - VDSetWindowTextW32(hwnd, buf); - va_end(val); - return; - } - } - - VDStringW s; - s.append_vsprintf(format, val); - VDSetWindowTextW32(hwnd, s.c_str()); - - va_end(val); -} - -VDStringA VDGetWindowTextAW32(HWND hwnd) { - char buf[512]; - - int len = GetWindowTextLengthA(hwnd); - - if (len > 511) { - vdblock tmp(len + 1); - len = GetWindowTextA(hwnd, tmp.data(), tmp.size()); - - const char *s = tmp.data(); - VDStringA text(s, s+len); - return text; - } else if (len > 0) { - len = GetWindowTextA(hwnd, buf, 512); - - return VDStringA(buf, buf + len); - } - - return VDStringA(); -} - -VDStringW VDGetWindowTextW32(HWND hwnd) { - union { - wchar_t w[256]; - char a[512]; - } buf; - - if (VDIsWindowsNT()) { - int len = GetWindowTextLengthW(hwnd); - - if (len > 255) { - vdblock tmp(len + 1); - len = GetWindowTextW(hwnd, tmp.data(), tmp.size()); - - VDStringW text(tmp.data(), len); - return text; - } else if (len > 0) { - len = GetWindowTextW(hwnd, buf.w, 256); - - VDStringW text(buf.w, len); - return text; - } - } else { - int len = GetWindowTextLengthA(hwnd); - - if (len > 511) { - vdblock tmp(len + 1); - len = GetWindowTextA(hwnd, tmp.data(), tmp.size()); - - VDStringW text(VDTextAToW(tmp.data(), len)); - return text; - } else if (len > 0) { - len = GetWindowTextA(hwnd, buf.a, 512); - - VDStringW text(VDTextAToW(buf.a, len)); - return text; - } - } - - return VDStringW(); -} - -void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text){ - if (VDIsWindowsNT()) { - AppendMenuW(hmenu, flags, id, text); - } else { - AppendMenuA(hmenu, flags, id, VDTextWToA(text).c_str()); - } -} - -bool VDAppendPopupMenuW32(HMENU hmenu, UINT flags, HMENU hmenuPopup, const wchar_t *text){ - flags |= MF_POPUP; - - if (VDIsWindowsNT()) - return 0 != AppendMenuW(hmenu, flags, (UINT_PTR)hmenuPopup, text); - else - return 0 != AppendMenuA(hmenu, flags, (UINT_PTR)hmenuPopup, VDTextWToA(text).c_str()); -} - -void VDAppendMenuSeparatorW32(HMENU hmenu) { - int pos = GetMenuItemCount(hmenu); - if (pos < 0) - return; - - if (VDIsWindowsNT()) { - MENUITEMINFOW mmiW; - vdfastfixedvector bufW; - - mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; - mmiW.fMask = MIIM_TYPE; - mmiW.fType = MFT_SEPARATOR; - - InsertMenuItemW(hmenu, pos, TRUE, &mmiW); - } else { - MENUITEMINFOA mmiA; - - mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; - mmiA.fMask = MIIM_TYPE; - mmiA.fType = MFT_SEPARATOR; - - InsertMenuItemA(hmenu, pos, TRUE, &mmiA); - } -} - -void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) { - CheckMenuItem(hmenu, pos, checked ? MF_BYPOSITION|MF_CHECKED : MF_BYPOSITION|MF_UNCHECKED); -} - -void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { - CheckMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED); -} - -void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) { - MENUITEMINFOA mii; - - mii.cbSize = sizeof(MENUITEMINFOA); - mii.fMask = MIIM_FTYPE | MIIM_STATE; - if (GetMenuItemInfo(hmenu, pos, TRUE, &mii)) { - mii.fType |= MFT_RADIOCHECK; - mii.fState &= ~MFS_CHECKED; - if (checked) - mii.fState |= MFS_CHECKED; - SetMenuItemInfo(hmenu, pos, TRUE, &mii); - } -} - -void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { - MENUITEMINFOA mii; - - mii.cbSize = sizeof(MENUITEMINFOA); - mii.fMask = MIIM_FTYPE | MIIM_STATE; - if (GetMenuItemInfo(hmenu, cmd, FALSE, &mii)) { - mii.fType |= MFT_RADIOCHECK; - mii.fState &= ~MFS_CHECKED; - if (checked) - mii.fState |= MFS_CHECKED; - SetMenuItemInfo(hmenu, cmd, FALSE, &mii); - } -} - -void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { - EnableMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_ENABLED : MF_BYCOMMAND|MF_GRAYED); -} - -VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd) { - VDStringW s; - - if (VDIsWindowsNT()) { - MENUITEMINFOW mmiW; - vdfastfixedvector bufW; - - mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; - mmiW.fMask = MIIM_TYPE; - mmiW.fType = MFT_STRING; - mmiW.dwTypeData = NULL; - mmiW.cch = 0; // required to avoid crash on NT4 - - if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) { - bufW.resize(mmiW.cch + 1, 0); - ++mmiW.cch; - mmiW.dwTypeData = bufW.data(); - - if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) - s = bufW.data(); - } - } else { - MENUITEMINFOA mmiA; - vdfastfixedvector bufA; - - mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; - mmiA.fMask = MIIM_TYPE; - mmiA.fType = MFT_STRING; - mmiA.dwTypeData = NULL; - - if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) { - bufA.resize(mmiA.cch + 1, 0); - ++mmiA.cch; - mmiA.dwTypeData = bufA.data(); - - if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) - s = VDTextAToW(bufA.data()); - } - } - - return s; -} - -void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text) { - if (VDIsWindowsNT()) { - MENUITEMINFOW mmiW; - - mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; - mmiW.fMask = MIIM_TYPE; - mmiW.fType = MFT_STRING; - mmiW.dwTypeData = (LPWSTR)text; - - SetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW); - } else { - MENUITEMINFOA mmiA; - VDStringA textA(VDTextWToA(text)); - - mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; - mmiA.fMask = MIIM_TYPE; - mmiA.fType = MFT_STRING; - mmiA.dwTypeData = (LPSTR)textA.c_str(); - - SetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA); - } -} - -LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - return (IsWindowUnicode(hwnd) ? CallWindowProcW : CallWindowProcA)(wp, hwnd, msg, wParam, lParam); -} - -LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, msg, wParam, lParam) : DefWindowProcA(hwnd, msg, wParam, lParam); -} - -EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags) { - EXECUTION_STATE es = 0; - - // SetThreadExecutionState(): requires Windows 98+/2000+. - typedef EXECUTION_STATE (WINAPI *tSetThreadExecutionState)(EXECUTION_STATE); - static tSetThreadExecutionState pFunc = (tSetThreadExecutionState)GetProcAddress(GetModuleHandle("kernel32"), "SetThreadExecutionState"); - - if (pFunc) - es = pFunc(esFlags); - - return es; -} - -bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod) { - LONG posHi = (LONG)(pos >> 32); - DWORD result = SetFilePointer(h, (LONG)pos, &posHi, dwMoveMethod); - - if (result != INVALID_SET_FILE_POINTER) - return true; - - DWORD dwError = GetLastError(); - - return (dwError == NO_ERROR); -} - -bool VDGetFileSizeW32(HANDLE h, sint64& size) { - DWORD dwSizeHigh; - DWORD dwSizeLow = GetFileSize(h, &dwSizeHigh); - - if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) - return false; - - size = dwSizeLow + ((sint64)dwSizeHigh << 32); - return true; -} - -#if !defined(_MSC_VER) || _MSC_VER < 1300 -HMODULE VDGetLocalModuleHandleW32() { - MEMORY_BASIC_INFORMATION meminfo; - static HMODULE shmod = (VirtualQuery((HINSTANCE)&VDGetLocalModuleHandleW32, &meminfo, sizeof meminfo), (HMODULE)meminfo.AllocationBase); - - return shmod; -} -#endif - -bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat) { - RECT r; - if (VDIsWindowsNT()) { - // If multiline and vcentered (not normally supported...) - if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) { - uFormat &= ~DT_VCENTER; - - r = *lpRect; - if (!DrawTextW(hdc, s, nCount, &r, uFormat | DT_CALCRECT)) - return false; - - int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1; - int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1; - - r.left += dx; - r.right += dx; - r.top += dy; - r.bottom += dy; - lpRect = &r; - } - - return !!DrawTextW(hdc, s, nCount, lpRect, uFormat); - } else { - VDStringA strA(VDTextWToA(s, nCount)); - - // If multiline and vcentered (not normally supported...) - if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) { - uFormat &= ~DT_VCENTER; - - r = *lpRect; - if (!DrawTextA(hdc, strA.data(), strA.size(), &r, uFormat | DT_CALCRECT)) - return false; - - int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1; - int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1; - - r.left += dx; - r.right += dx; - r.top += dy; - r.bottom += dy; - lpRect = &r; - } - - return !!DrawTextA(hdc, strA.data(), strA.size(), lpRect, uFormat); - } -} - -bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) { - char *pBase = (char *)hmod; - - vd_seh_guard_try { - // The PEheader offset is at hmod+0x3c. Add the size of the optional header - // to step to the section headers. - - const uint32 peoffset = ((const long *)pBase)[15]; - const uint32 signature = *(uint32 *)(pBase + peoffset); - - if (signature != IMAGE_NT_SIGNATURE) - return false; - - const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4); - - // Verify the PE optional structure. - - if (pHeader->SizeOfOptionalHeader < 104) - return false; - - // Find import header. - - const IMAGE_IMPORT_DESCRIPTOR *pImportDir; - int nImports; - - switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) { - -#ifdef _M_AMD64 - case IMAGE_NT_OPTIONAL_HDR64_MAGIC: - { - const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); - - if (pOpt->NumberOfRvaAndSizes < 2) - return false; - - pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); - nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); - } - break; -#else - case IMAGE_NT_OPTIONAL_HDR32_MAGIC: - { - const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); - - if (pOpt->NumberOfRvaAndSizes < 2) - return false; - - pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); - nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); - } - break; -#endif - - default: // reject PE32+ - return false; - } - - // Hmmm... no imports? - - if ((const char *)pImportDir == pBase) - return false; - - // Scan down the import entries. We are looking for MSVFW32. - - int i; - - for(i=0; i= nImports) - return false; - - // Found it. Start scanning MSVFW32 imports until we find DrawDibDraw. - - const long *pImports = (const long *)(pBase + pImportDir[i].OriginalFirstThunk); - void * volatile *pVector = (void * volatile *)(pBase + pImportDir[i].FirstThunk); - - while(*pImports) { - if (*pImports >= 0) { - const char *pName = pBase + *pImports + 2; - - if (!strcmp(pName, name)) { - - // Found it! Reset the protection. - - DWORD dwOldProtect; - - if (VirtualProtect((void *)pVector, sizeof(void *), PAGE_EXECUTE_READWRITE, &dwOldProtect)) { - if (ppOldValue) { - for(;;) { - void *old = *pVector; - if (pCompareValue && pCompareValue != old) - return false; - - *ppOldValue = old; - if (old == VDAtomicCompareExchangePointer(pVector, pNewValue, old)) - break; - } - } else { - *pVector = pNewValue; - } - - VirtualProtect((void *)pVector, sizeof(void *), dwOldProtect, &dwOldProtect); - - return true; - } - - break; - } - } - - ++pImports; - ++pVector; - } - } vd_seh_guard_except { - } - - return false; -} - -bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) { - char *pBase = (char *)hmod; - - vd_seh_guard_try { - // The PEheader offset is at hmod+0x3c. Add the size of the optional header - // to step to the section headers. - - const uint32 peoffset = ((const long *)pBase)[15]; - const uint32 signature = *(uint32 *)(pBase + peoffset); - - if (signature != IMAGE_NT_SIGNATURE) - return false; - - const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4); - - // Verify the PE optional structure. - - if (pHeader->SizeOfOptionalHeader < 104) - return false; - - // Find export directory. - - const IMAGE_EXPORT_DIRECTORY *pExportDir; - - switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) { - -#ifdef _M_AMD64 - case IMAGE_NT_OPTIONAL_HDR64_MAGIC: - { - const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); - - if (pOpt->NumberOfRvaAndSizes < 1) - return false; - - DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - - if (!exportDirRVA) - return false; - - pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA); - } - break; -#else - case IMAGE_NT_OPTIONAL_HDR32_MAGIC: - { - const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); - - if (pOpt->NumberOfRvaAndSizes < 1) - return false; - - DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - - if (!exportDirRVA) - return false; - - pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA); - } - break; -#endif - - default: // reject PE32+ - return false; - } - - // Scan for the export name. - DWORD nameCount = pExportDir->AddressOfNames; - const DWORD *nameRVAs = (const DWORD *)(pBase + pExportDir->AddressOfNames); - const WORD *nameOrdinals = (const WORD *)(pBase + pExportDir->AddressOfNameOrdinals); - DWORD *functionTable = (DWORD *)(pBase + pExportDir->AddressOfFunctions); - - for(DWORD i=0; i pathW(MAX_PATH, 0); - - size_t len = GetSystemDirectoryW(pathW.data(), MAX_PATH); - - if (!len) - return NULL; - - if (len > MAX_PATH) { - pathW.resize(len + 1, 0); - - len = GetSystemDirectoryW(pathW.data(), len); - if (!len || len >= pathW.size()) - return NULL; - } - - pathW.resize(len); - - if (pathW.back() != '\\') - pathW.push_back('\\'); - - while(const char c = *name++) - pathW.push_back(c); - - pathW.push_back(0); - - return LoadLibraryW(pathW.data()); - } else { - vdfastvector pathA(MAX_PATH, 0); - size_t len = GetSystemDirectoryA(pathA.data(), MAX_PATH); - - if (!len) - return NULL; - - if (len > MAX_PATH) { - pathA.resize(len + 1, 0); - - len = GetSystemDirectoryA(pathA.data(), len); - if (!len || len >= pathA.size()) - return NULL; - } - - pathA.resize(len); - - if (pathA.back() != '\\') - pathA.push_back('\\'); - - pathA.insert(pathA.end(), name, name + strlen(name)); - pathA.push_back(0); - - return LoadLibraryA(pathA.data()); - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include +#include +#include + +bool VDIsForegroundTaskW32() { + HWND hwndFore = GetForegroundWindow(); + + if (!hwndFore) + return false; + + DWORD dwProcessId = 0; + GetWindowThreadProcessId(hwndFore, &dwProcessId); + + return dwProcessId == GetCurrentProcessId(); +} + +LPVOID VDConvertThreadToFiberW32(LPVOID parm) { + typedef LPVOID (WINAPI *tpConvertThreadToFiber)(LPVOID p); + static tpConvertThreadToFiber ctof = (tpConvertThreadToFiber)GetProcAddress(GetModuleHandle("kernel32"), "ConvertThreadToFiber"); + + if (!ctof) + return NULL; + + return ctof(parm); +} + +void VDSwitchToFiberW32(LPVOID fiber) { + typedef void (WINAPI *tpSwitchToFiber)(LPVOID p); + static tpSwitchToFiber stof = (tpSwitchToFiber)GetProcAddress(GetModuleHandle("kernel32"), "SwitchToFiber"); + + if (stof) + stof(fiber); +} + +int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr) { + int palents = 0; + + if ((pHdr->biCompression == BI_RGB || pHdr->biCompression == BI_RLE4 || pHdr->biCompression == BI_RLE8) && pHdr->biBitCount <= 8) { + palents = pHdr->biClrUsed; + if (!palents) + palents = 1 << pHdr->biBitCount; + } + int size = pHdr->biSize + palents * sizeof(RGBQUAD); + + if (pHdr->biSize < sizeof(BITMAPV4HEADER) && pHdr->biCompression == BI_BITFIELDS) + size += sizeof(DWORD) * 3; + + return size; +} + +void VDSetWindowTextW32(HWND hwnd, const wchar_t *s) { + if (VDIsWindowsNT()) { + SetWindowTextW(hwnd, s); + } else { + SetWindowTextA(hwnd, VDTextWToA(s).c_str()); + } +} + +void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...) { + va_list val; + + va_start(val, format); + { + wchar_t buf[512]; + int r = vdvswprintf(buf, 512, format, val); + + if ((unsigned)r < 512) { + VDSetWindowTextW32(hwnd, buf); + va_end(val); + return; + } + } + + VDStringW s; + s.append_vsprintf(format, val); + VDSetWindowTextW32(hwnd, s.c_str()); + + va_end(val); +} + +VDStringA VDGetWindowTextAW32(HWND hwnd) { + char buf[512]; + + int len = GetWindowTextLengthA(hwnd); + + if (len > 511) { + vdblock tmp(len + 1); + len = GetWindowTextA(hwnd, tmp.data(), tmp.size()); + + const char *s = tmp.data(); + VDStringA text(s, s+len); + return text; + } else if (len > 0) { + len = GetWindowTextA(hwnd, buf, 512); + + return VDStringA(buf, buf + len); + } + + return VDStringA(); +} + +VDStringW VDGetWindowTextW32(HWND hwnd) { + union { + wchar_t w[256]; + char a[512]; + } buf; + + if (VDIsWindowsNT()) { + int len = GetWindowTextLengthW(hwnd); + + if (len > 255) { + vdblock tmp(len + 1); + len = GetWindowTextW(hwnd, tmp.data(), tmp.size()); + + VDStringW text(tmp.data(), len); + return text; + } else if (len > 0) { + len = GetWindowTextW(hwnd, buf.w, 256); + + VDStringW text(buf.w, len); + return text; + } + } else { + int len = GetWindowTextLengthA(hwnd); + + if (len > 511) { + vdblock tmp(len + 1); + len = GetWindowTextA(hwnd, tmp.data(), tmp.size()); + + VDStringW text(VDTextAToW(tmp.data(), len)); + return text; + } else if (len > 0) { + len = GetWindowTextA(hwnd, buf.a, 512); + + VDStringW text(VDTextAToW(buf.a, len)); + return text; + } + } + + return VDStringW(); +} + +void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text){ + if (VDIsWindowsNT()) { + AppendMenuW(hmenu, flags, id, text); + } else { + AppendMenuA(hmenu, flags, id, VDTextWToA(text).c_str()); + } +} + +bool VDAppendPopupMenuW32(HMENU hmenu, UINT flags, HMENU hmenuPopup, const wchar_t *text){ + flags |= MF_POPUP; + + if (VDIsWindowsNT()) + return 0 != AppendMenuW(hmenu, flags, (UINT_PTR)hmenuPopup, text); + else + return 0 != AppendMenuA(hmenu, flags, (UINT_PTR)hmenuPopup, VDTextWToA(text).c_str()); +} + +void VDAppendMenuSeparatorW32(HMENU hmenu) { + int pos = GetMenuItemCount(hmenu); + if (pos < 0) + return; + + if (VDIsWindowsNT()) { + MENUITEMINFOW mmiW; + vdfastfixedvector bufW; + + mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; + mmiW.fMask = MIIM_TYPE; + mmiW.fType = MFT_SEPARATOR; + + InsertMenuItemW(hmenu, pos, TRUE, &mmiW); + } else { + MENUITEMINFOA mmiA; + + mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; + mmiA.fMask = MIIM_TYPE; + mmiA.fType = MFT_SEPARATOR; + + InsertMenuItemA(hmenu, pos, TRUE, &mmiA); + } +} + +void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) { + CheckMenuItem(hmenu, pos, checked ? MF_BYPOSITION|MF_CHECKED : MF_BYPOSITION|MF_UNCHECKED); +} + +void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { + CheckMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED); +} + +void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) { + MENUITEMINFOA mii; + + mii.cbSize = sizeof(MENUITEMINFOA); + mii.fMask = MIIM_FTYPE | MIIM_STATE; + if (GetMenuItemInfo(hmenu, pos, TRUE, &mii)) { + mii.fType |= MFT_RADIOCHECK; + mii.fState &= ~MFS_CHECKED; + if (checked) + mii.fState |= MFS_CHECKED; + SetMenuItemInfo(hmenu, pos, TRUE, &mii); + } +} + +void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { + MENUITEMINFOA mii; + + mii.cbSize = sizeof(MENUITEMINFOA); + mii.fMask = MIIM_FTYPE | MIIM_STATE; + if (GetMenuItemInfo(hmenu, cmd, FALSE, &mii)) { + mii.fType |= MFT_RADIOCHECK; + mii.fState &= ~MFS_CHECKED; + if (checked) + mii.fState |= MFS_CHECKED; + SetMenuItemInfo(hmenu, cmd, FALSE, &mii); + } +} + +void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { + EnableMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_ENABLED : MF_BYCOMMAND|MF_GRAYED); +} + +VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd) { + VDStringW s; + + if (VDIsWindowsNT()) { + MENUITEMINFOW mmiW; + vdfastfixedvector bufW; + + mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; + mmiW.fMask = MIIM_TYPE; + mmiW.fType = MFT_STRING; + mmiW.dwTypeData = NULL; + mmiW.cch = 0; // required to avoid crash on NT4 + + if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) { + bufW.resize(mmiW.cch + 1, 0); + ++mmiW.cch; + mmiW.dwTypeData = bufW.data(); + + if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) + s = bufW.data(); + } + } else { + MENUITEMINFOA mmiA; + vdfastfixedvector bufA; + + mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; + mmiA.fMask = MIIM_TYPE; + mmiA.fType = MFT_STRING; + mmiA.dwTypeData = NULL; + + if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) { + bufA.resize(mmiA.cch + 1, 0); + ++mmiA.cch; + mmiA.dwTypeData = bufA.data(); + + if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) + s = VDTextAToW(bufA.data()); + } + } + + return s; +} + +void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text) { + if (VDIsWindowsNT()) { + MENUITEMINFOW mmiW; + + mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; + mmiW.fMask = MIIM_TYPE; + mmiW.fType = MFT_STRING; + mmiW.dwTypeData = (LPWSTR)text; + + SetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW); + } else { + MENUITEMINFOA mmiA; + VDStringA textA(VDTextWToA(text)); + + mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; + mmiA.fMask = MIIM_TYPE; + mmiA.fType = MFT_STRING; + mmiA.dwTypeData = (LPSTR)textA.c_str(); + + SetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA); + } +} + +LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + return (IsWindowUnicode(hwnd) ? CallWindowProcW : CallWindowProcA)(wp, hwnd, msg, wParam, lParam); +} + +LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, msg, wParam, lParam) : DefWindowProcA(hwnd, msg, wParam, lParam); +} + +EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags) { + EXECUTION_STATE es = 0; + + // SetThreadExecutionState(): requires Windows 98+/2000+. + typedef EXECUTION_STATE (WINAPI *tSetThreadExecutionState)(EXECUTION_STATE); + static tSetThreadExecutionState pFunc = (tSetThreadExecutionState)GetProcAddress(GetModuleHandle("kernel32"), "SetThreadExecutionState"); + + if (pFunc) + es = pFunc(esFlags); + + return es; +} + +bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod) { + LONG posHi = (LONG)(pos >> 32); + DWORD result = SetFilePointer(h, (LONG)pos, &posHi, dwMoveMethod); + + if (result != INVALID_SET_FILE_POINTER) + return true; + + DWORD dwError = GetLastError(); + + return (dwError == NO_ERROR); +} + +bool VDGetFileSizeW32(HANDLE h, sint64& size) { + DWORD dwSizeHigh; + DWORD dwSizeLow = GetFileSize(h, &dwSizeHigh); + + if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) + return false; + + size = dwSizeLow + ((sint64)dwSizeHigh << 32); + return true; +} + +#if !defined(_MSC_VER) || _MSC_VER < 1300 +HMODULE VDGetLocalModuleHandleW32() { + MEMORY_BASIC_INFORMATION meminfo; + static HMODULE shmod = (VirtualQuery((HINSTANCE)&VDGetLocalModuleHandleW32, &meminfo, sizeof meminfo), (HMODULE)meminfo.AllocationBase); + + return shmod; +} +#endif + +bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat) { + RECT r; + if (VDIsWindowsNT()) { + // If multiline and vcentered (not normally supported...) + if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) { + uFormat &= ~DT_VCENTER; + + r = *lpRect; + if (!DrawTextW(hdc, s, nCount, &r, uFormat | DT_CALCRECT)) + return false; + + int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1; + int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1; + + r.left += dx; + r.right += dx; + r.top += dy; + r.bottom += dy; + lpRect = &r; + } + + return !!DrawTextW(hdc, s, nCount, lpRect, uFormat); + } else { + VDStringA strA(VDTextWToA(s, nCount)); + + // If multiline and vcentered (not normally supported...) + if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) { + uFormat &= ~DT_VCENTER; + + r = *lpRect; + if (!DrawTextA(hdc, strA.data(), strA.size(), &r, uFormat | DT_CALCRECT)) + return false; + + int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1; + int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1; + + r.left += dx; + r.right += dx; + r.top += dy; + r.bottom += dy; + lpRect = &r; + } + + return !!DrawTextA(hdc, strA.data(), strA.size(), lpRect, uFormat); + } +} + +bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) { + char *pBase = (char *)hmod; + + vd_seh_guard_try { + // The PEheader offset is at hmod+0x3c. Add the size of the optional header + // to step to the section headers. + + const uint32 peoffset = ((const long *)pBase)[15]; + const uint32 signature = *(uint32 *)(pBase + peoffset); + + if (signature != IMAGE_NT_SIGNATURE) + return false; + + const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4); + + // Verify the PE optional structure. + + if (pHeader->SizeOfOptionalHeader < 104) + return false; + + // Find import header. + + const IMAGE_IMPORT_DESCRIPTOR *pImportDir; + int nImports; + + switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) { + +#ifdef _M_AMD64 + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + { + const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); + + if (pOpt->NumberOfRvaAndSizes < 2) + return false; + + pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); + } + break; +#else + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + { + const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); + + if (pOpt->NumberOfRvaAndSizes < 2) + return false; + + pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); + } + break; +#endif + + default: // reject PE32+ + return false; + } + + // Hmmm... no imports? + + if ((const char *)pImportDir == pBase) + return false; + + // Scan down the import entries. We are looking for MSVFW32. + + int i; + + for(i=0; i= nImports) + return false; + + // Found it. Start scanning MSVFW32 imports until we find DrawDibDraw. + + const long *pImports = (const long *)(pBase + pImportDir[i].OriginalFirstThunk); + void * volatile *pVector = (void * volatile *)(pBase + pImportDir[i].FirstThunk); + + while(*pImports) { + if (*pImports >= 0) { + const char *pName = pBase + *pImports + 2; + + if (!strcmp(pName, name)) { + + // Found it! Reset the protection. + + DWORD dwOldProtect; + + if (VirtualProtect((void *)pVector, sizeof(void *), PAGE_EXECUTE_READWRITE, &dwOldProtect)) { + if (ppOldValue) { + for(;;) { + void *old = *pVector; + if (pCompareValue && pCompareValue != old) + return false; + + *ppOldValue = old; + if (old == VDAtomicCompareExchangePointer(pVector, pNewValue, old)) + break; + } + } else { + *pVector = pNewValue; + } + + VirtualProtect((void *)pVector, sizeof(void *), dwOldProtect, &dwOldProtect); + + return true; + } + + break; + } + } + + ++pImports; + ++pVector; + } + } vd_seh_guard_except { + } + + return false; +} + +bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) { + char *pBase = (char *)hmod; + + vd_seh_guard_try { + // The PEheader offset is at hmod+0x3c. Add the size of the optional header + // to step to the section headers. + + const uint32 peoffset = ((const long *)pBase)[15]; + const uint32 signature = *(uint32 *)(pBase + peoffset); + + if (signature != IMAGE_NT_SIGNATURE) + return false; + + const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4); + + // Verify the PE optional structure. + + if (pHeader->SizeOfOptionalHeader < 104) + return false; + + // Find export directory. + + const IMAGE_EXPORT_DIRECTORY *pExportDir; + + switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) { + +#ifdef _M_AMD64 + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + { + const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); + + if (pOpt->NumberOfRvaAndSizes < 1) + return false; + + DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + + if (!exportDirRVA) + return false; + + pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA); + } + break; +#else + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + { + const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); + + if (pOpt->NumberOfRvaAndSizes < 1) + return false; + + DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + + if (!exportDirRVA) + return false; + + pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA); + } + break; +#endif + + default: // reject PE32+ + return false; + } + + // Scan for the export name. + DWORD nameCount = pExportDir->AddressOfNames; + const DWORD *nameRVAs = (const DWORD *)(pBase + pExportDir->AddressOfNames); + const WORD *nameOrdinals = (const WORD *)(pBase + pExportDir->AddressOfNameOrdinals); + DWORD *functionTable = (DWORD *)(pBase + pExportDir->AddressOfFunctions); + + for(DWORD i=0; i pathW(MAX_PATH, 0); + + size_t len = GetSystemDirectoryW(pathW.data(), MAX_PATH); + + if (!len) + return NULL; + + if (len > MAX_PATH) { + pathW.resize(len + 1, 0); + + len = GetSystemDirectoryW(pathW.data(), len); + if (!len || len >= pathW.size()) + return NULL; + } + + pathW.resize(len); + + if (pathW.back() != '\\') + pathW.push_back('\\'); + + while(const char c = *name++) + pathW.push_back(c); + + pathW.push_back(0); + + return LoadLibraryW(pathW.data()); + } else { + vdfastvector pathA(MAX_PATH, 0); + size_t len = GetSystemDirectoryA(pathA.data(), MAX_PATH); + + if (!len) + return NULL; + + if (len > MAX_PATH) { + pathA.resize(len + 1, 0); + + len = GetSystemDirectoryA(pathA.data(), len); + if (!len || len >= pathA.size()) + return NULL; + } + + pathA.resize(len); + + if (pathA.back() != '\\') + pathA.push_back('\\'); + + pathA.insert(pathA.end(), name, name + strlen(name)); + pathA.push_back(0); + + return LoadLibraryA(pathA.data()); + } +} diff --git a/src/thirdparty/VirtualDub/system/system.vcxproj b/src/thirdparty/VirtualDub/system/system.vcxproj index 367d112cb60..d6851c64287 100644 --- a/src/thirdparty/VirtualDub/system/system.vcxproj +++ b/src/thirdparty/VirtualDub/system/system.vcxproj @@ -1,178 +1,178 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {C2082189-3ECB-4079-91FA-89D3C8A305C0} - system - system - - - - - StaticLibrary - MultiByte - - - - - - - - - - - - - - ..\h;h;%(AdditionalIncludeDirectories) - _LIB;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - - - Winmm.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - NotUsing - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {C2082189-3ECB-4079-91FA-89D3C8A305C0} + system + system + + + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + ..\h;h;%(AdditionalIncludeDirectories) + _LIB;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Winmm.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + NotUsing + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/system/system.vcxproj.filters b/src/thirdparty/VirtualDub/system/system.vcxproj.filters index 255c87dcbe4..57366dfa8d8 100644 --- a/src/thirdparty/VirtualDub/system/system.vcxproj.filters +++ b/src/thirdparty/VirtualDub/system/system.vcxproj.filters @@ -1,332 +1,332 @@ - - - - - {5c673951-5083-408a-a3de-a63babf1344b} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {75631612-a2f0-4a60-80e8-cd36f92f4a73} - h;hpp;hxx;hm;inl - - - {0d0e6712-502c-46f9-b0e5-e14256cf6143} - - - {f8e51076-77af-4e45-90bf-adf37a8929fc} - asm - - - {710e4e94-dd20-48a6-8e4d-8c9b28bb7584} - - - {811fdd7e-ea30-44c3-8790-87fb8cd7109f} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Precompiled Header Support - - - Precompiled Header Support - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\win32 - - - Header Files\win32 - - - Precompiled Header Support - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Assembly Files %28x86%29 - - - Assembly Files %28x86%29 - - - Assembly Files %28AMD64%29 - - - Assembly Files %28AMD64%29 - - - Assembly Files %28AMD64%29 - - - Assembly Files %28AMD64%29 - - + + + + + {5c673951-5083-408a-a3de-a63babf1344b} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {75631612-a2f0-4a60-80e8-cd36f92f4a73} + h;hpp;hxx;hm;inl + + + {0d0e6712-502c-46f9-b0e5-e14256cf6143} + + + {f8e51076-77af-4e45-90bf-adf37a8929fc} + asm + + + {710e4e94-dd20-48a6-8e4d-8c9b28bb7584} + + + {811fdd7e-ea30-44c3-8790-87fb8cd7109f} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Precompiled Header Support + + + Precompiled Header Support + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\win32 + + + Header Files\win32 + + + Precompiled Header Support + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Assembly Files %28x86%29 + + + Assembly Files %28x86%29 + + + Assembly Files %28AMD64%29 + + + Assembly Files %28AMD64%29 + + + Assembly Files %28AMD64%29 + + + Assembly Files %28AMD64%29 + + \ No newline at end of file diff --git a/src/thirdparty/XeScrollBar/XeScrollBarBase.cpp b/src/thirdparty/XeScrollBar/XeScrollBarBase.cpp index 52d17e3fb1c..19dd70daa4a 100755 --- a/src/thirdparty/XeScrollBar/XeScrollBarBase.cpp +++ b/src/thirdparty/XeScrollBar/XeScrollBarBase.cpp @@ -1,1430 +1,1430 @@ -///////////////////////////////////////////////////////////////////////////////////////// -// XeScrollBarBase.cpp Version 1.1 -// This class is designed as a base class for another class that will -// do all painting. This class handles all business logic. No painting -// is done in this class - except in debug mode. -// -// Author: Snorri Kristjansson -// snorrikris@gmail.com -// -// History -// Version 1.1 - 2010 October 21 -// - Changed base class to CScrollBar (was CWnd). -// - Fixed many issues to make this scroll bar behave (almost) the same as windows -// scroll bar. -// -// Version 1.0 - 2009 -// - Never released. -// -// Acknowledgements: -// Thanks to Hans Dietrich for his CXScrollBar class, -// which I used as the starting point for CXeScrollBarBase: -// http://www.codeproject.com/KB/miscctrl/XScrollBar.aspx -// (I don't think any of his code survived into this version - but thanks all the same). -// -// License: -// This software is released into the public domain. You are free to use -// it in any way you like, except that you may not sell this source code. -// -// This software is provided "as is" with no expressed or implied warranty. -// I accept no liability for any damage or loss of business that this -// software may cause. -// -///////////////////////////////////////////////////////////////////////////////////////// - -/**************************************************************************************** -TODO: - H Mouse wheel support (L/R wheel push) - WM_MOUSEHWHEEL (new message Vista and later). - - Change code to pure WIN32 - no MFC - use as base base class for CXeScrollBarBase. -****************************************************************************************/ - -#include "stdafx.h" -#include "XeScrollBarBase.h" - -/**************************************************************************************** -Research resources: - -Scroll bar MSDN WIN32 reference. -http://msdn.microsoft.com/en-us/library/bb787529(VS.85).aspx - -Scroll Bar Controls in Win32 -http://msdn.microsoft.com/en-us/library/ms997557.aspx - -How/why to handle WM_CANCELMODE message. -http://support.microsoft.com/kb/74548/en-us - -How/why to handle WM_GETDLGCODE message. -http://support.microsoft.com/kb/83302 - -Discussion about thumb size calculations and more (good one). -http://blogs.msdn.com/oldnewthing/archive/2009/09/21/9897553.aspx - -Discussion about thumb size calculations. -http://social.msdn.microsoft.com/forums/en-US/wpf/thread/415eacf6-481e-4ebd-a6b0-2953e851183d/ - -From the November 2001 issue of MSDN Magazine. -Understanding CControlView, Changing Scroll Bar Color in MFC Apps -by Paul DiLascia -http://msdn.microsoft.com/en-us/magazine/cc301457.aspx - -Handling Keyboard and Mouse Application Buttons in WTL -By Michael Dunn -http://www.codeproject.com/KB/wtl/WTLAppButtons.aspx - -XScrollBar - Scroll bar like Windows Media Player's -By Hans Dietrich -http://www.codeproject.com/KB/miscctrl/XScrollBar.aspx - -Developing a Custom Windows Scrollbar in MFC -By Don Metzler, DDJ June 01, 2003 -http://www.drdobbs.com/windows/184416659 - -SkinControls 1.1 - A journey in automating the skinning of Windows controls -by .dan.g. -http://www.codeproject.com/KB/library/SkinCtrl.aspx - -Custom Scrollbar Library version 1.1 -by James Brown -http://www.codeproject.com/KB/dialog/coolscroll.aspx - -Replace a Window's Internal Scrollbar with a customdraw scrollbar Control -By flyhigh -http://www.codeproject.com/KB/dialog/skinscrollbar.aspx -****************************************************************************************/ - -double fabs_dbl( double dbl ) -{ - if( dbl >= 0 ) - return dbl; - return (-dbl); -} - -// Round a double number up or down. -int round_ud_dbl( double dbl ) -{ - BOOL bNeg = FALSE; - if( dbl < 0 ) - { - bNeg = TRUE; - dbl = -dbl; - } - int n = (int)dbl; - double fract = dbl - (double)n; - if( fract > 0.5 ) - n++; - if( bNeg ) - n = -n; - return n; -} - -/////////////////////////////////////////////////////////////////////////// -// CXeScrollBarBase - -#define XESCROLLBARWND_CLASSNAME _T("XeScrollBarWndClass") // Window class name - -#define XSB_LBTN_DOWN_TIMERID 1001 -#define XSB_LBTN_DOWN_TIME 200 // mS - time to first auto repeat. -#define XSB_LBTN_REPT_TIMERID 1002 -#define XSB_LBTN_REPT_TIME 50 // mS - repeat interval. -#define XSB_FOCUS_TIMERID 1003 -#define XSB_FOCUS_TIME 500 // mS - blink 'gripper' interval. - -// Menu ID's - Note: same ID's as menu from user32.dll. -#define XSB_IDM_SCRHERE 4100 // Scroll Here Scroll Here -#define XSB_IDM_SCR_TL 4102 // Top Left Edge -#define XSB_IDM_SCR_BR 4103 // Bottom Right Edge -#define XSB_IDM_SCR_PG_UL 4098 // Page Up Page Left -#define XSB_IDM_SCR_PG_DR 4099 // Page Down Page Right -#define XSB_IDM_SCR_UL 4096 // Scroll Up Scroll Left -#define XSB_IDM_SCR_DR 4097 // Scroll Down Scroll Right - - -IMPLEMENT_DYNAMIC(CXeScrollBarBase, CScrollBar) - -BEGIN_MESSAGE_MAP(CXeScrollBarBase, CScrollBar) - ON_MESSAGE(SBM_ENABLE_ARROWS, OnSbmEnableArrows) - ON_MESSAGE(SBM_GETPOS, OnSbmGetPos) - ON_MESSAGE(SBM_GETRANGE, OnSbmGetRange) - ON_MESSAGE(SBM_GETSCROLLBARINFO, OnSbmGetScrollBarInfo) - ON_MESSAGE(SBM_GETSCROLLINFO, OnSbmGetScrollInfo) - ON_MESSAGE(SBM_SETPOS, OnSbmSetPos) - ON_MESSAGE(SBM_SETRANGE, OnSbmSetRange) - ON_MESSAGE(SBM_SETRANGEREDRAW, OnSbmSetRangeRedraw) - ON_MESSAGE(SBM_SETSCROLLINFO, OnSbmSetScrollInfo) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_MESSAGE(WM_KEYDOWN, OnKeyDown) - ON_MESSAGE(WM_KEYUP, OnKeyUp) - ON_WM_LBUTTONDOWN() - ON_WM_LBUTTONUP() - ON_WM_MOUSEMOVE() - ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) - ON_MESSAGE(WM_GETDLGCODE, OnGetDlgCode) - ON_WM_CANCELMODE() - ON_WM_CONTEXTMENU() - ON_COMMAND_RANGE(XSB_IDM_SCR_UL,XSB_IDM_SCR_BR,OnMenuCommands) - ON_WM_TIMER() - ON_WM_SIZE() - ON_WM_SETFOCUS() - ON_WM_KILLFOCUS() - ON_WM_ENABLE() - ON_WM_MOUSEWHEEL() -END_MESSAGE_MAP() - -CXeScrollBarBase::CXeScrollBarBase() -{ - m_pParent = 0; - m_bEnabled = m_bHorizontal = m_bDrawGripper = TRUE; - m_bHasFocus = FALSE; - m_bNoScroll = m_bDragging = m_bTrackMouseLeave = m_bNeedEndScroll = FALSE; - m_nPos = m_nTrackPos = m_nMinPos = m_nMaxPos = m_nMaxReportedPos = 0; - m_uPage = 1; - m_rectClient.SetRectEmpty(); - m_rectThumb.SetRectEmpty(); - m_rectTLArrow.SetRectEmpty(); - m_rectBRArrow.SetRectEmpty(); - m_rectTLChannel.SetRectEmpty(); - m_rectBRChannel.SetRectEmpty(); - m_uArrowWH = 0; - m_uThumbMinHW = 8; // Minimum thumb width or height - m_dblPx_SU = 0; - m_ptMenu.SetPoint(0,0); - m_xyThumbDragOffset = 0; - if (!SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0)) { //added to support multiple rows per mouse notch - scrollLines = 3; - } -} - -CXeScrollBarBase::~CXeScrollBarBase() -{ - // Note - base class dtor (CScrollBar) calls DestroyWindow(). -} - -BOOL CXeScrollBarBase::Create( DWORD dwStyle, const RECT& rect, CWnd *pParentWnd, UINT nID ) -{ - if( !RegisterWindowClass() ) - return FALSE; - - ASSERT(pParentWnd); - ASSERT(IsWindow(pParentWnd->m_hWnd)); - m_pParent = pParentWnd; - - m_bHorizontal = ( dwStyle & SBS_VERT ) ? FALSE : TRUE; - // Note - SBS_HORZ is defined as 0 in winuser.h. - - m_bEnabled = ( dwStyle & WS_DISABLED ) ? FALSE : TRUE; - - BOOL bResult = CWnd::Create( XESCROLLBARWND_CLASSNAME, 0, dwStyle, rect, - pParentWnd, nID ); - - if( bResult ) - { - RecalcRects(); - } - else - { - TRACE(_T("ERROR - failed to create %s\n"),XESCROLLBARWND_CLASSNAME); - ASSERT(FALSE); - } - - return bResult; - - // Note - We DO NOT call base class (CScrollBar) because CScrollBar creates 'normal' - // windows scrollbar. -} - -BOOL CXeScrollBarBase::CreateFromExisting( CWnd *pParentWnd, UINT nID, - BOOL bUseDefaultWH /*= TRUE*/ ) -{ - ASSERT(pParentWnd); - HWND hWndParent = pParentWnd->GetSafeHwnd(); - if( !::IsWindow( hWndParent ) ) - { - ASSERT(FALSE); - return FALSE; - } - HWND hWndExistingSB = ::GetDlgItem( hWndParent, nID ); - if( !hWndExistingSB ) - { - ASSERT(FALSE); - return FALSE; - } - - DWORD dwStyle = ::GetWindowLong( hWndExistingSB, GWL_STYLE ); - - RECT rect; - ::GetWindowRect( hWndExistingSB, &rect ); - ::ScreenToClient( hWndParent, (LPPOINT)&rect ); - ::ScreenToClient( hWndParent, ((LPPOINT)&rect) + 1 ); - if( bUseDefaultWH ) - { // Set width or height to system standard scroll bar width/height. - if( dwStyle & SBS_VERT ) - { - // Get width of 'sys' vert. SB. - int cxSysSbV = ::GetSystemMetrics( SM_CXVSCROLL ); - rect.right = rect.left + cxSysSbV; // Set width of vert. SB to 'normal'. - } - else - { - // Get height of 'sys' horz. SB. - int cySysSbH = ::GetSystemMetrics( SM_CYHSCROLL ); - rect.bottom = rect.top + cySysSbH; // Set height of horz. SB to 'normal'. - } - } - - // Get current range, page and position from existing scrollbar. - SCROLLINFO info; - info.cbSize = sizeof(SCROLLINFO); - info.fMask = SIF_ALL; - ::SendMessage( hWndExistingSB, SBM_GETSCROLLINFO, 0, (LPARAM)&info ); - - // Create new scroll bar of 'this' type. Note - Control ID = 0 until old SB destroyed. - if( !Create( dwStyle, rect, pParentWnd, 0 ) ) - return FALSE; - - // Note - new scroll bar is now the last window in our parent window child Z-order. - - HWND hWndNewSB = GetSafeHwnd(); - ASSERT(hWndNewSB); - - // Set Z-order of new scroll bar - insert after the existing scroll bar. - ::SetWindowPos( hWndNewSB, hWndExistingSB, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); - - // Destroy existing (old) scroll bar. - ::DestroyWindow( hWndExistingSB ); - - // Set Control ID of new scroll bar. - ::SetWindowLong( hWndNewSB, GWL_ID, nID ); - - // Set range, page and position parameters in scroll bar. - SetScrollInfo( &info ); - - return TRUE; -} - -BOOL CXeScrollBarBase::RegisterWindowClass() -{ - WNDCLASS wndcls; - HINSTANCE hInst = AfxGetInstanceHandle(); - - // 'Our' class already registered? - if( !(::GetClassInfo( hInst, XESCROLLBARWND_CLASSNAME, &wndcls )) ) - { // Otherwise we need to register a new class - wndcls.style = CS_HREDRAW | CS_VREDRAW; - // Note - CS_DBLCLKS style not used so don't need to - // process WM_LBUTTONDBLCLK message. - wndcls.lpfnWndProc = ::DefWindowProc; - wndcls.cbClsExtra = wndcls.cbWndExtra = 0; - wndcls.hInstance = hInst; - wndcls.hIcon = NULL; - wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); - wndcls.hbrBackground = NULL; - wndcls.lpszMenuName = NULL; - wndcls.lpszClassName = XESCROLLBARWND_CLASSNAME; - - if( !AfxRegisterClass( &wndcls ) ) - { - TRACE(_T("Register window class %s failed\n"),XESCROLLBARWND_CLASSNAME); - ASSERT(FALSE); - AfxThrowResourceException(); - return FALSE; - } - } - return TRUE; -} - -void CXeScrollBarBase::DrawScrollBar( CDC* pDC ) -{ - // Draw scrollbar as solid color rects - in debug mode ONLY! -#ifdef _DEBUG -#define X_GRBTN RGB(140,140,140) -#define X_GRCH RGB(180,180,180) -#define X_GRTHM RGB(96,96,96) -#define X_NRMBT RGB(128,0,128) -#define X_NRMCH RGB(128,128,0) -#define X_NRMTH RGB(0,192,0) -#define X_HOTBT RGB(192,0,192) -#define X_HOTCH RGB(192,192,0) -#define X_HOTTH RGB(0,255,0) -#define X_DWNBT (~X_NRMBT & 0xFFFFFF) -#define X_DWNCH (~X_NRMCH & 0xFFFFFF) -#define X_DWNTH (~X_NRMTH & 0xFFFFFF) - COLORREF rgbarr[5][6] = { -// eNone eTLbutton eBRbutton eTLchannel eBRchannel eThumb -// 0 1 2 3 4 5 - { 0, 0, 0, 0, 0, 0 }, // 0 eNotDrawn - { 0, X_GRBTN, X_GRBTN, X_GRCH, X_GRCH, X_GRTHM }, // 1 eDisabled - { 0, X_NRMBT, X_NRMBT, X_NRMCH, X_NRMCH, X_NRMTH }, // 2 eNormal - { 0, X_DWNBT, X_DWNBT, X_DWNCH, X_DWNCH, X_DWNTH }, // 3 eDown - { 0, X_HOTBT, X_HOTBT, X_HOTCH, X_HOTCH, X_HOTTH } // 4 eHot - }; - XSB_EDRAWELEM eState; - const CRect *prcElem = 0; - for( int nElem = eTLbutton; nElem <= eThumb; nElem++ ) - { - prcElem = GetUIelementDrawState( (eXSB_AREA)nElem, eState ); - if( !prcElem || eState == eNotDrawn ) - continue; - COLORREF rgb = rgbarr[eState][nElem]; - pDC->FillSolidRect( prcElem, rgb ); - } -#endif -} - -// SBM_GETPOS message handler. -LRESULT CXeScrollBarBase::OnSbmGetPos( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - return m_nPos; -} - -// SBM_SETPOS message handler. -LRESULT CXeScrollBarBase::OnSbmSetPos( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - int nPos = (int)wparam; - BOOL bRedraw = (BOOL)lparam; - int nOldPos = m_nPos; - - m_nPos = nPos; - - if( m_nPos < m_nMinPos ) - m_nPos = m_nMinPos; - else if( m_nPos > m_nMaxReportedPos ) - m_nPos = m_nMaxReportedPos; - - if( m_bNoScroll && !m_bEnabled ) // SB disabled because of SIF_DISABLENOSCROLL? - { // SBM_SETPOS cancels SIF_DISABLENOSCROLL. - m_bNoScroll = FALSE; - EnableWindow( TRUE ); - } - - RecalcRects(); - - if( bRedraw ) - Invalidate(); - - return nOldPos; -} - -// SBM_GETRANGE message handler. -LRESULT CXeScrollBarBase::OnSbmGetRange( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - LPINT lpMinPos = (LPINT)wparam; - LPINT lpMaxPos = (LPINT)lparam; - *lpMinPos = m_nMinPos; - *lpMaxPos = m_nMaxPos; - return 0; -} - -// SBM_SETRANGE message handler. -LRESULT CXeScrollBarBase::OnSbmSetRange( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - int nMinPos = (int)wparam; - int nMaxPos = (int)lparam; - m_nMinPos = nMinPos; - m_nMaxPos = nMaxPos; - if( m_nMaxPos < m_nMinPos ) - m_nMaxPos = m_nMinPos; - int nSUrange = abs(m_nMaxPos - m_nMinPos) + 1; - if( m_uPage > (UINT)nSUrange ) - m_uPage = (UINT)nSUrange; - - if( m_uPage == 0 ) - m_nMaxReportedPos = m_nMaxPos; - else - m_nMaxReportedPos = m_nMaxPos - ((int)m_uPage - 1); - - int nOldPos = m_nPos; - if( m_nPos < m_nMinPos ) - m_nPos = m_nMinPos; - else if( m_nPos > m_nMaxReportedPos ) - m_nPos = m_nMaxReportedPos; - - if( m_bNoScroll && !m_bEnabled ) // SB disabled because of SIF_DISABLENOSCROLL? - { // SBM_SETRANGE cancels SIF_DISABLENOSCROLL. - m_bNoScroll = FALSE; - EnableWindow( TRUE ); - } - - RecalcRects(); - - if( nOldPos != m_nPos ) - return nOldPos; - return 0; -} - -// SBM_SETRANGEREDRAW message handler. -LRESULT CXeScrollBarBase::OnSbmSetRangeRedraw( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - LRESULT lResult = OnSbmSetRange( wparam, lparam ); - Invalidate(); - return lResult; -} - -// SBM_GETSCROLLINFO message handler. -LRESULT CXeScrollBarBase::OnSbmGetScrollInfo( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - LPSCROLLINFO lpScrollInfo = (LPSCROLLINFO)lparam; - if( lpScrollInfo->cbSize != sizeof(SCROLLINFO) ) - return FALSE; - lpScrollInfo->nMin = m_nMinPos; - lpScrollInfo->nMax = m_nMaxPos; - lpScrollInfo->nPage = m_uPage; - lpScrollInfo->nPos = m_nPos; - lpScrollInfo->nTrackPos = m_nTrackPos; - return TRUE; -} - -// SBM_SETSCROLLINFO message handler. -LRESULT CXeScrollBarBase::OnSbmSetScrollInfo( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - BOOL bRedraw = (BOOL)wparam; - LPSCROLLINFO lpScrollInfo = (LPSCROLLINFO)lparam; - if( lpScrollInfo->cbSize != sizeof(SCROLLINFO) ) - return 0; - if( lpScrollInfo->fMask & SIF_PAGE ) - { - m_uPage = lpScrollInfo->nPage; - // Note - windows scrollbars can have a page size = 0. - } - if( lpScrollInfo->fMask & SIF_RANGE ) - { - m_nMinPos = lpScrollInfo->nMin; - m_nMaxPos = lpScrollInfo->nMax; - } - if( lpScrollInfo->fMask & SIF_POS ) - { - m_nPos = lpScrollInfo->nPos; - } - if( lpScrollInfo->fMask & SIF_DISABLENOSCROLL ) - { - BOOL bEnable = ( (int)m_uPage < (m_nMaxPos - m_nMinPos) ) ? TRUE : FALSE; - m_bNoScroll = !bEnable; - EnableWindow( bEnable ); - } - - if( m_nMaxPos < m_nMinPos ) - m_nMaxPos = m_nMinPos; - int nSUrange = abs(m_nMaxPos - m_nMinPos) + 1; - if( m_uPage > (UINT)nSUrange ) - m_uPage = (UINT)nSUrange; - - if( m_uPage == 0 ) - m_nMaxReportedPos = m_nMaxPos; - else - m_nMaxReportedPos = m_nMaxPos - ((int)m_uPage - 1); - - if( m_nPos < m_nMinPos ) - m_nPos = m_nMinPos; - else if( m_nPos > m_nMaxReportedPos ) - m_nPos = m_nMaxReportedPos; - - RecalcRects(); - - if( bRedraw ) - Invalidate(); - - return m_nPos; -} - -// SBM_ENABLE_ARROWS message handler. -LRESULT CXeScrollBarBase::OnSbmEnableArrows( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - /* ImplNote - during testing the windows scrollbar behaved strangely when only one - button was disabled. For that reason only enable/disable both is supported here. */ - EnableWindow( ( wparam & ESB_DISABLE_BOTH ) ? FALSE : TRUE ); - // wParam Specifies whether the scroll bar arrows are enabled or disabled and - // indicates which arrows are enabled or disabled. - return TRUE; -} - -// SBM_GETSCROLLBARINFO message handler. -LRESULT CXeScrollBarBase::OnSbmGetScrollBarInfo( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - SCROLLBARINFO *psbi = (SCROLLBARINFO *)lparam; - if( !psbi || psbi->cbSize != sizeof(SCROLLBARINFO) ) - return FALSE; - - /* Note - information on how to implement this is a little sparse from MS. - Need make a few educated guesses. - Note - testing (comparing 'this' to WIN SBs) has shown that: - rcScrollBar is in screen coords. - dxyLineButton is arrow button width when horz. SB. - dxyLineButton is arrow button height when vert. SB. - */ - - psbi->rcScrollBar = m_rectClient; // Coordinates of the scroll bar. - ClientToScreen( &psbi->rcScrollBar ); // In screen coords. - - if( m_bHorizontal ) - { - psbi->dxyLineButton = m_rectTLArrow.Width();// arrow button width. - psbi->xyThumbTop = m_rectThumb.left; // Position of the left of the thumb. - psbi->xyThumbBottom = m_rectThumb.right; // Position of the right of the thumb. - } - else - { - psbi->dxyLineButton = m_rectTLArrow.Height();// arrow button height. - psbi->xyThumbTop = m_rectThumb.top; // Position of the top of the thumb. - psbi->xyThumbBottom = m_rectThumb.bottom; // Position of the bottom of the thumb. - } - - // psbi->rgstate - An array of DWORD elements. Each element indicates the state of a - // scroll bar component. The following values show the scroll bar component that - // corresponds to each array index. Index Scroll bar component - // 0 The scroll bar itself. - // 1 The top or right arrow button. - // 2 The page up or page right region. - // 3 The scroll box (thumb). - // 4 The page down or page left region. - // 5 The bottom or left arrow button. - DWORD dwState = ( m_bEnabled ) ? 0 : STATE_SYSTEM_UNAVAILABLE; - DWORD dwTLchSt = dwState, dwBRchSt = dwState, dwThumbSt = dwState; - DWORD dwTLbtnSt = dwState, dwBRbtnSt = dwState; - if( m_rectTLChannel.IsRectEmpty() ) - dwTLchSt |= STATE_SYSTEM_INVISIBLE; - if( m_rectBRChannel.IsRectEmpty() ) - dwBRchSt |= STATE_SYSTEM_INVISIBLE; - if( m_rectThumb.IsRectEmpty() ) - dwThumbSt |= STATE_SYSTEM_INVISIBLE; - if( m_eMouseDownArea.IsTLButton() ) - dwTLbtnSt |= STATE_SYSTEM_PRESSED; - if( m_eMouseDownArea.IsTLChannel() ) - dwTLchSt |= STATE_SYSTEM_PRESSED; - if( m_eMouseDownArea.IsThumb() ) - dwThumbSt |= STATE_SYSTEM_PRESSED; - if( m_eMouseDownArea.IsBRChannel() ) - dwBRchSt |= STATE_SYSTEM_PRESSED; - if( m_eMouseDownArea.IsBRButton() ) - dwBRbtnSt |= STATE_SYSTEM_PRESSED; - psbi->rgstate[0] = dwState; - psbi->rgstate[1] = dwTLbtnSt; - psbi->rgstate[2] = dwTLchSt; - psbi->rgstate[3] = dwThumbSt; - psbi->rgstate[4] = dwBRchSt; - psbi->rgstate[5] = dwBRbtnSt; - - // The DWORD element for each scroll bar component can include a combination of the - // following bit flags. - // STATE_SYSTEM_INVISIBLE - For the scroll bar itself, indicates the specified - // vertical or horizontal scroll bar does not exist. For the page up or page - // down regions, indicates the thumb is positioned such that the region does - // not exist. - // STATE_SYSTEM_OFFSCREEN - For the scroll bar itself, indicates the window is sized - // such that the specified vertical or horizontal scroll bar is not currently - // displayed. (SK note - applies to NC scroll bars only). - // STATE_SYSTEM_PRESSED - The arrow button or page region is pressed. - // STATE_SYSTEM_UNAVAILABLE - The component is disabled. - - return TRUE; -} - -void CXeScrollBarBase::OnPaint() -{ // WM_PAINT message handler. - ASSERT(::IsWindow(m_hWnd)); - CPaintDC dc(this); // device context for painting - - DrawScrollBar( &dc ); - // Do not call CScrollBar::OnPaint() for painting messages -} - -BOOL CXeScrollBarBase::OnEraseBkgnd( CDC* pDC ) -{ // WM_ERASEBKGND message handler. - return TRUE; // All painting done in OnPaint. -} - -LRESULT CXeScrollBarBase::OnKeyDown( WPARAM wParam, LPARAM lParam ) -{ // WM_KEYDOWN message handler. - ASSERT(::IsWindow(m_hWnd)); - WORD wSBcode = 0xFFFF; - // Note - SB_PAGELEFT == SB_PAGEUP etc. see winuser.h - switch( wParam ) - { - case VK_PRIOR: - wSBcode = SB_PAGELEFT; - break; - - case VK_NEXT: - wSBcode = SB_PAGERIGHT; - break; - - case VK_HOME: - wSBcode = SB_LEFT; - break; - - case VK_END: - wSBcode = SB_RIGHT; - break; - - case VK_LEFT: - wSBcode = SB_LINELEFT; - break; - - case VK_RIGHT: - wSBcode = SB_LINERIGHT; - break; - - case VK_UP: - wSBcode = SB_LINEUP; - break; - - case VK_DOWN: - wSBcode = SB_LINEDOWN; - break; - } - - if( wSBcode != 0xFFFF ) - { - SendScrollMsg( wSBcode ); - m_bNeedEndScroll = TRUE; // Send SB_ENDSCROLL on WM_KEYUP. - } - - return 0; // Indicate we processed this message (eat all key msgs). - // Note - testing shows that windows looks for another child control to process - // keyboard input if we don't return 0 here (and we lose focus). -} - -LRESULT CXeScrollBarBase::OnKeyUp( WPARAM wParam, LPARAM lParam ) -{ // WM_KEYUP message handler. - if( m_bNeedEndScroll ) - { - SendScrollMsg( SB_ENDSCROLL ); - m_bNeedEndScroll = FALSE; - } - return 0; // Indicate we processed this message (eat all key msgs). -} - -void CXeScrollBarBase::OnLButtonDown( UINT nFlags, CPoint point ) -{ // WM_LBUTTONDOWN message handler. - ASSERT(::IsWindow(m_hWnd)); - SetCapture(); - BOOL bHasTabStop = ( ::GetWindowLong( m_hWnd, GWL_STYLE ) & WS_TABSTOP ) ? TRUE : FALSE; - if( bHasTabStop ) - SetFocus(); // Only 'steal' focus if 'this' has Tab stop. - - m_eMouseDownArea = GetAreaFromPoint( point ); - - WORD wSBcode = 0xFFFF; - // Note - SB_PAGELEFT == SB_PAGEUP etc. see winuser.h - if( m_eMouseDownArea.eArea == eTLbutton ) - wSBcode = SB_LINELEFT; - else if( m_eMouseDownArea.eArea == eTLchannel ) - wSBcode = SB_PAGELEFT; - else if( m_eMouseDownArea.eArea == eBRchannel ) - wSBcode = SB_PAGERIGHT; - else if( m_eMouseDownArea.eArea == eBRbutton ) - wSBcode = SB_LINERIGHT; - - if( wSBcode != 0xFFFF ) - { - SendScrollMsg( wSBcode ); - m_bNeedEndScroll = TRUE; // Send SB_ENDSCROLL on WM_LBUTTONUP message. - } - - if( m_eMouseDownArea.IsThumb() ) // Store X or Y offset from thumb edge. - m_xyThumbDragOffset = ( m_bHorizontal ) ? point.x - m_rectThumb.left - : point.y - m_rectThumb.top; - - // Set timer for first auto repeat - when button or channel clicked. - if( m_eMouseDownArea.IsButton() || m_eMouseDownArea.IsChannel() ) - SetTimer( XSB_LBTN_DOWN_TIMERID, XSB_LBTN_DOWN_TIME, 0 ); - - CScrollBar::OnLButtonDown(nFlags, point); -} - -void CXeScrollBarBase::OnLButtonUp( UINT nFlags, CPoint point ) -{ // WM_LBUTTONUP message handler. - ASSERT(::IsWindow(m_hWnd)); - ReleaseCapture(); - KillTimer( XSB_LBTN_DOWN_TIMERID ); - KillTimer( XSB_LBTN_REPT_TIMERID ); - - m_eMouseDownArea = eNone; - - if( m_bDragging ) // Did we send any SB_THUMBTRACK messages? - { - SendScrollMsg( SB_THUMBPOSITION, (WORD)m_nTrackPos ); - m_bDragging = FALSE; - RecalcRects(); // Reset thumb pos. to current scroll pos. - } - - if( m_bNeedEndScroll ) - { - SendScrollMsg( SB_ENDSCROLL ); // Let parent know scrolling has ended. - m_bNeedEndScroll = FALSE; - } - - Invalidate(); - - CScrollBar::OnLButtonUp(nFlags, point); -} - -/* updated to newer api and reversing return value to avoid mousewheel propagating */ -/* remove restriction on vert scrollbar, as both are valid in win32 */ -BOOL CXeScrollBarBase::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { - ASSERT(::IsWindow(m_hWnd)); - //short xPos = pt.x; - //short yPos = pt.y; - - //if (!m_bHorizontal) // Mouse wheel messages only apply to vertical scrollbar. - //{ - WORD wSBcode = 0xFFFF; - if (zDelta >= WHEEL_DELTA) { - wSBcode = SB_LINEUP; - } else if (zDelta <= -WHEEL_DELTA) { - wSBcode = SB_LINEDOWN; - zDelta = -zDelta; - } - if (wSBcode != 0xFFFF) { - do { - for (UINT i=0; i= WHEEL_DELTA); - SendScrollMsg(SB_ENDSCROLL); - } - return 1; // Message was processed. (was 0, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 1 if scrolling enabled - //} - //return 0; // Message not processed. (was 1, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 0 if scrolling not enabled -} - - -void CXeScrollBarBase::OnMouseMove( UINT nFlags, CPoint point ) -{ // WM_MOUSEMOVE message handler. - ASSERT(::IsWindow(m_hWnd)); - if( !m_bTrackMouseLeave ) - { // We want a WM_MOUSELEAVE message when mouse leaves our client area. - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(tme); - tme.hwndTrack = m_hWnd; - tme.dwFlags = TME_LEAVE; - tme.dwHoverTime = 0; - - // Note - _TrackMouseEvent is from comctl32.dll - emulates TrackMouseEvent - // if it does not exist. - m_bTrackMouseLeave = _TrackMouseEvent( &tme ); - } - - stXSB_AREA eOldMouseArea = m_eMouseOverArea; - - m_eMouseOverArea = GetAreaFromPoint( point ); // Update mouse over area. - - if( m_eMouseDownArea.IsThumb() && m_dblPx_SU > 0 ) - { // User is dragging the thumb. - BOOL bStartDrag = FALSE; - if( !m_bDragging ) - { - bStartDrag = TRUE; // Start of thumb dragging. - m_bDragging = TRUE; - } - int nTrackPos; - double dblScrollPos; - if( m_bHorizontal ) - { // X pos of left edge of thumb (0...?) - int xPos = point.x - m_xyThumbDragOffset - m_rectTLArrow.right; - dblScrollPos = (double)xPos / m_dblPx_SU; - nTrackPos = round_ud_dbl( dblScrollPos ) + m_nMinPos; - } - else - { // Y pos of top edge of thumb (0...?) - int yPos = point.y - m_xyThumbDragOffset - m_rectTLArrow.bottom; - dblScrollPos = (double)yPos / m_dblPx_SU; - nTrackPos = round_ud_dbl( dblScrollPos ) + m_nMinPos; - } - if( nTrackPos < m_nMinPos ) - nTrackPos = m_nMinPos; - else if( nTrackPos > m_nMaxReportedPos ) - nTrackPos = m_nMaxReportedPos; - - //adipose: moved this block to before sending scroll message. otherwise scrollbar updates poorly on slower windows (listctrl) - //also call updatewindow to redraw immediately - // Recalculate thumb XY pos. and redraw if pos. changed. - if (RecalcRectsThumbTrack(point)) { - Invalidate(); - UpdateWindow(); - } - - if( bStartDrag || m_nTrackPos != nTrackPos ) - { // Send scroll message when user starts dragging - // OR when track pos has changed. - m_nTrackPos = nTrackPos; - SendScrollMsg( SB_THUMBTRACK, (WORD)m_nTrackPos ); - m_bNeedEndScroll = TRUE; - } - } - - if( m_eMouseOverArea != eOldMouseArea ) - Invalidate(); - - CScrollBar::OnMouseMove(nFlags, point); -} - -LRESULT CXeScrollBarBase::OnMouseLeave( WPARAM wparam, LPARAM lparam ) -{ // WM_MOUSELEAVE message handler. - ASSERT(::IsWindow(m_hWnd)); - m_bTrackMouseLeave = FALSE; - m_eMouseOverArea = eNone; - Invalidate(); - return 0; -} - -LRESULT CXeScrollBarBase::OnGetDlgCode( WPARAM wParam, LPARAM lParam ) -{ // WM_GETDLGCODE message handler. - ASSERT(::IsWindow(m_hWnd)); - BOOL bHasTabStop = ( ::GetWindowLong( m_hWnd, GWL_STYLE ) & WS_TABSTOP ) ? TRUE : FALSE; - - LRESULT lResult = Default(); - if( lParam ) // lParam points to an MSG structure? - { - LPMSG lpmsg = (LPMSG)lParam; - if( (lpmsg->message == WM_KEYDOWN // Keyboard input? - || lpmsg->message == WM_KEYUP) - && lpmsg->wParam != VK_TAB ) // AND NOT TAB key? - { - if( bHasTabStop ) // 'this' window has Tab stop? - { - lResult |= DLGC_WANTMESSAGE; // We want keyboard input (except TAB). - // Note - windows will set focus to 'this' (and send WM_SETFOCUS) - // if we return DLGC_WANTMESSAGE here. - } - else - { // 'this' windows does NOT have TAB stop. - // Note - windows standard scroll bar implements a special behaviour - // for scroll bars when no tab stop for the UP, DOWN, LEFT, RIGHT keys. - if( m_bHorizontal ) - { - if( lpmsg->wParam == VK_LEFT || lpmsg->wParam == VK_RIGHT ) - lResult |= DLGC_WANTMESSAGE; - } - else - { - if( lpmsg->wParam == VK_UP || lpmsg->wParam == VK_DOWN ) - lResult |= DLGC_WANTMESSAGE; - } - } - } - } - else - { - if( bHasTabStop ) - lResult |= DLGC_WANTTAB; // 'this' has WS_TABSTOP style - we want focus. - else - lResult |= DLGC_STATIC; // no tab stop - we don't want focus. - } - return lResult; -} - -void CXeScrollBarBase::OnCancelMode() -{ // WM_CANCELMODE message handler. - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnCancelMode(); - - // Need to handle WM_CANCELMODE message. - // See -> http://support.microsoft.com/kb/74548/en-us - - if( !m_eMouseDownArea.IsNone() ) // Mouse L button down? - OnLButtonUp( 0, CPoint(0,0) ); // Do L btn up processing now. -} - -void CXeScrollBarBase::OnContextMenu( CWnd* pWnd, CPoint point ) -{ // WM_CONTEXTMENU message handler. - ASSERT(::IsWindow(m_hWnd)); - - m_ptMenu = point; - ScreenToClient( &m_ptMenu ); - - // Try to load scroll bar menu from user32.dll - to get menu in 'local' language. - CString strDllPathName; - GetWindowsDirectory( strDllPathName.GetBuffer(MAX_PATH), MAX_PATH ); - strDllPathName.ReleaseBuffer(); - strDllPathName += _T("\\system32\\user32.dll"); - - HMODULE hUser32dllModule = ::LoadLibrary( strDllPathName ); - if( hUser32dllModule ) - { // Get menu #64 (horz.) or menu #80 (vert.) from user32.dll. - HMENU hMenu = 0, hSubMenu = 0; - if( m_bHorizontal ) - hMenu = ::LoadMenu( hUser32dllModule, MAKEINTRESOURCE(64) ); - else - hMenu = ::LoadMenu( hUser32dllModule, MAKEINTRESOURCE(80) ); - if( hMenu ) - { - hSubMenu = ::GetSubMenu( hMenu, 0 ); - if( hSubMenu ) - { - ::TrackPopupMenu( hSubMenu, TPM_LEFTALIGN, point.x, point.y, 0, - GetSafeHwnd(), 0 ); - // Note - TrackPopupMenu does not return until menu has been dismissed. - ::DestroyMenu( hMenu ); - } - } - ::FreeLibrary( hUser32dllModule ); - if( hSubMenu ) - return; // Using menu from user32.dll was successful. - } - - // If using menu from user32.dll was unsuccessful - create menu (in english). - CMenu menu; - menu.CreatePopupMenu(); - menu.AppendMenu( MF_STRING, XSB_IDM_SCRHERE, _T("Scroll Here") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - if( m_bHorizontal ) - { - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_TL, _T("Left Edge") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_BR, _T("Right Edge") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_UL, _T("Page Left") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_DR, _T("Page Right") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_UL, _T("Scroll Left") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_DR, _T("Scroll Right") ); - } - else - { - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_TL, _T("Top") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_BR, _T("Bottom") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_UL, _T("Page Up") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_DR, _T("Page Down") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_UL, _T("Scroll Up") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_DR, _T("Scroll Down") ); - } - menu.TrackPopupMenu( TPM_LEFTALIGN, point.x, point.y, pWnd ); - // Note - TrackPopupMenu does not return until menu has been dismissed. - menu.DestroyMenu(); -} - -void CXeScrollBarBase::OnMenuCommands( UINT uID ) -{ - ASSERT(::IsWindow(m_hWnd)); - int xyOfs, nScrollHerePos; - double dblScrollPos; - WORD wSBcode = 0xFFFF; - switch( uID ) - { - case XSB_IDM_SCRHERE: - // Calculate pos (in scroll units) - if( m_bHorizontal ) - xyOfs = m_ptMenu.x - m_rectTLArrow.right; - else - xyOfs = m_ptMenu.y - m_rectTLArrow.bottom; - if( xyOfs < 0 ) - xyOfs = 0; - if( m_rectThumb.IsRectEmpty() || !(m_dblPx_SU > 0) ) - break; // Can't 'Scroll Here'. - dblScrollPos = (double)xyOfs / m_dblPx_SU; - nScrollHerePos = m_nMinPos + round_ud_dbl( dblScrollPos ); - if( nScrollHerePos < m_nMinPos ) - nScrollHerePos = m_nMinPos; - else if( nScrollHerePos > m_nMaxReportedPos ) - nScrollHerePos = m_nMaxReportedPos; - m_nTrackPos = nScrollHerePos; - SendScrollMsg( SB_THUMBPOSITION, (WORD)m_nTrackPos ); - SendScrollMsg( SB_ENDSCROLL ); - break; - case XSB_IDM_SCR_TL: - wSBcode = SB_TOP; - break; - case XSB_IDM_SCR_BR: - wSBcode = SB_BOTTOM; - break; - case XSB_IDM_SCR_PG_UL: - wSBcode = SB_PAGEUP; - break; - case XSB_IDM_SCR_PG_DR: - wSBcode = SB_PAGEDOWN; - break; - case XSB_IDM_SCR_UL: - wSBcode = SB_LINEUP; - break; - case XSB_IDM_SCR_DR: - wSBcode = SB_LINEDOWN; - break; - } - if( wSBcode != 0xFFFF ) - { - SendScrollMsg( wSBcode ); - SendScrollMsg( SB_ENDSCROLL ); - } -} - -void CXeScrollBarBase::OnTimer( UINT_PTR nIDEvent ) -{ // WM_TIMER message handler. - ASSERT(::IsWindow(m_hWnd)); - if( nIDEvent == XSB_LBTN_DOWN_TIMERID ) - { // First auto repeat timer event. - KillTimer( XSB_LBTN_DOWN_TIMERID ); - SetTimer( XSB_LBTN_REPT_TIMERID, XSB_LBTN_REPT_TIME, 0 ); - } - if( nIDEvent == XSB_LBTN_DOWN_TIMERID || nIDEvent == XSB_LBTN_REPT_TIMERID ) - { // Auto repeat - CPoint ptCurMouse; - if( ::GetCursorPos( &ptCurMouse ) ) - { - ::ScreenToClient( GetSafeHwnd(), &ptCurMouse ); - m_eMouseOverArea = GetAreaFromPoint( ptCurMouse ); // Update mouse over area. - } - if( m_eMouseDownArea.IsTLButton() ) - { - if( m_eMouseOverArea.IsTLButton() ) // Mouse still over button? - SendScrollMsg( SB_LINELEFT ); - } - else if( m_eMouseDownArea.IsBRButton() ) - { - if( m_eMouseOverArea.IsBRButton() ) // Mouse still over button? - SendScrollMsg( SB_LINERIGHT ); - } - else if( m_eMouseDownArea.IsTLChannel() ) - { - if( m_eMouseOverArea.IsTLChannel() ) // Mouse still over channel? - SendScrollMsg( SB_PAGELEFT ); - } - else if( m_eMouseDownArea.IsBRChannel() ) - { - if( m_eMouseOverArea.IsBRChannel() ) // Mouse still over channel? - SendScrollMsg( SB_PAGERIGHT ); - } - // Note - SB_LINELEFT == SB_LINEUP etc. see winuser.h - } - if( nIDEvent == XSB_FOCUS_TIMERID ) - { // Blinking focus timer. - if( m_bNeedEndScroll ) - { // Draw normal thumb box while user is scrolling. - if( !m_bDrawGripper ) - { // Redraw scroll bar if currently drawn without 'gripper'. - m_bDrawGripper = TRUE; - Invalidate(); // Draw 'blinking' focus. - } - } - else - { // Draw blinking 'gripper' to indicate 'focus'. - m_bDrawGripper = !m_bDrawGripper; - Invalidate(); // Draw 'blinking' focus. - } - } - - CScrollBar::OnTimer( nIDEvent ); -} - -void CXeScrollBarBase::OnSize( UINT nType, int cx, int cy ) -{ // WM_SIZE message handler. - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnSize( nType, cx, cy ); - - if( m_hWnd ) - RecalcRects(); -} - -void CXeScrollBarBase::OnSetFocus( CWnd* pOldWnd ) -{ // WM_SETFOCUS message handler. - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnSetFocus( pOldWnd ); - m_bHasFocus = TRUE; - m_bDrawGripper = FALSE; - SetTimer( XSB_FOCUS_TIMERID, XSB_FOCUS_TIME, 0 ); - Invalidate(); -} - -void CXeScrollBarBase::OnKillFocus( CWnd* pNewWnd ) -{ // WM_KILLFOCUS message handler. - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnKillFocus( pNewWnd ); - m_bHasFocus = FALSE; - m_bDrawGripper = TRUE; - KillTimer( XSB_FOCUS_TIMERID ); - Invalidate(); -} - -void CXeScrollBarBase::OnEnable( BOOL bEnable ) -{ // WM_ENABLE message handler - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnEnable(bEnable); - - m_bEnabled = bEnable; - - RecalcRects(); // Need to recalc. because no thumb is shown when disabled. - - Invalidate(); -} - -void CXeScrollBarBase::SendScrollMsg( WORD wSBcode, WORD wHiWPARAM /*= 0*/ ) -{ - ASSERT(::IsWindow(m_hWnd)); - if( m_pParent && ::IsWindow( m_pParent->m_hWnd ) ) - { - m_pParent->SendMessage( ( m_bHorizontal ) ? WM_HSCROLL : WM_VSCROLL, - MAKELONG(wSBcode,wHiWPARAM), (LPARAM)m_hWnd ); - } -} - -eXSB_AREA CXeScrollBarBase::GetAreaFromPoint( CPoint point ) -{ - ASSERT(::IsWindow(m_hWnd)); - if( !m_rectClient.PtInRect( point ) ) - return eNone; - if( m_rectThumb.PtInRect( point ) ) - return eThumb; - if( m_rectTLArrow.PtInRect( point ) ) - return eTLbutton; - if( m_rectBRArrow.PtInRect( point ) ) - return eBRbutton; - if( m_rectTLChannel.PtInRect( point ) ) - return eTLchannel; - if( m_rectBRChannel.PtInRect( point ) ) - return eBRchannel; - return eNone; -} - -const CRect *CXeScrollBarBase::GetUIelementDrawState( eXSB_AREA eElem, - XSB_EDRAWELEM &eState ) -{ - ASSERT(::IsWindow(m_hWnd)); - CRect *prcElem = 0; - eState = eNotDrawn; - switch( eElem ) - { - case eTLbutton: - prcElem = &m_rectTLArrow; - break; - case eBRbutton: - prcElem = &m_rectBRArrow; - break; - case eTLchannel: - prcElem = &m_rectTLChannel; - break; - case eBRchannel: - prcElem = &m_rectBRChannel; - break; - case eThumb: - prcElem = &m_rectThumb; - break; - } - if( !prcElem || prcElem->IsRectEmpty() ) - eState = eNotDrawn; - if( !m_bEnabled ) - eState = eDisabled; - else if( m_eMouseDownArea.eArea == eElem ) - eState = eDown; - else if( m_eMouseOverArea.eArea == eElem && !m_bDragging) - eState = eHot; - else - eState = eNormal; - return prcElem; -} - -BOOL CXeScrollBarBase::CalcThumb( int cxyChannel, int &xyThumb, int &cxyThumb ) -{ - // Range in 'scroll units' (SU) - Note +1 because min/max are 'inclusive' values. - int nSU_Range = abs(m_nMaxPos - m_nMinPos) + 1; - if( nSU_Range == 0 // No thumb when scroll range is 0 - || cxyChannel <= (int)m_uThumbMinHW // No space for thumb. - || !m_bEnabled ) // No thumb when disabled. - return FALSE; - - // We have space for thumb. - - // thumb size = scroll bar size * page size / scroll bar range - // (pixels) (pixels) (scroll units) (scroll units) - - // When page size is 0 thumb size is set to minimum size. - - m_dblPx_SU = (double)cxyChannel / (double)nSU_Range; // Pixels per scroll unit. - - double dblXY = (double)(m_nPos - m_nMinPos) * m_dblPx_SU; - xyThumb = (int)dblXY; - if( fabs_dbl( dblXY - (double)xyThumb ) > 0.5 ) - xyThumb++; - - double dblCXY = (double)m_uPage * m_dblPx_SU; - cxyThumb = (int)dblCXY; - if( fabs_dbl( dblCXY - (double)cxyThumb ) > 0.5 ) - cxyThumb++; - - //if( m_uPage == 0 ) - // cxyThumb = GetCXYarrow(); // Thumb is same as arrow button when page = 0. - // Note - WIN SBs show thumb box same size as arrow button when PAGE = 0. - - if( cxyThumb < (int)m_uThumbMinHW ) - { - int nErrCXY = (int)m_uThumbMinHW - cxyThumb; - cxyThumb = (int)m_uThumbMinHW; - - // Calculate new thumb X or Y position when 'error' in position. - double dblErr_Px = (double)nErrCXY / (double)cxyChannel; - double dblXYoffs = dblErr_Px * xyThumb; - int xyOffs = (int)dblXYoffs; - if( fabs_dbl( dblXYoffs - (double)xyOffs ) > 0.5 ) - xyOffs++; - xyThumb -= xyOffs; - } - - // Sometimes it's needed to adjust the size and or position because scroll bar - // parameters are in error. - - // Calculate last possible X or Y for thumb. - int xyLastPossible = cxyChannel - cxyThumb; - if( xyThumb > xyLastPossible ) - xyThumb = xyLastPossible; - - if( xyThumb < 0 ) - xyThumb = 0; - - if( (xyThumb + cxyThumb) > cxyChannel ) - cxyThumb = cxyChannel - xyThumb; - - return TRUE; -} - -void CXeScrollBarBase::RecalcRects() -{ - if( !GetSafeHwnd() ) - return; - - GetClientRect( &m_rectClient ); // Update client rect. - - BOOL bHasThumb = FALSE; - m_rectThumb.SetRectEmpty(); - - if( m_bHorizontal ) - { // Calc. arrows - int cxClient = m_rectClient.Width(); - int cxArrow = GetCXYarrow(); // Arrow button width. - - if( cxClient < (2 * cxArrow) ) - cxArrow = cxClient / 2; // Limit arrow width to available area. - - m_rectTLArrow.SetRect( m_rectClient.left, m_rectClient.top, - m_rectClient.left + cxArrow, m_rectClient.bottom); - - m_rectBRArrow.SetRect( m_rectClient.right - cxArrow, m_rectClient.top, - m_rectClient.right, m_rectClient.bottom ); - - // Calc. thumb size and position - int xThumb, cxThumb, cxChannel = cxClient - (2 * cxArrow); - bHasThumb = CalcThumb( cxChannel, xThumb, cxThumb ); - if( bHasThumb ) - { // We have space for thumb. - xThumb += m_rectTLArrow.right; - m_rectThumb = m_rectTLArrow; - m_rectThumb.left = xThumb; - m_rectThumb.right = xThumb + cxThumb; - } - - // Calc. channels - m_rectTLChannel = m_rectTLArrow; - m_rectBRChannel = m_rectBRArrow; - m_rectTLChannel.left = m_rectTLArrow.right; - if( bHasThumb ) - { - m_rectTLChannel.right = m_rectThumb.left; - m_rectBRChannel.left = m_rectThumb.right; - m_rectBRChannel.right = m_rectBRArrow.left; - } - else - { - m_rectTLChannel.right = m_rectBRArrow.left; // L channel reaches to R arrow. - m_rectBRChannel.SetRectEmpty(); // No thumb - so R channel not needed. - } - } - else // Vertical scroll bar. - { // Calc. arrows - int cyClient = m_rectClient.Height(); - int cyArrow = GetCXYarrow(); // Arrow button height. - - if( cyClient < (2 * cyArrow) ) - cyArrow = cyClient / 2; // Limit arrow height to available area. - - m_rectTLArrow.SetRect( m_rectClient.left, m_rectClient.top, - m_rectClient.right, m_rectClient.top + cyArrow ); - - m_rectBRArrow.SetRect( m_rectClient.left, m_rectClient.bottom - cyArrow, - m_rectClient.right, m_rectClient.bottom ); - - // Calc. thumb size and position - int yThumb, cyThumb, cyChannel = cyClient - (2 * cyArrow); - bHasThumb = CalcThumb( cyChannel, yThumb, cyThumb ); - if( bHasThumb ) - { // We have space for thumb. - yThumb +=m_rectTLArrow.bottom ; - m_rectThumb = m_rectTLArrow; - m_rectThumb.top = yThumb; - m_rectThumb.bottom = yThumb + cyThumb; - } - - // Calc. channels - m_rectTLChannel = m_rectTLArrow; - m_rectBRChannel = m_rectBRArrow; - m_rectTLChannel.top = m_rectTLArrow.bottom; - if( bHasThumb ) - { - m_rectTLChannel.bottom = m_rectThumb.top; - m_rectBRChannel.top = m_rectThumb.bottom; - m_rectBRChannel.bottom = m_rectBRArrow.top; - } - else - { - m_rectTLChannel.bottom = m_rectBRArrow.top; // T channel reaches to B arrow. - m_rectBRChannel.SetRectEmpty(); // No thumb - so T channel not needed. - } - } -} - -BOOL CXeScrollBarBase::RecalcRectsThumbTrack( CPoint point ) -{ - ASSERT(m_bDragging && !m_rectThumb.IsRectEmpty()); // Sanity check. - if( m_bHorizontal ) - { // Horizontal scroll bar. - // X pos of left edge of thumb (0...?) - int xPos = point.x - m_xyThumbDragOffset; - if( xPos < m_rectTLArrow.right ) - xPos = m_rectTLArrow.right; - int nThumbWidth = m_rectThumb.Width(); - if( xPos > (m_rectBRArrow.left - nThumbWidth) ) - xPos = (m_rectBRArrow.left - nThumbWidth); - if( xPos == m_rectThumb.left ) - return FALSE; // No change. - m_rectThumb.left = xPos; - m_rectThumb.right = m_rectThumb.left + nThumbWidth; - m_rectTLChannel.right = m_rectThumb.left; - m_rectBRChannel.left = m_rectThumb.right; - } - else - { // Vertical scroll bar. - // Y pos of top edge of thumb (0...?) - int yPos = point.y - m_xyThumbDragOffset; - if( yPos < m_rectTLArrow.bottom ) - yPos = m_rectTLArrow.bottom; - int nThumbHeight = m_rectThumb.Height(); - if( yPos > (m_rectBRArrow.top - nThumbHeight) ) - yPos = (m_rectBRArrow.top - nThumbHeight); - if( yPos == m_rectThumb.top ) - return FALSE; // No change. - m_rectThumb.top = yPos; - m_rectThumb.bottom = m_rectThumb.top + nThumbHeight; - m_rectTLChannel.bottom = m_rectThumb.top; - m_rectBRChannel.top = m_rectThumb.bottom; - } - return TRUE; -} - -UINT CXeScrollBarBase::GetCXYarrow() -{ - if( m_uArrowWH ) // Has derived class set this value? - return m_uArrowWH; // Use arrow button width/height set by derived class. - - // If m_uArrowWH == 0 we must assume the arrow button is same width or height as - // the scrollbar window. - if( m_bHorizontal ) - return m_rectClient.Height(); // Horz. arrow button is same height as window. - return m_rectClient.Width(); // Vert. arrow button is same width as window. +///////////////////////////////////////////////////////////////////////////////////////// +// XeScrollBarBase.cpp Version 1.1 +// This class is designed as a base class for another class that will +// do all painting. This class handles all business logic. No painting +// is done in this class - except in debug mode. +// +// Author: Snorri Kristjansson +// snorrikris@gmail.com +// +// History +// Version 1.1 - 2010 October 21 +// - Changed base class to CScrollBar (was CWnd). +// - Fixed many issues to make this scroll bar behave (almost) the same as windows +// scroll bar. +// +// Version 1.0 - 2009 +// - Never released. +// +// Acknowledgements: +// Thanks to Hans Dietrich for his CXScrollBar class, +// which I used as the starting point for CXeScrollBarBase: +// http://www.codeproject.com/KB/miscctrl/XScrollBar.aspx +// (I don't think any of his code survived into this version - but thanks all the same). +// +// License: +// This software is released into the public domain. You are free to use +// it in any way you like, except that you may not sell this source code. +// +// This software is provided "as is" with no expressed or implied warranty. +// I accept no liability for any damage or loss of business that this +// software may cause. +// +///////////////////////////////////////////////////////////////////////////////////////// + +/**************************************************************************************** +TODO: + H Mouse wheel support (L/R wheel push) - WM_MOUSEHWHEEL (new message Vista and later). + + Change code to pure WIN32 - no MFC - use as base base class for CXeScrollBarBase. +****************************************************************************************/ + +#include "stdafx.h" +#include "XeScrollBarBase.h" + +/**************************************************************************************** +Research resources: + +Scroll bar MSDN WIN32 reference. +http://msdn.microsoft.com/en-us/library/bb787529(VS.85).aspx + +Scroll Bar Controls in Win32 +http://msdn.microsoft.com/en-us/library/ms997557.aspx + +How/why to handle WM_CANCELMODE message. +http://support.microsoft.com/kb/74548/en-us + +How/why to handle WM_GETDLGCODE message. +http://support.microsoft.com/kb/83302 + +Discussion about thumb size calculations and more (good one). +http://blogs.msdn.com/oldnewthing/archive/2009/09/21/9897553.aspx + +Discussion about thumb size calculations. +http://social.msdn.microsoft.com/forums/en-US/wpf/thread/415eacf6-481e-4ebd-a6b0-2953e851183d/ + +From the November 2001 issue of MSDN Magazine. +Understanding CControlView, Changing Scroll Bar Color in MFC Apps +by Paul DiLascia +http://msdn.microsoft.com/en-us/magazine/cc301457.aspx + +Handling Keyboard and Mouse Application Buttons in WTL +By Michael Dunn +http://www.codeproject.com/KB/wtl/WTLAppButtons.aspx + +XScrollBar - Scroll bar like Windows Media Player's +By Hans Dietrich +http://www.codeproject.com/KB/miscctrl/XScrollBar.aspx + +Developing a Custom Windows Scrollbar in MFC +By Don Metzler, DDJ June 01, 2003 +http://www.drdobbs.com/windows/184416659 + +SkinControls 1.1 - A journey in automating the skinning of Windows controls +by .dan.g. +http://www.codeproject.com/KB/library/SkinCtrl.aspx + +Custom Scrollbar Library version 1.1 +by James Brown +http://www.codeproject.com/KB/dialog/coolscroll.aspx + +Replace a Window's Internal Scrollbar with a customdraw scrollbar Control +By flyhigh +http://www.codeproject.com/KB/dialog/skinscrollbar.aspx +****************************************************************************************/ + +double fabs_dbl( double dbl ) +{ + if( dbl >= 0 ) + return dbl; + return (-dbl); +} + +// Round a double number up or down. +int round_ud_dbl( double dbl ) +{ + BOOL bNeg = FALSE; + if( dbl < 0 ) + { + bNeg = TRUE; + dbl = -dbl; + } + int n = (int)dbl; + double fract = dbl - (double)n; + if( fract > 0.5 ) + n++; + if( bNeg ) + n = -n; + return n; +} + +/////////////////////////////////////////////////////////////////////////// +// CXeScrollBarBase + +#define XESCROLLBARWND_CLASSNAME _T("XeScrollBarWndClass") // Window class name + +#define XSB_LBTN_DOWN_TIMERID 1001 +#define XSB_LBTN_DOWN_TIME 200 // mS - time to first auto repeat. +#define XSB_LBTN_REPT_TIMERID 1002 +#define XSB_LBTN_REPT_TIME 50 // mS - repeat interval. +#define XSB_FOCUS_TIMERID 1003 +#define XSB_FOCUS_TIME 500 // mS - blink 'gripper' interval. + +// Menu ID's - Note: same ID's as menu from user32.dll. +#define XSB_IDM_SCRHERE 4100 // Scroll Here Scroll Here +#define XSB_IDM_SCR_TL 4102 // Top Left Edge +#define XSB_IDM_SCR_BR 4103 // Bottom Right Edge +#define XSB_IDM_SCR_PG_UL 4098 // Page Up Page Left +#define XSB_IDM_SCR_PG_DR 4099 // Page Down Page Right +#define XSB_IDM_SCR_UL 4096 // Scroll Up Scroll Left +#define XSB_IDM_SCR_DR 4097 // Scroll Down Scroll Right + + +IMPLEMENT_DYNAMIC(CXeScrollBarBase, CScrollBar) + +BEGIN_MESSAGE_MAP(CXeScrollBarBase, CScrollBar) + ON_MESSAGE(SBM_ENABLE_ARROWS, OnSbmEnableArrows) + ON_MESSAGE(SBM_GETPOS, OnSbmGetPos) + ON_MESSAGE(SBM_GETRANGE, OnSbmGetRange) + ON_MESSAGE(SBM_GETSCROLLBARINFO, OnSbmGetScrollBarInfo) + ON_MESSAGE(SBM_GETSCROLLINFO, OnSbmGetScrollInfo) + ON_MESSAGE(SBM_SETPOS, OnSbmSetPos) + ON_MESSAGE(SBM_SETRANGE, OnSbmSetRange) + ON_MESSAGE(SBM_SETRANGEREDRAW, OnSbmSetRangeRedraw) + ON_MESSAGE(SBM_SETSCROLLINFO, OnSbmSetScrollInfo) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_MESSAGE(WM_KEYDOWN, OnKeyDown) + ON_MESSAGE(WM_KEYUP, OnKeyUp) + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_MOUSEMOVE() + ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) + ON_MESSAGE(WM_GETDLGCODE, OnGetDlgCode) + ON_WM_CANCELMODE() + ON_WM_CONTEXTMENU() + ON_COMMAND_RANGE(XSB_IDM_SCR_UL,XSB_IDM_SCR_BR,OnMenuCommands) + ON_WM_TIMER() + ON_WM_SIZE() + ON_WM_SETFOCUS() + ON_WM_KILLFOCUS() + ON_WM_ENABLE() + ON_WM_MOUSEWHEEL() +END_MESSAGE_MAP() + +CXeScrollBarBase::CXeScrollBarBase() +{ + m_pParent = 0; + m_bEnabled = m_bHorizontal = m_bDrawGripper = TRUE; + m_bHasFocus = FALSE; + m_bNoScroll = m_bDragging = m_bTrackMouseLeave = m_bNeedEndScroll = FALSE; + m_nPos = m_nTrackPos = m_nMinPos = m_nMaxPos = m_nMaxReportedPos = 0; + m_uPage = 1; + m_rectClient.SetRectEmpty(); + m_rectThumb.SetRectEmpty(); + m_rectTLArrow.SetRectEmpty(); + m_rectBRArrow.SetRectEmpty(); + m_rectTLChannel.SetRectEmpty(); + m_rectBRChannel.SetRectEmpty(); + m_uArrowWH = 0; + m_uThumbMinHW = 8; // Minimum thumb width or height + m_dblPx_SU = 0; + m_ptMenu.SetPoint(0,0); + m_xyThumbDragOffset = 0; + if (!SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0)) { //added to support multiple rows per mouse notch + scrollLines = 3; + } +} + +CXeScrollBarBase::~CXeScrollBarBase() +{ + // Note - base class dtor (CScrollBar) calls DestroyWindow(). +} + +BOOL CXeScrollBarBase::Create( DWORD dwStyle, const RECT& rect, CWnd *pParentWnd, UINT nID ) +{ + if( !RegisterWindowClass() ) + return FALSE; + + ASSERT(pParentWnd); + ASSERT(IsWindow(pParentWnd->m_hWnd)); + m_pParent = pParentWnd; + + m_bHorizontal = ( dwStyle & SBS_VERT ) ? FALSE : TRUE; + // Note - SBS_HORZ is defined as 0 in winuser.h. + + m_bEnabled = ( dwStyle & WS_DISABLED ) ? FALSE : TRUE; + + BOOL bResult = CWnd::Create( XESCROLLBARWND_CLASSNAME, 0, dwStyle, rect, + pParentWnd, nID ); + + if( bResult ) + { + RecalcRects(); + } + else + { + TRACE(_T("ERROR - failed to create %s\n"),XESCROLLBARWND_CLASSNAME); + ASSERT(FALSE); + } + + return bResult; + + // Note - We DO NOT call base class (CScrollBar) because CScrollBar creates 'normal' + // windows scrollbar. +} + +BOOL CXeScrollBarBase::CreateFromExisting( CWnd *pParentWnd, UINT nID, + BOOL bUseDefaultWH /*= TRUE*/ ) +{ + ASSERT(pParentWnd); + HWND hWndParent = pParentWnd->GetSafeHwnd(); + if( !::IsWindow( hWndParent ) ) + { + ASSERT(FALSE); + return FALSE; + } + HWND hWndExistingSB = ::GetDlgItem( hWndParent, nID ); + if( !hWndExistingSB ) + { + ASSERT(FALSE); + return FALSE; + } + + DWORD dwStyle = ::GetWindowLong( hWndExistingSB, GWL_STYLE ); + + RECT rect; + ::GetWindowRect( hWndExistingSB, &rect ); + ::ScreenToClient( hWndParent, (LPPOINT)&rect ); + ::ScreenToClient( hWndParent, ((LPPOINT)&rect) + 1 ); + if( bUseDefaultWH ) + { // Set width or height to system standard scroll bar width/height. + if( dwStyle & SBS_VERT ) + { + // Get width of 'sys' vert. SB. + int cxSysSbV = ::GetSystemMetrics( SM_CXVSCROLL ); + rect.right = rect.left + cxSysSbV; // Set width of vert. SB to 'normal'. + } + else + { + // Get height of 'sys' horz. SB. + int cySysSbH = ::GetSystemMetrics( SM_CYHSCROLL ); + rect.bottom = rect.top + cySysSbH; // Set height of horz. SB to 'normal'. + } + } + + // Get current range, page and position from existing scrollbar. + SCROLLINFO info; + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_ALL; + ::SendMessage( hWndExistingSB, SBM_GETSCROLLINFO, 0, (LPARAM)&info ); + + // Create new scroll bar of 'this' type. Note - Control ID = 0 until old SB destroyed. + if( !Create( dwStyle, rect, pParentWnd, 0 ) ) + return FALSE; + + // Note - new scroll bar is now the last window in our parent window child Z-order. + + HWND hWndNewSB = GetSafeHwnd(); + ASSERT(hWndNewSB); + + // Set Z-order of new scroll bar - insert after the existing scroll bar. + ::SetWindowPos( hWndNewSB, hWndExistingSB, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); + + // Destroy existing (old) scroll bar. + ::DestroyWindow( hWndExistingSB ); + + // Set Control ID of new scroll bar. + ::SetWindowLong( hWndNewSB, GWL_ID, nID ); + + // Set range, page and position parameters in scroll bar. + SetScrollInfo( &info ); + + return TRUE; +} + +BOOL CXeScrollBarBase::RegisterWindowClass() +{ + WNDCLASS wndcls; + HINSTANCE hInst = AfxGetInstanceHandle(); + + // 'Our' class already registered? + if( !(::GetClassInfo( hInst, XESCROLLBARWND_CLASSNAME, &wndcls )) ) + { // Otherwise we need to register a new class + wndcls.style = CS_HREDRAW | CS_VREDRAW; + // Note - CS_DBLCLKS style not used so don't need to + // process WM_LBUTTONDBLCLK message. + wndcls.lpfnWndProc = ::DefWindowProc; + wndcls.cbClsExtra = wndcls.cbWndExtra = 0; + wndcls.hInstance = hInst; + wndcls.hIcon = NULL; + wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); + wndcls.hbrBackground = NULL; + wndcls.lpszMenuName = NULL; + wndcls.lpszClassName = XESCROLLBARWND_CLASSNAME; + + if( !AfxRegisterClass( &wndcls ) ) + { + TRACE(_T("Register window class %s failed\n"),XESCROLLBARWND_CLASSNAME); + ASSERT(FALSE); + AfxThrowResourceException(); + return FALSE; + } + } + return TRUE; +} + +void CXeScrollBarBase::DrawScrollBar( CDC* pDC ) +{ + // Draw scrollbar as solid color rects - in debug mode ONLY! +#ifdef _DEBUG +#define X_GRBTN RGB(140,140,140) +#define X_GRCH RGB(180,180,180) +#define X_GRTHM RGB(96,96,96) +#define X_NRMBT RGB(128,0,128) +#define X_NRMCH RGB(128,128,0) +#define X_NRMTH RGB(0,192,0) +#define X_HOTBT RGB(192,0,192) +#define X_HOTCH RGB(192,192,0) +#define X_HOTTH RGB(0,255,0) +#define X_DWNBT (~X_NRMBT & 0xFFFFFF) +#define X_DWNCH (~X_NRMCH & 0xFFFFFF) +#define X_DWNTH (~X_NRMTH & 0xFFFFFF) + COLORREF rgbarr[5][6] = { +// eNone eTLbutton eBRbutton eTLchannel eBRchannel eThumb +// 0 1 2 3 4 5 + { 0, 0, 0, 0, 0, 0 }, // 0 eNotDrawn + { 0, X_GRBTN, X_GRBTN, X_GRCH, X_GRCH, X_GRTHM }, // 1 eDisabled + { 0, X_NRMBT, X_NRMBT, X_NRMCH, X_NRMCH, X_NRMTH }, // 2 eNormal + { 0, X_DWNBT, X_DWNBT, X_DWNCH, X_DWNCH, X_DWNTH }, // 3 eDown + { 0, X_HOTBT, X_HOTBT, X_HOTCH, X_HOTCH, X_HOTTH } // 4 eHot + }; + XSB_EDRAWELEM eState; + const CRect *prcElem = 0; + for( int nElem = eTLbutton; nElem <= eThumb; nElem++ ) + { + prcElem = GetUIelementDrawState( (eXSB_AREA)nElem, eState ); + if( !prcElem || eState == eNotDrawn ) + continue; + COLORREF rgb = rgbarr[eState][nElem]; + pDC->FillSolidRect( prcElem, rgb ); + } +#endif +} + +// SBM_GETPOS message handler. +LRESULT CXeScrollBarBase::OnSbmGetPos( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + return m_nPos; +} + +// SBM_SETPOS message handler. +LRESULT CXeScrollBarBase::OnSbmSetPos( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + int nPos = (int)wparam; + BOOL bRedraw = (BOOL)lparam; + int nOldPos = m_nPos; + + m_nPos = nPos; + + if( m_nPos < m_nMinPos ) + m_nPos = m_nMinPos; + else if( m_nPos > m_nMaxReportedPos ) + m_nPos = m_nMaxReportedPos; + + if( m_bNoScroll && !m_bEnabled ) // SB disabled because of SIF_DISABLENOSCROLL? + { // SBM_SETPOS cancels SIF_DISABLENOSCROLL. + m_bNoScroll = FALSE; + EnableWindow( TRUE ); + } + + RecalcRects(); + + if( bRedraw ) + Invalidate(); + + return nOldPos; +} + +// SBM_GETRANGE message handler. +LRESULT CXeScrollBarBase::OnSbmGetRange( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + LPINT lpMinPos = (LPINT)wparam; + LPINT lpMaxPos = (LPINT)lparam; + *lpMinPos = m_nMinPos; + *lpMaxPos = m_nMaxPos; + return 0; +} + +// SBM_SETRANGE message handler. +LRESULT CXeScrollBarBase::OnSbmSetRange( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + int nMinPos = (int)wparam; + int nMaxPos = (int)lparam; + m_nMinPos = nMinPos; + m_nMaxPos = nMaxPos; + if( m_nMaxPos < m_nMinPos ) + m_nMaxPos = m_nMinPos; + int nSUrange = abs(m_nMaxPos - m_nMinPos) + 1; + if( m_uPage > (UINT)nSUrange ) + m_uPage = (UINT)nSUrange; + + if( m_uPage == 0 ) + m_nMaxReportedPos = m_nMaxPos; + else + m_nMaxReportedPos = m_nMaxPos - ((int)m_uPage - 1); + + int nOldPos = m_nPos; + if( m_nPos < m_nMinPos ) + m_nPos = m_nMinPos; + else if( m_nPos > m_nMaxReportedPos ) + m_nPos = m_nMaxReportedPos; + + if( m_bNoScroll && !m_bEnabled ) // SB disabled because of SIF_DISABLENOSCROLL? + { // SBM_SETRANGE cancels SIF_DISABLENOSCROLL. + m_bNoScroll = FALSE; + EnableWindow( TRUE ); + } + + RecalcRects(); + + if( nOldPos != m_nPos ) + return nOldPos; + return 0; +} + +// SBM_SETRANGEREDRAW message handler. +LRESULT CXeScrollBarBase::OnSbmSetRangeRedraw( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + LRESULT lResult = OnSbmSetRange( wparam, lparam ); + Invalidate(); + return lResult; +} + +// SBM_GETSCROLLINFO message handler. +LRESULT CXeScrollBarBase::OnSbmGetScrollInfo( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + LPSCROLLINFO lpScrollInfo = (LPSCROLLINFO)lparam; + if( lpScrollInfo->cbSize != sizeof(SCROLLINFO) ) + return FALSE; + lpScrollInfo->nMin = m_nMinPos; + lpScrollInfo->nMax = m_nMaxPos; + lpScrollInfo->nPage = m_uPage; + lpScrollInfo->nPos = m_nPos; + lpScrollInfo->nTrackPos = m_nTrackPos; + return TRUE; +} + +// SBM_SETSCROLLINFO message handler. +LRESULT CXeScrollBarBase::OnSbmSetScrollInfo( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + BOOL bRedraw = (BOOL)wparam; + LPSCROLLINFO lpScrollInfo = (LPSCROLLINFO)lparam; + if( lpScrollInfo->cbSize != sizeof(SCROLLINFO) ) + return 0; + if( lpScrollInfo->fMask & SIF_PAGE ) + { + m_uPage = lpScrollInfo->nPage; + // Note - windows scrollbars can have a page size = 0. + } + if( lpScrollInfo->fMask & SIF_RANGE ) + { + m_nMinPos = lpScrollInfo->nMin; + m_nMaxPos = lpScrollInfo->nMax; + } + if( lpScrollInfo->fMask & SIF_POS ) + { + m_nPos = lpScrollInfo->nPos; + } + if( lpScrollInfo->fMask & SIF_DISABLENOSCROLL ) + { + BOOL bEnable = ( (int)m_uPage < (m_nMaxPos - m_nMinPos) ) ? TRUE : FALSE; + m_bNoScroll = !bEnable; + EnableWindow( bEnable ); + } + + if( m_nMaxPos < m_nMinPos ) + m_nMaxPos = m_nMinPos; + int nSUrange = abs(m_nMaxPos - m_nMinPos) + 1; + if( m_uPage > (UINT)nSUrange ) + m_uPage = (UINT)nSUrange; + + if( m_uPage == 0 ) + m_nMaxReportedPos = m_nMaxPos; + else + m_nMaxReportedPos = m_nMaxPos - ((int)m_uPage - 1); + + if( m_nPos < m_nMinPos ) + m_nPos = m_nMinPos; + else if( m_nPos > m_nMaxReportedPos ) + m_nPos = m_nMaxReportedPos; + + RecalcRects(); + + if( bRedraw ) + Invalidate(); + + return m_nPos; +} + +// SBM_ENABLE_ARROWS message handler. +LRESULT CXeScrollBarBase::OnSbmEnableArrows( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + /* ImplNote - during testing the windows scrollbar behaved strangely when only one + button was disabled. For that reason only enable/disable both is supported here. */ + EnableWindow( ( wparam & ESB_DISABLE_BOTH ) ? FALSE : TRUE ); + // wParam Specifies whether the scroll bar arrows are enabled or disabled and + // indicates which arrows are enabled or disabled. + return TRUE; +} + +// SBM_GETSCROLLBARINFO message handler. +LRESULT CXeScrollBarBase::OnSbmGetScrollBarInfo( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + SCROLLBARINFO *psbi = (SCROLLBARINFO *)lparam; + if( !psbi || psbi->cbSize != sizeof(SCROLLBARINFO) ) + return FALSE; + + /* Note - information on how to implement this is a little sparse from MS. + Need make a few educated guesses. + Note - testing (comparing 'this' to WIN SBs) has shown that: + rcScrollBar is in screen coords. + dxyLineButton is arrow button width when horz. SB. + dxyLineButton is arrow button height when vert. SB. + */ + + psbi->rcScrollBar = m_rectClient; // Coordinates of the scroll bar. + ClientToScreen( &psbi->rcScrollBar ); // In screen coords. + + if( m_bHorizontal ) + { + psbi->dxyLineButton = m_rectTLArrow.Width();// arrow button width. + psbi->xyThumbTop = m_rectThumb.left; // Position of the left of the thumb. + psbi->xyThumbBottom = m_rectThumb.right; // Position of the right of the thumb. + } + else + { + psbi->dxyLineButton = m_rectTLArrow.Height();// arrow button height. + psbi->xyThumbTop = m_rectThumb.top; // Position of the top of the thumb. + psbi->xyThumbBottom = m_rectThumb.bottom; // Position of the bottom of the thumb. + } + + // psbi->rgstate - An array of DWORD elements. Each element indicates the state of a + // scroll bar component. The following values show the scroll bar component that + // corresponds to each array index. Index Scroll bar component + // 0 The scroll bar itself. + // 1 The top or right arrow button. + // 2 The page up or page right region. + // 3 The scroll box (thumb). + // 4 The page down or page left region. + // 5 The bottom or left arrow button. + DWORD dwState = ( m_bEnabled ) ? 0 : STATE_SYSTEM_UNAVAILABLE; + DWORD dwTLchSt = dwState, dwBRchSt = dwState, dwThumbSt = dwState; + DWORD dwTLbtnSt = dwState, dwBRbtnSt = dwState; + if( m_rectTLChannel.IsRectEmpty() ) + dwTLchSt |= STATE_SYSTEM_INVISIBLE; + if( m_rectBRChannel.IsRectEmpty() ) + dwBRchSt |= STATE_SYSTEM_INVISIBLE; + if( m_rectThumb.IsRectEmpty() ) + dwThumbSt |= STATE_SYSTEM_INVISIBLE; + if( m_eMouseDownArea.IsTLButton() ) + dwTLbtnSt |= STATE_SYSTEM_PRESSED; + if( m_eMouseDownArea.IsTLChannel() ) + dwTLchSt |= STATE_SYSTEM_PRESSED; + if( m_eMouseDownArea.IsThumb() ) + dwThumbSt |= STATE_SYSTEM_PRESSED; + if( m_eMouseDownArea.IsBRChannel() ) + dwBRchSt |= STATE_SYSTEM_PRESSED; + if( m_eMouseDownArea.IsBRButton() ) + dwBRbtnSt |= STATE_SYSTEM_PRESSED; + psbi->rgstate[0] = dwState; + psbi->rgstate[1] = dwTLbtnSt; + psbi->rgstate[2] = dwTLchSt; + psbi->rgstate[3] = dwThumbSt; + psbi->rgstate[4] = dwBRchSt; + psbi->rgstate[5] = dwBRbtnSt; + + // The DWORD element for each scroll bar component can include a combination of the + // following bit flags. + // STATE_SYSTEM_INVISIBLE - For the scroll bar itself, indicates the specified + // vertical or horizontal scroll bar does not exist. For the page up or page + // down regions, indicates the thumb is positioned such that the region does + // not exist. + // STATE_SYSTEM_OFFSCREEN - For the scroll bar itself, indicates the window is sized + // such that the specified vertical or horizontal scroll bar is not currently + // displayed. (SK note - applies to NC scroll bars only). + // STATE_SYSTEM_PRESSED - The arrow button or page region is pressed. + // STATE_SYSTEM_UNAVAILABLE - The component is disabled. + + return TRUE; +} + +void CXeScrollBarBase::OnPaint() +{ // WM_PAINT message handler. + ASSERT(::IsWindow(m_hWnd)); + CPaintDC dc(this); // device context for painting + + DrawScrollBar( &dc ); + // Do not call CScrollBar::OnPaint() for painting messages +} + +BOOL CXeScrollBarBase::OnEraseBkgnd( CDC* pDC ) +{ // WM_ERASEBKGND message handler. + return TRUE; // All painting done in OnPaint. +} + +LRESULT CXeScrollBarBase::OnKeyDown( WPARAM wParam, LPARAM lParam ) +{ // WM_KEYDOWN message handler. + ASSERT(::IsWindow(m_hWnd)); + WORD wSBcode = 0xFFFF; + // Note - SB_PAGELEFT == SB_PAGEUP etc. see winuser.h + switch( wParam ) + { + case VK_PRIOR: + wSBcode = SB_PAGELEFT; + break; + + case VK_NEXT: + wSBcode = SB_PAGERIGHT; + break; + + case VK_HOME: + wSBcode = SB_LEFT; + break; + + case VK_END: + wSBcode = SB_RIGHT; + break; + + case VK_LEFT: + wSBcode = SB_LINELEFT; + break; + + case VK_RIGHT: + wSBcode = SB_LINERIGHT; + break; + + case VK_UP: + wSBcode = SB_LINEUP; + break; + + case VK_DOWN: + wSBcode = SB_LINEDOWN; + break; + } + + if( wSBcode != 0xFFFF ) + { + SendScrollMsg( wSBcode ); + m_bNeedEndScroll = TRUE; // Send SB_ENDSCROLL on WM_KEYUP. + } + + return 0; // Indicate we processed this message (eat all key msgs). + // Note - testing shows that windows looks for another child control to process + // keyboard input if we don't return 0 here (and we lose focus). +} + +LRESULT CXeScrollBarBase::OnKeyUp( WPARAM wParam, LPARAM lParam ) +{ // WM_KEYUP message handler. + if( m_bNeedEndScroll ) + { + SendScrollMsg( SB_ENDSCROLL ); + m_bNeedEndScroll = FALSE; + } + return 0; // Indicate we processed this message (eat all key msgs). +} + +void CXeScrollBarBase::OnLButtonDown( UINT nFlags, CPoint point ) +{ // WM_LBUTTONDOWN message handler. + ASSERT(::IsWindow(m_hWnd)); + SetCapture(); + BOOL bHasTabStop = ( ::GetWindowLong( m_hWnd, GWL_STYLE ) & WS_TABSTOP ) ? TRUE : FALSE; + if( bHasTabStop ) + SetFocus(); // Only 'steal' focus if 'this' has Tab stop. + + m_eMouseDownArea = GetAreaFromPoint( point ); + + WORD wSBcode = 0xFFFF; + // Note - SB_PAGELEFT == SB_PAGEUP etc. see winuser.h + if( m_eMouseDownArea.eArea == eTLbutton ) + wSBcode = SB_LINELEFT; + else if( m_eMouseDownArea.eArea == eTLchannel ) + wSBcode = SB_PAGELEFT; + else if( m_eMouseDownArea.eArea == eBRchannel ) + wSBcode = SB_PAGERIGHT; + else if( m_eMouseDownArea.eArea == eBRbutton ) + wSBcode = SB_LINERIGHT; + + if( wSBcode != 0xFFFF ) + { + SendScrollMsg( wSBcode ); + m_bNeedEndScroll = TRUE; // Send SB_ENDSCROLL on WM_LBUTTONUP message. + } + + if( m_eMouseDownArea.IsThumb() ) // Store X or Y offset from thumb edge. + m_xyThumbDragOffset = ( m_bHorizontal ) ? point.x - m_rectThumb.left + : point.y - m_rectThumb.top; + + // Set timer for first auto repeat - when button or channel clicked. + if( m_eMouseDownArea.IsButton() || m_eMouseDownArea.IsChannel() ) + SetTimer( XSB_LBTN_DOWN_TIMERID, XSB_LBTN_DOWN_TIME, 0 ); + + CScrollBar::OnLButtonDown(nFlags, point); +} + +void CXeScrollBarBase::OnLButtonUp( UINT nFlags, CPoint point ) +{ // WM_LBUTTONUP message handler. + ASSERT(::IsWindow(m_hWnd)); + ReleaseCapture(); + KillTimer( XSB_LBTN_DOWN_TIMERID ); + KillTimer( XSB_LBTN_REPT_TIMERID ); + + m_eMouseDownArea = eNone; + + if( m_bDragging ) // Did we send any SB_THUMBTRACK messages? + { + SendScrollMsg( SB_THUMBPOSITION, (WORD)m_nTrackPos ); + m_bDragging = FALSE; + RecalcRects(); // Reset thumb pos. to current scroll pos. + } + + if( m_bNeedEndScroll ) + { + SendScrollMsg( SB_ENDSCROLL ); // Let parent know scrolling has ended. + m_bNeedEndScroll = FALSE; + } + + Invalidate(); + + CScrollBar::OnLButtonUp(nFlags, point); +} + +/* updated to newer api and reversing return value to avoid mousewheel propagating */ +/* remove restriction on vert scrollbar, as both are valid in win32 */ +BOOL CXeScrollBarBase::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { + ASSERT(::IsWindow(m_hWnd)); + //short xPos = pt.x; + //short yPos = pt.y; + + //if (!m_bHorizontal) // Mouse wheel messages only apply to vertical scrollbar. + //{ + WORD wSBcode = 0xFFFF; + if (zDelta >= WHEEL_DELTA) { + wSBcode = SB_LINEUP; + } else if (zDelta <= -WHEEL_DELTA) { + wSBcode = SB_LINEDOWN; + zDelta = -zDelta; + } + if (wSBcode != 0xFFFF) { + do { + for (UINT i=0; i= WHEEL_DELTA); + SendScrollMsg(SB_ENDSCROLL); + } + return 1; // Message was processed. (was 0, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 1 if scrolling enabled + //} + //return 0; // Message not processed. (was 1, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 0 if scrolling not enabled +} + + +void CXeScrollBarBase::OnMouseMove( UINT nFlags, CPoint point ) +{ // WM_MOUSEMOVE message handler. + ASSERT(::IsWindow(m_hWnd)); + if( !m_bTrackMouseLeave ) + { // We want a WM_MOUSELEAVE message when mouse leaves our client area. + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.hwndTrack = m_hWnd; + tme.dwFlags = TME_LEAVE; + tme.dwHoverTime = 0; + + // Note - _TrackMouseEvent is from comctl32.dll - emulates TrackMouseEvent + // if it does not exist. + m_bTrackMouseLeave = _TrackMouseEvent( &tme ); + } + + stXSB_AREA eOldMouseArea = m_eMouseOverArea; + + m_eMouseOverArea = GetAreaFromPoint( point ); // Update mouse over area. + + if( m_eMouseDownArea.IsThumb() && m_dblPx_SU > 0 ) + { // User is dragging the thumb. + BOOL bStartDrag = FALSE; + if( !m_bDragging ) + { + bStartDrag = TRUE; // Start of thumb dragging. + m_bDragging = TRUE; + } + int nTrackPos; + double dblScrollPos; + if( m_bHorizontal ) + { // X pos of left edge of thumb (0...?) + int xPos = point.x - m_xyThumbDragOffset - m_rectTLArrow.right; + dblScrollPos = (double)xPos / m_dblPx_SU; + nTrackPos = round_ud_dbl( dblScrollPos ) + m_nMinPos; + } + else + { // Y pos of top edge of thumb (0...?) + int yPos = point.y - m_xyThumbDragOffset - m_rectTLArrow.bottom; + dblScrollPos = (double)yPos / m_dblPx_SU; + nTrackPos = round_ud_dbl( dblScrollPos ) + m_nMinPos; + } + if( nTrackPos < m_nMinPos ) + nTrackPos = m_nMinPos; + else if( nTrackPos > m_nMaxReportedPos ) + nTrackPos = m_nMaxReportedPos; + + //adipose: moved this block to before sending scroll message. otherwise scrollbar updates poorly on slower windows (listctrl) + //also call updatewindow to redraw immediately + // Recalculate thumb XY pos. and redraw if pos. changed. + if (RecalcRectsThumbTrack(point)) { + Invalidate(); + UpdateWindow(); + } + + if( bStartDrag || m_nTrackPos != nTrackPos ) + { // Send scroll message when user starts dragging + // OR when track pos has changed. + m_nTrackPos = nTrackPos; + SendScrollMsg( SB_THUMBTRACK, (WORD)m_nTrackPos ); + m_bNeedEndScroll = TRUE; + } + } + + if( m_eMouseOverArea != eOldMouseArea ) + Invalidate(); + + CScrollBar::OnMouseMove(nFlags, point); +} + +LRESULT CXeScrollBarBase::OnMouseLeave( WPARAM wparam, LPARAM lparam ) +{ // WM_MOUSELEAVE message handler. + ASSERT(::IsWindow(m_hWnd)); + m_bTrackMouseLeave = FALSE; + m_eMouseOverArea = eNone; + Invalidate(); + return 0; +} + +LRESULT CXeScrollBarBase::OnGetDlgCode( WPARAM wParam, LPARAM lParam ) +{ // WM_GETDLGCODE message handler. + ASSERT(::IsWindow(m_hWnd)); + BOOL bHasTabStop = ( ::GetWindowLong( m_hWnd, GWL_STYLE ) & WS_TABSTOP ) ? TRUE : FALSE; + + LRESULT lResult = Default(); + if( lParam ) // lParam points to an MSG structure? + { + LPMSG lpmsg = (LPMSG)lParam; + if( (lpmsg->message == WM_KEYDOWN // Keyboard input? + || lpmsg->message == WM_KEYUP) + && lpmsg->wParam != VK_TAB ) // AND NOT TAB key? + { + if( bHasTabStop ) // 'this' window has Tab stop? + { + lResult |= DLGC_WANTMESSAGE; // We want keyboard input (except TAB). + // Note - windows will set focus to 'this' (and send WM_SETFOCUS) + // if we return DLGC_WANTMESSAGE here. + } + else + { // 'this' windows does NOT have TAB stop. + // Note - windows standard scroll bar implements a special behaviour + // for scroll bars when no tab stop for the UP, DOWN, LEFT, RIGHT keys. + if( m_bHorizontal ) + { + if( lpmsg->wParam == VK_LEFT || lpmsg->wParam == VK_RIGHT ) + lResult |= DLGC_WANTMESSAGE; + } + else + { + if( lpmsg->wParam == VK_UP || lpmsg->wParam == VK_DOWN ) + lResult |= DLGC_WANTMESSAGE; + } + } + } + } + else + { + if( bHasTabStop ) + lResult |= DLGC_WANTTAB; // 'this' has WS_TABSTOP style - we want focus. + else + lResult |= DLGC_STATIC; // no tab stop - we don't want focus. + } + return lResult; +} + +void CXeScrollBarBase::OnCancelMode() +{ // WM_CANCELMODE message handler. + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnCancelMode(); + + // Need to handle WM_CANCELMODE message. + // See -> http://support.microsoft.com/kb/74548/en-us + + if( !m_eMouseDownArea.IsNone() ) // Mouse L button down? + OnLButtonUp( 0, CPoint(0,0) ); // Do L btn up processing now. +} + +void CXeScrollBarBase::OnContextMenu( CWnd* pWnd, CPoint point ) +{ // WM_CONTEXTMENU message handler. + ASSERT(::IsWindow(m_hWnd)); + + m_ptMenu = point; + ScreenToClient( &m_ptMenu ); + + // Try to load scroll bar menu from user32.dll - to get menu in 'local' language. + CString strDllPathName; + GetWindowsDirectory( strDllPathName.GetBuffer(MAX_PATH), MAX_PATH ); + strDllPathName.ReleaseBuffer(); + strDllPathName += _T("\\system32\\user32.dll"); + + HMODULE hUser32dllModule = ::LoadLibrary( strDllPathName ); + if( hUser32dllModule ) + { // Get menu #64 (horz.) or menu #80 (vert.) from user32.dll. + HMENU hMenu = 0, hSubMenu = 0; + if( m_bHorizontal ) + hMenu = ::LoadMenu( hUser32dllModule, MAKEINTRESOURCE(64) ); + else + hMenu = ::LoadMenu( hUser32dllModule, MAKEINTRESOURCE(80) ); + if( hMenu ) + { + hSubMenu = ::GetSubMenu( hMenu, 0 ); + if( hSubMenu ) + { + ::TrackPopupMenu( hSubMenu, TPM_LEFTALIGN, point.x, point.y, 0, + GetSafeHwnd(), 0 ); + // Note - TrackPopupMenu does not return until menu has been dismissed. + ::DestroyMenu( hMenu ); + } + } + ::FreeLibrary( hUser32dllModule ); + if( hSubMenu ) + return; // Using menu from user32.dll was successful. + } + + // If using menu from user32.dll was unsuccessful - create menu (in english). + CMenu menu; + menu.CreatePopupMenu(); + menu.AppendMenu( MF_STRING, XSB_IDM_SCRHERE, _T("Scroll Here") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + if( m_bHorizontal ) + { + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_TL, _T("Left Edge") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_BR, _T("Right Edge") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_UL, _T("Page Left") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_DR, _T("Page Right") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_UL, _T("Scroll Left") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_DR, _T("Scroll Right") ); + } + else + { + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_TL, _T("Top") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_BR, _T("Bottom") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_UL, _T("Page Up") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_DR, _T("Page Down") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_UL, _T("Scroll Up") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_DR, _T("Scroll Down") ); + } + menu.TrackPopupMenu( TPM_LEFTALIGN, point.x, point.y, pWnd ); + // Note - TrackPopupMenu does not return until menu has been dismissed. + menu.DestroyMenu(); +} + +void CXeScrollBarBase::OnMenuCommands( UINT uID ) +{ + ASSERT(::IsWindow(m_hWnd)); + int xyOfs, nScrollHerePos; + double dblScrollPos; + WORD wSBcode = 0xFFFF; + switch( uID ) + { + case XSB_IDM_SCRHERE: + // Calculate pos (in scroll units) + if( m_bHorizontal ) + xyOfs = m_ptMenu.x - m_rectTLArrow.right; + else + xyOfs = m_ptMenu.y - m_rectTLArrow.bottom; + if( xyOfs < 0 ) + xyOfs = 0; + if( m_rectThumb.IsRectEmpty() || !(m_dblPx_SU > 0) ) + break; // Can't 'Scroll Here'. + dblScrollPos = (double)xyOfs / m_dblPx_SU; + nScrollHerePos = m_nMinPos + round_ud_dbl( dblScrollPos ); + if( nScrollHerePos < m_nMinPos ) + nScrollHerePos = m_nMinPos; + else if( nScrollHerePos > m_nMaxReportedPos ) + nScrollHerePos = m_nMaxReportedPos; + m_nTrackPos = nScrollHerePos; + SendScrollMsg( SB_THUMBPOSITION, (WORD)m_nTrackPos ); + SendScrollMsg( SB_ENDSCROLL ); + break; + case XSB_IDM_SCR_TL: + wSBcode = SB_TOP; + break; + case XSB_IDM_SCR_BR: + wSBcode = SB_BOTTOM; + break; + case XSB_IDM_SCR_PG_UL: + wSBcode = SB_PAGEUP; + break; + case XSB_IDM_SCR_PG_DR: + wSBcode = SB_PAGEDOWN; + break; + case XSB_IDM_SCR_UL: + wSBcode = SB_LINEUP; + break; + case XSB_IDM_SCR_DR: + wSBcode = SB_LINEDOWN; + break; + } + if( wSBcode != 0xFFFF ) + { + SendScrollMsg( wSBcode ); + SendScrollMsg( SB_ENDSCROLL ); + } +} + +void CXeScrollBarBase::OnTimer( UINT_PTR nIDEvent ) +{ // WM_TIMER message handler. + ASSERT(::IsWindow(m_hWnd)); + if( nIDEvent == XSB_LBTN_DOWN_TIMERID ) + { // First auto repeat timer event. + KillTimer( XSB_LBTN_DOWN_TIMERID ); + SetTimer( XSB_LBTN_REPT_TIMERID, XSB_LBTN_REPT_TIME, 0 ); + } + if( nIDEvent == XSB_LBTN_DOWN_TIMERID || nIDEvent == XSB_LBTN_REPT_TIMERID ) + { // Auto repeat + CPoint ptCurMouse; + if( ::GetCursorPos( &ptCurMouse ) ) + { + ::ScreenToClient( GetSafeHwnd(), &ptCurMouse ); + m_eMouseOverArea = GetAreaFromPoint( ptCurMouse ); // Update mouse over area. + } + if( m_eMouseDownArea.IsTLButton() ) + { + if( m_eMouseOverArea.IsTLButton() ) // Mouse still over button? + SendScrollMsg( SB_LINELEFT ); + } + else if( m_eMouseDownArea.IsBRButton() ) + { + if( m_eMouseOverArea.IsBRButton() ) // Mouse still over button? + SendScrollMsg( SB_LINERIGHT ); + } + else if( m_eMouseDownArea.IsTLChannel() ) + { + if( m_eMouseOverArea.IsTLChannel() ) // Mouse still over channel? + SendScrollMsg( SB_PAGELEFT ); + } + else if( m_eMouseDownArea.IsBRChannel() ) + { + if( m_eMouseOverArea.IsBRChannel() ) // Mouse still over channel? + SendScrollMsg( SB_PAGERIGHT ); + } + // Note - SB_LINELEFT == SB_LINEUP etc. see winuser.h + } + if( nIDEvent == XSB_FOCUS_TIMERID ) + { // Blinking focus timer. + if( m_bNeedEndScroll ) + { // Draw normal thumb box while user is scrolling. + if( !m_bDrawGripper ) + { // Redraw scroll bar if currently drawn without 'gripper'. + m_bDrawGripper = TRUE; + Invalidate(); // Draw 'blinking' focus. + } + } + else + { // Draw blinking 'gripper' to indicate 'focus'. + m_bDrawGripper = !m_bDrawGripper; + Invalidate(); // Draw 'blinking' focus. + } + } + + CScrollBar::OnTimer( nIDEvent ); +} + +void CXeScrollBarBase::OnSize( UINT nType, int cx, int cy ) +{ // WM_SIZE message handler. + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnSize( nType, cx, cy ); + + if( m_hWnd ) + RecalcRects(); +} + +void CXeScrollBarBase::OnSetFocus( CWnd* pOldWnd ) +{ // WM_SETFOCUS message handler. + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnSetFocus( pOldWnd ); + m_bHasFocus = TRUE; + m_bDrawGripper = FALSE; + SetTimer( XSB_FOCUS_TIMERID, XSB_FOCUS_TIME, 0 ); + Invalidate(); +} + +void CXeScrollBarBase::OnKillFocus( CWnd* pNewWnd ) +{ // WM_KILLFOCUS message handler. + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnKillFocus( pNewWnd ); + m_bHasFocus = FALSE; + m_bDrawGripper = TRUE; + KillTimer( XSB_FOCUS_TIMERID ); + Invalidate(); +} + +void CXeScrollBarBase::OnEnable( BOOL bEnable ) +{ // WM_ENABLE message handler + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnEnable(bEnable); + + m_bEnabled = bEnable; + + RecalcRects(); // Need to recalc. because no thumb is shown when disabled. + + Invalidate(); +} + +void CXeScrollBarBase::SendScrollMsg( WORD wSBcode, WORD wHiWPARAM /*= 0*/ ) +{ + ASSERT(::IsWindow(m_hWnd)); + if( m_pParent && ::IsWindow( m_pParent->m_hWnd ) ) + { + m_pParent->SendMessage( ( m_bHorizontal ) ? WM_HSCROLL : WM_VSCROLL, + MAKELONG(wSBcode,wHiWPARAM), (LPARAM)m_hWnd ); + } +} + +eXSB_AREA CXeScrollBarBase::GetAreaFromPoint( CPoint point ) +{ + ASSERT(::IsWindow(m_hWnd)); + if( !m_rectClient.PtInRect( point ) ) + return eNone; + if( m_rectThumb.PtInRect( point ) ) + return eThumb; + if( m_rectTLArrow.PtInRect( point ) ) + return eTLbutton; + if( m_rectBRArrow.PtInRect( point ) ) + return eBRbutton; + if( m_rectTLChannel.PtInRect( point ) ) + return eTLchannel; + if( m_rectBRChannel.PtInRect( point ) ) + return eBRchannel; + return eNone; +} + +const CRect *CXeScrollBarBase::GetUIelementDrawState( eXSB_AREA eElem, + XSB_EDRAWELEM &eState ) +{ + ASSERT(::IsWindow(m_hWnd)); + CRect *prcElem = 0; + eState = eNotDrawn; + switch( eElem ) + { + case eTLbutton: + prcElem = &m_rectTLArrow; + break; + case eBRbutton: + prcElem = &m_rectBRArrow; + break; + case eTLchannel: + prcElem = &m_rectTLChannel; + break; + case eBRchannel: + prcElem = &m_rectBRChannel; + break; + case eThumb: + prcElem = &m_rectThumb; + break; + } + if( !prcElem || prcElem->IsRectEmpty() ) + eState = eNotDrawn; + if( !m_bEnabled ) + eState = eDisabled; + else if( m_eMouseDownArea.eArea == eElem ) + eState = eDown; + else if( m_eMouseOverArea.eArea == eElem && !m_bDragging) + eState = eHot; + else + eState = eNormal; + return prcElem; +} + +BOOL CXeScrollBarBase::CalcThumb( int cxyChannel, int &xyThumb, int &cxyThumb ) +{ + // Range in 'scroll units' (SU) - Note +1 because min/max are 'inclusive' values. + int nSU_Range = abs(m_nMaxPos - m_nMinPos) + 1; + if( nSU_Range == 0 // No thumb when scroll range is 0 + || cxyChannel <= (int)m_uThumbMinHW // No space for thumb. + || !m_bEnabled ) // No thumb when disabled. + return FALSE; + + // We have space for thumb. + + // thumb size = scroll bar size * page size / scroll bar range + // (pixels) (pixels) (scroll units) (scroll units) + + // When page size is 0 thumb size is set to minimum size. + + m_dblPx_SU = (double)cxyChannel / (double)nSU_Range; // Pixels per scroll unit. + + double dblXY = (double)(m_nPos - m_nMinPos) * m_dblPx_SU; + xyThumb = (int)dblXY; + if( fabs_dbl( dblXY - (double)xyThumb ) > 0.5 ) + xyThumb++; + + double dblCXY = (double)m_uPage * m_dblPx_SU; + cxyThumb = (int)dblCXY; + if( fabs_dbl( dblCXY - (double)cxyThumb ) > 0.5 ) + cxyThumb++; + + //if( m_uPage == 0 ) + // cxyThumb = GetCXYarrow(); // Thumb is same as arrow button when page = 0. + // Note - WIN SBs show thumb box same size as arrow button when PAGE = 0. + + if( cxyThumb < (int)m_uThumbMinHW ) + { + int nErrCXY = (int)m_uThumbMinHW - cxyThumb; + cxyThumb = (int)m_uThumbMinHW; + + // Calculate new thumb X or Y position when 'error' in position. + double dblErr_Px = (double)nErrCXY / (double)cxyChannel; + double dblXYoffs = dblErr_Px * xyThumb; + int xyOffs = (int)dblXYoffs; + if( fabs_dbl( dblXYoffs - (double)xyOffs ) > 0.5 ) + xyOffs++; + xyThumb -= xyOffs; + } + + // Sometimes it's needed to adjust the size and or position because scroll bar + // parameters are in error. + + // Calculate last possible X or Y for thumb. + int xyLastPossible = cxyChannel - cxyThumb; + if( xyThumb > xyLastPossible ) + xyThumb = xyLastPossible; + + if( xyThumb < 0 ) + xyThumb = 0; + + if( (xyThumb + cxyThumb) > cxyChannel ) + cxyThumb = cxyChannel - xyThumb; + + return TRUE; +} + +void CXeScrollBarBase::RecalcRects() +{ + if( !GetSafeHwnd() ) + return; + + GetClientRect( &m_rectClient ); // Update client rect. + + BOOL bHasThumb = FALSE; + m_rectThumb.SetRectEmpty(); + + if( m_bHorizontal ) + { // Calc. arrows + int cxClient = m_rectClient.Width(); + int cxArrow = GetCXYarrow(); // Arrow button width. + + if( cxClient < (2 * cxArrow) ) + cxArrow = cxClient / 2; // Limit arrow width to available area. + + m_rectTLArrow.SetRect( m_rectClient.left, m_rectClient.top, + m_rectClient.left + cxArrow, m_rectClient.bottom); + + m_rectBRArrow.SetRect( m_rectClient.right - cxArrow, m_rectClient.top, + m_rectClient.right, m_rectClient.bottom ); + + // Calc. thumb size and position + int xThumb, cxThumb, cxChannel = cxClient - (2 * cxArrow); + bHasThumb = CalcThumb( cxChannel, xThumb, cxThumb ); + if( bHasThumb ) + { // We have space for thumb. + xThumb += m_rectTLArrow.right; + m_rectThumb = m_rectTLArrow; + m_rectThumb.left = xThumb; + m_rectThumb.right = xThumb + cxThumb; + } + + // Calc. channels + m_rectTLChannel = m_rectTLArrow; + m_rectBRChannel = m_rectBRArrow; + m_rectTLChannel.left = m_rectTLArrow.right; + if( bHasThumb ) + { + m_rectTLChannel.right = m_rectThumb.left; + m_rectBRChannel.left = m_rectThumb.right; + m_rectBRChannel.right = m_rectBRArrow.left; + } + else + { + m_rectTLChannel.right = m_rectBRArrow.left; // L channel reaches to R arrow. + m_rectBRChannel.SetRectEmpty(); // No thumb - so R channel not needed. + } + } + else // Vertical scroll bar. + { // Calc. arrows + int cyClient = m_rectClient.Height(); + int cyArrow = GetCXYarrow(); // Arrow button height. + + if( cyClient < (2 * cyArrow) ) + cyArrow = cyClient / 2; // Limit arrow height to available area. + + m_rectTLArrow.SetRect( m_rectClient.left, m_rectClient.top, + m_rectClient.right, m_rectClient.top + cyArrow ); + + m_rectBRArrow.SetRect( m_rectClient.left, m_rectClient.bottom - cyArrow, + m_rectClient.right, m_rectClient.bottom ); + + // Calc. thumb size and position + int yThumb, cyThumb, cyChannel = cyClient - (2 * cyArrow); + bHasThumb = CalcThumb( cyChannel, yThumb, cyThumb ); + if( bHasThumb ) + { // We have space for thumb. + yThumb +=m_rectTLArrow.bottom ; + m_rectThumb = m_rectTLArrow; + m_rectThumb.top = yThumb; + m_rectThumb.bottom = yThumb + cyThumb; + } + + // Calc. channels + m_rectTLChannel = m_rectTLArrow; + m_rectBRChannel = m_rectBRArrow; + m_rectTLChannel.top = m_rectTLArrow.bottom; + if( bHasThumb ) + { + m_rectTLChannel.bottom = m_rectThumb.top; + m_rectBRChannel.top = m_rectThumb.bottom; + m_rectBRChannel.bottom = m_rectBRArrow.top; + } + else + { + m_rectTLChannel.bottom = m_rectBRArrow.top; // T channel reaches to B arrow. + m_rectBRChannel.SetRectEmpty(); // No thumb - so T channel not needed. + } + } +} + +BOOL CXeScrollBarBase::RecalcRectsThumbTrack( CPoint point ) +{ + ASSERT(m_bDragging && !m_rectThumb.IsRectEmpty()); // Sanity check. + if( m_bHorizontal ) + { // Horizontal scroll bar. + // X pos of left edge of thumb (0...?) + int xPos = point.x - m_xyThumbDragOffset; + if( xPos < m_rectTLArrow.right ) + xPos = m_rectTLArrow.right; + int nThumbWidth = m_rectThumb.Width(); + if( xPos > (m_rectBRArrow.left - nThumbWidth) ) + xPos = (m_rectBRArrow.left - nThumbWidth); + if( xPos == m_rectThumb.left ) + return FALSE; // No change. + m_rectThumb.left = xPos; + m_rectThumb.right = m_rectThumb.left + nThumbWidth; + m_rectTLChannel.right = m_rectThumb.left; + m_rectBRChannel.left = m_rectThumb.right; + } + else + { // Vertical scroll bar. + // Y pos of top edge of thumb (0...?) + int yPos = point.y - m_xyThumbDragOffset; + if( yPos < m_rectTLArrow.bottom ) + yPos = m_rectTLArrow.bottom; + int nThumbHeight = m_rectThumb.Height(); + if( yPos > (m_rectBRArrow.top - nThumbHeight) ) + yPos = (m_rectBRArrow.top - nThumbHeight); + if( yPos == m_rectThumb.top ) + return FALSE; // No change. + m_rectThumb.top = yPos; + m_rectThumb.bottom = m_rectThumb.top + nThumbHeight; + m_rectTLChannel.bottom = m_rectThumb.top; + m_rectBRChannel.top = m_rectThumb.bottom; + } + return TRUE; +} + +UINT CXeScrollBarBase::GetCXYarrow() +{ + if( m_uArrowWH ) // Has derived class set this value? + return m_uArrowWH; // Use arrow button width/height set by derived class. + + // If m_uArrowWH == 0 we must assume the arrow button is same width or height as + // the scrollbar window. + if( m_bHorizontal ) + return m_rectClient.Height(); // Horz. arrow button is same height as window. + return m_rectClient.Width(); // Vert. arrow button is same width as window. } \ No newline at end of file diff --git a/src/thirdparty/XeScrollBar/xescrollbarbase.h b/src/thirdparty/XeScrollBar/xescrollbarbase.h index 0d0dfa4e7ac..e75de1259ad 100755 --- a/src/thirdparty/XeScrollBar/xescrollbarbase.h +++ b/src/thirdparty/XeScrollBar/xescrollbarbase.h @@ -1,399 +1,399 @@ -#pragma once - -/**************************************************************************************** -CXeScrollBarBase class. -This class implements a very close copy of the standard windows scroll bar. -This class is designed as a base class for another class that will do all painting. -This class handles all the business logic. -No painting is done in this class - except in debug mode. - -The derived class needs to do the following: -* MUST override DrawScrollBar member function to do all the painting. - Example: - Create memory DC - same size as client area. - XSB_EDRAWELEM eState; - const CRect *prcElem = 0; - stXSB_AREA stArea; - for( int nElem = eTLbutton; nElem <= eThumb; nElem++ ) // loop through all UI elements. - { - stArea.eArea = (eXSB_AREA)nElem; - - // Get bounding rect of UI element to draw (client coords.) - prcElem = GetUIelementDrawState( stArea.eArea, eState ); - if( !prcElem || eState == eNotDrawn ) // Rect empty or area not drawn? - continue; - - // stArea.eArea identifies UI element to draw: - // eTLbutton or eTLchannel or eThumb or eBRchannel or eBRbutton. - - // eState identifes in what state the UI element is drawn: - // eDisabled or eNormal or eDown or eHot. - - // m_bHorizontal is TRUE if 'this' is a horizontal scroll bar. - - // Draw UI element to memory DC. (using prcElem rect). - // Note - use m_bDrawGripper to determine if 'gripper' is drawn on thumb box. - // This is used to implement 'blinking' to show scroll bar has input - // focus. (every 500mS). - } - Copy memory DC to pDC. - -* (optional) Set m_uArrowWH to the width of the arrow button in horizontal scrollbar, - note - height of arrow button in vertical scrollbar is the same. - If this member is left unchanged (= 0) the arrow button width in horizontal scrollbar - is assumed to be equal to the height of the window. Same for vertical scroll bar - except the width of the window is arrow button height. - This number is needed to calculate sizes of other UI elements of the scroll bar. - -* (optional) Set m_uThumbMinHW to the minimum allowed width of the thumb box in a - horizontal scroll bar, this value is also the minimum height of the thumb box in a - vertical scroll bar. The default is 8 pixels. -****************************************************************************************/ - -// Enum - UI element state - helps with drawing scrollbar. -typedef enum tagXSB_EDRAWELEM -{ - eNotDrawn = 0, // UI element is not visible. (UI Rect empty). - eDisabled, // Element should be drawn in disabled state. - eNormal, // Element should be drawn in normal state. - eDown, // Element should be drawn in down state. - eHot // Element should be drawn in hot state. - // Note - Scroll bar channel is usually not drawn 'hot'. -} XSB_EDRAWELEM; - -// Enum - For Scrollbar five UI elements: -// Top (Left) arrow button. -// Top (Left) channel (or shaft). -// Thumb track button. -// Bottom (Right) channel (or shaft). -// Bottom (Right) arrow button. -typedef enum tagXSB_EAREA -{ - eNone = 0, - eTLbutton, // Top (Left) arrow button. - eBRbutton, // Bottom (Right) arrow button. - eTLchannel, // Top (Left) channel (or shaft). - eBRchannel, // Bottom (Right) channel (or shaft). - eThumb // Thumb track button. -} eXSB_AREA; - -// 'Helper' data structure - helps make the code readable. -typedef struct tagXSB_STAREA -{ - tagXSB_STAREA() { eArea = eNone; } - void operator=( eXSB_AREA e ) { eArea = e; } - void operator=( tagXSB_STAREA &st ) { eArea = st.eArea; } - - bool operator==( tagXSB_STAREA &stB ) { return ( eArea == stB.eArea ); } - bool operator!=( tagXSB_STAREA &stB ) { return ( eArea != stB.eArea ); } - - bool IsNone() { return ( eArea == eNone ); } - - bool IsButton() { return ( eArea == eTLbutton || eArea == eBRbutton ); } - - bool IsThumb() { return ( eArea == eThumb ); } - - bool IsChannel() { return ( eArea == eTLchannel || eArea == eBRchannel ); } - - bool IsLeftButton() { return ( eArea == eTLbutton ); } - - bool IsRightButton() { return ( eArea == eBRbutton ); } - - bool IsUpButton() { return ( eArea == eTLbutton ); } - - bool IsDownButton() { return ( eArea == eBRbutton ); } - - bool IsLeftChannel() { return ( eArea == eTLchannel ); } - - bool IsRightChannel() { return ( eArea == eBRchannel ); } - - bool IsUpChannel() { return ( eArea == eTLchannel ); } - - bool IsDownChannel() { return ( eArea == eBRchannel ); } - - bool IsTLButton() { return ( eArea == eTLbutton ); } - - bool IsBRButton() { return ( eArea == eBRbutton ); } - - bool IsTLChannel() { return ( eArea == eTLchannel ); } - - bool IsBRChannel() { return ( eArea == eBRchannel ); } - - eXSB_AREA eArea; // <- the only data member of this structure. -} stXSB_AREA; - -/////////////////////////////////////////////////////////////////////////// -// CXeScrollBarBase class. - -class CXeScrollBarBase : public CScrollBar -{ - DECLARE_DYNAMIC(CXeScrollBarBase) - -public: - /////////////////////////////////////////////////////////////////////////// - // Construction / destruction - - CXeScrollBarBase(); - virtual ~CXeScrollBarBase(); - - /////////////////////////////////////////////////////////////////////////// - // Create - - // Create 'this' type of scroll bar. - // [IN] dwStyle = Window style. (if SBS_VERT present a vertical scroll bar is created). - // [IN] rect = position and size of window in parent client coords. - // [IN] pParentWnd = Parent window. ASSERTs if not valid. - // [IN] uID = Control identifier. - // Returns TRUE if create was successful. - // returns FALSE if create failed. - virtual BOOL Create( DWORD dwStyle, const RECT& rect, CWnd *pParentWnd, UINT nID ); - - // Create 'this' type of scroll bar from existing (windows standard) scroll bar. - // New scroll bar is created by using the following from the existing scroll bar: - // * Window style. (if SBS_VERT present a vertical scroll bar is created). - // * Window size and position. - // * Control ID. - // * Z-order. - // * Scroll bar parameters (range, page and position). - // [IN] pParentWnd = Parent window. ASSERTs if not valid. - // [IN] nID = Control identifier of exisiting scroll bar. ASSERTs if not found. - // [IN] bUseDefaultWH = TRUE to use system default scroll bar width/height. - // = FALSE to use width/height from existing scroll bar. - // Returns TRUE if create was successful, note - existing scroll has been destroyed. - // returns FALSE if create failed. - BOOL CreateFromExisting( CWnd *pParentWnd, UINT nID, BOOL bUseDefaultWH = TRUE ); - - BOOL RegisterWindowClass(); - - /////////////////////////////////////////////////////////////////////////// - // Overrides - - // This is the only member a derived class needs to override. - // Note - derived class should NOT call DrawScrollBar in this class. - virtual void DrawScrollBar( CDC* pDC ); - -protected: - /////////////////////////////////////////////////////////////////////////// - // Message map functions - - /////////////////////////////////////////////////////////////////////////// - // Scroll bar message (SBM_XXX) handlers - - // SBM_ENABLE_ARROWS message handler. - afx_msg LRESULT OnSbmEnableArrows( WPARAM wparam, LPARAM lparam ); - - // SBM_GETPOS message handler. - afx_msg LRESULT OnSbmGetPos( WPARAM wparam, LPARAM lparam ); - - // SBM_GETRANGE message handler. - afx_msg LRESULT OnSbmGetRange( WPARAM wparam, LPARAM lparam ); - - // SBM_GETSCROLLBARINFO message handler. - afx_msg LRESULT OnSbmGetScrollBarInfo( WPARAM wparam, LPARAM lparam ); - - // SBM_GETSCROLLINFO message handler. - afx_msg LRESULT OnSbmGetScrollInfo( WPARAM wparam, LPARAM lparam ); - - // SBM_SETPOS message handler. - afx_msg LRESULT OnSbmSetPos( WPARAM wparam, LPARAM lparam ); - - // SBM_SETRANGE message handler. - afx_msg LRESULT OnSbmSetRange( WPARAM wparam, LPARAM lparam ); - - // SBM_SETRANGEREDRAW message handler. - afx_msg LRESULT OnSbmSetRangeRedraw( WPARAM wparam, LPARAM lparam ); - - // SBM_SETSCROLLINFO message handler. - afx_msg LRESULT OnSbmSetScrollInfo( WPARAM wparam, LPARAM lparam ); - - /////////////////////////////////////////////////////////////////////////// - // Paint messages - - // WM_PAINT message handler. - afx_msg void OnPaint(); - - // WM_ERASEBKGND message handler. - afx_msg BOOL OnEraseBkgnd( CDC* pDC ); - - /////////////////////////////////////////////////////////////////////////// - // Keyboard messages - - // WM_KEYDOWN message handler. - afx_msg LRESULT OnKeyDown( WPARAM wParam, LPARAM lParam ); - - // WM_KEYUP message handler. - afx_msg LRESULT OnKeyUp( WPARAM wParam, LPARAM lParam ); - - /////////////////////////////////////////////////////////////////////////// - // Mouse messages - - // WM_LBUTTONDOWN message handler. - afx_msg void OnLButtonDown( UINT nFlags, CPoint point ); - - // WM_LBUTTONUP message handler. - afx_msg void OnLButtonUp( UINT nFlags, CPoint point ); - - // WM_MOUSEWHEEL message handler. - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - - // WM_MOUSEMOVE message handler. - afx_msg void OnMouseMove( UINT nFlags, CPoint point ); - - // WM_MOUSELEAVE message handler. - afx_msg LRESULT OnMouseLeave( WPARAM wparam, LPARAM lparam ); - - /////////////////////////////////////////////////////////////////////////// - // Other messages - - // WM_GETDLGCODE message handler. - afx_msg LRESULT OnGetDlgCode( WPARAM wParam, LPARAM lParam ); - - // WM_CANCELMODE message handler. - afx_msg void OnCancelMode(); - - // WM_CONTEXTMENU message handler. - afx_msg void OnContextMenu( CWnd* pWnd, CPoint point ); - - // ON_COMMAND_RANGE message map handler - for menu commands. - afx_msg void OnMenuCommands( UINT uID ); - - // WM_TIMER message handler. - afx_msg void OnTimer(UINT_PTR nIDEvent ); - - // WM_SIZE message handler. - afx_msg void OnSize( UINT nType, int cx, int cy ); - - // WM_SETFOCUS message handler. - afx_msg void OnSetFocus( CWnd* pOldWnd ); - - // WM_KILLFOCUS message handler. - afx_msg void OnKillFocus( CWnd* pNewWnd ); - - // WM_ENABLE message handler. - afx_msg void OnEnable( BOOL bEnable ); - - /////////////////////////////////////////////////////////////////////////// - // Helpers - - // Send WM_HSCROLL or WM_VSCROLL message to parent window. - // [IN] wSBcode = SB_XXX message (LOWORD of WPARAM). - // [IN] wHiWPARAM = Scroll pos when SB_THUMBTRACK or SB_THUMBPOSITION. - virtual void SendScrollMsg( WORD wSBcode, WORD wHiWPARAM = 0 ); - - // Get UI area (element) from point. - // Returns UI area enum if point is within a UI element else eNone. - eXSB_AREA GetAreaFromPoint( CPoint point ); - - // Get 'state' of UI element. - // [IN] eElem = UI area (element). - // [OUT] eState = enumerated 'state' of requested area. - // Returns pointer to CRect of UI element or NULL if eElem invalid enum. - const CRect *GetUIelementDrawState( eXSB_AREA eElem, XSB_EDRAWELEM &eState ); - - // Calculate thumb size and position - used by RecalcRects(). - // [IN] cxyChannel = channel width or height (excluding arrow buttons). - // [OUT] xyThumb = Thumb x or y pos. (0 = first pixel in channel). - // [OUT] cxyThumb = Thumb width or height. - // Returns TRUE if channel W/H big enough for a thumb. - // Returns FALSE if no space for thumb (xyThumb and cxyThumb unchanged). - BOOL CalcThumb( int cxyChannel, int &xyThumb, int &cxyThumb ); - - // Recalculate UI elements size and positions. - // Note - thumb XY position is calculated from current scroll pos (m_nPos). - // Called from Create(...), SetScrollPos(...), SetScrollRange(...), - // SetScrollInfo(...), OnSize(...). - void RecalcRects(); - - // Recalculate thumb and channel rects - used while user is dragging the thumb. - // [IN] point = current mouse coords. in client coords. - // Returns TRUE if thumb XY position has changed, else FALSE. - // Note - Only thumb position changes, not the width/height. - // Note - called from within OnMouseMove(...). - BOOL RecalcRectsThumbTrack( CPoint point ); - - /////////////////////////////////////////////////////////////////////////// - // Data members - CWnd *m_pParent; // Parent window. - - BOOL m_bEnabled; // Window enabled state - TRUE = enabled. - // Note - Updated on WM_ENABLE message. - - BOOL m_bHasFocus; // TRUE when 'this' has input focus. - // Set TRUE in OnSetFocus. - // Set FALSE in OnKillFocus. - - BOOL m_bDrawGripper; // TRUE when 'gripper' shown on thumb box. - // FALSE when 'gripper' not drawn. - // Note - helps implement 'blinking' focus. - - BOOL m_bHorizontal; // TRUE = 'this' is horizontal scroll bar - - int m_nPos; // Current thumb position in scroll units - int m_nTrackPos; // Current thumb position (while dragging). - UINT m_uPage; // Scroll 'page' size in scroll units (min = 0). - int m_nMinPos; // Minimum scrolling position - int m_nMaxPos; // Maximum scrolling position - - BOOL m_bNoScroll; // Set TRUE if 'this' scroll bar was disabled because - // of SIF_DISABLENOSCROLL flag in SBM_SETSCROLLINFO msg. - - int m_nMaxReportedPos; // Max. pos scrollbar can report. - // = m_nMaxPos - (m_uPage - 1). - // = m_nMaxPos when m_uPage == 0. - - BOOL m_bDragging; // TRUE = thumb is being dragged - - BOOL m_bTrackMouseLeave; // TRUE when TrackMouseEvent called. - // Set FALSE when OnMouseLeave called. - - BOOL m_bNeedEndScroll; // TRUE if sending SB_ENDSCROLL is needed. - // Set TRUE in OnKeyDown if a SB_XXX message was sent. - // Set TRUE in OnLButtonDown if a SB_XXX message was sent. - // Set TRUE in OnMouseMove if a SB_XXX message was sent. - // Note - SB_ENDSCROLL is sent in OnKeyDown and in - // OnLButtonUp if m_bNeedEndScroll is TRUE. - - stXSB_AREA m_eMouseOverArea; // Where mouse is 'now'. - stXSB_AREA m_eMouseDownArea; // Where mouse is when L btn down. - - CPoint m_ptMenu; // Client coords. of context menu. - // Needed for 'Scroll Here' command. - - //=================================================================================== - // These vars. are calculated when RecalcRects() called. - CRect m_rectClient; // client rect - updated when RecalcRects() called. - CRect m_rectThumb; // current rect for thumb - CRect m_rectTLArrow; // top or left arrow rect - CRect m_rectBRArrow; // bottom or right arrow rect - CRect m_rectTLChannel; // top or left channel rect - CRect m_rectBRChannel; // bottom or right channel rect - - double m_dblPx_SU; // Number of pixels in one scroll unit. - // Note - not valid unless m_rectThumb is not empty. - //=================================================================================== - - UINT m_uArrowWH; // width or height of arrow button - // - set by derived class. - // If = 0 and Horz - // button width = client area height. - // If = 0 and Vert - // button height = client area width. - // Set to 0 by ctor. - UINT GetCXYarrow(); - - UINT m_uThumbMinHW; // Minimum width or height of thumb (pixels). - // Set to 8 pixels by ctor. - - int m_xyThumbDragOffset;// Offset (x or y) into m_rectThumb. - // When user presses L button down in the thumb - we need to capture the - // relative X or Y position of the mouse cursor in m_rectThumb. - // This is used while dragging so mouse x or y rel. pos. in thumb is unchanged. - - /////////////////////////////////////////////////////////////////////////// - - UINT scrollLines; //added to support multiple rows per mouse notch - - DECLARE_MESSAGE_MAP() -}; - - +#pragma once + +/**************************************************************************************** +CXeScrollBarBase class. +This class implements a very close copy of the standard windows scroll bar. +This class is designed as a base class for another class that will do all painting. +This class handles all the business logic. +No painting is done in this class - except in debug mode. + +The derived class needs to do the following: +* MUST override DrawScrollBar member function to do all the painting. + Example: + Create memory DC - same size as client area. + XSB_EDRAWELEM eState; + const CRect *prcElem = 0; + stXSB_AREA stArea; + for( int nElem = eTLbutton; nElem <= eThumb; nElem++ ) // loop through all UI elements. + { + stArea.eArea = (eXSB_AREA)nElem; + + // Get bounding rect of UI element to draw (client coords.) + prcElem = GetUIelementDrawState( stArea.eArea, eState ); + if( !prcElem || eState == eNotDrawn ) // Rect empty or area not drawn? + continue; + + // stArea.eArea identifies UI element to draw: + // eTLbutton or eTLchannel or eThumb or eBRchannel or eBRbutton. + + // eState identifes in what state the UI element is drawn: + // eDisabled or eNormal or eDown or eHot. + + // m_bHorizontal is TRUE if 'this' is a horizontal scroll bar. + + // Draw UI element to memory DC. (using prcElem rect). + // Note - use m_bDrawGripper to determine if 'gripper' is drawn on thumb box. + // This is used to implement 'blinking' to show scroll bar has input + // focus. (every 500mS). + } + Copy memory DC to pDC. + +* (optional) Set m_uArrowWH to the width of the arrow button in horizontal scrollbar, + note - height of arrow button in vertical scrollbar is the same. + If this member is left unchanged (= 0) the arrow button width in horizontal scrollbar + is assumed to be equal to the height of the window. Same for vertical scroll bar + except the width of the window is arrow button height. + This number is needed to calculate sizes of other UI elements of the scroll bar. + +* (optional) Set m_uThumbMinHW to the minimum allowed width of the thumb box in a + horizontal scroll bar, this value is also the minimum height of the thumb box in a + vertical scroll bar. The default is 8 pixels. +****************************************************************************************/ + +// Enum - UI element state - helps with drawing scrollbar. +typedef enum tagXSB_EDRAWELEM +{ + eNotDrawn = 0, // UI element is not visible. (UI Rect empty). + eDisabled, // Element should be drawn in disabled state. + eNormal, // Element should be drawn in normal state. + eDown, // Element should be drawn in down state. + eHot // Element should be drawn in hot state. + // Note - Scroll bar channel is usually not drawn 'hot'. +} XSB_EDRAWELEM; + +// Enum - For Scrollbar five UI elements: +// Top (Left) arrow button. +// Top (Left) channel (or shaft). +// Thumb track button. +// Bottom (Right) channel (or shaft). +// Bottom (Right) arrow button. +typedef enum tagXSB_EAREA +{ + eNone = 0, + eTLbutton, // Top (Left) arrow button. + eBRbutton, // Bottom (Right) arrow button. + eTLchannel, // Top (Left) channel (or shaft). + eBRchannel, // Bottom (Right) channel (or shaft). + eThumb // Thumb track button. +} eXSB_AREA; + +// 'Helper' data structure - helps make the code readable. +typedef struct tagXSB_STAREA +{ + tagXSB_STAREA() { eArea = eNone; } + void operator=( eXSB_AREA e ) { eArea = e; } + void operator=( tagXSB_STAREA &st ) { eArea = st.eArea; } + + bool operator==( tagXSB_STAREA &stB ) { return ( eArea == stB.eArea ); } + bool operator!=( tagXSB_STAREA &stB ) { return ( eArea != stB.eArea ); } + + bool IsNone() { return ( eArea == eNone ); } + + bool IsButton() { return ( eArea == eTLbutton || eArea == eBRbutton ); } + + bool IsThumb() { return ( eArea == eThumb ); } + + bool IsChannel() { return ( eArea == eTLchannel || eArea == eBRchannel ); } + + bool IsLeftButton() { return ( eArea == eTLbutton ); } + + bool IsRightButton() { return ( eArea == eBRbutton ); } + + bool IsUpButton() { return ( eArea == eTLbutton ); } + + bool IsDownButton() { return ( eArea == eBRbutton ); } + + bool IsLeftChannel() { return ( eArea == eTLchannel ); } + + bool IsRightChannel() { return ( eArea == eBRchannel ); } + + bool IsUpChannel() { return ( eArea == eTLchannel ); } + + bool IsDownChannel() { return ( eArea == eBRchannel ); } + + bool IsTLButton() { return ( eArea == eTLbutton ); } + + bool IsBRButton() { return ( eArea == eBRbutton ); } + + bool IsTLChannel() { return ( eArea == eTLchannel ); } + + bool IsBRChannel() { return ( eArea == eBRchannel ); } + + eXSB_AREA eArea; // <- the only data member of this structure. +} stXSB_AREA; + +/////////////////////////////////////////////////////////////////////////// +// CXeScrollBarBase class. + +class CXeScrollBarBase : public CScrollBar +{ + DECLARE_DYNAMIC(CXeScrollBarBase) + +public: + /////////////////////////////////////////////////////////////////////////// + // Construction / destruction + + CXeScrollBarBase(); + virtual ~CXeScrollBarBase(); + + /////////////////////////////////////////////////////////////////////////// + // Create + + // Create 'this' type of scroll bar. + // [IN] dwStyle = Window style. (if SBS_VERT present a vertical scroll bar is created). + // [IN] rect = position and size of window in parent client coords. + // [IN] pParentWnd = Parent window. ASSERTs if not valid. + // [IN] uID = Control identifier. + // Returns TRUE if create was successful. + // returns FALSE if create failed. + virtual BOOL Create( DWORD dwStyle, const RECT& rect, CWnd *pParentWnd, UINT nID ); + + // Create 'this' type of scroll bar from existing (windows standard) scroll bar. + // New scroll bar is created by using the following from the existing scroll bar: + // * Window style. (if SBS_VERT present a vertical scroll bar is created). + // * Window size and position. + // * Control ID. + // * Z-order. + // * Scroll bar parameters (range, page and position). + // [IN] pParentWnd = Parent window. ASSERTs if not valid. + // [IN] nID = Control identifier of exisiting scroll bar. ASSERTs if not found. + // [IN] bUseDefaultWH = TRUE to use system default scroll bar width/height. + // = FALSE to use width/height from existing scroll bar. + // Returns TRUE if create was successful, note - existing scroll has been destroyed. + // returns FALSE if create failed. + BOOL CreateFromExisting( CWnd *pParentWnd, UINT nID, BOOL bUseDefaultWH = TRUE ); + + BOOL RegisterWindowClass(); + + /////////////////////////////////////////////////////////////////////////// + // Overrides + + // This is the only member a derived class needs to override. + // Note - derived class should NOT call DrawScrollBar in this class. + virtual void DrawScrollBar( CDC* pDC ); + +protected: + /////////////////////////////////////////////////////////////////////////// + // Message map functions + + /////////////////////////////////////////////////////////////////////////// + // Scroll bar message (SBM_XXX) handlers + + // SBM_ENABLE_ARROWS message handler. + afx_msg LRESULT OnSbmEnableArrows( WPARAM wparam, LPARAM lparam ); + + // SBM_GETPOS message handler. + afx_msg LRESULT OnSbmGetPos( WPARAM wparam, LPARAM lparam ); + + // SBM_GETRANGE message handler. + afx_msg LRESULT OnSbmGetRange( WPARAM wparam, LPARAM lparam ); + + // SBM_GETSCROLLBARINFO message handler. + afx_msg LRESULT OnSbmGetScrollBarInfo( WPARAM wparam, LPARAM lparam ); + + // SBM_GETSCROLLINFO message handler. + afx_msg LRESULT OnSbmGetScrollInfo( WPARAM wparam, LPARAM lparam ); + + // SBM_SETPOS message handler. + afx_msg LRESULT OnSbmSetPos( WPARAM wparam, LPARAM lparam ); + + // SBM_SETRANGE message handler. + afx_msg LRESULT OnSbmSetRange( WPARAM wparam, LPARAM lparam ); + + // SBM_SETRANGEREDRAW message handler. + afx_msg LRESULT OnSbmSetRangeRedraw( WPARAM wparam, LPARAM lparam ); + + // SBM_SETSCROLLINFO message handler. + afx_msg LRESULT OnSbmSetScrollInfo( WPARAM wparam, LPARAM lparam ); + + /////////////////////////////////////////////////////////////////////////// + // Paint messages + + // WM_PAINT message handler. + afx_msg void OnPaint(); + + // WM_ERASEBKGND message handler. + afx_msg BOOL OnEraseBkgnd( CDC* pDC ); + + /////////////////////////////////////////////////////////////////////////// + // Keyboard messages + + // WM_KEYDOWN message handler. + afx_msg LRESULT OnKeyDown( WPARAM wParam, LPARAM lParam ); + + // WM_KEYUP message handler. + afx_msg LRESULT OnKeyUp( WPARAM wParam, LPARAM lParam ); + + /////////////////////////////////////////////////////////////////////////// + // Mouse messages + + // WM_LBUTTONDOWN message handler. + afx_msg void OnLButtonDown( UINT nFlags, CPoint point ); + + // WM_LBUTTONUP message handler. + afx_msg void OnLButtonUp( UINT nFlags, CPoint point ); + + // WM_MOUSEWHEEL message handler. + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + + // WM_MOUSEMOVE message handler. + afx_msg void OnMouseMove( UINT nFlags, CPoint point ); + + // WM_MOUSELEAVE message handler. + afx_msg LRESULT OnMouseLeave( WPARAM wparam, LPARAM lparam ); + + /////////////////////////////////////////////////////////////////////////// + // Other messages + + // WM_GETDLGCODE message handler. + afx_msg LRESULT OnGetDlgCode( WPARAM wParam, LPARAM lParam ); + + // WM_CANCELMODE message handler. + afx_msg void OnCancelMode(); + + // WM_CONTEXTMENU message handler. + afx_msg void OnContextMenu( CWnd* pWnd, CPoint point ); + + // ON_COMMAND_RANGE message map handler - for menu commands. + afx_msg void OnMenuCommands( UINT uID ); + + // WM_TIMER message handler. + afx_msg void OnTimer(UINT_PTR nIDEvent ); + + // WM_SIZE message handler. + afx_msg void OnSize( UINT nType, int cx, int cy ); + + // WM_SETFOCUS message handler. + afx_msg void OnSetFocus( CWnd* pOldWnd ); + + // WM_KILLFOCUS message handler. + afx_msg void OnKillFocus( CWnd* pNewWnd ); + + // WM_ENABLE message handler. + afx_msg void OnEnable( BOOL bEnable ); + + /////////////////////////////////////////////////////////////////////////// + // Helpers + + // Send WM_HSCROLL or WM_VSCROLL message to parent window. + // [IN] wSBcode = SB_XXX message (LOWORD of WPARAM). + // [IN] wHiWPARAM = Scroll pos when SB_THUMBTRACK or SB_THUMBPOSITION. + virtual void SendScrollMsg( WORD wSBcode, WORD wHiWPARAM = 0 ); + + // Get UI area (element) from point. + // Returns UI area enum if point is within a UI element else eNone. + eXSB_AREA GetAreaFromPoint( CPoint point ); + + // Get 'state' of UI element. + // [IN] eElem = UI area (element). + // [OUT] eState = enumerated 'state' of requested area. + // Returns pointer to CRect of UI element or NULL if eElem invalid enum. + const CRect *GetUIelementDrawState( eXSB_AREA eElem, XSB_EDRAWELEM &eState ); + + // Calculate thumb size and position - used by RecalcRects(). + // [IN] cxyChannel = channel width or height (excluding arrow buttons). + // [OUT] xyThumb = Thumb x or y pos. (0 = first pixel in channel). + // [OUT] cxyThumb = Thumb width or height. + // Returns TRUE if channel W/H big enough for a thumb. + // Returns FALSE if no space for thumb (xyThumb and cxyThumb unchanged). + BOOL CalcThumb( int cxyChannel, int &xyThumb, int &cxyThumb ); + + // Recalculate UI elements size and positions. + // Note - thumb XY position is calculated from current scroll pos (m_nPos). + // Called from Create(...), SetScrollPos(...), SetScrollRange(...), + // SetScrollInfo(...), OnSize(...). + void RecalcRects(); + + // Recalculate thumb and channel rects - used while user is dragging the thumb. + // [IN] point = current mouse coords. in client coords. + // Returns TRUE if thumb XY position has changed, else FALSE. + // Note - Only thumb position changes, not the width/height. + // Note - called from within OnMouseMove(...). + BOOL RecalcRectsThumbTrack( CPoint point ); + + /////////////////////////////////////////////////////////////////////////// + // Data members + CWnd *m_pParent; // Parent window. + + BOOL m_bEnabled; // Window enabled state - TRUE = enabled. + // Note - Updated on WM_ENABLE message. + + BOOL m_bHasFocus; // TRUE when 'this' has input focus. + // Set TRUE in OnSetFocus. + // Set FALSE in OnKillFocus. + + BOOL m_bDrawGripper; // TRUE when 'gripper' shown on thumb box. + // FALSE when 'gripper' not drawn. + // Note - helps implement 'blinking' focus. + + BOOL m_bHorizontal; // TRUE = 'this' is horizontal scroll bar + + int m_nPos; // Current thumb position in scroll units + int m_nTrackPos; // Current thumb position (while dragging). + UINT m_uPage; // Scroll 'page' size in scroll units (min = 0). + int m_nMinPos; // Minimum scrolling position + int m_nMaxPos; // Maximum scrolling position + + BOOL m_bNoScroll; // Set TRUE if 'this' scroll bar was disabled because + // of SIF_DISABLENOSCROLL flag in SBM_SETSCROLLINFO msg. + + int m_nMaxReportedPos; // Max. pos scrollbar can report. + // = m_nMaxPos - (m_uPage - 1). + // = m_nMaxPos when m_uPage == 0. + + BOOL m_bDragging; // TRUE = thumb is being dragged + + BOOL m_bTrackMouseLeave; // TRUE when TrackMouseEvent called. + // Set FALSE when OnMouseLeave called. + + BOOL m_bNeedEndScroll; // TRUE if sending SB_ENDSCROLL is needed. + // Set TRUE in OnKeyDown if a SB_XXX message was sent. + // Set TRUE in OnLButtonDown if a SB_XXX message was sent. + // Set TRUE in OnMouseMove if a SB_XXX message was sent. + // Note - SB_ENDSCROLL is sent in OnKeyDown and in + // OnLButtonUp if m_bNeedEndScroll is TRUE. + + stXSB_AREA m_eMouseOverArea; // Where mouse is 'now'. + stXSB_AREA m_eMouseDownArea; // Where mouse is when L btn down. + + CPoint m_ptMenu; // Client coords. of context menu. + // Needed for 'Scroll Here' command. + + //=================================================================================== + // These vars. are calculated when RecalcRects() called. + CRect m_rectClient; // client rect - updated when RecalcRects() called. + CRect m_rectThumb; // current rect for thumb + CRect m_rectTLArrow; // top or left arrow rect + CRect m_rectBRArrow; // bottom or right arrow rect + CRect m_rectTLChannel; // top or left channel rect + CRect m_rectBRChannel; // bottom or right channel rect + + double m_dblPx_SU; // Number of pixels in one scroll unit. + // Note - not valid unless m_rectThumb is not empty. + //=================================================================================== + + UINT m_uArrowWH; // width or height of arrow button + // - set by derived class. + // If = 0 and Horz + // button width = client area height. + // If = 0 and Vert + // button height = client area width. + // Set to 0 by ctor. + UINT GetCXYarrow(); + + UINT m_uThumbMinHW; // Minimum width or height of thumb (pixels). + // Set to 8 pixels by ctor. + + int m_xyThumbDragOffset;// Offset (x or y) into m_rectThumb. + // When user presses L button down in the thumb - we need to capture the + // relative X or Y position of the mouse cursor in m_rectThumb. + // This is used while dragging so mouse x or y rel. pos. in thumb is unchanged. + + /////////////////////////////////////////////////////////////////////////// + + UINT scrollLines; //added to support multiple rows per mouse notch + + DECLARE_MESSAGE_MAP() +}; + + diff --git a/src/thirdparty/lcms2/lcms2.vcxproj b/src/thirdparty/lcms2/lcms2.vcxproj index a9324e7992d..d4eba961026 100644 --- a/src/thirdparty/lcms2/lcms2.vcxproj +++ b/src/thirdparty/lcms2/lcms2.vcxproj @@ -1,88 +1,88 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {ACF5C64B-78AA-4730-91A2-24F4910FBAD9} - Win32Proj - lcms2 - lcms2 - - - - - StaticLibrary - Unicode - - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - library\include;library\src - lcms2_internal.h - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {ACF5C64B-78AA-4730-91A2-24F4910FBAD9} + Win32Proj + lcms2 + lcms2 + + + + + StaticLibrary + Unicode + + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + library\include;library\src + lcms2_internal.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + \ No newline at end of file diff --git a/src/thirdparty/lcms2/lcms2.vcxproj.filters b/src/thirdparty/lcms2/lcms2.vcxproj.filters index 781d672b6bf..6587959dda5 100644 --- a/src/thirdparty/lcms2/lcms2.vcxproj.filters +++ b/src/thirdparty/lcms2/lcms2.vcxproj.filters @@ -1,107 +1,107 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Header Files - - - Header Files - - - Source Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/src/thirdparty/sizecbar/scbarcf.cpp b/src/thirdparty/sizecbar/scbarcf.cpp index d5a965e643b..23c7be1d20d 100644 --- a/src/thirdparty/sizecbar/scbarcf.cpp +++ b/src/thirdparty/sizecbar/scbarcf.cpp @@ -1,234 +1,234 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBarCF Version 2.44 -// -// Created: Dec 21, 1998 Last Modified: March 31, 2002 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2002 by Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// You must obtain the author's consent before you can include this code -// in a software library. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com or post them at the message board at the site. -///////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "scbarcf.h" - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarCF - -IMPLEMENT_DYNAMIC(CSizingControlBarCF, baseCSizingControlBarCF); - -int CALLBACK EnumFontFamProc(ENUMLOGFONT FAR *lpelf, - NEWTEXTMETRIC FAR *lpntm, - int FontType, - LPARAM lParam) -{ - UNUSED_ALWAYS(lpelf); - UNUSED_ALWAYS(lpntm); - UNUSED_ALWAYS(FontType); - UNUSED_ALWAYS(lParam); - - return 0; -} - -CSizingControlBarCF::CSizingControlBarCF() -{ - m_bActive = FALSE; - - CDC dc; - dc.CreateCompatibleDC(NULL); - - m_sFontFace = (::EnumFontFamilies(dc.m_hDC, - _T("Tahoma"), (FONTENUMPROC) EnumFontFamProc, 0) == 0) ? - _T("Tahoma") : _T("Arial"); - - dc.DeleteDC(); - -} - -BEGIN_MESSAGE_MAP(CSizingControlBarCF, baseCSizingControlBarCF) - //{{AFX_MSG_MAP(CSizingControlBarCF) - //}}AFX_MSG_MAP - ON_MESSAGE(WM_SETTEXT, OnSetText) -END_MESSAGE_MAP() - -void CSizingControlBarCF::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) -{ - baseCSizingControlBarCF::OnUpdateCmdUI(pTarget, bDisableIfNoHndler); - - if (!HasGripper()) - return; - - BOOL bNeedPaint = FALSE; - - CWnd* pFocus = GetFocus(); - BOOL bActiveOld = m_bActive; - - m_bActive = (pFocus->GetSafeHwnd() && IsChild(pFocus)); - - if (m_bActive != bActiveOld) - bNeedPaint = TRUE; - - if (bNeedPaint) - SendMessage(WM_NCPAINT); -} - -// gradient defines (if not already defined) -#ifndef COLOR_GRADIENTACTIVECAPTION -#define COLOR_GRADIENTACTIVECAPTION 27 -#define COLOR_GRADIENTINACTIVECAPTION 28 -#define SPI_GETGRADIENTCAPTIONS 0x1008 -#endif - -void CSizingControlBarCF::NcPaintGripper(CDC* pDC, CRect rcClient) -{ - if (!HasGripper()) - return; - - // compute the caption rectangle - BOOL bHorz = IsHorzDocked(); - CRect rcGrip = rcClient; - CRect rcBtn = m_biHide.GetRect(); - if (bHorz) - { // right side gripper - rcGrip.left -= m_cyGripper + 1; - rcGrip.right = rcGrip.left + 11; - rcGrip.top = rcBtn.bottom + 3; - } - else - { // gripper at top - rcGrip.top -= m_cyGripper + 1; - rcGrip.bottom = rcGrip.top + 11; - rcGrip.right = rcBtn.left - 3; - } - rcGrip.InflateRect(bHorz ? 1 : 0, bHorz ? 0 : 1); - - // draw the caption background - //CBrush br; - COLORREF clrCptn = m_bActive ? - ::GetSysColor(COLOR_ACTIVECAPTION) : - ::GetSysColor(COLOR_INACTIVECAPTION); - - // query gradient info (usually TRUE for Win98/Win2k) - BOOL bGradient = FALSE; - ::SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &bGradient, 0); - - if (!bGradient) - pDC->FillSolidRect(&rcGrip, clrCptn); // solid color - else - { - // gradient from left to right or from bottom to top - // get second gradient color (the right end) - COLORREF clrCptnRight = m_bActive ? - ::GetSysColor(COLOR_GRADIENTACTIVECAPTION) : - ::GetSysColor(COLOR_GRADIENTINACTIVECAPTION); - - // this will make 2^6 = 64 fountain steps - int nShift = 6; - int nSteps = 1 << nShift; - - for (int i = 0; i < nSteps; i++) - { - // do a little alpha blending - int nR = (GetRValue(clrCptn) * (nSteps - i) + - GetRValue(clrCptnRight) * i) >> nShift; - int nG = (GetGValue(clrCptn) * (nSteps - i) + - GetGValue(clrCptnRight) * i) >> nShift; - int nB = (GetBValue(clrCptn) * (nSteps - i) + - GetBValue(clrCptnRight) * i) >> nShift; - - COLORREF cr = RGB(nR, nG, nB); - - // then paint with the resulting color - CRect r2 = rcGrip; - if (bHorz) - { - r2.bottom = rcGrip.bottom - - ((i * rcGrip.Height()) >> nShift); - r2.top = rcGrip.bottom - - (((i + 1) * rcGrip.Height()) >> nShift); - if (r2.Height() > 0) - pDC->FillSolidRect(r2, cr); - } - else - { - r2.left = rcGrip.left + - ((i * rcGrip.Width()) >> nShift); - r2.right = rcGrip.left + - (((i + 1) * rcGrip.Width()) >> nShift); - if (r2.Width() > 0) - pDC->FillSolidRect(r2, cr); - } - } - } - - // draw the caption text - first select a font - CFont font; - int ppi = pDC->GetDeviceCaps(LOGPIXELSX); - int pointsize = MulDiv(85, 96, ppi); // 8.5 points at 96 ppi - - LOGFONT lf; - BOOL bFont = font.CreatePointFont(pointsize, m_sFontFace); - if (bFont) - { - // get the text color - COLORREF clrCptnText = m_bActive ? - ::GetSysColor(COLOR_CAPTIONTEXT) : - ::GetSysColor(COLOR_INACTIVECAPTIONTEXT); - - int nOldBkMode = pDC->SetBkMode(TRANSPARENT); - COLORREF clrOldText = pDC->SetTextColor(clrCptnText); - - if (bHorz) - { - // rotate text 90 degrees CCW if horizontally docked - font.GetLogFont(&lf); - font.DeleteObject(); - lf.lfEscapement = 900; - font.CreateFontIndirect(&lf); - } - - CFont* pOldFont = pDC->SelectObject(&font); - CString sTitle; - GetWindowText(sTitle); - - CPoint ptOrg = bHorz ? - CPoint(rcGrip.left - 1, rcGrip.bottom - 3) : - CPoint(rcGrip.left + 3, rcGrip.top - 1); - - pDC->ExtTextOut(ptOrg.x, ptOrg.y, - ETO_CLIPPED, rcGrip, sTitle, NULL); - - pDC->SelectObject(pOldFont); - pDC->SetBkMode(nOldBkMode); - pDC->SetTextColor(clrOldText); - } - - // draw the button - m_biHide.Paint(pDC); -} - -LRESULT CSizingControlBarCF::OnSetText(WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = baseCSizingControlBarCF::OnSetText(wParam, lParam); - - SendMessage(WM_NCPAINT); - - return lResult; -} +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBarCF Version 2.44 +// +// Created: Dec 21, 1998 Last Modified: March 31, 2002 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2002 by Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// You must obtain the author's consent before you can include this code +// in a software library. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com or post them at the message board at the site. +///////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "scbarcf.h" + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarCF + +IMPLEMENT_DYNAMIC(CSizingControlBarCF, baseCSizingControlBarCF); + +int CALLBACK EnumFontFamProc(ENUMLOGFONT FAR *lpelf, + NEWTEXTMETRIC FAR *lpntm, + int FontType, + LPARAM lParam) +{ + UNUSED_ALWAYS(lpelf); + UNUSED_ALWAYS(lpntm); + UNUSED_ALWAYS(FontType); + UNUSED_ALWAYS(lParam); + + return 0; +} + +CSizingControlBarCF::CSizingControlBarCF() +{ + m_bActive = FALSE; + + CDC dc; + dc.CreateCompatibleDC(NULL); + + m_sFontFace = (::EnumFontFamilies(dc.m_hDC, + _T("Tahoma"), (FONTENUMPROC) EnumFontFamProc, 0) == 0) ? + _T("Tahoma") : _T("Arial"); + + dc.DeleteDC(); + +} + +BEGIN_MESSAGE_MAP(CSizingControlBarCF, baseCSizingControlBarCF) + //{{AFX_MSG_MAP(CSizingControlBarCF) + //}}AFX_MSG_MAP + ON_MESSAGE(WM_SETTEXT, OnSetText) +END_MESSAGE_MAP() + +void CSizingControlBarCF::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) +{ + baseCSizingControlBarCF::OnUpdateCmdUI(pTarget, bDisableIfNoHndler); + + if (!HasGripper()) + return; + + BOOL bNeedPaint = FALSE; + + CWnd* pFocus = GetFocus(); + BOOL bActiveOld = m_bActive; + + m_bActive = (pFocus->GetSafeHwnd() && IsChild(pFocus)); + + if (m_bActive != bActiveOld) + bNeedPaint = TRUE; + + if (bNeedPaint) + SendMessage(WM_NCPAINT); +} + +// gradient defines (if not already defined) +#ifndef COLOR_GRADIENTACTIVECAPTION +#define COLOR_GRADIENTACTIVECAPTION 27 +#define COLOR_GRADIENTINACTIVECAPTION 28 +#define SPI_GETGRADIENTCAPTIONS 0x1008 +#endif + +void CSizingControlBarCF::NcPaintGripper(CDC* pDC, CRect rcClient) +{ + if (!HasGripper()) + return; + + // compute the caption rectangle + BOOL bHorz = IsHorzDocked(); + CRect rcGrip = rcClient; + CRect rcBtn = m_biHide.GetRect(); + if (bHorz) + { // right side gripper + rcGrip.left -= m_cyGripper + 1; + rcGrip.right = rcGrip.left + 11; + rcGrip.top = rcBtn.bottom + 3; + } + else + { // gripper at top + rcGrip.top -= m_cyGripper + 1; + rcGrip.bottom = rcGrip.top + 11; + rcGrip.right = rcBtn.left - 3; + } + rcGrip.InflateRect(bHorz ? 1 : 0, bHorz ? 0 : 1); + + // draw the caption background + //CBrush br; + COLORREF clrCptn = m_bActive ? + ::GetSysColor(COLOR_ACTIVECAPTION) : + ::GetSysColor(COLOR_INACTIVECAPTION); + + // query gradient info (usually TRUE for Win98/Win2k) + BOOL bGradient = FALSE; + ::SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &bGradient, 0); + + if (!bGradient) + pDC->FillSolidRect(&rcGrip, clrCptn); // solid color + else + { + // gradient from left to right or from bottom to top + // get second gradient color (the right end) + COLORREF clrCptnRight = m_bActive ? + ::GetSysColor(COLOR_GRADIENTACTIVECAPTION) : + ::GetSysColor(COLOR_GRADIENTINACTIVECAPTION); + + // this will make 2^6 = 64 fountain steps + int nShift = 6; + int nSteps = 1 << nShift; + + for (int i = 0; i < nSteps; i++) + { + // do a little alpha blending + int nR = (GetRValue(clrCptn) * (nSteps - i) + + GetRValue(clrCptnRight) * i) >> nShift; + int nG = (GetGValue(clrCptn) * (nSteps - i) + + GetGValue(clrCptnRight) * i) >> nShift; + int nB = (GetBValue(clrCptn) * (nSteps - i) + + GetBValue(clrCptnRight) * i) >> nShift; + + COLORREF cr = RGB(nR, nG, nB); + + // then paint with the resulting color + CRect r2 = rcGrip; + if (bHorz) + { + r2.bottom = rcGrip.bottom - + ((i * rcGrip.Height()) >> nShift); + r2.top = rcGrip.bottom - + (((i + 1) * rcGrip.Height()) >> nShift); + if (r2.Height() > 0) + pDC->FillSolidRect(r2, cr); + } + else + { + r2.left = rcGrip.left + + ((i * rcGrip.Width()) >> nShift); + r2.right = rcGrip.left + + (((i + 1) * rcGrip.Width()) >> nShift); + if (r2.Width() > 0) + pDC->FillSolidRect(r2, cr); + } + } + } + + // draw the caption text - first select a font + CFont font; + int ppi = pDC->GetDeviceCaps(LOGPIXELSX); + int pointsize = MulDiv(85, 96, ppi); // 8.5 points at 96 ppi + + LOGFONT lf; + BOOL bFont = font.CreatePointFont(pointsize, m_sFontFace); + if (bFont) + { + // get the text color + COLORREF clrCptnText = m_bActive ? + ::GetSysColor(COLOR_CAPTIONTEXT) : + ::GetSysColor(COLOR_INACTIVECAPTIONTEXT); + + int nOldBkMode = pDC->SetBkMode(TRANSPARENT); + COLORREF clrOldText = pDC->SetTextColor(clrCptnText); + + if (bHorz) + { + // rotate text 90 degrees CCW if horizontally docked + font.GetLogFont(&lf); + font.DeleteObject(); + lf.lfEscapement = 900; + font.CreateFontIndirect(&lf); + } + + CFont* pOldFont = pDC->SelectObject(&font); + CString sTitle; + GetWindowText(sTitle); + + CPoint ptOrg = bHorz ? + CPoint(rcGrip.left - 1, rcGrip.bottom - 3) : + CPoint(rcGrip.left + 3, rcGrip.top - 1); + + pDC->ExtTextOut(ptOrg.x, ptOrg.y, + ETO_CLIPPED, rcGrip, sTitle, NULL); + + pDC->SelectObject(pOldFont); + pDC->SetBkMode(nOldBkMode); + pDC->SetTextColor(clrOldText); + } + + // draw the button + m_biHide.Paint(pDC); +} + +LRESULT CSizingControlBarCF::OnSetText(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = baseCSizingControlBarCF::OnSetText(wParam, lParam); + + SendMessage(WM_NCPAINT); + + return lResult; +} diff --git a/src/thirdparty/sizecbar/scbarcf.h b/src/thirdparty/sizecbar/scbarcf.h index e5c20d2463e..9788fd5cbfc 100644 --- a/src/thirdparty/sizecbar/scbarcf.h +++ b/src/thirdparty/sizecbar/scbarcf.h @@ -1,78 +1,78 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBarCF Version 2.44 -// -// Created: Dec 21, 1998 Last Modified: March 31, 2002 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2002 by Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// You must obtain the author's consent before you can include this code -// in a software library. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com or post them at the message board at the site. -///////////////////////////////////////////////////////////////////////// - -#if !defined(__SCBARCF_H__) -#define __SCBARCF_H__ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 -// scbarcf.h : header file -// - -#include "scbarg.h" - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarCF - -#ifndef baseCSizingControlBarCF -#define baseCSizingControlBarCF CSizingControlBarG -#endif - -class CSizingControlBarCF : public baseCSizingControlBarCF -{ - DECLARE_DYNAMIC(CSizingControlBarCF) - -// Construction -public: - CSizingControlBarCF(); - -// Overridables - virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); - -// Implementation -protected: - // implementation helpers - virtual void NcPaintGripper(CDC* pDC, CRect rcClient); - -protected: - BOOL m_bActive; // a child has focus - CString m_sFontFace; - -// Generated message map functions -protected: - //{{AFX_MSG(CSizingControlBarCF) - //}}AFX_MSG - afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam); - - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////// - -#endif // !defined(__SCBARCF_H__) +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBarCF Version 2.44 +// +// Created: Dec 21, 1998 Last Modified: March 31, 2002 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2002 by Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// You must obtain the author's consent before you can include this code +// in a software library. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com or post them at the message board at the site. +///////////////////////////////////////////////////////////////////////// + +#if !defined(__SCBARCF_H__) +#define __SCBARCF_H__ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// scbarcf.h : header file +// + +#include "scbarg.h" + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarCF + +#ifndef baseCSizingControlBarCF +#define baseCSizingControlBarCF CSizingControlBarG +#endif + +class CSizingControlBarCF : public baseCSizingControlBarCF +{ + DECLARE_DYNAMIC(CSizingControlBarCF) + +// Construction +public: + CSizingControlBarCF(); + +// Overridables + virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); + +// Implementation +protected: + // implementation helpers + virtual void NcPaintGripper(CDC* pDC, CRect rcClient); + +protected: + BOOL m_bActive; // a child has focus + CString m_sFontFace; + +// Generated message map functions +protected: + //{{AFX_MSG(CSizingControlBarCF) + //}}AFX_MSG + afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////// + +#endif // !defined(__SCBARCF_H__) diff --git a/src/thirdparty/sizecbar/scbarg.cpp b/src/thirdparty/sizecbar/scbarg.cpp index 5922940460e..5e9c249c64a 100644 --- a/src/thirdparty/sizecbar/scbarg.cpp +++ b/src/thirdparty/sizecbar/scbarg.cpp @@ -1,256 +1,256 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBarG Version 2.45 -// -// Created: Jan 24, 1998 Last Modified: April 16, 2010 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com . -///////////////////////////////////////////////////////////////////////// - -// sizecbar.cpp : implementation file -// - -#include "stdafx.h" -#include "scbarg.h" - - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarG - -IMPLEMENT_DYNAMIC(CSizingControlBarG, baseCSizingControlBarG); - -CSizingControlBarG::CSizingControlBarG() -{ - m_cyGripper = 12; -} - -CSizingControlBarG::~CSizingControlBarG() -{ -} - -BEGIN_MESSAGE_MAP(CSizingControlBarG, baseCSizingControlBarG) - //{{AFX_MSG_MAP(CSizingControlBarG) - ON_WM_NCLBUTTONUP() - ON_WM_NCHITTEST() - //}}AFX_MSG_MAP - ON_MESSAGE(WM_SETTEXT, OnSetText) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarG message handlers - -///////////////////////////////////////////////////////////////////////// -// Mouse Handling -// - -void CSizingControlBarG::OnNcLButtonUp(UINT nHitTest, CPoint point) -{ - if (nHitTest == HTCLOSE) - m_pDockSite->ShowControlBar(this, FALSE, FALSE); // hide - - baseCSizingControlBarG::OnNcLButtonUp(nHitTest, point); -} - -void CSizingControlBarG::NcCalcClient(LPRECT pRc, UINT nDockBarID) -{ - CRect rcBar(pRc); // save the bar rect - - // subtract edges - baseCSizingControlBarG::NcCalcClient(pRc, nDockBarID); - - if (!HasGripper()) - return; - - CRect rc(pRc); // the client rect as calculated by the base class - //mpc-hc custom code start - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ClientToScreen(rcBar); - GetParent()->ClientToScreen(rc); - //mpc-hc custom code end - - BOOL bHorz = (nDockBarID == AFX_IDW_DOCKBAR_TOP) || - (nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); - - if (bHorz) - rc.DeflateRect(m_cyGripper, 0, 0, 0); - else - rc.DeflateRect(0, m_cyGripper, 0, 0); - - // set position for the "x" (hide bar) button - CPoint ptOrgBtn; - if (bHorz) - ptOrgBtn = CPoint(rc.left - 13, rc.top); - else - ptOrgBtn = CPoint(rc.right - 12, rc.top - 13); - - m_biHide.Move(ptOrgBtn - rcBar.TopLeft()); - - //mpc-hc custom code start - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ScreenToClient(&rc); - //mpc-hc custom code end - - *pRc = rc; -} - -void CSizingControlBarG::NcPaintGripper(CDC* pDC, CRect rcClient) -{ - if (!HasGripper()) - return; - - // paints a simple "two raised lines" gripper - // override this if you want a more sophisticated gripper - CRect gripper = rcClient; - CRect rcbtn = m_biHide.GetRect(); - BOOL bHorz = IsHorzDocked(); - - gripper.DeflateRect(1, 1); - if (bHorz) - { // gripper at left - gripper.left -= m_cyGripper; - gripper.right = gripper.left + 3; - gripper.top = rcbtn.bottom + 3; - } - else - { // gripper at top - gripper.top -= m_cyGripper; - gripper.bottom = gripper.top + 3; - gripper.right = rcbtn.left - 3; - } - - pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), - ::GetSysColor(COLOR_BTNSHADOW)); - - gripper.OffsetRect(bHorz ? 3 : 0, bHorz ? 0 : 3); - - pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), - ::GetSysColor(COLOR_BTNSHADOW)); - - m_biHide.Paint(pDC); -} - -LRESULT CSizingControlBarG::OnNcHitTest(CPoint point) -{ - CRect rcBar; - GetWindowRect(rcBar); - - LRESULT nRet = baseCSizingControlBarG::OnNcHitTest(point); - if (nRet != HTCLIENT) - return nRet; - - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - ScreenToClient(&rcBar); - ScreenToClient(&point); - //mpc-hc custom code end - - CRect rc = m_biHide.GetRect(); - rc.OffsetRect(rcBar.TopLeft()); - if (rc.PtInRect(point)) - return HTCLOSE; - - return HTCLIENT; -} - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarG implementation helpers - -void CSizingControlBarG::OnUpdateCmdUI(CFrameWnd* pTarget, - BOOL bDisableIfNoHndler) -{ - UNUSED_ALWAYS(bDisableIfNoHndler); - UNUSED_ALWAYS(pTarget); - - if (!HasGripper()) - return; - - BOOL bNeedPaint = FALSE; - - CPoint pt; - ::GetCursorPos(&pt); - BOOL bHit = (OnNcHitTest(pt) == HTCLOSE); - BOOL bLButtonDown = (::GetKeyState(VK_LBUTTON) < 0); - - BOOL bWasPushed = m_biHide.bPushed; - m_biHide.bPushed = bHit && bLButtonDown; - - BOOL bWasRaised = m_biHide.bRaised; - m_biHide.bRaised = bHit && !bLButtonDown; - - bNeedPaint |= (m_biHide.bPushed ^ bWasPushed) || - (m_biHide.bRaised ^ bWasRaised); - - if (bNeedPaint) - SendMessage(WM_NCPAINT); -} - -///////////////////////////////////////////////////////////////////////// -// CSCBButton - -CSCBButton::CSCBButton() -{ - bRaised = FALSE; - bPushed = FALSE; - dpiSize = CSize(11, 11); //mpc-hc addition to support dpi sizing -} - -void CSCBButton::Paint(CDC* pDC) -{ - CRect rc = GetRect(); - - if (bPushed) - pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNSHADOW), - ::GetSysColor(COLOR_BTNHIGHLIGHT)); - else - if (bRaised) - pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNHIGHLIGHT), - ::GetSysColor(COLOR_BTNSHADOW)); - - COLORREF clrOldTextColor = pDC->GetTextColor(); - pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT)); - int nPrevBkMode = pDC->SetBkMode(TRANSPARENT); - CFont font; - int ppi = pDC->GetDeviceCaps(LOGPIXELSX); - int pointsize = MulDiv(60, 96, ppi); // 6 points at 96 ppi - font.CreatePointFont(pointsize, _T("Marlett")); - CFont* oldfont = pDC->SelectObject(&font); - - //mpc-hc custom code start - // TextOut is affected by the layout so we need to account for that - DWORD dwLayout = pDC->GetLayout(); - pDC->TextOut(ptOrg.x + (dwLayout == LAYOUT_LTR ? 2 : -1), ptOrg.y + 2, CString(_T("r"))); // x-like - //mpc-hc custom code end - - pDC->SelectObject(oldfont); - pDC->SetBkMode(nPrevBkMode); - pDC->SetTextColor(clrOldTextColor); -} - -BOOL CSizingControlBarG::HasGripper() const -{ -#if defined(_SCB_MINIFRAME_CAPTION) || !defined(_SCB_REPLACE_MINIFRAME) - // if the miniframe has a caption, don't display the gripper - if (IsFloating()) - return FALSE; -#endif //_SCB_MINIFRAME_CAPTION - - return TRUE; +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBarG Version 2.45 +// +// Created: Jan 24, 1998 Last Modified: April 16, 2010 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com . +///////////////////////////////////////////////////////////////////////// + +// sizecbar.cpp : implementation file +// + +#include "stdafx.h" +#include "scbarg.h" + + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarG + +IMPLEMENT_DYNAMIC(CSizingControlBarG, baseCSizingControlBarG); + +CSizingControlBarG::CSizingControlBarG() +{ + m_cyGripper = 12; +} + +CSizingControlBarG::~CSizingControlBarG() +{ +} + +BEGIN_MESSAGE_MAP(CSizingControlBarG, baseCSizingControlBarG) + //{{AFX_MSG_MAP(CSizingControlBarG) + ON_WM_NCLBUTTONUP() + ON_WM_NCHITTEST() + //}}AFX_MSG_MAP + ON_MESSAGE(WM_SETTEXT, OnSetText) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarG message handlers + +///////////////////////////////////////////////////////////////////////// +// Mouse Handling +// + +void CSizingControlBarG::OnNcLButtonUp(UINT nHitTest, CPoint point) +{ + if (nHitTest == HTCLOSE) + m_pDockSite->ShowControlBar(this, FALSE, FALSE); // hide + + baseCSizingControlBarG::OnNcLButtonUp(nHitTest, point); +} + +void CSizingControlBarG::NcCalcClient(LPRECT pRc, UINT nDockBarID) +{ + CRect rcBar(pRc); // save the bar rect + + // subtract edges + baseCSizingControlBarG::NcCalcClient(pRc, nDockBarID); + + if (!HasGripper()) + return; + + CRect rc(pRc); // the client rect as calculated by the base class + //mpc-hc custom code start + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ClientToScreen(rcBar); + GetParent()->ClientToScreen(rc); + //mpc-hc custom code end + + BOOL bHorz = (nDockBarID == AFX_IDW_DOCKBAR_TOP) || + (nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); + + if (bHorz) + rc.DeflateRect(m_cyGripper, 0, 0, 0); + else + rc.DeflateRect(0, m_cyGripper, 0, 0); + + // set position for the "x" (hide bar) button + CPoint ptOrgBtn; + if (bHorz) + ptOrgBtn = CPoint(rc.left - 13, rc.top); + else + ptOrgBtn = CPoint(rc.right - 12, rc.top - 13); + + m_biHide.Move(ptOrgBtn - rcBar.TopLeft()); + + //mpc-hc custom code start + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ScreenToClient(&rc); + //mpc-hc custom code end + + *pRc = rc; +} + +void CSizingControlBarG::NcPaintGripper(CDC* pDC, CRect rcClient) +{ + if (!HasGripper()) + return; + + // paints a simple "two raised lines" gripper + // override this if you want a more sophisticated gripper + CRect gripper = rcClient; + CRect rcbtn = m_biHide.GetRect(); + BOOL bHorz = IsHorzDocked(); + + gripper.DeflateRect(1, 1); + if (bHorz) + { // gripper at left + gripper.left -= m_cyGripper; + gripper.right = gripper.left + 3; + gripper.top = rcbtn.bottom + 3; + } + else + { // gripper at top + gripper.top -= m_cyGripper; + gripper.bottom = gripper.top + 3; + gripper.right = rcbtn.left - 3; + } + + pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), + ::GetSysColor(COLOR_BTNSHADOW)); + + gripper.OffsetRect(bHorz ? 3 : 0, bHorz ? 0 : 3); + + pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), + ::GetSysColor(COLOR_BTNSHADOW)); + + m_biHide.Paint(pDC); +} + +LRESULT CSizingControlBarG::OnNcHitTest(CPoint point) +{ + CRect rcBar; + GetWindowRect(rcBar); + + LRESULT nRet = baseCSizingControlBarG::OnNcHitTest(point); + if (nRet != HTCLIENT) + return nRet; + + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + ScreenToClient(&rcBar); + ScreenToClient(&point); + //mpc-hc custom code end + + CRect rc = m_biHide.GetRect(); + rc.OffsetRect(rcBar.TopLeft()); + if (rc.PtInRect(point)) + return HTCLOSE; + + return HTCLIENT; +} + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarG implementation helpers + +void CSizingControlBarG::OnUpdateCmdUI(CFrameWnd* pTarget, + BOOL bDisableIfNoHndler) +{ + UNUSED_ALWAYS(bDisableIfNoHndler); + UNUSED_ALWAYS(pTarget); + + if (!HasGripper()) + return; + + BOOL bNeedPaint = FALSE; + + CPoint pt; + ::GetCursorPos(&pt); + BOOL bHit = (OnNcHitTest(pt) == HTCLOSE); + BOOL bLButtonDown = (::GetKeyState(VK_LBUTTON) < 0); + + BOOL bWasPushed = m_biHide.bPushed; + m_biHide.bPushed = bHit && bLButtonDown; + + BOOL bWasRaised = m_biHide.bRaised; + m_biHide.bRaised = bHit && !bLButtonDown; + + bNeedPaint |= (m_biHide.bPushed ^ bWasPushed) || + (m_biHide.bRaised ^ bWasRaised); + + if (bNeedPaint) + SendMessage(WM_NCPAINT); +} + +///////////////////////////////////////////////////////////////////////// +// CSCBButton + +CSCBButton::CSCBButton() +{ + bRaised = FALSE; + bPushed = FALSE; + dpiSize = CSize(11, 11); //mpc-hc addition to support dpi sizing +} + +void CSCBButton::Paint(CDC* pDC) +{ + CRect rc = GetRect(); + + if (bPushed) + pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNSHADOW), + ::GetSysColor(COLOR_BTNHIGHLIGHT)); + else + if (bRaised) + pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNHIGHLIGHT), + ::GetSysColor(COLOR_BTNSHADOW)); + + COLORREF clrOldTextColor = pDC->GetTextColor(); + pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT)); + int nPrevBkMode = pDC->SetBkMode(TRANSPARENT); + CFont font; + int ppi = pDC->GetDeviceCaps(LOGPIXELSX); + int pointsize = MulDiv(60, 96, ppi); // 6 points at 96 ppi + font.CreatePointFont(pointsize, _T("Marlett")); + CFont* oldfont = pDC->SelectObject(&font); + + //mpc-hc custom code start + // TextOut is affected by the layout so we need to account for that + DWORD dwLayout = pDC->GetLayout(); + pDC->TextOut(ptOrg.x + (dwLayout == LAYOUT_LTR ? 2 : -1), ptOrg.y + 2, CString(_T("r"))); // x-like + //mpc-hc custom code end + + pDC->SelectObject(oldfont); + pDC->SetBkMode(nPrevBkMode); + pDC->SetTextColor(clrOldTextColor); +} + +BOOL CSizingControlBarG::HasGripper() const +{ +#if defined(_SCB_MINIFRAME_CAPTION) || !defined(_SCB_REPLACE_MINIFRAME) + // if the miniframe has a caption, don't display the gripper + if (IsFloating()) + return FALSE; +#endif //_SCB_MINIFRAME_CAPTION + + return TRUE; } \ No newline at end of file diff --git a/src/thirdparty/sizecbar/scbarg.h b/src/thirdparty/sizecbar/scbarg.h index 2e880fe43ec..43900b8b3d8 100644 --- a/src/thirdparty/sizecbar/scbarg.h +++ b/src/thirdparty/sizecbar/scbarg.h @@ -1,118 +1,118 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBarG Version 2.45 -// -// Created: Jan 24, 1998 Last Modified: April 16, 2010 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com . -///////////////////////////////////////////////////////////////////////// - -#if !defined(__SCBARG_H__) -#define __SCBARG_H__ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 - -#include "sizecbar.h" - -///////////////////////////////////////////////////////////////////////// -// CSCBButton (button info) helper class - -class CSCBButton -{ -public: - CSCBButton(); - - void Move(CPoint ptTo) {ptOrg = ptTo; }; - //mpc-hc changes to allow DPI changes - //CRect GetRect() { return CRect(ptOrg, CSize(11, 11)); }; - CRect GetRect() { return CRect(ptOrg, dpiSize); }; - void SetDpiSize(CSize s) { dpiSize = s; }; - - CSize dpiSize; - //end mpc-hc - - void Paint(CDC* pDC); - - - BOOL bPushed; - BOOL bRaised; - -protected: - CPoint ptOrg; -}; - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar control bar - -#ifndef baseCSizingControlBarG -#define baseCSizingControlBarG CSizingControlBar -#endif - -class CSizingControlBarG : public baseCSizingControlBarG -{ - DECLARE_DYNAMIC(CSizingControlBarG); - -// Construction -public: - CSizingControlBarG(); - -// Attributes -public: - virtual BOOL HasGripper() const; - -// Operations -public: - -// Overridables - virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); - -// Overrides -public: - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CSizingControlBarG) - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CSizingControlBarG(); - -protected: - // implementation helpers - virtual void NcPaintGripper(CDC* pDC, CRect rcClient); - virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); - -protected: - int m_cyGripper; - - CSCBButton m_biHide; - -// Generated message map functions -protected: - //{{AFX_MSG(CSizingControlBarG) - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg void OnNcLButtonUp(UINT nHitTest, CPoint point); - //}}AFX_MSG - - DECLARE_MESSAGE_MAP() -}; - -#endif // !defined(__SCBARG_H__) - +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBarG Version 2.45 +// +// Created: Jan 24, 1998 Last Modified: April 16, 2010 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com . +///////////////////////////////////////////////////////////////////////// + +#if !defined(__SCBARG_H__) +#define __SCBARG_H__ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#include "sizecbar.h" + +///////////////////////////////////////////////////////////////////////// +// CSCBButton (button info) helper class + +class CSCBButton +{ +public: + CSCBButton(); + + void Move(CPoint ptTo) {ptOrg = ptTo; }; + //mpc-hc changes to allow DPI changes + //CRect GetRect() { return CRect(ptOrg, CSize(11, 11)); }; + CRect GetRect() { return CRect(ptOrg, dpiSize); }; + void SetDpiSize(CSize s) { dpiSize = s; }; + + CSize dpiSize; + //end mpc-hc + + void Paint(CDC* pDC); + + + BOOL bPushed; + BOOL bRaised; + +protected: + CPoint ptOrg; +}; + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar control bar + +#ifndef baseCSizingControlBarG +#define baseCSizingControlBarG CSizingControlBar +#endif + +class CSizingControlBarG : public baseCSizingControlBarG +{ + DECLARE_DYNAMIC(CSizingControlBarG); + +// Construction +public: + CSizingControlBarG(); + +// Attributes +public: + virtual BOOL HasGripper() const; + +// Operations +public: + +// Overridables + virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); + +// Overrides +public: + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSizingControlBarG) + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CSizingControlBarG(); + +protected: + // implementation helpers + virtual void NcPaintGripper(CDC* pDC, CRect rcClient); + virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); + +protected: + int m_cyGripper; + + CSCBButton m_biHide; + +// Generated message map functions +protected: + //{{AFX_MSG(CSizingControlBarG) + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg void OnNcLButtonUp(UINT nHitTest, CPoint point); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +#endif // !defined(__SCBARG_H__) + diff --git a/src/thirdparty/sizecbar/sizecbar.cpp b/src/thirdparty/sizecbar/sizecbar.cpp index 8ad2d64733a..fc95004a8e4 100644 --- a/src/thirdparty/sizecbar/sizecbar.cpp +++ b/src/thirdparty/sizecbar/sizecbar.cpp @@ -1,1463 +1,1463 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBar Version 2.45 -// -// Created: Jan 24, 1998 Last Modified: April 16, 2010 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com . -// -// The sources and a short version of the docs are also available at -// www.codeproject.com . Look for a "Docking Windows" section and check -// the version to be sure you get the latest one ;) -// -// Hint: These classes are intended to be used as base classes. Do not -// simply add your code to these files - instead create a new class -// derived from one of CSizingControlBarXX classes and put there what -// you need. See CMyBar classes in the demo projects for examples. -// Modify this file only to fix bugs, and don't forget to send me a copy. -///////////////////////////////////////////////////////////////////////// -// Acknowledgements: -// o Thanks to Harlan R. Seymour for his continuous support during -// development of this code. -// o Thanks to Dundas Software and Formatta Corporation for the -// opportunities to test this code on real-life applications. -// o Some ideas for the gripper came from the CToolBarEx flat toolbar -// by Joerg Koenig. Thanks, Joerg! -// o Thanks to Robert Wolpow for the code on which CDockContext based -// dialgonal resizing is based. -// o Thanks to the following people for various bug fixes and/or -// enhancements: Chris Maunder, Jakawan Ratiwanich, Udo Schaefer, -// Anatoly Ivasyuk, Peter Hauptmann, DJ(?), Pat Kusbel, Aleksey -// Malyshev, and many others who used this code and sent feedback. -///////////////////////////////////////////////////////////////////////// - -// sizecbar.cpp : implementation file -// - -#include "stdafx.h" -#include "sizecbar.h" - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar - -IMPLEMENT_DYNAMIC(CSizingControlBar, baseCSizingControlBar); - -CSizingControlBar::CSizingControlBar() -{ - m_szMinHorz = CSize(33, 32); - m_szMinVert = CSize(33, 32); - m_szMinFloat = CSize(37, 32); - m_szHorz = CSize(200, 200); - m_szVert = CSize(200, 200); - m_szFloat = CSize(200, 200); - m_bTracking = FALSE; - m_bKeepSize = FALSE; - m_bParentSizing = FALSE; - m_cxEdge = 5; - m_bDragShowContent = FALSE; - m_nDockBarID = 0; - m_dwSCBStyle = 0; - m_htEdge = 0; - m_nTrackPosMin = 0; - m_nTrackPosMax = 0; - m_nTrackPosOld = 0; - m_nTrackEdgeOfs = 0; - m_bFixedFloat = FALSE; -} - -CSizingControlBar::~CSizingControlBar() -{ -} - -BEGIN_MESSAGE_MAP(CSizingControlBar, baseCSizingControlBar) - //{{AFX_MSG_MAP(CSizingControlBar) - ON_WM_CREATE() - ON_WM_PAINT() - ON_WM_NCPAINT() - ON_WM_NCCALCSIZE() - ON_WM_WINDOWPOSCHANGING() - ON_WM_CAPTURECHANGED() - ON_WM_SETTINGCHANGE() - ON_WM_LBUTTONUP() - ON_WM_MOUSEMOVE() - ON_WM_NCLBUTTONDOWN() - ON_WM_LBUTTONDOWN() - ON_WM_LBUTTONDBLCLK() - ON_WM_RBUTTONDOWN() - ON_WM_NCMOUSEMOVE() - ON_WM_NCHITTEST() - ON_WM_CLOSE() - ON_WM_SIZE() - //}}AFX_MSG_MAP - ON_MESSAGE(WM_SETTEXT, OnSetText) -END_MESSAGE_MAP() - -// old creation method, still here for compatibility reasons -BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, - CSize sizeDefault, BOOL bHasGripper, - UINT nID, DWORD dwStyle) -{ - UNUSED_ALWAYS(bHasGripper); - - m_szHorz = m_szVert = m_szFloat = sizeDefault; - return Create(lpszWindowName, pParentWnd, nID, dwStyle); -} - -// preffered creation method -BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, - CWnd* pParentWnd, UINT nID, - DWORD dwStyle) -{ - // must have a parent - ASSERT_VALID(pParentWnd); - // cannot be both fixed and dynamic - // (CBRS_SIZE_DYNAMIC is used for resizng when floating) - ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && - (dwStyle & CBRS_SIZE_DYNAMIC))); - - m_dwStyle = dwStyle & CBRS_ALL; // save the control bar styles - - // register and create the window - skip CControlBar::Create() - CString wndclass = ::AfxRegisterWndClass(CS_DBLCLKS, - ::LoadCursor(NULL, IDC_ARROW), - ::GetSysColorBrush(COLOR_BTNFACE), 0); - - dwStyle &= ~CBRS_ALL; // keep only the generic window styles - dwStyle |= WS_CLIPCHILDREN; // prevents flashing - if (!CWnd::Create(wndclass, lpszWindowName, dwStyle, - CRect(0, 0, 0, 0), pParentWnd, nID)) - return FALSE; - - return TRUE; -} - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar operations -#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) -void CSizingControlBar::EnableDocking(DWORD dwDockStyle) -{ - // must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only - ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI)) == 0); - // cannot have the CBRS_FLOAT_MULTI style - ASSERT((dwDockStyle & CBRS_FLOAT_MULTI) == 0); - // the bar must have CBRS_SIZE_DYNAMIC style - ASSERT((m_dwStyle & CBRS_SIZE_DYNAMIC) != 0); - - m_dwDockStyle = dwDockStyle; - if (m_pDockContext == NULL) - m_pDockContext = new CSCBDockContext(this); - - // permanently wire the bar's owner to its current parent - if (m_hWndOwner == NULL) - m_hWndOwner = ::GetParent(m_hWnd); -} -#endif - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar message handlers - -int CSizingControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (baseCSizingControlBar::OnCreate(lpCreateStruct) == -1) - return -1; - - // query SPI_GETDRAGFULLWINDOWS system parameter - // OnSettingChange() will update m_bDragShowContent - m_bDragShowContent = FALSE; - ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, - &m_bDragShowContent, 0); - - // uncomment this line if you want raised borders -// m_dwSCBStyle |= SCBS_SHOWEDGES; - - return 0; -} - - -LRESULT CSizingControlBar::OnSetText(WPARAM wParam, LPARAM lParam) -{ - UNUSED_ALWAYS(wParam); - - LRESULT lResult = CWnd::Default(); - - if (IsFloating() && - GetParentFrame()->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd))) - { - m_pDockBar->SetWindowText((LPCTSTR) lParam); // update dockbar - GetParentFrame()->DelayRecalcLayout(); // refresh miniframe - } - - return lResult; -} - -const BOOL CSizingControlBar::IsFloating() const -{ - return !IsHorzDocked() && !IsVertDocked(); -} - -const BOOL CSizingControlBar::IsHorzDocked() const -{ - return (m_nDockBarID == AFX_IDW_DOCKBAR_TOP || - m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); -} - -const BOOL CSizingControlBar::IsVertDocked() const -{ - return (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT || - m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT); -} - -const BOOL CSizingControlBar::IsSideTracking() const -{ - // don't call this when not tracking - ASSERT(m_bTracking && !IsFloating()); - - return (m_htEdge == HTLEFT || m_htEdge == HTRIGHT) ? - IsHorzDocked() : IsVertDocked(); -} - -CSize CSizingControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) -{ - if (bStretch) // the bar is stretched (is not the child of a dockbar) - if (bHorz) - return CSize(32767, m_szHorz.cy); - else - return CSize(m_szVert.cx, 32767); - - // dirty cast - we need access to protected CDockBar members - CSCBDockBar* pDockBar = static_cast (m_pDockBar); - - // force imediate RecalcDelayShow() for all sizing bars on the row - // with delayShow/delayHide flags set to avoid IsVisible() problems - CSCBArray arrSCBars; - GetRowSizingBars(arrSCBars); - AFX_SIZEPARENTPARAMS layout; - layout.hDWP = pDockBar->m_bLayoutQuery ? - NULL : ::BeginDeferWindowPos(arrSCBars.GetSize()); - for (int i = 0; i < arrSCBars.GetSize(); i++) - if (arrSCBars[i]->m_nStateFlags & (delayHide|delayShow)) - arrSCBars[i]->RecalcDelayShow(&layout); - if (layout.hDWP != NULL) - ::EndDeferWindowPos(layout.hDWP); - - // get available length - CRect rc = pDockBar->m_rectLayout; - if (rc.IsRectEmpty()) - m_pDockSite->GetClientRect(&rc); - int nLengthTotal = bHorz ? rc.Width() + 2 : rc.Height() - 2; - - if (IsVisible() && !IsFloating() && - m_bParentSizing && arrSCBars[0] == this) - if (NegotiateSpace(nLengthTotal, (bHorz != FALSE))) - AlignControlBars(); - - m_bParentSizing = FALSE; - - if (bHorz) - return CSize(max(m_szMinHorz.cx, m_szHorz.cx), - max(m_szMinHorz.cy, m_szHorz.cy)); - - return CSize(max(m_szMinVert.cx, m_szVert.cx), - max(m_szMinVert.cy, m_szVert.cy)); -} - -CSize CSizingControlBar::CalcDynamicLayout(int nLength, DWORD dwMode) -{ - if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) // docked ? - { - if (nLength == -1) - m_bParentSizing = TRUE; - - return baseCSizingControlBar::CalcDynamicLayout(nLength, dwMode); - } - - if (dwMode & LM_MRUWIDTH) return m_szFloat; - if (dwMode & LM_COMMIT) return m_szFloat; // already committed - -#ifndef _SCB_REPLACE_MINIFRAME - // check for dialgonal resizing hit test - int nHitTest = m_pDockContext->m_nHitTest; - if (IsFloating() && - (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT || - nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT)) - { - CPoint ptCursor; - ::GetCursorPos(&ptCursor); - - CRect rFrame, rBar; - GetParentFrame()->GetWindowRect(&rFrame); - GetWindowRect(&rBar); - - if (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT) - { - m_szFloat.cx = rFrame.left + rBar.Width() - ptCursor.x; - m_pDockContext->m_rectFrameDragHorz.left = - min(ptCursor.x, rFrame.left + rBar.Width() - m_szMinFloat.cx); - } - - if (nHitTest == HTTOPLEFT || nHitTest == HTTOPRIGHT) - { - m_szFloat.cy = rFrame.top + rBar.Height() - ptCursor.y; - m_pDockContext->m_rectFrameDragHorz.top = - min(ptCursor.y, rFrame.top + rBar.Height() - m_szMinFloat.cy); - } - - if (nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT) - m_szFloat.cx = rBar.Width() + ptCursor.x - rFrame.right; - - if (nHitTest == HTBOTTOMLEFT || nHitTest == HTBOTTOMRIGHT) - m_szFloat.cy = rBar.Height() + ptCursor.y - rFrame.bottom; - } - else -#endif //_SCB_REPLACE_MINIFRAME - ((dwMode & LM_LENGTHY) ? m_szFloat.cy : m_szFloat.cx) = nLength; - - m_szFloat.cx = max(m_szFloat.cx, m_szMinFloat.cx); - m_szFloat.cy = max(m_szFloat.cy, m_szMinFloat.cy); - - return m_szFloat; -} - -void CSizingControlBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) -{ - // force non-client recalc if moved or resized - lpwndpos->flags |= SWP_FRAMECHANGED; - - baseCSizingControlBar::OnWindowPosChanging(lpwndpos); - - // find on which side are we docked - m_nDockBarID = GetParent()->GetDlgCtrlID(); - - if (!IsFloating()) - if (lpwndpos->flags & SWP_SHOWWINDOW) - m_bKeepSize = TRUE; -} - -///////////////////////////////////////////////////////////////////////// -// Mouse Handling -// -void CSizingControlBar::OnLButtonDown(UINT nFlags, CPoint point) -{ - if (m_pDockBar != NULL) - { - // start the drag - ASSERT(m_pDockContext != NULL); - ClientToScreen(&point); - m_pDockContext->StartDrag(point); - } - else - CWnd::OnLButtonDown(nFlags, point); -} - -void CSizingControlBar::OnLButtonDblClk(UINT nFlags, CPoint point) -{ - if (m_pDockBar != NULL) - { - // toggle docking - ASSERT(m_pDockContext != NULL); - m_pDockContext->ToggleDocking(); - } - else - CWnd::OnLButtonDblClk(nFlags, point); -} - -void CSizingControlBar::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - UNUSED_ALWAYS(point); - - if (m_bTracking || IsFloating()) - return; - - if ((nHitTest >= HTSIZEFIRST) && (nHitTest <= HTSIZELAST)) - StartTracking(nHitTest, point); // sizing edge hit -} - -void CSizingControlBar::OnLButtonUp(UINT nFlags, CPoint point) -{ - if (m_bTracking) - StopTracking(); - - baseCSizingControlBar::OnLButtonUp(nFlags, point); -} - -void CSizingControlBar::OnRButtonDown(UINT nFlags, CPoint point) -{ - if (m_bTracking) - StopTracking(); - - baseCSizingControlBar::OnRButtonDown(nFlags, point); -} - -void CSizingControlBar::OnMouseMove(UINT nFlags, CPoint point) -{ - if (m_bTracking) - { - CPoint ptScreen = point; - ClientToScreen(&ptScreen); - - //mpc-hc custom code start - // Switch to parent window client coordinates to account for possible RTL layout - CPoint ptParentClient = ptScreen; - GetParentFrame()->ScreenToClient(&ptParentClient); - OnTrackUpdateSize(ptParentClient); - //mpc-hc custom code end - } - - baseCSizingControlBar::OnMouseMove(nFlags, point); -} - -void CSizingControlBar::OnCaptureChanged(CWnd *pWnd) -{ - if (m_bTracking && (pWnd != this)) - StopTracking(); - - baseCSizingControlBar::OnCaptureChanged(pWnd); -} - -void CSizingControlBar::OnNcCalcSize(BOOL bCalcValidRects, - NCCALCSIZE_PARAMS FAR* lpncsp) -{ - UNUSED_ALWAYS(bCalcValidRects); - -#ifndef _SCB_REPLACE_MINIFRAME - // Enable diagonal resizing for floating miniframe - if (IsFloating()) - { - CFrameWnd* pFrame = GetParentFrame(); - if (pFrame != NULL && - pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd))) - { -//mpc-hc custom code start - LONG_PTR dwStyle = ::GetWindowLongPtr(pFrame->m_hWnd, GWL_STYLE); -//mpc-hc custom code end - if ((dwStyle & MFS_4THICKFRAME) != 0) - { - pFrame->ModifyStyle(MFS_4THICKFRAME, 0); // clear - GetParent()->ModifyStyle(0, WS_CLIPCHILDREN); - } - } - } -#endif _SCB_REPLACE_MINIFRAME - - // compute the the client area - m_dwSCBStyle &= ~SCBS_EDGEALL; - - // add resizing edges between bars on the same row - if (!IsFloating() && m_pDockBar != NULL) - { - CSCBArray arrSCBars; - int nThis; - GetRowSizingBars(arrSCBars, nThis); - - BOOL bHorz = IsHorzDocked(); - if (nThis > 0) - m_dwSCBStyle |= bHorz ? SCBS_EDGELEFT : SCBS_EDGETOP; - - if (nThis < arrSCBars.GetUpperBound()) - m_dwSCBStyle |= bHorz ? SCBS_EDGERIGHT : SCBS_EDGEBOTTOM; - } - - NcCalcClient(&lpncsp->rgrc[0], m_nDockBarID); -} - -void CSizingControlBar::NcCalcClient(LPRECT pRc, UINT nDockBarID) -{ - CRect rc(pRc); - //mpc-hc custom code start - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ClientToScreen(&rc); - //mpc-hc custom code end - - rc.DeflateRect(3, 5, 3, 3); - if (nDockBarID != AFX_IDW_DOCKBAR_FLOAT) - rc.DeflateRect(2, 0, 2, 2); - - switch(nDockBarID) - { - case AFX_IDW_DOCKBAR_TOP: - m_dwSCBStyle |= SCBS_EDGEBOTTOM; - break; - case AFX_IDW_DOCKBAR_BOTTOM: - m_dwSCBStyle |= SCBS_EDGETOP; - break; - case AFX_IDW_DOCKBAR_LEFT: - m_dwSCBStyle |= SCBS_EDGERIGHT; - break; - case AFX_IDW_DOCKBAR_RIGHT: - m_dwSCBStyle |= SCBS_EDGELEFT; - break; - } - - // make room for edges only if they will be painted - if (m_dwSCBStyle & SCBS_SHOWEDGES) - rc.DeflateRect( - (m_dwSCBStyle & SCBS_EDGELEFT) ? m_cxEdge : 0, - (m_dwSCBStyle & SCBS_EDGETOP) ? m_cxEdge : 0, - (m_dwSCBStyle & SCBS_EDGERIGHT) ? m_cxEdge : 0, - (m_dwSCBStyle & SCBS_EDGEBOTTOM) ? m_cxEdge : 0); - - //mpc-hc custom code start - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ScreenToClient(&rc); - //mpc-hc custom code end - - *pRc = rc; -} - -void CSizingControlBar::OnNcPaint() -{ - // get window DC that is clipped to the non-client area - CWindowDC dc(this); // the HDC will be released by the destructor - - CRect rcClient, rcBar; - GetClientRect(rcClient); - //mpc-hc custom code start - //ClientToScreen(rcClient); - //mpc-hc custom code end - GetWindowRect(rcBar); - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - ScreenToClient(rcBar); - //mpc-hc custom code end - rcClient.OffsetRect(-rcBar.TopLeft()); - rcBar.OffsetRect(-rcBar.TopLeft()); - - CDC mdc; - mdc.CreateCompatibleDC(&dc); - - CBitmap bm; - bm.CreateCompatibleBitmap(&dc, rcBar.Width(), rcBar.Height()); - CBitmap* pOldBm = mdc.SelectObject(&bm); - - // draw borders in non-client area - CRect rcDraw = rcBar; - DrawBorders(&mdc, rcDraw); - - // erase the NC background -//mpc-hc custom code start - mpc_fillNcBG(&mdc, rcDraw); -//mpc-hc custom code end - - if (m_dwSCBStyle & SCBS_SHOWEDGES) - { - CRect rcEdge; // paint the sizing edges - for (int i = 0; i < 4; i++) - if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge)) - mdc.Draw3dRect(rcEdge, ::GetSysColor(COLOR_BTNHIGHLIGHT), - ::GetSysColor(COLOR_BTNSHADOW)); - } - - NcPaintGripper(&mdc, rcClient); - - // client area is not our bussiness :) - dc.IntersectClipRect(rcBar); - dc.ExcludeClipRect(rcClient); - - dc.BitBlt(0, 0, rcBar.Width(), rcBar.Height(), &mdc, 0, 0, SRCCOPY); - - mdc.SelectObject(pOldBm); - bm.DeleteObject(); - mdc.DeleteDC(); -} - -void CSizingControlBar::NcPaintGripper(CDC* pDC, CRect rcClient) -{ - UNUSED_ALWAYS(pDC); - UNUSED_ALWAYS(rcClient); -} - -void CSizingControlBar::OnPaint() -{ - // overridden to skip border painting based on clientrect - CPaintDC dc(this); -} - -LRESULT CSizingControlBar::OnNcHitTest(CPoint point) -{ - CRect rcBar, rcEdge; - GetWindowRect(rcBar); - - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - ScreenToClient(&rcBar); - ScreenToClient(&point); - //mpc-hc custom code end - - if (!IsFloating()) - for (int i = 0; i < 4; i++) - if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge)) - if (rcEdge.PtInRect(point)) - return GetEdgeHTCode(i); - - return HTCLIENT; -} - -void CSizingControlBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) -{ - baseCSizingControlBar::OnSettingChange(uFlags, lpszSection); - - m_bDragShowContent = FALSE; - ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, - &m_bDragShowContent, 0); // update -} - -void CSizingControlBar::OnSize(UINT nType, int cx, int cy) -{ - UNUSED_ALWAYS(nType); - - if ((m_dwSCBStyle & SCBS_SIZECHILD) != 0) - { - // automatic child resizing - only one child is allowed - CWnd* pWnd = GetWindow(GW_CHILD); - if (pWnd != NULL) - { - pWnd->MoveWindow(0, 0, cx, cy); - ASSERT(pWnd->GetWindow(GW_HWNDNEXT) == NULL); - } - } -} - -void CSizingControlBar::OnClose() -{ - // do nothing: protection against accidentally destruction by the - // child control (i.e. if user hits Esc in a child editctrl) -} - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar implementation helpers - -void CSizingControlBar::StartTracking(UINT nHitTest, CPoint point) -{ - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - GetParentFrame()->ScreenToClient(&point); - //mpc-hc custom code end - - SetCapture(); - - // make sure no updates are pending - if (!m_bDragShowContent) - RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); - - m_htEdge = nHitTest; - m_bTracking = TRUE; - - BOOL bHorz = IsHorzDocked(); - BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; - - m_nTrackPosOld = bHorzTracking ? point.x : point.y; - - CRect rcBar, rcEdge; - GetWindowRect(rcBar); - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - GetParent()->ScreenToClient(&rcBar); - //mpc-hc custom code end - GetEdgeRect(rcBar, m_htEdge, rcEdge); - m_nTrackEdgeOfs = m_nTrackPosOld - - (bHorzTracking ? rcEdge.CenterPoint().x : rcEdge.CenterPoint().y); - - CSCBArray arrSCBars; - int nThis; - GetRowSizingBars(arrSCBars, nThis); - - m_nTrackPosMin = m_nTrackPosMax = m_nTrackPosOld; - if (!IsSideTracking()) - { - // calc minwidth as the max minwidth of the sizing bars on row - int nMinWidth = bHorz ? m_szMinHorz.cy : m_szMinVert.cx; - for (int i = 0; i < arrSCBars.GetSize(); i++) - nMinWidth = max(nMinWidth, bHorz ? - arrSCBars[i]->m_szMinHorz.cy : - arrSCBars[i]->m_szMinVert.cx); - int nExcessWidth = (bHorz ? m_szHorz.cy : m_szVert.cx) - nMinWidth; - - // the control bar cannot grow with more than the width of - // remaining client area of the mainframe - CRect rcT; - m_pDockSite->RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST, - reposQuery, &rcT, NULL, TRUE); - int nMaxWidth = bHorz ? rcT.Height() - 2 : rcT.Width() - 2; - - BOOL bTopOrLeft = m_htEdge == HTTOP || m_htEdge == HTLEFT; - - m_nTrackPosMin -= bTopOrLeft ? nMaxWidth : nExcessWidth; - m_nTrackPosMax += bTopOrLeft ? nExcessWidth : nMaxWidth; - } - else - { - // side tracking: - // max size is the actual size plus the amount the other - // sizing bars can be decreased until they reach their minsize - if (m_htEdge == HTBOTTOM || m_htEdge == HTRIGHT) - nThis++; - - for (int i = 0; i < arrSCBars.GetSize(); i++) - { - CSizingControlBar* pBar = arrSCBars[i]; - - int nExcessWidth = bHorz ? - pBar->m_szHorz.cx - pBar->m_szMinHorz.cx : - pBar->m_szVert.cy - pBar->m_szMinVert.cy; - - if (i < nThis) - m_nTrackPosMin -= nExcessWidth; - else - m_nTrackPosMax += nExcessWidth; - } - } - - OnTrackInvertTracker(); // draw tracker -} - -void CSizingControlBar::StopTracking() -{ - OnTrackInvertTracker(); // erase tracker - - m_bTracking = FALSE; - ReleaseCapture(); - - m_pDockSite->DelayRecalcLayout(); -} - -void CSizingControlBar::OnTrackUpdateSize(CPoint& point) -{ - ASSERT(!IsFloating()); - - BOOL bHorzTrack = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; - - int nTrackPos = bHorzTrack ? point.x : point.y; - nTrackPos = max(m_nTrackPosMin, min(m_nTrackPosMax, nTrackPos)); - - int nDelta = nTrackPos - m_nTrackPosOld; - - if (nDelta == 0) - return; // no pos change - - OnTrackInvertTracker(); // erase tracker - - m_nTrackPosOld = nTrackPos; - - BOOL bHorz = IsHorzDocked(); - - CSize sizeNew = bHorz ? m_szHorz : m_szVert; - switch (m_htEdge) - { - case HTLEFT: sizeNew -= CSize(nDelta, 0); break; - case HTTOP: sizeNew -= CSize(0, nDelta); break; - case HTRIGHT: sizeNew += CSize(nDelta, 0); break; - case HTBOTTOM: sizeNew += CSize(0, nDelta); break; - } - - CSCBArray arrSCBars; - int nThis; - GetRowSizingBars(arrSCBars, nThis); - - if (!IsSideTracking()) - for (int i = 0; i < arrSCBars.GetSize(); i++) - { - CSizingControlBar* pBar = arrSCBars[i]; - // make same width (or height) - (bHorz ? pBar->m_szHorz.cy : pBar->m_szVert.cx) = - bHorz ? sizeNew.cy : sizeNew.cx; - } - else - { - int nGrowingBar = nThis; - BOOL bBefore = m_htEdge == HTTOP || m_htEdge == HTLEFT; - if (bBefore && nDelta > 0) - nGrowingBar--; - if (!bBefore && nDelta < 0) - nGrowingBar++; - if (nGrowingBar != nThis) - bBefore = !bBefore; - - // nGrowing is growing - nDelta = abs(nDelta); - CSizingControlBar* pBar = arrSCBars[nGrowingBar]; - (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta; - - // the others are shrinking - int nFirst = bBefore ? nGrowingBar - 1 : nGrowingBar + 1; - int nLimit = bBefore ? -1 : arrSCBars.GetSize(); - - for (int i = nFirst; nDelta != 0 && i != nLimit; i += (bBefore ? -1 : 1)) - { - CSizingControlBar* pBar = arrSCBars[i]; - - int nDeltaT = min(nDelta, - (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) - - (bHorz ? pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy)); - - (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) -= nDeltaT; - nDelta -= nDeltaT; - } - } - - OnTrackInvertTracker(); // redraw tracker at new pos - - if (m_bDragShowContent) - m_pDockSite->DelayRecalcLayout(); -} - -void CSizingControlBar::OnTrackInvertTracker() -{ - ASSERT(m_bTracking); - - if (m_bDragShowContent) - return; // don't show tracker if DragFullWindows is on - - BOOL bHorz = IsHorzDocked(); - CRect rc, rcBar, rcDock, rcFrame; - GetWindowRect(rcBar); - m_pDockBar->GetWindowRect(rcDock); - m_pDockSite->GetWindowRect(rcFrame); - VERIFY(GetEdgeRect(rcBar, m_htEdge, rc)); - if (!IsSideTracking()) - rc = bHorz ? - CRect(rcDock.left + 1, rc.top, rcDock.right - 1, rc.bottom) : - CRect(rc.left, rcDock.top + 1, rc.right, rcDock.bottom - 1); - - BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; - int nOfs = m_nTrackPosOld - m_nTrackEdgeOfs; - nOfs -= bHorzTracking ? rc.CenterPoint().x : rc.CenterPoint().y; - rc.OffsetRect(bHorzTracking ? nOfs : 0, bHorzTracking ? 0 : nOfs); - rc.OffsetRect(-rcFrame.TopLeft()); - - CDC *pDC = m_pDockSite->GetDCEx(NULL, - DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); - CBrush* pBrush = CDC::GetHalftoneBrush(); - CBrush* pBrushOld = pDC->SelectObject(pBrush); - - pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATINVERT); - - pDC->SelectObject(pBrushOld); - m_pDockSite->ReleaseDC(pDC); -} - -BOOL CSizingControlBar::GetEdgeRect(CRect rcWnd, UINT nHitTest, - CRect& rcEdge) -{ - rcEdge = rcWnd; - if (m_dwSCBStyle & SCBS_SHOWEDGES) - rcEdge.DeflateRect(1, 1); - BOOL bHorz = IsHorzDocked(); - - switch (nHitTest) - { - case HTLEFT: - if (!(m_dwSCBStyle & SCBS_EDGELEFT)) return FALSE; - rcEdge.right = rcEdge.left + m_cxEdge; - rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0); - break; - case HTTOP: - if (!(m_dwSCBStyle & SCBS_EDGETOP)) return FALSE; - rcEdge.bottom = rcEdge.top + m_cxEdge; - rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0); - break; - case HTRIGHT: - if (!(m_dwSCBStyle & SCBS_EDGERIGHT)) return FALSE; - rcEdge.left = rcEdge.right - m_cxEdge; - rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0); - break; - case HTBOTTOM: - if (!(m_dwSCBStyle & SCBS_EDGEBOTTOM)) return FALSE; - rcEdge.top = rcEdge.bottom - m_cxEdge; - rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0); - break; - default: - ASSERT(FALSE); // invalid hit test code - } - return TRUE; -} - -UINT CSizingControlBar::GetEdgeHTCode(int nEdge) -{ - if (nEdge == 0) return HTLEFT; - if (nEdge == 1) return HTTOP; - if (nEdge == 2) return HTRIGHT; - if (nEdge == 3) return HTBOTTOM; - ASSERT(FALSE); // invalid edge code - return HTNOWHERE; -} - -void CSizingControlBar::GetRowInfo(int& nFirst, int& nLast, int& nThis) -{ - ASSERT_VALID(m_pDockBar); // verify bounds - - nThis = m_pDockBar->FindBar(this); - ASSERT(nThis != -1); - - int i, nBars = m_pDockBar->m_arrBars.GetSize(); - - // find the first and the last bar in row - for (nFirst = -1, i = nThis - 1; i >= 0 && nFirst == -1; i--) - if (m_pDockBar->m_arrBars[i] == NULL) - nFirst = i + 1; - for (nLast = -1, i = nThis + 1; i < nBars && nLast == -1; i++) - if (m_pDockBar->m_arrBars[i] == NULL) - nLast = i - 1; - - ASSERT((nLast != -1) && (nFirst != -1)); -} - -void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars) -{ - int nThis; // dummy - GetRowSizingBars(arrSCBars, nThis); -} - -void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars, int& nThis) -{ - arrSCBars.RemoveAll(); - - int nFirstT, nLastT, nThisT; - GetRowInfo(nFirstT, nLastT, nThisT); - - nThis = -1; - for (int i = nFirstT; i <= nLastT; i++) - { - CSizingControlBar* pBar = static_cast (m_pDockBar->m_arrBars[i]); - if (HIWORD(pBar) == 0) continue; // placeholder - if (!pBar->IsVisible()) continue; - if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - { - if (pBar == this) - nThis = arrSCBars.GetSize(); - - arrSCBars.Add(pBar); - } - } -} - -BOOL CSizingControlBar::NegotiateSpace(int nLengthTotal, BOOL bHorz) -{ - ASSERT(bHorz == IsHorzDocked()); - - int nFirst, nLast, nThis; - GetRowInfo(nFirst, nLast, nThis); - - int nLengthAvail = nLengthTotal; - int nLengthActual = 0; - int nLengthMin = 2; - int nWidthMax = 0; - CSizingControlBar* pBar; - - int i; - for (i = nFirst; i <= nLast; i++) - { - pBar = static_cast (m_pDockBar->m_arrBars[i]); - if (HIWORD(pBar) == 0) continue; // placeholder - if (!pBar->IsVisible()) continue; - BOOL bIsSizingBar = - pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar)); - - int nLengthBar; // minimum length of the bar - if (bIsSizingBar) - nLengthBar = bHorz ? pBar->m_szMinHorz.cx - 2 : - pBar->m_szMinVert.cy - 2; - else - { - CRect rcBar; - pBar->GetWindowRect(&rcBar); - nLengthBar = bHorz ? rcBar.Width() - 2 : rcBar.Height() - 2; - } - - nLengthMin += nLengthBar; - if (nLengthMin > nLengthTotal) - { - // split the row after fixed bar - if (i < nThis) - { - m_pDockBar->m_arrBars.InsertAt(i + 1, - (CControlBar*) NULL); - return FALSE; - } - - // only this sizebar remains on the row, adjust it to minsize - if (i == nThis) - { - if (bHorz) - m_szHorz.cx = m_szMinHorz.cx; - else - m_szVert.cy = m_szMinVert.cy; - - return TRUE; // the dockbar will split the row for us - } - - // we have enough bars - go negotiate with them - m_pDockBar->m_arrBars.InsertAt(i, (CControlBar*) NULL); - nLast = i - 1; - break; - } - - if (bIsSizingBar) - { - nLengthActual += bHorz ? pBar->m_szHorz.cx - 2 : - pBar->m_szVert.cy - 2; - nWidthMax = max(nWidthMax, bHorz ? pBar->m_szHorz.cy : - pBar->m_szVert.cx); - } - else - nLengthAvail -= nLengthBar; - } - - CSCBArray arrSCBars; - GetRowSizingBars(arrSCBars); - int nNumBars = arrSCBars.GetSize(); - int nDelta = nLengthAvail - nLengthActual; - - // return faster when there is only one sizing bar per row (this one) - if (nNumBars == 1) - { - ASSERT(arrSCBars[0] == this); - - if (nDelta == 0) - return TRUE; - - m_bKeepSize = FALSE; - (bHorz ? m_szHorz.cx : m_szVert.cy) += nDelta; - - return TRUE; - } - - // make all the bars the same width - for (i = 0; i < nNumBars; i++) - if (bHorz) - arrSCBars[i]->m_szHorz.cy = nWidthMax; - else - arrSCBars[i]->m_szVert.cx = nWidthMax; - - // distribute the difference between the bars, - // but don't shrink them below their minsizes - while (nDelta != 0) - { - int nDeltaOld = nDelta; - for (i = 0; i < nNumBars; i++) - { - pBar = arrSCBars[i]; - int nLMin = bHorz ? - pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy; - int nL = bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy; - - if ((nL == nLMin) && (nDelta < 0) || // already at min length - pBar->m_bKeepSize) // or wants to keep its size - continue; - - // sign of nDelta - int nDelta2 = (nDelta < 0) ? -1 : 1; - - (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta2; - nDelta -= nDelta2; - if (nDelta == 0) break; - } - // clear m_bKeepSize flags - if ((nDeltaOld == nDelta) || (nDelta == 0)) - for (i = 0; i < nNumBars; i++) - arrSCBars[i]->m_bKeepSize = FALSE; - } - - return TRUE; -} - -void CSizingControlBar::AlignControlBars() -{ - int nFirst, nLast, nThis; - GetRowInfo(nFirst, nLast, nThis); - - BOOL bHorz = IsHorzDocked(); - BOOL bNeedRecalc = FALSE; - int nAlign = bHorz ? -2 : 0; - - CRect rc, rcDock; - m_pDockBar->GetWindowRect(&rcDock); - - for (int i = nFirst; i <= nLast; i++) - { - CSizingControlBar* pBar = static_cast(m_pDockBar->m_arrBars[i]); - if (HIWORD(pBar) == 0) continue; // placeholder - if (!pBar->IsVisible()) continue; - - pBar->GetWindowRect(&rc); - rc.OffsetRect(-rcDock.TopLeft()); - - if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - rc = CRect(rc.TopLeft(), - bHorz ? pBar->m_szHorz : pBar->m_szVert); - - if ((bHorz ? rc.left : rc.top) != nAlign) - { - if (!bHorz) - rc.OffsetRect(0, nAlign - rc.top - 2); - else if (m_nDockBarID == AFX_IDW_DOCKBAR_TOP) - rc.OffsetRect(nAlign - rc.left, -2); - else - rc.OffsetRect(nAlign - rc.left, 0); - pBar->MoveWindow(rc); - bNeedRecalc = TRUE; - } - nAlign += (bHorz ? rc.Width() : rc.Height()) - 2; - } - - if (bNeedRecalc) - m_pDockSite->DelayRecalcLayout(); -} - -void CSizingControlBar::OnUpdateCmdUI(CFrameWnd* pTarget, - BOOL bDisableIfNoHndler) -{ - UNUSED_ALWAYS(bDisableIfNoHndler); - UNUSED_ALWAYS(pTarget); -} - -void CSizingControlBar::LoadState(LPCTSTR lpszProfileName) -{ - ASSERT_VALID(this); - ASSERT(GetSafeHwnd()); // must be called after Create() - -#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) - // compensate the caption miscalculation in CFrameWnd::SetDockState() - CDockState state; - state.LoadState(lpszProfileName); - - UINT nID = GetDlgCtrlID(); - for (int i = 0; i < state.m_arrBarInfo.GetSize(); i++) - { - CControlBarInfo* pInfo = (CControlBarInfo*)state.m_arrBarInfo[i]; - ASSERT(pInfo != NULL); - if (!pInfo->m_bFloating) - continue; - - // this is a floating dockbar - check the ID array - for (int j = 0; j < pInfo->m_arrBarID.GetSize(); j++) - if ((DWORD) pInfo->m_arrBarID[j] == nID) - { - // found this bar - offset origin and save settings - pInfo->m_pointPos.x++; - pInfo->m_pointPos.y += - ::GetSystemMetrics(SM_CYSMCAPTION) + 1; - pInfo->SaveState(lpszProfileName, i); - } - } -#endif //_SCB_REPLACE_MINIFRAME && !_SCB_MINIFRAME_CAPTION - - CWinApp* pApp = AfxGetApp(); - - TCHAR szSection[256]; - wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName, - GetDlgCtrlID()); - - m_szHorz.cx = max(m_szMinHorz.cx, (int) pApp->GetProfileInt( - szSection, _T("sizeHorzCX"), m_szHorz.cx)); - m_szHorz.cy = max(m_szMinHorz.cy, (int) pApp->GetProfileInt( - szSection, _T("sizeHorzCY"), m_szHorz.cy)); - - m_szVert.cx = max(m_szMinVert.cx, (int) pApp->GetProfileInt( - szSection, _T("sizeVertCX"), m_szVert.cx)); - m_szVert.cy = max(m_szMinVert.cy, (int) pApp->GetProfileInt( - szSection, _T("sizeVertCY"), m_szVert.cy)); - - m_szFloat.cx = max(m_szMinFloat.cx, (int) pApp->GetProfileInt( - szSection, _T("sizeFloatCX"), m_szFloat.cx)); - m_szFloat.cy = max(m_szMinFloat.cy, (int) pApp->GetProfileInt( - szSection, _T("sizeFloatCY"), m_szFloat.cy)); -} - -void CSizingControlBar::SaveState(LPCTSTR lpszProfileName) -{ - // place your SaveState or GlobalSaveState call in - // CMainFrame's OnClose() or DestroyWindow(), not in OnDestroy() - ASSERT_VALID(this); - ASSERT(GetSafeHwnd()); - - CWinApp* pApp = AfxGetApp(); - - TCHAR szSection[256]; - wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName, - GetDlgCtrlID()); - - pApp->WriteProfileInt(szSection, _T("sizeHorzCX"), m_szHorz.cx); - pApp->WriteProfileInt(szSection, _T("sizeHorzCY"), m_szHorz.cy); - - pApp->WriteProfileInt(szSection, _T("sizeVertCX"), m_szVert.cx); - pApp->WriteProfileInt(szSection, _T("sizeVertCY"), m_szVert.cy); - - pApp->WriteProfileInt(szSection, _T("sizeFloatCX"), m_szFloat.cx); - pApp->WriteProfileInt(szSection, _T("sizeFloatCY"), m_szFloat.cy); -} - -void CSizingControlBar::GlobalLoadState(CFrameWnd* pFrame, - LPCTSTR lpszProfileName) -{ - POSITION pos = pFrame->m_listControlBars.GetHeadPosition(); - while (pos != NULL) - { - CSizingControlBar* pBar = static_cast (pFrame->m_listControlBars.GetNext(pos)); - ASSERT(pBar != NULL); - if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - pBar->LoadState(lpszProfileName); - } -} - -void CSizingControlBar::GlobalSaveState(CFrameWnd* pFrame, - LPCTSTR lpszProfileName) -{ - POSITION pos = pFrame->m_listControlBars.GetHeadPosition(); - while (pos != NULL) - { - CSizingControlBar* pBar = static_cast (pFrame->m_listControlBars.GetNext(pos)); - ASSERT(pBar != NULL); - if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - pBar->SaveState(lpszProfileName); - } -} - -//mpc-hc custom code start -void CSizingControlBar::mpc_fillNcBG(CDC* mdc, CRect rcDraw) { - mdc->FillRect(rcDraw, CBrush::FromHandle( - (HBRUSH)GetClassLongPtr(m_hWnd, GCLP_HBRBACKGROUND))); -} -//mpc-hc custom code end - -#ifdef _SCB_REPLACE_MINIFRAME -#ifndef _SCB_MINIFRAME_CAPTION -///////////////////////////////////////////////////////////////////////////// -// CSCBDockContext Drag Operations - -static void AdjustRectangle(CRect& rect, CPoint pt) -{ - int nXOffset = (pt.x < rect.left) ? (pt.x - rect.left) : - (pt.x > rect.right) ? (pt.x - rect.right) : 0; - int nYOffset = (pt.y < rect.top) ? (pt.y - rect.top) : - (pt.y > rect.bottom) ? (pt.y - rect.bottom) : 0; - rect.OffsetRect(nXOffset, nYOffset); -} - -void CSCBDockContext::StartDrag(CPoint pt) -{ - ASSERT_VALID(m_pBar); - m_bDragging = TRUE; - - InitLoop(); - - ASSERT((m_pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) != 0); - - // get true bar size (including borders) - CRect rect; - m_pBar->GetWindowRect(rect); - m_ptLast = pt; - CSize sizeHorz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK); - CSize sizeVert = m_pBar->CalcDynamicLayout(0, LM_VERTDOCK); - CSize sizeFloat = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH); - - m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz); - m_rectDragVert = CRect(rect.TopLeft(), sizeVert); - - // calculate frame dragging rectangle - m_rectFrameDragHorz = CRect(rect.TopLeft(), sizeFloat); - -#ifdef _MAC - CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, - WS_THICKFRAME, WS_EX_FORCESIZEBOX); -#else - CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, WS_THICKFRAME); -#endif - m_rectFrameDragHorz.DeflateRect(2, 2); - m_rectFrameDragVert = m_rectFrameDragHorz; - - // adjust rectangles so that point is inside - AdjustRectangle(m_rectDragHorz, pt); - AdjustRectangle(m_rectDragVert, pt); - AdjustRectangle(m_rectFrameDragHorz, pt); - AdjustRectangle(m_rectFrameDragVert, pt); - - // initialize tracking state and enter tracking loop - m_dwOverDockStyle = CanDock(); - Move(pt); // call it here to handle special keys - Track(); -} -#endif //_SCB_MINIFRAME_CAPTION - -///////////////////////////////////////////////////////////////////////////// -// CSCBMiniDockFrameWnd - -IMPLEMENT_DYNCREATE(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd); - -BEGIN_MESSAGE_MAP(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd) - //{{AFX_MSG_MAP(CSCBMiniDockFrameWnd) - ON_WM_NCLBUTTONDOWN() - ON_WM_GETMINMAXINFO() - ON_WM_WINDOWPOSCHANGING() - ON_WM_SIZE() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -BOOL CSCBMiniDockFrameWnd::Create(CWnd* pParent, DWORD dwBarStyle) -{ - // set m_bInRecalcLayout to avoid flashing during creation - // RecalcLayout will be called once something is docked - m_bInRecalcLayout = TRUE; - - DWORD dwStyle = WS_POPUP|WS_CAPTION|WS_SYSMENU|MFS_MOVEFRAME| - MFS_4THICKFRAME|MFS_SYNCACTIVE|MFS_BLOCKSYSMENU| - FWS_SNAPTOBARS; - - if (dwBarStyle & CBRS_SIZE_DYNAMIC) - dwStyle &= ~MFS_MOVEFRAME; - - DWORD dwExStyle = 0; -#ifdef _MAC - if (dwBarStyle & CBRS_SIZE_DYNAMIC) - dwExStyle |= WS_EX_FORCESIZEBOX; - else - dwStyle &= ~(MFS_MOVEFRAME|MFS_4THICKFRAME); -#endif - - if (!CMiniFrameWnd::CreateEx(dwExStyle, - NULL, "", dwStyle, rectDefault, pParent)) - { - m_bInRecalcLayout = FALSE; - return FALSE; - } - dwStyle = dwBarStyle & (CBRS_ALIGN_LEFT|CBRS_ALIGN_RIGHT) ? - CBRS_ALIGN_LEFT : CBRS_ALIGN_TOP; - dwStyle |= dwBarStyle & CBRS_FLOAT_MULTI; - CMenu* pSysMenu = GetSystemMenu(FALSE); - //pSysMenu->DeleteMenu(SC_SIZE, MF_BYCOMMAND); - CString strHide; - if (strHide.LoadString(AFX_IDS_HIDE)) - { - pSysMenu->DeleteMenu(SC_CLOSE, MF_BYCOMMAND); - pSysMenu->AppendMenu(MF_STRING|MF_ENABLED, SC_CLOSE, strHide); - } - - // must initially create with parent frame as parent - if (!m_wndDockBar.Create(pParent, WS_CHILD | WS_VISIBLE | dwStyle, - AFX_IDW_DOCKBAR_FLOAT)) - { - m_bInRecalcLayout = FALSE; - return FALSE; - } - - // set parent to CMiniDockFrameWnd - m_wndDockBar.SetParent(this); - m_bInRecalcLayout = FALSE; - - return TRUE; -} - -void CSCBMiniDockFrameWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - if (nHitTest == HTCAPTION || nHitTest == HTCLOSE) - { - baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); - return; - } - - if (GetSizingControlBar() != NULL) - CMiniFrameWnd::OnNcLButtonDown(nHitTest, point); - else - baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); -} - -CSizingControlBar* CSCBMiniDockFrameWnd::GetSizingControlBar() -{ - CWnd* pWnd = GetWindow(GW_CHILD); // get the dockbar - if (pWnd == NULL) - return NULL; - - pWnd = pWnd->GetWindow(GW_CHILD); // get the controlbar - if (pWnd == NULL) - return NULL; - - if (!pWnd->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - return NULL; - - return static_cast (pWnd); -} - -void CSCBMiniDockFrameWnd::OnSize(UINT nType, int cx, int cy) -{ - CSizingControlBar* pBar = GetSizingControlBar(); - if ((pBar != NULL) && (GetStyle() & MFS_4THICKFRAME) == 0 - && pBar->IsVisible() && - cx + 4 >= pBar->m_szMinFloat.cx && - cy + 4 >= pBar->m_szMinFloat.cy) - pBar->m_szFloat = CSize(cx + 4, cy + 4); - - baseCSCBMiniDockFrameWnd::OnSize(nType, cx, cy); -} - -void CSCBMiniDockFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) -{ - baseCSCBMiniDockFrameWnd::OnGetMinMaxInfo(lpMMI); - - CSizingControlBar* pBar = GetSizingControlBar(); - if (pBar != NULL) - { - CRect r(CPoint(0, 0), pBar->m_szMinFloat - CSize(4, 4)); -#ifndef _SCB_MINIFRAME_CAPTION - CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME); -#else - CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME|WS_CAPTION); -#endif //_SCB_MINIFRAME_CAPTION - lpMMI->ptMinTrackSize.x = r.Width(); - lpMMI->ptMinTrackSize.y = r.Height(); -// mpc-hc custom code start - if(pBar->m_bFixedFloat) - { - lpMMI->ptMinTrackSize.x = pBar->m_szFixedFloat.cx; - lpMMI->ptMinTrackSize.y = pBar->m_szFixedFloat.cy; - lpMMI->ptMaxTrackSize.x = pBar->m_szFixedFloat.cx; - lpMMI->ptMaxTrackSize.y = pBar->m_szFixedFloat.cy; - } -// mpc-hc custom code end - } -} - -void CSCBMiniDockFrameWnd::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) -{ - if ((GetStyle() & MFS_4THICKFRAME) != 0) - { - CSizingControlBar* pBar = GetSizingControlBar(); - if (pBar != NULL) - { - lpwndpos->flags |= SWP_NOSIZE; // don't size this time - // prevents flicker - pBar->m_pDockBar->ModifyStyle(0, WS_CLIPCHILDREN); - - // enable diagonal resizing - DWORD dwStyleRemove = MFS_4THICKFRAME; -#ifndef _SCB_MINIFRAME_CAPTION - // remove caption - dwStyleRemove |= WS_SYSMENU|WS_CAPTION; -#endif - ModifyStyle(dwStyleRemove, 0); - - DelayRecalcLayout(); - pBar->PostMessage(WM_NCPAINT); - } - } - - CMiniFrameWnd::OnWindowPosChanging(lpwndpos); -} - -#endif //_SCB_REPLACE_MINIFRAME +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBar Version 2.45 +// +// Created: Jan 24, 1998 Last Modified: April 16, 2010 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com . +// +// The sources and a short version of the docs are also available at +// www.codeproject.com . Look for a "Docking Windows" section and check +// the version to be sure you get the latest one ;) +// +// Hint: These classes are intended to be used as base classes. Do not +// simply add your code to these files - instead create a new class +// derived from one of CSizingControlBarXX classes and put there what +// you need. See CMyBar classes in the demo projects for examples. +// Modify this file only to fix bugs, and don't forget to send me a copy. +///////////////////////////////////////////////////////////////////////// +// Acknowledgements: +// o Thanks to Harlan R. Seymour for his continuous support during +// development of this code. +// o Thanks to Dundas Software and Formatta Corporation for the +// opportunities to test this code on real-life applications. +// o Some ideas for the gripper came from the CToolBarEx flat toolbar +// by Joerg Koenig. Thanks, Joerg! +// o Thanks to Robert Wolpow for the code on which CDockContext based +// dialgonal resizing is based. +// o Thanks to the following people for various bug fixes and/or +// enhancements: Chris Maunder, Jakawan Ratiwanich, Udo Schaefer, +// Anatoly Ivasyuk, Peter Hauptmann, DJ(?), Pat Kusbel, Aleksey +// Malyshev, and many others who used this code and sent feedback. +///////////////////////////////////////////////////////////////////////// + +// sizecbar.cpp : implementation file +// + +#include "stdafx.h" +#include "sizecbar.h" + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar + +IMPLEMENT_DYNAMIC(CSizingControlBar, baseCSizingControlBar); + +CSizingControlBar::CSizingControlBar() +{ + m_szMinHorz = CSize(33, 32); + m_szMinVert = CSize(33, 32); + m_szMinFloat = CSize(37, 32); + m_szHorz = CSize(200, 200); + m_szVert = CSize(200, 200); + m_szFloat = CSize(200, 200); + m_bTracking = FALSE; + m_bKeepSize = FALSE; + m_bParentSizing = FALSE; + m_cxEdge = 5; + m_bDragShowContent = FALSE; + m_nDockBarID = 0; + m_dwSCBStyle = 0; + m_htEdge = 0; + m_nTrackPosMin = 0; + m_nTrackPosMax = 0; + m_nTrackPosOld = 0; + m_nTrackEdgeOfs = 0; + m_bFixedFloat = FALSE; +} + +CSizingControlBar::~CSizingControlBar() +{ +} + +BEGIN_MESSAGE_MAP(CSizingControlBar, baseCSizingControlBar) + //{{AFX_MSG_MAP(CSizingControlBar) + ON_WM_CREATE() + ON_WM_PAINT() + ON_WM_NCPAINT() + ON_WM_NCCALCSIZE() + ON_WM_WINDOWPOSCHANGING() + ON_WM_CAPTURECHANGED() + ON_WM_SETTINGCHANGE() + ON_WM_LBUTTONUP() + ON_WM_MOUSEMOVE() + ON_WM_NCLBUTTONDOWN() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONDBLCLK() + ON_WM_RBUTTONDOWN() + ON_WM_NCMOUSEMOVE() + ON_WM_NCHITTEST() + ON_WM_CLOSE() + ON_WM_SIZE() + //}}AFX_MSG_MAP + ON_MESSAGE(WM_SETTEXT, OnSetText) +END_MESSAGE_MAP() + +// old creation method, still here for compatibility reasons +BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, + CSize sizeDefault, BOOL bHasGripper, + UINT nID, DWORD dwStyle) +{ + UNUSED_ALWAYS(bHasGripper); + + m_szHorz = m_szVert = m_szFloat = sizeDefault; + return Create(lpszWindowName, pParentWnd, nID, dwStyle); +} + +// preffered creation method +BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, + CWnd* pParentWnd, UINT nID, + DWORD dwStyle) +{ + // must have a parent + ASSERT_VALID(pParentWnd); + // cannot be both fixed and dynamic + // (CBRS_SIZE_DYNAMIC is used for resizng when floating) + ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && + (dwStyle & CBRS_SIZE_DYNAMIC))); + + m_dwStyle = dwStyle & CBRS_ALL; // save the control bar styles + + // register and create the window - skip CControlBar::Create() + CString wndclass = ::AfxRegisterWndClass(CS_DBLCLKS, + ::LoadCursor(NULL, IDC_ARROW), + ::GetSysColorBrush(COLOR_BTNFACE), 0); + + dwStyle &= ~CBRS_ALL; // keep only the generic window styles + dwStyle |= WS_CLIPCHILDREN; // prevents flashing + if (!CWnd::Create(wndclass, lpszWindowName, dwStyle, + CRect(0, 0, 0, 0), pParentWnd, nID)) + return FALSE; + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar operations +#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) +void CSizingControlBar::EnableDocking(DWORD dwDockStyle) +{ + // must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only + ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI)) == 0); + // cannot have the CBRS_FLOAT_MULTI style + ASSERT((dwDockStyle & CBRS_FLOAT_MULTI) == 0); + // the bar must have CBRS_SIZE_DYNAMIC style + ASSERT((m_dwStyle & CBRS_SIZE_DYNAMIC) != 0); + + m_dwDockStyle = dwDockStyle; + if (m_pDockContext == NULL) + m_pDockContext = new CSCBDockContext(this); + + // permanently wire the bar's owner to its current parent + if (m_hWndOwner == NULL) + m_hWndOwner = ::GetParent(m_hWnd); +} +#endif + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar message handlers + +int CSizingControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (baseCSizingControlBar::OnCreate(lpCreateStruct) == -1) + return -1; + + // query SPI_GETDRAGFULLWINDOWS system parameter + // OnSettingChange() will update m_bDragShowContent + m_bDragShowContent = FALSE; + ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, + &m_bDragShowContent, 0); + + // uncomment this line if you want raised borders +// m_dwSCBStyle |= SCBS_SHOWEDGES; + + return 0; +} + + +LRESULT CSizingControlBar::OnSetText(WPARAM wParam, LPARAM lParam) +{ + UNUSED_ALWAYS(wParam); + + LRESULT lResult = CWnd::Default(); + + if (IsFloating() && + GetParentFrame()->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd))) + { + m_pDockBar->SetWindowText((LPCTSTR) lParam); // update dockbar + GetParentFrame()->DelayRecalcLayout(); // refresh miniframe + } + + return lResult; +} + +const BOOL CSizingControlBar::IsFloating() const +{ + return !IsHorzDocked() && !IsVertDocked(); +} + +const BOOL CSizingControlBar::IsHorzDocked() const +{ + return (m_nDockBarID == AFX_IDW_DOCKBAR_TOP || + m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); +} + +const BOOL CSizingControlBar::IsVertDocked() const +{ + return (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT || + m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT); +} + +const BOOL CSizingControlBar::IsSideTracking() const +{ + // don't call this when not tracking + ASSERT(m_bTracking && !IsFloating()); + + return (m_htEdge == HTLEFT || m_htEdge == HTRIGHT) ? + IsHorzDocked() : IsVertDocked(); +} + +CSize CSizingControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) +{ + if (bStretch) // the bar is stretched (is not the child of a dockbar) + if (bHorz) + return CSize(32767, m_szHorz.cy); + else + return CSize(m_szVert.cx, 32767); + + // dirty cast - we need access to protected CDockBar members + CSCBDockBar* pDockBar = static_cast (m_pDockBar); + + // force imediate RecalcDelayShow() for all sizing bars on the row + // with delayShow/delayHide flags set to avoid IsVisible() problems + CSCBArray arrSCBars; + GetRowSizingBars(arrSCBars); + AFX_SIZEPARENTPARAMS layout; + layout.hDWP = pDockBar->m_bLayoutQuery ? + NULL : ::BeginDeferWindowPos(arrSCBars.GetSize()); + for (int i = 0; i < arrSCBars.GetSize(); i++) + if (arrSCBars[i]->m_nStateFlags & (delayHide|delayShow)) + arrSCBars[i]->RecalcDelayShow(&layout); + if (layout.hDWP != NULL) + ::EndDeferWindowPos(layout.hDWP); + + // get available length + CRect rc = pDockBar->m_rectLayout; + if (rc.IsRectEmpty()) + m_pDockSite->GetClientRect(&rc); + int nLengthTotal = bHorz ? rc.Width() + 2 : rc.Height() - 2; + + if (IsVisible() && !IsFloating() && + m_bParentSizing && arrSCBars[0] == this) + if (NegotiateSpace(nLengthTotal, (bHorz != FALSE))) + AlignControlBars(); + + m_bParentSizing = FALSE; + + if (bHorz) + return CSize(max(m_szMinHorz.cx, m_szHorz.cx), + max(m_szMinHorz.cy, m_szHorz.cy)); + + return CSize(max(m_szMinVert.cx, m_szVert.cx), + max(m_szMinVert.cy, m_szVert.cy)); +} + +CSize CSizingControlBar::CalcDynamicLayout(int nLength, DWORD dwMode) +{ + if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) // docked ? + { + if (nLength == -1) + m_bParentSizing = TRUE; + + return baseCSizingControlBar::CalcDynamicLayout(nLength, dwMode); + } + + if (dwMode & LM_MRUWIDTH) return m_szFloat; + if (dwMode & LM_COMMIT) return m_szFloat; // already committed + +#ifndef _SCB_REPLACE_MINIFRAME + // check for dialgonal resizing hit test + int nHitTest = m_pDockContext->m_nHitTest; + if (IsFloating() && + (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT || + nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT)) + { + CPoint ptCursor; + ::GetCursorPos(&ptCursor); + + CRect rFrame, rBar; + GetParentFrame()->GetWindowRect(&rFrame); + GetWindowRect(&rBar); + + if (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT) + { + m_szFloat.cx = rFrame.left + rBar.Width() - ptCursor.x; + m_pDockContext->m_rectFrameDragHorz.left = + min(ptCursor.x, rFrame.left + rBar.Width() - m_szMinFloat.cx); + } + + if (nHitTest == HTTOPLEFT || nHitTest == HTTOPRIGHT) + { + m_szFloat.cy = rFrame.top + rBar.Height() - ptCursor.y; + m_pDockContext->m_rectFrameDragHorz.top = + min(ptCursor.y, rFrame.top + rBar.Height() - m_szMinFloat.cy); + } + + if (nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT) + m_szFloat.cx = rBar.Width() + ptCursor.x - rFrame.right; + + if (nHitTest == HTBOTTOMLEFT || nHitTest == HTBOTTOMRIGHT) + m_szFloat.cy = rBar.Height() + ptCursor.y - rFrame.bottom; + } + else +#endif //_SCB_REPLACE_MINIFRAME + ((dwMode & LM_LENGTHY) ? m_szFloat.cy : m_szFloat.cx) = nLength; + + m_szFloat.cx = max(m_szFloat.cx, m_szMinFloat.cx); + m_szFloat.cy = max(m_szFloat.cy, m_szMinFloat.cy); + + return m_szFloat; +} + +void CSizingControlBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) +{ + // force non-client recalc if moved or resized + lpwndpos->flags |= SWP_FRAMECHANGED; + + baseCSizingControlBar::OnWindowPosChanging(lpwndpos); + + // find on which side are we docked + m_nDockBarID = GetParent()->GetDlgCtrlID(); + + if (!IsFloating()) + if (lpwndpos->flags & SWP_SHOWWINDOW) + m_bKeepSize = TRUE; +} + +///////////////////////////////////////////////////////////////////////// +// Mouse Handling +// +void CSizingControlBar::OnLButtonDown(UINT nFlags, CPoint point) +{ + if (m_pDockBar != NULL) + { + // start the drag + ASSERT(m_pDockContext != NULL); + ClientToScreen(&point); + m_pDockContext->StartDrag(point); + } + else + CWnd::OnLButtonDown(nFlags, point); +} + +void CSizingControlBar::OnLButtonDblClk(UINT nFlags, CPoint point) +{ + if (m_pDockBar != NULL) + { + // toggle docking + ASSERT(m_pDockContext != NULL); + m_pDockContext->ToggleDocking(); + } + else + CWnd::OnLButtonDblClk(nFlags, point); +} + +void CSizingControlBar::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + UNUSED_ALWAYS(point); + + if (m_bTracking || IsFloating()) + return; + + if ((nHitTest >= HTSIZEFIRST) && (nHitTest <= HTSIZELAST)) + StartTracking(nHitTest, point); // sizing edge hit +} + +void CSizingControlBar::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (m_bTracking) + StopTracking(); + + baseCSizingControlBar::OnLButtonUp(nFlags, point); +} + +void CSizingControlBar::OnRButtonDown(UINT nFlags, CPoint point) +{ + if (m_bTracking) + StopTracking(); + + baseCSizingControlBar::OnRButtonDown(nFlags, point); +} + +void CSizingControlBar::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_bTracking) + { + CPoint ptScreen = point; + ClientToScreen(&ptScreen); + + //mpc-hc custom code start + // Switch to parent window client coordinates to account for possible RTL layout + CPoint ptParentClient = ptScreen; + GetParentFrame()->ScreenToClient(&ptParentClient); + OnTrackUpdateSize(ptParentClient); + //mpc-hc custom code end + } + + baseCSizingControlBar::OnMouseMove(nFlags, point); +} + +void CSizingControlBar::OnCaptureChanged(CWnd *pWnd) +{ + if (m_bTracking && (pWnd != this)) + StopTracking(); + + baseCSizingControlBar::OnCaptureChanged(pWnd); +} + +void CSizingControlBar::OnNcCalcSize(BOOL bCalcValidRects, + NCCALCSIZE_PARAMS FAR* lpncsp) +{ + UNUSED_ALWAYS(bCalcValidRects); + +#ifndef _SCB_REPLACE_MINIFRAME + // Enable diagonal resizing for floating miniframe + if (IsFloating()) + { + CFrameWnd* pFrame = GetParentFrame(); + if (pFrame != NULL && + pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd))) + { +//mpc-hc custom code start + LONG_PTR dwStyle = ::GetWindowLongPtr(pFrame->m_hWnd, GWL_STYLE); +//mpc-hc custom code end + if ((dwStyle & MFS_4THICKFRAME) != 0) + { + pFrame->ModifyStyle(MFS_4THICKFRAME, 0); // clear + GetParent()->ModifyStyle(0, WS_CLIPCHILDREN); + } + } + } +#endif _SCB_REPLACE_MINIFRAME + + // compute the the client area + m_dwSCBStyle &= ~SCBS_EDGEALL; + + // add resizing edges between bars on the same row + if (!IsFloating() && m_pDockBar != NULL) + { + CSCBArray arrSCBars; + int nThis; + GetRowSizingBars(arrSCBars, nThis); + + BOOL bHorz = IsHorzDocked(); + if (nThis > 0) + m_dwSCBStyle |= bHorz ? SCBS_EDGELEFT : SCBS_EDGETOP; + + if (nThis < arrSCBars.GetUpperBound()) + m_dwSCBStyle |= bHorz ? SCBS_EDGERIGHT : SCBS_EDGEBOTTOM; + } + + NcCalcClient(&lpncsp->rgrc[0], m_nDockBarID); +} + +void CSizingControlBar::NcCalcClient(LPRECT pRc, UINT nDockBarID) +{ + CRect rc(pRc); + //mpc-hc custom code start + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ClientToScreen(&rc); + //mpc-hc custom code end + + rc.DeflateRect(3, 5, 3, 3); + if (nDockBarID != AFX_IDW_DOCKBAR_FLOAT) + rc.DeflateRect(2, 0, 2, 2); + + switch(nDockBarID) + { + case AFX_IDW_DOCKBAR_TOP: + m_dwSCBStyle |= SCBS_EDGEBOTTOM; + break; + case AFX_IDW_DOCKBAR_BOTTOM: + m_dwSCBStyle |= SCBS_EDGETOP; + break; + case AFX_IDW_DOCKBAR_LEFT: + m_dwSCBStyle |= SCBS_EDGERIGHT; + break; + case AFX_IDW_DOCKBAR_RIGHT: + m_dwSCBStyle |= SCBS_EDGELEFT; + break; + } + + // make room for edges only if they will be painted + if (m_dwSCBStyle & SCBS_SHOWEDGES) + rc.DeflateRect( + (m_dwSCBStyle & SCBS_EDGELEFT) ? m_cxEdge : 0, + (m_dwSCBStyle & SCBS_EDGETOP) ? m_cxEdge : 0, + (m_dwSCBStyle & SCBS_EDGERIGHT) ? m_cxEdge : 0, + (m_dwSCBStyle & SCBS_EDGEBOTTOM) ? m_cxEdge : 0); + + //mpc-hc custom code start + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ScreenToClient(&rc); + //mpc-hc custom code end + + *pRc = rc; +} + +void CSizingControlBar::OnNcPaint() +{ + // get window DC that is clipped to the non-client area + CWindowDC dc(this); // the HDC will be released by the destructor + + CRect rcClient, rcBar; + GetClientRect(rcClient); + //mpc-hc custom code start + //ClientToScreen(rcClient); + //mpc-hc custom code end + GetWindowRect(rcBar); + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + ScreenToClient(rcBar); + //mpc-hc custom code end + rcClient.OffsetRect(-rcBar.TopLeft()); + rcBar.OffsetRect(-rcBar.TopLeft()); + + CDC mdc; + mdc.CreateCompatibleDC(&dc); + + CBitmap bm; + bm.CreateCompatibleBitmap(&dc, rcBar.Width(), rcBar.Height()); + CBitmap* pOldBm = mdc.SelectObject(&bm); + + // draw borders in non-client area + CRect rcDraw = rcBar; + DrawBorders(&mdc, rcDraw); + + // erase the NC background +//mpc-hc custom code start + mpc_fillNcBG(&mdc, rcDraw); +//mpc-hc custom code end + + if (m_dwSCBStyle & SCBS_SHOWEDGES) + { + CRect rcEdge; // paint the sizing edges + for (int i = 0; i < 4; i++) + if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge)) + mdc.Draw3dRect(rcEdge, ::GetSysColor(COLOR_BTNHIGHLIGHT), + ::GetSysColor(COLOR_BTNSHADOW)); + } + + NcPaintGripper(&mdc, rcClient); + + // client area is not our bussiness :) + dc.IntersectClipRect(rcBar); + dc.ExcludeClipRect(rcClient); + + dc.BitBlt(0, 0, rcBar.Width(), rcBar.Height(), &mdc, 0, 0, SRCCOPY); + + mdc.SelectObject(pOldBm); + bm.DeleteObject(); + mdc.DeleteDC(); +} + +void CSizingControlBar::NcPaintGripper(CDC* pDC, CRect rcClient) +{ + UNUSED_ALWAYS(pDC); + UNUSED_ALWAYS(rcClient); +} + +void CSizingControlBar::OnPaint() +{ + // overridden to skip border painting based on clientrect + CPaintDC dc(this); +} + +LRESULT CSizingControlBar::OnNcHitTest(CPoint point) +{ + CRect rcBar, rcEdge; + GetWindowRect(rcBar); + + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + ScreenToClient(&rcBar); + ScreenToClient(&point); + //mpc-hc custom code end + + if (!IsFloating()) + for (int i = 0; i < 4; i++) + if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge)) + if (rcEdge.PtInRect(point)) + return GetEdgeHTCode(i); + + return HTCLIENT; +} + +void CSizingControlBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) +{ + baseCSizingControlBar::OnSettingChange(uFlags, lpszSection); + + m_bDragShowContent = FALSE; + ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, + &m_bDragShowContent, 0); // update +} + +void CSizingControlBar::OnSize(UINT nType, int cx, int cy) +{ + UNUSED_ALWAYS(nType); + + if ((m_dwSCBStyle & SCBS_SIZECHILD) != 0) + { + // automatic child resizing - only one child is allowed + CWnd* pWnd = GetWindow(GW_CHILD); + if (pWnd != NULL) + { + pWnd->MoveWindow(0, 0, cx, cy); + ASSERT(pWnd->GetWindow(GW_HWNDNEXT) == NULL); + } + } +} + +void CSizingControlBar::OnClose() +{ + // do nothing: protection against accidentally destruction by the + // child control (i.e. if user hits Esc in a child editctrl) +} + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar implementation helpers + +void CSizingControlBar::StartTracking(UINT nHitTest, CPoint point) +{ + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + GetParentFrame()->ScreenToClient(&point); + //mpc-hc custom code end + + SetCapture(); + + // make sure no updates are pending + if (!m_bDragShowContent) + RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); + + m_htEdge = nHitTest; + m_bTracking = TRUE; + + BOOL bHorz = IsHorzDocked(); + BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; + + m_nTrackPosOld = bHorzTracking ? point.x : point.y; + + CRect rcBar, rcEdge; + GetWindowRect(rcBar); + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + GetParent()->ScreenToClient(&rcBar); + //mpc-hc custom code end + GetEdgeRect(rcBar, m_htEdge, rcEdge); + m_nTrackEdgeOfs = m_nTrackPosOld - + (bHorzTracking ? rcEdge.CenterPoint().x : rcEdge.CenterPoint().y); + + CSCBArray arrSCBars; + int nThis; + GetRowSizingBars(arrSCBars, nThis); + + m_nTrackPosMin = m_nTrackPosMax = m_nTrackPosOld; + if (!IsSideTracking()) + { + // calc minwidth as the max minwidth of the sizing bars on row + int nMinWidth = bHorz ? m_szMinHorz.cy : m_szMinVert.cx; + for (int i = 0; i < arrSCBars.GetSize(); i++) + nMinWidth = max(nMinWidth, bHorz ? + arrSCBars[i]->m_szMinHorz.cy : + arrSCBars[i]->m_szMinVert.cx); + int nExcessWidth = (bHorz ? m_szHorz.cy : m_szVert.cx) - nMinWidth; + + // the control bar cannot grow with more than the width of + // remaining client area of the mainframe + CRect rcT; + m_pDockSite->RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST, + reposQuery, &rcT, NULL, TRUE); + int nMaxWidth = bHorz ? rcT.Height() - 2 : rcT.Width() - 2; + + BOOL bTopOrLeft = m_htEdge == HTTOP || m_htEdge == HTLEFT; + + m_nTrackPosMin -= bTopOrLeft ? nMaxWidth : nExcessWidth; + m_nTrackPosMax += bTopOrLeft ? nExcessWidth : nMaxWidth; + } + else + { + // side tracking: + // max size is the actual size plus the amount the other + // sizing bars can be decreased until they reach their minsize + if (m_htEdge == HTBOTTOM || m_htEdge == HTRIGHT) + nThis++; + + for (int i = 0; i < arrSCBars.GetSize(); i++) + { + CSizingControlBar* pBar = arrSCBars[i]; + + int nExcessWidth = bHorz ? + pBar->m_szHorz.cx - pBar->m_szMinHorz.cx : + pBar->m_szVert.cy - pBar->m_szMinVert.cy; + + if (i < nThis) + m_nTrackPosMin -= nExcessWidth; + else + m_nTrackPosMax += nExcessWidth; + } + } + + OnTrackInvertTracker(); // draw tracker +} + +void CSizingControlBar::StopTracking() +{ + OnTrackInvertTracker(); // erase tracker + + m_bTracking = FALSE; + ReleaseCapture(); + + m_pDockSite->DelayRecalcLayout(); +} + +void CSizingControlBar::OnTrackUpdateSize(CPoint& point) +{ + ASSERT(!IsFloating()); + + BOOL bHorzTrack = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; + + int nTrackPos = bHorzTrack ? point.x : point.y; + nTrackPos = max(m_nTrackPosMin, min(m_nTrackPosMax, nTrackPos)); + + int nDelta = nTrackPos - m_nTrackPosOld; + + if (nDelta == 0) + return; // no pos change + + OnTrackInvertTracker(); // erase tracker + + m_nTrackPosOld = nTrackPos; + + BOOL bHorz = IsHorzDocked(); + + CSize sizeNew = bHorz ? m_szHorz : m_szVert; + switch (m_htEdge) + { + case HTLEFT: sizeNew -= CSize(nDelta, 0); break; + case HTTOP: sizeNew -= CSize(0, nDelta); break; + case HTRIGHT: sizeNew += CSize(nDelta, 0); break; + case HTBOTTOM: sizeNew += CSize(0, nDelta); break; + } + + CSCBArray arrSCBars; + int nThis; + GetRowSizingBars(arrSCBars, nThis); + + if (!IsSideTracking()) + for (int i = 0; i < arrSCBars.GetSize(); i++) + { + CSizingControlBar* pBar = arrSCBars[i]; + // make same width (or height) + (bHorz ? pBar->m_szHorz.cy : pBar->m_szVert.cx) = + bHorz ? sizeNew.cy : sizeNew.cx; + } + else + { + int nGrowingBar = nThis; + BOOL bBefore = m_htEdge == HTTOP || m_htEdge == HTLEFT; + if (bBefore && nDelta > 0) + nGrowingBar--; + if (!bBefore && nDelta < 0) + nGrowingBar++; + if (nGrowingBar != nThis) + bBefore = !bBefore; + + // nGrowing is growing + nDelta = abs(nDelta); + CSizingControlBar* pBar = arrSCBars[nGrowingBar]; + (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta; + + // the others are shrinking + int nFirst = bBefore ? nGrowingBar - 1 : nGrowingBar + 1; + int nLimit = bBefore ? -1 : arrSCBars.GetSize(); + + for (int i = nFirst; nDelta != 0 && i != nLimit; i += (bBefore ? -1 : 1)) + { + CSizingControlBar* pBar = arrSCBars[i]; + + int nDeltaT = min(nDelta, + (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) - + (bHorz ? pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy)); + + (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) -= nDeltaT; + nDelta -= nDeltaT; + } + } + + OnTrackInvertTracker(); // redraw tracker at new pos + + if (m_bDragShowContent) + m_pDockSite->DelayRecalcLayout(); +} + +void CSizingControlBar::OnTrackInvertTracker() +{ + ASSERT(m_bTracking); + + if (m_bDragShowContent) + return; // don't show tracker if DragFullWindows is on + + BOOL bHorz = IsHorzDocked(); + CRect rc, rcBar, rcDock, rcFrame; + GetWindowRect(rcBar); + m_pDockBar->GetWindowRect(rcDock); + m_pDockSite->GetWindowRect(rcFrame); + VERIFY(GetEdgeRect(rcBar, m_htEdge, rc)); + if (!IsSideTracking()) + rc = bHorz ? + CRect(rcDock.left + 1, rc.top, rcDock.right - 1, rc.bottom) : + CRect(rc.left, rcDock.top + 1, rc.right, rcDock.bottom - 1); + + BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; + int nOfs = m_nTrackPosOld - m_nTrackEdgeOfs; + nOfs -= bHorzTracking ? rc.CenterPoint().x : rc.CenterPoint().y; + rc.OffsetRect(bHorzTracking ? nOfs : 0, bHorzTracking ? 0 : nOfs); + rc.OffsetRect(-rcFrame.TopLeft()); + + CDC *pDC = m_pDockSite->GetDCEx(NULL, + DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); + CBrush* pBrush = CDC::GetHalftoneBrush(); + CBrush* pBrushOld = pDC->SelectObject(pBrush); + + pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATINVERT); + + pDC->SelectObject(pBrushOld); + m_pDockSite->ReleaseDC(pDC); +} + +BOOL CSizingControlBar::GetEdgeRect(CRect rcWnd, UINT nHitTest, + CRect& rcEdge) +{ + rcEdge = rcWnd; + if (m_dwSCBStyle & SCBS_SHOWEDGES) + rcEdge.DeflateRect(1, 1); + BOOL bHorz = IsHorzDocked(); + + switch (nHitTest) + { + case HTLEFT: + if (!(m_dwSCBStyle & SCBS_EDGELEFT)) return FALSE; + rcEdge.right = rcEdge.left + m_cxEdge; + rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0); + break; + case HTTOP: + if (!(m_dwSCBStyle & SCBS_EDGETOP)) return FALSE; + rcEdge.bottom = rcEdge.top + m_cxEdge; + rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0); + break; + case HTRIGHT: + if (!(m_dwSCBStyle & SCBS_EDGERIGHT)) return FALSE; + rcEdge.left = rcEdge.right - m_cxEdge; + rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0); + break; + case HTBOTTOM: + if (!(m_dwSCBStyle & SCBS_EDGEBOTTOM)) return FALSE; + rcEdge.top = rcEdge.bottom - m_cxEdge; + rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0); + break; + default: + ASSERT(FALSE); // invalid hit test code + } + return TRUE; +} + +UINT CSizingControlBar::GetEdgeHTCode(int nEdge) +{ + if (nEdge == 0) return HTLEFT; + if (nEdge == 1) return HTTOP; + if (nEdge == 2) return HTRIGHT; + if (nEdge == 3) return HTBOTTOM; + ASSERT(FALSE); // invalid edge code + return HTNOWHERE; +} + +void CSizingControlBar::GetRowInfo(int& nFirst, int& nLast, int& nThis) +{ + ASSERT_VALID(m_pDockBar); // verify bounds + + nThis = m_pDockBar->FindBar(this); + ASSERT(nThis != -1); + + int i, nBars = m_pDockBar->m_arrBars.GetSize(); + + // find the first and the last bar in row + for (nFirst = -1, i = nThis - 1; i >= 0 && nFirst == -1; i--) + if (m_pDockBar->m_arrBars[i] == NULL) + nFirst = i + 1; + for (nLast = -1, i = nThis + 1; i < nBars && nLast == -1; i++) + if (m_pDockBar->m_arrBars[i] == NULL) + nLast = i - 1; + + ASSERT((nLast != -1) && (nFirst != -1)); +} + +void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars) +{ + int nThis; // dummy + GetRowSizingBars(arrSCBars, nThis); +} + +void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars, int& nThis) +{ + arrSCBars.RemoveAll(); + + int nFirstT, nLastT, nThisT; + GetRowInfo(nFirstT, nLastT, nThisT); + + nThis = -1; + for (int i = nFirstT; i <= nLastT; i++) + { + CSizingControlBar* pBar = static_cast (m_pDockBar->m_arrBars[i]); + if (HIWORD(pBar) == 0) continue; // placeholder + if (!pBar->IsVisible()) continue; + if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + { + if (pBar == this) + nThis = arrSCBars.GetSize(); + + arrSCBars.Add(pBar); + } + } +} + +BOOL CSizingControlBar::NegotiateSpace(int nLengthTotal, BOOL bHorz) +{ + ASSERT(bHorz == IsHorzDocked()); + + int nFirst, nLast, nThis; + GetRowInfo(nFirst, nLast, nThis); + + int nLengthAvail = nLengthTotal; + int nLengthActual = 0; + int nLengthMin = 2; + int nWidthMax = 0; + CSizingControlBar* pBar; + + int i; + for (i = nFirst; i <= nLast; i++) + { + pBar = static_cast (m_pDockBar->m_arrBars[i]); + if (HIWORD(pBar) == 0) continue; // placeholder + if (!pBar->IsVisible()) continue; + BOOL bIsSizingBar = + pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar)); + + int nLengthBar; // minimum length of the bar + if (bIsSizingBar) + nLengthBar = bHorz ? pBar->m_szMinHorz.cx - 2 : + pBar->m_szMinVert.cy - 2; + else + { + CRect rcBar; + pBar->GetWindowRect(&rcBar); + nLengthBar = bHorz ? rcBar.Width() - 2 : rcBar.Height() - 2; + } + + nLengthMin += nLengthBar; + if (nLengthMin > nLengthTotal) + { + // split the row after fixed bar + if (i < nThis) + { + m_pDockBar->m_arrBars.InsertAt(i + 1, + (CControlBar*) NULL); + return FALSE; + } + + // only this sizebar remains on the row, adjust it to minsize + if (i == nThis) + { + if (bHorz) + m_szHorz.cx = m_szMinHorz.cx; + else + m_szVert.cy = m_szMinVert.cy; + + return TRUE; // the dockbar will split the row for us + } + + // we have enough bars - go negotiate with them + m_pDockBar->m_arrBars.InsertAt(i, (CControlBar*) NULL); + nLast = i - 1; + break; + } + + if (bIsSizingBar) + { + nLengthActual += bHorz ? pBar->m_szHorz.cx - 2 : + pBar->m_szVert.cy - 2; + nWidthMax = max(nWidthMax, bHorz ? pBar->m_szHorz.cy : + pBar->m_szVert.cx); + } + else + nLengthAvail -= nLengthBar; + } + + CSCBArray arrSCBars; + GetRowSizingBars(arrSCBars); + int nNumBars = arrSCBars.GetSize(); + int nDelta = nLengthAvail - nLengthActual; + + // return faster when there is only one sizing bar per row (this one) + if (nNumBars == 1) + { + ASSERT(arrSCBars[0] == this); + + if (nDelta == 0) + return TRUE; + + m_bKeepSize = FALSE; + (bHorz ? m_szHorz.cx : m_szVert.cy) += nDelta; + + return TRUE; + } + + // make all the bars the same width + for (i = 0; i < nNumBars; i++) + if (bHorz) + arrSCBars[i]->m_szHorz.cy = nWidthMax; + else + arrSCBars[i]->m_szVert.cx = nWidthMax; + + // distribute the difference between the bars, + // but don't shrink them below their minsizes + while (nDelta != 0) + { + int nDeltaOld = nDelta; + for (i = 0; i < nNumBars; i++) + { + pBar = arrSCBars[i]; + int nLMin = bHorz ? + pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy; + int nL = bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy; + + if ((nL == nLMin) && (nDelta < 0) || // already at min length + pBar->m_bKeepSize) // or wants to keep its size + continue; + + // sign of nDelta + int nDelta2 = (nDelta < 0) ? -1 : 1; + + (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta2; + nDelta -= nDelta2; + if (nDelta == 0) break; + } + // clear m_bKeepSize flags + if ((nDeltaOld == nDelta) || (nDelta == 0)) + for (i = 0; i < nNumBars; i++) + arrSCBars[i]->m_bKeepSize = FALSE; + } + + return TRUE; +} + +void CSizingControlBar::AlignControlBars() +{ + int nFirst, nLast, nThis; + GetRowInfo(nFirst, nLast, nThis); + + BOOL bHorz = IsHorzDocked(); + BOOL bNeedRecalc = FALSE; + int nAlign = bHorz ? -2 : 0; + + CRect rc, rcDock; + m_pDockBar->GetWindowRect(&rcDock); + + for (int i = nFirst; i <= nLast; i++) + { + CSizingControlBar* pBar = static_cast(m_pDockBar->m_arrBars[i]); + if (HIWORD(pBar) == 0) continue; // placeholder + if (!pBar->IsVisible()) continue; + + pBar->GetWindowRect(&rc); + rc.OffsetRect(-rcDock.TopLeft()); + + if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + rc = CRect(rc.TopLeft(), + bHorz ? pBar->m_szHorz : pBar->m_szVert); + + if ((bHorz ? rc.left : rc.top) != nAlign) + { + if (!bHorz) + rc.OffsetRect(0, nAlign - rc.top - 2); + else if (m_nDockBarID == AFX_IDW_DOCKBAR_TOP) + rc.OffsetRect(nAlign - rc.left, -2); + else + rc.OffsetRect(nAlign - rc.left, 0); + pBar->MoveWindow(rc); + bNeedRecalc = TRUE; + } + nAlign += (bHorz ? rc.Width() : rc.Height()) - 2; + } + + if (bNeedRecalc) + m_pDockSite->DelayRecalcLayout(); +} + +void CSizingControlBar::OnUpdateCmdUI(CFrameWnd* pTarget, + BOOL bDisableIfNoHndler) +{ + UNUSED_ALWAYS(bDisableIfNoHndler); + UNUSED_ALWAYS(pTarget); +} + +void CSizingControlBar::LoadState(LPCTSTR lpszProfileName) +{ + ASSERT_VALID(this); + ASSERT(GetSafeHwnd()); // must be called after Create() + +#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) + // compensate the caption miscalculation in CFrameWnd::SetDockState() + CDockState state; + state.LoadState(lpszProfileName); + + UINT nID = GetDlgCtrlID(); + for (int i = 0; i < state.m_arrBarInfo.GetSize(); i++) + { + CControlBarInfo* pInfo = (CControlBarInfo*)state.m_arrBarInfo[i]; + ASSERT(pInfo != NULL); + if (!pInfo->m_bFloating) + continue; + + // this is a floating dockbar - check the ID array + for (int j = 0; j < pInfo->m_arrBarID.GetSize(); j++) + if ((DWORD) pInfo->m_arrBarID[j] == nID) + { + // found this bar - offset origin and save settings + pInfo->m_pointPos.x++; + pInfo->m_pointPos.y += + ::GetSystemMetrics(SM_CYSMCAPTION) + 1; + pInfo->SaveState(lpszProfileName, i); + } + } +#endif //_SCB_REPLACE_MINIFRAME && !_SCB_MINIFRAME_CAPTION + + CWinApp* pApp = AfxGetApp(); + + TCHAR szSection[256]; + wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName, + GetDlgCtrlID()); + + m_szHorz.cx = max(m_szMinHorz.cx, (int) pApp->GetProfileInt( + szSection, _T("sizeHorzCX"), m_szHorz.cx)); + m_szHorz.cy = max(m_szMinHorz.cy, (int) pApp->GetProfileInt( + szSection, _T("sizeHorzCY"), m_szHorz.cy)); + + m_szVert.cx = max(m_szMinVert.cx, (int) pApp->GetProfileInt( + szSection, _T("sizeVertCX"), m_szVert.cx)); + m_szVert.cy = max(m_szMinVert.cy, (int) pApp->GetProfileInt( + szSection, _T("sizeVertCY"), m_szVert.cy)); + + m_szFloat.cx = max(m_szMinFloat.cx, (int) pApp->GetProfileInt( + szSection, _T("sizeFloatCX"), m_szFloat.cx)); + m_szFloat.cy = max(m_szMinFloat.cy, (int) pApp->GetProfileInt( + szSection, _T("sizeFloatCY"), m_szFloat.cy)); +} + +void CSizingControlBar::SaveState(LPCTSTR lpszProfileName) +{ + // place your SaveState or GlobalSaveState call in + // CMainFrame's OnClose() or DestroyWindow(), not in OnDestroy() + ASSERT_VALID(this); + ASSERT(GetSafeHwnd()); + + CWinApp* pApp = AfxGetApp(); + + TCHAR szSection[256]; + wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName, + GetDlgCtrlID()); + + pApp->WriteProfileInt(szSection, _T("sizeHorzCX"), m_szHorz.cx); + pApp->WriteProfileInt(szSection, _T("sizeHorzCY"), m_szHorz.cy); + + pApp->WriteProfileInt(szSection, _T("sizeVertCX"), m_szVert.cx); + pApp->WriteProfileInt(szSection, _T("sizeVertCY"), m_szVert.cy); + + pApp->WriteProfileInt(szSection, _T("sizeFloatCX"), m_szFloat.cx); + pApp->WriteProfileInt(szSection, _T("sizeFloatCY"), m_szFloat.cy); +} + +void CSizingControlBar::GlobalLoadState(CFrameWnd* pFrame, + LPCTSTR lpszProfileName) +{ + POSITION pos = pFrame->m_listControlBars.GetHeadPosition(); + while (pos != NULL) + { + CSizingControlBar* pBar = static_cast (pFrame->m_listControlBars.GetNext(pos)); + ASSERT(pBar != NULL); + if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + pBar->LoadState(lpszProfileName); + } +} + +void CSizingControlBar::GlobalSaveState(CFrameWnd* pFrame, + LPCTSTR lpszProfileName) +{ + POSITION pos = pFrame->m_listControlBars.GetHeadPosition(); + while (pos != NULL) + { + CSizingControlBar* pBar = static_cast (pFrame->m_listControlBars.GetNext(pos)); + ASSERT(pBar != NULL); + if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + pBar->SaveState(lpszProfileName); + } +} + +//mpc-hc custom code start +void CSizingControlBar::mpc_fillNcBG(CDC* mdc, CRect rcDraw) { + mdc->FillRect(rcDraw, CBrush::FromHandle( + (HBRUSH)GetClassLongPtr(m_hWnd, GCLP_HBRBACKGROUND))); +} +//mpc-hc custom code end + +#ifdef _SCB_REPLACE_MINIFRAME +#ifndef _SCB_MINIFRAME_CAPTION +///////////////////////////////////////////////////////////////////////////// +// CSCBDockContext Drag Operations + +static void AdjustRectangle(CRect& rect, CPoint pt) +{ + int nXOffset = (pt.x < rect.left) ? (pt.x - rect.left) : + (pt.x > rect.right) ? (pt.x - rect.right) : 0; + int nYOffset = (pt.y < rect.top) ? (pt.y - rect.top) : + (pt.y > rect.bottom) ? (pt.y - rect.bottom) : 0; + rect.OffsetRect(nXOffset, nYOffset); +} + +void CSCBDockContext::StartDrag(CPoint pt) +{ + ASSERT_VALID(m_pBar); + m_bDragging = TRUE; + + InitLoop(); + + ASSERT((m_pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) != 0); + + // get true bar size (including borders) + CRect rect; + m_pBar->GetWindowRect(rect); + m_ptLast = pt; + CSize sizeHorz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK); + CSize sizeVert = m_pBar->CalcDynamicLayout(0, LM_VERTDOCK); + CSize sizeFloat = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH); + + m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz); + m_rectDragVert = CRect(rect.TopLeft(), sizeVert); + + // calculate frame dragging rectangle + m_rectFrameDragHorz = CRect(rect.TopLeft(), sizeFloat); + +#ifdef _MAC + CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, + WS_THICKFRAME, WS_EX_FORCESIZEBOX); +#else + CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, WS_THICKFRAME); +#endif + m_rectFrameDragHorz.DeflateRect(2, 2); + m_rectFrameDragVert = m_rectFrameDragHorz; + + // adjust rectangles so that point is inside + AdjustRectangle(m_rectDragHorz, pt); + AdjustRectangle(m_rectDragVert, pt); + AdjustRectangle(m_rectFrameDragHorz, pt); + AdjustRectangle(m_rectFrameDragVert, pt); + + // initialize tracking state and enter tracking loop + m_dwOverDockStyle = CanDock(); + Move(pt); // call it here to handle special keys + Track(); +} +#endif //_SCB_MINIFRAME_CAPTION + +///////////////////////////////////////////////////////////////////////////// +// CSCBMiniDockFrameWnd + +IMPLEMENT_DYNCREATE(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd); + +BEGIN_MESSAGE_MAP(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd) + //{{AFX_MSG_MAP(CSCBMiniDockFrameWnd) + ON_WM_NCLBUTTONDOWN() + ON_WM_GETMINMAXINFO() + ON_WM_WINDOWPOSCHANGING() + ON_WM_SIZE() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +BOOL CSCBMiniDockFrameWnd::Create(CWnd* pParent, DWORD dwBarStyle) +{ + // set m_bInRecalcLayout to avoid flashing during creation + // RecalcLayout will be called once something is docked + m_bInRecalcLayout = TRUE; + + DWORD dwStyle = WS_POPUP|WS_CAPTION|WS_SYSMENU|MFS_MOVEFRAME| + MFS_4THICKFRAME|MFS_SYNCACTIVE|MFS_BLOCKSYSMENU| + FWS_SNAPTOBARS; + + if (dwBarStyle & CBRS_SIZE_DYNAMIC) + dwStyle &= ~MFS_MOVEFRAME; + + DWORD dwExStyle = 0; +#ifdef _MAC + if (dwBarStyle & CBRS_SIZE_DYNAMIC) + dwExStyle |= WS_EX_FORCESIZEBOX; + else + dwStyle &= ~(MFS_MOVEFRAME|MFS_4THICKFRAME); +#endif + + if (!CMiniFrameWnd::CreateEx(dwExStyle, + NULL, "", dwStyle, rectDefault, pParent)) + { + m_bInRecalcLayout = FALSE; + return FALSE; + } + dwStyle = dwBarStyle & (CBRS_ALIGN_LEFT|CBRS_ALIGN_RIGHT) ? + CBRS_ALIGN_LEFT : CBRS_ALIGN_TOP; + dwStyle |= dwBarStyle & CBRS_FLOAT_MULTI; + CMenu* pSysMenu = GetSystemMenu(FALSE); + //pSysMenu->DeleteMenu(SC_SIZE, MF_BYCOMMAND); + CString strHide; + if (strHide.LoadString(AFX_IDS_HIDE)) + { + pSysMenu->DeleteMenu(SC_CLOSE, MF_BYCOMMAND); + pSysMenu->AppendMenu(MF_STRING|MF_ENABLED, SC_CLOSE, strHide); + } + + // must initially create with parent frame as parent + if (!m_wndDockBar.Create(pParent, WS_CHILD | WS_VISIBLE | dwStyle, + AFX_IDW_DOCKBAR_FLOAT)) + { + m_bInRecalcLayout = FALSE; + return FALSE; + } + + // set parent to CMiniDockFrameWnd + m_wndDockBar.SetParent(this); + m_bInRecalcLayout = FALSE; + + return TRUE; +} + +void CSCBMiniDockFrameWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + if (nHitTest == HTCAPTION || nHitTest == HTCLOSE) + { + baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); + return; + } + + if (GetSizingControlBar() != NULL) + CMiniFrameWnd::OnNcLButtonDown(nHitTest, point); + else + baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); +} + +CSizingControlBar* CSCBMiniDockFrameWnd::GetSizingControlBar() +{ + CWnd* pWnd = GetWindow(GW_CHILD); // get the dockbar + if (pWnd == NULL) + return NULL; + + pWnd = pWnd->GetWindow(GW_CHILD); // get the controlbar + if (pWnd == NULL) + return NULL; + + if (!pWnd->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + return NULL; + + return static_cast (pWnd); +} + +void CSCBMiniDockFrameWnd::OnSize(UINT nType, int cx, int cy) +{ + CSizingControlBar* pBar = GetSizingControlBar(); + if ((pBar != NULL) && (GetStyle() & MFS_4THICKFRAME) == 0 + && pBar->IsVisible() && + cx + 4 >= pBar->m_szMinFloat.cx && + cy + 4 >= pBar->m_szMinFloat.cy) + pBar->m_szFloat = CSize(cx + 4, cy + 4); + + baseCSCBMiniDockFrameWnd::OnSize(nType, cx, cy); +} + +void CSCBMiniDockFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + baseCSCBMiniDockFrameWnd::OnGetMinMaxInfo(lpMMI); + + CSizingControlBar* pBar = GetSizingControlBar(); + if (pBar != NULL) + { + CRect r(CPoint(0, 0), pBar->m_szMinFloat - CSize(4, 4)); +#ifndef _SCB_MINIFRAME_CAPTION + CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME); +#else + CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME|WS_CAPTION); +#endif //_SCB_MINIFRAME_CAPTION + lpMMI->ptMinTrackSize.x = r.Width(); + lpMMI->ptMinTrackSize.y = r.Height(); +// mpc-hc custom code start + if(pBar->m_bFixedFloat) + { + lpMMI->ptMinTrackSize.x = pBar->m_szFixedFloat.cx; + lpMMI->ptMinTrackSize.y = pBar->m_szFixedFloat.cy; + lpMMI->ptMaxTrackSize.x = pBar->m_szFixedFloat.cx; + lpMMI->ptMaxTrackSize.y = pBar->m_szFixedFloat.cy; + } +// mpc-hc custom code end + } +} + +void CSCBMiniDockFrameWnd::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) +{ + if ((GetStyle() & MFS_4THICKFRAME) != 0) + { + CSizingControlBar* pBar = GetSizingControlBar(); + if (pBar != NULL) + { + lpwndpos->flags |= SWP_NOSIZE; // don't size this time + // prevents flicker + pBar->m_pDockBar->ModifyStyle(0, WS_CLIPCHILDREN); + + // enable diagonal resizing + DWORD dwStyleRemove = MFS_4THICKFRAME; +#ifndef _SCB_MINIFRAME_CAPTION + // remove caption + dwStyleRemove |= WS_SYSMENU|WS_CAPTION; +#endif + ModifyStyle(dwStyleRemove, 0); + + DelayRecalcLayout(); + pBar->PostMessage(WM_NCPAINT); + } + } + + CMiniFrameWnd::OnWindowPosChanging(lpwndpos); +} + +#endif //_SCB_REPLACE_MINIFRAME diff --git a/src/thirdparty/sizecbar/sizecbar.h b/src/thirdparty/sizecbar/sizecbar.h index 10de2dc68cb..d3338d629e5 100644 --- a/src/thirdparty/sizecbar/sizecbar.h +++ b/src/thirdparty/sizecbar/sizecbar.h @@ -1,257 +1,257 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBar Version 2.45 -// -// Created: Jan 24, 1998 Last Modified: April 16, 2010 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com . -///////////////////////////////////////////////////////////////////////// - -#if !defined(__SIZECBAR_H__) -#define __SIZECBAR_H__ - -#include // for CDockContext -#include // for CTypedPtrArray - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 - - -#if defined(_SCB_MINIFRAME_CAPTION) && !defined(_SCB_REPLACE_MINIFRAME) - #error "_SCB_MINIFRAME_CAPTION requires _SCB_REPLACE_MINIFRAME" -#endif - -///////////////////////////////////////////////////////////////////////// -// CSCBDockBar dummy class for access to protected members - -class CSCBDockBar : public CDockBar -{ - friend class CSizingControlBar; -}; - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar control bar styles - -#define SCBS_EDGELEFT 0x00000001 -#define SCBS_EDGERIGHT 0x00000002 -#define SCBS_EDGETOP 0x00000004 -#define SCBS_EDGEBOTTOM 0x00000008 -#define SCBS_EDGEALL 0x0000000F -#define SCBS_SHOWEDGES 0x00000010 -#define SCBS_SIZECHILD 0x00000020 - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar control bar - -#ifndef baseCSizingControlBar -#define baseCSizingControlBar CControlBar -#endif - -class CSizingControlBar; -typedef CTypedPtrArray CSCBArray; - -class CSizingControlBar : public baseCSizingControlBar -{ - DECLARE_DYNAMIC(CSizingControlBar); - -// Construction -public: - CSizingControlBar(); - - virtual BOOL Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, - CSize sizeDefault, BOOL bHasGripper, - UINT nID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP); - virtual BOOL Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, - UINT nID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP); - -// Attributes -public: - const BOOL IsFloating() const; - const BOOL IsHorzDocked() const; - const BOOL IsVertDocked() const; - const BOOL IsSideTracking() const; - const BOOL GetSCBStyle() const {return m_dwSCBStyle;} - -// Operations -public: -#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) - void EnableDocking(DWORD dwDockStyle); -#endif - virtual void LoadState(LPCTSTR lpszProfileName); - virtual void SaveState(LPCTSTR lpszProfileName); - static void GlobalLoadState(CFrameWnd* pFrame, LPCTSTR lpszProfileName); - static void GlobalSaveState(CFrameWnd* pFrame, LPCTSTR lpszProfileName); - void SetSCBStyle(DWORD dwSCBStyle) - {m_dwSCBStyle = (dwSCBStyle & ~SCBS_EDGEALL);} - -//mpc-hc custom code start - virtual void mpc_fillNcBG(CDC *mdc, CRect rcDraw); - - void SetWidth(const int nWidth) - { - m_szFloat.cx = m_szHorz.cx = m_szVert.cx = nWidth; - m_pDockSite->DelayRecalcLayout(); - } - - void SetHeight(const int nHeight) - { - m_szFloat.cy = m_szHorz.cy = m_szVert.cy = nHeight; - m_pDockSite->DelayRecalcLayout(); - } -//mpc-hc custom code end - -// Overridables - virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); - -// Overrides -public: - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CSizingControlBar) - public: - virtual CSize CalcFixedLayout(BOOL bStretch, BOOL bHorz); - virtual CSize CalcDynamicLayout(int nLength, DWORD dwMode); - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CSizingControlBar(); - -protected: - // implementation helpers - UINT GetEdgeHTCode(int nEdge); - BOOL GetEdgeRect(CRect rcWnd, UINT nHitTest, CRect& rcEdge); - virtual void StartTracking(UINT nHitTest, CPoint point); - virtual void StopTracking(); - virtual void OnTrackUpdateSize(CPoint& point); - virtual void OnTrackInvertTracker(); - virtual void NcPaintGripper(CDC* pDC, CRect rcClient); - virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); - - virtual void AlignControlBars(); - void GetRowInfo(int& nFirst, int& nLast, int& nThis); - void GetRowSizingBars(CSCBArray& arrSCBars); - void GetRowSizingBars(CSCBArray& arrSCBars, int& nThis); - BOOL NegotiateSpace(int nLengthTotal, BOOL bHorz); - -protected: - DWORD m_dwSCBStyle; - UINT m_htEdge; - - CSize m_szHorz; - CSize m_szVert; - CSize m_szFloat; - CSize m_szMinHorz; - CSize m_szMinVert; - CSize m_szMinFloat; - int m_nTrackPosMin; - int m_nTrackPosMax; - int m_nTrackPosOld; - int m_nTrackEdgeOfs; - BOOL m_bTracking; - BOOL m_bKeepSize; - BOOL m_bParentSizing; - BOOL m_bDragShowContent; - UINT m_nDockBarID; - int m_cxEdge; - -//mpc-hc custom code start - BOOL m_bFixedFloat; - CSize m_szFixedFloat; -//mpc-hc custom code end - -// Generated message map functions -protected: - //{{AFX_MSG(CSizingControlBar) - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnNcPaint(); - afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp); - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg void OnCaptureChanged(CWnd *pWnd); - afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); - afx_msg void OnRButtonDown(UINT nFlags, CPoint point); - afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); - afx_msg void OnPaint(); - afx_msg void OnClose(); - afx_msg void OnSize(UINT nType, int cx, int cy); - //}}AFX_MSG - afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam); - - DECLARE_MESSAGE_MAP() - -#ifdef _SCB_REPLACE_MINIFRAME - friend class CSCBMiniDockFrameWnd; -#endif //_SCB_REPLACE_MINIFRAME -}; - -#ifdef _SCB_REPLACE_MINIFRAME -#ifndef _SCB_MINIFRAME_CAPTION -///////////////////////////////////////////////////////////////////////// -// CSCBDockContext dockcontext - -class CSCBDockContext : public CDockContext -{ -public: -// Construction - CSCBDockContext(CControlBar* pBar) : CDockContext(pBar) {} - -// Drag Operations - virtual void StartDrag(CPoint pt); -}; -#endif //_SCB_MINIFRAME_CAPTION - -///////////////////////////////////////////////////////////////////////// -// CSCBMiniDockFrameWnd miniframe - -#ifndef baseCSCBMiniDockFrameWnd -#define baseCSCBMiniDockFrameWnd CMiniDockFrameWnd -#endif - -class CSCBMiniDockFrameWnd : public baseCSCBMiniDockFrameWnd -{ - DECLARE_DYNCREATE(CSCBMiniDockFrameWnd) - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CSCBMiniDockFrameWnd) - public: - virtual BOOL Create(CWnd* pParent, DWORD dwBarStyle); - //}}AFX_VIRTUAL - -// Implementation -public: - CSizingControlBar* GetSizingControlBar(); - - //{{AFX_MSG(CSCBMiniDockFrameWnd) - afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); - afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); - afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); - afx_msg void OnSize(UINT nType, int cx, int cy); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; -#endif //_SCB_REPLACE_MINIFRAME - -#endif // !defined(__SIZECBAR_H__) - +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBar Version 2.45 +// +// Created: Jan 24, 1998 Last Modified: April 16, 2010 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com . +///////////////////////////////////////////////////////////////////////// + +#if !defined(__SIZECBAR_H__) +#define __SIZECBAR_H__ + +#include // for CDockContext +#include // for CTypedPtrArray + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + + +#if defined(_SCB_MINIFRAME_CAPTION) && !defined(_SCB_REPLACE_MINIFRAME) + #error "_SCB_MINIFRAME_CAPTION requires _SCB_REPLACE_MINIFRAME" +#endif + +///////////////////////////////////////////////////////////////////////// +// CSCBDockBar dummy class for access to protected members + +class CSCBDockBar : public CDockBar +{ + friend class CSizingControlBar; +}; + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar control bar styles + +#define SCBS_EDGELEFT 0x00000001 +#define SCBS_EDGERIGHT 0x00000002 +#define SCBS_EDGETOP 0x00000004 +#define SCBS_EDGEBOTTOM 0x00000008 +#define SCBS_EDGEALL 0x0000000F +#define SCBS_SHOWEDGES 0x00000010 +#define SCBS_SIZECHILD 0x00000020 + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar control bar + +#ifndef baseCSizingControlBar +#define baseCSizingControlBar CControlBar +#endif + +class CSizingControlBar; +typedef CTypedPtrArray CSCBArray; + +class CSizingControlBar : public baseCSizingControlBar +{ + DECLARE_DYNAMIC(CSizingControlBar); + +// Construction +public: + CSizingControlBar(); + + virtual BOOL Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, + CSize sizeDefault, BOOL bHasGripper, + UINT nID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP); + virtual BOOL Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, + UINT nID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP); + +// Attributes +public: + const BOOL IsFloating() const; + const BOOL IsHorzDocked() const; + const BOOL IsVertDocked() const; + const BOOL IsSideTracking() const; + const BOOL GetSCBStyle() const {return m_dwSCBStyle;} + +// Operations +public: +#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) + void EnableDocking(DWORD dwDockStyle); +#endif + virtual void LoadState(LPCTSTR lpszProfileName); + virtual void SaveState(LPCTSTR lpszProfileName); + static void GlobalLoadState(CFrameWnd* pFrame, LPCTSTR lpszProfileName); + static void GlobalSaveState(CFrameWnd* pFrame, LPCTSTR lpszProfileName); + void SetSCBStyle(DWORD dwSCBStyle) + {m_dwSCBStyle = (dwSCBStyle & ~SCBS_EDGEALL);} + +//mpc-hc custom code start + virtual void mpc_fillNcBG(CDC *mdc, CRect rcDraw); + + void SetWidth(const int nWidth) + { + m_szFloat.cx = m_szHorz.cx = m_szVert.cx = nWidth; + m_pDockSite->DelayRecalcLayout(); + } + + void SetHeight(const int nHeight) + { + m_szFloat.cy = m_szHorz.cy = m_szVert.cy = nHeight; + m_pDockSite->DelayRecalcLayout(); + } +//mpc-hc custom code end + +// Overridables + virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); + +// Overrides +public: + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSizingControlBar) + public: + virtual CSize CalcFixedLayout(BOOL bStretch, BOOL bHorz); + virtual CSize CalcDynamicLayout(int nLength, DWORD dwMode); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CSizingControlBar(); + +protected: + // implementation helpers + UINT GetEdgeHTCode(int nEdge); + BOOL GetEdgeRect(CRect rcWnd, UINT nHitTest, CRect& rcEdge); + virtual void StartTracking(UINT nHitTest, CPoint point); + virtual void StopTracking(); + virtual void OnTrackUpdateSize(CPoint& point); + virtual void OnTrackInvertTracker(); + virtual void NcPaintGripper(CDC* pDC, CRect rcClient); + virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); + + virtual void AlignControlBars(); + void GetRowInfo(int& nFirst, int& nLast, int& nThis); + void GetRowSizingBars(CSCBArray& arrSCBars); + void GetRowSizingBars(CSCBArray& arrSCBars, int& nThis); + BOOL NegotiateSpace(int nLengthTotal, BOOL bHorz); + +protected: + DWORD m_dwSCBStyle; + UINT m_htEdge; + + CSize m_szHorz; + CSize m_szVert; + CSize m_szFloat; + CSize m_szMinHorz; + CSize m_szMinVert; + CSize m_szMinFloat; + int m_nTrackPosMin; + int m_nTrackPosMax; + int m_nTrackPosOld; + int m_nTrackEdgeOfs; + BOOL m_bTracking; + BOOL m_bKeepSize; + BOOL m_bParentSizing; + BOOL m_bDragShowContent; + UINT m_nDockBarID; + int m_cxEdge; + +//mpc-hc custom code start + BOOL m_bFixedFloat; + CSize m_szFixedFloat; +//mpc-hc custom code end + +// Generated message map functions +protected: + //{{AFX_MSG(CSizingControlBar) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnNcPaint(); + afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp); + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg void OnCaptureChanged(CWnd *pWnd); + afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); + afx_msg void OnPaint(); + afx_msg void OnClose(); + afx_msg void OnSize(UINT nType, int cx, int cy); + //}}AFX_MSG + afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +#ifdef _SCB_REPLACE_MINIFRAME + friend class CSCBMiniDockFrameWnd; +#endif //_SCB_REPLACE_MINIFRAME +}; + +#ifdef _SCB_REPLACE_MINIFRAME +#ifndef _SCB_MINIFRAME_CAPTION +///////////////////////////////////////////////////////////////////////// +// CSCBDockContext dockcontext + +class CSCBDockContext : public CDockContext +{ +public: +// Construction + CSCBDockContext(CControlBar* pBar) : CDockContext(pBar) {} + +// Drag Operations + virtual void StartDrag(CPoint pt); +}; +#endif //_SCB_MINIFRAME_CAPTION + +///////////////////////////////////////////////////////////////////////// +// CSCBMiniDockFrameWnd miniframe + +#ifndef baseCSCBMiniDockFrameWnd +#define baseCSCBMiniDockFrameWnd CMiniDockFrameWnd +#endif + +class CSCBMiniDockFrameWnd : public baseCSCBMiniDockFrameWnd +{ + DECLARE_DYNCREATE(CSCBMiniDockFrameWnd) + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSCBMiniDockFrameWnd) + public: + virtual BOOL Create(CWnd* pParent, DWORD dwBarStyle); + //}}AFX_VIRTUAL + +// Implementation +public: + CSizingControlBar* GetSizingControlBar(); + + //{{AFX_MSG(CSCBMiniDockFrameWnd) + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); + afx_msg void OnSize(UINT nType, int cx, int cy); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; +#endif //_SCB_REPLACE_MINIFRAME + +#endif // !defined(__SIZECBAR_H__) + diff --git a/src/thirdparty/sizecbar/sizecbar.vcxproj b/src/thirdparty/sizecbar/sizecbar.vcxproj index ead70eb5d60..f9273bf15ec 100644 --- a/src/thirdparty/sizecbar/sizecbar.vcxproj +++ b/src/thirdparty/sizecbar/sizecbar.vcxproj @@ -1,67 +1,67 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {61E6EB4D-2F1A-443B-94B0-E8200B26E99F} - sizecbar - MFCProj - sizecbar - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - False - - - - _LIB;%(PreprocessorDefinitions) - - - - - - - - Create - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {61E6EB4D-2F1A-443B-94B0-E8200B26E99F} + sizecbar + MFCProj + sizecbar + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + False + + + + _LIB;%(PreprocessorDefinitions) + + + + + + + + Create + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/sizecbar/sizecbar.vcxproj.filters b/src/thirdparty/sizecbar/sizecbar.vcxproj.filters index 23fc896d1cb..c73b56b00a4 100644 --- a/src/thirdparty/sizecbar/sizecbar.vcxproj.filters +++ b/src/thirdparty/sizecbar/sizecbar.vcxproj.filters @@ -1,41 +1,41 @@ - - - - - {8d9a4844-0f68-4c0d-a6f5-a20f411affaa} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {c249b3fd-b54b-4fe2-b48b-b2ecf391f42a} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {8d9a4844-0f68-4c0d-a6f5-a20f411affaa} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c249b3fd-b54b-4fe2-b48b-b2ecf391f42a} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/sizecbar/stdafx.cpp b/src/thirdparty/sizecbar/stdafx.cpp index 784f2cebc5c..36116eb6a86 100644 --- a/src/thirdparty/sizecbar/stdafx.cpp +++ b/src/thirdparty/sizecbar/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/thirdparty/sizecbar/stdafx.h b/src/thirdparty/sizecbar/stdafx.h index 9efc54936db..228e406bec3 100644 --- a/src/thirdparty/sizecbar/stdafx.h +++ b/src/thirdparty/sizecbar/stdafx.h @@ -1,33 +1,33 @@ -/* - * (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 . - * - */ - -#pragma once - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#endif - -#include "scbarcf.h" +/* + * (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 . + * + */ + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +#include "scbarcf.h" diff --git a/src/thirdparty/unrar/acknow.txt b/src/thirdparty/unrar/acknow.txt index ec2c2c7cdcf..b8d35a6aac2 100644 --- a/src/thirdparty/unrar/acknow.txt +++ b/src/thirdparty/unrar/acknow.txt @@ -1,59 +1,59 @@ - ACKNOWLEDGMENTS - -* We used "Screaming Fast Galois Field Arithmetic Using Intel - SIMD Instructions" paper by James S. Plank, Kevin M. Greenan - and Ethan L. Miller to improve Reed-Solomon coding performance. - Also we are grateful to Artem Drobanov and Bulat Ziganshin - for samples and ideas allowed to make Reed-Solomon coding - more efficient. - -* RAR4 text compression algorithm is based on Dmitry Shkarin PPMII - and Dmitry Subbotin carryless rangecoder public domain source code. - You can find it in ftp.elf.stuba.sk/pub/pc/pack. - -* RAR encryption includes parts of public domain code - from Szymon Stefanek AES and Steve Reid SHA-1 implementations. - -* With exception of SFX modules, RAR uses CRC32 function based - on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code - is available here: - - https://sourceforge.net/projects/slicing-by-8/ - - Original Intel Slicing-by-8 code is licensed under BSD License - available at http://www.opensource.org/licenses/bsd-license.html - - Copyright (c) 2004-2006 Intel Corporation. - All Rights Reserved - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with - the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ), - designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn - and Christian Winnerlein. - -* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed - to significantly improve RAR compression and speed. + ACKNOWLEDGMENTS + +* We used "Screaming Fast Galois Field Arithmetic Using Intel + SIMD Instructions" paper by James S. Plank, Kevin M. Greenan + and Ethan L. Miller to improve Reed-Solomon coding performance. + Also we are grateful to Artem Drobanov and Bulat Ziganshin + for samples and ideas allowed to make Reed-Solomon coding + more efficient. + +* RAR4 text compression algorithm is based on Dmitry Shkarin PPMII + and Dmitry Subbotin carryless rangecoder public domain source code. + You can find it in ftp.elf.stuba.sk/pub/pc/pack. + +* RAR encryption includes parts of public domain code + from Szymon Stefanek AES and Steve Reid SHA-1 implementations. + +* With exception of SFX modules, RAR uses CRC32 function based + on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code + is available here: + + https://sourceforge.net/projects/slicing-by-8/ + + Original Intel Slicing-by-8 code is licensed under BSD License + available at http://www.opensource.org/licenses/bsd-license.html + + Copyright (c) 2004-2006 Intel Corporation. + All Rights Reserved + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with + the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ), + designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn + and Christian Winnerlein. + +* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed + to significantly improve RAR compression and speed. diff --git a/src/thirdparty/unrar/dll.def b/src/thirdparty/unrar/dll.def index 3c9a2c83ab5..a7241141a07 100644 --- a/src/thirdparty/unrar/dll.def +++ b/src/thirdparty/unrar/dll.def @@ -1,13 +1,13 @@ -EXPORTS - RAROpenArchive - RAROpenArchiveEx - RARCloseArchive - RARReadHeader - RARReadHeaderEx - RARProcessFile - RARProcessFileW - RARSetCallback - RARSetChangeVolProc - RARSetProcessDataProc - RARSetPassword - RARGetDllVersion +EXPORTS + RAROpenArchive + RAROpenArchiveEx + RARCloseArchive + RARReadHeader + RARReadHeaderEx + RARProcessFile + RARProcessFileW + RARSetCallback + RARSetChangeVolProc + RARSetProcessDataProc + RARSetPassword + RARGetDllVersion diff --git a/src/thirdparty/unrar/dll.rc b/src/thirdparty/unrar/dll.rc index b7f07785b11..645f8b4b99f 100644 --- a/src/thirdparty/unrar/dll.rc +++ b/src/thirdparty/unrar/dll.rc @@ -1,28 +1,28 @@ -#include -#include - -VS_VERSION_INFO VERSIONINFO +#include +#include + +VS_VERSION_INFO VERSIONINFO FILEVERSION 6, 24, 100, 1007 PRODUCTVERSION 6, 24, 100, 1007 -FILEOS VOS__WINDOWS32 -FILETYPE VFT_APP -{ - BLOCK "StringFileInfo" - { - BLOCK "040904E4" - { - VALUE "CompanyName", "Alexander Roshal\0" - VALUE "ProductName", "RAR decompression library\0" - VALUE "FileDescription", "RAR decompression library\0" +FILEOS VOS__WINDOWS32 +FILETYPE VFT_APP +{ + BLOCK "StringFileInfo" + { + BLOCK "040904E4" + { + VALUE "CompanyName", "Alexander Roshal\0" + VALUE "ProductName", "RAR decompression library\0" + VALUE "FileDescription", "RAR decompression library\0" VALUE "FileVersion", "6.24.0\0" VALUE "ProductVersion", "6.24.0\0" VALUE "LegalCopyright", "Copyright Alexander Roshal 1993-2023\0" - VALUE "OriginalFilename", "Unrar.dll\0" - } - } - BLOCK "VarFileInfo" - { - VALUE "Translation", 0x0409, 0x04E4 - } -} - + VALUE "OriginalFilename", "Unrar.dll\0" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04E4 + } +} + diff --git a/src/thirdparty/unrar/unrar.vcxproj b/src/thirdparty/unrar/unrar.vcxproj index 952243010a2..7445a240edf 100644 --- a/src/thirdparty/unrar/unrar.vcxproj +++ b/src/thirdparty/unrar/unrar.vcxproj @@ -1,173 +1,173 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - unrar - {DA8461C4-7683-4360-9372-2A9E0F1795C2} - Win32Proj - - - - - StaticLibrary - MultiByte - - - - - - - - - - - - - rar.hpp - _LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - NotUsing - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + unrar + {DA8461C4-7683-4360-9372-2A9E0F1795C2} + Win32Proj + + + + + StaticLibrary + MultiByte + + + + + + + + + + + + + rar.hpp + _LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + NotUsing + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/unrar/unrar.vcxproj.filters b/src/thirdparty/unrar/unrar.vcxproj.filters index 5a8f8aa24b4..ef1d860ccee 100644 --- a/src/thirdparty/unrar/unrar.vcxproj.filters +++ b/src/thirdparty/unrar/unrar.vcxproj.filters @@ -1,365 +1,365 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/zlib/zlib.vcxproj b/src/thirdparty/zlib/zlib.vcxproj index 41fe3e42579..c2ee8fed805 100644 --- a/src/thirdparty/zlib/zlib.vcxproj +++ b/src/thirdparty/zlib/zlib.vcxproj @@ -1,84 +1,84 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {2FCD4B66-9CF9-4C8F-BC70-37CD20002D49} - zlib - Win32Proj - zlib - - - - - StaticLibrary - Unicode - - - - - - - - - - - - - _LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - NotUsing - TurnOffAllWarnings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2FCD4B66-9CF9-4C8F-BC70-37CD20002D49} + zlib + Win32Proj + zlib + + + + + StaticLibrary + Unicode + + + + + + + + + + + + + _LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + NotUsing + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/zlib/zlib.vcxproj.filters b/src/thirdparty/zlib/zlib.vcxproj.filters index 6030351d8b4..e6e5259d9e6 100644 --- a/src/thirdparty/zlib/zlib.vcxproj.filters +++ b/src/thirdparty/zlib/zlib.vcxproj.filters @@ -1,101 +1,101 @@ - - - - - {65ae02f7-7823-4d41-b101-45ef452df4b8} - cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90 - - - {53954850-f4af-433e-97cf-8e28a81233fa} - h;hpp;hxx;hm;inl;fi;fd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {65ae02f7-7823-4d41-b101-45ef452df4b8} + cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90 + + + {53954850-f4af-433e-97cf-8e28a81233fa} + h;hpp;hxx;hm;inl;fi;fd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/update_version.bat b/update_version.bat index e2555950014..13a2c8b1a9a 100755 --- a/update_version.bat +++ b/update_version.bat @@ -1,51 +1,51 @@ -@ECHO OFF -REM (C) 2010-2020 see Authors.txt -REM -REM This file is part of MPC-HC. -REM -REM MPC-HC is free software; you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation; either version 3 of the License, or -REM (at your option) any later version. -REM -REM MPC-HC is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with this program. If not, see . - - -SETLOCAL -SET "FILE_DIR=%~dp0" -PUSHD "%FILE_DIR%" - -SET "COMMON=%FILE_DIR%\common.bat" - -IF EXIST "build.user.bat" CALL "build.user.bat" - -IF NOT DEFINED MPCHC_GIT IF DEFINED GIT (SET MPCHC_GIT=%GIT%) ELSE (SET MPCHC_GIT="C:\Program Files\Git") - -SET "PATH=%MPCHC_GIT%\bin;%PATH%" - -CALL "%COMMON%" :SubDoesExist bash.exe -IF %ERRORLEVEL% NEQ 0 GOTO MissingVar - -bash.exe ./version.sh %* - - -:END -POPD -ENDLOCAL -EXIT /B - - -:MissingVar -copy /Y "build\version_rev_fallback.h" "build\version_rev.h" -copy /Y "src\mpc-hc\res\mpc-hc.exe.manifest.fallback" "src\mpc-hc\res\mpc-hc.exe.manifest" -ECHO Not all build dependencies were found: Missing bash.exe in Git installation -ECHO. -ECHO See "docs\Compilation.md" for more information. -ENDLOCAL -EXIT /B +@ECHO OFF +REM (C) 2010-2020 see Authors.txt +REM +REM This file is part of MPC-HC. +REM +REM MPC-HC is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation; either version 3 of the License, or +REM (at your option) any later version. +REM +REM MPC-HC is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with this program. If not, see . + + +SETLOCAL +SET "FILE_DIR=%~dp0" +PUSHD "%FILE_DIR%" + +SET "COMMON=%FILE_DIR%\common.bat" + +IF EXIST "build.user.bat" CALL "build.user.bat" + +IF NOT DEFINED MPCHC_GIT IF DEFINED GIT (SET MPCHC_GIT=%GIT%) ELSE (SET MPCHC_GIT="C:\Program Files\Git") + +SET "PATH=%MPCHC_GIT%\bin;%PATH%" + +CALL "%COMMON%" :SubDoesExist bash.exe +IF %ERRORLEVEL% NEQ 0 GOTO MissingVar + +bash.exe ./version.sh %* + + +:END +POPD +ENDLOCAL +EXIT /B + + +:MissingVar +copy /Y "build\version_rev_fallback.h" "build\version_rev.h" +copy /Y "src\mpc-hc\res\mpc-hc.exe.manifest.fallback" "src\mpc-hc\res\mpc-hc.exe.manifest" +ECHO Not all build dependencies were found: Missing bash.exe in Git installation +ECHO. +ECHO See "docs\Compilation.md" for more information. +ENDLOCAL +EXIT /B From e1ac8281a00e20fb65111cd1d319d29aa7b4d7b5 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 9 Mar 2025 00:11:56 -0800 Subject: [PATCH 10/20] disable buttons in obvious cases --- src/mpc-hc/PPageToolBar.cpp | 52 +++++++++++++++++++++++++++++++++++++ src/mpc-hc/PPageToolBar.h | 5 ++++ 2 files changed, 57 insertions(+) diff --git a/src/mpc-hc/PPageToolBar.cpp b/src/mpc-hc/PPageToolBar.cpp index 4698bacc2ea..cd6713b6964 100644 --- a/src/mpc-hc/PPageToolBar.cpp +++ b/src/mpc-hc/PPageToolBar.cpp @@ -133,8 +133,59 @@ BEGIN_MESSAGE_MAP(CPPageToolBar, CMPCThemePPageBase) ON_BN_CLICKED(IDC_BUTTON5, &CPPageToolBar::MoveUp) ON_BN_CLICKED(IDC_BUTTON6, &CPPageToolBar::MoveDown) ON_BN_CLICKED(IDC_BUTTON1, &CPPageToolBar::DefaultButtons) + ON_UPDATE_COMMAND_UI(IDC_BUTTON3, OnUpdateLeft) + ON_UPDATE_COMMAND_UI(IDC_BUTTON4, OnUpdateRight) + ON_UPDATE_COMMAND_UI(IDC_BUTTON5, OnUpdateUp) + ON_UPDATE_COMMAND_UI(IDC_BUTTON6, OnUpdateDown) END_MESSAGE_MAP() +void CPPageToolBar::OnUpdateLeft(CCmdUI* pCmdUI) { + CPlayerToolBar& tb = AfxGetMainFrame()->m_wndToolBar; + CToolBarCtrl& tbctrl = tb.GetToolBarCtrl(); + auto supportedButtons = tb.GetSupportedSvgButtons(); + + int selectedRowLeft = m_list_active.GetSelectionMark(); + int selectedRowRight = m_list_inactive.GetSelectionMark(); + + if (IsValidInsertPos(selectedRowLeft) && -1 != selectedRowRight) { + pCmdUI->Enable(true); + } else { + pCmdUI->Enable(false); + } +} + +bool CPPageToolBar::LeftSelectedButtonLocked() { + CPlayerToolBar& tb = AfxGetMainFrame()->m_wndToolBar; + CToolBarCtrl& tbctrl = tb.GetToolBarCtrl(); + auto supportedButtons = tb.GetSupportedSvgButtons(); + + int selectedRowLeft = m_list_active.GetSelectionMark(); + + bool enable = false; + if (-1 != selectedRowLeft) { + int tidCommand = (int)m_list_active.GetItemData(selectedRowLeft); + if (supportedButtons.count(tidCommand) == 0 || supportedButtons[tidCommand].positionLocked) { + enable = false; + } else { + enable = true; + } + } + return enable; +} + +void CPPageToolBar::OnUpdateRight(CCmdUI* pCmdUI) { + pCmdUI->Enable(LeftSelectedButtonLocked()); +} + +void CPPageToolBar::OnUpdateUp(CCmdUI* pCmdUI) { + pCmdUI->Enable(LeftSelectedButtonLocked()); +} + +void CPPageToolBar::OnUpdateDown(CCmdUI* pCmdUI) { + pCmdUI->Enable(LeftSelectedButtonLocked()); +} + + bool CPPageToolBar::InsertButton(int beforeID, int buttonID) { CPlayerToolBar& tb = AfxGetMainFrame()->m_wndToolBar; CToolBarCtrl& tbctrl = tb.GetToolBarCtrl(); @@ -175,6 +226,7 @@ bool CPPageToolBar::IsValidInsertPos(int destRow) { if (destRow == -1 || destRow >= m_list_active.GetItemCount()) { return false; } + //avoid inserting between two locked rows, or before first locked or after last locked CPlayerToolBar& tb = AfxGetMainFrame()->m_wndToolBar; diff --git a/src/mpc-hc/PPageToolBar.h b/src/mpc-hc/PPageToolBar.h index 48269ffb1dc..b2b42efe2c0 100644 --- a/src/mpc-hc/PPageToolBar.h +++ b/src/mpc-hc/PPageToolBar.h @@ -55,12 +55,17 @@ class CPPageToolBar : public CMPCThemePPageBase CImage arrow; virtual void DoDataExchange(CDataExchange* pDX) override; + void OnUpdateLeft(CCmdUI* pCmdUI); + void OnUpdateRight(CCmdUI* pCmdUI); + void OnUpdateUp(CCmdUI* pCmdUI); + void OnUpdateDown(CCmdUI* pCmdUI); void LoadToolBarButtons(); virtual BOOL OnInitDialog() override; virtual BOOL OnApply() override; bool InsertButton(int beforeID, int buttonID); bool DeleteButton(int buttonID); bool IsValidInsertPos(int destRow); + bool LeftSelectedButtonLocked(); bool MoveButton(CMPCThemePlayerListCtrl& srcList, CMPCThemePlayerListCtrl& dstList); bool OrderButton(ButtonPosition pos); From be5fbc710be23df239e95365b829aa5f47a99128 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 9 Mar 2025 13:17:44 -0700 Subject: [PATCH 11/20] revert 8e5681 --- build.bat | 1044 +- contrib/sign.bat | 160 +- distrib/Languages/Basque.isl | 678 +- distrib/Languages/Belarusian.isl | 638 +- distrib/Languages/ChineseSimplified.isl | 674 +- distrib/Languages/ChineseTraditional.isl | 662 +- distrib/Languages/Korean.isl | 644 +- distrib/Languages/Slovak.isl | 526 +- distrib/custom_messages.iss | 110 +- distrib/mpc-hc_setup.iss | 1134 +- docs/Compilation.md | 324 +- include/IBitRateInfo.h | 60 +- include/IBufferInfo.h | 62 +- include/IChapterInfo.h | 132 +- include/IFilterVersion.h | 58 +- include/IKeyFrameInfo.h | 60 +- include/ITrackInfo.h | 168 +- include/avisynth/avisynth1.h | 828 +- include/avisynth/avisynth25.h | 1590 +- include/dsm/dsm.h | 74 +- include/lglcd/lglcd.h | 912 +- include/moreuuids.h | 3350 +- include/unrar.h | 370 +- include/vd2/Copying | 678 +- include/vd2/OldFilterSDK/Filter.h | 114 +- include/vd2/OldFilterSDK/ScriptError.h | 16 +- include/vd2/OldFilterSDK/ScriptInterpreter.h | 22 +- include/vd2/OldFilterSDK/ScriptValue.h | 34 +- include/vd2/OldFilterSDK/VBitmap.h | 32 +- include/vd2/OldFilterSDK/VirtualDub.h | 14 +- include/vd2/VDXFrame/Unknown.h | 220 +- include/vd2/VDXFrame/VideoFilter.h | 442 +- include/vd2/VDXFrame/VideoFilterDialog.h | 92 +- include/vd2/VDXFrame/VideoFilterEntry.h | 168 +- include/vd2/extras/FilterSDK/Filter.h | 488 +- include/vd2/extras/FilterSDK/ScriptError.h | 186 +- .../vd2/extras/FilterSDK/ScriptInterpreter.h | 140 +- include/vd2/extras/FilterSDK/ScriptValue.h | 252 +- include/vd2/extras/FilterSDK/VBitmap.h | 344 +- include/vd2/extras/FilterSDK/VirtualDub.h | 14 +- include/vd2/plugin/vdaudiofilt.h | 296 +- include/vd2/plugin/vdinputdriver.h | 568 +- include/vd2/plugin/vdplugin.h | 412 +- include/vd2/plugin/vdvideofilt.h | 1034 +- include/vd2/plugin/vdvideoutil.h | 242 +- include/version.h | 234 +- include/winddk/devioctl.h | 328 +- include/winddk/ntddcdrm.h | 1884 +- include/winddk/ntddcdvd.h | 1592 +- include/winddk/ntdddisk.h | 3518 +- include/winddk/ntddstor.h | 2776 +- src/CmdUI/CmdUI.cpp | 392 +- src/CmdUI/CmdUI.h | 130 +- src/CmdUI/CmdUI.vcxproj | 118 +- src/CmdUI/CmdUI.vcxproj.filters | 58 +- src/CmdUI/stdafx.cpp | 44 +- src/CmdUI/stdafx.h | 56 +- src/DSUtil/DSMPropertyBag.cpp | 1084 +- src/DSUtil/DSMPropertyBag.h | 468 +- src/DSUtil/DSUtil.cpp | 4496 +- src/DSUtil/DSUtil.h | 712 +- src/DSUtil/DSUtil.vcxproj | 240 +- src/DSUtil/DSUtil.vcxproj.filters | 374 +- src/DSUtil/FileVersionInfo.cpp | 182 +- src/DSUtil/FileVersionInfo.h | 64 +- src/DSUtil/FontInstaller.cpp | 278 +- src/DSUtil/FontInstaller.h | 96 +- src/DSUtil/GolombBuffer.cpp | 410 +- src/DSUtil/GolombBuffer.h | 136 +- src/DSUtil/H264Nalu.cpp | 220 +- src/DSUtil/H264Nalu.h | 164 +- src/DSUtil/HdmvClipInfo.cpp | 1642 +- src/DSUtil/HdmvClipInfo.h | 378 +- src/DSUtil/MediaTypeEx.cpp | 1502 +- src/DSUtil/MediaTypeEx.h | 84 +- src/DSUtil/MediaTypes.cpp | 926 +- src/DSUtil/MediaTypes.h | 96 +- src/DSUtil/Mpeg2Def.h | 400 +- src/DSUtil/NullRenderers.cpp | 906 +- src/DSUtil/NullRenderers.h | 190 +- src/DSUtil/SharedInclude.h | 82 +- src/DSUtil/VersionHelpersInternal.h | 166 +- src/DSUtil/WinAPIUtils.cpp | 696 +- src/DSUtil/WinAPIUtils.h | 128 +- src/DSUtil/deinterlace.cpp | 3936 +- src/DSUtil/stdafx.cpp | 44 +- src/DSUtil/stdafx.h | 86 +- src/DSUtil/text.cpp | 838 +- src/DSUtil/text.h | 510 +- src/DSUtil/vd.cpp | 784 +- src/DSUtil/vd.h | 94 +- src/DSUtil/vd_asm.cpp | 864 +- src/DSUtil/vd_asm.h | 68 +- src/DeCSS/CSSauth.cpp | 678 +- src/DeCSS/CSSauth.h | 10 +- src/DeCSS/CSSscramble.cpp | 472 +- src/DeCSS/CSSscramble.h | 16 +- src/DeCSS/DeCSS.vcxproj | 140 +- src/DeCSS/DeCSS.vcxproj.filters | 122 +- src/DeCSS/DeCSSInputPin.cpp | 722 +- src/DeCSS/DeCSSInputPin.h | 100 +- src/DeCSS/VobDec.cpp | 324 +- src/DeCSS/VobDec.h | 42 +- src/DeCSS/VobFile.cpp | 1756 +- src/DeCSS/VobFile.h | 214 +- src/DeCSS/stdafx.cpp | 44 +- src/DeCSS/stdafx.h | 64 +- src/DeCSS/udf.cpp | 704 +- src/DeCSS/udf.h | 512 +- src/MPCTestAPI/HScrollListBox.cpp | 338 +- src/MPCTestAPI/HScrollListBox.h | 124 +- src/MPCTestAPI/MPCTestAPI.cpp | 162 +- src/MPCTestAPI/MPCTestAPI.h | 104 +- src/MPCTestAPI/MPCTestAPI.rc | 520 +- src/MPCTestAPI/MPCTestAPI.vcxproj | 162 +- src/MPCTestAPI/MPCTestAPI.vcxproj.filters | 120 +- src/MPCTestAPI/MPCTestAPIDlg.cpp | 718 +- src/MPCTestAPI/MPCTestAPIDlg.h | 148 +- src/MPCTestAPI/res/MPCTestAPI.exe.manifest | 84 +- src/MPCTestAPI/resource.h | 60 +- src/MPCTestAPI/stdafx.cpp | 42 +- src/MPCTestAPI/stdafx.h | 62 +- src/SubPic/CoordGeom.cpp | 1136 +- src/SubPic/CoordGeom.h | 274 +- src/SubPic/DX9SubPic.cpp | 964 +- src/SubPic/DX9SubPic.h | 156 +- src/SubPic/ISubPic.h | 524 +- src/SubPic/ISubRender.h | 146 +- src/SubPic/MemSubPic.cpp | 1562 +- src/SubPic/MemSubPic.h | 172 +- src/SubPic/SubPic.vcxproj | 168 +- src/SubPic/SubPic.vcxproj.filters | 200 +- src/SubPic/SubPicAllocatorPresenterImpl.cpp | 1292 +- src/SubPic/SubPicAllocatorPresenterImpl.h | 350 +- src/SubPic/SubPicImpl.cpp | 868 +- src/SubPic/SubPicImpl.h | 290 +- src/SubPic/SubPicProviderImpl.cpp | 130 +- src/SubPic/SubPicProviderImpl.h | 104 +- src/SubPic/SubPicQueueImpl.cpp | 1788 +- src/SubPic/SubPicQueueImpl.h | 386 +- src/SubPic/stdafx.cpp | 44 +- src/SubPic/stdafx.h | 78 +- src/Subtitles/CCDecoder.cpp | 780 +- src/Subtitles/CCDecoder.h | 92 +- src/Subtitles/CompositionObject.cpp | 740 +- src/Subtitles/CompositionObject.h | 184 +- src/Subtitles/DVBSub.cpp | 1416 +- src/Subtitles/DVBSub.h | 350 +- src/Subtitles/PGSSub.cpp | 1234 +- src/Subtitles/PGSSub.h | 322 +- src/Subtitles/RTS.cpp | 7450 +-- src/Subtitles/RTS.h | 1092 +- src/Subtitles/Rasterizer.cpp | 4000 +- src/Subtitles/Rasterizer.h | 412 +- src/Subtitles/RealTextParser.cpp | 1198 +- src/Subtitles/RealTextParser.h | 212 +- src/Subtitles/STS.cpp | 7824 +-- src/Subtitles/STS.h | 394 +- src/Subtitles/SeparableFilter.h | 748 +- src/Subtitles/SubtitleInputPin.cpp | 1038 +- src/Subtitles/SubtitleInputPin.h | 172 +- src/Subtitles/Subtitles.vcxproj | 234 +- src/Subtitles/Subtitles.vcxproj.filters | 352 +- src/Subtitles/TextFile.cpp | 1774 +- src/Subtitles/TextFile.h | 194 +- src/Subtitles/USFSubtitles.cpp | 1566 +- src/Subtitles/USFSubtitles.h | 206 +- src/Subtitles/VobSubFile.cpp | 5300 +- src/Subtitles/VobSubFile.h | 438 +- src/Subtitles/VobSubFileRipper.cpp | 2368 +- src/Subtitles/VobSubFileRipper.h | 382 +- src/Subtitles/VobSubImage.cpp | 2722 +- src/Subtitles/VobSubImage.h | 192 +- src/Subtitles/stdafx.cpp | 44 +- src/Subtitles/stdafx.h | 86 +- src/YASM.props | 68 +- src/YASM.targets | 168 +- src/YASM.xml | 292 +- src/common.props | 192 +- src/filters/FilterApp.cpp | 104 +- src/filters/FilterApp.h | 66 +- src/filters/Filters.h | 76 +- src/filters/Filters.vcxproj | 148 +- src/filters/Filters.vcxproj.filters | 86 +- src/filters/InternalPropertyPage.cpp | 714 +- src/filters/InternalPropertyPage.h | 248 +- src/filters/PinInfoWnd.cpp | 572 +- src/filters/PinInfoWnd.h | 140 +- src/filters/muxer/BaseMuxer/BaseMuxer.cpp | 1042 +- src/filters/muxer/BaseMuxer/BaseMuxer.h | 220 +- src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj | 146 +- .../muxer/BaseMuxer/BaseMuxer.vcxproj.filters | 104 +- .../muxer/BaseMuxer/BaseMuxerInputPin.cpp | 572 +- .../muxer/BaseMuxer/BaseMuxerInputPin.h | 194 +- .../muxer/BaseMuxer/BaseMuxerOutputPin.cpp | 974 +- .../muxer/BaseMuxer/BaseMuxerOutputPin.h | 136 +- .../muxer/BaseMuxer/BaseMuxerRelatedPin.cpp | 98 +- .../muxer/BaseMuxer/BaseMuxerRelatedPin.h | 88 +- src/filters/muxer/BaseMuxer/BitStream.cpp | 324 +- src/filters/muxer/BaseMuxer/BitStream.h | 116 +- src/filters/muxer/BaseMuxer/stdafx.cpp | 44 +- src/filters/muxer/BaseMuxer/stdafx.h | 74 +- src/filters/muxer/DSMMuxer/DSMMuxer.cpp | 900 +- src/filters/muxer/DSMMuxer/DSMMuxer.def | 10 +- src/filters/muxer/DSMMuxer/DSMMuxer.h | 132 +- src/filters/muxer/DSMMuxer/DSMMuxer.rc | 204 +- src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj | 252 +- .../muxer/DSMMuxer/DSMMuxer.vcxproj.filters | 90 +- src/filters/muxer/DSMMuxer/resource.h | 30 +- src/filters/muxer/DSMMuxer/stdafx.cpp | 44 +- src/filters/muxer/DSMMuxer/stdafx.h | 78 +- .../muxer/MatroskaMuxer/MatroskaFile.cpp | 1874 +- .../muxer/MatroskaMuxer/MatroskaFile.h | 854 +- .../muxer/MatroskaMuxer/MatroskaMuxer.cpp | 2838 +- .../muxer/MatroskaMuxer/MatroskaMuxer.def | 10 +- .../muxer/MatroskaMuxer/MatroskaMuxer.h | 324 +- .../muxer/MatroskaMuxer/MatroskaMuxer.rc | 204 +- .../muxer/MatroskaMuxer/MatroskaMuxer.vcxproj | 250 +- .../MatroskaMuxer.vcxproj.filters | 102 +- src/filters/muxer/MatroskaMuxer/resource.h | 28 +- src/filters/muxer/MatroskaMuxer/stdafx.cpp | 44 +- src/filters/muxer/MatroskaMuxer/stdafx.h | 70 +- src/filters/muxer/WavDest/WavDest.cpp | 668 +- src/filters/muxer/WavDest/WavDest.def | 10 +- src/filters/muxer/WavDest/WavDest.h | 132 +- src/filters/muxer/WavDest/WavDest.rc | 204 +- src/filters/muxer/WavDest/WavDest.vcxproj | 226 +- .../muxer/WavDest/WavDest.vcxproj.filters | 88 +- src/filters/muxer/WavDest/resource.h | 28 +- src/filters/muxer/WavDest/stdafx.cpp | 44 +- src/filters/muxer/WavDest/stdafx.h | 62 +- .../parser/BaseSplitter/AsyncReader.cpp | 480 +- src/filters/parser/BaseSplitter/AsyncReader.h | 208 +- .../parser/BaseSplitter/BaseSplitter.cpp | 3272 +- .../parser/BaseSplitter/BaseSplitter.h | 832 +- .../parser/BaseSplitter/BaseSplitter.vcxproj | 142 +- .../BaseSplitter/BaseSplitter.vcxproj.filters | 92 +- .../parser/BaseSplitter/BaseSplitterFile.cpp | 518 +- .../parser/BaseSplitter/BaseSplitterFile.h | 142 +- .../parser/BaseSplitter/MultiFiles.cpp | 396 +- src/filters/parser/BaseSplitter/MultiFiles.h | 202 +- src/filters/parser/BaseSplitter/stdafx.cpp | 44 +- src/filters/parser/BaseSplitter/stdafx.h | 70 +- .../parser/DSMSplitter/DSMSplitter.cpp | 582 +- .../parser/DSMSplitter/DSMSplitter.def | 10 +- src/filters/parser/DSMSplitter/DSMSplitter.h | 122 +- src/filters/parser/DSMSplitter/DSMSplitter.rc | 204 +- .../parser/DSMSplitter/DSMSplitter.vcxproj | 256 +- .../DSMSplitter/DSMSplitter.vcxproj.filters | 102 +- .../parser/DSMSplitter/DSMSplitterFile.cpp | 850 +- .../parser/DSMSplitter/DSMSplitterFile.h | 124 +- src/filters/parser/DSMSplitter/resource.h | 28 +- src/filters/parser/DSMSplitter/stdafx.cpp | 44 +- src/filters/parser/DSMSplitter/stdafx.h | 72 +- .../StreamDriveThru/StreamDriveThru.cpp | 1248 +- .../StreamDriveThru/StreamDriveThru.def | 10 +- .../parser/StreamDriveThru/StreamDriveThru.h | 258 +- .../parser/StreamDriveThru/StreamDriveThru.rc | 204 +- .../StreamDriveThru/StreamDriveThru.vcxproj | 246 +- .../StreamDriveThru.vcxproj.filters | 90 +- src/filters/parser/StreamDriveThru/resource.h | 28 +- src/filters/parser/StreamDriveThru/stdafx.cpp | 44 +- src/filters/parser/StreamDriveThru/stdafx.h | 68 +- src/filters/reader/CDDAReader/CDDAReader.cpp | 1120 +- src/filters/reader/CDDAReader/CDDAReader.def | 10 +- src/filters/reader/CDDAReader/CDDAReader.h | 286 +- src/filters/reader/CDDAReader/CDDAReader.rc | 204 +- .../reader/CDDAReader/CDDAReader.vcxproj | 252 +- .../CDDAReader/CDDAReader.vcxproj.filters | 90 +- src/filters/reader/CDDAReader/resource.h | 28 +- src/filters/reader/CDDAReader/stdafx.cpp | 44 +- src/filters/reader/CDDAReader/stdafx.h | 68 +- src/filters/reader/CDXAReader/CDXAReader.cpp | 1122 +- src/filters/reader/CDXAReader/CDXAReader.def | 10 +- src/filters/reader/CDXAReader/CDXAReader.h | 186 +- src/filters/reader/CDXAReader/CDXAReader.rc | 204 +- .../reader/CDXAReader/CDXAReader.vcxproj | 252 +- .../CDXAReader/CDXAReader.vcxproj.filters | 90 +- src/filters/reader/CDXAReader/resource.h | 28 +- src/filters/reader/CDXAReader/stdafx.cpp | 44 +- src/filters/reader/CDXAReader/stdafx.h | 68 +- src/filters/reader/VTSReader/VTSReader.cpp | 594 +- src/filters/reader/VTSReader/VTSReader.def | 10 +- src/filters/reader/VTSReader/VTSReader.h | 192 +- src/filters/reader/VTSReader/VTSReader.rc | 204 +- .../reader/VTSReader/VTSReader.vcxproj | 258 +- .../VTSReader/VTSReader.vcxproj.filters | 90 +- src/filters/reader/VTSReader/resource.h | 28 +- src/filters/reader/VTSReader/stdafx.cpp | 44 +- src/filters/reader/VTSReader/stdafx.h | 66 +- src/filters/renderer/SyncClock/Interfaces.h | 66 +- src/filters/renderer/SyncClock/SyncClock.cpp | 240 +- src/filters/renderer/SyncClock/SyncClock.h | 142 +- .../renderer/SyncClock/SyncClock.vcxproj | 122 +- .../SyncClock/SyncClock.vcxproj.filters | 62 +- src/filters/renderer/SyncClock/stdafx.cpp | 42 +- src/filters/renderer/SyncClock/stdafx.h | 64 +- .../VideoRenderers/AllocatorCommon.cpp | 642 +- .../renderer/VideoRenderers/AllocatorCommon.h | 122 +- .../renderer/VideoRenderers/D3DFont.cpp | 1754 +- src/filters/renderer/VideoRenderers/D3DFont.h | 156 +- .../VideoRenderers/DX9AllocatorPresenter.cpp | 4618 +- .../VideoRenderers/DX9AllocatorPresenter.h | 626 +- .../VideoRenderers/DX9RenderingEngine.cpp | 3510 +- .../VideoRenderers/DX9RenderingEngine.h | 370 +- .../VideoRenderers/DXRAllocatorPresenter.cpp | 456 +- .../VideoRenderers/DXRAllocatorPresenter.h | 206 +- .../renderer/VideoRenderers/Dither.cpp | 180 +- src/filters/renderer/VideoRenderers/Dither.h | 48 +- .../VideoRenderers/EVRAllocatorPresenter.cpp | 5992 +-- .../VideoRenderers/EVRAllocatorPresenter.h | 560 +- .../renderer/VideoRenderers/IPinHook.cpp | 588 +- .../renderer/VideoRenderers/IPinHook.h | 164 +- .../renderer/VideoRenderers/IQTVideoSurface.h | 68 +- .../VideoRenderers/MacrovisionKicker.cpp | 196 +- .../VideoRenderers/MacrovisionKicker.h | 86 +- .../renderer/VideoRenderers/OuterEVR.cpp | 308 +- .../renderer/VideoRenderers/OuterEVR.h | 182 +- .../renderer/VideoRenderers/OuterVMR.cpp | 340 +- .../renderer/VideoRenderers/OuterVMR.h | 402 +- .../VideoRenderers/PixelShaderCompiler.cpp | 460 +- .../VideoRenderers/PixelShaderCompiler.h | 140 +- .../VideoRenderers/RenderersSettings.cpp | 258 +- .../VideoRenderers/RenderersSettings.h | 310 +- .../VideoRenderers/SyncAllocatorPresenter.h | 66 +- .../renderer/VideoRenderers/SyncRenderer.cpp | 9440 ++-- .../renderer/VideoRenderers/SyncRenderer.h | 1372 +- .../VideoRenderers/VMR9AllocatorPresenter.cpp | 1164 +- .../VideoRenderers/VMR9AllocatorPresenter.h | 160 +- .../VideoRenderers/VideoRenderers.vcxproj | 210 +- .../VideoRenderers.vcxproj.filters | 308 +- .../madVRAllocatorPresenter.cpp | 598 +- .../VideoRenderers/madVRAllocatorPresenter.h | 178 +- .../renderer/VideoRenderers/stdafx.cpp | 44 +- src/filters/renderer/VideoRenderers/stdafx.h | 72 +- src/filters/source/BaseSource/BaseSource.cpp | 384 +- src/filters/source/BaseSource/BaseSource.h | 260 +- .../source/BaseSource/BaseSource.vcxproj | 130 +- .../BaseSource/BaseSource.vcxproj.filters | 56 +- src/filters/source/BaseSource/stdafx.cpp | 44 +- src/filters/source/BaseSource/stdafx.h | 70 +- .../source/SubtitleSource/SubtitleSource.cpp | 1602 +- .../source/SubtitleSource/SubtitleSource.def | 10 +- .../source/SubtitleSource/SubtitleSource.h | 310 +- .../source/SubtitleSource/SubtitleSource.rc | 204 +- .../SubtitleSource/SubtitleSource.vcxproj | 264 +- .../SubtitleSource.vcxproj.filters | 90 +- src/filters/source/SubtitleSource/resource.h | 28 +- src/filters/source/SubtitleSource/stdafx.cpp | 44 +- src/filters/source/SubtitleSource/stdafx.h | 68 +- src/filters/stdafx.cpp | 44 +- src/filters/stdafx.h | 86 +- src/filters/switcher/AudioSwitcher/Audio.cpp | 644 +- src/filters/switcher/AudioSwitcher/Audio.h | 100 +- .../switcher/AudioSwitcher/AudioSwitcher.cpp | 1510 +- .../switcher/AudioSwitcher/AudioSwitcher.def | 10 +- .../switcher/AudioSwitcher/AudioSwitcher.h | 208 +- .../switcher/AudioSwitcher/AudioSwitcher.rc | 204 +- .../AudioSwitcher/AudioSwitcher.vcxproj | 254 +- .../AudioSwitcher.vcxproj.filters | 112 +- .../switcher/AudioSwitcher/StreamSwitcher.cpp | 3280 +- .../switcher/AudioSwitcher/StreamSwitcher.h | 538 +- src/filters/switcher/AudioSwitcher/resource.h | 28 +- src/filters/switcher/AudioSwitcher/stdafx.cpp | 44 +- src/filters/switcher/AudioSwitcher/stdafx.h | 72 +- .../transform/AVI2AC3Filter/AVI2AC3Filter.cpp | 1024 +- .../transform/AVI2AC3Filter/AVI2AC3Filter.def | 10 +- .../transform/AVI2AC3Filter/AVI2AC3Filter.h | 134 +- .../transform/AVI2AC3Filter/AVI2AC3Filter.rc | 204 +- .../AVI2AC3Filter/AVI2AC3Filter.vcxproj | 226 +- .../AVI2AC3Filter.vcxproj.filters | 90 +- .../transform/AVI2AC3Filter/resource.h | 28 +- .../transform/AVI2AC3Filter/stdafx.cpp | 44 +- src/filters/transform/AVI2AC3Filter/stdafx.h | 68 +- .../transform/BufferFilter/BufferFilter.cpp | 744 +- .../transform/BufferFilter/BufferFilter.def | 10 +- .../transform/BufferFilter/BufferFilter.h | 198 +- .../transform/BufferFilter/BufferFilter.rc | 204 +- .../BufferFilter/BufferFilter.vcxproj | 226 +- .../BufferFilter/BufferFilter.vcxproj.filters | 88 +- src/filters/transform/BufferFilter/resource.h | 28 +- src/filters/transform/BufferFilter/stdafx.cpp | 44 +- src/filters/transform/BufferFilter/stdafx.h | 68 +- .../transform/DeCSSFilter/DeCSSFilter.cpp | 518 +- .../transform/DeCSSFilter/DeCSSFilter.def | 10 +- .../transform/DeCSSFilter/DeCSSFilter.h | 80 +- .../transform/DeCSSFilter/DeCSSFilter.rc | 204 +- .../transform/DeCSSFilter/DeCSSFilter.vcxproj | 232 +- .../DeCSSFilter/DeCSSFilter.vcxproj.filters | 88 +- src/filters/transform/DeCSSFilter/resource.h | 28 +- src/filters/transform/DeCSSFilter/stdafx.cpp | 44 +- src/filters/transform/DeCSSFilter/stdafx.h | 68 +- .../transform/VSFilter/IDirectVobSub.h | 388 +- src/mpc-hc/AboutDlg.cpp | 680 +- src/mpc-hc/AboutDlg.h | 134 +- src/mpc-hc/AppSettings.cpp | 7738 +-- src/mpc-hc/AppSettings.h | 2152 +- src/mpc-hc/AuthDlg.cpp | 184 +- src/mpc-hc/AuthDlg.h | 52 +- src/mpc-hc/BaseGraph.cpp | 1818 +- src/mpc-hc/BaseGraph.h | 522 +- src/mpc-hc/CMPCTheme.cpp | 1394 +- src/mpc-hc/CMPCTheme.h | 390 +- src/mpc-hc/CMPCThemeButton.cpp | 382 +- src/mpc-hc/CMPCThemeButton.h | 44 +- src/mpc-hc/CMPCThemeCmdUIDialog.cpp | 90 +- src/mpc-hc/CMPCThemeCmdUIDialog.h | 42 +- src/mpc-hc/CMPCThemeComPropertyPage.cpp | 92 +- src/mpc-hc/CMPCThemeComPropertyPage.h | 42 +- src/mpc-hc/CMPCThemeComboBox.cpp | 600 +- src/mpc-hc/CMPCThemeComboBox.h | 66 +- src/mpc-hc/CMPCThemeDialog.cpp | 134 +- src/mpc-hc/CMPCThemeDialog.h | 58 +- src/mpc-hc/CMPCThemeDockBar.cpp | 124 +- src/mpc-hc/CMPCThemeDockBar.h | 30 +- src/mpc-hc/CMPCThemeEdit.cpp | 874 +- src/mpc-hc/CMPCThemeEdit.h | 78 +- src/mpc-hc/CMPCThemeFrameUtil.cpp | 14 +- src/mpc-hc/CMPCThemeFrameUtil.h | 28 +- src/mpc-hc/CMPCThemeFrameWnd.cpp | 900 +- src/mpc-hc/CMPCThemeFrameWnd.h | 98 +- src/mpc-hc/CMPCThemeGroupBox.cpp | 212 +- src/mpc-hc/CMPCThemeGroupBox.h | 36 +- src/mpc-hc/CMPCThemeHeaderCtrl.cpp | 544 +- src/mpc-hc/CMPCThemeHeaderCtrl.h | 42 +- src/mpc-hc/CMPCThemeInlineEdit.cpp | 138 +- src/mpc-hc/CMPCThemeInlineEdit.h | 42 +- src/mpc-hc/CMPCThemeLinkCtrl.cpp | 70 +- src/mpc-hc/CMPCThemeLinkCtrl.h | 26 +- src/mpc-hc/CMPCThemeListBox.cpp | 448 +- src/mpc-hc/CMPCThemeListBox.h | 74 +- src/mpc-hc/CMPCThemeMaskedEdit.cpp | 102 +- src/mpc-hc/CMPCThemeMaskedEdit.h | 36 +- src/mpc-hc/CMPCThemeMenu.cpp | 1180 +- src/mpc-hc/CMPCThemeMenu.h | 126 +- src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp | 42 +- src/mpc-hc/CMPCThemeMiniDockFrameWnd.h | 24 +- src/mpc-hc/CMPCThemeMsgBox.cpp | 164 +- src/mpc-hc/CMPCThemeMsgBox.h | 40 +- src/mpc-hc/CMPCThemePPageBase.cpp | 178 +- src/mpc-hc/CMPCThemePPageBase.h | 48 +- src/mpc-hc/CMPCThemePlayerBar.cpp | 282 +- src/mpc-hc/CMPCThemePlayerBar.h | 44 +- src/mpc-hc/CMPCThemePlayerListCtrl.cpp | 1266 +- src/mpc-hc/CMPCThemePlayerListCtrl.h | 148 +- src/mpc-hc/CMPCThemePropPageFrame.cpp | 196 +- src/mpc-hc/CMPCThemePropPageFrame.h | 38 +- src/mpc-hc/CMPCThemePropertyPage.cpp | 72 +- src/mpc-hc/CMPCThemePropertyPage.h | 38 +- src/mpc-hc/CMPCThemePropertySheet.cpp | 132 +- src/mpc-hc/CMPCThemePropertySheet.h | 50 +- src/mpc-hc/CMPCThemeRadioOrCheck.cpp | 548 +- src/mpc-hc/CMPCThemeRadioOrCheck.h | 76 +- src/mpc-hc/CMPCThemeResizableDialog.cpp | 102 +- src/mpc-hc/CMPCThemeResizableDialog.h | 38 +- src/mpc-hc/CMPCThemeScrollBar.cpp | 560 +- src/mpc-hc/CMPCThemeScrollBar.h | 62 +- src/mpc-hc/CMPCThemeScrollBarHelper.cpp | 696 +- src/mpc-hc/CMPCThemeScrollBarHelper.h | 102 +- src/mpc-hc/CMPCThemeSliderCtrl.cpp | 402 +- src/mpc-hc/CMPCThemeSliderCtrl.h | 56 +- src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp | 472 +- src/mpc-hc/CMPCThemeSpinButtonCtrl.h | 54 +- src/mpc-hc/CMPCThemeStatic.cpp | 358 +- src/mpc-hc/CMPCThemeStatic.h | 42 +- src/mpc-hc/CMPCThemeStaticLink.cpp | 198 +- src/mpc-hc/CMPCThemeStaticLink.h | 36 +- src/mpc-hc/CMPCThemeStatusBar.cpp | 246 +- src/mpc-hc/CMPCThemeStatusBar.h | 46 +- src/mpc-hc/CMPCThemeTabCtrl.cpp | 400 +- src/mpc-hc/CMPCThemeTabCtrl.h | 42 +- src/mpc-hc/CMPCThemeTitleBarControlButton.cpp | 266 +- src/mpc-hc/CMPCThemeTitleBarControlButton.h | 42 +- src/mpc-hc/CMPCThemeToolTipCtrl.cpp | 526 +- src/mpc-hc/CMPCThemeToolTipCtrl.h | 90 +- src/mpc-hc/CMPCThemeTreeCtrl.cpp | 488 +- src/mpc-hc/CMPCThemeTreeCtrl.h | 72 +- src/mpc-hc/CMPCThemeUtil.cpp | 2602 +- src/mpc-hc/CMPCThemeUtil.h | 270 +- src/mpc-hc/CMPCThemeWin10Api.h | 120 +- src/mpc-hc/CShockwaveFlash.cpp | 58 +- src/mpc-hc/CShockwaveFlash.h | 766 +- src/mpc-hc/ChildView.cpp | 414 +- src/mpc-hc/ChildView.h | 106 +- src/mpc-hc/ColorButton.cpp | 192 +- src/mpc-hc/ComPropertyPage.cpp | 208 +- src/mpc-hc/ComPropertyPage.h | 104 +- src/mpc-hc/ComPropertySheet.cpp | 574 +- src/mpc-hc/ComPropertySheet.h | 140 +- src/mpc-hc/DVBChannel.cpp | 620 +- src/mpc-hc/DVBChannel.h | 442 +- src/mpc-hc/DeinterlacerFilter.cpp | 340 +- src/mpc-hc/DeinterlacerFilter.h | 74 +- src/mpc-hc/EditListEditor.cpp | 1324 +- src/mpc-hc/EditListEditor.h | 242 +- src/mpc-hc/EditWithButton.cpp | 726 +- src/mpc-hc/EditWithButton.h | 226 +- src/mpc-hc/ExceptionHandler.cpp | 426 +- src/mpc-hc/ExceptionHandler.h | 54 +- src/mpc-hc/FGFilter.cpp | 1556 +- src/mpc-hc/FGFilter.h | 386 +- src/mpc-hc/FGFilterLAV.cpp | 2548 +- src/mpc-hc/FGManager.cpp | 6088 +-- src/mpc-hc/FGManager.h | 424 +- src/mpc-hc/FGManagerBDA.cpp | 2912 +- src/mpc-hc/FGManagerBDA.h | 356 +- src/mpc-hc/FakeFilterMapper2.cpp | 1436 +- src/mpc-hc/FakeFilterMapper2.h | 198 +- src/mpc-hc/FavoriteAddDlg.cpp | 250 +- src/mpc-hc/FavoriteAddDlg.h | 108 +- src/mpc-hc/FavoriteOrganizeDlg.cpp | 1064 +- src/mpc-hc/FavoriteOrganizeDlg.h | 168 +- src/mpc-hc/FileAssoc.cpp | 1488 +- src/mpc-hc/FileAssoc.h | 272 +- src/mpc-hc/FilterEnum.h | 548 +- src/mpc-hc/FloatEdit.cpp | 362 +- src/mpc-hc/FloatEdit.h | 140 +- src/mpc-hc/FullscreenWnd.cpp | 206 +- src/mpc-hc/FullscreenWnd.h | 102 +- src/mpc-hc/GoToDlg.cpp | 390 +- src/mpc-hc/GoToDlg.h | 134 +- src/mpc-hc/GraphThread.cpp | 214 +- src/mpc-hc/GraphThread.h | 112 +- src/mpc-hc/IGraphBuilder2.h | 122 +- src/mpc-hc/Ifo.cpp | 564 +- src/mpc-hc/Ifo.h | 372 +- src/mpc-hc/ImageGrayer.cpp | 608 +- src/mpc-hc/ImageGrayer.h | 70 +- src/mpc-hc/InternalFiltersConfig.h | 248 +- src/mpc-hc/KeyProvider.cpp | 114 +- src/mpc-hc/KeyProvider.h | 84 +- src/mpc-hc/LcdSupport.cpp | 1522 +- src/mpc-hc/LcdSupport.h | 272 +- src/mpc-hc/MPCPngImage.cpp | 228 +- src/mpc-hc/MPCPngImage.h | 58 +- src/mpc-hc/MainFrm.cpp | 44364 ++++++++-------- src/mpc-hc/MainFrm.h | 2822 +- src/mpc-hc/MediaFormats.cpp | 686 +- src/mpc-hc/MediaFormats.h | 182 +- src/mpc-hc/MediaTypesDlg.cpp | 316 +- src/mpc-hc/MediaTypesDlg.h | 128 +- src/mpc-hc/Monitors.cpp | 492 +- src/mpc-hc/Monitors.h | 180 +- src/mpc-hc/MpcApi.h | 572 +- src/mpc-hc/Mpeg2SectionData.cpp | 1758 +- src/mpc-hc/Mpeg2SectionData.h | 188 +- src/mpc-hc/MultiMonitor.cpp | 526 +- src/mpc-hc/MultiMonitor.h | 178 +- src/mpc-hc/OpenDirHelper.cpp | 226 +- src/mpc-hc/OpenDirHelper.h | 72 +- src/mpc-hc/OpenDlg.cpp | 474 +- src/mpc-hc/OpenDlg.h | 136 +- src/mpc-hc/OpenFileDlg.cpp | 474 +- src/mpc-hc/OpenFileDlg.h | 124 +- src/mpc-hc/PPageAccelTbl.cpp | 2904 +- src/mpc-hc/PPageAccelTbl.h | 250 +- src/mpc-hc/PPageAudioSwitcher.cpp | 880 +- src/mpc-hc/PPageAudioSwitcher.h | 188 +- src/mpc-hc/PPageBase.cpp | 382 +- src/mpc-hc/PPageBase.h | 122 +- src/mpc-hc/PPageCapture.cpp | 1460 +- src/mpc-hc/PPageCapture.h | 146 +- src/mpc-hc/PPageDVD.cpp | 660 +- src/mpc-hc/PPageDVD.h | 140 +- src/mpc-hc/PPageExternalFilters.cpp | 1740 +- src/mpc-hc/PPageExternalFilters.h | 234 +- src/mpc-hc/PPageFileInfoClip.cpp | 450 +- src/mpc-hc/PPageFileInfoClip.h | 130 +- src/mpc-hc/PPageFileInfoDetails.cpp | 786 +- src/mpc-hc/PPageFileInfoDetails.h | 126 +- src/mpc-hc/PPageFileInfoSheet.cpp | 196 +- src/mpc-hc/PPageFileInfoSheet.h | 116 +- src/mpc-hc/PPageFileMediaInfo.cpp | 596 +- src/mpc-hc/PPageFileMediaInfo.h | 140 +- src/mpc-hc/PPageFormats.cpp | 1050 +- src/mpc-hc/PPageFormats.h | 198 +- src/mpc-hc/PPageFullscreen.cpp | 1514 +- src/mpc-hc/PPageFullscreen.h | 222 +- src/mpc-hc/PPageInternalFilters.cpp | 1546 +- src/mpc-hc/PPageInternalFilters.h | 214 +- src/mpc-hc/PPageLogo.cpp | 474 +- src/mpc-hc/PPageLogo.h | 130 +- src/mpc-hc/PPageMisc.cpp | 586 +- src/mpc-hc/PPageMisc.h | 172 +- src/mpc-hc/PPageOutput.cpp | 1524 +- src/mpc-hc/PPageOutput.h | 206 +- src/mpc-hc/PPagePlayback.cpp | 740 +- src/mpc-hc/PPagePlayback.h | 192 +- src/mpc-hc/PPagePlayer.cpp | 412 +- src/mpc-hc/PPagePlayer.h | 152 +- src/mpc-hc/PPageShaders.cpp | 1218 +- src/mpc-hc/PPageShaders.h | 244 +- src/mpc-hc/PPageSheet.cpp | 786 +- src/mpc-hc/PPageSheet.h | 304 +- src/mpc-hc/PPageSubMisc.cpp | 770 +- src/mpc-hc/PPageSubMisc.h | 172 +- src/mpc-hc/PPageSubStyle.cpp | 834 +- src/mpc-hc/PPageSubStyle.h | 200 +- src/mpc-hc/PPageSubtitles.cpp | 676 +- src/mpc-hc/PPageSubtitles.h | 146 +- src/mpc-hc/PPageSync.cpp | 362 +- src/mpc-hc/PPageSync.h | 132 +- src/mpc-hc/PPageTweaks.cpp | 340 +- src/mpc-hc/PPageTweaks.h | 128 +- src/mpc-hc/PPageWebServer.cpp | 522 +- src/mpc-hc/PPageWebServer.h | 144 +- src/mpc-hc/PlayerBar.cpp | 398 +- src/mpc-hc/PlayerBar.h | 134 +- src/mpc-hc/PlayerCaptureBar.cpp | 220 +- src/mpc-hc/PlayerCaptureBar.h | 102 +- src/mpc-hc/PlayerCaptureDialog.cpp | 3506 +- src/mpc-hc/PlayerCaptureDialog.h | 1020 +- src/mpc-hc/PlayerInfoBar.cpp | 600 +- src/mpc-hc/PlayerInfoBar.h | 144 +- src/mpc-hc/PlayerListCtrl.cpp | 2296 +- src/mpc-hc/PlayerListCtrl.h | 408 +- src/mpc-hc/PlayerNavigationBar.cpp | 296 +- src/mpc-hc/PlayerNavigationBar.h | 114 +- src/mpc-hc/PlayerNavigationDialog.cpp | 702 +- src/mpc-hc/PlayerNavigationDialog.h | 164 +- src/mpc-hc/PlayerPlaylistBar.cpp | 5194 +- src/mpc-hc/PlayerPlaylistBar.h | 412 +- src/mpc-hc/PlayerSeekBar.cpp | 1912 +- src/mpc-hc/PlayerSeekBar.h | 268 +- src/mpc-hc/PlayerStatusBar.cpp | 1266 +- src/mpc-hc/PlayerStatusBar.h | 202 +- src/mpc-hc/PlayerSubresyncBar.cpp | 3130 +- src/mpc-hc/PlayerSubresyncBar.h | 356 +- src/mpc-hc/PlayerToolBar.cpp | 1694 +- src/mpc-hc/PlayerToolBar.h | 268 +- src/mpc-hc/Playlist.cpp | 954 +- src/mpc-hc/Playlist.h | 246 +- src/mpc-hc/PnSPresetsDlg.cpp | 544 +- src/mpc-hc/PnSPresetsDlg.h | 146 +- src/mpc-hc/RegFilterChooserDlg.cpp | 368 +- src/mpc-hc/RegFilterChooserDlg.h | 122 +- src/mpc-hc/SaveDlg.cpp | 562 +- src/mpc-hc/SaveDlg.h | 126 +- src/mpc-hc/SaveImageDialog.cpp | 232 +- src/mpc-hc/SaveImageDialog.h | 96 +- src/mpc-hc/SaveTextFileDialog.cpp | 180 +- src/mpc-hc/SaveTextFileDialog.h | 108 +- src/mpc-hc/SaveThumbnailsDialog.cpp | 204 +- src/mpc-hc/SaveThumbnailsDialog.h | 100 +- src/mpc-hc/SelectMediaType.cpp | 204 +- src/mpc-hc/SelectMediaType.h | 114 +- src/mpc-hc/SettingsDefines.h | 816 +- src/mpc-hc/ShockwaveGraph.cpp | 652 +- src/mpc-hc/ShockwaveGraph.h | 164 +- src/mpc-hc/StaticLink.cpp | 302 +- src/mpc-hc/StaticLink.h | 148 +- src/mpc-hc/StatusLabel.cpp | 198 +- src/mpc-hc/StatusLabel.h | 102 +- src/mpc-hc/Struct.h | 164 +- src/mpc-hc/SubtitleDlDlg.cpp | 1694 +- src/mpc-hc/SubtitleDlDlg.h | 272 +- src/mpc-hc/SubtitlesProvider.cpp | 2016 +- src/mpc-hc/SubtitlesProvider.h | 246 +- src/mpc-hc/SubtitlesProviders.h | 886 +- src/mpc-hc/TextPassThruFilter.cpp | 510 +- src/mpc-hc/TextPassThruFilter.h | 92 +- src/mpc-hc/TunerScanDlg.cpp | 634 +- src/mpc-hc/TunerScanDlg.h | 160 +- src/mpc-hc/UpdateChecker.cpp | 576 +- src/mpc-hc/UpdateChecker.h | 174 +- src/mpc-hc/UpdateCheckerDlg.cpp | 264 +- src/mpc-hc/UpdateCheckerDlg.h | 108 +- src/mpc-hc/VMROSD.cpp | 1324 +- src/mpc-hc/VMROSD.h | 288 +- src/mpc-hc/VolumeCtrl.cpp | 996 +- src/mpc-hc/VolumeCtrl.h | 132 +- src/mpc-hc/WebClientSocket.cpp | 2036 +- src/mpc-hc/WebClientSocket.h | 170 +- src/mpc-hc/WebServer.cpp | 1430 +- src/mpc-hc/WebServer.h | 146 +- src/mpc-hc/WebServerSocket.cpp | 90 +- src/mpc-hc/WebServerSocket.h | 72 +- src/mpc-hc/WinHotkeyCtrl.cpp | 634 +- src/mpc-hc/WinHotkeyCtrl.h | 144 +- src/mpc-hc/mpc-hc.vcxproj | 1684 +- src/mpc-hc/mpc-hc.vcxproj.filters | 2952 +- src/mpc-hc/mpciconlib/mpciconlib.cpp | 546 +- src/mpc-hc/mpciconlib/mpciconlib.h | 172 +- src/mpc-hc/mpciconlib/mpciconlib.rc | 308 +- src/mpc-hc/mpciconlib/mpciconlib.vcxproj | 226 +- .../mpciconlib/mpciconlib.vcxproj.filters | 342 +- src/mpc-hc/mpcresources/mpcresources.vcxproj | 1192 +- .../mpcresources/mpcresources.vcxproj.filters | 320 +- src/mpc-hc/mplayerc.cpp | 5650 +- src/mpc-hc/mplayerc.h | 468 +- src/mpc-hc/res/mpc-hc.exe.manifest.conf | 88 +- src/mpc-hc/res/shaders/empty.psh | 34 +- src/mpc-hc/res/shaders/final.psh | 58 +- src/mpc-hc/res/shaders/resizer.psh | 230 +- src/mpc-hc/res/web/404.html | 28 +- src/mpc-hc/res/web/browser.html | 66 +- src/mpc-hc/res/web/controls.html | 2408 +- src/mpc-hc/res/web/default.css | 700 +- src/mpc-hc/res/web/index.html | 50 +- src/mpc-hc/res/web/info.html | 28 +- src/mpc-hc/res/web/javascript.js | 1148 +- src/mpc-hc/res/web/player.html | 218 +- src/mpc-hc/res/web/variables.html | 62 +- src/mpc-hc/resource.h | 3540 +- src/mpc-hc/stdafx.cpp | 44 +- src/mpc-hc/stdafx.h | 178 +- src/mpc-hc/vkCodes.cpp | 674 +- src/mpc-hc/vkCodes.h | 52 +- .../AsyncReader/AsyncReader.vcxproj | 134 +- .../AsyncReader/AsyncReader.vcxproj.filters | 68 +- src/thirdparty/AsyncReader/asyncio.cpp | 1418 +- src/thirdparty/AsyncReader/asyncio.h | 560 +- src/thirdparty/AsyncReader/asyncrdr.cpp | 908 +- src/thirdparty/AsyncReader/asyncrdr.h | 472 +- src/thirdparty/AsyncReader/stdafx.cpp | 44 +- src/thirdparty/AsyncReader/stdafx.h | 56 +- .../BaseClasses/BaseClasses.vcxproj | 258 +- .../BaseClasses/BaseClasses.vcxproj.filters | 446 +- src/thirdparty/BaseClasses/amextra.cpp | 222 +- src/thirdparty/BaseClasses/amextra.h | 112 +- src/thirdparty/BaseClasses/amfilter.cpp | 10746 ++-- src/thirdparty/BaseClasses/amfilter.h | 3174 +- src/thirdparty/BaseClasses/amvideo.cpp | 550 +- src/thirdparty/BaseClasses/arithutil.cpp | 720 +- src/thirdparty/BaseClasses/cache.h | 148 +- src/thirdparty/BaseClasses/checkbmi.h | 240 +- src/thirdparty/BaseClasses/combase.cpp | 532 +- src/thirdparty/BaseClasses/combase.h | 630 +- src/thirdparty/BaseClasses/cprop.cpp | 768 +- src/thirdparty/BaseClasses/cprop.h | 190 +- src/thirdparty/BaseClasses/ctlutil.cpp | 5078 +- src/thirdparty/BaseClasses/ctlutil.h | 1846 +- src/thirdparty/BaseClasses/ddmm.cpp | 258 +- src/thirdparty/BaseClasses/ddmm.h | 56 +- src/thirdparty/BaseClasses/dllentry.cpp | 730 +- src/thirdparty/BaseClasses/dllsetup.cpp | 1392 +- src/thirdparty/BaseClasses/dllsetup.h | 92 +- src/thirdparty/BaseClasses/dxmperf.h | 500 +- src/thirdparty/BaseClasses/fourcc.h | 202 +- src/thirdparty/BaseClasses/measure.h | 444 +- src/thirdparty/BaseClasses/msgthrd.h | 240 +- src/thirdparty/BaseClasses/mtype.cpp | 956 +- src/thirdparty/BaseClasses/mtype.h | 178 +- src/thirdparty/BaseClasses/outputq.cpp | 1602 +- src/thirdparty/BaseClasses/outputq.h | 274 +- src/thirdparty/BaseClasses/perflog.cpp | 694 +- src/thirdparty/BaseClasses/perflog.h | 112 +- src/thirdparty/BaseClasses/perfstruct.h | 388 +- src/thirdparty/BaseClasses/pstream.cpp | 394 +- src/thirdparty/BaseClasses/pstream.h | 228 +- src/thirdparty/BaseClasses/pullpin.cpp | 1186 +- src/thirdparty/BaseClasses/pullpin.h | 304 +- src/thirdparty/BaseClasses/refclock.cpp | 806 +- src/thirdparty/BaseClasses/refclock.h | 368 +- src/thirdparty/BaseClasses/reftime.h | 232 +- src/thirdparty/BaseClasses/renbase.cpp | 5716 +- src/thirdparty/BaseClasses/renbase.h | 956 +- src/thirdparty/BaseClasses/schedule.cpp | 576 +- src/thirdparty/BaseClasses/schedule.h | 280 +- src/thirdparty/BaseClasses/seekpt.cpp | 166 +- src/thirdparty/BaseClasses/seekpt.h | 60 +- src/thirdparty/BaseClasses/source.cpp | 1044 +- src/thirdparty/BaseClasses/source.h | 344 +- src/thirdparty/BaseClasses/stdafx.cpp | 46 +- src/thirdparty/BaseClasses/streams.h | 380 +- src/thirdparty/BaseClasses/strmctl.cpp | 810 +- src/thirdparty/BaseClasses/strmctl.h | 314 +- src/thirdparty/BaseClasses/sysclock.cpp | 148 +- src/thirdparty/BaseClasses/sysclock.h | 78 +- src/thirdparty/BaseClasses/transfrm.cpp | 2032 +- src/thirdparty/BaseClasses/transfrm.h | 608 +- src/thirdparty/BaseClasses/transip.cpp | 1954 +- src/thirdparty/BaseClasses/transip.h | 500 +- src/thirdparty/BaseClasses/videoctl.cpp | 1490 +- src/thirdparty/BaseClasses/videoctl.h | 336 +- src/thirdparty/BaseClasses/vtrans.cpp | 938 +- src/thirdparty/BaseClasses/vtrans.h | 286 +- src/thirdparty/BaseClasses/winctrl.cpp | 4162 +- src/thirdparty/BaseClasses/winctrl.h | 448 +- src/thirdparty/BaseClasses/winutil.cpp | 5518 +- src/thirdparty/BaseClasses/winutil.h | 842 +- src/thirdparty/BaseClasses/wxdebug.cpp | 2950 +- src/thirdparty/BaseClasses/wxdebug.h | 718 +- src/thirdparty/BaseClasses/wxlist.cpp | 1782 +- src/thirdparty/BaseClasses/wxlist.h | 1106 +- src/thirdparty/BaseClasses/wxutil.cpp | 1544 +- src/thirdparty/BaseClasses/wxutil.h | 1064 +- src/thirdparty/LAVFilters/LAVFilters.vcxproj | 98 +- .../LAVFilters/build_lavfilters.bat | 446 +- src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp | 292 +- src/thirdparty/LCDUI/LCDAnimatedBitmap.h | 114 +- src/thirdparty/LCDUI/LCDBase.cpp | 770 +- src/thirdparty/LCDUI/LCDBase.h | 194 +- src/thirdparty/LCDUI/LCDBitmap.cpp | 358 +- src/thirdparty/LCDUI/LCDBitmap.h | 108 +- src/thirdparty/LCDUI/LCDCollection.cpp | 466 +- src/thirdparty/LCDUI/LCDCollection.h | 102 +- src/thirdparty/LCDUI/LCDColorProgressBar.cpp | 406 +- src/thirdparty/LCDUI/LCDColorProgressBar.h | 104 +- src/thirdparty/LCDUI/LCDColorText.cpp | 602 +- src/thirdparty/LCDUI/LCDColorText.h | 126 +- src/thirdparty/LCDUI/LCDConnection.cpp | 1446 +- src/thirdparty/LCDUI/LCDConnection.h | 322 +- src/thirdparty/LCDUI/LCDGfxBase.cpp | 600 +- src/thirdparty/LCDUI/LCDGfxBase.h | 190 +- src/thirdparty/LCDUI/LCDGfxColor.cpp | 188 +- src/thirdparty/LCDUI/LCDGfxColor.h | 96 +- src/thirdparty/LCDUI/LCDGfxMono.cpp | 216 +- src/thirdparty/LCDUI/LCDGfxMono.h | 98 +- src/thirdparty/LCDUI/LCDIcon.cpp | 172 +- src/thirdparty/LCDUI/LCDIcon.h | 100 +- src/thirdparty/LCDUI/LCDOutput.cpp | 1308 +- src/thirdparty/LCDUI/LCDOutput.h | 214 +- src/thirdparty/LCDUI/LCDPage.cpp | 448 +- src/thirdparty/LCDUI/LCDPage.h | 116 +- src/thirdparty/LCDUI/LCDPaginateText.cpp | 548 +- src/thirdparty/LCDUI/LCDPaginateText.h | 126 +- src/thirdparty/LCDUI/LCDPopup.cpp | 1112 +- src/thirdparty/LCDUI/LCDPopup.h | 200 +- src/thirdparty/LCDUI/LCDProgressBar.cpp | 526 +- src/thirdparty/LCDUI/LCDProgressBar.h | 144 +- src/thirdparty/LCDUI/LCDScrollingText.cpp | 612 +- src/thirdparty/LCDUI/LCDScrollingText.h | 150 +- .../LCDUI/LCDSkinnedProgressBar.cpp | 646 +- src/thirdparty/LCDUI/LCDSkinnedProgressBar.h | 166 +- src/thirdparty/LCDUI/LCDStreamingText.cpp | 1510 +- src/thirdparty/LCDUI/LCDStreamingText.h | 240 +- src/thirdparty/LCDUI/LCDText.cpp | 934 +- src/thirdparty/LCDUI/LCDText.h | 164 +- src/thirdparty/LCDUI/LCDUI.h | 184 +- src/thirdparty/LCDUI/LCDUI.vcxproj | 212 +- src/thirdparty/LCDUI/LCDUI.vcxproj.filters | 284 +- src/thirdparty/LCDUI/stdafx.cpp | 42 +- .../MessageBoxDialog/MessageBoxDialog.cpp | 2146 +- .../MessageBoxDialog/MessageBoxDialog.h | 376 +- src/thirdparty/MessageBoxDialog/lgpl-2.1.txt | 962 +- src/thirdparty/MessageBoxDialog/mpl-1.1.txt | 940 +- src/thirdparty/RARFileSource/File.h | 24 +- src/thirdparty/RARFileSource/OutputPin.h | 2 +- .../RARFileSource/RARFileSource.vcxproj | 186 +- .../RARFileSource.vcxproj.filters | 134 +- .../ResizableLib/ResizableDialog.cpp | 332 +- src/thirdparty/ResizableLib/ResizableDialog.h | 206 +- src/thirdparty/ResizableLib/ResizableGrip.cpp | 636 +- src/thirdparty/ResizableLib/ResizableGrip.h | 188 +- .../ResizableLib/ResizableLayout.cpp | 1840 +- src/thirdparty/ResizableLib/ResizableLayout.h | 632 +- .../ResizableLib/ResizableLib.vcxproj | 160 +- .../ResizableLib/ResizableLib.vcxproj.filters | 176 +- .../ResizableLib/ResizableMinMax.cpp | 422 +- src/thirdparty/ResizableLib/ResizableMinMax.h | 164 +- .../ResizableLib/ResizableMsgSupport.h | 208 +- src/thirdparty/ResizableLib/ResizablePage.cpp | 238 +- src/thirdparty/ResizableLib/ResizablePage.h | 164 +- .../ResizableLib/ResizableSheet.cpp | 952 +- src/thirdparty/ResizableLib/ResizableSheet.h | 242 +- .../ResizableLib/ResizableState.cpp | 264 +- src/thirdparty/ResizableLib/ResizableState.h | 154 +- src/thirdparty/ResizableLib/stdafx.cpp | 12 +- src/thirdparty/ResizableLib/stdafx.h | 136 +- .../TreePropSheet/PropPageFrame.cpp | 374 +- src/thirdparty/TreePropSheet/PropPageFrame.h | 612 +- .../TreePropSheet/PropPageFrameDefault.cpp | 820 +- .../TreePropSheet/PropPageFrameDefault.h | 234 +- .../TreePropSheet/TreePropSheet.cpp | 2000 +- src/thirdparty/TreePropSheet/TreePropSheet.h | 974 +- .../TreePropSheet/TreePropSheet.vcxproj | 128 +- .../TreePropSheet.vcxproj.filters | 80 +- src/thirdparty/TreePropSheet/stdafx.cpp | 44 +- src/thirdparty/TreePropSheet/stdafx.h | 68 +- .../VirtualDub/Kasumi/Kasumi.vcxproj | 398 +- .../VirtualDub/Kasumi/Kasumi.vcxproj.filters | 646 +- src/thirdparty/VirtualDub/Kasumi/h/bitutils.h | 52 +- .../VirtualDub/Kasumi/h/blt_setup.h | 124 +- .../VirtualDub/Kasumi/h/blt_spanutils.h | 46 +- .../VirtualDub/Kasumi/h/blt_spanutils_x86.h | 70 +- .../VirtualDub/Kasumi/h/resample_stages.h | 160 +- .../Kasumi/h/resample_stages_reference.h | 312 +- .../VirtualDub/Kasumi/h/resample_stages_x64.h | 52 +- .../VirtualDub/Kasumi/h/resample_stages_x86.h | 386 +- src/thirdparty/VirtualDub/Kasumi/h/stdafx.h | 42 +- src/thirdparty/VirtualDub/Kasumi/h/uberblit.h | 190 +- .../VirtualDub/Kasumi/h/uberblit_16f.h | 78 +- .../VirtualDub/Kasumi/h/uberblit_base.h | 258 +- .../VirtualDub/Kasumi/h/uberblit_fill.h | 110 +- .../VirtualDub/Kasumi/h/uberblit_gen.h | 354 +- .../VirtualDub/Kasumi/h/uberblit_input.h | 138 +- .../VirtualDub/Kasumi/h/uberblit_interlace.h | 246 +- .../VirtualDub/Kasumi/h/uberblit_pal.h | 296 +- .../VirtualDub/Kasumi/h/uberblit_resample.h | 166 +- .../Kasumi/h/uberblit_resample_special.h | 162 +- .../Kasumi/h/uberblit_resample_special_x86.h | 52 +- .../VirtualDub/Kasumi/h/uberblit_rgb.h | 1104 +- .../VirtualDub/Kasumi/h/uberblit_rgb_x86.h | 228 +- .../VirtualDub/Kasumi/h/uberblit_swizzle.h | 686 +- .../Kasumi/h/uberblit_swizzle_x86.h | 142 +- .../VirtualDub/Kasumi/h/uberblit_v210.h | 144 +- .../VirtualDub/Kasumi/h/uberblit_ycbcr.h | 1200 +- .../Kasumi/h/uberblit_ycbcr_generic.h | 308 +- .../VirtualDub/Kasumi/h/uberblit_ycbcr_x86.h | 54 +- .../Kasumi/source/a64_resample.asm64 | 1240 +- .../VirtualDub/Kasumi/source/a_bltrgb.asm | 1624 +- .../Kasumi/source/a_bltrgb2yuv_mmx.asm | 1302 +- .../VirtualDub/Kasumi/source/a_bltrgb_mmx.asm | 1612 +- .../Kasumi/source/a_bltyuv2rgb_sse2.asm | 322 +- .../Kasumi/source/a_resample_mmx.asm | 3118 +- .../Kasumi/source/a_resample_sse41.asm | 716 +- .../Kasumi/source/a_spanutils_isse.asm | 386 +- .../Kasumi/source/a_stretchrgb_mmx.asm | 652 +- .../Kasumi/source/a_stretchrgb_point.asm | 192 +- .../VirtualDub/Kasumi/source/a_triblt.inc | 48 +- .../VirtualDub/Kasumi/source/a_triblt_mmx.asm | 850 +- .../Kasumi/source/a_triblt_scalar.asm | 70 +- .../Kasumi/source/a_triblt_sse2.asm | 394 +- .../VirtualDub/Kasumi/source/alphablt.cpp | 190 +- .../VirtualDub/Kasumi/source/blitter.cpp | 104 +- .../VirtualDub/Kasumi/source/blt.cpp | 584 +- .../Kasumi/source/blt_reference.cpp | 688 +- .../Kasumi/source/blt_reference_pal.cpp | 1128 +- .../Kasumi/source/blt_reference_rgb.cpp | 658 +- .../Kasumi/source/blt_reference_yuv.cpp | 3220 +- .../Kasumi/source/blt_reference_yuv2yuv.cpp | 558 +- .../Kasumi/source/blt_reference_yuvrev.cpp | 1098 +- .../VirtualDub/Kasumi/source/blt_setup.cpp | 72 +- .../Kasumi/source/blt_spanutils.cpp | 768 +- .../Kasumi/source/blt_spanutils_x86.cpp | 342 +- .../VirtualDub/Kasumi/source/blt_uberblit.cpp | 76 +- .../VirtualDub/Kasumi/source/blt_x86.cpp | 326 +- .../VirtualDub/Kasumi/source/pixel.cpp | 1884 +- .../VirtualDub/Kasumi/source/pixmaputils.cpp | 1266 +- .../VirtualDub/Kasumi/source/region.cpp | 2750 +- .../VirtualDub/Kasumi/source/resample.cpp | 832 +- .../Kasumi/source/resample_kernels.cpp | 584 +- .../Kasumi/source/resample_stages.cpp | 336 +- .../source/resample_stages_reference.cpp | 888 +- .../Kasumi/source/resample_stages_x64.cpp | 54 +- .../Kasumi/source/resample_stages_x86.cpp | 2592 +- .../VirtualDub/Kasumi/source/stdafx.cpp | 36 +- .../Kasumi/source/stretchblt_reference.cpp | 1670 +- .../VirtualDub/Kasumi/source/tables.cpp | 410 +- .../VirtualDub/Kasumi/source/triblt.cpp | 3520 +- .../VirtualDub/Kasumi/source/uberblit.cpp | 2832 +- .../VirtualDub/Kasumi/source/uberblit_16f.cpp | 118 +- .../VirtualDub/Kasumi/source/uberblit_gen.cpp | 3458 +- .../Kasumi/source/uberblit_resample.cpp | 1284 +- .../source/uberblit_resample_special.cpp | 410 +- .../source/uberblit_resample_special_x86.cpp | 108 +- .../Kasumi/source/uberblit_swizzle.cpp | 216 +- .../Kasumi/source/uberblit_swizzle_x86.cpp | 838 +- .../Kasumi/source/uberblit_v210.cpp | 436 +- .../Kasumi/source/uberblit_ycbcr_generic.cpp | 1090 +- .../Kasumi/source/uberblit_ycbcr_x86.cpp | 108 +- .../VirtualDub/h/vd2/Kasumi/blitter.h | 78 +- .../VirtualDub/h/vd2/Kasumi/pixel.h | 80 +- .../VirtualDub/h/vd2/Kasumi/pixmap.h | 218 +- .../VirtualDub/h/vd2/Kasumi/pixmapops.h | 40 +- .../VirtualDub/h/vd2/Kasumi/pixmaputils.h | 342 +- .../VirtualDub/h/vd2/Kasumi/region.h | 186 +- .../VirtualDub/h/vd2/Kasumi/resample.h | 62 +- .../h/vd2/Kasumi/resample_kernels.h | 182 +- .../VirtualDub/h/vd2/Kasumi/tables.h | 82 +- src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h | 152 +- .../VirtualDub/h/vd2/Kasumi/triblt.h | 144 +- .../VirtualDub/h/vd2/system/Error.h | 250 +- .../VirtualDub/h/vd2/system/Fraction.h | 190 +- .../VirtualDub/h/vd2/system/VDNamespace.h | 314 +- .../VirtualDub/h/vd2/system/VDQueue.h | 180 +- .../VirtualDub/h/vd2/system/VDRingBuffer.h | 602 +- .../VirtualDub/h/vd2/system/VDScheduler.h | 294 +- .../VirtualDub/h/vd2/system/VDString.h | 2528 +- .../VirtualDub/h/vd2/system/atomic.h | 752 +- .../VirtualDub/h/vd2/system/binary.h | 362 +- .../VirtualDub/h/vd2/system/bitmath.h | 190 +- .../VirtualDub/h/vd2/system/cache.h | 650 +- .../VirtualDub/h/vd2/system/cmdline.h | 168 +- .../VirtualDub/h/vd2/system/cpuaccel.h | 102 +- .../VirtualDub/h/vd2/system/debug.h | 192 +- .../VirtualDub/h/vd2/system/debugx86.h | 74 +- .../VirtualDub/h/vd2/system/event.h | 398 +- src/thirdparty/VirtualDub/h/vd2/system/file.h | 654 +- .../VirtualDub/h/vd2/system/fileasync.h | 134 +- .../VirtualDub/h/vd2/system/halffloat.h | 18 +- src/thirdparty/VirtualDub/h/vd2/system/hash.h | 102 +- .../VirtualDub/h/vd2/system/int128.h | 750 +- .../VirtualDub/h/vd2/system/linearalloc.h | 176 +- src/thirdparty/VirtualDub/h/vd2/system/list.h | 550 +- src/thirdparty/VirtualDub/h/vd2/system/math.h | 538 +- .../VirtualDub/h/vd2/system/memory.h | 168 +- .../VirtualDub/h/vd2/system/progress.h | 192 +- .../VirtualDub/h/vd2/system/protscope.h | 490 +- .../VirtualDub/h/vd2/system/refcount.h | 694 +- .../VirtualDub/h/vd2/system/registry.h | 310 +- .../VirtualDub/h/vd2/system/registrymemory.h | 162 +- .../h/vd2/system/source/registrymemory.cpp | 1338 +- .../VirtualDub/h/vd2/system/strutil.h | 120 +- src/thirdparty/VirtualDub/h/vd2/system/text.h | 120 +- .../VirtualDub/h/vd2/system/thread.h | 570 +- .../VirtualDub/h/vd2/system/thunk.h | 152 +- src/thirdparty/VirtualDub/h/vd2/system/tls.h | 76 +- .../VirtualDub/h/vd2/system/unknown.h | 154 +- .../VirtualDub/h/vd2/system/vdalloc.h | 380 +- .../VirtualDub/h/vd2/system/vdstl.h | 3528 +- .../VirtualDub/h/vd2/system/vdstl_hash.h | 280 +- .../VirtualDub/h/vd2/system/vdstl_hashmap.h | 1208 +- .../VirtualDub/h/vd2/system/vdstl_hashset.h | 1052 +- .../VirtualDub/h/vd2/system/vdstl_hashtable.h | 730 +- .../VirtualDub/h/vd2/system/vdstl_vector.h | 1212 +- .../VirtualDub/h/vd2/system/vdtypes.h | 898 +- .../VirtualDub/h/vd2/system/vectors.h | 1232 +- .../VirtualDub/h/vd2/system/vectors_float.h | 414 +- .../VirtualDub/h/vd2/system/vectors_int.h | 366 +- .../VirtualDub/h/vd2/system/w32assist.h | 214 +- .../VirtualDub/h/vd2/system/win32/intrin.h | 112 +- .../h/vd2/system/win32/miniwindows.h | 122 +- src/thirdparty/VirtualDub/system/h/stdafx.h | 72 +- .../VirtualDub/system/source/Error.cpp | 298 +- .../VirtualDub/system/source/Fraction.cpp | 654 +- .../VirtualDub/system/source/VDNamespace.cpp | 506 +- .../VirtualDub/system/source/VDScheduler.cpp | 644 +- .../VirtualDub/system/source/VDString.cpp | 592 +- .../VirtualDub/system/source/a64_cpuaccel.asm | 84 +- .../VirtualDub/system/source/a64_fraction.asm | 116 +- .../VirtualDub/system/source/a64_int128.asm | 146 +- .../VirtualDub/system/source/a64_thunk.asm | 116 +- .../VirtualDub/system/source/a_memory.asm | 394 +- .../VirtualDub/system/source/a_thunk.asm | 126 +- .../VirtualDub/system/source/cache.cpp | 844 +- .../VirtualDub/system/source/cmdline.cpp | 548 +- .../VirtualDub/system/source/cpuaccel.cpp | 376 +- .../VirtualDub/system/source/debug.cpp | 580 +- .../VirtualDub/system/source/debugx86.cpp | 312 +- .../VirtualDub/system/source/event.cpp | 176 +- .../VirtualDub/system/source/file.cpp | 860 +- .../VirtualDub/system/source/fileasync.cpp | 1850 +- .../VirtualDub/system/source/filewatcher.cpp | 314 +- .../VirtualDub/system/source/halffloat.cpp | 158 +- .../VirtualDub/system/source/hash.cpp | 246 +- .../VirtualDub/system/source/int128.cpp | 1330 +- .../VirtualDub/system/source/list.cpp | 194 +- .../VirtualDub/system/source/math.cpp | 370 +- .../VirtualDub/system/source/memory.cpp | 944 +- .../VirtualDub/system/source/progress.cpp | 70 +- .../VirtualDub/system/source/protscope.cpp | 74 +- .../VirtualDub/system/source/refcount.cpp | 58 +- .../VirtualDub/system/source/registry.cpp | 960 +- .../VirtualDub/system/source/stdaccel.cpp | 84 +- .../VirtualDub/system/source/stdafx.cpp | 92 +- .../VirtualDub/system/source/strutil.cpp | 198 +- .../VirtualDub/system/source/text.cpp | 1306 +- .../VirtualDub/system/source/thread.cpp | 624 +- .../VirtualDub/system/source/thunk.cpp | 616 +- .../VirtualDub/system/source/tls.cpp | 86 +- .../VirtualDub/system/source/vdstl.cpp | 74 +- .../VirtualDub/system/source/vdstl_hash.cpp | 218 +- .../system/source/vdstl_hashtable.cpp | 164 +- .../VirtualDub/system/source/vectors.cpp | 166 +- .../VirtualDub/system/source/w32assist.cpp | 1420 +- .../VirtualDub/system/system.vcxproj | 354 +- .../VirtualDub/system/system.vcxproj.filters | 662 +- .../XeScrollBar/XeScrollBarBase.cpp | 2858 +- src/thirdparty/XeScrollBar/xescrollbarbase.h | 798 +- src/thirdparty/lcms2/lcms2.vcxproj | 174 +- src/thirdparty/lcms2/lcms2.vcxproj.filters | 212 +- src/thirdparty/sizecbar/scbarcf.cpp | 468 +- src/thirdparty/sizecbar/scbarcf.h | 156 +- src/thirdparty/sizecbar/scbarg.cpp | 510 +- src/thirdparty/sizecbar/scbarg.h | 236 +- src/thirdparty/sizecbar/sizecbar.cpp | 2926 +- src/thirdparty/sizecbar/sizecbar.h | 514 +- src/thirdparty/sizecbar/sizecbar.vcxproj | 132 +- .../sizecbar/sizecbar.vcxproj.filters | 80 +- src/thirdparty/sizecbar/stdafx.cpp | 44 +- src/thirdparty/sizecbar/stdafx.h | 66 +- src/thirdparty/unrar/acknow.txt | 118 +- src/thirdparty/unrar/dll.def | 26 +- src/thirdparty/unrar/dll.rc | 46 +- src/thirdparty/unrar/unrar.vcxproj | 344 +- src/thirdparty/unrar/unrar.vcxproj.filters | 728 +- src/thirdparty/zlib/zlib.vcxproj | 166 +- src/thirdparty/zlib/zlib.vcxproj.filters | 200 +- update_version.bat | 102 +- 1081 files changed, 328060 insertions(+), 328060 deletions(-) diff --git a/build.bat b/build.bat index 455b1368b2d..fa2d8feb75f 100755 --- a/build.bat +++ b/build.bat @@ -1,522 +1,522 @@ -@ECHO OFF -REM (C) 2009-2019 see Authors.txt -REM -REM This file is part of MPC-HC. -REM -REM MPC-HC is free software; you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation; either version 3 of the License, or -REM (at your option) any later version. -REM -REM MPC-HC is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with this program. If not, see . - - -SETLOCAL EnableDelayedExpansion - -SET ARG=/%* -SET ARG=%ARG:/=% -SET ARG=%ARG:-=% -SET ARGB=0 -SET ARGBC=0 -SET ARGC=0 -SET ARGPL=0 -SET INPUT=0 -SET VALID=0 - -IF /I "%ARG%" == "?" GOTO ShowHelp - -FOR %%G IN (%ARG%) DO ( - IF /I "%%G" == "help" GOTO ShowHelp - IF /I "%%G" == "GetVersion" ENDLOCAL & SET "FORCE_VER_UPDATE=True" & CALL "%~dp0common.bat" :SubGetVersion & EXIT /B - IF /I "%%G" == "Build" SET "BUILDTYPE=Build" & SET /A ARGB+=1 - IF /I "%%G" == "Clean" SET "BUILDTYPE=Clean" & SET /A ARGB+=1 & SET "NO_INST=True" & SET /A "NO_ZIP=True" & SET "NO_LAV=True" - IF /I "%%G" == "Rebuild" SET "BUILDTYPE=Rebuild" & SET /A ARGB+=1 & SET "NO_LAV=True" - IF /I "%%G" == "Both" SET "PPLATFORM=Both" & SET /A ARGPL+=1 - IF /I "%%G" == "Win32" SET "PPLATFORM=Win32" & SET /A ARGPL+=1 - IF /I "%%G" == "x86" SET "PPLATFORM=Win32" & SET /A ARGPL+=1 - IF /I "%%G" == "x64" SET "PPLATFORM=x64" & SET /A ARGPL+=1 - IF /I "%%G" == "All" SET "CONFIG=All" & SET /A ARGC+=1 & SET "NO_LITE=True" - IF /I "%%G" == "Main" SET "CONFIG=Main" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" - IF /I "%%G" == "Filters" SET "CONFIG=Filters" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_LITE=True" - IF /I "%%G" == "Filter" SET "CONFIG=Filters" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_LITE=True" - IF /I "%%G" == "API" SET "CONFIG=API" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "MPCHC" SET "CONFIG=MPCHC" & SET /A ARGC+=1 - IF /I "%%G" == "MPC-HC" SET "CONFIG=MPCHC" & SET /A ARGC+=1 - IF /I "%%G" == "Resources" SET "CONFIG=Resources" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "MPCIconLib" SET "CONFIG=IconLib" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "IconLib" SET "CONFIG=IconLib" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "Translations" SET "CONFIG=Translation" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" - IF /I "%%G" == "Debug" SET "BUILDCFG=Debug" & SET /A ARGBC+=1 & SET "NO_INST=True" - IF /I "%%G" == "Release" SET "BUILDCFG=Release" & SET /A ARGBC+=1 - IF /I "%%G" == "Packages" SET "PACKAGES=True" & SET /A VALID+=1 - IF /I "%%G" == "Installer" SET "INSTALLER=True" & SET /A VALID+=1 - IF /I "%%G" == "7z" SET "ZIP=True" & SET /A VALID+=1 - IF /I "%%G" == "Lite" SET "MPCHC_LITE=True" & SET /A VALID+=1 - IF /I "%%G" == "LAVFilters" SET "CLEAN=LAVFilters" & SET /A VALID+=1 - IF /I "%%G" == "Silent" SET "SILENT=True" & SET /A VALID+=1 - IF /I "%%G" == "Nocolors" SET "NOCOLORS=True" & SET /A VALID+=1 - IF /I "%%G" == "Analyze" SET "ANALYZE=True" & SET /A VALID+=1 - IF /I "%%G" == "MINGWLIB" ENDLOCAL & SET "FORCE_MINGW_UPDATE=True" & CALL "%~dp0common.bat" :SubMINGWLIB & EXIT /B -) - -SET "FILE_DIR=%~dp0" -PUSHD "%FILE_DIR%" - -SET "COMMON=%FILE_DIR%\common.bat" - -CALL "%COMMON%" :SubPreBuild -IF %ERRORLEVEL% NEQ 0 GOTO MissingVar - -FOR %%G IN (%*) DO SET /A INPUT+=1 -SET /A VALID+=%ARGB%+%ARGPL%+%ARGC%+%ARGBC% -IF %VALID% NEQ %INPUT% GOTO UnsupportedSwitch - -IF %ARGB% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGB% == 0 (SET "BUILDTYPE=Build") -IF %ARGPL% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGPL% == 0 (SET "PPLATFORM=Both") -IF %ARGC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGC% == 0 (SET "CONFIG=MPCHC") -IF %ARGBC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGBC% == 0 (SET "BUILDCFG=Release") - -IF /I "%PACKAGES%" == "True" SET "INSTALLER=True" & SET "ZIP=True" - -IF /I "%INSTALLER%" == "True" IF "%NO_INST%" == "True" GOTO UnsupportedSwitch -IF /I "%ZIP%" == "True" IF "%NO_ZIP%" == "True" GOTO UnsupportedSwitch -IF /I "%MPCHC_LITE%" == "True" IF "%NO_LITE%" == "True" GOTO UnsupportedSwitch -IF /I "%CLEAN%" == "LAVFilters" IF "%NO_LAV%" == "True" GOTO UnsupportedSwitch - -IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath -IF NOT EXIST "!MPCHC_VS_PATH!" GOTO MissingVar -SET "TOOLSET=!MPCHC_VS_PATH!\Common7\Tools\vsdevcmd" -SET "BIN_DIR=bin" -IF NOT EXIST "%TOOLSET%" GOTO MissingVar - -IF EXIST "%FILE_DIR%signinfo.txt" ( - IF /I "%INSTALLER%" == "True" SET "SIGN=True" - IF /I "%ZIP%" == "True" SET "SIGN=True" -) - -REM Set version for DX libraries -CALL "%COMMON%" :SubParseConfig - -:Start -REM Check if the %LOG_DIR% folder exists otherwise MSBuild will fail -SET "LOG_DIR=%BIN_DIR%\logs" -IF NOT EXIST "%LOG_DIR%" MD "%LOG_DIR%" - -IF DEFINED MPCHC_LITE SET "BUILDCFG=%BUILDCFG% Lite" - -SET "MSBUILD_SWITCHES=/nologo /consoleloggerparameters:Verbosity=minimal /maxcpucount /nodeReuse:true" - -SET START_TIME=%TIME% -SET START_DATE=%DATE% - -IF /I "%PPLATFORM%" == "Both" ( - SET "PPLATFORM=Win32" & CALL :Main - SET "PPLATFORM=x64" & CALL :Main -) ELSE ( - CALL :Main -) -GOTO End - - -:Main -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%PPLATFORM%" == "x64" ( - SET "LAVFILTERSDIR=LAVFilters64" -) ELSE ( - SET "LAVFILTERSDIR=LAVFilters" -) - -IF /I "%CLEAN%" == "LAVFilters" CALL "src\thirdparty\LAVFilters\build_lavfilters.bat" Clean %PPLATFORM% %BUILDCFG% %COMPILER% -IF %ERRORLEVEL% NEQ 0 ENDLOCAL & EXIT /B - -IF /I "%PPLATFORM%" == "Win32" (SET ARCH=x86) ELSE (SET ARCH=amd64) -CALL "%TOOLSET%" -no_logo -arch=%ARCH% -winsdk=%MPCHC_WINSDK_VER% -IF %ERRORLEVEL% NEQ 0 GOTO MissingVar - -IF /I "%CONFIG%" == "Filters" ( - CALL :SubFilters %PPLATFORM% - IF /I "%ZIP%" == "True" CALL :SubCreatePackages Filters %PPLATFORM% - EXIT /B -) - -IF /I "%CONFIG%" == "IconLib" ( - CALL :SubMPCIconLib %PPLATFORM% - EXIT /B -) - -IF /I "%CONFIG%" == "Translation" ( - CALL :SubMPCRresources %PPLATFORM% - EXIT /B -) - -IF /I "%CONFIG%" == "API" ( - CALL :SubMPCTestAPI %PPLATFORM% - EXIT /B -) - -IF /I "%CONFIG%" NEQ "Resources" CALL :SubMPCHC %PPLATFORM% -IF /I "%CONFIG%" NEQ "Main" CALL :SubResources %PPLATFORM% - -IF /I "%INSTALLER%" == "True" CALL :SubCreateInstaller %PPLATFORM% -IF /I "%ZIP%" == "True" CALL :SubCreatePackages MPC-HC %PPLATFORM% - -IF /I "%CONFIG%" == "All" ( - CALL :SubFilters %PPLATFORM% - IF /I "%ZIP%" == "True" CALL :SubCreatePackages Filters %PPLATFORM% -) -EXIT /B - - -:End -IF %ERRORLEVEL% NEQ 0 EXIT /B -TITLE Compiling MPC-HC %COMPILER% [FINISHED] -SET END_TIME=%TIME% -CALL "%COMMON%" :SubGetDuration -CALL "%COMMON%" :SubMsg "INFO" "Compilation started on %START_DATE%-%START_TIME% and completed on %DATE%-%END_TIME% [%DURATION%]" -ENDLOCAL -EXIT /B - - -:SubFilters -IF %ERRORLEVEL% NEQ 0 EXIT /B - -TITLE Compiling MPC-HC Filters %COMPILER% - %BUILDCFG% Filter^|%1... -CALL "update_version.bat" - -MSBuild.exe mpc-hc.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration="%BUILDCFG% Filter";Platform=%1^ - /flp1:LogFile=%LOG_DIR%\filters_errors_%BUILDCFG%_%1.log;errorsonly;Verbosity=diagnostic^ - /flp2:LogFile=%LOG_DIR%\filters_warnings_%BUILDCFG%_%1.log;warningsonly;Verbosity=diagnostic -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "mpc-hc.sln %BUILDCFG% Filter %1 - Compilation failed!" - EXIT /B -) ELSE ( - CALL "%COMMON%" :SubMsg "INFO" "mpc-hc.sln %BUILDCFG% Filter %1 compiled successfully" -) -IF /I "%SIGN%" == "True" CALL :SubSign Filters *.ax -IF /I "%SIGN%" == "True" CALL :SubSign Filters VSFilter.dll -EXIT /B - - -:SubMPCHC -IF %ERRORLEVEL% NEQ 0 EXIT /B - -TITLE Compiling MPC-HC %COMPILER% - %BUILDCFG%^|%1... -CALL "update_version.bat" - -MSBuild.exe mpc-hc.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration="%BUILDCFG%";Platform=%1^ - /flp1:LogFile="%LOG_DIR%\mpc-hc_errors_%BUILDCFG%_%1.log";errorsonly;Verbosity=diagnostic^ - /flp2:LogFile="%LOG_DIR%\mpc-hc_warnings_%BUILDCFG%_%1.log";warningsonly;Verbosity=diagnostic -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "mpc-hc.sln %BUILDCFG% %1 - Compilation failed!" - EXIT /B -) ELSE ( - CALL "%COMMON%" :SubMsg "INFO" "mpc-hc.sln %BUILDCFG% %1 compiled successfully" -) -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpc-hc*.exe -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC *.dll %LAVFILTERSDIR% -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC *.ax %LAVFILTERSDIR% -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC CrashReporterDialog.dll CrashReporter - -EXIT /B - - -:SubResources -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%BUILDCFG%" == "Debug" ( - CALL "%COMMON%" :SubMsg "WARNING" "/debug was used, resources will not be built" - EXIT /B -) - -CALL :SubMPCIconLib %1 - -IF DEFINED MPCHC_LITE ( - CALL "%COMMON%" :SubMsg "WARNING" "/lite was used, translations will not be built" - EXIT /B -) - -CALL :SubMPCRresources %1 -EXIT /B - - -:SubMPCIconLib -IF %ERRORLEVEL% NEQ 0 EXIT /B - -TITLE Compiling mpciconlib %COMPILER% - Release^|%1... -MSBuild.exe mpciconlib.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration=Release;Platform=%1 -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "mpciconlib.sln %1 - Compilation failed!" - EXIT /B -) ELSE ( - CALL "%COMMON%" :SubMsg "INFO" "mpciconlib.sln %1 compiled successfully" -) -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpciconlib.dll - -IF /I "%1" == "Win32" (SET "VS_OUT_DIR=mpc-hc_x86") ELSE (SET "VS_OUT_DIR=mpc-hc_x64") -IF DEFINED MPCHC_LITE ( - PUSHD "%BIN_DIR%" - COPY /Y /V "%VS_OUT_DIR%\mpciconlib.dll" "%VS_OUT_DIR% Lite" >NUL - POPD -) - -EXIT /B - - -:SubMPCRresources -IF %ERRORLEVEL% NEQ 0 EXIT /B - -TITLE Compiling mpcresources %COMPILER%... -MSBuild.exe mpcresources.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration="Release";Platform=%1 -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpcresources.??.dll Lang -IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpcresources.??_??.dll Lang -EXIT /B - - -:SubMPCTestAPI -IF %ERRORLEVEL% NEQ 0 EXIT /B - -PUSHD "src\MPCTestAPI" -TITLE Compiling MPCTestAPI %COMPILER% - %BUILDCFG%^|%1... -MSBuild.exe MPCTestAPI.sln %MSBUILD_SWITCHES%^ - /target:%BUILDTYPE% /property:Configuration=%BUILDCFG%;Platform=%1 -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "MPCTestAPI.sln %1 - Compilation failed!" - EXIT /B -) ELSE ( - CALL "%COMMON%" :SubMsg "INFO" "MPCTestAPI.sln %1 compiled successfully" -) -POPD -EXIT /B - - -:SubSign -IF %ERRORLEVEL% NEQ 0 EXIT /B -REM %1 is Filters or MPC-HC -REM %2 is name of the file to sign -REM %3 is the subfolder - -IF /I "%PPLATFORM%" == "Win32" PUSHD "%BIN_DIR%\%~1_x86\%3" -IF /I "%PPLATFORM%" == "x64" PUSHD "%BIN_DIR%\%~1_x64\%3" - -FOR /F "delims=" %%A IN ('DIR "%2" /b') DO ( - CALL "%FILE_DIR%contrib\sign.bat" "%%A" || (CALL "%COMMON%" :SubMsg "ERROR" "Problem signing %%A" & GOTO Break) -) -CALL "%COMMON%" :SubMsg "INFO" "%2 signed successfully." - -:Break -POPD -EXIT /B - - -:SubCopyDXDll -REM SubCopyDXDll skipped -EXIT /B -IF /I "%BUILDCFG%" == "Debug" EXIT /B -PUSHD "%BIN_DIR%" -COPY /Y /V "%WindowsSdkDir%\Redist\D3D\%~1\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" "mpc-hc_%~1%~2" >NUL -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Problem when copying %WindowsSdkDir%\Redist\D3D\%~1\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" & EXIT /B -EXPAND "%DXSDK_DIR%\Redist\Jun2010_d3dx9_%MPC_DX_SDK_NUMBER%_%~1.cab" -F:d3dx9_%MPC_DX_SDK_NUMBER%.dll "mpc-hc_%~1%~2" -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Problem when extracting Jun2010_d3dx9_%MPC_DX_SDK_NUMBER%_%~1.cab" & EXIT /B -POPD -EXIT /B - - -:SubCreateInstaller -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%~1" == "x64" ( - SET MPCHC_INNO_DEF=%MPCHC_INNO_DEF% /Dx64Build - SET MPCHC_COPY_DX_DLL_ARGS=x64 -) ELSE SET MPCHC_COPY_DX_DLL_ARGS=x86 - - -IF DEFINED MPCHC_LITE ( - SET MPCHC_INNO_DEF=%MPCHC_INNO_DEF% /DMPCHC_LITE - SET MPCHC_COPY_DX_DLL_ARGS=%MPCHC_COPY_DX_DLL_ARGS% " Lite" -) - -CALL :SubCopyDXDll %MPCHC_COPY_DX_DLL_ARGS% - -CALL "%COMMON%" :SubDetectInnoSetup - -IF NOT DEFINED InnoSetupPath ( - CALL "%COMMON%" :SubMsg "WARNING" "Inno Setup wasn't found, the %1 installer wasn't built" - EXIT /B -) - -TITLE Compiling %1 %COMPILER% installer... -"%InnoSetupPath%" /SMySignTool="cmd /c "%FILE_DIR%contrib\sign.bat" $f" /Q /O"%BIN_DIR%"^ - "distrib\mpc-hc_setup.iss" %MPCHC_INNO_DEF% -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B -CALL "%COMMON%" :SubMsg "INFO" "%1 installer successfully built" - -EXIT /B - - -:SubCreatePackages -IF %ERRORLEVEL% NEQ 0 EXIT /B - -CALL "%COMMON%" :SubDetectSevenzipPath -CALL "%COMMON%" :SubGetVersion -CALL "%COMMON%" :SubMINGWLIB - -IF NOT DEFINED SEVENZIP ( - CALL "%COMMON%" :SubMsg "WARNING" "7-Zip wasn't found, the %1 %2 package wasn't built" - EXIT /B -) - -IF /I "%~1" == "Filters" (SET "NAME=MPC-HC_standalone_filters") ELSE (SET "NAME=MPC-HC") -IF /I "%~2" == "Win32" ( - SET ARCH=x86 -) ELSE ( - SET ARCH=x64 -) - -IF DEFINED MPCHC_LITE ( - CALL :SubCopyDXDll %ARCH% " Lite" -) ELSE IF /I "%NAME%" == "MPC-HC" ( - CALL :SubCopyDXDll %ARCH% -) - -PUSHD "%BIN_DIR%" - -SET "VS_OUT_DIR=%~1_%ARCH%" -SET "PCKG_NAME=%NAME%.%MPCHC_VER%.%ARCH%" -IF DEFINED MPCHC_LITE ( - SET "VS_OUT_DIR=%VS_OUT_DIR% Lite" - SET "PCKG_NAME=%PCKG_NAME%.Lite" -) -IF /I "%BUILDCFG%" == "Debug" ( - SET "PCKG_NAME=%PCKG_NAME%.dbg" - SET "VS_OUT_DIR=%VS_OUT_DIR%_Debug" -) - -IF EXIST "%PCKG_NAME%.7z" DEL "%PCKG_NAME%.7z" -IF EXIST "%PCKG_NAME%.pdb.7z" DEL "%PCKG_NAME%.pdb.7z" -IF EXIST "%PCKG_NAME%" RD /Q /S "%PCKG_NAME%" - -SET "PDB_FILES=*.pdb" -IF NOT DEFINED MPCHC_LITE (SET "PDB_FILES=%PDB_FILES% %LAVFILTERSDIR%\*.pdb") - -REM Compress the pdb file for mpc-hc only -IF /I "%NAME%" == "MPC-HC" ( - PUSHD "%VS_OUT_DIR%" - TITLE Creating archive %PCKG_NAME%.pdb.7z... - START "7z" /B /WAIT "%SEVENZIP%" a -t7z "%PCKG_NAME%.pdb.7z" %PDB_FILES% -m0=LZMA2^ - -mmt=%NUMBER_OF_PROCESSORS% -mx9 -ms=on - IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Unable to create %PCKG_NAME%.pdb.7z!" & EXIT /B - CALL "%COMMON%" :SubMsg "INFO" "%PCKG_NAME%.pdb.7z successfully created" - IF EXIST "%PCKG_NAME%.pdb.7z" MOVE /Y "%PCKG_NAME%.pdb.7z" ".." >NUL - POPD -) - -TITLE Copying %PCKG_NAME%... -IF NOT EXIST "%PCKG_NAME%" MD "%PCKG_NAME%" - -IF /I "%NAME%" == "MPC-HC" ( - IF NOT DEFINED MPCHC_LITE ( - IF /I "%BUILDCFG%" NEQ "Debug" ( - IF NOT EXIST "%PCKG_NAME%\Lang" MD "%PCKG_NAME%\Lang" - ) - IF NOT EXIST "%PCKG_NAME%\%LAVFILTERSDIR%" MD "%PCKG_NAME%\%LAVFILTERSDIR%" - ) - IF /I "%ARCH%" == "x64" ( - COPY /Y /V "%VS_OUT_DIR%\mpc-hc64.exe" "%PCKG_NAME%\mpc-hc64.exe" >NUL - ) ELSE ( - COPY /Y /V "%VS_OUT_DIR%\mpc-hc.exe" "%PCKG_NAME%\mpc-hc.exe" >NUL - ) - COPY /Y /V "%VS_OUT_DIR%\mpciconlib.dll" "%PCKG_NAME%\*.dll" >NUL - IF NOT DEFINED MPCHC_LITE ( - COPY /Y /V "%VS_OUT_DIR%\Lang\mpcresources.??.dll" "%PCKG_NAME%\Lang\" >NUL - COPY /Y /V "%VS_OUT_DIR%\Lang\mpcresources.??_??.dll" "%PCKG_NAME%\Lang\" >NUL - COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.ax" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL - COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.dll" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL - COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.manifest" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL - ) - COPY /Y /V "%VS_OUT_DIR%\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" "%PCKG_NAME%\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" >NUL - COPY /Y /V "%VS_OUT_DIR%\d3dx9_%MPC_DX_SDK_NUMBER%.dll" "%PCKG_NAME%\d3dx9_%MPC_DX_SDK_NUMBER%.dll" >NUL - IF NOT EXIST "%PCKG_NAME%\Shaders" MD "%PCKG_NAME%\Shaders" - COPY /Y /V "..\src\mpc-hc\res\shaders\dx9\*.hlsl" "%PCKG_NAME%\Shaders" >NUL - IF NOT EXIST "%PCKG_NAME%\Shaders11" MD "%PCKG_NAME%\Shaders11" - COPY /Y /V "..\src\mpc-hc\res\shaders\dx11\*.hlsl" "%PCKG_NAME%\Shaders11" >NUL - IF /I "%BUILDCFG%" NEQ "Debug" IF /I "%BUILDCFG%" NEQ "Debug Lite" IF EXIST "%VS_OUT_DIR%\CrashReporter\crashrpt.dll" ( - IF NOT EXIST "%PCKG_NAME%\CrashReporter" MD "%PCKG_NAME%\CrashReporter" - COPY /Y /V "%VS_OUT_DIR%\CrashReporter\crashrpt.dll" "%PCKG_NAME%\CrashReporter" - COPY /Y /V "%VS_OUT_DIR%\CrashReporter\dbghelp.dll" "%PCKG_NAME%\CrashReporter" - COPY /Y /V "%VS_OUT_DIR%\CrashReporter\sendrpt.exe" "%PCKG_NAME%\CrashReporter" - COPY /Y /V "%VS_OUT_DIR%\CrashReporter\CrashReporterDialog.dll" "%PCKG_NAME%\CrashReporter" - ) -) ELSE ( - COPY /Y /V "%VS_OUT_DIR%\*.ax" "%PCKG_NAME%\*.ax" >NUL - COPY /Y /V "%VS_OUT_DIR%\VSFilter.dll" "%PCKG_NAME%\VSFilter.dll" >NUL -) - -COPY /Y /V "..\COPYING.txt" "%PCKG_NAME%" >NUL - -TITLE Creating archive %PCKG_NAME%.7z... -START "7z" /B /WAIT "%SEVENZIP%" a -t7z "%PCKG_NAME%.7z" "%PCKG_NAME%" -m0=LZMA2^ - -mmt=%NUMBER_OF_PROCESSORS% -mx9 -ms=on -IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Unable to create %PCKG_NAME%.7z!" & EXIT /B -CALL "%COMMON%" :SubMsg "INFO" "%PCKG_NAME%.7z successfully created" - -IF EXIST "%PCKG_NAME%" RD /Q /S "%PCKG_NAME%" - -POPD -EXIT /B - - -:ShowHelp -TITLE %~nx0 Help -ECHO. -ECHO Usage: -ECHO %~nx0 [Clean^|Build^|Rebuild] [x86^|x64^|Both] [Main^|Resources^|MPCHC^|IconLib^|Translations^|Filters^|API^|All] [Debug^|Release] [Lite] [Packages^|Installer^|7z] [LAVFilters] [Analyze] -ECHO. -ECHO Notes: You can also prefix the commands with "-", "--" or "/". -ECHO Debug only applies to mpc-hc.sln. -ECHO The arguments are not case sensitive and can be ommitted. -ECHO. & ECHO. -ECHO Executing %~nx0 without any arguments will use the default ones: -ECHO "%~nx0 Build Both MPCHC Release" -ECHO. & ECHO. -ECHO Examples: -ECHO %~nx0 x86 Resources -Builds the x86 resources -ECHO %~nx0 Resources -Builds both x86 and x64 resources -ECHO %~nx0 x86 -Builds x86 Main exe and the x86 resources -ECHO %~nx0 x86 Debug -Builds x86 Main Debug exe and x86 resources -ECHO %~nx0 x86 Filters -Builds x86 Filters -ECHO %~nx0 x86 All -Builds x86 Main exe, x86 Filters and the x86 resources -ECHO %~nx0 x86 Packages -Builds x86 Main exe, x86 resources and creates the installer and the .7z package -ECHO %~nx0 x64 LAVFilters 7z -Rebuilds LAVFilters, builds x64 Main exe, x64 resources and creates the .7z package -ECHO. -ENDLOCAL -EXIT /B - - -:MissingVar -TITLE Compiling MPC-HC %COMPILER% [ERROR] -ECHO Not all build dependencies were found. -ECHO. -ECHO See "docs\Compilation.md" for more information. -CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B - - -:UnsupportedSwitch -ECHO. -ECHO Unsupported commandline switch! -ECHO. -ECHO "%~nx0 %*" -ECHO. -ECHO Run "%~nx0 help" for details about the commandline switches. -CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B +@ECHO OFF +REM (C) 2009-2019 see Authors.txt +REM +REM This file is part of MPC-HC. +REM +REM MPC-HC is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation; either version 3 of the License, or +REM (at your option) any later version. +REM +REM MPC-HC is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with this program. If not, see . + + +SETLOCAL EnableDelayedExpansion + +SET ARG=/%* +SET ARG=%ARG:/=% +SET ARG=%ARG:-=% +SET ARGB=0 +SET ARGBC=0 +SET ARGC=0 +SET ARGPL=0 +SET INPUT=0 +SET VALID=0 + +IF /I "%ARG%" == "?" GOTO ShowHelp + +FOR %%G IN (%ARG%) DO ( + IF /I "%%G" == "help" GOTO ShowHelp + IF /I "%%G" == "GetVersion" ENDLOCAL & SET "FORCE_VER_UPDATE=True" & CALL "%~dp0common.bat" :SubGetVersion & EXIT /B + IF /I "%%G" == "Build" SET "BUILDTYPE=Build" & SET /A ARGB+=1 + IF /I "%%G" == "Clean" SET "BUILDTYPE=Clean" & SET /A ARGB+=1 & SET "NO_INST=True" & SET /A "NO_ZIP=True" & SET "NO_LAV=True" + IF /I "%%G" == "Rebuild" SET "BUILDTYPE=Rebuild" & SET /A ARGB+=1 & SET "NO_LAV=True" + IF /I "%%G" == "Both" SET "PPLATFORM=Both" & SET /A ARGPL+=1 + IF /I "%%G" == "Win32" SET "PPLATFORM=Win32" & SET /A ARGPL+=1 + IF /I "%%G" == "x86" SET "PPLATFORM=Win32" & SET /A ARGPL+=1 + IF /I "%%G" == "x64" SET "PPLATFORM=x64" & SET /A ARGPL+=1 + IF /I "%%G" == "All" SET "CONFIG=All" & SET /A ARGC+=1 & SET "NO_LITE=True" + IF /I "%%G" == "Main" SET "CONFIG=Main" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" + IF /I "%%G" == "Filters" SET "CONFIG=Filters" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_LITE=True" + IF /I "%%G" == "Filter" SET "CONFIG=Filters" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_LITE=True" + IF /I "%%G" == "API" SET "CONFIG=API" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "MPCHC" SET "CONFIG=MPCHC" & SET /A ARGC+=1 + IF /I "%%G" == "MPC-HC" SET "CONFIG=MPCHC" & SET /A ARGC+=1 + IF /I "%%G" == "Resources" SET "CONFIG=Resources" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "MPCIconLib" SET "CONFIG=IconLib" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "IconLib" SET "CONFIG=IconLib" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "Translations" SET "CONFIG=Translation" & SET /A ARGC+=1 & SET "NO_INST=True" & SET "NO_ZIP=True" & SET "NO_LITE=True" + IF /I "%%G" == "Debug" SET "BUILDCFG=Debug" & SET /A ARGBC+=1 & SET "NO_INST=True" + IF /I "%%G" == "Release" SET "BUILDCFG=Release" & SET /A ARGBC+=1 + IF /I "%%G" == "Packages" SET "PACKAGES=True" & SET /A VALID+=1 + IF /I "%%G" == "Installer" SET "INSTALLER=True" & SET /A VALID+=1 + IF /I "%%G" == "7z" SET "ZIP=True" & SET /A VALID+=1 + IF /I "%%G" == "Lite" SET "MPCHC_LITE=True" & SET /A VALID+=1 + IF /I "%%G" == "LAVFilters" SET "CLEAN=LAVFilters" & SET /A VALID+=1 + IF /I "%%G" == "Silent" SET "SILENT=True" & SET /A VALID+=1 + IF /I "%%G" == "Nocolors" SET "NOCOLORS=True" & SET /A VALID+=1 + IF /I "%%G" == "Analyze" SET "ANALYZE=True" & SET /A VALID+=1 + IF /I "%%G" == "MINGWLIB" ENDLOCAL & SET "FORCE_MINGW_UPDATE=True" & CALL "%~dp0common.bat" :SubMINGWLIB & EXIT /B +) + +SET "FILE_DIR=%~dp0" +PUSHD "%FILE_DIR%" + +SET "COMMON=%FILE_DIR%\common.bat" + +CALL "%COMMON%" :SubPreBuild +IF %ERRORLEVEL% NEQ 0 GOTO MissingVar + +FOR %%G IN (%*) DO SET /A INPUT+=1 +SET /A VALID+=%ARGB%+%ARGPL%+%ARGC%+%ARGBC% +IF %VALID% NEQ %INPUT% GOTO UnsupportedSwitch + +IF %ARGB% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGB% == 0 (SET "BUILDTYPE=Build") +IF %ARGPL% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGPL% == 0 (SET "PPLATFORM=Both") +IF %ARGC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGC% == 0 (SET "CONFIG=MPCHC") +IF %ARGBC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGBC% == 0 (SET "BUILDCFG=Release") + +IF /I "%PACKAGES%" == "True" SET "INSTALLER=True" & SET "ZIP=True" + +IF /I "%INSTALLER%" == "True" IF "%NO_INST%" == "True" GOTO UnsupportedSwitch +IF /I "%ZIP%" == "True" IF "%NO_ZIP%" == "True" GOTO UnsupportedSwitch +IF /I "%MPCHC_LITE%" == "True" IF "%NO_LITE%" == "True" GOTO UnsupportedSwitch +IF /I "%CLEAN%" == "LAVFilters" IF "%NO_LAV%" == "True" GOTO UnsupportedSwitch + +IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath +IF NOT EXIST "!MPCHC_VS_PATH!" GOTO MissingVar +SET "TOOLSET=!MPCHC_VS_PATH!\Common7\Tools\vsdevcmd" +SET "BIN_DIR=bin" +IF NOT EXIST "%TOOLSET%" GOTO MissingVar + +IF EXIST "%FILE_DIR%signinfo.txt" ( + IF /I "%INSTALLER%" == "True" SET "SIGN=True" + IF /I "%ZIP%" == "True" SET "SIGN=True" +) + +REM Set version for DX libraries +CALL "%COMMON%" :SubParseConfig + +:Start +REM Check if the %LOG_DIR% folder exists otherwise MSBuild will fail +SET "LOG_DIR=%BIN_DIR%\logs" +IF NOT EXIST "%LOG_DIR%" MD "%LOG_DIR%" + +IF DEFINED MPCHC_LITE SET "BUILDCFG=%BUILDCFG% Lite" + +SET "MSBUILD_SWITCHES=/nologo /consoleloggerparameters:Verbosity=minimal /maxcpucount /nodeReuse:true" + +SET START_TIME=%TIME% +SET START_DATE=%DATE% + +IF /I "%PPLATFORM%" == "Both" ( + SET "PPLATFORM=Win32" & CALL :Main + SET "PPLATFORM=x64" & CALL :Main +) ELSE ( + CALL :Main +) +GOTO End + + +:Main +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%PPLATFORM%" == "x64" ( + SET "LAVFILTERSDIR=LAVFilters64" +) ELSE ( + SET "LAVFILTERSDIR=LAVFilters" +) + +IF /I "%CLEAN%" == "LAVFilters" CALL "src\thirdparty\LAVFilters\build_lavfilters.bat" Clean %PPLATFORM% %BUILDCFG% %COMPILER% +IF %ERRORLEVEL% NEQ 0 ENDLOCAL & EXIT /B + +IF /I "%PPLATFORM%" == "Win32" (SET ARCH=x86) ELSE (SET ARCH=amd64) +CALL "%TOOLSET%" -no_logo -arch=%ARCH% -winsdk=%MPCHC_WINSDK_VER% +IF %ERRORLEVEL% NEQ 0 GOTO MissingVar + +IF /I "%CONFIG%" == "Filters" ( + CALL :SubFilters %PPLATFORM% + IF /I "%ZIP%" == "True" CALL :SubCreatePackages Filters %PPLATFORM% + EXIT /B +) + +IF /I "%CONFIG%" == "IconLib" ( + CALL :SubMPCIconLib %PPLATFORM% + EXIT /B +) + +IF /I "%CONFIG%" == "Translation" ( + CALL :SubMPCRresources %PPLATFORM% + EXIT /B +) + +IF /I "%CONFIG%" == "API" ( + CALL :SubMPCTestAPI %PPLATFORM% + EXIT /B +) + +IF /I "%CONFIG%" NEQ "Resources" CALL :SubMPCHC %PPLATFORM% +IF /I "%CONFIG%" NEQ "Main" CALL :SubResources %PPLATFORM% + +IF /I "%INSTALLER%" == "True" CALL :SubCreateInstaller %PPLATFORM% +IF /I "%ZIP%" == "True" CALL :SubCreatePackages MPC-HC %PPLATFORM% + +IF /I "%CONFIG%" == "All" ( + CALL :SubFilters %PPLATFORM% + IF /I "%ZIP%" == "True" CALL :SubCreatePackages Filters %PPLATFORM% +) +EXIT /B + + +:End +IF %ERRORLEVEL% NEQ 0 EXIT /B +TITLE Compiling MPC-HC %COMPILER% [FINISHED] +SET END_TIME=%TIME% +CALL "%COMMON%" :SubGetDuration +CALL "%COMMON%" :SubMsg "INFO" "Compilation started on %START_DATE%-%START_TIME% and completed on %DATE%-%END_TIME% [%DURATION%]" +ENDLOCAL +EXIT /B + + +:SubFilters +IF %ERRORLEVEL% NEQ 0 EXIT /B + +TITLE Compiling MPC-HC Filters %COMPILER% - %BUILDCFG% Filter^|%1... +CALL "update_version.bat" + +MSBuild.exe mpc-hc.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration="%BUILDCFG% Filter";Platform=%1^ + /flp1:LogFile=%LOG_DIR%\filters_errors_%BUILDCFG%_%1.log;errorsonly;Verbosity=diagnostic^ + /flp2:LogFile=%LOG_DIR%\filters_warnings_%BUILDCFG%_%1.log;warningsonly;Verbosity=diagnostic +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "mpc-hc.sln %BUILDCFG% Filter %1 - Compilation failed!" + EXIT /B +) ELSE ( + CALL "%COMMON%" :SubMsg "INFO" "mpc-hc.sln %BUILDCFG% Filter %1 compiled successfully" +) +IF /I "%SIGN%" == "True" CALL :SubSign Filters *.ax +IF /I "%SIGN%" == "True" CALL :SubSign Filters VSFilter.dll +EXIT /B + + +:SubMPCHC +IF %ERRORLEVEL% NEQ 0 EXIT /B + +TITLE Compiling MPC-HC %COMPILER% - %BUILDCFG%^|%1... +CALL "update_version.bat" + +MSBuild.exe mpc-hc.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration="%BUILDCFG%";Platform=%1^ + /flp1:LogFile="%LOG_DIR%\mpc-hc_errors_%BUILDCFG%_%1.log";errorsonly;Verbosity=diagnostic^ + /flp2:LogFile="%LOG_DIR%\mpc-hc_warnings_%BUILDCFG%_%1.log";warningsonly;Verbosity=diagnostic +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "mpc-hc.sln %BUILDCFG% %1 - Compilation failed!" + EXIT /B +) ELSE ( + CALL "%COMMON%" :SubMsg "INFO" "mpc-hc.sln %BUILDCFG% %1 compiled successfully" +) +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpc-hc*.exe +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC *.dll %LAVFILTERSDIR% +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC *.ax %LAVFILTERSDIR% +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC CrashReporterDialog.dll CrashReporter + +EXIT /B + + +:SubResources +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%BUILDCFG%" == "Debug" ( + CALL "%COMMON%" :SubMsg "WARNING" "/debug was used, resources will not be built" + EXIT /B +) + +CALL :SubMPCIconLib %1 + +IF DEFINED MPCHC_LITE ( + CALL "%COMMON%" :SubMsg "WARNING" "/lite was used, translations will not be built" + EXIT /B +) + +CALL :SubMPCRresources %1 +EXIT /B + + +:SubMPCIconLib +IF %ERRORLEVEL% NEQ 0 EXIT /B + +TITLE Compiling mpciconlib %COMPILER% - Release^|%1... +MSBuild.exe mpciconlib.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration=Release;Platform=%1 +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "mpciconlib.sln %1 - Compilation failed!" + EXIT /B +) ELSE ( + CALL "%COMMON%" :SubMsg "INFO" "mpciconlib.sln %1 compiled successfully" +) +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpciconlib.dll + +IF /I "%1" == "Win32" (SET "VS_OUT_DIR=mpc-hc_x86") ELSE (SET "VS_OUT_DIR=mpc-hc_x64") +IF DEFINED MPCHC_LITE ( + PUSHD "%BIN_DIR%" + COPY /Y /V "%VS_OUT_DIR%\mpciconlib.dll" "%VS_OUT_DIR% Lite" >NUL + POPD +) + +EXIT /B + + +:SubMPCRresources +IF %ERRORLEVEL% NEQ 0 EXIT /B + +TITLE Compiling mpcresources %COMPILER%... +MSBuild.exe mpcresources.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration="Release";Platform=%1 +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpcresources.??.dll Lang +IF /I "%SIGN%" == "True" CALL :SubSign MPC-HC mpcresources.??_??.dll Lang +EXIT /B + + +:SubMPCTestAPI +IF %ERRORLEVEL% NEQ 0 EXIT /B + +PUSHD "src\MPCTestAPI" +TITLE Compiling MPCTestAPI %COMPILER% - %BUILDCFG%^|%1... +MSBuild.exe MPCTestAPI.sln %MSBUILD_SWITCHES%^ + /target:%BUILDTYPE% /property:Configuration=%BUILDCFG%;Platform=%1 +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "MPCTestAPI.sln %1 - Compilation failed!" + EXIT /B +) ELSE ( + CALL "%COMMON%" :SubMsg "INFO" "MPCTestAPI.sln %1 compiled successfully" +) +POPD +EXIT /B + + +:SubSign +IF %ERRORLEVEL% NEQ 0 EXIT /B +REM %1 is Filters or MPC-HC +REM %2 is name of the file to sign +REM %3 is the subfolder + +IF /I "%PPLATFORM%" == "Win32" PUSHD "%BIN_DIR%\%~1_x86\%3" +IF /I "%PPLATFORM%" == "x64" PUSHD "%BIN_DIR%\%~1_x64\%3" + +FOR /F "delims=" %%A IN ('DIR "%2" /b') DO ( + CALL "%FILE_DIR%contrib\sign.bat" "%%A" || (CALL "%COMMON%" :SubMsg "ERROR" "Problem signing %%A" & GOTO Break) +) +CALL "%COMMON%" :SubMsg "INFO" "%2 signed successfully." + +:Break +POPD +EXIT /B + + +:SubCopyDXDll +REM SubCopyDXDll skipped +EXIT /B +IF /I "%BUILDCFG%" == "Debug" EXIT /B +PUSHD "%BIN_DIR%" +COPY /Y /V "%WindowsSdkDir%\Redist\D3D\%~1\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" "mpc-hc_%~1%~2" >NUL +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Problem when copying %WindowsSdkDir%\Redist\D3D\%~1\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" & EXIT /B +EXPAND "%DXSDK_DIR%\Redist\Jun2010_d3dx9_%MPC_DX_SDK_NUMBER%_%~1.cab" -F:d3dx9_%MPC_DX_SDK_NUMBER%.dll "mpc-hc_%~1%~2" +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Problem when extracting Jun2010_d3dx9_%MPC_DX_SDK_NUMBER%_%~1.cab" & EXIT /B +POPD +EXIT /B + + +:SubCreateInstaller +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%~1" == "x64" ( + SET MPCHC_INNO_DEF=%MPCHC_INNO_DEF% /Dx64Build + SET MPCHC_COPY_DX_DLL_ARGS=x64 +) ELSE SET MPCHC_COPY_DX_DLL_ARGS=x86 + + +IF DEFINED MPCHC_LITE ( + SET MPCHC_INNO_DEF=%MPCHC_INNO_DEF% /DMPCHC_LITE + SET MPCHC_COPY_DX_DLL_ARGS=%MPCHC_COPY_DX_DLL_ARGS% " Lite" +) + +CALL :SubCopyDXDll %MPCHC_COPY_DX_DLL_ARGS% + +CALL "%COMMON%" :SubDetectInnoSetup + +IF NOT DEFINED InnoSetupPath ( + CALL "%COMMON%" :SubMsg "WARNING" "Inno Setup wasn't found, the %1 installer wasn't built" + EXIT /B +) + +TITLE Compiling %1 %COMPILER% installer... +"%InnoSetupPath%" /SMySignTool="cmd /c "%FILE_DIR%contrib\sign.bat" $f" /Q /O"%BIN_DIR%"^ + "distrib\mpc-hc_setup.iss" %MPCHC_INNO_DEF% +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B +CALL "%COMMON%" :SubMsg "INFO" "%1 installer successfully built" + +EXIT /B + + +:SubCreatePackages +IF %ERRORLEVEL% NEQ 0 EXIT /B + +CALL "%COMMON%" :SubDetectSevenzipPath +CALL "%COMMON%" :SubGetVersion +CALL "%COMMON%" :SubMINGWLIB + +IF NOT DEFINED SEVENZIP ( + CALL "%COMMON%" :SubMsg "WARNING" "7-Zip wasn't found, the %1 %2 package wasn't built" + EXIT /B +) + +IF /I "%~1" == "Filters" (SET "NAME=MPC-HC_standalone_filters") ELSE (SET "NAME=MPC-HC") +IF /I "%~2" == "Win32" ( + SET ARCH=x86 +) ELSE ( + SET ARCH=x64 +) + +IF DEFINED MPCHC_LITE ( + CALL :SubCopyDXDll %ARCH% " Lite" +) ELSE IF /I "%NAME%" == "MPC-HC" ( + CALL :SubCopyDXDll %ARCH% +) + +PUSHD "%BIN_DIR%" + +SET "VS_OUT_DIR=%~1_%ARCH%" +SET "PCKG_NAME=%NAME%.%MPCHC_VER%.%ARCH%" +IF DEFINED MPCHC_LITE ( + SET "VS_OUT_DIR=%VS_OUT_DIR% Lite" + SET "PCKG_NAME=%PCKG_NAME%.Lite" +) +IF /I "%BUILDCFG%" == "Debug" ( + SET "PCKG_NAME=%PCKG_NAME%.dbg" + SET "VS_OUT_DIR=%VS_OUT_DIR%_Debug" +) + +IF EXIST "%PCKG_NAME%.7z" DEL "%PCKG_NAME%.7z" +IF EXIST "%PCKG_NAME%.pdb.7z" DEL "%PCKG_NAME%.pdb.7z" +IF EXIST "%PCKG_NAME%" RD /Q /S "%PCKG_NAME%" + +SET "PDB_FILES=*.pdb" +IF NOT DEFINED MPCHC_LITE (SET "PDB_FILES=%PDB_FILES% %LAVFILTERSDIR%\*.pdb") + +REM Compress the pdb file for mpc-hc only +IF /I "%NAME%" == "MPC-HC" ( + PUSHD "%VS_OUT_DIR%" + TITLE Creating archive %PCKG_NAME%.pdb.7z... + START "7z" /B /WAIT "%SEVENZIP%" a -t7z "%PCKG_NAME%.pdb.7z" %PDB_FILES% -m0=LZMA2^ + -mmt=%NUMBER_OF_PROCESSORS% -mx9 -ms=on + IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Unable to create %PCKG_NAME%.pdb.7z!" & EXIT /B + CALL "%COMMON%" :SubMsg "INFO" "%PCKG_NAME%.pdb.7z successfully created" + IF EXIST "%PCKG_NAME%.pdb.7z" MOVE /Y "%PCKG_NAME%.pdb.7z" ".." >NUL + POPD +) + +TITLE Copying %PCKG_NAME%... +IF NOT EXIST "%PCKG_NAME%" MD "%PCKG_NAME%" + +IF /I "%NAME%" == "MPC-HC" ( + IF NOT DEFINED MPCHC_LITE ( + IF /I "%BUILDCFG%" NEQ "Debug" ( + IF NOT EXIST "%PCKG_NAME%\Lang" MD "%PCKG_NAME%\Lang" + ) + IF NOT EXIST "%PCKG_NAME%\%LAVFILTERSDIR%" MD "%PCKG_NAME%\%LAVFILTERSDIR%" + ) + IF /I "%ARCH%" == "x64" ( + COPY /Y /V "%VS_OUT_DIR%\mpc-hc64.exe" "%PCKG_NAME%\mpc-hc64.exe" >NUL + ) ELSE ( + COPY /Y /V "%VS_OUT_DIR%\mpc-hc.exe" "%PCKG_NAME%\mpc-hc.exe" >NUL + ) + COPY /Y /V "%VS_OUT_DIR%\mpciconlib.dll" "%PCKG_NAME%\*.dll" >NUL + IF NOT DEFINED MPCHC_LITE ( + COPY /Y /V "%VS_OUT_DIR%\Lang\mpcresources.??.dll" "%PCKG_NAME%\Lang\" >NUL + COPY /Y /V "%VS_OUT_DIR%\Lang\mpcresources.??_??.dll" "%PCKG_NAME%\Lang\" >NUL + COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.ax" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL + COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.dll" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL + COPY /Y /V "%VS_OUT_DIR%\%LAVFILTERSDIR%\*.manifest" "%PCKG_NAME%\%LAVFILTERSDIR%" >NUL + ) + COPY /Y /V "%VS_OUT_DIR%\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" "%PCKG_NAME%\d3dcompiler_%MPC_D3D_COMPILER_VERSION%.dll" >NUL + COPY /Y /V "%VS_OUT_DIR%\d3dx9_%MPC_DX_SDK_NUMBER%.dll" "%PCKG_NAME%\d3dx9_%MPC_DX_SDK_NUMBER%.dll" >NUL + IF NOT EXIST "%PCKG_NAME%\Shaders" MD "%PCKG_NAME%\Shaders" + COPY /Y /V "..\src\mpc-hc\res\shaders\dx9\*.hlsl" "%PCKG_NAME%\Shaders" >NUL + IF NOT EXIST "%PCKG_NAME%\Shaders11" MD "%PCKG_NAME%\Shaders11" + COPY /Y /V "..\src\mpc-hc\res\shaders\dx11\*.hlsl" "%PCKG_NAME%\Shaders11" >NUL + IF /I "%BUILDCFG%" NEQ "Debug" IF /I "%BUILDCFG%" NEQ "Debug Lite" IF EXIST "%VS_OUT_DIR%\CrashReporter\crashrpt.dll" ( + IF NOT EXIST "%PCKG_NAME%\CrashReporter" MD "%PCKG_NAME%\CrashReporter" + COPY /Y /V "%VS_OUT_DIR%\CrashReporter\crashrpt.dll" "%PCKG_NAME%\CrashReporter" + COPY /Y /V "%VS_OUT_DIR%\CrashReporter\dbghelp.dll" "%PCKG_NAME%\CrashReporter" + COPY /Y /V "%VS_OUT_DIR%\CrashReporter\sendrpt.exe" "%PCKG_NAME%\CrashReporter" + COPY /Y /V "%VS_OUT_DIR%\CrashReporter\CrashReporterDialog.dll" "%PCKG_NAME%\CrashReporter" + ) +) ELSE ( + COPY /Y /V "%VS_OUT_DIR%\*.ax" "%PCKG_NAME%\*.ax" >NUL + COPY /Y /V "%VS_OUT_DIR%\VSFilter.dll" "%PCKG_NAME%\VSFilter.dll" >NUL +) + +COPY /Y /V "..\COPYING.txt" "%PCKG_NAME%" >NUL + +TITLE Creating archive %PCKG_NAME%.7z... +START "7z" /B /WAIT "%SEVENZIP%" a -t7z "%PCKG_NAME%.7z" "%PCKG_NAME%" -m0=LZMA2^ + -mmt=%NUMBER_OF_PROCESSORS% -mx9 -ms=on +IF %ERRORLEVEL% NEQ 0 CALL "%COMMON%" :SubMsg "ERROR" "Unable to create %PCKG_NAME%.7z!" & EXIT /B +CALL "%COMMON%" :SubMsg "INFO" "%PCKG_NAME%.7z successfully created" + +IF EXIST "%PCKG_NAME%" RD /Q /S "%PCKG_NAME%" + +POPD +EXIT /B + + +:ShowHelp +TITLE %~nx0 Help +ECHO. +ECHO Usage: +ECHO %~nx0 [Clean^|Build^|Rebuild] [x86^|x64^|Both] [Main^|Resources^|MPCHC^|IconLib^|Translations^|Filters^|API^|All] [Debug^|Release] [Lite] [Packages^|Installer^|7z] [LAVFilters] [Analyze] +ECHO. +ECHO Notes: You can also prefix the commands with "-", "--" or "/". +ECHO Debug only applies to mpc-hc.sln. +ECHO The arguments are not case sensitive and can be ommitted. +ECHO. & ECHO. +ECHO Executing %~nx0 without any arguments will use the default ones: +ECHO "%~nx0 Build Both MPCHC Release" +ECHO. & ECHO. +ECHO Examples: +ECHO %~nx0 x86 Resources -Builds the x86 resources +ECHO %~nx0 Resources -Builds both x86 and x64 resources +ECHO %~nx0 x86 -Builds x86 Main exe and the x86 resources +ECHO %~nx0 x86 Debug -Builds x86 Main Debug exe and x86 resources +ECHO %~nx0 x86 Filters -Builds x86 Filters +ECHO %~nx0 x86 All -Builds x86 Main exe, x86 Filters and the x86 resources +ECHO %~nx0 x86 Packages -Builds x86 Main exe, x86 resources and creates the installer and the .7z package +ECHO %~nx0 x64 LAVFilters 7z -Rebuilds LAVFilters, builds x64 Main exe, x64 resources and creates the .7z package +ECHO. +ENDLOCAL +EXIT /B + + +:MissingVar +TITLE Compiling MPC-HC %COMPILER% [ERROR] +ECHO Not all build dependencies were found. +ECHO. +ECHO See "docs\Compilation.md" for more information. +CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B + + +:UnsupportedSwitch +ECHO. +ECHO Unsupported commandline switch! +ECHO. +ECHO "%~nx0 %*" +ECHO. +ECHO Run "%~nx0 help" for details about the commandline switches. +CALL "%COMMON%" :SubMsg "ERROR" "Compilation failed!" & EXIT /B diff --git a/contrib/sign.bat b/contrib/sign.bat index adc1a0ad9a1..0ae0418a3eb 100755 --- a/contrib/sign.bat +++ b/contrib/sign.bat @@ -1,80 +1,80 @@ -@ECHO OFF -REM (C) 2013, 2015-2017 see Authors.txt -REM -REM This file is part of MPC-HC. -REM -REM MPC-HC is free software; you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation; either version 3 of the License, or -REM (at your option) any later version. -REM -REM MPC-HC is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with this program. If not, see . - - -SETLOCAL -SET "FILE_DIR=%~dp0" - -SET "COMMON=%FILE_DIR%..\common.bat" - -IF "%~1" == "" ( - ECHO %~nx0: No input specified! - SET SIGN_ERROR=True - GOTO END -) - -IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath -IF NOT EXIST "%MPCHC_VS_PATH%" ( - ECHO %~nx0: Visual Studio 2017 does not seem to be installed... - SET SIGN_ERROR=True - GOTO END -) -SET "TOOLSET=%MPCHC_VS_PATH%\Common7\Tools\vsdevcmd" - -IF NOT EXIST "%FILE_DIR%..\signinfo.txt" ( - ECHO %~nx0: %FILE_DIR%..\signinfo.txt is not present! - SET SIGN_ERROR=True - GOTO END -) - -signtool /? 2>NUL || CALL "%TOOLSET%" 2>NUL -IF %ERRORLEVEL% NEQ 0 ( - ECHO vcvarsall.bat call failed. - GOTO End -) - -REM Repeat n times when signing fails -SET REPEAT=5 -FOR /F "delims=" %%A IN (%FILE_DIR%..\signinfo.txt) DO (SET "SIGN_CMD=%%A" && CALL :START_SIGN %1) - -:END -IF /I "%SIGN_ERROR%" == "True" ( - IF "%~1" == "" PAUSE - ENDLOCAL - EXIT /B 1 -) -ENDLOCAL -EXIT /B - -:START_SIGN -IF /I "%SIGN_ERROR%" == "True" EXIT /B -REM %1 is name of the file to sign -TITLE Signing "%~1"... -ECHO. & ECHO Signing "%~1"... -SET TRY=0 - -:SIGN -SET /A TRY+=1 -signtool sign %SIGN_CMD% %1 -IF %ERRORLEVEL% EQU 0 EXIT /B -IF %TRY% LSS %REPEAT% ( - REM Wait 5 seconds before next try - PING -n 5 127.0.0.1 > NUL - GOTO SIGN -) -SET SIGN_ERROR=True +@ECHO OFF +REM (C) 2013, 2015-2017 see Authors.txt +REM +REM This file is part of MPC-HC. +REM +REM MPC-HC is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation; either version 3 of the License, or +REM (at your option) any later version. +REM +REM MPC-HC is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with this program. If not, see . + + +SETLOCAL +SET "FILE_DIR=%~dp0" + +SET "COMMON=%FILE_DIR%..\common.bat" + +IF "%~1" == "" ( + ECHO %~nx0: No input specified! + SET SIGN_ERROR=True + GOTO END +) + +IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath +IF NOT EXIST "%MPCHC_VS_PATH%" ( + ECHO %~nx0: Visual Studio 2017 does not seem to be installed... + SET SIGN_ERROR=True + GOTO END +) +SET "TOOLSET=%MPCHC_VS_PATH%\Common7\Tools\vsdevcmd" + +IF NOT EXIST "%FILE_DIR%..\signinfo.txt" ( + ECHO %~nx0: %FILE_DIR%..\signinfo.txt is not present! + SET SIGN_ERROR=True + GOTO END +) + +signtool /? 2>NUL || CALL "%TOOLSET%" 2>NUL +IF %ERRORLEVEL% NEQ 0 ( + ECHO vcvarsall.bat call failed. + GOTO End +) + +REM Repeat n times when signing fails +SET REPEAT=5 +FOR /F "delims=" %%A IN (%FILE_DIR%..\signinfo.txt) DO (SET "SIGN_CMD=%%A" && CALL :START_SIGN %1) + +:END +IF /I "%SIGN_ERROR%" == "True" ( + IF "%~1" == "" PAUSE + ENDLOCAL + EXIT /B 1 +) +ENDLOCAL +EXIT /B + +:START_SIGN +IF /I "%SIGN_ERROR%" == "True" EXIT /B +REM %1 is name of the file to sign +TITLE Signing "%~1"... +ECHO. & ECHO Signing "%~1"... +SET TRY=0 + +:SIGN +SET /A TRY+=1 +signtool sign %SIGN_CMD% %1 +IF %ERRORLEVEL% EQU 0 EXIT /B +IF %TRY% LSS %REPEAT% ( + REM Wait 5 seconds before next try + PING -n 5 127.0.0.1 > NUL + GOTO SIGN +) +SET SIGN_ERROR=True diff --git a/distrib/Languages/Basque.isl b/distrib/Languages/Basque.isl index f44148f47e9..a4b9cebeb13 100644 --- a/distrib/Languages/Basque.isl +++ b/distrib/Languages/Basque.isl @@ -1,339 +1,339 @@ -; *** Inno Setup version 5.5.3+ Basque messages *** -; -; Basque Translation: (EUS_Xabier Aramendi) (azpidatziak@gmail.com) -; -; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ -; -; Note: When translating this text, do not add periods (.) to the end of -; messages that didn't have them already, because on those messages Inno -; Setup adds the periods automatically (appending a period would result in -; two periods being displayed). - -[LangOptions] -; The following three entries are very important. Be sure to read and -; understand the '[LangOptions] section' topic in the help file. -LanguageName=Euskara -LanguageID=$042d -LanguageCodePage=0 -; If the language you are translating to requires special font faces or -; sizes, uncomment any of the following entries and change them accordingly. -;DialogFontName= -;DialogFontSize=8 -;WelcomeFontName=Verdana -;WelcomeFontSize=12 -;TitleFontName=Arial -;TitleFontSize=29 -;CopyrightFontName=Arial -;CopyrightFontSize=8 - -[Messages] - -; *** Application titles -SetupAppTitle=Ezarpena -SetupWindowTitle=Ezarpena - %1 -UninstallAppTitle=Kentzea -UninstallAppFullTitle=Kentzea - %1 - -; *** Misc. common -InformationTitle=Argibideak -ConfirmTitle=Baieztatu -ErrorTitle=Akatsa - -; *** SetupLdr messages -SetupLdrStartupMessage=Honek %1 ezarriko du. Jarraitzea nahi duzu? -LdrCannotCreateTemp=Ezinezkoa aldibaterako agiri bat sortzea. Ezarpena utzita -LdrCannotExecTemp=Ezinezkoa agiria exekutatzea aldibaterako zuzenbidean. Ezarpena utzita - -; *** Startup error messages -LastErrorMessage=%1.%n%nAkatsa %2: %3 -SetupFileMissing=%1 agiria ez dago ezarpen zuzenbidean. Mesedez zuzendu arazoa edo lortu programaren kopia berri bat. -SetupFileCorrupt=Ezarpen agiriak hondatuta daude. Mesedez lortu programaren kopia berri bat. -SetupFileCorruptOrWrongVer=Ezarpen agiriak hondatuta daude, edo bateraezinak dira Ezartzaile bertsio honekin. Mesedez zuzendu arazoa edo lortu programaren kopia berri bat. -InvalidParameter=Parametro baliogabe bat igaro da komando lerroan:%n%n%1 -SetupAlreadyRunning=Ezarpena jadanik ekinean dago. -WindowsVersionNotSupported=Programa honek ez du zure ordenagailuan ekinean dagoen Windows bertsioa sostengatzen. -WindowsServicePackRequired=Programa honek %1 Service Pack %2 edo berriagoa behar du. - - -NotOnThisPlatform=Programa honek ez du ekingo hemen: %1. -OnlyOnThisPlatform=Programa hau hemen ekin behar da: %1. -OnlyOnTheseArchitectures=Programa hau hurrengo Windows arkitekturatarako diseinaturiko bertsioetan bakarrik ezarri daiteke:%n%n%1 -MissingWOW64APIs=Erabiltzen ari zaren Windows bertsioak ez du Ezartzaileak 64-biteko ezarpen bat egiteko behar dituen eginkizunak barneratzen. Arazo hau zuzentzeko, mesedez ezarri Service Pack %1. -WinVersionTooLowError=Programa honek %1 bertsioa %2 edo berriagoa behar du. -WinVersionTooHighError=Programa hau ezin da %1 bertsioa %2 edo berriagoan ezarria izan. -AdminPrivilegesRequired=Administrari bezala izena-emanda egon behar zara programa hau ezartzeko. -PowerUserPrivilegesRequired=Administrari bezala izena-emanda edo Boteredun Erabiltzaile taldeko kide bezala egon behar zara programa hau ezartzerakoan. -SetupAppRunningError=Ezartzaileak %1 ekinean dagoela atzeman du.%n%nMesedez itxi bere eskabide guztiak orain, orduan klikatu Ongi jarritzeko, edo Ezeztatu irtetzeko. -UninstallAppRunningError=Kentzaileak %1 ekinean dagoela atzeman du.%n%nMesedez itxi bere eskabide guztiak orain, orduan klikatu Ongi jarritzeko, edo Ezeztatu irtetzeko. - -; *** Misc. errors -ErrorCreatingDir=Ezartzaileak ezin izan du zuzenbidea sortu "%1" -ErrorTooManyFilesInDir=Ezinezkoa agiri bat sortzea "%1" zuzenbidean agiri gehiegi dituelako - -; *** Setup common messages -ExitSetupTitle=Irten Ezartzailetik -ExitSetupMessage=Ezarpena ez dago osatuta. Orain irtetzen bazara, programa ez da ezarriko.%n%nEzartzailea berriro edonoiz abiatu dezakezu ezarpena osatzeko.%n%nIrten Ezartzailetik? -AboutSetupMenuItem=&Ezartzaileari buruz... -AboutSetupTitle=Ezartzaileari buruz -AboutSetupMessage=%1 bertsioa %2%n%3%n%n%1 webgunea:%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< &Atzera -ButtonNext=&Hurrengoa > -ButtonInstall=&Ezarri -ButtonOK=Ongi -ButtonCancel=Ezeztatu -ButtonYes=&Bai -ButtonYesToAll=Bai &Guztiari -ButtonNo=&Ez -ButtonNoToAll=E&z Guztiari -ButtonFinish=A&maitu -ButtonBrowse=&Bilatu... -ButtonWizardBrowse=B&ilatu... -ButtonNewFolder=Egi&n Agiritegi Berria - -; *** "Select Language" dialog messages -SelectLanguageTitle=Hautatu Ezarpen Hizkuntza -SelectLanguageLabel=Hautatu ezarpenean zehar erabiltzeko hizkuntza: - -; *** Common wizard text -ClickNext=Klikatu Hurrengoa jarraitzeko, edo Ezeztatu Ezartzailetik irtetzeko -BeveledLabel= -BrowseDialogTitle=Bilatu Agiritegia -BrowseDialogLabel=Hautatu agiritegi bat azpiko zerrendan, orduan klikatu Ongi -NewFolderName=Agiritegi Berria - -; *** "Welcome" wizard page -WelcomeLabel1=Ongi etorria [name] Ezarpen Laguntzailera -WelcomeLabel2=Honek [name/ver] zure ordenagailuan ezarriko du.%n%nGomendagarria da beste aplikazio guztiak istea jarraitu aurretik. - -; *** "Password" wizard page -WizardPassword=Sarhitza -PasswordLabel1=Ezarpen hau sarhitzez babestuta dago. -PasswordLabel3=Mesedez eman sarhitza, orduan klikatu Hurrengoa jarraitzeko. Sarhitzek hizki larri-xeheak bereizten dituzte. -PasswordEditLabel=&Sarhitza: -IncorrectPassword=Eman duzun sarhitza ez da zuzena. Mesedez saiatu berriro. - -; *** "License Agreement" wizard page -WizardLicense=Baimen Ituna -LicenseLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. -LicenseLabel3=Mesedez irakurri hurrengo Baimen Ituna. Itun honen baldintzak onartu behar dituzu ezarpenarekin jarraitu aurretik. -LicenseAccepted=&Onartzen dut ituna -LicenseNotAccepted=&Ez dut onartzen ituna - -; *** "Information" wizard pages -WizardInfoBefore=Argibideak -InfoBeforeLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. -InfoBeforeClickLabel=Ezarpenarekin jarraitzeko gertu zaudenean, klikatu Hurrengoa. -WizardInfoAfter=Argibideak -InfoAfterLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. -InfoAfterClickLabel=Ezarpenarekin jarraitzeko gertu zaudenean, klikatu Hurrengoa. - -; *** "User Information" wizard page -WizardUserInfo=Erabailtzaile Argibideak -UserInfoDesc=Mesedez sartu zure argibideak -UserInfoName=&Erabiltzaile Izena: -UserInfoOrg=&Antolakundea: -UserInfoSerial=&Serie Zenbakia: -UserInfoNameRequired=Izen bat sartu behar duzu. - -; *** "Select Destination Location" wizard page -WizardSelectDir=Hautatu Helmuga Kokalekua -SelectDirDesc=Non ezarri behar da [name]? -SelectDirLabel3=Ezartzaileak [name] hurrengo agiritegian ezarriko du. -SelectDirBrowseLabel=Jarraitzeko, klikatu Hurrengoa. Beste agiritegi bat hautatzea nahi baduzu, klikatu Bilatu. -DiskSpaceMBLabel=Gutxienez [mb] MB-eko toki askea behar da diska gogorrean. -CannotInstallToNetworkDrive=Ezarpena ezin da sare gidagailu batean egin. -CannotInstallToUNCPath=Ezarpena ezin da UNC helburu batean egin. -InvalidPath=Helburu osoa gidagailu hizkiarekin sartu behar duzu; adibidez:%n%nC:\APP%n%nedo UNC helburu bat forma honetan:%n%n\\server\share -InvalidDrive=Hautatu duzun gidagailua edo UNC elkarbanaketa ez dago edo sarbidea ezinezkoa da. Mesedez hautatu beste bat. -DiskSpaceWarningTitle=Ez Dago Nahikoa Toki Diskan -DiskSpaceWarning=Ezarpenak gutxienez %1 KB-eko toki askea behar du ezartzeko, baina hautaturiko gidagailuak %2 KB bakarrik ditu eskuragarri.%n%nHorrela ere jarraitzea nahi duzu? -DirNameTooLong=Agiritegi izena edo helburua luzeegia da. -InvalidDirName=Agiritegi izena ez da baliozkoa. -BadDirName32=Agiritegi izenek ezin dute hurrengo hizkietako bat ere izan:%n%n%1 -DirExistsTitle=Agiritegia Badago -DirExists=Agiritegia:%n%n%1%n%njadanik badago. Horrela ere agiritegi horretan ezartzea nahi duzu? -DirDoesntExistTitle=Agiritegia Ez Dago -DirDoesntExist=Agiritegia:%n%n%1%n%nez dago. Nahi duzu agiritegia sortzea? - -; *** "Select Components" wizard page -WizardSelectComponents=Hautatu Osagaiak -SelectComponentsDesc=Zer osagai ezarri behar dira? -SelectComponentsLabel2=Hautatu ezartzea nahi dituzun osagaiak; garbitu ezartzea nahi ez dituzun osagaiak. Klikatu Hurrengoa jarraitzeko gertu zaudenean. -FullInstallation=Ezarpen osoa -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=Ezarpen trinkoa -CustomInstallation=Norbere ezarpena -NoUninstallWarningTitle=Osagaiak Badaude -NoUninstallWarning=Ezartzaileak atzeman du hurrengo osagaiak jadanik zure ordenagailuan ezarrita daudela:%n%n%1%n%nOsagai hauek deshautatuz gero ez dira ezarriko.%n%nHorrela ere jarraitzea nahi duzu? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=Oraingo hautapenak gutxienez [mb] MB-eko tokia behar du diskan. - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=Hautatu Eginkizun Gehigarriak -SelectTasksDesc=Zer eginkizun gehigarri burutu behar dira? -SelectTasksLabel2=Hautatu Ezartzaileak [name]-ren ezarpenean zehar burutzea nahi dituzun eginkizun gehigarriak, orduan klikatu Hurrengoa - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=Hautatu Hasiera Menuko Agiritegia -SelectStartMenuFolderDesc=Non ezarri behar ditu Ezartzaileak programaren lasterbideak? -SelectStartMenuFolderLabel3=Ezartzaileak programaren lasterbideak hurrengo Hasiera Menuko agiritegian sortuko ditu. -SelectStartMenuFolderBrowseLabel=Jarraitzeko, klikatu Hurrengoa. Beste agiritegi bat hautatzea nahi baduzu, klikatu Bilatu. -MustEnterGroupName=Agiritegi izen bat sartu behar duzu. -GroupNameTooLong=Agiritegi izena edo helburua luzeegia da. -InvalidGroupName=Agiritegi izena ez da baliozkoa. -BadGroupName=Agiritegi izenak ezin du hurrengo hizkietako bat ere izan:%n%n%1 -NoProgramGroupCheck2=&Ez sortu Hasiera Menuko agiritegia - -; *** "Ready to Install" wizard page -WizardReady=Ezartzeko Gertu -ReadyLabel1=Ezartzailea orain gertu dago [name] zure ordenagailuan ezartzeko. -ReadyLabel2a=Klikatu Ezarri ezarpenarekin jarraitzeko, edo klikatu Atzera ezarpenen bat berrikustea edo aldatzea nahi baduzu. -ReadyLabel2b=Klikatu Ezarri ezarpenarekin jarraitzeko. -ReadyMemoUserInfo=Erabiltzaile argibideak: -ReadyMemoDir=Helmuga kokalekua: -ReadyMemoType=Ezarpen mota: -ReadyMemoComponents=Hautaturiko osagaiak: -ReadyMemoGroup=Hasiera Menuko agiritegia: -ReadyMemoTasks=Eginkizun gehigarriak: - -; *** "Preparing to Install" wizard page -WizardPreparing=Ezartzeko Gertatzen -PreparingDesc=Ezartzailea [name] zure ordenagailuan ezartzeko gertatzen ari da. -PreviousInstallNotCompleted=Aurreko programaren ezartze/kentzea ez dago osatuta. Zure ordenagailua berrabiarazi behar duzu ezarpena osatzeko.%n%nZure ordenagailua berrabiarazi ondoren, ekin Ezartzailea berriro [name]-ren ezarpena osatzeko. -CannotContinue=Ezarpenak ezin du jarraitu. Mesedez klikatu Ezeztatu irtetzeko. -ApplicationsFound=Hurrengo aplikazioak Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari dira. Gomendagarria da Ezartzaileari aplikazio hauek berezgaitasunez istea ahalbidetzea. -ApplicationsFound2=Hurrengo aplikazioak Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari dira. Gomendagarria da Ezartzaileari aplikazio hauek berezgaitasunez istea ahalbidetzea. Ezarpena osatu ondoren, Ezartzailea aplikazioak berrabiarazten saiatuko da. -CloseApplications=&Berezgaitasunez itxi aplikazioak -DontCloseApplications=&Ez itxi aplikazioak -ErrorCloseApplications=Ezartzaileak ezin ditu berezgaitasunez aplikazio guztiak itxi. Gomendagarria da Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari diren aplikazio guztiak istea jarraitu aurretik. - -; *** "Installing" wizard page -WizardInstalling=Ezartzen -InstallingLabel=Mesedez itxaron Ezartzaileak [name] zure ordenagailuan ezartzen duen bitartean. - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=[name] Ezarpen Laguntzailea osatzen -FinishedLabelNoIcons=Ezartzaileak amaitu du [name] zure ordenagailuan ezartzeaz. -FinishedLabel=Ezartzaileak amaitu du [name] zure ordenagailuan ezartzea. Aplikazioa ezarritako ikurren bidez abiarazi daiteke. -ClickFinish=Klikatu Amaitu Ezartzailetik irtetzeko. -FinishedRestartLabel=[name]-ren ezarpena osatzeko, Ezartzaileak zure ordenagailua berrabiarazi behar du. Orain berrabiaraztea nahi duzu? -FinishedRestartMessage=[name]-ren ezarpena osatzeko, Ezartzaileak zure ordenagailua berrabiarazi behar du.%n%nOrain berrabiaraztea nahi duzu? -ShowReadmeCheck=Bai, IRAKURRI agiria ikustea nahi dut -YesRadio=&Bai, berrabiarazi ordenagailua orain -NoRadio=&Ez, geroago berrabiaraziko dut ordenagailua -; used for example as 'Run MyProg.exe' -RunEntryExec=Ekin %1 -; used for example as 'View Readme.txt' -RunEntryShellExec=Ikusi %1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=Ezarpenak Hurrengo Diska Behar Du -SelectDiskLabel2=Mesedez txertatu %1 Diska eta klikatu Ongi.%n%nDiska honetako agiriak azpian erakutsitakoa ez den beste agiritegi batean aurkitu badaitezke, sartu helburu zuzena edo klikatu Bilatu. -PathLabel=&Helburua: -FileNotInDir2="%1" agiria ezin da hemen aurkitu: "%2". Mesedez txertatu diska zuzena edo hautatu beste agiritegi bat. -SelectDirectoryLabel=Mesedez adierazi hurrengo diskaren kokalekua. - -; *** Installation phase messages -SetupAborted=Ezarpena ez da osatu.%n%nMesedez zuzendu arazoa eta ekin Ezartzailea berriro. -EntryAbortRetryIgnore=Klikatu Bersaiatu berriro saiatzeko, Ezikusi horrela ere jarraitzeko, edo Utzi ezarpena ezeztatzeko. - -; *** Installation status messages -StatusClosingApplications=Aplikazioak isten... -StatusCreateDirs=Zuzenbideak sortzen... -StatusExtractFiles=Agiriak ateratzen... -StatusCreateIcons=Lasterbideak sortzen... -StatusCreateIniEntries=INI sarrerak sortzen... -StatusCreateRegistryEntries=Erregistro sarrerak sortzen... -StatusRegisterFiles=Agiriak erregistratzen... -StatusSavingUninstall=Kentze argibideak gordetzen... -StatusRunProgram=Ezarpena amaitzen... -StatusRestartingApplications=Aplikazioak berrabiarazten... -StatusRollback=Aldaketak leheneratzen... - -; *** Misc. errors -ErrorInternal2=Barneko akatsa: %1 -ErrorFunctionFailedNoCode=%1 hutsegitea -ErrorFunctionFailed=%1 hutsegitea; kodea %2 -ErrorFunctionFailedWithMessage=%1 hutsegitea; kodea %2.%n%3 -ErrorExecutingProgram=Ezinezkoa agiria exekutatzea:%n%1 - -; *** Registry errors -ErrorRegOpenKey=Akatsa erregistro giltza irekitzerakoan:%n%1\%2 -ErrorRegCreateKey=Akatsa erregistro giltza sortzerakoan:%n%1\%2 -ErrorRegWriteKey=Akatsa erregistro giltza idazterakoan:%n%1\%2 - -; *** INI errors -ErrorIniEntry=Akatsa INI sarrera "%1" agirian sortzerakoan. - -; *** File copying errors -FileAbortRetryIgnore=Klikatu Bersaiatu berriro saitzeko, Ezikusi agiri hau jauzteko (ez da gomendatua), edo Utzi ezarpena ezeztatzeko. -FileAbortRetryIgnore2=Klikatu Bersaiatu berriro saitzeko, Ezikusi horrela ere jarraitzeko (ez da gomendatua), edo Utzi ezarpena ezeztatzeko. -SourceIsCorrupted=Iturburu agiria hondatuta dago. -SourceDoesntExist="%1" iturburu agiria ez dago -ExistingFileReadOnly=Dagoen agiria irakurtzeko-bakarrik bezala markatuta dago.%n%nKlikatu Bersaiatu irakurtzeko-bakarrik ezaugarria kentzeko eta saiatu berriro, Ezikusi agiri hau jauzteko, edo Utzi ezarpena ezeztatzeko. -ErrorReadingExistingDest=Akats bat gertatu da dagoen agiria irakurtzen saiatzerakoan: -FileExists=Agiria jadanik badago.%n%nNahi duzu Ezartzaileak gainidaztea? -ExistingFileNewer=Dagoen agiria Ezartzailea ezartzen saiatzen ari dena baino berriagoa da. Gomendagarria da dagoen agiriari heustea.%n%nDagoen agiriari heustea nahi diozu? -ErrorChangingAttr=Akats bat gertatu da dagoen agiriaren ezaugarriak aldatzen saiatzerakoan: -ErrorCreatingTemp=Akats bat gertatu da helmuga zuzenbidean agiri bat sortzen saiatzerakoan: -ErrorReadingSource=Akats bat gertatu da iturburu agiria irakurtzen saiatzerakoan: -ErrorCopying=Akats bat gertatu da agiri bat kopiatzen saiatzerakoan: -ErrorReplacingExistingFile=Akats bat gertatu da dagoen agiria ordezten saiatzerakoan: -ErrorRestartReplace=Berrabiarazte-Ordezte hutsegitea: -ErrorRenamingTemp=Akats bat gertatu da helmuga zuzenbideko agiri bat berrizendatzen saiatzerakoan: -ErrorRegisterServer=Ezinezkoa DLL/OCX erregistratzea: %1 -ErrorRegSvr32Failed=RegSvr32 hutsegitea %1 irteera kodearekin -ErrorRegisterTypeLib=Ezinezkoa liburutegi mota erregistratzea: %1 - -; *** Post-installation errors -ErrorOpeningReadme=Akats bat gertatu da IRAKURRI agiria irekitzen saiatzerakoan. -ErrorRestartingComputer=Ezartzaileak ezin du ordenagailua berrabiarazi. Mesedez egin hau eskuz. - -; *** Uninstaller messages -UninstallNotFound="%1" agiria ez dago. Ezinezkoa kentzea -UninstallOpenError="%1" agiria ezin da ireki. Ezinezkoa kentzea -UninstallUnsupportedVer="%1" kentze ohar agiria kentzaile bertsio honek ezagutzen ez duen heuskarri batean dago. Ezinezkoa kentzea. -UninstallUnknownEntry=Sarrera ezezagun bat (%1) aurkitu da kentze oharrean -ConfirmUninstall=Zihur zaude %1 eta bere osagai guztiak erabat kentzea nahi dituzula? -UninstallOnlyOnWin64=Ezarpen hau 64-biteko Windows-etik bakarrik kendu daiteke. -OnlyAdminCanUninstall=Ezarpen hau administrari pribilegioak dituen erabiltzaile batek bakarrik kendu dezake. -UninstallStatusLabel=Mesedez itxaron %1 zure ordenagailutik kentzen den bitartean. -UninstalledAll=%1 ongi kendu da zure ordenagailutik. -UninstalledMost=%1-ren kentzea osatuta.%n%nZenbait gai ezin izan dira kendu. Hauek eskuz kendu daitezke. -UninstalledAndNeedsRestart=%1-ren kentzea osatzeko, zure ordenagailua berrabiarazi behar duzu.%n%nOrain berrabiaraztea nahi duzu? -UninstallDataCorrupted="%1" agiria hondatuta da. Ezinezkoa kentzea - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=Ezabatu Agiri Elkarbanatua? -ConfirmDeleteSharedFile2=Sistemaren arabera hurrengo agiri elkarbanatua ez du inongo programak erabiliko hemendik aurrera. Kentzaileak agiri hau ezabatu dezan nahi duzu?%n%nProgramaren bat agiri hau erabiltzen ari da oraindik eta ezabatzen baduzu, programa hori ez da egoki ibiliko. Zihur ez bazaude, hautatu Ez. Agiria sisteman uzteak ez du inongo kalterik eragingo. -SharedFileNameLabel=Agiri izena: -SharedFileLocationLabel=Kokalekua: -WizardUninstalling=Kentze Egoera -StatusUninstalling=Kentzen %1... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=Ezartzen %1. -ShutdownBlockReasonUninstallingApp=Kentzen %1. -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] -;Inno Setup Built-in Custom Messages -NameAndVersion=%1 %2 bertsioa -AdditionalIcons=Ikur gehigarriak: -CreateDesktopIcon=Sortu &mahaigain ikurra -CreateQuickLaunchIcon=Sortu &Abiarazpen Azkarreko ikurra -ProgramOnTheWeb=%1 Webean -UninstallProgram=Kendu %1 -LaunchProgram=Abiarazi %1 -AssocFileExtension=&Elkartu %1 programa %2 agiri luzapenarekin -AssocingFileExtension=%1 programa %2 agiri luzapenarekin elkartzen... -AutoStartProgramGroupDescription=Abirazpena: -AutoStartProgram=Berezgaitasunez abiarazi %1 -AddonHostProgramNotFound=%1 ezin da aurkitu hautatu duzun agiritegian.%n%nHorrela ere jarraitzea nahi duzu? +; *** Inno Setup version 5.5.3+ Basque messages *** +; +; Basque Translation: (EUS_Xabier Aramendi) (azpidatziak@gmail.com) +; +; To download user-contributed translations of this file, go to: +; http://www.jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Euskara +LanguageID=$042d +LanguageCodePage=0 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Ezarpena +SetupWindowTitle=Ezarpena - %1 +UninstallAppTitle=Kentzea +UninstallAppFullTitle=Kentzea - %1 + +; *** Misc. common +InformationTitle=Argibideak +ConfirmTitle=Baieztatu +ErrorTitle=Akatsa + +; *** SetupLdr messages +SetupLdrStartupMessage=Honek %1 ezarriko du. Jarraitzea nahi duzu? +LdrCannotCreateTemp=Ezinezkoa aldibaterako agiri bat sortzea. Ezarpena utzita +LdrCannotExecTemp=Ezinezkoa agiria exekutatzea aldibaterako zuzenbidean. Ezarpena utzita + +; *** Startup error messages +LastErrorMessage=%1.%n%nAkatsa %2: %3 +SetupFileMissing=%1 agiria ez dago ezarpen zuzenbidean. Mesedez zuzendu arazoa edo lortu programaren kopia berri bat. +SetupFileCorrupt=Ezarpen agiriak hondatuta daude. Mesedez lortu programaren kopia berri bat. +SetupFileCorruptOrWrongVer=Ezarpen agiriak hondatuta daude, edo bateraezinak dira Ezartzaile bertsio honekin. Mesedez zuzendu arazoa edo lortu programaren kopia berri bat. +InvalidParameter=Parametro baliogabe bat igaro da komando lerroan:%n%n%1 +SetupAlreadyRunning=Ezarpena jadanik ekinean dago. +WindowsVersionNotSupported=Programa honek ez du zure ordenagailuan ekinean dagoen Windows bertsioa sostengatzen. +WindowsServicePackRequired=Programa honek %1 Service Pack %2 edo berriagoa behar du. + + +NotOnThisPlatform=Programa honek ez du ekingo hemen: %1. +OnlyOnThisPlatform=Programa hau hemen ekin behar da: %1. +OnlyOnTheseArchitectures=Programa hau hurrengo Windows arkitekturatarako diseinaturiko bertsioetan bakarrik ezarri daiteke:%n%n%1 +MissingWOW64APIs=Erabiltzen ari zaren Windows bertsioak ez du Ezartzaileak 64-biteko ezarpen bat egiteko behar dituen eginkizunak barneratzen. Arazo hau zuzentzeko, mesedez ezarri Service Pack %1. +WinVersionTooLowError=Programa honek %1 bertsioa %2 edo berriagoa behar du. +WinVersionTooHighError=Programa hau ezin da %1 bertsioa %2 edo berriagoan ezarria izan. +AdminPrivilegesRequired=Administrari bezala izena-emanda egon behar zara programa hau ezartzeko. +PowerUserPrivilegesRequired=Administrari bezala izena-emanda edo Boteredun Erabiltzaile taldeko kide bezala egon behar zara programa hau ezartzerakoan. +SetupAppRunningError=Ezartzaileak %1 ekinean dagoela atzeman du.%n%nMesedez itxi bere eskabide guztiak orain, orduan klikatu Ongi jarritzeko, edo Ezeztatu irtetzeko. +UninstallAppRunningError=Kentzaileak %1 ekinean dagoela atzeman du.%n%nMesedez itxi bere eskabide guztiak orain, orduan klikatu Ongi jarritzeko, edo Ezeztatu irtetzeko. + +; *** Misc. errors +ErrorCreatingDir=Ezartzaileak ezin izan du zuzenbidea sortu "%1" +ErrorTooManyFilesInDir=Ezinezkoa agiri bat sortzea "%1" zuzenbidean agiri gehiegi dituelako + +; *** Setup common messages +ExitSetupTitle=Irten Ezartzailetik +ExitSetupMessage=Ezarpena ez dago osatuta. Orain irtetzen bazara, programa ez da ezarriko.%n%nEzartzailea berriro edonoiz abiatu dezakezu ezarpena osatzeko.%n%nIrten Ezartzailetik? +AboutSetupMenuItem=&Ezartzaileari buruz... +AboutSetupTitle=Ezartzaileari buruz +AboutSetupMessage=%1 bertsioa %2%n%3%n%n%1 webgunea:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< &Atzera +ButtonNext=&Hurrengoa > +ButtonInstall=&Ezarri +ButtonOK=Ongi +ButtonCancel=Ezeztatu +ButtonYes=&Bai +ButtonYesToAll=Bai &Guztiari +ButtonNo=&Ez +ButtonNoToAll=E&z Guztiari +ButtonFinish=A&maitu +ButtonBrowse=&Bilatu... +ButtonWizardBrowse=B&ilatu... +ButtonNewFolder=Egi&n Agiritegi Berria + +; *** "Select Language" dialog messages +SelectLanguageTitle=Hautatu Ezarpen Hizkuntza +SelectLanguageLabel=Hautatu ezarpenean zehar erabiltzeko hizkuntza: + +; *** Common wizard text +ClickNext=Klikatu Hurrengoa jarraitzeko, edo Ezeztatu Ezartzailetik irtetzeko +BeveledLabel= +BrowseDialogTitle=Bilatu Agiritegia +BrowseDialogLabel=Hautatu agiritegi bat azpiko zerrendan, orduan klikatu Ongi +NewFolderName=Agiritegi Berria + +; *** "Welcome" wizard page +WelcomeLabel1=Ongi etorria [name] Ezarpen Laguntzailera +WelcomeLabel2=Honek [name/ver] zure ordenagailuan ezarriko du.%n%nGomendagarria da beste aplikazio guztiak istea jarraitu aurretik. + +; *** "Password" wizard page +WizardPassword=Sarhitza +PasswordLabel1=Ezarpen hau sarhitzez babestuta dago. +PasswordLabel3=Mesedez eman sarhitza, orduan klikatu Hurrengoa jarraitzeko. Sarhitzek hizki larri-xeheak bereizten dituzte. +PasswordEditLabel=&Sarhitza: +IncorrectPassword=Eman duzun sarhitza ez da zuzena. Mesedez saiatu berriro. + +; *** "License Agreement" wizard page +WizardLicense=Baimen Ituna +LicenseLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. +LicenseLabel3=Mesedez irakurri hurrengo Baimen Ituna. Itun honen baldintzak onartu behar dituzu ezarpenarekin jarraitu aurretik. +LicenseAccepted=&Onartzen dut ituna +LicenseNotAccepted=&Ez dut onartzen ituna + +; *** "Information" wizard pages +WizardInfoBefore=Argibideak +InfoBeforeLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. +InfoBeforeClickLabel=Ezarpenarekin jarraitzeko gertu zaudenean, klikatu Hurrengoa. +WizardInfoAfter=Argibideak +InfoAfterLabel=Mesedez irakurri hurrengo argibide garrantzitsuak jarraitu aurretik. +InfoAfterClickLabel=Ezarpenarekin jarraitzeko gertu zaudenean, klikatu Hurrengoa. + +; *** "User Information" wizard page +WizardUserInfo=Erabailtzaile Argibideak +UserInfoDesc=Mesedez sartu zure argibideak +UserInfoName=&Erabiltzaile Izena: +UserInfoOrg=&Antolakundea: +UserInfoSerial=&Serie Zenbakia: +UserInfoNameRequired=Izen bat sartu behar duzu. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Hautatu Helmuga Kokalekua +SelectDirDesc=Non ezarri behar da [name]? +SelectDirLabel3=Ezartzaileak [name] hurrengo agiritegian ezarriko du. +SelectDirBrowseLabel=Jarraitzeko, klikatu Hurrengoa. Beste agiritegi bat hautatzea nahi baduzu, klikatu Bilatu. +DiskSpaceMBLabel=Gutxienez [mb] MB-eko toki askea behar da diska gogorrean. +CannotInstallToNetworkDrive=Ezarpena ezin da sare gidagailu batean egin. +CannotInstallToUNCPath=Ezarpena ezin da UNC helburu batean egin. +InvalidPath=Helburu osoa gidagailu hizkiarekin sartu behar duzu; adibidez:%n%nC:\APP%n%nedo UNC helburu bat forma honetan:%n%n\\server\share +InvalidDrive=Hautatu duzun gidagailua edo UNC elkarbanaketa ez dago edo sarbidea ezinezkoa da. Mesedez hautatu beste bat. +DiskSpaceWarningTitle=Ez Dago Nahikoa Toki Diskan +DiskSpaceWarning=Ezarpenak gutxienez %1 KB-eko toki askea behar du ezartzeko, baina hautaturiko gidagailuak %2 KB bakarrik ditu eskuragarri.%n%nHorrela ere jarraitzea nahi duzu? +DirNameTooLong=Agiritegi izena edo helburua luzeegia da. +InvalidDirName=Agiritegi izena ez da baliozkoa. +BadDirName32=Agiritegi izenek ezin dute hurrengo hizkietako bat ere izan:%n%n%1 +DirExistsTitle=Agiritegia Badago +DirExists=Agiritegia:%n%n%1%n%njadanik badago. Horrela ere agiritegi horretan ezartzea nahi duzu? +DirDoesntExistTitle=Agiritegia Ez Dago +DirDoesntExist=Agiritegia:%n%n%1%n%nez dago. Nahi duzu agiritegia sortzea? + +; *** "Select Components" wizard page +WizardSelectComponents=Hautatu Osagaiak +SelectComponentsDesc=Zer osagai ezarri behar dira? +SelectComponentsLabel2=Hautatu ezartzea nahi dituzun osagaiak; garbitu ezartzea nahi ez dituzun osagaiak. Klikatu Hurrengoa jarraitzeko gertu zaudenean. +FullInstallation=Ezarpen osoa +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Ezarpen trinkoa +CustomInstallation=Norbere ezarpena +NoUninstallWarningTitle=Osagaiak Badaude +NoUninstallWarning=Ezartzaileak atzeman du hurrengo osagaiak jadanik zure ordenagailuan ezarrita daudela:%n%n%1%n%nOsagai hauek deshautatuz gero ez dira ezarriko.%n%nHorrela ere jarraitzea nahi duzu? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel=Oraingo hautapenak gutxienez [mb] MB-eko tokia behar du diskan. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Hautatu Eginkizun Gehigarriak +SelectTasksDesc=Zer eginkizun gehigarri burutu behar dira? +SelectTasksLabel2=Hautatu Ezartzaileak [name]-ren ezarpenean zehar burutzea nahi dituzun eginkizun gehigarriak, orduan klikatu Hurrengoa + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Hautatu Hasiera Menuko Agiritegia +SelectStartMenuFolderDesc=Non ezarri behar ditu Ezartzaileak programaren lasterbideak? +SelectStartMenuFolderLabel3=Ezartzaileak programaren lasterbideak hurrengo Hasiera Menuko agiritegian sortuko ditu. +SelectStartMenuFolderBrowseLabel=Jarraitzeko, klikatu Hurrengoa. Beste agiritegi bat hautatzea nahi baduzu, klikatu Bilatu. +MustEnterGroupName=Agiritegi izen bat sartu behar duzu. +GroupNameTooLong=Agiritegi izena edo helburua luzeegia da. +InvalidGroupName=Agiritegi izena ez da baliozkoa. +BadGroupName=Agiritegi izenak ezin du hurrengo hizkietako bat ere izan:%n%n%1 +NoProgramGroupCheck2=&Ez sortu Hasiera Menuko agiritegia + +; *** "Ready to Install" wizard page +WizardReady=Ezartzeko Gertu +ReadyLabel1=Ezartzailea orain gertu dago [name] zure ordenagailuan ezartzeko. +ReadyLabel2a=Klikatu Ezarri ezarpenarekin jarraitzeko, edo klikatu Atzera ezarpenen bat berrikustea edo aldatzea nahi baduzu. +ReadyLabel2b=Klikatu Ezarri ezarpenarekin jarraitzeko. +ReadyMemoUserInfo=Erabiltzaile argibideak: +ReadyMemoDir=Helmuga kokalekua: +ReadyMemoType=Ezarpen mota: +ReadyMemoComponents=Hautaturiko osagaiak: +ReadyMemoGroup=Hasiera Menuko agiritegia: +ReadyMemoTasks=Eginkizun gehigarriak: + +; *** "Preparing to Install" wizard page +WizardPreparing=Ezartzeko Gertatzen +PreparingDesc=Ezartzailea [name] zure ordenagailuan ezartzeko gertatzen ari da. +PreviousInstallNotCompleted=Aurreko programaren ezartze/kentzea ez dago osatuta. Zure ordenagailua berrabiarazi behar duzu ezarpena osatzeko.%n%nZure ordenagailua berrabiarazi ondoren, ekin Ezartzailea berriro [name]-ren ezarpena osatzeko. +CannotContinue=Ezarpenak ezin du jarraitu. Mesedez klikatu Ezeztatu irtetzeko. +ApplicationsFound=Hurrengo aplikazioak Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari dira. Gomendagarria da Ezartzaileari aplikazio hauek berezgaitasunez istea ahalbidetzea. +ApplicationsFound2=Hurrengo aplikazioak Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari dira. Gomendagarria da Ezartzaileari aplikazio hauek berezgaitasunez istea ahalbidetzea. Ezarpena osatu ondoren, Ezartzailea aplikazioak berrabiarazten saiatuko da. +CloseApplications=&Berezgaitasunez itxi aplikazioak +DontCloseApplications=&Ez itxi aplikazioak +ErrorCloseApplications=Ezartzaileak ezin ditu berezgaitasunez aplikazio guztiak itxi. Gomendagarria da Ezartzaileak eguneratu behar dituen agiriak erabiltzen ari diren aplikazio guztiak istea jarraitu aurretik. + +; *** "Installing" wizard page +WizardInstalling=Ezartzen +InstallingLabel=Mesedez itxaron Ezartzaileak [name] zure ordenagailuan ezartzen duen bitartean. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name] Ezarpen Laguntzailea osatzen +FinishedLabelNoIcons=Ezartzaileak amaitu du [name] zure ordenagailuan ezartzeaz. +FinishedLabel=Ezartzaileak amaitu du [name] zure ordenagailuan ezartzea. Aplikazioa ezarritako ikurren bidez abiarazi daiteke. +ClickFinish=Klikatu Amaitu Ezartzailetik irtetzeko. +FinishedRestartLabel=[name]-ren ezarpena osatzeko, Ezartzaileak zure ordenagailua berrabiarazi behar du. Orain berrabiaraztea nahi duzu? +FinishedRestartMessage=[name]-ren ezarpena osatzeko, Ezartzaileak zure ordenagailua berrabiarazi behar du.%n%nOrain berrabiaraztea nahi duzu? +ShowReadmeCheck=Bai, IRAKURRI agiria ikustea nahi dut +YesRadio=&Bai, berrabiarazi ordenagailua orain +NoRadio=&Ez, geroago berrabiaraziko dut ordenagailua +; used for example as 'Run MyProg.exe' +RunEntryExec=Ekin %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Ikusi %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Ezarpenak Hurrengo Diska Behar Du +SelectDiskLabel2=Mesedez txertatu %1 Diska eta klikatu Ongi.%n%nDiska honetako agiriak azpian erakutsitakoa ez den beste agiritegi batean aurkitu badaitezke, sartu helburu zuzena edo klikatu Bilatu. +PathLabel=&Helburua: +FileNotInDir2="%1" agiria ezin da hemen aurkitu: "%2". Mesedez txertatu diska zuzena edo hautatu beste agiritegi bat. +SelectDirectoryLabel=Mesedez adierazi hurrengo diskaren kokalekua. + +; *** Installation phase messages +SetupAborted=Ezarpena ez da osatu.%n%nMesedez zuzendu arazoa eta ekin Ezartzailea berriro. +EntryAbortRetryIgnore=Klikatu Bersaiatu berriro saiatzeko, Ezikusi horrela ere jarraitzeko, edo Utzi ezarpena ezeztatzeko. + +; *** Installation status messages +StatusClosingApplications=Aplikazioak isten... +StatusCreateDirs=Zuzenbideak sortzen... +StatusExtractFiles=Agiriak ateratzen... +StatusCreateIcons=Lasterbideak sortzen... +StatusCreateIniEntries=INI sarrerak sortzen... +StatusCreateRegistryEntries=Erregistro sarrerak sortzen... +StatusRegisterFiles=Agiriak erregistratzen... +StatusSavingUninstall=Kentze argibideak gordetzen... +StatusRunProgram=Ezarpena amaitzen... +StatusRestartingApplications=Aplikazioak berrabiarazten... +StatusRollback=Aldaketak leheneratzen... + +; *** Misc. errors +ErrorInternal2=Barneko akatsa: %1 +ErrorFunctionFailedNoCode=%1 hutsegitea +ErrorFunctionFailed=%1 hutsegitea; kodea %2 +ErrorFunctionFailedWithMessage=%1 hutsegitea; kodea %2.%n%3 +ErrorExecutingProgram=Ezinezkoa agiria exekutatzea:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Akatsa erregistro giltza irekitzerakoan:%n%1\%2 +ErrorRegCreateKey=Akatsa erregistro giltza sortzerakoan:%n%1\%2 +ErrorRegWriteKey=Akatsa erregistro giltza idazterakoan:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Akatsa INI sarrera "%1" agirian sortzerakoan. + +; *** File copying errors +FileAbortRetryIgnore=Klikatu Bersaiatu berriro saitzeko, Ezikusi agiri hau jauzteko (ez da gomendatua), edo Utzi ezarpena ezeztatzeko. +FileAbortRetryIgnore2=Klikatu Bersaiatu berriro saitzeko, Ezikusi horrela ere jarraitzeko (ez da gomendatua), edo Utzi ezarpena ezeztatzeko. +SourceIsCorrupted=Iturburu agiria hondatuta dago. +SourceDoesntExist="%1" iturburu agiria ez dago +ExistingFileReadOnly=Dagoen agiria irakurtzeko-bakarrik bezala markatuta dago.%n%nKlikatu Bersaiatu irakurtzeko-bakarrik ezaugarria kentzeko eta saiatu berriro, Ezikusi agiri hau jauzteko, edo Utzi ezarpena ezeztatzeko. +ErrorReadingExistingDest=Akats bat gertatu da dagoen agiria irakurtzen saiatzerakoan: +FileExists=Agiria jadanik badago.%n%nNahi duzu Ezartzaileak gainidaztea? +ExistingFileNewer=Dagoen agiria Ezartzailea ezartzen saiatzen ari dena baino berriagoa da. Gomendagarria da dagoen agiriari heustea.%n%nDagoen agiriari heustea nahi diozu? +ErrorChangingAttr=Akats bat gertatu da dagoen agiriaren ezaugarriak aldatzen saiatzerakoan: +ErrorCreatingTemp=Akats bat gertatu da helmuga zuzenbidean agiri bat sortzen saiatzerakoan: +ErrorReadingSource=Akats bat gertatu da iturburu agiria irakurtzen saiatzerakoan: +ErrorCopying=Akats bat gertatu da agiri bat kopiatzen saiatzerakoan: +ErrorReplacingExistingFile=Akats bat gertatu da dagoen agiria ordezten saiatzerakoan: +ErrorRestartReplace=Berrabiarazte-Ordezte hutsegitea: +ErrorRenamingTemp=Akats bat gertatu da helmuga zuzenbideko agiri bat berrizendatzen saiatzerakoan: +ErrorRegisterServer=Ezinezkoa DLL/OCX erregistratzea: %1 +ErrorRegSvr32Failed=RegSvr32 hutsegitea %1 irteera kodearekin +ErrorRegisterTypeLib=Ezinezkoa liburutegi mota erregistratzea: %1 + +; *** Post-installation errors +ErrorOpeningReadme=Akats bat gertatu da IRAKURRI agiria irekitzen saiatzerakoan. +ErrorRestartingComputer=Ezartzaileak ezin du ordenagailua berrabiarazi. Mesedez egin hau eskuz. + +; *** Uninstaller messages +UninstallNotFound="%1" agiria ez dago. Ezinezkoa kentzea +UninstallOpenError="%1" agiria ezin da ireki. Ezinezkoa kentzea +UninstallUnsupportedVer="%1" kentze ohar agiria kentzaile bertsio honek ezagutzen ez duen heuskarri batean dago. Ezinezkoa kentzea. +UninstallUnknownEntry=Sarrera ezezagun bat (%1) aurkitu da kentze oharrean +ConfirmUninstall=Zihur zaude %1 eta bere osagai guztiak erabat kentzea nahi dituzula? +UninstallOnlyOnWin64=Ezarpen hau 64-biteko Windows-etik bakarrik kendu daiteke. +OnlyAdminCanUninstall=Ezarpen hau administrari pribilegioak dituen erabiltzaile batek bakarrik kendu dezake. +UninstallStatusLabel=Mesedez itxaron %1 zure ordenagailutik kentzen den bitartean. +UninstalledAll=%1 ongi kendu da zure ordenagailutik. +UninstalledMost=%1-ren kentzea osatuta.%n%nZenbait gai ezin izan dira kendu. Hauek eskuz kendu daitezke. +UninstalledAndNeedsRestart=%1-ren kentzea osatzeko, zure ordenagailua berrabiarazi behar duzu.%n%nOrain berrabiaraztea nahi duzu? +UninstallDataCorrupted="%1" agiria hondatuta da. Ezinezkoa kentzea + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Ezabatu Agiri Elkarbanatua? +ConfirmDeleteSharedFile2=Sistemaren arabera hurrengo agiri elkarbanatua ez du inongo programak erabiliko hemendik aurrera. Kentzaileak agiri hau ezabatu dezan nahi duzu?%n%nProgramaren bat agiri hau erabiltzen ari da oraindik eta ezabatzen baduzu, programa hori ez da egoki ibiliko. Zihur ez bazaude, hautatu Ez. Agiria sisteman uzteak ez du inongo kalterik eragingo. +SharedFileNameLabel=Agiri izena: +SharedFileLocationLabel=Kokalekua: +WizardUninstalling=Kentze Egoera +StatusUninstalling=Kentzen %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Ezartzen %1. +ShutdownBlockReasonUninstallingApp=Kentzen %1. +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] +;Inno Setup Built-in Custom Messages +NameAndVersion=%1 %2 bertsioa +AdditionalIcons=Ikur gehigarriak: +CreateDesktopIcon=Sortu &mahaigain ikurra +CreateQuickLaunchIcon=Sortu &Abiarazpen Azkarreko ikurra +ProgramOnTheWeb=%1 Webean +UninstallProgram=Kendu %1 +LaunchProgram=Abiarazi %1 +AssocFileExtension=&Elkartu %1 programa %2 agiri luzapenarekin +AssocingFileExtension=%1 programa %2 agiri luzapenarekin elkartzen... +AutoStartProgramGroupDescription=Abirazpena: +AutoStartProgram=Berezgaitasunez abiarazi %1 +AddonHostProgramNotFound=%1 ezin da aurkitu hautatu duzun agiritegian.%n%nHorrela ere jarraitzea nahi duzu? diff --git a/distrib/Languages/Belarusian.isl b/distrib/Languages/Belarusian.isl index 9bd129cd837..25f616df81b 100644 --- a/distrib/Languages/Belarusian.isl +++ b/distrib/Languages/Belarusian.isl @@ -1,319 +1,319 @@ -; *** Inno Setup version 5.5.3+ Belarusian messages *** -; -; Translated by Aleg Azarousky, http://belazar.info/belsoft/ -; E-mail: olegtut@tut.by - -[LangOptions] -LanguageName=<0411><0435><043B><0430><0440><0443><0441><043A><0430><044F> -LanguageID=$0423 -LanguageCodePage=1251 - -[Messages] - -; *** Application titles -SetupAppTitle= -SetupWindowTitle= %1 -UninstallAppTitle= -UninstallAppFullTitle= %1 - -; *** Misc. common -InformationTitle= -ConfirmTitle= -ErrorTitle= - -; *** SetupLdr messages -SetupLdrStartupMessage= %1. ? -LdrCannotCreateTemp= . -LdrCannotExecTemp= . 븢 - -; *** Startup error messages -LastErrorMessage=%1.%n%n %2: %3 -SetupFileMissing= %1 . , , . -SetupFileCorrupt= 븢 . , . -SetupFileCorruptOrWrongVer= 븢 븢. , , . -InvalidParameter= :%n%n%1 -SetupAlreadyRunning= . -WindowsVersionNotSupported= Windows . -WindowsServicePackRequired= %1 Service Pack %2 . -NotOnThisPlatform= %1. -OnlyOnThisPlatform= %1. -OnlyOnTheseArchitectures= Windows :%n%n%1 -MissingWOW64APIs= Windows 64- . , (Service Pack) %1. -WinVersionTooLowError= %1 %2 . -WinVersionTooHighError= %1 %2 . -AdminPrivilegesRequired= , . -PowerUserPrivilegesRequired= , . -SetupAppRunningError=, %1!%n%n , , - . -UninstallAppRunningError=, %1!%n%n , , , - . - -; *** Misc. errors -ErrorCreatingDir= %1 -ErrorTooManyFilesInDir= %1, - -; *** Setup common messages -ExitSetupTitle= -ExitSetupMessage= . , .%n%n 븢 , .%n%n 븢? -AboutSetupMenuItem= ... -AboutSetupTitle= -AboutSetupMessage=%1, %2%n%3%n%n %1:%n%4 -AboutSetupNote= -TranslatorNote=Belarusian translation by Aleg Azarousky, http://belazar.info/belsoft/ - -; *** Buttons -ButtonBack=< & -ButtonNext=& > -ButtonInstall=& -ButtonOK= -ButtonCancel= -ButtonYes=& -ButtonYesToAll= & -ButtonNo=& -ButtonNoToAll=& -ButtonFinish= -ButtonBrowse=&... -ButtonWizardBrowse=&... -ButtonNewFolder=& - -; *** "Select Language" dialog messages -SelectLanguageTitle= 븢 -SelectLanguageLabel= : - -; *** Common wizard text -ClickNext= , - . -BeveledLabel=InnoSetup -BrowseDialogTitle= -BrowseDialogLabel= . -NewFolderName= - -; *** "Welcome" wizard page -WelcomeLabel1= [name] -WelcomeLabel2= [name/ver] .%n%n , . - -; *** "Password" wizard page -WizardPassword= -PasswordLabel1=븢 . -PasswordLabel3= , . . -PasswordEditLabel=&: -IncorrectPassword=ճ . . - -; *** "License Agreement" wizard page -WizardLicense=˳ -LicenseLabel= , , . -LicenseLabel3= , . . -LicenseAccepted= & -LicenseNotAccepted= & - -; *** "Information" wizard pages -WizardInfoBefore= -InfoBeforeLabel= . -InfoBeforeClickLabel= , . -WizardInfoAfter= -InfoAfterLabel= . -InfoAfterClickLabel= , . - -; *** "User Information" wizard page -WizardUserInfo= -UserInfoDesc= , . -UserInfoName= : -UserInfoOrg=&: -UserInfoSerial=& : -UserInfoNameRequired= . - -; *** "Select Destination Location" wizard page -WizardSelectDir= -SelectDirDesc= [name]? -SelectDirLabel3= [name] : -SelectDirBrowseLabel= . , . -DiskSpaceMBLabel= [mb] . -CannotInstallToNetworkDrive= . -CannotInstallToUNCPath= UNC-. -InvalidPath= , :%n%nC:\APP%n%n UNC:%n%n\\\ -InvalidDrive= . , . -DiskSpaceWarningTitle= -DiskSpaceWarning=븢 %1 , %2 .%n%n ? -DirNameTooLong= . -InvalidDirName= . -BadDirName32= :%n%n%1 -DirExistsTitle= -DirExists=:%n%n%1%n%n . ? -DirDoesntExistTitle= -DirDoesntExist=:%n%n%1%n%n . ? - -; *** "Select Components" wizard page -WizardSelectComponents= -SelectComponentsDesc= ? -SelectComponentsLabel2= , 븢; . , . -FullInstallation= -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation= -CustomInstallation= -NoUninstallWarningTitle= -NoUninstallWarning=, :%n%n%1%n%n , .%n%n ? -ComponentSize1=%1 -ComponentSize2=%1 -ComponentsDiskSpaceMBLabel= [mb] . - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks= -SelectTasksDesc= ? -SelectTasksLabel2= , [name], . - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup= -SelectStartMenuFolderDesc= , . -SelectStartMenuFolderLabel3= . -SelectStartMenuFolderBrowseLabel= - . - . -MustEnterGroupName= . -GroupNameTooLong= . -InvalidGroupName= . -BadGroupName= :%n%n%1 -NoProgramGroupCheck2=& - -; *** "Ready to Install" wizard page -WizardReady= -ReadyLabel1= [name] . -ReadyLabel2a= , - . -ReadyLabel2b= . -ReadyMemoUserInfo= : -ReadyMemoDir= : -ReadyMemoType= 븢: -ReadyMemoComponents= : -ReadyMemoGroup= : -ReadyMemoTasks= : - -; *** "Preparing to Install" wizard page -WizardPreparing= -PreparingDesc= [name] . -PreviousInstallNotCompleted= . , .%n%n 븢 , [name]. -CannotContinue= . . -ApplicationsFound= , 븢 . 븢 . -ApplicationsFound2= , 븢 . 븢 . , 븢 . -CloseApplications=& -DontCloseApplications=& -ErrorCloseApplications=븢 . , , . - -; *** "Installing" wizard page -WizardInstalling= -InstallingLabel=, [name] 븢 . - -; *** "Setup Completed" wizard page -FinishedHeadingLabel= [name]. -FinishedLabelNoIcons= [name] . -FinishedLabel= [name] . . -ClickFinish= , 븢. -FinishedRestartLabel= [name] . ? -FinishedRestartMessage= [name] .%n%n ? -ShowReadmeCheck= -YesRadio=&, -NoRadio=&, -; used for example as 'Run MyProg.exe' -RunEntryExec= %1 -; used for example as 'View Readme.txt' -RunEntryShellExec= %1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle= -SelectDiskLabel2= %1 .%n%n , , , . -PathLabel=&: -FileNotInDir2= %1 %2. . -SelectDirectoryLabel= . - -; *** Installation phase messages -SetupAborted= .%n%n , 븢 -EntryAbortRetryIgnore= , , - , - . - -; *** Installation status messages -StatusClosingApplications= ... -StatusCreateDirs= ... -StatusExtractFiles= ... -StatusCreateIcons= ... -StatusCreateIniEntries= INI-... -StatusCreateRegistryEntries= ... -StatusRegisterFiles= ... -StatusSavingUninstall= ... -StatusRunProgram= ... -StatusRestartingApplications= ... -StatusRollback= ... - -; *** Misc. errors -ErrorInternal2= %1 -ErrorFunctionFailedNoCode=%1: -ErrorFunctionFailed=%1: ; %2 -ErrorFunctionFailedWithMessage=%1: ; %2.%n%3 -ErrorExecutingProgram= :%n%1 - -; *** Registry errors -ErrorRegOpenKey= :%n%1\%2 -ErrorRegCreateKey= :%n%1\%2 -ErrorRegWriteKey= :%n%1\%2 - -; *** INI errors -ErrorIniEntry= INI- %1. - -; *** File copying errors -FileAbortRetryIgnore= , , - ( ), - . -FileAbortRetryIgnore2= , , - ( ), - . -SourceIsCorrupted= . -SourceDoesntExist= %1 . -ExistingFileReadOnly= .%n%n , , - , - . -ErrorReadingExistingDest= : -FileExists= .%n%n ? -ExistingFileNewer= , 븢. .%n%n ? -ErrorChangingAttr= : -ErrorCreatingTemp= : -ErrorReadingSource= : -ErrorCopying= : -ErrorReplacingExistingFile= : -ErrorRestartReplace= : -ErrorRenamingTemp= : -ErrorRegisterServer= DLL/OCX: %1 -ErrorRegSvr32Failed= RegSvr32, %1 -ErrorRegisterTypeLib= : %1 - -; *** Post-installation errors -ErrorOpeningReadme= README: -ErrorRestartingComputer=븢 . . - -; *** Uninstaller messages -UninstallNotFound= %1 , . -UninstallOpenError= %1, . -UninstallUnsupportedVer= %1 븢. . -UninstallUnknownEntry= (%1) -ConfirmUninstall= %1 ? -UninstallOnlyOnWin64= 64- Windows. -OnlyAdminCanUninstall= . -UninstallStatusLabel=, %1 . -UninstalledAll= %1 . -UninstalledMost= %1 .%n%n . . -UninstalledAndNeedsRestart= %1, .%n%nֳ ? -UninstallDataCorrupted= %1 . . - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle= ? -ConfirmDeleteSharedFile2=ѳ , . ?%n%n , , . - . . -SharedFileNameLabel= : -SharedFileLocationLabel=: -WizardUninstalling= -StatusUninstalling= %1... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp= %1. -ShutdownBlockReasonUninstallingApp= %1. - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] - -NameAndVersion=%1, %2 -AdditionalIcons= : -CreateDesktopIcon= & -CreateQuickLaunchIcon= & -ProgramOnTheWeb= %1 -UninstallProgram= %1 -LaunchProgram= %1 -AssocFileExtension=& %1 %2 -AssocingFileExtension= %1 %2... -AutoStartProgramGroupDescription=: -AutoStartProgram= %1 -AddonHostProgramNotFound=%1 .%n%n ? +; *** Inno Setup version 5.5.3+ Belarusian messages *** +; +; Translated by Aleg Azarousky, http://belazar.info/belsoft/ +; E-mail: olegtut@tut.by + +[LangOptions] +LanguageName=<0411><0435><043B><0430><0440><0443><0441><043A><0430><044F> +LanguageID=$0423 +LanguageCodePage=1251 + +[Messages] + +; *** Application titles +SetupAppTitle= +SetupWindowTitle= %1 +UninstallAppTitle= +UninstallAppFullTitle= %1 + +; *** Misc. common +InformationTitle= +ConfirmTitle= +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage= %1. ? +LdrCannotCreateTemp= . +LdrCannotExecTemp= . 븢 + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing= %1 . , , . +SetupFileCorrupt= 븢 . , . +SetupFileCorruptOrWrongVer= 븢 븢. , , . +InvalidParameter= :%n%n%1 +SetupAlreadyRunning= . +WindowsVersionNotSupported= Windows . +WindowsServicePackRequired= %1 Service Pack %2 . +NotOnThisPlatform= %1. +OnlyOnThisPlatform= %1. +OnlyOnTheseArchitectures= Windows :%n%n%1 +MissingWOW64APIs= Windows 64- . , (Service Pack) %1. +WinVersionTooLowError= %1 %2 . +WinVersionTooHighError= %1 %2 . +AdminPrivilegesRequired= , . +PowerUserPrivilegesRequired= , . +SetupAppRunningError=, %1!%n%n , , - . +UninstallAppRunningError=, %1!%n%n , , , - . + +; *** Misc. errors +ErrorCreatingDir= %1 +ErrorTooManyFilesInDir= %1, + +; *** Setup common messages +ExitSetupTitle= +ExitSetupMessage= . , .%n%n 븢 , .%n%n 븢? +AboutSetupMenuItem= ... +AboutSetupTitle= +AboutSetupMessage=%1, %2%n%3%n%n %1:%n%4 +AboutSetupNote= +TranslatorNote=Belarusian translation by Aleg Azarousky, http://belazar.info/belsoft/ + +; *** Buttons +ButtonBack=< & +ButtonNext=& > +ButtonInstall=& +ButtonOK= +ButtonCancel= +ButtonYes=& +ButtonYesToAll= & +ButtonNo=& +ButtonNoToAll=& +ButtonFinish= +ButtonBrowse=&... +ButtonWizardBrowse=&... +ButtonNewFolder=& + +; *** "Select Language" dialog messages +SelectLanguageTitle= 븢 +SelectLanguageLabel= : + +; *** Common wizard text +ClickNext= , - . +BeveledLabel=InnoSetup +BrowseDialogTitle= +BrowseDialogLabel= . +NewFolderName= + +; *** "Welcome" wizard page +WelcomeLabel1= [name] +WelcomeLabel2= [name/ver] .%n%n , . + +; *** "Password" wizard page +WizardPassword= +PasswordLabel1=븢 . +PasswordLabel3= , . . +PasswordEditLabel=&: +IncorrectPassword=ճ . . + +; *** "License Agreement" wizard page +WizardLicense=˳ +LicenseLabel= , , . +LicenseLabel3= , . . +LicenseAccepted= & +LicenseNotAccepted= & + +; *** "Information" wizard pages +WizardInfoBefore= +InfoBeforeLabel= . +InfoBeforeClickLabel= , . +WizardInfoAfter= +InfoAfterLabel= . +InfoAfterClickLabel= , . + +; *** "User Information" wizard page +WizardUserInfo= +UserInfoDesc= , . +UserInfoName= : +UserInfoOrg=&: +UserInfoSerial=& : +UserInfoNameRequired= . + +; *** "Select Destination Location" wizard page +WizardSelectDir= +SelectDirDesc= [name]? +SelectDirLabel3= [name] : +SelectDirBrowseLabel= . , . +DiskSpaceMBLabel= [mb] . +CannotInstallToNetworkDrive= . +CannotInstallToUNCPath= UNC-. +InvalidPath= , :%n%nC:\APP%n%n UNC:%n%n\\\ +InvalidDrive= . , . +DiskSpaceWarningTitle= +DiskSpaceWarning=븢 %1 , %2 .%n%n ? +DirNameTooLong= . +InvalidDirName= . +BadDirName32= :%n%n%1 +DirExistsTitle= +DirExists=:%n%n%1%n%n . ? +DirDoesntExistTitle= +DirDoesntExist=:%n%n%1%n%n . ? + +; *** "Select Components" wizard page +WizardSelectComponents= +SelectComponentsDesc= ? +SelectComponentsLabel2= , 븢; . , . +FullInstallation= +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation= +CustomInstallation= +NoUninstallWarningTitle= +NoUninstallWarning=, :%n%n%1%n%n , .%n%n ? +ComponentSize1=%1 +ComponentSize2=%1 +ComponentsDiskSpaceMBLabel= [mb] . + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks= +SelectTasksDesc= ? +SelectTasksLabel2= , [name], . + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup= +SelectStartMenuFolderDesc= , . +SelectStartMenuFolderLabel3= . +SelectStartMenuFolderBrowseLabel= - . - . +MustEnterGroupName= . +GroupNameTooLong= . +InvalidGroupName= . +BadGroupName= :%n%n%1 +NoProgramGroupCheck2=& + +; *** "Ready to Install" wizard page +WizardReady= +ReadyLabel1= [name] . +ReadyLabel2a= , - . +ReadyLabel2b= . +ReadyMemoUserInfo= : +ReadyMemoDir= : +ReadyMemoType= 븢: +ReadyMemoComponents= : +ReadyMemoGroup= : +ReadyMemoTasks= : + +; *** "Preparing to Install" wizard page +WizardPreparing= +PreparingDesc= [name] . +PreviousInstallNotCompleted= . , .%n%n 븢 , [name]. +CannotContinue= . . +ApplicationsFound= , 븢 . 븢 . +ApplicationsFound2= , 븢 . 븢 . , 븢 . +CloseApplications=& +DontCloseApplications=& +ErrorCloseApplications=븢 . , , . + +; *** "Installing" wizard page +WizardInstalling= +InstallingLabel=, [name] 븢 . + +; *** "Setup Completed" wizard page +FinishedHeadingLabel= [name]. +FinishedLabelNoIcons= [name] . +FinishedLabel= [name] . . +ClickFinish= , 븢. +FinishedRestartLabel= [name] . ? +FinishedRestartMessage= [name] .%n%n ? +ShowReadmeCheck= +YesRadio=&, +NoRadio=&, +; used for example as 'Run MyProg.exe' +RunEntryExec= %1 +; used for example as 'View Readme.txt' +RunEntryShellExec= %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle= +SelectDiskLabel2= %1 .%n%n , , , . +PathLabel=&: +FileNotInDir2= %1 %2. . +SelectDirectoryLabel= . + +; *** Installation phase messages +SetupAborted= .%n%n , 븢 +EntryAbortRetryIgnore= , , - , - . + +; *** Installation status messages +StatusClosingApplications= ... +StatusCreateDirs= ... +StatusExtractFiles= ... +StatusCreateIcons= ... +StatusCreateIniEntries= INI-... +StatusCreateRegistryEntries= ... +StatusRegisterFiles= ... +StatusSavingUninstall= ... +StatusRunProgram= ... +StatusRestartingApplications= ... +StatusRollback= ... + +; *** Misc. errors +ErrorInternal2= %1 +ErrorFunctionFailedNoCode=%1: +ErrorFunctionFailed=%1: ; %2 +ErrorFunctionFailedWithMessage=%1: ; %2.%n%3 +ErrorExecutingProgram= :%n%1 + +; *** Registry errors +ErrorRegOpenKey= :%n%1\%2 +ErrorRegCreateKey= :%n%1\%2 +ErrorRegWriteKey= :%n%1\%2 + +; *** INI errors +ErrorIniEntry= INI- %1. + +; *** File copying errors +FileAbortRetryIgnore= , , - ( ), - . +FileAbortRetryIgnore2= , , - ( ), - . +SourceIsCorrupted= . +SourceDoesntExist= %1 . +ExistingFileReadOnly= .%n%n , , - , - . +ErrorReadingExistingDest= : +FileExists= .%n%n ? +ExistingFileNewer= , 븢. .%n%n ? +ErrorChangingAttr= : +ErrorCreatingTemp= : +ErrorReadingSource= : +ErrorCopying= : +ErrorReplacingExistingFile= : +ErrorRestartReplace= : +ErrorRenamingTemp= : +ErrorRegisterServer= DLL/OCX: %1 +ErrorRegSvr32Failed= RegSvr32, %1 +ErrorRegisterTypeLib= : %1 + +; *** Post-installation errors +ErrorOpeningReadme= README: +ErrorRestartingComputer=븢 . . + +; *** Uninstaller messages +UninstallNotFound= %1 , . +UninstallOpenError= %1, . +UninstallUnsupportedVer= %1 븢. . +UninstallUnknownEntry= (%1) +ConfirmUninstall= %1 ? +UninstallOnlyOnWin64= 64- Windows. +OnlyAdminCanUninstall= . +UninstallStatusLabel=, %1 . +UninstalledAll= %1 . +UninstalledMost= %1 .%n%n . . +UninstalledAndNeedsRestart= %1, .%n%nֳ ? +UninstallDataCorrupted= %1 . . + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle= ? +ConfirmDeleteSharedFile2=ѳ , . ?%n%n , , . - . . +SharedFileNameLabel= : +SharedFileLocationLabel=: +WizardUninstalling= +StatusUninstalling= %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp= %1. +ShutdownBlockReasonUninstallingApp= %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1, %2 +AdditionalIcons= : +CreateDesktopIcon= & +CreateQuickLaunchIcon= & +ProgramOnTheWeb= %1 +UninstallProgram= %1 +LaunchProgram= %1 +AssocFileExtension=& %1 %2 +AssocingFileExtension= %1 %2... +AutoStartProgramGroupDescription=: +AutoStartProgram= %1 +AddonHostProgramNotFound=%1 .%n%n ? diff --git a/distrib/Languages/ChineseSimplified.isl b/distrib/Languages/ChineseSimplified.isl index 6029850d5cd..22c29815a0b 100644 --- a/distrib/Languages/ChineseSimplified.isl +++ b/distrib/Languages/ChineseSimplified.isl @@ -1,337 +1,337 @@ -; *** Inno Setup version 5.5.3+ Chinese (Simplified) messages *** -; By Qiming Li (qiming at clault.com) -; -; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ -; -; Note: When translating this text, do not add periods (.) to the end of -; messages that didn't have them already, because on those messages Inno -; Setup adds the periods automatically (appending a period would result in -; two periods being displayed). - -[LangOptions] -; The following three entries are very important. Be sure to read and -; understand the '[LangOptions] section' topic in the help file. -LanguageName=<4E2D><6587><7B80><4F53> -LanguageID=$0804 -LanguageCodePage=936 -; If the language you are translating to requires special font faces or -; sizes, uncomment any of the following entries and change them accordingly. -DialogFontName= -;DialogFontSize=8 -;WelcomeFontName=Verdana -;WelcomeFontSize=12 -;TitleFontName=Arial -;TitleFontSize=29 -;CopyrightFontName=Arial -;CopyrightFontSize=8 - -[Messages] - -; *** Application titles -SetupAppTitle=װ -SetupWindowTitle=װ - %1 -UninstallAppTitle=ж -UninstallAppFullTitle=%1ж - -; *** Misc. common -InformationTitle=Ϣ -ConfirmTitle=ȷ -ErrorTitle= - -; *** SetupLdr messages -SetupLdrStartupMessage=װ򵼽ĵϰװ%1ȷҪ -LdrCannotCreateTemp=޷ʱļװֹ -LdrCannotExecTemp=޷ʱļеļװֹ - -; *** Startup error messages -LastErrorMessage=%1.%n%n %2: %3 -SetupFileMissing=װĿ¼ȱʧļ%1⣬»ȡһݳ򿽱 -SetupFileCorrupt=װļѱ𻵡»ȡһݳ򿽱 -SetupFileCorruptOrWrongVer=װļѱ𻵣뱾װ򵼰汾ݡ⣬»ȡһݳ򿽱 -InvalidParameter=Чв%n%n%1 -SetupAlreadyRunning=װѾС -WindowsVersionNotSupported=֧еWindows汾 -WindowsServicePackRequired=Ҫ%1 Service Pack %2°汾 -NotOnThisPlatform=򲻿%1С -OnlyOnThisPlatform=%1С -OnlyOnTheseArchitectures=ֻΪ´ܹƵWindows汾ϰװ%n%n%1 -MissingWOW64APIs=ʹõWindows汾ûа64λװĹܡ밲װService Pack %1⡣ -WinVersionTooLowError=Ҫ%2汾ϵ%1 -WinVersionTooHighError=򲻿ɰװ%2߰汾%1ϡ -AdminPrivilegesRequired=¼ΪԱܰװ˳ -PowerUserPrivilegesRequired=¼ΪԱȨûܰװ˳ -SetupAppRunningError=װ򵼼⵽%1С%n%nرдڲȷȡ˳װ -UninstallAppRunningError=ж򵼼⵽%1С%n%nرдڣȻȷȡ˳ - -; *** Misc. errors -ErrorCreatingDir=װ޷ļС%1 -ErrorTooManyFilesInDir=ļС%1ļ࣬޷дļ - -; *** Setup common messages -ExitSetupTitle=˳װ -ExitSetupMessage=װδɡ˳򽫲ᱻװ %n%n´аװɳİװ%n%nȷ˳װ -AboutSetupMenuItem=ڰװ(&A) -AboutSetupTitle=ڰװ -AboutSetupMessage=%1汾%2%n%3%n%n%1ҳ%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< һ(&B) -ButtonNext=һ(&N) > -ButtonInstall=װ(&I) -ButtonOK=ȷ -ButtonCancel=ȡ -ButtonYes=(&Y) -ButtonYesToAll=ȫѡ(&A) -ButtonNo=(&N) -ButtonNoToAll=ȫѡ(&O) -ButtonFinish=(&F) -ButtonBrowse=(&B) -ButtonWizardBrowse=(&R) -ButtonNewFolder=ļ(&M) - -; *** "Select Language" dialog messages -SelectLanguageTitle=ѡ -SelectLanguageLabel=ѡװʱʹԣ - -; *** Common wizard text -ClickNext=һȡ˳װ򵼡 -BeveledLabel= -BrowseDialogTitle=ѡļ -BrowseDialogLabel=бѡȡһļУȷ -NewFolderName=½ļ - -; *** "Welcome" wizard page -WelcomeLabel1=ӭʹ[name]װ -WelcomeLabel2=򵼽ĵϰװ[name/ver]%n%nڼ֮ǰرӦó - -; *** "Password" wizard page -WizardPassword= -PasswordLabel1=װ뱣 -PasswordLabel3=룬һִСд -PasswordEditLabel=(&P) -IncorrectPassword=벻ȷԡ - -; *** "License Agreement" wizard page -WizardLicense=Э -LicenseLabel=ĶҪϢȻٽһ -LicenseLabel3=ĶЭ顣ܴЭȻܼװ -LicenseAccepted=ҽЭ(&A) -LicenseNotAccepted=ҲЭ(&D) - -; *** "Information" wizard pages -WizardInfoBefore=Ϣ -InfoBeforeLabel=ĶҪϢٽһ -InfoBeforeClickLabel=׼üװ󣬵һ -WizardInfoAfter=Ϣ -InfoAfterLabel=ĶҪϢٽһ -InfoAfterClickLabel=׼üװ󣬵һ - -; *** "User Information" wizard page -WizardUserInfo=ûϢ -UserInfoDesc=Ϣ -UserInfoName=û(&U) -UserInfoOrg=(&O) -UserInfoSerial=к(&S) -UserInfoNameRequired=û - -; *** "Select Destination Location" wizard page -WizardSelectDir=ѡװλ -SelectDirDesc=[name]װδ -SelectDirLabel3=װ򵼽[name]װļС -SelectDirBrowseLabel=һҪѡͬļУ -DiskSpaceMBLabel=[mb]ֽڣMBô̿ռ䡣 -CannotInstallToNetworkDrive=޷װ -CannotInstallToUNCPath=޷װUNC· -InvalidPath=̷·磺%n%nC:\Ӧó%n%n¸ʽUNC·%n%n\\\Ŀ¼ -InvalidDrive=ѡUNCڻ򲻿ɷʡѡһ -DiskSpaceWarningTitle=̿ռ䲻 -DiskSpaceWarning=%1ǧֽڣKBÿռſɰװѡ%2ǧֽڣKBÿռ䡣%n%nȷҪ -DirNameTooLong=ļƻ·̫ -InvalidDirName=ļЧ -BadDirName32=ļƲַܰ%n%n%1 -DirExistsTitle=ļѴ -DirExists=ļ%n%n%1%n%nѴڡȷҪװļ -DirDoesntExistTitle=ļв -DirDoesntExist=ļ%n%n%1%n%nڡҪļ - -; *** "Select Components" wizard page -WizardSelectComponents=ѡ -SelectComponentsDesc=ҪװЩ -SelectComponentsLabel2=ѡҪװҪװ׼úһ -FullInstallation=ȫװ -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=లװ -CustomInstallation=Զ尲װ -NoUninstallWarningTitle=Ѵ -NoUninstallWarning=װ򵼼⵽Ѿװ%n%n%1%n%nȡѡжЩ%n%nȷҪװ -ComponentSize1=%1ǧֽڣKB -ComponentSize2=%1ֽڣMB -ComponentsDiskSpaceMBLabel=ĿǰѡҪ[mb]ֽڣMB̿ռ䡣 - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=ѡ񸽼 -SelectTasksDesc=ҪִЩ -SelectTasksLabel2=ѡװ[name]ʱҪִеĸȻһ - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=ѡʼ˵ļ -SelectStartMenuFolderDesc=ѳݷʽŵ -SelectStartMenuFolderLabel3=װ򵼽¿ʼ˵ļдݷʽ -SelectStartMenuFolderBrowseLabel=һҪѡһļУ -MustEnterGroupName=ļ -GroupNameTooLong=ļƻ·̫ -InvalidGroupName=ļЧ -BadGroupName=ļƲַܰ%n%n%1 -NoProgramGroupCheck2=Ҫʼ˵ļ(&D) - -; *** "Ready to Install" wizard page -WizardReady=װ׼ -ReadyLabel1=װ׼ϣʼĵϰװ[name] -ReadyLabel2a=װʼװҪȷϻһ -ReadyLabel2b=װʼװ -ReadyMemoUserInfo=ûϢ -ReadyMemoDir=װλã -ReadyMemoType=װͣ -ReadyMemoComponents=ѡ -ReadyMemoGroup=ʼ˵ļУ -ReadyMemoTasks= - -; *** "Preparing to Install" wizard page -WizardPreparing=׼װ -PreparingDesc=װ׼ĵϰװ[name] -PreviousInstallNotCompleted=ϴγװ/жδɡҪϴΰװ%n%n֮аװװ[name] -CannotContinue=װ޷ȡ˳ -ApplicationsFound=װҪµļӦóռáװԶرЩӦó -ApplicationsFound2=װҪµļӦóռáװԶرЩӦó򡣰װɺ󣬰װ򵼽ЩӦó -CloseApplications=ԶرӦó(&A) -DontCloseApplications=ԶرӦó(&D) -ErrorCloseApplications=װ޷ԶرеӦóڽһ֮ǰرЩռðװҪļӦó - -; *** "Installing" wizard page -WizardInstalling=ڰװ -InstallingLabel=Ժ򣬰װĵϰװ[name] - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=[name]װ -FinishedLabelNoIcons=װĵϰװ[name] -FinishedLabel=װĵϰװ[name]ͨѰװĿݷʽ򿪴Ӧó -ClickFinish=˳װ -FinishedRestartLabel=Ϊ[name]İװװ򵼱ĵԡҪ -FinishedRestartMessage=Ϊ[name]İװװ򵼱ĵԡ%n%nҪ -ShowReadmeCheck=ǣҪĶļ -YesRadio=ǣ(&Y) -NoRadio=Ժ(&N) -; used for example as 'Run MyProg.exe' -RunEntryExec=%1 -; used for example as 'View Readme.txt' -RunEntryShellExec=%1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=װҪһŴ -SelectDiskLabel2=%1 ȷ%n%nôеļʾļУȷ· -PathLabel=·(&P) -FileNotInDir2=ļ%1ڡ%2СȷĴ̻ѡļС -SelectDirectoryLabel=ָһŴ̵λá - -; *** Installation phase messages -SetupAborted=װδɡ%n%nаװ򵼡 -EntryAbortRetryIgnore=ԡ³ԣԡװֹȡװ - -; *** Installation status messages -StatusClosingApplications=ڹرӦó -StatusCreateDirs=ڴļС -StatusExtractFiles=ȡļ -StatusCreateIcons=ڴݷʽ -StatusCreateIniEntries=ڴINIĿ -StatusCreateRegistryEntries=ڴעĿ -StatusRegisterFiles=ڴעĿ -StatusSavingUninstall=ڱжϢ -StatusRunProgram=ڽװ -StatusRestartingApplications=Ӧó -StatusRollback=ڳġ - -; *** Misc. errors -ErrorInternal2=ڲ%1 -ErrorFunctionFailedNoCode=%1ʧ -ErrorFunctionFailed=%1ʧܣ%2 -ErrorFunctionFailedWithMessage=%1ʧܣ%2%n%3 -ErrorExecutingProgram=޷г%n%1 - -; *** Registry errors -ErrorRegOpenKey=עʱ%n%1\%2 -ErrorRegCreateKey=עʱ%n%1\%2 -ErrorRegWriteKey=дעʱ%n%1\%2 - -; *** INI errors -ErrorIniEntry=ļ%1дINIĿʱ - -; *** File copying errors -FileAbortRetryIgnore=ԡ³ԣԡļƼֹȡװ -FileAbortRetryIgnore2=ԡ³ԣԡװƼֹȡװ -SourceIsCorrupted=Դļ -SourceDoesntExist=Դļ%1 -ExistingFileReadOnly=ļΪֻ%n%nԡƳֻԲ³ԣԡļֹȡװ -ErrorReadingExistingDest=ȡļʱ -FileExists=ļѴڡ%n%nðװ򵼸 -ExistingFileNewer=ļȰװͼװĻҪ¡鱣ļ%n%nҪļ -ErrorChangingAttr=ļʱ -ErrorCreatingTemp=Ŀļдļʱ -ErrorReadingSource=ȡԴļʱ -ErrorCopying=ļʱ -ErrorReplacingExistingFile=滻ļʱ -ErrorRestartReplace=滻ʧܣ -ErrorRenamingTemp=ΪĿļļʱ -ErrorRegisterServer=޷עᶯ̬ؼDLL/OCX%1 -ErrorRegSvr32Failed=RegSvr32ʧܣ䷵ֵΪ%1 -ErrorRegisterTypeLib=޷עͿ⣺%1 - -; *** Post-installation errors -ErrorOpeningReadme=ļʱ -ErrorRestartingComputer=װ޷ԡֶ - -; *** Uninstaller messages -UninstallNotFound=ļ%1ڡ޷жء -UninstallOpenError=޷ļ%1޷ж -UninstallUnsupportedVer=˰汾ж޷ʶж־ļ%1ĸʽ޷ж -UninstallUnknownEntry=ж־δ֪Ŀ (%1) -ConfirmUninstall=ǷȷҪȫɾ%1 -UninstallOnlyOnWin64=˰װֻ64λWindowsжء -OnlyAdminCanUninstall=˰װֻɾ߱ԱȨ޵ûжء -UninstallStatusLabel=Ժɾ%1 -UninstalledAll=ѳɹشĵɾ%1 -UninstalledMost=%1жϡ%n%nijЩĿ޷жعɾֶɾЩĿ -UninstalledAndNeedsRestart=Ҫ%1жأԡ%n%nҪ -UninstallDataCorrupted=ļ%1𻵡޷ж - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=ɾļ -ConfirmDeleteSharedFile2=ϵͳʾûκγʹ¹ļҪɾùļ%n%nгʹøļɾЩ޷Сȷѡ񡰷񡱡¸ļϵͳκΣ -SharedFileNameLabel=ļ -SharedFileLocationLabel=λã -WizardUninstalling=ж״̬ -StatusUninstalling=ж%1 - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=ڰװ%1 -ShutdownBlockReasonUninstallingApp=ж%1 - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] - -NameAndVersion=%1汾%2 -AdditionalIcons=ӿݷʽ -CreateDesktopIcon=ݷʽ(&D) -CreateQuickLaunchIcon=ݷʽ(&Q) -ProgramOnTheWeb=%1վ -UninstallProgram=ж%1 -LaunchProgram=%1 -AssocFileExtension=%1%2ļչ(&A) -AssocingFileExtension=ڽ%1%2ļչ -AutoStartProgramGroupDescription= -AutoStartProgram=Զ%1 -AddonHostProgramNotFound=ѡļҲ%1%n%nǷȻ +; *** Inno Setup version 5.5.3+ Chinese (Simplified) messages *** +; By Qiming Li (qiming at clault.com) +; +; To download user-contributed translations of this file, go to: +; http://www.jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=<4E2D><6587><7B80><4F53> +LanguageID=$0804 +LanguageCodePage=936 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=װ +SetupWindowTitle=װ - %1 +UninstallAppTitle=ж +UninstallAppFullTitle=%1ж + +; *** Misc. common +InformationTitle=Ϣ +ConfirmTitle=ȷ +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage=װ򵼽ĵϰװ%1ȷҪ +LdrCannotCreateTemp=޷ʱļװֹ +LdrCannotExecTemp=޷ʱļеļװֹ + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing=װĿ¼ȱʧļ%1⣬»ȡһݳ򿽱 +SetupFileCorrupt=װļѱ𻵡»ȡһݳ򿽱 +SetupFileCorruptOrWrongVer=װļѱ𻵣뱾װ򵼰汾ݡ⣬»ȡһݳ򿽱 +InvalidParameter=Чв%n%n%1 +SetupAlreadyRunning=װѾС +WindowsVersionNotSupported=֧еWindows汾 +WindowsServicePackRequired=Ҫ%1 Service Pack %2°汾 +NotOnThisPlatform=򲻿%1С +OnlyOnThisPlatform=%1С +OnlyOnTheseArchitectures=ֻΪ´ܹƵWindows汾ϰװ%n%n%1 +MissingWOW64APIs=ʹõWindows汾ûа64λװĹܡ밲װService Pack %1⡣ +WinVersionTooLowError=Ҫ%2汾ϵ%1 +WinVersionTooHighError=򲻿ɰװ%2߰汾%1ϡ +AdminPrivilegesRequired=¼ΪԱܰװ˳ +PowerUserPrivilegesRequired=¼ΪԱȨûܰװ˳ +SetupAppRunningError=װ򵼼⵽%1С%n%nرдڲȷȡ˳װ +UninstallAppRunningError=ж򵼼⵽%1С%n%nرдڣȻȷȡ˳ + +; *** Misc. errors +ErrorCreatingDir=װ޷ļС%1 +ErrorTooManyFilesInDir=ļС%1ļ࣬޷дļ + +; *** Setup common messages +ExitSetupTitle=˳װ +ExitSetupMessage=װδɡ˳򽫲ᱻװ %n%n´аװɳİװ%n%nȷ˳װ +AboutSetupMenuItem=ڰװ(&A) +AboutSetupTitle=ڰװ +AboutSetupMessage=%1汾%2%n%3%n%n%1ҳ%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< һ(&B) +ButtonNext=һ(&N) > +ButtonInstall=װ(&I) +ButtonOK=ȷ +ButtonCancel=ȡ +ButtonYes=(&Y) +ButtonYesToAll=ȫѡ(&A) +ButtonNo=(&N) +ButtonNoToAll=ȫѡ(&O) +ButtonFinish=(&F) +ButtonBrowse=(&B) +ButtonWizardBrowse=(&R) +ButtonNewFolder=ļ(&M) + +; *** "Select Language" dialog messages +SelectLanguageTitle=ѡ +SelectLanguageLabel=ѡװʱʹԣ + +; *** Common wizard text +ClickNext=һȡ˳װ򵼡 +BeveledLabel= +BrowseDialogTitle=ѡļ +BrowseDialogLabel=бѡȡһļУȷ +NewFolderName=½ļ + +; *** "Welcome" wizard page +WelcomeLabel1=ӭʹ[name]װ +WelcomeLabel2=򵼽ĵϰװ[name/ver]%n%nڼ֮ǰرӦó + +; *** "Password" wizard page +WizardPassword= +PasswordLabel1=װ뱣 +PasswordLabel3=룬һִСд +PasswordEditLabel=(&P) +IncorrectPassword=벻ȷԡ + +; *** "License Agreement" wizard page +WizardLicense=Э +LicenseLabel=ĶҪϢȻٽһ +LicenseLabel3=ĶЭ顣ܴЭȻܼװ +LicenseAccepted=ҽЭ(&A) +LicenseNotAccepted=ҲЭ(&D) + +; *** "Information" wizard pages +WizardInfoBefore=Ϣ +InfoBeforeLabel=ĶҪϢٽһ +InfoBeforeClickLabel=׼üװ󣬵һ +WizardInfoAfter=Ϣ +InfoAfterLabel=ĶҪϢٽһ +InfoAfterClickLabel=׼üװ󣬵һ + +; *** "User Information" wizard page +WizardUserInfo=ûϢ +UserInfoDesc=Ϣ +UserInfoName=û(&U) +UserInfoOrg=(&O) +UserInfoSerial=к(&S) +UserInfoNameRequired=û + +; *** "Select Destination Location" wizard page +WizardSelectDir=ѡװλ +SelectDirDesc=[name]װδ +SelectDirLabel3=װ򵼽[name]װļС +SelectDirBrowseLabel=һҪѡͬļУ +DiskSpaceMBLabel=[mb]ֽڣMBô̿ռ䡣 +CannotInstallToNetworkDrive=޷װ +CannotInstallToUNCPath=޷װUNC· +InvalidPath=̷·磺%n%nC:\Ӧó%n%n¸ʽUNC·%n%n\\\Ŀ¼ +InvalidDrive=ѡUNCڻ򲻿ɷʡѡһ +DiskSpaceWarningTitle=̿ռ䲻 +DiskSpaceWarning=%1ǧֽڣKBÿռſɰװѡ%2ǧֽڣKBÿռ䡣%n%nȷҪ +DirNameTooLong=ļƻ·̫ +InvalidDirName=ļЧ +BadDirName32=ļƲַܰ%n%n%1 +DirExistsTitle=ļѴ +DirExists=ļ%n%n%1%n%nѴڡȷҪװļ +DirDoesntExistTitle=ļв +DirDoesntExist=ļ%n%n%1%n%nڡҪļ + +; *** "Select Components" wizard page +WizardSelectComponents=ѡ +SelectComponentsDesc=ҪװЩ +SelectComponentsLabel2=ѡҪװҪװ׼úһ +FullInstallation=ȫװ +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=లװ +CustomInstallation=Զ尲װ +NoUninstallWarningTitle=Ѵ +NoUninstallWarning=װ򵼼⵽Ѿװ%n%n%1%n%nȡѡжЩ%n%nȷҪװ +ComponentSize1=%1ǧֽڣKB +ComponentSize2=%1ֽڣMB +ComponentsDiskSpaceMBLabel=ĿǰѡҪ[mb]ֽڣMB̿ռ䡣 + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=ѡ񸽼 +SelectTasksDesc=ҪִЩ +SelectTasksLabel2=ѡװ[name]ʱҪִеĸȻһ + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=ѡʼ˵ļ +SelectStartMenuFolderDesc=ѳݷʽŵ +SelectStartMenuFolderLabel3=װ򵼽¿ʼ˵ļдݷʽ +SelectStartMenuFolderBrowseLabel=һҪѡһļУ +MustEnterGroupName=ļ +GroupNameTooLong=ļƻ·̫ +InvalidGroupName=ļЧ +BadGroupName=ļƲַܰ%n%n%1 +NoProgramGroupCheck2=Ҫʼ˵ļ(&D) + +; *** "Ready to Install" wizard page +WizardReady=װ׼ +ReadyLabel1=װ׼ϣʼĵϰװ[name] +ReadyLabel2a=װʼװҪȷϻһ +ReadyLabel2b=װʼװ +ReadyMemoUserInfo=ûϢ +ReadyMemoDir=װλã +ReadyMemoType=װͣ +ReadyMemoComponents=ѡ +ReadyMemoGroup=ʼ˵ļУ +ReadyMemoTasks= + +; *** "Preparing to Install" wizard page +WizardPreparing=׼װ +PreparingDesc=װ׼ĵϰװ[name] +PreviousInstallNotCompleted=ϴγװ/жδɡҪϴΰװ%n%n֮аװװ[name] +CannotContinue=װ޷ȡ˳ +ApplicationsFound=װҪµļӦóռáװԶرЩӦó +ApplicationsFound2=װҪµļӦóռáװԶرЩӦó򡣰װɺ󣬰װ򵼽ЩӦó +CloseApplications=ԶرӦó(&A) +DontCloseApplications=ԶرӦó(&D) +ErrorCloseApplications=װ޷ԶرеӦóڽһ֮ǰرЩռðװҪļӦó + +; *** "Installing" wizard page +WizardInstalling=ڰװ +InstallingLabel=Ժ򣬰װĵϰװ[name] + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name]װ +FinishedLabelNoIcons=װĵϰװ[name] +FinishedLabel=װĵϰװ[name]ͨѰװĿݷʽ򿪴Ӧó +ClickFinish=˳װ +FinishedRestartLabel=Ϊ[name]İװװ򵼱ĵԡҪ +FinishedRestartMessage=Ϊ[name]İװװ򵼱ĵԡ%n%nҪ +ShowReadmeCheck=ǣҪĶļ +YesRadio=ǣ(&Y) +NoRadio=Ժ(&N) +; used for example as 'Run MyProg.exe' +RunEntryExec=%1 +; used for example as 'View Readme.txt' +RunEntryShellExec=%1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=װҪһŴ +SelectDiskLabel2=%1 ȷ%n%nôеļʾļУȷ· +PathLabel=·(&P) +FileNotInDir2=ļ%1ڡ%2СȷĴ̻ѡļС +SelectDirectoryLabel=ָһŴ̵λá + +; *** Installation phase messages +SetupAborted=װδɡ%n%nаװ򵼡 +EntryAbortRetryIgnore=ԡ³ԣԡװֹȡװ + +; *** Installation status messages +StatusClosingApplications=ڹرӦó +StatusCreateDirs=ڴļС +StatusExtractFiles=ȡļ +StatusCreateIcons=ڴݷʽ +StatusCreateIniEntries=ڴINIĿ +StatusCreateRegistryEntries=ڴעĿ +StatusRegisterFiles=ڴעĿ +StatusSavingUninstall=ڱжϢ +StatusRunProgram=ڽװ +StatusRestartingApplications=Ӧó +StatusRollback=ڳġ + +; *** Misc. errors +ErrorInternal2=ڲ%1 +ErrorFunctionFailedNoCode=%1ʧ +ErrorFunctionFailed=%1ʧܣ%2 +ErrorFunctionFailedWithMessage=%1ʧܣ%2%n%3 +ErrorExecutingProgram=޷г%n%1 + +; *** Registry errors +ErrorRegOpenKey=עʱ%n%1\%2 +ErrorRegCreateKey=עʱ%n%1\%2 +ErrorRegWriteKey=дעʱ%n%1\%2 + +; *** INI errors +ErrorIniEntry=ļ%1дINIĿʱ + +; *** File copying errors +FileAbortRetryIgnore=ԡ³ԣԡļƼֹȡװ +FileAbortRetryIgnore2=ԡ³ԣԡװƼֹȡװ +SourceIsCorrupted=Դļ +SourceDoesntExist=Դļ%1 +ExistingFileReadOnly=ļΪֻ%n%nԡƳֻԲ³ԣԡļֹȡװ +ErrorReadingExistingDest=ȡļʱ +FileExists=ļѴڡ%n%nðװ򵼸 +ExistingFileNewer=ļȰװͼװĻҪ¡鱣ļ%n%nҪļ +ErrorChangingAttr=ļʱ +ErrorCreatingTemp=Ŀļдļʱ +ErrorReadingSource=ȡԴļʱ +ErrorCopying=ļʱ +ErrorReplacingExistingFile=滻ļʱ +ErrorRestartReplace=滻ʧܣ +ErrorRenamingTemp=ΪĿļļʱ +ErrorRegisterServer=޷עᶯ̬ؼDLL/OCX%1 +ErrorRegSvr32Failed=RegSvr32ʧܣ䷵ֵΪ%1 +ErrorRegisterTypeLib=޷עͿ⣺%1 + +; *** Post-installation errors +ErrorOpeningReadme=ļʱ +ErrorRestartingComputer=װ޷ԡֶ + +; *** Uninstaller messages +UninstallNotFound=ļ%1ڡ޷жء +UninstallOpenError=޷ļ%1޷ж +UninstallUnsupportedVer=˰汾ж޷ʶж־ļ%1ĸʽ޷ж +UninstallUnknownEntry=ж־δ֪Ŀ (%1) +ConfirmUninstall=ǷȷҪȫɾ%1 +UninstallOnlyOnWin64=˰װֻ64λWindowsжء +OnlyAdminCanUninstall=˰װֻɾ߱ԱȨ޵ûжء +UninstallStatusLabel=Ժɾ%1 +UninstalledAll=ѳɹشĵɾ%1 +UninstalledMost=%1жϡ%n%nijЩĿ޷жعɾֶɾЩĿ +UninstalledAndNeedsRestart=Ҫ%1жأԡ%n%nҪ +UninstallDataCorrupted=ļ%1𻵡޷ж + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=ɾļ +ConfirmDeleteSharedFile2=ϵͳʾûκγʹ¹ļҪɾùļ%n%nгʹøļɾЩ޷Сȷѡ񡰷񡱡¸ļϵͳκΣ +SharedFileNameLabel=ļ +SharedFileLocationLabel=λã +WizardUninstalling=ж״̬ +StatusUninstalling=ж%1 + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=ڰװ%1 +ShutdownBlockReasonUninstallingApp=ж%1 + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1汾%2 +AdditionalIcons=ӿݷʽ +CreateDesktopIcon=ݷʽ(&D) +CreateQuickLaunchIcon=ݷʽ(&Q) +ProgramOnTheWeb=%1վ +UninstallProgram=ж%1 +LaunchProgram=%1 +AssocFileExtension=%1%2ļչ(&A) +AssocingFileExtension=ڽ%1%2ļչ +AutoStartProgramGroupDescription= +AutoStartProgram=Զ%1 +AddonHostProgramNotFound=ѡļҲ%1%n%nǷȻ diff --git a/distrib/Languages/ChineseTraditional.isl b/distrib/Languages/ChineseTraditional.isl index fc3c4b26009..f4d026794a3 100644 --- a/distrib/Languages/ChineseTraditional.isl +++ b/distrib/Languages/ChineseTraditional.isl @@ -1,331 +1,331 @@ -; *** Inno Setup version 5.5.3+ Chinese (Traditional) messages by Samuel Lee (751555749@qq.com) *** -; -; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ -; -; Note: When translating this text, do not add periods (.) to the end of -; messages that didn't have them already, because on those messages Inno -; Setup adds the periods automatically (appending a period would result in -; two periods being displayed). -[LangOptions] -; The following three entries are very important. Be sure to read and -; understand the '[LangOptions] section' topic in the help file. -LanguageName=<7e41><9ad4><4e2d><6587> -LanguageID=$0404 -LanguageCodepage=950 -; If the language you are translating to requires special font faces or -; sizes, uncomment any of the following entries and change them accordingly. -DialogFontName=sө -DialogFontSize=9 -TitleFontName=Arial -TitleFontSize=28 -WelcomeFontName=sө -WelcomeFontSize=12 -CopyrightFontName=sө -CopyrightFontSize=9 - -[Messages] -; *** Application titles -SetupAppTitle=w˵{ -SetupWindowTitle=%1 w˵{ -UninstallAppTitle=Ѱw -UninstallAppFullTitle=Ѱw %1 -; *** Misc. common -InformationTitle=T -ConfirmTitle=T{ -ErrorTitle=~ - -; *** SetupLdr messages -SetupLdrStartupMessage=oN|w %1CzQn~? -LdrCannotCreateTemp=Lkإ߼ȦsɮסCw˵{N|C -LdrCannotExecTemp=LkȦsɮסCw˵{N|C - -; *** Startup error messages -LastErrorMessage=%1%n%n~ %2: %3 -SetupFileMissing=w˸Ƨɮ %1CЭץDέsonC -SetupFileCorrupt=wɮפwglCЭsonC -SetupFileCorruptOrWrongVer=wɮפwglAλPw˵{šCЭsonC -InvalidParameter=YӵLĪܶqwQǻFROC:%n%n%1 -SetupAlreadyRunning=w˵{wgbC -WindowsVersionNotSupported=w˵{ä䴩ثebqҹB檺 Windows C -WindowsServicePackRequired=w˵{ݭn %1 Service Pack %2 ΧsC -NotOnThisPlatform=oӵ{Lkb %1 C -OnlyOnThisPlatform=oӵ{b %1 C -OnlyOnTheseArchitectures=oӵ{ubMHUBz[cӳ]p Windows Ww:%n%n%1 -MissingWOW64APIs=oӪ Windows ]tw˵{ 64 줸w˩һݪ\CЦw Service Pack %1 hץDC -WinVersionTooLowError=oӵ{b %1 %2 ΥHWtΰC -WinVersionTooHighError=oӵ{Lkw˦b %1 %2 ΥHWtΡC -AdminPrivilegesRequired=znJtκ޲zHw˳oӵ{C -PowerUserPrivilegesRequired=znJ㦳tκ޲z Power User vϥΪ̥Hw˳oӵ{C -SetupAppRunningError=w˵{ %1 bC%n%nӵ{ [Tw] ~AΫ [] }C -UninstallAppRunningError=Ѱw˵{ %1 bC%n%nӵ{ [Tw] ~AΫ [] }C - -; *** Misc. errors -ErrorCreatingDir=w˵{Lkإ߸Ƨ%1C -ErrorTooManyFilesInDir=LkbƧ%1إɮסA]ƧӦhɮסC - -; *** Setup common messages -ExitSetupTitle=w˵{ -ExitSetupMessage=w˩|CpGz{bw˵{Aoӵ{N|QwˡC%n%nziHyAw˵{Hw˵{ǡCz{bnw˵{? -AboutSetupMenuItem=w˵{(&A)... -AboutSetupTitle=w˵{ -AboutSetupMessage=%1 %2%n%3%n%n%1 }:%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< W@B(&B) -ButtonNext=U@B(&N) > -ButtonInstall=w(&I) -ButtonOK=Tw -ButtonCancel= -ButtonYes=O(&Y) -ButtonYesToAll=ҬO(&A) -ButtonNo=_(&N) -ButtonNoToAll=ҧ_(&O) -ButtonFinish=(&F) -ButtonBrowse=s(&B)... -ButtonWizardBrowse=s(&R)... -ButtonNewFolder=إ߷sƧ(&M) - -; *** "Select Language" dialog messages -SelectLanguageTitle=ܦw˻y -SelectLanguageLabel=ܦbw˹L{ϥΪy: - -; *** Common wizard text -ClickNext= [U@B] ~wˡAΫ [] w˵{C -BeveledLabel= -BrowseDialogTitle=sƧ -BrowseDialogLabel=bUƧCܤ@ӸƧAM [Tw]C -NewFolderName=sƧ - -; *** "Welcome" wizard page -WelcomeLabel1=wϥ [name] w˵{ -WelcomeLabel2=oӦw˵{N|w [name/ver] zqC%n%nڭ̱jPijzbw˹L{䥦ε{AHקKPw˵{oͨRC - -; *** "Password" wizard page -WizardPassword=KX -PasswordLabel1=oӦw˵{㦳KXO@C -PasswordLabel3=пJKXAM [U@B] ~CKXOϤjpgC -PasswordEditLabel=KX(&P): -IncorrectPassword=zJKXTAЭsJC - -; *** "License Agreement" wizard page -WizardLicense=vX -LicenseLabel=о\ŪHUvXC -LicenseLabel3=о\ŪHUvXAzXUڤ~~wˡC -LicenseAccepted=ڦPN(&A) -LicenseNotAccepted=ڤPN(&D) - -; *** "Information" wizard pages -WizardInfoBefore=T -InfoBeforeLabel=b~wˤeо\ŪHUnTC -InfoBeforeClickLabel=zdzƦn~wˡAЫ [U@B]C -WizardInfoAfter=T -InfoAfterLabel=b~wˤeо\ŪHUnTC -InfoAfterClickLabel=zdzƦn~wˡAЫ [U@B]C - -; *** "User Information" wizard page -WizardUserInfo=ϥΪ̸T -UserInfoDesc=пJzơC -UserInfoName=ϥΪ̦W(&U): -UserInfoOrg=´(&O): -UserInfoSerial=Ǹ(&S): -UserInfoNameRequired=zJzW١C - -; *** "Select Destination Location" wizard page -WizardSelectDir=ܥتƧ -SelectDirDesc=ܦw˵{w [name] mC -SelectDirLabel3=w˵{N| [name] w˨UƧC -SelectDirBrowseLabel= [U@B] ~ApGzQܥt@ӸƧAЫ [s]C -DiskSpaceMBLabel=ֻ̤ݭn [mb] MB ϺЪŶC -CannotInstallToNetworkDrive=w˵{Lkw˩ϺоC -CannotInstallToUNCPath=w˵{Lkw˩ UNC |C -InvalidPath=zJ㪺|W٤κϺоNXC%n%nҦp C:\App UNC |榡 \\A\@θƧC -InvalidDrive=zϺо UNC W٤sbεLksAпܨLتaC -DiskSpaceWarningTitle=ϺЪŶ -DiskSpaceWarning=w˵{ݭnܤ %1 KB ϺЪŶAzҿϺХu %2 KB iΪŶC%n%nzn~w˶? -DirNameTooLong=ƧW٩θ|ӪC -InvalidDirName=ƧW٤TC -BadDirName32=ƧW٤o]tHUSr:%n%n%1 -DirExistsTitle=Ƨwgsb -DirExists=Ƨ %1 wgsbC%n%nzn~w˨oӸƧ? -DirDoesntExistTitle=Ƨsb -DirDoesntExist=Ƨ %1 sbC%n%nznإ߳oӸƧ? - -; *** "Select Components" wizard page -WizardSelectComponents=ܤ -SelectComponentsDesc=ܱN|Qw˪C -SelectComponentsLabel2=ܱzQnw˪FMzQw˪CM [U@B] ~wˡC -FullInstallation=w -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=̤pw -CustomInstallation=ۭqw -NoUninstallWarningTitle=wsb -NoUninstallWarning=w˵{HUwgw˦bzqW:%n%n%1%n%nܳoǤN|̡C%n%nzMn~? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=ثeܻݭnܤ [mb] MB ϺЪŶC - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=ܪ[u@ -SelectTasksDesc=ܭn檺[u@C -SelectTasksLabel2=ܦw˵{bw [name] ɭn檺[u@AM [U@B]C - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=ܡu}lv\Ƨ -SelectStartMenuFolderDesc=ܦw˵{إߵ{|mC -SelectStartMenuFolderLabel3=w˵{N|{|إߦbUu}lv\ƧC -SelectStartMenuFolderBrowseLabel= [U@B] ~ApGzQܥt@ӸƧAЫ [s]C -MustEnterGroupName=zJ@ӸƧW١C -GroupNameTooLong=ƧW٩θ|ӪC -InvalidGroupName=ƧW٤TC -BadGroupName=ƧW٤o]tUCr:%n%n%1 -NoProgramGroupCheck2=nbu}lv\إ߸Ƨ(&D) - -; *** "Ready to Install" wizard page -WizardReady=dzƦw -ReadyLabel1=w˵{N}lw [name] zqC -ReadyLabel2a=U [w] ~wˡAΫ [W@B] s˵γ]wUﶵeC -ReadyLabel2b=U [w] ~wˡC -ReadyMemoUserInfo=ϥΪ̸T -ReadyMemoDir=تƧ: -ReadyMemoType=w˫A: -ReadyMemoComponents=ܪ: -ReadyMemoGroup=u}lv\Ƨ: -ReadyMemoTasks=[u@: -; *** "Preparing to Install" wizard page -WizardPreparing=dzƦw˵{ -PreparingDesc=w˵{dzƱN [name] w˨zqWC -PreviousInstallNotCompleted=ew/ Ѱw˩|AzsҰʹqHӦwˡC%n%nbsҰʹqAЦAoӵ{Ӧw [name]C -CannotContinue=w˵{Lk~CЫ [] }C -ApplicationsFound=Uε{bϥΦw˵{һݭnsɡCijz\w˵{۰oε{C -ApplicationsFound2=Uε{bϥΦw˵{һݭnsɡCijz\w˵{۰oε{Cw˹L{Aw˵{N|խs}Ҹε{C -CloseApplications=ε{(&A) -DontCloseApplications=nε{ (&D) -ErrorCloseApplications=w˵{Lk۰Ҧε{Cijzb~eҦε{ϥΪɮסC -; *** "Installing" wizard page -WizardInstalling=bw -InstallingLabel=еyԡAw˵{bN [name] w˨zqW - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=w˧ -FinishedLabelNoIcons=w˵{wgN [name] w˦bzqWC -FinishedLabel=w˵{wgN [name] w˦bzqAziHܵ{ϥܨӰε{C -ClickFinish= [] Hw˵{C -FinishedRestartLabel=n [name] wˡAw˵{sҰʱzqCzQn{bsҰʹq? -FinishedRestartMessage=n [name] wˡAw˵{sҰʱzqC%n%nzQn{bsҰʹq? -ShowReadmeCheck=OAڭn\ŪŪɮסC -YesRadio=OAߧYsҰʹq(&Y) -NoRadio=_Aڵy᭫sҰʹq(&N) -; used for example as 'Run MyProg.exe' -RunEntryExec= %1 -; used for example as 'View Readme.txt' -RunEntryShellExec=˵ %1 - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=w˵{ݭnU@iϤ -SelectDiskLabel2=дJϤ %1AM [Tw]C%n%npGɮפbHUܪƧAпJTƧW٩Ϋ [s] C -PathLabel=|(&P): -FileNotInDir2=ɮס%1Lkb%2CдJTϤοܨ䥦ƧC -SelectDirectoryLabel=ЫwU@iϤmC - -; *** Installation phase messages -SetupAborted=w˨SC%n%nЧ󥿰D᭫swˤ@C -EntryAbortRetryIgnore= [] դ@AU [L] LoɮסAΫU [] wˡC - -; *** Installation status messages -StatusClosingApplications=bε{... -StatusCreateDirs=bإ߸Ƨ... -StatusExtractFiles=bYɮ... -StatusCreateIcons=bإߵ{ϥ... -StatusCreateIniEntries=gJ INI ɮת... -StatusCreateRegistryEntries=bstεn... -StatusRegisterFiles=bnɮ... -StatusSavingUninstall=xsѰw˸T... -StatusRunProgram=bw... -StatusRestartingApplications=bs}ε{... -StatusRollback=b_ܧ... - -; *** Misc. errors -ErrorInternal2=~: %1 -ErrorFunctionFailedNoCode=%1 -ErrorFunctionFailed=%1 ѡFNX %2 -ErrorFunctionFailedWithMessage=%1 ѡFNX %2.%n%3 -ErrorExecutingProgram=Lkɮ:%n%1 - -; *** Registry errors -ErrorRegOpenKey=Lk}ҵn:%n%1\%2 -ErrorRegCreateKey=Lkإߵn:%n%1\%2 -ErrorRegWriteKey=Lkܧn:%n%1\%2 - -; *** INI errors -ErrorIniEntry=bɮס%1إ INI ؿ~C - -; *** File copying errors -FileAbortRetryIgnore= [] Aդ@A [L] Loɮס]ij^AΫ [] wˡC -FileAbortRetryIgnore2= [] Aդ@A [L] ~i]ij^AΫ [] wˡC -SourceIsCorrupted=ӷɮפwglC -SourceDoesntExist=ӷɮס%1sbC -ExistingFileReadOnly=ɮݩʤw]ŪC%n%n [] NŪݩʲ}Aդ@A [L] LoɮסAΫ [] wˡC -ErrorReadingExistingDest=Ū@Ӥwsbɮ׮ɵoͿ~: -FileExists=ɮפwgsbCznNثeɮ׶? -ExistingFileNewer=sbɮתsAijzOdثewsbɮסC%n%nznOdثewsbɮ׶? -ErrorChangingAttr=bܧɮݩʮɵoͿ~: -ErrorCreatingTemp=bتƧإɮ׮ɵoͿ~: -ErrorReadingSource=Ūlɮ׮ɵoͿ~: -ErrorCopying=_ɮ׮ɵoͿ~: -ErrorReplacingExistingFile=Nɮ׮ɵoͿ~: -ErrorRestartReplace=sҰʹqNɮץ: -ErrorRenamingTemp=bتƧܧɮצWٮɵoͿ~: -ErrorRegisterServer=Lk`U DLL/OCX ɮ: %1C -ErrorRegSvr32Failed=RegSvr32 ѡFhXNX %1 -ErrorRegisterTypeLib=Lk`Uw: %1C - -; *** Post-installation errors -ErrorOpeningReadme=}Ūɮ׮ɵoͿ~C -ErrorRestartingComputer=w˵{LksҰʹqAХHʤ覡ۦ歫sҰʹqC - -; *** Uninstaller messages -UninstallNotFound=ɮס%1sbALk{C -UninstallOpenError=Lk}ɮס%1ALk{C -UninstallUnsupportedVer=oӪѰw˵{LkѰO %1 榡ALkѰwˡC -UninstallUnknownEntry=Ѱw˰Oɤo{O (%1)C -ConfirmUninstall=zTwn %1 Ψɮ׶? -UninstallOnlyOnWin64=oӵ{ub 64 줸 Windows WѰwˡC -OnlyAdminCanUninstall=oӵ{nƨtκ޲zvϥΪ̤iѰwˡC -UninstallStatusLabel=bqzq %1 Aеy... -UninstalledAll=%1 wg\qzqC -UninstalledMost=%1 Ѱw˧C%n%nYɮפΤLkAziHۦRoɮסC -UninstalledAndNeedsRestart=n %1 Ѱw˵{ǡAzsҰʹqC%n%nzQn{bsҰʹq? -UninstallDataCorrupted=ɮס%1wglALkѰwˡC - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=@ɮ -ConfirmDeleteSharedFile2=tܤUC@ɮפwAQ{ҨϥΡAznoɮ׶?%n%n%1%n%nխYzFHWɮצ{ݭnϥΥ̡ANyoǵ{Lk`A]zYLkTwп [_]COdoɮצbztΤ|yl`C -SharedFileNameLabel=ɮצW: -SharedFileLocationLabel=m: -WizardUninstalling=Ѱw˪A -StatusUninstalling=bѰw %1... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=bw %1. -ShutdownBlockReasonUninstallingApp=bѰw %1. - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] -NameAndVersion=%1 %2 -AdditionalIcons=[ϥ: -CreateDesktopIcon=إ߮ୱϥ(&D) -CreateQuickLaunchIcon=إߧֳtҰʹϥ(&Q) -ProgramOnTheWeb=%1 -UninstallProgram=Ѱw %1 -LaunchProgram=Ұ %1 -AssocFileExtension=N %1 PɮװɦW %2 p(&A) -AssocingFileExtension=bN %1 PɮװɦW %2 p... -AutoStartProgramGroupDescription=}: -AutoStartProgram=۰ʶ} %1 -AddonHostProgramNotFound=%1 Lkbzҿ諸ƧC%n%nzO_٭n~H - +; *** Inno Setup version 5.5.3+ Chinese (Traditional) messages by Samuel Lee (751555749@qq.com) *** +; +; To download user-contributed translations of this file, go to: +; http://www.jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=<7e41><9ad4><4e2d><6587> +LanguageID=$0404 +LanguageCodepage=950 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +DialogFontName=sө +DialogFontSize=9 +TitleFontName=Arial +TitleFontSize=28 +WelcomeFontName=sө +WelcomeFontSize=12 +CopyrightFontName=sө +CopyrightFontSize=9 + +[Messages] +; *** Application titles +SetupAppTitle=w˵{ +SetupWindowTitle=%1 w˵{ +UninstallAppTitle=Ѱw +UninstallAppFullTitle=Ѱw %1 +; *** Misc. common +InformationTitle=T +ConfirmTitle=T{ +ErrorTitle=~ + +; *** SetupLdr messages +SetupLdrStartupMessage=oN|w %1CzQn~? +LdrCannotCreateTemp=Lkإ߼ȦsɮסCw˵{N|C +LdrCannotExecTemp=LkȦsɮסCw˵{N|C + +; *** Startup error messages +LastErrorMessage=%1%n%n~ %2: %3 +SetupFileMissing=w˸Ƨɮ %1CЭץDέsonC +SetupFileCorrupt=wɮפwglCЭsonC +SetupFileCorruptOrWrongVer=wɮפwglAλPw˵{šCЭsonC +InvalidParameter=YӵLĪܶqwQǻFROC:%n%n%1 +SetupAlreadyRunning=w˵{wgbC +WindowsVersionNotSupported=w˵{ä䴩ثebqҹB檺 Windows C +WindowsServicePackRequired=w˵{ݭn %1 Service Pack %2 ΧsC +NotOnThisPlatform=oӵ{Lkb %1 C +OnlyOnThisPlatform=oӵ{b %1 C +OnlyOnTheseArchitectures=oӵ{ubMHUBz[cӳ]p Windows Ww:%n%n%1 +MissingWOW64APIs=oӪ Windows ]tw˵{ 64 줸w˩һݪ\CЦw Service Pack %1 hץDC +WinVersionTooLowError=oӵ{b %1 %2 ΥHWtΰC +WinVersionTooHighError=oӵ{Lkw˦b %1 %2 ΥHWtΡC +AdminPrivilegesRequired=znJtκ޲zHw˳oӵ{C +PowerUserPrivilegesRequired=znJ㦳tκ޲z Power User vϥΪ̥Hw˳oӵ{C +SetupAppRunningError=w˵{ %1 bC%n%nӵ{ [Tw] ~AΫ [] }C +UninstallAppRunningError=Ѱw˵{ %1 bC%n%nӵ{ [Tw] ~AΫ [] }C + +; *** Misc. errors +ErrorCreatingDir=w˵{Lkإ߸Ƨ%1C +ErrorTooManyFilesInDir=LkbƧ%1إɮסA]ƧӦhɮסC + +; *** Setup common messages +ExitSetupTitle=w˵{ +ExitSetupMessage=w˩|CpGz{bw˵{Aoӵ{N|QwˡC%n%nziHyAw˵{Hw˵{ǡCz{bnw˵{? +AboutSetupMenuItem=w˵{(&A)... +AboutSetupTitle=w˵{ +AboutSetupMessage=%1 %2%n%3%n%n%1 }:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< W@B(&B) +ButtonNext=U@B(&N) > +ButtonInstall=w(&I) +ButtonOK=Tw +ButtonCancel= +ButtonYes=O(&Y) +ButtonYesToAll=ҬO(&A) +ButtonNo=_(&N) +ButtonNoToAll=ҧ_(&O) +ButtonFinish=(&F) +ButtonBrowse=s(&B)... +ButtonWizardBrowse=s(&R)... +ButtonNewFolder=إ߷sƧ(&M) + +; *** "Select Language" dialog messages +SelectLanguageTitle=ܦw˻y +SelectLanguageLabel=ܦbw˹L{ϥΪy: + +; *** Common wizard text +ClickNext= [U@B] ~wˡAΫ [] w˵{C +BeveledLabel= +BrowseDialogTitle=sƧ +BrowseDialogLabel=bUƧCܤ@ӸƧAM [Tw]C +NewFolderName=sƧ + +; *** "Welcome" wizard page +WelcomeLabel1=wϥ [name] w˵{ +WelcomeLabel2=oӦw˵{N|w [name/ver] zqC%n%nڭ̱jPijzbw˹L{䥦ε{AHקKPw˵{oͨRC + +; *** "Password" wizard page +WizardPassword=KX +PasswordLabel1=oӦw˵{㦳KXO@C +PasswordLabel3=пJKXAM [U@B] ~CKXOϤjpgC +PasswordEditLabel=KX(&P): +IncorrectPassword=zJKXTAЭsJC + +; *** "License Agreement" wizard page +WizardLicense=vX +LicenseLabel=о\ŪHUvXC +LicenseLabel3=о\ŪHUvXAzXUڤ~~wˡC +LicenseAccepted=ڦPN(&A) +LicenseNotAccepted=ڤPN(&D) + +; *** "Information" wizard pages +WizardInfoBefore=T +InfoBeforeLabel=b~wˤeо\ŪHUnTC +InfoBeforeClickLabel=zdzƦn~wˡAЫ [U@B]C +WizardInfoAfter=T +InfoAfterLabel=b~wˤeо\ŪHUnTC +InfoAfterClickLabel=zdzƦn~wˡAЫ [U@B]C + +; *** "User Information" wizard page +WizardUserInfo=ϥΪ̸T +UserInfoDesc=пJzơC +UserInfoName=ϥΪ̦W(&U): +UserInfoOrg=´(&O): +UserInfoSerial=Ǹ(&S): +UserInfoNameRequired=zJzW١C + +; *** "Select Destination Location" wizard page +WizardSelectDir=ܥتƧ +SelectDirDesc=ܦw˵{w [name] mC +SelectDirLabel3=w˵{N| [name] w˨UƧC +SelectDirBrowseLabel= [U@B] ~ApGzQܥt@ӸƧAЫ [s]C +DiskSpaceMBLabel=ֻ̤ݭn [mb] MB ϺЪŶC +CannotInstallToNetworkDrive=w˵{Lkw˩ϺоC +CannotInstallToUNCPath=w˵{Lkw˩ UNC |C +InvalidPath=zJ㪺|W٤κϺоNXC%n%nҦp C:\App UNC |榡 \\A\@θƧC +InvalidDrive=zϺо UNC W٤sbεLksAпܨLتaC +DiskSpaceWarningTitle=ϺЪŶ +DiskSpaceWarning=w˵{ݭnܤ %1 KB ϺЪŶAzҿϺХu %2 KB iΪŶC%n%nzn~w˶? +DirNameTooLong=ƧW٩θ|ӪC +InvalidDirName=ƧW٤TC +BadDirName32=ƧW٤o]tHUSr:%n%n%1 +DirExistsTitle=Ƨwgsb +DirExists=Ƨ %1 wgsbC%n%nzn~w˨oӸƧ? +DirDoesntExistTitle=Ƨsb +DirDoesntExist=Ƨ %1 sbC%n%nznإ߳oӸƧ? + +; *** "Select Components" wizard page +WizardSelectComponents=ܤ +SelectComponentsDesc=ܱN|Qw˪C +SelectComponentsLabel2=ܱzQnw˪FMzQw˪CM [U@B] ~wˡC +FullInstallation=w +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=̤pw +CustomInstallation=ۭqw +NoUninstallWarningTitle=wsb +NoUninstallWarning=w˵{HUwgw˦bzqW:%n%n%1%n%nܳoǤN|̡C%n%nzMn~? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel=ثeܻݭnܤ [mb] MB ϺЪŶC + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=ܪ[u@ +SelectTasksDesc=ܭn檺[u@C +SelectTasksLabel2=ܦw˵{bw [name] ɭn檺[u@AM [U@B]C + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=ܡu}lv\Ƨ +SelectStartMenuFolderDesc=ܦw˵{إߵ{|mC +SelectStartMenuFolderLabel3=w˵{N|{|إߦbUu}lv\ƧC +SelectStartMenuFolderBrowseLabel= [U@B] ~ApGzQܥt@ӸƧAЫ [s]C +MustEnterGroupName=zJ@ӸƧW١C +GroupNameTooLong=ƧW٩θ|ӪC +InvalidGroupName=ƧW٤TC +BadGroupName=ƧW٤o]tUCr:%n%n%1 +NoProgramGroupCheck2=nbu}lv\إ߸Ƨ(&D) + +; *** "Ready to Install" wizard page +WizardReady=dzƦw +ReadyLabel1=w˵{N}lw [name] zqC +ReadyLabel2a=U [w] ~wˡAΫ [W@B] s˵γ]wUﶵeC +ReadyLabel2b=U [w] ~wˡC +ReadyMemoUserInfo=ϥΪ̸T +ReadyMemoDir=تƧ: +ReadyMemoType=w˫A: +ReadyMemoComponents=ܪ: +ReadyMemoGroup=u}lv\Ƨ: +ReadyMemoTasks=[u@: +; *** "Preparing to Install" wizard page +WizardPreparing=dzƦw˵{ +PreparingDesc=w˵{dzƱN [name] w˨zqWC +PreviousInstallNotCompleted=ew/ Ѱw˩|AzsҰʹqHӦwˡC%n%nbsҰʹqAЦAoӵ{Ӧw [name]C +CannotContinue=w˵{Lk~CЫ [] }C +ApplicationsFound=Uε{bϥΦw˵{һݭnsɡCijz\w˵{۰oε{C +ApplicationsFound2=Uε{bϥΦw˵{һݭnsɡCijz\w˵{۰oε{Cw˹L{Aw˵{N|խs}Ҹε{C +CloseApplications=ε{(&A) +DontCloseApplications=nε{ (&D) +ErrorCloseApplications=w˵{Lk۰Ҧε{Cijzb~eҦε{ϥΪɮסC +; *** "Installing" wizard page +WizardInstalling=bw +InstallingLabel=еyԡAw˵{bN [name] w˨zqW + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=w˧ +FinishedLabelNoIcons=w˵{wgN [name] w˦bzqWC +FinishedLabel=w˵{wgN [name] w˦bzqAziHܵ{ϥܨӰε{C +ClickFinish= [] Hw˵{C +FinishedRestartLabel=n [name] wˡAw˵{sҰʱzqCzQn{bsҰʹq? +FinishedRestartMessage=n [name] wˡAw˵{sҰʱzqC%n%nzQn{bsҰʹq? +ShowReadmeCheck=OAڭn\ŪŪɮסC +YesRadio=OAߧYsҰʹq(&Y) +NoRadio=_Aڵy᭫sҰʹq(&N) +; used for example as 'Run MyProg.exe' +RunEntryExec= %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=˵ %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=w˵{ݭnU@iϤ +SelectDiskLabel2=дJϤ %1AM [Tw]C%n%npGɮפbHUܪƧAпJTƧW٩Ϋ [s] C +PathLabel=|(&P): +FileNotInDir2=ɮס%1Lkb%2CдJTϤοܨ䥦ƧC +SelectDirectoryLabel=ЫwU@iϤmC + +; *** Installation phase messages +SetupAborted=w˨SC%n%nЧ󥿰D᭫swˤ@C +EntryAbortRetryIgnore= [] դ@AU [L] LoɮסAΫU [] wˡC + +; *** Installation status messages +StatusClosingApplications=bε{... +StatusCreateDirs=bإ߸Ƨ... +StatusExtractFiles=bYɮ... +StatusCreateIcons=bإߵ{ϥ... +StatusCreateIniEntries=gJ INI ɮת... +StatusCreateRegistryEntries=bstεn... +StatusRegisterFiles=bnɮ... +StatusSavingUninstall=xsѰw˸T... +StatusRunProgram=bw... +StatusRestartingApplications=bs}ε{... +StatusRollback=b_ܧ... + +; *** Misc. errors +ErrorInternal2=~: %1 +ErrorFunctionFailedNoCode=%1 +ErrorFunctionFailed=%1 ѡFNX %2 +ErrorFunctionFailedWithMessage=%1 ѡFNX %2.%n%3 +ErrorExecutingProgram=Lkɮ:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Lk}ҵn:%n%1\%2 +ErrorRegCreateKey=Lkإߵn:%n%1\%2 +ErrorRegWriteKey=Lkܧn:%n%1\%2 + +; *** INI errors +ErrorIniEntry=bɮס%1إ INI ؿ~C + +; *** File copying errors +FileAbortRetryIgnore= [] Aդ@A [L] Loɮס]ij^AΫ [] wˡC +FileAbortRetryIgnore2= [] Aդ@A [L] ~i]ij^AΫ [] wˡC +SourceIsCorrupted=ӷɮפwglC +SourceDoesntExist=ӷɮס%1sbC +ExistingFileReadOnly=ɮݩʤw]ŪC%n%n [] NŪݩʲ}Aդ@A [L] LoɮסAΫ [] wˡC +ErrorReadingExistingDest=Ū@Ӥwsbɮ׮ɵoͿ~: +FileExists=ɮפwgsbCznNثeɮ׶? +ExistingFileNewer=sbɮתsAijzOdثewsbɮסC%n%nznOdثewsbɮ׶? +ErrorChangingAttr=bܧɮݩʮɵoͿ~: +ErrorCreatingTemp=bتƧإɮ׮ɵoͿ~: +ErrorReadingSource=Ūlɮ׮ɵoͿ~: +ErrorCopying=_ɮ׮ɵoͿ~: +ErrorReplacingExistingFile=Nɮ׮ɵoͿ~: +ErrorRestartReplace=sҰʹqNɮץ: +ErrorRenamingTemp=bتƧܧɮצWٮɵoͿ~: +ErrorRegisterServer=Lk`U DLL/OCX ɮ: %1C +ErrorRegSvr32Failed=RegSvr32 ѡFhXNX %1 +ErrorRegisterTypeLib=Lk`Uw: %1C + +; *** Post-installation errors +ErrorOpeningReadme=}Ūɮ׮ɵoͿ~C +ErrorRestartingComputer=w˵{LksҰʹqAХHʤ覡ۦ歫sҰʹqC + +; *** Uninstaller messages +UninstallNotFound=ɮס%1sbALk{C +UninstallOpenError=Lk}ɮס%1ALk{C +UninstallUnsupportedVer=oӪѰw˵{LkѰO %1 榡ALkѰwˡC +UninstallUnknownEntry=Ѱw˰Oɤo{O (%1)C +ConfirmUninstall=zTwn %1 Ψɮ׶? +UninstallOnlyOnWin64=oӵ{ub 64 줸 Windows WѰwˡC +OnlyAdminCanUninstall=oӵ{nƨtκ޲zvϥΪ̤iѰwˡC +UninstallStatusLabel=bqzq %1 Aеy... +UninstalledAll=%1 wg\qzqC +UninstalledMost=%1 Ѱw˧C%n%nYɮפΤLkAziHۦRoɮסC +UninstalledAndNeedsRestart=n %1 Ѱw˵{ǡAzsҰʹqC%n%nzQn{bsҰʹq? +UninstallDataCorrupted=ɮס%1wglALkѰwˡC + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=@ɮ +ConfirmDeleteSharedFile2=tܤUC@ɮפwAQ{ҨϥΡAznoɮ׶?%n%n%1%n%nխYzFHWɮצ{ݭnϥΥ̡ANyoǵ{Lk`A]zYLkTwп [_]COdoɮצbztΤ|yl`C +SharedFileNameLabel=ɮצW: +SharedFileLocationLabel=m: +WizardUninstalling=Ѱw˪A +StatusUninstalling=bѰw %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=bw %1. +ShutdownBlockReasonUninstallingApp=bѰw %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] +NameAndVersion=%1 %2 +AdditionalIcons=[ϥ: +CreateDesktopIcon=إ߮ୱϥ(&D) +CreateQuickLaunchIcon=إߧֳtҰʹϥ(&Q) +ProgramOnTheWeb=%1 +UninstallProgram=Ѱw %1 +LaunchProgram=Ұ %1 +AssocFileExtension=N %1 PɮװɦW %2 p(&A) +AssocingFileExtension=bN %1 PɮװɦW %2 p... +AutoStartProgramGroupDescription=}: +AutoStartProgram=۰ʶ} %1 +AddonHostProgramNotFound=%1 Lkbzҿ諸ƧC%n%nzO_٭n~H + diff --git a/distrib/Languages/Korean.isl b/distrib/Languages/Korean.isl index d99d3fd853f..e775d84bb3f 100644 --- a/distrib/Languages/Korean.isl +++ b/distrib/Languages/Korean.isl @@ -1,322 +1,322 @@ -; *** Inno Setup version 5.5.3+ Korean messages *** -; -; 5.5.3+ Translator: Domddol (domddol@gmail.com) -; Translation date: MAR 04, 2014 -; Contributors: Hansoo KIM (iryna7@gmail.com), Woong-Jae An (a183393@hanmail.net) -; Storage: http://www.jrsoftware.org/files/istrans/ -; ο ѱ Ģ ؼմϴ. - -[LangOptions] -LanguageName=Korean -LanguageID=$0412 -LanguageCodePage=949 - -[Messages] - -; *** Application titles -SetupAppTitle=ġ -SetupWindowTitle=%1 ġ -UninstallAppTitle= -UninstallAppFullTitle=%1 - -; *** Misc. common -InformationTitle= -ConfirmTitle=Ȯ -ErrorTitle= - -; *** SetupLdr messages -SetupLdrStartupMessage=%1() ġմϴ, Ͻðڽϱ? -LdrCannotCreateTemp=ӽ ϴ, ġ ߴմϴ -LdrCannotExecTemp=ӽ ϴ, ġ ߴմϴ - -; *** Startup error messages -LastErrorMessage=%1.%n%n %2: %3 -SetupFileMissing=%1 ʽϴ, ذ ų ο ġ α׷ Ͻñ ٶϴ. -SetupFileCorrupt=ġ ջǾϴ, ο ġ α׷ Ͻñ ٶϴ. -SetupFileCorruptOrWrongVer=ġ ջ̰ų ġ ȣȯ ʽϴ, ذ ų ο ġ α׷ Ͻñ ٶϴ. -InvalidParameter=߸ Ű Դϴ:%n%n%1 -SetupAlreadyRunning=ġ ̹ Դϴ. -WindowsVersionNotSupported= α׷ Windows ʽϴ. -WindowsServicePackRequired= α׷ Ϸ %1 sp%2 ̻̾ մϴ. -NotOnThisPlatform= α׷ %1 ۵ ʽϴ. -OnlyOnThisPlatform= α׷ %1 ؾ մϴ. -OnlyOnTheseArchitectures= α׷ Ʒ ó ȣȯǴ Windows ġ ֽϴ:%n%n%1 -MissingWOW64APIs= Windows 64Ʈ ġ ʿ ԵǾ ʽϴ, ذϷ sp%1() ġϽñ ٶϴ. -WinVersionTooLowError= α׷ %1 %2 ̻ ʿմϴ. -WinVersionTooHighError= α׷ %1 %2 ̻󿡼 ġ ϴ. -AdminPrivilegesRequired= α׷ ġϷ ڷ αؾ մϴ. -PowerUserPrivilegesRequired= α׷ ġϷ Ǵ ڷ αؾ մϴ. -SetupAppRunningError= %1() Դϴ!%n%n װ νϽ ݾ ֽʽÿ. ׷ Ϸ "Ȯ", Ϸ "" ŬϽʽÿ. -UninstallAppRunningError= %1() Դϴ!%n%n װ νϽ ݾ ֽʽÿ. ׷ Ϸ "Ȯ", Ϸ "" ŬϽʽÿ. - -; *** Misc. errors -ErrorCreatingDir="%1" ϴ. -ErrorTooManyFilesInDir="%1" ʹ ϴ. - -; *** Setup common messages -ExitSetupTitle=ġ Ϸ -ExitSetupMessage=ġ Ϸ ʾҽϴ, ⼭ ġ ϸ α׷ ġ ʽϴ.%n%nġ ϷϷ ߿ ٽ ġ α׷ ؾ մϴ.%n%n׷ ġ Ͻðڽϱ? -AboutSetupMenuItem=ġ (&A)... -AboutSetupTitle=ġ -AboutSetupMessage=%1 %2%n%3%n%n%1 Ȩ :%n%4 -AboutSetupNote= -TranslatorNote= - -; *** Buttons -ButtonBack=< ڷ(&B) -ButtonNext=(&N) > -ButtonInstall=ġ(&I) -ButtonOK=Ȯ -ButtonCancel= -ButtonYes=(&Y) -ButtonYesToAll= (&A) -ButtonNo=ƴϿ(&N) -ButtonNoToAll= ƴϿ(&O) -ButtonFinish=(&F) -ButtonBrowse=ãƺ(&B)... -ButtonWizardBrowse=ãƺ(&R)... -ButtonNewFolder= (&M) - -; *** "Select Language" dialog messages -SelectLanguageTitle=ġ -SelectLanguageLabel=ġ ǥ : - -; *** Common wizard text -ClickNext=Ϸ "" Ŭϰ ġ Ϸ "" Ŭմϴ. -BeveledLabel= -BrowseDialogTitle= ãƺ -BrowseDialogLabel=Ʒ Ͽ "Ȯ" Ŭմϴ. -NewFolderName= - -; *** "Welcome" wizard page -WelcomeLabel1=[name] ġ -WelcomeLabel2= ǻͿ [name/ver]() ġ Դϴ.%n%nġϱ ٸ α׷ ñ ٶϴ. - -; *** "Password" wizard page -WizardPassword= ȣ -PasswordLabel1= ġ ȣ ȣǾ ֽϴ. -PasswordLabel3= ȣ Էϰ "" ŬϽʽÿ. ȣ ҹڸ ؾ մϴ. -PasswordEditLabel= ȣ(&P): -IncorrectPassword= ȣ Ȯ ʽϴ, ٽ ԷϽʽÿ! - -; *** "License Agreement" wizard page -WizardLicense= -LicenseLabel=ϱ ߿ оʽÿ. -LicenseLabel3= оʽÿ, ġ Ϸ ࿡ ؾ մϴ. -LicenseAccepted=մϴ(&A) -LicenseNotAccepted= ʽϴ(&D) - -; *** "Information" wizard pages -WizardInfoBefore= -InfoBeforeLabel=ϱ ߿ оʽÿ. -InfoBeforeClickLabel=ġ Ϸ "" ŬϽʽÿ. -WizardInfoAfter= -InfoAfterLabel=ϱ ߿ оʽÿ. -InfoAfterClickLabel=ġ Ϸ "" ŬϽʽÿ. - -; *** "User Information" wizard page -WizardUserInfo= -UserInfoDesc= ԷϽʽÿ. -UserInfoName= ̸(&U): -UserInfoOrg=(&O): -UserInfoSerial=Ϸ ȣ(&S): -UserInfoNameRequired= ̸ ԷϽʽÿ. - -; *** "Select Destination Location" wizard page -WizardSelectDir=ġ ġ -SelectDirDesc=[name] ġ ġ Ͻʽÿ. -SelectDirLabel3= [name]() ġմϴ. -SelectDirBrowseLabel=Ϸ "", ٸ Ϸ "ãƺ" ŬϽʽÿ. -DiskSpaceMBLabel= α׷ ּ [mb] MB ũ ʿմϴ. -CannotInstallToNetworkDrive=Ʈũ ̺꿡 ġ ϴ. -CannotInstallToUNCPath=UNC ο ġ ϴ. -InvalidPath=̺ ڸ ü θ ԷϽʽÿ.%n : C:\APP %n%nǴ, UNC θ ԷϽʽÿ.%n : \\server\share -InvalidDrive= ̺ Ǵ UNC ʰų ׼ ϴ, ٸ θ Ͻʽÿ. -DiskSpaceWarningTitle=ũ մϴ -DiskSpaceWarning=ġ ּ %1 KB ũ ʿ, ̺ %2 KB ۿ ϴ.%n%n׷ Ͻðڽϱ? -DirNameTooLong= ̸ Ǵ ΰ ʹ ϴ. -InvalidDirName= ̸ ȿ ʽϴ. -BadDirName32= ̸ ڸ ϴ:%n%n%1 -DirExistsTitle= մϴ -DirExists= %n%n%1%n%n() ̹ մϴ, ġϽðڽϱ? -DirDoesntExistTitle= ʽϴ -DirDoesntExist= %n%n%1%n%n() ʽϴ, ðڽϱ? - -; *** "Select Components" wizard page -WizardSelectComponents= -SelectComponentsDesc=ġ Ҹ Ͻʽÿ. -SelectComponentsLabel2=ʿ Ҵ üũϰ ʿ Ҵ üũ մϴ, Ϸ "" ŬϽʽÿ. -FullInstallation= ġ -; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=ּ ġ -CustomInstallation= ġ -NoUninstallWarningTitle= Ұ մϴ -NoUninstallWarning= Ұ ̹ ġǾ ֽϴ:%n%n%1%n%n , α׷ Ž ҵ ŵ ̴ϴ.%n%n׷ Ͻðڽϱ? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel= ּ [mb] MB ũ ʿմϴ. - -; *** "Select Additional Tasks" wizard page -WizardSelectTasks=߰ ۾ -SelectTasksDesc= ߰ ۾ Ͻʽÿ. -SelectTasksLabel2=[name] ġ ߰ ۾ , "" ŬϽʽÿ. - -; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup= ޴ -SelectStartMenuFolderDesc= α׷ ٷΰ⸦ ġϰڽϱ? -SelectStartMenuFolderLabel3= ޴ α׷ ٷΰ⸦ ϴ. -SelectStartMenuFolderBrowseLabel=Ϸ "" Ŭϰ, ٸ Ϸ "ãƺ" ŬϽʽÿ. -MustEnterGroupName= ̸ ԷϽʽÿ. -GroupNameTooLong= ̸ Ǵ ΰ ʹ ϴ. -InvalidGroupName= ̸ ȿ ʽϴ. -BadGroupName= ̸ ڸ ϴ:%n%n%1 -NoProgramGroupCheck2= ޴ (&D) - -; *** "Ready to Install" wizard page -WizardReady=ġ غ Ϸ -ReadyLabel1= ǻͿ [name]() ġ غ Ǿϴ. -ReadyLabel2a=ġ Ϸ "ġ", ϰų Ϸ "ڷ" ŬϽʽÿ. -ReadyLabel2b=ġ Ϸ "ġ" ŬϽʽÿ. -ReadyMemoUserInfo= : -ReadyMemoDir=ġ ġ: -ReadyMemoType=ġ : -ReadyMemoComponents= : -ReadyMemoGroup= ޴ : -ReadyMemoTasks=߰ ۾: - -; *** "Preparing to Install" wizard page -WizardPreparing=ġ غ -PreparingDesc= ǻͿ [name] ġ غϴ Դϴ. -PreviousInstallNotCompleted= α׷ ġ/ ۾ Ϸ ʾҽϴ, ϷϷ ǻ͸ ٽ ؾ մϴ.%n%nǻ͸ ٽ , ġ 縦 ٽ Ͽ [name] ġ ϷϽñ ٶϴ. -CannotContinue=ġ ϴ, "" ŬϿ ġ Ͻʽÿ. -ApplicationsFound= α׷ ġ Ʈ ʿ ϰ ֽϴ, ġ 簡 ̷ α׷ ڵ ֵ Ͻñ ٶϴ. -ApplicationsFound2= α׷ ġ Ʈ ʿ ϰ ֽϴ, ġ 簡 ̷ α׷ ڵ ֵ Ͻñ ٶϴ. ġ ϷǸ, ġ α׷ ٽ ۵ǵ õ ̴ϴ. -CloseApplications=ڵ α׷ (&A) -DontCloseApplications=α׷ (&D) -ErrorCloseApplications=ġ 簡 α׷ ڵ ϴ, ϱ ġ Ʈ ʿ ϰ ִ α׷ Ͻñ ٶϴ. - -; *** "Installing" wizard page -WizardInstalling=ġ -InstallingLabel= ǻͿ [name]() ġϴ ... ٷ ֽʽÿ. - -; *** "Setup Completed" wizard page -FinishedHeadingLabel=[name] ġ Ϸ -FinishedLabelNoIcons= ǻͿ [name]() ġǾϴ. -FinishedLabel= ǻͿ [name]() ġǾϴ, α׷ ġ Ͽ ֽϴ. -ClickFinish=ġ "" ŬϽʽÿ. -FinishedRestartLabel=[name] ġ ϷϷ, ǻ͸ ٽ ؾ մϴ. ٽ Ͻðڽϱ? -FinishedRestartMessage=[name] ġ ϷϷ, ǻ͸ ٽ ؾ մϴ.%n%n ٽ Ͻðڽϱ? -ShowReadmeCheck=, README ǥմϴ -YesRadio=, ٽ մϴ(&Y) -NoRadio=ƴϿ, ߿ ٽ մϴ(&N) -; used for example as 'Run MyProg.exe' -RunEntryExec=%1 -; used for example as 'View Readme.txt' -RunEntryShellExec=%1 ǥ - -; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=ũ ʿմϴ -SelectDiskLabel2=ũ %1() ϰ "Ȯ" ŬϽʽÿ.%n%n ũ Ʒ ΰ ƴ ִ , ùٸ θ Էϰų "ãƺ" ŬϽñ ٶϴ. -PathLabel=(&P): -FileNotInDir2=%2 %1() ġ ϴ, ùٸ ũ ϰų ٸ Ͻʽÿ. -SelectDirectoryLabel= ũ ġ Ͻʽÿ. - -; *** Installation phase messages -SetupAborted=ġ Ϸ ʾҽϴ.%n%n ذ , ٽ ġ Ͻʽÿ. -EntryAbortRetryIgnore=ٽ õϷ "õ", ϰ Ϸ "", ġ Ϸ "" ŬϽʽÿ. - -; *** Installation status messages -StatusClosingApplications=α׷ ϴ ... -StatusCreateDirs= ... -StatusExtractFiles= ϴ ... -StatusCreateIcons=ٷΰ⸦ ϴ ... -StatusCreateIniEntries=INI ׸ ... -StatusCreateRegistryEntries=Ʈ ׸ ... -StatusRegisterFiles= ϴ ... -StatusSavingUninstall= ϴ ... -StatusRunProgram=ġ Ϸϴ ... -StatusRestartingApplications=α׷ ٽ ϴ ... -StatusRollback= ϴ ... - -; *** Misc. errors -ErrorInternal2= : %1 -ErrorFunctionFailedNoCode=%1 -ErrorFunctionFailed=%1 , ڵ: %2 -ErrorFunctionFailedWithMessage=%1 , ڵ: %2.%n%3 -ErrorExecutingProgram= :%n%1 - -; *** Registry errors -ErrorRegOpenKey=Ʈ Ű :%n%1\%2 -ErrorRegCreateKey=Ʈ Ű :%n%1\%2 -ErrorRegWriteKey=Ʈ Ű :%n%1\%2 - -; *** INI errors -ErrorIniEntry=%1 Ͽ INI ׸ Դϴ. - -; *** File copying errors -FileAbortRetryIgnore=ٽ õϷ "õ", dzʶٷ ""(õ), ġ Ϸ "" ŬϽʽÿ. -FileAbortRetryIgnore2=ٽ õϷ "õ", Ϸ ""(õ), ġ Ϸ "" ŬϽʽÿ. -SourceIsCorrupted= ջ -SourceDoesntExist= %1() -ExistingFileReadOnly= б Դϴ.%n%nб Ӽ ϰ ٽ õϷ "õ", dzʶٷ "", ġ Ϸ "" ŬϽʽÿ. -ErrorReadingExistingDest= д ߻: -FileExists= ̹ մϴ.%n%n ðڽϱ? -ExistingFileNewer= ġϷ ϴ Ϻ Դϴ, Ͻñ ٶϴ.%n%n Ͻðڽϱ? -ErrorChangingAttr= Ӽ ϴ ߻: -ErrorCreatingTemp= ߻: -ErrorReadingSource= д ߻: -ErrorCopying= ϴ ߻: -ErrorReplacingExistingFile= üϴ ߻: -ErrorRestartReplace=RestartReplace : -ErrorRenamingTemp= ̸ ٲٴ ߻: -ErrorRegisterServer=DLL/OCX : %1 -ErrorRegSvr32Failed=RegSvr32 ڵ : %1 -ErrorRegisterTypeLib= ̺귯 Ͽ : %1 - -; *** Post-installation errors -ErrorOpeningReadme=README ߻߽ϴ. -ErrorRestartingComputer=ǻ͸ ٽ ϴ, ٽ Ͻʽÿ. - -; *** Uninstaller messages -UninstallNotFound= %1() ʱ , Ÿ ϴ. -UninstallOpenError= %1() , Ÿ ϴ. -UninstallUnsupportedVer= α "%1"() ν ̱ , Ÿ ϴ. -UninstallUnknownEntry= ׸ %1() α׿ ԵǾ ֽϴ. -ConfirmUninstall= %1() Ҹ Ͻðڽϱ? -UninstallOnlyOnWin64= α׷ 64Ʈ Windows ֽϴ. -OnlyAdminCanUninstall= α׷ Ϸ ʿմϴ. -UninstallStatusLabel= ǻͿ %1() ϴ ... ٷ ֽʽÿ. -UninstalledAll=%1() ŵǾϴ! -UninstalledMost=%1 Ű ϷǾϴ.%n%nϺ Ҵ , Ͻñ ٶϴ. -UninstalledAndNeedsRestart=%1 Ÿ ϷϷ, ǻ͸ ٽ ؾ մϴ.%n%n ٽ Ͻðڽϱ? -UninstallDataCorrupted= "%1"() ջǾ , Ÿ ϴ. - -; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle= Ͻðڽϱ? -ConfirmDeleteSharedFile2=ý  α׷ ʽϴ, Ͻðڽϱ?%n%n ٸ α׷ ϰ ִ ¿ , ش α׷ ۵ , Ȯ "ƴϿ" ϼŵ ˴ϴ. ýۿ ־ ʽϴ. -SharedFileNameLabel= ̸: -SharedFileLocationLabel=ġ: -WizardUninstalling= -StatusUninstalling=%1() ϴ ... - -; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=%1() ġϴ Դϴ. -ShutdownBlockReasonUninstallingApp=%1() ϴ Դϴ. - -; The custom messages below aren't used by Setup itself, but if you make -; use of them in your scripts, you'll want to translate them. - -[CustomMessages] - -NameAndVersion=%1 %2 -AdditionalIcons= ߰: -CreateDesktopIcon= ȭ鿡 ٷΰ (&D) -CreateQuickLaunchIcon= (&Q) -ProgramOnTheWeb=%1 -UninstallProgram=%1 -LaunchProgram=%1 -AssocFileExtension= Ȯ %2() %1 մϴ. -AssocingFileExtension= Ȯ %2() %1 ϴ ... -AutoStartProgramGroupDescription=: -AutoStartProgram=%1() ڵ -AddonHostProgramNotFound=%1() ġ ϴ.%n%n׷ Ͻðڽϱ? +; *** Inno Setup version 5.5.3+ Korean messages *** +; +; 5.5.3+ Translator: Domddol (domddol@gmail.com) +; Translation date: MAR 04, 2014 +; Contributors: Hansoo KIM (iryna7@gmail.com), Woong-Jae An (a183393@hanmail.net) +; Storage: http://www.jrsoftware.org/files/istrans/ +; ο ѱ Ģ ؼմϴ. + +[LangOptions] +LanguageName=Korean +LanguageID=$0412 +LanguageCodePage=949 + +[Messages] + +; *** Application titles +SetupAppTitle=ġ +SetupWindowTitle=%1 ġ +UninstallAppTitle= +UninstallAppFullTitle=%1 + +; *** Misc. common +InformationTitle= +ConfirmTitle=Ȯ +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage=%1() ġմϴ, Ͻðڽϱ? +LdrCannotCreateTemp=ӽ ϴ, ġ ߴմϴ +LdrCannotExecTemp=ӽ ϴ, ġ ߴմϴ + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing=%1 ʽϴ, ذ ų ο ġ α׷ Ͻñ ٶϴ. +SetupFileCorrupt=ġ ջǾϴ, ο ġ α׷ Ͻñ ٶϴ. +SetupFileCorruptOrWrongVer=ġ ջ̰ų ġ ȣȯ ʽϴ, ذ ų ο ġ α׷ Ͻñ ٶϴ. +InvalidParameter=߸ Ű Դϴ:%n%n%1 +SetupAlreadyRunning=ġ ̹ Դϴ. +WindowsVersionNotSupported= α׷ Windows ʽϴ. +WindowsServicePackRequired= α׷ Ϸ %1 sp%2 ̻̾ մϴ. +NotOnThisPlatform= α׷ %1 ۵ ʽϴ. +OnlyOnThisPlatform= α׷ %1 ؾ մϴ. +OnlyOnTheseArchitectures= α׷ Ʒ ó ȣȯǴ Windows ġ ֽϴ:%n%n%1 +MissingWOW64APIs= Windows 64Ʈ ġ ʿ ԵǾ ʽϴ, ذϷ sp%1() ġϽñ ٶϴ. +WinVersionTooLowError= α׷ %1 %2 ̻ ʿմϴ. +WinVersionTooHighError= α׷ %1 %2 ̻󿡼 ġ ϴ. +AdminPrivilegesRequired= α׷ ġϷ ڷ αؾ մϴ. +PowerUserPrivilegesRequired= α׷ ġϷ Ǵ ڷ αؾ մϴ. +SetupAppRunningError= %1() Դϴ!%n%n װ νϽ ݾ ֽʽÿ. ׷ Ϸ "Ȯ", Ϸ "" ŬϽʽÿ. +UninstallAppRunningError= %1() Դϴ!%n%n װ νϽ ݾ ֽʽÿ. ׷ Ϸ "Ȯ", Ϸ "" ŬϽʽÿ. + +; *** Misc. errors +ErrorCreatingDir="%1" ϴ. +ErrorTooManyFilesInDir="%1" ʹ ϴ. + +; *** Setup common messages +ExitSetupTitle=ġ Ϸ +ExitSetupMessage=ġ Ϸ ʾҽϴ, ⼭ ġ ϸ α׷ ġ ʽϴ.%n%nġ ϷϷ ߿ ٽ ġ α׷ ؾ մϴ.%n%n׷ ġ Ͻðڽϱ? +AboutSetupMenuItem=ġ (&A)... +AboutSetupTitle=ġ +AboutSetupMessage=%1 %2%n%3%n%n%1 Ȩ :%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< ڷ(&B) +ButtonNext=(&N) > +ButtonInstall=ġ(&I) +ButtonOK=Ȯ +ButtonCancel= +ButtonYes=(&Y) +ButtonYesToAll= (&A) +ButtonNo=ƴϿ(&N) +ButtonNoToAll= ƴϿ(&O) +ButtonFinish=(&F) +ButtonBrowse=ãƺ(&B)... +ButtonWizardBrowse=ãƺ(&R)... +ButtonNewFolder= (&M) + +; *** "Select Language" dialog messages +SelectLanguageTitle=ġ +SelectLanguageLabel=ġ ǥ : + +; *** Common wizard text +ClickNext=Ϸ "" Ŭϰ ġ Ϸ "" Ŭմϴ. +BeveledLabel= +BrowseDialogTitle= ãƺ +BrowseDialogLabel=Ʒ Ͽ "Ȯ" Ŭմϴ. +NewFolderName= + +; *** "Welcome" wizard page +WelcomeLabel1=[name] ġ +WelcomeLabel2= ǻͿ [name/ver]() ġ Դϴ.%n%nġϱ ٸ α׷ ñ ٶϴ. + +; *** "Password" wizard page +WizardPassword= ȣ +PasswordLabel1= ġ ȣ ȣǾ ֽϴ. +PasswordLabel3= ȣ Էϰ "" ŬϽʽÿ. ȣ ҹڸ ؾ մϴ. +PasswordEditLabel= ȣ(&P): +IncorrectPassword= ȣ Ȯ ʽϴ, ٽ ԷϽʽÿ! + +; *** "License Agreement" wizard page +WizardLicense= +LicenseLabel=ϱ ߿ оʽÿ. +LicenseLabel3= оʽÿ, ġ Ϸ ࿡ ؾ մϴ. +LicenseAccepted=մϴ(&A) +LicenseNotAccepted= ʽϴ(&D) + +; *** "Information" wizard pages +WizardInfoBefore= +InfoBeforeLabel=ϱ ߿ оʽÿ. +InfoBeforeClickLabel=ġ Ϸ "" ŬϽʽÿ. +WizardInfoAfter= +InfoAfterLabel=ϱ ߿ оʽÿ. +InfoAfterClickLabel=ġ Ϸ "" ŬϽʽÿ. + +; *** "User Information" wizard page +WizardUserInfo= +UserInfoDesc= ԷϽʽÿ. +UserInfoName= ̸(&U): +UserInfoOrg=(&O): +UserInfoSerial=Ϸ ȣ(&S): +UserInfoNameRequired= ̸ ԷϽʽÿ. + +; *** "Select Destination Location" wizard page +WizardSelectDir=ġ ġ +SelectDirDesc=[name] ġ ġ Ͻʽÿ. +SelectDirLabel3= [name]() ġմϴ. +SelectDirBrowseLabel=Ϸ "", ٸ Ϸ "ãƺ" ŬϽʽÿ. +DiskSpaceMBLabel= α׷ ּ [mb] MB ũ ʿմϴ. +CannotInstallToNetworkDrive=Ʈũ ̺꿡 ġ ϴ. +CannotInstallToUNCPath=UNC ο ġ ϴ. +InvalidPath=̺ ڸ ü θ ԷϽʽÿ.%n : C:\APP %n%nǴ, UNC θ ԷϽʽÿ.%n : \\server\share +InvalidDrive= ̺ Ǵ UNC ʰų ׼ ϴ, ٸ θ Ͻʽÿ. +DiskSpaceWarningTitle=ũ մϴ +DiskSpaceWarning=ġ ּ %1 KB ũ ʿ, ̺ %2 KB ۿ ϴ.%n%n׷ Ͻðڽϱ? +DirNameTooLong= ̸ Ǵ ΰ ʹ ϴ. +InvalidDirName= ̸ ȿ ʽϴ. +BadDirName32= ̸ ڸ ϴ:%n%n%1 +DirExistsTitle= մϴ +DirExists= %n%n%1%n%n() ̹ մϴ, ġϽðڽϱ? +DirDoesntExistTitle= ʽϴ +DirDoesntExist= %n%n%1%n%n() ʽϴ, ðڽϱ? + +; *** "Select Components" wizard page +WizardSelectComponents= +SelectComponentsDesc=ġ Ҹ Ͻʽÿ. +SelectComponentsLabel2=ʿ Ҵ üũϰ ʿ Ҵ üũ մϴ, Ϸ "" ŬϽʽÿ. +FullInstallation= ġ +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=ּ ġ +CustomInstallation= ġ +NoUninstallWarningTitle= Ұ մϴ +NoUninstallWarning= Ұ ̹ ġǾ ֽϴ:%n%n%1%n%n , α׷ Ž ҵ ŵ ̴ϴ.%n%n׷ Ͻðڽϱ? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel= ּ [mb] MB ũ ʿմϴ. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=߰ ۾ +SelectTasksDesc= ߰ ۾ Ͻʽÿ. +SelectTasksLabel2=[name] ġ ߰ ۾ , "" ŬϽʽÿ. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup= ޴ +SelectStartMenuFolderDesc= α׷ ٷΰ⸦ ġϰڽϱ? +SelectStartMenuFolderLabel3= ޴ α׷ ٷΰ⸦ ϴ. +SelectStartMenuFolderBrowseLabel=Ϸ "" Ŭϰ, ٸ Ϸ "ãƺ" ŬϽʽÿ. +MustEnterGroupName= ̸ ԷϽʽÿ. +GroupNameTooLong= ̸ Ǵ ΰ ʹ ϴ. +InvalidGroupName= ̸ ȿ ʽϴ. +BadGroupName= ̸ ڸ ϴ:%n%n%1 +NoProgramGroupCheck2= ޴ (&D) + +; *** "Ready to Install" wizard page +WizardReady=ġ غ Ϸ +ReadyLabel1= ǻͿ [name]() ġ غ Ǿϴ. +ReadyLabel2a=ġ Ϸ "ġ", ϰų Ϸ "ڷ" ŬϽʽÿ. +ReadyLabel2b=ġ Ϸ "ġ" ŬϽʽÿ. +ReadyMemoUserInfo= : +ReadyMemoDir=ġ ġ: +ReadyMemoType=ġ : +ReadyMemoComponents= : +ReadyMemoGroup= ޴ : +ReadyMemoTasks=߰ ۾: + +; *** "Preparing to Install" wizard page +WizardPreparing=ġ غ +PreparingDesc= ǻͿ [name] ġ غϴ Դϴ. +PreviousInstallNotCompleted= α׷ ġ/ ۾ Ϸ ʾҽϴ, ϷϷ ǻ͸ ٽ ؾ մϴ.%n%nǻ͸ ٽ , ġ 縦 ٽ Ͽ [name] ġ ϷϽñ ٶϴ. +CannotContinue=ġ ϴ, "" ŬϿ ġ Ͻʽÿ. +ApplicationsFound= α׷ ġ Ʈ ʿ ϰ ֽϴ, ġ 簡 ̷ α׷ ڵ ֵ Ͻñ ٶϴ. +ApplicationsFound2= α׷ ġ Ʈ ʿ ϰ ֽϴ, ġ 簡 ̷ α׷ ڵ ֵ Ͻñ ٶϴ. ġ ϷǸ, ġ α׷ ٽ ۵ǵ õ ̴ϴ. +CloseApplications=ڵ α׷ (&A) +DontCloseApplications=α׷ (&D) +ErrorCloseApplications=ġ 簡 α׷ ڵ ϴ, ϱ ġ Ʈ ʿ ϰ ִ α׷ Ͻñ ٶϴ. + +; *** "Installing" wizard page +WizardInstalling=ġ +InstallingLabel= ǻͿ [name]() ġϴ ... ٷ ֽʽÿ. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name] ġ Ϸ +FinishedLabelNoIcons= ǻͿ [name]() ġǾϴ. +FinishedLabel= ǻͿ [name]() ġǾϴ, α׷ ġ Ͽ ֽϴ. +ClickFinish=ġ "" ŬϽʽÿ. +FinishedRestartLabel=[name] ġ ϷϷ, ǻ͸ ٽ ؾ մϴ. ٽ Ͻðڽϱ? +FinishedRestartMessage=[name] ġ ϷϷ, ǻ͸ ٽ ؾ մϴ.%n%n ٽ Ͻðڽϱ? +ShowReadmeCheck=, README ǥմϴ +YesRadio=, ٽ մϴ(&Y) +NoRadio=ƴϿ, ߿ ٽ մϴ(&N) +; used for example as 'Run MyProg.exe' +RunEntryExec=%1 +; used for example as 'View Readme.txt' +RunEntryShellExec=%1 ǥ + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=ũ ʿմϴ +SelectDiskLabel2=ũ %1() ϰ "Ȯ" ŬϽʽÿ.%n%n ũ Ʒ ΰ ƴ ִ , ùٸ θ Էϰų "ãƺ" ŬϽñ ٶϴ. +PathLabel=(&P): +FileNotInDir2=%2 %1() ġ ϴ, ùٸ ũ ϰų ٸ Ͻʽÿ. +SelectDirectoryLabel= ũ ġ Ͻʽÿ. + +; *** Installation phase messages +SetupAborted=ġ Ϸ ʾҽϴ.%n%n ذ , ٽ ġ Ͻʽÿ. +EntryAbortRetryIgnore=ٽ õϷ "õ", ϰ Ϸ "", ġ Ϸ "" ŬϽʽÿ. + +; *** Installation status messages +StatusClosingApplications=α׷ ϴ ... +StatusCreateDirs= ... +StatusExtractFiles= ϴ ... +StatusCreateIcons=ٷΰ⸦ ϴ ... +StatusCreateIniEntries=INI ׸ ... +StatusCreateRegistryEntries=Ʈ ׸ ... +StatusRegisterFiles= ϴ ... +StatusSavingUninstall= ϴ ... +StatusRunProgram=ġ Ϸϴ ... +StatusRestartingApplications=α׷ ٽ ϴ ... +StatusRollback= ϴ ... + +; *** Misc. errors +ErrorInternal2= : %1 +ErrorFunctionFailedNoCode=%1 +ErrorFunctionFailed=%1 , ڵ: %2 +ErrorFunctionFailedWithMessage=%1 , ڵ: %2.%n%3 +ErrorExecutingProgram= :%n%1 + +; *** Registry errors +ErrorRegOpenKey=Ʈ Ű :%n%1\%2 +ErrorRegCreateKey=Ʈ Ű :%n%1\%2 +ErrorRegWriteKey=Ʈ Ű :%n%1\%2 + +; *** INI errors +ErrorIniEntry=%1 Ͽ INI ׸ Դϴ. + +; *** File copying errors +FileAbortRetryIgnore=ٽ õϷ "õ", dzʶٷ ""(õ), ġ Ϸ "" ŬϽʽÿ. +FileAbortRetryIgnore2=ٽ õϷ "õ", Ϸ ""(õ), ġ Ϸ "" ŬϽʽÿ. +SourceIsCorrupted= ջ +SourceDoesntExist= %1() +ExistingFileReadOnly= б Դϴ.%n%nб Ӽ ϰ ٽ õϷ "õ", dzʶٷ "", ġ Ϸ "" ŬϽʽÿ. +ErrorReadingExistingDest= д ߻: +FileExists= ̹ մϴ.%n%n ðڽϱ? +ExistingFileNewer= ġϷ ϴ Ϻ Դϴ, Ͻñ ٶϴ.%n%n Ͻðڽϱ? +ErrorChangingAttr= Ӽ ϴ ߻: +ErrorCreatingTemp= ߻: +ErrorReadingSource= д ߻: +ErrorCopying= ϴ ߻: +ErrorReplacingExistingFile= üϴ ߻: +ErrorRestartReplace=RestartReplace : +ErrorRenamingTemp= ̸ ٲٴ ߻: +ErrorRegisterServer=DLL/OCX : %1 +ErrorRegSvr32Failed=RegSvr32 ڵ : %1 +ErrorRegisterTypeLib= ̺귯 Ͽ : %1 + +; *** Post-installation errors +ErrorOpeningReadme=README ߻߽ϴ. +ErrorRestartingComputer=ǻ͸ ٽ ϴ, ٽ Ͻʽÿ. + +; *** Uninstaller messages +UninstallNotFound= %1() ʱ , Ÿ ϴ. +UninstallOpenError= %1() , Ÿ ϴ. +UninstallUnsupportedVer= α "%1"() ν ̱ , Ÿ ϴ. +UninstallUnknownEntry= ׸ %1() α׿ ԵǾ ֽϴ. +ConfirmUninstall= %1() Ҹ Ͻðڽϱ? +UninstallOnlyOnWin64= α׷ 64Ʈ Windows ֽϴ. +OnlyAdminCanUninstall= α׷ Ϸ ʿմϴ. +UninstallStatusLabel= ǻͿ %1() ϴ ... ٷ ֽʽÿ. +UninstalledAll=%1() ŵǾϴ! +UninstalledMost=%1 Ű ϷǾϴ.%n%nϺ Ҵ , Ͻñ ٶϴ. +UninstalledAndNeedsRestart=%1 Ÿ ϷϷ, ǻ͸ ٽ ؾ մϴ.%n%n ٽ Ͻðڽϱ? +UninstallDataCorrupted= "%1"() ջǾ , Ÿ ϴ. + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle= Ͻðڽϱ? +ConfirmDeleteSharedFile2=ý  α׷ ʽϴ, Ͻðڽϱ?%n%n ٸ α׷ ϰ ִ ¿ , ش α׷ ۵ , Ȯ "ƴϿ" ϼŵ ˴ϴ. ýۿ ־ ʽϴ. +SharedFileNameLabel= ̸: +SharedFileLocationLabel=ġ: +WizardUninstalling= +StatusUninstalling=%1() ϴ ... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=%1() ġϴ Դϴ. +ShutdownBlockReasonUninstallingApp=%1() ϴ Դϴ. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 %2 +AdditionalIcons= ߰: +CreateDesktopIcon= ȭ鿡 ٷΰ (&D) +CreateQuickLaunchIcon= (&Q) +ProgramOnTheWeb=%1 +UninstallProgram=%1 +LaunchProgram=%1 +AssocFileExtension= Ȯ %2() %1 մϴ. +AssocingFileExtension= Ȯ %2() %1 ϴ ... +AutoStartProgramGroupDescription=: +AutoStartProgram=%1() ڵ +AddonHostProgramNotFound=%1() ġ ϴ.%n%n׷ Ͻðڽϱ? diff --git a/distrib/Languages/Slovak.isl b/distrib/Languages/Slovak.isl index 43fa0c55c58..8805791de9c 100644 --- a/distrib/Languages/Slovak.isl +++ b/distrib/Languages/Slovak.isl @@ -1,263 +1,263 @@ -; ****************************************************** -; *** *** -; *** Inno Setup version 5.5.3+ Slovak messages *** -; *** *** -; *** Original Author: *** -; *** *** -; *** Milan Potancok (milan.potancok AT gmail.com) *** -; *** *** -; *** Contributors: *** -; *** *** -; *** Ivo Bauer (bauer AT ozm.cz) *** -; *** *** -; *** Tomas Falb (tomasf AT pobox.sk) *** -; *** Slappy (slappy AT pobox.sk) *** -; *** *** -; *** Update: 04.02.2013 *** -; *** *** -; ****************************************************** -; -; - -[LangOptions] -LanguageName=Sloven<010D>ina -LanguageID=$041b -LanguageCodePage=1250 - -[Messages] -SetupAppTitle=Sprievodca intalciou -SetupWindowTitle=Sprievodca intalciou - %1 -UninstallAppTitle=Sprievodca odintalciou -UninstallAppFullTitle=Sprievodca odintalciou - %1 -InformationTitle=Informcie -ConfirmTitle=Potvrdenie -ErrorTitle=Chyba -SetupLdrStartupMessage=Toto je sprievodca intalciou produktu %1. Prajete si pokraova? -LdrCannotCreateTemp=Nie je mon vytvori doasn sbor. Sprievodca intalciou sa ukon -LdrCannotExecTemp=Nie je mon spusti sbor v doasnom adresri. Sprievodca intalciou sa ukon -LastErrorMessage=%1.%n%nChyba %2: %3 -SetupFileMissing=Intalan adresr neobsahuje sbor %1. Opravte, prosm, tto chybu alebo si zaobstarajte nov kpiu tohto produktu. -SetupFileCorrupt=Sbory sprievodcu intalciou s pokoden. Zaobstarajte si, prosm, nov kpiu tohto produktu. -SetupFileCorruptOrWrongVer=Sbory sprievodcu intalciou s pokoden alebo sa nezhoduj s touto verziou sprievodcu instalciou. Opravte, prosm, tto chybu alebo si zaobstarajte nov kpiu tohto produktu. -InvalidParameter=Nesprvny parameter na prkazovom riadku:%n%n%1 -SetupAlreadyRunning=Intalcia u be. -WindowsVersionNotSupported=Tento program nepodporuje vau verziu Windows. -WindowsServicePackRequired=Tento program vyaduje %1 Service Pack %2 alebo nov. -NotOnThisPlatform=Tento produkt sa ned spusti v %1. -OnlyOnThisPlatform=Tento produkt mus by spusten v %1. -OnlyOnTheseArchitectures=Tento produkt je mon naintalova iba vo verzich MS Windows s podporou architektry procesorov:%n%n%1 -MissingWOW64APIs=Aktulna verzia MS Windows neobsahuje funkcie, ktor vyaduje sprievodca intalciou pre 64-bitov intalciu. Opravte, prosm, tto chybu naintalovanm aktualizcie Service Pack %1. -WinVersionTooLowError=Tento produkt vyaduje %1 verzie %2 alebo vyej. -WinVersionTooHighError=Tento produkt sa ned naintalova vo %1 verzie %2 alebo vyej. -AdminPrivilegesRequired=Na intalciu tohto produktu muste by prihlsen s prvami administrtora. -PowerUserPrivilegesRequired=Na intalciu tohto produktu muste by prihlsen s prvami administrtora alebo lena skupiny Power Users. -SetupAppRunningError=Sprievodca intalciou zistil, e produkt %1 je teraz spusten.%n%nUkonite, prosm, vetky spusten intancie tohto produktu a pokraujte kliknutm na tlaidlo OK alebo ukonite intalciu tlaidlom Zrui. -UninstallAppRunningError=Sprievodca odintalciou zistil, e produkt %1 je teraz spusten.%n%nUkonite, prosm, vetky spusten intancie tohto produktu a pokraujte kliknutm na tlaidlo OK alebo ukonite intalciu tlaidlom Zrui. -ErrorCreatingDir=Sprievodca intalciou nemohol vytvori adresr "%1" -ErrorTooManyFilesInDir=Ned sa vytvori sbor v adresri "%1", pretoe tento adresr u obsahuje prli vea sborov -ExitSetupTitle=Ukoni sprievodcu intalciou -ExitSetupMessage=Intalcia nebola celkom dokonen. Ak teraz ukonte sprievodcu intalciou, produkt nebude naintalovan.%n%nSprievodcu intalciou mete znovu spusti neskr a dokoni tak intalciu.%n%nUkoni sprievodcu intalciou? -AboutSetupMenuItem=&O sprievodcovi intalcie... -AboutSetupTitle=O sprievodcovi intalcie -AboutSetupMessage=%1 verzia %2%n%3%n%n%1 domovsk strnka:%n%4 -AboutSetupNote= -TranslatorNote=Slovak translation maintained by Milan Potancok (milan.potancok AT gmail.com), Ivo Bauer (bauer AT ozm.cz) and Tomas Falb (tomasf AT pobox.sk) + Slappy (slappy AT pobox.sk) -ButtonBack=< &Sp -ButtonNext=&alej > -ButtonInstall=&Intalova -ButtonOK=OK -ButtonCancel=Zrui -ButtonYes=&no -ButtonYesToAll=no &vetkm -ButtonNo=&Nie -ButtonNoToAll=Ni&e vetkm -ButtonFinish=&Dokoni -ButtonBrowse=&Prechdza... -ButtonWizardBrowse=&Prechdza... -ButtonNewFolder=&Vytvori nov adresr -SelectLanguageTitle=Vber jazyka sprievodcu intalciou -SelectLanguageLabel=Zvote jazyk, ktor sa m poui pri intalcii: -ClickNext=Pokraujte kliknutm na tlaidlo alej alebo ukonite sprievodcu intalciou tlaidlom Zrui. -BeveledLabel= -BrowseDialogTitle=Njs adresr -BrowseDialogLabel=Z dole uvedenho zoznamu vyberte adresr a kliknite na OK. -NewFolderName=Nov adresr -WelcomeLabel1=Vt Vs sprievodca intalciou produktu [name]. -WelcomeLabel2=Produkt [name/ver] sa naintaluje na V pota.%n%nSkr, ako budete pokraova, odporame Vm ukoni vetky spusten aplikcie. -WizardPassword=Heslo -PasswordLabel1=Tto intalcia je chrnen heslom. -PasswordLabel3=Zadajte, prosm, heslo a pokraujte kliknutm na tlaidlo alej. Pri zadvn hesla rozliujte mal a vek psmen. -PasswordEditLabel=&Heslo: -IncorrectPassword=Zadan heslo nie je sprvne. Zkste to, prosm, ete raz. -WizardLicense=Licenn zmluva -LicenseLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. -LicenseLabel3=Pretajte si, prosm, tto Licenn zmluvu. Aby mohla intalcia pokraova, muste shlasi s podmienkami tejto zmluvy. -LicenseAccepted=&Shlasm s podmienkami Licennej zmluvy -LicenseNotAccepted=&Neshlasm s podmienkami Licennej zmluvy -WizardInfoBefore=Informcie -InfoBeforeLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. -InfoBeforeClickLabel=Pokraujte v intalcii kliknutm na tlaidlo alej. -WizardInfoAfter=Informcie -InfoAfterLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. -InfoAfterClickLabel=Pokraujte v intalcii kliknutm na tlaidlo alej. -WizardUserInfo=Informcie o pouvateovi -UserInfoDesc=Zadajte, prosm, poadovan informcie. -UserInfoName=&Pouvatesk meno: -UserInfoOrg=&Organizcia: -UserInfoSerial=&Sriove slo: -UserInfoNameRequired=Pouvatesk meno mus by zadan. -WizardSelectDir=Vyberte cieov adresr -SelectDirDesc=Kam m by produkt [name] naintalovan? -SelectDirLabel3=Sprievodca naintaluje produkt [name] do nasledujceho adresra. -SelectDirBrowseLabel=Pokraujte kliknutm na tlaidlo alej. Ak chcete vybra in adresr, kliknite na tlaidlo Prechdza. -DiskSpaceMBLabel=Intalcia vyaduje najmenej [mb] MB miesta na disku. -CannotInstallToNetworkDrive=Intaltor neme intalova na sieov jednotku. -CannotInstallToUNCPath=Intaltor neme intalova na UNC cestu. -InvalidPath=Muste zadat pln cestu vrtane psmena jednotky; naprklad:%n%nC:\Aplikcia%n%nalebo cestu UNC v tvare:%n%n\\server\zdiean adresr -InvalidDrive=Vami vybran jednotka alebo cesta UNC neexistuje alebo nie je dostupn. Vyberte, prosm, in umiestnenie. -DiskSpaceWarningTitle=Nedostatok miesta na disku -DiskSpaceWarning=Sprievodca intalciou vyaduje najmenej %1 KB vonho miesta na intalciu produktu, ale na vybranej jednotke je dostupnch len %2 KB.%n%nPrajete si napriek tomu pokraova? -DirNameTooLong=Nzov adresra alebo cesta s prli dlh. -InvalidDirName=Nzov adresra nie je platn. -BadDirName32=Nzvy adresrov nesm obsahova iadny z nasledujcich znakov:%n%n%1 -DirExistsTitle=Adresr existuje -DirExists=Adresr:%n%n%1%n%nu existuje. M sa napriek tomu intalova do tohto adresra? -DirDoesntExistTitle=Adresr neexistuje -DirDoesntExist=Adresr:%n%n%1%n%nete neexistuje. M sa tento adresr vytvori? -WizardSelectComponents=Vyberte komponenty -SelectComponentsDesc=Ak komponenty maj by naintalovan? -SelectComponentsLabel2=Zakrtnite komponenty, ktor maj by naintalovan; komponenty, ktor se nemaj intalova, nechajte nezakrtnut. Pokraujte kliknutm na tlaidlo alej. -FullInstallation=pln intalcia -CompactInstallation=Kompaktn intalcia -CustomInstallation=Voliten intalcia -NoUninstallWarningTitle=Komponenty existuj -NoUninstallWarning=Sprievodca intalciou zistil, e nasledujce komponenty s u na Vaom potai naintalovan:%n%n%1%n%nAk ich teraz nezahrniete do vberu, nebud neskr odintalovan.%n%nPrajete si napriek tomu pokraova? -ComponentSize1=%1 KB -ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=Vybran komponenty vyaduj najmenej [mb] MB miesta na disku. -WizardSelectTasks=Vyberte alie lohy -SelectTasksDesc=Ktor alie lohy maj by vykonan? -SelectTasksLabel2=Vyberte alie lohy, ktor maj by vykonan v priebehu intalcie produktu [name] a pokraujte kliknutm na tlaidlo alej. -WizardSelectProgramGroup=Vyberte skupinu v ponuke tart -SelectStartMenuFolderDesc=Kam m sprievodca intalcie umiestni zstupcov aplikcie? -SelectStartMenuFolderLabel3=Sprievodca intalciou vytvor zstupcov aplikcie v nasledujcom adresri ponuky tart. -SelectStartMenuFolderBrowseLabel=Pokraujte kliknutm na tlaidlo alej. Ak chcete zvoli in adresr, kliknite na tlaidlo Prechdza. -MustEnterGroupName=Muste zada nzov skupiny. -GroupNameTooLong=Nzov adresra alebo cesta s prli dlh. -InvalidGroupName=Nzov adresra nie je platn. -BadGroupName=Nzov skupiny nesmie obsahova iadny z nasledujcich znakov:%n%n%1 -NoProgramGroupCheck2=&Nevytvra skupinu v ponuke tart -WizardReady=Intalcia je pripraven -ReadyLabel1=Sprievodca intalciou je teraz pripraven naintalova produkt [name] na V pota. -ReadyLabel2a=Pokraujte v intalcii kliknutm na tlaidlo Intalova. Ak si prajete zmeni niektor nastavenia intalcie, kliknite na tlaidlo Sp. -ReadyLabel2b=Pokraujte v intalcii kliknutm na tlaidlo Intalova. -ReadyMemoUserInfo=Informcie o pouvateovi: -ReadyMemoDir=Cieov adresr: -ReadyMemoType=Typ intalcie: -ReadyMemoComponents=Vybran komponenty: -ReadyMemoGroup=Skupina v ponuke tart: -ReadyMemoTasks=alie lohy: -WizardPreparing=Prprava intalcie -PreparingDesc=Sprievodca intalciou pripravuje intalciu produktu [name] na V pota. -PreviousInstallNotCompleted=Intalcia/odintalcia predolho produktu nebola plne dokonen. Dokonenie tohto procesu vyaduje retart potaa.%n%nPo retartovan potaa spustite znovu sprievodcu intalciou, aby bolo mon dokoni intalciu produktu [name]. -CannotContinue=Sprievodca intalciou neme pokraova. Ukonite, prosm, sprievodcu intalciou kliknutm na tlaidlo Zrui. -ApplicationsFound=Nasledujce aplikcie pracuj so sbormi, ktor mus intaltor aktualizova. Odporame Vm, aby ste povolili intaltoru automaticky ukoni tieto aplikcie. -ApplicationsFound2=Nasledujce aplikcie pracuj so sbormi, ktor mus intaltor aktualizova. Odporame Vm, aby ste povolili intaltoru automaticky ukoni tieto aplikcie. Po skonen intalcie sa intaltor poksi tieto aplikcie optovne spusti. -CloseApplications=&Automaticky ukoni aplikcie -DontCloseApplications=&Neukonova aplikcie -ErrorCloseApplications=Sprievodca nemohol automaticky zatvori vetky aplikcie. Odporame Vm, aby ste rune uzavreli vetky aplikcie, ktor pouvaj sbory, ktor m Sprievodca aktualizova. -WizardInstalling=Intalujem -InstallingLabel=Pokajte prosm, km sprievodca intalciou nedokon intalciu produktu [name] na V pota. -FinishedHeadingLabel=Dokonuje sa intalcia produktu [name] -FinishedLabelNoIcons=Sprievodca intalciou dokonil intalciu produktu [name] na V pota. -FinishedLabel=Sprievodca intalciou dokonil intalciu produktu [name] na V pota. Produkt je mon spusti pomocou naintalovanch ikon a zstupcov. -ClickFinish=Ukonite sprievodcu intalciou kliknutm na tlaidlo Dokoni. -FinishedRestartLabel=Na dokonenie intalcie produktu [name] je nutn retartova V pota. Prajete si teraz retartova V pota? -FinishedRestartMessage=Na dokonenie intalcie produktu [name] je nutn retartova V pota.%n%nPrajete si teraz retartova V pota? -ShowReadmeCheck=no, chcem zobrazi dokument "ITAJMA" -YesRadio=&no, chcem teraz retartova pota -NoRadio=&Nie, pota retartujem neskr -RunEntryExec=Spusti %1 -RunEntryShellExec=Zobrazi %1 -ChangeDiskTitle=Sprievodca intalciou vyaduje al disk -SelectDiskLabel2=Vlote, prosm, disk %1 a kliknite na tlaidlo OK.%n%nAk sa sbory na tomto disku nachdzaj v inom adresri, ako v tom, ktor je zobrazen niie, zadejte sprvnu cestu alebo kliknite na tlaidlo Prechdza. -PathLabel=&Cesta: -FileNotInDir2=Sbor "%1" sa ned njs v "%2". Vlote, prosm, sprvny disk alebo zvote in adresr. -SelectDirectoryLabel=pecifikujte,prosm, umiestnenie alieho disku. -SetupAborted=Intalcia nebola plne dokonen.%n%nOpravte, prosm, chybu a spustite sprievodcu intalciou znova. -EntryAbortRetryIgnore=Akciu zopakujete kliknutm na tlaidlo Opakova. Akciu vynechte kliknutm na tlaidlo Preskoi. Intalciu prerute kliknutm na tlaidlo Prerui. -StatusClosingApplications=Ukonovanie aplikci... -StatusCreateDirs=Vytvraj sa adresre... -StatusExtractFiles=Rozbauj sa sbory... -StatusCreateIcons=Vytvraj sa ikony a zstupcovia... -StatusCreateIniEntries=Vytvraj sa zznamy v konfiguranch sboroch... -StatusCreateRegistryEntries=Vytvraj sa zznamy v systmovom registri... -StatusRegisterFiles=Registruj sa sbory... -StatusSavingUninstall=Ukladaj sa informcie potrebn pre neskorie odintalovanie produktu... -StatusRunProgram=Dokonuje sa intalcia... -StatusRestartingApplications=Retartovanie aplikci... -StatusRollback=Vykonan zmeny sa vracaj sp... -ErrorInternal2=Intern chyba: %1 -ErrorFunctionFailedNoCode=%1 zlyhala -ErrorFunctionFailed=%1 zlyhala; kd %2 -ErrorFunctionFailedWithMessage=%1 zlyhala; kd %2.%n%3 -ErrorExecutingProgram=Ned sa spusti sbor:%n%1 -ErrorRegOpenKey=Dolo k chybe pri otvran ka systmovho registra:%n%1\%2 -ErrorRegCreateKey=Dolo k chybe pri vytvran ka systmovho registra:%n%1\%2 -ErrorRegWriteKey=Dolo k chybe pri zpise do ka systmovho registra:%n%1\%2 -ErrorIniEntry=Dolo k chybe pri vytvran zznamu v konfiguranom sbore "%1". -FileAbortRetryIgnore=Akciu zopakujete kliknutm na tlaidlo Opakova. Tento sbor preskote kliknutm na tlaidlo Preskoi (neodpora sa). Intalciu prerute tlaidlom Prerui. -FileAbortRetryIgnore2=Akciu zopakujete kliknutm na tlaidlo Opakova. Pokraujete kliknutm na tlaidlo Preskoi (neodpora sa). Intalciu prerute tlaidlom Prerui. -SourceIsCorrupted=Zdrojov sbor je pokoden -SourceDoesntExist=Zdrojov sbor "%1" neexistuje -ExistingFileReadOnly=Existujci sbor je uren len na tanie.%n%nAtribt "Iba na tanie" odstrnite a akciu zopakujete kliknutm na tlaidlo Opakova. Sbor preskote kliknutm na tlaidlo Preskoi. Intalciu prerute kliknutm na tlaidlo Prerui. -ErrorReadingExistingDest=Dolo k chybe pri pokuse o tanie existujceho sboru: -FileExists=Sbor u existuje.%n%nM ho sprievodca intalcie prepsa? -ExistingFileNewer=Existujci sbor je nov ako ten, ktor sa sprievodca intalciou poka naintalova. Odpora sa ponecha existujci sbor.%n%nPrajete si ponechat existujci sbor? -ErrorChangingAttr=Dolo k chybe pri pokuse o modifikciu atribtov existujceho sboru: -ErrorCreatingTemp=Dolo k chybe pri pokuse o vytvorenie sboru v cieovom adresri: -ErrorReadingSource=Dolo k chybe pri pokuse o tanie zdrojovho sboru: -ErrorCopying=Dolo k chybe pri pokuse o skoprovanie sboru: -ErrorReplacingExistingFile=Dolo k chybe pri pokuse o nahradenie existujceho sboru: -ErrorRestartReplace=Zlyhala funkcia "RestartReplace" sprievodcu intalciou: -ErrorRenamingTemp=Dolo k chybe pri pokuse o premenovanie sboru v cieovom adresri: -ErrorRegisterServer=Ned sa vykona registrcia DLL/OCX: %1 -ErrorRegSvr32Failed=Volanie RegSvr32 zlyhalo s nvratovm kdom %1 -ErrorRegisterTypeLib=Ned sa vykona registrcia typovej kninice: %1 -ErrorOpeningReadme=Dolo k chybe pri pokuse o otvorenie dokumentu "ITAJMA". -ErrorRestartingComputer=Sprievodcovi intalciou sa nepodarilo retartova V pota. Retartujte ho, prosm, manulne. -UninstallNotFound=Sbor "%1" neexistuje. Produkt sa ned odintalova. -UninstallOpenError=Sbor "%1" nie je mon otvori. Produkt nie je mon odintalova. -UninstallUnsupportedVer=Sprievodcovi odintalciou sa nepodarilo rozpozna formt sboru obsahujceho informcie na odintalovanie produktu "%1". Produkt sa ned odintalova -UninstallUnknownEntry=V sbore obsahujcom informcie na odintalovanie produktu bola zisten neznma poloka (%1) -ConfirmUninstall=Ste si naozaj ist, e chcete odintalova %1 a vetky jeho komponenty? -UninstallOnlyOnWin64=Tento produkt je mon odintalova iba v 64-bitovch verzich MS Windows. -OnlyAdminCanUninstall=K odintalovaniu tohto produktu muste by prihlsen s prvami administrtora. -UninstallStatusLabel=Pokajte prosm, km produkt %1 nebude odintalovan z Vho potaa. -UninstalledAll=%1 bol spene odintalovan z Vho potaa. -UninstalledMost=%1 bol odintalovan z Vho potaa.%n%nNiektor jeho komponenty sa vak nepodarilo odintalova. Mete ich odintalova manulne. -UninstalledAndNeedsRestart=Na dokonenie odintalcie produktu %1 je potrebn retartova V pota.%n%nPrajete si teraz retartova V pota? -UninstallDataCorrupted=Sbor "%1" je pokoden. Produkt sa ned odintalova -ConfirmDeleteSharedFileTitle=Odintalova zdiean sbor? -ConfirmDeleteSharedFile2=Systm indikuje, e nsledujci zdiean sbor nie je pouvan iadnymi inmi aplikciami. M sprievodca odintalcie tento zdiean sbor odstrni?%n%nAk niektor aplikcie tento sbor pouvaj, nemusia po jeho odintalovan pracova sprvne. Ak si nie ste ist, zvote Nie. Ponechanie tohoto sboru vo Vaom systme nespsob iadnu kodu. -SharedFileNameLabel=Nzov sboru: -SharedFileLocationLabel=Umiestnenie: -WizardUninstalling=Stav odintalovania -StatusUninstalling=Odintalujem %1... -ShutdownBlockReasonInstallingApp=Intalovanie %1. -ShutdownBlockReasonUninstallingApp=Odintalovanie %1. - - -[CustomMessages] -NameAndVersion=%1 verzia %2 -AdditionalIcons=al zstupcovia: -CreateDesktopIcon=Vytvori zstupcu na &ploche -CreateQuickLaunchIcon=Vytvori zstupcu na paneli &Rchle spustenie -ProgramOnTheWeb=Aplikcia %1 na internete -UninstallProgram=Odintalova aplikciu %1 -LaunchProgram=Spusti aplikciu %1 -AssocFileExtension=Vytvori &asociciu medzi sbormi typu %2 a aplikciou %1 -AssocingFileExtension=Vytvra sa asocicia medzi sbormi typu %2 a aplikciou %1... -AutoStartProgramGroupDescription=Po spusten: -AutoStartProgram=Automaticky spusti %1 -AddonHostProgramNotFound=Nepodarilo sa njs %1 v prieinku, ktor ste zvolili.%n%nChcete napriek tomu pokraova? +; ****************************************************** +; *** *** +; *** Inno Setup version 5.5.3+ Slovak messages *** +; *** *** +; *** Original Author: *** +; *** *** +; *** Milan Potancok (milan.potancok AT gmail.com) *** +; *** *** +; *** Contributors: *** +; *** *** +; *** Ivo Bauer (bauer AT ozm.cz) *** +; *** *** +; *** Tomas Falb (tomasf AT pobox.sk) *** +; *** Slappy (slappy AT pobox.sk) *** +; *** *** +; *** Update: 04.02.2013 *** +; *** *** +; ****************************************************** +; +; + +[LangOptions] +LanguageName=Sloven<010D>ina +LanguageID=$041b +LanguageCodePage=1250 + +[Messages] +SetupAppTitle=Sprievodca intalciou +SetupWindowTitle=Sprievodca intalciou - %1 +UninstallAppTitle=Sprievodca odintalciou +UninstallAppFullTitle=Sprievodca odintalciou - %1 +InformationTitle=Informcie +ConfirmTitle=Potvrdenie +ErrorTitle=Chyba +SetupLdrStartupMessage=Toto je sprievodca intalciou produktu %1. Prajete si pokraova? +LdrCannotCreateTemp=Nie je mon vytvori doasn sbor. Sprievodca intalciou sa ukon +LdrCannotExecTemp=Nie je mon spusti sbor v doasnom adresri. Sprievodca intalciou sa ukon +LastErrorMessage=%1.%n%nChyba %2: %3 +SetupFileMissing=Intalan adresr neobsahuje sbor %1. Opravte, prosm, tto chybu alebo si zaobstarajte nov kpiu tohto produktu. +SetupFileCorrupt=Sbory sprievodcu intalciou s pokoden. Zaobstarajte si, prosm, nov kpiu tohto produktu. +SetupFileCorruptOrWrongVer=Sbory sprievodcu intalciou s pokoden alebo sa nezhoduj s touto verziou sprievodcu instalciou. Opravte, prosm, tto chybu alebo si zaobstarajte nov kpiu tohto produktu. +InvalidParameter=Nesprvny parameter na prkazovom riadku:%n%n%1 +SetupAlreadyRunning=Intalcia u be. +WindowsVersionNotSupported=Tento program nepodporuje vau verziu Windows. +WindowsServicePackRequired=Tento program vyaduje %1 Service Pack %2 alebo nov. +NotOnThisPlatform=Tento produkt sa ned spusti v %1. +OnlyOnThisPlatform=Tento produkt mus by spusten v %1. +OnlyOnTheseArchitectures=Tento produkt je mon naintalova iba vo verzich MS Windows s podporou architektry procesorov:%n%n%1 +MissingWOW64APIs=Aktulna verzia MS Windows neobsahuje funkcie, ktor vyaduje sprievodca intalciou pre 64-bitov intalciu. Opravte, prosm, tto chybu naintalovanm aktualizcie Service Pack %1. +WinVersionTooLowError=Tento produkt vyaduje %1 verzie %2 alebo vyej. +WinVersionTooHighError=Tento produkt sa ned naintalova vo %1 verzie %2 alebo vyej. +AdminPrivilegesRequired=Na intalciu tohto produktu muste by prihlsen s prvami administrtora. +PowerUserPrivilegesRequired=Na intalciu tohto produktu muste by prihlsen s prvami administrtora alebo lena skupiny Power Users. +SetupAppRunningError=Sprievodca intalciou zistil, e produkt %1 je teraz spusten.%n%nUkonite, prosm, vetky spusten intancie tohto produktu a pokraujte kliknutm na tlaidlo OK alebo ukonite intalciu tlaidlom Zrui. +UninstallAppRunningError=Sprievodca odintalciou zistil, e produkt %1 je teraz spusten.%n%nUkonite, prosm, vetky spusten intancie tohto produktu a pokraujte kliknutm na tlaidlo OK alebo ukonite intalciu tlaidlom Zrui. +ErrorCreatingDir=Sprievodca intalciou nemohol vytvori adresr "%1" +ErrorTooManyFilesInDir=Ned sa vytvori sbor v adresri "%1", pretoe tento adresr u obsahuje prli vea sborov +ExitSetupTitle=Ukoni sprievodcu intalciou +ExitSetupMessage=Intalcia nebola celkom dokonen. Ak teraz ukonte sprievodcu intalciou, produkt nebude naintalovan.%n%nSprievodcu intalciou mete znovu spusti neskr a dokoni tak intalciu.%n%nUkoni sprievodcu intalciou? +AboutSetupMenuItem=&O sprievodcovi intalcie... +AboutSetupTitle=O sprievodcovi intalcie +AboutSetupMessage=%1 verzia %2%n%3%n%n%1 domovsk strnka:%n%4 +AboutSetupNote= +TranslatorNote=Slovak translation maintained by Milan Potancok (milan.potancok AT gmail.com), Ivo Bauer (bauer AT ozm.cz) and Tomas Falb (tomasf AT pobox.sk) + Slappy (slappy AT pobox.sk) +ButtonBack=< &Sp +ButtonNext=&alej > +ButtonInstall=&Intalova +ButtonOK=OK +ButtonCancel=Zrui +ButtonYes=&no +ButtonYesToAll=no &vetkm +ButtonNo=&Nie +ButtonNoToAll=Ni&e vetkm +ButtonFinish=&Dokoni +ButtonBrowse=&Prechdza... +ButtonWizardBrowse=&Prechdza... +ButtonNewFolder=&Vytvori nov adresr +SelectLanguageTitle=Vber jazyka sprievodcu intalciou +SelectLanguageLabel=Zvote jazyk, ktor sa m poui pri intalcii: +ClickNext=Pokraujte kliknutm na tlaidlo alej alebo ukonite sprievodcu intalciou tlaidlom Zrui. +BeveledLabel= +BrowseDialogTitle=Njs adresr +BrowseDialogLabel=Z dole uvedenho zoznamu vyberte adresr a kliknite na OK. +NewFolderName=Nov adresr +WelcomeLabel1=Vt Vs sprievodca intalciou produktu [name]. +WelcomeLabel2=Produkt [name/ver] sa naintaluje na V pota.%n%nSkr, ako budete pokraova, odporame Vm ukoni vetky spusten aplikcie. +WizardPassword=Heslo +PasswordLabel1=Tto intalcia je chrnen heslom. +PasswordLabel3=Zadajte, prosm, heslo a pokraujte kliknutm na tlaidlo alej. Pri zadvn hesla rozliujte mal a vek psmen. +PasswordEditLabel=&Heslo: +IncorrectPassword=Zadan heslo nie je sprvne. Zkste to, prosm, ete raz. +WizardLicense=Licenn zmluva +LicenseLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. +LicenseLabel3=Pretajte si, prosm, tto Licenn zmluvu. Aby mohla intalcia pokraova, muste shlasi s podmienkami tejto zmluvy. +LicenseAccepted=&Shlasm s podmienkami Licennej zmluvy +LicenseNotAccepted=&Neshlasm s podmienkami Licennej zmluvy +WizardInfoBefore=Informcie +InfoBeforeLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. +InfoBeforeClickLabel=Pokraujte v intalcii kliknutm na tlaidlo alej. +WizardInfoAfter=Informcie +InfoAfterLabel=Skr, ako budete pokraova, pretajte si, prosm, tieto dleit informcie. +InfoAfterClickLabel=Pokraujte v intalcii kliknutm na tlaidlo alej. +WizardUserInfo=Informcie o pouvateovi +UserInfoDesc=Zadajte, prosm, poadovan informcie. +UserInfoName=&Pouvatesk meno: +UserInfoOrg=&Organizcia: +UserInfoSerial=&Sriove slo: +UserInfoNameRequired=Pouvatesk meno mus by zadan. +WizardSelectDir=Vyberte cieov adresr +SelectDirDesc=Kam m by produkt [name] naintalovan? +SelectDirLabel3=Sprievodca naintaluje produkt [name] do nasledujceho adresra. +SelectDirBrowseLabel=Pokraujte kliknutm na tlaidlo alej. Ak chcete vybra in adresr, kliknite na tlaidlo Prechdza. +DiskSpaceMBLabel=Intalcia vyaduje najmenej [mb] MB miesta na disku. +CannotInstallToNetworkDrive=Intaltor neme intalova na sieov jednotku. +CannotInstallToUNCPath=Intaltor neme intalova na UNC cestu. +InvalidPath=Muste zadat pln cestu vrtane psmena jednotky; naprklad:%n%nC:\Aplikcia%n%nalebo cestu UNC v tvare:%n%n\\server\zdiean adresr +InvalidDrive=Vami vybran jednotka alebo cesta UNC neexistuje alebo nie je dostupn. Vyberte, prosm, in umiestnenie. +DiskSpaceWarningTitle=Nedostatok miesta na disku +DiskSpaceWarning=Sprievodca intalciou vyaduje najmenej %1 KB vonho miesta na intalciu produktu, ale na vybranej jednotke je dostupnch len %2 KB.%n%nPrajete si napriek tomu pokraova? +DirNameTooLong=Nzov adresra alebo cesta s prli dlh. +InvalidDirName=Nzov adresra nie je platn. +BadDirName32=Nzvy adresrov nesm obsahova iadny z nasledujcich znakov:%n%n%1 +DirExistsTitle=Adresr existuje +DirExists=Adresr:%n%n%1%n%nu existuje. M sa napriek tomu intalova do tohto adresra? +DirDoesntExistTitle=Adresr neexistuje +DirDoesntExist=Adresr:%n%n%1%n%nete neexistuje. M sa tento adresr vytvori? +WizardSelectComponents=Vyberte komponenty +SelectComponentsDesc=Ak komponenty maj by naintalovan? +SelectComponentsLabel2=Zakrtnite komponenty, ktor maj by naintalovan; komponenty, ktor se nemaj intalova, nechajte nezakrtnut. Pokraujte kliknutm na tlaidlo alej. +FullInstallation=pln intalcia +CompactInstallation=Kompaktn intalcia +CustomInstallation=Voliten intalcia +NoUninstallWarningTitle=Komponenty existuj +NoUninstallWarning=Sprievodca intalciou zistil, e nasledujce komponenty s u na Vaom potai naintalovan:%n%n%1%n%nAk ich teraz nezahrniete do vberu, nebud neskr odintalovan.%n%nPrajete si napriek tomu pokraova? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel=Vybran komponenty vyaduj najmenej [mb] MB miesta na disku. +WizardSelectTasks=Vyberte alie lohy +SelectTasksDesc=Ktor alie lohy maj by vykonan? +SelectTasksLabel2=Vyberte alie lohy, ktor maj by vykonan v priebehu intalcie produktu [name] a pokraujte kliknutm na tlaidlo alej. +WizardSelectProgramGroup=Vyberte skupinu v ponuke tart +SelectStartMenuFolderDesc=Kam m sprievodca intalcie umiestni zstupcov aplikcie? +SelectStartMenuFolderLabel3=Sprievodca intalciou vytvor zstupcov aplikcie v nasledujcom adresri ponuky tart. +SelectStartMenuFolderBrowseLabel=Pokraujte kliknutm na tlaidlo alej. Ak chcete zvoli in adresr, kliknite na tlaidlo Prechdza. +MustEnterGroupName=Muste zada nzov skupiny. +GroupNameTooLong=Nzov adresra alebo cesta s prli dlh. +InvalidGroupName=Nzov adresra nie je platn. +BadGroupName=Nzov skupiny nesmie obsahova iadny z nasledujcich znakov:%n%n%1 +NoProgramGroupCheck2=&Nevytvra skupinu v ponuke tart +WizardReady=Intalcia je pripraven +ReadyLabel1=Sprievodca intalciou je teraz pripraven naintalova produkt [name] na V pota. +ReadyLabel2a=Pokraujte v intalcii kliknutm na tlaidlo Intalova. Ak si prajete zmeni niektor nastavenia intalcie, kliknite na tlaidlo Sp. +ReadyLabel2b=Pokraujte v intalcii kliknutm na tlaidlo Intalova. +ReadyMemoUserInfo=Informcie o pouvateovi: +ReadyMemoDir=Cieov adresr: +ReadyMemoType=Typ intalcie: +ReadyMemoComponents=Vybran komponenty: +ReadyMemoGroup=Skupina v ponuke tart: +ReadyMemoTasks=alie lohy: +WizardPreparing=Prprava intalcie +PreparingDesc=Sprievodca intalciou pripravuje intalciu produktu [name] na V pota. +PreviousInstallNotCompleted=Intalcia/odintalcia predolho produktu nebola plne dokonen. Dokonenie tohto procesu vyaduje retart potaa.%n%nPo retartovan potaa spustite znovu sprievodcu intalciou, aby bolo mon dokoni intalciu produktu [name]. +CannotContinue=Sprievodca intalciou neme pokraova. Ukonite, prosm, sprievodcu intalciou kliknutm na tlaidlo Zrui. +ApplicationsFound=Nasledujce aplikcie pracuj so sbormi, ktor mus intaltor aktualizova. Odporame Vm, aby ste povolili intaltoru automaticky ukoni tieto aplikcie. +ApplicationsFound2=Nasledujce aplikcie pracuj so sbormi, ktor mus intaltor aktualizova. Odporame Vm, aby ste povolili intaltoru automaticky ukoni tieto aplikcie. Po skonen intalcie sa intaltor poksi tieto aplikcie optovne spusti. +CloseApplications=&Automaticky ukoni aplikcie +DontCloseApplications=&Neukonova aplikcie +ErrorCloseApplications=Sprievodca nemohol automaticky zatvori vetky aplikcie. Odporame Vm, aby ste rune uzavreli vetky aplikcie, ktor pouvaj sbory, ktor m Sprievodca aktualizova. +WizardInstalling=Intalujem +InstallingLabel=Pokajte prosm, km sprievodca intalciou nedokon intalciu produktu [name] na V pota. +FinishedHeadingLabel=Dokonuje sa intalcia produktu [name] +FinishedLabelNoIcons=Sprievodca intalciou dokonil intalciu produktu [name] na V pota. +FinishedLabel=Sprievodca intalciou dokonil intalciu produktu [name] na V pota. Produkt je mon spusti pomocou naintalovanch ikon a zstupcov. +ClickFinish=Ukonite sprievodcu intalciou kliknutm na tlaidlo Dokoni. +FinishedRestartLabel=Na dokonenie intalcie produktu [name] je nutn retartova V pota. Prajete si teraz retartova V pota? +FinishedRestartMessage=Na dokonenie intalcie produktu [name] je nutn retartova V pota.%n%nPrajete si teraz retartova V pota? +ShowReadmeCheck=no, chcem zobrazi dokument "ITAJMA" +YesRadio=&no, chcem teraz retartova pota +NoRadio=&Nie, pota retartujem neskr +RunEntryExec=Spusti %1 +RunEntryShellExec=Zobrazi %1 +ChangeDiskTitle=Sprievodca intalciou vyaduje al disk +SelectDiskLabel2=Vlote, prosm, disk %1 a kliknite na tlaidlo OK.%n%nAk sa sbory na tomto disku nachdzaj v inom adresri, ako v tom, ktor je zobrazen niie, zadejte sprvnu cestu alebo kliknite na tlaidlo Prechdza. +PathLabel=&Cesta: +FileNotInDir2=Sbor "%1" sa ned njs v "%2". Vlote, prosm, sprvny disk alebo zvote in adresr. +SelectDirectoryLabel=pecifikujte,prosm, umiestnenie alieho disku. +SetupAborted=Intalcia nebola plne dokonen.%n%nOpravte, prosm, chybu a spustite sprievodcu intalciou znova. +EntryAbortRetryIgnore=Akciu zopakujete kliknutm na tlaidlo Opakova. Akciu vynechte kliknutm na tlaidlo Preskoi. Intalciu prerute kliknutm na tlaidlo Prerui. +StatusClosingApplications=Ukonovanie aplikci... +StatusCreateDirs=Vytvraj sa adresre... +StatusExtractFiles=Rozbauj sa sbory... +StatusCreateIcons=Vytvraj sa ikony a zstupcovia... +StatusCreateIniEntries=Vytvraj sa zznamy v konfiguranch sboroch... +StatusCreateRegistryEntries=Vytvraj sa zznamy v systmovom registri... +StatusRegisterFiles=Registruj sa sbory... +StatusSavingUninstall=Ukladaj sa informcie potrebn pre neskorie odintalovanie produktu... +StatusRunProgram=Dokonuje sa intalcia... +StatusRestartingApplications=Retartovanie aplikci... +StatusRollback=Vykonan zmeny sa vracaj sp... +ErrorInternal2=Intern chyba: %1 +ErrorFunctionFailedNoCode=%1 zlyhala +ErrorFunctionFailed=%1 zlyhala; kd %2 +ErrorFunctionFailedWithMessage=%1 zlyhala; kd %2.%n%3 +ErrorExecutingProgram=Ned sa spusti sbor:%n%1 +ErrorRegOpenKey=Dolo k chybe pri otvran ka systmovho registra:%n%1\%2 +ErrorRegCreateKey=Dolo k chybe pri vytvran ka systmovho registra:%n%1\%2 +ErrorRegWriteKey=Dolo k chybe pri zpise do ka systmovho registra:%n%1\%2 +ErrorIniEntry=Dolo k chybe pri vytvran zznamu v konfiguranom sbore "%1". +FileAbortRetryIgnore=Akciu zopakujete kliknutm na tlaidlo Opakova. Tento sbor preskote kliknutm na tlaidlo Preskoi (neodpora sa). Intalciu prerute tlaidlom Prerui. +FileAbortRetryIgnore2=Akciu zopakujete kliknutm na tlaidlo Opakova. Pokraujete kliknutm na tlaidlo Preskoi (neodpora sa). Intalciu prerute tlaidlom Prerui. +SourceIsCorrupted=Zdrojov sbor je pokoden +SourceDoesntExist=Zdrojov sbor "%1" neexistuje +ExistingFileReadOnly=Existujci sbor je uren len na tanie.%n%nAtribt "Iba na tanie" odstrnite a akciu zopakujete kliknutm na tlaidlo Opakova. Sbor preskote kliknutm na tlaidlo Preskoi. Intalciu prerute kliknutm na tlaidlo Prerui. +ErrorReadingExistingDest=Dolo k chybe pri pokuse o tanie existujceho sboru: +FileExists=Sbor u existuje.%n%nM ho sprievodca intalcie prepsa? +ExistingFileNewer=Existujci sbor je nov ako ten, ktor sa sprievodca intalciou poka naintalova. Odpora sa ponecha existujci sbor.%n%nPrajete si ponechat existujci sbor? +ErrorChangingAttr=Dolo k chybe pri pokuse o modifikciu atribtov existujceho sboru: +ErrorCreatingTemp=Dolo k chybe pri pokuse o vytvorenie sboru v cieovom adresri: +ErrorReadingSource=Dolo k chybe pri pokuse o tanie zdrojovho sboru: +ErrorCopying=Dolo k chybe pri pokuse o skoprovanie sboru: +ErrorReplacingExistingFile=Dolo k chybe pri pokuse o nahradenie existujceho sboru: +ErrorRestartReplace=Zlyhala funkcia "RestartReplace" sprievodcu intalciou: +ErrorRenamingTemp=Dolo k chybe pri pokuse o premenovanie sboru v cieovom adresri: +ErrorRegisterServer=Ned sa vykona registrcia DLL/OCX: %1 +ErrorRegSvr32Failed=Volanie RegSvr32 zlyhalo s nvratovm kdom %1 +ErrorRegisterTypeLib=Ned sa vykona registrcia typovej kninice: %1 +ErrorOpeningReadme=Dolo k chybe pri pokuse o otvorenie dokumentu "ITAJMA". +ErrorRestartingComputer=Sprievodcovi intalciou sa nepodarilo retartova V pota. Retartujte ho, prosm, manulne. +UninstallNotFound=Sbor "%1" neexistuje. Produkt sa ned odintalova. +UninstallOpenError=Sbor "%1" nie je mon otvori. Produkt nie je mon odintalova. +UninstallUnsupportedVer=Sprievodcovi odintalciou sa nepodarilo rozpozna formt sboru obsahujceho informcie na odintalovanie produktu "%1". Produkt sa ned odintalova +UninstallUnknownEntry=V sbore obsahujcom informcie na odintalovanie produktu bola zisten neznma poloka (%1) +ConfirmUninstall=Ste si naozaj ist, e chcete odintalova %1 a vetky jeho komponenty? +UninstallOnlyOnWin64=Tento produkt je mon odintalova iba v 64-bitovch verzich MS Windows. +OnlyAdminCanUninstall=K odintalovaniu tohto produktu muste by prihlsen s prvami administrtora. +UninstallStatusLabel=Pokajte prosm, km produkt %1 nebude odintalovan z Vho potaa. +UninstalledAll=%1 bol spene odintalovan z Vho potaa. +UninstalledMost=%1 bol odintalovan z Vho potaa.%n%nNiektor jeho komponenty sa vak nepodarilo odintalova. Mete ich odintalova manulne. +UninstalledAndNeedsRestart=Na dokonenie odintalcie produktu %1 je potrebn retartova V pota.%n%nPrajete si teraz retartova V pota? +UninstallDataCorrupted=Sbor "%1" je pokoden. Produkt sa ned odintalova +ConfirmDeleteSharedFileTitle=Odintalova zdiean sbor? +ConfirmDeleteSharedFile2=Systm indikuje, e nsledujci zdiean sbor nie je pouvan iadnymi inmi aplikciami. M sprievodca odintalcie tento zdiean sbor odstrni?%n%nAk niektor aplikcie tento sbor pouvaj, nemusia po jeho odintalovan pracova sprvne. Ak si nie ste ist, zvote Nie. Ponechanie tohoto sboru vo Vaom systme nespsob iadnu kodu. +SharedFileNameLabel=Nzov sboru: +SharedFileLocationLabel=Umiestnenie: +WizardUninstalling=Stav odintalovania +StatusUninstalling=Odintalujem %1... +ShutdownBlockReasonInstallingApp=Intalovanie %1. +ShutdownBlockReasonUninstallingApp=Odintalovanie %1. + + +[CustomMessages] +NameAndVersion=%1 verzia %2 +AdditionalIcons=al zstupcovia: +CreateDesktopIcon=Vytvori zstupcu na &ploche +CreateQuickLaunchIcon=Vytvori zstupcu na paneli &Rchle spustenie +ProgramOnTheWeb=Aplikcia %1 na internete +UninstallProgram=Odintalova aplikciu %1 +LaunchProgram=Spusti aplikciu %1 +AssocFileExtension=Vytvori &asociciu medzi sbormi typu %2 a aplikciou %1 +AssocingFileExtension=Vytvra sa asocicia medzi sbormi typu %2 a aplikciou %1... +AutoStartProgramGroupDescription=Po spusten: +AutoStartProgram=Automaticky spusti %1 +AddonHostProgramNotFound=Nepodarilo sa njs %1 v prieinku, ktor ste zvolili.%n%nChcete napriek tomu pokraova? diff --git a/distrib/custom_messages.iss b/distrib/custom_messages.iss index f51c10e1cd9..d2f44a49317 100644 --- a/distrib/custom_messages.iss +++ b/distrib/custom_messages.iss @@ -1,55 +1,55 @@ -; (C) 2009-2017 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 . - - -; Do NOT translate your language's name -; Do NOT translate [name]/[ver] -; Do NOT change the langid -; Do NOT change the file encoding; it must be UTF-8 Signature -; Keep the translations close to the English strings -; comp=component, msg=Message, tsk=Task - - -[Messages] -; English -WelcomeLabel1=[name/ver] -en.WelcomeLabel2=This will install [name] on your computer.%n%nIt is recommended that you close all other applications before continuing. -en.WinVersionTooLowError=[name] requires Windows 7 or newer to run. - - -[CustomMessages] -; English -en.langid=00000000 -en.comp_mpciconlib=Icon Library -en.comp_mpcresources=Translations -en.msg_DeleteSettings=Do you also want to delete MPC-HC settings?%n%nIf you plan on installing MPC-HC again then you do not have to delete them. -#if defined(sse2_required) -en.msg_simd_sse2=This build of MPC-HC requires a CPU with SSE2 extension support.%n%nYour CPU does not have those capabilities. -#endif -en.run_DownloadToolbarImages=Visit our Wiki page to download toolbar images -en.tsk_AllUsers=For all users -en.tsk_CurrentUser=For the current user only -en.tsk_Other=Other tasks: -en.tsk_ResetSettings=Reset settings -en.types_DefaultInstallation=Default installation -en.types_CustomInstallation=Custom installation -en.ViewChangelog=View Changelog - - -#if localize == "true" - #include "custom_messages_translated.iss" -#endif +; (C) 2009-2017 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 . + + +; Do NOT translate your language's name +; Do NOT translate [name]/[ver] +; Do NOT change the langid +; Do NOT change the file encoding; it must be UTF-8 Signature +; Keep the translations close to the English strings +; comp=component, msg=Message, tsk=Task + + +[Messages] +; English +WelcomeLabel1=[name/ver] +en.WelcomeLabel2=This will install [name] on your computer.%n%nIt is recommended that you close all other applications before continuing. +en.WinVersionTooLowError=[name] requires Windows 7 or newer to run. + + +[CustomMessages] +; English +en.langid=00000000 +en.comp_mpciconlib=Icon Library +en.comp_mpcresources=Translations +en.msg_DeleteSettings=Do you also want to delete MPC-HC settings?%n%nIf you plan on installing MPC-HC again then you do not have to delete them. +#if defined(sse2_required) +en.msg_simd_sse2=This build of MPC-HC requires a CPU with SSE2 extension support.%n%nYour CPU does not have those capabilities. +#endif +en.run_DownloadToolbarImages=Visit our Wiki page to download toolbar images +en.tsk_AllUsers=For all users +en.tsk_CurrentUser=For the current user only +en.tsk_Other=Other tasks: +en.tsk_ResetSettings=Reset settings +en.types_DefaultInstallation=Default installation +en.types_CustomInstallation=Custom installation +en.ViewChangelog=View Changelog + + +#if localize == "true" + #include "custom_messages_translated.iss" +#endif diff --git a/distrib/mpc-hc_setup.iss b/distrib/mpc-hc_setup.iss index 8094f65b93f..88247b37769 100644 --- a/distrib/mpc-hc_setup.iss +++ b/distrib/mpc-hc_setup.iss @@ -1,567 +1,567 @@ -; (C) 2009-2018 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 . - - -; Requirements: -; Inno Setup Unicode: http://www.jrsoftware.org/isdl.php - - -#if VER < EncodeVer(6,3,2) - #error Update your Inno Setup version (6.3.2 or newer) -#endif - -#ifndef UNICODE - #error Use the Unicode Inno Setup -#endif - -; If you want to compile the 64-bit version define "x64build" (uncomment the define below or use build.bat) -;#define x64Build -;#define MPCHC_LITE - -; Include translations by default. You can bypass this by defining localize=whatever or false etc in build.bat or here -#if !defined(localize) - #if defined(MPCHC_LITE) - #define localize = "false" - #else - #define localize = "true" - #endif -#endif -#define sse2_required - -#if GetEnv('MPC_DRDUMP') == '1' -#define USE_DRDUMP_CRASH_REPORTER 1 -#endif - -; From now on you shouldn't need to change anything - -#include "..\include\mpc-hc_config.h" -#include "..\include\version.h" - -#define copyright_str str(MPC_COPYRIGHT_STR) -#define app_name "MPC-HC" - -#if MPC_NIGHTLY_RELEASE - #define app_ver str(MPC_VERSION_MAJOR) + "." + str(MPC_VERSION_MINOR) + "." + str(MPC_VERSION_PATCH) + "." + str(MPC_VERSION_REV) -#else - #define app_ver str(MPC_VERSION_MAJOR) + "." + str(MPC_VERSION_MINOR) + "." + str(MPC_VERSION_PATCH) -#endif - -#define app_vername = app_name + " " + app_ver -#define quick_launch "{userappdata}\Microsoft\Internet Explorer\Quick Launch" - -#define base_bindir = "..\bin" - -#ifdef x64Build - #define bindir = AddBackslash(base_bindir) + "mpc-hc_x64" - #define mpchc_exe = "mpc-hc64.exe" - #define mpchc_ini = "mpc-hc64.ini" - #define lavfiltersdir = "LAVFilters64" - #define OutFilename = app_name + "." + app_ver + ".x64" - #define platform = "x64" - #define mpcvr_ax = "MpcVideoRenderer64.ax" - #define mediainfo_dll = "..\distrib\x64\MediaInfo.dll" -#else - #define bindir = AddBackslash(base_bindir) + "mpc-hc_x86" - #define mpchc_exe = "mpc-hc.exe" - #define mpchc_ini = "mpc-hc.ini" - #define lavfiltersdir = "LAVFilters" - #define OutFilename = app_name + "." + app_ver + ".x86" - #define platform = "x86" - #define mpcvr_ax = "MpcVideoRenderer.ax" - #define mediainfo_dll = "..\distrib\x86\MediaInfo.dll" -#endif - -#if defined(MPCHC_LITE) - #define bindir = bindir + " Lite" -#endif - -#ifnexist AddBackslash(bindir) + mpchc_exe - #error Compile MPC-HC first -#endif - -#if localize != "true" - #if defined(MPCHC_LITE) - #define OutFilename = OutFilename + ".Lite" - #else - #define OutFilename = OutFilename + ".en" - #endif -#endif - -#if MPC_NIGHTLY_RELEASE - #define FullAppNameVer = app_vername + " " + "(" + str(MPCHC_HASH) + ")" -#else - #define FullAppNameVer = app_vername -#endif - -#if MPC_NIGHTLY_RELEASE - #define FullAppNameVer = FullAppNameVer + " " + str(MPC_VERSION_NIGHTLY) -#endif -#ifdef MPCHC_LITE - #define FullAppNameVer = FullAppNameVer + " " + "Lite" -#endif -#ifdef x64Build - #define FullAppNameVer = FullAppNameVer + " " + "(64-bit)" -#endif - -#ifexist "..\distrib\mpcvr\MpcVideoRenderer.ax" -#define INCLUDE_MPCVR = true -#else -#define INCLUDE_MPCVR = false -#bla -#endif - -#ifexist mediainfo_dll - #if !defined(MPCHC_LITE) -#define INCLUDE_MEDIAINFO = true - #else -#define INCLUDE_MEDIAINFO = false - #endif -#else -#define INCLUDE_MEDIAINFO = false -#endif - - -[Setup] -#ifdef x64Build -AppId = {{2ACBF1FA-F5C3-4B19-A774-B22A31F231B9} -DefaultGroupName = {#app_name} x64 -ArchitecturesAllowed = x64compatible -ArchitecturesInstallIn64BitMode = x64compatible -#else -AppId = {{2624B969-7135-4EB1-B0F6-2D8C397B45F7} -DefaultGroupName = {#app_name} -#endif - -AppName = {#app_name} -AppVersion = {#app_ver} -AppVerName = {#app_vername} -AppPublisher = MPC-HC Team -AppPublisherURL = {#WEBSITE_URL} -AppCopyright = {#copyright_str} -VersionInfoVersion = {#app_ver} -UninstallDisplayIcon = {app}\{#mpchc_exe} -UninstallDisplayName = {#FullAppNameVer} -OutputBaseFilename = {#OutFilename} -DefaultDirName = {code:GetInstallFolder} -LicenseFile = ..\COPYING.txt -OutputDir = . -SetupIconFile = ..\src\mpc-hc\res\icon.ico -WizardImageFile = WizardImageFile.bmp -WizardSmallImageFile = WizardSmallImageFile.bmp -Compression = lzma2/ultra -InternalCompressLevel = ultra -SolidCompression = yes -AllowNoIcons = yes -ShowTasksTreeLines = yes -DisableDirPage = auto -DisableProgramGroupPage = auto -MinVersion = 6.1 -CloseApplications = true -#ifexist "..\signinfo.txt" -SignTool = MySignTool -#endif -SetupMutex = 'mpchc_setup_mutex' - -[Languages] -Name: en; MessagesFile: compiler:Default.isl - -#if localize == "true" -Name: ar; MessagesFile: Languages\Arabic.isl -Name: be; MessagesFile: Languages\Belarusian.isl -Name: bn; MessagesFile: Languages\Bengali.islu -Name: bs_BA; MessagesFile: Languages\Bosnian.isl -Name: ca; MessagesFile: compiler:Languages\Catalan.isl -Name: cs; MessagesFile: compiler:Languages\Czech.isl -Name: da; MessagesFile: compiler:Languages\Danish.isl -Name: de; MessagesFile: compiler:Languages\German.isl -Name: en_GB; MessagesFile: Languages\EnglishBritish.isl -Name: es; MessagesFile: compiler:Languages\Spanish.isl -Name: eu; MessagesFile: Languages\Basque.isl -Name: fi; MessagesFile: compiler:Languages\Finnish.isl -Name: fr; MessagesFile: compiler:Languages\French.isl -Name: gl; MessagesFile: Languages\Galician.isl -Name: he; MessagesFile: compiler:Languages\Hebrew.isl -Name: hr; MessagesFile: Languages\Croatian.isl -Name: hu; MessagesFile: compiler:Languages\Hungarian.isl -Name: hy; MessagesFile: compiler:Languages\Armenian.isl -Name: id; MessagesFile: Languages\Indonesian.isl -Name: it; MessagesFile: compiler:Languages\Italian.isl -Name: ja; MessagesFile: compiler:Languages\Japanese.isl -Name: ko; MessagesFile: Languages\Korean.isl -Name: lt; MessagesFile: Languages\Lithuanian.isl -Name: ms_MY; MessagesFile: Languages\Malaysian.isl -Name: nl; MessagesFile: compiler:Languages\Dutch.isl -Name: pl; MessagesFile: compiler:Languages\Polish.isl -Name: pt_BR; MessagesFile: compiler:Languages\BrazilianPortuguese.isl -Name: pt_PT; MessagesFile: compiler:Languages\Portuguese.isl -Name: ro; MessagesFile: Languages\Romanian.isl -Name: ru; MessagesFile: compiler:Languages\Russian.isl -Name: sk; MessagesFile: Languages\Slovak.isl -Name: sl; MessagesFile: compiler:Languages\Slovenian.isl -Name: sv; MessagesFile: Languages\Swedish.isl -Name: th_TH; MessagesFile: Languages\Thai.isl -Name: tt; MessagesFile: Languages\Tatar.isl -Name: tr; MessagesFile: compiler:Languages\Turkish.isl -Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl -Name: vi; MessagesFile: Languages\Vietnamese.isl -Name: zh_CN; MessagesFile: Languages\ChineseSimplified.isl -Name: zh_TW; MessagesFile: Languages\ChineseTraditional.isl -#endif - -; Include installer's custom messages -#include "custom_messages.iss" - - -[Types] -Name: default; Description: {cm:types_DefaultInstallation} -Name: custom; Description: {cm:types_CustomInstallation}; Flags: iscustom - - -[Components] -Name: main; Description: {#app_vername}; Types: default custom; Flags: fixed -#if INCLUDE_MPCVR -Name: mpcvr; Description: MPC Video Renderer; Types: default custom -#endif -Name: mpciconlib; Description: {cm:comp_mpciconlib}; Types: default custom -#if localize == "true" -Name: mpcresources; Description: {cm:comp_mpcresources}; Types: default custom; Flags: disablenouninstallwarning -#endif - - -[Tasks] -Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons} -Name: desktopicon\user; Description: {cm:tsk_CurrentUser}; GroupDescription: {cm:AdditionalIcons}; Flags: exclusive -Name: desktopicon\common; Description: {cm:tsk_AllUsers}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked exclusive -Name: quicklaunchicon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked; OnlyBelowVersion: 6.01 -Name: reset_settings; Description: {cm:tsk_ResetSettings}; GroupDescription: {cm:tsk_Other}; Flags: checkedonce unchecked; Check: SettingsExist() - - -[Files] -Source: {#bindir}\{#mpchc_exe}; DestDir: {app}; Components: main; Flags: ignoreversion - #if localize == "true" -Source: {#bindir}\Lang\mpcresources.??.dll; DestDir: {app}\Lang; Components: mpcresources; Flags: ignoreversion -Source: {#bindir}\Lang\mpcresources.??_??.dll; DestDir: {app}\Lang; Components: mpcresources; Flags: ignoreversion - #endif -Source: {#bindir}\mpciconlib.dll; DestDir: {app}; Components: mpciconlib; Flags: ignoreversion - #ifndef MPCHC_LITE -Source: {#bindir}\{#lavfiltersdir}\*.dll; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion -Source: {#bindir}\{#lavfiltersdir}\*.ax; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion -Source: {#bindir}\{#lavfiltersdir}\*.manifest; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion - #endif -Source: {#platform}\d3dcompiler_{#MPC_D3D_COMPILER_VERSION}.dll; DestDir: {app}; Components: main; Flags: ignoreversion -Source: {#platform}\d3dx9_{#MPC_DX_SDK_NUMBER}.dll; DestDir: {app}; Components: main; Flags: ignoreversion - #if INCLUDE_MEDIAINFO -Source: {#platform}\mediainfo.dll; DestDir: {app}; Components: main; Flags: ignoreversion - #endif -Source: ..\src\mpc-hc\res\shaders\dx9\*.hlsl; DestDir: {app}\Shaders; Components: main; Flags: onlyifdoesntexist -Source: ..\src\mpc-hc\res\shaders\dx11\*.hlsl; DestDir: {app}\Shaders11; Components: main; Flags: onlyifdoesntexist -Source: ..\COPYING.txt; DestDir: {app}; Components: main; Flags: ignoreversion -Source: ..\docs\Authors.txt; DestDir: {app}; Components: main; Flags: ignoreversion - #if USE_DRDUMP_CRASH_REPORTER -Source: {#platform}\crashrpt.dll; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion -Source: {#platform}\dbghelp.dll; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion -Source: {#platform}\sendrpt.exe; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion -Source: CrashReporter_LICENSE.txt; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion - #endif - #if INCLUDE_MPCVR -Source: ..\distrib\mpcvr\{#mpcvr_ax}; DestDir: {app}\MPCVR; Components: mpcvr; Flags: ignoreversion - #endif - - -[Icons] -#ifdef x64Build -Name: {group}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0 -Name: {commondesktop}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\common -Name: {userdesktop}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\user -Name: {#quick_launch}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: quicklaunchicon -#else -Name: {group}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0 -Name: {commondesktop}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\common -Name: {userdesktop}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\user -Name: {#quick_launch}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: quicklaunchicon -#endif -Name: {group}\{cm:UninstallProgram,{#app_name}}; Filename: {uninstallexe}; Comment: {cm:UninstallProgram,{#app_name}}; WorkingDir: {app} - - -[Run] -Filename: {app}\{#mpchc_exe}; Description: {cm:LaunchProgram,{#app_name}}; WorkingDir: {app}; Flags: nowait postinstall skipifsilent unchecked - - -[InstallDelete] -Type: files; Name: {userdesktop}\{#app_name}.lnk; Check: not IsTaskSelected('desktopicon\user') and IsUpgrade() -Type: files; Name: {commondesktop}\{#app_name}.lnk; Check: not IsTaskSelected('desktopicon\common') and IsUpgrade() -Type: files; Name: {#quick_launch}\{#app_name}.lnk; Check: not IsTaskSelected('quicklaunchicon') and IsUpgrade(); OnlyBelowVersion: 6.01 -Type: files; Name: {app}\AUTHORS; Check: IsUpgrade() -Type: files; Name: {app}\COPYING; Check: IsUpgrade() - #if !USE_DRDUMP_CRASH_REPORTER -Type: filesandordirs; Name: {app}\CrashReporter; Check: IsUpgrade() - #endif - -; old shortcuts -#ifdef x64Build -Type: files; Name: {group}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() -Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() -Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() -Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() -#else -Type: files; Name: {group}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() -Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() -Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() -Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() -#endif -Type: files; Name: {group}\{cm:ProgramOnTheWeb,Media Player Classic - Home Cinema}.url; Check: IsUpgrade() -Type: files; Name: {group}\{cm:UninstallProgram,Media Player Classic - Home Cinema}.lnk; Check: IsUpgrade() - -Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('desktopicon\user') and IsUpgrade() -Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('desktopicon\common') and IsUpgrade() -Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('quicklaunchicon') and IsUpgrade(); OnlyBelowVersion: 6.01 - -; Old ffmpeg dlls from LAV Filters -Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-60.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-59.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-58.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-57.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-9.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-8.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-7.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-60.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-59.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-58.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-57.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-58.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-57.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-56.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-55.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swresample-lav-4.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-7.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-6.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-5.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-4.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avresample-lav-4.dll; Check: IsUpgrade() -Type: files; Name: {app}\{#lavfiltersdir}\avresample-lav-3.dll; Check: IsUpgrade() - -#ifdef x64Build -; Super old LAV files -Type: files; Name: {app}\LAVFilters\avcodec-lav-??.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\avfilter-lav-?.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\avformat-lav-??.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\avresample-lav-?.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\avutil-lav-??.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\IntelQuickSyncDecoder.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\LAVAudio.ax; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\LAVFilters.Dependencies.manifest; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\LAVSplitter.ax; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\LAVVideo.ax; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\libbluray.dll; Check: IsUpgrade() -Type: files; Name: {app}\LAVFilters\swscale-lav-?.dll; Check: IsUpgrade() -Type: dirifempty; Name: {app}\LAVFilters\; Check: IsUpgrade() -#endif - - -#if localize == "true" -; remove the old language dlls when upgrading -Type: files; Name: {app}\mpcresources.br.dll -Type: files; Name: {app}\mpcresources.by.dll -Type: files; Name: {app}\mpcresources.ca.dll -Type: files; Name: {app}\mpcresources.cz.dll -Type: files; Name: {app}\mpcresources.de.dll -Type: files; Name: {app}\mpcresources.es.dll -Type: files; Name: {app}\mpcresources.fr.dll -Type: files; Name: {app}\mpcresources.he.dll -Type: files; Name: {app}\mpcresources.hu.dll -Type: files; Name: {app}\mpcresources.hy.dll -Type: files; Name: {app}\mpcresources.it.dll -Type: files; Name: {app}\mpcresources.ja.dll -Type: files; Name: {app}\mpcresources.kr.dll -Type: files; Name: {app}\mpcresources.nl.dll -Type: files; Name: {app}\mpcresources.pl.dll -Type: files; Name: {app}\mpcresources.ru.dll -Type: files; Name: {app}\mpcresources.sc.dll -Type: files; Name: {app}\mpcresources.sk.dll -Type: files; Name: {app}\mpcresources.sv.dll -Type: files; Name: {app}\mpcresources.tc.dll -Type: files; Name: {app}\mpcresources.tr.dll -Type: files; Name: {app}\mpcresources.ua.dll -Type: files; Name: {app}\Lang\mpcresources.br.dll -Type: files; Name: {app}\Lang\mpcresources.by.dll -Type: files; Name: {app}\Lang\mpcresources.cz.dll -Type: files; Name: {app}\Lang\mpcresources.en-GB.dll -Type: files; Name: {app}\Lang\mpcresources.kr.dll -Type: files; Name: {app}\Lang\mpcresources.sc.dll -Type: files; Name: {app}\Lang\mpcresources.tc.dll -Type: files; Name: {app}\Lang\mpcresources.ua.dll -#endif - - -[Code] -#if defined(sse2_required) -function IsProcessorFeaturePresent(Feature: Integer): Boolean; -external 'IsProcessorFeaturePresent@kernel32.dll stdcall'; -#endif - - -function GetInstallFolder(Default: String): String; -var - sInstallPath: String; -begin - if not RegQueryStringValue(HKCU, 'SOFTWARE\Gabest\Media Player Classic', 'ExePath', sInstallPath) - or not RegQueryStringValue(HKCU, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath', sInstallPath) then begin - Result := ExpandConstant('{pf}\MPC-HC'); - end - else begin - RegQueryStringValue(HKCU, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath', sInstallPath); - Result := ExtractFileDir(sInstallPath); - if (Result = '') or not DirExists(Result) then begin - Result := ExpandConstant('{pf}\MPC-HC'); - end; - end; -end; - - -#if defined(sse2_required) - -function Is_SSE2_Supported(): Boolean; -begin - // PF_XMMI64_INSTRUCTIONS_AVAILABLE - Result := IsProcessorFeaturePresent(10); -end; - -#endif - - -function IsUpgrade(): Boolean; -var - sPrevPath: String; -begin - sPrevPath := WizardForm.PrevAppDir; - Result := (sPrevPath <> ''); -end; - - -// Check if MPC-HC's settings exist -function SettingsExist(): Boolean; -begin - if RegKeyExists(HKEY_CURRENT_USER, 'Software\Gabest\Media Player Classic') or - RegKeyExists(HKEY_CURRENT_USER, 'Software\MPC-HC\MPC-HC') or - FileExists(ExpandConstant('{app}\{#mpchc_ini}')) then - Result := True - else - Result := False; -end; - - -function ShouldSkipPage(PageID: Integer): Boolean; -begin - // Hide the License page - if IsUpgrade() and (PageID = wpLicense) then - Result := True; -end; - - -procedure CleanUpSettingsAndFiles(); -var - ResultCode: Integer; -begin - try - Exec(ExpandConstant('{app}\{#mpchc_exe}'), '/unregall', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); - except - end; - DeleteFile(ExpandConstant('{app}\{#mpchc_ini}')); - DelTree(ExpandConstant('{userappdata}\MPC-HC\ShaderCache'), True, True, True); - DeleteFile(ExpandConstant('{userappdata}\MPC-HC\default.mpcpl')); - RemoveDir(ExpandConstant('{userappdata}\MPC-HC')); - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-HC\Filters'); - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-HC\MPC-HC'); - RegDeleteKeyIfEmpty(HKCU, 'Software\MPC-HC'); - - #if INCLUDE_MPCVR - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-BE Filters\MPC Video Renderer'); - RegDeleteKeyIfEmpty(HKCU, 'Software\MPC-BE Filters'); - #endif -end; - - -procedure CleanUpOldSettingsAndFiles(); -begin - DeleteFile(ExpandConstant('{userappdata}\Media Player Classic\default.mpcpl')); - RemoveDir(ExpandConstant('{userappdata}\Media Player Classic')); - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\Gabest\Filters'); - RegDeleteKeyIncludingSubkeys(HKCU, 'Software\Gabest\Media Player Classic'); - RegDeleteKeyIfEmpty(HKCU, 'Software\Gabest'); - RegDeleteValue(HKLM, 'SOFTWARE\Gabest\Media Player Classic', 'ExePath') - RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\Gabest\Media Player Classic'); - RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\Gabest'); -end; - - -procedure InitializeWizard(); -begin - WizardForm.LicenseAcceptedRadio.Checked := True; -end; - - -procedure CurStepChanged(CurStep: TSetupStep); -var - iLanguage: Integer; -begin - if CurStep = ssPostInstall then begin - if IsTaskSelected('reset_settings') then begin - CleanUpSettingsAndFiles(); - RegWriteStringValue(HKCU, 'Software\MPC-HC\MPC-HC', 'ExePath', ExpandConstant('{app}\{#mpchc_exe}')); - end; - - iLanguage := StrToInt(ExpandConstant('{cm:langid}')); - if IsComponentSelected('mpcresources') then begin - if FileExists(ExpandConstant('{app}\{#mpchc_ini}')) then - SetIniInt('Settings', 'InterfaceLanguage', iLanguage, ExpandConstant('{app}\{#mpchc_ini}')) - else - RegWriteDWordValue(HKCU, 'Software\MPC-HC\MPC-HC\Settings', 'InterfaceLanguage', iLanguage); - end; - end; - -end; - - -procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); -begin - // When uninstalling, ask the user to delete MPC-HC settings - if (CurUninstallStep = usUninstall) and SettingsExist() then begin - if SuppressibleMsgBox(CustomMessage('msg_DeleteSettings'), mbConfirmation, MB_YESNO or MB_DEFBUTTON2, IDNO) = IDYES then begin - CleanUpSettingsAndFiles(); - CleanUpOldSettingsAndFiles(); - end; - - RegDeleteValue(HKLM, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath') - RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\MPC-HC\MPC-HC'); - RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\MPC-HC'); - - end; -end; - - -function InitializeSetup(): Boolean; -begin - Result := True; - -#if defined(sse2_required) - if not Is_SSE2_Supported() then begin - SuppressibleMsgBox(CustomMessage('msg_simd_sse2'), mbCriticalError, MB_OK, MB_OK); - Result := False; - end; -#endif - -end; +; (C) 2009-2018 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 . + + +; Requirements: +; Inno Setup Unicode: http://www.jrsoftware.org/isdl.php + + +#if VER < EncodeVer(6,3,2) + #error Update your Inno Setup version (6.3.2 or newer) +#endif + +#ifndef UNICODE + #error Use the Unicode Inno Setup +#endif + +; If you want to compile the 64-bit version define "x64build" (uncomment the define below or use build.bat) +;#define x64Build +;#define MPCHC_LITE + +; Include translations by default. You can bypass this by defining localize=whatever or false etc in build.bat or here +#if !defined(localize) + #if defined(MPCHC_LITE) + #define localize = "false" + #else + #define localize = "true" + #endif +#endif +#define sse2_required + +#if GetEnv('MPC_DRDUMP') == '1' +#define USE_DRDUMP_CRASH_REPORTER 1 +#endif + +; From now on you shouldn't need to change anything + +#include "..\include\mpc-hc_config.h" +#include "..\include\version.h" + +#define copyright_str str(MPC_COPYRIGHT_STR) +#define app_name "MPC-HC" + +#if MPC_NIGHTLY_RELEASE + #define app_ver str(MPC_VERSION_MAJOR) + "." + str(MPC_VERSION_MINOR) + "." + str(MPC_VERSION_PATCH) + "." + str(MPC_VERSION_REV) +#else + #define app_ver str(MPC_VERSION_MAJOR) + "." + str(MPC_VERSION_MINOR) + "." + str(MPC_VERSION_PATCH) +#endif + +#define app_vername = app_name + " " + app_ver +#define quick_launch "{userappdata}\Microsoft\Internet Explorer\Quick Launch" + +#define base_bindir = "..\bin" + +#ifdef x64Build + #define bindir = AddBackslash(base_bindir) + "mpc-hc_x64" + #define mpchc_exe = "mpc-hc64.exe" + #define mpchc_ini = "mpc-hc64.ini" + #define lavfiltersdir = "LAVFilters64" + #define OutFilename = app_name + "." + app_ver + ".x64" + #define platform = "x64" + #define mpcvr_ax = "MpcVideoRenderer64.ax" + #define mediainfo_dll = "..\distrib\x64\MediaInfo.dll" +#else + #define bindir = AddBackslash(base_bindir) + "mpc-hc_x86" + #define mpchc_exe = "mpc-hc.exe" + #define mpchc_ini = "mpc-hc.ini" + #define lavfiltersdir = "LAVFilters" + #define OutFilename = app_name + "." + app_ver + ".x86" + #define platform = "x86" + #define mpcvr_ax = "MpcVideoRenderer.ax" + #define mediainfo_dll = "..\distrib\x86\MediaInfo.dll" +#endif + +#if defined(MPCHC_LITE) + #define bindir = bindir + " Lite" +#endif + +#ifnexist AddBackslash(bindir) + mpchc_exe + #error Compile MPC-HC first +#endif + +#if localize != "true" + #if defined(MPCHC_LITE) + #define OutFilename = OutFilename + ".Lite" + #else + #define OutFilename = OutFilename + ".en" + #endif +#endif + +#if MPC_NIGHTLY_RELEASE + #define FullAppNameVer = app_vername + " " + "(" + str(MPCHC_HASH) + ")" +#else + #define FullAppNameVer = app_vername +#endif + +#if MPC_NIGHTLY_RELEASE + #define FullAppNameVer = FullAppNameVer + " " + str(MPC_VERSION_NIGHTLY) +#endif +#ifdef MPCHC_LITE + #define FullAppNameVer = FullAppNameVer + " " + "Lite" +#endif +#ifdef x64Build + #define FullAppNameVer = FullAppNameVer + " " + "(64-bit)" +#endif + +#ifexist "..\distrib\mpcvr\MpcVideoRenderer.ax" +#define INCLUDE_MPCVR = true +#else +#define INCLUDE_MPCVR = false +#bla +#endif + +#ifexist mediainfo_dll + #if !defined(MPCHC_LITE) +#define INCLUDE_MEDIAINFO = true + #else +#define INCLUDE_MEDIAINFO = false + #endif +#else +#define INCLUDE_MEDIAINFO = false +#endif + + +[Setup] +#ifdef x64Build +AppId = {{2ACBF1FA-F5C3-4B19-A774-B22A31F231B9} +DefaultGroupName = {#app_name} x64 +ArchitecturesAllowed = x64compatible +ArchitecturesInstallIn64BitMode = x64compatible +#else +AppId = {{2624B969-7135-4EB1-B0F6-2D8C397B45F7} +DefaultGroupName = {#app_name} +#endif + +AppName = {#app_name} +AppVersion = {#app_ver} +AppVerName = {#app_vername} +AppPublisher = MPC-HC Team +AppPublisherURL = {#WEBSITE_URL} +AppCopyright = {#copyright_str} +VersionInfoVersion = {#app_ver} +UninstallDisplayIcon = {app}\{#mpchc_exe} +UninstallDisplayName = {#FullAppNameVer} +OutputBaseFilename = {#OutFilename} +DefaultDirName = {code:GetInstallFolder} +LicenseFile = ..\COPYING.txt +OutputDir = . +SetupIconFile = ..\src\mpc-hc\res\icon.ico +WizardImageFile = WizardImageFile.bmp +WizardSmallImageFile = WizardSmallImageFile.bmp +Compression = lzma2/ultra +InternalCompressLevel = ultra +SolidCompression = yes +AllowNoIcons = yes +ShowTasksTreeLines = yes +DisableDirPage = auto +DisableProgramGroupPage = auto +MinVersion = 6.1 +CloseApplications = true +#ifexist "..\signinfo.txt" +SignTool = MySignTool +#endif +SetupMutex = 'mpchc_setup_mutex' + +[Languages] +Name: en; MessagesFile: compiler:Default.isl + +#if localize == "true" +Name: ar; MessagesFile: Languages\Arabic.isl +Name: be; MessagesFile: Languages\Belarusian.isl +Name: bn; MessagesFile: Languages\Bengali.islu +Name: bs_BA; MessagesFile: Languages\Bosnian.isl +Name: ca; MessagesFile: compiler:Languages\Catalan.isl +Name: cs; MessagesFile: compiler:Languages\Czech.isl +Name: da; MessagesFile: compiler:Languages\Danish.isl +Name: de; MessagesFile: compiler:Languages\German.isl +Name: en_GB; MessagesFile: Languages\EnglishBritish.isl +Name: es; MessagesFile: compiler:Languages\Spanish.isl +Name: eu; MessagesFile: Languages\Basque.isl +Name: fi; MessagesFile: compiler:Languages\Finnish.isl +Name: fr; MessagesFile: compiler:Languages\French.isl +Name: gl; MessagesFile: Languages\Galician.isl +Name: he; MessagesFile: compiler:Languages\Hebrew.isl +Name: hr; MessagesFile: Languages\Croatian.isl +Name: hu; MessagesFile: compiler:Languages\Hungarian.isl +Name: hy; MessagesFile: compiler:Languages\Armenian.isl +Name: id; MessagesFile: Languages\Indonesian.isl +Name: it; MessagesFile: compiler:Languages\Italian.isl +Name: ja; MessagesFile: compiler:Languages\Japanese.isl +Name: ko; MessagesFile: Languages\Korean.isl +Name: lt; MessagesFile: Languages\Lithuanian.isl +Name: ms_MY; MessagesFile: Languages\Malaysian.isl +Name: nl; MessagesFile: compiler:Languages\Dutch.isl +Name: pl; MessagesFile: compiler:Languages\Polish.isl +Name: pt_BR; MessagesFile: compiler:Languages\BrazilianPortuguese.isl +Name: pt_PT; MessagesFile: compiler:Languages\Portuguese.isl +Name: ro; MessagesFile: Languages\Romanian.isl +Name: ru; MessagesFile: compiler:Languages\Russian.isl +Name: sk; MessagesFile: Languages\Slovak.isl +Name: sl; MessagesFile: compiler:Languages\Slovenian.isl +Name: sv; MessagesFile: Languages\Swedish.isl +Name: th_TH; MessagesFile: Languages\Thai.isl +Name: tt; MessagesFile: Languages\Tatar.isl +Name: tr; MessagesFile: compiler:Languages\Turkish.isl +Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl +Name: vi; MessagesFile: Languages\Vietnamese.isl +Name: zh_CN; MessagesFile: Languages\ChineseSimplified.isl +Name: zh_TW; MessagesFile: Languages\ChineseTraditional.isl +#endif + +; Include installer's custom messages +#include "custom_messages.iss" + + +[Types] +Name: default; Description: {cm:types_DefaultInstallation} +Name: custom; Description: {cm:types_CustomInstallation}; Flags: iscustom + + +[Components] +Name: main; Description: {#app_vername}; Types: default custom; Flags: fixed +#if INCLUDE_MPCVR +Name: mpcvr; Description: MPC Video Renderer; Types: default custom +#endif +Name: mpciconlib; Description: {cm:comp_mpciconlib}; Types: default custom +#if localize == "true" +Name: mpcresources; Description: {cm:comp_mpcresources}; Types: default custom; Flags: disablenouninstallwarning +#endif + + +[Tasks] +Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons} +Name: desktopicon\user; Description: {cm:tsk_CurrentUser}; GroupDescription: {cm:AdditionalIcons}; Flags: exclusive +Name: desktopicon\common; Description: {cm:tsk_AllUsers}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked exclusive +Name: quicklaunchicon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked; OnlyBelowVersion: 6.01 +Name: reset_settings; Description: {cm:tsk_ResetSettings}; GroupDescription: {cm:tsk_Other}; Flags: checkedonce unchecked; Check: SettingsExist() + + +[Files] +Source: {#bindir}\{#mpchc_exe}; DestDir: {app}; Components: main; Flags: ignoreversion + #if localize == "true" +Source: {#bindir}\Lang\mpcresources.??.dll; DestDir: {app}\Lang; Components: mpcresources; Flags: ignoreversion +Source: {#bindir}\Lang\mpcresources.??_??.dll; DestDir: {app}\Lang; Components: mpcresources; Flags: ignoreversion + #endif +Source: {#bindir}\mpciconlib.dll; DestDir: {app}; Components: mpciconlib; Flags: ignoreversion + #ifndef MPCHC_LITE +Source: {#bindir}\{#lavfiltersdir}\*.dll; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion +Source: {#bindir}\{#lavfiltersdir}\*.ax; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion +Source: {#bindir}\{#lavfiltersdir}\*.manifest; DestDir: {app}\{#lavfiltersdir}; Components: main; Flags: ignoreversion + #endif +Source: {#platform}\d3dcompiler_{#MPC_D3D_COMPILER_VERSION}.dll; DestDir: {app}; Components: main; Flags: ignoreversion +Source: {#platform}\d3dx9_{#MPC_DX_SDK_NUMBER}.dll; DestDir: {app}; Components: main; Flags: ignoreversion + #if INCLUDE_MEDIAINFO +Source: {#platform}\mediainfo.dll; DestDir: {app}; Components: main; Flags: ignoreversion + #endif +Source: ..\src\mpc-hc\res\shaders\dx9\*.hlsl; DestDir: {app}\Shaders; Components: main; Flags: onlyifdoesntexist +Source: ..\src\mpc-hc\res\shaders\dx11\*.hlsl; DestDir: {app}\Shaders11; Components: main; Flags: onlyifdoesntexist +Source: ..\COPYING.txt; DestDir: {app}; Components: main; Flags: ignoreversion +Source: ..\docs\Authors.txt; DestDir: {app}; Components: main; Flags: ignoreversion + #if USE_DRDUMP_CRASH_REPORTER +Source: {#platform}\crashrpt.dll; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion +Source: {#platform}\dbghelp.dll; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion +Source: {#platform}\sendrpt.exe; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion +Source: CrashReporter_LICENSE.txt; DestDir: {app}\CrashReporter; Components: main; Flags: ignoreversion + #endif + #if INCLUDE_MPCVR +Source: ..\distrib\mpcvr\{#mpcvr_ax}; DestDir: {app}\MPCVR; Components: mpcvr; Flags: ignoreversion + #endif + + +[Icons] +#ifdef x64Build +Name: {group}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0 +Name: {commondesktop}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\common +Name: {userdesktop}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\user +Name: {#quick_launch}\{#app_name} x64; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername} (64-bit); WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: quicklaunchicon +#else +Name: {group}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0 +Name: {commondesktop}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\common +Name: {userdesktop}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: desktopicon\user +Name: {#quick_launch}\{#app_name}; Filename: {app}\{#mpchc_exe}; Comment: {#app_vername}; WorkingDir: {app}; IconFilename: {app}\{#mpchc_exe}; IconIndex: 0; Tasks: quicklaunchicon +#endif +Name: {group}\{cm:UninstallProgram,{#app_name}}; Filename: {uninstallexe}; Comment: {cm:UninstallProgram,{#app_name}}; WorkingDir: {app} + + +[Run] +Filename: {app}\{#mpchc_exe}; Description: {cm:LaunchProgram,{#app_name}}; WorkingDir: {app}; Flags: nowait postinstall skipifsilent unchecked + + +[InstallDelete] +Type: files; Name: {userdesktop}\{#app_name}.lnk; Check: not IsTaskSelected('desktopicon\user') and IsUpgrade() +Type: files; Name: {commondesktop}\{#app_name}.lnk; Check: not IsTaskSelected('desktopicon\common') and IsUpgrade() +Type: files; Name: {#quick_launch}\{#app_name}.lnk; Check: not IsTaskSelected('quicklaunchicon') and IsUpgrade(); OnlyBelowVersion: 6.01 +Type: files; Name: {app}\AUTHORS; Check: IsUpgrade() +Type: files; Name: {app}\COPYING; Check: IsUpgrade() + #if !USE_DRDUMP_CRASH_REPORTER +Type: filesandordirs; Name: {app}\CrashReporter; Check: IsUpgrade() + #endif + +; old shortcuts +#ifdef x64Build +Type: files; Name: {group}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() +Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() +Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() +Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema x64.lnk; Check: IsUpgrade() +#else +Type: files; Name: {group}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() +Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() +Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() +Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema.lnk; Check: IsUpgrade() +#endif +Type: files; Name: {group}\{cm:ProgramOnTheWeb,Media Player Classic - Home Cinema}.url; Check: IsUpgrade() +Type: files; Name: {group}\{cm:UninstallProgram,Media Player Classic - Home Cinema}.lnk; Check: IsUpgrade() + +Type: files; Name: {userdesktop}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('desktopicon\user') and IsUpgrade() +Type: files; Name: {commondesktop}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('desktopicon\common') and IsUpgrade() +Type: files; Name: {#quick_launch}\Media Player Classic - Home Cinema.lnk; Check: not IsTaskSelected('quicklaunchicon') and IsUpgrade(); OnlyBelowVersion: 6.01 + +; Old ffmpeg dlls from LAV Filters +Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-60.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-59.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-58.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avcodec-lav-57.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-9.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-8.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avfilter-lav-7.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-60.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-59.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-58.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avformat-lav-57.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-58.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-57.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-56.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avutil-lav-55.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swresample-lav-4.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-7.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-6.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-5.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\swscale-lav-4.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avresample-lav-4.dll; Check: IsUpgrade() +Type: files; Name: {app}\{#lavfiltersdir}\avresample-lav-3.dll; Check: IsUpgrade() + +#ifdef x64Build +; Super old LAV files +Type: files; Name: {app}\LAVFilters\avcodec-lav-??.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\avfilter-lav-?.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\avformat-lav-??.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\avresample-lav-?.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\avutil-lav-??.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\IntelQuickSyncDecoder.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\LAVAudio.ax; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\LAVFilters.Dependencies.manifest; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\LAVSplitter.ax; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\LAVVideo.ax; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\libbluray.dll; Check: IsUpgrade() +Type: files; Name: {app}\LAVFilters\swscale-lav-?.dll; Check: IsUpgrade() +Type: dirifempty; Name: {app}\LAVFilters\; Check: IsUpgrade() +#endif + + +#if localize == "true" +; remove the old language dlls when upgrading +Type: files; Name: {app}\mpcresources.br.dll +Type: files; Name: {app}\mpcresources.by.dll +Type: files; Name: {app}\mpcresources.ca.dll +Type: files; Name: {app}\mpcresources.cz.dll +Type: files; Name: {app}\mpcresources.de.dll +Type: files; Name: {app}\mpcresources.es.dll +Type: files; Name: {app}\mpcresources.fr.dll +Type: files; Name: {app}\mpcresources.he.dll +Type: files; Name: {app}\mpcresources.hu.dll +Type: files; Name: {app}\mpcresources.hy.dll +Type: files; Name: {app}\mpcresources.it.dll +Type: files; Name: {app}\mpcresources.ja.dll +Type: files; Name: {app}\mpcresources.kr.dll +Type: files; Name: {app}\mpcresources.nl.dll +Type: files; Name: {app}\mpcresources.pl.dll +Type: files; Name: {app}\mpcresources.ru.dll +Type: files; Name: {app}\mpcresources.sc.dll +Type: files; Name: {app}\mpcresources.sk.dll +Type: files; Name: {app}\mpcresources.sv.dll +Type: files; Name: {app}\mpcresources.tc.dll +Type: files; Name: {app}\mpcresources.tr.dll +Type: files; Name: {app}\mpcresources.ua.dll +Type: files; Name: {app}\Lang\mpcresources.br.dll +Type: files; Name: {app}\Lang\mpcresources.by.dll +Type: files; Name: {app}\Lang\mpcresources.cz.dll +Type: files; Name: {app}\Lang\mpcresources.en-GB.dll +Type: files; Name: {app}\Lang\mpcresources.kr.dll +Type: files; Name: {app}\Lang\mpcresources.sc.dll +Type: files; Name: {app}\Lang\mpcresources.tc.dll +Type: files; Name: {app}\Lang\mpcresources.ua.dll +#endif + + +[Code] +#if defined(sse2_required) +function IsProcessorFeaturePresent(Feature: Integer): Boolean; +external 'IsProcessorFeaturePresent@kernel32.dll stdcall'; +#endif + + +function GetInstallFolder(Default: String): String; +var + sInstallPath: String; +begin + if not RegQueryStringValue(HKCU, 'SOFTWARE\Gabest\Media Player Classic', 'ExePath', sInstallPath) + or not RegQueryStringValue(HKCU, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath', sInstallPath) then begin + Result := ExpandConstant('{pf}\MPC-HC'); + end + else begin + RegQueryStringValue(HKCU, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath', sInstallPath); + Result := ExtractFileDir(sInstallPath); + if (Result = '') or not DirExists(Result) then begin + Result := ExpandConstant('{pf}\MPC-HC'); + end; + end; +end; + + +#if defined(sse2_required) + +function Is_SSE2_Supported(): Boolean; +begin + // PF_XMMI64_INSTRUCTIONS_AVAILABLE + Result := IsProcessorFeaturePresent(10); +end; + +#endif + + +function IsUpgrade(): Boolean; +var + sPrevPath: String; +begin + sPrevPath := WizardForm.PrevAppDir; + Result := (sPrevPath <> ''); +end; + + +// Check if MPC-HC's settings exist +function SettingsExist(): Boolean; +begin + if RegKeyExists(HKEY_CURRENT_USER, 'Software\Gabest\Media Player Classic') or + RegKeyExists(HKEY_CURRENT_USER, 'Software\MPC-HC\MPC-HC') or + FileExists(ExpandConstant('{app}\{#mpchc_ini}')) then + Result := True + else + Result := False; +end; + + +function ShouldSkipPage(PageID: Integer): Boolean; +begin + // Hide the License page + if IsUpgrade() and (PageID = wpLicense) then + Result := True; +end; + + +procedure CleanUpSettingsAndFiles(); +var + ResultCode: Integer; +begin + try + Exec(ExpandConstant('{app}\{#mpchc_exe}'), '/unregall', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + except + end; + DeleteFile(ExpandConstant('{app}\{#mpchc_ini}')); + DelTree(ExpandConstant('{userappdata}\MPC-HC\ShaderCache'), True, True, True); + DeleteFile(ExpandConstant('{userappdata}\MPC-HC\default.mpcpl')); + RemoveDir(ExpandConstant('{userappdata}\MPC-HC')); + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-HC\Filters'); + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-HC\MPC-HC'); + RegDeleteKeyIfEmpty(HKCU, 'Software\MPC-HC'); + + #if INCLUDE_MPCVR + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\MPC-BE Filters\MPC Video Renderer'); + RegDeleteKeyIfEmpty(HKCU, 'Software\MPC-BE Filters'); + #endif +end; + + +procedure CleanUpOldSettingsAndFiles(); +begin + DeleteFile(ExpandConstant('{userappdata}\Media Player Classic\default.mpcpl')); + RemoveDir(ExpandConstant('{userappdata}\Media Player Classic')); + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\Gabest\Filters'); + RegDeleteKeyIncludingSubkeys(HKCU, 'Software\Gabest\Media Player Classic'); + RegDeleteKeyIfEmpty(HKCU, 'Software\Gabest'); + RegDeleteValue(HKLM, 'SOFTWARE\Gabest\Media Player Classic', 'ExePath') + RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\Gabest\Media Player Classic'); + RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\Gabest'); +end; + + +procedure InitializeWizard(); +begin + WizardForm.LicenseAcceptedRadio.Checked := True; +end; + + +procedure CurStepChanged(CurStep: TSetupStep); +var + iLanguage: Integer; +begin + if CurStep = ssPostInstall then begin + if IsTaskSelected('reset_settings') then begin + CleanUpSettingsAndFiles(); + RegWriteStringValue(HKCU, 'Software\MPC-HC\MPC-HC', 'ExePath', ExpandConstant('{app}\{#mpchc_exe}')); + end; + + iLanguage := StrToInt(ExpandConstant('{cm:langid}')); + if IsComponentSelected('mpcresources') then begin + if FileExists(ExpandConstant('{app}\{#mpchc_ini}')) then + SetIniInt('Settings', 'InterfaceLanguage', iLanguage, ExpandConstant('{app}\{#mpchc_ini}')) + else + RegWriteDWordValue(HKCU, 'Software\MPC-HC\MPC-HC\Settings', 'InterfaceLanguage', iLanguage); + end; + end; + +end; + + +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +begin + // When uninstalling, ask the user to delete MPC-HC settings + if (CurUninstallStep = usUninstall) and SettingsExist() then begin + if SuppressibleMsgBox(CustomMessage('msg_DeleteSettings'), mbConfirmation, MB_YESNO or MB_DEFBUTTON2, IDNO) = IDYES then begin + CleanUpSettingsAndFiles(); + CleanUpOldSettingsAndFiles(); + end; + + RegDeleteValue(HKLM, 'SOFTWARE\MPC-HC\MPC-HC', 'ExePath') + RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\MPC-HC\MPC-HC'); + RegDeleteKeyIfEmpty(HKLM, 'SOFTWARE\MPC-HC'); + + end; +end; + + +function InitializeSetup(): Boolean; +begin + Result := True; + +#if defined(sse2_required) + if not Is_SSE2_Supported() then begin + SuppressibleMsgBox(CustomMessage('msg_simd_sse2'), mbCriticalError, MB_OK, MB_OK); + Result := False; + end; +#endif + +end; diff --git a/docs/Compilation.md b/docs/Compilation.md index d018365dde6..9c4e8b6bdcf 100644 --- a/docs/Compilation.md +++ b/docs/Compilation.md @@ -1,162 +1,162 @@ -# Compilation instructions - -## Part A: Preparing the Visual Studio environment - -### Visual Studio 2019 - -1. Install Visual Studio (any edition will work fine). Select at minimum the following components: - - C++ core features - - IntelliCode - - Windows Universal C Runtime - - Windows Universal CRT SDK - - C++ build tools (x86 & x64) - - C++ ATL - - C++ MFC - - Windows 10 SDK (10.0.17763.0 or any other version) -2. Install the Windows 8.1 SDK → - - When choosing which features to install you only need to select "Windows Software Development Kit". - - Alternatively you can use Windows 10 SDK, but then resulting binaries will require at least Windows 7 SP1, so you lose compatibility with Windows 7 RTM. - - -## Part B: Install Python 3 (optional) - -This is required for building the translation DLL files. - -1. Install Python version 3.8.7 from (You can use Python 3.6 or later version) -2. Run this command to install a required library: - `C:\Program Files\Python38\Scripts\pip install --upgrade polib` - - -## Part C: Preparing the MSYS and GCC environment (optional) - -This is required for building LAV Filters, which is used as the internal codecs by MPC-HC. - -You can skip compilation of LAV Filters by selecting the "Release Lite"/"Debug Lite" build configuration -in the MPC-HC project file. This can be useful for making quick builds during development. The resulting -binary will be missing the internal filter functionality. So don't use this configuration for actual -releases. - -1. Download MSYS2 from . - If you are using a 64-bit Operating System, which you should be, get the 64-bit version. -2. Install it to for example **`C:\MSYS64\`**. The installation path should be specified in your **build.user.bat** configuration script that you will create later. -3. Run `msys2_shell.bat` -4. Install some additional required tools by running this command: - ```text - pacman -S make pkg-config diffutils - ``` -5. Then update all packages by running this command: - ```text - pacman -Syu - ``` - When you are asked to restart MSYS, say yes. Start MSYS again and repeat the above command. Once everything is updated, you can close MSYS. -6. Download the latest mingw-w64-gcc package from and extract it to folder **`C:\MSYS64\mingw64`** (overwriting any existing files). -7. It is recommended to add **`C:\MSYS64\mingw64\bin`** and **`C:\MSYS64\usr\bin`** to the %PATH% environment variable. - This allows you to run GCC and all other MSYS tools from the Windows command line. - Windows Control Panel > System > Advanced System Settings > Environment variables. - On Windows 10 you can access the legacy control panel by clicking on the Windows Start menu and typing `control.exe`. - -## Part D: Yasm - -1. Download YASM from -2. Rename it to **yasm.exe** and put it in a folder that is included in %PATH%. For example **`C:\Windows`** or **`C:\MSYS64\usr\bin`** (see part C). - -## PART E: NASM - -1. Download NASM from -2. Put nasm.exe in a folder that is included in %PATH%. For example **`C:\Windows`**. - -## Part F: Config file with paths - -Create a file named **build.user.bat** in the source code folder of MPC-HC (see part F). It should have the following contents: (with paths adapted for your system!) - -```bat -@ECHO OFF -REM [Required for LAVFilters] MSYS2/MinGW paths: -SET "MPCHC_MSYS=C:\MSYS64" -SET "MPCHC_MINGW32=C:\MSYS64\mingw64" -SET "MPCHC_MINGW64=C:\MSYS64\mingw64" -SET "MSYSTEM=MINGW32" -SET "MSYS2_PATH_TYPE=inherit" -REM [Optional] Specify GIT location if it is not already set in %PATH% -SET "MPCHC_GIT=C:\Program Files\Git" -REM [Optional] If you plan to modify the translations, install Python 3.8 and set the variable to its path -SET "MPCHC_PYTHON=C:\Program Files\Python38" -REM [Optional] If you want to customize the Windows SDK version used, set this variable -SET "MPCHC_WINSDK_VER=8.1" -``` - -Notes: - -* For Visual Studio, we will try to detect the VS installation path automatically. If that fails you need to specify the installation path yourself. For example: - ``` - SET "MPCHC_VS_PATH=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\" - ``` -* If you installed the MSYS package in another directory then make sure that you have set the correct paths in your **build.user.bat** file. -* If you don't have Git installed then the build version will be inaccurate, the revision number will be a hard-coded as zero. - - -## Part G: Downloading the MPC-HC source - -You need Git for downloading the source code. - -Install **Git for Windows** from and also **Git Extensions** from . -Choose `Use Git from the Windows command prompt`. This isn't mandatory, so if you choose -`Use Git from Git Bash only` make sure you set the `MPCHC_GIT` variable in **build.user.bat**. - -Use Git to clone MPC-HC's repository to **C:\mpc-hc** (or anywhere else you like). - -1. Install Git -2. Run these commands: - - ```text - git clone --recursive https://github.com/clsid2/mpc-hc.git - ``` - - or - - ```text - git clone https://github.com/clsid2/mpc-hc.git - git submodule update --init --recursive - ``` - - If a submodule update fails, try running: - - ```text - git submodule foreach --recursive git fetch --tags - ``` - - then run the update again - - ```text - git submodule update --init --recursive - ``` - -Note that you can add `-b master` to the `git clone` command if you want to get the latest -stable version instead of the latest development version. - -## Part H: Compiling the MPC-HC source - -1. Open the solution file **C:\mpc-hc\mpc-hc.sln**. - Change the solution's configuration to **Release** (in the toolbar). -2. Press **F7** to build the solution. -3. You now have **mpc-hc.exe** under **C:\mpc-hc\bin\mpc-hc_x86** -4. Open the solution file **C:\mpc-hc\mpciconlib.sln** -5. Press **F7** to build the solution. -6. You now have **mpciconlib.dll** under **C:\mpc-hc\bin\mpc-hc_x86** -7. Open the solution file **C:\mpc-hc\mpcresources.sln** -8. Build **BuildAll** project. -9. You now have **mpcresources.XX.dll** under **C:\mpc-hc\bin\mpc-hc_x86\Lang** - -Alternatively, you can use **build.bat** that can build everything for you (run: `build.bat help` for more info). - - -## Part I: Building the installer - -Download Inno Setup Unicode v5.5.9 or newer from . -Install everything and then go to **C:\mpc-hc\distrib**, open **mpc-hc_setup.iss** with Inno Setup, -read the first comments in the script and compile it. - -### NOTES - -* **build.bat** can build the installer by using the **installer** or the **packages** switch. -* Use Inno Setup's built-in IDE if you want to edit the iss file and don't change its encoding since it can break easily. +# Compilation instructions + +## Part A: Preparing the Visual Studio environment + +### Visual Studio 2019 + +1. Install Visual Studio (any edition will work fine). Select at minimum the following components: + - C++ core features + - IntelliCode + - Windows Universal C Runtime + - Windows Universal CRT SDK + - C++ build tools (x86 & x64) + - C++ ATL + - C++ MFC + - Windows 10 SDK (10.0.17763.0 or any other version) +2. Install the Windows 8.1 SDK → + - When choosing which features to install you only need to select "Windows Software Development Kit". + - Alternatively you can use Windows 10 SDK, but then resulting binaries will require at least Windows 7 SP1, so you lose compatibility with Windows 7 RTM. + + +## Part B: Install Python 3 (optional) + +This is required for building the translation DLL files. + +1. Install Python version 3.8.7 from (You can use Python 3.6 or later version) +2. Run this command to install a required library: + `C:\Program Files\Python38\Scripts\pip install --upgrade polib` + + +## Part C: Preparing the MSYS and GCC environment (optional) + +This is required for building LAV Filters, which is used as the internal codecs by MPC-HC. + +You can skip compilation of LAV Filters by selecting the "Release Lite"/"Debug Lite" build configuration +in the MPC-HC project file. This can be useful for making quick builds during development. The resulting +binary will be missing the internal filter functionality. So don't use this configuration for actual +releases. + +1. Download MSYS2 from . + If you are using a 64-bit Operating System, which you should be, get the 64-bit version. +2. Install it to for example **`C:\MSYS64\`**. The installation path should be specified in your **build.user.bat** configuration script that you will create later. +3. Run `msys2_shell.bat` +4. Install some additional required tools by running this command: + ```text + pacman -S make pkg-config diffutils + ``` +5. Then update all packages by running this command: + ```text + pacman -Syu + ``` + When you are asked to restart MSYS, say yes. Start MSYS again and repeat the above command. Once everything is updated, you can close MSYS. +6. Download the latest mingw-w64-gcc package from and extract it to folder **`C:\MSYS64\mingw64`** (overwriting any existing files). +7. It is recommended to add **`C:\MSYS64\mingw64\bin`** and **`C:\MSYS64\usr\bin`** to the %PATH% environment variable. + This allows you to run GCC and all other MSYS tools from the Windows command line. + Windows Control Panel > System > Advanced System Settings > Environment variables. + On Windows 10 you can access the legacy control panel by clicking on the Windows Start menu and typing `control.exe`. + +## Part D: Yasm + +1. Download YASM from +2. Rename it to **yasm.exe** and put it in a folder that is included in %PATH%. For example **`C:\Windows`** or **`C:\MSYS64\usr\bin`** (see part C). + +## PART E: NASM + +1. Download NASM from +2. Put nasm.exe in a folder that is included in %PATH%. For example **`C:\Windows`**. + +## Part F: Config file with paths + +Create a file named **build.user.bat** in the source code folder of MPC-HC (see part F). It should have the following contents: (with paths adapted for your system!) + +```bat +@ECHO OFF +REM [Required for LAVFilters] MSYS2/MinGW paths: +SET "MPCHC_MSYS=C:\MSYS64" +SET "MPCHC_MINGW32=C:\MSYS64\mingw64" +SET "MPCHC_MINGW64=C:\MSYS64\mingw64" +SET "MSYSTEM=MINGW32" +SET "MSYS2_PATH_TYPE=inherit" +REM [Optional] Specify GIT location if it is not already set in %PATH% +SET "MPCHC_GIT=C:\Program Files\Git" +REM [Optional] If you plan to modify the translations, install Python 3.8 and set the variable to its path +SET "MPCHC_PYTHON=C:\Program Files\Python38" +REM [Optional] If you want to customize the Windows SDK version used, set this variable +SET "MPCHC_WINSDK_VER=8.1" +``` + +Notes: + +* For Visual Studio, we will try to detect the VS installation path automatically. If that fails you need to specify the installation path yourself. For example: + ``` + SET "MPCHC_VS_PATH=%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\" + ``` +* If you installed the MSYS package in another directory then make sure that you have set the correct paths in your **build.user.bat** file. +* If you don't have Git installed then the build version will be inaccurate, the revision number will be a hard-coded as zero. + + +## Part G: Downloading the MPC-HC source + +You need Git for downloading the source code. + +Install **Git for Windows** from and also **Git Extensions** from . +Choose `Use Git from the Windows command prompt`. This isn't mandatory, so if you choose +`Use Git from Git Bash only` make sure you set the `MPCHC_GIT` variable in **build.user.bat**. + +Use Git to clone MPC-HC's repository to **C:\mpc-hc** (or anywhere else you like). + +1. Install Git +2. Run these commands: + + ```text + git clone --recursive https://github.com/clsid2/mpc-hc.git + ``` + + or + + ```text + git clone https://github.com/clsid2/mpc-hc.git + git submodule update --init --recursive + ``` + + If a submodule update fails, try running: + + ```text + git submodule foreach --recursive git fetch --tags + ``` + + then run the update again + + ```text + git submodule update --init --recursive + ``` + +Note that you can add `-b master` to the `git clone` command if you want to get the latest +stable version instead of the latest development version. + +## Part H: Compiling the MPC-HC source + +1. Open the solution file **C:\mpc-hc\mpc-hc.sln**. + Change the solution's configuration to **Release** (in the toolbar). +2. Press **F7** to build the solution. +3. You now have **mpc-hc.exe** under **C:\mpc-hc\bin\mpc-hc_x86** +4. Open the solution file **C:\mpc-hc\mpciconlib.sln** +5. Press **F7** to build the solution. +6. You now have **mpciconlib.dll** under **C:\mpc-hc\bin\mpc-hc_x86** +7. Open the solution file **C:\mpc-hc\mpcresources.sln** +8. Build **BuildAll** project. +9. You now have **mpcresources.XX.dll** under **C:\mpc-hc\bin\mpc-hc_x86\Lang** + +Alternatively, you can use **build.bat** that can build everything for you (run: `build.bat help` for more info). + + +## Part I: Building the installer + +Download Inno Setup Unicode v5.5.9 or newer from . +Install everything and then go to **C:\mpc-hc\distrib**, open **mpc-hc_setup.iss** with Inno Setup, +read the first comments in the script and compile it. + +### NOTES + +* **build.bat** can build the installer by using the **installer** or the **packages** switch. +* Use Inno Setup's built-in IDE if you want to edit the iss file and don't change its encoding since it can break easily. diff --git a/include/IBitRateInfo.h b/include/IBitRateInfo.h index 2cbab1e7679..b2593838987 100644 --- a/include/IBitRateInfo.h +++ b/include/IBitRateInfo.h @@ -1,30 +1,30 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("EB2CD9E6-BA08-4acb-AA0F-3D8D0DD521CA")) - IBitRateInfo : - public IUnknown -{ - STDMETHOD_(DWORD, GetCurrentBitRate)() PURE; - STDMETHOD_(DWORD, GetAverageBitRate)() PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("EB2CD9E6-BA08-4acb-AA0F-3D8D0DD521CA")) + IBitRateInfo : + public IUnknown +{ + STDMETHOD_(DWORD, GetCurrentBitRate)() PURE; + STDMETHOD_(DWORD, GetAverageBitRate)() PURE; +}; diff --git a/include/IBufferInfo.h b/include/IBufferInfo.h index 7a1eebf9a15..ca6133b125a 100644 --- a/include/IBufferInfo.h +++ b/include/IBufferInfo.h @@ -1,31 +1,31 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("46070104-1318-4A82-8822-E99AB7CD15C1")) - IBufferInfo : - public IUnknown -{ - STDMETHOD_(int, GetCount()) = 0; - STDMETHOD(GetStatus(int i, int& samples, int& size)) = 0; - STDMETHOD_(DWORD, GetPriority()) = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("46070104-1318-4A82-8822-E99AB7CD15C1")) + IBufferInfo : + public IUnknown +{ + STDMETHOD_(int, GetCount()) = 0; + STDMETHOD(GetStatus(int i, int& samples, int& size)) = 0; + STDMETHOD_(DWORD, GetPriority()) = 0; +}; diff --git a/include/IChapterInfo.h b/include/IChapterInfo.h index 9c82de438ff..dac4d58a944 100644 --- a/include/IChapterInfo.h +++ b/include/IChapterInfo.h @@ -1,66 +1,66 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -enum ChapterType { - AtomicChapter = 0, // only contain one element - SubChapter = 1 // contain a list of elements -}; - -#pragma pack(push, 1) -struct ChapterElement { - WORD Size; // size of this structure - BYTE Type; // see ChapterType - UINT ChapterId; // unique identifier for this element - REFERENCE_TIME rtStart; // REFERENCE_TIME in 100ns - REFERENCE_TIME rtStop; // REFERENCE_TIME in 100ns - ChapterElement() - : Size(sizeof(ChapterElement)) - , Type(0) - , ChapterId(0) - , rtStart(0) - , rtStop(0) - {} -}; -#pragma pack(pop) - -interface __declspec(uuid("8E128709-3DC8-4e49-B632-380FCF496B6D")) - IChapterInfo : - public IUnknown -{ -#define CHAPTER_BAD_ID 0xFFFFFFFF -#define CHAPTER_ROOT_ID 0 - - // \param aChapterID is 0 for the top level one - STDMETHOD_(UINT, GetChapterCount)(UINT aChapterID) = 0; - - // \param aIndex start from 1 to GetChapterCount(aParentChapterId) - STDMETHOD_(UINT, GetChapterId)(UINT aParentChapterId, UINT aIndex) = 0; - - STDMETHOD_(UINT, GetChapterCurrentId)() = 0; - - STDMETHOD_(BOOL, GetChapterInfo)(UINT aChapterID, struct ChapterElement* pStructureToFill) = 0; - - // \param PreferredLanguage Language code as in ISO-639-2 (3 chars) - // \param CountryCode Country code as in internet domains - STDMETHOD_(BSTR, GetChapterStringInfo)(UINT aChapterID, CHAR PreferredLanguage[3], CHAR CountryCode[2]) = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +enum ChapterType { + AtomicChapter = 0, // only contain one element + SubChapter = 1 // contain a list of elements +}; + +#pragma pack(push, 1) +struct ChapterElement { + WORD Size; // size of this structure + BYTE Type; // see ChapterType + UINT ChapterId; // unique identifier for this element + REFERENCE_TIME rtStart; // REFERENCE_TIME in 100ns + REFERENCE_TIME rtStop; // REFERENCE_TIME in 100ns + ChapterElement() + : Size(sizeof(ChapterElement)) + , Type(0) + , ChapterId(0) + , rtStart(0) + , rtStop(0) + {} +}; +#pragma pack(pop) + +interface __declspec(uuid("8E128709-3DC8-4e49-B632-380FCF496B6D")) + IChapterInfo : + public IUnknown +{ +#define CHAPTER_BAD_ID 0xFFFFFFFF +#define CHAPTER_ROOT_ID 0 + + // \param aChapterID is 0 for the top level one + STDMETHOD_(UINT, GetChapterCount)(UINT aChapterID) = 0; + + // \param aIndex start from 1 to GetChapterCount(aParentChapterId) + STDMETHOD_(UINT, GetChapterId)(UINT aParentChapterId, UINT aIndex) = 0; + + STDMETHOD_(UINT, GetChapterCurrentId)() = 0; + + STDMETHOD_(BOOL, GetChapterInfo)(UINT aChapterID, struct ChapterElement* pStructureToFill) = 0; + + // \param PreferredLanguage Language code as in ISO-639-2 (3 chars) + // \param CountryCode Country code as in internet domains + STDMETHOD_(BSTR, GetChapterStringInfo)(UINT aChapterID, CHAR PreferredLanguage[3], CHAR CountryCode[2]) = 0; +}; diff --git a/include/IFilterVersion.h b/include/IFilterVersion.h index e07f077036d..0f7d44bf12d 100644 --- a/include/IFilterVersion.h +++ b/include/IFilterVersion.h @@ -1,29 +1,29 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("A0DD28E1-61C0-4539-A7E6-14544AFF092E")) - IFilterVersion : - public IUnknown -{ - STDMETHOD_(DWORD, GetFilterVersion)() = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("A0DD28E1-61C0-4539-A7E6-14544AFF092E")) + IFilterVersion : + public IUnknown +{ + STDMETHOD_(DWORD, GetFilterVersion)() = 0; +}; diff --git a/include/IKeyFrameInfo.h b/include/IKeyFrameInfo.h index 1ec8f486edd..4bb611682a4 100644 --- a/include/IKeyFrameInfo.h +++ b/include/IKeyFrameInfo.h @@ -1,30 +1,30 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("01A5BBD3-FE71-487C-A2EC-F585918A8724")) - IKeyFrameInfo : - public IUnknown -{ - STDMETHOD(GetKeyFrameCount)(UINT& nKFs) = 0; // returns S_FALSE when every frame is a keyframe - STDMETHOD(GetKeyFrames)(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs /* in, out*/) = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("01A5BBD3-FE71-487C-A2EC-F585918A8724")) + IKeyFrameInfo : + public IUnknown +{ + STDMETHOD(GetKeyFrameCount)(UINT& nKFs) = 0; // returns S_FALSE when every frame is a keyframe + STDMETHOD(GetKeyFrames)(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs /* in, out*/) = 0; +}; diff --git a/include/ITrackInfo.h b/include/ITrackInfo.h index 12d1261b2cb..2795a36e3b1 100644 --- a/include/ITrackInfo.h +++ b/include/ITrackInfo.h @@ -1,84 +1,84 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -enum TrackType { - TypeVideo = 1, - TypeAudio = 2, - TypeComplex = 3, - TypeLogo = 0x10, - TypeSubtitle = 0x11, - TypeControl = 0x20 -}; - -#pragma pack(push, 1) - -struct TrackElement { - WORD Size; // Size of this structure - BYTE Type; // See TrackType - BOOL FlagDefault; // Set if the track is the default for its TrackType. - BOOL FlagForced; // Set if that track MUST be used during playback. - BOOL FlagLacing; // Set if the track may contain blocks using lacing. - UINT MinCache; // The minimum number of frames a player should be able to cache during playback. - UINT MaxCache; // The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed. - CHAR Language[4]; // Specifies the language of the track, in the ISO-639-2 form. (end with '\0') -}; - -struct TrackExtendedInfoVideo { - WORD Size; // Size of this structure - BOOL Interlaced; // Set if the video is interlaced. - UINT PixelWidth; // Width of the encoded video frames in pixels. - UINT PixelHeight; // Height of the encoded video frames in pixels. - UINT DisplayWidth; // Width of the video frames to display. - UINT DisplayHeight; // Height of the video frames to display. - BYTE DisplayUnit; // Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches). - BYTE AspectRatioType; // Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed). -}; - -struct TrackExtendedInfoAudio { - WORD Size; // Size of this structure - float SamplingFreq; // Sampling frequency in Hz. - float OutputSamplingFrequency; // Real output sampling frequency in Hz (used for SBR techniques). - UINT Channels; // Numbers of channels in the track. - UINT BitDepth; // Bits per sample, mostly used for PCM. -}; - -#pragma pack(pop) - -interface __declspec(uuid("03E98D51-DDE7-43aa-B70C-42EF84A3A23D")) - ITrackInfo : - public IUnknown -{ - STDMETHOD_(UINT, GetTrackCount)() = 0; - - // \param aTrackIdx the track index (from 0 to GetTrackCount()-1) - STDMETHOD_(BOOL, GetTrackInfo)(UINT aTrackIdx, struct TrackElement* pStructureToFill) = 0; - - // Get an extended information struct relative to the track type - STDMETHOD_(BOOL, GetTrackExtendedInfo)(UINT aTrackIdx, void* pStructureToFill) = 0; - - STDMETHOD_(BSTR, GetTrackCodecID)(UINT aTrackIdx) = 0; - STDMETHOD_(BSTR, GetTrackName)(UINT aTrackIdx) = 0; - STDMETHOD_(BSTR, GetTrackCodecName)(UINT aTrackIdx) = 0; - STDMETHOD_(BSTR, GetTrackCodecInfoURL)(UINT aTrackIdx) = 0; - STDMETHOD_(BSTR, GetTrackCodecDownloadURL)(UINT aTrackIdx) = 0; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +enum TrackType { + TypeVideo = 1, + TypeAudio = 2, + TypeComplex = 3, + TypeLogo = 0x10, + TypeSubtitle = 0x11, + TypeControl = 0x20 +}; + +#pragma pack(push, 1) + +struct TrackElement { + WORD Size; // Size of this structure + BYTE Type; // See TrackType + BOOL FlagDefault; // Set if the track is the default for its TrackType. + BOOL FlagForced; // Set if that track MUST be used during playback. + BOOL FlagLacing; // Set if the track may contain blocks using lacing. + UINT MinCache; // The minimum number of frames a player should be able to cache during playback. + UINT MaxCache; // The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed. + CHAR Language[4]; // Specifies the language of the track, in the ISO-639-2 form. (end with '\0') +}; + +struct TrackExtendedInfoVideo { + WORD Size; // Size of this structure + BOOL Interlaced; // Set if the video is interlaced. + UINT PixelWidth; // Width of the encoded video frames in pixels. + UINT PixelHeight; // Height of the encoded video frames in pixels. + UINT DisplayWidth; // Width of the video frames to display. + UINT DisplayHeight; // Height of the video frames to display. + BYTE DisplayUnit; // Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches). + BYTE AspectRatioType; // Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed). +}; + +struct TrackExtendedInfoAudio { + WORD Size; // Size of this structure + float SamplingFreq; // Sampling frequency in Hz. + float OutputSamplingFrequency; // Real output sampling frequency in Hz (used for SBR techniques). + UINT Channels; // Numbers of channels in the track. + UINT BitDepth; // Bits per sample, mostly used for PCM. +}; + +#pragma pack(pop) + +interface __declspec(uuid("03E98D51-DDE7-43aa-B70C-42EF84A3A23D")) + ITrackInfo : + public IUnknown +{ + STDMETHOD_(UINT, GetTrackCount)() = 0; + + // \param aTrackIdx the track index (from 0 to GetTrackCount()-1) + STDMETHOD_(BOOL, GetTrackInfo)(UINT aTrackIdx, struct TrackElement* pStructureToFill) = 0; + + // Get an extended information struct relative to the track type + STDMETHOD_(BOOL, GetTrackExtendedInfo)(UINT aTrackIdx, void* pStructureToFill) = 0; + + STDMETHOD_(BSTR, GetTrackCodecID)(UINT aTrackIdx) = 0; + STDMETHOD_(BSTR, GetTrackName)(UINT aTrackIdx) = 0; + STDMETHOD_(BSTR, GetTrackCodecName)(UINT aTrackIdx) = 0; + STDMETHOD_(BSTR, GetTrackCodecInfoURL)(UINT aTrackIdx) = 0; + STDMETHOD_(BSTR, GetTrackCodecDownloadURL)(UINT aTrackIdx) = 0; +}; diff --git a/include/avisynth/avisynth1.h b/include/avisynth/avisynth1.h index 937a9bbf75d..3a2ef0f0174 100644 --- a/include/avisynth/avisynth1.h +++ b/include/avisynth/avisynth1.h @@ -1,414 +1,414 @@ -// Avisynth v1.0 beta. Copyright 2000 Ben Rudiak-Gould. -// http://www.math.berkeley.edu/~benrg/avisynth.html - -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit -// http://www.gnu.org/copyleft/gpl.html . - - -#pragma once - -#ifdef _MSC_VER - #include -#else - #define _ASSERTE(x) assert(x) - #include -#endif - - -enum { AVISYNTH_INTERFACE_VERSION = 1 }; - - -// I had problems with Premiere wanting 1-byte alignment for its structures, -// so I now set the Avisynth struct alignment explicitly here. -#pragma pack(push,8) - - -// The VideoInfo struct holds global information about a clip (i.e. -// information that does not depend on the frame number). The GetVideoInfo -// method in IClip returns this struct. - -struct VideoInfo { - int width, height; // width=0 means no video - unsigned fps_numerator, fps_denominator; - int num_frames; - enum { UNKNOWN=0, BGR24=0x13, BGR32=0x14, YUY2=0x22 }; - unsigned char pixel_type; - bool field_based; - - int audio_samples_per_second; // 0 means no audio - int num_audio_samples; - bool stereo, sixteen_bit; - - // useful functions of the above - bool HasVideo() const { return !!width; } - bool HasAudio() const { return !!audio_samples_per_second; } - bool IsRGB() const { return !!(pixel_type&0x10); } - bool IsRGB24() const { return pixel_type == BGR24; } - bool IsRGB32() const { return pixel_type == BGR32; } - bool IsYUV() const { return !!(pixel_type&0x20); } - bool IsYUY2() const { return pixel_type == YUY2; } - int BytesFromPixels(int pixels) const { return pixels * (pixel_type&7); } - int RowSize() const { return BytesFromPixels(width); } - int BitsPerPixel() const { return (pixel_type&7) * 8; } - int BMPSize() const { return height * ((RowSize()+3) & -4); } - int AudioSamplesFromFrames(int frames) const { return int(__int64(frames) * audio_samples_per_second * fps_denominator / fps_numerator); } - int FramesFromAudioSamples(int samples) const { return int(__int64(samples) * fps_numerator / fps_denominator / audio_samples_per_second); } - int AudioSamplesFromBytes(int bytes) const { return bytes >> (stereo + sixteen_bit); } - int BytesFromAudioSamples(int samples) const { return samples << (stereo + sixteen_bit); } - int BytesPerAudioSample() const { return BytesFromAudioSamples(1); } - - // useful mutator - void SetFPS(unsigned numerator, unsigned denominator) { - unsigned x=numerator, y=denominator; - while (y) { // find gcd - unsigned t = x%y; x = y; y = t; - } - fps_numerator = numerator/x; - fps_denominator = denominator/x; - } -}; - - -// VideoFrameBuffer holds information about a memory block which is used -// for video data. For efficiency, instances of this class are not deleted -// when the refcount reaches zero; instead they're stored in a linked list -// to be reused. The instances are deleted when the corresponding AVS -// file is closed. - -class VideoFrameBuffer { - unsigned char* const data; - const int data_size; - // sequence_number is incremented every time the buffer is changed, so - // that stale views can tell they're no longer valid. - long sequence_number; - - friend class VideoFrame; - friend class Cache; - long refcount; - -public: - VideoFrameBuffer(int size); - VideoFrameBuffer(); - ~VideoFrameBuffer(); - - const unsigned char* GetReadPtr() const { return data; } - unsigned char* GetWritePtr() { ++sequence_number; return data; } - int GetDataSize() { return data_size; } - int GetSequenceNumber() { return sequence_number; } - int GetRefcount() { return refcount; } -}; - - -class IClip; -class PClip; -class PVideoFrame; -class IScriptEnvironment; -class AVSValue; - - -// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new -// is overloaded to recycle class instances. - -class VideoFrame { - int refcount; - VideoFrameBuffer* const vfb; - const int offset, pitch, row_size, height; - - friend class PVideoFrame; - void AddRef() { ++refcount; } - void Release() { if (refcount==1) --vfb->refcount; --refcount; } - - friend class ScriptEnvironment; - friend class Cache; - - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); - - void* operator new(size_t size); - -public: - int GetPitch() const { return pitch; } - int GetRowSize() const { return row_size; } - int GetHeight() const { return height; } - - // generally you shouldn't use these two - VideoFrameBuffer* GetFrameBuffer() const { return vfb; } - int GetOffset() const { return offset; } - - // in plugins use env->SubFrame() - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; - - const unsigned char* GetReadPtr() const { return vfb->GetReadPtr() + offset; } - - bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } - - unsigned char* GetWritePtr() const { - return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; - } - - ~VideoFrame() { --vfb->refcount; } -}; - - -// Base class for all filters. -class IClip { - friend class PClip; - friend class AVSValue; - int refcnt; - void AddRef() { ++refcnt; } - void Release() { if (!--refcnt) delete this; } -public: - IClip() : refcnt(0) {} - - virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } - - virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; - virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame - virtual void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) = 0; // start and count are in samples - virtual const VideoInfo& __stdcall GetVideoInfo() = 0; -#if defined(__INTEL_COMPILER) - virtual ~IClip() {} -#else - virtual __stdcall ~IClip() {} -#endif -}; - - -// smart pointer to IClip -class PClip { - - IClip* p; - - IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } - friend class AVSValue; - friend class VideoFrame; - - void Init(IClip* x) { - if (x) x->AddRef(); - p=x; - } - void Set(IClip* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PClip() { p = 0; } - PClip(const PClip& x) { Init(x.p); } - PClip(IClip* x) { Init(x); } - void operator=(IClip* x) { Set(x); } - void operator=(const PClip& x) { Set(x.p); } - - IClip* operator->() const { return p; } - - // useful in conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PClip() { if (p) p->Release(); } -}; - - -// smart pointer to VideoFrame -class PVideoFrame { - - VideoFrame* p; - - void Init(VideoFrame* x) { - if (x) x->AddRef(); - p=x; - } - void Set(VideoFrame* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PVideoFrame() { p = 0; } - PVideoFrame(const PVideoFrame& x) { Init(x.p); } - PVideoFrame(VideoFrame* x) { Init(x); } - void operator=(VideoFrame* x) { Set(x); } - void operator=(const PVideoFrame& x) { Set(x.p); } - - VideoFrame* operator->() const { return p; } - - // for conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PVideoFrame() { if (p) p->Release(); } -}; - - -class AVSValue { -public: - - AVSValue() { type = 'v'; } - AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } - AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } - AVSValue(bool b) { type = 'b'; boolean = b; } - AVSValue(int i) { type = 'i'; integer = i; } - AVSValue(float f) { type = 'f'; floating_pt = f; } - AVSValue(double f) { type = 'f'; floating_pt = float(f); } - AVSValue(const char* s) { type = 's'; string = s; } - AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } - AVSValue(const AVSValue& v) { Assign(&v, true); } - - ~AVSValue() { if (IsClip() && clip) clip->Release(); } - AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } - - // Note that we transparently allow 'int' to be treated as 'float'. - // There are no int<->bool conversions, though. - - bool Defined() const { return type != 'v'; } - bool IsClip() const { return type == 'c'; } - bool IsBool() const { return type == 'b'; } - bool IsInt() const { return type == 'i'; } - bool IsFloat() const { return type == 'f' || type == 'i'; } - bool IsString() const { return type == 's'; } - bool IsArray() const { return type == 'a'; } - - PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } - bool AsBool() const { _ASSERTE(IsBool()); return boolean; } - int AsInt() const { _ASSERTE(IsInt()); return integer; } - const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } - double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } - - bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } - int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } - double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } - const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } - - int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } - const AVSValue& operator[](int index) const { - _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) - src->clip->AddRef(); - if (!init && IsClip() && clip) - clip->Release(); - // make sure this copies the whole struct! - ((__int32*)this)[0] = ((__int32*)src)[0]; - ((__int32*)this)[1] = ((__int32*)src)[1]; - } -}; - - -// instantiable null filter -class GenericVideoFilter : public IClip { -protected: - PClip child; - VideoInfo vi; -public: - GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } - void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } - const VideoInfo& __stdcall GetVideoInfo() { return vi; } - bool __stdcall GetParity(int n) { return child->GetParity(n); } -}; - - -class AvisynthError /* exception */ { -public: - const char* const msg; - AvisynthError(const char* _msg) : msg(_msg) {} -}; - - -// For GetCPUFlags. These are the same as in VirtualDub. -enum { - CPUF_FORCE = 0x01, - CPUF_FPU = 0x02, - CPUF_MMX = 0x04, - CPUF_INTEGER_SSE = 0x08, // Athlon MMX extensions or Intel SSE - CPUF_SSE = 0x10, // Full SSE (PIII) - CPUF_SSE2 = 0x20, // (PIV) - CPUF_3DNOW = 0x40, - CPUF_3DNOW_EXT = 0x80, // Athlon 3DNow! extensions -}; - - -class IScriptEnvironment { -public: -#if defined(__INTEL_COMPILER) - virtual ~IScriptEnvironment() {} -#else - virtual __stdcall ~IScriptEnvironment() {} -#endif - - virtual /*static*/ long __stdcall GetCPUFlags() = 0; - - virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; - virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; - // note: val is really a va_list; I hope everyone typedefs va_list to a pointer - virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; - - __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; - - class NotFound /*exception*/ {}; // thrown by Invoke and GetVar - - typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); - - virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; - virtual bool __stdcall FunctionExists(const char* name) = 0; - virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; - - virtual AVSValue __stdcall GetVar(const char* name) = 0; - virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; - virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; - - virtual void __stdcall PushContext(int level=0) = 0; - virtual void __stdcall PopContext() = 0; - - // align should be 4 or 8 - virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=8) = 0; - - virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; - - virtual /*static*/ void __stdcall BitBlt(unsigned char* dstp, int dst_pitch, const unsigned char* srcp, int src_pitch, int row_size, int height) = 0; - - typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); - virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; - - virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; - - virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; -}; - - -// avisynth.dll exports this; it's a way to use it as a library, without -// writing an AVS script or without going through AVIFile. -IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); - - -#pragma pack(pop) - +// Avisynth v1.0 beta. Copyright 2000 Ben Rudiak-Gould. +// http://www.math.berkeley.edu/~benrg/avisynth.html + +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . + + +#pragma once + +#ifdef _MSC_VER + #include +#else + #define _ASSERTE(x) assert(x) + #include +#endif + + +enum { AVISYNTH_INTERFACE_VERSION = 1 }; + + +// I had problems with Premiere wanting 1-byte alignment for its structures, +// so I now set the Avisynth struct alignment explicitly here. +#pragma pack(push,8) + + +// The VideoInfo struct holds global information about a clip (i.e. +// information that does not depend on the frame number). The GetVideoInfo +// method in IClip returns this struct. + +struct VideoInfo { + int width, height; // width=0 means no video + unsigned fps_numerator, fps_denominator; + int num_frames; + enum { UNKNOWN=0, BGR24=0x13, BGR32=0x14, YUY2=0x22 }; + unsigned char pixel_type; + bool field_based; + + int audio_samples_per_second; // 0 means no audio + int num_audio_samples; + bool stereo, sixteen_bit; + + // useful functions of the above + bool HasVideo() const { return !!width; } + bool HasAudio() const { return !!audio_samples_per_second; } + bool IsRGB() const { return !!(pixel_type&0x10); } + bool IsRGB24() const { return pixel_type == BGR24; } + bool IsRGB32() const { return pixel_type == BGR32; } + bool IsYUV() const { return !!(pixel_type&0x20); } + bool IsYUY2() const { return pixel_type == YUY2; } + int BytesFromPixels(int pixels) const { return pixels * (pixel_type&7); } + int RowSize() const { return BytesFromPixels(width); } + int BitsPerPixel() const { return (pixel_type&7) * 8; } + int BMPSize() const { return height * ((RowSize()+3) & -4); } + int AudioSamplesFromFrames(int frames) const { return int(__int64(frames) * audio_samples_per_second * fps_denominator / fps_numerator); } + int FramesFromAudioSamples(int samples) const { return int(__int64(samples) * fps_numerator / fps_denominator / audio_samples_per_second); } + int AudioSamplesFromBytes(int bytes) const { return bytes >> (stereo + sixteen_bit); } + int BytesFromAudioSamples(int samples) const { return samples << (stereo + sixteen_bit); } + int BytesPerAudioSample() const { return BytesFromAudioSamples(1); } + + // useful mutator + void SetFPS(unsigned numerator, unsigned denominator) { + unsigned x=numerator, y=denominator; + while (y) { // find gcd + unsigned t = x%y; x = y; y = t; + } + fps_numerator = numerator/x; + fps_denominator = denominator/x; + } +}; + + +// VideoFrameBuffer holds information about a memory block which is used +// for video data. For efficiency, instances of this class are not deleted +// when the refcount reaches zero; instead they're stored in a linked list +// to be reused. The instances are deleted when the corresponding AVS +// file is closed. + +class VideoFrameBuffer { + unsigned char* const data; + const int data_size; + // sequence_number is incremented every time the buffer is changed, so + // that stale views can tell they're no longer valid. + long sequence_number; + + friend class VideoFrame; + friend class Cache; + long refcount; + +public: + VideoFrameBuffer(int size); + VideoFrameBuffer(); + ~VideoFrameBuffer(); + + const unsigned char* GetReadPtr() const { return data; } + unsigned char* GetWritePtr() { ++sequence_number; return data; } + int GetDataSize() { return data_size; } + int GetSequenceNumber() { return sequence_number; } + int GetRefcount() { return refcount; } +}; + + +class IClip; +class PClip; +class PVideoFrame; +class IScriptEnvironment; +class AVSValue; + + +// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new +// is overloaded to recycle class instances. + +class VideoFrame { + int refcount; + VideoFrameBuffer* const vfb; + const int offset, pitch, row_size, height; + + friend class PVideoFrame; + void AddRef() { ++refcount; } + void Release() { if (refcount==1) --vfb->refcount; --refcount; } + + friend class ScriptEnvironment; + friend class Cache; + + VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); + + void* operator new(size_t size); + +public: + int GetPitch() const { return pitch; } + int GetRowSize() const { return row_size; } + int GetHeight() const { return height; } + + // generally you shouldn't use these two + VideoFrameBuffer* GetFrameBuffer() const { return vfb; } + int GetOffset() const { return offset; } + + // in plugins use env->SubFrame() + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; + + const unsigned char* GetReadPtr() const { return vfb->GetReadPtr() + offset; } + + bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } + + unsigned char* GetWritePtr() const { + return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; + } + + ~VideoFrame() { --vfb->refcount; } +}; + + +// Base class for all filters. +class IClip { + friend class PClip; + friend class AVSValue; + int refcnt; + void AddRef() { ++refcnt; } + void Release() { if (!--refcnt) delete this; } +public: + IClip() : refcnt(0) {} + + virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } + + virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; + virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame + virtual void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) = 0; // start and count are in samples + virtual const VideoInfo& __stdcall GetVideoInfo() = 0; +#if defined(__INTEL_COMPILER) + virtual ~IClip() {} +#else + virtual __stdcall ~IClip() {} +#endif +}; + + +// smart pointer to IClip +class PClip { + + IClip* p; + + IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } + friend class AVSValue; + friend class VideoFrame; + + void Init(IClip* x) { + if (x) x->AddRef(); + p=x; + } + void Set(IClip* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PClip() { p = 0; } + PClip(const PClip& x) { Init(x.p); } + PClip(IClip* x) { Init(x); } + void operator=(IClip* x) { Set(x); } + void operator=(const PClip& x) { Set(x.p); } + + IClip* operator->() const { return p; } + + // useful in conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PClip() { if (p) p->Release(); } +}; + + +// smart pointer to VideoFrame +class PVideoFrame { + + VideoFrame* p; + + void Init(VideoFrame* x) { + if (x) x->AddRef(); + p=x; + } + void Set(VideoFrame* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PVideoFrame() { p = 0; } + PVideoFrame(const PVideoFrame& x) { Init(x.p); } + PVideoFrame(VideoFrame* x) { Init(x); } + void operator=(VideoFrame* x) { Set(x); } + void operator=(const PVideoFrame& x) { Set(x.p); } + + VideoFrame* operator->() const { return p; } + + // for conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PVideoFrame() { if (p) p->Release(); } +}; + + +class AVSValue { +public: + + AVSValue() { type = 'v'; } + AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } + AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } + AVSValue(bool b) { type = 'b'; boolean = b; } + AVSValue(int i) { type = 'i'; integer = i; } + AVSValue(float f) { type = 'f'; floating_pt = f; } + AVSValue(double f) { type = 'f'; floating_pt = float(f); } + AVSValue(const char* s) { type = 's'; string = s; } + AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } + AVSValue(const AVSValue& v) { Assign(&v, true); } + + ~AVSValue() { if (IsClip() && clip) clip->Release(); } + AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } + + // Note that we transparently allow 'int' to be treated as 'float'. + // There are no int<->bool conversions, though. + + bool Defined() const { return type != 'v'; } + bool IsClip() const { return type == 'c'; } + bool IsBool() const { return type == 'b'; } + bool IsInt() const { return type == 'i'; } + bool IsFloat() const { return type == 'f' || type == 'i'; } + bool IsString() const { return type == 's'; } + bool IsArray() const { return type == 'a'; } + + PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } + bool AsBool() const { _ASSERTE(IsBool()); return boolean; } + int AsInt() const { _ASSERTE(IsInt()); return integer; } + const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } + double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } + + bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } + int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } + double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } + const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } + + int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } + const AVSValue& operator[](int index) const { + _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) + src->clip->AddRef(); + if (!init && IsClip() && clip) + clip->Release(); + // make sure this copies the whole struct! + ((__int32*)this)[0] = ((__int32*)src)[0]; + ((__int32*)this)[1] = ((__int32*)src)[1]; + } +}; + + +// instantiable null filter +class GenericVideoFilter : public IClip { +protected: + PClip child; + VideoInfo vi; +public: + GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } + void __stdcall GetAudio(void* buf, int start, int count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } + const VideoInfo& __stdcall GetVideoInfo() { return vi; } + bool __stdcall GetParity(int n) { return child->GetParity(n); } +}; + + +class AvisynthError /* exception */ { +public: + const char* const msg; + AvisynthError(const char* _msg) : msg(_msg) {} +}; + + +// For GetCPUFlags. These are the same as in VirtualDub. +enum { + CPUF_FORCE = 0x01, + CPUF_FPU = 0x02, + CPUF_MMX = 0x04, + CPUF_INTEGER_SSE = 0x08, // Athlon MMX extensions or Intel SSE + CPUF_SSE = 0x10, // Full SSE (PIII) + CPUF_SSE2 = 0x20, // (PIV) + CPUF_3DNOW = 0x40, + CPUF_3DNOW_EXT = 0x80, // Athlon 3DNow! extensions +}; + + +class IScriptEnvironment { +public: +#if defined(__INTEL_COMPILER) + virtual ~IScriptEnvironment() {} +#else + virtual __stdcall ~IScriptEnvironment() {} +#endif + + virtual /*static*/ long __stdcall GetCPUFlags() = 0; + + virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; + virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; + // note: val is really a va_list; I hope everyone typedefs va_list to a pointer + virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; + + __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; + + class NotFound /*exception*/ {}; // thrown by Invoke and GetVar + + typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); + + virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; + virtual bool __stdcall FunctionExists(const char* name) = 0; + virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; + + virtual AVSValue __stdcall GetVar(const char* name) = 0; + virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; + virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; + + virtual void __stdcall PushContext(int level=0) = 0; + virtual void __stdcall PopContext() = 0; + + // align should be 4 or 8 + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=8) = 0; + + virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; + + virtual /*static*/ void __stdcall BitBlt(unsigned char* dstp, int dst_pitch, const unsigned char* srcp, int src_pitch, int row_size, int height) = 0; + + typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); + virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; + + virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; + + virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; +}; + + +// avisynth.dll exports this; it's a way to use it as a library, without +// writing an AVS script or without going through AVIFile. +IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); + + +#pragma pack(pop) + diff --git a/include/avisynth/avisynth25.h b/include/avisynth/avisynth25.h index c8d58cb49c5..85b9f1afd1c 100644 --- a/include/avisynth/avisynth25.h +++ b/include/avisynth/avisynth25.h @@ -1,795 +1,795 @@ -// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. -// http://www.avisynth.org - -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit -// http://www.gnu.org/copyleft/gpl.html . -// -// Linking Avisynth statically or dynamically with other modules is making a -// combined work based on Avisynth. Thus, the terms and conditions of the GNU -// General Public License cover the whole combination. -// -// As a special exception, the copyright holders of Avisynth give you -// permission to link Avisynth with independent modules that communicate with -// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license -// terms of these independent modules, and to copy and distribute the -// resulting combined work under terms of your choice, provided that -// every copy of the combined work is accompanied by a complete copy of -// the source code of Avisynth (the version of Avisynth used to produce the -// combined work), being distributed under the terms of the GNU General -// Public License plus this exception. An independent module is a module -// which is not derived from or based on Avisynth, such as 3rd-party filters, -// import and export plugins, or graphical user interfaces. - - - - -#ifndef __AVISYNTH_H__ -#define __AVISYNTH_H__ - -enum { AVISYNTH_INTERFACE_VERSION = 3 }; - - -/* Define all types necessary for interfacing with avisynth.dll - Moved from internal.h */ - -// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc. -#include - -#if (_MSC_VER >= 1400) -extern "C" LONG __cdecl _InterlockedIncrement(LONG volatile * pn); -extern "C" LONG __cdecl _InterlockedDecrement(LONG volatile * pn); -#pragma intrinsic(_InterlockedIncrement) -#pragma intrinsic(_InterlockedDecrement) -#define InterlockedIncrement _InterlockedIncrement -#define InterlockedDecrement _InterlockedDecrement -#endif - -// COM interface macros -#include - - -// Raster types used by VirtualDub & Avisynth -#define in64 (__int64)(unsigned short) -typedef unsigned long Pixel; // this will break on 64-bit machines! -typedef unsigned long Pixel32; -typedef unsigned char Pixel8; -typedef long PixCoord; -typedef long PixDim; -typedef long PixOffset; - - -/* Compiler-specific crap */ - -// Tell MSVC to stop precompiling here -#ifdef _MSC_VER - #pragma hdrstop -#endif - -// Set up debugging macros for MS compilers; for others, step down to the -// standard interface -#ifdef _MSC_VER - #include -#else - #define _RPT0(a,b) ((void)0) - #define _RPT1(a,b,c) ((void)0) - #define _RPT2(a,b,c,d) ((void)0) - #define _RPT3(a,b,c,d,e) ((void)0) - #define _RPT4(a,b,c,d,e,f) ((void)0) - - #define _ASSERTE(x) assert(x) - #include -#endif - - - -// I had problems with Premiere wanting 1-byte alignment for its structures, -// so I now set the Avisynth struct alignment explicitly here. -#pragma pack(push,8) - -#define FRAME_ALIGN 16 -// Default frame alignment is 16 bytes, to help P4, when using SSE2 - -// The VideoInfo struct holds global information about a clip (i.e. -// information that does not depend on the frame number). The GetVideoInfo -// method in IClip returns this struct. - -// Audio Sample information -typedef float SFLOAT; - -enum {SAMPLE_INT8 = 1<<0, - SAMPLE_INT16 = 1<<1, - SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware. - SAMPLE_INT32 = 1<<3, - SAMPLE_FLOAT = 1<<4}; - -enum { - PLANAR_Y=1<<0, - PLANAR_U=1<<1, - PLANAR_V=1<<2, - PLANAR_ALIGNED=1<<3, - PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED, - PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED, - PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED - }; - -class AvisynthError /* exception */ { -public: - const char* const msg; - AvisynthError(const char* _msg) : msg(_msg) {} -}; - -struct VideoInfo { - int width, height; // width=0 means no video - unsigned fps_numerator, fps_denominator; - int num_frames; - // This is more extensible than previous versions. More properties can be added seeminglesly. - - // Colorspace properties. - enum { - CS_BGR = 1<<28, - CS_YUV = 1<<29, - CS_INTERLEAVED = 1<<30, - CS_PLANAR = 1<<31 - }; - - // Specific colorformats - enum { CS_UNKNOWN = 0, - CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED, - CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED, - CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED, - CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, 4:2:0 planar - CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, 4:2:0 planar - CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above - }; - int pixel_type; // changed to int as of 2.5 - - - int audio_samples_per_second; // 0 means no audio - int sample_type; // as of 2.5 - __int64 num_audio_samples; // changed as of 2.5 - int nchannels; // as of 2.5 - - // Imagetype properties - - int image_type; - - enum { - IT_BFF = 1<<0, - IT_TFF = 1<<1, - IT_FIELDBASED = 1<<2 - }; - - // useful functions of the above - bool HasVideo() const { return (width!=0); } - bool HasAudio() const { return (audio_samples_per_second!=0); } - bool IsRGB() const { return !!(pixel_type&CS_BGR); } - bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties - bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; } - bool IsYUV() const { return !!(pixel_type&CS_YUV ); } - bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; } - bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); } - bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); } - bool Is(int property) const { return ((pixel_type & property)==property ); } - bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); } - bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); } - bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); } - bool IsBFF() const { return !!(image_type & IT_BFF); } - bool IsTFF() const { return !!(image_type & IT_TFF); } - - bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this - int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes - int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images - int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); } - __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; } - int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; } - __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; } - __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); } - int AudioChannels() const { return HasAudio() ? nchannels : 0; } - int SampleType() const{ return sample_type;} - bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);} - int SamplesPerSecond() const { return audio_samples_per_second; } - int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();} - void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; } - void Set(int property) { image_type|=property; } - void Clear(int property) { image_type&=~property; } - - int BitsPerPixel() const { - switch (pixel_type) { - case CS_BGR24: - return 24; - case CS_BGR32: - return 32; - case CS_YUY2: - return 16; - case CS_YV12: - case CS_I420: - return 12; - default: - return 0; - } - } - - int BytesPerChannelSample() const { - switch (sample_type) { - case SAMPLE_INT8: - return sizeof(signed char); - case SAMPLE_INT16: - return sizeof(signed short); - case SAMPLE_INT24: - return 3; - case SAMPLE_INT32: - return sizeof(signed int); - case SAMPLE_FLOAT: - return sizeof(SFLOAT); - default: - _ASSERTE("Sample type not recognized!"); - return 0; - } - } - - // useful mutator - void SetFPS(unsigned numerator, unsigned denominator) { - if ((numerator == 0) || (denominator == 0)) { - fps_numerator = 0; - fps_denominator = 1; - } - else { - unsigned x=numerator, y=denominator; - while (y) { // find gcd - unsigned t = x%y; x = y; y = t; - } - fps_numerator = numerator/x; - fps_denominator = denominator/x; - } - } - - // Range protected multiply-divide of FPS - void MulDivFPS(unsigned multiplier, unsigned divisor) { - unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier); - unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor); - - unsigned __int64 x=numerator, y=denominator; - while (y) { // find gcd - unsigned __int64 t = x%y; x = y; y = t; - } - numerator /= x; // normalize - denominator /= x; - - unsigned __int64 temp = numerator | denominator; // Just looking top bit - unsigned u = 0; - while (temp & 0xffffffff80000000ull) { // or perhaps > 16777216*2 - temp = Int64ShrlMod32(temp, 1); - u++; - } - if (u) { // Scale to fit - const unsigned round = 1 << (u-1); - SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u), - (unsigned)Int64ShrlMod32(denominator + round, u) ); - } - else { - fps_numerator = (unsigned)numerator; - fps_denominator = (unsigned)denominator; - } - } - - // Test for same colorspace - bool IsSameColorspace(const VideoInfo& vi) const { - if (vi.pixel_type == pixel_type) return TRUE; - if (IsYV12() && vi.IsYV12()) return TRUE; - return FALSE; - } - -}; - - - - -// VideoFrameBuffer holds information about a memory block which is used -// for video data. For efficiency, instances of this class are not deleted -// when the refcount reaches zero; instead they're stored in a linked list -// to be reused. The instances are deleted when the corresponding AVS -// file is closed. - -class VideoFrameBuffer { - BYTE* const data; - const int data_size; - // sequence_number is incremented every time the buffer is changed, so - // that stale views can tell they're no longer valid. - volatile long sequence_number; - - friend class VideoFrame; - friend class Cache; - friend class CacheMT; - friend class ScriptEnvironment; - volatile long refcount; - -public: - VideoFrameBuffer(int size); - VideoFrameBuffer(); - ~VideoFrameBuffer(); - - const BYTE* GetReadPtr() const { return data; } - BYTE* GetWritePtr() { InterlockedIncrement(&sequence_number); return data; } - int GetDataSize() { return data_size; } - int GetSequenceNumber() { return sequence_number; } - int GetRefcount() { return refcount; } -}; - - -class IClip; -class PClip; -class PVideoFrame; -class IScriptEnvironment; -class AVSValue; - - -// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new -// is overloaded to recycle class instances. - -class VideoFrame { - volatile long refcount; - VideoFrameBuffer* const vfb; - const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. - - friend class PVideoFrame; - void AddRef() { InterlockedIncrement(&refcount); } - void Release() { VideoFrameBuffer* vfb_local = vfb; if (!InterlockedDecrement(&refcount)) InterlockedDecrement(&vfb_local->refcount); } - - friend class Cache; - friend class CacheMT; - friend class ScriptEnvironment; - - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); - VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV); - -#ifndef _WIN64 - void* operator new(unsigned size); -#else - void* operator new(size_t size); -#endif -// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard! -public: - int GetPitch() const { return pitch; } - int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; } - int GetRowSize() const { return row_size; } - __declspec(noinline) int GetRowSize(int plane) const { - switch (plane) { - case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0; - case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED: - if (pitchUV) { - int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize - if (r<=pitchUV) - return r; - return row_size>>1; - } else return 0; - case PLANAR_Y_ALIGNED: - int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize - if (r<=pitch) - return r; - return row_size; - } - return row_size; } - int GetHeight() const { return height; } - int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; } - - // generally you shouldn't use these three - VideoFrameBuffer* GetFrameBuffer() const { return vfb; } - int GetOffset() const { return offset; } - int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; } - - // in plugins use env->SubFrame() - //If you really want to use these remember to increase vfb->refcount before calling and decrement it afterwards. - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; - VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const; - - - const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; } - const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); } - - bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } - - BYTE* GetWritePtr() const { - if (vfb->GetRefcount()>1) { - _ASSERT(FALSE); - //throw AvisynthError("Internal Error - refcount was more than one!"); - } - return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; - } - - BYTE* GetWritePtr(int plane) const { - if (plane==PLANAR_Y) { - if (vfb->GetRefcount()>1) { - _ASSERT(FALSE); -// throw AvisynthError("Internal Error - refcount was more than one!"); - } - return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0; - } - return vfb->data + GetOffset(plane); - } - - ~VideoFrame() { VideoFrameBuffer* vfb_local = vfb; if (InterlockedDecrement(&refcount) >= 0) InterlockedDecrement(&vfb_local->refcount); } -}; - -enum { - CACHE_NOTHING=0, - CACHE_RANGE=1, - CACHE_ALL=2, - CACHE_AUDIO=3, - CACHE_AUDIO_NONE=4, - CACHE_AUDIO_AUTO=5 - }; - -// Base class for all filters. -class IClip { - friend class PClip; - friend class AVSValue; - volatile long refcnt; - void AddRef() { InterlockedIncrement(&refcnt); } - void Release() { if (!InterlockedDecrement(&refcnt)) delete this; } -public: - IClip() : refcnt(0) {} - - virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } - - virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; - virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame - virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples - virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter. - virtual const VideoInfo& __stdcall GetVideoInfo() = 0; -#if defined(__INTEL_COMPILER) - virtual ~IClip() {} -#else - virtual __stdcall ~IClip() {} -#endif -}; - - -// smart pointer to IClip -class PClip { - - IClip* p; - - IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } - friend class AVSValue; - friend class VideoFrame; - - void Init(IClip* x) { - if (x) x->AddRef(); - p=x; - } - void Set(IClip* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PClip() { p = 0; } - PClip(const PClip& x) { Init(x.p); } - PClip(IClip* x) { Init(x); } - void operator=(IClip* x) { Set(x); } - void operator=(const PClip& x) { Set(x.p); } - - IClip* operator->() const { return p; } - - // useful in conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PClip() { if (p) p->Release(); } -}; - - -// smart pointer to VideoFrame -class PVideoFrame { - - VideoFrame* p; - - void Init(VideoFrame* x) { - if (x) x->AddRef(); - p=x; - } - void Set(VideoFrame* x) { - if (x) x->AddRef(); - if (p) p->Release(); - p=x; - } - -public: - PVideoFrame() { p = 0; } - PVideoFrame(const PVideoFrame& x) { Init(x.p); } - PVideoFrame(VideoFrame* x) { Init(x); } - void operator=(VideoFrame* x) { Set(x); } - void operator=(const PVideoFrame& x) { Set(x.p); } - - VideoFrame* operator->() const { return p; } - - // for conditional expressions - operator void*() const { return p; } - bool operator!() const { return !p; } - - ~PVideoFrame() { if (p) p->Release();} -}; - - -class AVSValue { -public: - - AVSValue() { type = 'v'; } - AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } - AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } - AVSValue(bool b) { type = 'b'; boolean = b; } - AVSValue(int i) { type = 'i'; integer = i; } -// AVSValue(__int64 l) { type = 'l'; longlong = l; } - AVSValue(float f) { type = 'f'; floating_pt = f; } - AVSValue(double f) { type = 'f'; floating_pt = float(f); } - AVSValue(const char* s) { type = 's'; string = s; } - AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } - AVSValue(const AVSValue& v) { Assign(&v, true); } - - ~AVSValue() { if (IsClip() && clip) clip->Release(); } - AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } - - // Note that we transparently allow 'int' to be treated as 'float'. - // There are no int<->bool conversions, though. - - bool Defined() const { return type != 'v'; } - bool IsClip() const { return type == 'c'; } - bool IsBool() const { return type == 'b'; } - bool IsInt() const { return type == 'i'; } -// bool IsLong() const { return (type == 'l'|| type == 'i'); } - bool IsFloat() const { return type == 'f' || type == 'i'; } - bool IsString() const { return type == 's'; } - bool IsArray() const { return type == 'a'; } - - PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } - bool AsBool() const { _ASSERTE(IsBool()); return boolean; } - int AsInt() const { _ASSERTE(IsInt()); return integer; } -// int AsLong() const { _ASSERTE(IsLong()); return longlong; } - const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } - double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } - - bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } - int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } - double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } - const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } - - int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } - - const AVSValue& operator[](int index) const { - _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) - src->clip->AddRef(); - if (!init && IsClip() && clip) - clip->Release(); - // make sure this copies the whole struct! - /* UGH! what the- ? - ((__int32*)this)[0] = ((__int32*)src)[0]; - ((__int32*)this)[1] = ((__int32*)src)[1]; - */ - this->clip = src->clip; - this->type = src->type; - this->array_size = src->array_size; - } -}; - - -// instantiable null filter -class GenericVideoFilter : public IClip { -protected: - PClip child; - VideoInfo vi; -public: - GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } - void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } - const VideoInfo& __stdcall GetVideoInfo() { return vi; } - bool __stdcall GetParity(int n) { return child->GetParity(n); } - void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter. -}; - - - - - -/* Helper classes useful to plugin authors */ - -class AlignPlanar : public GenericVideoFilter -{ -public: - AlignPlanar(PClip _clip); - static PClip Create(PClip clip); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); -}; - - - -class FillBorder : public GenericVideoFilter -{ -public: - FillBorder(PClip _clip); - static PClip Create(PClip clip); - PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); -}; - - - -class ConvertAudio : public GenericVideoFilter -/** - * Helper class to convert audio to any format - **/ -{ -public: - ConvertAudio(PClip _clip, int prefered_format); - void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env); - void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache! - - static PClip Create(PClip clip, int sample_type, int prefered_type); - static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_8bit (AVSValue args, void*, IScriptEnvironment*); - static AVSValue __cdecl Create_Any (AVSValue args, void*, IScriptEnvironment*); - virtual ~ConvertAudio(); - -private: - void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count); - void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count); - void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count); - void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count); - - __inline int Saturate_int8(float n); - __inline short Saturate_int16(float n); - __inline int Saturate_int24(float n); - __inline int Saturate_int32(float n); - - char src_format; - char dst_format; - int src_bps; - char *tempbuffer; - SFLOAT *floatbuffer; - int tempbuffer_size; -}; - - -// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. -enum { - /* slowest CPU to support extension */ - CPUF_FORCE = 0x01, // N/A - CPUF_FPU = 0x02, // 386/486DX - CPUF_MMX = 0x04, // P55C, K6, PII - CPUF_INTEGER_SSE = 0x08, // PIII, Athlon - CPUF_SSE = 0x10, // PIII, Athlon XP/MP - CPUF_SSE2 = 0x20, // PIV, Hammer - CPUF_3DNOW = 0x40, // K6-2 - CPUF_3DNOW_EXT = 0x80, // Athlon - CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which - // only Hammer will have anyway) - CPUF_SSE3 = 0x100, // PIV+, Hammer - CPUF_SSSE3 = 0x200, // prescott? - CPUF_SSE4 = 0x400, // penryn - CPUF_SSE4_2 = 0x800 // Core iX -}; - -//josh: changed these just bc winsdk defines them in BaseTsd.h -#define MAX_INT MAXINT32 -#define MIN_INT MININT32 // ::FIXME:: research why this is not 0x80000000 - - - -class IClipLocalStorage; - -class IScriptEnvironment { -public: -#if defined(__INTEL_COMPILER) - virtual ~IScriptEnvironment() {} -#else - virtual __stdcall ~IScriptEnvironment() {} -#endif - - virtual /*static*/ long __stdcall GetCPUFlags() = 0; - - virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; - virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; - // note: val is really a va_list; I hope everyone typedefs va_list to a pointer - virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; - - __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; - - class NotFound /*exception*/ {}; // thrown by Invoke and GetVar - - typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); - - virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; - virtual bool __stdcall FunctionExists(const char* name) = 0; - virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; - - virtual AVSValue __stdcall GetVar(const char* name) = 0; - virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; - virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; - - virtual void __stdcall PushContext(int level=0) = 0; - virtual void __stdcall PopContext() = 0; - - // align should be 4 or 8 - virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0; - - virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; - - virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; - - typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); - virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; - - virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; - - virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; - - virtual int __stdcall SetMemoryMax(int mem) = 0; - - virtual int __stdcall SetWorkingDir(const char * newdir) = 0; - - virtual void* __stdcall ManageCache(int key, void* data) = 0; - - enum PlanarChromaAlignmentMode { - PlanarChromaAlignmentOff, - PlanarChromaAlignmentOn, - PlanarChromaAlignmentTest }; - - virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0; - - virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; - - virtual void __stdcall SetMTMode(int mode,int threads,bool temporary)=0; - virtual int __stdcall GetMTMode(bool return_nthreads)=0; - - virtual IClipLocalStorage* __stdcall AllocClipLocalStorage()=0; - - virtual void __stdcall SaveClipLocalStorage()=0; - virtual void __stdcall RestoreClipLocalStorage()=0; -}; - - -// avisynth.dll exports this; it's a way to use it as a library, without -// writing an AVS script or without going through AVIFile. -IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); - - -#pragma pack(pop) - -#endif //__AVISYNTH_H__ +// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. +// http://www.avisynth.org + +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// Linking Avisynth statically or dynamically with other modules is making a +// combined work based on Avisynth. Thus, the terms and conditions of the GNU +// General Public License cover the whole combination. +// +// As a special exception, the copyright holders of Avisynth give you +// permission to link Avisynth with independent modules that communicate with +// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license +// terms of these independent modules, and to copy and distribute the +// resulting combined work under terms of your choice, provided that +// every copy of the combined work is accompanied by a complete copy of +// the source code of Avisynth (the version of Avisynth used to produce the +// combined work), being distributed under the terms of the GNU General +// Public License plus this exception. An independent module is a module +// which is not derived from or based on Avisynth, such as 3rd-party filters, +// import and export plugins, or graphical user interfaces. + + + + +#ifndef __AVISYNTH_H__ +#define __AVISYNTH_H__ + +enum { AVISYNTH_INTERFACE_VERSION = 3 }; + + +/* Define all types necessary for interfacing with avisynth.dll + Moved from internal.h */ + +// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc. +#include + +#if (_MSC_VER >= 1400) +extern "C" LONG __cdecl _InterlockedIncrement(LONG volatile * pn); +extern "C" LONG __cdecl _InterlockedDecrement(LONG volatile * pn); +#pragma intrinsic(_InterlockedIncrement) +#pragma intrinsic(_InterlockedDecrement) +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#endif + +// COM interface macros +#include + + +// Raster types used by VirtualDub & Avisynth +#define in64 (__int64)(unsigned short) +typedef unsigned long Pixel; // this will break on 64-bit machines! +typedef unsigned long Pixel32; +typedef unsigned char Pixel8; +typedef long PixCoord; +typedef long PixDim; +typedef long PixOffset; + + +/* Compiler-specific crap */ + +// Tell MSVC to stop precompiling here +#ifdef _MSC_VER + #pragma hdrstop +#endif + +// Set up debugging macros for MS compilers; for others, step down to the +// standard interface +#ifdef _MSC_VER + #include +#else + #define _RPT0(a,b) ((void)0) + #define _RPT1(a,b,c) ((void)0) + #define _RPT2(a,b,c,d) ((void)0) + #define _RPT3(a,b,c,d,e) ((void)0) + #define _RPT4(a,b,c,d,e,f) ((void)0) + + #define _ASSERTE(x) assert(x) + #include +#endif + + + +// I had problems with Premiere wanting 1-byte alignment for its structures, +// so I now set the Avisynth struct alignment explicitly here. +#pragma pack(push,8) + +#define FRAME_ALIGN 16 +// Default frame alignment is 16 bytes, to help P4, when using SSE2 + +// The VideoInfo struct holds global information about a clip (i.e. +// information that does not depend on the frame number). The GetVideoInfo +// method in IClip returns this struct. + +// Audio Sample information +typedef float SFLOAT; + +enum {SAMPLE_INT8 = 1<<0, + SAMPLE_INT16 = 1<<1, + SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware. + SAMPLE_INT32 = 1<<3, + SAMPLE_FLOAT = 1<<4}; + +enum { + PLANAR_Y=1<<0, + PLANAR_U=1<<1, + PLANAR_V=1<<2, + PLANAR_ALIGNED=1<<3, + PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED, + PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED, + PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED + }; + +class AvisynthError /* exception */ { +public: + const char* const msg; + AvisynthError(const char* _msg) : msg(_msg) {} +}; + +struct VideoInfo { + int width, height; // width=0 means no video + unsigned fps_numerator, fps_denominator; + int num_frames; + // This is more extensible than previous versions. More properties can be added seeminglesly. + + // Colorspace properties. + enum { + CS_BGR = 1<<28, + CS_YUV = 1<<29, + CS_INTERLEAVED = 1<<30, + CS_PLANAR = 1<<31 + }; + + // Specific colorformats + enum { CS_UNKNOWN = 0, + CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED, + CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED, + CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED, + CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, 4:2:0 planar + CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, 4:2:0 planar + CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above + }; + int pixel_type; // changed to int as of 2.5 + + + int audio_samples_per_second; // 0 means no audio + int sample_type; // as of 2.5 + __int64 num_audio_samples; // changed as of 2.5 + int nchannels; // as of 2.5 + + // Imagetype properties + + int image_type; + + enum { + IT_BFF = 1<<0, + IT_TFF = 1<<1, + IT_FIELDBASED = 1<<2 + }; + + // useful functions of the above + bool HasVideo() const { return (width!=0); } + bool HasAudio() const { return (audio_samples_per_second!=0); } + bool IsRGB() const { return !!(pixel_type&CS_BGR); } + bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties + bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; } + bool IsYUV() const { return !!(pixel_type&CS_YUV ); } + bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; } + bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); } + bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); } + bool Is(int property) const { return ((pixel_type & property)==property ); } + bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); } + bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); } + bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); } + bool IsBFF() const { return !!(image_type & IT_BFF); } + bool IsTFF() const { return !!(image_type & IT_TFF); } + + bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this + int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes + int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images + int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); } + __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; } + int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; } + __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; } + __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); } + int AudioChannels() const { return HasAudio() ? nchannels : 0; } + int SampleType() const{ return sample_type;} + bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);} + int SamplesPerSecond() const { return audio_samples_per_second; } + int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();} + void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; } + void Set(int property) { image_type|=property; } + void Clear(int property) { image_type&=~property; } + + int BitsPerPixel() const { + switch (pixel_type) { + case CS_BGR24: + return 24; + case CS_BGR32: + return 32; + case CS_YUY2: + return 16; + case CS_YV12: + case CS_I420: + return 12; + default: + return 0; + } + } + + int BytesPerChannelSample() const { + switch (sample_type) { + case SAMPLE_INT8: + return sizeof(signed char); + case SAMPLE_INT16: + return sizeof(signed short); + case SAMPLE_INT24: + return 3; + case SAMPLE_INT32: + return sizeof(signed int); + case SAMPLE_FLOAT: + return sizeof(SFLOAT); + default: + _ASSERTE("Sample type not recognized!"); + return 0; + } + } + + // useful mutator + void SetFPS(unsigned numerator, unsigned denominator) { + if ((numerator == 0) || (denominator == 0)) { + fps_numerator = 0; + fps_denominator = 1; + } + else { + unsigned x=numerator, y=denominator; + while (y) { // find gcd + unsigned t = x%y; x = y; y = t; + } + fps_numerator = numerator/x; + fps_denominator = denominator/x; + } + } + + // Range protected multiply-divide of FPS + void MulDivFPS(unsigned multiplier, unsigned divisor) { + unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier); + unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor); + + unsigned __int64 x=numerator, y=denominator; + while (y) { // find gcd + unsigned __int64 t = x%y; x = y; y = t; + } + numerator /= x; // normalize + denominator /= x; + + unsigned __int64 temp = numerator | denominator; // Just looking top bit + unsigned u = 0; + while (temp & 0xffffffff80000000ull) { // or perhaps > 16777216*2 + temp = Int64ShrlMod32(temp, 1); + u++; + } + if (u) { // Scale to fit + const unsigned round = 1 << (u-1); + SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u), + (unsigned)Int64ShrlMod32(denominator + round, u) ); + } + else { + fps_numerator = (unsigned)numerator; + fps_denominator = (unsigned)denominator; + } + } + + // Test for same colorspace + bool IsSameColorspace(const VideoInfo& vi) const { + if (vi.pixel_type == pixel_type) return TRUE; + if (IsYV12() && vi.IsYV12()) return TRUE; + return FALSE; + } + +}; + + + + +// VideoFrameBuffer holds information about a memory block which is used +// for video data. For efficiency, instances of this class are not deleted +// when the refcount reaches zero; instead they're stored in a linked list +// to be reused. The instances are deleted when the corresponding AVS +// file is closed. + +class VideoFrameBuffer { + BYTE* const data; + const int data_size; + // sequence_number is incremented every time the buffer is changed, so + // that stale views can tell they're no longer valid. + volatile long sequence_number; + + friend class VideoFrame; + friend class Cache; + friend class CacheMT; + friend class ScriptEnvironment; + volatile long refcount; + +public: + VideoFrameBuffer(int size); + VideoFrameBuffer(); + ~VideoFrameBuffer(); + + const BYTE* GetReadPtr() const { return data; } + BYTE* GetWritePtr() { InterlockedIncrement(&sequence_number); return data; } + int GetDataSize() { return data_size; } + int GetSequenceNumber() { return sequence_number; } + int GetRefcount() { return refcount; } +}; + + +class IClip; +class PClip; +class PVideoFrame; +class IScriptEnvironment; +class AVSValue; + + +// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new +// is overloaded to recycle class instances. + +class VideoFrame { + volatile long refcount; + VideoFrameBuffer* const vfb; + const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. + + friend class PVideoFrame; + void AddRef() { InterlockedIncrement(&refcount); } + void Release() { VideoFrameBuffer* vfb_local = vfb; if (!InterlockedDecrement(&refcount)) InterlockedDecrement(&vfb_local->refcount); } + + friend class Cache; + friend class CacheMT; + friend class ScriptEnvironment; + + VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); + VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV); + +#ifndef _WIN64 + void* operator new(unsigned size); +#else + void* operator new(size_t size); +#endif +// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard! +public: + int GetPitch() const { return pitch; } + int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; } + int GetRowSize() const { return row_size; } + __declspec(noinline) int GetRowSize(int plane) const { + switch (plane) { + case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0; + case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED: + if (pitchUV) { + int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize + if (r<=pitchUV) + return r; + return row_size>>1; + } else return 0; + case PLANAR_Y_ALIGNED: + int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize + if (r<=pitch) + return r; + return row_size; + } + return row_size; } + int GetHeight() const { return height; } + int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; } + + // generally you shouldn't use these three + VideoFrameBuffer* GetFrameBuffer() const { return vfb; } + int GetOffset() const { return offset; } + int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; } + + // in plugins use env->SubFrame() + //If you really want to use these remember to increase vfb->refcount before calling and decrement it afterwards. + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const; + + + const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; } + const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); } + + bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } + + BYTE* GetWritePtr() const { + if (vfb->GetRefcount()>1) { + _ASSERT(FALSE); + //throw AvisynthError("Internal Error - refcount was more than one!"); + } + return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; + } + + BYTE* GetWritePtr(int plane) const { + if (plane==PLANAR_Y) { + if (vfb->GetRefcount()>1) { + _ASSERT(FALSE); +// throw AvisynthError("Internal Error - refcount was more than one!"); + } + return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0; + } + return vfb->data + GetOffset(plane); + } + + ~VideoFrame() { VideoFrameBuffer* vfb_local = vfb; if (InterlockedDecrement(&refcount) >= 0) InterlockedDecrement(&vfb_local->refcount); } +}; + +enum { + CACHE_NOTHING=0, + CACHE_RANGE=1, + CACHE_ALL=2, + CACHE_AUDIO=3, + CACHE_AUDIO_NONE=4, + CACHE_AUDIO_AUTO=5 + }; + +// Base class for all filters. +class IClip { + friend class PClip; + friend class AVSValue; + volatile long refcnt; + void AddRef() { InterlockedIncrement(&refcnt); } + void Release() { if (!InterlockedDecrement(&refcnt)) delete this; } +public: + IClip() : refcnt(0) {} + + virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } + + virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; + virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame + virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples + virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter. + virtual const VideoInfo& __stdcall GetVideoInfo() = 0; +#if defined(__INTEL_COMPILER) + virtual ~IClip() {} +#else + virtual __stdcall ~IClip() {} +#endif +}; + + +// smart pointer to IClip +class PClip { + + IClip* p; + + IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } + friend class AVSValue; + friend class VideoFrame; + + void Init(IClip* x) { + if (x) x->AddRef(); + p=x; + } + void Set(IClip* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PClip() { p = 0; } + PClip(const PClip& x) { Init(x.p); } + PClip(IClip* x) { Init(x); } + void operator=(IClip* x) { Set(x); } + void operator=(const PClip& x) { Set(x.p); } + + IClip* operator->() const { return p; } + + // useful in conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PClip() { if (p) p->Release(); } +}; + + +// smart pointer to VideoFrame +class PVideoFrame { + + VideoFrame* p; + + void Init(VideoFrame* x) { + if (x) x->AddRef(); + p=x; + } + void Set(VideoFrame* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PVideoFrame() { p = 0; } + PVideoFrame(const PVideoFrame& x) { Init(x.p); } + PVideoFrame(VideoFrame* x) { Init(x); } + void operator=(VideoFrame* x) { Set(x); } + void operator=(const PVideoFrame& x) { Set(x.p); } + + VideoFrame* operator->() const { return p; } + + // for conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PVideoFrame() { if (p) p->Release();} +}; + + +class AVSValue { +public: + + AVSValue() { type = 'v'; } + AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } + AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } + AVSValue(bool b) { type = 'b'; boolean = b; } + AVSValue(int i) { type = 'i'; integer = i; } +// AVSValue(__int64 l) { type = 'l'; longlong = l; } + AVSValue(float f) { type = 'f'; floating_pt = f; } + AVSValue(double f) { type = 'f'; floating_pt = float(f); } + AVSValue(const char* s) { type = 's'; string = s; } + AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } + AVSValue(const AVSValue& v) { Assign(&v, true); } + + ~AVSValue() { if (IsClip() && clip) clip->Release(); } + AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } + + // Note that we transparently allow 'int' to be treated as 'float'. + // There are no int<->bool conversions, though. + + bool Defined() const { return type != 'v'; } + bool IsClip() const { return type == 'c'; } + bool IsBool() const { return type == 'b'; } + bool IsInt() const { return type == 'i'; } +// bool IsLong() const { return (type == 'l'|| type == 'i'); } + bool IsFloat() const { return type == 'f' || type == 'i'; } + bool IsString() const { return type == 's'; } + bool IsArray() const { return type == 'a'; } + + PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } + bool AsBool() const { _ASSERTE(IsBool()); return boolean; } + int AsInt() const { _ASSERTE(IsInt()); return integer; } +// int AsLong() const { _ASSERTE(IsLong()); return longlong; } + const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } + double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } + + bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } + int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } + double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } + const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } + + int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } + + const AVSValue& operator[](int index) const { + _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) + src->clip->AddRef(); + if (!init && IsClip() && clip) + clip->Release(); + // make sure this copies the whole struct! + /* UGH! what the- ? + ((__int32*)this)[0] = ((__int32*)src)[0]; + ((__int32*)this)[1] = ((__int32*)src)[1]; + */ + this->clip = src->clip; + this->type = src->type; + this->array_size = src->array_size; + } +}; + + +// instantiable null filter +class GenericVideoFilter : public IClip { +protected: + PClip child; + VideoInfo vi; +public: + GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } + void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } + const VideoInfo& __stdcall GetVideoInfo() { return vi; } + bool __stdcall GetParity(int n) { return child->GetParity(n); } + void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter. +}; + + + + + +/* Helper classes useful to plugin authors */ + +class AlignPlanar : public GenericVideoFilter +{ +public: + AlignPlanar(PClip _clip); + static PClip Create(PClip clip); + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); +}; + + + +class FillBorder : public GenericVideoFilter +{ +public: + FillBorder(PClip _clip); + static PClip Create(PClip clip); + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); +}; + + + +class ConvertAudio : public GenericVideoFilter +/** + * Helper class to convert audio to any format + **/ +{ +public: + ConvertAudio(PClip _clip, int prefered_format); + void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env); + void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache! + + static PClip Create(PClip clip, int sample_type, int prefered_type); + static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_8bit (AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_Any (AVSValue args, void*, IScriptEnvironment*); + virtual ~ConvertAudio(); + +private: + void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count); + void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count); + + __inline int Saturate_int8(float n); + __inline short Saturate_int16(float n); + __inline int Saturate_int24(float n); + __inline int Saturate_int32(float n); + + char src_format; + char dst_format; + int src_bps; + char *tempbuffer; + SFLOAT *floatbuffer; + int tempbuffer_size; +}; + + +// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. +enum { + /* slowest CPU to support extension */ + CPUF_FORCE = 0x01, // N/A + CPUF_FPU = 0x02, // 386/486DX + CPUF_MMX = 0x04, // P55C, K6, PII + CPUF_INTEGER_SSE = 0x08, // PIII, Athlon + CPUF_SSE = 0x10, // PIII, Athlon XP/MP + CPUF_SSE2 = 0x20, // PIV, Hammer + CPUF_3DNOW = 0x40, // K6-2 + CPUF_3DNOW_EXT = 0x80, // Athlon + CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which + // only Hammer will have anyway) + CPUF_SSE3 = 0x100, // PIV+, Hammer + CPUF_SSSE3 = 0x200, // prescott? + CPUF_SSE4 = 0x400, // penryn + CPUF_SSE4_2 = 0x800 // Core iX +}; + +//josh: changed these just bc winsdk defines them in BaseTsd.h +#define MAX_INT MAXINT32 +#define MIN_INT MININT32 // ::FIXME:: research why this is not 0x80000000 + + + +class IClipLocalStorage; + +class IScriptEnvironment { +public: +#if defined(__INTEL_COMPILER) + virtual ~IScriptEnvironment() {} +#else + virtual __stdcall ~IScriptEnvironment() {} +#endif + + virtual /*static*/ long __stdcall GetCPUFlags() = 0; + + virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; + virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; + // note: val is really a va_list; I hope everyone typedefs va_list to a pointer + virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; + + __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; + + class NotFound /*exception*/ {}; // thrown by Invoke and GetVar + + typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); + + virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; + virtual bool __stdcall FunctionExists(const char* name) = 0; + virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; + + virtual AVSValue __stdcall GetVar(const char* name) = 0; + virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; + virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; + + virtual void __stdcall PushContext(int level=0) = 0; + virtual void __stdcall PopContext() = 0; + + // align should be 4 or 8 + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0; + + virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; + + virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; + + typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); + virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; + + virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; + + virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; + + virtual int __stdcall SetMemoryMax(int mem) = 0; + + virtual int __stdcall SetWorkingDir(const char * newdir) = 0; + + virtual void* __stdcall ManageCache(int key, void* data) = 0; + + enum PlanarChromaAlignmentMode { + PlanarChromaAlignmentOff, + PlanarChromaAlignmentOn, + PlanarChromaAlignmentTest }; + + virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0; + + virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; + + virtual void __stdcall SetMTMode(int mode,int threads,bool temporary)=0; + virtual int __stdcall GetMTMode(bool return_nthreads)=0; + + virtual IClipLocalStorage* __stdcall AllocClipLocalStorage()=0; + + virtual void __stdcall SaveClipLocalStorage()=0; + virtual void __stdcall RestoreClipLocalStorage()=0; +}; + + +// avisynth.dll exports this; it's a way to use it as a library, without +// writing an AVS script or without going through AVIFile. +IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); + + +#pragma pack(pop) + +#endif //__AVISYNTH_H__ diff --git a/include/dsm/dsm.h b/include/dsm/dsm.h index 981e7d2082e..dc2920dae71 100644 --- a/include/dsm/dsm.h +++ b/include/dsm/dsm.h @@ -1,37 +1,37 @@ -/* - * (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 . - * - */ - -#pragma once - -#define DSMF_VERSION 0x01 - -#define DSMSW 0x44534D53ui64 -#define DSMSW_SIZE 4 - -enum dsmp_t { - DSMP_FILEINFO = 0, - DSMP_STREAMINFO = 1, - DSMP_MEDIATYPE = 2, - DSMP_CHAPTERS = 3, - DSMP_SAMPLE = 4, - DSMP_SYNCPOINTS = 5, - DSMP_RESOURCE = 6 -}; +/* + * (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 . + * + */ + +#pragma once + +#define DSMF_VERSION 0x01 + +#define DSMSW 0x44534D53ui64 +#define DSMSW_SIZE 4 + +enum dsmp_t { + DSMP_FILEINFO = 0, + DSMP_STREAMINFO = 1, + DSMP_MEDIATYPE = 2, + DSMP_CHAPTERS = 3, + DSMP_SAMPLE = 4, + DSMP_SYNCPOINTS = 5, + DSMP_RESOURCE = 6 +}; diff --git a/include/lglcd/lglcd.h b/include/lglcd/lglcd.h index f70145f10b5..e86c2ca2088 100644 --- a/include/lglcd/lglcd.h +++ b/include/lglcd/lglcd.h @@ -1,456 +1,456 @@ -/* - - lglcd.h - - library definition for lglcd.a - part of lglcd for Microsoft(R) Windows(R) - - The Logitech LCD SDK, including all acompanying documentation, - is protected by intellectual property laws. All use of the Logitech - LCD SDK is subject to the License Agreement found in the - "ReadMe License Agreement" file and in the Reference Manual. All rights - not expressly granted by Logitech are reserved. - - - 01/14/2005 1.00 initial draft - 02/23/2005 1.01 added callbacks, implemented changes as discussed - 02/08/2006 1.02 added call to set foreground, sync update with confirmation - 05/29/2006 1.03 Added device family feature - 12/03/2007 3.00 Added support for color devices and partial event notifications (arrival and removal) - 10/03/2008 3.01 Added more event notifications - 10/27/2008 3.01 Deprecated enumeration and index-based open; Applets should use lgLcdOpenByType() (and - possibly notifications) - -*/ - -#ifndef _LGLCD_H_INCLUDED_ -#define _LGLCD_H_INCLUDED_ - -#ifdef __cplusplus -extern "C" { -#endif - -#pragma pack(push, 8) - -//// Definitions - -// Invalid handle definitions -#define LGLCD_INVALID_CONNECTION (-1) -#define LGLCD_INVALID_DEVICE (-1) - - -// Common Soft-Buttons available through the SDK -#define LGLCDBUTTON_LEFT (0x00000100) -#define LGLCDBUTTON_RIGHT (0x00000200) -#define LGLCDBUTTON_OK (0x00000400) -#define LGLCDBUTTON_CANCEL (0x00000800) -#define LGLCDBUTTON_UP (0x00001000) -#define LGLCDBUTTON_DOWN (0x00002000) -#define LGLCDBUTTON_MENU (0x00004000) - -// Soft-Button masks. Kept for backwards compatibility -#define LGLCDBUTTON_BUTTON0 (0x00000001) -#define LGLCDBUTTON_BUTTON1 (0x00000002) -#define LGLCDBUTTON_BUTTON2 (0x00000004) -#define LGLCDBUTTON_BUTTON3 (0x00000008) -#define LGLCDBUTTON_BUTTON4 (0x00000010) -#define LGLCDBUTTON_BUTTON5 (0x00000020) -#define LGLCDBUTTON_BUTTON6 (0x00000040) -#define LGLCDBUTTON_BUTTON7 (0x00000080) - -//************************************************************************ -// lgLcdDeviceDesc -//************************************************************************ -typedef struct -{ - DWORD Width; - DWORD Height; - DWORD Bpp; - DWORD NumSoftButtons; -} lgLcdDeviceDesc; - - -//************************************************************************ -// lgLcdDeviceDescEx -//************************************************************************ -typedef struct -{ - DWORD deviceFamilyId; - WCHAR deviceDisplayName[MAX_PATH]; - DWORD Width; // # of pixels (horizontally) on the LCD - DWORD Height; // # of pixels (lines) on the LCD - DWORD Bpp; // # of bits per pixel (1,8,16,24,...) - DWORD NumSoftButtons; - DWORD Reserved1; - DWORD Reserved2; -} lgLcdDeviceDescExW; - -typedef struct -{ - DWORD deviceFamilyId; - CHAR deviceDisplayName[MAX_PATH]; - DWORD Width; - DWORD Height; - DWORD Bpp; - DWORD NumSoftButtons; - DWORD Reserved1; - DWORD Reserved2; -} lgLcdDeviceDescExA; - -#ifdef UNICODE -typedef lgLcdDeviceDescExW lgLcdDeviceDescEx; -#else -typedef lgLcdDeviceDescExA lgLcdDeviceDescEx; -#endif - -//************************************************************************ -// lgLcdBitmap -//************************************************************************ - -#define LGLCD_BMP_FORMAT_160x43x1 (0x00000001) -#define LGLCD_BMP_FORMAT_QVGAx32 (0x00000003) -#define LGLCD_BMP_WIDTH (160) -#define LGLCD_BMP_HEIGHT (43) -#define LGLCD_BMP_BPP (1) -#define LGLCD_BW_BMP_WIDTH (160) -#define LGLCD_BW_BMP_HEIGHT (43) -#define LGLCD_BW_BMP_BPP (1) -#define LGLCD_QVGA_BMP_WIDTH (320) -#define LGLCD_QVGA_BMP_HEIGHT (240) -#define LGLCD_QVGA_BMP_BPP (4) - -typedef struct -{ - DWORD Format; -} lgLcdBitmapHeader; - -typedef struct -{ - lgLcdBitmapHeader hdr; - BYTE pixels[LGLCD_BMP_WIDTH * LGLCD_BMP_HEIGHT * LGLCD_BMP_BPP]; -} lgLcdBitmap160x43x1; - -typedef struct -{ - lgLcdBitmapHeader hdr; // Format = LGLCD_BMP_FORMAT_QVGAx32 - BYTE pixels[LGLCD_QVGA_BMP_WIDTH * LGLCD_QVGA_BMP_HEIGHT * LGLCD_QVGA_BMP_BPP]; -} lgLcdBitmapQVGAx32; -// -// Generic bitmap for use by both color and BW applets -// -typedef union -{ - lgLcdBitmapHeader hdr; // provides easy access to the header - lgLcdBitmap160x43x1 bmp_mono; // B/W bitmap data - lgLcdBitmapQVGAx32 bmp_qvga32; // Color bitmap data -} lgLcdBitmap; - -// Priorities -#define LGLCD_PRIORITY_IDLE_NO_SHOW (0) -#define LGLCD_PRIORITY_BACKGROUND (64) -#define LGLCD_PRIORITY_NORMAL (128) -#define LGLCD_PRIORITY_ALERT (255) -#define LGLCD_SYNC_UPDATE(priority) (0x80000000 | (priority)) -#define LGLCD_SYNC_COMPLETE_WITHIN_FRAME(priority) (0xC0000000 | (priority)) -#define LGLCD_ASYNC_UPDATE(priority) (priority) - -// Foreground mode for client applications -#define LGLCD_LCD_FOREGROUND_APP_NO (0) -#define LGLCD_LCD_FOREGROUND_APP_YES (1) - -// Device family definitions -#define LGLCD_DEVICE_FAMILY_BW_160x43_GAMING (0x00000001) -#define LGLCD_DEVICE_FAMILY_KEYBOARD_G15 (0x00000001) -#define LGLCD_DEVICE_FAMILY_BW_160x43_AUDIO (0x00000002) -#define LGLCD_DEVICE_FAMILY_SPEAKERS_Z10 (0x00000002) -#define LGLCD_DEVICE_FAMILY_JACKBOX (0x00000004) -#define LGLCD_DEVICE_FAMILY_BW_160x43_BASIC (0x00000008) -#define LGLCD_DEVICE_FAMILY_LCDEMULATOR_G15 (0x00000008) -#define LGLCD_DEVICE_FAMILY_RAINBOW (0x00000010) -#define LGLCD_DEVICE_FAMILY_QVGA_BASIC (0x00000020) -#define LGLCD_DEVICE_FAMILY_QVGA_GAMING (0x00000040) -#define LGLCD_DEVICE_FAMILY_GAMEBOARD_G13 (0x00000080) -#define LGLCD_DEVICE_FAMILY_KEYBOARD_G510 (0x00000100) -#define LGLCD_DEVICE_FAMILY_OTHER (0x80000000) - -// Combinations of device families (device clans?) -#define LGLCD_DEVICE_FAMILY_ALL_BW_160x43 (LGLCD_DEVICE_FAMILY_BW_160x43_GAMING \ - | LGLCD_DEVICE_FAMILY_BW_160x43_AUDIO \ - | LGLCD_DEVICE_FAMILY_JACKBOX \ - | LGLCD_DEVICE_FAMILY_BW_160x43_BASIC \ - | LGLCD_DEVICE_FAMILY_RAINBOW \ - | LGLCD_DEVICE_FAMILY_GAMEBOARD_G13 \ - | LGLCD_DEVICE_FAMILY_KEYBOARD_G510) - -#define LGLCD_DEVICE_FAMILY_ALL_QVGA (LGLCD_DEVICE_FAMILY_QVGA_BASIC \ - | LGLCD_DEVICE_FAMILY_QVGA_GAMING) - -#define LGLCD_DEVICE_FAMILY_ALL (LGLCD_DEVICE_FAMILY_ALL_BW_160x43 \ - | LGLCD_DEVICE_FAMILY_ALL_QVGA) - - -// Capabilities of applets connecting to LCD Manager. -#define LGLCD_APPLET_CAP_BASIC (0x00000000) -#define LGLCD_APPLET_CAP_BW (0x00000001) -#define LGLCD_APPLET_CAP_QVGA (0x00000002) - -// Notifications sent by LCD Manager to applets connected to it. -#define LGLCD_NOTIFICATION_DEVICE_ARRIVAL (0x00000001) -#define LGLCD_NOTIFICATION_DEVICE_REMOVAL (0x00000002) -#define LGLCD_NOTIFICATION_CLOSE_CONNECTION (0x00000003) -#define LGLCD_NOTIFICATION_APPLET_DISABLED (0x00000004) -#define LGLCD_NOTIFICATION_APPLET_ENABLED (0x00000005) -#define LGLCD_NOTIFICATION_TERMINATE_APPLET (0x00000006) - -// Device types used in notifications -#define LGLCD_DEVICE_BW (0x00000001) -#define LGLCD_DEVICE_QVGA (0x00000002) - -//************************************************************************ -// Callbacks -//************************************************************************ - -// Callback used to notify client of soft button change -typedef DWORD (WINAPI *lgLcdOnSoftButtonsCB)(IN int device, - IN DWORD dwButtons, - IN const PVOID pContext); - -// Callback used to allow client to pop up a "configuration panel" -typedef DWORD (WINAPI *lgLcdOnConfigureCB)(IN int connection, - IN const PVOID pContext); - -// Callback used to notify client of events, such as device arrival, ... -// Arrival, removal, applet enable/disable supported as of version 3.0. -typedef DWORD (WINAPI *lgLcdOnNotificationCB)(IN int connection, - IN const PVOID pContext, - IN DWORD notificationCode, - IN DWORD notifyParm1, - IN DWORD notifyParm2, - IN DWORD notifyParm3, - IN DWORD notifyParm4); - - -//************************************************************************ -// lgLcdConfigureContext -//************************************************************************ -typedef struct -{ - // Set to NULL if not configurable - lgLcdOnConfigureCB configCallback; - PVOID configContext; -} lgLcdConfigureContext; - -//************************************************************************ -// lgLcdNotificationContext -//************************************************************************ -typedef struct -{ - // Set to NULL if not notifiable - lgLcdOnNotificationCB notificationCallback; - PVOID notifyContext; -} lgLcdNotificationContext; - -//************************************************************************ -// lgLcdConnectContext -//************************************************************************ -typedef struct -{ - // "Friendly name" display in the listing - LPCWSTR appFriendlyName; - // isPersistent determines whether this connection persists in the list - BOOL isPersistent; - // isAutostartable determines whether the client can be started by - // LCDMon - BOOL isAutostartable; - lgLcdConfigureContext onConfigure; - // --> Connection handle - int connection; -} lgLcdConnectContextW; - -typedef struct -{ - // "Friendly name" display in the listing - LPCSTR appFriendlyName; - // isPersistent determines whether this connection persists in the list - BOOL isPersistent; - // isAutostartable determines whether the client can be started by - // LCDMon - BOOL isAutostartable; - lgLcdConfigureContext onConfigure; - // --> Connection handle - int connection; -} lgLcdConnectContextA; - -//************************************************************************ -// lgLcdConnectContextEx -//************************************************************************ -typedef struct -{ - // "Friendly name" display in the listing - LPCWSTR appFriendlyName; - // isPersistent determines whether this connection persists in the list - BOOL isPersistent; - // isAutostartable determines whether the client can be started by - // LCDMon - BOOL isAutostartable; - lgLcdConfigureContext onConfigure; - // --> Connection handle - int connection; - // New additions added in 1.03 revision - DWORD dwAppletCapabilitiesSupported; // Or'd combination of LGLCD_APPLET_CAP_... defines - DWORD dwReserved1; - lgLcdNotificationContext onNotify; -} lgLcdConnectContextExW; - -typedef struct -{ - // "Friendly name" display in the listing - LPCSTR appFriendlyName; - // isPersistent determines whether this connection persists in the list - BOOL isPersistent; - // isAutostartable determines whether the client can be started by - // LCDMon - BOOL isAutostartable; - lgLcdConfigureContext onConfigure; - // --> Connection handle - int connection; - // New additions added in 1.03 revision - DWORD dwAppletCapabilitiesSupported; // Or'd combination of LGLCD_APPLET_CAP_... defines - DWORD dwReserved1; - lgLcdNotificationContext onNotify; -} lgLcdConnectContextExA; - -#ifdef UNICODE -typedef lgLcdConnectContextW lgLcdConnectContext; -typedef lgLcdConnectContextExW lgLcdConnectContextEx; -#else -typedef lgLcdConnectContextA lgLcdConnectContext; -typedef lgLcdConnectContextExA lgLcdConnectContextEx; -#endif - -//************************************************************************ -// lgLcdOpenContext & lgLcdOpenByTypeContext -//************************************************************************ - -typedef struct -{ - // Set to NULL if no softbutton notifications are needed - lgLcdOnSoftButtonsCB softbuttonsChangedCallback; - PVOID softbuttonsChangedContext; -} lgLcdSoftbuttonsChangedContext; - -typedef struct -{ - int connection; - // Device index to open - int index; - lgLcdSoftbuttonsChangedContext onSoftbuttonsChanged; - // --> Device handle - int device; -} lgLcdOpenContext; - -typedef struct -{ - int connection; - // Device type to open (either LGLCD_DEVICE_BW or LGLCD_DEVICE_QVGA) - int deviceType; - lgLcdSoftbuttonsChangedContext onSoftbuttonsChanged; - // --> Device handle - int device; -} lgLcdOpenByTypeContext; - - -//************************************************************************ -// Prototypes -//************************************************************************ - -// Initialize the library by calling this function. -DWORD WINAPI lgLcdInit(void); - -// Must be called to release the library and free all allocated structures. -DWORD WINAPI lgLcdDeInit(void); - -// Connect as a client to the LCD subsystem. Provide name to be -// displayed for user when viewing the user interface of the LCD module, -// as well as a configuration callback and context, and a flag that states -// whether this client is startable by LCDMon -DWORD WINAPI lgLcdConnectW(IN OUT lgLcdConnectContextW *ctx); -DWORD WINAPI lgLcdConnectA(IN OUT lgLcdConnectContextA *ctx); -DWORD WINAPI lgLcdConnectExW(IN OUT lgLcdConnectContextExW *ctx); -DWORD WINAPI lgLcdConnectExA(IN OUT lgLcdConnectContextExA *ctx); -#ifdef UNICODE -#define lgLcdConnect lgLcdConnectW -#define lgLcdConnectEx lgLcdConnectExW -#else -#define lgLcdConnect lgLcdConnectA -#define lgLcdConnectEx lgLcdConnectExA -#endif // !UNICODE - -// Must be called to release the connection and free all allocated resources -DWORD WINAPI lgLcdDisconnect(int connection); - -// New additions added in 1.03 revision of API. Call this method to setup which device families the applet -// is interested in. After this call, the applet can use lgLcdEnumerateEx to determine -// if a device from the device family wanted is found. -DWORD WINAPI lgLcdSetDeviceFamiliesToUse(IN int connection, - DWORD dwDeviceFamiliesSupported, // Or'd combination of LGLCD_DEVICE_FAMILY_... defines - DWORD dwReserved1); - -// To determine all connected LCD devices supported by this library, and -// their capabilities. Start with index 0, and increment by one, until -// the library returns an error (WHICH?). -DWORD WINAPI lgLcdEnumerate(IN int connection, IN int index, - OUT lgLcdDeviceDesc *description); - -// To determine all connected LCD devices supported by this library, and -// their capabilities. Start with 0, and increment by one, until -// the library returns an error (WHICH?). -DWORD WINAPI lgLcdEnumerateExW(IN int connection, IN int index, - OUT lgLcdDeviceDescExW *description); -DWORD WINAPI lgLcdEnumerateExA(IN int connection, IN int index, - OUT lgLcdDeviceDescExA *description); -#ifdef UNICODE -#define lgLcdEnumerateEx lgLcdEnumerateExW -#else -#define lgLcdEnumerateEx lgLcdEnumerateExA -#endif // !UNICODE - -// Opens the LCD at position=index. Library sets the device parameter to -// its internal reference to the device. Calling application provides the -// device handle in all calls that access the LCD. -DWORD WINAPI lgLcdOpen(IN OUT lgLcdOpenContext *ctx); - -// Opens an LCD of the specified type. If no such device is available, returns -// an error. -DWORD WINAPI lgLcdOpenByType(IN OUT lgLcdOpenByTypeContext *ctx); - -// Closes the LCD. Must be paired with lgLcdOpen()/lgLcdOpenByType(). -DWORD WINAPI lgLcdClose(IN int device); - -// Reads the state of the soft buttons for the device. -DWORD WINAPI lgLcdReadSoftButtons(IN int device, OUT DWORD *buttons); - -// Provides a bitmap to be displayed on the LCD. The priority field -// further describes the way in which the bitmap is to be applied. -DWORD WINAPI lgLcdUpdateBitmap(IN int device, - IN const lgLcdBitmapHeader *bitmap, - IN DWORD priority); - -// Sets the calling application as the shown application on the LCD, and stops -// any type of rotation among other applications on the LCD. -DWORD WINAPI lgLcdSetAsLCDForegroundApp(IN int device, IN int foregroundYesNoFlag); - -// These API calls are being deprecated. Consider using lgLcdOpenByType() and -// device arrival/removal notifications instead. -#pragma deprecated(lgLcdEnumerate,lgLcdEnumerateExA,lgLcdEnumerateExW,lgLcdOpen) - - -#pragma pack(pop) - -#ifdef __cplusplus -} -#endif - -#endif // _LGLCD_H_INCLUDED_ - -//** end of lglcd.h *************************************************** +/* + + lglcd.h + + library definition for lglcd.a + part of lglcd for Microsoft(R) Windows(R) + + The Logitech LCD SDK, including all acompanying documentation, + is protected by intellectual property laws. All use of the Logitech + LCD SDK is subject to the License Agreement found in the + "ReadMe License Agreement" file and in the Reference Manual. All rights + not expressly granted by Logitech are reserved. + + + 01/14/2005 1.00 initial draft + 02/23/2005 1.01 added callbacks, implemented changes as discussed + 02/08/2006 1.02 added call to set foreground, sync update with confirmation + 05/29/2006 1.03 Added device family feature + 12/03/2007 3.00 Added support for color devices and partial event notifications (arrival and removal) + 10/03/2008 3.01 Added more event notifications + 10/27/2008 3.01 Deprecated enumeration and index-based open; Applets should use lgLcdOpenByType() (and + possibly notifications) + +*/ + +#ifndef _LGLCD_H_INCLUDED_ +#define _LGLCD_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(push, 8) + +//// Definitions + +// Invalid handle definitions +#define LGLCD_INVALID_CONNECTION (-1) +#define LGLCD_INVALID_DEVICE (-1) + + +// Common Soft-Buttons available through the SDK +#define LGLCDBUTTON_LEFT (0x00000100) +#define LGLCDBUTTON_RIGHT (0x00000200) +#define LGLCDBUTTON_OK (0x00000400) +#define LGLCDBUTTON_CANCEL (0x00000800) +#define LGLCDBUTTON_UP (0x00001000) +#define LGLCDBUTTON_DOWN (0x00002000) +#define LGLCDBUTTON_MENU (0x00004000) + +// Soft-Button masks. Kept for backwards compatibility +#define LGLCDBUTTON_BUTTON0 (0x00000001) +#define LGLCDBUTTON_BUTTON1 (0x00000002) +#define LGLCDBUTTON_BUTTON2 (0x00000004) +#define LGLCDBUTTON_BUTTON3 (0x00000008) +#define LGLCDBUTTON_BUTTON4 (0x00000010) +#define LGLCDBUTTON_BUTTON5 (0x00000020) +#define LGLCDBUTTON_BUTTON6 (0x00000040) +#define LGLCDBUTTON_BUTTON7 (0x00000080) + +//************************************************************************ +// lgLcdDeviceDesc +//************************************************************************ +typedef struct +{ + DWORD Width; + DWORD Height; + DWORD Bpp; + DWORD NumSoftButtons; +} lgLcdDeviceDesc; + + +//************************************************************************ +// lgLcdDeviceDescEx +//************************************************************************ +typedef struct +{ + DWORD deviceFamilyId; + WCHAR deviceDisplayName[MAX_PATH]; + DWORD Width; // # of pixels (horizontally) on the LCD + DWORD Height; // # of pixels (lines) on the LCD + DWORD Bpp; // # of bits per pixel (1,8,16,24,...) + DWORD NumSoftButtons; + DWORD Reserved1; + DWORD Reserved2; +} lgLcdDeviceDescExW; + +typedef struct +{ + DWORD deviceFamilyId; + CHAR deviceDisplayName[MAX_PATH]; + DWORD Width; + DWORD Height; + DWORD Bpp; + DWORD NumSoftButtons; + DWORD Reserved1; + DWORD Reserved2; +} lgLcdDeviceDescExA; + +#ifdef UNICODE +typedef lgLcdDeviceDescExW lgLcdDeviceDescEx; +#else +typedef lgLcdDeviceDescExA lgLcdDeviceDescEx; +#endif + +//************************************************************************ +// lgLcdBitmap +//************************************************************************ + +#define LGLCD_BMP_FORMAT_160x43x1 (0x00000001) +#define LGLCD_BMP_FORMAT_QVGAx32 (0x00000003) +#define LGLCD_BMP_WIDTH (160) +#define LGLCD_BMP_HEIGHT (43) +#define LGLCD_BMP_BPP (1) +#define LGLCD_BW_BMP_WIDTH (160) +#define LGLCD_BW_BMP_HEIGHT (43) +#define LGLCD_BW_BMP_BPP (1) +#define LGLCD_QVGA_BMP_WIDTH (320) +#define LGLCD_QVGA_BMP_HEIGHT (240) +#define LGLCD_QVGA_BMP_BPP (4) + +typedef struct +{ + DWORD Format; +} lgLcdBitmapHeader; + +typedef struct +{ + lgLcdBitmapHeader hdr; + BYTE pixels[LGLCD_BMP_WIDTH * LGLCD_BMP_HEIGHT * LGLCD_BMP_BPP]; +} lgLcdBitmap160x43x1; + +typedef struct +{ + lgLcdBitmapHeader hdr; // Format = LGLCD_BMP_FORMAT_QVGAx32 + BYTE pixels[LGLCD_QVGA_BMP_WIDTH * LGLCD_QVGA_BMP_HEIGHT * LGLCD_QVGA_BMP_BPP]; +} lgLcdBitmapQVGAx32; +// +// Generic bitmap for use by both color and BW applets +// +typedef union +{ + lgLcdBitmapHeader hdr; // provides easy access to the header + lgLcdBitmap160x43x1 bmp_mono; // B/W bitmap data + lgLcdBitmapQVGAx32 bmp_qvga32; // Color bitmap data +} lgLcdBitmap; + +// Priorities +#define LGLCD_PRIORITY_IDLE_NO_SHOW (0) +#define LGLCD_PRIORITY_BACKGROUND (64) +#define LGLCD_PRIORITY_NORMAL (128) +#define LGLCD_PRIORITY_ALERT (255) +#define LGLCD_SYNC_UPDATE(priority) (0x80000000 | (priority)) +#define LGLCD_SYNC_COMPLETE_WITHIN_FRAME(priority) (0xC0000000 | (priority)) +#define LGLCD_ASYNC_UPDATE(priority) (priority) + +// Foreground mode for client applications +#define LGLCD_LCD_FOREGROUND_APP_NO (0) +#define LGLCD_LCD_FOREGROUND_APP_YES (1) + +// Device family definitions +#define LGLCD_DEVICE_FAMILY_BW_160x43_GAMING (0x00000001) +#define LGLCD_DEVICE_FAMILY_KEYBOARD_G15 (0x00000001) +#define LGLCD_DEVICE_FAMILY_BW_160x43_AUDIO (0x00000002) +#define LGLCD_DEVICE_FAMILY_SPEAKERS_Z10 (0x00000002) +#define LGLCD_DEVICE_FAMILY_JACKBOX (0x00000004) +#define LGLCD_DEVICE_FAMILY_BW_160x43_BASIC (0x00000008) +#define LGLCD_DEVICE_FAMILY_LCDEMULATOR_G15 (0x00000008) +#define LGLCD_DEVICE_FAMILY_RAINBOW (0x00000010) +#define LGLCD_DEVICE_FAMILY_QVGA_BASIC (0x00000020) +#define LGLCD_DEVICE_FAMILY_QVGA_GAMING (0x00000040) +#define LGLCD_DEVICE_FAMILY_GAMEBOARD_G13 (0x00000080) +#define LGLCD_DEVICE_FAMILY_KEYBOARD_G510 (0x00000100) +#define LGLCD_DEVICE_FAMILY_OTHER (0x80000000) + +// Combinations of device families (device clans?) +#define LGLCD_DEVICE_FAMILY_ALL_BW_160x43 (LGLCD_DEVICE_FAMILY_BW_160x43_GAMING \ + | LGLCD_DEVICE_FAMILY_BW_160x43_AUDIO \ + | LGLCD_DEVICE_FAMILY_JACKBOX \ + | LGLCD_DEVICE_FAMILY_BW_160x43_BASIC \ + | LGLCD_DEVICE_FAMILY_RAINBOW \ + | LGLCD_DEVICE_FAMILY_GAMEBOARD_G13 \ + | LGLCD_DEVICE_FAMILY_KEYBOARD_G510) + +#define LGLCD_DEVICE_FAMILY_ALL_QVGA (LGLCD_DEVICE_FAMILY_QVGA_BASIC \ + | LGLCD_DEVICE_FAMILY_QVGA_GAMING) + +#define LGLCD_DEVICE_FAMILY_ALL (LGLCD_DEVICE_FAMILY_ALL_BW_160x43 \ + | LGLCD_DEVICE_FAMILY_ALL_QVGA) + + +// Capabilities of applets connecting to LCD Manager. +#define LGLCD_APPLET_CAP_BASIC (0x00000000) +#define LGLCD_APPLET_CAP_BW (0x00000001) +#define LGLCD_APPLET_CAP_QVGA (0x00000002) + +// Notifications sent by LCD Manager to applets connected to it. +#define LGLCD_NOTIFICATION_DEVICE_ARRIVAL (0x00000001) +#define LGLCD_NOTIFICATION_DEVICE_REMOVAL (0x00000002) +#define LGLCD_NOTIFICATION_CLOSE_CONNECTION (0x00000003) +#define LGLCD_NOTIFICATION_APPLET_DISABLED (0x00000004) +#define LGLCD_NOTIFICATION_APPLET_ENABLED (0x00000005) +#define LGLCD_NOTIFICATION_TERMINATE_APPLET (0x00000006) + +// Device types used in notifications +#define LGLCD_DEVICE_BW (0x00000001) +#define LGLCD_DEVICE_QVGA (0x00000002) + +//************************************************************************ +// Callbacks +//************************************************************************ + +// Callback used to notify client of soft button change +typedef DWORD (WINAPI *lgLcdOnSoftButtonsCB)(IN int device, + IN DWORD dwButtons, + IN const PVOID pContext); + +// Callback used to allow client to pop up a "configuration panel" +typedef DWORD (WINAPI *lgLcdOnConfigureCB)(IN int connection, + IN const PVOID pContext); + +// Callback used to notify client of events, such as device arrival, ... +// Arrival, removal, applet enable/disable supported as of version 3.0. +typedef DWORD (WINAPI *lgLcdOnNotificationCB)(IN int connection, + IN const PVOID pContext, + IN DWORD notificationCode, + IN DWORD notifyParm1, + IN DWORD notifyParm2, + IN DWORD notifyParm3, + IN DWORD notifyParm4); + + +//************************************************************************ +// lgLcdConfigureContext +//************************************************************************ +typedef struct +{ + // Set to NULL if not configurable + lgLcdOnConfigureCB configCallback; + PVOID configContext; +} lgLcdConfigureContext; + +//************************************************************************ +// lgLcdNotificationContext +//************************************************************************ +typedef struct +{ + // Set to NULL if not notifiable + lgLcdOnNotificationCB notificationCallback; + PVOID notifyContext; +} lgLcdNotificationContext; + +//************************************************************************ +// lgLcdConnectContext +//************************************************************************ +typedef struct +{ + // "Friendly name" display in the listing + LPCWSTR appFriendlyName; + // isPersistent determines whether this connection persists in the list + BOOL isPersistent; + // isAutostartable determines whether the client can be started by + // LCDMon + BOOL isAutostartable; + lgLcdConfigureContext onConfigure; + // --> Connection handle + int connection; +} lgLcdConnectContextW; + +typedef struct +{ + // "Friendly name" display in the listing + LPCSTR appFriendlyName; + // isPersistent determines whether this connection persists in the list + BOOL isPersistent; + // isAutostartable determines whether the client can be started by + // LCDMon + BOOL isAutostartable; + lgLcdConfigureContext onConfigure; + // --> Connection handle + int connection; +} lgLcdConnectContextA; + +//************************************************************************ +// lgLcdConnectContextEx +//************************************************************************ +typedef struct +{ + // "Friendly name" display in the listing + LPCWSTR appFriendlyName; + // isPersistent determines whether this connection persists in the list + BOOL isPersistent; + // isAutostartable determines whether the client can be started by + // LCDMon + BOOL isAutostartable; + lgLcdConfigureContext onConfigure; + // --> Connection handle + int connection; + // New additions added in 1.03 revision + DWORD dwAppletCapabilitiesSupported; // Or'd combination of LGLCD_APPLET_CAP_... defines + DWORD dwReserved1; + lgLcdNotificationContext onNotify; +} lgLcdConnectContextExW; + +typedef struct +{ + // "Friendly name" display in the listing + LPCSTR appFriendlyName; + // isPersistent determines whether this connection persists in the list + BOOL isPersistent; + // isAutostartable determines whether the client can be started by + // LCDMon + BOOL isAutostartable; + lgLcdConfigureContext onConfigure; + // --> Connection handle + int connection; + // New additions added in 1.03 revision + DWORD dwAppletCapabilitiesSupported; // Or'd combination of LGLCD_APPLET_CAP_... defines + DWORD dwReserved1; + lgLcdNotificationContext onNotify; +} lgLcdConnectContextExA; + +#ifdef UNICODE +typedef lgLcdConnectContextW lgLcdConnectContext; +typedef lgLcdConnectContextExW lgLcdConnectContextEx; +#else +typedef lgLcdConnectContextA lgLcdConnectContext; +typedef lgLcdConnectContextExA lgLcdConnectContextEx; +#endif + +//************************************************************************ +// lgLcdOpenContext & lgLcdOpenByTypeContext +//************************************************************************ + +typedef struct +{ + // Set to NULL if no softbutton notifications are needed + lgLcdOnSoftButtonsCB softbuttonsChangedCallback; + PVOID softbuttonsChangedContext; +} lgLcdSoftbuttonsChangedContext; + +typedef struct +{ + int connection; + // Device index to open + int index; + lgLcdSoftbuttonsChangedContext onSoftbuttonsChanged; + // --> Device handle + int device; +} lgLcdOpenContext; + +typedef struct +{ + int connection; + // Device type to open (either LGLCD_DEVICE_BW or LGLCD_DEVICE_QVGA) + int deviceType; + lgLcdSoftbuttonsChangedContext onSoftbuttonsChanged; + // --> Device handle + int device; +} lgLcdOpenByTypeContext; + + +//************************************************************************ +// Prototypes +//************************************************************************ + +// Initialize the library by calling this function. +DWORD WINAPI lgLcdInit(void); + +// Must be called to release the library and free all allocated structures. +DWORD WINAPI lgLcdDeInit(void); + +// Connect as a client to the LCD subsystem. Provide name to be +// displayed for user when viewing the user interface of the LCD module, +// as well as a configuration callback and context, and a flag that states +// whether this client is startable by LCDMon +DWORD WINAPI lgLcdConnectW(IN OUT lgLcdConnectContextW *ctx); +DWORD WINAPI lgLcdConnectA(IN OUT lgLcdConnectContextA *ctx); +DWORD WINAPI lgLcdConnectExW(IN OUT lgLcdConnectContextExW *ctx); +DWORD WINAPI lgLcdConnectExA(IN OUT lgLcdConnectContextExA *ctx); +#ifdef UNICODE +#define lgLcdConnect lgLcdConnectW +#define lgLcdConnectEx lgLcdConnectExW +#else +#define lgLcdConnect lgLcdConnectA +#define lgLcdConnectEx lgLcdConnectExA +#endif // !UNICODE + +// Must be called to release the connection and free all allocated resources +DWORD WINAPI lgLcdDisconnect(int connection); + +// New additions added in 1.03 revision of API. Call this method to setup which device families the applet +// is interested in. After this call, the applet can use lgLcdEnumerateEx to determine +// if a device from the device family wanted is found. +DWORD WINAPI lgLcdSetDeviceFamiliesToUse(IN int connection, + DWORD dwDeviceFamiliesSupported, // Or'd combination of LGLCD_DEVICE_FAMILY_... defines + DWORD dwReserved1); + +// To determine all connected LCD devices supported by this library, and +// their capabilities. Start with index 0, and increment by one, until +// the library returns an error (WHICH?). +DWORD WINAPI lgLcdEnumerate(IN int connection, IN int index, + OUT lgLcdDeviceDesc *description); + +// To determine all connected LCD devices supported by this library, and +// their capabilities. Start with 0, and increment by one, until +// the library returns an error (WHICH?). +DWORD WINAPI lgLcdEnumerateExW(IN int connection, IN int index, + OUT lgLcdDeviceDescExW *description); +DWORD WINAPI lgLcdEnumerateExA(IN int connection, IN int index, + OUT lgLcdDeviceDescExA *description); +#ifdef UNICODE +#define lgLcdEnumerateEx lgLcdEnumerateExW +#else +#define lgLcdEnumerateEx lgLcdEnumerateExA +#endif // !UNICODE + +// Opens the LCD at position=index. Library sets the device parameter to +// its internal reference to the device. Calling application provides the +// device handle in all calls that access the LCD. +DWORD WINAPI lgLcdOpen(IN OUT lgLcdOpenContext *ctx); + +// Opens an LCD of the specified type. If no such device is available, returns +// an error. +DWORD WINAPI lgLcdOpenByType(IN OUT lgLcdOpenByTypeContext *ctx); + +// Closes the LCD. Must be paired with lgLcdOpen()/lgLcdOpenByType(). +DWORD WINAPI lgLcdClose(IN int device); + +// Reads the state of the soft buttons for the device. +DWORD WINAPI lgLcdReadSoftButtons(IN int device, OUT DWORD *buttons); + +// Provides a bitmap to be displayed on the LCD. The priority field +// further describes the way in which the bitmap is to be applied. +DWORD WINAPI lgLcdUpdateBitmap(IN int device, + IN const lgLcdBitmapHeader *bitmap, + IN DWORD priority); + +// Sets the calling application as the shown application on the LCD, and stops +// any type of rotation among other applications on the LCD. +DWORD WINAPI lgLcdSetAsLCDForegroundApp(IN int device, IN int foregroundYesNoFlag); + +// These API calls are being deprecated. Consider using lgLcdOpenByType() and +// device arrival/removal notifications instead. +#pragma deprecated(lgLcdEnumerate,lgLcdEnumerateExA,lgLcdEnumerateExW,lgLcdOpen) + + +#pragma pack(pop) + +#ifdef __cplusplus +} +#endif + +#endif // _LGLCD_H_INCLUDED_ + +//** end of lglcd.h *************************************************** diff --git a/include/moreuuids.h b/include/moreuuids.h index a8a25fed901..51f5d08ad11 100644 --- a/include/moreuuids.h +++ b/include/moreuuids.h @@ -1,1675 +1,1675 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#define WAVE_FORMAT_DOLBY_AC3 0x2000 -// {00002000-0000-0010-8000-00aa00389b71} -DEFINE_GUID(MEDIASUBTYPE_WAVE_DOLBY_AC3, WAVE_FORMAT_DOLBY_AC3, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, - 0x9b, 0x71); - -#define WAVE_FORMAT_DVD_DTS 0x2001 -// {00002001-0000-0010-8000-00aa00389b71} -DEFINE_GUID(MEDIASUBTYPE_WAVE_DTS, WAVE_FORMAT_DVD_DTS, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// Be compatible with 3ivx -#define WAVE_FORMAT_AAC 0x00FF -// {000000FF-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_AAC, WAVE_FORMAT_AAC, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_LATM_AAC 0x01FF -// {000001FF-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_LATM_AAC, WAVE_FORMAT_LATM_AAC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -// ... and also compatible with nero -// btw, older nero parsers use a lower-case fourcc, newer upper-case (why can't it just offer both?) -// {4134504D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_MP4A, 0x4134504D, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {6134706D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_mp4a, 0x6134706D, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_MP3 0x0055 -// 00000055-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MP3, WAVE_FORMAT_MP3, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_FLAC 0xF1AC -// 0000F1AC-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FLAC, WAVE_FORMAT_FLAC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {1541C5C0-CDDF-477d-BC0A-86F8AE7F8354} -DEFINE_GUID(MEDIASUBTYPE_FLAC_FRAMED, 0x1541c5c0, 0xcddf, 0x477d, 0xbc, 0xa, 0x86, 0xf8, 0xae, 0x7f, 0x83, 0x54); - -#define WAVE_FORMAT_TTA1 0x77A1 -// {000077A1-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_TTA1, WAVE_FORMAT_TTA1, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_WAVPACK4 0x5756 -// {00005756-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_WAVPACK4, WAVE_FORMAT_WAVPACK4, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_AMR, 0x000000FE, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -// {726D6173-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_SAMR, 0x726D6173, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VP70, 0x30375056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VP80, 0x30385056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VP90, 0x30395056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_AV01, 0x31305641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_IMA4, 0x34616D69, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); -// {34616D69-0000-0010-8000-00AA00389B71} - -DEFINE_GUID(MEDIASUBTYPE_SAWB, 0x62776173, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {DA5B82EE-6BD2-426f-BF1E-30112DA78AE1} -DEFINE_GUID(MEDIASUBTYPE_SVCD_SUBPICTURE, 0xda5b82ee, 0x6bd2, 0x426f, 0xbf, 0x1e, 0x30, 0x11, 0x2d, 0xa7, 0x8a, 0xe1); - -// {7B57308F-5154-4c36-B903-52FE76E184FC} -DEFINE_GUID(MEDIASUBTYPE_CVD_SUBPICTURE, 0x7b57308f, 0x5154, 0x4c36, 0xb9, 0x3, 0x52, 0xfe, 0x76, 0xe1, 0x84, 0xfc); - -// {0E3A2342-F6E2-4c91-BDAE-87C71EAD0D63} -DEFINE_GUID(MEDIASUBTYPE_MPEG2_PVA, 0xe3a2342, 0xf6e2, 0x4c91, 0xbd, 0xae, 0x87, 0xc7, 0x1e, 0xad, 0xd, 0x63); - -// {6B6D0800-9ADA-11d0-A520-00A0D10129C0} -DEFINE_GUID(CLSID_NetShowSource, 0x6b6d0800, 0x9ada, 0x11d0, 0xa5, 0x20, 0x0, 0xa0, 0xd1, 0x1, 0x29, 0xc0); - -// DirectShowMedia - -// {5E9C9EE0-2E4A-4f22-9906-7BBBB75AA2B6} -DEFINE_GUID(MEDIASUBTYPE_DirectShowMedia, 0x5e9c9ee0, 0x2e4a, 0x4f22, 0x99, 0x6, 0x7b, 0xbb, 0xb7, 0x5a, 0xa2, 0xb6); - -// Dirac - -// {A29DA00F-A22B-40ea-98DE-2F7FECADA5DE} -DEFINE_GUID(MEDIASUBTYPE_Dirac, 0xa29da00f, 0xa22b, 0x40ea, 0x98, 0xde, 0x2f, 0x7f, 0xec, 0xad, 0xa5, 0xde); - -// {64726376-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_DiracVideo, 0x64726376, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {D2667A7E-4055-4244-A65F-DDDDF2B74BD7} -DEFINE_GUID(FORMAT_DiracVideoInfo, 0xd2667a7e, 0x4055, 0x4244, 0xa6, 0x5f, 0xdd, 0xdd, 0xf2, 0xb7, 0x4b, 0xd7); - -// {63617264-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_DRAC, 0x63617264, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -struct DIRACINFOHEADER -{ - VIDEOINFOHEADER2 hdr; - DWORD cbSequenceHeader; - DWORD dwSequenceHeader[1]; -}; - -// MP4 - -// {08E22ADA-B715-45ed-9D20-7B87750301D4} -DEFINE_GUID(MEDIASUBTYPE_MP4, 0x8e22ada, 0xb715, 0x45ed, 0x9d, 0x20, 0x7b, 0x87, 0x75, 0x3, 0x1, 0xd4); - -// FLV - -// {F2FAC0F1-3852-4670-AAC0-9051D400AC54} -DEFINE_GUID(MEDIASUBTYPE_FLV, 0xf2fac0f1, 0x3852, 0x4670, 0xaa, 0xc0, 0x90, 0x51, 0xd4, 0x0, 0xac, 0x54); - -// 31564C46-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FLV1, 0x31564C46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31766C66-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_flv1, 0x31766C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34564C46-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FLV4, 0x34564C46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34766C66-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_flv4, 0x34766C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30355056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP50, 0x30355056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30357076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp50, 0x30357076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP60, 0x30365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp60, 0x30367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP61, 0x31365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp61, 0x31367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP62, 0x32365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp62, 0x32367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 41365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP6A, 0x41365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 61367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp6a, 0x61367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 46365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP6F, 0x46365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 66367076-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vp6f, 0x66367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// -// RealMedia -// - -enum -{ - WAVE_FORMAT_14_4 = 0x2002, - WAVE_FORMAT_28_8 = 0x2003, - WAVE_FORMAT_ATRC = 0x0270, // WAVE_FORMAT_SONY_SCX, - WAVE_FORMAT_COOK = 0x2004, - WAVE_FORMAT_DNET = 0x2005, - WAVE_FORMAT_RAAC = 0x2006, - WAVE_FORMAT_RACP = 0x2007, - WAVE_FORMAT_SIPR = 0x0130, // WAVE_FORMAT_SIPROLAB_ACEPLNET, -}; - -// {57428EC6-C2B2-44a2-AA9C-28F0B6A5C48E} -DEFINE_GUID(MEDIASUBTYPE_RealMedia, 0x57428ec6, 0xc2b2, 0x44a2, 0xaa, 0x9c, 0x28, 0xf0, 0xb6, 0xa5, 0xc4, 0x8e); - -// 30315652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV10, 0x30315652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30325652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV20, 0x30325652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30335652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV30, 0x30335652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30345652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV40, 0x30345652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31345652-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RV41, 0x31345652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 345f3431-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_14_4, 0x345f3431, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 385f3832-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_28_8, 0x385f3832, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4b4f4f43-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_COOK, 0x4b4f4f43, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 54454e44-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DNET, 0x54454e44, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 52504953-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SIPR, 0x52504953, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 00000130-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SIPR_WAVE, WAVE_FORMAT_SIPR, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43414152-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RAAC, 0x43414152, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 50434152-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RACP, 0x50434152, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -#define WAVE_FORMAT_RALF mmioFOURCC('R', 'A', 'L', 'F') -DEFINE_GUID(MEDIASUBTYPE_RALF, WAVE_FORMAT_RALF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// QuickTime PCM - -// 454E4F4E-0000-0010-8000-00AA00389B71 (unsigned 8-bit) -DEFINE_GUID(MEDIASUBTYPE_PCM_NONE, 0x454E4F4E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 20776172-0000-0010-8000-00AA00389B71 (unsigned 8-bit, signed big-endian 16 bit) -DEFINE_GUID(MEDIASUBTYPE_PCM_RAW, 0x20776172, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 736f7774-0000-0010-8000-00AA00389B71 (signed 8-bit, signed big-endian 16-bit) -DEFINE_GUID(MEDIASUBTYPE_PCM_TWOS, 0x736f7774, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 74776f73-0000-0010-8000-00AA00389B71 (signed 8-bit, signed little-endian 16-bit) -DEFINE_GUID(MEDIASUBTYPE_PCM_SOWT, 0x74776f73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34326E69-0000-0010-8000-00AA00389B71 (signed big-endian int24) -DEFINE_GUID(MEDIASUBTYPE_PCM_IN24, 0x34326E69, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32336E69-0000-0010-8000-00AA00389B71 (signed big-endian int32) -DEFINE_GUID(MEDIASUBTYPE_PCM_IN32, 0x32336E69, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32336C66-0000-0010-8000-00AA00389B71 (signed big-endian float32) -DEFINE_GUID(MEDIASUBTYPE_PCM_FL32, 0x32336C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34366C66-0000-0010-8000-00AA00389B71 (signed big-endian float64) -DEFINE_GUID(MEDIASUBTYPE_PCM_FL64, 0x34366C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Reverse GUIDs for little-endian 'in24', 'in32', 'fl32', 'fl64' -// 696E3234-0000-0010-8000-00AA00389B71 (signed little-endian int24, reverse 'in24') -DEFINE_GUID(MEDIASUBTYPE_PCM_IN24_le, 0x696E3234, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); -// 696E3332-0000-0010-8000-00AA00389B71 (signed little-endian int32, reverse 'in32') -DEFINE_GUID(MEDIASUBTYPE_PCM_IN32_le, 0x696E3332, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); -// 666C3332-0000-0010-8000-00AA00389B71 (signed little-endian float32, reverse 'fl32') -DEFINE_GUID(MEDIASUBTYPE_PCM_FL32_le, 0x666C3332, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); -// 666C3634-0000-0010-8000-00AA00389B71 (signed little-endian float64, reverse 'fl64') -DEFINE_GUID(MEDIASUBTYPE_PCM_FL64_le, 0x666C3634, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// -// PS2 -// - -#define WAVE_FORMAT_PS2_PCM 0xF521 -// 0000F521-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_PS2_PCM, WAVE_FORMAT_PS2_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_PS2_ADPCM 0xF522 -// 0000F522-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_PS2_ADPCM, WAVE_FORMAT_PS2_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -#define WAVE_FORMAT_ADPCM_SWF 0x5346 -// 00005346-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ADPCM_SWF, - WAVE_FORMAT_ADPCM_SWF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 41564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ADPCM_AMV, - 0x41564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - - -struct WAVEFORMATEXPS2 : public WAVEFORMATEX -{ - DWORD dwInterleave; - - struct WAVEFORMATEXPS2() - { - memset(this, 0, sizeof(*this)); - cbSize = sizeof(WAVEFORMATEXPS2) - sizeof(WAVEFORMATEX); - } -}; - -// {4F3D3D21-6D7C-4f73-AA05-E397B5EAE0AA} -DEFINE_GUID(MEDIASUBTYPE_PS2_SUB, 0x4f3d3d21, 0x6d7c, 0x4f73, 0xaa, 0x5, 0xe3, 0x97, 0xb5, 0xea, 0xe0, 0xaa); - -// ATRAC - -// 43525441-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ATRC, 0x43525441, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 00000270-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ATRAC3, WAVE_FORMAT_SONY_SCX, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -#define WAVE_FORMAT_ATRAC3P 0xE923AABF -// E923AABF-CB58-4471-A119-FFFA01E4CE62 -DEFINE_GUID(MEDIASUBTYPE_ATRAC3P, 0xE923AABF, 0xCB58, 0x4471, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62); - -// Haali's video renderer - -// {760A8F35-97E7-479d-AAF5-DA9EFF95D751} -DEFINE_GUID(CLSID_DXR, 0x760a8f35, 0x97e7, 0x479d, 0xaa, 0xf5, 0xda, 0x9e, 0xff, 0x95, 0xd7, 0x51); - -// {E1A8B82A-32CE-4B0D-BE0D-AA68C772E423} -DEFINE_GUID(CLSID_MadVR, 0xE1A8B82A, 0x32CE, 0x4B0D, 0xBE, 0x0D, 0xAA, 0x68, 0xC7, 0x72, 0xE4, 0x23); - -// {71F080AA-8661-4093-B15E-4F6903E77D0A} -DEFINE_GUID(CLSID_MPCVR, 0x71F080AA, 0x8661, 0x4093, 0xB1, 0x5E, 0x4F, 0x69, 0x03, 0xE7, 0x7D, 0x0A); - -// {C1F400A4-3F08-11D3-9F0B-006008039E37} -DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11D3, 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); - -// {A0025E90-E45B-11D1-ABE9-00A0C905F375} -DEFINE_GUID(CLSID_OverlayMixer2, 0xA0025E90, 0xE45B, 0x11D1, 0xAB, 0xE9, 0x00, 0xA0, 0xC9, 0x05, 0xF3, 0x75); - -// -// Ogg -// - -// 9FF48807-E133-40AA-826F-9B2959E5232D -DEFINE_GUID(CLSID_MPCHCOggSplitter, 0x9FF48807, 0xE133, 0x40AA, 0x82, 0x6F, 0x9B, 0x29, 0x59, 0xE5, 0x23, 0x2D); - -// 6D3688CE-3E9D-42F4-92CA-8A11119D25CD -DEFINE_GUID(CLSID_MPCHCOggSource, 0x6D3688CE, 0x3E9D, 0x42F4, 0x92, 0xCA, 0x8A, 0x11, 0x11, 0x9D, 0x25, 0xCD); - -// f07e245f-5a1f-4d1e-8bff-dc31d84a55ab -DEFINE_GUID(CLSID_OggSplitter, 0xf07e245f, 0x5a1f, 0x4d1e, 0x8b, 0xff, 0xdc, 0x31, 0xd8, 0x4a, 0x55, 0xab); - -// {078C3DAA-9E58-4d42-9E1C-7C8EE79539C5} -DEFINE_GUID(CLSID_OggSplitPropPage, 0x78c3daa, 0x9e58, 0x4d42, 0x9e, 0x1c, 0x7c, 0x8e, 0xe7, 0x95, 0x39, 0xc5); - -// 8cae96b7-85b1-4605-b23c-17ff5262b296 -DEFINE_GUID(CLSID_OggMux, 0x8cae96b7, 0x85b1, 0x4605, 0xb2, 0x3c, 0x17, 0xff, 0x52, 0x62, 0xb2, 0x96); - -// {AB97AFC3-D08E-4e2d-98E0-AEE6D4634BA4} -DEFINE_GUID(CLSID_OggMuxPropPage, 0xab97afc3, 0xd08e, 0x4e2d, 0x98, 0xe0, 0xae, 0xe6, 0xd4, 0x63, 0x4b, 0xa4); - -// {889EF574-0656-4B52-9091-072E52BB1B80} -DEFINE_GUID(CLSID_VorbisEnc, 0x889ef574, 0x0656, 0x4b52, 0x90, 0x91, 0x07, 0x2e, 0x52, 0xbb, 0x1b, 0x80); - -// {c5379125-fd36-4277-a7cd-fab469ef3a2f} -DEFINE_GUID(CLSID_VorbisEncPropPage, 0xc5379125, 0xfd36, 0x4277, 0xa7, 0xcd, 0xfa, 0xb4, 0x69, 0xef, 0x3a, 0x2f); - -// 02391f44-2767-4e6a-a484-9b47b506f3a4 -DEFINE_GUID(CLSID_VorbisDec, 0x02391f44, 0x2767, 0x4e6a, 0xa4, 0x84, 0x9b, 0x47, 0xb5, 0x06, 0xf3, 0xa4); - -// 77983549-ffda-4a88-b48f-b924e8d1f01c -DEFINE_GUID(CLSID_OggDSAboutPage, 0x77983549, 0xffda, 0x4a88, 0xb4, 0x8f, 0xb9, 0x24, 0xe8, 0xd1, 0xf0, 0x1c); - -// {D2855FA9-61A7-4db0-B979-71F297C17A04} -DEFINE_GUID(MEDIASUBTYPE_Ogg, 0xd2855fa9, 0x61a7, 0x4db0, 0xb9, 0x79, 0x71, 0xf2, 0x97, 0xc1, 0x7a, 0x4); - -// cddca2d5-6d75-4f98-840e-737bedd5c63b -DEFINE_GUID(MEDIASUBTYPE_Vorbis, 0xcddca2d5, 0x6d75, 0x4f98, 0x84, 0x0e, 0x73, 0x7b, 0xed, 0xd5, 0xc6, 0x3b); - -// 6bddfa7e-9f22-46a9-ab5e-884eff294d9f -DEFINE_GUID(FORMAT_VorbisFormat, 0x6bddfa7e, 0x9f22, 0x46a9, 0xab, 0x5e, 0x88, 0x4e, 0xff, 0x29, 0x4d, 0x9f); - -typedef struct tagVORBISFORMAT -{ - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nMinBitsPerSec; - DWORD nAvgBitsPerSec; - DWORD nMaxBitsPerSec; - float fQuality; -} VORBISFORMAT, *PVORBISFORMAT, FAR *LPVORBISFORMAT; - -// {8D2FD10B-5841-4a6b-8905-588FEC1ADED9} -DEFINE_GUID(MEDIASUBTYPE_Vorbis2, 0x8d2fd10b, 0x5841, 0x4a6b, 0x89, 0x5, 0x58, 0x8f, 0xec, 0x1a, 0xde, 0xd9); - -// {B36E107F-A938-4387-93C7-55E966757473} -DEFINE_GUID(FORMAT_VorbisFormat2, 0xb36e107f, 0xa938, 0x4387, 0x93, 0xc7, 0x55, 0xe9, 0x66, 0x75, 0x74, 0x73); - -typedef struct tagVORBISFORMAT2 -{ - DWORD Channels; - DWORD SamplesPerSec; - DWORD BitsPerSample; - DWORD HeaderSize[3]; // 0: Identification, 1: Comment, 2: Setup -} VORBISFORMAT2, *PVORBISFORMAT2, FAR *LPVORBISFORMAT2; - -// -// Matroska -// - -// {1AC0BEBD-4D2B-45ad-BCEB-F2C41C5E3788} -DEFINE_GUID(MEDIASUBTYPE_Matroska, 0x1ac0bebd, 0x4d2b, 0x45ad, 0xbc, 0xeb, 0xf2, 0xc4, 0x1c, 0x5e, 0x37, 0x88); - -// {E487EB08-6B26-4be9-9DD3-993434D313FD} -DEFINE_GUID(MEDIATYPE_Subtitle, 0xe487eb08, 0x6b26, 0x4be9, 0x9d, 0xd3, 0x99, 0x34, 0x34, 0xd3, 0x13, 0xfd); - -// {87C0B230-03A8-4fdf-8010-B27A5848200D} -DEFINE_GUID(MEDIASUBTYPE_UTF8, 0x87c0b230, 0x3a8, 0x4fdf, 0x80, 0x10, 0xb2, 0x7a, 0x58, 0x48, 0x20, 0xd); - -// {3020560F-255A-4ddc-806E-6C5CC6DCD70A} -DEFINE_GUID(MEDIASUBTYPE_SSA, 0x3020560f, 0x255a, 0x4ddc, 0x80, 0x6e, 0x6c, 0x5c, 0xc6, 0xdc, 0xd7, 0xa); - -// {326444F7-686F-47ff-A4B2-C8C96307B4C2} -DEFINE_GUID(MEDIASUBTYPE_ASS, 0x326444f7, 0x686f, 0x47ff, 0xa4, 0xb2, 0xc8, 0xc9, 0x63, 0x7, 0xb4, 0xc2); - -// {370689E7-B226-4f67-978D-F10BC1A9C6AE} -DEFINE_GUID(MEDIASUBTYPE_ASS2, 0x370689e7, 0xb226, 0x4f67, 0x97, 0x8d, 0xf1, 0xb, 0xc1, 0xa9, 0xc6, 0xae); - -// {76C421C4-DB89-42ec-936E-A9FBC1794714} -DEFINE_GUID(MEDIASUBTYPE_SSF, 0x76c421c4, 0xdb89, 0x42ec, 0x93, 0x6e, 0xa9, 0xfb, 0xc1, 0x79, 0x47, 0x14); - -// {B753B29A-0A96-45be-985F-68351D9CAB90} -DEFINE_GUID(MEDIASUBTYPE_USF, 0xb753b29a, 0xa96, 0x45be, 0x98, 0x5f, 0x68, 0x35, 0x1d, 0x9c, 0xab, 0x90); - -// {F7239E31-9599-4e43-8DD5-FBAF75CF37F1} -DEFINE_GUID(MEDIASUBTYPE_VOBSUB, 0xf7239e31, 0x9599, 0x4e43, 0x8d, 0xd5, 0xfb, 0xaf, 0x75, 0xcf, 0x37, 0xf1); - -// {A33D2F7D-96BC-4337-B23B-A8B9FBC295E9} -DEFINE_GUID(FORMAT_SubtitleInfo, 0xa33d2f7d, 0x96bc, 0x4337, 0xb2, 0x3b, 0xa8, 0xb9, 0xfb, 0xc2, 0x95, 0xe9); - -// {04EBA53E-9330-436c-9133-553EC87031DC} -DEFINE_GUID(MEDIASUBTYPE_HDMVSUB, 0x4eba53e, 0x9330, 0x436c, 0x91, 0x33, 0x55, 0x3e, 0xc8, 0x70, 0x31, 0xdc); - -// {C886D215-F485-40BB-8DB6-FADBC619A45D} -DEFINE_GUID(MEDIASUBTYPE_WEBVTT, 0xc886d215, 0xf485, 0x40bb, 0x8d, 0xb6, 0xfa, 0xdb, 0xc6, 0x19, 0xa4, 0x5d); - -#pragma pack(push, 1) -typedef struct -{ - DWORD dwOffset; - CHAR IsoLang[4]; // three letter lang code + terminating zero - WCHAR TrackName[256]; // 256 chars ought to be enough for everyone :) -} SUBTITLEINFO; -#pragma pack(pop) - -// SUBTITLEINFO structure content starting at dwOffset (also the content of CodecPrivate) -// -------------------------------------------------------------------------------------- -// -// Here the text should start with the Byte Order Mark, even though -// UTF-8 is preferred, it also helps identifying the encoding type. -// -// MEDIASUBTYPE_USF: -// -// -// -// -// -// -// ... every element excluding ... -// -// -// MEDIASUBTYPE_SSA/ASS: -// -// The file header and all sub-sections except [Events] -// -// MEDIATYPE_VOBSUB: -// -// TODO -// - -// Data description of the media samples (everything is UTF-8 encoded here) -// ------------------------------------------------------------------------ -// -// MEDIASUBTYPE_USF: -// -// The text _inside_ the .. element. -// -// Since timing is set on the sample, there is no need to put -// into the data. -// -// MEDIASUBTYPE_SSA/ASS: -// -// Comma separated values similar to the "Dialogue: ..." line with these fields: -// ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text -// -// With the exception of ReadOrder every field can be found in ASS files. The -// ReadOrder field is needed for the decoder to be able to reorder the streamed -// samples as they were placed originally in the file. -// -// If the source is only SSA, the Layer field can be left empty. -// -// MEDIATYPE_VOBSUB: -// -// Standard dvd subpic data, without the stream id at the beginning. -// - -// Matroska CodecID mappings -// ------------------------ -// -// S_TEXT/ASCII <-> MEDIATYPE_Text MEDIASUBTYPE_NULL FORMAT_None -// S_TEXT/UTF8 <-> MEDIATYPE_Subtitle MEDIASUBTYPE_UTF8 FORMAT_SubtitleInfo -// S_TEXT/SSA <-> MEDIATYPE_Subtitle MEDIASUBTYPE_SSA FORMAT_SubtitleInfo -// S_TEXT/ASS <-> MEDIATYPE_Subtitle MEDIASUBTYPE_ASS FORMAT_SubtitleInfo -// S_TEXT/USF <-> MEDIATYPE_Subtitle MEDIASUBTYPE_USF FORMAT_SubtitleInfo -// S_VOBSUB <-> MEDIATYPE_Subtitle MEDIASUBTYPE_VOBSUB FORMAT_SubtitleInfo -// S_VOBSUB/ZLIB<-> MEDIATYPE_Subtitle MEDIASUBTYPE_VOBSUB FORMAT_SubtitleInfo -// - -/* -DEFINE_GUID( MEDIATYPE_MPEG2_SECTIONS, - 0x455f176c, 0x4b06, 0x47ce, 0x9a, 0xef, 0x8c, 0xae, 0xf7, 0x3d, 0xf7, 0xb5); - -DEFINE_GUID(MEDIASUBTYPE_ATSC_SI, -0xb3c7397c, 0xd303, 0x414d, 0xb3, 0x3c, 0x4e, 0xd2, 0xc9, 0xd2, 0x97, 0x33); - -DEFINE_GUID(MEDIASUBTYPE_DVB_SI, -0xe9dd31a3, 0x221d, 0x4adb, 0x85, 0x32, 0x9a, 0xf3, 0x9, 0xc1, 0xa4, 0x8); - - -// {C892E55B-252D-42b5-A316-D997E7A5D995} -DEFINE_GUID(MEDIASUBTYPE_MPEG2DATA, -0xc892e55b, 0x252d, 0x42b5, 0xa3, 0x16, 0xd9, 0x97, 0xe7, 0xa5, 0xd9, 0x95); - -*/ - -// ASF -// {6B6D0801-9ADA-11D0-A520-00A0D10129C0} -DEFINE_GUID(MEDIASUBTYPE_ASF, - 0x6b6d0801, 0x9ada, 0x11d0, 0xa5, 0x20, 0x00, 0xa0, 0xd1, 0x01, 0x29, 0xc0); - -// H264 - -// 6F29D2AD-E130-45AA-B42F-F623AD354A90 -DEFINE_GUID(MEDIASUBTYPE_ArcsoftH264, 0x6F29D2AD, 0xE130, 0x45AA, 0xB4, 0x2F, 0xF6, 0x23, 0xAD, 0x35, 0x4A, 0x90); - -// 48535356-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VSSH, 0x48535356, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 68737376-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_vssh, 0x68737376, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43564144-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DAVC, 0x43564144, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 63766164-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_davc, 0x63766164, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43564150-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_PAVC, 0x43564150, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 63766170-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_pavc, 0x63766170, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31637661-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_avc1, 0x31637661, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31564343-0000-0010-8000-00AA00389B71 (custom H.264 FourCC used by Haali Media Splitter) -DEFINE_GUID(MEDIASUBTYPE_CCV1, 0x31564343, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 8D2D71CB-243F-45E3-B2D8-5FD7967EC09B <= Use by MediaPortal for example... -DEFINE_GUID(MEDIASUBTYPE_H264_bis, 0x8D2D71CB, 0x243F, 0x45E3, 0xB2, 0xD8, 0x5F, 0xD7, 0x96, 0x7E, 0xC0, 0x9B); - -// 676C6178-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_xalg, 0x676C6178, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 676C7661-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_avlg, 0x676C7661, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33515653-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_SVQ3, 0x33515653, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_XVID, 0x44495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_xvid, 0x64697678, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30355844-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_DX50, 0x30355844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30357864-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_dx50, 0x30357864, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIVX, 0x58564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 78766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_divx, 0x78766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 78766944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_Divx, 0x78766944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 5634504d-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_MP4V, 0x5634504d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 7634706D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_mp4v, 0x7634706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31564933-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_3IV1, 0x31564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31766933-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_3iv1, 0x31766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32564933-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_3IV2, 0x32564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32766933-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_3iv2, 0x32766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 58564933-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_3IVX, 0x58564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 78766933-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_3ivx, 0x78766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 305A4C42-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_BLZ0, 0x305A4C42, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 307A6C62-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_blz0, 0x307A6C62, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {564F4547-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_GEOV, 0x564F4547, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56344D44-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DM4V, 0x56344D44, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 76346D64-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_dm4v, 0x76346D64, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4D475844-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DXGM, 0x4D475844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 6D677864-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_dxgm, 0x6D677864, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 53444646-0000-0010-8000-00aa00389b71 -DEFINE_GUID(MEDIASUBTYPE_FFDS, 0x53444646, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 73646666-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ffds, 0x73646666, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 57465646-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FVFW, 0x57465646, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 77667666-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_fvfw, 0x77667666, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D46-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FMP4, 0x34504D46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D66-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_fmp4, 0x34706D66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34584448-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HDX4, 0x34584448, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34786468-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_hdx4, 0x34786468, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D4C-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_LMP4, 0x34504D4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D6C-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_lmp4, 0x34706D6C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4749444E-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_NDIG, 0x4749444E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 6769646E-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ndig, 0x6769646E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D52-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RMP4, 0x34504D52, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D72-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_rmp4, 0x34706D72, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D53-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SMP4, 0x34504D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D73-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_smp4, 0x34706D73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 47444553-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SEDG, 0x47444553, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 67646573-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_sedg, 0x67646573, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4D475844-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DGXM, 0x4D475844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34504D55-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_UMP4, 0x34504D55, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34706D75-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ump4, 0x34706D75, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 46315657-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_WV1F, 0x46315657, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 66317677-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_wv1f, 0x66317677, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 58495658-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_XVIX, 0x58495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 78697678-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_xvix, 0x78697678, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31515653-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SVQ1, 0x31515653, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363248-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_H263, 0x33363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363268-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_h263, 0x33363268, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363249-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_I263, 0x33363249, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363269-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_i263, 0x33363269, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31363248-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_H261, 0x31363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31363268-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_h261, 0x31363268, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_S263, 0x33363273, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33363273-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_s263, 0x33363273, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AMVV, 0x56564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 46564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AMVF, 0x46564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33585644-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVX3, 0x33585644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33787664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_dvx3, 0x33787664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 44564933-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_3IVD, 0x44564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV3, 0x33564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div3, 0x33766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 314C4F43-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_COL1, 0x314C4F43, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 316C6F63-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_col1, 0x316C6F63, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV4, 0x34564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div4, 0x34766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV5, 0x35564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div5, 0x35766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 36564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV6, 0x36564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 36766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div6, 0x36766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31345041-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AP41, 0x31345041, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31347061-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ap41, 0x31347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3347504D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MPG3, 0x3347504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3367706D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_mpg3, 0x3367706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV2, 0x32564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div2, 0x32766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31564944-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DIV1, 0x31564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31766964-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_div1, 0x31766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3134504D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MP41, 0x3134504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3134706D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_mp41, 0x3134706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4F454854-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_THEORA, 0x4F454854, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 6F656874-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_theora, 0x6F656874, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 63637374-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_TSCC, 0x63637374, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32637374-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_TSC2, 0x32637374, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30355649-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IV50, 0x30355649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31345649-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IV41, 0x31345649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31335649-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IV31, 0x31335649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32335649-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IV32, 0x32335649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 48564443-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CDVH, 0x48564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43564443-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CDVC, 0x43564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35564443-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CDV5, 0x35564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35325644-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DV25, 0x35325644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 30355644-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DV50, 0x30355644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70637664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVCP, 0x70637664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70707664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVPP, 0x70707664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70357664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DV5P, 0x70357664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 6E357664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DV5N, 0x6E357664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70637664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVC, 0x20637664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 31687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH1, 0x31687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 32687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH2, 0x32687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 33687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH3, 0x33687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 34687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH4, 0x34687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 35687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH5, 0x35687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 36687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVH6, 0x36687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 71687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVHQ, 0x71687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 70687664-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DVHP, 0x70687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 76645641-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVdv, 0x76645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 31645641-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVd1, 0x31645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 31535046-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_FPS1, 0x31535046, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 55594648-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HuffYUV, 0x55594648, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 5347414C-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_Lagarith, 0x5347414C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 64697663-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CVID, 0x64697663, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 694B4942-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_BIKI, 0x694B4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 624B4942-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_BIKB, 0x624B4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 664b4942-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_BIKf, 0x664b4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -DEFINE_GUID(FORMAT_RLTheora, 0xe69b30d1, 0x7d65, 0x4166, 0xb9, 0x90, 0x10, 0x3d, 0xa8, 0xc9, 0x11, 0xe3); - -// 62706A6D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MJPGB, 0x62706A6D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 30365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP30, 0x30335056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30365056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP31, 0x31335056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 324B4D53-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SMK2, 0x324B4D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 344B4D53-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SMK4, 0x344B4D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 44435343-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CSCD, 0x44435343, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 47455051-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_QPEG, 0x47455051, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 302E3151-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_QP10, 0x302E3151, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 312E3151-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_QP11, 0x312E3151, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 485A534D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MSZH, 0x485A534D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 42494C5A-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ZLIB, 0x42494C5A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 20676E70-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_PNG, 0x20676E70, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_TIFF, MAKEFOURCC('T', 'I', 'F', 'F'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_BMP, MAKEFOURCC('B', 'M', 'P', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_GIF, MAKEFOURCC('G', 'I', 'F', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_TGA, MAKEFOURCC('T', 'G', 'A', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_WEBP, MAKEFOURCC('W', 'E', 'B', 'P'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_FSV1, 0x31565346, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_CRAM, MAKEFOURCC('C', 'R', 'A', 'M'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_MSVC, MAKEFOURCC('M', 'S', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_WHAM, MAKEFOURCC('W', 'H', 'A', 'M'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_8BPS, MAKEFOURCC('8', 'B', 'P', 'S'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_LOCO, MAKEFOURCC('L', 'O', 'C', 'O'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ZMBV, MAKEFOURCC('Z', 'M', 'B', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VCR1, MAKEFOURCC('V', 'C', 'R', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_AASC, MAKEFOURCC('A', 'A', 'S', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_SNOW, MAKEFOURCC('S', 'N', 'O', 'W'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_FFV1, MAKEFOURCC('F', 'F', 'V', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_FFVH, MAKEFOURCC('F', 'F', 'V', 'H'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_v410, MAKEFOURCC('v', '4', '1', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_VMNC, MAKEFOURCC('V', 'M', 'n', 'c'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// {3267706D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_MPG2, 0x3267706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Apple ProRes -DEFINE_GUID(MEDIASUBTYPE_apch, 0x68637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_apcn, 0x6e637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_apcs, 0x73637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_apco, 0x6f637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ap4h, 0x68347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ap4x, 0x78347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Apple ICOD -DEFINE_GUID(MEDIASUBTYPE_icod, 0x646F6369, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Ut Video -DEFINE_GUID(MEDIASUBTYPE_ULRA, MAKEFOURCC('U', 'L', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULRG, MAKEFOURCC('U', 'L', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULY0, MAKEFOURCC('U', 'L', 'Y', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULY2, MAKEFOURCC('U', 'L', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULY4, MAKEFOURCC('U', 'L', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UQY2, MAKEFOURCC('U', 'Q', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UQRG, MAKEFOURCC('U', 'Q', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UQRA, MAKEFOURCC('U', 'Q', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULH0, MAKEFOURCC('U', 'L', 'H', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULH2, MAKEFOURCC('U', 'L', 'H', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ULH4, MAKEFOURCC('U', 'L', 'H', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMY2, MAKEFOURCC('U', 'M', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMH2, MAKEFOURCC('U', 'M', 'H', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMY4, MAKEFOURCC('U', 'M', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMH4, MAKEFOURCC('U', 'M', 'H', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMRG, MAKEFOURCC('U', 'M', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_UMRA, MAKEFOURCC('U', 'M', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// G2M -DEFINE_GUID(MEDIASUBTYPE_G2M2, MAKEFOURCC('G', '2', 'M', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_G2M3, MAKEFOURCC('G', '2', 'M', '3'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_G2M4, MAKEFOURCC('G', '2', 'M', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_G2M5, MAKEFOURCC('G', '2', 'M', '5'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// CFHD -DEFINE_GUID(MEDIASUBTYPE_CFHD, MAKEFOURCC('C', 'F', 'H', 'D'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// MagicYUV -DEFINE_GUID(MEDIASUBTYPE_MAGY, MAKEFOURCC('M', 'A', 'G', 'Y'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8RG, MAKEFOURCC('M', '8', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8RA, MAKEFOURCC('M', '8', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8G0, MAKEFOURCC('M', '8', 'G', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8Y0, MAKEFOURCC('M', '8', 'Y', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8Y2, MAKEFOURCC('M', '8', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8Y4, MAKEFOURCC('M', '8', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -DEFINE_GUID(MEDIASUBTYPE_M8YA, MAKEFOURCC('M', '8', 'Y', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// MagicYUV -DEFINE_GUID(MEDIASUBTYPE_FICV, MAKEFOURCC('F', 'I', 'C', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// DNxHD -// {6E645641-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_AVdn, 0x6E645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// DNxHR -// {68645641-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_AVdh, 0x68645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// JPEG2000 -// {32706A6D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_mjp2, 0x32706A6D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {43324A4D-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_MJ2C, 0x43324A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {43324A4C-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_LJ2C, 0x43324A4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {4B324A4C-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_LJ2K, 0x4B324A4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {324A5049-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_IPJ2, 0x324A5049, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {D80FA03C-35C1-4FA1-8C8E-375C8667166E} -DEFINE_GUID(MEDIASUBTYPE_LAV_RAWVIDEO, 0xd80fa03c, 0x35c1, 0x4fa1, 0x8c, 0x8e, 0x37, 0x5c, 0x86, 0x67, 0x16, 0x6e); - -// {434C4641-0000-0010-8000-00AA00389B71} -DEFINE_GUID(MEDIASUBTYPE_FLIC, 0x434C4641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// {} -DEFINE_GUID(MEDIASUBTYPE_THPV, MAKEFOURCC('T', 'H', 'P', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -DEFINE_GUID(MEDIASUBTYPE_ROQV, MAKEFOURCC('R', 'o', 'Q', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// 31435648-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HVC1, 0x31435648, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43564548-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HEVC, 0x43564548, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30314D48-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HM10, 0x30314D48, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35363248-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_H265, 0x35363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// VVC ("VVC1") -DEFINE_GUID(MEDIASUBTYPE_VVC1, MAKEFOURCC('V', 'V', 'C', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, - 0x71); - -// Full MVC -DEFINE_GUID(MEDIASUBTYPE_AMVC, MAKEFOURCC('A', 'M', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -// Full MVC in mp4-form -DEFINE_GUID(MEDIASUBTYPE_MVC1, MAKEFOURCC('M', 'V', 'C', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -// Subset MVC -DEFINE_GUID(MEDIASUBTYPE_EMVC, MAKEFOURCC('E', 'M', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, - 0x71); - -// 4B435544-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DUCK, 0x4B435544, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30324D54-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_TM20, 0x30324D54, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 20636D73-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_smc, 0x20636D73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4C584956-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VIXL, 0x4C584956, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 49544C55-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ULTI, 0x49544C55, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31564E57-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_WNV1, 0x31564E57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 76757963-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_CYUV, 0x76757963, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31565341-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVS1, 0x31565341, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 32565341-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVS2, 0x32565341, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31325452-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_RT21, 0x31325452, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 6E525641-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_AVRn, 0x6E525641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 47504a4c-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_LJPG, 0x47504a4c, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4C47504A-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_JPGL, 0x4C47504A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 534c4a4d-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MJLS, 0x534c4a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 41504a4d-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MJPA, 0x41504a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 42504a4d-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MJPB, 0x42504a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 58355053-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SP5X, 0x58355053, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 31706148-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_Hap1, 0x31706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 35706148-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_Hap5, 0x35706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 59706148-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_HapY, 0x59706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 33445844-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DXD3, 0x33445844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 49445844-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_DXDI, 0x49445844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 574D5632-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_2VMW, 0x574D5632, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 56334357-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_WC3V, 0x56334357, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 4345444D-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MDEC, 0x4345444D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 564D5834-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_4XMV, 0x564D5834, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 43425241-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ARBC, 0x43425241, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 30345056-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VP40, 0x30345056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 34355053-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_SP54, 0x34355053, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// 3156474B-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_KGV1, 0x3156474B, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -// Audio codecs - -// 41564D41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IMA_AMV, 0x41564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 4C4C454E-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_NELLYMOSER, 0x4C4C454E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000006-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ALAW, WAVE_FORMAT_ALAW, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000007-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MULAW, WAVE_FORMAT_MULAW, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000031-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_MSGSM610, WAVE_FORMAT_GSM610, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000002-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ADPCM_MS, WAVE_FORMAT_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000022-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_TRUESPEECH, WAVE_FORMAT_DSPGROUP_TRUESPEECH, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, - 0x38, 0x9b, 0x71); - -// 00000075-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VOXWARE_RT29, WAVE_FORMAT_VOXWARE_RT29, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, - 0x9b, 0x71); - -// 324D4451-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_QDM2, 0x324D4451, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 63616C61-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ALAC, 0x63616C61, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// B82196E9-1B3F-4796-A636-46239087B38E dsfTAKsource specific -DEFINE_GUID(MEDIASUBTYPE_TAK, 0xB82196E9, 0x1B3F, 0x4796, 0xA6, 0x36, 0x46, 0x23, 0x90, 0x87, 0xB3, 0x8E); - -// 20534C41-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_ALS, 0x20534C41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 0000729A-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_729A, 0x0000729A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000133-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_G729, 0x00000133, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 36323767-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_G726, 0x36323767, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000401-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IMC, 0x00000401, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 0000011-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_IMA_WAV, WAVE_FORMAT_IMA_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {A23EB7FC-510B-466F-9FBF-5F878F69347C} LAVF/LAVC specific -DEFINE_GUID(MEDIASUBTYPE_BD_LPCM_AUDIO, 0xa23eb7fc, 0x510b, 0x466f, 0x9f, 0xbf, 0x5f, 0x87, 0x8f, 0x69, 0x34, 0x7c); - -// {53544441-0000-0010-8000-00AA00389B71} AAC-ADTS LAVF/LAVC specific -#define WAVE_FORMAT_AAC_ADTS mmioFOURCC('A', 'D', 'T', 'S') -DEFINE_GUID(MEDIASUBTYPE_AAC_ADTS, WAVE_FORMAT_AAC_ADTS, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {33534541-0000-0010-8000-00AA00389B71} S302M AES3 -#define WAVE_FORMAT_S302M_AES3 mmioFOURCC('A', 'E', 'S', '3') -DEFINE_GUID(MEDIASUBTYPE_AES3, WAVE_FORMAT_S302M_AES3, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// {949F97FD-56F6-4527-B4AE-DDEB375AB80F} Mpc-hc specific ! -DEFINE_GUID(MEDIASUBTYPE_HDMV_LPCM_AUDIO, 0x949f97fd, 0x56f6, 0x4527, 0xb4, 0xae, 0xdd, 0xeb, 0x37, 0x5a, 0xb8, 0xf); - -#define WAVE_FORMAT_MLP mmioFOURCC('M', 'L', 'P', ' ') -DEFINE_GUID(MEDIASUBTYPE_MLP, WAVE_FORMAT_MLP, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -#define WAVE_FORMAT_SPEEX 0xA109 -DEFINE_GUID(MEDIASUBTYPE_SPEEX, WAVE_FORMAT_SPEEX, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); - -#ifndef WAVE_FORMAT_OPUS -#define WAVE_FORMAT_OPUS 0x704F -#endif -DEFINE_GUID(MEDIASUBTYPE_OPUS, WAVE_FORMAT_OPUS, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_OPUS_OLD mmioFOURCC('O', 'P', 'U', 'S') -DEFINE_GUID(MEDIASUBTYPE_OPUS_OLD, WAVE_FORMAT_OPUS_OLD, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_DSDL mmioFOURCC('D', 'S', 'D', 'L') -DEFINE_GUID(MEDIASUBTYPE_DSDL, WAVE_FORMAT_DSDL, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_DSDM mmioFOURCC('D', 'S', 'D', 'M') -DEFINE_GUID(MEDIASUBTYPE_DSDM, WAVE_FORMAT_DSDM, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_DSD1 mmioFOURCC('D', 'S', 'D', '1') -DEFINE_GUID(MEDIASUBTYPE_DSD1, WAVE_FORMAT_DSD1, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -#define WAVE_FORMAT_DSD8 mmioFOURCC('D', 'S', 'D', '8') -DEFINE_GUID(MEDIASUBTYPE_DSD8, WAVE_FORMAT_DSD8, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000014-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_G723, 0x00000014, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 00000111-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_VIVO_G723, 0x00000111, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -// 20455041-0000-0010-8000-00AA00389B71 -DEFINE_GUID(MEDIASUBTYPE_APE, 0x20455041, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - - -struct WAVEFORMATEX_HDMV_LPCM : public WAVEFORMATEX -{ - BYTE channel_conf; - - struct WAVEFORMATEX_HDMV_LPCM() - { - memset(this, 0, sizeof(*this)); - cbSize = sizeof(WAVEFORMATEX_HDMV_LPCM) - sizeof(WAVEFORMATEX); - } -}; - -// {AFBC2343-3DCB-4047-9655-E1E62A61B1C5} -DEFINE_GUID(MEDIASUBTYPE_FFMPEG_AUDIO, 0xafbc2343, 0x3dcb, 0x4047, 0x96, 0x55, 0xe1, 0xe6, 0x2a, 0x61, 0xb1, 0xc5); - -// {35189950-CAC9-4C8D-819D-B6FAEE15DD9D} -DEFINE_GUID(FORMAT_WaveFormatExFFMPEG, 0x35189950, 0xcac9, 0x4c8d, 0x81, 0x9d, 0xb6, 0xfa, 0xee, 0x15, 0xdd, 0x9d); - -struct WAVEFORMATEXFFMPEG -{ - int nCodecId; - WAVEFORMATEX wfex; - - struct WAVEFORMATEXFFMPEG() - { - nCodecId = 0; - } -}; - -// {20884BC2-629F-45EA-B1C5-FA4FFA438250} -DEFINE_GUID(MEDIASUBTYPE_LAVBluRay, 0x20884bc2, 0x629f, 0x45ea, 0xb1, 0xc5, 0xfa, 0x4f, 0xfa, 0x43, 0x82, 0x50); - -// {D51BD5A3-7548-11cf-A520-0080C77EF58A} -DEFINE_GUID(CLSID_MultFile, 0xd51bd5a3, 0x7548, 0x11cf, 0xa5, 0x20, 0x0, 0x80, 0xc7, 0x7e, 0xf5, 0x8a); - -// Additionnal DXVA GUIDs - -// Intel ClearVideo VC1 bitstream decoder -DEFINE_GUID(DXVA_Intel_VC1_ClearVideo, 0xBCC5DB6D, 0xA2B6, 0x4AF0, 0xAC, 0xE4, 0xAD, 0xB1, 0xF7, 0x87, 0xBC, 0x89); -DEFINE_GUID(DXVA_Intel_VC1_ClearVideo_2, 0xE07EC519, 0xE651, 0x4CD6, 0xAC, 0x84, 0x13, 0x70, 0xCC, 0xEE, 0xC8, 0x51); - -// Intel ClearVideo H264 bitstream decoder -DEFINE_GUID(DXVA_Intel_H264_ClearVideo, 0x604F8E68, 0x4951, 0x4C54, 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6); - -// Nvidia MPEG-4 ASP bitstream decoder -// 9947EC6F-689B-11DC-A320-0019DBBC4184 -DEFINE_GUID(DXVA_MPEG4_ASP, 0x9947EC6F, 0x689B, 0x11DC, 0xA3, 0x20, 0x00, 0x19, 0xDB, 0xBC, 0x41, 0x84); - -// Filter/Commercial GUIDs - -DEFINE_GUID(CLSID_AC3Filter, 0xA753A1EC, 0x973E, 0x4718, 0xAF, 0x8E, 0xA3, 0xF5, 0x54, 0xD4, 0x5C, 0x44); - -// {212690FB-83E5-4526-8FD7-74478B7939CD} from wmcodecdsp.h -DEFINE_GUID(CLSID_CMPEG2VidDecoderDS, 0x212690FB, 0x83E5, 0x4526, 0x8F, 0xD7, 0x74, 0x47, 0x8B, 0x79, 0x39, 0xCD); - -// {39F498AF-1A09-4275-B193-673B0BA3D478} -DEFINE_GUID(CLSID_CMpeg2DecFilter, 0x39F498AF, 0x1A09, 0x4275, 0xB1, 0x93, 0x67, 0x3B, 0x0B, 0xA3, 0xD4, 0x78); - -// Nvidia Video Decoder - {71E4616A-DB5E-452B-8CA5-71D9CC7805E9} -DEFINE_GUID(CLSID_NvidiaVideoDecoder, 0x71E4616A, 0xDB5E, 0x452B, 0x8C, 0xA5, 0x71, 0xD9, 0xCC, 0x78, 0x05, 0xE9); - -// Sonic Cinemaster Video Decoder - {D7D50E8D-DD72-43C2-8587-A0C197D837D2} -DEFINE_GUID(CLSID_SonicCinemasterVideoDecoder, 0xD7D50E8D, 0xDD72, 0x43C2, 0x85, 0x87, 0xA0, 0xC1, 0x97, 0xD8, 0x37, 0xD2); - -// RDP DirectShow Redirection Filter - {AB9D6472-752F-43F6-B29E-61207BDA8E06} -DEFINE_GUID(CLSID_RDPDShowRedirectionFilter, 0xAB9D6472, 0x752F, 0x43F6, 0xB2, 0x9E, 0x61, 0x20, 0x7B, 0xDA, 0x8E, 0x06); - -// ReClock - {9DC15360-914C-46B8-B9DF-E67FD36C6A} -DEFINE_GUID(CLSID_ReClock, 0x9DC15360, 0x914C, 0x46B8, 0xB9, 0xDF, 0xBF, 0xE6, 0x7F, 0xD3, 0x6C, 0x6A); - -// MPC(BE) Audio Renderer - {601D2A2B-9CDE-40BD-8650-0485E3522727} -DEFINE_GUID(CLSID_MPCBEAudioRenderer, 0x601D2A2B, 0x9CDE, 0x40BD, 0x86, 0x50, 0x04, 0x85, 0xE3, 0x52, 0x27, 0x27); - -// Morgan's Stream Switcher - {D3CD7858-971A-4838-ACEC-40CA5D529DC8} -DEFINE_GUID(CLSID_MorganStreamSwitcher, 0xD3CD7858, 0x971A, 0x4838, 0xAC, 0xEC, 0x40, 0xCA, 0x5D, 0x52, 0x9D, 0xC8); - -// FFDShow DXVA Decoder - {0B0EFF97-C750-462C-9488-B10E7D87F1A6} -DEFINE_GUID(CLSID_FFDShowDXVADecoder, 0x0B0EFF97, 0xC750, 0x462C, 0x94, 0x88, 0xB1, 0x0E, 0x7D, 0x87, 0xF1, 0xA6); - -// Microsoft DTV-DVD Audio Decoder - {E1F1A0B8-BEEE-490D-BA7C-066C40B5E2B9} -DEFINE_GUID(CLSID_MSDVTDVDAudioDecoder, 0xE1F1A0B8, 0xBEEE, 0x490D, 0xBA, 0x7C, 0x06, 0x6C, 0x40, 0xB5, 0xE2, 0xB9); - -// Old MPC-HC filters -DEFINE_GUID(CLSID_MPCMpegSplitter, 0xDC257063, 0x045F, 0x4BE2, 0xBD, 0x5B, 0xE1, 0x22, 0x79, 0xC4, 0x64, 0xF0); -DEFINE_GUID(CLSID_MPCMpegSplitterSource, 0x1365BE7A, 0xC86A, 0x473C, 0x9A, 0x41, 0xC0, 0xA6, 0xE8, 0x2C, 0x9F, 0xA3); -DEFINE_GUID(CLSID_MPCVideoDecoder, 0x008BAC12, 0xFBAF, 0x497b, 0x96, 0x70, 0xBC, 0x6F, 0x6F, 0xBA, 0xE2, 0xC4); -DEFINE_GUID(CLSID_MPCShoutcastSource, 0x68F540E9, 0x766F, 0x44d2, 0xAB, 0x07, 0xE2, 0x6C, 0xC6, 0xD2, 0x7A, 0x79); - -// DirectVobSub || VSFilter (auto-loading version) - {9852A670-F845-491B-9BE6-EBD841B8A613} -DEFINE_GUID(CLSID_VSFilter, 0x9852A670, 0xF845, 0x491B, 0x9B, 0xE6, 0xEB, 0xD8, 0x41, 0xB8, 0xA6, 0x13); - -// DirectVobSub || VSFilter - {93A22E7A-5091-45EF-BA61-6DA26156A5D0} -DEFINE_GUID(CLSID_VSFilter2, 0x93A22E7A, 0x5091, 0x45EF, 0xBA, 0x61, 0x6D, 0xA2, 0x61, 0x56, 0xA5, 0xD0); - -// XySubFilter - {2DFCB782-EC20-4A7C-B530-4577ADB33F21} -DEFINE_GUID(CLSID_XySubFilter, 0x2DFCB782, 0xEC20, 0x4A7C, 0xB5, 0x30, 0x45, 0x77, 0xAD, 0xB3, 0x3F, 0x21); - -// XySubFilterAutoLoader - {6B237877-902B-4C6C-92F6-E63169A5166C} -DEFINE_GUID(CLSID_XySubFilter_AutoLoader, 0x6B237877, 0x902B, 0x4C6C, 0x92, 0xF6, 0xE6, 0x31, 0x69, 0xA5, 0x16, 0x6C); - -// sanear (internal version) -// SaneAudioRenderer::Factory::GetFilterGuid() is the right way do optain it, -// but we link DSUtil to everything and consequently will have to link sanear to everything. -DEFINE_GUID(CLSID_SANEAR_INTERNAL, 0x2AE00773, 0x819A, 0x40FB, 0xA5, 0x54, 0x54, 0x82, 0x7E, 0x11, 0x63, 0x59); - -// sanear (standalone version) - {DF557071-C9FD-433A-9627-81E0D3640ED9} -DEFINE_GUID(CLSID_SANEAR, 0xdf557071, 0xc9fd, 0x433a, 0x96, 0x27, 0x81, 0xe0, 0xd3, 0x64, 0xe, 0xd9); - -// AssFilter - {8A3704F3-BE3B-4944-9FF3-EE8757FDBDA5} -DEFINE_GUID(CLSID_AssFilter, 0x8A3704F3, 0xBE3B, 0x4944, 0x9F, 0xF3, 0xEE, 0x87, 0x57, 0xFD, 0xBD, 0xA5); - -// AssFilterAutoLoader - {8A6DFC6A-0A79-4790-85DA-0688B8093B54} -DEFINE_GUID(CLSID_AssFilter_AutoLoader, 0x8A6DFC6A, 0x0A79, 0x4790, 0x85, 0xDA, 0x06, 0x88, 0xB8, 0x09, 0x3B, 0x54); - -// Generate Still Video - {7DF62B50-6843-11D2-9EEB-006008039E37} -DEFINE_GUID(CLSID_StillVideo, 0x7DF62B50, 0x6843, 0x11D2, 0x9E, 0xEB, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); - -// MPC Image Source - {7DB5C3B3-2419-4508-B1D0-F2D22DA8E439} -DEFINE_GUID(CLSID_MPCImageSource, 0x7DB5C3B3, 0x2419, 0x4508, 0xB1, 0xD0, 0xF2, 0xD2, 0x2D, 0xA8, 0xE4, 0x39); - -DEFINE_GUID(CLSID_Generic_WDM_FilterProxy, 0x17CCA71B, 0xECD7, 0x11D0, 0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96); - -// uncompressed -#define DEFINE_GUID_FOURCC(FOURCC) \ - DEFINE_GUID(MEDIASUBTYPE_##FOURCC, FOURCC_##FOURCC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); - -//uncompressed -#define FOURCC_YUY2 mmioFOURCC('Y','U','Y','2') -#define FOURCC_V422 mmioFOURCC('V','4','2','2') -#define FOURCC_YV12 mmioFOURCC('Y','V','1','2') -#define FOURCC_YVYU mmioFOURCC('Y','V','Y','U') -#define FOURCC_UYVY mmioFOURCC('U','Y','V','Y') -#define FOURCC_YUYV mmioFOURCC('Y','U','Y','V') -#define FOURCC_VYUY mmioFOURCC('V','Y','U','Y') -#define FOURCC_I420 mmioFOURCC('I','4','2','0') -#define FOURCC_IYUV mmioFOURCC('I','Y','U','V') -#define FOURCC_444P mmioFOURCC('4','4','4','P') -#define FOURCC_YV24 mmioFOURCC('Y','V','2','4') // YUV 4:4:4 -#define FOURCC_422P mmioFOURCC('4','2','2','P') -#define FOURCC_YV16 mmioFOURCC('Y','V','1','6') // YUV 4:2:2 -#define FOURCC_411P mmioFOURCC('4','1','1','P') -#define FOURCC_Y41B mmioFOURCC('Y','4','1','B') // YUV 4:1:1 -#define FOURCC_410P mmioFOURCC('4','1','0','P') -#define FOURCC_PAL1 mmioFOURCC('P','A','L','1') -#define FOURCC_PAL4 mmioFOURCC('P','A','L','4') -#define FOURCC_PAL8 mmioFOURCC('P','A','L','8') -#define FOURCC_RGB2 mmioFOURCC('R','G','B','2') -#define FOURCC_RGB3 mmioFOURCC('R','G','B','3') -#define FOURCC_RGB5 mmioFOURCC('R','G','B','5') -#define FOURCC_RGB6 mmioFOURCC('R','G','B','6') -#define FOURCC_CLJR mmioFOURCC('C','L','J','R') -#define FOURCC_Y800 mmioFOURCC('Y','8','0','0') -#define FOURCC_NV12 mmioFOURCC('N','V','1','2') -#define FOURCC_NV21 mmioFOURCC('N','V','2','1') -#define FOURCC_P010 mmioFOURCC('P','0','1','0') -#define FOURCC_P016 mmioFOURCC('P','0','1','6') -#define FOURCC_420R mmioFOURCC('4','2','0','R') -#define FOURCC_422R mmioFOURCC('4','2','2','R') -#define FOURCC_444R mmioFOURCC('4','4','4','R') -#define FOURCC_P210 mmioFOURCC('P','2','1','0') -#define FOURCC_P216 mmioFOURCC('P','2','1','6') -#define FOURCC_AYUV mmioFOURCC('A','Y','U','V') -#define FOURCC_Y416 mmioFOURCC('Y','4','1','6') - -#define FOURCC_nv12 mmioFOURCC('n','v','1','2') -#define FOURCC_yv12 mmioFOURCC('y','v','1','2') -#define FOURCC_ICM1 mmioFOURCC('I','C','M','1') -#define FOURCC_ICM2 mmioFOURCC('I','C','M','2') -#define FOURCC_ICM3 mmioFOURCC('I','C','M','3') -#define FOURCC_ICM4 mmioFOURCC('I','C','M','4') -#define FOURCC_yuy2 mmioFOURCC('y','u','y','2') -#define FOURCC_uyvy mmioFOURCC('u','y','v','y') -#define FOURCC_cyuv mmioFOURCC('c','y','u','v') -#define FOURCC_UYNV mmioFOURCC('U','Y','N','V') -#define FOURCC_UYNY mmioFOURCC('U','Y','N','Y') -#define FOURCC_HDYC mmioFOURCC('H','D','Y','C') -#define FOURCC_uyv1 mmioFOURCC('u','y','v','1') -#define FOURCC_2Vu1 mmioFOURCC('2','V','u','1') -#define FOURCC_VDTZ mmioFOURCC('V','D','T','Z') -#define FOURCC_YUV2 mmioFOURCC('Y','U','V','2') -#define FOURCC_yuv2 mmioFOURCC('y','u','v','2') -#define FOURCC_2vuy mmioFOURCC('2','v','u','y') -#define FOURCC_2Vuy mmioFOURCC('2','V','u','y') -#define FOURCC_yuvu mmioFOURCC('y','u','v','u') -#define FOURCC_yuvs mmioFOURCC('y','u','v','s') -#define FOURCC_I422 mmioFOURCC('I','4','2','2') -#define FOURCC_Y422 mmioFOURCC('Y','4','2','2') -#define FOURCC_V422 mmioFOURCC('V','4','2','2') -#define FOURCC_Y42B mmioFOURCC('Y','4','2','B') -#define FOURCC_P422 mmioFOURCC('P','4','2','2') -#define FOURCC_YUNV mmioFOURCC('Y','U','N','V') -#define FOURCC_AVUI mmioFOURCC('A','V','U','I') -#define FOURCC_I444 mmioFOURCC('I','4','4','4') -#define FOURCC_v308 mmioFOURCC('v','3','0','8') -#define FOURCC_v408 mmioFOURCC('v','4','0','8') -#define FOURCC_24BG mmioFOURCC('2','4','B','G') -#define FOURCC_BGRA mmioFOURCC('B','G','R','A') -#define FOURCC_ABGR mmioFOURCC('A','B','G','R') -#define FOURCC_RGBA mmioFOURCC('R','G','B','A') -#define FOURCC_RGB0 mmioFOURCC('R','G','B','0') -#define FOURCC_0RGB mmioFOURCC('0','R','G','B') -#define FOURCC_b48r mmioFOURCC('b','4','8','r') -#define FOURCC_RBA64 mmioFOURCC('R','B','A',64) -#define FOURCC_64RBA mmioFOURCC(64,'R','B','A') -#define FOURCC_b64a mmioFOURCC('b','6','4','a') -#define FOURCC_Y410 mmioFOURCC('Y','4','1','0') -#define FOURCC_v216 mmioFOURCC('v','2','1','6') -#define FOURCC_v416 mmioFOURCC('v','4','1','6') -#define FOURCC_Y8 mmioFOURCC('Y','8',0x20,0x20) -#define FOURCC_Y16 mmioFOURCC('Y','1',0,16) - -DEFINE_GUID_FOURCC(422P) -DEFINE_GUID_FOURCC(444P) -DEFINE_GUID_FOURCC(411P) -DEFINE_GUID_FOURCC(410P) -DEFINE_GUID_FOURCC(VYUY) -DEFINE_GUID_FOURCC(Y800) -DEFINE_GUID_FOURCC(NV21) -DEFINE_GUID_FOURCC(YV16) -DEFINE_GUID_FOURCC(YV24) -DEFINE_GUID_FOURCC(420R) -DEFINE_GUID_FOURCC(422R) -DEFINE_GUID_FOURCC(444R) -DEFINE_GUID_FOURCC(Y416) - -DEFINE_GUID_FOURCC(nv12) -DEFINE_GUID_FOURCC(yv12) -DEFINE_GUID_FOURCC(ICM1) -DEFINE_GUID_FOURCC(ICM2) -DEFINE_GUID_FOURCC(ICM3) -DEFINE_GUID_FOURCC(ICM4) -DEFINE_GUID_FOURCC(yuy2) -DEFINE_GUID_FOURCC(uyvy) -DEFINE_GUID_FOURCC(cyuv) -DEFINE_GUID_FOURCC(UYNV) -DEFINE_GUID_FOURCC(UYNY) -DEFINE_GUID_FOURCC(HDYC) -DEFINE_GUID_FOURCC(uyv1) -DEFINE_GUID_FOURCC(2Vu1) -DEFINE_GUID_FOURCC(VDTZ) -DEFINE_GUID_FOURCC(YUV2) -DEFINE_GUID_FOURCC(yuv2) -DEFINE_GUID_FOURCC(2vuy) -DEFINE_GUID_FOURCC(2Vuy) -DEFINE_GUID_FOURCC(yuvu) -DEFINE_GUID_FOURCC(yuvs) -DEFINE_GUID_FOURCC(I422) -DEFINE_GUID_FOURCC(Y422) -DEFINE_GUID_FOURCC(V422) -DEFINE_GUID_FOURCC(Y42B) -DEFINE_GUID_FOURCC(P422) -DEFINE_GUID_FOURCC(YUNV) -DEFINE_GUID_FOURCC(AVUI) -DEFINE_GUID_FOURCC(I444) -DEFINE_GUID_FOURCC(v308) -DEFINE_GUID_FOURCC(v408) -DEFINE_GUID_FOURCC(24BG) -DEFINE_GUID_FOURCC(BGRA) -DEFINE_GUID_FOURCC(ABGR) -DEFINE_GUID_FOURCC(RGBA) -DEFINE_GUID_FOURCC(RGB0) -DEFINE_GUID_FOURCC(0RGB) -DEFINE_GUID_FOURCC(b48r) -DEFINE_GUID_FOURCC(RBA64) -DEFINE_GUID_FOURCC(64RBA) -DEFINE_GUID_FOURCC(b64a) -DEFINE_GUID_FOURCC(Y410) -DEFINE_GUID_FOURCC(v216) -DEFINE_GUID_FOURCC(v416) -DEFINE_GUID_FOURCC(Y8) -DEFINE_GUID_FOURCC(Y16) +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#define WAVE_FORMAT_DOLBY_AC3 0x2000 +// {00002000-0000-0010-8000-00aa00389b71} +DEFINE_GUID(MEDIASUBTYPE_WAVE_DOLBY_AC3, WAVE_FORMAT_DOLBY_AC3, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, + 0x9b, 0x71); + +#define WAVE_FORMAT_DVD_DTS 0x2001 +// {00002001-0000-0010-8000-00aa00389b71} +DEFINE_GUID(MEDIASUBTYPE_WAVE_DTS, WAVE_FORMAT_DVD_DTS, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// Be compatible with 3ivx +#define WAVE_FORMAT_AAC 0x00FF +// {000000FF-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_AAC, WAVE_FORMAT_AAC, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_LATM_AAC 0x01FF +// {000001FF-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_LATM_AAC, WAVE_FORMAT_LATM_AAC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +// ... and also compatible with nero +// btw, older nero parsers use a lower-case fourcc, newer upper-case (why can't it just offer both?) +// {4134504D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_MP4A, 0x4134504D, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {6134706D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_mp4a, 0x6134706D, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_MP3 0x0055 +// 00000055-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MP3, WAVE_FORMAT_MP3, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_FLAC 0xF1AC +// 0000F1AC-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FLAC, WAVE_FORMAT_FLAC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {1541C5C0-CDDF-477d-BC0A-86F8AE7F8354} +DEFINE_GUID(MEDIASUBTYPE_FLAC_FRAMED, 0x1541c5c0, 0xcddf, 0x477d, 0xbc, 0xa, 0x86, 0xf8, 0xae, 0x7f, 0x83, 0x54); + +#define WAVE_FORMAT_TTA1 0x77A1 +// {000077A1-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_TTA1, WAVE_FORMAT_TTA1, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_WAVPACK4 0x5756 +// {00005756-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_WAVPACK4, WAVE_FORMAT_WAVPACK4, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_AMR, 0x000000FE, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// {726D6173-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_SAMR, 0x726D6173, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VP70, 0x30375056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VP80, 0x30385056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VP90, 0x30395056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_AV01, 0x31305641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_IMA4, 0x34616D69, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +// {34616D69-0000-0010-8000-00AA00389B71} + +DEFINE_GUID(MEDIASUBTYPE_SAWB, 0x62776173, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {DA5B82EE-6BD2-426f-BF1E-30112DA78AE1} +DEFINE_GUID(MEDIASUBTYPE_SVCD_SUBPICTURE, 0xda5b82ee, 0x6bd2, 0x426f, 0xbf, 0x1e, 0x30, 0x11, 0x2d, 0xa7, 0x8a, 0xe1); + +// {7B57308F-5154-4c36-B903-52FE76E184FC} +DEFINE_GUID(MEDIASUBTYPE_CVD_SUBPICTURE, 0x7b57308f, 0x5154, 0x4c36, 0xb9, 0x3, 0x52, 0xfe, 0x76, 0xe1, 0x84, 0xfc); + +// {0E3A2342-F6E2-4c91-BDAE-87C71EAD0D63} +DEFINE_GUID(MEDIASUBTYPE_MPEG2_PVA, 0xe3a2342, 0xf6e2, 0x4c91, 0xbd, 0xae, 0x87, 0xc7, 0x1e, 0xad, 0xd, 0x63); + +// {6B6D0800-9ADA-11d0-A520-00A0D10129C0} +DEFINE_GUID(CLSID_NetShowSource, 0x6b6d0800, 0x9ada, 0x11d0, 0xa5, 0x20, 0x0, 0xa0, 0xd1, 0x1, 0x29, 0xc0); + +// DirectShowMedia + +// {5E9C9EE0-2E4A-4f22-9906-7BBBB75AA2B6} +DEFINE_GUID(MEDIASUBTYPE_DirectShowMedia, 0x5e9c9ee0, 0x2e4a, 0x4f22, 0x99, 0x6, 0x7b, 0xbb, 0xb7, 0x5a, 0xa2, 0xb6); + +// Dirac + +// {A29DA00F-A22B-40ea-98DE-2F7FECADA5DE} +DEFINE_GUID(MEDIASUBTYPE_Dirac, 0xa29da00f, 0xa22b, 0x40ea, 0x98, 0xde, 0x2f, 0x7f, 0xec, 0xad, 0xa5, 0xde); + +// {64726376-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_DiracVideo, 0x64726376, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {D2667A7E-4055-4244-A65F-DDDDF2B74BD7} +DEFINE_GUID(FORMAT_DiracVideoInfo, 0xd2667a7e, 0x4055, 0x4244, 0xa6, 0x5f, 0xdd, 0xdd, 0xf2, 0xb7, 0x4b, 0xd7); + +// {63617264-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_DRAC, 0x63617264, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +struct DIRACINFOHEADER +{ + VIDEOINFOHEADER2 hdr; + DWORD cbSequenceHeader; + DWORD dwSequenceHeader[1]; +}; + +// MP4 + +// {08E22ADA-B715-45ed-9D20-7B87750301D4} +DEFINE_GUID(MEDIASUBTYPE_MP4, 0x8e22ada, 0xb715, 0x45ed, 0x9d, 0x20, 0x7b, 0x87, 0x75, 0x3, 0x1, 0xd4); + +// FLV + +// {F2FAC0F1-3852-4670-AAC0-9051D400AC54} +DEFINE_GUID(MEDIASUBTYPE_FLV, 0xf2fac0f1, 0x3852, 0x4670, 0xaa, 0xc0, 0x90, 0x51, 0xd4, 0x0, 0xac, 0x54); + +// 31564C46-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FLV1, 0x31564C46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31766C66-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_flv1, 0x31766C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34564C46-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FLV4, 0x34564C46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34766C66-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_flv4, 0x34766C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30355056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP50, 0x30355056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30357076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp50, 0x30357076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP60, 0x30365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp60, 0x30367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP61, 0x31365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp61, 0x31367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP62, 0x32365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp62, 0x32367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 41365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP6A, 0x41365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 61367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp6a, 0x61367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 46365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP6F, 0x46365056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 66367076-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vp6f, 0x66367076, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// +// RealMedia +// + +enum +{ + WAVE_FORMAT_14_4 = 0x2002, + WAVE_FORMAT_28_8 = 0x2003, + WAVE_FORMAT_ATRC = 0x0270, // WAVE_FORMAT_SONY_SCX, + WAVE_FORMAT_COOK = 0x2004, + WAVE_FORMAT_DNET = 0x2005, + WAVE_FORMAT_RAAC = 0x2006, + WAVE_FORMAT_RACP = 0x2007, + WAVE_FORMAT_SIPR = 0x0130, // WAVE_FORMAT_SIPROLAB_ACEPLNET, +}; + +// {57428EC6-C2B2-44a2-AA9C-28F0B6A5C48E} +DEFINE_GUID(MEDIASUBTYPE_RealMedia, 0x57428ec6, 0xc2b2, 0x44a2, 0xaa, 0x9c, 0x28, 0xf0, 0xb6, 0xa5, 0xc4, 0x8e); + +// 30315652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV10, 0x30315652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30325652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV20, 0x30325652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30335652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV30, 0x30335652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30345652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV40, 0x30345652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31345652-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RV41, 0x31345652, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 345f3431-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_14_4, 0x345f3431, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 385f3832-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_28_8, 0x385f3832, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4b4f4f43-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_COOK, 0x4b4f4f43, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 54454e44-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DNET, 0x54454e44, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 52504953-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SIPR, 0x52504953, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 00000130-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SIPR_WAVE, WAVE_FORMAT_SIPR, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43414152-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RAAC, 0x43414152, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 50434152-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RACP, 0x50434152, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +#define WAVE_FORMAT_RALF mmioFOURCC('R', 'A', 'L', 'F') +DEFINE_GUID(MEDIASUBTYPE_RALF, WAVE_FORMAT_RALF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// QuickTime PCM + +// 454E4F4E-0000-0010-8000-00AA00389B71 (unsigned 8-bit) +DEFINE_GUID(MEDIASUBTYPE_PCM_NONE, 0x454E4F4E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 20776172-0000-0010-8000-00AA00389B71 (unsigned 8-bit, signed big-endian 16 bit) +DEFINE_GUID(MEDIASUBTYPE_PCM_RAW, 0x20776172, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 736f7774-0000-0010-8000-00AA00389B71 (signed 8-bit, signed big-endian 16-bit) +DEFINE_GUID(MEDIASUBTYPE_PCM_TWOS, 0x736f7774, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 74776f73-0000-0010-8000-00AA00389B71 (signed 8-bit, signed little-endian 16-bit) +DEFINE_GUID(MEDIASUBTYPE_PCM_SOWT, 0x74776f73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34326E69-0000-0010-8000-00AA00389B71 (signed big-endian int24) +DEFINE_GUID(MEDIASUBTYPE_PCM_IN24, 0x34326E69, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32336E69-0000-0010-8000-00AA00389B71 (signed big-endian int32) +DEFINE_GUID(MEDIASUBTYPE_PCM_IN32, 0x32336E69, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32336C66-0000-0010-8000-00AA00389B71 (signed big-endian float32) +DEFINE_GUID(MEDIASUBTYPE_PCM_FL32, 0x32336C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34366C66-0000-0010-8000-00AA00389B71 (signed big-endian float64) +DEFINE_GUID(MEDIASUBTYPE_PCM_FL64, 0x34366C66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Reverse GUIDs for little-endian 'in24', 'in32', 'fl32', 'fl64' +// 696E3234-0000-0010-8000-00AA00389B71 (signed little-endian int24, reverse 'in24') +DEFINE_GUID(MEDIASUBTYPE_PCM_IN24_le, 0x696E3234, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 696E3332-0000-0010-8000-00AA00389B71 (signed little-endian int32, reverse 'in32') +DEFINE_GUID(MEDIASUBTYPE_PCM_IN32_le, 0x696E3332, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 666C3332-0000-0010-8000-00AA00389B71 (signed little-endian float32, reverse 'fl32') +DEFINE_GUID(MEDIASUBTYPE_PCM_FL32_le, 0x666C3332, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +// 666C3634-0000-0010-8000-00AA00389B71 (signed little-endian float64, reverse 'fl64') +DEFINE_GUID(MEDIASUBTYPE_PCM_FL64_le, 0x666C3634, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// +// PS2 +// + +#define WAVE_FORMAT_PS2_PCM 0xF521 +// 0000F521-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_PS2_PCM, WAVE_FORMAT_PS2_PCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_PS2_ADPCM 0xF522 +// 0000F522-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_PS2_ADPCM, WAVE_FORMAT_PS2_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +#define WAVE_FORMAT_ADPCM_SWF 0x5346 +// 00005346-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ADPCM_SWF, + WAVE_FORMAT_ADPCM_SWF, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 41564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ADPCM_AMV, + 0x41564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + + +struct WAVEFORMATEXPS2 : public WAVEFORMATEX +{ + DWORD dwInterleave; + + struct WAVEFORMATEXPS2() + { + memset(this, 0, sizeof(*this)); + cbSize = sizeof(WAVEFORMATEXPS2) - sizeof(WAVEFORMATEX); + } +}; + +// {4F3D3D21-6D7C-4f73-AA05-E397B5EAE0AA} +DEFINE_GUID(MEDIASUBTYPE_PS2_SUB, 0x4f3d3d21, 0x6d7c, 0x4f73, 0xaa, 0x5, 0xe3, 0x97, 0xb5, 0xea, 0xe0, 0xaa); + +// ATRAC + +// 43525441-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ATRC, 0x43525441, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 00000270-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ATRAC3, WAVE_FORMAT_SONY_SCX, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +#define WAVE_FORMAT_ATRAC3P 0xE923AABF +// E923AABF-CB58-4471-A119-FFFA01E4CE62 +DEFINE_GUID(MEDIASUBTYPE_ATRAC3P, 0xE923AABF, 0xCB58, 0x4471, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62); + +// Haali's video renderer + +// {760A8F35-97E7-479d-AAF5-DA9EFF95D751} +DEFINE_GUID(CLSID_DXR, 0x760a8f35, 0x97e7, 0x479d, 0xaa, 0xf5, 0xda, 0x9e, 0xff, 0x95, 0xd7, 0x51); + +// {E1A8B82A-32CE-4B0D-BE0D-AA68C772E423} +DEFINE_GUID(CLSID_MadVR, 0xE1A8B82A, 0x32CE, 0x4B0D, 0xBE, 0x0D, 0xAA, 0x68, 0xC7, 0x72, 0xE4, 0x23); + +// {71F080AA-8661-4093-B15E-4F6903E77D0A} +DEFINE_GUID(CLSID_MPCVR, 0x71F080AA, 0x8661, 0x4093, 0xB1, 0x5E, 0x4F, 0x69, 0x03, 0xE7, 0x7D, 0x0A); + +// {C1F400A4-3F08-11D3-9F0B-006008039E37} +DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11D3, 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); + +// {A0025E90-E45B-11D1-ABE9-00A0C905F375} +DEFINE_GUID(CLSID_OverlayMixer2, 0xA0025E90, 0xE45B, 0x11D1, 0xAB, 0xE9, 0x00, 0xA0, 0xC9, 0x05, 0xF3, 0x75); + +// +// Ogg +// + +// 9FF48807-E133-40AA-826F-9B2959E5232D +DEFINE_GUID(CLSID_MPCHCOggSplitter, 0x9FF48807, 0xE133, 0x40AA, 0x82, 0x6F, 0x9B, 0x29, 0x59, 0xE5, 0x23, 0x2D); + +// 6D3688CE-3E9D-42F4-92CA-8A11119D25CD +DEFINE_GUID(CLSID_MPCHCOggSource, 0x6D3688CE, 0x3E9D, 0x42F4, 0x92, 0xCA, 0x8A, 0x11, 0x11, 0x9D, 0x25, 0xCD); + +// f07e245f-5a1f-4d1e-8bff-dc31d84a55ab +DEFINE_GUID(CLSID_OggSplitter, 0xf07e245f, 0x5a1f, 0x4d1e, 0x8b, 0xff, 0xdc, 0x31, 0xd8, 0x4a, 0x55, 0xab); + +// {078C3DAA-9E58-4d42-9E1C-7C8EE79539C5} +DEFINE_GUID(CLSID_OggSplitPropPage, 0x78c3daa, 0x9e58, 0x4d42, 0x9e, 0x1c, 0x7c, 0x8e, 0xe7, 0x95, 0x39, 0xc5); + +// 8cae96b7-85b1-4605-b23c-17ff5262b296 +DEFINE_GUID(CLSID_OggMux, 0x8cae96b7, 0x85b1, 0x4605, 0xb2, 0x3c, 0x17, 0xff, 0x52, 0x62, 0xb2, 0x96); + +// {AB97AFC3-D08E-4e2d-98E0-AEE6D4634BA4} +DEFINE_GUID(CLSID_OggMuxPropPage, 0xab97afc3, 0xd08e, 0x4e2d, 0x98, 0xe0, 0xae, 0xe6, 0xd4, 0x63, 0x4b, 0xa4); + +// {889EF574-0656-4B52-9091-072E52BB1B80} +DEFINE_GUID(CLSID_VorbisEnc, 0x889ef574, 0x0656, 0x4b52, 0x90, 0x91, 0x07, 0x2e, 0x52, 0xbb, 0x1b, 0x80); + +// {c5379125-fd36-4277-a7cd-fab469ef3a2f} +DEFINE_GUID(CLSID_VorbisEncPropPage, 0xc5379125, 0xfd36, 0x4277, 0xa7, 0xcd, 0xfa, 0xb4, 0x69, 0xef, 0x3a, 0x2f); + +// 02391f44-2767-4e6a-a484-9b47b506f3a4 +DEFINE_GUID(CLSID_VorbisDec, 0x02391f44, 0x2767, 0x4e6a, 0xa4, 0x84, 0x9b, 0x47, 0xb5, 0x06, 0xf3, 0xa4); + +// 77983549-ffda-4a88-b48f-b924e8d1f01c +DEFINE_GUID(CLSID_OggDSAboutPage, 0x77983549, 0xffda, 0x4a88, 0xb4, 0x8f, 0xb9, 0x24, 0xe8, 0xd1, 0xf0, 0x1c); + +// {D2855FA9-61A7-4db0-B979-71F297C17A04} +DEFINE_GUID(MEDIASUBTYPE_Ogg, 0xd2855fa9, 0x61a7, 0x4db0, 0xb9, 0x79, 0x71, 0xf2, 0x97, 0xc1, 0x7a, 0x4); + +// cddca2d5-6d75-4f98-840e-737bedd5c63b +DEFINE_GUID(MEDIASUBTYPE_Vorbis, 0xcddca2d5, 0x6d75, 0x4f98, 0x84, 0x0e, 0x73, 0x7b, 0xed, 0xd5, 0xc6, 0x3b); + +// 6bddfa7e-9f22-46a9-ab5e-884eff294d9f +DEFINE_GUID(FORMAT_VorbisFormat, 0x6bddfa7e, 0x9f22, 0x46a9, 0xab, 0x5e, 0x88, 0x4e, 0xff, 0x29, 0x4d, 0x9f); + +typedef struct tagVORBISFORMAT +{ + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nMinBitsPerSec; + DWORD nAvgBitsPerSec; + DWORD nMaxBitsPerSec; + float fQuality; +} VORBISFORMAT, *PVORBISFORMAT, FAR *LPVORBISFORMAT; + +// {8D2FD10B-5841-4a6b-8905-588FEC1ADED9} +DEFINE_GUID(MEDIASUBTYPE_Vorbis2, 0x8d2fd10b, 0x5841, 0x4a6b, 0x89, 0x5, 0x58, 0x8f, 0xec, 0x1a, 0xde, 0xd9); + +// {B36E107F-A938-4387-93C7-55E966757473} +DEFINE_GUID(FORMAT_VorbisFormat2, 0xb36e107f, 0xa938, 0x4387, 0x93, 0xc7, 0x55, 0xe9, 0x66, 0x75, 0x74, 0x73); + +typedef struct tagVORBISFORMAT2 +{ + DWORD Channels; + DWORD SamplesPerSec; + DWORD BitsPerSample; + DWORD HeaderSize[3]; // 0: Identification, 1: Comment, 2: Setup +} VORBISFORMAT2, *PVORBISFORMAT2, FAR *LPVORBISFORMAT2; + +// +// Matroska +// + +// {1AC0BEBD-4D2B-45ad-BCEB-F2C41C5E3788} +DEFINE_GUID(MEDIASUBTYPE_Matroska, 0x1ac0bebd, 0x4d2b, 0x45ad, 0xbc, 0xeb, 0xf2, 0xc4, 0x1c, 0x5e, 0x37, 0x88); + +// {E487EB08-6B26-4be9-9DD3-993434D313FD} +DEFINE_GUID(MEDIATYPE_Subtitle, 0xe487eb08, 0x6b26, 0x4be9, 0x9d, 0xd3, 0x99, 0x34, 0x34, 0xd3, 0x13, 0xfd); + +// {87C0B230-03A8-4fdf-8010-B27A5848200D} +DEFINE_GUID(MEDIASUBTYPE_UTF8, 0x87c0b230, 0x3a8, 0x4fdf, 0x80, 0x10, 0xb2, 0x7a, 0x58, 0x48, 0x20, 0xd); + +// {3020560F-255A-4ddc-806E-6C5CC6DCD70A} +DEFINE_GUID(MEDIASUBTYPE_SSA, 0x3020560f, 0x255a, 0x4ddc, 0x80, 0x6e, 0x6c, 0x5c, 0xc6, 0xdc, 0xd7, 0xa); + +// {326444F7-686F-47ff-A4B2-C8C96307B4C2} +DEFINE_GUID(MEDIASUBTYPE_ASS, 0x326444f7, 0x686f, 0x47ff, 0xa4, 0xb2, 0xc8, 0xc9, 0x63, 0x7, 0xb4, 0xc2); + +// {370689E7-B226-4f67-978D-F10BC1A9C6AE} +DEFINE_GUID(MEDIASUBTYPE_ASS2, 0x370689e7, 0xb226, 0x4f67, 0x97, 0x8d, 0xf1, 0xb, 0xc1, 0xa9, 0xc6, 0xae); + +// {76C421C4-DB89-42ec-936E-A9FBC1794714} +DEFINE_GUID(MEDIASUBTYPE_SSF, 0x76c421c4, 0xdb89, 0x42ec, 0x93, 0x6e, 0xa9, 0xfb, 0xc1, 0x79, 0x47, 0x14); + +// {B753B29A-0A96-45be-985F-68351D9CAB90} +DEFINE_GUID(MEDIASUBTYPE_USF, 0xb753b29a, 0xa96, 0x45be, 0x98, 0x5f, 0x68, 0x35, 0x1d, 0x9c, 0xab, 0x90); + +// {F7239E31-9599-4e43-8DD5-FBAF75CF37F1} +DEFINE_GUID(MEDIASUBTYPE_VOBSUB, 0xf7239e31, 0x9599, 0x4e43, 0x8d, 0xd5, 0xfb, 0xaf, 0x75, 0xcf, 0x37, 0xf1); + +// {A33D2F7D-96BC-4337-B23B-A8B9FBC295E9} +DEFINE_GUID(FORMAT_SubtitleInfo, 0xa33d2f7d, 0x96bc, 0x4337, 0xb2, 0x3b, 0xa8, 0xb9, 0xfb, 0xc2, 0x95, 0xe9); + +// {04EBA53E-9330-436c-9133-553EC87031DC} +DEFINE_GUID(MEDIASUBTYPE_HDMVSUB, 0x4eba53e, 0x9330, 0x436c, 0x91, 0x33, 0x55, 0x3e, 0xc8, 0x70, 0x31, 0xdc); + +// {C886D215-F485-40BB-8DB6-FADBC619A45D} +DEFINE_GUID(MEDIASUBTYPE_WEBVTT, 0xc886d215, 0xf485, 0x40bb, 0x8d, 0xb6, 0xfa, 0xdb, 0xc6, 0x19, 0xa4, 0x5d); + +#pragma pack(push, 1) +typedef struct +{ + DWORD dwOffset; + CHAR IsoLang[4]; // three letter lang code + terminating zero + WCHAR TrackName[256]; // 256 chars ought to be enough for everyone :) +} SUBTITLEINFO; +#pragma pack(pop) + +// SUBTITLEINFO structure content starting at dwOffset (also the content of CodecPrivate) +// -------------------------------------------------------------------------------------- +// +// Here the text should start with the Byte Order Mark, even though +// UTF-8 is preferred, it also helps identifying the encoding type. +// +// MEDIASUBTYPE_USF: +// +// +// +// +// +// +// ... every element excluding ... +// +// +// MEDIASUBTYPE_SSA/ASS: +// +// The file header and all sub-sections except [Events] +// +// MEDIATYPE_VOBSUB: +// +// TODO +// + +// Data description of the media samples (everything is UTF-8 encoded here) +// ------------------------------------------------------------------------ +// +// MEDIASUBTYPE_USF: +// +// The text _inside_ the .. element. +// +// Since timing is set on the sample, there is no need to put +// into the data. +// +// MEDIASUBTYPE_SSA/ASS: +// +// Comma separated values similar to the "Dialogue: ..." line with these fields: +// ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text +// +// With the exception of ReadOrder every field can be found in ASS files. The +// ReadOrder field is needed for the decoder to be able to reorder the streamed +// samples as they were placed originally in the file. +// +// If the source is only SSA, the Layer field can be left empty. +// +// MEDIATYPE_VOBSUB: +// +// Standard dvd subpic data, without the stream id at the beginning. +// + +// Matroska CodecID mappings +// ------------------------ +// +// S_TEXT/ASCII <-> MEDIATYPE_Text MEDIASUBTYPE_NULL FORMAT_None +// S_TEXT/UTF8 <-> MEDIATYPE_Subtitle MEDIASUBTYPE_UTF8 FORMAT_SubtitleInfo +// S_TEXT/SSA <-> MEDIATYPE_Subtitle MEDIASUBTYPE_SSA FORMAT_SubtitleInfo +// S_TEXT/ASS <-> MEDIATYPE_Subtitle MEDIASUBTYPE_ASS FORMAT_SubtitleInfo +// S_TEXT/USF <-> MEDIATYPE_Subtitle MEDIASUBTYPE_USF FORMAT_SubtitleInfo +// S_VOBSUB <-> MEDIATYPE_Subtitle MEDIASUBTYPE_VOBSUB FORMAT_SubtitleInfo +// S_VOBSUB/ZLIB<-> MEDIATYPE_Subtitle MEDIASUBTYPE_VOBSUB FORMAT_SubtitleInfo +// + +/* +DEFINE_GUID( MEDIATYPE_MPEG2_SECTIONS, + 0x455f176c, 0x4b06, 0x47ce, 0x9a, 0xef, 0x8c, 0xae, 0xf7, 0x3d, 0xf7, 0xb5); + +DEFINE_GUID(MEDIASUBTYPE_ATSC_SI, +0xb3c7397c, 0xd303, 0x414d, 0xb3, 0x3c, 0x4e, 0xd2, 0xc9, 0xd2, 0x97, 0x33); + +DEFINE_GUID(MEDIASUBTYPE_DVB_SI, +0xe9dd31a3, 0x221d, 0x4adb, 0x85, 0x32, 0x9a, 0xf3, 0x9, 0xc1, 0xa4, 0x8); + + +// {C892E55B-252D-42b5-A316-D997E7A5D995} +DEFINE_GUID(MEDIASUBTYPE_MPEG2DATA, +0xc892e55b, 0x252d, 0x42b5, 0xa3, 0x16, 0xd9, 0x97, 0xe7, 0xa5, 0xd9, 0x95); + +*/ + +// ASF +// {6B6D0801-9ADA-11D0-A520-00A0D10129C0} +DEFINE_GUID(MEDIASUBTYPE_ASF, + 0x6b6d0801, 0x9ada, 0x11d0, 0xa5, 0x20, 0x00, 0xa0, 0xd1, 0x01, 0x29, 0xc0); + +// H264 + +// 6F29D2AD-E130-45AA-B42F-F623AD354A90 +DEFINE_GUID(MEDIASUBTYPE_ArcsoftH264, 0x6F29D2AD, 0xE130, 0x45AA, 0xB4, 0x2F, 0xF6, 0x23, 0xAD, 0x35, 0x4A, 0x90); + +// 48535356-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VSSH, 0x48535356, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 68737376-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_vssh, 0x68737376, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43564144-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DAVC, 0x43564144, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 63766164-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_davc, 0x63766164, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43564150-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_PAVC, 0x43564150, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 63766170-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_pavc, 0x63766170, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31637661-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_avc1, 0x31637661, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31564343-0000-0010-8000-00AA00389B71 (custom H.264 FourCC used by Haali Media Splitter) +DEFINE_GUID(MEDIASUBTYPE_CCV1, 0x31564343, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 8D2D71CB-243F-45E3-B2D8-5FD7967EC09B <= Use by MediaPortal for example... +DEFINE_GUID(MEDIASUBTYPE_H264_bis, 0x8D2D71CB, 0x243F, 0x45E3, 0xB2, 0xD8, 0x5F, 0xD7, 0x96, 0x7E, 0xC0, 0x9B); + +// 676C6178-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_xalg, 0x676C6178, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 676C7661-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_avlg, 0x676C7661, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33515653-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_SVQ3, 0x33515653, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_XVID, 0x44495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_xvid, 0x64697678, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30355844-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_DX50, 0x30355844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30357864-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_dx50, 0x30357864, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIVX, 0x58564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 78766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_divx, 0x78766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 78766944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_Divx, 0x78766944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 5634504d-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_MP4V, 0x5634504d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 7634706D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_mp4v, 0x7634706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31564933-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_3IV1, 0x31564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31766933-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_3iv1, 0x31766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32564933-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_3IV2, 0x32564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32766933-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_3iv2, 0x32766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 58564933-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_3IVX, 0x58564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 78766933-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_3ivx, 0x78766933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 305A4C42-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_BLZ0, 0x305A4C42, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 307A6C62-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_blz0, 0x307A6C62, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {564F4547-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_GEOV, 0x564F4547, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56344D44-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DM4V, 0x56344D44, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 76346D64-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_dm4v, 0x76346D64, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4D475844-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DXGM, 0x4D475844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 6D677864-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_dxgm, 0x6D677864, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 53444646-0000-0010-8000-00aa00389b71 +DEFINE_GUID(MEDIASUBTYPE_FFDS, 0x53444646, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 73646666-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ffds, 0x73646666, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 57465646-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FVFW, 0x57465646, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 77667666-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_fvfw, 0x77667666, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D46-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FMP4, 0x34504D46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D66-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_fmp4, 0x34706D66, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34584448-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HDX4, 0x34584448, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34786468-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_hdx4, 0x34786468, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D4C-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_LMP4, 0x34504D4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D6C-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_lmp4, 0x34706D6C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4749444E-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_NDIG, 0x4749444E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 6769646E-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ndig, 0x6769646E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D52-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RMP4, 0x34504D52, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D72-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_rmp4, 0x34706D72, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D53-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SMP4, 0x34504D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D73-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_smp4, 0x34706D73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 47444553-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SEDG, 0x47444553, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 67646573-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_sedg, 0x67646573, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4D475844-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DGXM, 0x4D475844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34504D55-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_UMP4, 0x34504D55, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34706D75-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ump4, 0x34706D75, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 46315657-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_WV1F, 0x46315657, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 66317677-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_wv1f, 0x66317677, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 58495658-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_XVIX, 0x58495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 78697678-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_xvix, 0x78697678, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31515653-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SVQ1, 0x31515653, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363248-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_H263, 0x33363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363268-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_h263, 0x33363268, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363249-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_I263, 0x33363249, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363269-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_i263, 0x33363269, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31363248-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_H261, 0x31363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31363268-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_h261, 0x31363268, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_S263, 0x33363273, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33363273-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_s263, 0x33363273, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AMVV, 0x56564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 46564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AMVF, 0x46564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33585644-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVX3, 0x33585644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33787664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_dvx3, 0x33787664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 44564933-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_3IVD, 0x44564933, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV3, 0x33564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div3, 0x33766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 314C4F43-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_COL1, 0x314C4F43, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 316C6F63-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_col1, 0x316C6F63, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV4, 0x34564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div4, 0x34766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV5, 0x35564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div5, 0x35766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 36564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV6, 0x36564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 36766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div6, 0x36766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31345041-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AP41, 0x31345041, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31347061-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ap41, 0x31347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3347504D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MPG3, 0x3347504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3367706D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_mpg3, 0x3367706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV2, 0x32564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div2, 0x32766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31564944-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DIV1, 0x31564944, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31766964-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_div1, 0x31766964, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3134504D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MP41, 0x3134504D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3134706D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_mp41, 0x3134706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4F454854-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_THEORA, 0x4F454854, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 6F656874-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_theora, 0x6F656874, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 63637374-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_TSCC, 0x63637374, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32637374-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_TSC2, 0x32637374, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30355649-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IV50, 0x30355649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31345649-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IV41, 0x31345649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31335649-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IV31, 0x31335649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32335649-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IV32, 0x32335649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 48564443-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CDVH, 0x48564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43564443-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CDVC, 0x43564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35564443-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CDV5, 0x35564443, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35325644-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DV25, 0x35325644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 30355644-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DV50, 0x30355644, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70637664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVCP, 0x70637664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70707664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVPP, 0x70707664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70357664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DV5P, 0x70357664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 6E357664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DV5N, 0x6E357664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70637664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVC, 0x20637664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 31687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH1, 0x31687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 32687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH2, 0x32687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 33687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH3, 0x33687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 34687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH4, 0x34687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 35687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH5, 0x35687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 36687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVH6, 0x36687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 71687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVHQ, 0x71687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 70687664-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DVHP, 0x70687664, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 76645641-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVdv, 0x76645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 31645641-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVd1, 0x31645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 31535046-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_FPS1, 0x31535046, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 55594648-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HuffYUV, 0x55594648, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 5347414C-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_Lagarith, 0x5347414C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 64697663-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CVID, 0x64697663, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 694B4942-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_BIKI, 0x694B4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 624B4942-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_BIKB, 0x624B4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 664b4942-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_BIKf, 0x664b4942, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +DEFINE_GUID(FORMAT_RLTheora, 0xe69b30d1, 0x7d65, 0x4166, 0xb9, 0x90, 0x10, 0x3d, 0xa8, 0xc9, 0x11, 0xe3); + +// 62706A6D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MJPGB, 0x62706A6D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 30365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP30, 0x30335056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30365056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP31, 0x31335056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 324B4D53-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SMK2, 0x324B4D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 344B4D53-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SMK4, 0x344B4D53, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 44435343-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CSCD, 0x44435343, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 47455051-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_QPEG, 0x47455051, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 302E3151-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_QP10, 0x302E3151, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 312E3151-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_QP11, 0x312E3151, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 485A534D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MSZH, 0x485A534D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 42494C5A-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ZLIB, 0x42494C5A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 20676E70-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_PNG, 0x20676E70, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_TIFF, MAKEFOURCC('T', 'I', 'F', 'F'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_BMP, MAKEFOURCC('B', 'M', 'P', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_GIF, MAKEFOURCC('G', 'I', 'F', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_TGA, MAKEFOURCC('T', 'G', 'A', ' '), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_WEBP, MAKEFOURCC('W', 'E', 'B', 'P'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_FSV1, 0x31565346, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_CRAM, MAKEFOURCC('C', 'R', 'A', 'M'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_MSVC, MAKEFOURCC('M', 'S', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_WHAM, MAKEFOURCC('W', 'H', 'A', 'M'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_8BPS, MAKEFOURCC('8', 'B', 'P', 'S'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_LOCO, MAKEFOURCC('L', 'O', 'C', 'O'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ZMBV, MAKEFOURCC('Z', 'M', 'B', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VCR1, MAKEFOURCC('V', 'C', 'R', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_AASC, MAKEFOURCC('A', 'A', 'S', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_SNOW, MAKEFOURCC('S', 'N', 'O', 'W'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_FFV1, MAKEFOURCC('F', 'F', 'V', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_FFVH, MAKEFOURCC('F', 'F', 'V', 'H'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_v410, MAKEFOURCC('v', '4', '1', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_VMNC, MAKEFOURCC('V', 'M', 'n', 'c'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// {3267706D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_MPG2, 0x3267706D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Apple ProRes +DEFINE_GUID(MEDIASUBTYPE_apch, 0x68637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_apcn, 0x6e637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_apcs, 0x73637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_apco, 0x6f637061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ap4h, 0x68347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ap4x, 0x78347061, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Apple ICOD +DEFINE_GUID(MEDIASUBTYPE_icod, 0x646F6369, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Ut Video +DEFINE_GUID(MEDIASUBTYPE_ULRA, MAKEFOURCC('U', 'L', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULRG, MAKEFOURCC('U', 'L', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULY0, MAKEFOURCC('U', 'L', 'Y', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULY2, MAKEFOURCC('U', 'L', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULY4, MAKEFOURCC('U', 'L', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UQY2, MAKEFOURCC('U', 'Q', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UQRG, MAKEFOURCC('U', 'Q', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UQRA, MAKEFOURCC('U', 'Q', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULH0, MAKEFOURCC('U', 'L', 'H', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULH2, MAKEFOURCC('U', 'L', 'H', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ULH4, MAKEFOURCC('U', 'L', 'H', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMY2, MAKEFOURCC('U', 'M', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMH2, MAKEFOURCC('U', 'M', 'H', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMY4, MAKEFOURCC('U', 'M', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMH4, MAKEFOURCC('U', 'M', 'H', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMRG, MAKEFOURCC('U', 'M', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_UMRA, MAKEFOURCC('U', 'M', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// G2M +DEFINE_GUID(MEDIASUBTYPE_G2M2, MAKEFOURCC('G', '2', 'M', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_G2M3, MAKEFOURCC('G', '2', 'M', '3'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_G2M4, MAKEFOURCC('G', '2', 'M', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_G2M5, MAKEFOURCC('G', '2', 'M', '5'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// CFHD +DEFINE_GUID(MEDIASUBTYPE_CFHD, MAKEFOURCC('C', 'F', 'H', 'D'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// MagicYUV +DEFINE_GUID(MEDIASUBTYPE_MAGY, MAKEFOURCC('M', 'A', 'G', 'Y'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8RG, MAKEFOURCC('M', '8', 'R', 'G'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8RA, MAKEFOURCC('M', '8', 'R', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8G0, MAKEFOURCC('M', '8', 'G', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8Y0, MAKEFOURCC('M', '8', 'Y', '0'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8Y2, MAKEFOURCC('M', '8', 'Y', '2'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8Y4, MAKEFOURCC('M', '8', 'Y', '4'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +DEFINE_GUID(MEDIASUBTYPE_M8YA, MAKEFOURCC('M', '8', 'Y', 'A'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// MagicYUV +DEFINE_GUID(MEDIASUBTYPE_FICV, MAKEFOURCC('F', 'I', 'C', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// DNxHD +// {6E645641-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_AVdn, 0x6E645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// DNxHR +// {68645641-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_AVdh, 0x68645641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// JPEG2000 +// {32706A6D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_mjp2, 0x32706A6D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {43324A4D-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_MJ2C, 0x43324A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {43324A4C-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_LJ2C, 0x43324A4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {4B324A4C-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_LJ2K, 0x4B324A4C, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {324A5049-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_IPJ2, 0x324A5049, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {D80FA03C-35C1-4FA1-8C8E-375C8667166E} +DEFINE_GUID(MEDIASUBTYPE_LAV_RAWVIDEO, 0xd80fa03c, 0x35c1, 0x4fa1, 0x8c, 0x8e, 0x37, 0x5c, 0x86, 0x67, 0x16, 0x6e); + +// {434C4641-0000-0010-8000-00AA00389B71} +DEFINE_GUID(MEDIASUBTYPE_FLIC, 0x434C4641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// {} +DEFINE_GUID(MEDIASUBTYPE_THPV, MAKEFOURCC('T', 'H', 'P', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +DEFINE_GUID(MEDIASUBTYPE_ROQV, MAKEFOURCC('R', 'o', 'Q', 'V'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// 31435648-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HVC1, 0x31435648, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43564548-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HEVC, 0x43564548, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30314D48-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HM10, 0x30314D48, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35363248-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_H265, 0x35363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// VVC ("VVC1") +DEFINE_GUID(MEDIASUBTYPE_VVC1, MAKEFOURCC('V', 'V', 'C', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71); + +// Full MVC +DEFINE_GUID(MEDIASUBTYPE_AMVC, MAKEFOURCC('A', 'M', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +// Full MVC in mp4-form +DEFINE_GUID(MEDIASUBTYPE_MVC1, MAKEFOURCC('M', 'V', 'C', '1'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +// Subset MVC +DEFINE_GUID(MEDIASUBTYPE_EMVC, MAKEFOURCC('E', 'M', 'V', 'C'), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, + 0x71); + +// 4B435544-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DUCK, 0x4B435544, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30324D54-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_TM20, 0x30324D54, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 20636D73-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_smc, 0x20636D73, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4C584956-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VIXL, 0x4C584956, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 49544C55-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ULTI, 0x49544C55, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31564E57-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_WNV1, 0x31564E57, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 76757963-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_CYUV, 0x76757963, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31565341-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVS1, 0x31565341, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 32565341-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVS2, 0x32565341, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31325452-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_RT21, 0x31325452, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 6E525641-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_AVRn, 0x6E525641, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 47504a4c-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_LJPG, 0x47504a4c, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4C47504A-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_JPGL, 0x4C47504A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 534c4a4d-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MJLS, 0x534c4a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 41504a4d-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MJPA, 0x41504a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 42504a4d-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MJPB, 0x42504a4d, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 58355053-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SP5X, 0x58355053, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 31706148-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_Hap1, 0x31706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 35706148-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_Hap5, 0x35706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 59706148-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_HapY, 0x59706148, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 33445844-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DXD3, 0x33445844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 49445844-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_DXDI, 0x49445844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 574D5632-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_2VMW, 0x574D5632, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 56334357-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_WC3V, 0x56334357, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 4345444D-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MDEC, 0x4345444D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 564D5834-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_4XMV, 0x564D5834, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 43425241-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ARBC, 0x43425241, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 30345056-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VP40, 0x30345056, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 34355053-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_SP54, 0x34355053, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// 3156474B-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_KGV1, 0x3156474B, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +// Audio codecs + +// 41564D41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IMA_AMV, 0x41564D41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 4C4C454E-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_NELLYMOSER, 0x4C4C454E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000006-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ALAW, WAVE_FORMAT_ALAW, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000007-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MULAW, WAVE_FORMAT_MULAW, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000031-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_MSGSM610, WAVE_FORMAT_GSM610, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000002-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ADPCM_MS, WAVE_FORMAT_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000022-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_TRUESPEECH, WAVE_FORMAT_DSPGROUP_TRUESPEECH, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, + 0x38, 0x9b, 0x71); + +// 00000075-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VOXWARE_RT29, WAVE_FORMAT_VOXWARE_RT29, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, + 0x9b, 0x71); + +// 324D4451-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_QDM2, 0x324D4451, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 63616C61-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ALAC, 0x63616C61, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// B82196E9-1B3F-4796-A636-46239087B38E dsfTAKsource specific +DEFINE_GUID(MEDIASUBTYPE_TAK, 0xB82196E9, 0x1B3F, 0x4796, 0xA6, 0x36, 0x46, 0x23, 0x90, 0x87, 0xB3, 0x8E); + +// 20534C41-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_ALS, 0x20534C41, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 0000729A-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_729A, 0x0000729A, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000133-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_G729, 0x00000133, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 36323767-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_G726, 0x36323767, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000401-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IMC, 0x00000401, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 0000011-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_IMA_WAV, WAVE_FORMAT_IMA_ADPCM, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {A23EB7FC-510B-466F-9FBF-5F878F69347C} LAVF/LAVC specific +DEFINE_GUID(MEDIASUBTYPE_BD_LPCM_AUDIO, 0xa23eb7fc, 0x510b, 0x466f, 0x9f, 0xbf, 0x5f, 0x87, 0x8f, 0x69, 0x34, 0x7c); + +// {53544441-0000-0010-8000-00AA00389B71} AAC-ADTS LAVF/LAVC specific +#define WAVE_FORMAT_AAC_ADTS mmioFOURCC('A', 'D', 'T', 'S') +DEFINE_GUID(MEDIASUBTYPE_AAC_ADTS, WAVE_FORMAT_AAC_ADTS, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {33534541-0000-0010-8000-00AA00389B71} S302M AES3 +#define WAVE_FORMAT_S302M_AES3 mmioFOURCC('A', 'E', 'S', '3') +DEFINE_GUID(MEDIASUBTYPE_AES3, WAVE_FORMAT_S302M_AES3, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// {949F97FD-56F6-4527-B4AE-DDEB375AB80F} Mpc-hc specific ! +DEFINE_GUID(MEDIASUBTYPE_HDMV_LPCM_AUDIO, 0x949f97fd, 0x56f6, 0x4527, 0xb4, 0xae, 0xdd, 0xeb, 0x37, 0x5a, 0xb8, 0xf); + +#define WAVE_FORMAT_MLP mmioFOURCC('M', 'L', 'P', ' ') +DEFINE_GUID(MEDIASUBTYPE_MLP, WAVE_FORMAT_MLP, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +#define WAVE_FORMAT_SPEEX 0xA109 +DEFINE_GUID(MEDIASUBTYPE_SPEEX, WAVE_FORMAT_SPEEX, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +#ifndef WAVE_FORMAT_OPUS +#define WAVE_FORMAT_OPUS 0x704F +#endif +DEFINE_GUID(MEDIASUBTYPE_OPUS, WAVE_FORMAT_OPUS, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_OPUS_OLD mmioFOURCC('O', 'P', 'U', 'S') +DEFINE_GUID(MEDIASUBTYPE_OPUS_OLD, WAVE_FORMAT_OPUS_OLD, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_DSDL mmioFOURCC('D', 'S', 'D', 'L') +DEFINE_GUID(MEDIASUBTYPE_DSDL, WAVE_FORMAT_DSDL, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_DSDM mmioFOURCC('D', 'S', 'D', 'M') +DEFINE_GUID(MEDIASUBTYPE_DSDM, WAVE_FORMAT_DSDM, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_DSD1 mmioFOURCC('D', 'S', 'D', '1') +DEFINE_GUID(MEDIASUBTYPE_DSD1, WAVE_FORMAT_DSD1, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +#define WAVE_FORMAT_DSD8 mmioFOURCC('D', 'S', 'D', '8') +DEFINE_GUID(MEDIASUBTYPE_DSD8, WAVE_FORMAT_DSD8, 0x000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000014-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_G723, 0x00000014, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 00000111-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_VIVO_G723, 0x00000111, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +// 20455041-0000-0010-8000-00AA00389B71 +DEFINE_GUID(MEDIASUBTYPE_APE, 0x20455041, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + + +struct WAVEFORMATEX_HDMV_LPCM : public WAVEFORMATEX +{ + BYTE channel_conf; + + struct WAVEFORMATEX_HDMV_LPCM() + { + memset(this, 0, sizeof(*this)); + cbSize = sizeof(WAVEFORMATEX_HDMV_LPCM) - sizeof(WAVEFORMATEX); + } +}; + +// {AFBC2343-3DCB-4047-9655-E1E62A61B1C5} +DEFINE_GUID(MEDIASUBTYPE_FFMPEG_AUDIO, 0xafbc2343, 0x3dcb, 0x4047, 0x96, 0x55, 0xe1, 0xe6, 0x2a, 0x61, 0xb1, 0xc5); + +// {35189950-CAC9-4C8D-819D-B6FAEE15DD9D} +DEFINE_GUID(FORMAT_WaveFormatExFFMPEG, 0x35189950, 0xcac9, 0x4c8d, 0x81, 0x9d, 0xb6, 0xfa, 0xee, 0x15, 0xdd, 0x9d); + +struct WAVEFORMATEXFFMPEG +{ + int nCodecId; + WAVEFORMATEX wfex; + + struct WAVEFORMATEXFFMPEG() + { + nCodecId = 0; + } +}; + +// {20884BC2-629F-45EA-B1C5-FA4FFA438250} +DEFINE_GUID(MEDIASUBTYPE_LAVBluRay, 0x20884bc2, 0x629f, 0x45ea, 0xb1, 0xc5, 0xfa, 0x4f, 0xfa, 0x43, 0x82, 0x50); + +// {D51BD5A3-7548-11cf-A520-0080C77EF58A} +DEFINE_GUID(CLSID_MultFile, 0xd51bd5a3, 0x7548, 0x11cf, 0xa5, 0x20, 0x0, 0x80, 0xc7, 0x7e, 0xf5, 0x8a); + +// Additionnal DXVA GUIDs + +// Intel ClearVideo VC1 bitstream decoder +DEFINE_GUID(DXVA_Intel_VC1_ClearVideo, 0xBCC5DB6D, 0xA2B6, 0x4AF0, 0xAC, 0xE4, 0xAD, 0xB1, 0xF7, 0x87, 0xBC, 0x89); +DEFINE_GUID(DXVA_Intel_VC1_ClearVideo_2, 0xE07EC519, 0xE651, 0x4CD6, 0xAC, 0x84, 0x13, 0x70, 0xCC, 0xEE, 0xC8, 0x51); + +// Intel ClearVideo H264 bitstream decoder +DEFINE_GUID(DXVA_Intel_H264_ClearVideo, 0x604F8E68, 0x4951, 0x4C54, 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6); + +// Nvidia MPEG-4 ASP bitstream decoder +// 9947EC6F-689B-11DC-A320-0019DBBC4184 +DEFINE_GUID(DXVA_MPEG4_ASP, 0x9947EC6F, 0x689B, 0x11DC, 0xA3, 0x20, 0x00, 0x19, 0xDB, 0xBC, 0x41, 0x84); + +// Filter/Commercial GUIDs + +DEFINE_GUID(CLSID_AC3Filter, 0xA753A1EC, 0x973E, 0x4718, 0xAF, 0x8E, 0xA3, 0xF5, 0x54, 0xD4, 0x5C, 0x44); + +// {212690FB-83E5-4526-8FD7-74478B7939CD} from wmcodecdsp.h +DEFINE_GUID(CLSID_CMPEG2VidDecoderDS, 0x212690FB, 0x83E5, 0x4526, 0x8F, 0xD7, 0x74, 0x47, 0x8B, 0x79, 0x39, 0xCD); + +// {39F498AF-1A09-4275-B193-673B0BA3D478} +DEFINE_GUID(CLSID_CMpeg2DecFilter, 0x39F498AF, 0x1A09, 0x4275, 0xB1, 0x93, 0x67, 0x3B, 0x0B, 0xA3, 0xD4, 0x78); + +// Nvidia Video Decoder - {71E4616A-DB5E-452B-8CA5-71D9CC7805E9} +DEFINE_GUID(CLSID_NvidiaVideoDecoder, 0x71E4616A, 0xDB5E, 0x452B, 0x8C, 0xA5, 0x71, 0xD9, 0xCC, 0x78, 0x05, 0xE9); + +// Sonic Cinemaster Video Decoder - {D7D50E8D-DD72-43C2-8587-A0C197D837D2} +DEFINE_GUID(CLSID_SonicCinemasterVideoDecoder, 0xD7D50E8D, 0xDD72, 0x43C2, 0x85, 0x87, 0xA0, 0xC1, 0x97, 0xD8, 0x37, 0xD2); + +// RDP DirectShow Redirection Filter - {AB9D6472-752F-43F6-B29E-61207BDA8E06} +DEFINE_GUID(CLSID_RDPDShowRedirectionFilter, 0xAB9D6472, 0x752F, 0x43F6, 0xB2, 0x9E, 0x61, 0x20, 0x7B, 0xDA, 0x8E, 0x06); + +// ReClock - {9DC15360-914C-46B8-B9DF-E67FD36C6A} +DEFINE_GUID(CLSID_ReClock, 0x9DC15360, 0x914C, 0x46B8, 0xB9, 0xDF, 0xBF, 0xE6, 0x7F, 0xD3, 0x6C, 0x6A); + +// MPC(BE) Audio Renderer - {601D2A2B-9CDE-40BD-8650-0485E3522727} +DEFINE_GUID(CLSID_MPCBEAudioRenderer, 0x601D2A2B, 0x9CDE, 0x40BD, 0x86, 0x50, 0x04, 0x85, 0xE3, 0x52, 0x27, 0x27); + +// Morgan's Stream Switcher - {D3CD7858-971A-4838-ACEC-40CA5D529DC8} +DEFINE_GUID(CLSID_MorganStreamSwitcher, 0xD3CD7858, 0x971A, 0x4838, 0xAC, 0xEC, 0x40, 0xCA, 0x5D, 0x52, 0x9D, 0xC8); + +// FFDShow DXVA Decoder - {0B0EFF97-C750-462C-9488-B10E7D87F1A6} +DEFINE_GUID(CLSID_FFDShowDXVADecoder, 0x0B0EFF97, 0xC750, 0x462C, 0x94, 0x88, 0xB1, 0x0E, 0x7D, 0x87, 0xF1, 0xA6); + +// Microsoft DTV-DVD Audio Decoder - {E1F1A0B8-BEEE-490D-BA7C-066C40B5E2B9} +DEFINE_GUID(CLSID_MSDVTDVDAudioDecoder, 0xE1F1A0B8, 0xBEEE, 0x490D, 0xBA, 0x7C, 0x06, 0x6C, 0x40, 0xB5, 0xE2, 0xB9); + +// Old MPC-HC filters +DEFINE_GUID(CLSID_MPCMpegSplitter, 0xDC257063, 0x045F, 0x4BE2, 0xBD, 0x5B, 0xE1, 0x22, 0x79, 0xC4, 0x64, 0xF0); +DEFINE_GUID(CLSID_MPCMpegSplitterSource, 0x1365BE7A, 0xC86A, 0x473C, 0x9A, 0x41, 0xC0, 0xA6, 0xE8, 0x2C, 0x9F, 0xA3); +DEFINE_GUID(CLSID_MPCVideoDecoder, 0x008BAC12, 0xFBAF, 0x497b, 0x96, 0x70, 0xBC, 0x6F, 0x6F, 0xBA, 0xE2, 0xC4); +DEFINE_GUID(CLSID_MPCShoutcastSource, 0x68F540E9, 0x766F, 0x44d2, 0xAB, 0x07, 0xE2, 0x6C, 0xC6, 0xD2, 0x7A, 0x79); + +// DirectVobSub || VSFilter (auto-loading version) - {9852A670-F845-491B-9BE6-EBD841B8A613} +DEFINE_GUID(CLSID_VSFilter, 0x9852A670, 0xF845, 0x491B, 0x9B, 0xE6, 0xEB, 0xD8, 0x41, 0xB8, 0xA6, 0x13); + +// DirectVobSub || VSFilter - {93A22E7A-5091-45EF-BA61-6DA26156A5D0} +DEFINE_GUID(CLSID_VSFilter2, 0x93A22E7A, 0x5091, 0x45EF, 0xBA, 0x61, 0x6D, 0xA2, 0x61, 0x56, 0xA5, 0xD0); + +// XySubFilter - {2DFCB782-EC20-4A7C-B530-4577ADB33F21} +DEFINE_GUID(CLSID_XySubFilter, 0x2DFCB782, 0xEC20, 0x4A7C, 0xB5, 0x30, 0x45, 0x77, 0xAD, 0xB3, 0x3F, 0x21); + +// XySubFilterAutoLoader - {6B237877-902B-4C6C-92F6-E63169A5166C} +DEFINE_GUID(CLSID_XySubFilter_AutoLoader, 0x6B237877, 0x902B, 0x4C6C, 0x92, 0xF6, 0xE6, 0x31, 0x69, 0xA5, 0x16, 0x6C); + +// sanear (internal version) +// SaneAudioRenderer::Factory::GetFilterGuid() is the right way do optain it, +// but we link DSUtil to everything and consequently will have to link sanear to everything. +DEFINE_GUID(CLSID_SANEAR_INTERNAL, 0x2AE00773, 0x819A, 0x40FB, 0xA5, 0x54, 0x54, 0x82, 0x7E, 0x11, 0x63, 0x59); + +// sanear (standalone version) - {DF557071-C9FD-433A-9627-81E0D3640ED9} +DEFINE_GUID(CLSID_SANEAR, 0xdf557071, 0xc9fd, 0x433a, 0x96, 0x27, 0x81, 0xe0, 0xd3, 0x64, 0xe, 0xd9); + +// AssFilter - {8A3704F3-BE3B-4944-9FF3-EE8757FDBDA5} +DEFINE_GUID(CLSID_AssFilter, 0x8A3704F3, 0xBE3B, 0x4944, 0x9F, 0xF3, 0xEE, 0x87, 0x57, 0xFD, 0xBD, 0xA5); + +// AssFilterAutoLoader - {8A6DFC6A-0A79-4790-85DA-0688B8093B54} +DEFINE_GUID(CLSID_AssFilter_AutoLoader, 0x8A6DFC6A, 0x0A79, 0x4790, 0x85, 0xDA, 0x06, 0x88, 0xB8, 0x09, 0x3B, 0x54); + +// Generate Still Video - {7DF62B50-6843-11D2-9EEB-006008039E37} +DEFINE_GUID(CLSID_StillVideo, 0x7DF62B50, 0x6843, 0x11D2, 0x9E, 0xEB, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); + +// MPC Image Source - {7DB5C3B3-2419-4508-B1D0-F2D22DA8E439} +DEFINE_GUID(CLSID_MPCImageSource, 0x7DB5C3B3, 0x2419, 0x4508, 0xB1, 0xD0, 0xF2, 0xD2, 0x2D, 0xA8, 0xE4, 0x39); + +DEFINE_GUID(CLSID_Generic_WDM_FilterProxy, 0x17CCA71B, 0xECD7, 0x11D0, 0xB9, 0x08, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96); + +// uncompressed +#define DEFINE_GUID_FOURCC(FOURCC) \ + DEFINE_GUID(MEDIASUBTYPE_##FOURCC, FOURCC_##FOURCC, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); + +//uncompressed +#define FOURCC_YUY2 mmioFOURCC('Y','U','Y','2') +#define FOURCC_V422 mmioFOURCC('V','4','2','2') +#define FOURCC_YV12 mmioFOURCC('Y','V','1','2') +#define FOURCC_YVYU mmioFOURCC('Y','V','Y','U') +#define FOURCC_UYVY mmioFOURCC('U','Y','V','Y') +#define FOURCC_YUYV mmioFOURCC('Y','U','Y','V') +#define FOURCC_VYUY mmioFOURCC('V','Y','U','Y') +#define FOURCC_I420 mmioFOURCC('I','4','2','0') +#define FOURCC_IYUV mmioFOURCC('I','Y','U','V') +#define FOURCC_444P mmioFOURCC('4','4','4','P') +#define FOURCC_YV24 mmioFOURCC('Y','V','2','4') // YUV 4:4:4 +#define FOURCC_422P mmioFOURCC('4','2','2','P') +#define FOURCC_YV16 mmioFOURCC('Y','V','1','6') // YUV 4:2:2 +#define FOURCC_411P mmioFOURCC('4','1','1','P') +#define FOURCC_Y41B mmioFOURCC('Y','4','1','B') // YUV 4:1:1 +#define FOURCC_410P mmioFOURCC('4','1','0','P') +#define FOURCC_PAL1 mmioFOURCC('P','A','L','1') +#define FOURCC_PAL4 mmioFOURCC('P','A','L','4') +#define FOURCC_PAL8 mmioFOURCC('P','A','L','8') +#define FOURCC_RGB2 mmioFOURCC('R','G','B','2') +#define FOURCC_RGB3 mmioFOURCC('R','G','B','3') +#define FOURCC_RGB5 mmioFOURCC('R','G','B','5') +#define FOURCC_RGB6 mmioFOURCC('R','G','B','6') +#define FOURCC_CLJR mmioFOURCC('C','L','J','R') +#define FOURCC_Y800 mmioFOURCC('Y','8','0','0') +#define FOURCC_NV12 mmioFOURCC('N','V','1','2') +#define FOURCC_NV21 mmioFOURCC('N','V','2','1') +#define FOURCC_P010 mmioFOURCC('P','0','1','0') +#define FOURCC_P016 mmioFOURCC('P','0','1','6') +#define FOURCC_420R mmioFOURCC('4','2','0','R') +#define FOURCC_422R mmioFOURCC('4','2','2','R') +#define FOURCC_444R mmioFOURCC('4','4','4','R') +#define FOURCC_P210 mmioFOURCC('P','2','1','0') +#define FOURCC_P216 mmioFOURCC('P','2','1','6') +#define FOURCC_AYUV mmioFOURCC('A','Y','U','V') +#define FOURCC_Y416 mmioFOURCC('Y','4','1','6') + +#define FOURCC_nv12 mmioFOURCC('n','v','1','2') +#define FOURCC_yv12 mmioFOURCC('y','v','1','2') +#define FOURCC_ICM1 mmioFOURCC('I','C','M','1') +#define FOURCC_ICM2 mmioFOURCC('I','C','M','2') +#define FOURCC_ICM3 mmioFOURCC('I','C','M','3') +#define FOURCC_ICM4 mmioFOURCC('I','C','M','4') +#define FOURCC_yuy2 mmioFOURCC('y','u','y','2') +#define FOURCC_uyvy mmioFOURCC('u','y','v','y') +#define FOURCC_cyuv mmioFOURCC('c','y','u','v') +#define FOURCC_UYNV mmioFOURCC('U','Y','N','V') +#define FOURCC_UYNY mmioFOURCC('U','Y','N','Y') +#define FOURCC_HDYC mmioFOURCC('H','D','Y','C') +#define FOURCC_uyv1 mmioFOURCC('u','y','v','1') +#define FOURCC_2Vu1 mmioFOURCC('2','V','u','1') +#define FOURCC_VDTZ mmioFOURCC('V','D','T','Z') +#define FOURCC_YUV2 mmioFOURCC('Y','U','V','2') +#define FOURCC_yuv2 mmioFOURCC('y','u','v','2') +#define FOURCC_2vuy mmioFOURCC('2','v','u','y') +#define FOURCC_2Vuy mmioFOURCC('2','V','u','y') +#define FOURCC_yuvu mmioFOURCC('y','u','v','u') +#define FOURCC_yuvs mmioFOURCC('y','u','v','s') +#define FOURCC_I422 mmioFOURCC('I','4','2','2') +#define FOURCC_Y422 mmioFOURCC('Y','4','2','2') +#define FOURCC_V422 mmioFOURCC('V','4','2','2') +#define FOURCC_Y42B mmioFOURCC('Y','4','2','B') +#define FOURCC_P422 mmioFOURCC('P','4','2','2') +#define FOURCC_YUNV mmioFOURCC('Y','U','N','V') +#define FOURCC_AVUI mmioFOURCC('A','V','U','I') +#define FOURCC_I444 mmioFOURCC('I','4','4','4') +#define FOURCC_v308 mmioFOURCC('v','3','0','8') +#define FOURCC_v408 mmioFOURCC('v','4','0','8') +#define FOURCC_24BG mmioFOURCC('2','4','B','G') +#define FOURCC_BGRA mmioFOURCC('B','G','R','A') +#define FOURCC_ABGR mmioFOURCC('A','B','G','R') +#define FOURCC_RGBA mmioFOURCC('R','G','B','A') +#define FOURCC_RGB0 mmioFOURCC('R','G','B','0') +#define FOURCC_0RGB mmioFOURCC('0','R','G','B') +#define FOURCC_b48r mmioFOURCC('b','4','8','r') +#define FOURCC_RBA64 mmioFOURCC('R','B','A',64) +#define FOURCC_64RBA mmioFOURCC(64,'R','B','A') +#define FOURCC_b64a mmioFOURCC('b','6','4','a') +#define FOURCC_Y410 mmioFOURCC('Y','4','1','0') +#define FOURCC_v216 mmioFOURCC('v','2','1','6') +#define FOURCC_v416 mmioFOURCC('v','4','1','6') +#define FOURCC_Y8 mmioFOURCC('Y','8',0x20,0x20) +#define FOURCC_Y16 mmioFOURCC('Y','1',0,16) + +DEFINE_GUID_FOURCC(422P) +DEFINE_GUID_FOURCC(444P) +DEFINE_GUID_FOURCC(411P) +DEFINE_GUID_FOURCC(410P) +DEFINE_GUID_FOURCC(VYUY) +DEFINE_GUID_FOURCC(Y800) +DEFINE_GUID_FOURCC(NV21) +DEFINE_GUID_FOURCC(YV16) +DEFINE_GUID_FOURCC(YV24) +DEFINE_GUID_FOURCC(420R) +DEFINE_GUID_FOURCC(422R) +DEFINE_GUID_FOURCC(444R) +DEFINE_GUID_FOURCC(Y416) + +DEFINE_GUID_FOURCC(nv12) +DEFINE_GUID_FOURCC(yv12) +DEFINE_GUID_FOURCC(ICM1) +DEFINE_GUID_FOURCC(ICM2) +DEFINE_GUID_FOURCC(ICM3) +DEFINE_GUID_FOURCC(ICM4) +DEFINE_GUID_FOURCC(yuy2) +DEFINE_GUID_FOURCC(uyvy) +DEFINE_GUID_FOURCC(cyuv) +DEFINE_GUID_FOURCC(UYNV) +DEFINE_GUID_FOURCC(UYNY) +DEFINE_GUID_FOURCC(HDYC) +DEFINE_GUID_FOURCC(uyv1) +DEFINE_GUID_FOURCC(2Vu1) +DEFINE_GUID_FOURCC(VDTZ) +DEFINE_GUID_FOURCC(YUV2) +DEFINE_GUID_FOURCC(yuv2) +DEFINE_GUID_FOURCC(2vuy) +DEFINE_GUID_FOURCC(2Vuy) +DEFINE_GUID_FOURCC(yuvu) +DEFINE_GUID_FOURCC(yuvs) +DEFINE_GUID_FOURCC(I422) +DEFINE_GUID_FOURCC(Y422) +DEFINE_GUID_FOURCC(V422) +DEFINE_GUID_FOURCC(Y42B) +DEFINE_GUID_FOURCC(P422) +DEFINE_GUID_FOURCC(YUNV) +DEFINE_GUID_FOURCC(AVUI) +DEFINE_GUID_FOURCC(I444) +DEFINE_GUID_FOURCC(v308) +DEFINE_GUID_FOURCC(v408) +DEFINE_GUID_FOURCC(24BG) +DEFINE_GUID_FOURCC(BGRA) +DEFINE_GUID_FOURCC(ABGR) +DEFINE_GUID_FOURCC(RGBA) +DEFINE_GUID_FOURCC(RGB0) +DEFINE_GUID_FOURCC(0RGB) +DEFINE_GUID_FOURCC(b48r) +DEFINE_GUID_FOURCC(RBA64) +DEFINE_GUID_FOURCC(64RBA) +DEFINE_GUID_FOURCC(b64a) +DEFINE_GUID_FOURCC(Y410) +DEFINE_GUID_FOURCC(v216) +DEFINE_GUID_FOURCC(v416) +DEFINE_GUID_FOURCC(Y8) +DEFINE_GUID_FOURCC(Y16) diff --git a/include/unrar.h b/include/unrar.h index 7225d1420c4..268f00a069d 100644 --- a/include/unrar.h +++ b/include/unrar.h @@ -1,185 +1,185 @@ -#ifndef _UNRAR_DLL_ -#define _UNRAR_DLL_ - -#pragma pack(1) - -#define ERAR_SUCCESS 0 -#define ERAR_END_ARCHIVE 10 -#define ERAR_NO_MEMORY 11 -#define ERAR_BAD_DATA 12 -#define ERAR_BAD_ARCHIVE 13 -#define ERAR_UNKNOWN_FORMAT 14 -#define ERAR_EOPEN 15 -#define ERAR_ECREATE 16 -#define ERAR_ECLOSE 17 -#define ERAR_EREAD 18 -#define ERAR_EWRITE 19 -#define ERAR_SMALL_BUF 20 -#define ERAR_UNKNOWN 21 -#define ERAR_MISSING_PASSWORD 22 -#define ERAR_EREFERENCE 23 -#define ERAR_BAD_PASSWORD 24 - -#define RAR_OM_LIST 0 -#define RAR_OM_EXTRACT 1 -#define RAR_OM_LIST_INCSPLIT 2 - -#define RAR_SKIP 0 -#define RAR_TEST 1 -#define RAR_EXTRACT 2 - -#define RAR_VOL_ASK 0 -#define RAR_VOL_NOTIFY 1 - -#define RAR_DLL_VERSION 8 - -#define RAR_HASH_NONE 0 -#define RAR_HASH_CRC32 1 -#define RAR_HASH_BLAKE2 2 - - -#ifdef _UNIX -#define CALLBACK -#define PASCAL -#define LONG long -#define HANDLE void * -#define LPARAM long -#define UINT unsigned int -#endif - -#define RHDF_SPLITBEFORE 0x01 -#define RHDF_SPLITAFTER 0x02 -#define RHDF_ENCRYPTED 0x04 -#define RHDF_SOLID 0x10 -#define RHDF_DIRECTORY 0x20 - - -struct RARHeaderData -{ - char ArcName[260]; - char FileName[260]; - unsigned int Flags; - unsigned int PackSize; - unsigned int UnpSize; - unsigned int HostOS; - unsigned int FileCRC; - unsigned int FileTime; - unsigned int UnpVer; - unsigned int Method; - unsigned int FileAttr; - char *CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; -}; - - -struct RARHeaderDataEx -{ - char ArcName[1024]; - wchar_t ArcNameW[1024]; - char FileName[1024]; - wchar_t FileNameW[1024]; - unsigned int Flags; - unsigned int PackSize; - unsigned int PackSizeHigh; - unsigned int UnpSize; - unsigned int UnpSizeHigh; - unsigned int HostOS; - unsigned int FileCRC; - unsigned int FileTime; - unsigned int UnpVer; - unsigned int Method; - unsigned int FileAttr; - char *CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; - unsigned int DictSize; - unsigned int HashType; - char Hash[32]; - unsigned int RedirType; - wchar_t *RedirName; - unsigned int RedirNameSize; - unsigned int DirTarget; - unsigned int MtimeLow; - unsigned int MtimeHigh; - unsigned int CtimeLow; - unsigned int CtimeHigh; - unsigned int AtimeLow; - unsigned int AtimeHigh; - unsigned int Reserved[988]; -}; - - -struct RAROpenArchiveData -{ - char *ArcName; - unsigned int OpenMode; - unsigned int OpenResult; - char *CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; -}; - -typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2); - -#define ROADF_VOLUME 0x0001 -#define ROADF_COMMENT 0x0002 -#define ROADF_LOCK 0x0004 -#define ROADF_SOLID 0x0008 -#define ROADF_NEWNUMBERING 0x0010 -#define ROADF_SIGNED 0x0020 -#define ROADF_RECOVERY 0x0040 -#define ROADF_ENCHEADERS 0x0080 -#define ROADF_FIRSTVOLUME 0x0100 - -struct RAROpenArchiveDataEx -{ - char *ArcName; - wchar_t *ArcNameW; - unsigned int OpenMode; - unsigned int OpenResult; - char *CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; - unsigned int Flags; - UNRARCALLBACK Callback; - LPARAM UserData; - unsigned int Reserved[28]; -}; - -enum UNRARCALLBACK_MESSAGES { - UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW, - UCM_NEEDPASSWORDW -}; - -typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); -typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); - -#ifdef __cplusplus -extern "C" { -#endif - -typedef HANDLE (PASCAL *RAROpenArchive)(struct RAROpenArchiveData *ArchiveData); -typedef HANDLE (PASCAL *RAROpenArchiveEx)(struct RAROpenArchiveDataEx *ArchiveData); -typedef int (PASCAL *RARCloseArchive)(HANDLE hArcData); -typedef int (PASCAL *RARReadHeader)(HANDLE hArcData,struct RARHeaderData *HeaderData); -typedef int (PASCAL *RARReadHeaderEx)(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); -typedef int (PASCAL *RARProcessFile)(HANDLE hArcData,int Operation,char *DestPath,char *DestName); -typedef int (PASCAL *RARProcessFileW)(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); -typedef void (PASCAL *RARSetCallback)(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); -typedef void (PASCAL *RARSetChangeVolProc)(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); -typedef void (PASCAL *RARSetProcessDataProc)(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); -typedef void (PASCAL *RARSetPassword)(HANDLE hArcData,char *Password); -typedef int (PASCAL *RARGetDllVersion)(); - -#ifdef __cplusplus -} -#endif - -#pragma pack() - -#endif +#ifndef _UNRAR_DLL_ +#define _UNRAR_DLL_ + +#pragma pack(1) + +#define ERAR_SUCCESS 0 +#define ERAR_END_ARCHIVE 10 +#define ERAR_NO_MEMORY 11 +#define ERAR_BAD_DATA 12 +#define ERAR_BAD_ARCHIVE 13 +#define ERAR_UNKNOWN_FORMAT 14 +#define ERAR_EOPEN 15 +#define ERAR_ECREATE 16 +#define ERAR_ECLOSE 17 +#define ERAR_EREAD 18 +#define ERAR_EWRITE 19 +#define ERAR_SMALL_BUF 20 +#define ERAR_UNKNOWN 21 +#define ERAR_MISSING_PASSWORD 22 +#define ERAR_EREFERENCE 23 +#define ERAR_BAD_PASSWORD 24 + +#define RAR_OM_LIST 0 +#define RAR_OM_EXTRACT 1 +#define RAR_OM_LIST_INCSPLIT 2 + +#define RAR_SKIP 0 +#define RAR_TEST 1 +#define RAR_EXTRACT 2 + +#define RAR_VOL_ASK 0 +#define RAR_VOL_NOTIFY 1 + +#define RAR_DLL_VERSION 8 + +#define RAR_HASH_NONE 0 +#define RAR_HASH_CRC32 1 +#define RAR_HASH_BLAKE2 2 + + +#ifdef _UNIX +#define CALLBACK +#define PASCAL +#define LONG long +#define HANDLE void * +#define LPARAM long +#define UINT unsigned int +#endif + +#define RHDF_SPLITBEFORE 0x01 +#define RHDF_SPLITAFTER 0x02 +#define RHDF_ENCRYPTED 0x04 +#define RHDF_SOLID 0x10 +#define RHDF_DIRECTORY 0x20 + + +struct RARHeaderData +{ + char ArcName[260]; + char FileName[260]; + unsigned int Flags; + unsigned int PackSize; + unsigned int UnpSize; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + + +struct RARHeaderDataEx +{ + char ArcName[1024]; + wchar_t ArcNameW[1024]; + char FileName[1024]; + wchar_t FileNameW[1024]; + unsigned int Flags; + unsigned int PackSize; + unsigned int PackSizeHigh; + unsigned int UnpSize; + unsigned int UnpSizeHigh; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int DictSize; + unsigned int HashType; + char Hash[32]; + unsigned int RedirType; + wchar_t *RedirName; + unsigned int RedirNameSize; + unsigned int DirTarget; + unsigned int MtimeLow; + unsigned int MtimeHigh; + unsigned int CtimeLow; + unsigned int CtimeHigh; + unsigned int AtimeLow; + unsigned int AtimeHigh; + unsigned int Reserved[988]; +}; + + +struct RAROpenArchiveData +{ + char *ArcName; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + +typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2); + +#define ROADF_VOLUME 0x0001 +#define ROADF_COMMENT 0x0002 +#define ROADF_LOCK 0x0004 +#define ROADF_SOLID 0x0008 +#define ROADF_NEWNUMBERING 0x0010 +#define ROADF_SIGNED 0x0020 +#define ROADF_RECOVERY 0x0040 +#define ROADF_ENCHEADERS 0x0080 +#define ROADF_FIRSTVOLUME 0x0100 + +struct RAROpenArchiveDataEx +{ + char *ArcName; + wchar_t *ArcNameW; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int Flags; + UNRARCALLBACK Callback; + LPARAM UserData; + unsigned int Reserved[28]; +}; + +enum UNRARCALLBACK_MESSAGES { + UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW, + UCM_NEEDPASSWORDW +}; + +typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); +typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); + +#ifdef __cplusplus +extern "C" { +#endif + +typedef HANDLE (PASCAL *RAROpenArchive)(struct RAROpenArchiveData *ArchiveData); +typedef HANDLE (PASCAL *RAROpenArchiveEx)(struct RAROpenArchiveDataEx *ArchiveData); +typedef int (PASCAL *RARCloseArchive)(HANDLE hArcData); +typedef int (PASCAL *RARReadHeader)(HANDLE hArcData,struct RARHeaderData *HeaderData); +typedef int (PASCAL *RARReadHeaderEx)(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); +typedef int (PASCAL *RARProcessFile)(HANDLE hArcData,int Operation,char *DestPath,char *DestName); +typedef int (PASCAL *RARProcessFileW)(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); +typedef void (PASCAL *RARSetCallback)(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); +typedef void (PASCAL *RARSetChangeVolProc)(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); +typedef void (PASCAL *RARSetProcessDataProc)(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); +typedef void (PASCAL *RARSetPassword)(HANDLE hArcData,char *Password); +typedef int (PASCAL *RARGetDllVersion)(); + +#ifdef __cplusplus +} +#endif + +#pragma pack() + +#endif diff --git a/include/vd2/Copying b/include/vd2/Copying index a43ea2126fb..92851102051 100644 --- a/include/vd2/Copying +++ b/include/vd2/Copying @@ -1,339 +1,339 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program 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 2 of the License, or - (at your option) any later version. - - This program 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/include/vd2/OldFilterSDK/Filter.h b/include/vd2/OldFilterSDK/Filter.h index 1d74e7ae38c..c2a40040384 100644 --- a/include/vd2/OldFilterSDK/Filter.h +++ b/include/vd2/OldFilterSDK/Filter.h @@ -1,57 +1,57 @@ -#ifndef f_FILTER_H -#define f_FILTER_H - -#include -#include - -// This is really dumb, but necessary to support VTbls in C++. - -typedef struct VDXFilterVTbls { - void *pvtblVBitmap; -} FilterVTbls; - -#ifdef VDEXT_MAIN - VDXFilterVTbls g_vtbls; -#elif defined(VDEXT_NOTMAIN) - extern VDXFilterVTbls g_vtbls; -#endif - -#define INITIALIZE_VTBLS ff->InitVTables(&g_vtbls) - -#include "VBitmap.h" - -typedef ::VDXFilterInitProc FilterInitProc; -typedef ::VDXFilterDeinitProc FilterDeinitProc; -typedef ::VDXFilterRunProc FilterRunProc; -typedef ::VDXFilterParamProc FilterParamProc; -typedef ::VDXFilterConfigProc FilterConfigProc; -typedef ::VDXFilterStringProc FilterStringProc; -typedef ::VDXFilterStartProc FilterStartProc; -typedef ::VDXFilterEndProc FilterEndProc; -typedef ::VDXFilterScriptStrProc FilterScriptStrProc; -typedef ::VDXFilterStringProc2 FilterStringProc2; -typedef ::VDXFilterSerialize FilterSerialize; -typedef ::VDXFilterDeserialize FilterDeserialize; -typedef ::VDXFilterCopy FilterCopy; - -typedef ::VDXFilterModuleInitProc FilterModuleInitProc; -typedef ::VDXFilterModuleDeinitProc FilterModuleDeinitProc; - -////////// - -typedef ::VDXFilterPreviewButtonCallback FilterPreviewButtonCallback; -typedef ::VDXFilterPreviewSampleCallback FilterPreviewSampleCallback; - -typedef ::IVDXFilterPreview IFilterPreview; - -////////// - -typedef ::VDXFilterModule FilterModule; -typedef ::VDXFilterDefinition FilterDefinition; -typedef ::VDXFilterStateInfo FilterStateInfo; -typedef ::VDXFBitmap VFBitmap; - -typedef ::VDXFilterActivation FilterActivation; -typedef ::VDXFilterFunctions FilterFunctions; - -#endif +#ifndef f_FILTER_H +#define f_FILTER_H + +#include +#include + +// This is really dumb, but necessary to support VTbls in C++. + +typedef struct VDXFilterVTbls { + void *pvtblVBitmap; +} FilterVTbls; + +#ifdef VDEXT_MAIN + VDXFilterVTbls g_vtbls; +#elif defined(VDEXT_NOTMAIN) + extern VDXFilterVTbls g_vtbls; +#endif + +#define INITIALIZE_VTBLS ff->InitVTables(&g_vtbls) + +#include "VBitmap.h" + +typedef ::VDXFilterInitProc FilterInitProc; +typedef ::VDXFilterDeinitProc FilterDeinitProc; +typedef ::VDXFilterRunProc FilterRunProc; +typedef ::VDXFilterParamProc FilterParamProc; +typedef ::VDXFilterConfigProc FilterConfigProc; +typedef ::VDXFilterStringProc FilterStringProc; +typedef ::VDXFilterStartProc FilterStartProc; +typedef ::VDXFilterEndProc FilterEndProc; +typedef ::VDXFilterScriptStrProc FilterScriptStrProc; +typedef ::VDXFilterStringProc2 FilterStringProc2; +typedef ::VDXFilterSerialize FilterSerialize; +typedef ::VDXFilterDeserialize FilterDeserialize; +typedef ::VDXFilterCopy FilterCopy; + +typedef ::VDXFilterModuleInitProc FilterModuleInitProc; +typedef ::VDXFilterModuleDeinitProc FilterModuleDeinitProc; + +////////// + +typedef ::VDXFilterPreviewButtonCallback FilterPreviewButtonCallback; +typedef ::VDXFilterPreviewSampleCallback FilterPreviewSampleCallback; + +typedef ::IVDXFilterPreview IFilterPreview; + +////////// + +typedef ::VDXFilterModule FilterModule; +typedef ::VDXFilterDefinition FilterDefinition; +typedef ::VDXFilterStateInfo FilterStateInfo; +typedef ::VDXFBitmap VFBitmap; + +typedef ::VDXFilterActivation FilterActivation; +typedef ::VDXFilterFunctions FilterFunctions; + +#endif diff --git a/include/vd2/OldFilterSDK/ScriptError.h b/include/vd2/OldFilterSDK/ScriptError.h index d024eca8419..900a9fc0793 100644 --- a/include/vd2/OldFilterSDK/ScriptError.h +++ b/include/vd2/OldFilterSDK/ScriptError.h @@ -1,8 +1,8 @@ -#ifndef f_SYLIA_SCRIPTERROR_H -#define f_SYLIA_SCRIPTERROR_H - -#include - -typedef ::VDXScriptError CScriptError; - -#endif +#ifndef f_SYLIA_SCRIPTERROR_H +#define f_SYLIA_SCRIPTERROR_H + +#include + +typedef ::VDXScriptError CScriptError; + +#endif diff --git a/include/vd2/OldFilterSDK/ScriptInterpreter.h b/include/vd2/OldFilterSDK/ScriptInterpreter.h index 62e19772a96..fd12e969e7b 100644 --- a/include/vd2/OldFilterSDK/ScriptInterpreter.h +++ b/include/vd2/OldFilterSDK/ScriptInterpreter.h @@ -1,11 +1,11 @@ -#ifndef f_SYLIA_SCRIPTINTERPRETER_H -#define f_SYLIA_SCRIPTINTERPRETER_H - -#include - -typedef ::VDXScriptValue CScriptValue; -typedef ::VDXScriptError CScriptError; -typedef ::VDXScriptObject CScriptObject; -typedef ::IVDXScriptInterpreter IScriptInterpreter; - -#endif +#ifndef f_SYLIA_SCRIPTINTERPRETER_H +#define f_SYLIA_SCRIPTINTERPRETER_H + +#include + +typedef ::VDXScriptValue CScriptValue; +typedef ::VDXScriptError CScriptError; +typedef ::VDXScriptObject CScriptObject; +typedef ::IVDXScriptInterpreter IScriptInterpreter; + +#endif diff --git a/include/vd2/OldFilterSDK/ScriptValue.h b/include/vd2/OldFilterSDK/ScriptValue.h index 60aae619908..0d8628469a4 100644 --- a/include/vd2/OldFilterSDK/ScriptValue.h +++ b/include/vd2/OldFilterSDK/ScriptValue.h @@ -1,17 +1,17 @@ -#ifndef f_SYLIA_SCRIPTVALUE_H -#define f_SYLIA_SCRIPTVALUE_H - -#include - -typedef ::VDXScriptObject CScriptObject; -typedef ::VDXScriptValue CScriptValue; -typedef ::IVDXScriptInterpreter IScriptInterpreter; - -typedef ::VDXScriptFunctionPtr ScriptFunctionPtr; -typedef ::VDXVoidScriptFunctionPtr ScriptVoidFunctionPtr; -typedef ::VDXIntScriptFunctionPtr ScriptIntFunctionPtr; - -typedef ::VDXScriptFunctionDef ScriptFunctionDef; -typedef ::VDXScriptObject CScriptObject; - -#endif +#ifndef f_SYLIA_SCRIPTVALUE_H +#define f_SYLIA_SCRIPTVALUE_H + +#include + +typedef ::VDXScriptObject CScriptObject; +typedef ::VDXScriptValue CScriptValue; +typedef ::IVDXScriptInterpreter IScriptInterpreter; + +typedef ::VDXScriptFunctionPtr ScriptFunctionPtr; +typedef ::VDXVoidScriptFunctionPtr ScriptVoidFunctionPtr; +typedef ::VDXIntScriptFunctionPtr ScriptIntFunctionPtr; + +typedef ::VDXScriptFunctionDef ScriptFunctionDef; +typedef ::VDXScriptObject CScriptObject; + +#endif diff --git a/include/vd2/OldFilterSDK/VBitmap.h b/include/vd2/OldFilterSDK/VBitmap.h index 7daa475eb84..08795ac5fa2 100644 --- a/include/vd2/OldFilterSDK/VBitmap.h +++ b/include/vd2/OldFilterSDK/VBitmap.h @@ -1,16 +1,16 @@ -#ifndef f_VIRTUALDUB_VBITMAP_H -#define f_VIRTUALDUB_VBITMAP_H - -#include -#include - -typedef unsigned Pixel; -typedef unsigned Pixel32; -typedef unsigned char Pixel8; -typedef int PixCoord; -typedef int PixDim; -typedef ptrdiff_t PixOffset; - -typedef ::VDXBitmap VBitmap; - -#endif +#ifndef f_VIRTUALDUB_VBITMAP_H +#define f_VIRTUALDUB_VBITMAP_H + +#include +#include + +typedef unsigned Pixel; +typedef unsigned Pixel32; +typedef unsigned char Pixel8; +typedef int PixCoord; +typedef int PixDim; +typedef ptrdiff_t PixOffset; + +typedef ::VDXBitmap VBitmap; + +#endif diff --git a/include/vd2/OldFilterSDK/VirtualDub.h b/include/vd2/OldFilterSDK/VirtualDub.h index 5195b15f55d..25e5fd47595 100644 --- a/include/vd2/OldFilterSDK/VirtualDub.h +++ b/include/vd2/OldFilterSDK/VirtualDub.h @@ -1,7 +1,7 @@ -#pragma once - -#include "Filter.h" -#include "ScriptInterpreter.h" -#include "ScriptError.h" -#include "ScriptValue.h" -#include "VBitmap.h" +#pragma once + +#include "Filter.h" +#include "ScriptInterpreter.h" +#include "ScriptError.h" +#include "ScriptValue.h" +#include "VBitmap.h" diff --git a/include/vd2/VDXFrame/Unknown.h b/include/vd2/VDXFrame/Unknown.h index 57c6b317db5..34de61f46f2 100644 --- a/include/vd2/VDXFrame/Unknown.h +++ b/include/vd2/VDXFrame/Unknown.h @@ -1,110 +1,110 @@ -// VDXFrame - Helper library for VirtualDub plugins -// Copyright (C) 2008 Avery Lee -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_VDXFRAME_UNKNOWN_H -#define f_VD2_VDXFRAME_UNKNOWN_H - -#include - -extern "C" long _InterlockedExchangeAdd(volatile long *p, long v); -#pragma intrinsic(_InterlockedExchangeAdd) - -template class vdxunknown : public T { -public: - vdxunknown() : mRefCount(0) {} - vdxunknown(const vdxunknown& src) : mRefCount(0) {} // do not copy the refcount - virtual ~vdxunknown() {} - - vdxunknown& operator=(const vdxunknown&) {} // do not copy the refcount - - virtual int VDXAPIENTRY AddRef() { - return _InterlockedExchangeAdd(&mRefCount, 1) + 1; - } - - virtual int VDXAPIENTRY Release() { - long rc = _InterlockedExchangeAdd(&mRefCount, -1) - 1; - if (!mRefCount) { - mRefCount = 1; - delete this; - return 0; - } - - return rc; - } - - virtual void *VDXAPIENTRY AsInterface(uint32 iid) { - if (iid == T::kIID) - return static_cast(this); - - if (iid == IVDXUnknown::kIID) - return static_cast(this); - - return NULL; - } - -protected: - volatile long mRefCount; -}; - -template class vdxunknown2 : public T1, public T2 { -public: - vdxunknown2() : mRefCount(0) {} - vdxunknown2(const vdxunknown2& src) : mRefCount(0) {} // do not copy the refcount - virtual ~vdxunknown2() {} - - vdxunknown2& operator=(const vdxunknown2&) {} // do not copy the refcount - - virtual int VDXAPIENTRY AddRef() { - return _InterlockedExchangeAdd(&mRefCount, 1) + 1; - } - - virtual int VDXAPIENTRY Release() { - long rc = _InterlockedExchangeAdd(&mRefCount, -1) - 1; - if (!mRefCount) { - mRefCount = 1; - delete this; - return 0; - } - - return rc; - } - - virtual void *VDXAPIENTRY AsInterface(uint32 iid) { - if (iid == T1::kIID) - return static_cast(this); - - if (iid == T2::kIID) - return static_cast(this); - - if (iid == IVDXUnknown::kIID) - return static_cast(static_cast(this)); - - return NULL; - } - -protected: - volatile long mRefCount; -}; - -#endif +// VDXFrame - Helper library for VirtualDub plugins +// Copyright (C) 2008 Avery Lee +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_VDXFRAME_UNKNOWN_H +#define f_VD2_VDXFRAME_UNKNOWN_H + +#include + +extern "C" long _InterlockedExchangeAdd(volatile long *p, long v); +#pragma intrinsic(_InterlockedExchangeAdd) + +template class vdxunknown : public T { +public: + vdxunknown() : mRefCount(0) {} + vdxunknown(const vdxunknown& src) : mRefCount(0) {} // do not copy the refcount + virtual ~vdxunknown() {} + + vdxunknown& operator=(const vdxunknown&) {} // do not copy the refcount + + virtual int VDXAPIENTRY AddRef() { + return _InterlockedExchangeAdd(&mRefCount, 1) + 1; + } + + virtual int VDXAPIENTRY Release() { + long rc = _InterlockedExchangeAdd(&mRefCount, -1) - 1; + if (!mRefCount) { + mRefCount = 1; + delete this; + return 0; + } + + return rc; + } + + virtual void *VDXAPIENTRY AsInterface(uint32 iid) { + if (iid == T::kIID) + return static_cast(this); + + if (iid == IVDXUnknown::kIID) + return static_cast(this); + + return NULL; + } + +protected: + volatile long mRefCount; +}; + +template class vdxunknown2 : public T1, public T2 { +public: + vdxunknown2() : mRefCount(0) {} + vdxunknown2(const vdxunknown2& src) : mRefCount(0) {} // do not copy the refcount + virtual ~vdxunknown2() {} + + vdxunknown2& operator=(const vdxunknown2&) {} // do not copy the refcount + + virtual int VDXAPIENTRY AddRef() { + return _InterlockedExchangeAdd(&mRefCount, 1) + 1; + } + + virtual int VDXAPIENTRY Release() { + long rc = _InterlockedExchangeAdd(&mRefCount, -1) - 1; + if (!mRefCount) { + mRefCount = 1; + delete this; + return 0; + } + + return rc; + } + + virtual void *VDXAPIENTRY AsInterface(uint32 iid) { + if (iid == T1::kIID) + return static_cast(this); + + if (iid == T2::kIID) + return static_cast(this); + + if (iid == IVDXUnknown::kIID) + return static_cast(static_cast(this)); + + return NULL; + } + +protected: + volatile long mRefCount; +}; + +#endif diff --git a/include/vd2/VDXFrame/VideoFilter.h b/include/vd2/VDXFrame/VideoFilter.h index 219e2960b2a..78ef03bd195 100644 --- a/include/vd2/VDXFrame/VideoFilter.h +++ b/include/vd2/VDXFrame/VideoFilter.h @@ -1,221 +1,221 @@ -// VDXFrame - Helper library for VirtualDub plugins -// Copyright (C) 2008 Avery Lee -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_VDXFRAME_VIDEOFILTER_H -#define f_VD2_VDXFRAME_VIDEOFILTER_H - -#include -#include -#include - -#include - -/////////////////////////////////////////////////////////////////////////// -/// \class VDXVideoFilter -/// -/// This class handles most of the grimy work of creating the interface -/// between your filter and VirtualDub. -/// -class VDXVideoFilter { -public: - VDXVideoFilter(); - virtual ~VDXVideoFilter(); - - void SetHooks(VDXFilterActivation *fa, const VDXFilterFunctions *ff); - - // linkage routines - - virtual bool Init(); - virtual uint32 GetParams()=0; - virtual void Start(); - virtual void Run() = 0; - virtual void End(); - virtual bool Configure(VDXHWND hwnd); - virtual void GetSettingString(char *buf, int maxlen); - virtual void GetScriptString(char *buf, int maxlen); - virtual int Serialize(char *buf, int maxbuf); - virtual int Deserialize(const char *buf, int maxbuf); - virtual sint64 Prefetch(sint64 frame); - virtual bool Prefetch2(sint64 frame, IVDXVideoPrefetcher *prefetcher); - - virtual bool OnEvent(uint32 event, const void *eventData); - virtual bool OnInvalidateCaches(); - - static void __cdecl FilterDeinit (VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static int __cdecl FilterRun (const VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static long __cdecl FilterParam (VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static int __cdecl FilterConfig (VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hWnd); - static int __cdecl FilterStart (VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static int __cdecl FilterEnd (VDXFilterActivation *fa, const VDXFilterFunctions *ff); - static void __cdecl FilterString (const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf); - static bool __cdecl FilterScriptStr(VDXFilterActivation *fa, const VDXFilterFunctions *, char *, int); - static void __cdecl FilterString2 (const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen); - static int __cdecl FilterSerialize (VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxbuf); - static void __cdecl FilterDeserialize (VDXFilterActivation *fa, const VDXFilterFunctions *ff, const char *buf, int maxbuf); - static sint64 __cdecl FilterPrefetch(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame); - static bool __cdecl FilterPrefetch2(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame, IVDXVideoPrefetcher *prefetcher); - static bool __cdecl FilterEvent(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, uint32 event, const void *eventData); - - // member variables - VDXFilterActivation *fa; - const VDXFilterFunctions *ff; - - static const VDXScriptFunctionDef sScriptMethods[]; - -protected: - void SafePrintf(char *buf, int maxbuf, const char *format, ...); -}; - -/////////////////////////////////////////////////////////////////////////// -// Script method support -// -// To declare a Config() script method, add -// -// VDXVF_DECLARE_SCRIPT_METHODS() -// -// to the public portion of your class definition, and then add a method -// table at namespace scope: -// -// VDXVF_BEGIN_SCRIPT_METHODS(YUVTransformFilter) -// VDXVF_DEFINE_SCRIPT_METHOD(YUVTransformFilter, ScriptConfig, "iii") -// VDXVF_END_SCRIPT_METHODS() -// -// Use VDXVF_DEFINE_SCRIPT_METHOD() for the first method, and then -// VDXVF_DEFINE_SCRIPT_METHOD2() for any overloads. - -#define VDXVF_DECLARE_SCRIPT_METHODS() static const VDXScriptFunctionDef sScriptMethods[] - -#define VDXVF_BEGIN_SCRIPT_METHODS(klass) const VDXScriptFunctionDef klass::sScriptMethods[] = { -#define VDXVF_DEFINE_SCRIPT_METHOD(klass, method, args) { (VDXScriptFunctionPtr)VDXVideoFilterScriptAdapter::AdaptFn, "Config", "0" args }, -#define VDXVF_DEFINE_SCRIPT_METHOD2(klass, method, args) { (VDXScriptFunctionPtr)VDXVideoFilterScriptAdapter::AdaptFn, NULL, "0" args }, -#define VDXVF_END_SCRIPT_METHODS() { NULL } }; - -extern char VDXVideoFilterConfigureOverloadTest(bool (VDXVideoFilter::*)(VDXHWND)); -extern double VDXVideoFilterConfigureOverloadTest(...); -extern char VDXVideoFilterPrefetchOverloadTest(sint64 (VDXVideoFilter::*)(sint64)); -extern double VDXVideoFilterPrefetchOverloadTest(...); -extern char VDXVideoFilterPrefetch2OverloadTest(bool (VDXVideoFilter::*)(sint64, IVDXVideoPrefetcher *)); -extern double VDXVideoFilterPrefetch2OverloadTest(...); - -template -class VDXVideoFilterScriptAdapter -{ -public: - static void AdaptFn(IVDXScriptInterpreter *isi, void *fa0, const VDXScriptValue *argv, int argc) { - VDXFilterActivation *fa = (VDXFilterActivation *)fa0; - VDXVideoFilter *base = *(VDXVideoFilter **)fa->filter_data; - (static_cast(base)->*T_Method)(isi, argv, argc); - } -}; - -template -class VDXVideoFilterScriptObjectAdapter { -public: - static const VDXScriptObject sScriptObject; -}; - -template -const VDXScriptObject VDXVideoFilterScriptObjectAdapter::sScriptObject = { - NULL, (T::sScriptMethods == VDXVideoFilter::sScriptMethods) ? NULL : (VDXScriptFunctionDef *)static_cast(T::sScriptMethods), NULL -}; - -/////////////////////////////////////////////////////////////////////////// -/// \class VDXVideoFilterDefinition -/// -/// This template creates the FilterDefinition structure for you based on -/// your filter class. -/// -template -class VDXVideoFilterDefinition : public VDXFilterDefinition { -public: - VDXVideoFilterDefinition(const char *pszAuthor, const char *pszName, const char *pszDescription) { - _next = NULL; - _prev = NULL; - _module = NULL; - - name = pszName; - desc = pszDescription; - maker = pszAuthor; - private_data = NULL; - inst_data_size = sizeof(T) + sizeof(VDXVideoFilter *); - - initProc = FilterInit; - deinitProc = T::FilterDeinit; - runProc = T::FilterRun; - paramProc = T::FilterParam; - configProc = sizeof(VDXVideoFilterConfigureOverloadTest(&T::Configure)) > 1 ? T::FilterConfig : NULL; - stringProc = T::FilterString; - startProc = T::FilterStart; - endProc = T::FilterEnd; - - script_obj = T::sScriptMethods ? const_cast(&VDXVideoFilterScriptObjectAdapter::sScriptObject) : 0; - fssProc = T::FilterScriptStr; - - stringProc2 = T::FilterString2; - serializeProc = T::FilterSerialize; - deserializeProc = T::FilterDeserialize; - copyProc = FilterCopy; - copyProc2 = FilterCopy2; - - prefetchProc = sizeof(VDXVideoFilterPrefetchOverloadTest(&T::Prefetch)) > 1 ? T::FilterPrefetch : NULL; - prefetchProc2 = sizeof(VDXVideoFilterPrefetch2OverloadTest(&T::Prefetch2)) > 1 || sizeof(VDXVideoFilterPrefetchOverloadTest(&T::Prefetch)) > 1 ? T::FilterPrefetch2 : NULL; - - eventProc = T::FilterEvent; - } - -private: - static int __cdecl FilterInit (VDXFilterActivation *fa, const VDXFilterFunctions *ff) { - T *pThis = new((char *)fa->filter_data + sizeof(VDXVideoFilter *)) T; - *(VDXVideoFilter **)fa->filter_data = static_cast(pThis); - - pThis->SetHooks(fa, ff); - - try { - if (!pThis->Init()) { - pThis->~T(); - return 1; - } - - return 0; - } catch(...) { - pThis->~T(); - throw; - } - } - - static void __cdecl FilterCopy (VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst) { - T *p = new((char *)dst + sizeof(VDXVideoFilter *)) T(*static_cast(*reinterpret_cast(fa->filter_data))); - p->ff = ff; - *(VDXVideoFilter **)dst = p; - } - - static void __cdecl FilterCopy2 (VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst, VDXFilterActivation *fanew, const VDXFilterFunctions *ffnew) { - T *p = new((char *)dst + sizeof(VDXVideoFilter *)) T(*static_cast(*reinterpret_cast(fa->filter_data))); - p->ff = ffnew; - p->fa = fanew; - *(VDXVideoFilter **)dst = p; - } -}; - -#endif +// VDXFrame - Helper library for VirtualDub plugins +// Copyright (C) 2008 Avery Lee +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_VDXFRAME_VIDEOFILTER_H +#define f_VD2_VDXFRAME_VIDEOFILTER_H + +#include +#include +#include + +#include + +/////////////////////////////////////////////////////////////////////////// +/// \class VDXVideoFilter +/// +/// This class handles most of the grimy work of creating the interface +/// between your filter and VirtualDub. +/// +class VDXVideoFilter { +public: + VDXVideoFilter(); + virtual ~VDXVideoFilter(); + + void SetHooks(VDXFilterActivation *fa, const VDXFilterFunctions *ff); + + // linkage routines + + virtual bool Init(); + virtual uint32 GetParams()=0; + virtual void Start(); + virtual void Run() = 0; + virtual void End(); + virtual bool Configure(VDXHWND hwnd); + virtual void GetSettingString(char *buf, int maxlen); + virtual void GetScriptString(char *buf, int maxlen); + virtual int Serialize(char *buf, int maxbuf); + virtual int Deserialize(const char *buf, int maxbuf); + virtual sint64 Prefetch(sint64 frame); + virtual bool Prefetch2(sint64 frame, IVDXVideoPrefetcher *prefetcher); + + virtual bool OnEvent(uint32 event, const void *eventData); + virtual bool OnInvalidateCaches(); + + static void __cdecl FilterDeinit (VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static int __cdecl FilterRun (const VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static long __cdecl FilterParam (VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static int __cdecl FilterConfig (VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hWnd); + static int __cdecl FilterStart (VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static int __cdecl FilterEnd (VDXFilterActivation *fa, const VDXFilterFunctions *ff); + static void __cdecl FilterString (const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf); + static bool __cdecl FilterScriptStr(VDXFilterActivation *fa, const VDXFilterFunctions *, char *, int); + static void __cdecl FilterString2 (const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen); + static int __cdecl FilterSerialize (VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxbuf); + static void __cdecl FilterDeserialize (VDXFilterActivation *fa, const VDXFilterFunctions *ff, const char *buf, int maxbuf); + static sint64 __cdecl FilterPrefetch(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame); + static bool __cdecl FilterPrefetch2(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame, IVDXVideoPrefetcher *prefetcher); + static bool __cdecl FilterEvent(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, uint32 event, const void *eventData); + + // member variables + VDXFilterActivation *fa; + const VDXFilterFunctions *ff; + + static const VDXScriptFunctionDef sScriptMethods[]; + +protected: + void SafePrintf(char *buf, int maxbuf, const char *format, ...); +}; + +/////////////////////////////////////////////////////////////////////////// +// Script method support +// +// To declare a Config() script method, add +// +// VDXVF_DECLARE_SCRIPT_METHODS() +// +// to the public portion of your class definition, and then add a method +// table at namespace scope: +// +// VDXVF_BEGIN_SCRIPT_METHODS(YUVTransformFilter) +// VDXVF_DEFINE_SCRIPT_METHOD(YUVTransformFilter, ScriptConfig, "iii") +// VDXVF_END_SCRIPT_METHODS() +// +// Use VDXVF_DEFINE_SCRIPT_METHOD() for the first method, and then +// VDXVF_DEFINE_SCRIPT_METHOD2() for any overloads. + +#define VDXVF_DECLARE_SCRIPT_METHODS() static const VDXScriptFunctionDef sScriptMethods[] + +#define VDXVF_BEGIN_SCRIPT_METHODS(klass) const VDXScriptFunctionDef klass::sScriptMethods[] = { +#define VDXVF_DEFINE_SCRIPT_METHOD(klass, method, args) { (VDXScriptFunctionPtr)VDXVideoFilterScriptAdapter::AdaptFn, "Config", "0" args }, +#define VDXVF_DEFINE_SCRIPT_METHOD2(klass, method, args) { (VDXScriptFunctionPtr)VDXVideoFilterScriptAdapter::AdaptFn, NULL, "0" args }, +#define VDXVF_END_SCRIPT_METHODS() { NULL } }; + +extern char VDXVideoFilterConfigureOverloadTest(bool (VDXVideoFilter::*)(VDXHWND)); +extern double VDXVideoFilterConfigureOverloadTest(...); +extern char VDXVideoFilterPrefetchOverloadTest(sint64 (VDXVideoFilter::*)(sint64)); +extern double VDXVideoFilterPrefetchOverloadTest(...); +extern char VDXVideoFilterPrefetch2OverloadTest(bool (VDXVideoFilter::*)(sint64, IVDXVideoPrefetcher *)); +extern double VDXVideoFilterPrefetch2OverloadTest(...); + +template +class VDXVideoFilterScriptAdapter +{ +public: + static void AdaptFn(IVDXScriptInterpreter *isi, void *fa0, const VDXScriptValue *argv, int argc) { + VDXFilterActivation *fa = (VDXFilterActivation *)fa0; + VDXVideoFilter *base = *(VDXVideoFilter **)fa->filter_data; + (static_cast(base)->*T_Method)(isi, argv, argc); + } +}; + +template +class VDXVideoFilterScriptObjectAdapter { +public: + static const VDXScriptObject sScriptObject; +}; + +template +const VDXScriptObject VDXVideoFilterScriptObjectAdapter::sScriptObject = { + NULL, (T::sScriptMethods == VDXVideoFilter::sScriptMethods) ? NULL : (VDXScriptFunctionDef *)static_cast(T::sScriptMethods), NULL +}; + +/////////////////////////////////////////////////////////////////////////// +/// \class VDXVideoFilterDefinition +/// +/// This template creates the FilterDefinition structure for you based on +/// your filter class. +/// +template +class VDXVideoFilterDefinition : public VDXFilterDefinition { +public: + VDXVideoFilterDefinition(const char *pszAuthor, const char *pszName, const char *pszDescription) { + _next = NULL; + _prev = NULL; + _module = NULL; + + name = pszName; + desc = pszDescription; + maker = pszAuthor; + private_data = NULL; + inst_data_size = sizeof(T) + sizeof(VDXVideoFilter *); + + initProc = FilterInit; + deinitProc = T::FilterDeinit; + runProc = T::FilterRun; + paramProc = T::FilterParam; + configProc = sizeof(VDXVideoFilterConfigureOverloadTest(&T::Configure)) > 1 ? T::FilterConfig : NULL; + stringProc = T::FilterString; + startProc = T::FilterStart; + endProc = T::FilterEnd; + + script_obj = T::sScriptMethods ? const_cast(&VDXVideoFilterScriptObjectAdapter::sScriptObject) : 0; + fssProc = T::FilterScriptStr; + + stringProc2 = T::FilterString2; + serializeProc = T::FilterSerialize; + deserializeProc = T::FilterDeserialize; + copyProc = FilterCopy; + copyProc2 = FilterCopy2; + + prefetchProc = sizeof(VDXVideoFilterPrefetchOverloadTest(&T::Prefetch)) > 1 ? T::FilterPrefetch : NULL; + prefetchProc2 = sizeof(VDXVideoFilterPrefetch2OverloadTest(&T::Prefetch2)) > 1 || sizeof(VDXVideoFilterPrefetchOverloadTest(&T::Prefetch)) > 1 ? T::FilterPrefetch2 : NULL; + + eventProc = T::FilterEvent; + } + +private: + static int __cdecl FilterInit (VDXFilterActivation *fa, const VDXFilterFunctions *ff) { + T *pThis = new((char *)fa->filter_data + sizeof(VDXVideoFilter *)) T; + *(VDXVideoFilter **)fa->filter_data = static_cast(pThis); + + pThis->SetHooks(fa, ff); + + try { + if (!pThis->Init()) { + pThis->~T(); + return 1; + } + + return 0; + } catch(...) { + pThis->~T(); + throw; + } + } + + static void __cdecl FilterCopy (VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst) { + T *p = new((char *)dst + sizeof(VDXVideoFilter *)) T(*static_cast(*reinterpret_cast(fa->filter_data))); + p->ff = ff; + *(VDXVideoFilter **)dst = p; + } + + static void __cdecl FilterCopy2 (VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst, VDXFilterActivation *fanew, const VDXFilterFunctions *ffnew) { + T *p = new((char *)dst + sizeof(VDXVideoFilter *)) T(*static_cast(*reinterpret_cast(fa->filter_data))); + p->ff = ffnew; + p->fa = fanew; + *(VDXVideoFilter **)dst = p; + } +}; + +#endif diff --git a/include/vd2/VDXFrame/VideoFilterDialog.h b/include/vd2/VDXFrame/VideoFilterDialog.h index 51aaf2da370..1e9aa491766 100644 --- a/include/vd2/VDXFrame/VideoFilterDialog.h +++ b/include/vd2/VDXFrame/VideoFilterDialog.h @@ -1,46 +1,46 @@ -// VDXFrame - Helper library for VirtualDub plugins -// Copyright (C) 2008 Avery Lee -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_VDXFRAME_VIDEOFILTERDIALOG_H -#define f_VD2_VDXFRAME_VIDEOFILTERDIALOG_H - -#include - -class VDXVideoFilterDialog { -public: - VDXVideoFilterDialog(); - -protected: - HWND mhdlg; - - LRESULT Show(HINSTANCE hInst, LPCSTR templName, HWND parent); - LRESULT Show(HINSTANCE hInst, LPCWSTR templName, HWND parent); - HWND ShowModeless(HINSTANCE hInst, LPCSTR templName, HWND parent); - HWND ShowModeless(HINSTANCE hInst, LPCWSTR templName, HWND parent); - - static INT_PTR CALLBACK StaticDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam); - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); -}; - -#endif +// VDXFrame - Helper library for VirtualDub plugins +// Copyright (C) 2008 Avery Lee +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_VDXFRAME_VIDEOFILTERDIALOG_H +#define f_VD2_VDXFRAME_VIDEOFILTERDIALOG_H + +#include + +class VDXVideoFilterDialog { +public: + VDXVideoFilterDialog(); + +protected: + HWND mhdlg; + + LRESULT Show(HINSTANCE hInst, LPCSTR templName, HWND parent); + LRESULT Show(HINSTANCE hInst, LPCWSTR templName, HWND parent); + HWND ShowModeless(HINSTANCE hInst, LPCSTR templName, HWND parent); + HWND ShowModeless(HINSTANCE hInst, LPCWSTR templName, HWND parent); + + static INT_PTR CALLBACK StaticDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam); + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); +}; + +#endif diff --git a/include/vd2/VDXFrame/VideoFilterEntry.h b/include/vd2/VDXFrame/VideoFilterEntry.h index 5eacf1c0bc7..112f02c3fcc 100644 --- a/include/vd2/VDXFrame/VideoFilterEntry.h +++ b/include/vd2/VDXFrame/VideoFilterEntry.h @@ -1,84 +1,84 @@ -// VDXFrame - Helper library for VirtualDub plugins -// Copyright (C) 2008 Avery Lee -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_VDXFRAME_VIDEOFILTERENTRY_H -#define f_VD2_VDXFRAME_VIDEOFILTERENTRY_H - -#include - -#ifdef _MSC_VER - #pragma once -#endif - -struct VDXFilterModule; -struct VDXFilterFunctions; -struct VDXFilterDefinition; - -/////////////////////////////////////////////////////////////////////////////// -/// Video filter module entry point declaration macros -/// -/// To declare the module init and deinit functions: -/// -/// VDX_DECLARE_VFMODULE() -/// -/// By default this declares the module as requiring copy contructor support -/// (V9 / VirtualDub 1.4.12). If you need to declare a different minimum -/// version, use: -/// -/// VDX_DECLARE_VFMODULE_APIVER(version) -/// -#define VDX_DECLARE_VFMODULE() VDX_DECLARE_VFMODULE_APIVER(VIRTUALDUB_FILTERDEF_COMPATIBLE_COPYCTOR) -#define VDX_DECLARE_VFMODULE_APIVER(apiver) \ - extern "C" __declspec(dllexport) int __cdecl VirtualdubFilterModuleInit2(struct VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat) { \ - return VDXVideoFilterModuleInit2(fm, ff, vdfd_ver, vdfd_compat, (apiver)); \ - } \ - \ - extern "C" __declspec(dllexport) void __cdecl VirtualdubFilterModuleDeinit(struct VDXFilterModule *fm, const VDXFilterFunctions *ff) { \ - VDXVideoFilterModuleDeinit(fm, ff); \ - } - -/////////////////////////////////////////////////////////////////////////////// -/// Video filter declaration macros -/// -/// To declare video filters, use the following pattern: -/// -/// VDX_DECLARE_VIDEOFILTERS_BEGIN() -/// VDX_DECLARE_VIDEOFILTER(definitionSymbolName) -/// VDX_DECLARE_VIDEOFILTERS_END() -/// -/// Each entry points to a variable of type VDXFilterDefinition. Note that these must -/// be declared as _non-const_ for compatibility with older versions of VirtualDub. -/// Video filters declared this way are automatically registered by the module init -/// routine. -/// -#define VDX_DECLARE_VIDEOFILTERS_BEGIN() VDXFilterDefinition *VDXGetVideoFilterDefinition(int index) { -#define VDX_DECLARE_VIDEOFILTER(defVarName) if (!index--) { extern VDXFilterDefinition defVarName; return &defVarName; } -#define VDX_DECLARE_VIDEOFILTERS_END() return NULL; \ - } -int VDXVideoFilterModuleInit2(struct VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat, int ver_compat_target); -void VDXVideoFilterModuleDeinit(struct VDXFilterModule *fm, const VDXFilterFunctions *ff); - -int VDXGetVideoFilterAPIVersion(); - -#endif +// VDXFrame - Helper library for VirtualDub plugins +// Copyright (C) 2008 Avery Lee +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_VDXFRAME_VIDEOFILTERENTRY_H +#define f_VD2_VDXFRAME_VIDEOFILTERENTRY_H + +#include + +#ifdef _MSC_VER + #pragma once +#endif + +struct VDXFilterModule; +struct VDXFilterFunctions; +struct VDXFilterDefinition; + +/////////////////////////////////////////////////////////////////////////////// +/// Video filter module entry point declaration macros +/// +/// To declare the module init and deinit functions: +/// +/// VDX_DECLARE_VFMODULE() +/// +/// By default this declares the module as requiring copy contructor support +/// (V9 / VirtualDub 1.4.12). If you need to declare a different minimum +/// version, use: +/// +/// VDX_DECLARE_VFMODULE_APIVER(version) +/// +#define VDX_DECLARE_VFMODULE() VDX_DECLARE_VFMODULE_APIVER(VIRTUALDUB_FILTERDEF_COMPATIBLE_COPYCTOR) +#define VDX_DECLARE_VFMODULE_APIVER(apiver) \ + extern "C" __declspec(dllexport) int __cdecl VirtualdubFilterModuleInit2(struct VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat) { \ + return VDXVideoFilterModuleInit2(fm, ff, vdfd_ver, vdfd_compat, (apiver)); \ + } \ + \ + extern "C" __declspec(dllexport) void __cdecl VirtualdubFilterModuleDeinit(struct VDXFilterModule *fm, const VDXFilterFunctions *ff) { \ + VDXVideoFilterModuleDeinit(fm, ff); \ + } + +/////////////////////////////////////////////////////////////////////////////// +/// Video filter declaration macros +/// +/// To declare video filters, use the following pattern: +/// +/// VDX_DECLARE_VIDEOFILTERS_BEGIN() +/// VDX_DECLARE_VIDEOFILTER(definitionSymbolName) +/// VDX_DECLARE_VIDEOFILTERS_END() +/// +/// Each entry points to a variable of type VDXFilterDefinition. Note that these must +/// be declared as _non-const_ for compatibility with older versions of VirtualDub. +/// Video filters declared this way are automatically registered by the module init +/// routine. +/// +#define VDX_DECLARE_VIDEOFILTERS_BEGIN() VDXFilterDefinition *VDXGetVideoFilterDefinition(int index) { +#define VDX_DECLARE_VIDEOFILTER(defVarName) if (!index--) { extern VDXFilterDefinition defVarName; return &defVarName; } +#define VDX_DECLARE_VIDEOFILTERS_END() return NULL; \ + } +int VDXVideoFilterModuleInit2(struct VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat, int ver_compat_target); +void VDXVideoFilterModuleDeinit(struct VDXFilterModule *fm, const VDXFilterFunctions *ff); + +int VDXGetVideoFilterAPIVersion(); + +#endif diff --git a/include/vd2/extras/FilterSDK/Filter.h b/include/vd2/extras/FilterSDK/Filter.h index 8e37795d4b2..a8747a4a6b2 100644 --- a/include/vd2/extras/FilterSDK/Filter.h +++ b/include/vd2/extras/FilterSDK/Filter.h @@ -1,244 +1,244 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - - -#ifndef f_FILTER_H -#define f_FILTER_H - -#include - -// This is really dumb, but necessary to support VTbls in C++. - -struct FilterVTbls { - void *pvtblVBitmap; -}; - -#ifdef VDEXT_MAIN -struct FilterVTbls g_vtbls; -#elif defined(VDEXT_NOTMAIN) -extern struct FilterVTbls g_vtbls; -#endif - -#define INITIALIZE_VTBLS ff->InitVTables(&g_vtbls) - -#include "VBitmap.h" - -////////////////// - -struct CScriptObject; - -////////////////// - -enum { - FILTERPARAM_SWAP_BUFFERS = 0x00000001L, - FILTERPARAM_NEEDS_LAST = 0x00000002L, -}; - -#define FILTERPARAM_HAS_LAG(frames) ((int)(frames) << 16) - -/////////////////// - -class VFBitmap; -class FilterActivation; -struct FilterFunctions; - -typedef int (*FilterInitProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef void (*FilterDeinitProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef int (*FilterRunProc )(const FilterActivation *fa, const FilterFunctions *ff); -typedef long (*FilterParamProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef int (*FilterConfigProc )(FilterActivation *fa, const FilterFunctions *ff, HWND hWnd); -typedef void (*FilterStringProc )(const FilterActivation *fa, const FilterFunctions *ff, char *buf); -typedef int (*FilterStartProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef int (*FilterEndProc )(FilterActivation *fa, const FilterFunctions *ff); -typedef bool (*FilterScriptStrProc)(FilterActivation *fa, const FilterFunctions *, char *, int); -typedef void (*FilterStringProc2 )(const FilterActivation *fa, const FilterFunctions *ff, char *buf, int maxlen); -typedef int (*FilterSerialize )(FilterActivation *fa, const FilterFunctions *ff, char *buf, int maxbuf); -typedef void (*FilterDeserialize )(FilterActivation *fa, const FilterFunctions *ff, const char *buf, int maxbuf); -typedef void (*FilterCopy )(FilterActivation *fa, const FilterFunctions *ff, void *dst); - -typedef int (__cdecl *FilterModuleInitProc)(struct FilterModule *fm, const FilterFunctions *ff, int& vdfd_ver, int& vdfd_compat); -typedef void (__cdecl *FilterModuleDeinitProc)(struct FilterModule *fm, const FilterFunctions *ff); - -////////// - -typedef void (__cdecl *FilterPreviewButtonCallback)(bool fNewState, void *pData); -typedef void (__cdecl *FilterPreviewSampleCallback)(VFBitmap *, long lFrame, long lCount, void *pData); - -class IFilterPreview { -public: - virtual void SetButtonCallback(FilterPreviewButtonCallback, void *)=0; - virtual void SetSampleCallback(FilterPreviewSampleCallback, void *)=0; - - virtual bool isPreviewEnabled()=0; - virtual void Toggle(HWND)=0; - virtual void Display(HWND, bool)=0; - virtual void RedoFrame()=0; - virtual void RedoSystem()=0; - virtual void UndoSystem()=0; - virtual void InitButton(HWND)=0; - virtual void Close()=0; - virtual bool SampleCurrentFrame()=0; - virtual long SampleFrames()=0; -}; - -////////// - -#define VIRTUALDUB_FILTERDEF_VERSION (8) -#define VIRTUALDUB_FILTERDEF_COMPATIBLE (4) - -// v3: added lCurrentSourceFrame to FrameStateInfo -// v4 (1.2): lots of additions (VirtualDub 1.2) -// v5 (1.3d): lots of bugfixes - stretchblt bilinear, and non-zero startproc -// v6 (1.4): added error handling functions -// v7 (1.4d): added frame lag, exception handling -// v8 (1.4.11): - -typedef struct FilterModule { - struct FilterModule *next, *prev; - HINSTANCE hInstModule; - FilterModuleInitProc initProc; - FilterModuleDeinitProc deinitProc; -} FilterModule; - -typedef struct FilterDefinition { - - struct FilterDefinition *next, *prev; - FilterModule *module; - - const char * name; - const char * desc; - const char * maker; - void * private_data; - int inst_data_size; - - FilterInitProc initProc; - FilterDeinitProc deinitProc; - FilterRunProc runProc; - FilterParamProc paramProc; - FilterConfigProc configProc; - FilterStringProc stringProc; - FilterStartProc startProc; - FilterEndProc endProc; - - CScriptObject *script_obj; - - FilterScriptStrProc fssProc; - - // NEW - 1.4.11 - FilterStringProc2 stringProc2; - FilterSerialize serializeProc; - FilterDeserialize deserializeProc; - FilterCopy copyProc; -} FilterDefinition; - -////////// - -// FilterStateInfo: contains dynamic info about file being processed - -class FilterStateInfo { -public: - long lCurrentFrame; // current output frame - long lMicrosecsPerFrame; // microseconds per output frame - long lCurrentSourceFrame; // current source frame - long lMicrosecsPerSrcFrame; // microseconds per source frame - long lSourceFrameMS; // source frame timestamp - long lDestFrameMS; // output frame timestamp -}; - -// VFBitmap: VBitmap extended to hold filter-specific information - -class VFBitmap : public VBitmap { -public: - enum { - NEEDS_HDC = 0x00000001L, - }; - - DWORD dwFlags; - HDC hdc; -}; - -// FilterActivation: This is what is actually passed to filters at runtime. - -class FilterActivation { -public: - FilterDefinition *filter; - void *filter_data; - VFBitmap &dst, &src; - VFBitmap *__reserved0, *const last; - unsigned long x1, y1, x2, y2; - - FilterStateInfo *pfsi; - IFilterPreview *ifp; - - FilterActivation(VFBitmap& _dst, VFBitmap& _src, VFBitmap *_last) : dst(_dst), src(_src), last(_last) {} - FilterActivation(const FilterActivation& fa, VFBitmap& _dst, VFBitmap& _src, VFBitmap *_last); -}; - -// These flags must match those in cpuaccel.h! - -#ifndef f_VIRTUALDUB_CPUACCEL_H -#define CPUF_SUPPORTS_CPUID (0x00000001L) -#define CPUF_SUPPORTS_FPU (0x00000002L) -#define CPUF_SUPPORTS_MMX (0x00000004L) -#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) -#define CPUF_SUPPORTS_SSE (0x00000010L) -#define CPUF_SUPPORTS_SSE2 (0x00000020L) -#define CPUF_SUPPORTS_3DNOW (0x00000040L) -#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) -#endif - -struct FilterFunctions { - FilterDefinition *(*addFilter)(FilterModule *, FilterDefinition *, int fd_len); - void (*removeFilter)(FilterDefinition *); - bool (*isFPUEnabled)(); - bool (*isMMXEnabled)(); - void (*InitVTables)(struct FilterVTbls *); - - // These functions permit you to throw MyError exceptions from a filter. - // YOU MUST ONLY CALL THESE IN runProc, initProc, and startProc. - - void (*ExceptOutOfMemory)(); // ADDED: V6 (VirtualDub 1.4) - void (*Except)(const char *format, ...); // ADDED: V6 (VirtualDub 1.4) - - // These functions are callable at any time. - - long (*getCPUFlags)(); // ADDED: V6 (VirtualDub 1.4) - long (*getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d) -}; - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + + +#ifndef f_FILTER_H +#define f_FILTER_H + +#include + +// This is really dumb, but necessary to support VTbls in C++. + +struct FilterVTbls { + void *pvtblVBitmap; +}; + +#ifdef VDEXT_MAIN +struct FilterVTbls g_vtbls; +#elif defined(VDEXT_NOTMAIN) +extern struct FilterVTbls g_vtbls; +#endif + +#define INITIALIZE_VTBLS ff->InitVTables(&g_vtbls) + +#include "VBitmap.h" + +////////////////// + +struct CScriptObject; + +////////////////// + +enum { + FILTERPARAM_SWAP_BUFFERS = 0x00000001L, + FILTERPARAM_NEEDS_LAST = 0x00000002L, +}; + +#define FILTERPARAM_HAS_LAG(frames) ((int)(frames) << 16) + +/////////////////// + +class VFBitmap; +class FilterActivation; +struct FilterFunctions; + +typedef int (*FilterInitProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef void (*FilterDeinitProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef int (*FilterRunProc )(const FilterActivation *fa, const FilterFunctions *ff); +typedef long (*FilterParamProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef int (*FilterConfigProc )(FilterActivation *fa, const FilterFunctions *ff, HWND hWnd); +typedef void (*FilterStringProc )(const FilterActivation *fa, const FilterFunctions *ff, char *buf); +typedef int (*FilterStartProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef int (*FilterEndProc )(FilterActivation *fa, const FilterFunctions *ff); +typedef bool (*FilterScriptStrProc)(FilterActivation *fa, const FilterFunctions *, char *, int); +typedef void (*FilterStringProc2 )(const FilterActivation *fa, const FilterFunctions *ff, char *buf, int maxlen); +typedef int (*FilterSerialize )(FilterActivation *fa, const FilterFunctions *ff, char *buf, int maxbuf); +typedef void (*FilterDeserialize )(FilterActivation *fa, const FilterFunctions *ff, const char *buf, int maxbuf); +typedef void (*FilterCopy )(FilterActivation *fa, const FilterFunctions *ff, void *dst); + +typedef int (__cdecl *FilterModuleInitProc)(struct FilterModule *fm, const FilterFunctions *ff, int& vdfd_ver, int& vdfd_compat); +typedef void (__cdecl *FilterModuleDeinitProc)(struct FilterModule *fm, const FilterFunctions *ff); + +////////// + +typedef void (__cdecl *FilterPreviewButtonCallback)(bool fNewState, void *pData); +typedef void (__cdecl *FilterPreviewSampleCallback)(VFBitmap *, long lFrame, long lCount, void *pData); + +class IFilterPreview { +public: + virtual void SetButtonCallback(FilterPreviewButtonCallback, void *)=0; + virtual void SetSampleCallback(FilterPreviewSampleCallback, void *)=0; + + virtual bool isPreviewEnabled()=0; + virtual void Toggle(HWND)=0; + virtual void Display(HWND, bool)=0; + virtual void RedoFrame()=0; + virtual void RedoSystem()=0; + virtual void UndoSystem()=0; + virtual void InitButton(HWND)=0; + virtual void Close()=0; + virtual bool SampleCurrentFrame()=0; + virtual long SampleFrames()=0; +}; + +////////// + +#define VIRTUALDUB_FILTERDEF_VERSION (8) +#define VIRTUALDUB_FILTERDEF_COMPATIBLE (4) + +// v3: added lCurrentSourceFrame to FrameStateInfo +// v4 (1.2): lots of additions (VirtualDub 1.2) +// v5 (1.3d): lots of bugfixes - stretchblt bilinear, and non-zero startproc +// v6 (1.4): added error handling functions +// v7 (1.4d): added frame lag, exception handling +// v8 (1.4.11): + +typedef struct FilterModule { + struct FilterModule *next, *prev; + HINSTANCE hInstModule; + FilterModuleInitProc initProc; + FilterModuleDeinitProc deinitProc; +} FilterModule; + +typedef struct FilterDefinition { + + struct FilterDefinition *next, *prev; + FilterModule *module; + + const char * name; + const char * desc; + const char * maker; + void * private_data; + int inst_data_size; + + FilterInitProc initProc; + FilterDeinitProc deinitProc; + FilterRunProc runProc; + FilterParamProc paramProc; + FilterConfigProc configProc; + FilterStringProc stringProc; + FilterStartProc startProc; + FilterEndProc endProc; + + CScriptObject *script_obj; + + FilterScriptStrProc fssProc; + + // NEW - 1.4.11 + FilterStringProc2 stringProc2; + FilterSerialize serializeProc; + FilterDeserialize deserializeProc; + FilterCopy copyProc; +} FilterDefinition; + +////////// + +// FilterStateInfo: contains dynamic info about file being processed + +class FilterStateInfo { +public: + long lCurrentFrame; // current output frame + long lMicrosecsPerFrame; // microseconds per output frame + long lCurrentSourceFrame; // current source frame + long lMicrosecsPerSrcFrame; // microseconds per source frame + long lSourceFrameMS; // source frame timestamp + long lDestFrameMS; // output frame timestamp +}; + +// VFBitmap: VBitmap extended to hold filter-specific information + +class VFBitmap : public VBitmap { +public: + enum { + NEEDS_HDC = 0x00000001L, + }; + + DWORD dwFlags; + HDC hdc; +}; + +// FilterActivation: This is what is actually passed to filters at runtime. + +class FilterActivation { +public: + FilterDefinition *filter; + void *filter_data; + VFBitmap &dst, &src; + VFBitmap *__reserved0, *const last; + unsigned long x1, y1, x2, y2; + + FilterStateInfo *pfsi; + IFilterPreview *ifp; + + FilterActivation(VFBitmap& _dst, VFBitmap& _src, VFBitmap *_last) : dst(_dst), src(_src), last(_last) {} + FilterActivation(const FilterActivation& fa, VFBitmap& _dst, VFBitmap& _src, VFBitmap *_last); +}; + +// These flags must match those in cpuaccel.h! + +#ifndef f_VIRTUALDUB_CPUACCEL_H +#define CPUF_SUPPORTS_CPUID (0x00000001L) +#define CPUF_SUPPORTS_FPU (0x00000002L) +#define CPUF_SUPPORTS_MMX (0x00000004L) +#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) +#define CPUF_SUPPORTS_SSE (0x00000010L) +#define CPUF_SUPPORTS_SSE2 (0x00000020L) +#define CPUF_SUPPORTS_3DNOW (0x00000040L) +#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) +#endif + +struct FilterFunctions { + FilterDefinition *(*addFilter)(FilterModule *, FilterDefinition *, int fd_len); + void (*removeFilter)(FilterDefinition *); + bool (*isFPUEnabled)(); + bool (*isMMXEnabled)(); + void (*InitVTables)(struct FilterVTbls *); + + // These functions permit you to throw MyError exceptions from a filter. + // YOU MUST ONLY CALL THESE IN runProc, initProc, and startProc. + + void (*ExceptOutOfMemory)(); // ADDED: V6 (VirtualDub 1.4) + void (*Except)(const char *format, ...); // ADDED: V6 (VirtualDub 1.4) + + // These functions are callable at any time. + + long (*getCPUFlags)(); // ADDED: V6 (VirtualDub 1.4) + long (*getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d) +}; + +#endif diff --git a/include/vd2/extras/FilterSDK/ScriptError.h b/include/vd2/extras/FilterSDK/ScriptError.h index af29a72d45e..ceaad8bb060 100644 --- a/include/vd2/extras/FilterSDK/ScriptError.h +++ b/include/vd2/extras/FilterSDK/ScriptError.h @@ -1,93 +1,93 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - -#ifndef f_SYLIA_SCRIPTERROR_H -#define f_SYLIA_SCRIPTERROR_H - -class CScriptError { -public: - int err; - - enum { - PARSE_ERROR=1, - SEMICOLON_EXPECTED, - IDENTIFIER_EXPECTED, - - TYPE_INT_REQUIRED, - TYPE_ARRAY_REQUIRED, - TYPE_FUNCTION_REQUIRED, - TYPE_OBJECT_REQUIRED, - - OBJECT_MEMBER_NAME_REQUIRED, - FUNCCALLEND_EXPECTED, - TOO_MANY_PARAMS, - DIVIDE_BY_ZERO, - VAR_NOT_FOUND, - MEMBER_NOT_FOUND, - OVERLOADED_FUNCTION_NOT_FOUND, - IDENT_TOO_LONG, - OPERATOR_EXPECTED, - CLOSEPARENS_EXPECTED, - CLOSEBRACKET_EXPECTED, - - VAR_UNDEFINED, - - OUT_OF_STRING_SPACE, - OUT_OF_MEMORY, - INTERNAL_ERROR, - EXTERNAL_ERROR, - - FCALL_OUT_OF_RANGE, - FCALL_INVALID_PTYPE, - FCALL_UNKNOWN_STR, - }; - - CScriptError(int err_num) : err(err_num) { } - - int getErr() { return err; } -}; - -#define SCRIPT_ERROR(x) throw CScriptError(CScriptError::##x) - -extern "C" __declspec(dllexport) char * __stdcall TranslateScriptError(int); - -char inline *TranslateScriptError(CScriptError cse) { - return TranslateScriptError(cse.getErr()); -} - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + +#ifndef f_SYLIA_SCRIPTERROR_H +#define f_SYLIA_SCRIPTERROR_H + +class CScriptError { +public: + int err; + + enum { + PARSE_ERROR=1, + SEMICOLON_EXPECTED, + IDENTIFIER_EXPECTED, + + TYPE_INT_REQUIRED, + TYPE_ARRAY_REQUIRED, + TYPE_FUNCTION_REQUIRED, + TYPE_OBJECT_REQUIRED, + + OBJECT_MEMBER_NAME_REQUIRED, + FUNCCALLEND_EXPECTED, + TOO_MANY_PARAMS, + DIVIDE_BY_ZERO, + VAR_NOT_FOUND, + MEMBER_NOT_FOUND, + OVERLOADED_FUNCTION_NOT_FOUND, + IDENT_TOO_LONG, + OPERATOR_EXPECTED, + CLOSEPARENS_EXPECTED, + CLOSEBRACKET_EXPECTED, + + VAR_UNDEFINED, + + OUT_OF_STRING_SPACE, + OUT_OF_MEMORY, + INTERNAL_ERROR, + EXTERNAL_ERROR, + + FCALL_OUT_OF_RANGE, + FCALL_INVALID_PTYPE, + FCALL_UNKNOWN_STR, + }; + + CScriptError(int err_num) : err(err_num) { } + + int getErr() { return err; } +}; + +#define SCRIPT_ERROR(x) throw CScriptError(CScriptError::##x) + +extern "C" __declspec(dllexport) char * __stdcall TranslateScriptError(int); + +char inline *TranslateScriptError(CScriptError cse) { + return TranslateScriptError(cse.getErr()); +} + +#endif diff --git a/include/vd2/extras/FilterSDK/ScriptInterpreter.h b/include/vd2/extras/FilterSDK/ScriptInterpreter.h index 9a9a90994c3..ad01971185b 100644 --- a/include/vd2/extras/FilterSDK/ScriptInterpreter.h +++ b/include/vd2/extras/FilterSDK/ScriptInterpreter.h @@ -1,70 +1,70 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - -#ifndef f_SYLIA_SCRIPTINTERPRETER_H -#define f_SYLIA_SCRIPTINTERPRETER_H - -class CScriptValue; -class CScriptError; -struct CScriptObject; -class IScriptInterpreter; - -typedef CScriptValue (*ScriptRootHandlerPtr)(IScriptInterpreter *,char *,void *); - -class IScriptInterpreter { -public: - virtual void Destroy() =0; - - virtual void SetRootHandler(ScriptRootHandlerPtr, void *) =0; - - virtual void ExecuteLine(char *s) =0; - - virtual void ScriptError(int e) =0; - virtual char* TranslateScriptError(CScriptError& cse) =0; - virtual char** AllocTempString(long l) =0; - - virtual CScriptValue LookupObjectMember(CScriptObject *obj, void *, char *szIdent) = 0; -}; - -extern "C" __declspec(dllexport) IScriptInterpreter * __stdcall CreateScriptInterpreter(); - -#define GETPROC_CREATESCRIPTINTERPRETER(hInst) ((IScriptInterpreter *(__stdcall *)())GetProcAddress(hInst, "_CreateScriptInterpreter@0")) - -#define EXT_SCRIPT_ERROR(x) (isi->ScriptError((CScriptError::x))) - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + +#ifndef f_SYLIA_SCRIPTINTERPRETER_H +#define f_SYLIA_SCRIPTINTERPRETER_H + +class CScriptValue; +class CScriptError; +struct CScriptObject; +class IScriptInterpreter; + +typedef CScriptValue (*ScriptRootHandlerPtr)(IScriptInterpreter *,char *,void *); + +class IScriptInterpreter { +public: + virtual void Destroy() =0; + + virtual void SetRootHandler(ScriptRootHandlerPtr, void *) =0; + + virtual void ExecuteLine(char *s) =0; + + virtual void ScriptError(int e) =0; + virtual char* TranslateScriptError(CScriptError& cse) =0; + virtual char** AllocTempString(long l) =0; + + virtual CScriptValue LookupObjectMember(CScriptObject *obj, void *, char *szIdent) = 0; +}; + +extern "C" __declspec(dllexport) IScriptInterpreter * __stdcall CreateScriptInterpreter(); + +#define GETPROC_CREATESCRIPTINTERPRETER(hInst) ((IScriptInterpreter *(__stdcall *)())GetProcAddress(hInst, "_CreateScriptInterpreter@0")) + +#define EXT_SCRIPT_ERROR(x) (isi->ScriptError((CScriptError::x))) + +#endif diff --git a/include/vd2/extras/FilterSDK/ScriptValue.h b/include/vd2/extras/FilterSDK/ScriptValue.h index 91eec93ea29..52e629a3f3f 100644 --- a/include/vd2/extras/FilterSDK/ScriptValue.h +++ b/include/vd2/extras/FilterSDK/ScriptValue.h @@ -1,126 +1,126 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - -#ifndef f_SYLIA_SCRIPTVALUE_H -#define f_SYLIA_SCRIPTVALUE_H - -class CScriptArray; -struct CScriptObject; -class CScriptValue; -class IScriptInterpreter; -class VariableTableEntry; - -typedef CScriptValue (*ScriptObjectLookupFuncPtr)(IScriptInterpreter *, CScriptObject *, void *lpVoid, char *szName); -typedef CScriptValue (*ScriptFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); -typedef void (*ScriptVoidFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); -typedef int (*ScriptIntFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); -typedef CScriptValue (*ScriptArrayFunctionPtr)(IScriptInterpreter *, void *, int); - -typedef struct ScriptFunctionDef { - ScriptFunctionPtr func_ptr; - char *name; - char *arg_list; -} ScriptFunctionDef; - -typedef struct ScriptObjectDef { - char *name; - CScriptObject *obj; -} ScriptObjectDef; - -typedef struct CScriptObject { - ScriptObjectLookupFuncPtr Lookup; - ScriptFunctionDef *func_list; - ScriptObjectDef *obj_list; -} CScriptObject; - -class CScriptValue { -public: - enum { T_VOID, T_INT, T_PINT, T_STR, T_ARRAY, T_OBJECT, T_FNAME, T_FUNCTION, T_VARLV } type; - CScriptObject *thisPtr; - union { - int i; - int *pi; - char **s; - ScriptArrayFunctionPtr ary; - CScriptObject *obj; - ScriptFunctionPtr func; - ScriptFunctionDef *fname; - VariableTableEntry *vte; - } u; - void *lpVoid; - - CScriptValue() { type = T_VOID; } - CScriptValue(int i) { type = T_INT; u.i = i; } - CScriptValue(int *pi) { type = T_PINT; u.pi = pi; } - CScriptValue(char **s) { type = T_STR; u.s = s; } - CScriptValue(CScriptObject *obj) { type = T_OBJECT; u.obj = obj; } - CScriptValue(CScriptObject *_thisPtr, ScriptArrayFunctionPtr csa) { - type = T_ARRAY; - u.ary = csa; - thisPtr = _thisPtr; - } - CScriptValue(CScriptObject *_thisPtr, ScriptFunctionDef *sfd) { - type = T_FNAME; - u.fname = sfd; - thisPtr = _thisPtr; - } - CScriptValue(CScriptObject *_thisPtr, ScriptFunctionPtr fn) { - type = T_FUNCTION; - u.func = fn; - thisPtr = _thisPtr; - } - CScriptValue(VariableTableEntry *vte) { type = T_VARLV; u.vte = vte; } - - bool isVoid() { return type == T_VOID; } - bool isInt() { return type == T_INT; } - bool isString() { return type == T_STR; } - bool isArray() { return type == T_ARRAY; } - bool isObject() { return type == T_OBJECT; } - bool isFName() { return type == T_FNAME; } - bool isFunction() { return type == T_FUNCTION; } - bool isVarLV() { return type == T_VARLV; } - - int asInt() { return u.i; } - char ** asString() { return u.s; } - ScriptArrayFunctionPtr asArray() { return u.ary; } - CScriptObject * asObject() { return u.obj; } - ScriptFunctionPtr asFunction() { return u.func; } - VariableTableEntry* asVarLV() { return u.vte; } -}; - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + +#ifndef f_SYLIA_SCRIPTVALUE_H +#define f_SYLIA_SCRIPTVALUE_H + +class CScriptArray; +struct CScriptObject; +class CScriptValue; +class IScriptInterpreter; +class VariableTableEntry; + +typedef CScriptValue (*ScriptObjectLookupFuncPtr)(IScriptInterpreter *, CScriptObject *, void *lpVoid, char *szName); +typedef CScriptValue (*ScriptFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); +typedef void (*ScriptVoidFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); +typedef int (*ScriptIntFunctionPtr)(IScriptInterpreter *, void *, CScriptValue *, int); +typedef CScriptValue (*ScriptArrayFunctionPtr)(IScriptInterpreter *, void *, int); + +typedef struct ScriptFunctionDef { + ScriptFunctionPtr func_ptr; + char *name; + char *arg_list; +} ScriptFunctionDef; + +typedef struct ScriptObjectDef { + char *name; + CScriptObject *obj; +} ScriptObjectDef; + +typedef struct CScriptObject { + ScriptObjectLookupFuncPtr Lookup; + ScriptFunctionDef *func_list; + ScriptObjectDef *obj_list; +} CScriptObject; + +class CScriptValue { +public: + enum { T_VOID, T_INT, T_PINT, T_STR, T_ARRAY, T_OBJECT, T_FNAME, T_FUNCTION, T_VARLV } type; + CScriptObject *thisPtr; + union { + int i; + int *pi; + char **s; + ScriptArrayFunctionPtr ary; + CScriptObject *obj; + ScriptFunctionPtr func; + ScriptFunctionDef *fname; + VariableTableEntry *vte; + } u; + void *lpVoid; + + CScriptValue() { type = T_VOID; } + CScriptValue(int i) { type = T_INT; u.i = i; } + CScriptValue(int *pi) { type = T_PINT; u.pi = pi; } + CScriptValue(char **s) { type = T_STR; u.s = s; } + CScriptValue(CScriptObject *obj) { type = T_OBJECT; u.obj = obj; } + CScriptValue(CScriptObject *_thisPtr, ScriptArrayFunctionPtr csa) { + type = T_ARRAY; + u.ary = csa; + thisPtr = _thisPtr; + } + CScriptValue(CScriptObject *_thisPtr, ScriptFunctionDef *sfd) { + type = T_FNAME; + u.fname = sfd; + thisPtr = _thisPtr; + } + CScriptValue(CScriptObject *_thisPtr, ScriptFunctionPtr fn) { + type = T_FUNCTION; + u.func = fn; + thisPtr = _thisPtr; + } + CScriptValue(VariableTableEntry *vte) { type = T_VARLV; u.vte = vte; } + + bool isVoid() { return type == T_VOID; } + bool isInt() { return type == T_INT; } + bool isString() { return type == T_STR; } + bool isArray() { return type == T_ARRAY; } + bool isObject() { return type == T_OBJECT; } + bool isFName() { return type == T_FNAME; } + bool isFunction() { return type == T_FUNCTION; } + bool isVarLV() { return type == T_VARLV; } + + int asInt() { return u.i; } + char ** asString() { return u.s; } + ScriptArrayFunctionPtr asArray() { return u.ary; } + CScriptObject * asObject() { return u.obj; } + ScriptFunctionPtr asFunction() { return u.func; } + VariableTableEntry* asVarLV() { return u.vte; } +}; + +#endif diff --git a/include/vd2/extras/FilterSDK/VBitmap.h b/include/vd2/extras/FilterSDK/VBitmap.h index 8b1a8a00470..0b95066fc87 100644 --- a/include/vd2/extras/FilterSDK/VBitmap.h +++ b/include/vd2/extras/FilterSDK/VBitmap.h @@ -1,172 +1,172 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2002 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// -// FILTER EXEMPTION: -// -// As a special exemption to the GPL in order to permit creation of -// filters that work with multiple programs as well as VirtualDub, -// compiling with this header file shall not be considered creation -// of a derived work; that is, the act of compiling with this header -// file does not require your source code or the resulting module -// to be released in source code form or under a GPL-compatible -// license according to parts (2) and (3) of the GPL. A filter built -// using this header file may thus be licensed or dual-licensed so -// that it may be used with VirtualDub as well as an alternative -// product whose license is incompatible with the GPL. -// -// Nothing in this exemption shall be construed as applying to -// VirtualDub itself -- that is, this exemption does not give you -// permission to use parts of VirtualDub's source besides this -// header file, or to dynamically link with VirtualDub as part -// of the filter load process, in a fashion not permitted by the -// GPL. - -#ifndef f_VIRTUALDUB_VBITMAP_H -#define f_VIRTUALDUB_VBITMAP_H - -#include - -typedef unsigned long Pixel; -typedef unsigned long Pixel32; -typedef unsigned char Pixel8; -typedef long PixCoord; -typedef long PixDim; -typedef long PixOffset; - -#ifdef VDEXT_VIDEO_FILTER -#define NOVTABLE __declspec(novtable) -#else -#define NOVTABLE -#endif - -class NOVTABLE VBitmap { -public: - Pixel * data; - Pixel * palette; - int depth; - PixCoord w, h; - PixOffset pitch; - PixOffset modulo; - PixOffset size; - PixOffset offset; - - Pixel *Address(PixCoord x, PixCoord y) const { - return Addressi(x, h-y-1); - } - - Pixel *Addressi(PixCoord x, PixCoord y) const { - return (Pixel *)((char *)data + y*pitch + x*(depth>>3)); - } - - Pixel *Address16(PixCoord x, PixCoord y) const { - return Address16i(x, h-y-1); - } - - Pixel *Address16i(PixCoord x, PixCoord y) const { - return (Pixel *)((char *)data + y*pitch + x*2); - } - - Pixel *Address32(PixCoord x, PixCoord y) const { - return Address32i(x, h-y-1); - } - - Pixel *Address32i(PixCoord x, PixCoord y) const { - return (Pixel *)((char *)data + y*pitch + x*sizeof(Pixel)); - } - - PixOffset PitchAlign4() { - return ((w * depth + 31)/32)*4; - } - - PixOffset PitchAlign8() { - return ((w * depth + 63)/64)*8; - } - - PixOffset Modulo() { - return pitch - (w*depth+7)/8; - } - - PixOffset Size() { - return pitch*h; - } - - ////// - - VBitmap() throw() { -#ifdef VDEXT_VIDEO_FILTER - init(); -#endif - } - VBitmap(void *data, PixDim w, PixDim h, int depth) throw(); - VBitmap(void *data, BITMAPINFOHEADER *) throw(); - -#ifdef VDEXT_VIDEO_FILTER - void init() throw() { *(void **)this = g_vtbls.pvtblVBitmap; } -#endif - - virtual VBitmap& init(void *data, PixDim w, PixDim h, int depth) throw(); - virtual VBitmap& init(void *data, BITMAPINFOHEADER *) throw(); - - virtual void MakeBitmapHeader(BITMAPINFOHEADER *bih) const throw(); - - virtual void AlignTo4() throw(); - virtual void AlignTo8() throw(); - - virtual void BitBlt(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); - virtual void BitBltDither(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy, bool to565) const throw(); - virtual void BitBlt565(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy) const throw(); - - virtual bool BitBltXlat1(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel8 *tbl) const throw(); - virtual bool BitBltXlat3(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel32 *tbl) const throw(); - - virtual bool StretchBltNearestFast(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const VBitmap *src, double x2, double y2, double dx1, double dy1) const throw(); - - virtual bool StretchBltBilinearFast(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const VBitmap *src, double x2, double y2, double dx1, double dy1) const throw(); - - virtual bool RectFill(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, Pixel32 c) const throw(); - - enum { - HISTO_LUMA, - HISTO_GRAY, - HISTO_RED, - HISTO_GREEN, - HISTO_BLUE, - }; - - virtual bool Histogram(PixCoord x, PixCoord y, PixCoord dx, PixCoord dy, long *pHisto, int iHistoType) const throw(); - - //// NEW AS OF VIRTUALDUB V1.2B - - virtual bool BitBltFromYUY2(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); - virtual bool BitBltFromI420(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); - - //// NEW AS OF VIRTUALDUB V1.4C - - virtual void MakeBitmapHeaderNoPadding(BITMAPINFOHEADER *bih) const throw(); - - /////////// - - bool BitBltFromYUY2Fullscale(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); - -private: - bool dualrectclip(PixCoord& x2, PixCoord& y2, const VBitmap *src, PixCoord& x1, PixCoord& y1, PixDim& dx, PixDim& dy) const throw(); -}; - -#undef NOVTABLE - -#endif +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2002 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// FILTER EXEMPTION: +// +// As a special exemption to the GPL in order to permit creation of +// filters that work with multiple programs as well as VirtualDub, +// compiling with this header file shall not be considered creation +// of a derived work; that is, the act of compiling with this header +// file does not require your source code or the resulting module +// to be released in source code form or under a GPL-compatible +// license according to parts (2) and (3) of the GPL. A filter built +// using this header file may thus be licensed or dual-licensed so +// that it may be used with VirtualDub as well as an alternative +// product whose license is incompatible with the GPL. +// +// Nothing in this exemption shall be construed as applying to +// VirtualDub itself -- that is, this exemption does not give you +// permission to use parts of VirtualDub's source besides this +// header file, or to dynamically link with VirtualDub as part +// of the filter load process, in a fashion not permitted by the +// GPL. + +#ifndef f_VIRTUALDUB_VBITMAP_H +#define f_VIRTUALDUB_VBITMAP_H + +#include + +typedef unsigned long Pixel; +typedef unsigned long Pixel32; +typedef unsigned char Pixel8; +typedef long PixCoord; +typedef long PixDim; +typedef long PixOffset; + +#ifdef VDEXT_VIDEO_FILTER +#define NOVTABLE __declspec(novtable) +#else +#define NOVTABLE +#endif + +class NOVTABLE VBitmap { +public: + Pixel * data; + Pixel * palette; + int depth; + PixCoord w, h; + PixOffset pitch; + PixOffset modulo; + PixOffset size; + PixOffset offset; + + Pixel *Address(PixCoord x, PixCoord y) const { + return Addressi(x, h-y-1); + } + + Pixel *Addressi(PixCoord x, PixCoord y) const { + return (Pixel *)((char *)data + y*pitch + x*(depth>>3)); + } + + Pixel *Address16(PixCoord x, PixCoord y) const { + return Address16i(x, h-y-1); + } + + Pixel *Address16i(PixCoord x, PixCoord y) const { + return (Pixel *)((char *)data + y*pitch + x*2); + } + + Pixel *Address32(PixCoord x, PixCoord y) const { + return Address32i(x, h-y-1); + } + + Pixel *Address32i(PixCoord x, PixCoord y) const { + return (Pixel *)((char *)data + y*pitch + x*sizeof(Pixel)); + } + + PixOffset PitchAlign4() { + return ((w * depth + 31)/32)*4; + } + + PixOffset PitchAlign8() { + return ((w * depth + 63)/64)*8; + } + + PixOffset Modulo() { + return pitch - (w*depth+7)/8; + } + + PixOffset Size() { + return pitch*h; + } + + ////// + + VBitmap() throw() { +#ifdef VDEXT_VIDEO_FILTER + init(); +#endif + } + VBitmap(void *data, PixDim w, PixDim h, int depth) throw(); + VBitmap(void *data, BITMAPINFOHEADER *) throw(); + +#ifdef VDEXT_VIDEO_FILTER + void init() throw() { *(void **)this = g_vtbls.pvtblVBitmap; } +#endif + + virtual VBitmap& init(void *data, PixDim w, PixDim h, int depth) throw(); + virtual VBitmap& init(void *data, BITMAPINFOHEADER *) throw(); + + virtual void MakeBitmapHeader(BITMAPINFOHEADER *bih) const throw(); + + virtual void AlignTo4() throw(); + virtual void AlignTo8() throw(); + + virtual void BitBlt(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); + virtual void BitBltDither(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy, bool to565) const throw(); + virtual void BitBlt565(PixCoord x2, PixCoord y2, const VBitmap *src, PixDim x1, PixDim y1, PixDim dx, PixDim dy) const throw(); + + virtual bool BitBltXlat1(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel8 *tbl) const throw(); + virtual bool BitBltXlat3(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const Pixel32 *tbl) const throw(); + + virtual bool StretchBltNearestFast(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const VBitmap *src, double x2, double y2, double dx1, double dy1) const throw(); + + virtual bool StretchBltBilinearFast(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, const VBitmap *src, double x2, double y2, double dx1, double dy1) const throw(); + + virtual bool RectFill(PixCoord x1, PixCoord y1, PixDim dx, PixDim dy, Pixel32 c) const throw(); + + enum { + HISTO_LUMA, + HISTO_GRAY, + HISTO_RED, + HISTO_GREEN, + HISTO_BLUE, + }; + + virtual bool Histogram(PixCoord x, PixCoord y, PixCoord dx, PixCoord dy, long *pHisto, int iHistoType) const throw(); + + //// NEW AS OF VIRTUALDUB V1.2B + + virtual bool BitBltFromYUY2(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); + virtual bool BitBltFromI420(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); + + //// NEW AS OF VIRTUALDUB V1.4C + + virtual void MakeBitmapHeaderNoPadding(BITMAPINFOHEADER *bih) const throw(); + + /////////// + + bool BitBltFromYUY2Fullscale(PixCoord x2, PixCoord y2, const VBitmap *src, PixCoord x1, PixCoord y1, PixDim dx, PixDim dy) const throw(); + +private: + bool dualrectclip(PixCoord& x2, PixCoord& y2, const VBitmap *src, PixCoord& x1, PixCoord& y1, PixDim& dx, PixDim& dy) const throw(); +}; + +#undef NOVTABLE + +#endif diff --git a/include/vd2/extras/FilterSDK/VirtualDub.h b/include/vd2/extras/FilterSDK/VirtualDub.h index 5195b15f55d..25e5fd47595 100644 --- a/include/vd2/extras/FilterSDK/VirtualDub.h +++ b/include/vd2/extras/FilterSDK/VirtualDub.h @@ -1,7 +1,7 @@ -#pragma once - -#include "Filter.h" -#include "ScriptInterpreter.h" -#include "ScriptError.h" -#include "ScriptValue.h" -#include "VBitmap.h" +#pragma once + +#include "Filter.h" +#include "ScriptInterpreter.h" +#include "ScriptError.h" +#include "ScriptValue.h" +#include "VBitmap.h" diff --git a/include/vd2/plugin/vdaudiofilt.h b/include/vd2/plugin/vdaudiofilt.h index e4237ec4422..2680ad794c0 100644 --- a/include/vd2/plugin/vdaudiofilt.h +++ b/include/vd2/plugin/vdaudiofilt.h @@ -1,148 +1,148 @@ -#ifndef f_VD2_PLUGIN_VDAUDIOFILT_H -#define f_VD2_PLUGIN_VDAUDIOFILT_H - -/////////////////////////////////////////////////////////////////////////// -// -// Audio filter support - -struct VDAudioFilterDefinition; -struct VDXWaveFormat; -struct VDPluginCallbacks; - -enum { - kVDPlugin_AudioAPIVersion = 2 -}; - -struct VDAudioFilterPin { - unsigned mGranularity; // Block size a filter reads/writes this pin. - unsigned mDelay; // Delay in samples on this input. - unsigned mBufferSize; // The size, in samples, of the buffer. - unsigned mCurrentLevel; // The number of samples currently in the buffer. - sint64 mLength; // Approximate length of this stream in us. - const VDXWaveFormat *mpFormat; - bool mbVBR; - bool mbEnded; - char _pad[2]; - void *mpBuffer; - unsigned mSamplesWritten; // The number of samples just written to the buffer. - unsigned mAvailSpace; // Available room pointed to by mpBuffer (output pins only). - - uint32 (VDAPIENTRY *mpReadProc)(VDAudioFilterPin *pPin, void *dst, uint32 samples, bool bAllowFill, int format); - - // These helpers are non-virtual inlines and are compiled into filters. - uint32 Read(void *dst, uint32 samples, bool bAllowFill, int format) { - return mpReadProc(this, dst, samples, bAllowFill, format); - } -}; - -struct VDAudioFilterContext; - -struct VDAudioFilterCallbacks { - VDXWaveFormat *(VDAPIENTRY *AllocPCMWaveFormat)(unsigned sampling_rate, unsigned channels, unsigned bits, bool bFloat); - VDXWaveFormat *(VDAPIENTRY *AllocCustomWaveFormat)(unsigned extra_size); - VDXWaveFormat *(VDAPIENTRY *CopyWaveFormat)(const VDXWaveFormat *); - void (VDAPIENTRY *FreeWaveFormat)(const VDXWaveFormat *); - void (VDAPIENTRY *Wake)(const VDAudioFilterContext *pContext); -}; - -struct VDAudioFilterContext { - void *mpFilterData; - VDAudioFilterPin **mpInputs; - VDAudioFilterPin **mpOutputs; - IVDPluginCallbacks *mpServices; - const VDAudioFilterCallbacks *mpAudioCallbacks; - const VDAudioFilterDefinition *mpDefinition; - uint32 mAPIVersion; - uint32 mInputSamples; // Number of input samples available on all pins. - uint32 mInputGranules; // Number of input granules available on all pins. - uint32 mInputsEnded; // Number of inputs that have ended. - uint32 mOutputSamples; // Number of output sample spaces available on all pins. - uint32 mOutputGranules; // Number of output granule spaces available on all pins. - uint32 mCommonSamples; // Number of input samples and output sample spaces. - uint32 mCommonGranules; // Number of input and output granules. -}; - -// This structure is intentionally identical to WAVEFORMATEX, with one -// exception -- mExtraSize is *always* present, even for PCM. - -struct VDXWaveFormat { - enum { kTagPCM = 1 }; - - uint16 mTag; - uint16 mChannels; - uint32 mSamplingRate; - uint32 mDataRate; - uint16 mBlockSize; - uint16 mSampleBits; - uint16 mExtraSize; -}; - -enum { - kVFARun_OK = 0, - kVFARun_Finished = 1, - kVFARun_InternalWork = 2, - - kVFAPrepare_OK = 0, - kVFAPrepare_BadFormat = 1 -}; - -enum { - kVFARead_Native = 0, - kVFARead_PCM8 = 1, - kVFARead_PCM16 = 2, - kVFARead_PCM32F = 3 -}; - -typedef void * (VDAPIENTRY *VDAudioFilterExtProc )(const VDAudioFilterContext *pContext, const char *pInterfaceName); -typedef uint32 (VDAPIENTRY *VDAudioFilterRunProc )(const VDAudioFilterContext *pContext); -typedef sint64 (VDAPIENTRY *VDAudioFilterSeekProc )(const VDAudioFilterContext *pContext, sint64 microsecs); -typedef uint32 (VDAPIENTRY *VDAudioFilterPrepareProc )(const VDAudioFilterContext *pContext); -typedef void (VDAPIENTRY *VDAudioFilterStartProc )(const VDAudioFilterContext *pContext); -typedef void (VDAPIENTRY *VDAudioFilterStopProc )(const VDAudioFilterContext *pContext); -typedef void (VDAPIENTRY *VDAudioFilterInitProc )(const VDAudioFilterContext *pContext); -typedef void (VDAPIENTRY *VDAudioFilterDestroyProc )(const VDAudioFilterContext *pContext); -typedef unsigned (VDAPIENTRY *VDAudioFilterSuspendProc )(const VDAudioFilterContext *pContext, void *dst, unsigned size); -typedef void (VDAPIENTRY *VDAudioFilterResumeProc )(const VDAudioFilterContext *pContext, const void *src, unsigned size); -typedef unsigned (VDAPIENTRY *VDAudioFilterGetParamProc )(const VDAudioFilterContext *pContext, unsigned idx, void *dst, unsigned size); -typedef void (VDAPIENTRY *VDAudioFilterSetParamProc )(const VDAudioFilterContext *pContext, unsigned idx, const void *src, unsigned variant_count); -typedef bool (VDAPIENTRY *VDAudioFilterConfigProc )(const VDAudioFilterContext *pContext, struct HWND__ *hwnd); - -enum { - kVFAF_Zero = 0, - kVFAF_HasConfig = 1, // Filter has a configuration dialog. - kVFAF_SerializedIO = 2, // Filter must execute in the serialized I/O thread. - - kVFAF_Max = 0xFFFFFFFF, -}; - -struct VDAudioFilterVtbl { - uint32 mSize; - VDAudioFilterDestroyProc mpDestroy; - VDAudioFilterPrepareProc mpPrepare; - VDAudioFilterStartProc mpStart; - VDAudioFilterStopProc mpStop; - VDAudioFilterRunProc mpRun; - VDAudioFilterSeekProc mpSeek; - VDAudioFilterSuspendProc mpSuspend; - VDAudioFilterResumeProc mpResume; - VDAudioFilterGetParamProc mpGetParam; - VDAudioFilterSetParamProc mpSetParam; - VDAudioFilterConfigProc mpConfig; - VDAudioFilterExtProc mpExt; -}; - -struct VDAudioFilterDefinition { - uint32 mSize; // size of this structure in bytes - uint32 mFlags; - - uint32 mFilterDataSize; - uint32 mInputPins; - uint32 mOutputPins; - - const VDXPluginConfigEntry *mpConfigInfo; - - VDAudioFilterInitProc mpInit; - const VDAudioFilterVtbl *mpVtbl; -}; - -#endif +#ifndef f_VD2_PLUGIN_VDAUDIOFILT_H +#define f_VD2_PLUGIN_VDAUDIOFILT_H + +/////////////////////////////////////////////////////////////////////////// +// +// Audio filter support + +struct VDAudioFilterDefinition; +struct VDXWaveFormat; +struct VDPluginCallbacks; + +enum { + kVDPlugin_AudioAPIVersion = 2 +}; + +struct VDAudioFilterPin { + unsigned mGranularity; // Block size a filter reads/writes this pin. + unsigned mDelay; // Delay in samples on this input. + unsigned mBufferSize; // The size, in samples, of the buffer. + unsigned mCurrentLevel; // The number of samples currently in the buffer. + sint64 mLength; // Approximate length of this stream in us. + const VDXWaveFormat *mpFormat; + bool mbVBR; + bool mbEnded; + char _pad[2]; + void *mpBuffer; + unsigned mSamplesWritten; // The number of samples just written to the buffer. + unsigned mAvailSpace; // Available room pointed to by mpBuffer (output pins only). + + uint32 (VDAPIENTRY *mpReadProc)(VDAudioFilterPin *pPin, void *dst, uint32 samples, bool bAllowFill, int format); + + // These helpers are non-virtual inlines and are compiled into filters. + uint32 Read(void *dst, uint32 samples, bool bAllowFill, int format) { + return mpReadProc(this, dst, samples, bAllowFill, format); + } +}; + +struct VDAudioFilterContext; + +struct VDAudioFilterCallbacks { + VDXWaveFormat *(VDAPIENTRY *AllocPCMWaveFormat)(unsigned sampling_rate, unsigned channels, unsigned bits, bool bFloat); + VDXWaveFormat *(VDAPIENTRY *AllocCustomWaveFormat)(unsigned extra_size); + VDXWaveFormat *(VDAPIENTRY *CopyWaveFormat)(const VDXWaveFormat *); + void (VDAPIENTRY *FreeWaveFormat)(const VDXWaveFormat *); + void (VDAPIENTRY *Wake)(const VDAudioFilterContext *pContext); +}; + +struct VDAudioFilterContext { + void *mpFilterData; + VDAudioFilterPin **mpInputs; + VDAudioFilterPin **mpOutputs; + IVDPluginCallbacks *mpServices; + const VDAudioFilterCallbacks *mpAudioCallbacks; + const VDAudioFilterDefinition *mpDefinition; + uint32 mAPIVersion; + uint32 mInputSamples; // Number of input samples available on all pins. + uint32 mInputGranules; // Number of input granules available on all pins. + uint32 mInputsEnded; // Number of inputs that have ended. + uint32 mOutputSamples; // Number of output sample spaces available on all pins. + uint32 mOutputGranules; // Number of output granule spaces available on all pins. + uint32 mCommonSamples; // Number of input samples and output sample spaces. + uint32 mCommonGranules; // Number of input and output granules. +}; + +// This structure is intentionally identical to WAVEFORMATEX, with one +// exception -- mExtraSize is *always* present, even for PCM. + +struct VDXWaveFormat { + enum { kTagPCM = 1 }; + + uint16 mTag; + uint16 mChannels; + uint32 mSamplingRate; + uint32 mDataRate; + uint16 mBlockSize; + uint16 mSampleBits; + uint16 mExtraSize; +}; + +enum { + kVFARun_OK = 0, + kVFARun_Finished = 1, + kVFARun_InternalWork = 2, + + kVFAPrepare_OK = 0, + kVFAPrepare_BadFormat = 1 +}; + +enum { + kVFARead_Native = 0, + kVFARead_PCM8 = 1, + kVFARead_PCM16 = 2, + kVFARead_PCM32F = 3 +}; + +typedef void * (VDAPIENTRY *VDAudioFilterExtProc )(const VDAudioFilterContext *pContext, const char *pInterfaceName); +typedef uint32 (VDAPIENTRY *VDAudioFilterRunProc )(const VDAudioFilterContext *pContext); +typedef sint64 (VDAPIENTRY *VDAudioFilterSeekProc )(const VDAudioFilterContext *pContext, sint64 microsecs); +typedef uint32 (VDAPIENTRY *VDAudioFilterPrepareProc )(const VDAudioFilterContext *pContext); +typedef void (VDAPIENTRY *VDAudioFilterStartProc )(const VDAudioFilterContext *pContext); +typedef void (VDAPIENTRY *VDAudioFilterStopProc )(const VDAudioFilterContext *pContext); +typedef void (VDAPIENTRY *VDAudioFilterInitProc )(const VDAudioFilterContext *pContext); +typedef void (VDAPIENTRY *VDAudioFilterDestroyProc )(const VDAudioFilterContext *pContext); +typedef unsigned (VDAPIENTRY *VDAudioFilterSuspendProc )(const VDAudioFilterContext *pContext, void *dst, unsigned size); +typedef void (VDAPIENTRY *VDAudioFilterResumeProc )(const VDAudioFilterContext *pContext, const void *src, unsigned size); +typedef unsigned (VDAPIENTRY *VDAudioFilterGetParamProc )(const VDAudioFilterContext *pContext, unsigned idx, void *dst, unsigned size); +typedef void (VDAPIENTRY *VDAudioFilterSetParamProc )(const VDAudioFilterContext *pContext, unsigned idx, const void *src, unsigned variant_count); +typedef bool (VDAPIENTRY *VDAudioFilterConfigProc )(const VDAudioFilterContext *pContext, struct HWND__ *hwnd); + +enum { + kVFAF_Zero = 0, + kVFAF_HasConfig = 1, // Filter has a configuration dialog. + kVFAF_SerializedIO = 2, // Filter must execute in the serialized I/O thread. + + kVFAF_Max = 0xFFFFFFFF, +}; + +struct VDAudioFilterVtbl { + uint32 mSize; + VDAudioFilterDestroyProc mpDestroy; + VDAudioFilterPrepareProc mpPrepare; + VDAudioFilterStartProc mpStart; + VDAudioFilterStopProc mpStop; + VDAudioFilterRunProc mpRun; + VDAudioFilterSeekProc mpSeek; + VDAudioFilterSuspendProc mpSuspend; + VDAudioFilterResumeProc mpResume; + VDAudioFilterGetParamProc mpGetParam; + VDAudioFilterSetParamProc mpSetParam; + VDAudioFilterConfigProc mpConfig; + VDAudioFilterExtProc mpExt; +}; + +struct VDAudioFilterDefinition { + uint32 mSize; // size of this structure in bytes + uint32 mFlags; + + uint32 mFilterDataSize; + uint32 mInputPins; + uint32 mOutputPins; + + const VDXPluginConfigEntry *mpConfigInfo; + + VDAudioFilterInitProc mpInit; + const VDAudioFilterVtbl *mpVtbl; +}; + +#endif diff --git a/include/vd2/plugin/vdinputdriver.h b/include/vd2/plugin/vdinputdriver.h index a6b756e453f..b75738c98af 100644 --- a/include/vd2/plugin/vdinputdriver.h +++ b/include/vd2/plugin/vdinputdriver.h @@ -1,284 +1,284 @@ -// VirtualDub - Video processing and capture application -// Plugin headers -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_PLUGIN_VDINPUTDRIVER_H -#define f_VD2_PLUGIN_VDINPUTDRIVER_H - -#ifdef _MSC_VER - #pragma once - #pragma pack(push, 8) -#endif - -#include "vdplugin.h" - -/// Unsigned 32-bit fraction. -struct VDXFraction { - uint32 mNumerator; - uint32 mDenominator; -}; - -typedef struct VDXHWNDStruct *VDXHWND; -typedef struct VDXBITMAPINFOHEADERStruct { - enum { kCompressionRGB = 0 }; - uint32 mSize; - sint32 mWidth; - sint32 mHeight; - uint16 mPlanes; - uint16 mBitCount; - uint32 mCompression; - uint32 mSizeImage; - sint32 mXPelsPerMeter; - sint32 mYPelsPerMeter; - uint32 mClrUsed; - uint32 mClrImportant; -} VDXBITMAPINFOHEADER; - -typedef struct VDXWAVEFORMATEXStruct { - enum { kFormatPCM = 1 }; - uint16 mFormatTag; - uint16 mChannels; - uint32 mSamplesPerSec; - uint32 mAvgBytesPerSec; - uint16 mBlockAlign; - uint16 mBitsPerSample; - uint16 mExtraSize; -} VDXWAVEFORMATEX; - -struct VDXStreamSourceInfo { - VDXFraction mSampleRate; - sint64 mSampleCount; - VDXFraction mPixelAspectRatio; -}; - -// V3+ (1.7.X) only -struct VDXStreamSourceInfoV3 { - VDXStreamSourceInfo mInfo; - - enum { - kFlagVariableSizeSamples = 0x00000001 - }; - - uint32 mFlags; - uint32 mfccHandler; ///< If non-zero, specifies the FOURCC of a codec handler that should be preferred. -}; - -class IVDXStreamSource : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 's', 't', 's') }; - - virtual void VDXAPIENTRY GetStreamSourceInfo(VDXStreamSourceInfo&) = 0; - - virtual bool VDXAPIENTRY Read(sint64 lStart, uint32 lCount, void *lpBuffer, uint32 cbBuffer, uint32 *lBytesRead, uint32 *lSamplesRead) = 0; - - virtual const void * VDXAPIENTRY GetDirectFormat() = 0; - virtual int VDXAPIENTRY GetDirectFormatLen() = 0; - - enum ErrorMode { - kErrorModeReportAll = 0, - kErrorModeConceal, - kErrorModeDecodeAnyway, - kErrorModeCount - }; - - virtual ErrorMode VDXAPIENTRY GetDecodeErrorMode() = 0; - virtual void VDXAPIENTRY SetDecodeErrorMode(ErrorMode mode) = 0; - virtual bool VDXAPIENTRY IsDecodeErrorModeSupported(ErrorMode mode) = 0; - - virtual bool VDXAPIENTRY IsVBR() = 0; - virtual sint64 VDXAPIENTRY TimeToPositionVBR(sint64 us) = 0; - virtual sint64 VDXAPIENTRY PositionToTimeVBR(sint64 samples) = 0; -}; - -// V3+ (1.7.X) -class IVDXStreamSourceV3 : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 's', 't', '2') }; - - virtual void VDXAPIENTRY GetStreamSourceInfoV3(VDXStreamSourceInfoV3&) = 0; -}; - -class IVDXVideoDecoderModel : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 'm') }; - - virtual void VDXAPIENTRY Reset() = 0; - virtual void VDXAPIENTRY SetDesiredFrame(sint64 frame_num) = 0; - virtual sint64 VDXAPIENTRY GetNextRequiredSample(bool& is_preroll) = 0; - virtual int VDXAPIENTRY GetRequiredCount() = 0; -}; - -class IVDXVideoDecoder : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 'e') }; - - virtual const void * VDXAPIENTRY DecodeFrame(const void *inputBuffer, uint32 data_len, bool is_preroll, sint64 sampleNumber, sint64 targetFrame) = 0; - virtual uint32 VDXAPIENTRY GetDecodePadding() = 0; - virtual void VDXAPIENTRY Reset() = 0; - virtual bool VDXAPIENTRY IsFrameBufferValid() = 0; - virtual const VDXPixmap& VDXAPIENTRY GetFrameBuffer() = 0; - virtual bool VDXAPIENTRY SetTargetFormat(int format, bool useDIBAlignment) = 0; - virtual bool VDXAPIENTRY SetDecompressedFormat(const VDXBITMAPINFOHEADER *pbih) = 0; - - virtual bool VDXAPIENTRY IsDecodable(sint64 sample_num) = 0; - virtual const void * VDXAPIENTRY GetFrameBufferBase() = 0; -}; - -enum VDXVideoFrameType { - kVDXVFT_Independent, - kVDXVFT_Predicted, - kVDXVFT_Bidirectional, - kVDXVFT_Null, -}; - -struct VDXVideoFrameInfo { - char mTypeChar; - uint8 mFrameType; - sint64 mBytePosition; -}; - -struct VDXVideoSourceInfo { - enum DecoderModel { - kDecoderModelCustom, ///< A custom decoder model is provided. - kDecoderModelDefaultIP ///< Use the default I/P decoder model. - }; - - enum Flags { - kFlagNone = 0, - kFlagKeyframeOnly = 0x00000001, - kFlagAll = 0xFFFFFFFF - }; - -public: - uint32 mFlags; - uint32 mWidth; - uint32 mHeight; - uint8 mDecoderModel; - uint8 unused[3]; -}; - -class IVDXVideoSource : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 's') }; - - virtual void VDXAPIENTRY GetVideoSourceInfo(VDXVideoSourceInfo& info) = 0; - - virtual bool VDXAPIENTRY CreateVideoDecoderModel(IVDXVideoDecoderModel **) = 0; - virtual bool VDXAPIENTRY CreateVideoDecoder(IVDXVideoDecoder **) = 0; - - virtual void VDXAPIENTRY GetSampleInfo(sint64 sample_num, VDXVideoFrameInfo& frameInfo) = 0; - - virtual bool VDXAPIENTRY IsKey(sint64 sample_num) = 0; - - virtual sint64 VDXAPIENTRY GetFrameNumberForSample(sint64 sample_num) = 0; - virtual sint64 VDXAPIENTRY GetSampleNumberForFrame(sint64 frame_num) = 0; - virtual sint64 VDXAPIENTRY GetRealFrame(sint64 frame_num) = 0; - - virtual sint64 VDXAPIENTRY GetSampleBytePosition(sint64 sample_num) = 0; -}; - -struct VDXAudioSourceInfo { -public: - uint32 mFlags; -}; - -class IVDXAudioSource : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'a', 'd', 's') }; - - virtual void VDXAPIENTRY GetAudioSourceInfo(VDXAudioSourceInfo& info) = 0; -}; - -class IVDXInputOptions : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'i', 'o', 'p') }; - - virtual uint32 VDXAPIENTRY Write(void *buf, uint32 buflen) = 0; -}; - -class IVDXInputFile : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'i', 'f', 'l') }; - - virtual bool VDXAPIENTRY PromptForOptions(VDXHWND, IVDXInputOptions **ppOptions) = 0; - virtual bool VDXAPIENTRY CreateOptions(const void *buf, uint32 len, IVDXInputOptions **ppOptions) = 0; - - virtual void VDXAPIENTRY Init(const wchar_t *path, IVDXInputOptions *options) = 0; - virtual bool VDXAPIENTRY Append(const wchar_t *path) = 0; - - virtual void VDXAPIENTRY DisplayInfo(VDXHWND hwndParent) = 0; - - virtual bool VDXAPIENTRY GetVideoSource(int index, IVDXVideoSource **ppVS) = 0; - virtual bool VDXAPIENTRY GetAudioSource(int index, IVDXAudioSource **ppAS) = 0; -}; - -/////////////////////////////////////////////////////////////////////////////// -// IVDXInputFileDriver -// -class IVDXInputFileDriver : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'i', 'f', 'd') }; - - virtual int VDXAPIENTRY DetectBySignature(const void *pHeader, sint32 nHeaderSize, const void *pFooter, sint32 nFooterSize, sint64 nFileSize) = 0; - virtual bool VDXAPIENTRY CreateInputFile(uint32 flags, IVDXInputFile **ppFile) = 0; -}; - -struct VDXInputDriverContext { - uint32 mAPIVersion; - IVDPluginCallbacks *mpCallbacks; -}; - -typedef bool (VDXAPIENTRY *VDXInputDriverCreateProc)(const VDXInputDriverContext *pContext, IVDXInputFileDriver **); - -struct VDXInputDriverDefinition { - enum { - kFlagNone = 0x00000000, - kFlagSupportsVideo = 0x00000001, - kFlagSupportsAudio = 0x00000002, - kFlagCustomSignature = 0x00010000, - kFlagAll = 0xFFFFFFFF - }; - uint32 mSize; // size of this structure in bytes - uint32 mFlags; - sint32 mPriority; - uint32 mSignatureLength; - const void *mpSignature; - const wchar_t *mpFilenameDetectPattern; - const wchar_t *mpFilenamePattern; - const wchar_t *mpDriverTagName; - - VDXInputDriverCreateProc mpCreate; -}; - -enum { - // V1 (1.7.4.28204): Initial version - // V2 (1.7.5): Default I/P frame model fixed. - kVDXPlugin_InputDriverAPIVersion = 2 -}; - -#ifdef _MSC_VER - #pragma pack(pop) -#endif - -#endif +// VirtualDub - Video processing and capture application +// Plugin headers +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_PLUGIN_VDINPUTDRIVER_H +#define f_VD2_PLUGIN_VDINPUTDRIVER_H + +#ifdef _MSC_VER + #pragma once + #pragma pack(push, 8) +#endif + +#include "vdplugin.h" + +/// Unsigned 32-bit fraction. +struct VDXFraction { + uint32 mNumerator; + uint32 mDenominator; +}; + +typedef struct VDXHWNDStruct *VDXHWND; +typedef struct VDXBITMAPINFOHEADERStruct { + enum { kCompressionRGB = 0 }; + uint32 mSize; + sint32 mWidth; + sint32 mHeight; + uint16 mPlanes; + uint16 mBitCount; + uint32 mCompression; + uint32 mSizeImage; + sint32 mXPelsPerMeter; + sint32 mYPelsPerMeter; + uint32 mClrUsed; + uint32 mClrImportant; +} VDXBITMAPINFOHEADER; + +typedef struct VDXWAVEFORMATEXStruct { + enum { kFormatPCM = 1 }; + uint16 mFormatTag; + uint16 mChannels; + uint32 mSamplesPerSec; + uint32 mAvgBytesPerSec; + uint16 mBlockAlign; + uint16 mBitsPerSample; + uint16 mExtraSize; +} VDXWAVEFORMATEX; + +struct VDXStreamSourceInfo { + VDXFraction mSampleRate; + sint64 mSampleCount; + VDXFraction mPixelAspectRatio; +}; + +// V3+ (1.7.X) only +struct VDXStreamSourceInfoV3 { + VDXStreamSourceInfo mInfo; + + enum { + kFlagVariableSizeSamples = 0x00000001 + }; + + uint32 mFlags; + uint32 mfccHandler; ///< If non-zero, specifies the FOURCC of a codec handler that should be preferred. +}; + +class IVDXStreamSource : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 's', 't', 's') }; + + virtual void VDXAPIENTRY GetStreamSourceInfo(VDXStreamSourceInfo&) = 0; + + virtual bool VDXAPIENTRY Read(sint64 lStart, uint32 lCount, void *lpBuffer, uint32 cbBuffer, uint32 *lBytesRead, uint32 *lSamplesRead) = 0; + + virtual const void * VDXAPIENTRY GetDirectFormat() = 0; + virtual int VDXAPIENTRY GetDirectFormatLen() = 0; + + enum ErrorMode { + kErrorModeReportAll = 0, + kErrorModeConceal, + kErrorModeDecodeAnyway, + kErrorModeCount + }; + + virtual ErrorMode VDXAPIENTRY GetDecodeErrorMode() = 0; + virtual void VDXAPIENTRY SetDecodeErrorMode(ErrorMode mode) = 0; + virtual bool VDXAPIENTRY IsDecodeErrorModeSupported(ErrorMode mode) = 0; + + virtual bool VDXAPIENTRY IsVBR() = 0; + virtual sint64 VDXAPIENTRY TimeToPositionVBR(sint64 us) = 0; + virtual sint64 VDXAPIENTRY PositionToTimeVBR(sint64 samples) = 0; +}; + +// V3+ (1.7.X) +class IVDXStreamSourceV3 : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 's', 't', '2') }; + + virtual void VDXAPIENTRY GetStreamSourceInfoV3(VDXStreamSourceInfoV3&) = 0; +}; + +class IVDXVideoDecoderModel : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 'm') }; + + virtual void VDXAPIENTRY Reset() = 0; + virtual void VDXAPIENTRY SetDesiredFrame(sint64 frame_num) = 0; + virtual sint64 VDXAPIENTRY GetNextRequiredSample(bool& is_preroll) = 0; + virtual int VDXAPIENTRY GetRequiredCount() = 0; +}; + +class IVDXVideoDecoder : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 'e') }; + + virtual const void * VDXAPIENTRY DecodeFrame(const void *inputBuffer, uint32 data_len, bool is_preroll, sint64 sampleNumber, sint64 targetFrame) = 0; + virtual uint32 VDXAPIENTRY GetDecodePadding() = 0; + virtual void VDXAPIENTRY Reset() = 0; + virtual bool VDXAPIENTRY IsFrameBufferValid() = 0; + virtual const VDXPixmap& VDXAPIENTRY GetFrameBuffer() = 0; + virtual bool VDXAPIENTRY SetTargetFormat(int format, bool useDIBAlignment) = 0; + virtual bool VDXAPIENTRY SetDecompressedFormat(const VDXBITMAPINFOHEADER *pbih) = 0; + + virtual bool VDXAPIENTRY IsDecodable(sint64 sample_num) = 0; + virtual const void * VDXAPIENTRY GetFrameBufferBase() = 0; +}; + +enum VDXVideoFrameType { + kVDXVFT_Independent, + kVDXVFT_Predicted, + kVDXVFT_Bidirectional, + kVDXVFT_Null, +}; + +struct VDXVideoFrameInfo { + char mTypeChar; + uint8 mFrameType; + sint64 mBytePosition; +}; + +struct VDXVideoSourceInfo { + enum DecoderModel { + kDecoderModelCustom, ///< A custom decoder model is provided. + kDecoderModelDefaultIP ///< Use the default I/P decoder model. + }; + + enum Flags { + kFlagNone = 0, + kFlagKeyframeOnly = 0x00000001, + kFlagAll = 0xFFFFFFFF + }; + +public: + uint32 mFlags; + uint32 mWidth; + uint32 mHeight; + uint8 mDecoderModel; + uint8 unused[3]; +}; + +class IVDXVideoSource : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'v', 'd', 's') }; + + virtual void VDXAPIENTRY GetVideoSourceInfo(VDXVideoSourceInfo& info) = 0; + + virtual bool VDXAPIENTRY CreateVideoDecoderModel(IVDXVideoDecoderModel **) = 0; + virtual bool VDXAPIENTRY CreateVideoDecoder(IVDXVideoDecoder **) = 0; + + virtual void VDXAPIENTRY GetSampleInfo(sint64 sample_num, VDXVideoFrameInfo& frameInfo) = 0; + + virtual bool VDXAPIENTRY IsKey(sint64 sample_num) = 0; + + virtual sint64 VDXAPIENTRY GetFrameNumberForSample(sint64 sample_num) = 0; + virtual sint64 VDXAPIENTRY GetSampleNumberForFrame(sint64 frame_num) = 0; + virtual sint64 VDXAPIENTRY GetRealFrame(sint64 frame_num) = 0; + + virtual sint64 VDXAPIENTRY GetSampleBytePosition(sint64 sample_num) = 0; +}; + +struct VDXAudioSourceInfo { +public: + uint32 mFlags; +}; + +class IVDXAudioSource : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'a', 'd', 's') }; + + virtual void VDXAPIENTRY GetAudioSourceInfo(VDXAudioSourceInfo& info) = 0; +}; + +class IVDXInputOptions : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'i', 'o', 'p') }; + + virtual uint32 VDXAPIENTRY Write(void *buf, uint32 buflen) = 0; +}; + +class IVDXInputFile : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'i', 'f', 'l') }; + + virtual bool VDXAPIENTRY PromptForOptions(VDXHWND, IVDXInputOptions **ppOptions) = 0; + virtual bool VDXAPIENTRY CreateOptions(const void *buf, uint32 len, IVDXInputOptions **ppOptions) = 0; + + virtual void VDXAPIENTRY Init(const wchar_t *path, IVDXInputOptions *options) = 0; + virtual bool VDXAPIENTRY Append(const wchar_t *path) = 0; + + virtual void VDXAPIENTRY DisplayInfo(VDXHWND hwndParent) = 0; + + virtual bool VDXAPIENTRY GetVideoSource(int index, IVDXVideoSource **ppVS) = 0; + virtual bool VDXAPIENTRY GetAudioSource(int index, IVDXAudioSource **ppAS) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// IVDXInputFileDriver +// +class IVDXInputFileDriver : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'i', 'f', 'd') }; + + virtual int VDXAPIENTRY DetectBySignature(const void *pHeader, sint32 nHeaderSize, const void *pFooter, sint32 nFooterSize, sint64 nFileSize) = 0; + virtual bool VDXAPIENTRY CreateInputFile(uint32 flags, IVDXInputFile **ppFile) = 0; +}; + +struct VDXInputDriverContext { + uint32 mAPIVersion; + IVDPluginCallbacks *mpCallbacks; +}; + +typedef bool (VDXAPIENTRY *VDXInputDriverCreateProc)(const VDXInputDriverContext *pContext, IVDXInputFileDriver **); + +struct VDXInputDriverDefinition { + enum { + kFlagNone = 0x00000000, + kFlagSupportsVideo = 0x00000001, + kFlagSupportsAudio = 0x00000002, + kFlagCustomSignature = 0x00010000, + kFlagAll = 0xFFFFFFFF + }; + uint32 mSize; // size of this structure in bytes + uint32 mFlags; + sint32 mPriority; + uint32 mSignatureLength; + const void *mpSignature; + const wchar_t *mpFilenameDetectPattern; + const wchar_t *mpFilenamePattern; + const wchar_t *mpDriverTagName; + + VDXInputDriverCreateProc mpCreate; +}; + +enum { + // V1 (1.7.4.28204): Initial version + // V2 (1.7.5): Default I/P frame model fixed. + kVDXPlugin_InputDriverAPIVersion = 2 +}; + +#ifdef _MSC_VER + #pragma pack(pop) +#endif + +#endif diff --git a/include/vd2/plugin/vdplugin.h b/include/vd2/plugin/vdplugin.h index c909c7109ad..cec344d37f3 100644 --- a/include/vd2/plugin/vdplugin.h +++ b/include/vd2/plugin/vdplugin.h @@ -1,206 +1,206 @@ -// VirtualDub - Video processing and capture application -// Plugin headers -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_PLUGIN_VDPLUGIN_H -#define f_VD2_PLUGIN_VDPLUGIN_H - -#ifdef _MSC_VER - #pragma once - #pragma pack(push, 8) -#endif - -#include - -// Copied from . Must be in sync. -#ifndef VD_STANDARD_TYPES_DECLARED - #if defined(_MSC_VER) - typedef signed __int64 sint64; - typedef unsigned __int64 uint64; - #elif defined(__GNUC__) - typedef signed long long sint64; - typedef unsigned long long uint64; - #endif - typedef signed int sint32; - typedef unsigned int uint32; - typedef signed short sint16; - typedef unsigned short uint16; - typedef signed char sint8; - typedef unsigned char uint8; - - typedef sint64 int64; - typedef sint32 int32; - typedef sint16 int16; - typedef sint8 int8; - - typedef ptrdiff_t sintptr; - typedef size_t uintptr; -#endif - -#ifndef VDXAPIENTRY - #define VDXAPIENTRY __stdcall -#endif - -#ifndef VDXAPIENTRYV - #define VDXAPIENTRYV __cdecl -#endif - -enum VDXCPUFeatureFlags { - kVDXCPUF_CPUID = 0x00000001, - kVDXCPUF_MMX = 0x00000004, - kVDXCPUF_ISSE = 0x00000008, - kVDXCPUF_SSE = 0x00000010, - kVDXCPUF_SSE2 = 0x00000020, - kVDXCPUF_3DNOW = 0x00000040, - kVDXCPUF_3DNOW_EXT = 0x00000080, - kVDXCPUF_SSE3 = 0x00000100, - kVDXCPUF_SSSE3 = 0x00000200 -}; - -enum { - kVDXPlugin_APIVersion = 10 -}; - - -enum { - kVDXPluginType_Video, // Updated video filter API is not yet complete. - kVDXPluginType_Audio, - kVDXPluginType_Input -}; - -struct VDXPluginInfo { - uint32 mSize; // size of this structure in bytes - const wchar_t *mpName; - const wchar_t *mpAuthor; - const wchar_t *mpDescription; - uint32 mVersion; // (major<<24) + (minor<<16) + build. 1.4.1000 would be 0x010403E8. - uint32 mType; - uint32 mFlags; - uint32 mAPIVersionRequired; - uint32 mAPIVersionUsed; - uint32 mTypeAPIVersionRequired; - uint32 mTypeAPIVersionUsed; - const void * mpTypeSpecificInfo; -}; - -typedef const VDXPluginInfo *const *(VDXAPIENTRY *tpVDXGetPluginInfo)(); - -typedef VDXPluginInfo VDPluginInfo; -typedef tpVDXGetPluginInfo tpVDPluginInfo; - -class IVDXPluginCallbacks { -public: - virtual void * VDXAPIENTRY GetExtendedAPI(const char *pExtendedAPIName) = 0; - virtual void VDXAPIENTRYV SetError(const char *format, ...) = 0; - virtual void VDXAPIENTRY SetErrorOutOfMemory() = 0; - virtual uint32 VDXAPIENTRY GetCPUFeatureFlags() = 0; -}; - -typedef IVDXPluginCallbacks IVDPluginCallbacks; - -struct VDXPluginConfigEntry { - enum Type { - kTypeInvalid = 0, - kTypeU32 = 1, - kTypeS32, - kTypeU64, - kTypeS64, - kTypeDouble, - kTypeAStr, - kTypeWStr, - kTypeBlock - }; - - const VDXPluginConfigEntry *next; - - unsigned idx; - uint32 type; - const wchar_t *name; - const wchar_t *label; - const wchar_t *desc; -}; - -struct VDXPixmap { - void *data; - const uint32 *palette; - sint32 w; - sint32 h; - ptrdiff_t pitch; - sint32 format; - - // Auxiliary planes are always byte-per-pixel. - void *data2; // Cb (U) for YCbCr - ptrdiff_t pitch2; - void *data3; // Cr (V) for YCbCr - ptrdiff_t pitch3; -}; - -struct VDXPixmapLayout { - ptrdiff_t data; - const uint32 *palette; - sint32 w; - sint32 h; - ptrdiff_t pitch; - sint32 format; - - // Auxiliary planes are always byte-per-pixel. - ptrdiff_t data2; // Cb (U) for YCbCr - ptrdiff_t pitch2; - ptrdiff_t data3; // Cr (V) for YCbCr - ptrdiff_t pitch3; -}; - -namespace nsVDXPixmap { - enum VDXPixmapFormat { - kPixFormat_Null = 0, - kPixFormat_XRGB1555 = 5, - kPixFormat_RGB565 = 6, - kPixFormat_RGB888 = 7, - kPixFormat_XRGB8888 = 8, - kPixFormat_Y8 = 9, - kPixFormat_YUV422_UYVY = 10, - kPixFormat_YUV422_YUYV = 11, - kPixFormat_YUV444_Planar = 13, - kPixFormat_YUV422_Planar = 14, - kPixFormat_YUV420_Planar = 15, - kPixFormat_YUV411_Planar = 16, - kPixFormat_YUV410_Planar = 17 - }; -}; - -#define VDXMAKEFOURCC(a, b, c, d) ((uint32)(uint8)(d) + ((uint32)(uint8)(c) << 8) + ((uint32)(uint8)(b) << 16) + ((uint32)(uint8)(a) << 24)) - -class IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'u', 'n', 'k') }; - virtual int VDXAPIENTRY AddRef() = 0; - virtual int VDXAPIENTRY Release() = 0; - virtual void *VDXAPIENTRY AsInterface(uint32 iid) = 0; -}; - -#ifdef _MSC_VER - #pragma pack(pop) -#endif - -#endif +// VirtualDub - Video processing and capture application +// Plugin headers +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_PLUGIN_VDPLUGIN_H +#define f_VD2_PLUGIN_VDPLUGIN_H + +#ifdef _MSC_VER + #pragma once + #pragma pack(push, 8) +#endif + +#include + +// Copied from . Must be in sync. +#ifndef VD_STANDARD_TYPES_DECLARED + #if defined(_MSC_VER) + typedef signed __int64 sint64; + typedef unsigned __int64 uint64; + #elif defined(__GNUC__) + typedef signed long long sint64; + typedef unsigned long long uint64; + #endif + typedef signed int sint32; + typedef unsigned int uint32; + typedef signed short sint16; + typedef unsigned short uint16; + typedef signed char sint8; + typedef unsigned char uint8; + + typedef sint64 int64; + typedef sint32 int32; + typedef sint16 int16; + typedef sint8 int8; + + typedef ptrdiff_t sintptr; + typedef size_t uintptr; +#endif + +#ifndef VDXAPIENTRY + #define VDXAPIENTRY __stdcall +#endif + +#ifndef VDXAPIENTRYV + #define VDXAPIENTRYV __cdecl +#endif + +enum VDXCPUFeatureFlags { + kVDXCPUF_CPUID = 0x00000001, + kVDXCPUF_MMX = 0x00000004, + kVDXCPUF_ISSE = 0x00000008, + kVDXCPUF_SSE = 0x00000010, + kVDXCPUF_SSE2 = 0x00000020, + kVDXCPUF_3DNOW = 0x00000040, + kVDXCPUF_3DNOW_EXT = 0x00000080, + kVDXCPUF_SSE3 = 0x00000100, + kVDXCPUF_SSSE3 = 0x00000200 +}; + +enum { + kVDXPlugin_APIVersion = 10 +}; + + +enum { + kVDXPluginType_Video, // Updated video filter API is not yet complete. + kVDXPluginType_Audio, + kVDXPluginType_Input +}; + +struct VDXPluginInfo { + uint32 mSize; // size of this structure in bytes + const wchar_t *mpName; + const wchar_t *mpAuthor; + const wchar_t *mpDescription; + uint32 mVersion; // (major<<24) + (minor<<16) + build. 1.4.1000 would be 0x010403E8. + uint32 mType; + uint32 mFlags; + uint32 mAPIVersionRequired; + uint32 mAPIVersionUsed; + uint32 mTypeAPIVersionRequired; + uint32 mTypeAPIVersionUsed; + const void * mpTypeSpecificInfo; +}; + +typedef const VDXPluginInfo *const *(VDXAPIENTRY *tpVDXGetPluginInfo)(); + +typedef VDXPluginInfo VDPluginInfo; +typedef tpVDXGetPluginInfo tpVDPluginInfo; + +class IVDXPluginCallbacks { +public: + virtual void * VDXAPIENTRY GetExtendedAPI(const char *pExtendedAPIName) = 0; + virtual void VDXAPIENTRYV SetError(const char *format, ...) = 0; + virtual void VDXAPIENTRY SetErrorOutOfMemory() = 0; + virtual uint32 VDXAPIENTRY GetCPUFeatureFlags() = 0; +}; + +typedef IVDXPluginCallbacks IVDPluginCallbacks; + +struct VDXPluginConfigEntry { + enum Type { + kTypeInvalid = 0, + kTypeU32 = 1, + kTypeS32, + kTypeU64, + kTypeS64, + kTypeDouble, + kTypeAStr, + kTypeWStr, + kTypeBlock + }; + + const VDXPluginConfigEntry *next; + + unsigned idx; + uint32 type; + const wchar_t *name; + const wchar_t *label; + const wchar_t *desc; +}; + +struct VDXPixmap { + void *data; + const uint32 *palette; + sint32 w; + sint32 h; + ptrdiff_t pitch; + sint32 format; + + // Auxiliary planes are always byte-per-pixel. + void *data2; // Cb (U) for YCbCr + ptrdiff_t pitch2; + void *data3; // Cr (V) for YCbCr + ptrdiff_t pitch3; +}; + +struct VDXPixmapLayout { + ptrdiff_t data; + const uint32 *palette; + sint32 w; + sint32 h; + ptrdiff_t pitch; + sint32 format; + + // Auxiliary planes are always byte-per-pixel. + ptrdiff_t data2; // Cb (U) for YCbCr + ptrdiff_t pitch2; + ptrdiff_t data3; // Cr (V) for YCbCr + ptrdiff_t pitch3; +}; + +namespace nsVDXPixmap { + enum VDXPixmapFormat { + kPixFormat_Null = 0, + kPixFormat_XRGB1555 = 5, + kPixFormat_RGB565 = 6, + kPixFormat_RGB888 = 7, + kPixFormat_XRGB8888 = 8, + kPixFormat_Y8 = 9, + kPixFormat_YUV422_UYVY = 10, + kPixFormat_YUV422_YUYV = 11, + kPixFormat_YUV444_Planar = 13, + kPixFormat_YUV422_Planar = 14, + kPixFormat_YUV420_Planar = 15, + kPixFormat_YUV411_Planar = 16, + kPixFormat_YUV410_Planar = 17 + }; +}; + +#define VDXMAKEFOURCC(a, b, c, d) ((uint32)(uint8)(d) + ((uint32)(uint8)(c) << 8) + ((uint32)(uint8)(b) << 16) + ((uint32)(uint8)(a) << 24)) + +class IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'u', 'n', 'k') }; + virtual int VDXAPIENTRY AddRef() = 0; + virtual int VDXAPIENTRY Release() = 0; + virtual void *VDXAPIENTRY AsInterface(uint32 iid) = 0; +}; + +#ifdef _MSC_VER + #pragma pack(pop) +#endif + +#endif diff --git a/include/vd2/plugin/vdvideofilt.h b/include/vd2/plugin/vdvideofilt.h index 1e00fac39e3..cf331b7012c 100644 --- a/include/vd2/plugin/vdvideofilt.h +++ b/include/vd2/plugin/vdvideofilt.h @@ -1,517 +1,517 @@ -// VirtualDub - Video processing and capture application -// Plugin headers -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// The plugin headers in the VirtualDub plugin SDK are licensed differently -// differently than VirtualDub and the Plugin SDK themselves. This -// particular file is thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_PLUGIN_VDVIDEOFILT_H -#define f_VD2_PLUGIN_VDVIDEOFILT_H - -#ifdef _MSC_VER - #pragma once - #pragma pack(push, 8) -#endif - -#include - -#include "vdplugin.h" - -typedef struct VDXHINSTANCEStruct *VDXHINSTANCE; -typedef struct VDXHDCStruct *VDXHDC; -typedef struct VDXHWNDStruct *VDXHWND; - -////////////////// - -struct VDXScriptObject; -struct VDXFilterVTbls; - -////////////////// - -enum { - /// Request distinct source and destination buffers. Otherwise, the source and destination buffers - /// alias (in-place mode). - FILTERPARAM_SWAP_BUFFERS = 0x00000001L, - - /// Request an extra buffer for the previous source frame. - FILTERPARAM_NEEDS_LAST = 0x00000002L, - - /// Filter supports image formats other than RGB32. Filters that support format negotiation must - /// set this flag for all calls to paramProc. - FILTERPARAM_SUPPORTS_ALTFORMATS = 0x00000004L, - - /// Filter requests 16 byte alignment for source and destination buffers. This guarantees that: - /// - /// - data and pitch fields are multiples of 16 bytes (aligned) - /// - an integral number of 16 byte vectors may be read, even if the last vector includes - /// some bytes beyond the end of the scanline (their values are undefined) - /// - an integral number of 16 byte vectors may be written, even if the last vector includes - /// some bytes beyong the end of the scanline (their values are ignored) - /// - FILTERPARAM_ALIGN_SCANLINES = 0x00000008L, - - /// Filter's output is purely a function of configuration parameters and source image data, and not - /// source or output frame numbers. In other words, two output frames produced by a filter instance - /// can be assumed to be identical images if: - /// - /// - the same number of source frames are prefetched - /// - the same type of prefetches are performed (direct vs. non-direct) - /// - the frame numbers for the two prefetch lists, taken in order, correspond to identical - /// source frames - /// - the prefetch cookies match - /// - /// Enabling this flag improves the ability of the host to identify identical frames and drop them - /// in preview or in the output file. - /// - FILTERPARAM_PURE_TRANSFORM = 0x00000010L, - - /// Filter cannot support the requested source format. Note that this sets all bits, so the meaning - /// of other bits is ignored. The one exception is that FILTERPARAM_SUPPORTS_ALTFORMATS is assumed - /// to be implicitly set. - FILTERPARAM_NOT_SUPPORTED = (long)0xFFFFFFFF -}; - -/// The filter has a delay from source to output. For instance, a lag of 3 indicates that the -/// filter internally buffers three frames, so when it is fed frames in sequence, frame 0 emerges -/// after frame 3 has been processed. The host attempts to correct timestamps in order to compensate. -/// -/// VirtualDub 1.9.1 or later: Setting this flag can have a performance penalty, as it causes the host -/// to request additional frames to try to produce the correct requested output frames. -/// -#define FILTERPARAM_HAS_LAG(frames) ((int)(frames) << 16) - -/////////////////// - -class VDXFBitmap; -class VDXFilterActivation; -struct VDXFilterFunctions; -struct VDXFilterModule; -class IVDXVideoPrefetcher; - -enum { - kVDXVFEvent_None = 0, - kVDXVFEvent_InvalidateCaches = 1 -}; - -typedef int (__cdecl *VDXFilterInitProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef void (__cdecl *VDXFilterDeinitProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef int (__cdecl *VDXFilterRunProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef long (__cdecl *VDXFilterParamProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef int (__cdecl *VDXFilterConfigProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hWnd); -typedef void (__cdecl *VDXFilterStringProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf); -typedef int (__cdecl *VDXFilterStartProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef int (__cdecl *VDXFilterEndProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); -typedef bool (__cdecl *VDXFilterScriptStrProc)(VDXFilterActivation *fa, const VDXFilterFunctions *, char *, int); -typedef void (__cdecl *VDXFilterStringProc2 )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen); -typedef int (__cdecl *VDXFilterSerialize )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxbuf); -typedef void (__cdecl *VDXFilterDeserialize )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, const char *buf, int maxbuf); -typedef void (__cdecl *VDXFilterCopy )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst); -typedef sint64 (__cdecl *VDXFilterPrefetch )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame); -typedef void (__cdecl *VDXFilterCopy2Proc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst, VDXFilterActivation *fa2, const VDXFilterFunctions *ff2); -typedef bool (__cdecl *VDXFilterPrefetch2Proc)(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame, IVDXVideoPrefetcher *prefetcher); -typedef bool (__cdecl *VDXFilterEventProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, uint32 event, const void *eventData); - -typedef int (__cdecl *VDXFilterModuleInitProc)(VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat); -typedef void (__cdecl *VDXFilterModuleDeinitProc)(VDXFilterModule *fm, const VDXFilterFunctions *ff); - -////////// - -typedef void (__cdecl *VDXFilterPreviewButtonCallback)(bool fNewState, void *pData); -typedef void (__cdecl *VDXFilterPreviewSampleCallback)(VDXFBitmap *, long lFrame, long lCount, void *pData); - -class IVDXFilterPreview { -public: - virtual void SetButtonCallback(VDXFilterPreviewButtonCallback, void *)=0; - virtual void SetSampleCallback(VDXFilterPreviewSampleCallback, void *)=0; - - virtual bool isPreviewEnabled()=0; - virtual void Toggle(VDXHWND)=0; - virtual void Display(VDXHWND, bool)=0; - virtual void RedoFrame()=0; - virtual void RedoSystem()=0; - virtual void UndoSystem()=0; - virtual void InitButton(VDXHWND)=0; - virtual void Close()=0; - virtual bool SampleCurrentFrame()=0; - virtual long SampleFrames()=0; -}; - -class IVDXFilterPreview2 : public IVDXFilterPreview { -public: - virtual bool IsPreviewDisplayed() = 0; -}; - -class IVDXVideoPrefetcher : public IVDXUnknown { -public: - enum { kIID = VDXMAKEFOURCC('X', 'v', 'p', 'f') }; - - /// Request a video frame fetch from an upstream source. - virtual void VDXAPIENTRY PrefetchFrame(sint32 srcIndex, sint64 frame, uint64 cookie) = 0; - - /// Request a video frame fetch from an upstream source in direct mode. - /// This specifies that the output frame is the same as the input frame. - /// There cannot be more than one direct fetch and there must be no standard - /// fetches at the same time. There can, however, be symbolic fetches. - virtual void VDXAPIENTRY PrefetchFrameDirect(sint32 srcIndex, sint64 frame) = 0; - - /// Request a symbolic fetch from a source. This does not actually fetch - /// any frames, but marks an association from source to output. This is - /// useful for indicating the approximate center of where an output derives - /// in a source, even if those frames aren't fetched (perhaps due to caching). - /// There may be either zero or one symbolic fetch per source. - /// - /// If no symbolic fetches are performed, the symbolic frame is assumed to - /// be the rounded mean of the fetched source frames. - virtual void VDXAPIENTRY PrefetchFrameSymbolic(sint32 srcIndex, sint64 frame) = 0; -}; - -////////// - -enum { - // This is the highest API version supported by this header file. - VIRTUALDUB_FILTERDEF_VERSION = 14, - - // This is the absolute lowest API version supported by this header file. - // Note that V4 is rather old, corresponding to VirtualDub 1.2. - // Chances are you will need to declare a higher version. - VIRTUALDUB_FILTERDEF_COMPATIBLE = 4, - - // API V9 is a slightly saner baseline, since it is the first API - // version that has copy constructor support. You may still need to - // declare a higher vdfd_compat version in your module init if you - // need features beyond V9 (VirtualDub 1.4.12). - VIRTUALDUB_FILTERDEF_COMPATIBLE_COPYCTOR = 9 - -}; - -// v3: added lCurrentSourceFrame to FrameStateInfo -// v4 (1.2): lots of additions (VirtualDub 1.2) -// v5 (1.3d): lots of bugfixes - stretchblt bilinear, and non-zero startproc -// v6 (1.4): added error handling functions -// v7 (1.4d): added frame lag, exception handling -// v8 (1.4.11): added string2 proc -// v9 (1.4.12): added (working) copy constructor -// v10 (1.5.10): added preview flag -// v11 (1.7.0): guaranteed src structure setup before configProc; added IVDFilterPreview2 -// v12 (1.8.0): support for frame alteration -// v13 (1.8.2): added mOutputFrame field to VDXFilterStateInfo -// v14 (1.9.1): added copyProc2, prefetchProc2, input/output frame arrays - -struct VDXFilterDefinition { - void *_next; // deprecated - set to NULL - void *_prev; // deprecated - set to NULL - void *_module; // deprecated - set to NULL - - const char * name; - const char * desc; - const char * maker; - void * private_data; - int inst_data_size; - - VDXFilterInitProc initProc; - VDXFilterDeinitProc deinitProc; - VDXFilterRunProc runProc; - VDXFilterParamProc paramProc; - VDXFilterConfigProc configProc; - VDXFilterStringProc stringProc; - VDXFilterStartProc startProc; - VDXFilterEndProc endProc; - - VDXScriptObject *script_obj; - - VDXFilterScriptStrProc fssProc; - - // NEW - 1.4.11 - VDXFilterStringProc2 stringProc2; - VDXFilterSerialize serializeProc; - VDXFilterDeserialize deserializeProc; - VDXFilterCopy copyProc; - - VDXFilterPrefetch prefetchProc; // (V12/V1.7.4+) - - // NEW - V14 / 1.9.1 - VDXFilterCopy2Proc copyProc2; - VDXFilterPrefetch2Proc prefetchProc2; - VDXFilterEventProc eventProc; -}; - -////////// - -// FilterStateInfo: contains dynamic info about file being processed - -class VDXFilterStateInfo { -public: - sint32 lCurrentFrame; // current sequence frame (previously called output frame) - sint32 lMicrosecsPerFrame; // microseconds per sequence frame - sint32 lCurrentSourceFrame; // current source frame - sint32 lMicrosecsPerSrcFrame; // microseconds per source frame - sint32 lSourceFrameMS; // source frame timestamp - sint32 lDestFrameMS; // output frame timestamp - - enum { - kStateNone = 0x00000000, - kStatePreview = 0x00000001, // (V1.5.10+) Job output is not being saved to disk. - kStateRealTime = 0x00000002, // (V1.5.10+) Operation is running in real-time (capture, playback). - kStateMax = 0xFFFFFFFF - }; - - uint32 flags; // (V10 / 1.5.10+ only) - - sint32 mOutputFrame; // (V13/V1.8.2+) current output frame -}; - -// VDXFBitmap: VBitmap extended to hold filter-specific information - -class VDXBitmap { -public: - void * _vtable; // Reserved - do not use. - uint32 * data; // Pointer to start of _bottom-most_ scanline of plane 0. - uint32 * palette; // Pointer to palette (reserved - set to NULL). - sint32 depth; // Bit depth, in bits. Set to zero if mpPixmap/mpPixmapLayout are active. - sint32 w; // Width of bitmap, in pixels. - sint32 h; // Height of bitmap, in pixels. - ptrdiff_t pitch; // Distance, in bytes, from the start of one scanline in plane 0 to the next. - ptrdiff_t modulo; // Distance, in bytes, from the end of one scanline in plane 0 to the start of the next. - ptrdiff_t size; // Size of plane 0, including padding. - ptrdiff_t offset; // Offset from beginning of buffer to beginning of plane 0. - - uint32 *Address32(int x, int y) const { - return Address32i(x, h-y-1); - } - - uint32 *Address32i(int x, int y) const { - return (uint32 *)((char *)data + y*pitch + x*4); - } - - void AlignTo4() { - pitch = w << 2; - } - - void AlignTo8() { - pitch = ((w+1)&~1) << 2; - } -}; - -class VDXFBitmap : public VDXBitmap { -public: - enum { - /// Set in paramProc if the filter requires a Win32 GDI display context - /// for a bitmap. (Deprecated as of API V12 - do not use) - NEEDS_HDC = 0x00000001L, - }; - - uint32 dwFlags; - VDXHDC hdc; - - uint32 mFrameRateHi; // Frame rate numerator (V1.7.4+) - uint32 mFrameRateLo; // Frame rate denominator (V1.7.4+) - sint64 mFrameCount; // Frame count; -1 if unlimited or indeterminate (V1.7.4+) - - VDXPixmapLayout *mpPixmapLayout; - const VDXPixmap *mpPixmap; - - uint32 mAspectRatioHi; ///< Pixel aspect ratio fraction (numerator). 0/0 = unknown - uint32 mAspectRatioLo; ///< Pixel aspect ratio fraction (denominator). - - sint64 mFrameNumber; ///< Current frame number (zero based). - sint64 mFrameTimestampStart; ///< Starting timestamp of frame, in 100ns units. - sint64 mFrameTimestampEnd; ///< Ending timestamp of frame, in 100ns units. - sint64 mCookie; ///< Cookie supplied when frame was requested. -}; - -// VDXFilterActivation: This is what is actually passed to filters at runtime. - -class VDXFilterActivation { -public: - const VDXFilterDefinition *filter; // - void *filter_data; - VDXFBitmap& dst; - VDXFBitmap& src; - VDXFBitmap *_reserved0; - VDXFBitmap *const last; - uint32 x1; - uint32 y1; - uint32 x2; - uint32 y2; - - VDXFilterStateInfo *pfsi; - IVDXFilterPreview *ifp; - IVDXFilterPreview2 *ifp2; // (V11+) - - uint32 mSourceFrameCount; // (V14+) - VDXFBitmap *const *mpSourceFrames; // (V14+) - VDXFBitmap *const *mpOutputFrames; // (V14+) -}; - -// These flags must match those in cpuaccel.h! - -#ifndef f_VIRTUALDUB_CPUACCEL_H -#define CPUF_SUPPORTS_CPUID (0x00000001L) -#define CPUF_SUPPORTS_FPU (0x00000002L) -#define CPUF_SUPPORTS_MMX (0x00000004L) -#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) -#define CPUF_SUPPORTS_SSE (0x00000010L) -#define CPUF_SUPPORTS_SSE2 (0x00000020L) -#define CPUF_SUPPORTS_3DNOW (0x00000040L) -#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) -#endif - -struct VDXFilterFunctions { - VDXFilterDefinition *(__cdecl *addFilter)(VDXFilterModule *, VDXFilterDefinition *, int fd_len); - void (__cdecl *removeFilter)(VDXFilterDefinition *); - bool (__cdecl *isFPUEnabled)(); - bool (__cdecl *isMMXEnabled)(); - void (__cdecl *InitVTables)(VDXFilterVTbls *); - - // These functions permit you to throw MyError exceptions from a filter. - // YOU MUST ONLY CALL THESE IN runProc, initProc, and startProc. - - void (__cdecl *ExceptOutOfMemory)(); // ADDED: V6 (VirtualDub 1.4) - void (__cdecl *Except)(const char *format, ...); // ADDED: V6 (VirtualDub 1.4) - - // These functions are callable at any time. - - long (__cdecl *getCPUFlags)(); // ADDED: V6 (VirtualDub 1.4) - long (__cdecl *getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d) -}; - - - - - -/////////////////////////////////////////////////////////////////////////// - -class VDXScriptValue; -class VDXScriptError; -struct VDXScriptObject; - -class VDXScriptError { -public: - enum { - PARSE_ERROR=1, - SEMICOLON_EXPECTED, - IDENTIFIER_EXPECTED, - - TYPE_INT_REQUIRED, - TYPE_ARRAY_REQUIRED, - TYPE_FUNCTION_REQUIRED, - TYPE_OBJECT_REQUIRED, - - OBJECT_MEMBER_NAME_REQUIRED, - FUNCCALLEND_EXPECTED, - TOO_MANY_PARAMS, - DIVIDE_BY_ZERO, - VAR_NOT_FOUND, - MEMBER_NOT_FOUND, - OVERLOADED_FUNCTION_NOT_FOUND, - IDENT_TOO_LONG, - OPERATOR_EXPECTED, - CLOSEPARENS_EXPECTED, - CLOSEBRACKET_EXPECTED, - - VAR_UNDEFINED, - - OUT_OF_STRING_SPACE, - OUT_OF_MEMORY, - INTERNAL_ERROR, - EXTERNAL_ERROR, - - FCALL_OUT_OF_RANGE, - FCALL_INVALID_PTYPE, - FCALL_UNKNOWN_STR, - - ARRAY_INDEX_OUT_OF_BOUNDS, - - NUMERIC_OVERFLOW, - STRING_NOT_AN_INTEGER_VALUE, - STRING_NOT_A_REAL_VALUE, - - ASSERTION_FAILED, - AMBIGUOUS_CALL, - CANNOT_CAST - }; -}; - -class IVDXScriptInterpreter { -public: - virtual void _placeholder1() {} - virtual void _placeholder2(void *, void *) {} - virtual void _placeholder3(char *s) {} - - virtual void ScriptError(int e)=0; - virtual void _placeholder4(VDXScriptError& cse) {} - virtual char** AllocTempString(long l)=0; - - virtual void _placeholder5() {} -}; - -#define EXT_SCRIPT_ERROR(x) (isi->ScriptError((VDXScriptError::x))) - -typedef VDXScriptValue (*VDXScriptFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); -typedef void (*VDXScriptVoidFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); -typedef int (*VDXScriptIntFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); - -struct VDXScriptFunctionDef { - VDXScriptFunctionPtr func_ptr; - const char *name; - const char *arg_list; -}; - -struct VDXScriptObject { - void *_lookup; // reserved - set to NULL - VDXScriptFunctionDef *func_list; - void *_obj_list; // reserved - set to NULL -}; - -class VDXScriptValue { -public: - enum { T_VOID, T_INT, T_PINT, T_STR, T_ARRAY, T_OBJECT, T_FNAME, T_FUNCTION, T_VARLV, T_LONG, T_DOUBLE } type; - VDXScriptObject *thisPtr; - union { - int i; - char **s; - sint64 l; - double d; - } u; - - VDXScriptValue() { type = T_VOID; } - VDXScriptValue(int i) { type = T_INT; u.i = i; } - VDXScriptValue(sint64 l) { type = T_LONG; u.l = l; } - VDXScriptValue(double d) { type = T_DOUBLE; u.d = d; } - VDXScriptValue(char **s) { type = T_STR; u.s = s; } - - bool isVoid() const { return type == T_VOID; } - bool isInt() const { return type == T_INT; } - bool isString() const { return type == T_STR; } - bool isLong() const { return type == T_LONG; } - bool isDouble() const { return type == T_DOUBLE; } - - int asInt() const { return u.i; } - sint64 asLong() const { return u.l; } - double asDouble() const { return u.d; } - char ** asString() const { return u.s; } -}; - -#ifdef _MSC_VER - #pragma pack(pop) -#endif - -#endif +// VirtualDub - Video processing and capture application +// Plugin headers +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// The plugin headers in the VirtualDub plugin SDK are licensed differently +// differently than VirtualDub and the Plugin SDK themselves. This +// particular file is thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_PLUGIN_VDVIDEOFILT_H +#define f_VD2_PLUGIN_VDVIDEOFILT_H + +#ifdef _MSC_VER + #pragma once + #pragma pack(push, 8) +#endif + +#include + +#include "vdplugin.h" + +typedef struct VDXHINSTANCEStruct *VDXHINSTANCE; +typedef struct VDXHDCStruct *VDXHDC; +typedef struct VDXHWNDStruct *VDXHWND; + +////////////////// + +struct VDXScriptObject; +struct VDXFilterVTbls; + +////////////////// + +enum { + /// Request distinct source and destination buffers. Otherwise, the source and destination buffers + /// alias (in-place mode). + FILTERPARAM_SWAP_BUFFERS = 0x00000001L, + + /// Request an extra buffer for the previous source frame. + FILTERPARAM_NEEDS_LAST = 0x00000002L, + + /// Filter supports image formats other than RGB32. Filters that support format negotiation must + /// set this flag for all calls to paramProc. + FILTERPARAM_SUPPORTS_ALTFORMATS = 0x00000004L, + + /// Filter requests 16 byte alignment for source and destination buffers. This guarantees that: + /// + /// - data and pitch fields are multiples of 16 bytes (aligned) + /// - an integral number of 16 byte vectors may be read, even if the last vector includes + /// some bytes beyond the end of the scanline (their values are undefined) + /// - an integral number of 16 byte vectors may be written, even if the last vector includes + /// some bytes beyong the end of the scanline (their values are ignored) + /// + FILTERPARAM_ALIGN_SCANLINES = 0x00000008L, + + /// Filter's output is purely a function of configuration parameters and source image data, and not + /// source or output frame numbers. In other words, two output frames produced by a filter instance + /// can be assumed to be identical images if: + /// + /// - the same number of source frames are prefetched + /// - the same type of prefetches are performed (direct vs. non-direct) + /// - the frame numbers for the two prefetch lists, taken in order, correspond to identical + /// source frames + /// - the prefetch cookies match + /// + /// Enabling this flag improves the ability of the host to identify identical frames and drop them + /// in preview or in the output file. + /// + FILTERPARAM_PURE_TRANSFORM = 0x00000010L, + + /// Filter cannot support the requested source format. Note that this sets all bits, so the meaning + /// of other bits is ignored. The one exception is that FILTERPARAM_SUPPORTS_ALTFORMATS is assumed + /// to be implicitly set. + FILTERPARAM_NOT_SUPPORTED = (long)0xFFFFFFFF +}; + +/// The filter has a delay from source to output. For instance, a lag of 3 indicates that the +/// filter internally buffers three frames, so when it is fed frames in sequence, frame 0 emerges +/// after frame 3 has been processed. The host attempts to correct timestamps in order to compensate. +/// +/// VirtualDub 1.9.1 or later: Setting this flag can have a performance penalty, as it causes the host +/// to request additional frames to try to produce the correct requested output frames. +/// +#define FILTERPARAM_HAS_LAG(frames) ((int)(frames) << 16) + +/////////////////// + +class VDXFBitmap; +class VDXFilterActivation; +struct VDXFilterFunctions; +struct VDXFilterModule; +class IVDXVideoPrefetcher; + +enum { + kVDXVFEvent_None = 0, + kVDXVFEvent_InvalidateCaches = 1 +}; + +typedef int (__cdecl *VDXFilterInitProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef void (__cdecl *VDXFilterDeinitProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef int (__cdecl *VDXFilterRunProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef long (__cdecl *VDXFilterParamProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef int (__cdecl *VDXFilterConfigProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, VDXHWND hWnd); +typedef void (__cdecl *VDXFilterStringProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf); +typedef int (__cdecl *VDXFilterStartProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef int (__cdecl *VDXFilterEndProc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff); +typedef bool (__cdecl *VDXFilterScriptStrProc)(VDXFilterActivation *fa, const VDXFilterFunctions *, char *, int); +typedef void (__cdecl *VDXFilterStringProc2 )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxlen); +typedef int (__cdecl *VDXFilterSerialize )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, char *buf, int maxbuf); +typedef void (__cdecl *VDXFilterDeserialize )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, const char *buf, int maxbuf); +typedef void (__cdecl *VDXFilterCopy )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst); +typedef sint64 (__cdecl *VDXFilterPrefetch )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame); +typedef void (__cdecl *VDXFilterCopy2Proc )(VDXFilterActivation *fa, const VDXFilterFunctions *ff, void *dst, VDXFilterActivation *fa2, const VDXFilterFunctions *ff2); +typedef bool (__cdecl *VDXFilterPrefetch2Proc)(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, sint64 frame, IVDXVideoPrefetcher *prefetcher); +typedef bool (__cdecl *VDXFilterEventProc )(const VDXFilterActivation *fa, const VDXFilterFunctions *ff, uint32 event, const void *eventData); + +typedef int (__cdecl *VDXFilterModuleInitProc)(VDXFilterModule *fm, const VDXFilterFunctions *ff, int& vdfd_ver, int& vdfd_compat); +typedef void (__cdecl *VDXFilterModuleDeinitProc)(VDXFilterModule *fm, const VDXFilterFunctions *ff); + +////////// + +typedef void (__cdecl *VDXFilterPreviewButtonCallback)(bool fNewState, void *pData); +typedef void (__cdecl *VDXFilterPreviewSampleCallback)(VDXFBitmap *, long lFrame, long lCount, void *pData); + +class IVDXFilterPreview { +public: + virtual void SetButtonCallback(VDXFilterPreviewButtonCallback, void *)=0; + virtual void SetSampleCallback(VDXFilterPreviewSampleCallback, void *)=0; + + virtual bool isPreviewEnabled()=0; + virtual void Toggle(VDXHWND)=0; + virtual void Display(VDXHWND, bool)=0; + virtual void RedoFrame()=0; + virtual void RedoSystem()=0; + virtual void UndoSystem()=0; + virtual void InitButton(VDXHWND)=0; + virtual void Close()=0; + virtual bool SampleCurrentFrame()=0; + virtual long SampleFrames()=0; +}; + +class IVDXFilterPreview2 : public IVDXFilterPreview { +public: + virtual bool IsPreviewDisplayed() = 0; +}; + +class IVDXVideoPrefetcher : public IVDXUnknown { +public: + enum { kIID = VDXMAKEFOURCC('X', 'v', 'p', 'f') }; + + /// Request a video frame fetch from an upstream source. + virtual void VDXAPIENTRY PrefetchFrame(sint32 srcIndex, sint64 frame, uint64 cookie) = 0; + + /// Request a video frame fetch from an upstream source in direct mode. + /// This specifies that the output frame is the same as the input frame. + /// There cannot be more than one direct fetch and there must be no standard + /// fetches at the same time. There can, however, be symbolic fetches. + virtual void VDXAPIENTRY PrefetchFrameDirect(sint32 srcIndex, sint64 frame) = 0; + + /// Request a symbolic fetch from a source. This does not actually fetch + /// any frames, but marks an association from source to output. This is + /// useful for indicating the approximate center of where an output derives + /// in a source, even if those frames aren't fetched (perhaps due to caching). + /// There may be either zero or one symbolic fetch per source. + /// + /// If no symbolic fetches are performed, the symbolic frame is assumed to + /// be the rounded mean of the fetched source frames. + virtual void VDXAPIENTRY PrefetchFrameSymbolic(sint32 srcIndex, sint64 frame) = 0; +}; + +////////// + +enum { + // This is the highest API version supported by this header file. + VIRTUALDUB_FILTERDEF_VERSION = 14, + + // This is the absolute lowest API version supported by this header file. + // Note that V4 is rather old, corresponding to VirtualDub 1.2. + // Chances are you will need to declare a higher version. + VIRTUALDUB_FILTERDEF_COMPATIBLE = 4, + + // API V9 is a slightly saner baseline, since it is the first API + // version that has copy constructor support. You may still need to + // declare a higher vdfd_compat version in your module init if you + // need features beyond V9 (VirtualDub 1.4.12). + VIRTUALDUB_FILTERDEF_COMPATIBLE_COPYCTOR = 9 + +}; + +// v3: added lCurrentSourceFrame to FrameStateInfo +// v4 (1.2): lots of additions (VirtualDub 1.2) +// v5 (1.3d): lots of bugfixes - stretchblt bilinear, and non-zero startproc +// v6 (1.4): added error handling functions +// v7 (1.4d): added frame lag, exception handling +// v8 (1.4.11): added string2 proc +// v9 (1.4.12): added (working) copy constructor +// v10 (1.5.10): added preview flag +// v11 (1.7.0): guaranteed src structure setup before configProc; added IVDFilterPreview2 +// v12 (1.8.0): support for frame alteration +// v13 (1.8.2): added mOutputFrame field to VDXFilterStateInfo +// v14 (1.9.1): added copyProc2, prefetchProc2, input/output frame arrays + +struct VDXFilterDefinition { + void *_next; // deprecated - set to NULL + void *_prev; // deprecated - set to NULL + void *_module; // deprecated - set to NULL + + const char * name; + const char * desc; + const char * maker; + void * private_data; + int inst_data_size; + + VDXFilterInitProc initProc; + VDXFilterDeinitProc deinitProc; + VDXFilterRunProc runProc; + VDXFilterParamProc paramProc; + VDXFilterConfigProc configProc; + VDXFilterStringProc stringProc; + VDXFilterStartProc startProc; + VDXFilterEndProc endProc; + + VDXScriptObject *script_obj; + + VDXFilterScriptStrProc fssProc; + + // NEW - 1.4.11 + VDXFilterStringProc2 stringProc2; + VDXFilterSerialize serializeProc; + VDXFilterDeserialize deserializeProc; + VDXFilterCopy copyProc; + + VDXFilterPrefetch prefetchProc; // (V12/V1.7.4+) + + // NEW - V14 / 1.9.1 + VDXFilterCopy2Proc copyProc2; + VDXFilterPrefetch2Proc prefetchProc2; + VDXFilterEventProc eventProc; +}; + +////////// + +// FilterStateInfo: contains dynamic info about file being processed + +class VDXFilterStateInfo { +public: + sint32 lCurrentFrame; // current sequence frame (previously called output frame) + sint32 lMicrosecsPerFrame; // microseconds per sequence frame + sint32 lCurrentSourceFrame; // current source frame + sint32 lMicrosecsPerSrcFrame; // microseconds per source frame + sint32 lSourceFrameMS; // source frame timestamp + sint32 lDestFrameMS; // output frame timestamp + + enum { + kStateNone = 0x00000000, + kStatePreview = 0x00000001, // (V1.5.10+) Job output is not being saved to disk. + kStateRealTime = 0x00000002, // (V1.5.10+) Operation is running in real-time (capture, playback). + kStateMax = 0xFFFFFFFF + }; + + uint32 flags; // (V10 / 1.5.10+ only) + + sint32 mOutputFrame; // (V13/V1.8.2+) current output frame +}; + +// VDXFBitmap: VBitmap extended to hold filter-specific information + +class VDXBitmap { +public: + void * _vtable; // Reserved - do not use. + uint32 * data; // Pointer to start of _bottom-most_ scanline of plane 0. + uint32 * palette; // Pointer to palette (reserved - set to NULL). + sint32 depth; // Bit depth, in bits. Set to zero if mpPixmap/mpPixmapLayout are active. + sint32 w; // Width of bitmap, in pixels. + sint32 h; // Height of bitmap, in pixels. + ptrdiff_t pitch; // Distance, in bytes, from the start of one scanline in plane 0 to the next. + ptrdiff_t modulo; // Distance, in bytes, from the end of one scanline in plane 0 to the start of the next. + ptrdiff_t size; // Size of plane 0, including padding. + ptrdiff_t offset; // Offset from beginning of buffer to beginning of plane 0. + + uint32 *Address32(int x, int y) const { + return Address32i(x, h-y-1); + } + + uint32 *Address32i(int x, int y) const { + return (uint32 *)((char *)data + y*pitch + x*4); + } + + void AlignTo4() { + pitch = w << 2; + } + + void AlignTo8() { + pitch = ((w+1)&~1) << 2; + } +}; + +class VDXFBitmap : public VDXBitmap { +public: + enum { + /// Set in paramProc if the filter requires a Win32 GDI display context + /// for a bitmap. (Deprecated as of API V12 - do not use) + NEEDS_HDC = 0x00000001L, + }; + + uint32 dwFlags; + VDXHDC hdc; + + uint32 mFrameRateHi; // Frame rate numerator (V1.7.4+) + uint32 mFrameRateLo; // Frame rate denominator (V1.7.4+) + sint64 mFrameCount; // Frame count; -1 if unlimited or indeterminate (V1.7.4+) + + VDXPixmapLayout *mpPixmapLayout; + const VDXPixmap *mpPixmap; + + uint32 mAspectRatioHi; ///< Pixel aspect ratio fraction (numerator). 0/0 = unknown + uint32 mAspectRatioLo; ///< Pixel aspect ratio fraction (denominator). + + sint64 mFrameNumber; ///< Current frame number (zero based). + sint64 mFrameTimestampStart; ///< Starting timestamp of frame, in 100ns units. + sint64 mFrameTimestampEnd; ///< Ending timestamp of frame, in 100ns units. + sint64 mCookie; ///< Cookie supplied when frame was requested. +}; + +// VDXFilterActivation: This is what is actually passed to filters at runtime. + +class VDXFilterActivation { +public: + const VDXFilterDefinition *filter; // + void *filter_data; + VDXFBitmap& dst; + VDXFBitmap& src; + VDXFBitmap *_reserved0; + VDXFBitmap *const last; + uint32 x1; + uint32 y1; + uint32 x2; + uint32 y2; + + VDXFilterStateInfo *pfsi; + IVDXFilterPreview *ifp; + IVDXFilterPreview2 *ifp2; // (V11+) + + uint32 mSourceFrameCount; // (V14+) + VDXFBitmap *const *mpSourceFrames; // (V14+) + VDXFBitmap *const *mpOutputFrames; // (V14+) +}; + +// These flags must match those in cpuaccel.h! + +#ifndef f_VIRTUALDUB_CPUACCEL_H +#define CPUF_SUPPORTS_CPUID (0x00000001L) +#define CPUF_SUPPORTS_FPU (0x00000002L) +#define CPUF_SUPPORTS_MMX (0x00000004L) +#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) +#define CPUF_SUPPORTS_SSE (0x00000010L) +#define CPUF_SUPPORTS_SSE2 (0x00000020L) +#define CPUF_SUPPORTS_3DNOW (0x00000040L) +#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) +#endif + +struct VDXFilterFunctions { + VDXFilterDefinition *(__cdecl *addFilter)(VDXFilterModule *, VDXFilterDefinition *, int fd_len); + void (__cdecl *removeFilter)(VDXFilterDefinition *); + bool (__cdecl *isFPUEnabled)(); + bool (__cdecl *isMMXEnabled)(); + void (__cdecl *InitVTables)(VDXFilterVTbls *); + + // These functions permit you to throw MyError exceptions from a filter. + // YOU MUST ONLY CALL THESE IN runProc, initProc, and startProc. + + void (__cdecl *ExceptOutOfMemory)(); // ADDED: V6 (VirtualDub 1.4) + void (__cdecl *Except)(const char *format, ...); // ADDED: V6 (VirtualDub 1.4) + + // These functions are callable at any time. + + long (__cdecl *getCPUFlags)(); // ADDED: V6 (VirtualDub 1.4) + long (__cdecl *getHostVersionInfo)(char *buffer, int len); // ADDED: V7 (VirtualDub 1.4d) +}; + + + + + +/////////////////////////////////////////////////////////////////////////// + +class VDXScriptValue; +class VDXScriptError; +struct VDXScriptObject; + +class VDXScriptError { +public: + enum { + PARSE_ERROR=1, + SEMICOLON_EXPECTED, + IDENTIFIER_EXPECTED, + + TYPE_INT_REQUIRED, + TYPE_ARRAY_REQUIRED, + TYPE_FUNCTION_REQUIRED, + TYPE_OBJECT_REQUIRED, + + OBJECT_MEMBER_NAME_REQUIRED, + FUNCCALLEND_EXPECTED, + TOO_MANY_PARAMS, + DIVIDE_BY_ZERO, + VAR_NOT_FOUND, + MEMBER_NOT_FOUND, + OVERLOADED_FUNCTION_NOT_FOUND, + IDENT_TOO_LONG, + OPERATOR_EXPECTED, + CLOSEPARENS_EXPECTED, + CLOSEBRACKET_EXPECTED, + + VAR_UNDEFINED, + + OUT_OF_STRING_SPACE, + OUT_OF_MEMORY, + INTERNAL_ERROR, + EXTERNAL_ERROR, + + FCALL_OUT_OF_RANGE, + FCALL_INVALID_PTYPE, + FCALL_UNKNOWN_STR, + + ARRAY_INDEX_OUT_OF_BOUNDS, + + NUMERIC_OVERFLOW, + STRING_NOT_AN_INTEGER_VALUE, + STRING_NOT_A_REAL_VALUE, + + ASSERTION_FAILED, + AMBIGUOUS_CALL, + CANNOT_CAST + }; +}; + +class IVDXScriptInterpreter { +public: + virtual void _placeholder1() {} + virtual void _placeholder2(void *, void *) {} + virtual void _placeholder3(char *s) {} + + virtual void ScriptError(int e)=0; + virtual void _placeholder4(VDXScriptError& cse) {} + virtual char** AllocTempString(long l)=0; + + virtual void _placeholder5() {} +}; + +#define EXT_SCRIPT_ERROR(x) (isi->ScriptError((VDXScriptError::x))) + +typedef VDXScriptValue (*VDXScriptFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); +typedef void (*VDXScriptVoidFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); +typedef int (*VDXScriptIntFunctionPtr)(IVDXScriptInterpreter *, void *, const VDXScriptValue *, int); + +struct VDXScriptFunctionDef { + VDXScriptFunctionPtr func_ptr; + const char *name; + const char *arg_list; +}; + +struct VDXScriptObject { + void *_lookup; // reserved - set to NULL + VDXScriptFunctionDef *func_list; + void *_obj_list; // reserved - set to NULL +}; + +class VDXScriptValue { +public: + enum { T_VOID, T_INT, T_PINT, T_STR, T_ARRAY, T_OBJECT, T_FNAME, T_FUNCTION, T_VARLV, T_LONG, T_DOUBLE } type; + VDXScriptObject *thisPtr; + union { + int i; + char **s; + sint64 l; + double d; + } u; + + VDXScriptValue() { type = T_VOID; } + VDXScriptValue(int i) { type = T_INT; u.i = i; } + VDXScriptValue(sint64 l) { type = T_LONG; u.l = l; } + VDXScriptValue(double d) { type = T_DOUBLE; u.d = d; } + VDXScriptValue(char **s) { type = T_STR; u.s = s; } + + bool isVoid() const { return type == T_VOID; } + bool isInt() const { return type == T_INT; } + bool isString() const { return type == T_STR; } + bool isLong() const { return type == T_LONG; } + bool isDouble() const { return type == T_DOUBLE; } + + int asInt() const { return u.i; } + sint64 asLong() const { return u.l; } + double asDouble() const { return u.d; } + char ** asString() const { return u.s; } +}; + +#ifdef _MSC_VER + #pragma pack(pop) +#endif + +#endif diff --git a/include/vd2/plugin/vdvideoutil.h b/include/vd2/plugin/vdvideoutil.h index 152bfd5f055..8379e4f7d9a 100644 --- a/include/vd2/plugin/vdvideoutil.h +++ b/include/vd2/plugin/vdvideoutil.h @@ -1,121 +1,121 @@ -#ifndef f_VD2_PLUGIN_VDVIDEOUTIL_H -#define f_VD2_PLUGIN_VDVIDEOUTIL_H - -template -T *vd_ptroffset(T *p, ptrdiff_t diff) { - return (T *)((char *)p + diff); -} - -template -class vd_row_iter { -public: - vd_row_iter() {} - vd_row_iter(T *p, ptrdiff_t pitch) : mp(p), mpitch(pitch) {} - vd_row_iter(T *p, ptrdiff_t pitch, int y) : mp(vd_ptroffset(p, pitch*y)), mpitch(pitch) {} - - vd_row_iter(const VFBitmap& bm, int x = 0, int y = 0) : mp(vd_ptroffset((T*)bm.data, bm.pitch*(bm.h - 1 - y))+x), mpitch(-bm.pitch) {} - - operator T*() const { return mp; } - T& operator[](int x) const { return mp[x]; } - - void mulstep(int x) { - mpitch *= x; - } - - const vd_row_iter& operator+=(int y) { - mp = vd_ptroffset(mp, mpitch * y); - return *this; - } - - const vd_row_iter& operator-=(int y) { - mp = vd_ptroffset(mp, -(mpitch * y)); - return *this; - } - - const vd_row_iter& operator++() { - mp = vd_ptroffset(mp, mpitch); - return *this; - } - - const vd_row_iter operator++(int) { - const vd_row_iter temp(*this); - mp = vd_ptroffset(mp, mpitch); - return temp; - } - - const vd_row_iter& operator--() { - mp = vd_ptroffset(mp, -mpitch); - return *this; - } - - const vd_row_iter operator--(int) { - const vd_row_iter temp(*this); - mp = vd_ptroffset(mp, -mpitch); - return temp; - } - -protected: - T *mp; - ptrdiff_t mpitch; -}; - -typedef vd_row_iter vd_pixrow_iter; - -inline uint32 vd_pixavg_down(uint32 x, uint32 y) { - return (x&y) + (((x^y)&0xfefefefe)>>1); -} - -inline uint32 vd_pixavg_up(uint32 x, uint32 y) { - return (x|y) - (((x^y)&0xfefefefe)>>1); -} - -inline void vd_pixunpack(uint32 px, int& r, int& g, int& b) { - r = (px>>16)&255; - g = (px>> 8)&255; - b = (px )&255; -} - -inline uint32 vd_pixpack(int r, int g, int b) { - if ((unsigned)r >= 256) r = ~(r>>31) & 255; - if ((unsigned)g >= 256) g = ~(g>>31) & 255; - if ((unsigned)b >= 256) b = ~(b>>31) & 255; - - return (r<<16) + (g<<8) + b; -} - -inline uint32 vd_pixpackfast(int r, int g, int b) { - return (r<<16) + (g<<8) + b; -} - -struct vd_transform_pixmap_helper { - vd_transform_pixmap_helper(const VFBitmap& dst) - : p((uint32 *)dst.data) - , pitch(dst.pitch) - , w(dst.w) - , h(dst.h) {} - - operator bool() const { return false; } - - uint32 *p; - const ptrdiff_t pitch; - const int w, h; -}; - -#define vd_transform_pixmap_blt(dst, src) \ - if(vd_transform_pixmap_helper dstinfo = dst);else \ - if(vd_transform_pixmap_helper srcinfo = src);else \ - for(int y = 0, h = dstinfo.h, w = dstinfo.w; y < h; ++y, dstinfo.p=vd_ptroffset(dstinfo.p, dstinfo.pitch), srcinfo.p=vd_ptroffset(srcinfo.p, srcinfo.pitch)) \ - for(int x = 0; x < dstinfo.w; ++x) \ - switch(unsigned& out = dstinfo.p[x]) case 0: default: \ - switch(const unsigned& in = srcinfo.p[x]) case 0: default: - -#define vd_transform_pixmap_inplace(dst) \ - if(vd_transform_pixmap_helper dstinfo = dst);else \ - for(int y = 0, h = dstinfo.h, w = dstinfo.w; y < h; ++y, dstinfo.p=vd_ptroffset(dstinfo.p, dstinfo.pitch)) \ - for(int x = 0; x < dstinfo.w; ++x) \ - switch(unsigned& px = dstinfo.p[x]) case 0: default: \ - -#define vd_maketable256_16(x) formula((x+0)),formula((x+1)),formula((x+2)),formula((x+3)),formula((x+4)),formula((x+5)),formula((x+6)),formula((x+7)),formula((x+8)),formula((x+9)),formula((x+10)),formula((x+11)),formula((x+12)),formula((x+13)),formula((x+14)),formula((x+15)) -#define vd_maketable256 vd_maketable256_16(0x00),vd_maketable256_16(0x10),vd_maketable256_16(0x20),vd_maketable256_16(0x30),vd_maketable256_16(0x40),vd_maketable256_16(0x50),vd_maketable256_16(0x60),vd_maketable256_16(0x70),vd_maketable256_16(0x80),vd_maketable256_16(0x90),vd_maketable256_16(0xA0),vd_maketable256_16(0xB0),vd_maketable256_16(0xC0),vd_maketable256_16(0xD0),vd_maketable256_16(0xE0),vd_maketable256_16(0xF0), - -#endif +#ifndef f_VD2_PLUGIN_VDVIDEOUTIL_H +#define f_VD2_PLUGIN_VDVIDEOUTIL_H + +template +T *vd_ptroffset(T *p, ptrdiff_t diff) { + return (T *)((char *)p + diff); +} + +template +class vd_row_iter { +public: + vd_row_iter() {} + vd_row_iter(T *p, ptrdiff_t pitch) : mp(p), mpitch(pitch) {} + vd_row_iter(T *p, ptrdiff_t pitch, int y) : mp(vd_ptroffset(p, pitch*y)), mpitch(pitch) {} + + vd_row_iter(const VFBitmap& bm, int x = 0, int y = 0) : mp(vd_ptroffset((T*)bm.data, bm.pitch*(bm.h - 1 - y))+x), mpitch(-bm.pitch) {} + + operator T*() const { return mp; } + T& operator[](int x) const { return mp[x]; } + + void mulstep(int x) { + mpitch *= x; + } + + const vd_row_iter& operator+=(int y) { + mp = vd_ptroffset(mp, mpitch * y); + return *this; + } + + const vd_row_iter& operator-=(int y) { + mp = vd_ptroffset(mp, -(mpitch * y)); + return *this; + } + + const vd_row_iter& operator++() { + mp = vd_ptroffset(mp, mpitch); + return *this; + } + + const vd_row_iter operator++(int) { + const vd_row_iter temp(*this); + mp = vd_ptroffset(mp, mpitch); + return temp; + } + + const vd_row_iter& operator--() { + mp = vd_ptroffset(mp, -mpitch); + return *this; + } + + const vd_row_iter operator--(int) { + const vd_row_iter temp(*this); + mp = vd_ptroffset(mp, -mpitch); + return temp; + } + +protected: + T *mp; + ptrdiff_t mpitch; +}; + +typedef vd_row_iter vd_pixrow_iter; + +inline uint32 vd_pixavg_down(uint32 x, uint32 y) { + return (x&y) + (((x^y)&0xfefefefe)>>1); +} + +inline uint32 vd_pixavg_up(uint32 x, uint32 y) { + return (x|y) - (((x^y)&0xfefefefe)>>1); +} + +inline void vd_pixunpack(uint32 px, int& r, int& g, int& b) { + r = (px>>16)&255; + g = (px>> 8)&255; + b = (px )&255; +} + +inline uint32 vd_pixpack(int r, int g, int b) { + if ((unsigned)r >= 256) r = ~(r>>31) & 255; + if ((unsigned)g >= 256) g = ~(g>>31) & 255; + if ((unsigned)b >= 256) b = ~(b>>31) & 255; + + return (r<<16) + (g<<8) + b; +} + +inline uint32 vd_pixpackfast(int r, int g, int b) { + return (r<<16) + (g<<8) + b; +} + +struct vd_transform_pixmap_helper { + vd_transform_pixmap_helper(const VFBitmap& dst) + : p((uint32 *)dst.data) + , pitch(dst.pitch) + , w(dst.w) + , h(dst.h) {} + + operator bool() const { return false; } + + uint32 *p; + const ptrdiff_t pitch; + const int w, h; +}; + +#define vd_transform_pixmap_blt(dst, src) \ + if(vd_transform_pixmap_helper dstinfo = dst);else \ + if(vd_transform_pixmap_helper srcinfo = src);else \ + for(int y = 0, h = dstinfo.h, w = dstinfo.w; y < h; ++y, dstinfo.p=vd_ptroffset(dstinfo.p, dstinfo.pitch), srcinfo.p=vd_ptroffset(srcinfo.p, srcinfo.pitch)) \ + for(int x = 0; x < dstinfo.w; ++x) \ + switch(unsigned& out = dstinfo.p[x]) case 0: default: \ + switch(const unsigned& in = srcinfo.p[x]) case 0: default: + +#define vd_transform_pixmap_inplace(dst) \ + if(vd_transform_pixmap_helper dstinfo = dst);else \ + for(int y = 0, h = dstinfo.h, w = dstinfo.w; y < h; ++y, dstinfo.p=vd_ptroffset(dstinfo.p, dstinfo.pitch)) \ + for(int x = 0; x < dstinfo.w; ++x) \ + switch(unsigned& px = dstinfo.p[x]) case 0: default: \ + +#define vd_maketable256_16(x) formula((x+0)),formula((x+1)),formula((x+2)),formula((x+3)),formula((x+4)),formula((x+5)),formula((x+6)),formula((x+7)),formula((x+8)),formula((x+9)),formula((x+10)),formula((x+11)),formula((x+12)),formula((x+13)),formula((x+14)),formula((x+15)) +#define vd_maketable256 vd_maketable256_16(0x00),vd_maketable256_16(0x10),vd_maketable256_16(0x20),vd_maketable256_16(0x30),vd_maketable256_16(0x40),vd_maketable256_16(0x50),vd_maketable256_16(0x60),vd_maketable256_16(0x70),vd_maketable256_16(0x80),vd_maketable256_16(0x90),vd_maketable256_16(0xA0),vd_maketable256_16(0xB0),vd_maketable256_16(0xC0),vd_maketable256_16(0xD0),vd_maketable256_16(0xE0),vd_maketable256_16(0xF0), + +#endif diff --git a/include/version.h b/include/version.h index e554d1bc12c..596e817179a 100644 --- a/include/version.h +++ b/include/version.h @@ -1,117 +1,117 @@ -#ifndef ISPP_INVOKED -/* - * (C) 2010-2024 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 . - - - * Notes: - * NO_VERSION_REV_NEEDED is defined in those cases where we don't need the revision - number, but only the major/minor/patch version so the compiler does not rebuild - everything for every revision. It's currently used in mpcresources, mpciconlib - and VideoRenderers projects. - * MPC_VERSION_ARCH is currently used in VSFilter only. - */ -#endif // ISPP_INVOKED - -#ifndef MPC_VERSION_H -#define MPC_VERSION_H - -#include "mpc-hc_config.h" - -#ifndef _T -#if !defined(ISPP_INVOKED) && (defined(UNICODE) || defined(_UNICODE)) -#define _T(text) L##text -#else -#define _T(text) text -#endif -#endif - -#ifdef NO_VERSION_REV_NEEDED -#define MPC_VERSION_REV 0 -#else -#include "../build/version_rev.h" -#endif - -#define MPC_VERSION_MAJOR 2 -#define MPC_VERSION_MINOR 3 -#define MPC_VERSION_PATCH 7 - -#if MPC_VERSION_REV > 0 -#define MPC_NIGHTLY_RELEASE 1 -#else -#define MPC_NIGHTLY_RELEASE 0 -#endif - -#define MPC_COMP_NAME_STR _T("MPC-HC Team") -#define MPC_COPYRIGHT_STR _T("Copyright 2002-2024 clsid2 and others") -#define MPC_VERSION_COMMENTS WEBSITE_URL - - -#ifndef ISPP_INVOKED - -#ifdef NO_VERSION_REV_NEEDED - -#define MPC_VERSION_NUM MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCH,0 -#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) -#define MPC_VERSION_STR_FULL MPC_VERSION_STR - -#else // !NO_VERSION_REV_NEEDED - -#define MPC_VERSION_NUM MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCH,MPC_VERSION_REV - -#if MPC_NIGHTLY_RELEASE - -#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) _T(".") \ - MAKE_STR(MPC_VERSION_REV) -#define MPC_VERSION_STR_FULL MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) _T(".") \ - MAKE_STR(MPC_VERSION_REV) \ - MPC_VERSION_ADDITIONAL - -#else // !MPC_NIGHTLY_RELEASE - -#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) -#define MPC_VERSION_STR_FULL MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ - MAKE_STR(MPC_VERSION_MINOR) _T(".") \ - MAKE_STR(MPC_VERSION_PATCH) \ - MPC_VERSION_ADDITIONAL - -#endif // MPC_NIGHTLY_RELEASE - -#endif // NO_VERSION_REV_NEEDED - -#endif // ISPP_INVOKED - - -#if MPC_NIGHTLY_RELEASE -#define MPC_VERSION_NIGHTLY _T("Nightly") -#endif - -#ifdef _WIN64 -#define MPC_VERSION_ARCH _T("x64") -#else -#define MPC_VERSION_ARCH _T("x86") -#endif - -#endif // MPC_VERSION_H +#ifndef ISPP_INVOKED +/* + * (C) 2010-2024 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 . + + + * Notes: + * NO_VERSION_REV_NEEDED is defined in those cases where we don't need the revision + number, but only the major/minor/patch version so the compiler does not rebuild + everything for every revision. It's currently used in mpcresources, mpciconlib + and VideoRenderers projects. + * MPC_VERSION_ARCH is currently used in VSFilter only. + */ +#endif // ISPP_INVOKED + +#ifndef MPC_VERSION_H +#define MPC_VERSION_H + +#include "mpc-hc_config.h" + +#ifndef _T +#if !defined(ISPP_INVOKED) && (defined(UNICODE) || defined(_UNICODE)) +#define _T(text) L##text +#else +#define _T(text) text +#endif +#endif + +#ifdef NO_VERSION_REV_NEEDED +#define MPC_VERSION_REV 0 +#else +#include "../build/version_rev.h" +#endif + +#define MPC_VERSION_MAJOR 2 +#define MPC_VERSION_MINOR 3 +#define MPC_VERSION_PATCH 7 + +#if MPC_VERSION_REV > 0 +#define MPC_NIGHTLY_RELEASE 1 +#else +#define MPC_NIGHTLY_RELEASE 0 +#endif + +#define MPC_COMP_NAME_STR _T("MPC-HC Team") +#define MPC_COPYRIGHT_STR _T("Copyright 2002-2024 clsid2 and others") +#define MPC_VERSION_COMMENTS WEBSITE_URL + + +#ifndef ISPP_INVOKED + +#ifdef NO_VERSION_REV_NEEDED + +#define MPC_VERSION_NUM MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCH,0 +#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) +#define MPC_VERSION_STR_FULL MPC_VERSION_STR + +#else // !NO_VERSION_REV_NEEDED + +#define MPC_VERSION_NUM MPC_VERSION_MAJOR,MPC_VERSION_MINOR,MPC_VERSION_PATCH,MPC_VERSION_REV + +#if MPC_NIGHTLY_RELEASE + +#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) _T(".") \ + MAKE_STR(MPC_VERSION_REV) +#define MPC_VERSION_STR_FULL MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) _T(".") \ + MAKE_STR(MPC_VERSION_REV) \ + MPC_VERSION_ADDITIONAL + +#else // !MPC_NIGHTLY_RELEASE + +#define MPC_VERSION_STR MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) +#define MPC_VERSION_STR_FULL MAKE_STR(MPC_VERSION_MAJOR) _T(".") \ + MAKE_STR(MPC_VERSION_MINOR) _T(".") \ + MAKE_STR(MPC_VERSION_PATCH) \ + MPC_VERSION_ADDITIONAL + +#endif // MPC_NIGHTLY_RELEASE + +#endif // NO_VERSION_REV_NEEDED + +#endif // ISPP_INVOKED + + +#if MPC_NIGHTLY_RELEASE +#define MPC_VERSION_NIGHTLY _T("Nightly") +#endif + +#ifdef _WIN64 +#define MPC_VERSION_ARCH _T("x64") +#else +#define MPC_VERSION_ARCH _T("x86") +#endif + +#endif // MPC_VERSION_H diff --git a/include/winddk/devioctl.h b/include/winddk/devioctl.h index fa2e6995bcb..bcb458c74d1 100644 --- a/include/winddk/devioctl.h +++ b/include/winddk/devioctl.h @@ -1,164 +1,164 @@ -/*++ BUILD Version: 0004 // Increment this if a change has global effects - -Copyright (c) 1992-1999 Microsoft Corporation - -Module Name: - - devioctl.h - -Abstract: - - This module contains - - -Revision History: - - ---*/ - -// begin_winioctl - -#ifndef _DEVIOCTL_ -#define _DEVIOCTL_ - -// begin_ntddk begin_wdm begin_nthal begin_ntifs -// -// Define the various device type values. Note that values used by Microsoft -// Corporation are in the range 0-32767, and 32768-65535 are reserved for use -// by customers. -// - -#define DEVICE_TYPE ULONG - -#define FILE_DEVICE_BEEP 0x00000001 -#define FILE_DEVICE_CD_ROM 0x00000002 -#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 -#define FILE_DEVICE_CONTROLLER 0x00000004 -#define FILE_DEVICE_DATALINK 0x00000005 -#define FILE_DEVICE_DFS 0x00000006 -#define FILE_DEVICE_DISK 0x00000007 -#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 -#define FILE_DEVICE_FILE_SYSTEM 0x00000009 -#define FILE_DEVICE_INPORT_PORT 0x0000000a -#define FILE_DEVICE_KEYBOARD 0x0000000b -#define FILE_DEVICE_MAILSLOT 0x0000000c -#define FILE_DEVICE_MIDI_IN 0x0000000d -#define FILE_DEVICE_MIDI_OUT 0x0000000e -#define FILE_DEVICE_MOUSE 0x0000000f -#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 -#define FILE_DEVICE_NAMED_PIPE 0x00000011 -#define FILE_DEVICE_NETWORK 0x00000012 -#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 -#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 -#define FILE_DEVICE_NULL 0x00000015 -#define FILE_DEVICE_PARALLEL_PORT 0x00000016 -#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 -#define FILE_DEVICE_PRINTER 0x00000018 -#define FILE_DEVICE_SCANNER 0x00000019 -#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a -#define FILE_DEVICE_SERIAL_PORT 0x0000001b -#define FILE_DEVICE_SCREEN 0x0000001c -#define FILE_DEVICE_SOUND 0x0000001d -#define FILE_DEVICE_STREAMS 0x0000001e -#define FILE_DEVICE_TAPE 0x0000001f -#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 -#define FILE_DEVICE_TRANSPORT 0x00000021 -#define FILE_DEVICE_UNKNOWN 0x00000022 -#define FILE_DEVICE_VIDEO 0x00000023 -#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 -#define FILE_DEVICE_WAVE_IN 0x00000025 -#define FILE_DEVICE_WAVE_OUT 0x00000026 -#define FILE_DEVICE_8042_PORT 0x00000027 -#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 -#define FILE_DEVICE_BATTERY 0x00000029 -#define FILE_DEVICE_BUS_EXTENDER 0x0000002a -#define FILE_DEVICE_MODEM 0x0000002b -#define FILE_DEVICE_VDM 0x0000002c -#define FILE_DEVICE_MASS_STORAGE 0x0000002d -#define FILE_DEVICE_SMB 0x0000002e -#define FILE_DEVICE_KS 0x0000002f -#define FILE_DEVICE_CHANGER 0x00000030 -#define FILE_DEVICE_SMARTCARD 0x00000031 -#define FILE_DEVICE_ACPI 0x00000032 -#define FILE_DEVICE_DVD 0x00000033 -#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 -#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 -#define FILE_DEVICE_DFS_VOLUME 0x00000036 -#define FILE_DEVICE_SERENUM 0x00000037 -#define FILE_DEVICE_TERMSRV 0x00000038 -#define FILE_DEVICE_KSEC 0x00000039 -#define FILE_DEVICE_FIPS 0x0000003A -#define FILE_DEVICE_INFINIBAND 0x0000003B -#define FILE_DEVICE_VMBUS 0x0000003E -#define FILE_DEVICE_CRYPT_PROVIDER 0x0000003F -#define FILE_DEVICE_WPD 0x00000040 -#define FILE_DEVICE_BLUETOOTH 0x00000041 -#define FILE_DEVICE_MT_COMPOSITE 0x00000042 -#define FILE_DEVICE_MT_TRANSPORT 0x00000043 -#define FILE_DEVICE_BIOMETRIC 0x00000044 -#define FILE_DEVICE_PMI 0x00000045 - -// -// Macro definition for defining IOCTL and FSCTL function control codes. Note -// that function codes 0-2047 are reserved for Microsoft Corporation, and -// 2048-4095 are reserved for customers. -// - -#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ -) - -// -// Macro to extract device type out of the device io control code -// -#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16) - -// -// Macro to extract buffering method out of the device io control code -// -#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3)) - -// -// Define the method codes for how buffers are passed for I/O and FS controls -// - -#define METHOD_BUFFERED 0 -#define METHOD_IN_DIRECT 1 -#define METHOD_OUT_DIRECT 2 -#define METHOD_NEITHER 3 - -// -// Define some easier to comprehend aliases: -// METHOD_DIRECT_TO_HARDWARE (writes, aka METHOD_IN_DIRECT) -// METHOD_DIRECT_FROM_HARDWARE (reads, aka METHOD_OUT_DIRECT) -// - -#define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT -#define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT - -// -// Define the access check value for any access -// -// -// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in -// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these -// constants *MUST* always be in sync. -// -// -// FILE_SPECIAL_ACCESS is checked by the NT I/O system the same as FILE_ANY_ACCESS. -// The file systems, however, may add additional access checks for I/O and FS controls -// that use this value. -// - - -#define FILE_ANY_ACCESS 0 -#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) -#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe -#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe - -// end_ntddk end_wdm end_nthal end_ntifs - -#endif // _DEVIOCTL_ - -// end_winioctl - +/*++ BUILD Version: 0004 // Increment this if a change has global effects + +Copyright (c) 1992-1999 Microsoft Corporation + +Module Name: + + devioctl.h + +Abstract: + + This module contains + + +Revision History: + + +--*/ + +// begin_winioctl + +#ifndef _DEVIOCTL_ +#define _DEVIOCTL_ + +// begin_ntddk begin_wdm begin_nthal begin_ntifs +// +// Define the various device type values. Note that values used by Microsoft +// Corporation are in the range 0-32767, and 32768-65535 are reserved for use +// by customers. +// + +#define DEVICE_TYPE ULONG + +#define FILE_DEVICE_BEEP 0x00000001 +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_CONTROLLER 0x00000004 +#define FILE_DEVICE_DATALINK 0x00000005 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_INPORT_PORT 0x0000000a +#define FILE_DEVICE_KEYBOARD 0x0000000b +#define FILE_DEVICE_MAILSLOT 0x0000000c +#define FILE_DEVICE_MIDI_IN 0x0000000d +#define FILE_DEVICE_MIDI_OUT 0x0000000e +#define FILE_DEVICE_MOUSE 0x0000000f +#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SCANNER 0x00000019 +#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_SCREEN 0x0000001c +#define FILE_DEVICE_SOUND 0x0000001d +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_TRANSPORT 0x00000021 +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define FILE_DEVICE_VIDEO 0x00000023 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_WAVE_IN 0x00000025 +#define FILE_DEVICE_WAVE_OUT 0x00000026 +#define FILE_DEVICE_8042_PORT 0x00000027 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 +#define FILE_DEVICE_BATTERY 0x00000029 +#define FILE_DEVICE_BUS_EXTENDER 0x0000002a +#define FILE_DEVICE_MODEM 0x0000002b +#define FILE_DEVICE_VDM 0x0000002c +#define FILE_DEVICE_MASS_STORAGE 0x0000002d +#define FILE_DEVICE_SMB 0x0000002e +#define FILE_DEVICE_KS 0x0000002f +#define FILE_DEVICE_CHANGER 0x00000030 +#define FILE_DEVICE_SMARTCARD 0x00000031 +#define FILE_DEVICE_ACPI 0x00000032 +#define FILE_DEVICE_DVD 0x00000033 +#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 +#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 +#define FILE_DEVICE_DFS_VOLUME 0x00000036 +#define FILE_DEVICE_SERENUM 0x00000037 +#define FILE_DEVICE_TERMSRV 0x00000038 +#define FILE_DEVICE_KSEC 0x00000039 +#define FILE_DEVICE_FIPS 0x0000003A +#define FILE_DEVICE_INFINIBAND 0x0000003B +#define FILE_DEVICE_VMBUS 0x0000003E +#define FILE_DEVICE_CRYPT_PROVIDER 0x0000003F +#define FILE_DEVICE_WPD 0x00000040 +#define FILE_DEVICE_BLUETOOTH 0x00000041 +#define FILE_DEVICE_MT_COMPOSITE 0x00000042 +#define FILE_DEVICE_MT_TRANSPORT 0x00000043 +#define FILE_DEVICE_BIOMETRIC 0x00000044 +#define FILE_DEVICE_PMI 0x00000045 + +// +// Macro definition for defining IOCTL and FSCTL function control codes. Note +// that function codes 0-2047 are reserved for Microsoft Corporation, and +// 2048-4095 are reserved for customers. +// + +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +// +// Macro to extract device type out of the device io control code +// +#define DEVICE_TYPE_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xffff0000)) >> 16) + +// +// Macro to extract buffering method out of the device io control code +// +#define METHOD_FROM_CTL_CODE(ctrlCode) ((ULONG)(ctrlCode & 3)) + +// +// Define the method codes for how buffers are passed for I/O and FS controls +// + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +// +// Define some easier to comprehend aliases: +// METHOD_DIRECT_TO_HARDWARE (writes, aka METHOD_IN_DIRECT) +// METHOD_DIRECT_FROM_HARDWARE (reads, aka METHOD_OUT_DIRECT) +// + +#define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT +#define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT + +// +// Define the access check value for any access +// +// +// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in +// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these +// constants *MUST* always be in sync. +// +// +// FILE_SPECIAL_ACCESS is checked by the NT I/O system the same as FILE_ANY_ACCESS. +// The file systems, however, may add additional access checks for I/O and FS controls +// that use this value. +// + + +#define FILE_ANY_ACCESS 0 +#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe +#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe + +// end_ntddk end_wdm end_nthal end_ntifs + +#endif // _DEVIOCTL_ + +// end_winioctl + diff --git a/include/winddk/ntddcdrm.h b/include/winddk/ntddcdrm.h index 2f02b4609a5..909a9d8310a 100644 --- a/include/winddk/ntddcdrm.h +++ b/include/winddk/ntddcdrm.h @@ -1,942 +1,942 @@ -/*++ BUILD Version: 0001 // Increment this if a change has global effects - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - ntddcdrm.h - -Abstract: - - This module contains structures and definitions - associated with CDROM IOCTls. - - ---*/ - -// begin_winioctl - -#ifndef _NTDDCDRM_ -#define _NTDDCDRM_ - - -#ifdef __cplusplus -extern "C" { -#endif - - -#if _MSC_VER >= 1200 -#pragma warning(push) -#endif - -#if _MSC_VER > 1000 -#pragma once -#endif - -// -// remove some level 4 warnings for this header file: -#pragma warning(disable:4200) // array[0] -#pragma warning(disable:4201) // nameless struct/unions -#pragma warning(disable:4214) // bit fields other than int -#if defined(__INTEL_COMPILER) -#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// -// NtDeviceIoControlFile IoControlCode values for this device. -// -// Warning: Remember that the low two bits of the code specify how the -// buffers are passed to the driver! -// - -#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM - -#define IOCTL_CDROM_UNLOAD_DRIVER CTL_CODE(IOCTL_CDROM_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// CDROM Audio Device Control Functions -// - -#define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_STOP_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_PAUSE_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_RESUME_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_GET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_PLAY_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_SET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) -#if (NTDDI_VERSION < NTDDI_WS03) -#define IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) -#else -#define OBSOLETE_IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) -#endif -#define IOCTL_CDROM_GET_LAST_SESSION CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) -#define IOCTL_CDROM_DISK_TYPE CTL_CODE(IOCTL_CDROM_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0014, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_READ_TOC_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_GET_CONFIGURATION CTL_CODE(IOCTL_CDROM_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_EXCLUSIVE_ACCESS CTL_CODE(IOCTL_CDROM_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_CDROM_SET_SPEED CTL_CODE(IOCTL_CDROM_BASE, 0x0018, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_GET_INQUIRY_DATA CTL_CODE(IOCTL_CDROM_BASE, 0x0019, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_ENABLE_STREAMING CTL_CODE(IOCTL_CDROM_BASE, 0x001A, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_SEND_OPC_INFORMATION CTL_CODE(IOCTL_CDROM_BASE, 0x001B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_CDROM_GET_PERFORMANCE CTL_CODE(IOCTL_CDROM_BASE, 0x001C, METHOD_BUFFERED, FILE_READ_ACCESS) - -// end_winioctl - -// -// The following device control codes are common for all class drivers. The -// functions codes defined here must match all of the other class drivers. -// -// Warning: these codes will be replaced in the future with the IOCTL_STORAGE -// codes included below -// - -#define IOCTL_CDROM_CHECK_VERIFY CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_EJECT_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_LOAD_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_RESERVE CTL_CODE(IOCTL_CDROM_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_RELEASE CTL_CODE(IOCTL_CDROM_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_CDROM_FIND_NEW_DEVICES CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// The following file contains the IOCTL_STORAGE class ioctl definitions -// - -#include "ntddstor.h" - -// begin_winioctl - - -#define MINIMUM_CDROM_INQUIRY_SIZE 36 // RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) -#define MAXIMUM_CDROM_INQUIRY_SIZE 260 // MAXUCHAR + RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength) - -// -// The following device control code is for the SIMBAD simulated bad -// sector facility. See SIMBAD.H in this directory for related structures. -// - -#define IOCTL_CDROM_SIMBAD CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// Maximum CD Rom size -// - -#define MAXIMUM_NUMBER_TRACKS 100 -#define MAXIMUM_CDROM_SIZE 804 -#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2 // two bytes min transferred - -// -// READ_TOC_EX structure -// -typedef struct _CDROM_READ_TOC_EX { - UCHAR Format : 4; - UCHAR Reserved1 : 3; // future expansion - UCHAR Msf : 1; - UCHAR SessionTrack; - UCHAR Reserved2; // future expansion - UCHAR Reserved3; // future expansion -} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX; - -#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00 -#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01 -#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02 -#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03 -#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04 -#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05 - -// -// CD ROM Table OF Contents (TOC) -// Format 0 - Get table of contents -// - -typedef struct _TRACK_DATA { - UCHAR Reserved; - UCHAR Control : 4; - UCHAR Adr : 4; - UCHAR TrackNumber; - UCHAR Reserved1; - UCHAR Address[4]; -} TRACK_DATA, *PTRACK_DATA; - -typedef struct _CDROM_TOC { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR FirstTrack; - UCHAR LastTrack; - - // - // Track data - // - - TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; -} CDROM_TOC, *PCDROM_TOC; - -#define CDROM_TOC_SIZE sizeof(CDROM_TOC) - -// -// CD ROM Table OF Contents -// Format 1 - Session Information -// - -typedef struct _CDROM_TOC_SESSION_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR FirstCompleteSession; - UCHAR LastCompleteSession; - - // - // One track, representing the first track - // of the last finished session - // - - TRACK_DATA TrackData[1]; - -} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA; - - -// -// CD ROM Table OF Contents -// Format 2 - Full TOC -// - -typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK { - UCHAR SessionNumber; - UCHAR Control : 4; - UCHAR Adr : 4; - UCHAR Reserved1; - UCHAR Point; - UCHAR MsfExtra[3]; - UCHAR Zero; - UCHAR Msf[3]; -} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK; - -typedef struct _CDROM_TOC_FULL_TOC_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR FirstCompleteSession; - UCHAR LastCompleteSession; - - // - // one to N descriptors included - // - -#if !defined(__midl) - CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; -#endif - -} CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA; - -// -// CD ROM Table OF Contents -// Format 3 - Program Memory Area -// -typedef struct _CDROM_TOC_PMA_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR Reserved1; - UCHAR Reserved2; - - // - // one to N descriptors included - // - -#if !defined(__midl) - CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; -#endif - -} CDROM_TOC_PMA_DATA, *PCDROM_TOC_PMA_DATA; - -// -// CD ROM Table OF Contents -// Format 4 - Absolute Time In Pregroove -// - -typedef struct _CDROM_TOC_ATIP_DATA_BLOCK { - - UCHAR CdrwReferenceSpeed : 3; - UCHAR Reserved3 : 1; - UCHAR WritePower : 3; - UCHAR True1 : 1; - UCHAR Reserved4 : 6; - UCHAR UnrestrictedUse : 1; - UCHAR Reserved5 : 1; - UCHAR A3Valid : 1; - UCHAR A2Valid : 1; - UCHAR A1Valid : 1; - UCHAR DiscSubType : 3; - UCHAR IsCdrw : 1; - UCHAR True2 : 1; - UCHAR Reserved7; - - UCHAR LeadInMsf[3]; - UCHAR Reserved8; - - UCHAR LeadOutMsf[3]; - UCHAR Reserved9; - - UCHAR A1Values[3]; - UCHAR Reserved10; - - UCHAR A2Values[3]; - UCHAR Reserved11; - - UCHAR A3Values[3]; - UCHAR Reserved12; - -} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK; - -typedef struct _CDROM_TOC_ATIP_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR Reserved1; - UCHAR Reserved2; - - // - // zero? to N descriptors included. - // - -#if !defined(__midl) - CDROM_TOC_ATIP_DATA_BLOCK Descriptors[0]; -#endif - -} CDROM_TOC_ATIP_DATA, *PCDROM_TOC_ATIP_DATA; - -// -// CD ROM Table OF Contents -// Format 5 - CD Text Info -// -typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK { - UCHAR PackType; - UCHAR TrackNumber : 7; - UCHAR ExtensionFlag : 1; // should be zero! - UCHAR SequenceNumber; - UCHAR CharacterPosition : 4; - UCHAR BlockNumber : 3; - UCHAR Unicode : 1; - union { - UCHAR Text[12]; - WCHAR WText[6]; - }; - UCHAR CRC[2]; -} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK; - -typedef struct _CDROM_TOC_CD_TEXT_DATA { - - // - // Header - // - - UCHAR Length[2]; // add two bytes for this field - UCHAR Reserved1; - UCHAR Reserved2; - - // - // the text info comes in discrete blocks of - // a heavily-overloaded structure - // - -#if !defined(__midl) - CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0]; -#endif - -} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA; - -// -// These are the types used for PackType field in CDROM_TOC_CD_TEXT_DATA_BLOCK -// and also for requesting specific info from IOCTL_CDROM_READ_CD_TEXT -// -#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80 -#define CDROM_CD_TEXT_PACK_PERFORMER 0x81 -#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82 -#define CDROM_CD_TEXT_PACK_COMPOSER 0x83 -#define CDROM_CD_TEXT_PACK_ARRANGER 0x84 -#define CDROM_CD_TEXT_PACK_MESSAGES 0x85 -#define CDROM_CD_TEXT_PACK_DISC_ID 0x86 -#define CDROM_CD_TEXT_PACK_GENRE 0x87 -#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88 -#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89 -// 0x8a - 0x8d are reserved.... -#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e -#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f - -// -// Play audio starting at MSF and ending at MSF -// - -typedef struct _CDROM_PLAY_AUDIO_MSF { - UCHAR StartingM; - UCHAR StartingS; - UCHAR StartingF; - UCHAR EndingM; - UCHAR EndingS; - UCHAR EndingF; -} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF; - -// -// Seek to MSF -// - -typedef struct _CDROM_SEEK_AUDIO_MSF { - UCHAR M; - UCHAR S; - UCHAR F; -} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; - - -// -// Flags for the disk type -// - -typedef struct _CDROM_DISK_DATA { - - ULONG DiskData; - -} CDROM_DISK_DATA, *PCDROM_DISK_DATA; - -#define CDROM_DISK_AUDIO_TRACK (0x00000001) -#define CDROM_DISK_DATA_TRACK (0x00000002) - -// -// CD ROM Data Mode Codes, used with IOCTL_CDROM_READ_Q_CHANNEL -// - -#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 -#define IOCTL_CDROM_CURRENT_POSITION 0x01 -#define IOCTL_CDROM_MEDIA_CATALOG 0x02 -#define IOCTL_CDROM_TRACK_ISRC 0x03 - -typedef struct _CDROM_SUB_Q_DATA_FORMAT { - UCHAR Format; - UCHAR Track; -} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; - - -// -// CD ROM Sub-Q Channel Data Format -// - -typedef struct _SUB_Q_HEADER { - UCHAR Reserved; - UCHAR AudioStatus; - UCHAR DataLength[2]; -} SUB_Q_HEADER, *PSUB_Q_HEADER; - -typedef struct _SUB_Q_CURRENT_POSITION { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Control : 4; - UCHAR ADR : 4; - UCHAR TrackNumber; - UCHAR IndexNumber; - UCHAR AbsoluteAddress[4]; - UCHAR TrackRelativeAddress[4]; -} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; - -typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved[3]; - UCHAR Reserved1 : 7; - UCHAR Mcval : 1; - UCHAR MediaCatalog[15]; -} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; - -typedef struct _SUB_Q_TRACK_ISRC { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved0; - UCHAR Track; - UCHAR Reserved1; - UCHAR Reserved2 : 7; - UCHAR Tcval : 1; - UCHAR TrackIsrc[15]; -} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; - -typedef union _SUB_Q_CHANNEL_DATA { - SUB_Q_CURRENT_POSITION CurrentPosition; - SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; - SUB_Q_TRACK_ISRC TrackIsrc; -} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; - -// -// Audio Status Codes -// - -#define AUDIO_STATUS_NOT_SUPPORTED 0x00 -#define AUDIO_STATUS_IN_PROGRESS 0x11 -#define AUDIO_STATUS_PAUSED 0x12 -#define AUDIO_STATUS_PLAY_COMPLETE 0x13 -#define AUDIO_STATUS_PLAY_ERROR 0x14 -#define AUDIO_STATUS_NO_STATUS 0x15 - -// -// ADR Sub-channel Q Field -// - -#define ADR_NO_MODE_INFORMATION 0x0 -#define ADR_ENCODES_CURRENT_POSITION 0x1 -#define ADR_ENCODES_MEDIA_CATALOG 0x2 -#define ADR_ENCODES_ISRC 0x3 - -// -// Sub-channel Q Control Bits -// - -#define AUDIO_WITH_PREEMPHASIS 0x1 -#define DIGITAL_COPY_PERMITTED 0x2 -#define AUDIO_DATA_TRACK 0x4 -#define TWO_FOUR_CHANNEL_AUDIO 0x8 - -#if (NTDDI_VERSION < NTDDI_WS03) -typedef struct _CDROM_AUDIO_CONTROL { - UCHAR LbaFormat; - USHORT LogicalBlocksPerSecond; -} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL; -#else -#if PRAGMA_DEPRECATED_DDK -#define _CDROM_AUDIO_CONTROL _this_is_obsoleted__CDROM_AUDIO_CONTROL -#define CDROM_AUDIO_CONTROL _this_is_obsoleted_CDROM_AUDIO_CONTROL -#define PCDROM_AUDIO_CONTROL _this_is_obsoleted_PCDROM_AUDIO_CONTROL -#endif // PRAGMA_DEPRECATED_DDK -#endif - -// -// Volume control - Volume takes a value between 1 and 0xFF. -// SCSI-II CDROM audio suppports up to 4 audio ports with -// Independent volume control. -// - -typedef struct _VOLUME_CONTROL { - UCHAR PortVolume[4]; -} VOLUME_CONTROL, *PVOLUME_CONTROL; - -typedef enum _TRACK_MODE_TYPE { - YellowMode2, - XAForm2, - CDDA, - RawWithC2AndSubCode, // CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE per sector - RawWithC2, // CD_RAW_SECTOR_WITH_C2_SIZE per sector - RawWithSubCode // CD_RAW_SECTOR_WITH_SUBCODE_SIZE per sector -} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; - -#define CD_RAW_READ_C2_SIZE ( 296 ) -#define CD_RAW_READ_SUBCODE_SIZE ( 96) -#define CD_RAW_SECTOR_WITH_C2_SIZE (2352+296 ) -#define CD_RAW_SECTOR_WITH_SUBCODE_SIZE (2352 +96) -#define CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE (2352+296+96) - -// -// Passed to cdrom to describe the raw read, ie. Mode 2, Form 2, CDDA... -// - -typedef struct __RAW_READ_INFO { - LARGE_INTEGER DiskOffset; - ULONG SectorCount; - TRACK_MODE_TYPE TrackMode; -} RAW_READ_INFO, *PRAW_READ_INFO; - -typedef enum _MEDIA_BLANK_TYPE { - MediaBlankTypeFull = 0, // mandatory support - MediaBlankTypeMinimal = 1, // mandatory support - MediaBlankTypeIncompleteTrack = 2, // optional support - MediaBlankTypeUnreserveLastTrack = 3, // optional support, hairy - MediaBlankTypeTrackTail = 4, // mandatory support - MediaBlankTypeUncloseLastSession = 5, // optional support - MediaBlankTypeEraseLastSession = 6, // optional support - // MediaBlankType7 is reserved -} MEDIA_BLANK_TYPE, *PMEDIA_BLANK_TYPE; - -// -// IOCTL_CDROM_EXCLUSIVE_ACCESS can be used to get exclusive -// access to the CDROM device. -// - -#define CDROM_EXCLUSIVE_CALLER_LENGTH 64 - -// -// Input values (Flags) for ExclusiveAccessLockDevice -// -// CDROM_LOCK_IGNORE_VOLUME: -// Set it to lock the device even if the file system is mounted. -// WARNING: setting this may cause data corruption! -// -// CDROM_NO_MEDIA_NOTIFICATIONS: -// Set it to prevent sending of a media removal notification -// on exclusive access lock and a media arrival notification -// on unlock. -// - -#define CDROM_LOCK_IGNORE_VOLUME (1 << 0) -#define CDROM_NO_MEDIA_NOTIFICATIONS (1 << 1) - -// -// Output values (Flags) for ExclusiveAccessQueryState -// - -#define CDROM_NOT_IN_EXCLUSIVE_MODE 0 -#define CDROM_IN_EXCLUSIVE_MODE 1 - - -typedef enum _EXCLUSIVE_ACCESS_REQUEST_TYPE { - ExclusiveAccessQueryState, - ExclusiveAccessLockDevice, - ExclusiveAccessUnlockDevice -} EXCLUSIVE_ACCESS_REQUEST_TYPE, *PEXCLUSIVE_ACCESS_REQUEST_TYPE; - - -typedef struct _CDROM_EXCLUSIVE_ACCESS { - - // - // Request type - // - EXCLUSIVE_ACCESS_REQUEST_TYPE RequestType; - - // - // Additional parameters for each request type - // - ULONG Flags; - -} CDROM_EXCLUSIVE_ACCESS, *PCDROM_EXCLUSIVE_ACCESS; - - -typedef struct _CDROM_EXCLUSIVE_LOCK { - - CDROM_EXCLUSIVE_ACCESS Access; - - // - // Caller name string - // - UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; - -} CDROM_EXCLUSIVE_LOCK, *PCDROM_EXCLUSIVE_LOCK; - - -typedef struct _CDROM_EXCLUSIVE_LOCK_STATE { - - BOOLEAN LockState; - - // - // Caller name string - // - UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; - -} CDROM_EXCLUSIVE_LOCK_STATE, *PCDROM_EXCLUSIVE_LOCK_STATE; - -// -// Structure definitions for IOCTL_CDROM_SET_SPEED -// - -typedef enum _CDROM_SPEED_REQUEST { - CdromSetSpeed, - CdromSetStreaming -} CDROM_SPEED_REQUEST, *PCDROM_SPEED_REQUEST; - -typedef enum _WRITE_ROTATION { - CdromDefaultRotation, - CdromCAVRotation -} WRITE_ROTATION, *PWRITE_ROTATION; - -typedef struct _CDROM_SET_SPEED { - - // - // Request type for setting speed - // - CDROM_SPEED_REQUEST RequestType; - - // - // Drive read speed in KB/sec. - // - USHORT ReadSpeed; - - // - // Drive write speed in KB/sec. - // - USHORT WriteSpeed; - - // - // Drive rotation control for write - // - WRITE_ROTATION RotationControl; - -} CDROM_SET_SPEED, *PCDROM_SET_SPEED; - -typedef struct _CDROM_SET_STREAMING { - - // - // Request type for setting speed - // - CDROM_SPEED_REQUEST RequestType; - - // - // Drive read size in KB per ReadTime - // - ULONG ReadSize; - - // - // Read time in milliseconds - // - ULONG ReadTime; - - // - // Drive write size in KB per WriteTime - // - ULONG WriteSize; - - // - // Write time in milliseconds - // - ULONG WriteTime; - - // - // First Logical Block Address of the request - // - ULONG StartLba; - - // - // Last Logical Block Address of the request - // - ULONG EndLba; - - // - // Drive rotation control for write - // - WRITE_ROTATION RotationControl; - - // - // Restore drive defaults - // - BOOLEAN RestoreDefaults; - - // - // Set drive to exact value given - // - BOOLEAN SetExact; - - // - // Optimize performance for random changes - // - BOOLEAN RandomAccess; - - // - // Restore default speed on media change - // - BOOLEAN Persistent; - -} CDROM_SET_STREAMING, *PCDROM_SET_STREAMING; - - -// -// Structure definitions for IOCTL_CDROM_ENABLE_STREAMING -// - -typedef enum _STREAMING_CONTROL_REQUEST_TYPE { - CdromStreamingDisable = 1, - CdromStreamingEnableForReadOnly = 2, - CdromStreamingEnableForWriteOnly = 3, - CdromStreamingEnableForReadWrite = 4 -} STREAMING_CONTROL_REQUEST_TYPE, *PSTREAMING_CONTROL_REQUEST_TYPE; - -typedef struct _CDROM_STREAMING_CONTROL { - - // - // Request type - // - STREAMING_CONTROL_REQUEST_TYPE RequestType; - -} CDROM_STREAMING_CONTROL, *PCDROM_STREAMING_CONTROL; - - -// -// Structure definitions for IOCTL_CDROM_SEND_OPC_INFORMATION -// - -typedef enum _CDROM_OPC_INFO_TYPE { - SimpleOpcInfo = 1 -} CDROM_OPC_INFO_TYPE, *PCDROM_OPC_INFO_TYPE; - -typedef struct _CDROM_SIMPLE_OPC_INFO { - - // - // Request type (must be SimpleOpcInfo) - // - CDROM_OPC_INFO_TYPE RequestType; - - // - // Exclude Layer 0 from OPC - // - BOOLEAN Exclude0; - - // - // Exclude Layer 1 from OPC - // - BOOLEAN Exclude1; - -} CDROM_SIMPLE_OPC_INFO, *PCDROM_SIMPLE_OPC_INFO; - - -// -// Structure definitions for IOCTL_CDROM_GET_PERFORMANCE -// - -typedef enum _CDROM_PERFORMANCE_REQUEST_TYPE { - CdromPerformanceRequest = 1, - CdromWriteSpeedRequest = 2 -} CDROM_PERFORMANCE_REQUEST_TYPE, *PCDROM_PERFORMANCE_REQUEST_TYPE; - -typedef enum _CDROM_PERFORMANCE_TYPE { - CdromReadPerformance = 1, - CdromWritePerformance = 2 -} CDROM_PERFORMANCE_TYPE, *PCDROM_PERFORMANCE_TYPE; - -typedef enum _CDROM_PERFORMANCE_EXCEPTION_TYPE { - CdromNominalPerformance = 1, - CdromEntirePerformanceList = 2, - CdromPerformanceExceptionsOnly = 3 -} CDROM_PERFORMANCE_EXCEPTION_TYPE, *PCDROM_PERFORMANCE_EXCEPTION_TYPE; - -typedef enum _CDROM_PERFORMANCE_TOLERANCE_TYPE { - Cdrom10Nominal20Exceptions = 1 -} CDROM_PERFORMANCE_TOLERANCE_TYPE, *PCDROM_PERFORMANCE_TOLERANCE_TYPE; - -typedef struct _CDROM_PERFORMANCE_REQUEST { - - // - // Request type (must be CdromPerformanceRequest) - // - CDROM_PERFORMANCE_REQUEST_TYPE RequestType; - - // - // Performance type - // - CDROM_PERFORMANCE_TYPE PerformanceType; - - // - // Exceptions to be covered - // - CDROM_PERFORMANCE_EXCEPTION_TYPE Exceptions; - - // - // Tolerance to be ensured - // - CDROM_PERFORMANCE_TOLERANCE_TYPE Tolerance; - - // - // Starting LBA for entire performance list - // - ULONG StaringLba; - -} CDROM_PERFORMANCE_REQUEST, *PCDROM_PERFORMANCE_REQUEST; - -typedef struct _CDROM_WRITE_SPEED_REQUEST { - - // - // Request type (must be CdromWriteSpeedRequest) - // - CDROM_PERFORMANCE_REQUEST_TYPE RequestType; - -} CDROM_WRITE_SPEED_REQUEST, *PCDROM_WRITE_SPEED_REQUEST; - -// Header for data returned by IOCTL_CDROM_GET_PERFORMANCE -typedef struct _CDROM_PERFORMANCE_HEADER { - - // - // Size of available data (vs returned data), not including this field - // - UCHAR DataLength[4]; - - UCHAR Except : 1; - UCHAR Write : 1; - UCHAR Reserved1 : 6; - UCHAR Reserved2[3]; - - // - // Contains a list of the following records (depending on the request): - // CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR, - // CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR, - // CDROM_WRITE_SPEED_DESCRIPTOR - // - UCHAR Data[0]; - -} CDROM_PERFORMANCE_HEADER, *PCDROM_PERFORMANCE_HEADER; - -typedef struct _CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR { - UCHAR StartLba[4]; - UCHAR StartPerformance[4]; - UCHAR EndLba[4]; - UCHAR EndPerformance[4]; -} CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR, *PCDROM_NOMINAL_PERFORMANCE_DESCRIPTOR; - -typedef struct _CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR { - UCHAR Lba[4]; - UCHAR Time[2]; -} CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR, *PCDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR; - -typedef struct _CDROM_WRITE_SPEED_DESCRIPTOR { - UCHAR MixedReadWrite : 1; - UCHAR Exact : 1; - UCHAR Reserved1 : 1; - UCHAR WriteRotationControl : 2; - UCHAR Reserved2 : 3; - UCHAR Reserved3[3]; - UCHAR EndLba[4]; - UCHAR ReadSpeed[4]; - UCHAR WriteSpeed[4]; -} CDROM_WRITE_SPEED_DESCRIPTOR, *PCDROM_WRITE_SPEED_DESCRIPTOR; - - -#ifdef __cplusplus -} -#endif - - -#if _MSC_VER >= 1200 -#pragma warning(pop) // un-sets any local warning changes -#else -#pragma warning(default:4200) // array[0] is not a warning for this file -#pragma warning(default:4201) // nameless struct/unions -#pragma warning(default:4214) // bit fields other than int -#endif - - -#ifdef __cplusplus -} -#endif - -#endif // _NTDDCDRM_ - -// end_winioctl - - +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddcdrm.h + +Abstract: + + This module contains structures and definitions + associated with CDROM IOCTls. + + +--*/ + +// begin_winioctl + +#ifndef _NTDDCDRM_ +#define _NTDDCDRM_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif + +#if _MSC_VER > 1000 +#pragma once +#endif + +// +// remove some level 4 warnings for this header file: +#pragma warning(disable:4200) // array[0] +#pragma warning(disable:4201) // nameless struct/unions +#pragma warning(disable:4214) // bit fields other than int +#if defined(__INTEL_COMPILER) +#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// + +#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM + +#define IOCTL_CDROM_UNLOAD_DRIVER CTL_CODE(IOCTL_CDROM_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// CDROM Audio Device Control Functions +// + +#define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SEEK_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_STOP_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_PAUSE_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RESUME_AUDIO CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_PLAY_AUDIO_MSF CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SET_VOLUME CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_READ_Q_CHANNEL CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) +#if (NTDDI_VERSION < NTDDI_WS03) +#define IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) +#else +#define OBSOLETE_IOCTL_CDROM_GET_CONTROL CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) +#endif +#define IOCTL_CDROM_GET_LAST_SESSION CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) +#define IOCTL_CDROM_DISK_TYPE CTL_CODE(IOCTL_CDROM_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0014, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_READ_TOC_EX CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_CONFIGURATION CTL_CODE(IOCTL_CDROM_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_EXCLUSIVE_ACCESS CTL_CODE(IOCTL_CDROM_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_CDROM_SET_SPEED CTL_CODE(IOCTL_CDROM_BASE, 0x0018, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_GET_INQUIRY_DATA CTL_CODE(IOCTL_CDROM_BASE, 0x0019, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_ENABLE_STREAMING CTL_CODE(IOCTL_CDROM_BASE, 0x001A, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_SEND_OPC_INFORMATION CTL_CODE(IOCTL_CDROM_BASE, 0x001B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_CDROM_GET_PERFORMANCE CTL_CODE(IOCTL_CDROM_BASE, 0x001C, METHOD_BUFFERED, FILE_READ_ACCESS) + +// end_winioctl + +// +// The following device control codes are common for all class drivers. The +// functions codes defined here must match all of the other class drivers. +// +// Warning: these codes will be replaced in the future with the IOCTL_STORAGE +// codes included below +// + +#define IOCTL_CDROM_CHECK_VERIFY CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_EJECT_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_LOAD_MEDIA CTL_CODE(IOCTL_CDROM_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RESERVE CTL_CODE(IOCTL_CDROM_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_RELEASE CTL_CODE(IOCTL_CDROM_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_CDROM_FIND_NEW_DEVICES CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// The following file contains the IOCTL_STORAGE class ioctl definitions +// + +#include "ntddstor.h" + +// begin_winioctl + + +#define MINIMUM_CDROM_INQUIRY_SIZE 36 // RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, ProductRevisionLevel) +#define MAXIMUM_CDROM_INQUIRY_SIZE 260 // MAXUCHAR + RTL_SIZEOF_THROUGH_FIELD(INQUIRYDATA, AdditionalLength) + +// +// The following device control code is for the SIMBAD simulated bad +// sector facility. See SIMBAD.H in this directory for related structures. +// + +#define IOCTL_CDROM_SIMBAD CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// Maximum CD Rom size +// + +#define MAXIMUM_NUMBER_TRACKS 100 +#define MAXIMUM_CDROM_SIZE 804 +#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2 // two bytes min transferred + +// +// READ_TOC_EX structure +// +typedef struct _CDROM_READ_TOC_EX { + UCHAR Format : 4; + UCHAR Reserved1 : 3; // future expansion + UCHAR Msf : 1; + UCHAR SessionTrack; + UCHAR Reserved2; // future expansion + UCHAR Reserved3; // future expansion +} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX; + +#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00 +#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01 +#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02 +#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03 +#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04 +#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05 + +// +// CD ROM Table OF Contents (TOC) +// Format 0 - Get table of contents +// + +typedef struct _TRACK_DATA { + UCHAR Reserved; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR TrackNumber; + UCHAR Reserved1; + UCHAR Address[4]; +} TRACK_DATA, *PTRACK_DATA; + +typedef struct _CDROM_TOC { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstTrack; + UCHAR LastTrack; + + // + // Track data + // + + TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; +} CDROM_TOC, *PCDROM_TOC; + +#define CDROM_TOC_SIZE sizeof(CDROM_TOC) + +// +// CD ROM Table OF Contents +// Format 1 - Session Information +// + +typedef struct _CDROM_TOC_SESSION_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstCompleteSession; + UCHAR LastCompleteSession; + + // + // One track, representing the first track + // of the last finished session + // + + TRACK_DATA TrackData[1]; + +} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA; + + +// +// CD ROM Table OF Contents +// Format 2 - Full TOC +// + +typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK { + UCHAR SessionNumber; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR Reserved1; + UCHAR Point; + UCHAR MsfExtra[3]; + UCHAR Zero; + UCHAR Msf[3]; +} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK; + +typedef struct _CDROM_TOC_FULL_TOC_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR FirstCompleteSession; + UCHAR LastCompleteSession; + + // + // one to N descriptors included + // + +#if !defined(__midl) + CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; +#endif + +} CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA; + +// +// CD ROM Table OF Contents +// Format 3 - Program Memory Area +// +typedef struct _CDROM_TOC_PMA_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // one to N descriptors included + // + +#if !defined(__midl) + CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; +#endif + +} CDROM_TOC_PMA_DATA, *PCDROM_TOC_PMA_DATA; + +// +// CD ROM Table OF Contents +// Format 4 - Absolute Time In Pregroove +// + +typedef struct _CDROM_TOC_ATIP_DATA_BLOCK { + + UCHAR CdrwReferenceSpeed : 3; + UCHAR Reserved3 : 1; + UCHAR WritePower : 3; + UCHAR True1 : 1; + UCHAR Reserved4 : 6; + UCHAR UnrestrictedUse : 1; + UCHAR Reserved5 : 1; + UCHAR A3Valid : 1; + UCHAR A2Valid : 1; + UCHAR A1Valid : 1; + UCHAR DiscSubType : 3; + UCHAR IsCdrw : 1; + UCHAR True2 : 1; + UCHAR Reserved7; + + UCHAR LeadInMsf[3]; + UCHAR Reserved8; + + UCHAR LeadOutMsf[3]; + UCHAR Reserved9; + + UCHAR A1Values[3]; + UCHAR Reserved10; + + UCHAR A2Values[3]; + UCHAR Reserved11; + + UCHAR A3Values[3]; + UCHAR Reserved12; + +} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK; + +typedef struct _CDROM_TOC_ATIP_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // zero? to N descriptors included. + // + +#if !defined(__midl) + CDROM_TOC_ATIP_DATA_BLOCK Descriptors[0]; +#endif + +} CDROM_TOC_ATIP_DATA, *PCDROM_TOC_ATIP_DATA; + +// +// CD ROM Table OF Contents +// Format 5 - CD Text Info +// +typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK { + UCHAR PackType; + UCHAR TrackNumber : 7; + UCHAR ExtensionFlag : 1; // should be zero! + UCHAR SequenceNumber; + UCHAR CharacterPosition : 4; + UCHAR BlockNumber : 3; + UCHAR Unicode : 1; + union { + UCHAR Text[12]; + WCHAR WText[6]; + }; + UCHAR CRC[2]; +} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK; + +typedef struct _CDROM_TOC_CD_TEXT_DATA { + + // + // Header + // + + UCHAR Length[2]; // add two bytes for this field + UCHAR Reserved1; + UCHAR Reserved2; + + // + // the text info comes in discrete blocks of + // a heavily-overloaded structure + // + +#if !defined(__midl) + CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0]; +#endif + +} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA; + +// +// These are the types used for PackType field in CDROM_TOC_CD_TEXT_DATA_BLOCK +// and also for requesting specific info from IOCTL_CDROM_READ_CD_TEXT +// +#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80 +#define CDROM_CD_TEXT_PACK_PERFORMER 0x81 +#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82 +#define CDROM_CD_TEXT_PACK_COMPOSER 0x83 +#define CDROM_CD_TEXT_PACK_ARRANGER 0x84 +#define CDROM_CD_TEXT_PACK_MESSAGES 0x85 +#define CDROM_CD_TEXT_PACK_DISC_ID 0x86 +#define CDROM_CD_TEXT_PACK_GENRE 0x87 +#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88 +#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89 +// 0x8a - 0x8d are reserved.... +#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e +#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f + +// +// Play audio starting at MSF and ending at MSF +// + +typedef struct _CDROM_PLAY_AUDIO_MSF { + UCHAR StartingM; + UCHAR StartingS; + UCHAR StartingF; + UCHAR EndingM; + UCHAR EndingS; + UCHAR EndingF; +} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF; + +// +// Seek to MSF +// + +typedef struct _CDROM_SEEK_AUDIO_MSF { + UCHAR M; + UCHAR S; + UCHAR F; +} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; + + +// +// Flags for the disk type +// + +typedef struct _CDROM_DISK_DATA { + + ULONG DiskData; + +} CDROM_DISK_DATA, *PCDROM_DISK_DATA; + +#define CDROM_DISK_AUDIO_TRACK (0x00000001) +#define CDROM_DISK_DATA_TRACK (0x00000002) + +// +// CD ROM Data Mode Codes, used with IOCTL_CDROM_READ_Q_CHANNEL +// + +#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 +#define IOCTL_CDROM_CURRENT_POSITION 0x01 +#define IOCTL_CDROM_MEDIA_CATALOG 0x02 +#define IOCTL_CDROM_TRACK_ISRC 0x03 + +typedef struct _CDROM_SUB_Q_DATA_FORMAT { + UCHAR Format; + UCHAR Track; +} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; + + +// +// CD ROM Sub-Q Channel Data Format +// + +typedef struct _SUB_Q_HEADER { + UCHAR Reserved; + UCHAR AudioStatus; + UCHAR DataLength[2]; +} SUB_Q_HEADER, *PSUB_Q_HEADER; + +typedef struct _SUB_Q_CURRENT_POSITION { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Control : 4; + UCHAR ADR : 4; + UCHAR TrackNumber; + UCHAR IndexNumber; + UCHAR AbsoluteAddress[4]; + UCHAR TrackRelativeAddress[4]; +} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; + +typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved[3]; + UCHAR Reserved1 : 7; + UCHAR Mcval : 1; + UCHAR MediaCatalog[15]; +} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; + +typedef struct _SUB_Q_TRACK_ISRC { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved0; + UCHAR Track; + UCHAR Reserved1; + UCHAR Reserved2 : 7; + UCHAR Tcval : 1; + UCHAR TrackIsrc[15]; +} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; + +typedef union _SUB_Q_CHANNEL_DATA { + SUB_Q_CURRENT_POSITION CurrentPosition; + SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; + SUB_Q_TRACK_ISRC TrackIsrc; +} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; + +// +// Audio Status Codes +// + +#define AUDIO_STATUS_NOT_SUPPORTED 0x00 +#define AUDIO_STATUS_IN_PROGRESS 0x11 +#define AUDIO_STATUS_PAUSED 0x12 +#define AUDIO_STATUS_PLAY_COMPLETE 0x13 +#define AUDIO_STATUS_PLAY_ERROR 0x14 +#define AUDIO_STATUS_NO_STATUS 0x15 + +// +// ADR Sub-channel Q Field +// + +#define ADR_NO_MODE_INFORMATION 0x0 +#define ADR_ENCODES_CURRENT_POSITION 0x1 +#define ADR_ENCODES_MEDIA_CATALOG 0x2 +#define ADR_ENCODES_ISRC 0x3 + +// +// Sub-channel Q Control Bits +// + +#define AUDIO_WITH_PREEMPHASIS 0x1 +#define DIGITAL_COPY_PERMITTED 0x2 +#define AUDIO_DATA_TRACK 0x4 +#define TWO_FOUR_CHANNEL_AUDIO 0x8 + +#if (NTDDI_VERSION < NTDDI_WS03) +typedef struct _CDROM_AUDIO_CONTROL { + UCHAR LbaFormat; + USHORT LogicalBlocksPerSecond; +} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL; +#else +#if PRAGMA_DEPRECATED_DDK +#define _CDROM_AUDIO_CONTROL _this_is_obsoleted__CDROM_AUDIO_CONTROL +#define CDROM_AUDIO_CONTROL _this_is_obsoleted_CDROM_AUDIO_CONTROL +#define PCDROM_AUDIO_CONTROL _this_is_obsoleted_PCDROM_AUDIO_CONTROL +#endif // PRAGMA_DEPRECATED_DDK +#endif + +// +// Volume control - Volume takes a value between 1 and 0xFF. +// SCSI-II CDROM audio suppports up to 4 audio ports with +// Independent volume control. +// + +typedef struct _VOLUME_CONTROL { + UCHAR PortVolume[4]; +} VOLUME_CONTROL, *PVOLUME_CONTROL; + +typedef enum _TRACK_MODE_TYPE { + YellowMode2, + XAForm2, + CDDA, + RawWithC2AndSubCode, // CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE per sector + RawWithC2, // CD_RAW_SECTOR_WITH_C2_SIZE per sector + RawWithSubCode // CD_RAW_SECTOR_WITH_SUBCODE_SIZE per sector +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; + +#define CD_RAW_READ_C2_SIZE ( 296 ) +#define CD_RAW_READ_SUBCODE_SIZE ( 96) +#define CD_RAW_SECTOR_WITH_C2_SIZE (2352+296 ) +#define CD_RAW_SECTOR_WITH_SUBCODE_SIZE (2352 +96) +#define CD_RAW_SECTOR_WITH_C2_AND_SUBCODE_SIZE (2352+296+96) + +// +// Passed to cdrom to describe the raw read, ie. Mode 2, Form 2, CDDA... +// + +typedef struct __RAW_READ_INFO { + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +typedef enum _MEDIA_BLANK_TYPE { + MediaBlankTypeFull = 0, // mandatory support + MediaBlankTypeMinimal = 1, // mandatory support + MediaBlankTypeIncompleteTrack = 2, // optional support + MediaBlankTypeUnreserveLastTrack = 3, // optional support, hairy + MediaBlankTypeTrackTail = 4, // mandatory support + MediaBlankTypeUncloseLastSession = 5, // optional support + MediaBlankTypeEraseLastSession = 6, // optional support + // MediaBlankType7 is reserved +} MEDIA_BLANK_TYPE, *PMEDIA_BLANK_TYPE; + +// +// IOCTL_CDROM_EXCLUSIVE_ACCESS can be used to get exclusive +// access to the CDROM device. +// + +#define CDROM_EXCLUSIVE_CALLER_LENGTH 64 + +// +// Input values (Flags) for ExclusiveAccessLockDevice +// +// CDROM_LOCK_IGNORE_VOLUME: +// Set it to lock the device even if the file system is mounted. +// WARNING: setting this may cause data corruption! +// +// CDROM_NO_MEDIA_NOTIFICATIONS: +// Set it to prevent sending of a media removal notification +// on exclusive access lock and a media arrival notification +// on unlock. +// + +#define CDROM_LOCK_IGNORE_VOLUME (1 << 0) +#define CDROM_NO_MEDIA_NOTIFICATIONS (1 << 1) + +// +// Output values (Flags) for ExclusiveAccessQueryState +// + +#define CDROM_NOT_IN_EXCLUSIVE_MODE 0 +#define CDROM_IN_EXCLUSIVE_MODE 1 + + +typedef enum _EXCLUSIVE_ACCESS_REQUEST_TYPE { + ExclusiveAccessQueryState, + ExclusiveAccessLockDevice, + ExclusiveAccessUnlockDevice +} EXCLUSIVE_ACCESS_REQUEST_TYPE, *PEXCLUSIVE_ACCESS_REQUEST_TYPE; + + +typedef struct _CDROM_EXCLUSIVE_ACCESS { + + // + // Request type + // + EXCLUSIVE_ACCESS_REQUEST_TYPE RequestType; + + // + // Additional parameters for each request type + // + ULONG Flags; + +} CDROM_EXCLUSIVE_ACCESS, *PCDROM_EXCLUSIVE_ACCESS; + + +typedef struct _CDROM_EXCLUSIVE_LOCK { + + CDROM_EXCLUSIVE_ACCESS Access; + + // + // Caller name string + // + UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; + +} CDROM_EXCLUSIVE_LOCK, *PCDROM_EXCLUSIVE_LOCK; + + +typedef struct _CDROM_EXCLUSIVE_LOCK_STATE { + + BOOLEAN LockState; + + // + // Caller name string + // + UCHAR CallerName[CDROM_EXCLUSIVE_CALLER_LENGTH]; + +} CDROM_EXCLUSIVE_LOCK_STATE, *PCDROM_EXCLUSIVE_LOCK_STATE; + +// +// Structure definitions for IOCTL_CDROM_SET_SPEED +// + +typedef enum _CDROM_SPEED_REQUEST { + CdromSetSpeed, + CdromSetStreaming +} CDROM_SPEED_REQUEST, *PCDROM_SPEED_REQUEST; + +typedef enum _WRITE_ROTATION { + CdromDefaultRotation, + CdromCAVRotation +} WRITE_ROTATION, *PWRITE_ROTATION; + +typedef struct _CDROM_SET_SPEED { + + // + // Request type for setting speed + // + CDROM_SPEED_REQUEST RequestType; + + // + // Drive read speed in KB/sec. + // + USHORT ReadSpeed; + + // + // Drive write speed in KB/sec. + // + USHORT WriteSpeed; + + // + // Drive rotation control for write + // + WRITE_ROTATION RotationControl; + +} CDROM_SET_SPEED, *PCDROM_SET_SPEED; + +typedef struct _CDROM_SET_STREAMING { + + // + // Request type for setting speed + // + CDROM_SPEED_REQUEST RequestType; + + // + // Drive read size in KB per ReadTime + // + ULONG ReadSize; + + // + // Read time in milliseconds + // + ULONG ReadTime; + + // + // Drive write size in KB per WriteTime + // + ULONG WriteSize; + + // + // Write time in milliseconds + // + ULONG WriteTime; + + // + // First Logical Block Address of the request + // + ULONG StartLba; + + // + // Last Logical Block Address of the request + // + ULONG EndLba; + + // + // Drive rotation control for write + // + WRITE_ROTATION RotationControl; + + // + // Restore drive defaults + // + BOOLEAN RestoreDefaults; + + // + // Set drive to exact value given + // + BOOLEAN SetExact; + + // + // Optimize performance for random changes + // + BOOLEAN RandomAccess; + + // + // Restore default speed on media change + // + BOOLEAN Persistent; + +} CDROM_SET_STREAMING, *PCDROM_SET_STREAMING; + + +// +// Structure definitions for IOCTL_CDROM_ENABLE_STREAMING +// + +typedef enum _STREAMING_CONTROL_REQUEST_TYPE { + CdromStreamingDisable = 1, + CdromStreamingEnableForReadOnly = 2, + CdromStreamingEnableForWriteOnly = 3, + CdromStreamingEnableForReadWrite = 4 +} STREAMING_CONTROL_REQUEST_TYPE, *PSTREAMING_CONTROL_REQUEST_TYPE; + +typedef struct _CDROM_STREAMING_CONTROL { + + // + // Request type + // + STREAMING_CONTROL_REQUEST_TYPE RequestType; + +} CDROM_STREAMING_CONTROL, *PCDROM_STREAMING_CONTROL; + + +// +// Structure definitions for IOCTL_CDROM_SEND_OPC_INFORMATION +// + +typedef enum _CDROM_OPC_INFO_TYPE { + SimpleOpcInfo = 1 +} CDROM_OPC_INFO_TYPE, *PCDROM_OPC_INFO_TYPE; + +typedef struct _CDROM_SIMPLE_OPC_INFO { + + // + // Request type (must be SimpleOpcInfo) + // + CDROM_OPC_INFO_TYPE RequestType; + + // + // Exclude Layer 0 from OPC + // + BOOLEAN Exclude0; + + // + // Exclude Layer 1 from OPC + // + BOOLEAN Exclude1; + +} CDROM_SIMPLE_OPC_INFO, *PCDROM_SIMPLE_OPC_INFO; + + +// +// Structure definitions for IOCTL_CDROM_GET_PERFORMANCE +// + +typedef enum _CDROM_PERFORMANCE_REQUEST_TYPE { + CdromPerformanceRequest = 1, + CdromWriteSpeedRequest = 2 +} CDROM_PERFORMANCE_REQUEST_TYPE, *PCDROM_PERFORMANCE_REQUEST_TYPE; + +typedef enum _CDROM_PERFORMANCE_TYPE { + CdromReadPerformance = 1, + CdromWritePerformance = 2 +} CDROM_PERFORMANCE_TYPE, *PCDROM_PERFORMANCE_TYPE; + +typedef enum _CDROM_PERFORMANCE_EXCEPTION_TYPE { + CdromNominalPerformance = 1, + CdromEntirePerformanceList = 2, + CdromPerformanceExceptionsOnly = 3 +} CDROM_PERFORMANCE_EXCEPTION_TYPE, *PCDROM_PERFORMANCE_EXCEPTION_TYPE; + +typedef enum _CDROM_PERFORMANCE_TOLERANCE_TYPE { + Cdrom10Nominal20Exceptions = 1 +} CDROM_PERFORMANCE_TOLERANCE_TYPE, *PCDROM_PERFORMANCE_TOLERANCE_TYPE; + +typedef struct _CDROM_PERFORMANCE_REQUEST { + + // + // Request type (must be CdromPerformanceRequest) + // + CDROM_PERFORMANCE_REQUEST_TYPE RequestType; + + // + // Performance type + // + CDROM_PERFORMANCE_TYPE PerformanceType; + + // + // Exceptions to be covered + // + CDROM_PERFORMANCE_EXCEPTION_TYPE Exceptions; + + // + // Tolerance to be ensured + // + CDROM_PERFORMANCE_TOLERANCE_TYPE Tolerance; + + // + // Starting LBA for entire performance list + // + ULONG StaringLba; + +} CDROM_PERFORMANCE_REQUEST, *PCDROM_PERFORMANCE_REQUEST; + +typedef struct _CDROM_WRITE_SPEED_REQUEST { + + // + // Request type (must be CdromWriteSpeedRequest) + // + CDROM_PERFORMANCE_REQUEST_TYPE RequestType; + +} CDROM_WRITE_SPEED_REQUEST, *PCDROM_WRITE_SPEED_REQUEST; + +// Header for data returned by IOCTL_CDROM_GET_PERFORMANCE +typedef struct _CDROM_PERFORMANCE_HEADER { + + // + // Size of available data (vs returned data), not including this field + // + UCHAR DataLength[4]; + + UCHAR Except : 1; + UCHAR Write : 1; + UCHAR Reserved1 : 6; + UCHAR Reserved2[3]; + + // + // Contains a list of the following records (depending on the request): + // CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR, + // CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR, + // CDROM_WRITE_SPEED_DESCRIPTOR + // + UCHAR Data[0]; + +} CDROM_PERFORMANCE_HEADER, *PCDROM_PERFORMANCE_HEADER; + +typedef struct _CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR { + UCHAR StartLba[4]; + UCHAR StartPerformance[4]; + UCHAR EndLba[4]; + UCHAR EndPerformance[4]; +} CDROM_NOMINAL_PERFORMANCE_DESCRIPTOR, *PCDROM_NOMINAL_PERFORMANCE_DESCRIPTOR; + +typedef struct _CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR { + UCHAR Lba[4]; + UCHAR Time[2]; +} CDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR, *PCDROM_EXCEPTION_PERFORMANCE_DESCRIPTOR; + +typedef struct _CDROM_WRITE_SPEED_DESCRIPTOR { + UCHAR MixedReadWrite : 1; + UCHAR Exact : 1; + UCHAR Reserved1 : 1; + UCHAR WriteRotationControl : 2; + UCHAR Reserved2 : 3; + UCHAR Reserved3[3]; + UCHAR EndLba[4]; + UCHAR ReadSpeed[4]; + UCHAR WriteSpeed[4]; +} CDROM_WRITE_SPEED_DESCRIPTOR, *PCDROM_WRITE_SPEED_DESCRIPTOR; + + +#ifdef __cplusplus +} +#endif + + +#if _MSC_VER >= 1200 +#pragma warning(pop) // un-sets any local warning changes +#else +#pragma warning(default:4200) // array[0] is not a warning for this file +#pragma warning(default:4201) // nameless struct/unions +#pragma warning(default:4214) // bit fields other than int +#endif + + +#ifdef __cplusplus +} +#endif + +#endif // _NTDDCDRM_ + +// end_winioctl + + diff --git a/include/winddk/ntddcdvd.h b/include/winddk/ntddcdvd.h index c2baf1664e9..b4ded0888e1 100644 --- a/include/winddk/ntddcdvd.h +++ b/include/winddk/ntddcdvd.h @@ -1,796 +1,796 @@ -/*++ BUILD Version: 0001 // Increment this if a change has global effects - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - ntddcdvd.h - -Abstract: - - This module contains structures and definitions - associated with DVD ioctls. - - This module is used in conjunction with ntddcdrm.h which contains the - cdrom specific ioctls which will work on CDVD drives - - ---*/ - -// begin_winioctl - -#ifndef _NTDDCDVD_ -#define _NTDDCDVD_ -#pragma warning(push) -#pragma warning(disable:4200) // zero-sized array -#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union -#pragma warning(disable:4214) // bitfield other than int -#if defined(__INTEL_COMPILER) -#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero -#endif - -#if _MSC_VER > 1000 -#pragma once -#endif - -// -// NtDeviceIoControlFile IoControlCode values for this device. -// -// Warning: Remember that the low two bits of the code specify how the -// buffers are passed to the driver! -// - -#define IOCTL_DVD_BASE FILE_DEVICE_DVD - -// -// CDVD Device Control Functions -// -// Warning: Ioctls from 200 through 300 are used for the old common class -// driver ioctls and should not be used for device specific functionality -// - -// -// CSS-related IOCTLs -// - -#define IOCTL_DVD_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_READ_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_SEND_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0403, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_SET_READ_AHEAD CTL_CODE(IOCTL_DVD_BASE, 0x0404, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_GET_REGION CTL_CODE(IOCTL_DVD_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DVD_SEND_KEY2 CTL_CODE(IOCTL_DVD_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// AACS-related IOCTLs -// -#define IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE CTL_CODE(IOCTL_DVD_BASE, 0x430, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_MEDIA_KEY_BLOCK CTL_CODE(IOCTL_DVD_BASE, 0x431, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x432, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x433, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_SEND_CERTIFICATE CTL_CODE(IOCTL_DVD_BASE, 0x434, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_GET_CERTIFICATE CTL_CODE(IOCTL_DVD_BASE, 0x435, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_GET_CHALLENGE_KEY CTL_CODE(IOCTL_DVD_BASE, 0x436, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_SEND_CHALLENGE_KEY CTL_CODE(IOCTL_DVD_BASE, 0x437, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_VOLUME_ID CTL_CODE(IOCTL_DVD_BASE, 0x438, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_SERIAL_NUMBER CTL_CODE(IOCTL_DVD_BASE, 0x439, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_MEDIA_ID CTL_CODE(IOCTL_DVD_BASE, 0x43A, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_READ_BINDING_NONCE CTL_CODE(IOCTL_DVD_BASE, 0x43B, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_AACS_GENERATE_BINDING_NONCE CTL_CODE(IOCTL_DVD_BASE, 0x43C, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// DVD Structure queries -// - -#define IOCTL_DVD_READ_STRUCTURE CTL_CODE(IOCTL_DVD_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// The following file contains the IOCTL_STORAGE class ioctl definitions -// - -#define IOCTL_STORAGE_SET_READ_AHEAD CTL_CODE(IOCTL_STORAGE_BASE, 0x0100, METHOD_BUFFERED, FILE_READ_ACCESS) - -// end_winioctl - -#include "ntddstor.h" - -// begin_winioctl - - -#ifdef __cplusplus -extern "C" { -#endif - - -typedef enum { - DvdChallengeKey = 0x01, - DvdBusKey1, - DvdBusKey2, - DvdTitleKey, - DvdAsf, - DvdSetRpcKey = 0x6, - DvdGetRpcKey = 0x8, - DvdDiskKey = 0x80, - DvdInvalidateAGID = 0x3f -} DVD_KEY_TYPE; - -typedef __typefix(LONG) __range(-1,3) ULONG DVD_SESSION_ID, *PDVD_SESSION_ID; - -#include -typedef struct _DVD_COPY_PROTECT_KEY { - ULONG KeyLength; - DVD_SESSION_ID SessionId; - DVD_KEY_TYPE KeyType; - ULONG KeyFlags; - union { - HANDLE FileHandle; - LARGE_INTEGER TitleOffset; - } Parameters; - UCHAR KeyData[0]; -} DVD_COPY_PROTECT_KEY, *PDVD_COPY_PROTECT_KEY; -#include - -// -// Predefined (Mt. Fuji) key sizes -// Add sizeof(DVD_COPY_PROTECT_KEY) to get allocation size for -// the full key structure -// - -#define DVD_CHALLENGE_KEY_LENGTH (12 + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_BUS_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_TITLE_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_DISK_KEY_LENGTH (2048 + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_RPC_KEY_LENGTH (sizeof(DVD_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_SET_RPC_KEY_LENGTH (sizeof(DVD_SET_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY)) -#define DVD_ASF_LENGTH (sizeof(DVD_ASF) + sizeof(DVD_COPY_PROTECT_KEY)) - -// -// Used with IOCTL_DVD_END_SESSION to end all DVD sessions at once -// - -#define DVD_END_ALL_SESSIONS ((DVD_SESSION_ID) 0xffffffff) - -// -// CGMS Copy Protection Flags -// - -#define DVD_CGMS_RESERVED_MASK 0x00000078 - -#define DVD_CGMS_COPY_PROTECT_MASK 0x00000018 -#define DVD_CGMS_COPY_PERMITTED 0x00000000 -#define DVD_CGMS_COPY_ONCE 0x00000010 -#define DVD_CGMS_NO_COPY 0x00000018 - -#define DVD_COPYRIGHT_MASK 0x00000040 -#define DVD_NOT_COPYRIGHTED 0x00000000 -#define DVD_COPYRIGHTED 0x00000040 - -#define DVD_SECTOR_PROTECT_MASK 0x00000020 -#define DVD_SECTOR_NOT_PROTECTED 0x00000000 -#define DVD_SECTOR_PROTECTED 0x00000020 - -/*++ - -IOCTL_STORAGE_SET_READ_AHEAD - -Requests that the storage device skip to TargetAddress once it has run across -TriggerAddress during the course of it's read-ahead caching operations. - -Input: - - a STORAGE_SET_READ_AHEAD structure which contains: - * the trigger address - * the target address - -Output: - - none - ---*/ - -#include -typedef struct _STORAGE_SET_READ_AHEAD { - LARGE_INTEGER TriggerAddress; - LARGE_INTEGER TargetAddress; -} STORAGE_SET_READ_AHEAD, *PSTORAGE_SET_READ_AHEAD; -#include - -/*++ - -IOCTL_DVD_READ_STRUCTURE - -Issues a READ_DVD_STRUCTURE command to the drive. - -Input: - - a DVD_READ_STRUCTURE describing what information is requested - -Output: - - a DVD Layer Descriptor as defined below - ---*/ - -typedef enum DVD_STRUCTURE_FORMAT { - DvdPhysicalDescriptor, // 0x00 - DvdCopyrightDescriptor, // 0x01 - DvdDiskKeyDescriptor, // 0x02 - DvdBCADescriptor, // 0x03 - DvdManufacturerDescriptor, // 0x04 - DvdMaxDescriptor // 0x05 -} DVD_STRUCTURE_FORMAT, *PDVD_STRUCTURE_FORMAT; - -///////////////////////////////////////////////////////////// -// ALL THE FOLLOWING STRUCTURES ARE BYTE-PACKED: -#include - -typedef struct DVD_READ_STRUCTURE { - LARGE_INTEGER BlockByteOffset; - DVD_STRUCTURE_FORMAT Format; - DVD_SESSION_ID SessionId; - UCHAR LayerNumber; -} DVD_READ_STRUCTURE, *PDVD_READ_STRUCTURE; - -typedef struct _DVD_DESCRIPTOR_HEADER { - USHORT Length; - UCHAR Reserved[2]; -#if !defined(__midl) - UCHAR Data[0]; -#endif -} DVD_DESCRIPTOR_HEADER, *PDVD_DESCRIPTOR_HEADER; -C_ASSERT(sizeof(DVD_DESCRIPTOR_HEADER) == 4); - -// format 0x00 - DvdPhysicalDescriptor -typedef struct _DVD_LAYER_DESCRIPTOR { - UCHAR BookVersion : 4; // in MMC 5 : Part Version - UCHAR BookType : 4; // Disk Category - UCHAR MinimumRate : 4; // Maximum Rate - UCHAR DiskSize : 4; - UCHAR LayerType : 4; - UCHAR TrackPath : 1; - UCHAR NumberOfLayers : 2; - UCHAR Reserved1 : 1; - UCHAR TrackDensity : 4; - UCHAR LinearDensity : 4; - ULONG StartingDataSector; // 3bytes + 1 zeroed byte - ULONG EndDataSector; // 3bytes + 1 zeroed byte - ULONG EndLayerZeroSector; // 3bytes + 1 zeroed byte - UCHAR Reserved5 : 7; - UCHAR BCAFlag : 1; - // The large Media Specific field is not declared here to enable stack allocation -} DVD_LAYER_DESCRIPTOR, *PDVD_LAYER_DESCRIPTOR; -C_ASSERT(sizeof(DVD_LAYER_DESCRIPTOR) == 17); -typedef struct _DVD_FULL_LAYER_DESCRIPTOR { - DVD_LAYER_DESCRIPTOR commonHeader; - UCHAR MediaSpecific[2031]; -} DVD_FULL_LAYER_DESCRIPTOR, *PDVD_FULL_LAYER_DESCRIPTOR; -C_ASSERT(sizeof(DVD_FULL_LAYER_DESCRIPTOR) == 2048); - -// format 0x01 - DvdCopyrightDescriptor -typedef struct _DVD_COPYRIGHT_DESCRIPTOR { - UCHAR CopyrightProtectionType; - UCHAR RegionManagementInformation; - USHORT Reserved; -} DVD_COPYRIGHT_DESCRIPTOR, *PDVD_COPYRIGHT_DESCRIPTOR; -C_ASSERT(sizeof(DVD_COPYRIGHT_DESCRIPTOR) == 4); - -// format 0x02 - DvdDiskKeyDescriptor -typedef struct _DVD_DISK_KEY_DESCRIPTOR { - UCHAR DiskKeyData[2048]; -} DVD_DISK_KEY_DESCRIPTOR, *PDVD_DISK_KEY_DESCRIPTOR; -C_ASSERT(sizeof(DVD_DISK_KEY_DESCRIPTOR) == 2048); - -// format 0x03 - DvdBCADescriptor -typedef struct _DVD_BCA_DESCRIPTOR { - UCHAR BCAInformation[0]; -} DVD_BCA_DESCRIPTOR, *PDVD_BCA_DESCRIPTOR; - -// format 0x04 - DvdManufacturerDescriptor -typedef struct _DVD_MANUFACTURER_DESCRIPTOR { - UCHAR ManufacturingInformation[2048]; -} DVD_MANUFACTURER_DESCRIPTOR, *PDVD_MANUFACTURER_DESCRIPTOR; -C_ASSERT(sizeof(DVD_MANUFACTURER_DESCRIPTOR) == 2048); - -// format 0x05 - not defined in enum -typedef struct _DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR { - union { - struct { - UCHAR CopyProtectionMode : 4; - UCHAR ContentGenerationManagementSystem : 2; - UCHAR CopyProtectedSector : 1; - UCHAR CopyProtectedMaterial : 1; - } Dvdrom; - struct { - UCHAR Reserved0001 : 4; - UCHAR ContentGenerationManagementSystem : 2; - UCHAR Reserved0002 : 1; - UCHAR CopyProtectedMaterial : 1; - } DvdRecordable_Version1; - struct { - UCHAR Reserved0003; - } Dvdram; - struct { - UCHAR Reserved0004 : 2; - UCHAR ADP_TY : 2; // what is this mean? - UCHAR Reserved0005 : 4; - } DvdRecordable; - UCHAR CPR_MAI; - }; - UCHAR Reserved0[3]; -} DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR, *PDVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR; -C_ASSERT(FIELD_OFFSET(DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR, Reserved0) == 1); -C_ASSERT(sizeof(DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR) == 4); - -// format 0x06 (media ID) is unstructured in public spec -// format 0x07 (media key block) is unstructured in public spec -// format 0x08 (DVD-RAM DDS) is unstructured in public spec - -// format 0x09 - not defined in enum -// This is valid for DVD-RAM and also HD DVD-RAM -typedef struct _DVD_RAM_MEDIUM_STATUS { - UCHAR Reserved0 : 1; - UCHAR PersistentWriteProtect : 1; - UCHAR CartridgeWriteProtect : 1; - UCHAR MediaSpecificWriteInhibit : 1; - UCHAR Reserved1 : 2; - UCHAR CartridgeNotSealed : 1; - UCHAR MediaInCartridge : 1; - UCHAR DiscTypeIdentification; - UCHAR Reserved2; - UCHAR MediaSpecificWriteInhibitInformation; -} DVD_RAM_MEDIUM_STATUS, *PDVD_RAM_MEDIUM_STATUS; -C_ASSERT(sizeof(DVD_RAM_MEDIUM_STATUS) == 4); - -// format 0x0A - not defined in enum -typedef struct _DVD_RAM_SPARE_AREA_INFORMATION { - UCHAR FreePrimarySpareSectors[4]; - UCHAR FreeSupplementalSpareSectors[4]; - UCHAR AllocatedSupplementalSpareSectors[4]; -} DVD_RAM_SPARE_AREA_INFORMATION, *PDVD_RAM_SPARE_AREA_INFORMATION; -C_ASSERT(sizeof(DVD_RAM_SPARE_AREA_INFORMATION) == 12); - -// format 0x0B - not defined in enum -typedef struct _DVD_RAM_RECORDING_TYPE { - UCHAR Reserved0 : 4; - UCHAR RealTimeData : 1; - UCHAR Reserved1 : 3; - UCHAR Reserved2[3]; -} DVD_RAM_RECORDING_TYPE, *PDVD_RAM_RECORDING_TYPE; -C_ASSERT(sizeof(DVD_RAM_RECORDING_TYPE) == 4); - -// format 0x0C (RMD in last border-out) is unstructured in public spec -// format 0x0D - not defined in enum -typedef struct _DVD_RECORDING_MANAGEMENT_AREA_DATA { - UCHAR LastRecordedRMASectorNumber[4]; -#if !defined(__midl) - UCHAR RMDBytes[0]; -#endif -} DVD_RECORDING_MANAGEMENT_AREA_DATA, *PDVD_RECORDING_MANAGEMENT_AREA_DATA; -C_ASSERT(sizeof(DVD_RECORDING_MANAGEMENT_AREA_DATA) == 4); - -// format 0x0E - not define in enum -typedef struct _DVD_PRERECORDED_INFORMATION { - UCHAR FieldID_1; - UCHAR DiscApplicationCode; - UCHAR DiscPhysicalCode; - UCHAR LastAddressOfDataRecordableArea[3]; - UCHAR ExtensionCode : 4; // -R for general/authoring v2.0 - UCHAR PartVers1on : 4; // -R for general/authoring v2.0 - UCHAR Reserved0; - UCHAR FieldID_2; - UCHAR OpcSuggestedCode; - UCHAR WavelengthCode; - UCHAR WriteStrategyCode[4]; - UCHAR Reserved2; - UCHAR FieldID_3; - UCHAR ManufacturerId_3[6]; - UCHAR Reserved3; - UCHAR FieldID_4; - UCHAR ManufacturerId_4[6]; - UCHAR Reserved4; - UCHAR FieldID_5; - UCHAR ManufacturerId_5[6]; - UCHAR Reserved5; - UCHAR Reserved99[24]; -} DVD_PRERECORDED_INFORMATION, *PDVD_PRERECORDED_INFORMATION; -C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_2) == 8); -C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_3) == 16); -C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_4) == 24); -C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_5) == 32); -C_ASSERT(sizeof(DVD_PRERECORDED_INFORMATION) == 64); - -// format 0x0F - not defined in enum -typedef struct _DVD_UNIQUE_DISC_IDENTIFIER { - UCHAR Reserved0[2]; - UCHAR RandomNumber[2]; - UCHAR Year[4]; // ASCII? - UCHAR Month[2]; // ASCII? - UCHAR Day[2]; // ASCII? - UCHAR Hour[2]; // ASCII? - UCHAR Minute[2]; // ASCII? - UCHAR Second[2]; // ASCII? -} DVD_UNIQUE_DISC_IDENTIFIER, *PDVD_UNIQUE_DISC_IDENTIFIER; -C_ASSERT(sizeof(DVD_UNIQUE_DISC_IDENTIFIER) == 18); - -// format 0x10 - not define in enum - use DVD_LAYER_DESCRIPTOR structure above -// format 0x11 (ADIP information) is unstructured in public spec -// formats 0x12, 0x15 are is unstructured in public spec -// formats 0x13, 0x14, 0x16 through 0x18 are not yet defined - -// format 0x19 - not defined in enum -typedef struct _HD_DVD_R_MEDIUM_STATUS { - UCHAR ExtendedTestZone : 1; - UCHAR Reserved1 : 7; - UCHAR NumberOfRemainingRMDsInRDZ; - UCHAR NumberOfRemainingRMDsInCurrentRMZ[2]; -} HD_DVD_R_MEDIUM_STATUS, *PHD_DVD_R_MEDIUM_STATUS; -C_ASSERT(sizeof(HD_DVD_R_MEDIUM_STATUS) == 4); - -// format 0x1A (HD DVD-R - Last recorded RMD in the latest R) is unstructured in public spec -// formats 0x1B through 0x1F are not yet defined - -// format 0x20 - not define in enum -typedef struct _DVD_DUAL_LAYER_RECORDING_INFORMATION { - UCHAR Reserved0 : 7; - UCHAR Layer0SectorsImmutable : 1; - UCHAR Reserved1[3]; - UCHAR Layer0Sectors[4]; -} DVD_DUAL_LAYER_RECORDING_INFORMATION, *PDVD_DUAL_LAYER_RECORDING_INFORMATION; - -// format 0x21 - not define in enum -typedef struct _DVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS { - UCHAR Reserved0 : 7; - UCHAR InitStatus : 1; - UCHAR Reserved1[3]; - UCHAR ShiftedMiddleAreaStartAddress[4]; -} DVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS, *PDVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS; - -// format 0x22 - not define in enum -typedef struct _DVD_DUAL_LAYER_JUMP_INTERVAL_SIZE { - UCHAR Reserved1[4]; - UCHAR JumpIntervalSize[4]; -} DVD_DUAL_LAYER_JUMP_INTERVAL_SIZE, *PDVD_DUAL_LAYER_JUMP_INTERVAL_SIZE; - -// format 0x23 - not define in enum -typedef struct _DVD_DUAL_LAYER_MANUAL_LAYER_JUMP { - UCHAR Reserved1[4]; - UCHAR ManualJumpLayerAddress[4]; -} DVD_DUAL_LAYER_MANUAL_LAYER_JUMP, *PDVD_DUAL_LAYER_MANUAL_LAYER_JUMP; - -// format 0x24 - not define in enum -typedef struct _DVD_DUAL_LAYER_REMAPPING_INFORMATION { - UCHAR Reserved1[4]; - UCHAR RemappingAddress[4]; -} DVD_DUAL_LAYER_REMAPPING_INFORMATION, *PDVD_DUAL_LAYER_REMAPPING_INFORMATION; - -// formats 0x25 through 0x2F are not yet defined - -// format 0x30 - not defined in enum (common header) -typedef struct _DVD_DISC_CONTROL_BLOCK_HEADER { - UCHAR ContentDescriptor[4]; - union { - struct { - UCHAR ReservedDoNotUse_UseAsByteInstead_0[3]; - UCHAR RecordingWithinTheUserDataArea : 1; - UCHAR ReadingDiscControlBlocks : 1; - UCHAR FormattingTheMedium : 1; - UCHAR ModificationOfThisDiscControlBlock : 1; - UCHAR ReservedDoNotUse_UseAsByteInstead_1 : 4; - }; - UCHAR AsByte[4]; - } ProhibitedActions; - UCHAR VendorId[32]; // actually "non-specified" data - // UCHAR DCBData[32728]; -} DVD_DISC_CONTROL_BLOCK_HEADER, *PDVD_DISC_CONTROL_BLOCK_HEADER; -C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_HEADER) == 40); - -// publicly defined DCB types -typedef enum _DISC_CONTROL_BLOCK_TYPE { - FormattingDiscControlBlock = 0x46444300, // 'FDC\0' - WriteInhibitDiscControlBlock = 0x57444300, // 'WDC\0' - SessionInfoDiscControlBlock = 0x53444300, // 'SDC\0' - DiscControlBlockList = 0xFFFFFFFF -} DISC_CONTROL_BLOCK_TYPE, *PDISC_CONTROL_BLOCK_TYPE; - -// format 0x30 - not defined in enum -- Format DCB, not in MMC. - -// format 0x30 - not defined in enum -- Write Inhibit DCB -typedef struct _DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT { - DVD_DISC_CONTROL_BLOCK_HEADER header; - UCHAR UpdateCount[4]; - union { - struct { - UCHAR ReservedDoNotUse_UseAsByteInstead_0[3]; - UCHAR WriteProtectStatus : 2; - UCHAR ReservedDoNotUse_UseAsByteInstead_1 : 5; - UCHAR UpdateRequiresPassword : 1; - }; - UCHAR AsByte[4]; - } WriteProtectActions; - UCHAR Reserved0[16]; - UCHAR UpdatePassword[32]; - UCHAR Reserved1[32672]; -} DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT, *PDVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT; -C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT) == (16*2048)); - -// format 0x30 - not defined in enum - Session DCB -typedef struct _DVD_DISC_CONTROL_BLOCK_SESSION_ITEM { - UCHAR AsByte[16]; // not publicly defined? -} DVD_DISC_CONTROL_BLOCK_SESSION_ITEM, *PDVD_DISC_CONTROL_BLOCK_SESSION_ITEM; -typedef struct _DVD_DISC_CONTROL_BLOCK_SESSION { - DVD_DISC_CONTROL_BLOCK_HEADER header; - UCHAR SessionNumber[2]; - UCHAR Reserved0[22]; - UCHAR DiscID[32]; - UCHAR Reserved1[32]; - DVD_DISC_CONTROL_BLOCK_SESSION_ITEM SessionItem[504]; - UCHAR Reserved2[24576]; // 3 Repetitions of bytes 0 through 8191 -} DVD_DISC_CONTROL_BLOCK_SESSION, *PDVD_DISC_CONTROL_BLOCK_SESSION; -C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_SESSION) == ((8*1024) * 4)); - -// format 0x30 - not defined in enum - DCB list -typedef struct _DVD_DISC_CONTROL_BLOCK_LIST_DCB { - UCHAR DcbIdentifier[4]; -} DVD_DISC_CONTROL_BLOCK_LIST_DCB, *PDVD_DISC_CONTROL_BLOCK_LIST_DCB; -typedef struct _DVD_DISC_CONTROL_BLOCK_LIST { - DVD_DISC_CONTROL_BLOCK_HEADER header; - UCHAR Reserved0; - UCHAR ReadabldDCBs; - UCHAR Reserved1; - UCHAR WritableDCBs; -#if !defined(__midl) - DVD_DISC_CONTROL_BLOCK_LIST_DCB Dcbs[0]; -#endif -} DVD_DISC_CONTROL_BLOCK_LIST, *PDVD_DISC_CONTROL_BLOCK_LIST; -C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_LIST) == 44); - -// format 0x31 (MTA ECC Block) is unstructured in public spec -// formats 0x32 through 0xBF are not yet defined - -// format 0xC0 - not defined in enum -typedef struct _DVD_WRITE_PROTECTION_STATUS { - UCHAR SoftwareWriteProtectUntilPowerdown : 1; - UCHAR MediaPersistentWriteProtect : 1; - UCHAR CartridgeWriteProtect : 1; - UCHAR MediaSpecificWriteProtect : 1; - UCHAR Reserved0 : 4; - UCHAR Reserved1[3]; -} DVD_WRITE_PROTECTION_STATUS, *PDVD_WRITE_PROTECTION_STATUS; -C_ASSERT(sizeof(DVD_WRITE_PROTECTION_STATUS) == 4); - -// formats 0xC1 through 0x7F are not yet defined -// format 0x80 (AACS volume identifier) is unstructured in public spec -// format 0x81 (Pre-Recorded AACS media serial number) is unstructured in public spec -// format 0x82 (AACS media identifier) is unstructured in public spec -// format 0x83 (AACS media key block) is unstructured in public spec -// formats 0x84 through 0x8F are not yet defined - -// format 0x90 - not defined in enum -typedef struct _DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE { - UCHAR TypeCodeOfFormatLayer[2]; -} DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS, *PDVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS; -typedef struct _DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS { - UCHAR NumberOfRecognizedFormatLayers; - UCHAR OnlineFormatlayer : 2; - UCHAR Reserved1 : 2; - UCHAR DefaultFormatLayer : 2; - UCHAR Reserved2 : 2; - // DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE TypeCodes[0]; -} DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE, *PDVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE; -C_ASSERT(sizeof(DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE) == 2); - -// formats 0x91 through 0xFE are not yet defined - -// format 0xFF - not defined in enum -typedef struct _DVD_STRUCTURE_LIST_ENTRY { - UCHAR FormatCode; - UCHAR Reserved0 : 6; - UCHAR Readable : 1; - UCHAR Sendable : 1; - UCHAR FormatLength[2]; -} DVD_STRUCTURE_LIST_ENTRY, *PDVD_STRUCTURE_LIST_ENTRY; -C_ASSERT(sizeof(DVD_STRUCTURE_LIST_ENTRY) == 4); - -// BD Disc Structures - -// format 0x00 (BD Disc Information) is unstructured in public spec -// format 0x08 (BD Disc Definition Structure) is unstructured in public spec -// format 0x09 (BD Cartridge Status) is identical to DVD_RAM_MEDIUM_STATUS but -// only CartridgeWriteProtect, CartridgeNotSealed and MediaInCartridge are -// valid. Other fields are reserved. - -// format 0x09 (BD Spare Area Information) - not defined in enum -typedef struct _DVD_BD_SPARE_AREA_INFORMATION { - UCHAR Reserved1[4]; - UCHAR NumberOfFreeSpareBlocks[4]; - UCHAR NumberOfAllocatedSpareBlocks[4]; -} DVD_BD_SPARE_AREA_INFORMATION, *PDVD_BD_SPARE_AREA_INFORMATION; -C_ASSERT(sizeof(DVD_BD_SPARE_AREA_INFORMATION) == 12); - -// format 0x12 (BD Raw Defect List). DFL is not fully defined in public spec - -// format 0x30 (BD Physical Access Control). -typedef struct _BD_PAC_HEADER { - UCHAR PACId[3]; - UCHAR PACFormatNumber; - UCHAR PACUpdateCount[4]; - UCHAR UnknownPACRules[4]; - UCHAR UnkownPACEntireDiscFlag; - UCHAR Reserved1[2]; - UCHAR NumberOfSegments; - UCHAR Segments[8][32]; - UCHAR Reserved2[112]; -} BD_PAC_HEADER, *PBD_PAC_HEADER; -C_ASSERT(sizeof(BD_PAC_HEADER) == 384); - -// Primary PAC is unstructured in public spec - -// Disc Write Protect PAC -typedef struct _BD_DISC_WRITE_PROTECT_PAC { - BD_PAC_HEADER Header; - UCHAR KnownPACEntireDiscFlags; - UCHAR Reserved1[3]; - UCHAR WriteProtectControlByte; - UCHAR Reserved2[7]; - UCHAR WriteProtectPassword[32]; -} BD_DISC_WRITE_PROTECT_PAC, *PBD_DISC_WRITE_PROTECT_PAC; -C_ASSERT(sizeof(BD_DISC_WRITE_PROTECT_PAC) == 428); - - -typedef struct _DVD_RPC_KEY { - UCHAR UserResetsAvailable:3; - UCHAR ManufacturerResetsAvailable:3; - UCHAR TypeCode:2; - UCHAR RegionMask; - UCHAR RpcScheme; - UCHAR Reserved02; -} DVD_RPC_KEY, * PDVD_RPC_KEY; -C_ASSERT(sizeof(DVD_RPC_KEY) == 4); - -typedef struct _DVD_SET_RPC_KEY { - UCHAR PreferredDriveRegionCode; - UCHAR Reserved[3]; -} DVD_SET_RPC_KEY, * PDVD_SET_RPC_KEY; -C_ASSERT(sizeof(DVD_SET_RPC_KEY) == 4); - -typedef struct _DVD_ASF { // Authentication Success Flag - UCHAR Reserved0[3]; - UCHAR SuccessFlag:1; - UCHAR Reserved1:7; -} DVD_ASF, * PDVD_ASF; -C_ASSERT(sizeof(DVD_ASF) == 4); - -#if 0 -typedef struct _DVD_REGION { - UCHAR CopySystem; - UCHAR RegionData; // current media region (not playable when set) - UCHAR SystemRegion; // current drive region (playable when set) - UCHAR ResetCount; // number of resets available -} DVD_REGION, *PDVD_REGION; -C_ASSERT(sizeof(DVD_REGION) == 4); -#endif - -// ALL THE ABOVE STRUCTURES ARE BYTE-PACKED: -///////////////////////////////////////////////////////////// -#include - - -#ifdef __cplusplus -} -#endif - - -///////////////////////////////////////////////////////////// -// AACS-related structures -// (mostly opaque data, but useful for allocation) - -// The AACS layer number refers to the layer of the disc a structure -// is read from. This can only be a single byte in the CDB, so limit -// the value to 0..255. -typedef __range(0,255) ULONG AACS_LAYER_NUMBER, *PAACS_LAYER_NUMBER; -typedef __range(0,255) const ULONG CAACS_LAYER_NUMBER, *PCAACS_LAYER_NUMBER; - - -// The AACS Certificate (opaque data structure) is used to validate -// the host to the logical unit, as well as to validate the logical -// unit to the host. -typedef struct _AACS_CERTIFICATE { - UCHAR Nonce[20]; - UCHAR Certificate[92]; -} AACS_CERTIFICATE, *PAACS_CERTIFICATE; -typedef const AACS_CERTIFICATE CAACS_CERTIFICATE; -typedef const AACS_CERTIFICATE *PCAACS_CERTIFICATE; -C_ASSERT(sizeof(AACS_CERTIFICATE) == 112); - -// The AACS challenge key (opaque data structure) is used to setup -// a shared bus key for AACS-protected structure transfer. -typedef struct _AACS_CHALLENGE_KEY { - UCHAR EllipticCurvePoint[40]; - UCHAR Signature[40]; -} AACS_CHALLENGE_KEY, *PAACS_CHALLENGE_KEY; -typedef const AACS_CHALLENGE_KEY CAACS_CHALLENGE_KEY; -typedef const AACS_CHALLENGE_KEY *PCAACS_CHALLENGE_KEY; -C_ASSERT(sizeof(AACS_CHALLENGE_KEY) == 80); - -// The VolumeID is one of the unique identifiers on AACS protected media -typedef struct _AACS_VOLUME_ID { - UCHAR VolumeID[16]; - UCHAR MAC[16]; // MessageAuthenticationCode -} AACS_VOLUME_ID, *PAACS_VOLUME_ID; -typedef const AACS_VOLUME_ID CAACS_VOLUME_ID; -typedef const AACS_VOLUME_ID *PCAACS_VOLUME_ID; -C_ASSERT(sizeof(AACS_VOLUME_ID) == 32); - -// The prerecorded Serial Number is one of the unique identifiers on AACS protected media -typedef struct _AACS_SERIAL_NUMBER { - UCHAR PrerecordedSerialNumber[16]; - UCHAR MAC[16]; // MessageAuthenticationCode -} AACS_SERIAL_NUMBER, *PAACS_SERIAL_NUMBER; -typedef const AACS_SERIAL_NUMBER CAACS_SERIAL_NUMBER; -typedef const AACS_SERIAL_NUMBER *PCAACS_SERIAL_NUMBER; -C_ASSERT(sizeof(AACS_SERIAL_NUMBER) == 32); - -// The MediaID is one of the unique identifiers on AACS protected media -typedef struct _AACS_MEDIA_ID { - UCHAR MediaID[16]; - UCHAR MAC[16]; // MessageAuthenticationCode -} AACS_MEDIA_ID, *PAACS_MEDIA_ID; -typedef const AACS_MEDIA_ID CAACS_MEDIA_ID; -typedef const AACS_MEDIA_ID *PCAACS_MEDIA_ID; -C_ASSERT(sizeof(AACS_MEDIA_ID) == 32); - -// When sending a certificate or challenge key, need to wrap -// the data structure with a DVD_SESSION_ID. -typedef struct _AACS_SEND_CERTIFICATE { - DVD_SESSION_ID SessionId; - AACS_CERTIFICATE Certificate; -} AACS_SEND_CERTIFICATE, *PAACS_SEND_CERTIFICATE; -typedef const AACS_SEND_CERTIFICATE CAACS_SEND_CERTIFICATE; -typedef const AACS_SEND_CERTIFICATE *PCAACS_SEND_CERTIFICATE; - -// When sending a certificate or challenge key, need to wrap -// the data structure with a DVD_SESSION_ID. -typedef struct _AACS_SEND_CHALLENGE_KEY { - DVD_SESSION_ID SessionId; - AACS_CHALLENGE_KEY ChallengeKey; -} AACS_SEND_CHALLENGE_KEY, *PAACS_SEND_CHALLENGE_KEY; -typedef const AACS_SEND_CHALLENGE_KEY CAACS_SEND_CHALLENGE_KEY; -typedef const AACS_SEND_CHALLENGE_KEY *PCAACS_SEND_CHALLENGE_KEY; - - -// The AACS binding nonce (opaque data structure) is used to -// protect individual content. -typedef struct _AACS_BINDING_NONCE { - UCHAR BindingNonce[16]; - UCHAR MAC[16]; // MessageAuthenticationCode -} AACS_BINDING_NONCE, *PAACS_BINDING_NONCE; -typedef const AACS_BINDING_NONCE CAACS_BINDING_NONCE; -typedef const AACS_BINDING_NONCE *PCAACS_BINDING_NONCE; -C_ASSERT(sizeof(AACS_BINDING_NONCE) == 32); - - -// This structure is sent when reading a binding nonce -// either from the medium or when having the logical unit -// generate a new binding nonce for a set of sectors -// NOTE: This structure must be identically aligned for 32/64 bit builds -// -typedef struct _AACS_READ_BINDING_NONCE { - DVD_SESSION_ID SessionId; - __range(0,255) ULONG NumberOfSectors; // spec only provides one byte - ULONGLONG StartLba; - - // 32-bit HANDLE is 32 bits, 64-bit HANDLE is 64 bits - union { - HANDLE Handle; - ULONGLONG ForceStructureLengthToMatch64bit; - }; -} AACS_READ_BINDING_NONCE, *PAACS_READ_BINDING_NONCE; - -///////////////////////////////////////////////////////////// - -#pragma warning(pop) -#endif // _NTDDCDVD_ - -// end_winioctl - - +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddcdvd.h + +Abstract: + + This module contains structures and definitions + associated with DVD ioctls. + + This module is used in conjunction with ntddcdrm.h which contains the + cdrom specific ioctls which will work on CDVD drives + + +--*/ + +// begin_winioctl + +#ifndef _NTDDCDVD_ +#define _NTDDCDVD_ +#pragma warning(push) +#pragma warning(disable:4200) // zero-sized array +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable:4214) // bitfield other than int +#if defined(__INTEL_COMPILER) +#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero +#endif + +#if _MSC_VER > 1000 +#pragma once +#endif + +// +// NtDeviceIoControlFile IoControlCode values for this device. +// +// Warning: Remember that the low two bits of the code specify how the +// buffers are passed to the driver! +// + +#define IOCTL_DVD_BASE FILE_DEVICE_DVD + +// +// CDVD Device Control Functions +// +// Warning: Ioctls from 200 through 300 are used for the old common class +// driver ioctls and should not be used for device specific functionality +// + +// +// CSS-related IOCTLs +// + +#define IOCTL_DVD_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_READ_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_SEND_KEY CTL_CODE(IOCTL_DVD_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x0403, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_SET_READ_AHEAD CTL_CODE(IOCTL_DVD_BASE, 0x0404, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_GET_REGION CTL_CODE(IOCTL_DVD_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DVD_SEND_KEY2 CTL_CODE(IOCTL_DVD_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// AACS-related IOCTLs +// +#define IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE CTL_CODE(IOCTL_DVD_BASE, 0x430, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_MEDIA_KEY_BLOCK CTL_CODE(IOCTL_DVD_BASE, 0x431, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_START_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x432, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_END_SESSION CTL_CODE(IOCTL_DVD_BASE, 0x433, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_SEND_CERTIFICATE CTL_CODE(IOCTL_DVD_BASE, 0x434, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_GET_CERTIFICATE CTL_CODE(IOCTL_DVD_BASE, 0x435, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_GET_CHALLENGE_KEY CTL_CODE(IOCTL_DVD_BASE, 0x436, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_SEND_CHALLENGE_KEY CTL_CODE(IOCTL_DVD_BASE, 0x437, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_VOLUME_ID CTL_CODE(IOCTL_DVD_BASE, 0x438, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_SERIAL_NUMBER CTL_CODE(IOCTL_DVD_BASE, 0x439, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_MEDIA_ID CTL_CODE(IOCTL_DVD_BASE, 0x43A, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_READ_BINDING_NONCE CTL_CODE(IOCTL_DVD_BASE, 0x43B, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_AACS_GENERATE_BINDING_NONCE CTL_CODE(IOCTL_DVD_BASE, 0x43C, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// DVD Structure queries +// + +#define IOCTL_DVD_READ_STRUCTURE CTL_CODE(IOCTL_DVD_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// The following file contains the IOCTL_STORAGE class ioctl definitions +// + +#define IOCTL_STORAGE_SET_READ_AHEAD CTL_CODE(IOCTL_STORAGE_BASE, 0x0100, METHOD_BUFFERED, FILE_READ_ACCESS) + +// end_winioctl + +#include "ntddstor.h" + +// begin_winioctl + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum { + DvdChallengeKey = 0x01, + DvdBusKey1, + DvdBusKey2, + DvdTitleKey, + DvdAsf, + DvdSetRpcKey = 0x6, + DvdGetRpcKey = 0x8, + DvdDiskKey = 0x80, + DvdInvalidateAGID = 0x3f +} DVD_KEY_TYPE; + +typedef __typefix(LONG) __range(-1,3) ULONG DVD_SESSION_ID, *PDVD_SESSION_ID; + +#include +typedef struct _DVD_COPY_PROTECT_KEY { + ULONG KeyLength; + DVD_SESSION_ID SessionId; + DVD_KEY_TYPE KeyType; + ULONG KeyFlags; + union { + HANDLE FileHandle; + LARGE_INTEGER TitleOffset; + } Parameters; + UCHAR KeyData[0]; +} DVD_COPY_PROTECT_KEY, *PDVD_COPY_PROTECT_KEY; +#include + +// +// Predefined (Mt. Fuji) key sizes +// Add sizeof(DVD_COPY_PROTECT_KEY) to get allocation size for +// the full key structure +// + +#define DVD_CHALLENGE_KEY_LENGTH (12 + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_BUS_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_TITLE_KEY_LENGTH (8 + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_DISK_KEY_LENGTH (2048 + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_RPC_KEY_LENGTH (sizeof(DVD_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_SET_RPC_KEY_LENGTH (sizeof(DVD_SET_RPC_KEY) + sizeof(DVD_COPY_PROTECT_KEY)) +#define DVD_ASF_LENGTH (sizeof(DVD_ASF) + sizeof(DVD_COPY_PROTECT_KEY)) + +// +// Used with IOCTL_DVD_END_SESSION to end all DVD sessions at once +// + +#define DVD_END_ALL_SESSIONS ((DVD_SESSION_ID) 0xffffffff) + +// +// CGMS Copy Protection Flags +// + +#define DVD_CGMS_RESERVED_MASK 0x00000078 + +#define DVD_CGMS_COPY_PROTECT_MASK 0x00000018 +#define DVD_CGMS_COPY_PERMITTED 0x00000000 +#define DVD_CGMS_COPY_ONCE 0x00000010 +#define DVD_CGMS_NO_COPY 0x00000018 + +#define DVD_COPYRIGHT_MASK 0x00000040 +#define DVD_NOT_COPYRIGHTED 0x00000000 +#define DVD_COPYRIGHTED 0x00000040 + +#define DVD_SECTOR_PROTECT_MASK 0x00000020 +#define DVD_SECTOR_NOT_PROTECTED 0x00000000 +#define DVD_SECTOR_PROTECTED 0x00000020 + +/*++ + +IOCTL_STORAGE_SET_READ_AHEAD + +Requests that the storage device skip to TargetAddress once it has run across +TriggerAddress during the course of it's read-ahead caching operations. + +Input: + + a STORAGE_SET_READ_AHEAD structure which contains: + * the trigger address + * the target address + +Output: + + none + +--*/ + +#include +typedef struct _STORAGE_SET_READ_AHEAD { + LARGE_INTEGER TriggerAddress; + LARGE_INTEGER TargetAddress; +} STORAGE_SET_READ_AHEAD, *PSTORAGE_SET_READ_AHEAD; +#include + +/*++ + +IOCTL_DVD_READ_STRUCTURE + +Issues a READ_DVD_STRUCTURE command to the drive. + +Input: + + a DVD_READ_STRUCTURE describing what information is requested + +Output: + + a DVD Layer Descriptor as defined below + +--*/ + +typedef enum DVD_STRUCTURE_FORMAT { + DvdPhysicalDescriptor, // 0x00 + DvdCopyrightDescriptor, // 0x01 + DvdDiskKeyDescriptor, // 0x02 + DvdBCADescriptor, // 0x03 + DvdManufacturerDescriptor, // 0x04 + DvdMaxDescriptor // 0x05 +} DVD_STRUCTURE_FORMAT, *PDVD_STRUCTURE_FORMAT; + +///////////////////////////////////////////////////////////// +// ALL THE FOLLOWING STRUCTURES ARE BYTE-PACKED: +#include + +typedef struct DVD_READ_STRUCTURE { + LARGE_INTEGER BlockByteOffset; + DVD_STRUCTURE_FORMAT Format; + DVD_SESSION_ID SessionId; + UCHAR LayerNumber; +} DVD_READ_STRUCTURE, *PDVD_READ_STRUCTURE; + +typedef struct _DVD_DESCRIPTOR_HEADER { + USHORT Length; + UCHAR Reserved[2]; +#if !defined(__midl) + UCHAR Data[0]; +#endif +} DVD_DESCRIPTOR_HEADER, *PDVD_DESCRIPTOR_HEADER; +C_ASSERT(sizeof(DVD_DESCRIPTOR_HEADER) == 4); + +// format 0x00 - DvdPhysicalDescriptor +typedef struct _DVD_LAYER_DESCRIPTOR { + UCHAR BookVersion : 4; // in MMC 5 : Part Version + UCHAR BookType : 4; // Disk Category + UCHAR MinimumRate : 4; // Maximum Rate + UCHAR DiskSize : 4; + UCHAR LayerType : 4; + UCHAR TrackPath : 1; + UCHAR NumberOfLayers : 2; + UCHAR Reserved1 : 1; + UCHAR TrackDensity : 4; + UCHAR LinearDensity : 4; + ULONG StartingDataSector; // 3bytes + 1 zeroed byte + ULONG EndDataSector; // 3bytes + 1 zeroed byte + ULONG EndLayerZeroSector; // 3bytes + 1 zeroed byte + UCHAR Reserved5 : 7; + UCHAR BCAFlag : 1; + // The large Media Specific field is not declared here to enable stack allocation +} DVD_LAYER_DESCRIPTOR, *PDVD_LAYER_DESCRIPTOR; +C_ASSERT(sizeof(DVD_LAYER_DESCRIPTOR) == 17); +typedef struct _DVD_FULL_LAYER_DESCRIPTOR { + DVD_LAYER_DESCRIPTOR commonHeader; + UCHAR MediaSpecific[2031]; +} DVD_FULL_LAYER_DESCRIPTOR, *PDVD_FULL_LAYER_DESCRIPTOR; +C_ASSERT(sizeof(DVD_FULL_LAYER_DESCRIPTOR) == 2048); + +// format 0x01 - DvdCopyrightDescriptor +typedef struct _DVD_COPYRIGHT_DESCRIPTOR { + UCHAR CopyrightProtectionType; + UCHAR RegionManagementInformation; + USHORT Reserved; +} DVD_COPYRIGHT_DESCRIPTOR, *PDVD_COPYRIGHT_DESCRIPTOR; +C_ASSERT(sizeof(DVD_COPYRIGHT_DESCRIPTOR) == 4); + +// format 0x02 - DvdDiskKeyDescriptor +typedef struct _DVD_DISK_KEY_DESCRIPTOR { + UCHAR DiskKeyData[2048]; +} DVD_DISK_KEY_DESCRIPTOR, *PDVD_DISK_KEY_DESCRIPTOR; +C_ASSERT(sizeof(DVD_DISK_KEY_DESCRIPTOR) == 2048); + +// format 0x03 - DvdBCADescriptor +typedef struct _DVD_BCA_DESCRIPTOR { + UCHAR BCAInformation[0]; +} DVD_BCA_DESCRIPTOR, *PDVD_BCA_DESCRIPTOR; + +// format 0x04 - DvdManufacturerDescriptor +typedef struct _DVD_MANUFACTURER_DESCRIPTOR { + UCHAR ManufacturingInformation[2048]; +} DVD_MANUFACTURER_DESCRIPTOR, *PDVD_MANUFACTURER_DESCRIPTOR; +C_ASSERT(sizeof(DVD_MANUFACTURER_DESCRIPTOR) == 2048); + +// format 0x05 - not defined in enum +typedef struct _DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR { + union { + struct { + UCHAR CopyProtectionMode : 4; + UCHAR ContentGenerationManagementSystem : 2; + UCHAR CopyProtectedSector : 1; + UCHAR CopyProtectedMaterial : 1; + } Dvdrom; + struct { + UCHAR Reserved0001 : 4; + UCHAR ContentGenerationManagementSystem : 2; + UCHAR Reserved0002 : 1; + UCHAR CopyProtectedMaterial : 1; + } DvdRecordable_Version1; + struct { + UCHAR Reserved0003; + } Dvdram; + struct { + UCHAR Reserved0004 : 2; + UCHAR ADP_TY : 2; // what is this mean? + UCHAR Reserved0005 : 4; + } DvdRecordable; + UCHAR CPR_MAI; + }; + UCHAR Reserved0[3]; +} DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR, *PDVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR; +C_ASSERT(FIELD_OFFSET(DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR, Reserved0) == 1); +C_ASSERT(sizeof(DVD_COPYRIGHT_MANAGEMENT_DESCRIPTOR) == 4); + +// format 0x06 (media ID) is unstructured in public spec +// format 0x07 (media key block) is unstructured in public spec +// format 0x08 (DVD-RAM DDS) is unstructured in public spec + +// format 0x09 - not defined in enum +// This is valid for DVD-RAM and also HD DVD-RAM +typedef struct _DVD_RAM_MEDIUM_STATUS { + UCHAR Reserved0 : 1; + UCHAR PersistentWriteProtect : 1; + UCHAR CartridgeWriteProtect : 1; + UCHAR MediaSpecificWriteInhibit : 1; + UCHAR Reserved1 : 2; + UCHAR CartridgeNotSealed : 1; + UCHAR MediaInCartridge : 1; + UCHAR DiscTypeIdentification; + UCHAR Reserved2; + UCHAR MediaSpecificWriteInhibitInformation; +} DVD_RAM_MEDIUM_STATUS, *PDVD_RAM_MEDIUM_STATUS; +C_ASSERT(sizeof(DVD_RAM_MEDIUM_STATUS) == 4); + +// format 0x0A - not defined in enum +typedef struct _DVD_RAM_SPARE_AREA_INFORMATION { + UCHAR FreePrimarySpareSectors[4]; + UCHAR FreeSupplementalSpareSectors[4]; + UCHAR AllocatedSupplementalSpareSectors[4]; +} DVD_RAM_SPARE_AREA_INFORMATION, *PDVD_RAM_SPARE_AREA_INFORMATION; +C_ASSERT(sizeof(DVD_RAM_SPARE_AREA_INFORMATION) == 12); + +// format 0x0B - not defined in enum +typedef struct _DVD_RAM_RECORDING_TYPE { + UCHAR Reserved0 : 4; + UCHAR RealTimeData : 1; + UCHAR Reserved1 : 3; + UCHAR Reserved2[3]; +} DVD_RAM_RECORDING_TYPE, *PDVD_RAM_RECORDING_TYPE; +C_ASSERT(sizeof(DVD_RAM_RECORDING_TYPE) == 4); + +// format 0x0C (RMD in last border-out) is unstructured in public spec +// format 0x0D - not defined in enum +typedef struct _DVD_RECORDING_MANAGEMENT_AREA_DATA { + UCHAR LastRecordedRMASectorNumber[4]; +#if !defined(__midl) + UCHAR RMDBytes[0]; +#endif +} DVD_RECORDING_MANAGEMENT_AREA_DATA, *PDVD_RECORDING_MANAGEMENT_AREA_DATA; +C_ASSERT(sizeof(DVD_RECORDING_MANAGEMENT_AREA_DATA) == 4); + +// format 0x0E - not define in enum +typedef struct _DVD_PRERECORDED_INFORMATION { + UCHAR FieldID_1; + UCHAR DiscApplicationCode; + UCHAR DiscPhysicalCode; + UCHAR LastAddressOfDataRecordableArea[3]; + UCHAR ExtensionCode : 4; // -R for general/authoring v2.0 + UCHAR PartVers1on : 4; // -R for general/authoring v2.0 + UCHAR Reserved0; + UCHAR FieldID_2; + UCHAR OpcSuggestedCode; + UCHAR WavelengthCode; + UCHAR WriteStrategyCode[4]; + UCHAR Reserved2; + UCHAR FieldID_3; + UCHAR ManufacturerId_3[6]; + UCHAR Reserved3; + UCHAR FieldID_4; + UCHAR ManufacturerId_4[6]; + UCHAR Reserved4; + UCHAR FieldID_5; + UCHAR ManufacturerId_5[6]; + UCHAR Reserved5; + UCHAR Reserved99[24]; +} DVD_PRERECORDED_INFORMATION, *PDVD_PRERECORDED_INFORMATION; +C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_2) == 8); +C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_3) == 16); +C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_4) == 24); +C_ASSERT(FIELD_OFFSET(DVD_PRERECORDED_INFORMATION, FieldID_5) == 32); +C_ASSERT(sizeof(DVD_PRERECORDED_INFORMATION) == 64); + +// format 0x0F - not defined in enum +typedef struct _DVD_UNIQUE_DISC_IDENTIFIER { + UCHAR Reserved0[2]; + UCHAR RandomNumber[2]; + UCHAR Year[4]; // ASCII? + UCHAR Month[2]; // ASCII? + UCHAR Day[2]; // ASCII? + UCHAR Hour[2]; // ASCII? + UCHAR Minute[2]; // ASCII? + UCHAR Second[2]; // ASCII? +} DVD_UNIQUE_DISC_IDENTIFIER, *PDVD_UNIQUE_DISC_IDENTIFIER; +C_ASSERT(sizeof(DVD_UNIQUE_DISC_IDENTIFIER) == 18); + +// format 0x10 - not define in enum - use DVD_LAYER_DESCRIPTOR structure above +// format 0x11 (ADIP information) is unstructured in public spec +// formats 0x12, 0x15 are is unstructured in public spec +// formats 0x13, 0x14, 0x16 through 0x18 are not yet defined + +// format 0x19 - not defined in enum +typedef struct _HD_DVD_R_MEDIUM_STATUS { + UCHAR ExtendedTestZone : 1; + UCHAR Reserved1 : 7; + UCHAR NumberOfRemainingRMDsInRDZ; + UCHAR NumberOfRemainingRMDsInCurrentRMZ[2]; +} HD_DVD_R_MEDIUM_STATUS, *PHD_DVD_R_MEDIUM_STATUS; +C_ASSERT(sizeof(HD_DVD_R_MEDIUM_STATUS) == 4); + +// format 0x1A (HD DVD-R - Last recorded RMD in the latest R) is unstructured in public spec +// formats 0x1B through 0x1F are not yet defined + +// format 0x20 - not define in enum +typedef struct _DVD_DUAL_LAYER_RECORDING_INFORMATION { + UCHAR Reserved0 : 7; + UCHAR Layer0SectorsImmutable : 1; + UCHAR Reserved1[3]; + UCHAR Layer0Sectors[4]; +} DVD_DUAL_LAYER_RECORDING_INFORMATION, *PDVD_DUAL_LAYER_RECORDING_INFORMATION; + +// format 0x21 - not define in enum +typedef struct _DVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS { + UCHAR Reserved0 : 7; + UCHAR InitStatus : 1; + UCHAR Reserved1[3]; + UCHAR ShiftedMiddleAreaStartAddress[4]; +} DVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS, *PDVD_DUAL_LAYER_MIDDLE_ZONE_START_ADDRESS; + +// format 0x22 - not define in enum +typedef struct _DVD_DUAL_LAYER_JUMP_INTERVAL_SIZE { + UCHAR Reserved1[4]; + UCHAR JumpIntervalSize[4]; +} DVD_DUAL_LAYER_JUMP_INTERVAL_SIZE, *PDVD_DUAL_LAYER_JUMP_INTERVAL_SIZE; + +// format 0x23 - not define in enum +typedef struct _DVD_DUAL_LAYER_MANUAL_LAYER_JUMP { + UCHAR Reserved1[4]; + UCHAR ManualJumpLayerAddress[4]; +} DVD_DUAL_LAYER_MANUAL_LAYER_JUMP, *PDVD_DUAL_LAYER_MANUAL_LAYER_JUMP; + +// format 0x24 - not define in enum +typedef struct _DVD_DUAL_LAYER_REMAPPING_INFORMATION { + UCHAR Reserved1[4]; + UCHAR RemappingAddress[4]; +} DVD_DUAL_LAYER_REMAPPING_INFORMATION, *PDVD_DUAL_LAYER_REMAPPING_INFORMATION; + +// formats 0x25 through 0x2F are not yet defined + +// format 0x30 - not defined in enum (common header) +typedef struct _DVD_DISC_CONTROL_BLOCK_HEADER { + UCHAR ContentDescriptor[4]; + union { + struct { + UCHAR ReservedDoNotUse_UseAsByteInstead_0[3]; + UCHAR RecordingWithinTheUserDataArea : 1; + UCHAR ReadingDiscControlBlocks : 1; + UCHAR FormattingTheMedium : 1; + UCHAR ModificationOfThisDiscControlBlock : 1; + UCHAR ReservedDoNotUse_UseAsByteInstead_1 : 4; + }; + UCHAR AsByte[4]; + } ProhibitedActions; + UCHAR VendorId[32]; // actually "non-specified" data + // UCHAR DCBData[32728]; +} DVD_DISC_CONTROL_BLOCK_HEADER, *PDVD_DISC_CONTROL_BLOCK_HEADER; +C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_HEADER) == 40); + +// publicly defined DCB types +typedef enum _DISC_CONTROL_BLOCK_TYPE { + FormattingDiscControlBlock = 0x46444300, // 'FDC\0' + WriteInhibitDiscControlBlock = 0x57444300, // 'WDC\0' + SessionInfoDiscControlBlock = 0x53444300, // 'SDC\0' + DiscControlBlockList = 0xFFFFFFFF +} DISC_CONTROL_BLOCK_TYPE, *PDISC_CONTROL_BLOCK_TYPE; + +// format 0x30 - not defined in enum -- Format DCB, not in MMC. + +// format 0x30 - not defined in enum -- Write Inhibit DCB +typedef struct _DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT { + DVD_DISC_CONTROL_BLOCK_HEADER header; + UCHAR UpdateCount[4]; + union { + struct { + UCHAR ReservedDoNotUse_UseAsByteInstead_0[3]; + UCHAR WriteProtectStatus : 2; + UCHAR ReservedDoNotUse_UseAsByteInstead_1 : 5; + UCHAR UpdateRequiresPassword : 1; + }; + UCHAR AsByte[4]; + } WriteProtectActions; + UCHAR Reserved0[16]; + UCHAR UpdatePassword[32]; + UCHAR Reserved1[32672]; +} DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT, *PDVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT; +C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_WRITE_INHIBIT) == (16*2048)); + +// format 0x30 - not defined in enum - Session DCB +typedef struct _DVD_DISC_CONTROL_BLOCK_SESSION_ITEM { + UCHAR AsByte[16]; // not publicly defined? +} DVD_DISC_CONTROL_BLOCK_SESSION_ITEM, *PDVD_DISC_CONTROL_BLOCK_SESSION_ITEM; +typedef struct _DVD_DISC_CONTROL_BLOCK_SESSION { + DVD_DISC_CONTROL_BLOCK_HEADER header; + UCHAR SessionNumber[2]; + UCHAR Reserved0[22]; + UCHAR DiscID[32]; + UCHAR Reserved1[32]; + DVD_DISC_CONTROL_BLOCK_SESSION_ITEM SessionItem[504]; + UCHAR Reserved2[24576]; // 3 Repetitions of bytes 0 through 8191 +} DVD_DISC_CONTROL_BLOCK_SESSION, *PDVD_DISC_CONTROL_BLOCK_SESSION; +C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_SESSION) == ((8*1024) * 4)); + +// format 0x30 - not defined in enum - DCB list +typedef struct _DVD_DISC_CONTROL_BLOCK_LIST_DCB { + UCHAR DcbIdentifier[4]; +} DVD_DISC_CONTROL_BLOCK_LIST_DCB, *PDVD_DISC_CONTROL_BLOCK_LIST_DCB; +typedef struct _DVD_DISC_CONTROL_BLOCK_LIST { + DVD_DISC_CONTROL_BLOCK_HEADER header; + UCHAR Reserved0; + UCHAR ReadabldDCBs; + UCHAR Reserved1; + UCHAR WritableDCBs; +#if !defined(__midl) + DVD_DISC_CONTROL_BLOCK_LIST_DCB Dcbs[0]; +#endif +} DVD_DISC_CONTROL_BLOCK_LIST, *PDVD_DISC_CONTROL_BLOCK_LIST; +C_ASSERT(sizeof(DVD_DISC_CONTROL_BLOCK_LIST) == 44); + +// format 0x31 (MTA ECC Block) is unstructured in public spec +// formats 0x32 through 0xBF are not yet defined + +// format 0xC0 - not defined in enum +typedef struct _DVD_WRITE_PROTECTION_STATUS { + UCHAR SoftwareWriteProtectUntilPowerdown : 1; + UCHAR MediaPersistentWriteProtect : 1; + UCHAR CartridgeWriteProtect : 1; + UCHAR MediaSpecificWriteProtect : 1; + UCHAR Reserved0 : 4; + UCHAR Reserved1[3]; +} DVD_WRITE_PROTECTION_STATUS, *PDVD_WRITE_PROTECTION_STATUS; +C_ASSERT(sizeof(DVD_WRITE_PROTECTION_STATUS) == 4); + +// formats 0xC1 through 0x7F are not yet defined +// format 0x80 (AACS volume identifier) is unstructured in public spec +// format 0x81 (Pre-Recorded AACS media serial number) is unstructured in public spec +// format 0x82 (AACS media identifier) is unstructured in public spec +// format 0x83 (AACS media key block) is unstructured in public spec +// formats 0x84 through 0x8F are not yet defined + +// format 0x90 - not defined in enum +typedef struct _DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE { + UCHAR TypeCodeOfFormatLayer[2]; +} DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS, *PDVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS; +typedef struct _DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS { + UCHAR NumberOfRecognizedFormatLayers; + UCHAR OnlineFormatlayer : 2; + UCHAR Reserved1 : 2; + UCHAR DefaultFormatLayer : 2; + UCHAR Reserved2 : 2; + // DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE TypeCodes[0]; +} DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE, *PDVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE; +C_ASSERT(sizeof(DVD_LIST_OF_RECOGNIZED_FORMAT_LAYERS_TYPE_CODE) == 2); + +// formats 0x91 through 0xFE are not yet defined + +// format 0xFF - not defined in enum +typedef struct _DVD_STRUCTURE_LIST_ENTRY { + UCHAR FormatCode; + UCHAR Reserved0 : 6; + UCHAR Readable : 1; + UCHAR Sendable : 1; + UCHAR FormatLength[2]; +} DVD_STRUCTURE_LIST_ENTRY, *PDVD_STRUCTURE_LIST_ENTRY; +C_ASSERT(sizeof(DVD_STRUCTURE_LIST_ENTRY) == 4); + +// BD Disc Structures + +// format 0x00 (BD Disc Information) is unstructured in public spec +// format 0x08 (BD Disc Definition Structure) is unstructured in public spec +// format 0x09 (BD Cartridge Status) is identical to DVD_RAM_MEDIUM_STATUS but +// only CartridgeWriteProtect, CartridgeNotSealed and MediaInCartridge are +// valid. Other fields are reserved. + +// format 0x09 (BD Spare Area Information) - not defined in enum +typedef struct _DVD_BD_SPARE_AREA_INFORMATION { + UCHAR Reserved1[4]; + UCHAR NumberOfFreeSpareBlocks[4]; + UCHAR NumberOfAllocatedSpareBlocks[4]; +} DVD_BD_SPARE_AREA_INFORMATION, *PDVD_BD_SPARE_AREA_INFORMATION; +C_ASSERT(sizeof(DVD_BD_SPARE_AREA_INFORMATION) == 12); + +// format 0x12 (BD Raw Defect List). DFL is not fully defined in public spec + +// format 0x30 (BD Physical Access Control). +typedef struct _BD_PAC_HEADER { + UCHAR PACId[3]; + UCHAR PACFormatNumber; + UCHAR PACUpdateCount[4]; + UCHAR UnknownPACRules[4]; + UCHAR UnkownPACEntireDiscFlag; + UCHAR Reserved1[2]; + UCHAR NumberOfSegments; + UCHAR Segments[8][32]; + UCHAR Reserved2[112]; +} BD_PAC_HEADER, *PBD_PAC_HEADER; +C_ASSERT(sizeof(BD_PAC_HEADER) == 384); + +// Primary PAC is unstructured in public spec + +// Disc Write Protect PAC +typedef struct _BD_DISC_WRITE_PROTECT_PAC { + BD_PAC_HEADER Header; + UCHAR KnownPACEntireDiscFlags; + UCHAR Reserved1[3]; + UCHAR WriteProtectControlByte; + UCHAR Reserved2[7]; + UCHAR WriteProtectPassword[32]; +} BD_DISC_WRITE_PROTECT_PAC, *PBD_DISC_WRITE_PROTECT_PAC; +C_ASSERT(sizeof(BD_DISC_WRITE_PROTECT_PAC) == 428); + + +typedef struct _DVD_RPC_KEY { + UCHAR UserResetsAvailable:3; + UCHAR ManufacturerResetsAvailable:3; + UCHAR TypeCode:2; + UCHAR RegionMask; + UCHAR RpcScheme; + UCHAR Reserved02; +} DVD_RPC_KEY, * PDVD_RPC_KEY; +C_ASSERT(sizeof(DVD_RPC_KEY) == 4); + +typedef struct _DVD_SET_RPC_KEY { + UCHAR PreferredDriveRegionCode; + UCHAR Reserved[3]; +} DVD_SET_RPC_KEY, * PDVD_SET_RPC_KEY; +C_ASSERT(sizeof(DVD_SET_RPC_KEY) == 4); + +typedef struct _DVD_ASF { // Authentication Success Flag + UCHAR Reserved0[3]; + UCHAR SuccessFlag:1; + UCHAR Reserved1:7; +} DVD_ASF, * PDVD_ASF; +C_ASSERT(sizeof(DVD_ASF) == 4); + +#if 0 +typedef struct _DVD_REGION { + UCHAR CopySystem; + UCHAR RegionData; // current media region (not playable when set) + UCHAR SystemRegion; // current drive region (playable when set) + UCHAR ResetCount; // number of resets available +} DVD_REGION, *PDVD_REGION; +C_ASSERT(sizeof(DVD_REGION) == 4); +#endif + +// ALL THE ABOVE STRUCTURES ARE BYTE-PACKED: +///////////////////////////////////////////////////////////// +#include + + +#ifdef __cplusplus +} +#endif + + +///////////////////////////////////////////////////////////// +// AACS-related structures +// (mostly opaque data, but useful for allocation) + +// The AACS layer number refers to the layer of the disc a structure +// is read from. This can only be a single byte in the CDB, so limit +// the value to 0..255. +typedef __range(0,255) ULONG AACS_LAYER_NUMBER, *PAACS_LAYER_NUMBER; +typedef __range(0,255) const ULONG CAACS_LAYER_NUMBER, *PCAACS_LAYER_NUMBER; + + +// The AACS Certificate (opaque data structure) is used to validate +// the host to the logical unit, as well as to validate the logical +// unit to the host. +typedef struct _AACS_CERTIFICATE { + UCHAR Nonce[20]; + UCHAR Certificate[92]; +} AACS_CERTIFICATE, *PAACS_CERTIFICATE; +typedef const AACS_CERTIFICATE CAACS_CERTIFICATE; +typedef const AACS_CERTIFICATE *PCAACS_CERTIFICATE; +C_ASSERT(sizeof(AACS_CERTIFICATE) == 112); + +// The AACS challenge key (opaque data structure) is used to setup +// a shared bus key for AACS-protected structure transfer. +typedef struct _AACS_CHALLENGE_KEY { + UCHAR EllipticCurvePoint[40]; + UCHAR Signature[40]; +} AACS_CHALLENGE_KEY, *PAACS_CHALLENGE_KEY; +typedef const AACS_CHALLENGE_KEY CAACS_CHALLENGE_KEY; +typedef const AACS_CHALLENGE_KEY *PCAACS_CHALLENGE_KEY; +C_ASSERT(sizeof(AACS_CHALLENGE_KEY) == 80); + +// The VolumeID is one of the unique identifiers on AACS protected media +typedef struct _AACS_VOLUME_ID { + UCHAR VolumeID[16]; + UCHAR MAC[16]; // MessageAuthenticationCode +} AACS_VOLUME_ID, *PAACS_VOLUME_ID; +typedef const AACS_VOLUME_ID CAACS_VOLUME_ID; +typedef const AACS_VOLUME_ID *PCAACS_VOLUME_ID; +C_ASSERT(sizeof(AACS_VOLUME_ID) == 32); + +// The prerecorded Serial Number is one of the unique identifiers on AACS protected media +typedef struct _AACS_SERIAL_NUMBER { + UCHAR PrerecordedSerialNumber[16]; + UCHAR MAC[16]; // MessageAuthenticationCode +} AACS_SERIAL_NUMBER, *PAACS_SERIAL_NUMBER; +typedef const AACS_SERIAL_NUMBER CAACS_SERIAL_NUMBER; +typedef const AACS_SERIAL_NUMBER *PCAACS_SERIAL_NUMBER; +C_ASSERT(sizeof(AACS_SERIAL_NUMBER) == 32); + +// The MediaID is one of the unique identifiers on AACS protected media +typedef struct _AACS_MEDIA_ID { + UCHAR MediaID[16]; + UCHAR MAC[16]; // MessageAuthenticationCode +} AACS_MEDIA_ID, *PAACS_MEDIA_ID; +typedef const AACS_MEDIA_ID CAACS_MEDIA_ID; +typedef const AACS_MEDIA_ID *PCAACS_MEDIA_ID; +C_ASSERT(sizeof(AACS_MEDIA_ID) == 32); + +// When sending a certificate or challenge key, need to wrap +// the data structure with a DVD_SESSION_ID. +typedef struct _AACS_SEND_CERTIFICATE { + DVD_SESSION_ID SessionId; + AACS_CERTIFICATE Certificate; +} AACS_SEND_CERTIFICATE, *PAACS_SEND_CERTIFICATE; +typedef const AACS_SEND_CERTIFICATE CAACS_SEND_CERTIFICATE; +typedef const AACS_SEND_CERTIFICATE *PCAACS_SEND_CERTIFICATE; + +// When sending a certificate or challenge key, need to wrap +// the data structure with a DVD_SESSION_ID. +typedef struct _AACS_SEND_CHALLENGE_KEY { + DVD_SESSION_ID SessionId; + AACS_CHALLENGE_KEY ChallengeKey; +} AACS_SEND_CHALLENGE_KEY, *PAACS_SEND_CHALLENGE_KEY; +typedef const AACS_SEND_CHALLENGE_KEY CAACS_SEND_CHALLENGE_KEY; +typedef const AACS_SEND_CHALLENGE_KEY *PCAACS_SEND_CHALLENGE_KEY; + + +// The AACS binding nonce (opaque data structure) is used to +// protect individual content. +typedef struct _AACS_BINDING_NONCE { + UCHAR BindingNonce[16]; + UCHAR MAC[16]; // MessageAuthenticationCode +} AACS_BINDING_NONCE, *PAACS_BINDING_NONCE; +typedef const AACS_BINDING_NONCE CAACS_BINDING_NONCE; +typedef const AACS_BINDING_NONCE *PCAACS_BINDING_NONCE; +C_ASSERT(sizeof(AACS_BINDING_NONCE) == 32); + + +// This structure is sent when reading a binding nonce +// either from the medium or when having the logical unit +// generate a new binding nonce for a set of sectors +// NOTE: This structure must be identically aligned for 32/64 bit builds +// +typedef struct _AACS_READ_BINDING_NONCE { + DVD_SESSION_ID SessionId; + __range(0,255) ULONG NumberOfSectors; // spec only provides one byte + ULONGLONG StartLba; + + // 32-bit HANDLE is 32 bits, 64-bit HANDLE is 64 bits + union { + HANDLE Handle; + ULONGLONG ForceStructureLengthToMatch64bit; + }; +} AACS_READ_BINDING_NONCE, *PAACS_READ_BINDING_NONCE; + +///////////////////////////////////////////////////////////// + +#pragma warning(pop) +#endif // _NTDDCDVD_ + +// end_winioctl + + diff --git a/include/winddk/ntdddisk.h b/include/winddk/ntdddisk.h index 92e91f620ae..db36802a9d0 100644 --- a/include/winddk/ntdddisk.h +++ b/include/winddk/ntdddisk.h @@ -1,1759 +1,1759 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - ntdddisk.h - -Abstract: - - This is the include file that defines all constants and types for - accessing the Disk device. - -Revision History: - ---*/ - - -// begin_winioctl - -#ifndef _NTDDDISK_H_ -#define _NTDDDISK_H_ - -// end_winioctl - -#if _MSC_VER > 1000 -#pragma once -#endif - -#if (NTDDI_VERSION >= NTDDI_WINXP) -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// begin_winioctl - -#if defined(_MSC_VER) -#if (_MSC_VER >= 1200) -#pragma warning(push) -#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union -#pragma warning(disable:4214) // nonstandard extension used : bitfield other than int -#endif -#endif - -// end_winioctl - -// -// Device Name - this string is the name of the device. It is the name -// that should be passed to NtOpenFile when accessing the device. -// -// Note: For devices that support multiple units, it should be suffixed -// with the Ascii representation of the unit number. -// - -#define DD_DISK_DEVICE_NAME "\\Device\\UNKNOWN" - - -// -// NtDeviceIoControlFile - -// begin_winioctl - -// -// IoControlCode values for disk devices. -// - -#define IOCTL_DISK_BASE FILE_DEVICE_DISK -#define IOCTL_DISK_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_GET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_FORMAT_TRACKS CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_REASSIGN_BLOCKS CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_PERFORMANCE CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_IS_WRITABLE CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_LOGGING CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_FORMAT_TRACKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_HISTOGRAM_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_HISTOGRAM_DATA CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_HISTOGRAM_RESET CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_REQUEST_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_REQUEST_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_PERFORMANCE_OFF CTL_CODE(IOCTL_DISK_BASE, 0x0018, METHOD_BUFFERED, FILE_ANY_ACCESS) - - - -#if(_WIN32_WINNT >= 0x0400) -#define IOCTL_DISK_CONTROLLER_NUMBER CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// -// IOCTL support for SMART drive fault prediction. -// - -#define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) -#define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#endif /* _WIN32_WINNT >= 0x0400 */ - -#if (_WIN32_WINNT >= 0x500) - -// -// New IOCTLs for GUID Partition tabled disks. -// - -#define IOCTL_DISK_GET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_SET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0014, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_SET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_CREATE_DISK CTL_CODE(IOCTL_DISK_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#endif /* _WIN32_WINNT >= 0x0500 */ - - -#if (_WIN32_WINNT >= 0x0502) - -// -// New IOCTL for disk devices that support 8 byte LBA -// -#define IOCTL_DISK_REASSIGN_BLOCKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x0029, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#endif //_WIN32_WINNT >= 0x0502 - -#if(_WIN32_WINNT >= 0x0500) -#define IOCTL_DISK_UPDATE_DRIVE_SIZE CTL_CODE(IOCTL_DISK_BASE, 0x0032, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_GROW_PARTITION CTL_CODE(IOCTL_DISK_BASE, 0x0034, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_DISK_GET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0035, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0036, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#if (NTDDI_VERSION < NTDDI_WIN2003) -#define IOCTL_DISK_GET_WRITE_CACHE_STATE CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS) -#else -#define OBSOLETE_DISK_GET_WRITE_CACHE_STATE CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS) -#endif -#define IOCTL_DISK_DELETE_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0040, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// Called to flush cached information that the driver may have about this -// device's characteristics. Not all drivers cache characteristics, and not -// cached properties can be flushed. This simply serves as an update to the -// driver that it may want to do an expensive reexamination of the device's -// characteristics now (fixed media size, partition table, etc...) -// - -#define IOCTL_DISK_UPDATE_PROPERTIES CTL_CODE(IOCTL_DISK_BASE, 0x0050, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// -// Special IOCTLs needed to support PC-98 machines in Japan -// - -#define IOCTL_DISK_FORMAT_DRIVE CTL_CODE(IOCTL_DISK_BASE, 0x00f3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_DISK_SENSE_DEVICE CTL_CODE(IOCTL_DISK_BASE, 0x00f8, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#endif /* _WIN32_WINNT >= 0x0500 */ - -// end_winioctl - -// -// IOCTLs to report and modify our caching behavior -// - -#define IOCTL_DISK_GET_CACHE_SETTING CTL_CODE(IOCTL_DISK_BASE, 0x0038, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_CACHE_SETTING CTL_CODE(IOCTL_DISK_BASE, 0x0039, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -typedef enum _DISK_CACHE_STATE { - - DiskCacheNormal, - DiskCacheWriteThroughNotSupported, - DiskCacheModifyUnsuccessful - -} DISK_CACHE_STATE, *PDISK_CACHE_STATE; - -typedef struct _DISK_CACHE_SETTING { - - // - // The size of this structure is used for versioning - // - ULONG Version; - - // - // Indicates whether there are any issues with the disk cache - // - DISK_CACHE_STATE State; - - // - // Indicates whether the disk cache is power protected or not - // - BOOLEAN IsPowerProtected; - -} DISK_CACHE_SETTING, *PDISK_CACHE_SETTING; - - -// -// IOCTL for moving copying a run of sectors from one location of the disk -// to another. The caller of this IOCTL needs to be prepared for the call to -// fail and do the copy manually since this IOCTL will only rarely be -// implemented. -// - -#define IOCTL_DISK_COPY_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0019, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// This structure is passed in for a IOCTL_DISK_COPY_DATA call. -// - -typedef struct _DISK_COPY_DATA_PARAMETERS { - - // - // Byte offset from which to start the copy. - // - LARGE_INTEGER SourceOffset; - - // - // Byte offset of the copy destination. - // - LARGE_INTEGER DestinationOffset; - - // - // Length, in bytes, of the copy. - // - LARGE_INTEGER CopyLength; - - // - // Must be 0. - // - ULONGLONG Reserved; - - -} DISK_COPY_DATA_PARAMETERS, *PDISK_COPY_DATA_PARAMETERS; - -// -// Internal disk driver device controls to maintain the verify status bit -// for the device object. -// - -#define IOCTL_DISK_INTERNAL_SET_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS) -#define IOCTL_DISK_INTERNAL_CLEAR_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0101, METHOD_NEITHER, FILE_ANY_ACCESS) - -// -// Internal disk driver device control to set notification routine for -// the device object. Used in DiskPerf. -// - -#define IOCTL_DISK_INTERNAL_SET_NOTIFY CTL_CODE(IOCTL_DISK_BASE, 0x0102, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// begin_winioctl -// -// The following device control codes are common for all class drivers. The -// functions codes defined here must match all of the other class drivers. -// -// Warning: these codes will be replaced in the future by equivalent -// IOCTL_STORAGE codes -// - -#define IOCTL_DISK_CHECK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_MEDIA_REMOVAL CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_EJECT_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_LOAD_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_RESERVE CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_RELEASE CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_FIND_NEW_DEVICES CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_GET_MEDIA_TYPES CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// end_winioctl - -// -// The following file contains the IOCTL_STORAGE class ioctls -// - -#include - -// begin_winioctl -// -// Define the partition types returnable by known disk drivers. -// - -#define PARTITION_ENTRY_UNUSED 0x00 // Entry unused -#define PARTITION_FAT_12 0x01 // 12-bit FAT entries -#define PARTITION_XENIX_1 0x02 // Xenix -#define PARTITION_XENIX_2 0x03 // Xenix -#define PARTITION_FAT_16 0x04 // 16-bit FAT entries -#define PARTITION_EXTENDED 0x05 // Extended partition entry -#define PARTITION_HUGE 0x06 // Huge partition MS-DOS V4 -#define PARTITION_IFS 0x07 // IFS Partition -#define PARTITION_OS2BOOTMGR 0x0A // OS/2 Boot Manager/OPUS/Coherent swap -#define PARTITION_FAT32 0x0B // FAT32 -#define PARTITION_FAT32_XINT13 0x0C // FAT32 using extended int13 services -#define PARTITION_XINT13 0x0E // Win95 partition using extended int13 services -#define PARTITION_XINT13_EXTENDED 0x0F // Same as type 5 but uses extended int13 services -#define PARTITION_PREP 0x41 // PowerPC Reference Platform (PReP) Boot Partition -#define PARTITION_LDM 0x42 // Logical Disk Manager partition -#define PARTITION_UNIX 0x63 // Unix - -#define VALID_NTFT 0xC0 // NTFT uses high order bits - -// -// The high bit of the partition type code indicates that a partition -// is part of an NTFT mirror or striped array. -// - -#define PARTITION_NTFT 0x80 // NTFT partition - -// -// The following macro is used to determine which partitions should be -// assigned drive letters. -// - -//++ -// -// BOOLEAN -// IsRecognizedPartition( -// IN ULONG PartitionType -// ) -// -// Routine Description: -// -// This macro is used to determine to which partitions drive letters -// should be assigned. -// -// Arguments: -// -// PartitionType - Supplies the type of the partition being examined. -// -// Return Value: -// -// The return value is TRUE if the partition type is recognized, -// otherwise FALSE is returned. -// -//-- -#if (NTDDK_VERSION < NTDDI_VISTA) -#define IsRecognizedPartition( PartitionType ) ( \ - ((PartitionType & PARTITION_NTFT) && (((PartitionType & ~0xC0) == PARTITION_HUGE) || \ - ((PartitionType & ~0xC0) == PARTITION_IFS) || \ - ((PartitionType & ~0xC0) == PARTITION_FAT32) || \ - ((PartitionType & ~0xC0) == PARTITION_FAT32_XINT13))) || \ - ((PartitionType) == PARTITION_FAT_12) || \ - ((PartitionType) == PARTITION_FAT_16) || \ - ((PartitionType) == PARTITION_HUGE) || \ - ((PartitionType) == PARTITION_IFS) || \ - ((PartitionType) == PARTITION_FAT32) || \ - ((PartitionType) == PARTITION_FAT32_XINT13) || \ - ((PartitionType) == PARTITION_XINT13) ) -#else -#define IsRecognizedPartition( PartitionType ) ( \ - ((PartitionType) == PARTITION_FAT_12) || \ - ((PartitionType) == PARTITION_FAT_16) || \ - ((PartitionType) == PARTITION_HUGE) || \ - ((PartitionType) == PARTITION_IFS) || \ - ((PartitionType) == PARTITION_FAT32) || \ - ((PartitionType) == PARTITION_FAT32_XINT13) || \ - ((PartitionType) == PARTITION_XINT13) ) -#endif - -//++ -// -// BOOLEAN -// IsContainerPartition( -// IN ULONG PartitionType -// ) -// -// Routine Description: -// -// This macro is used to determine to which partition types are actually -// containers for other partitions (ie, extended partitions). -// -// Arguments: -// -// PartitionType - Supplies the type of the partition being examined. -// -// Return Value: -// -// The return value is TRUE if the partition type is a container, -// otherwise FALSE is returned. -// -//-- - -#define IsContainerPartition( PartitionType ) \ - ((PartitionType == PARTITION_EXTENDED) || (PartitionType == PARTITION_XINT13_EXTENDED)) - -//++ -// -// BOOLEAN -// IsFTPartition( -// IN ULONG PartitionType -// ) -// -// Routine Description: -// -// This macro is used to determine if the given partition is an FT -// partition. -// -// Arguments: -// -// PartitionType - Supplies the type of the partition being examined. -// -// Return Value: -// -// The return value is TRUE if the partition type is an FT partition, -// otherwise FALSE is returned. -// -//-- - -#define IsFTPartition( PartitionType ) \ - ((PartitionType & PARTITION_NTFT) && (((PartitionType & ~0xC0) == PARTITION_HUGE) || \ - ((PartitionType & ~0xC0) == PARTITION_IFS) || \ - ((PartitionType & ~0xC0) == PARTITION_FAT32) || \ - ((PartitionType & ~0xC0) == PARTITION_FAT32_XINT13))) - -// -// Define the media types supported by the driver. -// - -typedef enum _MEDIA_TYPE { - Unknown, // Format is unknown - F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector - F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector - F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector - F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector - F3_720_512, // 3.5", 720KB, 512 bytes/sector - F5_360_512, // 5.25", 360KB, 512 bytes/sector - F5_320_512, // 5.25", 320KB, 512 bytes/sector - F5_320_1024, // 5.25", 320KB, 1024 bytes/sector - F5_180_512, // 5.25", 180KB, 512 bytes/sector - F5_160_512, // 5.25", 160KB, 512 bytes/sector - RemovableMedia, // Removable media other than floppy - FixedMedia, // Fixed hard disk media - F3_120M_512, // 3.5", 120M Floppy - F3_640_512, // 3.5" , 640KB, 512 bytes/sector - F5_640_512, // 5.25", 640KB, 512 bytes/sector - F5_720_512, // 5.25", 720KB, 512 bytes/sector - F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector - F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector - F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector - F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector - F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector - F8_256_128, // 8", 256KB, 128 bytes/sector - F3_200Mb_512, // 3.5", 200M Floppy (HiFD) - F3_240M_512, // 3.5", 240Mb Floppy (HiFD) - F3_32M_512 // 3.5", 32Mb Floppy -} MEDIA_TYPE, *PMEDIA_TYPE; - -// -// Define the input buffer structure for the driver, when -// it is called with IOCTL_DISK_FORMAT_TRACKS. -// - -typedef struct _FORMAT_PARAMETERS { - MEDIA_TYPE MediaType; - ULONG StartCylinderNumber; - ULONG EndCylinderNumber; - ULONG StartHeadNumber; - ULONG EndHeadNumber; -} FORMAT_PARAMETERS, *PFORMAT_PARAMETERS; - -// -// Define the BAD_TRACK_NUMBER type. An array of elements of this type is -// returned by the driver on IOCTL_DISK_FORMAT_TRACKS requests, to indicate -// what tracks were bad during formatting. The length of that array is -// reported in the `Information' field of the I/O Status Block. -// - -typedef USHORT BAD_TRACK_NUMBER; -typedef USHORT *PBAD_TRACK_NUMBER; - -// -// Define the input buffer structure for the driver, when -// it is called with IOCTL_DISK_FORMAT_TRACKS_EX. -// - -typedef struct _FORMAT_EX_PARAMETERS { - MEDIA_TYPE MediaType; - ULONG StartCylinderNumber; - ULONG EndCylinderNumber; - ULONG StartHeadNumber; - ULONG EndHeadNumber; - USHORT FormatGapLength; - USHORT SectorsPerTrack; - USHORT SectorNumber[1]; -} FORMAT_EX_PARAMETERS, *PFORMAT_EX_PARAMETERS; - -// -// The following structure is returned on an IOCTL_DISK_GET_DRIVE_GEOMETRY -// request and an array of them is returned on an IOCTL_DISK_GET_MEDIA_TYPES -// request. -// - -typedef struct _DISK_GEOMETRY { - LARGE_INTEGER Cylinders; - MEDIA_TYPE MediaType; - ULONG TracksPerCylinder; - ULONG SectorsPerTrack; - ULONG BytesPerSector; -} DISK_GEOMETRY, *PDISK_GEOMETRY; - - - -// -// This wmi guid returns a DISK_GEOMETRY structure -// -#define WMI_DISK_GEOMETRY_GUID { 0x25007f51, 0x57c2, 0x11d1, { 0xa5, 0x28, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 } } - - - -// -// The following structure is returned on an IOCTL_DISK_GET_PARTITION_INFO -// and an IOCTL_DISK_GET_DRIVE_LAYOUT request. It is also used in a request -// to change the drive layout, IOCTL_DISK_SET_DRIVE_LAYOUT. -// - -typedef struct _PARTITION_INFORMATION { - LARGE_INTEGER StartingOffset; - LARGE_INTEGER PartitionLength; - ULONG HiddenSectors; - ULONG PartitionNumber; - UCHAR PartitionType; - BOOLEAN BootIndicator; - BOOLEAN RecognizedPartition; - BOOLEAN RewritePartition; -} PARTITION_INFORMATION, *PPARTITION_INFORMATION; - -// -// The following structure is used to change the partition type of a -// specified disk partition using an IOCTL_DISK_SET_PARTITION_INFO -// request. -// - -typedef struct _SET_PARTITION_INFORMATION { - UCHAR PartitionType; -} SET_PARTITION_INFORMATION, *PSET_PARTITION_INFORMATION; - -// -// The following structures is returned on an IOCTL_DISK_GET_DRIVE_LAYOUT -// request and given as input to an IOCTL_DISK_SET_DRIVE_LAYOUT request. -// - -typedef struct _DRIVE_LAYOUT_INFORMATION { - ULONG PartitionCount; - ULONG Signature; - PARTITION_INFORMATION PartitionEntry[1]; -} DRIVE_LAYOUT_INFORMATION, *PDRIVE_LAYOUT_INFORMATION; - -// -// The following structure is passed in on an IOCTL_DISK_VERIFY request. -// The offset and length parameters are both given in bytes. -// - -typedef struct _VERIFY_INFORMATION { - LARGE_INTEGER StartingOffset; - ULONG Length; -} VERIFY_INFORMATION, *PVERIFY_INFORMATION; - -// -// The following structure is passed in on an IOCTL_DISK_REASSIGN_BLOCKS -// request. -// - -typedef struct _REASSIGN_BLOCKS { - USHORT Reserved; - USHORT Count; - ULONG BlockNumber[1]; -} REASSIGN_BLOCKS, *PREASSIGN_BLOCKS; - -// -// The following structure is passed in on an IOCTL_DISK_REASSIGN_BLOCKS_EX -// request. -// - -#include -typedef struct _REASSIGN_BLOCKS_EX { - USHORT Reserved; - USHORT Count; - LARGE_INTEGER BlockNumber[1]; -} REASSIGN_BLOCKS_EX, *PREASSIGN_BLOCKS_EX; -#include - - -#if(_WIN32_WINNT >= 0x500) - -// -// Support for GUID Partition Table (GPT) disks. -// - -// -// There are currently two ways a disk can be partitioned. With a traditional -// AT-style master boot record (PARTITION_STYLE_MBR) and with a new, GPT -// partition table (PARTITION_STYLE_GPT). RAW is for an unrecognizable -// partition style. There are a very limited number of things you can -// do with a RAW partititon. -// - -typedef enum _PARTITION_STYLE { - PARTITION_STYLE_MBR, - PARTITION_STYLE_GPT, - PARTITION_STYLE_RAW -} PARTITION_STYLE; - - -// -// The following structure defines information in a GPT partition that is -// not common to both GPT and MBR partitions. -// - -typedef struct _PARTITION_INFORMATION_GPT { - GUID PartitionType; // Partition type. See table 16-3. - GUID PartitionId; // Unique GUID for this partition. - ULONG64 Attributes; // See table 16-4. - WCHAR Name [36]; // Partition Name in Unicode. -} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT; - -// -// The following are GPT partition attributes applicable for any -// partition type. These attributes are not OS-specific -// - -#define GPT_ATTRIBUTE_PLATFORM_REQUIRED (0x0000000000000001) - -// -// The following are GPT partition attributes applicable when the -// PartitionType is PARTITION_BASIC_DATA_GUID. -// - -#define GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER (0x8000000000000000) -#define GPT_BASIC_DATA_ATTRIBUTE_HIDDEN (0x4000000000000000) -#define GPT_BASIC_DATA_ATTRIBUTE_SHADOW_COPY (0x2000000000000000) -#define GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY (0x1000000000000000) - -// -// The following structure defines information in an MBR partition that is not -// common to both GPT and MBR partitions. -// - -typedef struct _PARTITION_INFORMATION_MBR { - UCHAR PartitionType; - BOOLEAN BootIndicator; - BOOLEAN RecognizedPartition; - ULONG HiddenSectors; -} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR; - - -// -// The structure SET_PARTITION_INFO_EX is used with the ioctl -// IOCTL_SET_PARTITION_INFO_EX to set information about a specific -// partition. Note that for MBR partitions, you can only set the partition -// signature, whereas GPT partitions allow setting of all fields that -// you can get. -// - -typedef SET_PARTITION_INFORMATION SET_PARTITION_INFORMATION_MBR; -typedef PARTITION_INFORMATION_GPT SET_PARTITION_INFORMATION_GPT; - - -typedef struct _SET_PARTITION_INFORMATION_EX { - PARTITION_STYLE PartitionStyle; - union { - SET_PARTITION_INFORMATION_MBR Mbr; - SET_PARTITION_INFORMATION_GPT Gpt; - } DUMMYUNIONNAME; -} SET_PARTITION_INFORMATION_EX, *PSET_PARTITION_INFORMATION_EX; - - -// -// The structure CREATE_DISK_GPT with the ioctl IOCTL_DISK_CREATE_DISK -// to initialize an virgin disk with an empty GPT partition table. -// - -typedef struct _CREATE_DISK_GPT { - GUID DiskId; // Unique disk id for the disk. - ULONG MaxPartitionCount; // Maximim number of partitions allowable. -} CREATE_DISK_GPT, *PCREATE_DISK_GPT; - -// -// The structure CREATE_DISK_MBR with the ioctl IOCTL_DISK_CREATE_DISK -// to initialize an virgin disk with an empty MBR partition table. -// - -typedef struct _CREATE_DISK_MBR { - ULONG Signature; -} CREATE_DISK_MBR, *PCREATE_DISK_MBR; - - -typedef struct _CREATE_DISK { - PARTITION_STYLE PartitionStyle; - union { - CREATE_DISK_MBR Mbr; - CREATE_DISK_GPT Gpt; - } DUMMYUNIONNAME; -} CREATE_DISK, *PCREATE_DISK; - - -// -// The structure GET_LENGTH_INFORMATION is used with the ioctl -// IOCTL_DISK_GET_LENGTH_INFO to obtain the length, in bytes, of the -// disk, partition, or volume. -// - -typedef struct _GET_LENGTH_INFORMATION { - LARGE_INTEGER Length; -} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION; - -// -// The PARTITION_INFORMATION_EX structure is used with the -// IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, -// IOCTL_DISK_GET_PARTITION_INFO_EX and IOCTL_DISK_GET_PARTITION_INFO_EX calls. -// - -typedef struct _PARTITION_INFORMATION_EX { - PARTITION_STYLE PartitionStyle; - LARGE_INTEGER StartingOffset; - LARGE_INTEGER PartitionLength; - ULONG PartitionNumber; - BOOLEAN RewritePartition; - union { - PARTITION_INFORMATION_MBR Mbr; - PARTITION_INFORMATION_GPT Gpt; - } DUMMYUNIONNAME; -} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX; - - -// -// GPT specific drive layout information. -// - -typedef struct _DRIVE_LAYOUT_INFORMATION_GPT { - GUID DiskId; - LARGE_INTEGER StartingUsableOffset; - LARGE_INTEGER UsableLength; - ULONG MaxPartitionCount; -} DRIVE_LAYOUT_INFORMATION_GPT, *PDRIVE_LAYOUT_INFORMATION_GPT; - - -// -// MBR specific drive layout information. -// - -typedef struct _DRIVE_LAYOUT_INFORMATION_MBR { - ULONG Signature; -} DRIVE_LAYOUT_INFORMATION_MBR, *PDRIVE_LAYOUT_INFORMATION_MBR; - -// -// The structure DRIVE_LAYOUT_INFORMATION_EX is used with the -// IOCTL_SET_DRIVE_LAYOUT_EX and IOCTL_GET_DRIVE_LAYOUT_EX calls. -// - -typedef struct _DRIVE_LAYOUT_INFORMATION_EX { - ULONG PartitionStyle; - ULONG PartitionCount; - union { - DRIVE_LAYOUT_INFORMATION_MBR Mbr; - DRIVE_LAYOUT_INFORMATION_GPT Gpt; - } DUMMYUNIONNAME; - PARTITION_INFORMATION_EX PartitionEntry[1]; -} DRIVE_LAYOUT_INFORMATION_EX, *PDRIVE_LAYOUT_INFORMATION_EX; - - -#endif // (_WIN32_WINNT >= 0x0500) - - -#if(_WIN32_WINNT >= 0x0500) - -// -// The DISK_GEOMETRY_EX structure is returned on issuing an -// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX ioctl. -// - -typedef enum _DETECTION_TYPE { - DetectNone, - DetectInt13, - DetectExInt13 -} DETECTION_TYPE; - -typedef struct _DISK_INT13_INFO { - USHORT DriveSelect; - ULONG MaxCylinders; - USHORT SectorsPerTrack; - USHORT MaxHeads; - USHORT NumberDrives; -} DISK_INT13_INFO, *PDISK_INT13_INFO; - -typedef struct _DISK_EX_INT13_INFO { - USHORT ExBufferSize; - USHORT ExFlags; - ULONG ExCylinders; - ULONG ExHeads; - ULONG ExSectorsPerTrack; - ULONG64 ExSectorsPerDrive; - USHORT ExSectorSize; - USHORT ExReserved; -} DISK_EX_INT13_INFO, *PDISK_EX_INT13_INFO; - -#if (_MSC_VER >= 1200) -#pragma warning(push) -#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union -#endif - -typedef struct _DISK_DETECTION_INFO { - ULONG SizeOfDetectInfo; - DETECTION_TYPE DetectionType; - union { - struct { - - // - // If DetectionType == DETECTION_INT13 then we have just the Int13 - // information. - // - - DISK_INT13_INFO Int13; - - // - // If DetectionType == DETECTION_EX_INT13, then we have the - // extended int 13 information. - // - - DISK_EX_INT13_INFO ExInt13; // If DetectionType == DetectExInt13 - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; -} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO; - - -typedef struct _DISK_PARTITION_INFO { - ULONG SizeOfPartitionInfo; - PARTITION_STYLE PartitionStyle; // PartitionStyle = RAW, GPT or MBR - union { - struct { // If PartitionStyle == MBR - ULONG Signature; // MBR Signature - ULONG CheckSum; // MBR CheckSum - } Mbr; - struct { // If PartitionStyle == GPT - GUID DiskId; - } Gpt; - } DUMMYUNIONNAME; -} DISK_PARTITION_INFO, *PDISK_PARTITION_INFO; - -#if (_MSC_VER >= 1200) -#pragma warning(pop) -#endif - -// -// The Geometry structure is a variable length structure composed of a -// DISK_GEOMETRY_EX structure followed by a DISK_PARTITION_INFO structure -// followed by a DISK_DETECTION_DATA structure. -// - -#if (NTDDI_VERSION < NTDDI_WIN2003) -#define DiskGeometryGetPartition(Geometry)\ - ((PDISK_PARTITION_INFO)((Geometry)+1)) - -#define DiskGeometryGetDetect(Geometry)\ - ((PDISK_DETECTION_INFO)(((PBYTE)DiskGeometryGetPartition(Geometry)+\ - DiskGeometryGetPartition(Geometry)->SizeOfPartitionInfo))) -#else -#define DiskGeometryGetPartition(Geometry)\ - ((PDISK_PARTITION_INFO)((Geometry)->Data)) - -#define DiskGeometryGetDetect(Geometry)\ - ((PDISK_DETECTION_INFO)(((ULONG_PTR)DiskGeometryGetPartition(Geometry)+\ - DiskGeometryGetPartition(Geometry)->SizeOfPartitionInfo))) -#endif -typedef struct _DISK_GEOMETRY_EX { - DISK_GEOMETRY Geometry; // Standard disk geometry: may be faked by driver. - LARGE_INTEGER DiskSize; // Must always be correct - UCHAR Data[1]; // Partition, Detect info -} DISK_GEOMETRY_EX, *PDISK_GEOMETRY_EX; - -#endif // (_WIN32_WINNT > 0x0500) - -#if(_WIN32_WINNT >= 0x0400) -// -// IOCTL_DISK_CONTROLLER_NUMBER returns the controller and disk -// number for the handle. This is used to determine if a disk -// is attached to the primary or secondary IDE controller. -// - -typedef struct _DISK_CONTROLLER_NUMBER { - ULONG ControllerNumber; - ULONG DiskNumber; -} DISK_CONTROLLER_NUMBER, *PDISK_CONTROLLER_NUMBER; -#endif /* _WIN32_WINNT >= 0x0400 */ - -#if(_WIN32_WINNT >= 0x0500) - -// -// IOCTL_DISK_SET_CACHE_INFORMATION -// -// Input Buffer: -// A DISK_CACHE_INFORMATION structure which describes how the disk -// read/write caches should be configured. -// -// Output Buffer: -// None -// - -// -// IOCTL_DISK_GET_CACHE_INFORMATION -// -// Input Buffer: -// None -// -// Output Buffer: -// A DISK_CACHE_INFORMATION structure which contains the current state -// of the disk read/write caches. -// - -typedef enum { - EqualPriority, - KeepPrefetchedData, - KeepReadData -} DISK_CACHE_RETENTION_PRIORITY; - -#if (OSVER(NTDDI_VERSION) == NTDDI_WINXP) -typedef enum _DISK_WRITE_CACHE_STATE { - DiskWriteCacheNormal, - DiskWriteCacheForceDisable, - DiskWriteCacheDisableNotSupported -} DISK_WRITE_CACHE_STATE, *PDISK_WRITE_CACHE_STATE; -#endif - -typedef struct _DISK_CACHE_INFORMATION { - - // - // on return indicates that the device is capable of saving any parameters - // in non-volatile storage. On send indicates that the device should - // save the state in non-volatile storage. - // - - BOOLEAN ParametersSavable; - - // - // Indicates whether the write and read caches are enabled. - // - - BOOLEAN ReadCacheEnabled; - BOOLEAN WriteCacheEnabled; - - // - // Controls the likelyhood of data remaining in the cache depending on how - // it got there. Data cached from a READ or WRITE operation may be given - // higher, lower or equal priority to data entered into the cache for other - // means (like prefetch) - // - - DISK_CACHE_RETENTION_PRIORITY ReadRetentionPriority; - DISK_CACHE_RETENTION_PRIORITY WriteRetentionPriority; - - // - // Requests for a larger number of blocks than this may have prefetching - // disabled. If this value is set to 0 prefetch will be disabled. - // - - USHORT DisablePrefetchTransferLength; - - // - // If TRUE then ScalarPrefetch (below) will be valid. If FALSE then - // the minimum and maximum values should be treated as a block count - // (BlockPrefetch) - // - - BOOLEAN PrefetchScalar; - - // - // Contains the minimum and maximum amount of data which will be - // will be prefetched into the cache on a disk operation. This value - // may either be a scalar multiplier of the transfer length of the request, - // or an abolute number of disk blocks. PrefetchScalar (above) indicates - // which interpretation is used. - // - - union { - struct { - USHORT Minimum; - USHORT Maximum; - - // - // The maximum number of blocks which will be prefetched - useful - // with the scalar limits to set definite upper limits. - // - - USHORT MaximumBlocks; - } ScalarPrefetch; - - struct { - USHORT Minimum; - USHORT Maximum; - } BlockPrefetch; - } DUMMYUNIONNAME; - -} DISK_CACHE_INFORMATION, *PDISK_CACHE_INFORMATION; - -// -// IOCTL_DISK_GROW_PARTITION will update the size of a partition -// by adding sectors to the length. The number of sectors must be -// predetermined by examining PARTITION_INFORMATION. -// - -typedef struct _DISK_GROW_PARTITION { - ULONG PartitionNumber; - LARGE_INTEGER BytesToGrow; -} DISK_GROW_PARTITION, *PDISK_GROW_PARTITION; -#endif /* _WIN32_WINNT >= 0x0500 */ - -/////////////////////////////////////////////////////// -// // -// The following structures define disk performance // -// statistics: specifically the locations of all the // -// reads and writes which have occured on the disk. // -// // -// To use these structures, you must issue an IOCTL_ // -// DISK_HIST_STRUCTURE (with a DISK_HISTOGRAM) to // -// obtain the basic histogram information. The // -// number of buckets which must allocated is part of // -// this structure. Allocate the required number of // -// buckets and call an IOCTL_DISK_HIST_DATA to fill // -// in the data // -// // -/////////////////////////////////////////////////////// - -#define HIST_NO_OF_BUCKETS 24 - -typedef struct _HISTOGRAM_BUCKET { - ULONG Reads; - ULONG Writes; -} HISTOGRAM_BUCKET, *PHISTOGRAM_BUCKET; - -#define HISTOGRAM_BUCKET_SIZE sizeof(HISTOGRAM_BUCKET) - -typedef struct _DISK_HISTOGRAM { - LARGE_INTEGER DiskSize; - LARGE_INTEGER Start; - LARGE_INTEGER End; - LARGE_INTEGER Average; - LARGE_INTEGER AverageRead; - LARGE_INTEGER AverageWrite; - ULONG Granularity; - ULONG Size; - ULONG ReadCount; - ULONG WriteCount; - PHISTOGRAM_BUCKET Histogram; -} DISK_HISTOGRAM, *PDISK_HISTOGRAM; - -#define DISK_HISTOGRAM_SIZE sizeof(DISK_HISTOGRAM) - -/////////////////////////////////////////////////////// -// // -// The following structures define disk debugging // -// capabilities. The IOCTLs are directed to one of // -// the two disk filter drivers. // -// // -// DISKPERF is a utilty for collecting disk request // -// statistics. // -// // -// SIMBAD is a utility for injecting faults in // -// IO requests to disks. // -// // -/////////////////////////////////////////////////////// - -// -// The following structure is exchanged on an IOCTL_DISK_GET_PERFORMANCE -// request. This ioctl collects summary disk request statistics used -// in measuring performance. -// - -typedef struct _DISK_PERFORMANCE { - LARGE_INTEGER BytesRead; - LARGE_INTEGER BytesWritten; - LARGE_INTEGER ReadTime; - LARGE_INTEGER WriteTime; - LARGE_INTEGER IdleTime; - ULONG ReadCount; - ULONG WriteCount; - ULONG QueueDepth; - ULONG SplitCount; - LARGE_INTEGER QueryTime; - ULONG StorageDeviceNumber; - WCHAR StorageManagerName[8]; -} DISK_PERFORMANCE, *PDISK_PERFORMANCE; - -// -// This structure defines the disk logging record. When disk logging -// is enabled, one of these is written to an internal buffer for each -// disk request. -// - -typedef struct _DISK_RECORD { - LARGE_INTEGER ByteOffset; - LARGE_INTEGER StartTime; - LARGE_INTEGER EndTime; - PVOID VirtualAddress; - ULONG NumberOfBytes; - UCHAR DeviceNumber; - BOOLEAN ReadRequest; -} DISK_RECORD, *PDISK_RECORD; - -// -// The following structure is exchanged on an IOCTL_DISK_LOG request. -// Not all fields are valid with each function type. -// - -typedef struct _DISK_LOGGING { - UCHAR Function; - PVOID BufferAddress; - ULONG BufferSize; -} DISK_LOGGING, *PDISK_LOGGING; - -// -// Disk logging functions -// -// Start disk logging. Only the Function and BufferSize fields are valid. -// - -#define DISK_LOGGING_START 0 - -// -// Stop disk logging. Only the Function field is valid. -// - -#define DISK_LOGGING_STOP 1 - -// -// Return disk log. All fields are valid. Data will be copied from internal -// buffer to buffer specified for the number of bytes requested. -// - -#define DISK_LOGGING_DUMP 2 - -// -// DISK BINNING -// -// DISKPERF will keep counters for IO that falls in each of these ranges. -// The application determines the number and size of the ranges. -// Joe Lin wanted me to keep it flexible as possible, for instance, IO -// sizes are interesting in ranges like 0-4096, 4097-16384, 16385-65536, 65537+. -// - -#define DISK_BINNING 3 - -// -// Bin types -// - -typedef enum _BIN_TYPES { - RequestSize, - RequestLocation -} BIN_TYPES; - -// -// Bin ranges -// - -typedef struct _BIN_RANGE { - LARGE_INTEGER StartValue; - LARGE_INTEGER Length; -} BIN_RANGE, *PBIN_RANGE; - -// -// Bin definition -// - -typedef struct _PERF_BIN { - ULONG NumberOfBins; - ULONG TypeOfBin; - BIN_RANGE BinsRanges[1]; -} PERF_BIN, *PPERF_BIN ; - -// -// Bin count -// - -typedef struct _BIN_COUNT { - BIN_RANGE BinRange; - ULONG BinCount; -} BIN_COUNT, *PBIN_COUNT; - -// -// Bin results -// - -typedef struct _BIN_RESULTS { - ULONG NumberOfBins; - BIN_COUNT BinCounts[1]; -} BIN_RESULTS, *PBIN_RESULTS; - -#if(_WIN32_WINNT >= 0x0400) -// -// Data structures for SMART drive fault prediction. -// -// GETVERSIONINPARAMS contains the data returned from the -// Get Driver Version function. -// - -#include -typedef struct _GETVERSIONINPARAMS { - UCHAR bVersion; // Binary driver version. - UCHAR bRevision; // Binary driver revision. - UCHAR bReserved; // Not used. - UCHAR bIDEDeviceMap; // Bit map of IDE devices. - ULONG fCapabilities; // Bit mask of driver capabilities. - ULONG dwReserved[4]; // For future use. -} GETVERSIONINPARAMS, *PGETVERSIONINPARAMS, *LPGETVERSIONINPARAMS; -#include - -// -// Bits returned in the fCapabilities member of GETVERSIONINPARAMS -// - -#define CAP_ATA_ID_CMD 1 // ATA ID command supported -#define CAP_ATAPI_ID_CMD 2 // ATAPI ID command supported -#define CAP_SMART_CMD 4 // SMART commannds supported - -// -// IDE registers -// - -#include -typedef struct _IDEREGS { - UCHAR bFeaturesReg; // Used for specifying SMART "commands". - UCHAR bSectorCountReg; // IDE sector count register - UCHAR bSectorNumberReg; // IDE sector number register - UCHAR bCylLowReg; // IDE low order cylinder value - UCHAR bCylHighReg; // IDE high order cylinder value - UCHAR bDriveHeadReg; // IDE drive/head register - UCHAR bCommandReg; // Actual IDE command. - UCHAR bReserved; // reserved for future use. Must be zero. -} IDEREGS, *PIDEREGS, *LPIDEREGS; -#include - -// -// Valid values for the bCommandReg member of IDEREGS. -// - -#define ATAPI_ID_CMD 0xA1 // Returns ID sector for ATAPI. -#define ID_CMD 0xEC // Returns ID sector for ATA. -#define SMART_CMD 0xB0 // Performs SMART cmd. - // Requires valid bFeaturesReg, - // bCylLowReg, and bCylHighReg - -// -// Cylinder register defines for SMART command -// - -#define SMART_CYL_LOW 0x4F -#define SMART_CYL_HI 0xC2 - - -// -// SENDCMDINPARAMS contains the input parameters for the -// Send Command to Drive function. -// - -#include -typedef struct _SENDCMDINPARAMS { - ULONG cBufferSize; // Buffer size in bytes - IDEREGS irDriveRegs; // Structure with drive register values. - UCHAR bDriveNumber; // Physical drive number to send - // command to (0,1,2,3). - UCHAR bReserved[3]; // Reserved for future expansion. - ULONG dwReserved[4]; // For future use. - UCHAR bBuffer[1]; // Input buffer. -} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS; -#include - -// -// Status returned from driver -// - -#include -typedef struct _DRIVERSTATUS { - UCHAR bDriverError; // Error code from driver, - // or 0 if no error. - UCHAR bIDEError; // Contents of IDE Error register. - // Only valid when bDriverError - // is SMART_IDE_ERROR. - UCHAR bReserved[2]; // Reserved for future expansion. - ULONG dwReserved[2]; // Reserved for future expansion. -} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS; -#include - -// -// bDriverError values -// - -#define SMART_NO_ERROR 0 // No error -#define SMART_IDE_ERROR 1 // Error from IDE controller -#define SMART_INVALID_FLAG 2 // Invalid command flag -#define SMART_INVALID_COMMAND 3 // Invalid command byte -#define SMART_INVALID_BUFFER 4 // Bad buffer (null, invalid addr..) -#define SMART_INVALID_DRIVE 5 // Drive number not valid -#define SMART_INVALID_IOCTL 6 // Invalid IOCTL -#define SMART_ERROR_NO_MEM 7 // Could not lock user's buffer -#define SMART_INVALID_REGISTER 8 // Some IDE Register not valid -#define SMART_NOT_SUPPORTED 9 // Invalid cmd flag set -#define SMART_NO_IDE_DEVICE 10 // Cmd issued to device not present - // although drive number is valid -// -// SMART sub commands for execute offline diags -// -#define SMART_OFFLINE_ROUTINE_OFFLINE 0 -#define SMART_SHORT_SELFTEST_OFFLINE 1 -#define SMART_EXTENDED_SELFTEST_OFFLINE 2 -#define SMART_ABORT_OFFLINE_SELFTEST 127 -#define SMART_SHORT_SELFTEST_CAPTIVE 129 -#define SMART_EXTENDED_SELFTEST_CAPTIVE 130 - - -#include -typedef struct _SENDCMDOUTPARAMS { - ULONG cBufferSize; // Size of bBuffer in bytes - DRIVERSTATUS DriverStatus; // Driver status structure. - UCHAR bBuffer[1]; // Buffer of arbitrary length in which to store the data read from the // drive. -} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS; -#include - - -#define READ_ATTRIBUTE_BUFFER_SIZE 512 -#define IDENTIFY_BUFFER_SIZE 512 -#define READ_THRESHOLD_BUFFER_SIZE 512 -#define SMART_LOG_SECTOR_SIZE 512 - -// -// Feature register defines for SMART "sub commands" -// - -#define READ_ATTRIBUTES 0xD0 -#define READ_THRESHOLDS 0xD1 -#define ENABLE_DISABLE_AUTOSAVE 0xD2 -#define SAVE_ATTRIBUTE_VALUES 0xD3 -#define EXECUTE_OFFLINE_DIAGS 0xD4 -#define SMART_READ_LOG 0xD5 -#define SMART_WRITE_LOG 0xd6 -#define ENABLE_SMART 0xD8 -#define DISABLE_SMART 0xD9 -#define RETURN_SMART_STATUS 0xDA -#define ENABLE_DISABLE_AUTO_OFFLINE 0xDB -#endif /* _WIN32_WINNT >= 0x0400 */ - -// end_winioctl - - -#if (NTDDI_VERSION >= NTDDI_VISTA) - -// -// IOCTLs to query and modify attributes -// associated with partitions. These are -// persisted within the partition table. -// - -#define IOCTL_DISK_GET_PARTITION_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003a, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_SET_PARTITION_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// IOCTL_DISK_GET_PARTITION_ATTRIBUTES -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type GET_PARTITION_ATTRIBUTES -// - -typedef struct _GET_PARTITION_ATTRIBUTES { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // For alignment purposes. - // - ULONG Reserved1; - - // - // Specifies the partition - // attributes. - // - ULONGLONG Attributes; - -} GET_PARTITION_ATTRIBUTES, *PGET_PARTITION_ATTRIBUTES; - -// -// IOCTL_DISK_SET_PARTITION_ATTRIBUTES -// -// Input Buffer: -// Structure of type SET_PARTITION_ATTRIBUTES -// -// Output Buffer: -// None -// - -typedef struct _SET_PARTITION_ATTRIBUTES { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // Indicates whether to remember - // these settings across reboots - // or not. - // - BOOLEAN Persist; - - // - // For alignment purposes. - // - BOOLEAN Reserved1[3]; - - // - // Specifies the new attributes. - // - ULONGLONG Attributes; - - // - // Specifies the attributes - // that are being modified. - // - ULONGLONG AttributesMask; - -} SET_PARTITION_ATTRIBUTES, *PSET_PARTITION_ATTRIBUTES; - - -// -// IOCTLs to query and modify attributes -// associated with the given disk. These -// are persisted within the registry. -// - -#define IOCTL_DISK_GET_DISK_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003c, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_DISK_SET_DISK_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003d, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define DISK_ATTRIBUTE_OFFLINE 0x0000000000000001 -#define DISK_ATTRIBUTE_READ_ONLY 0x0000000000000002 - -// -// IOCTL_DISK_GET_DISK_ATTRIBUTES -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type GET_DISK_ATTRIBUTES -// - -typedef struct _GET_DISK_ATTRIBUTES { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // For alignment purposes. - // - ULONG Reserved1; - - // - // Specifies the attributes - // associated with the disk. - // - ULONGLONG Attributes; - -} GET_DISK_ATTRIBUTES, *PGET_DISK_ATTRIBUTES; - -// -// IOCTL_DISK_SET_DISK_ATTRIBUTES -// -// Input Buffer: -// Structure of type SET_DISK_ATTRIBUTES -// -// Output Buffer: -// None -// - -typedef struct _SET_DISK_ATTRIBUTES { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // Indicates whether to remember - // these settings across reboots - // or not. - // - BOOLEAN Persist; - - // - // Indicates whether the ownership - // taken earlier is being released. - // - BOOLEAN RelinquishOwnership; - - // - // For alignment purposes. - // - BOOLEAN Reserved1[2]; - - // - // Specifies the new attributes. - // - ULONGLONG Attributes; - - // - // Specifies the attributes - // that are being modified. - // - ULONGLONG AttributesMask; - - // - // Specifies an identifier to be - // associated with the caller. - // This setting is not persisted - // across reboots. - // - GUID Owner; - -} SET_DISK_ATTRIBUTES, *PSET_DISK_ATTRIBUTES; - - -// -// IOCTL to determine if the disk is -// owned by the cluster service or not. -// - -#define IOCTL_DISK_IS_CLUSTERED CTL_CODE(IOCTL_DISK_BASE, 0x003e, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// -// IOCTL_DISK_IS_CLUSTERED -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type BOOLEAN -// - - -// -// IOCTLs to query and modify the current -// SAN settings. For instance, the policy -// associated with newly discovered disks. -// - -#define IOCTL_DISK_GET_SAN_SETTINGS CTL_CODE(IOCTL_DISK_BASE, 0x0080, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_SAN_SETTINGS CTL_CODE(IOCTL_DISK_BASE, 0x0081, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// IOCTL_DISK_GET_SAN_SETTINGS -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type DISK_SAN_SETTINGS -// - -// -// IOCTL_DISK_SET_SAN_SETTINGS -// -// Input Buffer: -// Structure of type DISK_SAN_SETTINGS -// -// Output Buffer: -// None -// - -typedef enum _DISK_SAN_POLICY { - - DiskSanPolicyUnknown, - DiskSanPolicyOnline, - DiskSanPolicyOfflineShared, - DiskSanPolicyOffline, - DiskSanPolicyMax - -} DISK_SAN_POLICY, *PDISK_SAN_POLICY; - -typedef struct _DISK_SAN_SETTINGS { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // Specifies the policy to be - // applied to all new disks. - // - DISK_SAN_POLICY SanPolicy; - -} DISK_SAN_SETTINGS, *PDISK_SAN_SETTINGS; - - -// -// IOCTLs to query and modify the context -// associated with snapshot disks created -// in hardware. -// - -#define IOCTL_DISK_GET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0082, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_DISK_SET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0083, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// begin_winioctl - -#define IOCTL_DISK_RESET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0084, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// end_winioctl - -// -// IOCTL_DISK_GET_SNAPSHOT_INFO -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type DISK_SNAPSHOT_INFO -// - -// -// IOCTL_DISK_SET_SNAPSHOT_INFO -// -// Input Buffer: -// Structure of type DISK_SNAPSHOT_INFO -// -// Output Buffer: -// None -// - -typedef enum _DISK_SNAPSHOT_STATE { - - DiskSnapshotNormalDisk, - DiskSnapshotSnapshotCheckRequired, - DiskSnapshotPreSnapshot, - DiskSnapshotSnapshotDisk - -} DISK_SNAPSHOT_STATE, *PDISK_SNAPSHOT_STATE; - -typedef struct _DISK_SNAPSHOT_INFO { - - // - // Specifies the size of the - // structure for versioning. - // - ULONG Version; - - // - // Specifies the state that this - // disk is in or the state to be - // transitioned to. - // - DISK_SNAPSHOT_STATE State; - - // - // Specifies a unique id that - // represents all of the disks - // involved in this snapshot. - // - GUID SnapshotSetId; - - // - // Specifies a unique id that - // represents this snapshot. - // - GUID SnapshotId; - - // - // Specifies a unique id that - // represents the logical unit - // whose snapshot was taken. - // - GUID LunId; - - // - // Specifies the time when this - // snapshot was taken. - // - LARGE_INTEGER CreationTimeStamp; - - // - // Specifies the number of times - // that this snapshot has been - // imported. - // - ULONG ImportCount; - - // - // Specifies attributes that are - // associated with this snapshot. - // - ULONG Flags; - - // - // Specifies the size in bytes of - // the following field. - // - ULONG AdditionalDataSize; - - // - // Specifies disk meta data that - // needs to be restored in the - // event of a fast recovery. - // - UCHAR AdditionalData[ANYSIZE_ARRAY]; - -} DISK_SNAPSHOT_INFO, *PDISK_SNAPSHOT_INFO; - -#endif // NTDDI_VERSION >= NTDDI_VISTA - - -// -// The following device control code is for the SIMBAD simulated bad -// sector facility. See SIMBAD.H in this directory for related structures. -// - -#define IOCTL_DISK_SIMBAD CTL_CODE(IOCTL_DISK_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// Queue link for mapped addresses stored for unmapping. -// - -typedef struct _MAPPED_ADDRESS { - struct _MAPPED_ADDRESS *NextMappedAddress; - PVOID MappedAddress; - ULONG NumberOfBytes; - LARGE_INTEGER IoAddress; - ULONG BusNumber; -} MAPPED_ADDRESS, *PMAPPED_ADDRESS; - -// begin_winioctl - -#if defined(_MSC_VER) -#if (_MSC_VER >= 1200) -#pragma warning(pop) -#endif -#endif - -// end_winioctl - -#ifdef __cplusplus -} -#endif - -// begin_winioctl - -#endif // _NTDDDISK_H_ - -// end_winioctl - +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntdddisk.h + +Abstract: + + This is the include file that defines all constants and types for + accessing the Disk device. + +Revision History: + +--*/ + + +// begin_winioctl + +#ifndef _NTDDDISK_H_ +#define _NTDDDISK_H_ + +// end_winioctl + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if (NTDDI_VERSION >= NTDDI_WINXP) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// begin_winioctl + +#if defined(_MSC_VER) +#if (_MSC_VER >= 1200) +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable:4214) // nonstandard extension used : bitfield other than int +#endif +#endif + +// end_winioctl + +// +// Device Name - this string is the name of the device. It is the name +// that should be passed to NtOpenFile when accessing the device. +// +// Note: For devices that support multiple units, it should be suffixed +// with the Ascii representation of the unit number. +// + +#define DD_DISK_DEVICE_NAME "\\Device\\UNKNOWN" + + +// +// NtDeviceIoControlFile + +// begin_winioctl + +// +// IoControlCode values for disk devices. +// + +#define IOCTL_DISK_BASE FILE_DEVICE_DISK +#define IOCTL_DISK_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_GET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_FORMAT_TRACKS CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_REASSIGN_BLOCKS CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_PERFORMANCE CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_IS_WRITABLE CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_LOGGING CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_FORMAT_TRACKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_HISTOGRAM_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_HISTOGRAM_DATA CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_HISTOGRAM_RESET CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_REQUEST_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_REQUEST_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_PERFORMANCE_OFF CTL_CODE(IOCTL_DISK_BASE, 0x0018, METHOD_BUFFERED, FILE_ANY_ACCESS) + + + +#if(_WIN32_WINNT >= 0x0400) +#define IOCTL_DISK_CONTROLLER_NUMBER CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL support for SMART drive fault prediction. +// + +#define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) +#define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#endif /* _WIN32_WINNT >= 0x0400 */ + +#if (_WIN32_WINNT >= 0x500) + +// +// New IOCTLs for GUID Partition tabled disks. +// + +#define IOCTL_DISK_GET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_SET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0014, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_SET_DRIVE_LAYOUT_EX CTL_CODE(IOCTL_DISK_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_CREATE_DISK CTL_CODE(IOCTL_DISK_BASE, 0x0016, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif /* _WIN32_WINNT >= 0x0500 */ + + +#if (_WIN32_WINNT >= 0x0502) + +// +// New IOCTL for disk devices that support 8 byte LBA +// +#define IOCTL_DISK_REASSIGN_BLOCKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x0029, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#endif //_WIN32_WINNT >= 0x0502 + +#if(_WIN32_WINNT >= 0x0500) +#define IOCTL_DISK_UPDATE_DRIVE_SIZE CTL_CODE(IOCTL_DISK_BASE, 0x0032, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GROW_PARTITION CTL_CODE(IOCTL_DISK_BASE, 0x0034, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_DISK_GET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0035, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_CACHE_INFORMATION CTL_CODE(IOCTL_DISK_BASE, 0x0036, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#if (NTDDI_VERSION < NTDDI_WIN2003) +#define IOCTL_DISK_GET_WRITE_CACHE_STATE CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS) +#else +#define OBSOLETE_DISK_GET_WRITE_CACHE_STATE CTL_CODE(IOCTL_DISK_BASE, 0x0037, METHOD_BUFFERED, FILE_READ_ACCESS) +#endif +#define IOCTL_DISK_DELETE_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0040, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// Called to flush cached information that the driver may have about this +// device's characteristics. Not all drivers cache characteristics, and not +// cached properties can be flushed. This simply serves as an update to the +// driver that it may want to do an expensive reexamination of the device's +// characteristics now (fixed media size, partition table, etc...) +// + +#define IOCTL_DISK_UPDATE_PROPERTIES CTL_CODE(IOCTL_DISK_BASE, 0x0050, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// Special IOCTLs needed to support PC-98 machines in Japan +// + +#define IOCTL_DISK_FORMAT_DRIVE CTL_CODE(IOCTL_DISK_BASE, 0x00f3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_SENSE_DEVICE CTL_CODE(IOCTL_DISK_BASE, 0x00f8, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#endif /* _WIN32_WINNT >= 0x0500 */ + +// end_winioctl + +// +// IOCTLs to report and modify our caching behavior +// + +#define IOCTL_DISK_GET_CACHE_SETTING CTL_CODE(IOCTL_DISK_BASE, 0x0038, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_CACHE_SETTING CTL_CODE(IOCTL_DISK_BASE, 0x0039, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +typedef enum _DISK_CACHE_STATE { + + DiskCacheNormal, + DiskCacheWriteThroughNotSupported, + DiskCacheModifyUnsuccessful + +} DISK_CACHE_STATE, *PDISK_CACHE_STATE; + +typedef struct _DISK_CACHE_SETTING { + + // + // The size of this structure is used for versioning + // + ULONG Version; + + // + // Indicates whether there are any issues with the disk cache + // + DISK_CACHE_STATE State; + + // + // Indicates whether the disk cache is power protected or not + // + BOOLEAN IsPowerProtected; + +} DISK_CACHE_SETTING, *PDISK_CACHE_SETTING; + + +// +// IOCTL for moving copying a run of sectors from one location of the disk +// to another. The caller of this IOCTL needs to be prepared for the call to +// fail and do the copy manually since this IOCTL will only rarely be +// implemented. +// + +#define IOCTL_DISK_COPY_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0019, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// This structure is passed in for a IOCTL_DISK_COPY_DATA call. +// + +typedef struct _DISK_COPY_DATA_PARAMETERS { + + // + // Byte offset from which to start the copy. + // + LARGE_INTEGER SourceOffset; + + // + // Byte offset of the copy destination. + // + LARGE_INTEGER DestinationOffset; + + // + // Length, in bytes, of the copy. + // + LARGE_INTEGER CopyLength; + + // + // Must be 0. + // + ULONGLONG Reserved; + + +} DISK_COPY_DATA_PARAMETERS, *PDISK_COPY_DATA_PARAMETERS; + +// +// Internal disk driver device controls to maintain the verify status bit +// for the device object. +// + +#define IOCTL_DISK_INTERNAL_SET_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_DISK_INTERNAL_CLEAR_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0101, METHOD_NEITHER, FILE_ANY_ACCESS) + +// +// Internal disk driver device control to set notification routine for +// the device object. Used in DiskPerf. +// + +#define IOCTL_DISK_INTERNAL_SET_NOTIFY CTL_CODE(IOCTL_DISK_BASE, 0x0102, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// begin_winioctl +// +// The following device control codes are common for all class drivers. The +// functions codes defined here must match all of the other class drivers. +// +// Warning: these codes will be replaced in the future by equivalent +// IOCTL_STORAGE codes +// + +#define IOCTL_DISK_CHECK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_MEDIA_REMOVAL CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_EJECT_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_LOAD_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_RESERVE CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_RELEASE CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_FIND_NEW_DEVICES CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_GET_MEDIA_TYPES CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// end_winioctl + +// +// The following file contains the IOCTL_STORAGE class ioctls +// + +#include + +// begin_winioctl +// +// Define the partition types returnable by known disk drivers. +// + +#define PARTITION_ENTRY_UNUSED 0x00 // Entry unused +#define PARTITION_FAT_12 0x01 // 12-bit FAT entries +#define PARTITION_XENIX_1 0x02 // Xenix +#define PARTITION_XENIX_2 0x03 // Xenix +#define PARTITION_FAT_16 0x04 // 16-bit FAT entries +#define PARTITION_EXTENDED 0x05 // Extended partition entry +#define PARTITION_HUGE 0x06 // Huge partition MS-DOS V4 +#define PARTITION_IFS 0x07 // IFS Partition +#define PARTITION_OS2BOOTMGR 0x0A // OS/2 Boot Manager/OPUS/Coherent swap +#define PARTITION_FAT32 0x0B // FAT32 +#define PARTITION_FAT32_XINT13 0x0C // FAT32 using extended int13 services +#define PARTITION_XINT13 0x0E // Win95 partition using extended int13 services +#define PARTITION_XINT13_EXTENDED 0x0F // Same as type 5 but uses extended int13 services +#define PARTITION_PREP 0x41 // PowerPC Reference Platform (PReP) Boot Partition +#define PARTITION_LDM 0x42 // Logical Disk Manager partition +#define PARTITION_UNIX 0x63 // Unix + +#define VALID_NTFT 0xC0 // NTFT uses high order bits + +// +// The high bit of the partition type code indicates that a partition +// is part of an NTFT mirror or striped array. +// + +#define PARTITION_NTFT 0x80 // NTFT partition + +// +// The following macro is used to determine which partitions should be +// assigned drive letters. +// + +//++ +// +// BOOLEAN +// IsRecognizedPartition( +// IN ULONG PartitionType +// ) +// +// Routine Description: +// +// This macro is used to determine to which partitions drive letters +// should be assigned. +// +// Arguments: +// +// PartitionType - Supplies the type of the partition being examined. +// +// Return Value: +// +// The return value is TRUE if the partition type is recognized, +// otherwise FALSE is returned. +// +//-- +#if (NTDDK_VERSION < NTDDI_VISTA) +#define IsRecognizedPartition( PartitionType ) ( \ + ((PartitionType & PARTITION_NTFT) && (((PartitionType & ~0xC0) == PARTITION_HUGE) || \ + ((PartitionType & ~0xC0) == PARTITION_IFS) || \ + ((PartitionType & ~0xC0) == PARTITION_FAT32) || \ + ((PartitionType & ~0xC0) == PARTITION_FAT32_XINT13))) || \ + ((PartitionType) == PARTITION_FAT_12) || \ + ((PartitionType) == PARTITION_FAT_16) || \ + ((PartitionType) == PARTITION_HUGE) || \ + ((PartitionType) == PARTITION_IFS) || \ + ((PartitionType) == PARTITION_FAT32) || \ + ((PartitionType) == PARTITION_FAT32_XINT13) || \ + ((PartitionType) == PARTITION_XINT13) ) +#else +#define IsRecognizedPartition( PartitionType ) ( \ + ((PartitionType) == PARTITION_FAT_12) || \ + ((PartitionType) == PARTITION_FAT_16) || \ + ((PartitionType) == PARTITION_HUGE) || \ + ((PartitionType) == PARTITION_IFS) || \ + ((PartitionType) == PARTITION_FAT32) || \ + ((PartitionType) == PARTITION_FAT32_XINT13) || \ + ((PartitionType) == PARTITION_XINT13) ) +#endif + +//++ +// +// BOOLEAN +// IsContainerPartition( +// IN ULONG PartitionType +// ) +// +// Routine Description: +// +// This macro is used to determine to which partition types are actually +// containers for other partitions (ie, extended partitions). +// +// Arguments: +// +// PartitionType - Supplies the type of the partition being examined. +// +// Return Value: +// +// The return value is TRUE if the partition type is a container, +// otherwise FALSE is returned. +// +//-- + +#define IsContainerPartition( PartitionType ) \ + ((PartitionType == PARTITION_EXTENDED) || (PartitionType == PARTITION_XINT13_EXTENDED)) + +//++ +// +// BOOLEAN +// IsFTPartition( +// IN ULONG PartitionType +// ) +// +// Routine Description: +// +// This macro is used to determine if the given partition is an FT +// partition. +// +// Arguments: +// +// PartitionType - Supplies the type of the partition being examined. +// +// Return Value: +// +// The return value is TRUE if the partition type is an FT partition, +// otherwise FALSE is returned. +// +//-- + +#define IsFTPartition( PartitionType ) \ + ((PartitionType & PARTITION_NTFT) && (((PartitionType & ~0xC0) == PARTITION_HUGE) || \ + ((PartitionType & ~0xC0) == PARTITION_IFS) || \ + ((PartitionType & ~0xC0) == PARTITION_FAT32) || \ + ((PartitionType & ~0xC0) == PARTITION_FAT32_XINT13))) + +// +// Define the media types supported by the driver. +// + +typedef enum _MEDIA_TYPE { + Unknown, // Format is unknown + F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector + F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector + F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector + F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector + F3_720_512, // 3.5", 720KB, 512 bytes/sector + F5_360_512, // 5.25", 360KB, 512 bytes/sector + F5_320_512, // 5.25", 320KB, 512 bytes/sector + F5_320_1024, // 5.25", 320KB, 1024 bytes/sector + F5_180_512, // 5.25", 180KB, 512 bytes/sector + F5_160_512, // 5.25", 160KB, 512 bytes/sector + RemovableMedia, // Removable media other than floppy + FixedMedia, // Fixed hard disk media + F3_120M_512, // 3.5", 120M Floppy + F3_640_512, // 3.5" , 640KB, 512 bytes/sector + F5_640_512, // 5.25", 640KB, 512 bytes/sector + F5_720_512, // 5.25", 720KB, 512 bytes/sector + F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector + F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector + F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector + F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector + F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector + F8_256_128, // 8", 256KB, 128 bytes/sector + F3_200Mb_512, // 3.5", 200M Floppy (HiFD) + F3_240M_512, // 3.5", 240Mb Floppy (HiFD) + F3_32M_512 // 3.5", 32Mb Floppy +} MEDIA_TYPE, *PMEDIA_TYPE; + +// +// Define the input buffer structure for the driver, when +// it is called with IOCTL_DISK_FORMAT_TRACKS. +// + +typedef struct _FORMAT_PARAMETERS { + MEDIA_TYPE MediaType; + ULONG StartCylinderNumber; + ULONG EndCylinderNumber; + ULONG StartHeadNumber; + ULONG EndHeadNumber; +} FORMAT_PARAMETERS, *PFORMAT_PARAMETERS; + +// +// Define the BAD_TRACK_NUMBER type. An array of elements of this type is +// returned by the driver on IOCTL_DISK_FORMAT_TRACKS requests, to indicate +// what tracks were bad during formatting. The length of that array is +// reported in the `Information' field of the I/O Status Block. +// + +typedef USHORT BAD_TRACK_NUMBER; +typedef USHORT *PBAD_TRACK_NUMBER; + +// +// Define the input buffer structure for the driver, when +// it is called with IOCTL_DISK_FORMAT_TRACKS_EX. +// + +typedef struct _FORMAT_EX_PARAMETERS { + MEDIA_TYPE MediaType; + ULONG StartCylinderNumber; + ULONG EndCylinderNumber; + ULONG StartHeadNumber; + ULONG EndHeadNumber; + USHORT FormatGapLength; + USHORT SectorsPerTrack; + USHORT SectorNumber[1]; +} FORMAT_EX_PARAMETERS, *PFORMAT_EX_PARAMETERS; + +// +// The following structure is returned on an IOCTL_DISK_GET_DRIVE_GEOMETRY +// request and an array of them is returned on an IOCTL_DISK_GET_MEDIA_TYPES +// request. +// + +typedef struct _DISK_GEOMETRY { + LARGE_INTEGER Cylinders; + MEDIA_TYPE MediaType; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; +} DISK_GEOMETRY, *PDISK_GEOMETRY; + + + +// +// This wmi guid returns a DISK_GEOMETRY structure +// +#define WMI_DISK_GEOMETRY_GUID { 0x25007f51, 0x57c2, 0x11d1, { 0xa5, 0x28, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 } } + + + +// +// The following structure is returned on an IOCTL_DISK_GET_PARTITION_INFO +// and an IOCTL_DISK_GET_DRIVE_LAYOUT request. It is also used in a request +// to change the drive layout, IOCTL_DISK_SET_DRIVE_LAYOUT. +// + +typedef struct _PARTITION_INFORMATION { + LARGE_INTEGER StartingOffset; + LARGE_INTEGER PartitionLength; + ULONG HiddenSectors; + ULONG PartitionNumber; + UCHAR PartitionType; + BOOLEAN BootIndicator; + BOOLEAN RecognizedPartition; + BOOLEAN RewritePartition; +} PARTITION_INFORMATION, *PPARTITION_INFORMATION; + +// +// The following structure is used to change the partition type of a +// specified disk partition using an IOCTL_DISK_SET_PARTITION_INFO +// request. +// + +typedef struct _SET_PARTITION_INFORMATION { + UCHAR PartitionType; +} SET_PARTITION_INFORMATION, *PSET_PARTITION_INFORMATION; + +// +// The following structures is returned on an IOCTL_DISK_GET_DRIVE_LAYOUT +// request and given as input to an IOCTL_DISK_SET_DRIVE_LAYOUT request. +// + +typedef struct _DRIVE_LAYOUT_INFORMATION { + ULONG PartitionCount; + ULONG Signature; + PARTITION_INFORMATION PartitionEntry[1]; +} DRIVE_LAYOUT_INFORMATION, *PDRIVE_LAYOUT_INFORMATION; + +// +// The following structure is passed in on an IOCTL_DISK_VERIFY request. +// The offset and length parameters are both given in bytes. +// + +typedef struct _VERIFY_INFORMATION { + LARGE_INTEGER StartingOffset; + ULONG Length; +} VERIFY_INFORMATION, *PVERIFY_INFORMATION; + +// +// The following structure is passed in on an IOCTL_DISK_REASSIGN_BLOCKS +// request. +// + +typedef struct _REASSIGN_BLOCKS { + USHORT Reserved; + USHORT Count; + ULONG BlockNumber[1]; +} REASSIGN_BLOCKS, *PREASSIGN_BLOCKS; + +// +// The following structure is passed in on an IOCTL_DISK_REASSIGN_BLOCKS_EX +// request. +// + +#include +typedef struct _REASSIGN_BLOCKS_EX { + USHORT Reserved; + USHORT Count; + LARGE_INTEGER BlockNumber[1]; +} REASSIGN_BLOCKS_EX, *PREASSIGN_BLOCKS_EX; +#include + + +#if(_WIN32_WINNT >= 0x500) + +// +// Support for GUID Partition Table (GPT) disks. +// + +// +// There are currently two ways a disk can be partitioned. With a traditional +// AT-style master boot record (PARTITION_STYLE_MBR) and with a new, GPT +// partition table (PARTITION_STYLE_GPT). RAW is for an unrecognizable +// partition style. There are a very limited number of things you can +// do with a RAW partititon. +// + +typedef enum _PARTITION_STYLE { + PARTITION_STYLE_MBR, + PARTITION_STYLE_GPT, + PARTITION_STYLE_RAW +} PARTITION_STYLE; + + +// +// The following structure defines information in a GPT partition that is +// not common to both GPT and MBR partitions. +// + +typedef struct _PARTITION_INFORMATION_GPT { + GUID PartitionType; // Partition type. See table 16-3. + GUID PartitionId; // Unique GUID for this partition. + ULONG64 Attributes; // See table 16-4. + WCHAR Name [36]; // Partition Name in Unicode. +} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT; + +// +// The following are GPT partition attributes applicable for any +// partition type. These attributes are not OS-specific +// + +#define GPT_ATTRIBUTE_PLATFORM_REQUIRED (0x0000000000000001) + +// +// The following are GPT partition attributes applicable when the +// PartitionType is PARTITION_BASIC_DATA_GUID. +// + +#define GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER (0x8000000000000000) +#define GPT_BASIC_DATA_ATTRIBUTE_HIDDEN (0x4000000000000000) +#define GPT_BASIC_DATA_ATTRIBUTE_SHADOW_COPY (0x2000000000000000) +#define GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY (0x1000000000000000) + +// +// The following structure defines information in an MBR partition that is not +// common to both GPT and MBR partitions. +// + +typedef struct _PARTITION_INFORMATION_MBR { + UCHAR PartitionType; + BOOLEAN BootIndicator; + BOOLEAN RecognizedPartition; + ULONG HiddenSectors; +} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR; + + +// +// The structure SET_PARTITION_INFO_EX is used with the ioctl +// IOCTL_SET_PARTITION_INFO_EX to set information about a specific +// partition. Note that for MBR partitions, you can only set the partition +// signature, whereas GPT partitions allow setting of all fields that +// you can get. +// + +typedef SET_PARTITION_INFORMATION SET_PARTITION_INFORMATION_MBR; +typedef PARTITION_INFORMATION_GPT SET_PARTITION_INFORMATION_GPT; + + +typedef struct _SET_PARTITION_INFORMATION_EX { + PARTITION_STYLE PartitionStyle; + union { + SET_PARTITION_INFORMATION_MBR Mbr; + SET_PARTITION_INFORMATION_GPT Gpt; + } DUMMYUNIONNAME; +} SET_PARTITION_INFORMATION_EX, *PSET_PARTITION_INFORMATION_EX; + + +// +// The structure CREATE_DISK_GPT with the ioctl IOCTL_DISK_CREATE_DISK +// to initialize an virgin disk with an empty GPT partition table. +// + +typedef struct _CREATE_DISK_GPT { + GUID DiskId; // Unique disk id for the disk. + ULONG MaxPartitionCount; // Maximim number of partitions allowable. +} CREATE_DISK_GPT, *PCREATE_DISK_GPT; + +// +// The structure CREATE_DISK_MBR with the ioctl IOCTL_DISK_CREATE_DISK +// to initialize an virgin disk with an empty MBR partition table. +// + +typedef struct _CREATE_DISK_MBR { + ULONG Signature; +} CREATE_DISK_MBR, *PCREATE_DISK_MBR; + + +typedef struct _CREATE_DISK { + PARTITION_STYLE PartitionStyle; + union { + CREATE_DISK_MBR Mbr; + CREATE_DISK_GPT Gpt; + } DUMMYUNIONNAME; +} CREATE_DISK, *PCREATE_DISK; + + +// +// The structure GET_LENGTH_INFORMATION is used with the ioctl +// IOCTL_DISK_GET_LENGTH_INFO to obtain the length, in bytes, of the +// disk, partition, or volume. +// + +typedef struct _GET_LENGTH_INFORMATION { + LARGE_INTEGER Length; +} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION; + +// +// The PARTITION_INFORMATION_EX structure is used with the +// IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, +// IOCTL_DISK_GET_PARTITION_INFO_EX and IOCTL_DISK_GET_PARTITION_INFO_EX calls. +// + +typedef struct _PARTITION_INFORMATION_EX { + PARTITION_STYLE PartitionStyle; + LARGE_INTEGER StartingOffset; + LARGE_INTEGER PartitionLength; + ULONG PartitionNumber; + BOOLEAN RewritePartition; + union { + PARTITION_INFORMATION_MBR Mbr; + PARTITION_INFORMATION_GPT Gpt; + } DUMMYUNIONNAME; +} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX; + + +// +// GPT specific drive layout information. +// + +typedef struct _DRIVE_LAYOUT_INFORMATION_GPT { + GUID DiskId; + LARGE_INTEGER StartingUsableOffset; + LARGE_INTEGER UsableLength; + ULONG MaxPartitionCount; +} DRIVE_LAYOUT_INFORMATION_GPT, *PDRIVE_LAYOUT_INFORMATION_GPT; + + +// +// MBR specific drive layout information. +// + +typedef struct _DRIVE_LAYOUT_INFORMATION_MBR { + ULONG Signature; +} DRIVE_LAYOUT_INFORMATION_MBR, *PDRIVE_LAYOUT_INFORMATION_MBR; + +// +// The structure DRIVE_LAYOUT_INFORMATION_EX is used with the +// IOCTL_SET_DRIVE_LAYOUT_EX and IOCTL_GET_DRIVE_LAYOUT_EX calls. +// + +typedef struct _DRIVE_LAYOUT_INFORMATION_EX { + ULONG PartitionStyle; + ULONG PartitionCount; + union { + DRIVE_LAYOUT_INFORMATION_MBR Mbr; + DRIVE_LAYOUT_INFORMATION_GPT Gpt; + } DUMMYUNIONNAME; + PARTITION_INFORMATION_EX PartitionEntry[1]; +} DRIVE_LAYOUT_INFORMATION_EX, *PDRIVE_LAYOUT_INFORMATION_EX; + + +#endif // (_WIN32_WINNT >= 0x0500) + + +#if(_WIN32_WINNT >= 0x0500) + +// +// The DISK_GEOMETRY_EX structure is returned on issuing an +// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX ioctl. +// + +typedef enum _DETECTION_TYPE { + DetectNone, + DetectInt13, + DetectExInt13 +} DETECTION_TYPE; + +typedef struct _DISK_INT13_INFO { + USHORT DriveSelect; + ULONG MaxCylinders; + USHORT SectorsPerTrack; + USHORT MaxHeads; + USHORT NumberDrives; +} DISK_INT13_INFO, *PDISK_INT13_INFO; + +typedef struct _DISK_EX_INT13_INFO { + USHORT ExBufferSize; + USHORT ExFlags; + ULONG ExCylinders; + ULONG ExHeads; + ULONG ExSectorsPerTrack; + ULONG64 ExSectorsPerDrive; + USHORT ExSectorSize; + USHORT ExReserved; +} DISK_EX_INT13_INFO, *PDISK_EX_INT13_INFO; + +#if (_MSC_VER >= 1200) +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#endif + +typedef struct _DISK_DETECTION_INFO { + ULONG SizeOfDetectInfo; + DETECTION_TYPE DetectionType; + union { + struct { + + // + // If DetectionType == DETECTION_INT13 then we have just the Int13 + // information. + // + + DISK_INT13_INFO Int13; + + // + // If DetectionType == DETECTION_EX_INT13, then we have the + // extended int 13 information. + // + + DISK_EX_INT13_INFO ExInt13; // If DetectionType == DetectExInt13 + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; +} DISK_DETECTION_INFO, *PDISK_DETECTION_INFO; + + +typedef struct _DISK_PARTITION_INFO { + ULONG SizeOfPartitionInfo; + PARTITION_STYLE PartitionStyle; // PartitionStyle = RAW, GPT or MBR + union { + struct { // If PartitionStyle == MBR + ULONG Signature; // MBR Signature + ULONG CheckSum; // MBR CheckSum + } Mbr; + struct { // If PartitionStyle == GPT + GUID DiskId; + } Gpt; + } DUMMYUNIONNAME; +} DISK_PARTITION_INFO, *PDISK_PARTITION_INFO; + +#if (_MSC_VER >= 1200) +#pragma warning(pop) +#endif + +// +// The Geometry structure is a variable length structure composed of a +// DISK_GEOMETRY_EX structure followed by a DISK_PARTITION_INFO structure +// followed by a DISK_DETECTION_DATA structure. +// + +#if (NTDDI_VERSION < NTDDI_WIN2003) +#define DiskGeometryGetPartition(Geometry)\ + ((PDISK_PARTITION_INFO)((Geometry)+1)) + +#define DiskGeometryGetDetect(Geometry)\ + ((PDISK_DETECTION_INFO)(((PBYTE)DiskGeometryGetPartition(Geometry)+\ + DiskGeometryGetPartition(Geometry)->SizeOfPartitionInfo))) +#else +#define DiskGeometryGetPartition(Geometry)\ + ((PDISK_PARTITION_INFO)((Geometry)->Data)) + +#define DiskGeometryGetDetect(Geometry)\ + ((PDISK_DETECTION_INFO)(((ULONG_PTR)DiskGeometryGetPartition(Geometry)+\ + DiskGeometryGetPartition(Geometry)->SizeOfPartitionInfo))) +#endif +typedef struct _DISK_GEOMETRY_EX { + DISK_GEOMETRY Geometry; // Standard disk geometry: may be faked by driver. + LARGE_INTEGER DiskSize; // Must always be correct + UCHAR Data[1]; // Partition, Detect info +} DISK_GEOMETRY_EX, *PDISK_GEOMETRY_EX; + +#endif // (_WIN32_WINNT > 0x0500) + +#if(_WIN32_WINNT >= 0x0400) +// +// IOCTL_DISK_CONTROLLER_NUMBER returns the controller and disk +// number for the handle. This is used to determine if a disk +// is attached to the primary or secondary IDE controller. +// + +typedef struct _DISK_CONTROLLER_NUMBER { + ULONG ControllerNumber; + ULONG DiskNumber; +} DISK_CONTROLLER_NUMBER, *PDISK_CONTROLLER_NUMBER; +#endif /* _WIN32_WINNT >= 0x0400 */ + +#if(_WIN32_WINNT >= 0x0500) + +// +// IOCTL_DISK_SET_CACHE_INFORMATION +// +// Input Buffer: +// A DISK_CACHE_INFORMATION structure which describes how the disk +// read/write caches should be configured. +// +// Output Buffer: +// None +// + +// +// IOCTL_DISK_GET_CACHE_INFORMATION +// +// Input Buffer: +// None +// +// Output Buffer: +// A DISK_CACHE_INFORMATION structure which contains the current state +// of the disk read/write caches. +// + +typedef enum { + EqualPriority, + KeepPrefetchedData, + KeepReadData +} DISK_CACHE_RETENTION_PRIORITY; + +#if (OSVER(NTDDI_VERSION) == NTDDI_WINXP) +typedef enum _DISK_WRITE_CACHE_STATE { + DiskWriteCacheNormal, + DiskWriteCacheForceDisable, + DiskWriteCacheDisableNotSupported +} DISK_WRITE_CACHE_STATE, *PDISK_WRITE_CACHE_STATE; +#endif + +typedef struct _DISK_CACHE_INFORMATION { + + // + // on return indicates that the device is capable of saving any parameters + // in non-volatile storage. On send indicates that the device should + // save the state in non-volatile storage. + // + + BOOLEAN ParametersSavable; + + // + // Indicates whether the write and read caches are enabled. + // + + BOOLEAN ReadCacheEnabled; + BOOLEAN WriteCacheEnabled; + + // + // Controls the likelyhood of data remaining in the cache depending on how + // it got there. Data cached from a READ or WRITE operation may be given + // higher, lower or equal priority to data entered into the cache for other + // means (like prefetch) + // + + DISK_CACHE_RETENTION_PRIORITY ReadRetentionPriority; + DISK_CACHE_RETENTION_PRIORITY WriteRetentionPriority; + + // + // Requests for a larger number of blocks than this may have prefetching + // disabled. If this value is set to 0 prefetch will be disabled. + // + + USHORT DisablePrefetchTransferLength; + + // + // If TRUE then ScalarPrefetch (below) will be valid. If FALSE then + // the minimum and maximum values should be treated as a block count + // (BlockPrefetch) + // + + BOOLEAN PrefetchScalar; + + // + // Contains the minimum and maximum amount of data which will be + // will be prefetched into the cache on a disk operation. This value + // may either be a scalar multiplier of the transfer length of the request, + // or an abolute number of disk blocks. PrefetchScalar (above) indicates + // which interpretation is used. + // + + union { + struct { + USHORT Minimum; + USHORT Maximum; + + // + // The maximum number of blocks which will be prefetched - useful + // with the scalar limits to set definite upper limits. + // + + USHORT MaximumBlocks; + } ScalarPrefetch; + + struct { + USHORT Minimum; + USHORT Maximum; + } BlockPrefetch; + } DUMMYUNIONNAME; + +} DISK_CACHE_INFORMATION, *PDISK_CACHE_INFORMATION; + +// +// IOCTL_DISK_GROW_PARTITION will update the size of a partition +// by adding sectors to the length. The number of sectors must be +// predetermined by examining PARTITION_INFORMATION. +// + +typedef struct _DISK_GROW_PARTITION { + ULONG PartitionNumber; + LARGE_INTEGER BytesToGrow; +} DISK_GROW_PARTITION, *PDISK_GROW_PARTITION; +#endif /* _WIN32_WINNT >= 0x0500 */ + +/////////////////////////////////////////////////////// +// // +// The following structures define disk performance // +// statistics: specifically the locations of all the // +// reads and writes which have occured on the disk. // +// // +// To use these structures, you must issue an IOCTL_ // +// DISK_HIST_STRUCTURE (with a DISK_HISTOGRAM) to // +// obtain the basic histogram information. The // +// number of buckets which must allocated is part of // +// this structure. Allocate the required number of // +// buckets and call an IOCTL_DISK_HIST_DATA to fill // +// in the data // +// // +/////////////////////////////////////////////////////// + +#define HIST_NO_OF_BUCKETS 24 + +typedef struct _HISTOGRAM_BUCKET { + ULONG Reads; + ULONG Writes; +} HISTOGRAM_BUCKET, *PHISTOGRAM_BUCKET; + +#define HISTOGRAM_BUCKET_SIZE sizeof(HISTOGRAM_BUCKET) + +typedef struct _DISK_HISTOGRAM { + LARGE_INTEGER DiskSize; + LARGE_INTEGER Start; + LARGE_INTEGER End; + LARGE_INTEGER Average; + LARGE_INTEGER AverageRead; + LARGE_INTEGER AverageWrite; + ULONG Granularity; + ULONG Size; + ULONG ReadCount; + ULONG WriteCount; + PHISTOGRAM_BUCKET Histogram; +} DISK_HISTOGRAM, *PDISK_HISTOGRAM; + +#define DISK_HISTOGRAM_SIZE sizeof(DISK_HISTOGRAM) + +/////////////////////////////////////////////////////// +// // +// The following structures define disk debugging // +// capabilities. The IOCTLs are directed to one of // +// the two disk filter drivers. // +// // +// DISKPERF is a utilty for collecting disk request // +// statistics. // +// // +// SIMBAD is a utility for injecting faults in // +// IO requests to disks. // +// // +/////////////////////////////////////////////////////// + +// +// The following structure is exchanged on an IOCTL_DISK_GET_PERFORMANCE +// request. This ioctl collects summary disk request statistics used +// in measuring performance. +// + +typedef struct _DISK_PERFORMANCE { + LARGE_INTEGER BytesRead; + LARGE_INTEGER BytesWritten; + LARGE_INTEGER ReadTime; + LARGE_INTEGER WriteTime; + LARGE_INTEGER IdleTime; + ULONG ReadCount; + ULONG WriteCount; + ULONG QueueDepth; + ULONG SplitCount; + LARGE_INTEGER QueryTime; + ULONG StorageDeviceNumber; + WCHAR StorageManagerName[8]; +} DISK_PERFORMANCE, *PDISK_PERFORMANCE; + +// +// This structure defines the disk logging record. When disk logging +// is enabled, one of these is written to an internal buffer for each +// disk request. +// + +typedef struct _DISK_RECORD { + LARGE_INTEGER ByteOffset; + LARGE_INTEGER StartTime; + LARGE_INTEGER EndTime; + PVOID VirtualAddress; + ULONG NumberOfBytes; + UCHAR DeviceNumber; + BOOLEAN ReadRequest; +} DISK_RECORD, *PDISK_RECORD; + +// +// The following structure is exchanged on an IOCTL_DISK_LOG request. +// Not all fields are valid with each function type. +// + +typedef struct _DISK_LOGGING { + UCHAR Function; + PVOID BufferAddress; + ULONG BufferSize; +} DISK_LOGGING, *PDISK_LOGGING; + +// +// Disk logging functions +// +// Start disk logging. Only the Function and BufferSize fields are valid. +// + +#define DISK_LOGGING_START 0 + +// +// Stop disk logging. Only the Function field is valid. +// + +#define DISK_LOGGING_STOP 1 + +// +// Return disk log. All fields are valid. Data will be copied from internal +// buffer to buffer specified for the number of bytes requested. +// + +#define DISK_LOGGING_DUMP 2 + +// +// DISK BINNING +// +// DISKPERF will keep counters for IO that falls in each of these ranges. +// The application determines the number and size of the ranges. +// Joe Lin wanted me to keep it flexible as possible, for instance, IO +// sizes are interesting in ranges like 0-4096, 4097-16384, 16385-65536, 65537+. +// + +#define DISK_BINNING 3 + +// +// Bin types +// + +typedef enum _BIN_TYPES { + RequestSize, + RequestLocation +} BIN_TYPES; + +// +// Bin ranges +// + +typedef struct _BIN_RANGE { + LARGE_INTEGER StartValue; + LARGE_INTEGER Length; +} BIN_RANGE, *PBIN_RANGE; + +// +// Bin definition +// + +typedef struct _PERF_BIN { + ULONG NumberOfBins; + ULONG TypeOfBin; + BIN_RANGE BinsRanges[1]; +} PERF_BIN, *PPERF_BIN ; + +// +// Bin count +// + +typedef struct _BIN_COUNT { + BIN_RANGE BinRange; + ULONG BinCount; +} BIN_COUNT, *PBIN_COUNT; + +// +// Bin results +// + +typedef struct _BIN_RESULTS { + ULONG NumberOfBins; + BIN_COUNT BinCounts[1]; +} BIN_RESULTS, *PBIN_RESULTS; + +#if(_WIN32_WINNT >= 0x0400) +// +// Data structures for SMART drive fault prediction. +// +// GETVERSIONINPARAMS contains the data returned from the +// Get Driver Version function. +// + +#include +typedef struct _GETVERSIONINPARAMS { + UCHAR bVersion; // Binary driver version. + UCHAR bRevision; // Binary driver revision. + UCHAR bReserved; // Not used. + UCHAR bIDEDeviceMap; // Bit map of IDE devices. + ULONG fCapabilities; // Bit mask of driver capabilities. + ULONG dwReserved[4]; // For future use. +} GETVERSIONINPARAMS, *PGETVERSIONINPARAMS, *LPGETVERSIONINPARAMS; +#include + +// +// Bits returned in the fCapabilities member of GETVERSIONINPARAMS +// + +#define CAP_ATA_ID_CMD 1 // ATA ID command supported +#define CAP_ATAPI_ID_CMD 2 // ATAPI ID command supported +#define CAP_SMART_CMD 4 // SMART commannds supported + +// +// IDE registers +// + +#include +typedef struct _IDEREGS { + UCHAR bFeaturesReg; // Used for specifying SMART "commands". + UCHAR bSectorCountReg; // IDE sector count register + UCHAR bSectorNumberReg; // IDE sector number register + UCHAR bCylLowReg; // IDE low order cylinder value + UCHAR bCylHighReg; // IDE high order cylinder value + UCHAR bDriveHeadReg; // IDE drive/head register + UCHAR bCommandReg; // Actual IDE command. + UCHAR bReserved; // reserved for future use. Must be zero. +} IDEREGS, *PIDEREGS, *LPIDEREGS; +#include + +// +// Valid values for the bCommandReg member of IDEREGS. +// + +#define ATAPI_ID_CMD 0xA1 // Returns ID sector for ATAPI. +#define ID_CMD 0xEC // Returns ID sector for ATA. +#define SMART_CMD 0xB0 // Performs SMART cmd. + // Requires valid bFeaturesReg, + // bCylLowReg, and bCylHighReg + +// +// Cylinder register defines for SMART command +// + +#define SMART_CYL_LOW 0x4F +#define SMART_CYL_HI 0xC2 + + +// +// SENDCMDINPARAMS contains the input parameters for the +// Send Command to Drive function. +// + +#include +typedef struct _SENDCMDINPARAMS { + ULONG cBufferSize; // Buffer size in bytes + IDEREGS irDriveRegs; // Structure with drive register values. + UCHAR bDriveNumber; // Physical drive number to send + // command to (0,1,2,3). + UCHAR bReserved[3]; // Reserved for future expansion. + ULONG dwReserved[4]; // For future use. + UCHAR bBuffer[1]; // Input buffer. +} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS; +#include + +// +// Status returned from driver +// + +#include +typedef struct _DRIVERSTATUS { + UCHAR bDriverError; // Error code from driver, + // or 0 if no error. + UCHAR bIDEError; // Contents of IDE Error register. + // Only valid when bDriverError + // is SMART_IDE_ERROR. + UCHAR bReserved[2]; // Reserved for future expansion. + ULONG dwReserved[2]; // Reserved for future expansion. +} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS; +#include + +// +// bDriverError values +// + +#define SMART_NO_ERROR 0 // No error +#define SMART_IDE_ERROR 1 // Error from IDE controller +#define SMART_INVALID_FLAG 2 // Invalid command flag +#define SMART_INVALID_COMMAND 3 // Invalid command byte +#define SMART_INVALID_BUFFER 4 // Bad buffer (null, invalid addr..) +#define SMART_INVALID_DRIVE 5 // Drive number not valid +#define SMART_INVALID_IOCTL 6 // Invalid IOCTL +#define SMART_ERROR_NO_MEM 7 // Could not lock user's buffer +#define SMART_INVALID_REGISTER 8 // Some IDE Register not valid +#define SMART_NOT_SUPPORTED 9 // Invalid cmd flag set +#define SMART_NO_IDE_DEVICE 10 // Cmd issued to device not present + // although drive number is valid +// +// SMART sub commands for execute offline diags +// +#define SMART_OFFLINE_ROUTINE_OFFLINE 0 +#define SMART_SHORT_SELFTEST_OFFLINE 1 +#define SMART_EXTENDED_SELFTEST_OFFLINE 2 +#define SMART_ABORT_OFFLINE_SELFTEST 127 +#define SMART_SHORT_SELFTEST_CAPTIVE 129 +#define SMART_EXTENDED_SELFTEST_CAPTIVE 130 + + +#include +typedef struct _SENDCMDOUTPARAMS { + ULONG cBufferSize; // Size of bBuffer in bytes + DRIVERSTATUS DriverStatus; // Driver status structure. + UCHAR bBuffer[1]; // Buffer of arbitrary length in which to store the data read from the // drive. +} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS; +#include + + +#define READ_ATTRIBUTE_BUFFER_SIZE 512 +#define IDENTIFY_BUFFER_SIZE 512 +#define READ_THRESHOLD_BUFFER_SIZE 512 +#define SMART_LOG_SECTOR_SIZE 512 + +// +// Feature register defines for SMART "sub commands" +// + +#define READ_ATTRIBUTES 0xD0 +#define READ_THRESHOLDS 0xD1 +#define ENABLE_DISABLE_AUTOSAVE 0xD2 +#define SAVE_ATTRIBUTE_VALUES 0xD3 +#define EXECUTE_OFFLINE_DIAGS 0xD4 +#define SMART_READ_LOG 0xD5 +#define SMART_WRITE_LOG 0xd6 +#define ENABLE_SMART 0xD8 +#define DISABLE_SMART 0xD9 +#define RETURN_SMART_STATUS 0xDA +#define ENABLE_DISABLE_AUTO_OFFLINE 0xDB +#endif /* _WIN32_WINNT >= 0x0400 */ + +// end_winioctl + + +#if (NTDDI_VERSION >= NTDDI_VISTA) + +// +// IOCTLs to query and modify attributes +// associated with partitions. These are +// persisted within the partition table. +// + +#define IOCTL_DISK_GET_PARTITION_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003a, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_SET_PARTITION_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTL_DISK_GET_PARTITION_ATTRIBUTES +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type GET_PARTITION_ATTRIBUTES +// + +typedef struct _GET_PARTITION_ATTRIBUTES { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // For alignment purposes. + // + ULONG Reserved1; + + // + // Specifies the partition + // attributes. + // + ULONGLONG Attributes; + +} GET_PARTITION_ATTRIBUTES, *PGET_PARTITION_ATTRIBUTES; + +// +// IOCTL_DISK_SET_PARTITION_ATTRIBUTES +// +// Input Buffer: +// Structure of type SET_PARTITION_ATTRIBUTES +// +// Output Buffer: +// None +// + +typedef struct _SET_PARTITION_ATTRIBUTES { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // Indicates whether to remember + // these settings across reboots + // or not. + // + BOOLEAN Persist; + + // + // For alignment purposes. + // + BOOLEAN Reserved1[3]; + + // + // Specifies the new attributes. + // + ULONGLONG Attributes; + + // + // Specifies the attributes + // that are being modified. + // + ULONGLONG AttributesMask; + +} SET_PARTITION_ATTRIBUTES, *PSET_PARTITION_ATTRIBUTES; + + +// +// IOCTLs to query and modify attributes +// associated with the given disk. These +// are persisted within the registry. +// + +#define IOCTL_DISK_GET_DISK_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003c, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_SET_DISK_ATTRIBUTES CTL_CODE(IOCTL_DISK_BASE, 0x003d, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define DISK_ATTRIBUTE_OFFLINE 0x0000000000000001 +#define DISK_ATTRIBUTE_READ_ONLY 0x0000000000000002 + +// +// IOCTL_DISK_GET_DISK_ATTRIBUTES +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type GET_DISK_ATTRIBUTES +// + +typedef struct _GET_DISK_ATTRIBUTES { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // For alignment purposes. + // + ULONG Reserved1; + + // + // Specifies the attributes + // associated with the disk. + // + ULONGLONG Attributes; + +} GET_DISK_ATTRIBUTES, *PGET_DISK_ATTRIBUTES; + +// +// IOCTL_DISK_SET_DISK_ATTRIBUTES +// +// Input Buffer: +// Structure of type SET_DISK_ATTRIBUTES +// +// Output Buffer: +// None +// + +typedef struct _SET_DISK_ATTRIBUTES { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // Indicates whether to remember + // these settings across reboots + // or not. + // + BOOLEAN Persist; + + // + // Indicates whether the ownership + // taken earlier is being released. + // + BOOLEAN RelinquishOwnership; + + // + // For alignment purposes. + // + BOOLEAN Reserved1[2]; + + // + // Specifies the new attributes. + // + ULONGLONG Attributes; + + // + // Specifies the attributes + // that are being modified. + // + ULONGLONG AttributesMask; + + // + // Specifies an identifier to be + // associated with the caller. + // This setting is not persisted + // across reboots. + // + GUID Owner; + +} SET_DISK_ATTRIBUTES, *PSET_DISK_ATTRIBUTES; + + +// +// IOCTL to determine if the disk is +// owned by the cluster service or not. +// + +#define IOCTL_DISK_IS_CLUSTERED CTL_CODE(IOCTL_DISK_BASE, 0x003e, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// +// IOCTL_DISK_IS_CLUSTERED +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type BOOLEAN +// + + +// +// IOCTLs to query and modify the current +// SAN settings. For instance, the policy +// associated with newly discovered disks. +// + +#define IOCTL_DISK_GET_SAN_SETTINGS CTL_CODE(IOCTL_DISK_BASE, 0x0080, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_SAN_SETTINGS CTL_CODE(IOCTL_DISK_BASE, 0x0081, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTL_DISK_GET_SAN_SETTINGS +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type DISK_SAN_SETTINGS +// + +// +// IOCTL_DISK_SET_SAN_SETTINGS +// +// Input Buffer: +// Structure of type DISK_SAN_SETTINGS +// +// Output Buffer: +// None +// + +typedef enum _DISK_SAN_POLICY { + + DiskSanPolicyUnknown, + DiskSanPolicyOnline, + DiskSanPolicyOfflineShared, + DiskSanPolicyOffline, + DiskSanPolicyMax + +} DISK_SAN_POLICY, *PDISK_SAN_POLICY; + +typedef struct _DISK_SAN_SETTINGS { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // Specifies the policy to be + // applied to all new disks. + // + DISK_SAN_POLICY SanPolicy; + +} DISK_SAN_SETTINGS, *PDISK_SAN_SETTINGS; + + +// +// IOCTLs to query and modify the context +// associated with snapshot disks created +// in hardware. +// + +#define IOCTL_DISK_GET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0082, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0083, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// begin_winioctl + +#define IOCTL_DISK_RESET_SNAPSHOT_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0084, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// end_winioctl + +// +// IOCTL_DISK_GET_SNAPSHOT_INFO +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type DISK_SNAPSHOT_INFO +// + +// +// IOCTL_DISK_SET_SNAPSHOT_INFO +// +// Input Buffer: +// Structure of type DISK_SNAPSHOT_INFO +// +// Output Buffer: +// None +// + +typedef enum _DISK_SNAPSHOT_STATE { + + DiskSnapshotNormalDisk, + DiskSnapshotSnapshotCheckRequired, + DiskSnapshotPreSnapshot, + DiskSnapshotSnapshotDisk + +} DISK_SNAPSHOT_STATE, *PDISK_SNAPSHOT_STATE; + +typedef struct _DISK_SNAPSHOT_INFO { + + // + // Specifies the size of the + // structure for versioning. + // + ULONG Version; + + // + // Specifies the state that this + // disk is in or the state to be + // transitioned to. + // + DISK_SNAPSHOT_STATE State; + + // + // Specifies a unique id that + // represents all of the disks + // involved in this snapshot. + // + GUID SnapshotSetId; + + // + // Specifies a unique id that + // represents this snapshot. + // + GUID SnapshotId; + + // + // Specifies a unique id that + // represents the logical unit + // whose snapshot was taken. + // + GUID LunId; + + // + // Specifies the time when this + // snapshot was taken. + // + LARGE_INTEGER CreationTimeStamp; + + // + // Specifies the number of times + // that this snapshot has been + // imported. + // + ULONG ImportCount; + + // + // Specifies attributes that are + // associated with this snapshot. + // + ULONG Flags; + + // + // Specifies the size in bytes of + // the following field. + // + ULONG AdditionalDataSize; + + // + // Specifies disk meta data that + // needs to be restored in the + // event of a fast recovery. + // + UCHAR AdditionalData[ANYSIZE_ARRAY]; + +} DISK_SNAPSHOT_INFO, *PDISK_SNAPSHOT_INFO; + +#endif // NTDDI_VERSION >= NTDDI_VISTA + + +// +// The following device control code is for the SIMBAD simulated bad +// sector facility. See SIMBAD.H in this directory for related structures. +// + +#define IOCTL_DISK_SIMBAD CTL_CODE(IOCTL_DISK_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// Queue link for mapped addresses stored for unmapping. +// + +typedef struct _MAPPED_ADDRESS { + struct _MAPPED_ADDRESS *NextMappedAddress; + PVOID MappedAddress; + ULONG NumberOfBytes; + LARGE_INTEGER IoAddress; + ULONG BusNumber; +} MAPPED_ADDRESS, *PMAPPED_ADDRESS; + +// begin_winioctl + +#if defined(_MSC_VER) +#if (_MSC_VER >= 1200) +#pragma warning(pop) +#endif +#endif + +// end_winioctl + +#ifdef __cplusplus +} +#endif + +// begin_winioctl + +#endif // _NTDDDISK_H_ + +// end_winioctl + diff --git a/include/winddk/ntddstor.h b/include/winddk/ntddstor.h index 3cdaeaf38f0..ec1535244ad 100644 --- a/include/winddk/ntddstor.h +++ b/include/winddk/ntddstor.h @@ -1,1388 +1,1388 @@ -/*++ BUILD Version: 0001 // Increment this if a change has global effects - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - ntddstor.h - -Abstract: - - This is the include file that defines all common constants and types - accessing the storage class drivers - ---*/ - -#include "devioctl.h" - -// -// Interface GUIDs -// -// need these GUIDs outside conditional includes so that user can -// #include in precompiled header -// #include in a single source file -// #include in that source file a second time to instantiate the GUIDs -// -#ifdef DEFINE_GUID -// -// Make sure FAR is defined... -// -#ifndef FAR -#ifdef _WIN32 -#define FAR -#else -#define FAR _far -#endif -#endif - -// begin_wioctlguids - -DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_CDROM, 0x53f56308L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_PARTITION, 0x53f5630aL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_TAPE, 0x53f5630bL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_WRITEONCEDISK, 0x53f5630cL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_MEDIUMCHANGER, 0x53f56310L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_FLOPPY, 0x53f56311L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_CDCHANGER, 0x53f56312L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); -DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); - -#define WDI_STORAGE_PREDICT_FAILURE_DPS_GUID {0xe9f2d03aL, 0x747c, 0x41c2, {0xbb, 0x9a, 0x02, 0xc6, 0x2b, 0x6d, 0x5f, 0xcb}}; - -// -// The interface used to discover volumes that are -// not reported by Win32 APIs. This includes those -// with an unrecognized partition type/id and ones -// with the hidden attribute. -// -DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME, 0x7f108a28L, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62); - -// end_wioctlguids - -// begin_wioctlobsoleteguids - -#define DiskClassGuid GUID_DEVINTERFACE_DISK -#define CdRomClassGuid GUID_DEVINTERFACE_CDROM -#define PartitionClassGuid GUID_DEVINTERFACE_PARTITION -#define TapeClassGuid GUID_DEVINTERFACE_TAPE -#define WriteOnceDiskClassGuid GUID_DEVINTERFACE_WRITEONCEDISK -#define VolumeClassGuid GUID_DEVINTERFACE_VOLUME -#define MediumChangerClassGuid GUID_DEVINTERFACE_MEDIUMCHANGER -#define FloppyClassGuid GUID_DEVINTERFACE_FLOPPY -#define CdChangerClassGuid GUID_DEVINTERFACE_CDCHANGER -#define StoragePortClassGuid GUID_DEVINTERFACE_STORAGEPORT -#define HiddenVolumeClassGuid GUID_DEVINTERFACE_HIDDEN_VOLUME - -// end_wioctlobsoleteguids -#endif - -// begin_winioctl - -#ifndef _NTDDSTOR_H_ -#define _NTDDSTOR_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// -// IoControlCode values for storage devices -// - -#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE - -// -// The following device control codes are common for all class drivers. They -// should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE -// common codes -// - -#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_STORAGE_EJECTION_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_MCN_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_STORAGE_GET_MEDIA_TYPES CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0304, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_GET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0305, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_SET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0306, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_BREAK_RESERVATION CTL_CODE(IOCTL_STORAGE_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_PERSISTENT_RESERVE_IN CTL_CODE(IOCTL_STORAGE_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_PERSISTENT_RESERVE_OUT CTL_CODE(IOCTL_STORAGE_BASE, 0x0407, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_PREDICT_FAILURE CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_READ_CAPACITY CTL_CODE(IOCTL_STORAGE_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) - -// -// IOCTLs 0x0463 to 0x0468 reserved for dependent disk support. -// - -#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES CTL_CODE(IOCTL_STORAGE_BASE, 0x0501, METHOD_BUFFERED, FILE_WRITE_ACCESS) - -// -// IOCTLs for bandwidth contracts on storage devices -// (Move this to ntddsfio if we decide to use a new base) -// - -#define IOCTL_STORAGE_GET_BC_PROPERTIES CTL_CODE(IOCTL_STORAGE_BASE, 0x0600, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_STORAGE_ALLOCATE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0601, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_STORAGE_FREE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0602, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// IOCTL to check for priority support -// -#define IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT CTL_CODE(IOCTL_STORAGE_BASE, 0x0620, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// begin_winioctl - -// -// These ioctl codes are obsolete. They are defined here to avoid resuing them -// and to allow class drivers to respond to them more easily. -// - -#define OBSOLETE_IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define OBSOLETE_IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -// -// IOCTLs 0x0643 to 0x0655 reserved for VHD disk support. -// - -// -// IOCTL_STORAGE_GET_HOTPLUG_INFO -// - -typedef struct _STORAGE_HOTPLUG_INFO { - ULONG Size; // version - BOOLEAN MediaRemovable; // ie. zip, jaz, cdrom, mo, etc. vs hdd - BOOLEAN MediaHotplug; // ie. does the device succeed a lock even though its not lockable media? - BOOLEAN DeviceHotplug; // ie. 1394, USB, etc. - BOOLEAN WriteCacheEnableOverride; // This field should not be relied upon because it is no longer used -} STORAGE_HOTPLUG_INFO, *PSTORAGE_HOTPLUG_INFO; - -// -// IOCTL_STORAGE_GET_DEVICE_NUMBER -// -// input - none -// -// output - STORAGE_DEVICE_NUMBER structure -// The values in the STORAGE_DEVICE_NUMBER structure are guaranteed -// to remain unchanged until the system is rebooted. They are not -// guaranteed to be persistant across boots. -// - -typedef struct _STORAGE_DEVICE_NUMBER { - - // - // The FILE_DEVICE_XXX type for this device. - // - - DEVICE_TYPE DeviceType; - - // - // The number of this device - // - - ULONG DeviceNumber; - - // - // If the device is partitionable, the partition number of the device. - // Otherwise -1 - // - - ULONG PartitionNumber; -} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER; - -// -// Define the structures for scsi resets -// - -typedef struct _STORAGE_BUS_RESET_REQUEST { - UCHAR PathId; -} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST; - -// -// Break reservation is sent to the Adapter/FDO with the given lun information. -// - -typedef struct STORAGE_BREAK_RESERVATION_REQUEST { - ULONG Length; - UCHAR _unused; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; -} STORAGE_BREAK_RESERVATION_REQUEST, *PSTORAGE_BREAK_RESERVATION_REQUEST; - - -// -// IOCTL_STORAGE_MEDIA_REMOVAL disables the mechanism -// on a storage device that ejects media. This function -// may or may not be supported on storage devices that -// support removable media. -// -// TRUE means prevent media from being removed. -// FALSE means allow media removal. -// - -typedef struct _PREVENT_MEDIA_REMOVAL { - BOOLEAN PreventMediaRemoval; -} PREVENT_MEDIA_REMOVAL, *PPREVENT_MEDIA_REMOVAL; - - - -// -// This is the format of TARGET_DEVICE_CUSTOM_NOTIFICATION.CustomDataBuffer -// passed to applications by the classpnp autorun code (via IoReportTargetDeviceChangeAsynchronous). -// -typedef struct _CLASS_MEDIA_CHANGE_CONTEXT { - ULONG MediaChangeCount; - ULONG NewState; // see MEDIA_CHANGE_DETECTION_STATE enum in classpnp.h in DDK -} CLASS_MEDIA_CHANGE_CONTEXT, *PCLASS_MEDIA_CHANGE_CONTEXT; - - -// begin_ntminitape - - -typedef struct _TAPE_STATISTICS { - ULONG Version; - ULONG Flags; - LARGE_INTEGER RecoveredWrites; - LARGE_INTEGER UnrecoveredWrites; - LARGE_INTEGER RecoveredReads; - LARGE_INTEGER UnrecoveredReads; - UCHAR CompressionRatioReads; - UCHAR CompressionRatioWrites; -} TAPE_STATISTICS, *PTAPE_STATISTICS; - -#define RECOVERED_WRITES_VALID 0x00000001 -#define UNRECOVERED_WRITES_VALID 0x00000002 -#define RECOVERED_READS_VALID 0x00000004 -#define UNRECOVERED_READS_VALID 0x00000008 -#define WRITE_COMPRESSION_INFO_VALID 0x00000010 -#define READ_COMPRESSION_INFO_VALID 0x00000020 - -typedef struct _TAPE_GET_STATISTICS { - ULONG Operation; -} TAPE_GET_STATISTICS, *PTAPE_GET_STATISTICS; - -#define TAPE_RETURN_STATISTICS 0L -#define TAPE_RETURN_ENV_INFO 1L -#define TAPE_RESET_STATISTICS 2L - -// -// IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO -// structures, one per supported type, embedded in the GET_MEDIA_TYPES struct. -// - -typedef enum _STORAGE_MEDIA_TYPE { - // - // Following are defined in ntdddisk.h in the MEDIA_TYPE enum - // - // Unknown, // Format is unknown - // F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector - // F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector - // F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector - // F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector - // F3_720_512, // 3.5", 720KB, 512 bytes/sector - // F5_360_512, // 5.25", 360KB, 512 bytes/sector - // F5_320_512, // 5.25", 320KB, 512 bytes/sector - // F5_320_1024, // 5.25", 320KB, 1024 bytes/sector - // F5_180_512, // 5.25", 180KB, 512 bytes/sector - // F5_160_512, // 5.25", 160KB, 512 bytes/sector - // RemovableMedia, // Removable media other than floppy - // FixedMedia, // Fixed hard disk media - // F3_120M_512, // 3.5", 120M Floppy - // F3_640_512, // 3.5" , 640KB, 512 bytes/sector - // F5_640_512, // 5.25", 640KB, 512 bytes/sector - // F5_720_512, // 5.25", 720KB, 512 bytes/sector - // F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector - // F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector - // F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector - // F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector - // F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector - // F8_256_128, // 8", 256KB, 128 bytes/sector - // F3_200Mb_512, // 3.5", 200M Floppy (HiFD) - // - - DDS_4mm = 0x20, // Tape - DAT DDS1,2,... (all vendors) - MiniQic, // Tape - miniQIC Tape - Travan, // Tape - Travan TR-1,2,3,... - QIC, // Tape - QIC - MP_8mm, // Tape - 8mm Exabyte Metal Particle - AME_8mm, // Tape - 8mm Exabyte Advanced Metal Evap - AIT1_8mm, // Tape - 8mm Sony AIT - DLT, // Tape - DLT Compact IIIxt, IV - NCTP, // Tape - Philips NCTP - IBM_3480, // Tape - IBM 3480 - IBM_3490E, // Tape - IBM 3490E - IBM_Magstar_3590, // Tape - IBM Magstar 3590 - IBM_Magstar_MP, // Tape - IBM Magstar MP - STK_DATA_D3, // Tape - STK Data D3 - SONY_DTF, // Tape - Sony DTF - DV_6mm, // Tape - 6mm Digital Video - DMI, // Tape - Exabyte DMI and compatibles - SONY_D2, // Tape - Sony D2S and D2L - CLEANER_CARTRIDGE, // Cleaner - All Drive types that support Drive Cleaners - CD_ROM, // Opt_Disk - CD - CD_R, // Opt_Disk - CD-Recordable (Write Once) - CD_RW, // Opt_Disk - CD-Rewriteable - DVD_ROM, // Opt_Disk - DVD-ROM - DVD_R, // Opt_Disk - DVD-Recordable (Write Once) - DVD_RW, // Opt_Disk - DVD-Rewriteable - MO_3_RW, // Opt_Disk - 3.5" Rewriteable MO Disk - MO_5_WO, // Opt_Disk - MO 5.25" Write Once - MO_5_RW, // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW) - MO_5_LIMDOW, // Opt_Disk - MO 5.25" Rewriteable (LIMDOW) - PC_5_WO, // Opt_Disk - Phase Change 5.25" Write Once Optical - PC_5_RW, // Opt_Disk - Phase Change 5.25" Rewriteable - PD_5_RW, // Opt_Disk - PhaseChange Dual Rewriteable - ABL_5_WO, // Opt_Disk - Ablative 5.25" Write Once Optical - PINNACLE_APEX_5_RW, // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical - SONY_12_WO, // Opt_Disk - Sony 12" Write Once - PHILIPS_12_WO, // Opt_Disk - Philips/LMS 12" Write Once - HITACHI_12_WO, // Opt_Disk - Hitachi 12" Write Once - CYGNET_12_WO, // Opt_Disk - Cygnet/ATG 12" Write Once - KODAK_14_WO, // Opt_Disk - Kodak 14" Write Once - MO_NFR_525, // Opt_Disk - Near Field Recording (Terastor) - NIKON_12_RW, // Opt_Disk - Nikon 12" Rewriteable - IOMEGA_ZIP, // Mag_Disk - Iomega Zip - IOMEGA_JAZ, // Mag_Disk - Iomega Jaz - SYQUEST_EZ135, // Mag_Disk - Syquest EZ135 - SYQUEST_EZFLYER, // Mag_Disk - Syquest EzFlyer - SYQUEST_SYJET, // Mag_Disk - Syquest SyJet - AVATAR_F2, // Mag_Disk - 2.5" Floppy - MP2_8mm, // Tape - 8mm Hitachi - DST_S, // Ampex DST Small Tapes - DST_M, // Ampex DST Medium Tapes - DST_L, // Ampex DST Large Tapes - VXATape_1, // Ecrix 8mm Tape - VXATape_2, // Ecrix 8mm Tape -#if (NTDDI_VERSION < NTDDI_WINXP) - STK_EAGLE, // STK Eagle -#else - STK_9840, // STK 9840 -#endif - LTO_Ultrium, // IBM, HP, Seagate LTO Ultrium - LTO_Accelis, // IBM, HP, Seagate LTO Accelis - DVD_RAM, // Opt_Disk - DVD-RAM - AIT_8mm, // AIT2 or higher - ADR_1, // OnStream ADR Mediatypes - ADR_2, - STK_9940, // STK 9940 - SAIT, // SAIT Tapes - VXATape // VXA (Ecrix 8mm) Tape -}STORAGE_MEDIA_TYPE, *PSTORAGE_MEDIA_TYPE; - -#define MEDIA_ERASEABLE 0x00000001 -#define MEDIA_WRITE_ONCE 0x00000002 -#define MEDIA_READ_ONLY 0x00000004 -#define MEDIA_READ_WRITE 0x00000008 - -#define MEDIA_WRITE_PROTECTED 0x00000100 -#define MEDIA_CURRENTLY_MOUNTED 0x80000000 - -// -// Define the different storage bus types -// Bus types below 128 (0x80) are reserved for Microsoft use -// - -typedef enum _STORAGE_BUS_TYPE { - BusTypeUnknown = 0x00, - BusTypeScsi, - BusTypeAtapi, - BusTypeAta, - BusType1394, - BusTypeSsa, - BusTypeFibre, - BusTypeUsb, - BusTypeRAID, - BusTypeiScsi, - BusTypeSas, - BusTypeSata, - BusTypeSd, - BusTypeMmc, - BusTypeVirtual, - BusTypeFileBackedVirtual, - BusTypeMax, - BusTypeMaxReserved = 0x7F -} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; - -typedef struct _DEVICE_MEDIA_INFO { - union { - struct { - LARGE_INTEGER Cylinders; - STORAGE_MEDIA_TYPE MediaType; - ULONG TracksPerCylinder; - ULONG SectorsPerTrack; - ULONG BytesPerSector; - ULONG NumberMediaSides; - ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. - } DiskInfo; - - struct { - LARGE_INTEGER Cylinders; - STORAGE_MEDIA_TYPE MediaType; - ULONG TracksPerCylinder; - ULONG SectorsPerTrack; - ULONG BytesPerSector; - ULONG NumberMediaSides; - ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. - } RemovableDiskInfo; - - struct { - STORAGE_MEDIA_TYPE MediaType; - ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. - ULONG CurrentBlockSize; - STORAGE_BUS_TYPE BusType; - - // - // Bus specific information describing the medium supported. - // - - union { - struct { - UCHAR MediumType; - UCHAR DensityCode; - } ScsiInformation; - } BusSpecificData; - - } TapeInfo; - } DeviceSpecific; -} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO; - -typedef struct _GET_MEDIA_TYPES { - ULONG DeviceType; // FILE_DEVICE_XXX values - ULONG MediaInfoCount; - DEVICE_MEDIA_INFO MediaInfo[1]; -} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES; - - -// -// IOCTL_STORAGE_PREDICT_FAILURE -// -// input - none -// -// output - STORAGE_PREDICT_FAILURE structure -// PredictFailure returns zero if no failure predicted and non zero -// if a failure is predicted. -// -// VendorSpecific returns 512 bytes of vendor specific information -// if a failure is predicted -// -typedef struct _STORAGE_PREDICT_FAILURE -{ - ULONG PredictFailure; - UCHAR VendorSpecific[512]; -} STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE; - -// end_ntminitape - -// -// Property Query Structures -// - -// -// IOCTL_STORAGE_QUERY_PROPERTY -// -// Input Buffer: -// a STORAGE_PROPERTY_QUERY structure which describes what type of query -// is being done, what property is being queried for, and any additional -// parameters which a particular property query requires. -// -// Output Buffer: -// Contains a buffer to place the results of the query into. Since all -// property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER, -// the IOCTL can be called once with a small buffer then again using -// a buffer as large as the header reports is necessary. -// - - -// -// Types of queries -// - -typedef enum _STORAGE_QUERY_TYPE { - PropertyStandardQuery = 0, // Retrieves the descriptor - PropertyExistsQuery, // Used to test whether the descriptor is supported - PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor - PropertyQueryMaxDefined // use to validate the value -} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; - -// -// define some initial property id's -// - -typedef enum _STORAGE_PROPERTY_ID { - StorageDeviceProperty = 0, - StorageAdapterProperty, - StorageDeviceIdProperty, - StorageDeviceUniqueIdProperty, // See storduid.h for details - StorageDeviceWriteCacheProperty, - StorageMiniportProperty, - StorageAccessAlignmentProperty, - StorageDeviceSeekPenaltyProperty, - StorageDeviceTrimProperty, - StorageDeviceWriteAggregationProperty -} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; - -// -// Query structure - additional parameters for specific queries can follow -// the header -// - -typedef struct _STORAGE_PROPERTY_QUERY { - - // - // ID of the property being retrieved - // - - STORAGE_PROPERTY_ID PropertyId; - - // - // Flags indicating the type of query being performed - // - - STORAGE_QUERY_TYPE QueryType; - - // - // Space for additional parameters if necessary - // - - UCHAR AdditionalParameters[1]; - -} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY; - -// -// Standard property descriptor header. All property pages should use this -// as their first element or should contain these two elements -// - -typedef __struct_bcount(Size) struct _STORAGE_DESCRIPTOR_HEADER { - - ULONG Version; - - ULONG Size; - -} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER; - -// -// Device property descriptor - this is really just a rehash of the inquiry -// data retrieved from a scsi device -// -// This may only be retrieved from a target device. Sending this to the bus -// will result in an error -// - -typedef __struct_bcount(Size) struct _STORAGE_DEVICE_DESCRIPTOR { - - // - // Sizeof(STORAGE_DEVICE_DESCRIPTOR) - // - - ULONG Version; - - // - // Total size of the descriptor, including the space for additional - // data and id strings - // - - ULONG Size; - - // - // The SCSI-2 device type - // - - UCHAR DeviceType; - - // - // The SCSI-2 device type modifier (if any) - this may be zero - // - - UCHAR DeviceTypeModifier; - - // - // Flag indicating whether the device's media (if any) is removable. This - // field should be ignored for media-less devices - // - - BOOLEAN RemovableMedia; - - // - // Flag indicating whether the device can support mulitple outstanding - // commands. The actual synchronization in this case is the responsibility - // of the port driver. - // - - BOOLEAN CommandQueueing; - - // - // Byte offset to the zero-terminated ascii string containing the device's - // vendor id string. For devices with no such ID this will be zero - // - - ULONG VendorIdOffset; - - // - // Byte offset to the zero-terminated ascii string containing the device's - // product id string. For devices with no such ID this will be zero - // - - ULONG ProductIdOffset; - - // - // Byte offset to the zero-terminated ascii string containing the device's - // product revision string. For devices with no such string this will be - // zero - // - - ULONG ProductRevisionOffset; - - // - // Byte offset to the zero-terminated ascii string containing the device's - // serial number. For devices with no serial number this will be zero - // - - ULONG SerialNumberOffset; - - // - // Contains the bus type (as defined above) of the device. It should be - // used to interpret the raw device properties at the end of this structure - // (if any) - // - - STORAGE_BUS_TYPE BusType; - - // - // The number of bytes of bus-specific data which have been appended to - // this descriptor - // - - ULONG RawPropertiesLength; - - // - // Place holder for the first byte of the bus specific property data - // - - UCHAR RawDeviceProperties[1]; - -} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR; - - -// -// Adapter properties -// -// This descriptor can be retrieved from a target device object of from the -// device object for the bus. Retrieving from the target device object will -// forward the request to the underlying bus -// - -typedef __struct_bcount(Size) struct _STORAGE_ADAPTER_DESCRIPTOR { - - ULONG Version; - - ULONG Size; - - ULONG MaximumTransferLength; - - ULONG MaximumPhysicalPages; - - ULONG AlignmentMask; - - BOOLEAN AdapterUsesPio; - - BOOLEAN AdapterScansDown; - - BOOLEAN CommandQueueing; - - BOOLEAN AcceleratedTransfer; - -#if (NTDDI_VERSION < NTDDI_WINXP) - BOOLEAN BusType; -#else - UCHAR BusType; -#endif - - USHORT BusMajorVersion; - - USHORT BusMinorVersion; - -} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR; - -typedef __struct_bcount(Size) struct _STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR { - - // - // Sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) - // - - ULONG Version; - - // - // Total size of the descriptor, including the space for additional - // data and id strings - // - - ULONG Size; - - // - // The number of bytes in a cache line of the device - // - - ULONG BytesPerCacheLine; - - // - // The address offset neccessary for proper cache access alignment in bytes - // - - ULONG BytesOffsetForCacheAlignment; - - // - // The number of bytes in a physical sector of the device - // - - ULONG BytesPerLogicalSector; - - // - // The number of bytes in an addressable logical sector (LBA)of the device - // - - ULONG BytesPerPhysicalSector; - - // - // The address offset neccessary for proper sector access alignment in bytes - // - - ULONG BytesOffsetForSectorAlignment; - -} STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR, *PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR; - - - -typedef enum _STORAGE_PORT_CODE_SET { - StoragePortCodeSetReserved = 0, - StoragePortCodeSetStorport = 1, - StoragePortCodeSetSCSIport = 2 -} STORAGE_PORT_CODE_SET, *PSTORAGE_PORT_CODE_SET; - -typedef struct _STORAGE_MINIPORT_DESCRIPTOR { - - ULONG Version; - - ULONG Size; - - STORAGE_PORT_CODE_SET Portdriver; - - BOOLEAN LUNResetSupported; - - BOOLEAN TargetResetSupported; - - -} STORAGE_MINIPORT_DESCRIPTOR, *PSTORAGE_MINIPORT_DESCRIPTOR; - -// -// Storage identification descriptor. -// The definitions here are based on the SCSI/SBP vital product data -// device identifier page. -// - -typedef enum _STORAGE_IDENTIFIER_CODE_SET { - StorageIdCodeSetReserved = 0, - StorageIdCodeSetBinary = 1, - StorageIdCodeSetAscii = 2, - StorageIdCodeSetUtf8 = 3 -} STORAGE_IDENTIFIER_CODE_SET, *PSTORAGE_IDENTIFIER_CODE_SET; - -typedef enum _STORAGE_IDENTIFIER_TYPE { - StorageIdTypeVendorSpecific = 0, - StorageIdTypeVendorId = 1, - StorageIdTypeEUI64 = 2, - StorageIdTypeFCPHName = 3, - StorageIdTypePortRelative = 4, - StorageIdTypeTargetPortGroup = 5, - StorageIdTypeLogicalUnitGroup = 6, - StorageIdTypeMD5LogicalUnitIdentifier = 7, - StorageIdTypeScsiNameString = 8 -} STORAGE_IDENTIFIER_TYPE, *PSTORAGE_IDENTIFIER_TYPE; - -// Mislabeled above but need to keep it for backwards compatibility -#define StorageIdTypeNAA StorageIdTypeFCPHName - -// NAA formats (Used with StorageIdTypeNAA) -typedef enum _STORAGE_ID_NAA_FORMAT { - StorageIdNAAFormatIEEEExtended = 2, - StorageIdNAAFormatIEEERegistered = 3, - StorageIdNAAFormatIEEEERegisteredExtended = 5 -} STORAGE_ID_NAA_FORMAT, *PSTORAGE_ID_NAA_FORMAT; - -typedef enum _STORAGE_ASSOCIATION_TYPE { - StorageIdAssocDevice = 0, - StorageIdAssocPort = 1, - StorageIdAssocTarget = 2 -} STORAGE_ASSOCIATION_TYPE, *PSTORAGE_ASSOCIATION_TYPE; - -typedef struct _STORAGE_IDENTIFIER { - STORAGE_IDENTIFIER_CODE_SET CodeSet; - STORAGE_IDENTIFIER_TYPE Type; - USHORT IdentifierSize; - USHORT NextOffset; - - // - // Add new fields here since existing code depends on - // the above layout not changing. - // - - STORAGE_ASSOCIATION_TYPE Association; - - // - // The identifier is a variable length array of bytes. - // - - UCHAR Identifier[1]; -} STORAGE_IDENTIFIER, *PSTORAGE_IDENTIFIER; - -typedef __struct_bcount(Size) struct _STORAGE_DEVICE_ID_DESCRIPTOR { - - ULONG Version; - - ULONG Size; - - // - // The number of identifiers reported by the device. - // - - ULONG NumberOfIdentifiers; - - // - // The following field is actually a variable length array of identification - // descriptors. Unfortunately there's no C notation for an array of - // variable length structures so we're forced to just pretend. - // - - UCHAR Identifiers[1]; -} STORAGE_DEVICE_ID_DESCRIPTOR, *PSTORAGE_DEVICE_ID_DESCRIPTOR; - -// output buffer for StorageDeviceSeekPenaltyProperty & PropertyStandardQuery -typedef struct _DEVICE_SEEK_PENALTY_DESCRIPTOR { - ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER - ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER - - BOOLEAN IncursSeekPenalty; -} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR; - -// output buffer for StorageDeviceWriteAggregationProperty & PropertyStandardQuery -typedef struct _DEVICE_WRITE_AGGREGATION_DESCRIPTOR { - ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER - ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER - - BOOLEAN BenefitsFromWriteAggregation; -} DEVICE_WRITE_AGGREGATION_DESCRIPTOR, *PDEVICE_WRITE_AGGREGATION_DESCRIPTOR; - -// output buffer for StorageDeviceTrimProperty & PropertyStandardQuery -typedef struct _DEVICE_TRIM_DESCRIPTOR { - ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER - ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER - - BOOLEAN TrimEnabled; -} DEVICE_TRIM_DESCRIPTOR, *PDEVICE_TRIM_DESCRIPTOR; - -// -// IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES -// -// Input Buffer: -// Structure of type DEVICE_MANAGE_DATA_SET_ATTRIBUTES -// -// Output Buffer: -// N/A -// -// Note: -// 1. Management of action Trim will be only allowed for kernel request. -// This request sent from user application will be rejected by kernel drivers. -// - -// -// This flag, when OR'd into an action indicates that the given action is -// non-destructive. If this flag is set then storage stack components which -// do not understand the action should forward the given request -// - -#define DeviceDsmActionFlag_NonDestructive 0x80000000 - -#define IsDsmActionNonDestructive(_Action) ((BOOLEAN)((_Action & DeviceDsmActionFlag_NonDestructive) != 0)) - -// -// Defines the various actions -// - -typedef ULONG DEVICE_DATA_MANAGEMENT_SET_ACTION; - #define DeviceDsmAction_None 0 - #define DeviceDsmAction_Trim 1 - #define DeviceDsmAction_Notification (2 | DeviceDsmActionFlag_NonDestructive) - -// -// Flags that are global across all actions -// - -#define DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE 0x00000001 // If set, the DataSetRanges fields should be 0 - - -typedef struct _DEVICE_DATA_SET_RANGE { - LONGLONG StartingOffset; //in bytes , must allign to sector - ULONGLONG LengthInBytes; // multiple of sector size. -} DEVICE_DATA_SET_RANGE, *PDEVICE_DATA_SET_RANGE; - -// -// input structure for IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES -// 1. Value ofParameterBlockOffset or ParameterBlockLength is 0 indicates that Parameter Block does not exist. -// 2. Value of DataSetRangesOffset or DataSetRangesLength is 0 indicates that DataSetRanges Block does not exist. -// If DataSetRanges Block exists, it contains contiguous DEVICE_DATA_SET_RANGE structures. -// 3. The total size of buffer should be at least: -// sizeof (DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + ParameterBlockLength + DataSetRangesLength -// -typedef struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES { - ULONG Size; // Size of structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES - DEVICE_DATA_MANAGEMENT_SET_ACTION Action; - - ULONG Flags; // Global flags across all actions - - ULONG ParameterBlockOffset; // must be alligned to corresponding structure allignment - ULONG ParameterBlockLength; // 0 means Parameter Block does not exist. - - ULONG DataSetRangesOffset; // must be alligned to DEVICE_DATA_SET_RANGE structure allignment. - ULONG DataSetRangesLength; // 0 means DataSetRanges Block does not exist. - -} DEVICE_MANAGE_DATA_SET_ATTRIBUTES, *PDEVICE_MANAGE_DATA_SET_ATTRIBUTES; - -// -// This defines the parameter block for the DeviceDsmAction_Notification -// action -// - -typedef struct _DEVICE_DSM_NOTIFICATION_PARAMETERS { - - ULONG Size; // Size of this structure - - ULONG Flags; // Flags specific to the notify operation - - ULONG NumFileTypeIDs; // Count of how many file type ID's are given - - GUID FileTypeID[1]; // Identifier for the type of file being notified - -} DEVICE_DSM_NOTIFICATION_PARAMETERS, *PDEVICE_DSM_NOTIFICATION_PARAMETERS; - -// -// DEVICE_DSM_NOTIFICATION_PARAMETERS flag definitions -// - -#define DEVICE_DSM_NOTIFY_FLAG_BEGIN 0x00000001 // The given LBA range is being used as defined by the FileID -#define DEVICE_DSM_NOTIFY_FLAG_END 0x00000002 // The given LBA range is no longer being used as defined by the FileID - -// -// There are some well known GUIDS for certail types of files. They are -// defined in NTIFS.H -// - - -// -// IOCTL_STORAGE_GET_BC_PROPERTIES -// -// Input Buffer: -// None -// -// Output Buffer: -// Structure of type STORAGE_GET_BC_PROPERTIES_OUTPUT -// - -typedef struct _STORAGE_GET_BC_PROPERTIES_OUTPUT { - - // - // Specifies the maximum number of requests - // that can be scheduled per period of time - // - ULONG MaximumRequestsPerPeriod; - - // - // Specifies the minimum period that the - // device uses when scheduling requests - // - ULONG MinimumPeriod; - - // - // Specifies the maximum transfer size supported - // for bandwidth contracts on this device. To - // achieve the highest level of performance, all - // requests should be of this size - // - ULONGLONG MaximumRequestSize; - - // - // Specifies the estimated time taken to - // perform an Io operstion. This field - // is for informational purposes only - // - ULONG EstimatedTimePerRequest; - - // - // Specifies the number of requests that should be - // kept outstanding. This helps keep the device - // device busy and thus obtain maximum throughput. - // This will only be filled in if the target file - // has an outstanding contract. - // - ULONG NumOutStandingRequests; - - // - // Specifies the required size of requests in this - // stream. This will only be filled in if the - // target file has an outstanding contract. - // - ULONGLONG RequestSize; - -} STORAGE_GET_BC_PROPERTIES_OUTPUT, *PSTORAGE_GET_BC_PROPERTIES_OUTPUT; - - -// -// IOCTL_STORAGE_ALLOCATE_BC_STREAM -// -// Input Buffer: -// Structure of type STORAGE_ALLOCATE_BC_STREAM_INPUT -// -// Output Buffer: -// Structure of type STORAGE_ALLOCATE_BC_STREAM_OUTPUT -// - - -// -// Current version -// -#define IOCTL_STORAGE_BC_VERSION 1 - -typedef struct _STORAGE_ALLOCATE_BC_STREAM_INPUT { - - // - // Specifies the corresponding structure version - // - ULONG Version; - - // - // Specifies the number of requests that - // need to complete per period of time - // - ULONG RequestsPerPeriod; - - // - // Specifies the period of time wherein the - // above number of requests must complete - // - ULONG Period; - - // - // Indicates whether failures - // should be retried or not - // - BOOLEAN RetryFailures; - - // - // Indicates whether reqests that will miss - // their deadline should be discarded or not - // - BOOLEAN Discardable; - - // - // Helps align the following field - // - BOOLEAN Reserved1[2]; - - // - // Indicates whether the Io will be - // comprised of reads, writes or both - // - ULONG AccessType; - - // - // Indicates whether the Io to the - // file will be sequential or random - // - ULONG AccessMode; - -} STORAGE_ALLOCATE_BC_STREAM_INPUT, *PSTORAGE_ALLOCATE_BC_STREAM_INPUT; - -typedef struct _STORAGE_ALLOCATE_BC_STREAM_OUTPUT { - - // - // Specifies the required size - // of requests in this stream - // - ULONGLONG RequestSize; - - // - // Specifies the number of requests that should be - // kept outstanding. This helps keep the device - // device busy and thus obtain maximum throughput - // - ULONG NumOutStandingRequests; - -} STORAGE_ALLOCATE_BC_STREAM_OUTPUT, *PSTORAGE_ALLOCATE_BC_STREAM_OUTPUT; - - -// -// IOCTL_STORAGE_FREE_BC_STREAM -// -// Input Buffer: -// None -// -// Output Buffer: -// None -// - -// -// IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT -// -// Input Buffer : -// None -// Output Buffer : -// Structure of type STORAGE_PRIORITY_HINT_SUPPORT -// - -#define STORAGE_PRIORITY_HINT_SUPPORTED 0x0001 - -typedef struct _STORAGE_PRIORITY_HINT_SUPPORT { - ULONG SupportFlags; -} STORAGE_PRIORITY_HINT_SUPPORT, *PSTORAGE_PRIORITY_HINT_SUPPORT; - -#pragma warning(push) -#pragma warning(disable:4200) - -#if defined(_MSC_EXTENSIONS) - -typedef struct _STORAGE_MEDIA_SERIAL_NUMBER_DATA { - - USHORT Reserved; - - // - // the SerialNumberLength will be set to zero - // if the command is supported and the media - // does not have a valid serial number. - // - - USHORT SerialNumberLength; - - // - // the following data is binary, and is not guaranteed - // to be NULL terminated. this is an excercise for the - // caller. - // - -#if !defined(__midl) - UCHAR SerialNumber[0]; -#endif - -} STORAGE_MEDIA_SERIAL_NUMBER_DATA, *PSTORAGE_MEDIA_SERIAL_NUMBER_DATA; - -#endif /* _MSC_EXTENSIONS */ - -typedef __struct_bcount(Size) struct _STORAGE_READ_CAPACITY { - - // - // The version number, size of the STORAGE_READ_CAPACITY structure - // - ULONG Version; - - // - // The size of the date returned, size of the STORAGE_READ_CAPACITY structure - // - ULONG Size; - - // - // Number of bytes per block - // - - ULONG BlockLength; - - // - // Total number of blocks in the disk - // This will have the last LBA + 1 - // - - LARGE_INTEGER NumberOfBlocks; - - // - // Disk size in bytes - // - - LARGE_INTEGER DiskLength; - -} STORAGE_READ_CAPACITY, *PSTORAGE_READ_CAPACITY; - -#pragma warning(pop) - -// -// Device write cache property -// -// This property provides the write cache information -// about the target device. -// - -typedef enum _WRITE_CACHE_TYPE { - WriteCacheTypeUnknown, - WriteCacheTypeNone, - WriteCacheTypeWriteBack, - WriteCacheTypeWriteThrough -} WRITE_CACHE_TYPE; - -typedef enum _WRITE_CACHE_ENABLE { - WriteCacheEnableUnknown, - WriteCacheDisabled, - WriteCacheEnabled -} WRITE_CACHE_ENABLE; - -typedef enum _WRITE_CACHE_CHANGE { - WriteCacheChangeUnknown, - WriteCacheNotChangeable, - WriteCacheChangeable -} WRITE_CACHE_CHANGE; - -typedef enum _WRITE_THROUGH { - WriteThroughUnknown, - WriteThroughNotSupported, - WriteThroughSupported -} WRITE_THROUGH; - -typedef __struct_bcount(Size) struct _STORAGE_WRITE_CACHE_PROPERTY { - - // - // The version number - // Size of STORAGE_WRITE_CACHE_PROPERTY structure - // - ULONG Version; - - // - // The size of the date returned - // Size of STORAGE_WRITE_CACHE_PROPERTY structure - // - ULONG Size; - - // - // Current write cache type - // - WRITE_CACHE_TYPE WriteCacheType; - - // - // Current write cache value - // - WRITE_CACHE_ENABLE WriteCacheEnabled; - - // - // Device write cache change capability - // - WRITE_CACHE_CHANGE WriteCacheChangeable; - - // - // Device write through support capability - // - WRITE_THROUGH WriteThroughSupported; - - // - // Device flush cache capability - // - BOOLEAN FlushCacheSupported; - - // - // User selected power protection option through registry - // - BOOLEAN UserDefinedPowerProtection; - - // - // Device has battery backup for write cache - // - BOOLEAN NVCacheEnabled; - -} STORAGE_WRITE_CACHE_PROPERTY, *PSTORAGE_WRITE_CACHE_PROPERTY; - -#pragma warning(push) -#pragma warning(disable:4200) // array[0] -#pragma warning(disable:4201) // nameless struct/unions -#pragma warning(disable:4214) // bit fields other than int -#if defined(__INTEL_COMPILER) -#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero -#endif - - -#if defined(_MSC_EXTENSIONS) - -typedef struct _PERSISTENT_RESERVE_COMMAND { - - ULONG Version; - ULONG Size; - - union { - - struct { - - // - // Persistent Reserve service action. - // - - UCHAR ServiceAction : 5; - UCHAR Reserved1 : 3; - - // - // Number of bytes allocated for returned parameter list. - // - - USHORT AllocationLength; - - } PR_IN; - - struct { - - // - // Persistent Reserve service action. - // - - UCHAR ServiceAction : 5; - UCHAR Reserved1 : 3; - - // - // Persistent Reserve type and scope. - // - - UCHAR Type : 4; - UCHAR Scope : 4; - - // - // Space for additional PR Out parameters. - // - -#if !defined(__midl) - UCHAR ParameterList[0]; -#endif - - } PR_OUT; - }; - -} PERSISTENT_RESERVE_COMMAND, *PPERSISTENT_RESERVE_COMMAND; - -#endif /* _MSC_EXTENSIONS */ -#pragma warning(pop) - - -#ifdef __cplusplus -} -#endif - -#endif // _NTDDSTOR_H_ -// end_winioctl - +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ntddstor.h + +Abstract: + + This is the include file that defines all common constants and types + accessing the storage class drivers + +--*/ + +#include "devioctl.h" + +// +// Interface GUIDs +// +// need these GUIDs outside conditional includes so that user can +// #include in precompiled header +// #include in a single source file +// #include in that source file a second time to instantiate the GUIDs +// +#ifdef DEFINE_GUID +// +// Make sure FAR is defined... +// +#ifndef FAR +#ifdef _WIN32 +#define FAR +#else +#define FAR _far +#endif +#endif + +// begin_wioctlguids + +DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_CDROM, 0x53f56308L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_PARTITION, 0x53f5630aL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_TAPE, 0x53f5630bL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_WRITEONCEDISK, 0x53f5630cL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_MEDIUMCHANGER, 0x53f56310L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_FLOPPY, 0x53f56311L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_CDCHANGER, 0x53f56312L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); +DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); + +#define WDI_STORAGE_PREDICT_FAILURE_DPS_GUID {0xe9f2d03aL, 0x747c, 0x41c2, {0xbb, 0x9a, 0x02, 0xc6, 0x2b, 0x6d, 0x5f, 0xcb}}; + +// +// The interface used to discover volumes that are +// not reported by Win32 APIs. This includes those +// with an unrecognized partition type/id and ones +// with the hidden attribute. +// +DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME, 0x7f108a28L, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62); + +// end_wioctlguids + +// begin_wioctlobsoleteguids + +#define DiskClassGuid GUID_DEVINTERFACE_DISK +#define CdRomClassGuid GUID_DEVINTERFACE_CDROM +#define PartitionClassGuid GUID_DEVINTERFACE_PARTITION +#define TapeClassGuid GUID_DEVINTERFACE_TAPE +#define WriteOnceDiskClassGuid GUID_DEVINTERFACE_WRITEONCEDISK +#define VolumeClassGuid GUID_DEVINTERFACE_VOLUME +#define MediumChangerClassGuid GUID_DEVINTERFACE_MEDIUMCHANGER +#define FloppyClassGuid GUID_DEVINTERFACE_FLOPPY +#define CdChangerClassGuid GUID_DEVINTERFACE_CDCHANGER +#define StoragePortClassGuid GUID_DEVINTERFACE_STORAGEPORT +#define HiddenVolumeClassGuid GUID_DEVINTERFACE_HIDDEN_VOLUME + +// end_wioctlobsoleteguids +#endif + +// begin_winioctl + +#ifndef _NTDDSTOR_H_ +#define _NTDDSTOR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// +// IoControlCode values for storage devices +// + +#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE + +// +// The following device control codes are common for all class drivers. They +// should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE +// common codes +// + +#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_STORAGE_EJECTION_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MCN_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_STORAGE_GET_MEDIA_TYPES CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0304, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0305, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_SET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0306, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_BREAK_RESERVATION CTL_CODE(IOCTL_STORAGE_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_PERSISTENT_RESERVE_IN CTL_CODE(IOCTL_STORAGE_BASE, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_PERSISTENT_RESERVE_OUT CTL_CODE(IOCTL_STORAGE_BASE, 0x0407, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_PREDICT_FAILURE CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_READ_CAPACITY CTL_CODE(IOCTL_STORAGE_BASE, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS) + +// +// IOCTLs 0x0463 to 0x0468 reserved for dependent disk support. +// + +#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES CTL_CODE(IOCTL_STORAGE_BASE, 0x0501, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +// +// IOCTLs for bandwidth contracts on storage devices +// (Move this to ntddsfio if we decide to use a new base) +// + +#define IOCTL_STORAGE_GET_BC_PROPERTIES CTL_CODE(IOCTL_STORAGE_BASE, 0x0600, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_ALLOCATE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0601, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_STORAGE_FREE_BC_STREAM CTL_CODE(IOCTL_STORAGE_BASE, 0x0602, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTL to check for priority support +// +#define IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT CTL_CODE(IOCTL_STORAGE_BASE, 0x0620, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// begin_winioctl + +// +// These ioctl codes are obsolete. They are defined here to avoid resuing them +// and to allow class drivers to respond to them more easily. +// + +#define OBSOLETE_IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define OBSOLETE_IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +// +// IOCTLs 0x0643 to 0x0655 reserved for VHD disk support. +// + +// +// IOCTL_STORAGE_GET_HOTPLUG_INFO +// + +typedef struct _STORAGE_HOTPLUG_INFO { + ULONG Size; // version + BOOLEAN MediaRemovable; // ie. zip, jaz, cdrom, mo, etc. vs hdd + BOOLEAN MediaHotplug; // ie. does the device succeed a lock even though its not lockable media? + BOOLEAN DeviceHotplug; // ie. 1394, USB, etc. + BOOLEAN WriteCacheEnableOverride; // This field should not be relied upon because it is no longer used +} STORAGE_HOTPLUG_INFO, *PSTORAGE_HOTPLUG_INFO; + +// +// IOCTL_STORAGE_GET_DEVICE_NUMBER +// +// input - none +// +// output - STORAGE_DEVICE_NUMBER structure +// The values in the STORAGE_DEVICE_NUMBER structure are guaranteed +// to remain unchanged until the system is rebooted. They are not +// guaranteed to be persistant across boots. +// + +typedef struct _STORAGE_DEVICE_NUMBER { + + // + // The FILE_DEVICE_XXX type for this device. + // + + DEVICE_TYPE DeviceType; + + // + // The number of this device + // + + ULONG DeviceNumber; + + // + // If the device is partitionable, the partition number of the device. + // Otherwise -1 + // + + ULONG PartitionNumber; +} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER; + +// +// Define the structures for scsi resets +// + +typedef struct _STORAGE_BUS_RESET_REQUEST { + UCHAR PathId; +} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST; + +// +// Break reservation is sent to the Adapter/FDO with the given lun information. +// + +typedef struct STORAGE_BREAK_RESERVATION_REQUEST { + ULONG Length; + UCHAR _unused; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} STORAGE_BREAK_RESERVATION_REQUEST, *PSTORAGE_BREAK_RESERVATION_REQUEST; + + +// +// IOCTL_STORAGE_MEDIA_REMOVAL disables the mechanism +// on a storage device that ejects media. This function +// may or may not be supported on storage devices that +// support removable media. +// +// TRUE means prevent media from being removed. +// FALSE means allow media removal. +// + +typedef struct _PREVENT_MEDIA_REMOVAL { + BOOLEAN PreventMediaRemoval; +} PREVENT_MEDIA_REMOVAL, *PPREVENT_MEDIA_REMOVAL; + + + +// +// This is the format of TARGET_DEVICE_CUSTOM_NOTIFICATION.CustomDataBuffer +// passed to applications by the classpnp autorun code (via IoReportTargetDeviceChangeAsynchronous). +// +typedef struct _CLASS_MEDIA_CHANGE_CONTEXT { + ULONG MediaChangeCount; + ULONG NewState; // see MEDIA_CHANGE_DETECTION_STATE enum in classpnp.h in DDK +} CLASS_MEDIA_CHANGE_CONTEXT, *PCLASS_MEDIA_CHANGE_CONTEXT; + + +// begin_ntminitape + + +typedef struct _TAPE_STATISTICS { + ULONG Version; + ULONG Flags; + LARGE_INTEGER RecoveredWrites; + LARGE_INTEGER UnrecoveredWrites; + LARGE_INTEGER RecoveredReads; + LARGE_INTEGER UnrecoveredReads; + UCHAR CompressionRatioReads; + UCHAR CompressionRatioWrites; +} TAPE_STATISTICS, *PTAPE_STATISTICS; + +#define RECOVERED_WRITES_VALID 0x00000001 +#define UNRECOVERED_WRITES_VALID 0x00000002 +#define RECOVERED_READS_VALID 0x00000004 +#define UNRECOVERED_READS_VALID 0x00000008 +#define WRITE_COMPRESSION_INFO_VALID 0x00000010 +#define READ_COMPRESSION_INFO_VALID 0x00000020 + +typedef struct _TAPE_GET_STATISTICS { + ULONG Operation; +} TAPE_GET_STATISTICS, *PTAPE_GET_STATISTICS; + +#define TAPE_RETURN_STATISTICS 0L +#define TAPE_RETURN_ENV_INFO 1L +#define TAPE_RESET_STATISTICS 2L + +// +// IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO +// structures, one per supported type, embedded in the GET_MEDIA_TYPES struct. +// + +typedef enum _STORAGE_MEDIA_TYPE { + // + // Following are defined in ntdddisk.h in the MEDIA_TYPE enum + // + // Unknown, // Format is unknown + // F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector + // F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector + // F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector + // F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector + // F3_720_512, // 3.5", 720KB, 512 bytes/sector + // F5_360_512, // 5.25", 360KB, 512 bytes/sector + // F5_320_512, // 5.25", 320KB, 512 bytes/sector + // F5_320_1024, // 5.25", 320KB, 1024 bytes/sector + // F5_180_512, // 5.25", 180KB, 512 bytes/sector + // F5_160_512, // 5.25", 160KB, 512 bytes/sector + // RemovableMedia, // Removable media other than floppy + // FixedMedia, // Fixed hard disk media + // F3_120M_512, // 3.5", 120M Floppy + // F3_640_512, // 3.5" , 640KB, 512 bytes/sector + // F5_640_512, // 5.25", 640KB, 512 bytes/sector + // F5_720_512, // 5.25", 720KB, 512 bytes/sector + // F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector + // F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector + // F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector + // F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector + // F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector + // F8_256_128, // 8", 256KB, 128 bytes/sector + // F3_200Mb_512, // 3.5", 200M Floppy (HiFD) + // + + DDS_4mm = 0x20, // Tape - DAT DDS1,2,... (all vendors) + MiniQic, // Tape - miniQIC Tape + Travan, // Tape - Travan TR-1,2,3,... + QIC, // Tape - QIC + MP_8mm, // Tape - 8mm Exabyte Metal Particle + AME_8mm, // Tape - 8mm Exabyte Advanced Metal Evap + AIT1_8mm, // Tape - 8mm Sony AIT + DLT, // Tape - DLT Compact IIIxt, IV + NCTP, // Tape - Philips NCTP + IBM_3480, // Tape - IBM 3480 + IBM_3490E, // Tape - IBM 3490E + IBM_Magstar_3590, // Tape - IBM Magstar 3590 + IBM_Magstar_MP, // Tape - IBM Magstar MP + STK_DATA_D3, // Tape - STK Data D3 + SONY_DTF, // Tape - Sony DTF + DV_6mm, // Tape - 6mm Digital Video + DMI, // Tape - Exabyte DMI and compatibles + SONY_D2, // Tape - Sony D2S and D2L + CLEANER_CARTRIDGE, // Cleaner - All Drive types that support Drive Cleaners + CD_ROM, // Opt_Disk - CD + CD_R, // Opt_Disk - CD-Recordable (Write Once) + CD_RW, // Opt_Disk - CD-Rewriteable + DVD_ROM, // Opt_Disk - DVD-ROM + DVD_R, // Opt_Disk - DVD-Recordable (Write Once) + DVD_RW, // Opt_Disk - DVD-Rewriteable + MO_3_RW, // Opt_Disk - 3.5" Rewriteable MO Disk + MO_5_WO, // Opt_Disk - MO 5.25" Write Once + MO_5_RW, // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW) + MO_5_LIMDOW, // Opt_Disk - MO 5.25" Rewriteable (LIMDOW) + PC_5_WO, // Opt_Disk - Phase Change 5.25" Write Once Optical + PC_5_RW, // Opt_Disk - Phase Change 5.25" Rewriteable + PD_5_RW, // Opt_Disk - PhaseChange Dual Rewriteable + ABL_5_WO, // Opt_Disk - Ablative 5.25" Write Once Optical + PINNACLE_APEX_5_RW, // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical + SONY_12_WO, // Opt_Disk - Sony 12" Write Once + PHILIPS_12_WO, // Opt_Disk - Philips/LMS 12" Write Once + HITACHI_12_WO, // Opt_Disk - Hitachi 12" Write Once + CYGNET_12_WO, // Opt_Disk - Cygnet/ATG 12" Write Once + KODAK_14_WO, // Opt_Disk - Kodak 14" Write Once + MO_NFR_525, // Opt_Disk - Near Field Recording (Terastor) + NIKON_12_RW, // Opt_Disk - Nikon 12" Rewriteable + IOMEGA_ZIP, // Mag_Disk - Iomega Zip + IOMEGA_JAZ, // Mag_Disk - Iomega Jaz + SYQUEST_EZ135, // Mag_Disk - Syquest EZ135 + SYQUEST_EZFLYER, // Mag_Disk - Syquest EzFlyer + SYQUEST_SYJET, // Mag_Disk - Syquest SyJet + AVATAR_F2, // Mag_Disk - 2.5" Floppy + MP2_8mm, // Tape - 8mm Hitachi + DST_S, // Ampex DST Small Tapes + DST_M, // Ampex DST Medium Tapes + DST_L, // Ampex DST Large Tapes + VXATape_1, // Ecrix 8mm Tape + VXATape_2, // Ecrix 8mm Tape +#if (NTDDI_VERSION < NTDDI_WINXP) + STK_EAGLE, // STK Eagle +#else + STK_9840, // STK 9840 +#endif + LTO_Ultrium, // IBM, HP, Seagate LTO Ultrium + LTO_Accelis, // IBM, HP, Seagate LTO Accelis + DVD_RAM, // Opt_Disk - DVD-RAM + AIT_8mm, // AIT2 or higher + ADR_1, // OnStream ADR Mediatypes + ADR_2, + STK_9940, // STK 9940 + SAIT, // SAIT Tapes + VXATape // VXA (Ecrix 8mm) Tape +}STORAGE_MEDIA_TYPE, *PSTORAGE_MEDIA_TYPE; + +#define MEDIA_ERASEABLE 0x00000001 +#define MEDIA_WRITE_ONCE 0x00000002 +#define MEDIA_READ_ONLY 0x00000004 +#define MEDIA_READ_WRITE 0x00000008 + +#define MEDIA_WRITE_PROTECTED 0x00000100 +#define MEDIA_CURRENTLY_MOUNTED 0x80000000 + +// +// Define the different storage bus types +// Bus types below 128 (0x80) are reserved for Microsoft use +// + +typedef enum _STORAGE_BUS_TYPE { + BusTypeUnknown = 0x00, + BusTypeScsi, + BusTypeAtapi, + BusTypeAta, + BusType1394, + BusTypeSsa, + BusTypeFibre, + BusTypeUsb, + BusTypeRAID, + BusTypeiScsi, + BusTypeSas, + BusTypeSata, + BusTypeSd, + BusTypeMmc, + BusTypeVirtual, + BusTypeFileBackedVirtual, + BusTypeMax, + BusTypeMaxReserved = 0x7F +} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; + +typedef struct _DEVICE_MEDIA_INFO { + union { + struct { + LARGE_INTEGER Cylinders; + STORAGE_MEDIA_TYPE MediaType; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; + ULONG NumberMediaSides; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + } DiskInfo; + + struct { + LARGE_INTEGER Cylinders; + STORAGE_MEDIA_TYPE MediaType; + ULONG TracksPerCylinder; + ULONG SectorsPerTrack; + ULONG BytesPerSector; + ULONG NumberMediaSides; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + } RemovableDiskInfo; + + struct { + STORAGE_MEDIA_TYPE MediaType; + ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values. + ULONG CurrentBlockSize; + STORAGE_BUS_TYPE BusType; + + // + // Bus specific information describing the medium supported. + // + + union { + struct { + UCHAR MediumType; + UCHAR DensityCode; + } ScsiInformation; + } BusSpecificData; + + } TapeInfo; + } DeviceSpecific; +} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO; + +typedef struct _GET_MEDIA_TYPES { + ULONG DeviceType; // FILE_DEVICE_XXX values + ULONG MediaInfoCount; + DEVICE_MEDIA_INFO MediaInfo[1]; +} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES; + + +// +// IOCTL_STORAGE_PREDICT_FAILURE +// +// input - none +// +// output - STORAGE_PREDICT_FAILURE structure +// PredictFailure returns zero if no failure predicted and non zero +// if a failure is predicted. +// +// VendorSpecific returns 512 bytes of vendor specific information +// if a failure is predicted +// +typedef struct _STORAGE_PREDICT_FAILURE +{ + ULONG PredictFailure; + UCHAR VendorSpecific[512]; +} STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE; + +// end_ntminitape + +// +// Property Query Structures +// + +// +// IOCTL_STORAGE_QUERY_PROPERTY +// +// Input Buffer: +// a STORAGE_PROPERTY_QUERY structure which describes what type of query +// is being done, what property is being queried for, and any additional +// parameters which a particular property query requires. +// +// Output Buffer: +// Contains a buffer to place the results of the query into. Since all +// property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER, +// the IOCTL can be called once with a small buffer then again using +// a buffer as large as the header reports is necessary. +// + + +// +// Types of queries +// + +typedef enum _STORAGE_QUERY_TYPE { + PropertyStandardQuery = 0, // Retrieves the descriptor + PropertyExistsQuery, // Used to test whether the descriptor is supported + PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor + PropertyQueryMaxDefined // use to validate the value +} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; + +// +// define some initial property id's +// + +typedef enum _STORAGE_PROPERTY_ID { + StorageDeviceProperty = 0, + StorageAdapterProperty, + StorageDeviceIdProperty, + StorageDeviceUniqueIdProperty, // See storduid.h for details + StorageDeviceWriteCacheProperty, + StorageMiniportProperty, + StorageAccessAlignmentProperty, + StorageDeviceSeekPenaltyProperty, + StorageDeviceTrimProperty, + StorageDeviceWriteAggregationProperty +} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; + +// +// Query structure - additional parameters for specific queries can follow +// the header +// + +typedef struct _STORAGE_PROPERTY_QUERY { + + // + // ID of the property being retrieved + // + + STORAGE_PROPERTY_ID PropertyId; + + // + // Flags indicating the type of query being performed + // + + STORAGE_QUERY_TYPE QueryType; + + // + // Space for additional parameters if necessary + // + + UCHAR AdditionalParameters[1]; + +} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY; + +// +// Standard property descriptor header. All property pages should use this +// as their first element or should contain these two elements +// + +typedef __struct_bcount(Size) struct _STORAGE_DESCRIPTOR_HEADER { + + ULONG Version; + + ULONG Size; + +} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER; + +// +// Device property descriptor - this is really just a rehash of the inquiry +// data retrieved from a scsi device +// +// This may only be retrieved from a target device. Sending this to the bus +// will result in an error +// + +typedef __struct_bcount(Size) struct _STORAGE_DEVICE_DESCRIPTOR { + + // + // Sizeof(STORAGE_DEVICE_DESCRIPTOR) + // + + ULONG Version; + + // + // Total size of the descriptor, including the space for additional + // data and id strings + // + + ULONG Size; + + // + // The SCSI-2 device type + // + + UCHAR DeviceType; + + // + // The SCSI-2 device type modifier (if any) - this may be zero + // + + UCHAR DeviceTypeModifier; + + // + // Flag indicating whether the device's media (if any) is removable. This + // field should be ignored for media-less devices + // + + BOOLEAN RemovableMedia; + + // + // Flag indicating whether the device can support mulitple outstanding + // commands. The actual synchronization in this case is the responsibility + // of the port driver. + // + + BOOLEAN CommandQueueing; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // vendor id string. For devices with no such ID this will be zero + // + + ULONG VendorIdOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // product id string. For devices with no such ID this will be zero + // + + ULONG ProductIdOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // product revision string. For devices with no such string this will be + // zero + // + + ULONG ProductRevisionOffset; + + // + // Byte offset to the zero-terminated ascii string containing the device's + // serial number. For devices with no serial number this will be zero + // + + ULONG SerialNumberOffset; + + // + // Contains the bus type (as defined above) of the device. It should be + // used to interpret the raw device properties at the end of this structure + // (if any) + // + + STORAGE_BUS_TYPE BusType; + + // + // The number of bytes of bus-specific data which have been appended to + // this descriptor + // + + ULONG RawPropertiesLength; + + // + // Place holder for the first byte of the bus specific property data + // + + UCHAR RawDeviceProperties[1]; + +} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR; + + +// +// Adapter properties +// +// This descriptor can be retrieved from a target device object of from the +// device object for the bus. Retrieving from the target device object will +// forward the request to the underlying bus +// + +typedef __struct_bcount(Size) struct _STORAGE_ADAPTER_DESCRIPTOR { + + ULONG Version; + + ULONG Size; + + ULONG MaximumTransferLength; + + ULONG MaximumPhysicalPages; + + ULONG AlignmentMask; + + BOOLEAN AdapterUsesPio; + + BOOLEAN AdapterScansDown; + + BOOLEAN CommandQueueing; + + BOOLEAN AcceleratedTransfer; + +#if (NTDDI_VERSION < NTDDI_WINXP) + BOOLEAN BusType; +#else + UCHAR BusType; +#endif + + USHORT BusMajorVersion; + + USHORT BusMinorVersion; + +} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR; + +typedef __struct_bcount(Size) struct _STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR { + + // + // Sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) + // + + ULONG Version; + + // + // Total size of the descriptor, including the space for additional + // data and id strings + // + + ULONG Size; + + // + // The number of bytes in a cache line of the device + // + + ULONG BytesPerCacheLine; + + // + // The address offset neccessary for proper cache access alignment in bytes + // + + ULONG BytesOffsetForCacheAlignment; + + // + // The number of bytes in a physical sector of the device + // + + ULONG BytesPerLogicalSector; + + // + // The number of bytes in an addressable logical sector (LBA)of the device + // + + ULONG BytesPerPhysicalSector; + + // + // The address offset neccessary for proper sector access alignment in bytes + // + + ULONG BytesOffsetForSectorAlignment; + +} STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR, *PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR; + + + +typedef enum _STORAGE_PORT_CODE_SET { + StoragePortCodeSetReserved = 0, + StoragePortCodeSetStorport = 1, + StoragePortCodeSetSCSIport = 2 +} STORAGE_PORT_CODE_SET, *PSTORAGE_PORT_CODE_SET; + +typedef struct _STORAGE_MINIPORT_DESCRIPTOR { + + ULONG Version; + + ULONG Size; + + STORAGE_PORT_CODE_SET Portdriver; + + BOOLEAN LUNResetSupported; + + BOOLEAN TargetResetSupported; + + +} STORAGE_MINIPORT_DESCRIPTOR, *PSTORAGE_MINIPORT_DESCRIPTOR; + +// +// Storage identification descriptor. +// The definitions here are based on the SCSI/SBP vital product data +// device identifier page. +// + +typedef enum _STORAGE_IDENTIFIER_CODE_SET { + StorageIdCodeSetReserved = 0, + StorageIdCodeSetBinary = 1, + StorageIdCodeSetAscii = 2, + StorageIdCodeSetUtf8 = 3 +} STORAGE_IDENTIFIER_CODE_SET, *PSTORAGE_IDENTIFIER_CODE_SET; + +typedef enum _STORAGE_IDENTIFIER_TYPE { + StorageIdTypeVendorSpecific = 0, + StorageIdTypeVendorId = 1, + StorageIdTypeEUI64 = 2, + StorageIdTypeFCPHName = 3, + StorageIdTypePortRelative = 4, + StorageIdTypeTargetPortGroup = 5, + StorageIdTypeLogicalUnitGroup = 6, + StorageIdTypeMD5LogicalUnitIdentifier = 7, + StorageIdTypeScsiNameString = 8 +} STORAGE_IDENTIFIER_TYPE, *PSTORAGE_IDENTIFIER_TYPE; + +// Mislabeled above but need to keep it for backwards compatibility +#define StorageIdTypeNAA StorageIdTypeFCPHName + +// NAA formats (Used with StorageIdTypeNAA) +typedef enum _STORAGE_ID_NAA_FORMAT { + StorageIdNAAFormatIEEEExtended = 2, + StorageIdNAAFormatIEEERegistered = 3, + StorageIdNAAFormatIEEEERegisteredExtended = 5 +} STORAGE_ID_NAA_FORMAT, *PSTORAGE_ID_NAA_FORMAT; + +typedef enum _STORAGE_ASSOCIATION_TYPE { + StorageIdAssocDevice = 0, + StorageIdAssocPort = 1, + StorageIdAssocTarget = 2 +} STORAGE_ASSOCIATION_TYPE, *PSTORAGE_ASSOCIATION_TYPE; + +typedef struct _STORAGE_IDENTIFIER { + STORAGE_IDENTIFIER_CODE_SET CodeSet; + STORAGE_IDENTIFIER_TYPE Type; + USHORT IdentifierSize; + USHORT NextOffset; + + // + // Add new fields here since existing code depends on + // the above layout not changing. + // + + STORAGE_ASSOCIATION_TYPE Association; + + // + // The identifier is a variable length array of bytes. + // + + UCHAR Identifier[1]; +} STORAGE_IDENTIFIER, *PSTORAGE_IDENTIFIER; + +typedef __struct_bcount(Size) struct _STORAGE_DEVICE_ID_DESCRIPTOR { + + ULONG Version; + + ULONG Size; + + // + // The number of identifiers reported by the device. + // + + ULONG NumberOfIdentifiers; + + // + // The following field is actually a variable length array of identification + // descriptors. Unfortunately there's no C notation for an array of + // variable length structures so we're forced to just pretend. + // + + UCHAR Identifiers[1]; +} STORAGE_DEVICE_ID_DESCRIPTOR, *PSTORAGE_DEVICE_ID_DESCRIPTOR; + +// output buffer for StorageDeviceSeekPenaltyProperty & PropertyStandardQuery +typedef struct _DEVICE_SEEK_PENALTY_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + BOOLEAN IncursSeekPenalty; +} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR; + +// output buffer for StorageDeviceWriteAggregationProperty & PropertyStandardQuery +typedef struct _DEVICE_WRITE_AGGREGATION_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + BOOLEAN BenefitsFromWriteAggregation; +} DEVICE_WRITE_AGGREGATION_DESCRIPTOR, *PDEVICE_WRITE_AGGREGATION_DESCRIPTOR; + +// output buffer for StorageDeviceTrimProperty & PropertyStandardQuery +typedef struct _DEVICE_TRIM_DESCRIPTOR { + ULONG Version; // keep compatible with STORAGE_DESCRIPTOR_HEADER + ULONG Size; // keep compatible with STORAGE_DESCRIPTOR_HEADER + + BOOLEAN TrimEnabled; +} DEVICE_TRIM_DESCRIPTOR, *PDEVICE_TRIM_DESCRIPTOR; + +// +// IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES +// +// Input Buffer: +// Structure of type DEVICE_MANAGE_DATA_SET_ATTRIBUTES +// +// Output Buffer: +// N/A +// +// Note: +// 1. Management of action Trim will be only allowed for kernel request. +// This request sent from user application will be rejected by kernel drivers. +// + +// +// This flag, when OR'd into an action indicates that the given action is +// non-destructive. If this flag is set then storage stack components which +// do not understand the action should forward the given request +// + +#define DeviceDsmActionFlag_NonDestructive 0x80000000 + +#define IsDsmActionNonDestructive(_Action) ((BOOLEAN)((_Action & DeviceDsmActionFlag_NonDestructive) != 0)) + +// +// Defines the various actions +// + +typedef ULONG DEVICE_DATA_MANAGEMENT_SET_ACTION; + #define DeviceDsmAction_None 0 + #define DeviceDsmAction_Trim 1 + #define DeviceDsmAction_Notification (2 | DeviceDsmActionFlag_NonDestructive) + +// +// Flags that are global across all actions +// + +#define DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE 0x00000001 // If set, the DataSetRanges fields should be 0 + + +typedef struct _DEVICE_DATA_SET_RANGE { + LONGLONG StartingOffset; //in bytes , must allign to sector + ULONGLONG LengthInBytes; // multiple of sector size. +} DEVICE_DATA_SET_RANGE, *PDEVICE_DATA_SET_RANGE; + +// +// input structure for IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES +// 1. Value ofParameterBlockOffset or ParameterBlockLength is 0 indicates that Parameter Block does not exist. +// 2. Value of DataSetRangesOffset or DataSetRangesLength is 0 indicates that DataSetRanges Block does not exist. +// If DataSetRanges Block exists, it contains contiguous DEVICE_DATA_SET_RANGE structures. +// 3. The total size of buffer should be at least: +// sizeof (DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + ParameterBlockLength + DataSetRangesLength +// +typedef struct _DEVICE_MANAGE_DATA_SET_ATTRIBUTES { + ULONG Size; // Size of structure DEVICE_MANAGE_DATA_SET_ATTRIBUTES + DEVICE_DATA_MANAGEMENT_SET_ACTION Action; + + ULONG Flags; // Global flags across all actions + + ULONG ParameterBlockOffset; // must be alligned to corresponding structure allignment + ULONG ParameterBlockLength; // 0 means Parameter Block does not exist. + + ULONG DataSetRangesOffset; // must be alligned to DEVICE_DATA_SET_RANGE structure allignment. + ULONG DataSetRangesLength; // 0 means DataSetRanges Block does not exist. + +} DEVICE_MANAGE_DATA_SET_ATTRIBUTES, *PDEVICE_MANAGE_DATA_SET_ATTRIBUTES; + +// +// This defines the parameter block for the DeviceDsmAction_Notification +// action +// + +typedef struct _DEVICE_DSM_NOTIFICATION_PARAMETERS { + + ULONG Size; // Size of this structure + + ULONG Flags; // Flags specific to the notify operation + + ULONG NumFileTypeIDs; // Count of how many file type ID's are given + + GUID FileTypeID[1]; // Identifier for the type of file being notified + +} DEVICE_DSM_NOTIFICATION_PARAMETERS, *PDEVICE_DSM_NOTIFICATION_PARAMETERS; + +// +// DEVICE_DSM_NOTIFICATION_PARAMETERS flag definitions +// + +#define DEVICE_DSM_NOTIFY_FLAG_BEGIN 0x00000001 // The given LBA range is being used as defined by the FileID +#define DEVICE_DSM_NOTIFY_FLAG_END 0x00000002 // The given LBA range is no longer being used as defined by the FileID + +// +// There are some well known GUIDS for certail types of files. They are +// defined in NTIFS.H +// + + +// +// IOCTL_STORAGE_GET_BC_PROPERTIES +// +// Input Buffer: +// None +// +// Output Buffer: +// Structure of type STORAGE_GET_BC_PROPERTIES_OUTPUT +// + +typedef struct _STORAGE_GET_BC_PROPERTIES_OUTPUT { + + // + // Specifies the maximum number of requests + // that can be scheduled per period of time + // + ULONG MaximumRequestsPerPeriod; + + // + // Specifies the minimum period that the + // device uses when scheduling requests + // + ULONG MinimumPeriod; + + // + // Specifies the maximum transfer size supported + // for bandwidth contracts on this device. To + // achieve the highest level of performance, all + // requests should be of this size + // + ULONGLONG MaximumRequestSize; + + // + // Specifies the estimated time taken to + // perform an Io operstion. This field + // is for informational purposes only + // + ULONG EstimatedTimePerRequest; + + // + // Specifies the number of requests that should be + // kept outstanding. This helps keep the device + // device busy and thus obtain maximum throughput. + // This will only be filled in if the target file + // has an outstanding contract. + // + ULONG NumOutStandingRequests; + + // + // Specifies the required size of requests in this + // stream. This will only be filled in if the + // target file has an outstanding contract. + // + ULONGLONG RequestSize; + +} STORAGE_GET_BC_PROPERTIES_OUTPUT, *PSTORAGE_GET_BC_PROPERTIES_OUTPUT; + + +// +// IOCTL_STORAGE_ALLOCATE_BC_STREAM +// +// Input Buffer: +// Structure of type STORAGE_ALLOCATE_BC_STREAM_INPUT +// +// Output Buffer: +// Structure of type STORAGE_ALLOCATE_BC_STREAM_OUTPUT +// + + +// +// Current version +// +#define IOCTL_STORAGE_BC_VERSION 1 + +typedef struct _STORAGE_ALLOCATE_BC_STREAM_INPUT { + + // + // Specifies the corresponding structure version + // + ULONG Version; + + // + // Specifies the number of requests that + // need to complete per period of time + // + ULONG RequestsPerPeriod; + + // + // Specifies the period of time wherein the + // above number of requests must complete + // + ULONG Period; + + // + // Indicates whether failures + // should be retried or not + // + BOOLEAN RetryFailures; + + // + // Indicates whether reqests that will miss + // their deadline should be discarded or not + // + BOOLEAN Discardable; + + // + // Helps align the following field + // + BOOLEAN Reserved1[2]; + + // + // Indicates whether the Io will be + // comprised of reads, writes or both + // + ULONG AccessType; + + // + // Indicates whether the Io to the + // file will be sequential or random + // + ULONG AccessMode; + +} STORAGE_ALLOCATE_BC_STREAM_INPUT, *PSTORAGE_ALLOCATE_BC_STREAM_INPUT; + +typedef struct _STORAGE_ALLOCATE_BC_STREAM_OUTPUT { + + // + // Specifies the required size + // of requests in this stream + // + ULONGLONG RequestSize; + + // + // Specifies the number of requests that should be + // kept outstanding. This helps keep the device + // device busy and thus obtain maximum throughput + // + ULONG NumOutStandingRequests; + +} STORAGE_ALLOCATE_BC_STREAM_OUTPUT, *PSTORAGE_ALLOCATE_BC_STREAM_OUTPUT; + + +// +// IOCTL_STORAGE_FREE_BC_STREAM +// +// Input Buffer: +// None +// +// Output Buffer: +// None +// + +// +// IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT +// +// Input Buffer : +// None +// Output Buffer : +// Structure of type STORAGE_PRIORITY_HINT_SUPPORT +// + +#define STORAGE_PRIORITY_HINT_SUPPORTED 0x0001 + +typedef struct _STORAGE_PRIORITY_HINT_SUPPORT { + ULONG SupportFlags; +} STORAGE_PRIORITY_HINT_SUPPORT, *PSTORAGE_PRIORITY_HINT_SUPPORT; + +#pragma warning(push) +#pragma warning(disable:4200) + +#if defined(_MSC_EXTENSIONS) + +typedef struct _STORAGE_MEDIA_SERIAL_NUMBER_DATA { + + USHORT Reserved; + + // + // the SerialNumberLength will be set to zero + // if the command is supported and the media + // does not have a valid serial number. + // + + USHORT SerialNumberLength; + + // + // the following data is binary, and is not guaranteed + // to be NULL terminated. this is an excercise for the + // caller. + // + +#if !defined(__midl) + UCHAR SerialNumber[0]; +#endif + +} STORAGE_MEDIA_SERIAL_NUMBER_DATA, *PSTORAGE_MEDIA_SERIAL_NUMBER_DATA; + +#endif /* _MSC_EXTENSIONS */ + +typedef __struct_bcount(Size) struct _STORAGE_READ_CAPACITY { + + // + // The version number, size of the STORAGE_READ_CAPACITY structure + // + ULONG Version; + + // + // The size of the date returned, size of the STORAGE_READ_CAPACITY structure + // + ULONG Size; + + // + // Number of bytes per block + // + + ULONG BlockLength; + + // + // Total number of blocks in the disk + // This will have the last LBA + 1 + // + + LARGE_INTEGER NumberOfBlocks; + + // + // Disk size in bytes + // + + LARGE_INTEGER DiskLength; + +} STORAGE_READ_CAPACITY, *PSTORAGE_READ_CAPACITY; + +#pragma warning(pop) + +// +// Device write cache property +// +// This property provides the write cache information +// about the target device. +// + +typedef enum _WRITE_CACHE_TYPE { + WriteCacheTypeUnknown, + WriteCacheTypeNone, + WriteCacheTypeWriteBack, + WriteCacheTypeWriteThrough +} WRITE_CACHE_TYPE; + +typedef enum _WRITE_CACHE_ENABLE { + WriteCacheEnableUnknown, + WriteCacheDisabled, + WriteCacheEnabled +} WRITE_CACHE_ENABLE; + +typedef enum _WRITE_CACHE_CHANGE { + WriteCacheChangeUnknown, + WriteCacheNotChangeable, + WriteCacheChangeable +} WRITE_CACHE_CHANGE; + +typedef enum _WRITE_THROUGH { + WriteThroughUnknown, + WriteThroughNotSupported, + WriteThroughSupported +} WRITE_THROUGH; + +typedef __struct_bcount(Size) struct _STORAGE_WRITE_CACHE_PROPERTY { + + // + // The version number + // Size of STORAGE_WRITE_CACHE_PROPERTY structure + // + ULONG Version; + + // + // The size of the date returned + // Size of STORAGE_WRITE_CACHE_PROPERTY structure + // + ULONG Size; + + // + // Current write cache type + // + WRITE_CACHE_TYPE WriteCacheType; + + // + // Current write cache value + // + WRITE_CACHE_ENABLE WriteCacheEnabled; + + // + // Device write cache change capability + // + WRITE_CACHE_CHANGE WriteCacheChangeable; + + // + // Device write through support capability + // + WRITE_THROUGH WriteThroughSupported; + + // + // Device flush cache capability + // + BOOLEAN FlushCacheSupported; + + // + // User selected power protection option through registry + // + BOOLEAN UserDefinedPowerProtection; + + // + // Device has battery backup for write cache + // + BOOLEAN NVCacheEnabled; + +} STORAGE_WRITE_CACHE_PROPERTY, *PSTORAGE_WRITE_CACHE_PROPERTY; + +#pragma warning(push) +#pragma warning(disable:4200) // array[0] +#pragma warning(disable:4201) // nameless struct/unions +#pragma warning(disable:4214) // bit fields other than int +#if defined(__INTEL_COMPILER) +#pragma warning(disable:94) // warning #94: the size of an array must be greater than zero +#endif + + +#if defined(_MSC_EXTENSIONS) + +typedef struct _PERSISTENT_RESERVE_COMMAND { + + ULONG Version; + ULONG Size; + + union { + + struct { + + // + // Persistent Reserve service action. + // + + UCHAR ServiceAction : 5; + UCHAR Reserved1 : 3; + + // + // Number of bytes allocated for returned parameter list. + // + + USHORT AllocationLength; + + } PR_IN; + + struct { + + // + // Persistent Reserve service action. + // + + UCHAR ServiceAction : 5; + UCHAR Reserved1 : 3; + + // + // Persistent Reserve type and scope. + // + + UCHAR Type : 4; + UCHAR Scope : 4; + + // + // Space for additional PR Out parameters. + // + +#if !defined(__midl) + UCHAR ParameterList[0]; +#endif + + } PR_OUT; + }; + +} PERSISTENT_RESERVE_COMMAND, *PPERSISTENT_RESERVE_COMMAND; + +#endif /* _MSC_EXTENSIONS */ +#pragma warning(pop) + + +#ifdef __cplusplus +} +#endif + +#endif // _NTDDSTOR_H_ +// end_winioctl + diff --git a/src/CmdUI/CmdUI.cpp b/src/CmdUI/CmdUI.cpp index 999cf4d52c1..13436d9db06 100644 --- a/src/CmdUI/CmdUI.cpp +++ b/src/CmdUI/CmdUI.cpp @@ -1,196 +1,196 @@ -/* - * (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 . - * - */ - -// CmdUI.cpp : implementation file -// - -#include "stdafx.h" -#include -#include "CmdUI.h" - -// CCmdUIDialog dialog - -IMPLEMENT_DYNAMIC(CCmdUIDialog, CDialog) - -CCmdUIDialog::CCmdUIDialog() -{ -} - -CCmdUIDialog::CCmdUIDialog(UINT nIDTemplate, CWnd* pParent /*=nullptr*/) - : CDialog(nIDTemplate, pParent) -{ -} - -CCmdUIDialog::CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) - : CDialog(lpszTemplateName, pParentWnd) -{ -} - -CCmdUIDialog::~CCmdUIDialog() -{ -} - -LRESULT CCmdUIDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT ret = __super::DefWindowProc(message, wParam, lParam); - - if (message == WM_INITDIALOG) { - SendMessage(WM_KICKIDLE); - } - - return ret; -} - -BEGIN_MESSAGE_MAP(CCmdUIDialog, CDialog) - ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) - ON_WM_INITMENUPOPUP() -END_MESSAGE_MAP() - - -// CCmdUIDialog message handlers - -void CCmdUIDialog::OnKickIdle() -{ - UpdateDialogControls(this, false); - - // TODO: maybe we should send this call to modeless child cdialogs too -} - -// Q242577 - -void CCmdUIDialog::OnInitMenuPopup(CMenu* pPopupMenu, UINT /*nIndex*/, BOOL /*bSysMenu*/) -{ - ASSERT(pPopupMenu != nullptr); - // Check the enabled state of various menu items. - - CCmdUI state; - state.m_pMenu = pPopupMenu; - ASSERT(state.m_pOther == nullptr); - ASSERT(state.m_pParentMenu == nullptr); - - // Determine if menu is popup in top-level menu and set m_pOther to - // it if so (m_pParentMenu == nullptr) indicates that it is secondary popup. - if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu) { - state.m_pParentMenu = pPopupMenu; // Parent == child for tracking popup. - } else if (::GetMenu(m_hWnd) != nullptr) { - HMENU hParentMenu; - CWnd* pParent = this; - // Child windows don't have menus--need to go to the top! - if (pParent != nullptr && - (hParentMenu = ::GetMenu(pParent->m_hWnd)) != nullptr) { - int nIndexMax = ::GetMenuItemCount(hParentMenu); - for (int nIndex = 0; nIndex < nIndexMax; nIndex++) { - if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu) { - // When popup is found, m_pParentMenu is containing menu. - state.m_pParentMenu = CMenu::FromHandle(hParentMenu); - break; - } - } - } - } - - state.m_nIndexMax = pPopupMenu->GetMenuItemCount(); - for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; - state.m_nIndex++) { - state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex); - if (state.m_nID == 0) { - continue; // Menu separator or invalid cmd - ignore it. - } - - ASSERT(state.m_pOther == nullptr); - ASSERT(state.m_pMenu != nullptr); - if (state.m_nID == UINT(-1)) { - // Possibly a popup menu, route to first item of that popup. - state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex); - if (state.m_pSubMenu == nullptr || - (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || - state.m_nID == UINT(-1)) { - continue; // First item of popup can't be routed to. - } - state.DoUpdate(this, TRUE); // Popups are never auto disabled. - } else { - // Normal menu item. - // Auto enable/disable if frame window has m_bAutoMenuEnable - // set and command is _not_ a system command. - state.m_pSubMenu = nullptr; - state.DoUpdate(this, FALSE); - } - - // Adjust for menu deletions and additions. - UINT nCount = pPopupMenu->GetMenuItemCount(); - if (nCount < state.m_nIndexMax) { - state.m_nIndex -= (state.m_nIndexMax - nCount); - while (state.m_nIndex < nCount && - pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID) { - state.m_nIndex++; - } - } - state.m_nIndexMax = nCount; - } -} - -// CCmdUIPropertyPage - -IMPLEMENT_DYNAMIC(CCmdUIPropertyPage, CPropertyPage) -CCmdUIPropertyPage::CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption) - : CPropertyPage(nIDTemplate, nIDCaption) -{ -} - -CCmdUIPropertyPage::~CCmdUIPropertyPage() -{ -} - -LRESULT CCmdUIPropertyPage::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_COMMAND) { - switch (HIWORD(wParam)) { - case BN_CLICKED: - case CBN_SELCHANGE: - case EN_CHANGE: - SetModified(); - default: - ; - } - } - - LRESULT ret = __super::DefWindowProc(message, wParam, lParam); - - if (message == WM_INITDIALOG) { - SendMessage(WM_KICKIDLE); - } - - return ret; -} - -BEGIN_MESSAGE_MAP(CCmdUIPropertyPage, CPropertyPage) - ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) -END_MESSAGE_MAP() - - -// CCmdUIPropertyPage message handlers - -void CCmdUIPropertyPage::OnKickIdle() -{ - UpdateDialogControls(this, false); - - // TODO: maybe we should send this call to modeless child cPropertyPages too -} +/* + * (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 . + * + */ + +// CmdUI.cpp : implementation file +// + +#include "stdafx.h" +#include +#include "CmdUI.h" + +// CCmdUIDialog dialog + +IMPLEMENT_DYNAMIC(CCmdUIDialog, CDialog) + +CCmdUIDialog::CCmdUIDialog() +{ +} + +CCmdUIDialog::CCmdUIDialog(UINT nIDTemplate, CWnd* pParent /*=nullptr*/) + : CDialog(nIDTemplate, pParent) +{ +} + +CCmdUIDialog::CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) + : CDialog(lpszTemplateName, pParentWnd) +{ +} + +CCmdUIDialog::~CCmdUIDialog() +{ +} + +LRESULT CCmdUIDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT ret = __super::DefWindowProc(message, wParam, lParam); + + if (message == WM_INITDIALOG) { + SendMessage(WM_KICKIDLE); + } + + return ret; +} + +BEGIN_MESSAGE_MAP(CCmdUIDialog, CDialog) + ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) + ON_WM_INITMENUPOPUP() +END_MESSAGE_MAP() + + +// CCmdUIDialog message handlers + +void CCmdUIDialog::OnKickIdle() +{ + UpdateDialogControls(this, false); + + // TODO: maybe we should send this call to modeless child cdialogs too +} + +// Q242577 + +void CCmdUIDialog::OnInitMenuPopup(CMenu* pPopupMenu, UINT /*nIndex*/, BOOL /*bSysMenu*/) +{ + ASSERT(pPopupMenu != nullptr); + // Check the enabled state of various menu items. + + CCmdUI state; + state.m_pMenu = pPopupMenu; + ASSERT(state.m_pOther == nullptr); + ASSERT(state.m_pParentMenu == nullptr); + + // Determine if menu is popup in top-level menu and set m_pOther to + // it if so (m_pParentMenu == nullptr) indicates that it is secondary popup. + if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu) { + state.m_pParentMenu = pPopupMenu; // Parent == child for tracking popup. + } else if (::GetMenu(m_hWnd) != nullptr) { + HMENU hParentMenu; + CWnd* pParent = this; + // Child windows don't have menus--need to go to the top! + if (pParent != nullptr && + (hParentMenu = ::GetMenu(pParent->m_hWnd)) != nullptr) { + int nIndexMax = ::GetMenuItemCount(hParentMenu); + for (int nIndex = 0; nIndex < nIndexMax; nIndex++) { + if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu) { + // When popup is found, m_pParentMenu is containing menu. + state.m_pParentMenu = CMenu::FromHandle(hParentMenu); + break; + } + } + } + } + + state.m_nIndexMax = pPopupMenu->GetMenuItemCount(); + for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; + state.m_nIndex++) { + state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex); + if (state.m_nID == 0) { + continue; // Menu separator or invalid cmd - ignore it. + } + + ASSERT(state.m_pOther == nullptr); + ASSERT(state.m_pMenu != nullptr); + if (state.m_nID == UINT(-1)) { + // Possibly a popup menu, route to first item of that popup. + state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex); + if (state.m_pSubMenu == nullptr || + (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || + state.m_nID == UINT(-1)) { + continue; // First item of popup can't be routed to. + } + state.DoUpdate(this, TRUE); // Popups are never auto disabled. + } else { + // Normal menu item. + // Auto enable/disable if frame window has m_bAutoMenuEnable + // set and command is _not_ a system command. + state.m_pSubMenu = nullptr; + state.DoUpdate(this, FALSE); + } + + // Adjust for menu deletions and additions. + UINT nCount = pPopupMenu->GetMenuItemCount(); + if (nCount < state.m_nIndexMax) { + state.m_nIndex -= (state.m_nIndexMax - nCount); + while (state.m_nIndex < nCount && + pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID) { + state.m_nIndex++; + } + } + state.m_nIndexMax = nCount; + } +} + +// CCmdUIPropertyPage + +IMPLEMENT_DYNAMIC(CCmdUIPropertyPage, CPropertyPage) +CCmdUIPropertyPage::CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption) + : CPropertyPage(nIDTemplate, nIDCaption) +{ +} + +CCmdUIPropertyPage::~CCmdUIPropertyPage() +{ +} + +LRESULT CCmdUIPropertyPage::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_COMMAND) { + switch (HIWORD(wParam)) { + case BN_CLICKED: + case CBN_SELCHANGE: + case EN_CHANGE: + SetModified(); + default: + ; + } + } + + LRESULT ret = __super::DefWindowProc(message, wParam, lParam); + + if (message == WM_INITDIALOG) { + SendMessage(WM_KICKIDLE); + } + + return ret; +} + +BEGIN_MESSAGE_MAP(CCmdUIPropertyPage, CPropertyPage) + ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle) +END_MESSAGE_MAP() + + +// CCmdUIPropertyPage message handlers + +void CCmdUIPropertyPage::OnKickIdle() +{ + UpdateDialogControls(this, false); + + // TODO: maybe we should send this call to modeless child cPropertyPages too +} diff --git a/src/CmdUI/CmdUI.h b/src/CmdUI/CmdUI.h index cf125cc673d..2e22aa9248f 100644 --- a/src/CmdUI/CmdUI.h +++ b/src/CmdUI/CmdUI.h @@ -1,65 +1,65 @@ -/* - * (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 . - * - */ - -#pragma once - -// CCmdUI dialog - -#include - -class CCmdUIDialog : public CDialog -{ - DECLARE_DYNAMIC(CCmdUIDialog) - -public: - CCmdUIDialog(); - CCmdUIDialog(UINT nIDTemplate, CWnd* pParent = nullptr); - CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); - virtual ~CCmdUIDialog(); - -protected: - virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnKickIdle(); - afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); -}; - -// CCmdUIPropertyPage - -class CCmdUIPropertyPage : public CPropertyPage -{ - DECLARE_DYNAMIC(CCmdUIPropertyPage) - -public: - CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption = 0); // standard constructor - virtual ~CCmdUIPropertyPage(); - -protected: - virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnKickIdle(); -}; +/* + * (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 . + * + */ + +#pragma once + +// CCmdUI dialog + +#include + +class CCmdUIDialog : public CDialog +{ + DECLARE_DYNAMIC(CCmdUIDialog) + +public: + CCmdUIDialog(); + CCmdUIDialog(UINT nIDTemplate, CWnd* pParent = nullptr); + CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); + virtual ~CCmdUIDialog(); + +protected: + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnKickIdle(); + afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); +}; + +// CCmdUIPropertyPage + +class CCmdUIPropertyPage : public CPropertyPage +{ + DECLARE_DYNAMIC(CCmdUIPropertyPage) + +public: + CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption = 0); // standard constructor + virtual ~CCmdUIPropertyPage(); + +protected: + virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnKickIdle(); +}; diff --git a/src/CmdUI/CmdUI.vcxproj b/src/CmdUI/CmdUI.vcxproj index bbaa7d42afd..1f1e2449b10 100644 --- a/src/CmdUI/CmdUI.vcxproj +++ b/src/CmdUI/CmdUI.vcxproj @@ -1,60 +1,60 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {03208025-D5C2-426A-B0FA-251D4338F30C} - CmdUI - MFCProj - CmdUI - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - - - - - - Create - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {03208025-D5C2-426A-B0FA-251D4338F30C} + CmdUI + MFCProj + CmdUI + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + + + + + + Create + + + + + + + + + \ No newline at end of file diff --git a/src/CmdUI/CmdUI.vcxproj.filters b/src/CmdUI/CmdUI.vcxproj.filters index 84e7e50a074..7816ced3b54 100644 --- a/src/CmdUI/CmdUI.vcxproj.filters +++ b/src/CmdUI/CmdUI.vcxproj.filters @@ -1,29 +1,29 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + diff --git a/src/CmdUI/stdafx.cpp b/src/CmdUI/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/CmdUI/stdafx.cpp +++ b/src/CmdUI/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/CmdUI/stdafx.h b/src/CmdUI/stdafx.h index 323ba6af8aa..f7ebda4a143 100644 --- a/src/CmdUI/stdafx.h +++ b/src/CmdUI/stdafx.h @@ -1,28 +1,28 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +/* + * (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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers diff --git a/src/DSUtil/DSMPropertyBag.cpp b/src/DSUtil/DSMPropertyBag.cpp index e4dfe40d1de..2ef50216690 100644 --- a/src/DSUtil/DSMPropertyBag.cpp +++ b/src/DSUtil/DSMPropertyBag.cpp @@ -1,542 +1,542 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include "DSUtil.h" -#include "DSMPropertyBag.h" - -// -// IDSMPropertyBagImpl -// - -IDSMPropertyBagImpl::IDSMPropertyBagImpl() -{ -} - -IDSMPropertyBagImpl::~IDSMPropertyBagImpl() -{ -} - -// IPropertyBag - -STDMETHODIMP IDSMPropertyBagImpl::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) -{ - CheckPointer(pVar, E_POINTER); - if (pVar->vt != VT_EMPTY) { - return E_INVALIDARG; - } - CStringW value = Lookup(pszPropName); - if (value.IsEmpty()) { - return E_FAIL; - } - CComVariant(value).Detach(pVar); - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::Write(LPCOLESTR pszPropName, VARIANT* pVar) -{ - return SetProperty(pszPropName, pVar); -} - -// IPropertyBag2 - -STDMETHODIMP IDSMPropertyBagImpl::Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrLog, VARIANT* pvarValue, HRESULT* phrError) -{ - CheckPointer(pPropBag, E_POINTER); - CheckPointer(pvarValue, E_POINTER); - CheckPointer(phrError, E_POINTER); - for (ULONG i = 0; i < cProperties; phrError[i] = S_OK, i++) { - CComVariant(Lookup(pPropBag[i].pstrName)).Detach(pvarValue); - } - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::Write(ULONG cProperties, PROPBAG2* pPropBag, VARIANT* pvarValue) -{ - CheckPointer(pPropBag, E_POINTER); - CheckPointer(pvarValue, E_POINTER); - for (ULONG i = 0; i < cProperties; i++) { - SetProperty(pPropBag[i].pstrName, &pvarValue[i]); - } - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::CountProperties(ULONG* pcProperties) -{ - CheckPointer(pcProperties, E_POINTER); - *pcProperties = GetSize(); - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties) -{ - CheckPointer(pPropBag, E_POINTER); - CheckPointer(pcProperties, E_POINTER); - for (ULONG i = 0; i < cProperties; i++, iProperty++, (*pcProperties)++) { - CStringW key = GetKeyAt(iProperty); - pPropBag[i].pstrName = (BSTR)CoTaskMemAlloc((key.GetLength() + 1) * sizeof(WCHAR)); - if (!pPropBag[i].pstrName) { - return E_FAIL; - } - wcscpy_s(pPropBag[i].pstrName, key.GetLength() + 1, key); - } - return S_OK; -} - -STDMETHODIMP IDSMPropertyBagImpl::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown* pUnkObject, IErrorLog* pErrLog) -{ - return E_NOTIMPL; -} - -// IDSMProperyBag - -HRESULT IDSMPropertyBagImpl::SetProperty(LPCWSTR key, LPCWSTR value) -{ - CheckPointer(key, E_POINTER); - CheckPointer(value, E_POINTER); - if (!Lookup(key).IsEmpty()) { - SetAt(key, value); - } else { - Add(key, value); - } - return S_OK; -} - -HRESULT IDSMPropertyBagImpl::SetProperty(LPCWSTR key, VARIANT* var) -{ - CheckPointer(key, E_POINTER); - CheckPointer(var, E_POINTER); - if ((var->vt & (VT_BSTR | VT_BYREF)) != VT_BSTR) { - return E_INVALIDARG; - } - return SetProperty(key, var->bstrVal); -} - -HRESULT IDSMPropertyBagImpl::GetProperty(LPCWSTR key, BSTR* value) -{ - CheckPointer(key, E_POINTER); - CheckPointer(value, E_POINTER); - int i = FindKey(key); - if (i < 0) { - return E_FAIL; - } - *value = GetValueAt(i).AllocSysString(); - return S_OK; -} - -HRESULT IDSMPropertyBagImpl::DelAllProperties() -{ - RemoveAll(); - return S_OK; -} - -HRESULT IDSMPropertyBagImpl::DelProperty(LPCWSTR key) -{ - return Remove(key) ? S_OK : S_FALSE; -} - -// -// CDSMResource -// - -CCritSec CDSMResource::m_csResources; -CAtlMap CDSMResource::m_resources; - -CDSMResource::CDSMResource() - : tag(0) - , mime(_T("application/octet-stream")) -{ - CAutoLock cAutoLock(&m_csResources); - m_resources.SetAt(reinterpret_cast(this), this); -} - -CDSMResource::CDSMResource(const CDSMResource& r) -{ - *this = r; - - CAutoLock cAutoLock(&m_csResources); - m_resources.SetAt(reinterpret_cast(this), this); -} - -CDSMResource::CDSMResource(LPCWSTR name, LPCWSTR desc, LPCWSTR mime, BYTE* pData, int len, DWORD_PTR tag) -{ - this->name = name; - this->desc = desc; - this->mime = mime; - data.SetCount(len); - memcpy(data.GetData(), pData, data.GetCount()); - this->tag = tag; - - CAutoLock cAutoLock(&m_csResources); - m_resources.SetAt(reinterpret_cast(this), this); -} - -CDSMResource::~CDSMResource() -{ - CAutoLock cAutoLock(&m_csResources); - m_resources.RemoveKey(reinterpret_cast(this)); -} - -CDSMResource& CDSMResource::operator = (const CDSMResource& r) -{ - if (this != &r) { - tag = r.tag; - name = r.name; - desc = r.desc; - mime = r.mime; - data.Copy(r.data); - } - return *this; -} - -// -// IDSMResourceBagImpl -// - -IDSMResourceBagImpl::IDSMResourceBagImpl() -{ -} - -// IDSMResourceBag - -STDMETHODIMP_(DWORD) IDSMResourceBagImpl::ResGetCount() -{ - return (DWORD)m_resources.GetCount(); -} - -STDMETHODIMP IDSMResourceBagImpl::ResGet(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag) -{ - if (ppData) { - CheckPointer(pDataLen, E_POINTER); - } - - if (iIndex >= m_resources.GetCount()) { - return E_INVALIDARG; - } - - CDSMResource& r = m_resources[iIndex]; - - if (ppName) { - *ppName = r.name.AllocSysString(); - } - if (ppDesc) { - *ppDesc = r.desc.AllocSysString(); - } - if (ppMime) { - *ppMime = r.mime.AllocSysString(); - } - if (ppData) { - *pDataLen = (DWORD)r.data.GetCount(); - memcpy(*ppData = (BYTE*)CoTaskMemAlloc(*pDataLen), r.data.GetData(), *pDataLen); - } - if (pTag) { - *pTag = r.tag; - } - - return S_OK; -} - -STDMETHODIMP IDSMResourceBagImpl::ResSet(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, const BYTE* pData, DWORD len, DWORD_PTR tag) -{ - if (iIndex >= m_resources.GetCount()) { - return E_INVALIDARG; - } - - CDSMResource& r = m_resources[iIndex]; - - if (pName) { - r.name = pName; - } - if (pDesc) { - r.desc = pDesc; - } - if (pMime) { - r.mime = pMime; - } - if (pData || len == 0) { - r.data.SetCount(len); - if (pData) { - memcpy(r.data.GetData(), pData, r.data.GetCount()); - } - } - r.tag = tag; - - return S_OK; -} - -STDMETHODIMP IDSMResourceBagImpl::ResAppend(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, BYTE* pData, DWORD len, DWORD_PTR tag) -{ - return ResSet((DWORD)m_resources.Add(CDSMResource()), pName, pDesc, pMime, pData, len, tag); -} - -STDMETHODIMP IDSMResourceBagImpl::ResRemoveAt(DWORD iIndex) -{ - if (iIndex >= m_resources.GetCount()) { - return E_INVALIDARG; - } - - m_resources.RemoveAt(iIndex); - - return S_OK; -} - -STDMETHODIMP IDSMResourceBagImpl::ResRemoveAll(DWORD_PTR tag) -{ - if (tag) { - for (ptrdiff_t i = m_resources.GetCount() - 1; i >= 0; i--) { - if (m_resources[i].tag == tag) { - m_resources.RemoveAt(i); - } - } - } else { - m_resources.RemoveAll(); - } - - return S_OK; -} - -// -// CDSMChapter -// - -CDSMChapter::CDSMChapter() -{ - order = counter++; - rt = 0; -} - -CDSMChapter::CDSMChapter(REFERENCE_TIME rt, LPCWSTR name) -{ - order = counter++; - this->rt = rt; - this->name = name; -} - -CDSMChapter& CDSMChapter::operator = (const CDSMChapter& c) -{ - if (this != &c) { - order = c.counter; - rt = c.rt; - name = c.name; - } - return *this; -} - -int CDSMChapter::counter = 0; - -// -// IDSMChapterBagImpl -// - -IDSMChapterBagImpl::IDSMChapterBagImpl() -{ - m_fSorted = false; -} - -// IDSMRChapterBag - -STDMETHODIMP_(DWORD) IDSMChapterBagImpl::ChapGetCount() -{ - return (DWORD)m_chapters.GetCount(); -} - -STDMETHODIMP IDSMChapterBagImpl::ChapGet(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName) -{ - if (iIndex >= m_chapters.GetCount()) { - return E_INVALIDARG; - } - - CDSMChapter& c = m_chapters[iIndex]; - - if (prt) { - *prt = c.rt; - } - if (ppName) { - *ppName = c.name.AllocSysString(); - } - - return S_OK; -} - -STDMETHODIMP IDSMChapterBagImpl::ChapSet(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName) -{ - if (iIndex >= m_chapters.GetCount()) { - return E_INVALIDARG; - } - - CDSMChapter& c = m_chapters[iIndex]; - - c.rt = rt; - if (pName) { - c.name = pName; - } - - m_fSorted = false; - - return S_OK; -} - -STDMETHODIMP IDSMChapterBagImpl::ChapAppend(REFERENCE_TIME rt, LPCWSTR pName) -{ - return ChapSet((DWORD)m_chapters.Add(CDSMChapter()), rt, pName); -} - -STDMETHODIMP IDSMChapterBagImpl::ChapRemoveAt(DWORD iIndex) -{ - if (iIndex >= m_chapters.GetCount()) { - return E_INVALIDARG; - } - - m_chapters.RemoveAt(iIndex); - - return S_OK; -} - -STDMETHODIMP IDSMChapterBagImpl::ChapRemoveAll() -{ - m_chapters.RemoveAll(); - - m_fSorted = false; - - return S_OK; -} - -STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookup(REFERENCE_TIME* prt, BSTR* ppName) -{ - CheckPointer(prt, -1); - if (m_chapters.IsEmpty()) { - return -1; - } - - size_t result = 0; - - if (m_fSorted) { - result = range_bsearch(m_chapters, *prt); - } - else { - // assume first entry is best, find better match - for (size_t i = 1; i < m_chapters.GetCount(); ++i) { - if (*prt >= m_chapters[i].rt && m_chapters[i].rt >= m_chapters[result].rt) { - result = i; - } - } - // validate first if it was best - if (result == 0 && *prt < m_chapters[result].rt) { - return -1; - } - } - - if (result != MAXSIZE_T) { - *prt = m_chapters[result].rt; - if (ppName) { - *ppName = m_chapters[result].name.AllocSysString(); - } - } - - return (long)result; -} - -STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookupPrevious(REFERENCE_TIME* prt, BSTR* ppName) -{ - CheckPointer(prt, -1); - - size_t chapcount = m_chapters.GetCount(); - if (chapcount < 1 || *prt < 0) { - return -1; - } - - size_t result = 0; - if (*prt < m_chapters[0].rt) { - return -1; - } else { - for (size_t i = 1; i < chapcount; ++i) { - if (*prt > m_chapters[i].rt) { - result = i; - } else { - break; - } - } - } - - *prt = m_chapters[result].rt; - if (ppName) { - *ppName = m_chapters[result].name.AllocSysString(); - } - - return (long)result; -} - -STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookupNext(REFERENCE_TIME* prt, BSTR* ppName) -{ - CheckPointer(prt, -1); - - size_t chapcount = m_chapters.GetCount(); - if (chapcount < 1) { - return -1; - } - - size_t result = 0; - if (*prt >= m_chapters[chapcount-1].rt) { - return -1; - } else { - for (size_t i = 0; i < chapcount; ++i) { - if (*prt < m_chapters[i].rt) { - result = i; - break; - } - } - } - - *prt = m_chapters[result].rt; - if (ppName) { - *ppName = m_chapters[result].name.AllocSysString(); - } - - return (long)result; -} - -STDMETHODIMP IDSMChapterBagImpl::ChapSort() -{ - if (m_fSorted) { - return S_FALSE; - } - std::sort(m_chapters.GetData(), m_chapters.GetData() + m_chapters.GetCount()); - m_fSorted = true; - return S_OK; -} - -// -// CDSMChapterBag -// - -CDSMChapterBag::CDSMChapterBag(LPUNKNOWN pUnk, HRESULT* phr) - : CUnknown(_T("CDSMChapterBag"), nullptr) -{ -} - -STDMETHODIMP CDSMChapterBag::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IDSMChapterBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include "DSUtil.h" +#include "DSMPropertyBag.h" + +// +// IDSMPropertyBagImpl +// + +IDSMPropertyBagImpl::IDSMPropertyBagImpl() +{ +} + +IDSMPropertyBagImpl::~IDSMPropertyBagImpl() +{ +} + +// IPropertyBag + +STDMETHODIMP IDSMPropertyBagImpl::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) +{ + CheckPointer(pVar, E_POINTER); + if (pVar->vt != VT_EMPTY) { + return E_INVALIDARG; + } + CStringW value = Lookup(pszPropName); + if (value.IsEmpty()) { + return E_FAIL; + } + CComVariant(value).Detach(pVar); + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::Write(LPCOLESTR pszPropName, VARIANT* pVar) +{ + return SetProperty(pszPropName, pVar); +} + +// IPropertyBag2 + +STDMETHODIMP IDSMPropertyBagImpl::Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrLog, VARIANT* pvarValue, HRESULT* phrError) +{ + CheckPointer(pPropBag, E_POINTER); + CheckPointer(pvarValue, E_POINTER); + CheckPointer(phrError, E_POINTER); + for (ULONG i = 0; i < cProperties; phrError[i] = S_OK, i++) { + CComVariant(Lookup(pPropBag[i].pstrName)).Detach(pvarValue); + } + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::Write(ULONG cProperties, PROPBAG2* pPropBag, VARIANT* pvarValue) +{ + CheckPointer(pPropBag, E_POINTER); + CheckPointer(pvarValue, E_POINTER); + for (ULONG i = 0; i < cProperties; i++) { + SetProperty(pPropBag[i].pstrName, &pvarValue[i]); + } + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::CountProperties(ULONG* pcProperties) +{ + CheckPointer(pcProperties, E_POINTER); + *pcProperties = GetSize(); + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties) +{ + CheckPointer(pPropBag, E_POINTER); + CheckPointer(pcProperties, E_POINTER); + for (ULONG i = 0; i < cProperties; i++, iProperty++, (*pcProperties)++) { + CStringW key = GetKeyAt(iProperty); + pPropBag[i].pstrName = (BSTR)CoTaskMemAlloc((key.GetLength() + 1) * sizeof(WCHAR)); + if (!pPropBag[i].pstrName) { + return E_FAIL; + } + wcscpy_s(pPropBag[i].pstrName, key.GetLength() + 1, key); + } + return S_OK; +} + +STDMETHODIMP IDSMPropertyBagImpl::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown* pUnkObject, IErrorLog* pErrLog) +{ + return E_NOTIMPL; +} + +// IDSMProperyBag + +HRESULT IDSMPropertyBagImpl::SetProperty(LPCWSTR key, LPCWSTR value) +{ + CheckPointer(key, E_POINTER); + CheckPointer(value, E_POINTER); + if (!Lookup(key).IsEmpty()) { + SetAt(key, value); + } else { + Add(key, value); + } + return S_OK; +} + +HRESULT IDSMPropertyBagImpl::SetProperty(LPCWSTR key, VARIANT* var) +{ + CheckPointer(key, E_POINTER); + CheckPointer(var, E_POINTER); + if ((var->vt & (VT_BSTR | VT_BYREF)) != VT_BSTR) { + return E_INVALIDARG; + } + return SetProperty(key, var->bstrVal); +} + +HRESULT IDSMPropertyBagImpl::GetProperty(LPCWSTR key, BSTR* value) +{ + CheckPointer(key, E_POINTER); + CheckPointer(value, E_POINTER); + int i = FindKey(key); + if (i < 0) { + return E_FAIL; + } + *value = GetValueAt(i).AllocSysString(); + return S_OK; +} + +HRESULT IDSMPropertyBagImpl::DelAllProperties() +{ + RemoveAll(); + return S_OK; +} + +HRESULT IDSMPropertyBagImpl::DelProperty(LPCWSTR key) +{ + return Remove(key) ? S_OK : S_FALSE; +} + +// +// CDSMResource +// + +CCritSec CDSMResource::m_csResources; +CAtlMap CDSMResource::m_resources; + +CDSMResource::CDSMResource() + : tag(0) + , mime(_T("application/octet-stream")) +{ + CAutoLock cAutoLock(&m_csResources); + m_resources.SetAt(reinterpret_cast(this), this); +} + +CDSMResource::CDSMResource(const CDSMResource& r) +{ + *this = r; + + CAutoLock cAutoLock(&m_csResources); + m_resources.SetAt(reinterpret_cast(this), this); +} + +CDSMResource::CDSMResource(LPCWSTR name, LPCWSTR desc, LPCWSTR mime, BYTE* pData, int len, DWORD_PTR tag) +{ + this->name = name; + this->desc = desc; + this->mime = mime; + data.SetCount(len); + memcpy(data.GetData(), pData, data.GetCount()); + this->tag = tag; + + CAutoLock cAutoLock(&m_csResources); + m_resources.SetAt(reinterpret_cast(this), this); +} + +CDSMResource::~CDSMResource() +{ + CAutoLock cAutoLock(&m_csResources); + m_resources.RemoveKey(reinterpret_cast(this)); +} + +CDSMResource& CDSMResource::operator = (const CDSMResource& r) +{ + if (this != &r) { + tag = r.tag; + name = r.name; + desc = r.desc; + mime = r.mime; + data.Copy(r.data); + } + return *this; +} + +// +// IDSMResourceBagImpl +// + +IDSMResourceBagImpl::IDSMResourceBagImpl() +{ +} + +// IDSMResourceBag + +STDMETHODIMP_(DWORD) IDSMResourceBagImpl::ResGetCount() +{ + return (DWORD)m_resources.GetCount(); +} + +STDMETHODIMP IDSMResourceBagImpl::ResGet(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag) +{ + if (ppData) { + CheckPointer(pDataLen, E_POINTER); + } + + if (iIndex >= m_resources.GetCount()) { + return E_INVALIDARG; + } + + CDSMResource& r = m_resources[iIndex]; + + if (ppName) { + *ppName = r.name.AllocSysString(); + } + if (ppDesc) { + *ppDesc = r.desc.AllocSysString(); + } + if (ppMime) { + *ppMime = r.mime.AllocSysString(); + } + if (ppData) { + *pDataLen = (DWORD)r.data.GetCount(); + memcpy(*ppData = (BYTE*)CoTaskMemAlloc(*pDataLen), r.data.GetData(), *pDataLen); + } + if (pTag) { + *pTag = r.tag; + } + + return S_OK; +} + +STDMETHODIMP IDSMResourceBagImpl::ResSet(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, const BYTE* pData, DWORD len, DWORD_PTR tag) +{ + if (iIndex >= m_resources.GetCount()) { + return E_INVALIDARG; + } + + CDSMResource& r = m_resources[iIndex]; + + if (pName) { + r.name = pName; + } + if (pDesc) { + r.desc = pDesc; + } + if (pMime) { + r.mime = pMime; + } + if (pData || len == 0) { + r.data.SetCount(len); + if (pData) { + memcpy(r.data.GetData(), pData, r.data.GetCount()); + } + } + r.tag = tag; + + return S_OK; +} + +STDMETHODIMP IDSMResourceBagImpl::ResAppend(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, BYTE* pData, DWORD len, DWORD_PTR tag) +{ + return ResSet((DWORD)m_resources.Add(CDSMResource()), pName, pDesc, pMime, pData, len, tag); +} + +STDMETHODIMP IDSMResourceBagImpl::ResRemoveAt(DWORD iIndex) +{ + if (iIndex >= m_resources.GetCount()) { + return E_INVALIDARG; + } + + m_resources.RemoveAt(iIndex); + + return S_OK; +} + +STDMETHODIMP IDSMResourceBagImpl::ResRemoveAll(DWORD_PTR tag) +{ + if (tag) { + for (ptrdiff_t i = m_resources.GetCount() - 1; i >= 0; i--) { + if (m_resources[i].tag == tag) { + m_resources.RemoveAt(i); + } + } + } else { + m_resources.RemoveAll(); + } + + return S_OK; +} + +// +// CDSMChapter +// + +CDSMChapter::CDSMChapter() +{ + order = counter++; + rt = 0; +} + +CDSMChapter::CDSMChapter(REFERENCE_TIME rt, LPCWSTR name) +{ + order = counter++; + this->rt = rt; + this->name = name; +} + +CDSMChapter& CDSMChapter::operator = (const CDSMChapter& c) +{ + if (this != &c) { + order = c.counter; + rt = c.rt; + name = c.name; + } + return *this; +} + +int CDSMChapter::counter = 0; + +// +// IDSMChapterBagImpl +// + +IDSMChapterBagImpl::IDSMChapterBagImpl() +{ + m_fSorted = false; +} + +// IDSMRChapterBag + +STDMETHODIMP_(DWORD) IDSMChapterBagImpl::ChapGetCount() +{ + return (DWORD)m_chapters.GetCount(); +} + +STDMETHODIMP IDSMChapterBagImpl::ChapGet(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName) +{ + if (iIndex >= m_chapters.GetCount()) { + return E_INVALIDARG; + } + + CDSMChapter& c = m_chapters[iIndex]; + + if (prt) { + *prt = c.rt; + } + if (ppName) { + *ppName = c.name.AllocSysString(); + } + + return S_OK; +} + +STDMETHODIMP IDSMChapterBagImpl::ChapSet(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName) +{ + if (iIndex >= m_chapters.GetCount()) { + return E_INVALIDARG; + } + + CDSMChapter& c = m_chapters[iIndex]; + + c.rt = rt; + if (pName) { + c.name = pName; + } + + m_fSorted = false; + + return S_OK; +} + +STDMETHODIMP IDSMChapterBagImpl::ChapAppend(REFERENCE_TIME rt, LPCWSTR pName) +{ + return ChapSet((DWORD)m_chapters.Add(CDSMChapter()), rt, pName); +} + +STDMETHODIMP IDSMChapterBagImpl::ChapRemoveAt(DWORD iIndex) +{ + if (iIndex >= m_chapters.GetCount()) { + return E_INVALIDARG; + } + + m_chapters.RemoveAt(iIndex); + + return S_OK; +} + +STDMETHODIMP IDSMChapterBagImpl::ChapRemoveAll() +{ + m_chapters.RemoveAll(); + + m_fSorted = false; + + return S_OK; +} + +STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookup(REFERENCE_TIME* prt, BSTR* ppName) +{ + CheckPointer(prt, -1); + if (m_chapters.IsEmpty()) { + return -1; + } + + size_t result = 0; + + if (m_fSorted) { + result = range_bsearch(m_chapters, *prt); + } + else { + // assume first entry is best, find better match + for (size_t i = 1; i < m_chapters.GetCount(); ++i) { + if (*prt >= m_chapters[i].rt && m_chapters[i].rt >= m_chapters[result].rt) { + result = i; + } + } + // validate first if it was best + if (result == 0 && *prt < m_chapters[result].rt) { + return -1; + } + } + + if (result != MAXSIZE_T) { + *prt = m_chapters[result].rt; + if (ppName) { + *ppName = m_chapters[result].name.AllocSysString(); + } + } + + return (long)result; +} + +STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookupPrevious(REFERENCE_TIME* prt, BSTR* ppName) +{ + CheckPointer(prt, -1); + + size_t chapcount = m_chapters.GetCount(); + if (chapcount < 1 || *prt < 0) { + return -1; + } + + size_t result = 0; + if (*prt < m_chapters[0].rt) { + return -1; + } else { + for (size_t i = 1; i < chapcount; ++i) { + if (*prt > m_chapters[i].rt) { + result = i; + } else { + break; + } + } + } + + *prt = m_chapters[result].rt; + if (ppName) { + *ppName = m_chapters[result].name.AllocSysString(); + } + + return (long)result; +} + +STDMETHODIMP_(long) IDSMChapterBagImpl::ChapLookupNext(REFERENCE_TIME* prt, BSTR* ppName) +{ + CheckPointer(prt, -1); + + size_t chapcount = m_chapters.GetCount(); + if (chapcount < 1) { + return -1; + } + + size_t result = 0; + if (*prt >= m_chapters[chapcount-1].rt) { + return -1; + } else { + for (size_t i = 0; i < chapcount; ++i) { + if (*prt < m_chapters[i].rt) { + result = i; + break; + } + } + } + + *prt = m_chapters[result].rt; + if (ppName) { + *ppName = m_chapters[result].name.AllocSysString(); + } + + return (long)result; +} + +STDMETHODIMP IDSMChapterBagImpl::ChapSort() +{ + if (m_fSorted) { + return S_FALSE; + } + std::sort(m_chapters.GetData(), m_chapters.GetData() + m_chapters.GetCount()); + m_fSorted = true; + return S_OK; +} + +// +// CDSMChapterBag +// + +CDSMChapterBag::CDSMChapterBag(LPUNKNOWN pUnk, HRESULT* phr) + : CUnknown(_T("CDSMChapterBag"), nullptr) +{ +} + +STDMETHODIMP CDSMChapterBag::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IDSMChapterBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} diff --git a/src/DSUtil/DSMPropertyBag.h b/src/DSUtil/DSMPropertyBag.h index 662e8d4d9ba..9fbe466031a 100644 --- a/src/DSUtil/DSMPropertyBag.h +++ b/src/DSUtil/DSMPropertyBag.h @@ -1,234 +1,234 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include - -// IDSMPropertyBag - -interface __declspec(uuid("232FD5D2-4954-41E7-BF9B-09E1257B1A95")) - IDSMPropertyBag : - public IPropertyBag2 -{ - STDMETHOD(SetProperty)(LPCWSTR key, LPCWSTR value) PURE; - STDMETHOD(SetProperty)(LPCWSTR key, VARIANT* var) PURE; - STDMETHOD(GetProperty)(LPCWSTR key, BSTR* value) PURE; - STDMETHOD(DelAllProperties)() PURE; - STDMETHOD(DelProperty)(LPCWSTR key) PURE; -}; - -class IDSMPropertyBagImpl : public ATL::CSimpleMap, public IDSMPropertyBag, public IPropertyBag -{ - BOOL Add(const CStringW& key, const CStringW& val) { - return __super::Add(key, val); - } - BOOL SetAt(const CStringW& key, const CStringW& val) { - return __super::SetAt(key, val); - } - -public: - IDSMPropertyBagImpl(); - virtual ~IDSMPropertyBagImpl(); - - // IPropertyBag - - STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog); - STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT* pVar); - - // IPropertyBag2 - - STDMETHODIMP Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrLog, VARIANT* pvarValue, HRESULT* phrError); - STDMETHODIMP Write(ULONG cProperties, PROPBAG2* pPropBag, VARIANT* pvarValue); - STDMETHODIMP CountProperties(ULONG* pcProperties); - STDMETHODIMP GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties); - STDMETHODIMP LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown* pUnkObject, IErrorLog* pErrLog); - - // IDSMPropertyBag - - STDMETHODIMP SetProperty(LPCWSTR key, LPCWSTR value); - STDMETHODIMP SetProperty(LPCWSTR key, VARIANT* var); - STDMETHODIMP GetProperty(LPCWSTR key, BSTR* value); - STDMETHODIMP DelAllProperties(); - STDMETHODIMP DelProperty(LPCWSTR key); -}; - -// IDSMResourceBag - -interface __declspec(uuid("EBAFBCBE-BDE0-489A-9789-05D5692E3A93")) - IDSMResourceBag : - public IUnknown -{ - STDMETHOD_(DWORD, ResGetCount)() PURE; - STDMETHOD(ResGet)(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag) PURE; - STDMETHOD(ResSet)(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, const BYTE* pData, DWORD len, DWORD_PTR tag) PURE; - STDMETHOD(ResAppend)(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, BYTE* pData, DWORD len, DWORD_PTR tag) PURE; - STDMETHOD(ResRemoveAt)(DWORD iIndex) PURE; - STDMETHOD(ResRemoveAll)(DWORD_PTR tag) PURE; -}; - -class CDSMResource -{ -public: - DWORD_PTR tag; - CStringW name, desc, mime; - CAtlArray data; - CDSMResource(); - CDSMResource(const CDSMResource& r); - CDSMResource(LPCWSTR name, LPCWSTR desc, LPCWSTR mime, BYTE* pData, int len, DWORD_PTR tag = 0); - virtual ~CDSMResource(); - CDSMResource& operator = (const CDSMResource& r); - - // global access to all resources - static CCritSec m_csResources; - static CAtlMap m_resources; -}; - -class IDSMResourceBagImpl : public IDSMResourceBag -{ -protected: - CAtlArray m_resources; - -public: - IDSMResourceBagImpl(); - - void operator += (const CDSMResource& r) { m_resources.Add(r); } - - // IDSMResourceBag - - STDMETHODIMP_(DWORD) ResGetCount(); - STDMETHODIMP ResGet(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, - BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag = nullptr); - STDMETHODIMP ResSet(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, - const BYTE* pData, DWORD len, DWORD_PTR tag = 0); - STDMETHODIMP ResAppend(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, - BYTE* pData, DWORD len, DWORD_PTR tag = 0); - STDMETHODIMP ResRemoveAt(DWORD iIndex); - STDMETHODIMP ResRemoveAll(DWORD_PTR tag = 0); -}; - -// IDSMChapterBag - -interface __declspec(uuid("926df57d-47c3-4e32-a911-5c66b3314d05")) - IDSMChapterBag : - public IUnknown -{ - STDMETHOD_(DWORD, ChapGetCount)() PURE; - STDMETHOD(ChapGet)(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName) PURE; - STDMETHOD(ChapSet)(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName) PURE; - STDMETHOD(ChapAppend)(REFERENCE_TIME rt, LPCWSTR pName) PURE; - STDMETHOD(ChapRemoveAt)(DWORD iIndex) PURE; - STDMETHOD(ChapRemoveAll)() PURE; - STDMETHOD_(long, ChapLookup)(REFERENCE_TIME* prt, BSTR* ppName) PURE; - STDMETHOD_(long, ChapLookupPrevious)(REFERENCE_TIME* prt, BSTR* ppName) PURE; - STDMETHOD_(long, ChapLookupNext)(REFERENCE_TIME* prt, BSTR* ppName) PURE; - STDMETHOD(ChapSort)() PURE; -}; - -class CDSMChapter -{ - static int counter; - int order; - -public: - REFERENCE_TIME rt; - CStringW name; - CDSMChapter(); - CDSMChapter(REFERENCE_TIME rt, LPCWSTR name); - CDSMChapter& operator = (const CDSMChapter& c); - - bool operator <(const CDSMChapter& rhs) const { - return (rt != rhs.rt) ? rt < rhs.rt : order < rhs.order; - } -}; - -class IDSMChapterBagImpl : public IDSMChapterBag -{ -protected: - CAtlArray m_chapters; - bool m_fSorted; - -public: - IDSMChapterBagImpl(); - - void operator += (const CDSMChapter& c) { m_chapters.Add(c); m_fSorted = false; } - - // IDSMChapterBag - - STDMETHODIMP_(DWORD) ChapGetCount(); - STDMETHODIMP ChapGet(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName = nullptr); - STDMETHODIMP ChapSet(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName); - STDMETHODIMP ChapAppend(REFERENCE_TIME rt, LPCWSTR pName); - STDMETHODIMP ChapRemoveAt(DWORD iIndex); - STDMETHODIMP ChapRemoveAll(); - STDMETHODIMP_(long) ChapLookup(REFERENCE_TIME* prt, BSTR* ppName = nullptr); - STDMETHODIMP ChapSort(); - - STDMETHODIMP_(long) ChapLookupPrevious(REFERENCE_TIME* prt, BSTR* ppName = nullptr); - STDMETHODIMP_(long) ChapLookupNext(REFERENCE_TIME* prt, BSTR* ppName = nullptr); -}; - -class CDSMChapterBag : public CUnknown, public IDSMChapterBagImpl -{ -public: - CDSMChapterBag(LPUNKNOWN pUnk, HRESULT* phr); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); -}; - -template -__declspec(nothrow noalias) __forceinline size_t range_bsearch(CAtlArray const& tArray, REFERENCE_TIME rt) -{ - // MAXSIZE_T is returned by this function for status invalid - ptrdiff_t k = tArray.GetCount() - 1; - if ((k < 0) || (rt >= tArray[k].rt)) { - return k; - } - size_t ret = MAXSIZE_T; - if (!k) { - return ret; - } - - size_t i = 0, j = k; - do { - size_t mid = (i + j) >> 1; - REFERENCE_TIME midrt = tArray[mid].rt; - if (rt == midrt) { - ret = mid; - break; - } else if (rt < midrt) { - ret = MAXSIZE_T; - if (j == mid) { - --mid; - } - j = mid; - } else if (rt > midrt) { - ret = mid; - if (i == mid) { - ++mid; - } - i = mid; - } - } while (i < j); - return ret; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include + +// IDSMPropertyBag + +interface __declspec(uuid("232FD5D2-4954-41E7-BF9B-09E1257B1A95")) + IDSMPropertyBag : + public IPropertyBag2 +{ + STDMETHOD(SetProperty)(LPCWSTR key, LPCWSTR value) PURE; + STDMETHOD(SetProperty)(LPCWSTR key, VARIANT* var) PURE; + STDMETHOD(GetProperty)(LPCWSTR key, BSTR* value) PURE; + STDMETHOD(DelAllProperties)() PURE; + STDMETHOD(DelProperty)(LPCWSTR key) PURE; +}; + +class IDSMPropertyBagImpl : public ATL::CSimpleMap, public IDSMPropertyBag, public IPropertyBag +{ + BOOL Add(const CStringW& key, const CStringW& val) { + return __super::Add(key, val); + } + BOOL SetAt(const CStringW& key, const CStringW& val) { + return __super::SetAt(key, val); + } + +public: + IDSMPropertyBagImpl(); + virtual ~IDSMPropertyBagImpl(); + + // IPropertyBag + + STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog); + STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT* pVar); + + // IPropertyBag2 + + STDMETHODIMP Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrLog, VARIANT* pvarValue, HRESULT* phrError); + STDMETHODIMP Write(ULONG cProperties, PROPBAG2* pPropBag, VARIANT* pvarValue); + STDMETHODIMP CountProperties(ULONG* pcProperties); + STDMETHODIMP GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties); + STDMETHODIMP LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown* pUnkObject, IErrorLog* pErrLog); + + // IDSMPropertyBag + + STDMETHODIMP SetProperty(LPCWSTR key, LPCWSTR value); + STDMETHODIMP SetProperty(LPCWSTR key, VARIANT* var); + STDMETHODIMP GetProperty(LPCWSTR key, BSTR* value); + STDMETHODIMP DelAllProperties(); + STDMETHODIMP DelProperty(LPCWSTR key); +}; + +// IDSMResourceBag + +interface __declspec(uuid("EBAFBCBE-BDE0-489A-9789-05D5692E3A93")) + IDSMResourceBag : + public IUnknown +{ + STDMETHOD_(DWORD, ResGetCount)() PURE; + STDMETHOD(ResGet)(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag) PURE; + STDMETHOD(ResSet)(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, const BYTE* pData, DWORD len, DWORD_PTR tag) PURE; + STDMETHOD(ResAppend)(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, BYTE* pData, DWORD len, DWORD_PTR tag) PURE; + STDMETHOD(ResRemoveAt)(DWORD iIndex) PURE; + STDMETHOD(ResRemoveAll)(DWORD_PTR tag) PURE; +}; + +class CDSMResource +{ +public: + DWORD_PTR tag; + CStringW name, desc, mime; + CAtlArray data; + CDSMResource(); + CDSMResource(const CDSMResource& r); + CDSMResource(LPCWSTR name, LPCWSTR desc, LPCWSTR mime, BYTE* pData, int len, DWORD_PTR tag = 0); + virtual ~CDSMResource(); + CDSMResource& operator = (const CDSMResource& r); + + // global access to all resources + static CCritSec m_csResources; + static CAtlMap m_resources; +}; + +class IDSMResourceBagImpl : public IDSMResourceBag +{ +protected: + CAtlArray m_resources; + +public: + IDSMResourceBagImpl(); + + void operator += (const CDSMResource& r) { m_resources.Add(r); } + + // IDSMResourceBag + + STDMETHODIMP_(DWORD) ResGetCount(); + STDMETHODIMP ResGet(DWORD iIndex, BSTR* ppName, BSTR* ppDesc, BSTR* ppMime, + BYTE** ppData, DWORD* pDataLen, DWORD_PTR* pTag = nullptr); + STDMETHODIMP ResSet(DWORD iIndex, LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, + const BYTE* pData, DWORD len, DWORD_PTR tag = 0); + STDMETHODIMP ResAppend(LPCWSTR pName, LPCWSTR pDesc, LPCWSTR pMime, + BYTE* pData, DWORD len, DWORD_PTR tag = 0); + STDMETHODIMP ResRemoveAt(DWORD iIndex); + STDMETHODIMP ResRemoveAll(DWORD_PTR tag = 0); +}; + +// IDSMChapterBag + +interface __declspec(uuid("926df57d-47c3-4e32-a911-5c66b3314d05")) + IDSMChapterBag : + public IUnknown +{ + STDMETHOD_(DWORD, ChapGetCount)() PURE; + STDMETHOD(ChapGet)(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName) PURE; + STDMETHOD(ChapSet)(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName) PURE; + STDMETHOD(ChapAppend)(REFERENCE_TIME rt, LPCWSTR pName) PURE; + STDMETHOD(ChapRemoveAt)(DWORD iIndex) PURE; + STDMETHOD(ChapRemoveAll)() PURE; + STDMETHOD_(long, ChapLookup)(REFERENCE_TIME* prt, BSTR* ppName) PURE; + STDMETHOD_(long, ChapLookupPrevious)(REFERENCE_TIME* prt, BSTR* ppName) PURE; + STDMETHOD_(long, ChapLookupNext)(REFERENCE_TIME* prt, BSTR* ppName) PURE; + STDMETHOD(ChapSort)() PURE; +}; + +class CDSMChapter +{ + static int counter; + int order; + +public: + REFERENCE_TIME rt; + CStringW name; + CDSMChapter(); + CDSMChapter(REFERENCE_TIME rt, LPCWSTR name); + CDSMChapter& operator = (const CDSMChapter& c); + + bool operator <(const CDSMChapter& rhs) const { + return (rt != rhs.rt) ? rt < rhs.rt : order < rhs.order; + } +}; + +class IDSMChapterBagImpl : public IDSMChapterBag +{ +protected: + CAtlArray m_chapters; + bool m_fSorted; + +public: + IDSMChapterBagImpl(); + + void operator += (const CDSMChapter& c) { m_chapters.Add(c); m_fSorted = false; } + + // IDSMChapterBag + + STDMETHODIMP_(DWORD) ChapGetCount(); + STDMETHODIMP ChapGet(DWORD iIndex, REFERENCE_TIME* prt, BSTR* ppName = nullptr); + STDMETHODIMP ChapSet(DWORD iIndex, REFERENCE_TIME rt, LPCWSTR pName); + STDMETHODIMP ChapAppend(REFERENCE_TIME rt, LPCWSTR pName); + STDMETHODIMP ChapRemoveAt(DWORD iIndex); + STDMETHODIMP ChapRemoveAll(); + STDMETHODIMP_(long) ChapLookup(REFERENCE_TIME* prt, BSTR* ppName = nullptr); + STDMETHODIMP ChapSort(); + + STDMETHODIMP_(long) ChapLookupPrevious(REFERENCE_TIME* prt, BSTR* ppName = nullptr); + STDMETHODIMP_(long) ChapLookupNext(REFERENCE_TIME* prt, BSTR* ppName = nullptr); +}; + +class CDSMChapterBag : public CUnknown, public IDSMChapterBagImpl +{ +public: + CDSMChapterBag(LPUNKNOWN pUnk, HRESULT* phr); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); +}; + +template +__declspec(nothrow noalias) __forceinline size_t range_bsearch(CAtlArray const& tArray, REFERENCE_TIME rt) +{ + // MAXSIZE_T is returned by this function for status invalid + ptrdiff_t k = tArray.GetCount() - 1; + if ((k < 0) || (rt >= tArray[k].rt)) { + return k; + } + size_t ret = MAXSIZE_T; + if (!k) { + return ret; + } + + size_t i = 0, j = k; + do { + size_t mid = (i + j) >> 1; + REFERENCE_TIME midrt = tArray[mid].rt; + if (rt == midrt) { + ret = mid; + break; + } else if (rt < midrt) { + ret = MAXSIZE_T; + if (j == mid) { + --mid; + } + j = mid; + } else if (rt > midrt) { + ret = mid; + if (i == mid) { + ++mid; + } + i = mid; + } + } while (i < j); + return ret; +} diff --git a/src/DSUtil/DSUtil.cpp b/src/DSUtil/DSUtil.cpp index 949661a6934..f4b75e8a4a1 100644 --- a/src/DSUtil/DSUtil.cpp +++ b/src/DSUtil/DSUtil.cpp @@ -1,2248 +1,2248 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "winddk/devioctl.h" -#include "winddk/ntddcdrm.h" -#include "DSUtil.h" -#include "Mpeg2Def.h" -#include -#include -#include "NullRenderers.h" -#include "mvrInterfaces.h" - -#include "moreuuids.h" -#include -#include -#include - -int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC) -{ - nIn = nOut = 0; - nInC = nOutC = 0; - - BeginEnumPins(pBF, pEP, pPin) { - PIN_DIRECTION dir; - if (SUCCEEDED(pPin->QueryDirection(&dir))) { - CComPtr pPinConnectedTo; - pPin->ConnectedTo(&pPinConnectedTo); - - if (dir == PINDIR_INPUT) { - nIn++; - if (pPinConnectedTo) { - nInC++; - } - } else if (dir == PINDIR_OUTPUT) { - nOut++; - if (pPinConnectedTo) { - nOutC++; - } - } - } - } - EndEnumPins; - - return (nIn + nOut); -} - -bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly) -{ - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - return (fCountConnectedOnly ? nOutC > 1 : nOut > 1); -} - -bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly) -{ - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - return (fCountConnectedOnly ? nInC > 1 : nIn > 1); -} - -bool IsStreamStart(IBaseFilter* pBF) -{ - CComQIPtr pAMMF(pBF); - if (pAMMF && pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE) { - return true; - } - - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - AM_MEDIA_TYPE mt; - CComPtr pIn = GetFirstPin(pBF); - return ((nOut > 1) - || (nOut > 0 && nIn == 1 && pIn && SUCCEEDED(pIn->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream)); -} - -bool IsStreamEnd(IBaseFilter* pBF) -{ - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - return (nOut == 0); -} - -bool IsVideoRenderer(IBaseFilter* pBF) -{ - CLSID clsid = GetCLSID(pBF); - if (clsid == CLSID_VideoRenderer || clsid == CLSID_VideoRendererDefault || clsid == CLSID_VideoMixingRenderer9 || clsid == CLSID_EnhancedVideoRenderer || clsid == CLSID_madVR || clsid == CLSID_DXR || clsid == CLSID_MPCVR) { - return true; - } - - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - - if (nInC > 0 && nOut == 0) { - BeginEnumPins(pBF, pEP, pPin) { - AM_MEDIA_TYPE mt; - if (S_OK != pPin->ConnectionMediaType(&mt)) { - continue; - } - - FreeMediaType(mt); - - return !!(mt.majortype == MEDIATYPE_Video); - /*&& (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_VideoInfo2));*/ - } - EndEnumPins; - } - - return false; -} - -bool IsAudioWaveRenderer(IBaseFilter* pBF) -{ - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - - if (nInC > 0 && nOut == 0 && CComQIPtr(pBF)) { - BeginEnumPins(pBF, pEP, pPin) { - AM_MEDIA_TYPE mt; - if (S_OK != pPin->ConnectionMediaType(&mt)) { - continue; - } - - FreeMediaType(mt); - - return !!(mt.majortype == MEDIATYPE_Audio); - /*&& mt.formattype == FORMAT_WaveFormatEx);*/ - } - EndEnumPins; - } - - CLSID clsid; - memcpy(&clsid, &GUID_NULL, sizeof(clsid)); - pBF->GetClassID(&clsid); - - return clsid == CLSID_DSoundRender || - clsid == CLSID_AudioRender || - clsid == CLSID_SANEAR_INTERNAL || - clsid == CLSID_SANEAR || - clsid == CLSID_ReClock || - clsid == CLSID_MPCBEAudioRenderer || - clsid == GUIDFromCString(L"{EC9ED6FC-7B03-4cb6-8C01-4EABE109F26B}") || // MediaPortal Audio Renderer - clsid == GUIDFromCString(L"{50063380-2B2F-4855-9A1E-40FCA344C7AC}") || // Surodev ASIO Renderer - clsid == GUIDFromCString(L"{8DE31E85-10FC-4088-8861-E0EC8E70744A}") || // MultiChannel ASIO Renderer - clsid == GUIDFromCString(L"{205F9417-8EEF-40B4-91CF-C7C6A96936EF}") || // MBSE MultiChannel ASIO Renderer - clsid == __uuidof(CNullAudioRenderer) || - clsid == __uuidof(CNullUAudioRenderer); -} - -IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin) -{ - return GetFilterFromPin(GetUpStreamPin(pBF, pInputPin)); -} - -IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin) -{ - BeginEnumPins(pBF, pEP, pPin) { - if (pInputPin && pInputPin != pPin) { - continue; - } - - PIN_DIRECTION dir; - CComPtr pPinConnectedTo; - if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT - && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo))) { - IPin* pRet = pPinConnectedTo.Detach(); - pRet->Release(); - return pRet; - } - } - EndEnumPins; - - return nullptr; -} - -IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir) -{ - if (pBF) { - BeginEnumPins(pBF, pEP, pPin) { - PIN_DIRECTION dir2; - if (SUCCEEDED(pPin->QueryDirection(&dir2)) && dir == dir2) { - IPin* pRet = pPin.Detach(); - pRet->Release(); - return pRet; - } - } - EndEnumPins; - } - - return nullptr; -} - -IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir) -{ - if (pBF) { - BeginEnumPins(pBF, pEP, pPin) { - PIN_DIRECTION dir2; - CComPtr pPinTo; - if (SUCCEEDED(pPin->QueryDirection(&dir2)) && dir == dir2 && (S_OK != pPin->ConnectedTo(&pPinTo))) { - IPin* pRet = pPin.Detach(); - pRet->Release(); - return pRet; - } - } - EndEnumPins; - } - - return nullptr; -} - -IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG) -{ - CLSID clsid2; - CLSIDFromString(CComBSTR(clsid), &clsid2); - return FindFilter(clsid2, pFG); -} - -IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG) -{ - BeginEnumFilters(pFG, pEF, pBF) { - CLSID clsid2; - if (SUCCEEDED(pBF->GetClassID(&clsid2)) && clsid == clsid2) { - return pBF; - } - } - EndEnumFilters; - - return nullptr; -} - -IBaseFilter* FindFirstFilter(IFilterGraph* pFG) { - BeginEnumFilters(pFG, pEF, pBF) { - return pBF; - } - EndEnumFilters; - - return nullptr; -} - -IPin* FindPin(IBaseFilter* pBF, PIN_DIRECTION direction, const AM_MEDIA_TYPE* pRequestedMT) -{ - PIN_DIRECTION pindir; - BeginEnumPins(pBF, pEP, pPin) { - CComPtr pFellow; - - if (SUCCEEDED(pPin->QueryDirection(&pindir)) && - pindir == direction && - pPin->ConnectedTo(&pFellow) == VFW_E_NOT_CONNECTED) { - BeginEnumMediaTypes(pPin, pEM, pmt) { - if (pmt->majortype == pRequestedMT->majortype && pmt->subtype == pRequestedMT->subtype) { - return (pPin); - } - } - EndEnumMediaTypes(pmt); - } - } - EndEnumPins; - return nullptr; -} - -CStringW GetFilterName(IBaseFilter* pBF) -{ - CStringW name = _T(""); - - if (pBF) { - CFilterInfo fi; - if (SUCCEEDED(pBF->QueryFilterInfo(&fi))) { - name = fi.achName; - } - } - - return name; -} - -CStringW GetPinName(IPin* pPin) -{ - CStringW name; - CPinInfo pi; - if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { - name = pi.achName; - } - - return name; -} - -IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF) -{ - if (!pBF) { - return nullptr; - } - IFilterGraph* pGraph = nullptr; - CFilterInfo fi; - if (pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) { - pGraph = fi.pGraph; - } - return pGraph; -} - -IBaseFilter* GetFilterFromPin(IPin* pPin) -{ - if (!pPin) { - return nullptr; - } - IBaseFilter* pBF = nullptr; - CPinInfo pi; - if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { - pBF = pi.pFilter; - } - return pBF; -} - -IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) -{ - IPin* pRet = pPin; - - CInterfaceList pFilters; - - do { - if (!pPin || DisplayName.IsEmpty() || !pGB) { - break; - } - - CComPtr pPinTo; - PIN_DIRECTION dir; - if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) { - break; - } - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { - break; - } - - CComPtr pBF; - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { - break; - } - - CComPtr pPB; - if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { - break; - } - - CComVariant var; - if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - break; - } - - pFilters.AddTail(pBF); - BeginEnumFilters(pGB, pEnum, pBF2); - pFilters.AddTail(pBF2); - EndEnumFilters; - - if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { - break; - } - - BeginEnumFilters(pGB, pEnum, pBF2); - if (!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) { - pEnum->Reset(); - } - EndEnumFilters; - - pPinTo = GetFirstPin(pBF, PINDIR_INPUT); - if (!pPinTo) { - pGB->RemoveFilter(pBF); - break; - } - - if (FAILED(pGB->ConnectDirect(pPin, pPinTo, nullptr))) { - pGB->Connect(pPin, pPinTo); - pGB->RemoveFilter(pBF); - break; - } - - BeginEnumFilters(pGB, pEnum, pBF2); - if (!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) { - pEnum->Reset(); - } - EndEnumFilters; - - pRet = GetFirstPin(pBF, PINDIR_OUTPUT); - if (!pRet) { - pRet = pPin; - pGB->RemoveFilter(pBF); - break; - } - } while (false); - - return pRet; -} - -IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) -{ - do { - if (!pPin || DisplayName.IsEmpty() || !pGB) { - break; - } - - PIN_DIRECTION dir; - if (FAILED(pPin->QueryDirection(&dir))) { - break; - } - - CComPtr pFrom, pTo; - - if (dir == PINDIR_INPUT) { - pPin->ConnectedTo(&pFrom); - pTo = pPin; - } else if (dir == PINDIR_OUTPUT) { - pFrom = pPin; - pPin->ConnectedTo(&pTo); - } - - if (!pFrom || !pTo) { - break; - } - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { - break; - } - - CComPtr pBF; - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { - break; - } - - CComPtr pPB; - if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { - break; - } - - CComVariant var; - if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - break; - } - - if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { - break; - } - - CComPtr pFromTo = GetFirstPin(pBF, PINDIR_INPUT); - if (!pFromTo) { - pGB->RemoveFilter(pBF); - break; - } - - if (FAILED(pGB->Disconnect(pFrom)) || FAILED(pGB->Disconnect(pTo))) { - pGB->RemoveFilter(pBF); - pGB->ConnectDirect(pFrom, pTo, nullptr); - break; - } - - if (FAILED(pGB->ConnectDirect(pFrom, pFromTo, nullptr))) { - pGB->RemoveFilter(pBF); - pGB->ConnectDirect(pFrom, pTo, nullptr); - break; - } - - CComPtr pToFrom = GetFirstPin(pBF, PINDIR_OUTPUT); - if (!pToFrom) { - pGB->RemoveFilter(pBF); - pGB->ConnectDirect(pFrom, pTo, nullptr); - break; - } - - if (FAILED(pGB->ConnectDirect(pToFrom, pTo, nullptr))) { - pGB->RemoveFilter(pBF); - pGB->ConnectDirect(pFrom, pTo, nullptr); - break; - } - - pPin = pToFrom; - } while (false); - - return pPin; -} - -void ExtractMediaTypes(IPin* pPin, CAtlArray& types) -{ - types.RemoveAll(); - - BeginEnumMediaTypes(pPin, pEM, pmt) { - bool fFound = false; - - for (ptrdiff_t i = 0; !fFound && i < (int)types.GetCount(); i += 2) { - if (types[i] == pmt->majortype && types[i + 1] == pmt->subtype) { - fFound = true; - } - } - - if (!fFound) { - types.Add(pmt->majortype); - types.Add(pmt->subtype); - } - } - EndEnumMediaTypes(pmt); -} - -void ExtractMediaTypes(IPin* pPin, CAtlList& mts) -{ - mts.RemoveAll(); - - BeginEnumMediaTypes(pPin, pEM, pmt) { - bool fFound = false; - - POSITION pos = mts.GetHeadPosition(); - while (!fFound && pos) { - CMediaType& mt = mts.GetNext(pos); - if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { - fFound = true; - } - } - - if (!fFound) { - mts.AddTail(CMediaType(*pmt)); - } - } - EndEnumMediaTypes(pmt); -} - -int Eval_Exception(int n_except) -{ - if (n_except == STATUS_ACCESS_VIOLATION) { - AfxMessageBox(_T("The property page of this filter has just caused a\nmemory access violation. The application will gently die now :)")); - } - - return EXCEPTION_CONTINUE_SEARCH; -} - -void MyOleCreatePropertyFrame(HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption, ULONG cObjects, LPUNKNOWN FAR* lplpUnk, ULONG cPages, LPCLSID lpPageClsID, LCID lcid, DWORD dwReserved, LPVOID lpvReserved) -{ - __try { - OleCreatePropertyFrame(hwndOwner, x, y, lpszCaption, cObjects, lplpUnk, cPages, lpPageClsID, lcid, dwReserved, lpvReserved); - } __except (Eval_Exception(GetExceptionCode())) { - // No code; this block never executed. - } -} - -void ShowPPage(CString DisplayName, HWND hParentWnd) -{ - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBindCtx, CStringW(DisplayName), &chEaten, &pMoniker)) { - return; - } - - CComPtr pBF; - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { - return; - } - - ShowPPage(pBF, hParentWnd); -} - -void ShowPPage(IUnknown* pUnk, HWND hParentWnd) -{ - CComQIPtr pSPP = pUnk; - if (!pSPP) { - return; - } - - CString str; - - CComQIPtr pBF = pSPP; - CFilterInfo fi; - CComQIPtr pPin = pSPP; - CPinInfo pi; - if (pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) { - str = fi.achName; - } else if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { - str = pi.achName; - } - - CAUUID caGUID; - caGUID.pElems = nullptr; - if (SUCCEEDED(pSPP->GetPages(&caGUID))) { - IUnknown* lpUnk = nullptr; - pSPP.QueryInterface(&lpUnk); - MyOleCreatePropertyFrame( - hParentWnd, 0, 0, CStringW(str), - 1, (IUnknown**)&lpUnk, - caGUID.cElems, caGUID.pElems, - 0, 0, nullptr); - lpUnk->Release(); - - if (caGUID.pElems) { - CoTaskMemFree(caGUID.pElems); - } - } -} - -CLSID GetCLSID(IBaseFilter* pBF) -{ - CLSID clsid = GUID_NULL; - if (pBF) { - pBF->GetClassID(&clsid); - } - return clsid; -} - -CLSID GetCLSID(IPin* pPin) -{ - return GetCLSID(GetFilterFromPin(pPin)); -} - -CString CLSIDToString(CLSID& clsid) -{ - CComHeapPtr pStr; - if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { - return CString(pStr); - } - return CString(); -} - -bool IsCLSIDRegistered(LPCTSTR clsid) -{ - CString rootkey1(_T("CLSID\\")); - CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); - - return ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey1 + clsid, KEY_READ) - || ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey2 + clsid, KEY_READ); -} - -bool IsCLSIDRegistered(const CLSID& clsid) -{ - bool fRet = false; - - CComHeapPtr pStr; - if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { - fRet = IsCLSIDRegistered(CString(pStr)); - } - - return fRet; -} - -CString GetFilterPath(LPCTSTR clsid) -{ - CString rootkey1(_T("CLSID\\")); - CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); - - CRegKey key; - CString path; - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, rootkey1 + clsid + _T("\\InprocServer32"), KEY_READ) - || ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, rootkey2 + clsid + _T("\\InprocServer32"), KEY_READ)) { - ULONG nCount = MAX_PATH; - key.QueryStringValue(nullptr, path.GetBuffer(nCount), &nCount); - path.ReleaseBuffer(nCount); - } - - return path; -} - -CString GetFilterPath(const CLSID& clsid) -{ - CString path; - - CComHeapPtr pStr; - if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { - path = GetFilterPath(CString(pStr)); - } - - return path; -} - -void CStringToBin(CString str, CAtlArray& data) -{ - str.Trim(); - ASSERT((str.GetLength() & 1) == 0); - data.SetCount(str.GetLength() / 2); - - BYTE b = 0; - - str.MakeUpper(); - for (int i = 0, j = str.GetLength(); i < j; i++) { - TCHAR c = str[i]; - if (c >= _T('0') && c <= _T('9')) { - if (!(i & 1)) { - b = ((char(c - _T('0')) << 4) & 0xf0) | (b & 0x0f); - } else { - b = (char(c - _T('0')) & 0x0f) | (b & 0xf0); - } - } else if (c >= _T('A') && c <= _T('F')) { - if (!(i & 1)) { - b = ((char(c - _T('A') + 10) << 4) & 0xf0) | (b & 0x0f); - } else { - b = (char(c - _T('A') + 10) & 0x0f) | (b & 0xf0); - } - } else { - break; - } - - if (i & 1) { - data[i >> 1] = b; - b = 0; - } - } -} - -CString BinToCString(const BYTE* ptr, size_t len) -{ - CString ret; - - while (len-- > 0) { - TCHAR high, low; - - high = (*ptr >> 4) >= 10 ? (*ptr >> 4) - 10 + _T('A') : (*ptr >> 4) + _T('0'); - low = (*ptr & 0xf) >= 10 ? (*ptr & 0xf) - 10 + _T('A') : (*ptr & 0xf) + _T('0'); - - ret.AppendFormat(_T("%c%c"), high, low); - - ptr++; - } - - return ret; -} - -void FindFiles(CString fn, CAtlList& files) -{ - ExtendMaxPathLengthIfNeeded(fn); - CString path = fn; - path.Replace('/', '\\'); - path = path.Left(path.ReverseFind('\\') + 1); - - WIN32_FIND_DATA findData; - ZeroMemory(&findData, sizeof(WIN32_FIND_DATA)); - HANDLE h = FindFirstFile(fn, &findData); - if (h != INVALID_HANDLE_VALUE) { - do { - files.AddTail(path + findData.cFileName); - } while (FindNextFile(h, &findData)); - - FindClose(h); - } -} - -OpticalDiskType_t GetOpticalDiskType(TCHAR drive, CAtlList& files) -{ - files.RemoveAll(); - - CString path; - path.Format(_T("%c:"), drive); - - if (GetDriveType(path + _T("\\")) != DRIVE_CDROM) { - return OpticalDisk_NotFound; - } - - // Check if it contains a disc - HANDLE hDevice = CreateFile(CString(_T("\\\\.\\")) + path, FILE_READ_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (hDevice == INVALID_HANDLE_VALUE) { - return OpticalDisk_NotFound; - } - DWORD cbBytesReturned; - BOOL bSuccess = DeviceIoControl(hDevice, IOCTL_STORAGE_CHECK_VERIFY2, - NULL, 0, NULL, 0, &cbBytesReturned, (LPOVERLAPPED)NULL); - if (!bSuccess) { - return OpticalDisk_NotFound; - } - - // CDROM_DVDVideo - FindFiles(path + _T("\\VIDEO_TS\\video_ts.ifo"), files); - if (!files.IsEmpty()) { - return OpticalDisk_DVDVideo; - } - - // CDROM_BD - FindFiles(path + _T("\\BDMV\\index.bdmv"), files); - if (!files.IsEmpty()) { - return OpticalDisk_BD; - } - - // CDROM_VideoCD - FindFiles(path + _T("\\mpegav\\avseq??.dat"), files); - FindFiles(path + _T("\\mpegav\\avseq??.mpg"), files); - FindFiles(path + _T("\\mpeg2\\avseq??.dat"), files); - FindFiles(path + _T("\\mpeg2\\avseq??.mpg"), files); - FindFiles(path + _T("\\mpegav\\music??.dat"), files); - FindFiles(path + _T("\\mpegav\\music??.mpg"), files); - FindFiles(path + _T("\\mpeg2\\music??.dat"), files); - FindFiles(path + _T("\\mpeg2\\music??.mpg"), files); - if (!files.IsEmpty()) { - return OpticalDisk_VideoCD; - } - - // CDROM_Audio - HANDLE hDrive = CreateFile(CString(_T("\\\\.\\")) + path, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)nullptr); - if (hDrive != INVALID_HANDLE_VALUE) { - DWORD BytesReturned; - CDROM_TOC TOC; - if (DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &TOC, sizeof(TOC), &BytesReturned, 0)) { - ASSERT(TOC.FirstTrack >= 1u && TOC.LastTrack <= _countof(TOC.TrackData)); - TOC.FirstTrack = std::max(TOC.FirstTrack, UCHAR(1)); - TOC.LastTrack = std::min(TOC.LastTrack, UCHAR(_countof(TOC.TrackData))); - for (ptrdiff_t i = TOC.FirstTrack; i <= TOC.LastTrack; i++) { - // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field - auto& trackData = TOC.TrackData[i - 1]; - trackData.Control &= 5; - if (trackData.Control == 0 || trackData.Control == 1) { - CString fn; - fn.Format(_T("%s\\track%02Id.cda"), path.GetString(), i); - files.AddTail(fn); - } - } - } - - CloseHandle(hDrive); - } - if (!files.IsEmpty()) { - return OpticalDisk_Audio; - } - - // it is a cdrom but nothing special - return OpticalDisk_Unknown; -} - -CString GetDriveLabel(TCHAR drive) -{ - CString path; - path.Format(_T("%c:\\"), drive); - - return GetDriveLabel(CPath(path)); -} - -CString GetDriveLabel(CPath path) -{ - CString label; - path.StripToRoot(); - - TCHAR VolumeNameBuffer[MAX_PATH], FileSystemNameBuffer[MAX_PATH]; - DWORD VolumeSerialNumber, MaximumComponentLength, FileSystemFlags; - if (GetVolumeInformation(path, - VolumeNameBuffer, MAX_PATH, &VolumeSerialNumber, &MaximumComponentLength, - &FileSystemFlags, FileSystemNameBuffer, MAX_PATH)) { - label = VolumeNameBuffer; - } - - return label; -} - -bool IsDriveVirtual(CString drive) -{ - HKEY hkey; - DWORD type = REG_BINARY; - TCHAR data[1024] = { 0 }; - DWORD size = sizeof(data) - 2; - - drive=(drive+_T(":")).Left(2); - CString subkey = _T("\\DosDevices\\") + drive; - - RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\MountedDevices"), 0, KEY_READ, &hkey); - if (hkey == INVALID_HANDLE_VALUE) return 0; - RegQueryValueEx(hkey, subkey, 0, &type, (BYTE*)data, &size); - - RegCloseKey(hkey); - CString sig(data); - sig.MakeUpper(); - return sig.Find(_T("VEN_MSFT&PROD_VIRTUAL_DVD-ROM")) >= 0 - || sig.Find(_T("VEN_DISCSOFT&")) >= 0 - || sig.Find(_T("VEN_ELBY&PROD_CLONEDRIVE")) >= 0; -} - -bool GetKeyFrames(CString fn, CUIntArray& kfs) -{ - kfs.RemoveAll(); - - CString fn2 = CString(fn).MakeLower(); - if (fn2.Mid(fn2.ReverseFind('.') + 1) == _T("avi")) { - AVIFileInit(); - - PAVIFILE pfile; - if (AVIFileOpen(&pfile, fn, OF_SHARE_DENY_WRITE, 0L) == 0) { - AVIFILEINFO afi; - ZeroMemory(&afi, sizeof(afi)); - AVIFileInfo(pfile, &afi, sizeof(AVIFILEINFO)); - - CComPtr pavi; - if (AVIFileGetStream(pfile, &pavi, streamtypeVIDEO, 0) == AVIERR_OK) { - AVISTREAMINFO si; - AVIStreamInfo(pavi, &si, sizeof(si)); - - if (afi.dwCaps & AVIFILECAPS_ALLKEYFRAMES) { - kfs.SetSize(si.dwLength); - for (DWORD kf = 0; kf < si.dwLength; kf++) { - kfs[kf] = kf; - } - } else { - for (LONG kf = 0; ; kf++) { - kf = pavi->FindSample(kf, FIND_KEY | FIND_NEXT); - if (kf < 0 || !kfs.IsEmpty() && kfs[kfs.GetCount() - 1] >= (UINT)kf) { - break; - } - kfs.Add(kf); - } - - if (!kfs.IsEmpty() && kfs[kfs.GetCount() - 1] < si.dwLength - 1) { - kfs.Add(si.dwLength - 1); - } - } - } - - AVIFileRelease(pfile); - } - - AVIFileExit(); - } - - return !kfs.IsEmpty(); -} - -DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps /*= 0.0*/) // use to remember the current position -{ - DVD_HMSF_TIMECODE hmsf = { - (BYTE)((rt / 10000000 / 60 / 60)), - (BYTE)((rt / 10000000 / 60) % 60), - (BYTE)((rt / 10000000) % 60), - (BYTE)(1.0 * ((rt / 10000) % 1000) * fps / 1000) - }; - - return hmsf; -} - -DVD_HMSF_TIMECODE RT2HMS(REFERENCE_TIME rt) // used only for information (for display on the screen) -{ - rt = rt / 10000000; - DVD_HMSF_TIMECODE hmsf = { - (BYTE)(rt / 3600), - (BYTE)(rt / 60 % 60), - (BYTE)(rt % 60), - 0 - }; - - return hmsf; -} - -DVD_HMSF_TIMECODE RT2HMS_r(REFERENCE_TIME rt) // used only for information (for display on the screen) -{ - // round to nearest second - return RT2HMS(rt + 5000000); -} - -REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps /*= -1.0*/) -{ - if (fps <= 0.0) { - hmsf.bFrames = 0; - fps = 1.0; - } - return (REFERENCE_TIME)((((REFERENCE_TIME)hmsf.bHours * 60 + hmsf.bMinutes) * 60 + hmsf.bSeconds) * 1000 + 1.0 * hmsf.bFrames * 1000 / fps) * 10000; -} - -void memsetd(void* dst, unsigned int c, size_t nbytes) -{ - size_t n = nbytes / 4; - __stosd((unsigned long*)dst, c, n); -} - -void memsetw(void* dst, unsigned short c, size_t nbytes) -{ - memsetd(dst, c << 16 | c, nbytes); - - size_t n = nbytes / 2; - size_t o = (n / 2) * 2; - if ((n - o) == 1) { - ((WORD*)dst)[o] = c; - } -} - -bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih) -{ - if (pmt && bih && pmt->pbFormat) { - ZeroMemory(bih, sizeof(*bih)); - - if (pmt->formattype == FORMAT_VideoInfo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } else if (pmt->formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } else if (pmt->formattype == FORMAT_MPEGVideo) { - VIDEOINFOHEADER* vih = &((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } else if (pmt->formattype == FORMAT_MPEG2_VIDEO) { - VIDEOINFOHEADER2* vih = &((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } else if (pmt->formattype == FORMAT_DiracVideoInfo) { - VIDEOINFOHEADER2* vih = &((DIRACINFOHEADER*)pmt->pbFormat)->hdr; - memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); - return true; - } - } - - return false; -} - -bool ExtractAvgTimePerFrame(const AM_MEDIA_TYPE* pmt, REFERENCE_TIME& rtAvgTimePerFrame) -{ - if (pmt->formattype == FORMAT_VideoInfo) { - rtAvgTimePerFrame = ((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame; - } else if (pmt->formattype == FORMAT_VideoInfo2) { - rtAvgTimePerFrame = ((VIDEOINFOHEADER2*)pmt->pbFormat)->AvgTimePerFrame; - } else if (pmt->formattype == FORMAT_MPEGVideo) { - rtAvgTimePerFrame = ((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr.AvgTimePerFrame; - } else if (pmt->formattype == FORMAT_MPEG2Video) { - rtAvgTimePerFrame = ((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.AvgTimePerFrame; - } else { - return false; - } - - return true; -} - -bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih) -{ - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pMS->GetMediaType(&pmt)) && pmt) { - bool fRet = ExtractBIH(pmt, bih); - DeleteMediaType(pmt); - return fRet; - } - - return false; -} - -bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary) -{ - w = h = arx = ary = 0; - - if (pmt->formattype == FORMAT_VideoInfo || pmt->formattype == FORMAT_MPEGVideo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; - w = vih->bmiHeader.biWidth; - h = abs(vih->bmiHeader.biHeight); - arx = w * vih->bmiHeader.biYPelsPerMeter; - ary = h * vih->bmiHeader.biXPelsPerMeter; - } else if (pmt->formattype == FORMAT_VideoInfo2 || pmt->formattype == FORMAT_MPEG2_VIDEO || pmt->formattype == FORMAT_DiracVideoInfo) { - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; - w = vih->bmiHeader.biWidth; - h = abs(vih->bmiHeader.biHeight); - arx = vih->dwPictAspectRatioX; - ary = vih->dwPictAspectRatioY; - } else { - return false; - } - - if (!arx || !ary) { - BYTE* ptr = nullptr; - DWORD len = 0; - - if (pmt->formattype == FORMAT_MPEGVideo) { - ptr = ((MPEG1VIDEOINFO*)pmt->pbFormat)->bSequenceHeader; - len = ((MPEG1VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; - - if (ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { - w = (ptr[4] << 4) | (ptr[5] >> 4); - h = ((ptr[5] & 0xf) << 8) | ptr[6]; - float ar[] = { - 1.0000f, 1.0000f, 0.6735f, 0.7031f, - 0.7615f, 0.8055f, 0.8437f, 0.8935f, - 0.9157f, 0.9815f, 1.0255f, 1.0695f, - 1.0950f, 1.1575f, 1.2015f, 1.0000f, - }; - arx = (int)((float)w / ar[ptr[7] >> 4] + 0.5); - ary = h; - } - } else if (pmt->formattype == FORMAT_MPEG2_VIDEO) { - ptr = (BYTE*)((MPEG2VIDEOINFO*)pmt->pbFormat)->dwSequenceHeader; - len = ((MPEG2VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; - - if (ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { - w = (ptr[4] << 4) | (ptr[5] >> 4); - h = ((ptr[5] & 0xf) << 8) | ptr[6]; - struct { - int x, y; - } ar[] = {{w, h}, {4, 3}, {16, 9}, {221, 100}, {w, h}}; - int i = std::min(std::max(ptr[7] >> 4, 1), 5) - 1; - arx = ar[i].x; - ary = ar[i].y; - } - } - } - - if (!arx || !ary) { - arx = w; - ary = h; - } - - DWORD a = arx, b = ary; - while (a) { - int tmp = a; - a = b % tmp; - b = tmp; - } - if (b) { - arx /= b, ary /= b; - } - - return true; -} - -bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName) -{ - if (!ppBF) { - return false; - } - - *ppBF = nullptr; - FriendlyName.Empty(); - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { - return false; - } - - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(ppBF))) || !*ppBF) { - return false; - } - - CComPtr pPB; - CComVariant var; - if (SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB))) - && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - FriendlyName = var.bstrVal; - } - - return true; -} - -IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB) -{ - do { - if (!pPin || !pMoniker || !pGB) { - break; - } - - CComPtr pPinTo; - PIN_DIRECTION dir; - if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) { - break; - } - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pPB; - if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { - break; - } - - CComVariant var; - if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - break; - } - - CComPtr pBF; - if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { - break; - } - - if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { - break; - } - - BeginEnumPins(pBF, pEP, pPinTo2) { - PIN_DIRECTION dir2; - if (FAILED(pPinTo2->QueryDirection(&dir2)) || dir2 != PINDIR_INPUT) { - continue; - } - - if (SUCCEEDED(pGB->ConnectDirect(pPin, pPinTo2, nullptr))) { - return pBF; - } - } - EndEnumFilters; - - pGB->RemoveFilter(pBF); - } while (false); - - return nullptr; -} - -CStringW GetFriendlyName(CStringW displayName) -{ - CStringW friendlyName; - - CComPtr pBindCtx; - CreateBindCtx(0, &pBindCtx); - - CComPtr pMoniker; - ULONG chEaten; - if (S_OK == MkParseDisplayName(pBindCtx, CComBSTR(displayName), &chEaten, &pMoniker)) { - CComPtr pPB; - CComVariant var; - if (SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB))) - && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - friendlyName = var.bstrVal; - } - } - - return friendlyName; -} - -typedef HRESULT(__stdcall* fDllCanUnloadNow)(void); - -struct ExternalObject { - CString path; - HINSTANCE hInst; - CLSID clsid; - fDllCanUnloadNow fpDllCanUnloadNow; - bool bUnloadOnNextCheck; -}; - -static CAtlList s_extObjs; -static CCritSec s_csExtObjs; - -HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv, IUnknown* aggregate) -{ - CheckPointer(ppv, E_POINTER); - - CAutoLock lock(&s_csExtObjs); - - CString fullpath = MakeFullPath(path); - - HINSTANCE hInst = nullptr; - bool fFound = false; - - POSITION pos = s_extObjs.GetHeadPosition(); - while (pos) { - ExternalObject& eo = s_extObjs.GetNext(pos); - if (!eo.path.CompareNoCase(fullpath)) { - hInst = eo.hInst; - fFound = true; - eo.bUnloadOnNextCheck = false; - break; - } - } - - HRESULT hr = E_FAIL; - - if (!hInst) { - hInst = LoadLibraryEx(fullpath, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); - } - if (hInst) { - typedef HRESULT(__stdcall * PDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID * ppv); - PDllGetClassObject p = (PDllGetClassObject)GetProcAddress(hInst, "DllGetClassObject"); - - if (p && (aggregate || FAILED(hr = p(clsid, iid, ppv)))) { - CComPtr pCF; - if (SUCCEEDED(hr = p(clsid, IID_PPV_ARGS(&pCF)))) { - hr = pCF->CreateInstance(aggregate, iid, ppv); - } - } - } - - if (FAILED(hr) && hInst && !fFound) { - FreeLibrary(hInst); - return hr; - } - - if (hInst && !fFound) { - ExternalObject eo; - eo.path = fullpath; - eo.hInst = hInst; - eo.clsid = clsid; - eo.fpDllCanUnloadNow = (fDllCanUnloadNow)GetProcAddress(hInst, "DllCanUnloadNow"); - eo.bUnloadOnNextCheck = false; - s_extObjs.AddTail(eo); - } - - return hr; -} - -HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF) -{ - return LoadExternalObject(path, clsid, IID_PPV_ARGS(ppBF)); -} - -HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP) -{ - CAutoLock lock(&s_csExtObjs); - - CLSID clsid2 = GUID_NULL; - if (FAILED(pP->GetClassID(&clsid2))) { - return E_FAIL; - } - - POSITION pos = s_extObjs.GetHeadPosition(); - while (pos) { - ExternalObject& eo = s_extObjs.GetNext(pos); - if (eo.clsid == clsid2) { - return LoadExternalObject(eo.path, clsid, IID_PPV_ARGS(ppPP)); - } - } - - return E_FAIL; -} - -bool UnloadUnusedExternalObjects() -{ - CAutoLock lock(&s_csExtObjs); - - POSITION pos = s_extObjs.GetHeadPosition(), currentPos; - while (pos) { - currentPos = pos; - ExternalObject& eo = s_extObjs.GetNext(pos); - - if (eo.fpDllCanUnloadNow && eo.fpDllCanUnloadNow() == S_OK) { - // Before actually unloading it, we require that the library reports - // that it can be unloaded safely twice in a row with a 60s delay - // between the two checks. - if (eo.bUnloadOnNextCheck) { - FreeLibrary(eo.hInst); - s_extObjs.RemoveAt(currentPos); - } else { - eo.bUnloadOnNextCheck = true; - } - } else { - eo.bUnloadOnNextCheck = false; - } - } - - return s_extObjs.IsEmpty(); -} - -void ExtendMaxPathLengthIfNeeded(CString& path, bool no_url /*= false */) -{ - if (path.GetLength() >= MAX_PATH) { - if (no_url || path.Find(_T("://")) < 0) { // not URL - if (path.Left(4) != _T("\\\\?\\")) { // not already have long path prefix - if (path.Left(2) == _T("\\\\")) { // UNC - path = _T("\\\\?\\UNC") + path.Mid(1); - } else { // normal - path = _T("\\\\?\\") + path; - } - } - } - } -} - -bool ContainsWildcard(CString& path) -{ - int p = path.Find('*'); - if (p >= 0) { - return true; - } - p = path.Find('?'); - if (p >= 0) { - if (p == 2 && path.Left(4) == _T("\\\\?\\")) { - CString tmp = CString(path); - tmp.Delete(0, 3); - return tmp.Find('?') > 0; - } - return true; - } - return false; -} - -void ShortenLongPath(CString& path) -{ - if (path.GetLength() > MAX_PATH && path.Find(_T("\\\\?\\")) < 0) { - CString longpath = _T("\\\\?\\") + path; - TCHAR* buffer = DEBUG_NEW TCHAR[MAX_PATH]; - long length = GetShortPathName(longpath, buffer, MAX_PATH); - if (length > 0 && length < MAX_PATH) { - path = buffer; - path.Replace(_T("\\\\?\\"), _T("")); - delete[] buffer; - } - } -} - -CString MakeFullPath(LPCTSTR path) -{ - CString full(path); - full.Replace('/', '\\'); - - if (full.GetLength() > MAX_PATH) { - return full; - } - - if (full.GetLength() >= 2 && full[0] == '\\') { - if (full[1] != '\\') { - CString fn; - fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); - CPath p(fn); - p.StripToRoot(); - full = CString(p) + full.Mid(1); - } - } else if (full.Find(_T(":\\")) < 0) { - CString fn; - fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); - CPath p(fn); - p.RemoveFileSpec(); - p.AddBackslash(); - full = CString(p) + full; - } - - CPath c(full); - c.Canonicalize(); - return CString(c); -} - -inline bool _IsFourCC(const GUID& guid) -{ - // XXXXXXXX-0000-0010-8000-00AA00389B71 - return (guid.Data2 == 0x0000) && (guid.Data3 == 0x0010) && - (((DWORD*)guid.Data4)[0] == 0xAA000080) && - (((DWORD*)guid.Data4)[1] == 0x719b3800); -} - -bool GetMediaTypeFourCC(const GUID& guid, CString& fourCC) -{ - if (_IsFourCC(guid) && (guid.Data1 >= 0x10000)) { - fourCC.Format(_T("%c%c%c%c"), - (TCHAR)(guid.Data1 >> 0 ) & 0xFF, (TCHAR)(guid.Data1 >> 8 ) & 0xFF, - (TCHAR)(guid.Data1 >> 16) & 0xFF, (TCHAR)(guid.Data1 >> 24) & 0xFF); - fourCC.MakeUpper(); - return true; - } - - fourCC = _T("UNKN"); - return false; -} - -CString GetMediaTypeName(const GUID& guid) -{ - CString ret = guid == GUID_NULL - ? CString(_T("Any type")) - : CString(GuidNames[guid]); - - if (ret == _T("FOURCC GUID")) { - CString str; - if (guid.Data1 >= 0x10000) { - str.Format(_T("Video: %c%c%c%c"), (guid.Data1 >> 0) & 0xff, (guid.Data1 >> 8) & 0xff, (guid.Data1 >> 16) & 0xff, (guid.Data1 >> 24) & 0xff); - } else { - str.Format(_T("Audio: 0x%08x"), guid.Data1); - } - ret = str; - } else if (ret == _T("Unknown GUID Name")) { - WCHAR null[128] = {0}, buff[128]; - StringFromGUID2(GUID_NULL, null, _countof(null) - 1); - ret = CString(CStringW(StringFromGUID2(guid, buff, _countof(buff) - 1) ? buff : null)); - } - - return ret; -} - -GUID GUIDFromCString(CString str) -{ - GUID guid = GUID_NULL; - HRESULT hr = CLSIDFromString(CComBSTR(str), &guid); - ASSERT(SUCCEEDED(hr)); - UNREFERENCED_PARAMETER(hr); - return guid; -} - -HRESULT GUIDFromCString(CString str, GUID& guid) -{ - guid = GUID_NULL; - return CLSIDFromString(CComBSTR(str), &guid); -} - -CString CStringFromGUID(const GUID& guid) -{ - WCHAR null[128] = {0}, buff[128]; - StringFromGUID2(GUID_NULL, null, _countof(null) - 1); - return CString(StringFromGUID2(guid, buff, _countof(buff) - 1) > 0 ? buff : null); -} - -CStringW UTF8To16(LPCSTR utf8) -{ - CStringW str; - int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0) - 1; - if (n <= 0) { - return str; - } - str.ReleaseBuffer(MultiByteToWideChar(CP_UTF8, 0, utf8, -1, str.GetBuffer(n), n + 1) - 1); - return str; -} - -CStringA UTF16To8(LPCWSTR utf16) -{ - CStringA str; - int n = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, nullptr, 0, nullptr, nullptr) - 1; - if (n < 0) { - return str; - } - str.ReleaseBuffer(WideCharToMultiByte(CP_UTF8, 0, utf16, -1, str.GetBuffer(n), n + 1, nullptr, nullptr) - 1); - return str; -} - -CStringW UTF8ToStringW(const char* S) -{ - CStringW str; - if (S == nullptr) { - return str; - } - - // Don't use MultiByteToWideChar(), some characters are not well decoded - const unsigned char* Z = (const unsigned char*)S; - while (*Z) { //0 is end - //1 byte - if (*Z < 0x80) { - str += (wchar_t)(*Z); - Z++; - } - //2 bytes - else if ((*Z & 0xE0) == 0xC0) { - if ((*(Z + 1) & 0xC0) == 0x80) { - str += (wchar_t)((((wchar_t)(*Z & 0x1F)) << 6) | (*(Z + 1) & 0x3F)); - Z += 2; - } else { - str.Empty(); - return str; //Bad character - } - } - //3 bytes - else if ((*Z & 0xF0) == 0xE0) { - if ((*(Z + 1) & 0xC0) == 0x80 && (*(Z + 2) & 0xC0) == 0x80) { - str += (wchar_t)((((wchar_t)(*Z & 0x0F)) << 12) | ((*(Z + 1) & 0x3F) << 6) | (*(Z + 2) & 0x3F)); - Z += 3; - } else { - str.Empty(); - return str; //Bad character - } - } - //4 bytes - else if ((*Z & 0xF8) == 0xF0) { - if ((*(Z + 1) & 0xC0) == 0x80 && (*(Z + 2) & 0xC0) == 0x80 && (*(Z + 3) & 0xC0) == 0x80) { - str += (wchar_t)((((wchar_t)(*Z & 0x0F)) << 18) | ((*(Z + 1) & 0x3F) << 12) || ((*(Z + 2) & 0x3F) << 6) | (*(Z + 3) & 0x3F)); - Z += 4; - } else { - str.Empty(); - return str; //Bad character - } - } else { - str.Empty(); - return str; //Bad character - } - } - return str; -} - -CStringW LocalToStringW(const char* S) -{ - CStringW str; - if (S == nullptr) { - return str; - } - - int Size = MultiByteToWideChar(CP_ACP, 0, S, -1, nullptr, 0); - if (Size != 0) { - str.ReleaseBuffer(MultiByteToWideChar(CP_ACP, 0, S, -1, str.GetBuffer(Size), Size + 1) - 1); - } - return str; -} - -BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status) -{ - try { - return CFile::GetStatus(lpszFileName, status); - } catch (CException* e) { - // MFCBUG: E_INVALIDARG / "Parameter is incorrect" is thrown for certain cds (vs2003) - // http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8&threadm=OZuXYRzWDHA.536%40TK2MSFTNGP10.phx.gbl&rnum=1&prev=/groups%3Fhl%3Den%26lr%3D%26ie%3DISO-8859-1 - TRACE(_T("CFile::GetStatus has thrown an exception\n")); - e->Delete(); - return false; - } -} - -// filter registration helpers - -bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey) -{ - bool bOK = false; - - HKEY hKey; - LONG ec = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, pszKey, 0, KEY_ALL_ACCESS, &hKey); - if (ec == ERROR_SUCCESS) { - if (pszSubkey != 0) { - ec = ::RegDeleteKey(hKey, pszSubkey); - } - - bOK = (ec == ERROR_SUCCESS); - - ::RegCloseKey(hKey); - } - - return bOK; -} - -bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue) -{ - bool bOK = false; - - CString szKey(pszKey); - if (pszSubkey != 0) { - szKey += CString(_T("\\")) + pszSubkey; - } - - HKEY hKey; - LONG ec = ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); - if (ec == ERROR_SUCCESS) { - if (pszValue != 0) { - ec = ::RegSetValueEx(hKey, pszValueName, 0, REG_SZ, - reinterpret_cast(const_cast(pszValue)), - (DWORD)(_tcslen(pszValue) + 1) * sizeof(TCHAR)); - } - - bOK = (ec == ERROR_SUCCESS); - - ::RegCloseKey(hKey); - } - - return bOK; -} - -bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue) -{ - return SetRegKeyValue(pszKey, pszSubkey, 0, pszValue); -} - -void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext, ...) -{ - CString null = CStringFromGUID(GUID_NULL); - CString majortype = CStringFromGUID(MEDIATYPE_Stream); - CString subtype = CStringFromGUID(subtype2); - - SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("0"), chkbytes); - SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); - - DeleteRegKey(_T("Media Type\\") + null, subtype); - - va_list marker; - va_start(marker, ext); - for (; ext; ext = va_arg(marker, LPCTSTR)) { - DeleteRegKey(_T("Media Type\\Extensions"), ext); - } - va_end(marker); -} - -void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext, ...) -{ - CString null = CStringFromGUID(GUID_NULL); - CString majortype = CStringFromGUID(MEDIATYPE_Stream); - CString subtype = CStringFromGUID(subtype2); - - POSITION pos = chkbytes.GetHeadPosition(); - for (ptrdiff_t i = 0; pos; i++) { - CString idx; - idx.Format(_T("%Id"), i); - SetRegKeyValue(_T("Media Type\\") + majortype, subtype, idx, chkbytes.GetNext(pos)); - } - - SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); - - DeleteRegKey(_T("Media Type\\") + null, subtype); - - va_list marker; - va_start(marker, ext); - for (; ext; ext = va_arg(marker, LPCTSTR)) { - DeleteRegKey(_T("Media Type\\Extensions"), ext); - } - va_end(marker); -} - -void UnRegisterSourceFilter(const GUID& subtype) -{ - DeleteRegKey(_T("Media Type\\") + CStringFromGUID(MEDIATYPE_Stream), CStringFromGUID(subtype)); -} - -struct DXVA2_DECODER { - const GUID* Guid; - LPCTSTR Description; -}; - -static const DXVA2_DECODER DXVA2Decoder[] = { - {&GUID_NULL, _T("Unknown")}, - {&GUID_NULL, _T("Not using DXVA")}, - {&DXVA_Intel_H264_ClearVideo, _T("H.264 bitstream decoder, ClearVideo(tm)")}, // Intel ClearVideo H264 bitstream decoder - {&DXVA_Intel_VC1_ClearVideo, _T("VC-1 bitstream decoder, ClearVideo(tm)")}, // Intel ClearVideo VC-1 bitstream decoder - {&DXVA_Intel_VC1_ClearVideo_2, _T("VC-1 bitstream decoder 2, ClearVideo(tm)")}, // Intel ClearVideo VC-1 bitstream decoder 2 - {&DXVA_MPEG4_ASP, _T("MPEG-4 ASP bitstream decoder")}, // NVIDIA MPEG-4 ASP bitstream decoder - {&DXVA_ModeNone, _T("Mode none")}, - {&DXVA_ModeH261_A, _T("H.261 A, post processing")}, - {&DXVA_ModeH261_B, _T("H.261 B, deblocking")}, - {&DXVA_ModeH263_A, _T("H.263 A, motion compensation, no FGT")}, - {&DXVA_ModeH263_B, _T("H.263 B, motion compensation, FGT")}, - {&DXVA_ModeH263_C, _T("H.263 C, IDCT, no FGT")}, - {&DXVA_ModeH263_D, _T("H.263 D, IDCT, FGT")}, - {&DXVA_ModeH263_E, _T("H.263 E, bitstream decoder, no FGT")}, - {&DXVA_ModeH263_F, _T("H.263 F, bitstream decoder, FGT")}, - {&DXVA_ModeMPEG1_A, _T("MPEG-1 A, post processing")}, - {&DXVA_ModeMPEG2_A, _T("MPEG-2 A, motion compensation")}, - {&DXVA_ModeMPEG2_B, _T("MPEG-2 B, motion compensation + blending")}, - {&DXVA_ModeMPEG2_C, _T("MPEG-2 C, IDCT")}, - {&DXVA_ModeMPEG2_D, _T("MPEG-2 D, IDCT + blending")}, - {&DXVA_ModeH264_A, _T("H.264 A, motion compensation, no FGT")}, - {&DXVA_ModeH264_B, _T("H.264 B, motion compensation, FGT")}, - {&DXVA_ModeH264_C, _T("H.264 C, IDCT, no FGT")}, - {&DXVA_ModeH264_D, _T("H.264 D, IDCT, FGT")}, - {&DXVA_ModeH264_E, _T("H.264 E, bitstream decoder, no FGT")}, - {&DXVA_ModeH264_F, _T("H.264 F, bitstream decoder, FGT")}, - {&DXVA_ModeWMV8_A, _T("WMV8 A, post processing")}, - {&DXVA_ModeWMV8_B, _T("WMV8 B, motion compensation")}, - {&DXVA_ModeWMV9_A, _T("WMV9 A, post processing")}, - {&DXVA_ModeWMV9_B, _T("WMV9 B, motion compensation")}, - {&DXVA_ModeWMV9_C, _T("WMV9 C, IDCT")}, - {&DXVA_ModeVC1_A, _T("VC-1 A, post processing")}, - {&DXVA_ModeVC1_B, _T("VC-1 B, motion compensation")}, - {&DXVA_ModeVC1_C, _T("VC-1 C, IDCT")}, - {&DXVA_ModeVC1_D, _T("VC-1 D, bitstream decoder")}, - {&DXVA_NoEncrypt, _T("No encryption")}, - {&DXVA2_ModeMPEG2_MoComp, _T("MPEG-2 motion compensation")}, - {&DXVA2_ModeMPEG2_IDCT, _T("MPEG-2 IDCT")}, - {&DXVA2_ModeMPEG2_VLD, _T("MPEG-2 variable-length decoder")}, - {&DXVA2_ModeH264_A, _T("H.264 A, motion compensation, no FGT")}, - {&DXVA2_ModeH264_B, _T("H.264 B, motion compensation, FGT")}, - {&DXVA2_ModeH264_C, _T("H.264 C, IDCT, no FGT")}, - {&DXVA2_ModeH264_D, _T("H.264 D, IDCT, FGT")}, - {&DXVA2_ModeH264_E, _T("H.264 E, bitstream decoder, no FGT")}, - {&DXVA2_ModeH264_F, _T("H.264 F, bitstream decoder, FGT")}, - {&DXVA2_ModeWMV8_A, _T("WMV8 A, post processing")}, - {&DXVA2_ModeWMV8_B, _T("WMV8 B, motion compensation")}, - {&DXVA2_ModeWMV9_A, _T("WMV9 A, post processing")}, - {&DXVA2_ModeWMV9_B, _T("WMV9 B, motion compensation")}, - {&DXVA2_ModeWMV9_C, _T("WMV9 C, IDCT")}, - {&DXVA2_ModeVC1_A, _T("VC-1 A, post processing")}, - {&DXVA2_ModeVC1_B, _T("VC-1 B, motion compensation")}, - {&DXVA2_ModeVC1_C, _T("VC-1 C, IDCT")}, - {&DXVA2_ModeVC1_D, _T("VC-1 D, bitstream decoder")}, - {&DXVA2_NoEncrypt, _T("No encryption")}, - {&DXVA2_VideoProcProgressiveDevice, _T("Progressive scan")}, - {&DXVA2_VideoProcBobDevice, _T("Bob deinterlacing")}, - {&DXVA2_VideoProcSoftwareDevice, _T("Software processing")} -}; - -LPCTSTR GetDXVAMode(const GUID* guidDecoder) -{ - int nPos = 0; - - for (int i = 1; i < _countof(DXVA2Decoder); i++) { - if (*guidDecoder == *DXVA2Decoder[i].Guid) { - nPos = i; - break; - } - } - - return DXVA2Decoder[nPos].Description; -} - -// hour, minute, second, millisec -CString ReftimeToString(const REFERENCE_TIME& rtVal) -{ - if (rtVal == _I64_MIN) { - return _T("INVALID TIME"); - } - - CString strTemp; - LONGLONG llTotalMs = ConvertToMilliseconds(rtVal); - int lHour = (int)(llTotalMs / (1000 * 60 * 60)); - int lMinute = (llTotalMs / (1000 * 60)) % 60; - int lSecond = (llTotalMs / 1000) % 60; - int lMillisec = llTotalMs % 1000; - - strTemp.Format(_T("%02d:%02d:%02d,%03d"), lHour, lMinute, lSecond, lMillisec); - return strTemp; -} - -// hour, minute, second (round) -CString ReftimeToString2(const REFERENCE_TIME& rtVal) -{ - CString strTemp; - LONGLONG seconds = (rtVal + 5000000) / 10000000; - int lHour = (int)(seconds / 3600); - int lMinute = (int)(seconds / 60 % 60); - int lSecond = (int)(seconds % 60); - - strTemp.Format(_T("%02d:%02d:%02d"), lHour, lMinute, lSecond); - return strTemp; -} - -// minute, second (round) -CString ReftimeToString3(const REFERENCE_TIME& rtVal) -{ - CString strTemp; - LONGLONG seconds = (rtVal + 5000000) / 10000000; - int lMinute = (int)(seconds / 60 % 60); - int lSecond = (int)(seconds % 60); - - ASSERT((int)(seconds / 3600) == 0); - - strTemp.Format(_T("%02d:%02d"), lMinute, lSecond); - return strTemp; -} - -//for compatibility with mpc-be ReftimeToString2, which has option to exclude hours -CStringW ReftimeToString4(REFERENCE_TIME rt, bool showZeroHours /* = true*/) -{ - if (rt == INT64_MIN) { - return L"INVALID TIME"; - } - - DVD_HMSF_TIMECODE tc = RT2HMSF(rt); - - return DVDtimeToString(tc, showZeroHours); -} - -CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours) -{ - CString strTemp; - if (rtVal.bHours > 0 || bAlwaysShowHours) { - strTemp.Format(_T("%02u:%02u:%02u"), rtVal.bHours, rtVal.bMinutes, rtVal.bSeconds); - } else { - strTemp.Format(_T("%02u:%02u"), rtVal.bMinutes, rtVal.bSeconds); - } - return strTemp; -} - -REFERENCE_TIME StringToReftime(LPCTSTR strVal) -{ - REFERENCE_TIME rt = 0; - int lHour = 0; - int lMinute = 0; - int lSecond = 0; - int lMillisec = 0; - - if (_stscanf_s(strVal, _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { - rt = ((((lHour * 60) + lMinute) * 60 + lSecond) * MILLISECONDS + lMillisec) * (UNITS / MILLISECONDS); - } - - return rt; -} - -const wchar_t* StreamTypeToName(PES_STREAM_TYPE _Type) -{ - switch (_Type) { - case VIDEO_STREAM_MPEG1: - return L"MPEG-1"; - case VIDEO_STREAM_MPEG2: - return L"MPEG-2"; - case AUDIO_STREAM_MPEG1: - return L"MPEG-1"; - case AUDIO_STREAM_MPEG2: - return L"MPEG-2"; - case VIDEO_STREAM_H264: - return L"H264"; - case VIDEO_STREAM_HEVC: - return L"HEVC"; - case AUDIO_STREAM_LPCM: - return L"LPCM"; - case AUDIO_STREAM_AC3: - return L"Dolby Digital"; - case AUDIO_STREAM_DTS: - return L"DTS"; - case AUDIO_STREAM_AC3_TRUE_HD: - return L"Dolby TrueHD"; - case AUDIO_STREAM_AC3_PLUS: - return L"Dolby Digital Plus"; - case AUDIO_STREAM_DTS_HD: - return L"DTS-HD High Resolution Audio"; - case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: - return L"DTS-HD Master Audio"; - case PRESENTATION_GRAPHICS_STREAM: - return L"Presentation Graphics Stream"; - case INTERACTIVE_GRAPHICS_STREAM: - return L"Interactive Graphics Stream"; - case SUBTITLE_STREAM: - return L"Subtitle"; - case SECONDARY_AUDIO_AC3_PLUS: - return L"Secondary Dolby Digital Plus"; - case SECONDARY_AUDIO_DTS_HD: - return L"Secondary DTS-HD High Resolution Audio"; - case VIDEO_STREAM_VC1: - return L"VC-1"; - } - return nullptr; -} - -// -// Usage: SetThreadName (-1, "MainThread"); -// Code from http://msdn.microsoft.com/en-us/library/xcb2z8hs%28v=vs.110%29.aspx -// - -#pragma pack(push,8) -typedef struct tagTHREADNAME_INFO { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1 caller thread) - DWORD dwFlags; // reserved for future use, must be zero -} THREADNAME_INFO; -#pragma pack(pop) - -void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) -{ - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = szThreadName; - info.dwThreadID = dwThreadID; - info.dwFlags = 0; - - __try { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); - } __except (EXCEPTION_EXECUTE_HANDLER) { - } -} - -void CorrectComboBoxHeaderWidth(CWnd* pComboBox) -{ - if (!pComboBox) { - return; - } - - CDC* pDC = pComboBox->GetDC(); - CFont* pFont = pComboBox->GetFont(); - CFont* pOldFont = pDC->SelectObject(pFont); - - CString str; - pComboBox->GetWindowText(str); - CSize szText = pDC->GetTextExtent(str); - - TEXTMETRIC tm; - pDC->GetTextMetrics(&tm); - pDC->SelectObject(pOldFont); - pComboBox->ReleaseDC(pDC); - - CRect r; - pComboBox->GetWindowRect(r); - pComboBox->GetOwner()->ScreenToClient(r); - - r.right = r.left + ::GetSystemMetrics(SM_CXMENUCHECK) + ::GetSystemMetrics(SM_CXEDGE) + szText.cx + tm.tmAveCharWidth; - pComboBox->MoveWindow(r); -} - -CString NormalizeUnicodeStrForSearch(CString srcStr, LANGID langid) { - if (srcStr.IsEmpty()) return srcStr; - wchar_t* src; - - _locale_t locale; - LCID lcid = MAKELCID(MAKELANGID(langid, SUBLANG_DEFAULT), SORT_DEFAULT); - wchar_t localeName[32]; - if (0 == LCIDToLocaleName(lcid, localeName, 32, LOCALE_ALLOW_NEUTRAL_NAMES)) { //try to lowercase by locale, but if not, do a regular MakeLower() - srcStr.MakeLower(); - src = srcStr.GetBuffer(); - } else { - src = srcStr.GetBuffer(); - locale = _wcreate_locale(LC_ALL, localeName); - _wcslwr_s_l(src, wcslen(src) + 1, locale); - } - - int dstLen = int(wcslen(src) * 4); - wchar_t* dest = DEBUG_NEW wchar_t[dstLen]; - - int cchActual = NormalizeString(NormalizationKD, src, -1, dest, dstLen); - if (cchActual <= 0) dest[0] = 0; - WORD* rgType = DEBUG_NEW WORD[dstLen]; - GetStringTypeW(CT_CTYPE3, dest, -1, rgType); - PWSTR pszWrite = dest; - for (int i = 0; dest[i]; i++) { - if (!(rgType[i] & C3_NONSPACING)) { - *pszWrite++ = dest[i]; - } - } - *pszWrite = 0; - delete[] rgType; - - CString ret = dest; - delete[] dest; - return ret; -} - -inline const LONGLONG GetPerfCounter() { - auto GetPerfFrequency = [] { - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - return freq.QuadPart; - }; - static const LONGLONG llPerfFrequency = GetPerfFrequency(); - if (llPerfFrequency) { - LARGE_INTEGER llPerfCounter; - QueryPerformanceCounter(&llPerfCounter); - return llMulDiv(llPerfCounter.QuadPart, 10000000LL, llPerfFrequency, 0); - } else { - // ms to 100ns units - return timeGetTime() * 10000; - } -} - -bool FindStringInList(const CAtlList& list, CString& value) -{ - bool found = false; - POSITION pos = list.GetHeadPosition(); - while (pos && !found) { - if (list.GetNext(pos).CompareNoCase(value) == 0) { - found = true; - } - } - return found; -} - -CStringW ForceTrailingSlash(CStringW folder) { - if (folder.Right(1) != L'\\' && folder.GetLength() > 0) { - folder += L'\\'; - } - return folder; -} - -CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt) { - int discard; - return GetChannelStrFromMediaType(pmt, discard); -} - -CStringW ChannelsToStr(int channels) { - CStringW ret; - switch (channels) { - case 1: - return L"mono"; - case 2: - return L"2.0"; - case 6: - return L"5.1"; - case 7: - return L"6.1"; - case 8: - return L"7.1"; - default: - ret.Format(L"%uch", channels); - return ret; - } -} - -CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt, int& channels) { - if (pmt) { - if (pmt->majortype == MEDIATYPE_Audio) { - if (pmt->formattype == FORMAT_WaveFormatEx) { - channels = ((WAVEFORMATEX*)pmt->pbFormat)->nChannels; - return ChannelsToStr(channels); - } else if (pmt->formattype == FORMAT_VorbisFormat) { - channels = ((VORBISFORMAT*)pmt->pbFormat)->nChannels; - return ChannelsToStr(channels); - } else if (pmt->formattype == FORMAT_VorbisFormat2) { - channels = ((VORBISFORMAT2*)pmt->pbFormat)->Channels; - return ChannelsToStr(channels); - } else { - channels = 2; - } - } else if (pmt->majortype == MEDIATYPE_Midi) { - channels = 2; - return L""; - } - } - ASSERT(false); - return L""; -} - -CStringW GetShortAudioNameFromMediaType(AM_MEDIA_TYPE* pmt) { - if (!pmt) { - return L""; - } - if (pmt->majortype != MEDIATYPE_Audio) { - if (pmt->majortype == MEDIATYPE_Midi) { - return L"MIDI"; - } else { - return L""; - } - } - - if (pmt->subtype == MEDIASUBTYPE_AAC || pmt->subtype == MEDIASUBTYPE_LATM_AAC || pmt->subtype == MEDIASUBTYPE_AAC_ADTS || pmt->subtype == MEDIASUBTYPE_MPEG_ADTS_AAC - || pmt->subtype == MEDIASUBTYPE_MPEG_HEAAC || pmt->subtype == MEDIASUBTYPE_MP4A || pmt->subtype == MEDIASUBTYPE_mp4a) { - return L"AAC"; - } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF - || pmt->subtype == MEDIASUBTYPE_RAW_SPORT || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h || pmt->subtype == MEDIASUBTYPE_DVM) { - return L"AC3"; - } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { - return L"E-AC3"; - } else if (pmt->subtype == MEDIASUBTYPE_DTS || pmt->subtype == MEDIASUBTYPE_DTS2 || pmt->subtype == MEDIASUBTYPE_WAVE_DTS) { - return L"DTS"; - } else if (pmt->subtype == MEDIASUBTYPE_DTS_HD) { - return L"DTS-HD"; - } else if (pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { - return L"LPCM"; - } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { - return L"TrueHD"; - } else if (pmt->subtype == MEDIASUBTYPE_MLP) { - return L"MLP"; - } else if (pmt->subtype == MEDIASUBTYPE_PCM || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT) { - return L"PCM"; - } else if (pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload || pmt->subtype == MEDIASUBTYPE_MPEG1Packet || pmt->subtype == MEDIASUBTYPE_MPEG1Payload) { //are these all actually possible? - return L"MP1"; - } else if (pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO) { - return L"MP2"; - } else if (pmt->subtype == MEDIASUBTYPE_MP3) { - return L"MP3"; - } else if (pmt->subtype == MEDIASUBTYPE_FLAC || pmt->subtype == MEDIASUBTYPE_FLAC_FRAMED) { - return L"FLAC"; - } else if (pmt->subtype == MEDIASUBTYPE_Vorbis || pmt->subtype == MEDIASUBTYPE_Vorbis2) { - return L"Vorbis"; - } else if (pmt->subtype == MEDIASUBTYPE_OPUS || pmt->subtype == MEDIASUBTYPE_OPUS_OLD) { - return L"Opus"; - } else if (pmt->subtype == MEDIASUBTYPE_MSAUDIO1) { - return L"WMA1"; - } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO2) { - return L"WMA2"; - } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO3) { - return L"WMA3"; - } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO4) { - return L"WMA4"; - } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO_LOSSLESS) { - return L"WMA-LL"; - } else if (pmt->subtype == MEDIASUBTYPE_BD_LPCM_AUDIO || pmt->subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { - return L"LPCM"; - } else if (pmt->subtype == MEDIASUBTYPE_IMA_AMV || pmt->subtype == MEDIASUBTYPE_ADPCM_MS || pmt->subtype == MEDIASUBTYPE_IMA_WAV || pmt->subtype == MEDIASUBTYPE_ADPCM_SWF) { - return L"ADPCM"; - } else if (pmt->subtype == MEDIASUBTYPE_TRUESPEECH) { - return L"TrueSpeech"; - } else if (pmt->subtype == MEDIASUBTYPE_PCM_NONE || pmt->subtype == MEDIASUBTYPE_PCM_RAW || pmt->subtype == MEDIASUBTYPE_PCM_TWOS || pmt->subtype == MEDIASUBTYPE_PCM_SOWT - || pmt->subtype == MEDIASUBTYPE_PCM_IN24 || pmt->subtype == MEDIASUBTYPE_PCM_IN32 || pmt->subtype == MEDIASUBTYPE_PCM_FL32 || pmt->subtype == MEDIASUBTYPE_PCM_FL64 - || pmt->subtype == MEDIASUBTYPE_PCM_IN24_le || pmt->subtype == MEDIASUBTYPE_PCM_IN32_le || pmt->subtype == MEDIASUBTYPE_PCM_FL32_le || pmt->subtype == MEDIASUBTYPE_PCM_FL64_le) { - return L"QTPCM"; - } else if (pmt->subtype == MEDIASUBTYPE_TTA1) { - return L"TTA"; - } else if (pmt->subtype == MEDIASUBTYPE_SAMR) { - return L"SAMR"; - } else if (pmt->subtype == MEDIASUBTYPE_QDM2) { - return L"QDM2"; - } else if (pmt->subtype == MEDIASUBTYPE_MSGSM610) { - return L"GSM610"; - } else if (pmt->subtype == MEDIASUBTYPE_ALAW || pmt->subtype == MEDIASUBTYPE_MULAW) { - return L"G711"; - } else if (pmt->subtype == MEDIASUBTYPE_G723 || pmt->subtype == MEDIASUBTYPE_VIVO_G723) { - return L"G723"; - } else if (pmt->subtype == MEDIASUBTYPE_G726) { - return L"G726"; - } else if (pmt->subtype == MEDIASUBTYPE_G729 || pmt->subtype == MEDIASUBTYPE_729A) { - return L"G729"; - } else if (pmt->subtype == MEDIASUBTYPE_APE) { - return L"APE"; - } else if (pmt->subtype == MEDIASUBTYPE_TAK) { - return L"TAK"; - } else if (pmt->subtype == MEDIASUBTYPE_ALS) { - return L"ALS"; - } else if (pmt->subtype == MEDIASUBTYPE_NELLYMOSER) { - return L"NELLY"; - } else if (pmt->subtype == MEDIASUBTYPE_SPEEX) { - return L"Speex"; - } else if (pmt->subtype == MEDIASUBTYPE_AES3) { - return L"AES3"; - } else if (pmt->subtype == MEDIASUBTYPE_DSDL || pmt->subtype == MEDIASUBTYPE_DSDM || pmt->subtype == MEDIASUBTYPE_DSD1 || pmt->subtype == MEDIASUBTYPE_DSD8) { - return L"DSD"; - } else if (pmt->subtype == MEDIASUBTYPE_IMC) { - return L"IMC"; - } else if (pmt->subtype == MEDIASUBTYPE_VOXWARE_RT29) { - return L"RT29"; - } else if (pmt->subtype == MEDIASUBTYPE_MPEG_LOAS) { - return L"LOAS"; - } - - if (_IsFourCC(pmt->subtype)) { - CString fcc; - DWORD a = (pmt->subtype.Data1 >> 24) & 0xFF; - DWORD b = (pmt->subtype.Data1 >> 16) & 0xFF; - DWORD c = (pmt->subtype.Data1 >> 8) & 0xFF; - DWORD d = (pmt->subtype.Data1 >> 0) & 0xFF; - if (a != 0 || b != 0) { - fcc.Format(_T("%02x%02x%02x%02x"), a, b, c, d); - } else { - fcc.Format(_T("%02x%02x"), c, d); - } - return fcc; - } - - return L"UNKN"; -} - -bool GetVideoFormatNameFromMediaType(const GUID& guid, CString& name) { - if (GetMediaTypeFourCC(guid, name)) { - if (name == L"HVC1") { - name = L"HEVC"; - } else if (name == L"AVC1") { - name = L"H264"; - } else if (name == L"VP90") { - name = L"VP9"; - } else if (name == L"AV01") { - name = L"AV1"; - } - return true; - } else if (guid == MEDIASUBTYPE_MPEG1Payload || guid == MEDIASUBTYPE_MPEG1Video) { - name = L"MPEG1"; - return true; - } else if (guid == MEDIASUBTYPE_MPEG2_VIDEO) { - name = L"MPEG2"; - return true; - } else if (guid == MEDIASUBTYPE_ARGB32) { - name = L"ARGB"; - return true; - } else if (guid == MEDIASUBTYPE_RGB32) { - name = L"RGB"; - return true; - } else if (guid == MEDIASUBTYPE_LAV_RAWVIDEO) { - name = L"RAW"; - return true; - } else { - name = L"UNKN"; - ASSERT(false); - } - - return false; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "winddk/devioctl.h" +#include "winddk/ntddcdrm.h" +#include "DSUtil.h" +#include "Mpeg2Def.h" +#include +#include +#include "NullRenderers.h" +#include "mvrInterfaces.h" + +#include "moreuuids.h" +#include +#include +#include + +int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC) +{ + nIn = nOut = 0; + nInC = nOutC = 0; + + BeginEnumPins(pBF, pEP, pPin) { + PIN_DIRECTION dir; + if (SUCCEEDED(pPin->QueryDirection(&dir))) { + CComPtr pPinConnectedTo; + pPin->ConnectedTo(&pPinConnectedTo); + + if (dir == PINDIR_INPUT) { + nIn++; + if (pPinConnectedTo) { + nInC++; + } + } else if (dir == PINDIR_OUTPUT) { + nOut++; + if (pPinConnectedTo) { + nOutC++; + } + } + } + } + EndEnumPins; + + return (nIn + nOut); +} + +bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly) +{ + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + return (fCountConnectedOnly ? nOutC > 1 : nOut > 1); +} + +bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly) +{ + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + return (fCountConnectedOnly ? nInC > 1 : nIn > 1); +} + +bool IsStreamStart(IBaseFilter* pBF) +{ + CComQIPtr pAMMF(pBF); + if (pAMMF && pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE) { + return true; + } + + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + AM_MEDIA_TYPE mt; + CComPtr pIn = GetFirstPin(pBF); + return ((nOut > 1) + || (nOut > 0 && nIn == 1 && pIn && SUCCEEDED(pIn->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream)); +} + +bool IsStreamEnd(IBaseFilter* pBF) +{ + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + return (nOut == 0); +} + +bool IsVideoRenderer(IBaseFilter* pBF) +{ + CLSID clsid = GetCLSID(pBF); + if (clsid == CLSID_VideoRenderer || clsid == CLSID_VideoRendererDefault || clsid == CLSID_VideoMixingRenderer9 || clsid == CLSID_EnhancedVideoRenderer || clsid == CLSID_madVR || clsid == CLSID_DXR || clsid == CLSID_MPCVR) { + return true; + } + + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + + if (nInC > 0 && nOut == 0) { + BeginEnumPins(pBF, pEP, pPin) { + AM_MEDIA_TYPE mt; + if (S_OK != pPin->ConnectionMediaType(&mt)) { + continue; + } + + FreeMediaType(mt); + + return !!(mt.majortype == MEDIATYPE_Video); + /*&& (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_VideoInfo2));*/ + } + EndEnumPins; + } + + return false; +} + +bool IsAudioWaveRenderer(IBaseFilter* pBF) +{ + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + + if (nInC > 0 && nOut == 0 && CComQIPtr(pBF)) { + BeginEnumPins(pBF, pEP, pPin) { + AM_MEDIA_TYPE mt; + if (S_OK != pPin->ConnectionMediaType(&mt)) { + continue; + } + + FreeMediaType(mt); + + return !!(mt.majortype == MEDIATYPE_Audio); + /*&& mt.formattype == FORMAT_WaveFormatEx);*/ + } + EndEnumPins; + } + + CLSID clsid; + memcpy(&clsid, &GUID_NULL, sizeof(clsid)); + pBF->GetClassID(&clsid); + + return clsid == CLSID_DSoundRender || + clsid == CLSID_AudioRender || + clsid == CLSID_SANEAR_INTERNAL || + clsid == CLSID_SANEAR || + clsid == CLSID_ReClock || + clsid == CLSID_MPCBEAudioRenderer || + clsid == GUIDFromCString(L"{EC9ED6FC-7B03-4cb6-8C01-4EABE109F26B}") || // MediaPortal Audio Renderer + clsid == GUIDFromCString(L"{50063380-2B2F-4855-9A1E-40FCA344C7AC}") || // Surodev ASIO Renderer + clsid == GUIDFromCString(L"{8DE31E85-10FC-4088-8861-E0EC8E70744A}") || // MultiChannel ASIO Renderer + clsid == GUIDFromCString(L"{205F9417-8EEF-40B4-91CF-C7C6A96936EF}") || // MBSE MultiChannel ASIO Renderer + clsid == __uuidof(CNullAudioRenderer) || + clsid == __uuidof(CNullUAudioRenderer); +} + +IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin) +{ + return GetFilterFromPin(GetUpStreamPin(pBF, pInputPin)); +} + +IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin) +{ + BeginEnumPins(pBF, pEP, pPin) { + if (pInputPin && pInputPin != pPin) { + continue; + } + + PIN_DIRECTION dir; + CComPtr pPinConnectedTo; + if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT + && SUCCEEDED(pPin->ConnectedTo(&pPinConnectedTo))) { + IPin* pRet = pPinConnectedTo.Detach(); + pRet->Release(); + return pRet; + } + } + EndEnumPins; + + return nullptr; +} + +IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir) +{ + if (pBF) { + BeginEnumPins(pBF, pEP, pPin) { + PIN_DIRECTION dir2; + if (SUCCEEDED(pPin->QueryDirection(&dir2)) && dir == dir2) { + IPin* pRet = pPin.Detach(); + pRet->Release(); + return pRet; + } + } + EndEnumPins; + } + + return nullptr; +} + +IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir) +{ + if (pBF) { + BeginEnumPins(pBF, pEP, pPin) { + PIN_DIRECTION dir2; + CComPtr pPinTo; + if (SUCCEEDED(pPin->QueryDirection(&dir2)) && dir == dir2 && (S_OK != pPin->ConnectedTo(&pPinTo))) { + IPin* pRet = pPin.Detach(); + pRet->Release(); + return pRet; + } + } + EndEnumPins; + } + + return nullptr; +} + +IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG) +{ + CLSID clsid2; + CLSIDFromString(CComBSTR(clsid), &clsid2); + return FindFilter(clsid2, pFG); +} + +IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG) +{ + BeginEnumFilters(pFG, pEF, pBF) { + CLSID clsid2; + if (SUCCEEDED(pBF->GetClassID(&clsid2)) && clsid == clsid2) { + return pBF; + } + } + EndEnumFilters; + + return nullptr; +} + +IBaseFilter* FindFirstFilter(IFilterGraph* pFG) { + BeginEnumFilters(pFG, pEF, pBF) { + return pBF; + } + EndEnumFilters; + + return nullptr; +} + +IPin* FindPin(IBaseFilter* pBF, PIN_DIRECTION direction, const AM_MEDIA_TYPE* pRequestedMT) +{ + PIN_DIRECTION pindir; + BeginEnumPins(pBF, pEP, pPin) { + CComPtr pFellow; + + if (SUCCEEDED(pPin->QueryDirection(&pindir)) && + pindir == direction && + pPin->ConnectedTo(&pFellow) == VFW_E_NOT_CONNECTED) { + BeginEnumMediaTypes(pPin, pEM, pmt) { + if (pmt->majortype == pRequestedMT->majortype && pmt->subtype == pRequestedMT->subtype) { + return (pPin); + } + } + EndEnumMediaTypes(pmt); + } + } + EndEnumPins; + return nullptr; +} + +CStringW GetFilterName(IBaseFilter* pBF) +{ + CStringW name = _T(""); + + if (pBF) { + CFilterInfo fi; + if (SUCCEEDED(pBF->QueryFilterInfo(&fi))) { + name = fi.achName; + } + } + + return name; +} + +CStringW GetPinName(IPin* pPin) +{ + CStringW name; + CPinInfo pi; + if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { + name = pi.achName; + } + + return name; +} + +IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF) +{ + if (!pBF) { + return nullptr; + } + IFilterGraph* pGraph = nullptr; + CFilterInfo fi; + if (pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) { + pGraph = fi.pGraph; + } + return pGraph; +} + +IBaseFilter* GetFilterFromPin(IPin* pPin) +{ + if (!pPin) { + return nullptr; + } + IBaseFilter* pBF = nullptr; + CPinInfo pi; + if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { + pBF = pi.pFilter; + } + return pBF; +} + +IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) +{ + IPin* pRet = pPin; + + CInterfaceList pFilters; + + do { + if (!pPin || DisplayName.IsEmpty() || !pGB) { + break; + } + + CComPtr pPinTo; + PIN_DIRECTION dir; + if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) { + break; + } + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { + break; + } + + CComPtr pBF; + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { + break; + } + + CComPtr pPB; + if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { + break; + } + + CComVariant var; + if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + break; + } + + pFilters.AddTail(pBF); + BeginEnumFilters(pGB, pEnum, pBF2); + pFilters.AddTail(pBF2); + EndEnumFilters; + + if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { + break; + } + + BeginEnumFilters(pGB, pEnum, pBF2); + if (!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) { + pEnum->Reset(); + } + EndEnumFilters; + + pPinTo = GetFirstPin(pBF, PINDIR_INPUT); + if (!pPinTo) { + pGB->RemoveFilter(pBF); + break; + } + + if (FAILED(pGB->ConnectDirect(pPin, pPinTo, nullptr))) { + pGB->Connect(pPin, pPinTo); + pGB->RemoveFilter(pBF); + break; + } + + BeginEnumFilters(pGB, pEnum, pBF2); + if (!pFilters.Find(pBF2) && SUCCEEDED(pGB->RemoveFilter(pBF2))) { + pEnum->Reset(); + } + EndEnumFilters; + + pRet = GetFirstPin(pBF, PINDIR_OUTPUT); + if (!pRet) { + pRet = pPin; + pGB->RemoveFilter(pBF); + break; + } + } while (false); + + return pRet; +} + +IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB) +{ + do { + if (!pPin || DisplayName.IsEmpty() || !pGB) { + break; + } + + PIN_DIRECTION dir; + if (FAILED(pPin->QueryDirection(&dir))) { + break; + } + + CComPtr pFrom, pTo; + + if (dir == PINDIR_INPUT) { + pPin->ConnectedTo(&pFrom); + pTo = pPin; + } else if (dir == PINDIR_OUTPUT) { + pFrom = pPin; + pPin->ConnectedTo(&pTo); + } + + if (!pFrom || !pTo) { + break; + } + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { + break; + } + + CComPtr pBF; + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { + break; + } + + CComPtr pPB; + if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { + break; + } + + CComVariant var; + if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + break; + } + + if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { + break; + } + + CComPtr pFromTo = GetFirstPin(pBF, PINDIR_INPUT); + if (!pFromTo) { + pGB->RemoveFilter(pBF); + break; + } + + if (FAILED(pGB->Disconnect(pFrom)) || FAILED(pGB->Disconnect(pTo))) { + pGB->RemoveFilter(pBF); + pGB->ConnectDirect(pFrom, pTo, nullptr); + break; + } + + if (FAILED(pGB->ConnectDirect(pFrom, pFromTo, nullptr))) { + pGB->RemoveFilter(pBF); + pGB->ConnectDirect(pFrom, pTo, nullptr); + break; + } + + CComPtr pToFrom = GetFirstPin(pBF, PINDIR_OUTPUT); + if (!pToFrom) { + pGB->RemoveFilter(pBF); + pGB->ConnectDirect(pFrom, pTo, nullptr); + break; + } + + if (FAILED(pGB->ConnectDirect(pToFrom, pTo, nullptr))) { + pGB->RemoveFilter(pBF); + pGB->ConnectDirect(pFrom, pTo, nullptr); + break; + } + + pPin = pToFrom; + } while (false); + + return pPin; +} + +void ExtractMediaTypes(IPin* pPin, CAtlArray& types) +{ + types.RemoveAll(); + + BeginEnumMediaTypes(pPin, pEM, pmt) { + bool fFound = false; + + for (ptrdiff_t i = 0; !fFound && i < (int)types.GetCount(); i += 2) { + if (types[i] == pmt->majortype && types[i + 1] == pmt->subtype) { + fFound = true; + } + } + + if (!fFound) { + types.Add(pmt->majortype); + types.Add(pmt->subtype); + } + } + EndEnumMediaTypes(pmt); +} + +void ExtractMediaTypes(IPin* pPin, CAtlList& mts) +{ + mts.RemoveAll(); + + BeginEnumMediaTypes(pPin, pEM, pmt) { + bool fFound = false; + + POSITION pos = mts.GetHeadPosition(); + while (!fFound && pos) { + CMediaType& mt = mts.GetNext(pos); + if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { + fFound = true; + } + } + + if (!fFound) { + mts.AddTail(CMediaType(*pmt)); + } + } + EndEnumMediaTypes(pmt); +} + +int Eval_Exception(int n_except) +{ + if (n_except == STATUS_ACCESS_VIOLATION) { + AfxMessageBox(_T("The property page of this filter has just caused a\nmemory access violation. The application will gently die now :)")); + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +void MyOleCreatePropertyFrame(HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption, ULONG cObjects, LPUNKNOWN FAR* lplpUnk, ULONG cPages, LPCLSID lpPageClsID, LCID lcid, DWORD dwReserved, LPVOID lpvReserved) +{ + __try { + OleCreatePropertyFrame(hwndOwner, x, y, lpszCaption, cObjects, lplpUnk, cPages, lpPageClsID, lcid, dwReserved, lpvReserved); + } __except (Eval_Exception(GetExceptionCode())) { + // No code; this block never executed. + } +} + +void ShowPPage(CString DisplayName, HWND hParentWnd) +{ + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBindCtx, CStringW(DisplayName), &chEaten, &pMoniker)) { + return; + } + + CComPtr pBF; + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { + return; + } + + ShowPPage(pBF, hParentWnd); +} + +void ShowPPage(IUnknown* pUnk, HWND hParentWnd) +{ + CComQIPtr pSPP = pUnk; + if (!pSPP) { + return; + } + + CString str; + + CComQIPtr pBF = pSPP; + CFilterInfo fi; + CComQIPtr pPin = pSPP; + CPinInfo pi; + if (pBF && SUCCEEDED(pBF->QueryFilterInfo(&fi))) { + str = fi.achName; + } else if (pPin && SUCCEEDED(pPin->QueryPinInfo(&pi))) { + str = pi.achName; + } + + CAUUID caGUID; + caGUID.pElems = nullptr; + if (SUCCEEDED(pSPP->GetPages(&caGUID))) { + IUnknown* lpUnk = nullptr; + pSPP.QueryInterface(&lpUnk); + MyOleCreatePropertyFrame( + hParentWnd, 0, 0, CStringW(str), + 1, (IUnknown**)&lpUnk, + caGUID.cElems, caGUID.pElems, + 0, 0, nullptr); + lpUnk->Release(); + + if (caGUID.pElems) { + CoTaskMemFree(caGUID.pElems); + } + } +} + +CLSID GetCLSID(IBaseFilter* pBF) +{ + CLSID clsid = GUID_NULL; + if (pBF) { + pBF->GetClassID(&clsid); + } + return clsid; +} + +CLSID GetCLSID(IPin* pPin) +{ + return GetCLSID(GetFilterFromPin(pPin)); +} + +CString CLSIDToString(CLSID& clsid) +{ + CComHeapPtr pStr; + if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { + return CString(pStr); + } + return CString(); +} + +bool IsCLSIDRegistered(LPCTSTR clsid) +{ + CString rootkey1(_T("CLSID\\")); + CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); + + return ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey1 + clsid, KEY_READ) + || ERROR_SUCCESS == CRegKey().Open(HKEY_CLASSES_ROOT, rootkey2 + clsid, KEY_READ); +} + +bool IsCLSIDRegistered(const CLSID& clsid) +{ + bool fRet = false; + + CComHeapPtr pStr; + if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { + fRet = IsCLSIDRegistered(CString(pStr)); + } + + return fRet; +} + +CString GetFilterPath(LPCTSTR clsid) +{ + CString rootkey1(_T("CLSID\\")); + CString rootkey2(_T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance\\")); + + CRegKey key; + CString path; + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, rootkey1 + clsid + _T("\\InprocServer32"), KEY_READ) + || ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, rootkey2 + clsid + _T("\\InprocServer32"), KEY_READ)) { + ULONG nCount = MAX_PATH; + key.QueryStringValue(nullptr, path.GetBuffer(nCount), &nCount); + path.ReleaseBuffer(nCount); + } + + return path; +} + +CString GetFilterPath(const CLSID& clsid) +{ + CString path; + + CComHeapPtr pStr; + if (S_OK == StringFromCLSID(clsid, &pStr) && pStr) { + path = GetFilterPath(CString(pStr)); + } + + return path; +} + +void CStringToBin(CString str, CAtlArray& data) +{ + str.Trim(); + ASSERT((str.GetLength() & 1) == 0); + data.SetCount(str.GetLength() / 2); + + BYTE b = 0; + + str.MakeUpper(); + for (int i = 0, j = str.GetLength(); i < j; i++) { + TCHAR c = str[i]; + if (c >= _T('0') && c <= _T('9')) { + if (!(i & 1)) { + b = ((char(c - _T('0')) << 4) & 0xf0) | (b & 0x0f); + } else { + b = (char(c - _T('0')) & 0x0f) | (b & 0xf0); + } + } else if (c >= _T('A') && c <= _T('F')) { + if (!(i & 1)) { + b = ((char(c - _T('A') + 10) << 4) & 0xf0) | (b & 0x0f); + } else { + b = (char(c - _T('A') + 10) & 0x0f) | (b & 0xf0); + } + } else { + break; + } + + if (i & 1) { + data[i >> 1] = b; + b = 0; + } + } +} + +CString BinToCString(const BYTE* ptr, size_t len) +{ + CString ret; + + while (len-- > 0) { + TCHAR high, low; + + high = (*ptr >> 4) >= 10 ? (*ptr >> 4) - 10 + _T('A') : (*ptr >> 4) + _T('0'); + low = (*ptr & 0xf) >= 10 ? (*ptr & 0xf) - 10 + _T('A') : (*ptr & 0xf) + _T('0'); + + ret.AppendFormat(_T("%c%c"), high, low); + + ptr++; + } + + return ret; +} + +void FindFiles(CString fn, CAtlList& files) +{ + ExtendMaxPathLengthIfNeeded(fn); + CString path = fn; + path.Replace('/', '\\'); + path = path.Left(path.ReverseFind('\\') + 1); + + WIN32_FIND_DATA findData; + ZeroMemory(&findData, sizeof(WIN32_FIND_DATA)); + HANDLE h = FindFirstFile(fn, &findData); + if (h != INVALID_HANDLE_VALUE) { + do { + files.AddTail(path + findData.cFileName); + } while (FindNextFile(h, &findData)); + + FindClose(h); + } +} + +OpticalDiskType_t GetOpticalDiskType(TCHAR drive, CAtlList& files) +{ + files.RemoveAll(); + + CString path; + path.Format(_T("%c:"), drive); + + if (GetDriveType(path + _T("\\")) != DRIVE_CDROM) { + return OpticalDisk_NotFound; + } + + // Check if it contains a disc + HANDLE hDevice = CreateFile(CString(_T("\\\\.\\")) + path, FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (hDevice == INVALID_HANDLE_VALUE) { + return OpticalDisk_NotFound; + } + DWORD cbBytesReturned; + BOOL bSuccess = DeviceIoControl(hDevice, IOCTL_STORAGE_CHECK_VERIFY2, + NULL, 0, NULL, 0, &cbBytesReturned, (LPOVERLAPPED)NULL); + if (!bSuccess) { + return OpticalDisk_NotFound; + } + + // CDROM_DVDVideo + FindFiles(path + _T("\\VIDEO_TS\\video_ts.ifo"), files); + if (!files.IsEmpty()) { + return OpticalDisk_DVDVideo; + } + + // CDROM_BD + FindFiles(path + _T("\\BDMV\\index.bdmv"), files); + if (!files.IsEmpty()) { + return OpticalDisk_BD; + } + + // CDROM_VideoCD + FindFiles(path + _T("\\mpegav\\avseq??.dat"), files); + FindFiles(path + _T("\\mpegav\\avseq??.mpg"), files); + FindFiles(path + _T("\\mpeg2\\avseq??.dat"), files); + FindFiles(path + _T("\\mpeg2\\avseq??.mpg"), files); + FindFiles(path + _T("\\mpegav\\music??.dat"), files); + FindFiles(path + _T("\\mpegav\\music??.mpg"), files); + FindFiles(path + _T("\\mpeg2\\music??.dat"), files); + FindFiles(path + _T("\\mpeg2\\music??.mpg"), files); + if (!files.IsEmpty()) { + return OpticalDisk_VideoCD; + } + + // CDROM_Audio + HANDLE hDrive = CreateFile(CString(_T("\\\\.\\")) + path, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)nullptr); + if (hDrive != INVALID_HANDLE_VALUE) { + DWORD BytesReturned; + CDROM_TOC TOC; + if (DeviceIoControl(hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &TOC, sizeof(TOC), &BytesReturned, 0)) { + ASSERT(TOC.FirstTrack >= 1u && TOC.LastTrack <= _countof(TOC.TrackData)); + TOC.FirstTrack = std::max(TOC.FirstTrack, UCHAR(1)); + TOC.LastTrack = std::min(TOC.LastTrack, UCHAR(_countof(TOC.TrackData))); + for (ptrdiff_t i = TOC.FirstTrack; i <= TOC.LastTrack; i++) { + // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field + auto& trackData = TOC.TrackData[i - 1]; + trackData.Control &= 5; + if (trackData.Control == 0 || trackData.Control == 1) { + CString fn; + fn.Format(_T("%s\\track%02Id.cda"), path.GetString(), i); + files.AddTail(fn); + } + } + } + + CloseHandle(hDrive); + } + if (!files.IsEmpty()) { + return OpticalDisk_Audio; + } + + // it is a cdrom but nothing special + return OpticalDisk_Unknown; +} + +CString GetDriveLabel(TCHAR drive) +{ + CString path; + path.Format(_T("%c:\\"), drive); + + return GetDriveLabel(CPath(path)); +} + +CString GetDriveLabel(CPath path) +{ + CString label; + path.StripToRoot(); + + TCHAR VolumeNameBuffer[MAX_PATH], FileSystemNameBuffer[MAX_PATH]; + DWORD VolumeSerialNumber, MaximumComponentLength, FileSystemFlags; + if (GetVolumeInformation(path, + VolumeNameBuffer, MAX_PATH, &VolumeSerialNumber, &MaximumComponentLength, + &FileSystemFlags, FileSystemNameBuffer, MAX_PATH)) { + label = VolumeNameBuffer; + } + + return label; +} + +bool IsDriveVirtual(CString drive) +{ + HKEY hkey; + DWORD type = REG_BINARY; + TCHAR data[1024] = { 0 }; + DWORD size = sizeof(data) - 2; + + drive=(drive+_T(":")).Left(2); + CString subkey = _T("\\DosDevices\\") + drive; + + RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\MountedDevices"), 0, KEY_READ, &hkey); + if (hkey == INVALID_HANDLE_VALUE) return 0; + RegQueryValueEx(hkey, subkey, 0, &type, (BYTE*)data, &size); + + RegCloseKey(hkey); + CString sig(data); + sig.MakeUpper(); + return sig.Find(_T("VEN_MSFT&PROD_VIRTUAL_DVD-ROM")) >= 0 + || sig.Find(_T("VEN_DISCSOFT&")) >= 0 + || sig.Find(_T("VEN_ELBY&PROD_CLONEDRIVE")) >= 0; +} + +bool GetKeyFrames(CString fn, CUIntArray& kfs) +{ + kfs.RemoveAll(); + + CString fn2 = CString(fn).MakeLower(); + if (fn2.Mid(fn2.ReverseFind('.') + 1) == _T("avi")) { + AVIFileInit(); + + PAVIFILE pfile; + if (AVIFileOpen(&pfile, fn, OF_SHARE_DENY_WRITE, 0L) == 0) { + AVIFILEINFO afi; + ZeroMemory(&afi, sizeof(afi)); + AVIFileInfo(pfile, &afi, sizeof(AVIFILEINFO)); + + CComPtr pavi; + if (AVIFileGetStream(pfile, &pavi, streamtypeVIDEO, 0) == AVIERR_OK) { + AVISTREAMINFO si; + AVIStreamInfo(pavi, &si, sizeof(si)); + + if (afi.dwCaps & AVIFILECAPS_ALLKEYFRAMES) { + kfs.SetSize(si.dwLength); + for (DWORD kf = 0; kf < si.dwLength; kf++) { + kfs[kf] = kf; + } + } else { + for (LONG kf = 0; ; kf++) { + kf = pavi->FindSample(kf, FIND_KEY | FIND_NEXT); + if (kf < 0 || !kfs.IsEmpty() && kfs[kfs.GetCount() - 1] >= (UINT)kf) { + break; + } + kfs.Add(kf); + } + + if (!kfs.IsEmpty() && kfs[kfs.GetCount() - 1] < si.dwLength - 1) { + kfs.Add(si.dwLength - 1); + } + } + } + + AVIFileRelease(pfile); + } + + AVIFileExit(); + } + + return !kfs.IsEmpty(); +} + +DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps /*= 0.0*/) // use to remember the current position +{ + DVD_HMSF_TIMECODE hmsf = { + (BYTE)((rt / 10000000 / 60 / 60)), + (BYTE)((rt / 10000000 / 60) % 60), + (BYTE)((rt / 10000000) % 60), + (BYTE)(1.0 * ((rt / 10000) % 1000) * fps / 1000) + }; + + return hmsf; +} + +DVD_HMSF_TIMECODE RT2HMS(REFERENCE_TIME rt) // used only for information (for display on the screen) +{ + rt = rt / 10000000; + DVD_HMSF_TIMECODE hmsf = { + (BYTE)(rt / 3600), + (BYTE)(rt / 60 % 60), + (BYTE)(rt % 60), + 0 + }; + + return hmsf; +} + +DVD_HMSF_TIMECODE RT2HMS_r(REFERENCE_TIME rt) // used only for information (for display on the screen) +{ + // round to nearest second + return RT2HMS(rt + 5000000); +} + +REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps /*= -1.0*/) +{ + if (fps <= 0.0) { + hmsf.bFrames = 0; + fps = 1.0; + } + return (REFERENCE_TIME)((((REFERENCE_TIME)hmsf.bHours * 60 + hmsf.bMinutes) * 60 + hmsf.bSeconds) * 1000 + 1.0 * hmsf.bFrames * 1000 / fps) * 10000; +} + +void memsetd(void* dst, unsigned int c, size_t nbytes) +{ + size_t n = nbytes / 4; + __stosd((unsigned long*)dst, c, n); +} + +void memsetw(void* dst, unsigned short c, size_t nbytes) +{ + memsetd(dst, c << 16 | c, nbytes); + + size_t n = nbytes / 2; + size_t o = (n / 2) * 2; + if ((n - o) == 1) { + ((WORD*)dst)[o] = c; + } +} + +bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih) +{ + if (pmt && bih && pmt->pbFormat) { + ZeroMemory(bih, sizeof(*bih)); + + if (pmt->formattype == FORMAT_VideoInfo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } else if (pmt->formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } else if (pmt->formattype == FORMAT_MPEGVideo) { + VIDEOINFOHEADER* vih = &((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } else if (pmt->formattype == FORMAT_MPEG2_VIDEO) { + VIDEOINFOHEADER2* vih = &((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } else if (pmt->formattype == FORMAT_DiracVideoInfo) { + VIDEOINFOHEADER2* vih = &((DIRACINFOHEADER*)pmt->pbFormat)->hdr; + memcpy(bih, &vih->bmiHeader, sizeof(BITMAPINFOHEADER)); + return true; + } + } + + return false; +} + +bool ExtractAvgTimePerFrame(const AM_MEDIA_TYPE* pmt, REFERENCE_TIME& rtAvgTimePerFrame) +{ + if (pmt->formattype == FORMAT_VideoInfo) { + rtAvgTimePerFrame = ((VIDEOINFOHEADER*)pmt->pbFormat)->AvgTimePerFrame; + } else if (pmt->formattype == FORMAT_VideoInfo2) { + rtAvgTimePerFrame = ((VIDEOINFOHEADER2*)pmt->pbFormat)->AvgTimePerFrame; + } else if (pmt->formattype == FORMAT_MPEGVideo) { + rtAvgTimePerFrame = ((MPEG1VIDEOINFO*)pmt->pbFormat)->hdr.AvgTimePerFrame; + } else if (pmt->formattype == FORMAT_MPEG2Video) { + rtAvgTimePerFrame = ((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.AvgTimePerFrame; + } else { + return false; + } + + return true; +} + +bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih) +{ + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pMS->GetMediaType(&pmt)) && pmt) { + bool fRet = ExtractBIH(pmt, bih); + DeleteMediaType(pmt); + return fRet; + } + + return false; +} + +bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary) +{ + w = h = arx = ary = 0; + + if (pmt->formattype == FORMAT_VideoInfo || pmt->formattype == FORMAT_MPEGVideo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pmt->pbFormat; + w = vih->bmiHeader.biWidth; + h = abs(vih->bmiHeader.biHeight); + arx = w * vih->bmiHeader.biYPelsPerMeter; + ary = h * vih->bmiHeader.biXPelsPerMeter; + } else if (pmt->formattype == FORMAT_VideoInfo2 || pmt->formattype == FORMAT_MPEG2_VIDEO || pmt->formattype == FORMAT_DiracVideoInfo) { + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pmt->pbFormat; + w = vih->bmiHeader.biWidth; + h = abs(vih->bmiHeader.biHeight); + arx = vih->dwPictAspectRatioX; + ary = vih->dwPictAspectRatioY; + } else { + return false; + } + + if (!arx || !ary) { + BYTE* ptr = nullptr; + DWORD len = 0; + + if (pmt->formattype == FORMAT_MPEGVideo) { + ptr = ((MPEG1VIDEOINFO*)pmt->pbFormat)->bSequenceHeader; + len = ((MPEG1VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; + + if (ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { + w = (ptr[4] << 4) | (ptr[5] >> 4); + h = ((ptr[5] & 0xf) << 8) | ptr[6]; + float ar[] = { + 1.0000f, 1.0000f, 0.6735f, 0.7031f, + 0.7615f, 0.8055f, 0.8437f, 0.8935f, + 0.9157f, 0.9815f, 1.0255f, 1.0695f, + 1.0950f, 1.1575f, 1.2015f, 1.0000f, + }; + arx = (int)((float)w / ar[ptr[7] >> 4] + 0.5); + ary = h; + } + } else if (pmt->formattype == FORMAT_MPEG2_VIDEO) { + ptr = (BYTE*)((MPEG2VIDEOINFO*)pmt->pbFormat)->dwSequenceHeader; + len = ((MPEG2VIDEOINFO*)pmt->pbFormat)->cbSequenceHeader; + + if (ptr && len >= 8 && *(DWORD*)ptr == 0xb3010000) { + w = (ptr[4] << 4) | (ptr[5] >> 4); + h = ((ptr[5] & 0xf) << 8) | ptr[6]; + struct { + int x, y; + } ar[] = {{w, h}, {4, 3}, {16, 9}, {221, 100}, {w, h}}; + int i = std::min(std::max(ptr[7] >> 4, 1), 5) - 1; + arx = ar[i].x; + ary = ar[i].y; + } + } + } + + if (!arx || !ary) { + arx = w; + ary = h; + } + + DWORD a = arx, b = ary; + while (a) { + int tmp = a; + a = b % tmp; + b = tmp; + } + if (b) { + arx /= b, ary /= b; + } + + return true; +} + +bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName) +{ + if (!ppBF) { + return false; + } + + *ppBF = nullptr; + FriendlyName.Empty(); + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBindCtx, CComBSTR(DisplayName), &chEaten, &pMoniker)) { + return false; + } + + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(ppBF))) || !*ppBF) { + return false; + } + + CComPtr pPB; + CComVariant var; + if (SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB))) + && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + FriendlyName = var.bstrVal; + } + + return true; +} + +IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB) +{ + do { + if (!pPin || !pMoniker || !pGB) { + break; + } + + CComPtr pPinTo; + PIN_DIRECTION dir; + if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT || SUCCEEDED(pPin->ConnectedTo(&pPinTo))) { + break; + } + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pPB; + if (FAILED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB)))) { + break; + } + + CComVariant var; + if (FAILED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + break; + } + + CComPtr pBF; + if (FAILED(pMoniker->BindToObject(pBindCtx, 0, IID_PPV_ARGS(&pBF))) || !pBF) { + break; + } + + if (FAILED(pGB->AddFilter(pBF, CStringW(var.bstrVal)))) { + break; + } + + BeginEnumPins(pBF, pEP, pPinTo2) { + PIN_DIRECTION dir2; + if (FAILED(pPinTo2->QueryDirection(&dir2)) || dir2 != PINDIR_INPUT) { + continue; + } + + if (SUCCEEDED(pGB->ConnectDirect(pPin, pPinTo2, nullptr))) { + return pBF; + } + } + EndEnumFilters; + + pGB->RemoveFilter(pBF); + } while (false); + + return nullptr; +} + +CStringW GetFriendlyName(CStringW displayName) +{ + CStringW friendlyName; + + CComPtr pBindCtx; + CreateBindCtx(0, &pBindCtx); + + CComPtr pMoniker; + ULONG chEaten; + if (S_OK == MkParseDisplayName(pBindCtx, CComBSTR(displayName), &chEaten, &pMoniker)) { + CComPtr pPB; + CComVariant var; + if (SUCCEEDED(pMoniker->BindToStorage(pBindCtx, 0, IID_PPV_ARGS(&pPB))) + && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + friendlyName = var.bstrVal; + } + } + + return friendlyName; +} + +typedef HRESULT(__stdcall* fDllCanUnloadNow)(void); + +struct ExternalObject { + CString path; + HINSTANCE hInst; + CLSID clsid; + fDllCanUnloadNow fpDllCanUnloadNow; + bool bUnloadOnNextCheck; +}; + +static CAtlList s_extObjs; +static CCritSec s_csExtObjs; + +HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv, IUnknown* aggregate) +{ + CheckPointer(ppv, E_POINTER); + + CAutoLock lock(&s_csExtObjs); + + CString fullpath = MakeFullPath(path); + + HINSTANCE hInst = nullptr; + bool fFound = false; + + POSITION pos = s_extObjs.GetHeadPosition(); + while (pos) { + ExternalObject& eo = s_extObjs.GetNext(pos); + if (!eo.path.CompareNoCase(fullpath)) { + hInst = eo.hInst; + fFound = true; + eo.bUnloadOnNextCheck = false; + break; + } + } + + HRESULT hr = E_FAIL; + + if (!hInst) { + hInst = LoadLibraryEx(fullpath, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); + } + if (hInst) { + typedef HRESULT(__stdcall * PDllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID * ppv); + PDllGetClassObject p = (PDllGetClassObject)GetProcAddress(hInst, "DllGetClassObject"); + + if (p && (aggregate || FAILED(hr = p(clsid, iid, ppv)))) { + CComPtr pCF; + if (SUCCEEDED(hr = p(clsid, IID_PPV_ARGS(&pCF)))) { + hr = pCF->CreateInstance(aggregate, iid, ppv); + } + } + } + + if (FAILED(hr) && hInst && !fFound) { + FreeLibrary(hInst); + return hr; + } + + if (hInst && !fFound) { + ExternalObject eo; + eo.path = fullpath; + eo.hInst = hInst; + eo.clsid = clsid; + eo.fpDllCanUnloadNow = (fDllCanUnloadNow)GetProcAddress(hInst, "DllCanUnloadNow"); + eo.bUnloadOnNextCheck = false; + s_extObjs.AddTail(eo); + } + + return hr; +} + +HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF) +{ + return LoadExternalObject(path, clsid, IID_PPV_ARGS(ppBF)); +} + +HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP) +{ + CAutoLock lock(&s_csExtObjs); + + CLSID clsid2 = GUID_NULL; + if (FAILED(pP->GetClassID(&clsid2))) { + return E_FAIL; + } + + POSITION pos = s_extObjs.GetHeadPosition(); + while (pos) { + ExternalObject& eo = s_extObjs.GetNext(pos); + if (eo.clsid == clsid2) { + return LoadExternalObject(eo.path, clsid, IID_PPV_ARGS(ppPP)); + } + } + + return E_FAIL; +} + +bool UnloadUnusedExternalObjects() +{ + CAutoLock lock(&s_csExtObjs); + + POSITION pos = s_extObjs.GetHeadPosition(), currentPos; + while (pos) { + currentPos = pos; + ExternalObject& eo = s_extObjs.GetNext(pos); + + if (eo.fpDllCanUnloadNow && eo.fpDllCanUnloadNow() == S_OK) { + // Before actually unloading it, we require that the library reports + // that it can be unloaded safely twice in a row with a 60s delay + // between the two checks. + if (eo.bUnloadOnNextCheck) { + FreeLibrary(eo.hInst); + s_extObjs.RemoveAt(currentPos); + } else { + eo.bUnloadOnNextCheck = true; + } + } else { + eo.bUnloadOnNextCheck = false; + } + } + + return s_extObjs.IsEmpty(); +} + +void ExtendMaxPathLengthIfNeeded(CString& path, bool no_url /*= false */) +{ + if (path.GetLength() >= MAX_PATH) { + if (no_url || path.Find(_T("://")) < 0) { // not URL + if (path.Left(4) != _T("\\\\?\\")) { // not already have long path prefix + if (path.Left(2) == _T("\\\\")) { // UNC + path = _T("\\\\?\\UNC") + path.Mid(1); + } else { // normal + path = _T("\\\\?\\") + path; + } + } + } + } +} + +bool ContainsWildcard(CString& path) +{ + int p = path.Find('*'); + if (p >= 0) { + return true; + } + p = path.Find('?'); + if (p >= 0) { + if (p == 2 && path.Left(4) == _T("\\\\?\\")) { + CString tmp = CString(path); + tmp.Delete(0, 3); + return tmp.Find('?') > 0; + } + return true; + } + return false; +} + +void ShortenLongPath(CString& path) +{ + if (path.GetLength() > MAX_PATH && path.Find(_T("\\\\?\\")) < 0) { + CString longpath = _T("\\\\?\\") + path; + TCHAR* buffer = DEBUG_NEW TCHAR[MAX_PATH]; + long length = GetShortPathName(longpath, buffer, MAX_PATH); + if (length > 0 && length < MAX_PATH) { + path = buffer; + path.Replace(_T("\\\\?\\"), _T("")); + delete[] buffer; + } + } +} + +CString MakeFullPath(LPCTSTR path) +{ + CString full(path); + full.Replace('/', '\\'); + + if (full.GetLength() > MAX_PATH) { + return full; + } + + if (full.GetLength() >= 2 && full[0] == '\\') { + if (full[1] != '\\') { + CString fn; + fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); + CPath p(fn); + p.StripToRoot(); + full = CString(p) + full.Mid(1); + } + } else if (full.Find(_T(":\\")) < 0) { + CString fn; + fn.ReleaseBuffer(GetModuleFileName(AfxGetInstanceHandle(), fn.GetBuffer(MAX_PATH), MAX_PATH)); + CPath p(fn); + p.RemoveFileSpec(); + p.AddBackslash(); + full = CString(p) + full; + } + + CPath c(full); + c.Canonicalize(); + return CString(c); +} + +inline bool _IsFourCC(const GUID& guid) +{ + // XXXXXXXX-0000-0010-8000-00AA00389B71 + return (guid.Data2 == 0x0000) && (guid.Data3 == 0x0010) && + (((DWORD*)guid.Data4)[0] == 0xAA000080) && + (((DWORD*)guid.Data4)[1] == 0x719b3800); +} + +bool GetMediaTypeFourCC(const GUID& guid, CString& fourCC) +{ + if (_IsFourCC(guid) && (guid.Data1 >= 0x10000)) { + fourCC.Format(_T("%c%c%c%c"), + (TCHAR)(guid.Data1 >> 0 ) & 0xFF, (TCHAR)(guid.Data1 >> 8 ) & 0xFF, + (TCHAR)(guid.Data1 >> 16) & 0xFF, (TCHAR)(guid.Data1 >> 24) & 0xFF); + fourCC.MakeUpper(); + return true; + } + + fourCC = _T("UNKN"); + return false; +} + +CString GetMediaTypeName(const GUID& guid) +{ + CString ret = guid == GUID_NULL + ? CString(_T("Any type")) + : CString(GuidNames[guid]); + + if (ret == _T("FOURCC GUID")) { + CString str; + if (guid.Data1 >= 0x10000) { + str.Format(_T("Video: %c%c%c%c"), (guid.Data1 >> 0) & 0xff, (guid.Data1 >> 8) & 0xff, (guid.Data1 >> 16) & 0xff, (guid.Data1 >> 24) & 0xff); + } else { + str.Format(_T("Audio: 0x%08x"), guid.Data1); + } + ret = str; + } else if (ret == _T("Unknown GUID Name")) { + WCHAR null[128] = {0}, buff[128]; + StringFromGUID2(GUID_NULL, null, _countof(null) - 1); + ret = CString(CStringW(StringFromGUID2(guid, buff, _countof(buff) - 1) ? buff : null)); + } + + return ret; +} + +GUID GUIDFromCString(CString str) +{ + GUID guid = GUID_NULL; + HRESULT hr = CLSIDFromString(CComBSTR(str), &guid); + ASSERT(SUCCEEDED(hr)); + UNREFERENCED_PARAMETER(hr); + return guid; +} + +HRESULT GUIDFromCString(CString str, GUID& guid) +{ + guid = GUID_NULL; + return CLSIDFromString(CComBSTR(str), &guid); +} + +CString CStringFromGUID(const GUID& guid) +{ + WCHAR null[128] = {0}, buff[128]; + StringFromGUID2(GUID_NULL, null, _countof(null) - 1); + return CString(StringFromGUID2(guid, buff, _countof(buff) - 1) > 0 ? buff : null); +} + +CStringW UTF8To16(LPCSTR utf8) +{ + CStringW str; + int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, nullptr, 0) - 1; + if (n <= 0) { + return str; + } + str.ReleaseBuffer(MultiByteToWideChar(CP_UTF8, 0, utf8, -1, str.GetBuffer(n), n + 1) - 1); + return str; +} + +CStringA UTF16To8(LPCWSTR utf16) +{ + CStringA str; + int n = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, nullptr, 0, nullptr, nullptr) - 1; + if (n < 0) { + return str; + } + str.ReleaseBuffer(WideCharToMultiByte(CP_UTF8, 0, utf16, -1, str.GetBuffer(n), n + 1, nullptr, nullptr) - 1); + return str; +} + +CStringW UTF8ToStringW(const char* S) +{ + CStringW str; + if (S == nullptr) { + return str; + } + + // Don't use MultiByteToWideChar(), some characters are not well decoded + const unsigned char* Z = (const unsigned char*)S; + while (*Z) { //0 is end + //1 byte + if (*Z < 0x80) { + str += (wchar_t)(*Z); + Z++; + } + //2 bytes + else if ((*Z & 0xE0) == 0xC0) { + if ((*(Z + 1) & 0xC0) == 0x80) { + str += (wchar_t)((((wchar_t)(*Z & 0x1F)) << 6) | (*(Z + 1) & 0x3F)); + Z += 2; + } else { + str.Empty(); + return str; //Bad character + } + } + //3 bytes + else if ((*Z & 0xF0) == 0xE0) { + if ((*(Z + 1) & 0xC0) == 0x80 && (*(Z + 2) & 0xC0) == 0x80) { + str += (wchar_t)((((wchar_t)(*Z & 0x0F)) << 12) | ((*(Z + 1) & 0x3F) << 6) | (*(Z + 2) & 0x3F)); + Z += 3; + } else { + str.Empty(); + return str; //Bad character + } + } + //4 bytes + else if ((*Z & 0xF8) == 0xF0) { + if ((*(Z + 1) & 0xC0) == 0x80 && (*(Z + 2) & 0xC0) == 0x80 && (*(Z + 3) & 0xC0) == 0x80) { + str += (wchar_t)((((wchar_t)(*Z & 0x0F)) << 18) | ((*(Z + 1) & 0x3F) << 12) || ((*(Z + 2) & 0x3F) << 6) | (*(Z + 3) & 0x3F)); + Z += 4; + } else { + str.Empty(); + return str; //Bad character + } + } else { + str.Empty(); + return str; //Bad character + } + } + return str; +} + +CStringW LocalToStringW(const char* S) +{ + CStringW str; + if (S == nullptr) { + return str; + } + + int Size = MultiByteToWideChar(CP_ACP, 0, S, -1, nullptr, 0); + if (Size != 0) { + str.ReleaseBuffer(MultiByteToWideChar(CP_ACP, 0, S, -1, str.GetBuffer(Size), Size + 1) - 1); + } + return str; +} + +BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status) +{ + try { + return CFile::GetStatus(lpszFileName, status); + } catch (CException* e) { + // MFCBUG: E_INVALIDARG / "Parameter is incorrect" is thrown for certain cds (vs2003) + // http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8&threadm=OZuXYRzWDHA.536%40TK2MSFTNGP10.phx.gbl&rnum=1&prev=/groups%3Fhl%3Den%26lr%3D%26ie%3DISO-8859-1 + TRACE(_T("CFile::GetStatus has thrown an exception\n")); + e->Delete(); + return false; + } +} + +// filter registration helpers + +bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey) +{ + bool bOK = false; + + HKEY hKey; + LONG ec = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, pszKey, 0, KEY_ALL_ACCESS, &hKey); + if (ec == ERROR_SUCCESS) { + if (pszSubkey != 0) { + ec = ::RegDeleteKey(hKey, pszSubkey); + } + + bOK = (ec == ERROR_SUCCESS); + + ::RegCloseKey(hKey); + } + + return bOK; +} + +bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue) +{ + bool bOK = false; + + CString szKey(pszKey); + if (pszSubkey != 0) { + szKey += CString(_T("\\")) + pszSubkey; + } + + HKEY hKey; + LONG ec = ::RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); + if (ec == ERROR_SUCCESS) { + if (pszValue != 0) { + ec = ::RegSetValueEx(hKey, pszValueName, 0, REG_SZ, + reinterpret_cast(const_cast(pszValue)), + (DWORD)(_tcslen(pszValue) + 1) * sizeof(TCHAR)); + } + + bOK = (ec == ERROR_SUCCESS); + + ::RegCloseKey(hKey); + } + + return bOK; +} + +bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue) +{ + return SetRegKeyValue(pszKey, pszSubkey, 0, pszValue); +} + +void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext, ...) +{ + CString null = CStringFromGUID(GUID_NULL); + CString majortype = CStringFromGUID(MEDIATYPE_Stream); + CString subtype = CStringFromGUID(subtype2); + + SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("0"), chkbytes); + SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); + + DeleteRegKey(_T("Media Type\\") + null, subtype); + + va_list marker; + va_start(marker, ext); + for (; ext; ext = va_arg(marker, LPCTSTR)) { + DeleteRegKey(_T("Media Type\\Extensions"), ext); + } + va_end(marker); +} + +void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext, ...) +{ + CString null = CStringFromGUID(GUID_NULL); + CString majortype = CStringFromGUID(MEDIATYPE_Stream); + CString subtype = CStringFromGUID(subtype2); + + POSITION pos = chkbytes.GetHeadPosition(); + for (ptrdiff_t i = 0; pos; i++) { + CString idx; + idx.Format(_T("%Id"), i); + SetRegKeyValue(_T("Media Type\\") + majortype, subtype, idx, chkbytes.GetNext(pos)); + } + + SetRegKeyValue(_T("Media Type\\") + majortype, subtype, _T("Source Filter"), CStringFromGUID(clsid)); + + DeleteRegKey(_T("Media Type\\") + null, subtype); + + va_list marker; + va_start(marker, ext); + for (; ext; ext = va_arg(marker, LPCTSTR)) { + DeleteRegKey(_T("Media Type\\Extensions"), ext); + } + va_end(marker); +} + +void UnRegisterSourceFilter(const GUID& subtype) +{ + DeleteRegKey(_T("Media Type\\") + CStringFromGUID(MEDIATYPE_Stream), CStringFromGUID(subtype)); +} + +struct DXVA2_DECODER { + const GUID* Guid; + LPCTSTR Description; +}; + +static const DXVA2_DECODER DXVA2Decoder[] = { + {&GUID_NULL, _T("Unknown")}, + {&GUID_NULL, _T("Not using DXVA")}, + {&DXVA_Intel_H264_ClearVideo, _T("H.264 bitstream decoder, ClearVideo(tm)")}, // Intel ClearVideo H264 bitstream decoder + {&DXVA_Intel_VC1_ClearVideo, _T("VC-1 bitstream decoder, ClearVideo(tm)")}, // Intel ClearVideo VC-1 bitstream decoder + {&DXVA_Intel_VC1_ClearVideo_2, _T("VC-1 bitstream decoder 2, ClearVideo(tm)")}, // Intel ClearVideo VC-1 bitstream decoder 2 + {&DXVA_MPEG4_ASP, _T("MPEG-4 ASP bitstream decoder")}, // NVIDIA MPEG-4 ASP bitstream decoder + {&DXVA_ModeNone, _T("Mode none")}, + {&DXVA_ModeH261_A, _T("H.261 A, post processing")}, + {&DXVA_ModeH261_B, _T("H.261 B, deblocking")}, + {&DXVA_ModeH263_A, _T("H.263 A, motion compensation, no FGT")}, + {&DXVA_ModeH263_B, _T("H.263 B, motion compensation, FGT")}, + {&DXVA_ModeH263_C, _T("H.263 C, IDCT, no FGT")}, + {&DXVA_ModeH263_D, _T("H.263 D, IDCT, FGT")}, + {&DXVA_ModeH263_E, _T("H.263 E, bitstream decoder, no FGT")}, + {&DXVA_ModeH263_F, _T("H.263 F, bitstream decoder, FGT")}, + {&DXVA_ModeMPEG1_A, _T("MPEG-1 A, post processing")}, + {&DXVA_ModeMPEG2_A, _T("MPEG-2 A, motion compensation")}, + {&DXVA_ModeMPEG2_B, _T("MPEG-2 B, motion compensation + blending")}, + {&DXVA_ModeMPEG2_C, _T("MPEG-2 C, IDCT")}, + {&DXVA_ModeMPEG2_D, _T("MPEG-2 D, IDCT + blending")}, + {&DXVA_ModeH264_A, _T("H.264 A, motion compensation, no FGT")}, + {&DXVA_ModeH264_B, _T("H.264 B, motion compensation, FGT")}, + {&DXVA_ModeH264_C, _T("H.264 C, IDCT, no FGT")}, + {&DXVA_ModeH264_D, _T("H.264 D, IDCT, FGT")}, + {&DXVA_ModeH264_E, _T("H.264 E, bitstream decoder, no FGT")}, + {&DXVA_ModeH264_F, _T("H.264 F, bitstream decoder, FGT")}, + {&DXVA_ModeWMV8_A, _T("WMV8 A, post processing")}, + {&DXVA_ModeWMV8_B, _T("WMV8 B, motion compensation")}, + {&DXVA_ModeWMV9_A, _T("WMV9 A, post processing")}, + {&DXVA_ModeWMV9_B, _T("WMV9 B, motion compensation")}, + {&DXVA_ModeWMV9_C, _T("WMV9 C, IDCT")}, + {&DXVA_ModeVC1_A, _T("VC-1 A, post processing")}, + {&DXVA_ModeVC1_B, _T("VC-1 B, motion compensation")}, + {&DXVA_ModeVC1_C, _T("VC-1 C, IDCT")}, + {&DXVA_ModeVC1_D, _T("VC-1 D, bitstream decoder")}, + {&DXVA_NoEncrypt, _T("No encryption")}, + {&DXVA2_ModeMPEG2_MoComp, _T("MPEG-2 motion compensation")}, + {&DXVA2_ModeMPEG2_IDCT, _T("MPEG-2 IDCT")}, + {&DXVA2_ModeMPEG2_VLD, _T("MPEG-2 variable-length decoder")}, + {&DXVA2_ModeH264_A, _T("H.264 A, motion compensation, no FGT")}, + {&DXVA2_ModeH264_B, _T("H.264 B, motion compensation, FGT")}, + {&DXVA2_ModeH264_C, _T("H.264 C, IDCT, no FGT")}, + {&DXVA2_ModeH264_D, _T("H.264 D, IDCT, FGT")}, + {&DXVA2_ModeH264_E, _T("H.264 E, bitstream decoder, no FGT")}, + {&DXVA2_ModeH264_F, _T("H.264 F, bitstream decoder, FGT")}, + {&DXVA2_ModeWMV8_A, _T("WMV8 A, post processing")}, + {&DXVA2_ModeWMV8_B, _T("WMV8 B, motion compensation")}, + {&DXVA2_ModeWMV9_A, _T("WMV9 A, post processing")}, + {&DXVA2_ModeWMV9_B, _T("WMV9 B, motion compensation")}, + {&DXVA2_ModeWMV9_C, _T("WMV9 C, IDCT")}, + {&DXVA2_ModeVC1_A, _T("VC-1 A, post processing")}, + {&DXVA2_ModeVC1_B, _T("VC-1 B, motion compensation")}, + {&DXVA2_ModeVC1_C, _T("VC-1 C, IDCT")}, + {&DXVA2_ModeVC1_D, _T("VC-1 D, bitstream decoder")}, + {&DXVA2_NoEncrypt, _T("No encryption")}, + {&DXVA2_VideoProcProgressiveDevice, _T("Progressive scan")}, + {&DXVA2_VideoProcBobDevice, _T("Bob deinterlacing")}, + {&DXVA2_VideoProcSoftwareDevice, _T("Software processing")} +}; + +LPCTSTR GetDXVAMode(const GUID* guidDecoder) +{ + int nPos = 0; + + for (int i = 1; i < _countof(DXVA2Decoder); i++) { + if (*guidDecoder == *DXVA2Decoder[i].Guid) { + nPos = i; + break; + } + } + + return DXVA2Decoder[nPos].Description; +} + +// hour, minute, second, millisec +CString ReftimeToString(const REFERENCE_TIME& rtVal) +{ + if (rtVal == _I64_MIN) { + return _T("INVALID TIME"); + } + + CString strTemp; + LONGLONG llTotalMs = ConvertToMilliseconds(rtVal); + int lHour = (int)(llTotalMs / (1000 * 60 * 60)); + int lMinute = (llTotalMs / (1000 * 60)) % 60; + int lSecond = (llTotalMs / 1000) % 60; + int lMillisec = llTotalMs % 1000; + + strTemp.Format(_T("%02d:%02d:%02d,%03d"), lHour, lMinute, lSecond, lMillisec); + return strTemp; +} + +// hour, minute, second (round) +CString ReftimeToString2(const REFERENCE_TIME& rtVal) +{ + CString strTemp; + LONGLONG seconds = (rtVal + 5000000) / 10000000; + int lHour = (int)(seconds / 3600); + int lMinute = (int)(seconds / 60 % 60); + int lSecond = (int)(seconds % 60); + + strTemp.Format(_T("%02d:%02d:%02d"), lHour, lMinute, lSecond); + return strTemp; +} + +// minute, second (round) +CString ReftimeToString3(const REFERENCE_TIME& rtVal) +{ + CString strTemp; + LONGLONG seconds = (rtVal + 5000000) / 10000000; + int lMinute = (int)(seconds / 60 % 60); + int lSecond = (int)(seconds % 60); + + ASSERT((int)(seconds / 3600) == 0); + + strTemp.Format(_T("%02d:%02d"), lMinute, lSecond); + return strTemp; +} + +//for compatibility with mpc-be ReftimeToString2, which has option to exclude hours +CStringW ReftimeToString4(REFERENCE_TIME rt, bool showZeroHours /* = true*/) +{ + if (rt == INT64_MIN) { + return L"INVALID TIME"; + } + + DVD_HMSF_TIMECODE tc = RT2HMSF(rt); + + return DVDtimeToString(tc, showZeroHours); +} + +CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours) +{ + CString strTemp; + if (rtVal.bHours > 0 || bAlwaysShowHours) { + strTemp.Format(_T("%02u:%02u:%02u"), rtVal.bHours, rtVal.bMinutes, rtVal.bSeconds); + } else { + strTemp.Format(_T("%02u:%02u"), rtVal.bMinutes, rtVal.bSeconds); + } + return strTemp; +} + +REFERENCE_TIME StringToReftime(LPCTSTR strVal) +{ + REFERENCE_TIME rt = 0; + int lHour = 0; + int lMinute = 0; + int lSecond = 0; + int lMillisec = 0; + + if (_stscanf_s(strVal, _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { + rt = ((((lHour * 60) + lMinute) * 60 + lSecond) * MILLISECONDS + lMillisec) * (UNITS / MILLISECONDS); + } + + return rt; +} + +const wchar_t* StreamTypeToName(PES_STREAM_TYPE _Type) +{ + switch (_Type) { + case VIDEO_STREAM_MPEG1: + return L"MPEG-1"; + case VIDEO_STREAM_MPEG2: + return L"MPEG-2"; + case AUDIO_STREAM_MPEG1: + return L"MPEG-1"; + case AUDIO_STREAM_MPEG2: + return L"MPEG-2"; + case VIDEO_STREAM_H264: + return L"H264"; + case VIDEO_STREAM_HEVC: + return L"HEVC"; + case AUDIO_STREAM_LPCM: + return L"LPCM"; + case AUDIO_STREAM_AC3: + return L"Dolby Digital"; + case AUDIO_STREAM_DTS: + return L"DTS"; + case AUDIO_STREAM_AC3_TRUE_HD: + return L"Dolby TrueHD"; + case AUDIO_STREAM_AC3_PLUS: + return L"Dolby Digital Plus"; + case AUDIO_STREAM_DTS_HD: + return L"DTS-HD High Resolution Audio"; + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + return L"DTS-HD Master Audio"; + case PRESENTATION_GRAPHICS_STREAM: + return L"Presentation Graphics Stream"; + case INTERACTIVE_GRAPHICS_STREAM: + return L"Interactive Graphics Stream"; + case SUBTITLE_STREAM: + return L"Subtitle"; + case SECONDARY_AUDIO_AC3_PLUS: + return L"Secondary Dolby Digital Plus"; + case SECONDARY_AUDIO_DTS_HD: + return L"Secondary DTS-HD High Resolution Audio"; + case VIDEO_STREAM_VC1: + return L"VC-1"; + } + return nullptr; +} + +// +// Usage: SetThreadName (-1, "MainThread"); +// Code from http://msdn.microsoft.com/en-us/library/xcb2z8hs%28v=vs.110%29.aspx +// + +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1 caller thread) + DWORD dwFlags; // reserved for future use, must be zero +} THREADNAME_INFO; +#pragma pack(pop) + +void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } +} + +void CorrectComboBoxHeaderWidth(CWnd* pComboBox) +{ + if (!pComboBox) { + return; + } + + CDC* pDC = pComboBox->GetDC(); + CFont* pFont = pComboBox->GetFont(); + CFont* pOldFont = pDC->SelectObject(pFont); + + CString str; + pComboBox->GetWindowText(str); + CSize szText = pDC->GetTextExtent(str); + + TEXTMETRIC tm; + pDC->GetTextMetrics(&tm); + pDC->SelectObject(pOldFont); + pComboBox->ReleaseDC(pDC); + + CRect r; + pComboBox->GetWindowRect(r); + pComboBox->GetOwner()->ScreenToClient(r); + + r.right = r.left + ::GetSystemMetrics(SM_CXMENUCHECK) + ::GetSystemMetrics(SM_CXEDGE) + szText.cx + tm.tmAveCharWidth; + pComboBox->MoveWindow(r); +} + +CString NormalizeUnicodeStrForSearch(CString srcStr, LANGID langid) { + if (srcStr.IsEmpty()) return srcStr; + wchar_t* src; + + _locale_t locale; + LCID lcid = MAKELCID(MAKELANGID(langid, SUBLANG_DEFAULT), SORT_DEFAULT); + wchar_t localeName[32]; + if (0 == LCIDToLocaleName(lcid, localeName, 32, LOCALE_ALLOW_NEUTRAL_NAMES)) { //try to lowercase by locale, but if not, do a regular MakeLower() + srcStr.MakeLower(); + src = srcStr.GetBuffer(); + } else { + src = srcStr.GetBuffer(); + locale = _wcreate_locale(LC_ALL, localeName); + _wcslwr_s_l(src, wcslen(src) + 1, locale); + } + + int dstLen = int(wcslen(src) * 4); + wchar_t* dest = DEBUG_NEW wchar_t[dstLen]; + + int cchActual = NormalizeString(NormalizationKD, src, -1, dest, dstLen); + if (cchActual <= 0) dest[0] = 0; + WORD* rgType = DEBUG_NEW WORD[dstLen]; + GetStringTypeW(CT_CTYPE3, dest, -1, rgType); + PWSTR pszWrite = dest; + for (int i = 0; dest[i]; i++) { + if (!(rgType[i] & C3_NONSPACING)) { + *pszWrite++ = dest[i]; + } + } + *pszWrite = 0; + delete[] rgType; + + CString ret = dest; + delete[] dest; + return ret; +} + +inline const LONGLONG GetPerfCounter() { + auto GetPerfFrequency = [] { + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return freq.QuadPart; + }; + static const LONGLONG llPerfFrequency = GetPerfFrequency(); + if (llPerfFrequency) { + LARGE_INTEGER llPerfCounter; + QueryPerformanceCounter(&llPerfCounter); + return llMulDiv(llPerfCounter.QuadPart, 10000000LL, llPerfFrequency, 0); + } else { + // ms to 100ns units + return timeGetTime() * 10000; + } +} + +bool FindStringInList(const CAtlList& list, CString& value) +{ + bool found = false; + POSITION pos = list.GetHeadPosition(); + while (pos && !found) { + if (list.GetNext(pos).CompareNoCase(value) == 0) { + found = true; + } + } + return found; +} + +CStringW ForceTrailingSlash(CStringW folder) { + if (folder.Right(1) != L'\\' && folder.GetLength() > 0) { + folder += L'\\'; + } + return folder; +} + +CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt) { + int discard; + return GetChannelStrFromMediaType(pmt, discard); +} + +CStringW ChannelsToStr(int channels) { + CStringW ret; + switch (channels) { + case 1: + return L"mono"; + case 2: + return L"2.0"; + case 6: + return L"5.1"; + case 7: + return L"6.1"; + case 8: + return L"7.1"; + default: + ret.Format(L"%uch", channels); + return ret; + } +} + +CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt, int& channels) { + if (pmt) { + if (pmt->majortype == MEDIATYPE_Audio) { + if (pmt->formattype == FORMAT_WaveFormatEx) { + channels = ((WAVEFORMATEX*)pmt->pbFormat)->nChannels; + return ChannelsToStr(channels); + } else if (pmt->formattype == FORMAT_VorbisFormat) { + channels = ((VORBISFORMAT*)pmt->pbFormat)->nChannels; + return ChannelsToStr(channels); + } else if (pmt->formattype == FORMAT_VorbisFormat2) { + channels = ((VORBISFORMAT2*)pmt->pbFormat)->Channels; + return ChannelsToStr(channels); + } else { + channels = 2; + } + } else if (pmt->majortype == MEDIATYPE_Midi) { + channels = 2; + return L""; + } + } + ASSERT(false); + return L""; +} + +CStringW GetShortAudioNameFromMediaType(AM_MEDIA_TYPE* pmt) { + if (!pmt) { + return L""; + } + if (pmt->majortype != MEDIATYPE_Audio) { + if (pmt->majortype == MEDIATYPE_Midi) { + return L"MIDI"; + } else { + return L""; + } + } + + if (pmt->subtype == MEDIASUBTYPE_AAC || pmt->subtype == MEDIASUBTYPE_LATM_AAC || pmt->subtype == MEDIASUBTYPE_AAC_ADTS || pmt->subtype == MEDIASUBTYPE_MPEG_ADTS_AAC + || pmt->subtype == MEDIASUBTYPE_MPEG_HEAAC || pmt->subtype == MEDIASUBTYPE_MP4A || pmt->subtype == MEDIASUBTYPE_mp4a) { + return L"AAC"; + } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF + || pmt->subtype == MEDIASUBTYPE_RAW_SPORT || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h || pmt->subtype == MEDIASUBTYPE_DVM) { + return L"AC3"; + } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { + return L"E-AC3"; + } else if (pmt->subtype == MEDIASUBTYPE_DTS || pmt->subtype == MEDIASUBTYPE_DTS2 || pmt->subtype == MEDIASUBTYPE_WAVE_DTS) { + return L"DTS"; + } else if (pmt->subtype == MEDIASUBTYPE_DTS_HD) { + return L"DTS-HD"; + } else if (pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { + return L"LPCM"; + } else if (pmt->subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { + return L"TrueHD"; + } else if (pmt->subtype == MEDIASUBTYPE_MLP) { + return L"MLP"; + } else if (pmt->subtype == MEDIASUBTYPE_PCM || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT) { + return L"PCM"; + } else if (pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload || pmt->subtype == MEDIASUBTYPE_MPEG1Packet || pmt->subtype == MEDIASUBTYPE_MPEG1Payload) { //are these all actually possible? + return L"MP1"; + } else if (pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO) { + return L"MP2"; + } else if (pmt->subtype == MEDIASUBTYPE_MP3) { + return L"MP3"; + } else if (pmt->subtype == MEDIASUBTYPE_FLAC || pmt->subtype == MEDIASUBTYPE_FLAC_FRAMED) { + return L"FLAC"; + } else if (pmt->subtype == MEDIASUBTYPE_Vorbis || pmt->subtype == MEDIASUBTYPE_Vorbis2) { + return L"Vorbis"; + } else if (pmt->subtype == MEDIASUBTYPE_OPUS || pmt->subtype == MEDIASUBTYPE_OPUS_OLD) { + return L"Opus"; + } else if (pmt->subtype == MEDIASUBTYPE_MSAUDIO1) { + return L"WMA1"; + } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO2) { + return L"WMA2"; + } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO3) { + return L"WMA3"; + } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO4) { + return L"WMA4"; + } else if (pmt->subtype == MEDIASUBTYPE_WMAUDIO_LOSSLESS) { + return L"WMA-LL"; + } else if (pmt->subtype == MEDIASUBTYPE_BD_LPCM_AUDIO || pmt->subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { + return L"LPCM"; + } else if (pmt->subtype == MEDIASUBTYPE_IMA_AMV || pmt->subtype == MEDIASUBTYPE_ADPCM_MS || pmt->subtype == MEDIASUBTYPE_IMA_WAV || pmt->subtype == MEDIASUBTYPE_ADPCM_SWF) { + return L"ADPCM"; + } else if (pmt->subtype == MEDIASUBTYPE_TRUESPEECH) { + return L"TrueSpeech"; + } else if (pmt->subtype == MEDIASUBTYPE_PCM_NONE || pmt->subtype == MEDIASUBTYPE_PCM_RAW || pmt->subtype == MEDIASUBTYPE_PCM_TWOS || pmt->subtype == MEDIASUBTYPE_PCM_SOWT + || pmt->subtype == MEDIASUBTYPE_PCM_IN24 || pmt->subtype == MEDIASUBTYPE_PCM_IN32 || pmt->subtype == MEDIASUBTYPE_PCM_FL32 || pmt->subtype == MEDIASUBTYPE_PCM_FL64 + || pmt->subtype == MEDIASUBTYPE_PCM_IN24_le || pmt->subtype == MEDIASUBTYPE_PCM_IN32_le || pmt->subtype == MEDIASUBTYPE_PCM_FL32_le || pmt->subtype == MEDIASUBTYPE_PCM_FL64_le) { + return L"QTPCM"; + } else if (pmt->subtype == MEDIASUBTYPE_TTA1) { + return L"TTA"; + } else if (pmt->subtype == MEDIASUBTYPE_SAMR) { + return L"SAMR"; + } else if (pmt->subtype == MEDIASUBTYPE_QDM2) { + return L"QDM2"; + } else if (pmt->subtype == MEDIASUBTYPE_MSGSM610) { + return L"GSM610"; + } else if (pmt->subtype == MEDIASUBTYPE_ALAW || pmt->subtype == MEDIASUBTYPE_MULAW) { + return L"G711"; + } else if (pmt->subtype == MEDIASUBTYPE_G723 || pmt->subtype == MEDIASUBTYPE_VIVO_G723) { + return L"G723"; + } else if (pmt->subtype == MEDIASUBTYPE_G726) { + return L"G726"; + } else if (pmt->subtype == MEDIASUBTYPE_G729 || pmt->subtype == MEDIASUBTYPE_729A) { + return L"G729"; + } else if (pmt->subtype == MEDIASUBTYPE_APE) { + return L"APE"; + } else if (pmt->subtype == MEDIASUBTYPE_TAK) { + return L"TAK"; + } else if (pmt->subtype == MEDIASUBTYPE_ALS) { + return L"ALS"; + } else if (pmt->subtype == MEDIASUBTYPE_NELLYMOSER) { + return L"NELLY"; + } else if (pmt->subtype == MEDIASUBTYPE_SPEEX) { + return L"Speex"; + } else if (pmt->subtype == MEDIASUBTYPE_AES3) { + return L"AES3"; + } else if (pmt->subtype == MEDIASUBTYPE_DSDL || pmt->subtype == MEDIASUBTYPE_DSDM || pmt->subtype == MEDIASUBTYPE_DSD1 || pmt->subtype == MEDIASUBTYPE_DSD8) { + return L"DSD"; + } else if (pmt->subtype == MEDIASUBTYPE_IMC) { + return L"IMC"; + } else if (pmt->subtype == MEDIASUBTYPE_VOXWARE_RT29) { + return L"RT29"; + } else if (pmt->subtype == MEDIASUBTYPE_MPEG_LOAS) { + return L"LOAS"; + } + + if (_IsFourCC(pmt->subtype)) { + CString fcc; + DWORD a = (pmt->subtype.Data1 >> 24) & 0xFF; + DWORD b = (pmt->subtype.Data1 >> 16) & 0xFF; + DWORD c = (pmt->subtype.Data1 >> 8) & 0xFF; + DWORD d = (pmt->subtype.Data1 >> 0) & 0xFF; + if (a != 0 || b != 0) { + fcc.Format(_T("%02x%02x%02x%02x"), a, b, c, d); + } else { + fcc.Format(_T("%02x%02x"), c, d); + } + return fcc; + } + + return L"UNKN"; +} + +bool GetVideoFormatNameFromMediaType(const GUID& guid, CString& name) { + if (GetMediaTypeFourCC(guid, name)) { + if (name == L"HVC1") { + name = L"HEVC"; + } else if (name == L"AVC1") { + name = L"H264"; + } else if (name == L"VP90") { + name = L"VP9"; + } else if (name == L"AV01") { + name = L"AV1"; + } + return true; + } else if (guid == MEDIASUBTYPE_MPEG1Payload || guid == MEDIASUBTYPE_MPEG1Video) { + name = L"MPEG1"; + return true; + } else if (guid == MEDIASUBTYPE_MPEG2_VIDEO) { + name = L"MPEG2"; + return true; + } else if (guid == MEDIASUBTYPE_ARGB32) { + name = L"ARGB"; + return true; + } else if (guid == MEDIASUBTYPE_RGB32) { + name = L"RGB"; + return true; + } else if (guid == MEDIASUBTYPE_LAV_RAWVIDEO) { + name = L"RAW"; + return true; + } else { + name = L"UNKN"; + ASSERT(false); + } + + return false; +} diff --git a/src/DSUtil/DSUtil.h b/src/DSUtil/DSUtil.h index fe20d5b0a04..ee7fbd8fa5e 100644 --- a/src/DSUtil/DSUtil.h +++ b/src/DSUtil/DSUtil.h @@ -1,356 +1,356 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "HdmvClipInfo.h" -#include "MediaTypeEx.h" -#include "text.h" -#include "vd.h" -#include "BaseClasses/streams.h" -#include -#include -#include "MFCHelper.h" -#include "Utils.h" - -#define LCID_NOSUBTITLES -1 - -#define IsWaveFormatExtensible(wfe) (wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfe->cbSize == 22) - -extern int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC); -extern bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly = false); -extern bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly = false); -extern bool IsStreamStart(IBaseFilter* pBF); -extern bool IsStreamEnd(IBaseFilter* pBF); -extern bool IsVideoRenderer(IBaseFilter* pBF); -extern bool IsAudioWaveRenderer(IBaseFilter* pBF); -extern IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin = nullptr); -extern IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin = nullptr); -extern IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir = PINDIR_INPUT); -extern IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir); -extern void NukeDownstream(IBaseFilter* pBF, IFilterGraph* pFG); -extern void NukeDownstream(IPin* pPin, IFilterGraph* pFG); -extern IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG); -extern IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG); -extern IBaseFilter* FindFirstFilter(IFilterGraph* pFG); -extern IPin* FindPin(IBaseFilter* pBF, PIN_DIRECTION direction, const AM_MEDIA_TYPE* pRequestedMT); -extern CStringW GetFilterName(IBaseFilter* pBF); -extern CStringW GetPinName(IPin* pPin); -extern IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF); -extern IBaseFilter* GetFilterFromPin(IPin* pPin); -extern IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB); -extern IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB); -extern void ExtractMediaTypes(IPin* pPin, CAtlArray& types); -extern void ExtractMediaTypes(IPin* pPin, CAtlList& mts); -extern void ShowPPage(CString DisplayName, HWND hParentWnd); -extern void ShowPPage(IUnknown* pUnknown, HWND hParentWnd); -extern CLSID GetCLSID(IBaseFilter* pBF); -extern CLSID GetCLSID(IPin* pPin); -extern CString CLSIDToString(CLSID& clsid); -extern bool IsCLSIDRegistered(LPCTSTR clsid); -extern bool IsCLSIDRegistered(const CLSID& clsid); -extern CString GetFilterPath(LPCTSTR clsid); -extern CString GetFilterPath(const CLSID& clsid); -extern void CStringToBin(CString str, CAtlArray& data); -extern CString BinToCString(const BYTE* ptr, size_t len); -extern void FindFiles(CString fn, CAtlList& files); -enum OpticalDiskType_t { - OpticalDisk_NotFound, - OpticalDisk_Audio, - OpticalDisk_VideoCD, - OpticalDisk_DVDVideo, - OpticalDisk_BD, - OpticalDisk_Unknown -}; -extern OpticalDiskType_t GetOpticalDiskType(TCHAR drive, CAtlList& files); -extern CString GetDriveLabel(TCHAR drive); -extern CString GetDriveLabel(CPath path); -bool IsDriveVirtual(CString drive); -extern bool GetKeyFrames(CString fn, CUIntArray& kfs); -extern DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps = 0.0); // used to remember the current position -extern DVD_HMSF_TIMECODE RT2HMS(REFERENCE_TIME rt); -extern DVD_HMSF_TIMECODE RT2HMS_r(REFERENCE_TIME rt); // used only to display information with rounding to nearest second -extern REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps = -1.0); -extern void memsetd(void* dst, unsigned int c, size_t nbytes); -extern void memsetw(void* dst, unsigned short c, size_t nbytes); -extern bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih); -extern bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih); -extern bool ExtractAvgTimePerFrame(const AM_MEDIA_TYPE* pmt, REFERENCE_TIME& rtAvgTimePerFrame); -extern bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary); -extern bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName); -extern IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB); -extern CStringW GetFriendlyName(CStringW DisplayName); -extern HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv, IUnknown* aggregate = nullptr); -extern HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF); -extern HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP); -extern bool UnloadUnusedExternalObjects(); -extern void ExtendMaxPathLengthIfNeeded(CString& path, bool no_url = false); -extern bool ContainsWildcard(CString& path); -extern void ShortenLongPath(CString& path); -extern CString MakeFullPath(LPCTSTR path); -extern bool GetMediaTypeFourCC(const GUID& guid, CString& fourCC); -extern CString GetMediaTypeName(const GUID& guid); -extern GUID GUIDFromCString(CString str); -extern HRESULT GUIDFromCString(CString str, GUID& guid); -extern CString CStringFromGUID(const GUID& guid); -extern CStringW UTF8To16(LPCSTR utf8); -extern CStringA UTF16To8(LPCWSTR utf16); -extern CStringW UTF8ToStringW(const char* S); -extern CStringW LocalToStringW(const char* S); -extern BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status); -extern bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey); -extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue); -extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue); -extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext = nullptr, ...); -extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext = nullptr, ...); -extern void UnRegisterSourceFilter(const GUID& subtype); -extern LPCTSTR GetDXVAMode(const GUID* guidDecoder); -extern CString ReftimeToString(const REFERENCE_TIME& rtVal); -extern CString ReftimeToString2(const REFERENCE_TIME& rtVal); -extern CString ReftimeToString3(const REFERENCE_TIME& rtVal); -extern CStringW ReftimeToString4(REFERENCE_TIME rt, bool showZeroHours = true); -extern CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours = false); -extern REFERENCE_TIME StringToReftime(LPCTSTR strVal); -extern void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName); -extern CString FindCoverArt(const CString& path, const CString& author); -extern CString NormalizeUnicodeStrForSearch(CString srcStr, LANGID langid); -extern bool FindStringInList(const CAtlList& list, CString& value); -extern CStringW ForceTrailingSlash(CStringW folder); -extern CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt); -extern CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt, int& channels); -extern CStringW GetShortAudioNameFromMediaType(AM_MEDIA_TYPE* pmt); -extern bool GetVideoFormatNameFromMediaType(const GUID& guid, CString& name); - -extern inline const LONGLONG GetPerfCounter(); - -enum FF_FIELD_TYPE { - PICT_NONE, - PICT_TOP_FIELD, - PICT_BOTTOM_FIELD, - PICT_FRAME -}; - -class CPinInfo : public PIN_INFO -{ -public: - CPinInfo() { - pFilter = nullptr; - } - ~CPinInfo() { - if (pFilter) { - pFilter->Release(); - } - } -}; - -class CFilterInfo : public FILTER_INFO -{ -public: - CFilterInfo() { - pGraph = nullptr; - } - ~CFilterInfo() { - if (pGraph) { - pGraph->Release(); - } - } -}; - -#define BeginEnumFilters(pFilterGraph, pEnumFilters, pBaseFilter) \ -{ \ - CComPtr pEnumFilters; \ - if (pFilterGraph && SUCCEEDED(pFilterGraph->EnumFilters(&pEnumFilters))) { \ - for (CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = nullptr) { - -#define EndEnumFilters }}} - -#define BeginEnumCachedFilters(pGraphConfig, pEnumFilters, pBaseFilter) \ -{ \ - CComPtr pEnumFilters; \ - if (pGraphConfig && SUCCEEDED(pGraphConfig->EnumCacheFilter(&pEnumFilters))) { \ - for (CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = nullptr) { - -#define EndEnumCachedFilters }}} - -#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \ -{ \ - CComPtr pEnumPins; \ - if (pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) { \ - for (CComPtr pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = nullptr) { - -#define EndEnumPins }}} - -#define BeginEnumMediaTypes(pPin, pEnumMediaTypes, pMediaType) \ -{ \ - CComPtr pEnumMediaTypes; \ - if (pPin && SUCCEEDED(pPin->EnumMediaTypes(&pEnumMediaTypes))) { \ - AM_MEDIA_TYPE* pMediaType = nullptr; \ - for (; S_OK == pEnumMediaTypes->Next(1, &pMediaType, nullptr); DeleteMediaType(pMediaType), pMediaType = nullptr) { - -#define EndEnumMediaTypes(pMediaType) \ - } \ - if (pMediaType) { \ - DeleteMediaType(pMediaType); \ - } \ - } \ -} - -#define BeginEnumSysDev(clsid, pMoniker) \ -{ \ - CComPtr pDevEnum4$##clsid; \ - if (SUCCEEDED(pDevEnum4$##clsid.CoCreateInstance(CLSID_SystemDeviceEnum))) { \ - CComPtr pClassEnum4$##clsid; \ - if (SUCCEEDED(pDevEnum4$##clsid->CreateClassEnumerator(clsid, &pClassEnum4$##clsid, 0)) \ - && pClassEnum4$##clsid) { \ - for (CComPtr pMoniker; pClassEnum4$##clsid->Next(1, &pMoniker, 0) == S_OK; pMoniker = nullptr) { - -#define EndEnumSysDev }}}} - -#define PauseGraph \ - CComQIPtr _pMC(m_pGraph); \ - OAFilterState _fs = -1; \ - if (_pMC) \ - _pMC->GetState(1000, &_fs); \ - if (_fs == State_Running) \ - _pMC->Pause(); \ - \ - HRESULT _hr = E_FAIL; \ - CComQIPtr _pMS((IUnknown*)(INonDelegatingUnknown*)m_pGraph); \ - REFERENCE_TIME _rtNow = 0; \ - if (_pMS) \ - _hr = _pMS->GetCurrentPosition(&_rtNow); - -#define ResumeGraph \ - if (SUCCEEDED(_hr) && _pMS && _fs != State_Stopped) \ - _hr = _pMS->SetPositions(&_rtNow, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); \ - \ - if (_fs == State_Running && _pMS) \ - _pMC->Run(); - -#define CallQueue(call) \ - if (!m_pOutputQueue) \ - return NOERROR; \ - m_pOutputQueue->##call; \ - return NOERROR; - -#define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : -#define QI2(i) (riid == IID_##i) ? GetInterface((i*)this, ppv) : - -#define SAFE_DELETE(p) { if (p) { delete (p); (p) = nullptr; } } -#define SAFE_DELETE_ARRAY(p) { if (p) { delete [] (p); (p) = nullptr; } } -#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } } -#define SAFE_CLOSE_HANDLE(p) { if (p) { if ((p) != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(p)); (p) = nullptr; } } -#define EXIT_ON_ERROR(hres) { if (FAILED(hres)) return hres; } - -#define StrRes(id) MAKEINTRESOURCE((id)) -#define ResStr(id) CString(StrRes((id))) - -#define UNREACHABLE_CODE() \ - do { \ - ASSERT(false); \ - __assume(false); \ - } while (false) - -template -static CUnknown* WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT* phr) -{ - *phr = S_OK; - CUnknown* punk = DEBUG_NEW T(lpunk, phr); - if (punk == nullptr) { - *phr = E_OUTOFMEMORY; - } - return punk; -} - -template -typename std::enable_if::value, T>::type GCD(T a, T b) -{ - static_assert(std::is_integral::value, "GCD supports integral types only"); - if (a == 0 || b == 0) { - return std::max(std::max(a, b), T(1)); - } - while (a != b) { - if (a < b) { - b -= a; - } else if (a > b) { - a -= b; - } - } - return a; -} - -template -typename std::enable_if::value, T>::type GCD(T a, T b) -{ - using uT = typename std::make_unsigned::type; - - return T(GCD(uT(std::abs(a)), uT(std::abs(b)))); -} - -template -constexpr typename std::enable_if::value, bool>::type IsEqual(T a, T b) -{ - return a == b; -} - -template -constexpr typename std::enable_if::value, bool>::type IsEqual(T a, T b) -{ - return std::abs(a - b) < std::numeric_limits::epsilon(); -} - -template -constexpr typename std::enable_if::value, bool>::type IsNearlyEqual(T a, T b, T epsilon) -{ - return std::abs(a - b) < epsilon; -} - -template -constexpr typename std::enable_if < std::is_integral::value&& std::is_unsigned::value, int >::type SGN(T n) -{ - return T(0) < n; -} - -template -constexpr typename std::enable_if < std::is_integral::value&& std::is_signed::value, int >::type SGN(T n) -{ - return (T(0) < n) - (n < T(0)); -} - -template -constexpr typename std::enable_if ::value, int>::type SGN(T n) -{ - return IsEqual(n, T(0)) ? 0 : (n > 0 ? 1 : -1); -} - -namespace CStringUtils -{ - struct IgnoreCaseLess { - bool operator()(const CString& str1, const CString& str2) const { - return str1.CompareNoCase(str2) < 0; - } - }; - struct LogicalLess { - bool operator()(const CString& str1, const CString& str2) const { - return StrCmpLogicalW(str1, str2) < 0; - } - }; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "HdmvClipInfo.h" +#include "MediaTypeEx.h" +#include "text.h" +#include "vd.h" +#include "BaseClasses/streams.h" +#include +#include +#include "MFCHelper.h" +#include "Utils.h" + +#define LCID_NOSUBTITLES -1 + +#define IsWaveFormatExtensible(wfe) (wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfe->cbSize == 22) + +extern int CountPins(IBaseFilter* pBF, int& nIn, int& nOut, int& nInC, int& nOutC); +extern bool IsSplitter(IBaseFilter* pBF, bool fCountConnectedOnly = false); +extern bool IsMultiplexer(IBaseFilter* pBF, bool fCountConnectedOnly = false); +extern bool IsStreamStart(IBaseFilter* pBF); +extern bool IsStreamEnd(IBaseFilter* pBF); +extern bool IsVideoRenderer(IBaseFilter* pBF); +extern bool IsAudioWaveRenderer(IBaseFilter* pBF); +extern IBaseFilter* GetUpStreamFilter(IBaseFilter* pBF, IPin* pInputPin = nullptr); +extern IPin* GetUpStreamPin(IBaseFilter* pBF, IPin* pInputPin = nullptr); +extern IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir = PINDIR_INPUT); +extern IPin* GetFirstDisconnectedPin(IBaseFilter* pBF, PIN_DIRECTION dir); +extern void NukeDownstream(IBaseFilter* pBF, IFilterGraph* pFG); +extern void NukeDownstream(IPin* pPin, IFilterGraph* pFG); +extern IBaseFilter* FindFilter(LPCWSTR clsid, IFilterGraph* pFG); +extern IBaseFilter* FindFilter(const CLSID& clsid, IFilterGraph* pFG); +extern IBaseFilter* FindFirstFilter(IFilterGraph* pFG); +extern IPin* FindPin(IBaseFilter* pBF, PIN_DIRECTION direction, const AM_MEDIA_TYPE* pRequestedMT); +extern CStringW GetFilterName(IBaseFilter* pBF); +extern CStringW GetPinName(IPin* pPin); +extern IFilterGraph* GetGraphFromFilter(IBaseFilter* pBF); +extern IBaseFilter* GetFilterFromPin(IPin* pPin); +extern IPin* AppendFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB); +extern IPin* InsertFilter(IPin* pPin, CString DisplayName, IGraphBuilder* pGB); +extern void ExtractMediaTypes(IPin* pPin, CAtlArray& types); +extern void ExtractMediaTypes(IPin* pPin, CAtlList& mts); +extern void ShowPPage(CString DisplayName, HWND hParentWnd); +extern void ShowPPage(IUnknown* pUnknown, HWND hParentWnd); +extern CLSID GetCLSID(IBaseFilter* pBF); +extern CLSID GetCLSID(IPin* pPin); +extern CString CLSIDToString(CLSID& clsid); +extern bool IsCLSIDRegistered(LPCTSTR clsid); +extern bool IsCLSIDRegistered(const CLSID& clsid); +extern CString GetFilterPath(LPCTSTR clsid); +extern CString GetFilterPath(const CLSID& clsid); +extern void CStringToBin(CString str, CAtlArray& data); +extern CString BinToCString(const BYTE* ptr, size_t len); +extern void FindFiles(CString fn, CAtlList& files); +enum OpticalDiskType_t { + OpticalDisk_NotFound, + OpticalDisk_Audio, + OpticalDisk_VideoCD, + OpticalDisk_DVDVideo, + OpticalDisk_BD, + OpticalDisk_Unknown +}; +extern OpticalDiskType_t GetOpticalDiskType(TCHAR drive, CAtlList& files); +extern CString GetDriveLabel(TCHAR drive); +extern CString GetDriveLabel(CPath path); +bool IsDriveVirtual(CString drive); +extern bool GetKeyFrames(CString fn, CUIntArray& kfs); +extern DVD_HMSF_TIMECODE RT2HMSF(REFERENCE_TIME rt, double fps = 0.0); // used to remember the current position +extern DVD_HMSF_TIMECODE RT2HMS(REFERENCE_TIME rt); +extern DVD_HMSF_TIMECODE RT2HMS_r(REFERENCE_TIME rt); // used only to display information with rounding to nearest second +extern REFERENCE_TIME HMSF2RT(DVD_HMSF_TIMECODE hmsf, double fps = -1.0); +extern void memsetd(void* dst, unsigned int c, size_t nbytes); +extern void memsetw(void* dst, unsigned short c, size_t nbytes); +extern bool ExtractBIH(const AM_MEDIA_TYPE* pmt, BITMAPINFOHEADER* bih); +extern bool ExtractBIH(IMediaSample* pMS, BITMAPINFOHEADER* bih); +extern bool ExtractAvgTimePerFrame(const AM_MEDIA_TYPE* pmt, REFERENCE_TIME& rtAvgTimePerFrame); +extern bool ExtractDim(const AM_MEDIA_TYPE* pmt, int& w, int& h, int& arx, int& ary); +extern bool CreateFilter(CStringW DisplayName, IBaseFilter** ppBF, CStringW& FriendlyName); +extern IBaseFilter* AppendFilter(IPin* pPin, IMoniker* pMoniker, IGraphBuilder* pGB); +extern CStringW GetFriendlyName(CStringW DisplayName); +extern HRESULT LoadExternalObject(LPCTSTR path, REFCLSID clsid, REFIID iid, void** ppv, IUnknown* aggregate = nullptr); +extern HRESULT LoadExternalFilter(LPCTSTR path, REFCLSID clsid, IBaseFilter** ppBF); +extern HRESULT LoadExternalPropertyPage(IPersist* pP, REFCLSID clsid, IPropertyPage** ppPP); +extern bool UnloadUnusedExternalObjects(); +extern void ExtendMaxPathLengthIfNeeded(CString& path, bool no_url = false); +extern bool ContainsWildcard(CString& path); +extern void ShortenLongPath(CString& path); +extern CString MakeFullPath(LPCTSTR path); +extern bool GetMediaTypeFourCC(const GUID& guid, CString& fourCC); +extern CString GetMediaTypeName(const GUID& guid); +extern GUID GUIDFromCString(CString str); +extern HRESULT GUIDFromCString(CString str, GUID& guid); +extern CString CStringFromGUID(const GUID& guid); +extern CStringW UTF8To16(LPCSTR utf8); +extern CStringA UTF16To8(LPCWSTR utf16); +extern CStringW UTF8ToStringW(const char* S); +extern CStringW LocalToStringW(const char* S); +extern BOOL CFileGetStatus(LPCTSTR lpszFileName, CFileStatus& status); +extern bool DeleteRegKey(LPCTSTR pszKey, LPCTSTR pszSubkey); +extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValueName, LPCTSTR pszValue); +extern bool SetRegKeyValue(LPCTSTR pszKey, LPCTSTR pszSubkey, LPCTSTR pszValue); +extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, LPCTSTR chkbytes, LPCTSTR ext = nullptr, ...); +extern void RegisterSourceFilter(const CLSID& clsid, const GUID& subtype2, const CAtlList& chkbytes, LPCTSTR ext = nullptr, ...); +extern void UnRegisterSourceFilter(const GUID& subtype); +extern LPCTSTR GetDXVAMode(const GUID* guidDecoder); +extern CString ReftimeToString(const REFERENCE_TIME& rtVal); +extern CString ReftimeToString2(const REFERENCE_TIME& rtVal); +extern CString ReftimeToString3(const REFERENCE_TIME& rtVal); +extern CStringW ReftimeToString4(REFERENCE_TIME rt, bool showZeroHours = true); +extern CString DVDtimeToString(const DVD_HMSF_TIMECODE& rtVal, bool bAlwaysShowHours = false); +extern REFERENCE_TIME StringToReftime(LPCTSTR strVal); +extern void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName); +extern CString FindCoverArt(const CString& path, const CString& author); +extern CString NormalizeUnicodeStrForSearch(CString srcStr, LANGID langid); +extern bool FindStringInList(const CAtlList& list, CString& value); +extern CStringW ForceTrailingSlash(CStringW folder); +extern CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt); +extern CStringW GetChannelStrFromMediaType(AM_MEDIA_TYPE* pmt, int& channels); +extern CStringW GetShortAudioNameFromMediaType(AM_MEDIA_TYPE* pmt); +extern bool GetVideoFormatNameFromMediaType(const GUID& guid, CString& name); + +extern inline const LONGLONG GetPerfCounter(); + +enum FF_FIELD_TYPE { + PICT_NONE, + PICT_TOP_FIELD, + PICT_BOTTOM_FIELD, + PICT_FRAME +}; + +class CPinInfo : public PIN_INFO +{ +public: + CPinInfo() { + pFilter = nullptr; + } + ~CPinInfo() { + if (pFilter) { + pFilter->Release(); + } + } +}; + +class CFilterInfo : public FILTER_INFO +{ +public: + CFilterInfo() { + pGraph = nullptr; + } + ~CFilterInfo() { + if (pGraph) { + pGraph->Release(); + } + } +}; + +#define BeginEnumFilters(pFilterGraph, pEnumFilters, pBaseFilter) \ +{ \ + CComPtr pEnumFilters; \ + if (pFilterGraph && SUCCEEDED(pFilterGraph->EnumFilters(&pEnumFilters))) { \ + for (CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = nullptr) { + +#define EndEnumFilters }}} + +#define BeginEnumCachedFilters(pGraphConfig, pEnumFilters, pBaseFilter) \ +{ \ + CComPtr pEnumFilters; \ + if (pGraphConfig && SUCCEEDED(pGraphConfig->EnumCacheFilter(&pEnumFilters))) { \ + for (CComPtr pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = nullptr) { + +#define EndEnumCachedFilters }}} + +#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \ +{ \ + CComPtr pEnumPins; \ + if (pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) { \ + for (CComPtr pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = nullptr) { + +#define EndEnumPins }}} + +#define BeginEnumMediaTypes(pPin, pEnumMediaTypes, pMediaType) \ +{ \ + CComPtr pEnumMediaTypes; \ + if (pPin && SUCCEEDED(pPin->EnumMediaTypes(&pEnumMediaTypes))) { \ + AM_MEDIA_TYPE* pMediaType = nullptr; \ + for (; S_OK == pEnumMediaTypes->Next(1, &pMediaType, nullptr); DeleteMediaType(pMediaType), pMediaType = nullptr) { + +#define EndEnumMediaTypes(pMediaType) \ + } \ + if (pMediaType) { \ + DeleteMediaType(pMediaType); \ + } \ + } \ +} + +#define BeginEnumSysDev(clsid, pMoniker) \ +{ \ + CComPtr pDevEnum4$##clsid; \ + if (SUCCEEDED(pDevEnum4$##clsid.CoCreateInstance(CLSID_SystemDeviceEnum))) { \ + CComPtr pClassEnum4$##clsid; \ + if (SUCCEEDED(pDevEnum4$##clsid->CreateClassEnumerator(clsid, &pClassEnum4$##clsid, 0)) \ + && pClassEnum4$##clsid) { \ + for (CComPtr pMoniker; pClassEnum4$##clsid->Next(1, &pMoniker, 0) == S_OK; pMoniker = nullptr) { + +#define EndEnumSysDev }}}} + +#define PauseGraph \ + CComQIPtr _pMC(m_pGraph); \ + OAFilterState _fs = -1; \ + if (_pMC) \ + _pMC->GetState(1000, &_fs); \ + if (_fs == State_Running) \ + _pMC->Pause(); \ + \ + HRESULT _hr = E_FAIL; \ + CComQIPtr _pMS((IUnknown*)(INonDelegatingUnknown*)m_pGraph); \ + REFERENCE_TIME _rtNow = 0; \ + if (_pMS) \ + _hr = _pMS->GetCurrentPosition(&_rtNow); + +#define ResumeGraph \ + if (SUCCEEDED(_hr) && _pMS && _fs != State_Stopped) \ + _hr = _pMS->SetPositions(&_rtNow, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); \ + \ + if (_fs == State_Running && _pMS) \ + _pMC->Run(); + +#define CallQueue(call) \ + if (!m_pOutputQueue) \ + return NOERROR; \ + m_pOutputQueue->##call; \ + return NOERROR; + +#define QI(i) (riid == __uuidof(i)) ? GetInterface((i*)this, ppv) : +#define QI2(i) (riid == IID_##i) ? GetInterface((i*)this, ppv) : + +#define SAFE_DELETE(p) { if (p) { delete (p); (p) = nullptr; } } +#define SAFE_DELETE_ARRAY(p) { if (p) { delete [] (p); (p) = nullptr; } } +#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } } +#define SAFE_CLOSE_HANDLE(p) { if (p) { if ((p) != INVALID_HANDLE_VALUE) VERIFY(CloseHandle(p)); (p) = nullptr; } } +#define EXIT_ON_ERROR(hres) { if (FAILED(hres)) return hres; } + +#define StrRes(id) MAKEINTRESOURCE((id)) +#define ResStr(id) CString(StrRes((id))) + +#define UNREACHABLE_CODE() \ + do { \ + ASSERT(false); \ + __assume(false); \ + } while (false) + +template +static CUnknown* WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT* phr) +{ + *phr = S_OK; + CUnknown* punk = DEBUG_NEW T(lpunk, phr); + if (punk == nullptr) { + *phr = E_OUTOFMEMORY; + } + return punk; +} + +template +typename std::enable_if::value, T>::type GCD(T a, T b) +{ + static_assert(std::is_integral::value, "GCD supports integral types only"); + if (a == 0 || b == 0) { + return std::max(std::max(a, b), T(1)); + } + while (a != b) { + if (a < b) { + b -= a; + } else if (a > b) { + a -= b; + } + } + return a; +} + +template +typename std::enable_if::value, T>::type GCD(T a, T b) +{ + using uT = typename std::make_unsigned::type; + + return T(GCD(uT(std::abs(a)), uT(std::abs(b)))); +} + +template +constexpr typename std::enable_if::value, bool>::type IsEqual(T a, T b) +{ + return a == b; +} + +template +constexpr typename std::enable_if::value, bool>::type IsEqual(T a, T b) +{ + return std::abs(a - b) < std::numeric_limits::epsilon(); +} + +template +constexpr typename std::enable_if::value, bool>::type IsNearlyEqual(T a, T b, T epsilon) +{ + return std::abs(a - b) < epsilon; +} + +template +constexpr typename std::enable_if < std::is_integral::value&& std::is_unsigned::value, int >::type SGN(T n) +{ + return T(0) < n; +} + +template +constexpr typename std::enable_if < std::is_integral::value&& std::is_signed::value, int >::type SGN(T n) +{ + return (T(0) < n) - (n < T(0)); +} + +template +constexpr typename std::enable_if ::value, int>::type SGN(T n) +{ + return IsEqual(n, T(0)) ? 0 : (n > 0 ? 1 : -1); +} + +namespace CStringUtils +{ + struct IgnoreCaseLess { + bool operator()(const CString& str1, const CString& str2) const { + return str1.CompareNoCase(str2) < 0; + } + }; + struct LogicalLess { + bool operator()(const CString& str1, const CString& str2) const { + return StrCmpLogicalW(str1, str2) < 0; + } + }; +} diff --git a/src/DSUtil/DSUtil.vcxproj b/src/DSUtil/DSUtil.vcxproj index 02d8b530914..3644ec33a01 100644 --- a/src/DSUtil/DSUtil.vcxproj +++ b/src/DSUtil/DSUtil.vcxproj @@ -1,121 +1,121 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {FC70988B-1AE5-4381-866D-4F405E28AC42} - DSUtil - MFCProj - DSUtil - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\include;..\DSUtil;..\filters\renderer\VideoRenderers;..\thirdparty;..\thirdparty\VirtualDub\h;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {FC70988B-1AE5-4381-866D-4F405E28AC42} + DSUtil + MFCProj + DSUtil + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\include;..\DSUtil;..\filters\renderer\VideoRenderers;..\thirdparty;..\thirdparty\VirtualDub\h;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + + + \ No newline at end of file diff --git a/src/DSUtil/DSUtil.vcxproj.filters b/src/DSUtil/DSUtil.vcxproj.filters index 309f889e253..c63c6abce35 100644 --- a/src/DSUtil/DSUtil.vcxproj.filters +++ b/src/DSUtil/DSUtil.vcxproj.filters @@ -1,188 +1,188 @@ - - - - - {7a9014bb-a149-4bb1-be1b-b988a38f79d0} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {2b09c18b-87fc-47da-a366-3e14c0b9d40f} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {7a9014bb-a149-4bb1-be1b-b988a38f79d0} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {2b09c18b-87fc-47da-a366-3e14c0b9d40f} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/DSUtil/FileVersionInfo.cpp b/src/DSUtil/FileVersionInfo.cpp index cdc19fc5e5e..8b5302ac006 100644 --- a/src/DSUtil/FileVersionInfo.cpp +++ b/src/DSUtil/FileVersionInfo.cpp @@ -1,91 +1,91 @@ -/* - * (C) 2012-2014 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 . - * - */ - -#include "stdafx.h" -#include "FileVersionInfo.h" - -bool FileVersionInfo::LoadInfo(LPCTSTR filePath, VS_FIXEDFILEINFO& fileInfo) -{ - bool success = false; - - // Get the buffer size required for the version information - DWORD dwFileVersionInfoSize = GetFileVersionInfoSize(filePath, nullptr); - if (dwFileVersionInfoSize) { - // Allocate the buffer - BYTE* lpData = (BYTE*)DEBUG_NEW BYTE[dwFileVersionInfoSize]; - if (lpData) { - // Load the file-version information - if (GetFileVersionInfo(filePath, 0, dwFileVersionInfoSize, (LPVOID)lpData)) { - // Parse the version information - VS_FIXEDFILEINFO* lpInfo; - UINT unInfoLen; - if (VerQueryValue((LPVOID)lpData, _T("\\"), (LPVOID*)&lpInfo, &unInfoLen) - && unInfoLen == sizeof(VS_FIXEDFILEINFO)) { - fileInfo = *lpInfo; - success = true; - } - } - - delete [] lpData; - } - } - - return success; -} - -CString FileVersionInfo::GetFileVersionStr(LPCTSTR filePath) -{ - VS_FIXEDFILEINFO fileInfo; - CString strFileVersion; - - if (LoadInfo(filePath, fileInfo)) { - strFileVersion = FormatVersionString(fileInfo.dwFileVersionLS, fileInfo.dwFileVersionMS); - } - - return strFileVersion; -} - -QWORD FileVersionInfo::GetFileVersionNum(LPCTSTR filePath) -{ - VS_FIXEDFILEINFO fileInfo; - QWORD qwFileVersion = 0; - - if (LoadInfo(filePath, fileInfo)) { - qwFileVersion = ((QWORD)fileInfo.dwFileVersionMS << 32) | fileInfo.dwFileVersionLS; - } - - return qwFileVersion; -} - -CString FileVersionInfo::FormatVersionString(DWORD dwVersionNumberLow, DWORD dwVersionNumberHigh) -{ - CString strFileVersion; - strFileVersion.Format(_T("%lu.%lu.%lu.%lu"), - (dwVersionNumberHigh & 0xFFFF0000) >> 16, - (dwVersionNumberHigh & 0x0000FFFF), - (dwVersionNumberLow & 0xFFFF0000) >> 16, - (dwVersionNumberLow & 0x0000FFFF)); - return strFileVersion; -} - -CString FileVersionInfo::FormatVersionString(QWORD qwVersionNumber) -{ - return FormatVersionString(qwVersionNumber & DWORD_MAX, (qwVersionNumber >> 32) & DWORD_MAX); -} +/* + * (C) 2012-2014 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 . + * + */ + +#include "stdafx.h" +#include "FileVersionInfo.h" + +bool FileVersionInfo::LoadInfo(LPCTSTR filePath, VS_FIXEDFILEINFO& fileInfo) +{ + bool success = false; + + // Get the buffer size required for the version information + DWORD dwFileVersionInfoSize = GetFileVersionInfoSize(filePath, nullptr); + if (dwFileVersionInfoSize) { + // Allocate the buffer + BYTE* lpData = (BYTE*)DEBUG_NEW BYTE[dwFileVersionInfoSize]; + if (lpData) { + // Load the file-version information + if (GetFileVersionInfo(filePath, 0, dwFileVersionInfoSize, (LPVOID)lpData)) { + // Parse the version information + VS_FIXEDFILEINFO* lpInfo; + UINT unInfoLen; + if (VerQueryValue((LPVOID)lpData, _T("\\"), (LPVOID*)&lpInfo, &unInfoLen) + && unInfoLen == sizeof(VS_FIXEDFILEINFO)) { + fileInfo = *lpInfo; + success = true; + } + } + + delete [] lpData; + } + } + + return success; +} + +CString FileVersionInfo::GetFileVersionStr(LPCTSTR filePath) +{ + VS_FIXEDFILEINFO fileInfo; + CString strFileVersion; + + if (LoadInfo(filePath, fileInfo)) { + strFileVersion = FormatVersionString(fileInfo.dwFileVersionLS, fileInfo.dwFileVersionMS); + } + + return strFileVersion; +} + +QWORD FileVersionInfo::GetFileVersionNum(LPCTSTR filePath) +{ + VS_FIXEDFILEINFO fileInfo; + QWORD qwFileVersion = 0; + + if (LoadInfo(filePath, fileInfo)) { + qwFileVersion = ((QWORD)fileInfo.dwFileVersionMS << 32) | fileInfo.dwFileVersionLS; + } + + return qwFileVersion; +} + +CString FileVersionInfo::FormatVersionString(DWORD dwVersionNumberLow, DWORD dwVersionNumberHigh) +{ + CString strFileVersion; + strFileVersion.Format(_T("%lu.%lu.%lu.%lu"), + (dwVersionNumberHigh & 0xFFFF0000) >> 16, + (dwVersionNumberHigh & 0x0000FFFF), + (dwVersionNumberLow & 0xFFFF0000) >> 16, + (dwVersionNumberLow & 0x0000FFFF)); + return strFileVersion; +} + +CString FileVersionInfo::FormatVersionString(QWORD qwVersionNumber) +{ + return FormatVersionString(qwVersionNumber & DWORD_MAX, (qwVersionNumber >> 32) & DWORD_MAX); +} diff --git a/src/DSUtil/FileVersionInfo.h b/src/DSUtil/FileVersionInfo.h index 6bd0a3e84bf..aa46444f9b3 100644 --- a/src/DSUtil/FileVersionInfo.h +++ b/src/DSUtil/FileVersionInfo.h @@ -1,32 +1,32 @@ -/* - * (C) 2012-2014 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 . - * - */ - -#pragma once - -namespace FileVersionInfo -{ - bool LoadInfo(LPCTSTR filePath, VS_FIXEDFILEINFO& fileInfo); - - CString GetFileVersionStr(LPCTSTR filePath); - QWORD GetFileVersionNum(LPCTSTR filePath); - - CString FormatVersionString(DWORD dwVersionNumberLow, DWORD dwVersionNumberHigh); - CString FormatVersionString(QWORD qwVersionNumber); -}; +/* + * (C) 2012-2014 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 . + * + */ + +#pragma once + +namespace FileVersionInfo +{ + bool LoadInfo(LPCTSTR filePath, VS_FIXEDFILEINFO& fileInfo); + + CString GetFileVersionStr(LPCTSTR filePath); + QWORD GetFileVersionNum(LPCTSTR filePath); + + CString FormatVersionString(DWORD dwVersionNumberLow, DWORD dwVersionNumberHigh); + CString FormatVersionString(QWORD qwVersionNumber); +}; diff --git a/src/DSUtil/FontInstaller.cpp b/src/DSUtil/FontInstaller.cpp index 4c3b32c86c5..53dedad86d4 100644 --- a/src/DSUtil/FontInstaller.cpp +++ b/src/DSUtil/FontInstaller.cpp @@ -1,139 +1,139 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "FontInstaller.h" - -CFontInstaller::CFontInstaller() - : pAddFontMemResourceEx(nullptr) - , pAddFontResourceEx(nullptr) - , pRemoveFontMemResourceEx(nullptr) - , pRemoveFontResourceEx(nullptr) - , pMoveFileEx(nullptr) -{ - if (HMODULE hGdi = GetModuleHandle(_T("gdi32.dll"))) { - pAddFontMemResourceEx = (HANDLE(WINAPI*)(PVOID, DWORD, PVOID, DWORD*))GetProcAddress(hGdi, "AddFontMemResourceEx"); - pAddFontResourceEx = (int (WINAPI*)(LPCTSTR, DWORD, PVOID))GetProcAddress(hGdi, "AddFontResourceExW"); - pRemoveFontMemResourceEx = (BOOL (WINAPI*)(HANDLE))GetProcAddress(hGdi, "RemoveFontMemResourceEx"); - pRemoveFontResourceEx = (BOOL (WINAPI*)(LPCTSTR, DWORD, PVOID))GetProcAddress(hGdi, "RemoveFontResourceExW"); - } - - if (HMODULE hGdi = GetModuleHandle(_T("kernel32.dll"))) { - pMoveFileEx = (BOOL (WINAPI*)(LPCTSTR, LPCTSTR, DWORD))GetProcAddress(hGdi, "MoveFileExW"); - } -} - -CFontInstaller::~CFontInstaller() -{ - UninstallFonts(); -} - -bool CFontInstaller::InstallFont(const CAtlArray& data) -{ - return InstallFont(data.GetData(), (UINT)data.GetCount()); -} - -bool CFontInstaller::InstallFont(const void* pData, UINT len) -{ - return InstallFontFile(pData, len) || InstallFontMemory(pData, len); -} - -void CFontInstaller::UninstallFonts() -{ - if (pRemoveFontMemResourceEx) { - POSITION pos = m_fonts.GetHeadPosition(); - while (pos) { - pRemoveFontMemResourceEx(m_fonts.GetNext(pos)); - } - m_fonts.RemoveAll(); - } - - if (pRemoveFontResourceEx) { - POSITION pos = m_files.GetHeadPosition(); - while (pos) { - CString fn = m_files.GetNext(pos); - pRemoveFontResourceEx(fn, FR_PRIVATE, 0); - if (!DeleteFile(fn) && pMoveFileEx) { - pMoveFileEx(fn, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); - } - } - - m_files.RemoveAll(); - - pos = m_tempfonts.GetHeadPosition(); - while (pos) { - CString fn = m_tempfonts.GetNext(pos); - pRemoveFontResourceEx(fn, FR_PRIVATE, 0); - } - - m_tempfonts.RemoveAll(); - } -} - -bool CFontInstaller::InstallFontMemory(const void* pData, UINT len) -{ - if (!pAddFontMemResourceEx) { - return false; - } - - DWORD nFonts = 0; - HANDLE hFont = pAddFontMemResourceEx((PVOID)pData, len, nullptr, &nFonts); - if (hFont && nFonts > 0) { - m_fonts.AddTail(hFont); - } - return hFont && nFonts > 0; -} - -bool CFontInstaller::InstallFontFile(const void* pData, UINT len) -{ - if (!pAddFontResourceEx) { - return false; - } - - CFile f; - TCHAR path[MAX_PATH], fn[MAX_PATH]; - if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("g_font"), 0, fn)) { - return false; - } - - if (f.Open(fn, CFile::modeWrite)) { - f.Write(pData, len); - f.Close(); - - if (pAddFontResourceEx(fn, FR_PRIVATE, 0) > 0) { - m_files.AddTail(fn); - return true; - } - } - - DeleteFile(fn); - return false; -} - -bool CFontInstaller::InstallTempFontFile(LPCTSTR fn) -{ - if (pAddFontResourceEx && pAddFontResourceEx(fn, FR_PRIVATE, 0) > 0) { - m_tempfonts.AddTail(fn); - return true; - } - - return false; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "FontInstaller.h" + +CFontInstaller::CFontInstaller() + : pAddFontMemResourceEx(nullptr) + , pAddFontResourceEx(nullptr) + , pRemoveFontMemResourceEx(nullptr) + , pRemoveFontResourceEx(nullptr) + , pMoveFileEx(nullptr) +{ + if (HMODULE hGdi = GetModuleHandle(_T("gdi32.dll"))) { + pAddFontMemResourceEx = (HANDLE(WINAPI*)(PVOID, DWORD, PVOID, DWORD*))GetProcAddress(hGdi, "AddFontMemResourceEx"); + pAddFontResourceEx = (int (WINAPI*)(LPCTSTR, DWORD, PVOID))GetProcAddress(hGdi, "AddFontResourceExW"); + pRemoveFontMemResourceEx = (BOOL (WINAPI*)(HANDLE))GetProcAddress(hGdi, "RemoveFontMemResourceEx"); + pRemoveFontResourceEx = (BOOL (WINAPI*)(LPCTSTR, DWORD, PVOID))GetProcAddress(hGdi, "RemoveFontResourceExW"); + } + + if (HMODULE hGdi = GetModuleHandle(_T("kernel32.dll"))) { + pMoveFileEx = (BOOL (WINAPI*)(LPCTSTR, LPCTSTR, DWORD))GetProcAddress(hGdi, "MoveFileExW"); + } +} + +CFontInstaller::~CFontInstaller() +{ + UninstallFonts(); +} + +bool CFontInstaller::InstallFont(const CAtlArray& data) +{ + return InstallFont(data.GetData(), (UINT)data.GetCount()); +} + +bool CFontInstaller::InstallFont(const void* pData, UINT len) +{ + return InstallFontFile(pData, len) || InstallFontMemory(pData, len); +} + +void CFontInstaller::UninstallFonts() +{ + if (pRemoveFontMemResourceEx) { + POSITION pos = m_fonts.GetHeadPosition(); + while (pos) { + pRemoveFontMemResourceEx(m_fonts.GetNext(pos)); + } + m_fonts.RemoveAll(); + } + + if (pRemoveFontResourceEx) { + POSITION pos = m_files.GetHeadPosition(); + while (pos) { + CString fn = m_files.GetNext(pos); + pRemoveFontResourceEx(fn, FR_PRIVATE, 0); + if (!DeleteFile(fn) && pMoveFileEx) { + pMoveFileEx(fn, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); + } + } + + m_files.RemoveAll(); + + pos = m_tempfonts.GetHeadPosition(); + while (pos) { + CString fn = m_tempfonts.GetNext(pos); + pRemoveFontResourceEx(fn, FR_PRIVATE, 0); + } + + m_tempfonts.RemoveAll(); + } +} + +bool CFontInstaller::InstallFontMemory(const void* pData, UINT len) +{ + if (!pAddFontMemResourceEx) { + return false; + } + + DWORD nFonts = 0; + HANDLE hFont = pAddFontMemResourceEx((PVOID)pData, len, nullptr, &nFonts); + if (hFont && nFonts > 0) { + m_fonts.AddTail(hFont); + } + return hFont && nFonts > 0; +} + +bool CFontInstaller::InstallFontFile(const void* pData, UINT len) +{ + if (!pAddFontResourceEx) { + return false; + } + + CFile f; + TCHAR path[MAX_PATH], fn[MAX_PATH]; + if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("g_font"), 0, fn)) { + return false; + } + + if (f.Open(fn, CFile::modeWrite)) { + f.Write(pData, len); + f.Close(); + + if (pAddFontResourceEx(fn, FR_PRIVATE, 0) > 0) { + m_files.AddTail(fn); + return true; + } + } + + DeleteFile(fn); + return false; +} + +bool CFontInstaller::InstallTempFontFile(LPCTSTR fn) +{ + if (pAddFontResourceEx && pAddFontResourceEx(fn, FR_PRIVATE, 0) > 0) { + m_tempfonts.AddTail(fn); + return true; + } + + return false; +} diff --git a/src/DSUtil/FontInstaller.h b/src/DSUtil/FontInstaller.h index 968448c459b..1693278838e 100644 --- a/src/DSUtil/FontInstaller.h +++ b/src/DSUtil/FontInstaller.h @@ -1,48 +1,48 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2014 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 . - * - */ - -#pragma once - -#include - -class CFontInstaller -{ - HANDLE(WINAPI* pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD*); - int (WINAPI* pAddFontResourceEx)(LPCTSTR, DWORD, PVOID); - BOOL (WINAPI* pRemoveFontMemResourceEx)(HANDLE); - BOOL (WINAPI* pRemoveFontResourceEx)(LPCTSTR, DWORD, PVOID); - BOOL (WINAPI* pMoveFileEx)(LPCTSTR, LPCTSTR, DWORD); - - CAtlList m_fonts; - CAtlList m_files; - CAtlList m_tempfonts; - bool InstallFontFile(const void* pData, UINT len); - -public: - CFontInstaller(); - virtual ~CFontInstaller(); - - bool InstallFont(const CAtlArray& data); - bool InstallFont(const void* pData, UINT len); - bool InstallFontMemory(const void* pData, UINT len); - bool InstallTempFontFile(LPCTSTR fn); - void UninstallFonts(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2014 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 . + * + */ + +#pragma once + +#include + +class CFontInstaller +{ + HANDLE(WINAPI* pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD*); + int (WINAPI* pAddFontResourceEx)(LPCTSTR, DWORD, PVOID); + BOOL (WINAPI* pRemoveFontMemResourceEx)(HANDLE); + BOOL (WINAPI* pRemoveFontResourceEx)(LPCTSTR, DWORD, PVOID); + BOOL (WINAPI* pMoveFileEx)(LPCTSTR, LPCTSTR, DWORD); + + CAtlList m_fonts; + CAtlList m_files; + CAtlList m_tempfonts; + bool InstallFontFile(const void* pData, UINT len); + +public: + CFontInstaller(); + virtual ~CFontInstaller(); + + bool InstallFont(const CAtlArray& data); + bool InstallFont(const void* pData, UINT len); + bool InstallFontMemory(const void* pData, UINT len); + bool InstallTempFontFile(LPCTSTR fn); + void UninstallFonts(); +}; diff --git a/src/DSUtil/GolombBuffer.cpp b/src/DSUtil/GolombBuffer.cpp index cc909da4b9e..00e23ff10f2 100644 --- a/src/DSUtil/GolombBuffer.cpp +++ b/src/DSUtil/GolombBuffer.cpp @@ -1,205 +1,205 @@ -/* - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "GolombBuffer.h" -#include - -static void RemoveMpegEscapeCode(BYTE* dst, const BYTE* src, int& length) -{ - memset(dst, 0, length); - int si = 0; - int di = 0; - while (si + 2 < length) { - if (src[si + 2] > 3) { - dst[di++] = src[si++]; - dst[di++] = src[si++]; - } else if (src[si] == 0 && src[si + 1] == 0) { - dst[di++] = 0; - dst[di++] = 0; - if (src[si + 2] == 3) { // escape - si += 3; - } else { - si += 2; - } - continue; - } - - dst[di++] = src[si++]; - } - while (si < length) { - dst[di++] = src[si++]; - } - - length = di; -} - -CGolombBuffer::CGolombBuffer(const BYTE* pBuffer, int nSize, const bool bRemoveMpegEscapes/* = false*/) - : m_bRemoveMpegEscapes(bRemoveMpegEscapes) - , m_pTmpBuffer(nullptr) -{ - Reset(pBuffer, nSize); -} - -CGolombBuffer::~CGolombBuffer() -{ - SAFE_DELETE_ARRAY(m_pTmpBuffer); -} - -UINT64 CGolombBuffer::BitRead(const int nBits, const bool bPeek/* = false*/) -{ - //ASSERT(nBits >= 0 && nBits <= 64); - const INT64 tmp_bitbuff = m_bitbuff; - const int tmp_nBitPos = m_nBitPos; - const int tmp_bitlen = m_bitlen; - - while (m_bitlen < nBits) { - m_bitbuff <<= 8; - - if (m_nBitPos >= m_nSize) { - return 0; - } - - *(BYTE*)&m_bitbuff = m_pBuffer[m_nBitPos++]; - m_bitlen += 8; - } - - const int bitlen = m_bitlen - nBits; - - UINT64 ret; - // The shift to 64 bits can give incorrect results. - // "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." - if (nBits == 64) { - ret = m_bitbuff; - } else { - ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); - } - - if (!bPeek) { - m_bitbuff &= ((1ui64 << bitlen) - 1); - m_bitlen = bitlen; - } else { - m_bitbuff = tmp_bitbuff; - m_nBitPos = tmp_nBitPos; - m_bitlen = tmp_bitlen; - } - - return ret; -} - -UINT64 CGolombBuffer::UExpGolombRead() -{ - int n = -1; - for (BYTE b = 0; !b && !IsEOF(); n++) { - b = (BYTE)BitRead(1); - } - return (1ui64 << n) - 1 + BitRead(n); -} - -unsigned int CGolombBuffer::UintGolombRead() -{ - unsigned int value = 0, count = 0; - while (!BitRead(1) && !IsEOF()) { - count++; - value <<= 1; - value |= BitRead(1); - } - - return (1 << count) - 1 + value; -} - -INT64 CGolombBuffer::SExpGolombRead() -{ - UINT64 k = UExpGolombRead(); - return ((k&1) ? 1 : -1) * ((k + 1) >> 1); -} - -void CGolombBuffer::BitByteAlign() -{ - m_bitlen &= ~7; -} - -int CGolombBuffer::GetPos() const -{ - return m_nBitPos - (m_bitlen >> 3); -} - -void CGolombBuffer::ReadBuffer(BYTE* pDest, int nSize) -{ - ASSERT(m_nBitPos + nSize <= m_nSize); - ASSERT(m_bitlen == 0); - nSize = std::min(nSize, m_nSize - m_nBitPos); - - memcpy(pDest, m_pBuffer + m_nBitPos, nSize); - m_nBitPos += nSize; -} - -void CGolombBuffer::Reset() -{ - m_nBitPos = 0; - m_bitlen = 0; - m_bitbuff = 0; -} - -void CGolombBuffer::Reset(const BYTE* pNewBuffer, int nNewSize) -{ - if (m_bRemoveMpegEscapes) { - SAFE_DELETE_ARRAY(m_pTmpBuffer); - m_pTmpBuffer = DEBUG_NEW BYTE[nNewSize]; - - RemoveMpegEscapeCode(m_pTmpBuffer, pNewBuffer, nNewSize); - m_pBuffer = m_pTmpBuffer; - m_nSize = nNewSize; - } else { - m_pBuffer = pNewBuffer; - m_nSize = nNewSize; - } - - Reset(); -} - -void CGolombBuffer::SkipBytes(const int nCount) -{ - m_nBitPos += nCount; - m_bitlen = 0; - m_bitbuff = 0; -} - -void CGolombBuffer::Seek(const int nCount) -{ - m_nBitPos = nCount; - m_bitlen = 0; - m_bitbuff = 0; -} - -bool CGolombBuffer::NextMpegStartCode(BYTE& code) -{ - BitByteAlign(); - DWORD dw = DWORD_MAX; - do { - if (IsEOF()) { - return false; - } - dw = (dw << 8) | (BYTE)BitRead(8); - } while ((dw & 0xffffff00) != 0x00000100); - code = (BYTE)(dw & 0xff); - - return true; -} +/* + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "GolombBuffer.h" +#include + +static void RemoveMpegEscapeCode(BYTE* dst, const BYTE* src, int& length) +{ + memset(dst, 0, length); + int si = 0; + int di = 0; + while (si + 2 < length) { + if (src[si + 2] > 3) { + dst[di++] = src[si++]; + dst[di++] = src[si++]; + } else if (src[si] == 0 && src[si + 1] == 0) { + dst[di++] = 0; + dst[di++] = 0; + if (src[si + 2] == 3) { // escape + si += 3; + } else { + si += 2; + } + continue; + } + + dst[di++] = src[si++]; + } + while (si < length) { + dst[di++] = src[si++]; + } + + length = di; +} + +CGolombBuffer::CGolombBuffer(const BYTE* pBuffer, int nSize, const bool bRemoveMpegEscapes/* = false*/) + : m_bRemoveMpegEscapes(bRemoveMpegEscapes) + , m_pTmpBuffer(nullptr) +{ + Reset(pBuffer, nSize); +} + +CGolombBuffer::~CGolombBuffer() +{ + SAFE_DELETE_ARRAY(m_pTmpBuffer); +} + +UINT64 CGolombBuffer::BitRead(const int nBits, const bool bPeek/* = false*/) +{ + //ASSERT(nBits >= 0 && nBits <= 64); + const INT64 tmp_bitbuff = m_bitbuff; + const int tmp_nBitPos = m_nBitPos; + const int tmp_bitlen = m_bitlen; + + while (m_bitlen < nBits) { + m_bitbuff <<= 8; + + if (m_nBitPos >= m_nSize) { + return 0; + } + + *(BYTE*)&m_bitbuff = m_pBuffer[m_nBitPos++]; + m_bitlen += 8; + } + + const int bitlen = m_bitlen - nBits; + + UINT64 ret; + // The shift to 64 bits can give incorrect results. + // "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." + if (nBits == 64) { + ret = m_bitbuff; + } else { + ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); + } + + if (!bPeek) { + m_bitbuff &= ((1ui64 << bitlen) - 1); + m_bitlen = bitlen; + } else { + m_bitbuff = tmp_bitbuff; + m_nBitPos = tmp_nBitPos; + m_bitlen = tmp_bitlen; + } + + return ret; +} + +UINT64 CGolombBuffer::UExpGolombRead() +{ + int n = -1; + for (BYTE b = 0; !b && !IsEOF(); n++) { + b = (BYTE)BitRead(1); + } + return (1ui64 << n) - 1 + BitRead(n); +} + +unsigned int CGolombBuffer::UintGolombRead() +{ + unsigned int value = 0, count = 0; + while (!BitRead(1) && !IsEOF()) { + count++; + value <<= 1; + value |= BitRead(1); + } + + return (1 << count) - 1 + value; +} + +INT64 CGolombBuffer::SExpGolombRead() +{ + UINT64 k = UExpGolombRead(); + return ((k&1) ? 1 : -1) * ((k + 1) >> 1); +} + +void CGolombBuffer::BitByteAlign() +{ + m_bitlen &= ~7; +} + +int CGolombBuffer::GetPos() const +{ + return m_nBitPos - (m_bitlen >> 3); +} + +void CGolombBuffer::ReadBuffer(BYTE* pDest, int nSize) +{ + ASSERT(m_nBitPos + nSize <= m_nSize); + ASSERT(m_bitlen == 0); + nSize = std::min(nSize, m_nSize - m_nBitPos); + + memcpy(pDest, m_pBuffer + m_nBitPos, nSize); + m_nBitPos += nSize; +} + +void CGolombBuffer::Reset() +{ + m_nBitPos = 0; + m_bitlen = 0; + m_bitbuff = 0; +} + +void CGolombBuffer::Reset(const BYTE* pNewBuffer, int nNewSize) +{ + if (m_bRemoveMpegEscapes) { + SAFE_DELETE_ARRAY(m_pTmpBuffer); + m_pTmpBuffer = DEBUG_NEW BYTE[nNewSize]; + + RemoveMpegEscapeCode(m_pTmpBuffer, pNewBuffer, nNewSize); + m_pBuffer = m_pTmpBuffer; + m_nSize = nNewSize; + } else { + m_pBuffer = pNewBuffer; + m_nSize = nNewSize; + } + + Reset(); +} + +void CGolombBuffer::SkipBytes(const int nCount) +{ + m_nBitPos += nCount; + m_bitlen = 0; + m_bitbuff = 0; +} + +void CGolombBuffer::Seek(const int nCount) +{ + m_nBitPos = nCount; + m_bitlen = 0; + m_bitbuff = 0; +} + +bool CGolombBuffer::NextMpegStartCode(BYTE& code) +{ + BitByteAlign(); + DWORD dw = DWORD_MAX; + do { + if (IsEOF()) { + return false; + } + dw = (dw << 8) | (BYTE)BitRead(8); + } while ((dw & 0xffffff00) != 0x00000100); + code = (BYTE)(dw & 0xff); + + return true; +} diff --git a/src/DSUtil/GolombBuffer.h b/src/DSUtil/GolombBuffer.h index 606a7b4d027..14158d860db 100644 --- a/src/DSUtil/GolombBuffer.h +++ b/src/DSUtil/GolombBuffer.h @@ -1,68 +1,68 @@ -/* - * (C) 2006-2018 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 . - * - */ - -#pragma once - -class CGolombBuffer -{ -public: - CGolombBuffer(const BYTE* pBuffer, int nSize, const bool bRemoveMpegEscapes = false); - ~CGolombBuffer(); - - UINT64 BitRead(const int nBits, const bool bPeek = false); - UINT64 UExpGolombRead(); - unsigned int UintGolombRead(); - INT64 SExpGolombRead(); - void BitByteAlign(); - - inline BYTE ReadByte() { return (BYTE)BitRead(8); } - inline SHORT ReadShort() { return (SHORT)BitRead(16); } - inline DWORD ReadDword() { return (DWORD)BitRead(32); } - inline SHORT ReadShortLE() { return _byteswap_ushort((SHORT)BitRead(16)); } - inline DWORD ReadDwordLE() { return _byteswap_ulong((DWORD)BitRead(32)); } - - void ReadBuffer(BYTE* pDest, int nSize); - - void Reset(); - void Reset(const BYTE* pNewBuffer, int nNewSize); - - void SetSize(const int nValue) { m_nSize = nValue; } - int GetSize() const { return m_nSize; } - int RemainingSize() const { return m_nSize - m_nBitPos; } - int BitsLeft() const { return 8 * RemainingSize() + m_bitlen; } - bool IsEOF() const { return m_nBitPos >= m_nSize; } - int GetPos() const; - const BYTE* GetBufferPos() const { return m_pBuffer + m_nBitPos; } - - void SkipBytes(const int nCount); - void Seek(const int nPos); - - bool NextMpegStartCode(BYTE& code); - -private : - const BYTE* m_pBuffer; - int m_nSize; - int m_nBitPos; - int m_bitlen; - INT64 m_bitbuff; - - BYTE* m_pTmpBuffer; - bool m_bRemoveMpegEscapes; -}; +/* + * (C) 2006-2018 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 . + * + */ + +#pragma once + +class CGolombBuffer +{ +public: + CGolombBuffer(const BYTE* pBuffer, int nSize, const bool bRemoveMpegEscapes = false); + ~CGolombBuffer(); + + UINT64 BitRead(const int nBits, const bool bPeek = false); + UINT64 UExpGolombRead(); + unsigned int UintGolombRead(); + INT64 SExpGolombRead(); + void BitByteAlign(); + + inline BYTE ReadByte() { return (BYTE)BitRead(8); } + inline SHORT ReadShort() { return (SHORT)BitRead(16); } + inline DWORD ReadDword() { return (DWORD)BitRead(32); } + inline SHORT ReadShortLE() { return _byteswap_ushort((SHORT)BitRead(16)); } + inline DWORD ReadDwordLE() { return _byteswap_ulong((DWORD)BitRead(32)); } + + void ReadBuffer(BYTE* pDest, int nSize); + + void Reset(); + void Reset(const BYTE* pNewBuffer, int nNewSize); + + void SetSize(const int nValue) { m_nSize = nValue; } + int GetSize() const { return m_nSize; } + int RemainingSize() const { return m_nSize - m_nBitPos; } + int BitsLeft() const { return 8 * RemainingSize() + m_bitlen; } + bool IsEOF() const { return m_nBitPos >= m_nSize; } + int GetPos() const; + const BYTE* GetBufferPos() const { return m_pBuffer + m_nBitPos; } + + void SkipBytes(const int nCount); + void Seek(const int nPos); + + bool NextMpegStartCode(BYTE& code); + +private : + const BYTE* m_pBuffer; + int m_nSize; + int m_nBitPos; + int m_bitlen; + INT64 m_bitbuff; + + BYTE* m_pTmpBuffer; + bool m_bRemoveMpegEscapes; +}; diff --git a/src/DSUtil/H264Nalu.cpp b/src/DSUtil/H264Nalu.cpp index d7d1482a934..02786343f88 100644 --- a/src/DSUtil/H264Nalu.cpp +++ b/src/DSUtil/H264Nalu.cpp @@ -1,110 +1,110 @@ -/* - * (C) 2008-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 . - * - */ - -#include "stdafx.h" -#include "H264Nalu.h" - -void CH264Nalu::SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize) -{ - m_pBuffer = pBuffer; - m_nSize = nSize; - m_nNALSize = nNALSize; - m_nCurPos = 0; - m_nNextRTP = 0; - - m_nNALStartPos = 0; - m_nNALDataPos = 0; - - // In AnnexB, the buffer is not guaranteed to start on a NAL boundary - if (nNALSize == 0 && nSize > 0) { - MoveToNextAnnexBStartcode(); - } -} - -bool CH264Nalu::MoveToNextAnnexBStartcode() -{ - if (m_nSize >= 4) { - size_t nBuffEnd = m_nSize - 4; - - for (size_t i = m_nCurPos; i <= nBuffEnd; i++) { - if ((*((DWORD*)(m_pBuffer + i)) & 0x00FFFFFF) == 0x00010000) { - // Found next AnnexB NAL - m_nCurPos = i; - return true; - } - } - } - - m_nCurPos = m_nSize; - return false; -} - -bool CH264Nalu::MoveToNextRTPStartcode() -{ - if (m_nNextRTP < m_nSize) { - m_nCurPos = m_nNextRTP; - return true; - } - - m_nCurPos = m_nSize; - return false; -} - -bool CH264Nalu::ReadNext() -{ - if (m_nCurPos >= m_nSize) { - return false; - } - - if ((m_nNALSize != 0) && (m_nCurPos == m_nNextRTP)) { - if (m_nCurPos + m_nNALSize >= m_nSize) { - return false; - } - // RTP Nalu type : (XX XX) XX XX NAL..., with XX XX XX XX or XX XX equal to NAL size - m_nNALStartPos = m_nCurPos; - m_nNALDataPos = m_nCurPos + m_nNALSize; - - // Read Length code from the buffer - unsigned nTemp = 0; - for (int i = 0; i < m_nNALSize; i++) { - nTemp = (nTemp << 8) + m_pBuffer[m_nCurPos++]; - } - - m_nNextRTP += nTemp + m_nNALSize; - MoveToNextRTPStartcode(); - } else { - // Remove trailing bits - while (m_pBuffer[m_nCurPos] == 0x00 && ((*((DWORD*)(m_pBuffer + m_nCurPos)) & 0x00FFFFFF) != 0x00010000)) { - m_nCurPos++; - } - - // AnnexB Nalu : 00 00 01 NAL... - m_nNALStartPos = m_nCurPos; - m_nCurPos += 3; - m_nNALDataPos = m_nCurPos; - MoveToNextAnnexBStartcode(); - } - - forbidden_bit = (m_pBuffer[m_nNALDataPos] >> 7) & 1; - nal_reference_idc = (m_pBuffer[m_nNALDataPos] >> 5) & 3; - nal_unit_type = (NALU_TYPE)(m_pBuffer[m_nNALDataPos] & 0x1f); - - return true; -} +/* + * (C) 2008-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 . + * + */ + +#include "stdafx.h" +#include "H264Nalu.h" + +void CH264Nalu::SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize) +{ + m_pBuffer = pBuffer; + m_nSize = nSize; + m_nNALSize = nNALSize; + m_nCurPos = 0; + m_nNextRTP = 0; + + m_nNALStartPos = 0; + m_nNALDataPos = 0; + + // In AnnexB, the buffer is not guaranteed to start on a NAL boundary + if (nNALSize == 0 && nSize > 0) { + MoveToNextAnnexBStartcode(); + } +} + +bool CH264Nalu::MoveToNextAnnexBStartcode() +{ + if (m_nSize >= 4) { + size_t nBuffEnd = m_nSize - 4; + + for (size_t i = m_nCurPos; i <= nBuffEnd; i++) { + if ((*((DWORD*)(m_pBuffer + i)) & 0x00FFFFFF) == 0x00010000) { + // Found next AnnexB NAL + m_nCurPos = i; + return true; + } + } + } + + m_nCurPos = m_nSize; + return false; +} + +bool CH264Nalu::MoveToNextRTPStartcode() +{ + if (m_nNextRTP < m_nSize) { + m_nCurPos = m_nNextRTP; + return true; + } + + m_nCurPos = m_nSize; + return false; +} + +bool CH264Nalu::ReadNext() +{ + if (m_nCurPos >= m_nSize) { + return false; + } + + if ((m_nNALSize != 0) && (m_nCurPos == m_nNextRTP)) { + if (m_nCurPos + m_nNALSize >= m_nSize) { + return false; + } + // RTP Nalu type : (XX XX) XX XX NAL..., with XX XX XX XX or XX XX equal to NAL size + m_nNALStartPos = m_nCurPos; + m_nNALDataPos = m_nCurPos + m_nNALSize; + + // Read Length code from the buffer + unsigned nTemp = 0; + for (int i = 0; i < m_nNALSize; i++) { + nTemp = (nTemp << 8) + m_pBuffer[m_nCurPos++]; + } + + m_nNextRTP += nTemp + m_nNALSize; + MoveToNextRTPStartcode(); + } else { + // Remove trailing bits + while (m_pBuffer[m_nCurPos] == 0x00 && ((*((DWORD*)(m_pBuffer + m_nCurPos)) & 0x00FFFFFF) != 0x00010000)) { + m_nCurPos++; + } + + // AnnexB Nalu : 00 00 01 NAL... + m_nNALStartPos = m_nCurPos; + m_nCurPos += 3; + m_nNALDataPos = m_nCurPos; + MoveToNextAnnexBStartcode(); + } + + forbidden_bit = (m_pBuffer[m_nNALDataPos] >> 7) & 1; + nal_reference_idc = (m_pBuffer[m_nNALDataPos] >> 5) & 3; + nal_unit_type = (NALU_TYPE)(m_pBuffer[m_nNALDataPos] & 0x1f); + + return true; +} diff --git a/src/DSUtil/H264Nalu.h b/src/DSUtil/H264Nalu.h index 0582166d2bf..dc660ad91ed 100644 --- a/src/DSUtil/H264Nalu.h +++ b/src/DSUtil/H264Nalu.h @@ -1,82 +1,82 @@ -/* - * (C) 2008-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 . - * - */ - -#pragma once - -enum NALU_TYPE { - NALU_TYPE_SLICE = 1, - NALU_TYPE_DPA = 2, - NALU_TYPE_DPB = 3, - NALU_TYPE_DPC = 4, - NALU_TYPE_IDR = 5, - NALU_TYPE_SEI = 6, - NALU_TYPE_SPS = 7, - NALU_TYPE_PPS = 8, - NALU_TYPE_AUD = 9, - NALU_TYPE_EOSEQ = 10, - NALU_TYPE_EOSTREAM = 11, - NALU_TYPE_FILL = 12 -}; - - -class CH264Nalu -{ -private: - int forbidden_bit; //! should be always FALSE - int nal_reference_idc; //! NALU_PRIORITY_xxxx - NALU_TYPE nal_unit_type; //! NALU_TYPE_xxxx - - size_t m_nNALStartPos; //! NALU start (including startcode / size) - size_t m_nNALDataPos; //! Useful part - - const BYTE* m_pBuffer; - size_t m_nCurPos; - size_t m_nNextRTP; - size_t m_nSize; - int m_nNALSize; - - bool MoveToNextAnnexBStartcode(); - bool MoveToNextRTPStartcode(); - -public: - CH264Nalu() : - forbidden_bit(0), - nal_reference_idc(0), - nal_unit_type() { - SetBuffer(nullptr, 0, 0); - } - - NALU_TYPE GetType() const { return nal_unit_type; }; - bool IsRefFrame() const { return (nal_reference_idc != 0); }; - - size_t GetDataLength() const { return m_nCurPos - m_nNALDataPos; }; - const BYTE* GetDataBuffer() { return m_pBuffer + m_nNALDataPos; }; - size_t GetRoundedDataLength() const { - size_t nSize = m_nCurPos - m_nNALDataPos; - return nSize + 128 - (nSize % 128); - } - - size_t GetLength() const { return m_nCurPos - m_nNALStartPos; }; - const BYTE* GetNALBuffer() { return m_pBuffer + m_nNALStartPos; }; - bool IsEOF() const { return m_nCurPos >= m_nSize; }; - - void SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize); - bool ReadNext(); -}; +/* + * (C) 2008-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 . + * + */ + +#pragma once + +enum NALU_TYPE { + NALU_TYPE_SLICE = 1, + NALU_TYPE_DPA = 2, + NALU_TYPE_DPB = 3, + NALU_TYPE_DPC = 4, + NALU_TYPE_IDR = 5, + NALU_TYPE_SEI = 6, + NALU_TYPE_SPS = 7, + NALU_TYPE_PPS = 8, + NALU_TYPE_AUD = 9, + NALU_TYPE_EOSEQ = 10, + NALU_TYPE_EOSTREAM = 11, + NALU_TYPE_FILL = 12 +}; + + +class CH264Nalu +{ +private: + int forbidden_bit; //! should be always FALSE + int nal_reference_idc; //! NALU_PRIORITY_xxxx + NALU_TYPE nal_unit_type; //! NALU_TYPE_xxxx + + size_t m_nNALStartPos; //! NALU start (including startcode / size) + size_t m_nNALDataPos; //! Useful part + + const BYTE* m_pBuffer; + size_t m_nCurPos; + size_t m_nNextRTP; + size_t m_nSize; + int m_nNALSize; + + bool MoveToNextAnnexBStartcode(); + bool MoveToNextRTPStartcode(); + +public: + CH264Nalu() : + forbidden_bit(0), + nal_reference_idc(0), + nal_unit_type() { + SetBuffer(nullptr, 0, 0); + } + + NALU_TYPE GetType() const { return nal_unit_type; }; + bool IsRefFrame() const { return (nal_reference_idc != 0); }; + + size_t GetDataLength() const { return m_nCurPos - m_nNALDataPos; }; + const BYTE* GetDataBuffer() { return m_pBuffer + m_nNALDataPos; }; + size_t GetRoundedDataLength() const { + size_t nSize = m_nCurPos - m_nNALDataPos; + return nSize + 128 - (nSize % 128); + } + + size_t GetLength() const { return m_nCurPos - m_nNALStartPos; }; + const BYTE* GetNALBuffer() { return m_pBuffer + m_nNALStartPos; }; + bool IsEOF() const { return m_nCurPos >= m_nSize; }; + + void SetBuffer(const BYTE* pBuffer, size_t nSize, int nNALSize); + bool ReadNext(); +}; diff --git a/src/DSUtil/HdmvClipInfo.cpp b/src/DSUtil/HdmvClipInfo.cpp index 026f63f4aef..85a6dc355c7 100644 --- a/src/DSUtil/HdmvClipInfo.cpp +++ b/src/DSUtil/HdmvClipInfo.cpp @@ -1,821 +1,821 @@ -/* - * (C) 2008-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include "HdmvClipInfo.h" -#include "DSUtil.h" -#include "ISOLang.h" -#include "tinyxml2/library/tinyxml2.h" -#include -#include "FileHandle.h" -#include "ISOLang.h" -using namespace tinyxml2; - -CHdmvClipInfo::CHdmvClipInfo() - : SequenceInfo_start_address(0) - , ProgramInfo_start_address(0) - , m_hFile(INVALID_HANDLE_VALUE) - , m_bIsHdmv(false) -{ -} - -CHdmvClipInfo::~CHdmvClipInfo() -{ - CloseFile(S_OK); -} - -HRESULT CHdmvClipInfo::CloseFile(HRESULT hr) -{ - if (m_hFile != INVALID_HANDLE_VALUE) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - } - return hr; -} - -DWORD CHdmvClipInfo::ReadDword() -{ - return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte(); -} - -short CHdmvClipInfo::ReadShort() -{ - return ReadByte() << 8 | ReadByte(); -} - -BYTE CHdmvClipInfo::ReadByte() -{ - BYTE bVal; - DWORD dwRead; - VERIFY(ReadFile(m_hFile, &bVal, sizeof(bVal), &dwRead, nullptr)); - - return bVal; -} - -BOOL CHdmvClipInfo::Skip(LONGLONG nLen) { - LARGE_INTEGER newPos = {}; - newPos.QuadPart = nLen; - return SetFilePointerEx(m_hFile, newPos, nullptr, FILE_CURRENT); -} - -BOOL CHdmvClipInfo::GetPos(LONGLONG& Pos) { - LARGE_INTEGER curPos = {}; - const BOOL bRet = SetFilePointerEx(m_hFile, curPos, &curPos, FILE_CURRENT); - Pos = curPos.QuadPart; - - return bRet; -} -BOOL CHdmvClipInfo::SetPos(LONGLONG Pos, DWORD dwMoveMethod/* = FILE_BEGIN*/) { - LARGE_INTEGER newPos = {}; - newPos.QuadPart = Pos; - return SetFilePointerEx(m_hFile, newPos, nullptr, dwMoveMethod); -} - -HRESULT CHdmvClipInfo::ReadLang(Stream& s) { - ReadBuffer((BYTE*)s.m_LanguageCode, 3); - s.m_LCID = ISOLang::ISO6392ToLcid(s.m_LanguageCode); - - return S_OK; -} - -void CHdmvClipInfo::ReadBuffer(BYTE* pBuff, DWORD nLen) -{ - DWORD dwRead; - VERIFY(ReadFile(m_hFile, pBuff, nLen, &dwRead, nullptr)); -} - -HRESULT CHdmvClipInfo::ReadProgramInfo() -{ - BYTE number_of_program_sequences; - LARGE_INTEGER Pos; - - m_Streams.RemoveAll(); - Pos.QuadPart = ProgramInfo_start_address; - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - - ReadDword(); //length - ReadByte(); //reserved_for_word_align - number_of_program_sequences = (BYTE)ReadByte(); - int iStream = 0; - for (size_t i = 0; i < number_of_program_sequences; i++) { - ReadDword(); //SPN_program_sequence_start - ReadShort(); //program_map_PID - BYTE number_of_streams_in_ps = (BYTE)ReadByte(); //number_of_streams_in_ps - ReadByte(); //reserved_for_future_use - - for (size_t stream_index = 0; stream_index < number_of_streams_in_ps; stream_index++) { - m_Streams.SetCount(iStream + 1); - m_Streams[iStream].m_PID = ReadShort(); // stream_PID - - // == StreamCodingInfo - Pos.QuadPart = 0; - SetFilePointerEx(m_hFile, Pos, &Pos, FILE_CURRENT); - Pos.QuadPart += ReadByte() + 1; // length - m_Streams[iStream].m_Type = (PES_STREAM_TYPE)ReadByte(); - - switch (m_Streams[iStream].m_Type) { - case VIDEO_STREAM_MPEG1: - case VIDEO_STREAM_MPEG2: - case VIDEO_STREAM_H264: - case VIDEO_STREAM_VC1: - case VIDEO_STREAM_HEVC: { - UINT8 Temp = ReadByte(); - BDVM_VideoFormat VideoFormat = (BDVM_VideoFormat)(Temp >> 4); - BDVM_FrameRate FrameRate = (BDVM_FrameRate)(Temp & 0xf); - Temp = ReadByte(); - BDVM_AspectRatio AspectRatio = (BDVM_AspectRatio)(Temp >> 4); - - m_Streams[iStream].m_VideoFormat = VideoFormat; - m_Streams[iStream].m_FrameRate = FrameRate; - m_Streams[iStream].m_AspectRatio = AspectRatio; - } - break; - case AUDIO_STREAM_MPEG1: - case AUDIO_STREAM_MPEG2: - case AUDIO_STREAM_LPCM: - case AUDIO_STREAM_AC3: - case AUDIO_STREAM_DTS: - case AUDIO_STREAM_AC3_TRUE_HD: - case AUDIO_STREAM_AC3_PLUS: - case AUDIO_STREAM_DTS_HD: - case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: - case SECONDARY_AUDIO_AC3_PLUS: - case SECONDARY_AUDIO_DTS_HD: { - UINT8 Temp = ReadByte(); - BDVM_ChannelLayout ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); - BDVM_SampleRate SampleRate = (BDVM_SampleRate)(Temp & 0xF); - - ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); - m_Streams[iStream].m_LanguageCode[3] = '\0'; - m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); - m_Streams[iStream].m_ChannelLayout = ChannelLayout; - m_Streams[iStream].m_SampleRate = SampleRate; - } - break; - case PRESENTATION_GRAPHICS_STREAM: - case INTERACTIVE_GRAPHICS_STREAM: { - ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); - m_Streams[iStream].m_LanguageCode[3] = '\0'; - m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); - } - break; - case SUBTITLE_STREAM: { - ReadByte(); // Should this really be here? - ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); - m_Streams[iStream].m_LanguageCode[3] = '\0'; - m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); - } - break; - default: - break; - } - - iStream++; - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - } - } - return S_OK; -} - -HRESULT CHdmvClipInfo::ReadInfo(LPCTSTR strFile) -{ - m_bIsHdmv = false; - m_hFile = CreateFile(strFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); - - if (m_hFile != INVALID_HANDLE_VALUE) { - BYTE Buff[100]; - ReadBuffer(Buff, 4); - if (memcmp(Buff, "HDMV", 4)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - ReadBuffer(Buff, 4); - if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - SequenceInfo_start_address = ReadDword(); - ProgramInfo_start_address = ReadDword(); - - ReadProgramInfo(); - - m_bIsHdmv = true; - - return CloseFile(S_OK); - } - - return AmHresultFromWin32(GetLastError()); -} - -CHdmvClipInfo::Stream* CHdmvClipInfo::FindStream(short wPID) -{ - size_t nStreams = m_Streams.GetCount(); - for (size_t i = 0; i < nStreams; i++) { - if (m_Streams[i].m_PID == wPID) { - return &m_Streams[i]; - } - } - - return nullptr; -} - -LPCTSTR CHdmvClipInfo::Stream::Format() -{ - switch (m_Type) { - case VIDEO_STREAM_MPEG1: - return _T("Mpeg1"); - case VIDEO_STREAM_MPEG2: - return _T("Mpeg2"); - case VIDEO_STREAM_H264: - return _T("H264"); - case VIDEO_STREAM_VC1: - return _T("VC1"); - case VIDEO_STREAM_HEVC: - return _T("HEVC"); - case AUDIO_STREAM_MPEG1: - return _T("MPEG1"); - case AUDIO_STREAM_MPEG2: - return _T("MPEG2"); - case AUDIO_STREAM_LPCM: - return _T("LPCM"); - case AUDIO_STREAM_AC3: - return _T("AC3"); - case AUDIO_STREAM_DTS: - return _T("DTS"); - case AUDIO_STREAM_AC3_TRUE_HD: - return _T("MLP"); - case AUDIO_STREAM_AC3_PLUS: - return _T("DD+"); - case AUDIO_STREAM_DTS_HD: - return _T("DTS-HD"); - case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: - return _T("DTS-HD XLL"); - case SECONDARY_AUDIO_AC3_PLUS: - return _T("Sec DD+"); - case SECONDARY_AUDIO_DTS_HD: - return _T("Sec DTS-HD"); - case PRESENTATION_GRAPHICS_STREAM: - return _T("PG"); - case INTERACTIVE_GRAPHICS_STREAM: - return _T("IG"); - case SUBTITLE_STREAM: - return _T("Text"); - default: - return _T("Unknown"); - } -} - -HRESULT CHdmvClipInfo::ReadStreamInfo() { - BYTE len = ReadByte(); - LONGLONG Pos = 0; - GetPos(Pos); - - Stream s; - const BYTE stream_type = ReadByte(); - switch (stream_type) { - case 1: - s.m_PID = ReadShort(); - break; - case 2: - case 4: - ReadShort(); - s.m_PID = ReadShort(); - break; - case 3: - ReadByte(); - s.m_PID = ReadShort(); - break; - } - - if (!SetPos(Pos + len)) { - return E_FAIL; - } - - len = ReadByte(); - GetPos(Pos); - - for (const auto& stream : stn.m_Streams) { - if (s.m_PID == stream.m_PID) { - return SetPos(Pos + len) ? S_OK : E_FAIL; - } - } - - s.m_Type = (PES_STREAM_TYPE)ReadByte(); - switch (s.m_Type) { - case VIDEO_STREAM_MPEG1: - case VIDEO_STREAM_MPEG2: - case VIDEO_STREAM_H264: - case MVC_H264: - case VIDEO_STREAM_HEVC: - case VIDEO_STREAM_VC1: { - const BYTE Temp = ReadByte(); - s.m_VideoFormat = (BDVM_VideoFormat)(Temp >> 4); - s.m_FrameRate = (BDVM_FrameRate)(Temp & 0xf); - } - break; - case AUDIO_STREAM_MPEG1: - case AUDIO_STREAM_MPEG2: - case AUDIO_STREAM_LPCM: - case AUDIO_STREAM_AC3: - case AUDIO_STREAM_DTS: - case AUDIO_STREAM_AC3_TRUE_HD: - case AUDIO_STREAM_AC3_PLUS: - case AUDIO_STREAM_DTS_HD: - case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: - case SECONDARY_AUDIO_AC3_PLUS: - case SECONDARY_AUDIO_DTS_HD: { - const BYTE Temp = ReadByte(); - s.m_ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); - s.m_SampleRate = (BDVM_SampleRate)(Temp & 0xF); - - ReadLang(s); - } - break; - case PRESENTATION_GRAPHICS_STREAM: - case INTERACTIVE_GRAPHICS_STREAM: - ReadLang(s); - break; - case SUBTITLE_STREAM: - ReadByte(); // bd_char_code - ReadLang(s); - break; - } - - stn.m_Streams.emplace_back(s); - - return SetPos(Pos + len) ? S_OK : E_FAIL; -} - -HRESULT CHdmvClipInfo::ReadSTNInfo() { - ReadShort(); // length - ReadShort(); // reserved_for_future_use - - stn.num_video = ReadByte(); // number of Primary Video Streams - stn.num_audio = ReadByte(); // number of Primary Audio Streams - stn.num_pg = ReadByte(); // number of Presentation Graphic Streams - stn.num_ig = ReadByte(); // number of Interactive Graphic Streams - stn.num_secondary_audio = ReadByte(); // number of Secondary Audio Streams - stn.num_secondary_video = ReadByte(); // number of Secondary Video Streams - stn.num_pip_pg = ReadByte(); // number of Presentation Graphic Streams - - Skip(5); // reserved_for_future_use - - for (BYTE i = 0; i < stn.num_video; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - } - - for (BYTE i = 0; i < stn.num_audio; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - } - - for (BYTE i = 0; i < (stn.num_pg + stn.num_pip_pg); i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - } - - for (BYTE i = 0; i < stn.num_ig; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - } - - for (BYTE i = 0; i < stn.num_secondary_audio; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - - // Secondary Audio Extra Attributes - const BYTE num_secondary_audio_extra = ReadByte(); - ReadByte(); - if (num_secondary_audio_extra) { - Skip(num_secondary_audio_extra); - if (num_secondary_audio_extra % 2) { - ReadByte(); - } - } - } - - for (BYTE i = 0; i < stn.num_secondary_video; i++) { - if (FAILED(ReadStreamInfo())) { - return E_FAIL; - } - - // Secondary Video Extra Attributes - const BYTE num_secondary_video_extra = ReadByte(); - ReadByte(); - if (num_secondary_video_extra) { - Skip(num_secondary_video_extra); - if (num_secondary_video_extra % 2) { - ReadByte(); - } - } - - const BYTE num_pip_pg_extra = ReadByte(); - ReadByte(); - if (num_pip_pg_extra) { - Skip(num_pip_pg_extra); - if (num_pip_pg_extra % 2) { - ReadByte(); - } - } - } - - return S_OK; -} - -HRESULT CHdmvClipInfo::ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, HdmvPlaylist& Playlist) -{ - CPath Path(strPlaylistFile); - rtDuration = 0; - - // Get BDMV folder - Path.RemoveFileSpec(); - Path.RemoveFileSpec(); - - m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); - - if (m_hFile != INVALID_HANDLE_VALUE) { - BYTE Buff[100]; - bool bDuplicate = false; - ReadBuffer(Buff, 4); - if (memcmp(Buff, "MPLS", 4)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - ReadBuffer(Buff, 4); - if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - LARGE_INTEGER size = {}; - GetFileSizeEx(m_hFile, &size); - Playlist.m_mpls_size = size.QuadPart; - - LARGE_INTEGER Pos; - unsigned short nPlaylistItems; - - Pos.QuadPart = ReadDword(); // PlayList_start_address - ReadDword(); // PlayListMark_start_address - - // PlayList() - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - ReadDword(); // length - ReadShort(); // reserved_for_future_use - nPlaylistItems = ReadShort(); // number_of_PlayItems - ReadShort(); // number_of_SubPaths - - Pos.QuadPart += 10; - for (size_t i = 0; i < nPlaylistItems; i++) { - DWORD dwTemp; - PlaylistItem Item; - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - Pos.QuadPart += ReadShort() + 2; - ReadBuffer(Buff, 5); - Item.m_strFileName.Format(_T("%s\\STREAM\\%c%c%c%c%c.M2TS"), static_cast(Path), Buff[0], Buff[1], Buff[2], Buff[3], Buff[4]); - - ReadBuffer(Buff, 4); - if (memcmp(Buff, "M2TS", 4)) { - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - ReadBuffer(Buff, 3); - const BYTE is_multi_angle = (Buff[1] >> 4) & 0x1; - - dwTemp = ReadDword(); - Item.m_rtIn = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits! - - dwTemp = ReadDword(); - Item.m_rtOut = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits! - - rtDuration += (Item.m_rtOut - Item.m_rtIn); - - Skip(8); // mpls uo - ReadByte(); - ReadByte(); // still mode - ReadShort(); // still time - BYTE angle_count = 1; - if (is_multi_angle) { - angle_count = ReadByte(); - if (angle_count < 1) { - angle_count = 1; - } - ReadByte(); - } - for (BYTE j = 1; j < angle_count; j++) { - Skip(9); // M2TS file name - ReadByte(); // stc_id - } - - // stn - ReadSTNInfo(); - - if (Playlist.contains(Item)) { - bDuplicate = true; - } - Playlist.emplace_back(Item); - - //TRACE(_T("File : %s, Duration : %s, Total duration : %s\n"), strTemp, ReftimeToString (rtOut - rtIn), ReftimeToString (rtDuration)); - } - - CloseFile(S_OK); - if (!stn.m_Streams.empty()) { - for (const auto& stream : stn.m_Streams) { - switch (stream.m_VideoFormat) { - case BDVM_VideoFormat_480i: - case BDVM_VideoFormat_480p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 480u); - break; - case BDVM_VideoFormat_576i: - case BDVM_VideoFormat_576p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 576u); - break; - case BDVM_VideoFormat_720p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 720u); - break; - case BDVM_VideoFormat_1080i: - case BDVM_VideoFormat_1080p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 1080u); - break; - case BDVM_VideoFormat_2160p: - Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 2160u); - break; - default: - break; - } - } - } - return bDuplicate ? S_FALSE : S_OK; - } - - return AmHresultFromWin32(GetLastError()); -} - -HRESULT CHdmvClipInfo::ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters) -{ - CPath Path(strPlaylistFile); - - // Get BDMV folder - Path.RemoveFileSpec(); - Path.RemoveFileSpec(); - - m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); - - if (m_hFile != INVALID_HANDLE_VALUE) { - REFERENCE_TIME* rtOffset = DEBUG_NEW REFERENCE_TIME[PlaylistItems.GetCount()]; - REFERENCE_TIME rtSum = 0; - int nIndex = 0; - BYTE Buff[100]; - - POSITION pos = PlaylistItems.GetHeadPosition(); - while (pos) { - CHdmvClipInfo::PlaylistItem& PI = PlaylistItems.GetNext(pos); - - rtOffset[nIndex] = rtSum - PI.m_rtIn; - rtSum = rtSum + PI.Duration(); - nIndex++; - } - - ReadBuffer(Buff, 4); - if (memcmp(Buff, "MPLS", 4)) { - SAFE_DELETE_ARRAY(rtOffset); - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - ReadBuffer(Buff, 4); - if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { - SAFE_DELETE_ARRAY(rtOffset); - return CloseFile(VFW_E_INVALID_FILE_FORMAT); - } - - LARGE_INTEGER Pos; - unsigned short nMarkCount; - - ReadDword(); // PlayList_start_address - Pos.QuadPart = ReadDword(); // PlayListMark_start_address - - // PlayListMark() - SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); - ReadDword(); // length - nMarkCount = ReadShort(); // number_of_PlayList_marks - for (size_t i = 0; i < nMarkCount; i++) { - PlaylistChapter Chapter; - - ReadByte(); // reserved_for_future_use - Chapter.m_nMarkType = (PlaylistMarkType)ReadByte(); // mark_type - Chapter.m_nPlayItemId = ReadShort(); // ref_to_PlayItem_id - Chapter.m_rtTimestamp = 20000i64 * ReadDword() / 90 + rtOffset[Chapter.m_nPlayItemId]; // mark_time_stamp - Chapter.m_nEntryPID = ReadShort(); // entry_ES_PID - Chapter.m_rtDuration = 20000i64 * ReadDword() / 90; // duration - - Chapters.AddTail(Chapter); - - //TRACE(_T("Chapter %d : %s\n"), i, ReftimeToString(Chapter.m_rtTimestamp)); - } - - CloseFile(S_OK); - SAFE_DELETE_ARRAY(rtOffset); - return S_OK; - } - - return AmHresultFromWin32(GetLastError()); -} - -#define MIN_LIMIT 3 - -HRESULT CHdmvClipInfo::FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, HdmvPlaylist& MainPlaylist, HdmvPlaylist& MPLSPlaylists) -{ - HRESULT hr = E_FAIL; - - CString strPath(strFolder); - CString strFilter; - - MPLSPlaylists.clear(); - - HdmvPlaylist Playlist; - WIN32_FIND_DATA fd; - ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); - - strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); - strPath.Replace(_T("\\STREAM\\"), _T("\\")); - strPath = AddSlash(strPath); - strPath += _T("BDMV\\"); - strFilter.Format(_T("%sPLAYLIST\\*.mpls"), strPath.GetString()); - - HANDLE hFind = FindFirstFile(strFilter, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - std::vector PlaylistArray; - - REFERENCE_TIME rtMax = 0; - REFERENCE_TIME rtCurrent; - CString strCurrentPlaylist; - __int64 mpls_size_max = 0; - unsigned max_video_res = 0u; - do { - strCurrentPlaylist.Format(_T("%sPLAYLIST\\%s"), strPath.GetString(), fd.cFileName); - Playlist.clear(); - - // Main movie shouldn't have duplicate M2TS filename... - if (ReadPlaylist(strCurrentPlaylist, rtCurrent, Playlist) == S_OK) { - if ((rtCurrent > rtMax && Playlist.m_max_video_res >= max_video_res) - || (rtCurrent == rtMax && Playlist.m_mpls_size > mpls_size_max) - || ((rtCurrent < rtMax && rtCurrent >= rtMax / 2) && Playlist.m_max_video_res > max_video_res)) { - rtMax = rtCurrent; - mpls_size_max = Playlist.m_mpls_size; - max_video_res = Playlist.m_max_video_res; - strPlaylistFile = strCurrentPlaylist; - MainPlaylist.clear(); - MainPlaylist.insert(std::end(MainPlaylist), std::begin(Playlist), std::end(Playlist)); - hr = S_OK; - } - - if (rtCurrent >= (REFERENCE_TIME)MIN_LIMIT * 600000000) { - // Search duplicate playlists ... - bool duplicate = false; - if (!MPLSPlaylists.empty()) { - for (const auto& item : PlaylistArray) { - if (item.size() != Playlist.size()) { - continue; - } - - duplicate = true; - for (size_t i = 0; i < item.size() && duplicate; i++) { - if (item[i] == Playlist[i]) { - continue; - } - - duplicate = false; - } - - if (duplicate) { - duplicate = (item.m_mpls_size == Playlist.m_mpls_size); - } - } - } - if (duplicate) { - continue; - } - - PlaylistItem Item; - Item.m_strFileName = strCurrentPlaylist; - Item.m_rtIn = 0; - Item.m_rtOut = rtCurrent; - MPLSPlaylists.emplace_back(Item); - PlaylistArray.emplace_back(Playlist); - } - - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - - if (MPLSPlaylists.size() > 1) { - std::sort(MPLSPlaylists.begin(), MPLSPlaylists.end(), std::greater()); - } - - return hr; -} - -//convert UTF8 const char to wstring. -std::wstring CW2WS(const char* str) -{ - int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - std::wstring wstrTo( size_needed, 0 ); - MultiByteToWideChar(CP_UTF8, 0, str, -1, &wstrTo[0], size_needed); - return wstrTo; -} - -bool CHdmvClipInfo::ReadMeta(LPCTSTR strFolder, CAtlList& meta) -{ - bool re = false; - CString strPath(strFolder); - CString strFilter; - - meta.RemoveAll(); - - strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); - strPath.Replace(_T("\\STREAM\\"), _T("\\")); - strPath += _T("\\BDMV\\"); - strPath.Replace(_T("\\\\"), _T("\\")); - strPath.Replace(_T("\\\\"), _T("\\")); - strFilter.Format(_T("%sMETA\\DL\\bdmt_*.xml"), strPath.GetString()); - - WIN32_FIND_DATA fd; - ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); - - HANDLE hFind = FindFirstFile(strFilter, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - std::wstring TempFileName(fd.cFileName); - std::match_results mr; - CHdmvClipInfo::BDMVMeta Item; - tinyxml2::XMLDocument doc; - CStringW FileName(fd.cFileName); - CStringW FilePath; - - bool matched = std::regex_search(TempFileName, mr, std::wregex(L"^bdmt_(\\w+).xml$")); - - if (matched) { - Item.langcode = mr[1].str().c_str(); - } - else { - Item.langcode = L""; - } - - FilePath.Format(L"%sMETA\\DL\\", strPath.GetString()); - FilePath += FileName; - FILE* f; - if (!_wfopen_s(&f, FilePath.GetString(), L"rb")) { - doc.LoadFile(f); - fclose(f); - - XMLElement* rootNote(doc.RootElement()); - if (rootNote && !strcmp(rootNote->Name(), "disclib")) { - XMLElement* discinfo = rootNote->FirstChildElement("di:discinfo"); - if (discinfo != NULL) { - XMLElement* title = discinfo->FirstChildElement("di:title"); - if (title != NULL) { - XMLElement* name = title->FirstChildElement("di:name"); - if (name != NULL) { - Item.title = CW2WS(name->GetText()).c_str(); - } - } - } - } - } - - if (!Item.title.IsEmpty()) { - meta.AddTail(Item); - re = true; - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - - return re; -} +/* + * (C) 2008-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include "HdmvClipInfo.h" +#include "DSUtil.h" +#include "ISOLang.h" +#include "tinyxml2/library/tinyxml2.h" +#include +#include "FileHandle.h" +#include "ISOLang.h" +using namespace tinyxml2; + +CHdmvClipInfo::CHdmvClipInfo() + : SequenceInfo_start_address(0) + , ProgramInfo_start_address(0) + , m_hFile(INVALID_HANDLE_VALUE) + , m_bIsHdmv(false) +{ +} + +CHdmvClipInfo::~CHdmvClipInfo() +{ + CloseFile(S_OK); +} + +HRESULT CHdmvClipInfo::CloseFile(HRESULT hr) +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } + return hr; +} + +DWORD CHdmvClipInfo::ReadDword() +{ + return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte(); +} + +short CHdmvClipInfo::ReadShort() +{ + return ReadByte() << 8 | ReadByte(); +} + +BYTE CHdmvClipInfo::ReadByte() +{ + BYTE bVal; + DWORD dwRead; + VERIFY(ReadFile(m_hFile, &bVal, sizeof(bVal), &dwRead, nullptr)); + + return bVal; +} + +BOOL CHdmvClipInfo::Skip(LONGLONG nLen) { + LARGE_INTEGER newPos = {}; + newPos.QuadPart = nLen; + return SetFilePointerEx(m_hFile, newPos, nullptr, FILE_CURRENT); +} + +BOOL CHdmvClipInfo::GetPos(LONGLONG& Pos) { + LARGE_INTEGER curPos = {}; + const BOOL bRet = SetFilePointerEx(m_hFile, curPos, &curPos, FILE_CURRENT); + Pos = curPos.QuadPart; + + return bRet; +} +BOOL CHdmvClipInfo::SetPos(LONGLONG Pos, DWORD dwMoveMethod/* = FILE_BEGIN*/) { + LARGE_INTEGER newPos = {}; + newPos.QuadPart = Pos; + return SetFilePointerEx(m_hFile, newPos, nullptr, dwMoveMethod); +} + +HRESULT CHdmvClipInfo::ReadLang(Stream& s) { + ReadBuffer((BYTE*)s.m_LanguageCode, 3); + s.m_LCID = ISOLang::ISO6392ToLcid(s.m_LanguageCode); + + return S_OK; +} + +void CHdmvClipInfo::ReadBuffer(BYTE* pBuff, DWORD nLen) +{ + DWORD dwRead; + VERIFY(ReadFile(m_hFile, pBuff, nLen, &dwRead, nullptr)); +} + +HRESULT CHdmvClipInfo::ReadProgramInfo() +{ + BYTE number_of_program_sequences; + LARGE_INTEGER Pos; + + m_Streams.RemoveAll(); + Pos.QuadPart = ProgramInfo_start_address; + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + + ReadDword(); //length + ReadByte(); //reserved_for_word_align + number_of_program_sequences = (BYTE)ReadByte(); + int iStream = 0; + for (size_t i = 0; i < number_of_program_sequences; i++) { + ReadDword(); //SPN_program_sequence_start + ReadShort(); //program_map_PID + BYTE number_of_streams_in_ps = (BYTE)ReadByte(); //number_of_streams_in_ps + ReadByte(); //reserved_for_future_use + + for (size_t stream_index = 0; stream_index < number_of_streams_in_ps; stream_index++) { + m_Streams.SetCount(iStream + 1); + m_Streams[iStream].m_PID = ReadShort(); // stream_PID + + // == StreamCodingInfo + Pos.QuadPart = 0; + SetFilePointerEx(m_hFile, Pos, &Pos, FILE_CURRENT); + Pos.QuadPart += ReadByte() + 1; // length + m_Streams[iStream].m_Type = (PES_STREAM_TYPE)ReadByte(); + + switch (m_Streams[iStream].m_Type) { + case VIDEO_STREAM_MPEG1: + case VIDEO_STREAM_MPEG2: + case VIDEO_STREAM_H264: + case VIDEO_STREAM_VC1: + case VIDEO_STREAM_HEVC: { + UINT8 Temp = ReadByte(); + BDVM_VideoFormat VideoFormat = (BDVM_VideoFormat)(Temp >> 4); + BDVM_FrameRate FrameRate = (BDVM_FrameRate)(Temp & 0xf); + Temp = ReadByte(); + BDVM_AspectRatio AspectRatio = (BDVM_AspectRatio)(Temp >> 4); + + m_Streams[iStream].m_VideoFormat = VideoFormat; + m_Streams[iStream].m_FrameRate = FrameRate; + m_Streams[iStream].m_AspectRatio = AspectRatio; + } + break; + case AUDIO_STREAM_MPEG1: + case AUDIO_STREAM_MPEG2: + case AUDIO_STREAM_LPCM: + case AUDIO_STREAM_AC3: + case AUDIO_STREAM_DTS: + case AUDIO_STREAM_AC3_TRUE_HD: + case AUDIO_STREAM_AC3_PLUS: + case AUDIO_STREAM_DTS_HD: + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + case SECONDARY_AUDIO_AC3_PLUS: + case SECONDARY_AUDIO_DTS_HD: { + UINT8 Temp = ReadByte(); + BDVM_ChannelLayout ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); + BDVM_SampleRate SampleRate = (BDVM_SampleRate)(Temp & 0xF); + + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LanguageCode[3] = '\0'; + m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); + m_Streams[iStream].m_ChannelLayout = ChannelLayout; + m_Streams[iStream].m_SampleRate = SampleRate; + } + break; + case PRESENTATION_GRAPHICS_STREAM: + case INTERACTIVE_GRAPHICS_STREAM: { + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LanguageCode[3] = '\0'; + m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); + } + break; + case SUBTITLE_STREAM: { + ReadByte(); // Should this really be here? + ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3); + m_Streams[iStream].m_LanguageCode[3] = '\0'; + m_Streams[iStream].m_LCID = ISOLang::ISO6392ToLcid(m_Streams[iStream].m_LanguageCode); + } + break; + default: + break; + } + + iStream++; + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + } + } + return S_OK; +} + +HRESULT CHdmvClipInfo::ReadInfo(LPCTSTR strFile) +{ + m_bIsHdmv = false; + m_hFile = CreateFile(strFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); + + if (m_hFile != INVALID_HANDLE_VALUE) { + BYTE Buff[100]; + ReadBuffer(Buff, 4); + if (memcmp(Buff, "HDMV", 4)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + SequenceInfo_start_address = ReadDword(); + ProgramInfo_start_address = ReadDword(); + + ReadProgramInfo(); + + m_bIsHdmv = true; + + return CloseFile(S_OK); + } + + return AmHresultFromWin32(GetLastError()); +} + +CHdmvClipInfo::Stream* CHdmvClipInfo::FindStream(short wPID) +{ + size_t nStreams = m_Streams.GetCount(); + for (size_t i = 0; i < nStreams; i++) { + if (m_Streams[i].m_PID == wPID) { + return &m_Streams[i]; + } + } + + return nullptr; +} + +LPCTSTR CHdmvClipInfo::Stream::Format() +{ + switch (m_Type) { + case VIDEO_STREAM_MPEG1: + return _T("Mpeg1"); + case VIDEO_STREAM_MPEG2: + return _T("Mpeg2"); + case VIDEO_STREAM_H264: + return _T("H264"); + case VIDEO_STREAM_VC1: + return _T("VC1"); + case VIDEO_STREAM_HEVC: + return _T("HEVC"); + case AUDIO_STREAM_MPEG1: + return _T("MPEG1"); + case AUDIO_STREAM_MPEG2: + return _T("MPEG2"); + case AUDIO_STREAM_LPCM: + return _T("LPCM"); + case AUDIO_STREAM_AC3: + return _T("AC3"); + case AUDIO_STREAM_DTS: + return _T("DTS"); + case AUDIO_STREAM_AC3_TRUE_HD: + return _T("MLP"); + case AUDIO_STREAM_AC3_PLUS: + return _T("DD+"); + case AUDIO_STREAM_DTS_HD: + return _T("DTS-HD"); + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + return _T("DTS-HD XLL"); + case SECONDARY_AUDIO_AC3_PLUS: + return _T("Sec DD+"); + case SECONDARY_AUDIO_DTS_HD: + return _T("Sec DTS-HD"); + case PRESENTATION_GRAPHICS_STREAM: + return _T("PG"); + case INTERACTIVE_GRAPHICS_STREAM: + return _T("IG"); + case SUBTITLE_STREAM: + return _T("Text"); + default: + return _T("Unknown"); + } +} + +HRESULT CHdmvClipInfo::ReadStreamInfo() { + BYTE len = ReadByte(); + LONGLONG Pos = 0; + GetPos(Pos); + + Stream s; + const BYTE stream_type = ReadByte(); + switch (stream_type) { + case 1: + s.m_PID = ReadShort(); + break; + case 2: + case 4: + ReadShort(); + s.m_PID = ReadShort(); + break; + case 3: + ReadByte(); + s.m_PID = ReadShort(); + break; + } + + if (!SetPos(Pos + len)) { + return E_FAIL; + } + + len = ReadByte(); + GetPos(Pos); + + for (const auto& stream : stn.m_Streams) { + if (s.m_PID == stream.m_PID) { + return SetPos(Pos + len) ? S_OK : E_FAIL; + } + } + + s.m_Type = (PES_STREAM_TYPE)ReadByte(); + switch (s.m_Type) { + case VIDEO_STREAM_MPEG1: + case VIDEO_STREAM_MPEG2: + case VIDEO_STREAM_H264: + case MVC_H264: + case VIDEO_STREAM_HEVC: + case VIDEO_STREAM_VC1: { + const BYTE Temp = ReadByte(); + s.m_VideoFormat = (BDVM_VideoFormat)(Temp >> 4); + s.m_FrameRate = (BDVM_FrameRate)(Temp & 0xf); + } + break; + case AUDIO_STREAM_MPEG1: + case AUDIO_STREAM_MPEG2: + case AUDIO_STREAM_LPCM: + case AUDIO_STREAM_AC3: + case AUDIO_STREAM_DTS: + case AUDIO_STREAM_AC3_TRUE_HD: + case AUDIO_STREAM_AC3_PLUS: + case AUDIO_STREAM_DTS_HD: + case AUDIO_STREAM_DTS_HD_MASTER_AUDIO: + case SECONDARY_AUDIO_AC3_PLUS: + case SECONDARY_AUDIO_DTS_HD: { + const BYTE Temp = ReadByte(); + s.m_ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4); + s.m_SampleRate = (BDVM_SampleRate)(Temp & 0xF); + + ReadLang(s); + } + break; + case PRESENTATION_GRAPHICS_STREAM: + case INTERACTIVE_GRAPHICS_STREAM: + ReadLang(s); + break; + case SUBTITLE_STREAM: + ReadByte(); // bd_char_code + ReadLang(s); + break; + } + + stn.m_Streams.emplace_back(s); + + return SetPos(Pos + len) ? S_OK : E_FAIL; +} + +HRESULT CHdmvClipInfo::ReadSTNInfo() { + ReadShort(); // length + ReadShort(); // reserved_for_future_use + + stn.num_video = ReadByte(); // number of Primary Video Streams + stn.num_audio = ReadByte(); // number of Primary Audio Streams + stn.num_pg = ReadByte(); // number of Presentation Graphic Streams + stn.num_ig = ReadByte(); // number of Interactive Graphic Streams + stn.num_secondary_audio = ReadByte(); // number of Secondary Audio Streams + stn.num_secondary_video = ReadByte(); // number of Secondary Video Streams + stn.num_pip_pg = ReadByte(); // number of Presentation Graphic Streams + + Skip(5); // reserved_for_future_use + + for (BYTE i = 0; i < stn.num_video; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + } + + for (BYTE i = 0; i < stn.num_audio; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + } + + for (BYTE i = 0; i < (stn.num_pg + stn.num_pip_pg); i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + } + + for (BYTE i = 0; i < stn.num_ig; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + } + + for (BYTE i = 0; i < stn.num_secondary_audio; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + + // Secondary Audio Extra Attributes + const BYTE num_secondary_audio_extra = ReadByte(); + ReadByte(); + if (num_secondary_audio_extra) { + Skip(num_secondary_audio_extra); + if (num_secondary_audio_extra % 2) { + ReadByte(); + } + } + } + + for (BYTE i = 0; i < stn.num_secondary_video; i++) { + if (FAILED(ReadStreamInfo())) { + return E_FAIL; + } + + // Secondary Video Extra Attributes + const BYTE num_secondary_video_extra = ReadByte(); + ReadByte(); + if (num_secondary_video_extra) { + Skip(num_secondary_video_extra); + if (num_secondary_video_extra % 2) { + ReadByte(); + } + } + + const BYTE num_pip_pg_extra = ReadByte(); + ReadByte(); + if (num_pip_pg_extra) { + Skip(num_pip_pg_extra); + if (num_pip_pg_extra % 2) { + ReadByte(); + } + } + } + + return S_OK; +} + +HRESULT CHdmvClipInfo::ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, HdmvPlaylist& Playlist) +{ + CPath Path(strPlaylistFile); + rtDuration = 0; + + // Get BDMV folder + Path.RemoveFileSpec(); + Path.RemoveFileSpec(); + + m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); + + if (m_hFile != INVALID_HANDLE_VALUE) { + BYTE Buff[100]; + bool bDuplicate = false; + ReadBuffer(Buff, 4); + if (memcmp(Buff, "MPLS", 4)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + LARGE_INTEGER size = {}; + GetFileSizeEx(m_hFile, &size); + Playlist.m_mpls_size = size.QuadPart; + + LARGE_INTEGER Pos; + unsigned short nPlaylistItems; + + Pos.QuadPart = ReadDword(); // PlayList_start_address + ReadDword(); // PlayListMark_start_address + + // PlayList() + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + ReadDword(); // length + ReadShort(); // reserved_for_future_use + nPlaylistItems = ReadShort(); // number_of_PlayItems + ReadShort(); // number_of_SubPaths + + Pos.QuadPart += 10; + for (size_t i = 0; i < nPlaylistItems; i++) { + DWORD dwTemp; + PlaylistItem Item; + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + Pos.QuadPart += ReadShort() + 2; + ReadBuffer(Buff, 5); + Item.m_strFileName.Format(_T("%s\\STREAM\\%c%c%c%c%c.M2TS"), static_cast(Path), Buff[0], Buff[1], Buff[2], Buff[3], Buff[4]); + + ReadBuffer(Buff, 4); + if (memcmp(Buff, "M2TS", 4)) { + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + ReadBuffer(Buff, 3); + const BYTE is_multi_angle = (Buff[1] >> 4) & 0x1; + + dwTemp = ReadDword(); + Item.m_rtIn = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits! + + dwTemp = ReadDword(); + Item.m_rtOut = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits! + + rtDuration += (Item.m_rtOut - Item.m_rtIn); + + Skip(8); // mpls uo + ReadByte(); + ReadByte(); // still mode + ReadShort(); // still time + BYTE angle_count = 1; + if (is_multi_angle) { + angle_count = ReadByte(); + if (angle_count < 1) { + angle_count = 1; + } + ReadByte(); + } + for (BYTE j = 1; j < angle_count; j++) { + Skip(9); // M2TS file name + ReadByte(); // stc_id + } + + // stn + ReadSTNInfo(); + + if (Playlist.contains(Item)) { + bDuplicate = true; + } + Playlist.emplace_back(Item); + + //TRACE(_T("File : %s, Duration : %s, Total duration : %s\n"), strTemp, ReftimeToString (rtOut - rtIn), ReftimeToString (rtDuration)); + } + + CloseFile(S_OK); + if (!stn.m_Streams.empty()) { + for (const auto& stream : stn.m_Streams) { + switch (stream.m_VideoFormat) { + case BDVM_VideoFormat_480i: + case BDVM_VideoFormat_480p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 480u); + break; + case BDVM_VideoFormat_576i: + case BDVM_VideoFormat_576p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 576u); + break; + case BDVM_VideoFormat_720p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 720u); + break; + case BDVM_VideoFormat_1080i: + case BDVM_VideoFormat_1080p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 1080u); + break; + case BDVM_VideoFormat_2160p: + Playlist.m_max_video_res = std::max(Playlist.m_max_video_res, 2160u); + break; + default: + break; + } + } + } + return bDuplicate ? S_FALSE : S_OK; + } + + return AmHresultFromWin32(GetLastError()); +} + +HRESULT CHdmvClipInfo::ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters) +{ + CPath Path(strPlaylistFile); + + // Get BDMV folder + Path.RemoveFileSpec(); + Path.RemoveFileSpec(); + + m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, nullptr); + + if (m_hFile != INVALID_HANDLE_VALUE) { + REFERENCE_TIME* rtOffset = DEBUG_NEW REFERENCE_TIME[PlaylistItems.GetCount()]; + REFERENCE_TIME rtSum = 0; + int nIndex = 0; + BYTE Buff[100]; + + POSITION pos = PlaylistItems.GetHeadPosition(); + while (pos) { + CHdmvClipInfo::PlaylistItem& PI = PlaylistItems.GetNext(pos); + + rtOffset[nIndex] = rtSum - PI.m_rtIn; + rtSum = rtSum + PI.Duration(); + nIndex++; + } + + ReadBuffer(Buff, 4); + if (memcmp(Buff, "MPLS", 4)) { + SAFE_DELETE_ARRAY(rtOffset); + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + ReadBuffer(Buff, 4); + if ((memcmp(Buff, "0300", 4) != 0) && (memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) { + SAFE_DELETE_ARRAY(rtOffset); + return CloseFile(VFW_E_INVALID_FILE_FORMAT); + } + + LARGE_INTEGER Pos; + unsigned short nMarkCount; + + ReadDword(); // PlayList_start_address + Pos.QuadPart = ReadDword(); // PlayListMark_start_address + + // PlayListMark() + SetFilePointerEx(m_hFile, Pos, nullptr, FILE_BEGIN); + ReadDword(); // length + nMarkCount = ReadShort(); // number_of_PlayList_marks + for (size_t i = 0; i < nMarkCount; i++) { + PlaylistChapter Chapter; + + ReadByte(); // reserved_for_future_use + Chapter.m_nMarkType = (PlaylistMarkType)ReadByte(); // mark_type + Chapter.m_nPlayItemId = ReadShort(); // ref_to_PlayItem_id + Chapter.m_rtTimestamp = 20000i64 * ReadDword() / 90 + rtOffset[Chapter.m_nPlayItemId]; // mark_time_stamp + Chapter.m_nEntryPID = ReadShort(); // entry_ES_PID + Chapter.m_rtDuration = 20000i64 * ReadDword() / 90; // duration + + Chapters.AddTail(Chapter); + + //TRACE(_T("Chapter %d : %s\n"), i, ReftimeToString(Chapter.m_rtTimestamp)); + } + + CloseFile(S_OK); + SAFE_DELETE_ARRAY(rtOffset); + return S_OK; + } + + return AmHresultFromWin32(GetLastError()); +} + +#define MIN_LIMIT 3 + +HRESULT CHdmvClipInfo::FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, HdmvPlaylist& MainPlaylist, HdmvPlaylist& MPLSPlaylists) +{ + HRESULT hr = E_FAIL; + + CString strPath(strFolder); + CString strFilter; + + MPLSPlaylists.clear(); + + HdmvPlaylist Playlist; + WIN32_FIND_DATA fd; + ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); + + strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); + strPath.Replace(_T("\\STREAM\\"), _T("\\")); + strPath = AddSlash(strPath); + strPath += _T("BDMV\\"); + strFilter.Format(_T("%sPLAYLIST\\*.mpls"), strPath.GetString()); + + HANDLE hFind = FindFirstFile(strFilter, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + std::vector PlaylistArray; + + REFERENCE_TIME rtMax = 0; + REFERENCE_TIME rtCurrent; + CString strCurrentPlaylist; + __int64 mpls_size_max = 0; + unsigned max_video_res = 0u; + do { + strCurrentPlaylist.Format(_T("%sPLAYLIST\\%s"), strPath.GetString(), fd.cFileName); + Playlist.clear(); + + // Main movie shouldn't have duplicate M2TS filename... + if (ReadPlaylist(strCurrentPlaylist, rtCurrent, Playlist) == S_OK) { + if ((rtCurrent > rtMax && Playlist.m_max_video_res >= max_video_res) + || (rtCurrent == rtMax && Playlist.m_mpls_size > mpls_size_max) + || ((rtCurrent < rtMax && rtCurrent >= rtMax / 2) && Playlist.m_max_video_res > max_video_res)) { + rtMax = rtCurrent; + mpls_size_max = Playlist.m_mpls_size; + max_video_res = Playlist.m_max_video_res; + strPlaylistFile = strCurrentPlaylist; + MainPlaylist.clear(); + MainPlaylist.insert(std::end(MainPlaylist), std::begin(Playlist), std::end(Playlist)); + hr = S_OK; + } + + if (rtCurrent >= (REFERENCE_TIME)MIN_LIMIT * 600000000) { + // Search duplicate playlists ... + bool duplicate = false; + if (!MPLSPlaylists.empty()) { + for (const auto& item : PlaylistArray) { + if (item.size() != Playlist.size()) { + continue; + } + + duplicate = true; + for (size_t i = 0; i < item.size() && duplicate; i++) { + if (item[i] == Playlist[i]) { + continue; + } + + duplicate = false; + } + + if (duplicate) { + duplicate = (item.m_mpls_size == Playlist.m_mpls_size); + } + } + } + if (duplicate) { + continue; + } + + PlaylistItem Item; + Item.m_strFileName = strCurrentPlaylist; + Item.m_rtIn = 0; + Item.m_rtOut = rtCurrent; + MPLSPlaylists.emplace_back(Item); + PlaylistArray.emplace_back(Playlist); + } + + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + + if (MPLSPlaylists.size() > 1) { + std::sort(MPLSPlaylists.begin(), MPLSPlaylists.end(), std::greater()); + } + + return hr; +} + +//convert UTF8 const char to wstring. +std::wstring CW2WS(const char* str) +{ + int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + std::wstring wstrTo( size_needed, 0 ); + MultiByteToWideChar(CP_UTF8, 0, str, -1, &wstrTo[0], size_needed); + return wstrTo; +} + +bool CHdmvClipInfo::ReadMeta(LPCTSTR strFolder, CAtlList& meta) +{ + bool re = false; + CString strPath(strFolder); + CString strFilter; + + meta.RemoveAll(); + + strPath.Replace(_T("\\PLAYLIST\\"), _T("\\")); + strPath.Replace(_T("\\STREAM\\"), _T("\\")); + strPath += _T("\\BDMV\\"); + strPath.Replace(_T("\\\\"), _T("\\")); + strPath.Replace(_T("\\\\"), _T("\\")); + strFilter.Format(_T("%sMETA\\DL\\bdmt_*.xml"), strPath.GetString()); + + WIN32_FIND_DATA fd; + ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); + + HANDLE hFind = FindFirstFile(strFilter, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + std::wstring TempFileName(fd.cFileName); + std::match_results mr; + CHdmvClipInfo::BDMVMeta Item; + tinyxml2::XMLDocument doc; + CStringW FileName(fd.cFileName); + CStringW FilePath; + + bool matched = std::regex_search(TempFileName, mr, std::wregex(L"^bdmt_(\\w+).xml$")); + + if (matched) { + Item.langcode = mr[1].str().c_str(); + } + else { + Item.langcode = L""; + } + + FilePath.Format(L"%sMETA\\DL\\", strPath.GetString()); + FilePath += FileName; + FILE* f; + if (!_wfopen_s(&f, FilePath.GetString(), L"rb")) { + doc.LoadFile(f); + fclose(f); + + XMLElement* rootNote(doc.RootElement()); + if (rootNote && !strcmp(rootNote->Name(), "disclib")) { + XMLElement* discinfo = rootNote->FirstChildElement("di:discinfo"); + if (discinfo != NULL) { + XMLElement* title = discinfo->FirstChildElement("di:title"); + if (title != NULL) { + XMLElement* name = title->FirstChildElement("di:name"); + if (name != NULL) { + Item.title = CW2WS(name->GetText()).c_str(); + } + } + } + } + } + + if (!Item.title.IsEmpty()) { + meta.AddTail(Item); + re = true; + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + + return re; +} diff --git a/src/DSUtil/HdmvClipInfo.h b/src/DSUtil/HdmvClipInfo.h index 678a1dba94d..75dc822cc0a 100644 --- a/src/DSUtil/HdmvClipInfo.h +++ b/src/DSUtil/HdmvClipInfo.h @@ -1,189 +1,189 @@ -/* - * (C) 2008-2013, 2016 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 . - * - */ - -#pragma once - -#include "Mpeg2Def.h" -#include -#include - -enum BDVM_VideoFormat { - BDVM_VideoFormat_Unknown = 0, - BDVM_VideoFormat_480i = 1, - BDVM_VideoFormat_576i = 2, - BDVM_VideoFormat_480p = 3, - BDVM_VideoFormat_1080i = 4, - BDVM_VideoFormat_720p = 5, - BDVM_VideoFormat_1080p = 6, - BDVM_VideoFormat_576p = 7, - BDVM_VideoFormat_2160p = 8, -}; - -enum BDVM_FrameRate { - BDVM_FrameRate_Unknown = 0, - BDVM_FrameRate_23_976 = 1, - BDVM_FrameRate_24 = 2, - BDVM_FrameRate_25 = 3, - BDVM_FrameRate_29_97 = 4, - BDVM_FrameRate_50 = 6, - BDVM_FrameRate_59_94 = 7 -}; - -enum BDVM_AspectRatio { - BDVM_AspectRatio_Unknown = 0, - BDVM_AspectRatio_4_3 = 2, - BDVM_AspectRatio_16_9 = 3, - BDVM_AspectRatio_2_21 = 4 -}; - -enum BDVM_ChannelLayout { - BDVM_ChannelLayout_Unknown = 0, - BDVM_ChannelLayout_MONO = 1, - BDVM_ChannelLayout_STEREO = 3, - BDVM_ChannelLayout_MULTI = 6, - BDVM_ChannelLayout_COMBO = 12 -}; - -enum BDVM_SampleRate { - BDVM_SampleRate_Unknown = 0, - BDVM_SampleRate_48 = 1, - BDVM_SampleRate_96 = 4, - BDVM_SampleRate_192 = 5, - BDVM_SampleRate_48_192 = 12, - BDVM_SampleRate_48_96 = 14 -}; - -class CHdmvClipInfo -{ -public: - - struct Stream { - Stream() { - ZeroMemory(this, sizeof(*this)); - } - short m_PID = 0; - PES_STREAM_TYPE m_Type = INVALID; - char m_LanguageCode[4] = {0}; - LCID m_LCID = 0; - - // Valid for video types - BDVM_VideoFormat m_VideoFormat = BDVM_VideoFormat_Unknown; - BDVM_FrameRate m_FrameRate = BDVM_FrameRate_Unknown; - BDVM_AspectRatio m_AspectRatio = BDVM_AspectRatio_Unknown; - // Valid for audio types - BDVM_ChannelLayout m_ChannelLayout = BDVM_ChannelLayout_Unknown; - BDVM_SampleRate m_SampleRate = BDVM_SampleRate_Unknown; - - LPCTSTR Format(); - }; - - struct PlaylistItem { - CString m_strFileName; - REFERENCE_TIME m_rtIn = 0; - REFERENCE_TIME m_rtOut = 0; - - REFERENCE_TIME Duration() const { return m_rtOut - m_rtIn; } - - bool operator == (const PlaylistItem& pi) const { - return pi.m_strFileName == m_strFileName; - } - bool operator >(const PlaylistItem& pi) const { - return Duration() > pi.Duration(); - } - }; - class HdmvPlaylist : public std::vector { - public: - __int64 m_mpls_size = 0; - unsigned m_max_video_res = 0u; - bool contains(PlaylistItem& pli) { return std::find(begin(), end(), pli) != end(); } - }; - - enum PlaylistMarkType { - Reserved = 0x00, - EntryMark = 0x01, - LinkPoint = 0x02 - }; - - struct PlaylistChapter { - short m_nPlayItemId = 0; - PlaylistMarkType m_nMarkType = Reserved; - REFERENCE_TIME m_rtTimestamp = 0; - short m_nEntryPID = 0; - REFERENCE_TIME m_rtDuration = 0; - }; - - struct BDMVMeta { - CString langcode; - CString title; - }; - - CHdmvClipInfo(); - ~CHdmvClipInfo(); - - HRESULT ReadInfo(LPCTSTR strFile); - Stream* FindStream(short wPID); - bool IsHdmv() const { return m_bIsHdmv; }; - size_t GetStreamNumber() { return m_Streams.GetCount(); }; - Stream* GetStreamByIndex(size_t nIndex) { return (nIndex < m_Streams.GetCount()) ? &m_Streams[nIndex] : nullptr; }; - - HRESULT FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, HdmvPlaylist& MainPlaylist, HdmvPlaylist& MPLSPlaylists); - HRESULT ReadStreamInfo(); - HRESULT ReadSTNInfo(); - HRESULT ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, HdmvPlaylist& Playlist); - HRESULT ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters); - bool ReadMeta(LPCTSTR strFolder, CAtlList& meta); - -private: - DWORD SequenceInfo_start_address; - DWORD ProgramInfo_start_address; - - HANDLE m_hFile; - - CAtlArray m_Streams; - typedef std::vector Streams; - struct { - BYTE num_video = 0; - BYTE num_audio = 0; - BYTE num_pg = 0; - BYTE num_ig = 0; - BYTE num_secondary_audio = 0; - BYTE num_secondary_video = 0; - BYTE num_pip_pg = 0; - - Streams m_Streams; - } stn; - - - bool m_bIsHdmv; - - DWORD ReadDword(); - short ReadShort(); - BYTE ReadByte(); - - BOOL Skip(LONGLONG nLen); - BOOL GetPos(LONGLONG& Pos); - BOOL SetPos(LONGLONG Pos, DWORD dwMoveMethod = FILE_BEGIN); - - void ReadBuffer(BYTE* pBuff, DWORD nLen); - - HRESULT ReadLang(Stream& s); - HRESULT ReadProgramInfo(); - HRESULT CloseFile(HRESULT hr); -}; +/* + * (C) 2008-2013, 2016 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 . + * + */ + +#pragma once + +#include "Mpeg2Def.h" +#include +#include + +enum BDVM_VideoFormat { + BDVM_VideoFormat_Unknown = 0, + BDVM_VideoFormat_480i = 1, + BDVM_VideoFormat_576i = 2, + BDVM_VideoFormat_480p = 3, + BDVM_VideoFormat_1080i = 4, + BDVM_VideoFormat_720p = 5, + BDVM_VideoFormat_1080p = 6, + BDVM_VideoFormat_576p = 7, + BDVM_VideoFormat_2160p = 8, +}; + +enum BDVM_FrameRate { + BDVM_FrameRate_Unknown = 0, + BDVM_FrameRate_23_976 = 1, + BDVM_FrameRate_24 = 2, + BDVM_FrameRate_25 = 3, + BDVM_FrameRate_29_97 = 4, + BDVM_FrameRate_50 = 6, + BDVM_FrameRate_59_94 = 7 +}; + +enum BDVM_AspectRatio { + BDVM_AspectRatio_Unknown = 0, + BDVM_AspectRatio_4_3 = 2, + BDVM_AspectRatio_16_9 = 3, + BDVM_AspectRatio_2_21 = 4 +}; + +enum BDVM_ChannelLayout { + BDVM_ChannelLayout_Unknown = 0, + BDVM_ChannelLayout_MONO = 1, + BDVM_ChannelLayout_STEREO = 3, + BDVM_ChannelLayout_MULTI = 6, + BDVM_ChannelLayout_COMBO = 12 +}; + +enum BDVM_SampleRate { + BDVM_SampleRate_Unknown = 0, + BDVM_SampleRate_48 = 1, + BDVM_SampleRate_96 = 4, + BDVM_SampleRate_192 = 5, + BDVM_SampleRate_48_192 = 12, + BDVM_SampleRate_48_96 = 14 +}; + +class CHdmvClipInfo +{ +public: + + struct Stream { + Stream() { + ZeroMemory(this, sizeof(*this)); + } + short m_PID = 0; + PES_STREAM_TYPE m_Type = INVALID; + char m_LanguageCode[4] = {0}; + LCID m_LCID = 0; + + // Valid for video types + BDVM_VideoFormat m_VideoFormat = BDVM_VideoFormat_Unknown; + BDVM_FrameRate m_FrameRate = BDVM_FrameRate_Unknown; + BDVM_AspectRatio m_AspectRatio = BDVM_AspectRatio_Unknown; + // Valid for audio types + BDVM_ChannelLayout m_ChannelLayout = BDVM_ChannelLayout_Unknown; + BDVM_SampleRate m_SampleRate = BDVM_SampleRate_Unknown; + + LPCTSTR Format(); + }; + + struct PlaylistItem { + CString m_strFileName; + REFERENCE_TIME m_rtIn = 0; + REFERENCE_TIME m_rtOut = 0; + + REFERENCE_TIME Duration() const { return m_rtOut - m_rtIn; } + + bool operator == (const PlaylistItem& pi) const { + return pi.m_strFileName == m_strFileName; + } + bool operator >(const PlaylistItem& pi) const { + return Duration() > pi.Duration(); + } + }; + class HdmvPlaylist : public std::vector { + public: + __int64 m_mpls_size = 0; + unsigned m_max_video_res = 0u; + bool contains(PlaylistItem& pli) { return std::find(begin(), end(), pli) != end(); } + }; + + enum PlaylistMarkType { + Reserved = 0x00, + EntryMark = 0x01, + LinkPoint = 0x02 + }; + + struct PlaylistChapter { + short m_nPlayItemId = 0; + PlaylistMarkType m_nMarkType = Reserved; + REFERENCE_TIME m_rtTimestamp = 0; + short m_nEntryPID = 0; + REFERENCE_TIME m_rtDuration = 0; + }; + + struct BDMVMeta { + CString langcode; + CString title; + }; + + CHdmvClipInfo(); + ~CHdmvClipInfo(); + + HRESULT ReadInfo(LPCTSTR strFile); + Stream* FindStream(short wPID); + bool IsHdmv() const { return m_bIsHdmv; }; + size_t GetStreamNumber() { return m_Streams.GetCount(); }; + Stream* GetStreamByIndex(size_t nIndex) { return (nIndex < m_Streams.GetCount()) ? &m_Streams[nIndex] : nullptr; }; + + HRESULT FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, HdmvPlaylist& MainPlaylist, HdmvPlaylist& MPLSPlaylists); + HRESULT ReadStreamInfo(); + HRESULT ReadSTNInfo(); + HRESULT ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, HdmvPlaylist& Playlist); + HRESULT ReadChapters(CString strPlaylistFile, CAtlList& PlaylistItems, CAtlList& Chapters); + bool ReadMeta(LPCTSTR strFolder, CAtlList& meta); + +private: + DWORD SequenceInfo_start_address; + DWORD ProgramInfo_start_address; + + HANDLE m_hFile; + + CAtlArray m_Streams; + typedef std::vector Streams; + struct { + BYTE num_video = 0; + BYTE num_audio = 0; + BYTE num_pg = 0; + BYTE num_ig = 0; + BYTE num_secondary_audio = 0; + BYTE num_secondary_video = 0; + BYTE num_pip_pg = 0; + + Streams m_Streams; + } stn; + + + bool m_bIsHdmv; + + DWORD ReadDword(); + short ReadShort(); + BYTE ReadByte(); + + BOOL Skip(LONGLONG nLen); + BOOL GetPos(LONGLONG& Pos); + BOOL SetPos(LONGLONG Pos, DWORD dwMoveMethod = FILE_BEGIN); + + void ReadBuffer(BYTE* pBuff, DWORD nLen); + + HRESULT ReadLang(Stream& s); + HRESULT ReadProgramInfo(); + HRESULT CloseFile(HRESULT hr); +}; diff --git a/src/DSUtil/MediaTypeEx.cpp b/src/DSUtil/MediaTypeEx.cpp index 16111001fa0..2c8e8555397 100644 --- a/src/DSUtil/MediaTypeEx.cpp +++ b/src/DSUtil/MediaTypeEx.cpp @@ -1,751 +1,751 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "DSUtil.h" -#include "MediaTypeEx.h" - -#include -#include "moreuuids.h" - -#pragma pack(push, 1) -struct DOLBYAC3WAVEFORMAT { - WAVEFORMATEX Format; - BYTE bBigEndian; - BYTE bsid; - BYTE lfeon; - BYTE copyrightb; - BYTE nAuxBitsCode; // Aux bits per frame -}; -#pragma pack(pop) - -CMediaTypeEx::CMediaTypeEx() -{ -} - -CMediaTypeEx::~CMediaTypeEx() -{ -} - -CString CMediaTypeEx::ToString(IPin* pPin) -{ - CString packing, type, codec, dim, rate, dur; - - // TODO - - if (majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { - packing = _T("Encrypted MPEG2 Pack"); - } else if (majortype == MEDIATYPE_MPEG2_PACK) { - packing = _T("MPEG2 Pack"); - } else if (majortype == MEDIATYPE_MPEG2_PES) { - packing = _T("MPEG2 PES"); - } - - if (majortype == MEDIATYPE_Video || subtype == MEDIASUBTYPE_MPEG2_VIDEO) { - type = _T("Video"); - - BITMAPINFOHEADER bih; - bool fBIH = ExtractBIH(this, &bih); - - int w, h, arx, ary; - bool fDim = ExtractDim(this, w, h, arx, ary); - - if (fBIH) { - codec = GetVideoCodecName(subtype, bih.biCompression); - } - - if (codec.IsEmpty()) { - if (formattype == FORMAT_MPEGVideo) { - codec = _T("MPEG1 Video"); - } else if (formattype == FORMAT_MPEG2_VIDEO) { - codec = _T("MPEG2 Video"); - } else if (formattype == FORMAT_DiracVideoInfo) { - codec = _T("Dirac Video"); - } - } - - if (fDim) { - dim.Format(_T("%dx%d"), w, h); - if (w * ary != h * arx) { - dim.AppendFormat(_T(" (%d:%d)"), arx, ary); - } - } - - if (formattype == FORMAT_VideoInfo || formattype == FORMAT_MPEGVideo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pbFormat; - if (vih->AvgTimePerFrame) { - rate.Format(_T("%0.3f"), 10000000.0f / vih->AvgTimePerFrame); - rate.TrimRight(_T('0')); // remove trailing zeros - rate.TrimRight(_T('.')); // remove the trailing dot - rate += _T("fps "); - } - if (vih->dwBitRate) { - rate.AppendFormat(_T("%ukbps"), vih->dwBitRate / 1000); - } - } else if (formattype == FORMAT_VideoInfo2 || formattype == FORMAT_MPEG2_VIDEO || formattype == FORMAT_DiracVideoInfo) { - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pbFormat; - if (vih->AvgTimePerFrame) { - rate.Format(_T("%0.3f"), 10000000.0f / vih->AvgTimePerFrame); - rate.TrimRight(_T('0')); // remove trailing zeros - rate.TrimRight(_T('.')); // remove the trailing dot - rate += _T("fps "); - } - if (vih->dwBitRate) { - rate.AppendFormat(_T("%ukbps"), vih->dwBitRate / 1000); - } - } - - rate.TrimRight(); - - if (subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { - type = _T("Subtitle"); - codec = _T("DVD Subpicture"); - } - } else if (majortype == MEDIATYPE_Audio || subtype == MEDIASUBTYPE_DOLBY_AC3) { - type = _T("Audio"); - - if (formattype == FORMAT_WaveFormatEx) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)Format(); - - if (wfe->wFormatTag/* > WAVE_FORMAT_PCM && wfe->wFormatTag < WAVE_FORMAT_EXTENSIBLE - && wfe->wFormatTag != WAVE_FORMAT_IEEE_FLOAT*/ - || subtype != GUID_NULL) { - codec = GetAudioCodecName(subtype, wfe->wFormatTag); - dim.Format(_T("%uHz"), wfe->nSamplesPerSec); - if (wfe->nChannels == 1) { - dim += _T(" mono"); - } else if (wfe->nChannels == 2) { - dim += _T(" stereo"); - } else { - dim.AppendFormat(_T(" %uch"), wfe->nChannels); - } - if (wfe->nAvgBytesPerSec) { - rate.Format(_T("%ukbps"), wfe->nAvgBytesPerSec * 8 / 1000); - } - } - } else if (formattype == FORMAT_VorbisFormat) { - VORBISFORMAT* vf = (VORBISFORMAT*)Format(); - - codec = GetAudioCodecName(subtype, 0); - dim.Format(_T("%luHz"), vf->nSamplesPerSec); - if (vf->nChannels == 1) { - dim += _T(" mono"); - } else if (vf->nChannels == 2) { - dim += _T(" stereo"); - } else { - dim.AppendFormat(_T(" %uch"), vf->nChannels); - } - if (vf->nAvgBitsPerSec) { - rate.Format(_T("%lukbps"), vf->nAvgBitsPerSec / 1000); - } - } else if (formattype == FORMAT_VorbisFormat2) { - VORBISFORMAT2* vf = (VORBISFORMAT2*)Format(); - - codec = GetAudioCodecName(subtype, 0); - dim.Format(_T("%luHz"), vf->SamplesPerSec); - if (vf->Channels == 1) { - dim += _T(" mono"); - } else if (vf->Channels == 2) { - dim += _T(" stereo"); - } else { - dim.AppendFormat(_T(" %luch"), vf->Channels); - } - } - } else if (majortype == MEDIATYPE_Text) { - type = _T("Text"); - } else if (majortype == MEDIATYPE_Subtitle || subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { - type = _T("Subtitle"); - codec = GetSubtitleCodecName(subtype); - } else { - type = _T("Unknown"); - } - - if (CComQIPtr pMS = pPin) { - REFERENCE_TIME rtDur = 0; - if (SUCCEEDED(pMS->GetDuration(&rtDur)) && rtDur) { - rtDur /= 10000000; - int s = rtDur % 60; - rtDur /= 60; - int m = rtDur % 60; - rtDur /= 60; - int h = (int)rtDur; - if (h) { - dur.Format(_T("%d:%02d:%02d"), h, m, s); - } else if (m) { - dur.Format(_T("%02d:%02d"), m, s); - } else if (s) { - dur.Format(_T("%ds"), s); - } - } - } - - CString str; - if (!codec.IsEmpty()) { - str += codec + _T(" "); - } - if (!dim.IsEmpty()) { - str += dim + _T(" "); - } - if (!rate.IsEmpty()) { - str += rate + _T(" "); - } - if (!dur.IsEmpty()) { - str += dur + _T(" "); - } - str.Trim(_T(" ,")); - - if (!str.IsEmpty()) { - str = type + _T(": ") + str; - } else { - str = type; - } - - return str; -} - -CString CMediaTypeEx::GetVideoCodecName(const GUID& subtype, DWORD biCompression) -{ - CString str = _T(""); - - static CAtlMap names; - - if (names.IsEmpty()) { - names['WMV1'] = _T("Windows Media Video 7"); - names['WMV2'] = _T("Windows Media Video 8"); - names['WMV3'] = _T("Windows Media Video 9"); - names['DIV3'] = _T("DivX 3"); - names['MP43'] = _T("MSMPEG4v3"); - names['MP42'] = _T("MSMPEG4v2"); - names['MP41'] = _T("MSMPEG4v1"); - names['DX50'] = _T("DivX 5"); - names['DIVX'] = _T("DivX 6"); - names['XVID'] = _T("Xvid"); - names['MP4V'] = _T("MPEG4 Video"); - names['AVC1'] = _T("MPEG4 Video (H264)"); - names['H264'] = _T("MPEG4 Video (H264)"); - names['RV10'] = _T("RealVideo 1"); - names['RV20'] = _T("RealVideo 2"); - names['RV30'] = _T("RealVideo 3"); - names['RV40'] = _T("RealVideo 4"); - names['FLV1'] = _T("Flash Video 1"); - names['FLV4'] = _T("Flash Video 4"); - names['VP50'] = _T("On2 VP5"); - names['VP60'] = _T("On2 VP6"); - names['SVQ3'] = _T("SVQ3"); - names['SVQ1'] = _T("SVQ1"); - names['H263'] = _T("H263"); - // names[''] = _T(""); - } - - if (biCompression) { - BYTE* b = (BYTE*)&biCompression; - - for (ptrdiff_t i = 0; i < 4; i++) { - if (b[i] >= 'a' && b[i] <= 'z') { - b[i] = (BYTE)toupper(b[i]); - } - } - - if (!names.Lookup(MAKEFOURCC(b[3], b[2], b[1], b[0]), str)) { - if (subtype == MEDIASUBTYPE_DiracVideo) { - str = _T("Dirac Video"); - } - // else if (subtype == ) str = _T(""); - else if (biCompression < 256) { - str.Format(_T("%lu"), biCompression); - } else { - str.Format(_T("%4.4hs"), &biCompression); - } - } - } else { - if (subtype == MEDIASUBTYPE_RGB32) { - str = _T("RGB32"); - } else if (subtype == MEDIASUBTYPE_RGB24) { - str = _T("RGB24"); - } else if (subtype == MEDIASUBTYPE_RGB555) { - str = _T("RGB555"); - } else if (subtype == MEDIASUBTYPE_RGB565) { - str = _T("RGB565"); - } - } - - return str; -} - -CString CMediaTypeEx::GetAudioCodecName(const GUID& subtype, WORD wFormatTag) -{ - CString str; - - static CAtlMap names; - - if (names.IsEmpty()) { - // MMReg.h - names[WAVE_FORMAT_ADPCM] = _T("MS ADPCM"); - names[WAVE_FORMAT_IEEE_FLOAT] = _T("IEEE Float"); - names[WAVE_FORMAT_ALAW] = _T("aLaw"); - names[WAVE_FORMAT_MULAW] = _T("muLaw"); - names[WAVE_FORMAT_DTS] = _T("DTS"); - names[WAVE_FORMAT_DRM] = _T("DRM"); - names[WAVE_FORMAT_WMAVOICE9] = _T("WMA Voice"); - names[WAVE_FORMAT_WMAVOICE10] = _T("WMA Voice"); - names[WAVE_FORMAT_OKI_ADPCM] = _T("OKI ADPCM"); - names[WAVE_FORMAT_IMA_ADPCM] = _T("IMA ADPCM"); - names[WAVE_FORMAT_MEDIASPACE_ADPCM] = _T("Mediaspace ADPCM"); - names[WAVE_FORMAT_SIERRA_ADPCM] = _T("Sierra ADPCM"); - names[WAVE_FORMAT_G723_ADPCM] = _T("G723 ADPCM"); - names[WAVE_FORMAT_DIALOGIC_OKI_ADPCM] = _T("Dialogic OKI ADPCM"); - names[WAVE_FORMAT_MEDIAVISION_ADPCM] = _T("Media Vision ADPCM"); - names[WAVE_FORMAT_YAMAHA_ADPCM] = _T("Yamaha ADPCM"); - names[WAVE_FORMAT_DSPGROUP_TRUESPEECH] = _T("DSP Group Truespeech"); - names[WAVE_FORMAT_DOLBY_AC2] = _T("Dolby AC2"); - names[WAVE_FORMAT_GSM610] = _T("GSM610"); - names[WAVE_FORMAT_MSNAUDIO] = _T("MSN Audio"); - names[WAVE_FORMAT_ANTEX_ADPCME] = _T("Antex ADPCME"); - names[WAVE_FORMAT_CS_IMAADPCM] = _T("Crystal Semiconductor IMA ADPCM"); - names[WAVE_FORMAT_ROCKWELL_ADPCM] = _T("Rockwell ADPCM"); - names[WAVE_FORMAT_ROCKWELL_DIGITALK] = _T("Rockwell Digitalk"); - names[WAVE_FORMAT_G721_ADPCM] = _T("G721"); - names[WAVE_FORMAT_G728_CELP] = _T("G728"); - names[WAVE_FORMAT_MSG723] = _T("MSG723"); - names[WAVE_FORMAT_MPEG] = _T("MPEG Audio"); - names[WAVE_FORMAT_MPEGLAYER3] = _T("MP3"); - names[WAVE_FORMAT_LUCENT_G723] = _T("Lucent G723"); - names[WAVE_FORMAT_VOXWARE] = _T("Voxware"); - names[WAVE_FORMAT_G726_ADPCM] = _T("G726"); - names[WAVE_FORMAT_G722_ADPCM] = _T("G722"); - names[WAVE_FORMAT_G729A] = _T("G729A"); - names[WAVE_FORMAT_MEDIASONIC_G723] = _T("MediaSonic G723"); - names[WAVE_FORMAT_ZYXEL_ADPCM] = _T("ZyXEL ADPCM"); - names[WAVE_FORMAT_RAW_AAC1] = _T("AAC"); // = WAVE_FORMAT_AAC - names[WAVE_FORMAT_RHETOREX_ADPCM] = _T("Rhetorex ADPCM"); - names[WAVE_FORMAT_VIVO_G723] = _T("Vivo G723"); - names[WAVE_FORMAT_VIVO_SIREN] = _T("Vivo Siren"); - names[WAVE_FORMAT_DIGITAL_G723] = _T("Digital G723"); - names[WAVE_FORMAT_SANYO_LD_ADPCM] = _T("Sanyo LD ADPCM"); - names[WAVE_FORMAT_MSAUDIO1] = _T("WMA 1"); - names[WAVE_FORMAT_WMAUDIO2] = _T("WMA 2"); - names[WAVE_FORMAT_WMAUDIO3] = _T("WMA Pro"); - names[WAVE_FORMAT_WMAUDIO_LOSSLESS] = _T("WMA Lossless"); - names[WAVE_FORMAT_CREATIVE_ADPCM] = _T("Creative ADPCM"); - names[WAVE_FORMAT_CREATIVE_FASTSPEECH8] = _T("Creative Fastspeech 8"); - names[WAVE_FORMAT_CREATIVE_FASTSPEECH10] = _T("Creative Fastspeech 10"); - names[WAVE_FORMAT_UHER_ADPCM] = _T("UHER ADPCM"); - names[WAVE_FORMAT_DTS2] = _T("DTS"); // = WAVE_FORMAT_DVD_DTS - // other - names[WAVE_FORMAT_DOLBY_AC3] = _T("Dolby AC3"); - names[WAVE_FORMAT_LATM_AAC] = _T("AAC(LATM)"); - names[WAVE_FORMAT_FLAC] = _T("FLAC"); - names[WAVE_FORMAT_TTA1] = _T("TTA"); - names[WAVE_FORMAT_WAVPACK4] = _T("WavPack"); - names[WAVE_FORMAT_14_4] = _T("RealAudio 14.4"); - names[WAVE_FORMAT_28_8] = _T("RealAudio 28.8"); - names[WAVE_FORMAT_ATRC] = _T("RealAudio ATRC"); - names[WAVE_FORMAT_COOK] = _T("RealAudio COOK"); - names[WAVE_FORMAT_DNET] = _T("RealAudio DNET"); - names[WAVE_FORMAT_RAAC] = _T("RealAudio RAAC"); - names[WAVE_FORMAT_RACP] = _T("RealAudio RACP"); - names[WAVE_FORMAT_SIPR] = _T("RealAudio SIPR"); - names[WAVE_FORMAT_PS2_PCM] = _T("PS2 PCM"); - names[WAVE_FORMAT_PS2_ADPCM] = _T("PS2 ADPCM"); - names[WAVE_FORMAT_AAC_ADTS] = _T("AAC"); // Specific to LAV Splitter and LAV Audio Decoder - // names[] = _T(""); - } - - // Check if we are bitstreaming to S/PDIF first to avoid misdetection as PCM - if (wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) { // Note that DTS bitstreaming uses the same format tag - str = _T("S/PDIF"); - } - // Check the subtype first after special cases have been handled - else if (subtype == MEDIASUBTYPE_PCM) { - str = _T("PCM"); - } else if (subtype == MEDIASUBTYPE_IEEE_FLOAT) { - str = _T("IEEE Float"); - } else if (subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO || subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { - str = _T("LPCM"); - } else if (subtype == MEDIASUBTYPE_Vorbis) { - str = _T("Vorbis (deprecated)"); - } else if (subtype == MEDIASUBTYPE_Vorbis2) { - str = _T("Vorbis"); - } else if (subtype == MEDIASUBTYPE_MP4A) { - str = _T("MPEG4 Audio"); - } else if (subtype == MEDIASUBTYPE_FLAC_FRAMED) { - str = _T("FLAC (framed)"); - } else if (subtype == MEDIASUBTYPE_DOLBY_AC3) { - str = _T("Dolby AC3"); - } else if (subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { - str = _T("DD+"); - } else if (subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { - str = _T("TrueHD"); - } else if (subtype == MEDIASUBTYPE_DTS) { - str = _T("DTS"); - } else if (subtype == MEDIASUBTYPE_MLP) { - str = _T("MLP"); - } else if (subtype == MEDIASUBTYPE_PCM_NONE || subtype == MEDIASUBTYPE_PCM_RAW || - subtype == MEDIASUBTYPE_PCM_TWOS || subtype == MEDIASUBTYPE_PCM_SOWT || - subtype == MEDIASUBTYPE_PCM_IN24 || subtype == MEDIASUBTYPE_PCM_IN32 || - subtype == MEDIASUBTYPE_PCM_FL32 || subtype == MEDIASUBTYPE_PCM_FL64) { - str = _T("QT PCM"); - } else if (subtype == MEDIASUBTYPE_IMA4 || - subtype == MEDIASUBTYPE_ADPCM_SWF || - subtype == MEDIASUBTYPE_ADPCM_AMV) { - str = _T("ADPCM"); - } else if (subtype == MEDIASUBTYPE_ALAC) { - str = _T("ALAC"); - } else if (subtype == MEDIASUBTYPE_ALS) { - str = _T("ALS"); - } else if (subtype == MEDIASUBTYPE_QDM2) { - str = _T("QDM2"); - } else if (subtype == MEDIASUBTYPE_AMR || - subtype == MEDIASUBTYPE_SAMR || - subtype == MEDIASUBTYPE_SAWB) { - str = _T("AMR"); - } else if (subtype == MEDIASUBTYPE_OPUS) { - str = _T("Opus"); - } // If the subtype wasn't enough to find the codec name, we try the format tag - else if (!names.Lookup(wFormatTag, str)) { - // If that fails, we have an unknown audio codec - str.Format(_T("0x%04x"), wFormatTag); - } - - return str; -} - -CString CMediaTypeEx::GetSubtitleCodecName(const GUID& subtype) -{ - CString str; - - static CAtlMap names; - - if (names.IsEmpty()) { - names[MEDIASUBTYPE_UTF8] = _T("UTF-8"); - names[MEDIASUBTYPE_SSA] = _T("SubStation Alpha"); - names[MEDIASUBTYPE_ASS] = _T("Advanced SubStation Alpha"); - names[MEDIASUBTYPE_ASS2] = _T("Advanced SubStation Alpha"); - names[MEDIASUBTYPE_USF] = _T("Universal Subtitle Format"); - names[MEDIASUBTYPE_VOBSUB] = _T("VobSub"); - names[MEDIASUBTYPE_DVB_SUBTITLES] = _T("DVB Subtitles"); - names[MEDIASUBTYPE_DVD_SUBPICTURE] = _T("DVD Subtitles"); - names[MEDIASUBTYPE_WEBVTT] = _T("WebVTT"); - } - - if (names.Lookup(subtype, str)) { - - } - - return str; -} - -void CMediaTypeEx::Dump(CAtlList& sl) -{ - CString str; - - sl.RemoveAll(); - - int fmtsize = 0; - - CString major = CStringFromGUID(majortype); - CString sub = CStringFromGUID(subtype); - CString format = CStringFromGUID(formattype); - - sl.AddTail(ToString() + _T("\n")); - - sl.AddTail(_T("AM_MEDIA_TYPE: ")); - str.Format(_T("majortype: %S %s"), GuidNames[majortype], major.GetString()); - sl.AddTail(str); - str.Format(_T("subtype: %S %s"), GuidNames[subtype], sub.GetString()); - sl.AddTail(str); - str.Format(_T("formattype: %S %s"), GuidNames[formattype], format.GetString()); - sl.AddTail(str); - str.Format(_T("bFixedSizeSamples: %d"), bFixedSizeSamples); - sl.AddTail(str); - str.Format(_T("bTemporalCompression: %d"), bTemporalCompression); - sl.AddTail(str); - str.Format(_T("lSampleSize: %lu"), lSampleSize); - sl.AddTail(str); - str.Format(_T("cbFormat: %lu"), cbFormat); - sl.AddTail(str); - - sl.AddTail(_T("")); - - if (formattype == FORMAT_VideoInfo || formattype == FORMAT_VideoInfo2 - || formattype == FORMAT_MPEGVideo || formattype == FORMAT_MPEG2_VIDEO) { - fmtsize = - formattype == FORMAT_VideoInfo ? sizeof(VIDEOINFOHEADER) : - formattype == FORMAT_VideoInfo2 ? sizeof(VIDEOINFOHEADER2) : - formattype == FORMAT_MPEGVideo ? sizeof(MPEG1VIDEOINFO) - 1 : - formattype == FORMAT_MPEG2_VIDEO ? sizeof(MPEG2VIDEOINFO) - 4 : - 0; - - VIDEOINFOHEADER& vih = *(VIDEOINFOHEADER*)pbFormat; - BITMAPINFOHEADER* bih = &vih.bmiHeader; - - sl.AddTail(_T("VIDEOINFOHEADER:")); - str.Format(_T("rcSource: (%ld,%ld)-(%ld,%ld)"), vih.rcSource.left, vih.rcSource.top, vih.rcSource.right, vih.rcSource.bottom); - sl.AddTail(str); - str.Format(_T("rcTarget: (%ld,%ld)-(%ld,%ld)"), vih.rcTarget.left, vih.rcTarget.top, vih.rcTarget.right, vih.rcTarget.bottom); - sl.AddTail(str); - str.Format(_T("dwBitRate: %u"), vih.dwBitRate); - sl.AddTail(str); - str.Format(_T("dwBitErrorRate: %u"), vih.dwBitErrorRate); - sl.AddTail(str); - str.Format(_T("AvgTimePerFrame: %I64d"), vih.AvgTimePerFrame); - sl.AddTail(str); - - sl.AddTail(_T("")); - - if (formattype == FORMAT_VideoInfo2 || formattype == FORMAT_MPEG2_VIDEO) { - VIDEOINFOHEADER2& vih2 = *(VIDEOINFOHEADER2*)pbFormat; - bih = &vih2.bmiHeader; - - sl.AddTail(_T("VIDEOINFOHEADER2:")); - str.Format(_T("dwInterlaceFlags: 0x%08x"), vih2.dwInterlaceFlags); - sl.AddTail(str); - str.Format(_T("dwCopyProtectFlags: 0x%08x"), vih2.dwCopyProtectFlags); - sl.AddTail(str); - str.Format(_T("dwPictAspectRatioX: %u"), vih2.dwPictAspectRatioX); - sl.AddTail(str); - str.Format(_T("dwPictAspectRatioY: %u"), vih2.dwPictAspectRatioY); - sl.AddTail(str); - str.Format(_T("dwControlFlags: 0x%08x"), vih2.dwControlFlags); - sl.AddTail(str); - str.Format(_T("dwReserved2: 0x%08x"), vih2.dwReserved2); - sl.AddTail(str); - - sl.AddTail(_T("")); - } - - if (formattype == FORMAT_MPEGVideo) { - MPEG1VIDEOINFO& mvih = *(MPEG1VIDEOINFO*)pbFormat; - - sl.AddTail(_T("MPEG1VIDEOINFO:")); - str.Format(_T("dwStartTimeCode: %u"), mvih.dwStartTimeCode); - sl.AddTail(str); - str.Format(_T("cbSequenceHeader: %u"), mvih.cbSequenceHeader); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (formattype == FORMAT_MPEG2_VIDEO) { - MPEG2VIDEOINFO& mvih = *(MPEG2VIDEOINFO*)pbFormat; - - sl.AddTail(_T("MPEG2VIDEOINFO:")); - str.Format(_T("dwStartTimeCode: %u"), mvih.dwStartTimeCode); - sl.AddTail(str); - str.Format(_T("cbSequenceHeader: %u"), mvih.cbSequenceHeader); - sl.AddTail(str); - str.Format(_T("dwProfile: 0x%08x"), mvih.dwProfile); - sl.AddTail(str); - str.Format(_T("dwLevel: 0x%08x"), mvih.dwLevel); - sl.AddTail(str); - str.Format(_T("dwFlags: 0x%08x"), mvih.dwFlags); - sl.AddTail(str); - - sl.AddTail(_T("")); - } - - sl.AddTail(_T("BITMAPINFOHEADER:")); - str.Format(_T("biSize: %u"), bih->biSize); - sl.AddTail(str); - str.Format(_T("biWidth: %ld"), bih->biWidth); - sl.AddTail(str); - str.Format(_T("biHeight: %ld"), bih->biHeight); - sl.AddTail(str); - str.Format(_T("biPlanes: %u"), bih->biPlanes); - sl.AddTail(str); - str.Format(_T("biBitCount: %u"), bih->biBitCount); - sl.AddTail(str); - if (bih->biCompression < 256) { - str.Format(_T("biCompression: %u"), bih->biCompression); - } else { - str.Format(_T("biCompression: %4.4hs"), &bih->biCompression); - } - sl.AddTail(str); - str.Format(_T("biSizeImage: %u"), bih->biSizeImage); - sl.AddTail(str); - str.Format(_T("biXPelsPerMeter: %ld"), bih->biXPelsPerMeter); - sl.AddTail(str); - str.Format(_T("biYPelsPerMeter: %ld"), bih->biYPelsPerMeter); - sl.AddTail(str); - str.Format(_T("biClrUsed: %u"), bih->biClrUsed); - sl.AddTail(str); - str.Format(_T("biClrImportant: %u"), bih->biClrImportant); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (formattype == FORMAT_WaveFormatEx || formattype == FORMAT_WaveFormatExFFMPEG) { - WAVEFORMATEX* pWfe = nullptr; - if (formattype == FORMAT_WaveFormatExFFMPEG) { - fmtsize = sizeof(WAVEFORMATEXFFMPEG); - - WAVEFORMATEXFFMPEG* wfeff = (WAVEFORMATEXFFMPEG*)pbFormat; - pWfe = &wfeff->wfex; - - sl.AddTail(_T("WAVEFORMATEXFFMPEG:")); - str.Format(_T("nCodecId: 0x%04x"), wfeff->nCodecId); - sl.AddTail(str); - sl.AddTail(_T("")); - } else { - fmtsize = sizeof(WAVEFORMATEX); - pWfe = (WAVEFORMATEX*)pbFormat; - } - - WAVEFORMATEX& wfe = *pWfe; - - sl.AddTail(_T("WAVEFORMATEX:")); - str.Format(_T("wFormatTag: 0x%04x"), wfe.wFormatTag); - sl.AddTail(str); - str.Format(_T("nChannels: %u"), wfe.nChannels); - sl.AddTail(str); - str.Format(_T("nSamplesPerSec: %u"), wfe.nSamplesPerSec); - sl.AddTail(str); - str.Format(_T("nAvgBytesPerSec: %u"), wfe.nAvgBytesPerSec); - sl.AddTail(str); - str.Format(_T("nBlockAlign: %u"), wfe.nBlockAlign); - sl.AddTail(str); - str.Format(_T("wBitsPerSample: %u"), wfe.wBitsPerSample); - sl.AddTail(str); - str.Format(_T("cbSize: %u (extra bytes)"), wfe.cbSize); - sl.AddTail(str); - - sl.AddTail(_T("")); - - if (wfe.wFormatTag != WAVE_FORMAT_PCM && wfe.cbSize > 0 && formattype == FORMAT_WaveFormatEx) { - if (wfe.wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfe.cbSize == sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { - fmtsize = sizeof(WAVEFORMATEXTENSIBLE); - - WAVEFORMATEXTENSIBLE& wfextensible = *(WAVEFORMATEXTENSIBLE*)pbFormat; - - sl.AddTail(_T("WAVEFORMATEXTENSIBLE:")); - if (wfextensible.Format.wBitsPerSample != 0) { - str.Format(_T("wValidBitsPerSample: %u"), wfextensible.Samples.wValidBitsPerSample); - } else { - str.Format(_T("wSamplesPerBlock: %u"), wfextensible.Samples.wSamplesPerBlock); - } - sl.AddTail(str); - str.Format(_T("dwChannelMask: 0x%08x"), wfextensible.dwChannelMask); - sl.AddTail(str); - str.Format(_T("SubFormat: %s"), CStringFromGUID(wfextensible.SubFormat).GetString()); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (wfe.wFormatTag == WAVE_FORMAT_DOLBY_AC3 && wfe.cbSize == sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX)) { - fmtsize = sizeof(DOLBYAC3WAVEFORMAT); - - DOLBYAC3WAVEFORMAT& dawf = *(DOLBYAC3WAVEFORMAT*)pbFormat; - - sl.AddTail(_T("DOLBYAC3WAVEFORMAT:")); - str.Format(_T("bBigEndian: %u"), dawf.bBigEndian); - sl.AddTail(str); - str.Format(_T("bsid: %u"), dawf.bsid); - sl.AddTail(str); - str.Format(_T("lfeon: %u"), dawf.lfeon); - sl.AddTail(str); - str.Format(_T("copyrightb: %u"), dawf.copyrightb); - sl.AddTail(str); - str.Format(_T("nAuxBitsCode: %u"), dawf.nAuxBitsCode); - sl.AddTail(str); - - sl.AddTail(_T("")); - } - } - } else if (formattype == FORMAT_VorbisFormat) { - fmtsize = sizeof(VORBISFORMAT); - - VORBISFORMAT& vf = *(VORBISFORMAT*)pbFormat; - - sl.AddTail(_T("VORBISFORMAT:")); - str.Format(_T("nChannels: %u"), vf.nChannels); - sl.AddTail(str); - str.Format(_T("nSamplesPerSec: %lu"), vf.nSamplesPerSec); - sl.AddTail(str); - str.Format(_T("nMinBitsPerSec: %lu"), vf.nMinBitsPerSec); - sl.AddTail(str); - str.Format(_T("nAvgBitsPerSec: %lu"), vf.nAvgBitsPerSec); - sl.AddTail(str); - str.Format(_T("nMaxBitsPerSec: %lu"), vf.nMaxBitsPerSec); - sl.AddTail(str); - str.Format(_T("fQuality: %.3f"), vf.fQuality); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (formattype == FORMAT_VorbisFormat2) { - fmtsize = sizeof(VORBISFORMAT2); - - VORBISFORMAT2& vf = *(VORBISFORMAT2*)pbFormat; - - sl.AddTail(_T("VORBISFORMAT:")); - str.Format(_T("Channels: %lu"), vf.Channels); - sl.AddTail(str); - str.Format(_T("SamplesPerSec: %lu"), vf.SamplesPerSec); - sl.AddTail(str); - str.Format(_T("BitsPerSample: %lu"), vf.BitsPerSample); - sl.AddTail(str); - str.Format(_T("HeaderSize: {%lu, %lu, %lu}"), vf.HeaderSize[0], vf.HeaderSize[1], vf.HeaderSize[2]); - sl.AddTail(str); - - sl.AddTail(_T("")); - } else if (formattype == FORMAT_SubtitleInfo) { - fmtsize = sizeof(SUBTITLEINFO); - - SUBTITLEINFO& si = *(SUBTITLEINFO*)pbFormat; - - sl.AddTail(_T("SUBTITLEINFO:")); - str.Format(_T("dwOffset: %lu"), si.dwOffset); - sl.AddTail(str); - str.Format(_T("IsoLang: %S"), CStringA(si.IsoLang, sizeof(si.IsoLang) - 1).GetString()); - sl.AddTail(str); - str.Format(_T("TrackName: %s"), CStringW(si.TrackName, sizeof(si.TrackName) - 1).GetString()); - sl.AddTail(str); - - sl.AddTail(_T("")); - } - - if (cbFormat > 0) { - sl.AddTail(_T("pbFormat:")); - - for (ptrdiff_t i = 0, j = (cbFormat + 15) & ~15; i < j; i += 16) { - str.Format(_T("%04Ix:"), i); - - for (ptrdiff_t k = i, l = std::min(i + 16, (ptrdiff_t)cbFormat); k < l; k++) { - CString byte; - byte.Format(_T("%c%02x"), fmtsize > 0 && fmtsize == k ? '|' : ' ', pbFormat[k]); - str += byte; - } - - for (ptrdiff_t k = std::min(i + 16, (ptrdiff_t)cbFormat), l = i + 16; k < l; k++) { - str += _T(" "); - } - - str += _T(' '); - - for (ptrdiff_t k = i, l = std::min(i + 16, (ptrdiff_t)cbFormat); k < l; k++) { - unsigned char c = (unsigned char)pbFormat[k]; - CString ch; - ch.Format(_T("%C"), c >= 0x20 ? c : '.'); - str += ch; - } - - sl.AddTail(str); - } - - sl.AddTail(_T("")); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "DSUtil.h" +#include "MediaTypeEx.h" + +#include +#include "moreuuids.h" + +#pragma pack(push, 1) +struct DOLBYAC3WAVEFORMAT { + WAVEFORMATEX Format; + BYTE bBigEndian; + BYTE bsid; + BYTE lfeon; + BYTE copyrightb; + BYTE nAuxBitsCode; // Aux bits per frame +}; +#pragma pack(pop) + +CMediaTypeEx::CMediaTypeEx() +{ +} + +CMediaTypeEx::~CMediaTypeEx() +{ +} + +CString CMediaTypeEx::ToString(IPin* pPin) +{ + CString packing, type, codec, dim, rate, dur; + + // TODO + + if (majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { + packing = _T("Encrypted MPEG2 Pack"); + } else if (majortype == MEDIATYPE_MPEG2_PACK) { + packing = _T("MPEG2 Pack"); + } else if (majortype == MEDIATYPE_MPEG2_PES) { + packing = _T("MPEG2 PES"); + } + + if (majortype == MEDIATYPE_Video || subtype == MEDIASUBTYPE_MPEG2_VIDEO) { + type = _T("Video"); + + BITMAPINFOHEADER bih; + bool fBIH = ExtractBIH(this, &bih); + + int w, h, arx, ary; + bool fDim = ExtractDim(this, w, h, arx, ary); + + if (fBIH) { + codec = GetVideoCodecName(subtype, bih.biCompression); + } + + if (codec.IsEmpty()) { + if (formattype == FORMAT_MPEGVideo) { + codec = _T("MPEG1 Video"); + } else if (formattype == FORMAT_MPEG2_VIDEO) { + codec = _T("MPEG2 Video"); + } else if (formattype == FORMAT_DiracVideoInfo) { + codec = _T("Dirac Video"); + } + } + + if (fDim) { + dim.Format(_T("%dx%d"), w, h); + if (w * ary != h * arx) { + dim.AppendFormat(_T(" (%d:%d)"), arx, ary); + } + } + + if (formattype == FORMAT_VideoInfo || formattype == FORMAT_MPEGVideo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)pbFormat; + if (vih->AvgTimePerFrame) { + rate.Format(_T("%0.3f"), 10000000.0f / vih->AvgTimePerFrame); + rate.TrimRight(_T('0')); // remove trailing zeros + rate.TrimRight(_T('.')); // remove the trailing dot + rate += _T("fps "); + } + if (vih->dwBitRate) { + rate.AppendFormat(_T("%ukbps"), vih->dwBitRate / 1000); + } + } else if (formattype == FORMAT_VideoInfo2 || formattype == FORMAT_MPEG2_VIDEO || formattype == FORMAT_DiracVideoInfo) { + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)pbFormat; + if (vih->AvgTimePerFrame) { + rate.Format(_T("%0.3f"), 10000000.0f / vih->AvgTimePerFrame); + rate.TrimRight(_T('0')); // remove trailing zeros + rate.TrimRight(_T('.')); // remove the trailing dot + rate += _T("fps "); + } + if (vih->dwBitRate) { + rate.AppendFormat(_T("%ukbps"), vih->dwBitRate / 1000); + } + } + + rate.TrimRight(); + + if (subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { + type = _T("Subtitle"); + codec = _T("DVD Subpicture"); + } + } else if (majortype == MEDIATYPE_Audio || subtype == MEDIASUBTYPE_DOLBY_AC3) { + type = _T("Audio"); + + if (formattype == FORMAT_WaveFormatEx) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)Format(); + + if (wfe->wFormatTag/* > WAVE_FORMAT_PCM && wfe->wFormatTag < WAVE_FORMAT_EXTENSIBLE + && wfe->wFormatTag != WAVE_FORMAT_IEEE_FLOAT*/ + || subtype != GUID_NULL) { + codec = GetAudioCodecName(subtype, wfe->wFormatTag); + dim.Format(_T("%uHz"), wfe->nSamplesPerSec); + if (wfe->nChannels == 1) { + dim += _T(" mono"); + } else if (wfe->nChannels == 2) { + dim += _T(" stereo"); + } else { + dim.AppendFormat(_T(" %uch"), wfe->nChannels); + } + if (wfe->nAvgBytesPerSec) { + rate.Format(_T("%ukbps"), wfe->nAvgBytesPerSec * 8 / 1000); + } + } + } else if (formattype == FORMAT_VorbisFormat) { + VORBISFORMAT* vf = (VORBISFORMAT*)Format(); + + codec = GetAudioCodecName(subtype, 0); + dim.Format(_T("%luHz"), vf->nSamplesPerSec); + if (vf->nChannels == 1) { + dim += _T(" mono"); + } else if (vf->nChannels == 2) { + dim += _T(" stereo"); + } else { + dim.AppendFormat(_T(" %uch"), vf->nChannels); + } + if (vf->nAvgBitsPerSec) { + rate.Format(_T("%lukbps"), vf->nAvgBitsPerSec / 1000); + } + } else if (formattype == FORMAT_VorbisFormat2) { + VORBISFORMAT2* vf = (VORBISFORMAT2*)Format(); + + codec = GetAudioCodecName(subtype, 0); + dim.Format(_T("%luHz"), vf->SamplesPerSec); + if (vf->Channels == 1) { + dim += _T(" mono"); + } else if (vf->Channels == 2) { + dim += _T(" stereo"); + } else { + dim.AppendFormat(_T(" %luch"), vf->Channels); + } + } + } else if (majortype == MEDIATYPE_Text) { + type = _T("Text"); + } else if (majortype == MEDIATYPE_Subtitle || subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { + type = _T("Subtitle"); + codec = GetSubtitleCodecName(subtype); + } else { + type = _T("Unknown"); + } + + if (CComQIPtr pMS = pPin) { + REFERENCE_TIME rtDur = 0; + if (SUCCEEDED(pMS->GetDuration(&rtDur)) && rtDur) { + rtDur /= 10000000; + int s = rtDur % 60; + rtDur /= 60; + int m = rtDur % 60; + rtDur /= 60; + int h = (int)rtDur; + if (h) { + dur.Format(_T("%d:%02d:%02d"), h, m, s); + } else if (m) { + dur.Format(_T("%02d:%02d"), m, s); + } else if (s) { + dur.Format(_T("%ds"), s); + } + } + } + + CString str; + if (!codec.IsEmpty()) { + str += codec + _T(" "); + } + if (!dim.IsEmpty()) { + str += dim + _T(" "); + } + if (!rate.IsEmpty()) { + str += rate + _T(" "); + } + if (!dur.IsEmpty()) { + str += dur + _T(" "); + } + str.Trim(_T(" ,")); + + if (!str.IsEmpty()) { + str = type + _T(": ") + str; + } else { + str = type; + } + + return str; +} + +CString CMediaTypeEx::GetVideoCodecName(const GUID& subtype, DWORD biCompression) +{ + CString str = _T(""); + + static CAtlMap names; + + if (names.IsEmpty()) { + names['WMV1'] = _T("Windows Media Video 7"); + names['WMV2'] = _T("Windows Media Video 8"); + names['WMV3'] = _T("Windows Media Video 9"); + names['DIV3'] = _T("DivX 3"); + names['MP43'] = _T("MSMPEG4v3"); + names['MP42'] = _T("MSMPEG4v2"); + names['MP41'] = _T("MSMPEG4v1"); + names['DX50'] = _T("DivX 5"); + names['DIVX'] = _T("DivX 6"); + names['XVID'] = _T("Xvid"); + names['MP4V'] = _T("MPEG4 Video"); + names['AVC1'] = _T("MPEG4 Video (H264)"); + names['H264'] = _T("MPEG4 Video (H264)"); + names['RV10'] = _T("RealVideo 1"); + names['RV20'] = _T("RealVideo 2"); + names['RV30'] = _T("RealVideo 3"); + names['RV40'] = _T("RealVideo 4"); + names['FLV1'] = _T("Flash Video 1"); + names['FLV4'] = _T("Flash Video 4"); + names['VP50'] = _T("On2 VP5"); + names['VP60'] = _T("On2 VP6"); + names['SVQ3'] = _T("SVQ3"); + names['SVQ1'] = _T("SVQ1"); + names['H263'] = _T("H263"); + // names[''] = _T(""); + } + + if (biCompression) { + BYTE* b = (BYTE*)&biCompression; + + for (ptrdiff_t i = 0; i < 4; i++) { + if (b[i] >= 'a' && b[i] <= 'z') { + b[i] = (BYTE)toupper(b[i]); + } + } + + if (!names.Lookup(MAKEFOURCC(b[3], b[2], b[1], b[0]), str)) { + if (subtype == MEDIASUBTYPE_DiracVideo) { + str = _T("Dirac Video"); + } + // else if (subtype == ) str = _T(""); + else if (biCompression < 256) { + str.Format(_T("%lu"), biCompression); + } else { + str.Format(_T("%4.4hs"), &biCompression); + } + } + } else { + if (subtype == MEDIASUBTYPE_RGB32) { + str = _T("RGB32"); + } else if (subtype == MEDIASUBTYPE_RGB24) { + str = _T("RGB24"); + } else if (subtype == MEDIASUBTYPE_RGB555) { + str = _T("RGB555"); + } else if (subtype == MEDIASUBTYPE_RGB565) { + str = _T("RGB565"); + } + } + + return str; +} + +CString CMediaTypeEx::GetAudioCodecName(const GUID& subtype, WORD wFormatTag) +{ + CString str; + + static CAtlMap names; + + if (names.IsEmpty()) { + // MMReg.h + names[WAVE_FORMAT_ADPCM] = _T("MS ADPCM"); + names[WAVE_FORMAT_IEEE_FLOAT] = _T("IEEE Float"); + names[WAVE_FORMAT_ALAW] = _T("aLaw"); + names[WAVE_FORMAT_MULAW] = _T("muLaw"); + names[WAVE_FORMAT_DTS] = _T("DTS"); + names[WAVE_FORMAT_DRM] = _T("DRM"); + names[WAVE_FORMAT_WMAVOICE9] = _T("WMA Voice"); + names[WAVE_FORMAT_WMAVOICE10] = _T("WMA Voice"); + names[WAVE_FORMAT_OKI_ADPCM] = _T("OKI ADPCM"); + names[WAVE_FORMAT_IMA_ADPCM] = _T("IMA ADPCM"); + names[WAVE_FORMAT_MEDIASPACE_ADPCM] = _T("Mediaspace ADPCM"); + names[WAVE_FORMAT_SIERRA_ADPCM] = _T("Sierra ADPCM"); + names[WAVE_FORMAT_G723_ADPCM] = _T("G723 ADPCM"); + names[WAVE_FORMAT_DIALOGIC_OKI_ADPCM] = _T("Dialogic OKI ADPCM"); + names[WAVE_FORMAT_MEDIAVISION_ADPCM] = _T("Media Vision ADPCM"); + names[WAVE_FORMAT_YAMAHA_ADPCM] = _T("Yamaha ADPCM"); + names[WAVE_FORMAT_DSPGROUP_TRUESPEECH] = _T("DSP Group Truespeech"); + names[WAVE_FORMAT_DOLBY_AC2] = _T("Dolby AC2"); + names[WAVE_FORMAT_GSM610] = _T("GSM610"); + names[WAVE_FORMAT_MSNAUDIO] = _T("MSN Audio"); + names[WAVE_FORMAT_ANTEX_ADPCME] = _T("Antex ADPCME"); + names[WAVE_FORMAT_CS_IMAADPCM] = _T("Crystal Semiconductor IMA ADPCM"); + names[WAVE_FORMAT_ROCKWELL_ADPCM] = _T("Rockwell ADPCM"); + names[WAVE_FORMAT_ROCKWELL_DIGITALK] = _T("Rockwell Digitalk"); + names[WAVE_FORMAT_G721_ADPCM] = _T("G721"); + names[WAVE_FORMAT_G728_CELP] = _T("G728"); + names[WAVE_FORMAT_MSG723] = _T("MSG723"); + names[WAVE_FORMAT_MPEG] = _T("MPEG Audio"); + names[WAVE_FORMAT_MPEGLAYER3] = _T("MP3"); + names[WAVE_FORMAT_LUCENT_G723] = _T("Lucent G723"); + names[WAVE_FORMAT_VOXWARE] = _T("Voxware"); + names[WAVE_FORMAT_G726_ADPCM] = _T("G726"); + names[WAVE_FORMAT_G722_ADPCM] = _T("G722"); + names[WAVE_FORMAT_G729A] = _T("G729A"); + names[WAVE_FORMAT_MEDIASONIC_G723] = _T("MediaSonic G723"); + names[WAVE_FORMAT_ZYXEL_ADPCM] = _T("ZyXEL ADPCM"); + names[WAVE_FORMAT_RAW_AAC1] = _T("AAC"); // = WAVE_FORMAT_AAC + names[WAVE_FORMAT_RHETOREX_ADPCM] = _T("Rhetorex ADPCM"); + names[WAVE_FORMAT_VIVO_G723] = _T("Vivo G723"); + names[WAVE_FORMAT_VIVO_SIREN] = _T("Vivo Siren"); + names[WAVE_FORMAT_DIGITAL_G723] = _T("Digital G723"); + names[WAVE_FORMAT_SANYO_LD_ADPCM] = _T("Sanyo LD ADPCM"); + names[WAVE_FORMAT_MSAUDIO1] = _T("WMA 1"); + names[WAVE_FORMAT_WMAUDIO2] = _T("WMA 2"); + names[WAVE_FORMAT_WMAUDIO3] = _T("WMA Pro"); + names[WAVE_FORMAT_WMAUDIO_LOSSLESS] = _T("WMA Lossless"); + names[WAVE_FORMAT_CREATIVE_ADPCM] = _T("Creative ADPCM"); + names[WAVE_FORMAT_CREATIVE_FASTSPEECH8] = _T("Creative Fastspeech 8"); + names[WAVE_FORMAT_CREATIVE_FASTSPEECH10] = _T("Creative Fastspeech 10"); + names[WAVE_FORMAT_UHER_ADPCM] = _T("UHER ADPCM"); + names[WAVE_FORMAT_DTS2] = _T("DTS"); // = WAVE_FORMAT_DVD_DTS + // other + names[WAVE_FORMAT_DOLBY_AC3] = _T("Dolby AC3"); + names[WAVE_FORMAT_LATM_AAC] = _T("AAC(LATM)"); + names[WAVE_FORMAT_FLAC] = _T("FLAC"); + names[WAVE_FORMAT_TTA1] = _T("TTA"); + names[WAVE_FORMAT_WAVPACK4] = _T("WavPack"); + names[WAVE_FORMAT_14_4] = _T("RealAudio 14.4"); + names[WAVE_FORMAT_28_8] = _T("RealAudio 28.8"); + names[WAVE_FORMAT_ATRC] = _T("RealAudio ATRC"); + names[WAVE_FORMAT_COOK] = _T("RealAudio COOK"); + names[WAVE_FORMAT_DNET] = _T("RealAudio DNET"); + names[WAVE_FORMAT_RAAC] = _T("RealAudio RAAC"); + names[WAVE_FORMAT_RACP] = _T("RealAudio RACP"); + names[WAVE_FORMAT_SIPR] = _T("RealAudio SIPR"); + names[WAVE_FORMAT_PS2_PCM] = _T("PS2 PCM"); + names[WAVE_FORMAT_PS2_ADPCM] = _T("PS2 ADPCM"); + names[WAVE_FORMAT_AAC_ADTS] = _T("AAC"); // Specific to LAV Splitter and LAV Audio Decoder + // names[] = _T(""); + } + + // Check if we are bitstreaming to S/PDIF first to avoid misdetection as PCM + if (wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) { // Note that DTS bitstreaming uses the same format tag + str = _T("S/PDIF"); + } + // Check the subtype first after special cases have been handled + else if (subtype == MEDIASUBTYPE_PCM) { + str = _T("PCM"); + } else if (subtype == MEDIASUBTYPE_IEEE_FLOAT) { + str = _T("IEEE Float"); + } else if (subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO || subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { + str = _T("LPCM"); + } else if (subtype == MEDIASUBTYPE_Vorbis) { + str = _T("Vorbis (deprecated)"); + } else if (subtype == MEDIASUBTYPE_Vorbis2) { + str = _T("Vorbis"); + } else if (subtype == MEDIASUBTYPE_MP4A) { + str = _T("MPEG4 Audio"); + } else if (subtype == MEDIASUBTYPE_FLAC_FRAMED) { + str = _T("FLAC (framed)"); + } else if (subtype == MEDIASUBTYPE_DOLBY_AC3) { + str = _T("Dolby AC3"); + } else if (subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { + str = _T("DD+"); + } else if (subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { + str = _T("TrueHD"); + } else if (subtype == MEDIASUBTYPE_DTS) { + str = _T("DTS"); + } else if (subtype == MEDIASUBTYPE_MLP) { + str = _T("MLP"); + } else if (subtype == MEDIASUBTYPE_PCM_NONE || subtype == MEDIASUBTYPE_PCM_RAW || + subtype == MEDIASUBTYPE_PCM_TWOS || subtype == MEDIASUBTYPE_PCM_SOWT || + subtype == MEDIASUBTYPE_PCM_IN24 || subtype == MEDIASUBTYPE_PCM_IN32 || + subtype == MEDIASUBTYPE_PCM_FL32 || subtype == MEDIASUBTYPE_PCM_FL64) { + str = _T("QT PCM"); + } else if (subtype == MEDIASUBTYPE_IMA4 || + subtype == MEDIASUBTYPE_ADPCM_SWF || + subtype == MEDIASUBTYPE_ADPCM_AMV) { + str = _T("ADPCM"); + } else if (subtype == MEDIASUBTYPE_ALAC) { + str = _T("ALAC"); + } else if (subtype == MEDIASUBTYPE_ALS) { + str = _T("ALS"); + } else if (subtype == MEDIASUBTYPE_QDM2) { + str = _T("QDM2"); + } else if (subtype == MEDIASUBTYPE_AMR || + subtype == MEDIASUBTYPE_SAMR || + subtype == MEDIASUBTYPE_SAWB) { + str = _T("AMR"); + } else if (subtype == MEDIASUBTYPE_OPUS) { + str = _T("Opus"); + } // If the subtype wasn't enough to find the codec name, we try the format tag + else if (!names.Lookup(wFormatTag, str)) { + // If that fails, we have an unknown audio codec + str.Format(_T("0x%04x"), wFormatTag); + } + + return str; +} + +CString CMediaTypeEx::GetSubtitleCodecName(const GUID& subtype) +{ + CString str; + + static CAtlMap names; + + if (names.IsEmpty()) { + names[MEDIASUBTYPE_UTF8] = _T("UTF-8"); + names[MEDIASUBTYPE_SSA] = _T("SubStation Alpha"); + names[MEDIASUBTYPE_ASS] = _T("Advanced SubStation Alpha"); + names[MEDIASUBTYPE_ASS2] = _T("Advanced SubStation Alpha"); + names[MEDIASUBTYPE_USF] = _T("Universal Subtitle Format"); + names[MEDIASUBTYPE_VOBSUB] = _T("VobSub"); + names[MEDIASUBTYPE_DVB_SUBTITLES] = _T("DVB Subtitles"); + names[MEDIASUBTYPE_DVD_SUBPICTURE] = _T("DVD Subtitles"); + names[MEDIASUBTYPE_WEBVTT] = _T("WebVTT"); + } + + if (names.Lookup(subtype, str)) { + + } + + return str; +} + +void CMediaTypeEx::Dump(CAtlList& sl) +{ + CString str; + + sl.RemoveAll(); + + int fmtsize = 0; + + CString major = CStringFromGUID(majortype); + CString sub = CStringFromGUID(subtype); + CString format = CStringFromGUID(formattype); + + sl.AddTail(ToString() + _T("\n")); + + sl.AddTail(_T("AM_MEDIA_TYPE: ")); + str.Format(_T("majortype: %S %s"), GuidNames[majortype], major.GetString()); + sl.AddTail(str); + str.Format(_T("subtype: %S %s"), GuidNames[subtype], sub.GetString()); + sl.AddTail(str); + str.Format(_T("formattype: %S %s"), GuidNames[formattype], format.GetString()); + sl.AddTail(str); + str.Format(_T("bFixedSizeSamples: %d"), bFixedSizeSamples); + sl.AddTail(str); + str.Format(_T("bTemporalCompression: %d"), bTemporalCompression); + sl.AddTail(str); + str.Format(_T("lSampleSize: %lu"), lSampleSize); + sl.AddTail(str); + str.Format(_T("cbFormat: %lu"), cbFormat); + sl.AddTail(str); + + sl.AddTail(_T("")); + + if (formattype == FORMAT_VideoInfo || formattype == FORMAT_VideoInfo2 + || formattype == FORMAT_MPEGVideo || formattype == FORMAT_MPEG2_VIDEO) { + fmtsize = + formattype == FORMAT_VideoInfo ? sizeof(VIDEOINFOHEADER) : + formattype == FORMAT_VideoInfo2 ? sizeof(VIDEOINFOHEADER2) : + formattype == FORMAT_MPEGVideo ? sizeof(MPEG1VIDEOINFO) - 1 : + formattype == FORMAT_MPEG2_VIDEO ? sizeof(MPEG2VIDEOINFO) - 4 : + 0; + + VIDEOINFOHEADER& vih = *(VIDEOINFOHEADER*)pbFormat; + BITMAPINFOHEADER* bih = &vih.bmiHeader; + + sl.AddTail(_T("VIDEOINFOHEADER:")); + str.Format(_T("rcSource: (%ld,%ld)-(%ld,%ld)"), vih.rcSource.left, vih.rcSource.top, vih.rcSource.right, vih.rcSource.bottom); + sl.AddTail(str); + str.Format(_T("rcTarget: (%ld,%ld)-(%ld,%ld)"), vih.rcTarget.left, vih.rcTarget.top, vih.rcTarget.right, vih.rcTarget.bottom); + sl.AddTail(str); + str.Format(_T("dwBitRate: %u"), vih.dwBitRate); + sl.AddTail(str); + str.Format(_T("dwBitErrorRate: %u"), vih.dwBitErrorRate); + sl.AddTail(str); + str.Format(_T("AvgTimePerFrame: %I64d"), vih.AvgTimePerFrame); + sl.AddTail(str); + + sl.AddTail(_T("")); + + if (formattype == FORMAT_VideoInfo2 || formattype == FORMAT_MPEG2_VIDEO) { + VIDEOINFOHEADER2& vih2 = *(VIDEOINFOHEADER2*)pbFormat; + bih = &vih2.bmiHeader; + + sl.AddTail(_T("VIDEOINFOHEADER2:")); + str.Format(_T("dwInterlaceFlags: 0x%08x"), vih2.dwInterlaceFlags); + sl.AddTail(str); + str.Format(_T("dwCopyProtectFlags: 0x%08x"), vih2.dwCopyProtectFlags); + sl.AddTail(str); + str.Format(_T("dwPictAspectRatioX: %u"), vih2.dwPictAspectRatioX); + sl.AddTail(str); + str.Format(_T("dwPictAspectRatioY: %u"), vih2.dwPictAspectRatioY); + sl.AddTail(str); + str.Format(_T("dwControlFlags: 0x%08x"), vih2.dwControlFlags); + sl.AddTail(str); + str.Format(_T("dwReserved2: 0x%08x"), vih2.dwReserved2); + sl.AddTail(str); + + sl.AddTail(_T("")); + } + + if (formattype == FORMAT_MPEGVideo) { + MPEG1VIDEOINFO& mvih = *(MPEG1VIDEOINFO*)pbFormat; + + sl.AddTail(_T("MPEG1VIDEOINFO:")); + str.Format(_T("dwStartTimeCode: %u"), mvih.dwStartTimeCode); + sl.AddTail(str); + str.Format(_T("cbSequenceHeader: %u"), mvih.cbSequenceHeader); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (formattype == FORMAT_MPEG2_VIDEO) { + MPEG2VIDEOINFO& mvih = *(MPEG2VIDEOINFO*)pbFormat; + + sl.AddTail(_T("MPEG2VIDEOINFO:")); + str.Format(_T("dwStartTimeCode: %u"), mvih.dwStartTimeCode); + sl.AddTail(str); + str.Format(_T("cbSequenceHeader: %u"), mvih.cbSequenceHeader); + sl.AddTail(str); + str.Format(_T("dwProfile: 0x%08x"), mvih.dwProfile); + sl.AddTail(str); + str.Format(_T("dwLevel: 0x%08x"), mvih.dwLevel); + sl.AddTail(str); + str.Format(_T("dwFlags: 0x%08x"), mvih.dwFlags); + sl.AddTail(str); + + sl.AddTail(_T("")); + } + + sl.AddTail(_T("BITMAPINFOHEADER:")); + str.Format(_T("biSize: %u"), bih->biSize); + sl.AddTail(str); + str.Format(_T("biWidth: %ld"), bih->biWidth); + sl.AddTail(str); + str.Format(_T("biHeight: %ld"), bih->biHeight); + sl.AddTail(str); + str.Format(_T("biPlanes: %u"), bih->biPlanes); + sl.AddTail(str); + str.Format(_T("biBitCount: %u"), bih->biBitCount); + sl.AddTail(str); + if (bih->biCompression < 256) { + str.Format(_T("biCompression: %u"), bih->biCompression); + } else { + str.Format(_T("biCompression: %4.4hs"), &bih->biCompression); + } + sl.AddTail(str); + str.Format(_T("biSizeImage: %u"), bih->biSizeImage); + sl.AddTail(str); + str.Format(_T("biXPelsPerMeter: %ld"), bih->biXPelsPerMeter); + sl.AddTail(str); + str.Format(_T("biYPelsPerMeter: %ld"), bih->biYPelsPerMeter); + sl.AddTail(str); + str.Format(_T("biClrUsed: %u"), bih->biClrUsed); + sl.AddTail(str); + str.Format(_T("biClrImportant: %u"), bih->biClrImportant); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (formattype == FORMAT_WaveFormatEx || formattype == FORMAT_WaveFormatExFFMPEG) { + WAVEFORMATEX* pWfe = nullptr; + if (formattype == FORMAT_WaveFormatExFFMPEG) { + fmtsize = sizeof(WAVEFORMATEXFFMPEG); + + WAVEFORMATEXFFMPEG* wfeff = (WAVEFORMATEXFFMPEG*)pbFormat; + pWfe = &wfeff->wfex; + + sl.AddTail(_T("WAVEFORMATEXFFMPEG:")); + str.Format(_T("nCodecId: 0x%04x"), wfeff->nCodecId); + sl.AddTail(str); + sl.AddTail(_T("")); + } else { + fmtsize = sizeof(WAVEFORMATEX); + pWfe = (WAVEFORMATEX*)pbFormat; + } + + WAVEFORMATEX& wfe = *pWfe; + + sl.AddTail(_T("WAVEFORMATEX:")); + str.Format(_T("wFormatTag: 0x%04x"), wfe.wFormatTag); + sl.AddTail(str); + str.Format(_T("nChannels: %u"), wfe.nChannels); + sl.AddTail(str); + str.Format(_T("nSamplesPerSec: %u"), wfe.nSamplesPerSec); + sl.AddTail(str); + str.Format(_T("nAvgBytesPerSec: %u"), wfe.nAvgBytesPerSec); + sl.AddTail(str); + str.Format(_T("nBlockAlign: %u"), wfe.nBlockAlign); + sl.AddTail(str); + str.Format(_T("wBitsPerSample: %u"), wfe.wBitsPerSample); + sl.AddTail(str); + str.Format(_T("cbSize: %u (extra bytes)"), wfe.cbSize); + sl.AddTail(str); + + sl.AddTail(_T("")); + + if (wfe.wFormatTag != WAVE_FORMAT_PCM && wfe.cbSize > 0 && formattype == FORMAT_WaveFormatEx) { + if (wfe.wFormatTag == WAVE_FORMAT_EXTENSIBLE && wfe.cbSize == sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { + fmtsize = sizeof(WAVEFORMATEXTENSIBLE); + + WAVEFORMATEXTENSIBLE& wfextensible = *(WAVEFORMATEXTENSIBLE*)pbFormat; + + sl.AddTail(_T("WAVEFORMATEXTENSIBLE:")); + if (wfextensible.Format.wBitsPerSample != 0) { + str.Format(_T("wValidBitsPerSample: %u"), wfextensible.Samples.wValidBitsPerSample); + } else { + str.Format(_T("wSamplesPerBlock: %u"), wfextensible.Samples.wSamplesPerBlock); + } + sl.AddTail(str); + str.Format(_T("dwChannelMask: 0x%08x"), wfextensible.dwChannelMask); + sl.AddTail(str); + str.Format(_T("SubFormat: %s"), CStringFromGUID(wfextensible.SubFormat).GetString()); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (wfe.wFormatTag == WAVE_FORMAT_DOLBY_AC3 && wfe.cbSize == sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX)) { + fmtsize = sizeof(DOLBYAC3WAVEFORMAT); + + DOLBYAC3WAVEFORMAT& dawf = *(DOLBYAC3WAVEFORMAT*)pbFormat; + + sl.AddTail(_T("DOLBYAC3WAVEFORMAT:")); + str.Format(_T("bBigEndian: %u"), dawf.bBigEndian); + sl.AddTail(str); + str.Format(_T("bsid: %u"), dawf.bsid); + sl.AddTail(str); + str.Format(_T("lfeon: %u"), dawf.lfeon); + sl.AddTail(str); + str.Format(_T("copyrightb: %u"), dawf.copyrightb); + sl.AddTail(str); + str.Format(_T("nAuxBitsCode: %u"), dawf.nAuxBitsCode); + sl.AddTail(str); + + sl.AddTail(_T("")); + } + } + } else if (formattype == FORMAT_VorbisFormat) { + fmtsize = sizeof(VORBISFORMAT); + + VORBISFORMAT& vf = *(VORBISFORMAT*)pbFormat; + + sl.AddTail(_T("VORBISFORMAT:")); + str.Format(_T("nChannels: %u"), vf.nChannels); + sl.AddTail(str); + str.Format(_T("nSamplesPerSec: %lu"), vf.nSamplesPerSec); + sl.AddTail(str); + str.Format(_T("nMinBitsPerSec: %lu"), vf.nMinBitsPerSec); + sl.AddTail(str); + str.Format(_T("nAvgBitsPerSec: %lu"), vf.nAvgBitsPerSec); + sl.AddTail(str); + str.Format(_T("nMaxBitsPerSec: %lu"), vf.nMaxBitsPerSec); + sl.AddTail(str); + str.Format(_T("fQuality: %.3f"), vf.fQuality); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (formattype == FORMAT_VorbisFormat2) { + fmtsize = sizeof(VORBISFORMAT2); + + VORBISFORMAT2& vf = *(VORBISFORMAT2*)pbFormat; + + sl.AddTail(_T("VORBISFORMAT:")); + str.Format(_T("Channels: %lu"), vf.Channels); + sl.AddTail(str); + str.Format(_T("SamplesPerSec: %lu"), vf.SamplesPerSec); + sl.AddTail(str); + str.Format(_T("BitsPerSample: %lu"), vf.BitsPerSample); + sl.AddTail(str); + str.Format(_T("HeaderSize: {%lu, %lu, %lu}"), vf.HeaderSize[0], vf.HeaderSize[1], vf.HeaderSize[2]); + sl.AddTail(str); + + sl.AddTail(_T("")); + } else if (formattype == FORMAT_SubtitleInfo) { + fmtsize = sizeof(SUBTITLEINFO); + + SUBTITLEINFO& si = *(SUBTITLEINFO*)pbFormat; + + sl.AddTail(_T("SUBTITLEINFO:")); + str.Format(_T("dwOffset: %lu"), si.dwOffset); + sl.AddTail(str); + str.Format(_T("IsoLang: %S"), CStringA(si.IsoLang, sizeof(si.IsoLang) - 1).GetString()); + sl.AddTail(str); + str.Format(_T("TrackName: %s"), CStringW(si.TrackName, sizeof(si.TrackName) - 1).GetString()); + sl.AddTail(str); + + sl.AddTail(_T("")); + } + + if (cbFormat > 0) { + sl.AddTail(_T("pbFormat:")); + + for (ptrdiff_t i = 0, j = (cbFormat + 15) & ~15; i < j; i += 16) { + str.Format(_T("%04Ix:"), i); + + for (ptrdiff_t k = i, l = std::min(i + 16, (ptrdiff_t)cbFormat); k < l; k++) { + CString byte; + byte.Format(_T("%c%02x"), fmtsize > 0 && fmtsize == k ? '|' : ' ', pbFormat[k]); + str += byte; + } + + for (ptrdiff_t k = std::min(i + 16, (ptrdiff_t)cbFormat), l = i + 16; k < l; k++) { + str += _T(" "); + } + + str += _T(' '); + + for (ptrdiff_t k = i, l = std::min(i + 16, (ptrdiff_t)cbFormat); k < l; k++) { + unsigned char c = (unsigned char)pbFormat[k]; + CString ch; + ch.Format(_T("%C"), c >= 0x20 ? c : '.'); + str += ch; + } + + sl.AddTail(str); + } + + sl.AddTail(_T("")); + } +} diff --git a/src/DSUtil/MediaTypeEx.h b/src/DSUtil/MediaTypeEx.h index 10d15b436c8..63ec7e0c1fd 100644 --- a/src/DSUtil/MediaTypeEx.h +++ b/src/DSUtil/MediaTypeEx.h @@ -1,42 +1,42 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#pragma once - -#include - -class CMediaTypeEx : public CMediaType -{ -public: - CMediaTypeEx(); - ~CMediaTypeEx(); - CMediaTypeEx(const CMediaType& mt) { - CMediaType::operator = (mt); - } - - CString ToString(IPin* pPin = nullptr); - - static CString GetVideoCodecName(const GUID& subtype, DWORD biCompression); - static CString GetAudioCodecName(const GUID& subtype, WORD wFormatTag); - static CString GetSubtitleCodecName(const GUID& subtype); - - void Dump(CAtlList& sl); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#pragma once + +#include + +class CMediaTypeEx : public CMediaType +{ +public: + CMediaTypeEx(); + ~CMediaTypeEx(); + CMediaTypeEx(const CMediaType& mt) { + CMediaType::operator = (mt); + } + + CString ToString(IPin* pPin = nullptr); + + static CString GetVideoCodecName(const GUID& subtype, DWORD biCompression); + static CString GetAudioCodecName(const GUID& subtype, WORD wFormatTag); + static CString GetSubtitleCodecName(const GUID& subtype); + + void Dump(CAtlList& sl); +}; diff --git a/src/DSUtil/MediaTypes.cpp b/src/DSUtil/MediaTypes.cpp index 158a43be670..efa66a4c9e8 100644 --- a/src/DSUtil/MediaTypes.cpp +++ b/src/DSUtil/MediaTypes.cpp @@ -1,463 +1,463 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include "moreuuids.h" -#include "MediaTypes.h" -#include "DSUtil.h" - -#define VIH_NORMAL (sizeof(VIDEOINFOHEADER)) -#define VIH_BITFIELDS (sizeof(VIDEOINFOHEADER) + 3 * sizeof(RGBQUAD)) -#define VIH2_NORMAL (sizeof(VIDEOINFOHEADER2)) -#define VIH2_BITFIELDS (sizeof(VIDEOINFOHEADER2) + 3 * sizeof(RGBQUAD)) -#define BIH_SIZE (sizeof(BITMAPINFOHEADER)) - -const VIH vihs[] = { - // VYUY - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('V', 'Y', 'U', 'Y'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_VYUY // subtype - }, - // YVYU - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'V', 'Y', 'U'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_YVYU // subtype - }, - // UYVY - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_UYVY // subtype - }, - // YUY2 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_YUY2 // subtype - }, - // YV12 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_YV12 // subtype - }, - // I420 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', '4', '2', '0'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_I420 // subtype - }, - // IYUV - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', 'Y', 'U', 'V'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_IYUV // subtype - }, - // NV12 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('N', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_NV12 // subtype - }, - // 8888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_RGB32 // subtype - }, - // 8888 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_RGB32 // subtype - }, - // A888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_ARGB32 // subtype - }, - // A888 bitf (I'm not sure if this exist...) - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_ARGB32 // subtype - }, - // 888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 24, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_RGB24 // subtype - }, - // 888 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 24, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_RGB24 // subtype - }, - // 565 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_RGB565 // subtype - }, - // 565 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xF800, 0x07E0, 0x001F}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_RGB565 // subtype - }, - // 555 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH_NORMAL, // size - &MEDIASUBTYPE_RGB555 // subtype - }, - // 555 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0x7C00, 0x03E0, 0x001F}, // mask[3] - VIH_BITFIELDS, // size - &MEDIASUBTYPE_RGB555 // subtype - }, -}; - -const VIH2 vih2s[] = { - // VYUY - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('V', 'Y', 'U', 'Y'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_VYUY // subtype - }, - // YVYU - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'V', 'Y', 'U'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_YVYU // subtype - }, - // UYVY - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_UYVY // subtype - }, - // YUY2 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_YUY2 // subtype - }, - // YV12 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_YV12 // subtype - }, - // I420 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', '4', '2', '0'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_I420 // subtype - }, - // IYUV - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', 'Y', 'U', 'V'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_IYUV // subtype - }, - // NV12 - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('N', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_NV12 // subtype - }, - // 8888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_RGB32 // subtype - }, - // 8888 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_RGB32 // subtype - }, - // A888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_ARGB32 // subtype - }, - // A888 bitf (I'm not sure if this exist...) - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_ARGB32 // subtype - }, - // 888 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 24, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_RGB24 // subtype - }, - // 888 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 24, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_RGB24 // subtype - }, - // 565 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_RGB565 // subtype - }, - // 565 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0xF800, 0x07E0, 0x001F}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_RGB565 // subtype - }, - // 555 normal - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader - }, - {0, 0, 0}, // mask[3] - VIH2_NORMAL, // size - &MEDIASUBTYPE_RGB555 // subtype - }, - // 555 bitf - { - { - {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, - {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader - }, - {0x7C00, 0x03E0, 0x001F}, // mask[3] - VIH2_BITFIELDS, // size - &MEDIASUBTYPE_RGB555 // subtype - }, -}; - -extern const UINT VIHSIZE = _countof(vihs); - -CString VIH2String(int i) -{ - CString ret(GuidNames[*vihs[i].subtype]); - if (!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) { - ret = ret.Mid(13); - } - if (vihs[i].vih.bmiHeader.biCompression == 3) { - ret += _T(" BITF"); - } - if (*vihs[i].subtype == MEDIASUBTYPE_I420) { - ret = _T("I420"); // FIXME - } - return ret; -} - -CString Subtype2String(const GUID& subtype) -{ - CString ret(GuidNames[subtype]); - if (!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) { - ret = ret.Mid(13); - } - if (subtype == MEDIASUBTYPE_I420) { - ret = _T("I420"); // FIXME - } - return ret; -} - -void CorrectMediaType(AM_MEDIA_TYPE* pmt) -{ - if (!pmt) { - return; - } - - CMediaType mt(*pmt); - - if (mt.formattype == FORMAT_VideoInfo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mt.pbFormat; - - for (UINT i = 0; i < VIHSIZE; i++) { - if (mt.subtype == *vihs[i].subtype - && vih->bmiHeader.biCompression == vihs[i].vih.bmiHeader.biCompression) { - mt.AllocFormatBuffer(vihs[i].size); - memcpy(mt.pbFormat, &vihs[i], vihs[i].size); - memcpy(mt.pbFormat, pmt->pbFormat, sizeof(VIDEOINFOHEADER)); - break; - } - } - } else if (mt.formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mt.pbFormat; - - for (UINT i = 0; i < VIHSIZE; i++) { - if (mt.subtype == *vih2s[i].subtype - && vih2->bmiHeader.biCompression == vih2s[i].vih.bmiHeader.biCompression) { - mt.AllocFormatBuffer(vih2s[i].size); - memcpy(mt.pbFormat, &vih2s[i], vih2s[i].size); - memcpy(mt.pbFormat, pmt->pbFormat, sizeof(VIDEOINFOHEADER2)); - break; - } - } - } - - CopyMediaType(pmt, &mt); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include "moreuuids.h" +#include "MediaTypes.h" +#include "DSUtil.h" + +#define VIH_NORMAL (sizeof(VIDEOINFOHEADER)) +#define VIH_BITFIELDS (sizeof(VIDEOINFOHEADER) + 3 * sizeof(RGBQUAD)) +#define VIH2_NORMAL (sizeof(VIDEOINFOHEADER2)) +#define VIH2_BITFIELDS (sizeof(VIDEOINFOHEADER2) + 3 * sizeof(RGBQUAD)) +#define BIH_SIZE (sizeof(BITMAPINFOHEADER)) + +const VIH vihs[] = { + // VYUY + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('V', 'Y', 'U', 'Y'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_VYUY // subtype + }, + // YVYU + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'V', 'Y', 'U'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_YVYU // subtype + }, + // UYVY + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_UYVY // subtype + }, + // YUY2 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_YUY2 // subtype + }, + // YV12 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_YV12 // subtype + }, + // I420 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', '4', '2', '0'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_I420 // subtype + }, + // IYUV + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', 'Y', 'U', 'V'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_IYUV // subtype + }, + // NV12 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('N', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_NV12 // subtype + }, + // 8888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_RGB32 // subtype + }, + // 8888 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_RGB32 // subtype + }, + // A888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_ARGB32 // subtype + }, + // A888 bitf (I'm not sure if this exist...) + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_ARGB32 // subtype + }, + // 888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 24, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_RGB24 // subtype + }, + // 888 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 24, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_RGB24 // subtype + }, + // 565 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_RGB565 // subtype + }, + // 565 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xF800, 0x07E0, 0x001F}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_RGB565 // subtype + }, + // 555 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH_NORMAL, // size + &MEDIASUBTYPE_RGB555 // subtype + }, + // 555 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0x7C00, 0x03E0, 0x001F}, // mask[3] + VIH_BITFIELDS, // size + &MEDIASUBTYPE_RGB555 // subtype + }, +}; + +const VIH2 vih2s[] = { + // VYUY + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('V', 'Y', 'U', 'Y'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_VYUY // subtype + }, + // YVYU + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'V', 'Y', 'U'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_YVYU // subtype + }, + // UYVY + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('U', 'Y', 'V', 'Y'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_UYVY // subtype + }, + // YUY2 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, mmioFOURCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_YUY2 // subtype + }, + // YV12 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('Y', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_YV12 // subtype + }, + // I420 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', '4', '2', '0'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_I420 // subtype + }, + // IYUV + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('I', 'Y', 'U', 'V'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_IYUV // subtype + }, + // NV12 + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 12, mmioFOURCC('N', 'V', '1', '2'), 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_NV12 // subtype + }, + // 8888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_RGB32 // subtype + }, + // 8888 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_RGB32 // subtype + }, + // A888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_ARGB32 // subtype + }, + // A888 bitf (I'm not sure if this exist...) + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_ARGB32 // subtype + }, + // 888 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 24, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_RGB24 // subtype + }, + // 888 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 24, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xFF0000, 0x00FF00, 0x0000FF}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_RGB24 // subtype + }, + // 565 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_RGB565 // subtype + }, + // 565 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0xF800, 0x07E0, 0x001F}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_RGB565 // subtype + }, + // 555 normal + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_RGB, 0, 0, 0, 0, 0} // bmiHeader + }, + {0, 0, 0}, // mask[3] + VIH2_NORMAL, // size + &MEDIASUBTYPE_RGB555 // subtype + }, + // 555 bitf + { + { + {0, 0, 0, 0}, {0, 0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, + {BIH_SIZE, 0, 0, 1, 16, BI_BITFIELDS, 0, 0, 0, 0, 0} // bmiHeader + }, + {0x7C00, 0x03E0, 0x001F}, // mask[3] + VIH2_BITFIELDS, // size + &MEDIASUBTYPE_RGB555 // subtype + }, +}; + +extern const UINT VIHSIZE = _countof(vihs); + +CString VIH2String(int i) +{ + CString ret(GuidNames[*vihs[i].subtype]); + if (!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) { + ret = ret.Mid(13); + } + if (vihs[i].vih.bmiHeader.biCompression == 3) { + ret += _T(" BITF"); + } + if (*vihs[i].subtype == MEDIASUBTYPE_I420) { + ret = _T("I420"); // FIXME + } + return ret; +} + +CString Subtype2String(const GUID& subtype) +{ + CString ret(GuidNames[subtype]); + if (!ret.Left(13).CompareNoCase(_T("MEDIASUBTYPE_"))) { + ret = ret.Mid(13); + } + if (subtype == MEDIASUBTYPE_I420) { + ret = _T("I420"); // FIXME + } + return ret; +} + +void CorrectMediaType(AM_MEDIA_TYPE* pmt) +{ + if (!pmt) { + return; + } + + CMediaType mt(*pmt); + + if (mt.formattype == FORMAT_VideoInfo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)mt.pbFormat; + + for (UINT i = 0; i < VIHSIZE; i++) { + if (mt.subtype == *vihs[i].subtype + && vih->bmiHeader.biCompression == vihs[i].vih.bmiHeader.biCompression) { + mt.AllocFormatBuffer(vihs[i].size); + memcpy(mt.pbFormat, &vihs[i], vihs[i].size); + memcpy(mt.pbFormat, pmt->pbFormat, sizeof(VIDEOINFOHEADER)); + break; + } + } + } else if (mt.formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mt.pbFormat; + + for (UINT i = 0; i < VIHSIZE; i++) { + if (mt.subtype == *vih2s[i].subtype + && vih2->bmiHeader.biCompression == vih2s[i].vih.bmiHeader.biCompression) { + mt.AllocFormatBuffer(vih2s[i].size); + memcpy(mt.pbFormat, &vih2s[i], vih2s[i].size); + memcpy(mt.pbFormat, pmt->pbFormat, sizeof(VIDEOINFOHEADER2)); + break; + } + } + } + + CopyMediaType(pmt, &mt); +} diff --git a/src/DSUtil/MediaTypes.h b/src/DSUtil/MediaTypes.h index 7e5f3d4466c..91919bf3ca9 100644 --- a/src/DSUtil/MediaTypes.h +++ b/src/DSUtil/MediaTypes.h @@ -1,48 +1,48 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include - -#pragma pack(push, 1) -struct VIH { - VIDEOINFOHEADER vih; - UINT mask[3]; - int size; - const GUID* subtype; -}; - -struct VIH2 { - VIDEOINFOHEADER2 vih; - UINT mask[3]; - int size; - const GUID* subtype; -}; -#pragma pack(pop) - -extern const VIH vihs[]; -extern const VIH2 vih2s[]; - -extern const UINT VIHSIZE; - -extern CString VIH2String(int i), Subtype2String(const GUID& subtype); -extern void CorrectMediaType(AM_MEDIA_TYPE* pmt); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include + +#pragma pack(push, 1) +struct VIH { + VIDEOINFOHEADER vih; + UINT mask[3]; + int size; + const GUID* subtype; +}; + +struct VIH2 { + VIDEOINFOHEADER2 vih; + UINT mask[3]; + int size; + const GUID* subtype; +}; +#pragma pack(pop) + +extern const VIH vihs[]; +extern const VIH2 vih2s[]; + +extern const UINT VIHSIZE; + +extern CString VIH2String(int i), Subtype2String(const GUID& subtype); +extern void CorrectMediaType(AM_MEDIA_TYPE* pmt); diff --git a/src/DSUtil/Mpeg2Def.h b/src/DSUtil/Mpeg2Def.h index 39473c91289..777da480d51 100644 --- a/src/DSUtil/Mpeg2Def.h +++ b/src/DSUtil/Mpeg2Def.h @@ -1,200 +1,200 @@ -/* - * (C) 2009-2015 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 . - * - */ - -#pragma once - -enum PES_STREAM_TYPE { - INVALID = 0, - VIDEO_STREAM_MPEG1 = 0x01, - VIDEO_STREAM_MPEG2 = 0x02, // ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream - AUDIO_STREAM_MPEG1 = 0x03, // all layers including mp3 (ISO/IEC 11172-3 Audio) - AUDIO_STREAM_MPEG2 = 0x04, // ISO/IEC 13818-3 Audio - PRIVATE = 0x05, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections - PES_PRIVATE = 0x06, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data - PES_07 = 0x07, // ISO/IEC 13522 MHEG - PES_08 = 0x08, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC - PES_09 = 0x09, // ITU-T Rec. H.222.1 - PES_0a = 0x0a, // ISO/IEC 13818-6 type A - PES_0b = 0x0b, // ISO/IEC 13818-6 type B - PES_0c = 0x0c, // ISO/IEC 13818-6 type C - PES_0d = 0x0d, // ISO/IEC 13818-6 type D - PES_0e = 0x0e, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary - AUDIO_STREAM_AAC = 0x0f, // ISO/IEC 13818-7 Audio with ADTS transport syntax - PES_10 = 0x10, // ISO/IEC 14496-2 Visual - AUDIO_STREAM_AAC_LATM = 0x11, // ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1 - PES_12 = 0x12, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets - PES_13 = 0x13, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections. - PES_14 = 0x14, // ISO/IEC 13818-6 Synchronized Download Protocol - METADATA_PES_PACKETS = 0x15, // Metadata carried in PES packets - METADATA_SECTIONS = 0X16, // Metadata carried in metadata_sections - DATA_CAROUSEL = 0x17, // Metadata carried in ISO/IEC 13818-6 Data Carousel - OBJECT_CAROUSEL = 0x18, // Metadata carried in ISO/IEC 13818-6 Object Carousel - SYNCHRONIZED_DOWNLOAD = 0x19, // Metadata carried in ISO/IEC 13818-6 Synchronized Download Protocol - IPMP = 0x1A, // IPMP stream (defined in ISO/IEC 13818-11, MPEG-2 IPMP) - VIDEO_STREAM_H264 = 0x1B, // AVC video stream conforming to one or more profiles defined in Annex A of ITU-T Rec. H.264 - PES_1C = 0x1C, // ISO/IEC 14496-3 Audio, without using any additional transport syntax, such as DST, ALS and SLS - TEXT = 0x1D, // ISO/IEC 14496-17 Text - AUXILIARY_VIDEO_STREAM = 0x1E, // Auxiliary video stream as defined in ISO/IEC 23002-3 - SVC_H264 = 0x1F, // SVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex G of ITU-T Rec. H.264 | ISO/IEC 14496-10 - MVC_H264 = 0x20, // MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10 - VIDEO_STREAM_JPEG2000 = 0x21, // ITU - T Rec.T.800 | ISO / IEC 15444 - 1 - ADDITIONAL_VIEW_MPEG2 = 0x22, // ITU - T Rec.H.262 | ISO / IEC 13818 - 2 Additional view for compatible 3D - ADDITIONAL_VIEW_H264 = 0x23, // ITU - T Rec.H.264 | ISO / IEC 14496 - 10 Additional view for compatible 3D - VIDEO_STREAM_HEVC = 0x24, // ITU - T Rec.H.265 | ISO / IEC 23008 - 2 video stream - VIDEO_SUBSET_HEVC = 0x25, // ITU - T Rec.H.265 | ISO / IEC 23008 - 2 Annex A temporal video subset - MVCD_H264 = 0x26, // ITU - T Rec.H.264 | ISO / IEC 14496 - 10 Annex I MVCD video sub - bitstream - AUDIO_STREAM_LPCM = 0x80, - AUDIO_STREAM_AC3 = 0x81, - AUDIO_STREAM_DTS = 0x82, - AUDIO_STREAM_AC3_TRUE_HD = 0x83, - AUDIO_STREAM_AC3_PLUS = 0x84, - AUDIO_STREAM_DTS_HD = 0x85, - AUDIO_STREAM_DTS_HD_MASTER_AUDIO = 0x86, - PRESENTATION_GRAPHICS_STREAM = 0x90, - INTERACTIVE_GRAPHICS_STREAM = 0x91, - SUBTITLE_STREAM = 0x92, - SECONDARY_AUDIO_AC3_PLUS = 0xa1, - SECONDARY_AUDIO_DTS_HD = 0xa2, - VIDEO_STREAM_VC1 = 0xea -}; - -enum MPEG2_PID { - PID_PAT = 0x000, // Program Association Table - PID_CAT = 0x001, // Conditional Access Table - PID_TSDT = 0x002, // Transport Stream Description Table - PID_NIT = 0x010, // Network Identification Table - PID_BAT = 0x011, // Bouquet Association Table or ... - PID_SDT = 0x011, // ... Service Description Table - PID_EIT = 0x012, // Event Information Table - PID_RST = 0x013, // Running Status Table - PID_TDT = 0x014, // Time and Date Table or ... - PID_TOT = 0x014, // ... Time Offset Table - PID_SFN = 0x015, // SFN/MIP synchronization - PID_DIT = 0x01e, - PID_SIT = 0x01f, - PID_ATSC_PAT_E = 0x1FF7, - PID_PSIP_TS_E = 0x1FF9, - PID_PSIP = 0x1FFB, - PID_NULL = 0x1fff // Null packet -}; - -enum DVB_SI { - SI_undef = -1, - SI_PAT = 0x00, - SI_CAT = 0x01, - SI_PMT = 0x02, - SI_DSMCC_a = 0x3a, - SI_DSMCC_b = 0x3b, - SI_DSMCC_c = 0x3c, - SI_DSMCC_d = 0x3d, - SI_DSMCC_e = 0x3e, - SI_DSMCC_f = 0x3f, - SI_NIT = 0x40, - SI_SDT = 0x42, - SI_EIT_act = 0x4e, - SI_EIT_oth = 0x4f, - SI_EIT_as0, SI_EIT_as1, SI_EIT_as2, SI_EIT_as3, SI_EIT_as4, SI_EIT_as5, SI_EIT_as6, SI_EIT_as7, - SI_EIT_as8, SI_EIT_as9, SI_EIT_asa, SI_EIT_asb, SI_EIT_asc, SI_EIT_asd, SI_EIT_ase, SI_EIT_asf, - SI_EIT_os0, SI_EIT_os1, SI_EIT_os2, SI_EIT_os3, SI_EIT_os4, SI_EIT_os5, SI_EIT_os6, SI_EIT_os7, - SI_EIT_os8, SI_EIT_os9, SI_EIT_osa, SI_EIT_osb, SI_EIT_osc, SI_EIT_osd, SI_EIT_ose, SI_EIT_osf, - TID_MGT = 0xC7, - TID_TVCT = 0xC8, - TID_CVCT = 0xC9 -}; - -enum ATSC_TABLE_TYPE { - TT_TVCT_C1 = 0x0000, - TT_TVCT_C0 = 0x0001, - TT_CVCT_C1 = 0x0002, - TT_CVCT_C0 = 0x0003, - TT_ETT = 0x0004, - TT_DCCSCT = 0x0005, -}; - -enum MPEG2_DESCRIPTOR { - // http://www.coolstf.com/tsreader/descriptors.html - DT_VIDEO_STREAM = 0x02, - DT_AUDIO_STREAM = 0x03, - DT_HIERARCHY = 0x04, - DT_REGISTRATION = 0x05, - DT_DATA_STREAM_ALIGNMENT = 0x06, - DT_TARGET_BACKGROUND_GRID = 0x07, - DT_VIDEO_WINDOW = 0x08, - DT_CONDITIONAL_ACCESS = 0x09, - DT_ISO_639_LANGUAGE = 0x0a, - DT_SYSTEM_CLOCK = 0x0b, - DT_MULTIPLEX_BUFFER_UTIL = 0x0c, - DT_COPYRIGHT_DESCRIPTOR = 0x0d, - DT_MAXIMUM_BITRATE = 0x0e, - DT_PRIVATE_DATA_INDICATOR = 0x0f, - DT_SMOOTHING_BUFFER = 0x10, - DT_STD = 0x11, // System Target Decoder ? - DT_IBP = 0x12, - DT_NETWORK_NAME = 0x40, - DT_SERVICE_LIST = 0x41, - DT_VBI_DATA = 0x45, - DT_SERVICE = 0x48, - DT_LINKAGE = 0x4a, - DT_SHORT_EVENT = 0x4d, - DT_EXTENDED_EVENT = 0x4e, - DT_COMPONENT = 0x50, - DT_STREAM_IDENTIFIER = 0x52, - DT_CONTENT = 0x54, - DT_PARENTAL_RATING = 0x55, - DT_TELETEXT = 0x56, - DT_SUBTITLING = 0x59, - DT_TERRESTRIAL_DELIV_SYS = 0x5a, - DT_PRIVATE_DATA = 0x5f, - DID_DATA_BROADCAST = 0x64, - DT_DATA_BROADCAST_ID = 0x66, - DT_AC3_AUDIO = 0x6a, // DVB - DT_EXTENDED_AC3_AUDIO = 0x7a, - DT_AAC_AUDIO = 0x7c, - - DT_AC3_AUDIO__2 = 0x81, // DCII or ATSC - DT_LOGICAL_CHANNEL = 0x83, - DT_HD_SIMCAST_LOG_CHANNEL = 0x88 -}; - -enum MPEG_TYPES { - mpeg_us, - mpeg_ps, - mpeg_ts, - mpeg_es, - mpeg_pva -}; - -enum SERVICE_TYPE { - DIGITAL_TV = 0x01, - DIGITAL_RADIO = 0x02, - AVC_DIGITAL_RADIO = 0x0A, - MPEG2_HD_DIGITAL_TV = 0x11, - AVC_SD_TV = 0x16, - AVC_HD_TV = 0x19, - HEVC_TV = 0x1F -}; - -enum ATSC_SERVICE_TYPE { - ATSC_ANALOG_TV = 0x01, - ATSC_DIGITAL_TV = 0x02, - ATSC_AUDIO = 0x03 -}; - -extern const wchar_t* StreamTypeToName(PES_STREAM_TYPE _Type); +/* + * (C) 2009-2015 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 . + * + */ + +#pragma once + +enum PES_STREAM_TYPE { + INVALID = 0, + VIDEO_STREAM_MPEG1 = 0x01, + VIDEO_STREAM_MPEG2 = 0x02, // ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream + AUDIO_STREAM_MPEG1 = 0x03, // all layers including mp3 (ISO/IEC 11172-3 Audio) + AUDIO_STREAM_MPEG2 = 0x04, // ISO/IEC 13818-3 Audio + PRIVATE = 0x05, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections + PES_PRIVATE = 0x06, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data + PES_07 = 0x07, // ISO/IEC 13522 MHEG + PES_08 = 0x08, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC + PES_09 = 0x09, // ITU-T Rec. H.222.1 + PES_0a = 0x0a, // ISO/IEC 13818-6 type A + PES_0b = 0x0b, // ISO/IEC 13818-6 type B + PES_0c = 0x0c, // ISO/IEC 13818-6 type C + PES_0d = 0x0d, // ISO/IEC 13818-6 type D + PES_0e = 0x0e, // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary + AUDIO_STREAM_AAC = 0x0f, // ISO/IEC 13818-7 Audio with ADTS transport syntax + PES_10 = 0x10, // ISO/IEC 14496-2 Visual + AUDIO_STREAM_AAC_LATM = 0x11, // ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1 + PES_12 = 0x12, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets + PES_13 = 0x13, // ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections. + PES_14 = 0x14, // ISO/IEC 13818-6 Synchronized Download Protocol + METADATA_PES_PACKETS = 0x15, // Metadata carried in PES packets + METADATA_SECTIONS = 0X16, // Metadata carried in metadata_sections + DATA_CAROUSEL = 0x17, // Metadata carried in ISO/IEC 13818-6 Data Carousel + OBJECT_CAROUSEL = 0x18, // Metadata carried in ISO/IEC 13818-6 Object Carousel + SYNCHRONIZED_DOWNLOAD = 0x19, // Metadata carried in ISO/IEC 13818-6 Synchronized Download Protocol + IPMP = 0x1A, // IPMP stream (defined in ISO/IEC 13818-11, MPEG-2 IPMP) + VIDEO_STREAM_H264 = 0x1B, // AVC video stream conforming to one or more profiles defined in Annex A of ITU-T Rec. H.264 + PES_1C = 0x1C, // ISO/IEC 14496-3 Audio, without using any additional transport syntax, such as DST, ALS and SLS + TEXT = 0x1D, // ISO/IEC 14496-17 Text + AUXILIARY_VIDEO_STREAM = 0x1E, // Auxiliary video stream as defined in ISO/IEC 23002-3 + SVC_H264 = 0x1F, // SVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex G of ITU-T Rec. H.264 | ISO/IEC 14496-10 + MVC_H264 = 0x20, // MVC video sub-bitstream of an AVC video stream conforming to one or more profiles defined in Annex H of ITU-T Rec. H.264 | ISO/IEC 14496-10 + VIDEO_STREAM_JPEG2000 = 0x21, // ITU - T Rec.T.800 | ISO / IEC 15444 - 1 + ADDITIONAL_VIEW_MPEG2 = 0x22, // ITU - T Rec.H.262 | ISO / IEC 13818 - 2 Additional view for compatible 3D + ADDITIONAL_VIEW_H264 = 0x23, // ITU - T Rec.H.264 | ISO / IEC 14496 - 10 Additional view for compatible 3D + VIDEO_STREAM_HEVC = 0x24, // ITU - T Rec.H.265 | ISO / IEC 23008 - 2 video stream + VIDEO_SUBSET_HEVC = 0x25, // ITU - T Rec.H.265 | ISO / IEC 23008 - 2 Annex A temporal video subset + MVCD_H264 = 0x26, // ITU - T Rec.H.264 | ISO / IEC 14496 - 10 Annex I MVCD video sub - bitstream + AUDIO_STREAM_LPCM = 0x80, + AUDIO_STREAM_AC3 = 0x81, + AUDIO_STREAM_DTS = 0x82, + AUDIO_STREAM_AC3_TRUE_HD = 0x83, + AUDIO_STREAM_AC3_PLUS = 0x84, + AUDIO_STREAM_DTS_HD = 0x85, + AUDIO_STREAM_DTS_HD_MASTER_AUDIO = 0x86, + PRESENTATION_GRAPHICS_STREAM = 0x90, + INTERACTIVE_GRAPHICS_STREAM = 0x91, + SUBTITLE_STREAM = 0x92, + SECONDARY_AUDIO_AC3_PLUS = 0xa1, + SECONDARY_AUDIO_DTS_HD = 0xa2, + VIDEO_STREAM_VC1 = 0xea +}; + +enum MPEG2_PID { + PID_PAT = 0x000, // Program Association Table + PID_CAT = 0x001, // Conditional Access Table + PID_TSDT = 0x002, // Transport Stream Description Table + PID_NIT = 0x010, // Network Identification Table + PID_BAT = 0x011, // Bouquet Association Table or ... + PID_SDT = 0x011, // ... Service Description Table + PID_EIT = 0x012, // Event Information Table + PID_RST = 0x013, // Running Status Table + PID_TDT = 0x014, // Time and Date Table or ... + PID_TOT = 0x014, // ... Time Offset Table + PID_SFN = 0x015, // SFN/MIP synchronization + PID_DIT = 0x01e, + PID_SIT = 0x01f, + PID_ATSC_PAT_E = 0x1FF7, + PID_PSIP_TS_E = 0x1FF9, + PID_PSIP = 0x1FFB, + PID_NULL = 0x1fff // Null packet +}; + +enum DVB_SI { + SI_undef = -1, + SI_PAT = 0x00, + SI_CAT = 0x01, + SI_PMT = 0x02, + SI_DSMCC_a = 0x3a, + SI_DSMCC_b = 0x3b, + SI_DSMCC_c = 0x3c, + SI_DSMCC_d = 0x3d, + SI_DSMCC_e = 0x3e, + SI_DSMCC_f = 0x3f, + SI_NIT = 0x40, + SI_SDT = 0x42, + SI_EIT_act = 0x4e, + SI_EIT_oth = 0x4f, + SI_EIT_as0, SI_EIT_as1, SI_EIT_as2, SI_EIT_as3, SI_EIT_as4, SI_EIT_as5, SI_EIT_as6, SI_EIT_as7, + SI_EIT_as8, SI_EIT_as9, SI_EIT_asa, SI_EIT_asb, SI_EIT_asc, SI_EIT_asd, SI_EIT_ase, SI_EIT_asf, + SI_EIT_os0, SI_EIT_os1, SI_EIT_os2, SI_EIT_os3, SI_EIT_os4, SI_EIT_os5, SI_EIT_os6, SI_EIT_os7, + SI_EIT_os8, SI_EIT_os9, SI_EIT_osa, SI_EIT_osb, SI_EIT_osc, SI_EIT_osd, SI_EIT_ose, SI_EIT_osf, + TID_MGT = 0xC7, + TID_TVCT = 0xC8, + TID_CVCT = 0xC9 +}; + +enum ATSC_TABLE_TYPE { + TT_TVCT_C1 = 0x0000, + TT_TVCT_C0 = 0x0001, + TT_CVCT_C1 = 0x0002, + TT_CVCT_C0 = 0x0003, + TT_ETT = 0x0004, + TT_DCCSCT = 0x0005, +}; + +enum MPEG2_DESCRIPTOR { + // http://www.coolstf.com/tsreader/descriptors.html + DT_VIDEO_STREAM = 0x02, + DT_AUDIO_STREAM = 0x03, + DT_HIERARCHY = 0x04, + DT_REGISTRATION = 0x05, + DT_DATA_STREAM_ALIGNMENT = 0x06, + DT_TARGET_BACKGROUND_GRID = 0x07, + DT_VIDEO_WINDOW = 0x08, + DT_CONDITIONAL_ACCESS = 0x09, + DT_ISO_639_LANGUAGE = 0x0a, + DT_SYSTEM_CLOCK = 0x0b, + DT_MULTIPLEX_BUFFER_UTIL = 0x0c, + DT_COPYRIGHT_DESCRIPTOR = 0x0d, + DT_MAXIMUM_BITRATE = 0x0e, + DT_PRIVATE_DATA_INDICATOR = 0x0f, + DT_SMOOTHING_BUFFER = 0x10, + DT_STD = 0x11, // System Target Decoder ? + DT_IBP = 0x12, + DT_NETWORK_NAME = 0x40, + DT_SERVICE_LIST = 0x41, + DT_VBI_DATA = 0x45, + DT_SERVICE = 0x48, + DT_LINKAGE = 0x4a, + DT_SHORT_EVENT = 0x4d, + DT_EXTENDED_EVENT = 0x4e, + DT_COMPONENT = 0x50, + DT_STREAM_IDENTIFIER = 0x52, + DT_CONTENT = 0x54, + DT_PARENTAL_RATING = 0x55, + DT_TELETEXT = 0x56, + DT_SUBTITLING = 0x59, + DT_TERRESTRIAL_DELIV_SYS = 0x5a, + DT_PRIVATE_DATA = 0x5f, + DID_DATA_BROADCAST = 0x64, + DT_DATA_BROADCAST_ID = 0x66, + DT_AC3_AUDIO = 0x6a, // DVB + DT_EXTENDED_AC3_AUDIO = 0x7a, + DT_AAC_AUDIO = 0x7c, + + DT_AC3_AUDIO__2 = 0x81, // DCII or ATSC + DT_LOGICAL_CHANNEL = 0x83, + DT_HD_SIMCAST_LOG_CHANNEL = 0x88 +}; + +enum MPEG_TYPES { + mpeg_us, + mpeg_ps, + mpeg_ts, + mpeg_es, + mpeg_pva +}; + +enum SERVICE_TYPE { + DIGITAL_TV = 0x01, + DIGITAL_RADIO = 0x02, + AVC_DIGITAL_RADIO = 0x0A, + MPEG2_HD_DIGITAL_TV = 0x11, + AVC_SD_TV = 0x16, + AVC_HD_TV = 0x19, + HEVC_TV = 0x1F +}; + +enum ATSC_SERVICE_TYPE { + ATSC_ANALOG_TV = 0x01, + ATSC_DIGITAL_TV = 0x02, + ATSC_AUDIO = 0x03 +}; + +extern const wchar_t* StreamTypeToName(PES_STREAM_TYPE _Type); diff --git a/src/DSUtil/NullRenderers.cpp b/src/DSUtil/NullRenderers.cpp index 1607e708e9e..4ad61e48c4b 100644 --- a/src/DSUtil/NullRenderers.cpp +++ b/src/DSUtil/NullRenderers.cpp @@ -1,453 +1,453 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "NullRenderers.h" -#include "moreuuids.h" - -#define USE_DXVA - -#ifdef USE_DXVA - -#include -#include -#include // DXVA2 -#include -#include // API Media Foundation -#include - -#pragma comment (lib, "d3d9.lib") - -// dxva.dll -typedef HRESULT(__stdcall* PTR_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager); -typedef HRESULT(__stdcall* PTR_DXVA2CreateVideoService)(IDirect3DDevice9* pDD, REFIID riid, void** ppService); - - -class CNullVideoRendererInputPin : public CRendererInputPin, - public IMFGetService, - public IDirectXVideoMemoryConfiguration, - public IMFVideoDisplayControl -{ -public: - CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name); - ~CNullVideoRendererInputPin() { - if (m_pD3DDeviceManager) { - if (m_hDevice != INVALID_HANDLE_VALUE) { - m_pD3DDeviceManager->CloseDeviceHandle(m_hDevice); - m_hDevice = INVALID_HANDLE_VALUE; - } - m_pD3DDeviceManager = nullptr; - } - if (m_pD3DDev) { - m_pD3DDev = nullptr; - } - if (m_hDXVA2Lib) { - FreeLibrary(m_hDXVA2Lib); - } - } - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator) { - // Renderer shouldn't manage allocator for DXVA - return E_NOTIMPL; - } - - STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES* pProps) { - // 1 buffer required - ZeroMemory(pProps, sizeof(ALLOCATOR_PROPERTIES)); - pProps->cbBuffer = 1; - return S_OK; - } - - // IMFGetService - STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject); - - // IDirectXVideoMemoryConfiguration - STDMETHODIMP GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType); - STDMETHODIMP SetSurfaceType(DXVA2_SurfaceType dwType); - - - // IMFVideoDisplayControl - STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) { - return E_NOTIMPL; - }; - STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) { - return E_NOTIMPL; - }; - STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, - const LPRECT prcDest) { - return E_NOTIMPL; - }; - STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, - LPRECT prcDest) { - return E_NOTIMPL; - }; - STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode) { - return E_NOTIMPL; - }; - STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode) { - return E_NOTIMPL; - }; - STDMETHODIMP SetVideoWindow(HWND hwndVideo) { - return E_NOTIMPL; - }; - STDMETHODIMP GetVideoWindow(HWND* phwndVideo); - STDMETHODIMP RepaintVideo() { - return E_NOTIMPL; - }; - STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, - DWORD* pcbDib, LONGLONG* pTimeStamp) { - return E_NOTIMPL; - }; - STDMETHODIMP SetBorderColor(COLORREF Clr) { - return E_NOTIMPL; - }; - STDMETHODIMP GetBorderColor(COLORREF* pClr) { - return E_NOTIMPL; - }; - STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags) { - return E_NOTIMPL; - }; - STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags) { - return E_NOTIMPL; - }; - STDMETHODIMP SetFullscreen(BOOL fFullscreen) { - return E_NOTIMPL; - }; - STDMETHODIMP GetFullscreen(BOOL* pfFullscreen) { - return E_NOTIMPL; - }; - -private: - HMODULE m_hDXVA2Lib; - PTR_DXVA2CreateDirect3DDeviceManager9 pfDXVA2CreateDirect3DDeviceManager9; - PTR_DXVA2CreateVideoService pfDXVA2CreateVideoService; - - CComPtr m_pD3D; - CComPtr m_pD3DDev; - CComPtr m_pD3DDeviceManager; - UINT m_nResetToken; - HANDLE m_hDevice; - HWND m_hWnd; - - void CreateSurface(); -}; - -CNullVideoRendererInputPin::CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name) - : CRendererInputPin(pRenderer, phr, Name) - , m_hDXVA2Lib(nullptr) - , pfDXVA2CreateDirect3DDeviceManager9(nullptr) - , pfDXVA2CreateVideoService(nullptr) - , m_pD3DDev(nullptr) - , m_pD3DDeviceManager(nullptr) - , m_nResetToken(0) - , m_hDevice(INVALID_HANDLE_VALUE) -{ - CreateSurface(); - - m_hDXVA2Lib = LoadLibrary(L"dxva2.dll"); - if (m_hDXVA2Lib) { - pfDXVA2CreateDirect3DDeviceManager9 = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateDirect3DDeviceManager9")); - pfDXVA2CreateVideoService = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateVideoService")); - pfDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DDeviceManager); - } - - // Initialize Device Manager with DX surface - if (m_pD3DDev) { - m_pD3DDeviceManager->ResetDevice(m_pD3DDev, m_nResetToken); - m_pD3DDeviceManager->OpenDeviceHandle(&m_hDevice); - } -} - -void CNullVideoRendererInputPin::CreateSurface() -{ - m_pD3D.Attach(Direct3DCreate9(D3D_SDK_VERSION)); - if (!m_pD3D) { - m_pD3D.Attach(Direct3DCreate9(D3D9b_SDK_VERSION)); - } - - m_hWnd = nullptr; // TODO : put true window - - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - VERIFY(SUCCEEDED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))); - - D3DPRESENT_PARAMETERS pp; - ZeroMemory(&pp, sizeof(pp)); - - pp.Windowed = TRUE; - pp.hDeviceWindow = m_hWnd; - pp.SwapEffect = D3DSWAPEFFECT_COPY; - pp.Flags = D3DPRESENTFLAG_VIDEO; - pp.BackBufferCount = 1; - pp.BackBufferWidth = d3ddm.Width; - pp.BackBufferHeight = d3ddm.Height; - pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - - VERIFY(SUCCEEDED(m_pD3D->CreateDevice( - D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, //| D3DCREATE_MANAGED, - &pp, &m_pD3DDev))); -} - -STDMETHODIMP CNullVideoRendererInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - (riid == __uuidof(IMFGetService)) ? GetInterface((IMFGetService*)this, ppv) : - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CNullVideoRendererInputPin::GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject) -{ - if (m_pD3DDeviceManager != nullptr && guidService == MR_VIDEO_ACCELERATION_SERVICE) { - if (riid == __uuidof(IDirect3DDeviceManager9)) { - return m_pD3DDeviceManager->QueryInterface(riid, ppvObject); - } else if (riid == __uuidof(IDirectXVideoDecoderService) || riid == __uuidof(IDirectXVideoProcessorService)) { - return m_pD3DDeviceManager->GetVideoService(m_hDevice, riid, ppvObject); - } else if (riid == __uuidof(IDirectXVideoAccelerationService)) { - // TODO : to be tested.... - return pfDXVA2CreateVideoService(m_pD3DDev, riid, ppvObject); - } else if (riid == __uuidof(IDirectXVideoMemoryConfiguration)) { - GetInterface((IDirectXVideoMemoryConfiguration*)this, ppvObject); - return S_OK; - } - } else if (guidService == MR_VIDEO_RENDER_SERVICE) { - if (riid == __uuidof(IMFVideoDisplayControl)) { - GetInterface((IMFVideoDisplayControl*)this, ppvObject); - return S_OK; - } - } - - return E_NOINTERFACE; -} - -STDMETHODIMP CNullVideoRendererInputPin::GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType) -{ - if (dwTypeIndex == 0) { - *pdwType = DXVA2_SurfaceType_DecoderRenderTarget; - return S_OK; - } else { - return MF_E_NO_MORE_TYPES; - } -} - -STDMETHODIMP CNullVideoRendererInputPin::SetSurfaceType(DXVA2_SurfaceType dwType) -{ - return S_OK; -} - -STDMETHODIMP CNullVideoRendererInputPin::GetVideoWindow(HWND* phwndVideo) -{ - CheckPointer(phwndVideo, E_POINTER); - *phwndVideo = m_hWnd; // Important to implement this method (used by MPC-HC) - return S_OK; -} - - -#endif // USE_DXVA - -// -// CNullRenderer -// - -CNullRenderer::CNullRenderer(REFCLSID clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr) - : CBaseRenderer(clsid, pName, pUnk, phr) -{ -} - -// -// CNullVideoRenderer -// - -CNullVideoRenderer::CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CNullRenderer(__uuidof(this), NAME("Null Video Renderer"), pUnk, phr) -{ -} - -HRESULT CNullVideoRenderer::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Video - || pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO - ? S_OK - : E_FAIL; -} - -// -// CNullUVideoRenderer -// - -CNullUVideoRenderer::CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CNullRenderer(__uuidof(this), NAME("Null Video Renderer (Uncompressed)"), pUnk, phr) -{ -#ifdef USE_DXVA - m_pInputPin = DEBUG_NEW CNullVideoRendererInputPin(this, phr, L"In"); -#endif -} - -HRESULT CNullUVideoRenderer::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Video - && (pmt->subtype == MEDIASUBTYPE_YV12 - || pmt->subtype == MEDIASUBTYPE_NV12 - || pmt->subtype == MEDIASUBTYPE_I420 - || pmt->subtype == MEDIASUBTYPE_YUYV - || pmt->subtype == MEDIASUBTYPE_IYUV - || pmt->subtype == MEDIASUBTYPE_YVU9 - || pmt->subtype == MEDIASUBTYPE_Y411 - || pmt->subtype == MEDIASUBTYPE_Y41P - || pmt->subtype == MEDIASUBTYPE_YUY2 - || pmt->subtype == MEDIASUBTYPE_YVYU - || pmt->subtype == MEDIASUBTYPE_UYVY - || pmt->subtype == MEDIASUBTYPE_Y211 - || pmt->subtype == MEDIASUBTYPE_AYUV - || pmt->subtype == MEDIASUBTYPE_YV16 - || pmt->subtype == MEDIASUBTYPE_YV24 - || pmt->subtype == MEDIASUBTYPE_P010 - || pmt->subtype == MEDIASUBTYPE_P016 - || pmt->subtype == MEDIASUBTYPE_P210 - || pmt->subtype == MEDIASUBTYPE_P216 - || pmt->subtype == MEDIASUBTYPE_RGB1 - || pmt->subtype == MEDIASUBTYPE_RGB4 - || pmt->subtype == MEDIASUBTYPE_RGB8 - || pmt->subtype == MEDIASUBTYPE_RGB565 - || pmt->subtype == MEDIASUBTYPE_RGB555 - || pmt->subtype == MEDIASUBTYPE_RGB24 - || pmt->subtype == MEDIASUBTYPE_RGB32 - || pmt->subtype == MEDIASUBTYPE_ARGB1555 - || pmt->subtype == MEDIASUBTYPE_ARGB4444 - || pmt->subtype == MEDIASUBTYPE_ARGB32 - || pmt->subtype == MEDIASUBTYPE_A2R10G10B10 - || pmt->subtype == MEDIASUBTYPE_A2B10G10R10) - ? S_OK - : E_FAIL; -} - -HRESULT CNullUVideoRenderer::DoRenderSample(IMediaSample* pSample) -{ -#ifdef USE_DXVA - CComQIPtr pService = pSample; - if (pService != nullptr) { - CComPtr pSurface; - if (SUCCEEDED(pService->GetService(MR_BUFFER_SERVICE, IID_PPV_ARGS(&pSurface)))) { - // TODO : render surface... - } - } -#endif - - return S_OK; -} - -// -// CNullAudioRenderer -// - -CNullAudioRenderer::CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer"), pUnk, phr) -{ -} - -HRESULT CNullAudioRenderer::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Audio - || pmt->majortype == MEDIATYPE_Midi - || pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO - || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 - || pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO - || pmt->subtype == MEDIASUBTYPE_DTS - || pmt->subtype == MEDIASUBTYPE_SDDS - || pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload - || pmt->subtype == MEDIASUBTYPE_MPEG1Audio - ? S_OK - : E_FAIL; -} - -// -// CNullUAudioRenderer -// - -CNullUAudioRenderer::CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer (Uncompressed)"), pUnk, phr) -{ -} - -HRESULT CNullUAudioRenderer::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Audio - && (pmt->subtype == MEDIASUBTYPE_PCM - || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT - || pmt->subtype == MEDIASUBTYPE_DRM_Audio - || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF - || pmt->subtype == MEDIASUBTYPE_RAW_SPORT - || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h) - ? S_OK - : E_FAIL; -} - -HRESULT CNullUAudioRenderer::DoRenderSample(IMediaSample* pSample) -{ -#if _DEBUG && 0 - static int nNb = 1; - if (nNb < 100) { - const long lSize = pSample->GetActualDataLength(); - BYTE* pMediaBuffer = nullptr; - HRESULT hr = pSample->GetPointer(&pMediaBuffer); - char strFile[MAX_PATH]; - - sprintf_s(strFile, "AudioData%02d.bin", nNb++); - FILE* hFile = fopen(strFile, "wb"); - if (hFile) { - fwrite(pMediaBuffer, - 1, - lSize, - hFile); - fclose(hFile); - } - } -#endif - - return S_OK; -} - -// -// CNullTextRenderer -// - -HRESULT CNullTextRenderer::CTextInputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Text - || pmt->majortype == MEDIATYPE_ScriptCommand - || pmt->majortype == MEDIATYPE_Subtitle - || pmt->subtype == MEDIASUBTYPE_DVD_SUBPICTURE - || pmt->subtype == MEDIASUBTYPE_CVD_SUBPICTURE - || pmt->subtype == MEDIASUBTYPE_SVCD_SUBPICTURE - ? S_OK - : E_FAIL; -} - -CNullTextRenderer::CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseFilter(NAME("CNullTextRenderer"), pUnk, this, __uuidof(this), phr) -{ - m_pInput.Attach(DEBUG_NEW CTextInputPin(this, this, phr)); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "NullRenderers.h" +#include "moreuuids.h" + +#define USE_DXVA + +#ifdef USE_DXVA + +#include +#include +#include // DXVA2 +#include +#include // API Media Foundation +#include + +#pragma comment (lib, "d3d9.lib") + +// dxva.dll +typedef HRESULT(__stdcall* PTR_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager); +typedef HRESULT(__stdcall* PTR_DXVA2CreateVideoService)(IDirect3DDevice9* pDD, REFIID riid, void** ppService); + + +class CNullVideoRendererInputPin : public CRendererInputPin, + public IMFGetService, + public IDirectXVideoMemoryConfiguration, + public IMFVideoDisplayControl +{ +public: + CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name); + ~CNullVideoRendererInputPin() { + if (m_pD3DDeviceManager) { + if (m_hDevice != INVALID_HANDLE_VALUE) { + m_pD3DDeviceManager->CloseDeviceHandle(m_hDevice); + m_hDevice = INVALID_HANDLE_VALUE; + } + m_pD3DDeviceManager = nullptr; + } + if (m_pD3DDev) { + m_pD3DDev = nullptr; + } + if (m_hDXVA2Lib) { + FreeLibrary(m_hDXVA2Lib); + } + } + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator) { + // Renderer shouldn't manage allocator for DXVA + return E_NOTIMPL; + } + + STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES* pProps) { + // 1 buffer required + ZeroMemory(pProps, sizeof(ALLOCATOR_PROPERTIES)); + pProps->cbBuffer = 1; + return S_OK; + } + + // IMFGetService + STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject); + + // IDirectXVideoMemoryConfiguration + STDMETHODIMP GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType); + STDMETHODIMP SetSurfaceType(DXVA2_SurfaceType dwType); + + + // IMFVideoDisplayControl + STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) { + return E_NOTIMPL; + }; + STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) { + return E_NOTIMPL; + }; + STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, + const LPRECT prcDest) { + return E_NOTIMPL; + }; + STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, + LPRECT prcDest) { + return E_NOTIMPL; + }; + STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode) { + return E_NOTIMPL; + }; + STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode) { + return E_NOTIMPL; + }; + STDMETHODIMP SetVideoWindow(HWND hwndVideo) { + return E_NOTIMPL; + }; + STDMETHODIMP GetVideoWindow(HWND* phwndVideo); + STDMETHODIMP RepaintVideo() { + return E_NOTIMPL; + }; + STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, + DWORD* pcbDib, LONGLONG* pTimeStamp) { + return E_NOTIMPL; + }; + STDMETHODIMP SetBorderColor(COLORREF Clr) { + return E_NOTIMPL; + }; + STDMETHODIMP GetBorderColor(COLORREF* pClr) { + return E_NOTIMPL; + }; + STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags) { + return E_NOTIMPL; + }; + STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags) { + return E_NOTIMPL; + }; + STDMETHODIMP SetFullscreen(BOOL fFullscreen) { + return E_NOTIMPL; + }; + STDMETHODIMP GetFullscreen(BOOL* pfFullscreen) { + return E_NOTIMPL; + }; + +private: + HMODULE m_hDXVA2Lib; + PTR_DXVA2CreateDirect3DDeviceManager9 pfDXVA2CreateDirect3DDeviceManager9; + PTR_DXVA2CreateVideoService pfDXVA2CreateVideoService; + + CComPtr m_pD3D; + CComPtr m_pD3DDev; + CComPtr m_pD3DDeviceManager; + UINT m_nResetToken; + HANDLE m_hDevice; + HWND m_hWnd; + + void CreateSurface(); +}; + +CNullVideoRendererInputPin::CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name) + : CRendererInputPin(pRenderer, phr, Name) + , m_hDXVA2Lib(nullptr) + , pfDXVA2CreateDirect3DDeviceManager9(nullptr) + , pfDXVA2CreateVideoService(nullptr) + , m_pD3DDev(nullptr) + , m_pD3DDeviceManager(nullptr) + , m_nResetToken(0) + , m_hDevice(INVALID_HANDLE_VALUE) +{ + CreateSurface(); + + m_hDXVA2Lib = LoadLibrary(L"dxva2.dll"); + if (m_hDXVA2Lib) { + pfDXVA2CreateDirect3DDeviceManager9 = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateDirect3DDeviceManager9")); + pfDXVA2CreateVideoService = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateVideoService")); + pfDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DDeviceManager); + } + + // Initialize Device Manager with DX surface + if (m_pD3DDev) { + m_pD3DDeviceManager->ResetDevice(m_pD3DDev, m_nResetToken); + m_pD3DDeviceManager->OpenDeviceHandle(&m_hDevice); + } +} + +void CNullVideoRendererInputPin::CreateSurface() +{ + m_pD3D.Attach(Direct3DCreate9(D3D_SDK_VERSION)); + if (!m_pD3D) { + m_pD3D.Attach(Direct3DCreate9(D3D9b_SDK_VERSION)); + } + + m_hWnd = nullptr; // TODO : put true window + + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + VERIFY(SUCCEEDED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))); + + D3DPRESENT_PARAMETERS pp; + ZeroMemory(&pp, sizeof(pp)); + + pp.Windowed = TRUE; + pp.hDeviceWindow = m_hWnd; + pp.SwapEffect = D3DSWAPEFFECT_COPY; + pp.Flags = D3DPRESENTFLAG_VIDEO; + pp.BackBufferCount = 1; + pp.BackBufferWidth = d3ddm.Width; + pp.BackBufferHeight = d3ddm.Height; + pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + + VERIFY(SUCCEEDED(m_pD3D->CreateDevice( + D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, //| D3DCREATE_MANAGED, + &pp, &m_pD3DDev))); +} + +STDMETHODIMP CNullVideoRendererInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + (riid == __uuidof(IMFGetService)) ? GetInterface((IMFGetService*)this, ppv) : + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CNullVideoRendererInputPin::GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject) +{ + if (m_pD3DDeviceManager != nullptr && guidService == MR_VIDEO_ACCELERATION_SERVICE) { + if (riid == __uuidof(IDirect3DDeviceManager9)) { + return m_pD3DDeviceManager->QueryInterface(riid, ppvObject); + } else if (riid == __uuidof(IDirectXVideoDecoderService) || riid == __uuidof(IDirectXVideoProcessorService)) { + return m_pD3DDeviceManager->GetVideoService(m_hDevice, riid, ppvObject); + } else if (riid == __uuidof(IDirectXVideoAccelerationService)) { + // TODO : to be tested.... + return pfDXVA2CreateVideoService(m_pD3DDev, riid, ppvObject); + } else if (riid == __uuidof(IDirectXVideoMemoryConfiguration)) { + GetInterface((IDirectXVideoMemoryConfiguration*)this, ppvObject); + return S_OK; + } + } else if (guidService == MR_VIDEO_RENDER_SERVICE) { + if (riid == __uuidof(IMFVideoDisplayControl)) { + GetInterface((IMFVideoDisplayControl*)this, ppvObject); + return S_OK; + } + } + + return E_NOINTERFACE; +} + +STDMETHODIMP CNullVideoRendererInputPin::GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType) +{ + if (dwTypeIndex == 0) { + *pdwType = DXVA2_SurfaceType_DecoderRenderTarget; + return S_OK; + } else { + return MF_E_NO_MORE_TYPES; + } +} + +STDMETHODIMP CNullVideoRendererInputPin::SetSurfaceType(DXVA2_SurfaceType dwType) +{ + return S_OK; +} + +STDMETHODIMP CNullVideoRendererInputPin::GetVideoWindow(HWND* phwndVideo) +{ + CheckPointer(phwndVideo, E_POINTER); + *phwndVideo = m_hWnd; // Important to implement this method (used by MPC-HC) + return S_OK; +} + + +#endif // USE_DXVA + +// +// CNullRenderer +// + +CNullRenderer::CNullRenderer(REFCLSID clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr) + : CBaseRenderer(clsid, pName, pUnk, phr) +{ +} + +// +// CNullVideoRenderer +// + +CNullVideoRenderer::CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CNullRenderer(__uuidof(this), NAME("Null Video Renderer"), pUnk, phr) +{ +} + +HRESULT CNullVideoRenderer::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Video + || pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO + ? S_OK + : E_FAIL; +} + +// +// CNullUVideoRenderer +// + +CNullUVideoRenderer::CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CNullRenderer(__uuidof(this), NAME("Null Video Renderer (Uncompressed)"), pUnk, phr) +{ +#ifdef USE_DXVA + m_pInputPin = DEBUG_NEW CNullVideoRendererInputPin(this, phr, L"In"); +#endif +} + +HRESULT CNullUVideoRenderer::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Video + && (pmt->subtype == MEDIASUBTYPE_YV12 + || pmt->subtype == MEDIASUBTYPE_NV12 + || pmt->subtype == MEDIASUBTYPE_I420 + || pmt->subtype == MEDIASUBTYPE_YUYV + || pmt->subtype == MEDIASUBTYPE_IYUV + || pmt->subtype == MEDIASUBTYPE_YVU9 + || pmt->subtype == MEDIASUBTYPE_Y411 + || pmt->subtype == MEDIASUBTYPE_Y41P + || pmt->subtype == MEDIASUBTYPE_YUY2 + || pmt->subtype == MEDIASUBTYPE_YVYU + || pmt->subtype == MEDIASUBTYPE_UYVY + || pmt->subtype == MEDIASUBTYPE_Y211 + || pmt->subtype == MEDIASUBTYPE_AYUV + || pmt->subtype == MEDIASUBTYPE_YV16 + || pmt->subtype == MEDIASUBTYPE_YV24 + || pmt->subtype == MEDIASUBTYPE_P010 + || pmt->subtype == MEDIASUBTYPE_P016 + || pmt->subtype == MEDIASUBTYPE_P210 + || pmt->subtype == MEDIASUBTYPE_P216 + || pmt->subtype == MEDIASUBTYPE_RGB1 + || pmt->subtype == MEDIASUBTYPE_RGB4 + || pmt->subtype == MEDIASUBTYPE_RGB8 + || pmt->subtype == MEDIASUBTYPE_RGB565 + || pmt->subtype == MEDIASUBTYPE_RGB555 + || pmt->subtype == MEDIASUBTYPE_RGB24 + || pmt->subtype == MEDIASUBTYPE_RGB32 + || pmt->subtype == MEDIASUBTYPE_ARGB1555 + || pmt->subtype == MEDIASUBTYPE_ARGB4444 + || pmt->subtype == MEDIASUBTYPE_ARGB32 + || pmt->subtype == MEDIASUBTYPE_A2R10G10B10 + || pmt->subtype == MEDIASUBTYPE_A2B10G10R10) + ? S_OK + : E_FAIL; +} + +HRESULT CNullUVideoRenderer::DoRenderSample(IMediaSample* pSample) +{ +#ifdef USE_DXVA + CComQIPtr pService = pSample; + if (pService != nullptr) { + CComPtr pSurface; + if (SUCCEEDED(pService->GetService(MR_BUFFER_SERVICE, IID_PPV_ARGS(&pSurface)))) { + // TODO : render surface... + } + } +#endif + + return S_OK; +} + +// +// CNullAudioRenderer +// + +CNullAudioRenderer::CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer"), pUnk, phr) +{ +} + +HRESULT CNullAudioRenderer::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Audio + || pmt->majortype == MEDIATYPE_Midi + || pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO + || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 + || pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO + || pmt->subtype == MEDIASUBTYPE_DTS + || pmt->subtype == MEDIASUBTYPE_SDDS + || pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload + || pmt->subtype == MEDIASUBTYPE_MPEG1Audio + ? S_OK + : E_FAIL; +} + +// +// CNullUAudioRenderer +// + +CNullUAudioRenderer::CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer (Uncompressed)"), pUnk, phr) +{ +} + +HRESULT CNullUAudioRenderer::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Audio + && (pmt->subtype == MEDIASUBTYPE_PCM + || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT + || pmt->subtype == MEDIASUBTYPE_DRM_Audio + || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF + || pmt->subtype == MEDIASUBTYPE_RAW_SPORT + || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h) + ? S_OK + : E_FAIL; +} + +HRESULT CNullUAudioRenderer::DoRenderSample(IMediaSample* pSample) +{ +#if _DEBUG && 0 + static int nNb = 1; + if (nNb < 100) { + const long lSize = pSample->GetActualDataLength(); + BYTE* pMediaBuffer = nullptr; + HRESULT hr = pSample->GetPointer(&pMediaBuffer); + char strFile[MAX_PATH]; + + sprintf_s(strFile, "AudioData%02d.bin", nNb++); + FILE* hFile = fopen(strFile, "wb"); + if (hFile) { + fwrite(pMediaBuffer, + 1, + lSize, + hFile); + fclose(hFile); + } + } +#endif + + return S_OK; +} + +// +// CNullTextRenderer +// + +HRESULT CNullTextRenderer::CTextInputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Text + || pmt->majortype == MEDIATYPE_ScriptCommand + || pmt->majortype == MEDIATYPE_Subtitle + || pmt->subtype == MEDIASUBTYPE_DVD_SUBPICTURE + || pmt->subtype == MEDIASUBTYPE_CVD_SUBPICTURE + || pmt->subtype == MEDIASUBTYPE_SVCD_SUBPICTURE + ? S_OK + : E_FAIL; +} + +CNullTextRenderer::CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseFilter(NAME("CNullTextRenderer"), pUnk, this, __uuidof(this), phr) +{ + m_pInput.Attach(DEBUG_NEW CTextInputPin(this, this, phr)); +} diff --git a/src/DSUtil/NullRenderers.h b/src/DSUtil/NullRenderers.h index 39fe97d8349..1437c20aef4 100644 --- a/src/DSUtil/NullRenderers.h +++ b/src/DSUtil/NullRenderers.h @@ -1,95 +1,95 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include "BaseClasses/streams.h" - -class CNullRenderer : public CBaseRenderer -{ -protected: - virtual HRESULT DoRenderSample(IMediaSample* pSample) { return S_OK; } - -public: - CNullRenderer(REFCLSID clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr); -}; - -class __declspec(uuid("579883A0-4E2D-481F-9436-467AAFAB7DE8")) - CNullVideoRenderer : public CNullRenderer -{ -protected: - HRESULT CheckMediaType(const CMediaType* pmt); - -public: - CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr); -}; - -class __declspec(uuid("DD9ED57D-6ABF-42E8-89A2-11D04798DC58")) - CNullUVideoRenderer : public CNullRenderer -{ -protected: - HRESULT CheckMediaType(const CMediaType* pmt); - -public: - CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr); - virtual HRESULT DoRenderSample(IMediaSample* pSample); -}; - -class __declspec(uuid("0C38BDFD-8C17-4E00-A344-F89397D3E22A")) - CNullAudioRenderer : public CNullRenderer -{ -protected: - HRESULT CheckMediaType(const CMediaType* pmt); - -public: - CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr); -}; - -class __declspec(uuid("64A45125-7343-4772-9DA4-179FAC9D462C")) - CNullUAudioRenderer : public CNullRenderer -{ -protected: - HRESULT CheckMediaType(const CMediaType* pmt); - virtual HRESULT DoRenderSample(IMediaSample* pSample); - -public: - CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr); -}; - -class __declspec(uuid("655D7613-C26C-4A25-BBBD-3C9C516122CC")) - CNullTextRenderer : public CBaseFilter, public CCritSec -{ - class CTextInputPin : public CBaseInputPin - { - public: - CTextInputPin(CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseInputPin(NAME("CTextInputPin"), pFilter, pLock, phr, L"In") {} - HRESULT CheckMediaType(const CMediaType* pmt); - }; - - CAutoPtr m_pInput; - -public: - CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr); - int GetPinCount() { return (int)!!m_pInput; } - CBasePin* GetPin(int n) { return n == 0 ? (CBasePin*)m_pInput : nullptr; } -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include "BaseClasses/streams.h" + +class CNullRenderer : public CBaseRenderer +{ +protected: + virtual HRESULT DoRenderSample(IMediaSample* pSample) { return S_OK; } + +public: + CNullRenderer(REFCLSID clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr); +}; + +class __declspec(uuid("579883A0-4E2D-481F-9436-467AAFAB7DE8")) + CNullVideoRenderer : public CNullRenderer +{ +protected: + HRESULT CheckMediaType(const CMediaType* pmt); + +public: + CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr); +}; + +class __declspec(uuid("DD9ED57D-6ABF-42E8-89A2-11D04798DC58")) + CNullUVideoRenderer : public CNullRenderer +{ +protected: + HRESULT CheckMediaType(const CMediaType* pmt); + +public: + CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr); + virtual HRESULT DoRenderSample(IMediaSample* pSample); +}; + +class __declspec(uuid("0C38BDFD-8C17-4E00-A344-F89397D3E22A")) + CNullAudioRenderer : public CNullRenderer +{ +protected: + HRESULT CheckMediaType(const CMediaType* pmt); + +public: + CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr); +}; + +class __declspec(uuid("64A45125-7343-4772-9DA4-179FAC9D462C")) + CNullUAudioRenderer : public CNullRenderer +{ +protected: + HRESULT CheckMediaType(const CMediaType* pmt); + virtual HRESULT DoRenderSample(IMediaSample* pSample); + +public: + CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr); +}; + +class __declspec(uuid("655D7613-C26C-4A25-BBBD-3C9C516122CC")) + CNullTextRenderer : public CBaseFilter, public CCritSec +{ + class CTextInputPin : public CBaseInputPin + { + public: + CTextInputPin(CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseInputPin(NAME("CTextInputPin"), pFilter, pLock, phr, L"In") {} + HRESULT CheckMediaType(const CMediaType* pmt); + }; + + CAutoPtr m_pInput; + +public: + CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr); + int GetPinCount() { return (int)!!m_pInput; } + CBasePin* GetPin(int n) { return n == 0 ? (CBasePin*)m_pInput : nullptr; } +}; diff --git a/src/DSUtil/SharedInclude.h b/src/DSUtil/SharedInclude.h index ccc8a12e0d1..2d1d3e8a451 100644 --- a/src/DSUtil/SharedInclude.h +++ b/src/DSUtil/SharedInclude.h @@ -1,41 +1,41 @@ -/* - * (C) 2009-2013, 2016 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 . - * - */ - -#pragma once - -#pragma warning(disable:4995) -#pragma warning(disable:5054) -#pragma warning(disable:4467) - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#ifndef STRICT_TYPED_ITEMIDS -#define STRICT_TYPED_ITEMIDS -#endif - -#ifdef _DEBUG -#if 1 -#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures -#include -#else -#include "vld.h" //include visual leak detector procedures -#endif -#endif +/* + * (C) 2009-2013, 2016 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 . + * + */ + +#pragma once + +#pragma warning(disable:4995) +#pragma warning(disable:5054) +#pragma warning(disable:4467) + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#ifndef STRICT_TYPED_ITEMIDS +#define STRICT_TYPED_ITEMIDS +#endif + +#ifdef _DEBUG +#if 1 +#define _CRTDBG_MAP_ALLOC // include Microsoft memory leak detection procedures +#include +#else +#include "vld.h" //include visual leak detector procedures +#endif +#endif diff --git a/src/DSUtil/VersionHelpersInternal.h b/src/DSUtil/VersionHelpersInternal.h index 22c79524cd2..5cef19a2fb7 100644 --- a/src/DSUtil/VersionHelpersInternal.h +++ b/src/DSUtil/VersionHelpersInternal.h @@ -1,83 +1,83 @@ -/* -* (C) 2017 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 . -* -*/ - -#pragma once - -#include - -// Remove once newer SDK is used -#ifndef _WIN32_WINNT_WINTHRESHOLD -#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 - -VERSIONHELPERAPI -IsWindows10OrGreater() -{ - return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0); -} - -#endif - -static VERSIONHELPERAPI -IsWindowsVersionOrGreaterBuild(WORD wMajorVersion, WORD wMinorVersion, DWORD dwBuildNumber) { - OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; - DWORDLONG const dwlConditionMask = VerSetConditionMask( - VerSetConditionMask( - VerSetConditionMask( - 0, VER_MAJORVERSION, VER_GREATER_EQUAL), - VER_MINORVERSION, VER_GREATER_EQUAL), - VER_BUILDNUMBER, VER_GREATER_EQUAL); - - osvi.dwMajorVersion = wMajorVersion; - osvi.dwMinorVersion = wMinorVersion; - osvi.dwBuildNumber = dwBuildNumber; - - return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, dwlConditionMask) != FALSE; -} - -#ifndef IsWindows11OrGreater - -VERSIONHELPERAPI -IsWindows11OrGreater() { - return IsWindowsVersionOrGreaterBuild(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 22000); -} - -#endif - -typedef LONG NTSTATUS, * PNTSTATUS; -#define STATUS_SUCCESS (0x00000000) - -typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); - -inline RTL_OSVERSIONINFOW GetRealOSVersion() -{ - HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); - if (hMod) { - RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); - if (fxPtr != nullptr) { - RTL_OSVERSIONINFOW rovi = { 0 }; - rovi.dwOSVersionInfoSize = sizeof(rovi); - if (STATUS_SUCCESS == fxPtr(&rovi)) { - return rovi; - } - } - } - RTL_OSVERSIONINFOW rovi = { 0 }; - return rovi; -} +/* +* (C) 2017 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 . +* +*/ + +#pragma once + +#include + +// Remove once newer SDK is used +#ifndef _WIN32_WINNT_WINTHRESHOLD +#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 + +VERSIONHELPERAPI +IsWindows10OrGreater() +{ + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 0); +} + +#endif + +static VERSIONHELPERAPI +IsWindowsVersionOrGreaterBuild(WORD wMajorVersion, WORD wMinorVersion, DWORD dwBuildNumber) { + OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + DWORDLONG const dwlConditionMask = VerSetConditionMask( + VerSetConditionMask( + VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_BUILDNUMBER, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = wMajorVersion; + osvi.dwMinorVersion = wMinorVersion; + osvi.dwBuildNumber = dwBuildNumber; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, dwlConditionMask) != FALSE; +} + +#ifndef IsWindows11OrGreater + +VERSIONHELPERAPI +IsWindows11OrGreater() { + return IsWindowsVersionOrGreaterBuild(HIBYTE(_WIN32_WINNT_WINTHRESHOLD), LOBYTE(_WIN32_WINNT_WINTHRESHOLD), 22000); +} + +#endif + +typedef LONG NTSTATUS, * PNTSTATUS; +#define STATUS_SUCCESS (0x00000000) + +typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); + +inline RTL_OSVERSIONINFOW GetRealOSVersion() +{ + HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); + if (hMod) { + RtlGetVersionPtr fxPtr = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); + if (fxPtr != nullptr) { + RTL_OSVERSIONINFOW rovi = { 0 }; + rovi.dwOSVersionInfoSize = sizeof(rovi); + if (STATUS_SUCCESS == fxPtr(&rovi)) { + return rovi; + } + } + } + RTL_OSVERSIONINFOW rovi = { 0 }; + return rovi; +} diff --git a/src/DSUtil/WinAPIUtils.cpp b/src/DSUtil/WinAPIUtils.cpp index ed73a98f531..10ea8ff21bf 100644 --- a/src/DSUtil/WinAPIUtils.cpp +++ b/src/DSUtil/WinAPIUtils.cpp @@ -1,348 +1,348 @@ -/* - * (C) 2011-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "WinAPIUtils.h" -#include "PathUtils.h" - - -bool SetPrivilege(LPCTSTR privilege, bool bEnable) -{ - HANDLE hToken; - TOKEN_PRIVILEGES tkp; - - SetThreadExecutionState(ES_CONTINUOUS); - - // Get a token for this process. - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { - return false; - } - - // Get the LUID for the privilege. - LookupPrivilegeValue(nullptr, privilege, &tkp.Privileges[0].Luid); - - tkp.PrivilegeCount = 1; // one privilege to set - tkp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0; - - // Set the privilege for this process. - AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)nullptr, 0); - - return (GetLastError() == ERROR_SUCCESS); -} - -CString GetHiveName(const HKEY hive) -{ - switch ((ULONG_PTR)hive) { - case (ULONG_PTR)HKEY_CLASSES_ROOT: - return _T("HKEY_CLASSES_ROOT"); - case (ULONG_PTR)HKEY_CURRENT_USER: - return _T("HKEY_CURRENT_USER"); - case (ULONG_PTR)HKEY_LOCAL_MACHINE: - return _T("HKEY_LOCAL_MACHINE"); - case (ULONG_PTR)HKEY_USERS: - return _T("HKEY_USERS"); - case (ULONG_PTR)HKEY_PERFORMANCE_DATA: - return _T("HKEY_PERFORMANCE_DATA"); - case (ULONG_PTR)HKEY_CURRENT_CONFIG: - return _T("HKEY_CURRENT_CONFIG"); - case (ULONG_PTR)HKEY_DYN_DATA: - return _T("HKEY_DYN_DATA"); - case (ULONG_PTR)HKEY_PERFORMANCE_TEXT: - return _T("HKEY_PERFORMANCE_TEXT"); - case (ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT: - return _T("HKEY_PERFORMANCE_NLSTEXT"); - default: - return _T(""); - } -} - -bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName) -{ - // Registry functions don't set GetLastError(), so it needs to be set explicitly - LSTATUS errorCode = ERROR_SUCCESS; - - HKEY hKey = nullptr; - errorCode = RegOpenKeyEx(hKeyRoot, keyName, 0, KEY_READ, &hKey); - if (errorCode != ERROR_SUCCESS) { - SetLastError(errorCode); - return false; - } - - DWORD subKeysCount = 0, maxSubKeyLen = 0; - DWORD valuesCount = 0, maxValueNameLen = 0, maxValueDataLen = 0; - errorCode = RegQueryInfoKey(hKey, nullptr, nullptr, nullptr, &subKeysCount, &maxSubKeyLen, nullptr, &valuesCount, &maxValueNameLen, &maxValueDataLen, nullptr, nullptr); - if (errorCode != ERROR_SUCCESS) { - SetLastError(errorCode); - return false; - } - maxSubKeyLen += 1; - maxValueNameLen += 1; - - CString buffer; - - buffer.Format(_T("[%s\\%s]\n"), GetHiveName(hKeyRoot).GetString(), keyName.GetString()); - file.WriteString(buffer); - - CString valueName; - DWORD valueNameLen, valueDataLen, type; - BYTE* data = DEBUG_NEW BYTE[maxValueDataLen]; - - for (DWORD indexValue = 0; indexValue < valuesCount; indexValue++) { - valueNameLen = maxValueNameLen; - valueDataLen = maxValueDataLen; - - errorCode = RegEnumValue(hKey, indexValue, valueName.GetBuffer(maxValueNameLen), &valueNameLen, nullptr, &type, data, &valueDataLen); - if (errorCode != ERROR_SUCCESS) { - SetLastError(errorCode); - return false; - } - - switch (type) { - case REG_SZ: { - CString str((TCHAR*)data); - str.Replace(_T("\\"), _T("\\\\")); - str.Replace(_T("\""), _T("\\\"")); - buffer.Format(_T("\"%s\"=\"%s\"\n"), valueName.GetString(), str.GetString()); - file.WriteString(buffer); - } - break; - case REG_BINARY: - buffer.Format(_T("\"%s\"=hex:%02x"), valueName.GetString(), data[0]); - file.WriteString(buffer); - for (DWORD i = 1; i < valueDataLen; i++) { - buffer.Format(_T(",%02x"), data[i]); - file.WriteString(buffer); - } - file.WriteString(_T("\n")); - break; - case REG_DWORD: - buffer.Format(_T("\"%s\"=dword:%08lx\n"), valueName.GetString(), *((DWORD*)data)); - file.WriteString(buffer); - break; - default: { - CString msg; - msg.Format(_T("The value \"%s\\%s\\%s\" has an unsupported type and has been ignored.\nPlease report this error to the developers."), - GetHiveName(hKeyRoot).GetString(), keyName.GetString(), valueName.GetString()); - AfxMessageBox(msg, MB_ICONERROR | MB_OK); - } - delete [] data; - return false; - } - } - - delete [] data; - - file.WriteString(_T("\n")); - - CString subKeyName; - DWORD subKeyLen; - - for (DWORD indexSubKey = 0; indexSubKey < subKeysCount; indexSubKey++) { - subKeyLen = maxSubKeyLen; - - errorCode = RegEnumKeyEx(hKey, indexSubKey, subKeyName.GetBuffer(maxSubKeyLen), &subKeyLen, nullptr, nullptr, nullptr, nullptr); - if (errorCode != ERROR_SUCCESS) { - SetLastError(errorCode); - return false; - } - - buffer.Format(_T("%s\\%s"), keyName.GetString(), subKeyName.GetString()); - - if (!ExportRegistryKey(file, hKeyRoot, buffer)) { - return false; - } - } - - errorCode = RegCloseKey(hKey); - SetLastError(errorCode); - return true; -} - -UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd) -{ - if (hWnd == nullptr || pD3D == nullptr) { - return D3DADAPTER_DEFAULT; - } - - HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); - if (hMonitor == nullptr) { - return D3DADAPTER_DEFAULT; - } - - for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { - HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp); - if (hAdpMon == hMonitor) { - return adp; - } - } - - return D3DADAPTER_DEFAULT; -} - -int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX* /*lpelfe*/, NEWTEXTMETRICEX* /*lpntme*/, int /*FontType*/, LPARAM lParam) -{ - LPARAM* l = (LPARAM*)lParam; - *l = TRUE; - return TRUE; -} - -namespace -{ - void GetNonClientMetrics(NONCLIENTMETRICS* ncm) - { - ZeroMemory(ncm, sizeof(NONCLIENTMETRICS)); - ncm->cbSize = sizeof(NONCLIENTMETRICS); - VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, 0)); - } -} - -void GetMessageFont(LOGFONT* lf) -{ - NONCLIENTMETRICS ncm; - GetNonClientMetrics(&ncm); - *lf = ncm.lfMessageFont; - ASSERT(lf->lfHeight); -} - -void GetStatusFont(LOGFONT* lf) -{ - NONCLIENTMETRICS ncm; - GetNonClientMetrics(&ncm); - *lf = ncm.lfStatusFont; - ASSERT(lf->lfHeight); -} - -bool IsFontInstalled(LPCTSTR lpszFont) -{ - // Get the screen DC - CDC dc; - if (!dc.CreateCompatibleDC(nullptr)) { - return false; - } - - LOGFONT lf; - ZeroMemory(&lf, sizeof(LOGFONT)); - // Any character set will do - lf.lfCharSet = DEFAULT_CHARSET; - // Set the facename to check for - _tcscpy_s(lf.lfFaceName, lpszFont); - LPARAM lParam = 0; - // Enumerate fonts - EnumFontFamiliesEx(dc.GetSafeHdc(), &lf, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)&lParam, 0); - - return lParam ? true : false; -} - -bool ExploreToFile(LPCTSTR path) -{ - CoInitializeHelper co; - - bool success = false; - PIDLIST_ABSOLUTE pidl; - - if (PathUtils::Exists(path) && SHParseDisplayName(path, nullptr, &pidl, 0, nullptr) == S_OK) { - success = SUCCEEDED(SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0)); - CoTaskMemFree(pidl); - } - - return success; -} - -CoInitializeHelper::CoInitializeHelper() -{ - HRESULT res = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - if (res == RPC_E_CHANGED_MODE) { // Try another threading model - res = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - } - if (res != S_OK && res != S_FALSE) { - throw res; - } -} - -CoInitializeHelper::~CoInitializeHelper() -{ - CoUninitialize(); -} - -HRESULT FileDelete(CString file, HWND hWnd, bool recycle /*= true*/, bool noconfirm /*= false*/) -{ - // Strings in SHFILEOPSTRUCT must be double-null terminated - file.AppendChar(_T('\0')); - - SHFILEOPSTRUCT fileOpStruct; - ZeroMemory(&fileOpStruct, sizeof(SHFILEOPSTRUCT)); - fileOpStruct.hwnd = hWnd; - fileOpStruct.wFunc = FO_DELETE; - fileOpStruct.pFrom = file; - fileOpStruct.fFlags = FOF_FILESONLY | FOF_SILENT; - if (recycle) { - fileOpStruct.fFlags |= FOF_ALLOWUNDO; - } - if (noconfirm) { - fileOpStruct.fFlags |= FOF_NOCONFIRMATION; - } else { - fileOpStruct.fFlags |= FOF_WANTNUKEWARNING; - } - int hRes = SHFileOperation(&fileOpStruct); - if (fileOpStruct.fAnyOperationsAborted) { - hRes = E_ABORT; - } - TRACE(_T("Delete recycle=%d hRes=0x%08x, file=%s\n"), recycle, hRes, file.GetString()); - return hRes; -} - -BOOL CClipboard::SetText(const CString& text) const -{ -#ifdef _UNICODE - const UINT format = CF_UNICODETEXT; -#else - const UINT format = CF_TEXT; -#endif - - BOOL bResult = FALSE; - - if(m_bOpened) { - // Allocate a global memory object for the text - int len = text.GetLength() + 1; - auto hGlob = GlobalAlloc(GMEM_MOVEABLE, len*sizeof(TCHAR)); - if (hGlob) { - // Lock the handle and copy the text to the buffer - auto pData = (LPTSTR)GlobalLock(hGlob); - if (pData) { - _tcscpy_s(pData, len, text.GetString()); - GlobalUnlock(hGlob); - - // Place the handle on the clipboard, if the call succeeds - // the system will take care of the allocated memory - if (::EmptyClipboard() && ::SetClipboardData(format, hGlob)) { - bResult = TRUE; - hGlob = nullptr; - } - } - - if (hGlob) { - GlobalFree(hGlob); - } - } - } - return bResult; -} +/* + * (C) 2011-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "WinAPIUtils.h" +#include "PathUtils.h" + + +bool SetPrivilege(LPCTSTR privilege, bool bEnable) +{ + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + + SetThreadExecutionState(ES_CONTINUOUS); + + // Get a token for this process. + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { + return false; + } + + // Get the LUID for the privilege. + LookupPrivilegeValue(nullptr, privilege, &tkp.Privileges[0].Luid); + + tkp.PrivilegeCount = 1; // one privilege to set + tkp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0; + + // Set the privilege for this process. + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)nullptr, 0); + + return (GetLastError() == ERROR_SUCCESS); +} + +CString GetHiveName(const HKEY hive) +{ + switch ((ULONG_PTR)hive) { + case (ULONG_PTR)HKEY_CLASSES_ROOT: + return _T("HKEY_CLASSES_ROOT"); + case (ULONG_PTR)HKEY_CURRENT_USER: + return _T("HKEY_CURRENT_USER"); + case (ULONG_PTR)HKEY_LOCAL_MACHINE: + return _T("HKEY_LOCAL_MACHINE"); + case (ULONG_PTR)HKEY_USERS: + return _T("HKEY_USERS"); + case (ULONG_PTR)HKEY_PERFORMANCE_DATA: + return _T("HKEY_PERFORMANCE_DATA"); + case (ULONG_PTR)HKEY_CURRENT_CONFIG: + return _T("HKEY_CURRENT_CONFIG"); + case (ULONG_PTR)HKEY_DYN_DATA: + return _T("HKEY_DYN_DATA"); + case (ULONG_PTR)HKEY_PERFORMANCE_TEXT: + return _T("HKEY_PERFORMANCE_TEXT"); + case (ULONG_PTR)HKEY_PERFORMANCE_NLSTEXT: + return _T("HKEY_PERFORMANCE_NLSTEXT"); + default: + return _T(""); + } +} + +bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName) +{ + // Registry functions don't set GetLastError(), so it needs to be set explicitly + LSTATUS errorCode = ERROR_SUCCESS; + + HKEY hKey = nullptr; + errorCode = RegOpenKeyEx(hKeyRoot, keyName, 0, KEY_READ, &hKey); + if (errorCode != ERROR_SUCCESS) { + SetLastError(errorCode); + return false; + } + + DWORD subKeysCount = 0, maxSubKeyLen = 0; + DWORD valuesCount = 0, maxValueNameLen = 0, maxValueDataLen = 0; + errorCode = RegQueryInfoKey(hKey, nullptr, nullptr, nullptr, &subKeysCount, &maxSubKeyLen, nullptr, &valuesCount, &maxValueNameLen, &maxValueDataLen, nullptr, nullptr); + if (errorCode != ERROR_SUCCESS) { + SetLastError(errorCode); + return false; + } + maxSubKeyLen += 1; + maxValueNameLen += 1; + + CString buffer; + + buffer.Format(_T("[%s\\%s]\n"), GetHiveName(hKeyRoot).GetString(), keyName.GetString()); + file.WriteString(buffer); + + CString valueName; + DWORD valueNameLen, valueDataLen, type; + BYTE* data = DEBUG_NEW BYTE[maxValueDataLen]; + + for (DWORD indexValue = 0; indexValue < valuesCount; indexValue++) { + valueNameLen = maxValueNameLen; + valueDataLen = maxValueDataLen; + + errorCode = RegEnumValue(hKey, indexValue, valueName.GetBuffer(maxValueNameLen), &valueNameLen, nullptr, &type, data, &valueDataLen); + if (errorCode != ERROR_SUCCESS) { + SetLastError(errorCode); + return false; + } + + switch (type) { + case REG_SZ: { + CString str((TCHAR*)data); + str.Replace(_T("\\"), _T("\\\\")); + str.Replace(_T("\""), _T("\\\"")); + buffer.Format(_T("\"%s\"=\"%s\"\n"), valueName.GetString(), str.GetString()); + file.WriteString(buffer); + } + break; + case REG_BINARY: + buffer.Format(_T("\"%s\"=hex:%02x"), valueName.GetString(), data[0]); + file.WriteString(buffer); + for (DWORD i = 1; i < valueDataLen; i++) { + buffer.Format(_T(",%02x"), data[i]); + file.WriteString(buffer); + } + file.WriteString(_T("\n")); + break; + case REG_DWORD: + buffer.Format(_T("\"%s\"=dword:%08lx\n"), valueName.GetString(), *((DWORD*)data)); + file.WriteString(buffer); + break; + default: { + CString msg; + msg.Format(_T("The value \"%s\\%s\\%s\" has an unsupported type and has been ignored.\nPlease report this error to the developers."), + GetHiveName(hKeyRoot).GetString(), keyName.GetString(), valueName.GetString()); + AfxMessageBox(msg, MB_ICONERROR | MB_OK); + } + delete [] data; + return false; + } + } + + delete [] data; + + file.WriteString(_T("\n")); + + CString subKeyName; + DWORD subKeyLen; + + for (DWORD indexSubKey = 0; indexSubKey < subKeysCount; indexSubKey++) { + subKeyLen = maxSubKeyLen; + + errorCode = RegEnumKeyEx(hKey, indexSubKey, subKeyName.GetBuffer(maxSubKeyLen), &subKeyLen, nullptr, nullptr, nullptr, nullptr); + if (errorCode != ERROR_SUCCESS) { + SetLastError(errorCode); + return false; + } + + buffer.Format(_T("%s\\%s"), keyName.GetString(), subKeyName.GetString()); + + if (!ExportRegistryKey(file, hKeyRoot, buffer)) { + return false; + } + } + + errorCode = RegCloseKey(hKey); + SetLastError(errorCode); + return true; +} + +UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd) +{ + if (hWnd == nullptr || pD3D == nullptr) { + return D3DADAPTER_DEFAULT; + } + + HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor == nullptr) { + return D3DADAPTER_DEFAULT; + } + + for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { + HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp); + if (hAdpMon == hMonitor) { + return adp; + } + } + + return D3DADAPTER_DEFAULT; +} + +int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX* /*lpelfe*/, NEWTEXTMETRICEX* /*lpntme*/, int /*FontType*/, LPARAM lParam) +{ + LPARAM* l = (LPARAM*)lParam; + *l = TRUE; + return TRUE; +} + +namespace +{ + void GetNonClientMetrics(NONCLIENTMETRICS* ncm) + { + ZeroMemory(ncm, sizeof(NONCLIENTMETRICS)); + ncm->cbSize = sizeof(NONCLIENTMETRICS); + VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm->cbSize, ncm, 0)); + } +} + +void GetMessageFont(LOGFONT* lf) +{ + NONCLIENTMETRICS ncm; + GetNonClientMetrics(&ncm); + *lf = ncm.lfMessageFont; + ASSERT(lf->lfHeight); +} + +void GetStatusFont(LOGFONT* lf) +{ + NONCLIENTMETRICS ncm; + GetNonClientMetrics(&ncm); + *lf = ncm.lfStatusFont; + ASSERT(lf->lfHeight); +} + +bool IsFontInstalled(LPCTSTR lpszFont) +{ + // Get the screen DC + CDC dc; + if (!dc.CreateCompatibleDC(nullptr)) { + return false; + } + + LOGFONT lf; + ZeroMemory(&lf, sizeof(LOGFONT)); + // Any character set will do + lf.lfCharSet = DEFAULT_CHARSET; + // Set the facename to check for + _tcscpy_s(lf.lfFaceName, lpszFont); + LPARAM lParam = 0; + // Enumerate fonts + EnumFontFamiliesEx(dc.GetSafeHdc(), &lf, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)&lParam, 0); + + return lParam ? true : false; +} + +bool ExploreToFile(LPCTSTR path) +{ + CoInitializeHelper co; + + bool success = false; + PIDLIST_ABSOLUTE pidl; + + if (PathUtils::Exists(path) && SHParseDisplayName(path, nullptr, &pidl, 0, nullptr) == S_OK) { + success = SUCCEEDED(SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0)); + CoTaskMemFree(pidl); + } + + return success; +} + +CoInitializeHelper::CoInitializeHelper() +{ + HRESULT res = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (res == RPC_E_CHANGED_MODE) { // Try another threading model + res = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + } + if (res != S_OK && res != S_FALSE) { + throw res; + } +} + +CoInitializeHelper::~CoInitializeHelper() +{ + CoUninitialize(); +} + +HRESULT FileDelete(CString file, HWND hWnd, bool recycle /*= true*/, bool noconfirm /*= false*/) +{ + // Strings in SHFILEOPSTRUCT must be double-null terminated + file.AppendChar(_T('\0')); + + SHFILEOPSTRUCT fileOpStruct; + ZeroMemory(&fileOpStruct, sizeof(SHFILEOPSTRUCT)); + fileOpStruct.hwnd = hWnd; + fileOpStruct.wFunc = FO_DELETE; + fileOpStruct.pFrom = file; + fileOpStruct.fFlags = FOF_FILESONLY | FOF_SILENT; + if (recycle) { + fileOpStruct.fFlags |= FOF_ALLOWUNDO; + } + if (noconfirm) { + fileOpStruct.fFlags |= FOF_NOCONFIRMATION; + } else { + fileOpStruct.fFlags |= FOF_WANTNUKEWARNING; + } + int hRes = SHFileOperation(&fileOpStruct); + if (fileOpStruct.fAnyOperationsAborted) { + hRes = E_ABORT; + } + TRACE(_T("Delete recycle=%d hRes=0x%08x, file=%s\n"), recycle, hRes, file.GetString()); + return hRes; +} + +BOOL CClipboard::SetText(const CString& text) const +{ +#ifdef _UNICODE + const UINT format = CF_UNICODETEXT; +#else + const UINT format = CF_TEXT; +#endif + + BOOL bResult = FALSE; + + if(m_bOpened) { + // Allocate a global memory object for the text + int len = text.GetLength() + 1; + auto hGlob = GlobalAlloc(GMEM_MOVEABLE, len*sizeof(TCHAR)); + if (hGlob) { + // Lock the handle and copy the text to the buffer + auto pData = (LPTSTR)GlobalLock(hGlob); + if (pData) { + _tcscpy_s(pData, len, text.GetString()); + GlobalUnlock(hGlob); + + // Place the handle on the clipboard, if the call succeeds + // the system will take care of the allocated memory + if (::EmptyClipboard() && ::SetClipboardData(format, hGlob)) { + bResult = TRUE; + hGlob = nullptr; + } + } + + if (hGlob) { + GlobalFree(hGlob); + } + } + } + return bResult; +} diff --git a/src/DSUtil/WinAPIUtils.h b/src/DSUtil/WinAPIUtils.h index b34fb3b6844..0e0af36489d 100644 --- a/src/DSUtil/WinAPIUtils.h +++ b/src/DSUtil/WinAPIUtils.h @@ -1,64 +1,64 @@ -/* - * (C) 2011-2014, 2016 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 . - * - */ - -#pragma once - -struct IDirect3D9; - - -bool SetPrivilege(LPCTSTR privilege, bool bEnable = true); - -bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName = _T("")); - -UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd); - -void GetMessageFont(LOGFONT* lf); -void GetStatusFont(LOGFONT* lf); - -bool IsFontInstalled(LPCTSTR lpszFont); - -bool ExploreToFile(LPCTSTR path); - -HRESULT FileDelete(CString file, HWND hWnd, bool recycle = true, bool noconfirm = false); - -class CoInitializeHelper -{ -public: - CoInitializeHelper(); - ~CoInitializeHelper(); -}; - -class CClipboard -{ -public: - CClipboard(CWnd* pWnd = nullptr) { - m_bOpened = ::OpenClipboard(pWnd->GetSafeHwnd()); - } - ~CClipboard() { - if(m_bOpened) { - VERIFY(::CloseClipboard()); - } - } - - BOOL SetText(const CString& text) const; - -protected: - BOOL m_bOpened; -}; +/* + * (C) 2011-2014, 2016 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 . + * + */ + +#pragma once + +struct IDirect3D9; + + +bool SetPrivilege(LPCTSTR privilege, bool bEnable = true); + +bool ExportRegistryKey(CStdioFile& file, HKEY hKeyRoot, CString keyName = _T("")); + +UINT GetAdapter(IDirect3D9* pD3D, HWND hWnd); + +void GetMessageFont(LOGFONT* lf); +void GetStatusFont(LOGFONT* lf); + +bool IsFontInstalled(LPCTSTR lpszFont); + +bool ExploreToFile(LPCTSTR path); + +HRESULT FileDelete(CString file, HWND hWnd, bool recycle = true, bool noconfirm = false); + +class CoInitializeHelper +{ +public: + CoInitializeHelper(); + ~CoInitializeHelper(); +}; + +class CClipboard +{ +public: + CClipboard(CWnd* pWnd = nullptr) { + m_bOpened = ::OpenClipboard(pWnd->GetSafeHwnd()); + } + ~CClipboard() { + if(m_bOpened) { + VERIFY(::CloseClipboard()); + } + } + + BOOL SetText(const CString& text) const; + +protected: + BOOL m_bOpened; +}; diff --git a/src/DSUtil/deinterlace.cpp b/src/DSUtil/deinterlace.cpp index b329ce10624..7ef0dce756c 100644 --- a/src/DSUtil/deinterlace.cpp +++ b/src/DSUtil/deinterlace.cpp @@ -1,1968 +1,1968 @@ -// VirtualDub - Video processing and capture application -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include "stdafx.h" -#include -#include "vd2/system/memory.h" -#include "vd2/system/cpuaccel.h" -#include "vd2/system/vdstl.h" - -#pragma warning(disable: 4799) // warning C4799: function has no EMMS instruction - -/////////////////////////////////////////////////////////////////////////// - -#ifdef _M_IX86 -static void __declspec(naked) asm_blend_row_clipped(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - __asm { - push ebp - push edi - push esi - push ebx - - mov edi,[esp+20] - mov esi,[esp+24] - sub edi,esi - mov ebp,[esp+28] - mov edx,[esp+32] - -xloop: - mov ecx,[esi] - mov eax,0fefefefeh - - mov ebx,[esi+edx] - and eax,ecx - - shr eax,1 - and ebx,0fefefefeh - - shr ebx,1 - add esi,4 - - add eax,ebx - dec ebp - - mov [edi+esi-4],eax - jnz xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -static void __declspec(naked) asm_blend_row(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - __asm { - push ebp - push edi - push esi - push ebx - - mov edi,[esp+20] - mov esi,[esp+24] - sub edi,esi - mov ebp,[esp+28] - mov edx,[esp+32] - -xloop: - mov ecx,[esi] - mov eax,0fcfcfcfch - - mov ebx,[esi+edx] - and eax,ecx - - shr ebx,1 - mov ecx,[esi+edx*2] - - shr ecx,2 - and ebx,07f7f7f7fh - - shr eax,2 - and ecx,03f3f3f3fh - - add eax,ebx - add esi,4 - - add eax,ecx - dec ebp - - mov [edi+esi-4],eax - jnz xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -static void __declspec(naked) asm_blend_row_MMX(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - static const __declspec(align(8)) __int64 mask0 = 0xfcfcfcfcfcfcfcfci64; - static const __declspec(align(8)) __int64 mask1 = 0x7f7f7f7f7f7f7f7fi64; - static const __declspec(align(8)) __int64 mask2 = 0x3f3f3f3f3f3f3f3fi64; - __asm { - push ebp - push edi - push esi - push ebx - - mov edi,[esp+20] - mov esi,[esp+24] - sub edi,esi - mov ebp,[esp+28] - mov edx,[esp+32] - - movq mm5,mask0 - movq mm6,mask1 - movq mm7,mask2 - inc ebp - shr ebp,1 -xloop: - movq mm2,[esi] - movq mm0,mm5 - - movq mm1,[esi+edx] - pand mm0,mm2 - - psrlq mm1,1 - movq mm2,[esi+edx*2] - - psrlq mm2,2 - pand mm1,mm6 - - psrlq mm0,2 - pand mm2,mm7 - - paddb mm0,mm1 - add esi,8 - - paddb mm0,mm2 - dec ebp - - movq [edi+esi-8],mm0 - jne xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -static void __declspec(naked) asm_blend_row_ISSE(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - __asm { - push ebp - push edi - push esi - push ebx - - mov edi,[esp+20] - mov esi,[esp+24] - sub edi,esi - mov ebp,[esp+28] - mov edx,[esp+32] - - inc ebp - shr ebp,1 - pcmpeqb mm7, mm7 - - align 16 -xloop: - movq mm0, [esi] - movq mm2, mm7 - pxor mm0, mm7 - - pxor mm2, [esi+edx*2] - pavgb mm0, mm2 - pxor mm0, mm7 - - pavgb mm0, [esi+edx] - add esi,8 - - movq [edi+esi-8],mm0 - dec ebp - jne xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} -#else -static void asm_blend_row_clipped(void *dst0, const void *src0, uint32 w, ptrdiff_t srcpitch) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - const uint32 *src2 = (const uint32 *)((const char *)src + srcpitch); - - do { - const uint32 x = *src++; - const uint32 y = *src2++; - - *dst++ = (x|y) - (((x^y)&0xfefefefe)>>1); - } while(--w); -} - -static void asm_blend_row(void *dst0, const void *src0, uint32 w, ptrdiff_t srcpitch) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - const uint32 *src2 = (const uint32 *)((const char *)src + srcpitch); - const uint32 *src3 = (const uint32 *)((const char *)src2 + srcpitch); - - do { - const uint32 a = *src++; - const uint32 b = *src2++; - const uint32 c = *src3++; - const uint32 hi = (a & 0xfcfcfc) + 2*(b & 0xfcfcfc) + (c & 0xfcfcfc); - const uint32 lo = (a & 0x030303) + 2*(b & 0x030303) + (c & 0x030303) + 0x020202; - - *dst++ = (hi + (lo & 0x0c0c0c))>>2; - } while(--w); -} -#endif - -#if defined(VD_CPU_X86) || defined(VD_CPU_AMD64) - static void asm_blend_row_SSE2(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { - __m128i zero = _mm_setzero_si128(); - __m128i inv = _mm_cmpeq_epi8(zero, zero); - - w = (w + 3) >> 2; - - const __m128i *src1 = (const __m128i *)src; - const __m128i *src2 = (const __m128i *)((const char *)src + srcpitch); - const __m128i *src3 = (const __m128i *)((const char *)src + srcpitch*2); - __m128i *dstrow = (__m128i *)dst; - do { - __m128i a = *src1++; - __m128i b = *src2++; - __m128i c = *src3++; - - *dstrow++ = _mm_avg_epu8(_mm_xor_si128(_mm_avg_epu8(_mm_xor_si128(a, inv), _mm_xor_si128(c, inv)), inv), b); - } while(--w); - } - - - void ela_L8_SSE2(__m128i *dst, const __m128i *srcat, const __m128i *srcab, int w16) { - do { - __m128i top0 = srcat[0]; - __m128i top1 = srcat[1]; - __m128i top2 = srcat[2]; - __m128i bot0 = srcab[0]; - __m128i bot1 = srcab[1]; - __m128i bot2 = srcab[2]; - ++srcat; - ++srcab; - - __m128i topl2 = _mm_or_si128(_mm_srli_si128(top0, 16 - 3), _mm_slli_si128(top1, 3)); - __m128i topl1 = _mm_or_si128(_mm_srli_si128(top0, 16 - 2), _mm_slli_si128(top1, 2)); - __m128i topc0 = _mm_or_si128(_mm_srli_si128(top0, 16 - 1), _mm_slli_si128(top1, 1)); - __m128i topr1 = top1; - __m128i topr2 = _mm_or_si128(_mm_srli_si128(top1, 1), _mm_slli_si128(top2, 16 - 1)); - __m128i topr3 = _mm_or_si128(_mm_srli_si128(top1, 2), _mm_slli_si128(top2, 16 - 2)); - - __m128i botl2 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 3), _mm_slli_si128(bot1, 3)); - __m128i botl1 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 2), _mm_slli_si128(bot1, 2)); - __m128i botc0 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 1), _mm_slli_si128(bot1, 1)); - __m128i botr1 = bot1; - __m128i botr2 = _mm_or_si128(_mm_srli_si128(bot1, 1), _mm_slli_si128(bot2, 16 - 1)); - __m128i botr3 = _mm_or_si128(_mm_srli_si128(bot1, 2), _mm_slli_si128(bot2, 16 - 2)); - - __m128i rawscorec0 = _mm_or_si128(_mm_subs_epu8(topc0, botc0), _mm_subs_epu8(botc0, topc0)); - __m128i rawscorel1 = _mm_or_si128(_mm_subs_epu8(topl1, botr1), _mm_subs_epu8(botr1, topl1)); - __m128i rawscorel2 = _mm_or_si128(_mm_subs_epu8(topl2, botr2), _mm_subs_epu8(botr2, topl2)); - __m128i rawscorer1 = _mm_or_si128(_mm_subs_epu8(topr1, botl1), _mm_subs_epu8(botl1, topr1)); - __m128i rawscorer2 = _mm_or_si128(_mm_subs_epu8(topr2, botl2), _mm_subs_epu8(botl2, topr2)); - - dst[0] = rawscorec0; - dst[1] = rawscorel1; - dst[2] = rawscorel2; - dst[3] = rawscorer1; - dst[4] = rawscorer2; - dst[5] = _mm_avg_epu8(topr1, botr1); - dst[6] = _mm_avg_epu8(topc0, botr2); - dst[7] = _mm_avg_epu8(topl1, botr3); - dst[8] = _mm_avg_epu8(topr2, botc0); - dst[9] = _mm_avg_epu8(topr3, botl1); - dst += 10; - } while(--w16); - } - - void nela_L8_SSE2(__m128i *dst, const __m128i *elabuf, int w16) { - __m128i zero = _mm_setzero_si128(); - __m128i x80b = _mm_set1_epi8((unsigned char)0x80); - - do { - __m128i x0, x1, x2, y; - - x0 = elabuf[0]; - y = elabuf[10]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorec0 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - x0 = elabuf[1]; - y = elabuf[11]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorel1 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - x0 = elabuf[2]; - y = elabuf[12]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorel2 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - x0 = elabuf[3]; - y = elabuf[13]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorer1 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - x0 = elabuf[4]; - y = elabuf[14]; - x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); - x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); - __m128i scorer2 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); - - scorec0 = _mm_xor_si128(scorec0, x80b); - scorel1 = _mm_xor_si128(scorel1, x80b); - scorel2 = _mm_xor_si128(scorel2, x80b); - scorer1 = _mm_xor_si128(scorer1, x80b); - scorer2 = _mm_xor_si128(scorer2, x80b); - - // result = (scorel1 < scorec0) ? (scorel2 < scorel1 ? l2 : l1) : (scorer1 < scorec0) ? (scorer2 < scorer1 ? r2 : r1) : c0 - - __m128i cmplt_l1_c0 = _mm_cmplt_epi8(scorel1, scorec0); - __m128i cmplt_r1_c0 = _mm_cmplt_epi8(scorer1, scorec0); - __m128i cmplt_l1_r1 = _mm_cmplt_epi8(scorel1, scorer1); - - __m128i is_l1 = _mm_and_si128(cmplt_l1_r1, cmplt_l1_c0); - __m128i is_r1 = _mm_andnot_si128(cmplt_l1_r1, cmplt_r1_c0); - __m128i is_c0_inv = _mm_or_si128(cmplt_l1_c0, cmplt_r1_c0); - __m128i is_c0 = _mm_andnot_si128(is_c0_inv, _mm_cmpeq_epi8(zero, zero)); - - __m128i is_l2 = _mm_and_si128(is_l1, _mm_cmplt_epi8(scorel2, scorel1)); - __m128i is_r2 = _mm_and_si128(is_r1, _mm_cmplt_epi8(scorer2, scorer1)); - - is_l1 = _mm_andnot_si128(is_l2, is_l1); - is_r1 = _mm_andnot_si128(is_r2, is_r1); - - __m128i mask_c0 = is_c0; - __m128i mask_l1 = is_l1; - __m128i mask_l2 = is_l2; - __m128i mask_r1 = is_r1; - __m128i mask_r2 = is_r2; - - __m128i result_c0 = _mm_and_si128(elabuf[5], mask_c0); - __m128i result_l1 = _mm_and_si128(elabuf[6], mask_l1); - __m128i result_l2 = _mm_and_si128(elabuf[7], mask_l2); - __m128i result_r1 = _mm_and_si128(elabuf[8], mask_r1); - __m128i result_r2 = _mm_and_si128(elabuf[9], mask_r2); - - elabuf += 10; - - __m128i pred = _mm_or_si128(_mm_or_si128(_mm_or_si128(result_l1, result_l2), _mm_or_si128(result_r1, result_r2)), result_c0); - - *dst++ = pred; - } while(--w16); - } -#endif - -#if defined(VD_CPU_X86) - void __declspec(naked) __stdcall ela_L8_MMX(void *dst, const void *srcat, const void *srcab, int w16) { - static const __declspec(align(8)) uint64 xFEb = 0xfefefefefefefefe; - __asm { - push ebx - mov ebx, [esp + 4 + 4] - mov ecx, [esp + 8 + 4] - mov edx, [esp + 12 + 4] - mov eax, [esp + 16 + 4] - movq mm7, xFEb - -xloop: - movq mm0, [ecx + 15] - movq mm1, [edx + 15] - movq mm4, mm0 - movq mm2, [ecx + 15 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 15 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx], mm0 - por mm2, mm3 - movq [ebx + 8], mm2 - - movq mm0, [ecx + 14] - movq mm1, [edx + 16] - movq mm4, mm0 - movq mm2, [ecx + 14 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 16 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 16], mm0 - por mm2, mm3 - movq [ebx + 24], mm2 - - movq mm0, [ecx + 13] - movq mm1, [edx + 17] - movq mm4, mm0 - movq mm2, [ecx + 13 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 17 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 32], mm0 - por mm2, mm3 - movq [ebx + 40], mm2 - - movq mm0, [ecx + 16] - movq mm1, [edx + 14] - movq mm4, mm0 - movq mm2, [ecx + 16 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 14 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 48], mm0 - por mm2, mm3 - movq [ebx + 56], mm2 - - movq mm0, [ecx + 17] - movq mm1, [edx + 13] - movq mm4, mm0 - movq mm2, [ecx + 17 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 13 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 64], mm0 - por mm2, mm3 - movq [ebx + 72], mm2 - - movq mm0, [ecx + 16] - movq mm1, [edx + 16] - movq mm2, [ecx + 16 + 8] - movq mm3, [edx + 16 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 80], mm1 - movq [ebx + 88], mm3 - - movq mm0, [ecx + 15] - movq mm1, [edx + 17] - movq mm2, [ecx + 15 + 8] - movq mm3, [edx + 17 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 96], mm1 - movq [ebx + 104], mm3 - - movq mm0, [ecx + 14] - movq mm1, [edx + 18] - movq mm2, [ecx + 14 + 8] - movq mm3, [edx + 18 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 112], mm1 - movq [ebx + 120], mm3 - - movq mm0, [ecx + 17] - movq mm1, [edx + 15] - movq mm2, [ecx + 17 + 8] - movq mm3, [edx + 15 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 128], mm1 - movq [ebx + 136], mm3 - - movq mm0, [ecx + 18] - movq mm1, [edx + 14] - movq mm2, [ecx + 18 + 8] - movq mm3, [edx + 14 + 8] - movq mm4, mm0 - movq mm5, mm2 - pxor mm0, mm1 - pxor mm2, mm3 - por mm1, mm4 - por mm3, mm5 - pand mm0, mm7 - pand mm2, mm7 - psrlw mm0, 1 - psrlw mm2, 1 - psubb mm1, mm0 - psubb mm3, mm2 - movq [ebx + 144], mm1 - movq [ebx + 152], mm3 - - add ebx, 160 - add ecx, 16 - add edx, 16 - dec eax - jne xloop - - emms - pop ebx - ret 16 - } - } - - void __declspec(naked) __stdcall ela_L8_ISSE(void *dst, const void *srcat, const void *srcab, int w16) { - static const __declspec(align(8)) uint64 xFEb = 0xfefefefefefefefe; - __asm { - push ebx - mov ebx, [esp + 4 + 4] - mov ecx, [esp + 8 + 4] - mov edx, [esp + 12 + 4] - mov eax, [esp + 16 + 4] - movq mm7, xFEb - -xloop: - movq mm0, [ecx + 15] - movq mm1, [edx + 15] - movq mm4, mm0 - movq mm2, [ecx + 15 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 15 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx], mm0 - por mm2, mm3 - movq [ebx + 8], mm2 - - movq mm0, [ecx + 14] - movq mm1, [edx + 16] - movq mm4, mm0 - movq mm2, [ecx + 14 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 16 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 16], mm0 - por mm2, mm3 - movq [ebx + 24], mm2 - - movq mm0, [ecx + 13] - movq mm1, [edx + 17] - movq mm4, mm0 - movq mm2, [ecx + 13 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 17 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 32], mm0 - por mm2, mm3 - movq [ebx + 40], mm2 - - movq mm0, [ecx + 16] - movq mm1, [edx + 14] - movq mm4, mm0 - movq mm2, [ecx + 16 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 14 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 48], mm0 - por mm2, mm3 - movq [ebx + 56], mm2 - - movq mm0, [ecx + 17] - movq mm1, [edx + 13] - movq mm4, mm0 - movq mm2, [ecx + 17 + 8] - psubusb mm0, mm1 - movq mm3, [edx + 13 + 8] - movq mm5, mm2 - psubusb mm2, mm3 - psubusb mm1, mm4 - psubusb mm3, mm5 - por mm0, mm1 - movq [ebx + 64], mm0 - por mm2, mm3 - movq [ebx + 72], mm2 - - movq mm0, [ecx + 16] - movq mm1, [edx + 16] - movq mm2, [ecx + 16 + 8] - movq mm3, [edx + 16 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 80], mm1 - movq [ebx + 88], mm3 - - movq mm0, [ecx + 15] - movq mm1, [edx + 17] - movq mm2, [ecx + 15 + 8] - movq mm3, [edx + 17 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 96], mm1 - movq [ebx + 104], mm3 - - movq mm0, [ecx + 14] - movq mm1, [edx + 18] - movq mm2, [ecx + 14 + 8] - movq mm3, [edx + 18 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 112], mm1 - movq [ebx + 120], mm3 - - movq mm0, [ecx + 17] - movq mm1, [edx + 15] - movq mm2, [ecx + 17 + 8] - movq mm3, [edx + 15 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 128], mm1 - movq [ebx + 136], mm3 - - movq mm0, [ecx + 18] - movq mm1, [edx + 14] - movq mm2, [ecx + 18 + 8] - movq mm3, [edx + 14 + 8] - pavgb mm1, mm0 - pavgb mm3, mm2 - movq [ebx + 144], mm1 - movq [ebx + 152], mm3 - - add ebx, 160 - add ecx, 16 - add edx, 16 - dec eax - jne xloop - - emms - pop ebx - ret 16 - } - } - - void __declspec(naked) __stdcall nela_L8_ISSE(void *dst, const void *elabuf, int w16) { - static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; - __asm { - mov edx, [esp+4] - mov ecx, [esp+8] - mov eax, [esp+12] -xloop: - movq mm0, [ecx+000h] - pavgb mm0, [ecx+002h] - pavgb mm0, [ecx+001h] - - movq mm1, [ecx+010h] - pavgb mm1, [ecx+012h] - pavgb mm1, [ecx+011h] - - movq mm2, [ecx+020h] - pavgb mm2, [ecx+022h] - pavgb mm2, [ecx+021h] - - movq mm3, [ecx+030h] - pavgb mm3, [ecx+032h] - pavgb mm3, [ecx+031h] - - movq mm4, [ecx+040h] - pavgb mm4, [ecx+042h] - pavgb mm4, [ecx+041h] - - movq mm5, x7fb - pxor mm0, mm5 - pxor mm1, mm5 - pxor mm2, mm5 - pxor mm3, mm5 - pxor mm4, mm5 - - ;mm0 = scorec0 - ;mm1 = scorel1 - ;mm2 = scorel2 - ;mm3 = scorer1 - ;mm4 = scorer2 - - movq mm5, mm3 - pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) - - pcmpgtb mm4, mm3 ;scorer2 > scorer1 - pcmpgtb mm2, mm1 ;scorel2 > scorel1 - - pcmpgtb mm1, mm0 ;scorel1 > scorec0 - pcmpgtb mm3, mm0 ;scorer1 > scorec0 - - movq mm6, mm1 - pcmpeqb mm0, mm0 - por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 - pxor mm0, mm6 ;mask_c0 - - pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 - pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 - - pand mm4, mm3 ;mask_r2 - pand mm2, mm5 ;mask_l2 - - pxor mm3, mm4 ;mask_r1 - pxor mm5, mm2 ;mask_l1 - - pand mm0, [ecx+050h] - pand mm5, [ecx+060h] - pand mm2, [ecx+070h] - pand mm3, [ecx+080h] - pand mm4, [ecx+090h] - por mm0, mm5 - por mm2, mm3 - por mm0, mm4 - por mm0, mm2 - movq [edx], mm0 - - movq mm0, [ecx+008h] - movq mm5, [ecx+0a0h] - movq mm6, mm0 - psrlq mm0, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm0, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm0, [ecx+008h] - pavgb mm0, mm6 - - movq mm1, [ecx+018h] - movq mm5, [ecx+0b0h] - movq mm6, mm1 - psrlq mm1, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm1, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm1, [ecx+018h] - pavgb mm1, mm6 - - movq mm2, [ecx+028h] - movq mm5, [ecx+0c0h] - movq mm6, mm2 - psrlq mm2, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm2, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm2, [ecx+028h] - pavgb mm2, mm6 - - movq mm3, [ecx+038h] - movq mm5, [ecx+0d0h] - movq mm6, mm3 - psrlq mm3, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm3, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm3, [ecx+038h] - pavgb mm3, mm6 - - movq mm4, [ecx+048h] - movq mm5, [ecx+0e0h] - movq mm6, mm4 - psrlq mm4, 16 - movq mm7, mm5 - psllq mm5, 48 - por mm4, mm5 - psrlq mm6, 8 - psllq mm7, 56 - por mm6, mm7 - pavgb mm4, [ecx+048h] - pavgb mm4, mm6 - - movq mm5, x7fb - pxor mm0, mm5 - pxor mm1, mm5 - pxor mm2, mm5 - pxor mm3, mm5 - pxor mm4, mm5 - - ;mm0 = scorec0 - ;mm1 = scorel1 - ;mm2 = scorel2 - ;mm3 = scorer1 - ;mm4 = scorer2 - - movq mm5, mm3 - pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) - - pcmpgtb mm4, mm3 ;scorer2 > scorer1 - pcmpgtb mm2, mm1 ;scorel2 > scorel1 - - pcmpgtb mm1, mm0 ;scorel1 > scorec0 - pcmpgtb mm3, mm0 ;scorer1 > scorec0 - - movq mm6, mm1 - pcmpeqb mm0, mm0 - por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 - pxor mm0, mm6 ;mask_c0 - - pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 - pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 - - pand mm4, mm3 ;mask_r2 - pand mm2, mm5 ;mask_l2 - - pxor mm3, mm4 ;mask_r1 - pxor mm5, mm2 ;mask_l1 - - pand mm0, [ecx+058h] - pand mm5, [ecx+068h] - pand mm2, [ecx+078h] - pand mm3, [ecx+088h] - pand mm4, [ecx+098h] - por mm0, mm5 - por mm2, mm3 - por mm0, mm4 - por mm0, mm2 - movq [edx+8], mm0 - - add ecx, 0a0h - add edx, 16 - - dec eax - jnz xloop - - emms - ret 12 - } - } - - void __declspec(naked) __stdcall nela_L8_MMX(void *dst, const void *elabuf, int w16) { - static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; - - __asm { - mov edx, [esp+4] - mov ecx, [esp+8] - mov eax, [esp+12] -xloop: - movq mm0, [ecx+000h] - movq mm5, [ecx+002h] - movq mm6, mm0 - pxor mm0, mm5 - por mm6, mm5 - movq mm7, [ecx+001h] - psrlq mm0, 1 - pand mm0, x7fb - psubb mm6, mm0 - movq mm0, mm6 - pxor mm6, mm7 - por mm0, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm0, mm6 - - movq mm1, [ecx+010h] - movq mm5, [ecx+012h] - movq mm6, mm1 - pxor mm1, mm5 - por mm6, mm5 - movq mm7, [ecx+011h] - psrlq mm1, 1 - pand mm1, x7fb - psubb mm6, mm1 - movq mm1, mm6 - pxor mm6, mm7 - por mm1, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm1, mm6 - - movq mm2, [ecx+020h] - movq mm5, [ecx+022h] - movq mm6, mm2 - pxor mm2, mm5 - por mm6, mm5 - movq mm7, [ecx+021h] - psrlq mm2, 1 - pand mm2, x7fb - psubb mm6, mm2 - movq mm2, mm6 - pxor mm6, mm7 - por mm2, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm2, mm6 - - movq mm3, [ecx+030h] - movq mm5, [ecx+032h] - movq mm6, mm3 - pxor mm3, mm5 - por mm6, mm5 - movq mm7, [ecx+031h] - psrlq mm3, 1 - pand mm3, x7fb - psubb mm6, mm3 - movq mm3, mm6 - pxor mm6, mm7 - por mm3, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm3, mm6 - - movq mm4, [ecx+040h] - movq mm5, [ecx+042h] - movq mm6, mm4 - pxor mm4, mm5 - por mm6, mm5 - movq mm7, [ecx+041h] - psrlq mm4, 1 - pand mm4, x7fb - psubb mm6, mm4 - movq mm4, mm6 - pxor mm6, mm7 - por mm4, mm7 - psrlq mm6, 1 - pand mm6, x7fb - psubb mm4, mm6 - - - movq mm5, x7fb - pxor mm0, mm5 - pxor mm1, mm5 - pxor mm2, mm5 - pxor mm3, mm5 - pxor mm4, mm5 - - ;mm0 = scorec0 - ;mm1 = scorel1 - ;mm2 = scorel2 - ;mm3 = scorer1 - ;mm4 = scorer2 - - movq mm5, mm3 - pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) - - pcmpgtb mm4, mm3 ;scorer2 > scorer1 - pcmpgtb mm2, mm1 ;scorel2 > scorel1 - - pcmpgtb mm1, mm0 ;scorel1 > scorec0 - pcmpgtb mm3, mm0 ;scorer1 > scorec0 - - movq mm6, mm1 - pcmpeqb mm0, mm0 - por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 - pxor mm0, mm6 ;mask_c0 - - pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 - pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 - - pand mm4, mm3 ;mask_r2 - pand mm2, mm5 ;mask_l2 - - pxor mm3, mm4 ;mask_r1 - pxor mm5, mm2 ;mask_l1 - - pand mm0, [ecx+050h] - pand mm5, [ecx+060h] - pand mm2, [ecx+070h] - pand mm3, [ecx+080h] - pand mm4, [ecx+090h] - por mm0, mm5 - por mm2, mm3 - por mm0, mm4 - por mm0, mm2 - - movq [edx], mm0 - - movq mm0, [ecx+008h] ;mm0 = x0 - movq mm5, [ecx+0a0h] ;mm5 = x1 - psrlq mm0, 16 ;mm0 = (x0 >> 16) - movq mm7, [ecx+008h] ;mm7 = y0 = x0 - psllq mm5, 48 ;mm5 = (x1 << 48) - movq mm6, mm7 ;mm6 = y0 = x0 - por mm0, mm5 ;mm0 = y2 = (x0 >> 16) | (x1 << 48) - pxor mm6, mm0 ;mm6 = y0 ^ y2 - por mm7, mm0 ;mm7 = y0 | y2 - movq mm5, [ecx+008h] ;mm5 = x0 - psrlq mm6, 1 ;mm6 = (y0 ^ y2) >> 1 - movq mm0, [ecx+0a0h] ;mm0 = x1 - psrlq mm5, 8 ;mm5 = x0 >> 8 - pand mm6, x7fb ;mm6 = ((y0 ^ y2) >> 1) & 0x7f7f7f7f7f7f7f7f - psllq mm0, 56 ;mm0 = x1 << 56 - psubb mm7, mm6 ;mm7 = t = (y0 | y2) - (((y0 ^ y2) >> 1) & 0x7f7f7f7f7f7f7f7f) = avgb(y0, y2) - por mm0, mm5 ;mm0 = y1 = (x0 >> 8) | (x1 << 56) - movq mm6, mm7 ;mm6 = t - pxor mm7, mm0 ;mm7 = t ^ y1 - por mm0, mm6 ;mm0 = t | y1 - psrlq mm7, 1 ;mm7 = (t ^ y1) >> 1 - pand mm7, x7fb ;mm7 = ((t ^ y1) >> 1) & 0x7f7f7f7f7f7f7f7f - psubb mm0, mm7 ;mm0 = (t | y1) - (((t ^ y1) >> 1) & 0x7f7f7f7f7f7f7f7f) = avgb(y1, avgb(y0, y2)) - - movq mm1, [ecx+018h] - movq mm5, [ecx+0b0h] - psrlq mm1, 16 - movq mm7, [ecx+018h] - psllq mm5, 48 - movq mm6, mm7 - por mm1, mm5 - pxor mm6, mm1 - por mm7, mm1 - movq mm5, [ecx+018h] - psrlq mm6, 1 - movq mm1, [ecx+0b0h] - psrlq mm5, 8 - pand mm6, x7fb - psllq mm1, 56 - psubb mm7, mm6 - por mm1, mm5 - movq mm6, mm7 - pxor mm7, mm1 - por mm1, mm6 - psrlq mm7, 1 - pand mm7, x7fb - psubb mm1, mm7 - - movq mm2, [ecx+028h] - movq mm5, [ecx+0c0h] - psrlq mm2, 16 - movq mm7, [ecx+028h] - psllq mm5, 48 - movq mm6, mm7 - por mm2, mm5 - pxor mm6, mm2 - por mm7, mm2 - movq mm5, [ecx+028h] - psrlq mm6, 1 - movq mm2, [ecx+0c0h] - psrlq mm5, 8 - pand mm6, x7fb - psllq mm2, 56 - psubb mm7, mm6 - por mm2, mm5 - movq mm6, mm7 - pxor mm7, mm2 - por mm2, mm6 - psrlq mm7, 1 - pand mm7, x7fb - psubb mm2, mm7 - - movq mm3, [ecx+038h] - movq mm5, [ecx+0d0h] - psrlq mm3, 16 - movq mm7, [ecx+038h] - psllq mm5, 48 - movq mm6, mm7 - por mm3, mm5 - pxor mm6, mm3 - por mm7, mm3 - movq mm5, [ecx+038h] - psrlq mm6, 1 - movq mm3, [ecx+0d0h] - psrlq mm5, 8 - pand mm6, x7fb - psllq mm3, 56 - psubb mm7, mm6 - por mm3, mm5 - movq mm6, mm7 - pxor mm7, mm3 - por mm3, mm6 - psrlq mm7, 1 - pand mm7, x7fb - psubb mm3, mm7 - - movq mm4, [ecx+048h] - movq mm5, [ecx+0e0h] - psrlq mm4, 16 - movq mm7, [ecx+048h] - psllq mm5, 48 - movq mm6, mm7 - por mm4, mm5 - pxor mm6, mm4 - por mm7, mm4 - movq mm5, [ecx+048h] - psrlq mm6, 1 - movq mm4, [ecx+0e0h] - psrlq mm5, 8 - pand mm6, x7fb - psllq mm4, 56 - psubb mm7, mm6 - por mm4, mm5 - movq mm6, mm7 - pxor mm7, mm4 - por mm4, mm6 - psrlq mm7, 1 - pand mm7, x7fb - psubb mm4, mm7 - - movq mm5, x7fb - pxor mm0, mm5 - pxor mm1, mm5 - pxor mm2, mm5 - pxor mm3, mm5 - pxor mm4, mm5 - - ;mm0 = scorec0 - ;mm1 = scorel1 - ;mm2 = scorel2 - ;mm3 = scorer1 - ;mm4 = scorer2 - - movq mm5, mm3 - pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) - - pcmpgtb mm4, mm3 ;scorer2 > scorer1 - pcmpgtb mm2, mm1 ;scorel2 > scorel1 - - pcmpgtb mm1, mm0 ;scorel1 > scorec0 - pcmpgtb mm3, mm0 ;scorer1 > scorec0 - - movq mm6, mm1 - pcmpeqb mm0, mm0 - por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 - pxor mm0, mm6 ;mask_c0 - - pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 - pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 - - pand mm4, mm3 ;mask_r2 - pand mm2, mm5 ;mask_l2 - - pxor mm3, mm4 ;mask_r1 - pxor mm5, mm2 ;mask_l1 - - pand mm0, [ecx+058h] - pand mm5, [ecx+068h] - pand mm2, [ecx+078h] - pand mm3, [ecx+088h] - pand mm4, [ecx+098h] - por mm0, mm5 - por mm2, mm3 - por mm0, mm4 - por mm0, mm2 - movq [edx+8], mm0 - - add ecx, 0a0h - add edx, 16 - - dec eax - jnz xloop - - emms - ret 12 - } - } -#endif - -namespace { - void ela_L8_scalar(uint8 *dst, const uint8 *srcat, const uint8 *srcab, int w16) { - int w = w16 << 4; - - srcat += 16; - srcab += 16; - do { - int topl2 = srcat[-3]; - int topl1 = srcat[-2]; - int topc0 = srcat[-1]; - int topr1 = srcat[0]; - int topr2 = srcat[1]; - int topr3 = srcat[2]; - - int botl2 = srcab[-3]; - int botl1 = srcab[-2]; - int botc0 = srcab[-1]; - int botr1 = srcab[0]; - int botr2 = srcab[1]; - int botr3 = srcab[2]; - ++srcat; - ++srcab; - - int rawscorec0 = abs(topc0 - botc0); - int rawscorel1 = abs(topl1 - botr1); - int rawscorel2 = abs(topl2 - botr2); - int rawscorer1 = abs(topr1 - botl1); - int rawscorer2 = abs(topr2 - botl2); - - dst[0] = (uint8)rawscorec0; - dst[1] = (uint8)rawscorel1; - dst[2] = (uint8)rawscorel2; - dst[3] = (uint8)rawscorer1; - dst[4] = (uint8)rawscorer2; - dst[5] = (uint8)((topr1 + botr1 + 1) >> 1); - dst[6] = (uint8)((topc0 + botr2 + 1) >> 1); - dst[7] = (uint8)((topl1 + botr3 + 1) >> 1); - dst[8] = (uint8)((topr2 + botc0 + 1) >> 1); - dst[9] = (uint8)((topr3 + botl1 + 1) >> 1); - dst += 10; - } while(--w); - } - - void nela_L8_scalar(uint8 *dst, const uint8 *elabuf, int w16) { - int w = w16 << 4; - - do { - int scorec0 = elabuf[10]*2 + (elabuf[0] + elabuf[20]); - int result = elabuf[5]; - - int scorel1 = elabuf[11]*2 + (elabuf[1] + elabuf[21]); - if (scorel1 < scorec0) { - result = elabuf[6]; - scorec0 = scorel1; - - int scorel2 = elabuf[12]*2 + (elabuf[2] + elabuf[22]); - if (scorel2 < scorec0) { - result = elabuf[7]; - scorec0 = scorel2; - } - } - - int scorer1 = elabuf[13]*2 + (elabuf[3] + elabuf[23]); - if (scorer1 < scorec0) { - result = elabuf[8]; - scorec0 = scorer1; - - int scorer2 = elabuf[14]*2 + (elabuf[4] + elabuf[24]); - if (scorer2 < scorec0) - result = elabuf[9]; - } - - elabuf += 10; - - *dst++ = (uint8)result; - } while(--w); - } - - void BlendScanLine_NELA_scalar(void *dst, const void *srcT, const void *srcB, uint32 w, uint8 *tempBuf) { - const uint8 *srcat = (const uint8 *)srcT; - const uint8 *srcab = (const uint8 *)srcB; - uint32 w16 = (w + 15) >> 4; - uint32 wr = w16 << 4; - - uint8 *elabuf = tempBuf; - uint8 *topbuf = elabuf + 10*wr; - uint8 *botbuf = topbuf + wr + 32; - - uint32 woffset = w & 15; - topbuf[13] = topbuf[14] = topbuf[15] = srcat[0]; - botbuf[13] = botbuf[14] = botbuf[15] = srcab[0]; - - for(uint32 x=0; x> 1); - srca += 4; - srcb += 4; - } while(--w4); - } - - void BlendScanLine_NELA_X8R8G8B8_scalar(void *dst, const void *srcT, const void *srcB, uint32 w, void *tempBuf) { - const uint32 *srcat = (const uint32 *)srcT; - const uint32 *srcab = (const uint32 *)srcB; - uint32 w4 = (w + 3) >> 2; - uint32 *elabuf = (uint32 *)tempBuf; - uint32 *topbuf = elabuf + 5*w4; - uint32 *botbuf = topbuf + w4 + 8; - - topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = srcat[0]; - botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = srcab[0]; - - for(uint32 x=0; x> 2; - uint32 *elabuf = (uint32 *)tempBuf; - uint32 *topbuf = elabuf + 5*w4; - uint32 *botbuf = topbuf + w4 + 8; - - topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = srcat[0]; - botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = srcab[0]; - - for(uint32 x=0; x> 4; - uint32 w4 = w16 * 4; - uint32 *elabuf = (uint32 *)tempBuf; - uint32 *topbuf = elabuf + 40*w16; - uint32 *botbuf = topbuf + w4 + 8; - - uint32 woffset = w & 15; - topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = (srcat[0] & 0xff) * 0x01010101; - botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = (srcab[0] & 0xff) * 0x01010101; - - for(uint32 x=0; x> 4; - __m128i *elabuf = tempBuf; - __m128i *topbuf = elabuf + 10*w16; - __m128i *botbuf = topbuf + w16 + 2; - - uint32 woffset = w & 15; - topbuf[0] = srcat[0]; - botbuf[0] = srcab[0]; - - for(uint32 x=0; x> 4; - vdfastvector > tempbuf((12 * w16 + 4) * 16); - void *elabuf = tempbuf.data(); - - if (!interpField2) - memcpy(dst, src, w16 << 4); - - int y0 = interpField2 ? 1 : 2; - for(uint32 y = y0; y < h - 1; y += 2) { - const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); - const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); - -#if defined(VD_CPU_X86) - if (MMX_enabled) - BlendScanLine_NELA_X8R8G8B8_MMX((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); - else -#endif - BlendScanLine_NELA_X8R8G8B8_scalar((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); - } - - if (interpField2) - memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w16 << 4); - } - - void InterpPlane_NELA(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, uint32 w, uint32 h, bool interpField2) { - uint32 w16 = (w + 15) >> 4; - vdfastvector > tempbuf((12 * w16 + 4) * 16); - void *elabuf = tempbuf.data(); - - if (!interpField2) - memcpy(dst, src, w16 << 4); - - int y0 = interpField2 ? 1 : 2; - if (SSE2_enabled) { - for(uint32 y = y0; y < h - 1; y += 2) { - const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); - const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); - - BlendScanLine_NELA_SSE2((char *)dst + dstpitch*y, srcat, srcab, w, (__m128i *)elabuf); - } - } -#if defined(VD_CPU_X86) - else if (MMX_enabled || ISSE_enabled) { - for(uint32 y = y0; y < h - 1; y += 2) { - const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); - const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); - - BlendScanLine_NELA_MMX_ISSE((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); - } - } -#endif - else { - for(uint32 y = y0; y < h - 1; y += 2) { - const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); - const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); - - BlendScanLine_NELA_scalar((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); - } - } - - if (interpField2) - memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w16 << 4); - } - - void Average_scalar(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { - uint32 w4 = w16 << 2; - do { - uint32 *dstv = (uint32 *)dst; - uint32 *src1v = (uint32 *)src1; - uint32 *src2v = (uint32 *)src2; - - for(uint32 i=0; i> 1); - } - - dst = (char *)dst + dstPitch; - src1 = (char *)src1 + srcPitch; - src2 = (char *)src2 + srcPitch; - } while(--h); - } - -#if defined(VD_CPU_X86) - void __declspec(naked) __cdecl Average_MMX(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { - static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; - static const __declspec(align(8)) uint64 xfeb = 0xfefefefefefefefe; - - __asm { - push ebp - push edi - push esi - push ebx - - mov esi, [esp+24+16] - mov eax, [esp+4+16] - shl esi, 4 - mov ecx, [esp+12+16] - mov edx, [esp+16+16] - mov ebp, [esp+20+16] - mov edi, [esp+8+16] - sub edi, esi - sub ebp, esi - - movq mm6, x7fb - movq mm7, xfeb - - mov esi, [esp+28+16] -yloop: - mov ebx, [esp+24+16] -mainRowLoop: - movq mm0, [ecx] - movq mm3, [ecx + 8] - movq mm1, mm0 - movq mm2, [edx] - movq mm4, mm3 - movq mm5, [edx + 8] - por mm1, mm2 - pxor mm0, mm2 - por mm4, mm5 - pxor mm3, mm5 - psrlq mm0, 1 - pand mm3, mm7 - pand mm0, mm6 - psrlq mm3, 1 - psubb mm1, mm0 - psubb mm4, mm3 - add ecx, 16 - movq [eax], mm1 - movq [eax+8], mm4 - add edx, 16 - add eax, 16 - dec ebx - jne mainRowLoop - - add eax, edi - add ecx, ebp - add edx, ebp - dec esi - jne yloop - - emms - pop ebx - pop esi - pop edi - pop ebp - ret - } - } - - void __declspec(naked) __cdecl Average_ISSE(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { - static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; - static const __declspec(align(8)) uint64 xfeb = 0xfefefefefefefefe; - - __asm { - push ebp - push edi - push esi - push ebx - - mov esi, [esp+24+16] - mov eax, [esp+4+16] - shl esi, 4 - mov ecx, [esp+12+16] - mov edx, [esp+16+16] - mov ebp, [esp+20+16] - mov edi, [esp+8+16] - sub edi, esi - sub ebp, esi - - movq mm6, x7fb - movq mm7, xfeb - - mov esi, [esp+28+16] -yloop: - mov ebx, [esp+24+16] -mainRowLoop: - movq mm0, [ecx] - movq mm1, [ecx + 8] - movq mm2, [edx] - movq mm3, [edx + 8] - pavgb mm0, mm2 - pavgb mm1, mm3 - movq [eax], mm0 - add ecx, 16 - add edx, 16 - movq [eax+8], mm1 - add eax, 16 - dec ebx - jne mainRowLoop - - add eax, edi - add ecx, ebp - add edx, ebp - dec esi - jne yloop - - emms - pop ebx - pop esi - pop edi - pop ebp - ret - } - } -#endif - -#if defined(VD_CPU_X86) || defined(VD_CPU_AMD64) - void Average_SSE2(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { - do { - __m128i *dstv = (__m128i *)dst; - __m128i *src1v = (__m128i *)src1; - __m128i *src2v = (__m128i *)src2; - - for(uint32 i=0; i> 2; - - uint32 y0 = interpField2 ? 1 : 2; - - if (!interpField2) - memcpy(dst, src, w * 4); - - if (h > y0) { - ASSERT(((UINT_PTR)dst & 0xF) == 0); - ASSERT((dstpitch & 0xF) == 0); - ASSERT(((UINT_PTR)src & 0xF) == 0); - ASSERT((srcpitch*(y0 - 1) & 0xF) == 0); - blend_func((char *)dst + dstpitch*y0, - dstpitch*2, - (const char *)src + srcpitch*(y0 - 1), - (const char *)src + srcpitch*(y0 + 1), - srcpitch*2, - (w + 3) >> 2, - (h - y0) >> 1); - } - - if (interpField2) - memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w*4); - -#ifdef _M_IX86 - if (MMX_enabled) - __asm emms -#endif - } - - void BlendPlane(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, uint32 w, uint32 h) { - void (*blend_func)(void *, const void *, uint32, ptrdiff_t); -#if defined(VD_CPU_X86) - if (SSE2_enabled && !(srcpitch % 16)) - blend_func = asm_blend_row_SSE2; - else - blend_func = ISSE_enabled ? asm_blend_row_ISSE : MMX_enabled ? asm_blend_row_MMX : asm_blend_row; -#else - blend_func = asm_blend_row_SSE2; -#endif - - w = (w + 3) >> 2; - - asm_blend_row_clipped(dst, src, w, srcpitch); - if (h-=2) - do { - dst = ((char *)dst + dstpitch); - - blend_func(dst, src, w, srcpitch); - - src = ((char *)src + srcpitch); - } while(--h); - - asm_blend_row_clipped((char *)dst + dstpitch, src, w, srcpitch); - -#ifdef _M_IX86 - if (MMX_enabled) - __asm emms -#endif - } -} - -void DeinterlaceELA_X8R8G8B8(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) -{ - topfield = !topfield; - - InterpPlane_NELA_X8R8G8B8(dst, dstpitch, src, srcpitch, w, h, topfield); -} - -void DeinterlaceELA(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) -{ - topfield = !topfield; - - InterpPlane_NELA(dst, dstpitch, src, srcpitch, w, h, topfield); -} - -void DeinterlaceBob(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) -{ - topfield = !topfield; - - InterpPlane_Bob(dst, dstpitch, src, srcpitch, w, h, topfield); -} - -void DeinterlaceBlend(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch) -{ - BlendPlane(dst, dstpitch, src, srcpitch, w, h); -} +// VirtualDub - Video processing and capture application +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include "stdafx.h" +#include +#include "vd2/system/memory.h" +#include "vd2/system/cpuaccel.h" +#include "vd2/system/vdstl.h" + +#pragma warning(disable: 4799) // warning C4799: function has no EMMS instruction + +/////////////////////////////////////////////////////////////////////////// + +#ifdef _M_IX86 +static void __declspec(naked) asm_blend_row_clipped(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + __asm { + push ebp + push edi + push esi + push ebx + + mov edi,[esp+20] + mov esi,[esp+24] + sub edi,esi + mov ebp,[esp+28] + mov edx,[esp+32] + +xloop: + mov ecx,[esi] + mov eax,0fefefefeh + + mov ebx,[esi+edx] + and eax,ecx + + shr eax,1 + and ebx,0fefefefeh + + shr ebx,1 + add esi,4 + + add eax,ebx + dec ebp + + mov [edi+esi-4],eax + jnz xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +static void __declspec(naked) asm_blend_row(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + __asm { + push ebp + push edi + push esi + push ebx + + mov edi,[esp+20] + mov esi,[esp+24] + sub edi,esi + mov ebp,[esp+28] + mov edx,[esp+32] + +xloop: + mov ecx,[esi] + mov eax,0fcfcfcfch + + mov ebx,[esi+edx] + and eax,ecx + + shr ebx,1 + mov ecx,[esi+edx*2] + + shr ecx,2 + and ebx,07f7f7f7fh + + shr eax,2 + and ecx,03f3f3f3fh + + add eax,ebx + add esi,4 + + add eax,ecx + dec ebp + + mov [edi+esi-4],eax + jnz xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +static void __declspec(naked) asm_blend_row_MMX(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + static const __declspec(align(8)) __int64 mask0 = 0xfcfcfcfcfcfcfcfci64; + static const __declspec(align(8)) __int64 mask1 = 0x7f7f7f7f7f7f7f7fi64; + static const __declspec(align(8)) __int64 mask2 = 0x3f3f3f3f3f3f3f3fi64; + __asm { + push ebp + push edi + push esi + push ebx + + mov edi,[esp+20] + mov esi,[esp+24] + sub edi,esi + mov ebp,[esp+28] + mov edx,[esp+32] + + movq mm5,mask0 + movq mm6,mask1 + movq mm7,mask2 + inc ebp + shr ebp,1 +xloop: + movq mm2,[esi] + movq mm0,mm5 + + movq mm1,[esi+edx] + pand mm0,mm2 + + psrlq mm1,1 + movq mm2,[esi+edx*2] + + psrlq mm2,2 + pand mm1,mm6 + + psrlq mm0,2 + pand mm2,mm7 + + paddb mm0,mm1 + add esi,8 + + paddb mm0,mm2 + dec ebp + + movq [edi+esi-8],mm0 + jne xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +static void __declspec(naked) asm_blend_row_ISSE(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + __asm { + push ebp + push edi + push esi + push ebx + + mov edi,[esp+20] + mov esi,[esp+24] + sub edi,esi + mov ebp,[esp+28] + mov edx,[esp+32] + + inc ebp + shr ebp,1 + pcmpeqb mm7, mm7 + + align 16 +xloop: + movq mm0, [esi] + movq mm2, mm7 + pxor mm0, mm7 + + pxor mm2, [esi+edx*2] + pavgb mm0, mm2 + pxor mm0, mm7 + + pavgb mm0, [esi+edx] + add esi,8 + + movq [edi+esi-8],mm0 + dec ebp + jne xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} +#else +static void asm_blend_row_clipped(void *dst0, const void *src0, uint32 w, ptrdiff_t srcpitch) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + const uint32 *src2 = (const uint32 *)((const char *)src + srcpitch); + + do { + const uint32 x = *src++; + const uint32 y = *src2++; + + *dst++ = (x|y) - (((x^y)&0xfefefefe)>>1); + } while(--w); +} + +static void asm_blend_row(void *dst0, const void *src0, uint32 w, ptrdiff_t srcpitch) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + const uint32 *src2 = (const uint32 *)((const char *)src + srcpitch); + const uint32 *src3 = (const uint32 *)((const char *)src2 + srcpitch); + + do { + const uint32 a = *src++; + const uint32 b = *src2++; + const uint32 c = *src3++; + const uint32 hi = (a & 0xfcfcfc) + 2*(b & 0xfcfcfc) + (c & 0xfcfcfc); + const uint32 lo = (a & 0x030303) + 2*(b & 0x030303) + (c & 0x030303) + 0x020202; + + *dst++ = (hi + (lo & 0x0c0c0c))>>2; + } while(--w); +} +#endif + +#if defined(VD_CPU_X86) || defined(VD_CPU_AMD64) + static void asm_blend_row_SSE2(void *dst, const void *src, uint32 w, ptrdiff_t srcpitch) { + __m128i zero = _mm_setzero_si128(); + __m128i inv = _mm_cmpeq_epi8(zero, zero); + + w = (w + 3) >> 2; + + const __m128i *src1 = (const __m128i *)src; + const __m128i *src2 = (const __m128i *)((const char *)src + srcpitch); + const __m128i *src3 = (const __m128i *)((const char *)src + srcpitch*2); + __m128i *dstrow = (__m128i *)dst; + do { + __m128i a = *src1++; + __m128i b = *src2++; + __m128i c = *src3++; + + *dstrow++ = _mm_avg_epu8(_mm_xor_si128(_mm_avg_epu8(_mm_xor_si128(a, inv), _mm_xor_si128(c, inv)), inv), b); + } while(--w); + } + + + void ela_L8_SSE2(__m128i *dst, const __m128i *srcat, const __m128i *srcab, int w16) { + do { + __m128i top0 = srcat[0]; + __m128i top1 = srcat[1]; + __m128i top2 = srcat[2]; + __m128i bot0 = srcab[0]; + __m128i bot1 = srcab[1]; + __m128i bot2 = srcab[2]; + ++srcat; + ++srcab; + + __m128i topl2 = _mm_or_si128(_mm_srli_si128(top0, 16 - 3), _mm_slli_si128(top1, 3)); + __m128i topl1 = _mm_or_si128(_mm_srli_si128(top0, 16 - 2), _mm_slli_si128(top1, 2)); + __m128i topc0 = _mm_or_si128(_mm_srli_si128(top0, 16 - 1), _mm_slli_si128(top1, 1)); + __m128i topr1 = top1; + __m128i topr2 = _mm_or_si128(_mm_srli_si128(top1, 1), _mm_slli_si128(top2, 16 - 1)); + __m128i topr3 = _mm_or_si128(_mm_srli_si128(top1, 2), _mm_slli_si128(top2, 16 - 2)); + + __m128i botl2 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 3), _mm_slli_si128(bot1, 3)); + __m128i botl1 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 2), _mm_slli_si128(bot1, 2)); + __m128i botc0 = _mm_or_si128(_mm_srli_si128(bot0, 16 - 1), _mm_slli_si128(bot1, 1)); + __m128i botr1 = bot1; + __m128i botr2 = _mm_or_si128(_mm_srli_si128(bot1, 1), _mm_slli_si128(bot2, 16 - 1)); + __m128i botr3 = _mm_or_si128(_mm_srli_si128(bot1, 2), _mm_slli_si128(bot2, 16 - 2)); + + __m128i rawscorec0 = _mm_or_si128(_mm_subs_epu8(topc0, botc0), _mm_subs_epu8(botc0, topc0)); + __m128i rawscorel1 = _mm_or_si128(_mm_subs_epu8(topl1, botr1), _mm_subs_epu8(botr1, topl1)); + __m128i rawscorel2 = _mm_or_si128(_mm_subs_epu8(topl2, botr2), _mm_subs_epu8(botr2, topl2)); + __m128i rawscorer1 = _mm_or_si128(_mm_subs_epu8(topr1, botl1), _mm_subs_epu8(botl1, topr1)); + __m128i rawscorer2 = _mm_or_si128(_mm_subs_epu8(topr2, botl2), _mm_subs_epu8(botl2, topr2)); + + dst[0] = rawscorec0; + dst[1] = rawscorel1; + dst[2] = rawscorel2; + dst[3] = rawscorer1; + dst[4] = rawscorer2; + dst[5] = _mm_avg_epu8(topr1, botr1); + dst[6] = _mm_avg_epu8(topc0, botr2); + dst[7] = _mm_avg_epu8(topl1, botr3); + dst[8] = _mm_avg_epu8(topr2, botc0); + dst[9] = _mm_avg_epu8(topr3, botl1); + dst += 10; + } while(--w16); + } + + void nela_L8_SSE2(__m128i *dst, const __m128i *elabuf, int w16) { + __m128i zero = _mm_setzero_si128(); + __m128i x80b = _mm_set1_epi8((unsigned char)0x80); + + do { + __m128i x0, x1, x2, y; + + x0 = elabuf[0]; + y = elabuf[10]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorec0 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + x0 = elabuf[1]; + y = elabuf[11]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorel1 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + x0 = elabuf[2]; + y = elabuf[12]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorel2 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + x0 = elabuf[3]; + y = elabuf[13]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorer1 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + x0 = elabuf[4]; + y = elabuf[14]; + x1 = _mm_or_si128(_mm_srli_si128(x0, 1), _mm_slli_si128(y, 15)); + x2 = _mm_or_si128(_mm_srli_si128(x0, 2), _mm_slli_si128(y, 14)); + __m128i scorer2 = _mm_avg_epu8(_mm_avg_epu8(x0, x2), x1); + + scorec0 = _mm_xor_si128(scorec0, x80b); + scorel1 = _mm_xor_si128(scorel1, x80b); + scorel2 = _mm_xor_si128(scorel2, x80b); + scorer1 = _mm_xor_si128(scorer1, x80b); + scorer2 = _mm_xor_si128(scorer2, x80b); + + // result = (scorel1 < scorec0) ? (scorel2 < scorel1 ? l2 : l1) : (scorer1 < scorec0) ? (scorer2 < scorer1 ? r2 : r1) : c0 + + __m128i cmplt_l1_c0 = _mm_cmplt_epi8(scorel1, scorec0); + __m128i cmplt_r1_c0 = _mm_cmplt_epi8(scorer1, scorec0); + __m128i cmplt_l1_r1 = _mm_cmplt_epi8(scorel1, scorer1); + + __m128i is_l1 = _mm_and_si128(cmplt_l1_r1, cmplt_l1_c0); + __m128i is_r1 = _mm_andnot_si128(cmplt_l1_r1, cmplt_r1_c0); + __m128i is_c0_inv = _mm_or_si128(cmplt_l1_c0, cmplt_r1_c0); + __m128i is_c0 = _mm_andnot_si128(is_c0_inv, _mm_cmpeq_epi8(zero, zero)); + + __m128i is_l2 = _mm_and_si128(is_l1, _mm_cmplt_epi8(scorel2, scorel1)); + __m128i is_r2 = _mm_and_si128(is_r1, _mm_cmplt_epi8(scorer2, scorer1)); + + is_l1 = _mm_andnot_si128(is_l2, is_l1); + is_r1 = _mm_andnot_si128(is_r2, is_r1); + + __m128i mask_c0 = is_c0; + __m128i mask_l1 = is_l1; + __m128i mask_l2 = is_l2; + __m128i mask_r1 = is_r1; + __m128i mask_r2 = is_r2; + + __m128i result_c0 = _mm_and_si128(elabuf[5], mask_c0); + __m128i result_l1 = _mm_and_si128(elabuf[6], mask_l1); + __m128i result_l2 = _mm_and_si128(elabuf[7], mask_l2); + __m128i result_r1 = _mm_and_si128(elabuf[8], mask_r1); + __m128i result_r2 = _mm_and_si128(elabuf[9], mask_r2); + + elabuf += 10; + + __m128i pred = _mm_or_si128(_mm_or_si128(_mm_or_si128(result_l1, result_l2), _mm_or_si128(result_r1, result_r2)), result_c0); + + *dst++ = pred; + } while(--w16); + } +#endif + +#if defined(VD_CPU_X86) + void __declspec(naked) __stdcall ela_L8_MMX(void *dst, const void *srcat, const void *srcab, int w16) { + static const __declspec(align(8)) uint64 xFEb = 0xfefefefefefefefe; + __asm { + push ebx + mov ebx, [esp + 4 + 4] + mov ecx, [esp + 8 + 4] + mov edx, [esp + 12 + 4] + mov eax, [esp + 16 + 4] + movq mm7, xFEb + +xloop: + movq mm0, [ecx + 15] + movq mm1, [edx + 15] + movq mm4, mm0 + movq mm2, [ecx + 15 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 15 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx], mm0 + por mm2, mm3 + movq [ebx + 8], mm2 + + movq mm0, [ecx + 14] + movq mm1, [edx + 16] + movq mm4, mm0 + movq mm2, [ecx + 14 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 16 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 16], mm0 + por mm2, mm3 + movq [ebx + 24], mm2 + + movq mm0, [ecx + 13] + movq mm1, [edx + 17] + movq mm4, mm0 + movq mm2, [ecx + 13 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 17 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 32], mm0 + por mm2, mm3 + movq [ebx + 40], mm2 + + movq mm0, [ecx + 16] + movq mm1, [edx + 14] + movq mm4, mm0 + movq mm2, [ecx + 16 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 14 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 48], mm0 + por mm2, mm3 + movq [ebx + 56], mm2 + + movq mm0, [ecx + 17] + movq mm1, [edx + 13] + movq mm4, mm0 + movq mm2, [ecx + 17 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 13 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 64], mm0 + por mm2, mm3 + movq [ebx + 72], mm2 + + movq mm0, [ecx + 16] + movq mm1, [edx + 16] + movq mm2, [ecx + 16 + 8] + movq mm3, [edx + 16 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 80], mm1 + movq [ebx + 88], mm3 + + movq mm0, [ecx + 15] + movq mm1, [edx + 17] + movq mm2, [ecx + 15 + 8] + movq mm3, [edx + 17 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 96], mm1 + movq [ebx + 104], mm3 + + movq mm0, [ecx + 14] + movq mm1, [edx + 18] + movq mm2, [ecx + 14 + 8] + movq mm3, [edx + 18 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 112], mm1 + movq [ebx + 120], mm3 + + movq mm0, [ecx + 17] + movq mm1, [edx + 15] + movq mm2, [ecx + 17 + 8] + movq mm3, [edx + 15 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 128], mm1 + movq [ebx + 136], mm3 + + movq mm0, [ecx + 18] + movq mm1, [edx + 14] + movq mm2, [ecx + 18 + 8] + movq mm3, [edx + 14 + 8] + movq mm4, mm0 + movq mm5, mm2 + pxor mm0, mm1 + pxor mm2, mm3 + por mm1, mm4 + por mm3, mm5 + pand mm0, mm7 + pand mm2, mm7 + psrlw mm0, 1 + psrlw mm2, 1 + psubb mm1, mm0 + psubb mm3, mm2 + movq [ebx + 144], mm1 + movq [ebx + 152], mm3 + + add ebx, 160 + add ecx, 16 + add edx, 16 + dec eax + jne xloop + + emms + pop ebx + ret 16 + } + } + + void __declspec(naked) __stdcall ela_L8_ISSE(void *dst, const void *srcat, const void *srcab, int w16) { + static const __declspec(align(8)) uint64 xFEb = 0xfefefefefefefefe; + __asm { + push ebx + mov ebx, [esp + 4 + 4] + mov ecx, [esp + 8 + 4] + mov edx, [esp + 12 + 4] + mov eax, [esp + 16 + 4] + movq mm7, xFEb + +xloop: + movq mm0, [ecx + 15] + movq mm1, [edx + 15] + movq mm4, mm0 + movq mm2, [ecx + 15 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 15 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx], mm0 + por mm2, mm3 + movq [ebx + 8], mm2 + + movq mm0, [ecx + 14] + movq mm1, [edx + 16] + movq mm4, mm0 + movq mm2, [ecx + 14 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 16 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 16], mm0 + por mm2, mm3 + movq [ebx + 24], mm2 + + movq mm0, [ecx + 13] + movq mm1, [edx + 17] + movq mm4, mm0 + movq mm2, [ecx + 13 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 17 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 32], mm0 + por mm2, mm3 + movq [ebx + 40], mm2 + + movq mm0, [ecx + 16] + movq mm1, [edx + 14] + movq mm4, mm0 + movq mm2, [ecx + 16 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 14 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 48], mm0 + por mm2, mm3 + movq [ebx + 56], mm2 + + movq mm0, [ecx + 17] + movq mm1, [edx + 13] + movq mm4, mm0 + movq mm2, [ecx + 17 + 8] + psubusb mm0, mm1 + movq mm3, [edx + 13 + 8] + movq mm5, mm2 + psubusb mm2, mm3 + psubusb mm1, mm4 + psubusb mm3, mm5 + por mm0, mm1 + movq [ebx + 64], mm0 + por mm2, mm3 + movq [ebx + 72], mm2 + + movq mm0, [ecx + 16] + movq mm1, [edx + 16] + movq mm2, [ecx + 16 + 8] + movq mm3, [edx + 16 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 80], mm1 + movq [ebx + 88], mm3 + + movq mm0, [ecx + 15] + movq mm1, [edx + 17] + movq mm2, [ecx + 15 + 8] + movq mm3, [edx + 17 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 96], mm1 + movq [ebx + 104], mm3 + + movq mm0, [ecx + 14] + movq mm1, [edx + 18] + movq mm2, [ecx + 14 + 8] + movq mm3, [edx + 18 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 112], mm1 + movq [ebx + 120], mm3 + + movq mm0, [ecx + 17] + movq mm1, [edx + 15] + movq mm2, [ecx + 17 + 8] + movq mm3, [edx + 15 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 128], mm1 + movq [ebx + 136], mm3 + + movq mm0, [ecx + 18] + movq mm1, [edx + 14] + movq mm2, [ecx + 18 + 8] + movq mm3, [edx + 14 + 8] + pavgb mm1, mm0 + pavgb mm3, mm2 + movq [ebx + 144], mm1 + movq [ebx + 152], mm3 + + add ebx, 160 + add ecx, 16 + add edx, 16 + dec eax + jne xloop + + emms + pop ebx + ret 16 + } + } + + void __declspec(naked) __stdcall nela_L8_ISSE(void *dst, const void *elabuf, int w16) { + static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; + __asm { + mov edx, [esp+4] + mov ecx, [esp+8] + mov eax, [esp+12] +xloop: + movq mm0, [ecx+000h] + pavgb mm0, [ecx+002h] + pavgb mm0, [ecx+001h] + + movq mm1, [ecx+010h] + pavgb mm1, [ecx+012h] + pavgb mm1, [ecx+011h] + + movq mm2, [ecx+020h] + pavgb mm2, [ecx+022h] + pavgb mm2, [ecx+021h] + + movq mm3, [ecx+030h] + pavgb mm3, [ecx+032h] + pavgb mm3, [ecx+031h] + + movq mm4, [ecx+040h] + pavgb mm4, [ecx+042h] + pavgb mm4, [ecx+041h] + + movq mm5, x7fb + pxor mm0, mm5 + pxor mm1, mm5 + pxor mm2, mm5 + pxor mm3, mm5 + pxor mm4, mm5 + + ;mm0 = scorec0 + ;mm1 = scorel1 + ;mm2 = scorel2 + ;mm3 = scorer1 + ;mm4 = scorer2 + + movq mm5, mm3 + pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) + + pcmpgtb mm4, mm3 ;scorer2 > scorer1 + pcmpgtb mm2, mm1 ;scorel2 > scorel1 + + pcmpgtb mm1, mm0 ;scorel1 > scorec0 + pcmpgtb mm3, mm0 ;scorer1 > scorec0 + + movq mm6, mm1 + pcmpeqb mm0, mm0 + por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 + pxor mm0, mm6 ;mask_c0 + + pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 + pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 + + pand mm4, mm3 ;mask_r2 + pand mm2, mm5 ;mask_l2 + + pxor mm3, mm4 ;mask_r1 + pxor mm5, mm2 ;mask_l1 + + pand mm0, [ecx+050h] + pand mm5, [ecx+060h] + pand mm2, [ecx+070h] + pand mm3, [ecx+080h] + pand mm4, [ecx+090h] + por mm0, mm5 + por mm2, mm3 + por mm0, mm4 + por mm0, mm2 + movq [edx], mm0 + + movq mm0, [ecx+008h] + movq mm5, [ecx+0a0h] + movq mm6, mm0 + psrlq mm0, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm0, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm0, [ecx+008h] + pavgb mm0, mm6 + + movq mm1, [ecx+018h] + movq mm5, [ecx+0b0h] + movq mm6, mm1 + psrlq mm1, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm1, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm1, [ecx+018h] + pavgb mm1, mm6 + + movq mm2, [ecx+028h] + movq mm5, [ecx+0c0h] + movq mm6, mm2 + psrlq mm2, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm2, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm2, [ecx+028h] + pavgb mm2, mm6 + + movq mm3, [ecx+038h] + movq mm5, [ecx+0d0h] + movq mm6, mm3 + psrlq mm3, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm3, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm3, [ecx+038h] + pavgb mm3, mm6 + + movq mm4, [ecx+048h] + movq mm5, [ecx+0e0h] + movq mm6, mm4 + psrlq mm4, 16 + movq mm7, mm5 + psllq mm5, 48 + por mm4, mm5 + psrlq mm6, 8 + psllq mm7, 56 + por mm6, mm7 + pavgb mm4, [ecx+048h] + pavgb mm4, mm6 + + movq mm5, x7fb + pxor mm0, mm5 + pxor mm1, mm5 + pxor mm2, mm5 + pxor mm3, mm5 + pxor mm4, mm5 + + ;mm0 = scorec0 + ;mm1 = scorel1 + ;mm2 = scorel2 + ;mm3 = scorer1 + ;mm4 = scorer2 + + movq mm5, mm3 + pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) + + pcmpgtb mm4, mm3 ;scorer2 > scorer1 + pcmpgtb mm2, mm1 ;scorel2 > scorel1 + + pcmpgtb mm1, mm0 ;scorel1 > scorec0 + pcmpgtb mm3, mm0 ;scorer1 > scorec0 + + movq mm6, mm1 + pcmpeqb mm0, mm0 + por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 + pxor mm0, mm6 ;mask_c0 + + pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 + pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 + + pand mm4, mm3 ;mask_r2 + pand mm2, mm5 ;mask_l2 + + pxor mm3, mm4 ;mask_r1 + pxor mm5, mm2 ;mask_l1 + + pand mm0, [ecx+058h] + pand mm5, [ecx+068h] + pand mm2, [ecx+078h] + pand mm3, [ecx+088h] + pand mm4, [ecx+098h] + por mm0, mm5 + por mm2, mm3 + por mm0, mm4 + por mm0, mm2 + movq [edx+8], mm0 + + add ecx, 0a0h + add edx, 16 + + dec eax + jnz xloop + + emms + ret 12 + } + } + + void __declspec(naked) __stdcall nela_L8_MMX(void *dst, const void *elabuf, int w16) { + static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; + + __asm { + mov edx, [esp+4] + mov ecx, [esp+8] + mov eax, [esp+12] +xloop: + movq mm0, [ecx+000h] + movq mm5, [ecx+002h] + movq mm6, mm0 + pxor mm0, mm5 + por mm6, mm5 + movq mm7, [ecx+001h] + psrlq mm0, 1 + pand mm0, x7fb + psubb mm6, mm0 + movq mm0, mm6 + pxor mm6, mm7 + por mm0, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm0, mm6 + + movq mm1, [ecx+010h] + movq mm5, [ecx+012h] + movq mm6, mm1 + pxor mm1, mm5 + por mm6, mm5 + movq mm7, [ecx+011h] + psrlq mm1, 1 + pand mm1, x7fb + psubb mm6, mm1 + movq mm1, mm6 + pxor mm6, mm7 + por mm1, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm1, mm6 + + movq mm2, [ecx+020h] + movq mm5, [ecx+022h] + movq mm6, mm2 + pxor mm2, mm5 + por mm6, mm5 + movq mm7, [ecx+021h] + psrlq mm2, 1 + pand mm2, x7fb + psubb mm6, mm2 + movq mm2, mm6 + pxor mm6, mm7 + por mm2, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm2, mm6 + + movq mm3, [ecx+030h] + movq mm5, [ecx+032h] + movq mm6, mm3 + pxor mm3, mm5 + por mm6, mm5 + movq mm7, [ecx+031h] + psrlq mm3, 1 + pand mm3, x7fb + psubb mm6, mm3 + movq mm3, mm6 + pxor mm6, mm7 + por mm3, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm3, mm6 + + movq mm4, [ecx+040h] + movq mm5, [ecx+042h] + movq mm6, mm4 + pxor mm4, mm5 + por mm6, mm5 + movq mm7, [ecx+041h] + psrlq mm4, 1 + pand mm4, x7fb + psubb mm6, mm4 + movq mm4, mm6 + pxor mm6, mm7 + por mm4, mm7 + psrlq mm6, 1 + pand mm6, x7fb + psubb mm4, mm6 + + + movq mm5, x7fb + pxor mm0, mm5 + pxor mm1, mm5 + pxor mm2, mm5 + pxor mm3, mm5 + pxor mm4, mm5 + + ;mm0 = scorec0 + ;mm1 = scorel1 + ;mm2 = scorel2 + ;mm3 = scorer1 + ;mm4 = scorer2 + + movq mm5, mm3 + pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) + + pcmpgtb mm4, mm3 ;scorer2 > scorer1 + pcmpgtb mm2, mm1 ;scorel2 > scorel1 + + pcmpgtb mm1, mm0 ;scorel1 > scorec0 + pcmpgtb mm3, mm0 ;scorer1 > scorec0 + + movq mm6, mm1 + pcmpeqb mm0, mm0 + por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 + pxor mm0, mm6 ;mask_c0 + + pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 + pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 + + pand mm4, mm3 ;mask_r2 + pand mm2, mm5 ;mask_l2 + + pxor mm3, mm4 ;mask_r1 + pxor mm5, mm2 ;mask_l1 + + pand mm0, [ecx+050h] + pand mm5, [ecx+060h] + pand mm2, [ecx+070h] + pand mm3, [ecx+080h] + pand mm4, [ecx+090h] + por mm0, mm5 + por mm2, mm3 + por mm0, mm4 + por mm0, mm2 + + movq [edx], mm0 + + movq mm0, [ecx+008h] ;mm0 = x0 + movq mm5, [ecx+0a0h] ;mm5 = x1 + psrlq mm0, 16 ;mm0 = (x0 >> 16) + movq mm7, [ecx+008h] ;mm7 = y0 = x0 + psllq mm5, 48 ;mm5 = (x1 << 48) + movq mm6, mm7 ;mm6 = y0 = x0 + por mm0, mm5 ;mm0 = y2 = (x0 >> 16) | (x1 << 48) + pxor mm6, mm0 ;mm6 = y0 ^ y2 + por mm7, mm0 ;mm7 = y0 | y2 + movq mm5, [ecx+008h] ;mm5 = x0 + psrlq mm6, 1 ;mm6 = (y0 ^ y2) >> 1 + movq mm0, [ecx+0a0h] ;mm0 = x1 + psrlq mm5, 8 ;mm5 = x0 >> 8 + pand mm6, x7fb ;mm6 = ((y0 ^ y2) >> 1) & 0x7f7f7f7f7f7f7f7f + psllq mm0, 56 ;mm0 = x1 << 56 + psubb mm7, mm6 ;mm7 = t = (y0 | y2) - (((y0 ^ y2) >> 1) & 0x7f7f7f7f7f7f7f7f) = avgb(y0, y2) + por mm0, mm5 ;mm0 = y1 = (x0 >> 8) | (x1 << 56) + movq mm6, mm7 ;mm6 = t + pxor mm7, mm0 ;mm7 = t ^ y1 + por mm0, mm6 ;mm0 = t | y1 + psrlq mm7, 1 ;mm7 = (t ^ y1) >> 1 + pand mm7, x7fb ;mm7 = ((t ^ y1) >> 1) & 0x7f7f7f7f7f7f7f7f + psubb mm0, mm7 ;mm0 = (t | y1) - (((t ^ y1) >> 1) & 0x7f7f7f7f7f7f7f7f) = avgb(y1, avgb(y0, y2)) + + movq mm1, [ecx+018h] + movq mm5, [ecx+0b0h] + psrlq mm1, 16 + movq mm7, [ecx+018h] + psllq mm5, 48 + movq mm6, mm7 + por mm1, mm5 + pxor mm6, mm1 + por mm7, mm1 + movq mm5, [ecx+018h] + psrlq mm6, 1 + movq mm1, [ecx+0b0h] + psrlq mm5, 8 + pand mm6, x7fb + psllq mm1, 56 + psubb mm7, mm6 + por mm1, mm5 + movq mm6, mm7 + pxor mm7, mm1 + por mm1, mm6 + psrlq mm7, 1 + pand mm7, x7fb + psubb mm1, mm7 + + movq mm2, [ecx+028h] + movq mm5, [ecx+0c0h] + psrlq mm2, 16 + movq mm7, [ecx+028h] + psllq mm5, 48 + movq mm6, mm7 + por mm2, mm5 + pxor mm6, mm2 + por mm7, mm2 + movq mm5, [ecx+028h] + psrlq mm6, 1 + movq mm2, [ecx+0c0h] + psrlq mm5, 8 + pand mm6, x7fb + psllq mm2, 56 + psubb mm7, mm6 + por mm2, mm5 + movq mm6, mm7 + pxor mm7, mm2 + por mm2, mm6 + psrlq mm7, 1 + pand mm7, x7fb + psubb mm2, mm7 + + movq mm3, [ecx+038h] + movq mm5, [ecx+0d0h] + psrlq mm3, 16 + movq mm7, [ecx+038h] + psllq mm5, 48 + movq mm6, mm7 + por mm3, mm5 + pxor mm6, mm3 + por mm7, mm3 + movq mm5, [ecx+038h] + psrlq mm6, 1 + movq mm3, [ecx+0d0h] + psrlq mm5, 8 + pand mm6, x7fb + psllq mm3, 56 + psubb mm7, mm6 + por mm3, mm5 + movq mm6, mm7 + pxor mm7, mm3 + por mm3, mm6 + psrlq mm7, 1 + pand mm7, x7fb + psubb mm3, mm7 + + movq mm4, [ecx+048h] + movq mm5, [ecx+0e0h] + psrlq mm4, 16 + movq mm7, [ecx+048h] + psllq mm5, 48 + movq mm6, mm7 + por mm4, mm5 + pxor mm6, mm4 + por mm7, mm4 + movq mm5, [ecx+048h] + psrlq mm6, 1 + movq mm4, [ecx+0e0h] + psrlq mm5, 8 + pand mm6, x7fb + psllq mm4, 56 + psubb mm7, mm6 + por mm4, mm5 + movq mm6, mm7 + pxor mm7, mm4 + por mm4, mm6 + psrlq mm7, 1 + pand mm7, x7fb + psubb mm4, mm7 + + movq mm5, x7fb + pxor mm0, mm5 + pxor mm1, mm5 + pxor mm2, mm5 + pxor mm3, mm5 + pxor mm4, mm5 + + ;mm0 = scorec0 + ;mm1 = scorel1 + ;mm2 = scorel2 + ;mm3 = scorer1 + ;mm4 = scorer2 + + movq mm5, mm3 + pcmpgtb mm5, mm1 ;(scorer1 > scorel1) == (scorel1 < scorer1) + + pcmpgtb mm4, mm3 ;scorer2 > scorer1 + pcmpgtb mm2, mm1 ;scorel2 > scorel1 + + pcmpgtb mm1, mm0 ;scorel1 > scorec0 + pcmpgtb mm3, mm0 ;scorer1 > scorec0 + + movq mm6, mm1 + pcmpeqb mm0, mm0 + por mm6, mm3 ;scorel1 > scorec0 || scorer1 > scorec0 + pxor mm0, mm6 ;mask_c0 + + pand mm3, mm5 ;scorer1 > scorec0 && scorer1 > scorel1 + pandn mm5, mm1 ;scorel1 > scorec0 && scorel1 >= scorer1 + + pand mm4, mm3 ;mask_r2 + pand mm2, mm5 ;mask_l2 + + pxor mm3, mm4 ;mask_r1 + pxor mm5, mm2 ;mask_l1 + + pand mm0, [ecx+058h] + pand mm5, [ecx+068h] + pand mm2, [ecx+078h] + pand mm3, [ecx+088h] + pand mm4, [ecx+098h] + por mm0, mm5 + por mm2, mm3 + por mm0, mm4 + por mm0, mm2 + movq [edx+8], mm0 + + add ecx, 0a0h + add edx, 16 + + dec eax + jnz xloop + + emms + ret 12 + } + } +#endif + +namespace { + void ela_L8_scalar(uint8 *dst, const uint8 *srcat, const uint8 *srcab, int w16) { + int w = w16 << 4; + + srcat += 16; + srcab += 16; + do { + int topl2 = srcat[-3]; + int topl1 = srcat[-2]; + int topc0 = srcat[-1]; + int topr1 = srcat[0]; + int topr2 = srcat[1]; + int topr3 = srcat[2]; + + int botl2 = srcab[-3]; + int botl1 = srcab[-2]; + int botc0 = srcab[-1]; + int botr1 = srcab[0]; + int botr2 = srcab[1]; + int botr3 = srcab[2]; + ++srcat; + ++srcab; + + int rawscorec0 = abs(topc0 - botc0); + int rawscorel1 = abs(topl1 - botr1); + int rawscorel2 = abs(topl2 - botr2); + int rawscorer1 = abs(topr1 - botl1); + int rawscorer2 = abs(topr2 - botl2); + + dst[0] = (uint8)rawscorec0; + dst[1] = (uint8)rawscorel1; + dst[2] = (uint8)rawscorel2; + dst[3] = (uint8)rawscorer1; + dst[4] = (uint8)rawscorer2; + dst[5] = (uint8)((topr1 + botr1 + 1) >> 1); + dst[6] = (uint8)((topc0 + botr2 + 1) >> 1); + dst[7] = (uint8)((topl1 + botr3 + 1) >> 1); + dst[8] = (uint8)((topr2 + botc0 + 1) >> 1); + dst[9] = (uint8)((topr3 + botl1 + 1) >> 1); + dst += 10; + } while(--w); + } + + void nela_L8_scalar(uint8 *dst, const uint8 *elabuf, int w16) { + int w = w16 << 4; + + do { + int scorec0 = elabuf[10]*2 + (elabuf[0] + elabuf[20]); + int result = elabuf[5]; + + int scorel1 = elabuf[11]*2 + (elabuf[1] + elabuf[21]); + if (scorel1 < scorec0) { + result = elabuf[6]; + scorec0 = scorel1; + + int scorel2 = elabuf[12]*2 + (elabuf[2] + elabuf[22]); + if (scorel2 < scorec0) { + result = elabuf[7]; + scorec0 = scorel2; + } + } + + int scorer1 = elabuf[13]*2 + (elabuf[3] + elabuf[23]); + if (scorer1 < scorec0) { + result = elabuf[8]; + scorec0 = scorer1; + + int scorer2 = elabuf[14]*2 + (elabuf[4] + elabuf[24]); + if (scorer2 < scorec0) + result = elabuf[9]; + } + + elabuf += 10; + + *dst++ = (uint8)result; + } while(--w); + } + + void BlendScanLine_NELA_scalar(void *dst, const void *srcT, const void *srcB, uint32 w, uint8 *tempBuf) { + const uint8 *srcat = (const uint8 *)srcT; + const uint8 *srcab = (const uint8 *)srcB; + uint32 w16 = (w + 15) >> 4; + uint32 wr = w16 << 4; + + uint8 *elabuf = tempBuf; + uint8 *topbuf = elabuf + 10*wr; + uint8 *botbuf = topbuf + wr + 32; + + uint32 woffset = w & 15; + topbuf[13] = topbuf[14] = topbuf[15] = srcat[0]; + botbuf[13] = botbuf[14] = botbuf[15] = srcab[0]; + + for(uint32 x=0; x> 1); + srca += 4; + srcb += 4; + } while(--w4); + } + + void BlendScanLine_NELA_X8R8G8B8_scalar(void *dst, const void *srcT, const void *srcB, uint32 w, void *tempBuf) { + const uint32 *srcat = (const uint32 *)srcT; + const uint32 *srcab = (const uint32 *)srcB; + uint32 w4 = (w + 3) >> 2; + uint32 *elabuf = (uint32 *)tempBuf; + uint32 *topbuf = elabuf + 5*w4; + uint32 *botbuf = topbuf + w4 + 8; + + topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = srcat[0]; + botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = srcab[0]; + + for(uint32 x=0; x> 2; + uint32 *elabuf = (uint32 *)tempBuf; + uint32 *topbuf = elabuf + 5*w4; + uint32 *botbuf = topbuf + w4 + 8; + + topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = srcat[0]; + botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = srcab[0]; + + for(uint32 x=0; x> 4; + uint32 w4 = w16 * 4; + uint32 *elabuf = (uint32 *)tempBuf; + uint32 *topbuf = elabuf + 40*w16; + uint32 *botbuf = topbuf + w4 + 8; + + uint32 woffset = w & 15; + topbuf[0] = topbuf[1] = topbuf[2] = topbuf[3] = (srcat[0] & 0xff) * 0x01010101; + botbuf[0] = botbuf[1] = botbuf[2] = botbuf[3] = (srcab[0] & 0xff) * 0x01010101; + + for(uint32 x=0; x> 4; + __m128i *elabuf = tempBuf; + __m128i *topbuf = elabuf + 10*w16; + __m128i *botbuf = topbuf + w16 + 2; + + uint32 woffset = w & 15; + topbuf[0] = srcat[0]; + botbuf[0] = srcab[0]; + + for(uint32 x=0; x> 4; + vdfastvector > tempbuf((12 * w16 + 4) * 16); + void *elabuf = tempbuf.data(); + + if (!interpField2) + memcpy(dst, src, w16 << 4); + + int y0 = interpField2 ? 1 : 2; + for(uint32 y = y0; y < h - 1; y += 2) { + const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); + const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); + +#if defined(VD_CPU_X86) + if (MMX_enabled) + BlendScanLine_NELA_X8R8G8B8_MMX((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); + else +#endif + BlendScanLine_NELA_X8R8G8B8_scalar((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); + } + + if (interpField2) + memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w16 << 4); + } + + void InterpPlane_NELA(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, uint32 w, uint32 h, bool interpField2) { + uint32 w16 = (w + 15) >> 4; + vdfastvector > tempbuf((12 * w16 + 4) * 16); + void *elabuf = tempbuf.data(); + + if (!interpField2) + memcpy(dst, src, w16 << 4); + + int y0 = interpField2 ? 1 : 2; + if (SSE2_enabled) { + for(uint32 y = y0; y < h - 1; y += 2) { + const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); + const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); + + BlendScanLine_NELA_SSE2((char *)dst + dstpitch*y, srcat, srcab, w, (__m128i *)elabuf); + } + } +#if defined(VD_CPU_X86) + else if (MMX_enabled || ISSE_enabled) { + for(uint32 y = y0; y < h - 1; y += 2) { + const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); + const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); + + BlendScanLine_NELA_MMX_ISSE((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); + } + } +#endif + else { + for(uint32 y = y0; y < h - 1; y += 2) { + const __m128i *srcat = (const __m128i *)((const char *)src + srcpitch * (y-1)); + const __m128i *srcab = (const __m128i *)((const char *)src + srcpitch * (y+1)); + + BlendScanLine_NELA_scalar((char *)dst + dstpitch*y, srcat, srcab, w, (uint8 *)elabuf); + } + } + + if (interpField2) + memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w16 << 4); + } + + void Average_scalar(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { + uint32 w4 = w16 << 2; + do { + uint32 *dstv = (uint32 *)dst; + uint32 *src1v = (uint32 *)src1; + uint32 *src2v = (uint32 *)src2; + + for(uint32 i=0; i> 1); + } + + dst = (char *)dst + dstPitch; + src1 = (char *)src1 + srcPitch; + src2 = (char *)src2 + srcPitch; + } while(--h); + } + +#if defined(VD_CPU_X86) + void __declspec(naked) __cdecl Average_MMX(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { + static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; + static const __declspec(align(8)) uint64 xfeb = 0xfefefefefefefefe; + + __asm { + push ebp + push edi + push esi + push ebx + + mov esi, [esp+24+16] + mov eax, [esp+4+16] + shl esi, 4 + mov ecx, [esp+12+16] + mov edx, [esp+16+16] + mov ebp, [esp+20+16] + mov edi, [esp+8+16] + sub edi, esi + sub ebp, esi + + movq mm6, x7fb + movq mm7, xfeb + + mov esi, [esp+28+16] +yloop: + mov ebx, [esp+24+16] +mainRowLoop: + movq mm0, [ecx] + movq mm3, [ecx + 8] + movq mm1, mm0 + movq mm2, [edx] + movq mm4, mm3 + movq mm5, [edx + 8] + por mm1, mm2 + pxor mm0, mm2 + por mm4, mm5 + pxor mm3, mm5 + psrlq mm0, 1 + pand mm3, mm7 + pand mm0, mm6 + psrlq mm3, 1 + psubb mm1, mm0 + psubb mm4, mm3 + add ecx, 16 + movq [eax], mm1 + movq [eax+8], mm4 + add edx, 16 + add eax, 16 + dec ebx + jne mainRowLoop + + add eax, edi + add ecx, ebp + add edx, ebp + dec esi + jne yloop + + emms + pop ebx + pop esi + pop edi + pop ebp + ret + } + } + + void __declspec(naked) __cdecl Average_ISSE(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { + static const __declspec(align(8)) uint64 x7fb = 0x7f7f7f7f7f7f7f7f; + static const __declspec(align(8)) uint64 xfeb = 0xfefefefefefefefe; + + __asm { + push ebp + push edi + push esi + push ebx + + mov esi, [esp+24+16] + mov eax, [esp+4+16] + shl esi, 4 + mov ecx, [esp+12+16] + mov edx, [esp+16+16] + mov ebp, [esp+20+16] + mov edi, [esp+8+16] + sub edi, esi + sub ebp, esi + + movq mm6, x7fb + movq mm7, xfeb + + mov esi, [esp+28+16] +yloop: + mov ebx, [esp+24+16] +mainRowLoop: + movq mm0, [ecx] + movq mm1, [ecx + 8] + movq mm2, [edx] + movq mm3, [edx + 8] + pavgb mm0, mm2 + pavgb mm1, mm3 + movq [eax], mm0 + add ecx, 16 + add edx, 16 + movq [eax+8], mm1 + add eax, 16 + dec ebx + jne mainRowLoop + + add eax, edi + add ecx, ebp + add edx, ebp + dec esi + jne yloop + + emms + pop ebx + pop esi + pop edi + pop ebp + ret + } + } +#endif + +#if defined(VD_CPU_X86) || defined(VD_CPU_AMD64) + void Average_SSE2(void *dst, ptrdiff_t dstPitch, const void *src1, const void *src2, ptrdiff_t srcPitch, uint32 w16, uint32 h) { + do { + __m128i *dstv = (__m128i *)dst; + __m128i *src1v = (__m128i *)src1; + __m128i *src2v = (__m128i *)src2; + + for(uint32 i=0; i> 2; + + uint32 y0 = interpField2 ? 1 : 2; + + if (!interpField2) + memcpy(dst, src, w * 4); + + if (h > y0) { + ASSERT(((UINT_PTR)dst & 0xF) == 0); + ASSERT((dstpitch & 0xF) == 0); + ASSERT(((UINT_PTR)src & 0xF) == 0); + ASSERT((srcpitch*(y0 - 1) & 0xF) == 0); + blend_func((char *)dst + dstpitch*y0, + dstpitch*2, + (const char *)src + srcpitch*(y0 - 1), + (const char *)src + srcpitch*(y0 + 1), + srcpitch*2, + (w + 3) >> 2, + (h - y0) >> 1); + } + + if (interpField2) + memcpy((char *)dst + dstpitch*(h - 1), (const char *)src + srcpitch*(h - 1), w*4); + +#ifdef _M_IX86 + if (MMX_enabled) + __asm emms +#endif + } + + void BlendPlane(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, uint32 w, uint32 h) { + void (*blend_func)(void *, const void *, uint32, ptrdiff_t); +#if defined(VD_CPU_X86) + if (SSE2_enabled && !(srcpitch % 16)) + blend_func = asm_blend_row_SSE2; + else + blend_func = ISSE_enabled ? asm_blend_row_ISSE : MMX_enabled ? asm_blend_row_MMX : asm_blend_row; +#else + blend_func = asm_blend_row_SSE2; +#endif + + w = (w + 3) >> 2; + + asm_blend_row_clipped(dst, src, w, srcpitch); + if (h-=2) + do { + dst = ((char *)dst + dstpitch); + + blend_func(dst, src, w, srcpitch); + + src = ((char *)src + srcpitch); + } while(--h); + + asm_blend_row_clipped((char *)dst + dstpitch, src, w, srcpitch); + +#ifdef _M_IX86 + if (MMX_enabled) + __asm emms +#endif + } +} + +void DeinterlaceELA_X8R8G8B8(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) +{ + topfield = !topfield; + + InterpPlane_NELA_X8R8G8B8(dst, dstpitch, src, srcpitch, w, h, topfield); +} + +void DeinterlaceELA(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) +{ + topfield = !topfield; + + InterpPlane_NELA(dst, dstpitch, src, srcpitch, w, h, topfield); +} + +void DeinterlaceBob(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield) +{ + topfield = !topfield; + + InterpPlane_Bob(dst, dstpitch, src, srcpitch, w, h, topfield); +} + +void DeinterlaceBlend(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch) +{ + BlendPlane(dst, dstpitch, src, srcpitch, w, h); +} diff --git a/src/DSUtil/stdafx.cpp b/src/DSUtil/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/DSUtil/stdafx.cpp +++ b/src/DSUtil/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/DSUtil/stdafx.h b/src/DSUtil/stdafx.h index b099e5c0006..e7f7ebdba9e 100644 --- a/src/DSUtil/stdafx.h +++ b/src/DSUtil/stdafx.h @@ -1,43 +1,43 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "SharedInclude.h" -#include - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include - -#include -#include - -#include "BaseClasses/streams.h" -#include - -#include -#include +/* + * (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 . + * + */ + +#pragma once + +#include "SharedInclude.h" +#include + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include + +#include +#include + +#include "BaseClasses/streams.h" +#include + +#include +#include diff --git a/src/DSUtil/text.cpp b/src/DSUtil/text.cpp index 704a934d891..22384bd9b18 100644 --- a/src/DSUtil/text.cpp +++ b/src/DSUtil/text.cpp @@ -1,419 +1,419 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "text.h" -#include - -DWORD CharSetToCodePage(DWORD dwCharSet) -{ - if (dwCharSet == CP_UTF8) { - return CP_UTF8; - } - if (dwCharSet == CP_UTF7) { - return CP_UTF7; - } - CHARSETINFO cs; - ZeroMemory(&cs, sizeof(CHARSETINFO)); - ::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwCharSet, &cs, TCI_SRCCHARSET); - return cs.ciACP; -} - -CStringA ConvertMBCS(CStringA str, DWORD SrcCharSet, DWORD DstCharSet) -{ - WCHAR* utf16 = DEBUG_NEW WCHAR[str.GetLength() + 1]; - ZeroMemory(utf16, (str.GetLength() + 1)*sizeof(WCHAR)); - - CHAR* mbcs = DEBUG_NEW CHAR[str.GetLength() * 6 + 1]; - ZeroMemory(mbcs, str.GetLength() * 6 + 1); - - int len = MultiByteToWideChar( - CharSetToCodePage(SrcCharSet), - 0, - str, - -1, // null terminated string - utf16, - str.GetLength() + 1); - - len = WideCharToMultiByte( - CharSetToCodePage(DstCharSet), - 0, - utf16, - len, - mbcs, - str.GetLength() * 6, - nullptr, - nullptr); - - str = mbcs; - - delete [] utf16; - delete [] mbcs; - - return str; -} - -CStringA UrlEncode(const CStringA& strIn) -{ - CStringA strOut; - DWORD dwStrLen = 0, dwMaxLength = 0; - // Request the buffer size needed to encode the URL - AtlEscapeUrl(strIn, strOut.GetBuffer(), &dwStrLen, dwMaxLength, ATL_URL_ENCODE_PERCENT); - dwMaxLength = dwStrLen; - // Encode the URL - if (dwMaxLength > 0) { - if (AtlEscapeUrl(strIn, strOut.GetBuffer(int(dwMaxLength)), &dwStrLen, dwMaxLength, ATL_URL_ENCODE_PERCENT)) { - dwStrLen--; - } else { - dwStrLen = 0; - } - strOut.ReleaseBuffer(dwStrLen); - } - - return strOut; -} - -CStringA EscapeJSONString(const CStringA& str) -{ - CStringA escapedString = str; - // replace all of JSON's reserved characters with their escaped - // equivalents. - escapedString.Replace("\"", "\\\""); - escapedString.Replace("\\", "\\\\"); - escapedString.Replace("/", "\\/"); - escapedString.Replace("\b", "\\b"); - escapedString.Replace("\f", "\\f"); - escapedString.Replace("\n", "\\n"); - escapedString.Replace("\r", "\\r"); - escapedString.Replace("\t", "\\t"); - return escapedString; -} - -CStringA UrlDecode(const CStringA& strIn) -{ - CStringA strOut; - DWORD dwStrLen = 0, dwMaxLength = strIn.GetLength() + 1; - - if (AtlUnescapeUrl(strIn, strOut.GetBuffer(int(dwMaxLength)), &dwStrLen, dwMaxLength)) { - dwStrLen--; - } else { - dwStrLen = 0; - } - strOut.ReleaseBuffer(dwStrLen); - - return strOut; -} - -CStringW UrlDecodeWithUTF8(CStringW in, bool keepEncodedSpecialChar) { - TCHAR t[100]; - DWORD bufSize = _countof(t); - CString tem(in); - tem.Replace(_T("+"), _T(" ")); //UrlUnescape does not deal with '+' properly - if (keepEncodedSpecialChar) { - tem.Replace(_T("%25"), _T("%2525")); // % - tem.Replace(_T("%3A"), _T("%253A")); - tem.Replace(_T("%3a"), _T("%253A")); - tem.Replace(_T("%2F"), _T("%252F")); - tem.Replace(_T("%2f"), _T("%252F")); - tem.Replace(_T("%3F"), _T("%253F")); - tem.Replace(_T("%3f"), _T("%253F")); - tem.Replace(_T("%23"), _T("%2523")); - tem.Replace(_T("%5B"), _T("%255B")); - tem.Replace(_T("%5b"), _T("%255B")); - tem.Replace(_T("%5D"), _T("%255D")); - tem.Replace(_T("%5d"), _T("%255D")); - tem.Replace(_T("%40"), _T("%2540")); - tem.Replace(_T("%21"), _T("%2521")); - tem.Replace(_T("%24"), _T("%2524")); - tem.Replace(_T("%26"), _T("%2526")); - tem.Replace(_T("%27"), _T("%2527")); - tem.Replace(_T("%28"), _T("%2528")); - tem.Replace(_T("%29"), _T("%2529")); - tem.Replace(_T("%2A"), _T("%252A")); - tem.Replace(_T("%2a"), _T("%252A")); - tem.Replace(_T("%2B"), _T("%252B")); - tem.Replace(_T("%2b"), _T("%252B")); - tem.Replace(_T("%2C"), _T("%252C")); - tem.Replace(_T("%2c"), _T("%252C")); - tem.Replace(_T("%3B"), _T("%253B")); - tem.Replace(_T("%3b"), _T("%253B")); - tem.Replace(_T("%3D"), _T("%253D")); - tem.Replace(_T("%3d"), _T("%253D")); - tem.Replace(_T("%20"), _T("%2520")); - } - HRESULT result = UrlUnescape(tem.GetBuffer(), t, &bufSize, URL_ESCAPE_AS_UTF8); //URL_ESCAPE_AS_UTF8 will work as URL_UNESCAPE_AS_UTF8 on windows 8+, otherwise it will just ignore utf-8 - - if (result == E_POINTER) { - std::shared_ptr buffer(new TCHAR[bufSize]); - if (S_OK == UrlUnescape(tem.GetBuffer(), buffer.get(), &bufSize, URL_ESCAPE_AS_UTF8)) { - CString urlDecoded(buffer.get()); - return urlDecoded; - } - } - else { - CString urlDecoded(t); - return urlDecoded; - } - return in; -} - -CStringW URLGetHostName(const CStringW in) { - CStringW t(in); - if (t.Find(_T("://")) > 1) { - t = t.Mid(t.Find(_T("://")) + 3); - } - if (t.Left(4) == _T("www.")) { - t = t.Mid(4); - } - if (t.Find(_T("/")) > 0) { - t = t.Left(t.Find(_T("/"))); - } - return UrlDecodeWithUTF8(t); -} - -CStringW ShortenURL(const CStringW url, int targetLength, bool returnHostnameIfTooLong) { - CStringW t(url); - if (t.Find(_T("://")) > 1) { - t = t.Mid(t.Find(_T("://")) + 3); - } - if (t.Left(4) == _T("www.")) { - t = t.Mid(4); - } - while (t.GetLength() > targetLength) { - int position = t.ReverseFind('#'); - if (position > 0) { - t = t.Left(position); - continue; - } - position = t.ReverseFind('&'); - if (position > 0) { - t = t.Left(position); - continue; - } - position = t.ReverseFind('?'); - if (position > 0) { - t = t.Left(position); - break; - } - break; - } - t = UrlDecodeWithUTF8(t); - if (t.GetLength() > targetLength && returnHostnameIfTooLong) return URLGetHostName(url); - return t; -} - -CString ExtractTag(CString tag, CMapStringToString& attribs, bool& fClosing) -{ - tag.Trim(); - attribs.RemoveAll(); - - fClosing = !tag.IsEmpty() ? tag[0] == '/' : false; - tag.TrimLeft('/'); - - int i = tag.Find(' '); - if (i < 0) { - i = tag.GetLength(); - } - CString type = tag.Left(i).MakeLower(); - tag = tag.Mid(i).Trim(); - - while ((i = tag.Find('=')) > 0) { - CString attrib = tag.Left(i).Trim().MakeLower(); - tag = tag.Mid(i + 1); - for (i = 0; i < tag.GetLength() && _istspace(tag[i]); i++) { - ; - } - if (i < tag.GetLength()) { - tag = tag.Mid(i); - } else { - tag.Empty(); - } - if (!tag.IsEmpty() && tag[0] == '\"') { - tag = tag.Mid(1); - i = tag.Find('\"'); - } else { - i = tag.Find(' '); - } - if (i < 0) { - i = tag.GetLength(); - } - CString param = tag.Left(i).Trim(); - if (!param.IsEmpty()) { - attribs[attrib] = param; - } - if (i + 1 < tag.GetLength()) { - tag = tag.Mid(i + 1); - } else { - tag.Empty(); - } - } - - return type; -} - -CStringA HtmlSpecialChars(CStringA str, bool bQuotes /*= false*/) -{ - str.Replace("&", "&"); - str.Replace("\"", """); - if (bQuotes) { - str.Replace("\'", "'"); - } - str.Replace("<", "<"); - str.Replace(">", ">"); - - return str; -} - -CStringA HtmlSpecialCharsDecode(CStringA str) -{ - str.Replace("&", "&"); - str.Replace(""", "\""); - str.Replace("'", "\'"); - str.Replace("<", "<"); - str.Replace(">", ">"); - str.Replace("’", "'"); - - return str; -} - -CAtlList& MakeLower(CAtlList& sl) -{ - POSITION pos = sl.GetHeadPosition(); - while (pos) { - sl.GetNext(pos).MakeLower(); - } - return sl; -} - -CAtlList& MakeUpper(CAtlList& sl) -{ - POSITION pos = sl.GetHeadPosition(); - while (pos) { - sl.GetNext(pos).MakeUpper(); - } - return sl; -} - -CString FormatNumber(CString szNumber, bool bNoFractionalDigits /*= true*/) -{ - CString ret; - - int nChars = GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNumber, nullptr, nullptr, 0); - GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNumber, nullptr, ret.GetBuffer(nChars), nChars); - ret.ReleaseBuffer(); - - if (bNoFractionalDigits) { - TCHAR szNumberFractionalDigits[2] = {0}; - GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, szNumberFractionalDigits, _countof(szNumberFractionalDigits)); - int nNumberFractionalDigits = _tcstol(szNumberFractionalDigits, nullptr, 10); - if (nNumberFractionalDigits) { - ret.Truncate(ret.GetLength() - nNumberFractionalDigits - 1); - } - } - - return ret; -} - -void GetLocaleString(LCID lcid, LCTYPE type, CString& output) { - int len = GetLocaleInfo(lcid, type, output.GetBuffer(256), 256); - output.ReleaseBufferSetLength(std::max(len - 1, 0)); -} - -int LastIndexOfCString(const CString& text, const CString& pattern) { - int found = -1; - int next_pos = 0; - while (true) { - next_pos = text.Find(pattern, next_pos); - if (next_pos > found) { - found = next_pos; - next_pos = next_pos + pattern.GetLength(); - } else { - return found; - } - } -} - -bool IsNameSimilar(const CString& title, const CString& fileName) { - if (fileName.Find(title.Left(25)) > -1) return true; - return false; -} - -CStringW ToUnicode(CStringW str, DWORD CharSet) { - CStringW ret; - DWORD cp = CharSetToCodePage(CharSet); - - for (int i = 0, j = str.GetLength(); i < j; i++) { - WCHAR wc = str.GetAt(i); - char c = wc & 0xff; - - if (IsDBCSLeadByteEx(cp, (BYTE)wc)) { - i++; - - if (i < j) { - char cc[2]; - cc[0] = c; - cc[1] = (char)str.GetAt(i); - - MultiByteToWideChar(cp, 0, cc, 2, &wc, 1); - } - } else { - MultiByteToWideChar(cp, 0, &c, 1, &wc, 1); - } - - ret += wc; - } - - return ret; -} - -void AppendWithDelimiter(CStringW &output, CStringW append, wchar_t delim) { - if (!append.IsEmpty()) { - if (!output.IsEmpty()) { - output.AppendChar(delim); - } - output.Append(append); - } -} - -bool EndsWith(CStringW str, CStringW suffix) { - const int str_len = str.GetLength(); - const int suffix_len = suffix.GetLength(); - return str_len >= suffix_len && 0 == str.Right(suffix_len).Compare(suffix); -} - -bool StartsWith(CStringW str, CStringW prefix) { - const int str_len = str.GetLength(); - const int prefix_len = prefix.GetLength(); - return str_len >= prefix_len && 0 == str.Left(prefix_len).Compare(prefix); -} - -bool EndsWithNoCase(CStringW str, CStringW suffix) { - const int str_len = str.GetLength(); - const int suffix_len = suffix.GetLength(); - return str_len >= suffix_len && 0 == str.Right(suffix_len).CompareNoCase(suffix); -} - -bool StartsWithNoCase(CStringW str, CStringW prefix) { - const int str_len = str.GetLength(); - const int prefix_len = prefix.GetLength(); - return str_len >= prefix_len && 0 == str.Left(prefix_len).CompareNoCase(prefix); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "text.h" +#include + +DWORD CharSetToCodePage(DWORD dwCharSet) +{ + if (dwCharSet == CP_UTF8) { + return CP_UTF8; + } + if (dwCharSet == CP_UTF7) { + return CP_UTF7; + } + CHARSETINFO cs; + ZeroMemory(&cs, sizeof(CHARSETINFO)); + ::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwCharSet, &cs, TCI_SRCCHARSET); + return cs.ciACP; +} + +CStringA ConvertMBCS(CStringA str, DWORD SrcCharSet, DWORD DstCharSet) +{ + WCHAR* utf16 = DEBUG_NEW WCHAR[str.GetLength() + 1]; + ZeroMemory(utf16, (str.GetLength() + 1)*sizeof(WCHAR)); + + CHAR* mbcs = DEBUG_NEW CHAR[str.GetLength() * 6 + 1]; + ZeroMemory(mbcs, str.GetLength() * 6 + 1); + + int len = MultiByteToWideChar( + CharSetToCodePage(SrcCharSet), + 0, + str, + -1, // null terminated string + utf16, + str.GetLength() + 1); + + len = WideCharToMultiByte( + CharSetToCodePage(DstCharSet), + 0, + utf16, + len, + mbcs, + str.GetLength() * 6, + nullptr, + nullptr); + + str = mbcs; + + delete [] utf16; + delete [] mbcs; + + return str; +} + +CStringA UrlEncode(const CStringA& strIn) +{ + CStringA strOut; + DWORD dwStrLen = 0, dwMaxLength = 0; + // Request the buffer size needed to encode the URL + AtlEscapeUrl(strIn, strOut.GetBuffer(), &dwStrLen, dwMaxLength, ATL_URL_ENCODE_PERCENT); + dwMaxLength = dwStrLen; + // Encode the URL + if (dwMaxLength > 0) { + if (AtlEscapeUrl(strIn, strOut.GetBuffer(int(dwMaxLength)), &dwStrLen, dwMaxLength, ATL_URL_ENCODE_PERCENT)) { + dwStrLen--; + } else { + dwStrLen = 0; + } + strOut.ReleaseBuffer(dwStrLen); + } + + return strOut; +} + +CStringA EscapeJSONString(const CStringA& str) +{ + CStringA escapedString = str; + // replace all of JSON's reserved characters with their escaped + // equivalents. + escapedString.Replace("\"", "\\\""); + escapedString.Replace("\\", "\\\\"); + escapedString.Replace("/", "\\/"); + escapedString.Replace("\b", "\\b"); + escapedString.Replace("\f", "\\f"); + escapedString.Replace("\n", "\\n"); + escapedString.Replace("\r", "\\r"); + escapedString.Replace("\t", "\\t"); + return escapedString; +} + +CStringA UrlDecode(const CStringA& strIn) +{ + CStringA strOut; + DWORD dwStrLen = 0, dwMaxLength = strIn.GetLength() + 1; + + if (AtlUnescapeUrl(strIn, strOut.GetBuffer(int(dwMaxLength)), &dwStrLen, dwMaxLength)) { + dwStrLen--; + } else { + dwStrLen = 0; + } + strOut.ReleaseBuffer(dwStrLen); + + return strOut; +} + +CStringW UrlDecodeWithUTF8(CStringW in, bool keepEncodedSpecialChar) { + TCHAR t[100]; + DWORD bufSize = _countof(t); + CString tem(in); + tem.Replace(_T("+"), _T(" ")); //UrlUnescape does not deal with '+' properly + if (keepEncodedSpecialChar) { + tem.Replace(_T("%25"), _T("%2525")); // % + tem.Replace(_T("%3A"), _T("%253A")); + tem.Replace(_T("%3a"), _T("%253A")); + tem.Replace(_T("%2F"), _T("%252F")); + tem.Replace(_T("%2f"), _T("%252F")); + tem.Replace(_T("%3F"), _T("%253F")); + tem.Replace(_T("%3f"), _T("%253F")); + tem.Replace(_T("%23"), _T("%2523")); + tem.Replace(_T("%5B"), _T("%255B")); + tem.Replace(_T("%5b"), _T("%255B")); + tem.Replace(_T("%5D"), _T("%255D")); + tem.Replace(_T("%5d"), _T("%255D")); + tem.Replace(_T("%40"), _T("%2540")); + tem.Replace(_T("%21"), _T("%2521")); + tem.Replace(_T("%24"), _T("%2524")); + tem.Replace(_T("%26"), _T("%2526")); + tem.Replace(_T("%27"), _T("%2527")); + tem.Replace(_T("%28"), _T("%2528")); + tem.Replace(_T("%29"), _T("%2529")); + tem.Replace(_T("%2A"), _T("%252A")); + tem.Replace(_T("%2a"), _T("%252A")); + tem.Replace(_T("%2B"), _T("%252B")); + tem.Replace(_T("%2b"), _T("%252B")); + tem.Replace(_T("%2C"), _T("%252C")); + tem.Replace(_T("%2c"), _T("%252C")); + tem.Replace(_T("%3B"), _T("%253B")); + tem.Replace(_T("%3b"), _T("%253B")); + tem.Replace(_T("%3D"), _T("%253D")); + tem.Replace(_T("%3d"), _T("%253D")); + tem.Replace(_T("%20"), _T("%2520")); + } + HRESULT result = UrlUnescape(tem.GetBuffer(), t, &bufSize, URL_ESCAPE_AS_UTF8); //URL_ESCAPE_AS_UTF8 will work as URL_UNESCAPE_AS_UTF8 on windows 8+, otherwise it will just ignore utf-8 + + if (result == E_POINTER) { + std::shared_ptr buffer(new TCHAR[bufSize]); + if (S_OK == UrlUnescape(tem.GetBuffer(), buffer.get(), &bufSize, URL_ESCAPE_AS_UTF8)) { + CString urlDecoded(buffer.get()); + return urlDecoded; + } + } + else { + CString urlDecoded(t); + return urlDecoded; + } + return in; +} + +CStringW URLGetHostName(const CStringW in) { + CStringW t(in); + if (t.Find(_T("://")) > 1) { + t = t.Mid(t.Find(_T("://")) + 3); + } + if (t.Left(4) == _T("www.")) { + t = t.Mid(4); + } + if (t.Find(_T("/")) > 0) { + t = t.Left(t.Find(_T("/"))); + } + return UrlDecodeWithUTF8(t); +} + +CStringW ShortenURL(const CStringW url, int targetLength, bool returnHostnameIfTooLong) { + CStringW t(url); + if (t.Find(_T("://")) > 1) { + t = t.Mid(t.Find(_T("://")) + 3); + } + if (t.Left(4) == _T("www.")) { + t = t.Mid(4); + } + while (t.GetLength() > targetLength) { + int position = t.ReverseFind('#'); + if (position > 0) { + t = t.Left(position); + continue; + } + position = t.ReverseFind('&'); + if (position > 0) { + t = t.Left(position); + continue; + } + position = t.ReverseFind('?'); + if (position > 0) { + t = t.Left(position); + break; + } + break; + } + t = UrlDecodeWithUTF8(t); + if (t.GetLength() > targetLength && returnHostnameIfTooLong) return URLGetHostName(url); + return t; +} + +CString ExtractTag(CString tag, CMapStringToString& attribs, bool& fClosing) +{ + tag.Trim(); + attribs.RemoveAll(); + + fClosing = !tag.IsEmpty() ? tag[0] == '/' : false; + tag.TrimLeft('/'); + + int i = tag.Find(' '); + if (i < 0) { + i = tag.GetLength(); + } + CString type = tag.Left(i).MakeLower(); + tag = tag.Mid(i).Trim(); + + while ((i = tag.Find('=')) > 0) { + CString attrib = tag.Left(i).Trim().MakeLower(); + tag = tag.Mid(i + 1); + for (i = 0; i < tag.GetLength() && _istspace(tag[i]); i++) { + ; + } + if (i < tag.GetLength()) { + tag = tag.Mid(i); + } else { + tag.Empty(); + } + if (!tag.IsEmpty() && tag[0] == '\"') { + tag = tag.Mid(1); + i = tag.Find('\"'); + } else { + i = tag.Find(' '); + } + if (i < 0) { + i = tag.GetLength(); + } + CString param = tag.Left(i).Trim(); + if (!param.IsEmpty()) { + attribs[attrib] = param; + } + if (i + 1 < tag.GetLength()) { + tag = tag.Mid(i + 1); + } else { + tag.Empty(); + } + } + + return type; +} + +CStringA HtmlSpecialChars(CStringA str, bool bQuotes /*= false*/) +{ + str.Replace("&", "&"); + str.Replace("\"", """); + if (bQuotes) { + str.Replace("\'", "'"); + } + str.Replace("<", "<"); + str.Replace(">", ">"); + + return str; +} + +CStringA HtmlSpecialCharsDecode(CStringA str) +{ + str.Replace("&", "&"); + str.Replace(""", "\""); + str.Replace("'", "\'"); + str.Replace("<", "<"); + str.Replace(">", ">"); + str.Replace("’", "'"); + + return str; +} + +CAtlList& MakeLower(CAtlList& sl) +{ + POSITION pos = sl.GetHeadPosition(); + while (pos) { + sl.GetNext(pos).MakeLower(); + } + return sl; +} + +CAtlList& MakeUpper(CAtlList& sl) +{ + POSITION pos = sl.GetHeadPosition(); + while (pos) { + sl.GetNext(pos).MakeUpper(); + } + return sl; +} + +CString FormatNumber(CString szNumber, bool bNoFractionalDigits /*= true*/) +{ + CString ret; + + int nChars = GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNumber, nullptr, nullptr, 0); + GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNumber, nullptr, ret.GetBuffer(nChars), nChars); + ret.ReleaseBuffer(); + + if (bNoFractionalDigits) { + TCHAR szNumberFractionalDigits[2] = {0}; + GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, szNumberFractionalDigits, _countof(szNumberFractionalDigits)); + int nNumberFractionalDigits = _tcstol(szNumberFractionalDigits, nullptr, 10); + if (nNumberFractionalDigits) { + ret.Truncate(ret.GetLength() - nNumberFractionalDigits - 1); + } + } + + return ret; +} + +void GetLocaleString(LCID lcid, LCTYPE type, CString& output) { + int len = GetLocaleInfo(lcid, type, output.GetBuffer(256), 256); + output.ReleaseBufferSetLength(std::max(len - 1, 0)); +} + +int LastIndexOfCString(const CString& text, const CString& pattern) { + int found = -1; + int next_pos = 0; + while (true) { + next_pos = text.Find(pattern, next_pos); + if (next_pos > found) { + found = next_pos; + next_pos = next_pos + pattern.GetLength(); + } else { + return found; + } + } +} + +bool IsNameSimilar(const CString& title, const CString& fileName) { + if (fileName.Find(title.Left(25)) > -1) return true; + return false; +} + +CStringW ToUnicode(CStringW str, DWORD CharSet) { + CStringW ret; + DWORD cp = CharSetToCodePage(CharSet); + + for (int i = 0, j = str.GetLength(); i < j; i++) { + WCHAR wc = str.GetAt(i); + char c = wc & 0xff; + + if (IsDBCSLeadByteEx(cp, (BYTE)wc)) { + i++; + + if (i < j) { + char cc[2]; + cc[0] = c; + cc[1] = (char)str.GetAt(i); + + MultiByteToWideChar(cp, 0, cc, 2, &wc, 1); + } + } else { + MultiByteToWideChar(cp, 0, &c, 1, &wc, 1); + } + + ret += wc; + } + + return ret; +} + +void AppendWithDelimiter(CStringW &output, CStringW append, wchar_t delim) { + if (!append.IsEmpty()) { + if (!output.IsEmpty()) { + output.AppendChar(delim); + } + output.Append(append); + } +} + +bool EndsWith(CStringW str, CStringW suffix) { + const int str_len = str.GetLength(); + const int suffix_len = suffix.GetLength(); + return str_len >= suffix_len && 0 == str.Right(suffix_len).Compare(suffix); +} + +bool StartsWith(CStringW str, CStringW prefix) { + const int str_len = str.GetLength(); + const int prefix_len = prefix.GetLength(); + return str_len >= prefix_len && 0 == str.Left(prefix_len).Compare(prefix); +} + +bool EndsWithNoCase(CStringW str, CStringW suffix) { + const int str_len = str.GetLength(); + const int suffix_len = suffix.GetLength(); + return str_len >= suffix_len && 0 == str.Right(suffix_len).CompareNoCase(suffix); +} + +bool StartsWithNoCase(CStringW str, CStringW prefix) { + const int str_len = str.GetLength(); + const int prefix_len = prefix.GetLength(); + return str_len >= prefix_len && 0 == str.Left(prefix_len).CompareNoCase(prefix); +} diff --git a/src/DSUtil/text.h b/src/DSUtil/text.h index 670d02de7a2..f02682486ce 100644 --- a/src/DSUtil/text.h +++ b/src/DSUtil/text.h @@ -1,255 +1,255 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include -#include -#include - -template -T Explode(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) -{ - sl.RemoveAll(); - - for (int i = 0, j = 0; ; i = j + 1) { - j = str.Find(sep, i); - - if (j < 0 || sl.GetCount() == limit - 1) { - sl.AddTail(str.Mid(i).Trim()); - break; - } else { - sl.AddTail(str.Mid(i, j - i).Trim()); - } - } - - return sl.GetHead(); -} - -template -T ExplodeNoTrim(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) -{ - sl.RemoveAll(); - - for (int i = 0, j = 0; ; i = j + 1) { - j = str.Find(sep, i); - - if (j < 0 || sl.GetCount() == limit - 1) { - sl.AddTail(str.Mid(i)); - break; - } else { - sl.AddTail(str.Mid(i, j - i)); - } - } - - return sl.GetHead(); -} - -template -T ExplodeMin(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) -{ - Explode(str, sl, sep, limit); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - POSITION tmp = pos; - if (sl.GetNext(pos).IsEmpty()) { - sl.RemoveAt(tmp); - } - } - if (sl.IsEmpty()) { - sl.AddTail(T()); // eh - } - - return sl.GetHead(); -} - -template -T ExplodeEsc(T str, CAtlList& sl, SEP sep, size_t limit = 0, SEP esc = _T('\\')) -{ - sl.RemoveAll(); - - int split = 0; - for (int i = 0, j = 0; ; i = j + 1) { - j = str.Find(sep, i); - if (j < 0) { - break; - } - - // Skip this separator if it is escaped - if (j > 0 && str.GetAt(j - 1) == esc) { - // Delete the escape character - str.Delete(j - 1); - continue; - } - - if (sl.GetCount() < limit - 1) { - sl.AddTail(str.Mid(split, j - split).Trim()); - - // Save new splitting position - split = j + 1; - } - } - sl.AddTail(str.Mid(split).Trim()); - - return sl.GetHead(); -} - -template -std::enable_if_t<(std::is_same_v || std::is_same_v), T> -ExplodeEsc(T str, std::list& sl, SEP sep, size_t limit = 0, SEP esc = '\\') { - sl.clear(); - if (str.IsEmpty()) { - return T(); - } - - int split = 0; - for (int i = 0, j = 0; ; i = j + 1) { - j = str.Find(sep, i); - if (j < 0) { - break; - } - - // Skip this separator if it is escaped - if (j > 0 && str.GetAt(j - 1) == esc) { - // Delete the escape character - str.Delete(j - 1); - continue; - } - - if (sl.size() < limit - 1) { - sl.push_back(str.Mid(split, j - split).Trim()); - - // Save new splitting position - split = j + 1; - } - } - sl.push_back(str.Mid(split).Trim()); - - return sl.front(); -} - -template -T Implode(const CAtlList& sl, SEP sep) -{ - T ret; - POSITION pos = sl.GetHeadPosition(); - while (pos) { - ret += sl.GetNext(pos); - if (pos) { - ret += sep; - } - } - return ret; -} - -template -T ImplodeEsc(const CAtlList& sl, SEP sep, SEP esc = _T('\\')) -{ - T ret; - T escsep = T(esc) + T(sep); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - T str = sl.GetNext(pos); - str.Replace(T(sep), escsep); - ret += str; - if (pos) { - ret += sep; - } - } - return ret; -} - -extern CString ExtractTag(CString tag, CMapStringToString& attribs, bool& fClosing); -extern CStringA ConvertMBCS(CStringA str, DWORD SrcCharSet, DWORD DstCharSet); -extern CStringA UrlEncode(const CStringA& strIn); -/** - * @brief Escape the characters that JSON reserves as special. - * @param str The string that needs escaping. - * @return The input string with the special characters escaped. - */ -extern CStringA EscapeJSONString(const CStringA& str); -extern CStringA UrlDecode(const CStringA& strIn); -extern CStringW UrlDecodeWithUTF8(const CStringW in, bool keepEncodedSpecialChar = false); -extern CStringW URLGetHostName(const CStringW in); -extern CStringW ShortenURL(const CStringW url, int targetLength = 100, bool returnHostnameIfTooLong = false); -extern CStringA HtmlSpecialChars(CStringA str, bool bQuotes = false); -extern CStringA HtmlSpecialCharsDecode(CStringA str); -extern DWORD CharSetToCodePage(DWORD dwCharSet); -extern CAtlList& MakeLower(CAtlList& sl); -extern CAtlList& MakeUpper(CAtlList& sl); -extern int LastIndexOfCString(const CString& text, const CString& pattern); -extern bool IsNameSimilar(const CString& title, const CString& fileName); -extern CStringW ToUnicode(CStringW str, DWORD CharSet); -extern void AppendWithDelimiter(CStringW& output, CStringW append, wchar_t delim = L' '); -extern bool EndsWith(CStringW str, CStringW suffix); -extern bool StartsWith(CStringW str, CStringW prefix); -extern bool EndsWithNoCase(CStringW str, CStringW suffix); -extern bool StartsWithNoCase(CStringW str, CStringW prefix); -extern CString FormatNumber(CString szNumber, bool bNoFractionalDigits = true); -extern void GetLocaleString(LCID lcid, LCTYPE type, CString& output); - -template -T& FastTrimRight(T& str) -{ - if (!str.IsEmpty()) { - typename T::PCXSTR szStart = str; - typename T::PCXSTR szEnd = szStart + str.GetLength() - 1; - typename T::PCXSTR szCur = szEnd; - for (; szCur >= szStart; szCur--) { - if (!T::StrTraits::IsSpace(*szCur) || *szCur == 133) { // allow ellipsis character - break; - } - } - - if (szCur != szEnd) { - str.Truncate(int(szCur - szStart + 1)); - } - } - - return str; -} - -template -T& FastTrim(T& str) -{ - return FastTrimRight(str).TrimLeft(); -} - -template -int FindOneOf(const T& str, typename T::PCXSTR pszCharSet, int iStart) throw() -{ - ATLASSERT(AtlIsValidString(pszCharSet)); - ATLASSERT(iStart >= 0); - - if (iStart < 0 || iStart >= str.GetLength()) { - return -1; - } - - typename T::PCXSTR psz = T::StrTraits::StringScanSet(str.GetString() + iStart, pszCharSet); - return ((psz == NULL) ? -1 : int(psz - str.GetString())); -} - -template -CString NumToCString(T num) -{ - static_assert(std::numeric_limits::is_specialized, "NumToCString can be used only for numeric types."); - return std::to_string(num).c_str(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include +#include +#include + +template +T Explode(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) +{ + sl.RemoveAll(); + + for (int i = 0, j = 0; ; i = j + 1) { + j = str.Find(sep, i); + + if (j < 0 || sl.GetCount() == limit - 1) { + sl.AddTail(str.Mid(i).Trim()); + break; + } else { + sl.AddTail(str.Mid(i, j - i).Trim()); + } + } + + return sl.GetHead(); +} + +template +T ExplodeNoTrim(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) +{ + sl.RemoveAll(); + + for (int i = 0, j = 0; ; i = j + 1) { + j = str.Find(sep, i); + + if (j < 0 || sl.GetCount() == limit - 1) { + sl.AddTail(str.Mid(i)); + break; + } else { + sl.AddTail(str.Mid(i, j - i)); + } + } + + return sl.GetHead(); +} + +template +T ExplodeMin(const T& str, CAtlList& sl, SEP sep, size_t limit = 0) +{ + Explode(str, sl, sep, limit); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + POSITION tmp = pos; + if (sl.GetNext(pos).IsEmpty()) { + sl.RemoveAt(tmp); + } + } + if (sl.IsEmpty()) { + sl.AddTail(T()); // eh + } + + return sl.GetHead(); +} + +template +T ExplodeEsc(T str, CAtlList& sl, SEP sep, size_t limit = 0, SEP esc = _T('\\')) +{ + sl.RemoveAll(); + + int split = 0; + for (int i = 0, j = 0; ; i = j + 1) { + j = str.Find(sep, i); + if (j < 0) { + break; + } + + // Skip this separator if it is escaped + if (j > 0 && str.GetAt(j - 1) == esc) { + // Delete the escape character + str.Delete(j - 1); + continue; + } + + if (sl.GetCount() < limit - 1) { + sl.AddTail(str.Mid(split, j - split).Trim()); + + // Save new splitting position + split = j + 1; + } + } + sl.AddTail(str.Mid(split).Trim()); + + return sl.GetHead(); +} + +template +std::enable_if_t<(std::is_same_v || std::is_same_v), T> +ExplodeEsc(T str, std::list& sl, SEP sep, size_t limit = 0, SEP esc = '\\') { + sl.clear(); + if (str.IsEmpty()) { + return T(); + } + + int split = 0; + for (int i = 0, j = 0; ; i = j + 1) { + j = str.Find(sep, i); + if (j < 0) { + break; + } + + // Skip this separator if it is escaped + if (j > 0 && str.GetAt(j - 1) == esc) { + // Delete the escape character + str.Delete(j - 1); + continue; + } + + if (sl.size() < limit - 1) { + sl.push_back(str.Mid(split, j - split).Trim()); + + // Save new splitting position + split = j + 1; + } + } + sl.push_back(str.Mid(split).Trim()); + + return sl.front(); +} + +template +T Implode(const CAtlList& sl, SEP sep) +{ + T ret; + POSITION pos = sl.GetHeadPosition(); + while (pos) { + ret += sl.GetNext(pos); + if (pos) { + ret += sep; + } + } + return ret; +} + +template +T ImplodeEsc(const CAtlList& sl, SEP sep, SEP esc = _T('\\')) +{ + T ret; + T escsep = T(esc) + T(sep); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + T str = sl.GetNext(pos); + str.Replace(T(sep), escsep); + ret += str; + if (pos) { + ret += sep; + } + } + return ret; +} + +extern CString ExtractTag(CString tag, CMapStringToString& attribs, bool& fClosing); +extern CStringA ConvertMBCS(CStringA str, DWORD SrcCharSet, DWORD DstCharSet); +extern CStringA UrlEncode(const CStringA& strIn); +/** + * @brief Escape the characters that JSON reserves as special. + * @param str The string that needs escaping. + * @return The input string with the special characters escaped. + */ +extern CStringA EscapeJSONString(const CStringA& str); +extern CStringA UrlDecode(const CStringA& strIn); +extern CStringW UrlDecodeWithUTF8(const CStringW in, bool keepEncodedSpecialChar = false); +extern CStringW URLGetHostName(const CStringW in); +extern CStringW ShortenURL(const CStringW url, int targetLength = 100, bool returnHostnameIfTooLong = false); +extern CStringA HtmlSpecialChars(CStringA str, bool bQuotes = false); +extern CStringA HtmlSpecialCharsDecode(CStringA str); +extern DWORD CharSetToCodePage(DWORD dwCharSet); +extern CAtlList& MakeLower(CAtlList& sl); +extern CAtlList& MakeUpper(CAtlList& sl); +extern int LastIndexOfCString(const CString& text, const CString& pattern); +extern bool IsNameSimilar(const CString& title, const CString& fileName); +extern CStringW ToUnicode(CStringW str, DWORD CharSet); +extern void AppendWithDelimiter(CStringW& output, CStringW append, wchar_t delim = L' '); +extern bool EndsWith(CStringW str, CStringW suffix); +extern bool StartsWith(CStringW str, CStringW prefix); +extern bool EndsWithNoCase(CStringW str, CStringW suffix); +extern bool StartsWithNoCase(CStringW str, CStringW prefix); +extern CString FormatNumber(CString szNumber, bool bNoFractionalDigits = true); +extern void GetLocaleString(LCID lcid, LCTYPE type, CString& output); + +template +T& FastTrimRight(T& str) +{ + if (!str.IsEmpty()) { + typename T::PCXSTR szStart = str; + typename T::PCXSTR szEnd = szStart + str.GetLength() - 1; + typename T::PCXSTR szCur = szEnd; + for (; szCur >= szStart; szCur--) { + if (!T::StrTraits::IsSpace(*szCur) || *szCur == 133) { // allow ellipsis character + break; + } + } + + if (szCur != szEnd) { + str.Truncate(int(szCur - szStart + 1)); + } + } + + return str; +} + +template +T& FastTrim(T& str) +{ + return FastTrimRight(str).TrimLeft(); +} + +template +int FindOneOf(const T& str, typename T::PCXSTR pszCharSet, int iStart) throw() +{ + ATLASSERT(AtlIsValidString(pszCharSet)); + ATLASSERT(iStart >= 0); + + if (iStart < 0 || iStart >= str.GetLength()) { + return -1; + } + + typename T::PCXSTR psz = T::StrTraits::StringScanSet(str.GetString() + iStart, pszCharSet); + return ((psz == NULL) ? -1 : int(psz - str.GetString())); +} + +template +CString NumToCString(T num) +{ + static_assert(std::numeric_limits::is_specialized, "NumToCString can be used only for numeric types."); + return std::to_string(num).c_str(); +} diff --git a/src/DSUtil/vd.cpp b/src/DSUtil/vd.cpp index 388bf3dccdb..6055c609b4d 100644 --- a/src/DSUtil/vd.cpp +++ b/src/DSUtil/vd.cpp @@ -1,392 +1,392 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// Notes: -// - VDPixmapBlt is from VirtualDub -// - sse2 yv12 to yuy2 conversion by Haali -// (- vd.cpp/h should be renamed to something more sensible already :) - - -#include "stdafx.h" -#include "vd.h" -#include "vd_asm.h" -#include - -#include "vd2/system/memory.h" -#include "vd2/system/vdstl.h" - -#include "vd2/Kasumi/pixmap.h" -#include "vd2/Kasumi/pixmaputils.h" -#include "vd2/Kasumi/pixmapops.h" -#include "vd2/Kasumi/resample.h" - -#pragma warning(disable : 4799) // no emms... blahblahblah - -bool BitBltFromI420ToI420(int w, int h, BYTE* dsty, BYTE* dstu, BYTE* dstv, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) -{ - VDPixmap srcbm = {0}; - - srcbm.data = srcy; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; - srcbm.data2 = srcu; - srcbm.pitch2 = srcpitch / 2; - srcbm.data3 = srcv; - srcbm.pitch3 = srcpitch / 2; - - VDPixmap dstpxm = {0}; - - dstpxm.data = dsty; - dstpxm.pitch = dstpitch; - dstpxm.w = w; - dstpxm.h = h; - dstpxm.format = nsVDPixmap::kPixFormat_YUV420_Planar; - dstpxm.data2 = dstu; - dstpxm.pitch2 = dstpitch / 2; - dstpxm.data3 = dstv; - dstpxm.pitch3 = dstpitch / 2; - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromYUY2ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* src, int srcpitch) -{ - VDPixmap srcbm = {0}; - - srcbm.data = src; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; - - VDPixmap dstpxm = { - dst, - NULL, - w, - h, - dstpitch - }; - - dstpxm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromI420ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) -{ - VDPixmap srcbm = {0}; - - srcbm.data = srcy; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; - srcbm.data2 = srcu; - srcbm.pitch2 = srcpitch/2; - srcbm.data3 = srcv; - srcbm.pitch3 = srcpitch/2; - - VDPixmap dstpxm = { - (char *)dst + dstpitch * (h - 1), - NULL, - w, - h, - -dstpitch - }; - - switch(dbpp) { - case 16: - dstpxm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - dstpxm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromI420ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) -{ - if (srcpitch == 0) srcpitch = w; - -#ifndef _WIN64 - if (!((DWORD_PTR)srcy&15) && !((DWORD_PTR)srcu&15) && !((DWORD_PTR)srcv&15) && !(srcpitch&31) && !((DWORD_PTR)dst&15) && !(dstpitch&15)) - { - if (w<=0 || h<=0 || (w&1) || (h&1)) - return false; - - yv12_yuy2_sse2(srcy, srcu, srcv, srcpitch/2, w/2, h, dst, dstpitch); - return true; - } -#endif - - VDPixmap srcbm = {0}; - - srcbm.data = srcy; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; - srcbm.data2 = srcu; - srcbm.pitch2 = srcpitch/2; - srcbm.data3 = srcv; - srcbm.pitch3 = srcpitch/2; - - VDPixmap dstpxm = { - dst, - NULL, - w, - h, - dstpitch - }; - - dstpxm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromRGBToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch, int sbpp) -{ - VDPixmap srcbm = { - (char *)src + srcpitch * (h - 1), - NULL, - w, - h, - -srcpitch - }; - - switch(sbpp) { - case 8: - srcbm.format = nsVDPixmap::kPixFormat_Pal8; - break; - case 16: - srcbm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - srcbm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - srcbm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - VDPixmap dstpxm = { - (char *)dst + dstpitch * (h - 1), - NULL, - w, - h, - -dstpitch - }; - - switch(dbpp) { - case 8: - dstpxm.format = nsVDPixmap::kPixFormat_Pal8; - break; - case 16: - dstpxm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - dstpxm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - return VDPixmapBlt(dstpxm, srcbm); -} - -bool BitBltFromRGBToRGBStretch(int dstw, int dsth, BYTE* dst, int dstpitch, int dbpp, int srcw, int srch, BYTE* src, int srcpitch, int sbpp) -{ - VDPixmap srcbm = { - src + srcpitch * (srch - 1), - nullptr, - srcw, - srch, - -srcpitch - }; - - switch (sbpp) { - case 8: - srcbm.format = nsVDPixmap::kPixFormat_Pal8; - break; - case 16: - srcbm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - srcbm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - srcbm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - VDPixmap dstpxm = { - dst + dstpitch * (dsth - 1), - nullptr, - dstw, - dsth, - -dstpitch - }; - - switch (dbpp) { - case 8: - dstpxm.format = nsVDPixmap::kPixFormat_Pal8; - break; - case 16: - dstpxm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - dstpxm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - return VDPixmapResample(dstpxm, srcbm, IVDPixmapResampler::kFilterCubic); -} - - -bool BitBltFromYUY2ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch) -{ - if (srcpitch == 0) srcpitch = w; - - VDPixmap srcbm = {0}; - - srcbm.data = src; - srcbm.pitch = srcpitch; - srcbm.w = w; - srcbm.h = h; - srcbm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; - - VDPixmap dstpxm = { - (char *)dst + dstpitch * (h - 1), - NULL, - w, - h, - -dstpitch - }; - - switch(dbpp) { - case 16: - dstpxm.format = nsVDPixmap::kPixFormat_RGB565; - break; - case 24: - dstpxm.format = nsVDPixmap::kPixFormat_RGB888; - break; - case 32: - dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; - break; - default: - VDASSERT(false); - } - - return VDPixmapBlt(dstpxm, srcbm); -} - -static void yuvtoyuy2row_c(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) -{ - WORD* dstw = (WORD*)dst; - for (; width > 1; width -= 2) - { - *dstw++ = (*srcu++<<8)|*srcy++; - *dstw++ = (*srcv++<<8)|*srcy++; - } -} - -static void yuvtoyuy2row_avg_c(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) -{ - WORD* dstw = (WORD*)dst; - for (; width > 1; width -= 2, srcu++, srcv++) - { - *dstw++ = (((srcu[0]+srcu[pitchuv])>>1)<<8)|*srcy++; - *dstw++ = (((srcv[0]+srcv[pitchuv])>>1)<<8)|*srcy++; - } -} - -bool BitBltFromI420ToYUY2Interlaced(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) -{ - if (w<=0 || h<=0 || (w&1) || (h&1)) - return false; - - if (srcpitch == 0) srcpitch = w; - - void (*yuvtoyuy2row)(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) = NULL; - void (*yuvtoyuy2row_avg)(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) = NULL; - -#ifndef _WIN64 - if (!((DWORD_PTR)srcy&15) && !((DWORD_PTR)srcu&15) && !((DWORD_PTR)srcv&15) && !(srcpitch&31) && !((DWORD_PTR)dst&15) && !(dstpitch&15)) - { - yv12_yuy2_sse2_interlaced(srcy, srcu, srcv, srcpitch/2, w/2, h, dst, dstpitch); - return true; - } - - if (!(w&7)) - { - yuvtoyuy2row = yuvtoyuy2row_MMX; - yuvtoyuy2row_avg = yuvtoyuy2row_avg_MMX; - } - else -#endif - { - yuvtoyuy2row = yuvtoyuy2row_c; - yuvtoyuy2row_avg = yuvtoyuy2row_avg_c; - } - - if (!yuvtoyuy2row) - return false; - - int halfsrcpitch = srcpitch/2; - do - { - yuvtoyuy2row(dst, srcy, srcu, srcv, w); - yuvtoyuy2row_avg(dst + dstpitch, srcy + srcpitch, srcu, srcv, w, halfsrcpitch); - - dst += 2*dstpitch; - srcy += 2*srcpitch; - srcu += halfsrcpitch; - srcv += halfsrcpitch; - } - while ((h -= 2) > 2); - - yuvtoyuy2row(dst, srcy, srcu, srcv, w); - yuvtoyuy2row(dst + dstpitch, srcy + srcpitch, srcu, srcv, w); - -#ifndef _WIN64 - __asm emms -#endif - - return true; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Notes: +// - VDPixmapBlt is from VirtualDub +// - sse2 yv12 to yuy2 conversion by Haali +// (- vd.cpp/h should be renamed to something more sensible already :) + + +#include "stdafx.h" +#include "vd.h" +#include "vd_asm.h" +#include + +#include "vd2/system/memory.h" +#include "vd2/system/vdstl.h" + +#include "vd2/Kasumi/pixmap.h" +#include "vd2/Kasumi/pixmaputils.h" +#include "vd2/Kasumi/pixmapops.h" +#include "vd2/Kasumi/resample.h" + +#pragma warning(disable : 4799) // no emms... blahblahblah + +bool BitBltFromI420ToI420(int w, int h, BYTE* dsty, BYTE* dstu, BYTE* dstv, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) +{ + VDPixmap srcbm = {0}; + + srcbm.data = srcy; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; + srcbm.data2 = srcu; + srcbm.pitch2 = srcpitch / 2; + srcbm.data3 = srcv; + srcbm.pitch3 = srcpitch / 2; + + VDPixmap dstpxm = {0}; + + dstpxm.data = dsty; + dstpxm.pitch = dstpitch; + dstpxm.w = w; + dstpxm.h = h; + dstpxm.format = nsVDPixmap::kPixFormat_YUV420_Planar; + dstpxm.data2 = dstu; + dstpxm.pitch2 = dstpitch / 2; + dstpxm.data3 = dstv; + dstpxm.pitch3 = dstpitch / 2; + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromYUY2ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* src, int srcpitch) +{ + VDPixmap srcbm = {0}; + + srcbm.data = src; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; + + VDPixmap dstpxm = { + dst, + NULL, + w, + h, + dstpitch + }; + + dstpxm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromI420ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) +{ + VDPixmap srcbm = {0}; + + srcbm.data = srcy; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; + srcbm.data2 = srcu; + srcbm.pitch2 = srcpitch/2; + srcbm.data3 = srcv; + srcbm.pitch3 = srcpitch/2; + + VDPixmap dstpxm = { + (char *)dst + dstpitch * (h - 1), + NULL, + w, + h, + -dstpitch + }; + + switch(dbpp) { + case 16: + dstpxm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + dstpxm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromI420ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) +{ + if (srcpitch == 0) srcpitch = w; + +#ifndef _WIN64 + if (!((DWORD_PTR)srcy&15) && !((DWORD_PTR)srcu&15) && !((DWORD_PTR)srcv&15) && !(srcpitch&31) && !((DWORD_PTR)dst&15) && !(dstpitch&15)) + { + if (w<=0 || h<=0 || (w&1) || (h&1)) + return false; + + yv12_yuy2_sse2(srcy, srcu, srcv, srcpitch/2, w/2, h, dst, dstpitch); + return true; + } +#endif + + VDPixmap srcbm = {0}; + + srcbm.data = srcy; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV420_Planar; + srcbm.data2 = srcu; + srcbm.pitch2 = srcpitch/2; + srcbm.data3 = srcv; + srcbm.pitch3 = srcpitch/2; + + VDPixmap dstpxm = { + dst, + NULL, + w, + h, + dstpitch + }; + + dstpxm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromRGBToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch, int sbpp) +{ + VDPixmap srcbm = { + (char *)src + srcpitch * (h - 1), + NULL, + w, + h, + -srcpitch + }; + + switch(sbpp) { + case 8: + srcbm.format = nsVDPixmap::kPixFormat_Pal8; + break; + case 16: + srcbm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + srcbm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + srcbm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + VDPixmap dstpxm = { + (char *)dst + dstpitch * (h - 1), + NULL, + w, + h, + -dstpitch + }; + + switch(dbpp) { + case 8: + dstpxm.format = nsVDPixmap::kPixFormat_Pal8; + break; + case 16: + dstpxm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + dstpxm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + return VDPixmapBlt(dstpxm, srcbm); +} + +bool BitBltFromRGBToRGBStretch(int dstw, int dsth, BYTE* dst, int dstpitch, int dbpp, int srcw, int srch, BYTE* src, int srcpitch, int sbpp) +{ + VDPixmap srcbm = { + src + srcpitch * (srch - 1), + nullptr, + srcw, + srch, + -srcpitch + }; + + switch (sbpp) { + case 8: + srcbm.format = nsVDPixmap::kPixFormat_Pal8; + break; + case 16: + srcbm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + srcbm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + srcbm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + VDPixmap dstpxm = { + dst + dstpitch * (dsth - 1), + nullptr, + dstw, + dsth, + -dstpitch + }; + + switch (dbpp) { + case 8: + dstpxm.format = nsVDPixmap::kPixFormat_Pal8; + break; + case 16: + dstpxm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + dstpxm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + return VDPixmapResample(dstpxm, srcbm, IVDPixmapResampler::kFilterCubic); +} + + +bool BitBltFromYUY2ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch) +{ + if (srcpitch == 0) srcpitch = w; + + VDPixmap srcbm = {0}; + + srcbm.data = src; + srcbm.pitch = srcpitch; + srcbm.w = w; + srcbm.h = h; + srcbm.format = nsVDPixmap::kPixFormat_YUV422_YUYV; + + VDPixmap dstpxm = { + (char *)dst + dstpitch * (h - 1), + NULL, + w, + h, + -dstpitch + }; + + switch(dbpp) { + case 16: + dstpxm.format = nsVDPixmap::kPixFormat_RGB565; + break; + case 24: + dstpxm.format = nsVDPixmap::kPixFormat_RGB888; + break; + case 32: + dstpxm.format = nsVDPixmap::kPixFormat_XRGB8888; + break; + default: + VDASSERT(false); + } + + return VDPixmapBlt(dstpxm, srcbm); +} + +static void yuvtoyuy2row_c(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) +{ + WORD* dstw = (WORD*)dst; + for (; width > 1; width -= 2) + { + *dstw++ = (*srcu++<<8)|*srcy++; + *dstw++ = (*srcv++<<8)|*srcy++; + } +} + +static void yuvtoyuy2row_avg_c(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) +{ + WORD* dstw = (WORD*)dst; + for (; width > 1; width -= 2, srcu++, srcv++) + { + *dstw++ = (((srcu[0]+srcu[pitchuv])>>1)<<8)|*srcy++; + *dstw++ = (((srcv[0]+srcv[pitchuv])>>1)<<8)|*srcy++; + } +} + +bool BitBltFromI420ToYUY2Interlaced(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch) +{ + if (w<=0 || h<=0 || (w&1) || (h&1)) + return false; + + if (srcpitch == 0) srcpitch = w; + + void (*yuvtoyuy2row)(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) = NULL; + void (*yuvtoyuy2row_avg)(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) = NULL; + +#ifndef _WIN64 + if (!((DWORD_PTR)srcy&15) && !((DWORD_PTR)srcu&15) && !((DWORD_PTR)srcv&15) && !(srcpitch&31) && !((DWORD_PTR)dst&15) && !(dstpitch&15)) + { + yv12_yuy2_sse2_interlaced(srcy, srcu, srcv, srcpitch/2, w/2, h, dst, dstpitch); + return true; + } + + if (!(w&7)) + { + yuvtoyuy2row = yuvtoyuy2row_MMX; + yuvtoyuy2row_avg = yuvtoyuy2row_avg_MMX; + } + else +#endif + { + yuvtoyuy2row = yuvtoyuy2row_c; + yuvtoyuy2row_avg = yuvtoyuy2row_avg_c; + } + + if (!yuvtoyuy2row) + return false; + + int halfsrcpitch = srcpitch/2; + do + { + yuvtoyuy2row(dst, srcy, srcu, srcv, w); + yuvtoyuy2row_avg(dst + dstpitch, srcy + srcpitch, srcu, srcv, w, halfsrcpitch); + + dst += 2*dstpitch; + srcy += 2*srcpitch; + srcu += halfsrcpitch; + srcv += halfsrcpitch; + } + while ((h -= 2) > 2); + + yuvtoyuy2row(dst, srcy, srcu, srcv, w); + yuvtoyuy2row(dst + dstpitch, srcy + srcpitch, srcu, srcv, w); + +#ifndef _WIN64 + __asm emms +#endif + + return true; +} diff --git a/src/DSUtil/vd.h b/src/DSUtil/vd.h index df867454c73..5f4d890dc64 100644 --- a/src/DSUtil/vd.h +++ b/src/DSUtil/vd.h @@ -1,47 +1,47 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// Notes: -// - VDPixmapBlt is from VirtualDub -// - sse2 yv12 to yuy2 conversion by Haali -// (- vd.cpp/h should be renamed to something more sensible already :) - -#pragma once - -#if 0 -class CCpuID { -public: - CCpuID(); - enum flag_t {mmx=1, ssemmx=2, ssefpu=4, sse2=8, _3dnow=16} m_flags; -}; -extern CCpuID g_cpuid; -#endif - -extern bool BitBltFromI420ToI420(int w, int h, BYTE* dsty, BYTE* dstu, BYTE* dstv, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); -extern bool BitBltFromI420ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); -extern bool BitBltFromI420ToYUY2Interlaced(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); -extern bool BitBltFromI420ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch /* TODO: , bool fInterlaced = false */); -extern bool BitBltFromYUY2ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* src, int srcpitch); -extern bool BitBltFromYUY2ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch); -extern bool BitBltFromRGBToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch, int sbpp); -extern bool BitBltFromRGBToRGBStretch(int dstw, int dsth, BYTE* dst, int dstpitch, int dbpp, int srcw, int srch, BYTE* src, int srcpitch, int sbpp); - -extern void DeinterlaceBlend(BYTE* dst, BYTE* src, DWORD rowbytes, DWORD h, DWORD dstpitch, DWORD srcpitch); -extern void DeinterlaceBob(BYTE* dst, BYTE* src, DWORD rowbytes, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); -extern void DeinterlaceELA_X8R8G8B8(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); -extern void DeinterlaceELA(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Notes: +// - VDPixmapBlt is from VirtualDub +// - sse2 yv12 to yuy2 conversion by Haali +// (- vd.cpp/h should be renamed to something more sensible already :) + +#pragma once + +#if 0 +class CCpuID { +public: + CCpuID(); + enum flag_t {mmx=1, ssemmx=2, ssefpu=4, sse2=8, _3dnow=16} m_flags; +}; +extern CCpuID g_cpuid; +#endif + +extern bool BitBltFromI420ToI420(int w, int h, BYTE* dsty, BYTE* dstu, BYTE* dstv, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); +extern bool BitBltFromI420ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); +extern bool BitBltFromI420ToYUY2Interlaced(int w, int h, BYTE* dst, int dstpitch, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch); +extern bool BitBltFromI420ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* srcy, BYTE* srcu, BYTE* srcv, int srcpitch /* TODO: , bool fInterlaced = false */); +extern bool BitBltFromYUY2ToYUY2(int w, int h, BYTE* dst, int dstpitch, BYTE* src, int srcpitch); +extern bool BitBltFromYUY2ToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch); +extern bool BitBltFromRGBToRGB(int w, int h, BYTE* dst, int dstpitch, int dbpp, BYTE* src, int srcpitch, int sbpp); +extern bool BitBltFromRGBToRGBStretch(int dstw, int dsth, BYTE* dst, int dstpitch, int dbpp, int srcw, int srch, BYTE* src, int srcpitch, int sbpp); + +extern void DeinterlaceBlend(BYTE* dst, BYTE* src, DWORD rowbytes, DWORD h, DWORD dstpitch, DWORD srcpitch); +extern void DeinterlaceBob(BYTE* dst, BYTE* src, DWORD rowbytes, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); +extern void DeinterlaceELA_X8R8G8B8(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); +extern void DeinterlaceELA(BYTE* dst, BYTE* src, DWORD w, DWORD h, DWORD dstpitch, DWORD srcpitch, bool topfield); diff --git a/src/DSUtil/vd_asm.cpp b/src/DSUtil/vd_asm.cpp index 0cc10e92e80..040dd500504 100644 --- a/src/DSUtil/vd_asm.cpp +++ b/src/DSUtil/vd_asm.cpp @@ -1,432 +1,432 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// Notes: -// - VDPixmapBlt is from VirtualDub -// - sse2 yv12 to yuy2 conversion by Haali -// (- vd.cpp/h should be renamed to something more sensible already :) - - -#include "stdafx.h" -#include "vd_asm.h" - -#pragma warning(disable : 4799) // no emms... blahblahblah - -#ifndef _WIN64 -void __declspec(naked) yuvtoyuy2row_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) -{ - __asm { - push ebp - push edi - push esi - push ebx - - mov edi, [esp+20] // dst - mov ebp, [esp+24] // srcy - mov ebx, [esp+28] // srcu - mov esi, [esp+32] // srcv - mov ecx, [esp+36] // width - - shr ecx, 3 - -yuvtoyuy2row_loop: - - movd mm0, [ebx] - punpcklbw mm0, [esi] - - movq mm1, [ebp] - movq mm2, mm1 - punpcklbw mm1, mm0 - punpckhbw mm2, mm0 - - movq [edi], mm1 - movq [edi+8], mm2 - - add ebp, 8 - add ebx, 4 - add esi, 4 - add edi, 16 - - dec ecx - jnz yuvtoyuy2row_loop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -void __declspec(naked) yuvtoyuy2row_avg_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) -{ - static const __int64 mask = 0x7f7f7f7f7f7f7f7fi64; - - __asm { - push ebp - push edi - push esi - push ebx - - movq mm7, mask - - mov edi, [esp+20] // dst - mov ebp, [esp+24] // srcy - mov ebx, [esp+28] // srcu - mov esi, [esp+32] // srcv - mov ecx, [esp+36] // width - mov eax, [esp+40] // pitchuv - - shr ecx, 3 - -yuvtoyuy2row_avg_loop: - - movd mm0, [ebx] - punpcklbw mm0, [esi] - movq mm1, mm0 - - movd mm2, [ebx + eax] - punpcklbw mm2, [esi + eax] - movq mm3, mm2 - - // (x+y)>>1 == (x&y)+((x^y)>>1) - - pand mm0, mm2 - pxor mm1, mm3 - psrlq mm1, 1 - pand mm1, mm7 - paddb mm0, mm1 - - movq mm1, [ebp] - movq mm2, mm1 - punpcklbw mm1, mm0 - punpckhbw mm2, mm0 - - movq [edi], mm1 - movq [edi+8], mm2 - - add ebp, 8 - add ebx, 4 - add esi, 4 - add edi, 16 - - dec ecx - jnz yuvtoyuy2row_avg_loop - - pop ebx - pop esi - pop edi - pop ebp - ret - }; -} - -void __declspec(naked) yv12_yuy2_row_sse2() { - __asm { - // ebx - Y - // edx - U - // esi - V - // edi - dest - // ecx - halfwidth - xor eax, eax - -one: - movdqa xmm0, [ebx + eax*2] // YYYYYYYY - movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY - - movdqa xmm2, [edx + eax] // UUUUUUUU - movdqa xmm3, [esi + eax] // VVVVVVVV - - movdqa xmm4, xmm2 - movdqa xmm5, xmm0 - movdqa xmm6, xmm1 - punpcklbw xmm2, xmm3 // VUVUVUVU - punpckhbw xmm4, xmm3 // VUVUVUVU - - punpcklbw xmm0, xmm2 // VYUYVYUY - punpcklbw xmm1, xmm4 - punpckhbw xmm5, xmm2 - punpckhbw xmm6, xmm4 - - movntdq [edi + eax*4], xmm0 - movntdq [edi + eax*4 + 16], xmm5 - movntdq [edi + eax*4 + 32], xmm1 - movntdq [edi + eax*4 + 48], xmm6 - - add eax, 16 - cmp eax, ecx - - jb one - - ret - }; -} - -void __declspec(naked) yv12_yuy2_row_sse2_linear() { - __asm { - // ebx - Y - // edx - U - // esi - V - // edi - dest - // ecx - width - // ebp - uv_stride - xor eax, eax - -one: - movdqa xmm0, [ebx + eax*2] // YYYYYYYY - movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY - - movdqa xmm2, [edx] - movdqa xmm3, [esi] - pavgb xmm2, [edx + ebp] // UUUUUUUU - pavgb xmm3, [esi + ebp] // VVVVVVVV - - movdqa xmm4, xmm2 - movdqa xmm5, xmm0 - movdqa xmm6, xmm1 - punpcklbw xmm2, xmm3 // VUVUVUVU - punpckhbw xmm4, xmm3 // VUVUVUVU - - punpcklbw xmm0, xmm2 // VYUYVYUY - punpcklbw xmm1, xmm4 - punpckhbw xmm5, xmm2 - punpckhbw xmm6, xmm4 - - movntdq [edi + eax*4], xmm0 - movntdq [edi + eax*4 + 16], xmm5 - movntdq [edi + eax*4 + 32], xmm1 - movntdq [edi + eax*4 + 48], xmm6 - - add eax, 16 - add edx, 16 - add esi, 16 - cmp eax, ecx - - jb one - - ret - }; -} - -void __declspec(naked) yv12_yuy2_row_sse2_linear_interlaced() { - __asm { - // ebx - Y - // edx - U - // esi - V - // edi - dest - // ecx - width - // ebp - uv_stride - xor eax, eax - -one: - movdqa xmm0, [ebx + eax*2] // YYYYYYYY - movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY - - movdqa xmm2, [edx] - movdqa xmm3, [esi] - pavgb xmm2, [edx + ebp*2] // UUUUUUUU - pavgb xmm3, [esi + ebp*2] // VVVVVVVV - - movdqa xmm4, xmm2 - movdqa xmm5, xmm0 - movdqa xmm6, xmm1 - punpcklbw xmm2, xmm3 // VUVUVUVU - punpckhbw xmm4, xmm3 // VUVUVUVU - - punpcklbw xmm0, xmm2 // VYUYVYUY - punpcklbw xmm1, xmm4 - punpckhbw xmm5, xmm2 - punpckhbw xmm6, xmm4 - - movntdq [edi + eax*4], xmm0 - movntdq [edi + eax*4 + 16], xmm5 - movntdq [edi + eax*4 + 32], xmm1 - movntdq [edi + eax*4 + 48], xmm6 - - add eax, 16 - add edx, 16 - add esi, 16 - cmp eax, ecx - - jb one - - ret - }; -} - -void __declspec(naked) yv12_yuy2_sse2(const BYTE *Y, const BYTE *U, const BYTE *V, - int halfstride, unsigned halfwidth, unsigned height, - BYTE *YUY2, int d_stride) -{ - __asm { - push ebx - push esi - push edi - push ebp - - mov ebx, [esp + 20] // Y - mov edx, [esp + 24] // U - mov esi, [esp + 28] // V - mov edi, [esp + 44] // D - mov ebp, [esp + 32] // uv_stride - mov ecx, [esp + 36] // uv_width - - mov eax, ecx - add eax, 15 - and eax, 0xfffffff0 - sub [esp + 32], eax - - cmp dword ptr [esp + 40], 2 - jbe last2 - -row: - sub dword ptr [esp + 40], 2 - call yv12_yuy2_row_sse2 - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - call yv12_yuy2_row_sse2_linear - - add edx, [esp + 32] - add esi, [esp + 32] - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - cmp dword ptr [esp + 40], 2 - ja row - -last2: - call yv12_yuy2_row_sse2 - - dec dword ptr [esp + 40] - jz done - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - call yv12_yuy2_row_sse2 -done: - - pop ebp - pop edi - pop esi - pop ebx - - ret - }; -} - -void __declspec(naked) yv12_yuy2_sse2_interlaced(const BYTE *Y, const BYTE *U, const BYTE *V, - int halfstride, unsigned halfwidth, unsigned height, - BYTE *YUY2, int d_stride) -{ - __asm { - push ebx - push esi - push edi - push ebp - - mov ebx, [esp + 20] // Y - mov edx, [esp + 24] // U - mov esi, [esp + 28] // V - mov edi, [esp + 44] // D - mov ebp, [esp + 32] // uv_stride - mov ecx, [esp + 36] // uv_width - - mov eax, ecx - add eax, 15 - and eax, 0xfffffff0 - sub [esp + 32], eax - - cmp dword ptr [esp + 40], 4 - jbe last4 - -row: - sub dword ptr [esp + 40], 4 - call yv12_yuy2_row_sse2 // first row, first field - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - add edx, ebp - add esi, ebp - - call yv12_yuy2_row_sse2 // first row, second field - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - sub edx, ebp - sub esi, ebp - - call yv12_yuy2_row_sse2_linear_interlaced // second row, first field - - add edx, [esp + 32] - add esi, [esp + 32] - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - call yv12_yuy2_row_sse2_linear_interlaced // second row, second field - - add edx, [esp + 32] - add esi, [esp + 32] - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - cmp dword ptr [esp + 40], 4 - ja row - -last4: - call yv12_yuy2_row_sse2 - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - add edx, ebp - add esi, ebp - - call yv12_yuy2_row_sse2 - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - sub edx, ebp - sub esi, ebp - - call yv12_yuy2_row_sse2 - - lea ebx, [ebx + ebp*2] - add edi, [esp + 48] - - add edx, ebp - add esi, ebp - - call yv12_yuy2_row_sse2 - - pop ebp - pop edi - pop esi - pop ebx - - ret - }; -} -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Notes: +// - VDPixmapBlt is from VirtualDub +// - sse2 yv12 to yuy2 conversion by Haali +// (- vd.cpp/h should be renamed to something more sensible already :) + + +#include "stdafx.h" +#include "vd_asm.h" + +#pragma warning(disable : 4799) // no emms... blahblahblah + +#ifndef _WIN64 +void __declspec(naked) yuvtoyuy2row_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width) +{ + __asm { + push ebp + push edi + push esi + push ebx + + mov edi, [esp+20] // dst + mov ebp, [esp+24] // srcy + mov ebx, [esp+28] // srcu + mov esi, [esp+32] // srcv + mov ecx, [esp+36] // width + + shr ecx, 3 + +yuvtoyuy2row_loop: + + movd mm0, [ebx] + punpcklbw mm0, [esi] + + movq mm1, [ebp] + movq mm2, mm1 + punpcklbw mm1, mm0 + punpckhbw mm2, mm0 + + movq [edi], mm1 + movq [edi+8], mm2 + + add ebp, 8 + add ebx, 4 + add esi, 4 + add edi, 16 + + dec ecx + jnz yuvtoyuy2row_loop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +void __declspec(naked) yuvtoyuy2row_avg_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv) +{ + static const __int64 mask = 0x7f7f7f7f7f7f7f7fi64; + + __asm { + push ebp + push edi + push esi + push ebx + + movq mm7, mask + + mov edi, [esp+20] // dst + mov ebp, [esp+24] // srcy + mov ebx, [esp+28] // srcu + mov esi, [esp+32] // srcv + mov ecx, [esp+36] // width + mov eax, [esp+40] // pitchuv + + shr ecx, 3 + +yuvtoyuy2row_avg_loop: + + movd mm0, [ebx] + punpcklbw mm0, [esi] + movq mm1, mm0 + + movd mm2, [ebx + eax] + punpcklbw mm2, [esi + eax] + movq mm3, mm2 + + // (x+y)>>1 == (x&y)+((x^y)>>1) + + pand mm0, mm2 + pxor mm1, mm3 + psrlq mm1, 1 + pand mm1, mm7 + paddb mm0, mm1 + + movq mm1, [ebp] + movq mm2, mm1 + punpcklbw mm1, mm0 + punpckhbw mm2, mm0 + + movq [edi], mm1 + movq [edi+8], mm2 + + add ebp, 8 + add ebx, 4 + add esi, 4 + add edi, 16 + + dec ecx + jnz yuvtoyuy2row_avg_loop + + pop ebx + pop esi + pop edi + pop ebp + ret + }; +} + +void __declspec(naked) yv12_yuy2_row_sse2() { + __asm { + // ebx - Y + // edx - U + // esi - V + // edi - dest + // ecx - halfwidth + xor eax, eax + +one: + movdqa xmm0, [ebx + eax*2] // YYYYYYYY + movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY + + movdqa xmm2, [edx + eax] // UUUUUUUU + movdqa xmm3, [esi + eax] // VVVVVVVV + + movdqa xmm4, xmm2 + movdqa xmm5, xmm0 + movdqa xmm6, xmm1 + punpcklbw xmm2, xmm3 // VUVUVUVU + punpckhbw xmm4, xmm3 // VUVUVUVU + + punpcklbw xmm0, xmm2 // VYUYVYUY + punpcklbw xmm1, xmm4 + punpckhbw xmm5, xmm2 + punpckhbw xmm6, xmm4 + + movntdq [edi + eax*4], xmm0 + movntdq [edi + eax*4 + 16], xmm5 + movntdq [edi + eax*4 + 32], xmm1 + movntdq [edi + eax*4 + 48], xmm6 + + add eax, 16 + cmp eax, ecx + + jb one + + ret + }; +} + +void __declspec(naked) yv12_yuy2_row_sse2_linear() { + __asm { + // ebx - Y + // edx - U + // esi - V + // edi - dest + // ecx - width + // ebp - uv_stride + xor eax, eax + +one: + movdqa xmm0, [ebx + eax*2] // YYYYYYYY + movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY + + movdqa xmm2, [edx] + movdqa xmm3, [esi] + pavgb xmm2, [edx + ebp] // UUUUUUUU + pavgb xmm3, [esi + ebp] // VVVVVVVV + + movdqa xmm4, xmm2 + movdqa xmm5, xmm0 + movdqa xmm6, xmm1 + punpcklbw xmm2, xmm3 // VUVUVUVU + punpckhbw xmm4, xmm3 // VUVUVUVU + + punpcklbw xmm0, xmm2 // VYUYVYUY + punpcklbw xmm1, xmm4 + punpckhbw xmm5, xmm2 + punpckhbw xmm6, xmm4 + + movntdq [edi + eax*4], xmm0 + movntdq [edi + eax*4 + 16], xmm5 + movntdq [edi + eax*4 + 32], xmm1 + movntdq [edi + eax*4 + 48], xmm6 + + add eax, 16 + add edx, 16 + add esi, 16 + cmp eax, ecx + + jb one + + ret + }; +} + +void __declspec(naked) yv12_yuy2_row_sse2_linear_interlaced() { + __asm { + // ebx - Y + // edx - U + // esi - V + // edi - dest + // ecx - width + // ebp - uv_stride + xor eax, eax + +one: + movdqa xmm0, [ebx + eax*2] // YYYYYYYY + movdqa xmm1, [ebx + eax*2 + 16] // YYYYYYYY + + movdqa xmm2, [edx] + movdqa xmm3, [esi] + pavgb xmm2, [edx + ebp*2] // UUUUUUUU + pavgb xmm3, [esi + ebp*2] // VVVVVVVV + + movdqa xmm4, xmm2 + movdqa xmm5, xmm0 + movdqa xmm6, xmm1 + punpcklbw xmm2, xmm3 // VUVUVUVU + punpckhbw xmm4, xmm3 // VUVUVUVU + + punpcklbw xmm0, xmm2 // VYUYVYUY + punpcklbw xmm1, xmm4 + punpckhbw xmm5, xmm2 + punpckhbw xmm6, xmm4 + + movntdq [edi + eax*4], xmm0 + movntdq [edi + eax*4 + 16], xmm5 + movntdq [edi + eax*4 + 32], xmm1 + movntdq [edi + eax*4 + 48], xmm6 + + add eax, 16 + add edx, 16 + add esi, 16 + cmp eax, ecx + + jb one + + ret + }; +} + +void __declspec(naked) yv12_yuy2_sse2(const BYTE *Y, const BYTE *U, const BYTE *V, + int halfstride, unsigned halfwidth, unsigned height, + BYTE *YUY2, int d_stride) +{ + __asm { + push ebx + push esi + push edi + push ebp + + mov ebx, [esp + 20] // Y + mov edx, [esp + 24] // U + mov esi, [esp + 28] // V + mov edi, [esp + 44] // D + mov ebp, [esp + 32] // uv_stride + mov ecx, [esp + 36] // uv_width + + mov eax, ecx + add eax, 15 + and eax, 0xfffffff0 + sub [esp + 32], eax + + cmp dword ptr [esp + 40], 2 + jbe last2 + +row: + sub dword ptr [esp + 40], 2 + call yv12_yuy2_row_sse2 + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + call yv12_yuy2_row_sse2_linear + + add edx, [esp + 32] + add esi, [esp + 32] + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + cmp dword ptr [esp + 40], 2 + ja row + +last2: + call yv12_yuy2_row_sse2 + + dec dword ptr [esp + 40] + jz done + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + call yv12_yuy2_row_sse2 +done: + + pop ebp + pop edi + pop esi + pop ebx + + ret + }; +} + +void __declspec(naked) yv12_yuy2_sse2_interlaced(const BYTE *Y, const BYTE *U, const BYTE *V, + int halfstride, unsigned halfwidth, unsigned height, + BYTE *YUY2, int d_stride) +{ + __asm { + push ebx + push esi + push edi + push ebp + + mov ebx, [esp + 20] // Y + mov edx, [esp + 24] // U + mov esi, [esp + 28] // V + mov edi, [esp + 44] // D + mov ebp, [esp + 32] // uv_stride + mov ecx, [esp + 36] // uv_width + + mov eax, ecx + add eax, 15 + and eax, 0xfffffff0 + sub [esp + 32], eax + + cmp dword ptr [esp + 40], 4 + jbe last4 + +row: + sub dword ptr [esp + 40], 4 + call yv12_yuy2_row_sse2 // first row, first field + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + add edx, ebp + add esi, ebp + + call yv12_yuy2_row_sse2 // first row, second field + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + sub edx, ebp + sub esi, ebp + + call yv12_yuy2_row_sse2_linear_interlaced // second row, first field + + add edx, [esp + 32] + add esi, [esp + 32] + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + call yv12_yuy2_row_sse2_linear_interlaced // second row, second field + + add edx, [esp + 32] + add esi, [esp + 32] + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + cmp dword ptr [esp + 40], 4 + ja row + +last4: + call yv12_yuy2_row_sse2 + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + add edx, ebp + add esi, ebp + + call yv12_yuy2_row_sse2 + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + sub edx, ebp + sub esi, ebp + + call yv12_yuy2_row_sse2 + + lea ebx, [ebx + ebp*2] + add edi, [esp + 48] + + add edx, ebp + add esi, ebp + + call yv12_yuy2_row_sse2 + + pop ebp + pop edi + pop esi + pop ebx + + ret + }; +} +#endif diff --git a/src/DSUtil/vd_asm.h b/src/DSUtil/vd_asm.h index b637eeffb48..4e0fd8e9005 100644 --- a/src/DSUtil/vd_asm.h +++ b/src/DSUtil/vd_asm.h @@ -1,34 +1,34 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2007 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// Notes: -// - VDPixmapBlt is from VirtualDub -// (- vd.cpp/h should be renamed to something more sensible already :) - -#pragma once - -#ifndef _WIN64 -void yuvtoyuy2row_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width); -void yuvtoyuy2row_avg_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv); - -void yv12_yuy2_row_sse2(); -void yv12_yuy2_row_sse2_linear(); -void yv12_yuy2_row_sse2_linear_interlaced(); -void yv12_yuy2_sse2(const BYTE *Y, const BYTE *U, const BYTE *V, int halfstride, unsigned halfwidth, unsigned height, BYTE *YUY2, int d_stride); -void yv12_yuy2_sse2_interlaced(const BYTE *Y, const BYTE *U, const BYTE *V, int halfstride, unsigned halfwidth, unsigned height, BYTE *YUY2, int d_stride); -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2007 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Notes: +// - VDPixmapBlt is from VirtualDub +// (- vd.cpp/h should be renamed to something more sensible already :) + +#pragma once + +#ifndef _WIN64 +void yuvtoyuy2row_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width); +void yuvtoyuy2row_avg_MMX(BYTE* dst, BYTE* srcy, BYTE* srcu, BYTE* srcv, DWORD width, DWORD pitchuv); + +void yv12_yuy2_row_sse2(); +void yv12_yuy2_row_sse2_linear(); +void yv12_yuy2_row_sse2_linear_interlaced(); +void yv12_yuy2_sse2(const BYTE *Y, const BYTE *U, const BYTE *V, int halfstride, unsigned halfwidth, unsigned height, BYTE *YUY2, int d_stride); +void yv12_yuy2_sse2_interlaced(const BYTE *Y, const BYTE *U, const BYTE *V, int halfstride, unsigned halfwidth, unsigned height, BYTE *YUY2, int d_stride); +#endif diff --git a/src/DeCSS/CSSauth.cpp b/src/DeCSS/CSSauth.cpp index eee0fa2f304..ca9142f45b3 100644 --- a/src/DeCSS/CSSauth.cpp +++ b/src/DeCSS/CSSauth.cpp @@ -1,339 +1,339 @@ -#include "stdafx.h" - -static void CSSengine(int varient,unsigned char const *input,unsigned char *output); - -void CSSkey1(int varient,unsigned char const *challenge,unsigned char *key) -{ - static unsigned char perm_challenge[] = {1,3,0,7,5, 2,9,6,4,8}; - - unsigned char scratch[10]; - int i; - - for (i = 9; i >= 0; --i) { - scratch[i] = challenge[perm_challenge[i]]; - } - - CSSengine(varient, scratch, key); -} - -void CSSkey2(int varient,unsigned char const *challenge,unsigned char *key) -{ - static unsigned char perm_challenge[] = {6,1,9,3,8, 5,7,4,0,2}; - - static unsigned char perm_varient[] = { - 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d, - 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d, - 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05, - 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 - }; - - unsigned char scratch[10]; - int i; - - for (i = 9; i >= 0; --i) { - scratch[i] = challenge[perm_challenge[i]]; - } - - CSSengine(perm_varient[varient], scratch, key); -} - -void CSSbuskey(int varient,unsigned char const *challenge,unsigned char *key) -{ - static unsigned char perm_challenge[] = {4,0,3,5,7, 2,8,6,1,9}; - static unsigned char perm_varient[] = { - 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e, - 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c, - 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f, - 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d - }; - - unsigned char scratch[10]; - int i; - - for (i = 9; i >= 0; --i) { - scratch[i] = challenge[perm_challenge[i]]; - } - - CSSengine(perm_varient[varient], scratch, key); -} - -static void CSSgenbits(unsigned char *output, int len,unsigned char const *s) -{ - unsigned long lfsr0, lfsr1; - unsigned char b1_combined; /* Save the old value of bit 1 for feedback */ - - /* In order to ensure that the LFSR works we need to ensure that the - * initial values are non-zero. Thus when we initialise them from - * the seed, we ensure that a bit is set. - */ - lfsr0 = (s[0] << 17) | (s[1] << 9) | ((s[2] & ~7) << 1) | 8 | (s[2] & 7); - lfsr1 = (s[3] << 9) | 0x100 | s[4]; - - ++output; - - b1_combined = 0; - do { - int bit; - unsigned char val; - - for (bit = 0, val = 0; bit < 8; ++bit) { - unsigned char o_lfsr0, o_lfsr1; /* Actually only 1 bit each */ - unsigned char combined; - - o_lfsr0 = ((lfsr0 >> 24) ^ (lfsr0 >> 21) ^ (lfsr0 >> 20) ^ (lfsr0 >> 12)) & 1; - lfsr0 = (lfsr0 << 1) | o_lfsr0; - - o_lfsr1 = ((lfsr1 >> 16) ^ (lfsr1 >> 2)) & 1; - lfsr1 = (lfsr1 << 1) | o_lfsr1; - -#define BIT0(x) ((x) & 1) -#define BIT1(x) (((x) >> 1) & 1) - - combined = !o_lfsr1 + b1_combined + !o_lfsr0; - b1_combined = BIT1(combined); - val |= BIT0(combined) << bit; - } - - *--output = val; - } while (--len > 0); -} - -unsigned char CSSsecret[]; -unsigned char CSSvarients[]; -unsigned char CSStable0[]; -unsigned char CSStable1[]; -unsigned char CSStable2[]; -unsigned char CSStable3[]; - -static void CSSengine(int varient, unsigned char const *input,unsigned char *output) -{ - unsigned char cse, term, index; - unsigned char temp1[5]; - unsigned char temp2[5]; - unsigned char bits[30]; - - int i; - - /* Feed the CSSsecret into the input values such that - * we alter the seed to the LFSR's used above, then - * generate the bits to play with. - */ - for (i = 5; --i >= 0; ) { - temp1[i] = input[5 + i] ^ CSSsecret[i] ^ CSStable2[i]; - } - - CSSgenbits(&bits[29], sizeof bits, temp1); - - /* This term is used throughout the following to - * select one of 32 different variations on the - * algorithm. - */ - cse = CSSvarients[varient] ^ CSStable2[varient]; - - /* Now the actual blocks doing the encryption. Each - * of these works on 40 bits at a time and are quite - * similar. - */ - for (i = 5, term = 0; --i >= 0; term = input[i]) { - index = bits[25 + i] ^ input[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - temp1[i] = CSStable2[index] ^ CSStable3[index] ^ term; - } - temp1[4] ^= temp1[0]; - - for (i = 5, term = 0; --i >= 0; term = temp1[i]) { - index = bits[20 + i] ^ temp1[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - temp2[i] = CSStable2[index] ^ CSStable3[index] ^ term; - } - temp2[4] ^= temp2[0]; - - for (i = 5, term = 0; --i >= 0; term = temp2[i]) { - index = bits[15 + i] ^ temp2[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - index = CSStable2[index] ^ CSStable3[index] ^ term; - - temp1[i] = CSStable0[index] ^ CSStable2[index]; - } - temp1[4] ^= temp1[0]; - - for (i = 5, term = 0; --i >= 0; term = temp1[i]) { - index = bits[10 + i] ^ temp1[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - index = CSStable2[index] ^ CSStable3[index] ^ term; - - temp2[i] = CSStable0[index] ^ CSStable2[index]; - } - temp2[4] ^= temp2[0]; - - for (i = 5, term = 0; --i >= 0; term = temp2[i]) { - index = bits[5 + i] ^ temp2[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - temp1[i] = CSStable2[index] ^ CSStable3[index] ^ term; - } - temp1[4] ^= temp1[0]; - - for (i = 5, term = 0; --i >= 0; term = temp1[i]) { - index = bits[i] ^ temp1[i]; - index = CSStable1[index] ^ ~CSStable2[index] ^ cse; - - output[i] = CSStable2[index] ^ CSStable3[index] ^ term; - } -} - -unsigned char CSSvarients[] = { - 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73, - 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42, - 0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B, - 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 -}; - -unsigned char CSSsecret[] = {0x55, 0xD6, 0xC4, 0xC5, 0x28}; - -unsigned char CSStable0[] = { - 0xB7, 0xF4, 0x82, 0x57, 0xDA, 0x4D, 0xDB, 0xE2, - 0x2F, 0x52, 0x1A, 0xA8, 0x68, 0x5A, 0x8A, 0xFF, - 0xFB, 0x0E, 0x6D, 0x35, 0xF7, 0x5C, 0x76, 0x12, - 0xCE, 0x25, 0x79, 0x29, 0x39, 0x62, 0x08, 0x24, - 0xA5, 0x85, 0x7B, 0x56, 0x01, 0x23, 0x68, 0xCF, - 0x0A, 0xE2, 0x5A, 0xED, 0x3D, 0x59, 0xB0, 0xA9, - 0xB0, 0x2C, 0xF2, 0xB8, 0xEF, 0x32, 0xA9, 0x40, - 0x80, 0x71, 0xAF, 0x1E, 0xDE, 0x8F, 0x58, 0x88, - 0xB8, 0x3A, 0xD0, 0xFC, 0xC4, 0x1E, 0xB5, 0xA0, - 0xBB, 0x3B, 0x0F, 0x01, 0x7E, 0x1F, 0x9F, 0xD9, - 0xAA, 0xB8, 0x3D, 0x9D, 0x74, 0x1E, 0x25, 0xDB, - 0x37, 0x56, 0x8F, 0x16, 0xBA, 0x49, 0x2B, 0xAC, - 0xD0, 0xBD, 0x95, 0x20, 0xBE, 0x7A, 0x28, 0xD0, - 0x51, 0x64, 0x63, 0x1C, 0x7F, 0x66, 0x10, 0xBB, - 0xC4, 0x56, 0x1A, 0x04, 0x6E, 0x0A, 0xEC, 0x9C, - 0xD6, 0xE8, 0x9A, 0x7A, 0xCF, 0x8C, 0xDB, 0xB1, - 0xEF, 0x71, 0xDE, 0x31, 0xFF, 0x54, 0x3E, 0x5E, - 0x07, 0x69, 0x96, 0xB0, 0xCF, 0xDD, 0x9E, 0x47, - 0xC7, 0x96, 0x8F, 0xE4, 0x2B, 0x59, 0xC6, 0xEE, - 0xB9, 0x86, 0x9A, 0x64, 0x84, 0x72, 0xE2, 0x5B, - 0xA2, 0x96, 0x58, 0x99, 0x50, 0x03, 0xF5, 0x38, - 0x4D, 0x02, 0x7D, 0xE7, 0x7D, 0x75, 0xA7, 0xB8, - 0x67, 0x87, 0x84, 0x3F, 0x1D, 0x11, 0xE5, 0xFC, - 0x1E, 0xD3, 0x83, 0x16, 0xA5, 0x29, 0xF6, 0xC7, - 0x15, 0x61, 0x29, 0x1A, 0x43, 0x4F, 0x9B, 0xAF, - 0xC5, 0x87, 0x34, 0x6C, 0x0F, 0x3B, 0xA8, 0x1D, - 0x45, 0x58, 0x25, 0xDC, 0xA8, 0xA3, 0x3B, 0xD1, - 0x79, 0x1B, 0x48, 0xF2, 0xE9, 0x93, 0x1F, 0xFC, - 0xDB, 0x2A, 0x90, 0xA9, 0x8A, 0x3D, 0x39, 0x18, - 0xA3, 0x8E, 0x58, 0x6C, 0xE0, 0x12, 0xBB, 0x25, - 0xCD, 0x71, 0x22, 0xA2, 0x64, 0xC6, 0xE7, 0xFB, - 0xAD, 0x94, 0x77, 0x04, 0x9A, 0x39, 0xCF, 0x7C -}; - -unsigned char CSStable1[] = { - 0x8C, 0x47, 0xB0, 0xE1, 0xEB, 0xFC, 0xEB, 0x56, - 0x10, 0xE5, 0x2C, 0x1A, 0x5D, 0xEF, 0xBE, 0x4F, - 0x08, 0x75, 0x97, 0x4B, 0x0E, 0x25, 0x8E, 0x6E, - 0x39, 0x5A, 0x87, 0x53, 0xC4, 0x1F, 0xF4, 0x5C, - 0x4E, 0xE6, 0x99, 0x30, 0xE0, 0x42, 0x88, 0xAB, - 0xE5, 0x85, 0xBC, 0x8F, 0xD8, 0x3C, 0x54, 0xC9, - 0x53, 0x47, 0x18, 0xD6, 0x06, 0x5B, 0x41, 0x2C, - 0x67, 0x1E, 0x41, 0x74, 0x33, 0xE2, 0xB4, 0xE0, - 0x23, 0x29, 0x42, 0xEA, 0x55, 0x0F, 0x25, 0xB4, - 0x24, 0x2C, 0x99, 0x13, 0xEB, 0x0A, 0x0B, 0xC9, - 0xF9, 0x63, 0x67, 0x43, 0x2D, 0xC7, 0x7D, 0x07, - 0x60, 0x89, 0xD1, 0xCC, 0xE7, 0x94, 0x77, 0x74, - 0x9B, 0x7E, 0xD7, 0xE6, 0xFF, 0xBB, 0x68, 0x14, - 0x1E, 0xA3, 0x25, 0xDE, 0x3A, 0xA3, 0x54, 0x7B, - 0x87, 0x9D, 0x50, 0xCA, 0x27, 0xC3, 0xA4, 0x50, - 0x91, 0x27, 0xD4, 0xB0, 0x82, 0x41, 0x97, 0x79, - 0x94, 0x82, 0xAC, 0xC7, 0x8E, 0xA5, 0x4E, 0xAA, - 0x78, 0x9E, 0xE0, 0x42, 0xBA, 0x28, 0xEA, 0xB7, - 0x74, 0xAD, 0x35, 0xDA, 0x92, 0x60, 0x7E, 0xD2, - 0x0E, 0xB9, 0x24, 0x5E, 0x39, 0x4F, 0x5E, 0x63, - 0x09, 0xB5, 0xFA, 0xBF, 0xF1, 0x22, 0x55, 0x1C, - 0xE2, 0x25, 0xDB, 0xC5, 0xD8, 0x50, 0x03, 0x98, - 0xC4, 0xAC, 0x2E, 0x11, 0xB4, 0x38, 0x4D, 0xD0, - 0xB9, 0xFC, 0x2D, 0x3C, 0x08, 0x04, 0x5A, 0xEF, - 0xCE, 0x32, 0xFB, 0x4C, 0x92, 0x1E, 0x4B, 0xFB, - 0x1A, 0xD0, 0xE2, 0x3E, 0xDA, 0x6E, 0x7C, 0x4D, - 0x56, 0xC3, 0x3F, 0x42, 0xB1, 0x3A, 0x23, 0x4D, - 0x6E, 0x84, 0x56, 0x68, 0xF4, 0x0E, 0x03, 0x64, - 0xD0, 0xA9, 0x92, 0x2F, 0x8B, 0xBC, 0x39, 0x9C, - 0xAC, 0x09, 0x5E, 0xEE, 0xE5, 0x97, 0xBF, 0xA5, - 0xCE, 0xFA, 0x28, 0x2C, 0x6D, 0x4F, 0xEF, 0x77, - 0xAA, 0x1B, 0x79, 0x8E, 0x97, 0xB4, 0xC3, 0xF4 -}; - -unsigned char CSStable2[] = { - 0xB7, 0x75, 0x81, 0xD5, 0xDC, 0xCA, 0xDE, 0x66, - 0x23, 0xDF, 0x15, 0x26, 0x62, 0xD1, 0x83, 0x77, - 0xE3, 0x97, 0x76, 0xAF, 0xE9, 0xC3, 0x6B, 0x8E, - 0xDA, 0xB0, 0x6E, 0xBF, 0x2B, 0xF1, 0x19, 0xB4, - 0x95, 0x34, 0x48, 0xE4, 0x37, 0x94, 0x5D, 0x7B, - 0x36, 0x5F, 0x65, 0x53, 0x07, 0xE2, 0x89, 0x11, - 0x98, 0x85, 0xD9, 0x12, 0xC1, 0x9D, 0x84, 0xEC, - 0xA4, 0xD4, 0x88, 0xB8, 0xFC, 0x2C, 0x79, 0x28, - 0xD8, 0xDB, 0xB3, 0x1E, 0xA2, 0xF9, 0xD0, 0x44, - 0xD7, 0xD6, 0x60, 0xEF, 0x14, 0xF4, 0xF6, 0x31, - 0xD2, 0x41, 0x46, 0x67, 0x0A, 0xE1, 0x58, 0x27, - 0x43, 0xA3, 0xF8, 0xE0, 0xC8, 0xBA, 0x5A, 0x5C, - 0x80, 0x6C, 0xC6, 0xF2, 0xE8, 0xAD, 0x7D, 0x04, - 0x0D, 0xB9, 0x3C, 0xC2, 0x25, 0xBD, 0x49, 0x63, - 0x8C, 0x9F, 0x51, 0xCE, 0x20, 0xC5, 0xA1, 0x50, - 0x92, 0x2D, 0xDD, 0xBC, 0x8D, 0x4F, 0x9A, 0x71, - 0x2F, 0x30, 0x1D, 0x73, 0x39, 0x13, 0xFB, 0x1A, - 0xCB, 0x24, 0x59, 0xFE, 0x05, 0x96, 0x57, 0x0F, - 0x1F, 0xCF, 0x54, 0xBE, 0xF5, 0x06, 0x1B, 0xB2, - 0x6D, 0xD3, 0x4D, 0x32, 0x56, 0x21, 0x33, 0x0B, - 0x52, 0xE7, 0xAB, 0xEB, 0xA6, 0x74, 0x00, 0x4C, - 0xB1, 0x7F, 0x82, 0x99, 0x87, 0x0E, 0x5E, 0xC0, - 0x8F, 0xEE, 0x6F, 0x55, 0xF3, 0x7E, 0x08, 0x90, - 0xFA, 0xB6, 0x64, 0x70, 0x47, 0x4A, 0x17, 0xA7, - 0xB5, 0x40, 0x8A, 0x38, 0xE5, 0x68, 0x3E, 0x8B, - 0x69, 0xAA, 0x9B, 0x42, 0xA5, 0x10, 0x01, 0x35, - 0xFD, 0x61, 0x9E, 0xE6, 0x16, 0x9C, 0x86, 0xED, - 0xCD, 0x2E, 0xFF, 0xC4, 0x5B, 0xA0, 0xAE, 0xCC, - 0x4B, 0x3B, 0x03, 0xBB, 0x1C, 0x2A, 0xAC, 0x0C, - 0x3F, 0x93, 0xC7, 0x72, 0x7A, 0x09, 0x22, 0x3D, - 0x45, 0x78, 0xA9, 0xA8, 0xEA, 0xC9, 0x6A, 0xF7, - 0x29, 0x91, 0xF0, 0x02, 0x18, 0x3A, 0x4E, 0x7C -}; - -unsigned char CSStable3[] = { - 0x73, 0x51, 0x95, 0xE1, 0x12, 0xE4, 0xC0, 0x58, - 0xEE, 0xF2, 0x08, 0x1B, 0xA9, 0xFA, 0x98, 0x4C, - 0xA7, 0x33, 0xE2, 0x1B, 0xA7, 0x6D, 0xF5, 0x30, - 0x97, 0x1D, 0xF3, 0x02, 0x60, 0x5A, 0x82, 0x0F, - 0x91, 0xD0, 0x9C, 0x10, 0x39, 0x7A, 0x83, 0x85, - 0x3B, 0xB2, 0xB8, 0xAE, 0x0C, 0x09, 0x52, 0xEA, - 0x1C, 0xE1, 0x8D, 0x66, 0x4F, 0xF3, 0xDA, 0x92, - 0x29, 0xB9, 0xD5, 0xC5, 0x77, 0x47, 0x22, 0x53, - 0x14, 0xF7, 0xAF, 0x22, 0x64, 0xDF, 0xC6, 0x72, - 0x12, 0xF3, 0x75, 0xDA, 0xD7, 0xD7, 0xE5, 0x02, - 0x9E, 0xED, 0xDA, 0xDB, 0x4C, 0x47, 0xCE, 0x91, - 0x06, 0x06, 0x6D, 0x55, 0x8B, 0x19, 0xC9, 0xEF, - 0x8C, 0x80, 0x1A, 0x0E, 0xEE, 0x4B, 0xAB, 0xF2, - 0x08, 0x5C, 0xE9, 0x37, 0x26, 0x5E, 0x9A, 0x90, - 0x00, 0xF3, 0x0D, 0xB2, 0xA6, 0xA3, 0xF7, 0x26, - 0x17, 0x48, 0x88, 0xC9, 0x0E, 0x2C, 0xC9, 0x02, - 0xE7, 0x18, 0x05, 0x4B, 0xF3, 0x39, 0xE1, 0x20, - 0x02, 0x0D, 0x40, 0xC7, 0xCA, 0xB9, 0x48, 0x30, - 0x57, 0x67, 0xCC, 0x06, 0xBF, 0xAC, 0x81, 0x08, - 0x24, 0x7A, 0xD4, 0x8B, 0x19, 0x8E, 0xAC, 0xB4, - 0x5A, 0x0F, 0x73, 0x13, 0xAC, 0x9E, 0xDA, 0xB6, - 0xB8, 0x96, 0x5B, 0x60, 0x88, 0xE1, 0x81, 0x3F, - 0x07, 0x86, 0x37, 0x2D, 0x79, 0x14, 0x52, 0xEA, - 0x73, 0xDF, 0x3D, 0x09, 0xC8, 0x25, 0x48, 0xD8, - 0x75, 0x60, 0x9A, 0x08, 0x27, 0x4A, 0x2C, 0xB9, - 0xA8, 0x8B, 0x8A, 0x73, 0x62, 0x37, 0x16, 0x02, - 0xBD, 0xC1, 0x0E, 0x56, 0x54, 0x3E, 0x14, 0x5F, - 0x8C, 0x8F, 0x6E, 0x75, 0x1C, 0x07, 0x39, 0x7B, - 0x4B, 0xDB, 0xD3, 0x4B, 0x1E, 0xC8, 0x7E, 0xFE, - 0x3E, 0x72, 0x16, 0x83, 0x7D, 0xEE, 0xF5, 0xCA, - 0xC5, 0x18, 0xF9, 0xD8, 0x68, 0xAB, 0x38, 0x85, - 0xA8, 0xF0, 0xA1, 0x73, 0x9F, 0x5D, 0x19, 0x0B, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x33, 0x72, 0x39, 0x25, 0x67, 0x26, 0x6D, 0x71, - 0x36, 0x77, 0x3C, 0x20, 0x62, 0x23, 0x68, 0x74, - 0xC3, 0x82, 0xC9, 0x15, 0x57, 0x16, 0x5D, 0x81 -}; +#include "stdafx.h" + +static void CSSengine(int varient,unsigned char const *input,unsigned char *output); + +void CSSkey1(int varient,unsigned char const *challenge,unsigned char *key) +{ + static unsigned char perm_challenge[] = {1,3,0,7,5, 2,9,6,4,8}; + + unsigned char scratch[10]; + int i; + + for (i = 9; i >= 0; --i) { + scratch[i] = challenge[perm_challenge[i]]; + } + + CSSengine(varient, scratch, key); +} + +void CSSkey2(int varient,unsigned char const *challenge,unsigned char *key) +{ + static unsigned char perm_challenge[] = {6,1,9,3,8, 5,7,4,0,2}; + + static unsigned char perm_varient[] = { + 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d, + 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d, + 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05, + 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 + }; + + unsigned char scratch[10]; + int i; + + for (i = 9; i >= 0; --i) { + scratch[i] = challenge[perm_challenge[i]]; + } + + CSSengine(perm_varient[varient], scratch, key); +} + +void CSSbuskey(int varient,unsigned char const *challenge,unsigned char *key) +{ + static unsigned char perm_challenge[] = {4,0,3,5,7, 2,8,6,1,9}; + static unsigned char perm_varient[] = { + 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e, + 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c, + 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f, + 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d + }; + + unsigned char scratch[10]; + int i; + + for (i = 9; i >= 0; --i) { + scratch[i] = challenge[perm_challenge[i]]; + } + + CSSengine(perm_varient[varient], scratch, key); +} + +static void CSSgenbits(unsigned char *output, int len,unsigned char const *s) +{ + unsigned long lfsr0, lfsr1; + unsigned char b1_combined; /* Save the old value of bit 1 for feedback */ + + /* In order to ensure that the LFSR works we need to ensure that the + * initial values are non-zero. Thus when we initialise them from + * the seed, we ensure that a bit is set. + */ + lfsr0 = (s[0] << 17) | (s[1] << 9) | ((s[2] & ~7) << 1) | 8 | (s[2] & 7); + lfsr1 = (s[3] << 9) | 0x100 | s[4]; + + ++output; + + b1_combined = 0; + do { + int bit; + unsigned char val; + + for (bit = 0, val = 0; bit < 8; ++bit) { + unsigned char o_lfsr0, o_lfsr1; /* Actually only 1 bit each */ + unsigned char combined; + + o_lfsr0 = ((lfsr0 >> 24) ^ (lfsr0 >> 21) ^ (lfsr0 >> 20) ^ (lfsr0 >> 12)) & 1; + lfsr0 = (lfsr0 << 1) | o_lfsr0; + + o_lfsr1 = ((lfsr1 >> 16) ^ (lfsr1 >> 2)) & 1; + lfsr1 = (lfsr1 << 1) | o_lfsr1; + +#define BIT0(x) ((x) & 1) +#define BIT1(x) (((x) >> 1) & 1) + + combined = !o_lfsr1 + b1_combined + !o_lfsr0; + b1_combined = BIT1(combined); + val |= BIT0(combined) << bit; + } + + *--output = val; + } while (--len > 0); +} + +unsigned char CSSsecret[]; +unsigned char CSSvarients[]; +unsigned char CSStable0[]; +unsigned char CSStable1[]; +unsigned char CSStable2[]; +unsigned char CSStable3[]; + +static void CSSengine(int varient, unsigned char const *input,unsigned char *output) +{ + unsigned char cse, term, index; + unsigned char temp1[5]; + unsigned char temp2[5]; + unsigned char bits[30]; + + int i; + + /* Feed the CSSsecret into the input values such that + * we alter the seed to the LFSR's used above, then + * generate the bits to play with. + */ + for (i = 5; --i >= 0; ) { + temp1[i] = input[5 + i] ^ CSSsecret[i] ^ CSStable2[i]; + } + + CSSgenbits(&bits[29], sizeof bits, temp1); + + /* This term is used throughout the following to + * select one of 32 different variations on the + * algorithm. + */ + cse = CSSvarients[varient] ^ CSStable2[varient]; + + /* Now the actual blocks doing the encryption. Each + * of these works on 40 bits at a time and are quite + * similar. + */ + for (i = 5, term = 0; --i >= 0; term = input[i]) { + index = bits[25 + i] ^ input[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + temp1[i] = CSStable2[index] ^ CSStable3[index] ^ term; + } + temp1[4] ^= temp1[0]; + + for (i = 5, term = 0; --i >= 0; term = temp1[i]) { + index = bits[20 + i] ^ temp1[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + temp2[i] = CSStable2[index] ^ CSStable3[index] ^ term; + } + temp2[4] ^= temp2[0]; + + for (i = 5, term = 0; --i >= 0; term = temp2[i]) { + index = bits[15 + i] ^ temp2[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + index = CSStable2[index] ^ CSStable3[index] ^ term; + + temp1[i] = CSStable0[index] ^ CSStable2[index]; + } + temp1[4] ^= temp1[0]; + + for (i = 5, term = 0; --i >= 0; term = temp1[i]) { + index = bits[10 + i] ^ temp1[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + index = CSStable2[index] ^ CSStable3[index] ^ term; + + temp2[i] = CSStable0[index] ^ CSStable2[index]; + } + temp2[4] ^= temp2[0]; + + for (i = 5, term = 0; --i >= 0; term = temp2[i]) { + index = bits[5 + i] ^ temp2[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + temp1[i] = CSStable2[index] ^ CSStable3[index] ^ term; + } + temp1[4] ^= temp1[0]; + + for (i = 5, term = 0; --i >= 0; term = temp1[i]) { + index = bits[i] ^ temp1[i]; + index = CSStable1[index] ^ ~CSStable2[index] ^ cse; + + output[i] = CSStable2[index] ^ CSStable3[index] ^ term; + } +} + +unsigned char CSSvarients[] = { + 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73, + 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42, + 0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B, + 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 +}; + +unsigned char CSSsecret[] = {0x55, 0xD6, 0xC4, 0xC5, 0x28}; + +unsigned char CSStable0[] = { + 0xB7, 0xF4, 0x82, 0x57, 0xDA, 0x4D, 0xDB, 0xE2, + 0x2F, 0x52, 0x1A, 0xA8, 0x68, 0x5A, 0x8A, 0xFF, + 0xFB, 0x0E, 0x6D, 0x35, 0xF7, 0x5C, 0x76, 0x12, + 0xCE, 0x25, 0x79, 0x29, 0x39, 0x62, 0x08, 0x24, + 0xA5, 0x85, 0x7B, 0x56, 0x01, 0x23, 0x68, 0xCF, + 0x0A, 0xE2, 0x5A, 0xED, 0x3D, 0x59, 0xB0, 0xA9, + 0xB0, 0x2C, 0xF2, 0xB8, 0xEF, 0x32, 0xA9, 0x40, + 0x80, 0x71, 0xAF, 0x1E, 0xDE, 0x8F, 0x58, 0x88, + 0xB8, 0x3A, 0xD0, 0xFC, 0xC4, 0x1E, 0xB5, 0xA0, + 0xBB, 0x3B, 0x0F, 0x01, 0x7E, 0x1F, 0x9F, 0xD9, + 0xAA, 0xB8, 0x3D, 0x9D, 0x74, 0x1E, 0x25, 0xDB, + 0x37, 0x56, 0x8F, 0x16, 0xBA, 0x49, 0x2B, 0xAC, + 0xD0, 0xBD, 0x95, 0x20, 0xBE, 0x7A, 0x28, 0xD0, + 0x51, 0x64, 0x63, 0x1C, 0x7F, 0x66, 0x10, 0xBB, + 0xC4, 0x56, 0x1A, 0x04, 0x6E, 0x0A, 0xEC, 0x9C, + 0xD6, 0xE8, 0x9A, 0x7A, 0xCF, 0x8C, 0xDB, 0xB1, + 0xEF, 0x71, 0xDE, 0x31, 0xFF, 0x54, 0x3E, 0x5E, + 0x07, 0x69, 0x96, 0xB0, 0xCF, 0xDD, 0x9E, 0x47, + 0xC7, 0x96, 0x8F, 0xE4, 0x2B, 0x59, 0xC6, 0xEE, + 0xB9, 0x86, 0x9A, 0x64, 0x84, 0x72, 0xE2, 0x5B, + 0xA2, 0x96, 0x58, 0x99, 0x50, 0x03, 0xF5, 0x38, + 0x4D, 0x02, 0x7D, 0xE7, 0x7D, 0x75, 0xA7, 0xB8, + 0x67, 0x87, 0x84, 0x3F, 0x1D, 0x11, 0xE5, 0xFC, + 0x1E, 0xD3, 0x83, 0x16, 0xA5, 0x29, 0xF6, 0xC7, + 0x15, 0x61, 0x29, 0x1A, 0x43, 0x4F, 0x9B, 0xAF, + 0xC5, 0x87, 0x34, 0x6C, 0x0F, 0x3B, 0xA8, 0x1D, + 0x45, 0x58, 0x25, 0xDC, 0xA8, 0xA3, 0x3B, 0xD1, + 0x79, 0x1B, 0x48, 0xF2, 0xE9, 0x93, 0x1F, 0xFC, + 0xDB, 0x2A, 0x90, 0xA9, 0x8A, 0x3D, 0x39, 0x18, + 0xA3, 0x8E, 0x58, 0x6C, 0xE0, 0x12, 0xBB, 0x25, + 0xCD, 0x71, 0x22, 0xA2, 0x64, 0xC6, 0xE7, 0xFB, + 0xAD, 0x94, 0x77, 0x04, 0x9A, 0x39, 0xCF, 0x7C +}; + +unsigned char CSStable1[] = { + 0x8C, 0x47, 0xB0, 0xE1, 0xEB, 0xFC, 0xEB, 0x56, + 0x10, 0xE5, 0x2C, 0x1A, 0x5D, 0xEF, 0xBE, 0x4F, + 0x08, 0x75, 0x97, 0x4B, 0x0E, 0x25, 0x8E, 0x6E, + 0x39, 0x5A, 0x87, 0x53, 0xC4, 0x1F, 0xF4, 0x5C, + 0x4E, 0xE6, 0x99, 0x30, 0xE0, 0x42, 0x88, 0xAB, + 0xE5, 0x85, 0xBC, 0x8F, 0xD8, 0x3C, 0x54, 0xC9, + 0x53, 0x47, 0x18, 0xD6, 0x06, 0x5B, 0x41, 0x2C, + 0x67, 0x1E, 0x41, 0x74, 0x33, 0xE2, 0xB4, 0xE0, + 0x23, 0x29, 0x42, 0xEA, 0x55, 0x0F, 0x25, 0xB4, + 0x24, 0x2C, 0x99, 0x13, 0xEB, 0x0A, 0x0B, 0xC9, + 0xF9, 0x63, 0x67, 0x43, 0x2D, 0xC7, 0x7D, 0x07, + 0x60, 0x89, 0xD1, 0xCC, 0xE7, 0x94, 0x77, 0x74, + 0x9B, 0x7E, 0xD7, 0xE6, 0xFF, 0xBB, 0x68, 0x14, + 0x1E, 0xA3, 0x25, 0xDE, 0x3A, 0xA3, 0x54, 0x7B, + 0x87, 0x9D, 0x50, 0xCA, 0x27, 0xC3, 0xA4, 0x50, + 0x91, 0x27, 0xD4, 0xB0, 0x82, 0x41, 0x97, 0x79, + 0x94, 0x82, 0xAC, 0xC7, 0x8E, 0xA5, 0x4E, 0xAA, + 0x78, 0x9E, 0xE0, 0x42, 0xBA, 0x28, 0xEA, 0xB7, + 0x74, 0xAD, 0x35, 0xDA, 0x92, 0x60, 0x7E, 0xD2, + 0x0E, 0xB9, 0x24, 0x5E, 0x39, 0x4F, 0x5E, 0x63, + 0x09, 0xB5, 0xFA, 0xBF, 0xF1, 0x22, 0x55, 0x1C, + 0xE2, 0x25, 0xDB, 0xC5, 0xD8, 0x50, 0x03, 0x98, + 0xC4, 0xAC, 0x2E, 0x11, 0xB4, 0x38, 0x4D, 0xD0, + 0xB9, 0xFC, 0x2D, 0x3C, 0x08, 0x04, 0x5A, 0xEF, + 0xCE, 0x32, 0xFB, 0x4C, 0x92, 0x1E, 0x4B, 0xFB, + 0x1A, 0xD0, 0xE2, 0x3E, 0xDA, 0x6E, 0x7C, 0x4D, + 0x56, 0xC3, 0x3F, 0x42, 0xB1, 0x3A, 0x23, 0x4D, + 0x6E, 0x84, 0x56, 0x68, 0xF4, 0x0E, 0x03, 0x64, + 0xD0, 0xA9, 0x92, 0x2F, 0x8B, 0xBC, 0x39, 0x9C, + 0xAC, 0x09, 0x5E, 0xEE, 0xE5, 0x97, 0xBF, 0xA5, + 0xCE, 0xFA, 0x28, 0x2C, 0x6D, 0x4F, 0xEF, 0x77, + 0xAA, 0x1B, 0x79, 0x8E, 0x97, 0xB4, 0xC3, 0xF4 +}; + +unsigned char CSStable2[] = { + 0xB7, 0x75, 0x81, 0xD5, 0xDC, 0xCA, 0xDE, 0x66, + 0x23, 0xDF, 0x15, 0x26, 0x62, 0xD1, 0x83, 0x77, + 0xE3, 0x97, 0x76, 0xAF, 0xE9, 0xC3, 0x6B, 0x8E, + 0xDA, 0xB0, 0x6E, 0xBF, 0x2B, 0xF1, 0x19, 0xB4, + 0x95, 0x34, 0x48, 0xE4, 0x37, 0x94, 0x5D, 0x7B, + 0x36, 0x5F, 0x65, 0x53, 0x07, 0xE2, 0x89, 0x11, + 0x98, 0x85, 0xD9, 0x12, 0xC1, 0x9D, 0x84, 0xEC, + 0xA4, 0xD4, 0x88, 0xB8, 0xFC, 0x2C, 0x79, 0x28, + 0xD8, 0xDB, 0xB3, 0x1E, 0xA2, 0xF9, 0xD0, 0x44, + 0xD7, 0xD6, 0x60, 0xEF, 0x14, 0xF4, 0xF6, 0x31, + 0xD2, 0x41, 0x46, 0x67, 0x0A, 0xE1, 0x58, 0x27, + 0x43, 0xA3, 0xF8, 0xE0, 0xC8, 0xBA, 0x5A, 0x5C, + 0x80, 0x6C, 0xC6, 0xF2, 0xE8, 0xAD, 0x7D, 0x04, + 0x0D, 0xB9, 0x3C, 0xC2, 0x25, 0xBD, 0x49, 0x63, + 0x8C, 0x9F, 0x51, 0xCE, 0x20, 0xC5, 0xA1, 0x50, + 0x92, 0x2D, 0xDD, 0xBC, 0x8D, 0x4F, 0x9A, 0x71, + 0x2F, 0x30, 0x1D, 0x73, 0x39, 0x13, 0xFB, 0x1A, + 0xCB, 0x24, 0x59, 0xFE, 0x05, 0x96, 0x57, 0x0F, + 0x1F, 0xCF, 0x54, 0xBE, 0xF5, 0x06, 0x1B, 0xB2, + 0x6D, 0xD3, 0x4D, 0x32, 0x56, 0x21, 0x33, 0x0B, + 0x52, 0xE7, 0xAB, 0xEB, 0xA6, 0x74, 0x00, 0x4C, + 0xB1, 0x7F, 0x82, 0x99, 0x87, 0x0E, 0x5E, 0xC0, + 0x8F, 0xEE, 0x6F, 0x55, 0xF3, 0x7E, 0x08, 0x90, + 0xFA, 0xB6, 0x64, 0x70, 0x47, 0x4A, 0x17, 0xA7, + 0xB5, 0x40, 0x8A, 0x38, 0xE5, 0x68, 0x3E, 0x8B, + 0x69, 0xAA, 0x9B, 0x42, 0xA5, 0x10, 0x01, 0x35, + 0xFD, 0x61, 0x9E, 0xE6, 0x16, 0x9C, 0x86, 0xED, + 0xCD, 0x2E, 0xFF, 0xC4, 0x5B, 0xA0, 0xAE, 0xCC, + 0x4B, 0x3B, 0x03, 0xBB, 0x1C, 0x2A, 0xAC, 0x0C, + 0x3F, 0x93, 0xC7, 0x72, 0x7A, 0x09, 0x22, 0x3D, + 0x45, 0x78, 0xA9, 0xA8, 0xEA, 0xC9, 0x6A, 0xF7, + 0x29, 0x91, 0xF0, 0x02, 0x18, 0x3A, 0x4E, 0x7C +}; + +unsigned char CSStable3[] = { + 0x73, 0x51, 0x95, 0xE1, 0x12, 0xE4, 0xC0, 0x58, + 0xEE, 0xF2, 0x08, 0x1B, 0xA9, 0xFA, 0x98, 0x4C, + 0xA7, 0x33, 0xE2, 0x1B, 0xA7, 0x6D, 0xF5, 0x30, + 0x97, 0x1D, 0xF3, 0x02, 0x60, 0x5A, 0x82, 0x0F, + 0x91, 0xD0, 0x9C, 0x10, 0x39, 0x7A, 0x83, 0x85, + 0x3B, 0xB2, 0xB8, 0xAE, 0x0C, 0x09, 0x52, 0xEA, + 0x1C, 0xE1, 0x8D, 0x66, 0x4F, 0xF3, 0xDA, 0x92, + 0x29, 0xB9, 0xD5, 0xC5, 0x77, 0x47, 0x22, 0x53, + 0x14, 0xF7, 0xAF, 0x22, 0x64, 0xDF, 0xC6, 0x72, + 0x12, 0xF3, 0x75, 0xDA, 0xD7, 0xD7, 0xE5, 0x02, + 0x9E, 0xED, 0xDA, 0xDB, 0x4C, 0x47, 0xCE, 0x91, + 0x06, 0x06, 0x6D, 0x55, 0x8B, 0x19, 0xC9, 0xEF, + 0x8C, 0x80, 0x1A, 0x0E, 0xEE, 0x4B, 0xAB, 0xF2, + 0x08, 0x5C, 0xE9, 0x37, 0x26, 0x5E, 0x9A, 0x90, + 0x00, 0xF3, 0x0D, 0xB2, 0xA6, 0xA3, 0xF7, 0x26, + 0x17, 0x48, 0x88, 0xC9, 0x0E, 0x2C, 0xC9, 0x02, + 0xE7, 0x18, 0x05, 0x4B, 0xF3, 0x39, 0xE1, 0x20, + 0x02, 0x0D, 0x40, 0xC7, 0xCA, 0xB9, 0x48, 0x30, + 0x57, 0x67, 0xCC, 0x06, 0xBF, 0xAC, 0x81, 0x08, + 0x24, 0x7A, 0xD4, 0x8B, 0x19, 0x8E, 0xAC, 0xB4, + 0x5A, 0x0F, 0x73, 0x13, 0xAC, 0x9E, 0xDA, 0xB6, + 0xB8, 0x96, 0x5B, 0x60, 0x88, 0xE1, 0x81, 0x3F, + 0x07, 0x86, 0x37, 0x2D, 0x79, 0x14, 0x52, 0xEA, + 0x73, 0xDF, 0x3D, 0x09, 0xC8, 0x25, 0x48, 0xD8, + 0x75, 0x60, 0x9A, 0x08, 0x27, 0x4A, 0x2C, 0xB9, + 0xA8, 0x8B, 0x8A, 0x73, 0x62, 0x37, 0x16, 0x02, + 0xBD, 0xC1, 0x0E, 0x56, 0x54, 0x3E, 0x14, 0x5F, + 0x8C, 0x8F, 0x6E, 0x75, 0x1C, 0x07, 0x39, 0x7B, + 0x4B, 0xDB, 0xD3, 0x4B, 0x1E, 0xC8, 0x7E, 0xFE, + 0x3E, 0x72, 0x16, 0x83, 0x7D, 0xEE, 0xF5, 0xCA, + 0xC5, 0x18, 0xF9, 0xD8, 0x68, 0xAB, 0x38, 0x85, + 0xA8, 0xF0, 0xA1, 0x73, 0x9F, 0x5D, 0x19, 0x0B, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x72, 0x39, 0x25, 0x67, 0x26, 0x6D, 0x71, + 0x36, 0x77, 0x3C, 0x20, 0x62, 0x23, 0x68, 0x74, + 0xC3, 0x82, 0xC9, 0x15, 0x57, 0x16, 0x5D, 0x81 +}; diff --git a/src/DeCSS/CSSauth.h b/src/DeCSS/CSSauth.h index ee2950cdf09..9929ae887d7 100644 --- a/src/DeCSS/CSSauth.h +++ b/src/DeCSS/CSSauth.h @@ -1,5 +1,5 @@ -#pragma once - -extern void CSSkey1(int varient, byte const *challenge, byte *key); -extern void CSSkey2(int varient, byte const *challenge, byte *key); -extern void CSSbuskey(int varient, byte const *challenge, byte *key); +#pragma once + +extern void CSSkey1(int varient, byte const *challenge, byte *key); +extern void CSSkey2(int varient, byte const *challenge, byte *key); +extern void CSSbuskey(int varient, byte const *challenge, byte *key); diff --git a/src/DeCSS/CSSscramble.cpp b/src/DeCSS/CSSscramble.cpp index 43b6c3323ab..902c99f4fd8 100644 --- a/src/DeCSS/CSSscramble.cpp +++ b/src/DeCSS/CSSscramble.cpp @@ -1,236 +1,236 @@ -#include "stdafx.h" - -static const unsigned int CSStab0[11]= {5,0,1,2,3,4,0,1,2,3,4}; - -static const unsigned char CSStab1[256]= { - 0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b, - 0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b, - 0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f, - 0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91, - 0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75, - 0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95, - 0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11, - 0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f, - 0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b, - 0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb, - 0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f, - 0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1, - 0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15, - 0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5, - 0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71, - 0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff -}; - -static const unsigned char CSStab2[256]= { - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, - 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, - 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, - 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, - 0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, - 0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55, - 0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63, - 0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71, - 0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c, - 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e, - 0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8, - 0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa, - 0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5, - 0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, - 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1, - 0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3 -}; - -static const unsigned char CSStab3[512]= { - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, - 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff -}; - -static const unsigned char CSStab4[256]= { - 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, - 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, - 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, - 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, - 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, - 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, - 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, - 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, - 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, - 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, - 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, - 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, - 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, - 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, - 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, - 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff -}; - -static const unsigned char CSStab5[256]= { - 0xff,0x7f,0xbf,0x3f,0xdf,0x5f,0x9f,0x1f,0xef,0x6f,0xaf,0x2f,0xcf,0x4f,0x8f,0x0f, - 0xf7,0x77,0xb7,0x37,0xd7,0x57,0x97,0x17,0xe7,0x67,0xa7,0x27,0xc7,0x47,0x87,0x07, - 0xfb,0x7b,0xbb,0x3b,0xdb,0x5b,0x9b,0x1b,0xeb,0x6b,0xab,0x2b,0xcb,0x4b,0x8b,0x0b, - 0xf3,0x73,0xb3,0x33,0xd3,0x53,0x93,0x13,0xe3,0x63,0xa3,0x23,0xc3,0x43,0x83,0x03, - 0xfd,0x7d,0xbd,0x3d,0xdd,0x5d,0x9d,0x1d,0xed,0x6d,0xad,0x2d,0xcd,0x4d,0x8d,0x0d, - 0xf5,0x75,0xb5,0x35,0xd5,0x55,0x95,0x15,0xe5,0x65,0xa5,0x25,0xc5,0x45,0x85,0x05, - 0xf9,0x79,0xb9,0x39,0xd9,0x59,0x99,0x19,0xe9,0x69,0xa9,0x29,0xc9,0x49,0x89,0x09, - 0xf1,0x71,0xb1,0x31,0xd1,0x51,0x91,0x11,0xe1,0x61,0xa1,0x21,0xc1,0x41,0x81,0x01, - 0xfe,0x7e,0xbe,0x3e,0xde,0x5e,0x9e,0x1e,0xee,0x6e,0xae,0x2e,0xce,0x4e,0x8e,0x0e, - 0xf6,0x76,0xb6,0x36,0xd6,0x56,0x96,0x16,0xe6,0x66,0xa6,0x26,0xc6,0x46,0x86,0x06, - 0xfa,0x7a,0xba,0x3a,0xda,0x5a,0x9a,0x1a,0xea,0x6a,0xaa,0x2a,0xca,0x4a,0x8a,0x0a, - 0xf2,0x72,0xb2,0x32,0xd2,0x52,0x92,0x12,0xe2,0x62,0xa2,0x22,0xc2,0x42,0x82,0x02, - 0xfc,0x7c,0xbc,0x3c,0xdc,0x5c,0x9c,0x1c,0xec,0x6c,0xac,0x2c,0xcc,0x4c,0x8c,0x0c, - 0xf4,0x74,0xb4,0x34,0xd4,0x54,0x94,0x14,0xe4,0x64,0xa4,0x24,0xc4,0x44,0x84,0x04, - 0xf8,0x78,0xb8,0x38,0xd8,0x58,0x98,0x18,0xe8,0x68,0xa8,0x28,0xc8,0x48,0x88,0x08, - 0xf0,0x70,0xb0,0x30,0xd0,0x50,0x90,0x10,0xe0,0x60,0xa0,0x20,0xc0,0x40,0x80,0x00 -}; - -void CSSdescramble(unsigned char *sec,const unsigned char *tkey) -{ - unsigned int t1,t2,t3,t4,t5,t6; - unsigned char *end=sec+0x800; - - t1=tkey[0]^sec[0x54]|0x100; - t2=tkey[1]^sec[0x55]; - t3=(*((unsigned int *)(tkey+2)))^(*((unsigned int *)(sec+0x56))); - t4=t3&7; - t3=t3*2+8-t4; - sec+=0x80; - t5=0; - while(sec!=end) { - t4=CSStab2[t2]^CSStab3[t1]; - t2=t1>>1; - t1=((t1&1)<<8)^t4; - t4=CSStab5[t4]; - t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; - t3=(t3<<8)|t6; - t6=CSStab4[t6]; - t5+=t6+t4; - *sec++=CSStab1[*sec]^(t5&0xff); - t5>>=8; - } -} - -void CSSdisckey(unsigned char *dkey,const unsigned char *pkey) -{ - unsigned int t1,t2,t3,t4,t5,t6; - unsigned char k[5]; - int i; - - t1=pkey[0]|0x100; - t2=pkey[1]; - t3=*((unsigned int *)(pkey+2)); - t4=t3&7; - t3=t3*2+8-t4; - t5=0; - for(i=0; i<5; i++) { - t4=CSStab2[t2]^CSStab3[t1]; - t2=t1>>1; - t1=((t1&1)<<8)^t4; - t4=CSStab4[t4]; - t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; - t3=(t3<<8)|t6; - t6=CSStab4[t6]; - t5+=t6+t4; - k[i]=t5&0xff; - t5>>=8; - } - for(i=9; i>=0; i--) { - dkey[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[dkey[CSStab0[i+1]]]^dkey[CSStab0[i]]; - } -} - -void CSStitlekey(unsigned char *tkey,const unsigned char *dkey) -{ - unsigned int t1,t2,t3,t4,t5,t6; - unsigned char k[5]; - int i; - - t1=dkey[0]|0x100; - t2=dkey[1]; - t3=*((unsigned int *)(dkey+2)); - t4=t3&7; - t3=t3*2+8-t4; - t5=0; - for(i=0; i<5; i++) { - t4=CSStab2[t2]^CSStab3[t1]; - t2=t1>>1; - t1=((t1&1)<<8)^t4; - t4=CSStab4[t4]; - t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; - t3=(t3<<8)|t6; - t6=CSStab5[t6]; - t5+=t6+t4; - k[i]=t5&0xff; - t5>>=8; - } - for(i=9; i>=0; i--) { - tkey[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[tkey[CSStab0[i+1]]]^tkey[CSStab0[i]]; - } -} - -extern const unsigned char g_PlayerKeys[][6] = { - // from mplayer: - {0x01, 0xaf, 0xe3, 0x12, 0x80}, - {0x12, 0x11, 0xca, 0x04, 0x3b}, - {0x14, 0x0c, 0x9e, 0xd0, 0x09}, - {0x14, 0x71, 0x35, 0xba, 0xe2}, - {0x1a, 0xa4, 0x33, 0x21, 0xa6}, - {0x26, 0xec, 0xc4, 0xa7, 0x4e}, - {0x2c, 0xb2, 0xc1, 0x09, 0xee}, - {0x2f, 0x25, 0x9e, 0x96, 0xdd}, - {0x33, 0x2f, 0x49, 0x6c, 0xe0}, - {0x35, 0x5b, 0xc1, 0x31, 0x0f}, - {0x36, 0x67, 0xb2, 0xe3, 0x85}, - {0x39, 0x3d, 0xf1, 0xf1, 0xbd}, - {0x3b, 0x31, 0x34, 0x0d, 0x91}, - {0x45, 0xed, 0x28, 0xeb, 0xd3}, - {0x48, 0xb7, 0x6c, 0xce, 0x69}, - {0x4b, 0x65, 0x0d, 0xc1, 0xee}, - {0x4c, 0xbb, 0xf5, 0x5b, 0x23}, - {0x51, 0x67, 0x67, 0xc5, 0xe0}, - {0x53, 0x94, 0xe1, 0x75, 0xbf}, - {0x57, 0x2c, 0x8b, 0x31, 0xae}, - {0x63, 0xdb, 0x4c, 0x5b, 0x4a}, - {0x7b, 0x1e, 0x5e, 0x2b, 0x57}, - {0x85, 0xf3, 0x85, 0xa0, 0xe0}, - {0xab, 0x1e, 0xe7, 0x7b, 0x72}, - {0xab, 0x36, 0xe3, 0xeb, 0x76}, - {0xb1, 0xb8, 0xf9, 0x38, 0x03}, - {0xb8, 0x5d, 0xd8, 0x53, 0xbd}, - {0xbf, 0x92, 0xc3, 0xb0, 0xe2}, - {0xcf, 0x1a, 0xb2, 0xf8, 0x0a}, - {0xec, 0xa0, 0xcf, 0xb3, 0xff}, - {0xfc, 0x95, 0xa9, 0x87, 0x35} - // TODO: find more player keys -}; - -extern const int g_nPlayerKeys = _countof(g_PlayerKeys); +#include "stdafx.h" + +static const unsigned int CSStab0[11]= {5,0,1,2,3,4,0,1,2,3,4}; + +static const unsigned char CSStab1[256]= { + 0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b, + 0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b, + 0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f, + 0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91, + 0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75, + 0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95, + 0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11, + 0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f, + 0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b, + 0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb, + 0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f, + 0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1, + 0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15, + 0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5, + 0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71, + 0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff +}; + +static const unsigned char CSStab2[256]= { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, + 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, + 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, + 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, + 0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55, + 0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63, + 0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71, + 0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c, + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e, + 0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8, + 0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa, + 0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5, + 0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, + 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1, + 0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3 +}; + +static const unsigned char CSStab3[512]= { + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, + 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff +}; + +static const unsigned char CSStab4[256]= { + 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, + 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, + 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, + 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, + 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, + 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, + 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, + 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, + 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, + 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, + 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, + 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, + 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, + 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, + 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, + 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +}; + +static const unsigned char CSStab5[256]= { + 0xff,0x7f,0xbf,0x3f,0xdf,0x5f,0x9f,0x1f,0xef,0x6f,0xaf,0x2f,0xcf,0x4f,0x8f,0x0f, + 0xf7,0x77,0xb7,0x37,0xd7,0x57,0x97,0x17,0xe7,0x67,0xa7,0x27,0xc7,0x47,0x87,0x07, + 0xfb,0x7b,0xbb,0x3b,0xdb,0x5b,0x9b,0x1b,0xeb,0x6b,0xab,0x2b,0xcb,0x4b,0x8b,0x0b, + 0xf3,0x73,0xb3,0x33,0xd3,0x53,0x93,0x13,0xe3,0x63,0xa3,0x23,0xc3,0x43,0x83,0x03, + 0xfd,0x7d,0xbd,0x3d,0xdd,0x5d,0x9d,0x1d,0xed,0x6d,0xad,0x2d,0xcd,0x4d,0x8d,0x0d, + 0xf5,0x75,0xb5,0x35,0xd5,0x55,0x95,0x15,0xe5,0x65,0xa5,0x25,0xc5,0x45,0x85,0x05, + 0xf9,0x79,0xb9,0x39,0xd9,0x59,0x99,0x19,0xe9,0x69,0xa9,0x29,0xc9,0x49,0x89,0x09, + 0xf1,0x71,0xb1,0x31,0xd1,0x51,0x91,0x11,0xe1,0x61,0xa1,0x21,0xc1,0x41,0x81,0x01, + 0xfe,0x7e,0xbe,0x3e,0xde,0x5e,0x9e,0x1e,0xee,0x6e,0xae,0x2e,0xce,0x4e,0x8e,0x0e, + 0xf6,0x76,0xb6,0x36,0xd6,0x56,0x96,0x16,0xe6,0x66,0xa6,0x26,0xc6,0x46,0x86,0x06, + 0xfa,0x7a,0xba,0x3a,0xda,0x5a,0x9a,0x1a,0xea,0x6a,0xaa,0x2a,0xca,0x4a,0x8a,0x0a, + 0xf2,0x72,0xb2,0x32,0xd2,0x52,0x92,0x12,0xe2,0x62,0xa2,0x22,0xc2,0x42,0x82,0x02, + 0xfc,0x7c,0xbc,0x3c,0xdc,0x5c,0x9c,0x1c,0xec,0x6c,0xac,0x2c,0xcc,0x4c,0x8c,0x0c, + 0xf4,0x74,0xb4,0x34,0xd4,0x54,0x94,0x14,0xe4,0x64,0xa4,0x24,0xc4,0x44,0x84,0x04, + 0xf8,0x78,0xb8,0x38,0xd8,0x58,0x98,0x18,0xe8,0x68,0xa8,0x28,0xc8,0x48,0x88,0x08, + 0xf0,0x70,0xb0,0x30,0xd0,0x50,0x90,0x10,0xe0,0x60,0xa0,0x20,0xc0,0x40,0x80,0x00 +}; + +void CSSdescramble(unsigned char *sec,const unsigned char *tkey) +{ + unsigned int t1,t2,t3,t4,t5,t6; + unsigned char *end=sec+0x800; + + t1=tkey[0]^sec[0x54]|0x100; + t2=tkey[1]^sec[0x55]; + t3=(*((unsigned int *)(tkey+2)))^(*((unsigned int *)(sec+0x56))); + t4=t3&7; + t3=t3*2+8-t4; + sec+=0x80; + t5=0; + while(sec!=end) { + t4=CSStab2[t2]^CSStab3[t1]; + t2=t1>>1; + t1=((t1&1)<<8)^t4; + t4=CSStab5[t4]; + t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; + t3=(t3<<8)|t6; + t6=CSStab4[t6]; + t5+=t6+t4; + *sec++=CSStab1[*sec]^(t5&0xff); + t5>>=8; + } +} + +void CSSdisckey(unsigned char *dkey,const unsigned char *pkey) +{ + unsigned int t1,t2,t3,t4,t5,t6; + unsigned char k[5]; + int i; + + t1=pkey[0]|0x100; + t2=pkey[1]; + t3=*((unsigned int *)(pkey+2)); + t4=t3&7; + t3=t3*2+8-t4; + t5=0; + for(i=0; i<5; i++) { + t4=CSStab2[t2]^CSStab3[t1]; + t2=t1>>1; + t1=((t1&1)<<8)^t4; + t4=CSStab4[t4]; + t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; + t3=(t3<<8)|t6; + t6=CSStab4[t6]; + t5+=t6+t4; + k[i]=t5&0xff; + t5>>=8; + } + for(i=9; i>=0; i--) { + dkey[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[dkey[CSStab0[i+1]]]^dkey[CSStab0[i]]; + } +} + +void CSStitlekey(unsigned char *tkey,const unsigned char *dkey) +{ + unsigned int t1,t2,t3,t4,t5,t6; + unsigned char k[5]; + int i; + + t1=dkey[0]|0x100; + t2=dkey[1]; + t3=*((unsigned int *)(dkey+2)); + t4=t3&7; + t3=t3*2+8-t4; + t5=0; + for(i=0; i<5; i++) { + t4=CSStab2[t2]^CSStab3[t1]; + t2=t1>>1; + t1=((t1&1)<<8)^t4; + t4=CSStab4[t4]; + t6=(((((((t3>>3)^t3)>>1)^t3)>>8)^t3)>>5)&0xff; + t3=(t3<<8)|t6; + t6=CSStab5[t6]; + t5+=t6+t4; + k[i]=t5&0xff; + t5>>=8; + } + for(i=9; i>=0; i--) { + tkey[CSStab0[i+1]]=k[CSStab0[i+1]]^CSStab1[tkey[CSStab0[i+1]]]^tkey[CSStab0[i]]; + } +} + +extern const unsigned char g_PlayerKeys[][6] = { + // from mplayer: + {0x01, 0xaf, 0xe3, 0x12, 0x80}, + {0x12, 0x11, 0xca, 0x04, 0x3b}, + {0x14, 0x0c, 0x9e, 0xd0, 0x09}, + {0x14, 0x71, 0x35, 0xba, 0xe2}, + {0x1a, 0xa4, 0x33, 0x21, 0xa6}, + {0x26, 0xec, 0xc4, 0xa7, 0x4e}, + {0x2c, 0xb2, 0xc1, 0x09, 0xee}, + {0x2f, 0x25, 0x9e, 0x96, 0xdd}, + {0x33, 0x2f, 0x49, 0x6c, 0xe0}, + {0x35, 0x5b, 0xc1, 0x31, 0x0f}, + {0x36, 0x67, 0xb2, 0xe3, 0x85}, + {0x39, 0x3d, 0xf1, 0xf1, 0xbd}, + {0x3b, 0x31, 0x34, 0x0d, 0x91}, + {0x45, 0xed, 0x28, 0xeb, 0xd3}, + {0x48, 0xb7, 0x6c, 0xce, 0x69}, + {0x4b, 0x65, 0x0d, 0xc1, 0xee}, + {0x4c, 0xbb, 0xf5, 0x5b, 0x23}, + {0x51, 0x67, 0x67, 0xc5, 0xe0}, + {0x53, 0x94, 0xe1, 0x75, 0xbf}, + {0x57, 0x2c, 0x8b, 0x31, 0xae}, + {0x63, 0xdb, 0x4c, 0x5b, 0x4a}, + {0x7b, 0x1e, 0x5e, 0x2b, 0x57}, + {0x85, 0xf3, 0x85, 0xa0, 0xe0}, + {0xab, 0x1e, 0xe7, 0x7b, 0x72}, + {0xab, 0x36, 0xe3, 0xeb, 0x76}, + {0xb1, 0xb8, 0xf9, 0x38, 0x03}, + {0xb8, 0x5d, 0xd8, 0x53, 0xbd}, + {0xbf, 0x92, 0xc3, 0xb0, 0xe2}, + {0xcf, 0x1a, 0xb2, 0xf8, 0x0a}, + {0xec, 0xa0, 0xcf, 0xb3, 0xff}, + {0xfc, 0x95, 0xa9, 0x87, 0x35} + // TODO: find more player keys +}; + +extern const int g_nPlayerKeys = _countof(g_PlayerKeys); diff --git a/src/DeCSS/CSSscramble.h b/src/DeCSS/CSSscramble.h index 09a7ab620b4..6ca6ebd305f 100644 --- a/src/DeCSS/CSSscramble.h +++ b/src/DeCSS/CSSscramble.h @@ -1,8 +1,8 @@ -#pragma once - -extern void CSSdisckey(unsigned char *dkey,const unsigned char *pkey); -extern void CSStitlekey(unsigned char *tkey,const unsigned char *dkey); -extern void CSSdescramble(unsigned char *sector,const unsigned char *tkey); - -extern const unsigned char g_PlayerKeys[][6]; -extern const int g_nPlayerKeys; +#pragma once + +extern void CSSdisckey(unsigned char *dkey,const unsigned char *pkey); +extern void CSStitlekey(unsigned char *tkey,const unsigned char *dkey); +extern void CSSdescramble(unsigned char *sector,const unsigned char *tkey); + +extern const unsigned char g_PlayerKeys[][6]; +extern const int g_nPlayerKeys; diff --git a/src/DeCSS/DeCSS.vcxproj b/src/DeCSS/DeCSS.vcxproj index 7bc50aeff5d..d13569ecce2 100644 --- a/src/DeCSS/DeCSS.vcxproj +++ b/src/DeCSS/DeCSS.vcxproj @@ -1,71 +1,71 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {1A2DFD1A-3C6C-44D1-909D-294AF646B575} - DeCSS - MFCProj - DeCSS - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\include;..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - Create - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {1A2DFD1A-3C6C-44D1-909D-294AF646B575} + DeCSS + MFCProj + DeCSS + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\include;..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + Create + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/DeCSS/DeCSS.vcxproj.filters b/src/DeCSS/DeCSS.vcxproj.filters index 7f9579f4877..101c20ecd05 100644 --- a/src/DeCSS/DeCSS.vcxproj.filters +++ b/src/DeCSS/DeCSS.vcxproj.filters @@ -1,62 +1,62 @@ - - - - - {ad1b8b81-9c26-4439-a44f-daa5cc1dce41} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {b38c1e37-5430-46a1-a691-f642a1ec480e} - h;hpp;hxx;hm;inl;inc - - - {1f95dfa7-830f-4db4-8a34-f58af7ec4315} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - vstrip - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - vstrip - - + + + + + {ad1b8b81-9c26-4439-a44f-daa5cc1dce41} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {b38c1e37-5430-46a1-a691-f642a1ec480e} + h;hpp;hxx;hm;inl;inc + + + {1f95dfa7-830f-4db4-8a34-f58af7ec4315} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + vstrip + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + vstrip + + \ No newline at end of file diff --git a/src/DeCSS/DeCSSInputPin.cpp b/src/DeCSS/DeCSSInputPin.cpp index 4ded58b95b7..96572e76221 100644 --- a/src/DeCSS/DeCSSInputPin.cpp +++ b/src/DeCSS/DeCSSInputPin.cpp @@ -1,361 +1,361 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "BaseClasses/streams.h" -#include -#include -#include -#include "DeCSSInputPin.h" -#include "../DSUtil/DSUtil.h" -#include "CSSauth.h" -#include "CSSscramble.h" - -#include "moreuuids.h" - -// -// CDeCSSInputPin -// - -CDeCSSInputPin::CDeCSSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName) - : CTransformInputPin(pObjectName, pFilter, phr, pName) - , m_varient(-1) -{ - ZeroMemory(m_Challenge, sizeof(m_Challenge)); - ZeroMemory(m_KeyCheck, sizeof(m_KeyCheck)); - ZeroMemory(m_Key, sizeof(m_Key)); - ZeroMemory(m_DiscKey, sizeof(m_DiscKey)); - ZeroMemory(m_TitleKey, sizeof(m_TitleKey)); -} - -STDMETHODIMP CDeCSSInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IKsPropertySet) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IMemInputPin - -STDMETHODIMP CDeCSSInputPin::Receive(IMediaSample* pSample) -{ - long len = pSample->GetActualDataLength(); - - BYTE* p = nullptr; - if (SUCCEEDED(pSample->GetPointer(&p)) && len > 0) { - if (m_mt.majortype == MEDIATYPE_DVD_ENCRYPTED_PACK && len == 2048 && (p[0x14] & 0x30)) { - CSSdescramble(p, m_TitleKey); - p[0x14] &= ~0x30; - - if (CComQIPtr pMS2 = pSample) { - AM_SAMPLE2_PROPERTIES props; - ZeroMemory(&props, sizeof(props)); - if (SUCCEEDED(pMS2->GetProperties(sizeof(props), (BYTE*)&props)) - && (props.dwTypeSpecificFlags & AM_UseNewCSSKey)) { - props.dwTypeSpecificFlags &= ~AM_UseNewCSSKey; - pMS2->SetProperties(sizeof(props), (BYTE*)&props); - } - } - } - } - - HRESULT hr = Transform(pSample); - - return hr == S_OK ? __super::Receive(pSample) : - hr == S_FALSE ? S_OK : hr; -} - -void CDeCSSInputPin::StripPacket(BYTE*& p, long& len) -{ - GUID majortype = m_mt.majortype; - - if (majortype == MEDIATYPE_MPEG2_PACK || majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { - if (len > 0 && *(DWORD*)p == 0xba010000) { // MEDIATYPE_*_PACK - len -= 14; - p += 14; - if (int stuffing = (p[-1] & 7)) { - len -= stuffing; - p += stuffing; - } - majortype = MEDIATYPE_MPEG2_PES; - } - } - - if (majortype == MEDIATYPE_MPEG2_PES) { - if (len > 0 && *(DWORD*)p == 0xbb010000) { - len -= 4; - p += 4; - int hdrlen = ((p[0] << 8) | p[1]) + 2; - len -= hdrlen; - p += hdrlen; - } - - if (len > 0 - && ((*(DWORD*)p & 0xf0ffffff) == 0xe0010000 - || (*(DWORD*)p & 0xe0ffffff) == 0xc0010000 - || (*(DWORD*)p & 0xbdffffff) == 0xbd010000)) { // PES - bool ps1 = (*(DWORD*)p & 0xbdffffff) == 0xbd010000; - - len -= 4; - p += 4; - long expected = ((p[0] << 8) | p[1]); - len -= 2; - p += 2; - BYTE* p0 = p; - - for (int i = 0; i < 16 && *p == 0xff; i++, len--, p++) { - ; - } - - if ((*p & 0xc0) == 0x80) { // mpeg2 - len -= 2; - p += 2; - len -= *p + 1; - p += *p + 1; - } else { // mpeg1 - if ((*p & 0xc0) == 0x40) { - len -= 2; - p += 2; - } - - if ((*p & 0x30) == 0x30 || (*p & 0x30) == 0x20) { - bool pts = !!(*p & 0x20), dts = !!(*p & 0x10); - if (pts) { - len -= 5; - } - p += 5; - if (dts) { - ASSERT((*p & 0xf0) == 0x10); - len -= 5; - p += 5; - } - } else { - len--; - p++; - } - } - - if (ps1) { - len--; - p++; - if (m_mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { - len -= 6; - p += 6; - } else if (m_mt.subtype == MEDIASUBTYPE_DOLBY_AC3 || m_mt.subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 - || m_mt.subtype == MEDIASUBTYPE_DTS || m_mt.subtype == MEDIASUBTYPE_WAVE_DTS) { - len -= 3; - p += 3; - } - } - - if (expected > 0) { - expected -= (long)(p - p0); - len = std::min(expected, len); - } - } - } - - if (len < 0) { - ASSERT(0); - len = 0; - } -} - -// IKsPropertySet - -STDMETHODIMP CDeCSSInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength) -{ - if (PropSet != AM_KSPROPSETID_CopyProt) { - return E_NOTIMPL; - } - - switch (Id) { - case AM_PROPERTY_COPY_MACROVISION: - break; - case AM_PROPERTY_DVDCOPY_CHLG_KEY: { // 3. auth: receive drive nonce word, also store and encrypt the buskey made up of the two nonce words - AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData; - for (int i = 0; i < 10; i++) { - m_Challenge[i] = pChlgKey->ChlgKey[9 - i]; - } - - CSSkey2(m_varient, m_Challenge, &m_Key[5]); - - CSSbuskey(m_varient, m_Key, m_KeyCheck); - } - break; - case AM_PROPERTY_DVDCOPY_DISC_KEY: { // 5. receive the disckey - AM_DVDCOPY_DISCKEY* pDiscKey = (AM_DVDCOPY_DISCKEY*)pPropertyData; // pDiscKey->DiscKey holds the disckey encrypted with itself and the 408 disckeys encrypted with the playerkeys - - bool fSuccess = false; - - for (int j = 0; j < g_nPlayerKeys; j++) { - for (int k = 1; k < 409; k++) { - BYTE DiscKey[6]; - for (int i = 0; i < 5; i++) { - DiscKey[i] = pDiscKey->DiscKey[k * 5 + i] ^ m_KeyCheck[4 - i]; - } - DiscKey[5] = 0; - - CSSdisckey(DiscKey, g_PlayerKeys[j]); - - BYTE Hash[6]; - for (int i = 0; i < 5; i++) { - Hash[i] = pDiscKey->DiscKey[i] ^ m_KeyCheck[4 - i]; - } - Hash[5] = 0; - - CSSdisckey(Hash, DiscKey); - - if (!memcmp(Hash, DiscKey, 6)) { - memcpy(m_DiscKey, DiscKey, 6); - j = g_nPlayerKeys; - fSuccess = true; - break; - } - } - } - - if (!fSuccess) { - return E_FAIL; - } - } - break; - case AM_PROPERTY_DVDCOPY_DVD_KEY1: { // 2. auth: receive our drive-encrypted nonce word and decrypt it for verification - AM_DVDCOPY_BUSKEY* pKey1 = (AM_DVDCOPY_BUSKEY*)pPropertyData; - for (int i = 0; i < 5; i++) { - m_Key[i] = pKey1->BusKey[4 - i]; - } - - m_varient = -1; - - for (int i = 31; i >= 0; i--) { - CSSkey1(i, m_Challenge, m_KeyCheck); - - if (memcmp(m_KeyCheck, &m_Key[0], 5) == 0) { - m_varient = i; - } - } - } - break; - case AM_PROPERTY_DVDCOPY_REGION: - break; - case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: - break; - case AM_PROPERTY_DVDCOPY_TITLE_KEY: { // 6. receive the title key and decrypt it with the disc key - AM_DVDCOPY_TITLEKEY* pTitleKey = (AM_DVDCOPY_TITLEKEY*)pPropertyData; - for (int i = 0; i < 5; i++) { - m_TitleKey[i] = pTitleKey->TitleKey[i] ^ m_KeyCheck[4 - i]; - } - m_TitleKey[5] = 0; - CSStitlekey(m_TitleKey, m_DiscKey); - } - break; - default: - return E_PROP_ID_UNSUPPORTED; - } - - return S_OK; -} - -STDMETHODIMP CDeCSSInputPin::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned) -{ - if (PropSet != AM_KSPROPSETID_CopyProt) { - return E_NOTIMPL; - } - - switch (Id) { - case AM_PROPERTY_DVDCOPY_CHLG_KEY: { // 1. auth: send our nonce word - AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData; - for (BYTE i = 0; i < 10; i++) { - pChlgKey->ChlgKey[i] = 9 - (m_Challenge[i] = i); - } - *pBytesReturned = sizeof(AM_DVDCOPY_CHLGKEY); - } - break; - case AM_PROPERTY_DVDCOPY_DEC_KEY2: { // 4. auth: send back the encrypted drive nonce word to finish the authentication - AM_DVDCOPY_BUSKEY* pKey2 = (AM_DVDCOPY_BUSKEY*)pPropertyData; - for (int i = 0; i < 5; i++) { - pKey2->BusKey[4 - i] = m_Key[5 + i]; - } - *pBytesReturned = sizeof(AM_DVDCOPY_BUSKEY); - } - break; - case AM_PROPERTY_DVDCOPY_REGION: { - DVD_REGION* pRegion = (DVD_REGION*)pPropertyData; - pRegion->RegionData = 0; - pRegion->SystemRegion = 0; - *pBytesReturned = sizeof(DVD_REGION); - } - break; - case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: { - AM_DVDCOPY_SET_COPY_STATE* pState = (AM_DVDCOPY_SET_COPY_STATE*)pPropertyData; - pState->DVDCopyState = AM_DVDCOPYSTATE_AUTHENTICATION_REQUIRED; - *pBytesReturned = sizeof(AM_DVDCOPY_SET_COPY_STATE); - } - break; - default: - return E_PROP_ID_UNSUPPORTED; - } - - return S_OK; -} - -STDMETHODIMP CDeCSSInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) -{ - if (PropSet != AM_KSPROPSETID_CopyProt) { - return E_NOTIMPL; - } - - switch (Id) { - case AM_PROPERTY_COPY_MACROVISION: - *pTypeSupport = KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_CHLG_KEY: - *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_DEC_KEY2: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - break; - case AM_PROPERTY_DVDCOPY_DISC_KEY: - *pTypeSupport = KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_DVD_KEY1: - *pTypeSupport = KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_REGION: - *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: - *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; - break; - case AM_PROPERTY_DVDCOPY_TITLE_KEY: - *pTypeSupport = KSPROPERTY_SUPPORT_SET; - break; - default: - return E_PROP_ID_UNSUPPORTED; - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "BaseClasses/streams.h" +#include +#include +#include +#include "DeCSSInputPin.h" +#include "../DSUtil/DSUtil.h" +#include "CSSauth.h" +#include "CSSscramble.h" + +#include "moreuuids.h" + +// +// CDeCSSInputPin +// + +CDeCSSInputPin::CDeCSSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName) + : CTransformInputPin(pObjectName, pFilter, phr, pName) + , m_varient(-1) +{ + ZeroMemory(m_Challenge, sizeof(m_Challenge)); + ZeroMemory(m_KeyCheck, sizeof(m_KeyCheck)); + ZeroMemory(m_Key, sizeof(m_Key)); + ZeroMemory(m_DiscKey, sizeof(m_DiscKey)); + ZeroMemory(m_TitleKey, sizeof(m_TitleKey)); +} + +STDMETHODIMP CDeCSSInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IKsPropertySet) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IMemInputPin + +STDMETHODIMP CDeCSSInputPin::Receive(IMediaSample* pSample) +{ + long len = pSample->GetActualDataLength(); + + BYTE* p = nullptr; + if (SUCCEEDED(pSample->GetPointer(&p)) && len > 0) { + if (m_mt.majortype == MEDIATYPE_DVD_ENCRYPTED_PACK && len == 2048 && (p[0x14] & 0x30)) { + CSSdescramble(p, m_TitleKey); + p[0x14] &= ~0x30; + + if (CComQIPtr pMS2 = pSample) { + AM_SAMPLE2_PROPERTIES props; + ZeroMemory(&props, sizeof(props)); + if (SUCCEEDED(pMS2->GetProperties(sizeof(props), (BYTE*)&props)) + && (props.dwTypeSpecificFlags & AM_UseNewCSSKey)) { + props.dwTypeSpecificFlags &= ~AM_UseNewCSSKey; + pMS2->SetProperties(sizeof(props), (BYTE*)&props); + } + } + } + } + + HRESULT hr = Transform(pSample); + + return hr == S_OK ? __super::Receive(pSample) : + hr == S_FALSE ? S_OK : hr; +} + +void CDeCSSInputPin::StripPacket(BYTE*& p, long& len) +{ + GUID majortype = m_mt.majortype; + + if (majortype == MEDIATYPE_MPEG2_PACK || majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { + if (len > 0 && *(DWORD*)p == 0xba010000) { // MEDIATYPE_*_PACK + len -= 14; + p += 14; + if (int stuffing = (p[-1] & 7)) { + len -= stuffing; + p += stuffing; + } + majortype = MEDIATYPE_MPEG2_PES; + } + } + + if (majortype == MEDIATYPE_MPEG2_PES) { + if (len > 0 && *(DWORD*)p == 0xbb010000) { + len -= 4; + p += 4; + int hdrlen = ((p[0] << 8) | p[1]) + 2; + len -= hdrlen; + p += hdrlen; + } + + if (len > 0 + && ((*(DWORD*)p & 0xf0ffffff) == 0xe0010000 + || (*(DWORD*)p & 0xe0ffffff) == 0xc0010000 + || (*(DWORD*)p & 0xbdffffff) == 0xbd010000)) { // PES + bool ps1 = (*(DWORD*)p & 0xbdffffff) == 0xbd010000; + + len -= 4; + p += 4; + long expected = ((p[0] << 8) | p[1]); + len -= 2; + p += 2; + BYTE* p0 = p; + + for (int i = 0; i < 16 && *p == 0xff; i++, len--, p++) { + ; + } + + if ((*p & 0xc0) == 0x80) { // mpeg2 + len -= 2; + p += 2; + len -= *p + 1; + p += *p + 1; + } else { // mpeg1 + if ((*p & 0xc0) == 0x40) { + len -= 2; + p += 2; + } + + if ((*p & 0x30) == 0x30 || (*p & 0x30) == 0x20) { + bool pts = !!(*p & 0x20), dts = !!(*p & 0x10); + if (pts) { + len -= 5; + } + p += 5; + if (dts) { + ASSERT((*p & 0xf0) == 0x10); + len -= 5; + p += 5; + } + } else { + len--; + p++; + } + } + + if (ps1) { + len--; + p++; + if (m_mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { + len -= 6; + p += 6; + } else if (m_mt.subtype == MEDIASUBTYPE_DOLBY_AC3 || m_mt.subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 + || m_mt.subtype == MEDIASUBTYPE_DTS || m_mt.subtype == MEDIASUBTYPE_WAVE_DTS) { + len -= 3; + p += 3; + } + } + + if (expected > 0) { + expected -= (long)(p - p0); + len = std::min(expected, len); + } + } + } + + if (len < 0) { + ASSERT(0); + len = 0; + } +} + +// IKsPropertySet + +STDMETHODIMP CDeCSSInputPin::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength) +{ + if (PropSet != AM_KSPROPSETID_CopyProt) { + return E_NOTIMPL; + } + + switch (Id) { + case AM_PROPERTY_COPY_MACROVISION: + break; + case AM_PROPERTY_DVDCOPY_CHLG_KEY: { // 3. auth: receive drive nonce word, also store and encrypt the buskey made up of the two nonce words + AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData; + for (int i = 0; i < 10; i++) { + m_Challenge[i] = pChlgKey->ChlgKey[9 - i]; + } + + CSSkey2(m_varient, m_Challenge, &m_Key[5]); + + CSSbuskey(m_varient, m_Key, m_KeyCheck); + } + break; + case AM_PROPERTY_DVDCOPY_DISC_KEY: { // 5. receive the disckey + AM_DVDCOPY_DISCKEY* pDiscKey = (AM_DVDCOPY_DISCKEY*)pPropertyData; // pDiscKey->DiscKey holds the disckey encrypted with itself and the 408 disckeys encrypted with the playerkeys + + bool fSuccess = false; + + for (int j = 0; j < g_nPlayerKeys; j++) { + for (int k = 1; k < 409; k++) { + BYTE DiscKey[6]; + for (int i = 0; i < 5; i++) { + DiscKey[i] = pDiscKey->DiscKey[k * 5 + i] ^ m_KeyCheck[4 - i]; + } + DiscKey[5] = 0; + + CSSdisckey(DiscKey, g_PlayerKeys[j]); + + BYTE Hash[6]; + for (int i = 0; i < 5; i++) { + Hash[i] = pDiscKey->DiscKey[i] ^ m_KeyCheck[4 - i]; + } + Hash[5] = 0; + + CSSdisckey(Hash, DiscKey); + + if (!memcmp(Hash, DiscKey, 6)) { + memcpy(m_DiscKey, DiscKey, 6); + j = g_nPlayerKeys; + fSuccess = true; + break; + } + } + } + + if (!fSuccess) { + return E_FAIL; + } + } + break; + case AM_PROPERTY_DVDCOPY_DVD_KEY1: { // 2. auth: receive our drive-encrypted nonce word and decrypt it for verification + AM_DVDCOPY_BUSKEY* pKey1 = (AM_DVDCOPY_BUSKEY*)pPropertyData; + for (int i = 0; i < 5; i++) { + m_Key[i] = pKey1->BusKey[4 - i]; + } + + m_varient = -1; + + for (int i = 31; i >= 0; i--) { + CSSkey1(i, m_Challenge, m_KeyCheck); + + if (memcmp(m_KeyCheck, &m_Key[0], 5) == 0) { + m_varient = i; + } + } + } + break; + case AM_PROPERTY_DVDCOPY_REGION: + break; + case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: + break; + case AM_PROPERTY_DVDCOPY_TITLE_KEY: { // 6. receive the title key and decrypt it with the disc key + AM_DVDCOPY_TITLEKEY* pTitleKey = (AM_DVDCOPY_TITLEKEY*)pPropertyData; + for (int i = 0; i < 5; i++) { + m_TitleKey[i] = pTitleKey->TitleKey[i] ^ m_KeyCheck[4 - i]; + } + m_TitleKey[5] = 0; + CSStitlekey(m_TitleKey, m_DiscKey); + } + break; + default: + return E_PROP_ID_UNSUPPORTED; + } + + return S_OK; +} + +STDMETHODIMP CDeCSSInputPin::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned) +{ + if (PropSet != AM_KSPROPSETID_CopyProt) { + return E_NOTIMPL; + } + + switch (Id) { + case AM_PROPERTY_DVDCOPY_CHLG_KEY: { // 1. auth: send our nonce word + AM_DVDCOPY_CHLGKEY* pChlgKey = (AM_DVDCOPY_CHLGKEY*)pPropertyData; + for (BYTE i = 0; i < 10; i++) { + pChlgKey->ChlgKey[i] = 9 - (m_Challenge[i] = i); + } + *pBytesReturned = sizeof(AM_DVDCOPY_CHLGKEY); + } + break; + case AM_PROPERTY_DVDCOPY_DEC_KEY2: { // 4. auth: send back the encrypted drive nonce word to finish the authentication + AM_DVDCOPY_BUSKEY* pKey2 = (AM_DVDCOPY_BUSKEY*)pPropertyData; + for (int i = 0; i < 5; i++) { + pKey2->BusKey[4 - i] = m_Key[5 + i]; + } + *pBytesReturned = sizeof(AM_DVDCOPY_BUSKEY); + } + break; + case AM_PROPERTY_DVDCOPY_REGION: { + DVD_REGION* pRegion = (DVD_REGION*)pPropertyData; + pRegion->RegionData = 0; + pRegion->SystemRegion = 0; + *pBytesReturned = sizeof(DVD_REGION); + } + break; + case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: { + AM_DVDCOPY_SET_COPY_STATE* pState = (AM_DVDCOPY_SET_COPY_STATE*)pPropertyData; + pState->DVDCopyState = AM_DVDCOPYSTATE_AUTHENTICATION_REQUIRED; + *pBytesReturned = sizeof(AM_DVDCOPY_SET_COPY_STATE); + } + break; + default: + return E_PROP_ID_UNSUPPORTED; + } + + return S_OK; +} + +STDMETHODIMP CDeCSSInputPin::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) +{ + if (PropSet != AM_KSPROPSETID_CopyProt) { + return E_NOTIMPL; + } + + switch (Id) { + case AM_PROPERTY_COPY_MACROVISION: + *pTypeSupport = KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_CHLG_KEY: + *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_DEC_KEY2: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + break; + case AM_PROPERTY_DVDCOPY_DISC_KEY: + *pTypeSupport = KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_DVD_KEY1: + *pTypeSupport = KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_REGION: + *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_SET_COPY_STATE: + *pTypeSupport = KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET; + break; + case AM_PROPERTY_DVDCOPY_TITLE_KEY: + *pTypeSupport = KSPROPERTY_SUPPORT_SET; + break; + default: + return E_PROP_ID_UNSUPPORTED; + } + + return S_OK; +} diff --git a/src/DeCSS/DeCSSInputPin.h b/src/DeCSS/DeCSSInputPin.h index 83a75faf366..29c4b72c7a9 100644 --- a/src/DeCSS/DeCSSInputPin.h +++ b/src/DeCSS/DeCSSInputPin.h @@ -1,50 +1,50 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -class CDeCSSInputPin : public CTransformInputPin, public IKsPropertySet -{ - int m_varient; - BYTE m_Challenge[10], m_KeyCheck[5], m_Key[10]; - BYTE m_DiscKey[6], m_TitleKey[6]; - -protected: - // return S_FALSE here if you don't want the base class - // to call CTransformFilter::Receive with this sample - virtual HRESULT Transform(IMediaSample* pSample) { return S_OK; } - -public: - CDeCSSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - void StripPacket(BYTE*& p, long& len); - - // IMemInputPin - STDMETHODIMP Receive(IMediaSample* pSample); - - // IKsPropertySet - STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength); - STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG* pBytesReturned); - STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +class CDeCSSInputPin : public CTransformInputPin, public IKsPropertySet +{ + int m_varient; + BYTE m_Challenge[10], m_KeyCheck[5], m_Key[10]; + BYTE m_DiscKey[6], m_TitleKey[6]; + +protected: + // return S_FALSE here if you don't want the base class + // to call CTransformFilter::Receive with this sample + virtual HRESULT Transform(IMediaSample* pSample) { return S_OK; } + +public: + CDeCSSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + void StripPacket(BYTE*& p, long& len); + + // IMemInputPin + STDMETHODIMP Receive(IMediaSample* pSample); + + // IKsPropertySet + STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength); + STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG* pBytesReturned); + STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport); +}; diff --git a/src/DeCSS/VobDec.cpp b/src/DeCSS/VobDec.cpp index e1f9b7bcbbb..570c27e6e9d 100644 --- a/src/DeCSS/VobDec.cpp +++ b/src/DeCSS/VobDec.cpp @@ -1,162 +1,162 @@ -#include "stdafx.h" -#include "VobDec.h" - -static BYTE reverse[0x100], table[0x100] = { - 0x33, 0x73, 0x3B, 0x26, 0x63, 0x23, 0x6B, 0x76, 0x3E, 0x7E, 0x36, 0x2B, 0x6E, 0x2E, 0x66, 0x7B, - 0xD3, 0x93, 0xDB, 0x06, 0x43, 0x03, 0x4B, 0x96, 0xDE, 0x9E, 0xD6, 0x0B, 0x4E, 0x0E, 0x46, 0x9B, - 0x57, 0x17, 0x5F, 0x82, 0xC7, 0x87, 0xCF, 0x12, 0x5A, 0x1A, 0x52, 0x8F, 0xCA, 0x8A, 0xC2, 0x1F, - 0xD9, 0x99, 0xD1, 0x00, 0x49, 0x09, 0x41, 0x90, 0xD8, 0x98, 0xD0, 0x01, 0x48, 0x08, 0x40, 0x91, - 0x3D, 0x7D, 0x35, 0x24, 0x6D, 0x2D, 0x65, 0x74, 0x3C, 0x7C, 0x34, 0x25, 0x6C, 0x2C, 0x64, 0x75, - 0xDD, 0x9D, 0xD5, 0x04, 0x4D, 0x0D, 0x45, 0x94, 0xDC, 0x9C, 0xD4, 0x05, 0x4C, 0x0C, 0x44, 0x95, - 0x59, 0x19, 0x51, 0x80, 0xC9, 0x89, 0xC1, 0x10, 0x58, 0x18, 0x50, 0x81, 0xC8, 0x88, 0xC0, 0x11, - 0xD7, 0x97, 0xDF, 0x02, 0x47, 0x07, 0x4F, 0x92, 0xDA, 0x9A, 0xD2, 0x0F, 0x4A, 0x0A, 0x42, 0x9F, - 0x53, 0x13, 0x5B, 0x86, 0xC3, 0x83, 0xCB, 0x16, 0x5E, 0x1E, 0x56, 0x8B, 0xCE, 0x8E, 0xC6, 0x1B, - 0xB3, 0xF3, 0xBB, 0xA6, 0xE3, 0xA3, 0xEB, 0xF6, 0xBE, 0xFE, 0xB6, 0xAB, 0xEE, 0xAE, 0xE6, 0xFB, - 0x37, 0x77, 0x3F, 0x22, 0x67, 0x27, 0x6F, 0x72, 0x3A, 0x7A, 0x32, 0x2F, 0x6A, 0x2A, 0x62, 0x7F, - 0xB9, 0xF9, 0xB1, 0xA0, 0xE9, 0xA9, 0xE1, 0xF0, 0xB8, 0xF8, 0xB0, 0xA1, 0xE8, 0xA8, 0xE0, 0xF1, - 0x5D, 0x1D, 0x55, 0x84, 0xCD, 0x8D, 0xC5, 0x14, 0x5C, 0x1C, 0x54, 0x85, 0xCC, 0x8C, 0xC4, 0x15, - 0xBD, 0xFD, 0xB5, 0xA4, 0xED, 0xAD, 0xE5, 0xF4, 0xBC, 0xFC, 0xB4, 0xA5, 0xEC, 0xAC, 0xE4, 0xF5, - 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70, 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71, - 0xB7, 0xF7, 0xBF, 0xA2, 0xE7, 0xA7, 0xEF, 0xF2, 0xBA, 0xFA, 0xB2, 0xAF, 0xEA, 0xAA, 0xE2, 0xFF, -}; - -CVobDec::CVobDec() -{ - m_fFoundKey = false; - m_lfsr0 = 0; - m_lfsr1 = 0; - - for (DWORD loop0 = 0; loop0 < 0x100; loop0++) { - BYTE value = 0; - - for (DWORD loop1 = 0; loop1 < 8; loop1++) { - value |= ((loop0 >> loop1) & 1) << (7 - loop1); - } - - reverse[loop0] = value; - } - -} - -CVobDec::~CVobDec() -{ -} - -void CVobDec::ClockLfsr0Forward(int& lfsr0) -{ - int temp = (lfsr0 << 3) | (lfsr0 >> 14); - lfsr0 = (lfsr0 >> 8) | ((((((temp << 3) ^ temp) << 3) ^ temp ^ lfsr0) & 0xFF) << 9); -} - -void CVobDec::ClockLfsr1Forward(int& lfsr1) -{ - lfsr1 = (lfsr1 >> 8) | ((((((((lfsr1 >> 8) ^ lfsr1) >> 1) ^ lfsr1) >> 3) ^ lfsr1) & 0xFF) << 17); -} - -void CVobDec::ClockBackward(int& lfsr0, int& lfsr1) -{ - int temp0, temp1; - - lfsr0 = ((lfsr0 << 8) ^ ((((lfsr0 >> 3) ^ lfsr0) >> 6) & 0xFF)) & ((1 << 17) - 1); - temp0 = ((lfsr1 >> 17) ^ (lfsr1 >> 4)) & 0xFF; - temp1 = (lfsr1 << 5) | (temp0 >> 3); - temp1 = ((temp1 >> 1) ^ temp1) & 0xFF; - lfsr1 = ((lfsr1 << 8) | ((((((temp1 >> 2) ^ temp1) >> 1) ^ temp1) >> 3) ^ temp1 ^ temp0)) & ((1 << 25) - 1); -} - -void CVobDec::Salt(const BYTE salt[5], int& lfsr0, int& lfsr1) -{ - lfsr0 ^= (reverse[salt[0]] << 9) | reverse[salt[1]]; - lfsr1 ^= ((reverse[salt[2]] & 0xE0) << 17) | ((reverse[salt[2]] & 0x1F) << 16) | (reverse[salt[3]] << 8) | reverse[salt[4]]; -} - -int CVobDec::FindLfsr(const BYTE* crypt, int offset, const BYTE* plain) -{ - int count = 0; - - for (int loop0 = 0; loop0 != (1 << 18); loop0++) { - int lfsr0 = loop0 >> 1; - int carry = loop0 & 0x01; - int loop1 = 0, lfsr1 = 0; - - for (; loop1 != 4; loop1++) { - ClockLfsr0Forward(lfsr0); - carry = (table[crypt[offset + loop1]] ^ plain[loop1]) - ((lfsr0 >> 9) ^ 0xFF) - carry; - lfsr1 = (lfsr1 >> 8) | ((carry & 0xFF) << 17); - carry = (carry >> 8) & 0x01; - } - for (; loop1 != 7; loop1++) { - ClockLfsr0Forward(lfsr0); - ClockLfsr1Forward(lfsr1); - carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17); - if ((carry & 0xFF) != (table[crypt[offset + loop1]] ^ plain[loop1])) { - break; - } - carry >>= 8; - } - if (loop1 == 7) { - for (loop1 = 0; loop1 != 6; loop1++) { - ClockBackward(lfsr0, lfsr1); - } - carry = ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17) + (loop0 & 0x01); - if ((carry & 0xFF) == (table[crypt[offset]] ^ plain[0])) { - for (loop1 = 0; loop1 != offset + 1; loop1++) { - ClockBackward(lfsr0, lfsr1); - } - if (lfsr0 & 0x100 && lfsr1 & 0x200000) { - m_lfsr0 = lfsr0; - m_lfsr1 = lfsr1; - count++; - } - } - } - } - - return count; -} - -bool CVobDec::FindKey(BYTE* buff) -{ - m_fFoundKey = false; - - if (buff[0x14] & 0x30) { - //int flag = 0x01; - - if (*(DWORD*)&buff[0x00] == 0xba010000 && (*(DWORD*)&buff[0x0e] & 0xffffff) == 0x010000) { - int offset = 0x14 + (buff[0x12] << 8) + buff[0x13]; - if (0x80 <= offset && offset <= 0x7F9) { - BYTE plain[7] = { 0x00, 0x00, 0x01, 0xBE, 0x00, 0x00, 0xFF }; - int left = 0x800 - offset - 6; - plain[4] = (char)(left >> 8); - plain[5] = (char)left; - if (FindLfsr(buff + 0x80, offset - 0x80, plain) == 1) { - Salt(buff + 0x54, m_lfsr0, m_lfsr1); - m_fFoundKey = true; - } - } - } - } - - return m_fFoundKey; -} - -void CVobDec::Decrypt(BYTE* buff) -{ - if (buff[0x14] & 0x30) { - buff[0x14] &= ~0x30; - - int lfsr0 = m_lfsr0, lfsr1 = m_lfsr1; - - Salt(buff + 0x54, lfsr0, lfsr1); - - buff += 0x80; - - for (int loop0 = 0, carry = 0; loop0 != 0x800 - 0x80; loop0++, buff++) { - ClockLfsr0Forward(lfsr0); - ClockLfsr1Forward(lfsr1); - carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17); - *buff = BYTE(table[*buff] ^ carry); - carry >>= 8; - } - } -} +#include "stdafx.h" +#include "VobDec.h" + +static BYTE reverse[0x100], table[0x100] = { + 0x33, 0x73, 0x3B, 0x26, 0x63, 0x23, 0x6B, 0x76, 0x3E, 0x7E, 0x36, 0x2B, 0x6E, 0x2E, 0x66, 0x7B, + 0xD3, 0x93, 0xDB, 0x06, 0x43, 0x03, 0x4B, 0x96, 0xDE, 0x9E, 0xD6, 0x0B, 0x4E, 0x0E, 0x46, 0x9B, + 0x57, 0x17, 0x5F, 0x82, 0xC7, 0x87, 0xCF, 0x12, 0x5A, 0x1A, 0x52, 0x8F, 0xCA, 0x8A, 0xC2, 0x1F, + 0xD9, 0x99, 0xD1, 0x00, 0x49, 0x09, 0x41, 0x90, 0xD8, 0x98, 0xD0, 0x01, 0x48, 0x08, 0x40, 0x91, + 0x3D, 0x7D, 0x35, 0x24, 0x6D, 0x2D, 0x65, 0x74, 0x3C, 0x7C, 0x34, 0x25, 0x6C, 0x2C, 0x64, 0x75, + 0xDD, 0x9D, 0xD5, 0x04, 0x4D, 0x0D, 0x45, 0x94, 0xDC, 0x9C, 0xD4, 0x05, 0x4C, 0x0C, 0x44, 0x95, + 0x59, 0x19, 0x51, 0x80, 0xC9, 0x89, 0xC1, 0x10, 0x58, 0x18, 0x50, 0x81, 0xC8, 0x88, 0xC0, 0x11, + 0xD7, 0x97, 0xDF, 0x02, 0x47, 0x07, 0x4F, 0x92, 0xDA, 0x9A, 0xD2, 0x0F, 0x4A, 0x0A, 0x42, 0x9F, + 0x53, 0x13, 0x5B, 0x86, 0xC3, 0x83, 0xCB, 0x16, 0x5E, 0x1E, 0x56, 0x8B, 0xCE, 0x8E, 0xC6, 0x1B, + 0xB3, 0xF3, 0xBB, 0xA6, 0xE3, 0xA3, 0xEB, 0xF6, 0xBE, 0xFE, 0xB6, 0xAB, 0xEE, 0xAE, 0xE6, 0xFB, + 0x37, 0x77, 0x3F, 0x22, 0x67, 0x27, 0x6F, 0x72, 0x3A, 0x7A, 0x32, 0x2F, 0x6A, 0x2A, 0x62, 0x7F, + 0xB9, 0xF9, 0xB1, 0xA0, 0xE9, 0xA9, 0xE1, 0xF0, 0xB8, 0xF8, 0xB0, 0xA1, 0xE8, 0xA8, 0xE0, 0xF1, + 0x5D, 0x1D, 0x55, 0x84, 0xCD, 0x8D, 0xC5, 0x14, 0x5C, 0x1C, 0x54, 0x85, 0xCC, 0x8C, 0xC4, 0x15, + 0xBD, 0xFD, 0xB5, 0xA4, 0xED, 0xAD, 0xE5, 0xF4, 0xBC, 0xFC, 0xB4, 0xA5, 0xEC, 0xAC, 0xE4, 0xF5, + 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70, 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71, + 0xB7, 0xF7, 0xBF, 0xA2, 0xE7, 0xA7, 0xEF, 0xF2, 0xBA, 0xFA, 0xB2, 0xAF, 0xEA, 0xAA, 0xE2, 0xFF, +}; + +CVobDec::CVobDec() +{ + m_fFoundKey = false; + m_lfsr0 = 0; + m_lfsr1 = 0; + + for (DWORD loop0 = 0; loop0 < 0x100; loop0++) { + BYTE value = 0; + + for (DWORD loop1 = 0; loop1 < 8; loop1++) { + value |= ((loop0 >> loop1) & 1) << (7 - loop1); + } + + reverse[loop0] = value; + } + +} + +CVobDec::~CVobDec() +{ +} + +void CVobDec::ClockLfsr0Forward(int& lfsr0) +{ + int temp = (lfsr0 << 3) | (lfsr0 >> 14); + lfsr0 = (lfsr0 >> 8) | ((((((temp << 3) ^ temp) << 3) ^ temp ^ lfsr0) & 0xFF) << 9); +} + +void CVobDec::ClockLfsr1Forward(int& lfsr1) +{ + lfsr1 = (lfsr1 >> 8) | ((((((((lfsr1 >> 8) ^ lfsr1) >> 1) ^ lfsr1) >> 3) ^ lfsr1) & 0xFF) << 17); +} + +void CVobDec::ClockBackward(int& lfsr0, int& lfsr1) +{ + int temp0, temp1; + + lfsr0 = ((lfsr0 << 8) ^ ((((lfsr0 >> 3) ^ lfsr0) >> 6) & 0xFF)) & ((1 << 17) - 1); + temp0 = ((lfsr1 >> 17) ^ (lfsr1 >> 4)) & 0xFF; + temp1 = (lfsr1 << 5) | (temp0 >> 3); + temp1 = ((temp1 >> 1) ^ temp1) & 0xFF; + lfsr1 = ((lfsr1 << 8) | ((((((temp1 >> 2) ^ temp1) >> 1) ^ temp1) >> 3) ^ temp1 ^ temp0)) & ((1 << 25) - 1); +} + +void CVobDec::Salt(const BYTE salt[5], int& lfsr0, int& lfsr1) +{ + lfsr0 ^= (reverse[salt[0]] << 9) | reverse[salt[1]]; + lfsr1 ^= ((reverse[salt[2]] & 0xE0) << 17) | ((reverse[salt[2]] & 0x1F) << 16) | (reverse[salt[3]] << 8) | reverse[salt[4]]; +} + +int CVobDec::FindLfsr(const BYTE* crypt, int offset, const BYTE* plain) +{ + int count = 0; + + for (int loop0 = 0; loop0 != (1 << 18); loop0++) { + int lfsr0 = loop0 >> 1; + int carry = loop0 & 0x01; + int loop1 = 0, lfsr1 = 0; + + for (; loop1 != 4; loop1++) { + ClockLfsr0Forward(lfsr0); + carry = (table[crypt[offset + loop1]] ^ plain[loop1]) - ((lfsr0 >> 9) ^ 0xFF) - carry; + lfsr1 = (lfsr1 >> 8) | ((carry & 0xFF) << 17); + carry = (carry >> 8) & 0x01; + } + for (; loop1 != 7; loop1++) { + ClockLfsr0Forward(lfsr0); + ClockLfsr1Forward(lfsr1); + carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17); + if ((carry & 0xFF) != (table[crypt[offset + loop1]] ^ plain[loop1])) { + break; + } + carry >>= 8; + } + if (loop1 == 7) { + for (loop1 = 0; loop1 != 6; loop1++) { + ClockBackward(lfsr0, lfsr1); + } + carry = ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17) + (loop0 & 0x01); + if ((carry & 0xFF) == (table[crypt[offset]] ^ plain[0])) { + for (loop1 = 0; loop1 != offset + 1; loop1++) { + ClockBackward(lfsr0, lfsr1); + } + if (lfsr0 & 0x100 && lfsr1 & 0x200000) { + m_lfsr0 = lfsr0; + m_lfsr1 = lfsr1; + count++; + } + } + } + } + + return count; +} + +bool CVobDec::FindKey(BYTE* buff) +{ + m_fFoundKey = false; + + if (buff[0x14] & 0x30) { + //int flag = 0x01; + + if (*(DWORD*)&buff[0x00] == 0xba010000 && (*(DWORD*)&buff[0x0e] & 0xffffff) == 0x010000) { + int offset = 0x14 + (buff[0x12] << 8) + buff[0x13]; + if (0x80 <= offset && offset <= 0x7F9) { + BYTE plain[7] = { 0x00, 0x00, 0x01, 0xBE, 0x00, 0x00, 0xFF }; + int left = 0x800 - offset - 6; + plain[4] = (char)(left >> 8); + plain[5] = (char)left; + if (FindLfsr(buff + 0x80, offset - 0x80, plain) == 1) { + Salt(buff + 0x54, m_lfsr0, m_lfsr1); + m_fFoundKey = true; + } + } + } + } + + return m_fFoundKey; +} + +void CVobDec::Decrypt(BYTE* buff) +{ + if (buff[0x14] & 0x30) { + buff[0x14] &= ~0x30; + + int lfsr0 = m_lfsr0, lfsr1 = m_lfsr1; + + Salt(buff + 0x54, lfsr0, lfsr1); + + buff += 0x80; + + for (int loop0 = 0, carry = 0; loop0 != 0x800 - 0x80; loop0++, buff++) { + ClockLfsr0Forward(lfsr0); + ClockLfsr1Forward(lfsr1); + carry += ((lfsr0 >> 9) ^ 0xFF) + (lfsr1 >> 17); + *buff = BYTE(table[*buff] ^ carry); + carry >>= 8; + } + } +} diff --git a/src/DeCSS/VobDec.h b/src/DeCSS/VobDec.h index fd86263fceb..c88e2f644b0 100644 --- a/src/DeCSS/VobDec.h +++ b/src/DeCSS/VobDec.h @@ -1,21 +1,21 @@ -#pragma once - -class CVobDec -{ - int m_lfsr0, m_lfsr1; - - void ClockLfsr0Forward(int& lfsr0); - void ClockLfsr1Forward(int& lfsr1); - void ClockBackward(int& lfsr0, int& lfsr1); - void Salt(const BYTE salt[5], int& lfsr0, int& lfsr1); - int FindLfsr(const BYTE* crypt, int offset, const BYTE* plain); - -public: - CVobDec(); - virtual ~CVobDec(); - - bool m_fFoundKey; - - bool FindKey(BYTE* buff); - void Decrypt(BYTE* buff); -}; +#pragma once + +class CVobDec +{ + int m_lfsr0, m_lfsr1; + + void ClockLfsr0Forward(int& lfsr0); + void ClockLfsr1Forward(int& lfsr1); + void ClockBackward(int& lfsr0, int& lfsr1); + void Salt(const BYTE salt[5], int& lfsr0, int& lfsr1); + int FindLfsr(const BYTE* crypt, int offset, const BYTE* plain); + +public: + CVobDec(); + virtual ~CVobDec(); + + bool m_fFoundKey; + + bool FindKey(BYTE* buff); + void Decrypt(BYTE* buff); +}; diff --git a/src/DeCSS/VobFile.cpp b/src/DeCSS/VobFile.cpp index 529b7815c90..286454e0ffd 100644 --- a/src/DeCSS/VobFile.cpp +++ b/src/DeCSS/VobFile.cpp @@ -1,878 +1,878 @@ -#include "stdafx.h" -#include -#include -#include "VobFile.h" -#include "CSSauth.h" -#include "CSSscramble.h" -#include "udf.h" - -#include "../DSUtil/GolombBuffer.h" -#include "../DSUtil/DSUtil.h" -#include "../DSUtil/ISOLang.h" - -#define AUDIO_BLOCK_SIZE 66 -#define SUBTITLE_BLOCK_SIZE 194 -#define IFO_HEADER_SIZE 12 -#define VIDEO_TS_HEADER "DVDVIDEO-VMG" -#define VTS_HEADER "DVDVIDEO-VTS" - -// -// CDVDSession -// - -CDVDSession::CDVDSession() - : m_hDrive(INVALID_HANDLE_VALUE) - , m_session(DVD_END_ALL_SESSIONS) -{ - ZeroMemory(m_SessionKey, sizeof(m_SessionKey)); - ZeroMemory(m_DiscKey, sizeof(m_DiscKey)); - ZeroMemory(m_TitleKey, sizeof(m_TitleKey)); -} - -CDVDSession::~CDVDSession() -{ - EndSession(); -} - -bool CDVDSession::Open(LPCTSTR path) -{ - Close(); - - CString fn = path; - CString drive = _T("\\\\.\\") + fn.Left(fn.Find(':') + 1); - - m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); - if (m_hDrive == INVALID_HANDLE_VALUE) { - return false; - } - - return true; -} - -void CDVDSession::Close() -{ - if (m_hDrive != INVALID_HANDLE_VALUE) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - } -} - -bool CDVDSession::BeginSession() -{ - EndSession(); - - if (m_hDrive == INVALID_HANDLE_VALUE) { - return false; - } - - DWORD BytesReturned; - if (!DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, nullptr, 0, &m_session, sizeof(m_session), &BytesReturned, nullptr)) { - m_session = DVD_END_ALL_SESSIONS; - if (!DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), nullptr, 0, &BytesReturned, nullptr) - || !DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, nullptr, 0, &m_session, sizeof(m_session), &BytesReturned, nullptr)) { - Close(); - DWORD err = GetLastError(); - UNREFERENCED_PARAMETER(err); - return false; - } - } - - return true; -} - -void CDVDSession::EndSession() -{ - if (m_session != DVD_END_ALL_SESSIONS) { - DWORD BytesReturned; - DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), nullptr, 0, &BytesReturned, nullptr); - m_session = DVD_END_ALL_SESSIONS; - } -} - -bool CDVDSession::Authenticate() -{ - if (m_session == DVD_END_ALL_SESSIONS) { - return false; - } - - BYTE Challenge[10], Key[10]; - - for (BYTE i = 0; i < 10; i++) { - Challenge[i] = i; - } - - if (!SendKey(DvdChallengeKey, Challenge)) { - return false; - } - - if (!ReadKey(DvdBusKey1, Key)) { - return false; - } - - int varient = -1; - - for (int i = 31; i >= 0; i--) { - BYTE KeyCheck[5]; - CSSkey1(i, Challenge, KeyCheck); - if (!memcmp(KeyCheck, Key, 5)) { - varient = i; - } - } - - if (!ReadKey(DvdChallengeKey, Challenge)) { - return false; - } - - CSSkey2(varient, Challenge, &Key[5]); - - if (!SendKey(DvdBusKey2, &Key[5])) { - return false; - } - - CSSbuskey(varient, Key, m_SessionKey); - - return true; -} - -bool CDVDSession::GetDiscKey() -{ - if (m_session == DVD_END_ALL_SESSIONS) { - return false; - } - - BYTE DiscKeys[2048]; - if (!ReadKey(DvdDiskKey, DiscKeys)) { - return false; - } - - for (int i = 0; i < g_nPlayerKeys; i++) { - for (int j = 1; j < 409; j++) { - BYTE DiscKey[6]; - memcpy(DiscKey, &DiscKeys[j * 5], 5); - DiscKey[5] = 0; - - CSSdisckey(DiscKey, g_PlayerKeys[i]); - - BYTE Hash[6]; - memcpy(Hash, &DiscKeys[0], 5); - Hash[5] = 0; - - CSSdisckey(Hash, DiscKey); - - if (!memcmp(Hash, DiscKey, 6)) { - memcpy(m_DiscKey, DiscKey, 6); - return true; - } - } - } - - return false; -} - -bool CDVDSession::GetTitleKey(int lba, BYTE* pKey) -{ - if (m_session == DVD_END_ALL_SESSIONS) { - return false; - } - - if (!ReadKey(DvdTitleKey, pKey, lba)) { - return false; - } - - if (!(pKey[0] | pKey[1] | pKey[2] | pKey[3] | pKey[4])) { - return false; - } - - pKey[5] = 0; - - CSStitlekey(pKey, m_DiscKey); - - return true; -} - -static void Reverse(BYTE* d, BYTE* s, int len) -{ - if (d == s) { - for (s += len - 1; d < s; d++, s--) { - *d ^= *s, *s ^= *d, *d ^= *s; - } - } else { - for (int i = 0; i < len; i++) { - d[i] = s[len - 1 - i]; - } - } -} - -bool CDVDSession::SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData) -{ - CAutoVectorPtr key; - DVD_COPY_PROTECT_KEY* pKey = nullptr; - - auto allocateKey = [&](ULONG len) { - bool bSuccess = key.Allocate(len); - if (bSuccess) { - pKey = (DVD_COPY_PROTECT_KEY*)(BYTE*)key; - pKey->KeyLength = len; - } - return bSuccess; - }; - - switch (KeyType) { - case DvdChallengeKey: - if (allocateKey(DVD_CHALLENGE_KEY_LENGTH)) { - Reverse(pKey->KeyData, pKeyData, 10); - } - break; - case DvdBusKey2: - if (allocateKey(DVD_BUS_KEY_LENGTH)) { - Reverse(pKey->KeyData, pKeyData, 5); - } - break; - default: - break; - } - - if (!pKey) { - return false; - } - - pKey->SessionId = m_session; - pKey->KeyType = KeyType; - pKey->KeyFlags = 0; - - DWORD dwBytesReturned; - return !!DeviceIoControl(m_hDrive, IOCTL_DVD_SEND_KEY, pKey, pKey->KeyLength, nullptr, 0, &dwBytesReturned, nullptr); -} - -bool CDVDSession::ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba) -{ - CAutoVectorPtr key; - DVD_COPY_PROTECT_KEY* pKey = nullptr; - - auto allocateKey = [&](ULONG len) { - bool bSuccess = key.Allocate(len); - if (bSuccess) { - pKey = (DVD_COPY_PROTECT_KEY*)(BYTE*)key; - pKey->KeyLength = len; - } - return bSuccess; - }; - - switch (KeyType) { - case DvdChallengeKey: - if (allocateKey(DVD_CHALLENGE_KEY_LENGTH)) { - pKey->Parameters.TitleOffset.QuadPart = 0; - } - break; - case DvdBusKey1: - if (allocateKey(DVD_BUS_KEY_LENGTH)) { - pKey->Parameters.TitleOffset.QuadPart = 0; - } - break; - case DvdDiskKey: - if (allocateKey(DVD_DISK_KEY_LENGTH)) { - pKey->Parameters.TitleOffset.QuadPart = 0; - } - break; - case DvdTitleKey: - if (allocateKey(DVD_TITLE_KEY_LENGTH)) { - pKey->Parameters.TitleOffset.QuadPart = 2048i64 * lba; - } - break; - default: - break; - } - - if (!pKey) { - return false; - } - - pKey->SessionId = m_session; - pKey->KeyType = KeyType; - pKey->KeyFlags = 0; - - DWORD dwBytesReturned; - if (!DeviceIoControl(m_hDrive, IOCTL_DVD_READ_KEY, pKey, pKey->KeyLength, pKey, pKey->KeyLength, &dwBytesReturned, nullptr)) { - DWORD err = GetLastError(); - UNREFERENCED_PARAMETER(err); - return false; - } - - switch (KeyType) { - case DvdChallengeKey: - Reverse(pKeyData, pKey->KeyData, 10); - break; - case DvdBusKey1: - Reverse(pKeyData, pKey->KeyData, 5); - break; - case DvdDiskKey: - memcpy(pKeyData, pKey->KeyData, 2048); - for (int i = 0; i < 2048 / 5; i++) { - pKeyData[i] ^= m_SessionKey[4 - (i % 5)]; - } - break; - case DvdTitleKey: - memcpy(pKeyData, pKey->KeyData, 5); - for (int i = 0; i < 5; i++) { - pKeyData[i] ^= m_SessionKey[4 - (i % 5)]; - } - break; - default: - break; - } - - return true; -} - -// -// CLBAFile -// - -CLBAFile::CLBAFile() -{ -} - -CLBAFile::~CLBAFile() -{ -} - -bool CLBAFile::IsOpen() const -{ - return (m_hFile != hFileNull); -} - -bool CLBAFile::Open(LPCTSTR path) -{ - Close(); - - return !!CFile::Open(path, modeRead | typeBinary | shareDenyNone | osSequentialScan); -} - -void CLBAFile::Close() -{ - if (m_hFile != hFileNull) { - CFile::Close(); - } -} - -int CLBAFile::GetLengthLBA() const -{ - return (int)(CFile::GetLength() / 2048); -} - -int CLBAFile::GetPositionLBA() const -{ - return (int)(CFile::GetPosition() / 2048); -} - -int CLBAFile::Seek(int lba) -{ - return (int)(CFile::Seek(2048i64 * lba, CFile::begin) / 2048); -} - -bool CLBAFile::Read(BYTE* buff) -{ - return CFile::Read(buff, 2048) == 2048; -} - -// -// CVobFile -// - -CVobFile::CVobFile() -{ - Close(); - m_iChaptersCount = -1; -} - -CVobFile::~CVobFile() -{ -} - -bool CVobFile::IsDVD() const -{ - return m_fDVD; -} - -bool CVobFile::HasDiscKey(BYTE* key) const -{ - if (key) { - memcpy(key, m_DiscKey, 5); - } - return m_fHasDiscKey; -} - -bool CVobFile::HasTitleKey(BYTE* key) const -{ - if (key) { - memcpy(key, m_TitleKey, 5); - } - return m_fHasTitleKey; -} - -DWORD CVobFile::ReadDword() -{ - return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte(); -} - -short CVobFile::ReadShort() -{ - return (ReadByte() << 8 | ReadByte()); -} - -BYTE CVobFile::ReadByte() -{ - BYTE bVal; - m_ifoFile.Read(&bVal, sizeof(bVal)); - return bVal; -} - -void CVobFile::ReadBuffer(BYTE* pBuff, DWORD nLen) -{ - m_ifoFile.Read(pBuff, nLen); -} - -static short GetFrames(byte val) -{ - int byte0_high = val >> 4; - int byte0_low = val & 0x0F; - if (byte0_high > 11) { - return (short)(((byte0_high - 12) * 10) + byte0_low); - } - if ((byte0_high <= 3) || (byte0_high >= 8)) { - return 0; - } - return (short)(((byte0_high - 4) * 10) + byte0_low); -} - -bool CVobFile::GetTitleInfo(LPCTSTR fn, ULONG nTitleNum, ULONG& VTSN, ULONG& TTN) -{ - CFile ifoFile; - if (!ifoFile.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - - char hdr[IFO_HEADER_SIZE + 1]; - ifoFile.Read(hdr, IFO_HEADER_SIZE); - hdr[IFO_HEADER_SIZE] = '\0'; - if (strcmp(hdr, VIDEO_TS_HEADER)) { - return false; - } - - ifoFile.Seek(0xC4, CFile::begin); - DWORD TT_SRPTPosition; // Read a 32-bit unsigned big-endian integer - ifoFile.Read(&TT_SRPTPosition, sizeof(TT_SRPTPosition)); - TT_SRPTPosition = _byteswap_ulong(TT_SRPTPosition); - TT_SRPTPosition *= 2048; - ifoFile.Seek(TT_SRPTPosition + 8 + (nTitleNum - 1) * 12 + 6, CFile::begin); - BYTE tmp; - ifoFile.Read(&tmp, sizeof(tmp)); - VTSN = tmp; - ifoFile.Read(&tmp, sizeof(tmp)); - TTN = tmp; - - ifoFile.Close(); - - return true; -} - -bool CVobFile::Open(CString fn, CAtlList& vobs, ULONG nProgNum /*= 1*/, bool bAuthenticate /*= true*/) -{ - if (!m_ifoFile.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - - try { - char hdr[IFO_HEADER_SIZE + 1]; - m_ifoFile.Read(hdr, IFO_HEADER_SIZE); - hdr[IFO_HEADER_SIZE] = '\0'; - if (strcmp(hdr, VTS_HEADER)) { - return false; - } - - // Audio streams ... - m_ifoFile.Seek(0x202, CFile::begin); - BYTE buffer[SUBTITLE_BLOCK_SIZE]; - m_ifoFile.Read(buffer, AUDIO_BLOCK_SIZE); - CGolombBuffer gb(buffer, AUDIO_BLOCK_SIZE); - int stream_count = gb.ReadShort(); - for (int i = 0; i < std::min(stream_count, 8); i++) { - BYTE Coding_mode = (BYTE)gb.BitRead(3); - gb.BitRead(5);// skip - int ToAdd = 0; - switch (Coding_mode) { - case 0: - ToAdd = 0x80; - break; - case 4: - ToAdd = 0xA0; - break; - case 6: - ToAdd = 0x88; - break; - default: - break; - } - gb.ReadByte();// skip - char lang[2]; - gb.ReadBuffer((BYTE*)lang, 2); - gb.ReadDword();// skip - if (ToAdd) { - m_pStream_Lang[ToAdd + i] = ISOLang::ISO6391ToLanguage(lang); - } - } - - // Subtitle streams ... - m_ifoFile.Seek(0x254, CFile::begin); - m_ifoFile.Read(buffer, SUBTITLE_BLOCK_SIZE); - CGolombBuffer gb_s(buffer, SUBTITLE_BLOCK_SIZE); - stream_count = gb_s.ReadShort(); - for (int i = 0; i < std::min(stream_count, 32); i++) { - gb_s.ReadShort(); - char lang[2]; - gb_s.ReadBuffer((BYTE*)lang, 2); - gb_s.ReadShort(); - m_pStream_Lang[0x20 + i] = ISOLang::ISO6391ToLanguage(lang); - } - - // Chapters ... - m_ifoFile.Seek(0xCC, CFile::begin); //Get VTS_PGCI address - DWORD pcgITPosition = ReadDword() * 2048; - m_ifoFile.Seek(pcgITPosition, CFile::begin); - WORD nProgCount = (WORD)ReadShort(); - if (nProgNum > nProgCount) { - return false; - } - m_ifoFile.Seek(pcgITPosition + 8 * nProgNum + 4, CFile::begin); - DWORD chainOffset = ReadDword(); - m_ifoFile.Seek(pcgITPosition + chainOffset + 2, CFile::begin); - BYTE programChainPrograms = ReadByte(); - m_iChaptersCount = programChainPrograms; - m_ifoFile.Seek(pcgITPosition + chainOffset + 230, CFile::begin); - int programMapOffset = ReadShort(); - m_ifoFile.Seek(pcgITPosition + chainOffset + 0xE8, CFile::begin); - int cellTableOffset = ReadShort(); - REFERENCE_TIME rtDuration = 0; - m_pChapters[0] = 0; - for (BYTE currentProgram = 0; currentProgram < programChainPrograms; currentProgram++) { - m_ifoFile.Seek(pcgITPosition + chainOffset + programMapOffset + currentProgram, CFile::begin); - byte entryCell = ReadByte(); - byte exitCell = entryCell; - if (currentProgram < (programChainPrograms - 1)) { - m_ifoFile.Seek(pcgITPosition + chainOffset + programMapOffset + (currentProgram + 1), CFile::begin); - exitCell = ReadByte() - 1; - } - - REFERENCE_TIME rtTotalTime = 0; - for (int currentCell = entryCell; currentCell <= exitCell; currentCell++) { - int cellStart = cellTableOffset + ((currentCell - 1) * 0x18); - m_ifoFile.Seek(pcgITPosition + chainOffset + cellStart, CFile::begin); - BYTE bytes[4]; - ReadBuffer(bytes, 4); - int cellType = bytes[0] >> 6; - if (cellType == 0x00 || cellType == 0x01) { - m_ifoFile.Seek(pcgITPosition + chainOffset + cellStart + 4, CFile::begin); - ReadBuffer(bytes, 4); - short frames = GetFrames(bytes[3]); - int fpsMask = bytes[3] >> 6; - double fps = fpsMask == 0x01 ? 25 : fpsMask == 0x03 ? (30 / 1.001) : 0; - CString tmp; - int hours = bytes[0]; - tmp.Format(_T("%x"), hours); - _stscanf_s(tmp, _T("%d"), &hours); - int minutes = bytes[1]; - tmp.Format(_T("%x"), minutes); - _stscanf_s(tmp, _T("%d"), &minutes); - int seconds = bytes[2]; - tmp.Format(_T("%x"), seconds); - _stscanf_s(tmp, _T("%d"), &seconds); - int mmseconds = 0; - if (fps != 0) { - mmseconds = (int)(1000 * frames / fps); - } - - REFERENCE_TIME rtCurrentTime = 10000i64 * (((hours * 60 + minutes) * 60 + seconds) * 1000 + mmseconds); - rtTotalTime += rtCurrentTime; - } - } - rtDuration += rtTotalTime; - m_pChapters[currentProgram + 1] = rtDuration; - } - } - catch (...) { - m_ifoFile.Close(); - ASSERT(FALSE); - return false; - } - - m_ifoFile.Close(); - - int offset = -1; - - vobs.RemoveAll(); - - fn = fn.Left(fn.ReverseFind('.') + 1); - fn.TrimRight(_T(".0123456789")); - for (int i = 0; i < 100; i++) { - CString vob; - vob.Format(_T("%s%d.vob"), fn.GetString(), i); - - CFileStatus status; - try { - if (!CFile::GetStatus(vob, status)) { - if (i == 0) { - continue; - } - else { - break; - } - } - } - catch (...) { - break; - } - - if (status.m_size & 0x7ff) { - vobs.RemoveAll(); - break; - } - - if (status.m_size > 0) { - vobs.AddTail(vob); - } - - if (i == 0) { - offset = (int)(status.m_size / 0x800); - } - } - - return Open(vobs, offset, bAuthenticate); -} - -bool CVobFile::Open(const CAtlList& vobs, int offset /*= -1*/, bool bAuthenticate /*= true*/) -{ - Close(); - - if (vobs.IsEmpty()) { - return false; - } - - m_offsetAuth = offset; - if (vobs.GetCount() == 1) { - m_offsetAuth = -1; - } - m_offset = std::max(m_offsetAuth, 0); - - POSITION pos = vobs.GetHeadPosition(); - while (pos) { - CString fn = vobs.GetNext(pos); - - WIN32_FIND_DATA fd; - HANDLE h = FindFirstFile(fn, &fd); - if (h == INVALID_HANDLE_VALUE) { - m_files.RemoveAll(); - return false; - } - FindClose(h); - - file_t f; - f.fn = fn; - f.size = (int)(((__int64(fd.nFileSizeHigh) << 32) | fd.nFileSizeLow) / 2048); - m_files.Add(f); - - m_size += f.size; - } - - return bAuthenticate ? Authenticate() : true; -} - -bool CVobFile::Authenticate() -{ - m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false; - - if (!m_files.IsEmpty() && CDVDSession::Open(m_files[0].fn)) { - for (size_t i = 0; !m_fHasTitleKey && i < m_files.GetCount(); i++) { - if (BeginSession()) { - m_fDVD = true; - CDVDSession::Authenticate(); - m_fHasDiscKey = GetDiscKey(); - EndSession(); - } else { - CString fn = m_files[0].fn; - fn.MakeLower(); - - if (fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM) { - m_fDVD = true; - } - - break; - } - - if (tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(_T(':')) + 1)))) { - DWORD start, end; - if (udf_get_lba(m_hDrive, f, &start, &end)) { - if (BeginSession()) { - CDVDSession::Authenticate(); - m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey); - EndSession(); - } - } - - udf_free(f); - } - - BYTE key[5]; - if (HasTitleKey(key) && i == 0 && m_offsetAuth >= 0) { - i++; - - if (BeginSession()) { - m_fDVD = true; - CDVDSession::Authenticate(); - m_fHasDiscKey = GetDiscKey(); - EndSession(); - } else { - break; - } - - if (tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(_T(':')) + 1)))) { - DWORD start, end; - if (udf_get_lba(m_hDrive, f, &start, &end)) { - if (BeginSession()) { - CDVDSession::Authenticate(); - m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey); - EndSession(); - } - } - - udf_free(f); - } - - if (!m_fHasTitleKey) { - memcpy(m_TitleKey, key, 5); - m_fHasTitleKey = true; - } - } - } - } - - /*if(!m_files.IsEmpty() && !m_fDVD) { - CString fn = m_files[0].fn; - fn.MakeLower(); - - if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM) - { - m_fDVD = true; - } - }*/ - - return true; -} - -void CVobFile::Close() -{ - CDVDSession::Close(); - m_files.RemoveAll(); - m_iFile = -1; - m_pos = m_size = m_offset = m_offsetAuth = 0; - m_file.Close(); - m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false; -} - -int CVobFile::GetLength() const -{ - return (m_size - m_offset); -} - -int CVobFile::GetPosition() const -{ - return (m_pos - m_offset); -} - -int CVobFile::Seek(int pos) -{ - pos = std::min(std::max(pos + m_offset, m_offset), m_size - 1); - - int i = -1; - int size = 0; - - // this suxx, but won't take long - do { - size += m_files[++i].size; - } while (i < (int)m_files.GetCount() && pos >= size); - - if (i != m_iFile && i < (int)m_files.GetCount()) { - if (!m_file.Open(m_files[i].fn)) { - return m_pos; - } - - m_iFile = i; - } - - m_pos = pos; - - pos -= (size - m_files[i].size); - try { - m_file.Seek(pos); - } catch (...) { - return -1; - } - - return GetPosition(); -} - -bool CVobFile::Read(BYTE* buff) -{ - if (m_pos >= m_size) { - return false; - } - - if (m_file.IsOpen() && m_file.GetPositionLBA() == m_file.GetLengthLBA()) { - m_file.Close(); - } - - if (!m_file.IsOpen()) { - if (m_iFile >= (int)m_files.GetCount() - 1) { - return false; - } - - if (!m_file.Open(m_files[++m_iFile].fn)) { - m_iFile = -1; - return false; - } - } - - if (!m_file.Read(buff)) { - // dvd still locked? - return false; - } - - m_pos++; - - if (buff[0x14] & 0x30) { - if (m_fHasTitleKey) { - CSSdescramble(buff, m_TitleKey); - buff[0x14] &= ~0x30; - } else { - // under win9x this is normal, but I'm not developing under win9x :P - ASSERT(0); - } - } - - return true; -} - -BSTR CVobFile::GetTrackName(UINT aTrackIdx) const -{ - CString trackName; - m_pStream_Lang.Lookup(aTrackIdx, trackName); - return trackName.AllocSysString(); -} - -REFERENCE_TIME CVobFile::GetChapterOffset(UINT ChapterNumber) const -{ - REFERENCE_TIME rtChapterOffset = 0; - ASSERT(ChapterNumber < BYTE_MAX); - m_pChapters.Lookup((BYTE)ChapterNumber, rtChapterOffset); - return rtChapterOffset; -} +#include "stdafx.h" +#include +#include +#include "VobFile.h" +#include "CSSauth.h" +#include "CSSscramble.h" +#include "udf.h" + +#include "../DSUtil/GolombBuffer.h" +#include "../DSUtil/DSUtil.h" +#include "../DSUtil/ISOLang.h" + +#define AUDIO_BLOCK_SIZE 66 +#define SUBTITLE_BLOCK_SIZE 194 +#define IFO_HEADER_SIZE 12 +#define VIDEO_TS_HEADER "DVDVIDEO-VMG" +#define VTS_HEADER "DVDVIDEO-VTS" + +// +// CDVDSession +// + +CDVDSession::CDVDSession() + : m_hDrive(INVALID_HANDLE_VALUE) + , m_session(DVD_END_ALL_SESSIONS) +{ + ZeroMemory(m_SessionKey, sizeof(m_SessionKey)); + ZeroMemory(m_DiscKey, sizeof(m_DiscKey)); + ZeroMemory(m_TitleKey, sizeof(m_TitleKey)); +} + +CDVDSession::~CDVDSession() +{ + EndSession(); +} + +bool CDVDSession::Open(LPCTSTR path) +{ + Close(); + + CString fn = path; + CString drive = _T("\\\\.\\") + fn.Left(fn.Find(':') + 1); + + m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); + if (m_hDrive == INVALID_HANDLE_VALUE) { + return false; + } + + return true; +} + +void CDVDSession::Close() +{ + if (m_hDrive != INVALID_HANDLE_VALUE) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + } +} + +bool CDVDSession::BeginSession() +{ + EndSession(); + + if (m_hDrive == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD BytesReturned; + if (!DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, nullptr, 0, &m_session, sizeof(m_session), &BytesReturned, nullptr)) { + m_session = DVD_END_ALL_SESSIONS; + if (!DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), nullptr, 0, &BytesReturned, nullptr) + || !DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, nullptr, 0, &m_session, sizeof(m_session), &BytesReturned, nullptr)) { + Close(); + DWORD err = GetLastError(); + UNREFERENCED_PARAMETER(err); + return false; + } + } + + return true; +} + +void CDVDSession::EndSession() +{ + if (m_session != DVD_END_ALL_SESSIONS) { + DWORD BytesReturned; + DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), nullptr, 0, &BytesReturned, nullptr); + m_session = DVD_END_ALL_SESSIONS; + } +} + +bool CDVDSession::Authenticate() +{ + if (m_session == DVD_END_ALL_SESSIONS) { + return false; + } + + BYTE Challenge[10], Key[10]; + + for (BYTE i = 0; i < 10; i++) { + Challenge[i] = i; + } + + if (!SendKey(DvdChallengeKey, Challenge)) { + return false; + } + + if (!ReadKey(DvdBusKey1, Key)) { + return false; + } + + int varient = -1; + + for (int i = 31; i >= 0; i--) { + BYTE KeyCheck[5]; + CSSkey1(i, Challenge, KeyCheck); + if (!memcmp(KeyCheck, Key, 5)) { + varient = i; + } + } + + if (!ReadKey(DvdChallengeKey, Challenge)) { + return false; + } + + CSSkey2(varient, Challenge, &Key[5]); + + if (!SendKey(DvdBusKey2, &Key[5])) { + return false; + } + + CSSbuskey(varient, Key, m_SessionKey); + + return true; +} + +bool CDVDSession::GetDiscKey() +{ + if (m_session == DVD_END_ALL_SESSIONS) { + return false; + } + + BYTE DiscKeys[2048]; + if (!ReadKey(DvdDiskKey, DiscKeys)) { + return false; + } + + for (int i = 0; i < g_nPlayerKeys; i++) { + for (int j = 1; j < 409; j++) { + BYTE DiscKey[6]; + memcpy(DiscKey, &DiscKeys[j * 5], 5); + DiscKey[5] = 0; + + CSSdisckey(DiscKey, g_PlayerKeys[i]); + + BYTE Hash[6]; + memcpy(Hash, &DiscKeys[0], 5); + Hash[5] = 0; + + CSSdisckey(Hash, DiscKey); + + if (!memcmp(Hash, DiscKey, 6)) { + memcpy(m_DiscKey, DiscKey, 6); + return true; + } + } + } + + return false; +} + +bool CDVDSession::GetTitleKey(int lba, BYTE* pKey) +{ + if (m_session == DVD_END_ALL_SESSIONS) { + return false; + } + + if (!ReadKey(DvdTitleKey, pKey, lba)) { + return false; + } + + if (!(pKey[0] | pKey[1] | pKey[2] | pKey[3] | pKey[4])) { + return false; + } + + pKey[5] = 0; + + CSStitlekey(pKey, m_DiscKey); + + return true; +} + +static void Reverse(BYTE* d, BYTE* s, int len) +{ + if (d == s) { + for (s += len - 1; d < s; d++, s--) { + *d ^= *s, *s ^= *d, *d ^= *s; + } + } else { + for (int i = 0; i < len; i++) { + d[i] = s[len - 1 - i]; + } + } +} + +bool CDVDSession::SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData) +{ + CAutoVectorPtr key; + DVD_COPY_PROTECT_KEY* pKey = nullptr; + + auto allocateKey = [&](ULONG len) { + bool bSuccess = key.Allocate(len); + if (bSuccess) { + pKey = (DVD_COPY_PROTECT_KEY*)(BYTE*)key; + pKey->KeyLength = len; + } + return bSuccess; + }; + + switch (KeyType) { + case DvdChallengeKey: + if (allocateKey(DVD_CHALLENGE_KEY_LENGTH)) { + Reverse(pKey->KeyData, pKeyData, 10); + } + break; + case DvdBusKey2: + if (allocateKey(DVD_BUS_KEY_LENGTH)) { + Reverse(pKey->KeyData, pKeyData, 5); + } + break; + default: + break; + } + + if (!pKey) { + return false; + } + + pKey->SessionId = m_session; + pKey->KeyType = KeyType; + pKey->KeyFlags = 0; + + DWORD dwBytesReturned; + return !!DeviceIoControl(m_hDrive, IOCTL_DVD_SEND_KEY, pKey, pKey->KeyLength, nullptr, 0, &dwBytesReturned, nullptr); +} + +bool CDVDSession::ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba) +{ + CAutoVectorPtr key; + DVD_COPY_PROTECT_KEY* pKey = nullptr; + + auto allocateKey = [&](ULONG len) { + bool bSuccess = key.Allocate(len); + if (bSuccess) { + pKey = (DVD_COPY_PROTECT_KEY*)(BYTE*)key; + pKey->KeyLength = len; + } + return bSuccess; + }; + + switch (KeyType) { + case DvdChallengeKey: + if (allocateKey(DVD_CHALLENGE_KEY_LENGTH)) { + pKey->Parameters.TitleOffset.QuadPart = 0; + } + break; + case DvdBusKey1: + if (allocateKey(DVD_BUS_KEY_LENGTH)) { + pKey->Parameters.TitleOffset.QuadPart = 0; + } + break; + case DvdDiskKey: + if (allocateKey(DVD_DISK_KEY_LENGTH)) { + pKey->Parameters.TitleOffset.QuadPart = 0; + } + break; + case DvdTitleKey: + if (allocateKey(DVD_TITLE_KEY_LENGTH)) { + pKey->Parameters.TitleOffset.QuadPart = 2048i64 * lba; + } + break; + default: + break; + } + + if (!pKey) { + return false; + } + + pKey->SessionId = m_session; + pKey->KeyType = KeyType; + pKey->KeyFlags = 0; + + DWORD dwBytesReturned; + if (!DeviceIoControl(m_hDrive, IOCTL_DVD_READ_KEY, pKey, pKey->KeyLength, pKey, pKey->KeyLength, &dwBytesReturned, nullptr)) { + DWORD err = GetLastError(); + UNREFERENCED_PARAMETER(err); + return false; + } + + switch (KeyType) { + case DvdChallengeKey: + Reverse(pKeyData, pKey->KeyData, 10); + break; + case DvdBusKey1: + Reverse(pKeyData, pKey->KeyData, 5); + break; + case DvdDiskKey: + memcpy(pKeyData, pKey->KeyData, 2048); + for (int i = 0; i < 2048 / 5; i++) { + pKeyData[i] ^= m_SessionKey[4 - (i % 5)]; + } + break; + case DvdTitleKey: + memcpy(pKeyData, pKey->KeyData, 5); + for (int i = 0; i < 5; i++) { + pKeyData[i] ^= m_SessionKey[4 - (i % 5)]; + } + break; + default: + break; + } + + return true; +} + +// +// CLBAFile +// + +CLBAFile::CLBAFile() +{ +} + +CLBAFile::~CLBAFile() +{ +} + +bool CLBAFile::IsOpen() const +{ + return (m_hFile != hFileNull); +} + +bool CLBAFile::Open(LPCTSTR path) +{ + Close(); + + return !!CFile::Open(path, modeRead | typeBinary | shareDenyNone | osSequentialScan); +} + +void CLBAFile::Close() +{ + if (m_hFile != hFileNull) { + CFile::Close(); + } +} + +int CLBAFile::GetLengthLBA() const +{ + return (int)(CFile::GetLength() / 2048); +} + +int CLBAFile::GetPositionLBA() const +{ + return (int)(CFile::GetPosition() / 2048); +} + +int CLBAFile::Seek(int lba) +{ + return (int)(CFile::Seek(2048i64 * lba, CFile::begin) / 2048); +} + +bool CLBAFile::Read(BYTE* buff) +{ + return CFile::Read(buff, 2048) == 2048; +} + +// +// CVobFile +// + +CVobFile::CVobFile() +{ + Close(); + m_iChaptersCount = -1; +} + +CVobFile::~CVobFile() +{ +} + +bool CVobFile::IsDVD() const +{ + return m_fDVD; +} + +bool CVobFile::HasDiscKey(BYTE* key) const +{ + if (key) { + memcpy(key, m_DiscKey, 5); + } + return m_fHasDiscKey; +} + +bool CVobFile::HasTitleKey(BYTE* key) const +{ + if (key) { + memcpy(key, m_TitleKey, 5); + } + return m_fHasTitleKey; +} + +DWORD CVobFile::ReadDword() +{ + return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte(); +} + +short CVobFile::ReadShort() +{ + return (ReadByte() << 8 | ReadByte()); +} + +BYTE CVobFile::ReadByte() +{ + BYTE bVal; + m_ifoFile.Read(&bVal, sizeof(bVal)); + return bVal; +} + +void CVobFile::ReadBuffer(BYTE* pBuff, DWORD nLen) +{ + m_ifoFile.Read(pBuff, nLen); +} + +static short GetFrames(byte val) +{ + int byte0_high = val >> 4; + int byte0_low = val & 0x0F; + if (byte0_high > 11) { + return (short)(((byte0_high - 12) * 10) + byte0_low); + } + if ((byte0_high <= 3) || (byte0_high >= 8)) { + return 0; + } + return (short)(((byte0_high - 4) * 10) + byte0_low); +} + +bool CVobFile::GetTitleInfo(LPCTSTR fn, ULONG nTitleNum, ULONG& VTSN, ULONG& TTN) +{ + CFile ifoFile; + if (!ifoFile.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + + char hdr[IFO_HEADER_SIZE + 1]; + ifoFile.Read(hdr, IFO_HEADER_SIZE); + hdr[IFO_HEADER_SIZE] = '\0'; + if (strcmp(hdr, VIDEO_TS_HEADER)) { + return false; + } + + ifoFile.Seek(0xC4, CFile::begin); + DWORD TT_SRPTPosition; // Read a 32-bit unsigned big-endian integer + ifoFile.Read(&TT_SRPTPosition, sizeof(TT_SRPTPosition)); + TT_SRPTPosition = _byteswap_ulong(TT_SRPTPosition); + TT_SRPTPosition *= 2048; + ifoFile.Seek(TT_SRPTPosition + 8 + (nTitleNum - 1) * 12 + 6, CFile::begin); + BYTE tmp; + ifoFile.Read(&tmp, sizeof(tmp)); + VTSN = tmp; + ifoFile.Read(&tmp, sizeof(tmp)); + TTN = tmp; + + ifoFile.Close(); + + return true; +} + +bool CVobFile::Open(CString fn, CAtlList& vobs, ULONG nProgNum /*= 1*/, bool bAuthenticate /*= true*/) +{ + if (!m_ifoFile.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + + try { + char hdr[IFO_HEADER_SIZE + 1]; + m_ifoFile.Read(hdr, IFO_HEADER_SIZE); + hdr[IFO_HEADER_SIZE] = '\0'; + if (strcmp(hdr, VTS_HEADER)) { + return false; + } + + // Audio streams ... + m_ifoFile.Seek(0x202, CFile::begin); + BYTE buffer[SUBTITLE_BLOCK_SIZE]; + m_ifoFile.Read(buffer, AUDIO_BLOCK_SIZE); + CGolombBuffer gb(buffer, AUDIO_BLOCK_SIZE); + int stream_count = gb.ReadShort(); + for (int i = 0; i < std::min(stream_count, 8); i++) { + BYTE Coding_mode = (BYTE)gb.BitRead(3); + gb.BitRead(5);// skip + int ToAdd = 0; + switch (Coding_mode) { + case 0: + ToAdd = 0x80; + break; + case 4: + ToAdd = 0xA0; + break; + case 6: + ToAdd = 0x88; + break; + default: + break; + } + gb.ReadByte();// skip + char lang[2]; + gb.ReadBuffer((BYTE*)lang, 2); + gb.ReadDword();// skip + if (ToAdd) { + m_pStream_Lang[ToAdd + i] = ISOLang::ISO6391ToLanguage(lang); + } + } + + // Subtitle streams ... + m_ifoFile.Seek(0x254, CFile::begin); + m_ifoFile.Read(buffer, SUBTITLE_BLOCK_SIZE); + CGolombBuffer gb_s(buffer, SUBTITLE_BLOCK_SIZE); + stream_count = gb_s.ReadShort(); + for (int i = 0; i < std::min(stream_count, 32); i++) { + gb_s.ReadShort(); + char lang[2]; + gb_s.ReadBuffer((BYTE*)lang, 2); + gb_s.ReadShort(); + m_pStream_Lang[0x20 + i] = ISOLang::ISO6391ToLanguage(lang); + } + + // Chapters ... + m_ifoFile.Seek(0xCC, CFile::begin); //Get VTS_PGCI address + DWORD pcgITPosition = ReadDword() * 2048; + m_ifoFile.Seek(pcgITPosition, CFile::begin); + WORD nProgCount = (WORD)ReadShort(); + if (nProgNum > nProgCount) { + return false; + } + m_ifoFile.Seek(pcgITPosition + 8 * nProgNum + 4, CFile::begin); + DWORD chainOffset = ReadDword(); + m_ifoFile.Seek(pcgITPosition + chainOffset + 2, CFile::begin); + BYTE programChainPrograms = ReadByte(); + m_iChaptersCount = programChainPrograms; + m_ifoFile.Seek(pcgITPosition + chainOffset + 230, CFile::begin); + int programMapOffset = ReadShort(); + m_ifoFile.Seek(pcgITPosition + chainOffset + 0xE8, CFile::begin); + int cellTableOffset = ReadShort(); + REFERENCE_TIME rtDuration = 0; + m_pChapters[0] = 0; + for (BYTE currentProgram = 0; currentProgram < programChainPrograms; currentProgram++) { + m_ifoFile.Seek(pcgITPosition + chainOffset + programMapOffset + currentProgram, CFile::begin); + byte entryCell = ReadByte(); + byte exitCell = entryCell; + if (currentProgram < (programChainPrograms - 1)) { + m_ifoFile.Seek(pcgITPosition + chainOffset + programMapOffset + (currentProgram + 1), CFile::begin); + exitCell = ReadByte() - 1; + } + + REFERENCE_TIME rtTotalTime = 0; + for (int currentCell = entryCell; currentCell <= exitCell; currentCell++) { + int cellStart = cellTableOffset + ((currentCell - 1) * 0x18); + m_ifoFile.Seek(pcgITPosition + chainOffset + cellStart, CFile::begin); + BYTE bytes[4]; + ReadBuffer(bytes, 4); + int cellType = bytes[0] >> 6; + if (cellType == 0x00 || cellType == 0x01) { + m_ifoFile.Seek(pcgITPosition + chainOffset + cellStart + 4, CFile::begin); + ReadBuffer(bytes, 4); + short frames = GetFrames(bytes[3]); + int fpsMask = bytes[3] >> 6; + double fps = fpsMask == 0x01 ? 25 : fpsMask == 0x03 ? (30 / 1.001) : 0; + CString tmp; + int hours = bytes[0]; + tmp.Format(_T("%x"), hours); + _stscanf_s(tmp, _T("%d"), &hours); + int minutes = bytes[1]; + tmp.Format(_T("%x"), minutes); + _stscanf_s(tmp, _T("%d"), &minutes); + int seconds = bytes[2]; + tmp.Format(_T("%x"), seconds); + _stscanf_s(tmp, _T("%d"), &seconds); + int mmseconds = 0; + if (fps != 0) { + mmseconds = (int)(1000 * frames / fps); + } + + REFERENCE_TIME rtCurrentTime = 10000i64 * (((hours * 60 + minutes) * 60 + seconds) * 1000 + mmseconds); + rtTotalTime += rtCurrentTime; + } + } + rtDuration += rtTotalTime; + m_pChapters[currentProgram + 1] = rtDuration; + } + } + catch (...) { + m_ifoFile.Close(); + ASSERT(FALSE); + return false; + } + + m_ifoFile.Close(); + + int offset = -1; + + vobs.RemoveAll(); + + fn = fn.Left(fn.ReverseFind('.') + 1); + fn.TrimRight(_T(".0123456789")); + for (int i = 0; i < 100; i++) { + CString vob; + vob.Format(_T("%s%d.vob"), fn.GetString(), i); + + CFileStatus status; + try { + if (!CFile::GetStatus(vob, status)) { + if (i == 0) { + continue; + } + else { + break; + } + } + } + catch (...) { + break; + } + + if (status.m_size & 0x7ff) { + vobs.RemoveAll(); + break; + } + + if (status.m_size > 0) { + vobs.AddTail(vob); + } + + if (i == 0) { + offset = (int)(status.m_size / 0x800); + } + } + + return Open(vobs, offset, bAuthenticate); +} + +bool CVobFile::Open(const CAtlList& vobs, int offset /*= -1*/, bool bAuthenticate /*= true*/) +{ + Close(); + + if (vobs.IsEmpty()) { + return false; + } + + m_offsetAuth = offset; + if (vobs.GetCount() == 1) { + m_offsetAuth = -1; + } + m_offset = std::max(m_offsetAuth, 0); + + POSITION pos = vobs.GetHeadPosition(); + while (pos) { + CString fn = vobs.GetNext(pos); + + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile(fn, &fd); + if (h == INVALID_HANDLE_VALUE) { + m_files.RemoveAll(); + return false; + } + FindClose(h); + + file_t f; + f.fn = fn; + f.size = (int)(((__int64(fd.nFileSizeHigh) << 32) | fd.nFileSizeLow) / 2048); + m_files.Add(f); + + m_size += f.size; + } + + return bAuthenticate ? Authenticate() : true; +} + +bool CVobFile::Authenticate() +{ + m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false; + + if (!m_files.IsEmpty() && CDVDSession::Open(m_files[0].fn)) { + for (size_t i = 0; !m_fHasTitleKey && i < m_files.GetCount(); i++) { + if (BeginSession()) { + m_fDVD = true; + CDVDSession::Authenticate(); + m_fHasDiscKey = GetDiscKey(); + EndSession(); + } else { + CString fn = m_files[0].fn; + fn.MakeLower(); + + if (fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM) { + m_fDVD = true; + } + + break; + } + + if (tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(_T(':')) + 1)))) { + DWORD start, end; + if (udf_get_lba(m_hDrive, f, &start, &end)) { + if (BeginSession()) { + CDVDSession::Authenticate(); + m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey); + EndSession(); + } + } + + udf_free(f); + } + + BYTE key[5]; + if (HasTitleKey(key) && i == 0 && m_offsetAuth >= 0) { + i++; + + if (BeginSession()) { + m_fDVD = true; + CDVDSession::Authenticate(); + m_fHasDiscKey = GetDiscKey(); + EndSession(); + } else { + break; + } + + if (tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(_T(':')) + 1)))) { + DWORD start, end; + if (udf_get_lba(m_hDrive, f, &start, &end)) { + if (BeginSession()) { + CDVDSession::Authenticate(); + m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey); + EndSession(); + } + } + + udf_free(f); + } + + if (!m_fHasTitleKey) { + memcpy(m_TitleKey, key, 5); + m_fHasTitleKey = true; + } + } + } + } + + /*if(!m_files.IsEmpty() && !m_fDVD) { + CString fn = m_files[0].fn; + fn.MakeLower(); + + if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM) + { + m_fDVD = true; + } + }*/ + + return true; +} + +void CVobFile::Close() +{ + CDVDSession::Close(); + m_files.RemoveAll(); + m_iFile = -1; + m_pos = m_size = m_offset = m_offsetAuth = 0; + m_file.Close(); + m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false; +} + +int CVobFile::GetLength() const +{ + return (m_size - m_offset); +} + +int CVobFile::GetPosition() const +{ + return (m_pos - m_offset); +} + +int CVobFile::Seek(int pos) +{ + pos = std::min(std::max(pos + m_offset, m_offset), m_size - 1); + + int i = -1; + int size = 0; + + // this suxx, but won't take long + do { + size += m_files[++i].size; + } while (i < (int)m_files.GetCount() && pos >= size); + + if (i != m_iFile && i < (int)m_files.GetCount()) { + if (!m_file.Open(m_files[i].fn)) { + return m_pos; + } + + m_iFile = i; + } + + m_pos = pos; + + pos -= (size - m_files[i].size); + try { + m_file.Seek(pos); + } catch (...) { + return -1; + } + + return GetPosition(); +} + +bool CVobFile::Read(BYTE* buff) +{ + if (m_pos >= m_size) { + return false; + } + + if (m_file.IsOpen() && m_file.GetPositionLBA() == m_file.GetLengthLBA()) { + m_file.Close(); + } + + if (!m_file.IsOpen()) { + if (m_iFile >= (int)m_files.GetCount() - 1) { + return false; + } + + if (!m_file.Open(m_files[++m_iFile].fn)) { + m_iFile = -1; + return false; + } + } + + if (!m_file.Read(buff)) { + // dvd still locked? + return false; + } + + m_pos++; + + if (buff[0x14] & 0x30) { + if (m_fHasTitleKey) { + CSSdescramble(buff, m_TitleKey); + buff[0x14] &= ~0x30; + } else { + // under win9x this is normal, but I'm not developing under win9x :P + ASSERT(0); + } + } + + return true; +} + +BSTR CVobFile::GetTrackName(UINT aTrackIdx) const +{ + CString trackName; + m_pStream_Lang.Lookup(aTrackIdx, trackName); + return trackName.AllocSysString(); +} + +REFERENCE_TIME CVobFile::GetChapterOffset(UINT ChapterNumber) const +{ + REFERENCE_TIME rtChapterOffset = 0; + ASSERT(ChapterNumber < BYTE_MAX); + m_pChapters.Lookup((BYTE)ChapterNumber, rtChapterOffset); + return rtChapterOffset; +} diff --git a/src/DeCSS/VobFile.h b/src/DeCSS/VobFile.h index 88f6093a6dd..08ef0e2e492 100644 --- a/src/DeCSS/VobFile.h +++ b/src/DeCSS/VobFile.h @@ -1,107 +1,107 @@ -#pragma once - -#include -#include -#include "winddk/ntddcdvd.h" - -class CDVDSession -{ -protected: - HANDLE m_hDrive; - - DVD_SESSION_ID m_session; - bool BeginSession(); - void EndSession(); - - BYTE m_SessionKey[5]; - bool Authenticate(); - - BYTE m_DiscKey[6], m_TitleKey[6]; - bool GetDiscKey(); - bool GetTitleKey(int lba, BYTE* pKey); - -public: - CDVDSession(); - virtual ~CDVDSession(); - - bool Open(LPCTSTR path); - void Close(); - - operator HANDLE() const { return m_hDrive; } - operator DVD_SESSION_ID() const { return m_session; } - - bool SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData); - bool ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba = 0); -}; - -class CLBAFile : private CFile -{ -public: - CLBAFile(); - virtual ~CLBAFile(); - - bool IsOpen() const; - - bool Open(LPCTSTR path); - void Close(); - - int GetLengthLBA() const; - int GetPositionLBA() const; - int Seek(int lba); - bool Read(BYTE* buff); -}; - -class CVobFile : public CDVDSession -{ - // all files - struct file_t { - CString fn; - int size; - }; - - CAtlArray m_files; - int m_iFile; - int m_pos, m_size, m_offset, m_offsetAuth; - - // currently opened file - CLBAFile m_file; - - // attribs - bool m_fDVD, m_fHasDiscKey, m_fHasTitleKey; - - CAtlMap m_pStream_Lang; - - int m_iChaptersCount; - CAtlMap m_pChapters; -public: - CVobFile(); - virtual ~CVobFile(); - - static bool GetTitleInfo(LPCTSTR fn, ULONG nTitleNum, ULONG& VTSN /* out */, ULONG& TTN /* out */); // video_ts.ifo - - bool IsDVD() const; - bool HasDiscKey(BYTE* key) const; - bool HasTitleKey(BYTE* key) const; - - bool Open(CString fn, CAtlList& files /* out */, ULONG nProgNum = 1, bool bAuthenticate = true); // vts ifo - bool Open(const CAtlList& files, int offset = -1, bool bAuthenticate = true); // vts vobs, video vob offset in lba - bool Authenticate(); - void Close(); - - int GetLength() const; - int GetPosition() const; - int Seek(int pos); - bool Read(BYTE* buff); - - BSTR GetTrackName(UINT aTrackIdx) const; - - int GetChaptersCount() const { return m_iChaptersCount; } - LONGLONG GetChapterOffset(UINT chapterNumber) const; - -private: - CFile m_ifoFile; - DWORD ReadDword(); - short ReadShort(); - BYTE ReadByte(); - void ReadBuffer(BYTE* pBuff, DWORD nLen); -}; +#pragma once + +#include +#include +#include "winddk/ntddcdvd.h" + +class CDVDSession +{ +protected: + HANDLE m_hDrive; + + DVD_SESSION_ID m_session; + bool BeginSession(); + void EndSession(); + + BYTE m_SessionKey[5]; + bool Authenticate(); + + BYTE m_DiscKey[6], m_TitleKey[6]; + bool GetDiscKey(); + bool GetTitleKey(int lba, BYTE* pKey); + +public: + CDVDSession(); + virtual ~CDVDSession(); + + bool Open(LPCTSTR path); + void Close(); + + operator HANDLE() const { return m_hDrive; } + operator DVD_SESSION_ID() const { return m_session; } + + bool SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData); + bool ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba = 0); +}; + +class CLBAFile : private CFile +{ +public: + CLBAFile(); + virtual ~CLBAFile(); + + bool IsOpen() const; + + bool Open(LPCTSTR path); + void Close(); + + int GetLengthLBA() const; + int GetPositionLBA() const; + int Seek(int lba); + bool Read(BYTE* buff); +}; + +class CVobFile : public CDVDSession +{ + // all files + struct file_t { + CString fn; + int size; + }; + + CAtlArray m_files; + int m_iFile; + int m_pos, m_size, m_offset, m_offsetAuth; + + // currently opened file + CLBAFile m_file; + + // attribs + bool m_fDVD, m_fHasDiscKey, m_fHasTitleKey; + + CAtlMap m_pStream_Lang; + + int m_iChaptersCount; + CAtlMap m_pChapters; +public: + CVobFile(); + virtual ~CVobFile(); + + static bool GetTitleInfo(LPCTSTR fn, ULONG nTitleNum, ULONG& VTSN /* out */, ULONG& TTN /* out */); // video_ts.ifo + + bool IsDVD() const; + bool HasDiscKey(BYTE* key) const; + bool HasTitleKey(BYTE* key) const; + + bool Open(CString fn, CAtlList& files /* out */, ULONG nProgNum = 1, bool bAuthenticate = true); // vts ifo + bool Open(const CAtlList& files, int offset = -1, bool bAuthenticate = true); // vts vobs, video vob offset in lba + bool Authenticate(); + void Close(); + + int GetLength() const; + int GetPosition() const; + int Seek(int pos); + bool Read(BYTE* buff); + + BSTR GetTrackName(UINT aTrackIdx) const; + + int GetChaptersCount() const { return m_iChaptersCount; } + LONGLONG GetChapterOffset(UINT chapterNumber) const; + +private: + CFile m_ifoFile; + DWORD ReadDword(); + short ReadShort(); + BYTE ReadByte(); + void ReadBuffer(BYTE* pBuff, DWORD nLen); +}; diff --git a/src/DeCSS/stdafx.cpp b/src/DeCSS/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/DeCSS/stdafx.cpp +++ b/src/DeCSS/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/DeCSS/stdafx.h b/src/DeCSS/stdafx.h index 3c373d921ec..377c0d5ea46 100644 --- a/src/DeCSS/stdafx.h +++ b/src/DeCSS/stdafx.h @@ -1,32 +1,32 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components -#include "BaseClasses/streams.h" +/* + * (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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components +#include "BaseClasses/streams.h" diff --git a/src/DeCSS/udf.cpp b/src/DeCSS/udf.cpp index 10b6ed2445d..ac1e08786a5 100644 --- a/src/DeCSS/udf.cpp +++ b/src/DeCSS/udf.cpp @@ -1,352 +1,352 @@ -/************************************************************************* - vStrip by [maven] (maven@maven.de) - udf.c: routines for udf-parsing (because windows just doesn't cut it), - refs: udf102.pdf, udf200.pdf -*************************************************************************/ - -#include "stdafx.h" -#include "udf.h" - -static bool aspi_GetSectorInfo(const HANDLE hDrive, DWORD* sec_size, DWORD* max_sec) -{ - LARGE_INTEGER size = {0, 0}; - GetFileSizeEx(hDrive, &size); - - *sec_size = 2048; - *max_sec = (DWORD)(size.QuadPart / *sec_size); - - return true; -} - -static bool aspi_ReadSectors(const HANDLE hDrive, int lba, int nSectors, DWORD sec_size, BYTE* sector) -{ - DWORD nbr = 0; - LARGE_INTEGER offset; - offset.QuadPart = lba*sec_size; - SetFilePointerEx(hDrive, offset, &offset, FILE_BEGIN); - return lba*sec_size == offset.QuadPart && ReadFile(hDrive, sector, nSectors*sec_size, &nbr, nullptr); -} - -static bool udf_GetLBA(const tp_udf_FileEntry fe, const DWORD sec_size, DWORD *start, DWORD *end) -{ - if (fe->LengthofAllocationDescriptors == 0) { - return false; - } - switch (fe->ICBTag.Flags & udf_icbf_Mask) { - case udf_icbf_ShortAd: { - tp_udf_short_ad ad = (tp_udf_short_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); - - *start = ad->Location; - *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; - return true; - } - break; - case udf_icbf_LongAd: { - tp_udf_long_ad ad = (tp_udf_long_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); - - *start = ad->Location.Location; // ignore partition number - *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; - return true; - } - break; - case udf_icbf_ExtAd: { - tp_udf_ext_ad ad = (tp_udf_ext_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); - - *start = ad->Location.Location; // ignore partition number - *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; - return true; - } - break; - } - return false; -} - -tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number) -{ - BYTE sector[fio_SECTOR_SIZE]; - tp_udf_tag tag = (tp_udf_tag)sector; - DWORD sec_size, max_sec, i; - DWORD MVDS_lba, MVDS_lba_end, MVDS_back_lba, MVDS_back_lba_end; - DWORD FileDescriptorSequence_lba = 0; - DWORD partition_lba = 0; - tp_udf_AnchorVolumeDescriptorPointer avd; - bool res, part_valid, vol_valid; - - if (!aspi_GetSectorInfo(hDrive, &sec_size, &max_sec)) { - return nullptr; - } - - if (sec_size != fio_SECTOR_SIZE || max_sec < 256) { - return nullptr; - } - - // read AnchorVolumeDescriptorPointer at 256 (or MaxSec) (Tag == 2) - res = aspi_ReadSectors(hDrive, 256, 1, sec_size, sector); - if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor) { - res = aspi_ReadSectors(hDrive, max_sec, 1, sec_size, sector); - if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor) { - return nullptr; - } - } - - // check Static Structures - - // get MainVolumeDescriptorSequence Location & Length - avd = (tp_udf_AnchorVolumeDescriptorPointer)sector; - MVDS_lba = avd->MainVolumeDescriptorSequenceExtent.Location; - MVDS_lba_end = MVDS_lba + (avd->MainVolumeDescriptorSequenceExtent.Length - 1) / sec_size; - MVDS_back_lba = avd->ReserveVolumeDescriptorSequenceExtent.Location; - MVDS_back_lba_end = MVDS_back_lba + (avd->ReserveVolumeDescriptorSequenceExtent.Length - 1) / sec_size; - - // read MVDS_Location..MVDS_Location + (MVDS_Length - 1) / SectorSize sectors - - part_valid = vol_valid = false; - i = 1; - do { - // try twice (if we need to) for ReserveAnchor - DWORD j = MVDS_lba; - do { - res = aspi_ReadSectors(hDrive, j++, 1, sec_size, sector); - if (res) { - if (tag->TagIdentifier == udf_TAG_PartitionDescriptor && !part_valid) { - // get stuff out of partition - tp_udf_PartitionDescriptor par = (tp_udf_PartitionDescriptor )sector; - - part_valid = par->PartitionNumber == partition_number; - if (part_valid) { - // extract par->PartitionStartingLocation, par->PartitionLength - partition_lba = par->PartitionStartingLocation; - } - } else if (tag->TagIdentifier == udf_TAG_LogicalVolumeDescriptor && !vol_valid) { - // get stuff out of volume - tp_udf_LogicalVolumeDescriptor vol = (tp_udf_LogicalVolumeDescriptor)sector; - - // check_volume sector size - vol_valid = (vol->LogicalBlockSize == sec_size) && (partition_number == vol->FileSetDescriptorSequence.Location.PartitionNumber); - if (vol_valid) { - // extract vol->FileSetDescriptorSequence - FileDescriptorSequence_lba = vol->FileSetDescriptorSequence.Location.Location; - // DWORD FileDescriptorSequence_lba_end = FileDescriptorSequence_lba + ((vol->FileSetDescriptorSequence.Length & udf_LengthMask) - 1) / sec_size; - } - } - } else { - tag->TagIdentifier = 0; - } - } while (j <= MVDS_lba_end && tag->TagIdentifier != udf_TAG_TerminatingDescriptor && ((!part_valid) || (!vol_valid))); - - if ((!part_valid) || (!vol_valid)) { - // try backup - MVDS_lba = MVDS_back_lba; - MVDS_lba_end = MVDS_back_lba_end; - } - } while (i-- && ((!part_valid) || (!vol_valid))); - - if (part_valid && vol_valid) { - // read FileSetDescriptor, get RootDir Location & Length, RootDir Length != 0 - res = aspi_ReadSectors(hDrive, FileDescriptorSequence_lba + partition_lba, 1, sec_size, sector); - if (res && tag->TagIdentifier == udf_TAG_FileSetDescriptor) { - tp_udf_FileSetDescriptor fsd = (tp_udf_FileSetDescriptor)sector; - - if (partition_number == fsd->RootDirectoryICB.Location.PartitionNumber) { - DWORD parent_icb = fsd->RootDirectoryICB.Location.Location; - res = aspi_ReadSectors(hDrive, partition_lba + parent_icb, 1, sec_size, sector); - if (res && tag->TagIdentifier == udf_TAG_FileEntry) { - tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; - - if (fe->ICBTag.FileType == udf_FT_Directory) { - tp_udf_file root = (tp_udf_file)malloc(sizeof *root); - - root->partition_lba = partition_lba; - udf_GetLBA(fe, sec_size, &root->dir_lba, &root->dir_end_lba); - root->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb - root->sector = nullptr; - root->fid = nullptr; - root->sec_size = sec_size; - strcpy_s(root->name, "/"); - root->is_dir = true; - root->is_parent = false; - return root; - } - } - } - } - } - - return nullptr; -} - -static void udf_GetName(const BYTE *data, const DWORD len, char *target) -{ - DWORD p = 1, i = 0; - - if (len == 0 || !(data[0] & 0x18)) { - target[0] = '\0'; - } - - if (data[0] & 0x10) { - // ignore MSB of unicode16 - p++; - - while (p < len) { - target[i++] = data[p += 2]; - } - } else { - while (p < len) { - target[i++] = data[p++]; - } - } - - target[i]='\0'; -} - -tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f) -{ - if (f->is_dir && !f->is_parent && f->fid) { - BYTE sector[fio_SECTOR_SIZE]; - tp_udf_tag tag = (tp_udf_tag)sector; - bool res; - - res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector); - if (res && tag->TagIdentifier == udf_TAG_FileEntry) { - tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; - - if (fe->ICBTag.FileType == udf_FT_Directory) { - tp_udf_file newf = (tp_udf_file)malloc(sizeof *newf); - - if (newf == nullptr) { - return nullptr; - } - - ZeroMemory(newf, sizeof(*newf)); - strcpy_s(newf->name, f->name); // maybe just ""? - newf->sec_size = f->sec_size; - newf->partition_lba = f->partition_lba; - udf_GetLBA(fe, f->sec_size, &newf->dir_lba, &newf->dir_end_lba); - newf->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb - newf->sector = nullptr; - newf->fid = nullptr; - newf->is_dir = true; - newf->is_parent = false; - return newf; - } - } - } - return nullptr; -} - -tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f) -{ - if (f->dir_left <= 0) { - f->fid = nullptr; - return nullptr; - } - - if (f->fid) { - // advance to next FileIdentifierDescriptor - DWORD ofs = 4 * ((sizeof *(f->fid) + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4); - - f->fid = (tp_udf_FileIdentifierDescriptor)((BYTE *)f->fid + ofs); - } - - if (f->fid == nullptr) { - bool res = true; - - DWORD size = f->sec_size * (f->dir_end_lba - f->dir_lba + 1); - - if (!f->sector) { - f->sector = (BYTE*)malloc(size); - } - res = aspi_ReadSectors(hDrive, f->partition_lba + f->dir_lba, (WORD)(f->dir_end_lba - f->dir_lba + 1), f->sec_size, f->sector); - if (res) { - f->fid = (tp_udf_FileIdentifierDescriptor)f->sector; - } else { - f->fid = nullptr; - } - } - - if (f->fid && f->fid->DescriptorTag.TagIdentifier == udf_TAG_FileIdentifierDescriptor) { - DWORD ofs = 4 * ((sizeof *f->fid + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4); - - f->dir_left -= ofs; - f->is_dir = (f->fid->FileCharacteristics & udf_FID_Directory) != 0; - f->is_parent = (f->fid->FileCharacteristics & udf_FID_Parent) != 0; - udf_GetName(f->fid->ImplementationUse + f->fid->LengthofImplementationUse, f->fid->LengthofFileIdentifier, f->name); - return f; - } - return nullptr; -} - -void udf_free(tp_udf_file f) -{ - if (f) { - if (f->sector) { - free(f->sector); - } - free(f); - } -} - -#pragma warning(push) -#pragma warning(disable:4995 4996) - -#define udf_PATH_DELIMITERS "/\\" - -static tp_udf_file udf_ff_traverse(const HANDLE hDrive, tp_udf_file f, char *token) -{ - while (udf_get_next(hDrive, f)) { - if (_stricmp(token, f->name) == 0) { - char *next_tok = strtok(nullptr, udf_PATH_DELIMITERS); - - if (!next_tok) { - return f; // found - } else if (f->is_dir) { - tp_udf_file f2 = udf_get_sub(hDrive, f); - - if (f2) { - tp_udf_file f3 = udf_ff_traverse(hDrive, f2, next_tok); - - if (!f3) { - udf_free(f2); - } - return f3; - } - } - } - } - return nullptr; -} - -tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name) -{ - tp_udf_file f = udf_get_root(hDrive, partition), f2 = nullptr; - - if (f) { - char tokenline[udf_MAX_PATHLEN]; - char *token; - - strcpy_s(tokenline, name); - token = strtok(tokenline, udf_PATH_DELIMITERS); - if (token) { - f2 = udf_ff_traverse(hDrive, f, token); - } - udf_free(f); - } - return f2; -} - -#pragma warning(pop) - -bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba) -{ - if (f->fid) { - BYTE sector[2048]; - tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; - bool res; - - res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector); - if (res && fe->DescriptorTag.TagIdentifier == udf_TAG_FileEntry) { - return udf_GetLBA(fe, f->sec_size, start_lba, end_lba); - } - } - return false; -} +/************************************************************************* + vStrip by [maven] (maven@maven.de) + udf.c: routines for udf-parsing (because windows just doesn't cut it), + refs: udf102.pdf, udf200.pdf +*************************************************************************/ + +#include "stdafx.h" +#include "udf.h" + +static bool aspi_GetSectorInfo(const HANDLE hDrive, DWORD* sec_size, DWORD* max_sec) +{ + LARGE_INTEGER size = {0, 0}; + GetFileSizeEx(hDrive, &size); + + *sec_size = 2048; + *max_sec = (DWORD)(size.QuadPart / *sec_size); + + return true; +} + +static bool aspi_ReadSectors(const HANDLE hDrive, int lba, int nSectors, DWORD sec_size, BYTE* sector) +{ + DWORD nbr = 0; + LARGE_INTEGER offset; + offset.QuadPart = lba*sec_size; + SetFilePointerEx(hDrive, offset, &offset, FILE_BEGIN); + return lba*sec_size == offset.QuadPart && ReadFile(hDrive, sector, nSectors*sec_size, &nbr, nullptr); +} + +static bool udf_GetLBA(const tp_udf_FileEntry fe, const DWORD sec_size, DWORD *start, DWORD *end) +{ + if (fe->LengthofAllocationDescriptors == 0) { + return false; + } + switch (fe->ICBTag.Flags & udf_icbf_Mask) { + case udf_icbf_ShortAd: { + tp_udf_short_ad ad = (tp_udf_short_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); + + *start = ad->Location; + *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; + return true; + } + break; + case udf_icbf_LongAd: { + tp_udf_long_ad ad = (tp_udf_long_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); + + *start = ad->Location.Location; // ignore partition number + *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; + return true; + } + break; + case udf_icbf_ExtAd: { + tp_udf_ext_ad ad = (tp_udf_ext_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes); + + *start = ad->Location.Location; // ignore partition number + *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size; + return true; + } + break; + } + return false; +} + +tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number) +{ + BYTE sector[fio_SECTOR_SIZE]; + tp_udf_tag tag = (tp_udf_tag)sector; + DWORD sec_size, max_sec, i; + DWORD MVDS_lba, MVDS_lba_end, MVDS_back_lba, MVDS_back_lba_end; + DWORD FileDescriptorSequence_lba = 0; + DWORD partition_lba = 0; + tp_udf_AnchorVolumeDescriptorPointer avd; + bool res, part_valid, vol_valid; + + if (!aspi_GetSectorInfo(hDrive, &sec_size, &max_sec)) { + return nullptr; + } + + if (sec_size != fio_SECTOR_SIZE || max_sec < 256) { + return nullptr; + } + + // read AnchorVolumeDescriptorPointer at 256 (or MaxSec) (Tag == 2) + res = aspi_ReadSectors(hDrive, 256, 1, sec_size, sector); + if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor) { + res = aspi_ReadSectors(hDrive, max_sec, 1, sec_size, sector); + if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor) { + return nullptr; + } + } + + // check Static Structures + + // get MainVolumeDescriptorSequence Location & Length + avd = (tp_udf_AnchorVolumeDescriptorPointer)sector; + MVDS_lba = avd->MainVolumeDescriptorSequenceExtent.Location; + MVDS_lba_end = MVDS_lba + (avd->MainVolumeDescriptorSequenceExtent.Length - 1) / sec_size; + MVDS_back_lba = avd->ReserveVolumeDescriptorSequenceExtent.Location; + MVDS_back_lba_end = MVDS_back_lba + (avd->ReserveVolumeDescriptorSequenceExtent.Length - 1) / sec_size; + + // read MVDS_Location..MVDS_Location + (MVDS_Length - 1) / SectorSize sectors + + part_valid = vol_valid = false; + i = 1; + do { + // try twice (if we need to) for ReserveAnchor + DWORD j = MVDS_lba; + do { + res = aspi_ReadSectors(hDrive, j++, 1, sec_size, sector); + if (res) { + if (tag->TagIdentifier == udf_TAG_PartitionDescriptor && !part_valid) { + // get stuff out of partition + tp_udf_PartitionDescriptor par = (tp_udf_PartitionDescriptor )sector; + + part_valid = par->PartitionNumber == partition_number; + if (part_valid) { + // extract par->PartitionStartingLocation, par->PartitionLength + partition_lba = par->PartitionStartingLocation; + } + } else if (tag->TagIdentifier == udf_TAG_LogicalVolumeDescriptor && !vol_valid) { + // get stuff out of volume + tp_udf_LogicalVolumeDescriptor vol = (tp_udf_LogicalVolumeDescriptor)sector; + + // check_volume sector size + vol_valid = (vol->LogicalBlockSize == sec_size) && (partition_number == vol->FileSetDescriptorSequence.Location.PartitionNumber); + if (vol_valid) { + // extract vol->FileSetDescriptorSequence + FileDescriptorSequence_lba = vol->FileSetDescriptorSequence.Location.Location; + // DWORD FileDescriptorSequence_lba_end = FileDescriptorSequence_lba + ((vol->FileSetDescriptorSequence.Length & udf_LengthMask) - 1) / sec_size; + } + } + } else { + tag->TagIdentifier = 0; + } + } while (j <= MVDS_lba_end && tag->TagIdentifier != udf_TAG_TerminatingDescriptor && ((!part_valid) || (!vol_valid))); + + if ((!part_valid) || (!vol_valid)) { + // try backup + MVDS_lba = MVDS_back_lba; + MVDS_lba_end = MVDS_back_lba_end; + } + } while (i-- && ((!part_valid) || (!vol_valid))); + + if (part_valid && vol_valid) { + // read FileSetDescriptor, get RootDir Location & Length, RootDir Length != 0 + res = aspi_ReadSectors(hDrive, FileDescriptorSequence_lba + partition_lba, 1, sec_size, sector); + if (res && tag->TagIdentifier == udf_TAG_FileSetDescriptor) { + tp_udf_FileSetDescriptor fsd = (tp_udf_FileSetDescriptor)sector; + + if (partition_number == fsd->RootDirectoryICB.Location.PartitionNumber) { + DWORD parent_icb = fsd->RootDirectoryICB.Location.Location; + res = aspi_ReadSectors(hDrive, partition_lba + parent_icb, 1, sec_size, sector); + if (res && tag->TagIdentifier == udf_TAG_FileEntry) { + tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; + + if (fe->ICBTag.FileType == udf_FT_Directory) { + tp_udf_file root = (tp_udf_file)malloc(sizeof *root); + + root->partition_lba = partition_lba; + udf_GetLBA(fe, sec_size, &root->dir_lba, &root->dir_end_lba); + root->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb + root->sector = nullptr; + root->fid = nullptr; + root->sec_size = sec_size; + strcpy_s(root->name, "/"); + root->is_dir = true; + root->is_parent = false; + return root; + } + } + } + } + } + + return nullptr; +} + +static void udf_GetName(const BYTE *data, const DWORD len, char *target) +{ + DWORD p = 1, i = 0; + + if (len == 0 || !(data[0] & 0x18)) { + target[0] = '\0'; + } + + if (data[0] & 0x10) { + // ignore MSB of unicode16 + p++; + + while (p < len) { + target[i++] = data[p += 2]; + } + } else { + while (p < len) { + target[i++] = data[p++]; + } + } + + target[i]='\0'; +} + +tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f) +{ + if (f->is_dir && !f->is_parent && f->fid) { + BYTE sector[fio_SECTOR_SIZE]; + tp_udf_tag tag = (tp_udf_tag)sector; + bool res; + + res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector); + if (res && tag->TagIdentifier == udf_TAG_FileEntry) { + tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; + + if (fe->ICBTag.FileType == udf_FT_Directory) { + tp_udf_file newf = (tp_udf_file)malloc(sizeof *newf); + + if (newf == nullptr) { + return nullptr; + } + + ZeroMemory(newf, sizeof(*newf)); + strcpy_s(newf->name, f->name); // maybe just ""? + newf->sec_size = f->sec_size; + newf->partition_lba = f->partition_lba; + udf_GetLBA(fe, f->sec_size, &newf->dir_lba, &newf->dir_end_lba); + newf->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb + newf->sector = nullptr; + newf->fid = nullptr; + newf->is_dir = true; + newf->is_parent = false; + return newf; + } + } + } + return nullptr; +} + +tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f) +{ + if (f->dir_left <= 0) { + f->fid = nullptr; + return nullptr; + } + + if (f->fid) { + // advance to next FileIdentifierDescriptor + DWORD ofs = 4 * ((sizeof *(f->fid) + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4); + + f->fid = (tp_udf_FileIdentifierDescriptor)((BYTE *)f->fid + ofs); + } + + if (f->fid == nullptr) { + bool res = true; + + DWORD size = f->sec_size * (f->dir_end_lba - f->dir_lba + 1); + + if (!f->sector) { + f->sector = (BYTE*)malloc(size); + } + res = aspi_ReadSectors(hDrive, f->partition_lba + f->dir_lba, (WORD)(f->dir_end_lba - f->dir_lba + 1), f->sec_size, f->sector); + if (res) { + f->fid = (tp_udf_FileIdentifierDescriptor)f->sector; + } else { + f->fid = nullptr; + } + } + + if (f->fid && f->fid->DescriptorTag.TagIdentifier == udf_TAG_FileIdentifierDescriptor) { + DWORD ofs = 4 * ((sizeof *f->fid + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4); + + f->dir_left -= ofs; + f->is_dir = (f->fid->FileCharacteristics & udf_FID_Directory) != 0; + f->is_parent = (f->fid->FileCharacteristics & udf_FID_Parent) != 0; + udf_GetName(f->fid->ImplementationUse + f->fid->LengthofImplementationUse, f->fid->LengthofFileIdentifier, f->name); + return f; + } + return nullptr; +} + +void udf_free(tp_udf_file f) +{ + if (f) { + if (f->sector) { + free(f->sector); + } + free(f); + } +} + +#pragma warning(push) +#pragma warning(disable:4995 4996) + +#define udf_PATH_DELIMITERS "/\\" + +static tp_udf_file udf_ff_traverse(const HANDLE hDrive, tp_udf_file f, char *token) +{ + while (udf_get_next(hDrive, f)) { + if (_stricmp(token, f->name) == 0) { + char *next_tok = strtok(nullptr, udf_PATH_DELIMITERS); + + if (!next_tok) { + return f; // found + } else if (f->is_dir) { + tp_udf_file f2 = udf_get_sub(hDrive, f); + + if (f2) { + tp_udf_file f3 = udf_ff_traverse(hDrive, f2, next_tok); + + if (!f3) { + udf_free(f2); + } + return f3; + } + } + } + } + return nullptr; +} + +tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name) +{ + tp_udf_file f = udf_get_root(hDrive, partition), f2 = nullptr; + + if (f) { + char tokenline[udf_MAX_PATHLEN]; + char *token; + + strcpy_s(tokenline, name); + token = strtok(tokenline, udf_PATH_DELIMITERS); + if (token) { + f2 = udf_ff_traverse(hDrive, f, token); + } + udf_free(f); + } + return f2; +} + +#pragma warning(pop) + +bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba) +{ + if (f->fid) { + BYTE sector[2048]; + tp_udf_FileEntry fe = (tp_udf_FileEntry)sector; + bool res; + + res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector); + if (res && fe->DescriptorTag.TagIdentifier == udf_TAG_FileEntry) { + return udf_GetLBA(fe, f->sec_size, start_lba, end_lba); + } + } + return false; +} diff --git a/src/DeCSS/udf.h b/src/DeCSS/udf.h index 6aff1bc71d2..d8848a8d373 100644 --- a/src/DeCSS/udf.h +++ b/src/DeCSS/udf.h @@ -1,256 +1,256 @@ -/************************************************************************* - vStrip by [maven] (maven@maven.de) -*************************************************************************/ - -#pragma once - -typedef char dstring; // last BYTE of string indicates encoding/length - -#define fio_SECTOR_SIZE 2048 - -#define udf_LengthMask 0x3fffffff - -#define udf_TAG_PrimaryVolumeDescriptor 0x0001 -#define udf_TAG_AnchorVolumeDescriptor 0x0002 -#define udf_TAG_PartitionDescriptor 0x0005 -#define udf_TAG_LogicalVolumeDescriptor 0x0006 -#define udf_TAG_TerminatingDescriptor 0x0008 -#define udf_TAG_FileSetDescriptor 0x0100 -#define udf_TAG_FileIdentifierDescriptor 0x0101 -#define udf_TAG_IndirectEntry 0x0103 -#define udf_TAG_TerminalEntry 0x0104 -#define udf_TAG_FileEntry 0x0105 - -#define udf_FT_IndirectEntry 0x03 -#define udf_FT_Directory 0x04 -#define udf_FT_File 0x05 -#define udf_FT_TerminalEntry 0x0b - -#define udf_icbf_Mask 0x0007 -#define udf_icbf_ShortAd 0x0000 -#define udf_icbf_LongAd 0x0001 -#define udf_icbf_ExtAd 0x0002 -#define udf_icbf_Direct 0x0003 -#define udf_icbf_Contiguous 0x0100 - -#define udf_FID_Directory 0x02 -#define udf_FID_Parent 0x08 - -#pragma pack(push, 1) - -typedef struct { - DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list - DWORD Location; // 04 -} t_udf_short_ad, *tp_udf_short_ad; // 08 - -typedef struct { - DWORD Length; // 00 - DWORD Location; // 04 -} t_udf_extent_ad, *tp_udf_extent_ad; // 08 - -typedef struct { - DWORD Location; // 00, relative to volume - WORD PartitionNumber; // 04 -} t_udf_lb_addr; // 06 - -typedef struct { - DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list - t_udf_lb_addr Location; // 04 - BYTE ImplementationUse[6]; // 10 -} t_udf_long_ad, *tp_udf_long_ad; // 16 - -typedef struct { - DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list - DWORD RecordedLength; // 04 - DWORD InformationLength; // 08 - t_udf_lb_addr Location; // 12 - BYTE ImplementationUse[2]; // 18 -} t_udf_ext_ad, *tp_udf_ext_ad; // 20 - -typedef struct { - BYTE CharacterSetType; // 00 - BYTE CharacterSetInfo[63]; // 01 -} t_udf_charspec; // 64 - -typedef struct { - /* ECMA 167 1/7.3 */ - WORD TypeAndTimezone; // 00 - WORD Year; // 02 - BYTE Month; // 04 - BYTE Day; // 05 - BYTE Hour; // 06 - BYTE Minute; // 07 - BYTE Second; // 08 - BYTE Centiseconds; // 09 - BYTE HundredsofMicroseconds; // 10 - BYTE Microseconds; // 11 -} t_udf_timestamp; // 12 - -typedef struct { - /* ISO 13346 3/7.2 */ - WORD TagIdentifier; // 00 - WORD DescriptorVersion; // 02 - BYTE TagChecksum; // 04 - BYTE Reserved; // 05 - WORD TagSerialNumber; // 06 - WORD DescriptorCRC; // 08 - WORD DescriptorCRCLength; // 10 - DWORD TagLocation; // 12 -} t_udf_tag, *tp_udf_tag; // 16 - -typedef struct { - /* ISO 13346 1/7.4 */ - BYTE Flags; // 00 - char Identifier[23]; // 01 - char IdentifierSuffix[8]; // 24 -} t_udf_EntityID; // 32 - -typedef struct { - /* ISO 13346 3/10.2 */ - t_udf_tag DescriptorTag; // 00 - t_udf_extent_ad MainVolumeDescriptorSequenceExtent; // 16 - t_udf_extent_ad ReserveVolumeDescriptorSequenceExtent; // 24 - BYTE Reserved[480]; // 32 -} t_udf_AnchorVolumeDescriptorPointer, *tp_udf_AnchorVolumeDescriptorPointer; // 512 - -typedef struct { - /* ISO 13346 3/10.6 */ - t_udf_tag DescriptorTag; // 00 - DWORD VolumeDescriptorSequenceNumber; // 16 - t_udf_charspec DescriptorCharacterSet; // 20 - dstring LogicalVolumeIdentifier[128]; // 84 - DWORD LogicalBlockSize; // 212 - t_udf_EntityID DomainIdentifier; // 244 - //BYTE LogicalVolumeContentsUse[16]; // 276 - t_udf_long_ad FileSetDescriptorSequence; // 276 - DWORD MapTableLength; // 292 - DWORD NumberofPartitionMaps; // 296 - t_udf_EntityID ImplementationIdentifier; // 300 - BYTE ImplementationUse[128]; // 332 - t_udf_extent_ad IntegritySequenceExtent; // 460 - BYTE PartitionMaps[1]; // 468 -} t_udf_LogicalVolumeDescriptor, *tp_udf_LogicalVolumeDescriptor; - -typedef struct { - t_udf_short_ad UnallocatedSpaceTable; // 00 - t_udf_short_ad UnallocatedSpaceBitmap; // 08 - t_udf_short_ad PartitionIntegrityTable; // 16 - t_udf_short_ad FreedSpaceTable; // 24 - t_udf_short_ad FreedSpaceBitmap; // 32 - BYTE Reserved[88]; // 40 -} t_udf_PartitionHeaderDescriptor; // 128 - -typedef struct { - /* ECMA 167 3/10.5 */ - t_udf_tag DescriptorTag; // 00 - DWORD VolumeDescriptorSequenceNumber; // 16 - WORD PartitionFlags; // 20 - WORD PartitionNumber; // 22 - t_udf_EntityID PartitionContents; // 24 - t_udf_PartitionHeaderDescriptor PartitionHeaderDescriptor; // 56 - DWORD AccessType; // 184, 0 unspecified, 1 read only, 2 write once, 3 rewriteable, 4 overwriteable - DWORD PartitionStartingLocation; // 188 - DWORD PartitionLength; // 192 - t_udf_EntityID ImplementationIdentifier; // 196 - BYTE ImplementationUse[128]; // 228 - BYTE Reserved[156]; // 356 -} t_udf_PartitionDescriptor, *tp_udf_PartitionDescriptor; // 512 - -typedef struct { - /* ECMA 167 4/14.1 */ - t_udf_tag DescriptorTag; // 00 - t_udf_timestamp RecordingDateandTime; // 16 - WORD InterchangeLevel; // 28 - WORD MaximumInterchangeLevel; // 30 - DWORD CharacterSetList; // 32 - DWORD MaximumCharacterSetList; // 36 - DWORD FileSetNumber; // 40 - DWORD FileSetDescriptorNumber; // 44 - t_udf_charspec LogicalVolumeIdentifierCharacterSet; // 48 - dstring LogicalVolumeIdentifier[128]; // 112 - t_udf_charspec FileSetCharacterSet; // 240 - dstring FileSetIdentifer[32]; // 304 - dstring CopyrightFileIdentifier[32]; // 336 - dstring AbstractFileIdentifier[32]; // 368 - t_udf_long_ad RootDirectoryICB; // 400 - t_udf_EntityID DomainIdentifier; // 416 - t_udf_long_ad NextExtent; // 448 - t_udf_long_ad StreamDirectoryICB; // 464 - BYTE Reserved[32]; // 480 -} t_udf_FileSetDescriptor, *tp_udf_FileSetDescriptor; // 512 - -typedef struct { - /* ECMA 167 4/14.6 */ - DWORD PriorRecordedNumberofDirectEntries; // 00 - WORD StrategyType; // 04 - BYTE StrategyParameter[2]; // 06 - WORD NumberofEntries; // 08 - BYTE Reserved; // 10 - BYTE FileType; // 11 - t_udf_lb_addr ParentICBLocation; // 12 - WORD Flags; // 18 -} t_udf_icbtag; // 20 - -typedef struct { - /* ECMA 167 4/14.9 */ - t_udf_tag DescriptorTag; // 00 - t_udf_icbtag ICBTag; // 16 - DWORD Uid; // 36 - DWORD Gid; // 40 - DWORD Permissions; // 44 - WORD FileLinkCount; // 48 - BYTE RecordFormat; // 50 - BYTE RecordDisplayAttributes; // 51 - DWORD RecordLength; // 52 - QWORD InformationLength; // 56 - QWORD LogicalBlocksRecorded; // 64 - t_udf_timestamp AccessTime; // 72 - t_udf_timestamp ModificationTime; // 84 - t_udf_timestamp AttributeTime; // 96 - DWORD Checkpoint; // 108 - t_udf_long_ad ExtendedAttributeICB; // 112 - t_udf_EntityID ImplementationIdentifier; // 128 - QWORD UniqueID; // 160 - DWORD LengthofExtendedAttributes; // 168 - DWORD LengthofAllocationDescriptors; // 172 - BYTE ExtendedAttributes[1]; // 176 - //BYTE AllocationDescriptors[]; // 176 -} t_udf_FileEntry, *tp_udf_FileEntry; // >= 176 - -typedef struct { - /* ECMA 167 4/14.4 */ - t_udf_tag DescriptorTag; // 00 - WORD FileVersionNumber; // 16 - BYTE FileCharacteristics; // 18 - BYTE LengthofFileIdentifier; // 19 - t_udf_long_ad ICB; // 20 - WORD LengthofImplementationUse; // 36 - BYTE ImplementationUse[1]; // 38 - //char FileIdentifier[]; // 38 - //BYTE Padding[]; // 38 -} t_udf_FileIdentifierDescriptor, *tp_udf_FileIdentifierDescriptor; // >= 38 - -#define udf_MAX_NAMELEN 256 -#define udf_MAX_PATHLEN 2048 - -typedef struct { - // public - char name[udf_MAX_NAMELEN]; - bool is_dir, is_parent; - // internal - BYTE *sector; - tp_udf_FileIdentifierDescriptor fid; - DWORD partition_lba; - DWORD dir_lba, dir_end_lba; - DWORD sec_size; - int dir_left; -} t_udf_file, *tp_udf_file; - -#pragma pack(pop) - -tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name); -tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number); -tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f); // advances f -tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f); // creates new f -bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba); -void udf_free(tp_udf_file f); +/************************************************************************* + vStrip by [maven] (maven@maven.de) +*************************************************************************/ + +#pragma once + +typedef char dstring; // last BYTE of string indicates encoding/length + +#define fio_SECTOR_SIZE 2048 + +#define udf_LengthMask 0x3fffffff + +#define udf_TAG_PrimaryVolumeDescriptor 0x0001 +#define udf_TAG_AnchorVolumeDescriptor 0x0002 +#define udf_TAG_PartitionDescriptor 0x0005 +#define udf_TAG_LogicalVolumeDescriptor 0x0006 +#define udf_TAG_TerminatingDescriptor 0x0008 +#define udf_TAG_FileSetDescriptor 0x0100 +#define udf_TAG_FileIdentifierDescriptor 0x0101 +#define udf_TAG_IndirectEntry 0x0103 +#define udf_TAG_TerminalEntry 0x0104 +#define udf_TAG_FileEntry 0x0105 + +#define udf_FT_IndirectEntry 0x03 +#define udf_FT_Directory 0x04 +#define udf_FT_File 0x05 +#define udf_FT_TerminalEntry 0x0b + +#define udf_icbf_Mask 0x0007 +#define udf_icbf_ShortAd 0x0000 +#define udf_icbf_LongAd 0x0001 +#define udf_icbf_ExtAd 0x0002 +#define udf_icbf_Direct 0x0003 +#define udf_icbf_Contiguous 0x0100 + +#define udf_FID_Directory 0x02 +#define udf_FID_Parent 0x08 + +#pragma pack(push, 1) + +typedef struct { + DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list + DWORD Location; // 04 +} t_udf_short_ad, *tp_udf_short_ad; // 08 + +typedef struct { + DWORD Length; // 00 + DWORD Location; // 04 +} t_udf_extent_ad, *tp_udf_extent_ad; // 08 + +typedef struct { + DWORD Location; // 00, relative to volume + WORD PartitionNumber; // 04 +} t_udf_lb_addr; // 06 + +typedef struct { + DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list + t_udf_lb_addr Location; // 04 + BYTE ImplementationUse[6]; // 10 +} t_udf_long_ad, *tp_udf_long_ad; // 16 + +typedef struct { + DWORD Length; // 00, high 2 bits: 0 ^= recorded & used, 1 ^= not recorded & used, 2 ^= not recorded & not used, 3 ^= linked list + DWORD RecordedLength; // 04 + DWORD InformationLength; // 08 + t_udf_lb_addr Location; // 12 + BYTE ImplementationUse[2]; // 18 +} t_udf_ext_ad, *tp_udf_ext_ad; // 20 + +typedef struct { + BYTE CharacterSetType; // 00 + BYTE CharacterSetInfo[63]; // 01 +} t_udf_charspec; // 64 + +typedef struct { + /* ECMA 167 1/7.3 */ + WORD TypeAndTimezone; // 00 + WORD Year; // 02 + BYTE Month; // 04 + BYTE Day; // 05 + BYTE Hour; // 06 + BYTE Minute; // 07 + BYTE Second; // 08 + BYTE Centiseconds; // 09 + BYTE HundredsofMicroseconds; // 10 + BYTE Microseconds; // 11 +} t_udf_timestamp; // 12 + +typedef struct { + /* ISO 13346 3/7.2 */ + WORD TagIdentifier; // 00 + WORD DescriptorVersion; // 02 + BYTE TagChecksum; // 04 + BYTE Reserved; // 05 + WORD TagSerialNumber; // 06 + WORD DescriptorCRC; // 08 + WORD DescriptorCRCLength; // 10 + DWORD TagLocation; // 12 +} t_udf_tag, *tp_udf_tag; // 16 + +typedef struct { + /* ISO 13346 1/7.4 */ + BYTE Flags; // 00 + char Identifier[23]; // 01 + char IdentifierSuffix[8]; // 24 +} t_udf_EntityID; // 32 + +typedef struct { + /* ISO 13346 3/10.2 */ + t_udf_tag DescriptorTag; // 00 + t_udf_extent_ad MainVolumeDescriptorSequenceExtent; // 16 + t_udf_extent_ad ReserveVolumeDescriptorSequenceExtent; // 24 + BYTE Reserved[480]; // 32 +} t_udf_AnchorVolumeDescriptorPointer, *tp_udf_AnchorVolumeDescriptorPointer; // 512 + +typedef struct { + /* ISO 13346 3/10.6 */ + t_udf_tag DescriptorTag; // 00 + DWORD VolumeDescriptorSequenceNumber; // 16 + t_udf_charspec DescriptorCharacterSet; // 20 + dstring LogicalVolumeIdentifier[128]; // 84 + DWORD LogicalBlockSize; // 212 + t_udf_EntityID DomainIdentifier; // 244 + //BYTE LogicalVolumeContentsUse[16]; // 276 + t_udf_long_ad FileSetDescriptorSequence; // 276 + DWORD MapTableLength; // 292 + DWORD NumberofPartitionMaps; // 296 + t_udf_EntityID ImplementationIdentifier; // 300 + BYTE ImplementationUse[128]; // 332 + t_udf_extent_ad IntegritySequenceExtent; // 460 + BYTE PartitionMaps[1]; // 468 +} t_udf_LogicalVolumeDescriptor, *tp_udf_LogicalVolumeDescriptor; + +typedef struct { + t_udf_short_ad UnallocatedSpaceTable; // 00 + t_udf_short_ad UnallocatedSpaceBitmap; // 08 + t_udf_short_ad PartitionIntegrityTable; // 16 + t_udf_short_ad FreedSpaceTable; // 24 + t_udf_short_ad FreedSpaceBitmap; // 32 + BYTE Reserved[88]; // 40 +} t_udf_PartitionHeaderDescriptor; // 128 + +typedef struct { + /* ECMA 167 3/10.5 */ + t_udf_tag DescriptorTag; // 00 + DWORD VolumeDescriptorSequenceNumber; // 16 + WORD PartitionFlags; // 20 + WORD PartitionNumber; // 22 + t_udf_EntityID PartitionContents; // 24 + t_udf_PartitionHeaderDescriptor PartitionHeaderDescriptor; // 56 + DWORD AccessType; // 184, 0 unspecified, 1 read only, 2 write once, 3 rewriteable, 4 overwriteable + DWORD PartitionStartingLocation; // 188 + DWORD PartitionLength; // 192 + t_udf_EntityID ImplementationIdentifier; // 196 + BYTE ImplementationUse[128]; // 228 + BYTE Reserved[156]; // 356 +} t_udf_PartitionDescriptor, *tp_udf_PartitionDescriptor; // 512 + +typedef struct { + /* ECMA 167 4/14.1 */ + t_udf_tag DescriptorTag; // 00 + t_udf_timestamp RecordingDateandTime; // 16 + WORD InterchangeLevel; // 28 + WORD MaximumInterchangeLevel; // 30 + DWORD CharacterSetList; // 32 + DWORD MaximumCharacterSetList; // 36 + DWORD FileSetNumber; // 40 + DWORD FileSetDescriptorNumber; // 44 + t_udf_charspec LogicalVolumeIdentifierCharacterSet; // 48 + dstring LogicalVolumeIdentifier[128]; // 112 + t_udf_charspec FileSetCharacterSet; // 240 + dstring FileSetIdentifer[32]; // 304 + dstring CopyrightFileIdentifier[32]; // 336 + dstring AbstractFileIdentifier[32]; // 368 + t_udf_long_ad RootDirectoryICB; // 400 + t_udf_EntityID DomainIdentifier; // 416 + t_udf_long_ad NextExtent; // 448 + t_udf_long_ad StreamDirectoryICB; // 464 + BYTE Reserved[32]; // 480 +} t_udf_FileSetDescriptor, *tp_udf_FileSetDescriptor; // 512 + +typedef struct { + /* ECMA 167 4/14.6 */ + DWORD PriorRecordedNumberofDirectEntries; // 00 + WORD StrategyType; // 04 + BYTE StrategyParameter[2]; // 06 + WORD NumberofEntries; // 08 + BYTE Reserved; // 10 + BYTE FileType; // 11 + t_udf_lb_addr ParentICBLocation; // 12 + WORD Flags; // 18 +} t_udf_icbtag; // 20 + +typedef struct { + /* ECMA 167 4/14.9 */ + t_udf_tag DescriptorTag; // 00 + t_udf_icbtag ICBTag; // 16 + DWORD Uid; // 36 + DWORD Gid; // 40 + DWORD Permissions; // 44 + WORD FileLinkCount; // 48 + BYTE RecordFormat; // 50 + BYTE RecordDisplayAttributes; // 51 + DWORD RecordLength; // 52 + QWORD InformationLength; // 56 + QWORD LogicalBlocksRecorded; // 64 + t_udf_timestamp AccessTime; // 72 + t_udf_timestamp ModificationTime; // 84 + t_udf_timestamp AttributeTime; // 96 + DWORD Checkpoint; // 108 + t_udf_long_ad ExtendedAttributeICB; // 112 + t_udf_EntityID ImplementationIdentifier; // 128 + QWORD UniqueID; // 160 + DWORD LengthofExtendedAttributes; // 168 + DWORD LengthofAllocationDescriptors; // 172 + BYTE ExtendedAttributes[1]; // 176 + //BYTE AllocationDescriptors[]; // 176 +} t_udf_FileEntry, *tp_udf_FileEntry; // >= 176 + +typedef struct { + /* ECMA 167 4/14.4 */ + t_udf_tag DescriptorTag; // 00 + WORD FileVersionNumber; // 16 + BYTE FileCharacteristics; // 18 + BYTE LengthofFileIdentifier; // 19 + t_udf_long_ad ICB; // 20 + WORD LengthofImplementationUse; // 36 + BYTE ImplementationUse[1]; // 38 + //char FileIdentifier[]; // 38 + //BYTE Padding[]; // 38 +} t_udf_FileIdentifierDescriptor, *tp_udf_FileIdentifierDescriptor; // >= 38 + +#define udf_MAX_NAMELEN 256 +#define udf_MAX_PATHLEN 2048 + +typedef struct { + // public + char name[udf_MAX_NAMELEN]; + bool is_dir, is_parent; + // internal + BYTE *sector; + tp_udf_FileIdentifierDescriptor fid; + DWORD partition_lba; + DWORD dir_lba, dir_end_lba; + DWORD sec_size; + int dir_left; +} t_udf_file, *tp_udf_file; + +#pragma pack(pop) + +tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name); +tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number); +tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f); // advances f +tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f); // creates new f +bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba); +void udf_free(tp_udf_file f); diff --git a/src/MPCTestAPI/HScrollListBox.cpp b/src/MPCTestAPI/HScrollListBox.cpp index a4c6bbc795a..9a45c901f23 100644 --- a/src/MPCTestAPI/HScrollListBox.cpp +++ b/src/MPCTestAPI/HScrollListBox.cpp @@ -1,169 +1,169 @@ -///////////////////////////////////////////////////////////////////////////// -// HScrollListBox.cpp : implementation file -// -// Copyright (c) 2002, Nebula Technologies, Inc. -// www.nebutech.com -// -// Nebula Technologies, Inc. grants you a royalty free -// license to use, modify and distribute this code -// provided that this copyright notice appears on all -// copies. This code is provided "AS IS," without a -// warranty of any kind. -// -///////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "HScrollListBox.h" - -///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CHScrollListBox, CListBox) - //{{AFX_MSG_MAP(CHScrollListBox) - // NOTE - the ClassWizard will add and remove mapping macros here. - //}}AFX_MSG_MAP - ON_MESSAGE(LB_ADDSTRING, OnAddString) - ON_MESSAGE(LB_INSERTSTRING, OnInsertString) - ON_MESSAGE(LB_DELETESTRING, OnDeleteString) - ON_MESSAGE(LB_DIR, OnDir) - ON_MESSAGE(LB_RESETCONTENT, OnResetContent) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CHScrollListBox -///////////////////////////////////////////////////////////////////////////// -CHScrollListBox::CHScrollListBox() -{ -} - -///////////////////////////////////////////////////////////////////////////// -CHScrollListBox::~CHScrollListBox() -{ -} - -///////////////////////////////////////////////////////////////////////////// -void CHScrollListBox::PreSubclassWindow() -{ - CListBox::PreSubclassWindow(); - -#ifdef _DEBUG - // NOTE: this list box is designed to work as a single column, system-drawn - // list box. The asserts below will ensure of that. - DWORD dwStyle = GetStyle(); - ASSERT((dwStyle & LBS_MULTICOLUMN) == 0); - ASSERT((dwStyle & LBS_OWNERDRAWFIXED) == 0); - ASSERT((dwStyle & LBS_OWNERDRAWVARIABLE) == 0); -#endif -} - -///////////////////////////////////////////////////////////////////////////// -// CHScrollListBox message handlers -/////////////////////////////////////////////////////////////////////////////// -int CHScrollListBox::GetTextLen(LPCTSTR lpszText) -{ - ASSERT(AfxIsValidString(lpszText)); - - CDC *pDC = GetDC(); - ASSERT(pDC); - - CSize size; - CFont* pOldFont = pDC->SelectObject(GetFont()); - if ((GetStyle() & LBS_USETABSTOPS) == 0) { - size = pDC->GetTextExtent(lpszText, (int) _tcslen(lpszText)); - size.cx += 3; - } else { - // Expand tabs as well - size = pDC->GetTabbedTextExtent(lpszText, (int) _tcslen(lpszText), 0, NULL); - size.cx += 2; - } - pDC->SelectObject(pOldFont); - ReleaseDC(pDC); - - return size.cx; -} - -/////////////////////////////////////////////////////////////////////////////// -void CHScrollListBox::ResetHExtent() -{ - if (GetCount() == 0) { - SetHorizontalExtent(0); - return; - } - - CWaitCursor cwc; - int iMaxHExtent = 0; - for (int i = 0; i < GetCount(); i++) { - CString csText; - GetText(i, csText); - int iExt = GetTextLen(csText); - if (iExt > iMaxHExtent) { - iMaxHExtent = iExt; - } - } - SetHorizontalExtent(iMaxHExtent); -} - -/////////////////////////////////////////////////////////////////////////////// -void CHScrollListBox::SetNewHExtent(LPCTSTR lpszNewString) -{ - int iExt = GetTextLen(lpszNewString); - if (iExt > GetHorizontalExtent()) { - SetHorizontalExtent(iExt); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// OnAddString: wParam - none, lParam - string, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnAddString(WPARAM /*wParam*/, LPARAM lParam) -{ - LRESULT lResult = Default(); - if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { - SetNewHExtent((LPCTSTR) lParam); - } - return lResult; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnInsertString: wParam - index, lParam - string, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnInsertString(WPARAM /*wParam*/, LPARAM lParam) -{ - LRESULT lResult = Default(); - if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { - SetNewHExtent((LPCTSTR) lParam); - } - return lResult; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnDeleteString: wParam - index, lParam - none, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnDeleteString(WPARAM /*wParam*/, LPARAM /*lParam*/) -{ - LRESULT lResult = Default(); - if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { - ResetHExtent(); - } - return lResult; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnDir: wParam - attr, lParam - wildcard, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnDir(WPARAM /*wParam*/, LPARAM /*lParam*/) -{ - LRESULT lResult = Default(); - if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { - ResetHExtent(); - } - return lResult; -} - -/////////////////////////////////////////////////////////////////////////////// -// OnResetContent: wParam - none, lParam - none, returns - int -/////////////////////////////////////////////////////////////////////////////// -LRESULT CHScrollListBox::OnResetContent(WPARAM /*wParam*/, LPARAM /*lParam*/) -{ - LRESULT lResult = Default(); - SetHorizontalExtent(0); - return lResult; -} +///////////////////////////////////////////////////////////////////////////// +// HScrollListBox.cpp : implementation file +// +// Copyright (c) 2002, Nebula Technologies, Inc. +// www.nebutech.com +// +// Nebula Technologies, Inc. grants you a royalty free +// license to use, modify and distribute this code +// provided that this copyright notice appears on all +// copies. This code is provided "AS IS," without a +// warranty of any kind. +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "HScrollListBox.h" + +///////////////////////////////////////////////////////////////////////////// +BEGIN_MESSAGE_MAP(CHScrollListBox, CListBox) + //{{AFX_MSG_MAP(CHScrollListBox) + // NOTE - the ClassWizard will add and remove mapping macros here. + //}}AFX_MSG_MAP + ON_MESSAGE(LB_ADDSTRING, OnAddString) + ON_MESSAGE(LB_INSERTSTRING, OnInsertString) + ON_MESSAGE(LB_DELETESTRING, OnDeleteString) + ON_MESSAGE(LB_DIR, OnDir) + ON_MESSAGE(LB_RESETCONTENT, OnResetContent) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CHScrollListBox +///////////////////////////////////////////////////////////////////////////// +CHScrollListBox::CHScrollListBox() +{ +} + +///////////////////////////////////////////////////////////////////////////// +CHScrollListBox::~CHScrollListBox() +{ +} + +///////////////////////////////////////////////////////////////////////////// +void CHScrollListBox::PreSubclassWindow() +{ + CListBox::PreSubclassWindow(); + +#ifdef _DEBUG + // NOTE: this list box is designed to work as a single column, system-drawn + // list box. The asserts below will ensure of that. + DWORD dwStyle = GetStyle(); + ASSERT((dwStyle & LBS_MULTICOLUMN) == 0); + ASSERT((dwStyle & LBS_OWNERDRAWFIXED) == 0); + ASSERT((dwStyle & LBS_OWNERDRAWVARIABLE) == 0); +#endif +} + +///////////////////////////////////////////////////////////////////////////// +// CHScrollListBox message handlers +/////////////////////////////////////////////////////////////////////////////// +int CHScrollListBox::GetTextLen(LPCTSTR lpszText) +{ + ASSERT(AfxIsValidString(lpszText)); + + CDC *pDC = GetDC(); + ASSERT(pDC); + + CSize size; + CFont* pOldFont = pDC->SelectObject(GetFont()); + if ((GetStyle() & LBS_USETABSTOPS) == 0) { + size = pDC->GetTextExtent(lpszText, (int) _tcslen(lpszText)); + size.cx += 3; + } else { + // Expand tabs as well + size = pDC->GetTabbedTextExtent(lpszText, (int) _tcslen(lpszText), 0, NULL); + size.cx += 2; + } + pDC->SelectObject(pOldFont); + ReleaseDC(pDC); + + return size.cx; +} + +/////////////////////////////////////////////////////////////////////////////// +void CHScrollListBox::ResetHExtent() +{ + if (GetCount() == 0) { + SetHorizontalExtent(0); + return; + } + + CWaitCursor cwc; + int iMaxHExtent = 0; + for (int i = 0; i < GetCount(); i++) { + CString csText; + GetText(i, csText); + int iExt = GetTextLen(csText); + if (iExt > iMaxHExtent) { + iMaxHExtent = iExt; + } + } + SetHorizontalExtent(iMaxHExtent); +} + +/////////////////////////////////////////////////////////////////////////////// +void CHScrollListBox::SetNewHExtent(LPCTSTR lpszNewString) +{ + int iExt = GetTextLen(lpszNewString); + if (iExt > GetHorizontalExtent()) { + SetHorizontalExtent(iExt); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// OnAddString: wParam - none, lParam - string, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnAddString(WPARAM /*wParam*/, LPARAM lParam) +{ + LRESULT lResult = Default(); + if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { + SetNewHExtent((LPCTSTR) lParam); + } + return lResult; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnInsertString: wParam - index, lParam - string, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnInsertString(WPARAM /*wParam*/, LPARAM lParam) +{ + LRESULT lResult = Default(); + if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { + SetNewHExtent((LPCTSTR) lParam); + } + return lResult; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnDeleteString: wParam - index, lParam - none, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnDeleteString(WPARAM /*wParam*/, LPARAM /*lParam*/) +{ + LRESULT lResult = Default(); + if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { + ResetHExtent(); + } + return lResult; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnDir: wParam - attr, lParam - wildcard, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnDir(WPARAM /*wParam*/, LPARAM /*lParam*/) +{ + LRESULT lResult = Default(); + if (!((lResult == LB_ERR) || (lResult == LB_ERRSPACE))) { + ResetHExtent(); + } + return lResult; +} + +/////////////////////////////////////////////////////////////////////////////// +// OnResetContent: wParam - none, lParam - none, returns - int +/////////////////////////////////////////////////////////////////////////////// +LRESULT CHScrollListBox::OnResetContent(WPARAM /*wParam*/, LPARAM /*lParam*/) +{ + LRESULT lResult = Default(); + SetHorizontalExtent(0); + return lResult; +} diff --git a/src/MPCTestAPI/HScrollListBox.h b/src/MPCTestAPI/HScrollListBox.h index 023ea815b0a..5bf7765ecc0 100644 --- a/src/MPCTestAPI/HScrollListBox.h +++ b/src/MPCTestAPI/HScrollListBox.h @@ -1,62 +1,62 @@ -///////////////////////////////////////////////////////////////////////////// -// HScrollListBox.h : header file -// -// Copyright (c) 2002, Nebula Technologies, Inc. -// www.nebutech.com -// -// Nebula Technologies, Inc. grants you a royalty free -// license to use, modify and distribute this code -// provided that this copyright notice appears on all -// copies. This code is provided "AS IS," without a -// warranty of any kind. -// -///////////////////////////////////////////////////////////////////////////// - -#pragma once - -///////////////////////////////////////////////////////////////////////////// -// CHScrollListBox window -///////////////////////////////////////////////////////////////////////////// -class CHScrollListBox : public CListBox -{ - // Construction -public: - CHScrollListBox(); - - // Attributes -public: - - // Operations -public: - - // Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CHScrollListBox) -protected: - virtual void PreSubclassWindow(); - //}}AFX_VIRTUAL - - // Implementation -public: - virtual ~CHScrollListBox(); - - // Generated message map functions -protected: - //{{AFX_MSG(CHScrollListBox) - // NOTE - the ClassWizard will add and remove member functions here. - //}}AFX_MSG - - afx_msg LRESULT OnAddString(WPARAM wParam, LPARAM lParam); // wParam - none, lParam - string, returns - int - afx_msg LRESULT OnInsertString(WPARAM wParam, LPARAM lParam); // wParam - index, lParam - string, returns - int - afx_msg LRESULT OnDeleteString(WPARAM wParam, LPARAM lParam); // wParam - index, lParam - none, returns - int - afx_msg LRESULT OnResetContent(WPARAM wParam, LPARAM lParam); // wParam - none, lParam - none, returns - int - afx_msg LRESULT OnDir(WPARAM wParam, LPARAM lParam); // wParam - attr, lParam - wildcard, returns - int - - DECLARE_MESSAGE_MAP() - -private: - void ResetHExtent(); - void SetNewHExtent(LPCTSTR lpszNewString); - int GetTextLen(LPCTSTR lpszText); - -}; +///////////////////////////////////////////////////////////////////////////// +// HScrollListBox.h : header file +// +// Copyright (c) 2002, Nebula Technologies, Inc. +// www.nebutech.com +// +// Nebula Technologies, Inc. grants you a royalty free +// license to use, modify and distribute this code +// provided that this copyright notice appears on all +// copies. This code is provided "AS IS," without a +// warranty of any kind. +// +///////////////////////////////////////////////////////////////////////////// + +#pragma once + +///////////////////////////////////////////////////////////////////////////// +// CHScrollListBox window +///////////////////////////////////////////////////////////////////////////// +class CHScrollListBox : public CListBox +{ + // Construction +public: + CHScrollListBox(); + + // Attributes +public: + + // Operations +public: + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CHScrollListBox) +protected: + virtual void PreSubclassWindow(); + //}}AFX_VIRTUAL + + // Implementation +public: + virtual ~CHScrollListBox(); + + // Generated message map functions +protected: + //{{AFX_MSG(CHScrollListBox) + // NOTE - the ClassWizard will add and remove member functions here. + //}}AFX_MSG + + afx_msg LRESULT OnAddString(WPARAM wParam, LPARAM lParam); // wParam - none, lParam - string, returns - int + afx_msg LRESULT OnInsertString(WPARAM wParam, LPARAM lParam); // wParam - index, lParam - string, returns - int + afx_msg LRESULT OnDeleteString(WPARAM wParam, LPARAM lParam); // wParam - index, lParam - none, returns - int + afx_msg LRESULT OnResetContent(WPARAM wParam, LPARAM lParam); // wParam - none, lParam - none, returns - int + afx_msg LRESULT OnDir(WPARAM wParam, LPARAM lParam); // wParam - attr, lParam - wildcard, returns - int + + DECLARE_MESSAGE_MAP() + +private: + void ResetHExtent(); + void SetNewHExtent(LPCTSTR lpszNewString); + int GetTextLen(LPCTSTR lpszText); + +}; diff --git a/src/MPCTestAPI/MPCTestAPI.cpp b/src/MPCTestAPI/MPCTestAPI.cpp index f99dde54aef..546f39b4058 100644 --- a/src/MPCTestAPI/MPCTestAPI.cpp +++ b/src/MPCTestAPI/MPCTestAPI.cpp @@ -1,81 +1,81 @@ -/* - * (C) 2008-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 . - * - */ - -// MPCTestAPI.cpp : Defines the class behaviors for the application. -// - -#include "stdafx.h" -#include "MPCTestAPI.h" -#include "MPCTestAPIDlg.h" - - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataApp - -BEGIN_MESSAGE_MAP(CRegisterCopyDataApp, CWinApp) - //{{AFX_MSG_MAP(CRegisterCopyDataApp) - // NOTE - the ClassWizard will add and remove mapping macros here. - // DO NOT EDIT what you see in these blocks of generated code! - //}}AFX_MSG - ON_COMMAND(ID_HELP, CWinApp::OnHelp) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataApp construction - -CRegisterCopyDataApp::CRegisterCopyDataApp() -{ - // TODO: add construction code here, - // Place all significant initialization in InitInstance -} - -///////////////////////////////////////////////////////////////////////////// -// The one and only CRegisterCopyDataApp object - -CRegisterCopyDataApp theApp; - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataApp initialization - -BOOL CRegisterCopyDataApp::InitInstance() -{ - AfxEnableControlContainer(); - - // Standard initialization - // If you are not using these features and wish to reduce the size - // of your final executable, you should remove from the following - // the specific initialization routines you do not need. - - CRegisterCopyDataDlg dlg; - m_pMainWnd = &dlg; - INT_PTR nResponse = dlg.DoModal(); - - if (nResponse == IDOK) { - // TODO: Place code here to handle when the dialog is - // dismissed with OK - } else if (nResponse == IDCANCEL) { - // TODO: Place code here to handle when the dialog is - // dismissed with Cancel - } - - // Since the dialog has been closed, return FALSE so that we exit the - // application, rather than start the application's message pump. - return FALSE; -} +/* + * (C) 2008-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 . + * + */ + +// MPCTestAPI.cpp : Defines the class behaviors for the application. +// + +#include "stdafx.h" +#include "MPCTestAPI.h" +#include "MPCTestAPIDlg.h" + + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataApp + +BEGIN_MESSAGE_MAP(CRegisterCopyDataApp, CWinApp) + //{{AFX_MSG_MAP(CRegisterCopyDataApp) + // NOTE - the ClassWizard will add and remove mapping macros here. + // DO NOT EDIT what you see in these blocks of generated code! + //}}AFX_MSG + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataApp construction + +CRegisterCopyDataApp::CRegisterCopyDataApp() +{ + // TODO: add construction code here, + // Place all significant initialization in InitInstance +} + +///////////////////////////////////////////////////////////////////////////// +// The one and only CRegisterCopyDataApp object + +CRegisterCopyDataApp theApp; + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataApp initialization + +BOOL CRegisterCopyDataApp::InitInstance() +{ + AfxEnableControlContainer(); + + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need. + + CRegisterCopyDataDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + + if (nResponse == IDOK) { + // TODO: Place code here to handle when the dialog is + // dismissed with OK + } else if (nResponse == IDCANCEL) { + // TODO: Place code here to handle when the dialog is + // dismissed with Cancel + } + + // Since the dialog has been closed, return FALSE so that we exit the + // application, rather than start the application's message pump. + return FALSE; +} diff --git a/src/MPCTestAPI/MPCTestAPI.h b/src/MPCTestAPI/MPCTestAPI.h index 01f5a8e0f9e..8c48048a3fe 100644 --- a/src/MPCTestAPI/MPCTestAPI.h +++ b/src/MPCTestAPI/MPCTestAPI.h @@ -1,52 +1,52 @@ -/* - * (C) 2008-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 . - * - */ - -// MPCTestAPI.h : main header file for the MPCTestAPI application -// - -#pragma once - -#include "resource.h" // main symbols - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataApp: -// See MPCTestAPI.cpp for the implementation of this class -// - -class CRegisterCopyDataApp : public CWinApp -{ -public: - CRegisterCopyDataApp(); - - // Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CRegisterCopyDataApp) -public: - virtual BOOL InitInstance(); - //}}AFX_VIRTUAL - - // Implementation - - //{{AFX_MSG(CRegisterCopyDataApp) - // NOTE - the ClassWizard will add and remove member functions here. - // DO NOT EDIT what you see in these blocks of generated code ! - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; +/* + * (C) 2008-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 . + * + */ + +// MPCTestAPI.h : main header file for the MPCTestAPI application +// + +#pragma once + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataApp: +// See MPCTestAPI.cpp for the implementation of this class +// + +class CRegisterCopyDataApp : public CWinApp +{ +public: + CRegisterCopyDataApp(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CRegisterCopyDataApp) +public: + virtual BOOL InitInstance(); + //}}AFX_VIRTUAL + + // Implementation + + //{{AFX_MSG(CRegisterCopyDataApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; diff --git a/src/MPCTestAPI/MPCTestAPI.rc b/src/MPCTestAPI/MPCTestAPI.rc index bac32cc918c..ec74497ae6b 100644 --- a/src/MPCTestAPI/MPCTestAPI.rc +++ b/src/MPCTestAPI/MPCTestAPI.rc @@ -1,260 +1,260 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\0" -END - -3 TEXTINCLUDE -BEGIN - "#define _AFX_NO_SPLITTER_RESOURCES\r\n" - "#define _AFX_NO_OLE_RESOURCES\r\n" - "#define _AFX_NO_TRACKER_RESOURCES\r\n" - "#define _AFX_NO_PROPERTY_RESOURCES\r\n" - "\r\n" - "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" - "LANGUAGE 9, 1\r\n" - "#pragma code_page(1252)\r\n" - "#include ""afxres.rc"" // Standard components\r\n" - "#endif\0" -END - -#endif // APSTUDIO_INVOKED - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDR_MAINFRAME ICON "res\\MPCTestAPI.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUTBOX DIALOGEX 0, 0, 244, 57 -STYLE DS_SHELLFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION -CAPTION "About MPC-HC Test API" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 - LTEXT "MPC-HC Test API Version 1.0.1.0",IDC_STATIC,40,10,120,10,SS_NOPREFIX - LTEXT "Copyright 2005-2013 all contributors, see Authors.txt",IDC_STATIC,40,27,197,10 - DEFPUSHBUTTON "OK",IDOK,187,7,50,14,WS_GROUP -END - -IDD_REGISTERCOPYDATA_DIALOG DIALOGEX 0, 0, 521, 406 -STYLE DS_SHELLFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_APPWINDOW -CAPTION "MPC-HC Test API" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - PUSHBUTTON "Start MPC-HC",IDC_BUTTON_FINDWINDOW,457,7,57,18 - EDITTEXT IDC_EDIT1,7,7,434,14,ES_AUTOHSCROLL - LISTBOX IDC_LOGLIST,7,89,507,310,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP - LTEXT "Messages from MPC-HC",IDC_STATIC,7,74,507,10 - EDITTEXT IDC_EDIT2,154,41,287,14,ES_AUTOHSCROLL - PUSHBUTTON "Send command",IDC_BUTTON_SENDCOMMAND,457,39,57,18 - COMBOBOX IDC_COMBO1,7,42,132,158,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,1,0 - PRODUCTVERSION 1,0,1,0 - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "MPC-HC Team" - VALUE "FileDescription", "MPC-HC Test API" - VALUE "FileVersion", "1.0.1.0" - VALUE "InternalName", "MPC-HC Test API" - VALUE "LegalCopyright", "Copyright 2005-2013 all contributors, see Authors.txt" - VALUE "OriginalFilename", "MPCTestAPI.exe" - VALUE "ProductName", "MPC-HC Test API" - VALUE "ProductVersion", "1.0.1.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_ABOUTBOX, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 237 - VERTGUIDE, 40 - TOPMARGIN, 7 - BOTTOMMARGIN, 50 - END - - IDD_REGISTERCOPYDATA_DIALOG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 514 - TOPMARGIN, 7 - BOTTOMMARGIN, 399 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog Info -// - -IDD_REGISTERCOPYDATA_DIALOG DLGINIT -BEGIN - IDC_COMBO1, 0x403, 10, 0 -0x704f, 0x6e65, 0x6620, 0x6c69, 0x0065, - IDC_COMBO1, 0x403, 5, 0 -0x7453, 0x706f, "\000" - IDC_COMBO1, 0x403, 6, 0 -0x6c43, 0x736f, 0x0065, - IDC_COMBO1, 0x403, 11, 0 -0x6c50, 0x7961, 0x502d, 0x7561, 0x6573, "\000" - IDC_COMBO1, 0x403, 16, 0 -0x6441, 0x2064, 0x6f74, 0x7020, 0x616c, 0x6c79, 0x7369, 0x0074, - IDC_COMBO1, 0x403, 15, 0 -0x7453, 0x7261, 0x2074, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" - IDC_COMBO1, 0x403, 15, 0 -0x6c43, 0x6165, 0x2072, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" - IDC_COMBO1, 0x403, 13, 0 -0x6553, 0x2074, 0x6f70, 0x6973, 0x6974, 0x6e6f, "\000" - IDC_COMBO1, 0x403, 16, 0 -0x6553, 0x2074, 0x7561, 0x6964, 0x206f, 0x6564, 0x616c, 0x0079, - IDC_COMBO1, 0x403, 19, 0 -0x6553, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x6420, 0x6c65, 0x7961, -"\000" - IDC_COMBO1, 0x403, 17, 0 -0x6547, 0x2074, 0x7561, 0x6964, 0x206f, 0x7274, 0x6361, 0x736b, "\000" - IDC_COMBO1, 0x403, 20, 0 -0x6547, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x7420, 0x6172, 0x6b63, -0x0073, - IDC_COMBO1, 0x403, 13, 0 -0x6547, 0x2074, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" - IDC_COMBO1, 0x403, 25, 0 -0x6553, 0x2074, 0x6f70, 0x6973, 0x6974, 0x6e6f, 0x6920, 0x206e, 0x6c70, -0x7961, 0x696c, 0x7473, "\000" - IDC_COMBO1, 0x403, 16, 0 -0x6553, 0x2074, 0x7561, 0x6964, 0x206f, 0x7274, 0x6361, 0x006b, - IDC_COMBO1, 0x403, 19, 0 -0x6553, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x7420, 0x6172, 0x6b63, -"\000" - IDC_COMBO1, 0x403, 11, 0 -0x7546, 0x6c6c, 0x6353, 0x6572, 0x6e65, "\000" - IDC_COMBO1, 0x403, 19, 0 -0x4d43, 0x5f44, 0x554a, 0x504d, 0x4f46, 0x5752, 0x5241, 0x4d44, 0x4445, -"\000" - IDC_COMBO1, 0x403, 20, 0 -0x4d43, 0x5f44, 0x554a, 0x504d, 0x4142, 0x4b43, 0x4157, 0x4452, 0x454d, -0x0044, - IDC_COMBO1, 0x403, 19, 0 -0x4d43, 0x5f44, 0x4e49, 0x5243, 0x4145, 0x4553, 0x4f56, 0x554c, 0x454d, -"\000" - IDC_COMBO1, 0x403, 19, 0 -0x4d43, 0x5f44, 0x4544, 0x5243, 0x4145, 0x4553, 0x4f56, 0x554c, 0x454d, -"\000" - IDC_COMBO1, 0x403, 18, 0 -0x4d43, 0x5f44, 0x4853, 0x4441, 0x5245, 0x545f, 0x474f, 0x4c47, 0x0045, - - IDC_COMBO1, 0x403, 13, 0 -0x4d43, 0x5f44, 0x4c43, 0x534f, 0x4145, 0x5050, "\000" - 0 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_ABOUTBOX "&About MPC-HC Test API..." -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// -#define _AFX_NO_SPLITTER_RESOURCES -#define _AFX_NO_OLE_RESOURCES -#define _AFX_NO_TRACKER_RESOURCES -#define _AFX_NO_PROPERTY_RESOURCES - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE 9, 1 -#pragma code_page(1252) -#include "afxres.rc" // Standard components -#endif -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\MPCTestAPI.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 244, 57 +STYLE DS_SHELLFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION +CAPTION "About MPC-HC Test API" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "MPC-HC Test API Version 1.0.1.0",IDC_STATIC,40,10,120,10,SS_NOPREFIX + LTEXT "Copyright 2005-2013 all contributors, see Authors.txt",IDC_STATIC,40,27,197,10 + DEFPUSHBUTTON "OK",IDOK,187,7,50,14,WS_GROUP +END + +IDD_REGISTERCOPYDATA_DIALOG DIALOGEX 0, 0, 521, 406 +STYLE DS_SHELLFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "MPC-HC Test API" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + PUSHBUTTON "Start MPC-HC",IDC_BUTTON_FINDWINDOW,457,7,57,18 + EDITTEXT IDC_EDIT1,7,7,434,14,ES_AUTOHSCROLL + LISTBOX IDC_LOGLIST,7,89,507,310,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP + LTEXT "Messages from MPC-HC",IDC_STATIC,7,74,507,10 + EDITTEXT IDC_EDIT2,154,41,287,14,ES_AUTOHSCROLL + PUSHBUTTON "Send command",IDC_BUTTON_SENDCOMMAND,457,39,57,18 + COMBOBOX IDC_COMBO1,7,42,132,158,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,1,0 + PRODUCTVERSION 1,0,1,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "MPC-HC Team" + VALUE "FileDescription", "MPC-HC Test API" + VALUE "FileVersion", "1.0.1.0" + VALUE "InternalName", "MPC-HC Test API" + VALUE "LegalCopyright", "Copyright 2005-2013 all contributors, see Authors.txt" + VALUE "OriginalFilename", "MPCTestAPI.exe" + VALUE "ProductName", "MPC-HC Test API" + VALUE "ProductVersion", "1.0.1.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 237 + VERTGUIDE, 40 + TOPMARGIN, 7 + BOTTOMMARGIN, 50 + END + + IDD_REGISTERCOPYDATA_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 514 + TOPMARGIN, 7 + BOTTOMMARGIN, 399 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_REGISTERCOPYDATA_DIALOG DLGINIT +BEGIN + IDC_COMBO1, 0x403, 10, 0 +0x704f, 0x6e65, 0x6620, 0x6c69, 0x0065, + IDC_COMBO1, 0x403, 5, 0 +0x7453, 0x706f, "\000" + IDC_COMBO1, 0x403, 6, 0 +0x6c43, 0x736f, 0x0065, + IDC_COMBO1, 0x403, 11, 0 +0x6c50, 0x7961, 0x502d, 0x7561, 0x6573, "\000" + IDC_COMBO1, 0x403, 16, 0 +0x6441, 0x2064, 0x6f74, 0x7020, 0x616c, 0x6c79, 0x7369, 0x0074, + IDC_COMBO1, 0x403, 15, 0 +0x7453, 0x7261, 0x2074, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" + IDC_COMBO1, 0x403, 15, 0 +0x6c43, 0x6165, 0x2072, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" + IDC_COMBO1, 0x403, 13, 0 +0x6553, 0x2074, 0x6f70, 0x6973, 0x6974, 0x6e6f, "\000" + IDC_COMBO1, 0x403, 16, 0 +0x6553, 0x2074, 0x7561, 0x6964, 0x206f, 0x6564, 0x616c, 0x0079, + IDC_COMBO1, 0x403, 19, 0 +0x6553, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x6420, 0x6c65, 0x7961, +"\000" + IDC_COMBO1, 0x403, 17, 0 +0x6547, 0x2074, 0x7561, 0x6964, 0x206f, 0x7274, 0x6361, 0x736b, "\000" + IDC_COMBO1, 0x403, 20, 0 +0x6547, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x7420, 0x6172, 0x6b63, +0x0073, + IDC_COMBO1, 0x403, 13, 0 +0x6547, 0x2074, 0x6c70, 0x7961, 0x696c, 0x7473, "\000" + IDC_COMBO1, 0x403, 25, 0 +0x6553, 0x2074, 0x6f70, 0x6973, 0x6974, 0x6e6f, 0x6920, 0x206e, 0x6c70, +0x7961, 0x696c, 0x7473, "\000" + IDC_COMBO1, 0x403, 16, 0 +0x6553, 0x2074, 0x7561, 0x6964, 0x206f, 0x7274, 0x6361, 0x006b, + IDC_COMBO1, 0x403, 19, 0 +0x6553, 0x2074, 0x7573, 0x7462, 0x7469, 0x656c, 0x7420, 0x6172, 0x6b63, +"\000" + IDC_COMBO1, 0x403, 11, 0 +0x7546, 0x6c6c, 0x6353, 0x6572, 0x6e65, "\000" + IDC_COMBO1, 0x403, 19, 0 +0x4d43, 0x5f44, 0x554a, 0x504d, 0x4f46, 0x5752, 0x5241, 0x4d44, 0x4445, +"\000" + IDC_COMBO1, 0x403, 20, 0 +0x4d43, 0x5f44, 0x554a, 0x504d, 0x4142, 0x4b43, 0x4157, 0x4452, 0x454d, +0x0044, + IDC_COMBO1, 0x403, 19, 0 +0x4d43, 0x5f44, 0x4e49, 0x5243, 0x4145, 0x4553, 0x4f56, 0x554c, 0x454d, +"\000" + IDC_COMBO1, 0x403, 19, 0 +0x4d43, 0x5f44, 0x4544, 0x5243, 0x4145, 0x4553, 0x4f56, 0x554c, 0x454d, +"\000" + IDC_COMBO1, 0x403, 18, 0 +0x4d43, 0x5f44, 0x4853, 0x4441, 0x5245, 0x545f, 0x474f, 0x4c47, 0x0045, + + IDC_COMBO1, 0x403, 13, 0 +0x4d43, 0x5f44, 0x4c43, 0x534f, 0x4145, 0x5050, "\000" + 0 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "&About MPC-HC Test API..." +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 +#pragma code_page(1252) +#include "afxres.rc" // Standard components +#endif +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/MPCTestAPI/MPCTestAPI.vcxproj b/src/MPCTestAPI/MPCTestAPI.vcxproj index f8b05464667..81865c17a13 100644 --- a/src/MPCTestAPI/MPCTestAPI.vcxproj +++ b/src/MPCTestAPI/MPCTestAPI.vcxproj @@ -1,82 +1,82 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {A1F84246-B9A1-455F-97E4-D730AB089947} - MPCTestAPI - MFCProj - MPCTestAPI - - - - - Application - Static - Unicode - - - - - - - - - - - $(SolutionDir)bin\$(Configuration)_$(Platform)\ - $(SolutionDir)bin15\$(Configuration)_$(Platform)\ - - - - _AFX_NO_MFC_CONTROLS_IN_DIALOGS;%(PreprocessorDefinitions) - Level4 - - - $(ProjectDir)res\MPCTestAPI.exe.manifest %(AdditionalManifestFiles) - - - - - - - - Create - - - - - - - - - - - - - - - - ICO - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A1F84246-B9A1-455F-97E4-D730AB089947} + MPCTestAPI + MFCProj + MPCTestAPI + + + + + Application + Static + Unicode + + + + + + + + + + + $(SolutionDir)bin\$(Configuration)_$(Platform)\ + $(SolutionDir)bin15\$(Configuration)_$(Platform)\ + + + + _AFX_NO_MFC_CONTROLS_IN_DIALOGS;%(PreprocessorDefinitions) + Level4 + + + $(ProjectDir)res\MPCTestAPI.exe.manifest %(AdditionalManifestFiles) + + + + + + + + Create + + + + + + + + + + + + + + + + ICO + + + + + \ No newline at end of file diff --git a/src/MPCTestAPI/MPCTestAPI.vcxproj.filters b/src/MPCTestAPI/MPCTestAPI.vcxproj.filters index af8de34a0c3..c41d5ada201 100644 --- a/src/MPCTestAPI/MPCTestAPI.vcxproj.filters +++ b/src/MPCTestAPI/MPCTestAPI.vcxproj.filters @@ -1,61 +1,61 @@ - - - - - {964fcf6f-5fba-4c1a-a7f3-fe297436533d} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {ebf436b1-b3d7-4106-8d3d-2605dc6e9293} - h;hpp;hxx;hm;inl - - - {52bab2df-aaf2-4ca2-97bf-b67260438c51} - ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - - - Resource Files - - + + + + + {964fcf6f-5fba-4c1a-a7f3-fe297436533d} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {ebf436b1-b3d7-4106-8d3d-2605dc6e9293} + h;hpp;hxx;hm;inl + + + {52bab2df-aaf2-4ca2-97bf-b67260438c51} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/MPCTestAPI/MPCTestAPIDlg.cpp b/src/MPCTestAPI/MPCTestAPIDlg.cpp index debae647459..1cd03ba3b2a 100644 --- a/src/MPCTestAPI/MPCTestAPIDlg.cpp +++ b/src/MPCTestAPI/MPCTestAPIDlg.cpp @@ -1,359 +1,359 @@ -/* - * (C) 2008-2015, 2017 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 . - * - */ - -// MPCTestAPIDlg.cpp : implementation file -// - -#include "stdafx.h" -#include "MPCTestAPI.h" -#include "MPCTestAPIDlg.h" -#include - - -LPCTSTR GetMPCCommandName(MPCAPI_COMMAND nCmd) -{ - switch (nCmd) { - case CMD_CONNECT: - return _T("CMD_CONNECT"); - case CMD_STATE: - return _T("CMD_STATE"); - case CMD_PLAYMODE: - return _T("CMD_PLAYMODE"); - case CMD_NOWPLAYING: - return _T("CMD_NOWPLAYING"); - case CMD_LISTSUBTITLETRACKS: - return _T("CMD_LISTSUBTITLETRACKS"); - case CMD_LISTAUDIOTRACKS: - return _T("CMD_LISTAUDIOTRACKS"); - case CMD_PLAYLIST: - return _T("CMD_PLAYLIST"); - default: - return _T("CMD_UNK"); - } -} - -///////////////////////////////////////////////////////////////////////////// -// CAboutDlg dialog used for App About - -class CAboutDlg : public CDialog -{ -public: - CAboutDlg(); - - // 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 - - // Implementation -protected: - //{{AFX_MSG(CAboutDlg) - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) -{ - //{{AFX_DATA_INIT(CAboutDlg) - //}}AFX_DATA_INIT -} - -void CAboutDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CAboutDlg) - //}}AFX_DATA_MAP -} - -BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) - //{{AFX_MSG_MAP(CAboutDlg) - // No message handlers - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataDlg dialog - -CRegisterCopyDataDlg::CRegisterCopyDataDlg(CWnd* pParent /*=nullptr*/) - : CDialog(CRegisterCopyDataDlg::IDD, pParent) - , m_RemoteWindow(nullptr) - , m_hWndMPC(nullptr) - , m_nCommandType(0) -{ - //{{AFX_DATA_INIT(CRegisterCopyDataDlg) - // NOTE: the ClassWizard will add member initialization here - //}}AFX_DATA_INIT - // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 - m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); -} - -void CRegisterCopyDataDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - //{{AFX_DATA_MAP(CRegisterCopyDataDlg) - // NOTE: the ClassWizard will add DDX and DDV calls here - //}}AFX_DATA_MAP - DDX_Text(pDX, IDC_EDIT1, m_strMPCPath); - DDX_Control(pDX, IDC_LOGLIST, m_listBox); - DDX_Text(pDX, IDC_EDIT2, m_txtCommand); - DDX_CBIndex(pDX, IDC_COMBO1, m_nCommandType); -} - -BEGIN_MESSAGE_MAP(CRegisterCopyDataDlg, CDialog) - //{{AFX_MSG_MAP(CRegisterCopyDataDlg) - ON_WM_SYSCOMMAND() - ON_WM_PAINT() - ON_WM_QUERYDRAGICON() - ON_BN_CLICKED(IDC_BUTTON_FINDWINDOW, OnButtonFindwindow) - ON_WM_COPYDATA() - //}}AFX_MSG_MAP - ON_BN_CLICKED(IDC_BUTTON_SENDCOMMAND, &CRegisterCopyDataDlg::OnBnClickedButtonSendcommand) -END_MESSAGE_MAP() - - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataDlg message handlers - -BOOL CRegisterCopyDataDlg::OnInitDialog() -{ - CDialog::OnInitDialog(); - - // Add "About..." menu item to system menu. - - // IDM_ABOUTBOX must be in the system command range. - ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); - ASSERT(IDM_ABOUTBOX < 0xF000); - - CMenu* pSysMenu = GetSystemMenu(FALSE); - if (pSysMenu != nullptr) { - CString strAboutMenu; - if (strAboutMenu.LoadString(IDS_ABOUTBOX)) { - pSysMenu->AppendMenu(MF_SEPARATOR); - pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); - } - } - - // Set the icon for this dialog. The framework does this automatically - // when the application's main window is not a dialog - SetIcon(m_hIcon, TRUE); // Set big icon - SetIcon(m_hIcon, FALSE); // Set small icon - - // TODO: Add extra initialization here - -#if (_MSC_VER < 1910) - m_strMPCPath = _T("..\\..\\..\\..\\bin15\\"); -#else - m_strMPCPath = _T("..\\..\\..\\..\\bin\\"); -#endif - -#if defined(_WIN64) - m_strMPCPath += _T("mpc-hc_x64"); -#else - m_strMPCPath += _T("mpc-hc_x86"); -#endif // _WIN64 - -#if defined(_DEBUG) - m_strMPCPath += _T("_Debug\\"); -#else - m_strMPCPath += _T("\\"); -#endif // _DEBUG - -#if defined(_WIN64) - m_strMPCPath += _T("mpc-hc64.exe"); -#else - m_strMPCPath += _T("mpc-hc.exe"); -#endif // _WIN64 - - UpdateData(FALSE); - - return TRUE; // return TRUE unless you set the focus to a control -} - -void CRegisterCopyDataDlg::OnSysCommand(UINT nID, LPARAM lParam) -{ - if ((nID & 0xFFF0) == IDM_ABOUTBOX) { - CAboutDlg dlgAbout; - dlgAbout.DoModal(); - } else { - CDialog::OnSysCommand(nID, lParam); - } -} - -// If you add a minimize button to your dialog, you will need the code below -// to draw the icon. For MFC applications using the document/view model, -// this is automatically done for you by the framework. - -void CRegisterCopyDataDlg::OnPaint() -{ - if (IsIconic()) { - CPaintDC dc(this); // device context for painting - - SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0); - - // Center icon in client rectangle - int cxIcon = GetSystemMetrics(SM_CXICON); - int cyIcon = GetSystemMetrics(SM_CYICON); - CRect rect; - GetClientRect(&rect); - int x = (rect.Width() - cxIcon + 1) / 2; - int y = (rect.Height() - cyIcon + 1) / 2; - - // Draw the icon - dc.DrawIcon(x, y, m_hIcon); - } else { - CDialog::OnPaint(); - } -} - -// The system calls this to obtain the cursor to display while the user drags -// the minimized window. -HCURSOR CRegisterCopyDataDlg::OnQueryDragIcon() -{ - return (HCURSOR)m_hIcon; -} - -void CRegisterCopyDataDlg::OnButtonFindwindow() -{ - CString strExec; - STARTUPINFO StartupInfo; - PROCESS_INFORMATION ProcessInfo; - - strExec.Format(_T("%s /slave %d"), (LPCTSTR)m_strMPCPath, PtrToInt(GetSafeHwnd())); - UpdateData(TRUE); - - ZeroMemory(&StartupInfo, sizeof(StartupInfo)); - StartupInfo.cb = sizeof(StartupInfo); - GetStartupInfo(&StartupInfo); - if (CreateProcess(nullptr, (LPTSTR)(LPCTSTR)strExec, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &StartupInfo, &ProcessInfo)) { - CloseHandle(ProcessInfo.hProcess); - CloseHandle(ProcessInfo.hThread); - } -} - -void CRegisterCopyDataDlg::Senddata(MPCAPI_COMMAND nCmd, LPCTSTR strCommand) -{ - if (m_hWndMPC) { - COPYDATASTRUCT MyCDS; - - MyCDS.dwData = nCmd; - MyCDS.cbData = (DWORD)(_tcslen(strCommand) + 1) * sizeof(TCHAR); - MyCDS.lpData = (LPVOID) strCommand; - - ::SendMessage(m_hWndMPC, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&MyCDS); - } -} - -BOOL CRegisterCopyDataDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) -{ - CString strMsg; - - if (pCopyDataStruct->dwData == CMD_CONNECT) { - m_hWndMPC = (HWND)IntToPtr(_ttoi((LPCTSTR)pCopyDataStruct->lpData)); - } - - strMsg.Format(_T("%s : %s"), GetMPCCommandName((MPCAPI_COMMAND)pCopyDataStruct->dwData), (LPCTSTR)pCopyDataStruct->lpData); - m_listBox.InsertString(0, strMsg); - return CDialog::OnCopyData(pWnd, pCopyDataStruct); -} - -void CRegisterCopyDataDlg::OnBnClickedButtonSendcommand() -{ - CString strEmpty(_T("")); - UpdateData(TRUE); - - switch (m_nCommandType) { - case 0: - Senddata(CMD_OPENFILE, m_txtCommand); - break; - case 1: - Senddata(CMD_STOP, strEmpty); - break; - case 2: - Senddata(CMD_CLOSEFILE, strEmpty); - break; - case 3: - Senddata(CMD_PLAYPAUSE, strEmpty); - break; - case 4: - Senddata(CMD_ADDTOPLAYLIST, m_txtCommand); - break; - case 5: - Senddata(CMD_STARTPLAYLIST, strEmpty); - break; - case 6: - Senddata(CMD_CLEARPLAYLIST, strEmpty); - break; - case 7: - Senddata(CMD_SETPOSITION, m_txtCommand); - break; - case 8: - Senddata(CMD_SETAUDIODELAY, m_txtCommand); - break; - case 9: - Senddata(CMD_SETSUBTITLEDELAY, m_txtCommand); - break; - case 10: - Senddata(CMD_GETAUDIOTRACKS, strEmpty); - break; - case 11: - Senddata(CMD_GETSUBTITLETRACKS, strEmpty); - break; - case 12: - Senddata(CMD_GETPLAYLIST, strEmpty); - break; - case 13: - Senddata(CMD_SETINDEXPLAYLIST, m_txtCommand); - break; - case 14: - Senddata(CMD_SETAUDIOTRACK, m_txtCommand); - break; - case 15: - Senddata(CMD_SETSUBTITLETRACK, m_txtCommand); - break; - case 16: - Senddata(CMD_TOGGLEFULLSCREEN, m_txtCommand); - break; - case 17: - Senddata(CMD_JUMPFORWARDMED, m_txtCommand); - break; - case 18: - Senddata(CMD_JUMPBACKWARDMED, m_txtCommand); - break; - case 19: - Senddata(CMD_INCREASEVOLUME, m_txtCommand); - break; - case 20: - Senddata(CMD_DECREASEVOLUME, m_txtCommand); - break; - case 21: - //Senddata(CMD_SHADER_TOGGLE, m_txtCommand); - break; - case 22: - Senddata(CMD_CLOSEAPP, m_txtCommand); - break; - } -} +/* + * (C) 2008-2015, 2017 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 . + * + */ + +// MPCTestAPIDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "MPCTestAPI.h" +#include "MPCTestAPIDlg.h" +#include + + +LPCTSTR GetMPCCommandName(MPCAPI_COMMAND nCmd) +{ + switch (nCmd) { + case CMD_CONNECT: + return _T("CMD_CONNECT"); + case CMD_STATE: + return _T("CMD_STATE"); + case CMD_PLAYMODE: + return _T("CMD_PLAYMODE"); + case CMD_NOWPLAYING: + return _T("CMD_NOWPLAYING"); + case CMD_LISTSUBTITLETRACKS: + return _T("CMD_LISTSUBTITLETRACKS"); + case CMD_LISTAUDIOTRACKS: + return _T("CMD_LISTAUDIOTRACKS"); + case CMD_PLAYLIST: + return _T("CMD_PLAYLIST"); + default: + return _T("CMD_UNK"); + } +} + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + + // 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 + + // Implementation +protected: + //{{AFX_MSG(CAboutDlg) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDlg) + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataDlg dialog + +CRegisterCopyDataDlg::CRegisterCopyDataDlg(CWnd* pParent /*=nullptr*/) + : CDialog(CRegisterCopyDataDlg::IDD, pParent) + , m_RemoteWindow(nullptr) + , m_hWndMPC(nullptr) + , m_nCommandType(0) +{ + //{{AFX_DATA_INIT(CRegisterCopyDataDlg) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT + // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CRegisterCopyDataDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CRegisterCopyDataDlg) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP + DDX_Text(pDX, IDC_EDIT1, m_strMPCPath); + DDX_Control(pDX, IDC_LOGLIST, m_listBox); + DDX_Text(pDX, IDC_EDIT2, m_txtCommand); + DDX_CBIndex(pDX, IDC_COMBO1, m_nCommandType); +} + +BEGIN_MESSAGE_MAP(CRegisterCopyDataDlg, CDialog) + //{{AFX_MSG_MAP(CRegisterCopyDataDlg) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED(IDC_BUTTON_FINDWINDOW, OnButtonFindwindow) + ON_WM_COPYDATA() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_BUTTON_SENDCOMMAND, &CRegisterCopyDataDlg::OnBnClickedButtonSendcommand) +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataDlg message handlers + +BOOL CRegisterCopyDataDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Add "About..." menu item to system menu. + + // IDM_ABOUTBOX must be in the system command range. + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != nullptr) { + CString strAboutMenu; + if (strAboutMenu.LoadString(IDS_ABOUTBOX)) { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // Set the icon for this dialog. The framework does this automatically + // when the application's main window is not a dialog + SetIcon(m_hIcon, TRUE); // Set big icon + SetIcon(m_hIcon, FALSE); // Set small icon + + // TODO: Add extra initialization here + +#if (_MSC_VER < 1910) + m_strMPCPath = _T("..\\..\\..\\..\\bin15\\"); +#else + m_strMPCPath = _T("..\\..\\..\\..\\bin\\"); +#endif + +#if defined(_WIN64) + m_strMPCPath += _T("mpc-hc_x64"); +#else + m_strMPCPath += _T("mpc-hc_x86"); +#endif // _WIN64 + +#if defined(_DEBUG) + m_strMPCPath += _T("_Debug\\"); +#else + m_strMPCPath += _T("\\"); +#endif // _DEBUG + +#if defined(_WIN64) + m_strMPCPath += _T("mpc-hc64.exe"); +#else + m_strMPCPath += _T("mpc-hc.exe"); +#endif // _WIN64 + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control +} + +void CRegisterCopyDataDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } else { + CDialog::OnSysCommand(nID, lParam); + } +} + +// If you add a minimize button to your dialog, you will need the code below +// to draw the icon. For MFC applications using the document/view model, +// this is automatically done for you by the framework. + +void CRegisterCopyDataDlg::OnPaint() +{ + if (IsIconic()) { + CPaintDC dc(this); // device context for painting + + SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0); + + // Center icon in client rectangle + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // Draw the icon + dc.DrawIcon(x, y, m_hIcon); + } else { + CDialog::OnPaint(); + } +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CRegisterCopyDataDlg::OnQueryDragIcon() +{ + return (HCURSOR)m_hIcon; +} + +void CRegisterCopyDataDlg::OnButtonFindwindow() +{ + CString strExec; + STARTUPINFO StartupInfo; + PROCESS_INFORMATION ProcessInfo; + + strExec.Format(_T("%s /slave %d"), (LPCTSTR)m_strMPCPath, PtrToInt(GetSafeHwnd())); + UpdateData(TRUE); + + ZeroMemory(&StartupInfo, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + GetStartupInfo(&StartupInfo); + if (CreateProcess(nullptr, (LPTSTR)(LPCTSTR)strExec, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &StartupInfo, &ProcessInfo)) { + CloseHandle(ProcessInfo.hProcess); + CloseHandle(ProcessInfo.hThread); + } +} + +void CRegisterCopyDataDlg::Senddata(MPCAPI_COMMAND nCmd, LPCTSTR strCommand) +{ + if (m_hWndMPC) { + COPYDATASTRUCT MyCDS; + + MyCDS.dwData = nCmd; + MyCDS.cbData = (DWORD)(_tcslen(strCommand) + 1) * sizeof(TCHAR); + MyCDS.lpData = (LPVOID) strCommand; + + ::SendMessage(m_hWndMPC, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&MyCDS); + } +} + +BOOL CRegisterCopyDataDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) +{ + CString strMsg; + + if (pCopyDataStruct->dwData == CMD_CONNECT) { + m_hWndMPC = (HWND)IntToPtr(_ttoi((LPCTSTR)pCopyDataStruct->lpData)); + } + + strMsg.Format(_T("%s : %s"), GetMPCCommandName((MPCAPI_COMMAND)pCopyDataStruct->dwData), (LPCTSTR)pCopyDataStruct->lpData); + m_listBox.InsertString(0, strMsg); + return CDialog::OnCopyData(pWnd, pCopyDataStruct); +} + +void CRegisterCopyDataDlg::OnBnClickedButtonSendcommand() +{ + CString strEmpty(_T("")); + UpdateData(TRUE); + + switch (m_nCommandType) { + case 0: + Senddata(CMD_OPENFILE, m_txtCommand); + break; + case 1: + Senddata(CMD_STOP, strEmpty); + break; + case 2: + Senddata(CMD_CLOSEFILE, strEmpty); + break; + case 3: + Senddata(CMD_PLAYPAUSE, strEmpty); + break; + case 4: + Senddata(CMD_ADDTOPLAYLIST, m_txtCommand); + break; + case 5: + Senddata(CMD_STARTPLAYLIST, strEmpty); + break; + case 6: + Senddata(CMD_CLEARPLAYLIST, strEmpty); + break; + case 7: + Senddata(CMD_SETPOSITION, m_txtCommand); + break; + case 8: + Senddata(CMD_SETAUDIODELAY, m_txtCommand); + break; + case 9: + Senddata(CMD_SETSUBTITLEDELAY, m_txtCommand); + break; + case 10: + Senddata(CMD_GETAUDIOTRACKS, strEmpty); + break; + case 11: + Senddata(CMD_GETSUBTITLETRACKS, strEmpty); + break; + case 12: + Senddata(CMD_GETPLAYLIST, strEmpty); + break; + case 13: + Senddata(CMD_SETINDEXPLAYLIST, m_txtCommand); + break; + case 14: + Senddata(CMD_SETAUDIOTRACK, m_txtCommand); + break; + case 15: + Senddata(CMD_SETSUBTITLETRACK, m_txtCommand); + break; + case 16: + Senddata(CMD_TOGGLEFULLSCREEN, m_txtCommand); + break; + case 17: + Senddata(CMD_JUMPFORWARDMED, m_txtCommand); + break; + case 18: + Senddata(CMD_JUMPBACKWARDMED, m_txtCommand); + break; + case 19: + Senddata(CMD_INCREASEVOLUME, m_txtCommand); + break; + case 20: + Senddata(CMD_DECREASEVOLUME, m_txtCommand); + break; + case 21: + //Senddata(CMD_SHADER_TOGGLE, m_txtCommand); + break; + case 22: + Senddata(CMD_CLOSEAPP, m_txtCommand); + break; + } +} diff --git a/src/MPCTestAPI/MPCTestAPIDlg.h b/src/MPCTestAPI/MPCTestAPIDlg.h index ad3386022ef..c1d7126d4fe 100644 --- a/src/MPCTestAPI/MPCTestAPIDlg.h +++ b/src/MPCTestAPI/MPCTestAPIDlg.h @@ -1,74 +1,74 @@ -/* - * (C) 2008-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 . - * - */ - -// MPCTestAPIDlg.h : header file -// - -#pragma once - -#include "../mpc-hc/MpcApi.h" -#include "HScrollListBox.h" - - -///////////////////////////////////////////////////////////////////////////// -// CRegisterCopyDataDlg dialog - -class CRegisterCopyDataDlg : public CDialog -{ - // Construction -public: - HWND m_RemoteWindow; - CRegisterCopyDataDlg(CWnd* pParent = nullptr); // standard constructor - - // Dialog Data - //{{AFX_DATA(CRegisterCopyDataDlg) - enum { IDD = IDD_REGISTERCOPYDATA_DIALOG }; - // NOTE: the ClassWizard will add data members here - //}}AFX_DATA - - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CRegisterCopyDataDlg) -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - - // Implementation -protected: - HICON m_hIcon; - HWND m_hWndMPC; - - // Generated message map functions - //{{AFX_MSG(CRegisterCopyDataDlg) - virtual BOOL OnInitDialog(); - afx_msg void OnSysCommand(UINT nID, LPARAM lParam); - afx_msg void OnPaint(); - afx_msg HCURSOR OnQueryDragIcon(); - afx_msg void OnButtonFindwindow(); - afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -public: - CString m_strMPCPath; - CHScrollListBox m_listBox; - CString m_txtCommand; - int m_nCommandType; - afx_msg void OnBnClickedButtonSendcommand(); - void Senddata(MPCAPI_COMMAND nCmd, LPCTSTR strCommand); -}; +/* + * (C) 2008-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 . + * + */ + +// MPCTestAPIDlg.h : header file +// + +#pragma once + +#include "../mpc-hc/MpcApi.h" +#include "HScrollListBox.h" + + +///////////////////////////////////////////////////////////////////////////// +// CRegisterCopyDataDlg dialog + +class CRegisterCopyDataDlg : public CDialog +{ + // Construction +public: + HWND m_RemoteWindow; + CRegisterCopyDataDlg(CWnd* pParent = nullptr); // standard constructor + + // Dialog Data + //{{AFX_DATA(CRegisterCopyDataDlg) + enum { IDD = IDD_REGISTERCOPYDATA_DIALOG }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CRegisterCopyDataDlg) +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + + // Implementation +protected: + HICON m_hIcon; + HWND m_hWndMPC; + + // Generated message map functions + //{{AFX_MSG(CRegisterCopyDataDlg) + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnButtonFindwindow(); + afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +public: + CString m_strMPCPath; + CHScrollListBox m_listBox; + CString m_txtCommand; + int m_nCommandType; + afx_msg void OnBnClickedButtonSendcommand(); + void Senddata(MPCAPI_COMMAND nCmd, LPCTSTR strCommand); +}; diff --git a/src/MPCTestAPI/res/MPCTestAPI.exe.manifest b/src/MPCTestAPI/res/MPCTestAPI.exe.manifest index 486cc8e0ac1..996ed084eb2 100644 --- a/src/MPCTestAPI/res/MPCTestAPI.exe.manifest +++ b/src/MPCTestAPI/res/MPCTestAPI.exe.manifest @@ -1,43 +1,43 @@ - - - - MPC-HC Test API - - - - - - - - - - - - - - - - - - - - - - - - true - - + + + + MPC-HC Test API + + + + + + + + + + + + + + + + + + + + + + + + true + + \ No newline at end of file diff --git a/src/MPCTestAPI/resource.h b/src/MPCTestAPI/resource.h index 2799b875ae4..f41d70f238f 100644 --- a/src/MPCTestAPI/resource.h +++ b/src/MPCTestAPI/resource.h @@ -1,30 +1,30 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by MPCTestAPI.rc -// -#define IDM_ABOUTBOX 0x0010 -#define IDD_ABOUTBOX 100 -#define IDS_ABOUTBOX 101 -#define IDD_REGISTERCOPYDATA_DIALOG 102 -#define IDR_MAINFRAME 128 -#define IDC_BUTTON_FINDWINDOW 1001 -#define IDC_EDIT_DATA 1002 -#define IDC_BUTTON_FINDWINDOW2 1002 -#define IDC_BUTTON_SENDCOMMAND 1002 -#define IDC_BUTTON_SENDDATA 1003 -#define IDC_EDIT_INTEGER 1004 -#define IDC_EDIT1 1005 -#define IDC_LOGLIST 1006 -#define IDC_EDIT2 1007 -#define IDC_COMBO1 1008 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 130 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1009 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by MPCTestAPI.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_REGISTERCOPYDATA_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON_FINDWINDOW 1001 +#define IDC_EDIT_DATA 1002 +#define IDC_BUTTON_FINDWINDOW2 1002 +#define IDC_BUTTON_SENDCOMMAND 1002 +#define IDC_BUTTON_SENDDATA 1003 +#define IDC_EDIT_INTEGER 1004 +#define IDC_EDIT1 1005 +#define IDC_LOGLIST 1006 +#define IDC_EDIT2 1007 +#define IDC_COMBO1 1008 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1009 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/MPCTestAPI/stdafx.cpp b/src/MPCTestAPI/stdafx.cpp index 78ec945609e..cfb035199b3 100644 --- a/src/MPCTestAPI/stdafx.cpp +++ b/src/MPCTestAPI/stdafx.cpp @@ -1,21 +1,21 @@ -/* - * (C) 2011-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 . - * - */ - -#include "stdafx.h" +/* + * (C) 2011-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 . + * + */ + +#include "stdafx.h" diff --git a/src/MPCTestAPI/stdafx.h b/src/MPCTestAPI/stdafx.h index cb3cf4d4068..98b948ca65f 100644 --- a/src/MPCTestAPI/stdafx.h +++ b/src/MPCTestAPI/stdafx.h @@ -1,31 +1,31 @@ -/* - * (C) 2011-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 . - * - */ - -#pragma once - -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include // MFC core and standard components -#include // MFC extensions -#include // MFC Automation classes -#include // MFC support for Internet Explorer 4 Common Controls -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT +/* + * (C) 2011-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 . + * + */ + +#pragma once + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT diff --git a/src/SubPic/CoordGeom.cpp b/src/SubPic/CoordGeom.cpp index 41f70ee2ff9..4bb5dfaaa40 100644 --- a/src/SubPic/CoordGeom.cpp +++ b/src/SubPic/CoordGeom.cpp @@ -1,568 +1,568 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "CoordGeom.h" -#include "../DSUtil/DSUtil.h" -#include - -static bool IsZero(float d) -{ - return IsEqual(d, 0.0f); -} - -// -// Vector -// - -Vector::Vector(float _x, float _y, float _z) - : x(_x), y(_y), z(_z) -{ -} - -void Vector::Set(float _x, float _y, float _z) -{ - x = _x; - y = _y; - z = _z; -} - -float Vector::Length() const -{ - return sqrt(x * x + y * y + z * z); -} - -float Vector::Sum() const -{ - return (x + y + z); -} - -float Vector::CrossSum() const -{ - return (x * y + x * z + y * z); -} - -Vector Vector::Cross() const -{ - return Vector(x * y, x * z, y * z); -} - -Vector Vector::Pow(float exp) const -{ - return (exp == 0.0f ? Vector(1.0f, 1.0f, 1.0f) : exp == 1.0f ? *this : Vector(pow(x, exp), pow(y, exp), pow(z, exp))); -} - -Vector Vector::Unit() const -{ - float l = Length(); - if (!l || l == 1.0f) { - return *this; - } - return (*this * (1.0f / l)); -} - -Vector& Vector::Unitalize() -{ - return (*this = Unit()); -} - -Vector Vector::Normal(const Vector& a, const Vector& b) const -{ - return ((a - *this) % (b - a)); -} - -float Vector::Angle(const Vector& a, const Vector& b) const -{ - return (((a - *this).Unit()).Angle((b - *this).Unit())); -} - -float Vector::Angle(const Vector& a) const -{ - float angle = *this | a; - return ((angle > 1.0f) ? 0.0f : (angle < -1.0f) ? (float)M_PI : acos(angle)); -} - -void Vector::Angle(float& u, float& v) const -{ - Vector n = Unit(); - - u = asin(n.y); - - if (IsZero(n.z)) { - v = (float)M_PI_2 * SGN(n.x); - } else if (n.z > 0) { - v = atan(n.x / n.z); - } else if (n.z < 0) { - v = IsZero(n.x) ? (float)M_PI : ((float)M_PI * SGN(n.x) + atan(n.x / n.z)); - } -} - -Vector Vector::Angle() const -{ - Vector ret; - Angle(ret.x, ret.y); - ret.z = 0; - return ret; -} - -Vector& Vector::Min(const Vector& a) -{ - x = (x < a.x) ? x : a.x; - y = (y < a.y) ? y : a.y; - z = (z < a.z) ? z : a.z; - return *this; -} - -Vector& Vector::Max(const Vector& a) -{ - x = (x > a.x) ? x : a.x; - y = (y > a.y) ? y : a.y; - z = (z > a.z) ? z : a.z; - return *this; -} - -Vector Vector::Abs() const -{ - return Vector(fabs(x), fabs(y), fabs(z)); -} - -Vector Vector::Reflect(const Vector& n) const -{ - return (n * ((-*this) | n) * 2 - (-*this)); -} - -Vector Vector::Refract(const Vector& N, float nFront, float nBack, float* nOut /*= nullptr*/) const -{ - Vector D = -*this; - - float N_dot_D = (N | D); - float n = N_dot_D >= 0.0f ? (nFront / nBack) : (nBack / nFront); - - Vector cos_D = N * N_dot_D; - Vector sin_T = (cos_D - D) * n; - - float len_sin_T = sin_T | sin_T; - - if (len_sin_T > 1.0f) { - if (nOut) { - *nOut = N_dot_D >= 0.0f ? nFront : nBack; - } - return this->Reflect(N); - } - - float N_dot_T = (float)sqrt(1.0f - len_sin_T); - if (N_dot_D < 0.0f) { - N_dot_T = -N_dot_T; - } - - if (nOut) { - *nOut = N_dot_D >= 0.0f ? nBack : nFront; - } - - return (sin_T - (N * N_dot_T)); -} - -Vector Vector::Refract2(const Vector& N, float nFrom, float nTo, float* nOut /*= nullptr*/) const -{ - Vector D = -*this; - - float N_dot_D = (N | D); - float n = nFrom / nTo; - - Vector cos_D = N * N_dot_D; - Vector sin_T = (cos_D - D) * n; - - float len_sin_T = sin_T | sin_T; - - if (len_sin_T > 1.0f) { - if (nOut) { - *nOut = nFrom; - } - return this->Reflect(N); - } - - float N_dot_T = (float)sqrt(1.0f - len_sin_T); - if (N_dot_D < 0.0f) { - N_dot_T = -N_dot_T; - } - - if (nOut) { - *nOut = nTo; - } - - return (sin_T - (N * N_dot_T)); -} - -float Vector::operator | (const Vector& v) const -{ - return (x * v.x + y * v.y + z * v.z); -} - -Vector Vector::operator % (const Vector& v) const -{ - return Vector(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); -} - -float& Vector::operator [](size_t i) -{ - return (!i ? x : (i == 1) ? y : z); -} - -Vector Vector::operator - () const -{ - return Vector(-x, -y, -z); -} - -bool Vector::operator == (const Vector& v) const -{ - return (IsZero(x - v.x) && IsZero(y - v.y) && IsZero(z - v.z)); -} - -bool Vector::operator != (const Vector& v) const -{ - return !(*this == v); -} - -Vector Vector::operator + (float d) const -{ - return Vector(x + d, y + d, z + d); -} - -Vector Vector::operator + (const Vector& v) const -{ - return Vector(x + v.x, y + v.y, z + v.z); -} - -Vector Vector::operator - (float d) const -{ - return Vector(x - d, y - d, z - d); -} - -Vector Vector::operator - (const Vector& v) const -{ - return Vector(x - v.x, y - v.y, z - v.z); -} - -Vector Vector::operator * (float d) const -{ - return Vector(x * d, y * d, z * d); -} - -Vector Vector::operator * (const Vector& v) const -{ - return Vector(x * v.x, y * v.y, z * v.z); -} - -Vector Vector::operator / (float d) const -{ - return Vector(x / d, y / d, z / d); -} - -Vector Vector::operator / (const Vector& v) const -{ - return Vector(x / v.x, y / v.y, z / v.z); -} - -Vector& Vector::operator += (float d) -{ - x += d; - y += d; - z += d; - return *this; -} - -Vector& Vector::operator += (const Vector& v) -{ - x += v.x; - y += v.y; - z += v.z; - return *this; -} - -Vector& Vector::operator -= (float d) -{ - x -= d; - y -= d; - z -= d; - return *this; -} - -Vector& Vector::operator -= (Vector& v) -{ - x -= v.x; - y -= v.y; - z -= v.z; - return *this; -} - -Vector& Vector::operator *= (float d) -{ - x *= d; - y *= d; - z *= d; - return *this; -} - -Vector& Vector::operator *= (const Vector& v) -{ - x *= v.x; - y *= v.y; - z *= v.z; - return *this; -} - -Vector& Vector::operator /= (float d) -{ - x /= d; - y /= d; - z /= d; - return *this; -} - -Vector& Vector::operator /= (const Vector& v) -{ - x /= v.x; - y /= v.y; - z /= v.z; - return *this; -} - -// -// Ray -// - -Ray::Ray(const Vector& _p, const Vector& _d) - : p(_p) - , d(_d) -{ -} - -void Ray::Set(const Vector& _p, const Vector& _d) -{ - p = _p; - d = _d; -} - -float Ray::GetDistanceFrom(const Ray& r) const -{ - float t = (d | r.d); - if (IsZero(t)) { - return -std::numeric_limits::infinity(); // plane is parallel to the ray, return -infinite - } - return (((r.p - p) | r.d) / t); -} - -float Ray::GetDistanceFrom(const Vector& v) const -{ - float t = ((v - p) | d) / (d | d); - return ((p + d * t) - v).Length(); -} - -Vector Ray::operator [](float t) const -{ - return (p + d * t); -} - -// -// XForm -// - - -XForm::XForm(const Ray& r, const Vector& s, bool isWorldToLocal /*= true*/) -{ - m_isWorldToLocal = isWorldToLocal; - if (isWorldToLocal) { - *this -= r.p; - *this >>= r.d; - *this /= s; - - } else { - *this *= s; - *this <<= r.d; - *this += r.p; - } -} - -void XForm::operator *= (const Vector& v) -{ - Matrix s; - s.mat[0][0] = v.x; - s.mat[1][1] = v.y; - s.mat[2][2] = v.z; - m *= s; -} - -void XForm::operator += (const Vector& v) -{ - Matrix t; - t.mat[3][0] = v.x; - t.mat[3][1] = v.y; - t.mat[3][2] = v.z; - m *= t; -} - -void XForm::operator <<= (const Vector& v) -{ - Matrix x; - x.mat[1][1] = cos(v.x); - x.mat[1][2] = -sin(v.x); - x.mat[2][1] = sin(v.x); - x.mat[2][2] = cos(v.x); - - Matrix y; - y.mat[0][0] = cos(v.y); - y.mat[0][2] = -sin(v.y); - y.mat[2][0] = sin(v.y); - y.mat[2][2] = cos(v.y); - - Matrix z; - z.mat[0][0] = cos(v.z); - z.mat[0][1] = -sin(v.z); - z.mat[1][0] = sin(v.z); - z.mat[1][1] = cos(v.z); - - m = m_isWorldToLocal ? (m * y * x * z) : (m * z * x * y); -} - -void XForm::operator /= (const Vector& v) -{ - Vector s; - s.x = IsZero(v.x) ? 0.0f : 1.0f / v.x; - s.y = IsZero(v.y) ? 0.0f : 1.0f / v.y; - s.z = IsZero(v.z) ? 0.0f : 1.0f / v.z; - *this *= s; -} - -void XForm::operator -= (const Vector& v) -{ - *this += -v; -} - -void XForm::operator >>= (const Vector& v) -{ - *this <<= -v; -} - -Vector XForm::operator < (const Vector& n) const -{ - Vector ret; - - ret.x = n.x * m.mat[0][0] + - n.y * m.mat[1][0] + - n.z * m.mat[2][0]; - ret.y = n.x * m.mat[0][1] + - n.y * m.mat[1][1] + - n.z * m.mat[2][1]; - ret.z = n.x * m.mat[0][2] + - n.y * m.mat[1][2] + - n.z * m.mat[2][2]; - - return ret; -} - -Vector XForm::operator << (const Vector& v) const -{ - Vector ret; - - ret.x = v.x * m.mat[0][0] + - v.y * m.mat[1][0] + - v.z * m.mat[2][0] + - m.mat[3][0]; - ret.y = v.x * m.mat[0][1] + - v.y * m.mat[1][1] + - v.z * m.mat[2][1] + - m.mat[3][1]; - ret.z = v.x * m.mat[0][2] + - v.y * m.mat[1][2] + - v.z * m.mat[2][2] + - m.mat[3][2]; - - return ret; -} - -Ray XForm::operator << (const Ray& r) const -{ - return Ray(*this << r.p, *this < r.d); -} - -bool XForm::operator == (const XForm& x) const -{ - return m_isWorldToLocal == x.m_isWorldToLocal && m == x.m; -} - -bool XForm::operator != (const XForm& x) const -{ - return !(*this == x); -} - -// -// XForm::Matrix -// - -XForm::Matrix::Matrix() -{ - mat[0][0] = 1.0f; - mat[0][1] = 0.0f; - mat[0][2] = 0.0f; - mat[0][3] = 0.0f; - mat[1][0] = 0.0f; - mat[1][1] = 1.0f; - mat[1][2] = 0.0f; - mat[1][3] = 0.0f; - mat[2][0] = 0.0f; - mat[2][1] = 0.0f; - mat[2][2] = 1.0f; - mat[2][3] = 0.0f; - mat[3][0] = 0.0f; - mat[3][1] = 0.0f; - mat[3][2] = 0.0f; - mat[3][3] = 1.0f; -} - -XForm::Matrix XForm::Matrix::operator * (const Matrix& m) const -{ - Matrix ret; - - for (ptrdiff_t i = 0; i < 4; i++) { - for (ptrdiff_t j = 0; j < 4; j++) { - ret.mat[i][j] = mat[i][0] * m.mat[0][j] + - mat[i][1] * m.mat[1][j] + - mat[i][2] * m.mat[2][j] + - mat[i][3] * m.mat[3][j]; - - if (IsZero(ret.mat[i][j])) { - ret.mat[i][j] = 0.0f; - } - } - } - - return ret; -} - -XForm::Matrix& XForm::Matrix::operator *= (XForm::Matrix& m) -{ - return (*this = *this * m); -} - -bool XForm::Matrix::operator == (const XForm::Matrix& m) const -{ - return mat == m.mat; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "CoordGeom.h" +#include "../DSUtil/DSUtil.h" +#include + +static bool IsZero(float d) +{ + return IsEqual(d, 0.0f); +} + +// +// Vector +// + +Vector::Vector(float _x, float _y, float _z) + : x(_x), y(_y), z(_z) +{ +} + +void Vector::Set(float _x, float _y, float _z) +{ + x = _x; + y = _y; + z = _z; +} + +float Vector::Length() const +{ + return sqrt(x * x + y * y + z * z); +} + +float Vector::Sum() const +{ + return (x + y + z); +} + +float Vector::CrossSum() const +{ + return (x * y + x * z + y * z); +} + +Vector Vector::Cross() const +{ + return Vector(x * y, x * z, y * z); +} + +Vector Vector::Pow(float exp) const +{ + return (exp == 0.0f ? Vector(1.0f, 1.0f, 1.0f) : exp == 1.0f ? *this : Vector(pow(x, exp), pow(y, exp), pow(z, exp))); +} + +Vector Vector::Unit() const +{ + float l = Length(); + if (!l || l == 1.0f) { + return *this; + } + return (*this * (1.0f / l)); +} + +Vector& Vector::Unitalize() +{ + return (*this = Unit()); +} + +Vector Vector::Normal(const Vector& a, const Vector& b) const +{ + return ((a - *this) % (b - a)); +} + +float Vector::Angle(const Vector& a, const Vector& b) const +{ + return (((a - *this).Unit()).Angle((b - *this).Unit())); +} + +float Vector::Angle(const Vector& a) const +{ + float angle = *this | a; + return ((angle > 1.0f) ? 0.0f : (angle < -1.0f) ? (float)M_PI : acos(angle)); +} + +void Vector::Angle(float& u, float& v) const +{ + Vector n = Unit(); + + u = asin(n.y); + + if (IsZero(n.z)) { + v = (float)M_PI_2 * SGN(n.x); + } else if (n.z > 0) { + v = atan(n.x / n.z); + } else if (n.z < 0) { + v = IsZero(n.x) ? (float)M_PI : ((float)M_PI * SGN(n.x) + atan(n.x / n.z)); + } +} + +Vector Vector::Angle() const +{ + Vector ret; + Angle(ret.x, ret.y); + ret.z = 0; + return ret; +} + +Vector& Vector::Min(const Vector& a) +{ + x = (x < a.x) ? x : a.x; + y = (y < a.y) ? y : a.y; + z = (z < a.z) ? z : a.z; + return *this; +} + +Vector& Vector::Max(const Vector& a) +{ + x = (x > a.x) ? x : a.x; + y = (y > a.y) ? y : a.y; + z = (z > a.z) ? z : a.z; + return *this; +} + +Vector Vector::Abs() const +{ + return Vector(fabs(x), fabs(y), fabs(z)); +} + +Vector Vector::Reflect(const Vector& n) const +{ + return (n * ((-*this) | n) * 2 - (-*this)); +} + +Vector Vector::Refract(const Vector& N, float nFront, float nBack, float* nOut /*= nullptr*/) const +{ + Vector D = -*this; + + float N_dot_D = (N | D); + float n = N_dot_D >= 0.0f ? (nFront / nBack) : (nBack / nFront); + + Vector cos_D = N * N_dot_D; + Vector sin_T = (cos_D - D) * n; + + float len_sin_T = sin_T | sin_T; + + if (len_sin_T > 1.0f) { + if (nOut) { + *nOut = N_dot_D >= 0.0f ? nFront : nBack; + } + return this->Reflect(N); + } + + float N_dot_T = (float)sqrt(1.0f - len_sin_T); + if (N_dot_D < 0.0f) { + N_dot_T = -N_dot_T; + } + + if (nOut) { + *nOut = N_dot_D >= 0.0f ? nBack : nFront; + } + + return (sin_T - (N * N_dot_T)); +} + +Vector Vector::Refract2(const Vector& N, float nFrom, float nTo, float* nOut /*= nullptr*/) const +{ + Vector D = -*this; + + float N_dot_D = (N | D); + float n = nFrom / nTo; + + Vector cos_D = N * N_dot_D; + Vector sin_T = (cos_D - D) * n; + + float len_sin_T = sin_T | sin_T; + + if (len_sin_T > 1.0f) { + if (nOut) { + *nOut = nFrom; + } + return this->Reflect(N); + } + + float N_dot_T = (float)sqrt(1.0f - len_sin_T); + if (N_dot_D < 0.0f) { + N_dot_T = -N_dot_T; + } + + if (nOut) { + *nOut = nTo; + } + + return (sin_T - (N * N_dot_T)); +} + +float Vector::operator | (const Vector& v) const +{ + return (x * v.x + y * v.y + z * v.z); +} + +Vector Vector::operator % (const Vector& v) const +{ + return Vector(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); +} + +float& Vector::operator [](size_t i) +{ + return (!i ? x : (i == 1) ? y : z); +} + +Vector Vector::operator - () const +{ + return Vector(-x, -y, -z); +} + +bool Vector::operator == (const Vector& v) const +{ + return (IsZero(x - v.x) && IsZero(y - v.y) && IsZero(z - v.z)); +} + +bool Vector::operator != (const Vector& v) const +{ + return !(*this == v); +} + +Vector Vector::operator + (float d) const +{ + return Vector(x + d, y + d, z + d); +} + +Vector Vector::operator + (const Vector& v) const +{ + return Vector(x + v.x, y + v.y, z + v.z); +} + +Vector Vector::operator - (float d) const +{ + return Vector(x - d, y - d, z - d); +} + +Vector Vector::operator - (const Vector& v) const +{ + return Vector(x - v.x, y - v.y, z - v.z); +} + +Vector Vector::operator * (float d) const +{ + return Vector(x * d, y * d, z * d); +} + +Vector Vector::operator * (const Vector& v) const +{ + return Vector(x * v.x, y * v.y, z * v.z); +} + +Vector Vector::operator / (float d) const +{ + return Vector(x / d, y / d, z / d); +} + +Vector Vector::operator / (const Vector& v) const +{ + return Vector(x / v.x, y / v.y, z / v.z); +} + +Vector& Vector::operator += (float d) +{ + x += d; + y += d; + z += d; + return *this; +} + +Vector& Vector::operator += (const Vector& v) +{ + x += v.x; + y += v.y; + z += v.z; + return *this; +} + +Vector& Vector::operator -= (float d) +{ + x -= d; + y -= d; + z -= d; + return *this; +} + +Vector& Vector::operator -= (Vector& v) +{ + x -= v.x; + y -= v.y; + z -= v.z; + return *this; +} + +Vector& Vector::operator *= (float d) +{ + x *= d; + y *= d; + z *= d; + return *this; +} + +Vector& Vector::operator *= (const Vector& v) +{ + x *= v.x; + y *= v.y; + z *= v.z; + return *this; +} + +Vector& Vector::operator /= (float d) +{ + x /= d; + y /= d; + z /= d; + return *this; +} + +Vector& Vector::operator /= (const Vector& v) +{ + x /= v.x; + y /= v.y; + z /= v.z; + return *this; +} + +// +// Ray +// + +Ray::Ray(const Vector& _p, const Vector& _d) + : p(_p) + , d(_d) +{ +} + +void Ray::Set(const Vector& _p, const Vector& _d) +{ + p = _p; + d = _d; +} + +float Ray::GetDistanceFrom(const Ray& r) const +{ + float t = (d | r.d); + if (IsZero(t)) { + return -std::numeric_limits::infinity(); // plane is parallel to the ray, return -infinite + } + return (((r.p - p) | r.d) / t); +} + +float Ray::GetDistanceFrom(const Vector& v) const +{ + float t = ((v - p) | d) / (d | d); + return ((p + d * t) - v).Length(); +} + +Vector Ray::operator [](float t) const +{ + return (p + d * t); +} + +// +// XForm +// + + +XForm::XForm(const Ray& r, const Vector& s, bool isWorldToLocal /*= true*/) +{ + m_isWorldToLocal = isWorldToLocal; + if (isWorldToLocal) { + *this -= r.p; + *this >>= r.d; + *this /= s; + + } else { + *this *= s; + *this <<= r.d; + *this += r.p; + } +} + +void XForm::operator *= (const Vector& v) +{ + Matrix s; + s.mat[0][0] = v.x; + s.mat[1][1] = v.y; + s.mat[2][2] = v.z; + m *= s; +} + +void XForm::operator += (const Vector& v) +{ + Matrix t; + t.mat[3][0] = v.x; + t.mat[3][1] = v.y; + t.mat[3][2] = v.z; + m *= t; +} + +void XForm::operator <<= (const Vector& v) +{ + Matrix x; + x.mat[1][1] = cos(v.x); + x.mat[1][2] = -sin(v.x); + x.mat[2][1] = sin(v.x); + x.mat[2][2] = cos(v.x); + + Matrix y; + y.mat[0][0] = cos(v.y); + y.mat[0][2] = -sin(v.y); + y.mat[2][0] = sin(v.y); + y.mat[2][2] = cos(v.y); + + Matrix z; + z.mat[0][0] = cos(v.z); + z.mat[0][1] = -sin(v.z); + z.mat[1][0] = sin(v.z); + z.mat[1][1] = cos(v.z); + + m = m_isWorldToLocal ? (m * y * x * z) : (m * z * x * y); +} + +void XForm::operator /= (const Vector& v) +{ + Vector s; + s.x = IsZero(v.x) ? 0.0f : 1.0f / v.x; + s.y = IsZero(v.y) ? 0.0f : 1.0f / v.y; + s.z = IsZero(v.z) ? 0.0f : 1.0f / v.z; + *this *= s; +} + +void XForm::operator -= (const Vector& v) +{ + *this += -v; +} + +void XForm::operator >>= (const Vector& v) +{ + *this <<= -v; +} + +Vector XForm::operator < (const Vector& n) const +{ + Vector ret; + + ret.x = n.x * m.mat[0][0] + + n.y * m.mat[1][0] + + n.z * m.mat[2][0]; + ret.y = n.x * m.mat[0][1] + + n.y * m.mat[1][1] + + n.z * m.mat[2][1]; + ret.z = n.x * m.mat[0][2] + + n.y * m.mat[1][2] + + n.z * m.mat[2][2]; + + return ret; +} + +Vector XForm::operator << (const Vector& v) const +{ + Vector ret; + + ret.x = v.x * m.mat[0][0] + + v.y * m.mat[1][0] + + v.z * m.mat[2][0] + + m.mat[3][0]; + ret.y = v.x * m.mat[0][1] + + v.y * m.mat[1][1] + + v.z * m.mat[2][1] + + m.mat[3][1]; + ret.z = v.x * m.mat[0][2] + + v.y * m.mat[1][2] + + v.z * m.mat[2][2] + + m.mat[3][2]; + + return ret; +} + +Ray XForm::operator << (const Ray& r) const +{ + return Ray(*this << r.p, *this < r.d); +} + +bool XForm::operator == (const XForm& x) const +{ + return m_isWorldToLocal == x.m_isWorldToLocal && m == x.m; +} + +bool XForm::operator != (const XForm& x) const +{ + return !(*this == x); +} + +// +// XForm::Matrix +// + +XForm::Matrix::Matrix() +{ + mat[0][0] = 1.0f; + mat[0][1] = 0.0f; + mat[0][2] = 0.0f; + mat[0][3] = 0.0f; + mat[1][0] = 0.0f; + mat[1][1] = 1.0f; + mat[1][2] = 0.0f; + mat[1][3] = 0.0f; + mat[2][0] = 0.0f; + mat[2][1] = 0.0f; + mat[2][2] = 1.0f; + mat[2][3] = 0.0f; + mat[3][0] = 0.0f; + mat[3][1] = 0.0f; + mat[3][2] = 0.0f; + mat[3][3] = 1.0f; +} + +XForm::Matrix XForm::Matrix::operator * (const Matrix& m) const +{ + Matrix ret; + + for (ptrdiff_t i = 0; i < 4; i++) { + for (ptrdiff_t j = 0; j < 4; j++) { + ret.mat[i][j] = mat[i][0] * m.mat[0][j] + + mat[i][1] * m.mat[1][j] + + mat[i][2] * m.mat[2][j] + + mat[i][3] * m.mat[3][j]; + + if (IsZero(ret.mat[i][j])) { + ret.mat[i][j] = 0.0f; + } + } + } + + return ret; +} + +XForm::Matrix& XForm::Matrix::operator *= (XForm::Matrix& m) +{ + return (*this = *this * m); +} + +bool XForm::Matrix::operator == (const XForm::Matrix& m) const +{ + return mat == m.mat; +} diff --git a/src/SubPic/CoordGeom.h b/src/SubPic/CoordGeom.h index fb86f06c4be..987a30d8283 100644 --- a/src/SubPic/CoordGeom.h +++ b/src/SubPic/CoordGeom.h @@ -1,137 +1,137 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#pragma once - -#include -#include - -class Vector -{ -public: - float x, y, z; - - Vector() { x = y = z = 0.0f; } - Vector(float x, float y, float z); - void Set(float x, float y, float z); - - Vector Normal(const Vector& a, const Vector& b) const; - float Angle(const Vector& a, const Vector& b) const; - float Angle(const Vector& a) const; - void Angle(float& u, float& v) const; // returns spherical coords in radian, -M_PI_2 <= u <= M_PI_2, -M_PI <= v <= M_PI - Vector Angle() const; // does like prev., returns 'u' in 'ret.x', and 'v' in 'ret.y' - - Vector Unit() const; - Vector& Unitalize(); - float Length() const; - float Sum() const; // x + y + z - float CrossSum() const; // xy + xz + yz - Vector Cross() const; // xy, xz, yz - Vector Pow(float exp) const; - - Vector& Min(const Vector& a); - Vector& Max(const Vector& a); - Vector Abs() const; - - Vector Reflect(const Vector& n) const; - Vector Refract(const Vector& n, float nFront, float nBack, float* nOut = nullptr) const; - Vector Refract2(const Vector& n, float nFrom, float nTo, float* nOut = nullptr) const; - - Vector operator - () const; - float& operator [](size_t i); - - float operator | (const Vector& v) const; // dot - Vector operator % (const Vector& v) const; // cross - - bool operator == (const Vector& v) const; - bool operator != (const Vector& v) const; - - Vector operator + (float d) const; - Vector operator + (const Vector& v) const; - Vector operator - (float d) const; - Vector operator - (const Vector& v) const; - Vector operator * (float d) const; - Vector operator * (const Vector& v) const; - Vector operator / (float d) const; - Vector operator / (const Vector& v) const; - Vector& operator += (float d); - Vector& operator += (const Vector& v); - Vector& operator -= (float d); - Vector& operator -= (Vector& v); - Vector& operator *= (float d); - Vector& operator *= (const Vector& v); - Vector& operator /= (float d); - Vector& operator /= (const Vector& v); - - template static float DegToRad(T angle) { return (float)(angle * M_PI / 180); } -}; - -class Ray -{ -public: - Vector p, d; - - Ray() {} - Ray(const Vector& p, const Vector& d); - void Set(const Vector& p, const Vector& d); - - float GetDistanceFrom(const Ray& r) const; // r = plane - float GetDistanceFrom(const Vector& v) const; // v = point - - Vector operator [](float t) const; -}; - -class XForm -{ - class Matrix - { - public: - std::array, 4> mat; - - Matrix(); - - Matrix operator * (const Matrix& m) const; - Matrix& operator *= (Matrix& m); - bool operator == (const Matrix& m) const; - } m; - - bool m_isWorldToLocal; - -public: - XForm() : m_isWorldToLocal(false) {} - XForm(const Ray& r, const Vector& s, bool isWorldToLocal = true); - - void operator *= (const Vector& s); // scale - void operator += (const Vector& t); // translate - void operator <<= (const Vector& r); // rotate - - void operator /= (const Vector& s); // scale - void operator -= (const Vector& t); // translate - void operator >>= (const Vector& r); // rotate - - bool operator == (const XForm& x) const; // compare - bool operator != (const XForm& x) const; - - // transformations - Vector operator < (const Vector& n) const; // normal - Vector operator << (const Vector& v) const; // vector - Ray operator << (const Ray& r) const; // ray -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#pragma once + +#include +#include + +class Vector +{ +public: + float x, y, z; + + Vector() { x = y = z = 0.0f; } + Vector(float x, float y, float z); + void Set(float x, float y, float z); + + Vector Normal(const Vector& a, const Vector& b) const; + float Angle(const Vector& a, const Vector& b) const; + float Angle(const Vector& a) const; + void Angle(float& u, float& v) const; // returns spherical coords in radian, -M_PI_2 <= u <= M_PI_2, -M_PI <= v <= M_PI + Vector Angle() const; // does like prev., returns 'u' in 'ret.x', and 'v' in 'ret.y' + + Vector Unit() const; + Vector& Unitalize(); + float Length() const; + float Sum() const; // x + y + z + float CrossSum() const; // xy + xz + yz + Vector Cross() const; // xy, xz, yz + Vector Pow(float exp) const; + + Vector& Min(const Vector& a); + Vector& Max(const Vector& a); + Vector Abs() const; + + Vector Reflect(const Vector& n) const; + Vector Refract(const Vector& n, float nFront, float nBack, float* nOut = nullptr) const; + Vector Refract2(const Vector& n, float nFrom, float nTo, float* nOut = nullptr) const; + + Vector operator - () const; + float& operator [](size_t i); + + float operator | (const Vector& v) const; // dot + Vector operator % (const Vector& v) const; // cross + + bool operator == (const Vector& v) const; + bool operator != (const Vector& v) const; + + Vector operator + (float d) const; + Vector operator + (const Vector& v) const; + Vector operator - (float d) const; + Vector operator - (const Vector& v) const; + Vector operator * (float d) const; + Vector operator * (const Vector& v) const; + Vector operator / (float d) const; + Vector operator / (const Vector& v) const; + Vector& operator += (float d); + Vector& operator += (const Vector& v); + Vector& operator -= (float d); + Vector& operator -= (Vector& v); + Vector& operator *= (float d); + Vector& operator *= (const Vector& v); + Vector& operator /= (float d); + Vector& operator /= (const Vector& v); + + template static float DegToRad(T angle) { return (float)(angle * M_PI / 180); } +}; + +class Ray +{ +public: + Vector p, d; + + Ray() {} + Ray(const Vector& p, const Vector& d); + void Set(const Vector& p, const Vector& d); + + float GetDistanceFrom(const Ray& r) const; // r = plane + float GetDistanceFrom(const Vector& v) const; // v = point + + Vector operator [](float t) const; +}; + +class XForm +{ + class Matrix + { + public: + std::array, 4> mat; + + Matrix(); + + Matrix operator * (const Matrix& m) const; + Matrix& operator *= (Matrix& m); + bool operator == (const Matrix& m) const; + } m; + + bool m_isWorldToLocal; + +public: + XForm() : m_isWorldToLocal(false) {} + XForm(const Ray& r, const Vector& s, bool isWorldToLocal = true); + + void operator *= (const Vector& s); // scale + void operator += (const Vector& t); // translate + void operator <<= (const Vector& r); // rotate + + void operator /= (const Vector& s); // scale + void operator -= (const Vector& t); // translate + void operator >>= (const Vector& r); // rotate + + bool operator == (const XForm& x) const; // compare + bool operator != (const XForm& x) const; + + // transformations + Vector operator < (const Vector& n) const; // normal + Vector operator << (const Vector& v) const; // vector + Ray operator << (const Ray& r) const; // ray +}; diff --git a/src/SubPic/DX9SubPic.cpp b/src/SubPic/DX9SubPic.cpp index e6cbeb98eca..17bf91ec9db 100644 --- a/src/SubPic/DX9SubPic.cpp +++ b/src/SubPic/DX9SubPic.cpp @@ -1,482 +1,482 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "DX9SubPic.h" -#include -#include - -#include "mpc-hc_config.h" - -#if !TRACE_SUBTITLES -#define TRACE(...) -#endif - -// -// CDX9SubPic -// - -CDX9SubPic::CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator* pAllocator, bool bExternalRenderer) - : m_pSurface(pSurface) - , m_pAllocator(pAllocator) - , m_bExternalRenderer(bExternalRenderer) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (SUCCEEDED(m_pSurface->GetDesc(&desc))) { - m_maxsize.SetSize(desc.Width, desc.Height); - m_rcDirty.SetRect(0, 0, desc.Width, desc.Height); - } -} - -CDX9SubPic::~CDX9SubPic() -{ - CAutoLock lock(&CDX9SubPicAllocator::ms_surfaceQueueLock); - // Add surface to cache - if (m_pAllocator) { - for (POSITION pos = m_pAllocator->m_allocatedSurfaces.GetHeadPosition(); pos;) { - POSITION thisPos = pos; - CDX9SubPic* pSubPic = m_pAllocator->m_allocatedSurfaces.GetNext(pos); - if (pSubPic == this) { - m_pAllocator->m_allocatedSurfaces.RemoveAt(thisPos); - break; - } - } - m_pAllocator->m_freeSurfaces.AddTail(m_pSurface); - } -} - - -// ISubPic - -STDMETHODIMP_(void*) CDX9SubPic::GetObject() -{ - CComPtr pTexture; - if (SUCCEEDED(m_pSurface->GetContainer(IID_PPV_ARGS(&pTexture)))) { - return (IDirect3DTexture9*)pTexture; - } - - return nullptr; -} - -STDMETHODIMP CDX9SubPic::GetDesc(SubPicDesc& spd) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(m_pSurface->GetDesc(&desc))) { - return E_FAIL; - } - - spd.type = 0; - spd.w = m_size.cx; - spd.h = m_size.cy; - spd.bpp = - desc.Format == D3DFMT_A8R8G8B8 ? 32 : - desc.Format == D3DFMT_A4R4G4B4 ? 16 : 0; - spd.pitch = 0; - spd.bits = nullptr; - spd.vidrect = m_vidrect; - - return S_OK; -} - -STDMETHODIMP CDX9SubPic::CopyTo(ISubPic* pSubPic) -{ - HRESULT hr; - if (FAILED(hr = __super::CopyTo(pSubPic))) { - return hr; - } - - if (m_rcDirty.IsRectEmpty()) { - return S_FALSE; - } - - CComPtr pD3DDev; - if (!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) { - return E_FAIL; - } - - IDirect3DTexture9* pSrcTex = (IDirect3DTexture9*)GetObject(); - CComPtr pSrcSurf; - pSrcTex->GetSurfaceLevel(0, &pSrcSurf); - if (!pSrcSurf) { - return E_FAIL; - } - D3DSURFACE_DESC srcDesc; - pSrcSurf->GetDesc(&srcDesc); - - IDirect3DTexture9* pDstTex = (IDirect3DTexture9*)pSubPic->GetObject(); - CComPtr pDstSurf; - pDstTex->GetSurfaceLevel(0, &pDstSurf); - D3DSURFACE_DESC dstDesc; - pDstSurf->GetDesc(&dstDesc); - - RECT r; - SetRect(&r, 0, 0, std::min(srcDesc.Width, dstDesc.Width), std::min(srcDesc.Height, dstDesc.Height)); - POINT p = { 0, 0 }; - hr = pD3DDev->UpdateSurface(pSrcSurf, &r, pDstSurf, &p); - - return SUCCEEDED(hr) ? S_OK : E_FAIL; -} - -STDMETHODIMP CDX9SubPic::ClearDirtyRect() -{ - if (m_rcDirty.IsRectEmpty()) { - return S_FALSE; - } - - CComPtr pD3DDev; - if (!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) { - return E_FAIL; - } - - m_rcDirty.IntersectRect(m_rcDirty, CRect(0, 0, m_maxsize.cx, m_maxsize.cy)); - - SubPicDesc spd; - if (SUCCEEDED(Lock(spd))) { - int h = m_rcDirty.Height(); - BYTE* ptr = spd.bits + spd.pitch * m_rcDirty.top + (m_rcDirty.left * spd.bpp >> 3); - - if (spd.bpp == 16) { - const unsigned short color = m_bInvAlpha ? 0x00000000 : 0xFF000000; - const int w2 = m_rcDirty.Width() * 2; - while (h-- > 0) { - memsetw(ptr, color, w2); - ptr += spd.pitch; - } - } else if (spd.bpp == 32) { - const DWORD color = m_bInvAlpha ? 0x00000000 : 0xFF000000; - const int w4 = m_rcDirty.Width() * 4; - while (h-- > 0) { - memsetd(ptr, color, w4); - ptr += spd.pitch; - } - } - Unlock(nullptr); - } - - m_rcDirty.SetRectEmpty(); - - return S_OK; -} - -STDMETHODIMP CDX9SubPic::Lock(SubPicDesc& spd) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(m_pSurface->GetDesc(&desc))) { - return E_FAIL; - } - - D3DLOCKED_RECT LockedRect; - ZeroMemory(&LockedRect, sizeof(LockedRect)); - if (FAILED(m_pSurface->LockRect(&LockedRect, nullptr, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK))) { - return E_FAIL; - } - - spd.type = 0; - spd.w = m_size.cx; - spd.h = m_size.cy; - spd.bpp = - desc.Format == D3DFMT_A8R8G8B8 ? 32 : - desc.Format == D3DFMT_A4R4G4B4 ? 16 : 0; - spd.pitch = LockedRect.Pitch; - spd.bits = (BYTE*)LockedRect.pBits; - spd.vidrect = m_vidrect; - - return S_OK; -} - -STDMETHODIMP CDX9SubPic::Unlock(RECT* pDirtyRect) -{ - m_pSurface->UnlockRect(); - - if (pDirtyRect) { - m_rcDirty = pDirtyRect; - if (!m_rcDirty.IsRectEmpty()) { - m_rcDirty.InflateRect(1, 1); - m_rcDirty.IntersectRect(m_rcDirty, CRect(0, 0, m_size.cx, m_size.cy)); - - CComPtr pTexture = (IDirect3DTexture9*)GetObject(); - if (pTexture) { - pTexture->AddDirtyRect(&m_rcDirty); - } - } - } else { - m_rcDirty = CRect(CPoint(0, 0), m_size); - } - - return S_OK; -} - -STDMETHODIMP CDX9SubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) -{ - ASSERT(pTarget == nullptr); - - if (!pSrc || !pDst) { - return E_POINTER; - } - - CRect src(*pSrc), dst(*pDst); - - CComPtr pD3DDev; - CComPtr pTexture = (IDirect3DTexture9*)GetObject(); - if (!pTexture || FAILED(pTexture->GetDevice(&pD3DDev)) || !pD3DDev) { - return E_NOINTERFACE; - } - - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile - // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly - // initialized and thus the subtitles weren't shown. - struct { - float x, y, z, rhw; - float tu, tv; - } pVertices[] = { - {float(dst.left), float(dst.top), 0.5f, 2.0f, float(src.left) / w, float(src.top) / h}, - {float(dst.right), float(dst.top), 0.5f, 2.0f, float(src.right) / w, float(src.top) / h}, - {float(dst.left), float(dst.bottom), 0.5f, 2.0f, float(src.left) / w, float(src.bottom) / h}, - {float(dst.right), float(dst.bottom), 0.5f, 2.0f, float(src.right) / w, float(src.bottom) / h}, - }; - - for (size_t i = 0; i < _countof(pVertices); i++) { - pVertices[i].x -= 0.5f; - pVertices[i].y -= 0.5f; - } - - pD3DDev->SetTexture(0, pTexture); - - // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE - // so we need to provide default values in case GetRenderState fails - DWORD abe, sb, db; - if (FAILED(pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { - abe = FALSE; - } - if (FAILED(pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { - sb = D3DBLEND_ONE; - } - if (FAILED(pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { - db = D3DBLEND_ZERO; - } - - pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... - pD3DDev->SetRenderState(D3DRS_DESTBLEND, m_bInvAlpha ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst - - pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - - if (src == dst) { - pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - } else { - pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - } - pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); - pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); - pD3DDev->SetSamplerState(0, D3DSAMP_BORDERCOLOR, m_bInvAlpha ? 0x00000000 : 0xFF000000); - - /*// - D3DCAPS9 d3dcaps9; - pD3DDev->GetDeviceCaps(&d3dcaps9); - if (d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS) { - pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE); - pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); - pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS); - } - */// - - pD3DDev->SetPixelShader(nullptr); - - if (m_bExternalRenderer && FAILED(pD3DDev->BeginScene())) { - return E_FAIL; - } - - pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); - pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); - - if (m_bExternalRenderer) { - pD3DDev->EndScene(); - } - - pD3DDev->SetTexture(0, nullptr); - - pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); - pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); - pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); - - return S_OK; -} - -// -// CDX9SubPicAllocator -// - -CDX9SubPicAllocator::CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool bExternalRenderer) - : CSubPicAllocatorImpl(maxsize, true) - , m_pD3DDev(pD3DDev) - , m_maxsize(maxsize) - , m_bExternalRenderer(bExternalRenderer) -{ -} - -CCritSec CDX9SubPicAllocator::ms_surfaceQueueLock; - -CDX9SubPicAllocator::~CDX9SubPicAllocator() -{ - ClearCache(); -} - -void CDX9SubPicAllocator::GetStats(int& nFree, int& nAlloc) const -{ - CAutoLock autoLock(&ms_surfaceQueueLock); - nFree = (int)m_freeSurfaces.GetCount(); - nAlloc = (int)m_allocatedSurfaces.GetCount(); -} - -void CDX9SubPicAllocator::ClearCache() -{ - TRACE(_T("CDX9SubPicAllocator::ClearCache\n")); - // Clear the allocator of any remaining subpics - CAutoLock autoLock(&ms_surfaceQueueLock); - for (POSITION pos = m_allocatedSurfaces.GetHeadPosition(); pos;) { - CDX9SubPic* pSubPic = m_allocatedSurfaces.GetNext(pos); - pSubPic->m_pAllocator = nullptr; - } - m_allocatedSurfaces.RemoveAll(); - m_freeSurfaces.RemoveAll(); -} - -// ISubPicAllocator - -STDMETHODIMP CDX9SubPicAllocator::ChangeDevice(IUnknown* pDev) -{ - CComQIPtr pD3DDev = pDev; - CheckPointer(pD3DDev, E_NOINTERFACE); - - CAutoLock cAutoLock(this); - HRESULT hr = S_FALSE; - if (m_pD3DDev != pD3DDev) { - ClearCache(); - m_pD3DDev = pD3DDev; - hr = __super::ChangeDevice(pDev); - } - - return hr; -} - -STDMETHODIMP CDX9SubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) -{ - CAutoLock cAutoLock(this); - -#if DEBUG_OVERRIDE_TEXTURE_SIZE - maxTextureSize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); -#endif - - if (maxTextureSize.cx > 0 && maxTextureSize.cy > 0 && m_maxsize != maxTextureSize) { - ClearCache(); - m_maxsize = maxTextureSize; - TRACE(_T("CDX9SubPicAllocator::SetMaxTextureSize %dx%d\n"), m_maxsize.cx, m_maxsize.cy); - } - - return S_OK; -} - -// ISubPicAllocatorImpl - -bool CDX9SubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) -{ - if (!ppSubPic) { - return false; - } - - if (m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { - TRACE(_T("CDX9SubPicAllocator::Alloc -> maxsize is zero\n")); - return false; - } - -#if DEBUG_OVERRIDE_TEXTURE_SIZE - ASSERT(m_maxsize.cx == DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH && m_maxsize.cy == DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); -#endif - - CAutoLock cAutoLock(this); - - *ppSubPic = nullptr; - - CComPtr pSurface; - - if (!fStatic) { - CAutoLock cAutoLock2(&ms_surfaceQueueLock); - if (!m_freeSurfaces.IsEmpty()) { - pSurface = m_freeSurfaces.RemoveHead(); - } - } - - if (!pSurface) { - CComPtr pTexture; - HRESULT hr = m_pD3DDev->CreateTexture(m_maxsize.cx, m_maxsize.cy, 1, 0, D3DFMT_A8R8G8B8, fStatic ? D3DPOOL_SYSTEMMEM : D3DPOOL_DEFAULT, &pTexture, nullptr); - if (FAILED(hr)) { - TRACE(_T("CDX9SubPicAllocator::Alloc -> CreateTexture failed (%dx%d), hr=%x\n"), m_maxsize.cx, m_maxsize.cy, hr); - return false; - } - - hr = pTexture->GetSurfaceLevel(0, &pSurface); - if (FAILED(hr)) { - TRACE(_T("CDX9SubPicAllocator::Alloc -> GetSurfaceLevel failed, hr=%x\n"), hr); - return false; - } - - TRACE(_T("CDX9SubPicAllocator::Alloc -> Surface allocated (%dx%d)\n"), m_maxsize.cx, m_maxsize.cy); - } - - try { - *ppSubPic = DEBUG_NEW CDX9SubPic(pSurface, fStatic ? nullptr : this, m_bExternalRenderer); - } catch (CMemoryException* e) { - e->Delete(); - TRACE(_T("CDX9SubPicAllocator::Alloc -> CDX9SubPic gave memory exception\n")); - return false; - } - - (*ppSubPic)->AddRef(); - (*ppSubPic)->SetInverseAlpha(m_bInvAlpha); - - if (!fStatic) { - CAutoLock cAutoLock2(&ms_surfaceQueueLock); - m_allocatedSurfaces.AddHead((CDX9SubPic*)*ppSubPic); - } - - return true; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "DX9SubPic.h" +#include +#include + +#include "mpc-hc_config.h" + +#if !TRACE_SUBTITLES +#define TRACE(...) +#endif + +// +// CDX9SubPic +// + +CDX9SubPic::CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator* pAllocator, bool bExternalRenderer) + : m_pSurface(pSurface) + , m_pAllocator(pAllocator) + , m_bExternalRenderer(bExternalRenderer) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (SUCCEEDED(m_pSurface->GetDesc(&desc))) { + m_maxsize.SetSize(desc.Width, desc.Height); + m_rcDirty.SetRect(0, 0, desc.Width, desc.Height); + } +} + +CDX9SubPic::~CDX9SubPic() +{ + CAutoLock lock(&CDX9SubPicAllocator::ms_surfaceQueueLock); + // Add surface to cache + if (m_pAllocator) { + for (POSITION pos = m_pAllocator->m_allocatedSurfaces.GetHeadPosition(); pos;) { + POSITION thisPos = pos; + CDX9SubPic* pSubPic = m_pAllocator->m_allocatedSurfaces.GetNext(pos); + if (pSubPic == this) { + m_pAllocator->m_allocatedSurfaces.RemoveAt(thisPos); + break; + } + } + m_pAllocator->m_freeSurfaces.AddTail(m_pSurface); + } +} + + +// ISubPic + +STDMETHODIMP_(void*) CDX9SubPic::GetObject() +{ + CComPtr pTexture; + if (SUCCEEDED(m_pSurface->GetContainer(IID_PPV_ARGS(&pTexture)))) { + return (IDirect3DTexture9*)pTexture; + } + + return nullptr; +} + +STDMETHODIMP CDX9SubPic::GetDesc(SubPicDesc& spd) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(m_pSurface->GetDesc(&desc))) { + return E_FAIL; + } + + spd.type = 0; + spd.w = m_size.cx; + spd.h = m_size.cy; + spd.bpp = + desc.Format == D3DFMT_A8R8G8B8 ? 32 : + desc.Format == D3DFMT_A4R4G4B4 ? 16 : 0; + spd.pitch = 0; + spd.bits = nullptr; + spd.vidrect = m_vidrect; + + return S_OK; +} + +STDMETHODIMP CDX9SubPic::CopyTo(ISubPic* pSubPic) +{ + HRESULT hr; + if (FAILED(hr = __super::CopyTo(pSubPic))) { + return hr; + } + + if (m_rcDirty.IsRectEmpty()) { + return S_FALSE; + } + + CComPtr pD3DDev; + if (!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) { + return E_FAIL; + } + + IDirect3DTexture9* pSrcTex = (IDirect3DTexture9*)GetObject(); + CComPtr pSrcSurf; + pSrcTex->GetSurfaceLevel(0, &pSrcSurf); + if (!pSrcSurf) { + return E_FAIL; + } + D3DSURFACE_DESC srcDesc; + pSrcSurf->GetDesc(&srcDesc); + + IDirect3DTexture9* pDstTex = (IDirect3DTexture9*)pSubPic->GetObject(); + CComPtr pDstSurf; + pDstTex->GetSurfaceLevel(0, &pDstSurf); + D3DSURFACE_DESC dstDesc; + pDstSurf->GetDesc(&dstDesc); + + RECT r; + SetRect(&r, 0, 0, std::min(srcDesc.Width, dstDesc.Width), std::min(srcDesc.Height, dstDesc.Height)); + POINT p = { 0, 0 }; + hr = pD3DDev->UpdateSurface(pSrcSurf, &r, pDstSurf, &p); + + return SUCCEEDED(hr) ? S_OK : E_FAIL; +} + +STDMETHODIMP CDX9SubPic::ClearDirtyRect() +{ + if (m_rcDirty.IsRectEmpty()) { + return S_FALSE; + } + + CComPtr pD3DDev; + if (!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) { + return E_FAIL; + } + + m_rcDirty.IntersectRect(m_rcDirty, CRect(0, 0, m_maxsize.cx, m_maxsize.cy)); + + SubPicDesc spd; + if (SUCCEEDED(Lock(spd))) { + int h = m_rcDirty.Height(); + BYTE* ptr = spd.bits + spd.pitch * m_rcDirty.top + (m_rcDirty.left * spd.bpp >> 3); + + if (spd.bpp == 16) { + const unsigned short color = m_bInvAlpha ? 0x00000000 : 0xFF000000; + const int w2 = m_rcDirty.Width() * 2; + while (h-- > 0) { + memsetw(ptr, color, w2); + ptr += spd.pitch; + } + } else if (spd.bpp == 32) { + const DWORD color = m_bInvAlpha ? 0x00000000 : 0xFF000000; + const int w4 = m_rcDirty.Width() * 4; + while (h-- > 0) { + memsetd(ptr, color, w4); + ptr += spd.pitch; + } + } + Unlock(nullptr); + } + + m_rcDirty.SetRectEmpty(); + + return S_OK; +} + +STDMETHODIMP CDX9SubPic::Lock(SubPicDesc& spd) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(m_pSurface->GetDesc(&desc))) { + return E_FAIL; + } + + D3DLOCKED_RECT LockedRect; + ZeroMemory(&LockedRect, sizeof(LockedRect)); + if (FAILED(m_pSurface->LockRect(&LockedRect, nullptr, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK))) { + return E_FAIL; + } + + spd.type = 0; + spd.w = m_size.cx; + spd.h = m_size.cy; + spd.bpp = + desc.Format == D3DFMT_A8R8G8B8 ? 32 : + desc.Format == D3DFMT_A4R4G4B4 ? 16 : 0; + spd.pitch = LockedRect.Pitch; + spd.bits = (BYTE*)LockedRect.pBits; + spd.vidrect = m_vidrect; + + return S_OK; +} + +STDMETHODIMP CDX9SubPic::Unlock(RECT* pDirtyRect) +{ + m_pSurface->UnlockRect(); + + if (pDirtyRect) { + m_rcDirty = pDirtyRect; + if (!m_rcDirty.IsRectEmpty()) { + m_rcDirty.InflateRect(1, 1); + m_rcDirty.IntersectRect(m_rcDirty, CRect(0, 0, m_size.cx, m_size.cy)); + + CComPtr pTexture = (IDirect3DTexture9*)GetObject(); + if (pTexture) { + pTexture->AddDirtyRect(&m_rcDirty); + } + } + } else { + m_rcDirty = CRect(CPoint(0, 0), m_size); + } + + return S_OK; +} + +STDMETHODIMP CDX9SubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) +{ + ASSERT(pTarget == nullptr); + + if (!pSrc || !pDst) { + return E_POINTER; + } + + CRect src(*pSrc), dst(*pDst); + + CComPtr pD3DDev; + CComPtr pTexture = (IDirect3DTexture9*)GetObject(); + if (!pTexture || FAILED(pTexture->GetDevice(&pD3DDev)) || !pD3DDev) { + return E_NOINTERFACE; + } + + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile + // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly + // initialized and thus the subtitles weren't shown. + struct { + float x, y, z, rhw; + float tu, tv; + } pVertices[] = { + {float(dst.left), float(dst.top), 0.5f, 2.0f, float(src.left) / w, float(src.top) / h}, + {float(dst.right), float(dst.top), 0.5f, 2.0f, float(src.right) / w, float(src.top) / h}, + {float(dst.left), float(dst.bottom), 0.5f, 2.0f, float(src.left) / w, float(src.bottom) / h}, + {float(dst.right), float(dst.bottom), 0.5f, 2.0f, float(src.right) / w, float(src.bottom) / h}, + }; + + for (size_t i = 0; i < _countof(pVertices); i++) { + pVertices[i].x -= 0.5f; + pVertices[i].y -= 0.5f; + } + + pD3DDev->SetTexture(0, pTexture); + + // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE + // so we need to provide default values in case GetRenderState fails + DWORD abe, sb, db; + if (FAILED(pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { + abe = FALSE; + } + if (FAILED(pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { + sb = D3DBLEND_ONE; + } + if (FAILED(pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { + db = D3DBLEND_ZERO; + } + + pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... + pD3DDev->SetRenderState(D3DRS_DESTBLEND, m_bInvAlpha ? D3DBLEND_INVSRCALPHA : D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst + + pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + if (src == dst) { + pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + } else { + pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + } + pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); + pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); + pD3DDev->SetSamplerState(0, D3DSAMP_BORDERCOLOR, m_bInvAlpha ? 0x00000000 : 0xFF000000); + + /*// + D3DCAPS9 d3dcaps9; + pD3DDev->GetDeviceCaps(&d3dcaps9); + if (d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS) { + pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE); + pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS); + } + */// + + pD3DDev->SetPixelShader(nullptr); + + if (m_bExternalRenderer && FAILED(pD3DDev->BeginScene())) { + return E_FAIL; + } + + pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + + if (m_bExternalRenderer) { + pD3DDev->EndScene(); + } + + pD3DDev->SetTexture(0, nullptr); + + pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); + pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); + pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); + + return S_OK; +} + +// +// CDX9SubPicAllocator +// + +CDX9SubPicAllocator::CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool bExternalRenderer) + : CSubPicAllocatorImpl(maxsize, true) + , m_pD3DDev(pD3DDev) + , m_maxsize(maxsize) + , m_bExternalRenderer(bExternalRenderer) +{ +} + +CCritSec CDX9SubPicAllocator::ms_surfaceQueueLock; + +CDX9SubPicAllocator::~CDX9SubPicAllocator() +{ + ClearCache(); +} + +void CDX9SubPicAllocator::GetStats(int& nFree, int& nAlloc) const +{ + CAutoLock autoLock(&ms_surfaceQueueLock); + nFree = (int)m_freeSurfaces.GetCount(); + nAlloc = (int)m_allocatedSurfaces.GetCount(); +} + +void CDX9SubPicAllocator::ClearCache() +{ + TRACE(_T("CDX9SubPicAllocator::ClearCache\n")); + // Clear the allocator of any remaining subpics + CAutoLock autoLock(&ms_surfaceQueueLock); + for (POSITION pos = m_allocatedSurfaces.GetHeadPosition(); pos;) { + CDX9SubPic* pSubPic = m_allocatedSurfaces.GetNext(pos); + pSubPic->m_pAllocator = nullptr; + } + m_allocatedSurfaces.RemoveAll(); + m_freeSurfaces.RemoveAll(); +} + +// ISubPicAllocator + +STDMETHODIMP CDX9SubPicAllocator::ChangeDevice(IUnknown* pDev) +{ + CComQIPtr pD3DDev = pDev; + CheckPointer(pD3DDev, E_NOINTERFACE); + + CAutoLock cAutoLock(this); + HRESULT hr = S_FALSE; + if (m_pD3DDev != pD3DDev) { + ClearCache(); + m_pD3DDev = pD3DDev; + hr = __super::ChangeDevice(pDev); + } + + return hr; +} + +STDMETHODIMP CDX9SubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) +{ + CAutoLock cAutoLock(this); + +#if DEBUG_OVERRIDE_TEXTURE_SIZE + maxTextureSize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); +#endif + + if (maxTextureSize.cx > 0 && maxTextureSize.cy > 0 && m_maxsize != maxTextureSize) { + ClearCache(); + m_maxsize = maxTextureSize; + TRACE(_T("CDX9SubPicAllocator::SetMaxTextureSize %dx%d\n"), m_maxsize.cx, m_maxsize.cy); + } + + return S_OK; +} + +// ISubPicAllocatorImpl + +bool CDX9SubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) +{ + if (!ppSubPic) { + return false; + } + + if (m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { + TRACE(_T("CDX9SubPicAllocator::Alloc -> maxsize is zero\n")); + return false; + } + +#if DEBUG_OVERRIDE_TEXTURE_SIZE + ASSERT(m_maxsize.cx == DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH && m_maxsize.cy == DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); +#endif + + CAutoLock cAutoLock(this); + + *ppSubPic = nullptr; + + CComPtr pSurface; + + if (!fStatic) { + CAutoLock cAutoLock2(&ms_surfaceQueueLock); + if (!m_freeSurfaces.IsEmpty()) { + pSurface = m_freeSurfaces.RemoveHead(); + } + } + + if (!pSurface) { + CComPtr pTexture; + HRESULT hr = m_pD3DDev->CreateTexture(m_maxsize.cx, m_maxsize.cy, 1, 0, D3DFMT_A8R8G8B8, fStatic ? D3DPOOL_SYSTEMMEM : D3DPOOL_DEFAULT, &pTexture, nullptr); + if (FAILED(hr)) { + TRACE(_T("CDX9SubPicAllocator::Alloc -> CreateTexture failed (%dx%d), hr=%x\n"), m_maxsize.cx, m_maxsize.cy, hr); + return false; + } + + hr = pTexture->GetSurfaceLevel(0, &pSurface); + if (FAILED(hr)) { + TRACE(_T("CDX9SubPicAllocator::Alloc -> GetSurfaceLevel failed, hr=%x\n"), hr); + return false; + } + + TRACE(_T("CDX9SubPicAllocator::Alloc -> Surface allocated (%dx%d)\n"), m_maxsize.cx, m_maxsize.cy); + } + + try { + *ppSubPic = DEBUG_NEW CDX9SubPic(pSurface, fStatic ? nullptr : this, m_bExternalRenderer); + } catch (CMemoryException* e) { + e->Delete(); + TRACE(_T("CDX9SubPicAllocator::Alloc -> CDX9SubPic gave memory exception\n")); + return false; + } + + (*ppSubPic)->AddRef(); + (*ppSubPic)->SetInverseAlpha(m_bInvAlpha); + + if (!fStatic) { + CAutoLock cAutoLock2(&ms_surfaceQueueLock); + m_allocatedSurfaces.AddHead((CDX9SubPic*)*ppSubPic); + } + + return true; +} diff --git a/src/SubPic/DX9SubPic.h b/src/SubPic/DX9SubPic.h index ff4e76bd089..7d871f1308b 100644 --- a/src/SubPic/DX9SubPic.h +++ b/src/SubPic/DX9SubPic.h @@ -1,78 +1,78 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "SubPicImpl.h" -#include "SubPicAllocatorPresenterImpl.h" -#include - -// CDX9SubPic - - -class CDX9SubPicAllocator; -class CDX9SubPic : public CSubPicImpl -{ - CComPtr m_pSurface; - -protected: - STDMETHODIMP_(void*) GetObject(); // returns IDirect3DTexture9* - -public: - CDX9SubPicAllocator* m_pAllocator; - bool m_bExternalRenderer; - CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator* pAllocator, bool bExternalRenderer); - ~CDX9SubPic(); - - // ISubPic - STDMETHODIMP GetDesc(SubPicDesc& spd); - STDMETHODIMP CopyTo(ISubPic* pSubPic); - STDMETHODIMP ClearDirtyRect(); - STDMETHODIMP Lock(SubPicDesc& spd); - STDMETHODIMP Unlock(RECT* pDirtyRect); - STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget); -}; - -// CDX9SubPicAllocator - -class CDX9SubPicAllocator : public CSubPicAllocatorImpl, public CCritSec -{ - CComPtr m_pD3DDev; - CSize m_maxsize; - bool m_bExternalRenderer; - - bool Alloc(bool fStatic, ISubPic** ppSubPic); - -public: - static CCritSec ms_surfaceQueueLock; - CAtlList> m_freeSurfaces; - CAtlList m_allocatedSurfaces; - - void GetStats(int& nFree, int& nAlloc) const; - - CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool bExternalRenderer); - ~CDX9SubPicAllocator(); - void ClearCache(); - - // ISubPicAllocator - STDMETHODIMP ChangeDevice(IUnknown* pDev); - STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "SubPicImpl.h" +#include "SubPicAllocatorPresenterImpl.h" +#include + +// CDX9SubPic + + +class CDX9SubPicAllocator; +class CDX9SubPic : public CSubPicImpl +{ + CComPtr m_pSurface; + +protected: + STDMETHODIMP_(void*) GetObject(); // returns IDirect3DTexture9* + +public: + CDX9SubPicAllocator* m_pAllocator; + bool m_bExternalRenderer; + CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator* pAllocator, bool bExternalRenderer); + ~CDX9SubPic(); + + // ISubPic + STDMETHODIMP GetDesc(SubPicDesc& spd); + STDMETHODIMP CopyTo(ISubPic* pSubPic); + STDMETHODIMP ClearDirtyRect(); + STDMETHODIMP Lock(SubPicDesc& spd); + STDMETHODIMP Unlock(RECT* pDirtyRect); + STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget); +}; + +// CDX9SubPicAllocator + +class CDX9SubPicAllocator : public CSubPicAllocatorImpl, public CCritSec +{ + CComPtr m_pD3DDev; + CSize m_maxsize; + bool m_bExternalRenderer; + + bool Alloc(bool fStatic, ISubPic** ppSubPic); + +public: + static CCritSec ms_surfaceQueueLock; + CAtlList> m_freeSurfaces; + CAtlList m_allocatedSurfaces; + + void GetStats(int& nFree, int& nAlloc) const; + + CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool bExternalRenderer); + ~CDX9SubPicAllocator(); + void ClearCache(); + + // ISubPicAllocator + STDMETHODIMP ChangeDevice(IUnknown* pDev); + STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize); +}; diff --git a/src/SubPic/ISubPic.h b/src/SubPic/ISubPic.h index e78f689a94b..189662a7d10 100644 --- a/src/SubPic/ISubPic.h +++ b/src/SubPic/ISubPic.h @@ -1,262 +1,262 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#pragma once - -#include -#include -#include "CoordGeom.h" -#include "strmif.h" - -// to force rendering subs at a specific size -#define DEBUG_OVERRIDE_TEXTURE_SIZE 0 -#define DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH 2560 -#define DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT 1440 - -#pragma pack(push, 1) -struct SubPicDesc { - int type; - int w, h, bpp, pitch, pitchUV; - BYTE* bits; - BYTE* bitsU; - BYTE* bitsV; - RECT vidrect; // video rectangle - - SubPicDesc() - : type(0) - , w(0) - , h(0) - , bpp(0) - , pitch(0) - , pitchUV(0) - , bits(nullptr) - , bitsU(nullptr) - , bitsV(nullptr) { - ZeroMemory(&vidrect, sizeof(vidrect)); - } -}; -#pragma pack(pop) - -enum RelativeTo { - WINDOW, - VIDEO, - BEST_FIT -}; - -// -// ISubPic -// - -interface __declspec(uuid("DA3A5B51-958C-4C28-BF66-68D7947577A2")) -ISubPic : -public IUnknown { - static const REFERENCE_TIME INVALID_SUBPIC_TIME = -1; - - STDMETHOD_(void*, GetObject)() PURE; - - STDMETHOD_(REFERENCE_TIME, GetStart)() const PURE; - STDMETHOD_(REFERENCE_TIME, GetStop)() const PURE; - STDMETHOD_(void, SetStart)(REFERENCE_TIME rtStart) PURE; - STDMETHOD_(void, SetStop)(REFERENCE_TIME rtStop) PURE; - - STDMETHOD(GetDesc)(SubPicDesc& spd /*[out]*/) PURE; - STDMETHOD(CopyTo)(ISubPic* pSubPic /*[in]*/) PURE; - - STDMETHOD(ClearDirtyRect)() PURE; - STDMETHOD(GetDirtyRect)(RECT* pDirtyRect /*[out]*/) const PURE; - STDMETHOD(SetDirtyRect)(const RECT* pDirtyRect /*[in]*/) PURE; - - STDMETHOD(GetMaxSize)(SIZE* pMaxSize /*[out]*/) const PURE; - STDMETHOD(SetSize)(SIZE pSize /*[in]*/, RECT vidrect /*[in]*/) PURE; - - STDMETHOD(Lock)(SubPicDesc& spd /*[out]*/) PURE; - STDMETHOD(Unlock)(RECT* pDirtyRect /*[in]*/) PURE; - - STDMETHOD(AlphaBlt)(RECT * pSrc, RECT * pDst, SubPicDesc* pTarget = nullptr /*[in]*/) PURE; - STDMETHOD(GetSourceAndDest)(RECT rcWindow /*[in]*/, RECT rcVideo /*[in]*/, - RECT* pRcSource /*[out]*/, RECT* pRcDest /*[out]*/, - const double videoStretchFactor = 1.0 /*[in]*/, - int xOffsetInPixels = 0 /*[in]*/, int yOffsetInPixels = 0 /*[in]*/) const PURE; - STDMETHOD(SetVirtualTextureSize)(const SIZE pSize, const POINT pTopLeft) PURE; - STDMETHOD(GetRelativeTo)(RelativeTo* pRelativeTo /*[out]*/) const PURE; - STDMETHOD(SetRelativeTo)(RelativeTo relativeTo /*[in]*/) PURE; - - STDMETHOD_(REFERENCE_TIME, GetSegmentStart)() const PURE; - STDMETHOD_(REFERENCE_TIME, GetSegmentStop)() const PURE; - STDMETHOD_(void, SetSegmentStart)(REFERENCE_TIME rtStart) PURE; - STDMETHOD_(void, SetSegmentStop)(REFERENCE_TIME rtStop) PURE; - - STDMETHOD_(void, SetInverseAlpha)(bool bInverted) PURE; -}; - -// -// ISubPicAllocator -// - -interface __declspec(uuid("CF7C3C23-6392-4a42-9E72-0736CFF793CB")) -ISubPicAllocator : -public IUnknown { - STDMETHOD(SetCurSize)(SIZE size /*[in]*/) PURE; - STDMETHOD(SetCurVidRect)(RECT curvidrect) PURE; - - STDMETHOD(GetStatic)(ISubPic** ppSubPic /*[out]*/) PURE; - STDMETHOD(AllocDynamic)(ISubPic** ppSubPic /*[out]*/) PURE; - - STDMETHOD_(bool, IsDynamicWriteOnly)() const PURE; - - STDMETHOD(ChangeDevice)(IUnknown * pDev) PURE; - STDMETHOD(SetMaxTextureSize)(SIZE maxTextureSize) PURE; - - STDMETHOD(FreeStatic)() PURE; - - STDMETHOD_(void, SetInverseAlpha)(bool bInverted) PURE; -}; - -// -// ISubPicProvider -// - -interface __declspec(uuid("D62B9A1A-879A-42db-AB04-88AA8F243CFD")) -ISubPicProvider : -public IUnknown { - static const REFERENCE_TIME UNKNOWN_TIME = _I64_MAX; - - STDMETHOD(Lock)() PURE; - STDMETHOD(Unlock)() PURE; - - STDMETHOD_(POSITION, GetStartPosition)(REFERENCE_TIME rt, double fps) PURE; - STDMETHOD_(POSITION, GetNext)(POSITION pos) PURE; - - STDMETHOD_(REFERENCE_TIME, GetStart)(POSITION pos, double fps) PURE; - STDMETHOD_(REFERENCE_TIME, GetStop)(POSITION pos, double fps) PURE; - - STDMETHOD_(bool, IsAnimated)(POSITION pos) PURE; - - STDMETHOD(Render)(SubPicDesc & spd, REFERENCE_TIME rt, double fps, RECT & bbox) PURE; - STDMETHOD(GetTextureSize)(POSITION pos, SIZE & MaxTextureSize, SIZE & VirtualSize, POINT & VirtualTopLeft) PURE; - STDMETHOD(GetRelativeTo)(POSITION pos, RelativeTo & relativeTo) PURE; -}; - -// -// ISubPicQueue -// - -interface __declspec(uuid("C8334466-CD1E-4ad1-9D2D-8EE8519BD180")) -ISubPicQueue : -public IUnknown { - STDMETHOD(SetSubPicProvider)(ISubPicProvider* pSubPicProvider /*[in]*/) PURE; - STDMETHOD(GetSubPicProvider)(ISubPicProvider** pSubPicProvider /*[out]*/) PURE; - - STDMETHOD(SetFPS)(double fps /*[in]*/) PURE; - STDMETHOD(SetTime)(REFERENCE_TIME rtNow /*[in]*/) PURE; - - STDMETHOD(Invalidate)(REFERENCE_TIME rtInvalidate = -1) PURE; - STDMETHOD_(bool, LookupSubPic)(REFERENCE_TIME rtNow /*[in]*/, CComPtr& pSubPic /*[out]*/) PURE; - - STDMETHOD(GetStats)(int& nSubPics, REFERENCE_TIME & rtNow, REFERENCE_TIME & rtStart, REFERENCE_TIME& rtStop /*[out]*/) PURE; - STDMETHOD(GetStats)(int nSubPic /*[in]*/, REFERENCE_TIME & rtStart, REFERENCE_TIME& rtStop /*[out]*/) PURE; - - STDMETHOD_(bool, LookupSubPic)(REFERENCE_TIME rtNow /*[in]*/, bool bAdviseBlocking, CComPtr& pSubPic /*[out]*/) PURE; -}; - -// -// ISubPicAllocatorPresenter -// -#define TARGET_FRAME 0 -#define TARGET_SCREEN 1 - -interface __declspec(uuid("CF75B1F0-535C-4074-8869-B15F177F944E")) -ISubPicAllocatorPresenter : -public IUnknown { - STDMETHOD(CreateRenderer)(IUnknown** ppRenderer) PURE; - - STDMETHOD_(SIZE, GetVideoSize)(bool bCorrectAR) const PURE; - STDMETHOD_(void, SetPosition)(RECT w, RECT v) PURE; - STDMETHOD_(bool, Paint)(bool bAll) PURE; - - STDMETHOD_(void, SetTime)(REFERENCE_TIME rtNow) PURE; - STDMETHOD_(void, SetSubtitleDelay)(int delayMs) PURE; - STDMETHOD_(int, GetSubtitleDelay)() const PURE; - STDMETHOD_(double, GetFPS)() const PURE; - - STDMETHOD_(void, SetSubPicProvider)(ISubPicProvider * pSubPicProvider) PURE; - STDMETHOD_(void, Invalidate)(REFERENCE_TIME rtInvalidate = -1) PURE; - - STDMETHOD(GetDIB)(BYTE * lpDib, DWORD * size) PURE; - STDMETHOD (GetDisplayedImage) (LPVOID* dibImage) PURE; - - STDMETHOD(SetVideoAngle)(Vector v) PURE; - STDMETHOD(SetPixelShader)(LPCSTR pSrcData, LPCSTR pTarget) PURE; - - STDMETHOD_(bool, ResetDevice)() PURE; - STDMETHOD_(bool, DisplayChange)() PURE; - - STDMETHOD_(void, GetPosition)(RECT* windowRect, RECT* videoRect) PURE; - - STDMETHOD_(void, SetVideoMediaType)(CMediaType input) PURE; -}; - -interface __declspec(uuid("767AEBA8-A084-488a-89C8-F6B74E53A90F")) -ISubPicAllocatorPresenter2 : -public ISubPicAllocatorPresenter { - STDMETHOD(SetPixelShader2)(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) PURE; - STDMETHOD_(SIZE, GetVisibleVideoSize)() const PURE; - - STDMETHOD_(bool, IsRendering)() PURE; - STDMETHOD(SetIsRendering)(bool bIsRendering) PURE; - - STDMETHOD(SetDefaultVideoAngle)(Vector v) PURE; -}; - - -interface __declspec(uuid("AD863F43-83F9-4B8E-962C-426F2BDBEAEF")) -ISubPicAllocatorPresenter3 : -public ISubPicAllocatorPresenter2 { - STDMETHOD (SetRotation) (int rotation) PURE; - STDMETHOD_(int, GetRotation) () PURE; - STDMETHOD (SetFlip) (bool flip) PURE; - STDMETHOD_(bool, GetFlip) () PURE; - STDMETHOD (GetVideoFrame) (BYTE* lpDib, DWORD* size) PURE; - STDMETHOD_(int, GetPixelShaderMode) () PURE; - STDMETHOD (ClearPixelShaders) (int target) PURE; - STDMETHOD (AddPixelShader) (int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) PURE; - STDMETHOD_(bool, ResizeDevice) () PURE; - STDMETHOD_(bool, ToggleStats) () PURE; -}; - -// -// ISubStream -// - -interface __declspec(uuid("DE11E2FB-02D3-45e4-A174-6B7CE2783BDB")) -ISubStream : -public IPersist { - STDMETHOD_(int, GetStreamCount)() PURE; - STDMETHOD(GetStreamInfo)(int i, WCHAR** ppName, LCID * pLCID) PURE; - STDMETHOD_(int, GetStream)() PURE; - STDMETHOD(SetStream)(int iStream) PURE; - STDMETHOD(Reload)() PURE; - STDMETHOD(SetSourceTargetInfo)(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) PURE; - virtual CString GetPath() { return _T(""); } - - // TODO: get rid of IPersist to identify type and use only - // interface functions to modify the settings of the substream -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#pragma once + +#include +#include +#include "CoordGeom.h" +#include "strmif.h" + +// to force rendering subs at a specific size +#define DEBUG_OVERRIDE_TEXTURE_SIZE 0 +#define DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH 2560 +#define DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT 1440 + +#pragma pack(push, 1) +struct SubPicDesc { + int type; + int w, h, bpp, pitch, pitchUV; + BYTE* bits; + BYTE* bitsU; + BYTE* bitsV; + RECT vidrect; // video rectangle + + SubPicDesc() + : type(0) + , w(0) + , h(0) + , bpp(0) + , pitch(0) + , pitchUV(0) + , bits(nullptr) + , bitsU(nullptr) + , bitsV(nullptr) { + ZeroMemory(&vidrect, sizeof(vidrect)); + } +}; +#pragma pack(pop) + +enum RelativeTo { + WINDOW, + VIDEO, + BEST_FIT +}; + +// +// ISubPic +// + +interface __declspec(uuid("DA3A5B51-958C-4C28-BF66-68D7947577A2")) +ISubPic : +public IUnknown { + static const REFERENCE_TIME INVALID_SUBPIC_TIME = -1; + + STDMETHOD_(void*, GetObject)() PURE; + + STDMETHOD_(REFERENCE_TIME, GetStart)() const PURE; + STDMETHOD_(REFERENCE_TIME, GetStop)() const PURE; + STDMETHOD_(void, SetStart)(REFERENCE_TIME rtStart) PURE; + STDMETHOD_(void, SetStop)(REFERENCE_TIME rtStop) PURE; + + STDMETHOD(GetDesc)(SubPicDesc& spd /*[out]*/) PURE; + STDMETHOD(CopyTo)(ISubPic* pSubPic /*[in]*/) PURE; + + STDMETHOD(ClearDirtyRect)() PURE; + STDMETHOD(GetDirtyRect)(RECT* pDirtyRect /*[out]*/) const PURE; + STDMETHOD(SetDirtyRect)(const RECT* pDirtyRect /*[in]*/) PURE; + + STDMETHOD(GetMaxSize)(SIZE* pMaxSize /*[out]*/) const PURE; + STDMETHOD(SetSize)(SIZE pSize /*[in]*/, RECT vidrect /*[in]*/) PURE; + + STDMETHOD(Lock)(SubPicDesc& spd /*[out]*/) PURE; + STDMETHOD(Unlock)(RECT* pDirtyRect /*[in]*/) PURE; + + STDMETHOD(AlphaBlt)(RECT * pSrc, RECT * pDst, SubPicDesc* pTarget = nullptr /*[in]*/) PURE; + STDMETHOD(GetSourceAndDest)(RECT rcWindow /*[in]*/, RECT rcVideo /*[in]*/, + RECT* pRcSource /*[out]*/, RECT* pRcDest /*[out]*/, + const double videoStretchFactor = 1.0 /*[in]*/, + int xOffsetInPixels = 0 /*[in]*/, int yOffsetInPixels = 0 /*[in]*/) const PURE; + STDMETHOD(SetVirtualTextureSize)(const SIZE pSize, const POINT pTopLeft) PURE; + STDMETHOD(GetRelativeTo)(RelativeTo* pRelativeTo /*[out]*/) const PURE; + STDMETHOD(SetRelativeTo)(RelativeTo relativeTo /*[in]*/) PURE; + + STDMETHOD_(REFERENCE_TIME, GetSegmentStart)() const PURE; + STDMETHOD_(REFERENCE_TIME, GetSegmentStop)() const PURE; + STDMETHOD_(void, SetSegmentStart)(REFERENCE_TIME rtStart) PURE; + STDMETHOD_(void, SetSegmentStop)(REFERENCE_TIME rtStop) PURE; + + STDMETHOD_(void, SetInverseAlpha)(bool bInverted) PURE; +}; + +// +// ISubPicAllocator +// + +interface __declspec(uuid("CF7C3C23-6392-4a42-9E72-0736CFF793CB")) +ISubPicAllocator : +public IUnknown { + STDMETHOD(SetCurSize)(SIZE size /*[in]*/) PURE; + STDMETHOD(SetCurVidRect)(RECT curvidrect) PURE; + + STDMETHOD(GetStatic)(ISubPic** ppSubPic /*[out]*/) PURE; + STDMETHOD(AllocDynamic)(ISubPic** ppSubPic /*[out]*/) PURE; + + STDMETHOD_(bool, IsDynamicWriteOnly)() const PURE; + + STDMETHOD(ChangeDevice)(IUnknown * pDev) PURE; + STDMETHOD(SetMaxTextureSize)(SIZE maxTextureSize) PURE; + + STDMETHOD(FreeStatic)() PURE; + + STDMETHOD_(void, SetInverseAlpha)(bool bInverted) PURE; +}; + +// +// ISubPicProvider +// + +interface __declspec(uuid("D62B9A1A-879A-42db-AB04-88AA8F243CFD")) +ISubPicProvider : +public IUnknown { + static const REFERENCE_TIME UNKNOWN_TIME = _I64_MAX; + + STDMETHOD(Lock)() PURE; + STDMETHOD(Unlock)() PURE; + + STDMETHOD_(POSITION, GetStartPosition)(REFERENCE_TIME rt, double fps) PURE; + STDMETHOD_(POSITION, GetNext)(POSITION pos) PURE; + + STDMETHOD_(REFERENCE_TIME, GetStart)(POSITION pos, double fps) PURE; + STDMETHOD_(REFERENCE_TIME, GetStop)(POSITION pos, double fps) PURE; + + STDMETHOD_(bool, IsAnimated)(POSITION pos) PURE; + + STDMETHOD(Render)(SubPicDesc & spd, REFERENCE_TIME rt, double fps, RECT & bbox) PURE; + STDMETHOD(GetTextureSize)(POSITION pos, SIZE & MaxTextureSize, SIZE & VirtualSize, POINT & VirtualTopLeft) PURE; + STDMETHOD(GetRelativeTo)(POSITION pos, RelativeTo & relativeTo) PURE; +}; + +// +// ISubPicQueue +// + +interface __declspec(uuid("C8334466-CD1E-4ad1-9D2D-8EE8519BD180")) +ISubPicQueue : +public IUnknown { + STDMETHOD(SetSubPicProvider)(ISubPicProvider* pSubPicProvider /*[in]*/) PURE; + STDMETHOD(GetSubPicProvider)(ISubPicProvider** pSubPicProvider /*[out]*/) PURE; + + STDMETHOD(SetFPS)(double fps /*[in]*/) PURE; + STDMETHOD(SetTime)(REFERENCE_TIME rtNow /*[in]*/) PURE; + + STDMETHOD(Invalidate)(REFERENCE_TIME rtInvalidate = -1) PURE; + STDMETHOD_(bool, LookupSubPic)(REFERENCE_TIME rtNow /*[in]*/, CComPtr& pSubPic /*[out]*/) PURE; + + STDMETHOD(GetStats)(int& nSubPics, REFERENCE_TIME & rtNow, REFERENCE_TIME & rtStart, REFERENCE_TIME& rtStop /*[out]*/) PURE; + STDMETHOD(GetStats)(int nSubPic /*[in]*/, REFERENCE_TIME & rtStart, REFERENCE_TIME& rtStop /*[out]*/) PURE; + + STDMETHOD_(bool, LookupSubPic)(REFERENCE_TIME rtNow /*[in]*/, bool bAdviseBlocking, CComPtr& pSubPic /*[out]*/) PURE; +}; + +// +// ISubPicAllocatorPresenter +// +#define TARGET_FRAME 0 +#define TARGET_SCREEN 1 + +interface __declspec(uuid("CF75B1F0-535C-4074-8869-B15F177F944E")) +ISubPicAllocatorPresenter : +public IUnknown { + STDMETHOD(CreateRenderer)(IUnknown** ppRenderer) PURE; + + STDMETHOD_(SIZE, GetVideoSize)(bool bCorrectAR) const PURE; + STDMETHOD_(void, SetPosition)(RECT w, RECT v) PURE; + STDMETHOD_(bool, Paint)(bool bAll) PURE; + + STDMETHOD_(void, SetTime)(REFERENCE_TIME rtNow) PURE; + STDMETHOD_(void, SetSubtitleDelay)(int delayMs) PURE; + STDMETHOD_(int, GetSubtitleDelay)() const PURE; + STDMETHOD_(double, GetFPS)() const PURE; + + STDMETHOD_(void, SetSubPicProvider)(ISubPicProvider * pSubPicProvider) PURE; + STDMETHOD_(void, Invalidate)(REFERENCE_TIME rtInvalidate = -1) PURE; + + STDMETHOD(GetDIB)(BYTE * lpDib, DWORD * size) PURE; + STDMETHOD (GetDisplayedImage) (LPVOID* dibImage) PURE; + + STDMETHOD(SetVideoAngle)(Vector v) PURE; + STDMETHOD(SetPixelShader)(LPCSTR pSrcData, LPCSTR pTarget) PURE; + + STDMETHOD_(bool, ResetDevice)() PURE; + STDMETHOD_(bool, DisplayChange)() PURE; + + STDMETHOD_(void, GetPosition)(RECT* windowRect, RECT* videoRect) PURE; + + STDMETHOD_(void, SetVideoMediaType)(CMediaType input) PURE; +}; + +interface __declspec(uuid("767AEBA8-A084-488a-89C8-F6B74E53A90F")) +ISubPicAllocatorPresenter2 : +public ISubPicAllocatorPresenter { + STDMETHOD(SetPixelShader2)(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) PURE; + STDMETHOD_(SIZE, GetVisibleVideoSize)() const PURE; + + STDMETHOD_(bool, IsRendering)() PURE; + STDMETHOD(SetIsRendering)(bool bIsRendering) PURE; + + STDMETHOD(SetDefaultVideoAngle)(Vector v) PURE; +}; + + +interface __declspec(uuid("AD863F43-83F9-4B8E-962C-426F2BDBEAEF")) +ISubPicAllocatorPresenter3 : +public ISubPicAllocatorPresenter2 { + STDMETHOD (SetRotation) (int rotation) PURE; + STDMETHOD_(int, GetRotation) () PURE; + STDMETHOD (SetFlip) (bool flip) PURE; + STDMETHOD_(bool, GetFlip) () PURE; + STDMETHOD (GetVideoFrame) (BYTE* lpDib, DWORD* size) PURE; + STDMETHOD_(int, GetPixelShaderMode) () PURE; + STDMETHOD (ClearPixelShaders) (int target) PURE; + STDMETHOD (AddPixelShader) (int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) PURE; + STDMETHOD_(bool, ResizeDevice) () PURE; + STDMETHOD_(bool, ToggleStats) () PURE; +}; + +// +// ISubStream +// + +interface __declspec(uuid("DE11E2FB-02D3-45e4-A174-6B7CE2783BDB")) +ISubStream : +public IPersist { + STDMETHOD_(int, GetStreamCount)() PURE; + STDMETHOD(GetStreamInfo)(int i, WCHAR** ppName, LCID * pLCID) PURE; + STDMETHOD_(int, GetStream)() PURE; + STDMETHOD(SetStream)(int iStream) PURE; + STDMETHOD(Reload)() PURE; + STDMETHOD(SetSourceTargetInfo)(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) PURE; + virtual CString GetPath() { return _T(""); } + + // TODO: get rid of IPersist to identify type and use only + // interface functions to modify the settings of the substream +}; diff --git a/src/SubPic/ISubRender.h b/src/SubPic/ISubRender.h index 210a897eccf..f4cafc6c469 100644 --- a/src/SubPic/ISubRender.h +++ b/src/SubPic/ISubRender.h @@ -1,73 +1,73 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2022 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 . - * - */ - -#pragma once - -#include -#include - -interface IDirect3DDevice9; - -DECLARE_INTERFACE_IID_(ISubRenderCallback, IUnknown, "CD6D2AA5-20D3-4ebe-A8A9-34D3B00CC253") -{ - // NULL means release current device, textures and other resources - STDMETHOD(SetDevice)(IDirect3DDevice9* dev) PURE; - - // destination video rectangle, will be inside (0, 0)-(width, height) - // width,height is the size of the entire output window - STDMETHOD(Render)(REFERENCE_TIME rtStart, - int left, int top, int right, int bottom, - int width, int height) PURE; -}; - - -DECLARE_INTERFACE_IID_(ISubRenderCallback2, ISubRenderCallback, "E602585E-C05A-4828-AC69-AF92997F2E0C") -{ - STDMETHOD(RenderEx)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME avgTimePerFrame, - int left, int top, int right, int bottom, - int width, int height) PURE; -}; - -DECLARE_INTERFACE_IID_(ISubRenderCallback3, ISubRenderCallback2, "BAC4273A-3EAD-47F5-9710-8488E52AC618") -{ - STDMETHOD(RenderEx2)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME avgTimePerFrame, RECT croppedVideoRect, - RECT originalVideoRect, RECT viewportRect, - const double videoStretchFactor = 1.0) PURE; -}; - -// const static DWORD SUBRENDER_LEFT_EYE = 1; -// const static DWORD SUBRENDER_RIGHT_EYE = 2; - -DECLARE_INTERFACE_IID_(ISubRenderCallback4, ISubRenderCallback3, "C89CF1D4-29C5-4A96-8AAC-528EC6F7AF1E") -{ - STDMETHOD(RenderEx3)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME avgTimePerFrame, RECT croppedVideoRect, - RECT originalVideoRect, RECT viewportRect, - const double videoStretchFactor = 1.0, - int xOffsetInPixels = 0, DWORD flags = 0) PURE; -}; - -DECLARE_INTERFACE_IID_(ISubRender, IUnknown, "9CC7F9F7-3ED1-493c-AF65-527EA1D9947F") -{ - STDMETHOD(SetCallback)(ISubRenderCallback* cb) PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2022 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 . + * + */ + +#pragma once + +#include +#include + +interface IDirect3DDevice9; + +DECLARE_INTERFACE_IID_(ISubRenderCallback, IUnknown, "CD6D2AA5-20D3-4ebe-A8A9-34D3B00CC253") +{ + // NULL means release current device, textures and other resources + STDMETHOD(SetDevice)(IDirect3DDevice9* dev) PURE; + + // destination video rectangle, will be inside (0, 0)-(width, height) + // width,height is the size of the entire output window + STDMETHOD(Render)(REFERENCE_TIME rtStart, + int left, int top, int right, int bottom, + int width, int height) PURE; +}; + + +DECLARE_INTERFACE_IID_(ISubRenderCallback2, ISubRenderCallback, "E602585E-C05A-4828-AC69-AF92997F2E0C") +{ + STDMETHOD(RenderEx)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME avgTimePerFrame, + int left, int top, int right, int bottom, + int width, int height) PURE; +}; + +DECLARE_INTERFACE_IID_(ISubRenderCallback3, ISubRenderCallback2, "BAC4273A-3EAD-47F5-9710-8488E52AC618") +{ + STDMETHOD(RenderEx2)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME avgTimePerFrame, RECT croppedVideoRect, + RECT originalVideoRect, RECT viewportRect, + const double videoStretchFactor = 1.0) PURE; +}; + +// const static DWORD SUBRENDER_LEFT_EYE = 1; +// const static DWORD SUBRENDER_RIGHT_EYE = 2; + +DECLARE_INTERFACE_IID_(ISubRenderCallback4, ISubRenderCallback3, "C89CF1D4-29C5-4A96-8AAC-528EC6F7AF1E") +{ + STDMETHOD(RenderEx3)(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME avgTimePerFrame, RECT croppedVideoRect, + RECT originalVideoRect, RECT viewportRect, + const double videoStretchFactor = 1.0, + int xOffsetInPixels = 0, DWORD flags = 0) PURE; +}; + +DECLARE_INTERFACE_IID_(ISubRender, IUnknown, "9CC7F9F7-3ED1-493c-AF65-527EA1D9947F") +{ + STDMETHOD(SetCallback)(ISubRenderCallback* cb) PURE; +}; diff --git a/src/SubPic/MemSubPic.cpp b/src/SubPic/MemSubPic.cpp index e54266b4ee0..43042223fd8 100644 --- a/src/SubPic/MemSubPic.cpp +++ b/src/SubPic/MemSubPic.cpp @@ -1,781 +1,781 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include "MemSubPic.h" - -#include -#include "stb/stb_image.h" -#include "stb/stb_image_resize2.h" - -// color conv - -static unsigned char clipBase[256 * 3]; -static unsigned char* clip = clipBase + 256; - -static const int c2y_cyb = std::lround(0.114 * 219 / 255 * 65536); -static const int c2y_cyg = std::lround(0.587 * 219 / 255 * 65536); -static const int c2y_cyr = std::lround(0.299 * 219 / 255 * 65536); -static const int c2y_cu = std::lround(1.0 / 2.018 * 1024); -static const int c2y_cv = std::lround(1.0 / 1.596 * 1024); - -int c2y_yb[256]; -int c2y_yg[256]; -int c2y_yr[256]; - -static const int y2c_cbu = std::lround(2.018 * 65536); -static const int y2c_cgu = std::lround(0.391 * 65536); -static const int y2c_cgv = std::lround(0.813 * 65536); -static const int y2c_crv = std::lround(1.596 * 65536); -static int y2c_bu[256]; -static int y2c_gu[256]; -static int y2c_gv[256]; -static int y2c_rv[256]; - -static const int cy_cy = std::lround(255.0 / 219.0 * 65536); -static const int cy_cy2 = std::lround(255.0 / 219.0 * 32768); - -void ColorConvInit() -{ - static bool bColorConvInitOK = false; - if (bColorConvInitOK) { - return; - } - - for (int i = 0; i < 256; i++) { - clipBase[i] = 0; - clipBase[i + 256] = BYTE(i); - clipBase[i + 512] = 255; - } - - for (int i = 0; i < 256; i++) { - c2y_yb[i] = c2y_cyb * i; - c2y_yg[i] = c2y_cyg * i; - c2y_yr[i] = c2y_cyr * i; - - y2c_bu[i] = y2c_cbu * (i - 128); - y2c_gu[i] = y2c_cgu * (i - 128); - y2c_gv[i] = y2c_cgv * (i - 128); - y2c_rv[i] = y2c_crv * (i - 128); - } - - bColorConvInitOK = true; -} - -// -// CMemSubPic -// - -CMemSubPic::CMemSubPic(const SubPicDesc& spd, CMemSubPicAllocator* pAllocator) - : m_pAllocator(pAllocator) - , m_spd(spd) -{ - m_maxsize.SetSize(spd.w, spd.h); - m_rcDirty.SetRect(0, 0, spd.w, spd.h); -} - -CMemSubPic::~CMemSubPic() -{ - m_pAllocator->FreeSpdBits(m_spd); - if (m_resizedSpd) { - m_pAllocator->FreeSpdBits(*m_resizedSpd); - } -} - -// ISubPic - -STDMETHODIMP_(void*) CMemSubPic::GetObject() -{ - return (void*)&m_spd; -} - -STDMETHODIMP CMemSubPic::GetDesc(SubPicDesc& spd) -{ - spd.type = m_spd.type; - spd.w = m_spd.w; - spd.h = m_spd.h; - spd.bpp = m_spd.bpp; - spd.pitch = m_spd.pitch; - spd.bits = m_spd.bits; - spd.bitsU = m_spd.bitsU; - spd.bitsV = m_spd.bitsV; - spd.vidrect = m_vidrect; - - return S_OK; -} - -STDMETHODIMP CMemSubPic::CopyTo(ISubPic* pSubPic) -{ - HRESULT hr; - if (FAILED(hr = __super::CopyTo(pSubPic))) { - return hr; - } - - SubPicDesc src, dst; - if (FAILED(GetDesc(src)) || FAILED(pSubPic->GetDesc(dst))) { - return E_FAIL; - } - - if (auto subPic = dynamic_cast(pSubPic)) { - ASSERT(subPic->m_pAllocator == m_pAllocator); - ASSERT(subPic->m_resizedSpd == nullptr); - // Move because we are not going to reuse it. - subPic->m_resizedSpd = std::move(m_resizedSpd); - } - - int w = m_rcDirty.Width(), h = m_rcDirty.Height(); - BYTE* s = src.bits + src.pitch * m_rcDirty.top + m_rcDirty.left * 4; - BYTE* d = dst.bits + dst.pitch * m_rcDirty.top + m_rcDirty.left * 4; - - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - memcpy(d, s, w * 4); - } - - return S_OK; -} - -STDMETHODIMP CMemSubPic::ClearDirtyRect() -{ - if (m_rcDirty.IsRectEmpty()) { - return S_FALSE; - } - - DWORD color = m_bInvAlpha ? 0x00000000 : 0xFF000000; - - BYTE* p = m_spd.bits + m_spd.pitch * m_rcDirty.top + m_rcDirty.left * (m_spd.bpp >> 3); - for (ptrdiff_t j = 0, h = m_rcDirty.Height(); j < h; j++, p += m_spd.pitch) { - int w = m_rcDirty.Width(); -#ifdef _WIN64 - memsetd(p, color, w * 4); // nya -#else - __asm { - mov eax, color - mov ecx, w - mov edi, p - cld - rep stosd - } -#endif - } - - m_rcDirty.SetRectEmpty(); - - return S_OK; -} - -STDMETHODIMP CMemSubPic::Lock(SubPicDesc& spd) -{ - return GetDesc(spd); -} - -HRESULT CMemSubPic::UnlockARGB() { //derived from Unlock(), supports ARGB - m_rcDirty = CRect(0, 0, m_spd.w, m_spd.h); - - if (m_rcDirty.IsRectEmpty()) { - return S_OK; - } - - if (m_spd.bpp != 32 || m_spd.type != MSP_RGB32) { - return E_INVALIDARG; - } - - CRect r = m_spd.vidrect; - CRect rcDirty = m_rcDirty; - if (m_spd.h != r.Height() || m_spd.w != r.Width()) { - if (!m_resizedSpd) { - m_resizedSpd = std::unique_ptr(DEBUG_NEW SubPicDesc); - } - - m_resizedSpd->type = m_spd.type; - m_resizedSpd->w = r.Width(); - m_resizedSpd->h = r.Height(); - m_resizedSpd->pitch = r.Width() * 4; - m_resizedSpd->bpp = m_spd.bpp; - m_resizedSpd->vidrect = { 0,0,r.Width(),r.Height() }; - - if (!m_resizedSpd->bits) { - m_pAllocator->AllocSpdBits(*m_resizedSpd); - } - - auto& s = m_spd; - auto& d = *m_resizedSpd; - stbir_resize(s.bits, s.w, s.h, s.pitch, d.bits, d.w, d.h, d.pitch, STBIR_RGBA_PM, STBIR_TYPE_UINT8_SRGB, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT); - TRACE("CMemSubPic: Resized SubPic %dx%d -> %dx%d\n", m_spd.w, m_spd.h, r.Width(), r.Height()); - - // Set whole resized spd as dirty, we are not going to reuse it. - rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); - } - else if (m_resizedSpd) { - // Resize is not needed so release m_resizedSpd. - m_pAllocator->FreeSpdBits(*m_resizedSpd); - m_resizedSpd = nullptr; - } - - if (!m_resizedSpd) { - m_rcDirty = rcDirty; - } - - return S_OK; -} - - -STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) -{ - m_rcDirty = pDirtyRect ? *pDirtyRect : CRect(0, 0, m_spd.w, m_spd.h); - - if (m_rcDirty.IsRectEmpty()) { - return S_OK; - } - - CRect r = m_spd.vidrect; - CRect rcDirty = m_rcDirty; - if (m_spd.h != r.Height() || m_spd.w != r.Width()) { - if (!m_resizedSpd) { - m_resizedSpd = std::unique_ptr(DEBUG_NEW SubPicDesc); - } - - m_resizedSpd->type = m_spd.type; - m_resizedSpd->w = r.Width(); - m_resizedSpd->h = r.Height(); - m_resizedSpd->pitch = r.Width() * 4; - m_resizedSpd->bpp = m_spd.bpp; - - if (!m_resizedSpd->bits) { - m_pAllocator->AllocSpdBits(*m_resizedSpd); - } - - BitBltFromRGBToRGBStretch(m_resizedSpd->w, m_resizedSpd->h, m_resizedSpd->bits, m_resizedSpd->pitch, m_resizedSpd->bpp - , m_spd.w, m_spd.h, m_spd.bits, m_spd.pitch, m_spd.bpp); - TRACE("CMemSubPic: Resized SubPic %dx%d -> %dx%d\n", m_spd.w, m_spd.h, r.Width(), r.Height()); - - // Set whole resized spd as dirty, we are not going to reuse it. - rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); - } else if (m_resizedSpd) { - // Resize is not needed so release m_resizedSpd. - m_pAllocator->FreeSpdBits(*m_resizedSpd); - m_resizedSpd = nullptr; - } - - const SubPicDesc& subPic = m_resizedSpd ? *m_resizedSpd : m_spd; - - if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV || subPic.type == MSP_AYUV) { - ColorConvInit(); - - if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { - rcDirty.left &= ~1; - rcDirty.right = (rcDirty.right + 1) & ~1; - - if (subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { - rcDirty.top &= ~1; - rcDirty.bottom = (rcDirty.bottom + 1) & ~1; - } - } - } - - if (!m_resizedSpd) { - m_rcDirty = rcDirty; - } - - int w = rcDirty.Width(), h = rcDirty.Height(); - BYTE* top = subPic.bits + subPic.pitch * rcDirty.top + rcDirty.left * 4; - BYTE* bottom = top + subPic.pitch * h; - - if (subPic.type == MSP_RGB16) { - for (; top < bottom ; top += subPic.pitch) { - DWORD* s = (DWORD*)top; - DWORD* e = s + w; - for (; s < e; s++) { - *s = ((*s >> 3) & 0x1f000000) | ((*s >> 8) & 0xf800) | ((*s >> 5) & 0x07e0) | ((*s >> 3) & 0x001f); - //*s = (*s&0xff000000)|((*s>>8)&0xf800)|((*s>>5)&0x07e0)|((*s>>3)&0x001f); - } - } - } else if (subPic.type == MSP_RGB15) { - for (; top < bottom; top += subPic.pitch) { - DWORD* s = (DWORD*)top; - DWORD* e = s + w; - for (; s < e; s++) { - *s = ((*s >> 3) & 0x1f000000) | ((*s >> 9) & 0x7c00) | ((*s >> 6) & 0x03e0) | ((*s >> 3) & 0x001f); - //*s = (*s&0xff000000)|((*s>>9)&0x7c00)|((*s>>6)&0x03e0)|((*s>>3)&0x001f); - } - } - } else if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { - for (; top < bottom ; top += subPic.pitch) { - BYTE* s = top; - BYTE* e = s + w * 4; - for (; s < e; s += 8) { // ARGB ARGB -> AxYU AxYV - if ((s[3] + s[7]) < 0x1fe) { - s[1] = BYTE((c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16); - s[5] = BYTE((c2y_yb[s[4]] + c2y_yg[s[5]] + c2y_yr[s[6]] + 0x108000) >> 16); - - int scaled_y = (s[1] + s[5] - 32) * cy_cy2; - - s[0] = clip[(((((s[0] + s[4]) << 15) - scaled_y) >> 10) * c2y_cu + 0x800000 + 0x8000) >> 16]; - s[4] = clip[(((((s[2] + s[6]) << 15) - scaled_y) >> 10) * c2y_cv + 0x800000 + 0x8000) >> 16]; - } else { - s[1] = s[5] = 0x10; - s[0] = s[4] = 0x80; - } - } - } - } else if (subPic.type == MSP_AYUV) { - for (; top < bottom ; top += subPic.pitch) { - BYTE* s = top; - BYTE* e = s + w * 4; - - for (; s < e; s += 4) { // ARGB -> AYUV - if (s[3] < 0xff) { - auto y = BYTE((c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16); - int scaled_y = (y - 32) * cy_cy; - s[1] = clip[((((s[0] << 16) - scaled_y) >> 10) * c2y_cu + 0x800000 + 0x8000) >> 16]; - s[0] = clip[((((s[2] << 16) - scaled_y) >> 10) * c2y_cv + 0x800000 + 0x8000) >> 16]; - s[2] = y; - } else { - s[0] = s[1] = 0x80; - s[2] = 0x10; - } - } - } - } - - return S_OK; -} - -#ifdef _WIN64 -void AlphaBlt_YUY2_SSE2(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) -{ - unsigned int ia; - static const __int64 _8181 = 0x0080001000800010i64; - - for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { - DWORD* d2 = (DWORD*)d; - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - - for (; s2 < s2end; s2 += 8, d2++) { - ia = (s2[3] + s2[7]) >> 1; - if (ia < 0xff) { - unsigned int c = (s2[4] << 24) | (s2[5] << 16) | (s2[0] << 8) | s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; - - ia = (ia << 24) | (s2[7] << 16) | (ia << 8) | s2[3]; - // SSE2 - __m128i mm_zero = _mm_setzero_si128(); - __m128i mm_8181 = _mm_move_epi64(_mm_cvtsi64_si128(_8181)); - __m128i mm_c = _mm_cvtsi32_si128(c); - mm_c = _mm_unpacklo_epi8(mm_c, mm_zero); - __m128i mm_d = _mm_cvtsi32_si128(*d2); - mm_d = _mm_unpacklo_epi8(mm_d, mm_zero); - __m128i mm_a = _mm_cvtsi32_si128(ia); - mm_a = _mm_unpacklo_epi8(mm_a, mm_zero); - mm_a = _mm_srli_epi16(mm_a, 1); - mm_d = _mm_sub_epi16(mm_d, mm_8181); - mm_d = _mm_mullo_epi16(mm_d, mm_a); - mm_d = _mm_srai_epi16(mm_d, 7); - mm_d = _mm_adds_epi16(mm_d, mm_c); - mm_d = _mm_packus_epi16(mm_d, mm_d); - *d2 = (DWORD)_mm_cvtsi128_si32(mm_d); - } - } - } -} - -#else - -void AlphaBlt_YUY2_MMX(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) -{ - unsigned int ia; - static const __int64 _8181 = 0x0080001000800010i64; - - for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { - DWORD* d2 = (DWORD*)d; - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - - for (; s2 < s2end; s2 += 8, d2++) { - ia = (s2[3] + s2[7]) >> 1; - if (ia < 0xff) { - unsigned int c = (s2[4] << 24) | (s2[5] << 16) | (s2[0] << 8) | s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; - ia = (ia << 24) | (s2[7] << 16) | (ia << 8) | s2[3]; - __asm { - mov esi, s2 - mov edi, d2 - pxor mm0, mm0 - movq mm1, _8181 - movd mm2, c - punpcklbw mm2, mm0 - movd mm3, [edi] - punpcklbw mm3, mm0 - movd mm4, ia - punpcklbw mm4, mm0 - psrlw mm4, 1 - psubsw mm3, mm1 - pmullw mm3, mm4 - psraw mm3, 7 - paddsw mm3, mm2 - packuswb mm3, mm3 - movd [edi], mm3 - }; - } - } - } - _mm_empty(); -} -#endif - -void AlphaBlt_YUY2_C(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) -{ - unsigned int ia; - - for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { - DWORD* d2 = (DWORD*)d; - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - - for (; s2 < s2end; s2 += 8, d2++) { - ia = (s2[3] + s2[7]) >> 1; - if (ia < 0xff) { - //unsigned int c = (s2[4]<<24)|(s2[5]<<16)|(s2[0]<<8)|s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; - - // YUY2 colorspace fix. rewritten from sse2 asm - DWORD y1 = (DWORD)(((((*d2 & 0xff) - 0x10) * (s2[3] >> 1)) >> 7) + s2[1]) & 0xff; // y1 - DWORD uu = (DWORD)((((((*d2 >> 8) & 0xff) - 0x80) * (ia >> 1)) >> 7) + s2[0]) & 0xff; // u - DWORD y2 = (DWORD)((((((*d2 >> 16) & 0xff) - 0x10) * (s2[7] >> 1)) >> 7) + s2[5]) & 0xff; // y2 - DWORD vv = (DWORD)((((((*d2 >> 24) & 0xff) - 0x80) * (ia >> 1)) >> 7) + s2[4]) & 0xff; // v - *d2 = (y1) | (uu << 8) | (y2 << 16) | (vv << 24); - } - } - } -} - -STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) -{ - ASSERT(pTarget); - - if (!pSrc || !pDst || !pTarget) { - return E_POINTER; - } - - const SubPicDesc& src = m_resizedSpd ? *m_resizedSpd : m_spd; - SubPicDesc dst = *pTarget; // copy, because we might modify it - - if (src.type != dst.type) { - return E_INVALIDARG; - } - - CRect rs(*pSrc), rd(*pDst); - - if (m_resizedSpd) { - rs = rd = CRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); - } - - if (dst.h < 0) { - dst.h = -dst.h; - rd.bottom = dst.h - rd.bottom; - rd.top = dst.h - rd.top; - } - - if (rs.Width() != rd.Width() || rs.Height() != abs(rd.Height())) { - return E_INVALIDARG; - } - - int w = rs.Width(), h = rs.Height(); - BYTE* s = src.bits + src.pitch * rs.top + rs.left * 4; - BYTE* d = dst.bits + dst.pitch * rd.top + ((rd.left * dst.bpp) >> 3); - - if (rd.top > rd.bottom) { - if (dst.type == MSP_RGB32 || dst.type == MSP_RGB24 - || dst.type == MSP_RGB16 || dst.type == MSP_RGB15 - || dst.type == MSP_YUY2 || dst.type == MSP_AYUV) { - d = dst.bits + dst.pitch * (rd.top - 1) + (rd.left * dst.bpp >> 3); - } else if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) { - d = dst.bits + dst.pitch * (rd.top - 1) + (rd.left * 8 >> 3); - } else { - return E_NOTIMPL; - } - - dst.pitch = -dst.pitch; - } - - // TODO: m_bInvAlpha support - switch (dst.type) { - case MSP_RGBA: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - DWORD* d2 = (DWORD*)d; - for (; s2 < s2end; s2 += 4, d2++) { - if (s2[3] < 0xff) { - DWORD bd = 0x00000100 - ((DWORD) s2[3]); - DWORD B = ((*((DWORD*)s2) & 0x000000ff) << 8) / bd; - DWORD V = ((*((DWORD*)s2) & 0x0000ff00) / bd) << 8; - DWORD R = (((*((DWORD*)s2) & 0x00ff0000) >> 8) / bd) << 16; - *d2 = B | V | R - | (0xff000000 - (*((DWORD*)s2) & 0xff000000)) & 0xff000000; - } - } - } - break; - case MSP_RGB32: - case MSP_AYUV: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - DWORD* d2 = (DWORD*)d; - for (; s2 < s2end; s2 += 4, d2++) { -#ifdef _WIN64 - DWORD ia = 256 - s2[3]; - if (s2[3] < 0xff) { - *d2 = ((((*d2 & 0x00ff00ff) * s2[3]) >> 8) + (((*((DWORD*)s2) & 0x00ff00ff) * ia) >> 8) & 0x00ff00ff) - | ((((*d2 & 0x0000ff00) * s2[3]) >> 8) + (((*((DWORD*)s2) & 0x0000ff00) * ia) >> 8) & 0x0000ff00); - } -#else - if (s2[3] < 0xff) { - *d2 = ((((*d2 & 0x00ff00ff) * s2[3]) >> 8) + (*((DWORD*)s2) & 0x00ff00ff) & 0x00ff00ff) - | ((((*d2 & 0x0000ff00) * s2[3]) >> 8) + (*((DWORD*)s2) & 0x0000ff00) & 0x0000ff00); - } -#endif - } - } - break; - case MSP_RGB24: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - BYTE* d2 = d; - for (; s2 < s2end; s2 += 4, d2 += 3) { - if (s2[3] < 0xff) { - d2[0] = ((d2[0] * s2[3]) >> 8) + s2[0]; - d2[1] = ((d2[1] * s2[3]) >> 8) + s2[1]; - d2[2] = ((d2[2] * s2[3]) >> 8) + s2[2]; - } - } - } - break; - case MSP_RGB16: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - WORD* d2 = (WORD*)d; - for (; s2 < s2end; s2 += 4, d2++) { - if (s2[3] < 0x1f) { - *d2 = (WORD)((((((*d2 & 0xf81f) * s2[3]) >> 5) + (*(DWORD*)s2 & 0xf81f)) & 0xf81f) - | (((((*d2 & 0x07e0) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x07e0)) & 0x07e0)); - } - } - } - break; - case MSP_RGB15: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - WORD* d2 = (WORD*)d; - for (; s2 < s2end; s2 += 4, d2++) { - if (s2[3] < 0x1f) { - *d2 = (WORD)((((((*d2 & 0x7c1f) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x7c1f)) & 0x7c1f) - | (((((*d2 & 0x03e0) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x03e0)) & 0x03e0)); - } - } - } - break; - case MSP_YUY2: { -#ifdef _WIN64 - auto alphablt_func = AlphaBlt_YUY2_SSE2; -#else - auto alphablt_func = AlphaBlt_YUY2_MMX; -#endif - //alphablt_func = AlphaBlt_YUY2_C; - - alphablt_func(w, h, d, dst.pitch, s, src.pitch); - } - break; - case MSP_YV12: - case MSP_IYUV: - for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - BYTE* d2 = d; - for (; s2 < s2end; s2 += 4, d2++) { - if (s2[3] < 0xff) { - d2[0] = (((d2[0] - 0x10) * s2[3]) >> 8) + s2[1]; - } - } - } - break; - default: - return E_NOTIMPL; - } - - dst.pitch = abs(dst.pitch); - - if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) { - int h2 = h / 2; - - if (!dst.pitchUV) { - dst.pitchUV = dst.pitch / 2; - } - - BYTE* ss[2]; - ss[0] = src.bits + src.pitch * rs.top + rs.left * 4; - ss[1] = ss[0] + 4; - - if (!dst.bitsU || !dst.bitsV) { - dst.bitsU = dst.bits + dst.pitch * dst.h; - dst.bitsV = dst.bitsU + dst.pitchUV * dst.h / 2; - - if (dst.type == MSP_YV12) { - BYTE* p = dst.bitsU; - dst.bitsU = dst.bitsV; - dst.bitsV = p; - } - } - - BYTE* dd[2]; - dd[0] = dst.bitsU + dst.pitchUV * rd.top / 2 + rd.left / 2; - dd[1] = dst.bitsV + dst.pitchUV * rd.top / 2 + rd.left / 2; - - if (rd.top > rd.bottom) { - dd[0] = dst.bitsU + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; - dd[1] = dst.bitsV + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; - dst.pitchUV = -dst.pitchUV; - } - - for (ptrdiff_t i = 0; i < 2; i++) { - s = ss[i]; - d = dd[i]; - BYTE* is = ss[1 - i]; - for (ptrdiff_t j = 0; j < h2; j++, s += src.pitch * 2, d += dst.pitchUV, is += src.pitch * 2) { - BYTE* s2 = s; - BYTE* s2end = s2 + w * 4; - BYTE* d2 = d; - BYTE* is2 = is; - for (; s2 < s2end; s2 += 8, d2++, is2 += 8) { - unsigned int ia = (s2[3] + s2[3 + src.pitch] + is2[3] + is2[3 + src.pitch]) >> 2; - if (ia < 0xff) { - *d2 = BYTE((((*d2 - 0x80) * ia) >> 8) + ((s2[0] + s2[src.pitch]) >> 1)); - } - } - } - } - } - - return S_OK; -} - -// -// CMemSubPicAllocator -// - -CMemSubPicAllocator::CMemSubPicAllocator(int type, SIZE maxsize) - : CSubPicAllocatorImpl(maxsize, false) - , m_type(type) - , m_maxsize(maxsize) -{ -} - -CMemSubPicAllocator::~CMemSubPicAllocator() -{ - CAutoLock cAutoLock(this); - - for (const auto& p : m_freeMemoryChunks) { - delete[] std::get<1>(p); - } -} - -// ISubPicAllocatorImpl - -bool CMemSubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) -{ - if (!ppSubPic || m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { - return false; - } - - SubPicDesc spd; - spd.w = m_maxsize.cx; - spd.h = m_maxsize.cy; - spd.bpp = 32; - spd.pitch = (spd.w * spd.bpp) >> 3; - spd.type = m_type; - spd.vidrect = m_curvidrect; - - if (!AllocSpdBits(spd)) { - return false; - } - - try { - *ppSubPic = DEBUG_NEW CMemSubPic(spd, this); - } catch (CMemoryException* e) { - e->Delete(); - delete [] spd.bits; - return false; - } - - (*ppSubPic)->AddRef(); - (*ppSubPic)->SetInverseAlpha(m_bInvAlpha); - - return true; -} - -bool CMemSubPicAllocator::AllocSpdBits(SubPicDesc& spd) -{ - CAutoLock cAutoLock(this); - - ASSERT(!spd.bits); - ASSERT(spd.pitch * spd.h > 0); - - auto it = std::find_if(m_freeMemoryChunks.cbegin(), m_freeMemoryChunks.cend(), [&](const std::pair& p) { - return std::get<0>(p) == size_t(spd.pitch) * spd.h; - }); - - if (it != m_freeMemoryChunks.cend()) { - spd.bits = std::get<1>(*it); - m_freeMemoryChunks.erase(it); - } else { - try { - spd.bits = DEBUG_NEW BYTE[spd.pitch * spd.h]; - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - return false; - } - } - return true; -} - -void CMemSubPicAllocator::FreeSpdBits(SubPicDesc& spd) -{ - CAutoLock cAutoLock(this); - - ASSERT(spd.bits); - m_freeMemoryChunks.emplace_back(spd.pitch * spd.h, spd.bits); - spd.bits = nullptr; -} - -STDMETHODIMP CMemSubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) -{ - if (maxTextureSize.cx > 0 && maxTextureSize.cy > 0 && m_maxsize != maxTextureSize) { - m_maxsize = maxTextureSize; - CAutoLock cAutoLock(this); - for (const auto& p : m_freeMemoryChunks) { - delete[] std::get<1>(p); - } - m_freeMemoryChunks.clear(); - } - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include "MemSubPic.h" + +#include +#include "stb/stb_image.h" +#include "stb/stb_image_resize2.h" + +// color conv + +static unsigned char clipBase[256 * 3]; +static unsigned char* clip = clipBase + 256; + +static const int c2y_cyb = std::lround(0.114 * 219 / 255 * 65536); +static const int c2y_cyg = std::lround(0.587 * 219 / 255 * 65536); +static const int c2y_cyr = std::lround(0.299 * 219 / 255 * 65536); +static const int c2y_cu = std::lround(1.0 / 2.018 * 1024); +static const int c2y_cv = std::lround(1.0 / 1.596 * 1024); + +int c2y_yb[256]; +int c2y_yg[256]; +int c2y_yr[256]; + +static const int y2c_cbu = std::lround(2.018 * 65536); +static const int y2c_cgu = std::lround(0.391 * 65536); +static const int y2c_cgv = std::lround(0.813 * 65536); +static const int y2c_crv = std::lround(1.596 * 65536); +static int y2c_bu[256]; +static int y2c_gu[256]; +static int y2c_gv[256]; +static int y2c_rv[256]; + +static const int cy_cy = std::lround(255.0 / 219.0 * 65536); +static const int cy_cy2 = std::lround(255.0 / 219.0 * 32768); + +void ColorConvInit() +{ + static bool bColorConvInitOK = false; + if (bColorConvInitOK) { + return; + } + + for (int i = 0; i < 256; i++) { + clipBase[i] = 0; + clipBase[i + 256] = BYTE(i); + clipBase[i + 512] = 255; + } + + for (int i = 0; i < 256; i++) { + c2y_yb[i] = c2y_cyb * i; + c2y_yg[i] = c2y_cyg * i; + c2y_yr[i] = c2y_cyr * i; + + y2c_bu[i] = y2c_cbu * (i - 128); + y2c_gu[i] = y2c_cgu * (i - 128); + y2c_gv[i] = y2c_cgv * (i - 128); + y2c_rv[i] = y2c_crv * (i - 128); + } + + bColorConvInitOK = true; +} + +// +// CMemSubPic +// + +CMemSubPic::CMemSubPic(const SubPicDesc& spd, CMemSubPicAllocator* pAllocator) + : m_pAllocator(pAllocator) + , m_spd(spd) +{ + m_maxsize.SetSize(spd.w, spd.h); + m_rcDirty.SetRect(0, 0, spd.w, spd.h); +} + +CMemSubPic::~CMemSubPic() +{ + m_pAllocator->FreeSpdBits(m_spd); + if (m_resizedSpd) { + m_pAllocator->FreeSpdBits(*m_resizedSpd); + } +} + +// ISubPic + +STDMETHODIMP_(void*) CMemSubPic::GetObject() +{ + return (void*)&m_spd; +} + +STDMETHODIMP CMemSubPic::GetDesc(SubPicDesc& spd) +{ + spd.type = m_spd.type; + spd.w = m_spd.w; + spd.h = m_spd.h; + spd.bpp = m_spd.bpp; + spd.pitch = m_spd.pitch; + spd.bits = m_spd.bits; + spd.bitsU = m_spd.bitsU; + spd.bitsV = m_spd.bitsV; + spd.vidrect = m_vidrect; + + return S_OK; +} + +STDMETHODIMP CMemSubPic::CopyTo(ISubPic* pSubPic) +{ + HRESULT hr; + if (FAILED(hr = __super::CopyTo(pSubPic))) { + return hr; + } + + SubPicDesc src, dst; + if (FAILED(GetDesc(src)) || FAILED(pSubPic->GetDesc(dst))) { + return E_FAIL; + } + + if (auto subPic = dynamic_cast(pSubPic)) { + ASSERT(subPic->m_pAllocator == m_pAllocator); + ASSERT(subPic->m_resizedSpd == nullptr); + // Move because we are not going to reuse it. + subPic->m_resizedSpd = std::move(m_resizedSpd); + } + + int w = m_rcDirty.Width(), h = m_rcDirty.Height(); + BYTE* s = src.bits + src.pitch * m_rcDirty.top + m_rcDirty.left * 4; + BYTE* d = dst.bits + dst.pitch * m_rcDirty.top + m_rcDirty.left * 4; + + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + memcpy(d, s, w * 4); + } + + return S_OK; +} + +STDMETHODIMP CMemSubPic::ClearDirtyRect() +{ + if (m_rcDirty.IsRectEmpty()) { + return S_FALSE; + } + + DWORD color = m_bInvAlpha ? 0x00000000 : 0xFF000000; + + BYTE* p = m_spd.bits + m_spd.pitch * m_rcDirty.top + m_rcDirty.left * (m_spd.bpp >> 3); + for (ptrdiff_t j = 0, h = m_rcDirty.Height(); j < h; j++, p += m_spd.pitch) { + int w = m_rcDirty.Width(); +#ifdef _WIN64 + memsetd(p, color, w * 4); // nya +#else + __asm { + mov eax, color + mov ecx, w + mov edi, p + cld + rep stosd + } +#endif + } + + m_rcDirty.SetRectEmpty(); + + return S_OK; +} + +STDMETHODIMP CMemSubPic::Lock(SubPicDesc& spd) +{ + return GetDesc(spd); +} + +HRESULT CMemSubPic::UnlockARGB() { //derived from Unlock(), supports ARGB + m_rcDirty = CRect(0, 0, m_spd.w, m_spd.h); + + if (m_rcDirty.IsRectEmpty()) { + return S_OK; + } + + if (m_spd.bpp != 32 || m_spd.type != MSP_RGB32) { + return E_INVALIDARG; + } + + CRect r = m_spd.vidrect; + CRect rcDirty = m_rcDirty; + if (m_spd.h != r.Height() || m_spd.w != r.Width()) { + if (!m_resizedSpd) { + m_resizedSpd = std::unique_ptr(DEBUG_NEW SubPicDesc); + } + + m_resizedSpd->type = m_spd.type; + m_resizedSpd->w = r.Width(); + m_resizedSpd->h = r.Height(); + m_resizedSpd->pitch = r.Width() * 4; + m_resizedSpd->bpp = m_spd.bpp; + m_resizedSpd->vidrect = { 0,0,r.Width(),r.Height() }; + + if (!m_resizedSpd->bits) { + m_pAllocator->AllocSpdBits(*m_resizedSpd); + } + + auto& s = m_spd; + auto& d = *m_resizedSpd; + stbir_resize(s.bits, s.w, s.h, s.pitch, d.bits, d.w, d.h, d.pitch, STBIR_RGBA_PM, STBIR_TYPE_UINT8_SRGB, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT); + TRACE("CMemSubPic: Resized SubPic %dx%d -> %dx%d\n", m_spd.w, m_spd.h, r.Width(), r.Height()); + + // Set whole resized spd as dirty, we are not going to reuse it. + rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); + } + else if (m_resizedSpd) { + // Resize is not needed so release m_resizedSpd. + m_pAllocator->FreeSpdBits(*m_resizedSpd); + m_resizedSpd = nullptr; + } + + if (!m_resizedSpd) { + m_rcDirty = rcDirty; + } + + return S_OK; +} + + +STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) +{ + m_rcDirty = pDirtyRect ? *pDirtyRect : CRect(0, 0, m_spd.w, m_spd.h); + + if (m_rcDirty.IsRectEmpty()) { + return S_OK; + } + + CRect r = m_spd.vidrect; + CRect rcDirty = m_rcDirty; + if (m_spd.h != r.Height() || m_spd.w != r.Width()) { + if (!m_resizedSpd) { + m_resizedSpd = std::unique_ptr(DEBUG_NEW SubPicDesc); + } + + m_resizedSpd->type = m_spd.type; + m_resizedSpd->w = r.Width(); + m_resizedSpd->h = r.Height(); + m_resizedSpd->pitch = r.Width() * 4; + m_resizedSpd->bpp = m_spd.bpp; + + if (!m_resizedSpd->bits) { + m_pAllocator->AllocSpdBits(*m_resizedSpd); + } + + BitBltFromRGBToRGBStretch(m_resizedSpd->w, m_resizedSpd->h, m_resizedSpd->bits, m_resizedSpd->pitch, m_resizedSpd->bpp + , m_spd.w, m_spd.h, m_spd.bits, m_spd.pitch, m_spd.bpp); + TRACE("CMemSubPic: Resized SubPic %dx%d -> %dx%d\n", m_spd.w, m_spd.h, r.Width(), r.Height()); + + // Set whole resized spd as dirty, we are not going to reuse it. + rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); + } else if (m_resizedSpd) { + // Resize is not needed so release m_resizedSpd. + m_pAllocator->FreeSpdBits(*m_resizedSpd); + m_resizedSpd = nullptr; + } + + const SubPicDesc& subPic = m_resizedSpd ? *m_resizedSpd : m_spd; + + if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV || subPic.type == MSP_AYUV) { + ColorConvInit(); + + if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { + rcDirty.left &= ~1; + rcDirty.right = (rcDirty.right + 1) & ~1; + + if (subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { + rcDirty.top &= ~1; + rcDirty.bottom = (rcDirty.bottom + 1) & ~1; + } + } + } + + if (!m_resizedSpd) { + m_rcDirty = rcDirty; + } + + int w = rcDirty.Width(), h = rcDirty.Height(); + BYTE* top = subPic.bits + subPic.pitch * rcDirty.top + rcDirty.left * 4; + BYTE* bottom = top + subPic.pitch * h; + + if (subPic.type == MSP_RGB16) { + for (; top < bottom ; top += subPic.pitch) { + DWORD* s = (DWORD*)top; + DWORD* e = s + w; + for (; s < e; s++) { + *s = ((*s >> 3) & 0x1f000000) | ((*s >> 8) & 0xf800) | ((*s >> 5) & 0x07e0) | ((*s >> 3) & 0x001f); + //*s = (*s&0xff000000)|((*s>>8)&0xf800)|((*s>>5)&0x07e0)|((*s>>3)&0x001f); + } + } + } else if (subPic.type == MSP_RGB15) { + for (; top < bottom; top += subPic.pitch) { + DWORD* s = (DWORD*)top; + DWORD* e = s + w; + for (; s < e; s++) { + *s = ((*s >> 3) & 0x1f000000) | ((*s >> 9) & 0x7c00) | ((*s >> 6) & 0x03e0) | ((*s >> 3) & 0x001f); + //*s = (*s&0xff000000)|((*s>>9)&0x7c00)|((*s>>6)&0x03e0)|((*s>>3)&0x001f); + } + } + } else if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { + for (; top < bottom ; top += subPic.pitch) { + BYTE* s = top; + BYTE* e = s + w * 4; + for (; s < e; s += 8) { // ARGB ARGB -> AxYU AxYV + if ((s[3] + s[7]) < 0x1fe) { + s[1] = BYTE((c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16); + s[5] = BYTE((c2y_yb[s[4]] + c2y_yg[s[5]] + c2y_yr[s[6]] + 0x108000) >> 16); + + int scaled_y = (s[1] + s[5] - 32) * cy_cy2; + + s[0] = clip[(((((s[0] + s[4]) << 15) - scaled_y) >> 10) * c2y_cu + 0x800000 + 0x8000) >> 16]; + s[4] = clip[(((((s[2] + s[6]) << 15) - scaled_y) >> 10) * c2y_cv + 0x800000 + 0x8000) >> 16]; + } else { + s[1] = s[5] = 0x10; + s[0] = s[4] = 0x80; + } + } + } + } else if (subPic.type == MSP_AYUV) { + for (; top < bottom ; top += subPic.pitch) { + BYTE* s = top; + BYTE* e = s + w * 4; + + for (; s < e; s += 4) { // ARGB -> AYUV + if (s[3] < 0xff) { + auto y = BYTE((c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16); + int scaled_y = (y - 32) * cy_cy; + s[1] = clip[((((s[0] << 16) - scaled_y) >> 10) * c2y_cu + 0x800000 + 0x8000) >> 16]; + s[0] = clip[((((s[2] << 16) - scaled_y) >> 10) * c2y_cv + 0x800000 + 0x8000) >> 16]; + s[2] = y; + } else { + s[0] = s[1] = 0x80; + s[2] = 0x10; + } + } + } + } + + return S_OK; +} + +#ifdef _WIN64 +void AlphaBlt_YUY2_SSE2(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) +{ + unsigned int ia; + static const __int64 _8181 = 0x0080001000800010i64; + + for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { + DWORD* d2 = (DWORD*)d; + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + + for (; s2 < s2end; s2 += 8, d2++) { + ia = (s2[3] + s2[7]) >> 1; + if (ia < 0xff) { + unsigned int c = (s2[4] << 24) | (s2[5] << 16) | (s2[0] << 8) | s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; + + ia = (ia << 24) | (s2[7] << 16) | (ia << 8) | s2[3]; + // SSE2 + __m128i mm_zero = _mm_setzero_si128(); + __m128i mm_8181 = _mm_move_epi64(_mm_cvtsi64_si128(_8181)); + __m128i mm_c = _mm_cvtsi32_si128(c); + mm_c = _mm_unpacklo_epi8(mm_c, mm_zero); + __m128i mm_d = _mm_cvtsi32_si128(*d2); + mm_d = _mm_unpacklo_epi8(mm_d, mm_zero); + __m128i mm_a = _mm_cvtsi32_si128(ia); + mm_a = _mm_unpacklo_epi8(mm_a, mm_zero); + mm_a = _mm_srli_epi16(mm_a, 1); + mm_d = _mm_sub_epi16(mm_d, mm_8181); + mm_d = _mm_mullo_epi16(mm_d, mm_a); + mm_d = _mm_srai_epi16(mm_d, 7); + mm_d = _mm_adds_epi16(mm_d, mm_c); + mm_d = _mm_packus_epi16(mm_d, mm_d); + *d2 = (DWORD)_mm_cvtsi128_si32(mm_d); + } + } + } +} + +#else + +void AlphaBlt_YUY2_MMX(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) +{ + unsigned int ia; + static const __int64 _8181 = 0x0080001000800010i64; + + for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { + DWORD* d2 = (DWORD*)d; + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + + for (; s2 < s2end; s2 += 8, d2++) { + ia = (s2[3] + s2[7]) >> 1; + if (ia < 0xff) { + unsigned int c = (s2[4] << 24) | (s2[5] << 16) | (s2[0] << 8) | s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; + ia = (ia << 24) | (s2[7] << 16) | (ia << 8) | s2[3]; + __asm { + mov esi, s2 + mov edi, d2 + pxor mm0, mm0 + movq mm1, _8181 + movd mm2, c + punpcklbw mm2, mm0 + movd mm3, [edi] + punpcklbw mm3, mm0 + movd mm4, ia + punpcklbw mm4, mm0 + psrlw mm4, 1 + psubsw mm3, mm1 + pmullw mm3, mm4 + psraw mm3, 7 + paddsw mm3, mm2 + packuswb mm3, mm3 + movd [edi], mm3 + }; + } + } + } + _mm_empty(); +} +#endif + +void AlphaBlt_YUY2_C(int w, int h, BYTE* d, int dstpitch, BYTE* s, int srcpitch) +{ + unsigned int ia; + + for (ptrdiff_t j = 0; j < h; j++, s += srcpitch, d += dstpitch) { + DWORD* d2 = (DWORD*)d; + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + + for (; s2 < s2end; s2 += 8, d2++) { + ia = (s2[3] + s2[7]) >> 1; + if (ia < 0xff) { + //unsigned int c = (s2[4]<<24)|(s2[5]<<16)|(s2[0]<<8)|s2[1]; // (v<<24)|(y2<<16)|(u<<8)|y1; + + // YUY2 colorspace fix. rewritten from sse2 asm + DWORD y1 = (DWORD)(((((*d2 & 0xff) - 0x10) * (s2[3] >> 1)) >> 7) + s2[1]) & 0xff; // y1 + DWORD uu = (DWORD)((((((*d2 >> 8) & 0xff) - 0x80) * (ia >> 1)) >> 7) + s2[0]) & 0xff; // u + DWORD y2 = (DWORD)((((((*d2 >> 16) & 0xff) - 0x10) * (s2[7] >> 1)) >> 7) + s2[5]) & 0xff; // y2 + DWORD vv = (DWORD)((((((*d2 >> 24) & 0xff) - 0x80) * (ia >> 1)) >> 7) + s2[4]) & 0xff; // v + *d2 = (y1) | (uu << 8) | (y2 << 16) | (vv << 24); + } + } + } +} + +STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) +{ + ASSERT(pTarget); + + if (!pSrc || !pDst || !pTarget) { + return E_POINTER; + } + + const SubPicDesc& src = m_resizedSpd ? *m_resizedSpd : m_spd; + SubPicDesc dst = *pTarget; // copy, because we might modify it + + if (src.type != dst.type) { + return E_INVALIDARG; + } + + CRect rs(*pSrc), rd(*pDst); + + if (m_resizedSpd) { + rs = rd = CRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); + } + + if (dst.h < 0) { + dst.h = -dst.h; + rd.bottom = dst.h - rd.bottom; + rd.top = dst.h - rd.top; + } + + if (rs.Width() != rd.Width() || rs.Height() != abs(rd.Height())) { + return E_INVALIDARG; + } + + int w = rs.Width(), h = rs.Height(); + BYTE* s = src.bits + src.pitch * rs.top + rs.left * 4; + BYTE* d = dst.bits + dst.pitch * rd.top + ((rd.left * dst.bpp) >> 3); + + if (rd.top > rd.bottom) { + if (dst.type == MSP_RGB32 || dst.type == MSP_RGB24 + || dst.type == MSP_RGB16 || dst.type == MSP_RGB15 + || dst.type == MSP_YUY2 || dst.type == MSP_AYUV) { + d = dst.bits + dst.pitch * (rd.top - 1) + (rd.left * dst.bpp >> 3); + } else if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) { + d = dst.bits + dst.pitch * (rd.top - 1) + (rd.left * 8 >> 3); + } else { + return E_NOTIMPL; + } + + dst.pitch = -dst.pitch; + } + + // TODO: m_bInvAlpha support + switch (dst.type) { + case MSP_RGBA: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + DWORD* d2 = (DWORD*)d; + for (; s2 < s2end; s2 += 4, d2++) { + if (s2[3] < 0xff) { + DWORD bd = 0x00000100 - ((DWORD) s2[3]); + DWORD B = ((*((DWORD*)s2) & 0x000000ff) << 8) / bd; + DWORD V = ((*((DWORD*)s2) & 0x0000ff00) / bd) << 8; + DWORD R = (((*((DWORD*)s2) & 0x00ff0000) >> 8) / bd) << 16; + *d2 = B | V | R + | (0xff000000 - (*((DWORD*)s2) & 0xff000000)) & 0xff000000; + } + } + } + break; + case MSP_RGB32: + case MSP_AYUV: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + DWORD* d2 = (DWORD*)d; + for (; s2 < s2end; s2 += 4, d2++) { +#ifdef _WIN64 + DWORD ia = 256 - s2[3]; + if (s2[3] < 0xff) { + *d2 = ((((*d2 & 0x00ff00ff) * s2[3]) >> 8) + (((*((DWORD*)s2) & 0x00ff00ff) * ia) >> 8) & 0x00ff00ff) + | ((((*d2 & 0x0000ff00) * s2[3]) >> 8) + (((*((DWORD*)s2) & 0x0000ff00) * ia) >> 8) & 0x0000ff00); + } +#else + if (s2[3] < 0xff) { + *d2 = ((((*d2 & 0x00ff00ff) * s2[3]) >> 8) + (*((DWORD*)s2) & 0x00ff00ff) & 0x00ff00ff) + | ((((*d2 & 0x0000ff00) * s2[3]) >> 8) + (*((DWORD*)s2) & 0x0000ff00) & 0x0000ff00); + } +#endif + } + } + break; + case MSP_RGB24: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + BYTE* d2 = d; + for (; s2 < s2end; s2 += 4, d2 += 3) { + if (s2[3] < 0xff) { + d2[0] = ((d2[0] * s2[3]) >> 8) + s2[0]; + d2[1] = ((d2[1] * s2[3]) >> 8) + s2[1]; + d2[2] = ((d2[2] * s2[3]) >> 8) + s2[2]; + } + } + } + break; + case MSP_RGB16: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + WORD* d2 = (WORD*)d; + for (; s2 < s2end; s2 += 4, d2++) { + if (s2[3] < 0x1f) { + *d2 = (WORD)((((((*d2 & 0xf81f) * s2[3]) >> 5) + (*(DWORD*)s2 & 0xf81f)) & 0xf81f) + | (((((*d2 & 0x07e0) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x07e0)) & 0x07e0)); + } + } + } + break; + case MSP_RGB15: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + WORD* d2 = (WORD*)d; + for (; s2 < s2end; s2 += 4, d2++) { + if (s2[3] < 0x1f) { + *d2 = (WORD)((((((*d2 & 0x7c1f) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x7c1f)) & 0x7c1f) + | (((((*d2 & 0x03e0) * s2[3]) >> 5) + (*(DWORD*)s2 & 0x03e0)) & 0x03e0)); + } + } + } + break; + case MSP_YUY2: { +#ifdef _WIN64 + auto alphablt_func = AlphaBlt_YUY2_SSE2; +#else + auto alphablt_func = AlphaBlt_YUY2_MMX; +#endif + //alphablt_func = AlphaBlt_YUY2_C; + + alphablt_func(w, h, d, dst.pitch, s, src.pitch); + } + break; + case MSP_YV12: + case MSP_IYUV: + for (ptrdiff_t j = 0; j < h; j++, s += src.pitch, d += dst.pitch) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + BYTE* d2 = d; + for (; s2 < s2end; s2 += 4, d2++) { + if (s2[3] < 0xff) { + d2[0] = (((d2[0] - 0x10) * s2[3]) >> 8) + s2[1]; + } + } + } + break; + default: + return E_NOTIMPL; + } + + dst.pitch = abs(dst.pitch); + + if (dst.type == MSP_YV12 || dst.type == MSP_IYUV) { + int h2 = h / 2; + + if (!dst.pitchUV) { + dst.pitchUV = dst.pitch / 2; + } + + BYTE* ss[2]; + ss[0] = src.bits + src.pitch * rs.top + rs.left * 4; + ss[1] = ss[0] + 4; + + if (!dst.bitsU || !dst.bitsV) { + dst.bitsU = dst.bits + dst.pitch * dst.h; + dst.bitsV = dst.bitsU + dst.pitchUV * dst.h / 2; + + if (dst.type == MSP_YV12) { + BYTE* p = dst.bitsU; + dst.bitsU = dst.bitsV; + dst.bitsV = p; + } + } + + BYTE* dd[2]; + dd[0] = dst.bitsU + dst.pitchUV * rd.top / 2 + rd.left / 2; + dd[1] = dst.bitsV + dst.pitchUV * rd.top / 2 + rd.left / 2; + + if (rd.top > rd.bottom) { + dd[0] = dst.bitsU + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; + dd[1] = dst.bitsV + dst.pitchUV * (rd.top / 2 - 1) + rd.left / 2; + dst.pitchUV = -dst.pitchUV; + } + + for (ptrdiff_t i = 0; i < 2; i++) { + s = ss[i]; + d = dd[i]; + BYTE* is = ss[1 - i]; + for (ptrdiff_t j = 0; j < h2; j++, s += src.pitch * 2, d += dst.pitchUV, is += src.pitch * 2) { + BYTE* s2 = s; + BYTE* s2end = s2 + w * 4; + BYTE* d2 = d; + BYTE* is2 = is; + for (; s2 < s2end; s2 += 8, d2++, is2 += 8) { + unsigned int ia = (s2[3] + s2[3 + src.pitch] + is2[3] + is2[3 + src.pitch]) >> 2; + if (ia < 0xff) { + *d2 = BYTE((((*d2 - 0x80) * ia) >> 8) + ((s2[0] + s2[src.pitch]) >> 1)); + } + } + } + } + } + + return S_OK; +} + +// +// CMemSubPicAllocator +// + +CMemSubPicAllocator::CMemSubPicAllocator(int type, SIZE maxsize) + : CSubPicAllocatorImpl(maxsize, false) + , m_type(type) + , m_maxsize(maxsize) +{ +} + +CMemSubPicAllocator::~CMemSubPicAllocator() +{ + CAutoLock cAutoLock(this); + + for (const auto& p : m_freeMemoryChunks) { + delete[] std::get<1>(p); + } +} + +// ISubPicAllocatorImpl + +bool CMemSubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) +{ + if (!ppSubPic || m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { + return false; + } + + SubPicDesc spd; + spd.w = m_maxsize.cx; + spd.h = m_maxsize.cy; + spd.bpp = 32; + spd.pitch = (spd.w * spd.bpp) >> 3; + spd.type = m_type; + spd.vidrect = m_curvidrect; + + if (!AllocSpdBits(spd)) { + return false; + } + + try { + *ppSubPic = DEBUG_NEW CMemSubPic(spd, this); + } catch (CMemoryException* e) { + e->Delete(); + delete [] spd.bits; + return false; + } + + (*ppSubPic)->AddRef(); + (*ppSubPic)->SetInverseAlpha(m_bInvAlpha); + + return true; +} + +bool CMemSubPicAllocator::AllocSpdBits(SubPicDesc& spd) +{ + CAutoLock cAutoLock(this); + + ASSERT(!spd.bits); + ASSERT(spd.pitch * spd.h > 0); + + auto it = std::find_if(m_freeMemoryChunks.cbegin(), m_freeMemoryChunks.cend(), [&](const std::pair& p) { + return std::get<0>(p) == size_t(spd.pitch) * spd.h; + }); + + if (it != m_freeMemoryChunks.cend()) { + spd.bits = std::get<1>(*it); + m_freeMemoryChunks.erase(it); + } else { + try { + spd.bits = DEBUG_NEW BYTE[spd.pitch * spd.h]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + return false; + } + } + return true; +} + +void CMemSubPicAllocator::FreeSpdBits(SubPicDesc& spd) +{ + CAutoLock cAutoLock(this); + + ASSERT(spd.bits); + m_freeMemoryChunks.emplace_back(spd.pitch * spd.h, spd.bits); + spd.bits = nullptr; +} + +STDMETHODIMP CMemSubPicAllocator::SetMaxTextureSize(SIZE maxTextureSize) +{ + if (maxTextureSize.cx > 0 && maxTextureSize.cy > 0 && m_maxsize != maxTextureSize) { + m_maxsize = maxTextureSize; + CAutoLock cAutoLock(this); + for (const auto& p : m_freeMemoryChunks) { + delete[] std::get<1>(p); + } + m_freeMemoryChunks.clear(); + } + return S_OK; +} diff --git a/src/SubPic/MemSubPic.h b/src/SubPic/MemSubPic.h index 7686b2df42e..cc82ee3b8c5 100644 --- a/src/SubPic/MemSubPic.h +++ b/src/SubPic/MemSubPic.h @@ -1,86 +1,86 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#pragma once - -#include "SubPicImpl.h" -#include -#include - -enum { - MSP_RGB32, - MSP_RGB24, - MSP_RGB16, - MSP_RGB15, - MSP_YUY2, - MSP_YV12, - MSP_IYUV, - MSP_AYUV, - MSP_RGBA -}; - -// CMemSubPic -class CMemSubPicAllocator; -class CMemSubPic : public CSubPicImpl -{ - CComPtr m_pAllocator; - - SubPicDesc m_spd; - std::unique_ptr m_resizedSpd; - -protected: - STDMETHODIMP_(void*) GetObject(); // returns SubPicDesc* - -public: - CMemSubPic(const SubPicDesc& spd, CMemSubPicAllocator* pAllocator); - virtual ~CMemSubPic(); - - HRESULT UnlockARGB(); - - // ISubPic - STDMETHODIMP GetDesc(SubPicDesc& spd); - STDMETHODIMP CopyTo(ISubPic* pSubPic); - STDMETHODIMP ClearDirtyRect(); - STDMETHODIMP Lock(SubPicDesc& spd); - STDMETHODIMP Unlock(RECT* pDirtyRect); - STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget); -}; - -// CMemSubPicAllocator - -class CMemSubPicAllocator : public CSubPicAllocatorImpl, public CCritSec -{ - int m_type; - CSize m_maxsize; - - std::vector> m_freeMemoryChunks; - - bool Alloc(bool fStatic, ISubPic** ppSubPic); - -public: - CMemSubPicAllocator(int type, SIZE maxsize); - virtual ~CMemSubPicAllocator(); - - bool AllocSpdBits(SubPicDesc& spd); - void FreeSpdBits(SubPicDesc& spd); - - STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize) override; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#pragma once + +#include "SubPicImpl.h" +#include +#include + +enum { + MSP_RGB32, + MSP_RGB24, + MSP_RGB16, + MSP_RGB15, + MSP_YUY2, + MSP_YV12, + MSP_IYUV, + MSP_AYUV, + MSP_RGBA +}; + +// CMemSubPic +class CMemSubPicAllocator; +class CMemSubPic : public CSubPicImpl +{ + CComPtr m_pAllocator; + + SubPicDesc m_spd; + std::unique_ptr m_resizedSpd; + +protected: + STDMETHODIMP_(void*) GetObject(); // returns SubPicDesc* + +public: + CMemSubPic(const SubPicDesc& spd, CMemSubPicAllocator* pAllocator); + virtual ~CMemSubPic(); + + HRESULT UnlockARGB(); + + // ISubPic + STDMETHODIMP GetDesc(SubPicDesc& spd); + STDMETHODIMP CopyTo(ISubPic* pSubPic); + STDMETHODIMP ClearDirtyRect(); + STDMETHODIMP Lock(SubPicDesc& spd); + STDMETHODIMP Unlock(RECT* pDirtyRect); + STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget); +}; + +// CMemSubPicAllocator + +class CMemSubPicAllocator : public CSubPicAllocatorImpl, public CCritSec +{ + int m_type; + CSize m_maxsize; + + std::vector> m_freeMemoryChunks; + + bool Alloc(bool fStatic, ISubPic** ppSubPic); + +public: + CMemSubPicAllocator(int type, SIZE maxsize); + virtual ~CMemSubPicAllocator(); + + bool AllocSpdBits(SubPicDesc& spd); + void FreeSpdBits(SubPicDesc& spd); + + STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize) override; +}; diff --git a/src/SubPic/SubPic.vcxproj b/src/SubPic/SubPic.vcxproj index d134d672ea4..faf266b6ee0 100644 --- a/src/SubPic/SubPic.vcxproj +++ b/src/SubPic/SubPic.vcxproj @@ -1,85 +1,85 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {D514EA4D-EAFB-47A9-A437-A582CA571251} - SubPic - MFCProj - SubPic - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\include;..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {D514EA4D-EAFB-47A9-A437-A582CA571251} + SubPic + MFCProj + SubPic + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\include;..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/SubPic/SubPic.vcxproj.filters b/src/SubPic/SubPic.vcxproj.filters index a87f236cad7..72112ad70e9 100644 --- a/src/SubPic/SubPic.vcxproj.filters +++ b/src/SubPic/SubPic.vcxproj.filters @@ -1,101 +1,101 @@ - - - - - {bbd07979-c9e6-4936-b818-b36901e0eca8} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {c4e622a8-2caa-417f-86ec-c5c16ad85753} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {bbd07979-c9e6-4936-b818-b36901e0eca8} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c4e622a8-2caa-417f-86ec-c5c16ad85753} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/SubPic/SubPicAllocatorPresenterImpl.cpp b/src/SubPic/SubPicAllocatorPresenterImpl.cpp index e643d1cc8ed..c3d0fab9ff6 100644 --- a/src/SubPic/SubPicAllocatorPresenterImpl.cpp +++ b/src/SubPic/SubPicAllocatorPresenterImpl.cpp @@ -1,646 +1,646 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "SubPicAllocatorPresenterImpl.h" -#include "../DSUtil/DSUtil.h" -#include "../filters/renderer/VideoRenderers/RenderersSettings.h" -#include "../mpc-hc/VersionInfo.h" -#include -#include "XySubPicQueueImpl.h" -#include "XySubPicProvider.h" -#include -#include -#include -#include -#include "ScreenUtil.h" - -#include "mpc-hc_config.h" - -#if !TRACE_SUBTITLES -#define TRACE(...) -#endif - -CSubPicAllocatorPresenterImpl::CSubPicAllocatorPresenterImpl(HWND hWnd, HRESULT& hr, CString* _pError) - : CUnknown(NAME("CSubPicAllocatorPresenterImpl"), nullptr) - , m_hWnd(hWnd) - , m_rtSubtitleDelay(0) - , m_maxSubtitleTextureSize(0, 0) - , m_nativeVideoSize(0, 0) - , m_aspectRatio(0, 0) - , m_videoRect(0, 0, 0, 0) - , m_windowRect(0, 0, 0, 0) - , m_rtNow(0) - , m_fps(25.0) - , m_refreshRate(0) - , m_bDeviceResetRequested(false) - , m_bPendingResetDevice(false) - , m_bDefaultVideoAngleSwitchAR(false) - , m_bHookedNewSegment(false) - , m_bHookedReceive(false) -{ - if (!IsWindow(m_hWnd)) { - hr = E_INVALIDARG; - if (_pError) { - *_pError += _T("Invalid window handle in ISubPicAllocatorPresenterImpl\n"); - } - return; - } - GetWindowRect(m_hWnd, &m_windowRect); - hr = S_OK; -} - -CSubPicAllocatorPresenterImpl::~CSubPicAllocatorPresenterImpl() -{ -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - - return - QI(ISubPicAllocatorPresenter) - QI(ISubPicAllocatorPresenter2) - QI(ISubRenderOptions) - QI(ISubRenderConsumer) - QI(ISubRenderConsumer2) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CSubPicAllocatorPresenterImpl::InitMaxSubtitleTextureSize(int maxSizeX, int maxSizeY, CSize largestScreen) -{ - if (maxSizeX < 384 || maxSizeY < 288) { - m_maxSubtitleTextureSize = largestScreen; - } else { - if (maxSizeX * maxSizeY > largestScreen.cx * largestScreen.cy) { - m_maxSubtitleTextureSize = largestScreen; - } else { - m_maxSubtitleTextureSize.cx = maxSizeX; - m_maxSubtitleTextureSize.cy = maxSizeY; - } - } -#if DEBUG_OVERRIDE_TEXTURE_SIZE - m_maxSubtitleTextureSize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); -#endif - m_curSubtitleTextureSize = m_maxSubtitleTextureSize; - TRACE(_T("CSubPicAllocatorPresenterImpl::InitMaxSubtitleTextureSize %dx%d\n"), m_maxSubtitleTextureSize.cx, m_maxSubtitleTextureSize.cy); -} - -HRESULT CSubPicAllocatorPresenterImpl::AlphaBltSubPic(const CRect& windowRect, - const CRect& videoRect, - SubPicDesc* pTarget /*= nullptr*/, - const double videoStretchFactor /*= 1.0*/, - int xOffsetInPixels /*= 0*/, int yOffsetInPixels /*= 0*/) -{ - CComPtr pSubPic; - if (m_pSubPicQueue->LookupSubPic(m_rtNow, !IsRendering(), pSubPic)) { - CRect rcSource, rcDest; - - const CRenderersSettings& r = GetRenderersSettings(); - int yOffset = yOffsetInPixels + r.subPicVerticalShift; - if (SUCCEEDED(pSubPic->GetSourceAndDest(windowRect, videoRect, rcSource, rcDest, - videoStretchFactor, xOffsetInPixels, yOffset))) { - return pSubPic->AlphaBlt(rcSource, rcDest, pTarget); - } - } - - return E_FAIL; -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetVideoSize(CSize szVideo, CSize szAspectRatio /* = CSize(0, 0) */) -{ - if (szVideo.cx == 0 || szVideo.cy == 0) { - return; - } - - m_nativeVideoSize = szVideo; - m_aspectRatio = szAspectRatio; -} - -STDMETHODIMP_(SIZE) CSubPicAllocatorPresenterImpl::GetVideoSize(bool bCorrectAR) const -{ - CSize videoSize(GetVisibleVideoSize()); - - if (bCorrectAR && m_aspectRatio.cx > 0 && m_aspectRatio.cy > 0) { - videoSize.cx = (LONGLONG(videoSize.cy) * LONGLONG(m_aspectRatio.cx)) / LONGLONG(m_aspectRatio.cy); - } - - if (m_bDefaultVideoAngleSwitchAR) { - std::swap(videoSize.cx, videoSize.cy); - } - - return videoSize; -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetPosition(RECT w, RECT v) -{ - bool bWindowPosChanged = !!(m_windowRect != w); - bool bWindowSizeChanged = !!(m_windowRect.Size() != CRect(w).Size()); - bool bVideoRectChanged = !!(m_videoRect != v); - - m_windowRect = w; - m_videoRect = v; - - if (m_pAllocator && (bWindowPosChanged || bWindowSizeChanged || bVideoRectChanged)) { - if (m_windowRect.Width() != m_curSubtitleTextureSize.cx || m_windowRect.Height() != m_curSubtitleTextureSize.cy) { - int maxpixels = m_maxSubtitleTextureSize.cx * m_maxSubtitleTextureSize.cy; - if (m_windowRect.Width() * m_windowRect.Height() <= maxpixels) { - // use window size - m_curSubtitleTextureSize = CSize(m_windowRect.Width(), m_windowRect.Height()); - } else { - bool correct_ar = false; - if (m_maxSubtitleTextureSize.cx == 2560 && m_windowRect.Width() >= 3800 && m_windowRect.Width() <= 4096) { // not 3840, to handle a maximized window as well - m_curSubtitleTextureSize = CSize(m_windowRect.Width() / 2, m_windowRect.Height() / 2); - } else { - m_curSubtitleTextureSize = CSize(m_maxSubtitleTextureSize.cx, m_maxSubtitleTextureSize.cy); - correct_ar = true; - } - - if (correct_ar) { - double new_w = sqrt((uint64_t)m_curSubtitleTextureSize.cx * m_curSubtitleTextureSize.cy * m_windowRect.Width() / m_windowRect.Height()); - double new_h = sqrt((uint64_t)m_curSubtitleTextureSize.cx * m_curSubtitleTextureSize.cy * m_windowRect.Height() / m_windowRect.Width()); - m_curSubtitleTextureSize.cx = lround(new_w); - m_curSubtitleTextureSize.cy = lround(new_h); - } - } - } - - m_pAllocator->SetMaxTextureSize(m_curSubtitleTextureSize); - m_pAllocator->SetCurSize(m_windowRect.Size()); - m_pAllocator->SetCurVidRect(m_videoRect); - - if (m_pSubPicQueue) { - m_pSubPicQueue->Invalidate(); - } - } - - if (bWindowPosChanged || bVideoRectChanged || m_bOtherTransform) { - Paint(false); - m_bOtherTransform = false; - } -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetTime(REFERENCE_TIME rtNow) -{ - m_rtNow = rtNow - m_rtSubtitleDelay; - - if (m_pSubPicQueue) { - m_pSubPicQueue->SetTime(m_rtNow); - } -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetSubtitleDelay(int delayMs) -{ - REFERENCE_TIME delay = MILLISECONDS_TO_100NS_UNITS(delayMs); - if (m_rtSubtitleDelay != delay) { - REFERENCE_TIME oldDelay = m_rtSubtitleDelay; - m_rtSubtitleDelay = delay; - SetTime(m_rtNow + oldDelay); - Paint(false); - } -} - -STDMETHODIMP_(int) CSubPicAllocatorPresenterImpl::GetSubtitleDelay() const -{ - return (int)(m_rtSubtitleDelay / 10000); -} - -STDMETHODIMP_(double) CSubPicAllocatorPresenterImpl::GetFPS() const -{ - return m_fps; -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider) -{ - CAutoLock cAutoLock(&m_csSubPicProvider); - - m_pSubPicProvider = pSubPicProvider; - - if (m_pSubPicQueue) { - m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); - } - - if (m_pAllocator) { - m_pAllocator->SetCurSize(CSize(m_windowRect.Width(), m_windowRect.Height())); - m_pAllocator->SetCurVidRect(m_videoRect); - } - - Paint(false); -} - -STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::Invalidate(REFERENCE_TIME rtInvalidate) -{ - if (m_pSubPicQueue) { - m_pSubPicQueue->Invalidate(rtInvalidate); - } -} - -void CSubPicAllocatorPresenterImpl::Transform(CRect r, Vector v[4]) -{ - v[0] = Vector((float)r.left, (float)r.top, 0); - v[1] = Vector((float)r.right, (float)r.top, 0); - v[2] = Vector((float)r.left, (float)r.bottom, 0); - v[3] = Vector((float)r.right, (float)r.bottom, 0); - - Vector center((float)r.CenterPoint().x, (float)r.CenterPoint().y, 0); - int l = (int)(Vector((float)r.Size().cx, (float)r.Size().cy, 0).Length() * 1.5f) + 1; - - for (size_t i = 0; i < 4; i++) { - v[i] = m_xform << (v[i] - center); - v[i].z = v[i].z / l + 0.5f; - v[i].x /= v[i].z * 2; - v[i].y /= v[i].z * 2; - v[i] += center; - } -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetDefaultVideoAngle(Vector v) -{ - if (m_defaultVideoAngle != v) { - constexpr float pi_2 = float(M_PI_2); - - // In theory it should be a multiple of 90 - int zAnglePi2 = std::lround(v.z / pi_2); - //ASSERT(zAnglePi2 * pi_2 == v.z); - - // Normalize the Z angle - zAnglePi2 %= 4; - if (zAnglePi2 < 0) { - zAnglePi2 += 4; - } - v.z = zAnglePi2 * pi_2; - - // Check if the default rotation change the AR - m_bDefaultVideoAngleSwitchAR = (v.z == pi_2 || v.z == 3.0f * pi_2); - - m_defaultVideoAngle = v; - UpdateXForm(); - return S_OK; - } - return S_FALSE; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetVideoAngle(Vector v) -{ - if (m_videoAngle != v) { - m_videoAngle = v; - UpdateXForm(); - return S_OK; - } - return S_FALSE; -} - -void CSubPicAllocatorPresenterImpl::UpdateXForm() -{ - Vector v = m_defaultVideoAngle + m_videoAngle; - - auto normalizeAngle = [](float & rad) { - constexpr float twoPi = float(2.0 * M_PI); - - while (rad < 0.0f) { - rad += twoPi; - } - while (rad > twoPi) { - rad -= twoPi; - } - }; - - normalizeAngle(v.x); - normalizeAngle(v.y); - normalizeAngle(v.z); - - CSize AR = GetVideoSize(true); - float fARCorrection = m_bDefaultVideoAngleSwitchAR ? float(AR.cx) / AR.cy : 1.0f; - - m_xform = XForm(Ray(Vector(), v), Vector(1.0f / fARCorrection, fARCorrection, 1.0f), false); - - Paint(false); -} - -HRESULT CSubPicAllocatorPresenterImpl::CreateDIBFromSurfaceData(D3DSURFACE_DESC desc, D3DLOCKED_RECT r, BYTE* lpDib) const -{ - bool bNeedRotation = !IsEqual(m_defaultVideoAngle.z, 0.0f); - - BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)lpDib; - ZeroMemory(bih, sizeof(BITMAPINFOHEADER)); - bih->biSize = sizeof(BITMAPINFOHEADER); - bih->biWidth = desc.Width; - bih->biHeight = desc.Height; - bih->biBitCount = 32; - bih->biPlanes = 1; - bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount >> 3; - - UINT* pBits; - if (bNeedRotation) { - pBits = (UINT*)malloc(bih->biSizeImage); - if (!pBits) { - return E_OUTOFMEMORY; - } - } else { - pBits = (UINT*)(bih + 1); - } - - BitBltFromRGBToRGB(bih->biWidth, bih->biHeight, - (BYTE*)pBits, bih->biWidth * bih->biBitCount >> 3, bih->biBitCount, - (BYTE*)r.pBits + r.Pitch * (desc.Height - 1), -r.Pitch, 32); - - if (bNeedRotation) { - constexpr float pi_2 = float(M_PI_2); - - if (m_bDefaultVideoAngleSwitchAR) { - std::swap(bih->biWidth, bih->biHeight); - } - - std::function convCoordinates; - if (IsEqual(m_defaultVideoAngle.z, pi_2)) { - convCoordinates = [desc](UINT x, UINT y) { - return x * desc.Height + desc.Height - 1 - y; - }; - } else if (IsEqual(m_defaultVideoAngle.z, 2 * pi_2)) { - convCoordinates = [desc](UINT x, UINT y) { - return desc.Width - 1 - x + (desc.Height - 1 - y) * desc.Width; - }; - } else { - ASSERT(IsEqual(m_defaultVideoAngle.z, 3 * pi_2)); - convCoordinates = [desc](UINT x, UINT y) { - return (desc.Width - 1 - x) * desc.Height + y; - }; - } - - UINT* pBitsDest = (UINT*)(bih + 1); - for (UINT x = 0; x < desc.Width; x++) { - for (UINT y = 0; y < desc.Height; y++) { - pBitsDest[convCoordinates(x, y)] = pBits[x + y * desc.Width]; - } - } - - free(pBits); - } - - return S_OK; -} - -// ISubRenderOptions - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetBool(LPCSTR field, bool* value) -{ - CheckPointer(value, E_POINTER); - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetInt(LPCSTR field, int* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "supportedLevels")) { - if (CComQIPtr pEVR = (ISubPicAllocatorPresenter*)this) { - const CRenderersSettings& r = GetRenderersSettings(); - if (r.m_AdvRendSets.iEVROutputRange == 1) { - *value = 3; // TV preferred - } else { - *value = 2; // PC preferred - } - } else { - *value = 0; // PC only - } - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetSize(LPCSTR field, SIZE* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "originalVideoSize")) { - *value = GetVideoSize(false); - return S_OK; - } else if (!strcmp(field, "arAdjustedVideoSize")) { - *value = GetVideoSize(true); - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetRect(LPCSTR field, RECT* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "videoOutputRect") || !strcmp(field, "subtitleTargetRect")) { - if (m_videoRect.IsRectEmpty()) { - *value = m_windowRect; - } else { - value->left = 0; - value->top = 0; - value->right = m_videoRect.Width(); - value->bottom = m_videoRect.Height(); - } - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetUlonglong(LPCSTR field, ULONGLONG* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "frameRate")) { - *value = (REFERENCE_TIME)(10000000.0 / m_fps); - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetDouble(LPCSTR field, double* value) -{ - CheckPointer(value, E_POINTER); - if (!strcmp(field, "refreshRate")) { - *value = 1000.0 / m_refreshRate; - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetString(LPCSTR field, LPWSTR* value, int* chars) -{ - CheckPointer(value, E_POINTER); - CheckPointer(chars, E_POINTER); - CStringW ret = nullptr; - - if (!strcmp(field, "name")) { - ret = L"MPC-HC"; - } else if (!strcmp(field, "version")) { - ret = VersionInfo::GetVersionString(); - } else if (!strcmp(field, "yuvMatrix")) { - ret = L"None"; - - if (m_inputMediaType.IsValid() && m_inputMediaType.formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* pVIH2 = (VIDEOINFOHEADER2*)m_inputMediaType.pbFormat; - - if (pVIH2->dwControlFlags & AMCONTROL_COLORINFO_PRESENT) { - DXVA2_ExtendedFormat& flags = (DXVA2_ExtendedFormat&)pVIH2->dwControlFlags; - - ret = (flags.NominalRange == DXVA2_NominalRange_Normal) ? L"PC." : L"TV."; - - switch (flags.VideoTransferMatrix) { - case DXVA2_VideoTransferMatrix_BT601: - ret.Append(L"601"); - break; - case DXVA2_VideoTransferMatrix_BT709: - ret.Append(L"709"); - break; - case DXVA2_VideoTransferMatrix_SMPTE240M: - ret.Append(L"240M"); - break; - case 4: - ret.Append(L"2020"); - break; - default: - ret = L"None"; - break; - } - } - } - } - - if (!ret.IsEmpty()) { - int len = ret.GetLength(); - size_t sz = (len + 1) * sizeof(WCHAR); - LPWSTR buf = (LPWSTR)LocalAlloc(LPTR, sz); - - if (!buf) { - return E_OUTOFMEMORY; - } - - wcscpy_s(buf, len + 1, ret); - *chars = len; - *value = buf; - - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::GetBin(LPCSTR field, LPVOID* value, int* size) -{ - CheckPointer(value, E_POINTER); - CheckPointer(size, E_POINTER); - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetBool(LPCSTR field, bool value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetInt(LPCSTR field, int value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetSize(LPCSTR field, SIZE value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetRect(LPCSTR field, RECT value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetUlonglong(LPCSTR field, ULONGLONG value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetDouble(LPCSTR field, double value) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetString(LPCSTR field, LPWSTR value, int chars) -{ - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::SetBin(LPCSTR field, LPVOID value, int size) -{ - return E_INVALIDARG; -} - -// ISubRenderConsumer - -STDMETHODIMP CSubPicAllocatorPresenterImpl::Connect(ISubRenderProvider* subtitleRenderer) -{ - HRESULT hr = E_FAIL; - - if (m_pSubPicProvider) { - return hr; - } - - hr = subtitleRenderer->SetBool("combineBitmaps", true); - if (FAILED(hr)) { - return hr; - } - - if (CComQIPtr pSubConsumer = m_pSubPicQueue) { - hr = pSubConsumer->Connect(subtitleRenderer); - } else { - CComPtr pSubPicProvider = (ISubPicProvider*)DEBUG_NEW CXySubPicProvider(subtitleRenderer); - CComPtr pSubPicQueue = (ISubPicQueue*)DEBUG_NEW CXySubPicQueueNoThread(m_pAllocator, &hr); - - if (SUCCEEDED(hr)) { - pSubPicQueue->SetSubPicProvider(pSubPicProvider); - m_pSubPicProvider = pSubPicProvider; - m_pSubPicQueue = pSubPicQueue; - m_pAllocator->SetInverseAlpha(true); - } - } - - return hr; -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::Disconnect() -{ - m_pSubPicProvider = nullptr; - return m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); -} - -STDMETHODIMP CSubPicAllocatorPresenterImpl::DeliverFrame(REFERENCE_TIME start, REFERENCE_TIME stop, LPVOID context, ISubRenderFrame* subtitleFrame) -{ - HRESULT hr = E_FAIL; - - if (CComQIPtr pXyProvider = m_pSubPicProvider) { - hr = pXyProvider->DeliverFrame(start, stop, context, subtitleFrame); - } - - return hr; -} - -// ISubRenderConsumer2 - -STDMETHODIMP CSubPicAllocatorPresenterImpl::Clear(REFERENCE_TIME clearNewerThan /* = 0 */) -{ - return m_pSubPicQueue->Invalidate(clearNewerThan); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "SubPicAllocatorPresenterImpl.h" +#include "../DSUtil/DSUtil.h" +#include "../filters/renderer/VideoRenderers/RenderersSettings.h" +#include "../mpc-hc/VersionInfo.h" +#include +#include "XySubPicQueueImpl.h" +#include "XySubPicProvider.h" +#include +#include +#include +#include +#include "ScreenUtil.h" + +#include "mpc-hc_config.h" + +#if !TRACE_SUBTITLES +#define TRACE(...) +#endif + +CSubPicAllocatorPresenterImpl::CSubPicAllocatorPresenterImpl(HWND hWnd, HRESULT& hr, CString* _pError) + : CUnknown(NAME("CSubPicAllocatorPresenterImpl"), nullptr) + , m_hWnd(hWnd) + , m_rtSubtitleDelay(0) + , m_maxSubtitleTextureSize(0, 0) + , m_nativeVideoSize(0, 0) + , m_aspectRatio(0, 0) + , m_videoRect(0, 0, 0, 0) + , m_windowRect(0, 0, 0, 0) + , m_rtNow(0) + , m_fps(25.0) + , m_refreshRate(0) + , m_bDeviceResetRequested(false) + , m_bPendingResetDevice(false) + , m_bDefaultVideoAngleSwitchAR(false) + , m_bHookedNewSegment(false) + , m_bHookedReceive(false) +{ + if (!IsWindow(m_hWnd)) { + hr = E_INVALIDARG; + if (_pError) { + *_pError += _T("Invalid window handle in ISubPicAllocatorPresenterImpl\n"); + } + return; + } + GetWindowRect(m_hWnd, &m_windowRect); + hr = S_OK; +} + +CSubPicAllocatorPresenterImpl::~CSubPicAllocatorPresenterImpl() +{ +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + + return + QI(ISubPicAllocatorPresenter) + QI(ISubPicAllocatorPresenter2) + QI(ISubRenderOptions) + QI(ISubRenderConsumer) + QI(ISubRenderConsumer2) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CSubPicAllocatorPresenterImpl::InitMaxSubtitleTextureSize(int maxSizeX, int maxSizeY, CSize largestScreen) +{ + if (maxSizeX < 384 || maxSizeY < 288) { + m_maxSubtitleTextureSize = largestScreen; + } else { + if (maxSizeX * maxSizeY > largestScreen.cx * largestScreen.cy) { + m_maxSubtitleTextureSize = largestScreen; + } else { + m_maxSubtitleTextureSize.cx = maxSizeX; + m_maxSubtitleTextureSize.cy = maxSizeY; + } + } +#if DEBUG_OVERRIDE_TEXTURE_SIZE + m_maxSubtitleTextureSize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); +#endif + m_curSubtitleTextureSize = m_maxSubtitleTextureSize; + TRACE(_T("CSubPicAllocatorPresenterImpl::InitMaxSubtitleTextureSize %dx%d\n"), m_maxSubtitleTextureSize.cx, m_maxSubtitleTextureSize.cy); +} + +HRESULT CSubPicAllocatorPresenterImpl::AlphaBltSubPic(const CRect& windowRect, + const CRect& videoRect, + SubPicDesc* pTarget /*= nullptr*/, + const double videoStretchFactor /*= 1.0*/, + int xOffsetInPixels /*= 0*/, int yOffsetInPixels /*= 0*/) +{ + CComPtr pSubPic; + if (m_pSubPicQueue->LookupSubPic(m_rtNow, !IsRendering(), pSubPic)) { + CRect rcSource, rcDest; + + const CRenderersSettings& r = GetRenderersSettings(); + int yOffset = yOffsetInPixels + r.subPicVerticalShift; + if (SUCCEEDED(pSubPic->GetSourceAndDest(windowRect, videoRect, rcSource, rcDest, + videoStretchFactor, xOffsetInPixels, yOffset))) { + return pSubPic->AlphaBlt(rcSource, rcDest, pTarget); + } + } + + return E_FAIL; +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetVideoSize(CSize szVideo, CSize szAspectRatio /* = CSize(0, 0) */) +{ + if (szVideo.cx == 0 || szVideo.cy == 0) { + return; + } + + m_nativeVideoSize = szVideo; + m_aspectRatio = szAspectRatio; +} + +STDMETHODIMP_(SIZE) CSubPicAllocatorPresenterImpl::GetVideoSize(bool bCorrectAR) const +{ + CSize videoSize(GetVisibleVideoSize()); + + if (bCorrectAR && m_aspectRatio.cx > 0 && m_aspectRatio.cy > 0) { + videoSize.cx = (LONGLONG(videoSize.cy) * LONGLONG(m_aspectRatio.cx)) / LONGLONG(m_aspectRatio.cy); + } + + if (m_bDefaultVideoAngleSwitchAR) { + std::swap(videoSize.cx, videoSize.cy); + } + + return videoSize; +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetPosition(RECT w, RECT v) +{ + bool bWindowPosChanged = !!(m_windowRect != w); + bool bWindowSizeChanged = !!(m_windowRect.Size() != CRect(w).Size()); + bool bVideoRectChanged = !!(m_videoRect != v); + + m_windowRect = w; + m_videoRect = v; + + if (m_pAllocator && (bWindowPosChanged || bWindowSizeChanged || bVideoRectChanged)) { + if (m_windowRect.Width() != m_curSubtitleTextureSize.cx || m_windowRect.Height() != m_curSubtitleTextureSize.cy) { + int maxpixels = m_maxSubtitleTextureSize.cx * m_maxSubtitleTextureSize.cy; + if (m_windowRect.Width() * m_windowRect.Height() <= maxpixels) { + // use window size + m_curSubtitleTextureSize = CSize(m_windowRect.Width(), m_windowRect.Height()); + } else { + bool correct_ar = false; + if (m_maxSubtitleTextureSize.cx == 2560 && m_windowRect.Width() >= 3800 && m_windowRect.Width() <= 4096) { // not 3840, to handle a maximized window as well + m_curSubtitleTextureSize = CSize(m_windowRect.Width() / 2, m_windowRect.Height() / 2); + } else { + m_curSubtitleTextureSize = CSize(m_maxSubtitleTextureSize.cx, m_maxSubtitleTextureSize.cy); + correct_ar = true; + } + + if (correct_ar) { + double new_w = sqrt((uint64_t)m_curSubtitleTextureSize.cx * m_curSubtitleTextureSize.cy * m_windowRect.Width() / m_windowRect.Height()); + double new_h = sqrt((uint64_t)m_curSubtitleTextureSize.cx * m_curSubtitleTextureSize.cy * m_windowRect.Height() / m_windowRect.Width()); + m_curSubtitleTextureSize.cx = lround(new_w); + m_curSubtitleTextureSize.cy = lround(new_h); + } + } + } + + m_pAllocator->SetMaxTextureSize(m_curSubtitleTextureSize); + m_pAllocator->SetCurSize(m_windowRect.Size()); + m_pAllocator->SetCurVidRect(m_videoRect); + + if (m_pSubPicQueue) { + m_pSubPicQueue->Invalidate(); + } + } + + if (bWindowPosChanged || bVideoRectChanged || m_bOtherTransform) { + Paint(false); + m_bOtherTransform = false; + } +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetTime(REFERENCE_TIME rtNow) +{ + m_rtNow = rtNow - m_rtSubtitleDelay; + + if (m_pSubPicQueue) { + m_pSubPicQueue->SetTime(m_rtNow); + } +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetSubtitleDelay(int delayMs) +{ + REFERENCE_TIME delay = MILLISECONDS_TO_100NS_UNITS(delayMs); + if (m_rtSubtitleDelay != delay) { + REFERENCE_TIME oldDelay = m_rtSubtitleDelay; + m_rtSubtitleDelay = delay; + SetTime(m_rtNow + oldDelay); + Paint(false); + } +} + +STDMETHODIMP_(int) CSubPicAllocatorPresenterImpl::GetSubtitleDelay() const +{ + return (int)(m_rtSubtitleDelay / 10000); +} + +STDMETHODIMP_(double) CSubPicAllocatorPresenterImpl::GetFPS() const +{ + return m_fps; +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider) +{ + CAutoLock cAutoLock(&m_csSubPicProvider); + + m_pSubPicProvider = pSubPicProvider; + + if (m_pSubPicQueue) { + m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); + } + + if (m_pAllocator) { + m_pAllocator->SetCurSize(CSize(m_windowRect.Width(), m_windowRect.Height())); + m_pAllocator->SetCurVidRect(m_videoRect); + } + + Paint(false); +} + +STDMETHODIMP_(void) CSubPicAllocatorPresenterImpl::Invalidate(REFERENCE_TIME rtInvalidate) +{ + if (m_pSubPicQueue) { + m_pSubPicQueue->Invalidate(rtInvalidate); + } +} + +void CSubPicAllocatorPresenterImpl::Transform(CRect r, Vector v[4]) +{ + v[0] = Vector((float)r.left, (float)r.top, 0); + v[1] = Vector((float)r.right, (float)r.top, 0); + v[2] = Vector((float)r.left, (float)r.bottom, 0); + v[3] = Vector((float)r.right, (float)r.bottom, 0); + + Vector center((float)r.CenterPoint().x, (float)r.CenterPoint().y, 0); + int l = (int)(Vector((float)r.Size().cx, (float)r.Size().cy, 0).Length() * 1.5f) + 1; + + for (size_t i = 0; i < 4; i++) { + v[i] = m_xform << (v[i] - center); + v[i].z = v[i].z / l + 0.5f; + v[i].x /= v[i].z * 2; + v[i].y /= v[i].z * 2; + v[i] += center; + } +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetDefaultVideoAngle(Vector v) +{ + if (m_defaultVideoAngle != v) { + constexpr float pi_2 = float(M_PI_2); + + // In theory it should be a multiple of 90 + int zAnglePi2 = std::lround(v.z / pi_2); + //ASSERT(zAnglePi2 * pi_2 == v.z); + + // Normalize the Z angle + zAnglePi2 %= 4; + if (zAnglePi2 < 0) { + zAnglePi2 += 4; + } + v.z = zAnglePi2 * pi_2; + + // Check if the default rotation change the AR + m_bDefaultVideoAngleSwitchAR = (v.z == pi_2 || v.z == 3.0f * pi_2); + + m_defaultVideoAngle = v; + UpdateXForm(); + return S_OK; + } + return S_FALSE; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetVideoAngle(Vector v) +{ + if (m_videoAngle != v) { + m_videoAngle = v; + UpdateXForm(); + return S_OK; + } + return S_FALSE; +} + +void CSubPicAllocatorPresenterImpl::UpdateXForm() +{ + Vector v = m_defaultVideoAngle + m_videoAngle; + + auto normalizeAngle = [](float & rad) { + constexpr float twoPi = float(2.0 * M_PI); + + while (rad < 0.0f) { + rad += twoPi; + } + while (rad > twoPi) { + rad -= twoPi; + } + }; + + normalizeAngle(v.x); + normalizeAngle(v.y); + normalizeAngle(v.z); + + CSize AR = GetVideoSize(true); + float fARCorrection = m_bDefaultVideoAngleSwitchAR ? float(AR.cx) / AR.cy : 1.0f; + + m_xform = XForm(Ray(Vector(), v), Vector(1.0f / fARCorrection, fARCorrection, 1.0f), false); + + Paint(false); +} + +HRESULT CSubPicAllocatorPresenterImpl::CreateDIBFromSurfaceData(D3DSURFACE_DESC desc, D3DLOCKED_RECT r, BYTE* lpDib) const +{ + bool bNeedRotation = !IsEqual(m_defaultVideoAngle.z, 0.0f); + + BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)lpDib; + ZeroMemory(bih, sizeof(BITMAPINFOHEADER)); + bih->biSize = sizeof(BITMAPINFOHEADER); + bih->biWidth = desc.Width; + bih->biHeight = desc.Height; + bih->biBitCount = 32; + bih->biPlanes = 1; + bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount >> 3; + + UINT* pBits; + if (bNeedRotation) { + pBits = (UINT*)malloc(bih->biSizeImage); + if (!pBits) { + return E_OUTOFMEMORY; + } + } else { + pBits = (UINT*)(bih + 1); + } + + BitBltFromRGBToRGB(bih->biWidth, bih->biHeight, + (BYTE*)pBits, bih->biWidth * bih->biBitCount >> 3, bih->biBitCount, + (BYTE*)r.pBits + r.Pitch * (desc.Height - 1), -r.Pitch, 32); + + if (bNeedRotation) { + constexpr float pi_2 = float(M_PI_2); + + if (m_bDefaultVideoAngleSwitchAR) { + std::swap(bih->biWidth, bih->biHeight); + } + + std::function convCoordinates; + if (IsEqual(m_defaultVideoAngle.z, pi_2)) { + convCoordinates = [desc](UINT x, UINT y) { + return x * desc.Height + desc.Height - 1 - y; + }; + } else if (IsEqual(m_defaultVideoAngle.z, 2 * pi_2)) { + convCoordinates = [desc](UINT x, UINT y) { + return desc.Width - 1 - x + (desc.Height - 1 - y) * desc.Width; + }; + } else { + ASSERT(IsEqual(m_defaultVideoAngle.z, 3 * pi_2)); + convCoordinates = [desc](UINT x, UINT y) { + return (desc.Width - 1 - x) * desc.Height + y; + }; + } + + UINT* pBitsDest = (UINT*)(bih + 1); + for (UINT x = 0; x < desc.Width; x++) { + for (UINT y = 0; y < desc.Height; y++) { + pBitsDest[convCoordinates(x, y)] = pBits[x + y * desc.Width]; + } + } + + free(pBits); + } + + return S_OK; +} + +// ISubRenderOptions + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetBool(LPCSTR field, bool* value) +{ + CheckPointer(value, E_POINTER); + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetInt(LPCSTR field, int* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "supportedLevels")) { + if (CComQIPtr pEVR = (ISubPicAllocatorPresenter*)this) { + const CRenderersSettings& r = GetRenderersSettings(); + if (r.m_AdvRendSets.iEVROutputRange == 1) { + *value = 3; // TV preferred + } else { + *value = 2; // PC preferred + } + } else { + *value = 0; // PC only + } + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetSize(LPCSTR field, SIZE* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "originalVideoSize")) { + *value = GetVideoSize(false); + return S_OK; + } else if (!strcmp(field, "arAdjustedVideoSize")) { + *value = GetVideoSize(true); + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetRect(LPCSTR field, RECT* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "videoOutputRect") || !strcmp(field, "subtitleTargetRect")) { + if (m_videoRect.IsRectEmpty()) { + *value = m_windowRect; + } else { + value->left = 0; + value->top = 0; + value->right = m_videoRect.Width(); + value->bottom = m_videoRect.Height(); + } + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetUlonglong(LPCSTR field, ULONGLONG* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "frameRate")) { + *value = (REFERENCE_TIME)(10000000.0 / m_fps); + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetDouble(LPCSTR field, double* value) +{ + CheckPointer(value, E_POINTER); + if (!strcmp(field, "refreshRate")) { + *value = 1000.0 / m_refreshRate; + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetString(LPCSTR field, LPWSTR* value, int* chars) +{ + CheckPointer(value, E_POINTER); + CheckPointer(chars, E_POINTER); + CStringW ret = nullptr; + + if (!strcmp(field, "name")) { + ret = L"MPC-HC"; + } else if (!strcmp(field, "version")) { + ret = VersionInfo::GetVersionString(); + } else if (!strcmp(field, "yuvMatrix")) { + ret = L"None"; + + if (m_inputMediaType.IsValid() && m_inputMediaType.formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* pVIH2 = (VIDEOINFOHEADER2*)m_inputMediaType.pbFormat; + + if (pVIH2->dwControlFlags & AMCONTROL_COLORINFO_PRESENT) { + DXVA2_ExtendedFormat& flags = (DXVA2_ExtendedFormat&)pVIH2->dwControlFlags; + + ret = (flags.NominalRange == DXVA2_NominalRange_Normal) ? L"PC." : L"TV."; + + switch (flags.VideoTransferMatrix) { + case DXVA2_VideoTransferMatrix_BT601: + ret.Append(L"601"); + break; + case DXVA2_VideoTransferMatrix_BT709: + ret.Append(L"709"); + break; + case DXVA2_VideoTransferMatrix_SMPTE240M: + ret.Append(L"240M"); + break; + case 4: + ret.Append(L"2020"); + break; + default: + ret = L"None"; + break; + } + } + } + } + + if (!ret.IsEmpty()) { + int len = ret.GetLength(); + size_t sz = (len + 1) * sizeof(WCHAR); + LPWSTR buf = (LPWSTR)LocalAlloc(LPTR, sz); + + if (!buf) { + return E_OUTOFMEMORY; + } + + wcscpy_s(buf, len + 1, ret); + *chars = len; + *value = buf; + + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::GetBin(LPCSTR field, LPVOID* value, int* size) +{ + CheckPointer(value, E_POINTER); + CheckPointer(size, E_POINTER); + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetBool(LPCSTR field, bool value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetInt(LPCSTR field, int value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetSize(LPCSTR field, SIZE value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetRect(LPCSTR field, RECT value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetUlonglong(LPCSTR field, ULONGLONG value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetDouble(LPCSTR field, double value) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetString(LPCSTR field, LPWSTR value, int chars) +{ + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::SetBin(LPCSTR field, LPVOID value, int size) +{ + return E_INVALIDARG; +} + +// ISubRenderConsumer + +STDMETHODIMP CSubPicAllocatorPresenterImpl::Connect(ISubRenderProvider* subtitleRenderer) +{ + HRESULT hr = E_FAIL; + + if (m_pSubPicProvider) { + return hr; + } + + hr = subtitleRenderer->SetBool("combineBitmaps", true); + if (FAILED(hr)) { + return hr; + } + + if (CComQIPtr pSubConsumer = m_pSubPicQueue) { + hr = pSubConsumer->Connect(subtitleRenderer); + } else { + CComPtr pSubPicProvider = (ISubPicProvider*)DEBUG_NEW CXySubPicProvider(subtitleRenderer); + CComPtr pSubPicQueue = (ISubPicQueue*)DEBUG_NEW CXySubPicQueueNoThread(m_pAllocator, &hr); + + if (SUCCEEDED(hr)) { + pSubPicQueue->SetSubPicProvider(pSubPicProvider); + m_pSubPicProvider = pSubPicProvider; + m_pSubPicQueue = pSubPicQueue; + m_pAllocator->SetInverseAlpha(true); + } + } + + return hr; +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::Disconnect() +{ + m_pSubPicProvider = nullptr; + return m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); +} + +STDMETHODIMP CSubPicAllocatorPresenterImpl::DeliverFrame(REFERENCE_TIME start, REFERENCE_TIME stop, LPVOID context, ISubRenderFrame* subtitleFrame) +{ + HRESULT hr = E_FAIL; + + if (CComQIPtr pXyProvider = m_pSubPicProvider) { + hr = pXyProvider->DeliverFrame(start, stop, context, subtitleFrame); + } + + return hr; +} + +// ISubRenderConsumer2 + +STDMETHODIMP CSubPicAllocatorPresenterImpl::Clear(REFERENCE_TIME clearNewerThan /* = 0 */) +{ + return m_pSubPicQueue->Invalidate(clearNewerThan); +} diff --git a/src/SubPic/SubPicAllocatorPresenterImpl.h b/src/SubPic/SubPicAllocatorPresenterImpl.h index 053a71d72e4..8d0a964d30e 100644 --- a/src/SubPic/SubPicAllocatorPresenterImpl.h +++ b/src/SubPic/SubPicAllocatorPresenterImpl.h @@ -1,175 +1,175 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#pragma once - -#include -#include -#include -#include "ISubPic.h" -#include "CoordGeom.h" -#include "SubRenderIntf.h" -#include "ScreenUtil.h" - -class CSubPicAllocatorPresenterImpl - : public CUnknown - , public CCritSec - , public ISubPicAllocatorPresenter3 - , public ISubRenderConsumer2 -{ -private: - CCritSec m_csSubPicProvider; - -protected: - HWND m_hWnd; - REFERENCE_TIME m_rtSubtitleDelay; - - CSize m_maxSubtitleTextureSize; - CSize m_curSubtitleTextureSize; - CSize m_nativeVideoSize, m_aspectRatio; - CRect m_videoRect, m_windowRect; - bool m_bOtherTransform = false; - - REFERENCE_TIME m_rtNow = 0; - double m_fps = 25.0; - UINT m_refreshRate = 0; - - CMediaType m_inputMediaType; - - CComPtr m_pSubPicProvider; - CComPtr m_pAllocator; - CComPtr m_pSubPicQueue; - - bool m_bDeviceResetRequested; - bool m_bPendingResetDevice; - - void InitMaxSubtitleTextureSize(int maxSizeX, int maxSizeY, CSize largestScreen); - - HRESULT AlphaBltSubPic(const CRect& windowRect, - const CRect& videoRect, - SubPicDesc* pTarget = nullptr, - const double videoStretchFactor = 1.0, - int xOffsetInPixels = 0, int yOffsetInPixels = 0); - - void UpdateXForm(); - HRESULT CreateDIBFromSurfaceData(D3DSURFACE_DESC desc, D3DLOCKED_RECT r, BYTE* lpDib) const; - - Vector m_defaultVideoAngle, m_videoAngle; - bool m_bDefaultVideoAngleSwitchAR; - XForm m_xform; - void Transform(CRect r, Vector v[4]); - - bool m_bHookedNewSegment; - bool m_bHookedReceive; - -public: - CSubPicAllocatorPresenterImpl(HWND hWnd, HRESULT& hr, CString* _pError); - virtual ~CSubPicAllocatorPresenterImpl(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - STDMETHODIMP_(void) SetVideoSize(CSize szVideo, CSize szAspectRatio = CSize(0, 0)); - - // ISubPicAllocatorPresenter - - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer) PURE; - STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const; - STDMETHODIMP_(void) SetPosition(RECT w, RECT v); - STDMETHODIMP_(bool) Paint(bool bAll) PURE; - STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow); - STDMETHODIMP_(void) SetSubtitleDelay(int delayMs); - STDMETHODIMP_(int) GetSubtitleDelay() const; - STDMETHODIMP_(double) GetFPS() const; - STDMETHODIMP_(void) SetSubPicProvider(ISubPicProvider* pSubPicProvider); - STDMETHODIMP_(void) Invalidate(REFERENCE_TIME rtInvalidate = -1); - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size) { return E_NOTIMPL; } - STDMETHODIMP GetDisplayedImage(LPVOID* dibImage) { return E_NOTIMPL; } - STDMETHODIMP SetVideoAngle(Vector v); - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) { return E_NOTIMPL; } - STDMETHODIMP_(bool) ResetDevice() { return false; } - STDMETHODIMP_(bool) DisplayChange() { return false; } - STDMETHODIMP_(void) GetPosition(RECT* windowRect, RECT* videoRect) { *windowRect = m_windowRect; *videoRect = m_videoRect; } - STDMETHODIMP_(void) SetVideoMediaType(CMediaType input) { m_inputMediaType = input; } - - // ISubPicAllocatorPresenter2 - - STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) { - if (!bScreenSpace) { - return SetPixelShader(pSrcData, pTarget); - } - return E_NOTIMPL; - } - - STDMETHODIMP_(SIZE) GetVisibleVideoSize() const { - return m_nativeVideoSize; - } - - STDMETHODIMP SetIsRendering(bool bIsRendering) { return E_NOTIMPL; } - STDMETHODIMP_(bool) IsRendering() { return true; } - STDMETHODIMP SetDefaultVideoAngle(Vector v); - - // ISubPicAllocatorPresenter3 - - STDMETHODIMP SetRotation(int rotation) { return E_NOTIMPL; } - STDMETHODIMP_(int) GetRotation() { return 0; } - STDMETHODIMP SetFlip(bool flip) { return E_NOTIMPL; } - STDMETHODIMP_(bool) GetFlip() { return false; } - STDMETHODIMP GetVideoFrame(BYTE* lpDib, DWORD* size) { return E_NOTIMPL; } - STDMETHODIMP_(int) GetPixelShaderMode() { return 0; } - STDMETHODIMP ClearPixelShaders(int target) { return E_NOTIMPL; } - STDMETHODIMP AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) { return E_NOTIMPL; } - STDMETHODIMP_(bool) ResizeDevice() { return false; } - STDMETHODIMP_(bool) ToggleStats() { return false; } - - // ISubRenderOptions - - STDMETHODIMP GetBool(LPCSTR field, bool* value); - STDMETHODIMP GetInt(LPCSTR field, int* value); - STDMETHODIMP GetSize(LPCSTR field, SIZE* value); - STDMETHODIMP GetRect(LPCSTR field, RECT* value); - STDMETHODIMP GetUlonglong(LPCSTR field, ULONGLONG* value); - STDMETHODIMP GetDouble(LPCSTR field, double* value); - STDMETHODIMP GetString(LPCSTR field, LPWSTR* value, int* chars); - STDMETHODIMP GetBin(LPCSTR field, LPVOID* value, int* size); - STDMETHODIMP SetBool(LPCSTR field, bool value); - STDMETHODIMP SetInt(LPCSTR field, int value); - STDMETHODIMP SetSize(LPCSTR field, SIZE value); - STDMETHODIMP SetRect(LPCSTR field, RECT value); - STDMETHODIMP SetUlonglong(LPCSTR field, ULONGLONG value); - STDMETHODIMP SetDouble(LPCSTR field, double value); - STDMETHODIMP SetString(LPCSTR field, LPWSTR value, int chars); - STDMETHODIMP SetBin(LPCSTR field, LPVOID value, int size); - - // ISubRenderConsumer - - STDMETHODIMP GetMerit(ULONG* plMerit) { - CheckPointer(plMerit, E_POINTER); - *plMerit = 4 << 16; - return S_OK; - } - STDMETHODIMP Connect(ISubRenderProvider* subtitleRenderer); - STDMETHODIMP Disconnect(); - STDMETHODIMP DeliverFrame(REFERENCE_TIME start, REFERENCE_TIME stop, LPVOID context, ISubRenderFrame* subtitleFrame); - - // ISubRenderConsumer2 - - STDMETHODIMP Clear(REFERENCE_TIME clearNewerThan = 0); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#pragma once + +#include +#include +#include +#include "ISubPic.h" +#include "CoordGeom.h" +#include "SubRenderIntf.h" +#include "ScreenUtil.h" + +class CSubPicAllocatorPresenterImpl + : public CUnknown + , public CCritSec + , public ISubPicAllocatorPresenter3 + , public ISubRenderConsumer2 +{ +private: + CCritSec m_csSubPicProvider; + +protected: + HWND m_hWnd; + REFERENCE_TIME m_rtSubtitleDelay; + + CSize m_maxSubtitleTextureSize; + CSize m_curSubtitleTextureSize; + CSize m_nativeVideoSize, m_aspectRatio; + CRect m_videoRect, m_windowRect; + bool m_bOtherTransform = false; + + REFERENCE_TIME m_rtNow = 0; + double m_fps = 25.0; + UINT m_refreshRate = 0; + + CMediaType m_inputMediaType; + + CComPtr m_pSubPicProvider; + CComPtr m_pAllocator; + CComPtr m_pSubPicQueue; + + bool m_bDeviceResetRequested; + bool m_bPendingResetDevice; + + void InitMaxSubtitleTextureSize(int maxSizeX, int maxSizeY, CSize largestScreen); + + HRESULT AlphaBltSubPic(const CRect& windowRect, + const CRect& videoRect, + SubPicDesc* pTarget = nullptr, + const double videoStretchFactor = 1.0, + int xOffsetInPixels = 0, int yOffsetInPixels = 0); + + void UpdateXForm(); + HRESULT CreateDIBFromSurfaceData(D3DSURFACE_DESC desc, D3DLOCKED_RECT r, BYTE* lpDib) const; + + Vector m_defaultVideoAngle, m_videoAngle; + bool m_bDefaultVideoAngleSwitchAR; + XForm m_xform; + void Transform(CRect r, Vector v[4]); + + bool m_bHookedNewSegment; + bool m_bHookedReceive; + +public: + CSubPicAllocatorPresenterImpl(HWND hWnd, HRESULT& hr, CString* _pError); + virtual ~CSubPicAllocatorPresenterImpl(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + STDMETHODIMP_(void) SetVideoSize(CSize szVideo, CSize szAspectRatio = CSize(0, 0)); + + // ISubPicAllocatorPresenter + + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer) PURE; + STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const; + STDMETHODIMP_(void) SetPosition(RECT w, RECT v); + STDMETHODIMP_(bool) Paint(bool bAll) PURE; + STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow); + STDMETHODIMP_(void) SetSubtitleDelay(int delayMs); + STDMETHODIMP_(int) GetSubtitleDelay() const; + STDMETHODIMP_(double) GetFPS() const; + STDMETHODIMP_(void) SetSubPicProvider(ISubPicProvider* pSubPicProvider); + STDMETHODIMP_(void) Invalidate(REFERENCE_TIME rtInvalidate = -1); + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size) { return E_NOTIMPL; } + STDMETHODIMP GetDisplayedImage(LPVOID* dibImage) { return E_NOTIMPL; } + STDMETHODIMP SetVideoAngle(Vector v); + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) { return E_NOTIMPL; } + STDMETHODIMP_(bool) ResetDevice() { return false; } + STDMETHODIMP_(bool) DisplayChange() { return false; } + STDMETHODIMP_(void) GetPosition(RECT* windowRect, RECT* videoRect) { *windowRect = m_windowRect; *videoRect = m_videoRect; } + STDMETHODIMP_(void) SetVideoMediaType(CMediaType input) { m_inputMediaType = input; } + + // ISubPicAllocatorPresenter2 + + STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) { + if (!bScreenSpace) { + return SetPixelShader(pSrcData, pTarget); + } + return E_NOTIMPL; + } + + STDMETHODIMP_(SIZE) GetVisibleVideoSize() const { + return m_nativeVideoSize; + } + + STDMETHODIMP SetIsRendering(bool bIsRendering) { return E_NOTIMPL; } + STDMETHODIMP_(bool) IsRendering() { return true; } + STDMETHODIMP SetDefaultVideoAngle(Vector v); + + // ISubPicAllocatorPresenter3 + + STDMETHODIMP SetRotation(int rotation) { return E_NOTIMPL; } + STDMETHODIMP_(int) GetRotation() { return 0; } + STDMETHODIMP SetFlip(bool flip) { return E_NOTIMPL; } + STDMETHODIMP_(bool) GetFlip() { return false; } + STDMETHODIMP GetVideoFrame(BYTE* lpDib, DWORD* size) { return E_NOTIMPL; } + STDMETHODIMP_(int) GetPixelShaderMode() { return 0; } + STDMETHODIMP ClearPixelShaders(int target) { return E_NOTIMPL; } + STDMETHODIMP AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) { return E_NOTIMPL; } + STDMETHODIMP_(bool) ResizeDevice() { return false; } + STDMETHODIMP_(bool) ToggleStats() { return false; } + + // ISubRenderOptions + + STDMETHODIMP GetBool(LPCSTR field, bool* value); + STDMETHODIMP GetInt(LPCSTR field, int* value); + STDMETHODIMP GetSize(LPCSTR field, SIZE* value); + STDMETHODIMP GetRect(LPCSTR field, RECT* value); + STDMETHODIMP GetUlonglong(LPCSTR field, ULONGLONG* value); + STDMETHODIMP GetDouble(LPCSTR field, double* value); + STDMETHODIMP GetString(LPCSTR field, LPWSTR* value, int* chars); + STDMETHODIMP GetBin(LPCSTR field, LPVOID* value, int* size); + STDMETHODIMP SetBool(LPCSTR field, bool value); + STDMETHODIMP SetInt(LPCSTR field, int value); + STDMETHODIMP SetSize(LPCSTR field, SIZE value); + STDMETHODIMP SetRect(LPCSTR field, RECT value); + STDMETHODIMP SetUlonglong(LPCSTR field, ULONGLONG value); + STDMETHODIMP SetDouble(LPCSTR field, double value); + STDMETHODIMP SetString(LPCSTR field, LPWSTR value, int chars); + STDMETHODIMP SetBin(LPCSTR field, LPVOID value, int size); + + // ISubRenderConsumer + + STDMETHODIMP GetMerit(ULONG* plMerit) { + CheckPointer(plMerit, E_POINTER); + *plMerit = 4 << 16; + return S_OK; + } + STDMETHODIMP Connect(ISubRenderProvider* subtitleRenderer); + STDMETHODIMP Disconnect(); + STDMETHODIMP DeliverFrame(REFERENCE_TIME start, REFERENCE_TIME stop, LPVOID context, ISubRenderFrame* subtitleFrame); + + // ISubRenderConsumer2 + + STDMETHODIMP Clear(REFERENCE_TIME clearNewerThan = 0); +}; diff --git a/src/SubPic/SubPicImpl.cpp b/src/SubPic/SubPicImpl.cpp index f49adaba4a8..1cafbf88986 100644 --- a/src/SubPic/SubPicImpl.cpp +++ b/src/SubPic/SubPicImpl.cpp @@ -1,434 +1,434 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "SubPicImpl.h" -#include "../DSUtil/DSUtil.h" - -#include "mpc-hc_config.h" - -#if !TRACE_SUBTITLES -#define TRACE(...) -#endif - -// -// CSubPicImpl -// - -CSubPicImpl::CSubPicImpl() - : CUnknown(NAME("CSubPicImpl"), nullptr) - , m_rtStart(0) - , m_rtStop(0) - , m_rtSegmentStart(0) - , m_rtSegmentStop(0) - , m_rcDirty(0, 0, 0, 0) - , m_maxsize(0, 0) - , m_size(0, 0) - , m_vidrect(0, 0, 0, 0) - , m_virtualTextureSize(0, 0) - , m_virtualTextureTopLeft(0, 0) - , m_bInvAlpha(false) - , m_relativeTo(WINDOW) -{ -} - -STDMETHODIMP CSubPicImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(ISubPic) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPic - -STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetStart() const -{ - return m_rtStart; -} - -STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetStop() const -{ - return m_rtStop; -} - -STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetSegmentStart() const -{ - return m_rtSegmentStart >= 0 ? m_rtSegmentStart : m_rtStart; -} - -STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetSegmentStop() const -{ - return m_rtSegmentStop >= 0 ? m_rtSegmentStop : m_rtStop; -} - -STDMETHODIMP_(void) CSubPicImpl::SetSegmentStart(REFERENCE_TIME rtStart) -{ - m_rtSegmentStart = rtStart; -} - -STDMETHODIMP_(void) CSubPicImpl::SetSegmentStop(REFERENCE_TIME rtStop) -{ - m_rtSegmentStop = rtStop; -} - -STDMETHODIMP_(void) CSubPicImpl::SetStart(REFERENCE_TIME rtStart) -{ - m_rtStart = rtStart; -} - -STDMETHODIMP_(void) CSubPicImpl::SetStop(REFERENCE_TIME rtStop) -{ - m_rtStop = rtStop; -} - -STDMETHODIMP CSubPicImpl::CopyTo(ISubPic* pSubPic) -{ - CheckPointer(pSubPic, E_POINTER); - - pSubPic->SetStart(m_rtStart); - pSubPic->SetStop(m_rtStop); - pSubPic->SetSegmentStart(m_rtSegmentStart); - pSubPic->SetSegmentStop(m_rtSegmentStop); - pSubPic->SetDirtyRect(m_rcDirty); - pSubPic->SetSize(m_size, m_vidrect); - pSubPic->SetVirtualTextureSize(m_virtualTextureSize, m_virtualTextureTopLeft); - pSubPic->SetInverseAlpha(m_bInvAlpha); - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::GetDirtyRect(RECT* pDirtyRect) const -{ - CheckPointer(pDirtyRect, E_POINTER); - - *pDirtyRect = m_rcDirty; - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::GetSourceAndDest(RECT rcWindow, RECT rcVideo, - RECT* pRcSource, RECT* pRcDest, - const double videoStretchFactor /*= 1.0*/, - int xOffsetInPixels /*= 0*/, int yOffsetInPixels /*= 0*/) const -{ - CheckPointer(pRcSource, E_POINTER); - CheckPointer(pRcDest, E_POINTER); - - if (m_size.cx > 0 && m_size.cy > 0 && m_rcDirty.Height() > 0) { - CRect videoRect(rcVideo); - CRect windowRect(rcWindow); - - CRect originalDirtyRect = m_rcDirty; - *pRcSource = originalDirtyRect; - originalDirtyRect.OffsetRect(m_virtualTextureTopLeft); - - CRect targetDirtyRect; - - // check if scaling is needed - if (videoRect.Size() != windowRect.Size() || videoRect.Size() != m_virtualTextureSize) { - if (m_relativeTo == BEST_FIT && m_virtualTextureSize.cx > 720 && videoStretchFactor == 1.0) { - CRect visibleRect; - visibleRect.top = videoRect.top > windowRect.top ? (videoRect.top > windowRect.bottom ? windowRect.bottom : videoRect.top) : windowRect.top; - visibleRect.bottom = videoRect.bottom < windowRect.bottom ? (videoRect.bottom < windowRect.top ? windowRect.top : videoRect.bottom) : windowRect.bottom; - visibleRect.left = videoRect.left > windowRect.left ? (videoRect.left > windowRect.right ? windowRect.right : videoRect.left) : windowRect.left; - visibleRect.right = videoRect.right < windowRect.right ? (videoRect.right < windowRect.left ? windowRect.left : videoRect.right) : windowRect.right; - if (visibleRect.Width() <= 0 || visibleRect.Height() <= 0) { - visibleRect = windowRect; - ASSERT(false); - } - CPoint offset(0, 0); - double scaleFactor; - double subtitleAR = double(m_virtualTextureSize.cx) / m_virtualTextureSize.cy; - double visibleAR = double(visibleRect.Width()) / visibleRect.Height(); - double vertical_stretch = 1.0; - if (visibleAR * 2 - subtitleAR < 0.01) { - // some PGS can be encoded with resolution at half height - vertical_stretch = 2.0; - subtitleAR /= 2.0; - } - - if (visibleAR == subtitleAR) { - // exact same AR - scaleFactor = double(visibleRect.Width()) / m_virtualTextureSize.cx; - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(visibleRect.TopLeft()); - } else if (visibleAR > subtitleAR) { - // video is cropped in height - scaleFactor = double(visibleRect.Width()) / m_virtualTextureSize.cx; - int extraheight = m_virtualTextureSize.cy * scaleFactor * vertical_stretch - visibleRect.Height(); - CRect expandedRect = visibleRect; - expandedRect.top -= extraheight / 2; - expandedRect.bottom += extraheight - extraheight / 2; - offset.x = expandedRect.left; - offset.y = expandedRect.top; - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(offset); - - if (expandedRect.left >= windowRect.left && expandedRect.top >= windowRect.top && expandedRect.right <= windowRect.right && expandedRect.bottom <= windowRect.bottom) { - // expanded fits in window - } else { - if (targetDirtyRect.left >= windowRect.left && targetDirtyRect.top >= windowRect.top && targetDirtyRect.right <= windowRect.right && targetDirtyRect.bottom <= windowRect.bottom) { - // dirty rect fits in window - } else { - // does not fit yet, rescale based on available window height - scaleFactor = double(windowRect.Height()) / m_virtualTextureSize.cy / vertical_stretch; - offset.x = lround((windowRect.Width() - scaleFactor * m_virtualTextureSize.cx) / 2.0); - offset.y = 0; - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(offset); - } - } - } else { - // video is cropped in width - scaleFactor = double(visibleRect.Height()) / m_virtualTextureSize.cy / vertical_stretch; - int extrawidth = m_virtualTextureSize.cx * scaleFactor - visibleRect.Width(); - CRect expandedRect = visibleRect; - expandedRect.left -= extrawidth / 2; - expandedRect.right += extrawidth - extrawidth / 2; - offset.x = expandedRect.left; - offset.y = expandedRect.top; - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(offset); - - if (expandedRect.left >= windowRect.left && expandedRect.top >= windowRect.top && expandedRect.right <= windowRect.right && expandedRect.bottom <= windowRect.bottom) { - // expanded fits in window - } else { - if (targetDirtyRect.left >= windowRect.left && targetDirtyRect.top >= windowRect.top && targetDirtyRect.right <= windowRect.right && targetDirtyRect.bottom <= windowRect.bottom) { - // dirty rect fits in window - } else { - // does not fit yet, rescale based on available window width - scaleFactor = double(windowRect.Width()) / m_virtualTextureSize.cx; - offset.x = 0; - offset.y = lround((windowRect.Height() - scaleFactor * m_virtualTextureSize.cy * vertical_stretch) / 2.0); - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); - targetDirtyRect.OffsetRect(offset); - } - } - } - } else { - CRect rcTarget = (m_relativeTo == WINDOW) ? windowRect : videoRect; - CSize szTarget = rcTarget.Size(); - double scaleX = double(szTarget.cx) / m_virtualTextureSize.cx; - double scaleY = double(szTarget.cy) / m_virtualTextureSize.cy; - - targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleX), lround(originalDirtyRect.top * scaleY), lround(originalDirtyRect.right * scaleX), lround(originalDirtyRect.bottom * scaleY)); - targetDirtyRect.OffsetRect(rcTarget.TopLeft()); - } - } else { - // no scaling needed - targetDirtyRect = originalDirtyRect; - } - - if (videoStretchFactor != 1.0) { - ASSERT(FALSE); - // FIXME: when is videoStretchFactor not equal to 1.0? Test that situation. Only madvr might possibly use it. Our own renderers do not. - LONG stretch = lround(targetDirtyRect.Width() * (1.0 - 1.0 / videoStretchFactor) / 2.0); - targetDirtyRect.left += stretch; - targetDirtyRect.right -= stretch; - } - - targetDirtyRect.OffsetRect(CPoint(xOffsetInPixels, yOffsetInPixels)); - - *pRcDest = targetDirtyRect; - return S_OK; - } - - return E_INVALIDARG; -} - -STDMETHODIMP CSubPicImpl::SetDirtyRect(const RECT* pDirtyRect) -{ - CheckPointer(pDirtyRect, E_POINTER); - - m_rcDirty = *pDirtyRect; - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::GetMaxSize(SIZE* pMaxSize) const -{ - CheckPointer(pMaxSize, E_POINTER); - - *pMaxSize = m_maxsize; - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::SetSize(SIZE size, RECT vidrect) -{ - m_size = size; - if (m_size.cx > m_maxsize.cx) { - m_size.cy = MulDiv(m_size.cy, m_maxsize.cx, m_size.cx); - m_size.cx = m_maxsize.cx; - } - if (m_size.cy > m_maxsize.cy) { - m_size.cx = MulDiv(m_size.cx, m_maxsize.cy, m_size.cy); - m_size.cy = m_maxsize.cy; - } - m_virtualTextureSize = m_size; - - m_vidrect = vidrect; - if (m_size.cx != size.cx || m_size.cy != size.cy) { - m_vidrect.top = MulDiv(m_vidrect.top, m_size.cx, size.cx); - m_vidrect.bottom = MulDiv(m_vidrect.bottom, m_size.cx, size.cx); - m_vidrect.left = MulDiv(m_vidrect.left, m_size.cy, size.cy); - m_vidrect.right = MulDiv(m_vidrect.right, m_size.cy, size.cy); - } - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::SetVirtualTextureSize(const SIZE pSize, const POINT pTopLeft) -{ - m_virtualTextureSize.SetSize(pSize.cx, pSize.cy); - m_virtualTextureTopLeft.SetPoint(pTopLeft.x, pTopLeft.y); - - return S_OK; -} - -STDMETHODIMP_(void) CSubPicImpl::SetInverseAlpha(bool bInverted) -{ - m_bInvAlpha = bInverted; -} - -STDMETHODIMP CSubPicImpl::GetRelativeTo(RelativeTo* pRelativeTo) const -{ - CheckPointer(pRelativeTo, E_POINTER); - - *pRelativeTo = m_relativeTo; - - return S_OK; -} - -STDMETHODIMP CSubPicImpl::SetRelativeTo(RelativeTo relativeTo) -{ - m_relativeTo = relativeTo; - - return S_OK; -} - -// -// ISubPicAllocatorImpl -// - -CSubPicAllocatorImpl::CSubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly) - : CUnknown(NAME("ISubPicAllocatorImpl"), nullptr) - , m_cursize(cursize) - , m_fDynamicWriteOnly(fDynamicWriteOnly) -{ - m_curvidrect = CRect(CPoint(0, 0), m_cursize); -} - -STDMETHODIMP CSubPicAllocatorImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(ISubPicAllocator) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPicAllocator - -STDMETHODIMP CSubPicAllocatorImpl::SetCurSize(SIZE cursize) -{ -#if DEBUG_OVERRIDE_TEXTURE_SIZE - cursize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); -#endif - if (m_cursize != cursize) { - TRACE(_T("CSubPicAllocatorImpl::SetCurSize: %dx%d\n"), cursize.cx, cursize.cy); - m_cursize = cursize; - FreeStatic(); - } - return S_OK; -} - -STDMETHODIMP CSubPicAllocatorImpl::SetCurVidRect(RECT curvidrect) -{ -#if DEBUG_OVERRIDE_TEXTURE_SIZE - m_curvidrect = CRect(CPoint(0, 0), CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT)); -#else - m_curvidrect = curvidrect; -#endif - return S_OK; -} - -STDMETHODIMP CSubPicAllocatorImpl::GetStatic(ISubPic** ppSubPic) -{ - CheckPointer(ppSubPic, E_POINTER); - - { - CAutoLock cAutoLock(&m_staticLock); - - if (!m_pStatic) { - if (!Alloc(true, &m_pStatic) || !m_pStatic) { - TRACE(_T("CSubPicAllocatorImpl::GetStatic failed\n")); - return E_OUTOFMEMORY; - } - } - - *ppSubPic = m_pStatic; - } - - (*ppSubPic)->AddRef(); - (*ppSubPic)->SetSize(m_cursize, m_curvidrect); - - return S_OK; -} - -STDMETHODIMP CSubPicAllocatorImpl::AllocDynamic(ISubPic** ppSubPic) -{ - CheckPointer(ppSubPic, E_POINTER); - - if (!Alloc(false, ppSubPic) || !*ppSubPic) { - return E_OUTOFMEMORY; - } - - (*ppSubPic)->SetSize(m_cursize, m_curvidrect); - - return S_OK; -} - -STDMETHODIMP_(bool) CSubPicAllocatorImpl::IsDynamicWriteOnly() const -{ - return m_fDynamicWriteOnly; -} - -STDMETHODIMP CSubPicAllocatorImpl::ChangeDevice(IUnknown* pDev) -{ - return FreeStatic(); -} - -STDMETHODIMP CSubPicAllocatorImpl::FreeStatic() -{ - CAutoLock cAutoLock(&m_staticLock); - if (m_pStatic) { - m_pStatic.Release(); - } - return S_OK; -} - -STDMETHODIMP_(void) CSubPicAllocatorImpl::SetInverseAlpha(bool bInverted) -{ - m_bInvAlpha = bInverted; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "SubPicImpl.h" +#include "../DSUtil/DSUtil.h" + +#include "mpc-hc_config.h" + +#if !TRACE_SUBTITLES +#define TRACE(...) +#endif + +// +// CSubPicImpl +// + +CSubPicImpl::CSubPicImpl() + : CUnknown(NAME("CSubPicImpl"), nullptr) + , m_rtStart(0) + , m_rtStop(0) + , m_rtSegmentStart(0) + , m_rtSegmentStop(0) + , m_rcDirty(0, 0, 0, 0) + , m_maxsize(0, 0) + , m_size(0, 0) + , m_vidrect(0, 0, 0, 0) + , m_virtualTextureSize(0, 0) + , m_virtualTextureTopLeft(0, 0) + , m_bInvAlpha(false) + , m_relativeTo(WINDOW) +{ +} + +STDMETHODIMP CSubPicImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(ISubPic) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPic + +STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetStart() const +{ + return m_rtStart; +} + +STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetStop() const +{ + return m_rtStop; +} + +STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetSegmentStart() const +{ + return m_rtSegmentStart >= 0 ? m_rtSegmentStart : m_rtStart; +} + +STDMETHODIMP_(REFERENCE_TIME) CSubPicImpl::GetSegmentStop() const +{ + return m_rtSegmentStop >= 0 ? m_rtSegmentStop : m_rtStop; +} + +STDMETHODIMP_(void) CSubPicImpl::SetSegmentStart(REFERENCE_TIME rtStart) +{ + m_rtSegmentStart = rtStart; +} + +STDMETHODIMP_(void) CSubPicImpl::SetSegmentStop(REFERENCE_TIME rtStop) +{ + m_rtSegmentStop = rtStop; +} + +STDMETHODIMP_(void) CSubPicImpl::SetStart(REFERENCE_TIME rtStart) +{ + m_rtStart = rtStart; +} + +STDMETHODIMP_(void) CSubPicImpl::SetStop(REFERENCE_TIME rtStop) +{ + m_rtStop = rtStop; +} + +STDMETHODIMP CSubPicImpl::CopyTo(ISubPic* pSubPic) +{ + CheckPointer(pSubPic, E_POINTER); + + pSubPic->SetStart(m_rtStart); + pSubPic->SetStop(m_rtStop); + pSubPic->SetSegmentStart(m_rtSegmentStart); + pSubPic->SetSegmentStop(m_rtSegmentStop); + pSubPic->SetDirtyRect(m_rcDirty); + pSubPic->SetSize(m_size, m_vidrect); + pSubPic->SetVirtualTextureSize(m_virtualTextureSize, m_virtualTextureTopLeft); + pSubPic->SetInverseAlpha(m_bInvAlpha); + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::GetDirtyRect(RECT* pDirtyRect) const +{ + CheckPointer(pDirtyRect, E_POINTER); + + *pDirtyRect = m_rcDirty; + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::GetSourceAndDest(RECT rcWindow, RECT rcVideo, + RECT* pRcSource, RECT* pRcDest, + const double videoStretchFactor /*= 1.0*/, + int xOffsetInPixels /*= 0*/, int yOffsetInPixels /*= 0*/) const +{ + CheckPointer(pRcSource, E_POINTER); + CheckPointer(pRcDest, E_POINTER); + + if (m_size.cx > 0 && m_size.cy > 0 && m_rcDirty.Height() > 0) { + CRect videoRect(rcVideo); + CRect windowRect(rcWindow); + + CRect originalDirtyRect = m_rcDirty; + *pRcSource = originalDirtyRect; + originalDirtyRect.OffsetRect(m_virtualTextureTopLeft); + + CRect targetDirtyRect; + + // check if scaling is needed + if (videoRect.Size() != windowRect.Size() || videoRect.Size() != m_virtualTextureSize) { + if (m_relativeTo == BEST_FIT && m_virtualTextureSize.cx > 720 && videoStretchFactor == 1.0) { + CRect visibleRect; + visibleRect.top = videoRect.top > windowRect.top ? (videoRect.top > windowRect.bottom ? windowRect.bottom : videoRect.top) : windowRect.top; + visibleRect.bottom = videoRect.bottom < windowRect.bottom ? (videoRect.bottom < windowRect.top ? windowRect.top : videoRect.bottom) : windowRect.bottom; + visibleRect.left = videoRect.left > windowRect.left ? (videoRect.left > windowRect.right ? windowRect.right : videoRect.left) : windowRect.left; + visibleRect.right = videoRect.right < windowRect.right ? (videoRect.right < windowRect.left ? windowRect.left : videoRect.right) : windowRect.right; + if (visibleRect.Width() <= 0 || visibleRect.Height() <= 0) { + visibleRect = windowRect; + ASSERT(false); + } + CPoint offset(0, 0); + double scaleFactor; + double subtitleAR = double(m_virtualTextureSize.cx) / m_virtualTextureSize.cy; + double visibleAR = double(visibleRect.Width()) / visibleRect.Height(); + double vertical_stretch = 1.0; + if (visibleAR * 2 - subtitleAR < 0.01) { + // some PGS can be encoded with resolution at half height + vertical_stretch = 2.0; + subtitleAR /= 2.0; + } + + if (visibleAR == subtitleAR) { + // exact same AR + scaleFactor = double(visibleRect.Width()) / m_virtualTextureSize.cx; + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(visibleRect.TopLeft()); + } else if (visibleAR > subtitleAR) { + // video is cropped in height + scaleFactor = double(visibleRect.Width()) / m_virtualTextureSize.cx; + int extraheight = m_virtualTextureSize.cy * scaleFactor * vertical_stretch - visibleRect.Height(); + CRect expandedRect = visibleRect; + expandedRect.top -= extraheight / 2; + expandedRect.bottom += extraheight - extraheight / 2; + offset.x = expandedRect.left; + offset.y = expandedRect.top; + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(offset); + + if (expandedRect.left >= windowRect.left && expandedRect.top >= windowRect.top && expandedRect.right <= windowRect.right && expandedRect.bottom <= windowRect.bottom) { + // expanded fits in window + } else { + if (targetDirtyRect.left >= windowRect.left && targetDirtyRect.top >= windowRect.top && targetDirtyRect.right <= windowRect.right && targetDirtyRect.bottom <= windowRect.bottom) { + // dirty rect fits in window + } else { + // does not fit yet, rescale based on available window height + scaleFactor = double(windowRect.Height()) / m_virtualTextureSize.cy / vertical_stretch; + offset.x = lround((windowRect.Width() - scaleFactor * m_virtualTextureSize.cx) / 2.0); + offset.y = 0; + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(offset); + } + } + } else { + // video is cropped in width + scaleFactor = double(visibleRect.Height()) / m_virtualTextureSize.cy / vertical_stretch; + int extrawidth = m_virtualTextureSize.cx * scaleFactor - visibleRect.Width(); + CRect expandedRect = visibleRect; + expandedRect.left -= extrawidth / 2; + expandedRect.right += extrawidth - extrawidth / 2; + offset.x = expandedRect.left; + offset.y = expandedRect.top; + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(offset); + + if (expandedRect.left >= windowRect.left && expandedRect.top >= windowRect.top && expandedRect.right <= windowRect.right && expandedRect.bottom <= windowRect.bottom) { + // expanded fits in window + } else { + if (targetDirtyRect.left >= windowRect.left && targetDirtyRect.top >= windowRect.top && targetDirtyRect.right <= windowRect.right && targetDirtyRect.bottom <= windowRect.bottom) { + // dirty rect fits in window + } else { + // does not fit yet, rescale based on available window width + scaleFactor = double(windowRect.Width()) / m_virtualTextureSize.cx; + offset.x = 0; + offset.y = lround((windowRect.Height() - scaleFactor * m_virtualTextureSize.cy * vertical_stretch) / 2.0); + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleFactor), lround(originalDirtyRect.top * scaleFactor * vertical_stretch), lround(originalDirtyRect.right * scaleFactor), lround(originalDirtyRect.bottom * scaleFactor * vertical_stretch)); + targetDirtyRect.OffsetRect(offset); + } + } + } + } else { + CRect rcTarget = (m_relativeTo == WINDOW) ? windowRect : videoRect; + CSize szTarget = rcTarget.Size(); + double scaleX = double(szTarget.cx) / m_virtualTextureSize.cx; + double scaleY = double(szTarget.cy) / m_virtualTextureSize.cy; + + targetDirtyRect = CRect(lround(originalDirtyRect.left * scaleX), lround(originalDirtyRect.top * scaleY), lround(originalDirtyRect.right * scaleX), lround(originalDirtyRect.bottom * scaleY)); + targetDirtyRect.OffsetRect(rcTarget.TopLeft()); + } + } else { + // no scaling needed + targetDirtyRect = originalDirtyRect; + } + + if (videoStretchFactor != 1.0) { + ASSERT(FALSE); + // FIXME: when is videoStretchFactor not equal to 1.0? Test that situation. Only madvr might possibly use it. Our own renderers do not. + LONG stretch = lround(targetDirtyRect.Width() * (1.0 - 1.0 / videoStretchFactor) / 2.0); + targetDirtyRect.left += stretch; + targetDirtyRect.right -= stretch; + } + + targetDirtyRect.OffsetRect(CPoint(xOffsetInPixels, yOffsetInPixels)); + + *pRcDest = targetDirtyRect; + return S_OK; + } + + return E_INVALIDARG; +} + +STDMETHODIMP CSubPicImpl::SetDirtyRect(const RECT* pDirtyRect) +{ + CheckPointer(pDirtyRect, E_POINTER); + + m_rcDirty = *pDirtyRect; + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::GetMaxSize(SIZE* pMaxSize) const +{ + CheckPointer(pMaxSize, E_POINTER); + + *pMaxSize = m_maxsize; + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::SetSize(SIZE size, RECT vidrect) +{ + m_size = size; + if (m_size.cx > m_maxsize.cx) { + m_size.cy = MulDiv(m_size.cy, m_maxsize.cx, m_size.cx); + m_size.cx = m_maxsize.cx; + } + if (m_size.cy > m_maxsize.cy) { + m_size.cx = MulDiv(m_size.cx, m_maxsize.cy, m_size.cy); + m_size.cy = m_maxsize.cy; + } + m_virtualTextureSize = m_size; + + m_vidrect = vidrect; + if (m_size.cx != size.cx || m_size.cy != size.cy) { + m_vidrect.top = MulDiv(m_vidrect.top, m_size.cx, size.cx); + m_vidrect.bottom = MulDiv(m_vidrect.bottom, m_size.cx, size.cx); + m_vidrect.left = MulDiv(m_vidrect.left, m_size.cy, size.cy); + m_vidrect.right = MulDiv(m_vidrect.right, m_size.cy, size.cy); + } + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::SetVirtualTextureSize(const SIZE pSize, const POINT pTopLeft) +{ + m_virtualTextureSize.SetSize(pSize.cx, pSize.cy); + m_virtualTextureTopLeft.SetPoint(pTopLeft.x, pTopLeft.y); + + return S_OK; +} + +STDMETHODIMP_(void) CSubPicImpl::SetInverseAlpha(bool bInverted) +{ + m_bInvAlpha = bInverted; +} + +STDMETHODIMP CSubPicImpl::GetRelativeTo(RelativeTo* pRelativeTo) const +{ + CheckPointer(pRelativeTo, E_POINTER); + + *pRelativeTo = m_relativeTo; + + return S_OK; +} + +STDMETHODIMP CSubPicImpl::SetRelativeTo(RelativeTo relativeTo) +{ + m_relativeTo = relativeTo; + + return S_OK; +} + +// +// ISubPicAllocatorImpl +// + +CSubPicAllocatorImpl::CSubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly) + : CUnknown(NAME("ISubPicAllocatorImpl"), nullptr) + , m_cursize(cursize) + , m_fDynamicWriteOnly(fDynamicWriteOnly) +{ + m_curvidrect = CRect(CPoint(0, 0), m_cursize); +} + +STDMETHODIMP CSubPicAllocatorImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(ISubPicAllocator) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicAllocator + +STDMETHODIMP CSubPicAllocatorImpl::SetCurSize(SIZE cursize) +{ +#if DEBUG_OVERRIDE_TEXTURE_SIZE + cursize = CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT); +#endif + if (m_cursize != cursize) { + TRACE(_T("CSubPicAllocatorImpl::SetCurSize: %dx%d\n"), cursize.cx, cursize.cy); + m_cursize = cursize; + FreeStatic(); + } + return S_OK; +} + +STDMETHODIMP CSubPicAllocatorImpl::SetCurVidRect(RECT curvidrect) +{ +#if DEBUG_OVERRIDE_TEXTURE_SIZE + m_curvidrect = CRect(CPoint(0, 0), CSize(DEBUG_OVERRIDE_TEXTURE_SIZE_WIDTH, DEBUG_OVERRIDE_TEXTURE_SIZE_HEIGHT)); +#else + m_curvidrect = curvidrect; +#endif + return S_OK; +} + +STDMETHODIMP CSubPicAllocatorImpl::GetStatic(ISubPic** ppSubPic) +{ + CheckPointer(ppSubPic, E_POINTER); + + { + CAutoLock cAutoLock(&m_staticLock); + + if (!m_pStatic) { + if (!Alloc(true, &m_pStatic) || !m_pStatic) { + TRACE(_T("CSubPicAllocatorImpl::GetStatic failed\n")); + return E_OUTOFMEMORY; + } + } + + *ppSubPic = m_pStatic; + } + + (*ppSubPic)->AddRef(); + (*ppSubPic)->SetSize(m_cursize, m_curvidrect); + + return S_OK; +} + +STDMETHODIMP CSubPicAllocatorImpl::AllocDynamic(ISubPic** ppSubPic) +{ + CheckPointer(ppSubPic, E_POINTER); + + if (!Alloc(false, ppSubPic) || !*ppSubPic) { + return E_OUTOFMEMORY; + } + + (*ppSubPic)->SetSize(m_cursize, m_curvidrect); + + return S_OK; +} + +STDMETHODIMP_(bool) CSubPicAllocatorImpl::IsDynamicWriteOnly() const +{ + return m_fDynamicWriteOnly; +} + +STDMETHODIMP CSubPicAllocatorImpl::ChangeDevice(IUnknown* pDev) +{ + return FreeStatic(); +} + +STDMETHODIMP CSubPicAllocatorImpl::FreeStatic() +{ + CAutoLock cAutoLock(&m_staticLock); + if (m_pStatic) { + m_pStatic.Release(); + } + return S_OK; +} + +STDMETHODIMP_(void) CSubPicAllocatorImpl::SetInverseAlpha(bool bInverted) +{ + m_bInvAlpha = bInverted; +} diff --git a/src/SubPic/SubPicImpl.h b/src/SubPic/SubPicImpl.h index 4e85b7e51e2..11b96973e29 100644 --- a/src/SubPic/SubPicImpl.h +++ b/src/SubPic/SubPicImpl.h @@ -1,145 +1,145 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "ISubPic.h" - -class CSubPicImpl : public CUnknown, public ISubPic -{ -protected: - REFERENCE_TIME m_rtStart, m_rtStop; - REFERENCE_TIME m_rtSegmentStart, m_rtSegmentStop; - CRect m_rcDirty; - CSize m_maxsize; - CSize m_size; - CRect m_vidrect; - CSize m_virtualTextureSize; - CPoint m_virtualTextureTopLeft; - bool m_bInvAlpha; - RelativeTo m_relativeTo; - - /* - - Texture - +-------+---------------------------------+ - | . | . - | . m_maxsize | . - TextureTopLeft .<=============================== |======> . Video - | . . . +-------------------------------- | -----+ +-----------------------------------+ - | | . | | | m_vidrect | - | | . | | | | - | | . | | | | - | | +-----------+ . | | | | - | | | m_rcDirty | . | | | | - | | | | . | | | | - | | +-----------+ . | | | | - | +-------------------------------- | -----+ | | - | m_size | | | - | <=========================> | | | - | | | | - | | +-----------------------------------+ - | | . - | | . - | | . - +-----------------------------------------+ - m_VirtualTextureSize - <=========================================> - - */ - - -public: - CSubPicImpl(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPic - - STDMETHODIMP_(REFERENCE_TIME) GetStart() const; - STDMETHODIMP_(REFERENCE_TIME) GetStop() const; - STDMETHODIMP_(void) SetStart(REFERENCE_TIME rtStart); - STDMETHODIMP_(void) SetStop(REFERENCE_TIME rtStop); - - STDMETHODIMP GetDesc(SubPicDesc& spd) PURE; - STDMETHODIMP CopyTo(ISubPic* pSubPic); - - STDMETHODIMP ClearDirtyRect() PURE; - STDMETHODIMP GetDirtyRect(RECT* pDirtyRect) const; - STDMETHODIMP SetDirtyRect(const RECT* pDirtyRect); - - STDMETHODIMP GetMaxSize(SIZE* pMaxSize) const; - STDMETHODIMP SetSize(SIZE size, RECT vidrect); - - STDMETHODIMP Lock(SubPicDesc& spd) PURE; - STDMETHODIMP Unlock(RECT* pDirtyRect) PURE; - - STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) PURE; - - STDMETHODIMP SetVirtualTextureSize(const SIZE pSize, const POINT pTopLeft); - STDMETHODIMP GetSourceAndDest(RECT rcWindow, RECT rcVideo, RECT* pRcSource, - RECT* pRcDest, const double videoStretchFactor = 1.0, - int xOffsetInPixels = 0, int yOffsetInPixels = 0) const; - STDMETHODIMP GetRelativeTo(RelativeTo* pRelativeTo) const; - STDMETHODIMP SetRelativeTo(RelativeTo relativeTo); - - STDMETHODIMP_(REFERENCE_TIME) GetSegmentStart() const; - STDMETHODIMP_(REFERENCE_TIME) GetSegmentStop() const; - STDMETHODIMP_(void) SetSegmentStart(REFERENCE_TIME rtStart); - STDMETHODIMP_(void) SetSegmentStop(REFERENCE_TIME rtStop); - STDMETHODIMP_(void) SetInverseAlpha(bool bInverted); -}; - - -class CSubPicAllocatorImpl : public CUnknown, public ISubPicAllocator -{ -protected: - CCritSec m_staticLock; - CComPtr m_pStatic; - - CSize m_cursize; - CRect m_curvidrect; - bool m_fDynamicWriteOnly; - - virtual bool Alloc(bool fStatic, ISubPic** ppSubPic) PURE; - -protected: - bool m_bInvAlpha = false; - -public: - CSubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicAllocator - - STDMETHODIMP SetCurSize(SIZE cursize); - STDMETHODIMP SetCurVidRect(RECT curvidrect); - STDMETHODIMP GetStatic(ISubPic** ppSubPic); - STDMETHODIMP AllocDynamic(ISubPic** ppSubPic); - STDMETHODIMP_(bool) IsDynamicWriteOnly() const; - STDMETHODIMP ChangeDevice(IUnknown* pDev); - STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize) PURE; - STDMETHODIMP FreeStatic(); - STDMETHODIMP_(void) SetInverseAlpha(bool bInverted); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "ISubPic.h" + +class CSubPicImpl : public CUnknown, public ISubPic +{ +protected: + REFERENCE_TIME m_rtStart, m_rtStop; + REFERENCE_TIME m_rtSegmentStart, m_rtSegmentStop; + CRect m_rcDirty; + CSize m_maxsize; + CSize m_size; + CRect m_vidrect; + CSize m_virtualTextureSize; + CPoint m_virtualTextureTopLeft; + bool m_bInvAlpha; + RelativeTo m_relativeTo; + + /* + + Texture + +-------+---------------------------------+ + | . | . + | . m_maxsize | . + TextureTopLeft .<=============================== |======> . Video + | . . . +-------------------------------- | -----+ +-----------------------------------+ + | | . | | | m_vidrect | + | | . | | | | + | | . | | | | + | | +-----------+ . | | | | + | | | m_rcDirty | . | | | | + | | | | . | | | | + | | +-----------+ . | | | | + | +-------------------------------- | -----+ | | + | m_size | | | + | <=========================> | | | + | | | | + | | +-----------------------------------+ + | | . + | | . + | | . + +-----------------------------------------+ + m_VirtualTextureSize + <=========================================> + + */ + + +public: + CSubPicImpl(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPic + + STDMETHODIMP_(REFERENCE_TIME) GetStart() const; + STDMETHODIMP_(REFERENCE_TIME) GetStop() const; + STDMETHODIMP_(void) SetStart(REFERENCE_TIME rtStart); + STDMETHODIMP_(void) SetStop(REFERENCE_TIME rtStop); + + STDMETHODIMP GetDesc(SubPicDesc& spd) PURE; + STDMETHODIMP CopyTo(ISubPic* pSubPic); + + STDMETHODIMP ClearDirtyRect() PURE; + STDMETHODIMP GetDirtyRect(RECT* pDirtyRect) const; + STDMETHODIMP SetDirtyRect(const RECT* pDirtyRect); + + STDMETHODIMP GetMaxSize(SIZE* pMaxSize) const; + STDMETHODIMP SetSize(SIZE size, RECT vidrect); + + STDMETHODIMP Lock(SubPicDesc& spd) PURE; + STDMETHODIMP Unlock(RECT* pDirtyRect) PURE; + + STDMETHODIMP AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) PURE; + + STDMETHODIMP SetVirtualTextureSize(const SIZE pSize, const POINT pTopLeft); + STDMETHODIMP GetSourceAndDest(RECT rcWindow, RECT rcVideo, RECT* pRcSource, + RECT* pRcDest, const double videoStretchFactor = 1.0, + int xOffsetInPixels = 0, int yOffsetInPixels = 0) const; + STDMETHODIMP GetRelativeTo(RelativeTo* pRelativeTo) const; + STDMETHODIMP SetRelativeTo(RelativeTo relativeTo); + + STDMETHODIMP_(REFERENCE_TIME) GetSegmentStart() const; + STDMETHODIMP_(REFERENCE_TIME) GetSegmentStop() const; + STDMETHODIMP_(void) SetSegmentStart(REFERENCE_TIME rtStart); + STDMETHODIMP_(void) SetSegmentStop(REFERENCE_TIME rtStop); + STDMETHODIMP_(void) SetInverseAlpha(bool bInverted); +}; + + +class CSubPicAllocatorImpl : public CUnknown, public ISubPicAllocator +{ +protected: + CCritSec m_staticLock; + CComPtr m_pStatic; + + CSize m_cursize; + CRect m_curvidrect; + bool m_fDynamicWriteOnly; + + virtual bool Alloc(bool fStatic, ISubPic** ppSubPic) PURE; + +protected: + bool m_bInvAlpha = false; + +public: + CSubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicAllocator + + STDMETHODIMP SetCurSize(SIZE cursize); + STDMETHODIMP SetCurVidRect(RECT curvidrect); + STDMETHODIMP GetStatic(ISubPic** ppSubPic); + STDMETHODIMP AllocDynamic(ISubPic** ppSubPic); + STDMETHODIMP_(bool) IsDynamicWriteOnly() const; + STDMETHODIMP ChangeDevice(IUnknown* pDev); + STDMETHODIMP SetMaxTextureSize(SIZE maxTextureSize) PURE; + STDMETHODIMP FreeStatic(); + STDMETHODIMP_(void) SetInverseAlpha(bool bInverted); +}; diff --git a/src/SubPic/SubPicProviderImpl.cpp b/src/SubPic/SubPicProviderImpl.cpp index 9bfc46a42fa..9a060886d2d 100644 --- a/src/SubPic/SubPicProviderImpl.cpp +++ b/src/SubPic/SubPicProviderImpl.cpp @@ -1,65 +1,65 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "SubPicProviderImpl.h" -#include "../DSUtil/DSUtil.h" - -CSubPicProviderImpl::CSubPicProviderImpl(CCritSec* pLock) - : CUnknown(NAME("CSubPicProviderImpl"), nullptr) - , m_pLock(pLock) -{ -} - -CSubPicProviderImpl::~CSubPicProviderImpl() -{ -} - -STDMETHODIMP CSubPicProviderImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(ISubPicProvider) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// CSubPicProviderImpl - -STDMETHODIMP CSubPicProviderImpl::Lock() -{ - CheckPointer(m_pLock, E_FAIL); -#if DEBUG - if (m_pLock->m_currentOwner != 0 && m_pLock->m_currentOwner != GetCurrentThreadId()) { - TRACE(_T("CSubPicProviderImpl::Lock -> Lockcount=%d Lockowner=%d Thread=%d\n"), m_pLock->m_lockCount, m_pLock->m_currentOwner, GetCurrentThreadId()); - }; -#endif - m_pLock->Lock(); - - return S_OK; -} - -STDMETHODIMP CSubPicProviderImpl::Unlock() -{ - CheckPointer(m_pLock, E_FAIL); - - m_pLock->Unlock(); - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "SubPicProviderImpl.h" +#include "../DSUtil/DSUtil.h" + +CSubPicProviderImpl::CSubPicProviderImpl(CCritSec* pLock) + : CUnknown(NAME("CSubPicProviderImpl"), nullptr) + , m_pLock(pLock) +{ +} + +CSubPicProviderImpl::~CSubPicProviderImpl() +{ +} + +STDMETHODIMP CSubPicProviderImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(ISubPicProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// CSubPicProviderImpl + +STDMETHODIMP CSubPicProviderImpl::Lock() +{ + CheckPointer(m_pLock, E_FAIL); +#if DEBUG + if (m_pLock->m_currentOwner != 0 && m_pLock->m_currentOwner != GetCurrentThreadId()) { + TRACE(_T("CSubPicProviderImpl::Lock -> Lockcount=%d Lockowner=%d Thread=%d\n"), m_pLock->m_lockCount, m_pLock->m_currentOwner, GetCurrentThreadId()); + }; +#endif + m_pLock->Lock(); + + return S_OK; +} + +STDMETHODIMP CSubPicProviderImpl::Unlock() +{ + CheckPointer(m_pLock, E_FAIL); + + m_pLock->Unlock(); + + return S_OK; +} diff --git a/src/SubPic/SubPicProviderImpl.h b/src/SubPic/SubPicProviderImpl.h index 7874921e3a6..0f0db0ddd24 100644 --- a/src/SubPic/SubPicProviderImpl.h +++ b/src/SubPic/SubPicProviderImpl.h @@ -1,52 +1,52 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "ISubPic.h" - -class CSubPicProviderImpl : public CUnknown, public ISubPicProvider -{ -protected: - CCritSec* m_pLock; - -public: - CSubPicProviderImpl(CCritSec* pLock); - virtual ~CSubPicProviderImpl(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicProvider - - STDMETHODIMP Lock(); - STDMETHODIMP Unlock(); - - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps) PURE; - STDMETHODIMP_(POSITION) GetNext(POSITION pos) PURE; - - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps) PURE; - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps) PURE; - - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) PURE; - STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft) { return E_NOTIMPL; }; - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo) { relativeTo = WINDOW; return S_OK; }; -}; +/* + * (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 . + * + */ + +#pragma once + +#include "ISubPic.h" + +class CSubPicProviderImpl : public CUnknown, public ISubPicProvider +{ +protected: + CCritSec* m_pLock; + +public: + CSubPicProviderImpl(CCritSec* pLock); + virtual ~CSubPicProviderImpl(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicProvider + + STDMETHODIMP Lock(); + STDMETHODIMP Unlock(); + + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps) PURE; + STDMETHODIMP_(POSITION) GetNext(POSITION pos) PURE; + + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps) PURE; + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps) PURE; + + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) PURE; + STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft) { return E_NOTIMPL; }; + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo) { relativeTo = WINDOW; return S_OK; }; +}; diff --git a/src/SubPic/SubPicQueueImpl.cpp b/src/SubPic/SubPicQueueImpl.cpp index ec4df761819..945e4dfa993 100644 --- a/src/SubPic/SubPicQueueImpl.cpp +++ b/src/SubPic/SubPicQueueImpl.cpp @@ -1,894 +1,894 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "SubPicQueueImpl.h" -#include "../DSUtil/DSUtil.h" - -#define SUBPIC_TRACE_LEVEL 0 -#define SUBPIC_TRACE_DROP 0 - -#define RT2SEC(x) (double(x) / 10000000.0) - -// -// CSubPicQueueImpl -// - -const double CSubPicQueueImpl::DEFAULT_FPS = 25.0; - -CSubPicQueueImpl::CSubPicQueueImpl(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) - : CUnknown(NAME("CSubPicQueueImpl"), nullptr) - , m_fps(DEFAULT_FPS) - , m_rtTimePerFrame(std::llround(10000000.0 / DEFAULT_FPS)) - , m_rtTimePerSubFrame(std::llround(10000000.0 / (DEFAULT_FPS * settings.nAnimationRate / 100.0))) - , m_rtNow(0) - , m_settings(settings) - , m_pAllocator(pAllocator) -{ - if (phr) { - *phr = S_OK; - } - - if (!m_pAllocator) { - if (phr) { - *phr = E_FAIL; - } - return; - } -} - -CSubPicQueueImpl::~CSubPicQueueImpl() -{ -} - -STDMETHODIMP CSubPicQueueImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(ISubPicQueue) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPicQueue - -STDMETHODIMP CSubPicQueueImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider) -{ - CAutoLock cAutoLock(&m_csSubPicProvider); - - if (m_pSubPicProviderWithSharedLock && m_pSubPicProviderWithSharedLock->pSubPicProvider != pSubPicProvider) { - m_pSubPicProviderWithSharedLock->Lock(); - m_pSubPicProviderWithSharedLock->Unlock(); - // queue is now not processing anything - } - - m_pSubPicProviderWithSharedLock = std::make_shared(pSubPicProvider); - - Invalidate(); - - return S_OK; -} - -STDMETHODIMP CSubPicQueueImpl::GetSubPicProvider(ISubPicProvider** pSubPicProvider) -{ - CheckPointer(pSubPicProvider, E_POINTER); - - CAutoLock cAutoLock(&m_csSubPicProvider); - - if (m_pSubPicProviderWithSharedLock && m_pSubPicProviderWithSharedLock->pSubPicProvider) { - *pSubPicProvider = m_pSubPicProviderWithSharedLock->pSubPicProvider; - (*pSubPicProvider)->AddRef(); - } - - return *pSubPicProvider ? S_OK : E_FAIL; -} - -STDMETHODIMP CSubPicQueueImpl::SetFPS(double fps) -{ - m_fps = fps; - - return S_OK; -} - -STDMETHODIMP CSubPicQueueImpl::SetTime(REFERENCE_TIME rtNow) -{ - m_rtNow = rtNow; - - return S_OK; -} - -// private - -HRESULT CSubPicQueueImpl::RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps, BOOL bIsAnimated) -{ - CheckPointer(pSubPic, E_POINTER); - - HRESULT hr = E_FAIL; - CComPtr pSubPicProvider; - if (FAILED(GetSubPicProvider(&pSubPicProvider)) || !pSubPicProvider) { - return hr; - } - - - hr = pSubPic->ClearDirtyRect(); - - SubPicDesc spd; - if (SUCCEEDED(hr)) { - hr = pSubPic->Lock(spd); - } - if (SUCCEEDED(hr)) { - CRect r(0, 0, 0, 0); - REFERENCE_TIME rtRender; - if (bIsAnimated) { - // This is some sort of hack to avoid rendering the wrong frame - // when the start time is slightly mispredicted by the queue - rtRender = (rtStart + rtStop) / 2; - } else { - rtRender = rtStart + std::llround((rtStop - rtStart - 1) * m_settings.nRenderAtWhenAnimationIsDisabled / 100.0); - } - hr = pSubPicProvider->Render(spd, rtRender, fps, r); - - pSubPic->SetStart(rtStart); - pSubPic->SetStop(rtStop); - - pSubPic->Unlock(r); - } - - return hr; -} - -// -// CSubPicQueue -// - -CSubPicQueue::CSubPicQueue(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) - : CSubPicQueueImpl(settings, pAllocator, phr) - , m_bExitThread(false) - , m_rtNowLast(LONGLONG_ERROR) - , m_bInvalidate(false) - , m_rtInvalidate(0) -{ - if (phr && FAILED(*phr)) { - return; - } - - if (m_settings.nSize < 1) { - if (phr) { - *phr = E_INVALIDARG; - } - return; - } - - CAMThread::Create(); -} - -CSubPicQueue::~CSubPicQueue() -{ - m_bExitThread = true; - SetSubPicProvider(nullptr); - CAMThread::Close(); - if (m_pAllocator) { - m_pAllocator->FreeStatic(); - } -} - -// ISubPicQueue - -STDMETHODIMP CSubPicQueue::SetFPS(double fps) -{ - HRESULT hr = __super::SetFPS(fps); - if (FAILED(hr)) { - return hr; - } - - m_rtTimePerFrame = std::llround(10000000.0 / m_fps); - m_rtTimePerSubFrame = std::llround(10000000.0 / (m_fps * m_settings.nAnimationRate / 100.0)); - - m_runQueueEvent.Set(); - - return S_OK; -} - -STDMETHODIMP CSubPicQueue::SetTime(REFERENCE_TIME rtNow) -{ - HRESULT hr = __super::SetTime(rtNow); - if (FAILED(hr)) { - return hr; - } - - // We want the queue to stay sorted so if we seek in the past, we invalidate - if (m_rtNowLast >= 0 && m_rtNowLast - m_rtNow >= m_rtTimePerFrame) { - Invalidate(m_rtNow); - } - - m_rtNowLast = m_rtNow; - - m_runQueueEvent.Set(); - - return S_OK; -} - -STDMETHODIMP CSubPicQueue::Invalidate(REFERENCE_TIME rtInvalidate /*= -1*/) -{ - std::unique_lock lockQueue(m_mutexQueue); - -#if SUBPIC_TRACE_LEVEL > 0 - TRACE(_T("Invalidate: %.3f\n"), RT2SEC(rtInvalidate)); -#endif - - m_bInvalidate = true; - m_rtInvalidate = rtInvalidate; - m_rtNowLast = LONGLONG_ERROR; - - { - std::lock_guard lockSubpic(m_mutexSubpic); - if (m_pSubPic && m_pSubPic->GetStop() > rtInvalidate) { - m_pSubPic.Release(); - } - } - - while (!m_queue.IsEmpty() && m_queue.GetTail()->GetStop() > rtInvalidate) { -#if SUBPIC_TRACE_LEVEL > 2 - const CComPtr& pSubPic = m_queue.GetTail(); - REFERENCE_TIME rtStart = pSubPic->GetStart(); - REFERENCE_TIME rtStop = pSubPic->GetStop(); - REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); - TRACE(_T(" %.3f -> %.3f -> %.3f\n"), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop)); -#endif - m_queue.RemoveTailNoReturn(); -#if SUBPIC_TRACE_LEVEL > 0 - TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); -#endif - } - - // If we invalidate in the past, always give the queue a chance to re-render the modified subtitles - if (rtInvalidate < m_rtNow) { - m_rtNow = std::max(rtInvalidate, 0LL); - } - - lockQueue.unlock(); - m_condQueueFull.notify_one(); - m_runQueueEvent.Set(); - - return S_OK; -} - -STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, CComPtr& ppSubPic) -{ - // Old version of LookupSubPic, keep legacy behavior and never try to block - return LookupSubPic(rtNow, false, ppSubPic); -} - -STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& ppSubPic) -{ - bool bStopSearch = false; - - { - std::lock_guard lock(m_mutexSubpic); - - // See if we can reuse the latest subpic - if (m_pSubPic) { - REFERENCE_TIME rtSegmentStart = m_pSubPic->GetSegmentStart(); - REFERENCE_TIME rtSegmentStop = m_pSubPic->GetSegmentStop(); - - if (rtSegmentStart <= rtNow && rtNow < rtSegmentStop) { - ppSubPic = m_pSubPic; - - REFERENCE_TIME rtStart = m_pSubPic->GetStart(); - REFERENCE_TIME rtStop = m_pSubPic->GetStop(); - - if (rtStart <= rtNow && rtNow < rtStop) { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("LookupSubPic: Exact match on the latest subpic, rtNow=%.3f rtSegmentStart=%.3f rtSegmentStop=%.3f\n"), RT2SEC(rtNow), RT2SEC(rtSegmentStart), RT2SEC(rtSegmentStop)); -#endif - bStopSearch = true; - } else { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("LookupSubPic: Possible match on the latest subpic, rtNow=%.3f rtStart=%.3f rtStop=%.3f\n"), RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop)); -#endif - } - } else if (rtSegmentStop <= rtNow) { - m_pSubPic.Release(); - } - } - } - - bool bTryBlocking = bAdviseBlocking || !m_settings.bAllowDroppingSubpic; - while (!bStopSearch) { - // Look for the subpic in the queue - { - std::unique_lock lock(m_mutexQueue); - -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("LookupSubPic: Searching the queue, rtNow=%.3f\n"), RT2SEC(rtNow)); -#endif - - while (!m_queue.IsEmpty() && !bStopSearch) { - const CComPtr& pSubPic = m_queue.GetHead(); - REFERENCE_TIME rtSegmentStart = pSubPic->GetSegmentStart(); - - if (rtSegmentStart > rtNow) { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("rtSegmentStart > rtNow, stopping the search, rtSegmentStart=%.3f\n"), RT2SEC(rtSegmentStart)); -#endif - bStopSearch = true; - } else { // rtSegmentStart <= rtNow - bool bRemoveFromQueue = true; - REFERENCE_TIME rtStart = pSubPic->GetStart(); - REFERENCE_TIME rtStop = pSubPic->GetStop(); - REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); - - if (rtSegmentStop <= rtNow) { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("Removing old subpic (rtNow=%.3f): %.3f -> %.3f -> %.3f\n"), - RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop)); -#endif - } else { // rtNow < rtSegmentStop - if (rtStart <= rtNow && rtNow < rtStop) { -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("Exact match found in the queue\n")); -#endif - ppSubPic = pSubPic; - bStopSearch = true; - } else if (rtNow >= rtStop) { - // Reuse old subpic - ppSubPic = pSubPic; - } else { // rtNow < rtStart - if (!ppSubPic || ppSubPic->GetStop() <= rtNow) { - // Should be really rare that we use a subpic in advance - // unless we mispredicted the timing slightly - ppSubPic = pSubPic; - } else { - bRemoveFromQueue = false; - } - bStopSearch = true; - } - } - - if (bRemoveFromQueue) { - m_queue.RemoveHeadNoReturn(); -#if SUBPIC_TRACE_LEVEL > 0 - TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); -#endif - } - } - } - - lock.unlock(); - m_condQueueFull.notify_one(); - } - - // If we didn't get any subpic yet and blocking is advised, just try harder to get one - if (!ppSubPic && bTryBlocking) { - bTryBlocking = false; - bStopSearch = true; - - auto pSubPicProviderWithSharedLock = GetSubPicProviderWithSharedLock(); - if (pSubPicProviderWithSharedLock && SUCCEEDED(pSubPicProviderWithSharedLock->Lock())) { - auto& pSubPicProvider = pSubPicProviderWithSharedLock->pSubPicProvider; - double fps = m_fps; - if (POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps)) { - REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); - REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); - if (rtStart <= rtNow && rtNow < rtStop) { - bStopSearch = false; - } - } - pSubPicProviderWithSharedLock->Unlock(); - - if (!bStopSearch && m_settings.nSize) { - std::unique_lock lock(m_mutexQueue); - - auto queueReady = [this, rtNow]() { - return ((int)m_queue.GetCount() == m_settings.nSize) - || (!m_queue.IsEmpty() && m_queue.GetTail()->GetStop() > rtNow); - }; - - std::chrono::milliseconds timeoutPeriod(250); - m_condQueueReady.wait_for(lock, timeoutPeriod, queueReady); - } - } - } else { - bStopSearch = true; - } - } - - if (ppSubPic) { - // Save the subpic for later reuse - std::lock_guard lock(m_mutexSubpic); - m_pSubPic = ppSubPic; - -#if SUBPIC_TRACE_LEVEL > 0 - REFERENCE_TIME rtStart = ppSubPic->GetStart(); - REFERENCE_TIME rtStop = ppSubPic->GetStop(); - REFERENCE_TIME rtSegmentStop = ppSubPic->GetSegmentStop(); - CRect r; - ppSubPic->GetDirtyRect(&r); - TRACE(_T("Display at %.3f: %.3f -> %.3f -> %.3f (%dx%d)\n"), - RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop), - r.Width(), r.Height()); -#endif - } else { -#if SUBPIC_TRACE_LEVEL > 1 - TRACE(_T("No subpicture to display at %.3f\n"), RT2SEC(rtNow)); -#endif - } - - return !!ppSubPic; -} - -STDMETHODIMP CSubPicQueue::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) -{ - std::lock_guard lock(m_mutexQueue); - - nSubPics = (int)m_queue.GetCount(); - rtNow = m_rtNow; - if (nSubPics) { - rtStart = m_queue.GetHead()->GetStart(); - rtStop = m_queue.GetTail()->GetStop(); - } else { - rtStart = rtStop = 0; - } - - return S_OK; -} - -STDMETHODIMP CSubPicQueue::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) -{ - std::lock_guard lock(m_mutexQueue); - - HRESULT hr = E_INVALIDARG; - - if (nSubPic >= 0 && nSubPic < (int)m_queue.GetCount()) { - if (POSITION pos = m_queue.FindIndex(nSubPic)) { - rtStart = m_queue.GetAt(pos)->GetStart(); - rtStop = m_queue.GetAt(pos)->GetStop(); - hr = S_OK; - } else { - // Can't happen - ASSERT(FALSE); - } - } else { - rtStart = rtStop = -1; - } - - return hr; -} - -// private - -bool CSubPicQueue::EnqueueSubPic(CComPtr& pSubPic, bool bBlocking) -{ - auto canAddToQueue = [this]() { - return (int)m_queue.GetCount() < m_settings.nSize; - }; - - bool bAdded = false; - - std::unique_lock lock(m_mutexQueue); - if (bBlocking) { - // Wait for enough room in the queue - m_condQueueFull.wait(lock, canAddToQueue); - } - - if (canAddToQueue()) { - if (m_bInvalidate && pSubPic->GetStop() > m_rtInvalidate) { -#if SUBPIC_TRACE_LEVEL > 1 | SUBPIC_TRACE_DROP - TRACE(_T("Subtitle Renderer Thread: Dropping rendered subpic because of invalidation\n")); -#endif - } else { - m_queue.AddTail(pSubPic); -#if SUBPIC_TRACE_LEVEL > 0 - TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); -#endif - lock.unlock(); - m_condQueueReady.notify_one(); - bAdded = true; - } - pSubPic.Release(); - } - - return bAdded; -} - -REFERENCE_TIME CSubPicQueue::GetCurrentRenderingTime() -{ - REFERENCE_TIME rtNow = -1; - - { - std::lock_guard lock(m_mutexQueue); - - if (!m_queue.IsEmpty()) { - rtNow = m_queue.GetTail()->GetStop(); - } - } - - return std::max(rtNow, m_rtNow); -} - -// overrides - -DWORD CSubPicQueue::ThreadProc() -{ - bool bDisableAnim = m_settings.bDisableSubtitleAnimation; - SetThreadName(DWORD(-1), "Subtitle Renderer Thread"); - SetThreadPriority(m_hThread, bDisableAnim ? THREAD_PRIORITY_LOWEST : THREAD_PRIORITY_ABOVE_NORMAL); - - bool bWaitForEvent = false; - for (; !m_bExitThread;) { - // When we have nothing to render, we just wait a bit - if (bWaitForEvent) { - bWaitForEvent = false; - m_runQueueEvent.Wait(); - } - - auto pSubPicProviderWithSharedLock = GetSubPicProviderWithSharedLock(); - if (pSubPicProviderWithSharedLock && SUCCEEDED(pSubPicProviderWithSharedLock->Lock())) { - auto& pSubPicProvider = pSubPicProviderWithSharedLock->pSubPicProvider; - double fps = m_fps; - REFERENCE_TIME rtTimePerFrame = m_rtTimePerFrame; - REFERENCE_TIME rtTimePerSubFrame = m_rtTimePerSubFrame; - m_bInvalidate = false; - CComPtr pSubPic; - - REFERENCE_TIME rtStartRendering = GetCurrentRenderingTime(); - POSITION pos = pSubPicProvider->GetStartPosition(rtStartRendering, fps); - if (!pos) { - bWaitForEvent = true; - } - for (; pos; pos = pSubPicProvider->GetNext(pos)) { - REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); - REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); - - // We are already one minute ahead, this should be enough - if (rtStart >= m_rtNow + 60 * 10000000i64) { - bWaitForEvent = true; - break; - } - -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("New subtitle sample: Start=%.3f Stop=%.3f\n"), RT2SEC(rtStart), RT2SEC(rtStop)); -#endif - - REFERENCE_TIME rtCurrent = std::max(rtStart, rtStartRendering); - if (rtCurrent < m_rtNow) { - rtCurrent = m_rtNow; - } else { -#if 0 - // FIXME: what is the purpose of this? - if (rtTimePerFrame <= rtStop - rtStart) { - // Round current time to the next estimated video frame timing - REFERENCE_TIME rtCurrentRounded = (rtCurrent / rtTimePerFrame) * rtTimePerFrame; - if (rtCurrentRounded < rtCurrent) { - rtCurrent = rtCurrentRounded + rtTimePerFrame; - } - } -#endif - } - - // Check that we aren't late already... - if (rtCurrent <= rtStop) { - bool bIsAnimated = pSubPicProvider->IsAnimated(pos) && !bDisableAnim; - bool bStopRendering = false; - - while (rtCurrent < rtStop) { - SIZE maxTextureSize, virtualSize; - POINT virtualTopLeft; - HRESULT hr2; - - if (SUCCEEDED(hr2 = pSubPicProvider->GetTextureSize(pos, maxTextureSize, virtualSize, virtualTopLeft))) { - m_pAllocator->SetMaxTextureSize(maxTextureSize); - m_pAllocator->SetCurSize(maxTextureSize); - } - - CComPtr pStatic; - if (FAILED(m_pAllocator->GetStatic(&pStatic))) { - break; - } - - REFERENCE_TIME rtStopReal; - if (rtStop == ISubPicProvider::UNKNOWN_TIME) { // Special case for subtitles with unknown end time - // Force a one frame duration - rtStopReal = rtCurrent + rtTimePerFrame; - } else { - rtStopReal = rtStop; - } - - HRESULT hr; - if (bIsAnimated) { - // 3/4 is a magic number we use to avoid reusing the wrong frame due to slight - // misprediction of the frame end time - hr = RenderTo(pStatic, rtCurrent, std::min(rtCurrent + rtTimePerSubFrame * 3 / 4, rtStopReal), fps, bIsAnimated); -#if SUBPIC_TRACE_LEVEL > 2 - TRACE(_T("rtCurrent=%.3f Start=%.3f SegmentStart=%.3f SegmentStop=%.3f Stop=%.3f\n"), RT2SEC(rtCurrent), RT2SEC(pStatic->GetStart()), RT2SEC(pStatic->GetSegmentStart()), RT2SEC(pStatic->GetSegmentStop()), RT2SEC(pStatic->GetStop())); -#endif - // Set the segment start and stop timings - pStatic->SetSegmentStart(rtStart); - // The stop timing can be moved so that the duration from the current start time - // of the subpic to the segment end is always at least one video frame long. This - // avoids missing subtitle frame due to rounding errors in the timings. - // At worst this can cause a segment to be displayed for one more frame than expected - // but it's much less annoying than having the subtitle disappearing for one frame - pStatic->SetSegmentStop(std::max(rtCurrent + rtTimePerFrame, rtStopReal)); - rtCurrent = std::min(rtCurrent + rtTimePerSubFrame, rtStopReal); - } else { - hr = RenderTo(pStatic, rtStart, rtStopReal, fps, false); - // Non-animated subtitles aren't part of a segment - pStatic->SetSegmentStart(ISubPic::INVALID_SUBPIC_TIME); - pStatic->SetSegmentStop(ISubPic::INVALID_SUBPIC_TIME); - rtCurrent = rtStopReal; - } - - if (FAILED(hr)) { - break; - } - -#if SUBPIC_TRACE_LEVEL > 1 - CRect r; - pStatic->GetDirtyRect(&r); - TRACE(_T("Subtitle Renderer Thread: Render %.3f -> %.3f -> %.3f -> %.3f res=%dx%d\n"), - RT2SEC(rtStart), RT2SEC(pStatic->GetStart()), RT2SEC(pStatic->GetStop()), RT2SEC(rtStop), - r.Width(), r.Height()); -#endif - - pSubPic.Release(); - if (FAILED(m_pAllocator->AllocDynamic(&pSubPic)) - || FAILED(pStatic->CopyTo(pSubPic))) { - break; - } - - if (SUCCEEDED(hr2)) { - pSubPic->SetVirtualTextureSize(virtualSize, virtualTopLeft); - } - - RelativeTo relativeTo; - if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { - pSubPic->SetRelativeTo(relativeTo); - } - - // Try to enqueue the subpic, if the queue is full stop rendering - if (!EnqueueSubPic(pSubPic, false)) { - bStopRendering = true; - break; - } - - if (m_rtNow > rtCurrent) { -#if SUBPIC_TRACE_LEVEL > 0 | SUBPIC_TRACE_DROP - TRACE(_T("Subtitle Renderer Thread: the queue is late, rtCurrent = %.03f rtNow = %.03f \n"), RT2SEC(rtCurrent), RT2SEC(m_rtNow)); -#endif - rtCurrent = m_rtNow; - } - } - - if (bStopRendering) { - break; - } - } else { -#if SUBPIC_TRACE_LEVEL > 0 | SUBPIC_TRACE_DROP - TRACE(_T("Subtitle Renderer Thread: the queue is late, rtCurrent = %.03f rtStart = %.03f rtStop = %.03f\n"), RT2SEC(rtCurrent), RT2SEC(rtStart), RT2SEC(rtStop)); -#endif - } - } - - pSubPicProviderWithSharedLock->Unlock(); - - // If we couldn't enqueue the subpic before, wait for some room in the queue - // but unsure to unlock the subpicture provider first to avoid deadlocks - if (pSubPic) { - EnqueueSubPic(pSubPic, true); - } - } else { - bWaitForEvent = true; - } - } - - return 0; -} - -// -// CSubPicQueueNoThread -// - -CSubPicQueueNoThread::CSubPicQueueNoThread(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) - : CSubPicQueueImpl(settings, pAllocator, phr) -{ - if (phr && SUCCEEDED(*phr) && m_settings.nSize != 0) { - *phr = E_INVALIDARG; - } -} - -CSubPicQueueNoThread::~CSubPicQueueNoThread() -{ - if (m_pAllocator) { - m_pAllocator->FreeStatic(); - } -} - -// ISubPicQueue - -STDMETHODIMP CSubPicQueueNoThread::SetFPS(double fps) -{ - HRESULT hr = __super::SetFPS(fps); - if (FAILED(hr)) { - return hr; - } - - if (m_settings.nAnimationRate == 100) { // Special case when rendering at full speed - // Ensure the subtitle will really be updated every frame by setting a really small duration - m_rtTimePerSubFrame = 1; - } else { - m_rtTimePerSubFrame = std::llround(10000000.0 / (m_fps * m_settings.nAnimationRate / 100.0)); - } - - return S_OK; -} - -STDMETHODIMP CSubPicQueueNoThread::Invalidate(REFERENCE_TIME rtInvalidate /*= -1*/) -{ - CAutoLock cQueueLock(&m_csLock); - - if (m_pSubPic && m_pSubPic->GetStop() > rtInvalidate) { - m_pSubPic = nullptr; - } - - return S_OK; -} - -STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, CComPtr& ppSubPic) -{ - // CSubPicQueueNoThread is always blocking so bAdviseBlocking doesn't matter anyway - return LookupSubPic(rtNow, true, ppSubPic); -} - -STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, bool /*bAdviseBlocking*/, CComPtr& ppSubPic) -{ - // CSubPicQueueNoThread is always blocking so we ignore bAdviseBlocking - - CComPtr pSubPic; - - { - CAutoLock cAutoLock(&m_csLock); - - pSubPic = m_pSubPic; - } - - if (pSubPic && pSubPic->GetStart() <= rtNow && rtNow < pSubPic->GetStop()) { - ppSubPic = pSubPic; - } else { - CComPtr pSubPicProvider; - if (SUCCEEDED(GetSubPicProvider(&pSubPicProvider)) && pSubPicProvider - && SUCCEEDED(pSubPicProvider->Lock())) { - double fps = m_fps; - POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps); - if (pos) { - REFERENCE_TIME rtStart; - REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); - bool bAnimated = pSubPicProvider->IsAnimated(pos) && !m_settings.bDisableSubtitleAnimation; - - // Special case for subtitles with unknown end time - if (rtStop == ISubPicProvider::UNKNOWN_TIME) { - // Force a one frame duration - rtStop = rtNow + 1; - } - - if (bAnimated) { - rtStart = rtNow; - rtStop = std::min(rtNow + m_rtTimePerSubFrame, rtStop); - } else { - rtStart = pSubPicProvider->GetStart(pos, fps); - } - - if (rtStart <= rtNow && rtNow < rtStop) { - bool bAllocSubPic = !pSubPic; - SIZE maxTextureSize, virtualSize; - POINT virtualTopLeft; - HRESULT hr; - if (SUCCEEDED(hr = pSubPicProvider->GetTextureSize(pos, maxTextureSize, virtualSize, virtualTopLeft))) { - m_pAllocator->SetMaxTextureSize(maxTextureSize); - m_pAllocator->SetCurSize(maxTextureSize); - if (!bAllocSubPic) { - // Ensure the previously allocated subpic is big enough to hold the subtitle to be rendered - SIZE maxSize = {0L,0L}; - bAllocSubPic = FAILED(pSubPic->GetMaxSize(&maxSize)) || maxSize.cx < maxTextureSize.cx || maxSize.cy < maxTextureSize.cy; - if (bAllocSubPic) { - TRACE(_T("AllocSubPic required: maxSize=%dx%d maxTextureSize=%dx%d\n"), maxSize.cx, maxSize.cy, maxTextureSize.cx, maxTextureSize.cy); - } - } - } - - if (bAllocSubPic) { - CAutoLock cAutoLock(&m_csLock); - - m_pSubPic.Release(); - - if (FAILED(m_pAllocator->AllocDynamic(&m_pSubPic))) { - TRACE(_T("CSubPicQueueNoThread::LookupSubPic -> AllocDynamic failed\n")); - pSubPicProvider->Unlock(); - return false; - } - - pSubPic = m_pSubPic; - } - - if (m_pAllocator->IsDynamicWriteOnly()) { - CComPtr pStatic; - if (SUCCEEDED(m_pAllocator->GetStatic(&pStatic)) - && SUCCEEDED(RenderTo(pStatic, rtStart, rtStop, fps, bAnimated)) - && SUCCEEDED(pStatic->CopyTo(pSubPic))) { - ppSubPic = pSubPic; - } - } else { - if (SUCCEEDED(RenderTo(pSubPic, rtStart, rtStop, fps, bAnimated))) { - ppSubPic = pSubPic; - } - } - - if (ppSubPic) { - if (SUCCEEDED(hr)) { - ppSubPic->SetVirtualTextureSize(virtualSize, virtualTopLeft); - } - - RelativeTo relativeTo; - if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { - ppSubPic->SetRelativeTo(relativeTo); - } - } - } - } - - pSubPicProvider->Unlock(); - } - } - - return !!ppSubPic; -} - -STDMETHODIMP CSubPicQueueNoThread::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) -{ - CAutoLock cAutoLock(&m_csLock); - - rtNow = m_rtNow; - - if (m_pSubPic) { - nSubPics = 1; - rtStart = m_pSubPic->GetStart(); - rtStop = m_pSubPic->GetStop(); - } else { - nSubPics = 0; - rtStart = rtStop = 0; - } - - return S_OK; -} - -STDMETHODIMP CSubPicQueueNoThread::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) -{ - CAutoLock cAutoLock(&m_csLock); - - if (!m_pSubPic || nSubPic != 0) { - return E_INVALIDARG; - } - - rtStart = m_pSubPic->GetStart(); - rtStop = m_pSubPic->GetStop(); - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "SubPicQueueImpl.h" +#include "../DSUtil/DSUtil.h" + +#define SUBPIC_TRACE_LEVEL 0 +#define SUBPIC_TRACE_DROP 0 + +#define RT2SEC(x) (double(x) / 10000000.0) + +// +// CSubPicQueueImpl +// + +const double CSubPicQueueImpl::DEFAULT_FPS = 25.0; + +CSubPicQueueImpl::CSubPicQueueImpl(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) + : CUnknown(NAME("CSubPicQueueImpl"), nullptr) + , m_fps(DEFAULT_FPS) + , m_rtTimePerFrame(std::llround(10000000.0 / DEFAULT_FPS)) + , m_rtTimePerSubFrame(std::llround(10000000.0 / (DEFAULT_FPS * settings.nAnimationRate / 100.0))) + , m_rtNow(0) + , m_settings(settings) + , m_pAllocator(pAllocator) +{ + if (phr) { + *phr = S_OK; + } + + if (!m_pAllocator) { + if (phr) { + *phr = E_FAIL; + } + return; + } +} + +CSubPicQueueImpl::~CSubPicQueueImpl() +{ +} + +STDMETHODIMP CSubPicQueueImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(ISubPicQueue) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicQueue + +STDMETHODIMP CSubPicQueueImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider) +{ + CAutoLock cAutoLock(&m_csSubPicProvider); + + if (m_pSubPicProviderWithSharedLock && m_pSubPicProviderWithSharedLock->pSubPicProvider != pSubPicProvider) { + m_pSubPicProviderWithSharedLock->Lock(); + m_pSubPicProviderWithSharedLock->Unlock(); + // queue is now not processing anything + } + + m_pSubPicProviderWithSharedLock = std::make_shared(pSubPicProvider); + + Invalidate(); + + return S_OK; +} + +STDMETHODIMP CSubPicQueueImpl::GetSubPicProvider(ISubPicProvider** pSubPicProvider) +{ + CheckPointer(pSubPicProvider, E_POINTER); + + CAutoLock cAutoLock(&m_csSubPicProvider); + + if (m_pSubPicProviderWithSharedLock && m_pSubPicProviderWithSharedLock->pSubPicProvider) { + *pSubPicProvider = m_pSubPicProviderWithSharedLock->pSubPicProvider; + (*pSubPicProvider)->AddRef(); + } + + return *pSubPicProvider ? S_OK : E_FAIL; +} + +STDMETHODIMP CSubPicQueueImpl::SetFPS(double fps) +{ + m_fps = fps; + + return S_OK; +} + +STDMETHODIMP CSubPicQueueImpl::SetTime(REFERENCE_TIME rtNow) +{ + m_rtNow = rtNow; + + return S_OK; +} + +// private + +HRESULT CSubPicQueueImpl::RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps, BOOL bIsAnimated) +{ + CheckPointer(pSubPic, E_POINTER); + + HRESULT hr = E_FAIL; + CComPtr pSubPicProvider; + if (FAILED(GetSubPicProvider(&pSubPicProvider)) || !pSubPicProvider) { + return hr; + } + + + hr = pSubPic->ClearDirtyRect(); + + SubPicDesc spd; + if (SUCCEEDED(hr)) { + hr = pSubPic->Lock(spd); + } + if (SUCCEEDED(hr)) { + CRect r(0, 0, 0, 0); + REFERENCE_TIME rtRender; + if (bIsAnimated) { + // This is some sort of hack to avoid rendering the wrong frame + // when the start time is slightly mispredicted by the queue + rtRender = (rtStart + rtStop) / 2; + } else { + rtRender = rtStart + std::llround((rtStop - rtStart - 1) * m_settings.nRenderAtWhenAnimationIsDisabled / 100.0); + } + hr = pSubPicProvider->Render(spd, rtRender, fps, r); + + pSubPic->SetStart(rtStart); + pSubPic->SetStop(rtStop); + + pSubPic->Unlock(r); + } + + return hr; +} + +// +// CSubPicQueue +// + +CSubPicQueue::CSubPicQueue(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) + : CSubPicQueueImpl(settings, pAllocator, phr) + , m_bExitThread(false) + , m_rtNowLast(LONGLONG_ERROR) + , m_bInvalidate(false) + , m_rtInvalidate(0) +{ + if (phr && FAILED(*phr)) { + return; + } + + if (m_settings.nSize < 1) { + if (phr) { + *phr = E_INVALIDARG; + } + return; + } + + CAMThread::Create(); +} + +CSubPicQueue::~CSubPicQueue() +{ + m_bExitThread = true; + SetSubPicProvider(nullptr); + CAMThread::Close(); + if (m_pAllocator) { + m_pAllocator->FreeStatic(); + } +} + +// ISubPicQueue + +STDMETHODIMP CSubPicQueue::SetFPS(double fps) +{ + HRESULT hr = __super::SetFPS(fps); + if (FAILED(hr)) { + return hr; + } + + m_rtTimePerFrame = std::llround(10000000.0 / m_fps); + m_rtTimePerSubFrame = std::llround(10000000.0 / (m_fps * m_settings.nAnimationRate / 100.0)); + + m_runQueueEvent.Set(); + + return S_OK; +} + +STDMETHODIMP CSubPicQueue::SetTime(REFERENCE_TIME rtNow) +{ + HRESULT hr = __super::SetTime(rtNow); + if (FAILED(hr)) { + return hr; + } + + // We want the queue to stay sorted so if we seek in the past, we invalidate + if (m_rtNowLast >= 0 && m_rtNowLast - m_rtNow >= m_rtTimePerFrame) { + Invalidate(m_rtNow); + } + + m_rtNowLast = m_rtNow; + + m_runQueueEvent.Set(); + + return S_OK; +} + +STDMETHODIMP CSubPicQueue::Invalidate(REFERENCE_TIME rtInvalidate /*= -1*/) +{ + std::unique_lock lockQueue(m_mutexQueue); + +#if SUBPIC_TRACE_LEVEL > 0 + TRACE(_T("Invalidate: %.3f\n"), RT2SEC(rtInvalidate)); +#endif + + m_bInvalidate = true; + m_rtInvalidate = rtInvalidate; + m_rtNowLast = LONGLONG_ERROR; + + { + std::lock_guard lockSubpic(m_mutexSubpic); + if (m_pSubPic && m_pSubPic->GetStop() > rtInvalidate) { + m_pSubPic.Release(); + } + } + + while (!m_queue.IsEmpty() && m_queue.GetTail()->GetStop() > rtInvalidate) { +#if SUBPIC_TRACE_LEVEL > 2 + const CComPtr& pSubPic = m_queue.GetTail(); + REFERENCE_TIME rtStart = pSubPic->GetStart(); + REFERENCE_TIME rtStop = pSubPic->GetStop(); + REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); + TRACE(_T(" %.3f -> %.3f -> %.3f\n"), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop)); +#endif + m_queue.RemoveTailNoReturn(); +#if SUBPIC_TRACE_LEVEL > 0 + TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); +#endif + } + + // If we invalidate in the past, always give the queue a chance to re-render the modified subtitles + if (rtInvalidate < m_rtNow) { + m_rtNow = std::max(rtInvalidate, 0LL); + } + + lockQueue.unlock(); + m_condQueueFull.notify_one(); + m_runQueueEvent.Set(); + + return S_OK; +} + +STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, CComPtr& ppSubPic) +{ + // Old version of LookupSubPic, keep legacy behavior and never try to block + return LookupSubPic(rtNow, false, ppSubPic); +} + +STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& ppSubPic) +{ + bool bStopSearch = false; + + { + std::lock_guard lock(m_mutexSubpic); + + // See if we can reuse the latest subpic + if (m_pSubPic) { + REFERENCE_TIME rtSegmentStart = m_pSubPic->GetSegmentStart(); + REFERENCE_TIME rtSegmentStop = m_pSubPic->GetSegmentStop(); + + if (rtSegmentStart <= rtNow && rtNow < rtSegmentStop) { + ppSubPic = m_pSubPic; + + REFERENCE_TIME rtStart = m_pSubPic->GetStart(); + REFERENCE_TIME rtStop = m_pSubPic->GetStop(); + + if (rtStart <= rtNow && rtNow < rtStop) { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("LookupSubPic: Exact match on the latest subpic, rtNow=%.3f rtSegmentStart=%.3f rtSegmentStop=%.3f\n"), RT2SEC(rtNow), RT2SEC(rtSegmentStart), RT2SEC(rtSegmentStop)); +#endif + bStopSearch = true; + } else { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("LookupSubPic: Possible match on the latest subpic, rtNow=%.3f rtStart=%.3f rtStop=%.3f\n"), RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop)); +#endif + } + } else if (rtSegmentStop <= rtNow) { + m_pSubPic.Release(); + } + } + } + + bool bTryBlocking = bAdviseBlocking || !m_settings.bAllowDroppingSubpic; + while (!bStopSearch) { + // Look for the subpic in the queue + { + std::unique_lock lock(m_mutexQueue); + +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("LookupSubPic: Searching the queue, rtNow=%.3f\n"), RT2SEC(rtNow)); +#endif + + while (!m_queue.IsEmpty() && !bStopSearch) { + const CComPtr& pSubPic = m_queue.GetHead(); + REFERENCE_TIME rtSegmentStart = pSubPic->GetSegmentStart(); + + if (rtSegmentStart > rtNow) { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("rtSegmentStart > rtNow, stopping the search, rtSegmentStart=%.3f\n"), RT2SEC(rtSegmentStart)); +#endif + bStopSearch = true; + } else { // rtSegmentStart <= rtNow + bool bRemoveFromQueue = true; + REFERENCE_TIME rtStart = pSubPic->GetStart(); + REFERENCE_TIME rtStop = pSubPic->GetStop(); + REFERENCE_TIME rtSegmentStop = pSubPic->GetSegmentStop(); + + if (rtSegmentStop <= rtNow) { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("Removing old subpic (rtNow=%.3f): %.3f -> %.3f -> %.3f\n"), + RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop)); +#endif + } else { // rtNow < rtSegmentStop + if (rtStart <= rtNow && rtNow < rtStop) { +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("Exact match found in the queue\n")); +#endif + ppSubPic = pSubPic; + bStopSearch = true; + } else if (rtNow >= rtStop) { + // Reuse old subpic + ppSubPic = pSubPic; + } else { // rtNow < rtStart + if (!ppSubPic || ppSubPic->GetStop() <= rtNow) { + // Should be really rare that we use a subpic in advance + // unless we mispredicted the timing slightly + ppSubPic = pSubPic; + } else { + bRemoveFromQueue = false; + } + bStopSearch = true; + } + } + + if (bRemoveFromQueue) { + m_queue.RemoveHeadNoReturn(); +#if SUBPIC_TRACE_LEVEL > 0 + TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); +#endif + } + } + } + + lock.unlock(); + m_condQueueFull.notify_one(); + } + + // If we didn't get any subpic yet and blocking is advised, just try harder to get one + if (!ppSubPic && bTryBlocking) { + bTryBlocking = false; + bStopSearch = true; + + auto pSubPicProviderWithSharedLock = GetSubPicProviderWithSharedLock(); + if (pSubPicProviderWithSharedLock && SUCCEEDED(pSubPicProviderWithSharedLock->Lock())) { + auto& pSubPicProvider = pSubPicProviderWithSharedLock->pSubPicProvider; + double fps = m_fps; + if (POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps)) { + REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); + REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); + if (rtStart <= rtNow && rtNow < rtStop) { + bStopSearch = false; + } + } + pSubPicProviderWithSharedLock->Unlock(); + + if (!bStopSearch && m_settings.nSize) { + std::unique_lock lock(m_mutexQueue); + + auto queueReady = [this, rtNow]() { + return ((int)m_queue.GetCount() == m_settings.nSize) + || (!m_queue.IsEmpty() && m_queue.GetTail()->GetStop() > rtNow); + }; + + std::chrono::milliseconds timeoutPeriod(250); + m_condQueueReady.wait_for(lock, timeoutPeriod, queueReady); + } + } + } else { + bStopSearch = true; + } + } + + if (ppSubPic) { + // Save the subpic for later reuse + std::lock_guard lock(m_mutexSubpic); + m_pSubPic = ppSubPic; + +#if SUBPIC_TRACE_LEVEL > 0 + REFERENCE_TIME rtStart = ppSubPic->GetStart(); + REFERENCE_TIME rtStop = ppSubPic->GetStop(); + REFERENCE_TIME rtSegmentStop = ppSubPic->GetSegmentStop(); + CRect r; + ppSubPic->GetDirtyRect(&r); + TRACE(_T("Display at %.3f: %.3f -> %.3f -> %.3f (%dx%d)\n"), + RT2SEC(rtNow), RT2SEC(rtStart), RT2SEC(rtStop), RT2SEC(rtSegmentStop), + r.Width(), r.Height()); +#endif + } else { +#if SUBPIC_TRACE_LEVEL > 1 + TRACE(_T("No subpicture to display at %.3f\n"), RT2SEC(rtNow)); +#endif + } + + return !!ppSubPic; +} + +STDMETHODIMP CSubPicQueue::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) +{ + std::lock_guard lock(m_mutexQueue); + + nSubPics = (int)m_queue.GetCount(); + rtNow = m_rtNow; + if (nSubPics) { + rtStart = m_queue.GetHead()->GetStart(); + rtStop = m_queue.GetTail()->GetStop(); + } else { + rtStart = rtStop = 0; + } + + return S_OK; +} + +STDMETHODIMP CSubPicQueue::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) +{ + std::lock_guard lock(m_mutexQueue); + + HRESULT hr = E_INVALIDARG; + + if (nSubPic >= 0 && nSubPic < (int)m_queue.GetCount()) { + if (POSITION pos = m_queue.FindIndex(nSubPic)) { + rtStart = m_queue.GetAt(pos)->GetStart(); + rtStop = m_queue.GetAt(pos)->GetStop(); + hr = S_OK; + } else { + // Can't happen + ASSERT(FALSE); + } + } else { + rtStart = rtStop = -1; + } + + return hr; +} + +// private + +bool CSubPicQueue::EnqueueSubPic(CComPtr& pSubPic, bool bBlocking) +{ + auto canAddToQueue = [this]() { + return (int)m_queue.GetCount() < m_settings.nSize; + }; + + bool bAdded = false; + + std::unique_lock lock(m_mutexQueue); + if (bBlocking) { + // Wait for enough room in the queue + m_condQueueFull.wait(lock, canAddToQueue); + } + + if (canAddToQueue()) { + if (m_bInvalidate && pSubPic->GetStop() > m_rtInvalidate) { +#if SUBPIC_TRACE_LEVEL > 1 | SUBPIC_TRACE_DROP + TRACE(_T("Subtitle Renderer Thread: Dropping rendered subpic because of invalidation\n")); +#endif + } else { + m_queue.AddTail(pSubPic); +#if SUBPIC_TRACE_LEVEL > 0 + TRACE(_T("subpic queue size = %d\n"), (int)m_queue.GetCount()); +#endif + lock.unlock(); + m_condQueueReady.notify_one(); + bAdded = true; + } + pSubPic.Release(); + } + + return bAdded; +} + +REFERENCE_TIME CSubPicQueue::GetCurrentRenderingTime() +{ + REFERENCE_TIME rtNow = -1; + + { + std::lock_guard lock(m_mutexQueue); + + if (!m_queue.IsEmpty()) { + rtNow = m_queue.GetTail()->GetStop(); + } + } + + return std::max(rtNow, m_rtNow); +} + +// overrides + +DWORD CSubPicQueue::ThreadProc() +{ + bool bDisableAnim = m_settings.bDisableSubtitleAnimation; + SetThreadName(DWORD(-1), "Subtitle Renderer Thread"); + SetThreadPriority(m_hThread, bDisableAnim ? THREAD_PRIORITY_LOWEST : THREAD_PRIORITY_ABOVE_NORMAL); + + bool bWaitForEvent = false; + for (; !m_bExitThread;) { + // When we have nothing to render, we just wait a bit + if (bWaitForEvent) { + bWaitForEvent = false; + m_runQueueEvent.Wait(); + } + + auto pSubPicProviderWithSharedLock = GetSubPicProviderWithSharedLock(); + if (pSubPicProviderWithSharedLock && SUCCEEDED(pSubPicProviderWithSharedLock->Lock())) { + auto& pSubPicProvider = pSubPicProviderWithSharedLock->pSubPicProvider; + double fps = m_fps; + REFERENCE_TIME rtTimePerFrame = m_rtTimePerFrame; + REFERENCE_TIME rtTimePerSubFrame = m_rtTimePerSubFrame; + m_bInvalidate = false; + CComPtr pSubPic; + + REFERENCE_TIME rtStartRendering = GetCurrentRenderingTime(); + POSITION pos = pSubPicProvider->GetStartPosition(rtStartRendering, fps); + if (!pos) { + bWaitForEvent = true; + } + for (; pos; pos = pSubPicProvider->GetNext(pos)) { + REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps); + REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); + + // We are already one minute ahead, this should be enough + if (rtStart >= m_rtNow + 60 * 10000000i64) { + bWaitForEvent = true; + break; + } + +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("New subtitle sample: Start=%.3f Stop=%.3f\n"), RT2SEC(rtStart), RT2SEC(rtStop)); +#endif + + REFERENCE_TIME rtCurrent = std::max(rtStart, rtStartRendering); + if (rtCurrent < m_rtNow) { + rtCurrent = m_rtNow; + } else { +#if 0 + // FIXME: what is the purpose of this? + if (rtTimePerFrame <= rtStop - rtStart) { + // Round current time to the next estimated video frame timing + REFERENCE_TIME rtCurrentRounded = (rtCurrent / rtTimePerFrame) * rtTimePerFrame; + if (rtCurrentRounded < rtCurrent) { + rtCurrent = rtCurrentRounded + rtTimePerFrame; + } + } +#endif + } + + // Check that we aren't late already... + if (rtCurrent <= rtStop) { + bool bIsAnimated = pSubPicProvider->IsAnimated(pos) && !bDisableAnim; + bool bStopRendering = false; + + while (rtCurrent < rtStop) { + SIZE maxTextureSize, virtualSize; + POINT virtualTopLeft; + HRESULT hr2; + + if (SUCCEEDED(hr2 = pSubPicProvider->GetTextureSize(pos, maxTextureSize, virtualSize, virtualTopLeft))) { + m_pAllocator->SetMaxTextureSize(maxTextureSize); + m_pAllocator->SetCurSize(maxTextureSize); + } + + CComPtr pStatic; + if (FAILED(m_pAllocator->GetStatic(&pStatic))) { + break; + } + + REFERENCE_TIME rtStopReal; + if (rtStop == ISubPicProvider::UNKNOWN_TIME) { // Special case for subtitles with unknown end time + // Force a one frame duration + rtStopReal = rtCurrent + rtTimePerFrame; + } else { + rtStopReal = rtStop; + } + + HRESULT hr; + if (bIsAnimated) { + // 3/4 is a magic number we use to avoid reusing the wrong frame due to slight + // misprediction of the frame end time + hr = RenderTo(pStatic, rtCurrent, std::min(rtCurrent + rtTimePerSubFrame * 3 / 4, rtStopReal), fps, bIsAnimated); +#if SUBPIC_TRACE_LEVEL > 2 + TRACE(_T("rtCurrent=%.3f Start=%.3f SegmentStart=%.3f SegmentStop=%.3f Stop=%.3f\n"), RT2SEC(rtCurrent), RT2SEC(pStatic->GetStart()), RT2SEC(pStatic->GetSegmentStart()), RT2SEC(pStatic->GetSegmentStop()), RT2SEC(pStatic->GetStop())); +#endif + // Set the segment start and stop timings + pStatic->SetSegmentStart(rtStart); + // The stop timing can be moved so that the duration from the current start time + // of the subpic to the segment end is always at least one video frame long. This + // avoids missing subtitle frame due to rounding errors in the timings. + // At worst this can cause a segment to be displayed for one more frame than expected + // but it's much less annoying than having the subtitle disappearing for one frame + pStatic->SetSegmentStop(std::max(rtCurrent + rtTimePerFrame, rtStopReal)); + rtCurrent = std::min(rtCurrent + rtTimePerSubFrame, rtStopReal); + } else { + hr = RenderTo(pStatic, rtStart, rtStopReal, fps, false); + // Non-animated subtitles aren't part of a segment + pStatic->SetSegmentStart(ISubPic::INVALID_SUBPIC_TIME); + pStatic->SetSegmentStop(ISubPic::INVALID_SUBPIC_TIME); + rtCurrent = rtStopReal; + } + + if (FAILED(hr)) { + break; + } + +#if SUBPIC_TRACE_LEVEL > 1 + CRect r; + pStatic->GetDirtyRect(&r); + TRACE(_T("Subtitle Renderer Thread: Render %.3f -> %.3f -> %.3f -> %.3f res=%dx%d\n"), + RT2SEC(rtStart), RT2SEC(pStatic->GetStart()), RT2SEC(pStatic->GetStop()), RT2SEC(rtStop), + r.Width(), r.Height()); +#endif + + pSubPic.Release(); + if (FAILED(m_pAllocator->AllocDynamic(&pSubPic)) + || FAILED(pStatic->CopyTo(pSubPic))) { + break; + } + + if (SUCCEEDED(hr2)) { + pSubPic->SetVirtualTextureSize(virtualSize, virtualTopLeft); + } + + RelativeTo relativeTo; + if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { + pSubPic->SetRelativeTo(relativeTo); + } + + // Try to enqueue the subpic, if the queue is full stop rendering + if (!EnqueueSubPic(pSubPic, false)) { + bStopRendering = true; + break; + } + + if (m_rtNow > rtCurrent) { +#if SUBPIC_TRACE_LEVEL > 0 | SUBPIC_TRACE_DROP + TRACE(_T("Subtitle Renderer Thread: the queue is late, rtCurrent = %.03f rtNow = %.03f \n"), RT2SEC(rtCurrent), RT2SEC(m_rtNow)); +#endif + rtCurrent = m_rtNow; + } + } + + if (bStopRendering) { + break; + } + } else { +#if SUBPIC_TRACE_LEVEL > 0 | SUBPIC_TRACE_DROP + TRACE(_T("Subtitle Renderer Thread: the queue is late, rtCurrent = %.03f rtStart = %.03f rtStop = %.03f\n"), RT2SEC(rtCurrent), RT2SEC(rtStart), RT2SEC(rtStop)); +#endif + } + } + + pSubPicProviderWithSharedLock->Unlock(); + + // If we couldn't enqueue the subpic before, wait for some room in the queue + // but unsure to unlock the subpicture provider first to avoid deadlocks + if (pSubPic) { + EnqueueSubPic(pSubPic, true); + } + } else { + bWaitForEvent = true; + } + } + + return 0; +} + +// +// CSubPicQueueNoThread +// + +CSubPicQueueNoThread::CSubPicQueueNoThread(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr) + : CSubPicQueueImpl(settings, pAllocator, phr) +{ + if (phr && SUCCEEDED(*phr) && m_settings.nSize != 0) { + *phr = E_INVALIDARG; + } +} + +CSubPicQueueNoThread::~CSubPicQueueNoThread() +{ + if (m_pAllocator) { + m_pAllocator->FreeStatic(); + } +} + +// ISubPicQueue + +STDMETHODIMP CSubPicQueueNoThread::SetFPS(double fps) +{ + HRESULT hr = __super::SetFPS(fps); + if (FAILED(hr)) { + return hr; + } + + if (m_settings.nAnimationRate == 100) { // Special case when rendering at full speed + // Ensure the subtitle will really be updated every frame by setting a really small duration + m_rtTimePerSubFrame = 1; + } else { + m_rtTimePerSubFrame = std::llround(10000000.0 / (m_fps * m_settings.nAnimationRate / 100.0)); + } + + return S_OK; +} + +STDMETHODIMP CSubPicQueueNoThread::Invalidate(REFERENCE_TIME rtInvalidate /*= -1*/) +{ + CAutoLock cQueueLock(&m_csLock); + + if (m_pSubPic && m_pSubPic->GetStop() > rtInvalidate) { + m_pSubPic = nullptr; + } + + return S_OK; +} + +STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, CComPtr& ppSubPic) +{ + // CSubPicQueueNoThread is always blocking so bAdviseBlocking doesn't matter anyway + return LookupSubPic(rtNow, true, ppSubPic); +} + +STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, bool /*bAdviseBlocking*/, CComPtr& ppSubPic) +{ + // CSubPicQueueNoThread is always blocking so we ignore bAdviseBlocking + + CComPtr pSubPic; + + { + CAutoLock cAutoLock(&m_csLock); + + pSubPic = m_pSubPic; + } + + if (pSubPic && pSubPic->GetStart() <= rtNow && rtNow < pSubPic->GetStop()) { + ppSubPic = pSubPic; + } else { + CComPtr pSubPicProvider; + if (SUCCEEDED(GetSubPicProvider(&pSubPicProvider)) && pSubPicProvider + && SUCCEEDED(pSubPicProvider->Lock())) { + double fps = m_fps; + POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps); + if (pos) { + REFERENCE_TIME rtStart; + REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps); + bool bAnimated = pSubPicProvider->IsAnimated(pos) && !m_settings.bDisableSubtitleAnimation; + + // Special case for subtitles with unknown end time + if (rtStop == ISubPicProvider::UNKNOWN_TIME) { + // Force a one frame duration + rtStop = rtNow + 1; + } + + if (bAnimated) { + rtStart = rtNow; + rtStop = std::min(rtNow + m_rtTimePerSubFrame, rtStop); + } else { + rtStart = pSubPicProvider->GetStart(pos, fps); + } + + if (rtStart <= rtNow && rtNow < rtStop) { + bool bAllocSubPic = !pSubPic; + SIZE maxTextureSize, virtualSize; + POINT virtualTopLeft; + HRESULT hr; + if (SUCCEEDED(hr = pSubPicProvider->GetTextureSize(pos, maxTextureSize, virtualSize, virtualTopLeft))) { + m_pAllocator->SetMaxTextureSize(maxTextureSize); + m_pAllocator->SetCurSize(maxTextureSize); + if (!bAllocSubPic) { + // Ensure the previously allocated subpic is big enough to hold the subtitle to be rendered + SIZE maxSize = {0L,0L}; + bAllocSubPic = FAILED(pSubPic->GetMaxSize(&maxSize)) || maxSize.cx < maxTextureSize.cx || maxSize.cy < maxTextureSize.cy; + if (bAllocSubPic) { + TRACE(_T("AllocSubPic required: maxSize=%dx%d maxTextureSize=%dx%d\n"), maxSize.cx, maxSize.cy, maxTextureSize.cx, maxTextureSize.cy); + } + } + } + + if (bAllocSubPic) { + CAutoLock cAutoLock(&m_csLock); + + m_pSubPic.Release(); + + if (FAILED(m_pAllocator->AllocDynamic(&m_pSubPic))) { + TRACE(_T("CSubPicQueueNoThread::LookupSubPic -> AllocDynamic failed\n")); + pSubPicProvider->Unlock(); + return false; + } + + pSubPic = m_pSubPic; + } + + if (m_pAllocator->IsDynamicWriteOnly()) { + CComPtr pStatic; + if (SUCCEEDED(m_pAllocator->GetStatic(&pStatic)) + && SUCCEEDED(RenderTo(pStatic, rtStart, rtStop, fps, bAnimated)) + && SUCCEEDED(pStatic->CopyTo(pSubPic))) { + ppSubPic = pSubPic; + } + } else { + if (SUCCEEDED(RenderTo(pSubPic, rtStart, rtStop, fps, bAnimated))) { + ppSubPic = pSubPic; + } + } + + if (ppSubPic) { + if (SUCCEEDED(hr)) { + ppSubPic->SetVirtualTextureSize(virtualSize, virtualTopLeft); + } + + RelativeTo relativeTo; + if (SUCCEEDED(pSubPicProvider->GetRelativeTo(pos, relativeTo))) { + ppSubPic->SetRelativeTo(relativeTo); + } + } + } + } + + pSubPicProvider->Unlock(); + } + } + + return !!ppSubPic; +} + +STDMETHODIMP CSubPicQueueNoThread::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) +{ + CAutoLock cAutoLock(&m_csLock); + + rtNow = m_rtNow; + + if (m_pSubPic) { + nSubPics = 1; + rtStart = m_pSubPic->GetStart(); + rtStop = m_pSubPic->GetStop(); + } else { + nSubPics = 0; + rtStart = rtStop = 0; + } + + return S_OK; +} + +STDMETHODIMP CSubPicQueueNoThread::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) +{ + CAutoLock cAutoLock(&m_csLock); + + if (!m_pSubPic || nSubPic != 0) { + return E_INVALIDARG; + } + + rtStart = m_pSubPic->GetStart(); + rtStop = m_pSubPic->GetStop(); + + return S_OK; +} diff --git a/src/SubPic/SubPicQueueImpl.h b/src/SubPic/SubPicQueueImpl.h index 16d08bd6f54..630bd074b9d 100644 --- a/src/SubPic/SubPicQueueImpl.h +++ b/src/SubPic/SubPicQueueImpl.h @@ -1,193 +1,193 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include -#include -#include - -#include "ISubPic.h" -#include "SubPicQueueSettings.h" - -class CSubPicQueueImpl : public CUnknown, public ISubPicQueue -{ - static const double DEFAULT_FPS; - -protected: - struct SubPicProviderWithSharedLock { - private: - unsigned int m_nRef = 0; - std::mutex m_mutex; - - public: - const CComPtr pSubPicProvider; - - SubPicProviderWithSharedLock(const CComPtr& pSubPicProvider) - : pSubPicProvider(pSubPicProvider) { - } - - HRESULT Lock() { - HRESULT hr; - - if (pSubPicProvider) { - std::lock_guard lock(m_mutex); - - hr = S_OK; - if ((m_nRef == 0 && SUCCEEDED(hr = pSubPicProvider->Lock())) - || m_nRef > 0) { - m_nRef++; - } - } else { - hr = E_POINTER; - } - - return hr; - } - - HRESULT Unlock() { - HRESULT hr; - - if (pSubPicProvider) { - std::lock_guard lock(m_mutex); - - hr = S_OK; - if ((m_nRef == 1 && SUCCEEDED(hr = pSubPicProvider->Unlock())) - || m_nRef > 1) { - m_nRef--; - } - } else { - hr = E_POINTER; - } - - return hr; - } - }; - -private: - CCritSec m_csSubPicProvider; - std::shared_ptr m_pSubPicProviderWithSharedLock; - -protected: - double m_fps; - REFERENCE_TIME m_rtTimePerFrame; - REFERENCE_TIME m_rtTimePerSubFrame; - REFERENCE_TIME m_rtNow; - - SubPicQueueSettings m_settings; - - CComPtr m_pAllocator; - - std::shared_ptr GetSubPicProviderWithSharedLock() { - CAutoLock cAutoLock(&m_csSubPicProvider); - return m_pSubPicProviderWithSharedLock; - } - - HRESULT RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps, BOOL bIsAnimated); - -public: - CSubPicQueueImpl(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); - virtual ~CSubPicQueueImpl(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicQueue - - STDMETHODIMP SetSubPicProvider(ISubPicProvider* pSubPicProvider); - STDMETHODIMP GetSubPicProvider(ISubPicProvider** pSubPicProvider); - - STDMETHODIMP SetFPS(double fps); - STDMETHODIMP SetTime(REFERENCE_TIME rtNow); - /* - STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1) PURE; - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, ISubPic** ppSubPic) PURE; - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); - - STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) PURE; - STDMETHODIMP GetStats(int nSubPics, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) PURE; - */ -}; - -class CSubPicQueue : public CSubPicQueueImpl, protected CAMThread -{ -protected: - bool m_bExitThread; - - CComPtr m_pSubPic; - CInterfaceList m_queue; - - std::mutex m_mutexSubpic; // to protect m_pSubPic - std::mutex m_mutexQueue; // to protect m_queue - std::condition_variable m_condQueueFull; - std::condition_variable m_condQueueReady; - - CAMEvent m_runQueueEvent; - - REFERENCE_TIME m_rtNowLast; - - bool m_bInvalidate; - REFERENCE_TIME m_rtInvalidate; - - bool EnqueueSubPic(CComPtr& pSubPic, bool bBlocking); - REFERENCE_TIME GetCurrentRenderingTime(); - - // CAMThread - virtual DWORD ThreadProc(); - -public: - CSubPicQueue(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); - virtual ~CSubPicQueue(); - - // ISubPicQueue - - STDMETHODIMP SetFPS(double fps); - STDMETHODIMP SetTime(REFERENCE_TIME rtNow); - - STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1); - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, CComPtr& pSubPic); - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); - - STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); - STDMETHODIMP GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); -}; - -class CSubPicQueueNoThread : public CSubPicQueueImpl -{ -protected: - CCritSec m_csLock; - CComPtr m_pSubPic; - -public: - CSubPicQueueNoThread(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); - virtual ~CSubPicQueueNoThread(); - - // ISubPicQueue - - STDMETHODIMP SetFPS(double fps); - - STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1); - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, CComPtr& pSubPic); - STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); - - STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); - STDMETHODIMP GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include +#include +#include + +#include "ISubPic.h" +#include "SubPicQueueSettings.h" + +class CSubPicQueueImpl : public CUnknown, public ISubPicQueue +{ + static const double DEFAULT_FPS; + +protected: + struct SubPicProviderWithSharedLock { + private: + unsigned int m_nRef = 0; + std::mutex m_mutex; + + public: + const CComPtr pSubPicProvider; + + SubPicProviderWithSharedLock(const CComPtr& pSubPicProvider) + : pSubPicProvider(pSubPicProvider) { + } + + HRESULT Lock() { + HRESULT hr; + + if (pSubPicProvider) { + std::lock_guard lock(m_mutex); + + hr = S_OK; + if ((m_nRef == 0 && SUCCEEDED(hr = pSubPicProvider->Lock())) + || m_nRef > 0) { + m_nRef++; + } + } else { + hr = E_POINTER; + } + + return hr; + } + + HRESULT Unlock() { + HRESULT hr; + + if (pSubPicProvider) { + std::lock_guard lock(m_mutex); + + hr = S_OK; + if ((m_nRef == 1 && SUCCEEDED(hr = pSubPicProvider->Unlock())) + || m_nRef > 1) { + m_nRef--; + } + } else { + hr = E_POINTER; + } + + return hr; + } + }; + +private: + CCritSec m_csSubPicProvider; + std::shared_ptr m_pSubPicProviderWithSharedLock; + +protected: + double m_fps; + REFERENCE_TIME m_rtTimePerFrame; + REFERENCE_TIME m_rtTimePerSubFrame; + REFERENCE_TIME m_rtNow; + + SubPicQueueSettings m_settings; + + CComPtr m_pAllocator; + + std::shared_ptr GetSubPicProviderWithSharedLock() { + CAutoLock cAutoLock(&m_csSubPicProvider); + return m_pSubPicProviderWithSharedLock; + } + + HRESULT RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps, BOOL bIsAnimated); + +public: + CSubPicQueueImpl(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); + virtual ~CSubPicQueueImpl(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicQueue + + STDMETHODIMP SetSubPicProvider(ISubPicProvider* pSubPicProvider); + STDMETHODIMP GetSubPicProvider(ISubPicProvider** pSubPicProvider); + + STDMETHODIMP SetFPS(double fps); + STDMETHODIMP SetTime(REFERENCE_TIME rtNow); + /* + STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1) PURE; + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, ISubPic** ppSubPic) PURE; + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); + + STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) PURE; + STDMETHODIMP GetStats(int nSubPics, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop) PURE; + */ +}; + +class CSubPicQueue : public CSubPicQueueImpl, protected CAMThread +{ +protected: + bool m_bExitThread; + + CComPtr m_pSubPic; + CInterfaceList m_queue; + + std::mutex m_mutexSubpic; // to protect m_pSubPic + std::mutex m_mutexQueue; // to protect m_queue + std::condition_variable m_condQueueFull; + std::condition_variable m_condQueueReady; + + CAMEvent m_runQueueEvent; + + REFERENCE_TIME m_rtNowLast; + + bool m_bInvalidate; + REFERENCE_TIME m_rtInvalidate; + + bool EnqueueSubPic(CComPtr& pSubPic, bool bBlocking); + REFERENCE_TIME GetCurrentRenderingTime(); + + // CAMThread + virtual DWORD ThreadProc(); + +public: + CSubPicQueue(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); + virtual ~CSubPicQueue(); + + // ISubPicQueue + + STDMETHODIMP SetFPS(double fps); + STDMETHODIMP SetTime(REFERENCE_TIME rtNow); + + STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1); + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, CComPtr& pSubPic); + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); + + STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); + STDMETHODIMP GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); +}; + +class CSubPicQueueNoThread : public CSubPicQueueImpl +{ +protected: + CCritSec m_csLock; + CComPtr m_pSubPic; + +public: + CSubPicQueueNoThread(SubPicQueueSettings settings, ISubPicAllocator* pAllocator, HRESULT* phr); + virtual ~CSubPicQueueNoThread(); + + // ISubPicQueue + + STDMETHODIMP SetFPS(double fps); + + STDMETHODIMP Invalidate(REFERENCE_TIME rtInvalidate = -1); + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, CComPtr& pSubPic); + STDMETHODIMP_(bool) LookupSubPic(REFERENCE_TIME rtNow, bool bAdviseBlocking, CComPtr& pSubPic); + + STDMETHODIMP GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); + STDMETHODIMP GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop); +}; diff --git a/src/SubPic/stdafx.cpp b/src/SubPic/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/SubPic/stdafx.cpp +++ b/src/SubPic/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/SubPic/stdafx.h b/src/SubPic/stdafx.h index eeb933aed07..dc4071968a8 100644 --- a/src/SubPic/stdafx.h +++ b/src/SubPic/stdafx.h @@ -1,39 +1,39 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include -#include "../DSUtil/DSUtil.h" - -#include -#include -#include +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include +#include "../DSUtil/DSUtil.h" + +#include +#include +#include diff --git a/src/Subtitles/CCDecoder.cpp b/src/Subtitles/CCDecoder.cpp index 56e62a956d6..5a54f73d168 100644 --- a/src/Subtitles/CCDecoder.cpp +++ b/src/Subtitles/CCDecoder.cpp @@ -1,390 +1,390 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "CCDecoder.h" -#include "SubtitleHelpers.h" - -CCDecoder::CCDecoder(CString fn, CString rawfn) : m_fn(fn), m_rawfn(rawfn) -{ - m_sts.CreateDefaultStyle(ANSI_CHARSET); - - m_time = 0; - m_fEndOfCaption = false; - ZeroMemory(m_buff, sizeof(m_buff)); - ZeroMemory(m_disp, sizeof(m_disp)); - m_cursor = CPoint(0, 0); - - if (!m_rawfn.IsEmpty()) { - _tremove(m_rawfn); - } -} - -CCDecoder::~CCDecoder() -{ - if (!m_sts.IsEmpty() && !m_fn.IsEmpty()) { - m_sts.Sort(); - m_sts.SaveAs(m_fn, Subtitle::SRT, -1, 0, CTextFile::DEFAULT_ENCODING); - m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf8.srt"), Subtitle::SRT, -1, 0, CTextFile::UTF8); - m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf16le.srt"), Subtitle::SRT, -1, 0, CTextFile::LE16); - m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf16be.srt"), Subtitle::SRT, -1, 0, CTextFile::BE16); - } -} - -void CCDecoder::MoveCursor(int x, int y) -{ - m_cursor = CPoint(x, y); - if (m_cursor.x < 0) { - m_cursor.x = 0; - } - if (m_cursor.y < 0) { - m_cursor.y = 0; - } - if (m_cursor.x >= 32) { - m_cursor.x = 0, m_cursor.y++; - } - if (m_cursor.y >= 16) { - m_cursor.y = 0; - } -} - -void CCDecoder::OffsetCursor(int x, int y) -{ - MoveCursor(m_cursor.x + x, m_cursor.y + y); -} - -void CCDecoder::PutChar(WCHAR c) -{ - m_buff[m_cursor.y][m_cursor.x] = c; - OffsetCursor(1, 0); -} - -void CCDecoder::SaveDisp(__int64 time) -{ - CStringW str; - - for (size_t row = 0; row < 16; row++) { - bool fNonEmptyRow = false; - - for (size_t col = 0; col < 32; col++) { - if (m_disp[row][col]) { - CStringW str2(&m_disp[row][col]); - if (fNonEmptyRow) { - str += L' '; - } - str += str2; - col += str2.GetLength(); - fNonEmptyRow = true; - } - } - - if (fNonEmptyRow) { - str += L'\n'; - } - } - - if (str.IsEmpty()) { - return; - } - - m_sts.Add(str, true, (int)m_time, (int)time); -} - -void CCDecoder::DecodeCC(const BYTE* buff, int len, __int64 time) -{ - if (!m_rawfn.IsEmpty()) { - FILE* f = nullptr; - if (!_tfopen_s(&f, m_rawfn, _T("at"))) { - _ftprintf_s(f, _T("%02d:%02d:%02d.%03d\n"), - (int)(time / 1000 / 60 / 60), - (int)((time / 1000 / 60) % 60), - (int)((time / 1000) % 60), - (int)(time % 1000)); - - for (ptrdiff_t i = 0; i < len; i++) { - _ftprintf_s(f, _T("%02x"), buff[i]); - if (i < len - 1) { - _ftprintf_s(f, _T(" ")); - } - if (i > 0 && (i & 15) == 15) { - _ftprintf_s(f, _T("\n")); - } - } - if (len > 0) { - _ftprintf_s(f, _T("\n\n")); - } - fclose(f); - } - } - - for (ptrdiff_t i = 0; i < len; i++) { - BYTE c = buff[i] & 0x7f; - if (c >= 0x20) { - static WCHAR charmap[0x60] = { - ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', 0xE1, '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', 0x3F, - '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', 0xE9, ']', 0xED, 0xF3, - 0xFA, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xE7, 0xF7, 'N', 'n', 0x3F - }; - - PutChar(charmap[c - 0x20]); - } else if (i < len - 1 && buff[i] != 0x80) { - // codes and special characters are supposed to be doubled - if (i < len - 3 && buff[i] == buff[i + 2] && buff[i + 1] == buff[i + 3]) { - i += 2; - } - - c = buff[i + 1] & 0x7f; - if (buff[i] == 0x91 && c >= 0x20 && c < 0x30) { // formating - // TODO - } else if (buff[i] == 0x91 && c == 0x39) { // transparent space - OffsetCursor(1, 0); - } else if (buff[i] == 0x91 && c >= 0x30 && c < 0x40) { // special characters - static WCHAR charmap[0x10] = { - 0x00ae, // (r)egistered - 0x00b0, // degree - 0x00bd, // 1/2 - 0x00bf, // inverted question mark - 0x2122, // trade mark - 0x00a2, // cent - 0x00a3, // pound - 0x266a, // music - 0x00e0, // a` - 0x00ff, // transparent space, handled above - 0x00e8, // e` - 0x00e2, // a^ - 0x00ea, // e^ - 0x00ee, // i^ - 0x00f4, // o^ - 0x00fb, // u^ - }; - - PutChar(charmap[c - 0x30]); - } else if (buff[i] == 0x92 && c >= 0x20 && c < 0x40) { // extended characters - static WCHAR charmap[0x20] = { - 0x00c0, // A' - 0x00c9, // E' - 0x00d3, // O' - 0x00da, // U' - 0x00dc, // U: - 0x00fc, // u: - 0x2018, // ` - 0x00a1, // inverted ! - 0x002a, // * - 0x2019, // ' - 0x002d, // - - 0x00a9, // (c)opyright - 0x2120, // SM - 0x00b7, // . (dot in the middle) - 0x201c, // inverted " - 0x201d, // " - - 0x00c1, // A` - 0x00c2, // A^ - 0x00c7, // C, - 0x00c8, // E` - 0x00ca, // E^ - 0x00cb, // E: - 0x00eb, // e: - 0x00ce, // I^ - 0x00cf, // I: - 0x00ef, // i: - 0x00d4, // O^ - 0x00d9, // U` - 0x00f9, // u` - 0x00db, // U^ - 0x00ab, // << - 0x00bb, // >> - }; - - PutChar(charmap[c - 0x20]); - } else if (buff[i] == 0x13 && c >= 0x20 && c < 0x40) { // more extended characters - static WCHAR charmap[0x20] = { - 0x00c3, // A~ - 0x00e3, // a~ - 0x00cd, // I' - 0x00cc, // I` - 0x00ec, // i` - 0x00d2, // O` - 0x00f2, // o` - 0x00d5, // O~ - 0x00f5, // o~ - 0x007b, // { - 0x007d, // } - 0x005c, // /* \ */ - 0x005e, // ^ - 0x005f, // _ - 0x00a6, // | - 0x007e, // ~ - - 0x00c4, // A: - 0x00e4, // a: - 0x00d6, // O: - 0x00f6, // o: - 0x00df, // B (ss in german) - 0x00a5, // Y= - 0x00a4, // ox - 0x007c, // | - 0x00c5, // Ao - 0x00e5, // ao - 0x00d8, // O/ - 0x00f8, // o/ - 0x250c, // |- - 0x2510, // -| - 0x2514, // |_ - 0x2518, // _| - }; - - PutChar(charmap[c - 0x20]); - } else if (buff[i] == 0x94 && buff[i + 1] == 0xae) { // Erase Non-displayed [buffer] Memory - ZeroMemory(m_buff, sizeof(m_buff)); - } else if (buff[i] == 0x94 && buff[i + 1] == 0x20) { // Resume Caption Loading - ZeroMemory(m_buff, sizeof(m_buff)); - } else if (buff[i] == 0x94 && buff[i + 1] == 0x2f) { // End Of Caption - if (memcmp(m_disp, m_buff, sizeof(m_disp)) != 0) { - if (m_fEndOfCaption) { - SaveDisp(time + (i / 2) * 1000 / 30); - } - - m_fEndOfCaption = true; - memcpy(m_disp, m_buff, sizeof(m_disp)); - m_time = time + (i / 2) * 1000 / 30; - } - } else if (buff[i] == 0x94 && buff[i + 1] == 0x2c) { // Erase Displayed Memory - if (m_fEndOfCaption) { - m_fEndOfCaption = false; - SaveDisp(time + (i / 2) * 1000 / 30); - } - - ZeroMemory(m_disp, sizeof(m_disp)); - } else if (buff[i] == 0x97 && (buff[i + 1] == 0xa1 || buff[i + 1] == 0xa2 || buff[i + 1] == 0x23)) { // Tab Over - OffsetCursor(buff[i + 1] & 3, 0); - } else if (buff[i] == 0x91 || buff[i] == 0x92 || buff[i] == 0x15 || buff[i] == 0x16 - || buff[i] == 0x97 || buff[i] == 0x10 || buff[i] == 0x13 || buff[i] == 0x94) { // curpos, color, underline - int row = 0; - switch (buff[i]) { - default: - case 0x91: - row = 0; - break; - case 0x92: - row = 2; - break; - case 0x15: - row = 4; - break; - case 0x16: - row = 6; - break; - case 0x97: - row = 8; - break; - case 0x10: - row = 10; - break; - case 0x13: - row = 12; - break; - case 0x94: - row = 14; - break; - } - if (buff[i + 1] & 0x20) { - row++; - } - - int col = buff[i + 1] & 0xe; - if (col == 0 || (col > 0 && !(buff[i + 1] & 0x10))) { - col = 0; - } else { - col <<= 1; - } - - MoveCursor(col, row); - } - - i++; - } - } -} - -void CCDecoder::ExtractCC(BYTE* buff, int len, __int64 time) -{ - for (ptrdiff_t i = 0; i < len - 9; i++) { - if (*(DWORD*)&buff[i] == 0xb2010000 && *(DWORD*)&buff[i + 4] == 0xf8014343) { - i += 8; - int nBytes = buff[i++] & 0x3f; - if (nBytes > 0) { - nBytes = (nBytes + 1) & ~1; - - BYTE* pData1 = DEBUG_NEW BYTE[nBytes]; - BYTE* pData2 = DEBUG_NEW BYTE[nBytes]; - - if (pData1 && pData2) { - int nBytes1 = 0, nBytes2 = 0; - - for (ptrdiff_t j = 0; j < nBytes && i < 0x800;) { - if (buff[i++] == 0xff) { - pData1[nBytes1++] = buff[i++]; - pData1[nBytes1++] = buff[i++]; - } else { - i += 2; - } - - j++; - - if (j >= nBytes) { - break; - } - - if (buff[i++] == 0xff) { - pData2[nBytes2++] = buff[i++]; - pData2[nBytes2++] = buff[i++]; - } else { - i += 2; - } - - j++; - } - - if (nBytes1 > 0) { - DecodeCC(pData1, nBytes1, time); - } - - if (nBytes2 > 0) { - DecodeCC(pData2, nBytes2, time); - } - } - - if (pData1) { - delete [] pData1; - } - if (pData2) { - delete [] pData2; - } - } - - break; - } - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "CCDecoder.h" +#include "SubtitleHelpers.h" + +CCDecoder::CCDecoder(CString fn, CString rawfn) : m_fn(fn), m_rawfn(rawfn) +{ + m_sts.CreateDefaultStyle(ANSI_CHARSET); + + m_time = 0; + m_fEndOfCaption = false; + ZeroMemory(m_buff, sizeof(m_buff)); + ZeroMemory(m_disp, sizeof(m_disp)); + m_cursor = CPoint(0, 0); + + if (!m_rawfn.IsEmpty()) { + _tremove(m_rawfn); + } +} + +CCDecoder::~CCDecoder() +{ + if (!m_sts.IsEmpty() && !m_fn.IsEmpty()) { + m_sts.Sort(); + m_sts.SaveAs(m_fn, Subtitle::SRT, -1, 0, CTextFile::DEFAULT_ENCODING); + m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf8.srt"), Subtitle::SRT, -1, 0, CTextFile::UTF8); + m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf16le.srt"), Subtitle::SRT, -1, 0, CTextFile::LE16); + m_sts.SaveAs(m_fn.Left(m_fn.ReverseFind('.') + 1) + _T("utf16be.srt"), Subtitle::SRT, -1, 0, CTextFile::BE16); + } +} + +void CCDecoder::MoveCursor(int x, int y) +{ + m_cursor = CPoint(x, y); + if (m_cursor.x < 0) { + m_cursor.x = 0; + } + if (m_cursor.y < 0) { + m_cursor.y = 0; + } + if (m_cursor.x >= 32) { + m_cursor.x = 0, m_cursor.y++; + } + if (m_cursor.y >= 16) { + m_cursor.y = 0; + } +} + +void CCDecoder::OffsetCursor(int x, int y) +{ + MoveCursor(m_cursor.x + x, m_cursor.y + y); +} + +void CCDecoder::PutChar(WCHAR c) +{ + m_buff[m_cursor.y][m_cursor.x] = c; + OffsetCursor(1, 0); +} + +void CCDecoder::SaveDisp(__int64 time) +{ + CStringW str; + + for (size_t row = 0; row < 16; row++) { + bool fNonEmptyRow = false; + + for (size_t col = 0; col < 32; col++) { + if (m_disp[row][col]) { + CStringW str2(&m_disp[row][col]); + if (fNonEmptyRow) { + str += L' '; + } + str += str2; + col += str2.GetLength(); + fNonEmptyRow = true; + } + } + + if (fNonEmptyRow) { + str += L'\n'; + } + } + + if (str.IsEmpty()) { + return; + } + + m_sts.Add(str, true, (int)m_time, (int)time); +} + +void CCDecoder::DecodeCC(const BYTE* buff, int len, __int64 time) +{ + if (!m_rawfn.IsEmpty()) { + FILE* f = nullptr; + if (!_tfopen_s(&f, m_rawfn, _T("at"))) { + _ftprintf_s(f, _T("%02d:%02d:%02d.%03d\n"), + (int)(time / 1000 / 60 / 60), + (int)((time / 1000 / 60) % 60), + (int)((time / 1000) % 60), + (int)(time % 1000)); + + for (ptrdiff_t i = 0; i < len; i++) { + _ftprintf_s(f, _T("%02x"), buff[i]); + if (i < len - 1) { + _ftprintf_s(f, _T(" ")); + } + if (i > 0 && (i & 15) == 15) { + _ftprintf_s(f, _T("\n")); + } + } + if (len > 0) { + _ftprintf_s(f, _T("\n\n")); + } + fclose(f); + } + } + + for (ptrdiff_t i = 0; i < len; i++) { + BYTE c = buff[i] & 0x7f; + if (c >= 0x20) { + static WCHAR charmap[0x60] = { + ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', 0xE1, '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', 0x3F, + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', 0xE9, ']', 0xED, 0xF3, + 0xFA, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xE7, 0xF7, 'N', 'n', 0x3F + }; + + PutChar(charmap[c - 0x20]); + } else if (i < len - 1 && buff[i] != 0x80) { + // codes and special characters are supposed to be doubled + if (i < len - 3 && buff[i] == buff[i + 2] && buff[i + 1] == buff[i + 3]) { + i += 2; + } + + c = buff[i + 1] & 0x7f; + if (buff[i] == 0x91 && c >= 0x20 && c < 0x30) { // formating + // TODO + } else if (buff[i] == 0x91 && c == 0x39) { // transparent space + OffsetCursor(1, 0); + } else if (buff[i] == 0x91 && c >= 0x30 && c < 0x40) { // special characters + static WCHAR charmap[0x10] = { + 0x00ae, // (r)egistered + 0x00b0, // degree + 0x00bd, // 1/2 + 0x00bf, // inverted question mark + 0x2122, // trade mark + 0x00a2, // cent + 0x00a3, // pound + 0x266a, // music + 0x00e0, // a` + 0x00ff, // transparent space, handled above + 0x00e8, // e` + 0x00e2, // a^ + 0x00ea, // e^ + 0x00ee, // i^ + 0x00f4, // o^ + 0x00fb, // u^ + }; + + PutChar(charmap[c - 0x30]); + } else if (buff[i] == 0x92 && c >= 0x20 && c < 0x40) { // extended characters + static WCHAR charmap[0x20] = { + 0x00c0, // A' + 0x00c9, // E' + 0x00d3, // O' + 0x00da, // U' + 0x00dc, // U: + 0x00fc, // u: + 0x2018, // ` + 0x00a1, // inverted ! + 0x002a, // * + 0x2019, // ' + 0x002d, // - + 0x00a9, // (c)opyright + 0x2120, // SM + 0x00b7, // . (dot in the middle) + 0x201c, // inverted " + 0x201d, // " + + 0x00c1, // A` + 0x00c2, // A^ + 0x00c7, // C, + 0x00c8, // E` + 0x00ca, // E^ + 0x00cb, // E: + 0x00eb, // e: + 0x00ce, // I^ + 0x00cf, // I: + 0x00ef, // i: + 0x00d4, // O^ + 0x00d9, // U` + 0x00f9, // u` + 0x00db, // U^ + 0x00ab, // << + 0x00bb, // >> + }; + + PutChar(charmap[c - 0x20]); + } else if (buff[i] == 0x13 && c >= 0x20 && c < 0x40) { // more extended characters + static WCHAR charmap[0x20] = { + 0x00c3, // A~ + 0x00e3, // a~ + 0x00cd, // I' + 0x00cc, // I` + 0x00ec, // i` + 0x00d2, // O` + 0x00f2, // o` + 0x00d5, // O~ + 0x00f5, // o~ + 0x007b, // { + 0x007d, // } + 0x005c, // /* \ */ + 0x005e, // ^ + 0x005f, // _ + 0x00a6, // | + 0x007e, // ~ + + 0x00c4, // A: + 0x00e4, // a: + 0x00d6, // O: + 0x00f6, // o: + 0x00df, // B (ss in german) + 0x00a5, // Y= + 0x00a4, // ox + 0x007c, // | + 0x00c5, // Ao + 0x00e5, // ao + 0x00d8, // O/ + 0x00f8, // o/ + 0x250c, // |- + 0x2510, // -| + 0x2514, // |_ + 0x2518, // _| + }; + + PutChar(charmap[c - 0x20]); + } else if (buff[i] == 0x94 && buff[i + 1] == 0xae) { // Erase Non-displayed [buffer] Memory + ZeroMemory(m_buff, sizeof(m_buff)); + } else if (buff[i] == 0x94 && buff[i + 1] == 0x20) { // Resume Caption Loading + ZeroMemory(m_buff, sizeof(m_buff)); + } else if (buff[i] == 0x94 && buff[i + 1] == 0x2f) { // End Of Caption + if (memcmp(m_disp, m_buff, sizeof(m_disp)) != 0) { + if (m_fEndOfCaption) { + SaveDisp(time + (i / 2) * 1000 / 30); + } + + m_fEndOfCaption = true; + memcpy(m_disp, m_buff, sizeof(m_disp)); + m_time = time + (i / 2) * 1000 / 30; + } + } else if (buff[i] == 0x94 && buff[i + 1] == 0x2c) { // Erase Displayed Memory + if (m_fEndOfCaption) { + m_fEndOfCaption = false; + SaveDisp(time + (i / 2) * 1000 / 30); + } + + ZeroMemory(m_disp, sizeof(m_disp)); + } else if (buff[i] == 0x97 && (buff[i + 1] == 0xa1 || buff[i + 1] == 0xa2 || buff[i + 1] == 0x23)) { // Tab Over + OffsetCursor(buff[i + 1] & 3, 0); + } else if (buff[i] == 0x91 || buff[i] == 0x92 || buff[i] == 0x15 || buff[i] == 0x16 + || buff[i] == 0x97 || buff[i] == 0x10 || buff[i] == 0x13 || buff[i] == 0x94) { // curpos, color, underline + int row = 0; + switch (buff[i]) { + default: + case 0x91: + row = 0; + break; + case 0x92: + row = 2; + break; + case 0x15: + row = 4; + break; + case 0x16: + row = 6; + break; + case 0x97: + row = 8; + break; + case 0x10: + row = 10; + break; + case 0x13: + row = 12; + break; + case 0x94: + row = 14; + break; + } + if (buff[i + 1] & 0x20) { + row++; + } + + int col = buff[i + 1] & 0xe; + if (col == 0 || (col > 0 && !(buff[i + 1] & 0x10))) { + col = 0; + } else { + col <<= 1; + } + + MoveCursor(col, row); + } + + i++; + } + } +} + +void CCDecoder::ExtractCC(BYTE* buff, int len, __int64 time) +{ + for (ptrdiff_t i = 0; i < len - 9; i++) { + if (*(DWORD*)&buff[i] == 0xb2010000 && *(DWORD*)&buff[i + 4] == 0xf8014343) { + i += 8; + int nBytes = buff[i++] & 0x3f; + if (nBytes > 0) { + nBytes = (nBytes + 1) & ~1; + + BYTE* pData1 = DEBUG_NEW BYTE[nBytes]; + BYTE* pData2 = DEBUG_NEW BYTE[nBytes]; + + if (pData1 && pData2) { + int nBytes1 = 0, nBytes2 = 0; + + for (ptrdiff_t j = 0; j < nBytes && i < 0x800;) { + if (buff[i++] == 0xff) { + pData1[nBytes1++] = buff[i++]; + pData1[nBytes1++] = buff[i++]; + } else { + i += 2; + } + + j++; + + if (j >= nBytes) { + break; + } + + if (buff[i++] == 0xff) { + pData2[nBytes2++] = buff[i++]; + pData2[nBytes2++] = buff[i++]; + } else { + i += 2; + } + + j++; + } + + if (nBytes1 > 0) { + DecodeCC(pData1, nBytes1, time); + } + + if (nBytes2 > 0) { + DecodeCC(pData2, nBytes2, time); + } + } + + if (pData1) { + delete [] pData1; + } + if (pData2) { + delete [] pData2; + } + } + + break; + } + } +} diff --git a/src/Subtitles/CCDecoder.h b/src/Subtitles/CCDecoder.h index bb87d2975d2..9b0e54e15f8 100644 --- a/src/Subtitles/CCDecoder.h +++ b/src/Subtitles/CCDecoder.h @@ -1,46 +1,46 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "STS.h" - -class CCDecoder -{ - CSimpleTextSubtitle m_sts; - CString m_fn, m_rawfn; - __int64 m_time; - bool m_fEndOfCaption; - WCHAR m_buff[16][33], m_disp[16][33]; - CPoint m_cursor; - - void SaveDisp(__int64 time); - void MoveCursor(int x, int y); - void OffsetCursor(int x, int y); - void PutChar(WCHAR c); - -public: - CCDecoder(CString fn = _T(""), CString rawfn = _T("")); - virtual ~CCDecoder(); - void DecodeCC(const BYTE* buff, int len, __int64 time); - void ExtractCC(BYTE* buff, int len, __int64 time); - CSimpleTextSubtitle& GetSTS() { return m_sts; } -}; +/* + * (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 . + * + */ + +#pragma once + +#include "STS.h" + +class CCDecoder +{ + CSimpleTextSubtitle m_sts; + CString m_fn, m_rawfn; + __int64 m_time; + bool m_fEndOfCaption; + WCHAR m_buff[16][33], m_disp[16][33]; + CPoint m_cursor; + + void SaveDisp(__int64 time); + void MoveCursor(int x, int y); + void OffsetCursor(int x, int y); + void PutChar(WCHAR c); + +public: + CCDecoder(CString fn = _T(""), CString rawfn = _T("")); + virtual ~CCDecoder(); + void DecodeCC(const BYTE* buff, int len, __int64 time); + void ExtractCC(BYTE* buff, int len, __int64 time); + CSimpleTextSubtitle& GetSTS() { return m_sts; } +}; diff --git a/src/Subtitles/CompositionObject.cpp b/src/Subtitles/CompositionObject.cpp index 76669558778..4993a790e03 100644 --- a/src/Subtitles/CompositionObject.cpp +++ b/src/Subtitles/CompositionObject.cpp @@ -1,370 +1,370 @@ -/* - * (C) 2009-2015 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 . - * - */ - -#include "stdafx.h" -#include "CompositionObject.h" -#include "ColorConvTable.h" -#include "../DSUtil/GolombBuffer.h" - - -CompositionObject::CompositionObject() -{ - Init(); -} - -CompositionObject::CompositionObject(const CompositionObject& obj) - : m_object_id_ref(obj.m_object_id_ref) - , m_window_id_ref(obj.m_window_id_ref) - , m_object_cropped_flag(obj.m_object_cropped_flag) - , m_forced_on_flag(obj.m_forced_on_flag) - , m_version_number(obj.m_version_number) - , m_horizontal_position(obj.m_horizontal_position) - , m_vertical_position(obj.m_vertical_position) - , m_width(obj.m_width) - , m_height(obj.m_height) - , m_cropping_horizontal_position(obj.m_cropping_horizontal_position) - , m_cropping_vertical_position(obj.m_cropping_vertical_position) - , m_cropping_width(obj.m_cropping_width) - , m_cropping_height(obj.m_cropping_height) - , m_pRLEData(nullptr) - , m_nRLEDataSize(0) - , m_nRLEPos(0) - , m_nColorNumber(obj.m_nColorNumber) - , m_colors(obj.m_colors) -{ - if (obj.m_pRLEData) { - SetRLEData(obj.m_pRLEData, obj.m_nRLEPos, obj.m_nRLEDataSize); - } -} - -CompositionObject::~CompositionObject() -{ - delete [] m_pRLEData; -} - -void CompositionObject::Init() -{ - m_pRLEData = nullptr; - m_nRLEDataSize = m_nRLEPos = 0; - m_nColorNumber = 0; - m_object_id_ref = 0; - m_window_id_ref = 0; - m_object_cropped_flag = false; - m_forced_on_flag = false; - m_version_number = 0; - m_horizontal_position = m_vertical_position = 0; - m_width = m_height = 0; - m_cropping_horizontal_position = m_cropping_vertical_position = 0; - m_cropping_width = m_cropping_height = 0; - - m_colors.fill(0); -} - -void CompositionObject::Reset() -{ - delete[] m_pRLEData; - Init(); -} - -void CompositionObject::SetPalette(int nNbEntry, const HDMV_PALETTE* pPalette, ColorConvTable::YuvMatrixType currentMatrix) -{ - m_nColorNumber = nNbEntry; - for (int i = 0; i < nNbEntry; i++) { - m_colors[pPalette[i].entry_id] = ColorConvTable::A8Y8U8V8_TO_ARGB(pPalette[i].T, pPalette[i].Y, pPalette[i].Cb, pPalette[i].Cr, currentMatrix); - } -} - -void CompositionObject::SetRLEData(const BYTE* pBuffer, size_t nSize, size_t nTotalSize) -{ - delete [] m_pRLEData; - - if (nTotalSize > 0 && nSize <= nTotalSize) { - m_pRLEData = DEBUG_NEW BYTE[nTotalSize]; - m_nRLEDataSize = nTotalSize; - m_nRLEPos = nSize; - - memcpy(m_pRLEData, pBuffer, nSize); - } else { - m_pRLEData = nullptr; - m_nRLEDataSize = m_nRLEPos = 0; - ASSERT(FALSE); // This shouldn't happen in normal operation - } -} - -void CompositionObject::AppendRLEData(const BYTE* pBuffer, size_t nSize) -{ - if (m_nRLEPos + nSize <= m_nRLEDataSize) { - memcpy(m_pRLEData + m_nRLEPos, pBuffer, nSize); - m_nRLEPos += nSize; - } else { - ASSERT(FALSE); // This shouldn't happen in normal operation - } -} - -void CompositionObject::RenderHdmv(SubPicDesc& spd) -{ - if (!m_pRLEData || !m_nColorNumber) { - return; - } - - CGolombBuffer GBuffer(m_pRLEData, m_nRLEDataSize); - BYTE bSwitch; - BYTE nPaletteIndex = 0; - LONG nCount; - LONG nX = m_horizontal_position; - LONG nY = m_vertical_position; - - while ((nY < (m_vertical_position + m_height)) && !GBuffer.IsEOF()) { - BYTE bTemp = GBuffer.ReadByte(); - if (bTemp != 0) { - nPaletteIndex = bTemp; - nCount = 1; - } else { - bSwitch = GBuffer.ReadByte(); - if (!(bSwitch & 0x80)) { - if (!(bSwitch & 0x40)) { - nCount = bSwitch & 0x3F; - if (nCount > 0) { - nPaletteIndex = 0; - } - } else { - nCount = (bSwitch & 0x3F) << 8 | (short)GBuffer.ReadByte(); - nPaletteIndex = 0; - } - } else { - if (!(bSwitch & 0x40)) { - nCount = bSwitch & 0x3F; - nPaletteIndex = GBuffer.ReadByte(); - } else { - nCount = (bSwitch & 0x3F) << 8 | (short)GBuffer.ReadByte(); - nPaletteIndex = GBuffer.ReadByte(); - } - } - } - - if (nCount > 0) { - if (nPaletteIndex != 0xFF) { // Fully transparent (section 9.14.4.2.2.1.1) - FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); - } - nX += nCount; - } else { - nY++; - nX = m_horizontal_position; - } - } -} - -void CompositionObject::RenderDvb(SubPicDesc& spd, short nX, short nY) -{ - if (!m_pRLEData) { - return; - } - - CGolombBuffer gb(m_pRLEData, m_nRLEDataSize); - short sTopFieldLength; - short sBottomFieldLength; - - sTopFieldLength = gb.ReadShort(); - sBottomFieldLength = gb.ReadShort(); - - DvbRenderField(spd, gb, nX, nY, sTopFieldLength); - DvbRenderField(spd, gb, nX, nY + 1, sBottomFieldLength); -} - -void CompositionObject::DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, short nXStart, short nYStart, short nLength) -{ - //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0xFFFF0000); // Red opaque - //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0xCC00FF00); // Green 80% - //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0x100000FF); // Blue 60% - //return; - short nX = nXStart; - short nY = nYStart; - size_t nEnd = gb.GetPos() + nLength; - if (nEnd > gb.GetSize()) { - // Unexpected end of data, the file is probably corrupted - // but try to render the subtitles anyway - ASSERT(FALSE); - nEnd = gb.GetSize(); - } - - while (gb.GetPos() < nEnd) { - BYTE bType = gb.ReadByte(); - switch (bType) { - case 0x10: - Dvb2PixelsCodeString(spd, gb, nX, nY); - break; - case 0x11: - Dvb4PixelsCodeString(spd, gb, nX, nY); - break; - case 0x12: - Dvb8PixelsCodeString(spd, gb, nX, nY); - break; - case 0x20: - gb.SkipBytes(2); - break; - case 0x21: - gb.SkipBytes(4); - break; - case 0x22: - gb.SkipBytes(16); - break; - case 0xF0: - nX = nXStart; - nY += 2; - break; - default: - ASSERT(FALSE); - break; - } - } -} - -void CompositionObject::Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) -{ - bool bQuit = false; - - while (!bQuit && !gb.IsEOF()) { - short nCount = 0; - BYTE nPaletteIndex = 0; - BYTE bTemp = (BYTE)gb.BitRead(2); - if (bTemp != 0) { - nPaletteIndex = bTemp; - nCount = 1; - } else { - if (gb.BitRead(1) == 1) { // switch_1 - nCount = 3 + (short)gb.BitRead(3); // run_length_3-9 - nPaletteIndex = (BYTE)gb.BitRead(2); - } else { - if (gb.BitRead(1) == 0) { // switch_2 - switch (gb.BitRead(2)) { // switch_3 - case 0: - bQuit = true; - break; - case 1: - nCount = 2; - break; - case 2: // if (switch_3 == '10') - nCount = 12 + (short)gb.BitRead(4); // run_length_12-27 - nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code - break; - case 3: - nCount = 29 + gb.ReadByte(); // run_length_29-284 - nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code - break; - } - } else { - nCount = 1; - } - } - } - - if (nCount > 0) { - FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); - nX += nCount; - } - } - - gb.BitByteAlign(); -} - -void CompositionObject::Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) -{ - bool bQuit = false; - - while (!bQuit && !gb.IsEOF()) { - short nCount = 0; - BYTE nPaletteIndex = 0; - BYTE bTemp = (BYTE)gb.BitRead(4); - if (bTemp != 0) { - nPaletteIndex = bTemp; - nCount = 1; - } else { - if (gb.BitRead(1) == 0) { // switch_1 - nCount = (short)gb.BitRead(3); // run_length_3-9 - if (nCount != 0) { - nCount += 2; - } else { - bQuit = true; - } - } else { - if (gb.BitRead(1) == 0) { // switch_2 - nCount = 4 + (short)gb.BitRead(2); // run_length_4-7 - nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code - } else { - switch (gb.BitRead(2)) { // switch_3 - case 0: - nCount = 1; - break; - case 1: - nCount = 2; - break; - case 2: // if (switch_3 == '10') - nCount = 9 + (short)gb.BitRead(4); // run_length_9-24 - nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code - break; - case 3: - nCount = 25 + gb.ReadByte(); // run_length_25-280 - nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code - break; - } - } - } - } - - if (nCount > 0) { - FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); - nX += nCount; - } - } - - gb.BitByteAlign(); -} - -void CompositionObject::Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) -{ - bool bQuit = false; - - while (!bQuit && !gb.IsEOF()) { - short nCount = 0; - BYTE nPaletteIndex = 0; - BYTE bTemp = gb.ReadByte(); - if (bTemp != 0) { - nPaletteIndex = bTemp; - nCount = 1; - } else { - if (gb.BitRead(1) == 0) { // switch_1 - nCount = (short)gb.BitRead(7); // run_length_1-127 - if (nCount == 0) { - bQuit = true; - } - } else { - nCount = (short)gb.BitRead(7); // run_length_3-127 - nPaletteIndex = gb.ReadByte(); - } - } - - if (nCount > 0) { - FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); - nX += nCount; - } - } - - gb.BitByteAlign(); -} +/* + * (C) 2009-2015 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 . + * + */ + +#include "stdafx.h" +#include "CompositionObject.h" +#include "ColorConvTable.h" +#include "../DSUtil/GolombBuffer.h" + + +CompositionObject::CompositionObject() +{ + Init(); +} + +CompositionObject::CompositionObject(const CompositionObject& obj) + : m_object_id_ref(obj.m_object_id_ref) + , m_window_id_ref(obj.m_window_id_ref) + , m_object_cropped_flag(obj.m_object_cropped_flag) + , m_forced_on_flag(obj.m_forced_on_flag) + , m_version_number(obj.m_version_number) + , m_horizontal_position(obj.m_horizontal_position) + , m_vertical_position(obj.m_vertical_position) + , m_width(obj.m_width) + , m_height(obj.m_height) + , m_cropping_horizontal_position(obj.m_cropping_horizontal_position) + , m_cropping_vertical_position(obj.m_cropping_vertical_position) + , m_cropping_width(obj.m_cropping_width) + , m_cropping_height(obj.m_cropping_height) + , m_pRLEData(nullptr) + , m_nRLEDataSize(0) + , m_nRLEPos(0) + , m_nColorNumber(obj.m_nColorNumber) + , m_colors(obj.m_colors) +{ + if (obj.m_pRLEData) { + SetRLEData(obj.m_pRLEData, obj.m_nRLEPos, obj.m_nRLEDataSize); + } +} + +CompositionObject::~CompositionObject() +{ + delete [] m_pRLEData; +} + +void CompositionObject::Init() +{ + m_pRLEData = nullptr; + m_nRLEDataSize = m_nRLEPos = 0; + m_nColorNumber = 0; + m_object_id_ref = 0; + m_window_id_ref = 0; + m_object_cropped_flag = false; + m_forced_on_flag = false; + m_version_number = 0; + m_horizontal_position = m_vertical_position = 0; + m_width = m_height = 0; + m_cropping_horizontal_position = m_cropping_vertical_position = 0; + m_cropping_width = m_cropping_height = 0; + + m_colors.fill(0); +} + +void CompositionObject::Reset() +{ + delete[] m_pRLEData; + Init(); +} + +void CompositionObject::SetPalette(int nNbEntry, const HDMV_PALETTE* pPalette, ColorConvTable::YuvMatrixType currentMatrix) +{ + m_nColorNumber = nNbEntry; + for (int i = 0; i < nNbEntry; i++) { + m_colors[pPalette[i].entry_id] = ColorConvTable::A8Y8U8V8_TO_ARGB(pPalette[i].T, pPalette[i].Y, pPalette[i].Cb, pPalette[i].Cr, currentMatrix); + } +} + +void CompositionObject::SetRLEData(const BYTE* pBuffer, size_t nSize, size_t nTotalSize) +{ + delete [] m_pRLEData; + + if (nTotalSize > 0 && nSize <= nTotalSize) { + m_pRLEData = DEBUG_NEW BYTE[nTotalSize]; + m_nRLEDataSize = nTotalSize; + m_nRLEPos = nSize; + + memcpy(m_pRLEData, pBuffer, nSize); + } else { + m_pRLEData = nullptr; + m_nRLEDataSize = m_nRLEPos = 0; + ASSERT(FALSE); // This shouldn't happen in normal operation + } +} + +void CompositionObject::AppendRLEData(const BYTE* pBuffer, size_t nSize) +{ + if (m_nRLEPos + nSize <= m_nRLEDataSize) { + memcpy(m_pRLEData + m_nRLEPos, pBuffer, nSize); + m_nRLEPos += nSize; + } else { + ASSERT(FALSE); // This shouldn't happen in normal operation + } +} + +void CompositionObject::RenderHdmv(SubPicDesc& spd) +{ + if (!m_pRLEData || !m_nColorNumber) { + return; + } + + CGolombBuffer GBuffer(m_pRLEData, m_nRLEDataSize); + BYTE bSwitch; + BYTE nPaletteIndex = 0; + LONG nCount; + LONG nX = m_horizontal_position; + LONG nY = m_vertical_position; + + while ((nY < (m_vertical_position + m_height)) && !GBuffer.IsEOF()) { + BYTE bTemp = GBuffer.ReadByte(); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + bSwitch = GBuffer.ReadByte(); + if (!(bSwitch & 0x80)) { + if (!(bSwitch & 0x40)) { + nCount = bSwitch & 0x3F; + if (nCount > 0) { + nPaletteIndex = 0; + } + } else { + nCount = (bSwitch & 0x3F) << 8 | (short)GBuffer.ReadByte(); + nPaletteIndex = 0; + } + } else { + if (!(bSwitch & 0x40)) { + nCount = bSwitch & 0x3F; + nPaletteIndex = GBuffer.ReadByte(); + } else { + nCount = (bSwitch & 0x3F) << 8 | (short)GBuffer.ReadByte(); + nPaletteIndex = GBuffer.ReadByte(); + } + } + } + + if (nCount > 0) { + if (nPaletteIndex != 0xFF) { // Fully transparent (section 9.14.4.2.2.1.1) + FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); + } + nX += nCount; + } else { + nY++; + nX = m_horizontal_position; + } + } +} + +void CompositionObject::RenderDvb(SubPicDesc& spd, short nX, short nY) +{ + if (!m_pRLEData) { + return; + } + + CGolombBuffer gb(m_pRLEData, m_nRLEDataSize); + short sTopFieldLength; + short sBottomFieldLength; + + sTopFieldLength = gb.ReadShort(); + sBottomFieldLength = gb.ReadShort(); + + DvbRenderField(spd, gb, nX, nY, sTopFieldLength); + DvbRenderField(spd, gb, nX, nY + 1, sBottomFieldLength); +} + +void CompositionObject::DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, short nXStart, short nYStart, short nLength) +{ + //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0xFFFF0000); // Red opaque + //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0xCC00FF00); // Green 80% + //FillSolidRect(spd, nXStart, nYStart, m_width, m_height, 0x100000FF); // Blue 60% + //return; + short nX = nXStart; + short nY = nYStart; + size_t nEnd = gb.GetPos() + nLength; + if (nEnd > gb.GetSize()) { + // Unexpected end of data, the file is probably corrupted + // but try to render the subtitles anyway + ASSERT(FALSE); + nEnd = gb.GetSize(); + } + + while (gb.GetPos() < nEnd) { + BYTE bType = gb.ReadByte(); + switch (bType) { + case 0x10: + Dvb2PixelsCodeString(spd, gb, nX, nY); + break; + case 0x11: + Dvb4PixelsCodeString(spd, gb, nX, nY); + break; + case 0x12: + Dvb8PixelsCodeString(spd, gb, nX, nY); + break; + case 0x20: + gb.SkipBytes(2); + break; + case 0x21: + gb.SkipBytes(4); + break; + case 0x22: + gb.SkipBytes(16); + break; + case 0xF0: + nX = nXStart; + nY += 2; + break; + default: + ASSERT(FALSE); + break; + } + } +} + +void CompositionObject::Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) +{ + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + short nCount = 0; + BYTE nPaletteIndex = 0; + BYTE bTemp = (BYTE)gb.BitRead(2); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 1) { // switch_1 + nCount = 3 + (short)gb.BitRead(3); // run_length_3-9 + nPaletteIndex = (BYTE)gb.BitRead(2); + } else { + if (gb.BitRead(1) == 0) { // switch_2 + switch (gb.BitRead(2)) { // switch_3 + case 0: + bQuit = true; + break; + case 1: + nCount = 2; + break; + case 2: // if (switch_3 == '10') + nCount = 12 + (short)gb.BitRead(4); // run_length_12-27 + nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code + break; + case 3: + nCount = 29 + gb.ReadByte(); // run_length_29-284 + nPaletteIndex = (BYTE)gb.BitRead(2); // 4-bit_pixel-code + break; + } + } else { + nCount = 1; + } + } + } + + if (nCount > 0) { + FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} + +void CompositionObject::Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) +{ + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + short nCount = 0; + BYTE nPaletteIndex = 0; + BYTE bTemp = (BYTE)gb.BitRead(4); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 0) { // switch_1 + nCount = (short)gb.BitRead(3); // run_length_3-9 + if (nCount != 0) { + nCount += 2; + } else { + bQuit = true; + } + } else { + if (gb.BitRead(1) == 0) { // switch_2 + nCount = 4 + (short)gb.BitRead(2); // run_length_4-7 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + } else { + switch (gb.BitRead(2)) { // switch_3 + case 0: + nCount = 1; + break; + case 1: + nCount = 2; + break; + case 2: // if (switch_3 == '10') + nCount = 9 + (short)gb.BitRead(4); // run_length_9-24 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + break; + case 3: + nCount = 25 + gb.ReadByte(); // run_length_25-280 + nPaletteIndex = (BYTE)gb.BitRead(4); // 4-bit_pixel-code + break; + } + } + } + } + + if (nCount > 0) { + FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} + +void CompositionObject::Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY) +{ + bool bQuit = false; + + while (!bQuit && !gb.IsEOF()) { + short nCount = 0; + BYTE nPaletteIndex = 0; + BYTE bTemp = gb.ReadByte(); + if (bTemp != 0) { + nPaletteIndex = bTemp; + nCount = 1; + } else { + if (gb.BitRead(1) == 0) { // switch_1 + nCount = (short)gb.BitRead(7); // run_length_1-127 + if (nCount == 0) { + bQuit = true; + } + } else { + nCount = (short)gb.BitRead(7); // run_length_3-127 + nPaletteIndex = gb.ReadByte(); + } + } + + if (nCount > 0) { + FillSolidRect(spd, nX, nY, nCount, 1, m_colors[nPaletteIndex]); + nX += nCount; + } + } + + gb.BitByteAlign(); +} diff --git a/src/Subtitles/CompositionObject.h b/src/Subtitles/CompositionObject.h index 3da3438ba3e..767ef4630ed 100644 --- a/src/Subtitles/CompositionObject.h +++ b/src/Subtitles/CompositionObject.h @@ -1,92 +1,92 @@ -/* - * (C) 2009-2015 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 . - * - */ - -#pragma once - -#include "Rasterizer.h" -#include "ColorConvTable.h" - - -struct HDMV_PALETTE { - BYTE entry_id; - BYTE Y; - BYTE Cr; - BYTE Cb; - BYTE T; // HDMV rule : 0 transparent, 255 opaque (compatible DirectX) -}; - -class CGolombBuffer; - -class CompositionObject : Rasterizer -{ -public: - short m_object_id_ref; - BYTE m_window_id_ref; - bool m_object_cropped_flag; - bool m_forced_on_flag; - BYTE m_version_number; - - LONG m_horizontal_position; - LONG m_vertical_position; - LONG m_width; - LONG m_height; - - LONG m_cropping_horizontal_position; - LONG m_cropping_vertical_position; - LONG m_cropping_width; - LONG m_cropping_height; - - CompositionObject(); - CompositionObject(const CompositionObject& obj); - ~CompositionObject(); - - void Init(); - void Reset(); - - void SetRLEData(const BYTE* pBuffer, size_t nSize, size_t nTotalSize); - void AppendRLEData(const BYTE* pBuffer, size_t nSize); - const BYTE* GetRLEData() const { return m_pRLEData; }; - size_t GetRLEDataSize() const { return m_nRLEDataSize; }; - size_t GetRLEPos() const { return m_nRLEPos; }; - bool IsRLEComplete() const { return m_nRLEPos >= m_nRLEDataSize; }; - void RenderHdmv(SubPicDesc& spd); - void RenderDvb(SubPicDesc& spd, short nX, short nY); - void WriteSeg(SubPicDesc& spd, short nX, short nY, short nCount, short nPaletteIndex); - void SetPalette(int nNbEntry, const HDMV_PALETTE* pPalette, ColorConvTable::YuvMatrixType currentMatrix); - bool HavePalette() const { return m_nColorNumber > 0; }; - - // Forbid the use of direct affectation for now, it would be dangerous because - // of possible leaks and double frees. We could do a deep copy to be safe but - // it could possibly hurt the performance if we forgot about this and start - // using affectation a lot. - CompositionObject& operator=(const CompositionObject&) = delete; - -private: - BYTE* m_pRLEData; - size_t m_nRLEDataSize; - size_t m_nRLEPos; - int m_nColorNumber; - std::array m_colors; - - void DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, short nXStart, short nYStart, short nLength); - void Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); - void Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); - void Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); -}; +/* + * (C) 2009-2015 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 . + * + */ + +#pragma once + +#include "Rasterizer.h" +#include "ColorConvTable.h" + + +struct HDMV_PALETTE { + BYTE entry_id; + BYTE Y; + BYTE Cr; + BYTE Cb; + BYTE T; // HDMV rule : 0 transparent, 255 opaque (compatible DirectX) +}; + +class CGolombBuffer; + +class CompositionObject : Rasterizer +{ +public: + short m_object_id_ref; + BYTE m_window_id_ref; + bool m_object_cropped_flag; + bool m_forced_on_flag; + BYTE m_version_number; + + LONG m_horizontal_position; + LONG m_vertical_position; + LONG m_width; + LONG m_height; + + LONG m_cropping_horizontal_position; + LONG m_cropping_vertical_position; + LONG m_cropping_width; + LONG m_cropping_height; + + CompositionObject(); + CompositionObject(const CompositionObject& obj); + ~CompositionObject(); + + void Init(); + void Reset(); + + void SetRLEData(const BYTE* pBuffer, size_t nSize, size_t nTotalSize); + void AppendRLEData(const BYTE* pBuffer, size_t nSize); + const BYTE* GetRLEData() const { return m_pRLEData; }; + size_t GetRLEDataSize() const { return m_nRLEDataSize; }; + size_t GetRLEPos() const { return m_nRLEPos; }; + bool IsRLEComplete() const { return m_nRLEPos >= m_nRLEDataSize; }; + void RenderHdmv(SubPicDesc& spd); + void RenderDvb(SubPicDesc& spd, short nX, short nY); + void WriteSeg(SubPicDesc& spd, short nX, short nY, short nCount, short nPaletteIndex); + void SetPalette(int nNbEntry, const HDMV_PALETTE* pPalette, ColorConvTable::YuvMatrixType currentMatrix); + bool HavePalette() const { return m_nColorNumber > 0; }; + + // Forbid the use of direct affectation for now, it would be dangerous because + // of possible leaks and double frees. We could do a deep copy to be safe but + // it could possibly hurt the performance if we forgot about this and start + // using affectation a lot. + CompositionObject& operator=(const CompositionObject&) = delete; + +private: + BYTE* m_pRLEData; + size_t m_nRLEDataSize; + size_t m_nRLEPos; + int m_nColorNumber; + std::array m_colors; + + void DvbRenderField(SubPicDesc& spd, CGolombBuffer& gb, short nXStart, short nYStart, short nLength); + void Dvb2PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); + void Dvb4PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); + void Dvb8PixelsCodeString(SubPicDesc& spd, CGolombBuffer& gb, short& nX, short& nY); +}; diff --git a/src/Subtitles/DVBSub.cpp b/src/Subtitles/DVBSub.cpp index 45054ce3385..cc1384869dc 100644 --- a/src/Subtitles/DVBSub.cpp +++ b/src/Subtitles/DVBSub.cpp @@ -1,708 +1,708 @@ -/* - * (C) 2009-2016 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 . - * - */ - - -#include "stdafx.h" -#include "DVBSub.h" -#include "../DSUtil/GolombBuffer.h" -#include - -#if (0) // Set to 1 to activate DVB subtitles traces -#define TRACE_DVB TRACE -#else -#define TRACE_DVB __noop -#endif - -#define BUFFER_CHUNK_GROW 0x1000 - -CDVBSub::CDVBSub(CCritSec* pLock, const CString& name, LCID lcid) - : CRLECodedSubtitle(pLock, name, lcid) - , m_nBufferSize(0) - , m_nBufferReadPos(0) - , m_nBufferWritePos(0) - , m_pBuffer(nullptr) -{ - if (m_name.IsEmpty() || m_name == _T("Unknown")) { - m_name = _T("DVB Embedded Subtitle"); - } -} - -CDVBSub::~CDVBSub() -{ - Reset(); - SAFE_DELETE(m_pBuffer); -} - -// ISubPicProvider - -STDMETHODIMP_(POSITION) CDVBSub::GetStartPosition(REFERENCE_TIME rt, double fps) -{ - CAutoLock cAutoLock(&m_csCritSec); - - POSITION pos = m_pages.GetHeadPosition(); - while (pos) { - const auto& pPage = m_pages.GetAt(pos); - if (pPage->rtStop <= rt) { - m_pages.GetNext(pos); - } else { - break; - } - } - - return pos; -} - -STDMETHODIMP_(POSITION) CDVBSub::GetNext(POSITION pos) -{ - CAutoLock cAutoLock(&m_csCritSec); - m_pages.GetNext(pos); - return pos; -} - -STDMETHODIMP_(REFERENCE_TIME) CDVBSub::GetStart(POSITION pos, double fps) -{ - const auto& pPage = m_pages.GetAt(pos); - return pPage ? pPage->rtStart : INVALID_TIME; -} - -STDMETHODIMP_(REFERENCE_TIME) CDVBSub::GetStop(POSITION pos, double fps) -{ - const auto& pPage = m_pages.GetAt(pos); - return pPage ? pPage->rtStop : INVALID_TIME; -} - -STDMETHODIMP_(bool) CDVBSub::IsAnimated(POSITION pos) -{ - return false; -} - -STDMETHODIMP CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - CAutoLock cAutoLock(&m_csCritSec); - - RemoveOldPages(rt); - - if (POSITION posPage = FindPage(rt)) { - const auto& pPage = m_pages.GetAt(posPage); - if (m_eSourceMatrix == ColorConvTable::AUTO) { - m_eSourceMatrix = (m_displayInfo.width > 720) ? ColorConvTable::BT709 : ColorConvTable::BT601; - } - - pPage->rendered = true; - TRACE_DVB(_T("DVB - Renderer - %s - %s\n"), ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); - - size_t nRegion = 1; - for (const auto& regionPos : pPage->regionsPos) { - auto itRegion = FindRegion(pPage, regionPos.id); - if (itRegion != pPage->regions.cend()) { - const auto& pRegion = *itRegion; - auto itCLUT = FindClut(pPage, pRegion->CLUT_id); - - if (itCLUT != pPage->CLUTs.cend()) { - const auto& pCLUT = *itCLUT; - - size_t nObject = 1; - for (const auto& objectPos : pRegion->objects) { - auto itObject = FindObject(pPage, objectPos.object_id); - - if (itObject != pPage->objects.cend()) { - const auto& pObject = *itObject; - - short nX = regionPos.horizAddr + objectPos.object_horizontal_position; - short nY = regionPos.vertAddr + objectPos.object_vertical_position; - pObject->m_width = pRegion->width; - pObject->m_height = pRegion->height; - pObject->SetPalette(pCLUT->size, pCLUT->palette.data(), m_eSourceMatrix); - pObject->RenderDvb(spd, nX, nY); - - TRACE_DVB(_T(" --> %Iu/%Iu - %Iu/%Iu\n"), nRegion, pPage->regionsPos.size(), nObject, pRegion->objects.size()); - } - - nObject++; - } - } - } - - nRegion++; - } - - bbox.left = 0; - bbox.top = 0; - bbox.right = m_displayInfo.width; - bbox.bottom = m_displayInfo.height; - } - - return S_OK; -} - -HRESULT CDVBSub::GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) -{ - MaxTextureSize.cx = VideoSize.cx = m_displayInfo.width; - MaxTextureSize.cy = VideoSize.cy = m_displayInfo.height; - - VideoTopLeft.x = 0; - VideoTopLeft.y = 0; - - return S_OK; -} - -#define MARKER \ - if (gb.BitRead(1) != 1) { \ - ASSERT(FALSE); \ - return E_FAIL; \ - } - -HRESULT CDVBSub::ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen) -{ - CheckPointer(pData, E_POINTER); - - CAutoLock cAutoLock(&m_csCritSec); - - HRESULT hr; - DVB_SEGMENT_TYPE nCurSegment; - - - if (*((LONG*)pData) == 0xBD010000) { - CGolombBuffer gb(pData, nLen); - - size_t headerSize = 9; - - gb.SkipBytes(4); - WORD wLength = (WORD)gb.BitRead(16); - UNREFERENCED_PARAMETER(wLength); - - if (gb.BitRead(2) != 2) { - return E_FAIL; // type - } - - gb.BitRead(2); // scrambling - gb.BitRead(1); // priority - gb.BitRead(1); // alignment - gb.BitRead(1); // copyright - gb.BitRead(1); // original - BYTE fpts = (BYTE)gb.BitRead(1); // fpts - BYTE fdts = (BYTE)gb.BitRead(1); // fdts - gb.BitRead(1); // escr - gb.BitRead(1); // esrate - gb.BitRead(1); // dsmtrickmode - gb.BitRead(1); // morecopyright - gb.BitRead(1); // crc - gb.BitRead(1); // extension - gb.BitRead(8); // hdrlen - - if (fpts) { - BYTE b = (BYTE)gb.BitRead(4); - if (!(fdts && b == 3 || !fdts && b == 2)) { - ASSERT(FALSE); - return E_FAIL; - } - - REFERENCE_TIME pts = 0; - pts |= gb.BitRead(3) << 30; - MARKER; // 32..30 - pts |= gb.BitRead(15) << 15; - MARKER; // 29..15 - pts |= gb.BitRead(15); - MARKER; // 14..0 - pts = 10000 * pts / 90; - - TRACE_DVB(_T("DVB - ParseSample: Received a packet with a presentation timestamp PTS=%s\n"), ReftimeToString(pts)); - if (pts != rtStart) { - TRACE_DVB(_T("DVB - ParseSample: WARNING: The parsed PTS doesn't match the sample start time (%s)\n"), ReftimeToString(rtStart)); - ASSERT(FALSE); - rtStart = pts; - } - - headerSize += 5; - } - - nLen -= headerSize; - pData += headerSize; - } - - hr = AddToBuffer(pData, nLen); - if (hr == S_OK) { - CGolombBuffer gb(m_pBuffer + m_nBufferReadPos, m_nBufferWritePos - m_nBufferReadPos); - size_t nLastPos = 0; - - while (gb.RemainingSize() >= 6) { // Ensure there is enough data to parse the entire segment header - if (gb.ReadByte() == 0x0F) { - TRACE_DVB(_T("DVB - ParseSample\n")); - - WORD wPageId; - WORD wSegLength; - - nCurSegment = (DVB_SEGMENT_TYPE)gb.ReadByte(); - wPageId = gb.ReadShort(); - wSegLength = gb.ReadShort(); - - if (gb.RemainingSize() < wSegLength) { - TRACE_DVB(_T("DVB - Full segment isn't availabled yet, delaying parsing (%Iu/%hu)\n"), gb.RemainingSize(), wSegLength); - hr = S_FALSE; - break; - } - - hr = S_OK; - switch (nCurSegment) { - case PAGE: { - if (rtStart == INVALID_TIME) { - TRACE_DVB(_T("DVB - Page update ignored, %s\n"), ReftimeToString(rtStart)); - break; - } - - if (m_pCurrentPage) { - TRACE_DVB(_T("DVB - Force End display\n")); - EnqueuePage(rtStart); - } - UpdateTimeStamp(rtStart); - - CAutoPtr pPage; - hr = ParsePage(gb, wSegLength, pPage); - pPage->rtStart = rtStart; - pPage->rtStop = pPage->rtStart + pPage->pageTimeOut * 10000000i64; - - if (FAILED(hr)) { - pPage.Free(); - } else if (pPage->pageState == DPS_ACQUISITION || pPage->pageState == DPS_MODE_CHANGE) { - m_pCurrentPage = pPage; - - TRACE_DVB(_T("DVB - Page started [pageState = %d] %s, TimeOut = %ds\n"), m_pCurrentPage->pageState, - ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->pageTimeOut); - } else if (pPage->pageState == DPS_NORMAL && !m_pages.IsEmpty()) { - m_pCurrentPage = pPage; - - // Copy data from the previous page - const auto& pPrevPage = m_pages.GetTail(); - - for (const auto& region : pPrevPage->regions) { - m_pCurrentPage->regions.emplace_back(DEBUG_NEW DVB_REGION(*region)); - } - - for (const auto& object : pPrevPage->objects) { - m_pCurrentPage->objects.emplace_back(DEBUG_NEW CompositionObject(*object)); - } - - for (const auto& CLUT : pPrevPage->CLUTs) { - m_pCurrentPage->CLUTs.emplace_back(DEBUG_NEW DVB_CLUT(*CLUT)); - } - - TRACE_DVB(_T("DVB - Page started [update] %s, TimeOut = %ds\n"), - ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->pageTimeOut); - } else { - TRACE_DVB(_T("DVB - Page update ignored %s\n"), ReftimeToString(rtStart)); - } - } - break; - case REGION: - ParseRegion(gb, wSegLength); - TRACE_DVB(_T("DVB - Region\n")); - break; - case CLUT: - ParseClut(gb, wSegLength); - TRACE_DVB(_T("DVB - Clut\n")); - break; - case OBJECT: - ParseObject(gb, wSegLength); - TRACE_DVB(_T("DVB - Object\n")); - break; - case DISPLAY: - ParseDisplay(gb, wSegLength); - TRACE_DVB(_T("DVB - Display\n")); - break; - case END_OF_DISPLAY: - if (m_pCurrentPage == nullptr) { - TRACE_DVB(_T("DVB - Ignored End display %s: no current page\n"), ReftimeToString(rtStart)); - } else if (m_pCurrentPage->rtStart < rtStart) { - TRACE_DVB(_T("DVB - End display\n")); - EnqueuePage(rtStart); - } else { - TRACE_DVB(_T("DVB - Ignored End display %s: no information on page duration\n"), ReftimeToString(rtStart)); - } - break; - default: - TRACE_DVB(_T("DVB - Ignored segment with unknown type %d\n"), nCurSegment); - break; - } - if (FAILED(hr)) { - gb.SkipBytes(6 + wSegLength - (gb.GetPos() - nLastPos)); - TRACE_DVB(_T("Parsing failed with code %x, skipping to the end of the segment\n"), hr); - } - } - nLastPos = gb.GetPos(); - } - m_nBufferReadPos += nLastPos; - } - - return hr; -} - -void CDVBSub::EndOfStream() -{ - CAutoLock cAutoLock(&m_csCritSec); - - // Enqueue the last page if necessary. - if (m_pCurrentPage) { - TRACE_DVB(_T("DVB - EndOfStream: Enqueue last page\n")); - EnqueuePage(INVALID_TIME); - } else { - TRACE_DVB(_T("DVB - EndOfStream ignored: no page to enqueue\n")); - } -} - -void CDVBSub::Reset() -{ - CAutoLock cAutoLock(&m_csCritSec); - - m_nBufferReadPos = 0; - m_nBufferWritePos = 0; - m_pCurrentPage.Free(); - m_pages.RemoveAll(); -} - -HRESULT CDVBSub::AddToBuffer(BYTE* pData, size_t nSize) -{ - bool bFirstChunk = (*((LONG*)pData) & 0x00FFFFFF) == 0x000f0020; // DVB sub start with 0x20 0x00 0x0F ... - - if (m_nBufferWritePos > 0 || bFirstChunk) { - if (bFirstChunk) { - m_nBufferWritePos = 0; - m_nBufferReadPos = 0; - } - - if (m_nBufferWritePos + nSize > m_nBufferSize) { - if (m_nBufferWritePos + nSize > 20 * BUFFER_CHUNK_GROW) { - // Too big to be a DVB sub ! - TRACE_DVB(_T("DVB - Too much data received...\n")); - ASSERT(FALSE); - - Reset(); - return E_INVALIDARG; - } - - BYTE* pPrev = m_pBuffer; - m_nBufferSize = std::max(m_nBufferWritePos + nSize, m_nBufferSize + BUFFER_CHUNK_GROW); - m_pBuffer = DEBUG_NEW BYTE[m_nBufferSize]; - if (pPrev != nullptr) { - memcpy_s(m_pBuffer, m_nBufferSize, pPrev, m_nBufferWritePos); - SAFE_DELETE(pPrev); - } - } - memcpy_s(m_pBuffer + m_nBufferWritePos, m_nBufferSize, pData, nSize); - m_nBufferWritePos += nSize; - return S_OK; - } - return S_FALSE; -} - -POSITION CDVBSub::FindPage(REFERENCE_TIME rt) const -{ - POSITION pos = m_pages.GetHeadPosition(); - - while (pos) { - POSITION currentPos = pos; - const auto& pPage = m_pages.GetNext(pos); - - if (rt >= pPage->rtStart && rt < pPage->rtStop) { - return currentPos; - } - } - - return nullptr; -} - -CDVBSub::RegionList::const_iterator CDVBSub::FindRegion(const CAutoPtr& pPage, BYTE bRegionId) const -{ - ENSURE(pPage); - - return std::find_if(pPage->regions.cbegin(), pPage->regions.cend(), - [bRegionId](const std::unique_ptr& pRegion) { - return pRegion->id == bRegionId; - }); -} - -CDVBSub::ClutList::const_iterator CDVBSub::FindClut(const CAutoPtr& pPage, BYTE bClutId) const -{ - ENSURE(pPage); - - return std::find_if(pPage->CLUTs.cbegin(), pPage->CLUTs.cend(), - [bClutId](const std::unique_ptr& pCLUT) { - return pCLUT->id == bClutId; - }); -} - -CDVBSub::CompositionObjectList::const_iterator CDVBSub::FindObject(const CAutoPtr& pPage, short sObjectId) const -{ - ENSURE(pPage); - - return std::find_if(pPage->objects.cbegin(), pPage->objects.cend(), - [sObjectId](const std::unique_ptr& pObject) { - return pObject->m_object_id_ref == sObjectId; - }); -} - -HRESULT CDVBSub::ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage) -{ - size_t nExpectedSize = 2; - size_t nEnd = gb.GetPos() + wSegLength; - - pPage.Attach(DEBUG_NEW DVB_PAGE()); - - pPage->pageTimeOut = gb.ReadByte(); - pPage->pageVersionNumber = (BYTE)gb.BitRead(4); - pPage->pageState = (BYTE)gb.BitRead(2); - gb.BitRead(2); // Reserved - while (gb.GetPos() < nEnd) { - nExpectedSize += 6; - DVB_REGION_POS regionPos; - regionPos.id = gb.ReadByte(); - gb.ReadByte(); // Reserved - regionPos.horizAddr = gb.ReadShort(); - regionPos.vertAddr = gb.ReadShort(); - pPage->regionsPos.emplace_back(std::move(regionPos)); - } - - return (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; -} - -HRESULT CDVBSub::ParseDisplay(CGolombBuffer& gb, WORD wSegLength) -{ - int nExpectedSize = 5; - - m_displayInfo.version_number = (BYTE)gb.BitRead(4); - m_displayInfo.display_window_flag = (BYTE)gb.BitRead(1); - gb.BitRead(3); // reserved - m_displayInfo.width = gb.ReadShort() + 1; - m_displayInfo.height = gb.ReadShort() + 1; - if (m_displayInfo.display_window_flag) { - nExpectedSize += 8; - m_displayInfo.horizontal_position_minimun = gb.ReadShort(); - m_displayInfo.horizontal_position_maximum = gb.ReadShort(); - m_displayInfo.vertical_position_minimun = gb.ReadShort(); - m_displayInfo.vertical_position_maximum = gb.ReadShort(); - } - - return (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; -} - -HRESULT CDVBSub::ParseRegion(CGolombBuffer& gb, WORD wSegLength) -{ - HRESULT hr = E_POINTER; - - if (m_pCurrentPage) { - size_t nExpectedSize = 10; - size_t nEnd = gb.GetPos() + wSegLength; - - BYTE id = gb.ReadByte(); - auto itRegion = FindRegion(m_pCurrentPage, id); - if (itRegion == m_pCurrentPage->regions.cend()) { - m_pCurrentPage->regions.emplace_back(DEBUG_NEW DVB_REGION()); - itRegion = std::prev(m_pCurrentPage->regions.cend()); - } - const auto& pRegion = *itRegion; - - pRegion->id = id; - pRegion->version_number = (BYTE)gb.BitRead(4); - pRegion->fill_flag = (BYTE)gb.BitRead(1); - gb.BitRead(3); // Reserved - pRegion->width = gb.ReadShort(); - pRegion->height = gb.ReadShort(); - pRegion->level_of_compatibility = (BYTE)gb.BitRead(3); - pRegion->depth = (BYTE)gb.BitRead(3); - gb.BitRead(2); // Reserved - pRegion->CLUT_id = gb.ReadByte(); - pRegion->_8_bit_pixel_code = gb.ReadByte(); - pRegion->_4_bit_pixel_code = (BYTE)gb.BitRead(4); - pRegion->_2_bit_pixel_code = (BYTE)gb.BitRead(2); - gb.BitRead(2); // Reserved - - while (gb.GetPos() < nEnd) { - nExpectedSize += 6; - DVB_OBJECT object; - object.object_id = gb.ReadShort(); - object.object_type = (BYTE)gb.BitRead(2); - object.object_provider_flag = (BYTE)gb.BitRead(2); - object.object_horizontal_position = (short)gb.BitRead(12); - gb.BitRead(4); // Reserved - object.object_vertical_position = (short)gb.BitRead(12); - if (object.object_type == 0x01 || object.object_type == 0x02) { - nExpectedSize += 2; - object.foreground_pixel_code = gb.ReadByte(); - object.background_pixel_code = gb.ReadByte(); - } - pRegion->objects.emplace_back(std::move(object)); - } - - hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; - } - - return hr; -} - -HRESULT CDVBSub::ParseClut(CGolombBuffer& gb, WORD wSegLength) -{ - HRESULT hr = E_POINTER; - - if (m_pCurrentPage) { - size_t nExpectedSize = 2; - size_t nEnd = gb.GetPos() + wSegLength; - - BYTE id = gb.ReadByte(); - auto itClut = FindClut(m_pCurrentPage, id); - if (itClut == m_pCurrentPage->CLUTs.cend()) { - m_pCurrentPage->CLUTs.emplace_back(DEBUG_NEW DVB_CLUT()); - itClut = std::prev(m_pCurrentPage->CLUTs.cend()); - } - const auto& pClut = *itClut; - - pClut->id = id; - pClut->version_number = (BYTE)gb.BitRead(4); - gb.BitRead(4); // Reserved - - pClut->size = 0; - while (gb.GetPos() < nEnd) { - nExpectedSize += 2; - pClut->palette[pClut->size].entry_id = gb.ReadByte(); - - BYTE _2_bit = (BYTE)gb.BitRead(1); - BYTE _4_bit = (BYTE)gb.BitRead(1); - BYTE _8_bit = (BYTE)gb.BitRead(1); - UNREFERENCED_PARAMETER(_2_bit); - UNREFERENCED_PARAMETER(_4_bit); - UNREFERENCED_PARAMETER(_8_bit); - gb.BitRead(4); // Reserved - - if (gb.BitRead(1)) { - nExpectedSize += 4; - pClut->palette[pClut->size].Y = gb.ReadByte(); - pClut->palette[pClut->size].Cr = gb.ReadByte(); - pClut->palette[pClut->size].Cb = gb.ReadByte(); - pClut->palette[pClut->size].T = 0xff - gb.ReadByte(); - } else { - nExpectedSize += 2; - pClut->palette[pClut->size].Y = (BYTE)gb.BitRead(6) << 2; - pClut->palette[pClut->size].Cr = (BYTE)gb.BitRead(4) << 4; - pClut->palette[pClut->size].Cb = (BYTE)gb.BitRead(4) << 4; - pClut->palette[pClut->size].T = 0xff - ((BYTE)gb.BitRead(2) << 6); - } - if (!pClut->palette[pClut->size].Y) { - pClut->palette[pClut->size].Cr = 0; - pClut->palette[pClut->size].Cb = 0; - pClut->palette[pClut->size].T = 0; - } - - pClut->size++; - } - - hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; - } - - return hr; -} - -HRESULT CDVBSub::ParseObject(CGolombBuffer& gb, WORD wSegLength) -{ - HRESULT hr = E_POINTER; - - if (m_pCurrentPage) { - size_t nExpectedSize = 3; - // size_t nEnd = gb.GetPos() + wSegLength; - - short id = gb.ReadShort(); - auto itObject = FindObject(m_pCurrentPage, id); - if (itObject == m_pCurrentPage->objects.cend()) { - m_pCurrentPage->objects.emplace_back(DEBUG_NEW CompositionObject()); - itObject = std::prev(m_pCurrentPage->objects.cend()); - } - const auto& pObject = *itObject; - - pObject->m_object_id_ref = id; - pObject->m_version_number = (BYTE)gb.BitRead(4); - - BYTE object_coding_method = (BYTE)gb.BitRead(2); // object_coding_method - gb.BitRead(1); // non_modifying_colour_flag - gb.BitRead(1); // reserved - - if (object_coding_method == 0x00) { - pObject->SetRLEData(gb.GetBufferPos(), wSegLength - nExpectedSize, wSegLength - nExpectedSize); - gb.SkipBytes(wSegLength - 3); - - hr = (wSegLength >= nExpectedSize) ? S_OK : E_UNEXPECTED; - } else { - TRACE_DVB(_T("DVB - Text subtitles are currently not supported\n")); - m_pCurrentPage->objects.pop_back(); - hr = E_NOTIMPL; - } - } - - return hr; -} - -HRESULT CDVBSub::EnqueuePage(REFERENCE_TIME rtStop) -{ - ASSERT(m_pCurrentPage != nullptr); - if (m_pCurrentPage->rtStart < rtStop && m_pCurrentPage->rtStop > rtStop) { - m_pCurrentPage->rtStop = rtStop; - } - TRACE_DVB(_T("DVB - Enqueue page %s (%s - %s)\n"), ReftimeToString(rtStop), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); - m_pages.AddTail(m_pCurrentPage); - - return S_OK; -} - -HRESULT CDVBSub::UpdateTimeStamp(REFERENCE_TIME rtStop) -{ - HRESULT hr = S_FALSE; - POSITION pos = m_pages.GetTailPosition(); - while (pos) { - const auto& pPage = m_pages.GetPrev(pos); - if (pPage->rtStop > rtStop) { - TRACE_DVB(_T("DVB - Updated end of display %s - %s --> %s - %s\n"), - ReftimeToString(pPage->rtStart), - ReftimeToString(pPage->rtStop), - ReftimeToString(pPage->rtStart), - ReftimeToString(rtStop)); - pPage->rtStop = rtStop; - hr = S_OK; - } else { - break; - } - } - - return hr; -} - -void CDVBSub::RemoveOldPages(REFERENCE_TIME rt) -{ - // Cleanup the old pages. We keep a 2 min buffer to play nice with the queue. - while (!m_pages.IsEmpty() && m_pages.GetHead()->rtStop + 120 * 10000000i64 < rt) { - const auto& pPage = m_pages.GetHead(); - if (!pPage->rendered) { - TRACE_DVB(_T("DVB - remove unrendered object, %s - %s\n"), - ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); - } - m_pages.RemoveHeadNoReturn(); - } -} - -STDMETHODIMP CDVBSub::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) -{ - relativeTo = RelativeTo::BEST_FIT; - return S_OK; -} +/* + * (C) 2009-2016 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 . + * + */ + + +#include "stdafx.h" +#include "DVBSub.h" +#include "../DSUtil/GolombBuffer.h" +#include + +#if (0) // Set to 1 to activate DVB subtitles traces +#define TRACE_DVB TRACE +#else +#define TRACE_DVB __noop +#endif + +#define BUFFER_CHUNK_GROW 0x1000 + +CDVBSub::CDVBSub(CCritSec* pLock, const CString& name, LCID lcid) + : CRLECodedSubtitle(pLock, name, lcid) + , m_nBufferSize(0) + , m_nBufferReadPos(0) + , m_nBufferWritePos(0) + , m_pBuffer(nullptr) +{ + if (m_name.IsEmpty() || m_name == _T("Unknown")) { + m_name = _T("DVB Embedded Subtitle"); + } +} + +CDVBSub::~CDVBSub() +{ + Reset(); + SAFE_DELETE(m_pBuffer); +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CDVBSub::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + CAutoLock cAutoLock(&m_csCritSec); + + POSITION pos = m_pages.GetHeadPosition(); + while (pos) { + const auto& pPage = m_pages.GetAt(pos); + if (pPage->rtStop <= rt) { + m_pages.GetNext(pos); + } else { + break; + } + } + + return pos; +} + +STDMETHODIMP_(POSITION) CDVBSub::GetNext(POSITION pos) +{ + CAutoLock cAutoLock(&m_csCritSec); + m_pages.GetNext(pos); + return pos; +} + +STDMETHODIMP_(REFERENCE_TIME) CDVBSub::GetStart(POSITION pos, double fps) +{ + const auto& pPage = m_pages.GetAt(pos); + return pPage ? pPage->rtStart : INVALID_TIME; +} + +STDMETHODIMP_(REFERENCE_TIME) CDVBSub::GetStop(POSITION pos, double fps) +{ + const auto& pPage = m_pages.GetAt(pos); + return pPage ? pPage->rtStop : INVALID_TIME; +} + +STDMETHODIMP_(bool) CDVBSub::IsAnimated(POSITION pos) +{ + return false; +} + +STDMETHODIMP CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + CAutoLock cAutoLock(&m_csCritSec); + + RemoveOldPages(rt); + + if (POSITION posPage = FindPage(rt)) { + const auto& pPage = m_pages.GetAt(posPage); + if (m_eSourceMatrix == ColorConvTable::AUTO) { + m_eSourceMatrix = (m_displayInfo.width > 720) ? ColorConvTable::BT709 : ColorConvTable::BT601; + } + + pPage->rendered = true; + TRACE_DVB(_T("DVB - Renderer - %s - %s\n"), ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); + + size_t nRegion = 1; + for (const auto& regionPos : pPage->regionsPos) { + auto itRegion = FindRegion(pPage, regionPos.id); + if (itRegion != pPage->regions.cend()) { + const auto& pRegion = *itRegion; + auto itCLUT = FindClut(pPage, pRegion->CLUT_id); + + if (itCLUT != pPage->CLUTs.cend()) { + const auto& pCLUT = *itCLUT; + + size_t nObject = 1; + for (const auto& objectPos : pRegion->objects) { + auto itObject = FindObject(pPage, objectPos.object_id); + + if (itObject != pPage->objects.cend()) { + const auto& pObject = *itObject; + + short nX = regionPos.horizAddr + objectPos.object_horizontal_position; + short nY = regionPos.vertAddr + objectPos.object_vertical_position; + pObject->m_width = pRegion->width; + pObject->m_height = pRegion->height; + pObject->SetPalette(pCLUT->size, pCLUT->palette.data(), m_eSourceMatrix); + pObject->RenderDvb(spd, nX, nY); + + TRACE_DVB(_T(" --> %Iu/%Iu - %Iu/%Iu\n"), nRegion, pPage->regionsPos.size(), nObject, pRegion->objects.size()); + } + + nObject++; + } + } + } + + nRegion++; + } + + bbox.left = 0; + bbox.top = 0; + bbox.right = m_displayInfo.width; + bbox.bottom = m_displayInfo.height; + } + + return S_OK; +} + +HRESULT CDVBSub::GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) +{ + MaxTextureSize.cx = VideoSize.cx = m_displayInfo.width; + MaxTextureSize.cy = VideoSize.cy = m_displayInfo.height; + + VideoTopLeft.x = 0; + VideoTopLeft.y = 0; + + return S_OK; +} + +#define MARKER \ + if (gb.BitRead(1) != 1) { \ + ASSERT(FALSE); \ + return E_FAIL; \ + } + +HRESULT CDVBSub::ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen) +{ + CheckPointer(pData, E_POINTER); + + CAutoLock cAutoLock(&m_csCritSec); + + HRESULT hr; + DVB_SEGMENT_TYPE nCurSegment; + + + if (*((LONG*)pData) == 0xBD010000) { + CGolombBuffer gb(pData, nLen); + + size_t headerSize = 9; + + gb.SkipBytes(4); + WORD wLength = (WORD)gb.BitRead(16); + UNREFERENCED_PARAMETER(wLength); + + if (gb.BitRead(2) != 2) { + return E_FAIL; // type + } + + gb.BitRead(2); // scrambling + gb.BitRead(1); // priority + gb.BitRead(1); // alignment + gb.BitRead(1); // copyright + gb.BitRead(1); // original + BYTE fpts = (BYTE)gb.BitRead(1); // fpts + BYTE fdts = (BYTE)gb.BitRead(1); // fdts + gb.BitRead(1); // escr + gb.BitRead(1); // esrate + gb.BitRead(1); // dsmtrickmode + gb.BitRead(1); // morecopyright + gb.BitRead(1); // crc + gb.BitRead(1); // extension + gb.BitRead(8); // hdrlen + + if (fpts) { + BYTE b = (BYTE)gb.BitRead(4); + if (!(fdts && b == 3 || !fdts && b == 2)) { + ASSERT(FALSE); + return E_FAIL; + } + + REFERENCE_TIME pts = 0; + pts |= gb.BitRead(3) << 30; + MARKER; // 32..30 + pts |= gb.BitRead(15) << 15; + MARKER; // 29..15 + pts |= gb.BitRead(15); + MARKER; // 14..0 + pts = 10000 * pts / 90; + + TRACE_DVB(_T("DVB - ParseSample: Received a packet with a presentation timestamp PTS=%s\n"), ReftimeToString(pts)); + if (pts != rtStart) { + TRACE_DVB(_T("DVB - ParseSample: WARNING: The parsed PTS doesn't match the sample start time (%s)\n"), ReftimeToString(rtStart)); + ASSERT(FALSE); + rtStart = pts; + } + + headerSize += 5; + } + + nLen -= headerSize; + pData += headerSize; + } + + hr = AddToBuffer(pData, nLen); + if (hr == S_OK) { + CGolombBuffer gb(m_pBuffer + m_nBufferReadPos, m_nBufferWritePos - m_nBufferReadPos); + size_t nLastPos = 0; + + while (gb.RemainingSize() >= 6) { // Ensure there is enough data to parse the entire segment header + if (gb.ReadByte() == 0x0F) { + TRACE_DVB(_T("DVB - ParseSample\n")); + + WORD wPageId; + WORD wSegLength; + + nCurSegment = (DVB_SEGMENT_TYPE)gb.ReadByte(); + wPageId = gb.ReadShort(); + wSegLength = gb.ReadShort(); + + if (gb.RemainingSize() < wSegLength) { + TRACE_DVB(_T("DVB - Full segment isn't availabled yet, delaying parsing (%Iu/%hu)\n"), gb.RemainingSize(), wSegLength); + hr = S_FALSE; + break; + } + + hr = S_OK; + switch (nCurSegment) { + case PAGE: { + if (rtStart == INVALID_TIME) { + TRACE_DVB(_T("DVB - Page update ignored, %s\n"), ReftimeToString(rtStart)); + break; + } + + if (m_pCurrentPage) { + TRACE_DVB(_T("DVB - Force End display\n")); + EnqueuePage(rtStart); + } + UpdateTimeStamp(rtStart); + + CAutoPtr pPage; + hr = ParsePage(gb, wSegLength, pPage); + pPage->rtStart = rtStart; + pPage->rtStop = pPage->rtStart + pPage->pageTimeOut * 10000000i64; + + if (FAILED(hr)) { + pPage.Free(); + } else if (pPage->pageState == DPS_ACQUISITION || pPage->pageState == DPS_MODE_CHANGE) { + m_pCurrentPage = pPage; + + TRACE_DVB(_T("DVB - Page started [pageState = %d] %s, TimeOut = %ds\n"), m_pCurrentPage->pageState, + ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->pageTimeOut); + } else if (pPage->pageState == DPS_NORMAL && !m_pages.IsEmpty()) { + m_pCurrentPage = pPage; + + // Copy data from the previous page + const auto& pPrevPage = m_pages.GetTail(); + + for (const auto& region : pPrevPage->regions) { + m_pCurrentPage->regions.emplace_back(DEBUG_NEW DVB_REGION(*region)); + } + + for (const auto& object : pPrevPage->objects) { + m_pCurrentPage->objects.emplace_back(DEBUG_NEW CompositionObject(*object)); + } + + for (const auto& CLUT : pPrevPage->CLUTs) { + m_pCurrentPage->CLUTs.emplace_back(DEBUG_NEW DVB_CLUT(*CLUT)); + } + + TRACE_DVB(_T("DVB - Page started [update] %s, TimeOut = %ds\n"), + ReftimeToString(m_pCurrentPage->rtStart), m_pCurrentPage->pageTimeOut); + } else { + TRACE_DVB(_T("DVB - Page update ignored %s\n"), ReftimeToString(rtStart)); + } + } + break; + case REGION: + ParseRegion(gb, wSegLength); + TRACE_DVB(_T("DVB - Region\n")); + break; + case CLUT: + ParseClut(gb, wSegLength); + TRACE_DVB(_T("DVB - Clut\n")); + break; + case OBJECT: + ParseObject(gb, wSegLength); + TRACE_DVB(_T("DVB - Object\n")); + break; + case DISPLAY: + ParseDisplay(gb, wSegLength); + TRACE_DVB(_T("DVB - Display\n")); + break; + case END_OF_DISPLAY: + if (m_pCurrentPage == nullptr) { + TRACE_DVB(_T("DVB - Ignored End display %s: no current page\n"), ReftimeToString(rtStart)); + } else if (m_pCurrentPage->rtStart < rtStart) { + TRACE_DVB(_T("DVB - End display\n")); + EnqueuePage(rtStart); + } else { + TRACE_DVB(_T("DVB - Ignored End display %s: no information on page duration\n"), ReftimeToString(rtStart)); + } + break; + default: + TRACE_DVB(_T("DVB - Ignored segment with unknown type %d\n"), nCurSegment); + break; + } + if (FAILED(hr)) { + gb.SkipBytes(6 + wSegLength - (gb.GetPos() - nLastPos)); + TRACE_DVB(_T("Parsing failed with code %x, skipping to the end of the segment\n"), hr); + } + } + nLastPos = gb.GetPos(); + } + m_nBufferReadPos += nLastPos; + } + + return hr; +} + +void CDVBSub::EndOfStream() +{ + CAutoLock cAutoLock(&m_csCritSec); + + // Enqueue the last page if necessary. + if (m_pCurrentPage) { + TRACE_DVB(_T("DVB - EndOfStream: Enqueue last page\n")); + EnqueuePage(INVALID_TIME); + } else { + TRACE_DVB(_T("DVB - EndOfStream ignored: no page to enqueue\n")); + } +} + +void CDVBSub::Reset() +{ + CAutoLock cAutoLock(&m_csCritSec); + + m_nBufferReadPos = 0; + m_nBufferWritePos = 0; + m_pCurrentPage.Free(); + m_pages.RemoveAll(); +} + +HRESULT CDVBSub::AddToBuffer(BYTE* pData, size_t nSize) +{ + bool bFirstChunk = (*((LONG*)pData) & 0x00FFFFFF) == 0x000f0020; // DVB sub start with 0x20 0x00 0x0F ... + + if (m_nBufferWritePos > 0 || bFirstChunk) { + if (bFirstChunk) { + m_nBufferWritePos = 0; + m_nBufferReadPos = 0; + } + + if (m_nBufferWritePos + nSize > m_nBufferSize) { + if (m_nBufferWritePos + nSize > 20 * BUFFER_CHUNK_GROW) { + // Too big to be a DVB sub ! + TRACE_DVB(_T("DVB - Too much data received...\n")); + ASSERT(FALSE); + + Reset(); + return E_INVALIDARG; + } + + BYTE* pPrev = m_pBuffer; + m_nBufferSize = std::max(m_nBufferWritePos + nSize, m_nBufferSize + BUFFER_CHUNK_GROW); + m_pBuffer = DEBUG_NEW BYTE[m_nBufferSize]; + if (pPrev != nullptr) { + memcpy_s(m_pBuffer, m_nBufferSize, pPrev, m_nBufferWritePos); + SAFE_DELETE(pPrev); + } + } + memcpy_s(m_pBuffer + m_nBufferWritePos, m_nBufferSize, pData, nSize); + m_nBufferWritePos += nSize; + return S_OK; + } + return S_FALSE; +} + +POSITION CDVBSub::FindPage(REFERENCE_TIME rt) const +{ + POSITION pos = m_pages.GetHeadPosition(); + + while (pos) { + POSITION currentPos = pos; + const auto& pPage = m_pages.GetNext(pos); + + if (rt >= pPage->rtStart && rt < pPage->rtStop) { + return currentPos; + } + } + + return nullptr; +} + +CDVBSub::RegionList::const_iterator CDVBSub::FindRegion(const CAutoPtr& pPage, BYTE bRegionId) const +{ + ENSURE(pPage); + + return std::find_if(pPage->regions.cbegin(), pPage->regions.cend(), + [bRegionId](const std::unique_ptr& pRegion) { + return pRegion->id == bRegionId; + }); +} + +CDVBSub::ClutList::const_iterator CDVBSub::FindClut(const CAutoPtr& pPage, BYTE bClutId) const +{ + ENSURE(pPage); + + return std::find_if(pPage->CLUTs.cbegin(), pPage->CLUTs.cend(), + [bClutId](const std::unique_ptr& pCLUT) { + return pCLUT->id == bClutId; + }); +} + +CDVBSub::CompositionObjectList::const_iterator CDVBSub::FindObject(const CAutoPtr& pPage, short sObjectId) const +{ + ENSURE(pPage); + + return std::find_if(pPage->objects.cbegin(), pPage->objects.cend(), + [sObjectId](const std::unique_ptr& pObject) { + return pObject->m_object_id_ref == sObjectId; + }); +} + +HRESULT CDVBSub::ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage) +{ + size_t nExpectedSize = 2; + size_t nEnd = gb.GetPos() + wSegLength; + + pPage.Attach(DEBUG_NEW DVB_PAGE()); + + pPage->pageTimeOut = gb.ReadByte(); + pPage->pageVersionNumber = (BYTE)gb.BitRead(4); + pPage->pageState = (BYTE)gb.BitRead(2); + gb.BitRead(2); // Reserved + while (gb.GetPos() < nEnd) { + nExpectedSize += 6; + DVB_REGION_POS regionPos; + regionPos.id = gb.ReadByte(); + gb.ReadByte(); // Reserved + regionPos.horizAddr = gb.ReadShort(); + regionPos.vertAddr = gb.ReadShort(); + pPage->regionsPos.emplace_back(std::move(regionPos)); + } + + return (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; +} + +HRESULT CDVBSub::ParseDisplay(CGolombBuffer& gb, WORD wSegLength) +{ + int nExpectedSize = 5; + + m_displayInfo.version_number = (BYTE)gb.BitRead(4); + m_displayInfo.display_window_flag = (BYTE)gb.BitRead(1); + gb.BitRead(3); // reserved + m_displayInfo.width = gb.ReadShort() + 1; + m_displayInfo.height = gb.ReadShort() + 1; + if (m_displayInfo.display_window_flag) { + nExpectedSize += 8; + m_displayInfo.horizontal_position_minimun = gb.ReadShort(); + m_displayInfo.horizontal_position_maximum = gb.ReadShort(); + m_displayInfo.vertical_position_minimun = gb.ReadShort(); + m_displayInfo.vertical_position_maximum = gb.ReadShort(); + } + + return (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; +} + +HRESULT CDVBSub::ParseRegion(CGolombBuffer& gb, WORD wSegLength) +{ + HRESULT hr = E_POINTER; + + if (m_pCurrentPage) { + size_t nExpectedSize = 10; + size_t nEnd = gb.GetPos() + wSegLength; + + BYTE id = gb.ReadByte(); + auto itRegion = FindRegion(m_pCurrentPage, id); + if (itRegion == m_pCurrentPage->regions.cend()) { + m_pCurrentPage->regions.emplace_back(DEBUG_NEW DVB_REGION()); + itRegion = std::prev(m_pCurrentPage->regions.cend()); + } + const auto& pRegion = *itRegion; + + pRegion->id = id; + pRegion->version_number = (BYTE)gb.BitRead(4); + pRegion->fill_flag = (BYTE)gb.BitRead(1); + gb.BitRead(3); // Reserved + pRegion->width = gb.ReadShort(); + pRegion->height = gb.ReadShort(); + pRegion->level_of_compatibility = (BYTE)gb.BitRead(3); + pRegion->depth = (BYTE)gb.BitRead(3); + gb.BitRead(2); // Reserved + pRegion->CLUT_id = gb.ReadByte(); + pRegion->_8_bit_pixel_code = gb.ReadByte(); + pRegion->_4_bit_pixel_code = (BYTE)gb.BitRead(4); + pRegion->_2_bit_pixel_code = (BYTE)gb.BitRead(2); + gb.BitRead(2); // Reserved + + while (gb.GetPos() < nEnd) { + nExpectedSize += 6; + DVB_OBJECT object; + object.object_id = gb.ReadShort(); + object.object_type = (BYTE)gb.BitRead(2); + object.object_provider_flag = (BYTE)gb.BitRead(2); + object.object_horizontal_position = (short)gb.BitRead(12); + gb.BitRead(4); // Reserved + object.object_vertical_position = (short)gb.BitRead(12); + if (object.object_type == 0x01 || object.object_type == 0x02) { + nExpectedSize += 2; + object.foreground_pixel_code = gb.ReadByte(); + object.background_pixel_code = gb.ReadByte(); + } + pRegion->objects.emplace_back(std::move(object)); + } + + hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; + } + + return hr; +} + +HRESULT CDVBSub::ParseClut(CGolombBuffer& gb, WORD wSegLength) +{ + HRESULT hr = E_POINTER; + + if (m_pCurrentPage) { + size_t nExpectedSize = 2; + size_t nEnd = gb.GetPos() + wSegLength; + + BYTE id = gb.ReadByte(); + auto itClut = FindClut(m_pCurrentPage, id); + if (itClut == m_pCurrentPage->CLUTs.cend()) { + m_pCurrentPage->CLUTs.emplace_back(DEBUG_NEW DVB_CLUT()); + itClut = std::prev(m_pCurrentPage->CLUTs.cend()); + } + const auto& pClut = *itClut; + + pClut->id = id; + pClut->version_number = (BYTE)gb.BitRead(4); + gb.BitRead(4); // Reserved + + pClut->size = 0; + while (gb.GetPos() < nEnd) { + nExpectedSize += 2; + pClut->palette[pClut->size].entry_id = gb.ReadByte(); + + BYTE _2_bit = (BYTE)gb.BitRead(1); + BYTE _4_bit = (BYTE)gb.BitRead(1); + BYTE _8_bit = (BYTE)gb.BitRead(1); + UNREFERENCED_PARAMETER(_2_bit); + UNREFERENCED_PARAMETER(_4_bit); + UNREFERENCED_PARAMETER(_8_bit); + gb.BitRead(4); // Reserved + + if (gb.BitRead(1)) { + nExpectedSize += 4; + pClut->palette[pClut->size].Y = gb.ReadByte(); + pClut->palette[pClut->size].Cr = gb.ReadByte(); + pClut->palette[pClut->size].Cb = gb.ReadByte(); + pClut->palette[pClut->size].T = 0xff - gb.ReadByte(); + } else { + nExpectedSize += 2; + pClut->palette[pClut->size].Y = (BYTE)gb.BitRead(6) << 2; + pClut->palette[pClut->size].Cr = (BYTE)gb.BitRead(4) << 4; + pClut->palette[pClut->size].Cb = (BYTE)gb.BitRead(4) << 4; + pClut->palette[pClut->size].T = 0xff - ((BYTE)gb.BitRead(2) << 6); + } + if (!pClut->palette[pClut->size].Y) { + pClut->palette[pClut->size].Cr = 0; + pClut->palette[pClut->size].Cb = 0; + pClut->palette[pClut->size].T = 0; + } + + pClut->size++; + } + + hr = (wSegLength == nExpectedSize) ? S_OK : E_UNEXPECTED; + } + + return hr; +} + +HRESULT CDVBSub::ParseObject(CGolombBuffer& gb, WORD wSegLength) +{ + HRESULT hr = E_POINTER; + + if (m_pCurrentPage) { + size_t nExpectedSize = 3; + // size_t nEnd = gb.GetPos() + wSegLength; + + short id = gb.ReadShort(); + auto itObject = FindObject(m_pCurrentPage, id); + if (itObject == m_pCurrentPage->objects.cend()) { + m_pCurrentPage->objects.emplace_back(DEBUG_NEW CompositionObject()); + itObject = std::prev(m_pCurrentPage->objects.cend()); + } + const auto& pObject = *itObject; + + pObject->m_object_id_ref = id; + pObject->m_version_number = (BYTE)gb.BitRead(4); + + BYTE object_coding_method = (BYTE)gb.BitRead(2); // object_coding_method + gb.BitRead(1); // non_modifying_colour_flag + gb.BitRead(1); // reserved + + if (object_coding_method == 0x00) { + pObject->SetRLEData(gb.GetBufferPos(), wSegLength - nExpectedSize, wSegLength - nExpectedSize); + gb.SkipBytes(wSegLength - 3); + + hr = (wSegLength >= nExpectedSize) ? S_OK : E_UNEXPECTED; + } else { + TRACE_DVB(_T("DVB - Text subtitles are currently not supported\n")); + m_pCurrentPage->objects.pop_back(); + hr = E_NOTIMPL; + } + } + + return hr; +} + +HRESULT CDVBSub::EnqueuePage(REFERENCE_TIME rtStop) +{ + ASSERT(m_pCurrentPage != nullptr); + if (m_pCurrentPage->rtStart < rtStop && m_pCurrentPage->rtStop > rtStop) { + m_pCurrentPage->rtStop = rtStop; + } + TRACE_DVB(_T("DVB - Enqueue page %s (%s - %s)\n"), ReftimeToString(rtStop), ReftimeToString(m_pCurrentPage->rtStart), ReftimeToString(m_pCurrentPage->rtStop)); + m_pages.AddTail(m_pCurrentPage); + + return S_OK; +} + +HRESULT CDVBSub::UpdateTimeStamp(REFERENCE_TIME rtStop) +{ + HRESULT hr = S_FALSE; + POSITION pos = m_pages.GetTailPosition(); + while (pos) { + const auto& pPage = m_pages.GetPrev(pos); + if (pPage->rtStop > rtStop) { + TRACE_DVB(_T("DVB - Updated end of display %s - %s --> %s - %s\n"), + ReftimeToString(pPage->rtStart), + ReftimeToString(pPage->rtStop), + ReftimeToString(pPage->rtStart), + ReftimeToString(rtStop)); + pPage->rtStop = rtStop; + hr = S_OK; + } else { + break; + } + } + + return hr; +} + +void CDVBSub::RemoveOldPages(REFERENCE_TIME rt) +{ + // Cleanup the old pages. We keep a 2 min buffer to play nice with the queue. + while (!m_pages.IsEmpty() && m_pages.GetHead()->rtStop + 120 * 10000000i64 < rt) { + const auto& pPage = m_pages.GetHead(); + if (!pPage->rendered) { + TRACE_DVB(_T("DVB - remove unrendered object, %s - %s\n"), + ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop)); + } + m_pages.RemoveHeadNoReturn(); + } +} + +STDMETHODIMP CDVBSub::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) +{ + relativeTo = RelativeTo::BEST_FIT; + return S_OK; +} diff --git a/src/Subtitles/DVBSub.h b/src/Subtitles/DVBSub.h index 9ebffeaac07..80f7465805c 100644 --- a/src/Subtitles/DVBSub.h +++ b/src/Subtitles/DVBSub.h @@ -1,175 +1,175 @@ -/* - * (C) 2009-2015 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 . - * - */ - -#pragma once - -#include "RLECodedSubtitle.h" -#include "CompositionObject.h" -#include -#include - -class CGolombBuffer; - -class CDVBSub : public CRLECodedSubtitle -{ -public: - CDVBSub(CCritSec* pLock, const CString& name, LCID lcid); - ~CDVBSub(); - - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); - - virtual HRESULT ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen); - virtual void EndOfStream(); - virtual void Reset(); - -private: - // EN 300-743, table 2 - enum DVB_SEGMENT_TYPE { - NO_SEGMENT = 0xFFFF, - PAGE = 0x10, - REGION = 0x11, - CLUT = 0x12, - OBJECT = 0x13, - DISPLAY = 0x14, - END_OF_DISPLAY = 0x80 - }; - - // EN 300-743, table 6 - enum DVB_OBJECT_TYPE { - OT_BASIC_BITMAP = 0x00, - OT_BASIC_CHAR = 0x01, - OT_COMPOSITE_STRING = 0x02 - }; - - enum DVB_PAGE_STATE { - DPS_NORMAL = 0x00, - DPS_ACQUISITION = 0x01, - DPS_MODE_CHANGE = 0x02, - DPS_RESERVED = 0x03 - }; - - struct DVB_CLUT { - BYTE id = 0; - BYTE version_number = 0; - WORD size = 0; - - std::array palette; - - DVB_CLUT() - : palette() { - } - }; - - struct DVB_DISPLAY { - // Default value (section 5.1.3) - BYTE version_number = 0; - BYTE display_window_flag = 0; - short width = 720; - short height = 576; - short horizontal_position_minimun = 0; - short horizontal_position_maximum = 0; - short vertical_position_minimun = 0; - short vertical_position_maximum = 0; - }; - - struct DVB_OBJECT { - short object_id = 0; - BYTE object_type = 0; - BYTE object_provider_flag = 0; - short object_horizontal_position = 0; - short object_vertical_position = 0; - BYTE foreground_pixel_code = 0; - BYTE background_pixel_code = 0; - }; - - struct DVB_REGION_POS { - BYTE id = 0; - WORD horizAddr = 0; - WORD vertAddr = 0; - }; - - struct DVB_REGION { - BYTE id = 0; - BYTE version_number = 0; - BYTE fill_flag = 0; - WORD width = 0; - WORD height = 0; - BYTE level_of_compatibility = 0; - BYTE depth = 0; - BYTE CLUT_id = 0; - BYTE _8_bit_pixel_code = 0; - BYTE _4_bit_pixel_code = 0; - BYTE _2_bit_pixel_code = 0; - std::list objects; - }; - - using RegionList = std::list>; - using CompositionObjectList = std::list>; - using ClutList = std::list>; - - class DVB_PAGE - { - public: - REFERENCE_TIME rtStart = 0; - REFERENCE_TIME rtStop = 0; - BYTE pageTimeOut = 0; - BYTE pageVersionNumber = 0; - BYTE pageState = 0; - std::list regionsPos; - RegionList regions; - CompositionObjectList objects; - ClutList CLUTs; - bool rendered = false; - }; - - size_t m_nBufferSize; - size_t m_nBufferReadPos; - size_t m_nBufferWritePos; - BYTE* m_pBuffer; - CAutoPtrList m_pages; - CAutoPtr m_pCurrentPage; - DVB_DISPLAY m_displayInfo; - - HRESULT AddToBuffer(BYTE* pData, size_t nSize); - - POSITION FindPage(REFERENCE_TIME rt) const; - RegionList::const_iterator FindRegion(const CAutoPtr& pPage, BYTE bRegionId) const; - ClutList::const_iterator FindClut(const CAutoPtr& pPage, BYTE bClutId) const; - CompositionObjectList::const_iterator FindObject(const CAutoPtr& pPage, short sObjectId) const; - - HRESULT ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage); - HRESULT ParseDisplay(CGolombBuffer& gb, WORD wSegLength); - HRESULT ParseRegion(CGolombBuffer& gb, WORD wSegLength); - HRESULT ParseClut(CGolombBuffer& gb, WORD wSegLength); - HRESULT ParseObject(CGolombBuffer& gb, WORD wSegLength); - - HRESULT EnqueuePage(REFERENCE_TIME rtStop); - HRESULT UpdateTimeStamp(REFERENCE_TIME rtStop); - - void RemoveOldPages(REFERENCE_TIME rt); -}; +/* + * (C) 2009-2015 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 . + * + */ + +#pragma once + +#include "RLECodedSubtitle.h" +#include "CompositionObject.h" +#include +#include + +class CGolombBuffer; + +class CDVBSub : public CRLECodedSubtitle +{ +public: + CDVBSub(CCritSec* pLock, const CString& name, LCID lcid); + ~CDVBSub(); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); + + virtual HRESULT ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen); + virtual void EndOfStream(); + virtual void Reset(); + +private: + // EN 300-743, table 2 + enum DVB_SEGMENT_TYPE { + NO_SEGMENT = 0xFFFF, + PAGE = 0x10, + REGION = 0x11, + CLUT = 0x12, + OBJECT = 0x13, + DISPLAY = 0x14, + END_OF_DISPLAY = 0x80 + }; + + // EN 300-743, table 6 + enum DVB_OBJECT_TYPE { + OT_BASIC_BITMAP = 0x00, + OT_BASIC_CHAR = 0x01, + OT_COMPOSITE_STRING = 0x02 + }; + + enum DVB_PAGE_STATE { + DPS_NORMAL = 0x00, + DPS_ACQUISITION = 0x01, + DPS_MODE_CHANGE = 0x02, + DPS_RESERVED = 0x03 + }; + + struct DVB_CLUT { + BYTE id = 0; + BYTE version_number = 0; + WORD size = 0; + + std::array palette; + + DVB_CLUT() + : palette() { + } + }; + + struct DVB_DISPLAY { + // Default value (section 5.1.3) + BYTE version_number = 0; + BYTE display_window_flag = 0; + short width = 720; + short height = 576; + short horizontal_position_minimun = 0; + short horizontal_position_maximum = 0; + short vertical_position_minimun = 0; + short vertical_position_maximum = 0; + }; + + struct DVB_OBJECT { + short object_id = 0; + BYTE object_type = 0; + BYTE object_provider_flag = 0; + short object_horizontal_position = 0; + short object_vertical_position = 0; + BYTE foreground_pixel_code = 0; + BYTE background_pixel_code = 0; + }; + + struct DVB_REGION_POS { + BYTE id = 0; + WORD horizAddr = 0; + WORD vertAddr = 0; + }; + + struct DVB_REGION { + BYTE id = 0; + BYTE version_number = 0; + BYTE fill_flag = 0; + WORD width = 0; + WORD height = 0; + BYTE level_of_compatibility = 0; + BYTE depth = 0; + BYTE CLUT_id = 0; + BYTE _8_bit_pixel_code = 0; + BYTE _4_bit_pixel_code = 0; + BYTE _2_bit_pixel_code = 0; + std::list objects; + }; + + using RegionList = std::list>; + using CompositionObjectList = std::list>; + using ClutList = std::list>; + + class DVB_PAGE + { + public: + REFERENCE_TIME rtStart = 0; + REFERENCE_TIME rtStop = 0; + BYTE pageTimeOut = 0; + BYTE pageVersionNumber = 0; + BYTE pageState = 0; + std::list regionsPos; + RegionList regions; + CompositionObjectList objects; + ClutList CLUTs; + bool rendered = false; + }; + + size_t m_nBufferSize; + size_t m_nBufferReadPos; + size_t m_nBufferWritePos; + BYTE* m_pBuffer; + CAutoPtrList m_pages; + CAutoPtr m_pCurrentPage; + DVB_DISPLAY m_displayInfo; + + HRESULT AddToBuffer(BYTE* pData, size_t nSize); + + POSITION FindPage(REFERENCE_TIME rt) const; + RegionList::const_iterator FindRegion(const CAutoPtr& pPage, BYTE bRegionId) const; + ClutList::const_iterator FindClut(const CAutoPtr& pPage, BYTE bClutId) const; + CompositionObjectList::const_iterator FindObject(const CAutoPtr& pPage, short sObjectId) const; + + HRESULT ParsePage(CGolombBuffer& gb, WORD wSegLength, CAutoPtr& pPage); + HRESULT ParseDisplay(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseRegion(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseClut(CGolombBuffer& gb, WORD wSegLength); + HRESULT ParseObject(CGolombBuffer& gb, WORD wSegLength); + + HRESULT EnqueuePage(REFERENCE_TIME rtStop); + HRESULT UpdateTimeStamp(REFERENCE_TIME rtStop); + + void RemoveOldPages(REFERENCE_TIME rt); +}; diff --git a/src/Subtitles/PGSSub.cpp b/src/Subtitles/PGSSub.cpp index 62554beac81..9399e9dc440 100644 --- a/src/Subtitles/PGSSub.cpp +++ b/src/Subtitles/PGSSub.cpp @@ -1,617 +1,617 @@ -/* - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "PGSSub.h" -#include "../DSUtil/GolombBuffer.h" -#include -#include -#include "SubtitleHelpers.h" - -#if (0) // Set to 1 to activate PGS subtitles traces -#define TRACE_PGSSUB TRACE -#else -#define TRACE_PGSSUB __noop -#endif - - -CPGSSub::CPGSSub(CCritSec* pLock, const CString& name, LCID lcid) - : CRLECodedSubtitle(pLock, name, lcid) - , m_nCurSegment(NO_SEGMENT) - , m_pSegBuffer(nullptr) - , m_nTotalSegBuffer(0) - , m_nSegBufferPos(0) - , m_nSegSize(0) -{ - if (m_name.IsEmpty() || m_name == _T("Unknown")) { - m_name = _T("PGS Embedded Subtitle"); - } -} - -CPGSSub::~CPGSSub() -{ - Reset(); - - delete [] m_pSegBuffer; -} - -// ISubPicProvider - -STDMETHODIMP_(POSITION) CPGSSub::GetStartPosition(REFERENCE_TIME rt, double fps) -{ - CAutoLock cAutoLock(&m_csCritSec); - - POSITION pos = m_pPresentationSegments.GetHeadPosition(); - while (pos) { - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - if (pPresentationSegment->rtStop <= rt) { - m_pPresentationSegments.GetNext(pos); - } else { - break; - } - } - - return pos; -} - -STDMETHODIMP_(POSITION) CPGSSub::GetNext(POSITION pos) -{ - CAutoLock cAutoLock(&m_csCritSec); - m_pPresentationSegments.GetNext(pos); - return pos; -} - -STDMETHODIMP_(REFERENCE_TIME) CPGSSub::GetStart(POSITION pos, double fps) -{ - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - return pPresentationSegment ? pPresentationSegment->rtStart : INVALID_TIME; -} - -STDMETHODIMP_(REFERENCE_TIME) CPGSSub::GetStop(POSITION pos, double fps) -{ - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - return pPresentationSegment ? pPresentationSegment->rtStop : INVALID_TIME; -} - -STDMETHODIMP_(bool) CPGSSub::IsAnimated(POSITION pos) -{ - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - // If the end time isn't known yet, we consider the subtitle as animated to be sure it will properly updated - return (pPresentationSegment && pPresentationSegment->rtStop == UNKNOWN_TIME); -} - -STDMETHODIMP CPGSSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - return Render(spd, rt, bbox, true); -} - -STDMETHODIMP CPGSSub::GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) -{ - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); - if (pPresentationSegment) { - MaxTextureSize.cx = VideoSize.cx = pPresentationSegment->video_descriptor.nVideoWidth; - MaxTextureSize.cy = VideoSize.cy = pPresentationSegment->video_descriptor.nVideoHeight; - - // The subs will be directly rendered into the proper position! - VideoTopLeft.x = 0; //pObject->m_horizontal_position; - VideoTopLeft.y = 0; //pObject->m_vertical_position; - - return S_OK; - } - - ASSERT(FALSE); - return E_INVALIDARG; -} - -HRESULT CPGSSub::ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen) -{ - CheckPointer(pData, E_POINTER); - - CAutoLock cAutoLock(&m_csCritSec); - - CGolombBuffer sampleBuffer(pData, nLen); - - while (!sampleBuffer.IsEOF()) { - if (m_nCurSegment == NO_SEGMENT) { - HDMV_SEGMENT_TYPE nSegType = (HDMV_SEGMENT_TYPE)sampleBuffer.ReadByte(); - unsigned short nUnitSize = sampleBuffer.ReadShort(); - nLen -= 3; - - switch (nSegType) { - case PALETTE: - case OBJECT: - case PRESENTATION_SEG: - case END_OF_DISPLAY: - m_nCurSegment = nSegType; - AllocSegment(nUnitSize); - break; - - case WINDOW_DEF: - case INTERACTIVE_SEG: - case HDMV_SUB1: - case HDMV_SUB2: - // Ignored stuff... - sampleBuffer.SkipBytes(nUnitSize); - break; - default: - return VFW_E_SAMPLE_REJECTED; - } - } - - if (m_nCurSegment != NO_SEGMENT) { - if (m_nSegBufferPos < m_nSegSize) { - size_t nSize = std::min(m_nSegSize - m_nSegBufferPos, nLen); - sampleBuffer.ReadBuffer(m_pSegBuffer + m_nSegBufferPos, nSize); - m_nSegBufferPos += nSize; - } - - if (m_nSegBufferPos >= m_nSegSize) { - CGolombBuffer SegmentBuffer(m_pSegBuffer, m_nSegSize); - - switch (m_nCurSegment) { - case PALETTE: - TRACE_PGSSUB(_T("CPGSSub:PALETTE %s\n"), ReftimeToString(rtStart)); - ParsePalette(&SegmentBuffer, m_nSegSize); - break; - case OBJECT: - TRACE_PGSSUB(_T("CPGSSub:OBJECT %s\n"), ReftimeToString(rtStart)); - ParseObject(&SegmentBuffer, m_nSegSize); - break; - case PRESENTATION_SEG: - TRACE_PGSSUB(_T("CPGSSub:PRESENTATION_SEG %s (size=%d)\n"), ReftimeToString(rtStart), m_nSegSize); - - if (rtStart == INVALID_TIME) { - break; - } - - // Update the timestamp for the previous segment - UpdateTimeStamp(rtStart); - - // Parse the new presentation segment - ParsePresentationSegment(rtStart, &SegmentBuffer); - - break; - case WINDOW_DEF: - //TRACE_PGSSUB(_T("CPGSSub:WINDOW_DEF %s\n"), ReftimeToString(rtStart)); - break; - case END_OF_DISPLAY: - TRACE_PGSSUB(_T("CPGSSub:END_OF_DISPLAY %s\n"), ReftimeToString(rtStart)); - // Enqueue the current presentation segment if any - EnqueuePresentationSegment(); - break; - default: - TRACE_PGSSUB(_T("CPGSSub:UNKNOWN Seg %d %s\n"), m_nCurSegment, ReftimeToString(rtStart)); - } - - m_nCurSegment = NO_SEGMENT; - } - } - } - - return S_OK; -} - -void CPGSSub::Reset() -{ - CAutoLock cAutoLock(&m_csCritSec); - - m_nSegBufferPos = m_nSegSize = 0; - m_nCurSegment = NO_SEGMENT; - m_pCurrentPresentationSegment.Free(); - m_pPresentationSegments.RemoveAll(); - for (auto& compositionObject : m_compositionObjects) { - compositionObject.Reset(); - } -} - -void CPGSSub::AllocSegment(size_t nSize) -{ - if (nSize > m_nTotalSegBuffer) { - delete[] m_pSegBuffer; - m_pSegBuffer = DEBUG_NEW BYTE[nSize]; - m_nTotalSegBuffer = nSize; - } - m_nSegBufferPos = 0; - m_nSegSize = nSize; -} - -HRESULT CPGSSub::GetPresentationSegmentTextureSize(REFERENCE_TIME rt, CSize& size) { - POSITION posPresentationSegment = FindPresentationSegment(rt); - - if (posPresentationSegment) { - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(posPresentationSegment); - if (pPresentationSegment->video_descriptor.nVideoWidth > 0) { - size.cx = pPresentationSegment->video_descriptor.nVideoWidth; - size.cy = pPresentationSegment->video_descriptor.nVideoHeight; - return S_OK; - } - } - return E_FAIL; -} - -HRESULT CPGSSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox, bool bRemoveOldSegments) -{ - CAutoLock cAutoLock(&m_csCritSec); - - bool bRendered = false; - - if (bRemoveOldSegments) { - RemoveOldSegments(rt); - } - - POSITION posPresentationSegment = FindPresentationSegment(rt); - - if (posPresentationSegment) { - const auto& pPresentationSegment = m_pPresentationSegments.GetAt(posPresentationSegment); - - if (m_eSourceMatrix == ColorConvTable::AUTO) { - m_eSourceMatrix = (pPresentationSegment->video_descriptor.nVideoWidth > 720) ? ColorConvTable::BT709 : ColorConvTable::BT601; - } - - TRACE_PGSSUB(_T("CPGSSub:Render Presentation segment %d --> %s - %s\n"), pPresentationSegment->composition_descriptor.nNumber, - ReftimeToString(pPresentationSegment->rtStart), - pPresentationSegment->rtStop == UNKNOWN_TIME ? _T("?") : ReftimeToString(pPresentationSegment->rtStop).GetString()); - - bbox.left = bbox.top = LONG_MAX; - bbox.right = bbox.bottom = 0; - - for (const auto& pObject : pPresentationSegment->objects) { - if (pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0 - && spd.w >= (pObject->m_horizontal_position + pObject->m_width) && spd.h >= (pObject->m_vertical_position + pObject->m_height)) { - pObject->SetPalette(pPresentationSegment->CLUT.size, pPresentationSegment->CLUT.palette.data(), m_eSourceMatrix); - bbox.left = std::min(pObject->m_horizontal_position, bbox.left); - bbox.top = std::min(pObject->m_vertical_position, bbox.top); - bbox.right = std::max(pObject->m_horizontal_position + pObject->m_width, bbox.right); - bbox.bottom = std::max(pObject->m_vertical_position + pObject->m_height, bbox.bottom); - - TRACE_PGSSUB(_T(" --> Object %d (Pos=%dx%d, Res=%dx%d, SPDRes=%dx%d)\n"), - pObject->m_object_id_ref, pObject->m_horizontal_position, pObject->m_vertical_position, pObject->m_width, pObject->m_height, spd.w, spd.h); - pObject->RenderHdmv(spd); - - bRendered = true; - } else { - TRACE_PGSSUB(_T(" --> Invalid object %d\n"), pObject->m_object_id_ref); - } - } - } - - if (!bRendered) { - bbox = { 0, 0, 0, 0 }; - } - - return S_OK; -} - -int CPGSSub::ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer) -{ - if (pGBuffer->RemainingSize() < 11) { - ASSERT(FALSE); - return 0; - } - - m_pCurrentPresentationSegment.Free(); - m_pCurrentPresentationSegment.Attach(DEBUG_NEW HDMV_PRESENTATION_SEGMENT()); - - m_pCurrentPresentationSegment->rtStart = rt; - m_pCurrentPresentationSegment->rtStop = UNKNOWN_TIME; // Unknown for now - - ParseVideoDescriptor(pGBuffer, &m_pCurrentPresentationSegment->video_descriptor); - ParseCompositionDescriptor(pGBuffer, &m_pCurrentPresentationSegment->composition_descriptor); - m_pCurrentPresentationSegment->palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); - m_pCurrentPresentationSegment->CLUT.id = pGBuffer->ReadByte(); - m_pCurrentPresentationSegment->objectCount = pGBuffer->ReadByte(); - - TRACE_PGSSUB(_T("CPGSSub::ParsePresentationSegment Size = %d, state = %#x, nObjectNumber = %d\n"), pGBuffer->GetSize(), - m_pCurrentPresentationSegment->composition_descriptor.bState, m_pCurrentPresentationSegment->objectCount); - - if (pGBuffer->RemainingSize() < (m_pCurrentPresentationSegment->objectCount * 8)) { - ASSERT(FALSE); - return 0; - } - - for (int i = 0; i < m_pCurrentPresentationSegment->objectCount; i++) { - std::unique_ptr pCompositionObject(DEBUG_NEW CompositionObject()); - if (ParseCompositionObject(pGBuffer, pCompositionObject)) { - m_pCurrentPresentationSegment->objects.emplace_back(std::move(pCompositionObject)); - } - } - - return m_pCurrentPresentationSegment->objectCount; -} - -void CPGSSub::EnqueuePresentationSegment() -{ - if (m_pCurrentPresentationSegment) { - if (m_pCurrentPresentationSegment->objectCount > 0) { - m_pCurrentPresentationSegment->CLUT = m_CLUTs[m_pCurrentPresentationSegment->CLUT.id]; - - // Get the objects' data - for (auto& pObject : m_pCurrentPresentationSegment->objects) { - const CompositionObject& pObjectData = m_compositionObjects[pObject->m_object_id_ref]; - - pObject->m_width = pObjectData.m_width; - pObject->m_height = pObjectData.m_height; - - if (pObjectData.GetRLEData()) { - pObject->SetRLEData(pObjectData.GetRLEData(), pObjectData.GetRLEPos(), pObjectData.GetRLEDataSize()); - } - } - - TRACE_PGSSUB(_T("CPGSSub: Enqueue Presentation Segment %d - %s => ?\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber, - ReftimeToString(m_pCurrentPresentationSegment->rtStart)); - m_pPresentationSegments.AddTail(m_pCurrentPresentationSegment); - } else { - TRACE_PGSSUB(_T("CPGSSub: Delete empty Presentation Segment %d\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber); - m_pCurrentPresentationSegment.Free(); - } - } -} - -void CPGSSub::UpdateTimeStamp(REFERENCE_TIME rtStop) -{ - if (!m_pPresentationSegments.IsEmpty()) { - const auto& pPresentationSegment = m_pPresentationSegments.GetTail(); - - // Since we drop empty segments we might be trying to update a segment that isn't - // in the queue so we update the timestamp only if it was previously unknown. - if (pPresentationSegment->rtStop == UNKNOWN_TIME) { - pPresentationSegment->rtStop = rtStop; - - TRACE_PGSSUB(_T("CPGSSub: Update Presentation Segment TimeStamp %d - %s => %s\n"), pPresentationSegment->composition_descriptor.nNumber, - ReftimeToString(pPresentationSegment->rtStart), - ReftimeToString(pPresentationSegment->rtStop)); - } - } -} - -void CPGSSub::ParsePalette(CGolombBuffer* pGBuffer, size_t nSize) // #497 -{ - if ((nSize - 2) % sizeof(HDMV_PALETTE) != 0) { - ASSERT(FALSE); - return; - } - - BYTE palette_id = pGBuffer->ReadByte(); - HDMV_CLUT& CLUT = m_CLUTs[palette_id]; - - CLUT.id = palette_id; - CLUT.version_number = pGBuffer->ReadByte(); - - CLUT.size = WORD((nSize - 2) / sizeof(HDMV_PALETTE)); - - for (WORD i = 0; i < CLUT.size; i++) { - CLUT.palette[i].entry_id = pGBuffer->ReadByte(); - - CLUT.palette[i].Y = pGBuffer->ReadByte(); - CLUT.palette[i].Cr = pGBuffer->ReadByte(); - CLUT.palette[i].Cb = pGBuffer->ReadByte(); - CLUT.palette[i].T = pGBuffer->ReadByte(); - } -} - -void CPGSSub::ParseObject(CGolombBuffer* pGBuffer, size_t nUnitSize) // #498 -{ - if (nUnitSize <= 4) { - return; - } - short object_id = pGBuffer->ReadShort(); - if (object_id < 0 || size_t(object_id) >= m_compositionObjects.size()) { - ASSERT(FALSE); // This is not supposed to happen - return; - } - - CompositionObject& pObject = m_compositionObjects[object_id]; - - pObject.m_version_number = pGBuffer->ReadByte(); - BYTE m_sequence_desc = pGBuffer->ReadByte(); - - if (m_sequence_desc & 0x80) { - if (nUnitSize <= 8) { - return; - } - - int object_data_length = (int)pGBuffer->BitRead(24); - - pObject.m_width = pGBuffer->ReadShort(); - pObject.m_height = pGBuffer->ReadShort(); - - pObject.SetRLEData(pGBuffer->GetBufferPos(), nUnitSize - 11, object_data_length - 4); - - TRACE_PGSSUB(_T("CPGSSub:ParseObject %d (size=%ld, %dx%d)\n"), object_id, object_data_length, pObject.m_width, pObject.m_height); - } else { - pObject.AppendRLEData(pGBuffer->GetBufferPos(), nUnitSize - 4); - } -} - -bool CPGSSub::ParseCompositionObject(CGolombBuffer* pGBuffer, const std::unique_ptr& pCompositionObject) -{ - short object_id_ref = pGBuffer->ReadShort(); - if (object_id_ref < 0 || size_t(object_id_ref) >= m_compositionObjects.size()) { - ASSERT(FALSE); // This is not supposed to happen - return false; - } - - pCompositionObject->m_object_id_ref = object_id_ref; - pCompositionObject->m_window_id_ref = pGBuffer->ReadByte(); - BYTE bTemp = pGBuffer->ReadByte(); - pCompositionObject->m_object_cropped_flag = !!(bTemp & 0x80); - pCompositionObject->m_forced_on_flag = !!(bTemp & 0x40); - pCompositionObject->m_horizontal_position = pGBuffer->ReadShort(); - pCompositionObject->m_vertical_position = pGBuffer->ReadShort(); - - if (pCompositionObject->m_object_cropped_flag) { - if (pGBuffer->RemainingSize() < 8) { - ASSERT(FALSE); - return false; - } - pCompositionObject->m_cropping_horizontal_position = pGBuffer->ReadShort(); - pCompositionObject->m_cropping_vertical_position = pGBuffer->ReadShort(); - pCompositionObject->m_cropping_width = pGBuffer->ReadShort(); - pCompositionObject->m_cropping_height = pGBuffer->ReadShort(); - } - - return true; -} - -void CPGSSub::ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor) -{ - pVideoDescriptor->nVideoWidth = pGBuffer->ReadShort(); - pVideoDescriptor->nVideoHeight = pGBuffer->ReadShort(); - pVideoDescriptor->bFrameRate = pGBuffer->ReadByte(); -} - -void CPGSSub::ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor) -{ - pCompositionDescriptor->nNumber = pGBuffer->ReadShort(); - pCompositionDescriptor->bState = pGBuffer->ReadByte() >> 6; -} - -POSITION CPGSSub::FindPresentationSegment(REFERENCE_TIME rt) const -{ - POSITION pos = m_pPresentationSegments.GetHeadPosition(); - - while (pos) { - POSITION currentPos = pos; - const auto& pPresentationSegment = m_pPresentationSegments.GetNext(pos); - - if (pPresentationSegment->rtStart <= rt && pPresentationSegment->rtStop > rt) { - return currentPos; - } - } - - return nullptr; -} - -void CPGSSub::RemoveOldSegments(REFERENCE_TIME rt) -{ - // Cleanup the old presentation segments. We keep a 2 min buffer to play nice with the queue. - while (!m_pPresentationSegments.IsEmpty() - && m_pPresentationSegments.GetHead()->rtStop != UNKNOWN_TIME - && m_pPresentationSegments.GetHead()->rtStop + 120 * 10000000i64 < rt) { - TRACE_PGSSUB(_T("CPGSSub::RemoveOldSegments Remove presentation segment %d %s => %s (rt=%s)\n"), - m_pPresentationSegments.GetHead()->composition_descriptor.nNumber, - ReftimeToString(m_pPresentationSegments.GetHead()->rtStart), - ReftimeToString(m_pPresentationSegments.GetHead()->rtStop), - ReftimeToString(rt)); - m_pPresentationSegments.RemoveHeadNoReturn(); - } -} - -STDMETHODIMP CPGSSub::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) -{ - relativeTo = RelativeTo::BEST_FIT; - return S_OK; -} - -CPGSSubFile::CPGSSubFile(CCritSec* pLock) - : CPGSSub(pLock, _T("PGS External Subtitle"), 0) - , m_bStopParsing(false) -{ -} - -CPGSSubFile::~CPGSSubFile() -{ - m_bStopParsing = true; - if (m_parsingThread.joinable()) { - m_parsingThread.join(); - } -} - -STDMETHODIMP CPGSSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - return __super::Render(spd, rt, bbox, false); -} - -bool CPGSSubFile::Open(CString fn, CString name /*= _T("")*/, CString videoName /*= _T("")*/) -{ - bool bOpened = false; - - CString tmp; - CString guessed = Subtitle::GuessSubtitleName(fn, videoName, m_lcid, tmp, m_eHearingImpaired); - if (name.IsEmpty()) { - m_name = guessed; - } else { - m_name = name; - } - - m_path = fn; - - try { - CFile f; - if (f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { - WORD wSyncCode = 0; - f.Read(&wSyncCode, sizeof(wSyncCode)); - wSyncCode = _byteswap_ushort(wSyncCode); - if (wSyncCode == PGS_SYNC_CODE) { - m_parsingThread = std::thread([this, fn] { ParseFile(fn); }); - bOpened = true; - } - } - } catch (CFileException*) { - } - - return bOpened; -} - -CString CPGSSubFile::GetPath() { - return m_path; -} - -void CPGSSubFile::ParseFile(CString fn) -{ - CFile f; - if (!f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { - return; - } - - // Header: Sync code | start time | stop time | segment type | segment size - std::array < BYTE, 2 + 2 * 4 + 1 + 2 > header; - const int nExtraSize = 1 + 2; // segment type + segment size - std::vector segBuff; - - while (!m_bStopParsing && f.Read(header.data(), (UINT)header.size()) == header.size()) { - // Parse the header - CGolombBuffer headerBuffer(header.data(), (int)header.size()); - - if (WORD(headerBuffer.ReadShort()) != PGS_SYNC_CODE) { - break; - } - - REFERENCE_TIME rtStart = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; - REFERENCE_TIME rtStop = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; - headerBuffer.ReadByte(); // segment type - WORD wLenSegment = (WORD)headerBuffer.ReadShort(); - - // Leave some room to add the segment type and size - int nLenData = nExtraSize + wLenSegment; - segBuff.resize(nLenData); - memcpy(segBuff.data(), &header[header.size() - nExtraSize], nExtraSize); - - // Read the segment - if (wLenSegment && f.Read(&segBuff[nExtraSize], wLenSegment) != wLenSegment) { - break; - } - - // Parse the data (even if the segment size is 0 because the header itself is important) - TRACE_PGSSUB(_T("--------- CPGSSubFile::ParseFile rtStart=%s, rtStop=%s, len=%d ---------\n"), - ReftimeToString(rtStart), ReftimeToString(rtStop), nLenData); - ParseSample(rtStart, rtStop, segBuff.data(), nLenData); - } -} +/* + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "PGSSub.h" +#include "../DSUtil/GolombBuffer.h" +#include +#include +#include "SubtitleHelpers.h" + +#if (0) // Set to 1 to activate PGS subtitles traces +#define TRACE_PGSSUB TRACE +#else +#define TRACE_PGSSUB __noop +#endif + + +CPGSSub::CPGSSub(CCritSec* pLock, const CString& name, LCID lcid) + : CRLECodedSubtitle(pLock, name, lcid) + , m_nCurSegment(NO_SEGMENT) + , m_pSegBuffer(nullptr) + , m_nTotalSegBuffer(0) + , m_nSegBufferPos(0) + , m_nSegSize(0) +{ + if (m_name.IsEmpty() || m_name == _T("Unknown")) { + m_name = _T("PGS Embedded Subtitle"); + } +} + +CPGSSub::~CPGSSub() +{ + Reset(); + + delete [] m_pSegBuffer; +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CPGSSub::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + CAutoLock cAutoLock(&m_csCritSec); + + POSITION pos = m_pPresentationSegments.GetHeadPosition(); + while (pos) { + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + if (pPresentationSegment->rtStop <= rt) { + m_pPresentationSegments.GetNext(pos); + } else { + break; + } + } + + return pos; +} + +STDMETHODIMP_(POSITION) CPGSSub::GetNext(POSITION pos) +{ + CAutoLock cAutoLock(&m_csCritSec); + m_pPresentationSegments.GetNext(pos); + return pos; +} + +STDMETHODIMP_(REFERENCE_TIME) CPGSSub::GetStart(POSITION pos, double fps) +{ + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + return pPresentationSegment ? pPresentationSegment->rtStart : INVALID_TIME; +} + +STDMETHODIMP_(REFERENCE_TIME) CPGSSub::GetStop(POSITION pos, double fps) +{ + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + return pPresentationSegment ? pPresentationSegment->rtStop : INVALID_TIME; +} + +STDMETHODIMP_(bool) CPGSSub::IsAnimated(POSITION pos) +{ + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + // If the end time isn't known yet, we consider the subtitle as animated to be sure it will properly updated + return (pPresentationSegment && pPresentationSegment->rtStop == UNKNOWN_TIME); +} + +STDMETHODIMP CPGSSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + return Render(spd, rt, bbox, true); +} + +STDMETHODIMP CPGSSub::GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VideoSize, POINT& VideoTopLeft) +{ + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(pos); + if (pPresentationSegment) { + MaxTextureSize.cx = VideoSize.cx = pPresentationSegment->video_descriptor.nVideoWidth; + MaxTextureSize.cy = VideoSize.cy = pPresentationSegment->video_descriptor.nVideoHeight; + + // The subs will be directly rendered into the proper position! + VideoTopLeft.x = 0; //pObject->m_horizontal_position; + VideoTopLeft.y = 0; //pObject->m_vertical_position; + + return S_OK; + } + + ASSERT(FALSE); + return E_INVALIDARG; +} + +HRESULT CPGSSub::ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen) +{ + CheckPointer(pData, E_POINTER); + + CAutoLock cAutoLock(&m_csCritSec); + + CGolombBuffer sampleBuffer(pData, nLen); + + while (!sampleBuffer.IsEOF()) { + if (m_nCurSegment == NO_SEGMENT) { + HDMV_SEGMENT_TYPE nSegType = (HDMV_SEGMENT_TYPE)sampleBuffer.ReadByte(); + unsigned short nUnitSize = sampleBuffer.ReadShort(); + nLen -= 3; + + switch (nSegType) { + case PALETTE: + case OBJECT: + case PRESENTATION_SEG: + case END_OF_DISPLAY: + m_nCurSegment = nSegType; + AllocSegment(nUnitSize); + break; + + case WINDOW_DEF: + case INTERACTIVE_SEG: + case HDMV_SUB1: + case HDMV_SUB2: + // Ignored stuff... + sampleBuffer.SkipBytes(nUnitSize); + break; + default: + return VFW_E_SAMPLE_REJECTED; + } + } + + if (m_nCurSegment != NO_SEGMENT) { + if (m_nSegBufferPos < m_nSegSize) { + size_t nSize = std::min(m_nSegSize - m_nSegBufferPos, nLen); + sampleBuffer.ReadBuffer(m_pSegBuffer + m_nSegBufferPos, nSize); + m_nSegBufferPos += nSize; + } + + if (m_nSegBufferPos >= m_nSegSize) { + CGolombBuffer SegmentBuffer(m_pSegBuffer, m_nSegSize); + + switch (m_nCurSegment) { + case PALETTE: + TRACE_PGSSUB(_T("CPGSSub:PALETTE %s\n"), ReftimeToString(rtStart)); + ParsePalette(&SegmentBuffer, m_nSegSize); + break; + case OBJECT: + TRACE_PGSSUB(_T("CPGSSub:OBJECT %s\n"), ReftimeToString(rtStart)); + ParseObject(&SegmentBuffer, m_nSegSize); + break; + case PRESENTATION_SEG: + TRACE_PGSSUB(_T("CPGSSub:PRESENTATION_SEG %s (size=%d)\n"), ReftimeToString(rtStart), m_nSegSize); + + if (rtStart == INVALID_TIME) { + break; + } + + // Update the timestamp for the previous segment + UpdateTimeStamp(rtStart); + + // Parse the new presentation segment + ParsePresentationSegment(rtStart, &SegmentBuffer); + + break; + case WINDOW_DEF: + //TRACE_PGSSUB(_T("CPGSSub:WINDOW_DEF %s\n"), ReftimeToString(rtStart)); + break; + case END_OF_DISPLAY: + TRACE_PGSSUB(_T("CPGSSub:END_OF_DISPLAY %s\n"), ReftimeToString(rtStart)); + // Enqueue the current presentation segment if any + EnqueuePresentationSegment(); + break; + default: + TRACE_PGSSUB(_T("CPGSSub:UNKNOWN Seg %d %s\n"), m_nCurSegment, ReftimeToString(rtStart)); + } + + m_nCurSegment = NO_SEGMENT; + } + } + } + + return S_OK; +} + +void CPGSSub::Reset() +{ + CAutoLock cAutoLock(&m_csCritSec); + + m_nSegBufferPos = m_nSegSize = 0; + m_nCurSegment = NO_SEGMENT; + m_pCurrentPresentationSegment.Free(); + m_pPresentationSegments.RemoveAll(); + for (auto& compositionObject : m_compositionObjects) { + compositionObject.Reset(); + } +} + +void CPGSSub::AllocSegment(size_t nSize) +{ + if (nSize > m_nTotalSegBuffer) { + delete[] m_pSegBuffer; + m_pSegBuffer = DEBUG_NEW BYTE[nSize]; + m_nTotalSegBuffer = nSize; + } + m_nSegBufferPos = 0; + m_nSegSize = nSize; +} + +HRESULT CPGSSub::GetPresentationSegmentTextureSize(REFERENCE_TIME rt, CSize& size) { + POSITION posPresentationSegment = FindPresentationSegment(rt); + + if (posPresentationSegment) { + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(posPresentationSegment); + if (pPresentationSegment->video_descriptor.nVideoWidth > 0) { + size.cx = pPresentationSegment->video_descriptor.nVideoWidth; + size.cy = pPresentationSegment->video_descriptor.nVideoHeight; + return S_OK; + } + } + return E_FAIL; +} + +HRESULT CPGSSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox, bool bRemoveOldSegments) +{ + CAutoLock cAutoLock(&m_csCritSec); + + bool bRendered = false; + + if (bRemoveOldSegments) { + RemoveOldSegments(rt); + } + + POSITION posPresentationSegment = FindPresentationSegment(rt); + + if (posPresentationSegment) { + const auto& pPresentationSegment = m_pPresentationSegments.GetAt(posPresentationSegment); + + if (m_eSourceMatrix == ColorConvTable::AUTO) { + m_eSourceMatrix = (pPresentationSegment->video_descriptor.nVideoWidth > 720) ? ColorConvTable::BT709 : ColorConvTable::BT601; + } + + TRACE_PGSSUB(_T("CPGSSub:Render Presentation segment %d --> %s - %s\n"), pPresentationSegment->composition_descriptor.nNumber, + ReftimeToString(pPresentationSegment->rtStart), + pPresentationSegment->rtStop == UNKNOWN_TIME ? _T("?") : ReftimeToString(pPresentationSegment->rtStop).GetString()); + + bbox.left = bbox.top = LONG_MAX; + bbox.right = bbox.bottom = 0; + + for (const auto& pObject : pPresentationSegment->objects) { + if (pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0 + && spd.w >= (pObject->m_horizontal_position + pObject->m_width) && spd.h >= (pObject->m_vertical_position + pObject->m_height)) { + pObject->SetPalette(pPresentationSegment->CLUT.size, pPresentationSegment->CLUT.palette.data(), m_eSourceMatrix); + bbox.left = std::min(pObject->m_horizontal_position, bbox.left); + bbox.top = std::min(pObject->m_vertical_position, bbox.top); + bbox.right = std::max(pObject->m_horizontal_position + pObject->m_width, bbox.right); + bbox.bottom = std::max(pObject->m_vertical_position + pObject->m_height, bbox.bottom); + + TRACE_PGSSUB(_T(" --> Object %d (Pos=%dx%d, Res=%dx%d, SPDRes=%dx%d)\n"), + pObject->m_object_id_ref, pObject->m_horizontal_position, pObject->m_vertical_position, pObject->m_width, pObject->m_height, spd.w, spd.h); + pObject->RenderHdmv(spd); + + bRendered = true; + } else { + TRACE_PGSSUB(_T(" --> Invalid object %d\n"), pObject->m_object_id_ref); + } + } + } + + if (!bRendered) { + bbox = { 0, 0, 0, 0 }; + } + + return S_OK; +} + +int CPGSSub::ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer) +{ + if (pGBuffer->RemainingSize() < 11) { + ASSERT(FALSE); + return 0; + } + + m_pCurrentPresentationSegment.Free(); + m_pCurrentPresentationSegment.Attach(DEBUG_NEW HDMV_PRESENTATION_SEGMENT()); + + m_pCurrentPresentationSegment->rtStart = rt; + m_pCurrentPresentationSegment->rtStop = UNKNOWN_TIME; // Unknown for now + + ParseVideoDescriptor(pGBuffer, &m_pCurrentPresentationSegment->video_descriptor); + ParseCompositionDescriptor(pGBuffer, &m_pCurrentPresentationSegment->composition_descriptor); + m_pCurrentPresentationSegment->palette_update_flag = !!(pGBuffer->ReadByte() & 0x80); + m_pCurrentPresentationSegment->CLUT.id = pGBuffer->ReadByte(); + m_pCurrentPresentationSegment->objectCount = pGBuffer->ReadByte(); + + TRACE_PGSSUB(_T("CPGSSub::ParsePresentationSegment Size = %d, state = %#x, nObjectNumber = %d\n"), pGBuffer->GetSize(), + m_pCurrentPresentationSegment->composition_descriptor.bState, m_pCurrentPresentationSegment->objectCount); + + if (pGBuffer->RemainingSize() < (m_pCurrentPresentationSegment->objectCount * 8)) { + ASSERT(FALSE); + return 0; + } + + for (int i = 0; i < m_pCurrentPresentationSegment->objectCount; i++) { + std::unique_ptr pCompositionObject(DEBUG_NEW CompositionObject()); + if (ParseCompositionObject(pGBuffer, pCompositionObject)) { + m_pCurrentPresentationSegment->objects.emplace_back(std::move(pCompositionObject)); + } + } + + return m_pCurrentPresentationSegment->objectCount; +} + +void CPGSSub::EnqueuePresentationSegment() +{ + if (m_pCurrentPresentationSegment) { + if (m_pCurrentPresentationSegment->objectCount > 0) { + m_pCurrentPresentationSegment->CLUT = m_CLUTs[m_pCurrentPresentationSegment->CLUT.id]; + + // Get the objects' data + for (auto& pObject : m_pCurrentPresentationSegment->objects) { + const CompositionObject& pObjectData = m_compositionObjects[pObject->m_object_id_ref]; + + pObject->m_width = pObjectData.m_width; + pObject->m_height = pObjectData.m_height; + + if (pObjectData.GetRLEData()) { + pObject->SetRLEData(pObjectData.GetRLEData(), pObjectData.GetRLEPos(), pObjectData.GetRLEDataSize()); + } + } + + TRACE_PGSSUB(_T("CPGSSub: Enqueue Presentation Segment %d - %s => ?\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber, + ReftimeToString(m_pCurrentPresentationSegment->rtStart)); + m_pPresentationSegments.AddTail(m_pCurrentPresentationSegment); + } else { + TRACE_PGSSUB(_T("CPGSSub: Delete empty Presentation Segment %d\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber); + m_pCurrentPresentationSegment.Free(); + } + } +} + +void CPGSSub::UpdateTimeStamp(REFERENCE_TIME rtStop) +{ + if (!m_pPresentationSegments.IsEmpty()) { + const auto& pPresentationSegment = m_pPresentationSegments.GetTail(); + + // Since we drop empty segments we might be trying to update a segment that isn't + // in the queue so we update the timestamp only if it was previously unknown. + if (pPresentationSegment->rtStop == UNKNOWN_TIME) { + pPresentationSegment->rtStop = rtStop; + + TRACE_PGSSUB(_T("CPGSSub: Update Presentation Segment TimeStamp %d - %s => %s\n"), pPresentationSegment->composition_descriptor.nNumber, + ReftimeToString(pPresentationSegment->rtStart), + ReftimeToString(pPresentationSegment->rtStop)); + } + } +} + +void CPGSSub::ParsePalette(CGolombBuffer* pGBuffer, size_t nSize) // #497 +{ + if ((nSize - 2) % sizeof(HDMV_PALETTE) != 0) { + ASSERT(FALSE); + return; + } + + BYTE palette_id = pGBuffer->ReadByte(); + HDMV_CLUT& CLUT = m_CLUTs[palette_id]; + + CLUT.id = palette_id; + CLUT.version_number = pGBuffer->ReadByte(); + + CLUT.size = WORD((nSize - 2) / sizeof(HDMV_PALETTE)); + + for (WORD i = 0; i < CLUT.size; i++) { + CLUT.palette[i].entry_id = pGBuffer->ReadByte(); + + CLUT.palette[i].Y = pGBuffer->ReadByte(); + CLUT.palette[i].Cr = pGBuffer->ReadByte(); + CLUT.palette[i].Cb = pGBuffer->ReadByte(); + CLUT.palette[i].T = pGBuffer->ReadByte(); + } +} + +void CPGSSub::ParseObject(CGolombBuffer* pGBuffer, size_t nUnitSize) // #498 +{ + if (nUnitSize <= 4) { + return; + } + short object_id = pGBuffer->ReadShort(); + if (object_id < 0 || size_t(object_id) >= m_compositionObjects.size()) { + ASSERT(FALSE); // This is not supposed to happen + return; + } + + CompositionObject& pObject = m_compositionObjects[object_id]; + + pObject.m_version_number = pGBuffer->ReadByte(); + BYTE m_sequence_desc = pGBuffer->ReadByte(); + + if (m_sequence_desc & 0x80) { + if (nUnitSize <= 8) { + return; + } + + int object_data_length = (int)pGBuffer->BitRead(24); + + pObject.m_width = pGBuffer->ReadShort(); + pObject.m_height = pGBuffer->ReadShort(); + + pObject.SetRLEData(pGBuffer->GetBufferPos(), nUnitSize - 11, object_data_length - 4); + + TRACE_PGSSUB(_T("CPGSSub:ParseObject %d (size=%ld, %dx%d)\n"), object_id, object_data_length, pObject.m_width, pObject.m_height); + } else { + pObject.AppendRLEData(pGBuffer->GetBufferPos(), nUnitSize - 4); + } +} + +bool CPGSSub::ParseCompositionObject(CGolombBuffer* pGBuffer, const std::unique_ptr& pCompositionObject) +{ + short object_id_ref = pGBuffer->ReadShort(); + if (object_id_ref < 0 || size_t(object_id_ref) >= m_compositionObjects.size()) { + ASSERT(FALSE); // This is not supposed to happen + return false; + } + + pCompositionObject->m_object_id_ref = object_id_ref; + pCompositionObject->m_window_id_ref = pGBuffer->ReadByte(); + BYTE bTemp = pGBuffer->ReadByte(); + pCompositionObject->m_object_cropped_flag = !!(bTemp & 0x80); + pCompositionObject->m_forced_on_flag = !!(bTemp & 0x40); + pCompositionObject->m_horizontal_position = pGBuffer->ReadShort(); + pCompositionObject->m_vertical_position = pGBuffer->ReadShort(); + + if (pCompositionObject->m_object_cropped_flag) { + if (pGBuffer->RemainingSize() < 8) { + ASSERT(FALSE); + return false; + } + pCompositionObject->m_cropping_horizontal_position = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_vertical_position = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_width = pGBuffer->ReadShort(); + pCompositionObject->m_cropping_height = pGBuffer->ReadShort(); + } + + return true; +} + +void CPGSSub::ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor) +{ + pVideoDescriptor->nVideoWidth = pGBuffer->ReadShort(); + pVideoDescriptor->nVideoHeight = pGBuffer->ReadShort(); + pVideoDescriptor->bFrameRate = pGBuffer->ReadByte(); +} + +void CPGSSub::ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor) +{ + pCompositionDescriptor->nNumber = pGBuffer->ReadShort(); + pCompositionDescriptor->bState = pGBuffer->ReadByte() >> 6; +} + +POSITION CPGSSub::FindPresentationSegment(REFERENCE_TIME rt) const +{ + POSITION pos = m_pPresentationSegments.GetHeadPosition(); + + while (pos) { + POSITION currentPos = pos; + const auto& pPresentationSegment = m_pPresentationSegments.GetNext(pos); + + if (pPresentationSegment->rtStart <= rt && pPresentationSegment->rtStop > rt) { + return currentPos; + } + } + + return nullptr; +} + +void CPGSSub::RemoveOldSegments(REFERENCE_TIME rt) +{ + // Cleanup the old presentation segments. We keep a 2 min buffer to play nice with the queue. + while (!m_pPresentationSegments.IsEmpty() + && m_pPresentationSegments.GetHead()->rtStop != UNKNOWN_TIME + && m_pPresentationSegments.GetHead()->rtStop + 120 * 10000000i64 < rt) { + TRACE_PGSSUB(_T("CPGSSub::RemoveOldSegments Remove presentation segment %d %s => %s (rt=%s)\n"), + m_pPresentationSegments.GetHead()->composition_descriptor.nNumber, + ReftimeToString(m_pPresentationSegments.GetHead()->rtStart), + ReftimeToString(m_pPresentationSegments.GetHead()->rtStop), + ReftimeToString(rt)); + m_pPresentationSegments.RemoveHeadNoReturn(); + } +} + +STDMETHODIMP CPGSSub::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) +{ + relativeTo = RelativeTo::BEST_FIT; + return S_OK; +} + +CPGSSubFile::CPGSSubFile(CCritSec* pLock) + : CPGSSub(pLock, _T("PGS External Subtitle"), 0) + , m_bStopParsing(false) +{ +} + +CPGSSubFile::~CPGSSubFile() +{ + m_bStopParsing = true; + if (m_parsingThread.joinable()) { + m_parsingThread.join(); + } +} + +STDMETHODIMP CPGSSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + return __super::Render(spd, rt, bbox, false); +} + +bool CPGSSubFile::Open(CString fn, CString name /*= _T("")*/, CString videoName /*= _T("")*/) +{ + bool bOpened = false; + + CString tmp; + CString guessed = Subtitle::GuessSubtitleName(fn, videoName, m_lcid, tmp, m_eHearingImpaired); + if (name.IsEmpty()) { + m_name = guessed; + } else { + m_name = name; + } + + m_path = fn; + + try { + CFile f; + if (f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { + WORD wSyncCode = 0; + f.Read(&wSyncCode, sizeof(wSyncCode)); + wSyncCode = _byteswap_ushort(wSyncCode); + if (wSyncCode == PGS_SYNC_CODE) { + m_parsingThread = std::thread([this, fn] { ParseFile(fn); }); + bOpened = true; + } + } + } catch (CFileException*) { + } + + return bOpened; +} + +CString CPGSSubFile::GetPath() { + return m_path; +} + +void CPGSSubFile::ParseFile(CString fn) +{ + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { + return; + } + + // Header: Sync code | start time | stop time | segment type | segment size + std::array < BYTE, 2 + 2 * 4 + 1 + 2 > header; + const int nExtraSize = 1 + 2; // segment type + segment size + std::vector segBuff; + + while (!m_bStopParsing && f.Read(header.data(), (UINT)header.size()) == header.size()) { + // Parse the header + CGolombBuffer headerBuffer(header.data(), (int)header.size()); + + if (WORD(headerBuffer.ReadShort()) != PGS_SYNC_CODE) { + break; + } + + REFERENCE_TIME rtStart = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; + REFERENCE_TIME rtStop = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; + headerBuffer.ReadByte(); // segment type + WORD wLenSegment = (WORD)headerBuffer.ReadShort(); + + // Leave some room to add the segment type and size + int nLenData = nExtraSize + wLenSegment; + segBuff.resize(nLenData); + memcpy(segBuff.data(), &header[header.size() - nExtraSize], nExtraSize); + + // Read the segment + if (wLenSegment && f.Read(&segBuff[nExtraSize], wLenSegment) != wLenSegment) { + break; + } + + // Parse the data (even if the segment size is 0 because the header itself is important) + TRACE_PGSSUB(_T("--------- CPGSSubFile::ParseFile rtStart=%s, rtStop=%s, len=%d ---------\n"), + ReftimeToString(rtStart), ReftimeToString(rtStop), nLenData); + ParseSample(rtStart, rtStop, segBuff.data(), nLenData); + } +} diff --git a/src/Subtitles/PGSSub.h b/src/Subtitles/PGSSub.h index 4996da03371..cb291de5f4c 100644 --- a/src/Subtitles/PGSSub.h +++ b/src/Subtitles/PGSSub.h @@ -1,161 +1,161 @@ -/* - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include "RLECodedSubtitle.h" -#include "CompositionObject.h" -#include -#include -#include - -class CGolombBuffer; - -class CPGSSub : public CRLECodedSubtitle -{ -public: - CPGSSub(CCritSec* pLock, const CString& name, LCID lcid); - virtual ~CPGSSub(); - - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); - - virtual HRESULT ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen); - virtual void EndOfStream() { /* Nothing to do */ }; - virtual void Reset(); - HRESULT GetPresentationSegmentTextureSize(REFERENCE_TIME rt, CSize& size); - -protected: - HRESULT Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox, bool bRemoveOldSegments); - -private: - enum HDMV_SEGMENT_TYPE { - NO_SEGMENT = 0xFFFF, - PALETTE = 0x14, - OBJECT = 0x15, - PRESENTATION_SEG = 0x16, - WINDOW_DEF = 0x17, - INTERACTIVE_SEG = 0x18, - END_OF_DISPLAY = 0x80, - HDMV_SUB1 = 0x81, - HDMV_SUB2 = 0x82 - }; - - - struct VIDEO_DESCRIPTOR { - int nVideoWidth; - int nVideoHeight; - BYTE bFrameRate; - }; - - struct COMPOSITION_DESCRIPTOR { - short nNumber; - BYTE bState; - }; - - struct SEQUENCE_DESCRIPTOR { - BYTE bFirstIn : 1; - BYTE bLastIn : 1; - BYTE bReserved : 6; - }; - - struct HDMV_CLUT { - BYTE id = 0; - BYTE version_number = 0; - WORD size = 0; - - std::array palette; - - HDMV_CLUT() - : palette() { - } - }; - - struct HDMV_PRESENTATION_SEGMENT { - REFERENCE_TIME rtStart = 0; - REFERENCE_TIME rtStop = 0; - - VIDEO_DESCRIPTOR video_descriptor; - COMPOSITION_DESCRIPTOR composition_descriptor; - - byte palette_update_flag = 0; - HDMV_CLUT CLUT; - - int objectCount = 0; - - std::list> objects; - }; - - HDMV_SEGMENT_TYPE m_nCurSegment; - BYTE* m_pSegBuffer; - size_t m_nTotalSegBuffer; - size_t m_nSegBufferPos; - size_t m_nSegSize; - - CAutoPtr m_pCurrentPresentationSegment; - CAutoPtrList m_pPresentationSegments; - - std::array m_CLUTs; - std::array m_compositionObjects; - - void AllocSegment(size_t nSize); - int ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer); - void EnqueuePresentationSegment(); - void UpdateTimeStamp(REFERENCE_TIME rtStop); - - void ParsePalette(CGolombBuffer* pGBuffer, size_t nSize); - void ParseObject(CGolombBuffer* pGBuffer, size_t nUnitSize); - void ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor); - void ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor); - bool ParseCompositionObject(CGolombBuffer* pGBuffer, const std::unique_ptr& pCompositionObject); - - POSITION FindPresentationSegment(REFERENCE_TIME rt) const; - - void RemoveOldSegments(REFERENCE_TIME rt); -}; - -class CPGSSubFile : public CPGSSub -{ -public: - CPGSSubFile(CCritSec* pLock); - virtual ~CPGSSubFile(); - - // ISubPicProvider - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - - bool Open(CString fn, CString name = _T(""), CString videoName = _T("")); - CString GetPath(); - -private: - static const WORD PGS_SYNC_CODE = 'PG'; - - bool m_bStopParsing; - std::thread m_parsingThread; - CString m_path; - - void ParseFile(CString fn); -}; +/* + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include "RLECodedSubtitle.h" +#include "CompositionObject.h" +#include +#include +#include + +class CGolombBuffer; + +class CPGSSub : public CRLECodedSubtitle +{ +public: + CPGSSub(CCritSec* pLock, const CString& name, LCID lcid); + virtual ~CPGSSub(); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetTextureSize(POSITION pos, SIZE& MaxTextureSize, SIZE& VirtualSize, POINT& VirtualTopLeft); + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); + + virtual HRESULT ParseSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t nLen); + virtual void EndOfStream() { /* Nothing to do */ }; + virtual void Reset(); + HRESULT GetPresentationSegmentTextureSize(REFERENCE_TIME rt, CSize& size); + +protected: + HRESULT Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox, bool bRemoveOldSegments); + +private: + enum HDMV_SEGMENT_TYPE { + NO_SEGMENT = 0xFFFF, + PALETTE = 0x14, + OBJECT = 0x15, + PRESENTATION_SEG = 0x16, + WINDOW_DEF = 0x17, + INTERACTIVE_SEG = 0x18, + END_OF_DISPLAY = 0x80, + HDMV_SUB1 = 0x81, + HDMV_SUB2 = 0x82 + }; + + + struct VIDEO_DESCRIPTOR { + int nVideoWidth; + int nVideoHeight; + BYTE bFrameRate; + }; + + struct COMPOSITION_DESCRIPTOR { + short nNumber; + BYTE bState; + }; + + struct SEQUENCE_DESCRIPTOR { + BYTE bFirstIn : 1; + BYTE bLastIn : 1; + BYTE bReserved : 6; + }; + + struct HDMV_CLUT { + BYTE id = 0; + BYTE version_number = 0; + WORD size = 0; + + std::array palette; + + HDMV_CLUT() + : palette() { + } + }; + + struct HDMV_PRESENTATION_SEGMENT { + REFERENCE_TIME rtStart = 0; + REFERENCE_TIME rtStop = 0; + + VIDEO_DESCRIPTOR video_descriptor; + COMPOSITION_DESCRIPTOR composition_descriptor; + + byte palette_update_flag = 0; + HDMV_CLUT CLUT; + + int objectCount = 0; + + std::list> objects; + }; + + HDMV_SEGMENT_TYPE m_nCurSegment; + BYTE* m_pSegBuffer; + size_t m_nTotalSegBuffer; + size_t m_nSegBufferPos; + size_t m_nSegSize; + + CAutoPtr m_pCurrentPresentationSegment; + CAutoPtrList m_pPresentationSegments; + + std::array m_CLUTs; + std::array m_compositionObjects; + + void AllocSegment(size_t nSize); + int ParsePresentationSegment(REFERENCE_TIME rt, CGolombBuffer* pGBuffer); + void EnqueuePresentationSegment(); + void UpdateTimeStamp(REFERENCE_TIME rtStop); + + void ParsePalette(CGolombBuffer* pGBuffer, size_t nSize); + void ParseObject(CGolombBuffer* pGBuffer, size_t nUnitSize); + void ParseVideoDescriptor(CGolombBuffer* pGBuffer, VIDEO_DESCRIPTOR* pVideoDescriptor); + void ParseCompositionDescriptor(CGolombBuffer* pGBuffer, COMPOSITION_DESCRIPTOR* pCompositionDescriptor); + bool ParseCompositionObject(CGolombBuffer* pGBuffer, const std::unique_ptr& pCompositionObject); + + POSITION FindPresentationSegment(REFERENCE_TIME rt) const; + + void RemoveOldSegments(REFERENCE_TIME rt); +}; + +class CPGSSubFile : public CPGSSub +{ +public: + CPGSSubFile(CCritSec* pLock); + virtual ~CPGSSubFile(); + + // ISubPicProvider + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + + bool Open(CString fn, CString name = _T(""), CString videoName = _T("")); + CString GetPath(); + +private: + static const WORD PGS_SYNC_CODE = 'PG'; + + bool m_bStopParsing; + std::thread m_parsingThread; + CString m_path; + + void ParseFile(CString fn); +}; diff --git a/src/Subtitles/RTS.cpp b/src/Subtitles/RTS.cpp index a382f6e76ff..545b04dccfe 100644 --- a/src/Subtitles/RTS.cpp +++ b/src/Subtitles/RTS.cpp @@ -1,3725 +1,3725 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2022 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "ColorConvTable.h" -#include "RTS.h" -#include "../DSUtil/PathUtils.h" -#include "../filters/renderer/VideoRenderers/RenderersSettings.h" -#include "moreuuids.h" - -#if !TRACE_SUBTITLES -#undef TRACE -#define TRACE(...) -#endif - -#define MAXGDIFONTSIZE 36000 - -// WARNING: this isn't very thread safe, use only one RTS a time. We should use TLS in future. -static HDC g_hDC; -static int g_hDC_refcnt = 0; - -static long revcolor(long c) -{ - return ((c & 0xff0000) >> 16) + (c & 0xff00) + ((c & 0xff) << 16); -} - -////////////////////////////////////////////////////////////////////////////////////////////// - -void alpha_mask_deleter::operator()(CAlphaMask* ptr) const noexcept -{ - m_alphaMaskPool.emplace_front(std::move(*ptr)); - std::default_delete()(ptr); - if (m_alphaMaskPool.size() > 10) { - m_alphaMaskPool.pop_back(); - } -} - -// CMyFont - -CMyFont::CMyFont(const STSStyle& style) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - lf <<= style; - lf.lfHeight = (LONG)(style.fontSize + 0.5); - lf.lfOutPrecision = OUT_TT_PRECIS; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfQuality = ANTIALIASED_QUALITY; - lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - if (lf.lfCharSet == 0) - lf.lfCharSet = DEFAULT_CHARSET; - - if (!CreateFontIndirect(&lf)) { - _tcscpy_s(lf.lfFaceName, _T("Calibri")); - VERIFY(CreateFontIndirect(&lf)); - } - - HFONT hOldFont = SelectFont(g_hDC, *this); - -#if 0 - WCHAR selectedFontName[LF_FACESIZE]; - GetTextFaceW(g_hDC, LF_FACESIZE, selectedFontName); - if (wcsncmp(selectedFontName, lf.lfFaceName, LF_FACESIZE)) { //GDI chose a different font -- let's use default instead - SelectFont(g_hDC, hOldFont); - DeleteObject(); - _tcscpy_s(lf.lfFaceName, _T("Calibri")); - VERIFY(CreateFontIndirect(&lf)); - HFONT hOldFont = SelectFont(g_hDC, *this); - } -#endif - - TEXTMETRIC tm; - GetTextMetrics(g_hDC, &tm); - m_ascent = ((tm.tmAscent + 4) >> 3); - m_descent = ((tm.tmDescent + 4) >> 3); - SelectFont(g_hDC, hOldFont); -} - -// CWord - -CWord::CWord(const STSStyle& style, CStringW str, int ktype, int kstart, int kend, double scalex, double scaley, - RenderingCaches& renderingCaches) - : m_fDrawn(false) - , m_p(INT_MAX, INT_MAX) - , m_renderingCaches(renderingCaches) - , m_scalex(scalex) - , m_scaley(scaley) - , m_str(str) - , m_fWhiteSpaceChar(false) - , m_fLineBreak(false) - , m_style(style) - , m_pOpaqueBox(nullptr) - , m_ktype(ktype) - , m_kstart(kstart) - , m_kend(kend) - , m_width(0) - , m_ascent(0) - , m_descent(0) -{ - if (str.IsEmpty()) { - m_fWhiteSpaceChar = m_fLineBreak = true; - } - if (m_style.fontSize > MAXGDIFONTSIZE) { - double fact = m_style.fontSize / MAXGDIFONTSIZE; - m_style.fontSize = MAXGDIFONTSIZE; - m_style.fontScaleX *= fact; - m_style.fontScaleY *= fact; - } - -} - -CWord::~CWord() -{ - delete m_pOpaqueBox; -} - -bool CWord::Append(CWord* w) -{ - if (m_style != w->m_style - || m_fLineBreak || w->m_fLineBreak - || w->m_kstart != w->m_kend || m_ktype != w->m_ktype) { - return false; - } - - m_fWhiteSpaceChar = m_fWhiteSpaceChar && w->m_fWhiteSpaceChar; - m_str += w->m_str; - m_width += w->m_width; - - m_fDrawn = false; - m_p = CPoint(INT_MAX, INT_MAX); - - return true; -} - -void CWord::Paint(const CPoint& p, const CPoint& org) -{ - if (!m_str) { - return; - } - - COverlayKey overlayKey(this, p, org); - - if (m_renderingCaches.overlayCache.Lookup(overlayKey, m_pOverlayData)) { - m_fDrawn = m_renderingCaches.outlineCache.Lookup(overlayKey, m_pOutlineData); - if (m_style.borderStyle == 1) { - if (m_style.outlineWidthX > 0.0 || m_style.shadowDepthX > 0.0 || m_style.outlineWidthY > 0.0 || m_style.shadowDepthY > 0.0) { - VERIFY(CreateOpaqueBox()); - } - } - } else { - if (!m_fDrawn) { - if (m_renderingCaches.outlineCache.Lookup(overlayKey, m_pOutlineData)) { - if (m_style.borderStyle == 1) { - if (m_style.outlineWidthX > 0.0 || m_style.shadowDepthX > 0.0 || m_style.outlineWidthY > 0.0 || m_style.shadowDepthY > 0.0) { - VERIFY(CreateOpaqueBox()); - } - } - } else { - if (!CreatePath()) { - return; - } - - Transform(CPoint((org.x - p.x) * 8, (org.y - p.y) * 8)); - - if (!ScanConvert()) { - return; - } - - if (m_style.borderStyle == 0 && (m_style.outlineWidthX + m_style.outlineWidthY > 0)) { - int rx = std::max(0, std::lround(m_style.outlineWidthX)); - int ry = std::max(0, std::lround(m_style.outlineWidthY)); - - if (!m_pEllipse || m_pEllipse->GetXRadius() != rx || m_pEllipse->GetYRadius() != ry) { - CEllipseKey ellipseKey(rx, ry); - if (!m_renderingCaches.ellipseCache.Lookup(ellipseKey, m_pEllipse)) { - m_pEllipse = std::make_shared(rx, ry); - - m_renderingCaches.ellipseCache.SetAt(ellipseKey, m_pEllipse); - } - } - - if (!CreateWidenedRegion(rx, ry)) { - return; - } - } else if (m_style.borderStyle == 1) { - if (m_style.outlineWidthX > 0.0 || m_style.shadowDepthX > 0.0 || m_style.outlineWidthY > 0.0 || m_style.shadowDepthY > 0.0) { - VERIFY(CreateOpaqueBox()); - } - } - - m_renderingCaches.outlineCache.SetAt(overlayKey, m_pOutlineData); - } - - m_fDrawn = true; - - if (!Rasterize(p.x & 7, p.y & 7, m_style.fBlur, m_style.fGaussianBlur)) { - return; - } - m_renderingCaches.overlayCache.SetAt(overlayKey, m_pOverlayData); - } else if ((m_p.x & 7) != (p.x & 7) || (m_p.y & 7) != (p.y & 7)) { - Rasterize(p.x & 7, p.y & 7, m_style.fBlur, m_style.fGaussianBlur); - m_renderingCaches.overlayCache.SetAt(overlayKey, m_pOverlayData); - } - } - - m_p = p; - - if (m_pOpaqueBox) { - m_pOpaqueBox->Paint(p, org); - } -} - -void CWord::Transform(CPoint org) -{ - if ((fabs(m_style.fontAngleX) > 0.000001) || (fabs(m_style.fontAngleY) > 0.000001) || (fabs(m_style.fontAngleZ) > 0.000001) || - (fabs(m_style.fontShiftX) > 0.000001) || (fabs(m_style.fontShiftY) > 0.000001)) { - Transform_SSE2(org); - } else if ((fabs(m_style.fontScaleX - 100) > 0.000001) || (fabs(m_style.fontScaleY - 100) > 0.000001)) { - Transform_quick_SSE2(org); - } -} - -bool CWord::CreateOpaqueBox() -{ - if (m_pOpaqueBox) { - return true; - } - - STSStyle style = m_style; - style.borderStyle = 0; - - // We don't want to apply the outline and the scaling twice - style.outlineWidthX = style.outlineWidthY = 0.0; - if (m_str.GetLength() > 2) { - // some SSA subs use an opaque box to draw text backgrounds for translated signs - // these use single character with a large fontscale - // don't adjust scale in that case - style.fontScaleX = style.fontScaleY = 100.0; - } - - style.colors[0] = m_style.colors[2]; - style.alpha[0] = m_style.alpha[2]; - - int w = std::lround(m_style.outlineWidthX); - int h = std::lround(m_style.outlineWidthY); - - // Convert to pixels rounding to nearest - CStringW str; - str.Format(L"m %d %d l %d %d %d %d %d %d", - -(w + 4) / 8, -(h + 4) / 8, - (m_width + w + 4) / 8, -(h + 4) / 8, - (m_width + w + 4) / 8, (m_ascent + m_descent + h + 4) / 8, - -(w + 4) / 8, (m_ascent + m_descent + h + 4) / 8); - - try { - m_pOpaqueBox = DEBUG_NEW CPolygon(style, str, 0, 0, 0, 1.0, 1.0, 0, m_renderingCaches); - } catch (CMemoryException* e) { - e->Delete(); - m_pOpaqueBox = nullptr; - } - - return !!m_pOpaqueBox; -} - -#if 0 -void CWord::Transform_C(const CPoint& org) -{ - const double scalex = m_style.fontScaleX / 100.0; - const double scaley = m_style.fontScaleY / 100.0; - const double xzoomf = m_scalex * 20000.0; - const double yzoomf = m_scaley * 20000.0; - - const double caz = cos((M_PI / 180.0) * m_style.fontAngleZ); - const double saz = sin((M_PI / 180.0) * m_style.fontAngleZ); - const double cax = cos((M_PI / 180.0) * m_style.fontAngleX); - const double sax = sin((M_PI / 180.0) * m_style.fontAngleX); - const double cay = cos((M_PI / 180.0) * m_style.fontAngleY); - const double say = sin((M_PI / 180.0) * m_style.fontAngleY); - - double dOrgX = static_cast(org.x), dOrgY = static_cast(org.y); - for (ptrdiff_t i = 0; i < mPathPoints; i++) { - double x, y, z, xx, yy, zz; - - x = mpPathPoints[i].x; - y = mpPathPoints[i].y; - z = 0; - - const double dPPx = m_style.fontShiftX * y + x; - y = scaley * (m_style.fontShiftY * x + y) - dOrgY; - x = scalex * dPPx - dOrgX; - - xx = x * caz + y * saz; - yy = -(x * saz - y * caz); - zz = z; - - x = xx; - y = yy * cax + zz * sax; - z = yy * sax - zz * cax; - - xx = x * cay + z * say; - yy = y; - zz = x * say - z * cay; - - x = xx * xzoomf / std::max((zz + xzoomf), 1000.0); - y = yy * yzoomf / std::max((zz + yzoomf), 1000.0); - - // round to integer - mpPathPoints[i].x = std::lround(x) + org.x; - mpPathPoints[i].y = std::lround(y) + org.y; - } -} -#endif - -#if 0 -void CWord::Transform_quick_C(const CPoint& org) -{ - const double scalex = m_style.fontScaleX / 100.0; - const double scaley = m_style.fontScaleY / 100.0; - - for (ptrdiff_t i = 0; i < mPathPoints; i++) { - double x = scalex * mpPathPoints[i].x; - double y = scaley * mpPathPoints[i].y; - - // round to integer - mpPathPoints[i].x = std::lround(x); - mpPathPoints[i].y = std::lround(y); - } -} -#endif - -void CWord::Transform_quick_SSE2(const CPoint& org) -{ - const __m128 __xscale = _mm_set_ps1((float)(m_style.fontScaleX / 100.0)); - const __m128 __yscale = _mm_set_ps1((float)(m_style.fontScaleY / 100.0)); - - int mPathPointsD4 = mPathPoints / 4; - int mPathPointsM4 = mPathPoints % 4; - - for (ptrdiff_t i = 0; i < mPathPointsD4 + 1; i++) { - __m128 __pointx, __pointy; - // we can't use load .-. - if (i != mPathPointsD4) { - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, (float)mpPathPoints[4 * i + 2].x, (float)mpPathPoints[4 * i + 3].x); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, (float)mpPathPoints[4 * i + 2].y, (float)mpPathPoints[4 * i + 3].y); - } else { // last cycle - switch (mPathPointsM4) { - default: - case 0: - continue; - case 1: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, 0, 0, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, 0, 0, 0); - break; - case 2: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, 0, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, 0, 0); - break; - case 3: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, (float)mpPathPoints[4 * i + 2].x, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, (float)mpPathPoints[4 * i + 2].y, 0); - break; - } - } - - // scale - __pointx = _mm_mul_ps(__pointx, __xscale); - __pointy = _mm_mul_ps(__pointy, __yscale); - - // round to integer - __m128i __pointxRounded = _mm_cvtps_epi32(__pointx); - __m128i __pointyRounded = _mm_cvtps_epi32(__pointy); - - if (i == mPathPointsD4) { // last cycle - for (int k = 0; k < mPathPointsM4; k++) { - mpPathPoints[i * 4 + k].x = __pointxRounded.m128i_i32[3 - k]; - mpPathPoints[i * 4 + k].y = __pointyRounded.m128i_i32[3 - k]; - } - } else { - for (int k = 0; k < 4; k++) { - mpPathPoints[i * 4 + k].x = __pointxRounded.m128i_i32[3 - k]; - mpPathPoints[i * 4 + k].y = __pointyRounded.m128i_i32[3 - k]; - } - } - } -} - -void CWord::Transform_SSE2(const CPoint& org) -{ - // SSE code - // speed up ~1.5-1.7x - const __m128 __xshift = _mm_set_ps1((float)m_style.fontShiftX); - const __m128 __yshift = _mm_set_ps1((float)m_style.fontShiftY); - - const __m128 __xorg = _mm_set_ps1((float)org.x); - const __m128 __yorg = _mm_set_ps1((float)org.y); - - const __m128 __xscale = _mm_set_ps1((float)(m_style.fontScaleX / 100.0)); - const __m128 __yscale = _mm_set_ps1((float)(m_style.fontScaleY / 100.0)); - const __m128 __xzoomf = _mm_set_ps1((float)(m_scalex * 20000.0)); - const __m128 __yzoomf = _mm_set_ps1((float)(m_scaley * 20000.0)); - - const __m128 __caz = _mm_set_ps1((float)cos((M_PI / 180.0) * m_style.fontAngleZ)); - const __m128 __saz = _mm_set_ps1((float)sin((M_PI / 180.0) * m_style.fontAngleZ)); - const __m128 __cax = _mm_set_ps1((float)cos((M_PI / 180.0) * m_style.fontAngleX)); - const __m128 __sax = _mm_set_ps1((float)sin((M_PI / 180.0) * m_style.fontAngleX)); - const __m128 __cay = _mm_set_ps1((float)cos((M_PI / 180.0) * m_style.fontAngleY)); - const __m128 __say = _mm_set_ps1((float)sin((M_PI / 180.0) * m_style.fontAngleY)); - - const __m128 __1000 = _mm_set_ps1(1000.0f); - - int mPathPointsD4 = mPathPoints / 4; - int mPathPointsM4 = mPathPoints % 4; - - for (ptrdiff_t i = 0; i < mPathPointsD4 + 1; i++) { - __m128 __pointx, __pointy, __tmpx, __tmpy; - // we can't use load .-. - if (i != mPathPointsD4) { - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, (float)mpPathPoints[4 * i + 2].x, (float)mpPathPoints[4 * i + 3].x); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, (float)mpPathPoints[4 * i + 2].y, (float)mpPathPoints[4 * i + 3].y); - } else { // last cycle - switch (mPathPointsM4) { - default: - case 0: - continue; - case 1: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, 0, 0, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, 0, 0, 0); - break; - case 2: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, 0, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, 0, 0); - break; - case 3: - __pointx = _mm_set_ps((float)mpPathPoints[4 * i + 0].x, (float)mpPathPoints[4 * i + 1].x, (float)mpPathPoints[4 * i + 2].x, 0); - __pointy = _mm_set_ps((float)mpPathPoints[4 * i + 0].y, (float)mpPathPoints[4 * i + 1].y, (float)mpPathPoints[4 * i + 2].y, 0); - break; - } - } - - // scale and shift - __tmpy = __pointx; // save a copy for calculating __pointy later - if (m_style.fontShiftX != 0) { - __tmpx = _mm_mul_ps(__xshift, __pointy); - __pointx = _mm_add_ps(__pointx, __tmpx); - } - __pointx = _mm_mul_ps(__pointx, __xscale); - __pointx = _mm_sub_ps(__pointx, __xorg); - - if (m_style.fontShiftY != 0) { - __tmpy = _mm_mul_ps(__yshift, __tmpy); // __tmpy is a copy of __pointx here, because it may otherwise be modified - __pointy = _mm_add_ps(__pointy, __tmpy); - } - __pointy = _mm_mul_ps(__pointy, __yscale); - __pointy = _mm_sub_ps(__pointy, __yorg); - - // rotate - - __m128 __xx, __yy; - __m128 __zz = _mm_setzero_ps(); - - // xx = x * caz + y * saz - __tmpx = _mm_mul_ps(__pointx, __caz); // x * caz - __tmpy = _mm_mul_ps(__pointy, __saz); // y * saz - __xx = _mm_add_ps(__tmpx, __tmpy); // xx = x * caz + y * saz; - - // yy = -(x * saz - y * caz) - __tmpx = _mm_mul_ps(__pointx, __saz); // x * saz - __tmpy = _mm_mul_ps(__pointy, __caz); // y * caz - __yy = _mm_sub_ps(__tmpy, __tmpx); // yy = -(x * saz - y * caz) = y * caz - x * saz - - __pointx = __xx; // x = xx - - // y = yy * cax + zz * sax - __tmpx = _mm_mul_ps(__zz, __sax); // zz * sax - __tmpy = _mm_mul_ps(__yy, __cax); // yy * cax - __pointy = _mm_add_ps(__tmpy, __tmpx); // y = yy * cax + zz * sax - - // z = yy * sax - zz * cax - __tmpx = _mm_mul_ps(__zz, __cax); // zz * cax - __tmpy = _mm_mul_ps(__yy, __sax); // yy * sax - __zz = _mm_sub_ps(__tmpy, __tmpx); // z = yy * sax - zz * cax - - // xx = x * cay + z * say - __tmpx = _mm_mul_ps(__pointx, __cay); // x * cay - __tmpy = _mm_mul_ps(__zz, __say); // z * say - __xx = _mm_add_ps(__tmpx, __tmpy); // xx = x * cay + z * say - - __yy = __pointy; // yy = y - - // zz = x * say - z * cay - __tmpx = _mm_mul_ps(__pointx, __say); // x * say - __zz = _mm_mul_ps(__zz, __cay); // z * cay - __zz = _mm_sub_ps(__tmpx, __zz); // zz = x * say - z * cay - - // x = xx * xzoomf / std::max((zz + xzoomf), 1000.0); - // y = yy * yzoomf / std::max((zz + yzoomf), 1000.0); - __m128 __tmpzz = _mm_add_ps(__zz, __xzoomf); // zz + xzoomf - - __xx = _mm_mul_ps(__xx, __xzoomf); // xx * xzoomf - __pointx = _mm_div_ps(__xx, _mm_max_ps(__tmpzz, __1000)); // x = (xx * xzoomf) / std::max((zz + xzoomf), 1000.0) - - __tmpzz = _mm_add_ps(__zz, __yzoomf); // zz + yzoomf - - __yy = _mm_mul_ps(__yy, __yzoomf); // yy * yzoomf - __pointy = _mm_div_ps(__yy, _mm_max_ps(__tmpzz, __1000)); // y = yy * yzoomf / std::max((zz + yzoomf), 1000.0); - - __pointx = _mm_add_ps(__pointx, __xorg); // x = x + org.x - __pointy = _mm_add_ps(__pointy, __yorg); // y = y + org.y - - // round to integer - __m128i __pointxRounded = _mm_cvtps_epi32(__pointx); - __m128i __pointyRounded = _mm_cvtps_epi32(__pointy); - - if (i == mPathPointsD4) { // last cycle - for (int k = 0; k < mPathPointsM4; k++) { - mpPathPoints[i * 4 + k].x = __pointxRounded.m128i_i32[3 - k]; - mpPathPoints[i * 4 + k].y = __pointyRounded.m128i_i32[3 - k]; - } - } else { - for (int k = 0; k < 4; k++) { - mpPathPoints[i * 4 + k].x = __pointxRounded.m128i_i32[3 - k]; - mpPathPoints[i * 4 + k].y = __pointyRounded.m128i_i32[3 - k]; - } - } - } -} - -// CText - -CText::CText(const STSStyle& style, CStringW str, int ktype, int kstart, int kend, double scalex, double scaley, - RenderingCaches& renderingCaches) - : CWord(style, str, ktype, kstart, kend, scalex, scaley, renderingCaches) -{ - if (m_str == L" ") { - m_fWhiteSpaceChar = true; - } - - CTextDimsKey textDimsKey(m_str, m_style); - CTextDims textDims; - if (!renderingCaches.textDimsCache.Lookup(textDimsKey, textDims)) { - CMyFont font(m_style); - m_ascent = font.m_ascent; - m_descent = font.m_descent; - - HFONT hOldFont = SelectFont(g_hDC, font); - - if (m_style.fontSpacing) { - for (LPCWSTR s = m_str; *s; s++) { - CSize extent; - if (!GetTextExtentPoint32W(g_hDC, s, 1, &extent)) { - SelectFont(g_hDC, hOldFont); - ASSERT(0); - return; - } - m_width += extent.cx + (int)m_style.fontSpacing; - } - // m_width -= (int)m_style.fontSpacing; // TODO: subtract only at the end of the line - } else { - CSize extent; - if (!GetTextExtentPoint32W(g_hDC, m_str, str.GetLength(), &extent)) { - SelectFont(g_hDC, hOldFont); - ASSERT(0); - return; - } - m_width += extent.cx; - } - - SelectFont(g_hDC, hOldFont); - - textDims.ascent = m_ascent; - textDims.descent = m_descent; - textDims.width = m_width; - - renderingCaches.textDimsCache.SetAt(textDimsKey, textDims); - } else { - m_ascent = textDims.ascent; - m_descent = textDims.descent; - m_width = textDims.width; - } - - m_ascent = (int)(m_style.fontScaleY / 100 * m_ascent); - m_descent = (int)(m_style.fontScaleY / 100 * m_descent); - m_width = (int)(m_style.fontScaleX / 100 * m_width + 4) >> 3; -} - -CWord* CText::Copy() -{ - return DEBUG_NEW CText(*this); -} - -bool CText::Append(CWord* w) -{ - return (dynamic_cast(w) && CWord::Append(w)); -} - -bool CText::CreatePath() -{ - CMyFont font(m_style); - - HFONT hOldFont = SelectFont(g_hDC, font); - - LONG cx = 0; - auto getExtent = [&](LPCWSTR s, int len) { - CSize extent; - if (!GetTextExtentPoint32W(g_hDC, s, len, &extent)) { - SelectFont(g_hDC, hOldFont); - ASSERT(0); - return false; - } - cx = extent.cx; - return true; - }; - - bool useFreetypePath = false; - std::wstring fontNameFT; - CStringA langHint = ""; - if (m_RTS) { - langHint = m_RTS->openTypeLangHint; - useFreetypePath = m_RTS->GetUseFreeType(); - if (useFreetypePath) { - fontNameFT = CW2W(m_style.fontName); - fontNameFT += std::to_wstring(m_style.fontSize); - } - } - - if (m_style.fontSpacing) { - int width = 0; - bool bFirstPath = true; - - if (!useFreetypePath) { - for (LPCWSTR s = m_str; *s; s++) { - if (!getExtent(s, 1)) { - return false; - } - if (cx == 0) { - // possible unhandled unprintable character - ASSERT(*s == L'\x202a' || *s == L'\x202b'); - continue; - } - PartialBeginPath(g_hDC, bFirstPath); - bFirstPath = false; - TextOutW(g_hDC, 0, 0, s, 1); - int mp = mPathPoints; - PartialEndPath(g_hDC, width, 0); - if (mp == mPathPoints && !CStringW::StrTraits::IsSpace(s[0]) && m_RTS) { //failed to add points, we will try again with FreeType as emulator - useFreetypePath = true; - fontNameFT = CW2W(m_style.fontName); - fontNameFT += std::to_wstring(m_style.fontSize); - break; - } -#if 0 - GetPathFreeType(g_hDC, false, s[0], m_style.fontSize, width+ cx + (int)m_style.fontSpacing, 0); - GetPathFreeType(g_hDC, false, s[0], m_style.fontSize, width, m_style.fontSize*2); -#endif - - width += cx + (int)m_style.fontSpacing; - } - } - if (useFreetypePath) { //try freetype - int ftWidth = 0; - bFirstPath = true; - m_RTS->m_ftLibrary.LoadCodeFaceData(g_hDC, fontNameFT); - if (!langHint.IsEmpty()) { - m_RTS->m_ftLibrary.LoadCodePoints(m_str, fontNameFT, langHint); - } - for (LPCWSTR s = m_str; *s; s++) { - if (!getExtent(s, 1)) { - return false; - } - if (cx == 0) { - // possible unhandled unprintable character - ASSERT(false); - continue; - } - - if (!GetPathFreeType(g_hDC, bFirstPath, fontNameFT, s[0], ftWidth, 0, langHint, &m_RTS->m_ftLibrary)) { - break; - } - bFirstPath = false; - ftWidth += cx + (int)m_style.fontSpacing; - } - } - } else { - int strlen = m_str.GetLength(); - - if (!getExtent(m_str, strlen) || cx == 0) { - // possible unhandled unprintable character - ASSERT(false); - return false; - } - - if (!useFreetypePath) { - BeginPath(g_hDC); - TextOutW(g_hDC, 0, 0, m_str, strlen); - EndPath(g_hDC); - - - if (mPathPoints == 0 && m_RTS && strlen > 0) { // try freetype as fallback - useFreetypePath = true; - fontNameFT = CW2W(m_style.fontName); - fontNameFT += std::to_wstring(m_style.fontSize); - } - } - - if (useFreetypePath && strlen > 0) { - int ftWidth = 0; - bool bFirstPath = true; - m_RTS->m_ftLibrary.LoadCodeFaceData(g_hDC, fontNameFT); - if (!langHint.IsEmpty()) { - m_RTS->m_ftLibrary.LoadCodePoints(m_str, fontNameFT, langHint); - } - for (LPCWSTR s = m_str; *s; s++) { - if (!getExtent(s, 1)) { - return false; - } - if (!GetPathFreeType(g_hDC, bFirstPath, fontNameFT, s[0], ftWidth, 0, langHint, &m_RTS->m_ftLibrary)) { - break; - } - bFirstPath = false; - ftWidth += cx; - } - } - } - - SelectFont(g_hDC, hOldFont); - - return true; -} - -// CPolygon - -CPolygon::CPolygon(const STSStyle& style, CStringW str, int ktype, int kstart, int kend, double scalex, double scaley, int baseline, - RenderingCaches& renderingCaches) - : CWord(style, str, ktype, kstart, kend, scalex, scaley, renderingCaches) - , m_baseline(baseline) -{ - ParseStr(); -} - -CPolygon::CPolygon(CPolygon& src) - : CWord(src.m_style, src.m_str, src.m_ktype, src.m_kstart, src.m_kend, src.m_scalex, src.m_scaley, src.m_renderingCaches) - , m_baseline(src.m_baseline) - , m_pPolygonPath(src.m_pPolygonPath) -{ - m_width = src.m_width; - m_ascent = src.m_ascent; - m_descent = src.m_descent; -} - -CPolygon::~CPolygon() -{ -} - -CWord* CPolygon::Copy() -{ - return (DEBUG_NEW CPolygon(*this)); -} - -bool CPolygon::Append(CWord* w) -{ - CPolygon* p = dynamic_cast(w); - if (!p) { - return false; - } - - // TODO - return false; - - //return true; -} - -bool CPolygon::GetPOINT(LPCWSTR& str, POINT& point) const -{ - LPWSTR xEnd = nullptr; - LPWSTR yEnd = nullptr; - - point.x = std::lround(wcstod(str, &xEnd) * m_scalex) * 64; - if (xEnd <= str) { - return false; - } - point.y = std::lround(wcstod(xEnd, &yEnd) * m_scaley) * 64; - - bool ret = yEnd > xEnd; - str = yEnd; - - return ret; -} - -bool CPolygon::ParseStr() -{ - if (m_pPolygonPath && !m_pPolygonPath->typesOrg.IsEmpty()) { - return true; - } - - CPolygonPathKey polygonPathKey(m_str, m_scalex, m_scaley); - if (!m_renderingCaches.polygonCache.Lookup(polygonPathKey, m_pPolygonPath)) { - m_pPolygonPath = std::make_shared(); - CPoint p; - bool bFoundMove = false; - size_t i, j, lastSplineStart = SIZE_T_ERROR; - - auto isValidAction = [](const WCHAR c) { - return c == L'm' || c == L'n' || c == L'l' || c == L'b' - || c == L's' || c == L'p' || c == L'c'; - }; - - for (LPCWSTR str = m_str; *str;) { - // Trim any leading invalid characters and whitespace - while (*str && !isValidAction(*str)) { - str++; - } - const WCHAR c = *str; - if (*str) { - do { - str++; - } while (isValidAction(*str)); - } - switch (c) { - case L'm': - if (!bFoundMove) { - if (m_pPolygonPath->typesOrg.GetCount() > 0) { - // move command not first so we abort - m_pPolygonPath = nullptr; - return false; - } - bFoundMove = true; - } - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_MOVETO); - m_pPolygonPath->pointsOrg.Add(p); - } - break; - case L'n': - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_MOVETONC); - m_pPolygonPath->pointsOrg.Add(p); - } - break; - case L'l': - if (m_pPolygonPath->pointsOrg.GetCount() < 1) { - break; - } - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_LINETO); - m_pPolygonPath->pointsOrg.Add(p); - } - break; - case L'b': - j = m_pPolygonPath->typesOrg.GetCount(); - if (j < 1) { - break; - } - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_BEZIERTO); - m_pPolygonPath->pointsOrg.Add(p); - ++j; - } - j = m_pPolygonPath->typesOrg.GetCount() - ((m_pPolygonPath->typesOrg.GetCount() - j) % 3); - m_pPolygonPath->typesOrg.SetCount(j); - m_pPolygonPath->pointsOrg.SetCount(j); - break; - case L's': - if (m_pPolygonPath->pointsOrg.GetCount() < 1) { - break; - } - j = lastSplineStart = m_pPolygonPath->typesOrg.GetCount(); - i = 3; - while (i-- && GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_BSPLINETO); - m_pPolygonPath->pointsOrg.Add(p); - ++j; - } - if (m_pPolygonPath->typesOrg.GetCount() - lastSplineStart < 3) { - m_pPolygonPath->typesOrg.SetCount(lastSplineStart); - m_pPolygonPath->pointsOrg.SetCount(lastSplineStart); - lastSplineStart = SIZE_T_ERROR; - } - // no break - case L'p': - if (m_pPolygonPath->pointsOrg.GetCount() < 3) { - break; - } - while (GetPOINT(str, p)) { - m_pPolygonPath->typesOrg.Add(PT_BSPLINEPATCHTO); - m_pPolygonPath->pointsOrg.Add(p); - } - break; - case L'c': - if (lastSplineStart != SIZE_T_ERROR && lastSplineStart > 0) { - m_pPolygonPath->typesOrg.Add(PT_BSPLINEPATCHTO); - m_pPolygonPath->typesOrg.Add(PT_BSPLINEPATCHTO); - m_pPolygonPath->typesOrg.Add(PT_BSPLINEPATCHTO); - p = m_pPolygonPath->pointsOrg[lastSplineStart - 1]; // we need p for temp storage, because operator [] will return a reference to CPoint and Add() may reallocate its internal buffer (this is true for MFC 7.0 but not for 6.0, hehe) - m_pPolygonPath->pointsOrg.Add(p); - p = m_pPolygonPath->pointsOrg[lastSplineStart]; - m_pPolygonPath->pointsOrg.Add(p); - p = m_pPolygonPath->pointsOrg[lastSplineStart + 1]; - m_pPolygonPath->pointsOrg.Add(p); - lastSplineStart = SIZE_T_ERROR; - } - break; - default: - break; - } - } - - if (!bFoundMove) { - // move command not found so we abort - m_pPolygonPath = nullptr; - return false; - } - - int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN; - - for (size_t m = 0; m < m_pPolygonPath->typesOrg.GetCount(); m++) { - if (minx > m_pPolygonPath->pointsOrg[m].x) { - minx = m_pPolygonPath->pointsOrg[m].x; - } - if (miny > m_pPolygonPath->pointsOrg[m].y) { - miny = m_pPolygonPath->pointsOrg[m].y; - } - if (maxx < m_pPolygonPath->pointsOrg[m].x) { - maxx = m_pPolygonPath->pointsOrg[m].x; - } - if (maxy < m_pPolygonPath->pointsOrg[m].y) { - maxy = m_pPolygonPath->pointsOrg[m].y; - } - } - - m_pPolygonPath->size.SetSize(std::max(maxx - minx, 0), std::max(maxy - miny, 0)); - - m_renderingCaches.polygonCache.SetAt(polygonPathKey, m_pPolygonPath); - } - - m_width = m_pPolygonPath->size.cx; - m_ascent = m_pPolygonPath->size.cy; - - int baseline = std::lround(m_scaley * m_baseline) * 64; - m_descent = baseline; - m_ascent -= baseline; - - m_width = ((int)(m_style.fontScaleX / 100.0 * m_width) + 4) >> 3; - m_ascent = ((int)(m_style.fontScaleY / 100.0 * m_ascent) + 4) >> 3; - m_descent = ((int)(m_style.fontScaleY / 100.0 * m_descent) + 4) >> 3; - - return true; -} - -bool CPolygon::CreatePath() -{ - int len = m_pPolygonPath ? (int)m_pPolygonPath->typesOrg.GetCount() : 0; - if (len == 0) { - return false; - } - - if (mPathPoints != len) { - BYTE* pNewPathTypes = (BYTE*)realloc(mpPathTypes, len * sizeof(BYTE)); - if (!pNewPathTypes) { - return false; - } - mpPathTypes = pNewPathTypes; - POINT* pNewPathPoints = (POINT*)realloc(mpPathPoints, len * sizeof(POINT)); - if (!pNewPathPoints) { - return false; - } - mpPathPoints = pNewPathPoints; - mPathPoints = len; - } - - memcpy(mpPathTypes, m_pPolygonPath->typesOrg.GetData(), len * sizeof(BYTE)); - memcpy(mpPathPoints, m_pPolygonPath->pointsOrg.GetData(), len * sizeof(POINT)); - - return true; -} - -// CClipper - -CClipper::CClipper(CStringW str, const CSize& size, double scalex, double scaley, bool inverse, const CPoint& cpOffset, - RenderingCaches& renderingCaches) - : CPolygon(STSStyle(), str, 0, 0, 0, scalex, scaley, 0, renderingCaches) - , m_size(size) - , m_inverse(inverse) - , m_cpOffset(cpOffset) - , m_pAlphaMask(nullptr) - , m_effectType(-1) -{ -} - -CAlphaMaskSharedPtr CClipper::GetAlphaMask(const std::shared_ptr& clipper) -{ - if (m_pAlphaMask) { - return m_pAlphaMask; - } - - ASSERT(this == clipper.get()); - if (m_size.cx <= 0 || m_size.cy <= 0) { - return nullptr; - } - - CClipperKey key(clipper); - if (m_renderingCaches.alphaMaskCache.Lookup(key, m_pAlphaMask)) { - return m_pAlphaMask; - } - - Paint(CPoint(0, 0), CPoint(0, 0)); - - if (!m_pOverlayData) { - return nullptr; - } - - int w = m_pOverlayData->mOverlayWidth, h = m_pOverlayData->mOverlayHeight; - - int x = (m_pOverlayData->mOffsetX + m_cpOffset.x + 4) >> 3, y = (m_pOverlayData->mOffsetY + m_cpOffset.y + 4) >> 3; - int xo = 0, yo = 0; - - if (x < 0) { - xo = -x; - w -= -x; - x = 0; - } - if (y < 0) { - yo = -y; - h -= -y; - y = 0; - } - if (x + w > m_size.cx) { - w = m_size.cx - x; - } - if (y + h > m_size.cy) { - h = m_size.cy - y; - } - - if (w <= 0 || h <= 0) { - return nullptr; - } - - const size_t alphaMaskSize = size_t(m_size.cx) * m_size.cy; - - try { - m_pAlphaMask = CAlphaMask::Alloc(m_renderingCaches.alphaMaskPool, alphaMaskSize); - } catch (CMemoryException* e) { - e->Delete(); - m_pAlphaMask = nullptr; - return nullptr; - } - - BYTE* pAlphaMask = m_pAlphaMask->get(); - memset(pAlphaMask, (m_inverse ? 0x40 : 0), alphaMaskSize); - - const BYTE* src = m_pOverlayData->mpOverlayBufferBody + m_pOverlayData->mOverlayPitch * yo + xo; - BYTE* dst = pAlphaMask + m_size.cx * y + x; - - if (m_inverse) { - for (ptrdiff_t i = 0; i < h; ++i) { - for (ptrdiff_t wt = 0; wt < w; ++wt) { - dst[wt] = 0x40 - src[wt]; - } - src += m_pOverlayData->mOverlayPitch; - dst += m_size.cx; - } - } else { - for (ptrdiff_t i = 0; i < h; ++i) { - memcpy(dst, src, w * sizeof(BYTE)); - src += m_pOverlayData->mOverlayPitch; - dst += m_size.cx; - } - } - - if (m_effectType == EF_SCROLL) { - int height = m_effect.param[4]; - int spd_w = m_size.cx, spd_h = m_size.cy; - int da = (64 << 8) / height; - int a = 0; - int k = m_effect.param[0] >> 3; - int l = k + height; - if (k < 0) { - a += -k * da; - k = 0; - } - if (l > spd_h) { - l = spd_h; - } - - if (k < spd_h) { - BYTE* am = &pAlphaMask[k * spd_w]; - - ZeroMemory(pAlphaMask, am - pAlphaMask); - - for (ptrdiff_t j = k; j < l; j++, a += da) { - for (ptrdiff_t i = 0; i < spd_w; i++, am++) { - *am = BYTE(((*am) * a) >> 14); - } - } - } - - da = -(64 << 8) / height; - a = 0x40 << 8; - l = m_effect.param[1] >> 3; - k = l - height; - if (k < 0) { - a += -k * da; - k = 0; - } - if (l > spd_h) { - l = spd_h; - } - - if (k < spd_h) { - BYTE* am = &pAlphaMask[k * spd_w]; - - int j = k; - for (; j < l; j++, a += da) { - for (ptrdiff_t i = 0; i < spd_w; i++, am++) { - *am = BYTE(((*am) * a) >> 14); - } - } - - ZeroMemory(am, (spd_h - j)*spd_w); - } - } else if (m_effectType == EF_BANNER) { - int width = m_effect.param[2]; - int spd_w = m_size.cx, spd_h = m_size.cy; - int da = (64 << 8) / width; - BYTE* am = pAlphaMask; - - for (ptrdiff_t j = 0; j < spd_h; j++, am += spd_w) { - int a = 0; - int k = std::min(width, spd_w); - - for (ptrdiff_t i = 0; i < k; i++, a += da) { - am[i] = BYTE((am[i] * a) >> 14); - } - - a = 0x40 << 8; - k = spd_w - width; - - if (k < 0) { - a -= -k * da; - k = 0; - } - - for (ptrdiff_t i = k; i < spd_w; i++, a -= da) { - am[i] = BYTE((am[i] * a) >> 14); - } - } - - } - m_renderingCaches.alphaMaskCache.SetAt(key, m_pAlphaMask); - return m_pAlphaMask; -} - -CWord* CClipper::Copy() -{ - return DEBUG_NEW CClipper(m_str, m_size, m_scalex, m_scaley, m_inverse, m_cpOffset, m_renderingCaches); -} - -bool CClipper::Append(CWord* w) -{ - return false; -} - -// CLine - -CLine::~CLine() -{ - POSITION pos = GetHeadPosition(); - while (pos) { - delete GetNext(pos); - } -} - -void CLine::Compact() -{ - POSITION pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - if (!w->m_fWhiteSpaceChar) { - break; - } - - m_width -= w->m_width; - delete w; - RemoveHead(); - } - - pos = GetTailPosition(); - while (pos) { - CWord* w = GetPrev(pos); - if (!w->m_fWhiteSpaceChar) { - break; - } - - m_width -= w->m_width; - delete w; - RemoveTail(); - } - - if (IsEmpty()) { - return; - } - - CLine l; - l.AddTailList(this); - RemoveAll(); - - CWord* last = nullptr; - - pos = l.GetHeadPosition(); - while (pos) { - CWord* w = l.GetNext(pos); - - if (!last || !last->Append(w)) { - AddTail(last = w->Copy()); - } - } - - m_ascent = m_descent = m_borderX = m_borderY = 0; - - pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - - if (m_ascent < w->m_ascent) { - m_ascent = w->m_ascent; - } - if (m_descent < w->m_descent) { - m_descent = w->m_descent; - } - if (m_borderX < w->m_style.outlineWidthX) { - m_borderX = (int)(w->m_style.outlineWidthX + 0.5); - } - if (m_borderY < w->m_style.outlineWidthY) { - m_borderY = (int)(w->m_style.outlineWidthY + 0.5); - } - } -} - -CRect CLine::PaintShadow(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha) -{ - CRect bbox(0, 0, 0, 0); - - POSITION pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - - if (w->m_fLineBreak) { - return bbox; // should not happen since this class is just a line of text without any breaks - } - - if (w->m_style.shadowDepthX != 0 || w->m_style.shadowDepthY != 0) { - int x = p.x + (int)(w->m_style.shadowDepthX + 0.5); - int y = p.y + m_ascent - w->m_ascent + (int)(w->m_style.shadowDepthY + 0.5); - - DWORD a = 0xff - w->m_style.alpha[3]; - if (alpha > 0) { - a = a * (0xff - static_cast(alpha)) / 0xff; - } - COLORREF shadow = revcolor(w->m_style.colors[3]) | (a << 24); - DWORD sw[6] = {shadow, DWORD_MAX}; - sw[0] = ColorConvTable::ColorCorrection(sw[0]); - - w->Paint(CPoint(x, y), org); - - if (w->m_style.borderStyle == 0) { - bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw, - w->m_ktype > 0 || w->m_style.alpha[0] < 0xff, - (w->m_style.outlineWidthX + w->m_style.outlineWidthY > 0) && !(w->m_ktype == 2 && time < w->m_kstart)); - } else if (w->m_style.borderStyle == 1 && w->m_pOpaqueBox) { - bbox |= w->m_pOpaqueBox->Draw(spd, clipRect, pAlphaMask, x, y, sw, true, false); - } - } - - p.x += w->m_width; - } - - return bbox; -} - -CRect CLine::PaintOutline(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha) -{ - CRect bbox(0, 0, 0, 0); - - POSITION pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - - if (w->m_fLineBreak) { - return bbox; // should not happen since this class is just a line of text without any breaks - } - - bool has_outline = w->m_style.outlineWidthX + w->m_style.outlineWidthY > 0.0; - if ((has_outline || w->m_style.borderStyle == 1) && !(w->m_ktype == 2 && time < w->m_kstart)) { - int x = p.x; - int y = p.y + m_ascent - w->m_ascent; - DWORD aoutline = w->m_style.alpha[2]; - if (alpha > 0) { - aoutline += alpha * (0xff - w->m_style.alpha[2]) / 0xff; - } - COLORREF outline = revcolor(has_outline ? w->m_style.colors[2] : w->m_style.colors[3]) | ((0xff - aoutline) << 24); - DWORD sw[6] = {outline, DWORD_MAX}; - sw[0] = ColorConvTable::ColorCorrection(sw[0]); - - w->Paint(CPoint(x, y), org); - - if (w->m_style.borderStyle == 0) { - bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw, !w->m_style.alpha[0] && !w->m_style.alpha[1] && !alpha, true); - } else if (w->m_style.borderStyle == 1 && w->m_pOpaqueBox) { - bbox |= w->m_pOpaqueBox->Draw(spd, clipRect, pAlphaMask, x, y, sw, true, false); - } - } - - p.x += w->m_width; - } - - return bbox; -} - -CRect CLine::PaintBody(SubPicDesc& spd, CRect& clipRect, BYTE* pAlphaMask, CPoint p, CPoint org, int time, int alpha) -{ - CRect bbox(0, 0, 0, 0); - - POSITION pos = GetHeadPosition(); - while (pos) { - CWord* w = GetNext(pos); - - if (w->m_fLineBreak) { - return bbox; // should not happen since this class is just a line of text without any breaks - } - - int x = p.x; - int y = p.y + m_ascent - w->m_ascent; - // colors - - DWORD aprimary = w->m_style.alpha[0]; - DWORD asecondary = w->m_style.alpha[1]; - if (alpha > 0) { - aprimary += alpha * (0xff - w->m_style.alpha[0]) / 0xff; - asecondary += alpha * (0xff - w->m_style.alpha[1]) / 0xff; - } - COLORREF primary = revcolor(w->m_style.colors[0]) | ((0xff - aprimary) << 24); - COLORREF secondary = revcolor(w->m_style.colors[1]) | ((0xff - asecondary) << 24); - - DWORD sw[6] = {primary, 0, secondary}; - - // karaoke - - double t = 0.0; - - if (w->m_ktype == 0 || w->m_ktype == 2) { - t = time < w->m_kstart ? 0.0 : 1.0; - } else if (w->m_ktype == 1) { - if (time < w->m_kstart) { - t = 0.0; - } else if (time < w->m_kend) { - t = 1.0 * (time - w->m_kstart) / (w->m_kend - w->m_kstart); - - double angle = fmod(w->m_style.fontAngleZ, 360.0); - if (angle > 90 && angle < 270) { - t = 1.0 - t; - COLORREF tmp = sw[0]; - sw[0] = sw[2]; - sw[2] = tmp; - } - } else { - t = 1.0; - } - } - - if (t >= 1.0) { - sw[1] = DWORD_MAX; - } - - // move dividerpoint - int bluradjust = 0; - if (w->m_style.fGaussianBlur > 0) { - bluradjust += (int)(w->m_style.fGaussianBlur * 3 * 8 + 0.5) | 1; - } - if (w->m_style.fBlur) { - bluradjust += 8; - } - - w->Paint(CPoint(x, y), org); - - sw[0] = ColorConvTable::ColorCorrection(sw[0]); - sw[2] = ColorConvTable::ColorCorrection(sw[2]); - sw[3] = (int)(w->m_style.outlineWidthX + t * w->getOverlayWidth() + t * bluradjust) >> 3; - sw[4] = sw[2]; - sw[5] = 0x00ffffff; - - bbox |= w->Draw(spd, clipRect, pAlphaMask, x, y, sw, true, false); - p.x += w->m_width; - } - - return bbox; -} - - -// CSubtitle - -CSubtitle::CSubtitle(RenderingCaches& renderingCaches) - : m_renderingCaches(renderingCaches) - , m_scrAlignment(0) - , m_wrapStyle(0) - , m_fAnimated(false) - , m_bIsAnimated(false) - , m_relativeTo(STSStyle::AUTO) - , m_pClipper(nullptr) - , m_topborder(0) - , m_bottomborder(0) - , m_clipInverse(false) - , m_target_scale_x(1.0) - , m_target_scale_y(1.0) - , m_script_scale_x(1.0) - , m_script_scale_y(1.0) - , m_total_scale_x(1.0) - , m_total_scale_y(1.0) - , m_allowLinePadding(false) -{ - ZeroMemory(m_effects, sizeof(Effect*)*EF_NUMBEROFEFFECTS); -} - -CSubtitle::~CSubtitle() -{ - Empty(); -} - -void CSubtitle::Empty() -{ - POSITION pos = GetHeadPosition(); - while (pos) { - delete GetNext(pos); - } - - pos = m_words.GetHeadPosition(); - while (pos) { - delete m_words.GetNext(pos); - } - - EmptyEffects(); - - m_pClipper.reset(); -} - -void CSubtitle::EmptyEffects() -{ - for (ptrdiff_t i = 0; i < EF_NUMBEROFEFFECTS; i++) { - SAFE_DELETE(m_effects[i]); - } -} - -int CSubtitle::GetFullWidth() -{ - int width = 0; - - POSITION pos = m_words.GetHeadPosition(); - while (pos) { - width += m_words.GetNext(pos)->m_width; - } - - return width; -} - -int CSubtitle::GetFullLineWidth(POSITION pos) -{ - int width = 0; - - while (pos) { - CWord* w = m_words.GetNext(pos); - if (w->m_fLineBreak) { - break; - } - width += w->m_width; - } - - return width; -} - -int CSubtitle::GetWrapWidth(POSITION pos, int maxwidth) -{ - if (m_wrapStyle == 0 || m_wrapStyle == 3) { - if (maxwidth > 0) { - int fullwidth = GetFullLineWidth(pos); - - int minwidth = fullwidth / ((abs(fullwidth) / maxwidth) + 1); - - int width = 0, wordwidth = 0; - - while (pos && width < minwidth) { - CWord* w = m_words.GetNext(pos); - wordwidth = w->m_width; - if (abs(width + wordwidth) < abs(maxwidth)) { - width += wordwidth; - } - } - - if (m_wrapStyle == 3 && width < fullwidth && fullwidth - width + wordwidth < maxwidth) { - width -= wordwidth; - } - maxwidth = width; - } - } else if (m_wrapStyle == 1) { - // maxwidth = maxwidth; - } else if (m_wrapStyle == 2) { - maxwidth = INT_MAX; - } - - return maxwidth; -} - -CLine* CSubtitle::GetNextLine(POSITION& pos, int maxwidth) -{ - if (pos == nullptr) { - return nullptr; - } - - CLine* ret; - try { - ret = DEBUG_NEW CLine(); - } catch (CMemoryException* e) { - e->Delete(); - return nullptr; - } - - ret->m_width = ret->m_ascent = ret->m_descent = ret->m_borderX = ret->m_borderY = ret->m_linePadding = 0; - - maxwidth = GetWrapWidth(pos, maxwidth); - - bool fEmptyLine = true; - - while (pos) { - CWord* w = m_words.GetNext(pos); - - if (ret->m_ascent < w->m_ascent) { - ret->m_ascent = w->m_ascent; - } - if (ret->m_descent < w->m_descent) { - ret->m_descent = w->m_descent; - } - if (ret->m_borderX < w->m_style.outlineWidthX) { - ret->m_borderX = (int)(w->m_style.outlineWidthX + 0.5); - } - if (ret->m_borderY < w->m_style.outlineWidthY) { - ret->m_borderY = (int)(w->m_style.outlineWidthY + 0.5); - } - if (w->m_style.borderStyle == 1 && m_allowLinePadding && (ret->m_linePadding < ret->m_borderY * 2)) { - ret->m_linePadding = ret->m_borderY * 2; - } - - if (w->m_fLineBreak) { - if (fEmptyLine) { - ret->m_ascent /= 2; - ret->m_descent /= 2; - ret->m_borderX = ret->m_borderY = 0; - } - - ret->Compact(); - - return ret; - } - - fEmptyLine = false; - - bool fWSC = w->m_fWhiteSpaceChar; - - int width = w->m_width; - POSITION pos2 = pos; - while (pos2) { - if (m_words.GetAt(pos2)->m_fWhiteSpaceChar != fWSC - || m_words.GetAt(pos2)->m_fLineBreak) { - break; - } - - CWord* w2 = m_words.GetNext(pos2); - width += w2->m_width; - } - - if ((ret->m_width += width) <= maxwidth || ret->IsEmpty()) { - ret->AddTail(w->Copy()); - - while (pos != pos2) { - ret->AddTail(m_words.GetNext(pos)->Copy()); - } - - pos = pos2; - } else { - if (pos) { - m_words.GetPrev(pos); - } else { - pos = m_words.GetTailPosition(); - } - - ret->m_width -= width; - - break; - } - } - - ret->Compact(); - - return ret; -} - -void CSubtitle::CreateClippers(CSize size) -{ - size.cx >>= 3; - size.cy >>= 3; - - auto createClipper = [this](const CSize & size) { - ASSERT(!m_pClipper); - CStringW str; - str.Format(L"m %d %d l %d %d %d %d %d %d", 0, 0, size.cx, 0, size.cx, size.cy, 0, size.cy); - - try { - m_pClipper = std::make_shared(str, size, 1.0, 1.0, false, CPoint(0, 0), m_renderingCaches); - } catch (CMemoryException* e) { - e->Delete(); - } - - return !!m_pClipper; - }; - - if (m_effects[EF_BANNER] && m_effects[EF_BANNER]->param[2]) { - if (!m_pClipper && !createClipper(size)) { - return; - } - m_pClipper->SetEffect(*m_effects[EF_BANNER], EF_BANNER); - } else if (m_effects[EF_SCROLL] && m_effects[EF_SCROLL]->param[4]) { - if (!m_pClipper && !createClipper(size)) { - return; - } - m_pClipper->SetEffect(*m_effects[EF_SCROLL], EF_SCROLL); - } -} - -void CSubtitle::MakeLines(CSize size, const CRect& marginRect) -{ - CSize spaceNeeded(0, 0); - - bool fFirstLine = true; - - m_topborder = m_bottomborder = 0; - - CLine* l = nullptr; - - POSITION pos = m_words.GetHeadPosition(); - while (pos) { - l = GetNextLine(pos, size.cx - marginRect.left - marginRect.right); - if (!l) { - break; - } - - if (fFirstLine) { - m_topborder = l->m_borderY; - l->m_linePadding = 0; - fFirstLine = false; - } - - spaceNeeded.cx = std::max(l->m_width + l->m_borderX, spaceNeeded.cx); - spaceNeeded.cy += l->m_ascent + l->m_descent + l->m_linePadding; - - AddTail(l); - } - - if (l) { - m_bottomborder = l->m_borderY; - } - - m_rect = CRect( - CPoint((m_scrAlignment % 3) == 1 ? marginRect.left - : (m_scrAlignment % 3) == 2 ? (marginRect.left + (size.cx - marginRect.right) - spaceNeeded.cx + 1) / 2 - : (size.cx - marginRect.right - spaceNeeded.cx), - m_scrAlignment <= 3 ? (size.cy - marginRect.bottom - spaceNeeded.cy) - : m_scrAlignment <= 6 ? (marginRect.top + (size.cy - marginRect.bottom) - spaceNeeded.cy + 1) / 2 - : marginRect.top), - spaceNeeded); -} - -// CScreenLayoutAllocator - -void CScreenLayoutAllocator::Empty() -{ - m_subrects.RemoveAll(); -} - -void CScreenLayoutAllocator::AdvanceToSegment(int segment, const CAtlArray& sa) -{ - POSITION pos = m_subrects.GetHeadPosition(); - while (pos) { - POSITION prev = pos; - - SubRect& sr = m_subrects.GetNext(pos); - - bool fFound = false; - - if (abs(sr.segment - segment) <= 1) { // using abs() makes it possible to play the subs backwards, too :) - for (size_t i = 0; i < sa.GetCount() && !fFound; i++) { - if (sa[i] == sr.entry) { - sr.segment = segment; - fFound = true; - } - } - } - - if (!fFound) { - m_subrects.RemoveAt(prev); - } - } -} - -CRect CScreenLayoutAllocator::AllocRect(const CSubtitle* s, int segment, int entry, int layer, int collisions) -{ - // TODO: handle collisions == 1 (reversed collisions) - - POSITION pos = m_subrects.GetHeadPosition(); - while (pos) { - SubRect& sr = m_subrects.GetNext(pos); - if (sr.segment == segment && sr.entry == entry) { - return (sr.r + CRect(0, -s->m_topborder, 0, -s->m_bottomborder)); - } - } - - CRect r = s->m_rect + CRect(0, s->m_topborder, 0, s->m_bottomborder); - - bool fSearchDown = s->m_scrAlignment > 3; - - bool fOK; - - do { - fOK = true; - - pos = m_subrects.GetHeadPosition(); - while (pos) { - SubRect& sr = m_subrects.GetNext(pos); - - if (layer == sr.layer && !(r & sr.r).IsRectEmpty()) { - if (fSearchDown) { - r.bottom = sr.r.bottom + r.Height(); - r.top = sr.r.bottom; - } else { - r.top = sr.r.top - r.Height(); - r.bottom = sr.r.top; - } - - fOK = false; - } - } - } while (!fOK); - - SubRect sr; - sr.r = r; - sr.segment = segment; - sr.entry = entry; - sr.layer = layer; - m_subrects.AddTail(sr); - - return (sr.r + CRect(0, -s->m_topborder, 0, -s->m_bottomborder)); -} - -// CRenderedTextSubtitle - -CAtlMap> CRenderedTextSubtitle::s_SSATagCmds; - -CRenderedTextSubtitle::CRenderedTextSubtitle(CCritSec* pLock) - : CSubPicProviderImpl(pLock) - , m_time(0) - , m_delay(0) - , m_animStart(0) - , m_animEnd(0) - , m_animAccel(0.0) - , m_ktype(0) - , m_kstart(0) - , m_kend(0) - , m_nPolygon(0) - , m_polygonBaselineOffset(0) - , m_bOverridePlacement(false) - , m_overridePlacement(50, 90) - , m_webvtt_allow_clear(false) - , m_bUseFreeType(false) -{ - m_size = CSize(0, 0); - - if (g_hDC_refcnt == 0) { - g_hDC = CreateCompatibleDC(nullptr); - SetBkMode(g_hDC, TRANSPARENT); - SetTextColor(g_hDC, 0xffffff); - SetMapMode(g_hDC, MM_TEXT); - } - - g_hDC_refcnt++; - - if (s_SSATagCmds.IsEmpty()) { - s_SSATagCmds[L"1c"] = SSA_1c; - s_SSATagCmds[L"2c"] = SSA_2c; - s_SSATagCmds[L"3c"] = SSA_3c; - s_SSATagCmds[L"4c"] = SSA_4c; - s_SSATagCmds[L"1a"] = SSA_1a; - s_SSATagCmds[L"2a"] = SSA_2a; - s_SSATagCmds[L"3a"] = SSA_3a; - s_SSATagCmds[L"4a"] = SSA_4a; - s_SSATagCmds[L"alpha"] = SSA_alpha; - s_SSATagCmds[L"an"] = SSA_an; - s_SSATagCmds[L"a"] = SSA_a; - s_SSATagCmds[L"blur"] = SSA_blur; - s_SSATagCmds[L"bord"] = SSA_bord; - s_SSATagCmds[L"be"] = SSA_be; - s_SSATagCmds[L"b"] = SSA_b; - s_SSATagCmds[L"clip"] = SSA_clip; - s_SSATagCmds[L"iclip"] = SSA_iclip; - s_SSATagCmds[L"c"] = SSA_c; - s_SSATagCmds[L"fade"] = SSA_fade; - s_SSATagCmds[L"fad"] = SSA_fade; - s_SSATagCmds[L"fax"] = SSA_fax; - s_SSATagCmds[L"fay"] = SSA_fay; - s_SSATagCmds[L"fe"] = SSA_fe; - s_SSATagCmds[L"fn"] = SSA_fn; - s_SSATagCmds[L"frx"] = SSA_frx; - s_SSATagCmds[L"fry"] = SSA_fry; - s_SSATagCmds[L"frz"] = SSA_frz; - s_SSATagCmds[L"fr"] = SSA_fr; - s_SSATagCmds[L"fscx"] = SSA_fscx; - s_SSATagCmds[L"fscy"] = SSA_fscy; - s_SSATagCmds[L"fsc"] = SSA_fsc; - s_SSATagCmds[L"fsp"] = SSA_fsp; - s_SSATagCmds[L"fs"] = SSA_fs; - s_SSATagCmds[L"i"] = SSA_i; - s_SSATagCmds[L"kt"] = SSA_kt; - s_SSATagCmds[L"kf"] = SSA_kf; - s_SSATagCmds[L"K"] = SSA_K; - s_SSATagCmds[L"ko"] = SSA_ko; - s_SSATagCmds[L"k"] = SSA_k; - s_SSATagCmds[L"move"] = SSA_move; - s_SSATagCmds[L"org"] = SSA_org; - s_SSATagCmds[L"pbo"] = SSA_pbo; - s_SSATagCmds[L"pos"] = SSA_pos; - s_SSATagCmds[L"p"] = SSA_p; - s_SSATagCmds[L"q"] = SSA_q; - s_SSATagCmds[L"r"] = SSA_r; - s_SSATagCmds[L"shad"] = SSA_shad; - s_SSATagCmds[L"s"] = SSA_s; - s_SSATagCmds[L"t"] = SSA_t; - s_SSATagCmds[L"u"] = SSA_u; - s_SSATagCmds[L"xbord"] = SSA_xbord; - s_SSATagCmds[L"xshad"] = SSA_xshad; - s_SSATagCmds[L"ybord"] = SSA_ybord; - s_SSATagCmds[L"yshad"] = SSA_yshad; - } -} - -CRenderedTextSubtitle::~CRenderedTextSubtitle() -{ - Deinit(); - - g_hDC_refcnt--; - if (g_hDC_refcnt == 0) { - DeleteDC(g_hDC); - } -} - -void CRenderedTextSubtitle::Copy(CSimpleTextSubtitle& sts) -{ - __super::Copy(sts); - - m_size = CSize(0, 0); - - if (CRenderedTextSubtitle* pRTS = dynamic_cast(&sts)) { - m_size = pRTS->m_size; - } -} - -void CRenderedTextSubtitle::Empty() -{ - Deinit(); - - __super::Empty(); -} - -void CRenderedTextSubtitle::SetOverride(bool bOverrideDefault, bool bOverrideAll, const STSStyle& styleOverride) { - overrideANSICharset = styleOverride.charSet; - bool bOverride = bOverrideDefault || bOverrideAll; - bool changed = (bOverride && !m_bStyleOverrideActive) || (m_SubRendererSettings.overrideDefaultStyle != bOverrideDefault) || (m_SubRendererSettings.overrideAllStyles != bOverrideAll) || bOverride && (m_SubRendererSettings.defaultStyle != styleOverride); - - if (changed) { - m_bStyleOverrideActive = bOverride; - m_SubRendererSettings.defaultStyle = bOverride ? styleOverride : GetOriginalDefaultStyle(); - m_SubRendererSettings.overrideDefaultStyle = bOverride; - m_SubRendererSettings.overrideAllStyles = bOverrideAll; - - UpdateSubRelativeTo(m_subtitleType, m_SubRendererSettings.defaultStyle.relativeTo); - - if (bOverride) { - m_scaledBAS = 0; - } - - if (bOverride && m_playRes.cy != 288 && m_playRes.cx > 0 && m_playRes.cy > 0) { - /* Default style is defined relative to a 384x288 PlayRes resolution. Scale to get consistent font size. */ - double scaleX = m_playRes.cx / 384.0; - double scaleY = m_playRes.cy / 288.0; - m_SubRendererSettings.defaultStyle.fontSize *= scaleY; - m_SubRendererSettings.defaultStyle.fontSpacing *= scaleX; - m_SubRendererSettings.defaultStyle.marginRect.left = std::lround(scaleX * m_SubRendererSettings.defaultStyle.marginRect.left); - m_SubRendererSettings.defaultStyle.marginRect.top = std::lround(scaleY * m_SubRendererSettings.defaultStyle.marginRect.top); - m_SubRendererSettings.defaultStyle.marginRect.right = std::lround(scaleX * m_SubRendererSettings.defaultStyle.marginRect.right); - m_SubRendererSettings.defaultStyle.marginRect.bottom = std::lround(scaleY * m_SubRendererSettings.defaultStyle.marginRect.bottom); - } - - SetDefaultStyle(m_SubRendererSettings.defaultStyle); - -#if USE_LIBASS - if (m_LibassContext.IsLibassActive()) { - m_LibassContext.StylesChanged(); - } -#endif - } -} - -void CRenderedTextSubtitle::OnChanged() -{ - __super::OnChanged(); - CAutoLock cAutoLock(&renderLock); - - POSITION pos = m_subtitleCache.GetStartPosition(); - while (pos) { - int i; - CSubtitle* s; - m_subtitleCache.GetNextAssoc(pos, i, s); - delete s; - } - - m_subtitleCache.RemoveAll(); - - m_sla.Empty(); -} - -bool CRenderedTextSubtitle::Init(CSize size, const CRect& vidrect) -{ - if (!vidrect.Width()) { - return false; - } - - CAutoLock cAutoLock(&renderLock); - CRect newVidRect = CRect(vidrect.left * 8, vidrect.top * 8, vidrect.right * 8, vidrect.bottom * 8); - CSize newSize = CSize(size.cx * 8, size.cy * 8); - if (m_size != newSize || m_vidrect != newVidRect) { - TRACE(_T("RTS Init | texture %dx%d | vidrect %dx%d\n"), size.cx, size.cy, vidrect.Width(), vidrect.Height()); - Deinit(); - m_size = newSize; - m_vidrect = newVidRect; - } - - return true; -} - -void CRenderedTextSubtitle::Deinit() -{ - CAutoLock cAutoLock(&renderLock); - POSITION pos = m_subtitleCache.GetStartPosition(); - while (pos) { - int i; - CSubtitle* s; - m_subtitleCache.GetNextAssoc(pos, i, s); - delete s; - } - m_subtitleCache.RemoveAll(); - - m_sla.Empty(); - - m_size = CSize(0, 0); - m_vidrect.SetRectEmpty(); -} - -void CRenderedTextSubtitle::ParseEffect(CSubtitle* sub, CString str) -{ - str.Trim(); - if (!sub || str.IsEmpty()) { - return; - } - - const TCHAR* s = _tcschr(str, ';'); - if (!s) { - s = (LPTSTR)(LPCTSTR)str; - s += str.GetLength() - 1; - } - s++; - CString effect = str.Left(int(s - str)); - - if (!effect.CompareNoCase(_T("Banner;"))) { - sub->m_bIsAnimated = true; - - int delay, lefttoright = 0, fadeawaywidth = 0; - if (_stscanf_s(s, _T("%d;%d;%d"), &delay, &lefttoright, &fadeawaywidth) < 1) { - return; - } - - Effect* e; - try { - e = DEBUG_NEW Effect; - } catch (CMemoryException* e) { - e->Delete(); - return; - } - - sub->m_effects[e->type = EF_BANNER] = e; - e->param[0] = (int)(std::max(1.0 * delay / sub->m_total_scale_x, 1.0)); - e->param[1] = lefttoright; - e->param[2] = std::lround(sub->m_total_scale_x * fadeawaywidth); - - sub->m_wrapStyle = 2; - } else if (!effect.CompareNoCase(_T("Scroll up;")) || !effect.CompareNoCase(_T("Scroll down;"))) { - sub->m_bIsAnimated = true; - - int top, bottom, delay, fadeawayheight = 0; - if (_stscanf_s(s, _T("%d;%d;%d;%d"), &top, &bottom, &delay, &fadeawayheight) < 3) { - return; - } - - if (top > bottom) { - int tmp = top; - top = bottom; - bottom = tmp; - } - - Effect* e; - try { - e = DEBUG_NEW Effect; - } catch (CMemoryException* e) { - e->Delete(); - return; - } - - sub->m_effects[e->type = EF_SCROLL] = e; - e->param[0] = std::lround(sub->m_total_scale_y * top * 8.0); - e->param[1] = std::lround(sub->m_total_scale_y * bottom * 8.0); - e->param[2] = (int)(std::max(double(delay) / sub->m_total_scale_y, 1.0)); - e->param[3] = (effect.GetLength() == 12); - e->param[4] = std::lround(sub->m_total_scale_y * fadeawayheight); - } -} - -void CRenderedTextSubtitle::ParseString(CSubtitle* sub, CStringW str, STSStyle& style) -{ - if (!sub) { - return; - } - - if (str.GetLength() == 1) { - if (str[0] == L'\x202a' || str[0] == L'\x202b') { - return; // ignore Unicode control character - } - } - - str.Replace(L"
", L"\n"); - str.Replace(L"\\N", L"\n"); - str.Replace(L"\\n", (sub->m_wrapStyle < 2 || sub->m_wrapStyle == 3) ? L" " : L"\n"); - str.Replace(L"\\h", L"\x00A0"); // no-break space - - for (int i = 0, j = 0, len = str.GetLength(); j <= len; j++) { - WCHAR c = str[j]; - - if (c != L'\n' && c != L' ' && c != 0) { - continue; - } - - if (i < j) { - if (CText* w = DEBUG_NEW CText(style, str.Mid(i, j - i), m_ktype, m_kstart, m_kend, sub->m_target_scale_x, sub->m_target_scale_y, m_renderingCaches)) { - w->SetRts(this); - sub->m_words.AddTail(w); - m_kstart = m_kend; - } - } - - if (c == L'\n') { - if (CText* w = DEBUG_NEW CText(style, CStringW(), m_ktype, m_kstart, m_kend, sub->m_target_scale_x, sub->m_target_scale_y, m_renderingCaches)) { - w->SetRts(this); - sub->m_words.AddTail(w); - m_kstart = m_kend; - } - } else if (c == L' ') { - if (CText* w = DEBUG_NEW CText(style, CStringW(c), m_ktype, m_kstart, m_kend, sub->m_target_scale_x, sub->m_target_scale_y, m_renderingCaches)) { - w->SetRts(this); - sub->m_words.AddTail(w); - m_kstart = m_kend; - } - } - - i = j + 1; - } - - return; -} - -void CRenderedTextSubtitle::ParsePolygon(CSubtitle* sub, CStringW str, STSStyle& style) -{ - if (!sub || !str.GetLength() || !m_nPolygon) { - return; - } - - int s = 1 << (m_nPolygon - 1); - if (CWord* w = DEBUG_NEW CPolygon(style, str, m_ktype, m_kstart, m_kend, - sub->m_total_scale_x / s, sub->m_total_scale_y / s, - m_polygonBaselineOffset, - m_renderingCaches)) { - sub->m_words.AddTail(w); - m_kstart = m_kend; - } -} - -bool CRenderedTextSubtitle::ParseSSATag(SSATagsList& tagsList, const CStringW& str) -{ - if (m_renderingCaches.SSATagsCache.Lookup(str, tagsList)) { - //TRACE(_T("ParseSSATag (cached): %s\n"), str.GetString()); - return true; - } - //TRACE(_T("ParseSSATag: %s\n"), str.GetString()); - - int nTags = 0, nUnrecognizedTags = 0; - tagsList.reset(DEBUG_NEW CAtlList()); - - for (int i = 0, j; (j = str.Find(L'\\', i)) >= 0; i = j) { - int jOld; - // find the end of the current tag or the start of its parameters - for (jOld = ++j; str[j] && str[j] != L'(' && str[j] != L'\\'; ++j) { - ; - } - CStringW cmd = str.Mid(jOld, j - jOld); - FastTrim(cmd); - if (cmd.IsEmpty()) { - continue; - } - - nTags++; - - SSATag tag; - tag.cmd = SSA_unknown; - for (int cmdLength = std::min(SSA_CMD_MAX_LENGTH, cmd.GetLength()), cmdLengthMin = SSA_CMD_MIN_LENGTH; cmdLength >= cmdLengthMin; cmdLength--) { - if (s_SSATagCmds.Lookup(cmd.Left(cmdLength), tag.cmd)) { - break; - } - } - if (tag.cmd == SSA_unknown) { - nUnrecognizedTags++; - continue; - } - - if (str[j] == L'(') { - // complex tags search - int br = 1; // 1 bracket - // find the end of the parameters - for (jOld = ++j; str[j] && br > 0; ++j) { - if (str[j] == L'(') { - br++; - } else if (str[j] == L')') { - br--; - } - if (br == 0) { - break; - } - } - CStringW param = str.Mid(jOld, j - jOld); - FastTrim(param); - - while (!param.IsEmpty()) { - int k = param.Find(L','), l = param.Find(L'\\'); - - if (k >= 0 && (l < 0 || k < l)) { - CStringW s = param.Left(k).Trim(); - if (!s.IsEmpty()) { - tag.params.Add(s); - } - param = k + 1 < param.GetLength() ? param.Mid(k + 1).GetString() : L""; - } else { - FastTrim(param); - if (!param.IsEmpty()) { - tag.params.Add(param); - } - param.Empty(); - } - } - } - - switch (tag.cmd) { - case SSA_1c: - case SSA_2c: - case SSA_3c: - case SSA_4c: - case SSA_1a: - case SSA_2a: - case SSA_3a: - case SSA_4a: - if (cmd.GetLength() > 2) { - tag.paramsInt.Add(wcstol(cmd.Mid(2).Trim(L"&H"), nullptr, 16)); - } - break; - case SSA_alpha: - if (cmd.GetLength() > 5) { - tag.paramsInt.Add(wcstol(cmd.Mid(5).Trim(L"&H"), nullptr, 16)); - } - break; - case SSA_an: - case SSA_be: - case SSA_fe: - case SSA_kt: - case SSA_kf: - case SSA_ko: - if (cmd.GetLength() > 2) { - tag.paramsInt.Add(wcstol(cmd.Mid(2), nullptr, 10)); - } - break; - case SSA_fn: - tag.params.Add(cmd.Mid(2)); - break; - case SSA_fr: - if (cmd.GetLength() > 2) { - tag.paramsReal.Add(wcstod(cmd.Mid(2), nullptr)); - } - break; - case SSA_fs: - if (cmd.GetLength() > 2) { - int s = 2; - if (cmd[s] == L'+' || cmd[s] == L'-') { - tag.params.Add(cmd.Mid(s, 1)); - } - tag.paramsInt.Add(wcstol(cmd.Mid(s), nullptr, 10)); - } - break; - case SSA_a: - case SSA_b: - case SSA_i: - case SSA_k: - case SSA_K: - case SSA_p: - case SSA_q: - case SSA_s: - case SSA_u: - if (cmd.GetLength() > 1) { - tag.paramsInt.Add(wcstol(cmd.Mid(1), nullptr, 10)); - } - break; - case SSA_r: - tag.params.Add(cmd.Mid(1)); - break; - case SSA_blur: - case SSA_bord: - case SSA_fscx: - case SSA_fscy: - case SSA_shad: - if (cmd.GetLength() > 4) { - tag.paramsReal.Add(wcstod(cmd.Mid(4), nullptr)); - } - break; - case SSA_clip: - case SSA_iclip: { - size_t nParams = tag.params.GetCount(); - if (nParams == 2) { - tag.paramsInt.Add(wcstol(tag.params[0], nullptr, 10)); - tag.params.RemoveAt(0); - } else if (nParams == 4) { - for (size_t n = 0; n < nParams; n++) { - tag.paramsInt.Add(wcstol(tag.params[n], nullptr, 10)); - } - tag.params.RemoveAll(); - } - } - break; - case SSA_fade: { - size_t nParams = tag.params.GetCount(); - if (nParams == 7 || nParams == 2) { - for (size_t n = 0; n < nParams; n++) { - tag.paramsInt.Add(wcstol(tag.params[n], nullptr, 10)); - } - tag.params.RemoveAll(); - } - } - break; - case SSA_move: { - size_t nParams = tag.params.GetCount(); - if (nParams == 4 || nParams == 6) { - for (size_t n = 0; n < 4; n++) { - tag.paramsReal.Add(wcstod(tag.params[n], nullptr)); - } - for (size_t n = 4; n < nParams; n++) { - tag.paramsInt.Add(wcstol(tag.params[n], nullptr, 10)); - } - tag.params.RemoveAll(); - } - } - break; - case SSA_org: - case SSA_pos: { - size_t nParams = tag.params.GetCount(); - if (nParams == 2) { - for (size_t n = 0; n < nParams; n++) { - tag.paramsReal.Add(wcstod(tag.params[n], nullptr)); - } - tag.params.RemoveAll(); - } - } - break; - case SSA_c: - if (cmd.GetLength() > 1) { - tag.paramsInt.Add(wcstol(cmd.Mid(1).Trim(L"&H"), nullptr, 16)); - } - break; - case SSA_frx: - case SSA_fry: - case SSA_frz: - case SSA_fax: - case SSA_fay: - case SSA_fsc: - case SSA_fsp: - if (cmd.GetLength() > 3) { - tag.paramsReal.Add(wcstod(cmd.Mid(3), nullptr)); - } - break; - case SSA_pbo: - if (cmd.GetLength() > 3) { - tag.paramsInt.Add(wcstol(cmd.Mid(3), nullptr, 10)); - } - break; - case SSA_t: { - size_t nParams = tag.params.GetCount(); - if (nParams >= 1 && nParams <= 4) { - if (nParams == 2) { - tag.paramsReal.Add(wcstod(tag.params[0], nullptr)); - } else if (nParams == 3) { - tag.paramsReal.Add(wcstod(tag.params[0], nullptr)); - tag.paramsReal.Add(wcstod(tag.params[1], nullptr)); - } else if (nParams == 4) { - tag.paramsInt.Add(wcstol(tag.params[0], nullptr, 10)); - tag.paramsInt.Add(wcstol(tag.params[1], nullptr, 10)); - tag.paramsReal.Add(wcstod(tag.params[2], nullptr)); - } - - ParseSSATag(tag.subTagsList, tag.params[nParams - 1]); - } - tag.params.RemoveAll(); - } - break; - case SSA_xbord: - case SSA_xshad: - case SSA_ybord: - case SSA_yshad: - if (cmd.GetLength() > 5) { - tag.paramsReal.Add(wcstod(cmd.Mid(5), nullptr)); - } - break; - } - - tagsList->AddTail(tag); - } - - m_renderingCaches.SSATagsCache.SetAt(str, tagsList); - - //return (nUnrecognizedTags < nTags); - return true; // there are people keeping comments inside {}, lets make them happy now -} - -bool CRenderedTextSubtitle::CreateSubFromSSATag(CSubtitle* sub, const SSATagsList& tagsList, - STSStyle& style, STSStyle& org, bool fAnimate /*= false*/) -{ - if (!sub || !tagsList) { - return false; - } - - POSITION pos = tagsList->GetHeadPosition(); - while (pos) { - const SSATag& tag = tagsList->GetNext(pos); - - // TODO: call ParseStyleModifier(cmd, params, ..) and move the rest there - - switch (tag.cmd) { - case SSA_1c: - case SSA_2c: - case SSA_3c: - case SSA_4c: { - int k = tag.cmd - SSA_1c; - - if (!tag.paramsInt.IsEmpty()) { - DWORD c = tag.paramsInt[0]; - style.colors[k] = (((int)CalcAnimation(c & 0xff, style.colors[k] & 0xff, fAnimate)) & 0xff - | ((int)CalcAnimation(c & 0xff00, style.colors[k] & 0xff00, fAnimate)) & 0xff00 - | ((int)CalcAnimation(c & 0xff0000, style.colors[k] & 0xff0000, fAnimate)) & 0xff0000); - } else { - style.colors[k] = org.colors[k]; - } - } - break; - case SSA_1a: - case SSA_2a: - case SSA_3a: - case SSA_4a: { - int k = tag.cmd - SSA_1a; - - style.alpha[k] = !tag.paramsInt.IsEmpty() - ? (BYTE)CalcAnimation(tag.paramsInt[0] & 0xff, style.alpha[k], fAnimate) - : org.alpha[k]; - } - break; - case SSA_alpha: - for (ptrdiff_t k = 0; k < 4; k++) { - style.alpha[k] = !tag.paramsInt.IsEmpty() - ? (BYTE)CalcAnimation(tag.paramsInt[0] & 0xff, style.alpha[k], fAnimate) - : org.alpha[k]; - } - break; - case SSA_an: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : 0; - if (sub->m_scrAlignment < 0) { - sub->m_scrAlignment = (n > 0 && n < 10) ? n : org.scrAlignment; - } - } - break; - case SSA_a: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : 0; - if (sub->m_scrAlignment < 0) { - sub->m_scrAlignment = (n > 0 && n < 12) ? ((((n - 1) & 3) + 1) + ((n & 4) ? 6 : 0) + ((n & 8) ? 3 : 0)) : org.scrAlignment; - } - } - break; - case SSA_blur: - if (!tag.paramsReal.IsEmpty()) { - double n = CalcAnimation(tag.paramsReal[0], style.fGaussianBlur, fAnimate); - style.fGaussianBlur = (n < 0 ? 0 : n); - } else { - style.fGaussianBlur = org.fGaussianBlur; - } - if (style.fGaussianBlur > 25.0) { - style.fGaussianBlur = 25.0; - TRACE(L"INSANE blur value !!!\n"); - } - break; - case SSA_bord: - if (!tag.paramsReal.IsEmpty()) { - double nx = CalcAnimation(tag.paramsReal[0], style.outlineWidthX, fAnimate); - style.outlineWidthX = (nx < 0 ? 0 : nx); - double ny = CalcAnimation(tag.paramsReal[0], style.outlineWidthY, fAnimate); - style.outlineWidthY = (ny < 0 ? 0 : ny); - } else { - style.outlineWidthX = org.outlineWidthX; - style.outlineWidthY = org.outlineWidthY; - } - break; - case SSA_be: - style.fBlur = !tag.paramsInt.IsEmpty() - ? (int)(CalcAnimation(tag.paramsInt[0], style.fBlur, fAnimate) + 0.5) - : org.fBlur; - break; - case SSA_b: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : -1; - style.fontWeight = (n == 0 ? FW_NORMAL : n == 1 ? FW_BOLD : n >= 100 ? n : org.fontWeight); - } - break; - case SSA_clip: - case SSA_iclip: { - bool invert = (tag.cmd == SSA_iclip); - size_t nParams = tag.params.GetCount(); - size_t nParamsInt = tag.paramsInt.GetCount(); - - if (nParams == 1 && nParamsInt == 0 && !sub->m_pClipper) { - sub->m_pClipper = std::make_shared(tag.params[0], CSize(m_size.cx >> 3, m_size.cy >> 3), sub->m_total_scale_x, sub->m_total_scale_y, - invert, (sub->m_relativeTo == STSStyle::VIDEO) ? CPoint(m_vidrect.left, m_vidrect.top) : CPoint(0, 0), - m_renderingCaches); - } else if (nParams == 1 && nParamsInt == 1 && !sub->m_pClipper) { - long scale = tag.paramsInt[0]; - if (scale < 1) { - scale = 1; - } - long scalediv = (1 << (scale - 1)); - sub->m_pClipper = std::make_shared(tag.params[0], CSize(m_size.cx >> 3, m_size.cy >> 3), - sub->m_total_scale_x / scalediv, sub->m_total_scale_y / scalediv, invert, - (sub->m_relativeTo == STSStyle::VIDEO) ? CPoint(m_vidrect.left, m_vidrect.top) : CPoint(0, 0), - m_renderingCaches); - } else if (nParamsInt == 4) { - sub->m_clipInverse = invert; - - double dLeft = sub->m_total_scale_x * tag.paramsInt[0]; - double dTop = sub->m_total_scale_y * tag.paramsInt[1]; - double dRight = sub->m_total_scale_x * tag.paramsInt[2]; - double dBottom = sub->m_total_scale_y * tag.paramsInt[3]; - - if (sub->m_relativeTo == STSStyle::VIDEO) { - double dOffsetX = m_vidrect.left / 8.0; - double dOffsetY = m_vidrect.top / 8.0; - dLeft += dOffsetX; - dTop += dOffsetY; - dRight += dOffsetX; - dBottom += dOffsetY; - } - - sub->m_clip.SetRect( - static_cast(CalcAnimation(dLeft, sub->m_clip.left, fAnimate)), - static_cast(CalcAnimation(dTop, sub->m_clip.top, fAnimate)), - static_cast(CalcAnimation(dRight, sub->m_clip.right, fAnimate)), - static_cast(CalcAnimation(dBottom, sub->m_clip.bottom, fAnimate))); - } - } - break; - case SSA_c: - if (!tag.paramsInt.IsEmpty()) { - DWORD c = tag.paramsInt[0]; - style.colors[0] = (((int)CalcAnimation(c & 0xff, style.colors[0] & 0xff, fAnimate)) & 0xff - | ((int)CalcAnimation(c & 0xff00, style.colors[0] & 0xff00, fAnimate)) & 0xff00 - | ((int)CalcAnimation(c & 0xff0000, style.colors[0] & 0xff0000, fAnimate)) & 0xff0000); - } else { - style.colors[0] = org.colors[0]; - } - break; - case SSA_fade: { - sub->m_bIsAnimated = true; - - if (tag.paramsInt.GetCount() == 7 && !sub->m_effects[EF_FADE]) { // {\fade(a1=param[0], a2=param[1], a3=param[2], t1=t[0], t2=t[1], t3=t[2], t4=t[3]) - if (Effect* e = DEBUG_NEW Effect) { - for (size_t k = 0; k < 3; k++) { - e->param[k] = tag.paramsInt[k]; - } - for (size_t k = 0; k < 4; k++) { - e->t[k] = tag.paramsInt[3 + k]; - } - - sub->m_effects[EF_FADE] = e; - } - } else if (tag.paramsInt.GetCount() == 2 && !sub->m_effects[EF_FADE]) { // {\fad(t1=t[1], t2=t[2]) - if (Effect* e = DEBUG_NEW Effect) { - e->param[0] = e->param[2] = 0xff; - e->param[1] = 0x00; - for (size_t k = 1; k < 3; k++) { - e->t[k] = tag.paramsInt[k - 1]; - } - e->t[0] = e->t[3] = -1; // will be substituted with "start" and "end" - - sub->m_effects[EF_FADE] = e; - } - } - } - break; - case SSA_fax: - style.fontShiftX = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontShiftX, fAnimate) - : org.fontShiftX; - break; - case SSA_fay: - style.fontShiftY = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontShiftY, fAnimate) - : org.fontShiftY; - break; - case SSA_fe: - style.charSet = !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] - : org.charSet; - break; - case SSA_fn: - style.fontName = (!tag.params.IsEmpty() && !tag.params[0].IsEmpty() && tag.params[0] != L"0") - ? CString(tag.params[0]).Trim() - : org.fontName; - if (style.fontName == _T("splatter")) { - /* workaround for slow rendering with this font - slowness occurs in Windows GDI CloseFigure() function - */ - style.fontName = _T("Arial"); - } - break; - case SSA_frx: - style.fontAngleX = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontAngleX, fAnimate) - : org.fontAngleX; - break; - case SSA_fry: - style.fontAngleY = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontAngleY, fAnimate) - : org.fontAngleY; - break; - case SSA_frz: - case SSA_fr: - style.fontAngleZ = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontAngleZ, fAnimate) - : org.fontAngleZ; - break; - case SSA_fscx: - if (!tag.paramsReal.IsEmpty()) { - double n = CalcAnimation(tag.paramsReal[0], style.fontScaleX, fAnimate); - style.fontScaleX = (n < 0 ? 0 : n); - } else { - style.fontScaleX = org.fontScaleX; - } - break; - case SSA_fscy: - if (!tag.paramsReal.IsEmpty()) { - double n = CalcAnimation(tag.paramsReal[0], style.fontScaleY, fAnimate); - style.fontScaleY = (n < 0 ? 0 : n); - } else { - style.fontScaleY = org.fontScaleY; - } - break; - case SSA_fsc: - style.fontScaleX = org.fontScaleX; - style.fontScaleY = org.fontScaleY; - break; - case SSA_fsp: - style.fontSpacing = !tag.paramsReal.IsEmpty() - ? CalcAnimation(tag.paramsReal[0], style.fontSpacing, fAnimate) - : org.fontSpacing; - break; - case SSA_fs: - if (!tag.paramsInt.IsEmpty()) { - if (!tag.params.IsEmpty() && (tag.params[0][0] == L'-' || tag.params[0][0] == L'+')) { - double n = CalcAnimation(style.fontSize + style.fontSize * tag.paramsInt[0] / 10, style.fontSize, fAnimate); - style.fontSize = (n > 0) ? n : org.fontSize; - } else { - double n = CalcAnimation(tag.paramsInt[0], style.fontSize, fAnimate); - style.fontSize = (n > 0) ? n : org.fontSize; - } - } else { - style.fontSize = org.fontSize; - } - break; - case SSA_i: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : -1; - style.fItalic = (n == 0 ? false : n == 1 ? true : org.fItalic); - } - break; - case SSA_kt: - sub->m_bIsAnimated = true; - - m_kstart = !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] * 10 - : 0; - m_kend = m_kstart; - break; - case SSA_kf: - case SSA_K: - sub->m_bIsAnimated = true; - - m_ktype = 1; - m_kstart = m_kend; - m_kend += !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] * 10 - : 1000; - break; - case SSA_ko: - sub->m_bIsAnimated = true; - - m_ktype = 2; - m_kstart = m_kend; - m_kend += !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] * 10 - : 1000; - break; - case SSA_k: - sub->m_bIsAnimated = true; - - m_ktype = 0; - m_kstart = m_kend; - m_kend += !tag.paramsInt.IsEmpty() - ? tag.paramsInt[0] * 10 - : 1000; - break; - case SSA_move: // {\move(x1=param[0], y1=param[1], x2=param[2], y2=param[3][, t1=t[0], t2=t[1]])} - sub->m_bIsAnimated = true; - - if (tag.paramsReal.GetCount() == 4 && !sub->m_effects[EF_MOVE]) { - if (Effect* e = DEBUG_NEW Effect) { - e->param[0] = std::lround(sub->m_total_scale_x * tag.paramsReal[0] * 8.0); - e->param[1] = std::lround(sub->m_total_scale_y * tag.paramsReal[1] * 8.0); - e->param[2] = std::lround(sub->m_total_scale_x * tag.paramsReal[2] * 8.0); - e->param[3] = std::lround(sub->m_total_scale_y * tag.paramsReal[3] * 8.0); - e->t[0] = e->t[1] = -1; - - if (tag.paramsInt.GetCount() == 2) { - for (size_t k = 0; k < 2; k++) { - e->t[k] = tag.paramsInt[k]; - } - } - - sub->m_effects[EF_MOVE] = e; - } - } - break; - case SSA_org: // {\org(x=param[0], y=param[1])} - if (tag.paramsReal.GetCount() == 2 && !sub->m_effects[EF_ORG]) { - if (Effect* e = DEBUG_NEW Effect) { - e->param[0] = std::lround(sub->m_total_scale_x * tag.paramsReal[0] * 8.0); - e->param[1] = std::lround(sub->m_total_scale_y * tag.paramsReal[1] * 8.0); - - if (sub->m_relativeTo == STSStyle::VIDEO) { - e->param[0] += m_vidrect.left; - e->param[1] += m_vidrect.top; - } - - sub->m_effects[EF_ORG] = e; - } - } - break; - case SSA_pbo: - m_polygonBaselineOffset = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : 0; - break; - case SSA_pos: - if (tag.paramsReal.GetCount() == 2 && !sub->m_effects[EF_MOVE]) { - if (Effect* e = DEBUG_NEW Effect) { - e->param[0] = e->param[2] = std::lround(sub->m_total_scale_x * tag.paramsReal[0] * 8.0); - e->param[1] = e->param[3] = std::lround(sub->m_total_scale_y * tag.paramsReal[1] * 8.0); - e->t[0] = e->t[1] = 0; - - sub->m_effects[EF_MOVE] = e; - } - } - break; - case SSA_p: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : 0; - m_nPolygon = (n <= 0 ? 0 : n); - } - break; - case SSA_q: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : -1; - sub->m_wrapStyle = (0 <= n && n <= 3) - ? n - : m_defaultWrapStyle; - } - break; - case SSA_r: - if (tag.params[0].IsEmpty() || !GetStyle(tag.params[0], style)) { - style = org; - } - break; - case SSA_shad: - if (!tag.paramsReal.IsEmpty()) { - double nx = CalcAnimation(tag.paramsReal[0], style.shadowDepthX, fAnimate); - style.shadowDepthX = (nx < 0 ? 0 : nx); - double ny = CalcAnimation(tag.paramsReal[0], style.shadowDepthY, fAnimate); - style.shadowDepthY = (ny < 0 ? 0 : ny); - } else { - style.shadowDepthX = org.shadowDepthX; - style.shadowDepthY = org.shadowDepthY; - } - break; - case SSA_s: { - int n = !tag.paramsInt.IsEmpty() ? tag.paramsInt[0] : -1; - style.fStrikeOut = (n == 0 ? false : n == 1 ? true : org.fStrikeOut); - } - break; - case SSA_t: // \t([,,][,]\n"); - str += _T("\n"); - str += _T("\n"); - str += _T("\n"); - - f.WriteString(str); - } else if (type == Subtitle::SSA || type == Subtitle::ASS) { - CString str; - - str = _T("[Script Info]\n"); - str += _T("; Note: This file was saved by MPC-HC.\n"); - str += (type == Subtitle::SSA) ? _T("ScriptType: v4.00\n") : _T("ScriptType: v4.00+\n"); - str += (m_collisions == 0) ? _T("Collisions: Normal\n") : _T("Collisions: Reverse\n"); - if (type == Subtitle::ASS && m_scaledBAS >= 0) { - if (m_scaledBAS == 1) { - str += _T("ScaledBorderAndShadow: yes\n"); - } else { - str += _T("ScaledBorderAndShadow: no\n"); - } - } - if (m_sYCbCrMatrix.IsEmpty()) { - str += _T("YCbCr Matrix: None\n"); - } else { - str += _T("YCbCr Matrix: ") + m_sYCbCrMatrix + _T("\n"); - } - str.AppendFormat(_T("PlayResX: %d\n"), m_playRes.cx); - str.AppendFormat(_T("PlayResY: %d\n"), m_playRes.cy); - if (m_layoutRes.cx > 0 && m_layoutRes.cy > 0) { - str.AppendFormat(_T("LayoutResX: %d\n"), m_layoutRes.cx); - str.AppendFormat(_T("LayoutResY: %d\n"), m_layoutRes.cy); - } - str += _T("Timer: 100.0000\n"); - str += _T("\n"); - str += (type == Subtitle::SSA) - ? _T("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n") - : _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"); - - f.WriteString(str); - - str = (type == Subtitle::SSA) - ? _T("Style: %s,%s,%d,&H%06x,&H%06x,&H%06x,&H%06x,%d,%d,%d,%.2f,%.2f,%d,%d,%d,%d,%d,%d\n") - : _T("Style: %s,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f,%d,%d,%d,%d,%d\n"); - - POSITION pos = m_styles.GetStartPosition(); - while (pos) { - CString key; - STSStyle* s; - m_styles.GetNextAssoc(pos, key, s); - - if (type == Subtitle::SSA) { - CString str2; - str2.Format(str, key.GetString(), - s->fontName.GetString(), (int)s->fontSize, - s->colors[0] & 0xffffff, - s->colors[1] & 0xffffff, - s->colors[2] & 0xffffff, - s->colors[3] & 0xffffff, - s->fontWeight > FW_NORMAL ? -1 : 0, s->fItalic ? -1 : 0, - s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, - s->outlineWidthY, s->shadowDepthY, - s->scrAlignment <= 3 ? s->scrAlignment : s->scrAlignment <= 6 ? ((s->scrAlignment - 3) | 8) : s->scrAlignment <= 9 ? ((s->scrAlignment - 6) | 4) : 2, - s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2, - s->alpha[0], - s->charSet); - f.WriteString(str2); - } else { - CString str2; - str2.Format(str, key.GetString(), - s->fontName.GetString(), (int)s->fontSize, - (s->colors[0] & 0xffffff) | (s->alpha[0] << 24), - (s->colors[1] & 0xffffff) | (s->alpha[1] << 24), - (s->colors[2] & 0xffffff) | (s->alpha[2] << 24), - (s->colors[3] & 0xffffff) | (s->alpha[3] << 24), - s->fontWeight > FW_NORMAL ? -1 : 0, - s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, - s->fontScaleX, s->fontScaleY, - s->fontSpacing, s->fontAngleZ, - s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, - s->outlineWidthY, s->shadowDepthY, - s->scrAlignment, - s->marginRect.left, s->marginRect.right, (int)((s->marginRect.top + s->marginRect.bottom) / 2), - s->charSet); - f.WriteString(str2); - } - } - - if (!IsEmpty()) { - str = _T("\n"); - str += _T("[Events]\n"); - str += (type == Subtitle::SSA) - ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n") - : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n"); - f.WriteString(str); - } - } - - CStringW fmt = - type == Subtitle::SRT ? L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n" : - type == Subtitle::SUB ? L"{%d}{%d}%s\n" : - type == Subtitle::SMI ? L"

\n%s\n

 \n" : - type == Subtitle::PSB ? L"{%d:%02d:%02d}{%d:%02d:%02d}%s\n" : - type == Subtitle::SSA ? L"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" : - type == Subtitle::ASS ? L"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" : - L""; - // Sort(true); - - if (m_mode == FRAME) { - delay = std::lround(delay * fps / 1000.0); - } - - for (int i = 0, j = (int)GetCount(), k = 0; i < j; i++) { - STSEntry& stse = GetAt(i); - - int t1 = (int)(RT2MS(TranslateStart(i, fps)) + delay); - if (t1 < 0) { - k++; - continue; - } - - int t2 = (int)(RT2MS(TranslateEnd(i, fps)) + delay); - - int hh1 = (t1 / 60 / 60 / 1000); - int mm1 = (t1 / 60 / 1000) % 60; - int ss1 = (t1 / 1000) % 60; - int ms1 = (t1) % 1000; - int hh2 = (t2 / 60 / 60 / 1000); - int mm2 = (t2 / 60 / 1000) % 60; - int ss2 = (t2 / 1000) % 60; - int ms2 = (t2) % 1000; - - CStringW str = f.IsUnicode() - ? GetStrW(i, type == Subtitle::SSA || type == Subtitle::ASS) - : GetStrWA(i, type == Subtitle::SSA || type == Subtitle::ASS); - - CStringW str2; - - if (type == Subtitle::SRT) { - str2.Format(fmt, i - k + 1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, str.GetString()); - } else if (type == Subtitle::SUB) { - str.Replace('\n', '|'); - str2.Format(fmt, int(t1 * fps / 1000), int(t2 * fps / 1000), str.GetString()); - } else if (type == Subtitle::SMI) { - str.Replace(L"\n", L"
"); - str2.Format(fmt, t1, str.GetString(), t2); - } else if (type == Subtitle::PSB) { - str.Replace('\n', '|'); - str2.Format(fmt, hh1, mm1, ss1, hh2, mm2, ss2, str.GetString()); - } else if (type == Subtitle::SSA) { - str.Replace(L"\n", L"\\N"); - str2.Format(fmt, - hh1, mm1, ss1, ms1 / 10, - hh2, mm2, ss2, ms2 / 10, - TToW(stse.style).GetString(), TToW(stse.actor).GetString(), - stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, - TToW(stse.effect).GetString(), str.GetString()); - } else if (type == Subtitle::ASS) { - str.Replace(L"\n", L"\\N"); - str2.Format(fmt, - stse.layer, - hh1, mm1, ss1, ms1 / 10, - hh2, mm2, ss2, ms2 / 10, - TToW(stse.style).GetString(), TToW(stse.actor).GetString(), - stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, - TToW(stse.effect).GetString(), str.GetString()); - } - - f.WriteString(str2); - } - - // Sort(); - - if (type == Subtitle::SMI) { - f.WriteString(_T("\n\n")); - } - - STSStyle* s; - if (bCreateExternalStyleFile && !m_bUsingPlayerDefaultStyle && m_styles.Lookup(_T("Default"), s) && type != Subtitle::SSA && type != Subtitle::ASS) { - CTextFile file; - if (!file.Save(fn + _T(".style"), e)) { - return false; - } - - CString str, str2; - - str += _T("ScriptType: v4.00+\n"); - str += _T("PlayResX: %d\n"); - str += _T("PlayResY: %d\n"); - str += _T("\n"); - str += _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"); - str2.Format(str, m_storageRes.cx, m_storageRes.cy); - file.WriteString(str2); - - str = _T("Style: Default,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f,%d,%d,%d,%d,%d\n"); - str2.Format(str, - s->fontName.GetString(), (int)s->fontSize, - (s->colors[0] & 0xffffff) | (s->alpha[0] << 24), - (s->colors[1] & 0xffffff) | (s->alpha[1] << 24), - (s->colors[2] & 0xffffff) | (s->alpha[2] << 24), - (s->colors[3] & 0xffffff) | (s->alpha[3] << 24), - s->fontWeight > FW_NORMAL ? -1 : 0, - s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, - s->fontScaleX, s->fontScaleY, - s->fontSpacing, s->fontAngleZ, - s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, - s->outlineWidthY, s->shadowDepthY, - s->scrAlignment, - s->marginRect.left, s->marginRect.right, (int)((s->marginRect.top + s->marginRect.bottom) / 2), - s->charSet); - file.WriteString(str2); - } - - m_provider = _T("Local"); - m_path = fn; - - return true; -} - -//////////////////////////////////////////////////////////////////// - -STSStyle::STSStyle() -{ - SetDefault(); -} - -void STSStyle::SetDefault() -{ - marginRect = CRect(20, 20, 20, 20); - scrAlignment = 2; - borderStyle = 0; - outlineWidthX = outlineWidthY = 2; - shadowDepthX = shadowDepthY = 3; - colors[0] = 0x00ffffff; - colors[1] = 0x0000ffff; - colors[2] = 0x00000000; - colors[3] = 0x00000000; - alpha[0] = 0x00; - alpha[1] = 0x00; - alpha[2] = 0x00; - alpha[3] = 0x80; - charSet = DEFAULT_CHARSET; - fontName = _T("Calibri"); - fontSize = 18; - fontScaleX = fontScaleY = 100; - fontSpacing = 0; - fontWeight = FW_BOLD; - fItalic = false; - fUnderline = false; - fStrikeOut = false; - fBlur = 0; - fGaussianBlur = 0; - fontShiftX = fontShiftY = fontAngleZ = fontAngleX = fontAngleY = 0; - relativeTo = STSStyle::AUTO; - hasAnsiStyleName = false; -#if USE_LIBASS - Kerning = false; - ScaledBorderAndShadow = false; - customTags = L""; -#endif -} - -bool STSStyle::operator == (const STSStyle& s) const -{ - return (marginRect == s.marginRect - && scrAlignment == s.scrAlignment - && borderStyle == s.borderStyle - && abs(outlineWidthX - s.outlineWidthX) < 0.00000001 - && abs(outlineWidthY - s.outlineWidthY) < 0.00000001 - && abs(shadowDepthX - s.shadowDepthX) < 0.00000001 - && abs(shadowDepthY - s.shadowDepthY) < 0.00000001 - && colors == s.colors - && alpha == s.alpha - && fBlur == s.fBlur - && abs(fGaussianBlur - s.fGaussianBlur) < 0.00000001 - && relativeTo == s.relativeTo - && IsFontStyleEqual(s)); -} - -bool STSStyle::IsFontStyleEqual(const STSStyle& s) const -{ - return ( - charSet == s.charSet - && fontName == s.fontName - && fontSize == s.fontSize - && abs(fontScaleX - s.fontScaleX) < 0.00000001 - && abs(fontScaleY - s.fontScaleY) < 0.00000001 - && abs(fontSpacing - s.fontSpacing) < 0.00000001 - && fontWeight == s.fontWeight - && fItalic == s.fItalic - && fUnderline == s.fUnderline - && fStrikeOut == s.fStrikeOut - && abs(fontAngleZ - s.fontAngleZ) < 0.00000001 - && abs(fontAngleX - s.fontAngleX) < 0.00000001 - && abs(fontAngleY - s.fontAngleY) < 0.00000001 - && abs(fontShiftX - s.fontShiftX) < 0.00000001 - && abs(fontShiftY - s.fontShiftY) < 0.00000001); -} - -STSStyle& STSStyle::operator = (LOGFONT& lf) -{ - charSet = lf.lfCharSet; - fontName = lf.lfFaceName; - HDC hDC = GetDC(nullptr); - fontSize = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY)); - ReleaseDC(nullptr, hDC); - // fontAngleZ = lf.lfEscapement/10.0; - fontWeight = lf.lfWeight; - fItalic = lf.lfItalic; - fUnderline = lf.lfUnderline; - fStrikeOut = lf.lfStrikeOut; - return *this; -} - -LOGFONTA& operator <<= (LOGFONTA& lfa, const STSStyle& s) -{ - lfa.lfCharSet = (BYTE)s.charSet; - strncpy_s(lfa.lfFaceName, LF_FACESIZE, CStringA(s.fontName), _TRUNCATE); - HDC hDC = GetDC(nullptr); - lfa.lfHeight = -MulDiv((int)(s.fontSize + 0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72); - ReleaseDC(nullptr, hDC); - lfa.lfWeight = s.fontWeight; - lfa.lfItalic = s.fItalic ? -1 : 0; - lfa.lfUnderline = s.fUnderline ? -1 : 0; - lfa.lfStrikeOut = s.fStrikeOut ? -1 : 0; - return lfa; -} - -LOGFONTW& operator <<= (LOGFONTW& lfw, const STSStyle& s) -{ - lfw.lfCharSet = (BYTE)s.charSet; - wcsncpy_s(lfw.lfFaceName, LF_FACESIZE, CStringW(s.fontName), _TRUNCATE); - HDC hDC = GetDC(nullptr); - lfw.lfHeight = -MulDiv((int)(s.fontSize + 0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72); - ReleaseDC(nullptr, hDC); - lfw.lfWeight = s.fontWeight; - lfw.lfItalic = s.fItalic ? -1 : 0; - lfw.lfUnderline = s.fUnderline ? -1 : 0; - lfw.lfStrikeOut = s.fStrikeOut ? -1 : 0; - return lfw; -} - -CString& operator <<= (CString& style, const STSStyle& s) -{ - style.Format(_T("%d;%d;%d;%d;%d;%d;%f;%f;%f;%f;0x%06lx;0x%06lx;0x%06lx;0x%06lx;0x%02x;0x%02x;0x%02x;0x%02x;%d;%s;%f;%f;%f;%f;%ld;%d;%d;%d;%d;%f;%f;%f;%f;%d"), - s.marginRect.left, s.marginRect.right, s.marginRect.top, s.marginRect.bottom, - s.scrAlignment, s.borderStyle, - s.outlineWidthX, s.outlineWidthY, s.shadowDepthX, s.shadowDepthY, - s.colors[0], s.colors[1], s.colors[2], s.colors[3], - s.alpha[0], s.alpha[1], s.alpha[2], s.alpha[3], - s.charSet, - s.fontName.GetString(), s.fontSize, - s.fontScaleX, s.fontScaleY, - s.fontSpacing, s.fontWeight, - s.fItalic, s.fUnderline, s.fStrikeOut, s.fBlur, s.fGaussianBlur, - s.fontAngleZ, s.fontAngleX, s.fontAngleY, - s.relativeTo); - - return style; -} - -STSStyle& operator <<= (STSStyle& s, const CString& style) -{ - s.SetDefault(); - - try { - CStringW str = TToW(style); - LPCWSTR pszBuff = str; - int nBuffLength = str.GetLength(); - if (str.Find(';') >= 0) { - s.marginRect.left = GetInt(pszBuff, nBuffLength, L';'); - s.marginRect.right = GetInt(pszBuff, nBuffLength, L';'); - s.marginRect.top = GetInt(pszBuff, nBuffLength, L';'); - s.marginRect.bottom = GetInt(pszBuff, nBuffLength, L';'); - s.scrAlignment = GetInt(pszBuff, nBuffLength, L';'); - s.borderStyle = GetInt(pszBuff, nBuffLength, L';'); - s.outlineWidthX = GetFloat(pszBuff, nBuffLength, L';'); - s.outlineWidthY = GetFloat(pszBuff, nBuffLength, L';'); - s.shadowDepthX = GetFloat(pszBuff, nBuffLength, L';'); - s.shadowDepthY = GetFloat(pszBuff, nBuffLength, L';'); - for (size_t i = 0; i < 4; i++) { - s.colors[i] = (COLORREF)GetInt(pszBuff, nBuffLength, L';'); - } - for (size_t i = 0; i < 4; i++) { - s.alpha[i] = (BYTE)GetInt(pszBuff, nBuffLength, L';'); - } - s.charSet = GetInt(pszBuff, nBuffLength, L';'); - s.fontName = WToT(GetStrW(pszBuff, nBuffLength, L';')); - s.fontSize = GetFloat(pszBuff, nBuffLength, L';'); - s.fontScaleX = GetFloat(pszBuff, nBuffLength, L';'); - s.fontScaleY = GetFloat(pszBuff, nBuffLength, L';'); - s.fontSpacing = GetFloat(pszBuff, nBuffLength, L';'); - s.fontWeight = GetInt(pszBuff, nBuffLength, L';'); - s.fItalic = GetInt(pszBuff, nBuffLength, L';'); - s.fUnderline = GetInt(pszBuff, nBuffLength, L';'); - s.fStrikeOut = GetInt(pszBuff, nBuffLength, L';'); - s.fBlur = GetInt(pszBuff, nBuffLength, L';'); - s.fGaussianBlur = GetFloat(pszBuff, nBuffLength, L';'); - s.fontAngleZ = GetFloat(pszBuff, nBuffLength, L';'); - s.fontAngleX = GetFloat(pszBuff, nBuffLength, L';'); - s.fontAngleY = GetFloat(pszBuff, nBuffLength, L';'); - s.relativeTo = (STSStyle::RelativeTo)GetInt(pszBuff, nBuffLength, L';'); - } - } catch (...) { - s.SetDefault(); - } - - return s; -} - -static bool OpenRealText(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet) -{ - std::wstring szFile; - CStringW buff; - - while (file->ReadString(buff)) { - FastTrim(buff); - if (buff.IsEmpty()) { - continue; - } - - // Make sure that the subtitle file starts with a tag - if (szFile.empty() && buff.CompareNoCase(_T("second.c_str()), - file->IsUnicode(), - MS2RT(i->first.first), - MS2RT(i->first.second)); - } - - return !ret.IsEmpty(); -} - -void CSTSStyleMap::Free() { - POSITION pos = GetStartPosition(); - while (pos) { - CString key; - STSStyle* val; - GetNextAssoc(pos, key, val); - delete val; - } - - RemoveAll(); -} + return false; +} + +bool CSimpleTextSubtitle::Open(CString provider, BYTE* data, int len, int CharSet, CString name, Subtitle::HearingImpairedType eHearingImpaired, LCID lcid) +{ + m_provider = provider; + m_eHearingImpaired = eHearingImpaired; + m_lcid = lcid; + + return Open(data, len, CharSet, name); +} + +bool CSimpleTextSubtitle::Open(BYTE* data, int len, int CharSet, CString name) +{ + TCHAR path[MAX_PATH]; + if (!GetTempPath(MAX_PATH, path)) { + return false; + } + + TCHAR fn[MAX_PATH]; + if (!GetTempFileName(path, _T("vs"), 0, fn)) { + return false; + } + + FILE* tmp = nullptr; + if (_tfopen_s(&tmp, fn, _T("wb"))) { + return false; + } + + int i = 0; + for (; i <= (len - 1024); i += 1024) { + fwrite(&data[i], 1024, 1, tmp); + } + if (len > i) { + fwrite(&data[i], len - i, 1, tmp); + } + + fclose(tmp); + + bool fRet = Open(fn, CharSet, name); + + _tremove(fn); + + m_path = _T(""); + + return fRet; +} + +bool CSimpleTextSubtitle::SaveAs(CString fn, Subtitle::SubType type, + double fps /*= -1*/, LONGLONG delay /*= 0*/, + CTextFile::enc e /*= CTextFile::DEFAULT_ENCODING*/, bool bCreateExternalStyleFile /*= true*/) +{ + LPCTSTR ext = Subtitle::GetSubtitleFileExt(type); + if (ext && fn.Mid(fn.ReverseFind('.') + 1).CompareNoCase(ext)) { + if (fn[fn.GetLength() - 1] != '.') { + fn += _T("."); + } + fn += ext; + } + + CTextFile f; + if (!f.Save(fn, e)) { + return false; + } + + if (type == Subtitle::SMI) { + CString str; + + str += _T("\n\n"); + str += _T("\n"); + str += _T("\n"); + str += _T("\n"); + str += _T("\n"); + + f.WriteString(str); + } else if (type == Subtitle::SSA || type == Subtitle::ASS) { + CString str; + + str = _T("[Script Info]\n"); + str += _T("; Note: This file was saved by MPC-HC.\n"); + str += (type == Subtitle::SSA) ? _T("ScriptType: v4.00\n") : _T("ScriptType: v4.00+\n"); + str += (m_collisions == 0) ? _T("Collisions: Normal\n") : _T("Collisions: Reverse\n"); + if (type == Subtitle::ASS && m_scaledBAS >= 0) { + if (m_scaledBAS == 1) { + str += _T("ScaledBorderAndShadow: yes\n"); + } else { + str += _T("ScaledBorderAndShadow: no\n"); + } + } + if (m_sYCbCrMatrix.IsEmpty()) { + str += _T("YCbCr Matrix: None\n"); + } else { + str += _T("YCbCr Matrix: ") + m_sYCbCrMatrix + _T("\n"); + } + str.AppendFormat(_T("PlayResX: %d\n"), m_playRes.cx); + str.AppendFormat(_T("PlayResY: %d\n"), m_playRes.cy); + if (m_layoutRes.cx > 0 && m_layoutRes.cy > 0) { + str.AppendFormat(_T("LayoutResX: %d\n"), m_layoutRes.cx); + str.AppendFormat(_T("LayoutResY: %d\n"), m_layoutRes.cy); + } + str += _T("Timer: 100.0000\n"); + str += _T("\n"); + str += (type == Subtitle::SSA) + ? _T("[V4 Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n") + : _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"); + + f.WriteString(str); + + str = (type == Subtitle::SSA) + ? _T("Style: %s,%s,%d,&H%06x,&H%06x,&H%06x,&H%06x,%d,%d,%d,%.2f,%.2f,%d,%d,%d,%d,%d,%d\n") + : _T("Style: %s,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f,%d,%d,%d,%d,%d\n"); + + POSITION pos = m_styles.GetStartPosition(); + while (pos) { + CString key; + STSStyle* s; + m_styles.GetNextAssoc(pos, key, s); + + if (type == Subtitle::SSA) { + CString str2; + str2.Format(str, key.GetString(), + s->fontName.GetString(), (int)s->fontSize, + s->colors[0] & 0xffffff, + s->colors[1] & 0xffffff, + s->colors[2] & 0xffffff, + s->colors[3] & 0xffffff, + s->fontWeight > FW_NORMAL ? -1 : 0, s->fItalic ? -1 : 0, + s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, + s->outlineWidthY, s->shadowDepthY, + s->scrAlignment <= 3 ? s->scrAlignment : s->scrAlignment <= 6 ? ((s->scrAlignment - 3) | 8) : s->scrAlignment <= 9 ? ((s->scrAlignment - 6) | 4) : 2, + s->marginRect.left, s->marginRect.right, (s->marginRect.top + s->marginRect.bottom) / 2, + s->alpha[0], + s->charSet); + f.WriteString(str2); + } else { + CString str2; + str2.Format(str, key.GetString(), + s->fontName.GetString(), (int)s->fontSize, + (s->colors[0] & 0xffffff) | (s->alpha[0] << 24), + (s->colors[1] & 0xffffff) | (s->alpha[1] << 24), + (s->colors[2] & 0xffffff) | (s->alpha[2] << 24), + (s->colors[3] & 0xffffff) | (s->alpha[3] << 24), + s->fontWeight > FW_NORMAL ? -1 : 0, + s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, + s->fontScaleX, s->fontScaleY, + s->fontSpacing, s->fontAngleZ, + s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, + s->outlineWidthY, s->shadowDepthY, + s->scrAlignment, + s->marginRect.left, s->marginRect.right, (int)((s->marginRect.top + s->marginRect.bottom) / 2), + s->charSet); + f.WriteString(str2); + } + } + + if (!IsEmpty()) { + str = _T("\n"); + str += _T("[Events]\n"); + str += (type == Subtitle::SSA) + ? _T("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n") + : _T("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n"); + f.WriteString(str); + } + } + + CStringW fmt = + type == Subtitle::SRT ? L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n" : + type == Subtitle::SUB ? L"{%d}{%d}%s\n" : + type == Subtitle::SMI ? L"

\n%s\n

 \n" : + type == Subtitle::PSB ? L"{%d:%02d:%02d}{%d:%02d:%02d}%s\n" : + type == Subtitle::SSA ? L"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" : + type == Subtitle::ASS ? L"Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s\n" : + L""; + // Sort(true); + + if (m_mode == FRAME) { + delay = std::lround(delay * fps / 1000.0); + } + + for (int i = 0, j = (int)GetCount(), k = 0; i < j; i++) { + STSEntry& stse = GetAt(i); + + int t1 = (int)(RT2MS(TranslateStart(i, fps)) + delay); + if (t1 < 0) { + k++; + continue; + } + + int t2 = (int)(RT2MS(TranslateEnd(i, fps)) + delay); + + int hh1 = (t1 / 60 / 60 / 1000); + int mm1 = (t1 / 60 / 1000) % 60; + int ss1 = (t1 / 1000) % 60; + int ms1 = (t1) % 1000; + int hh2 = (t2 / 60 / 60 / 1000); + int mm2 = (t2 / 60 / 1000) % 60; + int ss2 = (t2 / 1000) % 60; + int ms2 = (t2) % 1000; + + CStringW str = f.IsUnicode() + ? GetStrW(i, type == Subtitle::SSA || type == Subtitle::ASS) + : GetStrWA(i, type == Subtitle::SSA || type == Subtitle::ASS); + + CStringW str2; + + if (type == Subtitle::SRT) { + str2.Format(fmt, i - k + 1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, str.GetString()); + } else if (type == Subtitle::SUB) { + str.Replace('\n', '|'); + str2.Format(fmt, int(t1 * fps / 1000), int(t2 * fps / 1000), str.GetString()); + } else if (type == Subtitle::SMI) { + str.Replace(L"\n", L"
"); + str2.Format(fmt, t1, str.GetString(), t2); + } else if (type == Subtitle::PSB) { + str.Replace('\n', '|'); + str2.Format(fmt, hh1, mm1, ss1, hh2, mm2, ss2, str.GetString()); + } else if (type == Subtitle::SSA) { + str.Replace(L"\n", L"\\N"); + str2.Format(fmt, + hh1, mm1, ss1, ms1 / 10, + hh2, mm2, ss2, ms2 / 10, + TToW(stse.style).GetString(), TToW(stse.actor).GetString(), + stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, + TToW(stse.effect).GetString(), str.GetString()); + } else if (type == Subtitle::ASS) { + str.Replace(L"\n", L"\\N"); + str2.Format(fmt, + stse.layer, + hh1, mm1, ss1, ms1 / 10, + hh2, mm2, ss2, ms2 / 10, + TToW(stse.style).GetString(), TToW(stse.actor).GetString(), + stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, + TToW(stse.effect).GetString(), str.GetString()); + } + + f.WriteString(str2); + } + + // Sort(); + + if (type == Subtitle::SMI) { + f.WriteString(_T("\n\n")); + } + + STSStyle* s; + if (bCreateExternalStyleFile && !m_bUsingPlayerDefaultStyle && m_styles.Lookup(_T("Default"), s) && type != Subtitle::SSA && type != Subtitle::ASS) { + CTextFile file; + if (!file.Save(fn + _T(".style"), e)) { + return false; + } + + CString str, str2; + + str += _T("ScriptType: v4.00+\n"); + str += _T("PlayResX: %d\n"); + str += _T("PlayResY: %d\n"); + str += _T("\n"); + str += _T("[V4+ Styles]\nFormat: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"); + str2.Format(str, m_storageRes.cx, m_storageRes.cy); + file.WriteString(str2); + + str = _T("Style: Default,%s,%d,&H%08x,&H%08x,&H%08x,&H%08x,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%.2f,%.2f,%d,%d,%d,%d,%d\n"); + str2.Format(str, + s->fontName.GetString(), (int)s->fontSize, + (s->colors[0] & 0xffffff) | (s->alpha[0] << 24), + (s->colors[1] & 0xffffff) | (s->alpha[1] << 24), + (s->colors[2] & 0xffffff) | (s->alpha[2] << 24), + (s->colors[3] & 0xffffff) | (s->alpha[3] << 24), + s->fontWeight > FW_NORMAL ? -1 : 0, + s->fItalic ? -1 : 0, s->fUnderline ? -1 : 0, s->fStrikeOut ? -1 : 0, + s->fontScaleX, s->fontScaleY, + s->fontSpacing, s->fontAngleZ, + s->borderStyle == 0 ? 1 : s->borderStyle == 1 ? 3 : 0, + s->outlineWidthY, s->shadowDepthY, + s->scrAlignment, + s->marginRect.left, s->marginRect.right, (int)((s->marginRect.top + s->marginRect.bottom) / 2), + s->charSet); + file.WriteString(str2); + } + + m_provider = _T("Local"); + m_path = fn; + + return true; +} + +//////////////////////////////////////////////////////////////////// + +STSStyle::STSStyle() +{ + SetDefault(); +} + +void STSStyle::SetDefault() +{ + marginRect = CRect(20, 20, 20, 20); + scrAlignment = 2; + borderStyle = 0; + outlineWidthX = outlineWidthY = 2; + shadowDepthX = shadowDepthY = 3; + colors[0] = 0x00ffffff; + colors[1] = 0x0000ffff; + colors[2] = 0x00000000; + colors[3] = 0x00000000; + alpha[0] = 0x00; + alpha[1] = 0x00; + alpha[2] = 0x00; + alpha[3] = 0x80; + charSet = DEFAULT_CHARSET; + fontName = _T("Calibri"); + fontSize = 18; + fontScaleX = fontScaleY = 100; + fontSpacing = 0; + fontWeight = FW_BOLD; + fItalic = false; + fUnderline = false; + fStrikeOut = false; + fBlur = 0; + fGaussianBlur = 0; + fontShiftX = fontShiftY = fontAngleZ = fontAngleX = fontAngleY = 0; + relativeTo = STSStyle::AUTO; + hasAnsiStyleName = false; +#if USE_LIBASS + Kerning = false; + ScaledBorderAndShadow = false; + customTags = L""; +#endif +} + +bool STSStyle::operator == (const STSStyle& s) const +{ + return (marginRect == s.marginRect + && scrAlignment == s.scrAlignment + && borderStyle == s.borderStyle + && abs(outlineWidthX - s.outlineWidthX) < 0.00000001 + && abs(outlineWidthY - s.outlineWidthY) < 0.00000001 + && abs(shadowDepthX - s.shadowDepthX) < 0.00000001 + && abs(shadowDepthY - s.shadowDepthY) < 0.00000001 + && colors == s.colors + && alpha == s.alpha + && fBlur == s.fBlur + && abs(fGaussianBlur - s.fGaussianBlur) < 0.00000001 + && relativeTo == s.relativeTo + && IsFontStyleEqual(s)); +} + +bool STSStyle::IsFontStyleEqual(const STSStyle& s) const +{ + return ( + charSet == s.charSet + && fontName == s.fontName + && fontSize == s.fontSize + && abs(fontScaleX - s.fontScaleX) < 0.00000001 + && abs(fontScaleY - s.fontScaleY) < 0.00000001 + && abs(fontSpacing - s.fontSpacing) < 0.00000001 + && fontWeight == s.fontWeight + && fItalic == s.fItalic + && fUnderline == s.fUnderline + && fStrikeOut == s.fStrikeOut + && abs(fontAngleZ - s.fontAngleZ) < 0.00000001 + && abs(fontAngleX - s.fontAngleX) < 0.00000001 + && abs(fontAngleY - s.fontAngleY) < 0.00000001 + && abs(fontShiftX - s.fontShiftX) < 0.00000001 + && abs(fontShiftY - s.fontShiftY) < 0.00000001); +} + +STSStyle& STSStyle::operator = (LOGFONT& lf) +{ + charSet = lf.lfCharSet; + fontName = lf.lfFaceName; + HDC hDC = GetDC(nullptr); + fontSize = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY)); + ReleaseDC(nullptr, hDC); + // fontAngleZ = lf.lfEscapement/10.0; + fontWeight = lf.lfWeight; + fItalic = lf.lfItalic; + fUnderline = lf.lfUnderline; + fStrikeOut = lf.lfStrikeOut; + return *this; +} + +LOGFONTA& operator <<= (LOGFONTA& lfa, const STSStyle& s) +{ + lfa.lfCharSet = (BYTE)s.charSet; + strncpy_s(lfa.lfFaceName, LF_FACESIZE, CStringA(s.fontName), _TRUNCATE); + HDC hDC = GetDC(nullptr); + lfa.lfHeight = -MulDiv((int)(s.fontSize + 0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72); + ReleaseDC(nullptr, hDC); + lfa.lfWeight = s.fontWeight; + lfa.lfItalic = s.fItalic ? -1 : 0; + lfa.lfUnderline = s.fUnderline ? -1 : 0; + lfa.lfStrikeOut = s.fStrikeOut ? -1 : 0; + return lfa; +} + +LOGFONTW& operator <<= (LOGFONTW& lfw, const STSStyle& s) +{ + lfw.lfCharSet = (BYTE)s.charSet; + wcsncpy_s(lfw.lfFaceName, LF_FACESIZE, CStringW(s.fontName), _TRUNCATE); + HDC hDC = GetDC(nullptr); + lfw.lfHeight = -MulDiv((int)(s.fontSize + 0.5), GetDeviceCaps(hDC, LOGPIXELSY), 72); + ReleaseDC(nullptr, hDC); + lfw.lfWeight = s.fontWeight; + lfw.lfItalic = s.fItalic ? -1 : 0; + lfw.lfUnderline = s.fUnderline ? -1 : 0; + lfw.lfStrikeOut = s.fStrikeOut ? -1 : 0; + return lfw; +} + +CString& operator <<= (CString& style, const STSStyle& s) +{ + style.Format(_T("%d;%d;%d;%d;%d;%d;%f;%f;%f;%f;0x%06lx;0x%06lx;0x%06lx;0x%06lx;0x%02x;0x%02x;0x%02x;0x%02x;%d;%s;%f;%f;%f;%f;%ld;%d;%d;%d;%d;%f;%f;%f;%f;%d"), + s.marginRect.left, s.marginRect.right, s.marginRect.top, s.marginRect.bottom, + s.scrAlignment, s.borderStyle, + s.outlineWidthX, s.outlineWidthY, s.shadowDepthX, s.shadowDepthY, + s.colors[0], s.colors[1], s.colors[2], s.colors[3], + s.alpha[0], s.alpha[1], s.alpha[2], s.alpha[3], + s.charSet, + s.fontName.GetString(), s.fontSize, + s.fontScaleX, s.fontScaleY, + s.fontSpacing, s.fontWeight, + s.fItalic, s.fUnderline, s.fStrikeOut, s.fBlur, s.fGaussianBlur, + s.fontAngleZ, s.fontAngleX, s.fontAngleY, + s.relativeTo); + + return style; +} + +STSStyle& operator <<= (STSStyle& s, const CString& style) +{ + s.SetDefault(); + + try { + CStringW str = TToW(style); + LPCWSTR pszBuff = str; + int nBuffLength = str.GetLength(); + if (str.Find(';') >= 0) { + s.marginRect.left = GetInt(pszBuff, nBuffLength, L';'); + s.marginRect.right = GetInt(pszBuff, nBuffLength, L';'); + s.marginRect.top = GetInt(pszBuff, nBuffLength, L';'); + s.marginRect.bottom = GetInt(pszBuff, nBuffLength, L';'); + s.scrAlignment = GetInt(pszBuff, nBuffLength, L';'); + s.borderStyle = GetInt(pszBuff, nBuffLength, L';'); + s.outlineWidthX = GetFloat(pszBuff, nBuffLength, L';'); + s.outlineWidthY = GetFloat(pszBuff, nBuffLength, L';'); + s.shadowDepthX = GetFloat(pszBuff, nBuffLength, L';'); + s.shadowDepthY = GetFloat(pszBuff, nBuffLength, L';'); + for (size_t i = 0; i < 4; i++) { + s.colors[i] = (COLORREF)GetInt(pszBuff, nBuffLength, L';'); + } + for (size_t i = 0; i < 4; i++) { + s.alpha[i] = (BYTE)GetInt(pszBuff, nBuffLength, L';'); + } + s.charSet = GetInt(pszBuff, nBuffLength, L';'); + s.fontName = WToT(GetStrW(pszBuff, nBuffLength, L';')); + s.fontSize = GetFloat(pszBuff, nBuffLength, L';'); + s.fontScaleX = GetFloat(pszBuff, nBuffLength, L';'); + s.fontScaleY = GetFloat(pszBuff, nBuffLength, L';'); + s.fontSpacing = GetFloat(pszBuff, nBuffLength, L';'); + s.fontWeight = GetInt(pszBuff, nBuffLength, L';'); + s.fItalic = GetInt(pszBuff, nBuffLength, L';'); + s.fUnderline = GetInt(pszBuff, nBuffLength, L';'); + s.fStrikeOut = GetInt(pszBuff, nBuffLength, L';'); + s.fBlur = GetInt(pszBuff, nBuffLength, L';'); + s.fGaussianBlur = GetFloat(pszBuff, nBuffLength, L';'); + s.fontAngleZ = GetFloat(pszBuff, nBuffLength, L';'); + s.fontAngleX = GetFloat(pszBuff, nBuffLength, L';'); + s.fontAngleY = GetFloat(pszBuff, nBuffLength, L';'); + s.relativeTo = (STSStyle::RelativeTo)GetInt(pszBuff, nBuffLength, L';'); + } + } catch (...) { + s.SetDefault(); + } + + return s; +} + +static bool OpenRealText(CTextFile* file, CSimpleTextSubtitle& ret, int CharSet) +{ + std::wstring szFile; + CStringW buff; + + while (file->ReadString(buff)) { + FastTrim(buff); + if (buff.IsEmpty()) { + continue; + } + + // Make sure that the subtitle file starts with a tag + if (szFile.empty() && buff.CompareNoCase(_T("second.c_str()), + file->IsUnicode(), + MS2RT(i->first.first), + MS2RT(i->first.second)); + } + + return !ret.IsEmpty(); +} + +void CSTSStyleMap::Free() { + POSITION pos = GetStartPosition(); + while (pos) { + CString key; + STSStyle* val; + GetNextAssoc(pos, key, val); + delete val; + } + + RemoveAll(); +} diff --git a/src/Subtitles/STS.h b/src/Subtitles/STS.h index 7d836483ae3..78e0a8e2e32 100644 --- a/src/Subtitles/STS.h +++ b/src/Subtitles/STS.h @@ -1,205 +1,205 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include -#include -#include "TextFile.h" -#include "SubtitleHelpers.h" +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include +#include +#include "TextFile.h" +#include "SubtitleHelpers.h" #include "../../include/mpc-hc_config.h" #include "LibassContext.h" -#include "SubRendererSettings.h" +#include "SubRendererSettings.h" #include "OpenTypeLangTags.h" -#include "STSStyle.h" - -enum tmode { TIME, FRAME }; // the meaning of STSEntry::start/end - -struct STSEntry { - CStringW str; - bool fUnicode; - CString style, actor, effect; - CRect marginRect; - int layer; - REFERENCE_TIME start, end; - int readorder; -}; - -class STSSegment -{ -public: - REFERENCE_TIME start, end; - CAtlArray subs; - - STSSegment() - : start(0) - , end(0) {} - STSSegment(REFERENCE_TIME s, REFERENCE_TIME e) { - start = s; - end = e; - } - STSSegment(const STSSegment& stss) { - *this = stss; - } - STSSegment& operator = (const STSSegment& stss) { - if (this != &stss) { - start = stss.start; - end = stss.end; - subs.Copy(stss.subs); - } - return *this; - } -}; - -class CSimpleTextSubtitle : public CAtlArray -{ - friend class CSubtitleEditorDlg; - friend class SubtitlesProvider; - -protected: - CAtlArray m_segments; - virtual void OnChanged() {} - -public: - SubRendererSettings m_SubRendererSettings; - - CString m_name; - LCID m_lcid; - CString m_langname; - CStringA openTypeLangHint; - Subtitle::SubType m_subtitleType; - tmode m_mode; - CTextFile::enc m_encoding; - CString m_path; - - CString m_provider; - - Subtitle::HearingImpairedType m_eHearingImpaired; - - CSize m_storageRes; - CSize m_playRes; - CSize m_layoutRes; - - int m_defaultWrapStyle; - int m_collisions; - int m_scaledBAS; // -1 = unknown, 0 = no, 1 = yes - CString m_sYCbCrMatrix; - - bool m_bStyleOverrideActive; - STSStyle m_originalDefaultStyle; - bool m_bUsingPlayerDefaultStyle; - uint32_t event_param; - - CSTSStyleMap m_styles; - int overrideANSICharset; - - enum EPARCompensationType { - EPCTDisabled, - EPCTDownscale, - EPCTUpscale, - EPCTAccurateSize, - EPCTAccurateSize_ISR - }; - - EPARCompensationType m_ePARCompensationType; - double m_dPARCompensation; - -public: - CSimpleTextSubtitle(); - virtual ~CSimpleTextSubtitle(); - - virtual void Copy(CSimpleTextSubtitle& sts); - virtual void Empty(); - - void Sort(bool fRestoreReadorder = false); - void CreateSegments(); - void FlushEventsLibass(); - - void Append(CSimpleTextSubtitle& sts, REFERENCE_TIME timeoff = -1); - - bool Open(CString fn, int CharSet, CString name = _T(""), CString videoName = _T("")); - bool Open(CTextFile* f, int CharSet, CString name); - bool Open(BYTE* data, int length, int CharSet, CString provider, CString lang, CString ext = _T("")); - bool Open(CString data, CTextFile::enc SaveCharSet, int ReadCharSet, CString provider, CString lang, CString ext = _T("")); - bool Open(BYTE* data, int len, int CharSet, CString name); - bool Open(CString provider, BYTE* data, int len, int CharSet, CString name, Subtitle::HearingImpairedType eHearingImpaired, LCID lcid); - bool SaveAs(CString fn, Subtitle::SubType type, double fps = -1, LONGLONG delay = 0, CTextFile::enc e = CTextFile::DEFAULT_ENCODING, bool bCreateExternalStyleFile = true); - - void Add(CStringW str, bool fUnicode, REFERENCE_TIME start, REFERENCE_TIME end, CString style = _T("Default"), CString actor = _T(""), CString effect = _T(""), const CRect& marginRect = CRect(0, 0, 0, 0), int layer = 0, int readorder = -1); - STSStyle* CreateDefaultStyle(int CharSet); - STSStyle GetOriginalDefaultStyle(); - void ChangeUnknownStylesToDefault(); - void AddStyle(CString name, STSStyle* style); // style will be stored and freed in Empty() later - bool CopyToStyles(CSTSStyleMap& styles); - bool CopyStyles(const CSTSStyleMap& styles, bool fAppend = false); - - bool SetDefaultStyle(const STSStyle& s); - void SetStyleChanged(); - bool GetDefaultStyle(STSStyle& s) const; - - void ConvertToTimeBased(double fps); - void ConvertToFrameBased(double fps); - - REFERENCE_TIME TranslateStart(int i, double fps); - REFERENCE_TIME TranslateEnd(int i, double fps); - int SearchSub(REFERENCE_TIME t, double fps); - - REFERENCE_TIME TranslateSegmentStart(int i, double fps); - REFERENCE_TIME TranslateSegmentEnd(int i, double fps); - const STSSegment* SearchSubs(REFERENCE_TIME t, double fps, /*[out]*/ int* iSegment = nullptr, int* nSegments = nullptr); - const STSSegment* GetSegment(int iSegment) { - return iSegment >= 0 && iSegment < (int)m_segments.GetCount() ? &m_segments[iSegment] : nullptr; - } - - STSStyle* GetStyle(int i); - static void UpdateSubRelativeTo(Subtitle::SubType type, STSStyle::RelativeTo& relativeTo); - bool GetStyle(int i, STSStyle& stss); - bool GetStyle(CString styleName, STSStyle& stss); - int GetCharSet(int charSet); - int GetStyleCharSet(int i); - bool IsEntryUnicode(int i); - void ConvertUnicode(int i, bool fUnicode); - - CStringA GetStrA(int i, bool fSSA = false); - CStringW GetStrW(int i, bool fSSA = false); - CStringW GetStrWA(int i, bool fSSA = false); - - void SetStr(int i, CStringA str, bool fUnicode /* ignored */); - void SetStr(int i, CStringW str, bool fUnicode); - void SetOpenTypeLangHint(CStringA openTypeLangHint) { this->openTypeLangHint = openTypeLangHint; } +#include "STSStyle.h" + +enum tmode { TIME, FRAME }; // the meaning of STSEntry::start/end + +struct STSEntry { + CStringW str; + bool fUnicode; + CString style, actor, effect; + CRect marginRect; + int layer; + REFERENCE_TIME start, end; + int readorder; +}; + +class STSSegment +{ +public: + REFERENCE_TIME start, end; + CAtlArray subs; + + STSSegment() + : start(0) + , end(0) {} + STSSegment(REFERENCE_TIME s, REFERENCE_TIME e) { + start = s; + end = e; + } + STSSegment(const STSSegment& stss) { + *this = stss; + } + STSSegment& operator = (const STSSegment& stss) { + if (this != &stss) { + start = stss.start; + end = stss.end; + subs.Copy(stss.subs); + } + return *this; + } +}; + +class CSimpleTextSubtitle : public CAtlArray +{ + friend class CSubtitleEditorDlg; + friend class SubtitlesProvider; + +protected: + CAtlArray m_segments; + virtual void OnChanged() {} + +public: + SubRendererSettings m_SubRendererSettings; + + CString m_name; + LCID m_lcid; + CString m_langname; + CStringA openTypeLangHint; + Subtitle::SubType m_subtitleType; + tmode m_mode; + CTextFile::enc m_encoding; + CString m_path; + + CString m_provider; + + Subtitle::HearingImpairedType m_eHearingImpaired; + + CSize m_storageRes; + CSize m_playRes; + CSize m_layoutRes; + + int m_defaultWrapStyle; + int m_collisions; + int m_scaledBAS; // -1 = unknown, 0 = no, 1 = yes + CString m_sYCbCrMatrix; + + bool m_bStyleOverrideActive; + STSStyle m_originalDefaultStyle; + bool m_bUsingPlayerDefaultStyle; + uint32_t event_param; + + CSTSStyleMap m_styles; + int overrideANSICharset; + + enum EPARCompensationType { + EPCTDisabled, + EPCTDownscale, + EPCTUpscale, + EPCTAccurateSize, + EPCTAccurateSize_ISR + }; + + EPARCompensationType m_ePARCompensationType; + double m_dPARCompensation; + +public: + CSimpleTextSubtitle(); + virtual ~CSimpleTextSubtitle(); + + virtual void Copy(CSimpleTextSubtitle& sts); + virtual void Empty(); + + void Sort(bool fRestoreReadorder = false); + void CreateSegments(); + void FlushEventsLibass(); + + void Append(CSimpleTextSubtitle& sts, REFERENCE_TIME timeoff = -1); + + bool Open(CString fn, int CharSet, CString name = _T(""), CString videoName = _T("")); + bool Open(CTextFile* f, int CharSet, CString name); + bool Open(BYTE* data, int length, int CharSet, CString provider, CString lang, CString ext = _T("")); + bool Open(CString data, CTextFile::enc SaveCharSet, int ReadCharSet, CString provider, CString lang, CString ext = _T("")); + bool Open(BYTE* data, int len, int CharSet, CString name); + bool Open(CString provider, BYTE* data, int len, int CharSet, CString name, Subtitle::HearingImpairedType eHearingImpaired, LCID lcid); + bool SaveAs(CString fn, Subtitle::SubType type, double fps = -1, LONGLONG delay = 0, CTextFile::enc e = CTextFile::DEFAULT_ENCODING, bool bCreateExternalStyleFile = true); + + void Add(CStringW str, bool fUnicode, REFERENCE_TIME start, REFERENCE_TIME end, CString style = _T("Default"), CString actor = _T(""), CString effect = _T(""), const CRect& marginRect = CRect(0, 0, 0, 0), int layer = 0, int readorder = -1); + STSStyle* CreateDefaultStyle(int CharSet); + STSStyle GetOriginalDefaultStyle(); + void ChangeUnknownStylesToDefault(); + void AddStyle(CString name, STSStyle* style); // style will be stored and freed in Empty() later + bool CopyToStyles(CSTSStyleMap& styles); + bool CopyStyles(const CSTSStyleMap& styles, bool fAppend = false); + + bool SetDefaultStyle(const STSStyle& s); + void SetStyleChanged(); + bool GetDefaultStyle(STSStyle& s) const; + + void ConvertToTimeBased(double fps); + void ConvertToFrameBased(double fps); + + REFERENCE_TIME TranslateStart(int i, double fps); + REFERENCE_TIME TranslateEnd(int i, double fps); + int SearchSub(REFERENCE_TIME t, double fps); + + REFERENCE_TIME TranslateSegmentStart(int i, double fps); + REFERENCE_TIME TranslateSegmentEnd(int i, double fps); + const STSSegment* SearchSubs(REFERENCE_TIME t, double fps, /*[out]*/ int* iSegment = nullptr, int* nSegments = nullptr); + const STSSegment* GetSegment(int iSegment) { + return iSegment >= 0 && iSegment < (int)m_segments.GetCount() ? &m_segments[iSegment] : nullptr; + } + + STSStyle* GetStyle(int i); + static void UpdateSubRelativeTo(Subtitle::SubType type, STSStyle::RelativeTo& relativeTo); + bool GetStyle(int i, STSStyle& stss); + bool GetStyle(CString styleName, STSStyle& stss); + int GetCharSet(int charSet); + int GetStyleCharSet(int i); + bool IsEntryUnicode(int i); + void ConvertUnicode(int i, bool fUnicode); + + CStringA GetStrA(int i, bool fSSA = false); + CStringW GetStrW(int i, bool fSSA = false); + CStringW GetStrWA(int i, bool fSSA = false); + + void SetStr(int i, CStringA str, bool fUnicode /* ignored */); + void SetStr(int i, CStringW str, bool fUnicode); + void SetOpenTypeLangHint(CStringA openTypeLangHint) { this->openTypeLangHint = openTypeLangHint; } public: #if USE_LIBASS LibassContext m_LibassContext; #endif -}; - -extern const BYTE CharSetList[]; -extern const TCHAR* CharSetNames[]; -extern const int CharSetLen; - -class CHtmlColorMap : public CAtlMap> -{ -public: - CHtmlColorMap(); -}; - -extern const CHtmlColorMap g_colors; +}; + +extern const BYTE CharSetList[]; +extern const TCHAR* CharSetNames[]; +extern const int CharSetLen; + +class CHtmlColorMap : public CAtlMap> +{ +public: + CHtmlColorMap(); +}; + +extern const CHtmlColorMap g_colors; diff --git a/src/Subtitles/SeparableFilter.h b/src/Subtitles/SeparableFilter.h index cd38f99ae54..206112f23e9 100644 --- a/src/Subtitles/SeparableFilter.h +++ b/src/Subtitles/SeparableFilter.h @@ -1,374 +1,374 @@ -/* -* (C) 2007 Niels Martin Hansen -* (C) 2013-2017 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 . -* -*/ - -#pragma once - -#include - -#define LIBDIVIDE_USE_SSE2 1 -#pragma warning(push) -#pragma warning(disable: 4244 4456 4702) -#include "libdivide.h" -#pragma warning(pop) - -// Filter an image in horizontal direction with a one-dimensional filter -// PixelWidth is the distance in bytes between pixels -template -void SeparableFilterX(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, - short* kernel, int kernel_size, int divisor) -{ - int* tmp = DEBUG_NEW int[width]; - - for (int y = 0; y < height; y++) { - ZeroMemory(tmp, width * sizeof(int)); - - const unsigned char* in = src + y * stride; - unsigned char* out = dst + y * stride; - - for (int k = 0; k < kernel_size; k++) { - int xOffset = k - kernel_size / 2; - int xStart = 0; - int xEnd = width; - if (xOffset < 0) { - xEnd += xOffset; - } else if (xOffset > 0) { - xStart += xOffset; - } - for (int x = xStart; x < xEnd; x++) { - tmp[x - xOffset] += (int)(in[x * PixelDist] * kernel[k]); - } - } - for (int x = 0; x < width; x++) { - int accum = tmp[x] / divisor; - if (accum > 255) { - accum = 255; - } else if (accum < 0) { - accum = 0; - } - out[x * PixelDist] = (unsigned char)accum; - } - } - - delete [] tmp; -} - - -// Filter an image in vertical direction with a one-dimensional filter -// PixelWidth is the distance in bytes between pixels -template -void SeparableFilterY(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, - short* kernel, int kernel_size, int divisor) -{ - int* tmp = DEBUG_NEW int[width]; - - for (int y = 0; y < height; y++) { - ZeroMemory(tmp, width * sizeof(int)); - - const unsigned char* in = src + y * stride; - unsigned char* out = dst + y * stride; - - int kOffset = kernel_size / 2; - int kStart = 0; - int kEnd = kernel_size; - if (y < kOffset) { // 0 > y - kOffset - kStart += kOffset - y; - } else if (height <= y + kOffset) { - kEnd -= kOffset + y + 1 - height; - } - for (int k = kStart; k < kEnd; k++) { - for (int x = 0; x < width; x++) { - tmp[x] += (int)(in[(k - kOffset) * stride + x * PixelDist] * kernel[k]); - } - } - for (int x = 0; x < width; x++) { - int accum = tmp[x] / divisor; - if (accum > 255) { - accum = 255; - } else if (accum < 0) { - accum = 0; - } - out[x * PixelDist] = (unsigned char)accum; - } - } - - delete [] tmp; -} - - -// Filter an image in horizontal direction with a one-dimensional filter -void SeparableFilterX_SSE2(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, - short* kernel, int kernel_size, int divisor) -{ - int width16 = width & ~15; - int* tmp = (int*)_aligned_malloc(stride * sizeof(int), 16); - libdivide::divider divisorLibdivide(divisor); - - for (int y = 0; y < height; y++) { - ZeroMemory(tmp, stride * sizeof(int)); - - const unsigned char* in = src + y * stride; - unsigned char* out = dst + y * stride; - - for (int k = 0; k < kernel_size; k++) { - int xOffset = k - kernel_size / 2; - int xStart = 0; - int xEnd = width; - if (xOffset < 0) { - xEnd += xOffset; - } else if (xOffset > 0) { - xStart += xOffset; - } - int xStart16 = (xStart + 15) & ~15; - int xEnd16 = xEnd & ~15; - if (xStart16 >= xEnd16) { // Don't use SSE2 at all - xStart16 = xEnd16 = xEnd; - } - for (int x = xStart; x < xStart16; x++) { - tmp[x - xOffset] += (int)(in[x] * kernel[k]); - } - __m128i coeff = _mm_set1_epi16(kernel[k]); - for (int x = xStart16; x < xEnd16; x += 16) { - // Load 16 values - __m128i data16 = _mm_load_si128((__m128i*)&in[x]); - - // Multiply the first 8 values by the coefficient to get 8 32-bit integers - __m128i data8 = _mm_unpacklo_epi8(data16, _mm_setzero_si128()); - __m128i resLo = _mm_mullo_epi16(data8, coeff); - __m128i resHi = _mm_mulhi_epi16(data8, coeff); - __m128i res32bitLo = _mm_unpacklo_epi16(resLo, resHi); - __m128i res32bitHi = _mm_unpackhi_epi16(resLo, resHi); - - // Load the 4 32-bit integers values, add the values we computed and store them back - __m128i res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset]); - res = _mm_add_epi32(res, res32bitLo); - _mm_storeu_si128((__m128i*)&tmp[x - xOffset], res); - // Repeat the same operation for the next 4 values - res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 4]); - res = _mm_add_epi32(res, res32bitHi); - _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 4], res); - - // Multiply the next 8 values by the coefficient to get 8 32-bit integers - data8 = _mm_unpackhi_epi8(data16, _mm_setzero_si128()); - resLo = _mm_mullo_epi16(data8, coeff); - resHi = _mm_mulhi_epi16(data8, coeff); - res32bitLo = _mm_unpacklo_epi16(resLo, resHi); - res32bitHi = _mm_unpackhi_epi16(resLo, resHi); - - // Load the 4 32-bit integers values, add the values we computed and store them back - res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 8]); - res = _mm_add_epi32(res, res32bitLo); - _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 8], res); - // Repeat the same operation for the next 4 values - res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 12]); - res = _mm_add_epi32(res, res32bitHi); - _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 12], res); - } - for (int x = xEnd16; x < xEnd; x++) { - tmp[x - xOffset] += (int)(in[x] * kernel[k]); - } - } - for (int x = 0; x < width16; x += 16) { - // Load 4 32-bit integer values and divide them - __m128i accum1 = _mm_load_si128((__m128i*)&tmp[x]); - accum1 = accum1 / divisorLibdivide; - // Repeat the same operation on the next 4 32-bit integer values - __m128i accum2 = _mm_load_si128((__m128i*)&tmp[x + 4]); - accum2 = accum2 / divisorLibdivide; - // Pack the 8 32-bit integers into 8 16-bit integers - accum1 = _mm_packs_epi32(accum1, accum2); - - // Load 4 32-bit integer values and divide them - __m128i accum3 = _mm_load_si128((__m128i*)&tmp[x + 8]); - accum3 = accum3 / divisorLibdivide; - // Repeat the same operation on the next 4 32-bit integer values - __m128i accum4 = _mm_load_si128((__m128i*)&tmp[x + 12]); - accum4 = accum4 / divisorLibdivide; - // Pack the 8 32-bit integers into 8 16-bit integers - accum3 = _mm_packs_epi32(accum3, accum4); - - // Pack the 16 16-bit integers into 16 8-bit unsigned integers - accum1 = _mm_packus_epi16(accum1, accum3); - - // Store the 16 8-bit unsigned integers - _mm_store_si128((__m128i*)&out[x], accum1); - } - for (int x = width16; x < width; x++) { - int accum = tmp[x] / divisor; - if (accum > 255) { - accum = 255; - } else if (accum < 0) { - accum = 0; - } - out[x] = (unsigned char)accum; - } - } - - _aligned_free(tmp); -} - - -// Filter an image in vertical direction with a one-dimensional filter -void SeparableFilterY_SSE2(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, - short* kernel, int kernel_size, int divisor) -{ - int width16 = width & ~15; - int* tmp = (int*)_aligned_malloc(stride * sizeof(int), 16); - libdivide::divider divisorLibdivide(divisor); - -#ifdef _OPENMP - #pragma omp parallel for -#endif - for (int y = 0; y < height; y++) { - ZeroMemory(tmp, stride * sizeof(int)); - - const unsigned char* in = src + y * stride; - unsigned char* out = dst + y * stride; - - int kOffset = kernel_size / 2; - int kStart = 0; - int kEnd = kernel_size; - if (y < kOffset) { // 0 > y - kOffset - kStart += kOffset - y; - } else if (height <= y + kOffset) { - kEnd -= kOffset + y + 1 - height; - } - for (int k = kStart; k < kEnd; k++) { - __m128i coeff = _mm_set1_epi16(kernel[k]); - for (int x = 0; x < width16; x += 16) { - // Load 16 values - __m128i data16 = _mm_load_si128((__m128i*)&in[(k - kOffset) * stride + x]); - - // Multiply the first 8 values by the coefficient to get 8 32-bit integers - __m128i data8 = _mm_unpacklo_epi8(data16, _mm_setzero_si128()); - __m128i resLo = _mm_mullo_epi16(data8, coeff); - __m128i resHi = _mm_mulhi_epi16(data8, coeff); - __m128i res32bitLo = _mm_unpacklo_epi16(resLo, resHi); - __m128i res32bitHi = _mm_unpackhi_epi16(resLo, resHi); - - // Load the 4 32-bit integers values, add the values we computed and store them back - __m128i res = _mm_load_si128((__m128i*)&tmp[x]); - res = _mm_add_epi32(res, res32bitLo); - _mm_store_si128((__m128i*)&tmp[x], res); - // Repeat the same operation for the next 4 values - res = _mm_load_si128((__m128i*)&tmp[x + 4]); - res = _mm_add_epi32(res, res32bitHi); - _mm_store_si128((__m128i*)&tmp[x + 4], res); - - // Multiply the next 8 values by the coefficient to get 8 32-bit integers - data8 = _mm_unpackhi_epi8(data16, _mm_setzero_si128()); - resLo = _mm_mullo_epi16(data8, coeff); - resHi = _mm_mulhi_epi16(data8, coeff); - res32bitLo = _mm_unpacklo_epi16(resLo, resHi); - res32bitHi = _mm_unpackhi_epi16(resLo, resHi); - - // Load the 4 32-bit integers values, add the values we computed and store them back - res = _mm_load_si128((__m128i*)&tmp[x + 8]); - res = _mm_add_epi32(res, res32bitLo); - _mm_store_si128((__m128i*)&tmp[x + 8], res); - // Repeat the same operation for the next 4 values - res = _mm_load_si128((__m128i*)&tmp[x + 12]); - res = _mm_add_epi32(res, res32bitHi); - _mm_store_si128((__m128i*)&tmp[x + 12], res); - } - for (int x = width16; x < width; x++) { - tmp[x] += (int)(in[(k - kOffset) * stride + x] * kernel[k]); - } - } - for (int x = 0; x < width16; x += 16) { - // Load 4 32-bit integer values and divide them - __m128i accum1 = _mm_load_si128((__m128i*)&tmp[x]); - accum1 = accum1 / divisorLibdivide; - // Repeat the same operation on the next 4 32-bit integer values - __m128i accum2 = _mm_load_si128((__m128i*)&tmp[x + 4]); - accum2 = accum2 / divisorLibdivide; - // Pack the 8 32-bit integers into 8 16-bit integers - accum1 = _mm_packs_epi32(accum1, accum2); - - // Load 4 32-bit integer values and divide them - __m128i accum3 = _mm_load_si128((__m128i*)&tmp[x + 8]); - accum3 = accum3 / divisorLibdivide; - // Repeat the same operation on the next 4 32-bit integer values - __m128i accum4 = _mm_load_si128((__m128i*)&tmp[x + 12]); - accum4 = accum4 / divisorLibdivide; - // Pack the 8 32-bit integers into 8 16-bit integers - accum3 = _mm_packs_epi32(accum3, accum4); - - // Pack the 16 16-bit integers into 16 8-bit unsigned integers - accum1 = _mm_packus_epi16(accum1, accum3); - - // Store the 16 8-bit unsigned integers - _mm_store_si128((__m128i*)&out[x], accum1); - } - for (int x = width16; x < width; x++) { - int accum = tmp[x] / divisor; - if (accum > 255) { - accum = 255; - } else if (accum < 0) { - accum = 0; - } - out[x] = (unsigned char)accum; - } - } - - _aligned_free(tmp); -} - - - -static inline double NormalDist(double sigma, double x) -{ - if (sigma <= 0.000000001) { - return (x == 0.0) ? 1.0 : 0.0; - } else { - return exp(-(x * x) / (2 * sigma * sigma)) / (sigma * sqrt(2 * M_PI)); - } -} - - -struct GaussianKernel { - short* kernel; - int width; - int divisor; - - inline GaussianKernel(double sigma) { - width = (int)(sigma * 3.0 + 0.5) | 1; // binary-or with 1 to make sure the number is odd - if (width < 3) { - width = 3; - } - kernel = DEBUG_NEW short[width]; - kernel[width / 2] = (short)(NormalDist(sigma, 0.0) * 255); - divisor = kernel[width / 2]; - for (int x = width / 2 - 1; x >= 0; x--) { - short val = (short)(NormalDist(sigma, width / 2 - x) * 255 + 0.5); - divisor += val * 2; - kernel[x] = val; - kernel[width - x - 1] = val; - } - if (divisor == 0) { divisor = 1; } // workaround to prevent crash - } - - inline ~GaussianKernel() { - delete [] kernel; - } - - GaussianKernel(const GaussianKernel&) = delete; - GaussianKernel& operator=(const GaussianKernel&) = delete; -}; +/* +* (C) 2007 Niels Martin Hansen +* (C) 2013-2017 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 . +* +*/ + +#pragma once + +#include + +#define LIBDIVIDE_USE_SSE2 1 +#pragma warning(push) +#pragma warning(disable: 4244 4456 4702) +#include "libdivide.h" +#pragma warning(pop) + +// Filter an image in horizontal direction with a one-dimensional filter +// PixelWidth is the distance in bytes between pixels +template +void SeparableFilterX(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, + short* kernel, int kernel_size, int divisor) +{ + int* tmp = DEBUG_NEW int[width]; + + for (int y = 0; y < height; y++) { + ZeroMemory(tmp, width * sizeof(int)); + + const unsigned char* in = src + y * stride; + unsigned char* out = dst + y * stride; + + for (int k = 0; k < kernel_size; k++) { + int xOffset = k - kernel_size / 2; + int xStart = 0; + int xEnd = width; + if (xOffset < 0) { + xEnd += xOffset; + } else if (xOffset > 0) { + xStart += xOffset; + } + for (int x = xStart; x < xEnd; x++) { + tmp[x - xOffset] += (int)(in[x * PixelDist] * kernel[k]); + } + } + for (int x = 0; x < width; x++) { + int accum = tmp[x] / divisor; + if (accum > 255) { + accum = 255; + } else if (accum < 0) { + accum = 0; + } + out[x * PixelDist] = (unsigned char)accum; + } + } + + delete [] tmp; +} + + +// Filter an image in vertical direction with a one-dimensional filter +// PixelWidth is the distance in bytes between pixels +template +void SeparableFilterY(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, + short* kernel, int kernel_size, int divisor) +{ + int* tmp = DEBUG_NEW int[width]; + + for (int y = 0; y < height; y++) { + ZeroMemory(tmp, width * sizeof(int)); + + const unsigned char* in = src + y * stride; + unsigned char* out = dst + y * stride; + + int kOffset = kernel_size / 2; + int kStart = 0; + int kEnd = kernel_size; + if (y < kOffset) { // 0 > y - kOffset + kStart += kOffset - y; + } else if (height <= y + kOffset) { + kEnd -= kOffset + y + 1 - height; + } + for (int k = kStart; k < kEnd; k++) { + for (int x = 0; x < width; x++) { + tmp[x] += (int)(in[(k - kOffset) * stride + x * PixelDist] * kernel[k]); + } + } + for (int x = 0; x < width; x++) { + int accum = tmp[x] / divisor; + if (accum > 255) { + accum = 255; + } else if (accum < 0) { + accum = 0; + } + out[x * PixelDist] = (unsigned char)accum; + } + } + + delete [] tmp; +} + + +// Filter an image in horizontal direction with a one-dimensional filter +void SeparableFilterX_SSE2(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, + short* kernel, int kernel_size, int divisor) +{ + int width16 = width & ~15; + int* tmp = (int*)_aligned_malloc(stride * sizeof(int), 16); + libdivide::divider divisorLibdivide(divisor); + + for (int y = 0; y < height; y++) { + ZeroMemory(tmp, stride * sizeof(int)); + + const unsigned char* in = src + y * stride; + unsigned char* out = dst + y * stride; + + for (int k = 0; k < kernel_size; k++) { + int xOffset = k - kernel_size / 2; + int xStart = 0; + int xEnd = width; + if (xOffset < 0) { + xEnd += xOffset; + } else if (xOffset > 0) { + xStart += xOffset; + } + int xStart16 = (xStart + 15) & ~15; + int xEnd16 = xEnd & ~15; + if (xStart16 >= xEnd16) { // Don't use SSE2 at all + xStart16 = xEnd16 = xEnd; + } + for (int x = xStart; x < xStart16; x++) { + tmp[x - xOffset] += (int)(in[x] * kernel[k]); + } + __m128i coeff = _mm_set1_epi16(kernel[k]); + for (int x = xStart16; x < xEnd16; x += 16) { + // Load 16 values + __m128i data16 = _mm_load_si128((__m128i*)&in[x]); + + // Multiply the first 8 values by the coefficient to get 8 32-bit integers + __m128i data8 = _mm_unpacklo_epi8(data16, _mm_setzero_si128()); + __m128i resLo = _mm_mullo_epi16(data8, coeff); + __m128i resHi = _mm_mulhi_epi16(data8, coeff); + __m128i res32bitLo = _mm_unpacklo_epi16(resLo, resHi); + __m128i res32bitHi = _mm_unpackhi_epi16(resLo, resHi); + + // Load the 4 32-bit integers values, add the values we computed and store them back + __m128i res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset]); + res = _mm_add_epi32(res, res32bitLo); + _mm_storeu_si128((__m128i*)&tmp[x - xOffset], res); + // Repeat the same operation for the next 4 values + res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 4]); + res = _mm_add_epi32(res, res32bitHi); + _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 4], res); + + // Multiply the next 8 values by the coefficient to get 8 32-bit integers + data8 = _mm_unpackhi_epi8(data16, _mm_setzero_si128()); + resLo = _mm_mullo_epi16(data8, coeff); + resHi = _mm_mulhi_epi16(data8, coeff); + res32bitLo = _mm_unpacklo_epi16(resLo, resHi); + res32bitHi = _mm_unpackhi_epi16(resLo, resHi); + + // Load the 4 32-bit integers values, add the values we computed and store them back + res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 8]); + res = _mm_add_epi32(res, res32bitLo); + _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 8], res); + // Repeat the same operation for the next 4 values + res = _mm_loadu_si128((__m128i*)&tmp[x - xOffset + 12]); + res = _mm_add_epi32(res, res32bitHi); + _mm_storeu_si128((__m128i*)&tmp[x - xOffset + 12], res); + } + for (int x = xEnd16; x < xEnd; x++) { + tmp[x - xOffset] += (int)(in[x] * kernel[k]); + } + } + for (int x = 0; x < width16; x += 16) { + // Load 4 32-bit integer values and divide them + __m128i accum1 = _mm_load_si128((__m128i*)&tmp[x]); + accum1 = accum1 / divisorLibdivide; + // Repeat the same operation on the next 4 32-bit integer values + __m128i accum2 = _mm_load_si128((__m128i*)&tmp[x + 4]); + accum2 = accum2 / divisorLibdivide; + // Pack the 8 32-bit integers into 8 16-bit integers + accum1 = _mm_packs_epi32(accum1, accum2); + + // Load 4 32-bit integer values and divide them + __m128i accum3 = _mm_load_si128((__m128i*)&tmp[x + 8]); + accum3 = accum3 / divisorLibdivide; + // Repeat the same operation on the next 4 32-bit integer values + __m128i accum4 = _mm_load_si128((__m128i*)&tmp[x + 12]); + accum4 = accum4 / divisorLibdivide; + // Pack the 8 32-bit integers into 8 16-bit integers + accum3 = _mm_packs_epi32(accum3, accum4); + + // Pack the 16 16-bit integers into 16 8-bit unsigned integers + accum1 = _mm_packus_epi16(accum1, accum3); + + // Store the 16 8-bit unsigned integers + _mm_store_si128((__m128i*)&out[x], accum1); + } + for (int x = width16; x < width; x++) { + int accum = tmp[x] / divisor; + if (accum > 255) { + accum = 255; + } else if (accum < 0) { + accum = 0; + } + out[x] = (unsigned char)accum; + } + } + + _aligned_free(tmp); +} + + +// Filter an image in vertical direction with a one-dimensional filter +void SeparableFilterY_SSE2(unsigned char* src, unsigned char* dst, int width, int height, ptrdiff_t stride, + short* kernel, int kernel_size, int divisor) +{ + int width16 = width & ~15; + int* tmp = (int*)_aligned_malloc(stride * sizeof(int), 16); + libdivide::divider divisorLibdivide(divisor); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < height; y++) { + ZeroMemory(tmp, stride * sizeof(int)); + + const unsigned char* in = src + y * stride; + unsigned char* out = dst + y * stride; + + int kOffset = kernel_size / 2; + int kStart = 0; + int kEnd = kernel_size; + if (y < kOffset) { // 0 > y - kOffset + kStart += kOffset - y; + } else if (height <= y + kOffset) { + kEnd -= kOffset + y + 1 - height; + } + for (int k = kStart; k < kEnd; k++) { + __m128i coeff = _mm_set1_epi16(kernel[k]); + for (int x = 0; x < width16; x += 16) { + // Load 16 values + __m128i data16 = _mm_load_si128((__m128i*)&in[(k - kOffset) * stride + x]); + + // Multiply the first 8 values by the coefficient to get 8 32-bit integers + __m128i data8 = _mm_unpacklo_epi8(data16, _mm_setzero_si128()); + __m128i resLo = _mm_mullo_epi16(data8, coeff); + __m128i resHi = _mm_mulhi_epi16(data8, coeff); + __m128i res32bitLo = _mm_unpacklo_epi16(resLo, resHi); + __m128i res32bitHi = _mm_unpackhi_epi16(resLo, resHi); + + // Load the 4 32-bit integers values, add the values we computed and store them back + __m128i res = _mm_load_si128((__m128i*)&tmp[x]); + res = _mm_add_epi32(res, res32bitLo); + _mm_store_si128((__m128i*)&tmp[x], res); + // Repeat the same operation for the next 4 values + res = _mm_load_si128((__m128i*)&tmp[x + 4]); + res = _mm_add_epi32(res, res32bitHi); + _mm_store_si128((__m128i*)&tmp[x + 4], res); + + // Multiply the next 8 values by the coefficient to get 8 32-bit integers + data8 = _mm_unpackhi_epi8(data16, _mm_setzero_si128()); + resLo = _mm_mullo_epi16(data8, coeff); + resHi = _mm_mulhi_epi16(data8, coeff); + res32bitLo = _mm_unpacklo_epi16(resLo, resHi); + res32bitHi = _mm_unpackhi_epi16(resLo, resHi); + + // Load the 4 32-bit integers values, add the values we computed and store them back + res = _mm_load_si128((__m128i*)&tmp[x + 8]); + res = _mm_add_epi32(res, res32bitLo); + _mm_store_si128((__m128i*)&tmp[x + 8], res); + // Repeat the same operation for the next 4 values + res = _mm_load_si128((__m128i*)&tmp[x + 12]); + res = _mm_add_epi32(res, res32bitHi); + _mm_store_si128((__m128i*)&tmp[x + 12], res); + } + for (int x = width16; x < width; x++) { + tmp[x] += (int)(in[(k - kOffset) * stride + x] * kernel[k]); + } + } + for (int x = 0; x < width16; x += 16) { + // Load 4 32-bit integer values and divide them + __m128i accum1 = _mm_load_si128((__m128i*)&tmp[x]); + accum1 = accum1 / divisorLibdivide; + // Repeat the same operation on the next 4 32-bit integer values + __m128i accum2 = _mm_load_si128((__m128i*)&tmp[x + 4]); + accum2 = accum2 / divisorLibdivide; + // Pack the 8 32-bit integers into 8 16-bit integers + accum1 = _mm_packs_epi32(accum1, accum2); + + // Load 4 32-bit integer values and divide them + __m128i accum3 = _mm_load_si128((__m128i*)&tmp[x + 8]); + accum3 = accum3 / divisorLibdivide; + // Repeat the same operation on the next 4 32-bit integer values + __m128i accum4 = _mm_load_si128((__m128i*)&tmp[x + 12]); + accum4 = accum4 / divisorLibdivide; + // Pack the 8 32-bit integers into 8 16-bit integers + accum3 = _mm_packs_epi32(accum3, accum4); + + // Pack the 16 16-bit integers into 16 8-bit unsigned integers + accum1 = _mm_packus_epi16(accum1, accum3); + + // Store the 16 8-bit unsigned integers + _mm_store_si128((__m128i*)&out[x], accum1); + } + for (int x = width16; x < width; x++) { + int accum = tmp[x] / divisor; + if (accum > 255) { + accum = 255; + } else if (accum < 0) { + accum = 0; + } + out[x] = (unsigned char)accum; + } + } + + _aligned_free(tmp); +} + + + +static inline double NormalDist(double sigma, double x) +{ + if (sigma <= 0.000000001) { + return (x == 0.0) ? 1.0 : 0.0; + } else { + return exp(-(x * x) / (2 * sigma * sigma)) / (sigma * sqrt(2 * M_PI)); + } +} + + +struct GaussianKernel { + short* kernel; + int width; + int divisor; + + inline GaussianKernel(double sigma) { + width = (int)(sigma * 3.0 + 0.5) | 1; // binary-or with 1 to make sure the number is odd + if (width < 3) { + width = 3; + } + kernel = DEBUG_NEW short[width]; + kernel[width / 2] = (short)(NormalDist(sigma, 0.0) * 255); + divisor = kernel[width / 2]; + for (int x = width / 2 - 1; x >= 0; x--) { + short val = (short)(NormalDist(sigma, width / 2 - x) * 255 + 0.5); + divisor += val * 2; + kernel[x] = val; + kernel[width - x - 1] = val; + } + if (divisor == 0) { divisor = 1; } // workaround to prevent crash + } + + inline ~GaussianKernel() { + delete [] kernel; + } + + GaussianKernel(const GaussianKernel&) = delete; + GaussianKernel& operator=(const GaussianKernel&) = delete; +}; diff --git a/src/Subtitles/SubtitleInputPin.cpp b/src/Subtitles/SubtitleInputPin.cpp index b5feffb2dde..3d0a2f8614e 100644 --- a/src/Subtitles/SubtitleInputPin.cpp +++ b/src/Subtitles/SubtitleInputPin.cpp @@ -1,541 +1,541 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "SubtitleInputPin.h" -#include "VobSubFile.h" -#include "RTS.h" -#include "DVBSub.h" -#include "PGSSub.h" - -#include -#include "moreuuids.h" -#include "../DSUtil/ISOLang.h" - -#if !TRACE_SUBTITLES -#undef TRACE -#define TRACE(...) -#endif - -// our first format id -#define __GAB1__ "GAB1" - -// our tags for __GAB1__ (ushort) + size (ushort) - -// "lang" + '0' -#define __GAB1_LANGUAGE__ 0 -// (int)start+(int)stop+(char*)line+'0' -#define __GAB1_ENTRY__ 1 -// L"lang" + '0' -#define __GAB1_LANGUAGE_UNICODE__ 2 -// (int)start+(int)stop+(WCHAR*)line+'0' -#define __GAB1_ENTRY_UNICODE__ 3 - -// same as __GAB1__, but the size is (uint) and only __GAB1_LANGUAGE_UNICODE__ is valid -#define __GAB2__ "GAB2" - -// (BYTE*) -#define __GAB1_RAWTEXTSUBTITLE__ 4 - -CSubtitleInputPin::CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr) - : CBaseInputPin(NAME("CSubtitleInputPin"), pFilter, pLock, phr, L"Input") - , m_pSubLock(pSubLock) - , m_bExitDecodingThread(false) - , m_bStopDecoding(false) -{ - m_bCanReconnectWhenActive = true; - m_decodeThread = std::thread([this]() { - DecodeSamples(); - }); -} - -CSubtitleInputPin::~CSubtitleInputPin() -{ - m_bExitDecodingThread = m_bStopDecoding = true; - m_condQueueReady.notify_one(); - if (m_decodeThread.joinable()) { - m_decodeThread.join(); - } -} - -HRESULT CSubtitleInputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Text && (pmt->subtype == MEDIASUBTYPE_NULL || pmt->subtype == FOURCCMap((DWORD)0)) - || pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_UTF8 || pmt->subtype == MEDIASUBTYPE_SSA || pmt->subtype == MEDIASUBTYPE_ASS || pmt->subtype == MEDIASUBTYPE_ASS2 || pmt->subtype == MEDIASUBTYPE_VOBSUB || pmt->subtype == MEDIASUBTYPE_WEBVTT) - || IsRLECodedSub(pmt) - ? S_OK - : E_FAIL; -} - -HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin) -{ - InvalidateSamples(); - - if (m_mt.majortype == MEDIATYPE_Text) { - if (!(m_pSubStream = DEBUG_NEW CRenderedTextSubtitle(m_pSubLock))) { - return E_FAIL; - } - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; - pRTS->m_name = CString(GetPinName(pReceivePin)) + _T(" (embedded)"); - pRTS->m_storageRes = pRTS->m_playRes = CSize(384, 288); - pRTS->CreateDefaultStyle(DEFAULT_CHARSET); - } else if (m_mt.majortype == MEDIATYPE_Subtitle) { - SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; - DWORD dwOffset = 0; - CString name; - LCID lcid = 0; - - if (psi != nullptr) { - dwOffset = psi->dwOffset; - - lcid = ISOLang::ISO6392ToLcid(psi->IsoLang); - if (0 == lcid) { //try 639-1 in case it comes from BCP-47 (contains mix of 639-1 and 639-2) - lcid = ISOLang::ISO6391ToLcid(psi->IsoLang); - } - name = ISOLang::ISO639XToLanguage(psi->IsoLang); - - CString trackName(psi->TrackName); - trackName.Trim(); - if (!trackName.IsEmpty()) { - if (!name.IsEmpty()) { - if (trackName[0] != _T('(') && trackName[0] != _T('[')) { - name += _T(","); - } - name += _T(" "); - } - name += trackName; - } - if (name.IsEmpty()) { - name = _T("Unknown"); - } - } - - name.Replace(_T(""), _T("")); - name.Replace(_T(""), _T("")); - - bool subtype_utf8 = m_mt.subtype == MEDIASUBTYPE_UTF8; - bool subtype_vtt = m_mt.subtype == MEDIASUBTYPE_WEBVTT; - bool subtype_ass = m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2; - - if (subtype_utf8 || subtype_ass || subtype_vtt) { - if (!(m_pSubStream = DEBUG_NEW CRenderedTextSubtitle(m_pSubLock))) { - return E_FAIL; - } - - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; - pRTS->SetSubtitleTypeFromGUID(m_mt.subtype); -#if USE_LIBASS +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "SubtitleInputPin.h" +#include "VobSubFile.h" +#include "RTS.h" +#include "DVBSub.h" +#include "PGSSub.h" + +#include +#include "moreuuids.h" +#include "../DSUtil/ISOLang.h" + +#if !TRACE_SUBTITLES +#undef TRACE +#define TRACE(...) +#endif + +// our first format id +#define __GAB1__ "GAB1" + +// our tags for __GAB1__ (ushort) + size (ushort) + +// "lang" + '0' +#define __GAB1_LANGUAGE__ 0 +// (int)start+(int)stop+(char*)line+'0' +#define __GAB1_ENTRY__ 1 +// L"lang" + '0' +#define __GAB1_LANGUAGE_UNICODE__ 2 +// (int)start+(int)stop+(WCHAR*)line+'0' +#define __GAB1_ENTRY_UNICODE__ 3 + +// same as __GAB1__, but the size is (uint) and only __GAB1_LANGUAGE_UNICODE__ is valid +#define __GAB2__ "GAB2" + +// (BYTE*) +#define __GAB1_RAWTEXTSUBTITLE__ 4 + +CSubtitleInputPin::CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr) + : CBaseInputPin(NAME("CSubtitleInputPin"), pFilter, pLock, phr, L"Input") + , m_pSubLock(pSubLock) + , m_bExitDecodingThread(false) + , m_bStopDecoding(false) +{ + m_bCanReconnectWhenActive = true; + m_decodeThread = std::thread([this]() { + DecodeSamples(); + }); +} + +CSubtitleInputPin::~CSubtitleInputPin() +{ + m_bExitDecodingThread = m_bStopDecoding = true; + m_condQueueReady.notify_one(); + if (m_decodeThread.joinable()) { + m_decodeThread.join(); + } +} + +HRESULT CSubtitleInputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Text && (pmt->subtype == MEDIASUBTYPE_NULL || pmt->subtype == FOURCCMap((DWORD)0)) + || pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_UTF8 || pmt->subtype == MEDIASUBTYPE_SSA || pmt->subtype == MEDIASUBTYPE_ASS || pmt->subtype == MEDIASUBTYPE_ASS2 || pmt->subtype == MEDIASUBTYPE_VOBSUB || pmt->subtype == MEDIASUBTYPE_WEBVTT) + || IsRLECodedSub(pmt) + ? S_OK + : E_FAIL; +} + +HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin) +{ + InvalidateSamples(); + + if (m_mt.majortype == MEDIATYPE_Text) { + if (!(m_pSubStream = DEBUG_NEW CRenderedTextSubtitle(m_pSubLock))) { + return E_FAIL; + } + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; + pRTS->m_name = CString(GetPinName(pReceivePin)) + _T(" (embedded)"); + pRTS->m_storageRes = pRTS->m_playRes = CSize(384, 288); + pRTS->CreateDefaultStyle(DEFAULT_CHARSET); + } else if (m_mt.majortype == MEDIATYPE_Subtitle) { + SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; + DWORD dwOffset = 0; + CString name; + LCID lcid = 0; + + if (psi != nullptr) { + dwOffset = psi->dwOffset; + + lcid = ISOLang::ISO6392ToLcid(psi->IsoLang); + if (0 == lcid) { //try 639-1 in case it comes from BCP-47 (contains mix of 639-1 and 639-2) + lcid = ISOLang::ISO6391ToLcid(psi->IsoLang); + } + name = ISOLang::ISO639XToLanguage(psi->IsoLang); + + CString trackName(psi->TrackName); + trackName.Trim(); + if (!trackName.IsEmpty()) { + if (!name.IsEmpty()) { + if (trackName[0] != _T('(') && trackName[0] != _T('[')) { + name += _T(","); + } + name += _T(" "); + } + name += trackName; + } + if (name.IsEmpty()) { + name = _T("Unknown"); + } + } + + name.Replace(_T(""), _T("")); + name.Replace(_T(""), _T("")); + + bool subtype_utf8 = m_mt.subtype == MEDIASUBTYPE_UTF8; + bool subtype_vtt = m_mt.subtype == MEDIASUBTYPE_WEBVTT; + bool subtype_ass = m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2; + + if (subtype_utf8 || subtype_ass || subtype_vtt) { + if (!(m_pSubStream = DEBUG_NEW CRenderedTextSubtitle(m_pSubLock))) { + return E_FAIL; + } + + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; + pRTS->SetSubtitleTypeFromGUID(m_mt.subtype); +#if USE_LIBASS if (pRTS->m_LibassContext.CheckSubType()) { pRTS->m_LibassContext.SetFilterGraphFromFilter(m_pFilter); } #endif - pRTS->m_name = name; - pRTS->m_lcid = lcid; - if (lcid > 0) { - pRTS->m_langname = ISOLang::LCIDToLanguage(lcid); - } - pRTS->m_storageRes = pRTS->m_playRes = CSize(384, 288); - pRTS->CreateDefaultStyle(DEFAULT_CHARSET); - - if (dwOffset > 0 && m_mt.cbFormat - dwOffset > 0) { - CMediaType mt = m_mt; - if (mt.pbFormat[dwOffset + 0] != 0xef - && mt.pbFormat[dwOffset + 1] != 0xbb - && mt.pbFormat[dwOffset + 2] != 0xfb) { - dwOffset -= 3; - mt.pbFormat[dwOffset + 0] = 0xef; - mt.pbFormat[dwOffset + 1] = 0xbb; - mt.pbFormat[dwOffset + 2] = 0xbf; - } - - // process with own parser first, even when using libass, since we need certain info like PlayRes - pRTS->Open(mt.pbFormat + dwOffset, mt.cbFormat - dwOffset, DEFAULT_CHARSET, pRTS->m_name); -#if USE_LIBASS + pRTS->m_name = name; + pRTS->m_lcid = lcid; + if (lcid > 0) { + pRTS->m_langname = ISOLang::LCIDToLanguage(lcid); + } + pRTS->m_storageRes = pRTS->m_playRes = CSize(384, 288); + pRTS->CreateDefaultStyle(DEFAULT_CHARSET); + + if (dwOffset > 0 && m_mt.cbFormat - dwOffset > 0) { + CMediaType mt = m_mt; + if (mt.pbFormat[dwOffset + 0] != 0xef + && mt.pbFormat[dwOffset + 1] != 0xbb + && mt.pbFormat[dwOffset + 2] != 0xfb) { + dwOffset -= 3; + mt.pbFormat[dwOffset + 0] = 0xef; + mt.pbFormat[dwOffset + 1] = 0xbb; + mt.pbFormat[dwOffset + 2] = 0xbf; + } + + // process with own parser first, even when using libass, since we need certain info like PlayRes + pRTS->Open(mt.pbFormat + dwOffset, mt.cbFormat - dwOffset, DEFAULT_CHARSET, pRTS->m_name); +#if USE_LIBASS if (pRTS->m_LibassContext.m_renderUsingLibass) { bool success = pRTS->m_LibassContext.LoadASSTrack((char*)m_mt.Format() + psi->dwOffset, m_mt.FormatLength() - psi->dwOffset, subtype_ass ? Subtitle::ASS : Subtitle::SRT); pRTS->m_LibassContext.m_renderUsingLibass = success && pRTS->m_LibassContext.IsLibassActive(); } #endif - } - } else if (m_mt.subtype == MEDIASUBTYPE_VOBSUB) { - if (!(m_pSubStream = DEBUG_NEW CVobSubStream(m_pSubLock))) { - return E_FAIL; - } - CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; - pVSS->Open(name, m_mt.pbFormat + dwOffset, m_mt.cbFormat - dwOffset); - } else if (IsRLECodedSub(&m_mt)) { - if (m_mt.subtype == MEDIASUBTYPE_DVB_SUBTITLES) { - m_pSubStream = DEBUG_NEW CDVBSub(m_pSubLock, name, lcid); - } else { - m_pSubStream = DEBUG_NEW CPGSSub(m_pSubLock, name, lcid); - } - if (!m_pSubStream) { - return E_FAIL; - } - } - } - - AddSubStream(m_pSubStream); - - return __super::CompleteConnect(pReceivePin); -} - -HRESULT CSubtitleInputPin::BreakConnect() -{ - InvalidateSamples(); - - RemoveSubStream(m_pSubStream); - m_pSubStream = nullptr; - - ASSERT(IsStopped()); - - return __super::BreakConnect(); -} - -STDMETHODIMP CSubtitleInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) -{ - if (m_Connected) { - InvalidateSamples(); - - RemoveSubStream(m_pSubStream); - m_pSubStream = nullptr; - - m_Connected->Release(); - m_Connected = nullptr; - } - - return __super::ReceiveConnection(pConnector, pmt); -} - -STDMETHODIMP CSubtitleInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - CAutoLock cAutoLock(&m_csReceive); - - InvalidateSamples(); - - if (m_mt.majortype == MEDIATYPE_Text || m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_UTF8 - || m_mt.subtype == MEDIASUBTYPE_WEBVTT || m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS - || m_mt.subtype == MEDIASUBTYPE_ASS2)) { - CAutoLock cAutoLock2(m_pSubLock); - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; - if (pRTS->m_webvtt_allow_clear || pRTS->m_subtitleType != Subtitle::VTT) { - pRTS->RemoveAll(); - pRTS->CreateSegments(); - pRTS->FlushEventsLibass(); - } - // WebVTT can be read as one big blob of data during pin connection, instead of as samples during playback. - // This depends on how it is being demuxed. So clear only if we previously got data through samples. - } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_VOBSUB)) { - CAutoLock cAutoLock2(m_pSubLock); - CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; - pVSS->RemoveAll(); - } else if (IsRLECodedSub(&m_mt)) { - CAutoLock cAutoLock2(m_pSubLock); - CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; - pRLECodedSubtitle->NewSegment(tStart, tStop, dRate); - } - - TRACE(_T("NewSegment: InvalidateSubtitle %.3f\n"), RT2SEC(tStart)); - // IMPORTANT: m_pSubLock must not be locked when calling this - InvalidateSubtitle(tStart, m_pSubStream); - - return __super::NewSegment(tStart, tStop, dRate); -} - -STDMETHODIMP CSubtitleInputPin::Receive(IMediaSample* pSample) -{ - HRESULT hr = __super::Receive(pSample); - if (FAILED(hr)) { - return hr; - } - - CAutoLock cAutoLock(&m_csReceive); - - REFERENCE_TIME tStart, tStop; - hr = pSample->GetTime(&tStart, &tStop); - - switch (hr) { - case S_OK: - tStart += m_tStart; - tStop += m_tStart; - break; - case VFW_S_NO_STOP_TIME: - tStart += m_tStart; - tStop = INVALID_TIME; - break; - case VFW_E_SAMPLE_TIME_NOT_SET: - tStart = tStop = INVALID_TIME; - break; - default: - ASSERT(FALSE); - return hr; - } - - if ((tStart == INVALID_TIME || tStop == INVALID_TIME) && !IsRLECodedSub(&m_mt)) { - ASSERT(FALSE); - } else { - BYTE* pData = nullptr; - hr = pSample->GetPointer(&pData); - long len = pSample->GetActualDataLength(); - if (FAILED(hr) || pData == nullptr || len <= 0) { - return hr; - } - - { - std::unique_lock lock(m_mutexQueue); - m_sampleQueue.emplace_back(DEBUG_NEW SubtitleSample(tStart, tStop, pData, size_t(len))); - lock.unlock(); - m_condQueueReady.notify_one(); - } - } - - return S_OK; -} - -STDMETHODIMP CSubtitleInputPin::EndOfStream(void) -{ - HRESULT hr = __super::EndOfStream(); - - if (SUCCEEDED(hr)) { - std::unique_lock lock(m_mutexQueue); - m_sampleQueue.emplace_back(nullptr); // nullptr means end of stream - lock.unlock(); - m_condQueueReady.notify_one(); - } - - return hr; -} - -bool CSubtitleInputPin::IsRLECodedSub(const CMediaType* pmt) const -{ - return !!(pmt->majortype == MEDIATYPE_Subtitle - && (pmt->subtype == MEDIASUBTYPE_HDMVSUB // Blu-Ray presentation graphics - || pmt->subtype == MEDIASUBTYPE_DVB_SUBTITLES // DVB subtitles - || (pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_SubtitleInfo))); // Workaround : support for Haali PGS -} - -void CSubtitleInputPin::DecodeSamples() -{ - SetThreadName(DWORD(-1), "Subtitle Input Pin Thread"); - - for (; !m_bExitDecodingThread;) { - std::unique_lock lock(m_mutexQueue); - - auto needStopProcessing = [this]() { - return m_bStopDecoding || m_bExitDecodingThread; - }; - - auto isQueueReady = [&]() { - return !m_sampleQueue.empty() || needStopProcessing(); - }; - - m_condQueueReady.wait(lock, isQueueReady); - lock.unlock(); // Release this lock until we can acquire the other one - - REFERENCE_TIME rtInvalidate = -1; - - if (!needStopProcessing()) { - CAutoLock cAutoLock(m_pSubLock); - lock.lock(); // Reacquire the lock - - while (!m_sampleQueue.empty() && !needStopProcessing()) { - const auto& pSample = m_sampleQueue.front(); - - if (pSample) { - REFERENCE_TIME rtSampleInvalidate = DecodeSample(pSample); - if (rtSampleInvalidate >= 0 && (rtSampleInvalidate < rtInvalidate || rtInvalidate < 0)) { - rtInvalidate = rtSampleInvalidate; - } - } else { // marker for end of stream - if (IsRLECodedSub(&m_mt)) { - CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; - pRLECodedSubtitle->EndOfStream(); - } - } - - m_sampleQueue.pop_front(); - } - } - - if (rtInvalidate >= 0) { - //TRACE(_T("NewSegment: InvalidateSubtitle %.3f\n"), double(rtInvalidate) / 10000000.0); - // IMPORTANT: m_pSubLock must not be locked when calling this - InvalidateSubtitle(rtInvalidate, m_pSubStream); - } - } -} - -REFERENCE_TIME CSubtitleInputPin::DecodeSample(const std::unique_ptr& pSample) -{ - bool bInvalidate = false; - + } + } else if (m_mt.subtype == MEDIASUBTYPE_VOBSUB) { + if (!(m_pSubStream = DEBUG_NEW CVobSubStream(m_pSubLock))) { + return E_FAIL; + } + CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; + pVSS->Open(name, m_mt.pbFormat + dwOffset, m_mt.cbFormat - dwOffset); + } else if (IsRLECodedSub(&m_mt)) { + if (m_mt.subtype == MEDIASUBTYPE_DVB_SUBTITLES) { + m_pSubStream = DEBUG_NEW CDVBSub(m_pSubLock, name, lcid); + } else { + m_pSubStream = DEBUG_NEW CPGSSub(m_pSubLock, name, lcid); + } + if (!m_pSubStream) { + return E_FAIL; + } + } + } + + AddSubStream(m_pSubStream); + + return __super::CompleteConnect(pReceivePin); +} + +HRESULT CSubtitleInputPin::BreakConnect() +{ + InvalidateSamples(); + + RemoveSubStream(m_pSubStream); + m_pSubStream = nullptr; + + ASSERT(IsStopped()); + + return __super::BreakConnect(); +} + +STDMETHODIMP CSubtitleInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) +{ + if (m_Connected) { + InvalidateSamples(); + + RemoveSubStream(m_pSubStream); + m_pSubStream = nullptr; + + m_Connected->Release(); + m_Connected = nullptr; + } + + return __super::ReceiveConnection(pConnector, pmt); +} + +STDMETHODIMP CSubtitleInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CAutoLock cAutoLock(&m_csReceive); + + InvalidateSamples(); + + if (m_mt.majortype == MEDIATYPE_Text || m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_UTF8 + || m_mt.subtype == MEDIASUBTYPE_WEBVTT || m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS + || m_mt.subtype == MEDIASUBTYPE_ASS2)) { + CAutoLock cAutoLock2(m_pSubLock); + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; + if (pRTS->m_webvtt_allow_clear || pRTS->m_subtitleType != Subtitle::VTT) { + pRTS->RemoveAll(); + pRTS->CreateSegments(); + pRTS->FlushEventsLibass(); + } + // WebVTT can be read as one big blob of data during pin connection, instead of as samples during playback. + // This depends on how it is being demuxed. So clear only if we previously got data through samples. + } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_VOBSUB)) { + CAutoLock cAutoLock2(m_pSubLock); + CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; + pVSS->RemoveAll(); + } else if (IsRLECodedSub(&m_mt)) { + CAutoLock cAutoLock2(m_pSubLock); + CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; + pRLECodedSubtitle->NewSegment(tStart, tStop, dRate); + } + + TRACE(_T("NewSegment: InvalidateSubtitle %.3f\n"), RT2SEC(tStart)); + // IMPORTANT: m_pSubLock must not be locked when calling this + InvalidateSubtitle(tStart, m_pSubStream); + + return __super::NewSegment(tStart, tStop, dRate); +} + +STDMETHODIMP CSubtitleInputPin::Receive(IMediaSample* pSample) +{ + HRESULT hr = __super::Receive(pSample); + if (FAILED(hr)) { + return hr; + } + + CAutoLock cAutoLock(&m_csReceive); + + REFERENCE_TIME tStart, tStop; + hr = pSample->GetTime(&tStart, &tStop); + + switch (hr) { + case S_OK: + tStart += m_tStart; + tStop += m_tStart; + break; + case VFW_S_NO_STOP_TIME: + tStart += m_tStart; + tStop = INVALID_TIME; + break; + case VFW_E_SAMPLE_TIME_NOT_SET: + tStart = tStop = INVALID_TIME; + break; + default: + ASSERT(FALSE); + return hr; + } + + if ((tStart == INVALID_TIME || tStop == INVALID_TIME) && !IsRLECodedSub(&m_mt)) { + ASSERT(FALSE); + } else { + BYTE* pData = nullptr; + hr = pSample->GetPointer(&pData); + long len = pSample->GetActualDataLength(); + if (FAILED(hr) || pData == nullptr || len <= 0) { + return hr; + } + + { + std::unique_lock lock(m_mutexQueue); + m_sampleQueue.emplace_back(DEBUG_NEW SubtitleSample(tStart, tStop, pData, size_t(len))); + lock.unlock(); + m_condQueueReady.notify_one(); + } + } + + return S_OK; +} + +STDMETHODIMP CSubtitleInputPin::EndOfStream(void) +{ + HRESULT hr = __super::EndOfStream(); + + if (SUCCEEDED(hr)) { + std::unique_lock lock(m_mutexQueue); + m_sampleQueue.emplace_back(nullptr); // nullptr means end of stream + lock.unlock(); + m_condQueueReady.notify_one(); + } + + return hr; +} + +bool CSubtitleInputPin::IsRLECodedSub(const CMediaType* pmt) const +{ + return !!(pmt->majortype == MEDIATYPE_Subtitle + && (pmt->subtype == MEDIASUBTYPE_HDMVSUB // Blu-Ray presentation graphics + || pmt->subtype == MEDIASUBTYPE_DVB_SUBTITLES // DVB subtitles + || (pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_SubtitleInfo))); // Workaround : support for Haali PGS +} + +void CSubtitleInputPin::DecodeSamples() +{ + SetThreadName(DWORD(-1), "Subtitle Input Pin Thread"); + + for (; !m_bExitDecodingThread;) { + std::unique_lock lock(m_mutexQueue); + + auto needStopProcessing = [this]() { + return m_bStopDecoding || m_bExitDecodingThread; + }; + + auto isQueueReady = [&]() { + return !m_sampleQueue.empty() || needStopProcessing(); + }; + + m_condQueueReady.wait(lock, isQueueReady); + lock.unlock(); // Release this lock until we can acquire the other one + + REFERENCE_TIME rtInvalidate = -1; + + if (!needStopProcessing()) { + CAutoLock cAutoLock(m_pSubLock); + lock.lock(); // Reacquire the lock + + while (!m_sampleQueue.empty() && !needStopProcessing()) { + const auto& pSample = m_sampleQueue.front(); + + if (pSample) { + REFERENCE_TIME rtSampleInvalidate = DecodeSample(pSample); + if (rtSampleInvalidate >= 0 && (rtSampleInvalidate < rtInvalidate || rtInvalidate < 0)) { + rtInvalidate = rtSampleInvalidate; + } + } else { // marker for end of stream + if (IsRLECodedSub(&m_mt)) { + CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; + pRLECodedSubtitle->EndOfStream(); + } + } + + m_sampleQueue.pop_front(); + } + } + + if (rtInvalidate >= 0) { + //TRACE(_T("NewSegment: InvalidateSubtitle %.3f\n"), double(rtInvalidate) / 10000000.0); + // IMPORTANT: m_pSubLock must not be locked when calling this + InvalidateSubtitle(rtInvalidate, m_pSubStream); + } + } +} + +REFERENCE_TIME CSubtitleInputPin::DecodeSample(const std::unique_ptr& pSample) +{ + bool bInvalidate = false; + if (pSample->data.size() <= 0) { return -1; } - - if (m_mt.majortype == MEDIATYPE_Text) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; - - char* pData = (char*)pSample->data.data(); - - if (!strncmp(pData, __GAB1__, strlen(__GAB1__))) { - char* ptr = &pData[strlen(__GAB1__) + 1]; - char* end = &pData[pSample->data.size()]; - - while (ptr < end) { - WORD tag = *((WORD*)(ptr)); - ptr += 2; - WORD size = *((WORD*)(ptr)); - ptr += 2; - - if (tag == __GAB1_LANGUAGE__) { - pRTS->m_name = ptr; - } else if (tag == __GAB1_ENTRY__) { - pRTS->Add(AToW(&ptr[8]), false, MS2RT(*(int*)ptr), MS2RT(*(int*)(ptr + 4))); - bInvalidate = true; - } else if (tag == __GAB1_LANGUAGE_UNICODE__) { - pRTS->m_name = (WCHAR*)ptr; - } else if (tag == __GAB1_ENTRY_UNICODE__) { - pRTS->Add((WCHAR*)(ptr + 8), true, MS2RT(*(int*)ptr), MS2RT(*(int*)(ptr + 4))); - bInvalidate = true; - } - - ptr += size; - } - } else if (!strncmp(pData, __GAB2__, strlen(__GAB2__))) { - char* ptr = &pData[strlen(__GAB2__) + 1]; - char* end = &pData[pSample->data.size()]; - - while (ptr < end) { - WORD tag = *((WORD*)(ptr)); - ptr += 2; - DWORD size = *((DWORD*)(ptr)); - ptr += 4; - - if (tag == __GAB1_LANGUAGE_UNICODE__) { - pRTS->m_name = (WCHAR*)ptr; - } else if (tag == __GAB1_RAWTEXTSUBTITLE__) { - pRTS->Open((BYTE*)ptr, size, DEFAULT_CHARSET, pRTS->m_name); - bInvalidate = true; - } - - ptr += size; - } - } else if (pSample->data.size() > 1 && *pData != '\0') { - CStringA str(pData, (int)pSample->data.size()); - - str.Replace("\r\n", "\n"); - FastTrim(str); - - if (!str.IsEmpty()) { - pRTS->Add(AToW(str), false, pSample->rtStart, pSample->rtStop); - bInvalidate = true; - } - } - } else if (m_mt.majortype == MEDIATYPE_Subtitle) { - if (m_mt.subtype == MEDIASUBTYPE_UTF8 || m_mt.subtype == MEDIASUBTYPE_WEBVTT) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; -#if USE_LIBASS + + if (m_mt.majortype == MEDIATYPE_Text) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; + + char* pData = (char*)pSample->data.data(); + + if (!strncmp(pData, __GAB1__, strlen(__GAB1__))) { + char* ptr = &pData[strlen(__GAB1__) + 1]; + char* end = &pData[pSample->data.size()]; + + while (ptr < end) { + WORD tag = *((WORD*)(ptr)); + ptr += 2; + WORD size = *((WORD*)(ptr)); + ptr += 2; + + if (tag == __GAB1_LANGUAGE__) { + pRTS->m_name = ptr; + } else if (tag == __GAB1_ENTRY__) { + pRTS->Add(AToW(&ptr[8]), false, MS2RT(*(int*)ptr), MS2RT(*(int*)(ptr + 4))); + bInvalidate = true; + } else if (tag == __GAB1_LANGUAGE_UNICODE__) { + pRTS->m_name = (WCHAR*)ptr; + } else if (tag == __GAB1_ENTRY_UNICODE__) { + pRTS->Add((WCHAR*)(ptr + 8), true, MS2RT(*(int*)ptr), MS2RT(*(int*)(ptr + 4))); + bInvalidate = true; + } + + ptr += size; + } + } else if (!strncmp(pData, __GAB2__, strlen(__GAB2__))) { + char* ptr = &pData[strlen(__GAB2__) + 1]; + char* end = &pData[pSample->data.size()]; + + while (ptr < end) { + WORD tag = *((WORD*)(ptr)); + ptr += 2; + DWORD size = *((DWORD*)(ptr)); + ptr += 4; + + if (tag == __GAB1_LANGUAGE_UNICODE__) { + pRTS->m_name = (WCHAR*)ptr; + } else if (tag == __GAB1_RAWTEXTSUBTITLE__) { + pRTS->Open((BYTE*)ptr, size, DEFAULT_CHARSET, pRTS->m_name); + bInvalidate = true; + } + + ptr += size; + } + } else if (pSample->data.size() > 1 && *pData != '\0') { + CStringA str(pData, (int)pSample->data.size()); + + str.Replace("\r\n", "\n"); + FastTrim(str); + + if (!str.IsEmpty()) { + pRTS->Add(AToW(str), false, pSample->rtStart, pSample->rtStop); + bInvalidate = true; + } + } + } else if (m_mt.majortype == MEDIATYPE_Subtitle) { + if (m_mt.subtype == MEDIASUBTYPE_UTF8 || m_mt.subtype == MEDIASUBTYPE_WEBVTT) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; +#if USE_LIBASS if (pRTS->m_LibassContext.IsLibassActive()) { LPCSTR data = (LPCSTR)pSample->data.data(); int dataSize = (int)pSample->data.size(); pRTS->m_LibassContext.SetFilterGraphFromFilter(m_pFilter); pRTS->m_LibassContext.LoadASSSample((char*)data, dataSize, pSample->rtStart, pSample->rtStop); } else -#endif - { - CStringW str = UTF8To16(CStringA((LPCSTR)pSample->data.data(), (int)pSample->data.size())); - FastTrim(str); - if (!str.IsEmpty()) { - pRTS->Add(str, true, pSample->rtStart, pSample->rtStop); - bInvalidate = true; - if (pRTS->m_subtitleType == Subtitle::VTT) { - pRTS->m_webvtt_allow_clear = true; - } - } - } - } else if (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; +#endif + { + CStringW str = UTF8To16(CStringA((LPCSTR)pSample->data.data(), (int)pSample->data.size())); + FastTrim(str); + if (!str.IsEmpty()) { + pRTS->Add(str, true, pSample->rtStart, pSample->rtStop); + bInvalidate = true; + if (pRTS->m_subtitleType == Subtitle::VTT) { + pRTS->m_webvtt_allow_clear = true; + } + } + } + } else if (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream; #if USE_LIBASS if (pRTS->m_LibassContext.IsLibassActive()) { ass_process_chunk(pRTS->m_LibassContext.m_track.get(), (char*)pSample->data.data(), (int)pSample->data.size(), pSample->rtStart / 10000, (pSample->rtStop - pSample->rtStart) / 10000); - } else -#endif - { + } else +#endif + { CStringW str = UTF8To16(CStringA((LPCSTR)pSample->data.data(), (int)pSample->data.size())); - FastTrim(str); - if (!str.IsEmpty()) { - STSEntry stse; - int fields = m_mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9; - if (pRTS->event_param == 0b011111000001) { // non-standard variant - fields = 4; - } - CAtlList sl; - ExplodeNoTrim(str, sl, ',', fields); - if (sl.GetCount() == (size_t)fields) { - stse.readorder = wcstol(sl.RemoveHead(), nullptr, 10); - stse.layer = wcstol(sl.RemoveHead(), nullptr, 10); - stse.style = sl.RemoveHead(); // no trim, its value is a lookup key - if (fields >= 9) { - stse.actor = sl.RemoveHead().Trim(); - stse.marginRect.left = wcstol(sl.RemoveHead(), nullptr, 10); - stse.marginRect.right = wcstol(sl.RemoveHead(), nullptr, 10); - stse.marginRect.top = stse.marginRect.bottom = wcstol(sl.RemoveHead(), nullptr, 10); - } - if (fields == 10) { - stse.marginRect.bottom = wcstol(sl.RemoveHead(), nullptr, 10); - } - if (fields >= 9) { - stse.effect = sl.RemoveHead().Trim(); - } - stse.str = sl.RemoveHead().Trim(); - } else { - ASSERT(false); - } - - if (!stse.str.IsEmpty()) { - pRTS->Add(stse.str, true, pSample->rtStart, pSample->rtStop, - stse.style, stse.actor, stse.effect, stse.marginRect, stse.layer, stse.readorder); - bInvalidate = true; - } - } - } - } else if (m_mt.subtype == MEDIASUBTYPE_VOBSUB) { - CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; - pVSS->Add(pSample->rtStart, pSample->rtStop, pSample->data.data(), (int)pSample->data.size()); - } else if (IsRLECodedSub(&m_mt)) { - CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; - pRLECodedSubtitle->ParseSample(pSample->rtStart, pSample->rtStop, pSample->data.data(), (int)pSample->data.size()); - } - } - - return bInvalidate ? pSample->rtStart : -1; -} - -void CSubtitleInputPin::InvalidateSamples() -{ - m_bStopDecoding = true; - { - std::lock_guard lock(m_mutexQueue); - m_sampleQueue.clear(); - m_bStopDecoding = false; - } -} + FastTrim(str); + if (!str.IsEmpty()) { + STSEntry stse; + int fields = m_mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9; + if (pRTS->event_param == 0b011111000001) { // non-standard variant + fields = 4; + } + CAtlList sl; + ExplodeNoTrim(str, sl, ',', fields); + if (sl.GetCount() == (size_t)fields) { + stse.readorder = wcstol(sl.RemoveHead(), nullptr, 10); + stse.layer = wcstol(sl.RemoveHead(), nullptr, 10); + stse.style = sl.RemoveHead(); // no trim, its value is a lookup key + if (fields >= 9) { + stse.actor = sl.RemoveHead().Trim(); + stse.marginRect.left = wcstol(sl.RemoveHead(), nullptr, 10); + stse.marginRect.right = wcstol(sl.RemoveHead(), nullptr, 10); + stse.marginRect.top = stse.marginRect.bottom = wcstol(sl.RemoveHead(), nullptr, 10); + } + if (fields == 10) { + stse.marginRect.bottom = wcstol(sl.RemoveHead(), nullptr, 10); + } + if (fields >= 9) { + stse.effect = sl.RemoveHead().Trim(); + } + stse.str = sl.RemoveHead().Trim(); + } else { + ASSERT(false); + } + + if (!stse.str.IsEmpty()) { + pRTS->Add(stse.str, true, pSample->rtStart, pSample->rtStop, + stse.style, stse.actor, stse.effect, stse.marginRect, stse.layer, stse.readorder); + bInvalidate = true; + } + } + } + } else if (m_mt.subtype == MEDIASUBTYPE_VOBSUB) { + CVobSubStream* pVSS = (CVobSubStream*)(ISubStream*)m_pSubStream; + pVSS->Add(pSample->rtStart, pSample->rtStop, pSample->data.data(), (int)pSample->data.size()); + } else if (IsRLECodedSub(&m_mt)) { + CRLECodedSubtitle* pRLECodedSubtitle = (CRLECodedSubtitle*)(ISubStream*)m_pSubStream; + pRLECodedSubtitle->ParseSample(pSample->rtStart, pSample->rtStop, pSample->data.data(), (int)pSample->data.size()); + } + } + + return bInvalidate ? pSample->rtStart : -1; +} + +void CSubtitleInputPin::InvalidateSamples() +{ + m_bStopDecoding = true; + { + std::lock_guard lock(m_mutexQueue); + m_sampleQueue.clear(); + m_bStopDecoding = false; + } +} diff --git a/src/Subtitles/SubtitleInputPin.h b/src/Subtitles/SubtitleInputPin.h index 3a0d8a09385..c94635d3e15 100644 --- a/src/Subtitles/SubtitleInputPin.h +++ b/src/Subtitles/SubtitleInputPin.h @@ -1,86 +1,86 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "../SubPic/ISubPic.h" - -// -// CSubtitleInputPin -// - -class CSubtitleInputPin : public CBaseInputPin -{ - static const REFERENCE_TIME INVALID_TIME = _I64_MIN; - - CCritSec m_csReceive; - - CCritSec* m_pSubLock; - CComPtr m_pSubStream; - - struct SubtitleSample { - REFERENCE_TIME rtStart, rtStop; - std::vector data; - - SubtitleSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t len) - : rtStart(rtStart) - , rtStop(rtStop) - , data(pData, pData + len) {} - }; - - std::list> m_sampleQueue; - - bool m_bExitDecodingThread, m_bStopDecoding; - std::thread m_decodeThread; - std::mutex m_mutexQueue; // to protect m_sampleQueue - std::condition_variable m_condQueueReady; - - void DecodeSamples(); - REFERENCE_TIME DecodeSample(const std::unique_ptr& pSample); - void InvalidateSamples(); - -protected: - virtual void AddSubStream(ISubStream* pSubStream) = 0; - virtual void RemoveSubStream(ISubStream* pSubStream) = 0; - virtual void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) = 0; - - bool IsRLECodedSub(const CMediaType* pmt) const; - -public: - CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); - ~CSubtitleInputPin(); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT CompleteConnect(IPin* pReceivePin); - HRESULT BreakConnect(); - STDMETHODIMP ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP EndOfStream(void); - - ISubStream* GetSubStream() { return m_pSubStream; } -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "../SubPic/ISubPic.h" + +// +// CSubtitleInputPin +// + +class CSubtitleInputPin : public CBaseInputPin +{ + static const REFERENCE_TIME INVALID_TIME = _I64_MIN; + + CCritSec m_csReceive; + + CCritSec* m_pSubLock; + CComPtr m_pSubStream; + + struct SubtitleSample { + REFERENCE_TIME rtStart, rtStop; + std::vector data; + + SubtitleSample(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BYTE* pData, size_t len) + : rtStart(rtStart) + , rtStop(rtStop) + , data(pData, pData + len) {} + }; + + std::list> m_sampleQueue; + + bool m_bExitDecodingThread, m_bStopDecoding; + std::thread m_decodeThread; + std::mutex m_mutexQueue; // to protect m_sampleQueue + std::condition_variable m_condQueueReady; + + void DecodeSamples(); + REFERENCE_TIME DecodeSample(const std::unique_ptr& pSample); + void InvalidateSamples(); + +protected: + virtual void AddSubStream(ISubStream* pSubStream) = 0; + virtual void RemoveSubStream(ISubStream* pSubStream) = 0; + virtual void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) = 0; + + bool IsRLECodedSub(const CMediaType* pmt) const; + +public: + CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); + ~CSubtitleInputPin(); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT CompleteConnect(IPin* pReceivePin); + HRESULT BreakConnect(); + STDMETHODIMP ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP EndOfStream(void); + + ISubStream* GetSubStream() { return m_pSubStream; } +}; diff --git a/src/Subtitles/Subtitles.vcxproj b/src/Subtitles/Subtitles.vcxproj index 4e800c43061..63b19cecebc 100644 --- a/src/Subtitles/Subtitles.vcxproj +++ b/src/Subtitles/Subtitles.vcxproj @@ -1,117 +1,117 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {5E56335F-0FB1-4EEA-B240-D8DC5E0608E4} - Subtitles - MFCProj - Subtitles - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\include;..\thirdparty;..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - 6509;26812 - 6509;26812 - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {19677dfd-c020-434d-9cb1-d0f105e72770} - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {5E56335F-0FB1-4EEA-B240-D8DC5E0608E4} + Subtitles + MFCProj + Subtitles + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\include;..\thirdparty;..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + 6509;26812 + 6509;26812 + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {19677dfd-c020-434d-9cb1-d0f105e72770} + + + + + + diff --git a/src/Subtitles/Subtitles.vcxproj.filters b/src/Subtitles/Subtitles.vcxproj.filters index 47600170d57..018c96b3268 100644 --- a/src/Subtitles/Subtitles.vcxproj.filters +++ b/src/Subtitles/Subtitles.vcxproj.filters @@ -1,176 +1,176 @@ - - - - - {11712c7b-74ef-4965-a813-5290f06e30a4} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {405fa87b-b576-4329-99eb-f6c49c3a84be} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - + + + + + {11712c7b-74ef-4965-a813-5290f06e30a4} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {405fa87b-b576-4329-99eb-f6c49c3a84be} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + diff --git a/src/Subtitles/TextFile.cpp b/src/Subtitles/TextFile.cpp index 12c2c50cc19..4bddbecdd8a 100644 --- a/src/Subtitles/TextFile.cpp +++ b/src/Subtitles/TextFile.cpp @@ -1,887 +1,887 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include -#include "TextFile.h" -#include "Utf8.h" - -#define TEXTFILE_BUFFER_SIZE (64 * 1024) - -CTextFile::CTextFile(enc e) - : m_encoding(e) - , m_defaultencoding(e) - , m_fallbackencoding(DEFAULT_ENCODING) - , m_offset(0) - , m_posInFile(0) - , m_posInBuffer(0) - , m_nInBuffer(0) -{ - m_buffer.Allocate(TEXTFILE_BUFFER_SIZE); - m_wbuffer.Allocate(TEXTFILE_BUFFER_SIZE); -} - -bool CTextFile::Open(LPCTSTR lpszFileName) -{ - if (!__super::Open(lpszFileName, modeRead | typeBinary | shareDenyNone)) { - return false; - } - - m_encoding = m_defaultencoding; - m_offset = 0; - m_nInBuffer = m_posInBuffer = 0; - - try { - if (__super::GetLength() >= 2) { - WORD w; - if (sizeof(w) != Read(&w, sizeof(w))) { - return Close(), false; - } - - if (w == 0xfeff) { - m_encoding = LE16; - m_offset = 2; - } else if (w == 0xfffe) { - m_encoding = BE16; - m_offset = 2; - } else if (w == 0xbbef && __super::GetLength() >= 3) { - BYTE b; - if (sizeof(b) != Read(&b, sizeof(b))) { - return Close(), false; - } - - if (b == 0xbf) { - m_encoding = UTF8; - m_offset = 3; - } - } - } - - if (m_encoding == DEFAULT_ENCODING) { - if (!ReopenAsText()) { - return false; - } - } else if (m_offset == 0) { // No BOM detected, ensure the file is read from the beginning - Seek(0, begin); - } else { - m_posInFile = __super::GetPosition(); - } - } catch (CFileException*) { - return false; - } - - return true; -} - -bool CTextFile::ReopenAsText() -{ - CString strFileName = m_strFileName; - - __super::Close(); // CWebTextFile::Close() would delete the temp file if we called it... - - return !!__super::Open(strFileName, modeRead | typeText | shareDenyNone); -} - -bool CTextFile::Save(LPCTSTR lpszFileName, enc e) -{ - if (!__super::Open(lpszFileName, modeCreate | modeWrite | shareDenyWrite | (e == DEFAULT_ENCODING ? typeText : typeBinary))) { - return false; - } - - if (e == UTF8) { - BYTE b[3] = {0xef, 0xbb, 0xbf}; - Write(b, sizeof(b)); - } else if (e == LE16) { - BYTE b[2] = {0xff, 0xfe}; - Write(b, sizeof(b)); - } else if (e == BE16) { - BYTE b[2] = {0xfe, 0xff}; - Write(b, sizeof(b)); - } - - m_encoding = e; - - return true; -} - -void CTextFile::SetEncoding(enc e) -{ - m_encoding = e; -} - -void CTextFile::SetFallbackEncoding(enc e) -{ - m_fallbackencoding = e; -} - -CTextFile::enc CTextFile::GetEncoding() -{ - return m_encoding; -} - -bool CTextFile::IsUnicode() -{ - return m_encoding == UTF8 || m_encoding == LE16 || m_encoding == BE16; -} - -// CFile - -CString CTextFile::GetFilePath() const -{ - // to avoid a CException coming from CTime - return m_strFileName; // __super::GetFilePath(); -} - -// CStdioFile - -ULONGLONG CTextFile::GetPosition() const -{ - return (__super::GetPosition() - m_offset - (m_nInBuffer - m_posInBuffer)); -} - -ULONGLONG CTextFile::GetLength() const -{ - return (__super::GetLength() - m_offset); -} - -ULONGLONG CTextFile::Seek(LONGLONG lOff, UINT nFrom) -{ - ULONGLONG newPos; - - // Try to reuse the buffer if any - if (m_nInBuffer > 0) { - ULONGLONG pos = GetPosition(); - ULONGLONG len = GetLength(); - - switch (nFrom) { - default: - case begin: - break; - case current: - lOff = pos + lOff; - break; - case end: - lOff = len - lOff; - break; - } - - lOff = std::max((LONGLONG)std::min((ULONGLONG)lOff, len), 0ll); - - m_posInBuffer += LONGLONG(ULONGLONG(lOff) - pos); - if (m_posInBuffer < 0 || m_posInBuffer >= m_nInBuffer) { - // If we would have to end up out of the buffer, we just reset it and seek normally - m_nInBuffer = m_posInBuffer = 0; - newPos = __super::Seek(lOff + m_offset, begin) - m_offset; - } else { // If we can reuse the buffer, we have nothing special to do - newPos = ULONGLONG(lOff); - } - } else { // No buffer, we can use the base implementation - if (nFrom == begin) { - lOff += m_offset; - } - newPos = __super::Seek(lOff, nFrom) - m_offset; - } - - m_posInFile = newPos + m_offset + (m_nInBuffer - m_posInBuffer); - - return newPos; -} - -void CTextFile::WriteString(LPCSTR lpsz/*CStringA str*/) -{ - CStringA str(lpsz); - - if (m_encoding == DEFAULT_ENCODING) { - __super::WriteString(AToT(str)); - } else if (m_encoding == ANSI) { - str.Replace("\n", "\r\n"); - Write((LPCSTR)str, str.GetLength()); - } else if (m_encoding == UTF8) { - WriteString(AToW(str)); - } else if (m_encoding == LE16) { - WriteString(AToW(str)); - } else if (m_encoding == BE16) { - WriteString(AToW(str)); - } -} - -CStringA ConvertUnicodeToUTF8(const CStringW& input) -{ - if (input.IsEmpty()) { - return ""; - } - CStringA utf8; - int cc = 0; - if ((cc = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, 0, 0) - 1) > 0) - { - char* buf = utf8.GetBuffer(cc); - if (buf) { - WideCharToMultiByte(CP_UTF8, 0, input, -1, buf, cc, 0, 0); - } - utf8.ReleaseBuffer(); - } - return utf8; -} - -void CTextFile::WriteString(LPCWSTR lpsz/*CStringW str*/) -{ - CStringW str(lpsz); - - if (m_encoding == DEFAULT_ENCODING) { - __super::WriteString(WToT(str)); - } else if (m_encoding == ANSI) { - str.Replace(L"\n", L"\r\n"); - CStringA stra(str); // TODO: codepage - Write((LPCSTR)stra, stra.GetLength()); - } else if (m_encoding == UTF8) { - str.Replace(L"\n", L"\r\n"); - CStringA utf8data = ConvertUnicodeToUTF8(str); - Write((LPCSTR)utf8data, utf8data.GetLength()); - } else if (m_encoding == LE16) { - str.Replace(L"\n", L"\r\n"); - Write((LPCWSTR)str, str.GetLength() * 2); - } else if (m_encoding == BE16) { - str.Replace(L"\n", L"\r\n"); - for (unsigned int i = 0, l = str.GetLength(); i < l; i++) { - str.SetAt(i, ((str[i] >> 8) & 0x00ff) | ((str[i] << 8) & 0xff00)); - } - Write((LPCWSTR)str, str.GetLength() * 2); - } -} - -bool CTextFile::FillBuffer() -{ - if (m_posInBuffer < m_nInBuffer) { - m_nInBuffer -= m_posInBuffer; - memcpy(m_buffer, &m_buffer[m_posInBuffer], (size_t)m_nInBuffer * sizeof(char)); - } else { - m_nInBuffer = 0; - } - m_posInBuffer = 0; - - UINT nBytesRead; - try { - nBytesRead = __super::Read(&m_buffer[m_nInBuffer], UINT(TEXTFILE_BUFFER_SIZE - m_nInBuffer) * sizeof(char)); - } catch (...) { - return true; // signal EOF in case of exception - } - if (nBytesRead) { - m_nInBuffer += nBytesRead; - } - - // Workaround for buggy text files that contain a duplicate UTF BOM - if (m_posInFile == m_offset && m_offset >= 2 && m_nInBuffer > 3) { - if (m_buffer[0] == '\xEF' && m_buffer[1] == '\xBB' && m_buffer[2] == '\xBF') { - m_posInBuffer = 3; - } else if (m_buffer[0] == '\xFE' && m_buffer[1] == '\xFF' || m_buffer[0] == '\xFF' && m_buffer[1] == '\xEF') { - m_posInBuffer = 2; - } - } - - m_posInFile = __super::GetPosition(); - - return !nBytesRead; -} - -ULONGLONG CTextFile::GetPositionFastBuffered() const -{ - return (m_posInFile - m_offset - (m_nInBuffer - m_posInBuffer)); -} - -BOOL CTextFile::ReadString(CStringA& str) -{ - bool fEOF = true; - - str.Truncate(0); - - if (m_encoding == DEFAULT_ENCODING) { - CString s; - fEOF = !__super::ReadString(s); - str = TToA(s); - // For consistency with other encodings, we continue reading - // the file even when a NUL char is encountered. - char c; - while (fEOF && (Read(&c, sizeof(c)) == sizeof(c))) { - str += c; - fEOF = !__super::ReadString(s); - str += TToA(s); - } - } else if (m_encoding == ANSI) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - - for (nCharsRead = 0; m_posInBuffer + nCharsRead < m_nInBuffer; nCharsRead++) { - if (m_buffer[m_posInBuffer + nCharsRead] == '\n') { - break; - } else if (m_buffer[m_posInBuffer + nCharsRead] == '\r') { - break; - } - } - - str.Append(&m_buffer[m_posInBuffer], nCharsRead); - - m_posInBuffer += nCharsRead; - while (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\r') { - m_posInBuffer++; - } - if (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer++; - } - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } else if (m_encoding == UTF8) { - ULONGLONG lineStartPos = GetPositionFastBuffered(); - bool bValid = true; - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - char* abuffer = (char*)(WCHAR*)m_wbuffer; - - for (nCharsRead = 0; m_posInBuffer < m_nInBuffer; m_posInBuffer++, nCharsRead++) { - if (Utf8::isSingleByte(m_buffer[m_posInBuffer])) { // 0xxxxxxx - abuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; - } else if (Utf8::isFirstOfMultibyte(m_buffer[m_posInBuffer])) { - int nContinuationBytes = Utf8::continuationBytes(m_buffer[m_posInBuffer]); - ASSERT(bValid); - - if (m_posInBuffer + nContinuationBytes >= m_nInBuffer) { - // If we are at the end of the file, the buffer won't be full - // and we won't be able to read any more continuation bytes. - bValid = (m_nInBuffer == TEXTFILE_BUFFER_SIZE); - break; - } else { - for (int j = 1; j <= nContinuationBytes; j++) { - if (!Utf8::isContinuation(m_buffer[m_posInBuffer + j])) { - bValid = false; - } - } - - switch (nContinuationBytes) { - case 0: // 0xxxxxxx - abuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; - break; - case 1: // 110xxxxx 10xxxxxx - case 2: // 1110xxxx 10xxxxxx 10xxxxxx - case 3: // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - // Unsupported for non unicode strings - abuffer[nCharsRead] = '?'; - break; - } - m_posInBuffer += nContinuationBytes; - } - } else { - bValid = false; - TRACE(_T("Invalid UTF8 character found\n")); - } - - if (!bValid) { - abuffer[nCharsRead] = '?'; - m_posInBuffer++; - nCharsRead++; - break; - } else if (abuffer[nCharsRead] == '\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer++; - break; - } else if (abuffer[nCharsRead] == '\r') { - nCharsRead--; // Skip \r - } - } - - if (bValid || m_offset) { - str.Append(abuffer, nCharsRead); - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } else { - // Switch to text and read again - m_encoding = m_fallbackencoding; - // Stop using the buffer - m_posInBuffer = m_nInBuffer = 0; - - fEOF = !ReopenAsText(); - - if (!fEOF) { - // Seek back to the beginning of the line where we stopped - Seek(lineStartPos, begin); - - fEOF = !ReadString(str); - } - } - } while (bValid && !bLineEndFound); - } else if (m_encoding == LE16) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - WCHAR* wbuffer = (WCHAR*)&m_buffer[m_posInBuffer]; - char* abuffer = (char*)(WCHAR*)m_wbuffer; - - for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { - if (wbuffer[nCharsRead] == L'\n') { - break; // Stop at end of line - } else if (wbuffer[nCharsRead] == L'\r') { - break; // Skip \r - } else if (!(wbuffer[nCharsRead] & 0xff00)) { - abuffer[nCharsRead] = char(wbuffer[nCharsRead] & 0xff); - } else { - abuffer[nCharsRead] = '?'; - } - } - - str.Append(abuffer, nCharsRead); - - while (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\r') { - nCharsRead++; - m_posInBuffer += sizeof(WCHAR); - } - if (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\n') { - bLineEndFound = true; // Stop at end of line - nCharsRead++; - m_posInBuffer += sizeof(WCHAR); - } - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } else if (m_encoding == BE16) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - char* abuffer = (char*)(WCHAR*)m_wbuffer; - - for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { - if (!m_buffer[m_posInBuffer]) { - abuffer[nCharsRead] = m_buffer[m_posInBuffer + 1]; - } else { - abuffer[nCharsRead] = '?'; - } - - if (abuffer[nCharsRead] == '\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer += sizeof(WCHAR); - break; - } else if (abuffer[nCharsRead] == L'\r') { - nCharsRead--; // Skip \r - } - } - - str.Append(abuffer, nCharsRead); - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } - - return !fEOF; -} - -BOOL CTextFile::ReadString(CStringW& str) -{ - bool fEOF = true; - - str.Truncate(0); - - if (m_encoding == DEFAULT_ENCODING) { - CString s; - fEOF = !__super::ReadString(s); - str = TToW(s); - // For consistency with other encodings, we continue reading - // the file even when a NUL char is encountered. - char c; - while (fEOF && (Read(&c, sizeof(c)) == sizeof(c))) { - str += c; - fEOF = !__super::ReadString(s); - str += TToW(s); - } - } else if (m_encoding == ANSI) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - - for (nCharsRead = 0; m_posInBuffer + nCharsRead < m_nInBuffer; nCharsRead++) { - if (m_buffer[m_posInBuffer + nCharsRead] == '\n') { - break; - } else if (m_buffer[m_posInBuffer + nCharsRead] == '\r') { - break; - } - } - - // TODO: codepage - str.Append(CStringW(&m_buffer[m_posInBuffer], nCharsRead)); - - m_posInBuffer += nCharsRead; - while (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\r') { - m_posInBuffer++; - } - if (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer++; - } - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } else if (m_encoding == UTF8) { - ULONGLONG lineStartPos = GetPositionFastBuffered(); - bool bValid = true; - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - - for (nCharsRead = 0; m_posInBuffer < m_nInBuffer; m_posInBuffer++, nCharsRead++) { - if (Utf8::isSingleByte(m_buffer[m_posInBuffer])) { // 0xxxxxxx - m_wbuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; - } else if (Utf8::isFirstOfMultibyte(m_buffer[m_posInBuffer])) { - int nContinuationBytes = Utf8::continuationBytes(m_buffer[m_posInBuffer]); - if (m_posInBuffer + nContinuationBytes >= m_nInBuffer) { - // If we are at the end of the file, the buffer won't be full - // and we won't be able to read any more continuation bytes. - bValid = (m_nInBuffer == TEXTFILE_BUFFER_SIZE); - break; - } else { - for (int j = 1; j <= nContinuationBytes; j++) { - if (!Utf8::isContinuation(m_buffer[m_posInBuffer + j])) { //maybe redundant since MultiByteToWideChar should return zero if bad utf-8? - bValid = false; - } - } - if (bValid) { - int nWchars = MultiByteToWideChar(CP_UTF8, 0, &m_buffer[m_posInBuffer], nContinuationBytes + 1, nullptr, 0); - if (nWchars > 0) { - MultiByteToWideChar(CP_UTF8, 0, &m_buffer[m_posInBuffer], nContinuationBytes + 1, &m_wbuffer[nCharsRead], nWchars); - nCharsRead += nWchars - 1; //subtract one for loop increment - } else { - bValid = false; - } - } - m_posInBuffer += nContinuationBytes; - } - } else { - bValid = false; - TRACE(_T("Invalid UTF8 character found\n")); - } - - if (!bValid) { - m_wbuffer[nCharsRead] = L'?'; - m_posInBuffer++; - nCharsRead++; - break; - } else if (m_wbuffer[nCharsRead] == L'\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer++; - break; - } else if (m_wbuffer[nCharsRead] == L'\r') { - // check if it is followed by a '\n' - if (m_posInBuffer + 1 >= m_nInBuffer) { - bLineEndFound = FillBuffer(); - } - if (!bLineEndFound && Utf8::isSingleByte(m_buffer[m_posInBuffer+1]) && ((m_buffer[m_posInBuffer+1] & 0x7f) == L'\n')) { - nCharsRead--; // Skip '\r' - } else { - // Add the missing '\n' - nCharsRead++; - m_wbuffer[nCharsRead] = L'\n'; - bLineEndFound = true; - m_posInBuffer++; - break; - } - } - } - - if (bValid || m_offset) { - if (nCharsRead > 0) { - str.Append(m_wbuffer, nCharsRead); - } - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } else { - // Switch to text and read again - m_encoding = m_fallbackencoding; - // Stop using the buffer - m_posInBuffer = m_nInBuffer = 0; - - fEOF = !ReopenAsText(); - - if (!fEOF) { - // Seek back to the beginning of the line where we stopped - Seek(lineStartPos, begin); - - fEOF = !ReadString(str); - } - } - } while (bValid && !bLineEndFound); - } else if (m_encoding == LE16) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - WCHAR* wbuffer = (WCHAR*)&m_buffer[m_posInBuffer]; - - for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { - if (wbuffer[nCharsRead] == L'\n') { - break; // Stop at end of line - } else if (wbuffer[nCharsRead] == L'\r') { - break; // Skip \r - } - } - - str.Append(wbuffer, nCharsRead); - - while (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\r') { - nCharsRead++; - m_posInBuffer += sizeof(WCHAR); - } - if (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\n') { - bLineEndFound = true; // Stop at end of line - nCharsRead++; - m_posInBuffer += sizeof(WCHAR); - } - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } else if (m_encoding == BE16) { - bool bLineEndFound = false; - fEOF = false; - - do { - int nCharsRead; - - for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { - m_wbuffer[nCharsRead] = ((WCHAR(m_buffer[m_posInBuffer]) << 8) & 0xff00) | (WCHAR(m_buffer[m_posInBuffer + 1]) & 0x00ff); - if (m_wbuffer[nCharsRead] == L'\n') { - bLineEndFound = true; // Stop at end of line - m_posInBuffer += sizeof(WCHAR); - break; - } else if (m_wbuffer[nCharsRead] == L'\r') { - nCharsRead--; // Skip \r - } - } - - str.Append(m_wbuffer, nCharsRead); - - if (!bLineEndFound) { - bLineEndFound = FillBuffer(); - if (!nCharsRead) { - fEOF = bLineEndFound; - } - } - } while (!bLineEndFound); - } - - return !fEOF; -} - -// -// CWebTextFile -// - -CWebTextFile::CWebTextFile(CTextFile::enc e, LONGLONG llMaxSize) - : CTextFile(e) - , m_llMaxSize(llMaxSize) -{ -} - -bool CWebTextFile::Open(LPCTSTR lpszFileName) -{ - CString fn(lpszFileName); - - if (fn.Find(_T("://")) == -1) { - return __super::Open(lpszFileName); - } - - try { - CInternetSession is; - - CAutoPtr f(is.OpenURL(fn, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT)); - if (!f) { - return false; - } - - TCHAR path[MAX_PATH]; - GetTempPath(MAX_PATH, path); - - fn = path + fn.Mid(fn.ReverseFind('/') + 1); - int i = fn.Find(_T("?")); - if (i > 0) { - fn = fn.Left(i); - } - CFile temp; - if (!temp.Open(fn, modeCreate | modeWrite | typeBinary | shareDenyWrite)) { - f->Close(); - return false; - } - - BYTE buff[1024]; - int len, total = 0; - while ((len = f->Read(buff, 1024)) > 0) { - total += len; - temp.Write(buff, len); - if (m_llMaxSize > 0 && total >= m_llMaxSize) { - break; - } - } - - m_tempfn = fn; - - f->Close(); // must close it because the desctructor doesn't seem to do it and we will get an exception when "is" is destroying - } catch (CInternetException* ie) { - ie->Delete(); - return false; - } - - return __super::Open(m_tempfn); -} - -bool CWebTextFile::Save(LPCTSTR lpszFileName, enc e) -{ - // CWebTextFile is read-only... - ASSERT(0); - return false; -} - -void CWebTextFile::Close() -{ - __super::Close(); - - if (!m_tempfn.IsEmpty()) { - _tremove(m_tempfn); - m_tempfn.Empty(); - } -} - -/////////////////////////////////////////////////////////////// - -CStringW AToW(CStringA str) -{ - CStringW ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (WCHAR)(BYTE)str[i]; - } - return ret; -} - -CStringA WToA(CStringW str) -{ - CStringA ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (CHAR)(WORD)str[i]; - } - return ret; -} - -CString AToT(CStringA str) -{ -#ifdef UNICODE - CString ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (TCHAR)(BYTE)str[i]; - } - return ret; -#else - return str; -#endif -} - -CString WToT(CStringW str) -{ -#ifdef UNICODE - return str; -#else - CString ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (TCHAR)(WORD)str[i]; - } - return ret; -#endif -} - -CStringA TToA(CString str) -{ -#ifdef UNICODE - CStringA ret; - for (int i = 0, j = str.GetLength(); i < j; i++) { - ret += (CHAR)(BYTE)str[i]; - } - return ret; -#else - return str; -#endif -} - -CStringW TToW(CString str) -{ -#ifdef UNICODE - return str; -#else - CStringW ret; - for (size_t i = 0, j = str.GetLength(); i < j; i++) { - ret += (WCHAR)(BYTE)str[i]; - } - return ret; -#endif -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include +#include "TextFile.h" +#include "Utf8.h" + +#define TEXTFILE_BUFFER_SIZE (64 * 1024) + +CTextFile::CTextFile(enc e) + : m_encoding(e) + , m_defaultencoding(e) + , m_fallbackencoding(DEFAULT_ENCODING) + , m_offset(0) + , m_posInFile(0) + , m_posInBuffer(0) + , m_nInBuffer(0) +{ + m_buffer.Allocate(TEXTFILE_BUFFER_SIZE); + m_wbuffer.Allocate(TEXTFILE_BUFFER_SIZE); +} + +bool CTextFile::Open(LPCTSTR lpszFileName) +{ + if (!__super::Open(lpszFileName, modeRead | typeBinary | shareDenyNone)) { + return false; + } + + m_encoding = m_defaultencoding; + m_offset = 0; + m_nInBuffer = m_posInBuffer = 0; + + try { + if (__super::GetLength() >= 2) { + WORD w; + if (sizeof(w) != Read(&w, sizeof(w))) { + return Close(), false; + } + + if (w == 0xfeff) { + m_encoding = LE16; + m_offset = 2; + } else if (w == 0xfffe) { + m_encoding = BE16; + m_offset = 2; + } else if (w == 0xbbef && __super::GetLength() >= 3) { + BYTE b; + if (sizeof(b) != Read(&b, sizeof(b))) { + return Close(), false; + } + + if (b == 0xbf) { + m_encoding = UTF8; + m_offset = 3; + } + } + } + + if (m_encoding == DEFAULT_ENCODING) { + if (!ReopenAsText()) { + return false; + } + } else if (m_offset == 0) { // No BOM detected, ensure the file is read from the beginning + Seek(0, begin); + } else { + m_posInFile = __super::GetPosition(); + } + } catch (CFileException*) { + return false; + } + + return true; +} + +bool CTextFile::ReopenAsText() +{ + CString strFileName = m_strFileName; + + __super::Close(); // CWebTextFile::Close() would delete the temp file if we called it... + + return !!__super::Open(strFileName, modeRead | typeText | shareDenyNone); +} + +bool CTextFile::Save(LPCTSTR lpszFileName, enc e) +{ + if (!__super::Open(lpszFileName, modeCreate | modeWrite | shareDenyWrite | (e == DEFAULT_ENCODING ? typeText : typeBinary))) { + return false; + } + + if (e == UTF8) { + BYTE b[3] = {0xef, 0xbb, 0xbf}; + Write(b, sizeof(b)); + } else if (e == LE16) { + BYTE b[2] = {0xff, 0xfe}; + Write(b, sizeof(b)); + } else if (e == BE16) { + BYTE b[2] = {0xfe, 0xff}; + Write(b, sizeof(b)); + } + + m_encoding = e; + + return true; +} + +void CTextFile::SetEncoding(enc e) +{ + m_encoding = e; +} + +void CTextFile::SetFallbackEncoding(enc e) +{ + m_fallbackencoding = e; +} + +CTextFile::enc CTextFile::GetEncoding() +{ + return m_encoding; +} + +bool CTextFile::IsUnicode() +{ + return m_encoding == UTF8 || m_encoding == LE16 || m_encoding == BE16; +} + +// CFile + +CString CTextFile::GetFilePath() const +{ + // to avoid a CException coming from CTime + return m_strFileName; // __super::GetFilePath(); +} + +// CStdioFile + +ULONGLONG CTextFile::GetPosition() const +{ + return (__super::GetPosition() - m_offset - (m_nInBuffer - m_posInBuffer)); +} + +ULONGLONG CTextFile::GetLength() const +{ + return (__super::GetLength() - m_offset); +} + +ULONGLONG CTextFile::Seek(LONGLONG lOff, UINT nFrom) +{ + ULONGLONG newPos; + + // Try to reuse the buffer if any + if (m_nInBuffer > 0) { + ULONGLONG pos = GetPosition(); + ULONGLONG len = GetLength(); + + switch (nFrom) { + default: + case begin: + break; + case current: + lOff = pos + lOff; + break; + case end: + lOff = len - lOff; + break; + } + + lOff = std::max((LONGLONG)std::min((ULONGLONG)lOff, len), 0ll); + + m_posInBuffer += LONGLONG(ULONGLONG(lOff) - pos); + if (m_posInBuffer < 0 || m_posInBuffer >= m_nInBuffer) { + // If we would have to end up out of the buffer, we just reset it and seek normally + m_nInBuffer = m_posInBuffer = 0; + newPos = __super::Seek(lOff + m_offset, begin) - m_offset; + } else { // If we can reuse the buffer, we have nothing special to do + newPos = ULONGLONG(lOff); + } + } else { // No buffer, we can use the base implementation + if (nFrom == begin) { + lOff += m_offset; + } + newPos = __super::Seek(lOff, nFrom) - m_offset; + } + + m_posInFile = newPos + m_offset + (m_nInBuffer - m_posInBuffer); + + return newPos; +} + +void CTextFile::WriteString(LPCSTR lpsz/*CStringA str*/) +{ + CStringA str(lpsz); + + if (m_encoding == DEFAULT_ENCODING) { + __super::WriteString(AToT(str)); + } else if (m_encoding == ANSI) { + str.Replace("\n", "\r\n"); + Write((LPCSTR)str, str.GetLength()); + } else if (m_encoding == UTF8) { + WriteString(AToW(str)); + } else if (m_encoding == LE16) { + WriteString(AToW(str)); + } else if (m_encoding == BE16) { + WriteString(AToW(str)); + } +} + +CStringA ConvertUnicodeToUTF8(const CStringW& input) +{ + if (input.IsEmpty()) { + return ""; + } + CStringA utf8; + int cc = 0; + if ((cc = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, 0, 0) - 1) > 0) + { + char* buf = utf8.GetBuffer(cc); + if (buf) { + WideCharToMultiByte(CP_UTF8, 0, input, -1, buf, cc, 0, 0); + } + utf8.ReleaseBuffer(); + } + return utf8; +} + +void CTextFile::WriteString(LPCWSTR lpsz/*CStringW str*/) +{ + CStringW str(lpsz); + + if (m_encoding == DEFAULT_ENCODING) { + __super::WriteString(WToT(str)); + } else if (m_encoding == ANSI) { + str.Replace(L"\n", L"\r\n"); + CStringA stra(str); // TODO: codepage + Write((LPCSTR)stra, stra.GetLength()); + } else if (m_encoding == UTF8) { + str.Replace(L"\n", L"\r\n"); + CStringA utf8data = ConvertUnicodeToUTF8(str); + Write((LPCSTR)utf8data, utf8data.GetLength()); + } else if (m_encoding == LE16) { + str.Replace(L"\n", L"\r\n"); + Write((LPCWSTR)str, str.GetLength() * 2); + } else if (m_encoding == BE16) { + str.Replace(L"\n", L"\r\n"); + for (unsigned int i = 0, l = str.GetLength(); i < l; i++) { + str.SetAt(i, ((str[i] >> 8) & 0x00ff) | ((str[i] << 8) & 0xff00)); + } + Write((LPCWSTR)str, str.GetLength() * 2); + } +} + +bool CTextFile::FillBuffer() +{ + if (m_posInBuffer < m_nInBuffer) { + m_nInBuffer -= m_posInBuffer; + memcpy(m_buffer, &m_buffer[m_posInBuffer], (size_t)m_nInBuffer * sizeof(char)); + } else { + m_nInBuffer = 0; + } + m_posInBuffer = 0; + + UINT nBytesRead; + try { + nBytesRead = __super::Read(&m_buffer[m_nInBuffer], UINT(TEXTFILE_BUFFER_SIZE - m_nInBuffer) * sizeof(char)); + } catch (...) { + return true; // signal EOF in case of exception + } + if (nBytesRead) { + m_nInBuffer += nBytesRead; + } + + // Workaround for buggy text files that contain a duplicate UTF BOM + if (m_posInFile == m_offset && m_offset >= 2 && m_nInBuffer > 3) { + if (m_buffer[0] == '\xEF' && m_buffer[1] == '\xBB' && m_buffer[2] == '\xBF') { + m_posInBuffer = 3; + } else if (m_buffer[0] == '\xFE' && m_buffer[1] == '\xFF' || m_buffer[0] == '\xFF' && m_buffer[1] == '\xEF') { + m_posInBuffer = 2; + } + } + + m_posInFile = __super::GetPosition(); + + return !nBytesRead; +} + +ULONGLONG CTextFile::GetPositionFastBuffered() const +{ + return (m_posInFile - m_offset - (m_nInBuffer - m_posInBuffer)); +} + +BOOL CTextFile::ReadString(CStringA& str) +{ + bool fEOF = true; + + str.Truncate(0); + + if (m_encoding == DEFAULT_ENCODING) { + CString s; + fEOF = !__super::ReadString(s); + str = TToA(s); + // For consistency with other encodings, we continue reading + // the file even when a NUL char is encountered. + char c; + while (fEOF && (Read(&c, sizeof(c)) == sizeof(c))) { + str += c; + fEOF = !__super::ReadString(s); + str += TToA(s); + } + } else if (m_encoding == ANSI) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + + for (nCharsRead = 0; m_posInBuffer + nCharsRead < m_nInBuffer; nCharsRead++) { + if (m_buffer[m_posInBuffer + nCharsRead] == '\n') { + break; + } else if (m_buffer[m_posInBuffer + nCharsRead] == '\r') { + break; + } + } + + str.Append(&m_buffer[m_posInBuffer], nCharsRead); + + m_posInBuffer += nCharsRead; + while (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\r') { + m_posInBuffer++; + } + if (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer++; + } + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } else if (m_encoding == UTF8) { + ULONGLONG lineStartPos = GetPositionFastBuffered(); + bool bValid = true; + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + char* abuffer = (char*)(WCHAR*)m_wbuffer; + + for (nCharsRead = 0; m_posInBuffer < m_nInBuffer; m_posInBuffer++, nCharsRead++) { + if (Utf8::isSingleByte(m_buffer[m_posInBuffer])) { // 0xxxxxxx + abuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; + } else if (Utf8::isFirstOfMultibyte(m_buffer[m_posInBuffer])) { + int nContinuationBytes = Utf8::continuationBytes(m_buffer[m_posInBuffer]); + ASSERT(bValid); + + if (m_posInBuffer + nContinuationBytes >= m_nInBuffer) { + // If we are at the end of the file, the buffer won't be full + // and we won't be able to read any more continuation bytes. + bValid = (m_nInBuffer == TEXTFILE_BUFFER_SIZE); + break; + } else { + for (int j = 1; j <= nContinuationBytes; j++) { + if (!Utf8::isContinuation(m_buffer[m_posInBuffer + j])) { + bValid = false; + } + } + + switch (nContinuationBytes) { + case 0: // 0xxxxxxx + abuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; + break; + case 1: // 110xxxxx 10xxxxxx + case 2: // 1110xxxx 10xxxxxx 10xxxxxx + case 3: // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // Unsupported for non unicode strings + abuffer[nCharsRead] = '?'; + break; + } + m_posInBuffer += nContinuationBytes; + } + } else { + bValid = false; + TRACE(_T("Invalid UTF8 character found\n")); + } + + if (!bValid) { + abuffer[nCharsRead] = '?'; + m_posInBuffer++; + nCharsRead++; + break; + } else if (abuffer[nCharsRead] == '\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer++; + break; + } else if (abuffer[nCharsRead] == '\r') { + nCharsRead--; // Skip \r + } + } + + if (bValid || m_offset) { + str.Append(abuffer, nCharsRead); + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } else { + // Switch to text and read again + m_encoding = m_fallbackencoding; + // Stop using the buffer + m_posInBuffer = m_nInBuffer = 0; + + fEOF = !ReopenAsText(); + + if (!fEOF) { + // Seek back to the beginning of the line where we stopped + Seek(lineStartPos, begin); + + fEOF = !ReadString(str); + } + } + } while (bValid && !bLineEndFound); + } else if (m_encoding == LE16) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + WCHAR* wbuffer = (WCHAR*)&m_buffer[m_posInBuffer]; + char* abuffer = (char*)(WCHAR*)m_wbuffer; + + for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { + if (wbuffer[nCharsRead] == L'\n') { + break; // Stop at end of line + } else if (wbuffer[nCharsRead] == L'\r') { + break; // Skip \r + } else if (!(wbuffer[nCharsRead] & 0xff00)) { + abuffer[nCharsRead] = char(wbuffer[nCharsRead] & 0xff); + } else { + abuffer[nCharsRead] = '?'; + } + } + + str.Append(abuffer, nCharsRead); + + while (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\r') { + nCharsRead++; + m_posInBuffer += sizeof(WCHAR); + } + if (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\n') { + bLineEndFound = true; // Stop at end of line + nCharsRead++; + m_posInBuffer += sizeof(WCHAR); + } + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } else if (m_encoding == BE16) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + char* abuffer = (char*)(WCHAR*)m_wbuffer; + + for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { + if (!m_buffer[m_posInBuffer]) { + abuffer[nCharsRead] = m_buffer[m_posInBuffer + 1]; + } else { + abuffer[nCharsRead] = '?'; + } + + if (abuffer[nCharsRead] == '\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer += sizeof(WCHAR); + break; + } else if (abuffer[nCharsRead] == L'\r') { + nCharsRead--; // Skip \r + } + } + + str.Append(abuffer, nCharsRead); + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } + + return !fEOF; +} + +BOOL CTextFile::ReadString(CStringW& str) +{ + bool fEOF = true; + + str.Truncate(0); + + if (m_encoding == DEFAULT_ENCODING) { + CString s; + fEOF = !__super::ReadString(s); + str = TToW(s); + // For consistency with other encodings, we continue reading + // the file even when a NUL char is encountered. + char c; + while (fEOF && (Read(&c, sizeof(c)) == sizeof(c))) { + str += c; + fEOF = !__super::ReadString(s); + str += TToW(s); + } + } else if (m_encoding == ANSI) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + + for (nCharsRead = 0; m_posInBuffer + nCharsRead < m_nInBuffer; nCharsRead++) { + if (m_buffer[m_posInBuffer + nCharsRead] == '\n') { + break; + } else if (m_buffer[m_posInBuffer + nCharsRead] == '\r') { + break; + } + } + + // TODO: codepage + str.Append(CStringW(&m_buffer[m_posInBuffer], nCharsRead)); + + m_posInBuffer += nCharsRead; + while (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\r') { + m_posInBuffer++; + } + if (m_posInBuffer < m_nInBuffer && m_buffer[m_posInBuffer] == '\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer++; + } + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } else if (m_encoding == UTF8) { + ULONGLONG lineStartPos = GetPositionFastBuffered(); + bool bValid = true; + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + + for (nCharsRead = 0; m_posInBuffer < m_nInBuffer; m_posInBuffer++, nCharsRead++) { + if (Utf8::isSingleByte(m_buffer[m_posInBuffer])) { // 0xxxxxxx + m_wbuffer[nCharsRead] = m_buffer[m_posInBuffer] & 0x7f; + } else if (Utf8::isFirstOfMultibyte(m_buffer[m_posInBuffer])) { + int nContinuationBytes = Utf8::continuationBytes(m_buffer[m_posInBuffer]); + if (m_posInBuffer + nContinuationBytes >= m_nInBuffer) { + // If we are at the end of the file, the buffer won't be full + // and we won't be able to read any more continuation bytes. + bValid = (m_nInBuffer == TEXTFILE_BUFFER_SIZE); + break; + } else { + for (int j = 1; j <= nContinuationBytes; j++) { + if (!Utf8::isContinuation(m_buffer[m_posInBuffer + j])) { //maybe redundant since MultiByteToWideChar should return zero if bad utf-8? + bValid = false; + } + } + if (bValid) { + int nWchars = MultiByteToWideChar(CP_UTF8, 0, &m_buffer[m_posInBuffer], nContinuationBytes + 1, nullptr, 0); + if (nWchars > 0) { + MultiByteToWideChar(CP_UTF8, 0, &m_buffer[m_posInBuffer], nContinuationBytes + 1, &m_wbuffer[nCharsRead], nWchars); + nCharsRead += nWchars - 1; //subtract one for loop increment + } else { + bValid = false; + } + } + m_posInBuffer += nContinuationBytes; + } + } else { + bValid = false; + TRACE(_T("Invalid UTF8 character found\n")); + } + + if (!bValid) { + m_wbuffer[nCharsRead] = L'?'; + m_posInBuffer++; + nCharsRead++; + break; + } else if (m_wbuffer[nCharsRead] == L'\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer++; + break; + } else if (m_wbuffer[nCharsRead] == L'\r') { + // check if it is followed by a '\n' + if (m_posInBuffer + 1 >= m_nInBuffer) { + bLineEndFound = FillBuffer(); + } + if (!bLineEndFound && Utf8::isSingleByte(m_buffer[m_posInBuffer+1]) && ((m_buffer[m_posInBuffer+1] & 0x7f) == L'\n')) { + nCharsRead--; // Skip '\r' + } else { + // Add the missing '\n' + nCharsRead++; + m_wbuffer[nCharsRead] = L'\n'; + bLineEndFound = true; + m_posInBuffer++; + break; + } + } + } + + if (bValid || m_offset) { + if (nCharsRead > 0) { + str.Append(m_wbuffer, nCharsRead); + } + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } else { + // Switch to text and read again + m_encoding = m_fallbackencoding; + // Stop using the buffer + m_posInBuffer = m_nInBuffer = 0; + + fEOF = !ReopenAsText(); + + if (!fEOF) { + // Seek back to the beginning of the line where we stopped + Seek(lineStartPos, begin); + + fEOF = !ReadString(str); + } + } + } while (bValid && !bLineEndFound); + } else if (m_encoding == LE16) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + WCHAR* wbuffer = (WCHAR*)&m_buffer[m_posInBuffer]; + + for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { + if (wbuffer[nCharsRead] == L'\n') { + break; // Stop at end of line + } else if (wbuffer[nCharsRead] == L'\r') { + break; // Skip \r + } + } + + str.Append(wbuffer, nCharsRead); + + while (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\r') { + nCharsRead++; + m_posInBuffer += sizeof(WCHAR); + } + if (m_posInBuffer + 1 < m_nInBuffer && wbuffer[nCharsRead] == L'\n') { + bLineEndFound = true; // Stop at end of line + nCharsRead++; + m_posInBuffer += sizeof(WCHAR); + } + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } else if (m_encoding == BE16) { + bool bLineEndFound = false; + fEOF = false; + + do { + int nCharsRead; + + for (nCharsRead = 0; m_posInBuffer + 1 < m_nInBuffer; nCharsRead++, m_posInBuffer += sizeof(WCHAR)) { + m_wbuffer[nCharsRead] = ((WCHAR(m_buffer[m_posInBuffer]) << 8) & 0xff00) | (WCHAR(m_buffer[m_posInBuffer + 1]) & 0x00ff); + if (m_wbuffer[nCharsRead] == L'\n') { + bLineEndFound = true; // Stop at end of line + m_posInBuffer += sizeof(WCHAR); + break; + } else if (m_wbuffer[nCharsRead] == L'\r') { + nCharsRead--; // Skip \r + } + } + + str.Append(m_wbuffer, nCharsRead); + + if (!bLineEndFound) { + bLineEndFound = FillBuffer(); + if (!nCharsRead) { + fEOF = bLineEndFound; + } + } + } while (!bLineEndFound); + } + + return !fEOF; +} + +// +// CWebTextFile +// + +CWebTextFile::CWebTextFile(CTextFile::enc e, LONGLONG llMaxSize) + : CTextFile(e) + , m_llMaxSize(llMaxSize) +{ +} + +bool CWebTextFile::Open(LPCTSTR lpszFileName) +{ + CString fn(lpszFileName); + + if (fn.Find(_T("://")) == -1) { + return __super::Open(lpszFileName); + } + + try { + CInternetSession is; + + CAutoPtr f(is.OpenURL(fn, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT)); + if (!f) { + return false; + } + + TCHAR path[MAX_PATH]; + GetTempPath(MAX_PATH, path); + + fn = path + fn.Mid(fn.ReverseFind('/') + 1); + int i = fn.Find(_T("?")); + if (i > 0) { + fn = fn.Left(i); + } + CFile temp; + if (!temp.Open(fn, modeCreate | modeWrite | typeBinary | shareDenyWrite)) { + f->Close(); + return false; + } + + BYTE buff[1024]; + int len, total = 0; + while ((len = f->Read(buff, 1024)) > 0) { + total += len; + temp.Write(buff, len); + if (m_llMaxSize > 0 && total >= m_llMaxSize) { + break; + } + } + + m_tempfn = fn; + + f->Close(); // must close it because the desctructor doesn't seem to do it and we will get an exception when "is" is destroying + } catch (CInternetException* ie) { + ie->Delete(); + return false; + } + + return __super::Open(m_tempfn); +} + +bool CWebTextFile::Save(LPCTSTR lpszFileName, enc e) +{ + // CWebTextFile is read-only... + ASSERT(0); + return false; +} + +void CWebTextFile::Close() +{ + __super::Close(); + + if (!m_tempfn.IsEmpty()) { + _tremove(m_tempfn); + m_tempfn.Empty(); + } +} + +/////////////////////////////////////////////////////////////// + +CStringW AToW(CStringA str) +{ + CStringW ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (WCHAR)(BYTE)str[i]; + } + return ret; +} + +CStringA WToA(CStringW str) +{ + CStringA ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (CHAR)(WORD)str[i]; + } + return ret; +} + +CString AToT(CStringA str) +{ +#ifdef UNICODE + CString ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (TCHAR)(BYTE)str[i]; + } + return ret; +#else + return str; +#endif +} + +CString WToT(CStringW str) +{ +#ifdef UNICODE + return str; +#else + CString ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (TCHAR)(WORD)str[i]; + } + return ret; +#endif +} + +CStringA TToA(CString str) +{ +#ifdef UNICODE + CStringA ret; + for (int i = 0, j = str.GetLength(); i < j; i++) { + ret += (CHAR)(BYTE)str[i]; + } + return ret; +#else + return str; +#endif +} + +CStringW TToW(CString str) +{ +#ifdef UNICODE + return str; +#else + CStringW ret; + for (size_t i = 0, j = str.GetLength(); i < j; i++) { + ret += (WCHAR)(BYTE)str[i]; + } + return ret; +#endif +} diff --git a/src/Subtitles/TextFile.h b/src/Subtitles/TextFile.h index febc3177057..d0c381af1a7 100644 --- a/src/Subtitles/TextFile.h +++ b/src/Subtitles/TextFile.h @@ -1,97 +1,97 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "StdioFile64.h" - -class CTextFile : protected CStdioFile64 -{ -public: - enum enc { - DEFAULT_ENCODING, - UTF8, - LE16, - BE16, - ANSI - }; - -private: - enc m_encoding, m_defaultencoding, m_fallbackencoding; - int m_offset; - ULONGLONG m_posInFile; - CAutoVectorPtr m_buffer; - CAutoVectorPtr m_wbuffer; - LONGLONG m_posInBuffer, m_nInBuffer; - -public: - using CFile::Flush; - using CFile::Close; - CTextFile(enc e = DEFAULT_ENCODING); - - virtual bool Open(LPCTSTR lpszFileName); - virtual bool Save(LPCTSTR lpszFileName, enc e /*= DEFAULT_ENCODING*/); - - void SetEncoding(enc e); - void SetFallbackEncoding(enc e); - enc GetEncoding(); - bool IsUnicode(); - - // CFile - - CString GetFilePath() const; - - // CStdioFile - - ULONGLONG GetPosition() const; - ULONGLONG GetLength() const; - ULONGLONG Seek(LONGLONG lOff, UINT nFrom); - - void WriteString(LPCSTR lpsz/*CStringA str*/); - void WriteString(LPCWSTR lpsz/*CStringW str*/); - BOOL ReadString(CStringA& str); - BOOL ReadString(CStringW& str); - -protected: - virtual bool ReopenAsText(); - bool FillBuffer(); - ULONGLONG GetPositionFastBuffered() const; -}; - -class CWebTextFile : public CTextFile -{ - LONGLONG m_llMaxSize; - CString m_tempfn; - -public: - CWebTextFile(CTextFile::enc e = DEFAULT_ENCODING, LONGLONG llMaxSize = 64 * 1024 * 1024); - - bool Open(LPCTSTR lpszFileName); - bool Save(LPCTSTR lpszFileName, enc e /*= DEFAULT_ENCODING*/); - void Close(); -}; - -extern CStringW AToW(CStringA str); -extern CStringA WToA(CStringW str); -extern CString AToT(CStringA str); -extern CString WToT(CStringW str); -extern CStringA TToA(CString str); -extern CStringW TToW(CString str); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "StdioFile64.h" + +class CTextFile : protected CStdioFile64 +{ +public: + enum enc { + DEFAULT_ENCODING, + UTF8, + LE16, + BE16, + ANSI + }; + +private: + enc m_encoding, m_defaultencoding, m_fallbackencoding; + int m_offset; + ULONGLONG m_posInFile; + CAutoVectorPtr m_buffer; + CAutoVectorPtr m_wbuffer; + LONGLONG m_posInBuffer, m_nInBuffer; + +public: + using CFile::Flush; + using CFile::Close; + CTextFile(enc e = DEFAULT_ENCODING); + + virtual bool Open(LPCTSTR lpszFileName); + virtual bool Save(LPCTSTR lpszFileName, enc e /*= DEFAULT_ENCODING*/); + + void SetEncoding(enc e); + void SetFallbackEncoding(enc e); + enc GetEncoding(); + bool IsUnicode(); + + // CFile + + CString GetFilePath() const; + + // CStdioFile + + ULONGLONG GetPosition() const; + ULONGLONG GetLength() const; + ULONGLONG Seek(LONGLONG lOff, UINT nFrom); + + void WriteString(LPCSTR lpsz/*CStringA str*/); + void WriteString(LPCWSTR lpsz/*CStringW str*/); + BOOL ReadString(CStringA& str); + BOOL ReadString(CStringW& str); + +protected: + virtual bool ReopenAsText(); + bool FillBuffer(); + ULONGLONG GetPositionFastBuffered() const; +}; + +class CWebTextFile : public CTextFile +{ + LONGLONG m_llMaxSize; + CString m_tempfn; + +public: + CWebTextFile(CTextFile::enc e = DEFAULT_ENCODING, LONGLONG llMaxSize = 64 * 1024 * 1024); + + bool Open(LPCTSTR lpszFileName); + bool Save(LPCTSTR lpszFileName, enc e /*= DEFAULT_ENCODING*/); + void Close(); +}; + +extern CStringW AToW(CStringA str); +extern CStringA WToA(CStringW str); +extern CString AToT(CStringA str); +extern CString WToT(CStringW str); +extern CStringA TToA(CString str); +extern CStringW TToW(CString str); diff --git a/src/Subtitles/USFSubtitles.cpp b/src/Subtitles/USFSubtitles.cpp index 841226f4be0..e18df8f5912 100644 --- a/src/Subtitles/USFSubtitles.cpp +++ b/src/Subtitles/USFSubtitles.cpp @@ -1,783 +1,783 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "USFSubtitles.h" -#include -#include - -#define DeclareNameAndValue(pNode, name, val) \ - CComBSTR name; \ - pNode->get_nodeName(&name); \ - name.ToLower(); \ - CComVariant val; \ - pNode->get_nodeValue(&val); - -#define BeginEnumAttribs(pNode, pChild) \ - { \ - CComPtr pAttribs; \ - if (SUCCEEDED(pNode->get_attributes(&pAttribs)) && pAttribs != nullptr) { \ - CComPtr pChild; \ - for (pAttribs->nextNode(&pChild); pChild; pChild = nullptr, pAttribs->nextNode(&pChild)) { - -#define EndEnumAttribs }}} - -#define BeginEnumChildren(pNode, pChild) \ - { \ - CComPtr pChild, pChild##Next; \ - for (pNode->get_firstChild(&pChild); pChild; pChild##Next = nullptr, pChild->get_nextSibling(&pChild##Next), pChild = pChild##Next) { - -#define EndEnumChildren }} - -static CStringW GetText(CComPtr pNode) -{ - CComBSTR bstr; - pNode->get_text(&bstr); - - return CStringW(bstr); -} - -static CStringW GetXML(CComPtr pNode) -{ - CComBSTR bstr; - pNode->get_xml(&bstr); - CStringW str(bstr); - str.Remove('\r'); - str.Replace('\n', ' '); - - for (int i = 0; (i = str.Find(L" ", i)) >= 0;) { - for (++i; i < str.GetLength() && (str[i] == ' ');) { - str.Delete(i); - } - } - return str; -} - -static CStringW GetAttrib(CStringW attrib, CComPtr pNode) -{ - CStringW ret; - - BeginEnumAttribs(pNode, pChild) { - DeclareNameAndValue(pChild, name, val); - - if (CStringW(name) == attrib && val.vt == VT_BSTR) { // TODO: prepare for other types - ret = val.bstrVal; - break; - } - } - EndEnumAttribs; - - return ret; -} - -static int TimeToInt(CStringW str) -{ - CAtlList sl; - int i = 0; - for (CStringW token = str.Tokenize(L":.,", i); !token.IsEmpty(); token = str.Tokenize(L":.,", i)) { - sl.AddHead(token); - } - - if (sl.GetCount() > 4) { - return -1; - } - - int time = 0; - int mul[4] = {1, 1000, 60 * 1000, 60 * 60 * 1000}; - POSITION pos = sl.GetHeadPosition(); - - for (i = 0; pos; i++) { - const WCHAR* s = sl.GetNext(pos); - WCHAR* tmp = nullptr; - int t = wcstol(s, &tmp, 10); - if (s >= tmp) { - return -1; - } - time += t * mul[i]; - } - - return time; -} - -static DWORD StringToDWORD(CStringW str) -{ - if (str.IsEmpty()) { - return 0; - } - if (str[0] == '#') { - return (DWORD)wcstol(str, nullptr, 16); - } else { - return (DWORD)wcstol(str, nullptr, 10); - } -} - -static DWORD ColorToDWORD(CStringW str) -{ - if (str.IsEmpty()) { - return 0; - } - - DWORD ret = 0; - - if (str[0] == '#') { - ret = (DWORD)wcstol(str.TrimLeft('#'), nullptr, 16); - } else { - g_colors.Lookup(CString(str), ret); - } - - ret = ((ret & 0xff) << 16) | (ret & 0xff00ff00) | ((ret >> 16) & 0xff); - - return ret; -} - -static int TranslateAlignment(CStringW alignment) -{ - return - !alignment.CompareNoCase(L"BottomLeft") ? 1 : - !alignment.CompareNoCase(L"BottomCenter") ? 2 : - !alignment.CompareNoCase(L"BottomRight") ? 3 : - !alignment.CompareNoCase(L"MiddleLeft") ? 4 : - !alignment.CompareNoCase(L"MiddleCenter") ? 5 : - !alignment.CompareNoCase(L"MiddleRight") ? 6 : - !alignment.CompareNoCase(L"TopLeft") ? 7 : - !alignment.CompareNoCase(L"TopCenter") ? 8 : - !alignment.CompareNoCase(L"TopRight") ? 9 : - 2; -} - -static int TranslateMargin(CStringW margin, int wndsize) -{ - int ret = 0; - - if (!margin.IsEmpty()) { - ret = wcstol(margin, nullptr, 10); - if (margin.Find('%') >= 0) { - ret = wndsize * ret / 100; - } - } - - return ret; -} - -//////////////// - -CUSFSubtitles::CUSFSubtitles() -{ -} - -CUSFSubtitles::~CUSFSubtitles() -{ -} - -bool CUSFSubtitles::Read(LPCTSTR fn) -{ - VARIANT_BOOL vb; - CComPtr pDoc; - if (FAILED(pDoc.CoCreateInstance(CLSID_DOMDocument)) - || FAILED(pDoc->put_async(VARIANT_FALSE)) - || FAILED(pDoc->load(CComVariant(fn), &vb)) || vb != VARIANT_TRUE) { - return false; - } - - styles.RemoveAll(); - effects.RemoveAll(); - texts.RemoveAll(); - - if (!ParseUSFSubtitles(CComQIPtr(pDoc))) { - return false; - } - - POSITION pos = styles.GetHeadPosition(); - while (pos) { - style_t* def = styles.GetNext(pos); - - if (def->name.CompareNoCase(L"Default")) { - continue; - } - - POSITION pos2 = styles.GetHeadPosition(); - while (pos2) { - style_t* s = styles.GetNext(pos2); - - if (!s->name.CompareNoCase(L"Default")) { - continue; - } - - if (s->fontstyle.face.IsEmpty()) { - s->fontstyle.face = def->fontstyle.face; - } - if (s->fontstyle.size.IsEmpty()) { - s->fontstyle.size = def->fontstyle.size; - } - if (s->fontstyle.color[0].IsEmpty()) { - s->fontstyle.color[0] = def->fontstyle.color[0]; - } - if (s->fontstyle.color[1].IsEmpty()) { - s->fontstyle.color[1] = def->fontstyle.color[1]; - } - if (s->fontstyle.color[2].IsEmpty()) { - s->fontstyle.color[2] = def->fontstyle.color[2]; - } - if (s->fontstyle.color[3].IsEmpty()) { - s->fontstyle.color[3] = def->fontstyle.color[3]; - } - if (s->fontstyle.italic.IsEmpty()) { - s->fontstyle.italic = def->fontstyle.italic; - } - if (s->fontstyle.weight.IsEmpty()) { - s->fontstyle.weight = def->fontstyle.weight; - } - if (s->fontstyle.underline.IsEmpty()) { - s->fontstyle.underline = def->fontstyle.underline; - } - if (s->fontstyle.alpha.IsEmpty()) { - s->fontstyle.alpha = def->fontstyle.alpha; - } - if (s->fontstyle.outline.IsEmpty()) { - s->fontstyle.outline = def->fontstyle.outline; - } - if (s->fontstyle.shadow.IsEmpty()) { - s->fontstyle.shadow = def->fontstyle.shadow; - } - if (s->fontstyle.wrap.IsEmpty()) { - s->fontstyle.wrap = def->fontstyle.wrap; - } - if (s->pal.alignment.IsEmpty()) { - s->pal.alignment = def->pal.alignment; - } - if (s->pal.relativeto.IsEmpty()) { - s->pal.relativeto = def->pal.relativeto; - } - if (s->pal.horizontal_margin.IsEmpty()) { - s->pal.horizontal_margin = def->pal.horizontal_margin; - } - if (s->pal.vertical_margin.IsEmpty()) { - s->pal.vertical_margin = def->pal.vertical_margin; - } - if (s->pal.rotate[0].IsEmpty()) { - s->pal.rotate[0] = def->pal.rotate[0]; - } - if (s->pal.rotate[1].IsEmpty()) { - s->pal.rotate[1] = def->pal.rotate[1]; - } - if (s->pal.rotate[2].IsEmpty()) { - s->pal.rotate[2] = def->pal.rotate[2]; - } - } - - break; - } - - pos = texts.GetHeadPosition(); - while (pos) { - text_t* t = texts.GetNext(pos); - if (t->style.IsEmpty()) { - t->style = L"Default"; - } - } - - return true; -} - -bool CUSFSubtitles::ConvertToSTS(CSimpleTextSubtitle& sts) -{ - sts.m_name = metadata.language.text; - sts.m_encoding = CTextFile::UTF8; - sts.m_playRes = CSize(640, 480); - sts.m_scaledBAS = 0; - sts.m_defaultWrapStyle = 1; - - // TODO: map metadata.language.code to charset num (windows doesn't have such a function...) - int charSet = DEFAULT_CHARSET; - - POSITION pos = styles.GetHeadPosition(); - while (pos) { - style_t* s = styles.GetNext(pos); - - if (!s->name.CompareNoCase(L"Default") && !s->fontstyle.wrap.IsEmpty()) { - sts.m_defaultWrapStyle = - !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 : - /*!s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :*/ - 1; - } - - STSStyle* stss = DEBUG_NEW STSStyle; - if (!stss) { - continue; - } - - if (!s->pal.horizontal_margin.IsEmpty()) { - stss->marginRect.left = stss->marginRect.right = TranslateMargin(s->pal.horizontal_margin, sts.m_playRes.cx); - } - if (!s->pal.vertical_margin.IsEmpty()) { - stss->marginRect.top = stss->marginRect.bottom = TranslateMargin(s->pal.vertical_margin, sts.m_playRes.cy); - } - - stss->scrAlignment = TranslateAlignment(s->pal.alignment); - - if (!s->pal.relativeto.IsEmpty()) stss->relativeTo = - !s->pal.relativeto.CompareNoCase(L"window") ? STSStyle::WINDOW : - !s->pal.relativeto.CompareNoCase(L"video") ? STSStyle::VIDEO : - STSStyle::WINDOW; - - stss->borderStyle = 0; - if (!s->fontstyle.outline.IsEmpty()) { - stss->outlineWidthX = stss->outlineWidthY = wcstol(s->fontstyle.outline, nullptr, 10); - } - if (!s->fontstyle.shadow.IsEmpty()) { - stss->shadowDepthX = stss->shadowDepthY = wcstol(s->fontstyle.shadow, nullptr, 10); - } - - for (size_t i = 0; i < 4; i++) { - DWORD color = ColorToDWORD(s->fontstyle.color[i]); - auto alpha = (BYTE)wcstol(s->fontstyle.alpha, nullptr, 10); - - stss->colors[i] = color & 0xffffff; - stss->alpha[i] = (BYTE)(color >> 24); - - stss->alpha[i] = BYTE(stss->alpha[i] + (255 - stss->alpha[i]) * std::min(std::max(alpha, 0ui8), 100ui8) / 100); - } - - if (!s->fontstyle.face.IsEmpty()) { - stss->fontName = s->fontstyle.face; - } - if (!s->fontstyle.size.IsEmpty()) { - stss->fontSize = wcstol(s->fontstyle.size, nullptr, 10); - } - if (!s->fontstyle.weight.IsEmpty()) stss->fontWeight = - !s->fontstyle.weight.CompareNoCase(L"normal") ? FW_NORMAL : - !s->fontstyle.weight.CompareNoCase(L"bold") ? FW_BOLD : - !s->fontstyle.weight.CompareNoCase(L"lighter") ? FW_LIGHT : - !s->fontstyle.weight.CompareNoCase(L"bolder") ? FW_SEMIBOLD : - wcstol(s->fontstyle.weight, nullptr, 10); - if (stss->fontWeight == 0) { - stss->fontWeight = FW_NORMAL; - } - if (!s->fontstyle.italic.IsEmpty()) { - stss->fItalic = s->fontstyle.italic.CompareNoCase(L"yes") == 0; - } - if (!s->fontstyle.underline.IsEmpty()) { - stss->fUnderline = s->fontstyle.underline.CompareNoCase(L"yes") == 0; - } - if (!s->pal.rotate[0].IsEmpty()) { - stss->fontAngleZ = wcstol(s->pal.rotate[0], nullptr, 10); - } - if (!s->pal.rotate[1].IsEmpty()) { - stss->fontAngleX = wcstol(s->pal.rotate[1], nullptr, 10); - } - if (!s->pal.rotate[2].IsEmpty()) { - stss->fontAngleY = wcstol(s->pal.rotate[2], nullptr, 10); - } - - stss->charSet = charSet; - - sts.AddStyle(WToT(s->name), stss); - } - - pos = texts.GetHeadPosition(); - while (pos) { - text_t* t = texts.GetNext(pos); - - if (!t->pal.alignment.IsEmpty()) { - CStringW s; - s.Format(L"{\\an%d}", TranslateAlignment(t->pal.alignment)); - t->str = s + t->str; - } - - CRect marginRect; - marginRect.SetRectEmpty(); - - if (!t->pal.horizontal_margin.IsEmpty()) { - marginRect.left = marginRect.right = TranslateMargin(t->pal.horizontal_margin, sts.m_storageRes.cx); - } - if (!t->pal.vertical_margin.IsEmpty()) { - marginRect.top = marginRect.bottom = TranslateMargin(t->pal.vertical_margin, sts.m_storageRes.cy); - } - - WCHAR rtags[3][8] = {L"{\\rz%d}", L"{\\rx%d}", L"{\\ry%d}"}; - for (size_t i = 0; i < 3; i++) { - if (int angle = wcstol(t->pal.rotate[i], nullptr, 10)) { - CStringW str; - str.Format(rtags[i], angle); - t->str = str + t->str; - } - } - - if (t->style.CompareNoCase(L"Default") != 0) { - POSITION pos2 = styles.GetHeadPosition(); - while (pos2) { - style_t* s = styles.GetNext(pos2); - if (s->name == t->style && !s->fontstyle.wrap.IsEmpty()) { - int WrapStyle = - !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 : - /*!s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :*/ - 1; - - if (WrapStyle != sts.m_defaultWrapStyle) { - CStringW str; - str.Format(L"{\\q%d}", WrapStyle); - t->str = str + t->str; - } - - break; - } - } - } - - // TODO: apply effects as {\t(..)} after usf's standard clearly defines them - - sts.Add(t->str, true, t->start, t->stop, WToT(t->style), _T(""), _T(""), marginRect); - } - - return true; -} - -bool CUSFSubtitles::ParseUSFSubtitles(CComPtr pNode) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"usfsubtitles") { - // metadata - - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"metadata") { - ParseMetadata(pChild, metadata); - } - } - EndEnumChildren; - - // styles - - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"styles") { - BeginEnumChildren(pChild, pGrandChild) { // :) - DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); - - if (grandChildName == L"style") { - CAutoPtr s(DEBUG_NEW style_t); - if (s) { - ParseStyle(pGrandChild, s); - styles.AddTail(s); - } - } - } - EndEnumChildren; - } - } - EndEnumChildren; - - // effects - - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"effects") { - BeginEnumChildren(pChild, pGrandChild) { // :) - DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); - - if (grandChildName == L"effect") { - CAutoPtr e(DEBUG_NEW effect_t); - if (e) { - ParseEffect(pGrandChild, e); - effects.AddTail(e); - } - } - } - EndEnumChildren; - } - } - EndEnumChildren; - - // subtitles - - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"subtitles") { - BeginEnumChildren(pChild, pGrandChild) { // :) - DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); - - if (grandChildName == L"subtitle") { - CStringW sstart = GetAttrib(L"start", pGrandChild); - CStringW sstop = GetAttrib(L"stop", pGrandChild); - CStringW sduration = GetAttrib(L"duration", pGrandChild); - if (sstart.IsEmpty() || (sstop.IsEmpty() && sduration.IsEmpty())) { - continue; - } - - int start = TimeToInt(sstart); - int stop = !sstop.IsEmpty() ? TimeToInt(sstop) : (start + TimeToInt(sduration)); - - ParseSubtitle(pGrandChild, start, stop); - } - } - EndEnumChildren; - } - } - EndEnumChildren; - - return true; - } - - BeginEnumChildren(pNode, pChild) { - if (ParseUSFSubtitles(pChild)) { - return true; - } - } - EndEnumChildren; - - return false; -} - -void CUSFSubtitles::ParseMetadata(CComPtr pNode, metadata_t& m) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"title") { - m.title = GetText(pNode); - } else if (name == L"date") { - m.date = GetText(pNode); - } else if (name == L"comment") { - m.comment = GetText(pNode); - } else if (name == L"author") { - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"name") { - m.author.name = GetText(pChild); - } else if (childName == L"email") { - m.author.email = GetText(pChild); - } else if (childName == L"url") { - m.author.url = GetText(pChild); - } - } - EndEnumChildren; - - return; - } else if (name == L"language") { - m.language.text = GetText(pNode); - m.language.code = GetAttrib(L"code", pNode); - } else if (name == L"languageext") { - m.languageext.text = GetText(pNode); - m.languageext.code = GetAttrib(L"code", pNode); - } - - BeginEnumChildren(pNode, pChild) { - ParseMetadata(pChild, metadata); - } - EndEnumChildren; -} - -void CUSFSubtitles::ParseStyle(CComPtr pNode, style_t* s) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"style") { - s->name = GetAttrib(L"name", pNode); - } else if (name == L"fontstyle") { - ParseFontstyle(pNode, s->fontstyle); - return; - } else if (name == L"position") { - ParsePal(pNode, s->pal); - return; - } - - BeginEnumChildren(pNode, pChild) { - ParseStyle(pChild, s); - } - EndEnumChildren; -} - -void CUSFSubtitles::ParseFontstyle(CComPtr pNode, fontstyle_t& fs) -{ - fs.face = GetAttrib(L"face", pNode); - fs.size = GetAttrib(L"size", pNode); - fs.color[0] = GetAttrib(L"color", pNode); - fs.color[1] = GetAttrib(L"back-color", pNode); - fs.color[2] = GetAttrib(L"outline-color", pNode); - fs.color[3] = GetAttrib(L"shadow-color", pNode); - fs.italic = GetAttrib(L"italic", pNode); - fs.weight = GetAttrib(L"weight", pNode); - fs.underline = GetAttrib(L"underline", pNode); - fs.alpha = GetAttrib(L"alpha", pNode); - fs.outline = GetAttrib(L"outline-level", pNode); - fs.shadow = GetAttrib(L"shadow-level", pNode); - fs.wrap = GetAttrib(L"wrap", pNode); -} - -void CUSFSubtitles::ParsePal(CComPtr pNode, posattriblist_t& pal) -{ - pal.alignment = GetAttrib(L"alignment", pNode); - pal.relativeto = GetAttrib(L"relative-to", pNode); - pal.horizontal_margin = GetAttrib(L"horizontal-margin", pNode); - pal.vertical_margin = GetAttrib(L"vertical-margin", pNode); - pal.rotate[0] = GetAttrib(L"rotate-z", pNode); - pal.rotate[1] = GetAttrib(L"rotate-x", pNode); - pal.rotate[2] = GetAttrib(L"rotate-y", pNode); -} - -void CUSFSubtitles::ParseEffect(CComPtr pNode, effect_t* e) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"effect") { - e->name = GetAttrib(L"name", pNode); - } else if (name == L"keyframes") { - BeginEnumChildren(pNode, pChild) { - DeclareNameAndValue(pChild, childName, childVal); - - if (childName == L"keyframe") { - CAutoPtr k(DEBUG_NEW keyframe_t); - if (k) { - ParseKeyframe(pChild, k); - e->keyframes.AddTail(k); - } - } - } - EndEnumChildren; - - return; - } - - BeginEnumChildren(pNode, pChild) { - ParseEffect(pChild, e); - } - EndEnumChildren; -} - -void CUSFSubtitles::ParseKeyframe(CComPtr pNode, keyframe_t* k) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"keyframe") { - k->position = GetAttrib(L"position", pNode); - } else if (name == L"fontstyle") { - ParseFontstyle(pNode, k->fontstyle); - return; - } else if (name == L"position") { - ParsePal(pNode, k->pal); - return; - } -} - -void CUSFSubtitles::ParseSubtitle(CComPtr pNode, int start, int stop) -{ - DeclareNameAndValue(pNode, name, val); - - if (name == L"text" || name == L"karaoke") { - CAutoPtr t(DEBUG_NEW text_t); - if (t) { - t->start = start; - t->stop = stop; - t->style = GetAttrib(L"style", pNode); - t->effect = GetAttrib(L"effect", pNode); - ParsePal(pNode, t->pal); - ParseText(pNode, t->str); - texts.AddTail(t); - } - - return; - } - // else if - - BeginEnumChildren(pNode, pChild) { - ParseSubtitle(pChild, start, stop); - } - EndEnumChildren; -} - -void CUSFSubtitles::ParseText(CComPtr pNode, CStringW& str) -{ - DeclareNameAndValue(pNode, name, val); - - CStringW prefix, postfix; - - if (name == L"b") { - prefix = L"{\\b1}"; - postfix = L"{\\b}"; - } else if (name == L"i") { - prefix = L"{\\i1}"; - postfix = L"{\\i}"; - } else if (name == L"u") { - prefix = L"{\\u1}"; - postfix = L"{\\u}"; - } else if (name == L"font") { - fontstyle_t fs; - ParseFontstyle(pNode, fs); - - if (!fs.face.IsEmpty()) { - prefix += L"{\\fn" + fs.face + L"}"; - postfix += L"{\\fn}"; - } - if (!fs.size.IsEmpty()) { - prefix += L"{\\fs" + fs.size + L"}"; - postfix += L"{\\fs}"; - } - if (!fs.outline.IsEmpty()) { - prefix += L"{\\bord" + fs.outline + L"}"; - postfix += L"{\\bord}"; - } - if (!fs.shadow.IsEmpty()) { - prefix += L"{\\shad" + fs.shadow + L"}"; - postfix += L"{\\shad}"; - } - - for (size_t i = 0; i < 4; i++) { - if (!fs.color[i].IsEmpty()) { - CStringW s; - s.Format(L"{\\%uc&H%06x&}", i + 1, ColorToDWORD(fs.color[i])); - prefix += s; - s.Format(L"{\\%uc}", i + 1); - postfix += s; - } - } - } else if (name == L"k") { - int t = wcstol(GetAttrib(L"t", pNode), nullptr, 10); - CStringW s; - s.Format(L"{\\kf%d}", t / 10); - str += s; - return; - } else if (name == L"br") { - str += L"\\N"; - return; - } else if (name == L"#text") { - str += GetXML(pNode); - return; - } - - BeginEnumChildren(pNode, pChild) { - CStringW s; - ParseText(pChild, s); - str += s; - } - EndEnumChildren; - - str = prefix + str + postfix; -} - -void CUSFSubtitles::ParseShape(CComPtr pNode) -{ - // no specs on this yet -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "USFSubtitles.h" +#include +#include + +#define DeclareNameAndValue(pNode, name, val) \ + CComBSTR name; \ + pNode->get_nodeName(&name); \ + name.ToLower(); \ + CComVariant val; \ + pNode->get_nodeValue(&val); + +#define BeginEnumAttribs(pNode, pChild) \ + { \ + CComPtr pAttribs; \ + if (SUCCEEDED(pNode->get_attributes(&pAttribs)) && pAttribs != nullptr) { \ + CComPtr pChild; \ + for (pAttribs->nextNode(&pChild); pChild; pChild = nullptr, pAttribs->nextNode(&pChild)) { + +#define EndEnumAttribs }}} + +#define BeginEnumChildren(pNode, pChild) \ + { \ + CComPtr pChild, pChild##Next; \ + for (pNode->get_firstChild(&pChild); pChild; pChild##Next = nullptr, pChild->get_nextSibling(&pChild##Next), pChild = pChild##Next) { + +#define EndEnumChildren }} + +static CStringW GetText(CComPtr pNode) +{ + CComBSTR bstr; + pNode->get_text(&bstr); + + return CStringW(bstr); +} + +static CStringW GetXML(CComPtr pNode) +{ + CComBSTR bstr; + pNode->get_xml(&bstr); + CStringW str(bstr); + str.Remove('\r'); + str.Replace('\n', ' '); + + for (int i = 0; (i = str.Find(L" ", i)) >= 0;) { + for (++i; i < str.GetLength() && (str[i] == ' ');) { + str.Delete(i); + } + } + return str; +} + +static CStringW GetAttrib(CStringW attrib, CComPtr pNode) +{ + CStringW ret; + + BeginEnumAttribs(pNode, pChild) { + DeclareNameAndValue(pChild, name, val); + + if (CStringW(name) == attrib && val.vt == VT_BSTR) { // TODO: prepare for other types + ret = val.bstrVal; + break; + } + } + EndEnumAttribs; + + return ret; +} + +static int TimeToInt(CStringW str) +{ + CAtlList sl; + int i = 0; + for (CStringW token = str.Tokenize(L":.,", i); !token.IsEmpty(); token = str.Tokenize(L":.,", i)) { + sl.AddHead(token); + } + + if (sl.GetCount() > 4) { + return -1; + } + + int time = 0; + int mul[4] = {1, 1000, 60 * 1000, 60 * 60 * 1000}; + POSITION pos = sl.GetHeadPosition(); + + for (i = 0; pos; i++) { + const WCHAR* s = sl.GetNext(pos); + WCHAR* tmp = nullptr; + int t = wcstol(s, &tmp, 10); + if (s >= tmp) { + return -1; + } + time += t * mul[i]; + } + + return time; +} + +static DWORD StringToDWORD(CStringW str) +{ + if (str.IsEmpty()) { + return 0; + } + if (str[0] == '#') { + return (DWORD)wcstol(str, nullptr, 16); + } else { + return (DWORD)wcstol(str, nullptr, 10); + } +} + +static DWORD ColorToDWORD(CStringW str) +{ + if (str.IsEmpty()) { + return 0; + } + + DWORD ret = 0; + + if (str[0] == '#') { + ret = (DWORD)wcstol(str.TrimLeft('#'), nullptr, 16); + } else { + g_colors.Lookup(CString(str), ret); + } + + ret = ((ret & 0xff) << 16) | (ret & 0xff00ff00) | ((ret >> 16) & 0xff); + + return ret; +} + +static int TranslateAlignment(CStringW alignment) +{ + return + !alignment.CompareNoCase(L"BottomLeft") ? 1 : + !alignment.CompareNoCase(L"BottomCenter") ? 2 : + !alignment.CompareNoCase(L"BottomRight") ? 3 : + !alignment.CompareNoCase(L"MiddleLeft") ? 4 : + !alignment.CompareNoCase(L"MiddleCenter") ? 5 : + !alignment.CompareNoCase(L"MiddleRight") ? 6 : + !alignment.CompareNoCase(L"TopLeft") ? 7 : + !alignment.CompareNoCase(L"TopCenter") ? 8 : + !alignment.CompareNoCase(L"TopRight") ? 9 : + 2; +} + +static int TranslateMargin(CStringW margin, int wndsize) +{ + int ret = 0; + + if (!margin.IsEmpty()) { + ret = wcstol(margin, nullptr, 10); + if (margin.Find('%') >= 0) { + ret = wndsize * ret / 100; + } + } + + return ret; +} + +//////////////// + +CUSFSubtitles::CUSFSubtitles() +{ +} + +CUSFSubtitles::~CUSFSubtitles() +{ +} + +bool CUSFSubtitles::Read(LPCTSTR fn) +{ + VARIANT_BOOL vb; + CComPtr pDoc; + if (FAILED(pDoc.CoCreateInstance(CLSID_DOMDocument)) + || FAILED(pDoc->put_async(VARIANT_FALSE)) + || FAILED(pDoc->load(CComVariant(fn), &vb)) || vb != VARIANT_TRUE) { + return false; + } + + styles.RemoveAll(); + effects.RemoveAll(); + texts.RemoveAll(); + + if (!ParseUSFSubtitles(CComQIPtr(pDoc))) { + return false; + } + + POSITION pos = styles.GetHeadPosition(); + while (pos) { + style_t* def = styles.GetNext(pos); + + if (def->name.CompareNoCase(L"Default")) { + continue; + } + + POSITION pos2 = styles.GetHeadPosition(); + while (pos2) { + style_t* s = styles.GetNext(pos2); + + if (!s->name.CompareNoCase(L"Default")) { + continue; + } + + if (s->fontstyle.face.IsEmpty()) { + s->fontstyle.face = def->fontstyle.face; + } + if (s->fontstyle.size.IsEmpty()) { + s->fontstyle.size = def->fontstyle.size; + } + if (s->fontstyle.color[0].IsEmpty()) { + s->fontstyle.color[0] = def->fontstyle.color[0]; + } + if (s->fontstyle.color[1].IsEmpty()) { + s->fontstyle.color[1] = def->fontstyle.color[1]; + } + if (s->fontstyle.color[2].IsEmpty()) { + s->fontstyle.color[2] = def->fontstyle.color[2]; + } + if (s->fontstyle.color[3].IsEmpty()) { + s->fontstyle.color[3] = def->fontstyle.color[3]; + } + if (s->fontstyle.italic.IsEmpty()) { + s->fontstyle.italic = def->fontstyle.italic; + } + if (s->fontstyle.weight.IsEmpty()) { + s->fontstyle.weight = def->fontstyle.weight; + } + if (s->fontstyle.underline.IsEmpty()) { + s->fontstyle.underline = def->fontstyle.underline; + } + if (s->fontstyle.alpha.IsEmpty()) { + s->fontstyle.alpha = def->fontstyle.alpha; + } + if (s->fontstyle.outline.IsEmpty()) { + s->fontstyle.outline = def->fontstyle.outline; + } + if (s->fontstyle.shadow.IsEmpty()) { + s->fontstyle.shadow = def->fontstyle.shadow; + } + if (s->fontstyle.wrap.IsEmpty()) { + s->fontstyle.wrap = def->fontstyle.wrap; + } + if (s->pal.alignment.IsEmpty()) { + s->pal.alignment = def->pal.alignment; + } + if (s->pal.relativeto.IsEmpty()) { + s->pal.relativeto = def->pal.relativeto; + } + if (s->pal.horizontal_margin.IsEmpty()) { + s->pal.horizontal_margin = def->pal.horizontal_margin; + } + if (s->pal.vertical_margin.IsEmpty()) { + s->pal.vertical_margin = def->pal.vertical_margin; + } + if (s->pal.rotate[0].IsEmpty()) { + s->pal.rotate[0] = def->pal.rotate[0]; + } + if (s->pal.rotate[1].IsEmpty()) { + s->pal.rotate[1] = def->pal.rotate[1]; + } + if (s->pal.rotate[2].IsEmpty()) { + s->pal.rotate[2] = def->pal.rotate[2]; + } + } + + break; + } + + pos = texts.GetHeadPosition(); + while (pos) { + text_t* t = texts.GetNext(pos); + if (t->style.IsEmpty()) { + t->style = L"Default"; + } + } + + return true; +} + +bool CUSFSubtitles::ConvertToSTS(CSimpleTextSubtitle& sts) +{ + sts.m_name = metadata.language.text; + sts.m_encoding = CTextFile::UTF8; + sts.m_playRes = CSize(640, 480); + sts.m_scaledBAS = 0; + sts.m_defaultWrapStyle = 1; + + // TODO: map metadata.language.code to charset num (windows doesn't have such a function...) + int charSet = DEFAULT_CHARSET; + + POSITION pos = styles.GetHeadPosition(); + while (pos) { + style_t* s = styles.GetNext(pos); + + if (!s->name.CompareNoCase(L"Default") && !s->fontstyle.wrap.IsEmpty()) { + sts.m_defaultWrapStyle = + !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 : + /*!s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :*/ + 1; + } + + STSStyle* stss = DEBUG_NEW STSStyle; + if (!stss) { + continue; + } + + if (!s->pal.horizontal_margin.IsEmpty()) { + stss->marginRect.left = stss->marginRect.right = TranslateMargin(s->pal.horizontal_margin, sts.m_playRes.cx); + } + if (!s->pal.vertical_margin.IsEmpty()) { + stss->marginRect.top = stss->marginRect.bottom = TranslateMargin(s->pal.vertical_margin, sts.m_playRes.cy); + } + + stss->scrAlignment = TranslateAlignment(s->pal.alignment); + + if (!s->pal.relativeto.IsEmpty()) stss->relativeTo = + !s->pal.relativeto.CompareNoCase(L"window") ? STSStyle::WINDOW : + !s->pal.relativeto.CompareNoCase(L"video") ? STSStyle::VIDEO : + STSStyle::WINDOW; + + stss->borderStyle = 0; + if (!s->fontstyle.outline.IsEmpty()) { + stss->outlineWidthX = stss->outlineWidthY = wcstol(s->fontstyle.outline, nullptr, 10); + } + if (!s->fontstyle.shadow.IsEmpty()) { + stss->shadowDepthX = stss->shadowDepthY = wcstol(s->fontstyle.shadow, nullptr, 10); + } + + for (size_t i = 0; i < 4; i++) { + DWORD color = ColorToDWORD(s->fontstyle.color[i]); + auto alpha = (BYTE)wcstol(s->fontstyle.alpha, nullptr, 10); + + stss->colors[i] = color & 0xffffff; + stss->alpha[i] = (BYTE)(color >> 24); + + stss->alpha[i] = BYTE(stss->alpha[i] + (255 - stss->alpha[i]) * std::min(std::max(alpha, 0ui8), 100ui8) / 100); + } + + if (!s->fontstyle.face.IsEmpty()) { + stss->fontName = s->fontstyle.face; + } + if (!s->fontstyle.size.IsEmpty()) { + stss->fontSize = wcstol(s->fontstyle.size, nullptr, 10); + } + if (!s->fontstyle.weight.IsEmpty()) stss->fontWeight = + !s->fontstyle.weight.CompareNoCase(L"normal") ? FW_NORMAL : + !s->fontstyle.weight.CompareNoCase(L"bold") ? FW_BOLD : + !s->fontstyle.weight.CompareNoCase(L"lighter") ? FW_LIGHT : + !s->fontstyle.weight.CompareNoCase(L"bolder") ? FW_SEMIBOLD : + wcstol(s->fontstyle.weight, nullptr, 10); + if (stss->fontWeight == 0) { + stss->fontWeight = FW_NORMAL; + } + if (!s->fontstyle.italic.IsEmpty()) { + stss->fItalic = s->fontstyle.italic.CompareNoCase(L"yes") == 0; + } + if (!s->fontstyle.underline.IsEmpty()) { + stss->fUnderline = s->fontstyle.underline.CompareNoCase(L"yes") == 0; + } + if (!s->pal.rotate[0].IsEmpty()) { + stss->fontAngleZ = wcstol(s->pal.rotate[0], nullptr, 10); + } + if (!s->pal.rotate[1].IsEmpty()) { + stss->fontAngleX = wcstol(s->pal.rotate[1], nullptr, 10); + } + if (!s->pal.rotate[2].IsEmpty()) { + stss->fontAngleY = wcstol(s->pal.rotate[2], nullptr, 10); + } + + stss->charSet = charSet; + + sts.AddStyle(WToT(s->name), stss); + } + + pos = texts.GetHeadPosition(); + while (pos) { + text_t* t = texts.GetNext(pos); + + if (!t->pal.alignment.IsEmpty()) { + CStringW s; + s.Format(L"{\\an%d}", TranslateAlignment(t->pal.alignment)); + t->str = s + t->str; + } + + CRect marginRect; + marginRect.SetRectEmpty(); + + if (!t->pal.horizontal_margin.IsEmpty()) { + marginRect.left = marginRect.right = TranslateMargin(t->pal.horizontal_margin, sts.m_storageRes.cx); + } + if (!t->pal.vertical_margin.IsEmpty()) { + marginRect.top = marginRect.bottom = TranslateMargin(t->pal.vertical_margin, sts.m_storageRes.cy); + } + + WCHAR rtags[3][8] = {L"{\\rz%d}", L"{\\rx%d}", L"{\\ry%d}"}; + for (size_t i = 0; i < 3; i++) { + if (int angle = wcstol(t->pal.rotate[i], nullptr, 10)) { + CStringW str; + str.Format(rtags[i], angle); + t->str = str + t->str; + } + } + + if (t->style.CompareNoCase(L"Default") != 0) { + POSITION pos2 = styles.GetHeadPosition(); + while (pos2) { + style_t* s = styles.GetNext(pos2); + if (s->name == t->style && !s->fontstyle.wrap.IsEmpty()) { + int WrapStyle = + !s->fontstyle.wrap.CompareNoCase(L"no") ? 2 : + /*!s->fontstyle.wrap.CompareNoCase(L"auto") ? 1 :*/ + 1; + + if (WrapStyle != sts.m_defaultWrapStyle) { + CStringW str; + str.Format(L"{\\q%d}", WrapStyle); + t->str = str + t->str; + } + + break; + } + } + } + + // TODO: apply effects as {\t(..)} after usf's standard clearly defines them + + sts.Add(t->str, true, t->start, t->stop, WToT(t->style), _T(""), _T(""), marginRect); + } + + return true; +} + +bool CUSFSubtitles::ParseUSFSubtitles(CComPtr pNode) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"usfsubtitles") { + // metadata + + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"metadata") { + ParseMetadata(pChild, metadata); + } + } + EndEnumChildren; + + // styles + + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"styles") { + BeginEnumChildren(pChild, pGrandChild) { // :) + DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); + + if (grandChildName == L"style") { + CAutoPtr s(DEBUG_NEW style_t); + if (s) { + ParseStyle(pGrandChild, s); + styles.AddTail(s); + } + } + } + EndEnumChildren; + } + } + EndEnumChildren; + + // effects + + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"effects") { + BeginEnumChildren(pChild, pGrandChild) { // :) + DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); + + if (grandChildName == L"effect") { + CAutoPtr e(DEBUG_NEW effect_t); + if (e) { + ParseEffect(pGrandChild, e); + effects.AddTail(e); + } + } + } + EndEnumChildren; + } + } + EndEnumChildren; + + // subtitles + + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"subtitles") { + BeginEnumChildren(pChild, pGrandChild) { // :) + DeclareNameAndValue(pGrandChild, grandChildName, grandChildVal); + + if (grandChildName == L"subtitle") { + CStringW sstart = GetAttrib(L"start", pGrandChild); + CStringW sstop = GetAttrib(L"stop", pGrandChild); + CStringW sduration = GetAttrib(L"duration", pGrandChild); + if (sstart.IsEmpty() || (sstop.IsEmpty() && sduration.IsEmpty())) { + continue; + } + + int start = TimeToInt(sstart); + int stop = !sstop.IsEmpty() ? TimeToInt(sstop) : (start + TimeToInt(sduration)); + + ParseSubtitle(pGrandChild, start, stop); + } + } + EndEnumChildren; + } + } + EndEnumChildren; + + return true; + } + + BeginEnumChildren(pNode, pChild) { + if (ParseUSFSubtitles(pChild)) { + return true; + } + } + EndEnumChildren; + + return false; +} + +void CUSFSubtitles::ParseMetadata(CComPtr pNode, metadata_t& m) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"title") { + m.title = GetText(pNode); + } else if (name == L"date") { + m.date = GetText(pNode); + } else if (name == L"comment") { + m.comment = GetText(pNode); + } else if (name == L"author") { + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"name") { + m.author.name = GetText(pChild); + } else if (childName == L"email") { + m.author.email = GetText(pChild); + } else if (childName == L"url") { + m.author.url = GetText(pChild); + } + } + EndEnumChildren; + + return; + } else if (name == L"language") { + m.language.text = GetText(pNode); + m.language.code = GetAttrib(L"code", pNode); + } else if (name == L"languageext") { + m.languageext.text = GetText(pNode); + m.languageext.code = GetAttrib(L"code", pNode); + } + + BeginEnumChildren(pNode, pChild) { + ParseMetadata(pChild, metadata); + } + EndEnumChildren; +} + +void CUSFSubtitles::ParseStyle(CComPtr pNode, style_t* s) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"style") { + s->name = GetAttrib(L"name", pNode); + } else if (name == L"fontstyle") { + ParseFontstyle(pNode, s->fontstyle); + return; + } else if (name == L"position") { + ParsePal(pNode, s->pal); + return; + } + + BeginEnumChildren(pNode, pChild) { + ParseStyle(pChild, s); + } + EndEnumChildren; +} + +void CUSFSubtitles::ParseFontstyle(CComPtr pNode, fontstyle_t& fs) +{ + fs.face = GetAttrib(L"face", pNode); + fs.size = GetAttrib(L"size", pNode); + fs.color[0] = GetAttrib(L"color", pNode); + fs.color[1] = GetAttrib(L"back-color", pNode); + fs.color[2] = GetAttrib(L"outline-color", pNode); + fs.color[3] = GetAttrib(L"shadow-color", pNode); + fs.italic = GetAttrib(L"italic", pNode); + fs.weight = GetAttrib(L"weight", pNode); + fs.underline = GetAttrib(L"underline", pNode); + fs.alpha = GetAttrib(L"alpha", pNode); + fs.outline = GetAttrib(L"outline-level", pNode); + fs.shadow = GetAttrib(L"shadow-level", pNode); + fs.wrap = GetAttrib(L"wrap", pNode); +} + +void CUSFSubtitles::ParsePal(CComPtr pNode, posattriblist_t& pal) +{ + pal.alignment = GetAttrib(L"alignment", pNode); + pal.relativeto = GetAttrib(L"relative-to", pNode); + pal.horizontal_margin = GetAttrib(L"horizontal-margin", pNode); + pal.vertical_margin = GetAttrib(L"vertical-margin", pNode); + pal.rotate[0] = GetAttrib(L"rotate-z", pNode); + pal.rotate[1] = GetAttrib(L"rotate-x", pNode); + pal.rotate[2] = GetAttrib(L"rotate-y", pNode); +} + +void CUSFSubtitles::ParseEffect(CComPtr pNode, effect_t* e) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"effect") { + e->name = GetAttrib(L"name", pNode); + } else if (name == L"keyframes") { + BeginEnumChildren(pNode, pChild) { + DeclareNameAndValue(pChild, childName, childVal); + + if (childName == L"keyframe") { + CAutoPtr k(DEBUG_NEW keyframe_t); + if (k) { + ParseKeyframe(pChild, k); + e->keyframes.AddTail(k); + } + } + } + EndEnumChildren; + + return; + } + + BeginEnumChildren(pNode, pChild) { + ParseEffect(pChild, e); + } + EndEnumChildren; +} + +void CUSFSubtitles::ParseKeyframe(CComPtr pNode, keyframe_t* k) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"keyframe") { + k->position = GetAttrib(L"position", pNode); + } else if (name == L"fontstyle") { + ParseFontstyle(pNode, k->fontstyle); + return; + } else if (name == L"position") { + ParsePal(pNode, k->pal); + return; + } +} + +void CUSFSubtitles::ParseSubtitle(CComPtr pNode, int start, int stop) +{ + DeclareNameAndValue(pNode, name, val); + + if (name == L"text" || name == L"karaoke") { + CAutoPtr t(DEBUG_NEW text_t); + if (t) { + t->start = start; + t->stop = stop; + t->style = GetAttrib(L"style", pNode); + t->effect = GetAttrib(L"effect", pNode); + ParsePal(pNode, t->pal); + ParseText(pNode, t->str); + texts.AddTail(t); + } + + return; + } + // else if + + BeginEnumChildren(pNode, pChild) { + ParseSubtitle(pChild, start, stop); + } + EndEnumChildren; +} + +void CUSFSubtitles::ParseText(CComPtr pNode, CStringW& str) +{ + DeclareNameAndValue(pNode, name, val); + + CStringW prefix, postfix; + + if (name == L"b") { + prefix = L"{\\b1}"; + postfix = L"{\\b}"; + } else if (name == L"i") { + prefix = L"{\\i1}"; + postfix = L"{\\i}"; + } else if (name == L"u") { + prefix = L"{\\u1}"; + postfix = L"{\\u}"; + } else if (name == L"font") { + fontstyle_t fs; + ParseFontstyle(pNode, fs); + + if (!fs.face.IsEmpty()) { + prefix += L"{\\fn" + fs.face + L"}"; + postfix += L"{\\fn}"; + } + if (!fs.size.IsEmpty()) { + prefix += L"{\\fs" + fs.size + L"}"; + postfix += L"{\\fs}"; + } + if (!fs.outline.IsEmpty()) { + prefix += L"{\\bord" + fs.outline + L"}"; + postfix += L"{\\bord}"; + } + if (!fs.shadow.IsEmpty()) { + prefix += L"{\\shad" + fs.shadow + L"}"; + postfix += L"{\\shad}"; + } + + for (size_t i = 0; i < 4; i++) { + if (!fs.color[i].IsEmpty()) { + CStringW s; + s.Format(L"{\\%uc&H%06x&}", i + 1, ColorToDWORD(fs.color[i])); + prefix += s; + s.Format(L"{\\%uc}", i + 1); + postfix += s; + } + } + } else if (name == L"k") { + int t = wcstol(GetAttrib(L"t", pNode), nullptr, 10); + CStringW s; + s.Format(L"{\\kf%d}", t / 10); + str += s; + return; + } else if (name == L"br") { + str += L"\\N"; + return; + } else if (name == L"#text") { + str += GetXML(pNode); + return; + } + + BeginEnumChildren(pNode, pChild) { + CStringW s; + ParseText(pChild, s); + str += s; + } + EndEnumChildren; + + str = prefix + str + postfix; +} + +void CUSFSubtitles::ParseShape(CComPtr pNode) +{ + // no specs on this yet +} diff --git a/src/Subtitles/USFSubtitles.h b/src/Subtitles/USFSubtitles.h index c80eecec0ff..2d81a34ee89 100644 --- a/src/Subtitles/USFSubtitles.h +++ b/src/Subtitles/USFSubtitles.h @@ -1,103 +1,103 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "STS.h" - -// metadata -struct author_t { - CStringW name, email, url; -}; - -struct language_t { - CStringW code, text; -}; - -struct metadata_t { - CStringW title, date, comment; - author_t author; - language_t language, languageext; -}; - -// style -struct posattriblist_t { - CStringW alignment, relativeto, horizontal_margin, vertical_margin, rotate[3]; -}; - -struct fontstyle_t { - CStringW face, size, color[4], weight, italic, underline, alpha, outline, shadow, wrap; -}; - -struct style_t { - CStringW name; - fontstyle_t fontstyle; - posattriblist_t pal; -}; - -// effect -struct keyframe_t { - CStringW position; - fontstyle_t fontstyle; - posattriblist_t pal; -}; - -struct effect_t { - CStringW name; - CAutoPtrList keyframes; -}; - -// subtitle/text -struct text_t { - int start, stop; - CStringW effect, style, str; - posattriblist_t pal; -}; - -class CUSFSubtitles -{ - bool ParseUSFSubtitles(CComPtr pNode); - void ParseMetadata(CComPtr pNode, metadata_t& m); - void ParseStyle(CComPtr pNode, style_t* s); - void ParseFontstyle(CComPtr pNode, fontstyle_t& fs); - void ParsePal(CComPtr pNode, posattriblist_t& pal); - void ParseEffect(CComPtr pNode, effect_t* e); - void ParseKeyframe(CComPtr pNode, keyframe_t* k); - void ParseSubtitle(CComPtr pNode, int start, int stop); - void ParseText(CComPtr pNode, CStringW& assstr); - void ParseShape(CComPtr pNode); - -public: - CUSFSubtitles(); - virtual ~CUSFSubtitles(); - - bool Read(LPCTSTR fn); - //bool Write(LPCTSTR fn); // TODO - - metadata_t metadata; - CAutoPtrList styles; - CAutoPtrList effects; - CAutoPtrList texts; - - bool ConvertToSTS(CSimpleTextSubtitle& sts); - //bool ConvertFromSTS(CSimpleTextSubtitle& sts); // TODO -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "STS.h" + +// metadata +struct author_t { + CStringW name, email, url; +}; + +struct language_t { + CStringW code, text; +}; + +struct metadata_t { + CStringW title, date, comment; + author_t author; + language_t language, languageext; +}; + +// style +struct posattriblist_t { + CStringW alignment, relativeto, horizontal_margin, vertical_margin, rotate[3]; +}; + +struct fontstyle_t { + CStringW face, size, color[4], weight, italic, underline, alpha, outline, shadow, wrap; +}; + +struct style_t { + CStringW name; + fontstyle_t fontstyle; + posattriblist_t pal; +}; + +// effect +struct keyframe_t { + CStringW position; + fontstyle_t fontstyle; + posattriblist_t pal; +}; + +struct effect_t { + CStringW name; + CAutoPtrList keyframes; +}; + +// subtitle/text +struct text_t { + int start, stop; + CStringW effect, style, str; + posattriblist_t pal; +}; + +class CUSFSubtitles +{ + bool ParseUSFSubtitles(CComPtr pNode); + void ParseMetadata(CComPtr pNode, metadata_t& m); + void ParseStyle(CComPtr pNode, style_t* s); + void ParseFontstyle(CComPtr pNode, fontstyle_t& fs); + void ParsePal(CComPtr pNode, posattriblist_t& pal); + void ParseEffect(CComPtr pNode, effect_t* e); + void ParseKeyframe(CComPtr pNode, keyframe_t* k); + void ParseSubtitle(CComPtr pNode, int start, int stop); + void ParseText(CComPtr pNode, CStringW& assstr); + void ParseShape(CComPtr pNode); + +public: + CUSFSubtitles(); + virtual ~CUSFSubtitles(); + + bool Read(LPCTSTR fn); + //bool Write(LPCTSTR fn); // TODO + + metadata_t metadata; + CAutoPtrList styles; + CAutoPtrList effects; + CAutoPtrList texts; + + bool ConvertToSTS(CSimpleTextSubtitle& sts); + //bool ConvertFromSTS(CSimpleTextSubtitle& sts); // TODO +}; diff --git a/src/Subtitles/VobSubFile.cpp b/src/Subtitles/VobSubFile.cpp index afba8f9120b..9ee8a5210f0 100644 --- a/src/Subtitles/VobSubFile.cpp +++ b/src/Subtitles/VobSubFile.cpp @@ -1,2650 +1,2650 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "TextFile.h" -#include "VobSubFile.h" -#include "mpc-hc_config.h" - -#if !USE_STATIC_UNRAR -#include "unrar.h" -#else -#include "unrar/dll.hpp" -#endif -#include "RTS.h" -#include "../DSUtil/PathUtils.h" -#include "../DSUtil/ISOLang.h" - -// - -struct lang_type { - unsigned short id; - LPCSTR lang_long; -} static constexpr lang_tbl[] = { - {'--', "(Not detected)"}, - {'cc', "Closed Caption"}, - {'aa', "Afar"}, - {'ab', "Abkhazian"}, - {'af', "Afrikaans"}, - {'am', "Amharic"}, - {'ar', "Arabic"}, - {'as', "Assamese"}, - {'ay', "Aymara"}, - {'az', "Azerbaijani"}, - {'ba', "Bashkir"}, - {'be', "Byelorussian"}, - {'bg', "Bulgarian"}, - {'bh', "Bihari"}, - {'bi', "Bislama"}, - {'bn', "Bengali; Bangla"}, - {'bo', "Tibetan"}, - {'br', "Breton"}, - {'ca', "Catalan"}, - {'co', "Corsican"}, - {'cs', "Czech"}, - {'cy', "Welsh"}, - {'da', "Dansk"}, - {'de', "Deutsch"}, - {'dz', "Bhutani"}, - {'el', "Greek"}, - {'en', "English"}, - {'eo', "Esperanto"}, - {'es', "Espanol"}, - {'et', "Estonian"}, - {'eu', "Basque"}, - {'fa', "Persian"}, - {'fi', "Finnish"}, - {'fj', "Fiji"}, - {'fo', "Faroese"}, - {'fr', "Francais"}, - {'fy', "Frisian"}, - {'ga', "Irish"}, - {'gd', "Scots Gaelic"}, - {'gl', "Galician"}, - {'gn', "Guarani"}, - {'gu', "Gujarati"}, - {'ha', "Hausa"}, - {'he', "Hebrew"}, - {'hi', "Hindi"}, - {'hr', "Hrvatski"}, - {'hu', "Hungarian"}, - {'hy', "Armenian"}, - {'ia', "Interlingua"}, - {'id', "Indonesian"}, - {'ie', "Interlingue"}, - {'ik', "Inupiak"}, - {'in', "Indonesian"}, - {'is', "Islenska"}, - {'it', "Italiano"}, - {'iu', "Inuktitut"}, - {'iw', "Hebrew"}, - {'ja', "Japanese"}, - {'ji', "Yiddish"}, - {'jw', "Javanese"}, - {'ka', "Georgian"}, - {'kk', "Kazakh"}, - {'kl', "Greenlandic"}, - {'km', "Cambodian"}, - {'kn', "Kannada"}, - {'ko', "Korean"}, - {'ks', "Kashmiri"}, - {'ku', "Kurdish"}, - {'ky', "Kirghiz"}, - {'la', "Latin"}, - {'ln', "Lingala"}, - {'lo', "Laothian"}, - {'lt', "Lithuanian"}, - {'lv', "Latvian, Lettish"}, - {'mg', "Malagasy"}, - {'mi', "Maori"}, - {'mk', "Macedonian"}, - {'ml', "Malayalam"}, - {'mn', "Mongolian"}, - {'mo', "Moldavian"}, - {'mr', "Marathi"}, - {'ms', "Malay"}, - {'mt', "Maltese"}, - {'my', "Burmese"}, - {'na', "Nauru"}, - {'ne', "Nepali"}, - {'nl', "Nederlands"}, - {'no', "Norsk"}, - {'oc', "Occitan"}, - {'om', "(Afan) Oromo"}, - {'or', "Oriya"}, - {'pa', "Punjabi"}, - {'pl', "Polish"}, - {'ps', "Pashto, Pushto"}, - {'pt', "Portugues"}, - {'qu', "Quechua"}, - {'rm', "Rhaeto-Romance"}, - {'rn', "Kirundi"}, - {'ro', "Romanian"}, - {'ru', "Russian"}, - {'rw', "Kinyarwanda"}, - {'sa', "Sanskrit"}, - {'sd', "Sindhi"}, - {'sg', "Sangho"}, - {'sh', "Serbo-Croatian"}, - {'si', "Sinhalese"}, - {'sk', "Slovak"}, - {'sl', "Slovenian"}, - {'sm', "Samoan"}, - {'sn', "Shona"}, - {'so', "Somali"}, - {'sq', "Albanian"}, - {'sr', "Serbian"}, - {'ss', "Siswati"}, - {'st', "Sesotho"}, - {'su', "Sundanese"}, - {'sv', "Svenska"}, - {'sw', "Swahili"}, - {'ta', "Tamil"}, - {'te', "Telugu"}, - {'tg', "Tajik"}, - {'th', "Thai"}, - {'ti', "Tigrinya"}, - {'tk', "Turkmen"}, - {'tl', "Tagalog"}, - {'tn', "Setswana"}, - {'to', "Tonga"}, - {'tr', "Turkish"}, - {'ts', "Tsonga"}, - {'tt', "Tatar"}, - {'tw', "Twi"}, - {'ug', "Uighur"}, - {'uk', "Ukrainian"}, - {'ur', "Urdu"}, - {'uz', "Uzbek"}, - {'vi', "Vietnamese"}, - {'vo', "Volapuk"}, - {'wo', "Wolof"}, - {'xh', "Xhosa"}, - {'yi', "Yiddish"}, // formerly ji - {'yo', "Yoruba"}, - {'za', "Zhuang"}, - {'zh', "Chinese"}, - {'zu', "Zulu"}, -}; - -int find_lang(unsigned short id) -{ - int lo = 0, hi = _countof(lang_tbl) - 1; - - while (lo < hi) { - int mid = (lo + hi) >> 1; - - if (id < lang_tbl[mid].id) { - hi = mid; - } else if (id > lang_tbl[mid].id) { - lo = mid + 1; - } else { - return mid; - } - } - - return (id == lang_tbl[lo].id ? lo : 0); -} - -CString FindLangFromId(WORD id) -{ - return CString(lang_tbl[find_lang(id)].lang_long); -} - -// -// CVobSubFile -// - -CVobSubFile::CVobSubFile(CCritSec* pLock) - : CSubPicProviderImpl(pLock) - , m_sub(1024 * 1024) - , m_nLang(0) -{ -} - -CVobSubFile::~CVobSubFile() -{ -} - -// - -bool CVobSubFile::Copy(CVobSubFile& vsf) -{ - Close(); - - *(CVobSubSettings*)this = *(CVobSubSettings*)&vsf; - m_title = vsf.m_title; - m_nLang = vsf.m_nLang; - - m_sub.SetLength(vsf.m_sub.GetLength()); - m_sub.SeekToBegin(); - - for (size_t i = 0; i < m_langs.size(); i++) { - SubLang& src = vsf.m_langs[i]; - SubLang& dst = m_langs[i]; - - dst.id = src.id; - dst.name = src.name; - dst.alt = src.alt; - - for (size_t j = 0; j < src.subpos.GetCount(); j++) { - SubPos& sp = src.subpos[j]; - if (!sp.bValid) { - continue; - } - - if (sp.filepos != (__int64)vsf.m_sub.Seek(sp.filepos, CFile::begin)) { - continue; - } - - sp.filepos = m_sub.GetPosition(); - - BYTE buff[2048]; - UINT uRead = vsf.m_sub.Read(buff, 2048); - m_sub.Write(buff, uRead); - - WORD packetsize = (buff[buff[0x16] + 0x18] << 8) | buff[buff[0x16] + 0x19]; - - for (int k = 0, size, sizeleft = packetsize - 4; - k < packetsize - 4; - k += size, sizeleft -= size) { - int hsize = buff[0x16] + 0x18 + ((buff[0x15] & 0x80) ? 4 : 0); - size = std::min(sizeleft, 2048 - hsize); - - if (size != sizeleft) { - while ((uRead = vsf.m_sub.Read(buff, 2048)) > 0) { - if (!(buff[0x15] & 0x80) && buff[buff[0x16] + 0x17] == (i | 0x20)) { - break; - } - } - - m_sub.Write(buff, uRead); - } - } - - dst.subpos.Add(sp); - } - } - - m_sub.SetLength(m_sub.GetPosition()); - - return true; -} - -// - -void CVobSubFile::TrimExtension(CString& fn) -{ - int i = fn.ReverseFind('.'); - if (i > 0) { - CString ext = fn.Mid(i).MakeLower(); - if (ext == _T(".ifo") || ext == _T(".idx") || ext == _T(".sub") - || ext == _T(".sst") || ext == _T(".son") || ext == _T(".rar")) { - fn = fn.Left(i); - } - } -} - -bool CVobSubFile::Open(CString fn) -{ - m_path = fn; - TrimExtension(fn); - - do { - Close(); - - int ver; - if (!ReadIdx(fn + _T(".idx"), ver)) { - break; - } - - if (ver < 6 && !ReadIfo(fn + _T(".ifo"))) { - break; - } - - if (!ReadSub(fn + _T(".sub")) && !ReadRar(fn + _T(".rar"))) { - break; - } - - m_title = fn; - - for (size_t i = 0; i < m_langs.size(); i++) { - CAtlArray& sp = m_langs[i].subpos; - - for (size_t j = 0; j < sp.GetCount(); j++) { - sp[j].stop = sp[j].start; - sp[j].bForced = false; - - size_t packetSize = 0, dataSize = 0; - BYTE* buff = GetPacket(j, packetSize, dataSize, i); - if (!buff) { - sp[j].bValid = false; - continue; - } - - m_img.delay = j + 1 < sp.GetCount() ? sp[j + 1].start - sp[j].start : 3000; - m_img.GetPacketInfo(buff, packetSize, dataSize); - if (j + 1 < sp.GetCount()) { - m_img.delay = std::min(m_img.delay, sp[j + 1].start - sp[j].start); - } - - sp[j].stop = sp[j].start + m_img.delay; - sp[j].bForced = m_img.bForced; - sp[j].bAnimated = m_img.bAnimated; - - if (j > 0 && sp[j - 1].stop > sp[j].start) { - sp[j - 1].stop = sp[j].start; - } - - delete [] buff; - } - } - - return true; - } while (false); - - Close(); - - return false; -} - -bool CVobSubFile::Save(CString fn, int delay, SubFormat sf) -{ - TrimExtension(fn); - - CVobSubFile vsf(nullptr); - if (!vsf.Copy(*this)) { - return false; - } - - switch (sf) { - case VobSub: - return vsf.SaveVobSub(fn, delay); - case WinSubMux: - return vsf.SaveWinSubMux(fn, delay); - case Scenarist: - return vsf.SaveScenarist(fn, delay); - case Maestro: - return vsf.SaveMaestro(fn, delay); - default: - break; - } - - return false; -} - -void CVobSubFile::Close() -{ - InitSettings(); - m_title.Empty(); - m_sub.SetLength(0); - m_img.Invalidate(); - m_nLang = SIZE_T_ERROR; - for (auto& sl : m_langs) { - sl.id = 0; - sl.name.Empty(); - sl.alt.Empty(); - sl.subpos.RemoveAll(); - } -} - -// - -bool CVobSubFile::ReadIdx(CString fn, int& ver) -{ - CWebTextFile f; - if (!f.Open(fn)) { - return false; - } - - bool bError = false; - - int id = -1, delay = 0, vobid = -1, cellid = -1; - __int64 celltimestamp = 0; - - CString str; - for (ptrdiff_t line = 0; !bError && f.ReadString(str); line++) { - str.Trim(); - - if (line == 0) { - TCHAR buff[] = _T("VobSub index file, v"); - - const TCHAR* s = str; - - int i = str.Find(buff); - if (i < 0 || _stscanf_s(&s[i + _tcslen(buff)], _T("%d"), &ver) != 1 - || ver > VOBSUBIDXVER) { - TRACE(_T("[CVobSubFile::ReadIdx] Wrong file version!\n")); - bError = true; - continue; - } - } else if (!str.GetLength()) { - continue; - } else if (str[0] == _T('#')) { - TCHAR buff[] = _T("Vob/Cell ID:"); - - const TCHAR* s = str; - - int i = str.Find(buff); - if (i >= 0) { - _stscanf_s(&s[i + _tcslen(buff)], _T("%d, %d (PTS: %I64d)"), &vobid, &cellid, &celltimestamp); - } - - continue; - } - - int i = str.Find(':'); - if (i <= 0) { - continue; - } - - CString entry = str.Left(i).MakeLower(); - - str = str.Mid(i + 1); - str.Trim(); - if (str.IsEmpty()) { - continue; - } - - if (entry == _T("size")) { - int x, y; - if (_stscanf_s(str, _T("%dx%d"), &x, &y) != 2) { - bError = true; - } - m_size.cx = x; - m_size.cy = y; - } else if (entry == _T("org")) { - if (_stscanf_s(str, _T("%d,%d"), &m_x, &m_y) != 2) { - bError = true; - } else { - m_org = CPoint(m_x, m_y); - } - } else if (entry == _T("scale")) { - if (ver < 5) { - int scale = 100; - if (_stscanf_s(str, _T("%d%%"), &scale) != 1) { - bError = true; - } - m_scale_x = m_scale_y = scale; - } else { - if (_stscanf_s(str, _T("%d%%,%d%%"), &m_scale_x, &m_scale_y) != 2) { - bError = true; - } - } - } else if (entry == _T("alpha")) { - if (_stscanf_s(str, _T("%d"), &m_alpha) != 1) { - bError = true; - } - } else if (entry == _T("smooth")) { - str.MakeLower(); - - if (str.Find(_T("old")) >= 0 || str.Find(_T("2")) >= 0) { - m_iSmooth = 2; - } else if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { - m_iSmooth = 1; - } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { - m_iSmooth = 0; - } else { - bError = true; - } - } else if (entry == _T("fadein/out")) { - if (_stscanf_s(str, _T("%d,%d"), &m_fadein, &m_fadeout) != 2) { - bError = true; - } - } else if (entry == _T("align")) { - str.MakeLower(); - - int k = 0; - CString token; - for (int j = 0; j < 3; j++) { - token = str.Tokenize(_T(" "), k); - if (token.IsEmpty()) { - break; - } - - if (j == 0) { - if (token == _T("on") || token == _T("1")) { - m_bAlign = true; - } else if (token == _T("off") || token == _T("0")) { - m_bAlign = false; - } else { - bError = true; - break; - } - } else if (j == 1) { - if (token == _T("at")) { - j--; - continue; - } - - if (token == _T("left")) { - m_alignhor = 0; - } else if (token == _T("center")) { - m_alignhor = 1; - } else if (token == _T("right")) { - m_alignhor = 2; - } else { - bError = true; - break; - } - } else if (j == 2) { - if (token == _T("top")) { - m_alignver = 0; - } else if (token == _T("center")) { - m_alignver = 1; - } else if (token == _T("bottom")) { - m_alignver = 2; - } else { - bError = true; - break; - } - } - } - } else if (entry == _T("time offset")) { - bool bNegative = false; - if (str[0] == '-') { - bNegative = true; - } - str.TrimLeft(_T("+-")); - - TCHAR c; - int hh, mm, ss, ms; - int n = _stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms); - - switch (n) { - case 1: // We have read only one integer, interpret it as an offset expressed in milliseconds - m_toff = hh * (bNegative ? -1 : 1); - break; - case 7: // We have read 4 integers + 3 separators, interpret them as hh:mm:ss.ms - m_toff = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1); - break; - default: - bError = true; - m_toff = 0; - break; - } - } else if (entry == _T("forced subs")) { - str.MakeLower(); - - if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { - m_bOnlyShowForcedSubs = true; - } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { - m_bOnlyShowForcedSubs = false; - } else { - bError = true; - } - } else if (entry == _T("langidx")) { - int iLang = -1; - if (_stscanf_s(str, _T("%d"), &iLang) != 1) { - bError = true; - } - m_nLang = (iLang < 0 && size_t(iLang) >= m_langs.size()) ? SIZE_T_ERROR : size_t(iLang); - } else if (entry == _T("palette")) { - // The assert guarantees that the shortcut we use will work as expected - static_assert(sizeof(RGBQUAD) == 4, "Packing error"); -#pragma warning(push) -#pragma warning(disable: 4477) - if (_stscanf_s(str, _T("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"), - &m_orgpal[0], &m_orgpal[1], &m_orgpal[2], &m_orgpal[3], - &m_orgpal[4], &m_orgpal[5], &m_orgpal[6], &m_orgpal[7], - &m_orgpal[8], &m_orgpal[9], &m_orgpal[10], &m_orgpal[11], - &m_orgpal[12], &m_orgpal[13], &m_orgpal[14], &m_orgpal[15] - ) != 16) { -#pragma warning(pop) - bError = true; - } - } else if (entry == _T("custom colors")) { - str.MakeLower(); - - if (str.Find(_T("on")) == 0 || str.Find(_T("1")) == 0) { - m_bCustomPal = true; - } else if (str.Find(_T("off")) == 0 || str.Find(_T("0")) == 0) { - m_bCustomPal = false; - } else { - bError = true; - } - - i = str.Find(_T("tridx:")); - if (i < 0) { - bError = true; - continue; - } - str = str.Mid(i + (int)_tcslen(_T("tridx:"))); - - int tridx; - if (_stscanf_s(str, _T("%x"), &tridx) != 1) { - bError = true; - continue; - } - tridx = ((tridx & 0x1000) >> 12) | ((tridx & 0x100) >> 7) | ((tridx & 0x10) >> 2) | ((tridx & 1) << 3); - - i = str.Find(_T("colors:")); - if (i < 0) { - bError = true; - continue; - } - str = str.Mid(i + (int)_tcslen(_T("colors:"))); - - RGBQUAD pal[4]; -#pragma warning(push) -#pragma warning(disable: 4477) - if (_stscanf_s(str, _T("%x,%x,%x,%x"), &pal[0], &pal[1], &pal[2], &pal[3]) != 4) { -#pragma warning(pop) - bError = true; - continue; - } - - SetCustomPal(pal, tridx); - } else if (entry == _T("id")) { - str.MakeLower(); - - WORD langid = ((str[0] & 0xff) << 8) | (str[1] & 0xff); - - i = str.Find(_T("index:")); - if (i < 0) { - bError = true; - continue; - } - str = str.Mid(i + (int)_tcslen(_T("index:"))); - - if (_stscanf_s(str, _T("%d"), &id) != 1 || id < 0 || size_t(id) >= m_langs.size()) { - bError = true; - continue; - } - if (m_nLang == SIZE_T_ERROR) { - m_nLang = size_t(id); - } - - m_langs[id].id = langid; - m_langs[id].name = lang_tbl[find_lang(langid)].lang_long; - m_langs[id].alt = lang_tbl[find_lang(langid)].lang_long; - - delay = 0; - } else if (id >= 0 && entry == _T("alt")) { - m_langs[id].alt = str; - } else if (id >= 0 && entry == _T("delay")) { - bool bNegative = false; - if (str[0] == '-') { - bNegative = true; - } - str.TrimLeft(_T("+-")); - - TCHAR c; - int hh, mm, ss, ms; - if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { - bError = true; - continue; - } - - delay += (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1); - } else if (id >= 0 && entry == _T("timestamp")) { - SubPos sb; - - sb.vobid = (char)vobid; - sb.cellid = (char)cellid; - sb.celltimestamp = celltimestamp; - sb.bValid = true; - - bool bNegative = false; - if (str[0] == '-') { - bNegative = true; - } - str.TrimLeft(_T("+-")); - - TCHAR c; - int hh, mm, ss, ms; - if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { - bError = true; - continue; - } - - sb.start = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1) + delay; - - i = str.Find(_T("filepos:")); - if (i < 0) { - bError = true; - continue; - } - str = str.Mid(i + (int)_tcslen(_T("filepos:"))); - - if (_stscanf_s(str, _T("%I64x"), &sb.filepos) != 1) { - bError = true; - continue; - } - - if (delay < 0 && !m_langs[id].subpos.IsEmpty()) { - __int64 ts = m_langs[id].subpos[m_langs[id].subpos.GetCount() - 1].start; - - if (sb.start < ts) { - delay += (int)(ts - sb.start); - sb.start = ts; - } - } - - m_langs[id].subpos.Add(sb); - } else { - bError = true; - } - } - - return !bError; -} - -bool CVobSubFile::ReadSub(CString fn) -{ - CFile f; - if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - - int len; - BYTE buff[2048]; - try { - m_sub.SetLength(f.GetLength()); - m_sub.SeekToBegin(); - while ((len = f.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { - m_sub.Write(buff, len); - } - } - catch (CFileException*) { - return false; - } - - return true; -} - -static unsigned char* RARbuff = nullptr; -static unsigned int RARpos = 0; - -static int CALLBACK MyCallbackProc(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2) -{ - if (msg == UCM_PROCESSDATA) { - ASSERT(RARbuff); - - memcpy(&RARbuff[RARpos], (char*)P1, (size_t)P2); - RARpos += (unsigned int)P2; - } - - return 1; -} - -bool CVobSubFile::ReadRar(CString fn) -{ -#if !USE_STATIC_UNRAR -#ifdef _WIN64 - HMODULE h = LoadLibrary(_T("unrar64.dll")); -#else - HMODULE h = LoadLibrary(_T("unrar.dll")); -#endif - if (!h) { - return false; - } - - RAROpenArchiveEx OpenArchiveEx = (RAROpenArchiveEx)GetProcAddress(h, "RAROpenArchiveEx"); - RARCloseArchive CloseArchive = (RARCloseArchive)GetProcAddress(h, "RARCloseArchive"); - RARReadHeaderEx ReadHeaderEx = (RARReadHeaderEx)GetProcAddress(h, "RARReadHeaderEx"); - RARProcessFile ProcessFile = (RARProcessFile)GetProcAddress(h, "RARProcessFile"); - RARSetCallback SetCallback = (RARSetCallback)GetProcAddress(h, "RARSetCallback"); - - if (!(OpenArchiveEx && CloseArchive && ReadHeaderEx && ProcessFile && SetCallback)) { - FreeLibrary(h); - return false; - } - -#else - -#define OpenArchiveEx RAROpenArchiveEx -#define CloseArchive RARCloseArchive -#define ReadHeaderEx RARReadHeaderEx -#define ProcessFile RARProcessFile -#define SetCallback RARSetCallback -#endif /* USE_STATIC_UNRAR */ - - RAROpenArchiveDataEx OpenArchiveData; - ZeroMemory(&OpenArchiveData, sizeof(OpenArchiveData)); - - OpenArchiveData.ArcNameW = (LPTSTR)(LPCTSTR)fn; - char fnA[MAX_PATH]; - size_t size; - if (wcstombs_s(&size, fnA, fn, fn.GetLength())) { - fnA[0] = 0; - } - OpenArchiveData.ArcName = fnA; - OpenArchiveData.OpenMode = RAR_OM_EXTRACT; - OpenArchiveData.CmtBuf = 0; - OpenArchiveData.Callback = MyCallbackProc; - HANDLE hArcData = OpenArchiveEx(&OpenArchiveData); - if (!hArcData) { -#if !USE_STATIC_UNRAR - FreeLibrary(h); -#endif - return false; - } - - RARHeaderDataEx HeaderDataEx; - HeaderDataEx.CmtBuf = nullptr; - - while (ReadHeaderEx(hArcData, &HeaderDataEx) == 0) { - CString subfn(HeaderDataEx.FileNameW); - - if (!subfn.Right(4).CompareNoCase(_T(".sub"))) { - CAutoVectorPtr buff; - if (!buff.Allocate(HeaderDataEx.UnpSize)) { - CloseArchive(hArcData); -#if !USE_STATIC_UNRAR - FreeLibrary(h); -#endif - return false; - } - - RARbuff = buff; - RARpos = 0; - - if (ProcessFile(hArcData, RAR_TEST, nullptr, nullptr)) { - CloseArchive(hArcData); -#if !USE_STATIC_UNRAR - FreeLibrary(h); -#endif - - return false; - } - - m_sub.SetLength(HeaderDataEx.UnpSize); - m_sub.SeekToBegin(); - m_sub.Write(buff, HeaderDataEx.UnpSize); - m_sub.SeekToBegin(); - - RARbuff = nullptr; - RARpos = 0; - - break; - } - - ProcessFile(hArcData, RAR_SKIP, nullptr, nullptr); - } - - CloseArchive(hArcData); -#if !USE_STATIC_UNRAR - FreeLibrary(h); -#endif - - return true; -} - -bool CVobSubFile::ReadIfo(CString fn) -{ - CFile f; - if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - - /* PGC1 */ - - f.Seek(0xc0 + 0x0c, SEEK_SET); - - DWORD pos; - ReadBEdw(pos); - - f.Seek(pos * 0x800 + 0x0c, CFile::begin); - - DWORD offset; - ReadBEdw(offset); - - /* Subpic palette */ - - f.Seek(pos * 0x800 + offset + 0xa4, CFile::begin); - - for (size_t i = 0; i < 16; i++) { - BYTE y, u, v, tmp; - - f.Read(&tmp, 1); - f.Read(&y, 1); - f.Read(&u, 1); - f.Read(&v, 1); - - y = (y - 16) * 255 / 219; - - m_orgpal[i].rgbRed = std::min(std::max(BYTE(1.0 * y + 1.4022 * (u - 128)), 0u), 255u); - m_orgpal[i].rgbGreen = std::min(std::max(BYTE(1.0 * y - 0.3456 * (u - 128) - 0.7145 * (v - 128)), 0u), 255u); - m_orgpal[i].rgbBlue = std::min(std::max(BYTE(1.0 * y + 1.7710 * (v - 128)), 0u), 255u); - } - - return true; -} - -bool CVobSubFile::WriteIdx(CString fn, int delay) -{ - CTextFile f; - if (!f.Save(fn, CTextFile::DEFAULT_ENCODING)) { - return false; - } - - CString str; - str.Format(_T("# VobSub index file, v%d (do not modify this line!)\n"), VOBSUBIDXVER); - - f.WriteString(str); - f.WriteString(_T("# \n")); - f.WriteString(_T("# To repair desyncronization, you can insert gaps this way:\n")); - f.WriteString(_T("# (it usually happens after vob id changes)\n")); - f.WriteString(_T("# \n")); - f.WriteString(_T("#\t delay: [sign]hh:mm:ss:ms\n")); - f.WriteString(_T("# \n")); - f.WriteString(_T("# Where:\n")); - f.WriteString(_T("#\t [sign]: +, - (optional)\n")); - f.WriteString(_T("#\t hh: hours (0 <= hh)\n")); - f.WriteString(_T("#\t mm/ss: minutes/seconds (0 <= mm/ss <= 59)\n")); - f.WriteString(_T("#\t ms: milliseconds (0 <= ms <= 999)\n")); - f.WriteString(_T("# \n")); - f.WriteString(_T("#\t Note: You can't position a sub before the previous with a negative value.\n")); - f.WriteString(_T("# \n")); - f.WriteString(_T("# You can also modify timestamps or delete a few subs you don't like.\n")); - f.WriteString(_T("# Just make sure they stay in increasing order.\n")); - f.WriteString(_T("\n")); - f.WriteString(_T("\n")); - - // Settings - - f.WriteString(_T("# Settings\n\n")); - - f.WriteString(_T("# Original frame size\n")); - str.Format(_T("size: %ldx%ld\n\n"), m_size.cx, m_size.cy); - f.WriteString(str); - - f.WriteString(_T("# Origin, relative to the upper-left corner, can be overloaded by aligment\n")); - str.Format(_T("org: %d, %d\n\n"), m_x, m_y); - f.WriteString(str); - - f.WriteString(_T("# Image scaling (hor,ver), origin is at the upper-left corner or at the alignment coord (x, y)\n")); - str.Format(_T("scale: %d%%, %d%%\n\n"), m_scale_x, m_scale_y); - f.WriteString(str); - - f.WriteString(_T("# Alpha blending\n")); - str.Format(_T("alpha: %d%%\n\n"), m_alpha); - f.WriteString(str); - - f.WriteString(_T("# Smoothing for very blocky images (use OLD for no filtering)\n")); - str.Format(_T("smooth: %s\n\n"), m_iSmooth == 0 ? _T("OFF") : m_iSmooth == 1 ? _T("ON") : _T("OLD")); - f.WriteString(str); - - f.WriteString(_T("# In millisecs\n")); - str.Format(_T("fadein/out: %d, %d\n\n"), m_fadein, m_fadeout); - f.WriteString(str); - - f.WriteString(_T("# Force subtitle placement relative to (org.x, org.y)\n")); - str.Format(_T("align: %s %s %s\n\n"), - m_bAlign ? _T("ON at") : _T("OFF at"), - m_alignhor == 0 ? _T("LEFT") : m_alignhor == 1 ? _T("CENTER") : m_alignhor == 2 ? _T("RIGHT") : _T(""), - m_alignver == 0 ? _T("TOP") : m_alignver == 1 ? _T("CENTER") : m_alignver == 2 ? _T("BOTTOM") : _T("")); - f.WriteString(str); - - f.WriteString(_T("# For correcting non-progressive desync. (in millisecs or hh:mm:ss:ms)\n")); - f.WriteString(_T("# Note: Not effective in VSFilter, use \"delay: ... \" instead.\n")); - str.Format(_T("time offset: %u\n\n"), m_toff); - f.WriteString(str); - - f.WriteString(_T("# ON: displays only forced subtitles, OFF: shows everything\n")); - str.Format(_T("forced subs: %s\n\n"), m_bOnlyShowForcedSubs ? _T("ON") : _T("OFF")); - f.WriteString(str); - - f.WriteString(_T("# The original palette of the DVD\n")); - str.Format(_T("palette: %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n\n"), - *((unsigned int*)&m_orgpal[0]) & 0xffffff, - *((unsigned int*)&m_orgpal[1]) & 0xffffff, - *((unsigned int*)&m_orgpal[2]) & 0xffffff, - *((unsigned int*)&m_orgpal[3]) & 0xffffff, - *((unsigned int*)&m_orgpal[4]) & 0xffffff, - *((unsigned int*)&m_orgpal[5]) & 0xffffff, - *((unsigned int*)&m_orgpal[6]) & 0xffffff, - *((unsigned int*)&m_orgpal[7]) & 0xffffff, - *((unsigned int*)&m_orgpal[8]) & 0xffffff, - *((unsigned int*)&m_orgpal[9]) & 0xffffff, - *((unsigned int*)&m_orgpal[10]) & 0xffffff, - *((unsigned int*)&m_orgpal[11]) & 0xffffff, - *((unsigned int*)&m_orgpal[12]) & 0xffffff, - *((unsigned int*)&m_orgpal[13]) & 0xffffff, - *((unsigned int*)&m_orgpal[14]) & 0xffffff, - *((unsigned int*)&m_orgpal[15]) & 0xffffff); - f.WriteString(str); - - int tridx = (!!(m_tridx & 1)) * 0x1000 + (!!(m_tridx & 2)) * 0x100 + (!!(m_tridx & 4)) * 0x10 + (!!(m_tridx & 8)); - - f.WriteString(_T("# Custom colors (transp idxs and the four colors)\n")); - str.Format(_T("custom colors: %s, tridx: %04x, colors: %06x, %06x, %06x, %06x\n\n"), - m_bCustomPal ? _T("ON") : _T("OFF"), - tridx, - *((unsigned int*)&m_cuspal[0]) & 0xffffff, - *((unsigned int*)&m_cuspal[1]) & 0xffffff, - *((unsigned int*)&m_cuspal[2]) & 0xffffff, - *((unsigned int*)&m_cuspal[3]) & 0xffffff); - f.WriteString(str); - - f.WriteString(_T("# Language index in use\n")); - str.Format(_T("langidx: %Iu\n\n"), m_nLang); - f.WriteString(str); - - if (delay) { - str.Format(_T("delay: %s%02d:%02d:%02d:%03d\n\n"), - delay < 0 ? _T("-") : _T(""), - abs(delay / 1000 / 60 / 60) % 60, - abs(delay / 1000 / 60) % 60, - abs(delay / 1000) % 60, - abs(delay % 1000)); - f.WriteString(str); - } - - // Subs - - for (size_t i = 0; i < m_langs.size(); i++) { - SubLang& sl = m_langs[i]; - - CAtlArray& sp = sl.subpos; - if (sp.IsEmpty() && !sl.id) { - continue; - } - - str.Format(_T("# %s\n"), sl.name.GetString()); - f.WriteString(str); - - ASSERT(sl.id); - if (!sl.id) { - sl.id = '--'; - } - str.Format(_T("id: %c%c, index: %Iu\n"), sl.id >> 8, sl.id & 0xff, i); - f.WriteString(str); - - str = _T("# Uncomment next line to activate alternative name in VSFilter / Windows Media Player 6.x\n"); - f.WriteString(str); - str.Format(_T("alt: %s\n"), sl.alt.GetString()); - if (sl.name == sl.alt) { - str = _T("# ") + str; - } - f.WriteString(str); - - char vobid = -1, cellid = -1; - - for (size_t j = 0; j < sp.GetCount(); j++) { - if (!sp[j].bValid) { - continue; - } - - if (sp[j].vobid != vobid || sp[j].cellid != cellid) { - str.Format(_T("# Vob/Cell ID: %d, %d (PTS: %I64d)\n"), sp[j].vobid, sp[j].cellid, sp[j].celltimestamp); - f.WriteString(str); - vobid = sp[j].vobid; - cellid = sp[j].cellid; - } - - str.Format(_T("timestamp: %s%02d:%02d:%02d:%03d, filepos: %09I64x\n"), - sp[j].start < 0 ? _T("-") : _T(""), - abs(int((sp[j].start / 1000 / 60 / 60) % 60)), - abs(int((sp[j].start / 1000 / 60) % 60)), - abs(int((sp[j].start / 1000) % 60)), - abs(int((sp[j].start) % 1000)), - sp[j].filepos); - f.WriteString(str); - } - - f.WriteString(_T("\n")); - } - - return true; -} - -bool CVobSubFile::WriteSub(CString fn) -{ - CFile f; - if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { - return false; - } - - if (m_sub.GetLength() == 0) { - return true; // nothing to do... - } - - m_sub.SeekToBegin(); - - int len; - BYTE buff[2048]; - while ((len = m_sub.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { - f.Write(buff, len); - } - - return true; -} - -// - -BYTE* CVobSubFile::GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang /*= SIZE_T_ERROR*/) -{ - BYTE* ret = nullptr; - - if (nLang >= m_langs.size()) { - nLang = m_nLang; - } - CAtlArray& sp = m_langs[nLang].subpos; - - do { - if (idx >= sp.GetCount()) { - break; - } - - if ((__int64)m_sub.Seek(sp[idx].filepos, CFile::begin) != sp[idx].filepos) { - break; - } - - BYTE buff[0x800]; - if (sizeof(buff) != m_sub.Read(buff, sizeof(buff))) { - break; - } - - ASSERT(nLang < BYTE_MAX); - - // let's check a few things to make sure... - if (*(DWORD*)&buff[0x00] != 0xba010000 - || *(DWORD*)&buff[0x0e] != 0xbd010000 - || !(buff[0x15] & 0x80) - || (buff[0x17] & 0xf0) != 0x20 - || (buff[buff[0x16] + 0x17] & 0xe0) != 0x20 - || (buff[buff[0x16] + 0x17] & 0x1f) != (BYTE)nLang) { - break; - } - - packetSize = (buff[buff[0x16] + 0x18] << 8) + buff[buff[0x16] + 0x19]; - dataSize = (buff[buff[0x16] + 0x1a] << 8) + buff[buff[0x16] + 0x1b]; - - try { - ret = DEBUG_NEW BYTE[packetSize]; - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - break; - } - - size_t i = 0, sizeLeft = packetSize; - for (size_t size; i < packetSize; i += size, sizeLeft -= size) { - size_t hsize = 0x18 + buff[0x16]; - size = std::min(sizeLeft, 0x800 - hsize); - memcpy(&ret[i], &buff[hsize], size); - - if (size != sizeLeft) { - while (m_sub.Read(buff, sizeof(buff))) { - if (/*!(buff[0x15] & 0x80) &&*/ buff[buff[0x16] + 0x17] == (nLang | 0x20)) { - break; - } - } - } - } - - if (i != packetSize || sizeLeft > 0) { - delete [] ret; - ret = nullptr; - } - } while (false); - - return ret; -} - -const CVobSubFile::SubPos* CVobSubFile::GetFrameInfo(size_t idx, size_t nLang /*= SIZE_T_ERROR*/) const -{ - if (nLang >= m_langs.size()) { - nLang = m_nLang; - } - const CAtlArray& sp = m_langs[nLang].subpos; - - if (idx >= sp.GetCount() - || !sp[idx].bValid - || (m_bOnlyShowForcedSubs && !sp[idx].bForced)) { - return nullptr; - } - - return &sp[idx]; -} - -bool CVobSubFile::GetFrame(size_t idx, size_t nLang /*= SIZE_T_ERROR*/, REFERENCE_TIME rt /*= -1*/) -{ - if (nLang >= m_langs.size()) { - nLang = m_nLang; - } - CAtlArray& sp = m_langs[nLang].subpos; - - if (idx >= sp.GetCount()) { - return false; - } - - if (m_img.nLang != nLang || m_img.nIdx != idx - || (sp[idx].bAnimated && sp[idx].start + m_img.tCurrent <= rt)) { - size_t packetSize = 0, dataSize = 0; - CAutoVectorPtr buff; - buff.Attach(GetPacket(idx, packetSize, dataSize, nLang)); - if (!buff || packetSize == 0 || dataSize == 0) { - return false; - } - - m_img.start = sp[idx].start; - - bool ret = m_img.Decode(buff, packetSize, dataSize, rt >= 0 ? int(rt - sp[idx].start) : INT_MAX, - m_bCustomPal, m_tridx, m_orgpal, m_cuspal, true); - - m_img.delay = sp[idx].stop - sp[idx].start; - - if (!ret) { - return false; - } - - m_img.nIdx = idx; - m_img.nLang = nLang; - } - - return (m_bOnlyShowForcedSubs ? m_img.bForced : true); -} - -bool CVobSubFile::GetFrameByTimeStamp(__int64 time) -{ - return GetFrame(GetFrameIdxByTimeStamp(time)); -} - -size_t CVobSubFile::GetFrameIdxByTimeStamp(__int64 time) -{ - if (m_nLang >= m_langs.size() || m_langs[m_nLang].subpos.IsEmpty()) { - return SIZE_T_ERROR; - } - - CAtlArray& sp = m_langs[m_nLang].subpos; - - size_t i = 0, j = sp.GetCount() - 1, ret = SIZE_T_ERROR; - - if (time >= sp[j].start) { - return j; - } - - while (i < j) { - size_t mid = (i + j) >> 1; - __int64 midstart = sp[mid].start; - - if (time == midstart) { - ret = mid; - break; - } else if (time < midstart) { - ret = SIZE_T_ERROR; - if (j == mid) { - mid--; - } - j = mid; - } else if (time > midstart) { - ret = mid; - if (i == mid) { - mid++; - } - i = mid; - } - } - - return ret; -} - -// - -STDMETHODIMP CVobSubFile::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = nullptr; - - return - QI(IPersist) - QI(ISubStream) - QI(ISubPicProvider) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPicProvider - -STDMETHODIMP_(POSITION) CVobSubFile::GetStartPosition(REFERENCE_TIME rt, double fps) -{ - rt /= 10000; - - size_t i = GetFrameIdxByTimeStamp(rt); - - const SubPos* sp = GetFrameInfo(i); - if (!sp) { - return nullptr; - } - - if (rt >= sp->stop) { - if (!GetFrameInfo(++i)) { - return nullptr; - } - } - - return (POSITION)(i + 1); -} - -CString CVobSubFile::GetPath() { - return m_path; -} - -STDMETHODIMP_(POSITION) CVobSubFile::GetNext(POSITION pos) -{ - size_t i = (size_t)pos; - return (GetFrameInfo(i) ? (POSITION)(i + 1) : nullptr); -} - -STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStart(POSITION pos, double fps) -{ - size_t i = (size_t)pos - 1; - const SubPos* sp = GetFrameInfo(i); - return (sp ? 10000i64 * sp->start : 0); -} - -STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStop(POSITION pos, double fps) -{ - size_t i = (size_t)pos - 1; - const SubPos* sp = GetFrameInfo(i); - return (sp ? 10000i64 * sp->stop : 0); -} - -STDMETHODIMP_(bool) CVobSubFile::IsAnimated(POSITION pos) -{ - size_t i = (size_t)pos - 1; - const SubPos* sp = GetFrameInfo(i); - return (sp ? sp->bAnimated : false); -} - -STDMETHODIMP CVobSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - if (spd.bpp != 32) { - return E_INVALIDARG; - } - - rt /= 10000; - - if (!GetFrame(GetFrameIdxByTimeStamp(rt), SIZE_T_ERROR, rt)) { - return E_FAIL; - } - - if (rt >= (m_img.start + m_img.delay)) { - return E_FAIL; - } - - return __super::Render(spd, bbox); -} - -STDMETHODIMP CVobSubFile::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) -{ - relativeTo = VIDEO; - return S_OK; -} - -// IPersist - -STDMETHODIMP CVobSubFile::GetClassID(CLSID* pClassID) -{ - return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; -} - -// ISubStream - -STDMETHODIMP_(int) CVobSubFile::GetStreamCount() -{ - int iStreamCount = 0; - for (const auto& sl : m_langs) { - if (sl.subpos.GetCount()) { - iStreamCount++; - } - } - return iStreamCount; -} - -DWORD LangIDToLCID(WORD langid) -{ - unsigned short id = lang_tbl[find_lang(langid)].id; - CHAR tmp[3]; - tmp[0] = id / 256; - tmp[1] = id & 0xFF; - tmp[2] = 0; - return ISOLang::ISO6391ToLcid(tmp); -} - -STDMETHODIMP CVobSubFile::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID) -{ - for (const auto& sl : m_langs) { - if (sl.subpos.IsEmpty() || iStream-- > 0) { - continue; - } - - if (ppName) { - *ppName = (WCHAR*)CoTaskMemAlloc((sl.alt.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppName, sl.alt.GetLength() + 1, CStringW(sl.alt)); - } - - if (pLCID) { - *pLCID = LangIDToLCID(sl.id); - } - - return S_OK; - } - - return E_FAIL; -} - -STDMETHODIMP_(int) CVobSubFile::GetStream() -{ - int iStream = 0; - - if (m_nLang < m_langs.size()) { - for (size_t i = 0; i < m_nLang; i++) { - if (!m_langs[i].subpos.IsEmpty()) { - iStream++; - } - } - } - - return iStream; -} - -STDMETHODIMP CVobSubFile::SetStream(int iStream) -{ - for (size_t i = 0; i < m_langs.size(); i++) { - const CAtlArray& sp = m_langs[i].subpos; - - if (sp.IsEmpty() || iStream-- > 0) { - continue; - } - - m_nLang = i; - - m_img.Invalidate(); - - break; - } - - return iStream < 0 ? S_OK : E_FAIL; -} - -STDMETHODIMP CVobSubFile::Reload() -{ - if (!PathUtils::Exists(m_title + _T(".idx"))) { - return E_FAIL; - } - return !m_title.IsEmpty() && Open(m_title) ? S_OK : E_FAIL; -} - -// StretchBlt - -static void PixelAtBiLinear(RGBQUAD& c, int x, int y, CVobSubImage& src) -{ - int w = src.rect.Width(), - h = src.rect.Height(); - - int x1 = (x >> 16), y1 = (y >> 16) * w, - x2 = std::min(x1 + 1, w - 1), y2 = std::min(y1 + w, (h - 1) * w); - - RGBQUAD* ptr = src.lpPixels; - - RGBQUAD c11 = ptr[y1 + x1], c12 = ptr[y1 + x2], - c21 = ptr[y2 + x1], c22 = ptr[y2 + x2]; - - __int64 u2 = x & 0xffff, - v2 = y & 0xffff, - u1 = 0x10000 - u2, - v1 = 0x10000 - v2; - - int v1u1 = int(v1 * u1 >> 16) * c11.rgbReserved, - v1u2 = int(v1 * u2 >> 16) * c12.rgbReserved, - v2u1 = int(v2 * u1 >> 16) * c21.rgbReserved, - v2u2 = int(v2 * u2 >> 16) * c22.rgbReserved; - - c.rgbRed = (c11.rgbRed * v1u1 + c12.rgbRed * v1u2 - + c21.rgbRed * v2u1 + c22.rgbRed * v2u2) >> 24; - c.rgbGreen = (c11.rgbGreen * v1u1 + c12.rgbGreen * v1u2 - + c21.rgbGreen * v2u1 + c22.rgbGreen * v2u2) >> 24; - c.rgbBlue = (c11.rgbBlue * v1u1 + c12.rgbBlue * v1u2 - + c21.rgbBlue * v2u1 + c22.rgbBlue * v2u2) >> 24; - c.rgbReserved = BYTE((v1u1 + v1u2 - + v2u1 + v2u2) >> 16); -} - -static void StretchBlt(SubPicDesc& spd, CRect dstrect, CVobSubImage& src) -{ - if (dstrect.IsRectEmpty()) { - return; - } - - if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { - return; - } - - int sw = src.rect.Width(), - sh = src.rect.Height(), - dw = dstrect.Width(), - dh = dstrect.Height(); - - int srcx = 0, - srcy = 0, - srcdx = (sw << 16) / dw >> 1, - srcdy = (sh << 16) / dh >> 1; - - if (dstrect.left < 0) { - srcx = -dstrect.left * (srcdx << 1); - dstrect.left = 0; - } - if (dstrect.top < 0) { - srcy = -dstrect.top * (srcdy << 1); - dstrect.top = 0; - } - if (dstrect.right > spd.w) { - dstrect.right = spd.w; - } - if (dstrect.bottom > spd.h) { - dstrect.bottom = spd.h; - } - - if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { - return; - } - - dw = dstrect.Width(); - dh = dstrect.Height(); - - for (int y = dstrect.top; y < dstrect.bottom; y++, srcy += (srcdy << 1)) { - RGBQUAD* ptr = (RGBQUAD*) & ((BYTE*)spd.bits)[y * spd.pitch] + dstrect.left; - RGBQUAD* endptr = ptr + dw; - - for (int sx = srcx; ptr < endptr; sx += (srcdx << 1), ptr++) { - // PixelAtBiLinear(*ptr, sx, srcy, src); - //// - RGBQUAD cc[4]; - - PixelAtBiLinear(cc[0], sx, srcy, src); - PixelAtBiLinear(cc[1], sx + srcdx, srcy, src); - PixelAtBiLinear(cc[2], sx, srcy + srcdy, src); - PixelAtBiLinear(cc[3], sx + srcdx, srcy + srcdy, src); - - ptr->rgbRed = (cc[0].rgbRed + cc[1].rgbRed + cc[2].rgbRed + cc[3].rgbRed) >> 2; - ptr->rgbGreen = (cc[0].rgbGreen + cc[1].rgbGreen + cc[2].rgbGreen + cc[3].rgbGreen) >> 2; - ptr->rgbBlue = (cc[0].rgbBlue + cc[1].rgbBlue + cc[2].rgbBlue + cc[3].rgbBlue) >> 2; - ptr->rgbReserved = (cc[0].rgbReserved + cc[1].rgbReserved + cc[2].rgbReserved + cc[3].rgbReserved) >> 2; - //// - ptr->rgbRed = ptr->rgbRed * ptr->rgbReserved >> 8; - ptr->rgbGreen = ptr->rgbGreen * ptr->rgbReserved >> 8; - ptr->rgbBlue = ptr->rgbBlue * ptr->rgbReserved >> 8; - ptr->rgbReserved = ~ptr->rgbReserved; - - } - } -} - -// -// CVobSubSettings -// - -void CVobSubSettings::InitSettings() -{ - m_size.SetSize(720, 480); - m_toff = m_x = m_y = 0; - m_org.SetPoint(0, 0); - m_scale_x = m_scale_y = m_alpha = 100; - m_fadein = m_fadeout = 50; - m_iSmooth = 0; - m_bAlign = false; - m_alignhor = m_alignver = 0; - m_bOnlyShowForcedSubs = false; - m_bCustomPal = false; - m_tridx = 0; - ZeroMemory(m_orgpal, sizeof(m_orgpal)); - ZeroMemory(m_cuspal, sizeof(m_cuspal)); -} - -bool CVobSubSettings::GetCustomPal(RGBQUAD* cuspal, int& tridx) -{ - memcpy(cuspal, m_cuspal, sizeof(RGBQUAD) * 4); - tridx = m_tridx; - return m_bCustomPal; -} - -void CVobSubSettings::SetCustomPal(const RGBQUAD* cuspal, int tridx) -{ - memcpy(m_cuspal, cuspal, sizeof(RGBQUAD) * 4); - m_tridx = tridx & 0xf; - for (int i = 0; i < 4; i++) { - m_cuspal[i].rgbReserved = (tridx & (1 << i)) ? 0 : 0xff; - } - m_img.Invalidate(); -} - -void CVobSubSettings::GetDestrect(CRect& r) -{ - int w = MulDiv(m_img.rect.Width(), m_scale_x, 100); - int h = MulDiv(m_img.rect.Height(), m_scale_y, 100); - - if (!m_bAlign) { - r.left = MulDiv(m_img.rect.left, m_scale_x, 100); - r.right = MulDiv(m_img.rect.right, m_scale_x, 100); - r.top = MulDiv(m_img.rect.top, m_scale_y, 100); - r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); - } else { - switch (m_alignhor) { - case 0: - r.left = 0; - r.right = w; - break; // left - case 1: - r.left = -(w >> 1); - r.right = -(w >> 1) + w; - break; // center - case 2: - r.left = -w; - r.right = 0; - break; // right - default: - r.left = MulDiv(m_img.rect.left, m_scale_x, 100); - r.right = MulDiv(m_img.rect.right, m_scale_x, 100); - break; - } - - switch (m_alignver) { - case 0: - r.top = 0; - r.bottom = h; - break; // top - case 1: - r.top = -(h >> 1); - r.bottom = -(h >> 1) + h; - break; // center - case 2: - r.top = -h; - r.bottom = 0; - break; // bottom - default: - r.top = MulDiv(m_img.rect.top, m_scale_y, 100); - r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); - break; - } - } - - r += m_org; -} - -void CVobSubSettings::GetDestrect(CRect& r, int w, int h) -{ - GetDestrect(r); - - r.left = MulDiv(r.left, w, m_size.cx); - r.right = MulDiv(r.right, w, m_size.cx); - r.top = MulDiv(r.top, h, m_size.cy); - r.bottom = MulDiv(r.bottom, h, m_size.cy); -} - -void CVobSubSettings::SetAlignment(bool bAlign, int x, int y, int hor /*= 1*/, int ver /*= 1*/) -{ - m_bAlign = bAlign; - if (bAlign) { - m_org.x = MulDiv(m_size.cx, x, 100); - m_org.y = MulDiv(m_size.cy, y, 100); - m_alignhor = std::min(std::max(hor, 0), 2); - m_alignver = std::min(std::max(ver, 0), 2); - } else { - m_org.x = m_x; - m_org.y = m_y; - } -} - -HRESULT CVobSubSettings::Render(SubPicDesc& spd, RECT& bbox) -{ - CRect r; - GetDestrect(r, spd.w, spd.h); - StretchBlt(spd, r, m_img); - /* - CRenderedTextSubtitle rts(nullptr); - rts.CreateDefaultStyle(DEFAULT_CHARSET); - rts.m_storageRes.SetSize(m_size.cx, m_size.cy); - CStringW assstr; - m_img.Polygonize(assstr, false); - REFERENCE_TIME rtStart = 10000i64*m_img.start, rtStop = 10000i64*(m_img.start+m_img.delay); - rts.Add(assstr, true, rtStart, rtStop); - rts.Render(spd, (rtStart+rtStop)/2, 25, r); - */ - r &= CRect(CPoint(0, 0), CSize(spd.w, spd.h)); - bbox = r; - return !r.IsRectEmpty() ? S_OK : S_FALSE; -} - -///////////////////////////////////////////////////////// - -static bool CompressFile(CString fn) -{ - BOOL b = FALSE; - - HANDLE h = CreateFile(fn, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); - if (h != INVALID_HANDLE_VALUE) { - unsigned short us = COMPRESSION_FORMAT_DEFAULT; - DWORD nBytesReturned; - b = DeviceIoControl(h, FSCTL_SET_COMPRESSION, (LPVOID)&us, 2, nullptr, 0, (LPDWORD)&nBytesReturned, nullptr); - CloseHandle(h); - } - - return !!b; -} - -bool CVobSubFile::SaveVobSub(CString fn, int delay) -{ - if (!WriteIdx(fn + _T(".idx"), delay) || !WriteSub(fn + _T(".sub"))) { - return false; - } - m_path = fn + _T(".idx"); - return true; -} - -bool CVobSubFile::SaveWinSubMux(CString fn, int delay) -{ - TrimExtension(fn); - - CStdioFile f; - if (!f.Open(fn + _T(".sub"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { - return false; - } - - m_img.Invalidate(); - - CAutoVectorPtr p4bpp; - if (!p4bpp.Allocate(720 * 576 / 2)) { - return false; - } - - CAtlArray& sp = m_langs[m_nLang].subpos; - for (size_t i = 0; i < sp.GetCount(); i++) { - if (!GetFrame(i)) { - continue; - } - - int pal[4] = {0, 1, 2, 3}; - - for (int j = 0; j < 5; j++) { - if (j == 4 || !m_img.pal[j].tr) { - j &= 3; - memset(p4bpp, (j << 4) | j, 720 * 576 / 2); - pal[j] ^= pal[0], pal[0] ^= pal[j], pal[j] ^= pal[0]; - break; - } - } - - int tr[4] = {m_img.pal[pal[0]].tr, m_img.pal[pal[1]].tr, m_img.pal[pal[2]].tr, m_img.pal[pal[3]].tr}; - - DWORD uipal[4 + 12]; - - if (!m_bCustomPal) { - uipal[0] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[0]].pal]); - uipal[1] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[1]].pal]); - uipal[2] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[2]].pal]); - uipal[3] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[3]].pal]); - } else { - uipal[0] = *((DWORD*)&m_img.cuspal[pal[0]]) & 0xffffff; - uipal[1] = *((DWORD*)&m_img.cuspal[pal[1]]) & 0xffffff; - uipal[2] = *((DWORD*)&m_img.cuspal[pal[2]]) & 0xffffff; - uipal[3] = *((DWORD*)&m_img.cuspal[pal[3]]) & 0xffffff; - } - - CAtlMap palmap; - palmap[uipal[0]] = 0; - palmap[uipal[1]] = 1; - palmap[uipal[2]] = 2; - palmap[uipal[3]] = 3; - - uipal[0] = 0xff; // blue background - - int w = m_img.rect.Width() - 2; - int h = m_img.rect.Height() - 2; - int pitch = (((w + 1) >> 1) + 3) & ~3; - - for (ptrdiff_t y = 0; y < h; y++) { - DWORD* p = (DWORD*)&m_img.lpPixels[(y + 1) * (w + 2) + 1]; - - for (ptrdiff_t x = 0; x < w; x++, p++) { - BYTE c = 0; - - if (*p & 0xff000000) { - DWORD uic = *p & 0xffffff; - palmap.Lookup(uic, c); - } - - BYTE& c4bpp = p4bpp[(h - y - 1) * pitch + (x >> 1)]; - c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); - } - } - - int t1 = (int)m_img.start + delay; - int t2 = t1 + (int)m_img.delay /*+ (m_size.cy==480?(1000/29.97+1):(1000/25))*/; - - ASSERT(t2 > t1); - - if (t2 <= 0) { - continue; - } - if (t1 < 0) { - t1 = 0; - } - - CString bmpfn; - bmpfn.Format(_T("%s_%06Iu.bmp"), fn.GetString(), i + 1); - - CString str; - str.Format(_T("%s\t%02d:%02d:%02d:%02d %02d:%02d:%02d:%02d\t%03d %03d %03d %03d %d %d %d %d\n"), - bmpfn.GetString(), - t1 / 1000 / 60 / 60, (t1 / 1000 / 60) % 60, (t1 / 1000) % 60, (t1 % 1000) / 10, - t2 / 1000 / 60 / 60, (t2 / 1000 / 60) % 60, (t2 / 1000) % 60, (t2 % 1000) / 10, - m_img.rect.Width(), m_img.rect.Height(), m_img.rect.left, m_img.rect.top, - (tr[0] << 4) | tr[0], (tr[1] << 4) | tr[1], (tr[2] << 4) | tr[2], (tr[3] << 4) | tr[3]); - f.WriteString(str); - - BITMAPFILEHEADER fhdr = { - 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + pitch * h, - 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) - }; - - BITMAPINFOHEADER ihdr = { - sizeof(BITMAPINFOHEADER), - w, h, 1, 4, 0, - 0, - pitch * h, 0, - 16, 4 - }; - - CFile bmp; - if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { - bmp.Write(&fhdr, sizeof(fhdr)); - bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(uipal, sizeof(RGBQUAD) * 16); - bmp.Write(p4bpp, pitch * h); - bmp.Close(); - - CompressFile(bmpfn); - } - } - - m_path = fn + _T(".sub"); - - return true; -} - -bool CVobSubFile::SaveScenarist(CString fn, int delay) -{ - TrimExtension(fn); - - CStdioFile f; - if (!f.Open(fn + _T(".sst"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { - return false; - } - - m_img.Invalidate(); - - fn.Replace('\\', '/'); - CString title = fn.Mid(fn.ReverseFind('/') + 1); - - TCHAR buff[MAX_PATH], * pFilePart = buff; - if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { - return false; - } - - CString fullpath = CString(buff).Left(int(pFilePart - buff)); - fullpath.TrimRight(_T("\\/")); - if (fullpath.IsEmpty()) { - return false; - } - - CString str, str2; - str += _T("st_format\t2\n"); - str += _T("Display_Start\t%s\n"); - str += _T("TV_Type\t\t%s\n"); - str += _T("Tape_Type\tNON_DROP\n"); - str += _T("Pixel_Area\t(0 %d)\n"); - str += _T("Directory\t%s\n"); - str += _T("Subtitle\t%s\n"); - str += _T("Display_Area\t(0 2 719 %d)\n"); - str += _T("Contrast\t(15 15 15 0)\n"); - str += _T("\n"); - str += _T("PA\t(0 0 255 - - - )\n"); - str += _T("E1\t(255 0 0 - - - )\n"); - str += _T("E2\t(0 0 0 - - - )\n"); - str += _T("BG\t(255 255 255 - - - )\n"); - str += _T("\n"); - str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); - str2.Format(str, - !m_bOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), - m_size.cy == 480 ? _T("NTSC") : _T("PAL"), - m_size.cy - 3, - fullpath.GetString(), - title.GetString(), - m_size.cy == 480 ? 479 : 574); - - f.WriteString(str2); - - f.Flush(); - - RGBQUAD pal[16] = { - {255, 0, 0, 0}, - {0, 0, 255, 0}, - {0, 0, 0, 0}, - {255, 255, 255, 0}, - {0, 255, 0, 0}, - {255, 0, 255, 0}, - {0, 255, 255, 0}, - {125, 125, 0, 0}, - {125, 125, 125, 0}, - {225, 225, 225, 0}, - {0, 0, 125, 0}, - {0, 125, 0, 0}, - {125, 0, 0, 0}, - {255, 0, 222, 0}, - {0, 125, 222, 0}, - {125, 0, 125, 0}, - }; - - BITMAPFILEHEADER fhdr = { - 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), - 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) - }; - - BITMAPINFOHEADER ihdr = { - sizeof(BITMAPINFOHEADER), - 720, m_size.cy - 2, 1, 4, 0, - DWORD(360 * (m_size.cy - 2)), - 0, 0, - 16, 4 - }; - - bool bCustomPal = m_bCustomPal; - m_bCustomPal = true; - RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; - memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); - memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); - - CAutoVectorPtr p4bpp; - if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { - return false; - } - - BYTE colormap[16]; - - for (size_t i = 0; i < 16; i++) { - BYTE idx = 0; - int maxdif = 255 * 255 * 3 + 1; - - for (size_t j = 0; j < 16 && maxdif; j++) { - int rdif = pal[j].rgbRed - m_orgpal[i].rgbRed; - int gdif = pal[j].rgbGreen - m_orgpal[i].rgbGreen; - int bdif = pal[j].rgbBlue - m_orgpal[i].rgbBlue; - - int dif = rdif * rdif + gdif * gdif + bdif * bdif; - if (dif < maxdif) { - maxdif = dif; - idx = (BYTE)j; - } - } - - colormap[i] = idx + 1; - } - - int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; - - CAtlArray& sp = m_langs[m_nLang].subpos; - for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { - if (!GetFrame(i)) { - continue; - } - - for (int j = 0; j < 5; j++) { - if (j == 4 || !m_img.pal[j].tr) { - j &= 3; - memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); - break; - } - } - - for (ptrdiff_t y = std::max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { - ASSERT(m_size.cy - y - 1 >= 0); - if (m_size.cy - y - 1 < 0) { - break; - } - - DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; - - for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { - DWORD rgb = *p & 0xffffff; - BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; - BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; - c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); - } - } - - CString bmpfn; - bmpfn.Format(_T("%s_%04Iu.bmp"), fn.GetString(), i + 1); - title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); - - // E1, E2, P, Bg - int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]}; - c[0] ^= c[1], c[1] ^= c[0], c[0] ^= c[1]; - - if (memcmp(pc, c, sizeof(c))) { - memcpy(pc, c, sizeof(c)); - str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); - f.WriteString(str); - } - - // E1, E2, P, Bg - int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; - a[0] ^= a[1], a[1] ^= a[0], a[0] ^= a[1]; - - if (memcmp(pa, a, sizeof(a))) { - memcpy(pa, a, sizeof(a)); - str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); - f.WriteString(str); - } - - int t1 = (int)sp[i].start + delay; - int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; - int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); - - int t2 = (int)sp[i].stop + delay; - int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; - int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); - - if (t2 <= 0) { - continue; - } - if (t1 < 0) { - t1 = 0; - } - - if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { - f2++; - if (f2 == (m_size.cy == 480 ? 30 : 25)) { - f2 = 0; - s2++; - if (s2 == 60) { - s2 = 0; - m2++; - if (m2 == 60) { - m2 = 0; - h2++; - } - } - } - } - - if (i + 1 < sp.GetCount()) { - int t3 = (int)sp[i + 1].start + delay; - int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; - int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); - - if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { - f2--; - if (f2 == -1) { - f2 = (m_size.cy == 480 ? 29 : 24); - s2--; - if (s2 == -1) { - s2 = 59; - m2--; - if (m2 == -1) { - m2 = 59; - if (h2 > 0) { - h2--; - } - } - } - } - } - } - - if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { - continue; - } - - str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), - ++k, - h1, m1, s1, f1, - h2, m2, s2, f2, - title.GetString()); - f.WriteString(str); - - CFile bmp; - if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::modeRead | CFile::typeBinary)) { - bmp.Write(&fhdr, sizeof(fhdr)); - bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); - bmp.Write(p4bpp, 360 * (m_size.cy - 2)); - bmp.Close(); - - CompressFile(bmpfn); - } - } - - m_bCustomPal = bCustomPal; - memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); - - m_path = fn + _T(".sst"); - - return true; -} - -bool CVobSubFile::SaveMaestro(CString fn, int delay) -{ - TrimExtension(fn); - - CStdioFile f; - if (!f.Open(fn + _T(".son"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { - return false; - } - - m_img.Invalidate(); - - fn.Replace('\\', '/'); - CString title = fn.Mid(fn.ReverseFind('/') + 1); - - TCHAR buff[MAX_PATH], * pFilePart = buff; - if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { - return false; - } - - CString fullpath = CString(buff).Left(int(pFilePart - buff)); - fullpath.TrimRight(_T("\\/")); - if (fullpath.IsEmpty()) { - return false; - } - - CString str, str2; - str += _T("st_format\t2\n"); - str += _T("Display_Start\t%s\n"); - str += _T("TV_Type\t\t%s\n"); - str += _T("Tape_Type\tNON_DROP\n"); - str += _T("Pixel_Area\t(0 %d)\n"); - str += _T("Directory\t%s\n"); - str += _T("Subtitle\t%s\n"); - str += _T("Display_Area\t(0 2 719 %d)\n"); - str += _T("Contrast\t(15 15 15 0)\n"); - str += _T("\n"); - str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); - str2.Format(str, - !m_bOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), - m_size.cy == 480 ? _T("NTSC") : _T("PAL"), - m_size.cy - 3, - fullpath.GetString(), - title.GetString(), - m_size.cy == 480 ? 479 : 574); - - f.WriteString(str2); - - f.Flush(); - - BITMAPFILEHEADER fhdr = { - 0x4d42, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), - 0, 0, - sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) - }; - - BITMAPINFOHEADER ihdr = { - sizeof(BITMAPINFOHEADER), - 720, m_size.cy - 2, 1, 4, 0, - DWORD(360 * (m_size.cy - 2)), - 0, 0, - 16, 4 - }; - - bool bCustomPal = m_bCustomPal; - m_bCustomPal = true; - RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; - memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); - memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); - - CAutoVectorPtr p4bpp; - if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { - return false; - } - - BYTE colormap[16]; - for (BYTE i = 0; i < 16; i++) { - colormap[i] = i; - } - - CFile spf; - if (spf.Open(fn + _T(".spf"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { - for (size_t i = 0; i < 16; i++) { - COLORREF c = (m_orgpal[i].rgbBlue << 16) | (m_orgpal[i].rgbGreen << 8) | m_orgpal[i].rgbRed; - spf.Write(&c, sizeof(COLORREF)); - } - - spf.Close(); - } - - int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; - - CAtlArray& sp = m_langs[m_nLang].subpos; - for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { - if (!GetFrame(i)) { - continue; - } - - for (int j = 0; j < 5; j++) { - if (j == 4 || !m_img.pal[j].tr) { - j &= 3; - memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); - break; - } - } - - for (ptrdiff_t y = std::max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { - ASSERT(m_size.cy - y - 1 >= 0); - if (m_size.cy - y - 1 < 0) { - break; - } - - DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; - - for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { - DWORD rgb = *p & 0xffffff; - BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; - BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; - c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); - } - } - - CString bmpfn; - bmpfn.Format(_T("%s_%04Iu.bmp"), fn.GetString(), i + 1); - title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); - - // E1, E2, P, Bg - int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]}; - - if (memcmp(pc, c, sizeof(c))) { - memcpy(pc, c, sizeof(c)); - str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); - f.WriteString(str); - } - - // E1, E2, P, Bg - int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; - - if (memcmp(pa, a, sizeof(a))) { - memcpy(pa, a, sizeof(a)); - str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); - f.WriteString(str); - } - - int t1 = (int)sp[i].start + delay; - int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; - int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); - - int t2 = (int)sp[i].stop + delay; - int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; - int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); - - if (t2 <= 0) { - continue; - } - if (t1 < 0) { - t1 = 0; - } - - if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { - f2++; - if (f2 == (m_size.cy == 480 ? 30 : 25)) { - f2 = 0; - s2++; - if (s2 == 60) { - s2 = 0; - m2++; - if (m2 == 60) { - m2 = 0; - h2++; - } - } - } - } - - if (i < sp.GetCount() - 1) { - int t3 = (int)sp[i + 1].start + delay; - int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; - int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); - - if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { - f2--; - if (f2 == -1) { - f2 = (m_size.cy == 480 ? 29 : 24); - s2--; - if (s2 == -1) { - s2 = 59; - m2--; - if (m2 == -1) { - m2 = 59; - if (h2 > 0) { - h2--; - } - } - } - } - } - } - - if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { - continue; - } - - str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), - ++k, - h1, m1, s1, f1, - h2, m2, s2, f2, - title.GetString()); - f.WriteString(str); - - CFile bmp; - if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { - bmp.Write(&fhdr, sizeof(fhdr)); - bmp.Write(&ihdr, sizeof(ihdr)); - bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); - bmp.Write(p4bpp, 360 * (m_size.cy - 2)); - bmp.Close(); - - CompressFile(bmpfn); - } - } - - m_bCustomPal = bCustomPal; - memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); - - m_path = fn + _T(".son"); - - return true; -} - -// -// CVobSubStream -// - -CVobSubStream::CVobSubStream(CCritSec* pLock) - : CSubPicProviderImpl(pLock) -{ -} - -CVobSubStream::~CVobSubStream() -{ -} - -void CVobSubStream::Open(CString name, BYTE* pData, int len) -{ - CAutoLock cAutoLock(&m_csSubPics); - - m_name = name; - - CAtlList lines; - Explode(CString(CStringA((CHAR*)pData, len)), lines, _T('\n')); - while (lines.GetCount()) { - CAtlList sl; - Explode(lines.RemoveHead(), sl, ':', 2); - if (sl.GetCount() != 2) { - continue; - } - CString key = sl.GetHead(); - CString value = sl.GetTail(); - if (key == _T("size")) { - _stscanf_s(value, _T("%dx %d"), &m_size.cx, &m_size.cy); - } else if (key == _T("org")) { - _stscanf_s(value, _T("%d, %d"), &m_org.x, &m_org.y); - } else if (key == _T("scale")) { - _stscanf_s(value, _T("%d%%, %d%%"), &m_scale_x, &m_scale_y); - } else if (key == _T("alpha")) { - _stscanf_s(value, _T("%d%%"), &m_alpha); - } else if (key == _T("smooth")) - m_iSmooth = - value == _T("0") || value == _T("OFF") ? 0 : - value == _T("1") || value == _T("ON") ? 1 : - value == _T("2") || value == _T("OLD") ? 2 : - 0; - else if (key == _T("align")) { - Explode(value, sl, ' '); - if (sl.GetCount() == 4) { - sl.RemoveAt(sl.FindIndex(1)); - } - if (sl.GetCount() == 3) { - m_bAlign = sl.RemoveHead() == _T("ON"); - CString hor = sl.GetHead(), ver = sl.GetTail(); - m_alignhor = hor == _T("LEFT") ? 0 : hor == _T("CENTER") ? 1 : hor == _T("RIGHT") ? 2 : 1; - m_alignver = ver == _T("TOP") ? 0 : ver == _T("CENTER") ? 1 : /*ver == _T("BOTTOM") ? 2 :*/ 2; - } - } else if (key == _T("fade in/out")) { - _stscanf_s(value, _T("%d, %d"), &m_fadein, &m_fadeout); - } else if (key == _T("time offset")) { - m_toff = _tcstol(value, nullptr, 10); - } else if (key == _T("forced subs")) { - m_bOnlyShowForcedSubs = value == _T("1") || value == _T("ON"); - } else if (key == _T("palette")) { - Explode(value, sl, ',', 16); - for (size_t i = 0; i < 16 && sl.GetCount(); i++) { - *(DWORD*)&m_orgpal[i] = _tcstol(sl.RemoveHead(), nullptr, 16); - } - } else if (key == _T("custom colors")) { - m_bCustomPal = Explode(value, sl, ',', 3) == _T("ON"); - if (sl.GetCount() == 3) { - sl.RemoveHead(); - CAtlList tridx, colors; - - Explode(sl.RemoveHead(), tridx, ':', 2); - int _tridx = 1; - if (tridx.RemoveHead() == _T("tridx")) { - TCHAR tr[4]; - _stscanf_s(tridx.RemoveHead(), _T("%c%c%c%c"), &tr[0], 1, &tr[1], 1, &tr[2], 1, &tr[3], 1); - for (size_t i = 0; i < 4; i++) { - _tridx |= ((tr[i] == '1') ? 1 : 0) << i; - } - } - - Explode(sl.RemoveHead(), colors, ':', 2); - if (colors.RemoveHead() == _T("colors")) { - Explode(colors.RemoveHead(), colors, ',', 4); - - RGBQUAD pal[4]; - for (size_t i = 0; i < 4 && colors.GetCount(); i++) { - *(DWORD*)&pal[i] = _tcstol(colors.RemoveHead(), nullptr, 16); - } - - SetCustomPal(pal, _tridx); - } - } - } - } -} - -void CVobSubStream::Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len) -{ - if (len <= 4 || ((pData[0] << 8) | pData[1]) != len) { - return; - } - - CVobSubImage vsi; - vsi.GetPacketInfo(pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3]); - - CAutoPtr p(DEBUG_NEW SubPic()); - p->tStart = tStart; - p->tStop = vsi.delay > 0 ? (tStart + 10000i64 * vsi.delay) : tStop; - p->bAnimated = vsi.bAnimated; - p->pData.SetCount(len); - memcpy(p->pData.GetData(), pData, p->pData.GetCount()); - - CAutoLock cAutoLock(&m_csSubPics); - while (m_subpics.GetCount() && m_subpics.GetTail()->tStart >= tStart) { - m_subpics.RemoveTail(); - m_img.nIdx = SIZE_T_ERROR; - } - - // We can only render one subpicture at a time, thus if there is overlap - // we have to fix it. tStop = tStart seems to work. - if (m_subpics.GetCount() && m_subpics.GetTail()->tStop > p->tStart) { - TRACE(_T("[CVobSubStream::Add] Vobsub timestamp overlap detected! ") - _T("Subpicture #%d, StopTime %I64d > %I64d (Next StartTime), making them equal!\n"), - m_subpics.GetCount(), m_subpics.GetTail()->tStop, p->tStart); - m_subpics.GetTail()->tStop = p->tStart; - } - - m_subpics.AddTail(p); -} - -void CVobSubStream::RemoveAll() -{ - CAutoLock cAutoLock(&m_csSubPics); - m_subpics.RemoveAll(); - m_img.nIdx = SIZE_T_ERROR; -} - -STDMETHODIMP CVobSubStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = nullptr; - - return - QI(IPersist) - QI(ISubStream) - QI(ISubPicProvider) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubPicProvider - -STDMETHODIMP_(POSITION) CVobSubStream::GetStartPosition(REFERENCE_TIME rt, double fps) -{ - CAutoLock cAutoLock(&m_csSubPics); - POSITION pos = m_subpics.GetTailPosition(); - for (; pos; m_subpics.GetPrev(pos)) { - SubPic* sp = m_subpics.GetAt(pos); - if (sp->tStart <= rt) { - if (sp->tStop <= rt) { - m_subpics.GetNext(pos); - } - break; - } - } - return pos; -} - -STDMETHODIMP_(POSITION) CVobSubStream::GetNext(POSITION pos) -{ - CAutoLock cAutoLock(&m_csSubPics); - m_subpics.GetNext(pos); - return pos; -} - -STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStart(POSITION pos, double fps) -{ - CAutoLock cAutoLock(&m_csSubPics); - return m_subpics.GetAt(pos)->tStart; -} - -STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStop(POSITION pos, double fps) -{ - CAutoLock cAutoLock(&m_csSubPics); - return m_subpics.GetAt(pos)->tStop; -} - -STDMETHODIMP_(bool) CVobSubStream::IsAnimated(POSITION pos) -{ - CAutoLock cAutoLock(&m_csSubPics); - return m_subpics.GetAt(pos)->bAnimated; -} - -STDMETHODIMP CVobSubStream::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) -{ - if (spd.bpp != 32) { - return E_INVALIDARG; - } - - for (POSITION pos = m_subpics.GetTailPosition(); pos; m_subpics.GetPrev(pos)) { - SubPic* sp = m_subpics.GetAt(pos); - if (sp->tStart <= rt && rt < sp->tStop) { - if (m_img.nIdx != (size_t)pos || (sp->bAnimated && sp->tStart + m_img.tCurrent * 10000i64 <= rt)) { - BYTE* pData = sp->pData.GetData(); - m_img.Decode( - pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3], int((rt - sp->tStart) / 10000i64), - m_bCustomPal, m_tridx, m_orgpal, m_cuspal, true); - m_img.nIdx = (size_t)pos; - } - - return __super::Render(spd, bbox); - } - } - - return E_FAIL; -} - -STDMETHODIMP CVobSubStream::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) -{ - relativeTo = VIDEO; - return S_OK; -} - -// IPersist - -STDMETHODIMP CVobSubStream::GetClassID(CLSID* pClassID) -{ - return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; -} - -// ISubStream - -STDMETHODIMP_(int) CVobSubStream::GetStreamCount() -{ - return 1; -} - -STDMETHODIMP CVobSubStream::GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID) -{ - CAutoLock cAutoLock(&m_csSubPics); - - if (ppName) { - *ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppName)) { - return E_OUTOFMEMORY; - } - wcscpy_s(*ppName, m_name.GetLength() + 1, CStringW(m_name)); - } - - if (pLCID) { - *pLCID = 0; // TODO - } - - return S_OK; -} - -STDMETHODIMP_(int) CVobSubStream::GetStream() -{ - return 0; -} - -STDMETHODIMP CVobSubStream::SetStream(int iStream) -{ - return iStream == 0 ? S_OK : E_FAIL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "TextFile.h" +#include "VobSubFile.h" +#include "mpc-hc_config.h" + +#if !USE_STATIC_UNRAR +#include "unrar.h" +#else +#include "unrar/dll.hpp" +#endif +#include "RTS.h" +#include "../DSUtil/PathUtils.h" +#include "../DSUtil/ISOLang.h" + +// + +struct lang_type { + unsigned short id; + LPCSTR lang_long; +} static constexpr lang_tbl[] = { + {'--', "(Not detected)"}, + {'cc', "Closed Caption"}, + {'aa', "Afar"}, + {'ab', "Abkhazian"}, + {'af', "Afrikaans"}, + {'am', "Amharic"}, + {'ar', "Arabic"}, + {'as', "Assamese"}, + {'ay', "Aymara"}, + {'az', "Azerbaijani"}, + {'ba', "Bashkir"}, + {'be', "Byelorussian"}, + {'bg', "Bulgarian"}, + {'bh', "Bihari"}, + {'bi', "Bislama"}, + {'bn', "Bengali; Bangla"}, + {'bo', "Tibetan"}, + {'br', "Breton"}, + {'ca', "Catalan"}, + {'co', "Corsican"}, + {'cs', "Czech"}, + {'cy', "Welsh"}, + {'da', "Dansk"}, + {'de', "Deutsch"}, + {'dz', "Bhutani"}, + {'el', "Greek"}, + {'en', "English"}, + {'eo', "Esperanto"}, + {'es', "Espanol"}, + {'et', "Estonian"}, + {'eu', "Basque"}, + {'fa', "Persian"}, + {'fi', "Finnish"}, + {'fj', "Fiji"}, + {'fo', "Faroese"}, + {'fr', "Francais"}, + {'fy', "Frisian"}, + {'ga', "Irish"}, + {'gd', "Scots Gaelic"}, + {'gl', "Galician"}, + {'gn', "Guarani"}, + {'gu', "Gujarati"}, + {'ha', "Hausa"}, + {'he', "Hebrew"}, + {'hi', "Hindi"}, + {'hr', "Hrvatski"}, + {'hu', "Hungarian"}, + {'hy', "Armenian"}, + {'ia', "Interlingua"}, + {'id', "Indonesian"}, + {'ie', "Interlingue"}, + {'ik', "Inupiak"}, + {'in', "Indonesian"}, + {'is', "Islenska"}, + {'it', "Italiano"}, + {'iu', "Inuktitut"}, + {'iw', "Hebrew"}, + {'ja', "Japanese"}, + {'ji', "Yiddish"}, + {'jw', "Javanese"}, + {'ka', "Georgian"}, + {'kk', "Kazakh"}, + {'kl', "Greenlandic"}, + {'km', "Cambodian"}, + {'kn', "Kannada"}, + {'ko', "Korean"}, + {'ks', "Kashmiri"}, + {'ku', "Kurdish"}, + {'ky', "Kirghiz"}, + {'la', "Latin"}, + {'ln', "Lingala"}, + {'lo', "Laothian"}, + {'lt', "Lithuanian"}, + {'lv', "Latvian, Lettish"}, + {'mg', "Malagasy"}, + {'mi', "Maori"}, + {'mk', "Macedonian"}, + {'ml', "Malayalam"}, + {'mn', "Mongolian"}, + {'mo', "Moldavian"}, + {'mr', "Marathi"}, + {'ms', "Malay"}, + {'mt', "Maltese"}, + {'my', "Burmese"}, + {'na', "Nauru"}, + {'ne', "Nepali"}, + {'nl', "Nederlands"}, + {'no', "Norsk"}, + {'oc', "Occitan"}, + {'om', "(Afan) Oromo"}, + {'or', "Oriya"}, + {'pa', "Punjabi"}, + {'pl', "Polish"}, + {'ps', "Pashto, Pushto"}, + {'pt', "Portugues"}, + {'qu', "Quechua"}, + {'rm', "Rhaeto-Romance"}, + {'rn', "Kirundi"}, + {'ro', "Romanian"}, + {'ru', "Russian"}, + {'rw', "Kinyarwanda"}, + {'sa', "Sanskrit"}, + {'sd', "Sindhi"}, + {'sg', "Sangho"}, + {'sh', "Serbo-Croatian"}, + {'si', "Sinhalese"}, + {'sk', "Slovak"}, + {'sl', "Slovenian"}, + {'sm', "Samoan"}, + {'sn', "Shona"}, + {'so', "Somali"}, + {'sq', "Albanian"}, + {'sr', "Serbian"}, + {'ss', "Siswati"}, + {'st', "Sesotho"}, + {'su', "Sundanese"}, + {'sv', "Svenska"}, + {'sw', "Swahili"}, + {'ta', "Tamil"}, + {'te', "Telugu"}, + {'tg', "Tajik"}, + {'th', "Thai"}, + {'ti', "Tigrinya"}, + {'tk', "Turkmen"}, + {'tl', "Tagalog"}, + {'tn', "Setswana"}, + {'to', "Tonga"}, + {'tr', "Turkish"}, + {'ts', "Tsonga"}, + {'tt', "Tatar"}, + {'tw', "Twi"}, + {'ug', "Uighur"}, + {'uk', "Ukrainian"}, + {'ur', "Urdu"}, + {'uz', "Uzbek"}, + {'vi', "Vietnamese"}, + {'vo', "Volapuk"}, + {'wo', "Wolof"}, + {'xh', "Xhosa"}, + {'yi', "Yiddish"}, // formerly ji + {'yo', "Yoruba"}, + {'za', "Zhuang"}, + {'zh', "Chinese"}, + {'zu', "Zulu"}, +}; + +int find_lang(unsigned short id) +{ + int lo = 0, hi = _countof(lang_tbl) - 1; + + while (lo < hi) { + int mid = (lo + hi) >> 1; + + if (id < lang_tbl[mid].id) { + hi = mid; + } else if (id > lang_tbl[mid].id) { + lo = mid + 1; + } else { + return mid; + } + } + + return (id == lang_tbl[lo].id ? lo : 0); +} + +CString FindLangFromId(WORD id) +{ + return CString(lang_tbl[find_lang(id)].lang_long); +} + +// +// CVobSubFile +// + +CVobSubFile::CVobSubFile(CCritSec* pLock) + : CSubPicProviderImpl(pLock) + , m_sub(1024 * 1024) + , m_nLang(0) +{ +} + +CVobSubFile::~CVobSubFile() +{ +} + +// + +bool CVobSubFile::Copy(CVobSubFile& vsf) +{ + Close(); + + *(CVobSubSettings*)this = *(CVobSubSettings*)&vsf; + m_title = vsf.m_title; + m_nLang = vsf.m_nLang; + + m_sub.SetLength(vsf.m_sub.GetLength()); + m_sub.SeekToBegin(); + + for (size_t i = 0; i < m_langs.size(); i++) { + SubLang& src = vsf.m_langs[i]; + SubLang& dst = m_langs[i]; + + dst.id = src.id; + dst.name = src.name; + dst.alt = src.alt; + + for (size_t j = 0; j < src.subpos.GetCount(); j++) { + SubPos& sp = src.subpos[j]; + if (!sp.bValid) { + continue; + } + + if (sp.filepos != (__int64)vsf.m_sub.Seek(sp.filepos, CFile::begin)) { + continue; + } + + sp.filepos = m_sub.GetPosition(); + + BYTE buff[2048]; + UINT uRead = vsf.m_sub.Read(buff, 2048); + m_sub.Write(buff, uRead); + + WORD packetsize = (buff[buff[0x16] + 0x18] << 8) | buff[buff[0x16] + 0x19]; + + for (int k = 0, size, sizeleft = packetsize - 4; + k < packetsize - 4; + k += size, sizeleft -= size) { + int hsize = buff[0x16] + 0x18 + ((buff[0x15] & 0x80) ? 4 : 0); + size = std::min(sizeleft, 2048 - hsize); + + if (size != sizeleft) { + while ((uRead = vsf.m_sub.Read(buff, 2048)) > 0) { + if (!(buff[0x15] & 0x80) && buff[buff[0x16] + 0x17] == (i | 0x20)) { + break; + } + } + + m_sub.Write(buff, uRead); + } + } + + dst.subpos.Add(sp); + } + } + + m_sub.SetLength(m_sub.GetPosition()); + + return true; +} + +// + +void CVobSubFile::TrimExtension(CString& fn) +{ + int i = fn.ReverseFind('.'); + if (i > 0) { + CString ext = fn.Mid(i).MakeLower(); + if (ext == _T(".ifo") || ext == _T(".idx") || ext == _T(".sub") + || ext == _T(".sst") || ext == _T(".son") || ext == _T(".rar")) { + fn = fn.Left(i); + } + } +} + +bool CVobSubFile::Open(CString fn) +{ + m_path = fn; + TrimExtension(fn); + + do { + Close(); + + int ver; + if (!ReadIdx(fn + _T(".idx"), ver)) { + break; + } + + if (ver < 6 && !ReadIfo(fn + _T(".ifo"))) { + break; + } + + if (!ReadSub(fn + _T(".sub")) && !ReadRar(fn + _T(".rar"))) { + break; + } + + m_title = fn; + + for (size_t i = 0; i < m_langs.size(); i++) { + CAtlArray& sp = m_langs[i].subpos; + + for (size_t j = 0; j < sp.GetCount(); j++) { + sp[j].stop = sp[j].start; + sp[j].bForced = false; + + size_t packetSize = 0, dataSize = 0; + BYTE* buff = GetPacket(j, packetSize, dataSize, i); + if (!buff) { + sp[j].bValid = false; + continue; + } + + m_img.delay = j + 1 < sp.GetCount() ? sp[j + 1].start - sp[j].start : 3000; + m_img.GetPacketInfo(buff, packetSize, dataSize); + if (j + 1 < sp.GetCount()) { + m_img.delay = std::min(m_img.delay, sp[j + 1].start - sp[j].start); + } + + sp[j].stop = sp[j].start + m_img.delay; + sp[j].bForced = m_img.bForced; + sp[j].bAnimated = m_img.bAnimated; + + if (j > 0 && sp[j - 1].stop > sp[j].start) { + sp[j - 1].stop = sp[j].start; + } + + delete [] buff; + } + } + + return true; + } while (false); + + Close(); + + return false; +} + +bool CVobSubFile::Save(CString fn, int delay, SubFormat sf) +{ + TrimExtension(fn); + + CVobSubFile vsf(nullptr); + if (!vsf.Copy(*this)) { + return false; + } + + switch (sf) { + case VobSub: + return vsf.SaveVobSub(fn, delay); + case WinSubMux: + return vsf.SaveWinSubMux(fn, delay); + case Scenarist: + return vsf.SaveScenarist(fn, delay); + case Maestro: + return vsf.SaveMaestro(fn, delay); + default: + break; + } + + return false; +} + +void CVobSubFile::Close() +{ + InitSettings(); + m_title.Empty(); + m_sub.SetLength(0); + m_img.Invalidate(); + m_nLang = SIZE_T_ERROR; + for (auto& sl : m_langs) { + sl.id = 0; + sl.name.Empty(); + sl.alt.Empty(); + sl.subpos.RemoveAll(); + } +} + +// + +bool CVobSubFile::ReadIdx(CString fn, int& ver) +{ + CWebTextFile f; + if (!f.Open(fn)) { + return false; + } + + bool bError = false; + + int id = -1, delay = 0, vobid = -1, cellid = -1; + __int64 celltimestamp = 0; + + CString str; + for (ptrdiff_t line = 0; !bError && f.ReadString(str); line++) { + str.Trim(); + + if (line == 0) { + TCHAR buff[] = _T("VobSub index file, v"); + + const TCHAR* s = str; + + int i = str.Find(buff); + if (i < 0 || _stscanf_s(&s[i + _tcslen(buff)], _T("%d"), &ver) != 1 + || ver > VOBSUBIDXVER) { + TRACE(_T("[CVobSubFile::ReadIdx] Wrong file version!\n")); + bError = true; + continue; + } + } else if (!str.GetLength()) { + continue; + } else if (str[0] == _T('#')) { + TCHAR buff[] = _T("Vob/Cell ID:"); + + const TCHAR* s = str; + + int i = str.Find(buff); + if (i >= 0) { + _stscanf_s(&s[i + _tcslen(buff)], _T("%d, %d (PTS: %I64d)"), &vobid, &cellid, &celltimestamp); + } + + continue; + } + + int i = str.Find(':'); + if (i <= 0) { + continue; + } + + CString entry = str.Left(i).MakeLower(); + + str = str.Mid(i + 1); + str.Trim(); + if (str.IsEmpty()) { + continue; + } + + if (entry == _T("size")) { + int x, y; + if (_stscanf_s(str, _T("%dx%d"), &x, &y) != 2) { + bError = true; + } + m_size.cx = x; + m_size.cy = y; + } else if (entry == _T("org")) { + if (_stscanf_s(str, _T("%d,%d"), &m_x, &m_y) != 2) { + bError = true; + } else { + m_org = CPoint(m_x, m_y); + } + } else if (entry == _T("scale")) { + if (ver < 5) { + int scale = 100; + if (_stscanf_s(str, _T("%d%%"), &scale) != 1) { + bError = true; + } + m_scale_x = m_scale_y = scale; + } else { + if (_stscanf_s(str, _T("%d%%,%d%%"), &m_scale_x, &m_scale_y) != 2) { + bError = true; + } + } + } else if (entry == _T("alpha")) { + if (_stscanf_s(str, _T("%d"), &m_alpha) != 1) { + bError = true; + } + } else if (entry == _T("smooth")) { + str.MakeLower(); + + if (str.Find(_T("old")) >= 0 || str.Find(_T("2")) >= 0) { + m_iSmooth = 2; + } else if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { + m_iSmooth = 1; + } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { + m_iSmooth = 0; + } else { + bError = true; + } + } else if (entry == _T("fadein/out")) { + if (_stscanf_s(str, _T("%d,%d"), &m_fadein, &m_fadeout) != 2) { + bError = true; + } + } else if (entry == _T("align")) { + str.MakeLower(); + + int k = 0; + CString token; + for (int j = 0; j < 3; j++) { + token = str.Tokenize(_T(" "), k); + if (token.IsEmpty()) { + break; + } + + if (j == 0) { + if (token == _T("on") || token == _T("1")) { + m_bAlign = true; + } else if (token == _T("off") || token == _T("0")) { + m_bAlign = false; + } else { + bError = true; + break; + } + } else if (j == 1) { + if (token == _T("at")) { + j--; + continue; + } + + if (token == _T("left")) { + m_alignhor = 0; + } else if (token == _T("center")) { + m_alignhor = 1; + } else if (token == _T("right")) { + m_alignhor = 2; + } else { + bError = true; + break; + } + } else if (j == 2) { + if (token == _T("top")) { + m_alignver = 0; + } else if (token == _T("center")) { + m_alignver = 1; + } else if (token == _T("bottom")) { + m_alignver = 2; + } else { + bError = true; + break; + } + } + } + } else if (entry == _T("time offset")) { + bool bNegative = false; + if (str[0] == '-') { + bNegative = true; + } + str.TrimLeft(_T("+-")); + + TCHAR c; + int hh, mm, ss, ms; + int n = _stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms); + + switch (n) { + case 1: // We have read only one integer, interpret it as an offset expressed in milliseconds + m_toff = hh * (bNegative ? -1 : 1); + break; + case 7: // We have read 4 integers + 3 separators, interpret them as hh:mm:ss.ms + m_toff = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1); + break; + default: + bError = true; + m_toff = 0; + break; + } + } else if (entry == _T("forced subs")) { + str.MakeLower(); + + if (str.Find(_T("on")) >= 0 || str.Find(_T("1")) >= 0) { + m_bOnlyShowForcedSubs = true; + } else if (str.Find(_T("off")) >= 0 || str.Find(_T("0")) >= 0) { + m_bOnlyShowForcedSubs = false; + } else { + bError = true; + } + } else if (entry == _T("langidx")) { + int iLang = -1; + if (_stscanf_s(str, _T("%d"), &iLang) != 1) { + bError = true; + } + m_nLang = (iLang < 0 && size_t(iLang) >= m_langs.size()) ? SIZE_T_ERROR : size_t(iLang); + } else if (entry == _T("palette")) { + // The assert guarantees that the shortcut we use will work as expected + static_assert(sizeof(RGBQUAD) == 4, "Packing error"); +#pragma warning(push) +#pragma warning(disable: 4477) + if (_stscanf_s(str, _T("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"), + &m_orgpal[0], &m_orgpal[1], &m_orgpal[2], &m_orgpal[3], + &m_orgpal[4], &m_orgpal[5], &m_orgpal[6], &m_orgpal[7], + &m_orgpal[8], &m_orgpal[9], &m_orgpal[10], &m_orgpal[11], + &m_orgpal[12], &m_orgpal[13], &m_orgpal[14], &m_orgpal[15] + ) != 16) { +#pragma warning(pop) + bError = true; + } + } else if (entry == _T("custom colors")) { + str.MakeLower(); + + if (str.Find(_T("on")) == 0 || str.Find(_T("1")) == 0) { + m_bCustomPal = true; + } else if (str.Find(_T("off")) == 0 || str.Find(_T("0")) == 0) { + m_bCustomPal = false; + } else { + bError = true; + } + + i = str.Find(_T("tridx:")); + if (i < 0) { + bError = true; + continue; + } + str = str.Mid(i + (int)_tcslen(_T("tridx:"))); + + int tridx; + if (_stscanf_s(str, _T("%x"), &tridx) != 1) { + bError = true; + continue; + } + tridx = ((tridx & 0x1000) >> 12) | ((tridx & 0x100) >> 7) | ((tridx & 0x10) >> 2) | ((tridx & 1) << 3); + + i = str.Find(_T("colors:")); + if (i < 0) { + bError = true; + continue; + } + str = str.Mid(i + (int)_tcslen(_T("colors:"))); + + RGBQUAD pal[4]; +#pragma warning(push) +#pragma warning(disable: 4477) + if (_stscanf_s(str, _T("%x,%x,%x,%x"), &pal[0], &pal[1], &pal[2], &pal[3]) != 4) { +#pragma warning(pop) + bError = true; + continue; + } + + SetCustomPal(pal, tridx); + } else if (entry == _T("id")) { + str.MakeLower(); + + WORD langid = ((str[0] & 0xff) << 8) | (str[1] & 0xff); + + i = str.Find(_T("index:")); + if (i < 0) { + bError = true; + continue; + } + str = str.Mid(i + (int)_tcslen(_T("index:"))); + + if (_stscanf_s(str, _T("%d"), &id) != 1 || id < 0 || size_t(id) >= m_langs.size()) { + bError = true; + continue; + } + if (m_nLang == SIZE_T_ERROR) { + m_nLang = size_t(id); + } + + m_langs[id].id = langid; + m_langs[id].name = lang_tbl[find_lang(langid)].lang_long; + m_langs[id].alt = lang_tbl[find_lang(langid)].lang_long; + + delay = 0; + } else if (id >= 0 && entry == _T("alt")) { + m_langs[id].alt = str; + } else if (id >= 0 && entry == _T("delay")) { + bool bNegative = false; + if (str[0] == '-') { + bNegative = true; + } + str.TrimLeft(_T("+-")); + + TCHAR c; + int hh, mm, ss, ms; + if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { + bError = true; + continue; + } + + delay += (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1); + } else if (id >= 0 && entry == _T("timestamp")) { + SubPos sb; + + sb.vobid = (char)vobid; + sb.cellid = (char)cellid; + sb.celltimestamp = celltimestamp; + sb.bValid = true; + + bool bNegative = false; + if (str[0] == '-') { + bNegative = true; + } + str.TrimLeft(_T("+-")); + + TCHAR c; + int hh, mm, ss, ms; + if (_stscanf_s(str, _T("%d%c%d%c%d%c%d"), &hh, &c, 1, &mm, &c, 1, &ss, &c, 1, &ms) != 4 + 3) { + bError = true; + continue; + } + + sb.start = (hh * 60 * 60 * 1000 + mm * 60 * 1000 + ss * 1000 + ms) * (bNegative ? -1 : 1) + delay; + + i = str.Find(_T("filepos:")); + if (i < 0) { + bError = true; + continue; + } + str = str.Mid(i + (int)_tcslen(_T("filepos:"))); + + if (_stscanf_s(str, _T("%I64x"), &sb.filepos) != 1) { + bError = true; + continue; + } + + if (delay < 0 && !m_langs[id].subpos.IsEmpty()) { + __int64 ts = m_langs[id].subpos[m_langs[id].subpos.GetCount() - 1].start; + + if (sb.start < ts) { + delay += (int)(ts - sb.start); + sb.start = ts; + } + } + + m_langs[id].subpos.Add(sb); + } else { + bError = true; + } + } + + return !bError; +} + +bool CVobSubFile::ReadSub(CString fn) +{ + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + + int len; + BYTE buff[2048]; + try { + m_sub.SetLength(f.GetLength()); + m_sub.SeekToBegin(); + while ((len = f.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { + m_sub.Write(buff, len); + } + } + catch (CFileException*) { + return false; + } + + return true; +} + +static unsigned char* RARbuff = nullptr; +static unsigned int RARpos = 0; + +static int CALLBACK MyCallbackProc(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2) +{ + if (msg == UCM_PROCESSDATA) { + ASSERT(RARbuff); + + memcpy(&RARbuff[RARpos], (char*)P1, (size_t)P2); + RARpos += (unsigned int)P2; + } + + return 1; +} + +bool CVobSubFile::ReadRar(CString fn) +{ +#if !USE_STATIC_UNRAR +#ifdef _WIN64 + HMODULE h = LoadLibrary(_T("unrar64.dll")); +#else + HMODULE h = LoadLibrary(_T("unrar.dll")); +#endif + if (!h) { + return false; + } + + RAROpenArchiveEx OpenArchiveEx = (RAROpenArchiveEx)GetProcAddress(h, "RAROpenArchiveEx"); + RARCloseArchive CloseArchive = (RARCloseArchive)GetProcAddress(h, "RARCloseArchive"); + RARReadHeaderEx ReadHeaderEx = (RARReadHeaderEx)GetProcAddress(h, "RARReadHeaderEx"); + RARProcessFile ProcessFile = (RARProcessFile)GetProcAddress(h, "RARProcessFile"); + RARSetCallback SetCallback = (RARSetCallback)GetProcAddress(h, "RARSetCallback"); + + if (!(OpenArchiveEx && CloseArchive && ReadHeaderEx && ProcessFile && SetCallback)) { + FreeLibrary(h); + return false; + } + +#else + +#define OpenArchiveEx RAROpenArchiveEx +#define CloseArchive RARCloseArchive +#define ReadHeaderEx RARReadHeaderEx +#define ProcessFile RARProcessFile +#define SetCallback RARSetCallback +#endif /* USE_STATIC_UNRAR */ + + RAROpenArchiveDataEx OpenArchiveData; + ZeroMemory(&OpenArchiveData, sizeof(OpenArchiveData)); + + OpenArchiveData.ArcNameW = (LPTSTR)(LPCTSTR)fn; + char fnA[MAX_PATH]; + size_t size; + if (wcstombs_s(&size, fnA, fn, fn.GetLength())) { + fnA[0] = 0; + } + OpenArchiveData.ArcName = fnA; + OpenArchiveData.OpenMode = RAR_OM_EXTRACT; + OpenArchiveData.CmtBuf = 0; + OpenArchiveData.Callback = MyCallbackProc; + HANDLE hArcData = OpenArchiveEx(&OpenArchiveData); + if (!hArcData) { +#if !USE_STATIC_UNRAR + FreeLibrary(h); +#endif + return false; + } + + RARHeaderDataEx HeaderDataEx; + HeaderDataEx.CmtBuf = nullptr; + + while (ReadHeaderEx(hArcData, &HeaderDataEx) == 0) { + CString subfn(HeaderDataEx.FileNameW); + + if (!subfn.Right(4).CompareNoCase(_T(".sub"))) { + CAutoVectorPtr buff; + if (!buff.Allocate(HeaderDataEx.UnpSize)) { + CloseArchive(hArcData); +#if !USE_STATIC_UNRAR + FreeLibrary(h); +#endif + return false; + } + + RARbuff = buff; + RARpos = 0; + + if (ProcessFile(hArcData, RAR_TEST, nullptr, nullptr)) { + CloseArchive(hArcData); +#if !USE_STATIC_UNRAR + FreeLibrary(h); +#endif + + return false; + } + + m_sub.SetLength(HeaderDataEx.UnpSize); + m_sub.SeekToBegin(); + m_sub.Write(buff, HeaderDataEx.UnpSize); + m_sub.SeekToBegin(); + + RARbuff = nullptr; + RARpos = 0; + + break; + } + + ProcessFile(hArcData, RAR_SKIP, nullptr, nullptr); + } + + CloseArchive(hArcData); +#if !USE_STATIC_UNRAR + FreeLibrary(h); +#endif + + return true; +} + +bool CVobSubFile::ReadIfo(CString fn) +{ + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + + /* PGC1 */ + + f.Seek(0xc0 + 0x0c, SEEK_SET); + + DWORD pos; + ReadBEdw(pos); + + f.Seek(pos * 0x800 + 0x0c, CFile::begin); + + DWORD offset; + ReadBEdw(offset); + + /* Subpic palette */ + + f.Seek(pos * 0x800 + offset + 0xa4, CFile::begin); + + for (size_t i = 0; i < 16; i++) { + BYTE y, u, v, tmp; + + f.Read(&tmp, 1); + f.Read(&y, 1); + f.Read(&u, 1); + f.Read(&v, 1); + + y = (y - 16) * 255 / 219; + + m_orgpal[i].rgbRed = std::min(std::max(BYTE(1.0 * y + 1.4022 * (u - 128)), 0u), 255u); + m_orgpal[i].rgbGreen = std::min(std::max(BYTE(1.0 * y - 0.3456 * (u - 128) - 0.7145 * (v - 128)), 0u), 255u); + m_orgpal[i].rgbBlue = std::min(std::max(BYTE(1.0 * y + 1.7710 * (v - 128)), 0u), 255u); + } + + return true; +} + +bool CVobSubFile::WriteIdx(CString fn, int delay) +{ + CTextFile f; + if (!f.Save(fn, CTextFile::DEFAULT_ENCODING)) { + return false; + } + + CString str; + str.Format(_T("# VobSub index file, v%d (do not modify this line!)\n"), VOBSUBIDXVER); + + f.WriteString(str); + f.WriteString(_T("# \n")); + f.WriteString(_T("# To repair desyncronization, you can insert gaps this way:\n")); + f.WriteString(_T("# (it usually happens after vob id changes)\n")); + f.WriteString(_T("# \n")); + f.WriteString(_T("#\t delay: [sign]hh:mm:ss:ms\n")); + f.WriteString(_T("# \n")); + f.WriteString(_T("# Where:\n")); + f.WriteString(_T("#\t [sign]: +, - (optional)\n")); + f.WriteString(_T("#\t hh: hours (0 <= hh)\n")); + f.WriteString(_T("#\t mm/ss: minutes/seconds (0 <= mm/ss <= 59)\n")); + f.WriteString(_T("#\t ms: milliseconds (0 <= ms <= 999)\n")); + f.WriteString(_T("# \n")); + f.WriteString(_T("#\t Note: You can't position a sub before the previous with a negative value.\n")); + f.WriteString(_T("# \n")); + f.WriteString(_T("# You can also modify timestamps or delete a few subs you don't like.\n")); + f.WriteString(_T("# Just make sure they stay in increasing order.\n")); + f.WriteString(_T("\n")); + f.WriteString(_T("\n")); + + // Settings + + f.WriteString(_T("# Settings\n\n")); + + f.WriteString(_T("# Original frame size\n")); + str.Format(_T("size: %ldx%ld\n\n"), m_size.cx, m_size.cy); + f.WriteString(str); + + f.WriteString(_T("# Origin, relative to the upper-left corner, can be overloaded by aligment\n")); + str.Format(_T("org: %d, %d\n\n"), m_x, m_y); + f.WriteString(str); + + f.WriteString(_T("# Image scaling (hor,ver), origin is at the upper-left corner or at the alignment coord (x, y)\n")); + str.Format(_T("scale: %d%%, %d%%\n\n"), m_scale_x, m_scale_y); + f.WriteString(str); + + f.WriteString(_T("# Alpha blending\n")); + str.Format(_T("alpha: %d%%\n\n"), m_alpha); + f.WriteString(str); + + f.WriteString(_T("# Smoothing for very blocky images (use OLD for no filtering)\n")); + str.Format(_T("smooth: %s\n\n"), m_iSmooth == 0 ? _T("OFF") : m_iSmooth == 1 ? _T("ON") : _T("OLD")); + f.WriteString(str); + + f.WriteString(_T("# In millisecs\n")); + str.Format(_T("fadein/out: %d, %d\n\n"), m_fadein, m_fadeout); + f.WriteString(str); + + f.WriteString(_T("# Force subtitle placement relative to (org.x, org.y)\n")); + str.Format(_T("align: %s %s %s\n\n"), + m_bAlign ? _T("ON at") : _T("OFF at"), + m_alignhor == 0 ? _T("LEFT") : m_alignhor == 1 ? _T("CENTER") : m_alignhor == 2 ? _T("RIGHT") : _T(""), + m_alignver == 0 ? _T("TOP") : m_alignver == 1 ? _T("CENTER") : m_alignver == 2 ? _T("BOTTOM") : _T("")); + f.WriteString(str); + + f.WriteString(_T("# For correcting non-progressive desync. (in millisecs or hh:mm:ss:ms)\n")); + f.WriteString(_T("# Note: Not effective in VSFilter, use \"delay: ... \" instead.\n")); + str.Format(_T("time offset: %u\n\n"), m_toff); + f.WriteString(str); + + f.WriteString(_T("# ON: displays only forced subtitles, OFF: shows everything\n")); + str.Format(_T("forced subs: %s\n\n"), m_bOnlyShowForcedSubs ? _T("ON") : _T("OFF")); + f.WriteString(str); + + f.WriteString(_T("# The original palette of the DVD\n")); + str.Format(_T("palette: %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n\n"), + *((unsigned int*)&m_orgpal[0]) & 0xffffff, + *((unsigned int*)&m_orgpal[1]) & 0xffffff, + *((unsigned int*)&m_orgpal[2]) & 0xffffff, + *((unsigned int*)&m_orgpal[3]) & 0xffffff, + *((unsigned int*)&m_orgpal[4]) & 0xffffff, + *((unsigned int*)&m_orgpal[5]) & 0xffffff, + *((unsigned int*)&m_orgpal[6]) & 0xffffff, + *((unsigned int*)&m_orgpal[7]) & 0xffffff, + *((unsigned int*)&m_orgpal[8]) & 0xffffff, + *((unsigned int*)&m_orgpal[9]) & 0xffffff, + *((unsigned int*)&m_orgpal[10]) & 0xffffff, + *((unsigned int*)&m_orgpal[11]) & 0xffffff, + *((unsigned int*)&m_orgpal[12]) & 0xffffff, + *((unsigned int*)&m_orgpal[13]) & 0xffffff, + *((unsigned int*)&m_orgpal[14]) & 0xffffff, + *((unsigned int*)&m_orgpal[15]) & 0xffffff); + f.WriteString(str); + + int tridx = (!!(m_tridx & 1)) * 0x1000 + (!!(m_tridx & 2)) * 0x100 + (!!(m_tridx & 4)) * 0x10 + (!!(m_tridx & 8)); + + f.WriteString(_T("# Custom colors (transp idxs and the four colors)\n")); + str.Format(_T("custom colors: %s, tridx: %04x, colors: %06x, %06x, %06x, %06x\n\n"), + m_bCustomPal ? _T("ON") : _T("OFF"), + tridx, + *((unsigned int*)&m_cuspal[0]) & 0xffffff, + *((unsigned int*)&m_cuspal[1]) & 0xffffff, + *((unsigned int*)&m_cuspal[2]) & 0xffffff, + *((unsigned int*)&m_cuspal[3]) & 0xffffff); + f.WriteString(str); + + f.WriteString(_T("# Language index in use\n")); + str.Format(_T("langidx: %Iu\n\n"), m_nLang); + f.WriteString(str); + + if (delay) { + str.Format(_T("delay: %s%02d:%02d:%02d:%03d\n\n"), + delay < 0 ? _T("-") : _T(""), + abs(delay / 1000 / 60 / 60) % 60, + abs(delay / 1000 / 60) % 60, + abs(delay / 1000) % 60, + abs(delay % 1000)); + f.WriteString(str); + } + + // Subs + + for (size_t i = 0; i < m_langs.size(); i++) { + SubLang& sl = m_langs[i]; + + CAtlArray& sp = sl.subpos; + if (sp.IsEmpty() && !sl.id) { + continue; + } + + str.Format(_T("# %s\n"), sl.name.GetString()); + f.WriteString(str); + + ASSERT(sl.id); + if (!sl.id) { + sl.id = '--'; + } + str.Format(_T("id: %c%c, index: %Iu\n"), sl.id >> 8, sl.id & 0xff, i); + f.WriteString(str); + + str = _T("# Uncomment next line to activate alternative name in VSFilter / Windows Media Player 6.x\n"); + f.WriteString(str); + str.Format(_T("alt: %s\n"), sl.alt.GetString()); + if (sl.name == sl.alt) { + str = _T("# ") + str; + } + f.WriteString(str); + + char vobid = -1, cellid = -1; + + for (size_t j = 0; j < sp.GetCount(); j++) { + if (!sp[j].bValid) { + continue; + } + + if (sp[j].vobid != vobid || sp[j].cellid != cellid) { + str.Format(_T("# Vob/Cell ID: %d, %d (PTS: %I64d)\n"), sp[j].vobid, sp[j].cellid, sp[j].celltimestamp); + f.WriteString(str); + vobid = sp[j].vobid; + cellid = sp[j].cellid; + } + + str.Format(_T("timestamp: %s%02d:%02d:%02d:%03d, filepos: %09I64x\n"), + sp[j].start < 0 ? _T("-") : _T(""), + abs(int((sp[j].start / 1000 / 60 / 60) % 60)), + abs(int((sp[j].start / 1000 / 60) % 60)), + abs(int((sp[j].start / 1000) % 60)), + abs(int((sp[j].start) % 1000)), + sp[j].filepos); + f.WriteString(str); + } + + f.WriteString(_T("\n")); + } + + return true; +} + +bool CVobSubFile::WriteSub(CString fn) +{ + CFile f; + if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { + return false; + } + + if (m_sub.GetLength() == 0) { + return true; // nothing to do... + } + + m_sub.SeekToBegin(); + + int len; + BYTE buff[2048]; + while ((len = m_sub.Read(buff, sizeof(buff))) > 0 && *(DWORD*)buff == 0xba010000) { + f.Write(buff, len); + } + + return true; +} + +// + +BYTE* CVobSubFile::GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang /*= SIZE_T_ERROR*/) +{ + BYTE* ret = nullptr; + + if (nLang >= m_langs.size()) { + nLang = m_nLang; + } + CAtlArray& sp = m_langs[nLang].subpos; + + do { + if (idx >= sp.GetCount()) { + break; + } + + if ((__int64)m_sub.Seek(sp[idx].filepos, CFile::begin) != sp[idx].filepos) { + break; + } + + BYTE buff[0x800]; + if (sizeof(buff) != m_sub.Read(buff, sizeof(buff))) { + break; + } + + ASSERT(nLang < BYTE_MAX); + + // let's check a few things to make sure... + if (*(DWORD*)&buff[0x00] != 0xba010000 + || *(DWORD*)&buff[0x0e] != 0xbd010000 + || !(buff[0x15] & 0x80) + || (buff[0x17] & 0xf0) != 0x20 + || (buff[buff[0x16] + 0x17] & 0xe0) != 0x20 + || (buff[buff[0x16] + 0x17] & 0x1f) != (BYTE)nLang) { + break; + } + + packetSize = (buff[buff[0x16] + 0x18] << 8) + buff[buff[0x16] + 0x19]; + dataSize = (buff[buff[0x16] + 0x1a] << 8) + buff[buff[0x16] + 0x1b]; + + try { + ret = DEBUG_NEW BYTE[packetSize]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + break; + } + + size_t i = 0, sizeLeft = packetSize; + for (size_t size; i < packetSize; i += size, sizeLeft -= size) { + size_t hsize = 0x18 + buff[0x16]; + size = std::min(sizeLeft, 0x800 - hsize); + memcpy(&ret[i], &buff[hsize], size); + + if (size != sizeLeft) { + while (m_sub.Read(buff, sizeof(buff))) { + if (/*!(buff[0x15] & 0x80) &&*/ buff[buff[0x16] + 0x17] == (nLang | 0x20)) { + break; + } + } + } + } + + if (i != packetSize || sizeLeft > 0) { + delete [] ret; + ret = nullptr; + } + } while (false); + + return ret; +} + +const CVobSubFile::SubPos* CVobSubFile::GetFrameInfo(size_t idx, size_t nLang /*= SIZE_T_ERROR*/) const +{ + if (nLang >= m_langs.size()) { + nLang = m_nLang; + } + const CAtlArray& sp = m_langs[nLang].subpos; + + if (idx >= sp.GetCount() + || !sp[idx].bValid + || (m_bOnlyShowForcedSubs && !sp[idx].bForced)) { + return nullptr; + } + + return &sp[idx]; +} + +bool CVobSubFile::GetFrame(size_t idx, size_t nLang /*= SIZE_T_ERROR*/, REFERENCE_TIME rt /*= -1*/) +{ + if (nLang >= m_langs.size()) { + nLang = m_nLang; + } + CAtlArray& sp = m_langs[nLang].subpos; + + if (idx >= sp.GetCount()) { + return false; + } + + if (m_img.nLang != nLang || m_img.nIdx != idx + || (sp[idx].bAnimated && sp[idx].start + m_img.tCurrent <= rt)) { + size_t packetSize = 0, dataSize = 0; + CAutoVectorPtr buff; + buff.Attach(GetPacket(idx, packetSize, dataSize, nLang)); + if (!buff || packetSize == 0 || dataSize == 0) { + return false; + } + + m_img.start = sp[idx].start; + + bool ret = m_img.Decode(buff, packetSize, dataSize, rt >= 0 ? int(rt - sp[idx].start) : INT_MAX, + m_bCustomPal, m_tridx, m_orgpal, m_cuspal, true); + + m_img.delay = sp[idx].stop - sp[idx].start; + + if (!ret) { + return false; + } + + m_img.nIdx = idx; + m_img.nLang = nLang; + } + + return (m_bOnlyShowForcedSubs ? m_img.bForced : true); +} + +bool CVobSubFile::GetFrameByTimeStamp(__int64 time) +{ + return GetFrame(GetFrameIdxByTimeStamp(time)); +} + +size_t CVobSubFile::GetFrameIdxByTimeStamp(__int64 time) +{ + if (m_nLang >= m_langs.size() || m_langs[m_nLang].subpos.IsEmpty()) { + return SIZE_T_ERROR; + } + + CAtlArray& sp = m_langs[m_nLang].subpos; + + size_t i = 0, j = sp.GetCount() - 1, ret = SIZE_T_ERROR; + + if (time >= sp[j].start) { + return j; + } + + while (i < j) { + size_t mid = (i + j) >> 1; + __int64 midstart = sp[mid].start; + + if (time == midstart) { + ret = mid; + break; + } else if (time < midstart) { + ret = SIZE_T_ERROR; + if (j == mid) { + mid--; + } + j = mid; + } else if (time > midstart) { + ret = mid; + if (i == mid) { + mid++; + } + i = mid; + } + } + + return ret; +} + +// + +STDMETHODIMP CVobSubFile::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = nullptr; + + return + QI(IPersist) + QI(ISubStream) + QI(ISubPicProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CVobSubFile::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + rt /= 10000; + + size_t i = GetFrameIdxByTimeStamp(rt); + + const SubPos* sp = GetFrameInfo(i); + if (!sp) { + return nullptr; + } + + if (rt >= sp->stop) { + if (!GetFrameInfo(++i)) { + return nullptr; + } + } + + return (POSITION)(i + 1); +} + +CString CVobSubFile::GetPath() { + return m_path; +} + +STDMETHODIMP_(POSITION) CVobSubFile::GetNext(POSITION pos) +{ + size_t i = (size_t)pos; + return (GetFrameInfo(i) ? (POSITION)(i + 1) : nullptr); +} + +STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStart(POSITION pos, double fps) +{ + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? 10000i64 * sp->start : 0); +} + +STDMETHODIMP_(REFERENCE_TIME) CVobSubFile::GetStop(POSITION pos, double fps) +{ + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? 10000i64 * sp->stop : 0); +} + +STDMETHODIMP_(bool) CVobSubFile::IsAnimated(POSITION pos) +{ + size_t i = (size_t)pos - 1; + const SubPos* sp = GetFrameInfo(i); + return (sp ? sp->bAnimated : false); +} + +STDMETHODIMP CVobSubFile::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + if (spd.bpp != 32) { + return E_INVALIDARG; + } + + rt /= 10000; + + if (!GetFrame(GetFrameIdxByTimeStamp(rt), SIZE_T_ERROR, rt)) { + return E_FAIL; + } + + if (rt >= (m_img.start + m_img.delay)) { + return E_FAIL; + } + + return __super::Render(spd, bbox); +} + +STDMETHODIMP CVobSubFile::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) +{ + relativeTo = VIDEO; + return S_OK; +} + +// IPersist + +STDMETHODIMP CVobSubFile::GetClassID(CLSID* pClassID) +{ + return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; +} + +// ISubStream + +STDMETHODIMP_(int) CVobSubFile::GetStreamCount() +{ + int iStreamCount = 0; + for (const auto& sl : m_langs) { + if (sl.subpos.GetCount()) { + iStreamCount++; + } + } + return iStreamCount; +} + +DWORD LangIDToLCID(WORD langid) +{ + unsigned short id = lang_tbl[find_lang(langid)].id; + CHAR tmp[3]; + tmp[0] = id / 256; + tmp[1] = id & 0xFF; + tmp[2] = 0; + return ISOLang::ISO6391ToLcid(tmp); +} + +STDMETHODIMP CVobSubFile::GetStreamInfo(int iStream, WCHAR** ppName, LCID* pLCID) +{ + for (const auto& sl : m_langs) { + if (sl.subpos.IsEmpty() || iStream-- > 0) { + continue; + } + + if (ppName) { + *ppName = (WCHAR*)CoTaskMemAlloc((sl.alt.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppName, sl.alt.GetLength() + 1, CStringW(sl.alt)); + } + + if (pLCID) { + *pLCID = LangIDToLCID(sl.id); + } + + return S_OK; + } + + return E_FAIL; +} + +STDMETHODIMP_(int) CVobSubFile::GetStream() +{ + int iStream = 0; + + if (m_nLang < m_langs.size()) { + for (size_t i = 0; i < m_nLang; i++) { + if (!m_langs[i].subpos.IsEmpty()) { + iStream++; + } + } + } + + return iStream; +} + +STDMETHODIMP CVobSubFile::SetStream(int iStream) +{ + for (size_t i = 0; i < m_langs.size(); i++) { + const CAtlArray& sp = m_langs[i].subpos; + + if (sp.IsEmpty() || iStream-- > 0) { + continue; + } + + m_nLang = i; + + m_img.Invalidate(); + + break; + } + + return iStream < 0 ? S_OK : E_FAIL; +} + +STDMETHODIMP CVobSubFile::Reload() +{ + if (!PathUtils::Exists(m_title + _T(".idx"))) { + return E_FAIL; + } + return !m_title.IsEmpty() && Open(m_title) ? S_OK : E_FAIL; +} + +// StretchBlt + +static void PixelAtBiLinear(RGBQUAD& c, int x, int y, CVobSubImage& src) +{ + int w = src.rect.Width(), + h = src.rect.Height(); + + int x1 = (x >> 16), y1 = (y >> 16) * w, + x2 = std::min(x1 + 1, w - 1), y2 = std::min(y1 + w, (h - 1) * w); + + RGBQUAD* ptr = src.lpPixels; + + RGBQUAD c11 = ptr[y1 + x1], c12 = ptr[y1 + x2], + c21 = ptr[y2 + x1], c22 = ptr[y2 + x2]; + + __int64 u2 = x & 0xffff, + v2 = y & 0xffff, + u1 = 0x10000 - u2, + v1 = 0x10000 - v2; + + int v1u1 = int(v1 * u1 >> 16) * c11.rgbReserved, + v1u2 = int(v1 * u2 >> 16) * c12.rgbReserved, + v2u1 = int(v2 * u1 >> 16) * c21.rgbReserved, + v2u2 = int(v2 * u2 >> 16) * c22.rgbReserved; + + c.rgbRed = (c11.rgbRed * v1u1 + c12.rgbRed * v1u2 + + c21.rgbRed * v2u1 + c22.rgbRed * v2u2) >> 24; + c.rgbGreen = (c11.rgbGreen * v1u1 + c12.rgbGreen * v1u2 + + c21.rgbGreen * v2u1 + c22.rgbGreen * v2u2) >> 24; + c.rgbBlue = (c11.rgbBlue * v1u1 + c12.rgbBlue * v1u2 + + c21.rgbBlue * v2u1 + c22.rgbBlue * v2u2) >> 24; + c.rgbReserved = BYTE((v1u1 + v1u2 + + v2u1 + v2u2) >> 16); +} + +static void StretchBlt(SubPicDesc& spd, CRect dstrect, CVobSubImage& src) +{ + if (dstrect.IsRectEmpty()) { + return; + } + + if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { + return; + } + + int sw = src.rect.Width(), + sh = src.rect.Height(), + dw = dstrect.Width(), + dh = dstrect.Height(); + + int srcx = 0, + srcy = 0, + srcdx = (sw << 16) / dw >> 1, + srcdy = (sh << 16) / dh >> 1; + + if (dstrect.left < 0) { + srcx = -dstrect.left * (srcdx << 1); + dstrect.left = 0; + } + if (dstrect.top < 0) { + srcy = -dstrect.top * (srcdy << 1); + dstrect.top = 0; + } + if (dstrect.right > spd.w) { + dstrect.right = spd.w; + } + if (dstrect.bottom > spd.h) { + dstrect.bottom = spd.h; + } + + if ((dstrect & CRect(0, 0, spd.w, spd.h)).IsRectEmpty()) { + return; + } + + dw = dstrect.Width(); + dh = dstrect.Height(); + + for (int y = dstrect.top; y < dstrect.bottom; y++, srcy += (srcdy << 1)) { + RGBQUAD* ptr = (RGBQUAD*) & ((BYTE*)spd.bits)[y * spd.pitch] + dstrect.left; + RGBQUAD* endptr = ptr + dw; + + for (int sx = srcx; ptr < endptr; sx += (srcdx << 1), ptr++) { + // PixelAtBiLinear(*ptr, sx, srcy, src); + //// + RGBQUAD cc[4]; + + PixelAtBiLinear(cc[0], sx, srcy, src); + PixelAtBiLinear(cc[1], sx + srcdx, srcy, src); + PixelAtBiLinear(cc[2], sx, srcy + srcdy, src); + PixelAtBiLinear(cc[3], sx + srcdx, srcy + srcdy, src); + + ptr->rgbRed = (cc[0].rgbRed + cc[1].rgbRed + cc[2].rgbRed + cc[3].rgbRed) >> 2; + ptr->rgbGreen = (cc[0].rgbGreen + cc[1].rgbGreen + cc[2].rgbGreen + cc[3].rgbGreen) >> 2; + ptr->rgbBlue = (cc[0].rgbBlue + cc[1].rgbBlue + cc[2].rgbBlue + cc[3].rgbBlue) >> 2; + ptr->rgbReserved = (cc[0].rgbReserved + cc[1].rgbReserved + cc[2].rgbReserved + cc[3].rgbReserved) >> 2; + //// + ptr->rgbRed = ptr->rgbRed * ptr->rgbReserved >> 8; + ptr->rgbGreen = ptr->rgbGreen * ptr->rgbReserved >> 8; + ptr->rgbBlue = ptr->rgbBlue * ptr->rgbReserved >> 8; + ptr->rgbReserved = ~ptr->rgbReserved; + + } + } +} + +// +// CVobSubSettings +// + +void CVobSubSettings::InitSettings() +{ + m_size.SetSize(720, 480); + m_toff = m_x = m_y = 0; + m_org.SetPoint(0, 0); + m_scale_x = m_scale_y = m_alpha = 100; + m_fadein = m_fadeout = 50; + m_iSmooth = 0; + m_bAlign = false; + m_alignhor = m_alignver = 0; + m_bOnlyShowForcedSubs = false; + m_bCustomPal = false; + m_tridx = 0; + ZeroMemory(m_orgpal, sizeof(m_orgpal)); + ZeroMemory(m_cuspal, sizeof(m_cuspal)); +} + +bool CVobSubSettings::GetCustomPal(RGBQUAD* cuspal, int& tridx) +{ + memcpy(cuspal, m_cuspal, sizeof(RGBQUAD) * 4); + tridx = m_tridx; + return m_bCustomPal; +} + +void CVobSubSettings::SetCustomPal(const RGBQUAD* cuspal, int tridx) +{ + memcpy(m_cuspal, cuspal, sizeof(RGBQUAD) * 4); + m_tridx = tridx & 0xf; + for (int i = 0; i < 4; i++) { + m_cuspal[i].rgbReserved = (tridx & (1 << i)) ? 0 : 0xff; + } + m_img.Invalidate(); +} + +void CVobSubSettings::GetDestrect(CRect& r) +{ + int w = MulDiv(m_img.rect.Width(), m_scale_x, 100); + int h = MulDiv(m_img.rect.Height(), m_scale_y, 100); + + if (!m_bAlign) { + r.left = MulDiv(m_img.rect.left, m_scale_x, 100); + r.right = MulDiv(m_img.rect.right, m_scale_x, 100); + r.top = MulDiv(m_img.rect.top, m_scale_y, 100); + r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); + } else { + switch (m_alignhor) { + case 0: + r.left = 0; + r.right = w; + break; // left + case 1: + r.left = -(w >> 1); + r.right = -(w >> 1) + w; + break; // center + case 2: + r.left = -w; + r.right = 0; + break; // right + default: + r.left = MulDiv(m_img.rect.left, m_scale_x, 100); + r.right = MulDiv(m_img.rect.right, m_scale_x, 100); + break; + } + + switch (m_alignver) { + case 0: + r.top = 0; + r.bottom = h; + break; // top + case 1: + r.top = -(h >> 1); + r.bottom = -(h >> 1) + h; + break; // center + case 2: + r.top = -h; + r.bottom = 0; + break; // bottom + default: + r.top = MulDiv(m_img.rect.top, m_scale_y, 100); + r.bottom = MulDiv(m_img.rect.bottom, m_scale_y, 100); + break; + } + } + + r += m_org; +} + +void CVobSubSettings::GetDestrect(CRect& r, int w, int h) +{ + GetDestrect(r); + + r.left = MulDiv(r.left, w, m_size.cx); + r.right = MulDiv(r.right, w, m_size.cx); + r.top = MulDiv(r.top, h, m_size.cy); + r.bottom = MulDiv(r.bottom, h, m_size.cy); +} + +void CVobSubSettings::SetAlignment(bool bAlign, int x, int y, int hor /*= 1*/, int ver /*= 1*/) +{ + m_bAlign = bAlign; + if (bAlign) { + m_org.x = MulDiv(m_size.cx, x, 100); + m_org.y = MulDiv(m_size.cy, y, 100); + m_alignhor = std::min(std::max(hor, 0), 2); + m_alignver = std::min(std::max(ver, 0), 2); + } else { + m_org.x = m_x; + m_org.y = m_y; + } +} + +HRESULT CVobSubSettings::Render(SubPicDesc& spd, RECT& bbox) +{ + CRect r; + GetDestrect(r, spd.w, spd.h); + StretchBlt(spd, r, m_img); + /* + CRenderedTextSubtitle rts(nullptr); + rts.CreateDefaultStyle(DEFAULT_CHARSET); + rts.m_storageRes.SetSize(m_size.cx, m_size.cy); + CStringW assstr; + m_img.Polygonize(assstr, false); + REFERENCE_TIME rtStart = 10000i64*m_img.start, rtStop = 10000i64*(m_img.start+m_img.delay); + rts.Add(assstr, true, rtStart, rtStop); + rts.Render(spd, (rtStart+rtStop)/2, 25, r); + */ + r &= CRect(CPoint(0, 0), CSize(spd.w, spd.h)); + bbox = r; + return !r.IsRectEmpty() ? S_OK : S_FALSE; +} + +///////////////////////////////////////////////////////// + +static bool CompressFile(CString fn) +{ + BOOL b = FALSE; + + HANDLE h = CreateFile(fn, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); + if (h != INVALID_HANDLE_VALUE) { + unsigned short us = COMPRESSION_FORMAT_DEFAULT; + DWORD nBytesReturned; + b = DeviceIoControl(h, FSCTL_SET_COMPRESSION, (LPVOID)&us, 2, nullptr, 0, (LPDWORD)&nBytesReturned, nullptr); + CloseHandle(h); + } + + return !!b; +} + +bool CVobSubFile::SaveVobSub(CString fn, int delay) +{ + if (!WriteIdx(fn + _T(".idx"), delay) || !WriteSub(fn + _T(".sub"))) { + return false; + } + m_path = fn + _T(".idx"); + return true; +} + +bool CVobSubFile::SaveWinSubMux(CString fn, int delay) +{ + TrimExtension(fn); + + CStdioFile f; + if (!f.Open(fn + _T(".sub"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } + + m_img.Invalidate(); + + CAutoVectorPtr p4bpp; + if (!p4bpp.Allocate(720 * 576 / 2)) { + return false; + } + + CAtlArray& sp = m_langs[m_nLang].subpos; + for (size_t i = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } + + int pal[4] = {0, 1, 2, 3}; + + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { + j &= 3; + memset(p4bpp, (j << 4) | j, 720 * 576 / 2); + pal[j] ^= pal[0], pal[0] ^= pal[j], pal[j] ^= pal[0]; + break; + } + } + + int tr[4] = {m_img.pal[pal[0]].tr, m_img.pal[pal[1]].tr, m_img.pal[pal[2]].tr, m_img.pal[pal[3]].tr}; + + DWORD uipal[4 + 12]; + + if (!m_bCustomPal) { + uipal[0] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[0]].pal]); + uipal[1] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[1]].pal]); + uipal[2] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[2]].pal]); + uipal[3] = *((DWORD*)&m_img.orgpal[m_img.pal[pal[3]].pal]); + } else { + uipal[0] = *((DWORD*)&m_img.cuspal[pal[0]]) & 0xffffff; + uipal[1] = *((DWORD*)&m_img.cuspal[pal[1]]) & 0xffffff; + uipal[2] = *((DWORD*)&m_img.cuspal[pal[2]]) & 0xffffff; + uipal[3] = *((DWORD*)&m_img.cuspal[pal[3]]) & 0xffffff; + } + + CAtlMap palmap; + palmap[uipal[0]] = 0; + palmap[uipal[1]] = 1; + palmap[uipal[2]] = 2; + palmap[uipal[3]] = 3; + + uipal[0] = 0xff; // blue background + + int w = m_img.rect.Width() - 2; + int h = m_img.rect.Height() - 2; + int pitch = (((w + 1) >> 1) + 3) & ~3; + + for (ptrdiff_t y = 0; y < h; y++) { + DWORD* p = (DWORD*)&m_img.lpPixels[(y + 1) * (w + 2) + 1]; + + for (ptrdiff_t x = 0; x < w; x++, p++) { + BYTE c = 0; + + if (*p & 0xff000000) { + DWORD uic = *p & 0xffffff; + palmap.Lookup(uic, c); + } + + BYTE& c4bpp = p4bpp[(h - y - 1) * pitch + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); + } + } + + int t1 = (int)m_img.start + delay; + int t2 = t1 + (int)m_img.delay /*+ (m_size.cy==480?(1000/29.97+1):(1000/25))*/; + + ASSERT(t2 > t1); + + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } + + CString bmpfn; + bmpfn.Format(_T("%s_%06Iu.bmp"), fn.GetString(), i + 1); + + CString str; + str.Format(_T("%s\t%02d:%02d:%02d:%02d %02d:%02d:%02d:%02d\t%03d %03d %03d %03d %d %d %d %d\n"), + bmpfn.GetString(), + t1 / 1000 / 60 / 60, (t1 / 1000 / 60) % 60, (t1 / 1000) % 60, (t1 % 1000) / 10, + t2 / 1000 / 60 / 60, (t2 / 1000 / 60) % 60, (t2 / 1000) % 60, (t2 % 1000) / 10, + m_img.rect.Width(), m_img.rect.Height(), m_img.rect.left, m_img.rect.top, + (tr[0] << 4) | tr[0], (tr[1] << 4) | tr[1], (tr[2] << 4) | tr[2], (tr[3] << 4) | tr[3]); + f.WriteString(str); + + BITMAPFILEHEADER fhdr = { + 0x4d42, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + pitch * h, + 0, 0, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + }; + + BITMAPINFOHEADER ihdr = { + sizeof(BITMAPINFOHEADER), + w, h, 1, 4, 0, + 0, + pitch * h, 0, + 16, 4 + }; + + CFile bmp; + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { + bmp.Write(&fhdr, sizeof(fhdr)); + bmp.Write(&ihdr, sizeof(ihdr)); + bmp.Write(uipal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, pitch * h); + bmp.Close(); + + CompressFile(bmpfn); + } + } + + m_path = fn + _T(".sub"); + + return true; +} + +bool CVobSubFile::SaveScenarist(CString fn, int delay) +{ + TrimExtension(fn); + + CStdioFile f; + if (!f.Open(fn + _T(".sst"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } + + m_img.Invalidate(); + + fn.Replace('\\', '/'); + CString title = fn.Mid(fn.ReverseFind('/') + 1); + + TCHAR buff[MAX_PATH], * pFilePart = buff; + if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { + return false; + } + + CString fullpath = CString(buff).Left(int(pFilePart - buff)); + fullpath.TrimRight(_T("\\/")); + if (fullpath.IsEmpty()) { + return false; + } + + CString str, str2; + str += _T("st_format\t2\n"); + str += _T("Display_Start\t%s\n"); + str += _T("TV_Type\t\t%s\n"); + str += _T("Tape_Type\tNON_DROP\n"); + str += _T("Pixel_Area\t(0 %d)\n"); + str += _T("Directory\t%s\n"); + str += _T("Subtitle\t%s\n"); + str += _T("Display_Area\t(0 2 719 %d)\n"); + str += _T("Contrast\t(15 15 15 0)\n"); + str += _T("\n"); + str += _T("PA\t(0 0 255 - - - )\n"); + str += _T("E1\t(255 0 0 - - - )\n"); + str += _T("E2\t(0 0 0 - - - )\n"); + str += _T("BG\t(255 255 255 - - - )\n"); + str += _T("\n"); + str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); + str2.Format(str, + !m_bOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), + m_size.cy == 480 ? _T("NTSC") : _T("PAL"), + m_size.cy - 3, + fullpath.GetString(), + title.GetString(), + m_size.cy == 480 ? 479 : 574); + + f.WriteString(str2); + + f.Flush(); + + RGBQUAD pal[16] = { + {255, 0, 0, 0}, + {0, 0, 255, 0}, + {0, 0, 0, 0}, + {255, 255, 255, 0}, + {0, 255, 0, 0}, + {255, 0, 255, 0}, + {0, 255, 255, 0}, + {125, 125, 0, 0}, + {125, 125, 125, 0}, + {225, 225, 225, 0}, + {0, 0, 125, 0}, + {0, 125, 0, 0}, + {125, 0, 0, 0}, + {255, 0, 222, 0}, + {0, 125, 222, 0}, + {125, 0, 125, 0}, + }; + + BITMAPFILEHEADER fhdr = { + 0x4d42, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), + 0, 0, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + }; + + BITMAPINFOHEADER ihdr = { + sizeof(BITMAPINFOHEADER), + 720, m_size.cy - 2, 1, 4, 0, + DWORD(360 * (m_size.cy - 2)), + 0, 0, + 16, 4 + }; + + bool bCustomPal = m_bCustomPal; + m_bCustomPal = true; + RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; + memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); + memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); + + CAutoVectorPtr p4bpp; + if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { + return false; + } + + BYTE colormap[16]; + + for (size_t i = 0; i < 16; i++) { + BYTE idx = 0; + int maxdif = 255 * 255 * 3 + 1; + + for (size_t j = 0; j < 16 && maxdif; j++) { + int rdif = pal[j].rgbRed - m_orgpal[i].rgbRed; + int gdif = pal[j].rgbGreen - m_orgpal[i].rgbGreen; + int bdif = pal[j].rgbBlue - m_orgpal[i].rgbBlue; + + int dif = rdif * rdif + gdif * gdif + bdif * bdif; + if (dif < maxdif) { + maxdif = dif; + idx = (BYTE)j; + } + } + + colormap[i] = idx + 1; + } + + int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; + + CAtlArray& sp = m_langs[m_nLang].subpos; + for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } + + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { + j &= 3; + memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); + break; + } + } + + for (ptrdiff_t y = std::max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { + ASSERT(m_size.cy - y - 1 >= 0); + if (m_size.cy - y - 1 < 0) { + break; + } + + DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; + + for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { + DWORD rgb = *p & 0xffffff; + BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; + BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); + } + } + + CString bmpfn; + bmpfn.Format(_T("%s_%04Iu.bmp"), fn.GetString(), i + 1); + title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); + + // E1, E2, P, Bg + int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]}; + c[0] ^= c[1], c[1] ^= c[0], c[0] ^= c[1]; + + if (memcmp(pc, c, sizeof(c))) { + memcpy(pc, c, sizeof(c)); + str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); + f.WriteString(str); + } + + // E1, E2, P, Bg + int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; + a[0] ^= a[1], a[1] ^= a[0], a[0] ^= a[1]; + + if (memcmp(pa, a, sizeof(a))) { + memcpy(pa, a, sizeof(a)); + str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); + f.WriteString(str); + } + + int t1 = (int)sp[i].start + delay; + int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; + int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); + + int t2 = (int)sp[i].stop + delay; + int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; + int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); + + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } + + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { + f2++; + if (f2 == (m_size.cy == 480 ? 30 : 25)) { + f2 = 0; + s2++; + if (s2 == 60) { + s2 = 0; + m2++; + if (m2 == 60) { + m2 = 0; + h2++; + } + } + } + } + + if (i + 1 < sp.GetCount()) { + int t3 = (int)sp[i + 1].start + delay; + int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; + int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); + + if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { + f2--; + if (f2 == -1) { + f2 = (m_size.cy == 480 ? 29 : 24); + s2--; + if (s2 == -1) { + s2 = 59; + m2--; + if (m2 == -1) { + m2 = 59; + if (h2 > 0) { + h2--; + } + } + } + } + } + } + + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { + continue; + } + + str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), + ++k, + h1, m1, s1, f1, + h2, m2, s2, f2, + title.GetString()); + f.WriteString(str); + + CFile bmp; + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::modeRead | CFile::typeBinary)) { + bmp.Write(&fhdr, sizeof(fhdr)); + bmp.Write(&ihdr, sizeof(ihdr)); + bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, 360 * (m_size.cy - 2)); + bmp.Close(); + + CompressFile(bmpfn); + } + } + + m_bCustomPal = bCustomPal; + memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); + + m_path = fn + _T(".sst"); + + return true; +} + +bool CVobSubFile::SaveMaestro(CString fn, int delay) +{ + TrimExtension(fn); + + CStdioFile f; + if (!f.Open(fn + _T(".son"), CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::shareDenyWrite)) { + return false; + } + + m_img.Invalidate(); + + fn.Replace('\\', '/'); + CString title = fn.Mid(fn.ReverseFind('/') + 1); + + TCHAR buff[MAX_PATH], * pFilePart = buff; + if (GetFullPathName(fn, MAX_PATH, buff, &pFilePart) == 0) { + return false; + } + + CString fullpath = CString(buff).Left(int(pFilePart - buff)); + fullpath.TrimRight(_T("\\/")); + if (fullpath.IsEmpty()) { + return false; + } + + CString str, str2; + str += _T("st_format\t2\n"); + str += _T("Display_Start\t%s\n"); + str += _T("TV_Type\t\t%s\n"); + str += _T("Tape_Type\tNON_DROP\n"); + str += _T("Pixel_Area\t(0 %d)\n"); + str += _T("Directory\t%s\n"); + str += _T("Subtitle\t%s\n"); + str += _T("Display_Area\t(0 2 719 %d)\n"); + str += _T("Contrast\t(15 15 15 0)\n"); + str += _T("\n"); + str += _T("SP_NUMBER\tSTART\tEND\tFILE_NAME\n"); + str2.Format(str, + !m_bOnlyShowForcedSubs ? _T("non_forced") : _T("forced"), + m_size.cy == 480 ? _T("NTSC") : _T("PAL"), + m_size.cy - 3, + fullpath.GetString(), + title.GetString(), + m_size.cy == 480 ? 479 : 574); + + f.WriteString(str2); + + f.Flush(); + + BITMAPFILEHEADER fhdr = { + 0x4d42, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + 360 * (m_size.cy - 2), + 0, 0, + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16 * sizeof(RGBQUAD) + }; + + BITMAPINFOHEADER ihdr = { + sizeof(BITMAPINFOHEADER), + 720, m_size.cy - 2, 1, 4, 0, + DWORD(360 * (m_size.cy - 2)), + 0, 0, + 16, 4 + }; + + bool bCustomPal = m_bCustomPal; + m_bCustomPal = true; + RGBQUAD tempCusPal[4], newCusPal[4 + 12] = {{255, 0, 0, 0}, {0, 0, 255, 0}, {0, 0, 0, 0}, {255, 255, 255, 0}}; + memcpy(tempCusPal, m_cuspal, sizeof(tempCusPal)); + memcpy(m_cuspal, newCusPal, sizeof(m_cuspal)); + + CAutoVectorPtr p4bpp; + if (!p4bpp.Allocate((m_size.cy - 2) * 360)) { + return false; + } + + BYTE colormap[16]; + for (BYTE i = 0; i < 16; i++) { + colormap[i] = i; + } + + CFile spf; + if (spf.Open(fn + _T(".spf"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { + for (size_t i = 0; i < 16; i++) { + COLORREF c = (m_orgpal[i].rgbBlue << 16) | (m_orgpal[i].rgbGreen << 8) | m_orgpal[i].rgbRed; + spf.Write(&c, sizeof(COLORREF)); + } + + spf.Close(); + } + + int pc[4] = {1, 1, 1, 1}, pa[4] = {15, 15, 15, 0}; + + CAtlArray& sp = m_langs[m_nLang].subpos; + for (size_t i = 0, k = 0; i < sp.GetCount(); i++) { + if (!GetFrame(i)) { + continue; + } + + for (int j = 0; j < 5; j++) { + if (j == 4 || !m_img.pal[j].tr) { + j &= 3; + memset(p4bpp, (j << 4) | j, (m_size.cy - 2) * 360); + break; + } + } + + for (ptrdiff_t y = std::max(m_img.rect.top + 1, 2l); y < m_img.rect.bottom - 1; y++) { + ASSERT(m_size.cy - y - 1 >= 0); + if (m_size.cy - y - 1 < 0) { + break; + } + + DWORD* p = (DWORD*)&m_img.lpPixels[(y - m_img.rect.top) * m_img.rect.Width() + 1]; + + for (ptrdiff_t x = m_img.rect.left + 1; x < m_img.rect.right - 1; x++, p++) { + DWORD rgb = *p & 0xffffff; + BYTE c = rgb == 0x0000ff ? 0 : rgb == 0xff0000 ? 1 : rgb == 0x000000 ? 2 : 3; + BYTE& c4bpp = p4bpp[(m_size.cy - y - 1) * 360 + (x >> 1)]; + c4bpp = (x & 1) ? ((c4bpp & 0xf0) | c) : ((c4bpp & 0x0f) | (c << 4)); + } + } + + CString bmpfn; + bmpfn.Format(_T("%s_%04Iu.bmp"), fn.GetString(), i + 1); + title = bmpfn.Mid(bmpfn.ReverseFind('/') + 1); + + // E1, E2, P, Bg + int c[4] = {colormap[m_img.pal[1].pal], colormap[m_img.pal[2].pal], colormap[m_img.pal[0].pal], colormap[m_img.pal[3].pal]}; + + if (memcmp(pc, c, sizeof(c))) { + memcpy(pc, c, sizeof(c)); + str.Format(_T("Color\t (%d %d %d %d)\n"), c[0], c[1], c[2], c[3]); + f.WriteString(str); + } + + // E1, E2, P, Bg + int a[4] = {m_img.pal[1].tr, m_img.pal[2].tr, m_img.pal[0].tr, m_img.pal[3].tr}; + + if (memcmp(pa, a, sizeof(a))) { + memcpy(pa, a, sizeof(a)); + str.Format(_T("Contrast (%d %d %d %d)\n"), a[0], a[1], a[2], a[3]); + f.WriteString(str); + } + + int t1 = (int)sp[i].start + delay; + int h1 = t1 / 1000 / 60 / 60, m1 = (t1 / 1000 / 60) % 60, s1 = (t1 / 1000) % 60; + int f1 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t1 % 1000) / 1000); + + int t2 = (int)sp[i].stop + delay; + int h2 = t2 / 1000 / 60 / 60, m2 = (t2 / 1000 / 60) % 60, s2 = (t2 / 1000) % 60; + int f2 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t2 % 1000) / 1000); + + if (t2 <= 0) { + continue; + } + if (t1 < 0) { + t1 = 0; + } + + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { + f2++; + if (f2 == (m_size.cy == 480 ? 30 : 25)) { + f2 = 0; + s2++; + if (s2 == 60) { + s2 = 0; + m2++; + if (m2 == 60) { + m2 = 0; + h2++; + } + } + } + } + + if (i < sp.GetCount() - 1) { + int t3 = (int)sp[i + 1].start + delay; + int h3 = t3 / 1000 / 60 / 60, m3 = (t3 / 1000 / 60) % 60, s3 = (t3 / 1000) % 60; + int f3 = (int)((m_size.cy == 480 ? 29.97 : 25) * (t3 % 1000) / 1000); + + if (h3 == h2 && m3 == m2 && s3 == s2 && f3 == f2) { + f2--; + if (f2 == -1) { + f2 = (m_size.cy == 480 ? 29 : 24); + s2--; + if (s2 == -1) { + s2 = 59; + m2--; + if (m2 == -1) { + m2 = 59; + if (h2 > 0) { + h2--; + } + } + } + } + } + } + + if (h1 == h2 && m1 == m2 && s1 == s2 && f1 == f2) { + continue; + } + + str.Format(_T("%04u\t%02d:%02d:%02d:%02d\t%02d:%02d:%02d:%02d\t%s\n"), + ++k, + h1, m1, s1, f1, + h2, m2, s2, f2, + title.GetString()); + f.WriteString(str); + + CFile bmp; + if (bmp.Open(bmpfn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) { + bmp.Write(&fhdr, sizeof(fhdr)); + bmp.Write(&ihdr, sizeof(ihdr)); + bmp.Write(newCusPal, sizeof(RGBQUAD) * 16); + bmp.Write(p4bpp, 360 * (m_size.cy - 2)); + bmp.Close(); + + CompressFile(bmpfn); + } + } + + m_bCustomPal = bCustomPal; + memcpy(m_cuspal, tempCusPal, sizeof(m_cuspal)); + + m_path = fn + _T(".son"); + + return true; +} + +// +// CVobSubStream +// + +CVobSubStream::CVobSubStream(CCritSec* pLock) + : CSubPicProviderImpl(pLock) +{ +} + +CVobSubStream::~CVobSubStream() +{ +} + +void CVobSubStream::Open(CString name, BYTE* pData, int len) +{ + CAutoLock cAutoLock(&m_csSubPics); + + m_name = name; + + CAtlList lines; + Explode(CString(CStringA((CHAR*)pData, len)), lines, _T('\n')); + while (lines.GetCount()) { + CAtlList sl; + Explode(lines.RemoveHead(), sl, ':', 2); + if (sl.GetCount() != 2) { + continue; + } + CString key = sl.GetHead(); + CString value = sl.GetTail(); + if (key == _T("size")) { + _stscanf_s(value, _T("%dx %d"), &m_size.cx, &m_size.cy); + } else if (key == _T("org")) { + _stscanf_s(value, _T("%d, %d"), &m_org.x, &m_org.y); + } else if (key == _T("scale")) { + _stscanf_s(value, _T("%d%%, %d%%"), &m_scale_x, &m_scale_y); + } else if (key == _T("alpha")) { + _stscanf_s(value, _T("%d%%"), &m_alpha); + } else if (key == _T("smooth")) + m_iSmooth = + value == _T("0") || value == _T("OFF") ? 0 : + value == _T("1") || value == _T("ON") ? 1 : + value == _T("2") || value == _T("OLD") ? 2 : + 0; + else if (key == _T("align")) { + Explode(value, sl, ' '); + if (sl.GetCount() == 4) { + sl.RemoveAt(sl.FindIndex(1)); + } + if (sl.GetCount() == 3) { + m_bAlign = sl.RemoveHead() == _T("ON"); + CString hor = sl.GetHead(), ver = sl.GetTail(); + m_alignhor = hor == _T("LEFT") ? 0 : hor == _T("CENTER") ? 1 : hor == _T("RIGHT") ? 2 : 1; + m_alignver = ver == _T("TOP") ? 0 : ver == _T("CENTER") ? 1 : /*ver == _T("BOTTOM") ? 2 :*/ 2; + } + } else if (key == _T("fade in/out")) { + _stscanf_s(value, _T("%d, %d"), &m_fadein, &m_fadeout); + } else if (key == _T("time offset")) { + m_toff = _tcstol(value, nullptr, 10); + } else if (key == _T("forced subs")) { + m_bOnlyShowForcedSubs = value == _T("1") || value == _T("ON"); + } else if (key == _T("palette")) { + Explode(value, sl, ',', 16); + for (size_t i = 0; i < 16 && sl.GetCount(); i++) { + *(DWORD*)&m_orgpal[i] = _tcstol(sl.RemoveHead(), nullptr, 16); + } + } else if (key == _T("custom colors")) { + m_bCustomPal = Explode(value, sl, ',', 3) == _T("ON"); + if (sl.GetCount() == 3) { + sl.RemoveHead(); + CAtlList tridx, colors; + + Explode(sl.RemoveHead(), tridx, ':', 2); + int _tridx = 1; + if (tridx.RemoveHead() == _T("tridx")) { + TCHAR tr[4]; + _stscanf_s(tridx.RemoveHead(), _T("%c%c%c%c"), &tr[0], 1, &tr[1], 1, &tr[2], 1, &tr[3], 1); + for (size_t i = 0; i < 4; i++) { + _tridx |= ((tr[i] == '1') ? 1 : 0) << i; + } + } + + Explode(sl.RemoveHead(), colors, ':', 2); + if (colors.RemoveHead() == _T("colors")) { + Explode(colors.RemoveHead(), colors, ',', 4); + + RGBQUAD pal[4]; + for (size_t i = 0; i < 4 && colors.GetCount(); i++) { + *(DWORD*)&pal[i] = _tcstol(colors.RemoveHead(), nullptr, 16); + } + + SetCustomPal(pal, _tridx); + } + } + } + } +} + +void CVobSubStream::Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len) +{ + if (len <= 4 || ((pData[0] << 8) | pData[1]) != len) { + return; + } + + CVobSubImage vsi; + vsi.GetPacketInfo(pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3]); + + CAutoPtr p(DEBUG_NEW SubPic()); + p->tStart = tStart; + p->tStop = vsi.delay > 0 ? (tStart + 10000i64 * vsi.delay) : tStop; + p->bAnimated = vsi.bAnimated; + p->pData.SetCount(len); + memcpy(p->pData.GetData(), pData, p->pData.GetCount()); + + CAutoLock cAutoLock(&m_csSubPics); + while (m_subpics.GetCount() && m_subpics.GetTail()->tStart >= tStart) { + m_subpics.RemoveTail(); + m_img.nIdx = SIZE_T_ERROR; + } + + // We can only render one subpicture at a time, thus if there is overlap + // we have to fix it. tStop = tStart seems to work. + if (m_subpics.GetCount() && m_subpics.GetTail()->tStop > p->tStart) { + TRACE(_T("[CVobSubStream::Add] Vobsub timestamp overlap detected! ") + _T("Subpicture #%d, StopTime %I64d > %I64d (Next StartTime), making them equal!\n"), + m_subpics.GetCount(), m_subpics.GetTail()->tStop, p->tStart); + m_subpics.GetTail()->tStop = p->tStart; + } + + m_subpics.AddTail(p); +} + +void CVobSubStream::RemoveAll() +{ + CAutoLock cAutoLock(&m_csSubPics); + m_subpics.RemoveAll(); + m_img.nIdx = SIZE_T_ERROR; +} + +STDMETHODIMP CVobSubStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = nullptr; + + return + QI(IPersist) + QI(ISubStream) + QI(ISubPicProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubPicProvider + +STDMETHODIMP_(POSITION) CVobSubStream::GetStartPosition(REFERENCE_TIME rt, double fps) +{ + CAutoLock cAutoLock(&m_csSubPics); + POSITION pos = m_subpics.GetTailPosition(); + for (; pos; m_subpics.GetPrev(pos)) { + SubPic* sp = m_subpics.GetAt(pos); + if (sp->tStart <= rt) { + if (sp->tStop <= rt) { + m_subpics.GetNext(pos); + } + break; + } + } + return pos; +} + +STDMETHODIMP_(POSITION) CVobSubStream::GetNext(POSITION pos) +{ + CAutoLock cAutoLock(&m_csSubPics); + m_subpics.GetNext(pos); + return pos; +} + +STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStart(POSITION pos, double fps) +{ + CAutoLock cAutoLock(&m_csSubPics); + return m_subpics.GetAt(pos)->tStart; +} + +STDMETHODIMP_(REFERENCE_TIME) CVobSubStream::GetStop(POSITION pos, double fps) +{ + CAutoLock cAutoLock(&m_csSubPics); + return m_subpics.GetAt(pos)->tStop; +} + +STDMETHODIMP_(bool) CVobSubStream::IsAnimated(POSITION pos) +{ + CAutoLock cAutoLock(&m_csSubPics); + return m_subpics.GetAt(pos)->bAnimated; +} + +STDMETHODIMP CVobSubStream::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox) +{ + if (spd.bpp != 32) { + return E_INVALIDARG; + } + + for (POSITION pos = m_subpics.GetTailPosition(); pos; m_subpics.GetPrev(pos)) { + SubPic* sp = m_subpics.GetAt(pos); + if (sp->tStart <= rt && rt < sp->tStop) { + if (m_img.nIdx != (size_t)pos || (sp->bAnimated && sp->tStart + m_img.tCurrent * 10000i64 <= rt)) { + BYTE* pData = sp->pData.GetData(); + m_img.Decode( + pData, (pData[0] << 8) | pData[1], (pData[2] << 8) | pData[3], int((rt - sp->tStart) / 10000i64), + m_bCustomPal, m_tridx, m_orgpal, m_cuspal, true); + m_img.nIdx = (size_t)pos; + } + + return __super::Render(spd, bbox); + } + } + + return E_FAIL; +} + +STDMETHODIMP CVobSubStream::GetRelativeTo(POSITION pos, RelativeTo& relativeTo) +{ + relativeTo = VIDEO; + return S_OK; +} + +// IPersist + +STDMETHODIMP CVobSubStream::GetClassID(CLSID* pClassID) +{ + return pClassID ? *pClassID = __uuidof(this), S_OK : E_POINTER; +} + +// ISubStream + +STDMETHODIMP_(int) CVobSubStream::GetStreamCount() +{ + return 1; +} + +STDMETHODIMP CVobSubStream::GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID) +{ + CAutoLock cAutoLock(&m_csSubPics); + + if (ppName) { + *ppName = (WCHAR*)CoTaskMemAlloc((m_name.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppName)) { + return E_OUTOFMEMORY; + } + wcscpy_s(*ppName, m_name.GetLength() + 1, CStringW(m_name)); + } + + if (pLCID) { + *pLCID = 0; // TODO + } + + return S_OK; +} + +STDMETHODIMP_(int) CVobSubStream::GetStream() +{ + return 0; +} + +STDMETHODIMP CVobSubStream::SetStream(int iStream) +{ + return iStream == 0 ? S_OK : E_FAIL; +} diff --git a/src/Subtitles/VobSubFile.h b/src/Subtitles/VobSubFile.h index 97dc6e0d954..51d18fde508 100644 --- a/src/Subtitles/VobSubFile.h +++ b/src/Subtitles/VobSubFile.h @@ -1,219 +1,219 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#pragma once - -#include -#include "VobSubImage.h" -#include "../SubPic/SubPicProviderImpl.h" - -#define VOBSUBIDXVER 7 - -#define ReadBEb(var) \ - f.Read(&((BYTE*)&var)[0], 1); - -#define ReadBEw(var) \ - f.Read(&((BYTE*)&var)[1], 1); \ - f.Read(&((BYTE*)&var)[0], 1); - -#define ReadBEdw(var) \ - f.Read(&((BYTE*)&var)[3], 1); \ - f.Read(&((BYTE*)&var)[2], 1); \ - f.Read(&((BYTE*)&var)[1], 1); \ - f.Read(&((BYTE*)&var)[0], 1); - -extern CString FindLangFromId(WORD id); - -class CVobSubSettings -{ -protected: - HRESULT Render(SubPicDesc& spd, RECT& bbox); - -public: - CSize m_size; - int m_x, m_y; - CPoint m_org; - int m_scale_x, m_scale_y; // % (don't set it to unsigned because as a side effect it will mess up negative coordinates in GetDestrect()) - int m_alpha; // % - int m_iSmooth; // 0: OFF, 1: ON, 2: OLD (means no filtering at all) - int m_fadein, m_fadeout; // ms - bool m_bAlign; - int m_alignhor, m_alignver; // 0: left/top, 1: center, 2: right/bottom - unsigned int m_toff; // ms - bool m_bOnlyShowForcedSubs; - bool m_bCustomPal; - int m_tridx; - RGBQUAD m_orgpal[16], m_cuspal[4]; - - CVobSubImage m_img; - - CVobSubSettings() { InitSettings(); } - void InitSettings(); - - bool GetCustomPal(RGBQUAD* cuspal, int& tridx); - void SetCustomPal(const RGBQUAD* cuspal, int tridx); - - void GetDestrect(CRect& r); // destrect of m_img, considering the current alignment mode - void GetDestrect(CRect& r, int w, int h); // this will scale it to the frame size of (w, h) - - void SetAlignment(bool bAlign, int x, int y, int hor = 1, int ver = 1); -}; - -class __declspec(uuid("998D4C9A-460F-4de6-BDCD-35AB24F94ADF")) - CVobSubFile : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl -{ -public: - struct SubPos { - __int64 filepos = 0i64; - __int64 start = 0i64; - __int64 stop = 0i64; - bool bForced = false; - bool bAnimated = false; - char vobid = 0; - char cellid = 0; - __int64 celltimestamp = 0i64; - bool bValid = false; - - bool operator <(const SubPos& rhs) const { - return start < rhs.start; - } - }; - - struct SubLang { - WORD id = 0; - CString name, alt; - CAtlArray subpos; - }; - -protected: - CString m_title; - CString m_path; - - void TrimExtension(CString& fn); - bool ReadIdx(CString fn, int& ver), ReadSub(CString fn), ReadRar(CString fn), ReadIfo(CString fn); - bool WriteIdx(CString fn, int delay), WriteSub(CString fn); - - CMemFile m_sub; - - BYTE* GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang = SIZE_T_ERROR); - const SubPos* GetFrameInfo(size_t idx, size_t nLang = SIZE_T_ERROR) const; - bool GetFrame(size_t idx, size_t nLang = SIZE_T_ERROR, REFERENCE_TIME rt = -1); - bool GetFrameByTimeStamp(__int64 time); - size_t GetFrameIdxByTimeStamp(__int64 time); - - bool SaveVobSub(CString fn, int delay); - bool SaveWinSubMux(CString fn, int delay); - bool SaveScenarist(CString fn, int delay); - bool SaveMaestro(CString fn, int delay); - -public: - size_t m_nLang; - std::array m_langs; - - CVobSubFile(CCritSec* pLock); - virtual ~CVobSubFile(); - - bool Copy(CVobSubFile& vsf); - CString GetPath(); - - enum SubFormat { - None, - VobSub, - WinSubMux, - Scenarist, - Maestro - }; - - bool Open(CString fn); - bool Save(CString fn, int delay = 0, SubFormat sf = VobSub); - void Close(); - - CString GetTitle() { return m_title; } - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); - - // IPersist - STDMETHODIMP GetClassID(CLSID* pClassID); - - // ISubStream - STDMETHODIMP_(int) GetStreamCount(); - STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); - STDMETHODIMP_(int) GetStream(); - STDMETHODIMP SetStream(int iStream); - STDMETHODIMP Reload(); - STDMETHODIMP SetSourceTargetInfo(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) { return E_NOTIMPL; }; -}; - -class __declspec(uuid("D7FBFB45-2D13-494F-9B3D-FFC9557D5C45")) - CVobSubStream : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl -{ - CString m_name; - - CCritSec m_csSubPics; - struct SubPic { - REFERENCE_TIME tStart, tStop; - bool bAnimated; - CAtlArray pData; - }; - CAutoPtrList m_subpics; - -public: - CVobSubStream(CCritSec* pLock); - virtual ~CVobSubStream(); - - void Open(CString name, BYTE* pData, int len); - - void Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len); - void RemoveAll(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicProvider - STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); - STDMETHODIMP_(POSITION) GetNext(POSITION pos); - STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); - STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); - STDMETHODIMP_(bool) IsAnimated(POSITION pos); - STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); - STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); - - // IPersist - STDMETHODIMP GetClassID(CLSID* pClassID); - - // ISubStream - STDMETHODIMP_(int) GetStreamCount(); - STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); - STDMETHODIMP_(int) GetStream(); - STDMETHODIMP SetStream(int iStream); - STDMETHODIMP Reload() { return E_NOTIMPL; } - STDMETHODIMP SetSourceTargetInfo(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) { return E_NOTIMPL; } -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#pragma once + +#include +#include "VobSubImage.h" +#include "../SubPic/SubPicProviderImpl.h" + +#define VOBSUBIDXVER 7 + +#define ReadBEb(var) \ + f.Read(&((BYTE*)&var)[0], 1); + +#define ReadBEw(var) \ + f.Read(&((BYTE*)&var)[1], 1); \ + f.Read(&((BYTE*)&var)[0], 1); + +#define ReadBEdw(var) \ + f.Read(&((BYTE*)&var)[3], 1); \ + f.Read(&((BYTE*)&var)[2], 1); \ + f.Read(&((BYTE*)&var)[1], 1); \ + f.Read(&((BYTE*)&var)[0], 1); + +extern CString FindLangFromId(WORD id); + +class CVobSubSettings +{ +protected: + HRESULT Render(SubPicDesc& spd, RECT& bbox); + +public: + CSize m_size; + int m_x, m_y; + CPoint m_org; + int m_scale_x, m_scale_y; // % (don't set it to unsigned because as a side effect it will mess up negative coordinates in GetDestrect()) + int m_alpha; // % + int m_iSmooth; // 0: OFF, 1: ON, 2: OLD (means no filtering at all) + int m_fadein, m_fadeout; // ms + bool m_bAlign; + int m_alignhor, m_alignver; // 0: left/top, 1: center, 2: right/bottom + unsigned int m_toff; // ms + bool m_bOnlyShowForcedSubs; + bool m_bCustomPal; + int m_tridx; + RGBQUAD m_orgpal[16], m_cuspal[4]; + + CVobSubImage m_img; + + CVobSubSettings() { InitSettings(); } + void InitSettings(); + + bool GetCustomPal(RGBQUAD* cuspal, int& tridx); + void SetCustomPal(const RGBQUAD* cuspal, int tridx); + + void GetDestrect(CRect& r); // destrect of m_img, considering the current alignment mode + void GetDestrect(CRect& r, int w, int h); // this will scale it to the frame size of (w, h) + + void SetAlignment(bool bAlign, int x, int y, int hor = 1, int ver = 1); +}; + +class __declspec(uuid("998D4C9A-460F-4de6-BDCD-35AB24F94ADF")) + CVobSubFile : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl +{ +public: + struct SubPos { + __int64 filepos = 0i64; + __int64 start = 0i64; + __int64 stop = 0i64; + bool bForced = false; + bool bAnimated = false; + char vobid = 0; + char cellid = 0; + __int64 celltimestamp = 0i64; + bool bValid = false; + + bool operator <(const SubPos& rhs) const { + return start < rhs.start; + } + }; + + struct SubLang { + WORD id = 0; + CString name, alt; + CAtlArray subpos; + }; + +protected: + CString m_title; + CString m_path; + + void TrimExtension(CString& fn); + bool ReadIdx(CString fn, int& ver), ReadSub(CString fn), ReadRar(CString fn), ReadIfo(CString fn); + bool WriteIdx(CString fn, int delay), WriteSub(CString fn); + + CMemFile m_sub; + + BYTE* GetPacket(size_t idx, size_t& packetSize, size_t& dataSize, size_t nLang = SIZE_T_ERROR); + const SubPos* GetFrameInfo(size_t idx, size_t nLang = SIZE_T_ERROR) const; + bool GetFrame(size_t idx, size_t nLang = SIZE_T_ERROR, REFERENCE_TIME rt = -1); + bool GetFrameByTimeStamp(__int64 time); + size_t GetFrameIdxByTimeStamp(__int64 time); + + bool SaveVobSub(CString fn, int delay); + bool SaveWinSubMux(CString fn, int delay); + bool SaveScenarist(CString fn, int delay); + bool SaveMaestro(CString fn, int delay); + +public: + size_t m_nLang; + std::array m_langs; + + CVobSubFile(CCritSec* pLock); + virtual ~CVobSubFile(); + + bool Copy(CVobSubFile& vsf); + CString GetPath(); + + enum SubFormat { + None, + VobSub, + WinSubMux, + Scenarist, + Maestro + }; + + bool Open(CString fn); + bool Save(CString fn, int delay = 0, SubFormat sf = VobSub); + void Close(); + + CString GetTitle() { return m_title; } + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); + + // IPersist + STDMETHODIMP GetClassID(CLSID* pClassID); + + // ISubStream + STDMETHODIMP_(int) GetStreamCount(); + STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); + STDMETHODIMP_(int) GetStream(); + STDMETHODIMP SetStream(int iStream); + STDMETHODIMP Reload(); + STDMETHODIMP SetSourceTargetInfo(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) { return E_NOTIMPL; }; +}; + +class __declspec(uuid("D7FBFB45-2D13-494F-9B3D-FFC9557D5C45")) + CVobSubStream : public CVobSubSettings, public ISubStream, public CSubPicProviderImpl +{ + CString m_name; + + CCritSec m_csSubPics; + struct SubPic { + REFERENCE_TIME tStart, tStop; + bool bAnimated; + CAtlArray pData; + }; + CAutoPtrList m_subpics; + +public: + CVobSubStream(CCritSec* pLock); + virtual ~CVobSubStream(); + + void Open(CString name, BYTE* pData, int len); + + void Add(REFERENCE_TIME tStart, REFERENCE_TIME tStop, BYTE* pData, int len); + void RemoveAll(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicProvider + STDMETHODIMP_(POSITION) GetStartPosition(REFERENCE_TIME rt, double fps); + STDMETHODIMP_(POSITION) GetNext(POSITION pos); + STDMETHODIMP_(REFERENCE_TIME) GetStart(POSITION pos, double fps); + STDMETHODIMP_(REFERENCE_TIME) GetStop(POSITION pos, double fps); + STDMETHODIMP_(bool) IsAnimated(POSITION pos); + STDMETHODIMP Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox); + STDMETHODIMP GetRelativeTo(POSITION pos, RelativeTo& relativeTo); + + // IPersist + STDMETHODIMP GetClassID(CLSID* pClassID); + + // ISubStream + STDMETHODIMP_(int) GetStreamCount(); + STDMETHODIMP GetStreamInfo(int i, WCHAR** ppName, LCID* pLCID); + STDMETHODIMP_(int) GetStream(); + STDMETHODIMP SetStream(int iStream); + STDMETHODIMP Reload() { return E_NOTIMPL; } + STDMETHODIMP SetSourceTargetInfo(CString yuvMatrix, int targetBlackLevel, int targetWhiteLevel) { return E_NOTIMPL; } +}; diff --git a/src/Subtitles/VobSubFileRipper.cpp b/src/Subtitles/VobSubFileRipper.cpp index 4ee4a837ce7..160670b3cda 100644 --- a/src/Subtitles/VobSubFileRipper.cpp +++ b/src/Subtitles/VobSubFileRipper.cpp @@ -1,1184 +1,1184 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "VobSubFile.h" -#include "VobSubFileRipper.h" -#include "../DeCSS/VobDec.h" -#include "CCDecoder.h" - -// -// CVobSubFileRipper -// - -CVobSubFileRipper::CVobSubFileRipper() - : CVobSubFile(nullptr) - , m_bThreadActive(false) - , m_bBreakThread(false) - , m_bIndexing(false) -{ - m_rd.Reset(); - CAMThread::Create(); -} - -CVobSubFileRipper::~CVobSubFileRipper() -{ - CAMThread::CallWorker(CMD_EXIT); - CAMThread::Close(); -} - -STDMETHODIMP CVobSubFileRipper::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IVSFRipper) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CVobSubFileRipper::Log(log_t type, LPCTSTR lpszFormat, ...) -{ - CAutoLock cAutoLock(&m_csCallback); - if (!m_pCallback) { - return; - } - - TCHAR buff[1024]; - - va_list args; - va_start(args, lpszFormat); - _vstprintf_s(buff, _countof(buff), lpszFormat, args); - va_end(args); - - CString msg; - switch (type) { - default: - case LOG_INFO: - msg = _T(""); - break; - case LOG_WARNING: - msg = _T("WARNING: "); - break; - case LOG_ERROR: - msg = _T("ERROR: "); - break; - } - - msg += buff; - - m_pCallback->OnMessage(msg); -} - -void CVobSubFileRipper::Progress(double progress) -{ - CAutoLock cAutoLock(&m_csCallback); - if (!m_pCallback) { - return; - } - - m_pCallback->OnProgress(progress); -} - -void CVobSubFileRipper::Finished(bool bSucceeded) -{ - CAutoLock cAutoLock(&m_csCallback); - if (!m_pCallback) { - return; - } - - m_pCallback->OnFinished(bSucceeded); -} - -bool CVobSubFileRipper::LoadIfo(CString fn) -{ - CFileStatus status; - if (!CFileGetStatus(fn, status) || !status.m_size) { - Log(LOG_ERROR, _T("Invalid ifo")); - return false; - } - - CFile f; - if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - Log(LOG_ERROR, _T("Cannot open ifo")); - return false; - } - - Log(LOG_INFO, _T("Opening ifo OK")); - - char hdr[13]; - f.Read(hdr, 12); - hdr[12] = 0; - if (strcmp(hdr, "DVDVIDEO-VTS")) { - Log(LOG_ERROR, _T("Not a Video Title Set IFO file!")); - return false; - } - - // lang ids - - f.Seek(0x254, CFile::begin); - - WORD ids[32]; - ZeroMemory(ids, sizeof(ids)); - - int len = 0; - ReadBEw(len); - - for (ptrdiff_t i = 0; i < len; i++) { - f.Seek(2, CFile::current); // 01 00 ? - ReadBEw(ids[i]); - if (ids[i] == 0) { - ids[i] = '--'; - } - f.Seek(2, CFile::current); // 00 00 ? - } - - /* Video info */ - - f.Seek(0x200, CFile::begin); - f.Read(&m_rd.vidinfo, 2); - - SIZE res[4][2] = { - {{720, 480}, {720, 576}}, - {{704, 480}, {704, 576}}, - {{352, 480}, {352, 576}}, - {{352, 240}, {352, 288}} - }; - - m_rd.vidsize = res[m_rd.vidinfo.source_res][m_rd.vidinfo.system & 1]; - - double rate = (m_rd.vidinfo.system == 0) ? 30.0 / 29.97 : 1.0; - - /* PGCs */ - - { - DWORD offset; - - DWORD pgcpos; - f.Seek(0xc0 + 0x0c, CFile::begin); - ReadBEdw(pgcpos); - pgcpos *= 0x800; - - WORD nPGC; - f.Seek(pgcpos, CFile::begin); - ReadBEw(nPGC); - - m_rd.pgcs.RemoveAll(); - m_rd.pgcs.SetCount(nPGC); - - for (size_t i = 0; i < nPGC; i++) { - PGC& pgc = m_rd.pgcs[i]; - - f.Seek(pgcpos + 8 + i * 8 + 4, CFile::begin); - ReadBEdw(offset); - offset += pgcpos; - - BYTE nProgs, nCells; - f.Seek(offset + 2, CFile::begin); - ReadBEb(nProgs); - ReadBEb(nCells); - - // - - memcpy(pgc.ids, ids, sizeof(ids)); - - struct splanginfo { - BYTE res1, id1, id2, res2; - }; - splanginfo splinfo[32]; - - f.Seek(offset + 0x1c, CFile::begin); - f.Read(splinfo, 32 * 4); - - for (size_t j = 0; j < 32; j++) { - if (splinfo[j].id1 || splinfo[i].id2) { - - for (j = 0; j < 32; j++) { - if (!(splinfo[j].res1 & 0x80)) { - break; - } - - pgc.ids[splinfo[j].id1] = ids[j]; - pgc.ids[splinfo[j].id2] = ids[j]; - } - - break; - } - } - - // - - f.Seek(offset + 0xa4, CFile::begin); - - for (size_t j = 0; j < 16; j++) { - BYTE y, u, v, tmp; - - f.Read(&tmp, 1); - f.Read(&y, 1); - f.Read(&u, 1); - f.Read(&v, 1); - - y = (y - 16) * 255 / 219; - - pgc.pal[j].rgbRed = std::min(std::max(BYTE(1.0 * y + 1.4022 * (u - 128)), 0u), 255u); - pgc.pal[j].rgbGreen = std::min(std::max(BYTE(1.0 * y - 0.3456 * (u - 128) - 0.7145 * (v - 128)), 0u), 255u); - pgc.pal[j].rgbBlue = std::min(std::max(BYTE(1.0 * y + 1.7710 * (v - 128)), 0u), 255u); - } - - // - - WORD progoff, celladdroff, vobcelloff; - f.Seek(offset + 0xe6, CFile::begin); - ReadBEw(progoff); - f.Seek(offset + 0xe8, CFile::begin); - ReadBEw(celladdroff); - f.Seek(offset + 0xea, CFile::begin); - ReadBEw(vobcelloff); - - // - - CAtlArray progs; - progs.SetCount(nProgs); - f.Seek(offset + progoff, CFile::begin); - f.Read(progs.GetData(), nProgs); - - // - - pgc.angles[0].SetCount(nCells); - pgc.iSelAngle = 0; - - // - - f.Seek(offset + vobcelloff, CFile::begin); - for (size_t j = 0; j < nCells; j++) { - ReadBEw(pgc.angles[0][j].vob); - ReadBEw(pgc.angles[0][j].cell); - } - - // - - DWORD tOffset = 0, tTotal = 0; - - int iAngle = 0; - - pgc.nAngles = 0; - - f.Seek(offset + celladdroff, CFile::begin); - for (size_t j = 0; j < nCells; j++) { - BYTE b; - ReadBEb(b); - switch (b >> 6) { - case 0: - iAngle = 0; - break; // normal - case 1: - iAngle = 1; - break; // first angle block - case 2: - iAngle++; - break; // middle angle block - case 3: - iAngle++; - break; // last angle block (no more should follow) - } - pgc.angles[0][j].iAngle = iAngle; - pgc.nAngles = std::max(pgc.nAngles, iAngle); - - f.Seek(3, CFile::current); - ReadBEdw(pgc.angles[0][j].tTime); - ReadBEdw(pgc.angles[0][j].start); - f.Seek(8, CFile::current); - ReadBEdw(pgc.angles[0][j].end); - - float fps; - switch ((pgc.angles[0][j].tTime >> 6) & 0x3) { - default: - case 3: - fps = 30; - break; - case 1: - fps = 25; - break; - } - - int t = pgc.angles[0][j].tTime; - int hh = ((t >> 28) & 0xf) * 10 + ((t >> 24) & 0xf); - int mm = ((t >> 20) & 0xf) * 10 + ((t >> 16) & 0xf); - int ss = ((t >> 12) & 0xf) * 10 + ((t >> 8) & 0xf); - int ms = (int)(1000.0 * (((t >> 4) & 0x3) * 10 + ((t >> 0) & 0xf)) / fps); - pgc.angles[0][j].tTime = (DWORD)((((hh * 60 + mm) * 60 + ss) * 1000 + ms) * rate); - - // time discontinuity - if (b & 0x02) { - tOffset = tTotal; - } - pgc.angles[0][j].bDiscontinuity = !!(b & 0x02); - - pgc.angles[0][j].tTotal = tTotal; - pgc.angles[0][j].tOffset = tOffset; - - tTotal += pgc.angles[0][j].tTime; - } - - for (iAngle = 1; iAngle <= 9; iAngle++) { - tOffset = tTotal = 0; - - for (size_t j = 0, k = 0; j < nCells; j++) { - if (pgc.angles[0][j].iAngle != 0 - && pgc.angles[0][j].iAngle != iAngle) { - continue; - } - - pgc.angles[iAngle].Add(pgc.angles[0][j]); - - if (pgc.angles[iAngle][k].bDiscontinuity) { - tOffset = tTotal; - } - - pgc.angles[iAngle][k].tTotal = tTotal; - pgc.angles[iAngle][k].tOffset = tOffset; - - tTotal += pgc.angles[iAngle][k].tTime; - - k++; - } - } - } - } - - Log(LOG_INFO, _T("Parsing ifo OK")); - - return true; -} - -bool CVobSubFileRipper::LoadVob(CString fn) -{ - Log(LOG_INFO, _T("Searching vobs...")); - - CAtlList vobs; - if (!m_vob.Open(fn, vobs/*m_vobs*/)) { - Log(LOG_ERROR, _T("Cannot open vob sequence")); - return false; - } - - if (vobs.GetCount() <= 0) { - Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn.GetString()); - return false; - } - - POSITION pos = vobs.GetHeadPosition(); - while (pos) { - Log(LOG_INFO, _T("Found ") + vobs.GetNext(pos)); - } - - if (m_vob.IsDVD()) { - Log(LOG_INFO, _T("DVD detected...")); - - BYTE key[5]; - - if (m_vob.HasDiscKey(key)) { - Log(LOG_INFO, _T("Disc key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); - } else { - Log(LOG_WARNING, _T("Couldn't get the disc key")); - } - - if (m_vob.HasTitleKey(key)) { - Log(LOG_INFO, _T("Title key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); - } else { - Log(LOG_WARNING, _T("Couldn't get the title key")); - } - - BYTE buff[2048]; - - m_vob.Seek(0); - if (!m_vob.Read(buff)) { - Log(LOG_ERROR, _T("Can't read vob, please unlock it with a software player!")); - return false; - } - m_vob.Seek(0); - } - - return true; -} - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CVobSubFileRipper::ThreadProc() -{ - SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL); - - for (;;) { - DWORD cmd = GetRequest(); - - m_bThreadActive = true; - - switch (cmd) { - case CMD_EXIT: - Reply(S_OK); - return 0; - - case CMD_INDEX: - Reply(S_OK); - { - m_bIndexing = true; - bool bSucceeded = Create(); - m_bIndexing = false; - Finished(bSucceeded); - } - break; - - default: - Reply((DWORD)E_FAIL); - return DWORD_ERROR; - } - - m_bBreakThread = false; - m_bThreadActive = false; - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -bool CVobSubFileRipper::Create() -{ - CAutoLock cAutoLock(&m_csAccessLock); - - if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { - Log(LOG_ERROR, _T("Invalid program chain number (%d)!"), m_rd.iSelPGC); - return false; - } - - PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; - - if (pgc.iSelAngle < 0 || pgc.iSelAngle > 9 || pgc.angles[pgc.iSelAngle].IsEmpty()) { - Log(LOG_ERROR, _T("Invalid angle number (%d)!"), pgc.iSelAngle); - return false; - } - - CAtlArray& angle = pgc.angles[pgc.iSelAngle]; - - if (m_rd.selids.IsEmpty() && !m_rd.bClosedCaption) { - Log(LOG_ERROR, _T("No valid stream set to be extacted!")); - return false; - } - - if (m_rd.selvcs.IsEmpty()) { - Log(LOG_ERROR, _T("No valid vob/cell id set to be extacted!")); - return false; - } - - Log(LOG_INFO, _T("Indexing...")); - - // initalize CVobSubFile - CVobSubFile::Close(); - InitSettings(); - m_title = m_outfn; - m_size = m_rd.vidsize; - TrimExtension(m_title); - memcpy(m_orgpal, pgc.pal, sizeof(m_orgpal)); - m_sub.SetLength(0); - - CCDecoder ccdec(m_title + _T(".cc.srt"), m_title + _T(".cc.raw")); - - CVobDec vd; - - __int64 PTS = 0, tOffset = 0, tPrevOffset = 0, tTotal = 0, tStart = 0; - int vob = 0, cell = 0; - bool bDiscontinuity = false, bDiscontinuityFixApplied = false, bNavpackFound = false; - - int PTSframeoffset = 0, minPTSframeoffset = 0; - - if (m_rd.bResetTime) { - for (size_t i = 0; i < angle.GetCount() && (UINT)((angle[i].vob << 16) | angle[i].cell) != m_rd.selvcs[0]; i++) { - tStart += angle[i].tTime; - } - - Log(LOG_INFO, _T("Counting timestamps from %I64dms (v%02dc%02d)"), - tStart, m_rd.selvcs[0] >> 16, m_rd.selvcs[0] & 0xffff); - } - - CAtlMap selvcmap; - selvcmap.RemoveAll(); - for (size_t i = 0; i < m_rd.selvcs.GetCount(); i++) { - selvcmap[m_rd.selvcs[i]] = 90000; - } - - CAtlArray chunks, foundchunks, loadedchunks; - - if (m_vob.IsDVD()) { - Log(LOG_INFO, _T("Indexing mode: DVD")); - - for (size_t i = 0; i < angle.GetCount(); i++) { - DWORD vc = (angle[i].vob << 16) | angle[i].cell; - if (!selvcmap.Lookup(vc)) { - continue; - } - - vcchunk c = {2048i64 * angle[i].start, 2048i64 * angle[i].end + 2048, vc}; - chunks.Add(c); - - Log(LOG_INFO, _T("Adding: 0x%x - 0x%x (lba) for vob %d cell %d"), - angle[i].start, angle[i].end, angle[i].vob, angle[i].cell); - } - } else if (LoadChunks(loadedchunks)) { - Log(LOG_INFO, _T("Indexing mode: File")); - - for (size_t i = 0; i < loadedchunks.GetCount(); i++) { - DWORD vcid = loadedchunks[i].vc; - if (!selvcmap.Lookup(vcid)) { - continue; - } - - chunks.Add(loadedchunks[i]); - } - - Log(LOG_INFO, _T(".chunk file loaded")); - } else { - Log(LOG_INFO, _T("Indexing mode: File")); - - chunks.RemoveAll(); - vcchunk c = {0, 2048i64 * m_vob.GetLength(), 0}; - chunks.Add(c); - } - - __int64 sizedone = 0, sizetotal = 0; - for (size_t i = 0; i < chunks.GetCount(); i++) { - sizetotal += chunks[i].end - chunks[i].start; - } - - for (size_t i = 0; !m_bBreakThread && i < chunks.GetCount(); i++) { - __int64 curpos = chunks[i].start, endpos = chunks[i].end; - - vcchunk curchunk = {curpos, curpos, chunks[i].vc}; - - for (m_vob.Seek((int)(curpos / 2048)); !m_bBreakThread && curpos < endpos; curpos += 2048, sizedone += 2048) { - if (!(curpos & 0x7ffff)) { - Progress(1.0 * sizedone / sizetotal); - } - - static BYTE buff[2048]; - - if (!m_vob.Read(buff)) { - Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); - return false; - } - - curchunk.end = curpos; - - if (buff[0x14] & 0x30) { - if (!vd.m_fFoundKey) { - Log(LOG_INFO, _T("Encrypted sector found, searching key...")); - - __int64 savepos = curpos; - - m_vob.Seek(0); - for (__int64 pos = 0; !m_bBreakThread && pos < endpos; pos += 2048) { - if (!m_vob.Read(buff)) { - Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); - return false; - } - - if (vd.FindKey(buff)) { - break; - } - } - - if (m_bBreakThread) { - break; - } - - if (!vd.m_fFoundKey) { - Log(LOG_ERROR, _T("Key not found, can't decrypt!")); - return false; - } - - Log(LOG_INFO, _T("Key found, continuing extraction...")); - - m_vob.Seek((int)((curpos = savepos) / 2048)); - m_vob.Read(buff); - } - - vd.Decrypt(buff); - } - - if (*((DWORD*)&buff[0]) != 0xba010000) { - Log(LOG_WARNING, _T("Bad sector header at block %08d!"), (int)(curpos / 2048)); - - if (AfxMessageBox(_T("Bad packet header found, do you want to continue?"), MB_YESNO) == IDNO) { - Log(LOG_ERROR, _T("Terminated!")); - return false; - } - } - - /*__int64 SCR = (__int64(buff[0x04] & 0x38) >> 3) << 30 - | __int64(buff[0x04] & 0x03) << 28 - | __int64(buff[0x05]) << 20 - | (__int64(buff[0x06] & 0xf8) >> 3) << 15 - | __int64(buff[0x06] & 0x03) << 13 - | __int64(buff[0x07]) << 5 - | (__int64(buff[0x08] & 0xf8) >> 3) << 0;*/ - - bool hasPTS = false; - - if ((*(DWORD*)&buff[0x0e] == 0xe0010000 || *(DWORD*)&buff[0x0e] == 0xbd010000) - && buff[0x15] & 0x80) { - PTS = (__int64)(buff[0x17] & 0x0e) << 29 // 32-30 (+marker) - | ((__int64)(buff[0x18]) << 22) // 29-22 - | ((__int64)(buff[0x19] & 0xfe) << 14) // 21-15 (+marker) - | ((__int64)(buff[0x1a]) << 7) // 14-07 - | ((__int64)(buff[0x1b]) >> 1); // 06-00 (+marker) - - hasPTS = true; - } - - if (*((DWORD*)&buff[0x0e]) == 0xbb010000) { - bNavpackFound = true; - - if (vob == buff[0x420] && cell == buff[0x422]) { - continue; - } - - vob = buff[0x420]; - cell = buff[0x422]; - - tOffset = tTotal = 0; - - for (size_t j = 0; j < angle.GetCount(); j++) { - if (angle[j].vob == vob && angle[j].cell == cell) { - tPrevOffset = tOffset; - tOffset = (__int64)angle[j].tOffset; - tTotal = (__int64)angle[j].tTotal; - bDiscontinuity = angle[j].bDiscontinuity; - bDiscontinuityFixApplied = false; - break; - } - } - - if (curchunk.vc != (DWORD)((vob << 16) | cell)) { - if (curchunk.vc != 0) { - foundchunks.Add(curchunk); - } - curchunk.start = curchunk.end = curpos; - curchunk.vc = (vob << 16) | cell; - } - - CString str, str2; - str.Format(_T("v%02d c%02d lba%08d"), vob, cell, (int)(curpos / 2048)); - UINT vcid = (vob << 16) | cell; - if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { - str2 = _T(", skipping"); - } else str2.Format(_T(", total=%I64dms, off=%I64dms, corr=%I64dms, discont.:%d"), - tTotal, tOffset, -tStart, (int)bDiscontinuity); - Log(LOG_INFO, str + str2); - } - - DWORD vcid = (vob << 16) | cell; - if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { - continue; - } - - if (hasPTS && bDiscontinuity && !bDiscontinuityFixApplied) { - __int64 tDiff = tOffset - tPrevOffset; - if (tDiff > 0 && tDiff < (PTS / 90 + 1000)) { - CString str; - str.Format(_T("False discontinuity detected, correcting time by %I64dms"), -tDiff); - Log(LOG_INFO, str); - - tStart += tDiff; - } - bDiscontinuityFixApplied = true; - } - - if (*(DWORD*)&buff[0x0e] == 0xe0010000) { - if (bDiscontinuity) { - if (PTS < minPTSframeoffset) { - selvcmap[vcid] = PTSframeoffset = (int)PTS; - } - - bDiscontinuity = false; - } - - if (m_rd.bClosedCaption) { - ccdec.ExtractCC(buff, 2048, tOffset + ((PTS - PTSframeoffset) / 90) - tStart); - } - } else if (*(DWORD*)&buff[0x0e] == 0xbd010000) { - BYTE id = buff[0x17 + buff[0x16]], iLang = id & 0x1f; - - if ((id & 0xe0) == 0x20 && m_rd.selids.Lookup(iLang)) { - if (hasPTS) { - SubPos sb; - sb.filepos = m_sub.GetPosition(); - sb.start = tOffset + ((PTS - PTSframeoffset) / 90) - tStart; - sb.vobid = (char)vob; - sb.cellid = (char)cell; - sb.celltimestamp = tTotal; - sb.bValid = true; - m_langs[iLang].subpos.Add(sb); - } - - m_sub.Write(buff, 2048); - } - } - } - - if (curchunk.vc != (DWORD)((vob << 16) | cell)) { - if (curchunk.vc != 0) { - foundchunks.Add(curchunk); - } - curchunk.start = curchunk.end = curpos; - curchunk.vc = (vob << 16) | cell; - } - } - - if (sizedone < sizetotal) { - Log(LOG_ERROR, _T("Indexing terminated before reaching the end!")); - Progress(0); - return false; - } - - if (!bNavpackFound) { - Log(LOG_ERROR, _T("Could not find any system header start code! (0x000001bb)")); - if (!m_vob.IsDVD()) { - Log(LOG_ERROR, _T("Make sure the ripper doesn't strip these packets.")); - } - Progress(0); - return false; - } - - Log(LOG_INFO, _T("Indexing finished")); - Progress(1); - - for (size_t i = 0; i < m_langs.size(); i++) { - if (m_nLang == SIZE_T_ERROR && !m_langs[i].subpos.IsEmpty()) { - m_nLang = i; - } - m_langs[i].id = pgc.ids[i]; - m_langs[i].name = m_langs[i].alt = FindLangFromId(m_langs[i].id); - - CAtlArray& sp = m_langs[i].subpos; - std::sort(sp.GetData(), sp.GetData() + sp.GetCount()); - - if (m_rd.bForcedOnly) { - Log(LOG_INFO, _T("Searching for forced subs...")); - Progress(0); - - for (size_t j = 0, len = sp.GetCount(); j < len; j++) { - Progress(1.0 * j / len); - - sp[j].bValid = false; - size_t packetSize = 0, dataSize = 0; - if (BYTE* buff = GetPacket(j, packetSize, dataSize, i)) { - m_img.GetPacketInfo(buff, packetSize, dataSize); - sp[j].bValid = m_img.bForced; - delete [] buff; - } - } - - Progress(1); - } - } - - Log(LOG_INFO, _T("Saving files...")); - - if (m_nLang != SIZE_T_ERROR) { - if (!Save(m_title)) { - Log(LOG_ERROR, _T("Could not save output files!")); - return false; - } - } - - Log(LOG_INFO, _T("Subtitles saved")); - - if (!m_vob.IsDVD() && loadedchunks.IsEmpty()) { - if (SaveChunks(foundchunks)) { - Log(LOG_INFO, _T(".chunk file saved")); - } - } - - Log(LOG_INFO, _T("Done!")); - - return true; -} - -static const DWORD s_version = 1; - -bool CVobSubFileRipper::LoadChunks(CAtlArray& chunks) -{ - CFile f; - - CString fn = m_infn; - TrimExtension(fn); - fn += _T(".chunks"); - - DWORD chksum = 0, chunklen, version; - __int64 voblen = 0; - - if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - f.Read(&version, sizeof(version)); - if (version == 1) { - f.Read(&chksum, sizeof(chksum)); - f.Read(&voblen, sizeof(voblen)); - f.Read(&chunklen, sizeof(chunklen)); - chunks.SetCount(chunklen); - f.Read(chunks.GetData(), UINT(sizeof(vcchunk)*chunks.GetCount())); - } - f.Close(); - - if (voblen != m_vob.GetLength()) { - chunks.RemoveAll(); - return false; - } - - if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - DWORD dw, chksum2 = 0; - while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { - chksum2 += dw; - } - f.Close(); - - if (chksum != chksum2) { - chunks.RemoveAll(); - return false; - } - - return true; -} - -bool CVobSubFileRipper::SaveChunks(CAtlArray& chunks) -{ - CFile f; - - CString fn = m_infn; - TrimExtension(fn); - fn += _T(".chunks"); - - DWORD chksum = 0, chunklen = (DWORD)chunks.GetCount(); - __int64 voblen = m_vob.GetLength(); - - if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { - return false; - } - DWORD dw; - while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { - chksum += dw; - } - f.Close(); - - if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { - return false; - } - f.Write(&s_version, sizeof(s_version)); - f.Write(&chksum, sizeof(chksum)); - f.Write(&voblen, sizeof(voblen)); - f.Write(&chunklen, sizeof(chunklen)); - f.Write(chunks.GetData(), sizeof(vcchunk)*chunklen); - f.Close(); - - return true; -} - -// IVSFRipper - -STDMETHODIMP CVobSubFileRipper::SetCallBack(IVSFRipperCallback* pCallback) -{ - CAutoLock cAutoLock(&m_csCallback); - m_pCallback = pCallback; - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::LoadParamFile(CString fn) -{ - CAutoLock cAutoLock(&m_csAccessLock); - - m_rd.Reset(); - - CStdioFile f; - if (!f.Open(fn, CFile::modeRead | CFile::typeText)) { - return E_FAIL; - } - - TCHAR langid[256]; - - enum { - P_INPUT, - P_OUTPUT, - P_PGC, - P_ANGLE, - P_LANGS, - P_OPTIONS - }; - int phase = P_INPUT; - - CString line; - while (f.ReadString(line)) { - if (line.Trim().IsEmpty() || line[0] == '#') { - continue; - } - - if (phase == P_INPUT) { - if (S_OK != SetInput(line)) { - break; - } - phase = P_OUTPUT; - } else if (phase == P_OUTPUT) { - if (S_OK != SetOutput(line)) { - break; - } - phase = P_PGC; - } else if (phase == P_PGC) { - m_rd.iSelPGC = _tcstol(line, nullptr, 10) - 1; - if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { - break; - } - phase = P_ANGLE; - } else if (phase == 3) { - PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; - - pgc.iSelAngle = _tcstol(line, nullptr, 10); - if (pgc.iSelAngle < 0 || pgc.iSelAngle > std::max(1, pgc.nAngles) || pgc.iSelAngle > 9) { - break; - } - - CAtlArray& angle = pgc.angles[pgc.iSelAngle]; - - if (line.Find('v') >= 0) { - int vob = 0, cell = 0; - - line += _T(' '); - - TCHAR* s = (LPTSTR)(LPCTSTR)line; - TCHAR* e = s + line.GetLength(); - while (s < e) { - if (*s == 'v' || s == e - 1) { - s++; - if (vob != 0 && cell == 0) { - for (size_t i = 0; i < angle.GetCount(); i++) { - if (angle[i].vob == vob) { - m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); - } - } - } - - vob = _tcstol(s, &s, 10); - cell = 0; - } else if (*s == 'c' && vob > 0) { - s++; - cell = _tcstol(s, &s, 10); - - for (size_t i = 0; i < angle.GetCount(); i++) { - if (angle[i].vob == vob && angle[i].cell == cell) { - m_rd.selvcs.Add((vob << 16) | cell); - break; - } - } - } else { - s++; - } - } - } else { - for (size_t i = 0; i < angle.GetCount(); i++) { - m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); - } - } - - phase = P_LANGS; - } else if (phase == 4) { - if (!line.CompareNoCase(_T("ALL"))) { - for (BYTE i = 0; i < 32; i++) { - m_rd.selids[i] = true; - } - m_rd.bClosedCaption = true; - phase = P_OPTIONS; - } else { - line += _T(' '); - - while (!line.IsEmpty()) { - int n = line.Find(_T(" ")); - - CString lang = line.Left(n); - - line = line.Mid(n); - line.TrimLeft(); - - n = 0; - if (_istdigit(lang[0])) { - int langnum; - n = _stscanf_s(lang, _T("%d"), &langnum); - if (n != 1) { - break; - } - - m_rd.selids[(BYTE)langnum] = true; - } else if (_istalpha(lang[0])) { - n = _stscanf_s(lang, _T("%s"), langid, UINT(_countof(langid))); - if (n != 1) { - break; - } - - int id = (langid[0] << 8) + langid[1]; - - if (id == 'cc') { - m_rd.bClosedCaption = true; - } else { - ASSERT(id <= BYTE_MAX); - m_rd.selids[(BYTE)id] = true; - } - } else { - break; - } - } - - if ((!m_rd.selids.IsEmpty() || m_rd.bClosedCaption) && line.IsEmpty()) { - phase = P_OPTIONS; - } - } - } else if (phase == 5 && !line.CompareNoCase(_T("CLOSE"))) { - m_rd.bClose = true; - } else if (phase == 5 && !line.CompareNoCase(_T("BEEP"))) { - m_rd.bBeep = true; - } else if (phase == 5 && !line.CompareNoCase(_T("RESETTIME"))) { - m_rd.bResetTime = true; - } else if (phase == 5 && !line.CompareNoCase(_T("FORCEDONLY"))) { - m_rd.bForcedOnly = true; - } else if (phase == 5 && !line.CompareNoCase(_T("CLOSEIGNOREERRORS"))) { - m_rd.bCloseIgnoreError = true; - } - - } - - m_rd.bAuto = true; - - return phase == P_OPTIONS ? S_OK : E_FAIL; -} - -STDMETHODIMP CVobSubFileRipper::SetInput(CString infn) -{ - CAutoLock cAutoLock(&m_csAccessLock); - - m_rd.Reset(); - - if (!LoadIfo(infn) || !LoadVob(infn)) { - return E_INVALIDARG; - } - - m_infn = infn; - - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::SetOutput(CString outfn) -{ - CAutoLock cAutoLock(&m_csAccessLock); - m_outfn = outfn; - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::GetRipperData(VSFRipperData& rd) -{ - CAutoLock cAutoLock(&m_csAccessLock); - rd.Copy(m_rd); - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::UpdateRipperData(VSFRipperData& rd) -{ - CAutoLock cAutoLock(&m_csAccessLock); - m_rd.Copy(rd); - return S_OK; -} - -STDMETHODIMP CVobSubFileRipper::Index() -{ - if (m_bIndexing) { - return E_FAIL; - } - CAMThread::CallWorker(CMD_INDEX); - return S_OK; -} - - -STDMETHODIMP CVobSubFileRipper::IsIndexing() -{ - return m_bIndexing ? S_OK : S_FALSE; -} - -STDMETHODIMP CVobSubFileRipper::Abort(bool bSavePartial) -{ - m_bBreakThread = true; - return S_OK; -} - -// - -void VSFRipperData::Reset() -{ - vidsize.SetSize(0, 0); - ZeroMemory(&vidinfo, sizeof(vidinfo)); - pgcs.RemoveAll(); - iSelPGC = -1; - bResetTime = bClosedCaption = true; - bForcedOnly = false; - bClose = bBeep = bAuto = false; - bCloseIgnoreError = false; - - selvcs.RemoveAll(); - selids.RemoveAll(); -} - -void VSFRipperData::Copy(VSFRipperData& rd) -{ - Reset(); - - vidsize = rd.vidsize; - vidinfo = rd.vidinfo; - if (size_t len = rd.pgcs.GetCount()) { - pgcs.SetCount(len); - for (size_t i = 0; i < len; i++) { - PGC& src = rd.pgcs[i]; - PGC& dst = pgcs[i]; - dst.nAngles = src.nAngles; - for (size_t j = 0; j < _countof(dst.angles); j++) { - dst.angles[j].Copy(src.angles[j]); - } - dst.iSelAngle = src.iSelAngle; - memcpy(dst.pal, src.pal, sizeof(src.pal)); - memcpy(dst.ids, src.ids, sizeof(src.ids)); - } - } - iSelPGC = rd.iSelPGC; - bResetTime = rd.bResetTime; - bClosedCaption = rd.bClosedCaption; - bForcedOnly = rd.bForcedOnly; - bClose = rd.bClose; - bBeep = rd.bBeep; - bAuto = rd.bAuto; - bCloseIgnoreError = rd.bCloseIgnoreError; - selvcs.Copy(rd.selvcs); - POSITION pos = rd.selids.GetStartPosition(); - while (pos) { - BYTE key; - bool val; - rd.selids.GetNextAssoc(pos, key, val); - selids[key] = val; - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "VobSubFile.h" +#include "VobSubFileRipper.h" +#include "../DeCSS/VobDec.h" +#include "CCDecoder.h" + +// +// CVobSubFileRipper +// + +CVobSubFileRipper::CVobSubFileRipper() + : CVobSubFile(nullptr) + , m_bThreadActive(false) + , m_bBreakThread(false) + , m_bIndexing(false) +{ + m_rd.Reset(); + CAMThread::Create(); +} + +CVobSubFileRipper::~CVobSubFileRipper() +{ + CAMThread::CallWorker(CMD_EXIT); + CAMThread::Close(); +} + +STDMETHODIMP CVobSubFileRipper::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IVSFRipper) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CVobSubFileRipper::Log(log_t type, LPCTSTR lpszFormat, ...) +{ + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } + + TCHAR buff[1024]; + + va_list args; + va_start(args, lpszFormat); + _vstprintf_s(buff, _countof(buff), lpszFormat, args); + va_end(args); + + CString msg; + switch (type) { + default: + case LOG_INFO: + msg = _T(""); + break; + case LOG_WARNING: + msg = _T("WARNING: "); + break; + case LOG_ERROR: + msg = _T("ERROR: "); + break; + } + + msg += buff; + + m_pCallback->OnMessage(msg); +} + +void CVobSubFileRipper::Progress(double progress) +{ + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } + + m_pCallback->OnProgress(progress); +} + +void CVobSubFileRipper::Finished(bool bSucceeded) +{ + CAutoLock cAutoLock(&m_csCallback); + if (!m_pCallback) { + return; + } + + m_pCallback->OnFinished(bSucceeded); +} + +bool CVobSubFileRipper::LoadIfo(CString fn) +{ + CFileStatus status; + if (!CFileGetStatus(fn, status) || !status.m_size) { + Log(LOG_ERROR, _T("Invalid ifo")); + return false; + } + + CFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + Log(LOG_ERROR, _T("Cannot open ifo")); + return false; + } + + Log(LOG_INFO, _T("Opening ifo OK")); + + char hdr[13]; + f.Read(hdr, 12); + hdr[12] = 0; + if (strcmp(hdr, "DVDVIDEO-VTS")) { + Log(LOG_ERROR, _T("Not a Video Title Set IFO file!")); + return false; + } + + // lang ids + + f.Seek(0x254, CFile::begin); + + WORD ids[32]; + ZeroMemory(ids, sizeof(ids)); + + int len = 0; + ReadBEw(len); + + for (ptrdiff_t i = 0; i < len; i++) { + f.Seek(2, CFile::current); // 01 00 ? + ReadBEw(ids[i]); + if (ids[i] == 0) { + ids[i] = '--'; + } + f.Seek(2, CFile::current); // 00 00 ? + } + + /* Video info */ + + f.Seek(0x200, CFile::begin); + f.Read(&m_rd.vidinfo, 2); + + SIZE res[4][2] = { + {{720, 480}, {720, 576}}, + {{704, 480}, {704, 576}}, + {{352, 480}, {352, 576}}, + {{352, 240}, {352, 288}} + }; + + m_rd.vidsize = res[m_rd.vidinfo.source_res][m_rd.vidinfo.system & 1]; + + double rate = (m_rd.vidinfo.system == 0) ? 30.0 / 29.97 : 1.0; + + /* PGCs */ + + { + DWORD offset; + + DWORD pgcpos; + f.Seek(0xc0 + 0x0c, CFile::begin); + ReadBEdw(pgcpos); + pgcpos *= 0x800; + + WORD nPGC; + f.Seek(pgcpos, CFile::begin); + ReadBEw(nPGC); + + m_rd.pgcs.RemoveAll(); + m_rd.pgcs.SetCount(nPGC); + + for (size_t i = 0; i < nPGC; i++) { + PGC& pgc = m_rd.pgcs[i]; + + f.Seek(pgcpos + 8 + i * 8 + 4, CFile::begin); + ReadBEdw(offset); + offset += pgcpos; + + BYTE nProgs, nCells; + f.Seek(offset + 2, CFile::begin); + ReadBEb(nProgs); + ReadBEb(nCells); + + // + + memcpy(pgc.ids, ids, sizeof(ids)); + + struct splanginfo { + BYTE res1, id1, id2, res2; + }; + splanginfo splinfo[32]; + + f.Seek(offset + 0x1c, CFile::begin); + f.Read(splinfo, 32 * 4); + + for (size_t j = 0; j < 32; j++) { + if (splinfo[j].id1 || splinfo[i].id2) { + + for (j = 0; j < 32; j++) { + if (!(splinfo[j].res1 & 0x80)) { + break; + } + + pgc.ids[splinfo[j].id1] = ids[j]; + pgc.ids[splinfo[j].id2] = ids[j]; + } + + break; + } + } + + // + + f.Seek(offset + 0xa4, CFile::begin); + + for (size_t j = 0; j < 16; j++) { + BYTE y, u, v, tmp; + + f.Read(&tmp, 1); + f.Read(&y, 1); + f.Read(&u, 1); + f.Read(&v, 1); + + y = (y - 16) * 255 / 219; + + pgc.pal[j].rgbRed = std::min(std::max(BYTE(1.0 * y + 1.4022 * (u - 128)), 0u), 255u); + pgc.pal[j].rgbGreen = std::min(std::max(BYTE(1.0 * y - 0.3456 * (u - 128) - 0.7145 * (v - 128)), 0u), 255u); + pgc.pal[j].rgbBlue = std::min(std::max(BYTE(1.0 * y + 1.7710 * (v - 128)), 0u), 255u); + } + + // + + WORD progoff, celladdroff, vobcelloff; + f.Seek(offset + 0xe6, CFile::begin); + ReadBEw(progoff); + f.Seek(offset + 0xe8, CFile::begin); + ReadBEw(celladdroff); + f.Seek(offset + 0xea, CFile::begin); + ReadBEw(vobcelloff); + + // + + CAtlArray progs; + progs.SetCount(nProgs); + f.Seek(offset + progoff, CFile::begin); + f.Read(progs.GetData(), nProgs); + + // + + pgc.angles[0].SetCount(nCells); + pgc.iSelAngle = 0; + + // + + f.Seek(offset + vobcelloff, CFile::begin); + for (size_t j = 0; j < nCells; j++) { + ReadBEw(pgc.angles[0][j].vob); + ReadBEw(pgc.angles[0][j].cell); + } + + // + + DWORD tOffset = 0, tTotal = 0; + + int iAngle = 0; + + pgc.nAngles = 0; + + f.Seek(offset + celladdroff, CFile::begin); + for (size_t j = 0; j < nCells; j++) { + BYTE b; + ReadBEb(b); + switch (b >> 6) { + case 0: + iAngle = 0; + break; // normal + case 1: + iAngle = 1; + break; // first angle block + case 2: + iAngle++; + break; // middle angle block + case 3: + iAngle++; + break; // last angle block (no more should follow) + } + pgc.angles[0][j].iAngle = iAngle; + pgc.nAngles = std::max(pgc.nAngles, iAngle); + + f.Seek(3, CFile::current); + ReadBEdw(pgc.angles[0][j].tTime); + ReadBEdw(pgc.angles[0][j].start); + f.Seek(8, CFile::current); + ReadBEdw(pgc.angles[0][j].end); + + float fps; + switch ((pgc.angles[0][j].tTime >> 6) & 0x3) { + default: + case 3: + fps = 30; + break; + case 1: + fps = 25; + break; + } + + int t = pgc.angles[0][j].tTime; + int hh = ((t >> 28) & 0xf) * 10 + ((t >> 24) & 0xf); + int mm = ((t >> 20) & 0xf) * 10 + ((t >> 16) & 0xf); + int ss = ((t >> 12) & 0xf) * 10 + ((t >> 8) & 0xf); + int ms = (int)(1000.0 * (((t >> 4) & 0x3) * 10 + ((t >> 0) & 0xf)) / fps); + pgc.angles[0][j].tTime = (DWORD)((((hh * 60 + mm) * 60 + ss) * 1000 + ms) * rate); + + // time discontinuity + if (b & 0x02) { + tOffset = tTotal; + } + pgc.angles[0][j].bDiscontinuity = !!(b & 0x02); + + pgc.angles[0][j].tTotal = tTotal; + pgc.angles[0][j].tOffset = tOffset; + + tTotal += pgc.angles[0][j].tTime; + } + + for (iAngle = 1; iAngle <= 9; iAngle++) { + tOffset = tTotal = 0; + + for (size_t j = 0, k = 0; j < nCells; j++) { + if (pgc.angles[0][j].iAngle != 0 + && pgc.angles[0][j].iAngle != iAngle) { + continue; + } + + pgc.angles[iAngle].Add(pgc.angles[0][j]); + + if (pgc.angles[iAngle][k].bDiscontinuity) { + tOffset = tTotal; + } + + pgc.angles[iAngle][k].tTotal = tTotal; + pgc.angles[iAngle][k].tOffset = tOffset; + + tTotal += pgc.angles[iAngle][k].tTime; + + k++; + } + } + } + } + + Log(LOG_INFO, _T("Parsing ifo OK")); + + return true; +} + +bool CVobSubFileRipper::LoadVob(CString fn) +{ + Log(LOG_INFO, _T("Searching vobs...")); + + CAtlList vobs; + if (!m_vob.Open(fn, vobs/*m_vobs*/)) { + Log(LOG_ERROR, _T("Cannot open vob sequence")); + return false; + } + + if (vobs.GetCount() <= 0) { + Log(LOG_ERROR, _T("Nothing found! (%s*.vob)"), fn.GetString()); + return false; + } + + POSITION pos = vobs.GetHeadPosition(); + while (pos) { + Log(LOG_INFO, _T("Found ") + vobs.GetNext(pos)); + } + + if (m_vob.IsDVD()) { + Log(LOG_INFO, _T("DVD detected...")); + + BYTE key[5]; + + if (m_vob.HasDiscKey(key)) { + Log(LOG_INFO, _T("Disc key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); + } else { + Log(LOG_WARNING, _T("Couldn't get the disc key")); + } + + if (m_vob.HasTitleKey(key)) { + Log(LOG_INFO, _T("Title key: %02x%02x%02x%02x%02x"), key[0], key[1], key[2], key[3], key[4]); + } else { + Log(LOG_WARNING, _T("Couldn't get the title key")); + } + + BYTE buff[2048]; + + m_vob.Seek(0); + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Can't read vob, please unlock it with a software player!")); + return false; + } + m_vob.Seek(0); + } + + return true; +} + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CVobSubFileRipper::ThreadProc() +{ + SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL); + + for (;;) { + DWORD cmd = GetRequest(); + + m_bThreadActive = true; + + switch (cmd) { + case CMD_EXIT: + Reply(S_OK); + return 0; + + case CMD_INDEX: + Reply(S_OK); + { + m_bIndexing = true; + bool bSucceeded = Create(); + m_bIndexing = false; + Finished(bSucceeded); + } + break; + + default: + Reply((DWORD)E_FAIL); + return DWORD_ERROR; + } + + m_bBreakThread = false; + m_bThreadActive = false; + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +bool CVobSubFileRipper::Create() +{ + CAutoLock cAutoLock(&m_csAccessLock); + + if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { + Log(LOG_ERROR, _T("Invalid program chain number (%d)!"), m_rd.iSelPGC); + return false; + } + + PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; + + if (pgc.iSelAngle < 0 || pgc.iSelAngle > 9 || pgc.angles[pgc.iSelAngle].IsEmpty()) { + Log(LOG_ERROR, _T("Invalid angle number (%d)!"), pgc.iSelAngle); + return false; + } + + CAtlArray& angle = pgc.angles[pgc.iSelAngle]; + + if (m_rd.selids.IsEmpty() && !m_rd.bClosedCaption) { + Log(LOG_ERROR, _T("No valid stream set to be extacted!")); + return false; + } + + if (m_rd.selvcs.IsEmpty()) { + Log(LOG_ERROR, _T("No valid vob/cell id set to be extacted!")); + return false; + } + + Log(LOG_INFO, _T("Indexing...")); + + // initalize CVobSubFile + CVobSubFile::Close(); + InitSettings(); + m_title = m_outfn; + m_size = m_rd.vidsize; + TrimExtension(m_title); + memcpy(m_orgpal, pgc.pal, sizeof(m_orgpal)); + m_sub.SetLength(0); + + CCDecoder ccdec(m_title + _T(".cc.srt"), m_title + _T(".cc.raw")); + + CVobDec vd; + + __int64 PTS = 0, tOffset = 0, tPrevOffset = 0, tTotal = 0, tStart = 0; + int vob = 0, cell = 0; + bool bDiscontinuity = false, bDiscontinuityFixApplied = false, bNavpackFound = false; + + int PTSframeoffset = 0, minPTSframeoffset = 0; + + if (m_rd.bResetTime) { + for (size_t i = 0; i < angle.GetCount() && (UINT)((angle[i].vob << 16) | angle[i].cell) != m_rd.selvcs[0]; i++) { + tStart += angle[i].tTime; + } + + Log(LOG_INFO, _T("Counting timestamps from %I64dms (v%02dc%02d)"), + tStart, m_rd.selvcs[0] >> 16, m_rd.selvcs[0] & 0xffff); + } + + CAtlMap selvcmap; + selvcmap.RemoveAll(); + for (size_t i = 0; i < m_rd.selvcs.GetCount(); i++) { + selvcmap[m_rd.selvcs[i]] = 90000; + } + + CAtlArray chunks, foundchunks, loadedchunks; + + if (m_vob.IsDVD()) { + Log(LOG_INFO, _T("Indexing mode: DVD")); + + for (size_t i = 0; i < angle.GetCount(); i++) { + DWORD vc = (angle[i].vob << 16) | angle[i].cell; + if (!selvcmap.Lookup(vc)) { + continue; + } + + vcchunk c = {2048i64 * angle[i].start, 2048i64 * angle[i].end + 2048, vc}; + chunks.Add(c); + + Log(LOG_INFO, _T("Adding: 0x%x - 0x%x (lba) for vob %d cell %d"), + angle[i].start, angle[i].end, angle[i].vob, angle[i].cell); + } + } else if (LoadChunks(loadedchunks)) { + Log(LOG_INFO, _T("Indexing mode: File")); + + for (size_t i = 0; i < loadedchunks.GetCount(); i++) { + DWORD vcid = loadedchunks[i].vc; + if (!selvcmap.Lookup(vcid)) { + continue; + } + + chunks.Add(loadedchunks[i]); + } + + Log(LOG_INFO, _T(".chunk file loaded")); + } else { + Log(LOG_INFO, _T("Indexing mode: File")); + + chunks.RemoveAll(); + vcchunk c = {0, 2048i64 * m_vob.GetLength(), 0}; + chunks.Add(c); + } + + __int64 sizedone = 0, sizetotal = 0; + for (size_t i = 0; i < chunks.GetCount(); i++) { + sizetotal += chunks[i].end - chunks[i].start; + } + + for (size_t i = 0; !m_bBreakThread && i < chunks.GetCount(); i++) { + __int64 curpos = chunks[i].start, endpos = chunks[i].end; + + vcchunk curchunk = {curpos, curpos, chunks[i].vc}; + + for (m_vob.Seek((int)(curpos / 2048)); !m_bBreakThread && curpos < endpos; curpos += 2048, sizedone += 2048) { + if (!(curpos & 0x7ffff)) { + Progress(1.0 * sizedone / sizetotal); + } + + static BYTE buff[2048]; + + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); + return false; + } + + curchunk.end = curpos; + + if (buff[0x14] & 0x30) { + if (!vd.m_fFoundKey) { + Log(LOG_INFO, _T("Encrypted sector found, searching key...")); + + __int64 savepos = curpos; + + m_vob.Seek(0); + for (__int64 pos = 0; !m_bBreakThread && pos < endpos; pos += 2048) { + if (!m_vob.Read(buff)) { + Log(LOG_ERROR, _T("Cannot read, either locked dvd or truncated/missing files!")); + return false; + } + + if (vd.FindKey(buff)) { + break; + } + } + + if (m_bBreakThread) { + break; + } + + if (!vd.m_fFoundKey) { + Log(LOG_ERROR, _T("Key not found, can't decrypt!")); + return false; + } + + Log(LOG_INFO, _T("Key found, continuing extraction...")); + + m_vob.Seek((int)((curpos = savepos) / 2048)); + m_vob.Read(buff); + } + + vd.Decrypt(buff); + } + + if (*((DWORD*)&buff[0]) != 0xba010000) { + Log(LOG_WARNING, _T("Bad sector header at block %08d!"), (int)(curpos / 2048)); + + if (AfxMessageBox(_T("Bad packet header found, do you want to continue?"), MB_YESNO) == IDNO) { + Log(LOG_ERROR, _T("Terminated!")); + return false; + } + } + + /*__int64 SCR = (__int64(buff[0x04] & 0x38) >> 3) << 30 + | __int64(buff[0x04] & 0x03) << 28 + | __int64(buff[0x05]) << 20 + | (__int64(buff[0x06] & 0xf8) >> 3) << 15 + | __int64(buff[0x06] & 0x03) << 13 + | __int64(buff[0x07]) << 5 + | (__int64(buff[0x08] & 0xf8) >> 3) << 0;*/ + + bool hasPTS = false; + + if ((*(DWORD*)&buff[0x0e] == 0xe0010000 || *(DWORD*)&buff[0x0e] == 0xbd010000) + && buff[0x15] & 0x80) { + PTS = (__int64)(buff[0x17] & 0x0e) << 29 // 32-30 (+marker) + | ((__int64)(buff[0x18]) << 22) // 29-22 + | ((__int64)(buff[0x19] & 0xfe) << 14) // 21-15 (+marker) + | ((__int64)(buff[0x1a]) << 7) // 14-07 + | ((__int64)(buff[0x1b]) >> 1); // 06-00 (+marker) + + hasPTS = true; + } + + if (*((DWORD*)&buff[0x0e]) == 0xbb010000) { + bNavpackFound = true; + + if (vob == buff[0x420] && cell == buff[0x422]) { + continue; + } + + vob = buff[0x420]; + cell = buff[0x422]; + + tOffset = tTotal = 0; + + for (size_t j = 0; j < angle.GetCount(); j++) { + if (angle[j].vob == vob && angle[j].cell == cell) { + tPrevOffset = tOffset; + tOffset = (__int64)angle[j].tOffset; + tTotal = (__int64)angle[j].tTotal; + bDiscontinuity = angle[j].bDiscontinuity; + bDiscontinuityFixApplied = false; + break; + } + } + + if (curchunk.vc != (DWORD)((vob << 16) | cell)) { + if (curchunk.vc != 0) { + foundchunks.Add(curchunk); + } + curchunk.start = curchunk.end = curpos; + curchunk.vc = (vob << 16) | cell; + } + + CString str, str2; + str.Format(_T("v%02d c%02d lba%08d"), vob, cell, (int)(curpos / 2048)); + UINT vcid = (vob << 16) | cell; + if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { + str2 = _T(", skipping"); + } else str2.Format(_T(", total=%I64dms, off=%I64dms, corr=%I64dms, discont.:%d"), + tTotal, tOffset, -tStart, (int)bDiscontinuity); + Log(LOG_INFO, str + str2); + } + + DWORD vcid = (vob << 16) | cell; + if (!selvcmap.Lookup(vcid, minPTSframeoffset)) { + continue; + } + + if (hasPTS && bDiscontinuity && !bDiscontinuityFixApplied) { + __int64 tDiff = tOffset - tPrevOffset; + if (tDiff > 0 && tDiff < (PTS / 90 + 1000)) { + CString str; + str.Format(_T("False discontinuity detected, correcting time by %I64dms"), -tDiff); + Log(LOG_INFO, str); + + tStart += tDiff; + } + bDiscontinuityFixApplied = true; + } + + if (*(DWORD*)&buff[0x0e] == 0xe0010000) { + if (bDiscontinuity) { + if (PTS < minPTSframeoffset) { + selvcmap[vcid] = PTSframeoffset = (int)PTS; + } + + bDiscontinuity = false; + } + + if (m_rd.bClosedCaption) { + ccdec.ExtractCC(buff, 2048, tOffset + ((PTS - PTSframeoffset) / 90) - tStart); + } + } else if (*(DWORD*)&buff[0x0e] == 0xbd010000) { + BYTE id = buff[0x17 + buff[0x16]], iLang = id & 0x1f; + + if ((id & 0xe0) == 0x20 && m_rd.selids.Lookup(iLang)) { + if (hasPTS) { + SubPos sb; + sb.filepos = m_sub.GetPosition(); + sb.start = tOffset + ((PTS - PTSframeoffset) / 90) - tStart; + sb.vobid = (char)vob; + sb.cellid = (char)cell; + sb.celltimestamp = tTotal; + sb.bValid = true; + m_langs[iLang].subpos.Add(sb); + } + + m_sub.Write(buff, 2048); + } + } + } + + if (curchunk.vc != (DWORD)((vob << 16) | cell)) { + if (curchunk.vc != 0) { + foundchunks.Add(curchunk); + } + curchunk.start = curchunk.end = curpos; + curchunk.vc = (vob << 16) | cell; + } + } + + if (sizedone < sizetotal) { + Log(LOG_ERROR, _T("Indexing terminated before reaching the end!")); + Progress(0); + return false; + } + + if (!bNavpackFound) { + Log(LOG_ERROR, _T("Could not find any system header start code! (0x000001bb)")); + if (!m_vob.IsDVD()) { + Log(LOG_ERROR, _T("Make sure the ripper doesn't strip these packets.")); + } + Progress(0); + return false; + } + + Log(LOG_INFO, _T("Indexing finished")); + Progress(1); + + for (size_t i = 0; i < m_langs.size(); i++) { + if (m_nLang == SIZE_T_ERROR && !m_langs[i].subpos.IsEmpty()) { + m_nLang = i; + } + m_langs[i].id = pgc.ids[i]; + m_langs[i].name = m_langs[i].alt = FindLangFromId(m_langs[i].id); + + CAtlArray& sp = m_langs[i].subpos; + std::sort(sp.GetData(), sp.GetData() + sp.GetCount()); + + if (m_rd.bForcedOnly) { + Log(LOG_INFO, _T("Searching for forced subs...")); + Progress(0); + + for (size_t j = 0, len = sp.GetCount(); j < len; j++) { + Progress(1.0 * j / len); + + sp[j].bValid = false; + size_t packetSize = 0, dataSize = 0; + if (BYTE* buff = GetPacket(j, packetSize, dataSize, i)) { + m_img.GetPacketInfo(buff, packetSize, dataSize); + sp[j].bValid = m_img.bForced; + delete [] buff; + } + } + + Progress(1); + } + } + + Log(LOG_INFO, _T("Saving files...")); + + if (m_nLang != SIZE_T_ERROR) { + if (!Save(m_title)) { + Log(LOG_ERROR, _T("Could not save output files!")); + return false; + } + } + + Log(LOG_INFO, _T("Subtitles saved")); + + if (!m_vob.IsDVD() && loadedchunks.IsEmpty()) { + if (SaveChunks(foundchunks)) { + Log(LOG_INFO, _T(".chunk file saved")); + } + } + + Log(LOG_INFO, _T("Done!")); + + return true; +} + +static const DWORD s_version = 1; + +bool CVobSubFileRipper::LoadChunks(CAtlArray& chunks) +{ + CFile f; + + CString fn = m_infn; + TrimExtension(fn); + fn += _T(".chunks"); + + DWORD chksum = 0, chunklen, version; + __int64 voblen = 0; + + if (!f.Open(fn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + f.Read(&version, sizeof(version)); + if (version == 1) { + f.Read(&chksum, sizeof(chksum)); + f.Read(&voblen, sizeof(voblen)); + f.Read(&chunklen, sizeof(chunklen)); + chunks.SetCount(chunklen); + f.Read(chunks.GetData(), UINT(sizeof(vcchunk)*chunks.GetCount())); + } + f.Close(); + + if (voblen != m_vob.GetLength()) { + chunks.RemoveAll(); + return false; + } + + if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + DWORD dw, chksum2 = 0; + while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { + chksum2 += dw; + } + f.Close(); + + if (chksum != chksum2) { + chunks.RemoveAll(); + return false; + } + + return true; +} + +bool CVobSubFileRipper::SaveChunks(CAtlArray& chunks) +{ + CFile f; + + CString fn = m_infn; + TrimExtension(fn); + fn += _T(".chunks"); + + DWORD chksum = 0, chunklen = (DWORD)chunks.GetCount(); + __int64 voblen = m_vob.GetLength(); + + if (!f.Open(m_infn, CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone)) { + return false; + } + DWORD dw; + while (f.Read(&dw, sizeof(dw)) == sizeof(dw)) { + chksum += dw; + } + f.Close(); + + if (!f.Open(fn, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) { + return false; + } + f.Write(&s_version, sizeof(s_version)); + f.Write(&chksum, sizeof(chksum)); + f.Write(&voblen, sizeof(voblen)); + f.Write(&chunklen, sizeof(chunklen)); + f.Write(chunks.GetData(), sizeof(vcchunk)*chunklen); + f.Close(); + + return true; +} + +// IVSFRipper + +STDMETHODIMP CVobSubFileRipper::SetCallBack(IVSFRipperCallback* pCallback) +{ + CAutoLock cAutoLock(&m_csCallback); + m_pCallback = pCallback; + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::LoadParamFile(CString fn) +{ + CAutoLock cAutoLock(&m_csAccessLock); + + m_rd.Reset(); + + CStdioFile f; + if (!f.Open(fn, CFile::modeRead | CFile::typeText)) { + return E_FAIL; + } + + TCHAR langid[256]; + + enum { + P_INPUT, + P_OUTPUT, + P_PGC, + P_ANGLE, + P_LANGS, + P_OPTIONS + }; + int phase = P_INPUT; + + CString line; + while (f.ReadString(line)) { + if (line.Trim().IsEmpty() || line[0] == '#') { + continue; + } + + if (phase == P_INPUT) { + if (S_OK != SetInput(line)) { + break; + } + phase = P_OUTPUT; + } else if (phase == P_OUTPUT) { + if (S_OK != SetOutput(line)) { + break; + } + phase = P_PGC; + } else if (phase == P_PGC) { + m_rd.iSelPGC = _tcstol(line, nullptr, 10) - 1; + if (m_rd.iSelPGC < 0 || (size_t)m_rd.iSelPGC >= m_rd.pgcs.GetCount()) { + break; + } + phase = P_ANGLE; + } else if (phase == 3) { + PGC& pgc = m_rd.pgcs[m_rd.iSelPGC]; + + pgc.iSelAngle = _tcstol(line, nullptr, 10); + if (pgc.iSelAngle < 0 || pgc.iSelAngle > std::max(1, pgc.nAngles) || pgc.iSelAngle > 9) { + break; + } + + CAtlArray& angle = pgc.angles[pgc.iSelAngle]; + + if (line.Find('v') >= 0) { + int vob = 0, cell = 0; + + line += _T(' '); + + TCHAR* s = (LPTSTR)(LPCTSTR)line; + TCHAR* e = s + line.GetLength(); + while (s < e) { + if (*s == 'v' || s == e - 1) { + s++; + if (vob != 0 && cell == 0) { + for (size_t i = 0; i < angle.GetCount(); i++) { + if (angle[i].vob == vob) { + m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); + } + } + } + + vob = _tcstol(s, &s, 10); + cell = 0; + } else if (*s == 'c' && vob > 0) { + s++; + cell = _tcstol(s, &s, 10); + + for (size_t i = 0; i < angle.GetCount(); i++) { + if (angle[i].vob == vob && angle[i].cell == cell) { + m_rd.selvcs.Add((vob << 16) | cell); + break; + } + } + } else { + s++; + } + } + } else { + for (size_t i = 0; i < angle.GetCount(); i++) { + m_rd.selvcs.Add((angle[i].vob << 16) | angle[i].cell); + } + } + + phase = P_LANGS; + } else if (phase == 4) { + if (!line.CompareNoCase(_T("ALL"))) { + for (BYTE i = 0; i < 32; i++) { + m_rd.selids[i] = true; + } + m_rd.bClosedCaption = true; + phase = P_OPTIONS; + } else { + line += _T(' '); + + while (!line.IsEmpty()) { + int n = line.Find(_T(" ")); + + CString lang = line.Left(n); + + line = line.Mid(n); + line.TrimLeft(); + + n = 0; + if (_istdigit(lang[0])) { + int langnum; + n = _stscanf_s(lang, _T("%d"), &langnum); + if (n != 1) { + break; + } + + m_rd.selids[(BYTE)langnum] = true; + } else if (_istalpha(lang[0])) { + n = _stscanf_s(lang, _T("%s"), langid, UINT(_countof(langid))); + if (n != 1) { + break; + } + + int id = (langid[0] << 8) + langid[1]; + + if (id == 'cc') { + m_rd.bClosedCaption = true; + } else { + ASSERT(id <= BYTE_MAX); + m_rd.selids[(BYTE)id] = true; + } + } else { + break; + } + } + + if ((!m_rd.selids.IsEmpty() || m_rd.bClosedCaption) && line.IsEmpty()) { + phase = P_OPTIONS; + } + } + } else if (phase == 5 && !line.CompareNoCase(_T("CLOSE"))) { + m_rd.bClose = true; + } else if (phase == 5 && !line.CompareNoCase(_T("BEEP"))) { + m_rd.bBeep = true; + } else if (phase == 5 && !line.CompareNoCase(_T("RESETTIME"))) { + m_rd.bResetTime = true; + } else if (phase == 5 && !line.CompareNoCase(_T("FORCEDONLY"))) { + m_rd.bForcedOnly = true; + } else if (phase == 5 && !line.CompareNoCase(_T("CLOSEIGNOREERRORS"))) { + m_rd.bCloseIgnoreError = true; + } + + } + + m_rd.bAuto = true; + + return phase == P_OPTIONS ? S_OK : E_FAIL; +} + +STDMETHODIMP CVobSubFileRipper::SetInput(CString infn) +{ + CAutoLock cAutoLock(&m_csAccessLock); + + m_rd.Reset(); + + if (!LoadIfo(infn) || !LoadVob(infn)) { + return E_INVALIDARG; + } + + m_infn = infn; + + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::SetOutput(CString outfn) +{ + CAutoLock cAutoLock(&m_csAccessLock); + m_outfn = outfn; + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::GetRipperData(VSFRipperData& rd) +{ + CAutoLock cAutoLock(&m_csAccessLock); + rd.Copy(m_rd); + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::UpdateRipperData(VSFRipperData& rd) +{ + CAutoLock cAutoLock(&m_csAccessLock); + m_rd.Copy(rd); + return S_OK; +} + +STDMETHODIMP CVobSubFileRipper::Index() +{ + if (m_bIndexing) { + return E_FAIL; + } + CAMThread::CallWorker(CMD_INDEX); + return S_OK; +} + + +STDMETHODIMP CVobSubFileRipper::IsIndexing() +{ + return m_bIndexing ? S_OK : S_FALSE; +} + +STDMETHODIMP CVobSubFileRipper::Abort(bool bSavePartial) +{ + m_bBreakThread = true; + return S_OK; +} + +// + +void VSFRipperData::Reset() +{ + vidsize.SetSize(0, 0); + ZeroMemory(&vidinfo, sizeof(vidinfo)); + pgcs.RemoveAll(); + iSelPGC = -1; + bResetTime = bClosedCaption = true; + bForcedOnly = false; + bClose = bBeep = bAuto = false; + bCloseIgnoreError = false; + + selvcs.RemoveAll(); + selids.RemoveAll(); +} + +void VSFRipperData::Copy(VSFRipperData& rd) +{ + Reset(); + + vidsize = rd.vidsize; + vidinfo = rd.vidinfo; + if (size_t len = rd.pgcs.GetCount()) { + pgcs.SetCount(len); + for (size_t i = 0; i < len; i++) { + PGC& src = rd.pgcs[i]; + PGC& dst = pgcs[i]; + dst.nAngles = src.nAngles; + for (size_t j = 0; j < _countof(dst.angles); j++) { + dst.angles[j].Copy(src.angles[j]); + } + dst.iSelAngle = src.iSelAngle; + memcpy(dst.pal, src.pal, sizeof(src.pal)); + memcpy(dst.ids, src.ids, sizeof(src.ids)); + } + } + iSelPGC = rd.iSelPGC; + bResetTime = rd.bResetTime; + bClosedCaption = rd.bClosedCaption; + bForcedOnly = rd.bForcedOnly; + bClose = rd.bClose; + bBeep = rd.bBeep; + bAuto = rd.bAuto; + bCloseIgnoreError = rd.bCloseIgnoreError; + selvcs.Copy(rd.selvcs); + POSITION pos = rd.selids.GetStartPosition(); + while (pos) { + BYTE key; + bool val; + rd.selids.GetNextAssoc(pos, key, val); + selids[key] = val; + } +} diff --git a/src/Subtitles/VobSubFileRipper.h b/src/Subtitles/VobSubFileRipper.h index e0122b1e286..20e3050d8c2 100644 --- a/src/Subtitles/VobSubFileRipper.h +++ b/src/Subtitles/VobSubFileRipper.h @@ -1,191 +1,191 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#pragma once - -#include -#include "../DeCSS/VobFile.h" -#include "../DSUtil/DSUtil.h" -#include "VobSubFile.h" - -#pragma pack(push, 1) -struct vidinfo { - WORD perm_displ : 2; - WORD ratio : 2; - WORD system : 2; - WORD compression : 2; - WORD mode : 1; - WORD letterboxed : 1; - WORD source_res : 2; - WORD cbrvbr : 2; - WORD line21_2 : 1; - WORD line21_1 : 1; -}; - -struct vc_t { - BYTE vob, cell; - DWORD tTime, tOffset, tTotal; - DWORD start, end; - int iAngle; - bool bDiscontinuity; -}; - -struct PGC { - int nAngles; - CAtlArray angles[10]; - int iSelAngle; - RGBQUAD pal[16]; - WORD ids[32]; -}; - -struct VSFRipperData { - CSize vidsize; - vidinfo vidinfo; - CAtlArray pgcs; - int iSelPGC; - bool bResetTime, bClosedCaption, bForcedOnly; - - bool bClose, bBeep, bAuto; // only used by the UI externally, but may be set through the parameter file - bool bCloseIgnoreError; - - CAtlArray selvcs; - CAtlMap selids; - - void Reset(); - void Copy(struct VSFRipperData& rd); -}; - -struct vcchunk { - __int64 start, end; - DWORD vc; -}; - -#pragma pack(pop) - -// note: these interfaces only meant to be used internally with static linking - -// -// IVSFRipperCallback -// - -interface __declspec(uuid("9E2EBB5C-AD7C-452f-A48B-38685716AC46")) - IVSFRipperCallback : - public IUnknown -{ - STDMETHOD(OnMessage)(LPCTSTR msg) PURE; - STDMETHOD(OnProgress)(double progress /*0.0 -> 1.0*/) PURE; - STDMETHOD(OnFinished)(bool bSucceeded) PURE; -}; - -// IVSFRipperCallbackImpl - -class IVSFRipperCallbackImpl : public CUnknown, public IVSFRipperCallback -{ -protected: - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(IVSFRipperCallback) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IVSFRipperCallback - STDMETHODIMP OnMessage(LPCTSTR msg) { return S_FALSE; } - STDMETHODIMP OnProgress(double progress /*0.0 -> 1.0*/) { return S_FALSE; } - STDMETHODIMP OnFinished(bool bSucceeded) { return S_FALSE; } - -public: - IVSFRipperCallbackImpl() : CUnknown(NAME("IVSFRipperCallbackImpl"), nullptr) {} -}; - -// -// IVSFRipper -// - -interface __declspec(uuid("69F935BB-B8D0-43f5-AA2E-BBD0851CC9A6")) - IVSFRipper : - public IUnknown -{ - STDMETHOD(SetCallBack)(IVSFRipperCallback* pCallback) PURE; - STDMETHOD(LoadParamFile)(CString fn) PURE; - STDMETHOD(SetInput)(CString infn) PURE; - STDMETHOD(SetOutput)(CString outfn) PURE; - STDMETHOD(GetRipperData)(VSFRipperData& rd) PURE; - STDMETHOD(UpdateRipperData)(VSFRipperData& rd) PURE; - STDMETHOD(Index)() PURE; - STDMETHOD(IsIndexing)() PURE; - STDMETHOD(Abort)(bool bSavePartial) PURE; -}; - -class CVobSubFileRipper : public CVobSubFile, protected CAMThread, public IVSFRipper -{ -private: - bool m_bThreadActive, m_bBreakThread, m_bIndexing; - enum { CMD_EXIT, CMD_INDEX }; - DWORD ThreadProc(); - bool Create(); - - // - - enum log_t { - LOG_INFO, - LOG_WARNING, - LOG_ERROR - }; - void Log(log_t type, LPCTSTR lpszFormat, ...); - void Progress(double progress); - void Finished(bool bSucceeded); - - // - - CCritSec m_csAccessLock; - CString m_infn, m_outfn; - CVobFile m_vob; - VSFRipperData m_rd; - - bool LoadIfo(CString fn); - bool LoadVob(CString fn); - bool LoadChunks(CAtlArray& chunks); - bool SaveChunks(CAtlArray& chunks); - - // - - CCritSec m_csCallback; - CComPtr m_pCallback; - -public: - CVobSubFileRipper(); - virtual ~CVobSubFileRipper(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IVSFRipper - STDMETHODIMP SetCallBack(IVSFRipperCallback* pCallback); - STDMETHODIMP LoadParamFile(CString fn); - STDMETHODIMP SetInput(CString infn); - STDMETHODIMP SetOutput(CString outfn); - STDMETHODIMP GetRipperData(VSFRipperData& rd); - STDMETHODIMP UpdateRipperData(VSFRipperData& rd); - STDMETHODIMP Index(); - STDMETHODIMP IsIndexing(); - STDMETHODIMP Abort(bool bSavePartial); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#pragma once + +#include +#include "../DeCSS/VobFile.h" +#include "../DSUtil/DSUtil.h" +#include "VobSubFile.h" + +#pragma pack(push, 1) +struct vidinfo { + WORD perm_displ : 2; + WORD ratio : 2; + WORD system : 2; + WORD compression : 2; + WORD mode : 1; + WORD letterboxed : 1; + WORD source_res : 2; + WORD cbrvbr : 2; + WORD line21_2 : 1; + WORD line21_1 : 1; +}; + +struct vc_t { + BYTE vob, cell; + DWORD tTime, tOffset, tTotal; + DWORD start, end; + int iAngle; + bool bDiscontinuity; +}; + +struct PGC { + int nAngles; + CAtlArray angles[10]; + int iSelAngle; + RGBQUAD pal[16]; + WORD ids[32]; +}; + +struct VSFRipperData { + CSize vidsize; + vidinfo vidinfo; + CAtlArray pgcs; + int iSelPGC; + bool bResetTime, bClosedCaption, bForcedOnly; + + bool bClose, bBeep, bAuto; // only used by the UI externally, but may be set through the parameter file + bool bCloseIgnoreError; + + CAtlArray selvcs; + CAtlMap selids; + + void Reset(); + void Copy(struct VSFRipperData& rd); +}; + +struct vcchunk { + __int64 start, end; + DWORD vc; +}; + +#pragma pack(pop) + +// note: these interfaces only meant to be used internally with static linking + +// +// IVSFRipperCallback +// + +interface __declspec(uuid("9E2EBB5C-AD7C-452f-A48B-38685716AC46")) + IVSFRipperCallback : + public IUnknown +{ + STDMETHOD(OnMessage)(LPCTSTR msg) PURE; + STDMETHOD(OnProgress)(double progress /*0.0 -> 1.0*/) PURE; + STDMETHOD(OnFinished)(bool bSucceeded) PURE; +}; + +// IVSFRipperCallbackImpl + +class IVSFRipperCallbackImpl : public CUnknown, public IVSFRipperCallback +{ +protected: + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(IVSFRipperCallback) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IVSFRipperCallback + STDMETHODIMP OnMessage(LPCTSTR msg) { return S_FALSE; } + STDMETHODIMP OnProgress(double progress /*0.0 -> 1.0*/) { return S_FALSE; } + STDMETHODIMP OnFinished(bool bSucceeded) { return S_FALSE; } + +public: + IVSFRipperCallbackImpl() : CUnknown(NAME("IVSFRipperCallbackImpl"), nullptr) {} +}; + +// +// IVSFRipper +// + +interface __declspec(uuid("69F935BB-B8D0-43f5-AA2E-BBD0851CC9A6")) + IVSFRipper : + public IUnknown +{ + STDMETHOD(SetCallBack)(IVSFRipperCallback* pCallback) PURE; + STDMETHOD(LoadParamFile)(CString fn) PURE; + STDMETHOD(SetInput)(CString infn) PURE; + STDMETHOD(SetOutput)(CString outfn) PURE; + STDMETHOD(GetRipperData)(VSFRipperData& rd) PURE; + STDMETHOD(UpdateRipperData)(VSFRipperData& rd) PURE; + STDMETHOD(Index)() PURE; + STDMETHOD(IsIndexing)() PURE; + STDMETHOD(Abort)(bool bSavePartial) PURE; +}; + +class CVobSubFileRipper : public CVobSubFile, protected CAMThread, public IVSFRipper +{ +private: + bool m_bThreadActive, m_bBreakThread, m_bIndexing; + enum { CMD_EXIT, CMD_INDEX }; + DWORD ThreadProc(); + bool Create(); + + // + + enum log_t { + LOG_INFO, + LOG_WARNING, + LOG_ERROR + }; + void Log(log_t type, LPCTSTR lpszFormat, ...); + void Progress(double progress); + void Finished(bool bSucceeded); + + // + + CCritSec m_csAccessLock; + CString m_infn, m_outfn; + CVobFile m_vob; + VSFRipperData m_rd; + + bool LoadIfo(CString fn); + bool LoadVob(CString fn); + bool LoadChunks(CAtlArray& chunks); + bool SaveChunks(CAtlArray& chunks); + + // + + CCritSec m_csCallback; + CComPtr m_pCallback; + +public: + CVobSubFileRipper(); + virtual ~CVobSubFileRipper(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IVSFRipper + STDMETHODIMP SetCallBack(IVSFRipperCallback* pCallback); + STDMETHODIMP LoadParamFile(CString fn); + STDMETHODIMP SetInput(CString infn); + STDMETHODIMP SetOutput(CString outfn); + STDMETHODIMP GetRipperData(VSFRipperData& rd); + STDMETHODIMP UpdateRipperData(VSFRipperData& rd); + STDMETHODIMP Index(); + STDMETHODIMP IsIndexing(); + STDMETHODIMP Abort(bool bSavePartial); +}; diff --git a/src/Subtitles/VobSubImage.cpp b/src/Subtitles/VobSubImage.cpp index 70675655cc8..4229b0f0f60 100644 --- a/src/Subtitles/VobSubImage.cpp +++ b/src/Subtitles/VobSubImage.cpp @@ -1,1361 +1,1361 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "VobSubImage.h" -#include "RTS.h" -#include -#include - -CVobSubImage::CVobSubImage() - : org(CSize(0, 0)) - , lpTemp1(nullptr) - , lpTemp2(nullptr) - , nPlane(0) - , bCustomPal(false) - , bAligned(true) - , tridx(0) - , orgpal(nullptr) - , cuspal(nullptr) - , nLang(SIZE_T_ERROR) - , nIdx(SIZE_T_ERROR) - , bForced(false) - , bAnimated(false) - , tCurrent(-1) - , start(0) - , delay(0) - , rect(CRect(0, 0, 0, 0)) - , lpPixels(nullptr) -{ - ZeroMemory(&pal, sizeof(pal)); -} - -CVobSubImage::~CVobSubImage() -{ - Free(); -} - -bool CVobSubImage::Alloc(int w, int h) -{ - // if there is nothing to crop TrimSubImage might even add a 1 pixel - // wide border around the text, that's why we need a bit more memory - // to be allocated. - - if (lpTemp1 == nullptr || w * h > org.cx * org.cy || (w + 2) * (h + 2) > (org.cx + 2) * (org.cy + 2)) { - Free(); - - try { - lpTemp1 = DEBUG_NEW RGBQUAD[w * h]; - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - return false; - } - - try { - lpTemp2 = DEBUG_NEW RGBQUAD[(w + 2) * (h + 2)]; - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - delete [] lpTemp1; - lpTemp1 = nullptr; - return false; - } - - org.cx = w; - org.cy = h; - } - - lpPixels = lpTemp1; - - return true; -} - -void CVobSubImage::Free() -{ - SAFE_DELETE_ARRAY(lpTemp1); - SAFE_DELETE_ARRAY(lpTemp2); - - lpPixels = nullptr; -} - -bool CVobSubImage::Decode(BYTE* _lpData, size_t _packetSize, size_t _dataSize, int _t, - bool _bCustomPal, - int _tridx, - RGBQUAD* _orgpal /*[16]*/, RGBQUAD* _cuspal /*[4]*/, - bool _bTrim) -{ - GetPacketInfo(_lpData, _packetSize, _dataSize, _t); - - if (!Alloc(rect.Width(), rect.Height())) { - return false; - } - - lpPixels = lpTemp1; - - nPlane = 0; - bAligned = true; - - bCustomPal = _bCustomPal; - orgpal = _orgpal; - tridx = _tridx; - cuspal = _cuspal; - - CPoint p = rect.TopLeft(); - - size_t end[] = { nOffset[1], _dataSize }; - - while (nOffset[nPlane] < end[nPlane]) { - DWORD code; - - if ((code = GetNibble(_lpData)) >= 0x4 - || (code = (code << 4) | GetNibble(_lpData)) >= 0x10 - || (code = (code << 4) | GetNibble(_lpData)) >= 0x40 - || (code = (code << 4) | GetNibble(_lpData)) >= 0x100) { - DrawPixels(p, code >> 2, code & 3); - if ((p.x += code >> 2) < rect.right) { - continue; - } - } - - DrawPixels(p, rect.right - p.x, code & 3); - - if (!bAligned) { - GetNibble(_lpData); // align to byte - } - - p.x = rect.left; - p.y++; - nPlane = 1 - nPlane; - } - - rect.bottom = std::min(p.y, rect.bottom); - - if (_bTrim) { - TrimSubImage(); - } - - return true; -} - -void CVobSubImage::GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t /*= INT_MAX*/) -{ - // delay = 0; - - size_t i, nextctrlblk = dataSize; - WORD _pal = 0, tr = 0; - WORD nPal = 0, nTr = 0; - - do { - i = nextctrlblk; - - tCurrent = 1024 * ((lpData[i] << 8) | lpData[i + 1]) / 90; - i += 2; - nextctrlblk = (lpData[i] << 8) | lpData[i + 1]; - i += 2; - - if (nextctrlblk > packetSize || nextctrlblk < dataSize) { - ASSERT(0); - return; - } - - if (tCurrent > t) { - break; - } - - bool bBreak = false; - - while (!bBreak) { - size_t len = 0; - - switch (lpData[i]) { - case 0x00: - len = 0; - break; - case 0x01: - len = 0; - break; - case 0x02: - len = 0; - break; - case 0x03: - len = 2; - break; - case 0x04: - len = 2; - break; - case 0x05: - len = 6; - break; - case 0x06: - len = 4; - break; - default: - len = 0; - break; - } - - if (i + len >= packetSize) { - TRACE(_T("Warning: Wrong subpicture parameter block ending\n")); - break; - } - - switch (lpData[i++]) { - case 0x00: // forced start displaying - bForced = true; - break; - case 0x01: // start displaying - bForced = false; - break; - case 0x02: // stop displaying - delay = tCurrent; - break; - case 0x03: - _pal = (lpData[i] << 8) | lpData[i + 1]; - i += 2; - nPal++; - break; - case 0x04: - tr = (lpData[i] << 8) | lpData[i + 1]; - i += 2; - nTr++; - //tr &= 0x00f0; - break; - case 0x05: - rect = CRect((lpData[i] << 4) + (lpData[i + 1] >> 4), - (lpData[i + 3] << 4) + (lpData[i + 4] >> 4), - ((lpData[i + 1] & 0x0f) << 8) + lpData[i + 2] + 1, - ((lpData[i + 4] & 0x0f) << 8) + lpData[i + 5] + 1); - i += 6; - break; - case 0x06: - nOffset[0] = (lpData[i] << 8) + lpData[i + 1]; - i += 2; - nOffset[1] = (lpData[i] << 8) + lpData[i + 1]; - i += 2; - break; - case 0xff: // end of ctrlblk - bBreak = true; - continue; - default: // skip this ctrlblk - bBreak = true; - break; - } - } - } while (i <= nextctrlblk && i < packetSize); - - for (i = 0; i < 4; i++) { - this->pal[i].pal = (_pal >> (i << 2)) & 0xf; - this->pal[i].tr = (tr >> (i << 2)) & 0xf; - } - - bAnimated = (nPal > 1 || nTr > 1); -} - -BYTE CVobSubImage::GetNibble(const BYTE* lpData) -{ - size_t& off = nOffset[nPlane]; - BYTE ret = lpData[off]; - if (bAligned) { - ret >>= 4; - } - ret &= 0x0f; - bAligned = !bAligned; - if (bAligned) { - off++; - } - return ret; -} - -void CVobSubImage::DrawPixels(CPoint p, int length, size_t colorId) -{ - if (length <= 0 - || p.x + length < rect.left - || p.x >= rect.right - || p.y < rect.top - || p.y >= rect.bottom) { - return; - } - - if (p.x < rect.left) { - p.x = rect.left; - } - if (p.x + length >= rect.right) { - length = rect.right - p.x; - } - - RGBQUAD* ptr = &lpPixels[rect.Width() * (p.y - rect.top) + (p.x - rect.left)]; - - RGBQUAD c; - - if (!bCustomPal) { - c = orgpal[pal[colorId].pal]; - c.rgbReserved = (pal[colorId].tr << 4) | pal[colorId].tr; - } else { - c = cuspal[colorId]; - } - - while (length-- > 0) { - *ptr++ = c; - } -} - -void CVobSubImage::TrimSubImage() -{ - CRect r; - r.left = rect.Width(); - r.top = rect.Height(); - r.right = 0; - r.bottom = 0; - - RGBQUAD* ptr = lpTemp1; - - for (int j = 0, y = rect.Height(); j < y; j++) { - for (int i = 0, x = rect.Width(); i < x; i++, ptr++) { - if (ptr->rgbReserved) { - if (r.top > j) { - r.top = j; - } - if (r.bottom < j) { - r.bottom = j; - } - if (r.left > i) { - r.left = i; - } - if (r.right < i) { - r.right = i; - } - } - } - } - - if (r.left > r.right || r.top > r.bottom) { - return; - } - - r += CRect(0, 0, 1, 1); - - r &= CRect(CPoint(0, 0), rect.Size()); - - int w = r.Width(), h = r.Height(); - - DWORD offset = r.top * rect.Width() + r.left; - - r += CRect(1, 1, 1, 1); - - DWORD* src = (DWORD*)&lpTemp1[offset]; - DWORD* dst = (DWORD*)&lpTemp2[1 + w + 1]; - - ZeroMemory(lpTemp2, (1 + w + 1)*sizeof(RGBQUAD)); - - for (int height = h; height; height--, src += rect.Width()) { - *dst++ = 0; - memcpy(dst, src, w * sizeof(RGBQUAD)); - dst += w; - *dst++ = 0; - } - - ZeroMemory(dst, (1 + w + 1)*sizeof(RGBQUAD)); - - lpPixels = lpTemp2; - - rect = r + rect.TopLeft(); -} - -//////////////////////////////// - -#define GP(xx, yy) (((xx) < 0 || (yy) < 0 || (xx) >= w || (yy) >= h) ? 0 : p[(yy) * w + (xx)]) - -CAutoPtrList* CVobSubImage::GetOutlineList(CPoint& topleft) -{ - int w = rect.Width(), h = rect.Height(), len = w * h; - if (len <= 0) { - return nullptr; - } - - CAutoVectorPtr p; - if (!p.Allocate(len)) { - return nullptr; - } - - CAutoPtrList* ol; - try { - ol = DEBUG_NEW CAutoPtrList(); - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - return nullptr; - } - - BYTE* cp = p; - RGBQUAD* rgbp = (RGBQUAD*)lpPixels; - - for (int i = 0; i < len; i++, cp++, rgbp++) { - *cp = !!rgbp->rgbReserved; - } - - enum { UP, RIGHT, DOWN, LEFT }; - - topleft.x = topleft.y = INT_MAX; - - for (;;) { - cp = p; - - int x = 0; - int y = 0; - - for (y = 0; y < h; y++) { - for (x = 0; x < w - 1; x++, cp++) { - if (cp[0] == 0 && cp[1] == 1) { - break; - } - } - - if (x < w - 1) { - break; - } - - cp++; - } - - if (y == h) { - break; - } - - int dir = UP; - - int ox = x, oy = y, odir = dir; - - CAutoPtr o; - try { - o.Attach(DEBUG_NEW COutline); - } catch (CMemoryException* e) { - ASSERT(FALSE); - e->Delete(); - break; - } - - do { - CPoint pp; - BYTE fl = 0; - BYTE fr = 0; - BYTE br = 0; - - int prevdir = dir; - - switch (prevdir) { - case UP: - pp = CPoint(x + 1, y); - fl = GP(x, y - 1); - fr = GP(x + 1, y - 1); - br = GP(x + 1, y); - break; - case RIGHT: - pp = CPoint(x + 1, y + 1); - fl = GP(x + 1, y); - fr = GP(x + 1, y + 1); - br = GP(x, y + 1); - break; - case DOWN: - pp = CPoint(x, y + 1); - fl = GP(x, y + 1); - fr = GP(x - 1, y + 1); - br = GP(x - 1, y); - break; - case LEFT: - pp = CPoint(x, y); - fl = GP(x - 1, y); - fr = GP(x - 1, y - 1); - br = GP(x, y - 1); - break; - } - - // turning left if: - // o . | o . - // ^ o | < o - // turning right if: - // x x | x > - // ^ o | x o - // - // o set, x empty, . can be anything - - if (fl == 1) { - dir = (dir - 1 + 4) & 3; - } else if (fl != 1 && fr != 1 && br == 1) { - dir = (dir + 1) & 3; - } else if (p[y * w + x] & 16) { - ASSERT(0); // we are going around in one place (this must not happen if the starting conditions were correct) - break; - } - - p[y * w + x] = (p[y * w + x] << 1) | 2; // increase turn count (== log2(highordbit(*p))) - - switch (dir) { - case UP: - if (prevdir == LEFT) { - x--; - y--; - } - if (prevdir == UP) { - y--; - } - break; - case RIGHT: - if (prevdir == UP) { - x++; - y--; - } - if (prevdir == RIGHT) { - x++; - } - break; - case DOWN: - if (prevdir == RIGHT) { - x++; - y++; - } - if (prevdir == DOWN) { - y++; - } - break; - case LEFT: - if (prevdir == DOWN) { - x--; - y++; - } - if (prevdir == LEFT) { - x--; - } - break; - } - - int d = dir - prevdir; - o->Add(pp, d == 3 ? -1 : d == -3 ? 1 : d); - - if (topleft.x > pp.x) { - topleft.x = pp.x; - } - if (topleft.y > pp.y) { - topleft.y = pp.y; - } - } while (!(x == ox && y == oy && dir == odir)); - - if (!o->pa.IsEmpty() && (x == ox && y == oy && dir == odir)) { - ol->AddTail(o); - } else { - ASSERT(0); - } - } - - return ol; -} - -static bool FitLine(const COutline& o, int& start, int& end) -{ - int len = (int)o.pa.GetCount(); - if (len < 7) { - return false; // small segments should be handled with beziers... - } - - for (start = 0; start < len && !o.da[start]; start++) { - ; - } - for (end = len - 1; end > start && !o.da[end]; end--) { - ; - } - - if (end - start < 8 || end - start < (len - end) + (start - 0)) { - return false; - } - - CUIntArray la, ra; - - UINT i, j, k; - - for (i = start + 1, j = end, k = start; i <= j; i++) { - if (!o.da[i]) { - continue; - } - if (o.da[i] == o.da[k]) { - return false; - } - if (o.da[i] == -1) { - la.Add(i - k); - } else { - ra.Add(i - k); - } - k = i; - } - - bool fl = true, fr = true; - - // these tests are completly heuristic and might be redundant a bit... - - for (i = 0, j = (UINT)la.GetSize(); i < j && fl; i++) { - if (la[i] != 1) { - fl = false; - } - } - for (i = 0, j = (UINT)ra.GetSize(); i < j && fr; i++) { - if (ra[i] != 1) { - fr = false; - } - } - - if (!fl && !fr) { - return false; // can't be a line if there are bigger steps than one in both directions (lines are usually drawn by stepping one either horizontally or vertically) - } - if (fl && fr && 1.0 * (end - start) / ((len - end) * 2 + (start - 0) * 2) > 0.4) { - return false; // if this section is relatively too small it may only be a rounded corner - } - if (!fl && !la.IsEmpty() && la.GetSize() <= 4 && (la[0] == 1 && la[la.GetSize() - 1] == 1)) { - return false; // one step at both ends, doesn't sound good for a line (may be it was skewed, so only eliminate smaller sections where beziers going to look just as good) - } - if (!fr && !ra.IsEmpty() && ra.GetSize() <= 4 && (ra[0] == 1 && ra[ra.GetSize() - 1] == 1)) { - return false; // -''- - } - - CUIntArray& a = !fl ? la : ra; - - len = (int)a.GetSize(); - - int sum = 0; - - for (i = 0, j = INT_MAX, k = 0; i < (UINT)len; i++) { - if (j > a[i]) { - j = a[i]; - } - if (k < a[i]) { - k = a[i]; - } - sum += a[i]; - } - - if (k - j > 2 && 1.0 * sum / len < 2) { - return false; - } - if (k - j > 2 && 1.0 * sum / len >= 2 && len < 4) { - return false; - } - - if ((la.GetSize() / 2 + ra.GetSize() / 2) / 2 <= 2) { - if ((k + j) / 2 < 2 && k * j != 1) { - return false; - } - } - - double err = 0; - - CPoint sp = o.pa[start], ep = o.pa[end]; - - double minerr = 0, maxerr = 0; - - double vx = ep.x - sp.x, vy = ep.y - sp.y, l = sqrt(vx * vx + vy * vy); - vx /= l; - vy /= l; - - for (i = start + 1, j = end - 1; i <= j; i++) { - CPoint p = o.pa[i], dp = p - sp; - double t = vx * dp.x + vy * dp.y, dx = vx * t + sp.x - p.x, dy = vy * t + sp.y - p.y; - t = dx * dx + dy * dy; - err += t; - t = sqrt(t); - if (vy * dx - dy * vx < 0) { - if (minerr > -t) { - minerr = -t; - } - } else { - if (maxerr < t) { - maxerr = t; - } - } - } - - return ((maxerr - minerr) / l < 0.1 || err / l < 1.5 || (fabs(maxerr) < 8 && fabs(minerr) < 8)); -} - -static int CalcPossibleCurveDegree(const COutline& o) -{ - size_t len2 = o.da.GetCount(); - - CUIntArray la; - - for (size_t i = 0, j = 0; j < len2; j++) { - if (j + 1 == len2 || o.da[j]) { - la.Add(UINT(j - i)); - i = j; - } - } - - ptrdiff_t len = la.GetCount(); - - int ret = 0; - - // check if we can find a reason to add a penalty degree, or two :P - // it is mainly about looking for distant corners - { - int penalty = 0; - - int ma[2] = {0, 0}; - for (ptrdiff_t i = 0; i < len; i++) { - ma[i & 1] += la[i]; - } - - int ca[2] = {ma[0], ma[1]}; - for (ptrdiff_t i = 0; i < len; i++) { - ca[i & 1] -= la[i]; - - double c1 = 1.0 * ca[0] / ma[0], c2 = 1.0 * ca[1] / ma[1], c3 = 1.0 * la[i] / ma[i & 1]; - - if (len2 > 16 && (fabs(c1 - c2) > 0.7 || (c3 > 0.6 && la[i] > 5))) { - penalty = 2; - break; - } - - if (fabs(c1 - c2) > 0.6 || (c3 > 0.4 && la[i] > 5)) { - penalty = 1; - } - } - - ret += penalty; - } - - la[0] <<= 1; - la[len - 1] <<= 1; - - for (ptrdiff_t i = 0; i < len; i += 2) { - if (la[i] > 1) { - ret++; // prependicular to the last chosen section and bigger then 1 -> add a degree and continue with the other dir - i--; - } - } - - return ret; -} - -inline double vectlen(CPoint p) -{ - return sqrt((double)(p.x * p.x + p.y * p.y)); -} - -inline double vectlen(CPoint p1, CPoint p2) -{ - return vectlen(p2 - p1); -} - -static bool MinMaxCosfi(COutline& o, double& mincf, double& maxcf) // not really cosfi, it is weighted by the distance from the segment endpoints, and since it would be always between -1 and 0, the applied sign marks side -{ - CAtlArray& pa = o.pa; - - int len = (int)pa.GetCount(); - if (len < 6) { - return false; - } - - mincf = 1; - maxcf = -1; - - CPoint p = pa[len - 1] - pa[0]; - double l = vectlen(p); - UNREFERENCED_PARAMETER(l); - - for (ptrdiff_t i = 2; i < len - 2; i++) { // skip the endpoints, they aren't accurate - CPoint p1 = pa[0] - pa[i], p2 = pa[len - 1] - pa[i]; - double l1 = vectlen(p1), l2 = vectlen(p2); - int sign = p1.x * p.y - p1.y * p.x >= 0 ? 1 : -1; - - double c = (1.0 * len / 2 - fabs(i - 1.0 * len / 2)) / len * 2; // c: 0 -> 1 -> 0 - - double cosfi = (1 + (p1.x * p2.x + p1.y * p2.y) / (l1 * l2)) * sign * c; - if (mincf > cosfi) { - mincf = cosfi; - } - if (maxcf < cosfi) { - maxcf = cosfi; - } - } - - return true; -} - -static bool FitBezierVH(COutline& o, CPoint& p1, CPoint& p2) -{ - int i; - - CAtlArray& pa = o.pa; - - int len = (int)pa.GetCount(); - - if (len <= 1) { - return false; - } else if (len == 2) { - CPoint mid = pa[0] + pa[1]; - mid.x >>= 1; - mid.y >>= 1; - p1 = p2 = mid; - return true; - } - - CPoint dir1 = pa[1] - pa[0], dir2 = pa[len - 2] - pa[len - 1]; - if ((dir1.x && dir1.y) || (dir2.x && dir2.y)) { - return false; // we are only fitting beziers with hor./ver. endings - } - - if (CalcPossibleCurveDegree(o) > 3) { - return false; - } - - double mincf, maxcf; - if (MinMaxCosfi(o, mincf, maxcf)) { - if (maxcf - mincf > 0.8 - || maxcf - mincf > 0.6 && (maxcf >= 0.4 || mincf <= -0.4)) { - return false; - } - } - - CPoint p0 = p1 = pa[0]; - CPoint p3 = p2 = pa[len - 1]; - - CAtlArray pl; - pl.SetCount(len); - - double c10 = 0, c11 = 0, c12 = 0, c13 = 0, c1x = 0, c1y = 0; - double c20 = 0, c21 = 0, c22 = 0, c23 = 0, c2x = 0, c2y = 0; - double length = 0; - - for (pl[0] = 0, i = 1; i < len; i++) { - CPoint diff = (pa[i] - pa[i - 1]); - pl[i] = (length += sqrt((double)(diff.x * diff.x + diff.y * diff.y))); - } - - for (i = 0; i < len; i++) { - double t1 = pl[i] / length; - double t2 = t1 * t1; - double t3 = t2 * t1; - double it1 = 1 - t1; - double it2 = it1 * it1; - double it3 = it2 * it1; - - double dc1 = 3.0 * it2 * t1; - double dc2 = 3.0 * it1 * t2; - - c10 += it3 * dc1; - c11 += dc1 * dc1; - c12 += dc2 * dc1; - c13 += t3 * dc1; - c1x += pa[i].x * dc1; - c1y += pa[i].y * dc1; - - c20 += it3 * dc2; - c21 += dc1 * dc2; - c22 += dc2 * dc2; - c23 += t3 * dc2; - c2x += pa[i].x * dc2; - c2y += pa[i].y * dc2; - } - - if (dir1.y == 0 && dir2.x == 0) { - p1.x = (int)((c1x - c10 * p0.x - c12 * p3.x - c13 * p3.x) / c11 + 0.5); - p2.y = (int)((c2y - c20 * p0.y - c21 * p0.y - c23 * p3.y) / c22 + 0.5); - } else if (dir1.x == 0 && dir2.y == 0) { - p2.x = (int)((c2x - c20 * p0.x - c21 * p0.x - c23 * p3.x) / c22 + 0.5); - p1.y = (int)((c1y - c10 * p0.y - c12 * p3.y - c13 * p3.y) / c11 + 0.5); - } else if (dir1.y == 0 && dir2.y == 0) { - // cramer's rule - double D = c11 * c22 - c12 * c21; - p1.x = (int)(((c1x - c10 * p0.x - c13 * p3.x) * c22 - c12 * (c2x - c20 * p0.x - c23 * p3.x)) / D + 0.5); - p2.x = (int)((c11 * (c2x - c20 * p0.x - c23 * p3.x) - (c1x - c10 * p0.x - c13 * p3.x) * c21) / D + 0.5); - } else if (dir1.x == 0 && dir2.x == 0) { - // cramer's rule - double D = c11 * c22 - c12 * c21; - p1.y = (int)(((c1y - c10 * p0.y - c13 * p3.y) * c22 - c12 * (c2y - c20 * p0.y - c23 * p3.y)) / D + 0.5); - p2.y = (int)((c11 * (c2y - c20 * p0.y - c23 * p3.y) - (c1y - c10 * p0.y - c13 * p3.y) * c21) / D + 0.5); - } else { // must not happen - ASSERT(0); - return false; - } - - // check for "inside-out" beziers - CPoint dir3 = p1 - p0, dir4 = p2 - p3; - if ((dir1.x * dir3.x + dir1.y * dir3.y) <= 0 || (dir2.x * dir4.x + dir2.y * dir4.y) <= 0) { - return false; - } - - return true; -} - -int CVobSubImage::GrabSegment(int _start, const COutline& o, COutline& ret) -{ - ret.RemoveAll(); - - int len = int(o.pa.GetCount()); - - int cur = (_start) % len, first = -1, last = -1; - int lastDir = 0; - - for (ptrdiff_t i = 0; i < len; i++) { - cur = (cur + 1) % len; - - if (o.da[cur] == 0) { - continue; - } - - if (first == -1) { - first = cur; - } - - if (lastDir == o.da[cur]) { - CPoint startp = o.pa[first] + o.pa[_start]; - startp.x >>= 1; - startp.y >>= 1; - CPoint endp = o.pa[last] + o.pa[cur]; - endp.x >>= 1; - endp.y >>= 1; - - if (first < _start) { - first += len; - } - _start = ((_start + first) >> 1) + 1; - if (_start >= len) { - _start -= len; - } - if (cur < last) { - cur += len; - } - cur = ((last + cur + 1) >> 1); - if (cur >= len) { - cur -= len; - } - - ret.Add(startp, 0); - - while (_start != cur) { - ret.Add(o.pa[_start], o.da[_start]); - - _start++; - if (_start >= len) { - _start -= len; - } - } - - ret.Add(endp, 0); - - return last; - } - - lastDir = o.da[cur]; - last = cur; - } - - ASSERT(0); - - return _start; -} - -void CVobSubImage::SplitOutline(const COutline& o, COutline& o1, COutline& o2) -{ - size_t len = o.pa.GetCount(); - if (len < 4) { - return; - } - - CAtlArray la, sa, ea; - - size_t i, j, k; - - for (i = 0, j = 0; j < len; j++) { - if (j + 1 == len || o.da[j]) { - la.Add(unsigned int(j - i)); - sa.Add(unsigned int(i)); - ea.Add(unsigned int(j)); - i = j; - } - } - - size_t maxlen = 0, maxidx = SIZE_T_ERROR; - size_t maxlen2 = 0, maxidx2 = SIZE_T_ERROR; - - for (i = 0; i < la.GetCount(); i++) { - if (maxlen < la[i]) { - maxlen = la[i]; - maxidx = i; - } - - if (maxlen2 < la[i] && i > 0 && i < la.GetCount() - 1) { - maxlen2 = la[i]; - maxidx2 = i; - } - } - - ASSERT(maxidx != SIZE_T_ERROR && maxidx2 != SIZE_T_ERROR); - - if (maxlen == maxlen2) { - maxidx = maxidx2; // if equal choose the inner section - } - - j = (sa[maxidx] + ea[maxidx]) >> 1, k = (sa[maxidx] + ea[maxidx] + 1) >> 1; - - o1.RemoveAll(); - o2.RemoveAll(); - - for (i = 0; i <= j; i++) { - o1.Add(o.pa[i], o.da[i]); - } - - if (j != k) { - CPoint mid = o.pa[j] + o.pa[k]; - mid.x >>= 1; - mid.y >>= 1; - o1.Add(mid, 0); - o2.Add(mid, 0); - } - - for (i = k; i < len; i++) { - o2.Add(o.pa[i], o.da[i]); - } -} - -void CVobSubImage::AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints) -{ - int i, len = int(o.pa.GetCount()); - if (len < 3) { - return; - } - - int nLeftTurns = 0, nRightTurns = 0; - - for (i = 0; i < len; i++) { - if (o.da[i] == -1) { - nLeftTurns++; - } else if (o.da[i] == 1) { - nRightTurns++; - } - } - - if (nLeftTurns == 0 && nRightTurns == 0) { // line - pathTypes.Add(PT_LINETO); - pathPoints.Add(o.pa[len - 1]); - - return; - } - - if (nLeftTurns == 0 || nRightTurns == 0) { // b-spline - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); - - for (i = 0; i < 3; i++) { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[i]); - } - - for (; i < len; i++) { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[i]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[len - 1]); - - return; - } - - int _start, _end; - if (FitLine(o, _start, _end)) { // b-spline, line, b-spline - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); - - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[0]); - - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[1]); - - CPoint p[4], pp, d = o.pa[_end] - o.pa[_start]; - double l = sqrt((double)(d.x * d.x + d.y * d.y)), dx = 1.0 * d.x / l, dy = 1.0 * d.y / l; - - pp = o.pa[_start] - o.pa[_start - 1]; - double l1 = abs(pp.x) + abs(pp.y); - pp = o.pa[_end] - o.pa[_end + 1]; - double l2 = abs(pp.x) + abs(pp.y); - p[0] = CPoint((int)(1.0 * o.pa[_start].x + dx * l1 + 0.5), (int)(1.0 * o.pa[_start].y + dy * l1 + 0.5)); - p[1] = CPoint((int)(1.0 * o.pa[_start].x + dx * l1 * 2 + 0.5), (int)(1.0 * o.pa[_start].y + dy * l1 * 2 + 0.5)); - p[2] = CPoint((int)(1.0 * o.pa[_end].x - dx * l2 * 2 + 0.5), (int)(1.0 * o.pa[_end].y - dy * l2 * 2 + 0.5)); - p[3] = CPoint((int)(1.0 * o.pa[_end].x - dx * l2 + 0.5), (int)(1.0 * o.pa[_end].y - dy * l2 + 0.5)); - - if (_start == 1) { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(p[0]); - } else { - pathTypes.Add(PT_BSPLINETO); - pathPoints.Add(o.pa[2]); - - for (ptrdiff_t k = 3; k <= _start; k++) { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[k]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[0]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[1]); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(p[0]); - - pathTypes.Add(PT_LINETO); - pathPoints.Add(p[3]); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(p[2]); - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(p[3]); - - for (i = _end; i < len; i++) { - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[i]); - } - - pathTypes.Add(PT_BSPLINEPATCHTO); - pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); - - pathTypes.Add(PT_MOVETONC); - pathPoints.Add(o.pa[len - 1]); - - return; - } - - CPoint p1, p2; - if (FitBezierVH(o, p1, p2)) { // bezier - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(p1); - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(p2); - pathTypes.Add(PT_BEZIERTO); - pathPoints.Add(o.pa[o.pa.GetCount() - 1]); - - return; - } - - COutline o1, o2; - SplitOutline(o, o1, o2); - AddSegment(o1, pathTypes, pathPoints); - AddSegment(o2, pathTypes, pathPoints); -} - -bool CVobSubImage::Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool bSmooth, int scale) -{ - CPoint topleft; - CAutoPtr> ol(GetOutlineList(topleft)); - if (!ol) { - return false; - } - - POSITION pos; - - pos = ol->GetHeadPosition(); - while (pos) { - CAtlArray& pa = ol->GetNext(pos)->pa; - for (size_t i = 0; i < pa.GetCount(); i++) { - pa[i].x = (pa[i].x - topleft.x) << scale; - pa[i].y = (pa[i].y - topleft.y) << scale; - } - } - - pos = ol->GetHeadPosition(); - while (pos) { - COutline& o = *ol->GetNext(pos), o2; - - if (bSmooth) { - int i = 0, iFirst = -1; - - for (;;) { - i = GrabSegment(i, o, o2); - - if (i == iFirst) { - break; - } - - if (iFirst < 0) { - iFirst = i; - pathTypes.Add(PT_MOVETO); - pathPoints.Add(o2.pa[0]); - } - - AddSegment(o2, pathTypes, pathPoints); - } - } else { - /* - for (ptrdiff_t i = 1, len = o.pa.GetSize(); i < len; i++) - { - if (int dir = o.da[i-1]) - { - CPoint dir2 = o.pa[i] - o.pa[i-1]; - dir2.x /= 2; dir2.y /= 2; - CPoint dir1 = dir > 0 ? CPoint(dir2.y, -dir2.x) : CPoint(-dir2.y, dir2.x); - i = i; - o.pa[i-1] -= dir1; - o.pa.InsertAt(i, o.pa[i-1] + dir2); - o.da.InsertAt(i, -dir); - o.pa.InsertAt(i+1, o.pa[i] + dir1); - o.da.InsertAt(i+1, dir); - i += 2; - len += 2; - } - } - */ - pathTypes.Add(PT_MOVETO); - pathPoints.Add(o.pa[0]); - - for (size_t i = 1, len = o.pa.GetCount(); i < len; i++) { - pathTypes.Add(PT_LINETO); - pathPoints.Add(o.pa[i]); - } - } - } - - return !pathTypes.IsEmpty(); -} - -bool CVobSubImage::Polygonize(CStringW& assstr, bool bSmooth, int scale) -{ - CAtlArray pathTypes; - CAtlArray pathPoints; - - if (!Polygonize(pathTypes, pathPoints, bSmooth, scale)) { - return false; - } - - assstr.Format(L"{\\an7\\pos(%d,%d)\\p%d}", rect.left, rect.top, 1 + scale); - // assstr.Format(L"{\\p%d}", 1+scale); - - BYTE lastType = 0; - - size_t nPoints = pathTypes.GetCount(); - - for (size_t i = 0; i < nPoints; i++) { - CStringW s; - - switch (pathTypes[i]) { - case PT_MOVETO: - if (lastType != PT_MOVETO) { - assstr += L"m "; - } - s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_MOVETONC: - if (lastType != PT_MOVETONC) { - assstr += L"n "; - } - s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_LINETO: - if (lastType != PT_LINETO) { - assstr += L"l "; - } - s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); - break; - case PT_BEZIERTO: - if (i + 2 < nPoints) { - if (lastType != PT_BEZIERTO) { - assstr += L"b "; - } - s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); - i += 2; - } - break; - case PT_BSPLINETO: - if (i + 2 < nPoints) { - if (lastType != PT_BSPLINETO) { - assstr += L"s "; - } - s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); - i += 2; - } - break; - case PT_BSPLINEPATCHTO: - if (lastType != PT_BSPLINEPATCHTO) { - assstr += L"p "; - } - s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); - break; - } - - lastType = pathTypes[i]; - - assstr += s; - } - - assstr += L"{\\p0}"; - - return nPoints > 0; -} - -void CVobSubImage::Scale2x() -{ - int w = rect.Width(), h = rect.Height(); - - if (w > 0 && h > 0) { - DWORD* src = (DWORD*)lpPixels; - DWORD* dst = DEBUG_NEW DWORD[w * h]; - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++, src++, dst++) { - DWORD E = *src; - - DWORD A = x > 0 && y > 0 ? src[-w - 1] : E; - DWORD B = y > 0 ? src[-w] : E; - DWORD C = x < w - 1 && y > 0 ? src[-w + 1] : E; - UNREFERENCED_PARAMETER(A); - UNREFERENCED_PARAMETER(C); - - DWORD D = x > 0 ? src[-1] : E; - DWORD F = x < w - 1 ? src[+1] : E; - - DWORD G = x > 0 && y < h - 1 ? src[+w - 1] : E; - DWORD H = y < h - 1 ? src[+w] : E; - DWORD I = x < w - 1 && y < h - 1 ? src[+w + 1] : E; - UNREFERENCED_PARAMETER(G); - UNREFERENCED_PARAMETER(I); - - DWORD E0 = D == B && B != F && D != H ? D : E; - DWORD E1 = B == F && B != D && F != H ? F : E; - DWORD E2 = D == H && D != B && H != F ? D : E; - DWORD E3 = H == F && D != H && B != F ? F : E; - - *dst = ((((E0 & 0x00ff00ff) + (E1 & 0x00ff00ff) + (E2 & 0x00ff00ff) + (E3 & 0x00ff00ff) + 2) >> 2) & 0x00ff00ff) - | (((((E0 >> 8) & 0x00ff00ff) + ((E1 >> 8) & 0x00ff00ff) + ((E2 >> 8) & 0x00ff00ff) + ((E3 >> 8) & 0x00ff00ff) + 2) << 6) & 0xff00ff00); - } - } - - src -= w * h; - dst -= w * h; - - memcpy(src, dst, w * h * 4); - - delete [] dst; - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "VobSubImage.h" +#include "RTS.h" +#include +#include + +CVobSubImage::CVobSubImage() + : org(CSize(0, 0)) + , lpTemp1(nullptr) + , lpTemp2(nullptr) + , nPlane(0) + , bCustomPal(false) + , bAligned(true) + , tridx(0) + , orgpal(nullptr) + , cuspal(nullptr) + , nLang(SIZE_T_ERROR) + , nIdx(SIZE_T_ERROR) + , bForced(false) + , bAnimated(false) + , tCurrent(-1) + , start(0) + , delay(0) + , rect(CRect(0, 0, 0, 0)) + , lpPixels(nullptr) +{ + ZeroMemory(&pal, sizeof(pal)); +} + +CVobSubImage::~CVobSubImage() +{ + Free(); +} + +bool CVobSubImage::Alloc(int w, int h) +{ + // if there is nothing to crop TrimSubImage might even add a 1 pixel + // wide border around the text, that's why we need a bit more memory + // to be allocated. + + if (lpTemp1 == nullptr || w * h > org.cx * org.cy || (w + 2) * (h + 2) > (org.cx + 2) * (org.cy + 2)) { + Free(); + + try { + lpTemp1 = DEBUG_NEW RGBQUAD[w * h]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + return false; + } + + try { + lpTemp2 = DEBUG_NEW RGBQUAD[(w + 2) * (h + 2)]; + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + delete [] lpTemp1; + lpTemp1 = nullptr; + return false; + } + + org.cx = w; + org.cy = h; + } + + lpPixels = lpTemp1; + + return true; +} + +void CVobSubImage::Free() +{ + SAFE_DELETE_ARRAY(lpTemp1); + SAFE_DELETE_ARRAY(lpTemp2); + + lpPixels = nullptr; +} + +bool CVobSubImage::Decode(BYTE* _lpData, size_t _packetSize, size_t _dataSize, int _t, + bool _bCustomPal, + int _tridx, + RGBQUAD* _orgpal /*[16]*/, RGBQUAD* _cuspal /*[4]*/, + bool _bTrim) +{ + GetPacketInfo(_lpData, _packetSize, _dataSize, _t); + + if (!Alloc(rect.Width(), rect.Height())) { + return false; + } + + lpPixels = lpTemp1; + + nPlane = 0; + bAligned = true; + + bCustomPal = _bCustomPal; + orgpal = _orgpal; + tridx = _tridx; + cuspal = _cuspal; + + CPoint p = rect.TopLeft(); + + size_t end[] = { nOffset[1], _dataSize }; + + while (nOffset[nPlane] < end[nPlane]) { + DWORD code; + + if ((code = GetNibble(_lpData)) >= 0x4 + || (code = (code << 4) | GetNibble(_lpData)) >= 0x10 + || (code = (code << 4) | GetNibble(_lpData)) >= 0x40 + || (code = (code << 4) | GetNibble(_lpData)) >= 0x100) { + DrawPixels(p, code >> 2, code & 3); + if ((p.x += code >> 2) < rect.right) { + continue; + } + } + + DrawPixels(p, rect.right - p.x, code & 3); + + if (!bAligned) { + GetNibble(_lpData); // align to byte + } + + p.x = rect.left; + p.y++; + nPlane = 1 - nPlane; + } + + rect.bottom = std::min(p.y, rect.bottom); + + if (_bTrim) { + TrimSubImage(); + } + + return true; +} + +void CVobSubImage::GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t /*= INT_MAX*/) +{ + // delay = 0; + + size_t i, nextctrlblk = dataSize; + WORD _pal = 0, tr = 0; + WORD nPal = 0, nTr = 0; + + do { + i = nextctrlblk; + + tCurrent = 1024 * ((lpData[i] << 8) | lpData[i + 1]) / 90; + i += 2; + nextctrlblk = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + + if (nextctrlblk > packetSize || nextctrlblk < dataSize) { + ASSERT(0); + return; + } + + if (tCurrent > t) { + break; + } + + bool bBreak = false; + + while (!bBreak) { + size_t len = 0; + + switch (lpData[i]) { + case 0x00: + len = 0; + break; + case 0x01: + len = 0; + break; + case 0x02: + len = 0; + break; + case 0x03: + len = 2; + break; + case 0x04: + len = 2; + break; + case 0x05: + len = 6; + break; + case 0x06: + len = 4; + break; + default: + len = 0; + break; + } + + if (i + len >= packetSize) { + TRACE(_T("Warning: Wrong subpicture parameter block ending\n")); + break; + } + + switch (lpData[i++]) { + case 0x00: // forced start displaying + bForced = true; + break; + case 0x01: // start displaying + bForced = false; + break; + case 0x02: // stop displaying + delay = tCurrent; + break; + case 0x03: + _pal = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + nPal++; + break; + case 0x04: + tr = (lpData[i] << 8) | lpData[i + 1]; + i += 2; + nTr++; + //tr &= 0x00f0; + break; + case 0x05: + rect = CRect((lpData[i] << 4) + (lpData[i + 1] >> 4), + (lpData[i + 3] << 4) + (lpData[i + 4] >> 4), + ((lpData[i + 1] & 0x0f) << 8) + lpData[i + 2] + 1, + ((lpData[i + 4] & 0x0f) << 8) + lpData[i + 5] + 1); + i += 6; + break; + case 0x06: + nOffset[0] = (lpData[i] << 8) + lpData[i + 1]; + i += 2; + nOffset[1] = (lpData[i] << 8) + lpData[i + 1]; + i += 2; + break; + case 0xff: // end of ctrlblk + bBreak = true; + continue; + default: // skip this ctrlblk + bBreak = true; + break; + } + } + } while (i <= nextctrlblk && i < packetSize); + + for (i = 0; i < 4; i++) { + this->pal[i].pal = (_pal >> (i << 2)) & 0xf; + this->pal[i].tr = (tr >> (i << 2)) & 0xf; + } + + bAnimated = (nPal > 1 || nTr > 1); +} + +BYTE CVobSubImage::GetNibble(const BYTE* lpData) +{ + size_t& off = nOffset[nPlane]; + BYTE ret = lpData[off]; + if (bAligned) { + ret >>= 4; + } + ret &= 0x0f; + bAligned = !bAligned; + if (bAligned) { + off++; + } + return ret; +} + +void CVobSubImage::DrawPixels(CPoint p, int length, size_t colorId) +{ + if (length <= 0 + || p.x + length < rect.left + || p.x >= rect.right + || p.y < rect.top + || p.y >= rect.bottom) { + return; + } + + if (p.x < rect.left) { + p.x = rect.left; + } + if (p.x + length >= rect.right) { + length = rect.right - p.x; + } + + RGBQUAD* ptr = &lpPixels[rect.Width() * (p.y - rect.top) + (p.x - rect.left)]; + + RGBQUAD c; + + if (!bCustomPal) { + c = orgpal[pal[colorId].pal]; + c.rgbReserved = (pal[colorId].tr << 4) | pal[colorId].tr; + } else { + c = cuspal[colorId]; + } + + while (length-- > 0) { + *ptr++ = c; + } +} + +void CVobSubImage::TrimSubImage() +{ + CRect r; + r.left = rect.Width(); + r.top = rect.Height(); + r.right = 0; + r.bottom = 0; + + RGBQUAD* ptr = lpTemp1; + + for (int j = 0, y = rect.Height(); j < y; j++) { + for (int i = 0, x = rect.Width(); i < x; i++, ptr++) { + if (ptr->rgbReserved) { + if (r.top > j) { + r.top = j; + } + if (r.bottom < j) { + r.bottom = j; + } + if (r.left > i) { + r.left = i; + } + if (r.right < i) { + r.right = i; + } + } + } + } + + if (r.left > r.right || r.top > r.bottom) { + return; + } + + r += CRect(0, 0, 1, 1); + + r &= CRect(CPoint(0, 0), rect.Size()); + + int w = r.Width(), h = r.Height(); + + DWORD offset = r.top * rect.Width() + r.left; + + r += CRect(1, 1, 1, 1); + + DWORD* src = (DWORD*)&lpTemp1[offset]; + DWORD* dst = (DWORD*)&lpTemp2[1 + w + 1]; + + ZeroMemory(lpTemp2, (1 + w + 1)*sizeof(RGBQUAD)); + + for (int height = h; height; height--, src += rect.Width()) { + *dst++ = 0; + memcpy(dst, src, w * sizeof(RGBQUAD)); + dst += w; + *dst++ = 0; + } + + ZeroMemory(dst, (1 + w + 1)*sizeof(RGBQUAD)); + + lpPixels = lpTemp2; + + rect = r + rect.TopLeft(); +} + +//////////////////////////////// + +#define GP(xx, yy) (((xx) < 0 || (yy) < 0 || (xx) >= w || (yy) >= h) ? 0 : p[(yy) * w + (xx)]) + +CAutoPtrList* CVobSubImage::GetOutlineList(CPoint& topleft) +{ + int w = rect.Width(), h = rect.Height(), len = w * h; + if (len <= 0) { + return nullptr; + } + + CAutoVectorPtr p; + if (!p.Allocate(len)) { + return nullptr; + } + + CAutoPtrList* ol; + try { + ol = DEBUG_NEW CAutoPtrList(); + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + return nullptr; + } + + BYTE* cp = p; + RGBQUAD* rgbp = (RGBQUAD*)lpPixels; + + for (int i = 0; i < len; i++, cp++, rgbp++) { + *cp = !!rgbp->rgbReserved; + } + + enum { UP, RIGHT, DOWN, LEFT }; + + topleft.x = topleft.y = INT_MAX; + + for (;;) { + cp = p; + + int x = 0; + int y = 0; + + for (y = 0; y < h; y++) { + for (x = 0; x < w - 1; x++, cp++) { + if (cp[0] == 0 && cp[1] == 1) { + break; + } + } + + if (x < w - 1) { + break; + } + + cp++; + } + + if (y == h) { + break; + } + + int dir = UP; + + int ox = x, oy = y, odir = dir; + + CAutoPtr o; + try { + o.Attach(DEBUG_NEW COutline); + } catch (CMemoryException* e) { + ASSERT(FALSE); + e->Delete(); + break; + } + + do { + CPoint pp; + BYTE fl = 0; + BYTE fr = 0; + BYTE br = 0; + + int prevdir = dir; + + switch (prevdir) { + case UP: + pp = CPoint(x + 1, y); + fl = GP(x, y - 1); + fr = GP(x + 1, y - 1); + br = GP(x + 1, y); + break; + case RIGHT: + pp = CPoint(x + 1, y + 1); + fl = GP(x + 1, y); + fr = GP(x + 1, y + 1); + br = GP(x, y + 1); + break; + case DOWN: + pp = CPoint(x, y + 1); + fl = GP(x, y + 1); + fr = GP(x - 1, y + 1); + br = GP(x - 1, y); + break; + case LEFT: + pp = CPoint(x, y); + fl = GP(x - 1, y); + fr = GP(x - 1, y - 1); + br = GP(x, y - 1); + break; + } + + // turning left if: + // o . | o . + // ^ o | < o + // turning right if: + // x x | x > + // ^ o | x o + // + // o set, x empty, . can be anything + + if (fl == 1) { + dir = (dir - 1 + 4) & 3; + } else if (fl != 1 && fr != 1 && br == 1) { + dir = (dir + 1) & 3; + } else if (p[y * w + x] & 16) { + ASSERT(0); // we are going around in one place (this must not happen if the starting conditions were correct) + break; + } + + p[y * w + x] = (p[y * w + x] << 1) | 2; // increase turn count (== log2(highordbit(*p))) + + switch (dir) { + case UP: + if (prevdir == LEFT) { + x--; + y--; + } + if (prevdir == UP) { + y--; + } + break; + case RIGHT: + if (prevdir == UP) { + x++; + y--; + } + if (prevdir == RIGHT) { + x++; + } + break; + case DOWN: + if (prevdir == RIGHT) { + x++; + y++; + } + if (prevdir == DOWN) { + y++; + } + break; + case LEFT: + if (prevdir == DOWN) { + x--; + y++; + } + if (prevdir == LEFT) { + x--; + } + break; + } + + int d = dir - prevdir; + o->Add(pp, d == 3 ? -1 : d == -3 ? 1 : d); + + if (topleft.x > pp.x) { + topleft.x = pp.x; + } + if (topleft.y > pp.y) { + topleft.y = pp.y; + } + } while (!(x == ox && y == oy && dir == odir)); + + if (!o->pa.IsEmpty() && (x == ox && y == oy && dir == odir)) { + ol->AddTail(o); + } else { + ASSERT(0); + } + } + + return ol; +} + +static bool FitLine(const COutline& o, int& start, int& end) +{ + int len = (int)o.pa.GetCount(); + if (len < 7) { + return false; // small segments should be handled with beziers... + } + + for (start = 0; start < len && !o.da[start]; start++) { + ; + } + for (end = len - 1; end > start && !o.da[end]; end--) { + ; + } + + if (end - start < 8 || end - start < (len - end) + (start - 0)) { + return false; + } + + CUIntArray la, ra; + + UINT i, j, k; + + for (i = start + 1, j = end, k = start; i <= j; i++) { + if (!o.da[i]) { + continue; + } + if (o.da[i] == o.da[k]) { + return false; + } + if (o.da[i] == -1) { + la.Add(i - k); + } else { + ra.Add(i - k); + } + k = i; + } + + bool fl = true, fr = true; + + // these tests are completly heuristic and might be redundant a bit... + + for (i = 0, j = (UINT)la.GetSize(); i < j && fl; i++) { + if (la[i] != 1) { + fl = false; + } + } + for (i = 0, j = (UINT)ra.GetSize(); i < j && fr; i++) { + if (ra[i] != 1) { + fr = false; + } + } + + if (!fl && !fr) { + return false; // can't be a line if there are bigger steps than one in both directions (lines are usually drawn by stepping one either horizontally or vertically) + } + if (fl && fr && 1.0 * (end - start) / ((len - end) * 2 + (start - 0) * 2) > 0.4) { + return false; // if this section is relatively too small it may only be a rounded corner + } + if (!fl && !la.IsEmpty() && la.GetSize() <= 4 && (la[0] == 1 && la[la.GetSize() - 1] == 1)) { + return false; // one step at both ends, doesn't sound good for a line (may be it was skewed, so only eliminate smaller sections where beziers going to look just as good) + } + if (!fr && !ra.IsEmpty() && ra.GetSize() <= 4 && (ra[0] == 1 && ra[ra.GetSize() - 1] == 1)) { + return false; // -''- + } + + CUIntArray& a = !fl ? la : ra; + + len = (int)a.GetSize(); + + int sum = 0; + + for (i = 0, j = INT_MAX, k = 0; i < (UINT)len; i++) { + if (j > a[i]) { + j = a[i]; + } + if (k < a[i]) { + k = a[i]; + } + sum += a[i]; + } + + if (k - j > 2 && 1.0 * sum / len < 2) { + return false; + } + if (k - j > 2 && 1.0 * sum / len >= 2 && len < 4) { + return false; + } + + if ((la.GetSize() / 2 + ra.GetSize() / 2) / 2 <= 2) { + if ((k + j) / 2 < 2 && k * j != 1) { + return false; + } + } + + double err = 0; + + CPoint sp = o.pa[start], ep = o.pa[end]; + + double minerr = 0, maxerr = 0; + + double vx = ep.x - sp.x, vy = ep.y - sp.y, l = sqrt(vx * vx + vy * vy); + vx /= l; + vy /= l; + + for (i = start + 1, j = end - 1; i <= j; i++) { + CPoint p = o.pa[i], dp = p - sp; + double t = vx * dp.x + vy * dp.y, dx = vx * t + sp.x - p.x, dy = vy * t + sp.y - p.y; + t = dx * dx + dy * dy; + err += t; + t = sqrt(t); + if (vy * dx - dy * vx < 0) { + if (minerr > -t) { + minerr = -t; + } + } else { + if (maxerr < t) { + maxerr = t; + } + } + } + + return ((maxerr - minerr) / l < 0.1 || err / l < 1.5 || (fabs(maxerr) < 8 && fabs(minerr) < 8)); +} + +static int CalcPossibleCurveDegree(const COutline& o) +{ + size_t len2 = o.da.GetCount(); + + CUIntArray la; + + for (size_t i = 0, j = 0; j < len2; j++) { + if (j + 1 == len2 || o.da[j]) { + la.Add(UINT(j - i)); + i = j; + } + } + + ptrdiff_t len = la.GetCount(); + + int ret = 0; + + // check if we can find a reason to add a penalty degree, or two :P + // it is mainly about looking for distant corners + { + int penalty = 0; + + int ma[2] = {0, 0}; + for (ptrdiff_t i = 0; i < len; i++) { + ma[i & 1] += la[i]; + } + + int ca[2] = {ma[0], ma[1]}; + for (ptrdiff_t i = 0; i < len; i++) { + ca[i & 1] -= la[i]; + + double c1 = 1.0 * ca[0] / ma[0], c2 = 1.0 * ca[1] / ma[1], c3 = 1.0 * la[i] / ma[i & 1]; + + if (len2 > 16 && (fabs(c1 - c2) > 0.7 || (c3 > 0.6 && la[i] > 5))) { + penalty = 2; + break; + } + + if (fabs(c1 - c2) > 0.6 || (c3 > 0.4 && la[i] > 5)) { + penalty = 1; + } + } + + ret += penalty; + } + + la[0] <<= 1; + la[len - 1] <<= 1; + + for (ptrdiff_t i = 0; i < len; i += 2) { + if (la[i] > 1) { + ret++; // prependicular to the last chosen section and bigger then 1 -> add a degree and continue with the other dir + i--; + } + } + + return ret; +} + +inline double vectlen(CPoint p) +{ + return sqrt((double)(p.x * p.x + p.y * p.y)); +} + +inline double vectlen(CPoint p1, CPoint p2) +{ + return vectlen(p2 - p1); +} + +static bool MinMaxCosfi(COutline& o, double& mincf, double& maxcf) // not really cosfi, it is weighted by the distance from the segment endpoints, and since it would be always between -1 and 0, the applied sign marks side +{ + CAtlArray& pa = o.pa; + + int len = (int)pa.GetCount(); + if (len < 6) { + return false; + } + + mincf = 1; + maxcf = -1; + + CPoint p = pa[len - 1] - pa[0]; + double l = vectlen(p); + UNREFERENCED_PARAMETER(l); + + for (ptrdiff_t i = 2; i < len - 2; i++) { // skip the endpoints, they aren't accurate + CPoint p1 = pa[0] - pa[i], p2 = pa[len - 1] - pa[i]; + double l1 = vectlen(p1), l2 = vectlen(p2); + int sign = p1.x * p.y - p1.y * p.x >= 0 ? 1 : -1; + + double c = (1.0 * len / 2 - fabs(i - 1.0 * len / 2)) / len * 2; // c: 0 -> 1 -> 0 + + double cosfi = (1 + (p1.x * p2.x + p1.y * p2.y) / (l1 * l2)) * sign * c; + if (mincf > cosfi) { + mincf = cosfi; + } + if (maxcf < cosfi) { + maxcf = cosfi; + } + } + + return true; +} + +static bool FitBezierVH(COutline& o, CPoint& p1, CPoint& p2) +{ + int i; + + CAtlArray& pa = o.pa; + + int len = (int)pa.GetCount(); + + if (len <= 1) { + return false; + } else if (len == 2) { + CPoint mid = pa[0] + pa[1]; + mid.x >>= 1; + mid.y >>= 1; + p1 = p2 = mid; + return true; + } + + CPoint dir1 = pa[1] - pa[0], dir2 = pa[len - 2] - pa[len - 1]; + if ((dir1.x && dir1.y) || (dir2.x && dir2.y)) { + return false; // we are only fitting beziers with hor./ver. endings + } + + if (CalcPossibleCurveDegree(o) > 3) { + return false; + } + + double mincf, maxcf; + if (MinMaxCosfi(o, mincf, maxcf)) { + if (maxcf - mincf > 0.8 + || maxcf - mincf > 0.6 && (maxcf >= 0.4 || mincf <= -0.4)) { + return false; + } + } + + CPoint p0 = p1 = pa[0]; + CPoint p3 = p2 = pa[len - 1]; + + CAtlArray pl; + pl.SetCount(len); + + double c10 = 0, c11 = 0, c12 = 0, c13 = 0, c1x = 0, c1y = 0; + double c20 = 0, c21 = 0, c22 = 0, c23 = 0, c2x = 0, c2y = 0; + double length = 0; + + for (pl[0] = 0, i = 1; i < len; i++) { + CPoint diff = (pa[i] - pa[i - 1]); + pl[i] = (length += sqrt((double)(diff.x * diff.x + diff.y * diff.y))); + } + + for (i = 0; i < len; i++) { + double t1 = pl[i] / length; + double t2 = t1 * t1; + double t3 = t2 * t1; + double it1 = 1 - t1; + double it2 = it1 * it1; + double it3 = it2 * it1; + + double dc1 = 3.0 * it2 * t1; + double dc2 = 3.0 * it1 * t2; + + c10 += it3 * dc1; + c11 += dc1 * dc1; + c12 += dc2 * dc1; + c13 += t3 * dc1; + c1x += pa[i].x * dc1; + c1y += pa[i].y * dc1; + + c20 += it3 * dc2; + c21 += dc1 * dc2; + c22 += dc2 * dc2; + c23 += t3 * dc2; + c2x += pa[i].x * dc2; + c2y += pa[i].y * dc2; + } + + if (dir1.y == 0 && dir2.x == 0) { + p1.x = (int)((c1x - c10 * p0.x - c12 * p3.x - c13 * p3.x) / c11 + 0.5); + p2.y = (int)((c2y - c20 * p0.y - c21 * p0.y - c23 * p3.y) / c22 + 0.5); + } else if (dir1.x == 0 && dir2.y == 0) { + p2.x = (int)((c2x - c20 * p0.x - c21 * p0.x - c23 * p3.x) / c22 + 0.5); + p1.y = (int)((c1y - c10 * p0.y - c12 * p3.y - c13 * p3.y) / c11 + 0.5); + } else if (dir1.y == 0 && dir2.y == 0) { + // cramer's rule + double D = c11 * c22 - c12 * c21; + p1.x = (int)(((c1x - c10 * p0.x - c13 * p3.x) * c22 - c12 * (c2x - c20 * p0.x - c23 * p3.x)) / D + 0.5); + p2.x = (int)((c11 * (c2x - c20 * p0.x - c23 * p3.x) - (c1x - c10 * p0.x - c13 * p3.x) * c21) / D + 0.5); + } else if (dir1.x == 0 && dir2.x == 0) { + // cramer's rule + double D = c11 * c22 - c12 * c21; + p1.y = (int)(((c1y - c10 * p0.y - c13 * p3.y) * c22 - c12 * (c2y - c20 * p0.y - c23 * p3.y)) / D + 0.5); + p2.y = (int)((c11 * (c2y - c20 * p0.y - c23 * p3.y) - (c1y - c10 * p0.y - c13 * p3.y) * c21) / D + 0.5); + } else { // must not happen + ASSERT(0); + return false; + } + + // check for "inside-out" beziers + CPoint dir3 = p1 - p0, dir4 = p2 - p3; + if ((dir1.x * dir3.x + dir1.y * dir3.y) <= 0 || (dir2.x * dir4.x + dir2.y * dir4.y) <= 0) { + return false; + } + + return true; +} + +int CVobSubImage::GrabSegment(int _start, const COutline& o, COutline& ret) +{ + ret.RemoveAll(); + + int len = int(o.pa.GetCount()); + + int cur = (_start) % len, first = -1, last = -1; + int lastDir = 0; + + for (ptrdiff_t i = 0; i < len; i++) { + cur = (cur + 1) % len; + + if (o.da[cur] == 0) { + continue; + } + + if (first == -1) { + first = cur; + } + + if (lastDir == o.da[cur]) { + CPoint startp = o.pa[first] + o.pa[_start]; + startp.x >>= 1; + startp.y >>= 1; + CPoint endp = o.pa[last] + o.pa[cur]; + endp.x >>= 1; + endp.y >>= 1; + + if (first < _start) { + first += len; + } + _start = ((_start + first) >> 1) + 1; + if (_start >= len) { + _start -= len; + } + if (cur < last) { + cur += len; + } + cur = ((last + cur + 1) >> 1); + if (cur >= len) { + cur -= len; + } + + ret.Add(startp, 0); + + while (_start != cur) { + ret.Add(o.pa[_start], o.da[_start]); + + _start++; + if (_start >= len) { + _start -= len; + } + } + + ret.Add(endp, 0); + + return last; + } + + lastDir = o.da[cur]; + last = cur; + } + + ASSERT(0); + + return _start; +} + +void CVobSubImage::SplitOutline(const COutline& o, COutline& o1, COutline& o2) +{ + size_t len = o.pa.GetCount(); + if (len < 4) { + return; + } + + CAtlArray la, sa, ea; + + size_t i, j, k; + + for (i = 0, j = 0; j < len; j++) { + if (j + 1 == len || o.da[j]) { + la.Add(unsigned int(j - i)); + sa.Add(unsigned int(i)); + ea.Add(unsigned int(j)); + i = j; + } + } + + size_t maxlen = 0, maxidx = SIZE_T_ERROR; + size_t maxlen2 = 0, maxidx2 = SIZE_T_ERROR; + + for (i = 0; i < la.GetCount(); i++) { + if (maxlen < la[i]) { + maxlen = la[i]; + maxidx = i; + } + + if (maxlen2 < la[i] && i > 0 && i < la.GetCount() - 1) { + maxlen2 = la[i]; + maxidx2 = i; + } + } + + ASSERT(maxidx != SIZE_T_ERROR && maxidx2 != SIZE_T_ERROR); + + if (maxlen == maxlen2) { + maxidx = maxidx2; // if equal choose the inner section + } + + j = (sa[maxidx] + ea[maxidx]) >> 1, k = (sa[maxidx] + ea[maxidx] + 1) >> 1; + + o1.RemoveAll(); + o2.RemoveAll(); + + for (i = 0; i <= j; i++) { + o1.Add(o.pa[i], o.da[i]); + } + + if (j != k) { + CPoint mid = o.pa[j] + o.pa[k]; + mid.x >>= 1; + mid.y >>= 1; + o1.Add(mid, 0); + o2.Add(mid, 0); + } + + for (i = k; i < len; i++) { + o2.Add(o.pa[i], o.da[i]); + } +} + +void CVobSubImage::AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints) +{ + int i, len = int(o.pa.GetCount()); + if (len < 3) { + return; + } + + int nLeftTurns = 0, nRightTurns = 0; + + for (i = 0; i < len; i++) { + if (o.da[i] == -1) { + nLeftTurns++; + } else if (o.da[i] == 1) { + nRightTurns++; + } + } + + if (nLeftTurns == 0 && nRightTurns == 0) { // line + pathTypes.Add(PT_LINETO); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + if (nLeftTurns == 0 || nRightTurns == 0) { // b-spline + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); + + for (i = 0; i < 3; i++) { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[i]); + } + + for (; i < len; i++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[i]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + int _start, _end; + if (FitLine(o, _start, _end)) { // b-spline, line, b-spline + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[0] + (o.pa[0] - o.pa[1])); + + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[0]); + + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[1]); + + CPoint p[4], pp, d = o.pa[_end] - o.pa[_start]; + double l = sqrt((double)(d.x * d.x + d.y * d.y)), dx = 1.0 * d.x / l, dy = 1.0 * d.y / l; + + pp = o.pa[_start] - o.pa[_start - 1]; + double l1 = abs(pp.x) + abs(pp.y); + pp = o.pa[_end] - o.pa[_end + 1]; + double l2 = abs(pp.x) + abs(pp.y); + p[0] = CPoint((int)(1.0 * o.pa[_start].x + dx * l1 + 0.5), (int)(1.0 * o.pa[_start].y + dy * l1 + 0.5)); + p[1] = CPoint((int)(1.0 * o.pa[_start].x + dx * l1 * 2 + 0.5), (int)(1.0 * o.pa[_start].y + dy * l1 * 2 + 0.5)); + p[2] = CPoint((int)(1.0 * o.pa[_end].x - dx * l2 * 2 + 0.5), (int)(1.0 * o.pa[_end].y - dy * l2 * 2 + 0.5)); + p[3] = CPoint((int)(1.0 * o.pa[_end].x - dx * l2 + 0.5), (int)(1.0 * o.pa[_end].y - dy * l2 + 0.5)); + + if (_start == 1) { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(p[0]); + } else { + pathTypes.Add(PT_BSPLINETO); + pathPoints.Add(o.pa[2]); + + for (ptrdiff_t k = 3; k <= _start; k++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[k]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[0]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[1]); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(p[0]); + + pathTypes.Add(PT_LINETO); + pathPoints.Add(p[3]); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(p[2]); + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(p[3]); + + for (i = _end; i < len; i++) { + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[i]); + } + + pathTypes.Add(PT_BSPLINEPATCHTO); + pathPoints.Add(o.pa[len - 1] + (o.pa[len - 1] - o.pa[len - 2])); + + pathTypes.Add(PT_MOVETONC); + pathPoints.Add(o.pa[len - 1]); + + return; + } + + CPoint p1, p2; + if (FitBezierVH(o, p1, p2)) { // bezier + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(p1); + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(p2); + pathTypes.Add(PT_BEZIERTO); + pathPoints.Add(o.pa[o.pa.GetCount() - 1]); + + return; + } + + COutline o1, o2; + SplitOutline(o, o1, o2); + AddSegment(o1, pathTypes, pathPoints); + AddSegment(o2, pathTypes, pathPoints); +} + +bool CVobSubImage::Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool bSmooth, int scale) +{ + CPoint topleft; + CAutoPtr> ol(GetOutlineList(topleft)); + if (!ol) { + return false; + } + + POSITION pos; + + pos = ol->GetHeadPosition(); + while (pos) { + CAtlArray& pa = ol->GetNext(pos)->pa; + for (size_t i = 0; i < pa.GetCount(); i++) { + pa[i].x = (pa[i].x - topleft.x) << scale; + pa[i].y = (pa[i].y - topleft.y) << scale; + } + } + + pos = ol->GetHeadPosition(); + while (pos) { + COutline& o = *ol->GetNext(pos), o2; + + if (bSmooth) { + int i = 0, iFirst = -1; + + for (;;) { + i = GrabSegment(i, o, o2); + + if (i == iFirst) { + break; + } + + if (iFirst < 0) { + iFirst = i; + pathTypes.Add(PT_MOVETO); + pathPoints.Add(o2.pa[0]); + } + + AddSegment(o2, pathTypes, pathPoints); + } + } else { + /* + for (ptrdiff_t i = 1, len = o.pa.GetSize(); i < len; i++) + { + if (int dir = o.da[i-1]) + { + CPoint dir2 = o.pa[i] - o.pa[i-1]; + dir2.x /= 2; dir2.y /= 2; + CPoint dir1 = dir > 0 ? CPoint(dir2.y, -dir2.x) : CPoint(-dir2.y, dir2.x); + i = i; + o.pa[i-1] -= dir1; + o.pa.InsertAt(i, o.pa[i-1] + dir2); + o.da.InsertAt(i, -dir); + o.pa.InsertAt(i+1, o.pa[i] + dir1); + o.da.InsertAt(i+1, dir); + i += 2; + len += 2; + } + } + */ + pathTypes.Add(PT_MOVETO); + pathPoints.Add(o.pa[0]); + + for (size_t i = 1, len = o.pa.GetCount(); i < len; i++) { + pathTypes.Add(PT_LINETO); + pathPoints.Add(o.pa[i]); + } + } + } + + return !pathTypes.IsEmpty(); +} + +bool CVobSubImage::Polygonize(CStringW& assstr, bool bSmooth, int scale) +{ + CAtlArray pathTypes; + CAtlArray pathPoints; + + if (!Polygonize(pathTypes, pathPoints, bSmooth, scale)) { + return false; + } + + assstr.Format(L"{\\an7\\pos(%d,%d)\\p%d}", rect.left, rect.top, 1 + scale); + // assstr.Format(L"{\\p%d}", 1+scale); + + BYTE lastType = 0; + + size_t nPoints = pathTypes.GetCount(); + + for (size_t i = 0; i < nPoints; i++) { + CStringW s; + + switch (pathTypes[i]) { + case PT_MOVETO: + if (lastType != PT_MOVETO) { + assstr += L"m "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_MOVETONC: + if (lastType != PT_MOVETONC) { + assstr += L"n "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_LINETO: + if (lastType != PT_LINETO) { + assstr += L"l "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + case PT_BEZIERTO: + if (i + 2 < nPoints) { + if (lastType != PT_BEZIERTO) { + assstr += L"b "; + } + s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); + i += 2; + } + break; + case PT_BSPLINETO: + if (i + 2 < nPoints) { + if (lastType != PT_BSPLINETO) { + assstr += L"s "; + } + s.Format(L"%ld %ld %ld %ld %ld %ld ", pathPoints[i].x, pathPoints[i].y, pathPoints[i + 1].x, pathPoints[i + 1].y, pathPoints[i + 2].x, pathPoints[i + 2].y); + i += 2; + } + break; + case PT_BSPLINEPATCHTO: + if (lastType != PT_BSPLINEPATCHTO) { + assstr += L"p "; + } + s.Format(L"%ld %ld ", pathPoints[i].x, pathPoints[i].y); + break; + } + + lastType = pathTypes[i]; + + assstr += s; + } + + assstr += L"{\\p0}"; + + return nPoints > 0; +} + +void CVobSubImage::Scale2x() +{ + int w = rect.Width(), h = rect.Height(); + + if (w > 0 && h > 0) { + DWORD* src = (DWORD*)lpPixels; + DWORD* dst = DEBUG_NEW DWORD[w * h]; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++, src++, dst++) { + DWORD E = *src; + + DWORD A = x > 0 && y > 0 ? src[-w - 1] : E; + DWORD B = y > 0 ? src[-w] : E; + DWORD C = x < w - 1 && y > 0 ? src[-w + 1] : E; + UNREFERENCED_PARAMETER(A); + UNREFERENCED_PARAMETER(C); + + DWORD D = x > 0 ? src[-1] : E; + DWORD F = x < w - 1 ? src[+1] : E; + + DWORD G = x > 0 && y < h - 1 ? src[+w - 1] : E; + DWORD H = y < h - 1 ? src[+w] : E; + DWORD I = x < w - 1 && y < h - 1 ? src[+w + 1] : E; + UNREFERENCED_PARAMETER(G); + UNREFERENCED_PARAMETER(I); + + DWORD E0 = D == B && B != F && D != H ? D : E; + DWORD E1 = B == F && B != D && F != H ? F : E; + DWORD E2 = D == H && D != B && H != F ? D : E; + DWORD E3 = H == F && D != H && B != F ? F : E; + + *dst = ((((E0 & 0x00ff00ff) + (E1 & 0x00ff00ff) + (E2 & 0x00ff00ff) + (E3 & 0x00ff00ff) + 2) >> 2) & 0x00ff00ff) + | (((((E0 >> 8) & 0x00ff00ff) + ((E1 >> 8) & 0x00ff00ff) + ((E2 >> 8) & 0x00ff00ff) + ((E3 >> 8) & 0x00ff00ff) + 2) << 6) & 0xff00ff00); + } + } + + src -= w * h; + dst -= w * h; + + memcpy(src, dst, w * h * 4); + + delete [] dst; + } +} diff --git a/src/Subtitles/VobSubImage.h b/src/Subtitles/VobSubImage.h index 6665668ee18..bee6464321e 100644 --- a/src/Subtitles/VobSubImage.h +++ b/src/Subtitles/VobSubImage.h @@ -1,96 +1,96 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include - -struct COutline { - CAtlArray pa; - CAtlArray da; - void RemoveAll() { - pa.RemoveAll(); - da.RemoveAll(); - } - void Add(CPoint p, int d) { - pa.Add(p); - da.Add(d); - } -}; - -class CVobSubImage -{ - friend class CVobSubFile; - -private: - CSize org; - RGBQUAD* lpTemp1; - RGBQUAD* lpTemp2; - - size_t nOffset[2], nPlane; - bool bCustomPal; - bool bAligned; - int tridx; - RGBQUAD* orgpal /*[16]*/, * cuspal /*[4]*/; - - bool Alloc(int w, int h); - void Free(); - - BYTE GetNibble(const BYTE* lpData); - void DrawPixels(CPoint p, int length, size_t colorId); - void TrimSubImage(); - -public: - size_t nLang, nIdx; - bool bForced, bAnimated; - int tCurrent; - __int64 start, delay; - CRect rect; - struct SubPal { - BYTE pal: 4, tr: 4; - }; - SubPal pal[4]; - RGBQUAD* lpPixels; - - CVobSubImage(); - virtual ~CVobSubImage(); - - void Invalidate() { nLang = nIdx = SIZE_T_ERROR; } - - void GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t = INT_MAX); - bool Decode(BYTE* lpData, size_t packetSize, size_t dataSize, int t, - bool bCustomPal, - int tridx, - RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/, - bool bTrim); - -private: - CAutoPtrList* GetOutlineList(CPoint& topleft); - int GrabSegment(int start, const COutline& o, COutline& ret); - void SplitOutline(const COutline& o, COutline& o1, COutline& o2); - void AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints); - -public: - bool Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool bSmooth, int scale); - bool Polygonize(CStringW& assstr, bool bSmooth = true, int scale = 3); - - void Scale2x(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include + +struct COutline { + CAtlArray pa; + CAtlArray da; + void RemoveAll() { + pa.RemoveAll(); + da.RemoveAll(); + } + void Add(CPoint p, int d) { + pa.Add(p); + da.Add(d); + } +}; + +class CVobSubImage +{ + friend class CVobSubFile; + +private: + CSize org; + RGBQUAD* lpTemp1; + RGBQUAD* lpTemp2; + + size_t nOffset[2], nPlane; + bool bCustomPal; + bool bAligned; + int tridx; + RGBQUAD* orgpal /*[16]*/, * cuspal /*[4]*/; + + bool Alloc(int w, int h); + void Free(); + + BYTE GetNibble(const BYTE* lpData); + void DrawPixels(CPoint p, int length, size_t colorId); + void TrimSubImage(); + +public: + size_t nLang, nIdx; + bool bForced, bAnimated; + int tCurrent; + __int64 start, delay; + CRect rect; + struct SubPal { + BYTE pal: 4, tr: 4; + }; + SubPal pal[4]; + RGBQUAD* lpPixels; + + CVobSubImage(); + virtual ~CVobSubImage(); + + void Invalidate() { nLang = nIdx = SIZE_T_ERROR; } + + void GetPacketInfo(const BYTE* lpData, size_t packetSize, size_t dataSize, int t = INT_MAX); + bool Decode(BYTE* lpData, size_t packetSize, size_t dataSize, int t, + bool bCustomPal, + int tridx, + RGBQUAD* orgpal /*[16]*/, RGBQUAD* cuspal /*[4]*/, + bool bTrim); + +private: + CAutoPtrList* GetOutlineList(CPoint& topleft); + int GrabSegment(int start, const COutline& o, COutline& ret); + void SplitOutline(const COutline& o, COutline& o1, COutline& o2); + void AddSegment(COutline& o, CAtlArray& pathTypes, CAtlArray& pathPoints); + +public: + bool Polygonize(CAtlArray& pathTypes, CAtlArray& pathPoints, bool bSmooth, int scale); + bool Polygonize(CStringW& assstr, bool bSmooth = true, int scale = 3); + + void Scale2x(); +}; diff --git a/src/Subtitles/stdafx.cpp b/src/Subtitles/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/Subtitles/stdafx.cpp +++ b/src/Subtitles/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/Subtitles/stdafx.h b/src/Subtitles/stdafx.h index eb9cc29dc39..de33d75ce66 100644 --- a/src/Subtitles/stdafx.h +++ b/src/Subtitles/stdafx.h @@ -1,43 +1,43 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components -#include - -#include "BaseClasses/streams.h" - -#include "../DSUtil/DSUtil.h" -#include -#include -#include -#include -#include -#include -#include +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components +#include + +#include "BaseClasses/streams.h" + +#include "../DSUtil/DSUtil.h" +#include +#include +#include +#include +#include +#include +#include diff --git a/src/YASM.props b/src/YASM.props index aa361845b12..b47f531ba8c 100644 --- a/src/YASM.props +++ b/src/YASM.props @@ -1,35 +1,35 @@ - - - - Midl - CustomBuild - - - _SelectedFiles;$(YASMDependsOn) - - - - yasm.exe -X vc [Platform] [Debug] [Defines] [IncludePaths] -o "$(IntDir)%(Filename).obj" "%(FullPath)" - $(IntDir)%(Filename).obj - YASM: Assembling %(Filename)%(Extension) - False - - - - - win32 - - - - - win64 - - - - - True - - + + + + Midl + CustomBuild + + + _SelectedFiles;$(YASMDependsOn) + + + + yasm.exe -X vc [Platform] [Debug] [Defines] [IncludePaths] -o "$(IntDir)%(Filename).obj" "%(FullPath)" + $(IntDir)%(Filename).obj + YASM: Assembling %(Filename)%(Extension) + False + + + + + win32 + + + + + win64 + + + + + True + + \ No newline at end of file diff --git a/src/YASM.targets b/src/YASM.targets index 45663c9389d..b6c857ed579 100644 --- a/src/YASM.targets +++ b/src/YASM.targets @@ -1,85 +1,85 @@ - - - - - - _YASM - - - - $(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml - - - - - - - - @(YASM, '|') - - - - - - - - - $(ComputeLinkInputsTargets); - ComputeYASMOutput; - - - $(ComputeLibInputsTargets); - ComputeYASMOutput; - - - - - - - - - - - + + + + + + _YASM + + + + $(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml + + + + + + + + @(YASM, '|') + + + + + + + + + $(ComputeLinkInputsTargets); + ComputeYASMOutput; + + + $(ComputeLibInputsTargets); + ComputeYASMOutput; + + + + + + + + + + + \ No newline at end of file diff --git a/src/YASM.xml b/src/YASM.xml index 39a50bd5bbe..510b2065fbd 100644 --- a/src/YASM.xml +++ b/src/YASM.xml @@ -1,149 +1,149 @@ - - - - - - - - - - General - - - - - Command Line - - - - - - + + + + + + + + + General + + + + + Command Line + + + + + + - - - - - - - - - Execute Before - - - Specifies the targets for the build customization to run before. - - - - - - - - - - - Execute After - - - Specifies the targets for the build customization to run after. - - - - - - - - - - - - + + + + + + + + + Execute Before + + + Specifies the targets for the build customization to run before. + + + + + + + + + + + Execute After + + + Specifies the targets for the build customization to run after. + + + + + + + + + + + + - - - Additional Options - - - Additional Options - - - - - - + Switch="-I "[value]"" /> + + + Additional Options + + + Additional Options + + + + + + \ No newline at end of file diff --git a/src/common.props b/src/common.props index 91fda207f75..4e2e30ec11e 100644 --- a/src/common.props +++ b/src/common.props @@ -1,96 +1,96 @@ - - - - $(SolutionDir)bin\obj\$(Configuration)_$(PlatformName)\$(ProjectName)\ - $(SolutionDir)bin\lib\$(Configuration)_$(PlatformName)\ - $(SolutionDir)bin\Filters_x86_Debug\ - $(SolutionDir)bin\Filters_x64_Debug\ - $(SolutionDir)bin\Filters_x86\ - $(SolutionDir)bin\Filters_x64\ - true - false - True - - - - stdcpp17 - /w34127 /w34701 /w34706 /Zo /Zc:inline,referenceBinding,rvalueCast,ternary,throwingNew /Gw %(AdditionalOptions) - /wd4005 /wd6031 /wd6246 /wd6309 /wd6387 /wd28204 %(AdditionalOptions) - true - true - Sync - true - true - Use - stdafx.h - _WINDOWS;WINDOWS;WINVER=0x06010000;_WIN32_WINNT=0x06010000;_WIN32_IE=0x0800;PSAPI_VERSION=1;_USE_MATH_DEFINES;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) - NOMINMAX;%(PreprocessorDefinitions) - STANDALONE_FILTER;_USRDLL;_AFX_NO_MFC_CONTROLS_IN_DIALOGS;%(PreprocessorDefinitions) - WIN32;%(PreprocessorDefinitions) - _WIN64;WIN64;%(PreprocessorDefinitions) - Level3 - - - MachineX86 - MachineX64 - - - true - Debug - true - Windows - MachineX86 - MachineX64 - notelemetry.obj;%(AdditionalDependencies) - - - 0x0409 - WIN32;%(PreprocessorDefinitions) - _WIN64;%(PreprocessorDefinitions) - - - - - EnableFastChecks - EditAndContinue - ProgramDatabase - Disabled - _DEBUG;DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug - - - _DEBUG;%(PreprocessorDefinitions) - - - false - DebugFastLink - - - - - ProgramDatabase - StreamingSIMDExtensions2 - AnySuitable - true - Speed - MaxSpeed - NDEBUG;%(PreprocessorDefinitions) - MultiThreaded - true - true - - - true - - - /OPT:ICF=3 %(AdditionalOptions) - true - UseFastLinkTimeCodeGeneration - true - true - - - NDEBUG;%(PreprocessorDefinitions) - - - + + + + $(SolutionDir)bin\obj\$(Configuration)_$(PlatformName)\$(ProjectName)\ + $(SolutionDir)bin\lib\$(Configuration)_$(PlatformName)\ + $(SolutionDir)bin\Filters_x86_Debug\ + $(SolutionDir)bin\Filters_x64_Debug\ + $(SolutionDir)bin\Filters_x86\ + $(SolutionDir)bin\Filters_x64\ + true + false + True + + + + stdcpp17 + /w34127 /w34701 /w34706 /Zo /Zc:inline,referenceBinding,rvalueCast,ternary,throwingNew /Gw %(AdditionalOptions) + /wd4005 /wd6031 /wd6246 /wd6309 /wd6387 /wd28204 %(AdditionalOptions) + true + true + Sync + true + true + Use + stdafx.h + _WINDOWS;WINDOWS;WINVER=0x06010000;_WIN32_WINNT=0x06010000;_WIN32_IE=0x0800;PSAPI_VERSION=1;_USE_MATH_DEFINES;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) + NOMINMAX;%(PreprocessorDefinitions) + STANDALONE_FILTER;_USRDLL;_AFX_NO_MFC_CONTROLS_IN_DIALOGS;%(PreprocessorDefinitions) + WIN32;%(PreprocessorDefinitions) + _WIN64;WIN64;%(PreprocessorDefinitions) + Level3 + + + MachineX86 + MachineX64 + + + true + Debug + true + Windows + MachineX86 + MachineX64 + notelemetry.obj;%(AdditionalDependencies) + + + 0x0409 + WIN32;%(PreprocessorDefinitions) + _WIN64;%(PreprocessorDefinitions) + + + + + EnableFastChecks + EditAndContinue + ProgramDatabase + Disabled + _DEBUG;DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebug + + + _DEBUG;%(PreprocessorDefinitions) + + + false + DebugFastLink + + + + + ProgramDatabase + StreamingSIMDExtensions2 + AnySuitable + true + Speed + MaxSpeed + NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + true + + + true + + + /OPT:ICF=3 %(AdditionalOptions) + true + UseFastLinkTimeCodeGeneration + true + true + + + NDEBUG;%(PreprocessorDefinitions) + + + diff --git a/src/filters/FilterApp.cpp b/src/filters/FilterApp.cpp index 4ac03a34c33..b7a2c899fbe 100644 --- a/src/filters/FilterApp.cpp +++ b/src/filters/FilterApp.cpp @@ -1,52 +1,52 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include "FilterApp.h" - -extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); - -CFilterApp::CFilterApp() -{ -} - -BOOL CFilterApp::InitInstance() -{ - if (!__super::InitInstance()) { - return FALSE; - } - - SetRegistryKey(_T("Gabest")); - - DllEntryPoint(AfxGetInstanceHandle(), DLL_PROCESS_ATTACH, 0); - - return TRUE; -} - -BOOL CFilterApp::ExitInstance() -{ - DllEntryPoint(AfxGetInstanceHandle(), DLL_PROCESS_DETACH, 0); - - return __super::ExitInstance(); -} - -BEGIN_MESSAGE_MAP(CFilterApp, CWinApp) -END_MESSAGE_MAP() +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include "FilterApp.h" + +extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); + +CFilterApp::CFilterApp() +{ +} + +BOOL CFilterApp::InitInstance() +{ + if (!__super::InitInstance()) { + return FALSE; + } + + SetRegistryKey(_T("Gabest")); + + DllEntryPoint(AfxGetInstanceHandle(), DLL_PROCESS_ATTACH, 0); + + return TRUE; +} + +BOOL CFilterApp::ExitInstance() +{ + DllEntryPoint(AfxGetInstanceHandle(), DLL_PROCESS_DETACH, 0); + + return __super::ExitInstance(); +} + +BEGIN_MESSAGE_MAP(CFilterApp, CWinApp) +END_MESSAGE_MAP() diff --git a/src/filters/FilterApp.h b/src/filters/FilterApp.h index 3997ea2f558..dcd8f97cd4e 100644 --- a/src/filters/FilterApp.h +++ b/src/filters/FilterApp.h @@ -1,33 +1,33 @@ -/* - * (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 . - * - */ - -#pragma once - -class CFilterApp : public CWinApp -{ -public: - CFilterApp(); - - BOOL InitInstance(); - BOOL ExitInstance(); - - DECLARE_MESSAGE_MAP() -}; +/* + * (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 . + * + */ + +#pragma once + +class CFilterApp : public CWinApp +{ +public: + CFilterApp(); + + BOOL InitInstance(); + BOOL ExitInstance(); + + DECLARE_MESSAGE_MAP() +}; diff --git a/src/filters/Filters.h b/src/filters/Filters.h index a859d9cf258..0eafc3e8e6c 100644 --- a/src/filters/Filters.h +++ b/src/filters/Filters.h @@ -1,38 +1,38 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "muxer/DSMMuxer/DSMMuxer.h" -#include "muxer/MatroskaMuxer/MatroskaMuxer.h" -#include "muxer/WavDest/WavDest.h" -#include "parser/DSMSplitter/DSMSplitter.h" -#include "parser/StreamDriveThru/StreamDriveThru.h" -#include "reader/CDDAReader/CDDAReader.h" -#include "reader/CDXAReader/CDXAReader.h" -#include "reader/VTSReader/VTSReader.h" -#include "renderer/SyncClock/SyncClock.h" -#include "source/SubtitleSource/SubtitleSource.h" -#include "switcher/AudioSwitcher/AudioSwitcher.h" -#include "transform/AVI2AC3Filter/AVI2AC3Filter.h" -#include "transform/BufferFilter/BufferFilter.h" -#include "transform/DeCSSFilter/DeCSSFilter.h" -#include "RARFileSource/RFS.h" +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "muxer/DSMMuxer/DSMMuxer.h" +#include "muxer/MatroskaMuxer/MatroskaMuxer.h" +#include "muxer/WavDest/WavDest.h" +#include "parser/DSMSplitter/DSMSplitter.h" +#include "parser/StreamDriveThru/StreamDriveThru.h" +#include "reader/CDDAReader/CDDAReader.h" +#include "reader/CDXAReader/CDXAReader.h" +#include "reader/VTSReader/VTSReader.h" +#include "renderer/SyncClock/SyncClock.h" +#include "source/SubtitleSource/SubtitleSource.h" +#include "switcher/AudioSwitcher/AudioSwitcher.h" +#include "transform/AVI2AC3Filter/AVI2AC3Filter.h" +#include "transform/BufferFilter/BufferFilter.h" +#include "transform/DeCSSFilter/DeCSSFilter.h" +#include "RARFileSource/RFS.h" diff --git a/src/filters/Filters.vcxproj b/src/filters/Filters.vcxproj index fdcf00f9045..4bf90f69f49 100644 --- a/src/filters/Filters.vcxproj +++ b/src/filters/Filters.vcxproj @@ -1,75 +1,75 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {273B3149-3192-4B75-A791-470320B90812} - Filters - MFCProj - Filters - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\thirdparty;..\DSUtil;..\filters\renderer\VideoRenderers;..\..\Include;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - Create - - - - - - - - - - - - {981574ae-5a5e-4f27-bdf1-1b841e374cff} - false - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {273B3149-3192-4B75-A791-470320B90812} + Filters + MFCProj + Filters + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\thirdparty;..\DSUtil;..\filters\renderer\VideoRenderers;..\..\Include;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + Create + + + + + + + + + + + + {981574ae-5a5e-4f27-bdf1-1b841e374cff} + false + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/filters/Filters.vcxproj.filters b/src/filters/Filters.vcxproj.filters index f153249f14f..d5e04f35298 100644 --- a/src/filters/Filters.vcxproj.filters +++ b/src/filters/Filters.vcxproj.filters @@ -1,44 +1,44 @@ - - - - - {f8b5bbc2-2fe8-4b4f-bc46-236e4ad3d92d} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {d27517d8-49af-491a-b3a8-9a7531f9cc28} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {f8b5bbc2-2fe8-4b4f-bc46-236e4ad3d92d} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {d27517d8-49af-491a-b3a8-9a7531f9cc28} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/InternalPropertyPage.cpp b/src/filters/InternalPropertyPage.cpp index 64b2779fe26..d2b8efe293e 100644 --- a/src/filters/InternalPropertyPage.cpp +++ b/src/filters/InternalPropertyPage.cpp @@ -1,357 +1,357 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "InternalPropertyPage.h" -#include "../DSUtil/DSUtil.h" - - -// -// CInternalPropertyPageWnd -// - -void CInternalPropertyPageWnd::CalcTextRect(CRect& rect, long x, long y, long w, long border) -{ - rect.left = x; - rect.top = y; - rect.right = x + w; - rect.bottom = y + border; - m_dpi.ScaleRect(rect); - rect.bottom += m_fontheight; -} - -void CInternalPropertyPageWnd::CalcRect(CRect& rect, long x, long y, long w, long h) -{ - rect.left = x; - rect.top = y; - rect.right = x + w; - rect.bottom = y + h; - m_dpi.ScaleRect(rect); -} -CInternalPropertyPageWnd::CInternalPropertyPageWnd() - : m_fDirty(false) - , m_fontheight(IPP_FONTSIZE) -{ -} - -BOOL CInternalPropertyPageWnd::Create(IPropertyPageSite* pPageSite, LPCRECT pRect, CWnd* pParentWnd) -{ - if (!pPageSite || !pRect) { - return FALSE; - } - - m_pPageSite = pPageSite; - - if (!m_font.m_hObject) { - CString face; - WORD height; - extern BOOL AFXAPI AfxGetPropSheetFont(CString & strFace, WORD & wSize, BOOL bWizard); // yay - if (!AfxGetPropSheetFont(face, height, FALSE)) { - return FALSE; - } - - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - _tcscpy_s(lf.lfFaceName, face); - HDC hDC = ::GetDC(nullptr); - lf.lfHeight = -MulDiv(height, GetDeviceCaps(hDC, LOGPIXELSY), 72); - ::ReleaseDC(nullptr, hDC); - lf.lfWeight = FW_NORMAL; - lf.lfCharSet = DEFAULT_CHARSET; - if (!m_font.CreateFontIndirect(&lf)) { - return FALSE; - } - - lf.lfHeight -= -1; - _tcscpy_s(lf.lfFaceName, _T("Lucida Console")); - if (!m_monospacefont.CreateFontIndirect(&lf)) { - _tcscpy_s(lf.lfFaceName, _T("Courier New")); - if (!m_monospacefont.CreateFontIndirect(&lf)) { - return FALSE; - } - } - - hDC = ::GetDC(nullptr); - HFONT hFontOld = (HFONT)::SelectObject(hDC, m_font.m_hObject); - CSize size; - ::GetTextExtentPoint32(hDC, _T("x"), 1, &size); - ::SelectObject(hDC, hFontOld); - ::ReleaseDC(nullptr, hDC); - - m_fontheight = size.cy; - } - - LPCTSTR wc = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS, 0, (HBRUSH)(COLOR_BTNFACE + 1)); - if (!CreateEx(0, wc, _T("CInternalPropertyPageWnd"), WS_CHILDWINDOW, *pRect, pParentWnd, 0)) { - return FALSE; - } - - SetFont(&m_font); - - return TRUE; -} - -BOOL CInternalPropertyPageWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) -{ - if (message == WM_COMMAND || message == WM_HSCROLL || message == WM_VSCROLL) { - WORD notify = HIWORD(wParam); - // check only notifications that change the state of a control, otherwise false positives are possible. - if (notify == BN_CLICKED - || notify == CBN_SELCHANGE - || notify == EN_CHANGE - || notify == CLBN_CHKCHANGE) { - SetDirty(true); - } - } - - return __super::OnWndMsg(message, wParam, lParam, pResult); -} - -BEGIN_MESSAGE_MAP(CInternalPropertyPageWnd, CWnd) -END_MESSAGE_MAP() - -// -// CInternalPropertyPage -// - -CInternalPropertyPage::CInternalPropertyPage(LPUNKNOWN lpunk, HRESULT* phr) - : CUnknown(_T("CInternalPropertyPage"), lpunk) - , m_pWnd(nullptr) -{ - if (phr) { - *phr = S_OK; - } -} - -CInternalPropertyPage::~CInternalPropertyPage() -{ - if (m_pWnd) { - if (m_pWnd->m_hWnd) { - ASSERT(0); - m_pWnd->DestroyWindow(); - } - delete m_pWnd; - m_pWnd = nullptr; - } -} - -STDMETHODIMP CInternalPropertyPage::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI2(IPropertyPage) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IPropertyPage - -STDMETHODIMP CInternalPropertyPage::SetPageSite(IPropertyPageSite* pPageSite) -{ - CAutoLock cAutoLock(this); - - if (pPageSite && m_pPageSite || !pPageSite && !m_pPageSite) { - return E_UNEXPECTED; - } - - m_pPageSite = pPageSite; - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Activate(HWND hwndParent, LPCRECT pRect, BOOL fModal) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - CheckPointer(pRect, E_POINTER); - - if (!m_pWnd || m_pWnd->m_hWnd || m_pUnks.IsEmpty()) { - return E_UNEXPECTED; - } - - if (!m_pWnd->Create(m_pPageSite, pRect, CWnd::FromHandle(hwndParent))) { - return E_OUTOFMEMORY; - } - - if (!m_pWnd->OnActivate()) { - m_pWnd->DestroyWindow(); - return E_FAIL; - } - - m_pWnd->ModifyStyleEx(WS_EX_DLGMODALFRAME, WS_EX_CONTROLPARENT); - m_pWnd->ShowWindow(SW_SHOWNORMAL); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Deactivate() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - if (!m_pWnd || !m_pWnd->m_hWnd) { - return E_UNEXPECTED; - } - - m_pWnd->OnDeactivate(); - - m_pWnd->ModifyStyleEx(WS_EX_CONTROLPARENT, 0); - m_pWnd->DestroyWindow(); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::GetPageInfo(PROPPAGEINFO* pPageInfo) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPageInfo, E_POINTER); - - LPOLESTR pszTitle; - HRESULT hr = AMGetWideString(CStringW(GetWindowTitle()), &pszTitle); - if (FAILED(hr)) { - return hr; - } - - pPageInfo->cb = sizeof(PROPPAGEINFO); - pPageInfo->pszTitle = pszTitle; - pPageInfo->pszDocString = nullptr; - pPageInfo->pszHelpFile = nullptr; - pPageInfo->dwHelpContext = 0; - pPageInfo->size = GetWindowSize(); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::SetObjects(ULONG cObjects, LPUNKNOWN* ppUnk) -{ - CAutoLock cAutoLock(this); - - if (cObjects && m_pWnd || !cObjects && !m_pWnd) { - return E_UNEXPECTED; - } - - m_pUnks.RemoveAll(); - - if (cObjects > 0) { - CheckPointer(ppUnk, E_POINTER); - - for (ULONG i = 0; i < cObjects; i++) { - m_pUnks.AddTail(ppUnk[i]); - } - - m_pWnd = GetWindow(); - if (!m_pWnd) { - return E_OUTOFMEMORY; - } - - if (!m_pWnd->OnConnect(m_pUnks)) { - delete m_pWnd; - m_pWnd = nullptr; - - return E_FAIL; - } - } else { - m_pWnd->OnDisconnect(); - - m_pWnd->DestroyWindow(); - delete m_pWnd; - m_pWnd = nullptr; - } - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Show(UINT nCmdShow) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - if (!m_pWnd) { - return E_UNEXPECTED; - } - - if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { - return E_INVALIDARG; - } - - m_pWnd->ShowWindow(nCmdShow); - m_pWnd->Invalidate(); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Move(LPCRECT pRect) -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - CheckPointer(pRect, E_POINTER); - - if (!m_pWnd) { - return E_UNEXPECTED; - } - - m_pWnd->MoveWindow(pRect, TRUE); - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::IsPageDirty() -{ - CAutoLock cAutoLock(this); - - return m_pWnd && m_pWnd->GetDirty() ? S_OK : S_FALSE; -} - -STDMETHODIMP CInternalPropertyPage::Apply() -{ - AFX_MANAGE_STATE(AfxGetStaticModuleState()); - - CAutoLock cAutoLock(this); - - if (!m_pWnd || m_pUnks.IsEmpty() || !m_pPageSite) { - return E_UNEXPECTED; - } - - if (m_pWnd->GetDirty() && m_pWnd->OnApply()) { - m_pWnd->SetDirty(false); - } - - return S_OK; -} - -STDMETHODIMP CInternalPropertyPage::Help(LPCWSTR lpszHelpDir) -{ - CAutoLock cAutoLock(this); - - return E_NOTIMPL; -} - -STDMETHODIMP CInternalPropertyPage::TranslateAccelerator(LPMSG lpMsg) -{ - CAutoLock cAutoLock(this); - - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "InternalPropertyPage.h" +#include "../DSUtil/DSUtil.h" + + +// +// CInternalPropertyPageWnd +// + +void CInternalPropertyPageWnd::CalcTextRect(CRect& rect, long x, long y, long w, long border) +{ + rect.left = x; + rect.top = y; + rect.right = x + w; + rect.bottom = y + border; + m_dpi.ScaleRect(rect); + rect.bottom += m_fontheight; +} + +void CInternalPropertyPageWnd::CalcRect(CRect& rect, long x, long y, long w, long h) +{ + rect.left = x; + rect.top = y; + rect.right = x + w; + rect.bottom = y + h; + m_dpi.ScaleRect(rect); +} +CInternalPropertyPageWnd::CInternalPropertyPageWnd() + : m_fDirty(false) + , m_fontheight(IPP_FONTSIZE) +{ +} + +BOOL CInternalPropertyPageWnd::Create(IPropertyPageSite* pPageSite, LPCRECT pRect, CWnd* pParentWnd) +{ + if (!pPageSite || !pRect) { + return FALSE; + } + + m_pPageSite = pPageSite; + + if (!m_font.m_hObject) { + CString face; + WORD height; + extern BOOL AFXAPI AfxGetPropSheetFont(CString & strFace, WORD & wSize, BOOL bWizard); // yay + if (!AfxGetPropSheetFont(face, height, FALSE)) { + return FALSE; + } + + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + _tcscpy_s(lf.lfFaceName, face); + HDC hDC = ::GetDC(nullptr); + lf.lfHeight = -MulDiv(height, GetDeviceCaps(hDC, LOGPIXELSY), 72); + ::ReleaseDC(nullptr, hDC); + lf.lfWeight = FW_NORMAL; + lf.lfCharSet = DEFAULT_CHARSET; + if (!m_font.CreateFontIndirect(&lf)) { + return FALSE; + } + + lf.lfHeight -= -1; + _tcscpy_s(lf.lfFaceName, _T("Lucida Console")); + if (!m_monospacefont.CreateFontIndirect(&lf)) { + _tcscpy_s(lf.lfFaceName, _T("Courier New")); + if (!m_monospacefont.CreateFontIndirect(&lf)) { + return FALSE; + } + } + + hDC = ::GetDC(nullptr); + HFONT hFontOld = (HFONT)::SelectObject(hDC, m_font.m_hObject); + CSize size; + ::GetTextExtentPoint32(hDC, _T("x"), 1, &size); + ::SelectObject(hDC, hFontOld); + ::ReleaseDC(nullptr, hDC); + + m_fontheight = size.cy; + } + + LPCTSTR wc = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS, 0, (HBRUSH)(COLOR_BTNFACE + 1)); + if (!CreateEx(0, wc, _T("CInternalPropertyPageWnd"), WS_CHILDWINDOW, *pRect, pParentWnd, 0)) { + return FALSE; + } + + SetFont(&m_font); + + return TRUE; +} + +BOOL CInternalPropertyPageWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + if (message == WM_COMMAND || message == WM_HSCROLL || message == WM_VSCROLL) { + WORD notify = HIWORD(wParam); + // check only notifications that change the state of a control, otherwise false positives are possible. + if (notify == BN_CLICKED + || notify == CBN_SELCHANGE + || notify == EN_CHANGE + || notify == CLBN_CHKCHANGE) { + SetDirty(true); + } + } + + return __super::OnWndMsg(message, wParam, lParam, pResult); +} + +BEGIN_MESSAGE_MAP(CInternalPropertyPageWnd, CWnd) +END_MESSAGE_MAP() + +// +// CInternalPropertyPage +// + +CInternalPropertyPage::CInternalPropertyPage(LPUNKNOWN lpunk, HRESULT* phr) + : CUnknown(_T("CInternalPropertyPage"), lpunk) + , m_pWnd(nullptr) +{ + if (phr) { + *phr = S_OK; + } +} + +CInternalPropertyPage::~CInternalPropertyPage() +{ + if (m_pWnd) { + if (m_pWnd->m_hWnd) { + ASSERT(0); + m_pWnd->DestroyWindow(); + } + delete m_pWnd; + m_pWnd = nullptr; + } +} + +STDMETHODIMP CInternalPropertyPage::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI2(IPropertyPage) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IPropertyPage + +STDMETHODIMP CInternalPropertyPage::SetPageSite(IPropertyPageSite* pPageSite) +{ + CAutoLock cAutoLock(this); + + if (pPageSite && m_pPageSite || !pPageSite && !m_pPageSite) { + return E_UNEXPECTED; + } + + m_pPageSite = pPageSite; + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Activate(HWND hwndParent, LPCRECT pRect, BOOL fModal) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + CheckPointer(pRect, E_POINTER); + + if (!m_pWnd || m_pWnd->m_hWnd || m_pUnks.IsEmpty()) { + return E_UNEXPECTED; + } + + if (!m_pWnd->Create(m_pPageSite, pRect, CWnd::FromHandle(hwndParent))) { + return E_OUTOFMEMORY; + } + + if (!m_pWnd->OnActivate()) { + m_pWnd->DestroyWindow(); + return E_FAIL; + } + + m_pWnd->ModifyStyleEx(WS_EX_DLGMODALFRAME, WS_EX_CONTROLPARENT); + m_pWnd->ShowWindow(SW_SHOWNORMAL); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Deactivate() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + if (!m_pWnd || !m_pWnd->m_hWnd) { + return E_UNEXPECTED; + } + + m_pWnd->OnDeactivate(); + + m_pWnd->ModifyStyleEx(WS_EX_CONTROLPARENT, 0); + m_pWnd->DestroyWindow(); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::GetPageInfo(PROPPAGEINFO* pPageInfo) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPageInfo, E_POINTER); + + LPOLESTR pszTitle; + HRESULT hr = AMGetWideString(CStringW(GetWindowTitle()), &pszTitle); + if (FAILED(hr)) { + return hr; + } + + pPageInfo->cb = sizeof(PROPPAGEINFO); + pPageInfo->pszTitle = pszTitle; + pPageInfo->pszDocString = nullptr; + pPageInfo->pszHelpFile = nullptr; + pPageInfo->dwHelpContext = 0; + pPageInfo->size = GetWindowSize(); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::SetObjects(ULONG cObjects, LPUNKNOWN* ppUnk) +{ + CAutoLock cAutoLock(this); + + if (cObjects && m_pWnd || !cObjects && !m_pWnd) { + return E_UNEXPECTED; + } + + m_pUnks.RemoveAll(); + + if (cObjects > 0) { + CheckPointer(ppUnk, E_POINTER); + + for (ULONG i = 0; i < cObjects; i++) { + m_pUnks.AddTail(ppUnk[i]); + } + + m_pWnd = GetWindow(); + if (!m_pWnd) { + return E_OUTOFMEMORY; + } + + if (!m_pWnd->OnConnect(m_pUnks)) { + delete m_pWnd; + m_pWnd = nullptr; + + return E_FAIL; + } + } else { + m_pWnd->OnDisconnect(); + + m_pWnd->DestroyWindow(); + delete m_pWnd; + m_pWnd = nullptr; + } + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Show(UINT nCmdShow) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + if (!m_pWnd) { + return E_UNEXPECTED; + } + + if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { + return E_INVALIDARG; + } + + m_pWnd->ShowWindow(nCmdShow); + m_pWnd->Invalidate(); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Move(LPCRECT pRect) +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + CheckPointer(pRect, E_POINTER); + + if (!m_pWnd) { + return E_UNEXPECTED; + } + + m_pWnd->MoveWindow(pRect, TRUE); + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::IsPageDirty() +{ + CAutoLock cAutoLock(this); + + return m_pWnd && m_pWnd->GetDirty() ? S_OK : S_FALSE; +} + +STDMETHODIMP CInternalPropertyPage::Apply() +{ + AFX_MANAGE_STATE(AfxGetStaticModuleState()); + + CAutoLock cAutoLock(this); + + if (!m_pWnd || m_pUnks.IsEmpty() || !m_pPageSite) { + return E_UNEXPECTED; + } + + if (m_pWnd->GetDirty() && m_pWnd->OnApply()) { + m_pWnd->SetDirty(false); + } + + return S_OK; +} + +STDMETHODIMP CInternalPropertyPage::Help(LPCWSTR lpszHelpDir) +{ + CAutoLock cAutoLock(this); + + return E_NOTIMPL; +} + +STDMETHODIMP CInternalPropertyPage::TranslateAccelerator(LPMSG lpMsg) +{ + CAutoLock cAutoLock(this); + + return E_NOTIMPL; +} diff --git a/src/filters/InternalPropertyPage.h b/src/filters/InternalPropertyPage.h index 6315a8a30eb..8807f4f5fd2 100644 --- a/src/filters/InternalPropertyPage.h +++ b/src/filters/InternalPropertyPage.h @@ -1,124 +1,124 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -#include -#include "../mpc-hc/dpihelper.h" - -#define IPP_FONTSIZE 13 -#define IPP_SCALE(size) ((size) * m_fontheight / IPP_FONTSIZE) - -interface __declspec(uuid("03481710-D73E-4674-839F-03EDE2D60ED8")) - ISpecifyPropertyPages2 : - public ISpecifyPropertyPages -{ - STDMETHOD(CreatePage)(const GUID& guid, IPropertyPage** ppPage) = 0; -}; - -class CInternalPropertyPageWnd : public CWnd -{ - bool m_fDirty; - CComPtr m_pPageSite; - DpiHelper m_dpi; - -protected: - CFont m_font, m_monospacefont; - int m_fontheight; - - void CalcTextRect(CRect& rect, long x, long y, long w, long border = 0); - void CalcRect(CRect& rect, long x, long y, long w, long h); - virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); - -public: - CInternalPropertyPageWnd(); - - void SetDirty(bool fDirty = true) { - m_fDirty = fDirty; - if (m_pPageSite) { - if (fDirty) { - m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY); - } else { - m_pPageSite->OnStatusChange(PROPPAGESTATUS_CLEAN); - } - } - } - bool GetDirty() { return m_fDirty; } - - virtual BOOL Create(IPropertyPageSite* pPageSite, LPCRECT pRect, CWnd* pParentWnd); - - virtual bool OnConnect(const CInterfaceList& pUnks) { return true; } - virtual void OnDisconnect() {} - virtual bool OnActivate() { m_dpi.Override(GetSafeHwnd()); return true; } - virtual void OnDeactivate() {} - virtual bool OnApply() { return true; } - - DECLARE_MESSAGE_MAP() -}; - -class CInternalPropertyPage - : public CUnknown - , public IPropertyPage - , public CCritSec -{ - CComPtr m_pPageSite; - CInterfaceList m_pUnks; - CInternalPropertyPageWnd* m_pWnd; - -protected: - virtual CInternalPropertyPageWnd* GetWindow() = 0; - virtual LPCTSTR GetWindowTitle() = 0; - virtual CSize GetWindowSize() = 0; - -public: - CInternalPropertyPage(LPUNKNOWN lpunk, HRESULT* phr); - virtual ~CInternalPropertyPage(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IPropertyPage - - STDMETHODIMP SetPageSite(IPropertyPageSite* pPageSite); - STDMETHODIMP Activate(HWND hwndParent, LPCRECT pRect, BOOL fModal); - STDMETHODIMP Deactivate(); - STDMETHODIMP GetPageInfo(PROPPAGEINFO* pPageInfo); - STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN* ppUnk); - STDMETHODIMP Show(UINT nCmdShow); - STDMETHODIMP Move(LPCRECT prect); - STDMETHODIMP IsPageDirty(); - STDMETHODIMP Apply(); - STDMETHODIMP Help(LPCWSTR lpszHelpDir); - STDMETHODIMP TranslateAccelerator(LPMSG lpMsg); -}; - -template -class CInternalPropertyPageTempl : public CInternalPropertyPage -{ - virtual CInternalPropertyPageWnd* GetWindow() { return DEBUG_NEW WndClass(); } - virtual LPCTSTR GetWindowTitle() { return WndClass::GetWindowTitle(); } - virtual CSize GetWindowSize() { return WndClass::GetWindowSize(); } - -public: - CInternalPropertyPageTempl(LPUNKNOWN lpunk, HRESULT* phr) - : CInternalPropertyPage(lpunk, phr) { - } -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +#include +#include "../mpc-hc/dpihelper.h" + +#define IPP_FONTSIZE 13 +#define IPP_SCALE(size) ((size) * m_fontheight / IPP_FONTSIZE) + +interface __declspec(uuid("03481710-D73E-4674-839F-03EDE2D60ED8")) + ISpecifyPropertyPages2 : + public ISpecifyPropertyPages +{ + STDMETHOD(CreatePage)(const GUID& guid, IPropertyPage** ppPage) = 0; +}; + +class CInternalPropertyPageWnd : public CWnd +{ + bool m_fDirty; + CComPtr m_pPageSite; + DpiHelper m_dpi; + +protected: + CFont m_font, m_monospacefont; + int m_fontheight; + + void CalcTextRect(CRect& rect, long x, long y, long w, long border = 0); + void CalcRect(CRect& rect, long x, long y, long w, long h); + virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); + +public: + CInternalPropertyPageWnd(); + + void SetDirty(bool fDirty = true) { + m_fDirty = fDirty; + if (m_pPageSite) { + if (fDirty) { + m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY); + } else { + m_pPageSite->OnStatusChange(PROPPAGESTATUS_CLEAN); + } + } + } + bool GetDirty() { return m_fDirty; } + + virtual BOOL Create(IPropertyPageSite* pPageSite, LPCRECT pRect, CWnd* pParentWnd); + + virtual bool OnConnect(const CInterfaceList& pUnks) { return true; } + virtual void OnDisconnect() {} + virtual bool OnActivate() { m_dpi.Override(GetSafeHwnd()); return true; } + virtual void OnDeactivate() {} + virtual bool OnApply() { return true; } + + DECLARE_MESSAGE_MAP() +}; + +class CInternalPropertyPage + : public CUnknown + , public IPropertyPage + , public CCritSec +{ + CComPtr m_pPageSite; + CInterfaceList m_pUnks; + CInternalPropertyPageWnd* m_pWnd; + +protected: + virtual CInternalPropertyPageWnd* GetWindow() = 0; + virtual LPCTSTR GetWindowTitle() = 0; + virtual CSize GetWindowSize() = 0; + +public: + CInternalPropertyPage(LPUNKNOWN lpunk, HRESULT* phr); + virtual ~CInternalPropertyPage(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IPropertyPage + + STDMETHODIMP SetPageSite(IPropertyPageSite* pPageSite); + STDMETHODIMP Activate(HWND hwndParent, LPCRECT pRect, BOOL fModal); + STDMETHODIMP Deactivate(); + STDMETHODIMP GetPageInfo(PROPPAGEINFO* pPageInfo); + STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN* ppUnk); + STDMETHODIMP Show(UINT nCmdShow); + STDMETHODIMP Move(LPCRECT prect); + STDMETHODIMP IsPageDirty(); + STDMETHODIMP Apply(); + STDMETHODIMP Help(LPCWSTR lpszHelpDir); + STDMETHODIMP TranslateAccelerator(LPMSG lpMsg); +}; + +template +class CInternalPropertyPageTempl : public CInternalPropertyPage +{ + virtual CInternalPropertyPageWnd* GetWindow() { return DEBUG_NEW WndClass(); } + virtual LPCTSTR GetWindowTitle() { return WndClass::GetWindowTitle(); } + virtual CSize GetWindowSize() { return WndClass::GetWindowSize(); } + +public: + CInternalPropertyPageTempl(LPUNKNOWN lpunk, HRESULT* phr) + : CInternalPropertyPage(lpunk, phr) { + } +}; diff --git a/src/filters/PinInfoWnd.cpp b/src/filters/PinInfoWnd.cpp index 30727dd1bf6..8debee5a971 100644 --- a/src/filters/PinInfoWnd.cpp +++ b/src/filters/PinInfoWnd.cpp @@ -1,286 +1,286 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "PinInfoWnd.h" -#include "../DSUtil/DSUtil.h" -#include "../mpc-hc/DpiHelper.h" -#include "../DSUtil/MediaTypeEx.h" - -// -// CPinInfoWnd -// - -CPinInfoWnd::CPinInfoWnd() -{ -} - -bool CPinInfoWnd::OnConnect(const CInterfaceList& pUnks) -{ - ASSERT(!m_pBF); - - m_pBF.Release(); - - POSITION pos = pUnks.GetHeadPosition(); - while (pos && !(m_pBF = pUnks.GetNext(pos))) { - ; - } - - if (!m_pBF) { - return false; - } - - return true; -} - -void CPinInfoWnd::OnDisconnect() -{ - m_pBF.Release(); -} - -static WNDPROC OldControlProc; -static LRESULT CALLBACK ControlProc(HWND control, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_KEYDOWN) { - if (LOWORD(wParam) == VK_ESCAPE) { - return 0; // just ignore ESCAPE in edit control - } - 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 -} - -bool CPinInfoWnd::OnActivate() -{ - m_dpi.Override(GetSafeHwnd()); - - DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP; - CPoint p(m_dpi.ScaleX(10), m_dpi.ScaleY(10)); - - m_pin_static.Create(_T("Pin:"), dwStyle, - CRect(p + CPoint(m_dpi.ScaleX(0), m_dpi.ScaleY(3)), CSize(m_dpi.ScaleX(30), m_fontheight)), - this); - m_pin_combo.Create(dwStyle | CBS_DROPDOWNLIST, - CRect(p + CPoint(m_dpi.ScaleX(30), m_dpi.ScaleY(0)), CSize(m_dpi.ScaleX(520), m_dpi.ScaleY(200))), - this, IDC_PP_COMBO1); - BeginEnumPins(m_pBF, pEP, pPin) { - CPinInfo pi; - if (FAILED(pPin->QueryPinInfo(&pi))) { - continue; - } - CString str(pi.achName); - if (!str.Find(_T("Apple"))) { - str.Delete(0, 1); - } - CString dir = _T("[?] "); - if (pi.dir == PINDIR_INPUT) { - dir = _T("[IN] "); - } else if (pi.dir == PINDIR_OUTPUT) { - dir = _T("[OUT] "); - } - m_pin_combo.SetItemDataPtr(m_pin_combo.AddString(dir + str), pPin); - } - EndEnumPins; - m_pin_combo.SetCurSel(0); - - p.y += m_fontheight + m_dpi.ScaleY(20); - - m_info_edit.CreateEx(WS_EX_CLIENTEDGE, - _T("EDIT"), - _T(""), - dwStyle | - /* WS_BORDER | */ // equivalent to WS_EX_CLIENTEDGE - WS_VSCROLL | - WS_HSCROLL | - ES_MULTILINE | - ES_READONLY, - CRect(p, CSize(m_dpi.ScaleX(550), m_fontheight * 30)), - this, - IDC_PP_EDIT1); - m_info_edit.SetLimitText(60000); - - OnSelectedPinChange(); - - for (CWnd* pWnd = GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) { - pWnd->SetFont(&m_font, FALSE); - } - - m_info_edit.SetFixedWidthFont(m_monospacefont); - - // subclass the edit control - OldControlProc = (WNDPROC)SetWindowLongPtr(m_info_edit.m_hWnd, GWLP_WNDPROC, (LONG_PTR)ControlProc); - - return true; -} - -void CPinInfoWnd::OnDeactivate() -{ -} - -bool CPinInfoWnd::OnApply() -{ - OnDeactivate(); - - if (m_pBF) { - } - - return true; -} - -BOOL CPinInfoWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) -{ - //we don't need this anymore, as we bypass the CInternalPropertyPageWnd which is what sets it dirty - //SetDirty(false); - //we call CWnd implementation because CInternalPropertyPageWnd will set it right back to dirty on a scroll/command message - return CWnd::OnWndMsg(message, wParam, lParam, pResult); -} - -BEGIN_MESSAGE_MAP(CPinInfoWnd, CInternalPropertyPageWnd) - ON_CBN_SELCHANGE(IDC_PP_COMBO1, OnSelectedPinChange) - ON_WM_CTLCOLOR() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -void CPinInfoWnd::AddLine(CString str) -{ - str.Replace(_T("\n"), _T("\r\n")); - int len = m_info_edit.GetWindowTextLength(); - m_info_edit.SetSel(len, len, TRUE); - m_info_edit.ReplaceSel(str); -} - -void CPinInfoWnd::OnSelectedPinChange() -{ - m_info_edit.SetRedraw(FALSE); - m_info_edit.SetWindowText(_T("")); - - int i = m_pin_combo.GetCurSel(); - if (i < 0) { - return; - } - - CComPtr pPin = (IPin*)m_pin_combo.GetItemDataPtr(i); - if (!pPin) { - return; - } - - CString str; - CPinInfo pinInfo; - - if (SUCCEEDED(pPin->QueryPinInfo(&pinInfo))) { - CString strName; - CLSID filterClsid; - CFilterInfo filterInfo; - - if (SUCCEEDED(pinInfo.pFilter->QueryFilterInfo(&filterInfo))) { - CRegKey key; - pinInfo.pFilter->GetClassID(&filterClsid); - TCHAR buff[128]; - ULONG len = _countof(buff); - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\") + CStringFromGUID(filterClsid), KEY_READ) - && ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), buff, &len)) { - strName = CString(buff); - } else { - strName = filterInfo.achName; - } - str.Format(_T("Filter : %s - CLSID : %s\n\n"), strName.GetString(), CStringFromGUID(filterClsid).GetString()); - AddLine(str); - } - } - - CMediaTypeEx cmt; - - CComPtr pPinTo; - if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { - str.Format(_T("- Connected to:\n\nCLSID: %s\nFilter: %s\nPin: %s\n\n"), - CStringFromGUID(GetCLSID(pPinTo)).GetString(), - static_cast(GetFilterName(GetFilterFromPin(pPinTo))), - static_cast(GetPinName(pPinTo))); - - AddLine(str); - - AddLine(_T("- Connection media type:\n\n")); - - if (SUCCEEDED(pPin->ConnectionMediaType(&cmt))) { - CAtlList sl; - cmt.Dump(sl); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - AddLine(sl.GetNext(pos) + '\n'); - } - } - } else { - str = _T("- Not connected\n\n"); - } - - int iMT = 0; - - BeginEnumMediaTypes(pPin, pEMT, pmt) { - CMediaTypeEx mt(*pmt); - - str.Format(_T("- Enumerated media type %d:\n\n"), iMT++); - AddLine(str); - - if (cmt.majortype != GUID_NULL && mt == cmt) { - AddLine(_T("Set as the current media type\n\n")); - } else { - CAtlList sl; - mt.Dump(sl); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - AddLine(sl.GetNext(pos) + '\n'); - } - } - } - EndEnumMediaTypes(pmt); - - m_info_edit.SetSel(0, 0); - m_info_edit.SetRedraw(TRUE); - m_info_edit.RedrawWindow(NULL); -} - - -HBRUSH CPinInfoWnd::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} - -BOOL CPinInfoWnd::OnEraseBkgnd(CDC* pDC) -{ - bool ret = MPCThemeEraseBkgnd(pDC, this, CTLCOLOR_DLG); - if (ret) { - return ret; - } else { - return __super::OnEraseBkgnd(pDC); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "PinInfoWnd.h" +#include "../DSUtil/DSUtil.h" +#include "../mpc-hc/DpiHelper.h" +#include "../DSUtil/MediaTypeEx.h" + +// +// CPinInfoWnd +// + +CPinInfoWnd::CPinInfoWnd() +{ +} + +bool CPinInfoWnd::OnConnect(const CInterfaceList& pUnks) +{ + ASSERT(!m_pBF); + + m_pBF.Release(); + + POSITION pos = pUnks.GetHeadPosition(); + while (pos && !(m_pBF = pUnks.GetNext(pos))) { + ; + } + + if (!m_pBF) { + return false; + } + + return true; +} + +void CPinInfoWnd::OnDisconnect() +{ + m_pBF.Release(); +} + +static WNDPROC OldControlProc; +static LRESULT CALLBACK ControlProc(HWND control, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_KEYDOWN) { + if (LOWORD(wParam) == VK_ESCAPE) { + return 0; // just ignore ESCAPE in edit control + } + 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 +} + +bool CPinInfoWnd::OnActivate() +{ + m_dpi.Override(GetSafeHwnd()); + + DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP; + CPoint p(m_dpi.ScaleX(10), m_dpi.ScaleY(10)); + + m_pin_static.Create(_T("Pin:"), dwStyle, + CRect(p + CPoint(m_dpi.ScaleX(0), m_dpi.ScaleY(3)), CSize(m_dpi.ScaleX(30), m_fontheight)), + this); + m_pin_combo.Create(dwStyle | CBS_DROPDOWNLIST, + CRect(p + CPoint(m_dpi.ScaleX(30), m_dpi.ScaleY(0)), CSize(m_dpi.ScaleX(520), m_dpi.ScaleY(200))), + this, IDC_PP_COMBO1); + BeginEnumPins(m_pBF, pEP, pPin) { + CPinInfo pi; + if (FAILED(pPin->QueryPinInfo(&pi))) { + continue; + } + CString str(pi.achName); + if (!str.Find(_T("Apple"))) { + str.Delete(0, 1); + } + CString dir = _T("[?] "); + if (pi.dir == PINDIR_INPUT) { + dir = _T("[IN] "); + } else if (pi.dir == PINDIR_OUTPUT) { + dir = _T("[OUT] "); + } + m_pin_combo.SetItemDataPtr(m_pin_combo.AddString(dir + str), pPin); + } + EndEnumPins; + m_pin_combo.SetCurSel(0); + + p.y += m_fontheight + m_dpi.ScaleY(20); + + m_info_edit.CreateEx(WS_EX_CLIENTEDGE, + _T("EDIT"), + _T(""), + dwStyle | + /* WS_BORDER | */ // equivalent to WS_EX_CLIENTEDGE + WS_VSCROLL | + WS_HSCROLL | + ES_MULTILINE | + ES_READONLY, + CRect(p, CSize(m_dpi.ScaleX(550), m_fontheight * 30)), + this, + IDC_PP_EDIT1); + m_info_edit.SetLimitText(60000); + + OnSelectedPinChange(); + + for (CWnd* pWnd = GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) { + pWnd->SetFont(&m_font, FALSE); + } + + m_info_edit.SetFixedWidthFont(m_monospacefont); + + // subclass the edit control + OldControlProc = (WNDPROC)SetWindowLongPtr(m_info_edit.m_hWnd, GWLP_WNDPROC, (LONG_PTR)ControlProc); + + return true; +} + +void CPinInfoWnd::OnDeactivate() +{ +} + +bool CPinInfoWnd::OnApply() +{ + OnDeactivate(); + + if (m_pBF) { + } + + return true; +} + +BOOL CPinInfoWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + //we don't need this anymore, as we bypass the CInternalPropertyPageWnd which is what sets it dirty + //SetDirty(false); + //we call CWnd implementation because CInternalPropertyPageWnd will set it right back to dirty on a scroll/command message + return CWnd::OnWndMsg(message, wParam, lParam, pResult); +} + +BEGIN_MESSAGE_MAP(CPinInfoWnd, CInternalPropertyPageWnd) + ON_CBN_SELCHANGE(IDC_PP_COMBO1, OnSelectedPinChange) + ON_WM_CTLCOLOR() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +void CPinInfoWnd::AddLine(CString str) +{ + str.Replace(_T("\n"), _T("\r\n")); + int len = m_info_edit.GetWindowTextLength(); + m_info_edit.SetSel(len, len, TRUE); + m_info_edit.ReplaceSel(str); +} + +void CPinInfoWnd::OnSelectedPinChange() +{ + m_info_edit.SetRedraw(FALSE); + m_info_edit.SetWindowText(_T("")); + + int i = m_pin_combo.GetCurSel(); + if (i < 0) { + return; + } + + CComPtr pPin = (IPin*)m_pin_combo.GetItemDataPtr(i); + if (!pPin) { + return; + } + + CString str; + CPinInfo pinInfo; + + if (SUCCEEDED(pPin->QueryPinInfo(&pinInfo))) { + CString strName; + CLSID filterClsid; + CFilterInfo filterInfo; + + if (SUCCEEDED(pinInfo.pFilter->QueryFilterInfo(&filterInfo))) { + CRegKey key; + pinInfo.pFilter->GetClassID(&filterClsid); + TCHAR buff[128]; + ULONG len = _countof(buff); + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\") + CStringFromGUID(filterClsid), KEY_READ) + && ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), buff, &len)) { + strName = CString(buff); + } else { + strName = filterInfo.achName; + } + str.Format(_T("Filter : %s - CLSID : %s\n\n"), strName.GetString(), CStringFromGUID(filterClsid).GetString()); + AddLine(str); + } + } + + CMediaTypeEx cmt; + + CComPtr pPinTo; + if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { + str.Format(_T("- Connected to:\n\nCLSID: %s\nFilter: %s\nPin: %s\n\n"), + CStringFromGUID(GetCLSID(pPinTo)).GetString(), + static_cast(GetFilterName(GetFilterFromPin(pPinTo))), + static_cast(GetPinName(pPinTo))); + + AddLine(str); + + AddLine(_T("- Connection media type:\n\n")); + + if (SUCCEEDED(pPin->ConnectionMediaType(&cmt))) { + CAtlList sl; + cmt.Dump(sl); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + AddLine(sl.GetNext(pos) + '\n'); + } + } + } else { + str = _T("- Not connected\n\n"); + } + + int iMT = 0; + + BeginEnumMediaTypes(pPin, pEMT, pmt) { + CMediaTypeEx mt(*pmt); + + str.Format(_T("- Enumerated media type %d:\n\n"), iMT++); + AddLine(str); + + if (cmt.majortype != GUID_NULL && mt == cmt) { + AddLine(_T("Set as the current media type\n\n")); + } else { + CAtlList sl; + mt.Dump(sl); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + AddLine(sl.GetNext(pos) + '\n'); + } + } + } + EndEnumMediaTypes(pmt); + + m_info_edit.SetSel(0, 0); + m_info_edit.SetRedraw(TRUE); + m_info_edit.RedrawWindow(NULL); +} + + +HBRUSH CPinInfoWnd::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} + +BOOL CPinInfoWnd::OnEraseBkgnd(CDC* pDC) +{ + bool ret = MPCThemeEraseBkgnd(pDC, this, CTLCOLOR_DLG); + if (ret) { + return ret; + } else { + return __super::OnEraseBkgnd(pDC); + } +} diff --git a/src/filters/PinInfoWnd.h b/src/filters/PinInfoWnd.h index f84dc55e0ee..0fa17412109 100644 --- a/src/filters/PinInfoWnd.h +++ b/src/filters/PinInfoWnd.h @@ -1,70 +1,70 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2015 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 . - * - */ - -#pragma once - -#include "InternalPropertyPage.h" -#include "stdafx.h" -#include "../mpc-hc/DpiHelper.h" -#include "../mpc-hc/CMPCThemeStatic.h" -#include "../mpc-hc/CMPCThemeComboBox.h" -#include "../mpc-hc/CMPCThemeEdit.h" -#include "../mpc-hc/CMPCThemeUtil.h" -#include - -class __declspec(uuid("A1EB391C-6089-4A87-9988-BE50872317D4")) - CPinInfoWnd : public CInternalPropertyPageWnd, CMPCThemeUtil -{ - CComQIPtr m_pBF; - - enum { - IDC_PP_COMBO1 = 10000, - IDC_PP_EDIT1 - }; - - CMPCThemeStatic m_pin_static; - CMPCThemeComboBox m_pin_combo; - CMPCThemeEdit m_info_edit; - - DpiHelper m_dpi; - - void AddLine(CString str); - -public: - CPinInfoWnd(); - - bool OnConnect(const CInterfaceList& pUnks); - void OnDisconnect(); - bool OnActivate(); - void OnDeactivate(); - bool OnApply(); - - static LPCTSTR GetWindowTitle() { return _T("Pin Info"); } - static CSize GetWindowSize() { return { 0, 0 }; } - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - void OnSelectedPinChange(); - -protected: - virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2015 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 . + * + */ + +#pragma once + +#include "InternalPropertyPage.h" +#include "stdafx.h" +#include "../mpc-hc/DpiHelper.h" +#include "../mpc-hc/CMPCThemeStatic.h" +#include "../mpc-hc/CMPCThemeComboBox.h" +#include "../mpc-hc/CMPCThemeEdit.h" +#include "../mpc-hc/CMPCThemeUtil.h" +#include + +class __declspec(uuid("A1EB391C-6089-4A87-9988-BE50872317D4")) + CPinInfoWnd : public CInternalPropertyPageWnd, CMPCThemeUtil +{ + CComQIPtr m_pBF; + + enum { + IDC_PP_COMBO1 = 10000, + IDC_PP_EDIT1 + }; + + CMPCThemeStatic m_pin_static; + CMPCThemeComboBox m_pin_combo; + CMPCThemeEdit m_info_edit; + + DpiHelper m_dpi; + + void AddLine(CString str); + +public: + CPinInfoWnd(); + + bool OnConnect(const CInterfaceList& pUnks); + void OnDisconnect(); + bool OnActivate(); + void OnDeactivate(); + bool OnApply(); + + static LPCTSTR GetWindowTitle() { return _T("Pin Info"); } + static CSize GetWindowSize() { return { 0, 0 }; } + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + void OnSelectedPinChange(); + +protected: + virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); +}; diff --git a/src/filters/muxer/BaseMuxer/BaseMuxer.cpp b/src/filters/muxer/BaseMuxer/BaseMuxer.cpp index 3a0506879ca..25368cbd07e 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxer.cpp +++ b/src/filters/muxer/BaseMuxer/BaseMuxer.cpp @@ -1,521 +1,521 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "BaseMuxer.h" - -// -// CBaseMuxerFilter -// - -CBaseMuxerFilter::CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid) - : CBaseFilter(NAME("CBaseMuxerFilter"), pUnk, this, clsid) - , m_rtCurrent(0) -{ - if (phr) { - *phr = S_OK; - } - m_pOutput.Attach(DEBUG_NEW CBaseMuxerOutputPin(L"Output", this, this, phr)); - AddInput(); -} - -CBaseMuxerFilter::~CBaseMuxerFilter() -{ -} - -STDMETHODIMP CBaseMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - return - QI(IMediaSeeking) - QI(IPropertyBag) - QI(IPropertyBag2) - QI(IDSMPropertyBag) - QI(IDSMResourceBag) - QI(IDSMChapterBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// - -void CBaseMuxerFilter::AddInput() -{ - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CBasePin* pPin = m_pInputs.GetNext(pos); - if (!pPin->IsConnected()) { - return; - } - } - - CStringW name; - - name.Format(L"Input %u", m_pInputs.GetCount() + 1); - - CBaseMuxerInputPin* pInputPin = nullptr; - if (FAILED(CreateInput(name, &pInputPin)) || !pInputPin) { - ASSERT(0); - return; - } - CAutoPtr pAutoPtrInputPin(pInputPin); - - name.Format(L"~Output %u", m_pRawOutputs.GetCount() + 1); - - CBaseMuxerRawOutputPin* pRawOutputPin = nullptr; - if (FAILED(CreateRawOutput(name, &pRawOutputPin)) || !pRawOutputPin) { - ASSERT(0); - return; - } - CAutoPtr pAutoPtrRawOutputPin(pRawOutputPin); - - pInputPin->SetRelatedPin(pRawOutputPin); - pRawOutputPin->SetRelatedPin(pInputPin); - - m_pInputs.AddTail(pAutoPtrInputPin); - m_pRawOutputs.AddTail(pAutoPtrRawOutputPin); -} - -HRESULT CBaseMuxerFilter::CreateInput(CStringW name, CBaseMuxerInputPin** ppPin) -{ - CheckPointer(ppPin, E_POINTER); - HRESULT hr = S_OK; - *ppPin = DEBUG_NEW CBaseMuxerInputPin(name, this, this, &hr); - return hr; -} - -HRESULT CBaseMuxerFilter::CreateRawOutput(CStringW name, CBaseMuxerRawOutputPin** ppPin) -{ - CheckPointer(ppPin, E_POINTER); - HRESULT hr = S_OK; - *ppPin = DEBUG_NEW CBaseMuxerRawOutputPin(name, this, this, &hr); - return hr; -} - -// - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CBaseMuxerFilter::ThreadProc() -{ - SetThreadPriority(m_hThread, THREAD_PRIORITY_ABOVE_NORMAL); - - POSITION pos; - - for (;;) { - DWORD cmd = GetRequest(); - - switch (cmd) { - default: - case CMD_EXIT: - CAMThread::m_hThread = nullptr; - Reply(S_OK); - return 0; - - case CMD_RUN: - m_pActivePins.RemoveAll(); - m_pPins.RemoveAll(); - - pos = m_pInputs.GetHeadPosition(); - while (pos) { - CBaseMuxerInputPin* pPin = m_pInputs.GetNext(pos); - if (pPin->IsConnected()) { - m_pActivePins.AddTail(pPin); - m_pPins.AddTail(pPin); - } - } - - m_rtCurrent = 0; - - Reply(S_OK); - - MuxInit(); - - try { - MuxHeaderInternal(); - - while (!CheckRequest(nullptr) && m_pActivePins.GetCount()) { - if (m_State == State_Paused) { - Sleep(10); - continue; - } - - CAutoPtr pPacket(GetPacket().Detach()); - if (!pPacket) { - Sleep(1); - continue; - } - - if (pPacket->IsTimeValid()) { - m_rtCurrent = pPacket->rtStart; - } - - if (pPacket->IsEOS()) { - m_pActivePins.RemoveAt(m_pActivePins.Find(pPacket->pPin)); - } - - MuxPacketInternal(pPacket); - } - - MuxFooterInternal(); - } catch (HRESULT hr) { - CComQIPtr(m_pGraph)->Notify(EC_ERRORABORT, hr, 0); - } - - m_pOutput->DeliverEndOfStream(); - - pos = m_pRawOutputs.GetHeadPosition(); - while (pos) { - m_pRawOutputs.GetNext(pos)->DeliverEndOfStream(); - } - - m_pActivePins.RemoveAll(); - m_pPins.RemoveAll(); - - break; - } - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -void CBaseMuxerFilter::MuxHeaderInternal() -{ - TRACE(_T("MuxHeader\n")); - - if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { - MuxHeader(pBitStream); - } - - MuxHeader(); - - // - - POSITION pos = m_pPins.GetHeadPosition(); - while (pos) { - if (CBaseMuxerInputPin* pInput = m_pPins.GetNext(pos)) - if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { - pOutput->MuxHeader(pInput->CurrentMediaType()); - } - } -} - -void CBaseMuxerFilter::MuxPacketInternal(const MuxerPacket* pPacket) -{ - TRACE(_T("MuxPacket pPin=%x, size=%d, s%d e%d b%d, rt=(%I64d-%I64d)\n"), - pPacket->pPin->GetID(), - pPacket->pData.GetCount(), - !!(pPacket->flags & MuxerPacket::syncpoint), - !!(pPacket->flags & MuxerPacket::eos), - !!(pPacket->flags & MuxerPacket::bogus), - pPacket->rtStart / 10000, pPacket->rtStop / 10000); - - if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { - MuxPacket(pBitStream, pPacket); - } - - MuxPacket(pPacket); - - if (CBaseMuxerInputPin* pInput = pPacket->pPin) - if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { - pOutput->MuxPacket(pInput->CurrentMediaType(), pPacket); - } -} - -void CBaseMuxerFilter::MuxFooterInternal() -{ - TRACE(_T("MuxFooter\n")); - - if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { - MuxFooter(pBitStream); - } - - MuxFooter(); - - // - - POSITION pos = m_pPins.GetHeadPosition(); - while (pos) { - if (CBaseMuxerInputPin* pInput = m_pPins.GetNext(pos)) - if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { - pOutput->MuxFooter(pInput->CurrentMediaType()); - } - } -} - -CAutoPtr CBaseMuxerFilter::GetPacket() -{ - REFERENCE_TIME rtMin = _I64_MAX; - CBaseMuxerInputPin* pPinMin = nullptr; - int i = int(m_pActivePins.GetCount()); - - POSITION pos = m_pActivePins.GetHeadPosition(); - while (pos) { - CBaseMuxerInputPin* pPin = m_pActivePins.GetNext(pos); - - CAutoLock cAutoLock(&pPin->m_csQueue); - if (!pPin->m_queue.GetCount()) { - continue; - } - - MuxerPacket* p = pPin->m_queue.GetHead(); - - if (p->IsBogus() || !p->IsTimeValid() || p->IsEOS()) { - pPinMin = pPin; - i = 0; - break; - } - - if (p->rtStart < rtMin) { - rtMin = p->rtStart; - pPinMin = pPin; - } - - i--; - } - - CAutoPtr pPacket; - - if (pPinMin && i == 0) { - pPacket.Attach(pPinMin->PopPacket().Detach()); - } else { - pos = m_pActivePins.GetHeadPosition(); - while (pos) { - m_pActivePins.GetNext(pos)->m_evAcceptPacket.Set(); - } - } - - return pPacket; -} - -// - -int CBaseMuxerFilter::GetPinCount() -{ - return int(m_pInputs.GetCount()) + (m_pOutput ? 1 : 0) + int(m_pRawOutputs.GetCount()); -} - -CBasePin* CBaseMuxerFilter::GetPin(int n) -{ - CAutoLock cAutoLock(this); - - if (n >= 0 && n < (int)m_pInputs.GetCount()) { - if (POSITION pos = m_pInputs.FindIndex(n)) { - return m_pInputs.GetAt(pos); - } - } - - n -= int(m_pInputs.GetCount()); - - if (n == 0 && m_pOutput) { - return m_pOutput; - } - - n--; - - if (n >= 0 && n < (int)m_pRawOutputs.GetCount()) { - if (POSITION pos = m_pRawOutputs.FindIndex(n)) { - return m_pRawOutputs.GetAt(pos); - } - } - - //n -= int(m_pRawOutputs.GetCount()); - - return nullptr; -} - -STDMETHODIMP CBaseMuxerFilter::Stop() -{ - CAutoLock cAutoLock(this); - - HRESULT hr = __super::Stop(); - if (FAILED(hr)) { - return hr; - } - - CallWorker(CMD_EXIT); - - return hr; -} - -STDMETHODIMP CBaseMuxerFilter::Pause() -{ - CAutoLock cAutoLock(this); - - FILTER_STATE fs = m_State; - - HRESULT hr = __super::Pause(); - if (FAILED(hr)) { - return hr; - } - - if (fs == State_Stopped && m_pOutput) { - CAMThread::Create(); - CallWorker(CMD_RUN); - } - - return hr; -} - -STDMETHODIMP CBaseMuxerFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cAutoLock(this); - - HRESULT hr = __super::Run(tStart); - if (FAILED(hr)) { - return hr; - } - - return hr; -} - -// IMediaSeeking - -STDMETHODIMP CBaseMuxerFilter::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanGetDuration | AM_SEEKING_CanGetCurrentPos; - - return S_OK; -} - -STDMETHODIMP CBaseMuxerFilter::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - if (*pCapabilities == 0) { - return S_OK; - } - DWORD caps; - GetCapabilities(&caps); - caps &= *pCapabilities; - return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseMuxerFilter::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseMuxerFilter::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseMuxerFilter::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CBaseMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CBaseMuxerFilter::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CBaseMuxerFilter::GetDuration(LONGLONG* pDuration) -{ - CheckPointer(pDuration, E_POINTER); - *pDuration = 0; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - REFERENCE_TIME rt = m_pInputs.GetNext(pos)->GetDuration(); - if (rt > *pDuration) { - *pDuration = rt; - } - } - return S_OK; -} - -STDMETHODIMP CBaseMuxerFilter::GetStopPosition(LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent) -{ - CheckPointer(pCurrent, E_POINTER); - *pCurrent = m_rtCurrent; - return S_OK; -} - -STDMETHODIMP CBaseMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - FILTER_STATE fs; - - if (SUCCEEDED(GetState(0, &fs)) && fs == State_Stopped) { - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CBasePin* pPin = m_pInputs.GetNext(pos); - CComQIPtr pMS = pPin->GetConnected(); - if (!pMS) { - pMS = GetFilterFromPin(pPin->GetConnected()); - } - if (pMS) { - pMS->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); - } - } - - return S_OK; - } - - return VFW_E_WRONG_STATE; -} - -STDMETHODIMP CBaseMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::SetRate(double dRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::GetRate(double* pdRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseMuxerFilter::GetPreroll(LONGLONG* pllPreroll) -{ - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "BaseMuxer.h" + +// +// CBaseMuxerFilter +// + +CBaseMuxerFilter::CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid) + : CBaseFilter(NAME("CBaseMuxerFilter"), pUnk, this, clsid) + , m_rtCurrent(0) +{ + if (phr) { + *phr = S_OK; + } + m_pOutput.Attach(DEBUG_NEW CBaseMuxerOutputPin(L"Output", this, this, phr)); + AddInput(); +} + +CBaseMuxerFilter::~CBaseMuxerFilter() +{ +} + +STDMETHODIMP CBaseMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + return + QI(IMediaSeeking) + QI(IPropertyBag) + QI(IPropertyBag2) + QI(IDSMPropertyBag) + QI(IDSMResourceBag) + QI(IDSMChapterBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// + +void CBaseMuxerFilter::AddInput() +{ + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CBasePin* pPin = m_pInputs.GetNext(pos); + if (!pPin->IsConnected()) { + return; + } + } + + CStringW name; + + name.Format(L"Input %u", m_pInputs.GetCount() + 1); + + CBaseMuxerInputPin* pInputPin = nullptr; + if (FAILED(CreateInput(name, &pInputPin)) || !pInputPin) { + ASSERT(0); + return; + } + CAutoPtr pAutoPtrInputPin(pInputPin); + + name.Format(L"~Output %u", m_pRawOutputs.GetCount() + 1); + + CBaseMuxerRawOutputPin* pRawOutputPin = nullptr; + if (FAILED(CreateRawOutput(name, &pRawOutputPin)) || !pRawOutputPin) { + ASSERT(0); + return; + } + CAutoPtr pAutoPtrRawOutputPin(pRawOutputPin); + + pInputPin->SetRelatedPin(pRawOutputPin); + pRawOutputPin->SetRelatedPin(pInputPin); + + m_pInputs.AddTail(pAutoPtrInputPin); + m_pRawOutputs.AddTail(pAutoPtrRawOutputPin); +} + +HRESULT CBaseMuxerFilter::CreateInput(CStringW name, CBaseMuxerInputPin** ppPin) +{ + CheckPointer(ppPin, E_POINTER); + HRESULT hr = S_OK; + *ppPin = DEBUG_NEW CBaseMuxerInputPin(name, this, this, &hr); + return hr; +} + +HRESULT CBaseMuxerFilter::CreateRawOutput(CStringW name, CBaseMuxerRawOutputPin** ppPin) +{ + CheckPointer(ppPin, E_POINTER); + HRESULT hr = S_OK; + *ppPin = DEBUG_NEW CBaseMuxerRawOutputPin(name, this, this, &hr); + return hr; +} + +// + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CBaseMuxerFilter::ThreadProc() +{ + SetThreadPriority(m_hThread, THREAD_PRIORITY_ABOVE_NORMAL); + + POSITION pos; + + for (;;) { + DWORD cmd = GetRequest(); + + switch (cmd) { + default: + case CMD_EXIT: + CAMThread::m_hThread = nullptr; + Reply(S_OK); + return 0; + + case CMD_RUN: + m_pActivePins.RemoveAll(); + m_pPins.RemoveAll(); + + pos = m_pInputs.GetHeadPosition(); + while (pos) { + CBaseMuxerInputPin* pPin = m_pInputs.GetNext(pos); + if (pPin->IsConnected()) { + m_pActivePins.AddTail(pPin); + m_pPins.AddTail(pPin); + } + } + + m_rtCurrent = 0; + + Reply(S_OK); + + MuxInit(); + + try { + MuxHeaderInternal(); + + while (!CheckRequest(nullptr) && m_pActivePins.GetCount()) { + if (m_State == State_Paused) { + Sleep(10); + continue; + } + + CAutoPtr pPacket(GetPacket().Detach()); + if (!pPacket) { + Sleep(1); + continue; + } + + if (pPacket->IsTimeValid()) { + m_rtCurrent = pPacket->rtStart; + } + + if (pPacket->IsEOS()) { + m_pActivePins.RemoveAt(m_pActivePins.Find(pPacket->pPin)); + } + + MuxPacketInternal(pPacket); + } + + MuxFooterInternal(); + } catch (HRESULT hr) { + CComQIPtr(m_pGraph)->Notify(EC_ERRORABORT, hr, 0); + } + + m_pOutput->DeliverEndOfStream(); + + pos = m_pRawOutputs.GetHeadPosition(); + while (pos) { + m_pRawOutputs.GetNext(pos)->DeliverEndOfStream(); + } + + m_pActivePins.RemoveAll(); + m_pPins.RemoveAll(); + + break; + } + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +void CBaseMuxerFilter::MuxHeaderInternal() +{ + TRACE(_T("MuxHeader\n")); + + if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { + MuxHeader(pBitStream); + } + + MuxHeader(); + + // + + POSITION pos = m_pPins.GetHeadPosition(); + while (pos) { + if (CBaseMuxerInputPin* pInput = m_pPins.GetNext(pos)) + if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { + pOutput->MuxHeader(pInput->CurrentMediaType()); + } + } +} + +void CBaseMuxerFilter::MuxPacketInternal(const MuxerPacket* pPacket) +{ + TRACE(_T("MuxPacket pPin=%x, size=%d, s%d e%d b%d, rt=(%I64d-%I64d)\n"), + pPacket->pPin->GetID(), + pPacket->pData.GetCount(), + !!(pPacket->flags & MuxerPacket::syncpoint), + !!(pPacket->flags & MuxerPacket::eos), + !!(pPacket->flags & MuxerPacket::bogus), + pPacket->rtStart / 10000, pPacket->rtStop / 10000); + + if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { + MuxPacket(pBitStream, pPacket); + } + + MuxPacket(pPacket); + + if (CBaseMuxerInputPin* pInput = pPacket->pPin) + if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { + pOutput->MuxPacket(pInput->CurrentMediaType(), pPacket); + } +} + +void CBaseMuxerFilter::MuxFooterInternal() +{ + TRACE(_T("MuxFooter\n")); + + if (CComQIPtr pBitStream = m_pOutput->GetBitStream()) { + MuxFooter(pBitStream); + } + + MuxFooter(); + + // + + POSITION pos = m_pPins.GetHeadPosition(); + while (pos) { + if (CBaseMuxerInputPin* pInput = m_pPins.GetNext(pos)) + if (CBaseMuxerRawOutputPin* pOutput = dynamic_cast(pInput->GetRelatedPin())) { + pOutput->MuxFooter(pInput->CurrentMediaType()); + } + } +} + +CAutoPtr CBaseMuxerFilter::GetPacket() +{ + REFERENCE_TIME rtMin = _I64_MAX; + CBaseMuxerInputPin* pPinMin = nullptr; + int i = int(m_pActivePins.GetCount()); + + POSITION pos = m_pActivePins.GetHeadPosition(); + while (pos) { + CBaseMuxerInputPin* pPin = m_pActivePins.GetNext(pos); + + CAutoLock cAutoLock(&pPin->m_csQueue); + if (!pPin->m_queue.GetCount()) { + continue; + } + + MuxerPacket* p = pPin->m_queue.GetHead(); + + if (p->IsBogus() || !p->IsTimeValid() || p->IsEOS()) { + pPinMin = pPin; + i = 0; + break; + } + + if (p->rtStart < rtMin) { + rtMin = p->rtStart; + pPinMin = pPin; + } + + i--; + } + + CAutoPtr pPacket; + + if (pPinMin && i == 0) { + pPacket.Attach(pPinMin->PopPacket().Detach()); + } else { + pos = m_pActivePins.GetHeadPosition(); + while (pos) { + m_pActivePins.GetNext(pos)->m_evAcceptPacket.Set(); + } + } + + return pPacket; +} + +// + +int CBaseMuxerFilter::GetPinCount() +{ + return int(m_pInputs.GetCount()) + (m_pOutput ? 1 : 0) + int(m_pRawOutputs.GetCount()); +} + +CBasePin* CBaseMuxerFilter::GetPin(int n) +{ + CAutoLock cAutoLock(this); + + if (n >= 0 && n < (int)m_pInputs.GetCount()) { + if (POSITION pos = m_pInputs.FindIndex(n)) { + return m_pInputs.GetAt(pos); + } + } + + n -= int(m_pInputs.GetCount()); + + if (n == 0 && m_pOutput) { + return m_pOutput; + } + + n--; + + if (n >= 0 && n < (int)m_pRawOutputs.GetCount()) { + if (POSITION pos = m_pRawOutputs.FindIndex(n)) { + return m_pRawOutputs.GetAt(pos); + } + } + + //n -= int(m_pRawOutputs.GetCount()); + + return nullptr; +} + +STDMETHODIMP CBaseMuxerFilter::Stop() +{ + CAutoLock cAutoLock(this); + + HRESULT hr = __super::Stop(); + if (FAILED(hr)) { + return hr; + } + + CallWorker(CMD_EXIT); + + return hr; +} + +STDMETHODIMP CBaseMuxerFilter::Pause() +{ + CAutoLock cAutoLock(this); + + FILTER_STATE fs = m_State; + + HRESULT hr = __super::Pause(); + if (FAILED(hr)) { + return hr; + } + + if (fs == State_Stopped && m_pOutput) { + CAMThread::Create(); + CallWorker(CMD_RUN); + } + + return hr; +} + +STDMETHODIMP CBaseMuxerFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cAutoLock(this); + + HRESULT hr = __super::Run(tStart); + if (FAILED(hr)) { + return hr; + } + + return hr; +} + +// IMediaSeeking + +STDMETHODIMP CBaseMuxerFilter::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanGetDuration | AM_SEEKING_CanGetCurrentPos; + + return S_OK; +} + +STDMETHODIMP CBaseMuxerFilter::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + if (*pCapabilities == 0) { + return S_OK; + } + DWORD caps; + GetCapabilities(&caps); + caps &= *pCapabilities; + return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseMuxerFilter::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseMuxerFilter::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseMuxerFilter::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CBaseMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CBaseMuxerFilter::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CBaseMuxerFilter::GetDuration(LONGLONG* pDuration) +{ + CheckPointer(pDuration, E_POINTER); + *pDuration = 0; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + REFERENCE_TIME rt = m_pInputs.GetNext(pos)->GetDuration(); + if (rt > *pDuration) { + *pDuration = rt; + } + } + return S_OK; +} + +STDMETHODIMP CBaseMuxerFilter::GetStopPosition(LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent) +{ + CheckPointer(pCurrent, E_POINTER); + *pCurrent = m_rtCurrent; + return S_OK; +} + +STDMETHODIMP CBaseMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + FILTER_STATE fs; + + if (SUCCEEDED(GetState(0, &fs)) && fs == State_Stopped) { + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CBasePin* pPin = m_pInputs.GetNext(pos); + CComQIPtr pMS = pPin->GetConnected(); + if (!pMS) { + pMS = GetFilterFromPin(pPin->GetConnected()); + } + if (pMS) { + pMS->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags); + } + } + + return S_OK; + } + + return VFW_E_WRONG_STATE; +} + +STDMETHODIMP CBaseMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::SetRate(double dRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::GetRate(double* pdRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseMuxerFilter::GetPreroll(LONGLONG* pllPreroll) +{ + return E_NOTIMPL; +} diff --git a/src/filters/muxer/BaseMuxer/BaseMuxer.h b/src/filters/muxer/BaseMuxer/BaseMuxer.h index 942627830ea..be367f7b629 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxer.h +++ b/src/filters/muxer/BaseMuxer/BaseMuxer.h @@ -1,110 +1,110 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "BaseMuxerInputPin.h" -#include "BaseMuxerOutputPin.h" - -class CBaseMuxerFilter - : public CBaseFilter - , public CCritSec - , public CAMThread - , public IMediaSeeking - , public IDSMPropertyBagImpl - , public IDSMResourceBagImpl - , public IDSMChapterBagImpl -{ -private: - CAutoPtrList m_pInputs; - CAutoPtr m_pOutput; - CAutoPtrList m_pRawOutputs; - - enum { CMD_EXIT, CMD_RUN }; - DWORD ThreadProc(); - - REFERENCE_TIME m_rtCurrent; - CAtlList m_pActivePins; - - CAutoPtr GetPacket(); - - void MuxHeaderInternal(); - void MuxPacketInternal(const MuxerPacket* pPacket); - void MuxFooterInternal(); - -protected: - CAtlList m_pPins; - CBaseMuxerOutputPin* GetOutputPin() { return m_pOutput; } - - virtual void MuxInit() = 0; - - // only called when the output pin is connected - virtual void MuxHeader(IBitStream* pBS) {} - virtual void MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket) {} - virtual void MuxFooter(IBitStream* pBS) {} - - // always called (useful if the derived class wants to write somewhere else than downstream) - virtual void MuxHeader() {} - virtual void MuxPacket(const MuxerPacket* pPacket) {} - virtual void MuxFooter() {} - - // allows customized pins in derived classes - virtual HRESULT CreateInput(CStringW name, CBaseMuxerInputPin** ppPin); - virtual HRESULT CreateRawOutput(CStringW name, CBaseMuxerRawOutputPin** ppPin); - -public: - CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid); - virtual ~CBaseMuxerFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - void AddInput(); - - int GetPinCount(); - CBasePin* GetPin(int n); - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "BaseMuxerInputPin.h" +#include "BaseMuxerOutputPin.h" + +class CBaseMuxerFilter + : public CBaseFilter + , public CCritSec + , public CAMThread + , public IMediaSeeking + , public IDSMPropertyBagImpl + , public IDSMResourceBagImpl + , public IDSMChapterBagImpl +{ +private: + CAutoPtrList m_pInputs; + CAutoPtr m_pOutput; + CAutoPtrList m_pRawOutputs; + + enum { CMD_EXIT, CMD_RUN }; + DWORD ThreadProc(); + + REFERENCE_TIME m_rtCurrent; + CAtlList m_pActivePins; + + CAutoPtr GetPacket(); + + void MuxHeaderInternal(); + void MuxPacketInternal(const MuxerPacket* pPacket); + void MuxFooterInternal(); + +protected: + CAtlList m_pPins; + CBaseMuxerOutputPin* GetOutputPin() { return m_pOutput; } + + virtual void MuxInit() = 0; + + // only called when the output pin is connected + virtual void MuxHeader(IBitStream* pBS) {} + virtual void MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket) {} + virtual void MuxFooter(IBitStream* pBS) {} + + // always called (useful if the derived class wants to write somewhere else than downstream) + virtual void MuxHeader() {} + virtual void MuxPacket(const MuxerPacket* pPacket) {} + virtual void MuxFooter() {} + + // allows customized pins in derived classes + virtual HRESULT CreateInput(CStringW name, CBaseMuxerInputPin** ppPin); + virtual HRESULT CreateRawOutput(CStringW name, CBaseMuxerRawOutputPin** ppPin); + +public: + CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid); + virtual ~CBaseMuxerFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + void AddInput(); + + int GetPinCount(); + CBasePin* GetPin(int n); + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); +}; diff --git a/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj b/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj index 177c2b27430..0b774cefb9c 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj +++ b/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj @@ -1,74 +1,74 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {DB5F93B2-54D0-4474-A588-D259BE36C832} - BaseMuxer - MFCProj - BaseMuxer - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - - - Create - - - - - - - - - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {DB5F93B2-54D0-4474-A588-D259BE36C832} + BaseMuxer + MFCProj + BaseMuxer + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + + + Create + + + + + + + + + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj.filters b/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj.filters index 67f63e1d486..5b978fca968 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj.filters +++ b/src/filters/muxer/BaseMuxer/BaseMuxer.vcxproj.filters @@ -1,53 +1,53 @@ - - - - - {b0dec0e2-a0fd-4979-b3c8-e2a8b7b8a7b9} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {09ccdde9-0352-4031-8414-81a0579c014b} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {b0dec0e2-a0fd-4979-b3c8-e2a8b7b8a7b9} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {09ccdde9-0352-4031-8414-81a0579c014b} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.cpp b/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.cpp index 537bd233280..a55ade0e728 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.cpp +++ b/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.cpp @@ -1,286 +1,286 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "BaseMuxer.h" -#include "../../../DSUtil/DSUtil.h" -#include "moreuuids.h" - -#define MAXQUEUESIZE 100 - -// -// CBaseMuxerInputPin -// - -CBaseMuxerInputPin::CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseInputPin(NAME("CBaseMuxerInputPin"), pFilter, pLock, phr, pName) - , m_rtMaxStart(_I64_MIN) - , m_rtDuration(0) - , m_fEOS(false) - , m_iPacketIndex(0) - , m_evAcceptPacket(TRUE) -{ - static int s_iID = 0; - m_iID = s_iID++; -} - -CBaseMuxerInputPin::~CBaseMuxerInputPin() -{ -} - -STDMETHODIMP CBaseMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IBaseMuxerRelatedPin) - QI(IPropertyBag) - QI(IPropertyBag2) - QI(IDSMPropertyBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -bool CBaseMuxerInputPin::IsSubtitleStream() -{ - return m_mt.majortype == MEDIATYPE_Subtitle || m_mt.majortype == MEDIATYPE_Text; -} - -void CBaseMuxerInputPin::PushPacket(CAutoPtr pPacket) -{ - for (int i = 0; m_pFilter->IsActive() && !m_bFlushing - && !m_evAcceptPacket.Wait(1) - && i < 1000; - i++) { - ; - } - - if (!m_pFilter->IsActive() || m_bFlushing) { - return; - } - - CAutoLock cAutoLock(&m_csQueue); - - m_queue.AddTail(pPacket); - - if (m_queue.GetCount() >= MAXQUEUESIZE) { - m_evAcceptPacket.Reset(); - } -} - -CAutoPtr CBaseMuxerInputPin::PopPacket() -{ - CAutoPtr pPacket; - - CAutoLock cAutoLock(&m_csQueue); - - if (m_queue.GetCount()) { - pPacket.Attach(m_queue.RemoveHead().Detach()); - } - - if (m_queue.GetCount() < MAXQUEUESIZE) { - m_evAcceptPacket.Set(); - } - - return pPacket; -} - -HRESULT CBaseMuxerInputPin::CheckMediaType(const CMediaType* pmt) -{ - if (pmt->formattype == FORMAT_WaveFormatEx) { - WORD wFormatTag = ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag; - if ((wFormatTag == WAVE_FORMAT_PCM - || wFormatTag == WAVE_FORMAT_EXTENSIBLE - || wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - && pmt->subtype != FOURCCMap(wFormatTag) - && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_EXTENSIBLE) - && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - && pmt->subtype != MEDIASUBTYPE_DVD_LPCM_AUDIO - && pmt->subtype != MEDIASUBTYPE_DOLBY_AC3 - && pmt->subtype != MEDIASUBTYPE_DTS) { - return E_INVALIDARG; - } - } - - return pmt->majortype == MEDIATYPE_Video - || pmt->majortype == MEDIATYPE_Audio && pmt->formattype != FORMAT_VorbisFormat - || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None - || pmt->majortype == MEDIATYPE_Subtitle - ? S_OK - : E_INVALIDARG; -} - -HRESULT CBaseMuxerInputPin::BreakConnect() -{ - HRESULT hr = __super::BreakConnect(); - if (FAILED(hr)) { - return hr; - } - - RemoveAll(); - - // TODO: remove extra disconnected pins, leave one - - return hr; -} - -HRESULT CBaseMuxerInputPin::CompleteConnect(IPin* pReceivePin) -{ - HRESULT hr = __super::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - // duration - - m_rtDuration = 0; - CComQIPtr pMS; - if ((pMS = GetFilterFromPin(pReceivePin)) || (pMS = pReceivePin)) { - pMS->GetDuration(&m_rtDuration); - } - - // properties - - for (CComPtr pPin = pReceivePin; pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { - if (CComQIPtr pPB = pPin) { - ULONG cProperties = 0; - if (SUCCEEDED(pPB->CountProperties(&cProperties)) && cProperties > 0) { - for (ULONG iProperty = 0; iProperty < cProperties; iProperty++) { - PROPBAG2 PropBag; - ZeroMemory(&PropBag, sizeof(PropBag)); - ULONG cPropertiesReturned = 0; - if (FAILED(pPB->GetPropertyInfo(iProperty, 1, &PropBag, &cPropertiesReturned))) { - continue; - } - - HRESULT hr2; - CComVariant var; - if (SUCCEEDED(pPB->Read(1, &PropBag, nullptr, &var, &hr2)) && SUCCEEDED(hr2)) { - SetProperty(PropBag.pstrName, &var); - } - - CoTaskMemFree(PropBag.pstrName); - } - } - } - } - - (static_cast(m_pFilter))->AddInput(); - - return S_OK; -} - -HRESULT CBaseMuxerInputPin::Active() -{ - m_rtMaxStart = _I64_MIN; - m_fEOS = false; - m_iPacketIndex = 0; - m_evAcceptPacket.Set(); - return __super::Active(); -} - -HRESULT CBaseMuxerInputPin::Inactive() -{ - CAutoLock cAutoLock(&m_csQueue); - m_queue.RemoveAll(); - return __super::Inactive(); -} - -STDMETHODIMP CBaseMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - CAutoLock cAutoLock(&m_csReceive); - - return __super::NewSegment(tStart, tStop, dRate); -} - -STDMETHODIMP CBaseMuxerInputPin::Receive(IMediaSample* pSample) -{ - CAutoLock cAutoLock(&m_csReceive); - - HRESULT hr = __super::Receive(pSample); - if (FAILED(hr)) { - return hr; - } - - CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); - - long len = pSample->GetActualDataLength(); - - BYTE* pData = nullptr; - if (FAILED(pSample->GetPointer(&pData)) || !pData) { - return S_OK; - } - - pPacket->pData.SetCount(len); - memcpy(pPacket->pData.GetData(), pData, len); - - if (S_OK == pSample->IsSyncPoint() || m_mt.majortype == MEDIATYPE_Audio && !m_mt.bTemporalCompression) { - pPacket->flags |= MuxerPacket::syncpoint; - } - - if (S_OK == pSample->GetTime(&pPacket->rtStart, &pPacket->rtStop)) { - pPacket->flags |= MuxerPacket::timevalid; - - pPacket->rtStart += m_tStart; - pPacket->rtStop += m_tStart; - - if ((pPacket->flags & MuxerPacket::syncpoint) && pPacket->rtStart < m_rtMaxStart) { - pPacket->flags &= ~MuxerPacket::syncpoint; - pPacket->flags |= MuxerPacket::bogus; - } - - m_rtMaxStart = std::max(m_rtMaxStart, pPacket->rtStart); - } else if (pPacket->flags & MuxerPacket::syncpoint) { - pPacket->flags &= ~MuxerPacket::syncpoint; - pPacket->flags |= MuxerPacket::bogus; - } - - if (S_OK == pSample->IsDiscontinuity()) { - pPacket->flags |= MuxerPacket::discontinuity; - } - - pPacket->index = m_iPacketIndex++; - - PushPacket(pPacket); - - return S_OK; -} - -STDMETHODIMP CBaseMuxerInputPin::EndOfStream() -{ - CAutoLock cAutoLock(&m_csReceive); - - HRESULT hr = __super::EndOfStream(); - if (FAILED(hr)) { - return hr; - } - - ASSERT(!m_fEOS); - - CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); - pPacket->flags |= MuxerPacket::eos; - PushPacket(pPacket); - - m_fEOS = true; - - return hr; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "BaseMuxer.h" +#include "../../../DSUtil/DSUtil.h" +#include "moreuuids.h" + +#define MAXQUEUESIZE 100 + +// +// CBaseMuxerInputPin +// + +CBaseMuxerInputPin::CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseInputPin(NAME("CBaseMuxerInputPin"), pFilter, pLock, phr, pName) + , m_rtMaxStart(_I64_MIN) + , m_rtDuration(0) + , m_fEOS(false) + , m_iPacketIndex(0) + , m_evAcceptPacket(TRUE) +{ + static int s_iID = 0; + m_iID = s_iID++; +} + +CBaseMuxerInputPin::~CBaseMuxerInputPin() +{ +} + +STDMETHODIMP CBaseMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IBaseMuxerRelatedPin) + QI(IPropertyBag) + QI(IPropertyBag2) + QI(IDSMPropertyBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +bool CBaseMuxerInputPin::IsSubtitleStream() +{ + return m_mt.majortype == MEDIATYPE_Subtitle || m_mt.majortype == MEDIATYPE_Text; +} + +void CBaseMuxerInputPin::PushPacket(CAutoPtr pPacket) +{ + for (int i = 0; m_pFilter->IsActive() && !m_bFlushing + && !m_evAcceptPacket.Wait(1) + && i < 1000; + i++) { + ; + } + + if (!m_pFilter->IsActive() || m_bFlushing) { + return; + } + + CAutoLock cAutoLock(&m_csQueue); + + m_queue.AddTail(pPacket); + + if (m_queue.GetCount() >= MAXQUEUESIZE) { + m_evAcceptPacket.Reset(); + } +} + +CAutoPtr CBaseMuxerInputPin::PopPacket() +{ + CAutoPtr pPacket; + + CAutoLock cAutoLock(&m_csQueue); + + if (m_queue.GetCount()) { + pPacket.Attach(m_queue.RemoveHead().Detach()); + } + + if (m_queue.GetCount() < MAXQUEUESIZE) { + m_evAcceptPacket.Set(); + } + + return pPacket; +} + +HRESULT CBaseMuxerInputPin::CheckMediaType(const CMediaType* pmt) +{ + if (pmt->formattype == FORMAT_WaveFormatEx) { + WORD wFormatTag = ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag; + if ((wFormatTag == WAVE_FORMAT_PCM + || wFormatTag == WAVE_FORMAT_EXTENSIBLE + || wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + && pmt->subtype != FOURCCMap(wFormatTag) + && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_EXTENSIBLE) + && !(pmt->subtype == MEDIASUBTYPE_PCM && wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + && pmt->subtype != MEDIASUBTYPE_DVD_LPCM_AUDIO + && pmt->subtype != MEDIASUBTYPE_DOLBY_AC3 + && pmt->subtype != MEDIASUBTYPE_DTS) { + return E_INVALIDARG; + } + } + + return pmt->majortype == MEDIATYPE_Video + || pmt->majortype == MEDIATYPE_Audio && pmt->formattype != FORMAT_VorbisFormat + || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None + || pmt->majortype == MEDIATYPE_Subtitle + ? S_OK + : E_INVALIDARG; +} + +HRESULT CBaseMuxerInputPin::BreakConnect() +{ + HRESULT hr = __super::BreakConnect(); + if (FAILED(hr)) { + return hr; + } + + RemoveAll(); + + // TODO: remove extra disconnected pins, leave one + + return hr; +} + +HRESULT CBaseMuxerInputPin::CompleteConnect(IPin* pReceivePin) +{ + HRESULT hr = __super::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + // duration + + m_rtDuration = 0; + CComQIPtr pMS; + if ((pMS = GetFilterFromPin(pReceivePin)) || (pMS = pReceivePin)) { + pMS->GetDuration(&m_rtDuration); + } + + // properties + + for (CComPtr pPin = pReceivePin; pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { + if (CComQIPtr pPB = pPin) { + ULONG cProperties = 0; + if (SUCCEEDED(pPB->CountProperties(&cProperties)) && cProperties > 0) { + for (ULONG iProperty = 0; iProperty < cProperties; iProperty++) { + PROPBAG2 PropBag; + ZeroMemory(&PropBag, sizeof(PropBag)); + ULONG cPropertiesReturned = 0; + if (FAILED(pPB->GetPropertyInfo(iProperty, 1, &PropBag, &cPropertiesReturned))) { + continue; + } + + HRESULT hr2; + CComVariant var; + if (SUCCEEDED(pPB->Read(1, &PropBag, nullptr, &var, &hr2)) && SUCCEEDED(hr2)) { + SetProperty(PropBag.pstrName, &var); + } + + CoTaskMemFree(PropBag.pstrName); + } + } + } + } + + (static_cast(m_pFilter))->AddInput(); + + return S_OK; +} + +HRESULT CBaseMuxerInputPin::Active() +{ + m_rtMaxStart = _I64_MIN; + m_fEOS = false; + m_iPacketIndex = 0; + m_evAcceptPacket.Set(); + return __super::Active(); +} + +HRESULT CBaseMuxerInputPin::Inactive() +{ + CAutoLock cAutoLock(&m_csQueue); + m_queue.RemoveAll(); + return __super::Inactive(); +} + +STDMETHODIMP CBaseMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CAutoLock cAutoLock(&m_csReceive); + + return __super::NewSegment(tStart, tStop, dRate); +} + +STDMETHODIMP CBaseMuxerInputPin::Receive(IMediaSample* pSample) +{ + CAutoLock cAutoLock(&m_csReceive); + + HRESULT hr = __super::Receive(pSample); + if (FAILED(hr)) { + return hr; + } + + CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); + + long len = pSample->GetActualDataLength(); + + BYTE* pData = nullptr; + if (FAILED(pSample->GetPointer(&pData)) || !pData) { + return S_OK; + } + + pPacket->pData.SetCount(len); + memcpy(pPacket->pData.GetData(), pData, len); + + if (S_OK == pSample->IsSyncPoint() || m_mt.majortype == MEDIATYPE_Audio && !m_mt.bTemporalCompression) { + pPacket->flags |= MuxerPacket::syncpoint; + } + + if (S_OK == pSample->GetTime(&pPacket->rtStart, &pPacket->rtStop)) { + pPacket->flags |= MuxerPacket::timevalid; + + pPacket->rtStart += m_tStart; + pPacket->rtStop += m_tStart; + + if ((pPacket->flags & MuxerPacket::syncpoint) && pPacket->rtStart < m_rtMaxStart) { + pPacket->flags &= ~MuxerPacket::syncpoint; + pPacket->flags |= MuxerPacket::bogus; + } + + m_rtMaxStart = std::max(m_rtMaxStart, pPacket->rtStart); + } else if (pPacket->flags & MuxerPacket::syncpoint) { + pPacket->flags &= ~MuxerPacket::syncpoint; + pPacket->flags |= MuxerPacket::bogus; + } + + if (S_OK == pSample->IsDiscontinuity()) { + pPacket->flags |= MuxerPacket::discontinuity; + } + + pPacket->index = m_iPacketIndex++; + + PushPacket(pPacket); + + return S_OK; +} + +STDMETHODIMP CBaseMuxerInputPin::EndOfStream() +{ + CAutoLock cAutoLock(&m_csReceive); + + HRESULT hr = __super::EndOfStream(); + if (FAILED(hr)) { + return hr; + } + + ASSERT(!m_fEOS); + + CAutoPtr pPacket(DEBUG_NEW MuxerPacket(this)); + pPacket->flags |= MuxerPacket::eos; + PushPacket(pPacket); + + m_fEOS = true; + + return hr; +} diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.h b/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.h index 6b0023cb01c..eebaa293063 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.h +++ b/src/filters/muxer/BaseMuxer/BaseMuxerInputPin.h @@ -1,97 +1,97 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "BaseMuxerRelatedPin.h" -#include "../../../DSUtil/DSMPropertyBag.h" - -class CBaseMuxerInputPin; - -struct MuxerPacket { - CBaseMuxerInputPin* pPin; - REFERENCE_TIME rtStart, rtStop; - CAtlArray pData; - enum flag_t { - empty = 0, - timevalid = 1, - syncpoint = 2, - discontinuity = 4, - eos = 8, - bogus = 16 - }; - DWORD flags; - int index; - struct MuxerPacket(CBaseMuxerInputPin* pPin) { - this->pPin = pPin; - rtStart = rtStop = _I64_MIN; - flags = empty; - index = -1; - } - - bool IsTimeValid() const { return !!(flags & timevalid); } - bool IsSyncPoint() const { return !!(flags & syncpoint); } - bool IsDiscontinuity() const { return !!(flags & discontinuity); } - bool IsEOS() const { return !!(flags & eos); } - bool IsBogus() const { return !!(flags & bogus); } -}; - -class CBaseMuxerInputPin : public CBaseInputPin, public CBaseMuxerRelatedPin, public IDSMPropertyBagImpl -{ -private: - int m_iID; - - CCritSec m_csReceive; - REFERENCE_TIME m_rtMaxStart, m_rtDuration; - bool m_fEOS; - int m_iPacketIndex; - - CCritSec m_csQueue; - CAutoPtrList m_queue; - void PushPacket(CAutoPtr pPacket); - CAutoPtr PopPacket(); - CAMEvent m_evAcceptPacket; - - friend class CBaseMuxerFilter; - -public: - CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CBaseMuxerInputPin(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - REFERENCE_TIME GetDuration() { return m_rtDuration; } - int GetID() { return m_iID; } - CMediaType& CurrentMediaType() { return m_mt; } - bool IsSubtitleStream(); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pReceivePin); - - HRESULT Active(); - HRESULT Inactive(); - - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP EndOfStream(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "BaseMuxerRelatedPin.h" +#include "../../../DSUtil/DSMPropertyBag.h" + +class CBaseMuxerInputPin; + +struct MuxerPacket { + CBaseMuxerInputPin* pPin; + REFERENCE_TIME rtStart, rtStop; + CAtlArray pData; + enum flag_t { + empty = 0, + timevalid = 1, + syncpoint = 2, + discontinuity = 4, + eos = 8, + bogus = 16 + }; + DWORD flags; + int index; + struct MuxerPacket(CBaseMuxerInputPin* pPin) { + this->pPin = pPin; + rtStart = rtStop = _I64_MIN; + flags = empty; + index = -1; + } + + bool IsTimeValid() const { return !!(flags & timevalid); } + bool IsSyncPoint() const { return !!(flags & syncpoint); } + bool IsDiscontinuity() const { return !!(flags & discontinuity); } + bool IsEOS() const { return !!(flags & eos); } + bool IsBogus() const { return !!(flags & bogus); } +}; + +class CBaseMuxerInputPin : public CBaseInputPin, public CBaseMuxerRelatedPin, public IDSMPropertyBagImpl +{ +private: + int m_iID; + + CCritSec m_csReceive; + REFERENCE_TIME m_rtMaxStart, m_rtDuration; + bool m_fEOS; + int m_iPacketIndex; + + CCritSec m_csQueue; + CAutoPtrList m_queue; + void PushPacket(CAutoPtr pPacket); + CAutoPtr PopPacket(); + CAMEvent m_evAcceptPacket; + + friend class CBaseMuxerFilter; + +public: + CBaseMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CBaseMuxerInputPin(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + REFERENCE_TIME GetDuration() { return m_rtDuration; } + int GetID() { return m_iID; } + CMediaType& CurrentMediaType() { return m_mt; } + bool IsSubtitleStream(); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pReceivePin); + + HRESULT Active(); + HRESULT Inactive(); + + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP EndOfStream(); +}; diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.cpp b/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.cpp index fa570482ed8..764ba3b6c4b 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.cpp +++ b/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.cpp @@ -1,487 +1,487 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "BaseMuxerOutputPin.h" - -#include -#include -#include - -#include "moreuuids.h" -#include "../DSUtil/ISOLang.h" - -// -// CBaseMuxerOutputPin -// - -CBaseMuxerOutputPin::CBaseMuxerOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseOutputPin(_T("CBaseMuxerOutputPin"), pFilter, pLock, phr, pName) -{ -} - -IBitStream* CBaseMuxerOutputPin::GetBitStream() -{ - if (!m_pBitStream) { - if (CComQIPtr pStream = GetConnected()) { - m_pBitStream = DEBUG_NEW CBitStream(pStream, true); - } - } - - return m_pBitStream; -} - -HRESULT CBaseMuxerOutputPin::BreakConnect() -{ - m_pBitStream = nullptr; - - return __super::BreakConnect(); -} - -HRESULT CBaseMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = 1; - pProperties->cbBuffer = 1; - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CBaseMuxerOutputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_NULL - ? S_OK - : E_INVALIDARG; -} - -HRESULT CBaseMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CAutoLock cAutoLock(m_pLock); - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - pmt->ResetFormatBuffer(); - pmt->InitMediaType(); - pmt->majortype = MEDIATYPE_Stream; - pmt->subtype = MEDIASUBTYPE_NULL; - pmt->formattype = FORMAT_None; - - return S_OK; -} - -HRESULT CBaseMuxerOutputPin::DeliverEndOfStream() -{ - m_pBitStream = nullptr; - - return __super::DeliverEndOfStream(); -} - -STDMETHODIMP CBaseMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} - -// -// CBaseMuxerRawOutputPin -// - -CBaseMuxerRawOutputPin::CBaseMuxerRawOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseMuxerOutputPin(pName, pFilter, pLock, phr) -{ -} - -STDMETHODIMP CBaseMuxerRawOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IBaseMuxerRelatedPin) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CBaseMuxerRawOutputPin::MuxHeader(const CMediaType& mt) -{ - CComQIPtr pBitStream = GetBitStream(); - if (!pBitStream) { - return; - } - - const BYTE utf8bom[3] = {0xef, 0xbb, 0xbf}; - - if ((mt.subtype == FOURCCMap('1CVA') || mt.subtype == FOURCCMap('1cva')) && mt.formattype == FORMAT_MPEG2_VIDEO) { - MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.Format(); - - for (DWORD i = 0; i < vih->cbSequenceHeader - 2; i += 2) { - pBitStream->BitWrite(0x00000001, 32); - WORD size = (((BYTE*)vih->dwSequenceHeader)[i + 0] << 8) | ((BYTE*)vih->dwSequenceHeader)[i + 1]; - pBitStream->ByteWrite(&((BYTE*)vih->dwSequenceHeader)[i + 2], size); - i += size; - } - } else if (mt.subtype == MEDIASUBTYPE_UTF8) { - pBitStream->ByteWrite(utf8bom, sizeof(utf8bom)); - } else if (mt.subtype == MEDIASUBTYPE_SSA || mt.subtype == MEDIASUBTYPE_ASS || mt.subtype == MEDIASUBTYPE_ASS2) { - SUBTITLEINFO* si = (SUBTITLEINFO*)mt.Format(); - BYTE* p = (BYTE*)si + si->dwOffset; - - if (memcmp(utf8bom, p, 3) != 0) { - pBitStream->ByteWrite(utf8bom, sizeof(utf8bom)); - } - - CStringA str((char*)p, mt.FormatLength() - (ULONG)(p - mt.Format())); - pBitStream->StrWrite(str + '\n', true); - - if (str.Find("[Events]") < 0) { - pBitStream->StrWrite("\n\n[Events]\n", true); - } - } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { - m_idx.RemoveAll(); - } else if (mt.majortype == MEDIATYPE_Audio - && (mt.subtype == MEDIASUBTYPE_PCM - || mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO - || mt.subtype == FOURCCMap(WAVE_FORMAT_EXTENSIBLE) - || mt.subtype == FOURCCMap(WAVE_FORMAT_IEEE_FLOAT)) - && mt.formattype == FORMAT_WaveFormatEx) { - pBitStream->BitWrite('RIFF', 32); - pBitStream->BitWrite(0, 32); // file length - 8, set later - pBitStream->BitWrite('WAVE', 32); - - pBitStream->BitWrite('fmt ', 32); - pBitStream->ByteWrite(&mt.cbFormat, 4); - pBitStream->ByteWrite(mt.pbFormat, mt.cbFormat); - - pBitStream->BitWrite('data', 32); - pBitStream->BitWrite(0, 32); // data length, set later - } -} - -void CBaseMuxerRawOutputPin::MuxPacket(const CMediaType& mt, const MuxerPacket* pPacket) -{ - CComQIPtr pBitStream = GetBitStream(); - if (!pBitStream) { - return; - } - - const BYTE* pData = pPacket->pData.GetData(); - const int DataSize = int(pPacket->pData.GetCount()); - - if (mt.subtype == MEDIASUBTYPE_AAC && mt.formattype == FORMAT_WaveFormatEx) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); - - int profile = 0; - - int srate_idx = 11; - if (92017 <= wfe->nSamplesPerSec) { - srate_idx = 0; - } else if (75132 <= wfe->nSamplesPerSec) { - srate_idx = 1; - } else if (55426 <= wfe->nSamplesPerSec) { - srate_idx = 2; - } else if (46009 <= wfe->nSamplesPerSec) { - srate_idx = 3; - } else if (37566 <= wfe->nSamplesPerSec) { - srate_idx = 4; - } else if (27713 <= wfe->nSamplesPerSec) { - srate_idx = 5; - } else if (23004 <= wfe->nSamplesPerSec) { - srate_idx = 6; - } else if (18783 <= wfe->nSamplesPerSec) { - srate_idx = 7; - } else if (13856 <= wfe->nSamplesPerSec) { - srate_idx = 8; - } else if (11502 <= wfe->nSamplesPerSec) { - srate_idx = 9; - } else if (9391 <= wfe->nSamplesPerSec) { - srate_idx = 10; - } - - int channels = wfe->nChannels; - - if (wfe->cbSize >= 2) { - BYTE* p = (BYTE*)(wfe + 1); - profile = (p[0] >> 3) - 1; - srate_idx = ((p[0] & 7) << 1) | ((p[1] & 0x80) >> 7); - channels = (p[1] >> 3) & 15; - } - - int len = (DataSize + 7) & 0x1fff; - - BYTE hdr[7] = {0xff, 0xf9}; - hdr[2] = BYTE((profile << 6) | (srate_idx << 2) | ((channels & 4) >> 2)); - hdr[3] = BYTE(((channels & 3) << 6) | (len >> 11)); - hdr[4] = (len >> 3) & 0xff; - hdr[5] = ((len & 7) << 5) | 0x1f; - hdr[6] = 0xfc; - - pBitStream->ByteWrite(hdr, sizeof(hdr)); - } else if ((mt.subtype == FOURCCMap('1CVA') || mt.subtype == FOURCCMap('1cva')) && mt.formattype == FORMAT_MPEG2_VIDEO) { - const BYTE* p = pData; - int i = DataSize; - - while (i >= 4) { - DWORD len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - - i -= len + 4; - p += len + 4; - } - - if (i == 0) { - p = pData; - i = DataSize; - - while (i >= 4) { - DWORD len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; - - pBitStream->BitWrite(0x00000001, 32); - - p += 4; - i -= 4; - - if (len > (DWORD)i || len == 1) { - len = i; - ASSERT(0); - } - - pBitStream->ByteWrite(p, len); - - p += len; - i -= len; - } - - return; - } - } else if (mt.subtype == MEDIASUBTYPE_UTF8 || mt.majortype == MEDIATYPE_Text) { - CStringA str((char*)pData, DataSize); - str.Trim(); - if (str.IsEmpty()) { - return; - } - - DVD_HMSF_TIMECODE start = RT2HMSF(pPacket->rtStart, 25); - DVD_HMSF_TIMECODE stop = RT2HMSF(pPacket->rtStop, 25); - - str.Format("%d\n%02u:%02u:%02u,%03d --> %02u:%02u:%02u,%03d\n%s\n\n", - pPacket->index + 1, - start.bHours, start.bMinutes, start.bSeconds, (int)((pPacket->rtStart / 10000) % 1000), - stop.bHours, stop.bMinutes, stop.bSeconds, (int)((pPacket->rtStop / 10000) % 1000), - CStringA(str).GetString()); - - pBitStream->StrWrite(str, true); - - return; - } else if (mt.subtype == MEDIASUBTYPE_SSA || mt.subtype == MEDIASUBTYPE_ASS || mt.subtype == MEDIASUBTYPE_ASS2) { - CStringA str((char*)pData, DataSize); - str.Trim(); - if (str.IsEmpty()) { - return; - } - - DVD_HMSF_TIMECODE start = RT2HMSF(pPacket->rtStart, 25); - DVD_HMSF_TIMECODE stop = RT2HMSF(pPacket->rtStop, 25); - - size_t fields = mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9; - - CAtlList sl; - Explode(str, sl, ',', fields); - if (sl.GetCount() < fields) { - return; - } - - CStringA readorder = sl.RemoveHead(); // TODO - CStringA layer = sl.RemoveHead(); - CStringA style = sl.RemoveHead(); - CStringA actor = sl.RemoveHead(); - CStringA left = sl.RemoveHead(); - CStringA right = sl.RemoveHead(); - CStringA top = sl.RemoveHead(); - if (fields == 10) { - top += ',' + sl.RemoveHead(); // bottom - } - CStringA effect = sl.RemoveHead(); - str = sl.RemoveHead(); - - if (mt.subtype == MEDIASUBTYPE_SSA) { - layer = "Marked=0"; - } - - str.Format("Dialogue: %s,%u:%02u:%02u.%02d,%u:%02u:%02u.%02d,%s,%s,%s,%s,%s,%s,%s\n", - layer.GetString(), - start.bHours, start.bMinutes, start.bSeconds, (int)((pPacket->rtStart / 100000) % 100), - stop.bHours, stop.bMinutes, stop.bSeconds, (int)((pPacket->rtStop / 100000) % 100), - style.GetString(), actor.GetString(), left.GetString(), right.GetString(), top.GetString(), effect.GetString(), - CStringA(str).GetString()); - - pBitStream->StrWrite(str, true); - - return; - } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { - bool fTimeValid = pPacket->IsTimeValid(); - - if (fTimeValid) { - idx_t i; - i.rt = pPacket->rtStart; - i.fp = pBitStream->GetPos(); - m_idx.AddTail(i); - } - - int DataSizeLeft = DataSize; - - while (DataSizeLeft > 0) { - int BytesAvail = 0x7ec - (fTimeValid ? 9 : 4); - int Size = std::min(BytesAvail, DataSizeLeft); - int Padding = 0x800 - Size - 20 - (fTimeValid ? 9 : 4); - - pBitStream->BitWrite(0x000001ba, 32); - pBitStream->BitWrite(0x440004000401ui64, 48); - pBitStream->BitWrite(0x000003f8, 32); - pBitStream->BitWrite(0x000001bd, 32); - - if (fTimeValid) { - pBitStream->BitWrite(Size + 9, 16); - pBitStream->BitWrite(0x8180052100010001ui64, 64); - } else { - pBitStream->BitWrite(Size + 4, 16); - pBitStream->BitWrite(0x810000, 24); - } - - pBitStream->BitWrite(0x20, 8); - - pBitStream->ByteWrite(pData, Size); - - pData += Size; - DataSizeLeft -= Size; - - if (Padding > 0) { - Padding -= 6; - ASSERT(Padding >= 0); - pBitStream->BitWrite(0x000001be, 32); - pBitStream->BitWrite(Padding, 16); - while (Padding-- > 0) { - pBitStream->BitWrite(0xff, 8); - } - } - - fTimeValid = false; - } - - return; - } else if (mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); - - // This code is probably totally broken for anything but 16 bits - for (int i = 0, bps = wfe->wBitsPerSample / 8; i < DataSize; i += bps) - for (int j = bps - 1; j >= 0; j--) { - pBitStream->BitWrite(pData[i + j], 8); - } - - return; - } - // else // TODO: restore more streams (vorbis to ogg) - - pBitStream->ByteWrite(pData, DataSize); -} - -void CBaseMuxerRawOutputPin::MuxFooter(const CMediaType& mt) -{ - CComQIPtr pBitStream = GetBitStream(); - if (!pBitStream) { - return; - } - - if (mt.majortype == MEDIATYPE_Audio - && (mt.subtype == MEDIASUBTYPE_PCM - || mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO - || mt.subtype == FOURCCMap(WAVE_FORMAT_EXTENSIBLE) - || mt.subtype == FOURCCMap(WAVE_FORMAT_IEEE_FLOAT)) - && mt.formattype == FORMAT_WaveFormatEx) { - pBitStream->BitFlush(); - - ASSERT(pBitStream->GetPos() <= 0xffffffff); - UINT32 size = (UINT32)pBitStream->GetPos(); - - size -= 8; - pBitStream->Seek(4); - pBitStream->ByteWrite(&size, 4); - - size -= sizeof(RIFFLIST) + sizeof(RIFFCHUNK) + mt.FormatLength(); - pBitStream->Seek(sizeof(RIFFLIST) + sizeof(RIFFCHUNK) + mt.FormatLength() + 4); - pBitStream->ByteWrite(&size, 4); - } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { - if (CComQIPtr pFSF = GetFilterFromPin(GetConnected())) { - WCHAR* fn = nullptr; - if (SUCCEEDED(pFSF->GetCurFile(&fn, nullptr))) { - CPathW p(fn); - p.RenameExtension(L".idx"); - CoTaskMemFree(fn); - - FILE* f; - if (!_tfopen_s(&f, CString((LPCWSTR)p), _T("w"))) { - SUBTITLEINFO* si = (SUBTITLEINFO*)mt.Format(); - - _ftprintf_s(f, _T("%s\n"), _T("# VobSub index file, v7 (do not modify this line!)")); - - fwrite(mt.Format() + si->dwOffset, mt.FormatLength() - si->dwOffset, 1, f); - - CString iso6391 = ISOLang::ISO6392To6391(si->IsoLang); - if (iso6391.IsEmpty()) { - iso6391 = _T("--"); - } - _ftprintf_s(f, _T("\nlangidx: 0\n\nid: %s, index: 0\n"), iso6391.GetString()); - - CString alt = CString(CStringW(si->TrackName)); - if (!alt.IsEmpty()) { - _ftprintf_s(f, _T("alt: %s\n"), alt.GetString()); - } - - POSITION pos = m_idx.GetHeadPosition(); - while (pos) { - const idx_t& i = m_idx.GetNext(pos); - DVD_HMSF_TIMECODE start = RT2HMSF(i.rt, 25); - _ftprintf_s(f, _T("timestamp: %02u:%02u:%02u:%03d, filepos: %09I64x\n"), - start.bHours, start.bMinutes, start.bSeconds, (int)((i.rt / 10000) % 1000), - i.fp); - } - - fclose(f); - } - } - } - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "BaseMuxerOutputPin.h" + +#include +#include +#include + +#include "moreuuids.h" +#include "../DSUtil/ISOLang.h" + +// +// CBaseMuxerOutputPin +// + +CBaseMuxerOutputPin::CBaseMuxerOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseOutputPin(_T("CBaseMuxerOutputPin"), pFilter, pLock, phr, pName) +{ +} + +IBitStream* CBaseMuxerOutputPin::GetBitStream() +{ + if (!m_pBitStream) { + if (CComQIPtr pStream = GetConnected()) { + m_pBitStream = DEBUG_NEW CBitStream(pStream, true); + } + } + + return m_pBitStream; +} + +HRESULT CBaseMuxerOutputPin::BreakConnect() +{ + m_pBitStream = nullptr; + + return __super::BreakConnect(); +} + +HRESULT CBaseMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = 1; + pProperties->cbBuffer = 1; + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CBaseMuxerOutputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_NULL + ? S_OK + : E_INVALIDARG; +} + +HRESULT CBaseMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CAutoLock cAutoLock(m_pLock); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + pmt->ResetFormatBuffer(); + pmt->InitMediaType(); + pmt->majortype = MEDIATYPE_Stream; + pmt->subtype = MEDIASUBTYPE_NULL; + pmt->formattype = FORMAT_None; + + return S_OK; +} + +HRESULT CBaseMuxerOutputPin::DeliverEndOfStream() +{ + m_pBitStream = nullptr; + + return __super::DeliverEndOfStream(); +} + +STDMETHODIMP CBaseMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} + +// +// CBaseMuxerRawOutputPin +// + +CBaseMuxerRawOutputPin::CBaseMuxerRawOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseMuxerOutputPin(pName, pFilter, pLock, phr) +{ +} + +STDMETHODIMP CBaseMuxerRawOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IBaseMuxerRelatedPin) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CBaseMuxerRawOutputPin::MuxHeader(const CMediaType& mt) +{ + CComQIPtr pBitStream = GetBitStream(); + if (!pBitStream) { + return; + } + + const BYTE utf8bom[3] = {0xef, 0xbb, 0xbf}; + + if ((mt.subtype == FOURCCMap('1CVA') || mt.subtype == FOURCCMap('1cva')) && mt.formattype == FORMAT_MPEG2_VIDEO) { + MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.Format(); + + for (DWORD i = 0; i < vih->cbSequenceHeader - 2; i += 2) { + pBitStream->BitWrite(0x00000001, 32); + WORD size = (((BYTE*)vih->dwSequenceHeader)[i + 0] << 8) | ((BYTE*)vih->dwSequenceHeader)[i + 1]; + pBitStream->ByteWrite(&((BYTE*)vih->dwSequenceHeader)[i + 2], size); + i += size; + } + } else if (mt.subtype == MEDIASUBTYPE_UTF8) { + pBitStream->ByteWrite(utf8bom, sizeof(utf8bom)); + } else if (mt.subtype == MEDIASUBTYPE_SSA || mt.subtype == MEDIASUBTYPE_ASS || mt.subtype == MEDIASUBTYPE_ASS2) { + SUBTITLEINFO* si = (SUBTITLEINFO*)mt.Format(); + BYTE* p = (BYTE*)si + si->dwOffset; + + if (memcmp(utf8bom, p, 3) != 0) { + pBitStream->ByteWrite(utf8bom, sizeof(utf8bom)); + } + + CStringA str((char*)p, mt.FormatLength() - (ULONG)(p - mt.Format())); + pBitStream->StrWrite(str + '\n', true); + + if (str.Find("[Events]") < 0) { + pBitStream->StrWrite("\n\n[Events]\n", true); + } + } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { + m_idx.RemoveAll(); + } else if (mt.majortype == MEDIATYPE_Audio + && (mt.subtype == MEDIASUBTYPE_PCM + || mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO + || mt.subtype == FOURCCMap(WAVE_FORMAT_EXTENSIBLE) + || mt.subtype == FOURCCMap(WAVE_FORMAT_IEEE_FLOAT)) + && mt.formattype == FORMAT_WaveFormatEx) { + pBitStream->BitWrite('RIFF', 32); + pBitStream->BitWrite(0, 32); // file length - 8, set later + pBitStream->BitWrite('WAVE', 32); + + pBitStream->BitWrite('fmt ', 32); + pBitStream->ByteWrite(&mt.cbFormat, 4); + pBitStream->ByteWrite(mt.pbFormat, mt.cbFormat); + + pBitStream->BitWrite('data', 32); + pBitStream->BitWrite(0, 32); // data length, set later + } +} + +void CBaseMuxerRawOutputPin::MuxPacket(const CMediaType& mt, const MuxerPacket* pPacket) +{ + CComQIPtr pBitStream = GetBitStream(); + if (!pBitStream) { + return; + } + + const BYTE* pData = pPacket->pData.GetData(); + const int DataSize = int(pPacket->pData.GetCount()); + + if (mt.subtype == MEDIASUBTYPE_AAC && mt.formattype == FORMAT_WaveFormatEx) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); + + int profile = 0; + + int srate_idx = 11; + if (92017 <= wfe->nSamplesPerSec) { + srate_idx = 0; + } else if (75132 <= wfe->nSamplesPerSec) { + srate_idx = 1; + } else if (55426 <= wfe->nSamplesPerSec) { + srate_idx = 2; + } else if (46009 <= wfe->nSamplesPerSec) { + srate_idx = 3; + } else if (37566 <= wfe->nSamplesPerSec) { + srate_idx = 4; + } else if (27713 <= wfe->nSamplesPerSec) { + srate_idx = 5; + } else if (23004 <= wfe->nSamplesPerSec) { + srate_idx = 6; + } else if (18783 <= wfe->nSamplesPerSec) { + srate_idx = 7; + } else if (13856 <= wfe->nSamplesPerSec) { + srate_idx = 8; + } else if (11502 <= wfe->nSamplesPerSec) { + srate_idx = 9; + } else if (9391 <= wfe->nSamplesPerSec) { + srate_idx = 10; + } + + int channels = wfe->nChannels; + + if (wfe->cbSize >= 2) { + BYTE* p = (BYTE*)(wfe + 1); + profile = (p[0] >> 3) - 1; + srate_idx = ((p[0] & 7) << 1) | ((p[1] & 0x80) >> 7); + channels = (p[1] >> 3) & 15; + } + + int len = (DataSize + 7) & 0x1fff; + + BYTE hdr[7] = {0xff, 0xf9}; + hdr[2] = BYTE((profile << 6) | (srate_idx << 2) | ((channels & 4) >> 2)); + hdr[3] = BYTE(((channels & 3) << 6) | (len >> 11)); + hdr[4] = (len >> 3) & 0xff; + hdr[5] = ((len & 7) << 5) | 0x1f; + hdr[6] = 0xfc; + + pBitStream->ByteWrite(hdr, sizeof(hdr)); + } else if ((mt.subtype == FOURCCMap('1CVA') || mt.subtype == FOURCCMap('1cva')) && mt.formattype == FORMAT_MPEG2_VIDEO) { + const BYTE* p = pData; + int i = DataSize; + + while (i >= 4) { + DWORD len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + + i -= len + 4; + p += len + 4; + } + + if (i == 0) { + p = pData; + i = DataSize; + + while (i >= 4) { + DWORD len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + + pBitStream->BitWrite(0x00000001, 32); + + p += 4; + i -= 4; + + if (len > (DWORD)i || len == 1) { + len = i; + ASSERT(0); + } + + pBitStream->ByteWrite(p, len); + + p += len; + i -= len; + } + + return; + } + } else if (mt.subtype == MEDIASUBTYPE_UTF8 || mt.majortype == MEDIATYPE_Text) { + CStringA str((char*)pData, DataSize); + str.Trim(); + if (str.IsEmpty()) { + return; + } + + DVD_HMSF_TIMECODE start = RT2HMSF(pPacket->rtStart, 25); + DVD_HMSF_TIMECODE stop = RT2HMSF(pPacket->rtStop, 25); + + str.Format("%d\n%02u:%02u:%02u,%03d --> %02u:%02u:%02u,%03d\n%s\n\n", + pPacket->index + 1, + start.bHours, start.bMinutes, start.bSeconds, (int)((pPacket->rtStart / 10000) % 1000), + stop.bHours, stop.bMinutes, stop.bSeconds, (int)((pPacket->rtStop / 10000) % 1000), + CStringA(str).GetString()); + + pBitStream->StrWrite(str, true); + + return; + } else if (mt.subtype == MEDIASUBTYPE_SSA || mt.subtype == MEDIASUBTYPE_ASS || mt.subtype == MEDIASUBTYPE_ASS2) { + CStringA str((char*)pData, DataSize); + str.Trim(); + if (str.IsEmpty()) { + return; + } + + DVD_HMSF_TIMECODE start = RT2HMSF(pPacket->rtStart, 25); + DVD_HMSF_TIMECODE stop = RT2HMSF(pPacket->rtStop, 25); + + size_t fields = mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9; + + CAtlList sl; + Explode(str, sl, ',', fields); + if (sl.GetCount() < fields) { + return; + } + + CStringA readorder = sl.RemoveHead(); // TODO + CStringA layer = sl.RemoveHead(); + CStringA style = sl.RemoveHead(); + CStringA actor = sl.RemoveHead(); + CStringA left = sl.RemoveHead(); + CStringA right = sl.RemoveHead(); + CStringA top = sl.RemoveHead(); + if (fields == 10) { + top += ',' + sl.RemoveHead(); // bottom + } + CStringA effect = sl.RemoveHead(); + str = sl.RemoveHead(); + + if (mt.subtype == MEDIASUBTYPE_SSA) { + layer = "Marked=0"; + } + + str.Format("Dialogue: %s,%u:%02u:%02u.%02d,%u:%02u:%02u.%02d,%s,%s,%s,%s,%s,%s,%s\n", + layer.GetString(), + start.bHours, start.bMinutes, start.bSeconds, (int)((pPacket->rtStart / 100000) % 100), + stop.bHours, stop.bMinutes, stop.bSeconds, (int)((pPacket->rtStop / 100000) % 100), + style.GetString(), actor.GetString(), left.GetString(), right.GetString(), top.GetString(), effect.GetString(), + CStringA(str).GetString()); + + pBitStream->StrWrite(str, true); + + return; + } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { + bool fTimeValid = pPacket->IsTimeValid(); + + if (fTimeValid) { + idx_t i; + i.rt = pPacket->rtStart; + i.fp = pBitStream->GetPos(); + m_idx.AddTail(i); + } + + int DataSizeLeft = DataSize; + + while (DataSizeLeft > 0) { + int BytesAvail = 0x7ec - (fTimeValid ? 9 : 4); + int Size = std::min(BytesAvail, DataSizeLeft); + int Padding = 0x800 - Size - 20 - (fTimeValid ? 9 : 4); + + pBitStream->BitWrite(0x000001ba, 32); + pBitStream->BitWrite(0x440004000401ui64, 48); + pBitStream->BitWrite(0x000003f8, 32); + pBitStream->BitWrite(0x000001bd, 32); + + if (fTimeValid) { + pBitStream->BitWrite(Size + 9, 16); + pBitStream->BitWrite(0x8180052100010001ui64, 64); + } else { + pBitStream->BitWrite(Size + 4, 16); + pBitStream->BitWrite(0x810000, 24); + } + + pBitStream->BitWrite(0x20, 8); + + pBitStream->ByteWrite(pData, Size); + + pData += Size; + DataSizeLeft -= Size; + + if (Padding > 0) { + Padding -= 6; + ASSERT(Padding >= 0); + pBitStream->BitWrite(0x000001be, 32); + pBitStream->BitWrite(Padding, 16); + while (Padding-- > 0) { + pBitStream->BitWrite(0xff, 8); + } + } + + fTimeValid = false; + } + + return; + } else if (mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); + + // This code is probably totally broken for anything but 16 bits + for (int i = 0, bps = wfe->wBitsPerSample / 8; i < DataSize; i += bps) + for (int j = bps - 1; j >= 0; j--) { + pBitStream->BitWrite(pData[i + j], 8); + } + + return; + } + // else // TODO: restore more streams (vorbis to ogg) + + pBitStream->ByteWrite(pData, DataSize); +} + +void CBaseMuxerRawOutputPin::MuxFooter(const CMediaType& mt) +{ + CComQIPtr pBitStream = GetBitStream(); + if (!pBitStream) { + return; + } + + if (mt.majortype == MEDIATYPE_Audio + && (mt.subtype == MEDIASUBTYPE_PCM + || mt.subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO + || mt.subtype == FOURCCMap(WAVE_FORMAT_EXTENSIBLE) + || mt.subtype == FOURCCMap(WAVE_FORMAT_IEEE_FLOAT)) + && mt.formattype == FORMAT_WaveFormatEx) { + pBitStream->BitFlush(); + + ASSERT(pBitStream->GetPos() <= 0xffffffff); + UINT32 size = (UINT32)pBitStream->GetPos(); + + size -= 8; + pBitStream->Seek(4); + pBitStream->ByteWrite(&size, 4); + + size -= sizeof(RIFFLIST) + sizeof(RIFFCHUNK) + mt.FormatLength(); + pBitStream->Seek(sizeof(RIFFLIST) + sizeof(RIFFCHUNK) + mt.FormatLength() + 4); + pBitStream->ByteWrite(&size, 4); + } else if (mt.subtype == MEDIASUBTYPE_VOBSUB) { + if (CComQIPtr pFSF = GetFilterFromPin(GetConnected())) { + WCHAR* fn = nullptr; + if (SUCCEEDED(pFSF->GetCurFile(&fn, nullptr))) { + CPathW p(fn); + p.RenameExtension(L".idx"); + CoTaskMemFree(fn); + + FILE* f; + if (!_tfopen_s(&f, CString((LPCWSTR)p), _T("w"))) { + SUBTITLEINFO* si = (SUBTITLEINFO*)mt.Format(); + + _ftprintf_s(f, _T("%s\n"), _T("# VobSub index file, v7 (do not modify this line!)")); + + fwrite(mt.Format() + si->dwOffset, mt.FormatLength() - si->dwOffset, 1, f); + + CString iso6391 = ISOLang::ISO6392To6391(si->IsoLang); + if (iso6391.IsEmpty()) { + iso6391 = _T("--"); + } + _ftprintf_s(f, _T("\nlangidx: 0\n\nid: %s, index: 0\n"), iso6391.GetString()); + + CString alt = CString(CStringW(si->TrackName)); + if (!alt.IsEmpty()) { + _ftprintf_s(f, _T("alt: %s\n"), alt.GetString()); + } + + POSITION pos = m_idx.GetHeadPosition(); + while (pos) { + const idx_t& i = m_idx.GetNext(pos); + DVD_HMSF_TIMECODE start = RT2HMSF(i.rt, 25); + _ftprintf_s(f, _T("timestamp: %02u:%02u:%02u:%03d, filepos: %09I64x\n"), + start.bHours, start.bMinutes, start.bSeconds, (int)((i.rt / 10000) % 1000), + i.fp); + } + + fclose(f); + } + } + } + } +} diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.h b/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.h index 4fb99dbda40..eb9dd9d762f 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.h +++ b/src/filters/muxer/BaseMuxer/BaseMuxerOutputPin.h @@ -1,68 +1,68 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "BitStream.h" -#include "BaseMuxerInputPin.h" -#include "BaseMuxerRelatedPin.h" - -class CBaseMuxerOutputPin : public CBaseOutputPin -{ - CComPtr m_pBitStream; - -public: - CBaseMuxerOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CBaseMuxerOutputPin() {} - - IBitStream* GetBitStream(); - - HRESULT BreakConnect(); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - - HRESULT DeliverEndOfStream(); - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; - -class CBaseMuxerRawOutputPin : public CBaseMuxerOutputPin, public CBaseMuxerRelatedPin -{ - struct idx_t { - REFERENCE_TIME rt; - __int64 fp; - }; - CAtlList m_idx; - -public: - CBaseMuxerRawOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CBaseMuxerRawOutputPin() {} - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - virtual void MuxHeader(const CMediaType& mt); - virtual void MuxPacket(const CMediaType& mt, const MuxerPacket* pPacket); - virtual void MuxFooter(const CMediaType& mt); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "BitStream.h" +#include "BaseMuxerInputPin.h" +#include "BaseMuxerRelatedPin.h" + +class CBaseMuxerOutputPin : public CBaseOutputPin +{ + CComPtr m_pBitStream; + +public: + CBaseMuxerOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CBaseMuxerOutputPin() {} + + IBitStream* GetBitStream(); + + HRESULT BreakConnect(); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + + HRESULT DeliverEndOfStream(); + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; + +class CBaseMuxerRawOutputPin : public CBaseMuxerOutputPin, public CBaseMuxerRelatedPin +{ + struct idx_t { + REFERENCE_TIME rt; + __int64 fp; + }; + CAtlList m_idx; + +public: + CBaseMuxerRawOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CBaseMuxerRawOutputPin() {} + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + virtual void MuxHeader(const CMediaType& mt); + virtual void MuxPacket(const CMediaType& mt, const MuxerPacket* pPacket); + virtual void MuxFooter(const CMediaType& mt); +}; diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.cpp b/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.cpp index 7f6d6f33439..2505c3dba9d 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.cpp +++ b/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.cpp @@ -1,49 +1,49 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "BaseMuxerRelatedPin.h" - -// -// CBaseMuxerRelatedPin -// - -CBaseMuxerRelatedPin::CBaseMuxerRelatedPin() - : m_pRelatedPin(nullptr) -{ -} - -CBaseMuxerRelatedPin::~CBaseMuxerRelatedPin() -{ -} - -// IBaseMuxerRelatedPin - -STDMETHODIMP CBaseMuxerRelatedPin::SetRelatedPin(CBasePin* pPin) -{ - m_pRelatedPin = pPin; - return S_OK; -} - -STDMETHODIMP_(CBasePin*) CBaseMuxerRelatedPin::GetRelatedPin() -{ - return m_pRelatedPin; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "BaseMuxerRelatedPin.h" + +// +// CBaseMuxerRelatedPin +// + +CBaseMuxerRelatedPin::CBaseMuxerRelatedPin() + : m_pRelatedPin(nullptr) +{ +} + +CBaseMuxerRelatedPin::~CBaseMuxerRelatedPin() +{ +} + +// IBaseMuxerRelatedPin + +STDMETHODIMP CBaseMuxerRelatedPin::SetRelatedPin(CBasePin* pPin) +{ + m_pRelatedPin = pPin; + return S_OK; +} + +STDMETHODIMP_(CBasePin*) CBaseMuxerRelatedPin::GetRelatedPin() +{ + return m_pRelatedPin; +} diff --git a/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.h b/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.h index c886917484c..4a2b8d0f1dd 100644 --- a/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.h +++ b/src/filters/muxer/BaseMuxer/BaseMuxerRelatedPin.h @@ -1,44 +1,44 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("EE6F2741-7DB4-4AAD-A3CB-545208EE4C0A")) - IBaseMuxerRelatedPin : - public IUnknown -{ - STDMETHOD(SetRelatedPin)(CBasePin* pPin) PURE; - STDMETHOD_(CBasePin*, GetRelatedPin)() PURE; -}; - -class CBaseMuxerRelatedPin : public IBaseMuxerRelatedPin -{ - CBasePin* m_pRelatedPin; // should not hold a reference because it would be circular - -public: - CBaseMuxerRelatedPin(); - virtual ~CBaseMuxerRelatedPin(); - - // IBaseMuxerRelatedPin - - STDMETHODIMP SetRelatedPin(CBasePin* pPin); - STDMETHODIMP_(CBasePin*) GetRelatedPin(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("EE6F2741-7DB4-4AAD-A3CB-545208EE4C0A")) + IBaseMuxerRelatedPin : + public IUnknown +{ + STDMETHOD(SetRelatedPin)(CBasePin* pPin) PURE; + STDMETHOD_(CBasePin*, GetRelatedPin)() PURE; +}; + +class CBaseMuxerRelatedPin : public IBaseMuxerRelatedPin +{ + CBasePin* m_pRelatedPin; // should not hold a reference because it would be circular + +public: + CBaseMuxerRelatedPin(); + virtual ~CBaseMuxerRelatedPin(); + + // IBaseMuxerRelatedPin + + STDMETHODIMP SetRelatedPin(CBasePin* pPin); + STDMETHODIMP_(CBasePin*) GetRelatedPin(); +}; diff --git a/src/filters/muxer/BaseMuxer/BitStream.cpp b/src/filters/muxer/BaseMuxer/BitStream.cpp index 3327092a133..c58c45d881f 100644 --- a/src/filters/muxer/BaseMuxer/BitStream.cpp +++ b/src/filters/muxer/BaseMuxer/BitStream.cpp @@ -1,162 +1,162 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "BitStream.h" - -// -// CBitStream -// - -CBitStream::CBitStream(IStream* pStream, bool fThrowError) - : CUnknown(_T("CBitStream"), nullptr) - , m_pStream(pStream) - , m_fThrowError(fThrowError) - , m_bitbuff(0) - , m_bitlen(0) -{ - ASSERT(m_pStream); - - LARGE_INTEGER li = {0}; - m_pStream->Seek(li, STREAM_SEEK_SET, nullptr); - - ULARGE_INTEGER uli = {0}; - m_pStream->SetSize(uli); // not that it worked... - - m_pStream->Commit(S_OK); // also seems to have no effect, but maybe in the future... -} - -CBitStream::~CBitStream() -{ - BitFlush(); -} - -STDMETHODIMP CBitStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - return - QI(IBitStream) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IBitStream - -STDMETHODIMP_(UINT64) CBitStream::GetPos() -{ - ULARGE_INTEGER pos = {0, 0}; - m_pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos); - return pos.QuadPart; -} - -STDMETHODIMP_(UINT64) CBitStream::Seek(UINT64 pos) -{ - BitFlush(); - - LARGE_INTEGER li; - li.QuadPart = pos; - ULARGE_INTEGER linew; - linew.QuadPart = (ULONGLONG) - 1; - m_pStream->Seek(li, STREAM_SEEK_SET, &linew); - ASSERT(li.QuadPart == (LONGLONG)linew.QuadPart); - return linew.QuadPart; -} - -STDMETHODIMP CBitStream::ByteWrite(const void* pData, int len) -{ - HRESULT hr = S_OK; - - BitFlush(); - - if (len > 0) { - ULONG cbWritten = 0; - hr = m_pStream->Write(pData, len, &cbWritten); - - ASSERT(SUCCEEDED(hr)); - if (m_fThrowError && FAILED(hr)) { - throw hr; - } - } - - return hr; -} - -STDMETHODIMP CBitStream::BitWrite(UINT64 data, int len) -{ - HRESULT hr = S_OK; - - ASSERT(len >= 0 && len <= 64); - - if (len > 56) { - BitWrite(data >> 56, len - 56); - len = 56; - } - - m_bitbuff <<= len; - m_bitbuff |= data & ((1ui64 << len) - 1); - m_bitlen += len; - - while (m_bitlen >= 8) { - BYTE b = (BYTE)(m_bitbuff >> (m_bitlen - 8)); - hr = m_pStream->Write(&b, 1, nullptr); - m_bitlen -= 8; - - ASSERT(SUCCEEDED(hr)); - if (m_fThrowError && FAILED(hr)) { - throw E_FAIL; - } - } - - return hr; -} - -STDMETHODIMP CBitStream::BitFlush() -{ - HRESULT hr = S_OK; - - if (m_bitlen > 0) { - ASSERT(m_bitlen < 8); - BYTE b = (BYTE)(m_bitbuff << (8 - m_bitlen)); - hr = m_pStream->Write(&b, 1, nullptr); - m_bitlen = 0; - - ASSERT(SUCCEEDED(hr)); - if (m_fThrowError && FAILED(hr)) { - throw E_FAIL; - } - } - - return hr; -} - -STDMETHODIMP CBitStream::StrWrite(LPCSTR pData, BOOL bFixNewLine) -{ - CStringA str = pData; - - if (bFixNewLine) { - str.Replace("\r", ""); - str.Replace("\n", "\r\n"); - } - - return ByteWrite((LPCSTR)str, str.GetLength()); -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "BitStream.h" + +// +// CBitStream +// + +CBitStream::CBitStream(IStream* pStream, bool fThrowError) + : CUnknown(_T("CBitStream"), nullptr) + , m_pStream(pStream) + , m_fThrowError(fThrowError) + , m_bitbuff(0) + , m_bitlen(0) +{ + ASSERT(m_pStream); + + LARGE_INTEGER li = {0}; + m_pStream->Seek(li, STREAM_SEEK_SET, nullptr); + + ULARGE_INTEGER uli = {0}; + m_pStream->SetSize(uli); // not that it worked... + + m_pStream->Commit(S_OK); // also seems to have no effect, but maybe in the future... +} + +CBitStream::~CBitStream() +{ + BitFlush(); +} + +STDMETHODIMP CBitStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + return + QI(IBitStream) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IBitStream + +STDMETHODIMP_(UINT64) CBitStream::GetPos() +{ + ULARGE_INTEGER pos = {0, 0}; + m_pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos); + return pos.QuadPart; +} + +STDMETHODIMP_(UINT64) CBitStream::Seek(UINT64 pos) +{ + BitFlush(); + + LARGE_INTEGER li; + li.QuadPart = pos; + ULARGE_INTEGER linew; + linew.QuadPart = (ULONGLONG) - 1; + m_pStream->Seek(li, STREAM_SEEK_SET, &linew); + ASSERT(li.QuadPart == (LONGLONG)linew.QuadPart); + return linew.QuadPart; +} + +STDMETHODIMP CBitStream::ByteWrite(const void* pData, int len) +{ + HRESULT hr = S_OK; + + BitFlush(); + + if (len > 0) { + ULONG cbWritten = 0; + hr = m_pStream->Write(pData, len, &cbWritten); + + ASSERT(SUCCEEDED(hr)); + if (m_fThrowError && FAILED(hr)) { + throw hr; + } + } + + return hr; +} + +STDMETHODIMP CBitStream::BitWrite(UINT64 data, int len) +{ + HRESULT hr = S_OK; + + ASSERT(len >= 0 && len <= 64); + + if (len > 56) { + BitWrite(data >> 56, len - 56); + len = 56; + } + + m_bitbuff <<= len; + m_bitbuff |= data & ((1ui64 << len) - 1); + m_bitlen += len; + + while (m_bitlen >= 8) { + BYTE b = (BYTE)(m_bitbuff >> (m_bitlen - 8)); + hr = m_pStream->Write(&b, 1, nullptr); + m_bitlen -= 8; + + ASSERT(SUCCEEDED(hr)); + if (m_fThrowError && FAILED(hr)) { + throw E_FAIL; + } + } + + return hr; +} + +STDMETHODIMP CBitStream::BitFlush() +{ + HRESULT hr = S_OK; + + if (m_bitlen > 0) { + ASSERT(m_bitlen < 8); + BYTE b = (BYTE)(m_bitbuff << (8 - m_bitlen)); + hr = m_pStream->Write(&b, 1, nullptr); + m_bitlen = 0; + + ASSERT(SUCCEEDED(hr)); + if (m_fThrowError && FAILED(hr)) { + throw E_FAIL; + } + } + + return hr; +} + +STDMETHODIMP CBitStream::StrWrite(LPCSTR pData, BOOL bFixNewLine) +{ + CStringA str = pData; + + if (bFixNewLine) { + str.Replace("\r", ""); + str.Replace("\n", "\r\n"); + } + + return ByteWrite((LPCSTR)str, str.GetLength()); +} diff --git a/src/filters/muxer/BaseMuxer/BitStream.h b/src/filters/muxer/BaseMuxer/BitStream.h index 64791d95d60..a5b6d0340cc 100644 --- a/src/filters/muxer/BaseMuxer/BitStream.h +++ b/src/filters/muxer/BaseMuxer/BitStream.h @@ -1,58 +1,58 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -interface __declspec(uuid("30AB78C7-5259-4594-AEFE-9C0FC2F08A5E")) - IBitStream : - public IUnknown -{ - STDMETHOD_(UINT64, GetPos)() PURE; - STDMETHOD_(UINT64, Seek)(UINT64 pos) PURE; // it's a _stream_, please don't seek if you don't have to - STDMETHOD(ByteWrite)(const void* pData, int len) PURE; - STDMETHOD(BitWrite)(UINT64 data, int len) PURE; - STDMETHOD(BitFlush)() PURE; - STDMETHOD(StrWrite)(LPCSTR pData, BOOL bFixNewLine) PURE; -}; - -class CBitStream : public CUnknown, public IBitStream -{ - CComPtr m_pStream; - bool m_fThrowError; - UINT64 m_bitbuff; - int m_bitlen; - -public: - CBitStream(IStream* pStream, bool m_fThrowError = false); - virtual ~CBitStream(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IBitStream - - STDMETHODIMP_(UINT64) GetPos(); - STDMETHODIMP_(UINT64) Seek(UINT64 pos); - STDMETHODIMP ByteWrite(const void* pData, int len); - STDMETHODIMP BitWrite(UINT64 data, int len); - STDMETHODIMP BitFlush(); - STDMETHODIMP StrWrite(LPCSTR pData, BOOL bFixNewLine); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +interface __declspec(uuid("30AB78C7-5259-4594-AEFE-9C0FC2F08A5E")) + IBitStream : + public IUnknown +{ + STDMETHOD_(UINT64, GetPos)() PURE; + STDMETHOD_(UINT64, Seek)(UINT64 pos) PURE; // it's a _stream_, please don't seek if you don't have to + STDMETHOD(ByteWrite)(const void* pData, int len) PURE; + STDMETHOD(BitWrite)(UINT64 data, int len) PURE; + STDMETHOD(BitFlush)() PURE; + STDMETHOD(StrWrite)(LPCSTR pData, BOOL bFixNewLine) PURE; +}; + +class CBitStream : public CUnknown, public IBitStream +{ + CComPtr m_pStream; + bool m_fThrowError; + UINT64 m_bitbuff; + int m_bitlen; + +public: + CBitStream(IStream* pStream, bool m_fThrowError = false); + virtual ~CBitStream(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IBitStream + + STDMETHODIMP_(UINT64) GetPos(); + STDMETHODIMP_(UINT64) Seek(UINT64 pos); + STDMETHODIMP ByteWrite(const void* pData, int len); + STDMETHODIMP BitWrite(UINT64 data, int len); + STDMETHODIMP BitFlush(); + STDMETHODIMP StrWrite(LPCSTR pData, BOOL bFixNewLine); +}; diff --git a/src/filters/muxer/BaseMuxer/stdafx.cpp b/src/filters/muxer/BaseMuxer/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/muxer/BaseMuxer/stdafx.cpp +++ b/src/filters/muxer/BaseMuxer/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/muxer/BaseMuxer/stdafx.h b/src/filters/muxer/BaseMuxer/stdafx.h index 75ebfbc6a9d..0ebf71a1710 100644 --- a/src/filters/muxer/BaseMuxer/stdafx.h +++ b/src/filters/muxer/BaseMuxer/stdafx.h @@ -1,37 +1,37 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include - -#include "BaseClasses/streams.h" -#include "../../../DSUtil/DSUtil.h" +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include + +#include "BaseClasses/streams.h" +#include "../../../DSUtil/DSUtil.h" diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.cpp b/src/filters/muxer/DSMMuxer/DSMMuxer.cpp index 951322fc3ea..93ab3852272 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.cpp +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.cpp @@ -1,450 +1,450 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "DSMMuxer.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include -#include "moreuuids.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia} -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, nullptr, 0, nullptr}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CDSMMuxerFilter), DSMMuxerName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -template static T myabs(T n) -{ - return n >= 0 ? n : -n; -} - -static int GetByteLength(UINT64 data, int min = 0) -{ - int i = 7; - while (i >= min && ((BYTE*)&data)[i] == 0) { - i--; - } - return ++i; -} - -// -// CDSMMuxerFilter -// - -CDSMMuxerFilter::CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap, bool fAutoRes) - : CBaseMuxerFilter(pUnk, phr, __uuidof(this)) - , m_fAutoChap(fAutoChap) - , m_fAutoRes(fAutoRes) - , m_rtPrevSyncPoint(_I64_MIN) -{ - if (phr) { - *phr = S_OK; - } -} - -CDSMMuxerFilter::~CDSMMuxerFilter() -{ -} - -STDMETHODIMP CDSMMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CDSMMuxerFilter::MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len) -{ - ASSERT(type < 32); - - int i = GetByteLength(len, 1); - - pBS->BitWrite(DSMSW, DSMSW_SIZE << 3); - pBS->BitWrite(type, 5); - pBS->BitWrite(i - 1, 3); - pBS->BitWrite(len, i << 3); -} - -void CDSMMuxerFilter::MuxFileInfo(IBitStream* pBS) -{ - int len = 1; - CSimpleMap si; - - for (int i = 0; i < GetSize(); i++) { - CStringA key = CStringA(CString(GetKeyAt(i))), value = UTF16To8(GetValueAt(i)); - if (key.GetLength() != 4) { - continue; - } - si.Add(key, value); - len += 4 + value.GetLength() + 1; - } - - MuxPacketHeader(pBS, DSMP_FILEINFO, len); - pBS->BitWrite(DSMF_VERSION, 8); - for (int i = 0; i < si.GetSize(); i++) { - CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i); - pBS->ByteWrite((LPCSTR)key, 4); - pBS->ByteWrite((LPCSTR)value, value.GetLength() + 1); - } - -} - -void CDSMMuxerFilter::MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin) -{ - int len = 1; - CSimpleMap si; - - for (int i = 0; i < pPin->GetSize(); i++) { - CStringA key = CStringA(CString(pPin->GetKeyAt(i))), value = UTF16To8(pPin->GetValueAt(i)); - if (key.GetLength() != 4) { - continue; - } - si.Add(key, value); - len += 4 + value.GetLength() + 1; - } - - if (len > 1) { - MuxPacketHeader(pBS, DSMP_STREAMINFO, len); - pBS->BitWrite(pPin->GetID(), 8); - for (int i = 0; i < si.GetSize(); i++) { - CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i); - pBS->ByteWrite((LPCSTR)key, 4); - pBS->ByteWrite((LPCSTR)value, value.GetLength() + 1); - } - } -} - -void CDSMMuxerFilter::MuxInit() -{ - m_sps.RemoveAll(); - m_isps.RemoveAll(); - m_rtPrevSyncPoint = _I64_MIN; -} - -void CDSMMuxerFilter::MuxHeader(IBitStream* pBS) -{ - CString muxer; - muxer.Format(_T("DSM Muxer (%S)"), __TIMESTAMP__); - - SetProperty(L"MUXR", CStringW(muxer)); - SetProperty(L"DATE", CStringW(CTime::GetCurrentTime().FormatGmt(_T("%Y-%m-%d %H:%M:%S")))); - - MuxFileInfo(pBS); - - POSITION pos = m_pPins.GetHeadPosition(); - while (pos) { - CBaseMuxerInputPin* pPin = m_pPins.GetNext(pos); - const CMediaType& mt = pPin->CurrentMediaType(); - - ASSERT((mt.lSampleSize >> 30) == 0); // you don't need >1GB samples, do you? - - MuxPacketHeader(pBS, DSMP_MEDIATYPE, 5 + sizeof(GUID) * 3 + mt.FormatLength()); - pBS->BitWrite(pPin->GetID(), 8); - pBS->ByteWrite(&mt.majortype, sizeof(mt.majortype)); - pBS->ByteWrite(&mt.subtype, sizeof(mt.subtype)); - pBS->BitWrite(mt.bFixedSizeSamples, 1); - pBS->BitWrite(mt.bTemporalCompression, 1); - pBS->BitWrite(mt.lSampleSize, 30); - pBS->ByteWrite(&mt.formattype, sizeof(mt.formattype)); - pBS->ByteWrite(mt.Format(), mt.FormatLength()); - - MuxStreamInfo(pBS, pPin); - } - - // resources & chapters - - CInterfaceList pRBs; - pRBs.AddTail(this); - - CComQIPtr pCB = (IUnknown*)(INonDelegatingUnknown*)this; - - pos = m_pPins.GetHeadPosition(); - while (pos) { - for (CComPtr pPin = m_pPins.GetNext(pos)->GetConnected(); pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { - if (m_fAutoRes) { - CComQIPtr pPB = GetFilterFromPin(pPin); - if (pPB && !pRBs.Find(pPB)) { - pRBs.AddTail(pPB); - } - } - - if (m_fAutoChap) { - if (!pCB || pCB->ChapGetCount() == 0) { - pCB = GetFilterFromPin(pPin); - } - } - } - } - - // resources - - pos = pRBs.GetHeadPosition(); - while (pos) { - IDSMResourceBag* pRB = pRBs.GetNext(pos); - - for (DWORD i = 0, j = pRB->ResGetCount(); i < j; i++) { - CComBSTR name, desc, mime; - BYTE* pData = nullptr; - DWORD len = 0; - if (SUCCEEDED(pRB->ResGet(i, &name, &desc, &mime, &pData, &len, nullptr))) { - CStringA utf8_name = UTF16To8(name); - CStringA utf8_desc = UTF16To8(desc); - CStringA utf8_mime = UTF16To8(mime); - - MuxPacketHeader(pBS, DSMP_RESOURCE, - 1 + - utf8_name.GetLength() + 1 + - utf8_desc.GetLength() + 1 + - utf8_mime.GetLength() + 1 + - len); - - pBS->BitWrite(0, 2); - pBS->BitWrite(0, 6); // reserved - pBS->ByteWrite(utf8_name, utf8_name.GetLength() + 1); - pBS->ByteWrite(utf8_desc, utf8_desc.GetLength() + 1); - pBS->ByteWrite(utf8_mime, utf8_mime.GetLength() + 1); - pBS->ByteWrite(pData, len); - - CoTaskMemFree(pData); - } - } - } - - // chapters - - if (pCB) { - CAtlList chapters; - REFERENCE_TIME rtPrev = 0; - int len = 0; - - pCB->ChapSort(); - - for (DWORD i = 0; i < pCB->ChapGetCount(); i++) { - CDSMChapter c; - CComBSTR name; - if (SUCCEEDED(pCB->ChapGet(i, &c.rt, &name))) { - REFERENCE_TIME rtDiff = c.rt - rtPrev; - rtPrev = c.rt; - c.rt = rtDiff; - c.name = name; - len += 1 + GetByteLength(myabs(c.rt)) + UTF16To8(c.name).GetLength() + 1; - chapters.AddTail(c); - } - } - - if (chapters.GetCount()) { - MuxPacketHeader(pBS, DSMP_CHAPTERS, len); - - pos = chapters.GetHeadPosition(); - while (pos) { - CDSMChapter& c = chapters.GetNext(pos); - CStringA name = UTF16To8(c.name); - int irt = GetByteLength(myabs(c.rt)); - pBS->BitWrite(c.rt < 0, 1); - pBS->BitWrite(irt, 3); - pBS->BitWrite(0, 4); - pBS->BitWrite(myabs(c.rt), irt << 3); - pBS->ByteWrite((LPCSTR)name, name.GetLength() + 1); - } - } - } -} - -void CDSMMuxerFilter::MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket) -{ - if (pPacket->IsEOS()) { - return; - } - - if (pPacket->pPin->CurrentMediaType().majortype == MEDIATYPE_Text) { - CStringA str((char*)pPacket->pData.GetData(), (int)pPacket->pData.GetCount()); - str.Replace("\xff", " "); - str.Replace(" ", " "); - str.Replace(" ", " "); - str.Trim(); - if (str.IsEmpty()) { - return; - } - } - - ASSERT(!pPacket->IsSyncPoint() || pPacket->IsTimeValid()); - - REFERENCE_TIME rtTimeStamp = _I64_MIN, rtDuration = 0; - int iTimeStamp = 0, iDuration = 0; - - if (pPacket->IsTimeValid()) { - rtTimeStamp = pPacket->rtStart; - rtDuration = std::max(pPacket->rtStop - pPacket->rtStart, 0ll); - - iTimeStamp = GetByteLength(myabs(rtTimeStamp)); - ASSERT(iTimeStamp <= 7); - - iDuration = GetByteLength(rtDuration); - ASSERT(iDuration <= 7); - - IndexSyncPoint(pPacket, pBS->GetPos()); - } - - UINT64 len = 2 + iTimeStamp + iDuration + pPacket->pData.GetCount(); // id + flags + data - - MuxPacketHeader(pBS, DSMP_SAMPLE, len); - pBS->BitWrite(pPacket->pPin->GetID(), 8); - pBS->BitWrite(pPacket->IsSyncPoint(), 1); - pBS->BitWrite(rtTimeStamp < 0, 1); - pBS->BitWrite(iTimeStamp, 3); - pBS->BitWrite(iDuration, 3); - pBS->BitWrite(myabs(rtTimeStamp), iTimeStamp << 3); - pBS->BitWrite(rtDuration, iDuration << 3); - pBS->ByteWrite(pPacket->pData.GetData(), (int)pPacket->pData.GetCount()); -} - -void CDSMMuxerFilter::MuxFooter(IBitStream* pBS) -{ - // syncpoints - - int len = 0; - CAtlList isps; - REFERENCE_TIME rtPrev = 0, rt; - UINT64 fpPrev = 0, fp; - - POSITION pos = m_isps.GetHeadPosition(); - while (pos) { - IndexedSyncPoint& isp = m_isps.GetNext(pos); - TRACE(_T("sp[%d]: %I64d %I64x\n"), isp.id, isp.rt, isp.fp); - - rt = isp.rt - rtPrev; - rtPrev = isp.rt; - fp = isp.fp - fpPrev; - fpPrev = isp.fp; - - IndexedSyncPoint isp2; - isp2.fp = fp; - isp2.rt = rt; - isps.AddTail(isp2); - - len += 1 + GetByteLength(myabs(rt)) + GetByteLength(fp); // flags + rt + fp - } - - MuxPacketHeader(pBS, DSMP_SYNCPOINTS, len); - - pos = isps.GetHeadPosition(); - while (pos) { - IndexedSyncPoint& isp = isps.GetNext(pos); - - int irt = GetByteLength(myabs(isp.rt)); - int ifp = GetByteLength(isp.fp); - - pBS->BitWrite(isp.rt < 0, 1); - pBS->BitWrite(irt, 3); - pBS->BitWrite(ifp, 3); - pBS->BitWrite(0, 1); // reserved - pBS->BitWrite(myabs(isp.rt), irt << 3); - pBS->BitWrite(isp.fp, ifp << 3); - } -} - -void CDSMMuxerFilter::IndexSyncPoint(const MuxerPacket* p, __int64 fp) -{ - // Yes, this is as complicated as it looks. - // Rule #1: don't write this packet if you can't do it reliably. - // (think about overlapped subtitles, line1: 0->10, line2: 1->9) - - // FIXME: the very last syncpoints won't get moved to m_isps because there are no more syncpoints to trigger it! - - if (fp < 0 || !p || !p->IsTimeValid() || !p->IsSyncPoint()) { - return; - } - - ASSERT(p->rtStart >= m_rtPrevSyncPoint); - m_rtPrevSyncPoint = p->rtStart; - - SyncPoint sp; - sp.id = (BYTE)p->pPin->GetID(); - sp.rtStart = p->rtStart; - sp.rtStop = p->pPin->IsSubtitleStream() ? p->rtStop : _I64_MAX; - sp.fp = fp; - - { - SyncPoint& head = !m_sps.IsEmpty() ? m_sps.GetHead() : sp; - SyncPoint& tail = !m_sps.IsEmpty() ? m_sps.GetTail() : sp; - REFERENCE_TIME rtfp = !m_isps.IsEmpty() ? m_isps.GetTail().rtfp : _I64_MIN; - - if (head.rtStart > rtfp + 1000000) { // 100ms limit, just in case every stream had only keyframes, then sycnpoints would be too frequent - IndexedSyncPoint isp; - isp.id = head.id; - isp.rt = tail.rtStart; - isp.rtfp = head.rtStart; - isp.fp = head.fp; - m_isps.AddTail(isp); - } - } - - POSITION pos = m_sps.GetHeadPosition(); - while (pos) { - POSITION cur = pos; - SyncPoint& sp2 = m_sps.GetNext(pos); - if (sp2.id == sp.id && sp2.rtStop <= sp.rtStop || sp2.rtStop <= sp.rtStart) { - m_sps.RemoveAt(cur); - } - } - - m_sps.AddTail(sp); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "DSMMuxer.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include +#include "moreuuids.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia} +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, nullptr, 0, nullptr}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CDSMMuxerFilter), DSMMuxerName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +template static T myabs(T n) +{ + return n >= 0 ? n : -n; +} + +static int GetByteLength(UINT64 data, int min = 0) +{ + int i = 7; + while (i >= min && ((BYTE*)&data)[i] == 0) { + i--; + } + return ++i; +} + +// +// CDSMMuxerFilter +// + +CDSMMuxerFilter::CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap, bool fAutoRes) + : CBaseMuxerFilter(pUnk, phr, __uuidof(this)) + , m_fAutoChap(fAutoChap) + , m_fAutoRes(fAutoRes) + , m_rtPrevSyncPoint(_I64_MIN) +{ + if (phr) { + *phr = S_OK; + } +} + +CDSMMuxerFilter::~CDSMMuxerFilter() +{ +} + +STDMETHODIMP CDSMMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CDSMMuxerFilter::MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len) +{ + ASSERT(type < 32); + + int i = GetByteLength(len, 1); + + pBS->BitWrite(DSMSW, DSMSW_SIZE << 3); + pBS->BitWrite(type, 5); + pBS->BitWrite(i - 1, 3); + pBS->BitWrite(len, i << 3); +} + +void CDSMMuxerFilter::MuxFileInfo(IBitStream* pBS) +{ + int len = 1; + CSimpleMap si; + + for (int i = 0; i < GetSize(); i++) { + CStringA key = CStringA(CString(GetKeyAt(i))), value = UTF16To8(GetValueAt(i)); + if (key.GetLength() != 4) { + continue; + } + si.Add(key, value); + len += 4 + value.GetLength() + 1; + } + + MuxPacketHeader(pBS, DSMP_FILEINFO, len); + pBS->BitWrite(DSMF_VERSION, 8); + for (int i = 0; i < si.GetSize(); i++) { + CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i); + pBS->ByteWrite((LPCSTR)key, 4); + pBS->ByteWrite((LPCSTR)value, value.GetLength() + 1); + } + +} + +void CDSMMuxerFilter::MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin) +{ + int len = 1; + CSimpleMap si; + + for (int i = 0; i < pPin->GetSize(); i++) { + CStringA key = CStringA(CString(pPin->GetKeyAt(i))), value = UTF16To8(pPin->GetValueAt(i)); + if (key.GetLength() != 4) { + continue; + } + si.Add(key, value); + len += 4 + value.GetLength() + 1; + } + + if (len > 1) { + MuxPacketHeader(pBS, DSMP_STREAMINFO, len); + pBS->BitWrite(pPin->GetID(), 8); + for (int i = 0; i < si.GetSize(); i++) { + CStringA key = si.GetKeyAt(i), value = si.GetValueAt(i); + pBS->ByteWrite((LPCSTR)key, 4); + pBS->ByteWrite((LPCSTR)value, value.GetLength() + 1); + } + } +} + +void CDSMMuxerFilter::MuxInit() +{ + m_sps.RemoveAll(); + m_isps.RemoveAll(); + m_rtPrevSyncPoint = _I64_MIN; +} + +void CDSMMuxerFilter::MuxHeader(IBitStream* pBS) +{ + CString muxer; + muxer.Format(_T("DSM Muxer (%S)"), __TIMESTAMP__); + + SetProperty(L"MUXR", CStringW(muxer)); + SetProperty(L"DATE", CStringW(CTime::GetCurrentTime().FormatGmt(_T("%Y-%m-%d %H:%M:%S")))); + + MuxFileInfo(pBS); + + POSITION pos = m_pPins.GetHeadPosition(); + while (pos) { + CBaseMuxerInputPin* pPin = m_pPins.GetNext(pos); + const CMediaType& mt = pPin->CurrentMediaType(); + + ASSERT((mt.lSampleSize >> 30) == 0); // you don't need >1GB samples, do you? + + MuxPacketHeader(pBS, DSMP_MEDIATYPE, 5 + sizeof(GUID) * 3 + mt.FormatLength()); + pBS->BitWrite(pPin->GetID(), 8); + pBS->ByteWrite(&mt.majortype, sizeof(mt.majortype)); + pBS->ByteWrite(&mt.subtype, sizeof(mt.subtype)); + pBS->BitWrite(mt.bFixedSizeSamples, 1); + pBS->BitWrite(mt.bTemporalCompression, 1); + pBS->BitWrite(mt.lSampleSize, 30); + pBS->ByteWrite(&mt.formattype, sizeof(mt.formattype)); + pBS->ByteWrite(mt.Format(), mt.FormatLength()); + + MuxStreamInfo(pBS, pPin); + } + + // resources & chapters + + CInterfaceList pRBs; + pRBs.AddTail(this); + + CComQIPtr pCB = (IUnknown*)(INonDelegatingUnknown*)this; + + pos = m_pPins.GetHeadPosition(); + while (pos) { + for (CComPtr pPin = m_pPins.GetNext(pos)->GetConnected(); pPin; pPin = GetUpStreamPin(GetFilterFromPin(pPin))) { + if (m_fAutoRes) { + CComQIPtr pPB = GetFilterFromPin(pPin); + if (pPB && !pRBs.Find(pPB)) { + pRBs.AddTail(pPB); + } + } + + if (m_fAutoChap) { + if (!pCB || pCB->ChapGetCount() == 0) { + pCB = GetFilterFromPin(pPin); + } + } + } + } + + // resources + + pos = pRBs.GetHeadPosition(); + while (pos) { + IDSMResourceBag* pRB = pRBs.GetNext(pos); + + for (DWORD i = 0, j = pRB->ResGetCount(); i < j; i++) { + CComBSTR name, desc, mime; + BYTE* pData = nullptr; + DWORD len = 0; + if (SUCCEEDED(pRB->ResGet(i, &name, &desc, &mime, &pData, &len, nullptr))) { + CStringA utf8_name = UTF16To8(name); + CStringA utf8_desc = UTF16To8(desc); + CStringA utf8_mime = UTF16To8(mime); + + MuxPacketHeader(pBS, DSMP_RESOURCE, + 1 + + utf8_name.GetLength() + 1 + + utf8_desc.GetLength() + 1 + + utf8_mime.GetLength() + 1 + + len); + + pBS->BitWrite(0, 2); + pBS->BitWrite(0, 6); // reserved + pBS->ByteWrite(utf8_name, utf8_name.GetLength() + 1); + pBS->ByteWrite(utf8_desc, utf8_desc.GetLength() + 1); + pBS->ByteWrite(utf8_mime, utf8_mime.GetLength() + 1); + pBS->ByteWrite(pData, len); + + CoTaskMemFree(pData); + } + } + } + + // chapters + + if (pCB) { + CAtlList chapters; + REFERENCE_TIME rtPrev = 0; + int len = 0; + + pCB->ChapSort(); + + for (DWORD i = 0; i < pCB->ChapGetCount(); i++) { + CDSMChapter c; + CComBSTR name; + if (SUCCEEDED(pCB->ChapGet(i, &c.rt, &name))) { + REFERENCE_TIME rtDiff = c.rt - rtPrev; + rtPrev = c.rt; + c.rt = rtDiff; + c.name = name; + len += 1 + GetByteLength(myabs(c.rt)) + UTF16To8(c.name).GetLength() + 1; + chapters.AddTail(c); + } + } + + if (chapters.GetCount()) { + MuxPacketHeader(pBS, DSMP_CHAPTERS, len); + + pos = chapters.GetHeadPosition(); + while (pos) { + CDSMChapter& c = chapters.GetNext(pos); + CStringA name = UTF16To8(c.name); + int irt = GetByteLength(myabs(c.rt)); + pBS->BitWrite(c.rt < 0, 1); + pBS->BitWrite(irt, 3); + pBS->BitWrite(0, 4); + pBS->BitWrite(myabs(c.rt), irt << 3); + pBS->ByteWrite((LPCSTR)name, name.GetLength() + 1); + } + } + } +} + +void CDSMMuxerFilter::MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket) +{ + if (pPacket->IsEOS()) { + return; + } + + if (pPacket->pPin->CurrentMediaType().majortype == MEDIATYPE_Text) { + CStringA str((char*)pPacket->pData.GetData(), (int)pPacket->pData.GetCount()); + str.Replace("\xff", " "); + str.Replace(" ", " "); + str.Replace(" ", " "); + str.Trim(); + if (str.IsEmpty()) { + return; + } + } + + ASSERT(!pPacket->IsSyncPoint() || pPacket->IsTimeValid()); + + REFERENCE_TIME rtTimeStamp = _I64_MIN, rtDuration = 0; + int iTimeStamp = 0, iDuration = 0; + + if (pPacket->IsTimeValid()) { + rtTimeStamp = pPacket->rtStart; + rtDuration = std::max(pPacket->rtStop - pPacket->rtStart, 0ll); + + iTimeStamp = GetByteLength(myabs(rtTimeStamp)); + ASSERT(iTimeStamp <= 7); + + iDuration = GetByteLength(rtDuration); + ASSERT(iDuration <= 7); + + IndexSyncPoint(pPacket, pBS->GetPos()); + } + + UINT64 len = 2 + iTimeStamp + iDuration + pPacket->pData.GetCount(); // id + flags + data + + MuxPacketHeader(pBS, DSMP_SAMPLE, len); + pBS->BitWrite(pPacket->pPin->GetID(), 8); + pBS->BitWrite(pPacket->IsSyncPoint(), 1); + pBS->BitWrite(rtTimeStamp < 0, 1); + pBS->BitWrite(iTimeStamp, 3); + pBS->BitWrite(iDuration, 3); + pBS->BitWrite(myabs(rtTimeStamp), iTimeStamp << 3); + pBS->BitWrite(rtDuration, iDuration << 3); + pBS->ByteWrite(pPacket->pData.GetData(), (int)pPacket->pData.GetCount()); +} + +void CDSMMuxerFilter::MuxFooter(IBitStream* pBS) +{ + // syncpoints + + int len = 0; + CAtlList isps; + REFERENCE_TIME rtPrev = 0, rt; + UINT64 fpPrev = 0, fp; + + POSITION pos = m_isps.GetHeadPosition(); + while (pos) { + IndexedSyncPoint& isp = m_isps.GetNext(pos); + TRACE(_T("sp[%d]: %I64d %I64x\n"), isp.id, isp.rt, isp.fp); + + rt = isp.rt - rtPrev; + rtPrev = isp.rt; + fp = isp.fp - fpPrev; + fpPrev = isp.fp; + + IndexedSyncPoint isp2; + isp2.fp = fp; + isp2.rt = rt; + isps.AddTail(isp2); + + len += 1 + GetByteLength(myabs(rt)) + GetByteLength(fp); // flags + rt + fp + } + + MuxPacketHeader(pBS, DSMP_SYNCPOINTS, len); + + pos = isps.GetHeadPosition(); + while (pos) { + IndexedSyncPoint& isp = isps.GetNext(pos); + + int irt = GetByteLength(myabs(isp.rt)); + int ifp = GetByteLength(isp.fp); + + pBS->BitWrite(isp.rt < 0, 1); + pBS->BitWrite(irt, 3); + pBS->BitWrite(ifp, 3); + pBS->BitWrite(0, 1); // reserved + pBS->BitWrite(myabs(isp.rt), irt << 3); + pBS->BitWrite(isp.fp, ifp << 3); + } +} + +void CDSMMuxerFilter::IndexSyncPoint(const MuxerPacket* p, __int64 fp) +{ + // Yes, this is as complicated as it looks. + // Rule #1: don't write this packet if you can't do it reliably. + // (think about overlapped subtitles, line1: 0->10, line2: 1->9) + + // FIXME: the very last syncpoints won't get moved to m_isps because there are no more syncpoints to trigger it! + + if (fp < 0 || !p || !p->IsTimeValid() || !p->IsSyncPoint()) { + return; + } + + ASSERT(p->rtStart >= m_rtPrevSyncPoint); + m_rtPrevSyncPoint = p->rtStart; + + SyncPoint sp; + sp.id = (BYTE)p->pPin->GetID(); + sp.rtStart = p->rtStart; + sp.rtStop = p->pPin->IsSubtitleStream() ? p->rtStop : _I64_MAX; + sp.fp = fp; + + { + SyncPoint& head = !m_sps.IsEmpty() ? m_sps.GetHead() : sp; + SyncPoint& tail = !m_sps.IsEmpty() ? m_sps.GetTail() : sp; + REFERENCE_TIME rtfp = !m_isps.IsEmpty() ? m_isps.GetTail().rtfp : _I64_MIN; + + if (head.rtStart > rtfp + 1000000) { // 100ms limit, just in case every stream had only keyframes, then sycnpoints would be too frequent + IndexedSyncPoint isp; + isp.id = head.id; + isp.rt = tail.rtStart; + isp.rtfp = head.rtStart; + isp.fp = head.fp; + m_isps.AddTail(isp); + } + } + + POSITION pos = m_sps.GetHeadPosition(); + while (pos) { + POSITION cur = pos; + SyncPoint& sp2 = m_sps.GetNext(pos); + if (sp2.id == sp.id && sp2.rtStop <= sp.rtStop || sp2.rtStop <= sp.rtStart) { + m_sps.RemoveAt(cur); + } + } + + m_sps.AddTail(sp); +} diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.def b/src/filters/muxer/DSMMuxer/DSMMuxer.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.def +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.h b/src/filters/muxer/DSMMuxer/DSMMuxer.h index c955e1897b0..893267dcc9c 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.h +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.h @@ -1,66 +1,66 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../BaseMuxer/BaseMuxer.h" -#include "dsm/dsm.h" - -#define DSMMuxerName L"MPC DSM Muxer" - -class __declspec(uuid("C6590B76-587E-4082-9125-680D0693A97B")) - CDSMMuxerFilter : public CBaseMuxerFilter -{ - bool m_fAutoChap, m_fAutoRes; - - struct SyncPoint { - BYTE id; - REFERENCE_TIME rtStart, rtStop; - __int64 fp; - }; - struct IndexedSyncPoint { - BYTE id; - REFERENCE_TIME rt, rtfp; - __int64 fp; - }; - CAtlList m_sps; - CAtlList m_isps; - REFERENCE_TIME m_rtPrevSyncPoint; - void IndexSyncPoint(const MuxerPacket* p, __int64 fp); - - void MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len); - void MuxFileInfo(IBitStream* pBS); - void MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin); - -protected: - void MuxInit(); - - void MuxHeader(IBitStream* pBS); - void MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket); - void MuxFooter(IBitStream* pBS); - -public: - CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap = true, bool fAutoRes = true); - virtual ~CDSMMuxerFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "../BaseMuxer/BaseMuxer.h" +#include "dsm/dsm.h" + +#define DSMMuxerName L"MPC DSM Muxer" + +class __declspec(uuid("C6590B76-587E-4082-9125-680D0693A97B")) + CDSMMuxerFilter : public CBaseMuxerFilter +{ + bool m_fAutoChap, m_fAutoRes; + + struct SyncPoint { + BYTE id; + REFERENCE_TIME rtStart, rtStop; + __int64 fp; + }; + struct IndexedSyncPoint { + BYTE id; + REFERENCE_TIME rt, rtfp; + __int64 fp; + }; + CAtlList m_sps; + CAtlList m_isps; + REFERENCE_TIME m_rtPrevSyncPoint; + void IndexSyncPoint(const MuxerPacket* p, __int64 fp); + + void MuxPacketHeader(IBitStream* pBS, dsmp_t type, UINT64 len); + void MuxFileInfo(IBitStream* pBS); + void MuxStreamInfo(IBitStream* pBS, CBaseMuxerInputPin* pPin); + +protected: + void MuxInit(); + + void MuxHeader(IBitStream* pBS); + void MuxPacket(IBitStream* pBS, const MuxerPacket* pPacket); + void MuxFooter(IBitStream* pBS); + +public: + CDSMMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, bool fAutoChap = true, bool fAutoRes = true); + virtual ~CDSMMuxerFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); +}; diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.rc b/src/filters/muxer/DSMMuxer/DSMMuxer.rc index 02b928f6dde..9a5513dcfef 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.rc +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "DirectShow Media Muxer" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "DirectShow Media Muxer" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "DSMMuxer.ax" - VALUE "ProductName", "DirectShow Media Muxer" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "DirectShow Media Muxer" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "DirectShow Media Muxer" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "DSMMuxer.ax" + VALUE "ProductName", "DirectShow Media Muxer" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj b/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj index 5ab0c3293ab..3f17d32a7df 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj @@ -1,127 +1,127 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {65361C7C-83D6-42E4-870C-4DC85AE641FE} - DSMMuxer - Win32Proj - DSMMuxer - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - DSMMuxer.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {db5f93b2-54d0-4474-a588-d259be36c832} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {65361C7C-83D6-42E4-870C-4DC85AE641FE} + DSMMuxer + Win32Proj + DSMMuxer + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + DSMMuxer.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {db5f93b2-54d0-4474-a588-d259be36c832} + + + + + \ No newline at end of file diff --git a/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj.filters b/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj.filters index 3bddc44d39f..23b96ae456b 100644 --- a/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj.filters +++ b/src/filters/muxer/DSMMuxer/DSMMuxer.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {f2a0afa9-5123-40d6-9344-b1620d9ab714} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {181a9f13-cf46-4334-9042-2a7f21566a7f} - h;hpp;hxx;hm;inl;inc - - - {6e2d23f9-16bb-4682-ac30-1ab1b61e5774} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {f2a0afa9-5123-40d6-9344-b1620d9ab714} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {181a9f13-cf46-4334-9042-2a7f21566a7f} + h;hpp;hxx;hm;inl;inc + + + {6e2d23f9-16bb-4682-ac30-1ab1b61e5774} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/muxer/DSMMuxer/resource.h b/src/filters/muxer/DSMMuxer/resource.h index 1db5c7362b2..07b0c93390a 100644 --- a/src/filters/muxer/DSMMuxer/resource.h +++ b/src/filters/muxer/DSMMuxer/resource.h @@ -1,15 +1,15 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by DSMMuxer.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DSMMuxer.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/muxer/DSMMuxer/stdafx.cpp b/src/filters/muxer/DSMMuxer/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/muxer/DSMMuxer/stdafx.cpp +++ b/src/filters/muxer/DSMMuxer/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/muxer/DSMMuxer/stdafx.h b/src/filters/muxer/DSMMuxer/stdafx.h index 2cd026b0419..3d1feeda544 100644 --- a/src/filters/muxer/DSMMuxer/stdafx.h +++ b/src/filters/muxer/DSMMuxer/stdafx.h @@ -1,39 +1,39 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include -#include - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include +#include + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaFile.cpp b/src/filters/muxer/MatroskaMuxer/MatroskaFile.cpp index 32e3bdbdb70..f2c1e0d8278 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaFile.cpp +++ b/src/filters/muxer/MatroskaMuxer/MatroskaFile.cpp @@ -1,937 +1,937 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include -#include "MatroskaFile.h" -#include "../../../DSUtil/DSUtil.h" - -using namespace MatroskaWriter; - -static void bswap(BYTE* s, int len) -{ - for (BYTE* d = s + len - 1; s < d; s++, d--) { - *s ^= *d, *d ^= *s, *s ^= *d; - } -} - -// - -CID::CID(DWORD id) - : m_id(id) -{ -} - -QWORD CID::Size(bool fWithHeader) -{ - return CUInt(0, m_id).Size(false); -} - -HRESULT CID::Write(IStream* pStream) -{ - QWORD len = CID::Size(); - DWORD id = m_id; - bswap((BYTE*)&id, (int)len); - *(BYTE*)&id = ((*(BYTE*)&id) & (1 << (8 - len)) - 1) | (1 << (8 - len)); - return pStream->Write(&id, (ULONG)len, nullptr); -} - -QWORD CID::HeaderSize(QWORD len) -{ - return CID::Size() + CLength(len).Size(); -} - -HRESULT CID::HeaderWrite(IStream* pStream) -{ - CID::Write(pStream); - CLength(Size(false)).Write(pStream); - return S_OK; -} - -QWORD CBinary::Size(bool fWithHeader) -{ - if (IsEmpty()) { - return 0; - } - - QWORD len = 0; - len += GetCount(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CBinary::Write(IStream* pStream) -{ - if (IsEmpty()) { - return S_OK; - } - - HeaderWrite(pStream); - return pStream->Write(GetData(), (ULONG)GetCount(), nullptr); -} - -QWORD CANSI::Size(bool fWithHeader) -{ - if (IsEmpty()) { - return 0; - } - - QWORD len = 0; - len += GetLength(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CANSI::Write(IStream* pStream) -{ - if (IsEmpty()) { - return S_OK; - } - - HeaderWrite(pStream); - return pStream->Write((LPCSTR) * this, GetLength(), nullptr); -} - -QWORD CUTF8::Size(bool fWithHeader) -{ - if (IsEmpty()) { - return 0; - } - - QWORD len = 0; - len += UTF16To8(*this).GetLength(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CUTF8::Write(IStream* pStream) -{ - if (IsEmpty()) { - return S_OK; - } - - HeaderWrite(pStream); - CStringA str = UTF16To8(*this); - return pStream->Write((BYTE*)(LPCSTR)str, str.GetLength(), nullptr); -} - -template -QWORD CSimpleVar::Size(bool fWithHeader) -{ - if (!m_fSet) { - return 0; - } - - QWORD len = 0; - len += sizeof(T); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -template -HRESULT CSimpleVar::Write(IStream* pStream) -{ - if (!m_fSet) { - return S_OK; - } - - HeaderWrite(pStream); - T val = m_val; - bswap((BYTE*)&val, sizeof(T)); - return pStream->Write(&val, sizeof(T), nullptr); -} - -QWORD CUInt::Size(bool fWithHeader) -{ - if (!m_fSet) { - return 0; - } - - QWORD len = 0; - - if (m_val == 0) { - len++; - } else { - for (int i = 8; i > 0; i--) { - if (((0xffi64 << ((i - 1) * 8))&m_val)) { - len += i; - break; - } - } - } - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CUInt::Write(IStream* pStream) -{ - if (!m_fSet) { - return S_OK; - } - - CID::Write(pStream); - CLength l(Size(false)); - l.Write(pStream); - UINT64 val = m_val; - bswap((BYTE*)&val, (int)l); - return pStream->Write(&val, (ULONG)l, nullptr); -} - -QWORD CInt::Size(bool fWithHeader) -{ - if (!m_fSet) { - return 0; - } - - QWORD len = 0; - - if (m_val == 0) { - len++; - } else { - UINT64 val = m_val >= 0 ? m_val : -m_val; - for (int i = 8; i > 0; i--) { - if (((0xffi64 << ((i - 1) * 8))&val)) { - len += i; - if (m_val < 0 && !(m_val & (0x80 << (i - 1)))) { - len++; - } - break; - } - } - } - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CInt::Write(IStream* pStream) -{ - if (!m_fSet) { - return S_OK; - } - - CID::Write(pStream); - CLength l(Size(false)); - l.Write(pStream); - UINT64 val = m_val; - bswap((BYTE*)&val, (int)l); - return pStream->Write(&val, (ULONG)l, nullptr); -} - -QWORD CLength::Size(bool fWithHeader) -{ - if (m_len == 0x00FFFFFFFFFFFFFFi64) { - return 8; - } - - QWORD len = 0; - for (int i = 1; i <= 8; i++) { - if (!(m_len & (~((QWORD(1) << (7 * i)) - 1))) && (m_len & ((QWORD(1) << (7 * i)) - 1)) != ((QWORD(1) << (7 * i)) - 1)) { - len += i; - break; - } - } - return len; -} - -HRESULT CLength::Write(IStream* pStream) -{ - QWORD len = Size(false); - UINT64 val = m_len; - bswap((BYTE*)&val, (int)len); - *(BYTE*)&val = ((*(BYTE*)&val) & (1 << (8 - len)) - 1) | (1 << (8 - len)); - return pStream->Write(&val, (ULONG)len, nullptr); -} - -// - -EBML::EBML(DWORD id) - : CID(id) - , EBMLVersion(0x4286) - , EBMLReadVersion(0x42F7) - , EBMLMaxIDLength(0x42F2) - , EBMLMaxSizeLength(0x42F3) - , DocType(0x4282) - , DocTypeVersion(0x4287) - , DocTypeReadVersion(0x4285) -{ -} - -QWORD EBML::Size(bool fWithHeader) -{ - QWORD len = 0; - len += EBMLVersion.Size(); - len += EBMLReadVersion.Size(); - len += EBMLMaxIDLength.Size(); - len += EBMLMaxSizeLength.Size(); - len += DocType.Size(); - len += DocTypeVersion.Size(); - len += DocTypeReadVersion.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT EBML::Write(IStream* pStream) -{ - HeaderWrite(pStream); - EBMLVersion.Write(pStream); - EBMLReadVersion.Write(pStream); - EBMLMaxIDLength.Write(pStream); - EBMLMaxSizeLength.Write(pStream); - DocType.Write(pStream); - DocTypeVersion.Write(pStream); - DocTypeReadVersion.Write(pStream); - return S_OK; -} - -Info::Info(DWORD id) - : CID(id) - , SegmentUID(0x73A4) - , SegmentFilename(0x7384) - , PrevUID(0x3CB923) - , PrevFilename(0x3C83AB) - , NextUID(0x3EB923) - , NextFilename(0x3E83BB) - , TimeCodeScale(0x2AD7B1, 1000000ui64) - , Duration(0x4489) - , DateUTC(0x4461) - , Title(0x7BA9) - , MuxingApp(0x4D80) - , WritingApp(0x5741) -{ -} - -QWORD Info::Size(bool fWithHeader) -{ - QWORD len = 0; - len += SegmentUID.Size(); - len += PrevUID.Size(); - len += NextUID.Size(); - len += SegmentFilename.Size(); - len += PrevFilename.Size(); - len += NextFilename.Size(); - len += TimeCodeScale.Size(); - len += Duration.Size(); - len += DateUTC.Size(); - len += Title.Size(); - len += MuxingApp.Size(); - len += WritingApp.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Info::Write(IStream* pStream) -{ - HeaderWrite(pStream); - SegmentUID.Write(pStream); - PrevUID.Write(pStream); - NextUID.Write(pStream); - SegmentFilename.Write(pStream); - PrevFilename.Write(pStream); - NextFilename.Write(pStream); - TimeCodeScale.Write(pStream); - Duration.Write(pStream); - DateUTC.Write(pStream); - Title.Write(pStream); - MuxingApp.Write(pStream); - WritingApp.Write(pStream); - return S_OK; -} - -Segment::Segment(DWORD id) - : CID(id) -{ -} - -QWORD Segment::Size(bool fWithHeader) -{ - return 0x00FFFFFFFFFFFFFFi64; - /* - QWORD len = 0; - if (fWithHeader) len += HeaderSize(len); - return len; - */ -} - -HRESULT Segment::Write(IStream* pStream) -{ - HeaderWrite(pStream); - return S_OK; -} - -Track::Track(DWORD id) - : CID(id) -{ -} - -QWORD Track::Size(bool fWithHeader) -{ - QWORD len = 0; - len += TrackEntries.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Track::Write(IStream* pStream) -{ - HeaderWrite(pStream); - TrackEntries.Write(pStream); - return S_OK; -} - -TrackEntry::TrackEntry(DWORD id) - : CID(id) - , TrackNumber(0xD7) - , TrackUID(0x73C5) - , TrackType(0x83) - , FlagEnabled(0xB9) - , FlagDefault(0x88) - , FlagLacing(0x9C) - , MinCache(0x6DE7) - , MaxCache(0x6DF8) - , Name(0x536E) - , Language(0x22B59C) - , CodecID(0x86) - , CodecPrivate(0x63A2) - , CodecName(0x258688) - , CodecSettings(0x3A9697) - , CodecInfoURL(0x3B4040) - , CodecDownloadURL(0x26B240) - , CodecDecodeAll(0xAA) - , TrackOverlay(0x6FAB) - , DefaultDuration(0x23E383) - , v(0xE0) - , a(0xE1) -{ - DescType = NoDesc; -} - -QWORD TrackEntry::Size(bool fWithHeader) -{ - QWORD len = 0; - len += TrackNumber.Size(); - len += TrackUID.Size(); - len += TrackType.Size(); - len += FlagEnabled.Size(); - len += FlagDefault.Size(); - len += FlagLacing.Size(); - len += MinCache.Size(); - len += MaxCache.Size(); - len += Name.Size(); - len += Language.Size(); - len += CodecID.Size(); - len += CodecPrivate.Size(); - len += CodecName.Size(); - len += CodecSettings.Size(); - len += CodecInfoURL.Size(); - len += CodecDownloadURL.Size(); - len += CodecDecodeAll.Size(); - len += TrackOverlay.Size(); - len += DefaultDuration.Size(); - if (DescType == TypeVideo) { - len += v.Size(); - } - if (DescType == TypeAudio) { - len += a.Size(); - } - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT TrackEntry::Write(IStream* pStream) -{ - HeaderWrite(pStream); - TrackNumber.Write(pStream); - TrackUID.Write(pStream); - TrackType.Write(pStream); - FlagEnabled.Write(pStream); - FlagDefault.Write(pStream); - FlagLacing.Write(pStream); - MinCache.Write(pStream); - MaxCache.Write(pStream); - Name.Write(pStream); - Language.Write(pStream); - CodecID.Write(pStream); - CodecPrivate.Write(pStream); - CodecName.Write(pStream); - CodecSettings.Write(pStream); - CodecInfoURL.Write(pStream); - CodecDownloadURL.Write(pStream); - CodecDecodeAll.Write(pStream); - TrackOverlay.Write(pStream); - DefaultDuration.Write(pStream); - if (DescType == TypeVideo) { - v.Write(pStream); - } - if (DescType == TypeAudio) { - a.Write(pStream); - } - return S_OK; -} - -Video::Video(DWORD id) - : CID(id) - , FlagInterlaced(0x9A) - , StereoMode(0x53B8) - , PixelWidth(0xB0) - , PixelHeight(0xBA) - , DisplayWidth(0x54B0) - , DisplayHeight(0x54BA) - , DisplayUnit(0x54B2) - , AspectRatioType(0x54B3) - , ColourSpace(0x2EB524) - , GammaValue(0x2FB523) - , FramePerSec(0x2383E3) -{ -} - -QWORD Video::Size(bool fWithHeader) -{ - QWORD len = 0; - len += FlagInterlaced.Size(); - len += StereoMode.Size(); - len += PixelWidth.Size(); - len += PixelHeight.Size(); - len += DisplayWidth.Size(); - len += DisplayHeight.Size(); - len += DisplayUnit.Size(); - len += AspectRatioType.Size(); - len += ColourSpace.Size(); - len += GammaValue.Size(); - len += FramePerSec.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Video::Write(IStream* pStream) -{ - HeaderWrite(pStream); - FlagInterlaced.Write(pStream); - StereoMode.Write(pStream); - PixelWidth.Write(pStream); - PixelHeight.Write(pStream); - DisplayWidth.Write(pStream); - DisplayHeight.Write(pStream); - DisplayUnit.Write(pStream); - AspectRatioType.Write(pStream); - ColourSpace.Write(pStream); - GammaValue.Write(pStream); - FramePerSec.Write(pStream); - return S_OK; -} - -Audio::Audio(DWORD id) - : CID(id) - , SamplingFrequency(0xB5) - , OutputSamplingFrequency(0x78B5) - , Channels(0x9F) - , ChannelPositions(0x7D7B) - , BitDepth(0x6264) -{ -} - -QWORD Audio::Size(bool fWithHeader) -{ - QWORD len = 0; - len += SamplingFrequency.Size(); - len += OutputSamplingFrequency.Size(); - len += Channels.Size(); - len += ChannelPositions.Size(); - len += BitDepth.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Audio::Write(IStream* pStream) -{ - HeaderWrite(pStream); - SamplingFrequency.Write(pStream); - OutputSamplingFrequency.Write(pStream); - Channels.Write(pStream); - ChannelPositions.Write(pStream); - BitDepth.Write(pStream); - return S_OK; -} - -Cluster::Cluster(DWORD id) - : CID(id) - , TimeCode(0xE7) - , Position(0xA7) - , PrevSize(0xAB) -{ -} - -QWORD Cluster::Size(bool fWithHeader) -{ - QWORD len = 0; - len += TimeCode.Size(); - len += Position.Size(); - len += PrevSize.Size(); - len += BlockGroups.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Cluster::Write(IStream* pStream) -{ - HeaderWrite(pStream); - TimeCode.Write(pStream); - Position.Write(pStream); - PrevSize.Write(pStream); - BlockGroups.Write(pStream); - return S_OK; -} - -BlockGroup::BlockGroup(DWORD id) - : CID(id) - , BlockDuration(0x9B) - , ReferencePriority(0xFA) - , ReferenceBlock(0xFB) - , ReferenceVirtual(0xFD) - , CodecState(0xA4) -{ -} - -QWORD BlockGroup::Size(bool fWithHeader) -{ - QWORD len = 0; - len += BlockDuration.Size(); - len += ReferencePriority.Size(); - len += ReferenceBlock.Size(); - len += ReferenceVirtual.Size(); - len += CodecState.Size(); - len += Block.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT BlockGroup::Write(IStream* pStream) -{ - HeaderWrite(pStream); - BlockDuration.Write(pStream); - ReferencePriority.Write(pStream); - ReferenceBlock.Write(pStream); - ReferenceVirtual.Write(pStream); - CodecState.Write(pStream); - Block.Write(pStream); - return S_OK; -} - -CBlock::CBlock(DWORD id) - : CID(id) - , TimeCode(0) - , TimeCodeStop(0) -{ -} - -QWORD CBlock::Size(bool fWithHeader) -{ - QWORD len = 0; - len += TrackNumber.Size() + 2 + 1; // TrackNumber + TimeCode + Lacing - if (BlockData.GetCount() > 1) { - len += 1; // nBlockData - POSITION pos = BlockData.GetHeadPosition(); - while (pos) { - CBinary* b = BlockData.GetNext(pos); - if (pos) { - len += b->GetCount() / 255 + 1; - } - } - } - POSITION pos = BlockData.GetHeadPosition(); - while (pos) { - CBinary* b = BlockData.GetNext(pos); - len += b->GetCount(); - } - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CBlock::Write(IStream* pStream) -{ - HeaderWrite(pStream); - TrackNumber.Write(pStream); - short t = (short)TimeCode; - bswap((BYTE*)&t, 2); - pStream->Write(&t, 2, nullptr); - BYTE Lacing = 0; - BYTE n = (BYTE)BlockData.GetCount(); - if (n > 1) { - Lacing |= 2; - } - pStream->Write(&Lacing, 1, nullptr); - if (n > 1) { - pStream->Write(&n, 1, nullptr); - POSITION pos = BlockData.GetHeadPosition(); - while (pos) { - CBinary* b = BlockData.GetNext(pos); - if (pos) { - INT_PTR len = b->GetCount(); - while (len >= 0) { - n = (BYTE)std::min(len, 255); - pStream->Write(&n, 1, nullptr); - len -= 255; - } - } - } - } - POSITION pos = BlockData.GetHeadPosition(); - while (pos) { - CBinary* b = BlockData.GetNext(pos); - pStream->Write(b->GetData(), (ULONG)b->GetCount(), nullptr); - } - return S_OK; -} - -Cue::Cue(DWORD id) - : CID(id) -{ -} - -QWORD Cue::Size(bool fWithHeader) -{ - QWORD len = 0; - len += CuePoints.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Cue::Write(IStream* pStream) -{ - HeaderWrite(pStream); - CuePoints.Write(pStream); - return S_OK; -} - -CuePoint::CuePoint(DWORD id) - : CID(id) - , CueTime(0xB3) -{ -} - -QWORD CuePoint::Size(bool fWithHeader) -{ - QWORD len = 0; - len += CueTime.Size(); - len += CueTrackPositions.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CuePoint::Write(IStream* pStream) -{ - HeaderWrite(pStream); - CueTime.Write(pStream); - CueTrackPositions.Write(pStream); - return S_OK; -} - -CueTrackPosition::CueTrackPosition(DWORD id) - : CID(id) - , CueTrack(0xF7) - , CueClusterPosition(0xF1) - , CueBlockNumber(0x5387) - , CueCodecState(0xEA) -{ -} - -QWORD CueTrackPosition::Size(bool fWithHeader) -{ - QWORD len = 0; - len += CueTrack.Size(); - len += CueClusterPosition.Size(); - len += CueBlockNumber.Size(); - len += CueCodecState.Size(); - // len += CueReferences.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT CueTrackPosition::Write(IStream* pStream) -{ - HeaderWrite(pStream); - CueTrack.Write(pStream); - CueClusterPosition.Write(pStream); - CueBlockNumber.Write(pStream); - CueCodecState.Write(pStream); - // CueReferences.Write(pStream); - return S_OK; -} - -Seek::Seek(DWORD id) - : CID(id) -{ -} - -QWORD Seek::Size(bool fWithHeader) -{ - QWORD len = 0; - len += SeekHeads.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Seek::Write(IStream* pStream) -{ - HeaderWrite(pStream); - SeekHeads.Write(pStream); - return S_OK; -} - -SeekID::SeekID(DWORD id) - : CID(id) - , m_cid(0) -{ -} - -QWORD SeekID::Size(bool fWithHeader) -{ - QWORD len = 0; - len += m_cid.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT SeekID::Write(IStream* pStream) -{ - HeaderWrite(pStream); - m_cid.Write(pStream); - return S_OK; -} - -SeekHead::SeekHead(DWORD id) - : CID(id) - , Position(0x53AC) -{ -} - -QWORD SeekHead::Size(bool fWithHeader) -{ - QWORD len = 0; - len += ID.Size(); - len += Position.Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT SeekHead::Write(IStream* pStream) -{ - HeaderWrite(pStream); - ID.Write(pStream); - Position.Write(pStream); - return S_OK; -} - -Tags::Tags(DWORD id) - : CID(id) -{ -} - -QWORD Tags::Size(bool fWithHeader) -{ - QWORD len = 0; - // len += .Size(); - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Tags::Write(IStream* pStream) -{ - HeaderWrite(pStream); - // .Write(pStream); - return S_OK; -} - -Void::Void(QWORD len, DWORD id) - : CID(id) - , m_len(len) -{ -} - -QWORD Void::Size(bool fWithHeader) -{ - QWORD len = 0; - len += m_len; - if (fWithHeader) { - len += HeaderSize(len); - } - return len; -} - -HRESULT Void::Write(IStream* pStream) -{ - HeaderWrite(pStream); - BYTE buff[64]; - memset(buff, 0x80, sizeof(buff)); - QWORD len = m_len; - for (; len >= sizeof(buff); len -= sizeof(buff)) { - pStream->Write(buff, sizeof(buff), nullptr); - } - - if (len > 0) { - pStream->Write(buff, (ULONG)len, nullptr); - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include +#include "MatroskaFile.h" +#include "../../../DSUtil/DSUtil.h" + +using namespace MatroskaWriter; + +static void bswap(BYTE* s, int len) +{ + for (BYTE* d = s + len - 1; s < d; s++, d--) { + *s ^= *d, *d ^= *s, *s ^= *d; + } +} + +// + +CID::CID(DWORD id) + : m_id(id) +{ +} + +QWORD CID::Size(bool fWithHeader) +{ + return CUInt(0, m_id).Size(false); +} + +HRESULT CID::Write(IStream* pStream) +{ + QWORD len = CID::Size(); + DWORD id = m_id; + bswap((BYTE*)&id, (int)len); + *(BYTE*)&id = ((*(BYTE*)&id) & (1 << (8 - len)) - 1) | (1 << (8 - len)); + return pStream->Write(&id, (ULONG)len, nullptr); +} + +QWORD CID::HeaderSize(QWORD len) +{ + return CID::Size() + CLength(len).Size(); +} + +HRESULT CID::HeaderWrite(IStream* pStream) +{ + CID::Write(pStream); + CLength(Size(false)).Write(pStream); + return S_OK; +} + +QWORD CBinary::Size(bool fWithHeader) +{ + if (IsEmpty()) { + return 0; + } + + QWORD len = 0; + len += GetCount(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CBinary::Write(IStream* pStream) +{ + if (IsEmpty()) { + return S_OK; + } + + HeaderWrite(pStream); + return pStream->Write(GetData(), (ULONG)GetCount(), nullptr); +} + +QWORD CANSI::Size(bool fWithHeader) +{ + if (IsEmpty()) { + return 0; + } + + QWORD len = 0; + len += GetLength(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CANSI::Write(IStream* pStream) +{ + if (IsEmpty()) { + return S_OK; + } + + HeaderWrite(pStream); + return pStream->Write((LPCSTR) * this, GetLength(), nullptr); +} + +QWORD CUTF8::Size(bool fWithHeader) +{ + if (IsEmpty()) { + return 0; + } + + QWORD len = 0; + len += UTF16To8(*this).GetLength(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CUTF8::Write(IStream* pStream) +{ + if (IsEmpty()) { + return S_OK; + } + + HeaderWrite(pStream); + CStringA str = UTF16To8(*this); + return pStream->Write((BYTE*)(LPCSTR)str, str.GetLength(), nullptr); +} + +template +QWORD CSimpleVar::Size(bool fWithHeader) +{ + if (!m_fSet) { + return 0; + } + + QWORD len = 0; + len += sizeof(T); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +template +HRESULT CSimpleVar::Write(IStream* pStream) +{ + if (!m_fSet) { + return S_OK; + } + + HeaderWrite(pStream); + T val = m_val; + bswap((BYTE*)&val, sizeof(T)); + return pStream->Write(&val, sizeof(T), nullptr); +} + +QWORD CUInt::Size(bool fWithHeader) +{ + if (!m_fSet) { + return 0; + } + + QWORD len = 0; + + if (m_val == 0) { + len++; + } else { + for (int i = 8; i > 0; i--) { + if (((0xffi64 << ((i - 1) * 8))&m_val)) { + len += i; + break; + } + } + } + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CUInt::Write(IStream* pStream) +{ + if (!m_fSet) { + return S_OK; + } + + CID::Write(pStream); + CLength l(Size(false)); + l.Write(pStream); + UINT64 val = m_val; + bswap((BYTE*)&val, (int)l); + return pStream->Write(&val, (ULONG)l, nullptr); +} + +QWORD CInt::Size(bool fWithHeader) +{ + if (!m_fSet) { + return 0; + } + + QWORD len = 0; + + if (m_val == 0) { + len++; + } else { + UINT64 val = m_val >= 0 ? m_val : -m_val; + for (int i = 8; i > 0; i--) { + if (((0xffi64 << ((i - 1) * 8))&val)) { + len += i; + if (m_val < 0 && !(m_val & (0x80 << (i - 1)))) { + len++; + } + break; + } + } + } + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CInt::Write(IStream* pStream) +{ + if (!m_fSet) { + return S_OK; + } + + CID::Write(pStream); + CLength l(Size(false)); + l.Write(pStream); + UINT64 val = m_val; + bswap((BYTE*)&val, (int)l); + return pStream->Write(&val, (ULONG)l, nullptr); +} + +QWORD CLength::Size(bool fWithHeader) +{ + if (m_len == 0x00FFFFFFFFFFFFFFi64) { + return 8; + } + + QWORD len = 0; + for (int i = 1; i <= 8; i++) { + if (!(m_len & (~((QWORD(1) << (7 * i)) - 1))) && (m_len & ((QWORD(1) << (7 * i)) - 1)) != ((QWORD(1) << (7 * i)) - 1)) { + len += i; + break; + } + } + return len; +} + +HRESULT CLength::Write(IStream* pStream) +{ + QWORD len = Size(false); + UINT64 val = m_len; + bswap((BYTE*)&val, (int)len); + *(BYTE*)&val = ((*(BYTE*)&val) & (1 << (8 - len)) - 1) | (1 << (8 - len)); + return pStream->Write(&val, (ULONG)len, nullptr); +} + +// + +EBML::EBML(DWORD id) + : CID(id) + , EBMLVersion(0x4286) + , EBMLReadVersion(0x42F7) + , EBMLMaxIDLength(0x42F2) + , EBMLMaxSizeLength(0x42F3) + , DocType(0x4282) + , DocTypeVersion(0x4287) + , DocTypeReadVersion(0x4285) +{ +} + +QWORD EBML::Size(bool fWithHeader) +{ + QWORD len = 0; + len += EBMLVersion.Size(); + len += EBMLReadVersion.Size(); + len += EBMLMaxIDLength.Size(); + len += EBMLMaxSizeLength.Size(); + len += DocType.Size(); + len += DocTypeVersion.Size(); + len += DocTypeReadVersion.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT EBML::Write(IStream* pStream) +{ + HeaderWrite(pStream); + EBMLVersion.Write(pStream); + EBMLReadVersion.Write(pStream); + EBMLMaxIDLength.Write(pStream); + EBMLMaxSizeLength.Write(pStream); + DocType.Write(pStream); + DocTypeVersion.Write(pStream); + DocTypeReadVersion.Write(pStream); + return S_OK; +} + +Info::Info(DWORD id) + : CID(id) + , SegmentUID(0x73A4) + , SegmentFilename(0x7384) + , PrevUID(0x3CB923) + , PrevFilename(0x3C83AB) + , NextUID(0x3EB923) + , NextFilename(0x3E83BB) + , TimeCodeScale(0x2AD7B1, 1000000ui64) + , Duration(0x4489) + , DateUTC(0x4461) + , Title(0x7BA9) + , MuxingApp(0x4D80) + , WritingApp(0x5741) +{ +} + +QWORD Info::Size(bool fWithHeader) +{ + QWORD len = 0; + len += SegmentUID.Size(); + len += PrevUID.Size(); + len += NextUID.Size(); + len += SegmentFilename.Size(); + len += PrevFilename.Size(); + len += NextFilename.Size(); + len += TimeCodeScale.Size(); + len += Duration.Size(); + len += DateUTC.Size(); + len += Title.Size(); + len += MuxingApp.Size(); + len += WritingApp.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Info::Write(IStream* pStream) +{ + HeaderWrite(pStream); + SegmentUID.Write(pStream); + PrevUID.Write(pStream); + NextUID.Write(pStream); + SegmentFilename.Write(pStream); + PrevFilename.Write(pStream); + NextFilename.Write(pStream); + TimeCodeScale.Write(pStream); + Duration.Write(pStream); + DateUTC.Write(pStream); + Title.Write(pStream); + MuxingApp.Write(pStream); + WritingApp.Write(pStream); + return S_OK; +} + +Segment::Segment(DWORD id) + : CID(id) +{ +} + +QWORD Segment::Size(bool fWithHeader) +{ + return 0x00FFFFFFFFFFFFFFi64; + /* + QWORD len = 0; + if (fWithHeader) len += HeaderSize(len); + return len; + */ +} + +HRESULT Segment::Write(IStream* pStream) +{ + HeaderWrite(pStream); + return S_OK; +} + +Track::Track(DWORD id) + : CID(id) +{ +} + +QWORD Track::Size(bool fWithHeader) +{ + QWORD len = 0; + len += TrackEntries.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Track::Write(IStream* pStream) +{ + HeaderWrite(pStream); + TrackEntries.Write(pStream); + return S_OK; +} + +TrackEntry::TrackEntry(DWORD id) + : CID(id) + , TrackNumber(0xD7) + , TrackUID(0x73C5) + , TrackType(0x83) + , FlagEnabled(0xB9) + , FlagDefault(0x88) + , FlagLacing(0x9C) + , MinCache(0x6DE7) + , MaxCache(0x6DF8) + , Name(0x536E) + , Language(0x22B59C) + , CodecID(0x86) + , CodecPrivate(0x63A2) + , CodecName(0x258688) + , CodecSettings(0x3A9697) + , CodecInfoURL(0x3B4040) + , CodecDownloadURL(0x26B240) + , CodecDecodeAll(0xAA) + , TrackOverlay(0x6FAB) + , DefaultDuration(0x23E383) + , v(0xE0) + , a(0xE1) +{ + DescType = NoDesc; +} + +QWORD TrackEntry::Size(bool fWithHeader) +{ + QWORD len = 0; + len += TrackNumber.Size(); + len += TrackUID.Size(); + len += TrackType.Size(); + len += FlagEnabled.Size(); + len += FlagDefault.Size(); + len += FlagLacing.Size(); + len += MinCache.Size(); + len += MaxCache.Size(); + len += Name.Size(); + len += Language.Size(); + len += CodecID.Size(); + len += CodecPrivate.Size(); + len += CodecName.Size(); + len += CodecSettings.Size(); + len += CodecInfoURL.Size(); + len += CodecDownloadURL.Size(); + len += CodecDecodeAll.Size(); + len += TrackOverlay.Size(); + len += DefaultDuration.Size(); + if (DescType == TypeVideo) { + len += v.Size(); + } + if (DescType == TypeAudio) { + len += a.Size(); + } + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT TrackEntry::Write(IStream* pStream) +{ + HeaderWrite(pStream); + TrackNumber.Write(pStream); + TrackUID.Write(pStream); + TrackType.Write(pStream); + FlagEnabled.Write(pStream); + FlagDefault.Write(pStream); + FlagLacing.Write(pStream); + MinCache.Write(pStream); + MaxCache.Write(pStream); + Name.Write(pStream); + Language.Write(pStream); + CodecID.Write(pStream); + CodecPrivate.Write(pStream); + CodecName.Write(pStream); + CodecSettings.Write(pStream); + CodecInfoURL.Write(pStream); + CodecDownloadURL.Write(pStream); + CodecDecodeAll.Write(pStream); + TrackOverlay.Write(pStream); + DefaultDuration.Write(pStream); + if (DescType == TypeVideo) { + v.Write(pStream); + } + if (DescType == TypeAudio) { + a.Write(pStream); + } + return S_OK; +} + +Video::Video(DWORD id) + : CID(id) + , FlagInterlaced(0x9A) + , StereoMode(0x53B8) + , PixelWidth(0xB0) + , PixelHeight(0xBA) + , DisplayWidth(0x54B0) + , DisplayHeight(0x54BA) + , DisplayUnit(0x54B2) + , AspectRatioType(0x54B3) + , ColourSpace(0x2EB524) + , GammaValue(0x2FB523) + , FramePerSec(0x2383E3) +{ +} + +QWORD Video::Size(bool fWithHeader) +{ + QWORD len = 0; + len += FlagInterlaced.Size(); + len += StereoMode.Size(); + len += PixelWidth.Size(); + len += PixelHeight.Size(); + len += DisplayWidth.Size(); + len += DisplayHeight.Size(); + len += DisplayUnit.Size(); + len += AspectRatioType.Size(); + len += ColourSpace.Size(); + len += GammaValue.Size(); + len += FramePerSec.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Video::Write(IStream* pStream) +{ + HeaderWrite(pStream); + FlagInterlaced.Write(pStream); + StereoMode.Write(pStream); + PixelWidth.Write(pStream); + PixelHeight.Write(pStream); + DisplayWidth.Write(pStream); + DisplayHeight.Write(pStream); + DisplayUnit.Write(pStream); + AspectRatioType.Write(pStream); + ColourSpace.Write(pStream); + GammaValue.Write(pStream); + FramePerSec.Write(pStream); + return S_OK; +} + +Audio::Audio(DWORD id) + : CID(id) + , SamplingFrequency(0xB5) + , OutputSamplingFrequency(0x78B5) + , Channels(0x9F) + , ChannelPositions(0x7D7B) + , BitDepth(0x6264) +{ +} + +QWORD Audio::Size(bool fWithHeader) +{ + QWORD len = 0; + len += SamplingFrequency.Size(); + len += OutputSamplingFrequency.Size(); + len += Channels.Size(); + len += ChannelPositions.Size(); + len += BitDepth.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Audio::Write(IStream* pStream) +{ + HeaderWrite(pStream); + SamplingFrequency.Write(pStream); + OutputSamplingFrequency.Write(pStream); + Channels.Write(pStream); + ChannelPositions.Write(pStream); + BitDepth.Write(pStream); + return S_OK; +} + +Cluster::Cluster(DWORD id) + : CID(id) + , TimeCode(0xE7) + , Position(0xA7) + , PrevSize(0xAB) +{ +} + +QWORD Cluster::Size(bool fWithHeader) +{ + QWORD len = 0; + len += TimeCode.Size(); + len += Position.Size(); + len += PrevSize.Size(); + len += BlockGroups.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Cluster::Write(IStream* pStream) +{ + HeaderWrite(pStream); + TimeCode.Write(pStream); + Position.Write(pStream); + PrevSize.Write(pStream); + BlockGroups.Write(pStream); + return S_OK; +} + +BlockGroup::BlockGroup(DWORD id) + : CID(id) + , BlockDuration(0x9B) + , ReferencePriority(0xFA) + , ReferenceBlock(0xFB) + , ReferenceVirtual(0xFD) + , CodecState(0xA4) +{ +} + +QWORD BlockGroup::Size(bool fWithHeader) +{ + QWORD len = 0; + len += BlockDuration.Size(); + len += ReferencePriority.Size(); + len += ReferenceBlock.Size(); + len += ReferenceVirtual.Size(); + len += CodecState.Size(); + len += Block.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT BlockGroup::Write(IStream* pStream) +{ + HeaderWrite(pStream); + BlockDuration.Write(pStream); + ReferencePriority.Write(pStream); + ReferenceBlock.Write(pStream); + ReferenceVirtual.Write(pStream); + CodecState.Write(pStream); + Block.Write(pStream); + return S_OK; +} + +CBlock::CBlock(DWORD id) + : CID(id) + , TimeCode(0) + , TimeCodeStop(0) +{ +} + +QWORD CBlock::Size(bool fWithHeader) +{ + QWORD len = 0; + len += TrackNumber.Size() + 2 + 1; // TrackNumber + TimeCode + Lacing + if (BlockData.GetCount() > 1) { + len += 1; // nBlockData + POSITION pos = BlockData.GetHeadPosition(); + while (pos) { + CBinary* b = BlockData.GetNext(pos); + if (pos) { + len += b->GetCount() / 255 + 1; + } + } + } + POSITION pos = BlockData.GetHeadPosition(); + while (pos) { + CBinary* b = BlockData.GetNext(pos); + len += b->GetCount(); + } + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CBlock::Write(IStream* pStream) +{ + HeaderWrite(pStream); + TrackNumber.Write(pStream); + short t = (short)TimeCode; + bswap((BYTE*)&t, 2); + pStream->Write(&t, 2, nullptr); + BYTE Lacing = 0; + BYTE n = (BYTE)BlockData.GetCount(); + if (n > 1) { + Lacing |= 2; + } + pStream->Write(&Lacing, 1, nullptr); + if (n > 1) { + pStream->Write(&n, 1, nullptr); + POSITION pos = BlockData.GetHeadPosition(); + while (pos) { + CBinary* b = BlockData.GetNext(pos); + if (pos) { + INT_PTR len = b->GetCount(); + while (len >= 0) { + n = (BYTE)std::min(len, 255); + pStream->Write(&n, 1, nullptr); + len -= 255; + } + } + } + } + POSITION pos = BlockData.GetHeadPosition(); + while (pos) { + CBinary* b = BlockData.GetNext(pos); + pStream->Write(b->GetData(), (ULONG)b->GetCount(), nullptr); + } + return S_OK; +} + +Cue::Cue(DWORD id) + : CID(id) +{ +} + +QWORD Cue::Size(bool fWithHeader) +{ + QWORD len = 0; + len += CuePoints.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Cue::Write(IStream* pStream) +{ + HeaderWrite(pStream); + CuePoints.Write(pStream); + return S_OK; +} + +CuePoint::CuePoint(DWORD id) + : CID(id) + , CueTime(0xB3) +{ +} + +QWORD CuePoint::Size(bool fWithHeader) +{ + QWORD len = 0; + len += CueTime.Size(); + len += CueTrackPositions.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CuePoint::Write(IStream* pStream) +{ + HeaderWrite(pStream); + CueTime.Write(pStream); + CueTrackPositions.Write(pStream); + return S_OK; +} + +CueTrackPosition::CueTrackPosition(DWORD id) + : CID(id) + , CueTrack(0xF7) + , CueClusterPosition(0xF1) + , CueBlockNumber(0x5387) + , CueCodecState(0xEA) +{ +} + +QWORD CueTrackPosition::Size(bool fWithHeader) +{ + QWORD len = 0; + len += CueTrack.Size(); + len += CueClusterPosition.Size(); + len += CueBlockNumber.Size(); + len += CueCodecState.Size(); + // len += CueReferences.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT CueTrackPosition::Write(IStream* pStream) +{ + HeaderWrite(pStream); + CueTrack.Write(pStream); + CueClusterPosition.Write(pStream); + CueBlockNumber.Write(pStream); + CueCodecState.Write(pStream); + // CueReferences.Write(pStream); + return S_OK; +} + +Seek::Seek(DWORD id) + : CID(id) +{ +} + +QWORD Seek::Size(bool fWithHeader) +{ + QWORD len = 0; + len += SeekHeads.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Seek::Write(IStream* pStream) +{ + HeaderWrite(pStream); + SeekHeads.Write(pStream); + return S_OK; +} + +SeekID::SeekID(DWORD id) + : CID(id) + , m_cid(0) +{ +} + +QWORD SeekID::Size(bool fWithHeader) +{ + QWORD len = 0; + len += m_cid.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT SeekID::Write(IStream* pStream) +{ + HeaderWrite(pStream); + m_cid.Write(pStream); + return S_OK; +} + +SeekHead::SeekHead(DWORD id) + : CID(id) + , Position(0x53AC) +{ +} + +QWORD SeekHead::Size(bool fWithHeader) +{ + QWORD len = 0; + len += ID.Size(); + len += Position.Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT SeekHead::Write(IStream* pStream) +{ + HeaderWrite(pStream); + ID.Write(pStream); + Position.Write(pStream); + return S_OK; +} + +Tags::Tags(DWORD id) + : CID(id) +{ +} + +QWORD Tags::Size(bool fWithHeader) +{ + QWORD len = 0; + // len += .Size(); + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Tags::Write(IStream* pStream) +{ + HeaderWrite(pStream); + // .Write(pStream); + return S_OK; +} + +Void::Void(QWORD len, DWORD id) + : CID(id) + , m_len(len) +{ +} + +QWORD Void::Size(bool fWithHeader) +{ + QWORD len = 0; + len += m_len; + if (fWithHeader) { + len += HeaderSize(len); + } + return len; +} + +HRESULT Void::Write(IStream* pStream) +{ + HeaderWrite(pStream); + BYTE buff[64]; + memset(buff, 0x80, sizeof(buff)); + QWORD len = m_len; + for (; len >= sizeof(buff); len -= sizeof(buff)) { + pStream->Write(buff, sizeof(buff), nullptr); + } + + if (len > 0) { + pStream->Write(buff, (ULONG)len, nullptr); + } + + return S_OK; +} diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaFile.h b/src/filters/muxer/MatroskaMuxer/MatroskaFile.h index b8faf06c39f..5f2f183241e 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaFile.h +++ b/src/filters/muxer/MatroskaMuxer/MatroskaFile.h @@ -1,427 +1,427 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include -#include - -namespace MatroskaWriter -{ - class CID - { - protected: - DWORD m_id; - QWORD HeaderSize(QWORD len); - HRESULT HeaderWrite(IStream* pStream); - - public: - CID(DWORD id); - DWORD GetID() const { - return m_id; - } - virtual QWORD Size(bool fWithHeader = true); - virtual HRESULT Write(IStream* pStream); - }; - - class CLength : public CID - { - UINT64 m_len; - public: - CLength(UINT64 len = 0) : CID(0), m_len(len) {} - operator UINT64() { - return m_len; - } - QWORD Size(bool fWithHeader = false); - HRESULT Write(IStream* pStream); - }; - - class CBinary : public CAtlArray, public CID - { - public: - CBinary(DWORD id) : CID(id) {} - CBinary& operator = (const CBinary& b) { - Copy(b); - return *this; - } - operator BYTE* () { - return (BYTE*)GetData(); - } - CBinary& Set(CStringA str) { - SetCount(str.GetLength() + 1); - strcpy_s((char*)GetData(), str.GetLength() + 1, str); - return *this; - } - //CBinary& Set(CStringA str) {SetCount(str.GetLength()); memcpy((char*)GetData(), str, str.GetLength()); return *this;} - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CANSI : public CStringA, public CID - { - public: - CANSI(DWORD id) : CID(id) {} - CANSI& Set(CStringA str) { - CStringA::operator = (str); - return *this; - } - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CUTF8 : public CStringW, public CID - { - public: - CUTF8(DWORD id) : CID(id) {} - CUTF8& Set(CStringW str) { - CStringW::operator = (str); - return *this; - } - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - template - class CSimpleVar : public CID - { - protected: - T m_val; - bool m_fSet; - public: - explicit CSimpleVar(DWORD id, T val = 0) : CID(id), m_val(val) { - m_fSet = !!val; - } - operator T() { - return m_val; - } - BASE& Set(T val) { - m_val = val; - m_fSet = true; - return (*(BASE*)this); - } - void UnSet() { - m_fSet = false; - } - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CUInt : public CSimpleVar - { - public: - explicit CUInt(DWORD id, UINT64 val = 0) : CSimpleVar(id, val) {} - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CInt : public CSimpleVar - { - public: - explicit CInt(DWORD id, INT64 val = 0) : CSimpleVar(id, val) {} - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CByte : public CSimpleVar - { - public: - explicit CByte(DWORD id, BYTE val = 0) : CSimpleVar(id, val) {} - }; - - class CShort : public CSimpleVar - { - public: - explicit CShort(DWORD id, short val = 0) : CSimpleVar(id, val) {} - }; - - class CFloat : public CSimpleVar - { - public: - explicit CFloat(DWORD id, float val = 0) : CSimpleVar(id, val) {} - }; - - template - class CNode : public CAutoPtrList - { - public: - QWORD Size(bool fWithHeader = true) { - QWORD len = 0; - POSITION pos = CAutoPtrList::GetHeadPosition(); - while (pos) { - len += CAutoPtrList::GetNext(pos)->Size(fWithHeader); - } - return len; - } - HRESULT Write(IStream* pStream) { - POSITION pos = CAutoPtrList::GetHeadPosition(); - while (pos) { - HRESULT hr; - if (FAILED(hr = CAutoPtrList::GetNext(pos)->Write(pStream))) { - return hr; - } - } - return S_OK; - } - }; - - class EBML : public CID - { - public: - CUInt EBMLVersion, EBMLReadVersion; - CUInt EBMLMaxIDLength, EBMLMaxSizeLength; - CANSI DocType; - CUInt DocTypeVersion, DocTypeReadVersion; - - EBML(DWORD id = 0x1A45DFA3); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Info : public CID - { - public: - CBinary SegmentUID, PrevUID, NextUID; - CUTF8 SegmentFilename, PrevFilename, NextFilename; - CUInt TimeCodeScale; // [ns], default: 1.000.000 - CFloat Duration; - CInt DateUTC; - CUTF8 Title, MuxingApp, WritingApp; - - Info(DWORD id = 0x1549A966); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Video : public CID - { - public: - CUInt FlagInterlaced, StereoMode; - CUInt PixelWidth, PixelHeight, DisplayWidth, DisplayHeight, DisplayUnit; - CUInt AspectRatioType; - CUInt ColourSpace; - CFloat GammaValue; - CFloat FramePerSec; - - Video(DWORD id = 0xE0); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Audio : public CID - { - public: - CFloat SamplingFrequency; - CFloat OutputSamplingFrequency; - CUInt Channels; - CBinary ChannelPositions; - CUInt BitDepth; - - Audio(DWORD id = 0xE1); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class TrackEntry : public CID - { - public: - enum { - TypeVideo = 1, - TypeAudio = 2, - TypeComplex = 3, - TypeLogo = 0x10, - TypeSubtitle = 0x11, - TypeControl = 0x20 - }; - CUInt TrackNumber, TrackUID, TrackType; - CUInt FlagEnabled, FlagDefault, FlagLacing; - CUInt MinCache, MaxCache; - CUTF8 Name; - CANSI Language; - CBinary CodecID; - CBinary CodecPrivate; - CUTF8 CodecName; - CUTF8 CodecSettings; - CANSI CodecInfoURL; - CANSI CodecDownloadURL; - CUInt CodecDecodeAll; - CUInt TrackOverlay; - CUInt DefaultDuration; - enum { NoDesc = 0, DescVideo = 1, DescAudio = 2 }; - int DescType; - Video v; - Audio a; - - TrackEntry(DWORD id = 0xAE); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Track : public CID - { - public: - CNode TrackEntries; - - Track(DWORD id = 0x1654AE6B); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CBlock : public CID - { - public: - CLength TrackNumber; - REFERENCE_TIME TimeCode, TimeCodeStop; - CNode BlockData; - - CBlock(DWORD id = 0xA1); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class BlockGroup : public CID - { - public: - CUInt BlockDuration; - CUInt ReferencePriority; - CInt ReferenceBlock; - CInt ReferenceVirtual; - CBinary CodecState; - CBlock Block; - //CNode TimeSlices; - - BlockGroup(DWORD id = 0xA0); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Cluster : public CID - { - public: - CUInt TimeCode, Position, PrevSize; - CNode BlockGroups; - - Cluster(DWORD id = 0x1F43B675); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - /*class CueReference : public CID - { - public: - CUInt CueRefTime, CueRefCluster, CueRefNumber, CueRefCodecState; - - CueReference(DWORD id = 0xDB); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - };*/ - - class CueTrackPosition : public CID - { - public: - CUInt CueTrack, CueClusterPosition, CueBlockNumber, CueCodecState; - // CNode CueReferences; - - CueTrackPosition(DWORD id = 0xB7); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class CuePoint : public CID - { - public: - CUInt CueTime; - CNode CueTrackPositions; - - CuePoint(DWORD id = 0xBB); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Cue : public CID - { - public: - CNode CuePoints; - - Cue(DWORD id = 0x1C53BB6B); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class SeekID : public CID - { - CID m_cid; - public: - SeekID(DWORD id = 0x53AB); - void Set(DWORD id) { - m_cid = id; - } - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class SeekHead : public CID - { - public: - SeekID ID; - CUInt Position; - - SeekHead(DWORD id = 0x4DBB); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Seek : public CID - { - public: - CNode SeekHeads; - - Seek(DWORD id = 0x114D9B74); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Segment : public CID - { - public: - Segment(DWORD id = 0x18538067); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Tags : public CID - { - public: - // TODO - - Tags(DWORD id = 0x1254C367); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; - - class Void : public CID - { - QWORD m_len; - public: - Void(QWORD len, DWORD id = 0xEC); - QWORD Size(bool fWithHeader = true); - HRESULT Write(IStream* pStream); - }; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include +#include + +namespace MatroskaWriter +{ + class CID + { + protected: + DWORD m_id; + QWORD HeaderSize(QWORD len); + HRESULT HeaderWrite(IStream* pStream); + + public: + CID(DWORD id); + DWORD GetID() const { + return m_id; + } + virtual QWORD Size(bool fWithHeader = true); + virtual HRESULT Write(IStream* pStream); + }; + + class CLength : public CID + { + UINT64 m_len; + public: + CLength(UINT64 len = 0) : CID(0), m_len(len) {} + operator UINT64() { + return m_len; + } + QWORD Size(bool fWithHeader = false); + HRESULT Write(IStream* pStream); + }; + + class CBinary : public CAtlArray, public CID + { + public: + CBinary(DWORD id) : CID(id) {} + CBinary& operator = (const CBinary& b) { + Copy(b); + return *this; + } + operator BYTE* () { + return (BYTE*)GetData(); + } + CBinary& Set(CStringA str) { + SetCount(str.GetLength() + 1); + strcpy_s((char*)GetData(), str.GetLength() + 1, str); + return *this; + } + //CBinary& Set(CStringA str) {SetCount(str.GetLength()); memcpy((char*)GetData(), str, str.GetLength()); return *this;} + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CANSI : public CStringA, public CID + { + public: + CANSI(DWORD id) : CID(id) {} + CANSI& Set(CStringA str) { + CStringA::operator = (str); + return *this; + } + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CUTF8 : public CStringW, public CID + { + public: + CUTF8(DWORD id) : CID(id) {} + CUTF8& Set(CStringW str) { + CStringW::operator = (str); + return *this; + } + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + template + class CSimpleVar : public CID + { + protected: + T m_val; + bool m_fSet; + public: + explicit CSimpleVar(DWORD id, T val = 0) : CID(id), m_val(val) { + m_fSet = !!val; + } + operator T() { + return m_val; + } + BASE& Set(T val) { + m_val = val; + m_fSet = true; + return (*(BASE*)this); + } + void UnSet() { + m_fSet = false; + } + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CUInt : public CSimpleVar + { + public: + explicit CUInt(DWORD id, UINT64 val = 0) : CSimpleVar(id, val) {} + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CInt : public CSimpleVar + { + public: + explicit CInt(DWORD id, INT64 val = 0) : CSimpleVar(id, val) {} + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CByte : public CSimpleVar + { + public: + explicit CByte(DWORD id, BYTE val = 0) : CSimpleVar(id, val) {} + }; + + class CShort : public CSimpleVar + { + public: + explicit CShort(DWORD id, short val = 0) : CSimpleVar(id, val) {} + }; + + class CFloat : public CSimpleVar + { + public: + explicit CFloat(DWORD id, float val = 0) : CSimpleVar(id, val) {} + }; + + template + class CNode : public CAutoPtrList + { + public: + QWORD Size(bool fWithHeader = true) { + QWORD len = 0; + POSITION pos = CAutoPtrList::GetHeadPosition(); + while (pos) { + len += CAutoPtrList::GetNext(pos)->Size(fWithHeader); + } + return len; + } + HRESULT Write(IStream* pStream) { + POSITION pos = CAutoPtrList::GetHeadPosition(); + while (pos) { + HRESULT hr; + if (FAILED(hr = CAutoPtrList::GetNext(pos)->Write(pStream))) { + return hr; + } + } + return S_OK; + } + }; + + class EBML : public CID + { + public: + CUInt EBMLVersion, EBMLReadVersion; + CUInt EBMLMaxIDLength, EBMLMaxSizeLength; + CANSI DocType; + CUInt DocTypeVersion, DocTypeReadVersion; + + EBML(DWORD id = 0x1A45DFA3); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Info : public CID + { + public: + CBinary SegmentUID, PrevUID, NextUID; + CUTF8 SegmentFilename, PrevFilename, NextFilename; + CUInt TimeCodeScale; // [ns], default: 1.000.000 + CFloat Duration; + CInt DateUTC; + CUTF8 Title, MuxingApp, WritingApp; + + Info(DWORD id = 0x1549A966); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Video : public CID + { + public: + CUInt FlagInterlaced, StereoMode; + CUInt PixelWidth, PixelHeight, DisplayWidth, DisplayHeight, DisplayUnit; + CUInt AspectRatioType; + CUInt ColourSpace; + CFloat GammaValue; + CFloat FramePerSec; + + Video(DWORD id = 0xE0); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Audio : public CID + { + public: + CFloat SamplingFrequency; + CFloat OutputSamplingFrequency; + CUInt Channels; + CBinary ChannelPositions; + CUInt BitDepth; + + Audio(DWORD id = 0xE1); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class TrackEntry : public CID + { + public: + enum { + TypeVideo = 1, + TypeAudio = 2, + TypeComplex = 3, + TypeLogo = 0x10, + TypeSubtitle = 0x11, + TypeControl = 0x20 + }; + CUInt TrackNumber, TrackUID, TrackType; + CUInt FlagEnabled, FlagDefault, FlagLacing; + CUInt MinCache, MaxCache; + CUTF8 Name; + CANSI Language; + CBinary CodecID; + CBinary CodecPrivate; + CUTF8 CodecName; + CUTF8 CodecSettings; + CANSI CodecInfoURL; + CANSI CodecDownloadURL; + CUInt CodecDecodeAll; + CUInt TrackOverlay; + CUInt DefaultDuration; + enum { NoDesc = 0, DescVideo = 1, DescAudio = 2 }; + int DescType; + Video v; + Audio a; + + TrackEntry(DWORD id = 0xAE); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Track : public CID + { + public: + CNode TrackEntries; + + Track(DWORD id = 0x1654AE6B); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CBlock : public CID + { + public: + CLength TrackNumber; + REFERENCE_TIME TimeCode, TimeCodeStop; + CNode BlockData; + + CBlock(DWORD id = 0xA1); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class BlockGroup : public CID + { + public: + CUInt BlockDuration; + CUInt ReferencePriority; + CInt ReferenceBlock; + CInt ReferenceVirtual; + CBinary CodecState; + CBlock Block; + //CNode TimeSlices; + + BlockGroup(DWORD id = 0xA0); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Cluster : public CID + { + public: + CUInt TimeCode, Position, PrevSize; + CNode BlockGroups; + + Cluster(DWORD id = 0x1F43B675); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + /*class CueReference : public CID + { + public: + CUInt CueRefTime, CueRefCluster, CueRefNumber, CueRefCodecState; + + CueReference(DWORD id = 0xDB); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + };*/ + + class CueTrackPosition : public CID + { + public: + CUInt CueTrack, CueClusterPosition, CueBlockNumber, CueCodecState; + // CNode CueReferences; + + CueTrackPosition(DWORD id = 0xB7); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class CuePoint : public CID + { + public: + CUInt CueTime; + CNode CueTrackPositions; + + CuePoint(DWORD id = 0xBB); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Cue : public CID + { + public: + CNode CuePoints; + + Cue(DWORD id = 0x1C53BB6B); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class SeekID : public CID + { + CID m_cid; + public: + SeekID(DWORD id = 0x53AB); + void Set(DWORD id) { + m_cid = id; + } + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class SeekHead : public CID + { + public: + SeekID ID; + CUInt Position; + + SeekHead(DWORD id = 0x4DBB); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Seek : public CID + { + public: + CNode SeekHeads; + + Seek(DWORD id = 0x114D9B74); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Segment : public CID + { + public: + Segment(DWORD id = 0x18538067); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Tags : public CID + { + public: + // TODO + + Tags(DWORD id = 0x1254C367); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; + + class Void : public CID + { + QWORD m_len; + public: + Void(QWORD len, DWORD id = 0xEC); + QWORD Size(bool fWithHeader = true); + HRESULT Write(IStream* pStream); + }; +} diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.cpp b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.cpp index ddd726bf32d..81bd5e803a5 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.cpp +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.cpp @@ -1,1419 +1,1419 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "MatroskaMuxer.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -using namespace MatroskaWriter; - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_Matroska} -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, nullptr, 0, nullptr}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CMatroskaMuxerFilter), MatroskaMuxerName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CMatroskaMuxerFilter -// - -CMatroskaMuxerFilter::CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseFilter(NAME("CMatroskaMuxerFilter"), pUnk, this, __uuidof(this)) - , m_rtCurrent(0) - , m_fNegative(true) - , m_fPositive(false) -{ - if (phr) { - *phr = S_OK; - } - - m_pOutput.Attach(DEBUG_NEW CMatroskaMuxerOutputPin(NAME("CMatroskaMuxerOutputPin"), this, this, phr)); - - AddInput(); - - srand(clock()); -} - -CMatroskaMuxerFilter::~CMatroskaMuxerFilter() -{ - CAutoLock cAutoLock(this); -} - -STDMETHODIMP CMatroskaMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - return - // QI(IAMFilterMiscFlags) - QI(IMediaSeeking) - QI(IMatroskaMuxer) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -UINT CMatroskaMuxerFilter::GetTrackNumber(const CBasePin* pPin) -{ - UINT nTrackNumber = 0; - - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - nTrackNumber++; - if (m_pInputs.GetNext(pos) == pPin) { - return nTrackNumber; - } - } - - return 0; -} - -void CMatroskaMuxerFilter::AddInput() -{ - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CBasePin* pPin = m_pInputs.GetNext(pos); - if (!pPin->IsConnected()) { - return; - } - } - - CStringW name; - name.Format(L"Track %u", m_pInputs.GetCount() + 1); - - HRESULT hr; - CAutoPtr pPin(DEBUG_NEW CMatroskaMuxerInputPin(name, this, this, &hr)); - m_pInputs.AddTail(pPin); -} - -int CMatroskaMuxerFilter::GetPinCount() -{ - return (int)m_pInputs.GetCount() + (m_pOutput ? 1 : 0); -} - -CBasePin* CMatroskaMuxerFilter::GetPin(int n) -{ - CAutoLock cAutoLock(this); - - if (n >= 0 && n < (int)m_pInputs.GetCount()) { - if (POSITION pos = m_pInputs.FindIndex(n)) { - return m_pInputs.GetAt(pos); - } - } - - if (n == (int)m_pInputs.GetCount() && m_pOutput) { - return m_pOutput; - } - - return nullptr; -} - -STDMETHODIMP CMatroskaMuxerFilter::Stop() -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (FAILED(hr = __super::Stop())) { - return hr; - } - - CallWorker(CMD_EXIT); - - return hr; -} - -STDMETHODIMP CMatroskaMuxerFilter::Pause() -{ - CAutoLock cAutoLock(this); - - FILTER_STATE fs = m_State; - - HRESULT hr; - - if (FAILED(hr = __super::Pause())) { - return hr; - } - - if (fs == State_Stopped && m_pOutput) { - CAMThread::Create(); - CallWorker(CMD_RUN); - } - - return hr; -} - -STDMETHODIMP CMatroskaMuxerFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (FAILED(hr = __super::Run(tStart))) { - return hr; - } - - return hr; -} - -// IAMFilterMiscFlags - -STDMETHODIMP_(ULONG) CMatroskaMuxerFilter::GetMiscFlags() -{ - return AM_FILTER_MISC_FLAGS_IS_RENDERER; -} - -// IMediaSeeking - -STDMETHODIMP CMatroskaMuxerFilter::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanGetDuration | AM_SEEKING_CanGetCurrentPos; - - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerFilter::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - if (*pCapabilities == 0) { - return S_OK; - } - DWORD caps; - GetCapabilities(&caps); - caps &= *pCapabilities; - return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE; -} - -STDMETHODIMP CMatroskaMuxerFilter::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CMatroskaMuxerFilter::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CMatroskaMuxerFilter::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CMatroskaMuxerFilter::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetDuration(LONGLONG* pDuration) -{ - CheckPointer(pDuration, E_POINTER); - *pDuration = 0; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - REFERENCE_TIME rt = m_pInputs.GetNext(pos)->m_rtDur; - if (rt > *pDuration) { - *pDuration = rt; - } - } - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetStopPosition(LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent) -{ - CheckPointer(pCurrent, E_POINTER); - *pCurrent = m_rtCurrent; - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::SetRate(double dRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetRate(double* pdRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CMatroskaMuxerFilter::GetPreroll(LONGLONG* pllPreroll) -{ - return E_NOTIMPL; -} - -// IMatroskaMuxer - -STDMETHODIMP CMatroskaMuxerFilter::CorrectTimeOffset(bool fNegative, bool fPositive) -{ - m_fNegative = fNegative; - m_fPositive = fPositive; - return S_OK; -} - -// - -ULONGLONG GetStreamPosition(IStream* pStream) -{ - ULARGE_INTEGER pos = {0, 0}; - pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos); - return pos.QuadPart; -} - -ULONGLONG SetStreamPosition(IStream* pStream, ULONGLONG seekpos) -{ - LARGE_INTEGER pos; - pos.QuadPart = seekpos; - ULARGE_INTEGER posnew; - posnew.QuadPart = GetStreamPosition(pStream); - pStream->Seek(pos, STREAM_SEEK_SET, &posnew); - return posnew.QuadPart; -} - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CMatroskaMuxerFilter::ThreadProc() -{ - CComQIPtr pStream; - - if (!m_pOutput || !(pStream = m_pOutput->GetConnected())) { - for (;;) { - DWORD cmd = GetRequest(); - if (cmd == CMD_EXIT) { - CAMThread::m_hThread = nullptr; - } - Reply(S_OK); - if (cmd == CMD_EXIT) { - return 0; - } - } - } - - REFERENCE_TIME rtDur = 0; - GetDuration(&rtDur); - - SetStreamPosition(pStream, 0); - - ULARGE_INTEGER uli = {0}; - pStream->SetSize(uli); - - EBML hdr; - hdr.DocType.Set("matroska"); - hdr.DocTypeVersion.Set(1); - hdr.DocTypeReadVersion.Set(1); - hdr.Write(pStream); - - Segment().Write(pStream); - ULONGLONG segpos = GetStreamPosition(pStream); - - // TODO - QWORD voidlen = 100; - if (rtDur > 0) { - voidlen += QWORD(1.0 * rtDur / MAXCLUSTERTIME / 10000 + 0.5) * 20; - } else { - voidlen += QWORD(1.0 * 1000 * 60 * 60 * 24 / MAXCLUSTERTIME + 0.5) * 20; // when no duration is known, allocate for 24 hours (~340k) - } - ULONGLONG voidpos = GetStreamPosition(pStream); - { - Void v(voidlen); - voidlen = v.Size(); - v.Write(pStream); - } - - // Meta Seek - - Seek seek; - CAutoPtr sh; - - // Segment Info - - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(0x1549A966); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - ULONGLONG infopos = GetStreamPosition(pStream); - Info info; - info.MuxingApp.Set(L"DirectShow Matroska Muxer"); - info.TimeCodeScale.Set(1000000); - info.Duration.Set((float)rtDur / 10000); - struct tm _2001 = {0, 0, 0, 1, 0, 101, 0, 0, 1}; - info.DateUTC.Set((_time64(nullptr) - _mktime64(&_2001)) * 1000000000); - info.Write(pStream); - - // Tracks - - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(0x1654AE6B); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - UINT64 TrackNumber = 0; - /* - CNode Tracks; - CAutoPtr pT(DEBUG_NEW Track()); - POSITION pos = m_pInputs.GetHeadPosition(); - for (int i = 1; pos; i++) - { - CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos); - if (!pPin->IsConnected()) continue; - - CAutoPtr pTE(DEBUG_NEW TrackEntry()); - *pTE = *pPin->GetTrackEntry(); - if (TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo) - TrackNumber = pTE->TrackNumber; - pT->TrackEntries.AddTail(pTE); - } - Tracks.AddTail(pT); - Tracks.Write(pStream); - - if (TrackNumber == 0) TrackNumber = 1; - */ - bool fTracksWritten = false; - - // - - Cluster c; - c.TimeCode.Set(0); - - bool fFirstBlock = true; - INT64 firstTimeCode = 0; - - CAtlList pActivePins; - - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos); - if (pPin->IsConnected()) { - pActivePins.AddTail(pPin); - } - } - - for (;;) { - DWORD cmd = GetRequest(); - - switch (cmd) { - default: - case CMD_EXIT: - CAMThread::m_hThread = nullptr; - Reply(S_OK); - return 0; - - case CMD_RUN: - Reply(S_OK); - - Cue cue; - ULONGLONG lastcueclusterpos = (ULONGLONG) - 1; - INT64 lastcuetimecode = (INT64) - 1; - UINT64 nBlocksInCueTrack = 0; - - while (!CheckRequest(nullptr)) { - if (m_State == State_Paused) { - Sleep(10); - continue; - } - - int nPinsGotSomething = 0, nPinsNeeded = 0; - CMatroskaMuxerInputPin* pPin = nullptr; - REFERENCE_TIME rtMin = _I64_MAX; - - pos = pActivePins.GetHeadPosition(); - while (pos) { - CMatroskaMuxerInputPin* pTmp = pActivePins.GetNext(pos); - - CAutoLock cAutoLock(&pTmp->m_csQueue); - - if (pTmp->m_blocks.IsEmpty() && pTmp->m_fEndOfStreamReceived) { - pActivePins.RemoveAt(pActivePins.Find(pTmp)); - continue; - } - - if (pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle) { - nPinsNeeded++; - } - - if (!pTmp->m_blocks.IsEmpty()) { - if (pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle) { - nPinsGotSomething++; - } - - if (!pTmp->m_blocks.IsEmpty()) { - REFERENCE_TIME rt = pTmp->m_blocks.GetHead()->Block.TimeCode; - if (rt < rtMin) { - rtMin = rt; - pPin = pTmp; - } - } - } - } - - if (pActivePins.IsEmpty()) { - break; - } - - if (!pPin || nPinsNeeded > nPinsGotSomething || !pPin && nPinsGotSomething == 0) { - Sleep(1); - continue; - } - - if (!fTracksWritten) { - CNode Tracks; - CAutoPtr pT(DEBUG_NEW Track()); - pos = pActivePins.GetHeadPosition(); - for (int i = 1; pos; i++) { - CMatroskaMuxerInputPin* pActivePin = pActivePins.GetNext(pos); - - CAutoPtr pTE(DEBUG_NEW TrackEntry()); - *pTE = *pActivePin->GetTrackEntry(); - if (TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo) { - TrackNumber = pTE->TrackNumber; - } - pT->TrackEntries.AddTail(pTE); - } - Tracks.AddTail(pT); - Tracks.Write(pStream); - - if (TrackNumber == 0) { - TrackNumber = 1; - } - - fTracksWritten = true; - } - - ASSERT(pPin); - - CAutoPtr b; - - { - CAutoLock cAutoLock(&pPin->m_csQueue); - b.Attach(pPin->m_blocks.RemoveHead().Detach()); - } - - if (b) { - if (fFirstBlock) { - if (b->Block.TimeCode < 0 && m_fNegative || b->Block.TimeCode > 0 && m_fPositive) { - firstTimeCode = b->Block.TimeCode; - } - fFirstBlock = false; - } - - b->Block.TimeCode -= firstTimeCode; - b->Block.TimeCodeStop -= firstTimeCode; - - /* - TRACE(_T("Muxing (%d): %I64d-%I64d dur=%I64d (c=%d, co=%dms), cnt=%d, ref=%d\n"), - GetTrackNumber(pPin), - (INT64)b->Block.TimeCode, (INT64)b->Block.TimeCodeStop, (UINT64)b->BlockDuration, - (int)((b->Block.TimeCode)/MAXCLUSTERTIME), (int)(b->Block.TimeCode%MAXCLUSTERTIME), - b->Block.BlockData.GetCount(), (int)b->ReferenceBlock); - */ - if (b->Block.TimeCode < SHRT_MIN /*0*/) { - ASSERT(0); - continue; - } - - while ((INT64)(c.TimeCode + MAXCLUSTERTIME) < b->Block.TimeCode) { - if (!c.BlockGroups.IsEmpty()) { - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(c.GetID()/*0x1F43B675*/); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - c.Write(pStream); // TODO: write blocks - } - - c.TimeCode.Set(c.TimeCode + MAXCLUSTERTIME); - c.BlockGroups.RemoveAll(); - nBlocksInCueTrack = 0; - } - - if (b->Block.TrackNumber == TrackNumber) { - nBlocksInCueTrack++; - } - - if (b->ReferenceBlock == 0 && b->Block.TrackNumber == TrackNumber) { - ULONGLONG clusterpos = GetStreamPosition(pStream) - segpos; - if (lastcueclusterpos != clusterpos || lastcuetimecode + 1000 < b->Block.TimeCode) { - CAutoPtr ctp(DEBUG_NEW CueTrackPosition()); - ctp->CueTrack.Set(b->Block.TrackNumber); - ctp->CueClusterPosition.Set(clusterpos); - if (!c.BlockGroups.IsEmpty()) { - ctp->CueBlockNumber.Set(nBlocksInCueTrack); - } - CAutoPtr cp(DEBUG_NEW CuePoint()); - cp->CueTime.Set(b->Block.TimeCode); - cp->CueTrackPositions.AddTail(ctp); - cue.CuePoints.AddTail(cp); - lastcueclusterpos = clusterpos; - lastcuetimecode = b->Block.TimeCode; - } - } - - info.Duration.Set(std::max(info.Duration, (float)b->Block.TimeCodeStop)); - - m_rtCurrent = b->Block.TimeCode * 10000; - - b->Block.TimeCode -= c.TimeCode; - c.BlockGroups.AddTail(b); - } - } - - if (!c.BlockGroups.IsEmpty()) { - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(c.GetID()/*0x1F43B675*/); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - c.Write(pStream); - } - - if (!cue.CuePoints.IsEmpty()) { - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(cue.GetID()/*0x1C53BB6B*/); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - cue.Write(pStream); - } - - { - Tags tags; - - sh.Attach(DEBUG_NEW SeekHead()); - sh->ID.Set(tags.GetID()); - sh->Position.Set(GetStreamPosition(pStream) - segpos); - seek.SeekHeads.AddTail(sh); - - tags.Write(pStream); - } - - SetStreamPosition(pStream, voidpos); - QWORD len = voidlen - seek.Size(); - ASSERT(len >= 0 && len != 1); - seek.Write(pStream); - - if (len == 0) { - // nothing to do - } else if (len >= 2) { - for (QWORD i = 0; i < 8; i++) { - if (len >= (QWORD(1) << i * 7) - 2 && len <= (QWORD(1) << (i + 1) * 7) - 2) { - Void(len - 2 - i).Write(pStream); - break; - } - } - } - - if (abs(m_rtCurrent - (REFERENCE_TIME)info.Duration * 10000) > 10000000i64) { - info.Duration.Set((float)m_rtCurrent / 10000 + 1); - } - - SetStreamPosition(pStream, infopos); - info.Write(pStream); - - // TODO: write some tags - - m_pOutput->DeliverEndOfStream(); - - break; - } - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -// -// CMatroskaMuxerInputPin -// - -CMatroskaMuxerInputPin::CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseInputPin(NAME("CMatroskaMuxerInputPin"), pFilter, pLock, phr, pName) - , m_fActive(false) - , m_rtLastStart(0) - , m_rtLastStop(0) - , m_rtDur(0) - , m_fEndOfStreamReceived(false) -{ -} - -CMatroskaMuxerInputPin::~CMatroskaMuxerInputPin() -{ -} - -STDMETHODIMP CMatroskaMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CMatroskaMuxerInputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Video && (pmt->formattype == FORMAT_VideoInfo - || pmt->formattype == FORMAT_VideoInfo2) - // || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG1Payload && pmt->formattype == FORMAT_MPEGVideo - // || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO && pmt->formattype == FORMAT_MPEG2_VIDEO - || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_DiracVideo && pmt->formattype == FORMAT_DiracVideoInfo - || pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->subtype == FOURCCMap(((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag) - || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis && pmt->formattype == FORMAT_VorbisFormat - || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis2 && pmt->formattype == FORMAT_VorbisFormat2 - || pmt->majortype == MEDIATYPE_Audio && (pmt->subtype == MEDIASUBTYPE_14_4 - || pmt->subtype == MEDIASUBTYPE_28_8 - || pmt->subtype == MEDIASUBTYPE_ATRC - || pmt->subtype == MEDIASUBTYPE_COOK - || pmt->subtype == MEDIASUBTYPE_DNET - || pmt->subtype == MEDIASUBTYPE_SIPR) && pmt->formattype == FORMAT_WaveFormatEx - || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None - || pmt->majortype == MEDIATYPE_Subtitle && pmt->formattype == FORMAT_SubtitleInfo - ? S_OK - : E_INVALIDARG; -} - -HRESULT CMatroskaMuxerInputPin::BreakConnect() -{ - HRESULT hr; - - if (FAILED(hr = __super::BreakConnect())) { - return hr; - } - - m_pTE.Free(); - - return hr; -} - -HRESULT CMatroskaMuxerInputPin::CompleteConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CompleteConnect(pPin))) { - return hr; - } - - m_rtDur = 0; - CComQIPtr pMS; - if ((pMS = GetFilterFromPin(pPin)) || (pMS = pPin)) { - pMS->GetDuration(&m_rtDur); - } - - m_pTE.Free(); - m_pTE.Attach(DEBUG_NEW TrackEntry()); - - m_pTE->TrackUID.Set(rand()); - m_pTE->MinCache.Set(1); - m_pTE->MaxCache.Set(1); - m_pTE->TrackNumber.Set((static_cast(m_pFilter))->GetTrackNumber(this)); - - hr = E_FAIL; - - if (m_mt.majortype == MEDIATYPE_Video) { - m_pTE->TrackType.Set(TrackEntry::TypeVideo); - - if (m_mt.formattype == FORMAT_VideoInfo - && m_mt.subtype == MEDIASUBTYPE_RV10 || m_mt.subtype == MEDIASUBTYPE_RV20 - || m_mt.subtype == MEDIASUBTYPE_RV30 || m_mt.subtype == MEDIASUBTYPE_RV40) { - m_pTE->CodecID.Set("V_REAL/RV00"); - m_pTE->CodecID.SetAt(9, (BYTE)(m_mt.subtype.Data1 >> 16)); - - if (m_mt.formattype == FORMAT_VideoInfo) { - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat; - if (m_mt.cbFormat > sizeof(VIDEOINFOHEADER)) { - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - sizeof(VIDEOINFOHEADER)); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER), m_pTE->CodecPrivate.GetCount()); - } - m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); - if (vih->AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); - } - } else if (m_mt.formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat; - if (m_mt.cbFormat > sizeof(VIDEOINFOHEADER2)) { - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - sizeof(VIDEOINFOHEADER2)); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER2), m_pTE->CodecPrivate.GetCount()); - } - m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); - if (vih->AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); - } - m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); - m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); - } else { - ASSERT(0); - return hr; - } - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_VideoInfo) { - m_pTE->CodecID.Set("V_MS/VFW/FOURCC"); - - VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); - memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); - if (vih->AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); - } - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_VideoInfo2) { - m_pTE->CodecID.Set("V_MS/VFW/FOURCC"); - - VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader)); - memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); - m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); - m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); - if (vih->AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); - } - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_DiracVideoInfo) { - m_pTE->CodecID.Set("V_DIRAC"); - - DIRACINFOHEADER* vih = (DIRACINFOHEADER*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(vih->cbSequenceHeader); - memcpy(m_pTE->CodecPrivate, (BYTE*)&vih->dwSequenceHeader[0], m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(vih->hdr.AvgTimePerFrame * 100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(vih->hdr.bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(vih->hdr.bmiHeader.biHeight)); - // m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); - // m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); - if (vih->hdr.AvgTimePerFrame > 0) { - m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->hdr.AvgTimePerFrame)); - } - - hr = S_OK; - } - /* - else if (m_mt.formattype == FORMAT_MPEGVideo) - { - m_pTE->CodecID.Set("V_DSHOW/MPEG1VIDEO"); // V_MPEG1 - - MPEG1VIDEOINFO* pm1vi = (MPEG1VIDEOINFO*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.FormatLength()); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(pm1vi->hdr.AvgTimePerFrame*100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(pm1vi->hdr.bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(pm1vi->hdr.bmiHeader.biHeight)); - if (pm1vi->hdr.AvgTimePerFrame > 0) - m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm1vi->hdr.AvgTimePerFrame)); - - hr = S_OK; - } - else if (m_mt.formattype == FORMAT_MPEG2_VIDEO) - { - m_pTE->CodecID.Set("V_DSHOW/MPEG2VIDEO"); // V_MPEG2 - - MPEG2VIDEOINFO* pm2vi = (MPEG2VIDEOINFO*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.FormatLength()); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetCount()); - m_pTE->DefaultDuration.Set(pm2vi->hdr.AvgTimePerFrame*100); - m_pTE->DescType = TrackEntry::DescVideo; - m_pTE->v.PixelWidth.Set(pm2vi->hdr.bmiHeader.biWidth); - m_pTE->v.PixelHeight.Set(abs(pm2vi->hdr.bmiHeader.biHeight)); - if (pm2vi->hdr.AvgTimePerFrame > 0) - m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm2vi->hdr.AvgTimePerFrame)); - - hr = S_OK; - } - */ - } else if (m_mt.majortype == MEDIATYPE_Audio) { - m_pTE->TrackType.Set(TrackEntry::TypeAudio); - - if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_AAC - && m_mt.cbFormat >= sizeof(WAVEFORMATEX) + 2) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - BYTE* p = (BYTE*)(wfe + 1); - - DWORD nSamplesPerSec = wfe->nSamplesPerSec; - - int profile = (p[0] >> 3) - 1; - int rate1 = ((p[0] & 7) << 1) | (p[1] >> 7); - int channels = ((p[1] >> 3) & 15); - int rate2 = rate1; - - if (wfe->cbSize >= 5) { - profile = 4; - - int exttype = (p[2] << 3) | (p[3] >> 5); - ASSERT(exttype == 0x2B7); - ASSERT((p[3] & 31) == 5); - ASSERT((p[4] >> 7) == 1); - rate2 = ((p[4] >> 3) & 15); - - if (rate2 < rate1) { - m_pTE->a.OutputSamplingFrequency.Set((float)nSamplesPerSec); - nSamplesPerSec /= 2; - } - } - - switch (profile) { - default: - case 0: - m_pTE->CodecID.Set("A_AAC/MPEG2/MAIN"); - break; - case 1: - m_pTE->CodecID.Set("A_AAC/MPEG2/LC"); - break; - case 2: - m_pTE->CodecID.Set("A_AAC/MPEG2/SSR"); - break; - case 3: - m_pTE->CodecID.Set("A_AAC/MPEG4/LTP"); - break; - case 4: - m_pTE->CodecID.Set("A_AAC/MPEG4/LC/SBR"); - break; - } - - ASSERT(channels == wfe->nChannels); - - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)nSamplesPerSec); - m_pTE->a.Channels.Set(channels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3) { - m_pTE->CodecID.Set("A_AC3"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS) { - m_pTE->CodecID.Set("A_DTS"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_FLAC) { - m_pTE->CodecID.Set("A_FLAC"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - if (wfe->cbSize) { - m_pTE->CodecPrivate.SetCount(wfe->cbSize); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(WAVEFORMATEX), wfe->cbSize); - } - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && (m_mt.subtype == MEDIASUBTYPE_14_4 - || m_mt.subtype == MEDIASUBTYPE_28_8 - || m_mt.subtype == MEDIASUBTYPE_ATRC - || m_mt.subtype == MEDIASUBTYPE_COOK - || m_mt.subtype == MEDIASUBTYPE_DNET - || m_mt.subtype == MEDIASUBTYPE_SIPR)) { - CStringA id; - id.Format("A_REAL/%c%c%c%c", - (char)((m_mt.subtype.Data1 >> 0) & 0xff), - (char)((m_mt.subtype.Data1 >> 8) & 0xff), - (char)((m_mt.subtype.Data1 >> 16) & 0xff), - (char)((m_mt.subtype.Data1 >> 24) & 0xff)); - - m_pTE->CodecID.Set(id); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - DWORD cbSize = sizeof(WAVEFORMATEX) + wfe->cbSize; - if (m_mt.cbFormat > cbSize) { - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - cbSize); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + cbSize, m_pTE->CodecPrivate.GetCount()); - } - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM) { - m_pTE->CodecID.Set("A_PCM/INT/LIT"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_WaveFormatEx) { - m_pTE->CodecID.Set("A_MS/ACM"); - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat); - memcpy(m_pTE->CodecPrivate, wfe, m_pTE->CodecPrivate.GetCount()); - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); - m_pTE->a.Channels.Set(wfe->nChannels); - m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_VorbisFormat) { - m_pTE->CodecID.Set("A_VORBIS"); - - VORBISFORMAT* pvf = (VORBISFORMAT*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)pvf->nSamplesPerSec); - m_pTE->a.Channels.Set(pvf->nChannels); - - // m_pTE->CodecPrivate will be filled later - - hr = S_OK; - } else if (m_mt.formattype == FORMAT_VorbisFormat2) { - m_pTE->CodecID.Set("A_VORBIS"); - - VORBISFORMAT2* pvf2 = (VORBISFORMAT2*)m_mt.pbFormat; - m_pTE->DescType = TrackEntry::DescAudio; - m_pTE->a.SamplingFrequency.Set((float)pvf2->SamplesPerSec); - m_pTE->a.Channels.Set(pvf2->Channels); - m_pTE->a.BitDepth.Set(pvf2->BitsPerSample); - - int len = 1; - for (int i = 0; i < 2; i++) { - len += pvf2->HeaderSize[i] / 255 + 1; - } - for (int i = 0; i < 3; i++) { - len += pvf2->HeaderSize[i]; - } - m_pTE->CodecPrivate.SetCount(len); - - BYTE* src = (BYTE*)m_mt.pbFormat + sizeof(VORBISFORMAT2); - BYTE* dst = m_pTE->CodecPrivate.GetData(); - - *dst++ = 2; - for (int i = 0; i < 2; i++) { - for (int len2 = pvf2->HeaderSize[i]; len2 >= 0; len2 -= 255) { - *dst++ = (BYTE)std::min(len2, BYTE_MAX); - } - } - - memcpy(dst, src, pvf2->HeaderSize[0]); - dst += pvf2->HeaderSize[0]; - src += pvf2->HeaderSize[0]; - memcpy(dst, src, pvf2->HeaderSize[1]); - dst += pvf2->HeaderSize[1]; - src += pvf2->HeaderSize[1]; - memcpy(dst, src, pvf2->HeaderSize[2]); - dst += pvf2->HeaderSize[2]; - src += pvf2->HeaderSize[2]; - - ASSERT(src <= m_mt.pbFormat + m_mt.cbFormat); - ASSERT(dst <= m_pTE->CodecPrivate.GetData() + m_pTE->CodecPrivate.GetCount()); - - hr = S_OK; - } - } else if (m_mt.majortype == MEDIATYPE_Text) { - m_pTE->TrackType.Set(TrackEntry::TypeSubtitle); - - if (m_mt.formattype == FORMAT_None) { - m_pTE->CodecID.Set("S_TEXT/ASCII"); - hr = S_OK; - } - } else if (m_mt.majortype == MEDIATYPE_Subtitle) { - m_pTE->TrackType.Set(TrackEntry::TypeSubtitle); - - m_pTE->CodecID.Set( - m_mt.subtype == MEDIASUBTYPE_UTF8 ? "S_TEXT/UTF8" : - m_mt.subtype == MEDIASUBTYPE_SSA ? "S_TEXT/SSA" : - m_mt.subtype == MEDIASUBTYPE_ASS ? "S_TEXT/ASS" : - m_mt.subtype == MEDIASUBTYPE_USF ? "S_TEXT/USF" : - m_mt.subtype == MEDIASUBTYPE_VOBSUB ? "S_VOBSUB" : - ""); - - if (!m_pTE->CodecID.IsEmpty()) { - hr = S_OK; - - SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; - if (psi->dwOffset) { - m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - psi->dwOffset); - memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + psi->dwOffset, m_pTE->CodecPrivate.GetCount()); - } - } - } - - if (S_OK == hr) { - (static_cast(m_pFilter))->AddInput(); - } - - return hr; -} - -HRESULT CMatroskaMuxerInputPin::Active() -{ - m_fActive = true; - m_rtLastStart = m_rtLastStop = -1; - m_fEndOfStreamReceived = false; - return __super::Active(); -} - -HRESULT CMatroskaMuxerInputPin::Inactive() -{ - m_fActive = false; - CAutoLock cAutoLock(&m_csQueue); - m_blocks.RemoveAll(); - m_pVorbisHdrs.RemoveAll(); - return __super::Inactive(); -} - -STDMETHODIMP CMatroskaMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - CAutoLock cAutoLock(&m_csReceive); - return __super::NewSegment(tStart, tStop, dRate); -} - -STDMETHODIMP CMatroskaMuxerInputPin::BeginFlush() -{ - return __super::BeginFlush(); -} - -STDMETHODIMP CMatroskaMuxerInputPin::EndFlush() -{ - return __super::EndFlush(); -} - -STDMETHODIMP CMatroskaMuxerInputPin::Receive(IMediaSample* pSample) -{ - if (m_fEndOfStreamReceived) { - /*ASSERT(0);*/ - return S_FALSE; - } - - CAutoLock cAutoLock(&m_csReceive); - - while (m_fActive) { - { - CAutoLock cAutoLock2(&m_csQueue); - if (m_blocks.GetCount() < MAXBLOCKS) { - break; - } - } - - Sleep(1); - } - - if (!m_fActive) { - return S_FALSE; - } - - HRESULT hr; - - if (FAILED(hr = __super::Receive(pSample))) { - return hr; - } - - BYTE* pData = nullptr; - if (FAILED(hr = pSample->GetPointer(&pData)) || !pData) { - return hr; - } - - long inputLen = pSample->GetActualDataLength(); - - REFERENCE_TIME rtStart = -1, rtStop = -1; - hr = pSample->GetTime(&rtStart, &rtStop); - - if (FAILED(hr) || rtStart == -1 || rtStop == -1) { - TRACE(_T("No timestamp was set on the sample!!!")); - m_pFilter->NotifyEvent(EC_ERRORABORT, VFW_E_SAMPLE_TIME_NOT_SET, 0); - return VFW_E_SAMPLE_TIME_NOT_SET; - } - - //rtStart += m_tStart; - //rtStop += m_tStart; - - TRACE(_T("Received (%u): %I64d-%I64d (c=%d, co=%dms), len=%ld, d%d p%d s%d\n"), - (static_cast(m_pFilter))->GetTrackNumber(this), - rtStart, rtStop, (int)((rtStart / 10000) / MAXCLUSTERTIME), (int)((rtStart / 10000) % MAXCLUSTERTIME), - inputLen, - pSample->IsDiscontinuity() == S_OK ? 1 : 0, - pSample->IsPreroll() == S_OK ? 1 : 0, - pSample->IsSyncPoint() == S_OK ? 1 : 0); - - if (m_mt.subtype == MEDIASUBTYPE_Vorbis && m_pVorbisHdrs.GetCount() < 3) { - CAutoPtr data(DEBUG_NEW CBinary(0)); - data->SetCount(inputLen); - memcpy(data->GetData(), pData, inputLen); - m_pVorbisHdrs.Add(data); - - if (m_pVorbisHdrs.GetCount() == 3) { - int len = 1; - for (size_t i = 0; i < 2; i++) { - len += (int)m_pVorbisHdrs[i]->GetCount() / 255 + 1; - } - for (size_t i = 0; i < 3; i++) { - len += (int)m_pVorbisHdrs[i]->GetCount(); - } - m_pTE->CodecPrivate.SetCount(len); - - BYTE* dst = m_pTE->CodecPrivate.GetData(); - - *dst++ = 2; - for (size_t i = 0; i < 2; i++) { - for (INT_PTR len2 = m_pVorbisHdrs[i]->GetCount(); len2 >= 0; len2 -= 255) { - *dst++ = (BYTE)std::min(len2, 255); - } - } - - for (size_t i = 0; i < 3; i++) { - memcpy(dst, m_pVorbisHdrs[i]->GetData(), m_pVorbisHdrs[i]->GetCount()); - dst += m_pVorbisHdrs[i]->GetCount(); - } - } - - return S_OK; - } - - if (m_mt.formattype == FORMAT_WaveFormatEx - && (((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM - || ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_MPEGLAYER3)) { - pSample->SetSyncPoint(TRUE); // HACK: some capture filters don't set this - } - - CAutoPtr b(DEBUG_NEW BlockGroup()); - /* - // TODO: test this with a longer capture (pcm, mp3) - if (S_OK == pSample->IsSyncPoint() && rtStart < m_rtLastStart) - { - TRACE(_T("!!! timestamp went backwards, dropping this frame !!! rtStart (%I64) < m_rtLastStart (%I64)"), rtStart, m_rtLastStart); - return S_OK; - } - */ - if ((S_OK != pSample->IsSyncPoint() || m_rtLastStart == rtStart) && m_rtLastStart >= 0 /*&& m_rtLastStart < rtStart*/) { - ASSERT(m_rtLastStart - rtStart <= 0); - REFERENCE_TIME rtDiff = m_rtLastStart - rtStart; - b->ReferenceBlock.Set((rtDiff + (rtDiff >= 0 ? 5000 : -5000)) / 10000); - } - - b->Block.TrackNumber = (static_cast(m_pFilter))->GetTrackNumber(this); - - b->Block.TimeCode = (rtStart + 5000) / 10000; - b->Block.TimeCodeStop = (rtStop + 5000) / 10000; - - if (m_pTE->TrackType == TrackEntry::TypeSubtitle) { - b->BlockDuration.Set((rtStop - rtStart + 5000) / 10000); - } - - CAutoPtr data(DEBUG_NEW CBinary(0)); - data->SetCount(inputLen); - memcpy(data->GetData(), pData, inputLen); - b->Block.BlockData.AddTail(data); - - CAutoLock cAutoLock2(&m_csQueue); - m_blocks.AddTail(b); // TODO: lacing for audio - - m_rtLastStart = rtStart; - m_rtLastStop = rtStop; - - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerInputPin::EndOfStream() -{ - HRESULT hr; - - if (FAILED(hr = __super::EndOfStream())) { - return hr; - } - - CAutoLock cAutoLock(&m_csQueue); - - m_fEndOfStreamReceived = true; - - return hr; -} - -// -// CMatroskaMuxerOutputPin -// - -CMatroskaMuxerOutputPin::CMatroskaMuxerOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output") -{ -} - -CMatroskaMuxerOutputPin::~CMatroskaMuxerOutputPin() -{ -} - -STDMETHODIMP CMatroskaMuxerOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CMatroskaMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = 1; - pProperties->cbBuffer = 1; - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CMatroskaMuxerOutputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_Matroska - ? S_OK - : E_INVALIDARG; -} - -HRESULT CMatroskaMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CAutoLock cAutoLock(m_pLock); - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - pmt->ResetFormatBuffer(); - pmt->InitMediaType(); - pmt->majortype = MEDIATYPE_Stream; - pmt->subtype = MEDIASUBTYPE_Matroska; - pmt->formattype = FORMAT_None; - - return S_OK; -} - -STDMETHODIMP CMatroskaMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "MatroskaMuxer.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +using namespace MatroskaWriter; + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_Matroska} +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, TRUE, &CLSID_NULL, nullptr, 0, nullptr}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CMatroskaMuxerFilter), MatroskaMuxerName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CMatroskaMuxerFilter +// + +CMatroskaMuxerFilter::CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseFilter(NAME("CMatroskaMuxerFilter"), pUnk, this, __uuidof(this)) + , m_rtCurrent(0) + , m_fNegative(true) + , m_fPositive(false) +{ + if (phr) { + *phr = S_OK; + } + + m_pOutput.Attach(DEBUG_NEW CMatroskaMuxerOutputPin(NAME("CMatroskaMuxerOutputPin"), this, this, phr)); + + AddInput(); + + srand(clock()); +} + +CMatroskaMuxerFilter::~CMatroskaMuxerFilter() +{ + CAutoLock cAutoLock(this); +} + +STDMETHODIMP CMatroskaMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + return + // QI(IAMFilterMiscFlags) + QI(IMediaSeeking) + QI(IMatroskaMuxer) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +UINT CMatroskaMuxerFilter::GetTrackNumber(const CBasePin* pPin) +{ + UINT nTrackNumber = 0; + + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + nTrackNumber++; + if (m_pInputs.GetNext(pos) == pPin) { + return nTrackNumber; + } + } + + return 0; +} + +void CMatroskaMuxerFilter::AddInput() +{ + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CBasePin* pPin = m_pInputs.GetNext(pos); + if (!pPin->IsConnected()) { + return; + } + } + + CStringW name; + name.Format(L"Track %u", m_pInputs.GetCount() + 1); + + HRESULT hr; + CAutoPtr pPin(DEBUG_NEW CMatroskaMuxerInputPin(name, this, this, &hr)); + m_pInputs.AddTail(pPin); +} + +int CMatroskaMuxerFilter::GetPinCount() +{ + return (int)m_pInputs.GetCount() + (m_pOutput ? 1 : 0); +} + +CBasePin* CMatroskaMuxerFilter::GetPin(int n) +{ + CAutoLock cAutoLock(this); + + if (n >= 0 && n < (int)m_pInputs.GetCount()) { + if (POSITION pos = m_pInputs.FindIndex(n)) { + return m_pInputs.GetAt(pos); + } + } + + if (n == (int)m_pInputs.GetCount() && m_pOutput) { + return m_pOutput; + } + + return nullptr; +} + +STDMETHODIMP CMatroskaMuxerFilter::Stop() +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (FAILED(hr = __super::Stop())) { + return hr; + } + + CallWorker(CMD_EXIT); + + return hr; +} + +STDMETHODIMP CMatroskaMuxerFilter::Pause() +{ + CAutoLock cAutoLock(this); + + FILTER_STATE fs = m_State; + + HRESULT hr; + + if (FAILED(hr = __super::Pause())) { + return hr; + } + + if (fs == State_Stopped && m_pOutput) { + CAMThread::Create(); + CallWorker(CMD_RUN); + } + + return hr; +} + +STDMETHODIMP CMatroskaMuxerFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (FAILED(hr = __super::Run(tStart))) { + return hr; + } + + return hr; +} + +// IAMFilterMiscFlags + +STDMETHODIMP_(ULONG) CMatroskaMuxerFilter::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_RENDERER; +} + +// IMediaSeeking + +STDMETHODIMP CMatroskaMuxerFilter::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanGetDuration | AM_SEEKING_CanGetCurrentPos; + + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerFilter::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + if (*pCapabilities == 0) { + return S_OK; + } + DWORD caps; + GetCapabilities(&caps); + caps &= *pCapabilities; + return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE; +} + +STDMETHODIMP CMatroskaMuxerFilter::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CMatroskaMuxerFilter::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CMatroskaMuxerFilter::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CMatroskaMuxerFilter::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetDuration(LONGLONG* pDuration) +{ + CheckPointer(pDuration, E_POINTER); + *pDuration = 0; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + REFERENCE_TIME rt = m_pInputs.GetNext(pos)->m_rtDur; + if (rt > *pDuration) { + *pDuration = rt; + } + } + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetStopPosition(LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent) +{ + CheckPointer(pCurrent, E_POINTER); + *pCurrent = m_rtCurrent; + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::SetRate(double dRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetRate(double* pdRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CMatroskaMuxerFilter::GetPreroll(LONGLONG* pllPreroll) +{ + return E_NOTIMPL; +} + +// IMatroskaMuxer + +STDMETHODIMP CMatroskaMuxerFilter::CorrectTimeOffset(bool fNegative, bool fPositive) +{ + m_fNegative = fNegative; + m_fPositive = fPositive; + return S_OK; +} + +// + +ULONGLONG GetStreamPosition(IStream* pStream) +{ + ULARGE_INTEGER pos = {0, 0}; + pStream->Seek(*(LARGE_INTEGER*)&pos, STREAM_SEEK_CUR, &pos); + return pos.QuadPart; +} + +ULONGLONG SetStreamPosition(IStream* pStream, ULONGLONG seekpos) +{ + LARGE_INTEGER pos; + pos.QuadPart = seekpos; + ULARGE_INTEGER posnew; + posnew.QuadPart = GetStreamPosition(pStream); + pStream->Seek(pos, STREAM_SEEK_SET, &posnew); + return posnew.QuadPart; +} + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CMatroskaMuxerFilter::ThreadProc() +{ + CComQIPtr pStream; + + if (!m_pOutput || !(pStream = m_pOutput->GetConnected())) { + for (;;) { + DWORD cmd = GetRequest(); + if (cmd == CMD_EXIT) { + CAMThread::m_hThread = nullptr; + } + Reply(S_OK); + if (cmd == CMD_EXIT) { + return 0; + } + } + } + + REFERENCE_TIME rtDur = 0; + GetDuration(&rtDur); + + SetStreamPosition(pStream, 0); + + ULARGE_INTEGER uli = {0}; + pStream->SetSize(uli); + + EBML hdr; + hdr.DocType.Set("matroska"); + hdr.DocTypeVersion.Set(1); + hdr.DocTypeReadVersion.Set(1); + hdr.Write(pStream); + + Segment().Write(pStream); + ULONGLONG segpos = GetStreamPosition(pStream); + + // TODO + QWORD voidlen = 100; + if (rtDur > 0) { + voidlen += QWORD(1.0 * rtDur / MAXCLUSTERTIME / 10000 + 0.5) * 20; + } else { + voidlen += QWORD(1.0 * 1000 * 60 * 60 * 24 / MAXCLUSTERTIME + 0.5) * 20; // when no duration is known, allocate for 24 hours (~340k) + } + ULONGLONG voidpos = GetStreamPosition(pStream); + { + Void v(voidlen); + voidlen = v.Size(); + v.Write(pStream); + } + + // Meta Seek + + Seek seek; + CAutoPtr sh; + + // Segment Info + + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(0x1549A966); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + ULONGLONG infopos = GetStreamPosition(pStream); + Info info; + info.MuxingApp.Set(L"DirectShow Matroska Muxer"); + info.TimeCodeScale.Set(1000000); + info.Duration.Set((float)rtDur / 10000); + struct tm _2001 = {0, 0, 0, 1, 0, 101, 0, 0, 1}; + info.DateUTC.Set((_time64(nullptr) - _mktime64(&_2001)) * 1000000000); + info.Write(pStream); + + // Tracks + + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(0x1654AE6B); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + UINT64 TrackNumber = 0; + /* + CNode Tracks; + CAutoPtr pT(DEBUG_NEW Track()); + POSITION pos = m_pInputs.GetHeadPosition(); + for (int i = 1; pos; i++) + { + CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos); + if (!pPin->IsConnected()) continue; + + CAutoPtr pTE(DEBUG_NEW TrackEntry()); + *pTE = *pPin->GetTrackEntry(); + if (TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo) + TrackNumber = pTE->TrackNumber; + pT->TrackEntries.AddTail(pTE); + } + Tracks.AddTail(pT); + Tracks.Write(pStream); + + if (TrackNumber == 0) TrackNumber = 1; + */ + bool fTracksWritten = false; + + // + + Cluster c; + c.TimeCode.Set(0); + + bool fFirstBlock = true; + INT64 firstTimeCode = 0; + + CAtlList pActivePins; + + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CMatroskaMuxerInputPin* pPin = m_pInputs.GetNext(pos); + if (pPin->IsConnected()) { + pActivePins.AddTail(pPin); + } + } + + for (;;) { + DWORD cmd = GetRequest(); + + switch (cmd) { + default: + case CMD_EXIT: + CAMThread::m_hThread = nullptr; + Reply(S_OK); + return 0; + + case CMD_RUN: + Reply(S_OK); + + Cue cue; + ULONGLONG lastcueclusterpos = (ULONGLONG) - 1; + INT64 lastcuetimecode = (INT64) - 1; + UINT64 nBlocksInCueTrack = 0; + + while (!CheckRequest(nullptr)) { + if (m_State == State_Paused) { + Sleep(10); + continue; + } + + int nPinsGotSomething = 0, nPinsNeeded = 0; + CMatroskaMuxerInputPin* pPin = nullptr; + REFERENCE_TIME rtMin = _I64_MAX; + + pos = pActivePins.GetHeadPosition(); + while (pos) { + CMatroskaMuxerInputPin* pTmp = pActivePins.GetNext(pos); + + CAutoLock cAutoLock(&pTmp->m_csQueue); + + if (pTmp->m_blocks.IsEmpty() && pTmp->m_fEndOfStreamReceived) { + pActivePins.RemoveAt(pActivePins.Find(pTmp)); + continue; + } + + if (pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle) { + nPinsNeeded++; + } + + if (!pTmp->m_blocks.IsEmpty()) { + if (pTmp->GetTrackEntry()->TrackType != TrackEntry::TypeSubtitle) { + nPinsGotSomething++; + } + + if (!pTmp->m_blocks.IsEmpty()) { + REFERENCE_TIME rt = pTmp->m_blocks.GetHead()->Block.TimeCode; + if (rt < rtMin) { + rtMin = rt; + pPin = pTmp; + } + } + } + } + + if (pActivePins.IsEmpty()) { + break; + } + + if (!pPin || nPinsNeeded > nPinsGotSomething || !pPin && nPinsGotSomething == 0) { + Sleep(1); + continue; + } + + if (!fTracksWritten) { + CNode Tracks; + CAutoPtr pT(DEBUG_NEW Track()); + pos = pActivePins.GetHeadPosition(); + for (int i = 1; pos; i++) { + CMatroskaMuxerInputPin* pActivePin = pActivePins.GetNext(pos); + + CAutoPtr pTE(DEBUG_NEW TrackEntry()); + *pTE = *pActivePin->GetTrackEntry(); + if (TrackNumber == 0 && pTE->TrackType == TrackEntry::TypeVideo) { + TrackNumber = pTE->TrackNumber; + } + pT->TrackEntries.AddTail(pTE); + } + Tracks.AddTail(pT); + Tracks.Write(pStream); + + if (TrackNumber == 0) { + TrackNumber = 1; + } + + fTracksWritten = true; + } + + ASSERT(pPin); + + CAutoPtr b; + + { + CAutoLock cAutoLock(&pPin->m_csQueue); + b.Attach(pPin->m_blocks.RemoveHead().Detach()); + } + + if (b) { + if (fFirstBlock) { + if (b->Block.TimeCode < 0 && m_fNegative || b->Block.TimeCode > 0 && m_fPositive) { + firstTimeCode = b->Block.TimeCode; + } + fFirstBlock = false; + } + + b->Block.TimeCode -= firstTimeCode; + b->Block.TimeCodeStop -= firstTimeCode; + + /* + TRACE(_T("Muxing (%d): %I64d-%I64d dur=%I64d (c=%d, co=%dms), cnt=%d, ref=%d\n"), + GetTrackNumber(pPin), + (INT64)b->Block.TimeCode, (INT64)b->Block.TimeCodeStop, (UINT64)b->BlockDuration, + (int)((b->Block.TimeCode)/MAXCLUSTERTIME), (int)(b->Block.TimeCode%MAXCLUSTERTIME), + b->Block.BlockData.GetCount(), (int)b->ReferenceBlock); + */ + if (b->Block.TimeCode < SHRT_MIN /*0*/) { + ASSERT(0); + continue; + } + + while ((INT64)(c.TimeCode + MAXCLUSTERTIME) < b->Block.TimeCode) { + if (!c.BlockGroups.IsEmpty()) { + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(c.GetID()/*0x1F43B675*/); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + c.Write(pStream); // TODO: write blocks + } + + c.TimeCode.Set(c.TimeCode + MAXCLUSTERTIME); + c.BlockGroups.RemoveAll(); + nBlocksInCueTrack = 0; + } + + if (b->Block.TrackNumber == TrackNumber) { + nBlocksInCueTrack++; + } + + if (b->ReferenceBlock == 0 && b->Block.TrackNumber == TrackNumber) { + ULONGLONG clusterpos = GetStreamPosition(pStream) - segpos; + if (lastcueclusterpos != clusterpos || lastcuetimecode + 1000 < b->Block.TimeCode) { + CAutoPtr ctp(DEBUG_NEW CueTrackPosition()); + ctp->CueTrack.Set(b->Block.TrackNumber); + ctp->CueClusterPosition.Set(clusterpos); + if (!c.BlockGroups.IsEmpty()) { + ctp->CueBlockNumber.Set(nBlocksInCueTrack); + } + CAutoPtr cp(DEBUG_NEW CuePoint()); + cp->CueTime.Set(b->Block.TimeCode); + cp->CueTrackPositions.AddTail(ctp); + cue.CuePoints.AddTail(cp); + lastcueclusterpos = clusterpos; + lastcuetimecode = b->Block.TimeCode; + } + } + + info.Duration.Set(std::max(info.Duration, (float)b->Block.TimeCodeStop)); + + m_rtCurrent = b->Block.TimeCode * 10000; + + b->Block.TimeCode -= c.TimeCode; + c.BlockGroups.AddTail(b); + } + } + + if (!c.BlockGroups.IsEmpty()) { + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(c.GetID()/*0x1F43B675*/); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + c.Write(pStream); + } + + if (!cue.CuePoints.IsEmpty()) { + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(cue.GetID()/*0x1C53BB6B*/); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + cue.Write(pStream); + } + + { + Tags tags; + + sh.Attach(DEBUG_NEW SeekHead()); + sh->ID.Set(tags.GetID()); + sh->Position.Set(GetStreamPosition(pStream) - segpos); + seek.SeekHeads.AddTail(sh); + + tags.Write(pStream); + } + + SetStreamPosition(pStream, voidpos); + QWORD len = voidlen - seek.Size(); + ASSERT(len >= 0 && len != 1); + seek.Write(pStream); + + if (len == 0) { + // nothing to do + } else if (len >= 2) { + for (QWORD i = 0; i < 8; i++) { + if (len >= (QWORD(1) << i * 7) - 2 && len <= (QWORD(1) << (i + 1) * 7) - 2) { + Void(len - 2 - i).Write(pStream); + break; + } + } + } + + if (abs(m_rtCurrent - (REFERENCE_TIME)info.Duration * 10000) > 10000000i64) { + info.Duration.Set((float)m_rtCurrent / 10000 + 1); + } + + SetStreamPosition(pStream, infopos); + info.Write(pStream); + + // TODO: write some tags + + m_pOutput->DeliverEndOfStream(); + + break; + } + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +// +// CMatroskaMuxerInputPin +// + +CMatroskaMuxerInputPin::CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseInputPin(NAME("CMatroskaMuxerInputPin"), pFilter, pLock, phr, pName) + , m_fActive(false) + , m_rtLastStart(0) + , m_rtLastStop(0) + , m_rtDur(0) + , m_fEndOfStreamReceived(false) +{ +} + +CMatroskaMuxerInputPin::~CMatroskaMuxerInputPin() +{ +} + +STDMETHODIMP CMatroskaMuxerInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CMatroskaMuxerInputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Video && (pmt->formattype == FORMAT_VideoInfo + || pmt->formattype == FORMAT_VideoInfo2) + // || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG1Payload && pmt->formattype == FORMAT_MPEGVideo + // || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO && pmt->formattype == FORMAT_MPEG2_VIDEO + || pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_DiracVideo && pmt->formattype == FORMAT_DiracVideoInfo + || pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->subtype == FOURCCMap(((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag) + || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis && pmt->formattype == FORMAT_VorbisFormat + || pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_Vorbis2 && pmt->formattype == FORMAT_VorbisFormat2 + || pmt->majortype == MEDIATYPE_Audio && (pmt->subtype == MEDIASUBTYPE_14_4 + || pmt->subtype == MEDIASUBTYPE_28_8 + || pmt->subtype == MEDIASUBTYPE_ATRC + || pmt->subtype == MEDIASUBTYPE_COOK + || pmt->subtype == MEDIASUBTYPE_DNET + || pmt->subtype == MEDIASUBTYPE_SIPR) && pmt->formattype == FORMAT_WaveFormatEx + || pmt->majortype == MEDIATYPE_Text && pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_None + || pmt->majortype == MEDIATYPE_Subtitle && pmt->formattype == FORMAT_SubtitleInfo + ? S_OK + : E_INVALIDARG; +} + +HRESULT CMatroskaMuxerInputPin::BreakConnect() +{ + HRESULT hr; + + if (FAILED(hr = __super::BreakConnect())) { + return hr; + } + + m_pTE.Free(); + + return hr; +} + +HRESULT CMatroskaMuxerInputPin::CompleteConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CompleteConnect(pPin))) { + return hr; + } + + m_rtDur = 0; + CComQIPtr pMS; + if ((pMS = GetFilterFromPin(pPin)) || (pMS = pPin)) { + pMS->GetDuration(&m_rtDur); + } + + m_pTE.Free(); + m_pTE.Attach(DEBUG_NEW TrackEntry()); + + m_pTE->TrackUID.Set(rand()); + m_pTE->MinCache.Set(1); + m_pTE->MaxCache.Set(1); + m_pTE->TrackNumber.Set((static_cast(m_pFilter))->GetTrackNumber(this)); + + hr = E_FAIL; + + if (m_mt.majortype == MEDIATYPE_Video) { + m_pTE->TrackType.Set(TrackEntry::TypeVideo); + + if (m_mt.formattype == FORMAT_VideoInfo + && m_mt.subtype == MEDIASUBTYPE_RV10 || m_mt.subtype == MEDIASUBTYPE_RV20 + || m_mt.subtype == MEDIASUBTYPE_RV30 || m_mt.subtype == MEDIASUBTYPE_RV40) { + m_pTE->CodecID.Set("V_REAL/RV00"); + m_pTE->CodecID.SetAt(9, (BYTE)(m_mt.subtype.Data1 >> 16)); + + if (m_mt.formattype == FORMAT_VideoInfo) { + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat; + if (m_mt.cbFormat > sizeof(VIDEOINFOHEADER)) { + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - sizeof(VIDEOINFOHEADER)); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER), m_pTE->CodecPrivate.GetCount()); + } + m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); + if (vih->AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); + } + } else if (m_mt.formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat; + if (m_mt.cbFormat > sizeof(VIDEOINFOHEADER2)) { + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - sizeof(VIDEOINFOHEADER2)); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(VIDEOINFOHEADER2), m_pTE->CodecPrivate.GetCount()); + } + m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); + if (vih->AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); + } + m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); + m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); + } else { + ASSERT(0); + return hr; + } + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_VideoInfo) { + m_pTE->CodecID.Set("V_MS/VFW/FOURCC"); + + VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); + memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); + if (vih->AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); + } + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_VideoInfo2) { + m_pTE->CodecID.Set("V_MS/VFW/FOURCC"); + + VIDEOINFOHEADER2* vih = (VIDEOINFOHEADER2*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader)); + memcpy(m_pTE->CodecPrivate, &vih->bmiHeader, m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(vih->AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->bmiHeader.biHeight)); + m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); + m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); + if (vih->AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->AvgTimePerFrame)); + } + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_DiracVideoInfo) { + m_pTE->CodecID.Set("V_DIRAC"); + + DIRACINFOHEADER* vih = (DIRACINFOHEADER*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(vih->cbSequenceHeader); + memcpy(m_pTE->CodecPrivate, (BYTE*)&vih->dwSequenceHeader[0], m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(vih->hdr.AvgTimePerFrame * 100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(vih->hdr.bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(vih->hdr.bmiHeader.biHeight)); + // m_pTE->v.DisplayWidth.Set(vih->dwPictAspectRatioX); + // m_pTE->v.DisplayHeight.Set(vih->dwPictAspectRatioY); + if (vih->hdr.AvgTimePerFrame > 0) { + m_pTE->v.FramePerSec.Set((float)(10000000.0 / vih->hdr.AvgTimePerFrame)); + } + + hr = S_OK; + } + /* + else if (m_mt.formattype == FORMAT_MPEGVideo) + { + m_pTE->CodecID.Set("V_DSHOW/MPEG1VIDEO"); // V_MPEG1 + + MPEG1VIDEOINFO* pm1vi = (MPEG1VIDEOINFO*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.FormatLength()); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(pm1vi->hdr.AvgTimePerFrame*100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(pm1vi->hdr.bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(pm1vi->hdr.bmiHeader.biHeight)); + if (pm1vi->hdr.AvgTimePerFrame > 0) + m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm1vi->hdr.AvgTimePerFrame)); + + hr = S_OK; + } + else if (m_mt.formattype == FORMAT_MPEG2_VIDEO) + { + m_pTE->CodecID.Set("V_DSHOW/MPEG2VIDEO"); // V_MPEG2 + + MPEG2VIDEOINFO* pm2vi = (MPEG2VIDEOINFO*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.FormatLength()); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat, m_pTE->CodecPrivate.GetCount()); + m_pTE->DefaultDuration.Set(pm2vi->hdr.AvgTimePerFrame*100); + m_pTE->DescType = TrackEntry::DescVideo; + m_pTE->v.PixelWidth.Set(pm2vi->hdr.bmiHeader.biWidth); + m_pTE->v.PixelHeight.Set(abs(pm2vi->hdr.bmiHeader.biHeight)); + if (pm2vi->hdr.AvgTimePerFrame > 0) + m_pTE->v.FramePerSec.Set((float)(10000000.0 / pm2vi->hdr.AvgTimePerFrame)); + + hr = S_OK; + } + */ + } else if (m_mt.majortype == MEDIATYPE_Audio) { + m_pTE->TrackType.Set(TrackEntry::TypeAudio); + + if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_AAC + && m_mt.cbFormat >= sizeof(WAVEFORMATEX) + 2) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + BYTE* p = (BYTE*)(wfe + 1); + + DWORD nSamplesPerSec = wfe->nSamplesPerSec; + + int profile = (p[0] >> 3) - 1; + int rate1 = ((p[0] & 7) << 1) | (p[1] >> 7); + int channels = ((p[1] >> 3) & 15); + int rate2 = rate1; + + if (wfe->cbSize >= 5) { + profile = 4; + + int exttype = (p[2] << 3) | (p[3] >> 5); + ASSERT(exttype == 0x2B7); + ASSERT((p[3] & 31) == 5); + ASSERT((p[4] >> 7) == 1); + rate2 = ((p[4] >> 3) & 15); + + if (rate2 < rate1) { + m_pTE->a.OutputSamplingFrequency.Set((float)nSamplesPerSec); + nSamplesPerSec /= 2; + } + } + + switch (profile) { + default: + case 0: + m_pTE->CodecID.Set("A_AAC/MPEG2/MAIN"); + break; + case 1: + m_pTE->CodecID.Set("A_AAC/MPEG2/LC"); + break; + case 2: + m_pTE->CodecID.Set("A_AAC/MPEG2/SSR"); + break; + case 3: + m_pTE->CodecID.Set("A_AAC/MPEG4/LTP"); + break; + case 4: + m_pTE->CodecID.Set("A_AAC/MPEG4/LC/SBR"); + break; + } + + ASSERT(channels == wfe->nChannels); + + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)nSamplesPerSec); + m_pTE->a.Channels.Set(channels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3) { + m_pTE->CodecID.Set("A_AC3"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS) { + m_pTE->CodecID.Set("A_DTS"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_FLAC) { + m_pTE->CodecID.Set("A_FLAC"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + if (wfe->cbSize) { + m_pTE->CodecPrivate.SetCount(wfe->cbSize); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + sizeof(WAVEFORMATEX), wfe->cbSize); + } + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && (m_mt.subtype == MEDIASUBTYPE_14_4 + || m_mt.subtype == MEDIASUBTYPE_28_8 + || m_mt.subtype == MEDIASUBTYPE_ATRC + || m_mt.subtype == MEDIASUBTYPE_COOK + || m_mt.subtype == MEDIASUBTYPE_DNET + || m_mt.subtype == MEDIASUBTYPE_SIPR)) { + CStringA id; + id.Format("A_REAL/%c%c%c%c", + (char)((m_mt.subtype.Data1 >> 0) & 0xff), + (char)((m_mt.subtype.Data1 >> 8) & 0xff), + (char)((m_mt.subtype.Data1 >> 16) & 0xff), + (char)((m_mt.subtype.Data1 >> 24) & 0xff)); + + m_pTE->CodecID.Set(id); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + DWORD cbSize = sizeof(WAVEFORMATEX) + wfe->cbSize; + if (m_mt.cbFormat > cbSize) { + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - cbSize); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + cbSize, m_pTE->CodecPrivate.GetCount()); + } + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM) { + m_pTE->CodecID.Set("A_PCM/INT/LIT"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_WaveFormatEx) { + m_pTE->CodecID.Set("A_MS/ACM"); + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_mt.pbFormat; + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat); + memcpy(m_pTE->CodecPrivate, wfe, m_pTE->CodecPrivate.GetCount()); + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)wfe->nSamplesPerSec); + m_pTE->a.Channels.Set(wfe->nChannels); + m_pTE->a.BitDepth.Set(wfe->wBitsPerSample); + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_VorbisFormat) { + m_pTE->CodecID.Set("A_VORBIS"); + + VORBISFORMAT* pvf = (VORBISFORMAT*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)pvf->nSamplesPerSec); + m_pTE->a.Channels.Set(pvf->nChannels); + + // m_pTE->CodecPrivate will be filled later + + hr = S_OK; + } else if (m_mt.formattype == FORMAT_VorbisFormat2) { + m_pTE->CodecID.Set("A_VORBIS"); + + VORBISFORMAT2* pvf2 = (VORBISFORMAT2*)m_mt.pbFormat; + m_pTE->DescType = TrackEntry::DescAudio; + m_pTE->a.SamplingFrequency.Set((float)pvf2->SamplesPerSec); + m_pTE->a.Channels.Set(pvf2->Channels); + m_pTE->a.BitDepth.Set(pvf2->BitsPerSample); + + int len = 1; + for (int i = 0; i < 2; i++) { + len += pvf2->HeaderSize[i] / 255 + 1; + } + for (int i = 0; i < 3; i++) { + len += pvf2->HeaderSize[i]; + } + m_pTE->CodecPrivate.SetCount(len); + + BYTE* src = (BYTE*)m_mt.pbFormat + sizeof(VORBISFORMAT2); + BYTE* dst = m_pTE->CodecPrivate.GetData(); + + *dst++ = 2; + for (int i = 0; i < 2; i++) { + for (int len2 = pvf2->HeaderSize[i]; len2 >= 0; len2 -= 255) { + *dst++ = (BYTE)std::min(len2, BYTE_MAX); + } + } + + memcpy(dst, src, pvf2->HeaderSize[0]); + dst += pvf2->HeaderSize[0]; + src += pvf2->HeaderSize[0]; + memcpy(dst, src, pvf2->HeaderSize[1]); + dst += pvf2->HeaderSize[1]; + src += pvf2->HeaderSize[1]; + memcpy(dst, src, pvf2->HeaderSize[2]); + dst += pvf2->HeaderSize[2]; + src += pvf2->HeaderSize[2]; + + ASSERT(src <= m_mt.pbFormat + m_mt.cbFormat); + ASSERT(dst <= m_pTE->CodecPrivate.GetData() + m_pTE->CodecPrivate.GetCount()); + + hr = S_OK; + } + } else if (m_mt.majortype == MEDIATYPE_Text) { + m_pTE->TrackType.Set(TrackEntry::TypeSubtitle); + + if (m_mt.formattype == FORMAT_None) { + m_pTE->CodecID.Set("S_TEXT/ASCII"); + hr = S_OK; + } + } else if (m_mt.majortype == MEDIATYPE_Subtitle) { + m_pTE->TrackType.Set(TrackEntry::TypeSubtitle); + + m_pTE->CodecID.Set( + m_mt.subtype == MEDIASUBTYPE_UTF8 ? "S_TEXT/UTF8" : + m_mt.subtype == MEDIASUBTYPE_SSA ? "S_TEXT/SSA" : + m_mt.subtype == MEDIASUBTYPE_ASS ? "S_TEXT/ASS" : + m_mt.subtype == MEDIASUBTYPE_USF ? "S_TEXT/USF" : + m_mt.subtype == MEDIASUBTYPE_VOBSUB ? "S_VOBSUB" : + ""); + + if (!m_pTE->CodecID.IsEmpty()) { + hr = S_OK; + + SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat; + if (psi->dwOffset) { + m_pTE->CodecPrivate.SetCount(m_mt.cbFormat - psi->dwOffset); + memcpy(m_pTE->CodecPrivate, m_mt.pbFormat + psi->dwOffset, m_pTE->CodecPrivate.GetCount()); + } + } + } + + if (S_OK == hr) { + (static_cast(m_pFilter))->AddInput(); + } + + return hr; +} + +HRESULT CMatroskaMuxerInputPin::Active() +{ + m_fActive = true; + m_rtLastStart = m_rtLastStop = -1; + m_fEndOfStreamReceived = false; + return __super::Active(); +} + +HRESULT CMatroskaMuxerInputPin::Inactive() +{ + m_fActive = false; + CAutoLock cAutoLock(&m_csQueue); + m_blocks.RemoveAll(); + m_pVorbisHdrs.RemoveAll(); + return __super::Inactive(); +} + +STDMETHODIMP CMatroskaMuxerInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CAutoLock cAutoLock(&m_csReceive); + return __super::NewSegment(tStart, tStop, dRate); +} + +STDMETHODIMP CMatroskaMuxerInputPin::BeginFlush() +{ + return __super::BeginFlush(); +} + +STDMETHODIMP CMatroskaMuxerInputPin::EndFlush() +{ + return __super::EndFlush(); +} + +STDMETHODIMP CMatroskaMuxerInputPin::Receive(IMediaSample* pSample) +{ + if (m_fEndOfStreamReceived) { + /*ASSERT(0);*/ + return S_FALSE; + } + + CAutoLock cAutoLock(&m_csReceive); + + while (m_fActive) { + { + CAutoLock cAutoLock2(&m_csQueue); + if (m_blocks.GetCount() < MAXBLOCKS) { + break; + } + } + + Sleep(1); + } + + if (!m_fActive) { + return S_FALSE; + } + + HRESULT hr; + + if (FAILED(hr = __super::Receive(pSample))) { + return hr; + } + + BYTE* pData = nullptr; + if (FAILED(hr = pSample->GetPointer(&pData)) || !pData) { + return hr; + } + + long inputLen = pSample->GetActualDataLength(); + + REFERENCE_TIME rtStart = -1, rtStop = -1; + hr = pSample->GetTime(&rtStart, &rtStop); + + if (FAILED(hr) || rtStart == -1 || rtStop == -1) { + TRACE(_T("No timestamp was set on the sample!!!")); + m_pFilter->NotifyEvent(EC_ERRORABORT, VFW_E_SAMPLE_TIME_NOT_SET, 0); + return VFW_E_SAMPLE_TIME_NOT_SET; + } + + //rtStart += m_tStart; + //rtStop += m_tStart; + + TRACE(_T("Received (%u): %I64d-%I64d (c=%d, co=%dms), len=%ld, d%d p%d s%d\n"), + (static_cast(m_pFilter))->GetTrackNumber(this), + rtStart, rtStop, (int)((rtStart / 10000) / MAXCLUSTERTIME), (int)((rtStart / 10000) % MAXCLUSTERTIME), + inputLen, + pSample->IsDiscontinuity() == S_OK ? 1 : 0, + pSample->IsPreroll() == S_OK ? 1 : 0, + pSample->IsSyncPoint() == S_OK ? 1 : 0); + + if (m_mt.subtype == MEDIASUBTYPE_Vorbis && m_pVorbisHdrs.GetCount() < 3) { + CAutoPtr data(DEBUG_NEW CBinary(0)); + data->SetCount(inputLen); + memcpy(data->GetData(), pData, inputLen); + m_pVorbisHdrs.Add(data); + + if (m_pVorbisHdrs.GetCount() == 3) { + int len = 1; + for (size_t i = 0; i < 2; i++) { + len += (int)m_pVorbisHdrs[i]->GetCount() / 255 + 1; + } + for (size_t i = 0; i < 3; i++) { + len += (int)m_pVorbisHdrs[i]->GetCount(); + } + m_pTE->CodecPrivate.SetCount(len); + + BYTE* dst = m_pTE->CodecPrivate.GetData(); + + *dst++ = 2; + for (size_t i = 0; i < 2; i++) { + for (INT_PTR len2 = m_pVorbisHdrs[i]->GetCount(); len2 >= 0; len2 -= 255) { + *dst++ = (BYTE)std::min(len2, 255); + } + } + + for (size_t i = 0; i < 3; i++) { + memcpy(dst, m_pVorbisHdrs[i]->GetData(), m_pVorbisHdrs[i]->GetCount()); + dst += m_pVorbisHdrs[i]->GetCount(); + } + } + + return S_OK; + } + + if (m_mt.formattype == FORMAT_WaveFormatEx + && (((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_PCM + || ((WAVEFORMATEX*)m_mt.pbFormat)->wFormatTag == WAVE_FORMAT_MPEGLAYER3)) { + pSample->SetSyncPoint(TRUE); // HACK: some capture filters don't set this + } + + CAutoPtr b(DEBUG_NEW BlockGroup()); + /* + // TODO: test this with a longer capture (pcm, mp3) + if (S_OK == pSample->IsSyncPoint() && rtStart < m_rtLastStart) + { + TRACE(_T("!!! timestamp went backwards, dropping this frame !!! rtStart (%I64) < m_rtLastStart (%I64)"), rtStart, m_rtLastStart); + return S_OK; + } + */ + if ((S_OK != pSample->IsSyncPoint() || m_rtLastStart == rtStart) && m_rtLastStart >= 0 /*&& m_rtLastStart < rtStart*/) { + ASSERT(m_rtLastStart - rtStart <= 0); + REFERENCE_TIME rtDiff = m_rtLastStart - rtStart; + b->ReferenceBlock.Set((rtDiff + (rtDiff >= 0 ? 5000 : -5000)) / 10000); + } + + b->Block.TrackNumber = (static_cast(m_pFilter))->GetTrackNumber(this); + + b->Block.TimeCode = (rtStart + 5000) / 10000; + b->Block.TimeCodeStop = (rtStop + 5000) / 10000; + + if (m_pTE->TrackType == TrackEntry::TypeSubtitle) { + b->BlockDuration.Set((rtStop - rtStart + 5000) / 10000); + } + + CAutoPtr data(DEBUG_NEW CBinary(0)); + data->SetCount(inputLen); + memcpy(data->GetData(), pData, inputLen); + b->Block.BlockData.AddTail(data); + + CAutoLock cAutoLock2(&m_csQueue); + m_blocks.AddTail(b); // TODO: lacing for audio + + m_rtLastStart = rtStart; + m_rtLastStop = rtStop; + + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerInputPin::EndOfStream() +{ + HRESULT hr; + + if (FAILED(hr = __super::EndOfStream())) { + return hr; + } + + CAutoLock cAutoLock(&m_csQueue); + + m_fEndOfStreamReceived = true; + + return hr; +} + +// +// CMatroskaMuxerOutputPin +// + +CMatroskaMuxerOutputPin::CMatroskaMuxerOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output") +{ +} + +CMatroskaMuxerOutputPin::~CMatroskaMuxerOutputPin() +{ +} + +STDMETHODIMP CMatroskaMuxerOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CMatroskaMuxerOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = 1; + pProperties->cbBuffer = 1; + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CMatroskaMuxerOutputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_Matroska + ? S_OK + : E_INVALIDARG; +} + +HRESULT CMatroskaMuxerOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CAutoLock cAutoLock(m_pLock); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + pmt->ResetFormatBuffer(); + pmt->InitMediaType(); + pmt->majortype = MEDIATYPE_Stream; + pmt->subtype = MEDIASUBTYPE_Matroska; + pmt->formattype = FORMAT_None; + + return S_OK; +} + +STDMETHODIMP CMatroskaMuxerOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.def b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.def +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.h b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.h index 2fe06d8cf2e..b6237e62f01 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.h +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.h @@ -1,162 +1,162 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include -#include "MatroskaFile.h" - -#define MAXCLUSTERTIME 1000 -#define MAXBLOCKS 50 - -#define MatroskaMuxerName L"MPC Matroska Muxer" - -class CMatroskaMuxerInputPin : public CBaseInputPin -{ - CAutoPtr m_pTE; - CAutoPtrArray m_pVorbisHdrs; - - bool m_fActive; - CCritSec m_csReceive; - - REFERENCE_TIME m_rtLastStart, m_rtLastStop; - -public: - CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CMatroskaMuxerInputPin(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - MatroskaWriter::TrackEntry* GetTrackEntry() { return m_pTE; } - - REFERENCE_TIME m_rtDur; - - CCritSec m_csQueue; - CAutoPtrList m_blocks; - bool m_fEndOfStreamReceived; - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pPin); - HRESULT Active(), Inactive(); - - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP EndOfStream(); -}; - -class CMatroskaMuxerOutputPin : public CBaseOutputPin -{ -public: - CMatroskaMuxerOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CMatroskaMuxerOutputPin(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; - -interface __declspec(uuid("38E2D43D-915D-493C-B373-888DB16EE3DC")) - IMatroskaMuxer : - public IUnknown -{ - STDMETHOD(CorrectTimeOffset)(bool fNegative, bool fPositive) PURE; - // TODO: chapters -}; - -class __declspec(uuid("1E1299A2-9D42-4F12-8791-D79E376F4143")) - CMatroskaMuxerFilter - : public CBaseFilter - , public CCritSec - , public CAMThread - , public IAMFilterMiscFlags - , public IMediaSeeking - , public IMatroskaMuxer -{ -protected: - CAutoPtrList m_pInputs; - CAutoPtr m_pOutput; - - REFERENCE_TIME m_rtCurrent; - - bool m_fNegative, m_fPositive; - - enum { CMD_EXIT, CMD_RUN }; - DWORD ThreadProc(); - -public: - CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr); - virtual ~CMatroskaMuxerFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - void AddInput(); - UINT GetTrackNumber(const CBasePin* pPin); - - int GetPinCount(); - CBasePin* GetPin(int n); - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // IAMFilterMiscFlags - - STDMETHODIMP_(ULONG) GetMiscFlags(); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - - // IMatroskaMuxer - - STDMETHODIMP CorrectTimeOffset(bool fNegative, bool fPositive); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include +#include "MatroskaFile.h" + +#define MAXCLUSTERTIME 1000 +#define MAXBLOCKS 50 + +#define MatroskaMuxerName L"MPC Matroska Muxer" + +class CMatroskaMuxerInputPin : public CBaseInputPin +{ + CAutoPtr m_pTE; + CAutoPtrArray m_pVorbisHdrs; + + bool m_fActive; + CCritSec m_csReceive; + + REFERENCE_TIME m_rtLastStart, m_rtLastStop; + +public: + CMatroskaMuxerInputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CMatroskaMuxerInputPin(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + MatroskaWriter::TrackEntry* GetTrackEntry() { return m_pTE; } + + REFERENCE_TIME m_rtDur; + + CCritSec m_csQueue; + CAutoPtrList m_blocks; + bool m_fEndOfStreamReceived; + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pPin); + HRESULT Active(), Inactive(); + + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP EndOfStream(); +}; + +class CMatroskaMuxerOutputPin : public CBaseOutputPin +{ +public: + CMatroskaMuxerOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CMatroskaMuxerOutputPin(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; + +interface __declspec(uuid("38E2D43D-915D-493C-B373-888DB16EE3DC")) + IMatroskaMuxer : + public IUnknown +{ + STDMETHOD(CorrectTimeOffset)(bool fNegative, bool fPositive) PURE; + // TODO: chapters +}; + +class __declspec(uuid("1E1299A2-9D42-4F12-8791-D79E376F4143")) + CMatroskaMuxerFilter + : public CBaseFilter + , public CCritSec + , public CAMThread + , public IAMFilterMiscFlags + , public IMediaSeeking + , public IMatroskaMuxer +{ +protected: + CAutoPtrList m_pInputs; + CAutoPtr m_pOutput; + + REFERENCE_TIME m_rtCurrent; + + bool m_fNegative, m_fPositive; + + enum { CMD_EXIT, CMD_RUN }; + DWORD ThreadProc(); + +public: + CMatroskaMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr); + virtual ~CMatroskaMuxerFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + void AddInput(); + UINT GetTrackNumber(const CBasePin* pPin); + + int GetPinCount(); + CBasePin* GetPin(int n); + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // IAMFilterMiscFlags + + STDMETHODIMP_(ULONG) GetMiscFlags(); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + + // IMatroskaMuxer + + STDMETHODIMP CorrectTimeOffset(bool fNegative, bool fPositive); +}; diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.rc b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.rc index a19cf668c10..956a55e56eb 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.rc +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "Matroska Muxer" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "Matroska Muxer" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "MatroskaMuxer.ax" - VALUE "ProductName", "Matroska Muxer" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "Matroska Muxer" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "Matroska Muxer" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "MatroskaMuxer.ax" + VALUE "ProductName", "Matroska Muxer" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj index 5ae5862291a..0bf08977290 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj @@ -1,126 +1,126 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {67827491-8162-4039-9132-F934ABC836A0} - MatroskaMuxer - MFCProj - MatroskaMuxer - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - MatroskaMuxer.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - - Create - - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {67827491-8162-4039-9132-F934ABC836A0} + MatroskaMuxer + MFCProj + MatroskaMuxer + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + MatroskaMuxer.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + + Create + + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj.filters b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj.filters index 9c1e88ed197..3b9080e4865 100644 --- a/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj.filters +++ b/src/filters/muxer/MatroskaMuxer/MatroskaMuxer.vcxproj.filters @@ -1,52 +1,52 @@ - - - - - {5ba8ecdf-2b3a-4c43-8d71-30a1bbc63dbb} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {3325ae0c-9fde-43fb-905c-ba603cc0378f} - h;hpp;hxx;hm;inl;inc - - - {9e126e2d-b3ce-4bd5-bde1-9874e3a354d7} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {5ba8ecdf-2b3a-4c43-8d71-30a1bbc63dbb} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {3325ae0c-9fde-43fb-905c-ba603cc0378f} + h;hpp;hxx;hm;inl;inc + + + {9e126e2d-b3ce-4bd5-bde1-9874e3a354d7} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/muxer/MatroskaMuxer/resource.h b/src/filters/muxer/MatroskaMuxer/resource.h index ef1214d7bc0..22bd5aaf892 100644 --- a/src/filters/muxer/MatroskaMuxer/resource.h +++ b/src/filters/muxer/MatroskaMuxer/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by MatroskaMuxer.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by MatroskaMuxer.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/muxer/MatroskaMuxer/stdafx.cpp b/src/filters/muxer/MatroskaMuxer/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/muxer/MatroskaMuxer/stdafx.cpp +++ b/src/filters/muxer/MatroskaMuxer/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/muxer/MatroskaMuxer/stdafx.h b/src/filters/muxer/MatroskaMuxer/stdafx.h index a8517b3e334..619304dd68e 100644 --- a/src/filters/muxer/MatroskaMuxer/stdafx.h +++ b/src/filters/muxer/MatroskaMuxer/stdafx.h @@ -1,35 +1,35 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/muxer/WavDest/WavDest.cpp b/src/filters/muxer/WavDest/WavDest.cpp index af62b991850..f2f292e1dc2 100644 --- a/src/filters/muxer/WavDest/WavDest.cpp +++ b/src/filters/muxer/WavDest/WavDest.cpp @@ -1,334 +1,334 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include "BaseClasses/streams.h" -#include -#include "WavDest.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CWavDestFilter), WavDestName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {L"WavDest", &__uuidof(CWavDestFilter), CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CWavDestFilter -// - -CWavDestFilter::CWavDestFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CTransformFilter(NAME("WavDest filter"), pUnk, __uuidof(this)) - , m_cbWavData(0) - , m_cbHeader(0) -{ - if (CWavDestOutputPin* pOut = DEBUG_NEW CWavDestOutputPin(this, phr)) { - if (SUCCEEDED(*phr)) { - m_pOutput = pOut; - } else { - delete pOut; - } - } else { - *phr = E_OUTOFMEMORY; - return; - } - - if (CTransformInputPin* pIn = DEBUG_NEW CTransformInputPin(NAME("Transform input pin"), this, phr, L"In")) { - if (SUCCEEDED(*phr)) { - m_pInput = pIn; - } else { - delete pIn; - } - } else { - *phr = E_OUTOFMEMORY; - return; - } -} - -CWavDestFilter::~CWavDestFilter() -{ -} - -HRESULT CWavDestFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return CheckInputType(mtIn); -} - -HRESULT CWavDestFilter::Receive(IMediaSample* pSample) -{ - ULONG cbOld = m_cbWavData; - HRESULT hr = CTransformFilter::Receive(pSample); - - // don't update the count if Deliver() downstream fails. - if (hr != S_OK) { - m_cbWavData = cbOld; - } - - return hr; -} - -HRESULT CWavDestFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - REFERENCE_TIME rtStart, rtEnd; - - HRESULT hr = Copy(pIn, pOut); - if (FAILED(hr)) { - return hr; - } - - // Prepare it for writing - LONG lActual = pOut->GetActualDataLength(); - - if (m_cbWavData + m_cbHeader + lActual < m_cbWavData + m_cbHeader) { // overflow - return E_FAIL; - } - - rtStart = m_cbWavData + m_cbHeader; - rtEnd = rtStart + lActual; - m_cbWavData += lActual; - - EXECUTE_ASSERT(pOut->SetTime(&rtStart, &rtEnd) == S_OK); - - return S_OK; -} - -HRESULT CWavDestFilter::Copy(IMediaSample* pSource, IMediaSample* pDest) const -{ - BYTE* pSourceBuffer, * pDestBuffer; - long lSourceSize = pSource->GetActualDataLength(); - -#ifdef _DEBUG - long lDestSize = pDest->GetSize(); - ASSERT(lDestSize >= lSourceSize); -#endif - - if (FAILED(pSource->GetPointer(&pSourceBuffer)) || !pSourceBuffer) { - return E_FAIL; - } - if (FAILED(pDest->GetPointer(&pDestBuffer)) || !pDestBuffer) { - return E_FAIL; - } - - CopyMemory((PVOID)pDestBuffer, (PVOID)pSourceBuffer, lSourceSize); - - // Copy the sample times - - REFERENCE_TIME rtTimeStart, rtTimeEnd; - if (SUCCEEDED(pSource->GetTime(&rtTimeStart, &rtTimeEnd))) { - pDest->SetTime(&rtTimeStart, &rtTimeEnd); - } - - LONGLONG rtMediaStart, rtMediaEnd; - if (SUCCEEDED(pSource->GetMediaTime(&rtMediaStart, &rtMediaEnd))) { - pDest->SetMediaTime(&rtMediaStart, &rtMediaEnd); - } - - // Copy the media type - AM_MEDIA_TYPE* pMediaType; - if (SUCCEEDED(pSource->GetMediaType(&pMediaType)) && pMediaType) { - pDest->SetMediaType(pMediaType); - DeleteMediaType(pMediaType); - } - - // Copy the actual data length - long lDataLength = pSource->GetActualDataLength(); - pDest->SetActualDataLength(lDataLength); - - return NOERROR; -} - -HRESULT CWavDestFilter::CheckInputType(const CMediaType* mtIn) -{ - return mtIn->formattype == FORMAT_WaveFormatEx ? S_OK : S_FALSE; -} - -HRESULT CWavDestFilter::GetMediaType(int iPosition, CMediaType* pMediaType) -{ - ASSERT(iPosition == 0 || iPosition == 1); - - if (iPosition == 0) { - pMediaType->SetType(&MEDIATYPE_Stream); - pMediaType->SetSubtype(&MEDIASUBTYPE_WAVE); - return S_OK; - } - - return VFW_S_NO_MORE_ITEMS; -} - -HRESULT CWavDestFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = 1; - pProperties->cbAlign = 1; - - CComPtr pInAlloc; - ALLOCATOR_PROPERTIES InProps; - if (SUCCEEDED(hr = m_pInput->GetAllocator(&pInAlloc)) - && SUCCEEDED(hr = pInAlloc->GetProperties(&InProps))) { - pProperties->cbBuffer = InProps.cbBuffer; - } else { - return hr; - } - - ASSERT(pProperties->cbBuffer); - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - ASSERT(Actual.cBuffers == 1); - - if (pProperties->cBuffers > Actual.cBuffers - || pProperties->cbBuffer > Actual.cbBuffer) { - return E_FAIL; - } - - return NOERROR; -} - -// Compute the header size to allow space for us to write it at the end. -// -// 00000000 RIFF (00568BFE) 'WAVE' -// 0000000C fmt (00000010) -// 00000024 data (00568700) -// 0056872C -// - -HRESULT CWavDestFilter::StartStreaming() -{ - // leave space for the header - m_cbHeader = sizeof(RIFFLIST) + - sizeof(RIFFCHUNK) + - m_pInput->CurrentMediaType().FormatLength() + - sizeof(RIFFCHUNK); - - m_cbWavData = 0; - - return S_OK; -} - -HRESULT CWavDestFilter::StopStreaming() -{ - IStream* pStream; - if (m_pOutput->IsConnected() == FALSE) { - return E_FAIL; - } - - IPin* pDwnstrmInputPin = m_pOutput->GetConnected(); - - if (!pDwnstrmInputPin) { - return E_FAIL; - } - - HRESULT hr = ((IMemInputPin*) pDwnstrmInputPin)->QueryInterface(IID_PPV_ARGS(&pStream)); - if (SUCCEEDED(hr)) { - BYTE* pb = (BYTE*)_alloca(m_cbHeader); - - RIFFLIST* pRiffWave = (RIFFLIST*)pb; - RIFFCHUNK* pRiffFmt = (RIFFCHUNK*)(pRiffWave + 1); - RIFFCHUNK* pRiffData = (RIFFCHUNK*)(((BYTE*)(pRiffFmt + 1)) + m_pInput->CurrentMediaType().FormatLength()); - - pRiffData->fcc = FCC('data'); - pRiffData->cb = m_cbWavData; - - pRiffFmt->fcc = FCC('fmt '); - pRiffFmt->cb = m_pInput->CurrentMediaType().FormatLength(); - CopyMemory(pRiffFmt + 1, m_pInput->CurrentMediaType().Format(), pRiffFmt->cb); - - pRiffWave->fcc = FCC('RIFF'); - pRiffWave->cb = m_cbWavData + m_cbHeader - sizeof(RIFFCHUNK); - pRiffWave->fccListType = FCC('WAVE'); - - LARGE_INTEGER li; - ZeroMemory(&li, sizeof(li)); - - hr = pStream->Seek(li, STREAM_SEEK_SET, 0); - if (SUCCEEDED(hr)) { - hr = pStream->Write(pb, m_cbHeader, 0); - } - pStream->Release(); - } - - return hr; -} - -CWavDestOutputPin::CWavDestOutputPin(CTransformFilter* pFilter, HRESULT* phr) - : CTransformOutputPin(NAME("WavDest output pin"), pFilter, phr, L"Out") -{ -} - -STDMETHODIMP CWavDestOutputPin::EnumMediaTypes(IEnumMediaTypes** ppEnum) -{ - return CBaseOutputPin::EnumMediaTypes(ppEnum); -} - -HRESULT CWavDestOutputPin::CheckMediaType(const CMediaType* pmt) -{ - if (pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_WAVE) { - return S_OK; - } else { - return S_FALSE; - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include "BaseClasses/streams.h" +#include +#include "WavDest.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CWavDestFilter), WavDestName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {L"WavDest", &__uuidof(CWavDestFilter), CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CWavDestFilter +// + +CWavDestFilter::CWavDestFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CTransformFilter(NAME("WavDest filter"), pUnk, __uuidof(this)) + , m_cbWavData(0) + , m_cbHeader(0) +{ + if (CWavDestOutputPin* pOut = DEBUG_NEW CWavDestOutputPin(this, phr)) { + if (SUCCEEDED(*phr)) { + m_pOutput = pOut; + } else { + delete pOut; + } + } else { + *phr = E_OUTOFMEMORY; + return; + } + + if (CTransformInputPin* pIn = DEBUG_NEW CTransformInputPin(NAME("Transform input pin"), this, phr, L"In")) { + if (SUCCEEDED(*phr)) { + m_pInput = pIn; + } else { + delete pIn; + } + } else { + *phr = E_OUTOFMEMORY; + return; + } +} + +CWavDestFilter::~CWavDestFilter() +{ +} + +HRESULT CWavDestFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return CheckInputType(mtIn); +} + +HRESULT CWavDestFilter::Receive(IMediaSample* pSample) +{ + ULONG cbOld = m_cbWavData; + HRESULT hr = CTransformFilter::Receive(pSample); + + // don't update the count if Deliver() downstream fails. + if (hr != S_OK) { + m_cbWavData = cbOld; + } + + return hr; +} + +HRESULT CWavDestFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + REFERENCE_TIME rtStart, rtEnd; + + HRESULT hr = Copy(pIn, pOut); + if (FAILED(hr)) { + return hr; + } + + // Prepare it for writing + LONG lActual = pOut->GetActualDataLength(); + + if (m_cbWavData + m_cbHeader + lActual < m_cbWavData + m_cbHeader) { // overflow + return E_FAIL; + } + + rtStart = m_cbWavData + m_cbHeader; + rtEnd = rtStart + lActual; + m_cbWavData += lActual; + + EXECUTE_ASSERT(pOut->SetTime(&rtStart, &rtEnd) == S_OK); + + return S_OK; +} + +HRESULT CWavDestFilter::Copy(IMediaSample* pSource, IMediaSample* pDest) const +{ + BYTE* pSourceBuffer, * pDestBuffer; + long lSourceSize = pSource->GetActualDataLength(); + +#ifdef _DEBUG + long lDestSize = pDest->GetSize(); + ASSERT(lDestSize >= lSourceSize); +#endif + + if (FAILED(pSource->GetPointer(&pSourceBuffer)) || !pSourceBuffer) { + return E_FAIL; + } + if (FAILED(pDest->GetPointer(&pDestBuffer)) || !pDestBuffer) { + return E_FAIL; + } + + CopyMemory((PVOID)pDestBuffer, (PVOID)pSourceBuffer, lSourceSize); + + // Copy the sample times + + REFERENCE_TIME rtTimeStart, rtTimeEnd; + if (SUCCEEDED(pSource->GetTime(&rtTimeStart, &rtTimeEnd))) { + pDest->SetTime(&rtTimeStart, &rtTimeEnd); + } + + LONGLONG rtMediaStart, rtMediaEnd; + if (SUCCEEDED(pSource->GetMediaTime(&rtMediaStart, &rtMediaEnd))) { + pDest->SetMediaTime(&rtMediaStart, &rtMediaEnd); + } + + // Copy the media type + AM_MEDIA_TYPE* pMediaType; + if (SUCCEEDED(pSource->GetMediaType(&pMediaType)) && pMediaType) { + pDest->SetMediaType(pMediaType); + DeleteMediaType(pMediaType); + } + + // Copy the actual data length + long lDataLength = pSource->GetActualDataLength(); + pDest->SetActualDataLength(lDataLength); + + return NOERROR; +} + +HRESULT CWavDestFilter::CheckInputType(const CMediaType* mtIn) +{ + return mtIn->formattype == FORMAT_WaveFormatEx ? S_OK : S_FALSE; +} + +HRESULT CWavDestFilter::GetMediaType(int iPosition, CMediaType* pMediaType) +{ + ASSERT(iPosition == 0 || iPosition == 1); + + if (iPosition == 0) { + pMediaType->SetType(&MEDIATYPE_Stream); + pMediaType->SetSubtype(&MEDIASUBTYPE_WAVE); + return S_OK; + } + + return VFW_S_NO_MORE_ITEMS; +} + +HRESULT CWavDestFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = 1; + pProperties->cbAlign = 1; + + CComPtr pInAlloc; + ALLOCATOR_PROPERTIES InProps; + if (SUCCEEDED(hr = m_pInput->GetAllocator(&pInAlloc)) + && SUCCEEDED(hr = pInAlloc->GetProperties(&InProps))) { + pProperties->cbBuffer = InProps.cbBuffer; + } else { + return hr; + } + + ASSERT(pProperties->cbBuffer); + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + ASSERT(Actual.cBuffers == 1); + + if (pProperties->cBuffers > Actual.cBuffers + || pProperties->cbBuffer > Actual.cbBuffer) { + return E_FAIL; + } + + return NOERROR; +} + +// Compute the header size to allow space for us to write it at the end. +// +// 00000000 RIFF (00568BFE) 'WAVE' +// 0000000C fmt (00000010) +// 00000024 data (00568700) +// 0056872C +// + +HRESULT CWavDestFilter::StartStreaming() +{ + // leave space for the header + m_cbHeader = sizeof(RIFFLIST) + + sizeof(RIFFCHUNK) + + m_pInput->CurrentMediaType().FormatLength() + + sizeof(RIFFCHUNK); + + m_cbWavData = 0; + + return S_OK; +} + +HRESULT CWavDestFilter::StopStreaming() +{ + IStream* pStream; + if (m_pOutput->IsConnected() == FALSE) { + return E_FAIL; + } + + IPin* pDwnstrmInputPin = m_pOutput->GetConnected(); + + if (!pDwnstrmInputPin) { + return E_FAIL; + } + + HRESULT hr = ((IMemInputPin*) pDwnstrmInputPin)->QueryInterface(IID_PPV_ARGS(&pStream)); + if (SUCCEEDED(hr)) { + BYTE* pb = (BYTE*)_alloca(m_cbHeader); + + RIFFLIST* pRiffWave = (RIFFLIST*)pb; + RIFFCHUNK* pRiffFmt = (RIFFCHUNK*)(pRiffWave + 1); + RIFFCHUNK* pRiffData = (RIFFCHUNK*)(((BYTE*)(pRiffFmt + 1)) + m_pInput->CurrentMediaType().FormatLength()); + + pRiffData->fcc = FCC('data'); + pRiffData->cb = m_cbWavData; + + pRiffFmt->fcc = FCC('fmt '); + pRiffFmt->cb = m_pInput->CurrentMediaType().FormatLength(); + CopyMemory(pRiffFmt + 1, m_pInput->CurrentMediaType().Format(), pRiffFmt->cb); + + pRiffWave->fcc = FCC('RIFF'); + pRiffWave->cb = m_cbWavData + m_cbHeader - sizeof(RIFFCHUNK); + pRiffWave->fccListType = FCC('WAVE'); + + LARGE_INTEGER li; + ZeroMemory(&li, sizeof(li)); + + hr = pStream->Seek(li, STREAM_SEEK_SET, 0); + if (SUCCEEDED(hr)) { + hr = pStream->Write(pb, m_cbHeader, 0); + } + pStream->Release(); + } + + return hr; +} + +CWavDestOutputPin::CWavDestOutputPin(CTransformFilter* pFilter, HRESULT* phr) + : CTransformOutputPin(NAME("WavDest output pin"), pFilter, phr, L"Out") +{ +} + +STDMETHODIMP CWavDestOutputPin::EnumMediaTypes(IEnumMediaTypes** ppEnum) +{ + return CBaseOutputPin::EnumMediaTypes(ppEnum); +} + +HRESULT CWavDestOutputPin::CheckMediaType(const CMediaType* pmt) +{ + if (pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_WAVE) { + return S_OK; + } else { + return S_FALSE; + } +} diff --git a/src/filters/muxer/WavDest/WavDest.def b/src/filters/muxer/WavDest/WavDest.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/muxer/WavDest/WavDest.def +++ b/src/filters/muxer/WavDest/WavDest.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/muxer/WavDest/WavDest.h b/src/filters/muxer/WavDest/WavDest.h index 50267c0bd26..985ce1c5563 100644 --- a/src/filters/muxer/WavDest/WavDest.h +++ b/src/filters/muxer/WavDest/WavDest.h @@ -1,66 +1,66 @@ -/* - * (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 . - * - */ - -#pragma once - -#include - -#define WavDestName L"MPC WavDest" - -class CWavDestOutputPin : public CTransformOutputPin -{ -public: - CWavDestOutputPin(CTransformFilter* pFilter, HRESULT* phr); - - STDMETHODIMP EnumMediaTypes(IEnumMediaTypes** ppEnum); - HRESULT CheckMediaType(const CMediaType* pmt); -}; - -class __declspec(uuid("8685214E-4D32-4058-BE04-D01104F00B0C")) - CWavDestFilter : public CTransformFilter -{ -public: - CWavDestFilter(LPUNKNOWN pUnk, HRESULT* pHr); - ~CWavDestFilter(); - - DECLARE_IUNKNOWN; - - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT Receive(IMediaSample* pSample); - - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - - HRESULT StartStreaming(); - HRESULT StopStreaming(); - -private: - - HRESULT Copy(IMediaSample* pSource, IMediaSample* pDest) const; - HRESULT Transform(IMediaSample* pMediaSample); - HRESULT Transform(AM_MEDIA_TYPE* pType, const signed char ContrastLevel) const; - - ULONG m_cbWavData; - ULONG m_cbHeader; -}; +/* + * (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 . + * + */ + +#pragma once + +#include + +#define WavDestName L"MPC WavDest" + +class CWavDestOutputPin : public CTransformOutputPin +{ +public: + CWavDestOutputPin(CTransformFilter* pFilter, HRESULT* phr); + + STDMETHODIMP EnumMediaTypes(IEnumMediaTypes** ppEnum); + HRESULT CheckMediaType(const CMediaType* pmt); +}; + +class __declspec(uuid("8685214E-4D32-4058-BE04-D01104F00B0C")) + CWavDestFilter : public CTransformFilter +{ +public: + CWavDestFilter(LPUNKNOWN pUnk, HRESULT* pHr); + ~CWavDestFilter(); + + DECLARE_IUNKNOWN; + + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT Receive(IMediaSample* pSample); + + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + + HRESULT StartStreaming(); + HRESULT StopStreaming(); + +private: + + HRESULT Copy(IMediaSample* pSource, IMediaSample* pDest) const; + HRESULT Transform(IMediaSample* pMediaSample); + HRESULT Transform(AM_MEDIA_TYPE* pType, const signed char ContrastLevel) const; + + ULONG m_cbWavData; + ULONG m_cbHeader; +}; diff --git a/src/filters/muxer/WavDest/WavDest.rc b/src/filters/muxer/WavDest/WavDest.rc index d522de7f2fe..709a122ad18 100644 --- a/src/filters/muxer/WavDest/WavDest.rc +++ b/src/filters/muxer/WavDest/WavDest.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "WavDest" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "WavDest" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "WavDest.ax" - VALUE "ProductName", "WavDest" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "WavDest" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "WavDest" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "WavDest.ax" + VALUE "ProductName", "WavDest" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/muxer/WavDest/WavDest.vcxproj b/src/filters/muxer/WavDest/WavDest.vcxproj index c2dbb38e4eb..7552a4fb863 100644 --- a/src/filters/muxer/WavDest/WavDest.vcxproj +++ b/src/filters/muxer/WavDest/WavDest.vcxproj @@ -1,114 +1,114 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {EB202B68-8029-4985-B914-E94B44D2E230} - WavDest - MFCProj - WavDest - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - WavDest.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - Create - - - - - - - - - true - - - - - - - true - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {EB202B68-8029-4985-B914-E94B44D2E230} + WavDest + MFCProj + WavDest + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + WavDest.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + Create + + + + + + + + + true + + + + + + + true + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/muxer/WavDest/WavDest.vcxproj.filters b/src/filters/muxer/WavDest/WavDest.vcxproj.filters index 1bc74cb9ced..d6dec716288 100644 --- a/src/filters/muxer/WavDest/WavDest.vcxproj.filters +++ b/src/filters/muxer/WavDest/WavDest.vcxproj.filters @@ -1,45 +1,45 @@ - - - - - {4e8bc353-99a5-4a8a-8345-30fa00f8868c} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {352161b2-c379-4cb2-a6ea-2e55002639bc} - h;hpp;hxx;hm;inl;inc - - - {6939da75-f71e-49a0-a70e-feb331e5a56a} - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {4e8bc353-99a5-4a8a-8345-30fa00f8868c} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {352161b2-c379-4cb2-a6ea-2e55002639bc} + h;hpp;hxx;hm;inl;inc + + + {6939da75-f71e-49a0-a70e-feb331e5a56a} + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/muxer/WavDest/resource.h b/src/filters/muxer/WavDest/resource.h index 513732d0a97..b1483d5bbe1 100644 --- a/src/filters/muxer/WavDest/resource.h +++ b/src/filters/muxer/WavDest/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by WavDest.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by WavDest.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/muxer/WavDest/stdafx.cpp b/src/filters/muxer/WavDest/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/muxer/WavDest/stdafx.cpp +++ b/src/filters/muxer/WavDest/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/muxer/WavDest/stdafx.h b/src/filters/muxer/WavDest/stdafx.h index 844252f231b..505867e46c6 100644 --- a/src/filters/muxer/WavDest/stdafx.h +++ b/src/filters/muxer/WavDest/stdafx.h @@ -1,31 +1,31 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components diff --git a/src/filters/parser/BaseSplitter/AsyncReader.cpp b/src/filters/parser/BaseSplitter/AsyncReader.cpp index ca950c119ca..128072c8a8d 100644 --- a/src/filters/parser/BaseSplitter/AsyncReader.cpp +++ b/src/filters/parser/BaseSplitter/AsyncReader.cpp @@ -1,240 +1,240 @@ -/* - * (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 . - * - */ - - -#include "stdafx.h" -#include "AsyncReader.h" -#include -#include -#include "../../../DSUtil/DSUtil.h" - -// -// CAsyncFileReader -// - -CAsyncFileReader::CAsyncFileReader(CString fn, HRESULT& hr) - : CUnknown(NAME("CAsyncFileReader"), nullptr, &hr) - , m_len(ULONGLONG_MAX) - , m_hBreakEvent(nullptr) - , m_lOsError(0) -{ - hr = Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL; - if (SUCCEEDED(hr)) { - m_len = GetLength(); - } -} - -CAsyncFileReader::CAsyncFileReader(CAtlList& Items, HRESULT& hr) - : CUnknown(NAME("CAsyncFileReader"), nullptr, &hr) - , m_len(ULONGLONG_MAX) - , m_hBreakEvent(nullptr) - , m_lOsError(0) -{ - hr = OpenFiles(Items, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL; - if (SUCCEEDED(hr)) { - m_len = GetLength(); - } -} - -STDMETHODIMP CAsyncFileReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IAsyncReader) - QI(ISyncReader) - QI(IFileHandle) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IAsyncReader - -STDMETHODIMP CAsyncFileReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer) -{ - do { - try { - if ((ULONGLONG)llPosition + lLength > GetLength()) { - return E_FAIL; // strange, but the Seek below can return llPosition even if the file is not that big (?) - } - if ((ULONGLONG)llPosition != Seek(llPosition, begin)) { - return E_FAIL; - } - if ((UINT)lLength < Read(pBuffer, lLength)) { - return E_FAIL; - } - -#if 0 // def DEBUG - static __int64 s_total = 0, s_laststoppos = 0; - s_total += lLength; - if (s_laststoppos > llPosition) { - TRACE(_T("[%I64d - %I64d] %d (%I64d)\n"), llPosition, llPosition + lLength, lLength, s_total); - } - s_laststoppos = llPosition + lLength; -#endif - - return S_OK; - } catch (CFileException* e) { - m_lOsError = e->m_lOsError; - e->Delete(); - Sleep(1); - CString fn = m_strFileName; - try { - Close(); - } catch (CFileException* fe) { - fe->Delete(); - } - try { - Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan); - } catch (CFileException* fe) { - fe->Delete(); - } - m_strFileName = fn; - } - } while (m_hBreakEvent && WaitForSingleObject(m_hBreakEvent, 0) == WAIT_TIMEOUT); - - return E_FAIL; -} - -STDMETHODIMP CAsyncFileReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable) -{ - LONGLONG len = (m_len != ULONGLONG_MAX) ? m_len : GetLength(); - if (pTotal) { - *pTotal = len; - } - if (pAvailable) { - *pAvailable = len; - } - return S_OK; -} - -// IFileHandle - -STDMETHODIMP_(HANDLE) CAsyncFileReader::GetFileHandle() -{ - return m_hFile; -} - -STDMETHODIMP_(LPCTSTR) CAsyncFileReader::GetFileName() -{ - return m_nCurPart != -1 ? m_strFiles[m_nCurPart] : m_strFiles[0]; -} - -// -// CAsyncUrlReader -// - -CAsyncUrlReader::CAsyncUrlReader(CString url, HRESULT& hr) - : CAsyncFileReader(url, hr) -{ - if (SUCCEEDED(hr)) { - return; - } - - m_url = url; - - if (CAMThread::Create()) { - CallWorker(CMD_INIT); - } - - hr = Open(m_fn, modeRead | shareDenyRead | typeBinary | osSequentialScan) ? S_OK : E_FAIL; - m_len = ULONGLONG_MAX; // force GetLength() return actual length always -} - -CAsyncUrlReader::~CAsyncUrlReader() -{ - if (ThreadExists()) { - CallWorker(CMD_EXIT); - } - - if (!m_fn.IsEmpty()) { - CMultiFiles::Close(); - DeleteFile(m_fn); - } -} - -// IAsyncReader - -STDMETHODIMP CAsyncUrlReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable) -{ - if (pTotal) { - *pTotal = 0; - } - return __super::Length(nullptr, pAvailable); -} - -// CAMThread - -DWORD CAsyncUrlReader::ThreadProc() -{ - AfxSocketInit(nullptr); - - DWORD cmd = GetRequest(); - if (cmd != CMD_INIT) { - Reply((DWORD)E_FAIL); - return DWORD_ERROR; - } - - try { - CInternetSession is; - CAutoPtr fin(is.OpenURL(m_url, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_CACHE_WRITE)); - - TCHAR path[MAX_PATH], fn[MAX_PATH]; - CFile fout; - if (GetTempPath(MAX_PATH, path) && GetTempFileName(path, _T("mpc_http"), 0, fn) - && fout.Open(fn, modeCreate | modeWrite | shareDenyWrite | typeBinary)) { - m_fn = fn; - - char buff[1024]; - int len = fin->Read(buff, sizeof(buff)); - if (len > 0) { - fout.Write(buff, len); - } - - Reply(S_OK); - - while (!CheckRequest(&cmd)) { - int len2 = fin->Read(buff, sizeof(buff)); - if (len2 > 0) { - fout.Write(buff, len2); - } - } - } else { - Reply((DWORD)E_FAIL); - } - - fin->Close(); // must close it because the destructor doesn't seem to do it and we will get an exception when "is" is destroying - } catch (CInternetException* ie) { - ie->Delete(); - Reply((DWORD)E_FAIL); - } - - // - - cmd = GetRequest(); - ASSERT(cmd == CMD_EXIT); - Reply(S_OK); - - // - - m_hThread = nullptr; - - return S_OK; -} +/* + * (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 . + * + */ + + +#include "stdafx.h" +#include "AsyncReader.h" +#include +#include +#include "../../../DSUtil/DSUtil.h" + +// +// CAsyncFileReader +// + +CAsyncFileReader::CAsyncFileReader(CString fn, HRESULT& hr) + : CUnknown(NAME("CAsyncFileReader"), nullptr, &hr) + , m_len(ULONGLONG_MAX) + , m_hBreakEvent(nullptr) + , m_lOsError(0) +{ + hr = Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) { + m_len = GetLength(); + } +} + +CAsyncFileReader::CAsyncFileReader(CAtlList& Items, HRESULT& hr) + : CUnknown(NAME("CAsyncFileReader"), nullptr, &hr) + , m_len(ULONGLONG_MAX) + , m_hBreakEvent(nullptr) + , m_lOsError(0) +{ + hr = OpenFiles(Items, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) { + m_len = GetLength(); + } +} + +STDMETHODIMP CAsyncFileReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IAsyncReader) + QI(ISyncReader) + QI(IFileHandle) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IAsyncReader + +STDMETHODIMP CAsyncFileReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer) +{ + do { + try { + if ((ULONGLONG)llPosition + lLength > GetLength()) { + return E_FAIL; // strange, but the Seek below can return llPosition even if the file is not that big (?) + } + if ((ULONGLONG)llPosition != Seek(llPosition, begin)) { + return E_FAIL; + } + if ((UINT)lLength < Read(pBuffer, lLength)) { + return E_FAIL; + } + +#if 0 // def DEBUG + static __int64 s_total = 0, s_laststoppos = 0; + s_total += lLength; + if (s_laststoppos > llPosition) { + TRACE(_T("[%I64d - %I64d] %d (%I64d)\n"), llPosition, llPosition + lLength, lLength, s_total); + } + s_laststoppos = llPosition + lLength; +#endif + + return S_OK; + } catch (CFileException* e) { + m_lOsError = e->m_lOsError; + e->Delete(); + Sleep(1); + CString fn = m_strFileName; + try { + Close(); + } catch (CFileException* fe) { + fe->Delete(); + } + try { + Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan); + } catch (CFileException* fe) { + fe->Delete(); + } + m_strFileName = fn; + } + } while (m_hBreakEvent && WaitForSingleObject(m_hBreakEvent, 0) == WAIT_TIMEOUT); + + return E_FAIL; +} + +STDMETHODIMP CAsyncFileReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable) +{ + LONGLONG len = (m_len != ULONGLONG_MAX) ? m_len : GetLength(); + if (pTotal) { + *pTotal = len; + } + if (pAvailable) { + *pAvailable = len; + } + return S_OK; +} + +// IFileHandle + +STDMETHODIMP_(HANDLE) CAsyncFileReader::GetFileHandle() +{ + return m_hFile; +} + +STDMETHODIMP_(LPCTSTR) CAsyncFileReader::GetFileName() +{ + return m_nCurPart != -1 ? m_strFiles[m_nCurPart] : m_strFiles[0]; +} + +// +// CAsyncUrlReader +// + +CAsyncUrlReader::CAsyncUrlReader(CString url, HRESULT& hr) + : CAsyncFileReader(url, hr) +{ + if (SUCCEEDED(hr)) { + return; + } + + m_url = url; + + if (CAMThread::Create()) { + CallWorker(CMD_INIT); + } + + hr = Open(m_fn, modeRead | shareDenyRead | typeBinary | osSequentialScan) ? S_OK : E_FAIL; + m_len = ULONGLONG_MAX; // force GetLength() return actual length always +} + +CAsyncUrlReader::~CAsyncUrlReader() +{ + if (ThreadExists()) { + CallWorker(CMD_EXIT); + } + + if (!m_fn.IsEmpty()) { + CMultiFiles::Close(); + DeleteFile(m_fn); + } +} + +// IAsyncReader + +STDMETHODIMP CAsyncUrlReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable) +{ + if (pTotal) { + *pTotal = 0; + } + return __super::Length(nullptr, pAvailable); +} + +// CAMThread + +DWORD CAsyncUrlReader::ThreadProc() +{ + AfxSocketInit(nullptr); + + DWORD cmd = GetRequest(); + if (cmd != CMD_INIT) { + Reply((DWORD)E_FAIL); + return DWORD_ERROR; + } + + try { + CInternetSession is; + CAutoPtr fin(is.OpenURL(m_url, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_CACHE_WRITE)); + + TCHAR path[MAX_PATH], fn[MAX_PATH]; + CFile fout; + if (GetTempPath(MAX_PATH, path) && GetTempFileName(path, _T("mpc_http"), 0, fn) + && fout.Open(fn, modeCreate | modeWrite | shareDenyWrite | typeBinary)) { + m_fn = fn; + + char buff[1024]; + int len = fin->Read(buff, sizeof(buff)); + if (len > 0) { + fout.Write(buff, len); + } + + Reply(S_OK); + + while (!CheckRequest(&cmd)) { + int len2 = fin->Read(buff, sizeof(buff)); + if (len2 > 0) { + fout.Write(buff, len2); + } + } + } else { + Reply((DWORD)E_FAIL); + } + + fin->Close(); // must close it because the destructor doesn't seem to do it and we will get an exception when "is" is destroying + } catch (CInternetException* ie) { + ie->Delete(); + Reply((DWORD)E_FAIL); + } + + // + + cmd = GetRequest(); + ASSERT(cmd == CMD_EXIT); + Reply(S_OK); + + // + + m_hThread = nullptr; + + return S_OK; +} diff --git a/src/filters/parser/BaseSplitter/AsyncReader.h b/src/filters/parser/BaseSplitter/AsyncReader.h index e171589ed45..e1ee7d8c43b 100644 --- a/src/filters/parser/BaseSplitter/AsyncReader.h +++ b/src/filters/parser/BaseSplitter/AsyncReader.h @@ -1,104 +1,104 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include "MultiFiles.h" - -interface __declspec(uuid("6DDB4EE7-45A0-4459-A508-BD77B32C91B2")) - ISyncReader : - public IUnknown -{ - STDMETHOD_(void, SetBreakEvent)(HANDLE hBreakEvent) PURE; - STDMETHOD_(bool, HasErrors)() PURE; - STDMETHOD_(void, ClearErrors)() PURE; - STDMETHOD_(void, SetPTSOffset)(REFERENCE_TIME* rtPTSOffset) PURE; -}; - -interface __declspec(uuid("7D55F67A-826E-40B9-8A7D-3DF0CBBD272D")) - IFileHandle : - public IUnknown -{ - STDMETHOD_(HANDLE, GetFileHandle)() PURE; - STDMETHOD_(LPCTSTR, GetFileName)() PURE; -}; - -class CAsyncFileReader : public CUnknown, public CMultiFiles, public IAsyncReader, public ISyncReader, public IFileHandle -{ -protected: - ULONGLONG m_len; - HANDLE m_hBreakEvent; - LONG m_lOsError; // CFileException::m_lOsError - -public: - CAsyncFileReader(CString fn, HRESULT& hr); - CAsyncFileReader(CAtlList& Items, HRESULT& hr); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IAsyncReader - - STDMETHODIMP RequestAllocator(IMemAllocator* pPreferred, ALLOCATOR_PROPERTIES* pProps, IMemAllocator** ppActual) { - return E_NOTIMPL; - } - STDMETHODIMP Request(IMediaSample* pSample, DWORD_PTR dwUser) { - return E_NOTIMPL; - } - STDMETHODIMP WaitForNext(DWORD dwTimeout, IMediaSample** ppSample, DWORD_PTR* pdwUser) { - return E_NOTIMPL; - } - STDMETHODIMP SyncReadAligned(IMediaSample* pSample) { return E_NOTIMPL; } - STDMETHODIMP SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer); - STDMETHODIMP Length(LONGLONG* pTotal, LONGLONG* pAvailable); - STDMETHODIMP BeginFlush() { return E_NOTIMPL; } - STDMETHODIMP EndFlush() { return E_NOTIMPL; } - - // ISyncReader - - STDMETHODIMP_(void) SetBreakEvent(HANDLE hBreakEvent) { m_hBreakEvent = hBreakEvent; } - STDMETHODIMP_(bool) HasErrors() { return m_lOsError != 0; } - STDMETHODIMP_(void) ClearErrors() { m_lOsError = 0; } - STDMETHODIMP_(void) SetPTSOffset(REFERENCE_TIME* rtPTSOffset) { m_pCurrentPTSOffset = rtPTSOffset; }; - - // IFileHandle - - STDMETHODIMP_(HANDLE) GetFileHandle(); - STDMETHODIMP_(LPCTSTR) GetFileName(); - -}; - -class CAsyncUrlReader : public CAsyncFileReader, protected CAMThread -{ - CString m_url, m_fn; - -protected: - enum { CMD_EXIT, CMD_INIT }; - DWORD ThreadProc(); - -public: - CAsyncUrlReader(CString url, HRESULT& hr); - virtual ~CAsyncUrlReader(); - - // IAsyncReader - - STDMETHODIMP Length(LONGLONG* pTotal, LONGLONG* pAvailable); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include "MultiFiles.h" + +interface __declspec(uuid("6DDB4EE7-45A0-4459-A508-BD77B32C91B2")) + ISyncReader : + public IUnknown +{ + STDMETHOD_(void, SetBreakEvent)(HANDLE hBreakEvent) PURE; + STDMETHOD_(bool, HasErrors)() PURE; + STDMETHOD_(void, ClearErrors)() PURE; + STDMETHOD_(void, SetPTSOffset)(REFERENCE_TIME* rtPTSOffset) PURE; +}; + +interface __declspec(uuid("7D55F67A-826E-40B9-8A7D-3DF0CBBD272D")) + IFileHandle : + public IUnknown +{ + STDMETHOD_(HANDLE, GetFileHandle)() PURE; + STDMETHOD_(LPCTSTR, GetFileName)() PURE; +}; + +class CAsyncFileReader : public CUnknown, public CMultiFiles, public IAsyncReader, public ISyncReader, public IFileHandle +{ +protected: + ULONGLONG m_len; + HANDLE m_hBreakEvent; + LONG m_lOsError; // CFileException::m_lOsError + +public: + CAsyncFileReader(CString fn, HRESULT& hr); + CAsyncFileReader(CAtlList& Items, HRESULT& hr); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IAsyncReader + + STDMETHODIMP RequestAllocator(IMemAllocator* pPreferred, ALLOCATOR_PROPERTIES* pProps, IMemAllocator** ppActual) { + return E_NOTIMPL; + } + STDMETHODIMP Request(IMediaSample* pSample, DWORD_PTR dwUser) { + return E_NOTIMPL; + } + STDMETHODIMP WaitForNext(DWORD dwTimeout, IMediaSample** ppSample, DWORD_PTR* pdwUser) { + return E_NOTIMPL; + } + STDMETHODIMP SyncReadAligned(IMediaSample* pSample) { return E_NOTIMPL; } + STDMETHODIMP SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer); + STDMETHODIMP Length(LONGLONG* pTotal, LONGLONG* pAvailable); + STDMETHODIMP BeginFlush() { return E_NOTIMPL; } + STDMETHODIMP EndFlush() { return E_NOTIMPL; } + + // ISyncReader + + STDMETHODIMP_(void) SetBreakEvent(HANDLE hBreakEvent) { m_hBreakEvent = hBreakEvent; } + STDMETHODIMP_(bool) HasErrors() { return m_lOsError != 0; } + STDMETHODIMP_(void) ClearErrors() { m_lOsError = 0; } + STDMETHODIMP_(void) SetPTSOffset(REFERENCE_TIME* rtPTSOffset) { m_pCurrentPTSOffset = rtPTSOffset; }; + + // IFileHandle + + STDMETHODIMP_(HANDLE) GetFileHandle(); + STDMETHODIMP_(LPCTSTR) GetFileName(); + +}; + +class CAsyncUrlReader : public CAsyncFileReader, protected CAMThread +{ + CString m_url, m_fn; + +protected: + enum { CMD_EXIT, CMD_INIT }; + DWORD ThreadProc(); + +public: + CAsyncUrlReader(CString url, HRESULT& hr); + virtual ~CAsyncUrlReader(); + + // IAsyncReader + + STDMETHODIMP Length(LONGLONG* pTotal, LONGLONG* pAvailable); +}; diff --git a/src/filters/parser/BaseSplitter/BaseSplitter.cpp b/src/filters/parser/BaseSplitter/BaseSplitter.cpp index 656c464fdd7..f2644dc051a 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitter.cpp +++ b/src/filters/parser/BaseSplitter/BaseSplitter.cpp @@ -1,1636 +1,1636 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "../../../DSUtil/DSUtil.h" -#include "moreuuids.h" -#include "../../switcher/AudioSwitcher/AudioSwitcher.h" -#include "BaseSplitter.h" -#include - - -// -// CPacketQueue2 -// - -CPacketQueue2::CPacketQueue2() : m_size(0) -{ -} - -void CPacketQueue2::Add(CAutoPtr p) -{ - CAutoLock cAutoLock(this); - - if (p) { - m_size += p->GetDataSize(); - - if (p->bAppendable && !p->bDiscontinuity && !p->pmt - && p->rtStart == Packet::INVALID_TIME - && !IsEmpty() && GetTail()->rtStart != Packet::INVALID_TIME) { - Packet* tail = GetTail(); - size_t oldsize = tail->GetCount(); - size_t newsize = tail->GetCount() + p->GetCount(); - tail->SetCount(newsize, std::max(1024, (int)newsize)); // doubles the reserved buffer size - memcpy(tail->GetData() + oldsize, p->GetData(), p->GetCount()); - /* - GetTail()->Append(*p); // too slow - */ - return; - } - } - - AddTail(p); -} - -CAutoPtr CPacketQueue2::Remove() -{ - CAutoLock cAutoLock(this); - ASSERT(__super::GetCount() > 0); - CAutoPtr p(RemoveHead().Detach()); - if (p) { - m_size -= p->GetDataSize(); - } - return p; -} - -void CPacketQueue2::RemoveAll() -{ - CAutoLock cAutoLock(this); - m_size = 0; - __super::RemoveAll(); -} - -int CPacketQueue2::GetCount() -{ - CAutoLock cAutoLock(this); - return (int)__super::GetCount(); -} - -int CPacketQueue2::GetSize() -{ - CAutoLock cAutoLock(this); - return m_size; -} - -// -// CBaseSplitterInputPin -// - -CBaseSplitterInputPin::CBaseSplitterInputPin(LPCTSTR pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT) -{ -} - -CBaseSplitterInputPin::~CBaseSplitterInputPin() -{ -} - -HRESULT CBaseSplitterInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader) -{ - CheckPointer(ppAsyncReader, E_POINTER); - *ppAsyncReader = nullptr; - CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED); - (*ppAsyncReader = m_pAsyncReader)->AddRef(); - return S_OK; -} - -STDMETHODIMP CBaseSplitterInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CBaseSplitterInputPin::CheckMediaType(const CMediaType* pmt) -{ - return S_OK; - /* - return pmt->majortype == MEDIATYPE_Stream - ? S_OK - : E_INVALIDARG; - */ -} - -HRESULT CBaseSplitterInputPin::CheckConnect(IPin* pPin) -{ - HRESULT hr; - if (FAILED(hr = __super::CheckConnect(pPin))) { - return hr; - } - - return CComQIPtr(pPin) ? S_OK : E_NOINTERFACE; -} - -HRESULT CBaseSplitterInputPin::BreakConnect() -{ - HRESULT hr; - - if (FAILED(hr = __super::BreakConnect())) { - return hr; - } - - if (FAILED(hr = (static_cast(m_pFilter))->BreakConnect(PINDIR_INPUT, this))) { - return hr; - } - - m_pAsyncReader.Release(); - - return S_OK; -} - -HRESULT CBaseSplitterInputPin::CompleteConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CompleteConnect(pPin))) { - return hr; - } - - CheckPointer(pPin, E_POINTER); - m_pAsyncReader = pPin; - CheckPointer(m_pAsyncReader, E_NOINTERFACE); - - if (FAILED(hr = (static_cast(m_pFilter))->CompleteConnect(PINDIR_INPUT, this))) { - return hr; - } - - return S_OK; -} - -STDMETHODIMP CBaseSplitterInputPin::BeginFlush() -{ - return E_UNEXPECTED; -} - -STDMETHODIMP CBaseSplitterInputPin::EndFlush() -{ - return E_UNEXPECTED; -} - -// -// CBaseSplitterOutputPin -// - -CBaseSplitterOutputPin::CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers, int QueueMaxPackets) - : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName) - , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it - , m_fFlushing(false) - , m_fFlushed(false) - , m_eEndFlush(TRUE) - , m_QueueMaxPackets(QueueMaxPackets) - , m_rtStart(0) -{ - m_mts.Copy(mts); - m_nBuffers = std::max(nBuffers, 1); -} - -CBaseSplitterOutputPin::CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers, int QueueMaxPackets) - : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName) - , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it - , m_fFlushing(false) - , m_fFlushed(false) - , m_eEndFlush(TRUE) - , m_QueueMaxPackets(QueueMaxPackets) - , m_rtStart(0) -{ - m_nBuffers = std::max(nBuffers, 1); -} - -CBaseSplitterOutputPin::~CBaseSplitterOutputPin() -{ -} - -STDMETHODIMP CBaseSplitterOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - // riid == __uuidof(IMediaSeeking) ? m_pFilter->QueryInterface(riid, ppv) : - QI(IMediaSeeking) - QI(IPropertyBag) - QI(IPropertyBag2) - QI(IDSMPropertyBag) - QI(IBitRateInfo) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CBaseSplitterOutputPin::SetName(LPCWSTR pName) -{ - CheckPointer(pName, E_POINTER); - if (m_pName) { - delete [] m_pName; - } - m_pName = DEBUG_NEW WCHAR[wcslen(pName) + 1]; - CheckPointer(m_pName, E_OUTOFMEMORY); - wcscpy_s(m_pName, wcslen(pName) + 1, pName); - return S_OK; -} - -HRESULT CBaseSplitterOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = std::max(pProperties->cBuffers, m_nBuffers); - pProperties->cbBuffer = std::max((long)m_mt.lSampleSize, 1l); - - // TODO: is this still needed ? - if (m_mt.subtype == MEDIASUBTYPE_Vorbis && m_mt.formattype == FORMAT_VorbisFormat) { - // oh great, the oggds vorbis decoder assumes there will be two at least, stupid thing... - pProperties->cBuffers = std::max(pProperties->cBuffers, 2l); - } - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CBaseSplitterOutputPin::CheckMediaType(const CMediaType* pmt) -{ - for (size_t i = 0; i < m_mts.GetCount(); i++) { - if (*pmt == m_mts[i]) { - return S_OK; - } - } - - return E_INVALIDARG; -} - -HRESULT CBaseSplitterOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CAutoLock cAutoLock(m_pLock); - - if (iPosition < 0) { - return E_INVALIDARG; - } - if ((size_t)iPosition >= m_mts.GetCount()) { - return VFW_S_NO_MORE_ITEMS; - } - - *pmt = m_mts[iPosition]; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} - -// - -HRESULT CBaseSplitterOutputPin::Active() -{ - CAutoLock cAutoLock(m_pLock); - - if (m_Connected) { - Create(); - } - - return __super::Active(); -} - -HRESULT CBaseSplitterOutputPin::Inactive() -{ - CAutoLock cAutoLock(m_pLock); - - if (ThreadExists()) { - CallWorker(CMD_EXIT); - } - - return __super::Inactive(); -} - -HRESULT CBaseSplitterOutputPin::DeliverBeginFlush() -{ - m_eEndFlush.Reset(); - m_fFlushed = false; - m_fFlushing = true; - m_hrDeliver = S_FALSE; - m_queue.RemoveAll(); - HRESULT hr = IsConnected() ? GetConnected()->BeginFlush() : S_OK; - if (S_OK != hr) { - m_eEndFlush.Set(); - } - return hr; -} - -HRESULT CBaseSplitterOutputPin::DeliverEndFlush() -{ - if (!ThreadExists()) { - return S_FALSE; - } - HRESULT hr = IsConnected() ? GetConnected()->EndFlush() : S_OK; - m_hrDeliver = S_OK; - m_fFlushing = false; - m_fFlushed = true; - m_eEndFlush.Set(); - return hr; -} - -HRESULT CBaseSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - m_BitRate.rtLastDeliverTime = Packet::INVALID_TIME; - if (m_fFlushing) { - return S_FALSE; - } - m_rtStart = tStart; - if (!ThreadExists()) { - return S_FALSE; - } - HRESULT hr = __super::DeliverNewSegment(tStart, tStop, dRate); - if (S_OK != hr) { - return hr; - } - MakeISCRHappy(); - return hr; -} - -int CBaseSplitterOutputPin::QueueCount() -{ - return m_queue.GetCount(); -} - -int CBaseSplitterOutputPin::QueueSize() -{ - return m_queue.GetSize(); -} - -HRESULT CBaseSplitterOutputPin::QueueEndOfStream() -{ - CAutoPtr p; - return QueuePacket(p); // NULL means EndOfStream -} - -HRESULT CBaseSplitterOutputPin::QueuePacket(CAutoPtr p) -{ - if (!ThreadExists()) { - return S_FALSE; - } - - while (S_OK == m_hrDeliver - && ((m_queue.GetCount() > (m_QueueMaxPackets * 2) || m_queue.GetSize() > (MAXPACKETSIZE * 3 / 2)) - || ((m_queue.GetCount() > m_QueueMaxPackets || m_queue.GetSize() > MAXPACKETSIZE) && !(static_cast(m_pFilter))->IsAnyPinDrying()))) { - Sleep(10); - } - - if (S_OK != m_hrDeliver) { - return m_hrDeliver; - } - - m_queue.Add(p); - - return m_hrDeliver; -} - -bool CBaseSplitterOutputPin::IsDiscontinuous() -{ - return m_mt.majortype == MEDIATYPE_Text - || m_mt.majortype == MEDIATYPE_ScriptCommand - || m_mt.majortype == MEDIATYPE_Subtitle - || m_mt.subtype == MEDIASUBTYPE_DVD_SUBPICTURE - || m_mt.subtype == MEDIASUBTYPE_CVD_SUBPICTURE - || m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE; -} - -bool CBaseSplitterOutputPin::IsActive() -{ - CComPtr pPin = this; - do { - CComPtr pPinTo; - CComQIPtr pSSIP; - if (S_OK == pPin->ConnectedTo(&pPinTo) && (pSSIP = pPinTo) && !pSSIP->IsActive()) { - return false; - } - pPin = GetFirstPin(GetFilterFromPin(pPinTo), PINDIR_OUTPUT); - } while (pPin); - - return true; -} - -DWORD CBaseSplitterOutputPin::ThreadProc() -{ - SetThreadName(DWORD(-1), "CBaseSplitterOutputPin"); - m_hrDeliver = S_OK; - m_fFlushing = m_fFlushed = false; - m_eEndFlush.Set(); - - // fix for Microsoft DTV-DVD Video Decoder - video freeze after STOP/PLAY - bool iHaaliRenderConnect = false; - CComPtr pPinTo = this, pTmp; - while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { - pTmp = nullptr; - CComPtr pBF = GetFilterFromPin(pPinTo); - if (GetCLSID(pBF) == CLSID_DXR) { // Haali Renderer - iHaaliRenderConnect = true; - break; - } - pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); - } - if (IsConnected() && !iHaaliRenderConnect) { - GetConnected()->BeginFlush(); - GetConnected()->EndFlush(); - } - - for (;;) { - Sleep(1); - - DWORD cmd; - if (CheckRequest(&cmd)) { - m_hThread = nullptr; - cmd = GetRequest(); - Reply(S_OK); - ASSERT(cmd == CMD_EXIT); - return 0; - } - - int cnt = 0; - do { - CAutoPtr p; - - { - CAutoLock cAutoLock(&m_queue); - if ((cnt = m_queue.GetCount()) > 0) { - p.Attach(m_queue.Remove().Detach()); - } - } - - if (S_OK == m_hrDeliver && cnt > 0) { - ASSERT(!m_fFlushing); - - m_fFlushed = false; - - // flushing can still start here, to release a blocked deliver call - - HRESULT hr = p - ? DeliverPacket(p) - : DeliverEndOfStream(); - - m_eEndFlush.Wait(); // .. so we have to wait until it is done - - if (hr != S_OK && !m_fFlushed) { // and only report the error in m_hrDeliver if we didn't flush the stream - // CAutoLock cAutoLock(&m_csQueueLock); - m_hrDeliver = hr; - break; - } - } - } while (--cnt > 0); - } -} - -HRESULT CBaseSplitterOutputPin::DeliverPacket(CAutoPtr p) -{ - HRESULT hr; - - long nBytes = (long)p->GetCount(); - - if (nBytes == 0) { - return S_OK; - } - - m_BitRate.nBytesSinceLastDeliverTime += nBytes; - - if (p->rtStart != Packet::INVALID_TIME) { - if (m_BitRate.rtLastDeliverTime == Packet::INVALID_TIME) { - m_BitRate.rtLastDeliverTime = p->rtStart; - m_BitRate.nBytesSinceLastDeliverTime = 0; - } - - if (m_BitRate.rtLastDeliverTime + 10000000 < p->rtStart) { - REFERENCE_TIME rtDiff = p->rtStart - m_BitRate.rtLastDeliverTime; - - double dSecs, dBits; - - dSecs = rtDiff / 10000000.0; - dBits = 8.0 * m_BitRate.nBytesSinceLastDeliverTime; - m_BitRate.nCurrentBitRate = (DWORD)(dBits / dSecs); - - m_BitRate.rtTotalTimeDelivered += rtDiff; - m_BitRate.nTotalBytesDelivered += m_BitRate.nBytesSinceLastDeliverTime; - - dSecs = m_BitRate.rtTotalTimeDelivered / 10000000.0; - dBits = 8.0 * m_BitRate.nTotalBytesDelivered; - m_BitRate.nAverageBitRate = (DWORD)(dBits / dSecs); - - m_BitRate.rtLastDeliverTime = p->rtStart; - m_BitRate.nBytesSinceLastDeliverTime = 0; - /* - TRACE(_T("[%d] c: %d kbps, a: %d kbps\n"), - p->TrackNumber, - (m_brs.nCurrentBitRate+500)/1000, - (m_brs.nAverageBitRate+500)/1000); - */ - } - - double dRate = 1.0; - if (SUCCEEDED((static_cast(m_pFilter))->GetRate(&dRate))) { - p->rtStart = (REFERENCE_TIME)((double)p->rtStart / dRate); - p->rtStop = (REFERENCE_TIME)((double)p->rtStop / dRate); - } - } - - do { - CComPtr pSample; - if (S_OK != (hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0))) { - break; - } - - if (nBytes > pSample->GetSize()) { - pSample.Release(); - - ALLOCATOR_PROPERTIES props, actual; - if (S_OK != (hr = m_pAllocator->GetProperties(&props))) { - break; - } - props.cbBuffer = nBytes * 3 / 2; - - if (props.cBuffers > 1) { - if (S_OK != (hr = __super::DeliverBeginFlush())) { - break; - } - if (S_OK != (hr = __super::DeliverEndFlush())) { - break; - } - } - - if (S_OK != (hr = m_pAllocator->Decommit())) { - break; - } - if (S_OK != (hr = m_pAllocator->SetProperties(&props, &actual))) { - break; - } - if (S_OK != (hr = m_pAllocator->Commit())) { - break; - } - if (S_OK != (hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0))) { - break; - } - } - - if (p->pmt) { - pSample->SetMediaType(p->pmt); - p->bDiscontinuity = true; - - CAutoLock cAutoLock(m_pLock); - m_mts.RemoveAll(); - m_mts.Add(*p->pmt); - } - - bool fTimeValid = p->rtStart != Packet::INVALID_TIME; - -#if defined(_DEBUG) && 0 - TRACE(_T("[%d]: d%d s%d p%d, b=%d, [%20I64d - %20I64d]\n"), - p->TrackNumber, - p->bDiscontinuity, p->bSyncPoint, fTimeValid && p->rtStart < 0, - nBytes, p->rtStart, p->rtStop); -#endif - - ASSERT(!p->bSyncPoint || fTimeValid); - - BYTE* pData = nullptr; - if (S_OK != (hr = pSample->GetPointer(&pData)) || !pData) { - break; - } - memcpy(pData, p->GetData(), nBytes); - if (S_OK != (hr = pSample->SetActualDataLength(nBytes))) { - break; - } - if (S_OK != (hr = pSample->SetTime(fTimeValid ? &p->rtStart : nullptr, fTimeValid ? &p->rtStop : nullptr))) { - break; - } - if (S_OK != (hr = pSample->SetMediaTime(nullptr, nullptr))) { - break; - } - if (S_OK != (hr = pSample->SetDiscontinuity(p->bDiscontinuity))) { - break; - } - if (S_OK != (hr = pSample->SetSyncPoint(p->bSyncPoint))) { - break; - } - if (S_OK != (hr = pSample->SetPreroll(fTimeValid && p->rtStart < 0))) { - break; - } - if (S_OK != (hr = Deliver(pSample))) { - break; - } - } while (false); - - return hr; -} - -void CBaseSplitterOutputPin::MakeISCRHappy() -{ - CComPtr pPinTo = this, pTmp; - while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { - pTmp = nullptr; - - CComPtr pBF = GetFilterFromPin(pPinTo); - - if (GetCLSID(pBF) == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) { // ISCR - CAutoPtr p(DEBUG_NEW Packet()); - p->TrackNumber = DWORD_ERROR; - p->rtStart = -1; - p->rtStop = 0; - p->bSyncPoint = FALSE; - p->SetData(" ", 2); - QueuePacket(p); - break; - } - - pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); - } -} - -HRESULT CBaseSplitterOutputPin::GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags) -{ - return __super::GetDeliveryBuffer(ppSample, pStartTime, pEndTime, dwFlags); -} - -HRESULT CBaseSplitterOutputPin::Deliver(IMediaSample* pSample) -{ - return __super::Deliver(pSample); -} - -// IMediaSeeking - -STDMETHODIMP CBaseSplitterOutputPin::GetCapabilities(DWORD* pCapabilities) -{ - return (static_cast(m_pFilter))->GetCapabilities(pCapabilities); -} - -STDMETHODIMP CBaseSplitterOutputPin::CheckCapabilities(DWORD* pCapabilities) -{ - return (static_cast(m_pFilter))->CheckCapabilities(pCapabilities); -} - -STDMETHODIMP CBaseSplitterOutputPin::IsFormatSupported(const GUID* pFormat) -{ - return (static_cast(m_pFilter))->IsFormatSupported(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::QueryPreferredFormat(GUID* pFormat) -{ - return (static_cast(m_pFilter))->QueryPreferredFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetTimeFormat(GUID* pFormat) -{ - return (static_cast(m_pFilter))->GetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::IsUsingTimeFormat(const GUID* pFormat) -{ - return (static_cast(m_pFilter))->IsUsingTimeFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::SetTimeFormat(const GUID* pFormat) -{ - return (static_cast(m_pFilter))->SetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetDuration(LONGLONG* pDuration) -{ - return (static_cast(m_pFilter))->GetDuration(pDuration); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetStopPosition(LONGLONG* pStop) -{ - return (static_cast(m_pFilter))->GetStopPosition(pStop); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetCurrentPosition(LONGLONG* pCurrent) -{ - return (static_cast(m_pFilter))->GetCurrentPosition(pCurrent); -} - -STDMETHODIMP CBaseSplitterOutputPin::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return (static_cast(m_pFilter))->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); -} - -STDMETHODIMP CBaseSplitterOutputPin::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return (static_cast(m_pFilter))->SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return (static_cast(m_pFilter))->GetPositions(pCurrent, pStop); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return (static_cast(m_pFilter))->GetAvailable(pEarliest, pLatest); -} - -STDMETHODIMP CBaseSplitterOutputPin::SetRate(double dRate) -{ - return (static_cast(m_pFilter))->SetRate(dRate); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetRate(double* pdRate) -{ - return (static_cast(m_pFilter))->GetRate(pdRate); -} - -STDMETHODIMP CBaseSplitterOutputPin::GetPreroll(LONGLONG* pllPreroll) -{ - return (static_cast(m_pFilter))->GetPreroll(pllPreroll); -} - -// -// CBaseSplitterFilter -// - -CBaseSplitterFilter::CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid, int QueueMaxPackets) - : CBaseFilter(pName, pUnk, this, clsid) - , m_nOpenProgress(100) - , m_fAbort(false) - , m_rtDuration(0) - , m_rtStart(0) - , m_rtStop(0) - , m_rtCurrent(0) - , m_rtNewStart(0) - , m_rtNewStop(0) - , m_dRate(1.0) - , m_fFlushing(false) - , m_priority(THREAD_PRIORITY_NORMAL) - , m_QueueMaxPackets(QueueMaxPackets) - , m_rtLastStart(_I64_MIN) - , m_rtLastStop(_I64_MIN) -{ - if (phr) { - *phr = S_OK; - } - - m_pInput.Attach(DEBUG_NEW CBaseSplitterInputPin(NAME("CBaseSplitterInputPin"), this, this, phr)); -} - -CBaseSplitterFilter::~CBaseSplitterFilter() -{ - CAutoLock cAutoLock(this); - - CAMThread::CallWorker(CMD_EXIT); - CAMThread::Close(); -} - -STDMETHODIMP CBaseSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - *ppv = nullptr; - - if (m_pInput && riid == __uuidof(IFileSourceFilter)) { - return E_NOINTERFACE; - } - - return - QI(IFileSourceFilter) - QI(IMediaSeeking) - QI(IAMOpenProgress) - QI2(IAMMediaContent) - QI2(IAMExtendedSeeking) - QI(IKeyFrameInfo) - QI(IBufferInfo) - QI(IPropertyBag) - QI(IPropertyBag2) - QI(IDSMPropertyBag) - QI(IDSMResourceBag) - QI(IDSMChapterBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -CBaseSplitterOutputPin* CBaseSplitterFilter::GetOutputPin(DWORD TrackNum) -{ - CAutoLock cAutoLock(&m_csPinMap); - - CBaseSplitterOutputPin* pPin = nullptr; - m_pPinMap.Lookup(TrackNum, pPin); - return pPin; -} - -DWORD CBaseSplitterFilter::GetOutputTrackNum(CBaseSplitterOutputPin* pPin) -{ - CAutoLock cAutoLock(&m_csPinMap); - - POSITION pos = m_pPinMap.GetStartPosition(); - while (pos) { - DWORD TrackNum; - CBaseSplitterOutputPin* pPinTmp; - m_pPinMap.GetNextAssoc(pos, TrackNum, pPinTmp); - if (pPinTmp == pPin) { - return TrackNum; - } - } - - return DWORD_ERROR; -} - -HRESULT CBaseSplitterFilter::RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt) -{ - CAutoLock cAutoLock(&m_csPinMap); - - CBaseSplitterOutputPin* pPin; - if (m_pPinMap.Lookup(TrackNumSrc, pPin)) { - if (CComQIPtr pPinTo = pPin->GetConnected()) { - if (pmt && S_OK != pPinTo->QueryAccept(pmt)) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } - - m_pPinMap.RemoveKey(TrackNumSrc); - m_pPinMap[TrackNumDst] = pPin; - - if (pmt) { - CAutoLock cAutoLock2(&m_csmtnew); - m_mtnew[TrackNumDst] = *pmt; - } - - return S_OK; - } - - return E_FAIL; -} - -HRESULT CBaseSplitterFilter::AddOutputPin(DWORD TrackNum, CAutoPtr pPin) -{ - CAutoLock cAutoLock(&m_csPinMap); - - if (!pPin) { - return E_INVALIDARG; - } - m_pPinMap[TrackNum] = pPin; - m_pOutputs.AddTail(pPin); - return S_OK; -} - -HRESULT CBaseSplitterFilter::DeleteOutputs() -{ - m_rtDuration = 0; - - m_pRetiredOutputs.RemoveAll(); - - CAutoLock cAutoLockF(this); - if (m_State != State_Stopped) { - return VFW_E_NOT_STOPPED; - } - - while (m_pOutputs.GetCount()) { - CAutoPtr pPin(m_pOutputs.RemoveHead().Detach()); - if (IPin* pPinTo = pPin->GetConnected()) { - pPinTo->Disconnect(); - } - pPin->Disconnect(); - // we can't just let it be deleted now, something might have AddRefed on it (graphedit...) - m_pRetiredOutputs.AddTail(pPin); - } - - CAutoLock cAutoLockPM(&m_csPinMap); - m_pPinMap.RemoveAll(); - - CAutoLock cAutoLockMT(&m_csmtnew); - m_mtnew.RemoveAll(); - - RemoveAll(); - ResRemoveAll(); - ChapRemoveAll(); - - m_fontinst.UninstallFonts(); - - m_pSyncReader.Release(); - - return S_OK; -} - -void CBaseSplitterFilter::DeliverBeginFlush() -{ - m_fFlushing = true; - POSITION pos = m_pOutputs.GetHeadPosition(); - while (pos) { - m_pOutputs.GetNext(pos)->DeliverBeginFlush(); - } -} - -void CBaseSplitterFilter::DeliverEndFlush() -{ - POSITION pos = m_pOutputs.GetHeadPosition(); - while (pos) { - m_pOutputs.GetNext(pos)->DeliverEndFlush(); - } - m_fFlushing = false; - m_eEndFlush.Set(); -} - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CBaseSplitterFilter::ThreadProc() -{ - if (m_pSyncReader) { - m_pSyncReader->SetBreakEvent(GetRequestHandle()); - } - - if (!DemuxInit()) { - for (;;) { - DWORD cmd = GetRequest(); - if (cmd == CMD_EXIT) { - CAMThread::m_hThread = nullptr; - } - Reply(S_OK); - if (cmd == CMD_EXIT) { - return 0; - } - } - } - - m_eEndFlush.Set(); - m_fFlushing = false; - - for (DWORD cmd = DWORD_ERROR; ; cmd = GetRequest()) { - if (cmd == CMD_EXIT) { - m_hThread = nullptr; - Reply(S_OK); - return 0; - } - - SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); - - m_rtStart = m_rtNewStart; - m_rtStop = m_rtNewStop; - - DemuxSeek(m_rtStart); - - if (cmd != DWORD_ERROR) { - Reply(S_OK); - } - - m_eEndFlush.Wait(); - - m_pActivePins.RemoveAll(); - - POSITION pos = m_pOutputs.GetHeadPosition(); - while (pos && !m_fFlushing) { - CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos); - if (pPin->IsConnected() && pPin->IsActive()) { - m_pActivePins.AddTail(pPin); - pPin->DeliverNewSegment(m_rtStart, m_rtStop, m_dRate); - } - } - - do { - m_bDiscontinuitySent.RemoveAll(); - } while (!DemuxLoop()); - - pos = m_pActivePins.GetHeadPosition(); - while (pos && !CheckRequest(&cmd)) { - m_pActivePins.GetNext(pos)->QueueEndOfStream(); - } - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -HRESULT CBaseSplitterFilter::DeliverPacket(CAutoPtr p) -{ - HRESULT hr = S_FALSE; - - CBaseSplitterOutputPin* pPin = GetOutputPin(p->TrackNumber); - if (!pPin || !pPin->IsConnected() || !m_pActivePins.Find(pPin)) { - return S_FALSE; - } - - if (p->rtStart != Packet::INVALID_TIME) { - m_rtCurrent = p->rtStart; - - p->rtStart -= m_rtStart; - p->rtStop -= m_rtStart; - - ASSERT(p->rtStart <= p->rtStop); - } - - { - CAutoLock cAutoLock(&m_csmtnew); - - CMediaType mt; - if (m_mtnew.Lookup(p->TrackNumber, mt)) { - p->pmt = CreateMediaType(&mt); - m_mtnew.RemoveKey(p->TrackNumber); - } - } - - if (!m_bDiscontinuitySent.Find(p->TrackNumber)) { - p->bDiscontinuity = TRUE; - } - - DWORD TrackNumber = p->TrackNumber; - BOOL bDiscontinuity = p->bDiscontinuity; - -#if defined(_DEBUG) && 0 - TRACE(_T("[%d]: d%d s%d p%d, b=%d, [%20I64d - %20I64d]\n"), - p->TrackNumber, - p->bDiscontinuity, p->bSyncPoint, p->rtStart != Packet::INVALID_TIME && p->rtStart < 0, - p->GetCount(), p->rtStart, p->rtStop); -#endif - - hr = pPin->QueuePacket(p); - - if (S_OK != hr) { - if (POSITION pos = m_pActivePins.Find(pPin)) { - m_pActivePins.RemoveAt(pos); - } - - if (!m_pActivePins.IsEmpty()) { // only die when all pins are down - hr = S_OK; - } - - return hr; - } - - if (bDiscontinuity) { - m_bDiscontinuitySent.AddTail(TrackNumber); - } - - return hr; -} - -bool CBaseSplitterFilter::IsAnyPinDrying() -{ - int totalcount = 0, totalsize = 0; - - POSITION pos = m_pActivePins.GetHeadPosition(); - while (pos) { - CBaseSplitterOutputPin* pPin = m_pActivePins.GetNext(pos); - int count = pPin->QueueCount(); - int size = pPin->QueueSize(); - if (!pPin->IsDiscontinuous() && (count < MINPACKETS || size < MINPACKETSIZE)) { - // if (m_priority != THREAD_PRIORITY_ABOVE_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3)) - if (m_priority != THREAD_PRIORITY_BELOW_NORMAL && (count < MINPACKETS / 3 || size < MINPACKETSIZE / 3)) { - // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_ABOVE_NORMAL); - POSITION pos2 = m_pOutputs.GetHeadPosition(); - while (pos2) { - m_pOutputs.GetNext(pos2)->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); - } - m_priority = THREAD_PRIORITY_BELOW_NORMAL; - } - return true; - } - totalcount += count; - totalsize += size; - } - - if (m_priority != THREAD_PRIORITY_NORMAL && (totalcount > m_QueueMaxPackets * 2 / 3 || totalsize > MAXPACKETSIZE * 2 / 3)) { - // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); - POSITION pos2 = m_pOutputs.GetHeadPosition(); - while (pos2) { - m_pOutputs.GetNext(pos2)->SetThreadPriority(THREAD_PRIORITY_NORMAL); - } - m_priority = THREAD_PRIORITY_NORMAL; - } - - if (totalcount < m_QueueMaxPackets && totalsize < MAXPACKETSIZE) { - return true; - } - - return false; -} - -HRESULT CBaseSplitterFilter::BreakConnect(PIN_DIRECTION dir, CBasePin* pPin) -{ - CheckPointer(pPin, E_POINTER); - - if (dir == PINDIR_INPUT) { - DeleteOutputs(); - } else if (dir == PINDIR_OUTPUT) { - } else { - return E_UNEXPECTED; - } - - return S_OK; -} - -HRESULT CBaseSplitterFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin) -{ - CheckPointer(pPin, E_POINTER); - - if (dir == PINDIR_INPUT) { - CBaseSplitterInputPin* pIn = static_cast(pPin); - - HRESULT hr; - - CComPtr pAsyncReader; - if (FAILED(hr = pIn->GetAsyncReader(&pAsyncReader)) - || FAILED(hr = DeleteOutputs()) - || FAILED(hr = CreateOutputs(pAsyncReader))) { - return hr; - } - - ChapSort(); - - m_pSyncReader = pAsyncReader; - } else if (dir == PINDIR_OUTPUT) { - m_pRetiredOutputs.RemoveAll(); - } else { - return E_UNEXPECTED; - } - - return S_OK; -} - -int CBaseSplitterFilter::GetPinCount() -{ - return (m_pInput ? 1 : 0) + (int)m_pOutputs.GetCount(); -} - -CBasePin* CBaseSplitterFilter::GetPin(int n) -{ - CAutoLock cAutoLock(this); - - if (n >= 0 && n < (int)m_pOutputs.GetCount()) { - if (POSITION pos = m_pOutputs.FindIndex(n)) { - return m_pOutputs.GetAt(pos); - } - } - - if (n == (int)m_pOutputs.GetCount() && m_pInput) { - return m_pInput; - } - - return nullptr; -} - -STDMETHODIMP CBaseSplitterFilter::Stop() -{ - CAutoLock cAutoLock(this); - - DeliverBeginFlush(); - CallWorker(CMD_EXIT); - DeliverEndFlush(); - - HRESULT hr; - if (FAILED(hr = __super::Stop())) { - return hr; - } - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::Pause() -{ - CAutoLock cAutoLock(this); - - FILTER_STATE fs = m_State; - - HRESULT hr; - if (FAILED(hr = __super::Pause())) { - return hr; - } - - if (fs == State_Stopped) { - Create(); - } - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - if (FAILED(hr = __super::Run(tStart))) { - return hr; - } - - return S_OK; -} - -// IFileSourceFilter - -STDMETHODIMP CBaseSplitterFilter::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - CheckPointer(pszFileName, E_POINTER); - - m_fn = pszFileName; - HRESULT hr = E_FAIL; - CComPtr pAsyncReader; - CAtlList Items; - CAtlList Chapters; - - if (BuildPlaylist(pszFileName, Items)) { - pAsyncReader = (IAsyncReader*)DEBUG_NEW CAsyncFileReader(Items, hr); - } else { - pAsyncReader = (IAsyncReader*)DEBUG_NEW CAsyncFileReader(CString(pszFileName), hr); - } - - if (FAILED(hr) - || FAILED(hr = DeleteOutputs()) - || FAILED(hr = CreateOutputs(pAsyncReader))) { - m_fn.Empty(); - return hr; - } - - if (BuildChapters(pszFileName, Items, Chapters)) { - POSITION pos = Chapters.GetHeadPosition(); - int i = 1; - while (pos) { - CString str; - CHdmvClipInfo::PlaylistChapter& chap = Chapters.GetNext(pos); - if (chap.m_nMarkType == CHdmvClipInfo::EntryMark) { - str.Format(_T("Chapter %d"), i); - ChapAppend(chap.m_rtTimestamp, str); - i++; - } - } - } - - ChapSort(); - - m_pSyncReader = pAsyncReader; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - return S_OK; -} - -LPCTSTR CBaseSplitterFilter::GetPartFilename(IAsyncReader* pAsyncReader) -{ - CComQIPtr pFH = pAsyncReader; - return pFH ? pFH->GetFileName() : (LPCWSTR)m_fn; -} - -// IMediaSeeking - -STDMETHODIMP CBaseSplitterFilter::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration - | AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanSeekForwards | AM_SEEKING_CanSeekBackwards; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - if (*pCapabilities == 0) { - return S_OK; - } - DWORD caps; - GetCapabilities(&caps); - if ((caps&*pCapabilities) == 0) { - return E_FAIL; - } - if (caps == *pCapabilities) { - return S_OK; - } - return S_FALSE; -} - -STDMETHODIMP CBaseSplitterFilter::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseSplitterFilter::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseSplitterFilter::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CBaseSplitterFilter::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CBaseSplitterFilter::GetDuration(LONGLONG* pDuration) -{ - CheckPointer(pDuration, E_POINTER); - *pDuration = m_rtDuration; - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetStopPosition(LONGLONG* pStop) -{ - return GetDuration(pStop); -} - -STDMETHODIMP CBaseSplitterFilter::GetCurrentPosition(LONGLONG* pCurrent) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseSplitterFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseSplitterFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags); -} - -STDMETHODIMP CBaseSplitterFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - if (pCurrent) { - *pCurrent = m_rtCurrent; - } - if (pStop) { - *pStop = m_rtStop; - } - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - if (pEarliest) { - *pEarliest = 0; - } - return GetDuration(pLatest); -} - -STDMETHODIMP CBaseSplitterFilter::SetRate(double dRate) -{ - HRESULT hr = E_INVALIDARG; - - if (dRate > 0.0) { - m_dRate = dRate; - hr = S_OK; - } - - return hr; -} - -STDMETHODIMP CBaseSplitterFilter::GetRate(double* pdRate) -{ - CheckPointer(pdRate, E_POINTER); - - *pdRate = m_dRate; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetPreroll(LONGLONG* pllPreroll) -{ - CheckPointer(pllPreroll, E_POINTER); - - *pllPreroll = 0; - - return S_OK; -} - -HRESULT CBaseSplitterFilter::SetPositionsInternal(void* id, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - CAutoLock cAutoLock(this); - - if (!pCurrent && !pStop - || (dwCurrentFlags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning - && (dwStopFlags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning) { - return S_OK; - } - - REFERENCE_TIME rtCurrent = m_rtCurrent; - REFERENCE_TIME rtStop = m_rtStop; - - if (pCurrent) - switch (dwCurrentFlags & AM_SEEKING_PositioningBitsMask) { - case AM_SEEKING_NoPositioning: - break; - case AM_SEEKING_AbsolutePositioning: - rtCurrent = *pCurrent; - break; - case AM_SEEKING_RelativePositioning: - rtCurrent = rtCurrent + *pCurrent; - break; - case AM_SEEKING_IncrementalPositioning: - rtCurrent = rtCurrent + *pCurrent; - break; - } - - if (pStop) - switch (dwStopFlags & AM_SEEKING_PositioningBitsMask) { - case AM_SEEKING_NoPositioning: - break; - case AM_SEEKING_AbsolutePositioning: - rtStop = *pStop; - break; - case AM_SEEKING_RelativePositioning: - rtStop += *pStop; - break; - case AM_SEEKING_IncrementalPositioning: - rtStop = rtCurrent + *pStop; - break; - } - - if (m_rtCurrent == rtCurrent && m_rtStop == rtStop) { - return S_OK; - } - - if (m_rtLastStart == rtCurrent && m_rtLastStop == rtStop && !m_LastSeekers.Find(id)) { - m_LastSeekers.AddTail(id); - return S_OK; - } - - m_rtLastStart = rtCurrent; - m_rtLastStop = rtStop; - m_LastSeekers.RemoveAll(); - m_LastSeekers.AddTail(id); - - DbgLog((LOG_TRACE, 0, _T("Seek Started %I64d"), rtCurrent)); - - m_rtNewStart = m_rtCurrent = rtCurrent; - m_rtNewStop = rtStop; - - if (ThreadExists()) { - DeliverBeginFlush(); - CallWorker(CMD_SEEK); - DeliverEndFlush(); - } - - DbgLog((LOG_TRACE, 0, _T("Seek Ended"))); - - return S_OK; -} - -// IAMOpenProgress - -STDMETHODIMP CBaseSplitterFilter::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent) -{ - CheckPointer(pllTotal, E_POINTER); - CheckPointer(pllCurrent, E_POINTER); - - *pllTotal = 100; - *pllCurrent = m_nOpenProgress; - - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::AbortOperation() -{ - m_fAbort = true; - return S_OK; -} - -// IAMMediaContent - -STDMETHODIMP CBaseSplitterFilter::get_AuthorName(BSTR* pbstrAuthorName) -{ - return GetProperty(L"AUTH", pbstrAuthorName); -} - -STDMETHODIMP CBaseSplitterFilter::get_Title(BSTR* pbstrTitle) -{ - return GetProperty(L"TITL", pbstrTitle); -} - -STDMETHODIMP CBaseSplitterFilter::get_Rating(BSTR* pbstrRating) -{ - return GetProperty(L"RTNG", pbstrRating); -} - -STDMETHODIMP CBaseSplitterFilter::get_Description(BSTR* pbstrDescription) -{ - return GetProperty(L"DESC", pbstrDescription); -} - -STDMETHODIMP CBaseSplitterFilter::get_Copyright(BSTR* pbstrCopyright) -{ - return GetProperty(L"CPYR", pbstrCopyright); -} - -// IAMExtendedSeeking - -STDMETHODIMP CBaseSplitterFilter::get_ExSeekCapabilities(long* pExCapabilities) -{ - CheckPointer(pExCapabilities, E_POINTER); - *pExCapabilities = AM_EXSEEK_CANSEEK; - if (ChapGetCount()) { - *pExCapabilities |= AM_EXSEEK_MARKERSEEK; - } - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::get_MarkerCount(long* pMarkerCount) -{ - CheckPointer(pMarkerCount, E_POINTER); - *pMarkerCount = (long)ChapGetCount(); - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::get_CurrentMarker(long* pCurrentMarker) -{ - CheckPointer(pCurrentMarker, E_POINTER); - REFERENCE_TIME rt = m_rtCurrent; - long i = ChapLookup(&rt); - if (i < 0) { - return E_FAIL; - } - *pCurrentMarker = i + 1; - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetMarkerTime(long MarkerNum, double* pMarkerTime) -{ - CheckPointer(pMarkerTime, E_POINTER); - REFERENCE_TIME rt; - if (FAILED(ChapGet((int)MarkerNum - 1, &rt))) { - return E_FAIL; - } - *pMarkerTime = (double)rt / 10000000; - return S_OK; -} - -STDMETHODIMP CBaseSplitterFilter::GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName) -{ - return ChapGet((int)MarkerNum - 1, nullptr, pbstrMarkerName); -} - -// IKeyFrameInfo - -STDMETHODIMP CBaseSplitterFilter::GetKeyFrameCount(UINT& nKFs) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs) -{ - return E_NOTIMPL; -} - -// IBufferInfo - -STDMETHODIMP_(int) CBaseSplitterFilter::GetCount() -{ - CAutoLock cAutoLock(m_pLock); - - return (int)m_pOutputs.GetCount(); -} - -STDMETHODIMP CBaseSplitterFilter::GetStatus(int i, int& samples, int& size) -{ - CAutoLock cAutoLock(m_pLock); - - if (POSITION pos = m_pOutputs.FindIndex(i)) { - CBaseSplitterOutputPin* pPin = m_pOutputs.GetAt(pos); - samples = pPin->QueueCount(); - size = pPin->QueueSize(); - return pPin->IsConnected() ? S_OK : S_FALSE; - } - - return E_INVALIDARG; -} - -STDMETHODIMP_(DWORD) CBaseSplitterFilter::GetPriority() -{ - return m_priority; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "../../../DSUtil/DSUtil.h" +#include "moreuuids.h" +#include "../../switcher/AudioSwitcher/AudioSwitcher.h" +#include "BaseSplitter.h" +#include + + +// +// CPacketQueue2 +// + +CPacketQueue2::CPacketQueue2() : m_size(0) +{ +} + +void CPacketQueue2::Add(CAutoPtr p) +{ + CAutoLock cAutoLock(this); + + if (p) { + m_size += p->GetDataSize(); + + if (p->bAppendable && !p->bDiscontinuity && !p->pmt + && p->rtStart == Packet::INVALID_TIME + && !IsEmpty() && GetTail()->rtStart != Packet::INVALID_TIME) { + Packet* tail = GetTail(); + size_t oldsize = tail->GetCount(); + size_t newsize = tail->GetCount() + p->GetCount(); + tail->SetCount(newsize, std::max(1024, (int)newsize)); // doubles the reserved buffer size + memcpy(tail->GetData() + oldsize, p->GetData(), p->GetCount()); + /* + GetTail()->Append(*p); // too slow + */ + return; + } + } + + AddTail(p); +} + +CAutoPtr CPacketQueue2::Remove() +{ + CAutoLock cAutoLock(this); + ASSERT(__super::GetCount() > 0); + CAutoPtr p(RemoveHead().Detach()); + if (p) { + m_size -= p->GetDataSize(); + } + return p; +} + +void CPacketQueue2::RemoveAll() +{ + CAutoLock cAutoLock(this); + m_size = 0; + __super::RemoveAll(); +} + +int CPacketQueue2::GetCount() +{ + CAutoLock cAutoLock(this); + return (int)__super::GetCount(); +} + +int CPacketQueue2::GetSize() +{ + CAutoLock cAutoLock(this); + return m_size; +} + +// +// CBaseSplitterInputPin +// + +CBaseSplitterInputPin::CBaseSplitterInputPin(LPCTSTR pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT) +{ +} + +CBaseSplitterInputPin::~CBaseSplitterInputPin() +{ +} + +HRESULT CBaseSplitterInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader) +{ + CheckPointer(ppAsyncReader, E_POINTER); + *ppAsyncReader = nullptr; + CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED); + (*ppAsyncReader = m_pAsyncReader)->AddRef(); + return S_OK; +} + +STDMETHODIMP CBaseSplitterInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CBaseSplitterInputPin::CheckMediaType(const CMediaType* pmt) +{ + return S_OK; + /* + return pmt->majortype == MEDIATYPE_Stream + ? S_OK + : E_INVALIDARG; + */ +} + +HRESULT CBaseSplitterInputPin::CheckConnect(IPin* pPin) +{ + HRESULT hr; + if (FAILED(hr = __super::CheckConnect(pPin))) { + return hr; + } + + return CComQIPtr(pPin) ? S_OK : E_NOINTERFACE; +} + +HRESULT CBaseSplitterInputPin::BreakConnect() +{ + HRESULT hr; + + if (FAILED(hr = __super::BreakConnect())) { + return hr; + } + + if (FAILED(hr = (static_cast(m_pFilter))->BreakConnect(PINDIR_INPUT, this))) { + return hr; + } + + m_pAsyncReader.Release(); + + return S_OK; +} + +HRESULT CBaseSplitterInputPin::CompleteConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CompleteConnect(pPin))) { + return hr; + } + + CheckPointer(pPin, E_POINTER); + m_pAsyncReader = pPin; + CheckPointer(m_pAsyncReader, E_NOINTERFACE); + + if (FAILED(hr = (static_cast(m_pFilter))->CompleteConnect(PINDIR_INPUT, this))) { + return hr; + } + + return S_OK; +} + +STDMETHODIMP CBaseSplitterInputPin::BeginFlush() +{ + return E_UNEXPECTED; +} + +STDMETHODIMP CBaseSplitterInputPin::EndFlush() +{ + return E_UNEXPECTED; +} + +// +// CBaseSplitterOutputPin +// + +CBaseSplitterOutputPin::CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers, int QueueMaxPackets) + : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName) + , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it + , m_fFlushing(false) + , m_fFlushed(false) + , m_eEndFlush(TRUE) + , m_QueueMaxPackets(QueueMaxPackets) + , m_rtStart(0) +{ + m_mts.Copy(mts); + m_nBuffers = std::max(nBuffers, 1); +} + +CBaseSplitterOutputPin::CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers, int QueueMaxPackets) + : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName) + , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it + , m_fFlushing(false) + , m_fFlushed(false) + , m_eEndFlush(TRUE) + , m_QueueMaxPackets(QueueMaxPackets) + , m_rtStart(0) +{ + m_nBuffers = std::max(nBuffers, 1); +} + +CBaseSplitterOutputPin::~CBaseSplitterOutputPin() +{ +} + +STDMETHODIMP CBaseSplitterOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + // riid == __uuidof(IMediaSeeking) ? m_pFilter->QueryInterface(riid, ppv) : + QI(IMediaSeeking) + QI(IPropertyBag) + QI(IPropertyBag2) + QI(IDSMPropertyBag) + QI(IBitRateInfo) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CBaseSplitterOutputPin::SetName(LPCWSTR pName) +{ + CheckPointer(pName, E_POINTER); + if (m_pName) { + delete [] m_pName; + } + m_pName = DEBUG_NEW WCHAR[wcslen(pName) + 1]; + CheckPointer(m_pName, E_OUTOFMEMORY); + wcscpy_s(m_pName, wcslen(pName) + 1, pName); + return S_OK; +} + +HRESULT CBaseSplitterOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = std::max(pProperties->cBuffers, m_nBuffers); + pProperties->cbBuffer = std::max((long)m_mt.lSampleSize, 1l); + + // TODO: is this still needed ? + if (m_mt.subtype == MEDIASUBTYPE_Vorbis && m_mt.formattype == FORMAT_VorbisFormat) { + // oh great, the oggds vorbis decoder assumes there will be two at least, stupid thing... + pProperties->cBuffers = std::max(pProperties->cBuffers, 2l); + } + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CBaseSplitterOutputPin::CheckMediaType(const CMediaType* pmt) +{ + for (size_t i = 0; i < m_mts.GetCount(); i++) { + if (*pmt == m_mts[i]) { + return S_OK; + } + } + + return E_INVALIDARG; +} + +HRESULT CBaseSplitterOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CAutoLock cAutoLock(m_pLock); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if ((size_t)iPosition >= m_mts.GetCount()) { + return VFW_S_NO_MORE_ITEMS; + } + + *pmt = m_mts[iPosition]; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} + +// + +HRESULT CBaseSplitterOutputPin::Active() +{ + CAutoLock cAutoLock(m_pLock); + + if (m_Connected) { + Create(); + } + + return __super::Active(); +} + +HRESULT CBaseSplitterOutputPin::Inactive() +{ + CAutoLock cAutoLock(m_pLock); + + if (ThreadExists()) { + CallWorker(CMD_EXIT); + } + + return __super::Inactive(); +} + +HRESULT CBaseSplitterOutputPin::DeliverBeginFlush() +{ + m_eEndFlush.Reset(); + m_fFlushed = false; + m_fFlushing = true; + m_hrDeliver = S_FALSE; + m_queue.RemoveAll(); + HRESULT hr = IsConnected() ? GetConnected()->BeginFlush() : S_OK; + if (S_OK != hr) { + m_eEndFlush.Set(); + } + return hr; +} + +HRESULT CBaseSplitterOutputPin::DeliverEndFlush() +{ + if (!ThreadExists()) { + return S_FALSE; + } + HRESULT hr = IsConnected() ? GetConnected()->EndFlush() : S_OK; + m_hrDeliver = S_OK; + m_fFlushing = false; + m_fFlushed = true; + m_eEndFlush.Set(); + return hr; +} + +HRESULT CBaseSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + m_BitRate.rtLastDeliverTime = Packet::INVALID_TIME; + if (m_fFlushing) { + return S_FALSE; + } + m_rtStart = tStart; + if (!ThreadExists()) { + return S_FALSE; + } + HRESULT hr = __super::DeliverNewSegment(tStart, tStop, dRate); + if (S_OK != hr) { + return hr; + } + MakeISCRHappy(); + return hr; +} + +int CBaseSplitterOutputPin::QueueCount() +{ + return m_queue.GetCount(); +} + +int CBaseSplitterOutputPin::QueueSize() +{ + return m_queue.GetSize(); +} + +HRESULT CBaseSplitterOutputPin::QueueEndOfStream() +{ + CAutoPtr p; + return QueuePacket(p); // NULL means EndOfStream +} + +HRESULT CBaseSplitterOutputPin::QueuePacket(CAutoPtr p) +{ + if (!ThreadExists()) { + return S_FALSE; + } + + while (S_OK == m_hrDeliver + && ((m_queue.GetCount() > (m_QueueMaxPackets * 2) || m_queue.GetSize() > (MAXPACKETSIZE * 3 / 2)) + || ((m_queue.GetCount() > m_QueueMaxPackets || m_queue.GetSize() > MAXPACKETSIZE) && !(static_cast(m_pFilter))->IsAnyPinDrying()))) { + Sleep(10); + } + + if (S_OK != m_hrDeliver) { + return m_hrDeliver; + } + + m_queue.Add(p); + + return m_hrDeliver; +} + +bool CBaseSplitterOutputPin::IsDiscontinuous() +{ + return m_mt.majortype == MEDIATYPE_Text + || m_mt.majortype == MEDIATYPE_ScriptCommand + || m_mt.majortype == MEDIATYPE_Subtitle + || m_mt.subtype == MEDIASUBTYPE_DVD_SUBPICTURE + || m_mt.subtype == MEDIASUBTYPE_CVD_SUBPICTURE + || m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE; +} + +bool CBaseSplitterOutputPin::IsActive() +{ + CComPtr pPin = this; + do { + CComPtr pPinTo; + CComQIPtr pSSIP; + if (S_OK == pPin->ConnectedTo(&pPinTo) && (pSSIP = pPinTo) && !pSSIP->IsActive()) { + return false; + } + pPin = GetFirstPin(GetFilterFromPin(pPinTo), PINDIR_OUTPUT); + } while (pPin); + + return true; +} + +DWORD CBaseSplitterOutputPin::ThreadProc() +{ + SetThreadName(DWORD(-1), "CBaseSplitterOutputPin"); + m_hrDeliver = S_OK; + m_fFlushing = m_fFlushed = false; + m_eEndFlush.Set(); + + // fix for Microsoft DTV-DVD Video Decoder - video freeze after STOP/PLAY + bool iHaaliRenderConnect = false; + CComPtr pPinTo = this, pTmp; + while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { + pTmp = nullptr; + CComPtr pBF = GetFilterFromPin(pPinTo); + if (GetCLSID(pBF) == CLSID_DXR) { // Haali Renderer + iHaaliRenderConnect = true; + break; + } + pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); + } + if (IsConnected() && !iHaaliRenderConnect) { + GetConnected()->BeginFlush(); + GetConnected()->EndFlush(); + } + + for (;;) { + Sleep(1); + + DWORD cmd; + if (CheckRequest(&cmd)) { + m_hThread = nullptr; + cmd = GetRequest(); + Reply(S_OK); + ASSERT(cmd == CMD_EXIT); + return 0; + } + + int cnt = 0; + do { + CAutoPtr p; + + { + CAutoLock cAutoLock(&m_queue); + if ((cnt = m_queue.GetCount()) > 0) { + p.Attach(m_queue.Remove().Detach()); + } + } + + if (S_OK == m_hrDeliver && cnt > 0) { + ASSERT(!m_fFlushing); + + m_fFlushed = false; + + // flushing can still start here, to release a blocked deliver call + + HRESULT hr = p + ? DeliverPacket(p) + : DeliverEndOfStream(); + + m_eEndFlush.Wait(); // .. so we have to wait until it is done + + if (hr != S_OK && !m_fFlushed) { // and only report the error in m_hrDeliver if we didn't flush the stream + // CAutoLock cAutoLock(&m_csQueueLock); + m_hrDeliver = hr; + break; + } + } + } while (--cnt > 0); + } +} + +HRESULT CBaseSplitterOutputPin::DeliverPacket(CAutoPtr p) +{ + HRESULT hr; + + long nBytes = (long)p->GetCount(); + + if (nBytes == 0) { + return S_OK; + } + + m_BitRate.nBytesSinceLastDeliverTime += nBytes; + + if (p->rtStart != Packet::INVALID_TIME) { + if (m_BitRate.rtLastDeliverTime == Packet::INVALID_TIME) { + m_BitRate.rtLastDeliverTime = p->rtStart; + m_BitRate.nBytesSinceLastDeliverTime = 0; + } + + if (m_BitRate.rtLastDeliverTime + 10000000 < p->rtStart) { + REFERENCE_TIME rtDiff = p->rtStart - m_BitRate.rtLastDeliverTime; + + double dSecs, dBits; + + dSecs = rtDiff / 10000000.0; + dBits = 8.0 * m_BitRate.nBytesSinceLastDeliverTime; + m_BitRate.nCurrentBitRate = (DWORD)(dBits / dSecs); + + m_BitRate.rtTotalTimeDelivered += rtDiff; + m_BitRate.nTotalBytesDelivered += m_BitRate.nBytesSinceLastDeliverTime; + + dSecs = m_BitRate.rtTotalTimeDelivered / 10000000.0; + dBits = 8.0 * m_BitRate.nTotalBytesDelivered; + m_BitRate.nAverageBitRate = (DWORD)(dBits / dSecs); + + m_BitRate.rtLastDeliverTime = p->rtStart; + m_BitRate.nBytesSinceLastDeliverTime = 0; + /* + TRACE(_T("[%d] c: %d kbps, a: %d kbps\n"), + p->TrackNumber, + (m_brs.nCurrentBitRate+500)/1000, + (m_brs.nAverageBitRate+500)/1000); + */ + } + + double dRate = 1.0; + if (SUCCEEDED((static_cast(m_pFilter))->GetRate(&dRate))) { + p->rtStart = (REFERENCE_TIME)((double)p->rtStart / dRate); + p->rtStop = (REFERENCE_TIME)((double)p->rtStop / dRate); + } + } + + do { + CComPtr pSample; + if (S_OK != (hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0))) { + break; + } + + if (nBytes > pSample->GetSize()) { + pSample.Release(); + + ALLOCATOR_PROPERTIES props, actual; + if (S_OK != (hr = m_pAllocator->GetProperties(&props))) { + break; + } + props.cbBuffer = nBytes * 3 / 2; + + if (props.cBuffers > 1) { + if (S_OK != (hr = __super::DeliverBeginFlush())) { + break; + } + if (S_OK != (hr = __super::DeliverEndFlush())) { + break; + } + } + + if (S_OK != (hr = m_pAllocator->Decommit())) { + break; + } + if (S_OK != (hr = m_pAllocator->SetProperties(&props, &actual))) { + break; + } + if (S_OK != (hr = m_pAllocator->Commit())) { + break; + } + if (S_OK != (hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0))) { + break; + } + } + + if (p->pmt) { + pSample->SetMediaType(p->pmt); + p->bDiscontinuity = true; + + CAutoLock cAutoLock(m_pLock); + m_mts.RemoveAll(); + m_mts.Add(*p->pmt); + } + + bool fTimeValid = p->rtStart != Packet::INVALID_TIME; + +#if defined(_DEBUG) && 0 + TRACE(_T("[%d]: d%d s%d p%d, b=%d, [%20I64d - %20I64d]\n"), + p->TrackNumber, + p->bDiscontinuity, p->bSyncPoint, fTimeValid && p->rtStart < 0, + nBytes, p->rtStart, p->rtStop); +#endif + + ASSERT(!p->bSyncPoint || fTimeValid); + + BYTE* pData = nullptr; + if (S_OK != (hr = pSample->GetPointer(&pData)) || !pData) { + break; + } + memcpy(pData, p->GetData(), nBytes); + if (S_OK != (hr = pSample->SetActualDataLength(nBytes))) { + break; + } + if (S_OK != (hr = pSample->SetTime(fTimeValid ? &p->rtStart : nullptr, fTimeValid ? &p->rtStop : nullptr))) { + break; + } + if (S_OK != (hr = pSample->SetMediaTime(nullptr, nullptr))) { + break; + } + if (S_OK != (hr = pSample->SetDiscontinuity(p->bDiscontinuity))) { + break; + } + if (S_OK != (hr = pSample->SetSyncPoint(p->bSyncPoint))) { + break; + } + if (S_OK != (hr = pSample->SetPreroll(fTimeValid && p->rtStart < 0))) { + break; + } + if (S_OK != (hr = Deliver(pSample))) { + break; + } + } while (false); + + return hr; +} + +void CBaseSplitterOutputPin::MakeISCRHappy() +{ + CComPtr pPinTo = this, pTmp; + while (pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp)) { + pTmp = nullptr; + + CComPtr pBF = GetFilterFromPin(pPinTo); + + if (GetCLSID(pBF) == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) { // ISCR + CAutoPtr p(DEBUG_NEW Packet()); + p->TrackNumber = DWORD_ERROR; + p->rtStart = -1; + p->rtStop = 0; + p->bSyncPoint = FALSE; + p->SetData(" ", 2); + QueuePacket(p); + break; + } + + pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT); + } +} + +HRESULT CBaseSplitterOutputPin::GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags) +{ + return __super::GetDeliveryBuffer(ppSample, pStartTime, pEndTime, dwFlags); +} + +HRESULT CBaseSplitterOutputPin::Deliver(IMediaSample* pSample) +{ + return __super::Deliver(pSample); +} + +// IMediaSeeking + +STDMETHODIMP CBaseSplitterOutputPin::GetCapabilities(DWORD* pCapabilities) +{ + return (static_cast(m_pFilter))->GetCapabilities(pCapabilities); +} + +STDMETHODIMP CBaseSplitterOutputPin::CheckCapabilities(DWORD* pCapabilities) +{ + return (static_cast(m_pFilter))->CheckCapabilities(pCapabilities); +} + +STDMETHODIMP CBaseSplitterOutputPin::IsFormatSupported(const GUID* pFormat) +{ + return (static_cast(m_pFilter))->IsFormatSupported(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::QueryPreferredFormat(GUID* pFormat) +{ + return (static_cast(m_pFilter))->QueryPreferredFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetTimeFormat(GUID* pFormat) +{ + return (static_cast(m_pFilter))->GetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::IsUsingTimeFormat(const GUID* pFormat) +{ + return (static_cast(m_pFilter))->IsUsingTimeFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::SetTimeFormat(const GUID* pFormat) +{ + return (static_cast(m_pFilter))->SetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetDuration(LONGLONG* pDuration) +{ + return (static_cast(m_pFilter))->GetDuration(pDuration); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetStopPosition(LONGLONG* pStop) +{ + return (static_cast(m_pFilter))->GetStopPosition(pStop); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetCurrentPosition(LONGLONG* pCurrent) +{ + return (static_cast(m_pFilter))->GetCurrentPosition(pCurrent); +} + +STDMETHODIMP CBaseSplitterOutputPin::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return (static_cast(m_pFilter))->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat); +} + +STDMETHODIMP CBaseSplitterOutputPin::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return (static_cast(m_pFilter))->SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return (static_cast(m_pFilter))->GetPositions(pCurrent, pStop); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return (static_cast(m_pFilter))->GetAvailable(pEarliest, pLatest); +} + +STDMETHODIMP CBaseSplitterOutputPin::SetRate(double dRate) +{ + return (static_cast(m_pFilter))->SetRate(dRate); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetRate(double* pdRate) +{ + return (static_cast(m_pFilter))->GetRate(pdRate); +} + +STDMETHODIMP CBaseSplitterOutputPin::GetPreroll(LONGLONG* pllPreroll) +{ + return (static_cast(m_pFilter))->GetPreroll(pllPreroll); +} + +// +// CBaseSplitterFilter +// + +CBaseSplitterFilter::CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid, int QueueMaxPackets) + : CBaseFilter(pName, pUnk, this, clsid) + , m_nOpenProgress(100) + , m_fAbort(false) + , m_rtDuration(0) + , m_rtStart(0) + , m_rtStop(0) + , m_rtCurrent(0) + , m_rtNewStart(0) + , m_rtNewStop(0) + , m_dRate(1.0) + , m_fFlushing(false) + , m_priority(THREAD_PRIORITY_NORMAL) + , m_QueueMaxPackets(QueueMaxPackets) + , m_rtLastStart(_I64_MIN) + , m_rtLastStop(_I64_MIN) +{ + if (phr) { + *phr = S_OK; + } + + m_pInput.Attach(DEBUG_NEW CBaseSplitterInputPin(NAME("CBaseSplitterInputPin"), this, this, phr)); +} + +CBaseSplitterFilter::~CBaseSplitterFilter() +{ + CAutoLock cAutoLock(this); + + CAMThread::CallWorker(CMD_EXIT); + CAMThread::Close(); +} + +STDMETHODIMP CBaseSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + *ppv = nullptr; + + if (m_pInput && riid == __uuidof(IFileSourceFilter)) { + return E_NOINTERFACE; + } + + return + QI(IFileSourceFilter) + QI(IMediaSeeking) + QI(IAMOpenProgress) + QI2(IAMMediaContent) + QI2(IAMExtendedSeeking) + QI(IKeyFrameInfo) + QI(IBufferInfo) + QI(IPropertyBag) + QI(IPropertyBag2) + QI(IDSMPropertyBag) + QI(IDSMResourceBag) + QI(IDSMChapterBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +CBaseSplitterOutputPin* CBaseSplitterFilter::GetOutputPin(DWORD TrackNum) +{ + CAutoLock cAutoLock(&m_csPinMap); + + CBaseSplitterOutputPin* pPin = nullptr; + m_pPinMap.Lookup(TrackNum, pPin); + return pPin; +} + +DWORD CBaseSplitterFilter::GetOutputTrackNum(CBaseSplitterOutputPin* pPin) +{ + CAutoLock cAutoLock(&m_csPinMap); + + POSITION pos = m_pPinMap.GetStartPosition(); + while (pos) { + DWORD TrackNum; + CBaseSplitterOutputPin* pPinTmp; + m_pPinMap.GetNextAssoc(pos, TrackNum, pPinTmp); + if (pPinTmp == pPin) { + return TrackNum; + } + } + + return DWORD_ERROR; +} + +HRESULT CBaseSplitterFilter::RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt) +{ + CAutoLock cAutoLock(&m_csPinMap); + + CBaseSplitterOutputPin* pPin; + if (m_pPinMap.Lookup(TrackNumSrc, pPin)) { + if (CComQIPtr pPinTo = pPin->GetConnected()) { + if (pmt && S_OK != pPinTo->QueryAccept(pmt)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } + + m_pPinMap.RemoveKey(TrackNumSrc); + m_pPinMap[TrackNumDst] = pPin; + + if (pmt) { + CAutoLock cAutoLock2(&m_csmtnew); + m_mtnew[TrackNumDst] = *pmt; + } + + return S_OK; + } + + return E_FAIL; +} + +HRESULT CBaseSplitterFilter::AddOutputPin(DWORD TrackNum, CAutoPtr pPin) +{ + CAutoLock cAutoLock(&m_csPinMap); + + if (!pPin) { + return E_INVALIDARG; + } + m_pPinMap[TrackNum] = pPin; + m_pOutputs.AddTail(pPin); + return S_OK; +} + +HRESULT CBaseSplitterFilter::DeleteOutputs() +{ + m_rtDuration = 0; + + m_pRetiredOutputs.RemoveAll(); + + CAutoLock cAutoLockF(this); + if (m_State != State_Stopped) { + return VFW_E_NOT_STOPPED; + } + + while (m_pOutputs.GetCount()) { + CAutoPtr pPin(m_pOutputs.RemoveHead().Detach()); + if (IPin* pPinTo = pPin->GetConnected()) { + pPinTo->Disconnect(); + } + pPin->Disconnect(); + // we can't just let it be deleted now, something might have AddRefed on it (graphedit...) + m_pRetiredOutputs.AddTail(pPin); + } + + CAutoLock cAutoLockPM(&m_csPinMap); + m_pPinMap.RemoveAll(); + + CAutoLock cAutoLockMT(&m_csmtnew); + m_mtnew.RemoveAll(); + + RemoveAll(); + ResRemoveAll(); + ChapRemoveAll(); + + m_fontinst.UninstallFonts(); + + m_pSyncReader.Release(); + + return S_OK; +} + +void CBaseSplitterFilter::DeliverBeginFlush() +{ + m_fFlushing = true; + POSITION pos = m_pOutputs.GetHeadPosition(); + while (pos) { + m_pOutputs.GetNext(pos)->DeliverBeginFlush(); + } +} + +void CBaseSplitterFilter::DeliverEndFlush() +{ + POSITION pos = m_pOutputs.GetHeadPosition(); + while (pos) { + m_pOutputs.GetNext(pos)->DeliverEndFlush(); + } + m_fFlushing = false; + m_eEndFlush.Set(); +} + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CBaseSplitterFilter::ThreadProc() +{ + if (m_pSyncReader) { + m_pSyncReader->SetBreakEvent(GetRequestHandle()); + } + + if (!DemuxInit()) { + for (;;) { + DWORD cmd = GetRequest(); + if (cmd == CMD_EXIT) { + CAMThread::m_hThread = nullptr; + } + Reply(S_OK); + if (cmd == CMD_EXIT) { + return 0; + } + } + } + + m_eEndFlush.Set(); + m_fFlushing = false; + + for (DWORD cmd = DWORD_ERROR; ; cmd = GetRequest()) { + if (cmd == CMD_EXIT) { + m_hThread = nullptr; + Reply(S_OK); + return 0; + } + + SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); + + m_rtStart = m_rtNewStart; + m_rtStop = m_rtNewStop; + + DemuxSeek(m_rtStart); + + if (cmd != DWORD_ERROR) { + Reply(S_OK); + } + + m_eEndFlush.Wait(); + + m_pActivePins.RemoveAll(); + + POSITION pos = m_pOutputs.GetHeadPosition(); + while (pos && !m_fFlushing) { + CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos); + if (pPin->IsConnected() && pPin->IsActive()) { + m_pActivePins.AddTail(pPin); + pPin->DeliverNewSegment(m_rtStart, m_rtStop, m_dRate); + } + } + + do { + m_bDiscontinuitySent.RemoveAll(); + } while (!DemuxLoop()); + + pos = m_pActivePins.GetHeadPosition(); + while (pos && !CheckRequest(&cmd)) { + m_pActivePins.GetNext(pos)->QueueEndOfStream(); + } + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +HRESULT CBaseSplitterFilter::DeliverPacket(CAutoPtr p) +{ + HRESULT hr = S_FALSE; + + CBaseSplitterOutputPin* pPin = GetOutputPin(p->TrackNumber); + if (!pPin || !pPin->IsConnected() || !m_pActivePins.Find(pPin)) { + return S_FALSE; + } + + if (p->rtStart != Packet::INVALID_TIME) { + m_rtCurrent = p->rtStart; + + p->rtStart -= m_rtStart; + p->rtStop -= m_rtStart; + + ASSERT(p->rtStart <= p->rtStop); + } + + { + CAutoLock cAutoLock(&m_csmtnew); + + CMediaType mt; + if (m_mtnew.Lookup(p->TrackNumber, mt)) { + p->pmt = CreateMediaType(&mt); + m_mtnew.RemoveKey(p->TrackNumber); + } + } + + if (!m_bDiscontinuitySent.Find(p->TrackNumber)) { + p->bDiscontinuity = TRUE; + } + + DWORD TrackNumber = p->TrackNumber; + BOOL bDiscontinuity = p->bDiscontinuity; + +#if defined(_DEBUG) && 0 + TRACE(_T("[%d]: d%d s%d p%d, b=%d, [%20I64d - %20I64d]\n"), + p->TrackNumber, + p->bDiscontinuity, p->bSyncPoint, p->rtStart != Packet::INVALID_TIME && p->rtStart < 0, + p->GetCount(), p->rtStart, p->rtStop); +#endif + + hr = pPin->QueuePacket(p); + + if (S_OK != hr) { + if (POSITION pos = m_pActivePins.Find(pPin)) { + m_pActivePins.RemoveAt(pos); + } + + if (!m_pActivePins.IsEmpty()) { // only die when all pins are down + hr = S_OK; + } + + return hr; + } + + if (bDiscontinuity) { + m_bDiscontinuitySent.AddTail(TrackNumber); + } + + return hr; +} + +bool CBaseSplitterFilter::IsAnyPinDrying() +{ + int totalcount = 0, totalsize = 0; + + POSITION pos = m_pActivePins.GetHeadPosition(); + while (pos) { + CBaseSplitterOutputPin* pPin = m_pActivePins.GetNext(pos); + int count = pPin->QueueCount(); + int size = pPin->QueueSize(); + if (!pPin->IsDiscontinuous() && (count < MINPACKETS || size < MINPACKETSIZE)) { + // if (m_priority != THREAD_PRIORITY_ABOVE_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3)) + if (m_priority != THREAD_PRIORITY_BELOW_NORMAL && (count < MINPACKETS / 3 || size < MINPACKETSIZE / 3)) { + // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_ABOVE_NORMAL); + POSITION pos2 = m_pOutputs.GetHeadPosition(); + while (pos2) { + m_pOutputs.GetNext(pos2)->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); + } + m_priority = THREAD_PRIORITY_BELOW_NORMAL; + } + return true; + } + totalcount += count; + totalsize += size; + } + + if (m_priority != THREAD_PRIORITY_NORMAL && (totalcount > m_QueueMaxPackets * 2 / 3 || totalsize > MAXPACKETSIZE * 2 / 3)) { + // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL); + POSITION pos2 = m_pOutputs.GetHeadPosition(); + while (pos2) { + m_pOutputs.GetNext(pos2)->SetThreadPriority(THREAD_PRIORITY_NORMAL); + } + m_priority = THREAD_PRIORITY_NORMAL; + } + + if (totalcount < m_QueueMaxPackets && totalsize < MAXPACKETSIZE) { + return true; + } + + return false; +} + +HRESULT CBaseSplitterFilter::BreakConnect(PIN_DIRECTION dir, CBasePin* pPin) +{ + CheckPointer(pPin, E_POINTER); + + if (dir == PINDIR_INPUT) { + DeleteOutputs(); + } else if (dir == PINDIR_OUTPUT) { + } else { + return E_UNEXPECTED; + } + + return S_OK; +} + +HRESULT CBaseSplitterFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin) +{ + CheckPointer(pPin, E_POINTER); + + if (dir == PINDIR_INPUT) { + CBaseSplitterInputPin* pIn = static_cast(pPin); + + HRESULT hr; + + CComPtr pAsyncReader; + if (FAILED(hr = pIn->GetAsyncReader(&pAsyncReader)) + || FAILED(hr = DeleteOutputs()) + || FAILED(hr = CreateOutputs(pAsyncReader))) { + return hr; + } + + ChapSort(); + + m_pSyncReader = pAsyncReader; + } else if (dir == PINDIR_OUTPUT) { + m_pRetiredOutputs.RemoveAll(); + } else { + return E_UNEXPECTED; + } + + return S_OK; +} + +int CBaseSplitterFilter::GetPinCount() +{ + return (m_pInput ? 1 : 0) + (int)m_pOutputs.GetCount(); +} + +CBasePin* CBaseSplitterFilter::GetPin(int n) +{ + CAutoLock cAutoLock(this); + + if (n >= 0 && n < (int)m_pOutputs.GetCount()) { + if (POSITION pos = m_pOutputs.FindIndex(n)) { + return m_pOutputs.GetAt(pos); + } + } + + if (n == (int)m_pOutputs.GetCount() && m_pInput) { + return m_pInput; + } + + return nullptr; +} + +STDMETHODIMP CBaseSplitterFilter::Stop() +{ + CAutoLock cAutoLock(this); + + DeliverBeginFlush(); + CallWorker(CMD_EXIT); + DeliverEndFlush(); + + HRESULT hr; + if (FAILED(hr = __super::Stop())) { + return hr; + } + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::Pause() +{ + CAutoLock cAutoLock(this); + + FILTER_STATE fs = m_State; + + HRESULT hr; + if (FAILED(hr = __super::Pause())) { + return hr; + } + + if (fs == State_Stopped) { + Create(); + } + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + if (FAILED(hr = __super::Run(tStart))) { + return hr; + } + + return S_OK; +} + +// IFileSourceFilter + +STDMETHODIMP CBaseSplitterFilter::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + CheckPointer(pszFileName, E_POINTER); + + m_fn = pszFileName; + HRESULT hr = E_FAIL; + CComPtr pAsyncReader; + CAtlList Items; + CAtlList Chapters; + + if (BuildPlaylist(pszFileName, Items)) { + pAsyncReader = (IAsyncReader*)DEBUG_NEW CAsyncFileReader(Items, hr); + } else { + pAsyncReader = (IAsyncReader*)DEBUG_NEW CAsyncFileReader(CString(pszFileName), hr); + } + + if (FAILED(hr) + || FAILED(hr = DeleteOutputs()) + || FAILED(hr = CreateOutputs(pAsyncReader))) { + m_fn.Empty(); + return hr; + } + + if (BuildChapters(pszFileName, Items, Chapters)) { + POSITION pos = Chapters.GetHeadPosition(); + int i = 1; + while (pos) { + CString str; + CHdmvClipInfo::PlaylistChapter& chap = Chapters.GetNext(pos); + if (chap.m_nMarkType == CHdmvClipInfo::EntryMark) { + str.Format(_T("Chapter %d"), i); + ChapAppend(chap.m_rtTimestamp, str); + i++; + } + } + } + + ChapSort(); + + m_pSyncReader = pAsyncReader; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + return S_OK; +} + +LPCTSTR CBaseSplitterFilter::GetPartFilename(IAsyncReader* pAsyncReader) +{ + CComQIPtr pFH = pAsyncReader; + return pFH ? pFH->GetFileName() : (LPCWSTR)m_fn; +} + +// IMediaSeeking + +STDMETHODIMP CBaseSplitterFilter::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration + | AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanSeekForwards | AM_SEEKING_CanSeekBackwards; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + if (*pCapabilities == 0) { + return S_OK; + } + DWORD caps; + GetCapabilities(&caps); + if ((caps&*pCapabilities) == 0) { + return E_FAIL; + } + if (caps == *pCapabilities) { + return S_OK; + } + return S_FALSE; +} + +STDMETHODIMP CBaseSplitterFilter::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseSplitterFilter::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseSplitterFilter::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CBaseSplitterFilter::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CBaseSplitterFilter::GetDuration(LONGLONG* pDuration) +{ + CheckPointer(pDuration, E_POINTER); + *pDuration = m_rtDuration; + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetStopPosition(LONGLONG* pStop) +{ + return GetDuration(pStop); +} + +STDMETHODIMP CBaseSplitterFilter::GetCurrentPosition(LONGLONG* pCurrent) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseSplitterFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseSplitterFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags); +} + +STDMETHODIMP CBaseSplitterFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + if (pCurrent) { + *pCurrent = m_rtCurrent; + } + if (pStop) { + *pStop = m_rtStop; + } + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + if (pEarliest) { + *pEarliest = 0; + } + return GetDuration(pLatest); +} + +STDMETHODIMP CBaseSplitterFilter::SetRate(double dRate) +{ + HRESULT hr = E_INVALIDARG; + + if (dRate > 0.0) { + m_dRate = dRate; + hr = S_OK; + } + + return hr; +} + +STDMETHODIMP CBaseSplitterFilter::GetRate(double* pdRate) +{ + CheckPointer(pdRate, E_POINTER); + + *pdRate = m_dRate; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetPreroll(LONGLONG* pllPreroll) +{ + CheckPointer(pllPreroll, E_POINTER); + + *pllPreroll = 0; + + return S_OK; +} + +HRESULT CBaseSplitterFilter::SetPositionsInternal(void* id, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + CAutoLock cAutoLock(this); + + if (!pCurrent && !pStop + || (dwCurrentFlags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning + && (dwStopFlags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning) { + return S_OK; + } + + REFERENCE_TIME rtCurrent = m_rtCurrent; + REFERENCE_TIME rtStop = m_rtStop; + + if (pCurrent) + switch (dwCurrentFlags & AM_SEEKING_PositioningBitsMask) { + case AM_SEEKING_NoPositioning: + break; + case AM_SEEKING_AbsolutePositioning: + rtCurrent = *pCurrent; + break; + case AM_SEEKING_RelativePositioning: + rtCurrent = rtCurrent + *pCurrent; + break; + case AM_SEEKING_IncrementalPositioning: + rtCurrent = rtCurrent + *pCurrent; + break; + } + + if (pStop) + switch (dwStopFlags & AM_SEEKING_PositioningBitsMask) { + case AM_SEEKING_NoPositioning: + break; + case AM_SEEKING_AbsolutePositioning: + rtStop = *pStop; + break; + case AM_SEEKING_RelativePositioning: + rtStop += *pStop; + break; + case AM_SEEKING_IncrementalPositioning: + rtStop = rtCurrent + *pStop; + break; + } + + if (m_rtCurrent == rtCurrent && m_rtStop == rtStop) { + return S_OK; + } + + if (m_rtLastStart == rtCurrent && m_rtLastStop == rtStop && !m_LastSeekers.Find(id)) { + m_LastSeekers.AddTail(id); + return S_OK; + } + + m_rtLastStart = rtCurrent; + m_rtLastStop = rtStop; + m_LastSeekers.RemoveAll(); + m_LastSeekers.AddTail(id); + + DbgLog((LOG_TRACE, 0, _T("Seek Started %I64d"), rtCurrent)); + + m_rtNewStart = m_rtCurrent = rtCurrent; + m_rtNewStop = rtStop; + + if (ThreadExists()) { + DeliverBeginFlush(); + CallWorker(CMD_SEEK); + DeliverEndFlush(); + } + + DbgLog((LOG_TRACE, 0, _T("Seek Ended"))); + + return S_OK; +} + +// IAMOpenProgress + +STDMETHODIMP CBaseSplitterFilter::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent) +{ + CheckPointer(pllTotal, E_POINTER); + CheckPointer(pllCurrent, E_POINTER); + + *pllTotal = 100; + *pllCurrent = m_nOpenProgress; + + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::AbortOperation() +{ + m_fAbort = true; + return S_OK; +} + +// IAMMediaContent + +STDMETHODIMP CBaseSplitterFilter::get_AuthorName(BSTR* pbstrAuthorName) +{ + return GetProperty(L"AUTH", pbstrAuthorName); +} + +STDMETHODIMP CBaseSplitterFilter::get_Title(BSTR* pbstrTitle) +{ + return GetProperty(L"TITL", pbstrTitle); +} + +STDMETHODIMP CBaseSplitterFilter::get_Rating(BSTR* pbstrRating) +{ + return GetProperty(L"RTNG", pbstrRating); +} + +STDMETHODIMP CBaseSplitterFilter::get_Description(BSTR* pbstrDescription) +{ + return GetProperty(L"DESC", pbstrDescription); +} + +STDMETHODIMP CBaseSplitterFilter::get_Copyright(BSTR* pbstrCopyright) +{ + return GetProperty(L"CPYR", pbstrCopyright); +} + +// IAMExtendedSeeking + +STDMETHODIMP CBaseSplitterFilter::get_ExSeekCapabilities(long* pExCapabilities) +{ + CheckPointer(pExCapabilities, E_POINTER); + *pExCapabilities = AM_EXSEEK_CANSEEK; + if (ChapGetCount()) { + *pExCapabilities |= AM_EXSEEK_MARKERSEEK; + } + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::get_MarkerCount(long* pMarkerCount) +{ + CheckPointer(pMarkerCount, E_POINTER); + *pMarkerCount = (long)ChapGetCount(); + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::get_CurrentMarker(long* pCurrentMarker) +{ + CheckPointer(pCurrentMarker, E_POINTER); + REFERENCE_TIME rt = m_rtCurrent; + long i = ChapLookup(&rt); + if (i < 0) { + return E_FAIL; + } + *pCurrentMarker = i + 1; + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetMarkerTime(long MarkerNum, double* pMarkerTime) +{ + CheckPointer(pMarkerTime, E_POINTER); + REFERENCE_TIME rt; + if (FAILED(ChapGet((int)MarkerNum - 1, &rt))) { + return E_FAIL; + } + *pMarkerTime = (double)rt / 10000000; + return S_OK; +} + +STDMETHODIMP CBaseSplitterFilter::GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName) +{ + return ChapGet((int)MarkerNum - 1, nullptr, pbstrMarkerName); +} + +// IKeyFrameInfo + +STDMETHODIMP CBaseSplitterFilter::GetKeyFrameCount(UINT& nKFs) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs) +{ + return E_NOTIMPL; +} + +// IBufferInfo + +STDMETHODIMP_(int) CBaseSplitterFilter::GetCount() +{ + CAutoLock cAutoLock(m_pLock); + + return (int)m_pOutputs.GetCount(); +} + +STDMETHODIMP CBaseSplitterFilter::GetStatus(int i, int& samples, int& size) +{ + CAutoLock cAutoLock(m_pLock); + + if (POSITION pos = m_pOutputs.FindIndex(i)) { + CBaseSplitterOutputPin* pPin = m_pOutputs.GetAt(pos); + samples = pPin->QueueCount(); + size = pPin->QueueSize(); + return pPin->IsConnected() ? S_OK : S_FALSE; + } + + return E_INVALIDARG; +} + +STDMETHODIMP_(DWORD) CBaseSplitterFilter::GetPriority() +{ + return m_priority; +} diff --git a/src/filters/parser/BaseSplitter/BaseSplitter.h b/src/filters/parser/BaseSplitter/BaseSplitter.h index f705d95bb85..4b47b95093e 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitter.h +++ b/src/filters/parser/BaseSplitter/BaseSplitter.h @@ -1,416 +1,416 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#pragma once - -#include -#include -#include -#include "IKeyFrameInfo.h" -#include "IBufferInfo.h" -#include "IBitRateInfo.h" -#include "AsyncReader.h" -#include "../../../DSUtil/DSMPropertyBag.h" -#include "../../../DSUtil/FontInstaller.h" - -#define MINPACKETS 100 // Beliyaal: Changed the min number of packets to allow Bluray playback over network -#define MINPACKETSIZE 256*1024 // Beliyaal: Changed the min packet size to allow Bluray playback over network -#define MAXPACKETS 2000 -#define MAXPACKETSIZE 128*1024*1024 - -class Packet : public CAtlArray -{ -public: - DWORD TrackNumber; - BOOL bDiscontinuity, bSyncPoint, bAppendable; - static const REFERENCE_TIME INVALID_TIME = _I64_MIN; - REFERENCE_TIME rtStart, rtStop; - AM_MEDIA_TYPE* pmt; - Packet() - : TrackNumber(0) - , bDiscontinuity(FALSE) - , bSyncPoint(FALSE) - , bAppendable(FALSE) - , rtStart(0) - , rtStop(0) - , pmt(nullptr) { - } - virtual ~Packet() { - if (pmt) { - DeleteMediaType(pmt); - } - } - virtual int GetDataSize() { return (int)GetCount(); } - void SetData(const void* ptr, DWORD len) { - SetCount(len); - memcpy(GetData(), ptr, len); - } -}; - -class CPacketQueue2 - : public CCritSec - , protected CAutoPtrList -{ - int m_size; - -public: - CPacketQueue2(); - void Add(CAutoPtr p); - CAutoPtr Remove(); - void RemoveAll(); - int GetCount(), GetSize(); -}; - -class CBaseSplitterFilter; - -class CBaseSplitterInputPin - : public CBasePin -{ -protected: - CComQIPtr m_pAsyncReader; - -public: - CBaseSplitterInputPin(LPCTSTR pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CBaseSplitterInputPin(); - - HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT CheckMediaType(const CMediaType* pmt); - - HRESULT CheckConnect(IPin* pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pPin); - - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); -}; - -class CBaseSplitterOutputPin - : public CBaseOutputPin - , public IDSMPropertyBagImpl - , protected CAMThread - , public IMediaSeeking - , public IBitRateInfo -{ -protected: - CAtlArray m_mts; - int m_nBuffers; - -private: - CPacketQueue2 m_queue; - - HRESULT m_hrDeliver; - - bool m_fFlushing, m_fFlushed; - CAMEvent m_eEndFlush; - - enum { CMD_EXIT }; - DWORD ThreadProc(); - - void MakeISCRHappy(); - - // please only use DeliverPacket from the derived class - HRESULT GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags); - HRESULT Deliver(IMediaSample* pSample); - - // IBitRateInfo - struct BitRateInfo { - UINT64 nTotalBytesDelivered = 0; - REFERENCE_TIME rtTotalTimeDelivered = 0; - UINT64 nBytesSinceLastDeliverTime = 0; - REFERENCE_TIME rtLastDeliverTime = Packet::INVALID_TIME; - DWORD nCurrentBitRate = 0; - DWORD nAverageBitRate = 0; - } m_BitRate; - - int m_QueueMaxPackets; - -protected: - REFERENCE_TIME m_rtStart; - - // override this if you need some second level stream specific demuxing (optional) - // the default implementation will send the sample as is - virtual HRESULT DeliverPacket(CAutoPtr p); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - -public: - CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, - CBaseFilter* pFilter, CCritSec* pLock, - HRESULT* phr, int nBuffers = 0, - int QueueMaxPackets = MAXPACKETS); - CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, - CCritSec* pLock, HRESULT* phr, - int nBuffers = 0, - int QueueMaxPackets = MAXPACKETS); - virtual ~CBaseSplitterOutputPin(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT SetName(LPCWSTR pName); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - CMediaType& CurrentMediaType() { return m_mt; } - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); - - // Queueing - - HANDLE GetThreadHandle() { - ASSERT(m_hThread != nullptr); - return m_hThread; - } - void SetThreadPriority(int nPriority) { - if (m_hThread) { - ::SetThreadPriority(m_hThread, nPriority); - } - } - - HRESULT Active(); - HRESULT Inactive(); - - HRESULT DeliverBeginFlush(); - HRESULT DeliverEndFlush(); - HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - - int QueueCount(); - int QueueSize(); - HRESULT QueueEndOfStream(); - HRESULT QueuePacket(CAutoPtr p); - - // returns true for everything which (the lack of) would not block other streams (subtitle streams, basically) - virtual bool IsDiscontinuous(); - - // returns IStreamsSwitcherInputPin::IsActive(), when it can find one downstream - bool IsActive(); - - // IBitRateInfo - - STDMETHODIMP_(DWORD) GetCurrentBitRate() { return m_BitRate.nCurrentBitRate; } - STDMETHODIMP_(DWORD) GetAverageBitRate() { return m_BitRate.nAverageBitRate; } -}; - -class CBaseSplitterFilter - : public CBaseFilter - , public CCritSec - , public IDSMPropertyBagImpl - , public IDSMResourceBagImpl - , public IDSMChapterBagImpl - , protected CAMThread - , public IFileSourceFilter - , public IMediaSeeking - , public IAMOpenProgress - , public IAMMediaContent - , public IAMExtendedSeeking - , public IKeyFrameInfo - , public IBufferInfo -{ - CCritSec m_csPinMap; - CAtlMap m_pPinMap; - - CCritSec m_csmtnew; - CAtlMap m_mtnew; - - CAutoPtrList m_pRetiredOutputs; - - CComQIPtr m_pSyncReader; - -protected: - CStringW m_fn; - - CAutoPtr m_pInput; - CAutoPtrList m_pOutputs; - - CBaseSplitterOutputPin* GetOutputPin(DWORD TrackNum); - DWORD GetOutputTrackNum(CBaseSplitterOutputPin* pPin); - HRESULT AddOutputPin(DWORD TrackNum, CAutoPtr pPin); - HRESULT RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt); - virtual HRESULT DeleteOutputs(); - virtual HRESULT CreateOutputs(IAsyncReader* pAsyncReader) = 0; // override this ... - virtual LPCTSTR GetPartFilename(IAsyncReader* pAsyncReader); - - LONGLONG m_nOpenProgress; - bool m_fAbort; - - REFERENCE_TIME m_rtDuration; // derived filter should set this at the end of CreateOutputs - REFERENCE_TIME m_rtStart, m_rtStop, m_rtCurrent, m_rtNewStart, m_rtNewStop; - double m_dRate; - - CAtlList m_bDiscontinuitySent; - CAtlList m_pActivePins; - - CAMEvent m_eEndFlush; - bool m_fFlushing; - - void DeliverBeginFlush(); - void DeliverEndFlush(); - HRESULT DeliverPacket(CAutoPtr p); - - int m_priority; - - CFontInstaller m_fontinst; - - int m_QueueMaxPackets; - -protected: - enum { CMD_EXIT, CMD_SEEK }; - DWORD ThreadProc(); - - // ... and also override all these too - virtual bool DemuxInit() = 0; - virtual void DemuxSeek(REFERENCE_TIME rt) = 0; - virtual bool DemuxLoop() = 0; - virtual bool BuildPlaylist(LPCTSTR pszFileName, CAtlList& Items) { return false; }; - virtual bool BuildChapters(LPCTSTR pszFileName, CAtlList& PlaylistItems, CAtlList& Items) { return false; }; - -public: - CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, - const CLSID& clsid, int QueueMaxPackets = MAXPACKETS); - virtual ~CBaseSplitterFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - bool IsAnyPinDrying(); - - HRESULT BreakConnect(PIN_DIRECTION dir, CBasePin* pPin); - HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin); - - int GetPinCount(); - CBasePin* GetPin(int n); - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // IFileSourceFilter - - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - -protected: - friend class CBaseSplitterOutputPin; - virtual HRESULT SetPositionsInternal(void* id, LONGLONG* pCurrent, - DWORD dwCurrentFlags, LONGLONG* pStop, - DWORD dwStopFlags); - -private: - REFERENCE_TIME m_rtLastStart, m_rtLastStop; - CAtlList m_LastSeekers; - -public: - // IAMOpenProgress - - STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent); - STDMETHODIMP AbortOperation(); - - // IDispatch - - STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } - STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { return E_NOTIMPL; } - STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { return E_NOTIMPL; } - STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) { return E_NOTIMPL; } - - // IAMMediaContent - - STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName); - STDMETHODIMP get_Title(BSTR* pbstrTitle); - STDMETHODIMP get_Rating(BSTR* pbstrRating); - STDMETHODIMP get_Description(BSTR* pbstrDescription); - STDMETHODIMP get_Copyright(BSTR* pbstrCopyright); - STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL) { return E_NOTIMPL; } - STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; } - STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; } - STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL) { return E_NOTIMPL; } - STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL) { return E_NOTIMPL; } - STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) { return E_NOTIMPL; } - STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) { return E_NOTIMPL; } - STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText) { return E_NOTIMPL; } - - // IAMExtendedSeeking - - STDMETHODIMP get_ExSeekCapabilities(long* pExCapabilities); - STDMETHODIMP get_MarkerCount(long* pMarkerCount); - STDMETHODIMP get_CurrentMarker(long* pCurrentMarker); - STDMETHODIMP GetMarkerTime(long MarkerNum, double* pMarkerTime); - STDMETHODIMP GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName); - STDMETHODIMP put_PlaybackSpeed(double Speed) { return E_NOTIMPL; } - STDMETHODIMP get_PlaybackSpeed(double* pSpeed) { return E_NOTIMPL; } - - // IKeyFrameInfo - - STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs); - STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs); - - // IBufferInfo - - STDMETHODIMP_(int) GetCount(); - STDMETHODIMP GetStatus(int i, int& samples, int& size); - STDMETHODIMP_(DWORD) GetPriority(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#pragma once + +#include +#include +#include +#include "IKeyFrameInfo.h" +#include "IBufferInfo.h" +#include "IBitRateInfo.h" +#include "AsyncReader.h" +#include "../../../DSUtil/DSMPropertyBag.h" +#include "../../../DSUtil/FontInstaller.h" + +#define MINPACKETS 100 // Beliyaal: Changed the min number of packets to allow Bluray playback over network +#define MINPACKETSIZE 256*1024 // Beliyaal: Changed the min packet size to allow Bluray playback over network +#define MAXPACKETS 2000 +#define MAXPACKETSIZE 128*1024*1024 + +class Packet : public CAtlArray +{ +public: + DWORD TrackNumber; + BOOL bDiscontinuity, bSyncPoint, bAppendable; + static const REFERENCE_TIME INVALID_TIME = _I64_MIN; + REFERENCE_TIME rtStart, rtStop; + AM_MEDIA_TYPE* pmt; + Packet() + : TrackNumber(0) + , bDiscontinuity(FALSE) + , bSyncPoint(FALSE) + , bAppendable(FALSE) + , rtStart(0) + , rtStop(0) + , pmt(nullptr) { + } + virtual ~Packet() { + if (pmt) { + DeleteMediaType(pmt); + } + } + virtual int GetDataSize() { return (int)GetCount(); } + void SetData(const void* ptr, DWORD len) { + SetCount(len); + memcpy(GetData(), ptr, len); + } +}; + +class CPacketQueue2 + : public CCritSec + , protected CAutoPtrList +{ + int m_size; + +public: + CPacketQueue2(); + void Add(CAutoPtr p); + CAutoPtr Remove(); + void RemoveAll(); + int GetCount(), GetSize(); +}; + +class CBaseSplitterFilter; + +class CBaseSplitterInputPin + : public CBasePin +{ +protected: + CComQIPtr m_pAsyncReader; + +public: + CBaseSplitterInputPin(LPCTSTR pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CBaseSplitterInputPin(); + + HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT CheckMediaType(const CMediaType* pmt); + + HRESULT CheckConnect(IPin* pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pPin); + + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); +}; + +class CBaseSplitterOutputPin + : public CBaseOutputPin + , public IDSMPropertyBagImpl + , protected CAMThread + , public IMediaSeeking + , public IBitRateInfo +{ +protected: + CAtlArray m_mts; + int m_nBuffers; + +private: + CPacketQueue2 m_queue; + + HRESULT m_hrDeliver; + + bool m_fFlushing, m_fFlushed; + CAMEvent m_eEndFlush; + + enum { CMD_EXIT }; + DWORD ThreadProc(); + + void MakeISCRHappy(); + + // please only use DeliverPacket from the derived class + HRESULT GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags); + HRESULT Deliver(IMediaSample* pSample); + + // IBitRateInfo + struct BitRateInfo { + UINT64 nTotalBytesDelivered = 0; + REFERENCE_TIME rtTotalTimeDelivered = 0; + UINT64 nBytesSinceLastDeliverTime = 0; + REFERENCE_TIME rtLastDeliverTime = Packet::INVALID_TIME; + DWORD nCurrentBitRate = 0; + DWORD nAverageBitRate = 0; + } m_BitRate; + + int m_QueueMaxPackets; + +protected: + REFERENCE_TIME m_rtStart; + + // override this if you need some second level stream specific demuxing (optional) + // the default implementation will send the sample as is + virtual HRESULT DeliverPacket(CAutoPtr p); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + +public: + CBaseSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, + CBaseFilter* pFilter, CCritSec* pLock, + HRESULT* phr, int nBuffers = 0, + int QueueMaxPackets = MAXPACKETS); + CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, + CCritSec* pLock, HRESULT* phr, + int nBuffers = 0, + int QueueMaxPackets = MAXPACKETS); + virtual ~CBaseSplitterOutputPin(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT SetName(LPCWSTR pName); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + CMediaType& CurrentMediaType() { return m_mt; } + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); + + // Queueing + + HANDLE GetThreadHandle() { + ASSERT(m_hThread != nullptr); + return m_hThread; + } + void SetThreadPriority(int nPriority) { + if (m_hThread) { + ::SetThreadPriority(m_hThread, nPriority); + } + } + + HRESULT Active(); + HRESULT Inactive(); + + HRESULT DeliverBeginFlush(); + HRESULT DeliverEndFlush(); + HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + int QueueCount(); + int QueueSize(); + HRESULT QueueEndOfStream(); + HRESULT QueuePacket(CAutoPtr p); + + // returns true for everything which (the lack of) would not block other streams (subtitle streams, basically) + virtual bool IsDiscontinuous(); + + // returns IStreamsSwitcherInputPin::IsActive(), when it can find one downstream + bool IsActive(); + + // IBitRateInfo + + STDMETHODIMP_(DWORD) GetCurrentBitRate() { return m_BitRate.nCurrentBitRate; } + STDMETHODIMP_(DWORD) GetAverageBitRate() { return m_BitRate.nAverageBitRate; } +}; + +class CBaseSplitterFilter + : public CBaseFilter + , public CCritSec + , public IDSMPropertyBagImpl + , public IDSMResourceBagImpl + , public IDSMChapterBagImpl + , protected CAMThread + , public IFileSourceFilter + , public IMediaSeeking + , public IAMOpenProgress + , public IAMMediaContent + , public IAMExtendedSeeking + , public IKeyFrameInfo + , public IBufferInfo +{ + CCritSec m_csPinMap; + CAtlMap m_pPinMap; + + CCritSec m_csmtnew; + CAtlMap m_mtnew; + + CAutoPtrList m_pRetiredOutputs; + + CComQIPtr m_pSyncReader; + +protected: + CStringW m_fn; + + CAutoPtr m_pInput; + CAutoPtrList m_pOutputs; + + CBaseSplitterOutputPin* GetOutputPin(DWORD TrackNum); + DWORD GetOutputTrackNum(CBaseSplitterOutputPin* pPin); + HRESULT AddOutputPin(DWORD TrackNum, CAutoPtr pPin); + HRESULT RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt); + virtual HRESULT DeleteOutputs(); + virtual HRESULT CreateOutputs(IAsyncReader* pAsyncReader) = 0; // override this ... + virtual LPCTSTR GetPartFilename(IAsyncReader* pAsyncReader); + + LONGLONG m_nOpenProgress; + bool m_fAbort; + + REFERENCE_TIME m_rtDuration; // derived filter should set this at the end of CreateOutputs + REFERENCE_TIME m_rtStart, m_rtStop, m_rtCurrent, m_rtNewStart, m_rtNewStop; + double m_dRate; + + CAtlList m_bDiscontinuitySent; + CAtlList m_pActivePins; + + CAMEvent m_eEndFlush; + bool m_fFlushing; + + void DeliverBeginFlush(); + void DeliverEndFlush(); + HRESULT DeliverPacket(CAutoPtr p); + + int m_priority; + + CFontInstaller m_fontinst; + + int m_QueueMaxPackets; + +protected: + enum { CMD_EXIT, CMD_SEEK }; + DWORD ThreadProc(); + + // ... and also override all these too + virtual bool DemuxInit() = 0; + virtual void DemuxSeek(REFERENCE_TIME rt) = 0; + virtual bool DemuxLoop() = 0; + virtual bool BuildPlaylist(LPCTSTR pszFileName, CAtlList& Items) { return false; }; + virtual bool BuildChapters(LPCTSTR pszFileName, CAtlList& PlaylistItems, CAtlList& Items) { return false; }; + +public: + CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, + const CLSID& clsid, int QueueMaxPackets = MAXPACKETS); + virtual ~CBaseSplitterFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + bool IsAnyPinDrying(); + + HRESULT BreakConnect(PIN_DIRECTION dir, CBasePin* pPin); + HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin); + + int GetPinCount(); + CBasePin* GetPin(int n); + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // IFileSourceFilter + + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + +protected: + friend class CBaseSplitterOutputPin; + virtual HRESULT SetPositionsInternal(void* id, LONGLONG* pCurrent, + DWORD dwCurrentFlags, LONGLONG* pStop, + DWORD dwStopFlags); + +private: + REFERENCE_TIME m_rtLastStart, m_rtLastStop; + CAtlList m_LastSeekers; + +public: + // IAMOpenProgress + + STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent); + STDMETHODIMP AbortOperation(); + + // IDispatch + + STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } + STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { return E_NOTIMPL; } + STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) { return E_NOTIMPL; } + STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) { return E_NOTIMPL; } + + // IAMMediaContent + + STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName); + STDMETHODIMP get_Title(BSTR* pbstrTitle); + STDMETHODIMP get_Rating(BSTR* pbstrRating); + STDMETHODIMP get_Description(BSTR* pbstrDescription); + STDMETHODIMP get_Copyright(BSTR* pbstrCopyright); + STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL) { return E_NOTIMPL; } + STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; } + STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL) { return E_NOTIMPL; } + STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL) { return E_NOTIMPL; } + STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL) { return E_NOTIMPL; } + STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) { return E_NOTIMPL; } + STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) { return E_NOTIMPL; } + STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText) { return E_NOTIMPL; } + + // IAMExtendedSeeking + + STDMETHODIMP get_ExSeekCapabilities(long* pExCapabilities); + STDMETHODIMP get_MarkerCount(long* pMarkerCount); + STDMETHODIMP get_CurrentMarker(long* pCurrentMarker); + STDMETHODIMP GetMarkerTime(long MarkerNum, double* pMarkerTime); + STDMETHODIMP GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName); + STDMETHODIMP put_PlaybackSpeed(double Speed) { return E_NOTIMPL; } + STDMETHODIMP get_PlaybackSpeed(double* pSpeed) { return E_NOTIMPL; } + + // IKeyFrameInfo + + STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs); + STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs); + + // IBufferInfo + + STDMETHODIMP_(int) GetCount(); + STDMETHODIMP GetStatus(int i, int& samples, int& size); + STDMETHODIMP_(DWORD) GetPriority(); +}; diff --git a/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj b/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj index 35ba07511b3..ababd13b4a5 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj +++ b/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj @@ -1,72 +1,72 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {37768B3F-89BC-4C16-B2A8-767C5DA84C3F} - BaseSplitter - MFCProj - BaseSplitter - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - - - Create - - - - - - - - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {37768B3F-89BC-4C16-B2A8-767C5DA84C3F} + BaseSplitter + MFCProj + BaseSplitter + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + + + Create + + + + + + + + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj.filters b/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj.filters index 652569ca26a..0d75cd1e58f 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj.filters +++ b/src/filters/parser/BaseSplitter/BaseSplitter.vcxproj.filters @@ -1,47 +1,47 @@ - - - - - {b95be5c7-0978-4aad-b33b-140fbdb42012} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {c2020e7a-be9e-43da-8a23-fe30c723d21d} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {b95be5c7-0978-4aad-b33b-140fbdb42012} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2020e7a-be9e-43da-8a23-fe30c723d21d} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/parser/BaseSplitter/BaseSplitterFile.cpp b/src/filters/parser/BaseSplitter/BaseSplitterFile.cpp index 597b5e5d040..f549c0aa65e 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitterFile.cpp +++ b/src/filters/parser/BaseSplitter/BaseSplitterFile.cpp @@ -1,259 +1,259 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "BaseSplitterFile.h" -#include "../../../DSUtil/DSUtil.h" - -// -// CBaseSplitterFile -// - -CBaseSplitterFile::CBaseSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr, int cachelen, bool fRandomAccess, bool fStreaming) - : m_pAsyncReader(pAsyncReader) - , m_cachepos(0) - , m_cachelen(0) - , m_cachetotal(0) - , m_fStreaming(false) - , m_fRandomAccess(false) - , m_pos(0) - , m_len(0) - , m_bitbuff(0) - , m_bitlen(0) -{ - if (!m_pAsyncReader) { - hr = E_UNEXPECTED; - return; - } - - LONGLONG total = 0, available; - hr = m_pAsyncReader->Length(&total, &available); - - m_fStreaming = total == 0 && available > 0; - m_fRandomAccess = total > 0 && total == available; - m_len = total; - - if (FAILED(hr) || fRandomAccess && !m_fRandomAccess || !fStreaming && m_fStreaming || m_len < 0) { - hr = E_FAIL; - return; - } - - if (!SetCacheSize(cachelen)) { - hr = E_OUTOFMEMORY; - return; - } - - hr = S_OK; -} - -bool CBaseSplitterFile::SetCacheSize(int cachelen) -{ - m_pCache.Free(); - m_cachetotal = 0; - if (!m_pCache.Allocate((size_t)cachelen)) { - return false; - } - m_cachetotal = cachelen; - m_cachelen = 0; - return true; -} - -__int64 CBaseSplitterFile::GetPos() -{ - return m_pos - (m_bitlen >> 3); -} - -__int64 CBaseSplitterFile::GetAvailable() -{ - LONGLONG total, available = 0; - m_pAsyncReader->Length(&total, &available); - return available; -} - -__int64 CBaseSplitterFile::GetLength(bool fUpdate) -{ - if (m_fStreaming) { - m_len = GetAvailable(); - } else if (fUpdate) { - LONGLONG total = 0, available; - m_pAsyncReader->Length(&total, &available); - m_len = total; - } - - return m_len; -} - -void CBaseSplitterFile::Seek(__int64 pos) -{ - __int64 len = GetLength(); - m_pos = std::min(std::max(pos, 0ll), len); - BitFlush(); -} - -HRESULT CBaseSplitterFile::Read(BYTE* pData, __int64 len) -{ - CheckPointer(m_pAsyncReader, E_NOINTERFACE); - - HRESULT hr = S_OK; - - if (!m_fRandomAccess) { - LONGLONG total = 0, available = -1; - m_pAsyncReader->Length(&total, &available); - if (total == available) { - m_fRandomAccess = true; - OnComplete(); - } - } - - if (m_cachetotal == 0 || !m_pCache) { - hr = m_pAsyncReader->SyncRead(m_pos, (long)len, pData); - m_pos += len; - return hr; - } - - BYTE* pCache = m_pCache; - - if (m_cachepos <= m_pos && m_pos < m_cachepos + m_cachelen) { - __int64 minlen = std::min(len, m_cachelen - (m_pos - m_cachepos)); - - memcpy(pData, &pCache[m_pos - m_cachepos], (size_t)minlen); - - len -= minlen; - m_pos += minlen; - pData += minlen; - } - - while (len > m_cachetotal) { - hr = m_pAsyncReader->SyncRead(m_pos, (long)m_cachetotal, pData); - if (S_OK != hr) { - return hr; - } - - len -= m_cachetotal; - m_pos += m_cachetotal; - pData += m_cachetotal; - } - - while (len > 0) { - __int64 tmplen = GetLength(); - __int64 maxlen = std::min(tmplen - m_pos, m_cachetotal); - __int64 minlen = std::min(len, maxlen); - if (minlen <= 0) { - return S_FALSE; - } - - hr = m_pAsyncReader->SyncRead(m_pos, (long)maxlen, pCache); - if (S_OK != hr) { - return hr; - } - - m_cachepos = m_pos; - m_cachelen = maxlen; - - memcpy(pData, pCache, (size_t)minlen); - - len -= minlen; - m_pos += minlen; - pData += minlen; - } - - return hr; -} - -UINT64 CBaseSplitterFile::BitRead(int nBits, bool fPeek) -{ - ASSERT(nBits >= 0 && nBits <= 64); - - while (m_bitlen < nBits) { - m_bitbuff <<= 8; - if (S_OK != Read((BYTE*)&m_bitbuff, 1)) { - return 0; // EOF? // ASSERT(0); - } - m_bitlen += 8; - } - - int bitlen = m_bitlen - nBits; - - UINT64 ret; - // The shift to 64 bits can give incorrect results. - // "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." - if (nBits == 64) { - ret = m_bitbuff; - } else { - ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); - } - - if (!fPeek) { - m_bitbuff &= ((1ui64 << bitlen) - 1); - m_bitlen = bitlen; - } - - return ret; -} - -void CBaseSplitterFile::BitByteAlign() -{ - m_bitlen &= ~7; -} - -void CBaseSplitterFile::BitFlush() -{ - m_bitlen = 0; -} - -HRESULT CBaseSplitterFile::ByteRead(BYTE* pData, __int64 len) -{ - Seek(GetPos()); - return Read(pData, len); -} - -UINT64 CBaseSplitterFile::UExpGolombRead() -{ - int n = -1; - for (BYTE b = 0; !b; n++) { - b = (BYTE)BitRead(1); - } - return (1ui64 << n) - 1 + BitRead(n); -} - -INT64 CBaseSplitterFile::SExpGolombRead() -{ - UINT64 k = UExpGolombRead(); - return ((k & 1) ? 1 : -1) * ((k + 1) >> 1); -} - -HRESULT CBaseSplitterFile::HasMoreData(__int64 len, DWORD ms) -{ - __int64 available = GetLength() - GetPos(); - - if (!m_fStreaming) { - return available < 1 ? E_FAIL : S_OK; - } - - if (available < len) { - if (ms > 0) { - Sleep(ms); - } - return S_FALSE; - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "BaseSplitterFile.h" +#include "../../../DSUtil/DSUtil.h" + +// +// CBaseSplitterFile +// + +CBaseSplitterFile::CBaseSplitterFile(IAsyncReader* pAsyncReader, HRESULT& hr, int cachelen, bool fRandomAccess, bool fStreaming) + : m_pAsyncReader(pAsyncReader) + , m_cachepos(0) + , m_cachelen(0) + , m_cachetotal(0) + , m_fStreaming(false) + , m_fRandomAccess(false) + , m_pos(0) + , m_len(0) + , m_bitbuff(0) + , m_bitlen(0) +{ + if (!m_pAsyncReader) { + hr = E_UNEXPECTED; + return; + } + + LONGLONG total = 0, available; + hr = m_pAsyncReader->Length(&total, &available); + + m_fStreaming = total == 0 && available > 0; + m_fRandomAccess = total > 0 && total == available; + m_len = total; + + if (FAILED(hr) || fRandomAccess && !m_fRandomAccess || !fStreaming && m_fStreaming || m_len < 0) { + hr = E_FAIL; + return; + } + + if (!SetCacheSize(cachelen)) { + hr = E_OUTOFMEMORY; + return; + } + + hr = S_OK; +} + +bool CBaseSplitterFile::SetCacheSize(int cachelen) +{ + m_pCache.Free(); + m_cachetotal = 0; + if (!m_pCache.Allocate((size_t)cachelen)) { + return false; + } + m_cachetotal = cachelen; + m_cachelen = 0; + return true; +} + +__int64 CBaseSplitterFile::GetPos() +{ + return m_pos - (m_bitlen >> 3); +} + +__int64 CBaseSplitterFile::GetAvailable() +{ + LONGLONG total, available = 0; + m_pAsyncReader->Length(&total, &available); + return available; +} + +__int64 CBaseSplitterFile::GetLength(bool fUpdate) +{ + if (m_fStreaming) { + m_len = GetAvailable(); + } else if (fUpdate) { + LONGLONG total = 0, available; + m_pAsyncReader->Length(&total, &available); + m_len = total; + } + + return m_len; +} + +void CBaseSplitterFile::Seek(__int64 pos) +{ + __int64 len = GetLength(); + m_pos = std::min(std::max(pos, 0ll), len); + BitFlush(); +} + +HRESULT CBaseSplitterFile::Read(BYTE* pData, __int64 len) +{ + CheckPointer(m_pAsyncReader, E_NOINTERFACE); + + HRESULT hr = S_OK; + + if (!m_fRandomAccess) { + LONGLONG total = 0, available = -1; + m_pAsyncReader->Length(&total, &available); + if (total == available) { + m_fRandomAccess = true; + OnComplete(); + } + } + + if (m_cachetotal == 0 || !m_pCache) { + hr = m_pAsyncReader->SyncRead(m_pos, (long)len, pData); + m_pos += len; + return hr; + } + + BYTE* pCache = m_pCache; + + if (m_cachepos <= m_pos && m_pos < m_cachepos + m_cachelen) { + __int64 minlen = std::min(len, m_cachelen - (m_pos - m_cachepos)); + + memcpy(pData, &pCache[m_pos - m_cachepos], (size_t)minlen); + + len -= minlen; + m_pos += minlen; + pData += minlen; + } + + while (len > m_cachetotal) { + hr = m_pAsyncReader->SyncRead(m_pos, (long)m_cachetotal, pData); + if (S_OK != hr) { + return hr; + } + + len -= m_cachetotal; + m_pos += m_cachetotal; + pData += m_cachetotal; + } + + while (len > 0) { + __int64 tmplen = GetLength(); + __int64 maxlen = std::min(tmplen - m_pos, m_cachetotal); + __int64 minlen = std::min(len, maxlen); + if (minlen <= 0) { + return S_FALSE; + } + + hr = m_pAsyncReader->SyncRead(m_pos, (long)maxlen, pCache); + if (S_OK != hr) { + return hr; + } + + m_cachepos = m_pos; + m_cachelen = maxlen; + + memcpy(pData, pCache, (size_t)minlen); + + len -= minlen; + m_pos += minlen; + pData += minlen; + } + + return hr; +} + +UINT64 CBaseSplitterFile::BitRead(int nBits, bool fPeek) +{ + ASSERT(nBits >= 0 && nBits <= 64); + + while (m_bitlen < nBits) { + m_bitbuff <<= 8; + if (S_OK != Read((BYTE*)&m_bitbuff, 1)) { + return 0; // EOF? // ASSERT(0); + } + m_bitlen += 8; + } + + int bitlen = m_bitlen - nBits; + + UINT64 ret; + // The shift to 64 bits can give incorrect results. + // "The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand." + if (nBits == 64) { + ret = m_bitbuff; + } else { + ret = (m_bitbuff >> bitlen) & ((1ui64 << nBits) - 1); + } + + if (!fPeek) { + m_bitbuff &= ((1ui64 << bitlen) - 1); + m_bitlen = bitlen; + } + + return ret; +} + +void CBaseSplitterFile::BitByteAlign() +{ + m_bitlen &= ~7; +} + +void CBaseSplitterFile::BitFlush() +{ + m_bitlen = 0; +} + +HRESULT CBaseSplitterFile::ByteRead(BYTE* pData, __int64 len) +{ + Seek(GetPos()); + return Read(pData, len); +} + +UINT64 CBaseSplitterFile::UExpGolombRead() +{ + int n = -1; + for (BYTE b = 0; !b; n++) { + b = (BYTE)BitRead(1); + } + return (1ui64 << n) - 1 + BitRead(n); +} + +INT64 CBaseSplitterFile::SExpGolombRead() +{ + UINT64 k = UExpGolombRead(); + return ((k & 1) ? 1 : -1) * ((k + 1) >> 1); +} + +HRESULT CBaseSplitterFile::HasMoreData(__int64 len, DWORD ms) +{ + __int64 available = GetLength() - GetPos(); + + if (!m_fStreaming) { + return available < 1 ? E_FAIL : S_OK; + } + + if (available < len) { + if (ms > 0) { + Sleep(ms); + } + return S_FALSE; + } + + return S_OK; +} diff --git a/src/filters/parser/BaseSplitter/BaseSplitterFile.h b/src/filters/parser/BaseSplitter/BaseSplitterFile.h index ddcff2321ec..1069832ecdc 100644 --- a/src/filters/parser/BaseSplitter/BaseSplitterFile.h +++ b/src/filters/parser/BaseSplitter/BaseSplitterFile.h @@ -1,71 +1,71 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include - -#define DEFAULT_CACHE_LENGTH 64*1024 // Beliyaal: Changed the default cache length to allow Bluray playback over network - -class CBaseSplitterFile -{ - CComPtr m_pAsyncReader; - CAutoVectorPtr m_pCache; - __int64 m_cachepos, m_cachelen, m_cachetotal; - - bool m_fStreaming, m_fRandomAccess; - __int64 m_pos, m_len; - - virtual HRESULT Read(BYTE* pData, __int64 len); // use ByteRead - -protected: - UINT64 m_bitbuff; - int m_bitlen; - - virtual void OnComplete() {} - -public: - CBaseSplitterFile(IAsyncReader* pReader, HRESULT& hr, - int cachelen = DEFAULT_CACHE_LENGTH, - bool fRandomAccess = true, bool fStreaming = false); - virtual ~CBaseSplitterFile() {} - - bool SetCacheSize(int cachelen = DEFAULT_CACHE_LENGTH); - - __int64 GetPos(); - __int64 GetAvailable(); - __int64 GetLength(bool fUpdate = false); - __int64 GetRemaining() { return std::max(0ll, GetLength() - GetPos()); } - virtual void Seek(__int64 pos); - - UINT64 UExpGolombRead(); - INT64 SExpGolombRead(); - - UINT64 BitRead(int nBits, bool fPeek = false); - void BitByteAlign(), BitFlush(); - HRESULT ByteRead(BYTE* pData, __int64 len); - - bool IsStreaming() const { return m_fStreaming; } - bool IsRandomAccess() const { return m_fRandomAccess; } - - HRESULT HasMoreData(__int64 len = 1, DWORD ms = 1); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include + +#define DEFAULT_CACHE_LENGTH 64*1024 // Beliyaal: Changed the default cache length to allow Bluray playback over network + +class CBaseSplitterFile +{ + CComPtr m_pAsyncReader; + CAutoVectorPtr m_pCache; + __int64 m_cachepos, m_cachelen, m_cachetotal; + + bool m_fStreaming, m_fRandomAccess; + __int64 m_pos, m_len; + + virtual HRESULT Read(BYTE* pData, __int64 len); // use ByteRead + +protected: + UINT64 m_bitbuff; + int m_bitlen; + + virtual void OnComplete() {} + +public: + CBaseSplitterFile(IAsyncReader* pReader, HRESULT& hr, + int cachelen = DEFAULT_CACHE_LENGTH, + bool fRandomAccess = true, bool fStreaming = false); + virtual ~CBaseSplitterFile() {} + + bool SetCacheSize(int cachelen = DEFAULT_CACHE_LENGTH); + + __int64 GetPos(); + __int64 GetAvailable(); + __int64 GetLength(bool fUpdate = false); + __int64 GetRemaining() { return std::max(0ll, GetLength() - GetPos()); } + virtual void Seek(__int64 pos); + + UINT64 UExpGolombRead(); + INT64 SExpGolombRead(); + + UINT64 BitRead(int nBits, bool fPeek = false); + void BitByteAlign(), BitFlush(); + HRESULT ByteRead(BYTE* pData, __int64 len); + + bool IsStreaming() const { return m_fStreaming; } + bool IsRandomAccess() const { return m_fRandomAccess; } + + HRESULT HasMoreData(__int64 len = 1, DWORD ms = 1); +}; diff --git a/src/filters/parser/BaseSplitter/MultiFiles.cpp b/src/filters/parser/BaseSplitter/MultiFiles.cpp index eabd492d907..d422f85ff2d 100644 --- a/src/filters/parser/BaseSplitter/MultiFiles.cpp +++ b/src/filters/parser/BaseSplitter/MultiFiles.cpp @@ -1,198 +1,198 @@ -/* - * (C) 2009-2014 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 . - * - */ - - -#include "stdafx.h" -#include "MultiFiles.h" - - -IMPLEMENT_DYNAMIC(CMultiFiles, CObject) - -CMultiFiles::CMultiFiles() - : m_pCurrentPTSOffset(nullptr) - , m_hFile(INVALID_HANDLE_VALUE) - , m_nCurPart(-1) - , m_llTotalLength(0) -{ -} - -void CMultiFiles::Reset() -{ - m_strFiles.RemoveAll(); - m_FilesSize.RemoveAll(); - m_rtPtsOffsets.RemoveAll(); - m_llTotalLength = 0; -} - -BOOL CMultiFiles::Open(LPCTSTR lpszFileName, UINT nOpenFlags) -{ - Reset(); - m_strFiles.Add(lpszFileName); - - return OpenPart(0); -} - -BOOL CMultiFiles::OpenFiles(CAtlList& files, UINT nOpenFlags) -{ - POSITION pos = files.GetHeadPosition(); - LARGE_INTEGER llSize; - int nPos = 0; - REFERENCE_TIME rtDur = 0; - - Reset(); - while (pos) { - CHdmvClipInfo::PlaylistItem& s = files.GetNext(pos); - m_strFiles.Add(s.m_strFileName); - if (!OpenPart(nPos)) { - return false; - } - - llSize.QuadPart = 0; - GetFileSizeEx(m_hFile, &llSize); - m_llTotalLength += llSize.QuadPart; - m_FilesSize.Add(llSize.QuadPart); - m_rtPtsOffsets.Add(rtDur); - rtDur += s.Duration(); - nPos++; - } - - if (files.GetCount() > 1) { - ClosePart(); - } - - return TRUE; -} - -ULONGLONG CMultiFiles::Seek(LONGLONG lOff, UINT nFrom) -{ - LARGE_INTEGER llNewPos; - LARGE_INTEGER llOff; - - if (m_strFiles.GetCount() == 1) { - llOff.QuadPart = lOff; - SetFilePointerEx(m_hFile, llOff, &llNewPos, nFrom); - - return llNewPos.QuadPart; - } else { - ULONGLONG lAbsolutePos = GetAbsolutePosition(lOff, nFrom); - int nNewPart = 0; - ULONGLONG llSum = 0; - - while (m_FilesSize[nNewPart] + llSum <= lAbsolutePos) { - llSum += m_FilesSize[nNewPart]; - nNewPart++; - } - - OpenPart(nNewPart); - llOff.QuadPart = lAbsolutePos - llSum; - SetFilePointerEx(m_hFile, llOff, &llNewPos, FILE_BEGIN); - - return llSum + llNewPos.QuadPart; - } -} - -ULONGLONG CMultiFiles::GetAbsolutePosition(LONGLONG lOff, UINT nFrom) -{ - LARGE_INTEGER llNoMove = {0, 0}; - LARGE_INTEGER llCurPos; - - switch (nFrom) { - case begin: - return lOff; - case current: - SetFilePointerEx(m_hFile, llNoMove, &llCurPos, FILE_CURRENT); - return llCurPos.QuadPart + lOff; - case end: - return m_llTotalLength - lOff; - default: - return 0; // just used to quash "not all control paths return a value" warning - } -} - -ULONGLONG CMultiFiles::GetLength() const -{ - if (m_strFiles.GetCount() == 1) { - LARGE_INTEGER llSize; - GetFileSizeEx(m_hFile, &llSize); - return llSize.QuadPart; - } else { - return m_llTotalLength; - } -} - -UINT CMultiFiles::Read(void* lpBuf, UINT nCount) -{ - DWORD dwRead; - do { - if (!ReadFile(m_hFile, lpBuf, nCount, &dwRead, nullptr)) { - break; - } - - if (dwRead != nCount && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)) { - OpenPart(m_nCurPart + 1); - lpBuf = (void*)((BYTE*)lpBuf + dwRead); - nCount -= dwRead; - } - } while (nCount != dwRead && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)); - return dwRead; -} - -void CMultiFiles::Close() -{ - ClosePart(); - Reset(); -} - -CMultiFiles::~CMultiFiles() -{ - Close(); -} - -BOOL CMultiFiles::OpenPart(int nPart) -{ - if (m_nCurPart == nPart) { - return TRUE; - } else { - CString fn; - - ClosePart(); - - fn = m_strFiles.GetAt(nPart); - m_hFile = CreateFile(fn, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); - - if (m_hFile != INVALID_HANDLE_VALUE) { - m_nCurPart = nPart; - if (m_pCurrentPTSOffset != nullptr) { - *m_pCurrentPTSOffset = m_rtPtsOffsets[nPart]; - } - } - - return (m_hFile != INVALID_HANDLE_VALUE); - } -} - -void CMultiFiles::ClosePart() -{ - if (m_hFile != INVALID_HANDLE_VALUE) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - m_nCurPart = -1; - } -} +/* + * (C) 2009-2014 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 . + * + */ + + +#include "stdafx.h" +#include "MultiFiles.h" + + +IMPLEMENT_DYNAMIC(CMultiFiles, CObject) + +CMultiFiles::CMultiFiles() + : m_pCurrentPTSOffset(nullptr) + , m_hFile(INVALID_HANDLE_VALUE) + , m_nCurPart(-1) + , m_llTotalLength(0) +{ +} + +void CMultiFiles::Reset() +{ + m_strFiles.RemoveAll(); + m_FilesSize.RemoveAll(); + m_rtPtsOffsets.RemoveAll(); + m_llTotalLength = 0; +} + +BOOL CMultiFiles::Open(LPCTSTR lpszFileName, UINT nOpenFlags) +{ + Reset(); + m_strFiles.Add(lpszFileName); + + return OpenPart(0); +} + +BOOL CMultiFiles::OpenFiles(CAtlList& files, UINT nOpenFlags) +{ + POSITION pos = files.GetHeadPosition(); + LARGE_INTEGER llSize; + int nPos = 0; + REFERENCE_TIME rtDur = 0; + + Reset(); + while (pos) { + CHdmvClipInfo::PlaylistItem& s = files.GetNext(pos); + m_strFiles.Add(s.m_strFileName); + if (!OpenPart(nPos)) { + return false; + } + + llSize.QuadPart = 0; + GetFileSizeEx(m_hFile, &llSize); + m_llTotalLength += llSize.QuadPart; + m_FilesSize.Add(llSize.QuadPart); + m_rtPtsOffsets.Add(rtDur); + rtDur += s.Duration(); + nPos++; + } + + if (files.GetCount() > 1) { + ClosePart(); + } + + return TRUE; +} + +ULONGLONG CMultiFiles::Seek(LONGLONG lOff, UINT nFrom) +{ + LARGE_INTEGER llNewPos; + LARGE_INTEGER llOff; + + if (m_strFiles.GetCount() == 1) { + llOff.QuadPart = lOff; + SetFilePointerEx(m_hFile, llOff, &llNewPos, nFrom); + + return llNewPos.QuadPart; + } else { + ULONGLONG lAbsolutePos = GetAbsolutePosition(lOff, nFrom); + int nNewPart = 0; + ULONGLONG llSum = 0; + + while (m_FilesSize[nNewPart] + llSum <= lAbsolutePos) { + llSum += m_FilesSize[nNewPart]; + nNewPart++; + } + + OpenPart(nNewPart); + llOff.QuadPart = lAbsolutePos - llSum; + SetFilePointerEx(m_hFile, llOff, &llNewPos, FILE_BEGIN); + + return llSum + llNewPos.QuadPart; + } +} + +ULONGLONG CMultiFiles::GetAbsolutePosition(LONGLONG lOff, UINT nFrom) +{ + LARGE_INTEGER llNoMove = {0, 0}; + LARGE_INTEGER llCurPos; + + switch (nFrom) { + case begin: + return lOff; + case current: + SetFilePointerEx(m_hFile, llNoMove, &llCurPos, FILE_CURRENT); + return llCurPos.QuadPart + lOff; + case end: + return m_llTotalLength - lOff; + default: + return 0; // just used to quash "not all control paths return a value" warning + } +} + +ULONGLONG CMultiFiles::GetLength() const +{ + if (m_strFiles.GetCount() == 1) { + LARGE_INTEGER llSize; + GetFileSizeEx(m_hFile, &llSize); + return llSize.QuadPart; + } else { + return m_llTotalLength; + } +} + +UINT CMultiFiles::Read(void* lpBuf, UINT nCount) +{ + DWORD dwRead; + do { + if (!ReadFile(m_hFile, lpBuf, nCount, &dwRead, nullptr)) { + break; + } + + if (dwRead != nCount && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)) { + OpenPart(m_nCurPart + 1); + lpBuf = (void*)((BYTE*)lpBuf + dwRead); + nCount -= dwRead; + } + } while (nCount != dwRead && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)); + return dwRead; +} + +void CMultiFiles::Close() +{ + ClosePart(); + Reset(); +} + +CMultiFiles::~CMultiFiles() +{ + Close(); +} + +BOOL CMultiFiles::OpenPart(int nPart) +{ + if (m_nCurPart == nPart) { + return TRUE; + } else { + CString fn; + + ClosePart(); + + fn = m_strFiles.GetAt(nPart); + m_hFile = CreateFile(fn, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + + if (m_hFile != INVALID_HANDLE_VALUE) { + m_nCurPart = nPart; + if (m_pCurrentPTSOffset != nullptr) { + *m_pCurrentPTSOffset = m_rtPtsOffsets[nPart]; + } + } + + return (m_hFile != INVALID_HANDLE_VALUE); + } +} + +void CMultiFiles::ClosePart() +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + m_nCurPart = -1; + } +} diff --git a/src/filters/parser/BaseSplitter/MultiFiles.h b/src/filters/parser/BaseSplitter/MultiFiles.h index 1bddbdb77dc..7ea468fe98c 100644 --- a/src/filters/parser/BaseSplitter/MultiFiles.h +++ b/src/filters/parser/BaseSplitter/MultiFiles.h @@ -1,101 +1,101 @@ -/* - * (C) 2009-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 . - * - */ - -#pragma once - -#include -#include "../../../DSUtil/DSUtil.h" - -class CMultiFiles : public CObject -{ - DECLARE_DYNAMIC(CMultiFiles) - -public: - // Flag values - enum OpenFlags { - modeRead = (int)0x00000, - modeWrite = (int)0x00001, - modeReadWrite = (int)0x00002, - shareCompat = (int)0x00000, - shareExclusive = (int)0x00010, - shareDenyWrite = (int)0x00020, - shareDenyRead = (int)0x00030, - shareDenyNone = (int)0x00040, - modeNoInherit = (int)0x00080, - modeCreate = (int)0x01000, - modeNoTruncate = (int)0x02000, - typeText = (int)0x04000, // typeText and typeBinary are used in derived classes only - typeBinary = (int)0x08000, - osNoBuffer = (int)0x10000, - osWriteThrough = (int)0x20000, - osRandomAccess = (int)0x40000, - osSequentialScan = (int)0x80000 - }; - - enum Attribute { - normal = 0x00, - readOnly = 0x01, - hidden = 0x02, - system = 0x04, - volume = 0x08, - directory = 0x10, - archive = 0x20 - }; - - enum SeekPosition { - begin = 0x0, - current = 0x1, - end = 0x2 - }; - - // Constructors - CMultiFiles(); - - CString m_strFileName; - - // Operations - virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags); - virtual BOOL OpenFiles(CAtlList& files, UINT nOpenFlags); - - - virtual ULONGLONG Seek(LONGLONG lOff, UINT nFrom); - virtual ULONGLONG GetLength() const; - - virtual UINT Read(void* lpBuf, UINT nCount); - virtual void Close(); - - // Implementation -public: - virtual ~CMultiFiles(); - -protected: - REFERENCE_TIME* m_pCurrentPTSOffset; - CAtlArray m_strFiles; - CAtlArray m_FilesSize; - CAtlArray m_rtPtsOffsets; - HANDLE m_hFile; - int m_nCurPart; - ULONGLONG m_llTotalLength; - - BOOL OpenPart(int nPart); - void ClosePart(); - ULONGLONG GetAbsolutePosition(LONGLONG lOff, UINT nFrom); - void Reset(); -}; +/* + * (C) 2009-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 . + * + */ + +#pragma once + +#include +#include "../../../DSUtil/DSUtil.h" + +class CMultiFiles : public CObject +{ + DECLARE_DYNAMIC(CMultiFiles) + +public: + // Flag values + enum OpenFlags { + modeRead = (int)0x00000, + modeWrite = (int)0x00001, + modeReadWrite = (int)0x00002, + shareCompat = (int)0x00000, + shareExclusive = (int)0x00010, + shareDenyWrite = (int)0x00020, + shareDenyRead = (int)0x00030, + shareDenyNone = (int)0x00040, + modeNoInherit = (int)0x00080, + modeCreate = (int)0x01000, + modeNoTruncate = (int)0x02000, + typeText = (int)0x04000, // typeText and typeBinary are used in derived classes only + typeBinary = (int)0x08000, + osNoBuffer = (int)0x10000, + osWriteThrough = (int)0x20000, + osRandomAccess = (int)0x40000, + osSequentialScan = (int)0x80000 + }; + + enum Attribute { + normal = 0x00, + readOnly = 0x01, + hidden = 0x02, + system = 0x04, + volume = 0x08, + directory = 0x10, + archive = 0x20 + }; + + enum SeekPosition { + begin = 0x0, + current = 0x1, + end = 0x2 + }; + + // Constructors + CMultiFiles(); + + CString m_strFileName; + + // Operations + virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags); + virtual BOOL OpenFiles(CAtlList& files, UINT nOpenFlags); + + + virtual ULONGLONG Seek(LONGLONG lOff, UINT nFrom); + virtual ULONGLONG GetLength() const; + + virtual UINT Read(void* lpBuf, UINT nCount); + virtual void Close(); + + // Implementation +public: + virtual ~CMultiFiles(); + +protected: + REFERENCE_TIME* m_pCurrentPTSOffset; + CAtlArray m_strFiles; + CAtlArray m_FilesSize; + CAtlArray m_rtPtsOffsets; + HANDLE m_hFile; + int m_nCurPart; + ULONGLONG m_llTotalLength; + + BOOL OpenPart(int nPart); + void ClosePart(); + ULONGLONG GetAbsolutePosition(LONGLONG lOff, UINT nFrom); + void Reset(); +}; diff --git a/src/filters/parser/BaseSplitter/stdafx.cpp b/src/filters/parser/BaseSplitter/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/parser/BaseSplitter/stdafx.cpp +++ b/src/filters/parser/BaseSplitter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/parser/BaseSplitter/stdafx.h b/src/filters/parser/BaseSplitter/stdafx.h index a8517b3e334..619304dd68e 100644 --- a/src/filters/parser/BaseSplitter/stdafx.h +++ b/src/filters/parser/BaseSplitter/stdafx.h @@ -1,35 +1,35 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.cpp b/src/filters/parser/DSMSplitter/DSMSplitter.cpp index cc6cd4cf88f..d67b3f29f93 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.cpp +++ b/src/filters/parser/DSMSplitter/DSMSplitter.cpp @@ -1,291 +1,291 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include "../../../DSUtil/DSUtil.h" -#include "../../../DSUtil/ISOLang.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" -#include "DSMSplitter.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia}, - {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, 0, nullptr} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CDSMSplitterFilter), DSMSplitterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CDSMSourceFilter), DSMSourceName, MERIT_NORMAL, 0, nullptr, CLSID_LegacyAmFilterCategory}, -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, - {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - CString str; - str.Format(_T("0,%d,,%%0%dI64x"), DSMSW_SIZE, DSMSW_SIZE * 2); - str.Format(CString(str), DSMSW); - - RegisterSourceFilter( - CLSID_AsyncReader, - MEDIASUBTYPE_DirectShowMedia, - str, nullptr); - - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - UnRegisterSourceFilter(MEDIASUBTYPE_DirectShowMedia); - - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CDSMSplitterFilter -// - -CDSMSplitterFilter::CDSMSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseSplitterFilter(NAME("CDSMSplitterFilter"), pUnk, phr, __uuidof(this)) -{ -} - -CDSMSplitterFilter::~CDSMSplitterFilter() -{ -} - -STDMETHODIMP CDSMSplitterFilter::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - - if (m_pName && m_pName[0] == L'M' && m_pName[1] == L'P' && m_pName[2] == L'C') { - (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); - } else { - wcscpy_s(pInfo->achName, DSMSourceName); - } - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -HRESULT CDSMSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader) -{ - CheckPointer(pAsyncReader, E_POINTER); - - HRESULT hr = E_FAIL; - - m_pFile.Free(); - m_pFile.Attach(DEBUG_NEW CDSMSplitterFile(pAsyncReader, hr, *this, *this)); - if (!m_pFile) { - return E_OUTOFMEMORY; - } - if (FAILED(hr)) { - m_pFile.Free(); - return hr; - } - - m_rtNewStart = m_rtCurrent = 0; - m_rtNewStop = m_rtStop = m_rtDuration = m_pFile->m_rtDuration; - - CAtlArray ids; - - POSITION pos = m_pFile->m_mts.GetStartPosition(); - while (pos) { - BYTE id; - CMediaType mt; - m_pFile->m_mts.GetNextAssoc(pos, id, mt); - ids.Add(id); - } - - std::sort(ids.GetData(), ids.GetData() + ids.GetCount()); - - for (size_t i = 0; i < ids.GetCount(); i++) { - BYTE id = ids[i]; - CMediaType& mt = m_pFile->m_mts[id]; - - CStringW name, lang; - name.Format(L"Output %02u", id); - - CAtlArray mts; - mts.Add(mt); - - CAutoPtr pPinOut(DEBUG_NEW CBaseSplitterOutputPin(mts, name, this, this, &hr)); - - name.Empty(); - - pos = m_pFile->m_sim[id].GetStartPosition(); - while (pos) { - CStringA key; - CStringW value; - m_pFile->m_sim[id].GetNextAssoc(pos, key, value); - pPinOut->SetProperty(CStringW(key), value); - - if (key == "NAME") { - name = value; - } - if (key == "LANG") { - lang = ISOLang::ISO6392ToLanguage(CStringA(value)); - if (lang.IsEmpty()) { - lang = value; - } - } - } - - if (!name.IsEmpty() || !lang.IsEmpty()) { - if (!name.IsEmpty()) { - if (!lang.IsEmpty()) { - name += L" (" + lang + L")"; - } - } else if (!lang.IsEmpty()) { - name = lang; - } - pPinOut->SetName(name); - } - - EXECUTE_ASSERT(SUCCEEDED(AddOutputPin(id, pPinOut))); - } - - pos = m_pFile->m_fim.GetStartPosition(); - while (pos) { - CStringA key; - CStringW value; - m_pFile->m_fim.GetNextAssoc(pos, key, value); - SetProperty(CStringW(key), value); - } - - for (size_t i = 0; i < m_resources.GetCount(); i++) { - const CDSMResource& r = m_resources[i]; - if (r.mime == L"application/x-truetype-font" || - r.mime == L"application/x-font-ttf" || - r.mime == L"application/vnd.ms-opentype") { - //m_fontinst.InstallFont(r.data); - m_fontinst.InstallFontMemory(r.data.GetData(), (UINT)r.data.GetCount()); - } - } - - return !m_pOutputs.IsEmpty() ? S_OK : E_FAIL; -} - -bool CDSMSplitterFilter::DemuxInit() -{ - SetThreadName(DWORD(-1), "CDSMSplitterFilter"); - return true; -} - -void CDSMSplitterFilter::DemuxSeek(REFERENCE_TIME rt) -{ - m_pFile->Seek(m_pFile->FindSyncPoint(rt)); -} - -bool CDSMSplitterFilter::DemuxLoop() -{ - HRESULT hr = S_OK; - - while (SUCCEEDED(hr) && !CheckRequest(nullptr) && m_pFile->GetRemaining()) { - dsmp_t type; - UINT64 len; - - if (!m_pFile->Sync(type, len)) { - continue; - } - - __int64 pos = m_pFile->GetPos(); - - if (type == DSMP_SAMPLE) { - CAutoPtr p(DEBUG_NEW Packet()); - if (m_pFile->Read(len, p)) { - if (p->rtStart != Packet::INVALID_TIME) { - p->rtStart -= m_pFile->m_rtFirst; - p->rtStop -= m_pFile->m_rtFirst; - } - - hr = DeliverPacket(p); - } - } - - m_pFile->Seek(pos + len); - } - - return true; -} - -// IKeyFrameInfo - -STDMETHODIMP CDSMSplitterFilter::GetKeyFrameCount(UINT& nKFs) -{ - CheckPointer(m_pFile, E_UNEXPECTED); - nKFs = (UINT)m_pFile->m_sps.GetCount(); - return S_OK; -} - -STDMETHODIMP CDSMSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs) -{ - CheckPointer(pFormat, E_POINTER); - CheckPointer(pKFs, E_POINTER); - CheckPointer(m_pFile, E_UNEXPECTED); - - if (*pFormat != TIME_FORMAT_MEDIA_TIME) { - return E_INVALIDARG; - } - - // these aren't really the keyframes, but quicky accessable points in the stream - for (nKFs = 0; nKFs < m_pFile->m_sps.GetCount(); nKFs++) { - pKFs[nKFs] = m_pFile->m_sps[nKFs].rt; - } - - return S_OK; -} - -// -// CDSMSourceFilter -// - -CDSMSourceFilter::CDSMSourceFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CDSMSplitterFilter(pUnk, phr) -{ - m_clsid = __uuidof(this); - m_pInput.Free(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include "../../../DSUtil/DSUtil.h" +#include "../../../DSUtil/ISOLang.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" +#include "DSMSplitter.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_DirectShowMedia}, + {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, 0, nullptr} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CDSMSplitterFilter), DSMSplitterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CDSMSourceFilter), DSMSourceName, MERIT_NORMAL, 0, nullptr, CLSID_LegacyAmFilterCategory}, +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, + {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + CString str; + str.Format(_T("0,%d,,%%0%dI64x"), DSMSW_SIZE, DSMSW_SIZE * 2); + str.Format(CString(str), DSMSW); + + RegisterSourceFilter( + CLSID_AsyncReader, + MEDIASUBTYPE_DirectShowMedia, + str, nullptr); + + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + UnRegisterSourceFilter(MEDIASUBTYPE_DirectShowMedia); + + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CDSMSplitterFilter +// + +CDSMSplitterFilter::CDSMSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseSplitterFilter(NAME("CDSMSplitterFilter"), pUnk, phr, __uuidof(this)) +{ +} + +CDSMSplitterFilter::~CDSMSplitterFilter() +{ +} + +STDMETHODIMP CDSMSplitterFilter::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + + if (m_pName && m_pName[0] == L'M' && m_pName[1] == L'P' && m_pName[2] == L'C') { + (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); + } else { + wcscpy_s(pInfo->achName, DSMSourceName); + } + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +HRESULT CDSMSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader) +{ + CheckPointer(pAsyncReader, E_POINTER); + + HRESULT hr = E_FAIL; + + m_pFile.Free(); + m_pFile.Attach(DEBUG_NEW CDSMSplitterFile(pAsyncReader, hr, *this, *this)); + if (!m_pFile) { + return E_OUTOFMEMORY; + } + if (FAILED(hr)) { + m_pFile.Free(); + return hr; + } + + m_rtNewStart = m_rtCurrent = 0; + m_rtNewStop = m_rtStop = m_rtDuration = m_pFile->m_rtDuration; + + CAtlArray ids; + + POSITION pos = m_pFile->m_mts.GetStartPosition(); + while (pos) { + BYTE id; + CMediaType mt; + m_pFile->m_mts.GetNextAssoc(pos, id, mt); + ids.Add(id); + } + + std::sort(ids.GetData(), ids.GetData() + ids.GetCount()); + + for (size_t i = 0; i < ids.GetCount(); i++) { + BYTE id = ids[i]; + CMediaType& mt = m_pFile->m_mts[id]; + + CStringW name, lang; + name.Format(L"Output %02u", id); + + CAtlArray mts; + mts.Add(mt); + + CAutoPtr pPinOut(DEBUG_NEW CBaseSplitterOutputPin(mts, name, this, this, &hr)); + + name.Empty(); + + pos = m_pFile->m_sim[id].GetStartPosition(); + while (pos) { + CStringA key; + CStringW value; + m_pFile->m_sim[id].GetNextAssoc(pos, key, value); + pPinOut->SetProperty(CStringW(key), value); + + if (key == "NAME") { + name = value; + } + if (key == "LANG") { + lang = ISOLang::ISO6392ToLanguage(CStringA(value)); + if (lang.IsEmpty()) { + lang = value; + } + } + } + + if (!name.IsEmpty() || !lang.IsEmpty()) { + if (!name.IsEmpty()) { + if (!lang.IsEmpty()) { + name += L" (" + lang + L")"; + } + } else if (!lang.IsEmpty()) { + name = lang; + } + pPinOut->SetName(name); + } + + EXECUTE_ASSERT(SUCCEEDED(AddOutputPin(id, pPinOut))); + } + + pos = m_pFile->m_fim.GetStartPosition(); + while (pos) { + CStringA key; + CStringW value; + m_pFile->m_fim.GetNextAssoc(pos, key, value); + SetProperty(CStringW(key), value); + } + + for (size_t i = 0; i < m_resources.GetCount(); i++) { + const CDSMResource& r = m_resources[i]; + if (r.mime == L"application/x-truetype-font" || + r.mime == L"application/x-font-ttf" || + r.mime == L"application/vnd.ms-opentype") { + //m_fontinst.InstallFont(r.data); + m_fontinst.InstallFontMemory(r.data.GetData(), (UINT)r.data.GetCount()); + } + } + + return !m_pOutputs.IsEmpty() ? S_OK : E_FAIL; +} + +bool CDSMSplitterFilter::DemuxInit() +{ + SetThreadName(DWORD(-1), "CDSMSplitterFilter"); + return true; +} + +void CDSMSplitterFilter::DemuxSeek(REFERENCE_TIME rt) +{ + m_pFile->Seek(m_pFile->FindSyncPoint(rt)); +} + +bool CDSMSplitterFilter::DemuxLoop() +{ + HRESULT hr = S_OK; + + while (SUCCEEDED(hr) && !CheckRequest(nullptr) && m_pFile->GetRemaining()) { + dsmp_t type; + UINT64 len; + + if (!m_pFile->Sync(type, len)) { + continue; + } + + __int64 pos = m_pFile->GetPos(); + + if (type == DSMP_SAMPLE) { + CAutoPtr p(DEBUG_NEW Packet()); + if (m_pFile->Read(len, p)) { + if (p->rtStart != Packet::INVALID_TIME) { + p->rtStart -= m_pFile->m_rtFirst; + p->rtStop -= m_pFile->m_rtFirst; + } + + hr = DeliverPacket(p); + } + } + + m_pFile->Seek(pos + len); + } + + return true; +} + +// IKeyFrameInfo + +STDMETHODIMP CDSMSplitterFilter::GetKeyFrameCount(UINT& nKFs) +{ + CheckPointer(m_pFile, E_UNEXPECTED); + nKFs = (UINT)m_pFile->m_sps.GetCount(); + return S_OK; +} + +STDMETHODIMP CDSMSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs) +{ + CheckPointer(pFormat, E_POINTER); + CheckPointer(pKFs, E_POINTER); + CheckPointer(m_pFile, E_UNEXPECTED); + + if (*pFormat != TIME_FORMAT_MEDIA_TIME) { + return E_INVALIDARG; + } + + // these aren't really the keyframes, but quicky accessable points in the stream + for (nKFs = 0; nKFs < m_pFile->m_sps.GetCount(); nKFs++) { + pKFs[nKFs] = m_pFile->m_sps[nKFs].rt; + } + + return S_OK; +} + +// +// CDSMSourceFilter +// + +CDSMSourceFilter::CDSMSourceFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CDSMSplitterFilter(pUnk, phr) +{ + m_clsid = __uuidof(this); + m_pInput.Free(); +} diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.def b/src/filters/parser/DSMSplitter/DSMSplitter.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.def +++ b/src/filters/parser/DSMSplitter/DSMSplitter.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.h b/src/filters/parser/DSMSplitter/DSMSplitter.h index e12b1f823fc..0bdc7fab2e4 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.h +++ b/src/filters/parser/DSMSplitter/DSMSplitter.h @@ -1,61 +1,61 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include -#include "DSMSplitterFile.h" -#include "../BaseSplitter/BaseSplitter.h" - -#define DSMSplitterName L"MPC-HC DSM Splitter" -#define DSMSourceName L"MPC-HC DSM Source" - -class __declspec(uuid("0912B4DD-A30A-4568-B590-7179EBB420EC")) - CDSMSplitterFilter : public CBaseSplitterFilter -{ -protected: - CAutoPtr m_pFile; - HRESULT CreateOutputs(IAsyncReader* pAsyncReader); - - bool DemuxInit(); - void DemuxSeek(REFERENCE_TIME rt); - bool DemuxLoop(); - -public: - CDSMSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr); - virtual ~CDSMSplitterFilter(); - - // CBaseFilter - STDMETHODIMP_(HRESULT) QueryFilterInfo(FILTER_INFO* pInfo); - - // IKeyFrameInfo - - STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs); - STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs); -}; - -class __declspec(uuid("803E8280-F3CE-4201-982C-8CD8FB512004")) - CDSMSourceFilter : public CDSMSplitterFilter -{ -public: - CDSMSourceFilter(LPUNKNOWN pUnk, HRESULT* phr); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include +#include "DSMSplitterFile.h" +#include "../BaseSplitter/BaseSplitter.h" + +#define DSMSplitterName L"MPC-HC DSM Splitter" +#define DSMSourceName L"MPC-HC DSM Source" + +class __declspec(uuid("0912B4DD-A30A-4568-B590-7179EBB420EC")) + CDSMSplitterFilter : public CBaseSplitterFilter +{ +protected: + CAutoPtr m_pFile; + HRESULT CreateOutputs(IAsyncReader* pAsyncReader); + + bool DemuxInit(); + void DemuxSeek(REFERENCE_TIME rt); + bool DemuxLoop(); + +public: + CDSMSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr); + virtual ~CDSMSplitterFilter(); + + // CBaseFilter + STDMETHODIMP_(HRESULT) QueryFilterInfo(FILTER_INFO* pInfo); + + // IKeyFrameInfo + + STDMETHODIMP_(HRESULT) GetKeyFrameCount(UINT& nKFs); + STDMETHODIMP_(HRESULT) GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs); +}; + +class __declspec(uuid("803E8280-F3CE-4201-982C-8CD8FB512004")) + CDSMSourceFilter : public CDSMSplitterFilter +{ +public: + CDSMSourceFilter(LPUNKNOWN pUnk, HRESULT* phr); +}; diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.rc b/src/filters/parser/DSMSplitter/DSMSplitter.rc index fd5892bd66f..8f450206304 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.rc +++ b/src/filters/parser/DSMSplitter/DSMSplitter.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "DSM Splitter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "DSM Splitter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "DSMSplitter.ax" - VALUE "ProductName", "DSM Splitter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "DSM Splitter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "DSM Splitter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "DSMSplitter.ax" + VALUE "ProductName", "DSM Splitter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj b/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj index db6ce9500f0..baefd385d19 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj +++ b/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj @@ -1,129 +1,129 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {1E91F58C-0BAE-4021-8087-D1864D8EC066} - DSMSplitter - MFCProj - DSMSplitter - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - DSMSplitter.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - - Create - - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {37768b3f-89bc-4c16-b2a8-767c5da84c3f} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {1E91F58C-0BAE-4021-8087-D1864D8EC066} + DSMSplitter + MFCProj + DSMSplitter + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + DSMSplitter.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + + Create + + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {37768b3f-89bc-4c16-b2a8-767c5da84c3f} + + + + + \ No newline at end of file diff --git a/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj.filters b/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj.filters index d6d733cba22..83f06422a24 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj.filters +++ b/src/filters/parser/DSMSplitter/DSMSplitter.vcxproj.filters @@ -1,52 +1,52 @@ - - - - - {a337cc5d-54f7-4fa2-9559-6c88116d892c} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {a0724c80-5211-43cc-a621-b2d8fe3f71eb} - h;hpp;hxx;hm;inl;inc - - - {5e9cd397-d7f8-4cb7-8db8-10f28ea7ef1c} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {a337cc5d-54f7-4fa2-9559-6c88116d892c} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {a0724c80-5211-43cc-a621-b2d8fe3f71eb} + h;hpp;hxx;hm;inl;inc + + + {5e9cd397-d7f8-4cb7-8db8-10f28ea7ef1c} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/parser/DSMSplitter/DSMSplitterFile.cpp b/src/filters/parser/DSMSplitter/DSMSplitterFile.cpp index e25c9c0a047..6d03e913a6d 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitterFile.cpp +++ b/src/filters/parser/DSMSplitter/DSMSplitterFile.cpp @@ -1,425 +1,425 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "DSMSplitterFile.h" -#include "../../../DSUtil/DSUtil.h" -#include "moreuuids.h" - -CDSMSplitterFile::CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap) - : CBaseSplitterFile(pReader, hr, DEFAULT_CACHE_LENGTH, false) - , m_rtFirst(0) - , m_rtDuration(0) -{ - if (FAILED(hr)) { - return; - } - - hr = Init(res, chap); -} - -HRESULT CDSMSplitterFile::Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap) -{ - Seek(0); - - if (BitRead(DSMSW_SIZE << 3) != DSMSW || BitRead(5) != DSMP_FILEINFO) { - return E_FAIL; - } - - Seek(0); - - m_mts.RemoveAll(); - m_rtFirst = m_rtDuration = 0; - m_fim.RemoveAll(); - m_sim.RemoveAll(); - res.ResRemoveAll(); - chap.ChapRemoveAll(); - - dsmp_t type; - UINT64 len; - - // examine the beginning of the file ... - - while (Sync(type, len, 0)) { - __int64 pos = GetPos(); - - if (type == DSMP_MEDIATYPE) { - BYTE id; - CMediaType mt; - if (Read(len, id, mt)) { - m_mts[id] = mt; - } - } else if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { - m_rtFirst = p.rtStart; - break; - } - } else if (type == DSMP_FILEINFO) { - if ((BYTE)BitRead(8) > DSMF_VERSION) { - return E_FAIL; - } - Read(len - 1, m_fim); - } else if (type == DSMP_STREAMINFO) { - Read(len - 1, m_sim[(BYTE)BitRead(8)]); - } else if (type == DSMP_SYNCPOINTS) { - Read(len, m_sps); - } else if (type == DSMP_RESOURCE) { - Read(len, res); - } else if (type == DSMP_CHAPTERS) { - Read(len, chap); - } - - Seek(pos + len); - } - - if (type != DSMP_SAMPLE) { - return E_FAIL; - } - - // ... and the end - - if (IsRandomAccess()) { - int limit = MAX_PROBE_SIZE; - - for (int i = 1, j = (int)((GetLength() + limit / 2) / limit); i <= j; i++) { - __int64 seekpos = std::max(0ll, GetLength() - i * limit); - Seek(seekpos); - - while (Sync(type, len, limit) && GetPos() < seekpos + limit) { - __int64 pos = GetPos(); - - if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { - m_rtDuration = std::max(m_rtDuration, p.rtStop - m_rtFirst); // max isn't really needed, only for safety - i = j; - } - } else if (type == DSMP_SYNCPOINTS) { - Read(len, m_sps); - } else if (type == DSMP_RESOURCE) { - Read(len, res); - } else if (type == DSMP_CHAPTERS) { - Read(len, chap); - } - - Seek(pos + len); - } - } - } - - if (m_rtFirst < 0) { - m_rtDuration += m_rtFirst; - m_rtFirst = 0; - } - - return !m_mts.IsEmpty() ? S_OK : E_FAIL; -} - -bool CDSMSplitterFile::Sync(dsmp_t& type, UINT64& len, __int64 limit) -{ - UINT64 pos; - return Sync(pos, type, len, limit); -} - -bool CDSMSplitterFile::Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit) -{ - BitByteAlign(); - - limit += DSMSW_SIZE; - - for (UINT64 id = 0; (id & ((1ui64 << (DSMSW_SIZE << 3)) - 1)) != DSMSW; id = (id << 8) | (BYTE)BitRead(8)) { - if (limit-- <= 0 || GetRemaining() <= 2) { - return false; - } - } - - syncpos = GetPos() - (DSMSW_SIZE << 3); - type = (dsmp_t)BitRead(5); - len = BitRead(((int)BitRead(3) + 1) << 3); - - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, BYTE& id, CMediaType& mt) -{ - id = (BYTE)BitRead(8); - ByteRead((BYTE*)&mt.majortype, sizeof(mt.majortype)); - ByteRead((BYTE*)&mt.subtype, sizeof(mt.subtype)); - mt.bFixedSizeSamples = (BOOL)BitRead(1); - mt.bTemporalCompression = (BOOL)BitRead(1); - mt.lSampleSize = (ULONG)BitRead(30); - ByteRead((BYTE*)&mt.formattype, sizeof(mt.formattype)); - len -= 5 + sizeof(GUID) * 3; - ASSERT(len >= 0); - if (len > 0) { - mt.AllocFormatBuffer((LONG)len); - ByteRead(mt.Format(), mt.FormatLength()); - } else { - mt.ResetFormatBuffer(); - } - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, Packet* p, bool fData) -{ - if (!p) { - return false; - } - - p->TrackNumber = (DWORD)BitRead(8); - p->bSyncPoint = (BOOL)BitRead(1); - bool fSign = !!BitRead(1); - int iTimeStamp = (int)BitRead(3); - int iDuration = (int)BitRead(3); - - if (fSign && !iTimeStamp) { - ASSERT(!iDuration); - p->rtStart = Packet::INVALID_TIME; - p->rtStop = Packet::INVALID_TIME + 1; - } else { - p->rtStart = (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); - p->rtStop = p->rtStart + BitRead(iDuration << 3); - } - - if (fData) { - p->SetCount((INT_PTR)len - (2 + iTimeStamp + iDuration)); - ByteRead(p->GetData(), p->GetCount()); - } - - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, CAtlArray& sps) -{ - SyncPoint sp = {0, 0}; - sps.RemoveAll(); - - while (len > 0) { - bool fSign = !!BitRead(1); - int iTimeStamp = (int)BitRead(3); - int iFilePos = (int)BitRead(3); - BitRead(1); // reserved - - sp.rt += (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); - sp.fp += BitRead(iFilePos << 3); - sps.Add(sp); - - len -= 1 + iTimeStamp + iFilePos; - } - - if (len != 0) { - sps.RemoveAll(); - return false; - } - - // TODO: sort sps - - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, CStreamInfoMap& im) -{ - while (len >= 5) { - CStringA key; - ByteRead((BYTE*)key.GetBufferSetLength(4), 4); - len -= 4; - len -= Read(len, im[key]); - } - - return len == 0; -} - -bool CDSMSplitterFile::Read(__int64 len, IDSMResourceBagImpl& res) -{ - BYTE compression = (BYTE)BitRead(2); - BYTE reserved = (BYTE)BitRead(6); - UNREFERENCED_PARAMETER(reserved); - len--; - - CDSMResource r; - len -= Read(len, r.name); - len -= Read(len, r.desc); - len -= Read(len, r.mime); - - if (compression != 0) { - return false; // TODO - } - - r.data.SetCount((size_t)len); - ByteRead(r.data.GetData(), r.data.GetCount()); - - res += r; - - return true; -} - -bool CDSMSplitterFile::Read(__int64 len, IDSMChapterBagImpl& chap) -{ - CDSMChapter c(0, L""); - - while (len > 0) { - bool fSign = !!BitRead(1); - int iTimeStamp = (int)BitRead(3); - BitRead(4); // reserved - len--; - - c.rt += (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); - len -= iTimeStamp; - len -= Read(len, c.name); - - chap += c; - } - - chap.ChapSort(); - - return len == 0; -} - -__int64 CDSMSplitterFile::Read(__int64 len, CStringW& str) -{ - char c; - CStringA s; - __int64 i = 0; - while (i++ < len && (c = (char)BitRead(8)) != 0) { - s += c; - } - str = UTF8To16(s); - return i; -} - -__int64 CDSMSplitterFile::FindSyncPoint(REFERENCE_TIME rt) -{ - if (/*!m_sps.IsEmpty()*/ m_sps.GetCount() > 1) { - size_t i = range_bsearch(m_sps, m_rtFirst + rt); - return (i != MAXSIZE_T) ? m_sps[i].fp : 0; - } - - if (m_rtDuration <= 0 || rt <= m_rtFirst) { - return 0; - } - - // ok, do the hard way then - - dsmp_t type; - UINT64 syncpos, len; - - // 1. find some boundaries close to rt's position (minpos, maxpos) - - __int64 minpos = 0, maxpos = GetLength(); - - for (int i = 0; i < 10 && (maxpos - minpos) >= 1024 * 1024; i++) { - Seek((minpos + maxpos) / 2); - - while (GetPos() < maxpos) { - if (!Sync(syncpos, type, len)) { - continue; - } - - __int64 pos = GetPos(); - - if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { - REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt; - if (dt >= 0) { - maxpos = std::max((__int64)syncpos - MAX_PROBE_SIZE, minpos); - } else { - minpos = syncpos; - } - break; - } - } - - Seek(pos + len); - } - } - - // 2. find the first packet just after rt (maxpos) - - Seek(minpos); - - while (GetRemaining()) { - if (!Sync(syncpos, type, len)) { - continue; - } - - __int64 pos = GetPos(); - - if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { - REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt; - if (dt >= 0) { - maxpos = (__int64)syncpos; - break; - } - } - } - - Seek(pos + len); - } - - // 3. iterate backwards from maxpos and find at least one syncpoint for every stream, except for subtitle streams - - CAtlMap ids; - - { - POSITION pos = m_mts.GetStartPosition(); - while (pos) { - BYTE id; - CMediaType mt; - m_mts.GetNextAssoc(pos, id, mt); - if (mt.majortype != MEDIATYPE_Text && mt.majortype != MEDIATYPE_Subtitle) { - ids[id] = 0; - } - } - } - - __int64 ret = maxpos; - - while (maxpos > 0 && !ids.IsEmpty()) { - minpos = std::max(0ll, maxpos - MAX_PROBE_SIZE); - - Seek(minpos); - - while (Sync(syncpos, type, len) && GetPos() < maxpos) { - UINT64 pos = GetPos(); - - if (type == DSMP_SAMPLE) { - Packet p; - if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME && p.bSyncPoint) { - BYTE id = (BYTE)p.TrackNumber, tmp; - if (ids.Lookup(id, tmp)) { - ids.RemoveKey((BYTE)p.TrackNumber); - ret = std::min(ret, (__int64)syncpos); - } - } - } - - Seek(pos + len); - } - - maxpos = minpos; - } - - return ret; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "DSMSplitterFile.h" +#include "../../../DSUtil/DSUtil.h" +#include "moreuuids.h" + +CDSMSplitterFile::CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap) + : CBaseSplitterFile(pReader, hr, DEFAULT_CACHE_LENGTH, false) + , m_rtFirst(0) + , m_rtDuration(0) +{ + if (FAILED(hr)) { + return; + } + + hr = Init(res, chap); +} + +HRESULT CDSMSplitterFile::Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap) +{ + Seek(0); + + if (BitRead(DSMSW_SIZE << 3) != DSMSW || BitRead(5) != DSMP_FILEINFO) { + return E_FAIL; + } + + Seek(0); + + m_mts.RemoveAll(); + m_rtFirst = m_rtDuration = 0; + m_fim.RemoveAll(); + m_sim.RemoveAll(); + res.ResRemoveAll(); + chap.ChapRemoveAll(); + + dsmp_t type; + UINT64 len; + + // examine the beginning of the file ... + + while (Sync(type, len, 0)) { + __int64 pos = GetPos(); + + if (type == DSMP_MEDIATYPE) { + BYTE id; + CMediaType mt; + if (Read(len, id, mt)) { + m_mts[id] = mt; + } + } else if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { + m_rtFirst = p.rtStart; + break; + } + } else if (type == DSMP_FILEINFO) { + if ((BYTE)BitRead(8) > DSMF_VERSION) { + return E_FAIL; + } + Read(len - 1, m_fim); + } else if (type == DSMP_STREAMINFO) { + Read(len - 1, m_sim[(BYTE)BitRead(8)]); + } else if (type == DSMP_SYNCPOINTS) { + Read(len, m_sps); + } else if (type == DSMP_RESOURCE) { + Read(len, res); + } else if (type == DSMP_CHAPTERS) { + Read(len, chap); + } + + Seek(pos + len); + } + + if (type != DSMP_SAMPLE) { + return E_FAIL; + } + + // ... and the end + + if (IsRandomAccess()) { + int limit = MAX_PROBE_SIZE; + + for (int i = 1, j = (int)((GetLength() + limit / 2) / limit); i <= j; i++) { + __int64 seekpos = std::max(0ll, GetLength() - i * limit); + Seek(seekpos); + + while (Sync(type, len, limit) && GetPos() < seekpos + limit) { + __int64 pos = GetPos(); + + if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { + m_rtDuration = std::max(m_rtDuration, p.rtStop - m_rtFirst); // max isn't really needed, only for safety + i = j; + } + } else if (type == DSMP_SYNCPOINTS) { + Read(len, m_sps); + } else if (type == DSMP_RESOURCE) { + Read(len, res); + } else if (type == DSMP_CHAPTERS) { + Read(len, chap); + } + + Seek(pos + len); + } + } + } + + if (m_rtFirst < 0) { + m_rtDuration += m_rtFirst; + m_rtFirst = 0; + } + + return !m_mts.IsEmpty() ? S_OK : E_FAIL; +} + +bool CDSMSplitterFile::Sync(dsmp_t& type, UINT64& len, __int64 limit) +{ + UINT64 pos; + return Sync(pos, type, len, limit); +} + +bool CDSMSplitterFile::Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit) +{ + BitByteAlign(); + + limit += DSMSW_SIZE; + + for (UINT64 id = 0; (id & ((1ui64 << (DSMSW_SIZE << 3)) - 1)) != DSMSW; id = (id << 8) | (BYTE)BitRead(8)) { + if (limit-- <= 0 || GetRemaining() <= 2) { + return false; + } + } + + syncpos = GetPos() - (DSMSW_SIZE << 3); + type = (dsmp_t)BitRead(5); + len = BitRead(((int)BitRead(3) + 1) << 3); + + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, BYTE& id, CMediaType& mt) +{ + id = (BYTE)BitRead(8); + ByteRead((BYTE*)&mt.majortype, sizeof(mt.majortype)); + ByteRead((BYTE*)&mt.subtype, sizeof(mt.subtype)); + mt.bFixedSizeSamples = (BOOL)BitRead(1); + mt.bTemporalCompression = (BOOL)BitRead(1); + mt.lSampleSize = (ULONG)BitRead(30); + ByteRead((BYTE*)&mt.formattype, sizeof(mt.formattype)); + len -= 5 + sizeof(GUID) * 3; + ASSERT(len >= 0); + if (len > 0) { + mt.AllocFormatBuffer((LONG)len); + ByteRead(mt.Format(), mt.FormatLength()); + } else { + mt.ResetFormatBuffer(); + } + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, Packet* p, bool fData) +{ + if (!p) { + return false; + } + + p->TrackNumber = (DWORD)BitRead(8); + p->bSyncPoint = (BOOL)BitRead(1); + bool fSign = !!BitRead(1); + int iTimeStamp = (int)BitRead(3); + int iDuration = (int)BitRead(3); + + if (fSign && !iTimeStamp) { + ASSERT(!iDuration); + p->rtStart = Packet::INVALID_TIME; + p->rtStop = Packet::INVALID_TIME + 1; + } else { + p->rtStart = (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); + p->rtStop = p->rtStart + BitRead(iDuration << 3); + } + + if (fData) { + p->SetCount((INT_PTR)len - (2 + iTimeStamp + iDuration)); + ByteRead(p->GetData(), p->GetCount()); + } + + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, CAtlArray& sps) +{ + SyncPoint sp = {0, 0}; + sps.RemoveAll(); + + while (len > 0) { + bool fSign = !!BitRead(1); + int iTimeStamp = (int)BitRead(3); + int iFilePos = (int)BitRead(3); + BitRead(1); // reserved + + sp.rt += (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); + sp.fp += BitRead(iFilePos << 3); + sps.Add(sp); + + len -= 1 + iTimeStamp + iFilePos; + } + + if (len != 0) { + sps.RemoveAll(); + return false; + } + + // TODO: sort sps + + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, CStreamInfoMap& im) +{ + while (len >= 5) { + CStringA key; + ByteRead((BYTE*)key.GetBufferSetLength(4), 4); + len -= 4; + len -= Read(len, im[key]); + } + + return len == 0; +} + +bool CDSMSplitterFile::Read(__int64 len, IDSMResourceBagImpl& res) +{ + BYTE compression = (BYTE)BitRead(2); + BYTE reserved = (BYTE)BitRead(6); + UNREFERENCED_PARAMETER(reserved); + len--; + + CDSMResource r; + len -= Read(len, r.name); + len -= Read(len, r.desc); + len -= Read(len, r.mime); + + if (compression != 0) { + return false; // TODO + } + + r.data.SetCount((size_t)len); + ByteRead(r.data.GetData(), r.data.GetCount()); + + res += r; + + return true; +} + +bool CDSMSplitterFile::Read(__int64 len, IDSMChapterBagImpl& chap) +{ + CDSMChapter c(0, L""); + + while (len > 0) { + bool fSign = !!BitRead(1); + int iTimeStamp = (int)BitRead(3); + BitRead(4); // reserved + len--; + + c.rt += (REFERENCE_TIME)BitRead(iTimeStamp << 3) * (fSign ? -1 : 1); + len -= iTimeStamp; + len -= Read(len, c.name); + + chap += c; + } + + chap.ChapSort(); + + return len == 0; +} + +__int64 CDSMSplitterFile::Read(__int64 len, CStringW& str) +{ + char c; + CStringA s; + __int64 i = 0; + while (i++ < len && (c = (char)BitRead(8)) != 0) { + s += c; + } + str = UTF8To16(s); + return i; +} + +__int64 CDSMSplitterFile::FindSyncPoint(REFERENCE_TIME rt) +{ + if (/*!m_sps.IsEmpty()*/ m_sps.GetCount() > 1) { + size_t i = range_bsearch(m_sps, m_rtFirst + rt); + return (i != MAXSIZE_T) ? m_sps[i].fp : 0; + } + + if (m_rtDuration <= 0 || rt <= m_rtFirst) { + return 0; + } + + // ok, do the hard way then + + dsmp_t type; + UINT64 syncpos, len; + + // 1. find some boundaries close to rt's position (minpos, maxpos) + + __int64 minpos = 0, maxpos = GetLength(); + + for (int i = 0; i < 10 && (maxpos - minpos) >= 1024 * 1024; i++) { + Seek((minpos + maxpos) / 2); + + while (GetPos() < maxpos) { + if (!Sync(syncpos, type, len)) { + continue; + } + + __int64 pos = GetPos(); + + if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { + REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt; + if (dt >= 0) { + maxpos = std::max((__int64)syncpos - MAX_PROBE_SIZE, minpos); + } else { + minpos = syncpos; + } + break; + } + } + + Seek(pos + len); + } + } + + // 2. find the first packet just after rt (maxpos) + + Seek(minpos); + + while (GetRemaining()) { + if (!Sync(syncpos, type, len)) { + continue; + } + + __int64 pos = GetPos(); + + if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME) { + REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt; + if (dt >= 0) { + maxpos = (__int64)syncpos; + break; + } + } + } + + Seek(pos + len); + } + + // 3. iterate backwards from maxpos and find at least one syncpoint for every stream, except for subtitle streams + + CAtlMap ids; + + { + POSITION pos = m_mts.GetStartPosition(); + while (pos) { + BYTE id; + CMediaType mt; + m_mts.GetNextAssoc(pos, id, mt); + if (mt.majortype != MEDIATYPE_Text && mt.majortype != MEDIATYPE_Subtitle) { + ids[id] = 0; + } + } + } + + __int64 ret = maxpos; + + while (maxpos > 0 && !ids.IsEmpty()) { + minpos = std::max(0ll, maxpos - MAX_PROBE_SIZE); + + Seek(minpos); + + while (Sync(syncpos, type, len) && GetPos() < maxpos) { + UINT64 pos = GetPos(); + + if (type == DSMP_SAMPLE) { + Packet p; + if (Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME && p.bSyncPoint) { + BYTE id = (BYTE)p.TrackNumber, tmp; + if (ids.Lookup(id, tmp)) { + ids.RemoveKey((BYTE)p.TrackNumber); + ret = std::min(ret, (__int64)syncpos); + } + } + } + + Seek(pos + len); + } + + maxpos = minpos; + } + + return ret; +} diff --git a/src/filters/parser/DSMSplitter/DSMSplitterFile.h b/src/filters/parser/DSMSplitter/DSMSplitterFile.h index 27a6c119bd8..e9f041c2585 100644 --- a/src/filters/parser/DSMSplitter/DSMSplitterFile.h +++ b/src/filters/parser/DSMSplitter/DSMSplitterFile.h @@ -1,62 +1,62 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../BaseSplitter/BaseSplitter.h" -#include "../BaseSplitter/BaseSplitterFile.h" -#include "dsm/dsm.h" -#include "../../../DSUtil/DSMPropertyBag.h" - -#define MAX_PROBE_SIZE (64 * 1024) - -class CDSMSplitterFile : public CBaseSplitterFile -{ - HRESULT Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap); - -public: - CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap); - - CAtlMap m_mts; - REFERENCE_TIME m_rtFirst, m_rtDuration; - - struct SyncPoint { - REFERENCE_TIME rt; - __int64 fp; - }; - CAtlArray m_sps; - - typedef CAtlMap, CStringElementTraits> CStreamInfoMap; - CStreamInfoMap m_fim; - CAtlMap m_sim; - - bool Sync(dsmp_t& type, UINT64& len, __int64 limit = MAX_PROBE_SIZE); - bool Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit = MAX_PROBE_SIZE); - bool Read(__int64 len, BYTE& id, CMediaType& mt); - bool Read(__int64 len, Packet* p, bool fData = true); - bool Read(__int64 len, CAtlArray& sps); - bool Read(__int64 len, CStreamInfoMap& im); - bool Read(__int64 len, IDSMResourceBagImpl& res); - bool Read(__int64 len, IDSMChapterBagImpl& chap); - __int64 Read(__int64 len, CStringW& str); - - __int64 FindSyncPoint(REFERENCE_TIME rt); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "../BaseSplitter/BaseSplitter.h" +#include "../BaseSplitter/BaseSplitterFile.h" +#include "dsm/dsm.h" +#include "../../../DSUtil/DSMPropertyBag.h" + +#define MAX_PROBE_SIZE (64 * 1024) + +class CDSMSplitterFile : public CBaseSplitterFile +{ + HRESULT Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap); + +public: + CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap); + + CAtlMap m_mts; + REFERENCE_TIME m_rtFirst, m_rtDuration; + + struct SyncPoint { + REFERENCE_TIME rt; + __int64 fp; + }; + CAtlArray m_sps; + + typedef CAtlMap, CStringElementTraits> CStreamInfoMap; + CStreamInfoMap m_fim; + CAtlMap m_sim; + + bool Sync(dsmp_t& type, UINT64& len, __int64 limit = MAX_PROBE_SIZE); + bool Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit = MAX_PROBE_SIZE); + bool Read(__int64 len, BYTE& id, CMediaType& mt); + bool Read(__int64 len, Packet* p, bool fData = true); + bool Read(__int64 len, CAtlArray& sps); + bool Read(__int64 len, CStreamInfoMap& im); + bool Read(__int64 len, IDSMResourceBagImpl& res); + bool Read(__int64 len, IDSMChapterBagImpl& chap); + __int64 Read(__int64 len, CStringW& str); + + __int64 FindSyncPoint(REFERENCE_TIME rt); +}; diff --git a/src/filters/parser/DSMSplitter/resource.h b/src/filters/parser/DSMSplitter/resource.h index e7b2ca36c3a..66d1331cb8d 100644 --- a/src/filters/parser/DSMSplitter/resource.h +++ b/src/filters/parser/DSMSplitter/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by DSMSplitter.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DSMSplitter.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/parser/DSMSplitter/stdafx.cpp b/src/filters/parser/DSMSplitter/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/parser/DSMSplitter/stdafx.cpp +++ b/src/filters/parser/DSMSplitter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/parser/DSMSplitter/stdafx.h b/src/filters/parser/DSMSplitter/stdafx.h index 2095b5f2385..5647391d25c 100644 --- a/src/filters/parser/DSMSplitter/stdafx.h +++ b/src/filters/parser/DSMSplitter/stdafx.h @@ -1,36 +1,36 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components -#include - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components +#include + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.cpp b/src/filters/parser/StreamDriveThru/StreamDriveThru.cpp index cef9f0513c6..c654f20cfe8 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.cpp +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.cpp @@ -1,624 +1,624 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "StreamDriveThru.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CStreamDriveThruFilter), StreamDriveThruName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CStreamDriveThruFilter -// - -CStreamDriveThruFilter::CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseFilter(NAME("CStreamDriveThruFilter"), pUnk, &m_csLock, __uuidof(this)) - , m_position(0) -{ - if (phr) { - *phr = S_OK; - } - - m_pInput = DEBUG_NEW CStreamDriveThruInputPin(NAME("CStreamDriveThruInputPin"), this, &m_csLock, phr); - m_pOutput = DEBUG_NEW CStreamDriveThruOutputPin(NAME("CStreamDriveThruOutputPin"), this, &m_csLock, phr); - - CAMThread::Create(); -} - -CStreamDriveThruFilter::~CStreamDriveThruFilter() -{ - CAutoLock csAutoLock(&m_csLock); - - CAMThread::CallWorker(CMD_EXIT); - CAMThread::Close(); - - delete m_pInput; - delete m_pOutput; -} - -STDMETHODIMP CStreamDriveThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IMediaSeeking) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -#define PACKETSIZE 65536 - -#pragma warning(push) -#pragma warning(disable: 4702) -DWORD CStreamDriveThruFilter::ThreadProc() -{ - for (;;) { - DWORD cmd = GetRequest(); - - switch (cmd) { - default: - case CMD_EXIT: - Reply(S_OK); - return 0; - case CMD_STOP: - Reply(S_OK); - break; - case CMD_PAUSE: - Reply(S_OK); - break; - case CMD_RUN: - Reply(S_OK); - - do { - CComPtr pAsyncReader; - CComPtr pStream; - - if (!m_pInput || !m_pInput->IsConnected() || FAILED(m_pInput->GetAsyncReader(&pAsyncReader)) - || !m_pOutput || !m_pOutput->IsConnected() || FAILED(m_pOutput->GetStream(&pStream))) { - break; - } - - LARGE_INTEGER li = {0}; - ULARGE_INTEGER uli = {0}; - - if (FAILED(pStream->Seek(li, STREAM_SEEK_SET, nullptr)) - || FAILED(pStream->SetSize(uli))) { - break; - } - - if (CComQIPtr pFSF = GetFilterFromPin(m_pOutput->GetConnected())) { - pFSF->SetMode(AM_FILE_OVERWRITE); - - CComHeapPtr pfn; - if (SUCCEEDED(pFSF->GetCurFile(&pfn, nullptr))) { - pFSF->SetFileName(pfn, nullptr); - } - } - - m_position = 0; - BYTE buff[PACKETSIZE]; - - do { - while (!CheckRequest(&cmd)) { - CAutoLock csAutoLock(&m_csLock); - - LONGLONG total = 0, available = 0; - if (FAILED(pAsyncReader->Length(&total, &available)) || m_position >= total) { - cmd = CMD_STOP; - break; - } - - LONG size = std::min(PACKETSIZE, LONG(total - m_position)); - if (FAILED(pAsyncReader->SyncRead(m_position, size, buff))) { - cmd = CMD_STOP; - break; - } - - ULONG written = 0; - if (FAILED(pStream->Write(buff, (ULONG)size, &written)) || (ULONG)size != written) { - cmd = CMD_STOP; - break; - } - - m_position += size; - } - - if (cmd == CMD_PAUSE) { - Reply(S_OK); // reply to CMD_PAUSE - - while (!CheckRequest(&cmd)) { - Sleep(50); - } - - Reply(S_OK); // reply to something - } - } while (cmd == CMD_RUN); - - uli.QuadPart = m_position; - pStream->SetSize(uli); - - if (CComPtr pPin = m_pOutput->GetConnected()) { - pPin->EndOfStream(); - } - } while (false); - - break; - } - } - UNREACHABLE_CODE(); // we should only exit via CMD_EXIT -#pragma warning(pop) -} - -int CStreamDriveThruFilter::GetPinCount() -{ - return 2; -} - -CBasePin* CStreamDriveThruFilter::GetPin(int n) -{ - CAutoLock csAutoLock(&m_csLock); - - if (n == 0) { - return m_pInput; - } else if (n == 1) { - return m_pOutput; - } - - return nullptr; -} - -STDMETHODIMP CStreamDriveThruFilter::Stop() -{ - HRESULT hr; - - if (FAILED(hr = __super::Stop())) { - return hr; - } - - CallWorker(CMD_STOP); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::Pause() -{ - HRESULT hr; - - if (FAILED(hr = __super::Pause())) { - return hr; - } - - CallWorker(CMD_PAUSE); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::Run(REFERENCE_TIME tStart) -{ - HRESULT hr; - - if (FAILED(hr = __super::Run(tStart))) { - return hr; - } - - CallWorker(CMD_RUN); - - return S_OK; -} - -// IMediaSeeking - -STDMETHODIMP CStreamDriveThruFilter::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanGetCurrentPos | AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration; - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - if (*pCapabilities == 0) { - return S_OK; - } - - DWORD caps; - GetCapabilities(&caps); - - DWORD caps2 = caps & *pCapabilities; - - return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE; -} - -STDMETHODIMP CStreamDriveThruFilter::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CStreamDriveThruFilter::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CStreamDriveThruFilter::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CStreamDriveThruFilter::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CStreamDriveThruFilter::GetDuration(LONGLONG* pDuration) -{ - CheckPointer(pDuration, E_POINTER); - CheckPointer(m_pInput, VFW_E_NOT_CONNECTED); - - if (CComQIPtr pAsyncReader = m_pInput->GetConnected()) { - LONGLONG total, available; - if (SUCCEEDED(pAsyncReader->Length(&total, &available))) { - *pDuration = total; - return S_OK; - } - } - - return E_NOINTERFACE; -} - -STDMETHODIMP CStreamDriveThruFilter::GetStopPosition(LONGLONG* pStop) -{ - return GetDuration(pStop); -} - -STDMETHODIMP CStreamDriveThruFilter::GetCurrentPosition(LONGLONG* pCurrent) -{ - CheckPointer(pCurrent, E_POINTER); - - *pCurrent = m_position; - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::SetRate(double dRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::GetRate(double* pdRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CStreamDriveThruFilter::GetPreroll(LONGLONG* pllPreroll) -{ - CheckPointer(pllPreroll, E_POINTER); - - *pllPreroll = 0; - - return S_OK; -} - -// -// CStreamDriveThruInputPin -// - -CStreamDriveThruInputPin::CStreamDriveThruInputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT) -{ -} - -CStreamDriveThruInputPin::~CStreamDriveThruInputPin() -{ -} - -HRESULT CStreamDriveThruInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader) -{ - CheckPointer(ppAsyncReader, E_POINTER); - - *ppAsyncReader = nullptr; - - CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED); - - (*ppAsyncReader = m_pAsyncReader)->AddRef(); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CStreamDriveThruInputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Stream || pmt->majortype == MEDIATYPE_NULL - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CStreamDriveThruInputPin::CheckConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CheckConnect(pPin))) { - return hr; - } - - if (!CComQIPtr(pPin)) { - return E_NOINTERFACE; - } - - return S_OK; -} - -HRESULT CStreamDriveThruInputPin::BreakConnect() -{ - HRESULT hr; - - if (FAILED(hr = __super::BreakConnect())) { - return hr; - } - - m_pAsyncReader.Release(); - - return S_OK; -} - -HRESULT CStreamDriveThruInputPin::CompleteConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CompleteConnect(pPin))) { - return hr; - } - - CheckPointer(pPin, E_POINTER); - m_pAsyncReader = pPin; - CheckPointer(m_pAsyncReader, E_NOINTERFACE); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruInputPin::BeginFlush() -{ - return E_UNEXPECTED; -} - -STDMETHODIMP CStreamDriveThruInputPin::EndFlush() -{ - return E_UNEXPECTED; -} - -// -// CStreamDriveThruOutputPin -// - -CStreamDriveThruOutputPin::CStreamDriveThruOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) - : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output") -{ -} - -CStreamDriveThruOutputPin::~CStreamDriveThruOutputPin() -{ -} - -HRESULT CStreamDriveThruOutputPin::GetStream(IStream** ppStream) -{ - CheckPointer(ppStream, E_POINTER); - - *ppStream = nullptr; - - CheckPointer(m_pStream, VFW_E_NOT_CONNECTED); - - (*ppStream = m_pStream)->AddRef(); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CStreamDriveThruOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - pProperties->cBuffers = 1; - pProperties->cbBuffer = PACKETSIZE; - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CStreamDriveThruOutputPin::CheckMediaType(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Stream - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CStreamDriveThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CAutoLock cAutoLock(m_pLock); - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - pmt->majortype = MEDIATYPE_Stream; - pmt->subtype = GUID_NULL; - pmt->formattype = GUID_NULL; - pmt->SetSampleSize(PACKETSIZE); - - return S_OK; -} - -HRESULT CStreamDriveThruOutputPin::CheckConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CheckConnect(pPin))) { - return hr; - } - - if (!CComQIPtr(pPin)) { - return E_NOINTERFACE; - } - - return S_OK; -} - -HRESULT CStreamDriveThruOutputPin::BreakConnect() -{ - HRESULT hr; - - if (FAILED(hr = __super::BreakConnect())) { - return hr; - } - - m_pStream.Release(); - - return S_OK; -} - -HRESULT CStreamDriveThruOutputPin::CompleteConnect(IPin* pPin) -{ - HRESULT hr; - - if (FAILED(hr = __super::CompleteConnect(pPin))) { - return hr; - } - - CheckPointer(pPin, E_POINTER); - m_pStream = pPin; - CheckPointer(m_pStream, E_NOINTERFACE); - - return S_OK; -} - -STDMETHODIMP CStreamDriveThruOutputPin::BeginFlush() -{ - return E_UNEXPECTED; -} - -STDMETHODIMP CStreamDriveThruOutputPin::EndFlush() -{ - return E_UNEXPECTED; -} - -STDMETHODIMP CStreamDriveThruOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "StreamDriveThru.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CStreamDriveThruFilter), StreamDriveThruName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CStreamDriveThruFilter +// + +CStreamDriveThruFilter::CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseFilter(NAME("CStreamDriveThruFilter"), pUnk, &m_csLock, __uuidof(this)) + , m_position(0) +{ + if (phr) { + *phr = S_OK; + } + + m_pInput = DEBUG_NEW CStreamDriveThruInputPin(NAME("CStreamDriveThruInputPin"), this, &m_csLock, phr); + m_pOutput = DEBUG_NEW CStreamDriveThruOutputPin(NAME("CStreamDriveThruOutputPin"), this, &m_csLock, phr); + + CAMThread::Create(); +} + +CStreamDriveThruFilter::~CStreamDriveThruFilter() +{ + CAutoLock csAutoLock(&m_csLock); + + CAMThread::CallWorker(CMD_EXIT); + CAMThread::Close(); + + delete m_pInput; + delete m_pOutput; +} + +STDMETHODIMP CStreamDriveThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IMediaSeeking) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +#define PACKETSIZE 65536 + +#pragma warning(push) +#pragma warning(disable: 4702) +DWORD CStreamDriveThruFilter::ThreadProc() +{ + for (;;) { + DWORD cmd = GetRequest(); + + switch (cmd) { + default: + case CMD_EXIT: + Reply(S_OK); + return 0; + case CMD_STOP: + Reply(S_OK); + break; + case CMD_PAUSE: + Reply(S_OK); + break; + case CMD_RUN: + Reply(S_OK); + + do { + CComPtr pAsyncReader; + CComPtr pStream; + + if (!m_pInput || !m_pInput->IsConnected() || FAILED(m_pInput->GetAsyncReader(&pAsyncReader)) + || !m_pOutput || !m_pOutput->IsConnected() || FAILED(m_pOutput->GetStream(&pStream))) { + break; + } + + LARGE_INTEGER li = {0}; + ULARGE_INTEGER uli = {0}; + + if (FAILED(pStream->Seek(li, STREAM_SEEK_SET, nullptr)) + || FAILED(pStream->SetSize(uli))) { + break; + } + + if (CComQIPtr pFSF = GetFilterFromPin(m_pOutput->GetConnected())) { + pFSF->SetMode(AM_FILE_OVERWRITE); + + CComHeapPtr pfn; + if (SUCCEEDED(pFSF->GetCurFile(&pfn, nullptr))) { + pFSF->SetFileName(pfn, nullptr); + } + } + + m_position = 0; + BYTE buff[PACKETSIZE]; + + do { + while (!CheckRequest(&cmd)) { + CAutoLock csAutoLock(&m_csLock); + + LONGLONG total = 0, available = 0; + if (FAILED(pAsyncReader->Length(&total, &available)) || m_position >= total) { + cmd = CMD_STOP; + break; + } + + LONG size = std::min(PACKETSIZE, LONG(total - m_position)); + if (FAILED(pAsyncReader->SyncRead(m_position, size, buff))) { + cmd = CMD_STOP; + break; + } + + ULONG written = 0; + if (FAILED(pStream->Write(buff, (ULONG)size, &written)) || (ULONG)size != written) { + cmd = CMD_STOP; + break; + } + + m_position += size; + } + + if (cmd == CMD_PAUSE) { + Reply(S_OK); // reply to CMD_PAUSE + + while (!CheckRequest(&cmd)) { + Sleep(50); + } + + Reply(S_OK); // reply to something + } + } while (cmd == CMD_RUN); + + uli.QuadPart = m_position; + pStream->SetSize(uli); + + if (CComPtr pPin = m_pOutput->GetConnected()) { + pPin->EndOfStream(); + } + } while (false); + + break; + } + } + UNREACHABLE_CODE(); // we should only exit via CMD_EXIT +#pragma warning(pop) +} + +int CStreamDriveThruFilter::GetPinCount() +{ + return 2; +} + +CBasePin* CStreamDriveThruFilter::GetPin(int n) +{ + CAutoLock csAutoLock(&m_csLock); + + if (n == 0) { + return m_pInput; + } else if (n == 1) { + return m_pOutput; + } + + return nullptr; +} + +STDMETHODIMP CStreamDriveThruFilter::Stop() +{ + HRESULT hr; + + if (FAILED(hr = __super::Stop())) { + return hr; + } + + CallWorker(CMD_STOP); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::Pause() +{ + HRESULT hr; + + if (FAILED(hr = __super::Pause())) { + return hr; + } + + CallWorker(CMD_PAUSE); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::Run(REFERENCE_TIME tStart) +{ + HRESULT hr; + + if (FAILED(hr = __super::Run(tStart))) { + return hr; + } + + CallWorker(CMD_RUN); + + return S_OK; +} + +// IMediaSeeking + +STDMETHODIMP CStreamDriveThruFilter::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanGetCurrentPos | AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration; + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + if (*pCapabilities == 0) { + return S_OK; + } + + DWORD caps; + GetCapabilities(&caps); + + DWORD caps2 = caps & *pCapabilities; + + return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE; +} + +STDMETHODIMP CStreamDriveThruFilter::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CStreamDriveThruFilter::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CStreamDriveThruFilter::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CStreamDriveThruFilter::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CStreamDriveThruFilter::GetDuration(LONGLONG* pDuration) +{ + CheckPointer(pDuration, E_POINTER); + CheckPointer(m_pInput, VFW_E_NOT_CONNECTED); + + if (CComQIPtr pAsyncReader = m_pInput->GetConnected()) { + LONGLONG total, available; + if (SUCCEEDED(pAsyncReader->Length(&total, &available))) { + *pDuration = total; + return S_OK; + } + } + + return E_NOINTERFACE; +} + +STDMETHODIMP CStreamDriveThruFilter::GetStopPosition(LONGLONG* pStop) +{ + return GetDuration(pStop); +} + +STDMETHODIMP CStreamDriveThruFilter::GetCurrentPosition(LONGLONG* pCurrent) +{ + CheckPointer(pCurrent, E_POINTER); + + *pCurrent = m_position; + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::SetRate(double dRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::GetRate(double* pdRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CStreamDriveThruFilter::GetPreroll(LONGLONG* pllPreroll) +{ + CheckPointer(pllPreroll, E_POINTER); + + *pllPreroll = 0; + + return S_OK; +} + +// +// CStreamDriveThruInputPin +// + +CStreamDriveThruInputPin::CStreamDriveThruInputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT) +{ +} + +CStreamDriveThruInputPin::~CStreamDriveThruInputPin() +{ +} + +HRESULT CStreamDriveThruInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader) +{ + CheckPointer(ppAsyncReader, E_POINTER); + + *ppAsyncReader = nullptr; + + CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED); + + (*ppAsyncReader = m_pAsyncReader)->AddRef(); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CStreamDriveThruInputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Stream || pmt->majortype == MEDIATYPE_NULL + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CStreamDriveThruInputPin::CheckConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CheckConnect(pPin))) { + return hr; + } + + if (!CComQIPtr(pPin)) { + return E_NOINTERFACE; + } + + return S_OK; +} + +HRESULT CStreamDriveThruInputPin::BreakConnect() +{ + HRESULT hr; + + if (FAILED(hr = __super::BreakConnect())) { + return hr; + } + + m_pAsyncReader.Release(); + + return S_OK; +} + +HRESULT CStreamDriveThruInputPin::CompleteConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CompleteConnect(pPin))) { + return hr; + } + + CheckPointer(pPin, E_POINTER); + m_pAsyncReader = pPin; + CheckPointer(m_pAsyncReader, E_NOINTERFACE); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruInputPin::BeginFlush() +{ + return E_UNEXPECTED; +} + +STDMETHODIMP CStreamDriveThruInputPin::EndFlush() +{ + return E_UNEXPECTED; +} + +// +// CStreamDriveThruOutputPin +// + +CStreamDriveThruOutputPin::CStreamDriveThruOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr) + : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output") +{ +} + +CStreamDriveThruOutputPin::~CStreamDriveThruOutputPin() +{ +} + +HRESULT CStreamDriveThruOutputPin::GetStream(IStream** ppStream) +{ + CheckPointer(ppStream, E_POINTER); + + *ppStream = nullptr; + + CheckPointer(m_pStream, VFW_E_NOT_CONNECTED); + + (*ppStream = m_pStream)->AddRef(); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CStreamDriveThruOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + pProperties->cBuffers = 1; + pProperties->cbBuffer = PACKETSIZE; + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CStreamDriveThruOutputPin::CheckMediaType(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Stream + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CStreamDriveThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CAutoLock cAutoLock(m_pLock); + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + pmt->majortype = MEDIATYPE_Stream; + pmt->subtype = GUID_NULL; + pmt->formattype = GUID_NULL; + pmt->SetSampleSize(PACKETSIZE); + + return S_OK; +} + +HRESULT CStreamDriveThruOutputPin::CheckConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CheckConnect(pPin))) { + return hr; + } + + if (!CComQIPtr(pPin)) { + return E_NOINTERFACE; + } + + return S_OK; +} + +HRESULT CStreamDriveThruOutputPin::BreakConnect() +{ + HRESULT hr; + + if (FAILED(hr = __super::BreakConnect())) { + return hr; + } + + m_pStream.Release(); + + return S_OK; +} + +HRESULT CStreamDriveThruOutputPin::CompleteConnect(IPin* pPin) +{ + HRESULT hr; + + if (FAILED(hr = __super::CompleteConnect(pPin))) { + return hr; + } + + CheckPointer(pPin, E_POINTER); + m_pStream = pPin; + CheckPointer(m_pStream, E_NOINTERFACE); + + return S_OK; +} + +STDMETHODIMP CStreamDriveThruOutputPin::BeginFlush() +{ + return E_UNEXPECTED; +} + +STDMETHODIMP CStreamDriveThruOutputPin::EndFlush() +{ + return E_UNEXPECTED; +} + +STDMETHODIMP CStreamDriveThruOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.def b/src/filters/parser/StreamDriveThru/StreamDriveThru.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.def +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.h b/src/filters/parser/StreamDriveThru/StreamDriveThru.h index a2cb8fd3e6a..ddf052ef832 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.h +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.h @@ -1,129 +1,129 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include "../../../DSUtil/DSUtil.h" - -#define StreamDriveThruName L"MPC-HC StreamDriveThru" - -class CStreamDriveThruInputPin : public CBasePin -{ - CComQIPtr m_pAsyncReader; - -public: - CStreamDriveThruInputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CStreamDriveThruInputPin(); - - HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT CheckMediaType(const CMediaType* pmt); - - HRESULT CheckConnect(IPin* pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pPin); - - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); -}; - -class CStreamDriveThruOutputPin : public CBaseOutputPin -{ - CComQIPtr m_pStream; - -public: - CStreamDriveThruOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); - virtual ~CStreamDriveThruOutputPin(); - - HRESULT GetStream(IStream** ppStream); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - - HRESULT CheckConnect(IPin* pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pPin); - - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; - -class __declspec(uuid("534FE6FD-F1F0-4aec-9F45-FF397320CE33")) - CStreamDriveThruFilter : public CBaseFilter, protected CAMThread, public IMediaSeeking -{ - CCritSec m_csLock; - - CStreamDriveThruInputPin* m_pInput; - CStreamDriveThruOutputPin* m_pOutput; - -protected: - enum { CMD_EXIT, CMD_STOP, CMD_PAUSE, CMD_RUN }; - DWORD ThreadProc(); - - LONGLONG m_position; - -public: - CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr); - virtual ~CStreamDriveThruFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - int GetPinCount(); - CBasePin* GetPin(int n); - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // IMediaSeeking - - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, - LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include "../../../DSUtil/DSUtil.h" + +#define StreamDriveThruName L"MPC-HC StreamDriveThru" + +class CStreamDriveThruInputPin : public CBasePin +{ + CComQIPtr m_pAsyncReader; + +public: + CStreamDriveThruInputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CStreamDriveThruInputPin(); + + HRESULT GetAsyncReader(IAsyncReader** ppAsyncReader); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT CheckMediaType(const CMediaType* pmt); + + HRESULT CheckConnect(IPin* pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pPin); + + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); +}; + +class CStreamDriveThruOutputPin : public CBaseOutputPin +{ + CComQIPtr m_pStream; + +public: + CStreamDriveThruOutputPin(LPCTSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr); + virtual ~CStreamDriveThruOutputPin(); + + HRESULT GetStream(IStream** ppStream); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + + HRESULT CheckConnect(IPin* pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pPin); + + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; + +class __declspec(uuid("534FE6FD-F1F0-4aec-9F45-FF397320CE33")) + CStreamDriveThruFilter : public CBaseFilter, protected CAMThread, public IMediaSeeking +{ + CCritSec m_csLock; + + CStreamDriveThruInputPin* m_pInput; + CStreamDriveThruOutputPin* m_pOutput; + +protected: + enum { CMD_EXIT, CMD_STOP, CMD_PAUSE, CMD_RUN }; + DWORD ThreadProc(); + + LONGLONG m_position; + +public: + CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr); + virtual ~CStreamDriveThruFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + int GetPinCount(); + CBasePin* GetPin(int n); + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // IMediaSeeking + + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, + LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); +}; diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.rc b/src/filters/parser/StreamDriveThru/StreamDriveThru.rc index 695f23e0795..12c9437e836 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.rc +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "StreamDriverThru Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "StreamDriverThru Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "StreamDriverThru.ax" - VALUE "ProductName", "StreamDriverThru Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "StreamDriverThru Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "StreamDriverThru Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "StreamDriverThru.ax" + VALUE "ProductName", "StreamDriverThru Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj b/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj index d3e2e52b3c8..319a169a21d 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj @@ -1,124 +1,124 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {AE399B7E-2B2C-4A96-9016-C5C74B0A2FA0} - streamdrivethru - MFCProj - StreamDriveThru - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - StreamDriveThru.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - Create - - - - - - - - - true - - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {AE399B7E-2B2C-4A96-9016-C5C74B0A2FA0} + streamdrivethru + MFCProj + StreamDriveThru + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + StreamDriveThru.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + Create + + + + + + + + + true + + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj.filters b/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj.filters index 2a354a75d9e..173cd5f6f51 100644 --- a/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj.filters +++ b/src/filters/parser/StreamDriveThru/StreamDriveThru.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {28a35247-c38a-473b-8877-78de4c5a56e6} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {825cda28-5045-4bb1-bbf5-803ad068b185} - h;hpp;hxx;hm;inl;inc - - - {3e459df1-b036-4307-9bf5-af9011f90631} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {28a35247-c38a-473b-8877-78de4c5a56e6} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {825cda28-5045-4bb1-bbf5-803ad068b185} + h;hpp;hxx;hm;inl;inc + + + {3e459df1-b036-4307-9bf5-af9011f90631} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/parser/StreamDriveThru/resource.h b/src/filters/parser/StreamDriveThru/resource.h index 6f0cb1db6fa..94c5f77b99c 100644 --- a/src/filters/parser/StreamDriveThru/resource.h +++ b/src/filters/parser/StreamDriveThru/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by StreamDriveThru.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by StreamDriveThru.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/parser/StreamDriveThru/stdafx.cpp b/src/filters/parser/StreamDriveThru/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/parser/StreamDriveThru/stdafx.cpp +++ b/src/filters/parser/StreamDriveThru/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/parser/StreamDriveThru/stdafx.h b/src/filters/parser/StreamDriveThru/stdafx.h index 2dd14e5c1a9..104edd03d59 100644 --- a/src/filters/parser/StreamDriveThru/stdafx.h +++ b/src/filters/parser/StreamDriveThru/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include "BaseClasses/streams.h" +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include "BaseClasses/streams.h" diff --git a/src/filters/reader/CDDAReader/CDDAReader.cpp b/src/filters/reader/CDDAReader/CDDAReader.cpp index 0549ad6f387..9659c123f5e 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.cpp +++ b/src/filters/reader/CDDAReader/CDDAReader.cpp @@ -1,560 +1,560 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#ifdef STANDALONE_FILTER -#include -#endif -#include "CDDAReader.h" -#include "../../../DSUtil/DSUtil.h" - -#define RAW_SECTOR_SIZE 2352 -#define MSF2UINT(hgs) ((hgs[1] * 4500) + (hgs[2] * 75) + (hgs[3])) - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE}, -}; - -const AMOVIESETUP_PIN sudOpPin[] = { - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}, -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CCDDAReader), CCDDAReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"), - _T("0"), _T("0,4,,52494646,8,4,,43444441")); // "RIFFxxxxCDDA" - - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"), - _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".cda"), - _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); - - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".cda")); - - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CCDDAReader -// - -CCDDAReader::CCDDAReader(IUnknown* pUnk, HRESULT* phr) - : CAsyncReader(NAME("CCDDAReader"), pUnk, &m_stream, phr, __uuidof(this)) -{ - if (phr) { - *phr = S_OK; - } -} - -CCDDAReader::~CCDDAReader() -{ -} - -STDMETHODIMP CCDDAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFileSourceFilter) - QI2(IAMMediaContent) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CCDDAReader::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - - wcscpy_s(pInfo->achName, CCDDAReaderName); - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -// IFileSourceFilter - -STDMETHODIMP CCDDAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - if (!m_stream.Load(pszFileName)) { - return E_FAIL; - } - - m_fn = pszFileName; - - CMediaType mt; - mt.majortype = MEDIATYPE_Stream; - mt.subtype = m_stream.IsDTS() ? MEDIASUBTYPE_DTS : MEDIASUBTYPE_WAVE; - m_mt = mt; - - return S_OK; -} - -STDMETHODIMP CCDDAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - - return S_OK; -} - -// IAMMediaContent - -STDMETHODIMP CCDDAReader::GetTypeInfoCount(UINT* pctinfo) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_AuthorName(BSTR* pbstrAuthorName) -{ - CheckPointer(pbstrAuthorName, E_POINTER); - CString str = m_stream.m_trackArtist; - if (str.IsEmpty()) { - str = m_stream.m_discArtist; - } - *pbstrAuthorName = str.AllocSysString(); - return S_OK; -} - -STDMETHODIMP CCDDAReader::get_Title(BSTR* pbstrTitle) -{ - CheckPointer(pbstrTitle, E_POINTER); - CString str = m_stream.m_trackTitle; - if (str.IsEmpty()) { - str = m_stream.m_discTitle; - } - *pbstrTitle = str.AllocSysString(); - return S_OK; -} - -STDMETHODIMP CCDDAReader::get_Rating(BSTR* pbstrRating) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_Description(BSTR* pbstrDescription) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_Copyright(BSTR* pbstrCopyright) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_BaseURL(BSTR* pbstrBaseURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_LogoURL(BSTR* pbstrLogoURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_LogoIconURL(BSTR* pbstrLogoURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_WatermarkURL(BSTR* pbstrWatermarkURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_MoreInfoURL(BSTR* pbstrMoreInfoURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CCDDAReader::get_MoreInfoText(BSTR* pbstrMoreInfoText) -{ - return E_NOTIMPL; -} - -// CCDDAStream - -CCDDAStream::CCDDAStream() -{ - m_hDrive = INVALID_HANDLE_VALUE; - - m_llPosition = m_llLength = 0; - - ZeroMemory(&m_TOC, sizeof(m_TOC)); - m_nFirstSector = m_nStartSector = m_nStopSector = 0; - - ZeroMemory(&m_header, sizeof(m_header)); - m_header.riff.hdr.chunkID = RIFFID; - m_header.riff.WAVE = WAVEID; - m_header.frm.hdr.chunkID = FormatID; - m_header.frm.hdr.chunkSize = sizeof(m_header.frm.pcm); - m_header.frm.pcm.wf.wFormatTag = WAVE_FORMAT_PCM; - m_header.frm.pcm.wf.nSamplesPerSec = 44100; - m_header.frm.pcm.wf.nChannels = 2; - m_header.frm.pcm.wBitsPerSample = 16; - m_header.frm.pcm.wf.nBlockAlign = m_header.frm.pcm.wf.nChannels * m_header.frm.pcm.wBitsPerSample / 8; - m_header.frm.pcm.wf.nAvgBytesPerSec = m_header.frm.pcm.wf.nSamplesPerSec * m_header.frm.pcm.wf.nBlockAlign; - m_header.data.hdr.chunkID = DataID; - - m_bDTS = false; -} - -CCDDAStream::~CCDDAStream() -{ - if (m_hDrive != INVALID_HANDLE_VALUE) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - } -} - -bool CCDDAStream::Load(const WCHAR* fnw) -{ - CString path(fnw); - - int iDriveLetter = path.Find(_T(":\\")) - 1; - int iTrackIndex = CString(path).MakeLower().Find(_T(".cda")) - 1; - if (iDriveLetter < 0 || iTrackIndex <= iDriveLetter) { - return false; - } - - CString drive = CString(_T("\\\\.\\")) + path[iDriveLetter] + _T(":"); - while (iTrackIndex > 0 && _istdigit(path[iTrackIndex - 1])) { - iTrackIndex--; - } - if (1 != _stscanf_s(path.Mid(iTrackIndex), _T("%d"), &iTrackIndex)) { - return false; - } - - if (m_hDrive != INVALID_HANDLE_VALUE) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - } - - m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); - if (m_hDrive == INVALID_HANDLE_VALUE) { - return false; - } - - DWORD BytesReturned; - if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &m_TOC, sizeof(m_TOC), &BytesReturned, 0) - || !(m_TOC.FirstTrack <= iTrackIndex && iTrackIndex <= m_TOC.LastTrack)) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - return false; - } - - // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field - m_TOC.TrackData[iTrackIndex - 1].Control &= 5; - if (!(m_TOC.TrackData[iTrackIndex - 1].Control == 0 || m_TOC.TrackData[iTrackIndex - 1].Control == 1)) { - CloseHandle(m_hDrive); - m_hDrive = INVALID_HANDLE_VALUE; - return false; - } - - if (m_TOC.TrackData[iTrackIndex - 1].Control & 8) { - m_header.frm.pcm.wf.nChannels = 4; - } - - m_nStartSector = MSF2UINT(m_TOC.TrackData[iTrackIndex - 1].Address) - 150; - m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150; - - m_llLength = LONGLONG(m_nStopSector - m_nStartSector) * RAW_SECTOR_SIZE; - - m_header.riff.hdr.chunkSize = (long)(m_llLength + sizeof(m_header) - 8); - m_header.data.hdr.chunkSize = (long)(m_llLength); - - // Detect DTS Music Disk - m_bDTS = false; - - // DCA syncwords - const DWORD DCA_MARKER_RAW_BE = 0x7FFE8001; - const DWORD DCA_MARKER_RAW_LE = 0xFE7F0180; - const DWORD DCA_MARKER_14B_BE = 0x1FFFE800; - const DWORD DCA_MARKER_14B_LE = 0xFF1F00E8; - UINT nMarkerFound = 0, nAttempt = 0; - DWORD marker = DWORD_MAX; - - std::vector data(16384); - DWORD dwSizeRead = 0; - while (SUCCEEDED(Read(data.data(), (DWORD)data.size(), TRUE, &dwSizeRead)) && dwSizeRead && nAttempt < (4 + nMarkerFound)) { - nAttempt++; - - for (DWORD i = 0; i < dwSizeRead; i++) { - marker = (marker << 8) | data[i]; - if ((marker == DCA_MARKER_14B_LE && (i < dwSizeRead - 2) && (data[i + 1] & 0xF0) == 0xF0 && data[i + 2] == 0x07) - || (marker == DCA_MARKER_14B_BE && (i < dwSizeRead - 2) && data[i + 1] == 0x07 && (data[i + 2] & 0xF0) == 0xF0) - || marker == DCA_MARKER_RAW_LE || marker == DCA_MARKER_RAW_BE) { - nMarkerFound++; - } - } - dwSizeRead = 0; - - if (nMarkerFound >= 4) { - m_bDTS = true; - break; - } - } - SetPointer(0); - - CDROM_READ_TOC_EX TOCEx; - ZeroMemory(&TOCEx, sizeof(TOCEx)); - TOCEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT; - BYTE header[4] = { 0 }; - static_assert(sizeof(header) >= MINIMUM_CDROM_READ_TOC_EX_SIZE, "sizeof(header) must be greater or equal to MINIMUM_CDROM_READ_TOC_EX_SIZE"); - if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), header, sizeof(header), &BytesReturned, 0)) { - return true; - } - - DWORD size = 2 + (WORD(header[0]) << 8) + header[1]; - if (size <= 4) { // No cd-text information - return true; - } - - CAutoVectorPtr pCDTextData; - if (!pCDTextData.Allocate(size)) { - return true; - } - ZeroMemory(pCDTextData, size); - - if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), pCDTextData, size, &BytesReturned, 0)) { - return true; - } - - size = (WORD)(BytesReturned - sizeof(CDROM_TOC_CD_TEXT_DATA)); - CDROM_TOC_CD_TEXT_DATA_BLOCK* pDesc = ((CDROM_TOC_CD_TEXT_DATA*)(BYTE*)pCDTextData)->Descriptors; - - CStringArray str[16]; - for (int i = 0; i < _countof(str); i++) { - str[i].SetSize(1 + m_TOC.LastTrack); - } - CString last; - - for (int i = 0; size >= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK); i++, size -= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK), pDesc++) { - if (pDesc->TrackNumber > m_TOC.LastTrack) { - continue; - } - - CString text; - CString tmp; - if (pDesc->Unicode) { - const int lenW = _countof(pDesc->WText); - text = CString(CStringW((WCHAR*)pDesc->WText, lenW)); - int tlen = text.GetLength(); - int nLength = lenW - (tlen + 1); - if (nLength > 0 && tlen < 11) { - tmp = CString(CStringW((WCHAR*)pDesc->WText + tlen + 1, nLength)); - } else { - tmp = CString(_T("")); - } - } else { - const int lenU = _countof(pDesc->Text); - text = CString(CStringA((CHAR*)pDesc->Text, lenU)); - int tlen = text.GetLength(); - int nLength = lenU - (tlen + 1); - if (nLength > 0 && tlen < 11) { - tmp = CString(CStringA( (CHAR*)pDesc->Text + tlen + 1, nLength)); - } else { - tmp = CString(""); - } - } - - if (pDesc->PackType < 0x80 || pDesc->PackType >= 0x80 + 0x10) { - continue; - } - pDesc->PackType -= 0x80; - - if (pDesc->CharacterPosition == 0) { - str[pDesc->PackType][pDesc->TrackNumber] = text; - } else { // pDesc->CharacterPosition <= 0xf since CharacterPosition is a 4-bit field - if (pDesc->CharacterPosition < 0xf && !last.IsEmpty()) { - str[pDesc->PackType][pDesc->TrackNumber] = last + text; - } else { - str[pDesc->PackType][pDesc->TrackNumber] += text; - } - } - - last = tmp; - } - - m_discTitle = str[0][0]; - m_trackTitle = str[0][iTrackIndex]; - m_discArtist = str[1][0]; - m_trackArtist = str[1][iTrackIndex]; - - return true; -} - -HRESULT CCDDAStream::SetPointer(LONGLONG llPos) -{ - if (llPos < 0 || llPos > m_llLength) { - return S_FALSE; - } - m_llPosition = llPos; - return S_OK; -} - -HRESULT CCDDAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) -{ - CAutoLock lck(&m_csLock); - - PBYTE pbBufferOrg = pbBuffer; - LONGLONG pos = m_llPosition; - size_t len = dwBytesToRead; - - if (!m_bDTS) { - if (pos < sizeof(m_header) && len > 0) { - size_t l = std::min(len, size_t(sizeof(m_header) - pos)); - memcpy(pbBuffer, &((BYTE*)&m_header)[pos], l); - pbBuffer += l; - pos += l; - len -= l; - } - - pos -= sizeof(m_header); - } - - while (pos >= 0 && pos < m_llLength && len > 0) { - RAW_READ_INFO rawreadinfo; - rawreadinfo.TrackMode = CDDA; - - UINT sector = m_nStartSector + UINT(pos / RAW_SECTOR_SIZE); - UINT offset = pos % RAW_SECTOR_SIZE; - - // Reading 20 sectors at once seems to be a good trade-off between performance and compatibility - rawreadinfo.SectorCount = std::min(20u, m_nStopSector - sector); - - if (m_buff.size() < rawreadinfo.SectorCount * RAW_SECTOR_SIZE) { - m_buff.resize(rawreadinfo.SectorCount * RAW_SECTOR_SIZE); - } - - rawreadinfo.DiskOffset.QuadPart = sector * 2048; - DWORD dwBytesReturned = 0; - VERIFY(DeviceIoControl(m_hDrive, IOCTL_CDROM_RAW_READ, - &rawreadinfo, sizeof(rawreadinfo), - m_buff.data(), (DWORD)m_buff.size(), - &dwBytesReturned, 0)); - - size_t l = std::min(std::min(len, m_buff.size() - offset), size_t(m_llLength - pos)); - memcpy(pbBuffer, &m_buff[offset], l); - - pbBuffer += l; - pos += l; - len -= l; - } - - if (pdwBytesRead) { - *pdwBytesRead = DWORD(pbBuffer - pbBufferOrg); - } - m_llPosition += pbBuffer - pbBufferOrg; - - return S_OK; -} - -LONGLONG CCDDAStream::Size(LONGLONG* pSizeAvailable) -{ - LONGLONG size = m_llLength; - if (!m_bDTS) { - size += sizeof(m_header); - } - if (pSizeAvailable) { - *pSizeAvailable = size; - } - return size; -} - -DWORD CCDDAStream::Alignment() -{ - return 1; -} - -void CCDDAStream::Lock() -{ - m_csLock.Lock(); -} - -void CCDDAStream::Unlock() -{ - m_csLock.Unlock(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#ifdef STANDALONE_FILTER +#include +#endif +#include "CDDAReader.h" +#include "../../../DSUtil/DSUtil.h" + +#define RAW_SECTOR_SIZE 2352 +#define MSF2UINT(hgs) ((hgs[1] * 4500) + (hgs[2] * 75) + (hgs[3])) + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE}, +}; + +const AMOVIESETUP_PIN sudOpPin[] = { + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}, +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CCDDAReader), CCDDAReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"), + _T("0"), _T("0,4,,52494646,8,4,,43444441")); // "RIFFxxxxCDDA" + + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}"), + _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".cda"), + _T("Source Filter"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); + + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{54A35221-2C8D-4a31-A5DF-6D809847E393}")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".cda")); + + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CCDDAReader +// + +CCDDAReader::CCDDAReader(IUnknown* pUnk, HRESULT* phr) + : CAsyncReader(NAME("CCDDAReader"), pUnk, &m_stream, phr, __uuidof(this)) +{ + if (phr) { + *phr = S_OK; + } +} + +CCDDAReader::~CCDDAReader() +{ +} + +STDMETHODIMP CCDDAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFileSourceFilter) + QI2(IAMMediaContent) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CCDDAReader::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + + wcscpy_s(pInfo->achName, CCDDAReaderName); + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +// IFileSourceFilter + +STDMETHODIMP CCDDAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + if (!m_stream.Load(pszFileName)) { + return E_FAIL; + } + + m_fn = pszFileName; + + CMediaType mt; + mt.majortype = MEDIATYPE_Stream; + mt.subtype = m_stream.IsDTS() ? MEDIASUBTYPE_DTS : MEDIASUBTYPE_WAVE; + m_mt = mt; + + return S_OK; +} + +STDMETHODIMP CCDDAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + + return S_OK; +} + +// IAMMediaContent + +STDMETHODIMP CCDDAReader::GetTypeInfoCount(UINT* pctinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_AuthorName(BSTR* pbstrAuthorName) +{ + CheckPointer(pbstrAuthorName, E_POINTER); + CString str = m_stream.m_trackArtist; + if (str.IsEmpty()) { + str = m_stream.m_discArtist; + } + *pbstrAuthorName = str.AllocSysString(); + return S_OK; +} + +STDMETHODIMP CCDDAReader::get_Title(BSTR* pbstrTitle) +{ + CheckPointer(pbstrTitle, E_POINTER); + CString str = m_stream.m_trackTitle; + if (str.IsEmpty()) { + str = m_stream.m_discTitle; + } + *pbstrTitle = str.AllocSysString(); + return S_OK; +} + +STDMETHODIMP CCDDAReader::get_Rating(BSTR* pbstrRating) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_Description(BSTR* pbstrDescription) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_Copyright(BSTR* pbstrCopyright) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_BaseURL(BSTR* pbstrBaseURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_LogoURL(BSTR* pbstrLogoURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_LogoIconURL(BSTR* pbstrLogoURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_WatermarkURL(BSTR* pbstrWatermarkURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_MoreInfoURL(BSTR* pbstrMoreInfoURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CCDDAReader::get_MoreInfoText(BSTR* pbstrMoreInfoText) +{ + return E_NOTIMPL; +} + +// CCDDAStream + +CCDDAStream::CCDDAStream() +{ + m_hDrive = INVALID_HANDLE_VALUE; + + m_llPosition = m_llLength = 0; + + ZeroMemory(&m_TOC, sizeof(m_TOC)); + m_nFirstSector = m_nStartSector = m_nStopSector = 0; + + ZeroMemory(&m_header, sizeof(m_header)); + m_header.riff.hdr.chunkID = RIFFID; + m_header.riff.WAVE = WAVEID; + m_header.frm.hdr.chunkID = FormatID; + m_header.frm.hdr.chunkSize = sizeof(m_header.frm.pcm); + m_header.frm.pcm.wf.wFormatTag = WAVE_FORMAT_PCM; + m_header.frm.pcm.wf.nSamplesPerSec = 44100; + m_header.frm.pcm.wf.nChannels = 2; + m_header.frm.pcm.wBitsPerSample = 16; + m_header.frm.pcm.wf.nBlockAlign = m_header.frm.pcm.wf.nChannels * m_header.frm.pcm.wBitsPerSample / 8; + m_header.frm.pcm.wf.nAvgBytesPerSec = m_header.frm.pcm.wf.nSamplesPerSec * m_header.frm.pcm.wf.nBlockAlign; + m_header.data.hdr.chunkID = DataID; + + m_bDTS = false; +} + +CCDDAStream::~CCDDAStream() +{ + if (m_hDrive != INVALID_HANDLE_VALUE) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + } +} + +bool CCDDAStream::Load(const WCHAR* fnw) +{ + CString path(fnw); + + int iDriveLetter = path.Find(_T(":\\")) - 1; + int iTrackIndex = CString(path).MakeLower().Find(_T(".cda")) - 1; + if (iDriveLetter < 0 || iTrackIndex <= iDriveLetter) { + return false; + } + + CString drive = CString(_T("\\\\.\\")) + path[iDriveLetter] + _T(":"); + while (iTrackIndex > 0 && _istdigit(path[iTrackIndex - 1])) { + iTrackIndex--; + } + if (1 != _stscanf_s(path.Mid(iTrackIndex), _T("%d"), &iTrackIndex)) { + return false; + } + + if (m_hDrive != INVALID_HANDLE_VALUE) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + } + + m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); + if (m_hDrive == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD BytesReturned; + if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &m_TOC, sizeof(m_TOC), &BytesReturned, 0) + || !(m_TOC.FirstTrack <= iTrackIndex && iTrackIndex <= m_TOC.LastTrack)) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + return false; + } + + // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field + m_TOC.TrackData[iTrackIndex - 1].Control &= 5; + if (!(m_TOC.TrackData[iTrackIndex - 1].Control == 0 || m_TOC.TrackData[iTrackIndex - 1].Control == 1)) { + CloseHandle(m_hDrive); + m_hDrive = INVALID_HANDLE_VALUE; + return false; + } + + if (m_TOC.TrackData[iTrackIndex - 1].Control & 8) { + m_header.frm.pcm.wf.nChannels = 4; + } + + m_nStartSector = MSF2UINT(m_TOC.TrackData[iTrackIndex - 1].Address) - 150; + m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150; + + m_llLength = LONGLONG(m_nStopSector - m_nStartSector) * RAW_SECTOR_SIZE; + + m_header.riff.hdr.chunkSize = (long)(m_llLength + sizeof(m_header) - 8); + m_header.data.hdr.chunkSize = (long)(m_llLength); + + // Detect DTS Music Disk + m_bDTS = false; + + // DCA syncwords + const DWORD DCA_MARKER_RAW_BE = 0x7FFE8001; + const DWORD DCA_MARKER_RAW_LE = 0xFE7F0180; + const DWORD DCA_MARKER_14B_BE = 0x1FFFE800; + const DWORD DCA_MARKER_14B_LE = 0xFF1F00E8; + UINT nMarkerFound = 0, nAttempt = 0; + DWORD marker = DWORD_MAX; + + std::vector data(16384); + DWORD dwSizeRead = 0; + while (SUCCEEDED(Read(data.data(), (DWORD)data.size(), TRUE, &dwSizeRead)) && dwSizeRead && nAttempt < (4 + nMarkerFound)) { + nAttempt++; + + for (DWORD i = 0; i < dwSizeRead; i++) { + marker = (marker << 8) | data[i]; + if ((marker == DCA_MARKER_14B_LE && (i < dwSizeRead - 2) && (data[i + 1] & 0xF0) == 0xF0 && data[i + 2] == 0x07) + || (marker == DCA_MARKER_14B_BE && (i < dwSizeRead - 2) && data[i + 1] == 0x07 && (data[i + 2] & 0xF0) == 0xF0) + || marker == DCA_MARKER_RAW_LE || marker == DCA_MARKER_RAW_BE) { + nMarkerFound++; + } + } + dwSizeRead = 0; + + if (nMarkerFound >= 4) { + m_bDTS = true; + break; + } + } + SetPointer(0); + + CDROM_READ_TOC_EX TOCEx; + ZeroMemory(&TOCEx, sizeof(TOCEx)); + TOCEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT; + BYTE header[4] = { 0 }; + static_assert(sizeof(header) >= MINIMUM_CDROM_READ_TOC_EX_SIZE, "sizeof(header) must be greater or equal to MINIMUM_CDROM_READ_TOC_EX_SIZE"); + if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), header, sizeof(header), &BytesReturned, 0)) { + return true; + } + + DWORD size = 2 + (WORD(header[0]) << 8) + header[1]; + if (size <= 4) { // No cd-text information + return true; + } + + CAutoVectorPtr pCDTextData; + if (!pCDTextData.Allocate(size)) { + return true; + } + ZeroMemory(pCDTextData, size); + + if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), pCDTextData, size, &BytesReturned, 0)) { + return true; + } + + size = (WORD)(BytesReturned - sizeof(CDROM_TOC_CD_TEXT_DATA)); + CDROM_TOC_CD_TEXT_DATA_BLOCK* pDesc = ((CDROM_TOC_CD_TEXT_DATA*)(BYTE*)pCDTextData)->Descriptors; + + CStringArray str[16]; + for (int i = 0; i < _countof(str); i++) { + str[i].SetSize(1 + m_TOC.LastTrack); + } + CString last; + + for (int i = 0; size >= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK); i++, size -= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK), pDesc++) { + if (pDesc->TrackNumber > m_TOC.LastTrack) { + continue; + } + + CString text; + CString tmp; + if (pDesc->Unicode) { + const int lenW = _countof(pDesc->WText); + text = CString(CStringW((WCHAR*)pDesc->WText, lenW)); + int tlen = text.GetLength(); + int nLength = lenW - (tlen + 1); + if (nLength > 0 && tlen < 11) { + tmp = CString(CStringW((WCHAR*)pDesc->WText + tlen + 1, nLength)); + } else { + tmp = CString(_T("")); + } + } else { + const int lenU = _countof(pDesc->Text); + text = CString(CStringA((CHAR*)pDesc->Text, lenU)); + int tlen = text.GetLength(); + int nLength = lenU - (tlen + 1); + if (nLength > 0 && tlen < 11) { + tmp = CString(CStringA( (CHAR*)pDesc->Text + tlen + 1, nLength)); + } else { + tmp = CString(""); + } + } + + if (pDesc->PackType < 0x80 || pDesc->PackType >= 0x80 + 0x10) { + continue; + } + pDesc->PackType -= 0x80; + + if (pDesc->CharacterPosition == 0) { + str[pDesc->PackType][pDesc->TrackNumber] = text; + } else { // pDesc->CharacterPosition <= 0xf since CharacterPosition is a 4-bit field + if (pDesc->CharacterPosition < 0xf && !last.IsEmpty()) { + str[pDesc->PackType][pDesc->TrackNumber] = last + text; + } else { + str[pDesc->PackType][pDesc->TrackNumber] += text; + } + } + + last = tmp; + } + + m_discTitle = str[0][0]; + m_trackTitle = str[0][iTrackIndex]; + m_discArtist = str[1][0]; + m_trackArtist = str[1][iTrackIndex]; + + return true; +} + +HRESULT CCDDAStream::SetPointer(LONGLONG llPos) +{ + if (llPos < 0 || llPos > m_llLength) { + return S_FALSE; + } + m_llPosition = llPos; + return S_OK; +} + +HRESULT CCDDAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) +{ + CAutoLock lck(&m_csLock); + + PBYTE pbBufferOrg = pbBuffer; + LONGLONG pos = m_llPosition; + size_t len = dwBytesToRead; + + if (!m_bDTS) { + if (pos < sizeof(m_header) && len > 0) { + size_t l = std::min(len, size_t(sizeof(m_header) - pos)); + memcpy(pbBuffer, &((BYTE*)&m_header)[pos], l); + pbBuffer += l; + pos += l; + len -= l; + } + + pos -= sizeof(m_header); + } + + while (pos >= 0 && pos < m_llLength && len > 0) { + RAW_READ_INFO rawreadinfo; + rawreadinfo.TrackMode = CDDA; + + UINT sector = m_nStartSector + UINT(pos / RAW_SECTOR_SIZE); + UINT offset = pos % RAW_SECTOR_SIZE; + + // Reading 20 sectors at once seems to be a good trade-off between performance and compatibility + rawreadinfo.SectorCount = std::min(20u, m_nStopSector - sector); + + if (m_buff.size() < rawreadinfo.SectorCount * RAW_SECTOR_SIZE) { + m_buff.resize(rawreadinfo.SectorCount * RAW_SECTOR_SIZE); + } + + rawreadinfo.DiskOffset.QuadPart = sector * 2048; + DWORD dwBytesReturned = 0; + VERIFY(DeviceIoControl(m_hDrive, IOCTL_CDROM_RAW_READ, + &rawreadinfo, sizeof(rawreadinfo), + m_buff.data(), (DWORD)m_buff.size(), + &dwBytesReturned, 0)); + + size_t l = std::min(std::min(len, m_buff.size() - offset), size_t(m_llLength - pos)); + memcpy(pbBuffer, &m_buff[offset], l); + + pbBuffer += l; + pos += l; + len -= l; + } + + if (pdwBytesRead) { + *pdwBytesRead = DWORD(pbBuffer - pbBufferOrg); + } + m_llPosition += pbBuffer - pbBufferOrg; + + return S_OK; +} + +LONGLONG CCDDAStream::Size(LONGLONG* pSizeAvailable) +{ + LONGLONG size = m_llLength; + if (!m_bDTS) { + size += sizeof(m_header); + } + if (pSizeAvailable) { + *pSizeAvailable = size; + } + return size; +} + +DWORD CCDDAStream::Alignment() +{ + return 1; +} + +void CCDDAStream::Lock() +{ + m_csLock.Lock(); +} + +void CCDDAStream::Unlock() +{ + m_csLock.Unlock(); +} diff --git a/src/filters/reader/CDDAReader/CDDAReader.def b/src/filters/reader/CDDAReader/CDDAReader.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.def +++ b/src/filters/reader/CDDAReader/CDDAReader.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/reader/CDDAReader/CDDAReader.h b/src/filters/reader/CDDAReader/CDDAReader.h index 6b38e9a4d6d..fb34c6722ee 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.h +++ b/src/filters/reader/CDDAReader/CDDAReader.h @@ -1,143 +1,143 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include -#include -#include "winddk/devioctl.h" -#include "winddk/ntddcdrm.h" -#include -#include "AsyncReader/asyncio.h" -#include "AsyncReader/asyncrdr.h" - -#define CCDDAReaderName L"MPC-HC CDDA Reader" - -struct ChunkHeader { - UINT chunkID; - long chunkSize; -}; - -#define RIFFID 'FFIR' -#define WAVEID 'EVAW' -struct RIFFChunk { - ChunkHeader hdr; - UINT WAVE; -}; - -#define FormatID ' tmf' -struct FormatChunk { - ChunkHeader hdr; - PCMWAVEFORMAT pcm; -}; - -#define DataID 'atad' -struct DataChunk { - ChunkHeader hdr; -}; - -struct WAVEChunck { - RIFFChunk riff; - FormatChunk frm; - DataChunk data; -}; - -class CCDDAStream : public CAsyncStream -{ -private: - CCritSec m_csLock; - - LONGLONG m_llPosition, m_llLength; - - HANDLE m_hDrive; - CDROM_TOC m_TOC; - UINT m_nFirstSector, m_nStartSector, m_nStopSector; - bool m_bDTS; - - WAVEChunck m_header; - - std::vector m_buff; -public: - CCDDAStream(); - virtual ~CCDDAStream(); - - CString m_discTitle, m_trackTitle; - CString m_discArtist, m_trackArtist; - - bool Load(const WCHAR* fnw); - - bool IsDTS() const { return m_bDTS; }; - - // overrides - HRESULT SetPointer(LONGLONG llPos); - HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); - LONGLONG Size(LONGLONG* pSizeAvailable); - DWORD Alignment(); - void Lock(); - void Unlock(); -}; - -class __declspec(uuid("54A35221-2C8D-4a31-A5DF-6D809847E393")) - CCDDAReader - : public CAsyncReader - , public IFileSourceFilter - , public IAMMediaContent -{ - CCDDAStream m_stream; - CStringW m_fn; - -public: - CCDDAReader(IUnknown* pUnk, HRESULT* phr); - ~CCDDAReader(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // CBaseFilter - - STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); - - // IFileSourceFilter - - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); - - // IAMMediaContent - - STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); - STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo); - STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid); - STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr); - - STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName); - STDMETHODIMP get_Title(BSTR* pbstrTitle); - STDMETHODIMP get_Rating(BSTR* pbstrRating); - STDMETHODIMP get_Description(BSTR* pbstrDescription); - STDMETHODIMP get_Copyright(BSTR* pbstrCopyright); - STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL); - STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL); - STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL); - STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL); - STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL); - STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage); - STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL); - STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include +#include +#include "winddk/devioctl.h" +#include "winddk/ntddcdrm.h" +#include +#include "AsyncReader/asyncio.h" +#include "AsyncReader/asyncrdr.h" + +#define CCDDAReaderName L"MPC-HC CDDA Reader" + +struct ChunkHeader { + UINT chunkID; + long chunkSize; +}; + +#define RIFFID 'FFIR' +#define WAVEID 'EVAW' +struct RIFFChunk { + ChunkHeader hdr; + UINT WAVE; +}; + +#define FormatID ' tmf' +struct FormatChunk { + ChunkHeader hdr; + PCMWAVEFORMAT pcm; +}; + +#define DataID 'atad' +struct DataChunk { + ChunkHeader hdr; +}; + +struct WAVEChunck { + RIFFChunk riff; + FormatChunk frm; + DataChunk data; +}; + +class CCDDAStream : public CAsyncStream +{ +private: + CCritSec m_csLock; + + LONGLONG m_llPosition, m_llLength; + + HANDLE m_hDrive; + CDROM_TOC m_TOC; + UINT m_nFirstSector, m_nStartSector, m_nStopSector; + bool m_bDTS; + + WAVEChunck m_header; + + std::vector m_buff; +public: + CCDDAStream(); + virtual ~CCDDAStream(); + + CString m_discTitle, m_trackTitle; + CString m_discArtist, m_trackArtist; + + bool Load(const WCHAR* fnw); + + bool IsDTS() const { return m_bDTS; }; + + // overrides + HRESULT SetPointer(LONGLONG llPos); + HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); + LONGLONG Size(LONGLONG* pSizeAvailable); + DWORD Alignment(); + void Lock(); + void Unlock(); +}; + +class __declspec(uuid("54A35221-2C8D-4a31-A5DF-6D809847E393")) + CCDDAReader + : public CAsyncReader + , public IFileSourceFilter + , public IAMMediaContent +{ + CCDDAStream m_stream; + CStringW m_fn; + +public: + CCDDAReader(IUnknown* pUnk, HRESULT* phr); + ~CCDDAReader(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // CBaseFilter + + STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); + + // IFileSourceFilter + + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); + + // IAMMediaContent + + STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); + STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo); + STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid); + STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr); + + STDMETHODIMP get_AuthorName(BSTR* pbstrAuthorName); + STDMETHODIMP get_Title(BSTR* pbstrTitle); + STDMETHODIMP get_Rating(BSTR* pbstrRating); + STDMETHODIMP get_Description(BSTR* pbstrDescription); + STDMETHODIMP get_Copyright(BSTR* pbstrCopyright); + STDMETHODIMP get_BaseURL(BSTR* pbstrBaseURL); + STDMETHODIMP get_LogoURL(BSTR* pbstrLogoURL); + STDMETHODIMP get_LogoIconURL(BSTR* pbstrLogoURL); + STDMETHODIMP get_WatermarkURL(BSTR* pbstrWatermarkURL); + STDMETHODIMP get_MoreInfoURL(BSTR* pbstrMoreInfoURL); + STDMETHODIMP get_MoreInfoBannerImage(BSTR* pbstrMoreInfoBannerImage); + STDMETHODIMP get_MoreInfoBannerURL(BSTR* pbstrMoreInfoBannerURL); + STDMETHODIMP get_MoreInfoText(BSTR* pbstrMoreInfoText); +}; diff --git a/src/filters/reader/CDDAReader/CDDAReader.rc b/src/filters/reader/CDDAReader/CDDAReader.rc index 8ec8c11ffbe..b11cb32ed5c 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.rc +++ b/src/filters/reader/CDDAReader/CDDAReader.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "CDDA Reader Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "CDDA Reader Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "CDDAReader.ax" - VALUE "ProductName", "CDDA Reader Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "CDDA Reader Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "CDDA Reader Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "CDDAReader.ax" + VALUE "ProductName", "CDDA Reader Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/reader/CDDAReader/CDDAReader.vcxproj b/src/filters/reader/CDDAReader/CDDAReader.vcxproj index f9c2db96ff3..d8a4dbe97e7 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.vcxproj +++ b/src/filters/reader/CDDAReader/CDDAReader.vcxproj @@ -1,127 +1,127 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {543D40E9-8CA6-4E4B-9936-90CBA562B268} - CDDAReader - MFCProj - CDDAReader - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - CDDAReader.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {9f31d122-e84d-485a-a58d-09dad01a56ce} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {543D40E9-8CA6-4E4B-9936-90CBA562B268} + CDDAReader + MFCProj + CDDAReader + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + CDDAReader.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {9f31d122-e84d-485a-a58d-09dad01a56ce} + + + + + \ No newline at end of file diff --git a/src/filters/reader/CDDAReader/CDDAReader.vcxproj.filters b/src/filters/reader/CDDAReader/CDDAReader.vcxproj.filters index b346ad121af..0df042c209b 100644 --- a/src/filters/reader/CDDAReader/CDDAReader.vcxproj.filters +++ b/src/filters/reader/CDDAReader/CDDAReader.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {3251baa6-81ad-4ee0-a183-a0ace02fd96c} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {4e594eac-878e-4f75-84cf-61b6779dd162} - h;hpp;hxx;hm;inl;inc - - - {edb78716-8ad1-4c34-9651-495ae470c32a} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {3251baa6-81ad-4ee0-a183-a0ace02fd96c} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {4e594eac-878e-4f75-84cf-61b6779dd162} + h;hpp;hxx;hm;inl;inc + + + {edb78716-8ad1-4c34-9651-495ae470c32a} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/reader/CDDAReader/resource.h b/src/filters/reader/CDDAReader/resource.h index 0b70277da3b..6fd241bb55d 100644 --- a/src/filters/reader/CDDAReader/resource.h +++ b/src/filters/reader/CDDAReader/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by CDDAReader.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by CDDAReader.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/reader/CDDAReader/stdafx.cpp b/src/filters/reader/CDDAReader/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/reader/CDDAReader/stdafx.cpp +++ b/src/filters/reader/CDDAReader/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/reader/CDDAReader/stdafx.h b/src/filters/reader/CDDAReader/stdafx.h index 12bbe2db0a7..d8320f2c878 100644 --- a/src/filters/reader/CDDAReader/stdafx.h +++ b/src/filters/reader/CDDAReader/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/reader/CDXAReader/CDXAReader.cpp b/src/filters/reader/CDXAReader/CDXAReader.cpp index 6ddbdd4ce1d..bd042a1f189 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.cpp +++ b/src/filters/reader/CDXAReader/CDXAReader.cpp @@ -1,561 +1,561 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "CDXAReader.h" -#include "../../../DSUtil/DSUtil.h" -#ifdef STANDALONE_FILTER -#include -#endif -#include -#include "moreuuids.h" - -///////// - -static constexpr DWORD EDC_crctable[256] = { - 0x00000000l, 0x90910101l, 0x91210201l, 0x01b00300l, - 0x92410401l, 0x02d00500l, 0x03600600l, 0x93f10701l, - 0x94810801l, 0x04100900l, 0x05a00a00l, 0x95310b01l, - 0x06c00c00l, 0x96510d01l, 0x97e10e01l, 0x07700f00l, - 0x99011001l, 0x09901100l, 0x08201200l, 0x98b11301l, - 0x0b401400l, 0x9bd11501l, 0x9a611601l, 0x0af01700l, - 0x0d801800l, 0x9d111901l, 0x9ca11a01l, 0x0c301b00l, - 0x9fc11c01l, 0x0f501d00l, 0x0ee01e00l, 0x9e711f01l, - 0x82012001l, 0x12902100l, 0x13202200l, 0x83b12301l, - 0x10402400l, 0x80d12501l, 0x81612601l, 0x11f02700l, - 0x16802800l, 0x86112901l, 0x87a12a01l, 0x17302b00l, - 0x84c12c01l, 0x14502d00l, 0x15e02e00l, 0x85712f01l, - 0x1b003000l, 0x8b913101l, 0x8a213201l, 0x1ab03300l, - 0x89413401l, 0x19d03500l, 0x18603600l, 0x88f13701l, - 0x8f813801l, 0x1f103900l, 0x1ea03a00l, 0x8e313b01l, - 0x1dc03c00l, 0x8d513d01l, 0x8ce13e01l, 0x1c703f00l, - 0xb4014001l, 0x24904100l, 0x25204200l, 0xb5b14301l, - 0x26404400l, 0xb6d14501l, 0xb7614601l, 0x27f04700l, - 0x20804800l, 0xb0114901l, 0xb1a14a01l, 0x21304b00l, - 0xb2c14c01l, 0x22504d00l, 0x23e04e00l, 0xb3714f01l, - 0x2d005000l, 0xbd915101l, 0xbc215201l, 0x2cb05300l, - 0xbf415401l, 0x2fd05500l, 0x2e605600l, 0xbef15701l, - 0xb9815801l, 0x29105900l, 0x28a05a00l, 0xb8315b01l, - 0x2bc05c00l, 0xbb515d01l, 0xbae15e01l, 0x2a705f00l, - 0x36006000l, 0xa6916101l, 0xa7216201l, 0x37b06300l, - 0xa4416401l, 0x34d06500l, 0x35606600l, 0xa5f16701l, - 0xa2816801l, 0x32106900l, 0x33a06a00l, 0xa3316b01l, - 0x30c06c00l, 0xa0516d01l, 0xa1e16e01l, 0x31706f00l, - 0xaf017001l, 0x3f907100l, 0x3e207200l, 0xaeb17301l, - 0x3d407400l, 0xadd17501l, 0xac617601l, 0x3cf07700l, - 0x3b807800l, 0xab117901l, 0xaaa17a01l, 0x3a307b00l, - 0xa9c17c01l, 0x39507d00l, 0x38e07e00l, 0xa8717f01l, - 0xd8018001l, 0x48908100l, 0x49208200l, 0xd9b18301l, - 0x4a408400l, 0xdad18501l, 0xdb618601l, 0x4bf08700l, - 0x4c808800l, 0xdc118901l, 0xdda18a01l, 0x4d308b00l, - 0xdec18c01l, 0x4e508d00l, 0x4fe08e00l, 0xdf718f01l, - 0x41009000l, 0xd1919101l, 0xd0219201l, 0x40b09300l, - 0xd3419401l, 0x43d09500l, 0x42609600l, 0xd2f19701l, - 0xd5819801l, 0x45109900l, 0x44a09a00l, 0xd4319b01l, - 0x47c09c00l, 0xd7519d01l, 0xd6e19e01l, 0x46709f00l, - 0x5a00a000l, 0xca91a101l, 0xcb21a201l, 0x5bb0a300l, - 0xc841a401l, 0x58d0a500l, 0x5960a600l, 0xc9f1a701l, - 0xce81a801l, 0x5e10a900l, 0x5fa0aa00l, 0xcf31ab01l, - 0x5cc0ac00l, 0xcc51ad01l, 0xcde1ae01l, 0x5d70af00l, - 0xc301b001l, 0x5390b100l, 0x5220b200l, 0xc2b1b301l, - 0x5140b400l, 0xc1d1b501l, 0xc061b601l, 0x50f0b700l, - 0x5780b800l, 0xc711b901l, 0xc6a1ba01l, 0x5630bb00l, - 0xc5c1bc01l, 0x5550bd00l, 0x54e0be00l, 0xc471bf01l, - 0x6c00c000l, 0xfc91c101l, 0xfd21c201l, 0x6db0c300l, - 0xfe41c401l, 0x6ed0c500l, 0x6f60c600l, 0xfff1c701l, - 0xf881c801l, 0x6810c900l, 0x69a0ca00l, 0xf931cb01l, - 0x6ac0cc00l, 0xfa51cd01l, 0xfbe1ce01l, 0x6b70cf00l, - 0xf501d001l, 0x6590d100l, 0x6420d200l, 0xf4b1d301l, - 0x6740d400l, 0xf7d1d501l, 0xf661d601l, 0x66f0d700l, - 0x6180d800l, 0xf111d901l, 0xf0a1da01l, 0x6030db00l, - 0xf3c1dc01l, 0x6350dd00l, 0x62e0de00l, 0xf271df01l, - 0xee01e001l, 0x7e90e100l, 0x7f20e200l, 0xefb1e301l, - 0x7c40e400l, 0xecd1e501l, 0xed61e601l, 0x7df0e700l, - 0x7a80e800l, 0xea11e901l, 0xeba1ea01l, 0x7b30eb00l, - 0xe8c1ec01l, 0x7850ed00l, 0x79e0ee00l, 0xe971ef01l, - 0x7700f000l, 0xe791f101l, 0xe621f201l, 0x76b0f300l, - 0xe541f401l, 0x75d0f500l, 0x7460f600l, 0xe4f1f701l, - 0xe381f801l, 0x7310f900l, 0x72a0fa00l, 0xe231fb01l, - 0x71c0fc00l, 0xe151fd01l, 0xe0e1fe01l, 0x7070ff00l -}; - -static DWORD build_edc(const void* in, unsigned from, unsigned upto) -{ - const BYTE* p = (BYTE*)in + from; - DWORD result = 0; - - for (; from < upto; from++) { - result = EDC_crctable[(result ^ *p++) & 0xffL] ^ (result >> 8); - } - - return result; -} - -///////// - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL} -}; - -const AMOVIESETUP_PIN sudOpPin[] = { - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CCDXAReader), CCDXAReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}"), - _T("0"), _T("0,4,,52494646,8,4,,43445841")); // "RIFFxxxxCDXA" - - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}"), - _T("Source Filter"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}")); - - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}")); - - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CCDXAReader -// - -CCDXAReader::CCDXAReader(IUnknown* pUnk, HRESULT* phr) - : CAsyncReader(NAME("CCDXAReader"), pUnk, &m_stream, phr, __uuidof(this)) -{ - if (phr) { - *phr = S_OK; - } -} - -CCDXAReader::~CCDXAReader() -{ -} - -STDMETHODIMP CCDXAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IFileSourceFilter) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CCDXAReader::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - - wcscpy_s(pInfo->achName, CCDXAReaderName); - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -STDMETHODIMP CCDXAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - CMediaType mt; - m_mt = mt; - - if (!m_stream.Load(pszFileName)) { - return E_FAIL; - } - - m_fn = pszFileName; - - mt.majortype = MEDIATYPE_Stream; - mt.subtype = m_stream.m_subtype; - m_mt = mt; - - return S_OK; -} - -STDMETHODIMP CCDXAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - - return S_OK; -} - -// CCDXAStream - -CCDXAStream::CCDXAStream() -{ - m_subtype = MEDIASUBTYPE_NULL; - - m_hFile = INVALID_HANDLE_VALUE; - - m_llPosition = m_llLength = 0; - m_nFirstSector = 0; - m_nBufferedSector = -1; - ZeroMemory(m_sector, sizeof(m_sector)); -} - -CCDXAStream::~CCDXAStream() -{ - if (m_hFile != INVALID_HANDLE_VALUE) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - } -} - -bool CCDXAStream::Load(const WCHAR* fnw) -{ - if (m_hFile != INVALID_HANDLE_VALUE) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - } - - m_hFile = CreateFile(CString(fnw), GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); - if (m_hFile == INVALID_HANDLE_VALUE) { - return false; - } - - BYTE hdr[RIFFCDXA_HEADER_SIZE]; - DWORD NumberOfBytesRead; - if (!ReadFile(m_hFile, (LPVOID)hdr, RIFFCDXA_HEADER_SIZE, &NumberOfBytesRead, nullptr) - || *((DWORD*)&hdr[0]) != 'FFIR' || *((DWORD*)&hdr[8]) != 'AXDC' - || *((DWORD*)&hdr[4]) != (*((DWORD*)&hdr[0x28]) + 0x24)) { - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - return false; - } - - LARGE_INTEGER size = {0, 0}; - GetFileSizeEx(m_hFile, &size); - - m_llLength = ((size.QuadPart - RIFFCDXA_HEADER_SIZE) / RAW_SECTOR_SIZE) * RAW_DATA_SIZE; - - if (!LookForMediaSubType()) { - m_llPosition = m_llLength = 0; - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - return false; - } - - m_llPosition = 0; - - m_nBufferedSector = -1; - - return true; -} - -HRESULT CCDXAStream::SetPointer(LONGLONG llPos) -{ - HRESULT hr = S_FALSE; - - if (llPos >= 0 && llPos < m_llLength) { - m_llPosition = llPos; - hr = S_OK; - } - - return hr; -} - -HRESULT CCDXAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) -{ - CAutoLock lck(&m_csLock); - - PBYTE pbBufferOrg = pbBuffer; - LONGLONG pos = m_llPosition; - - while (pos >= 0 && pos < m_llLength && dwBytesToRead > 0) { - UINT sector = m_nFirstSector + int(pos / RAW_DATA_SIZE); - __int64 offset = pos % RAW_DATA_SIZE; - - if (m_nBufferedSector != (int)sector) { - LARGE_INTEGER FilePointer; - FilePointer.QuadPart = RIFFCDXA_HEADER_SIZE + sector * RAW_SECTOR_SIZE; - SetFilePointerEx(m_hFile, FilePointer, &FilePointer, FILE_BEGIN); - - ZeroMemory(m_sector, sizeof(m_sector)); - - DWORD NumberOfBytesRead = 0; - - int nRetries = 3; - while (nRetries--) { - NumberOfBytesRead = 0; - if (!ReadFile(m_hFile, m_sector, RAW_SECTOR_SIZE, &NumberOfBytesRead, nullptr) - || NumberOfBytesRead != RAW_SECTOR_SIZE) { - break; - } - - if (*(DWORD*)&m_sector[RAW_SECTOR_SIZE - 4] == 0) { // no CRC? it happens... - break; - } - - if (build_edc(m_sector, RAW_SYNC_SIZE + RAW_HEADER_SIZE, RAW_SECTOR_SIZE) == 0) { - break; - } - - TRACE(_T("CCDXAStream: CRC error at sector %u (fp=0x%I64x, retriesleft=%d)\n"), sector, FilePointer.QuadPart, nRetries); - } - - m_nBufferedSector = sector; - } - - DWORD l = std::min(dwBytesToRead, (DWORD)std::min(RAW_DATA_SIZE - offset, m_llLength - pos)); - memcpy(pbBuffer, &m_sector[RAW_SYNC_SIZE + RAW_HEADER_SIZE + RAW_SUBHEADER_SIZE + offset], l); - - pbBuffer += l; - pos += l; - dwBytesToRead -= l; - } - - if (pdwBytesRead) { - *pdwBytesRead = DWORD(pbBuffer - pbBufferOrg); - } - m_llPosition += pbBuffer - pbBufferOrg; - - if (dwBytesToRead != 0) { - return S_FALSE; - } - - return S_OK; -} - -LONGLONG CCDXAStream::Size(LONGLONG* pSizeAvailable) -{ - if (pSizeAvailable) { - *pSizeAvailable = m_llLength; - } - return m_llLength; -} - -DWORD CCDXAStream::Alignment() -{ - return 1; -} - -void CCDXAStream::Lock() -{ - m_csLock.Lock(); -} - -void CCDXAStream::Unlock() -{ - m_csLock.Unlock(); -} - -// - -bool CCDXAStream::LookForMediaSubType() -{ - BYTE buff[RAW_DATA_SIZE]; - - m_subtype = MEDIASUBTYPE_NULL; - - m_llPosition = 0; - - for (int iSectorsRead = 0; - Read(buff, RAW_DATA_SIZE, 1, nullptr) == S_OK && iSectorsRead < 1000; - iSectorsRead++) { - if (*((DWORD*)&buff[0]) == 0xba010000) { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - if ((buff[4] & 0xc4) == 0x44) { - m_subtype = MEDIASUBTYPE_MPEG2_PROGRAM; - } else if ((buff[4] & 0xf1) == 0x21) { - m_subtype = MEDIASUBTYPE_MPEG1System; - } - - return !!(m_subtype != MEDIASUBTYPE_NULL); - } else if (*((DWORD*)&buff[0]) == 'SggO') { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_Ogg; - - return true; - } else if (*((DWORD*)&buff[0]) == 0xA3DF451A) { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_Matroska; - - return true; - } else if (*((DWORD*)&buff[0]) == 'FMR.') { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_RealMedia; - - return true; - } else if (*((DWORD*)&buff[0]) == 'FFIR' && *((DWORD*)&buff[8]) == ' IVA') { - m_llPosition = 0; - m_llLength = std::min(m_llLength, LONGLONG(*((DWORD*)&buff[4])) + 8); - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_Avi; - - return true; - } else if (*((DWORD*)&buff[4]) == 'voom' || *((DWORD*)&buff[4]) == 'tadm' - || *((DWORD*)&buff[4]) == 'pytf' && *((DWORD*)&buff[8]) == 'mosi' && *((DWORD*)&buff[16]) == '14pm') { - m_llPosition = 0; - m_llLength -= iSectorsRead * RAW_DATA_SIZE; - m_nFirstSector = iSectorsRead; - - m_subtype = MEDIASUBTYPE_QTMovie; - - return true; - } - } - - m_llPosition = 0; - - CRegKey majorkey; - CString majortype = _T("\\Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"); - if (ERROR_SUCCESS == majorkey.Open(HKEY_CLASSES_ROOT, majortype, KEY_READ)) { - TCHAR subtype[256 + 1]; - DWORD len = 256; - for (int i = 0; ERROR_SUCCESS == majorkey.EnumKey(i, subtype, &len); i++, len = 256) { - CRegKey subkey; - if (ERROR_SUCCESS != subkey.Open(HKEY_CLASSES_ROOT, majortype + _T("\\") + subtype, KEY_READ)) { - continue; - } - - for (int j = 0; true; j++) { - TCHAR number[10]; - _stprintf_s(number, _countof(number), _T("%d"), j); - - TCHAR pattern[256 + 1]; - ULONG lenValue = 256; - if (ERROR_SUCCESS != subkey.QueryStringValue(number, pattern, &lenValue)) { - break; - } - - CString p = pattern; - p += _T(','); - - __int64 offset = 0; - DWORD cb = 0; - CAtlArray mask, val; - - int nMatches = 0, nTries = 0; - - for (int k = 0, l; nTries >= 0 && (l = p.Find(',', k)) >= 0; k = l + 1, nTries++) { - CString s = p.Mid(k, l - k); - TRACE(s + '\n'); - - TCHAR* end = nullptr; - - switch (nTries & 3) { - case 0: - offset = _tcstol(s, &end, 10); - break; - case 1: - cb = _tcstol(s, &end, 10); - break; - case 2: - CStringToBin(s, mask); - break; - case 3: - CStringToBin(s, val); - break; - default: - ASSERT(FALSE); // Shouldn't happen - nTries = -1; - break; - } - - if (nTries >= 0 && (nTries & 3) == 3) { - if (cb > 0 && !val.IsEmpty() && cb == val.GetCount()) { - if (offset >= 0 && S_OK == SetPointer(offset) - || S_OK == SetPointer(m_llLength + offset)) { - CAutoVectorPtr pData; - if (pData.Allocate(cb)) { - DWORD BytesRead = 0; - if (S_OK == Read(pData, cb, 1, &BytesRead) && cb == BytesRead) { - if (mask.GetCount() < cb) { - size_t x = mask.GetCount(); - mask.SetCount(cb); - for (; x < cb; x++) { - mask[x] = 0xff; - } - } - - for (unsigned int x = 0; x < cb; x++) { - pData[x] &= (BYTE)mask[x]; - } - - if (memcmp(pData, val.GetData(), cb) == 0) { - nMatches++; - } - } - } - } - - offset = 0; - cb = 0; - mask.RemoveAll(); - val.RemoveAll(); - } - } - } - - if (nMatches > 0 && nMatches * 4 == nTries) { - m_subtype = GUIDFromCString(subtype); - return S_OK; - } - } - } - } - - return false; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "CDXAReader.h" +#include "../../../DSUtil/DSUtil.h" +#ifdef STANDALONE_FILTER +#include +#endif +#include +#include "moreuuids.h" + +///////// + +static constexpr DWORD EDC_crctable[256] = { + 0x00000000l, 0x90910101l, 0x91210201l, 0x01b00300l, + 0x92410401l, 0x02d00500l, 0x03600600l, 0x93f10701l, + 0x94810801l, 0x04100900l, 0x05a00a00l, 0x95310b01l, + 0x06c00c00l, 0x96510d01l, 0x97e10e01l, 0x07700f00l, + 0x99011001l, 0x09901100l, 0x08201200l, 0x98b11301l, + 0x0b401400l, 0x9bd11501l, 0x9a611601l, 0x0af01700l, + 0x0d801800l, 0x9d111901l, 0x9ca11a01l, 0x0c301b00l, + 0x9fc11c01l, 0x0f501d00l, 0x0ee01e00l, 0x9e711f01l, + 0x82012001l, 0x12902100l, 0x13202200l, 0x83b12301l, + 0x10402400l, 0x80d12501l, 0x81612601l, 0x11f02700l, + 0x16802800l, 0x86112901l, 0x87a12a01l, 0x17302b00l, + 0x84c12c01l, 0x14502d00l, 0x15e02e00l, 0x85712f01l, + 0x1b003000l, 0x8b913101l, 0x8a213201l, 0x1ab03300l, + 0x89413401l, 0x19d03500l, 0x18603600l, 0x88f13701l, + 0x8f813801l, 0x1f103900l, 0x1ea03a00l, 0x8e313b01l, + 0x1dc03c00l, 0x8d513d01l, 0x8ce13e01l, 0x1c703f00l, + 0xb4014001l, 0x24904100l, 0x25204200l, 0xb5b14301l, + 0x26404400l, 0xb6d14501l, 0xb7614601l, 0x27f04700l, + 0x20804800l, 0xb0114901l, 0xb1a14a01l, 0x21304b00l, + 0xb2c14c01l, 0x22504d00l, 0x23e04e00l, 0xb3714f01l, + 0x2d005000l, 0xbd915101l, 0xbc215201l, 0x2cb05300l, + 0xbf415401l, 0x2fd05500l, 0x2e605600l, 0xbef15701l, + 0xb9815801l, 0x29105900l, 0x28a05a00l, 0xb8315b01l, + 0x2bc05c00l, 0xbb515d01l, 0xbae15e01l, 0x2a705f00l, + 0x36006000l, 0xa6916101l, 0xa7216201l, 0x37b06300l, + 0xa4416401l, 0x34d06500l, 0x35606600l, 0xa5f16701l, + 0xa2816801l, 0x32106900l, 0x33a06a00l, 0xa3316b01l, + 0x30c06c00l, 0xa0516d01l, 0xa1e16e01l, 0x31706f00l, + 0xaf017001l, 0x3f907100l, 0x3e207200l, 0xaeb17301l, + 0x3d407400l, 0xadd17501l, 0xac617601l, 0x3cf07700l, + 0x3b807800l, 0xab117901l, 0xaaa17a01l, 0x3a307b00l, + 0xa9c17c01l, 0x39507d00l, 0x38e07e00l, 0xa8717f01l, + 0xd8018001l, 0x48908100l, 0x49208200l, 0xd9b18301l, + 0x4a408400l, 0xdad18501l, 0xdb618601l, 0x4bf08700l, + 0x4c808800l, 0xdc118901l, 0xdda18a01l, 0x4d308b00l, + 0xdec18c01l, 0x4e508d00l, 0x4fe08e00l, 0xdf718f01l, + 0x41009000l, 0xd1919101l, 0xd0219201l, 0x40b09300l, + 0xd3419401l, 0x43d09500l, 0x42609600l, 0xd2f19701l, + 0xd5819801l, 0x45109900l, 0x44a09a00l, 0xd4319b01l, + 0x47c09c00l, 0xd7519d01l, 0xd6e19e01l, 0x46709f00l, + 0x5a00a000l, 0xca91a101l, 0xcb21a201l, 0x5bb0a300l, + 0xc841a401l, 0x58d0a500l, 0x5960a600l, 0xc9f1a701l, + 0xce81a801l, 0x5e10a900l, 0x5fa0aa00l, 0xcf31ab01l, + 0x5cc0ac00l, 0xcc51ad01l, 0xcde1ae01l, 0x5d70af00l, + 0xc301b001l, 0x5390b100l, 0x5220b200l, 0xc2b1b301l, + 0x5140b400l, 0xc1d1b501l, 0xc061b601l, 0x50f0b700l, + 0x5780b800l, 0xc711b901l, 0xc6a1ba01l, 0x5630bb00l, + 0xc5c1bc01l, 0x5550bd00l, 0x54e0be00l, 0xc471bf01l, + 0x6c00c000l, 0xfc91c101l, 0xfd21c201l, 0x6db0c300l, + 0xfe41c401l, 0x6ed0c500l, 0x6f60c600l, 0xfff1c701l, + 0xf881c801l, 0x6810c900l, 0x69a0ca00l, 0xf931cb01l, + 0x6ac0cc00l, 0xfa51cd01l, 0xfbe1ce01l, 0x6b70cf00l, + 0xf501d001l, 0x6590d100l, 0x6420d200l, 0xf4b1d301l, + 0x6740d400l, 0xf7d1d501l, 0xf661d601l, 0x66f0d700l, + 0x6180d800l, 0xf111d901l, 0xf0a1da01l, 0x6030db00l, + 0xf3c1dc01l, 0x6350dd00l, 0x62e0de00l, 0xf271df01l, + 0xee01e001l, 0x7e90e100l, 0x7f20e200l, 0xefb1e301l, + 0x7c40e400l, 0xecd1e501l, 0xed61e601l, 0x7df0e700l, + 0x7a80e800l, 0xea11e901l, 0xeba1ea01l, 0x7b30eb00l, + 0xe8c1ec01l, 0x7850ed00l, 0x79e0ee00l, 0xe971ef01l, + 0x7700f000l, 0xe791f101l, 0xe621f201l, 0x76b0f300l, + 0xe541f401l, 0x75d0f500l, 0x7460f600l, 0xe4f1f701l, + 0xe381f801l, 0x7310f900l, 0x72a0fa00l, 0xe231fb01l, + 0x71c0fc00l, 0xe151fd01l, 0xe0e1fe01l, 0x7070ff00l +}; + +static DWORD build_edc(const void* in, unsigned from, unsigned upto) +{ + const BYTE* p = (BYTE*)in + from; + DWORD result = 0; + + for (; from < upto; from++) { + result = EDC_crctable[(result ^ *p++) & 0xffL] ^ (result >> 8); + } + + return result; +} + +///////// + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL} +}; + +const AMOVIESETUP_PIN sudOpPin[] = { + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CCDXAReader), CCDXAReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}"), + _T("0"), _T("0,4,,52494646,8,4,,43445841")); // "RIFFxxxxCDXA" + + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}"), + _T("Source Filter"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}")); + + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{D367878E-F3B8-4235-A968-F378EF1B9A44}")); + + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CCDXAReader +// + +CCDXAReader::CCDXAReader(IUnknown* pUnk, HRESULT* phr) + : CAsyncReader(NAME("CCDXAReader"), pUnk, &m_stream, phr, __uuidof(this)) +{ + if (phr) { + *phr = S_OK; + } +} + +CCDXAReader::~CCDXAReader() +{ +} + +STDMETHODIMP CCDXAReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IFileSourceFilter) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CCDXAReader::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + + wcscpy_s(pInfo->achName, CCDXAReaderName); + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP CCDXAReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + CMediaType mt; + m_mt = mt; + + if (!m_stream.Load(pszFileName)) { + return E_FAIL; + } + + m_fn = pszFileName; + + mt.majortype = MEDIATYPE_Stream; + mt.subtype = m_stream.m_subtype; + m_mt = mt; + + return S_OK; +} + +STDMETHODIMP CCDXAReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + + return S_OK; +} + +// CCDXAStream + +CCDXAStream::CCDXAStream() +{ + m_subtype = MEDIASUBTYPE_NULL; + + m_hFile = INVALID_HANDLE_VALUE; + + m_llPosition = m_llLength = 0; + m_nFirstSector = 0; + m_nBufferedSector = -1; + ZeroMemory(m_sector, sizeof(m_sector)); +} + +CCDXAStream::~CCDXAStream() +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } +} + +bool CCDXAStream::Load(const WCHAR* fnw) +{ + if (m_hFile != INVALID_HANDLE_VALUE) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + } + + m_hFile = CreateFile(CString(fnw), GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr); + if (m_hFile == INVALID_HANDLE_VALUE) { + return false; + } + + BYTE hdr[RIFFCDXA_HEADER_SIZE]; + DWORD NumberOfBytesRead; + if (!ReadFile(m_hFile, (LPVOID)hdr, RIFFCDXA_HEADER_SIZE, &NumberOfBytesRead, nullptr) + || *((DWORD*)&hdr[0]) != 'FFIR' || *((DWORD*)&hdr[8]) != 'AXDC' + || *((DWORD*)&hdr[4]) != (*((DWORD*)&hdr[0x28]) + 0x24)) { + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + return false; + } + + LARGE_INTEGER size = {0, 0}; + GetFileSizeEx(m_hFile, &size); + + m_llLength = ((size.QuadPart - RIFFCDXA_HEADER_SIZE) / RAW_SECTOR_SIZE) * RAW_DATA_SIZE; + + if (!LookForMediaSubType()) { + m_llPosition = m_llLength = 0; + CloseHandle(m_hFile); + m_hFile = INVALID_HANDLE_VALUE; + return false; + } + + m_llPosition = 0; + + m_nBufferedSector = -1; + + return true; +} + +HRESULT CCDXAStream::SetPointer(LONGLONG llPos) +{ + HRESULT hr = S_FALSE; + + if (llPos >= 0 && llPos < m_llLength) { + m_llPosition = llPos; + hr = S_OK; + } + + return hr; +} + +HRESULT CCDXAStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) +{ + CAutoLock lck(&m_csLock); + + PBYTE pbBufferOrg = pbBuffer; + LONGLONG pos = m_llPosition; + + while (pos >= 0 && pos < m_llLength && dwBytesToRead > 0) { + UINT sector = m_nFirstSector + int(pos / RAW_DATA_SIZE); + __int64 offset = pos % RAW_DATA_SIZE; + + if (m_nBufferedSector != (int)sector) { + LARGE_INTEGER FilePointer; + FilePointer.QuadPart = RIFFCDXA_HEADER_SIZE + sector * RAW_SECTOR_SIZE; + SetFilePointerEx(m_hFile, FilePointer, &FilePointer, FILE_BEGIN); + + ZeroMemory(m_sector, sizeof(m_sector)); + + DWORD NumberOfBytesRead = 0; + + int nRetries = 3; + while (nRetries--) { + NumberOfBytesRead = 0; + if (!ReadFile(m_hFile, m_sector, RAW_SECTOR_SIZE, &NumberOfBytesRead, nullptr) + || NumberOfBytesRead != RAW_SECTOR_SIZE) { + break; + } + + if (*(DWORD*)&m_sector[RAW_SECTOR_SIZE - 4] == 0) { // no CRC? it happens... + break; + } + + if (build_edc(m_sector, RAW_SYNC_SIZE + RAW_HEADER_SIZE, RAW_SECTOR_SIZE) == 0) { + break; + } + + TRACE(_T("CCDXAStream: CRC error at sector %u (fp=0x%I64x, retriesleft=%d)\n"), sector, FilePointer.QuadPart, nRetries); + } + + m_nBufferedSector = sector; + } + + DWORD l = std::min(dwBytesToRead, (DWORD)std::min(RAW_DATA_SIZE - offset, m_llLength - pos)); + memcpy(pbBuffer, &m_sector[RAW_SYNC_SIZE + RAW_HEADER_SIZE + RAW_SUBHEADER_SIZE + offset], l); + + pbBuffer += l; + pos += l; + dwBytesToRead -= l; + } + + if (pdwBytesRead) { + *pdwBytesRead = DWORD(pbBuffer - pbBufferOrg); + } + m_llPosition += pbBuffer - pbBufferOrg; + + if (dwBytesToRead != 0) { + return S_FALSE; + } + + return S_OK; +} + +LONGLONG CCDXAStream::Size(LONGLONG* pSizeAvailable) +{ + if (pSizeAvailable) { + *pSizeAvailable = m_llLength; + } + return m_llLength; +} + +DWORD CCDXAStream::Alignment() +{ + return 1; +} + +void CCDXAStream::Lock() +{ + m_csLock.Lock(); +} + +void CCDXAStream::Unlock() +{ + m_csLock.Unlock(); +} + +// + +bool CCDXAStream::LookForMediaSubType() +{ + BYTE buff[RAW_DATA_SIZE]; + + m_subtype = MEDIASUBTYPE_NULL; + + m_llPosition = 0; + + for (int iSectorsRead = 0; + Read(buff, RAW_DATA_SIZE, 1, nullptr) == S_OK && iSectorsRead < 1000; + iSectorsRead++) { + if (*((DWORD*)&buff[0]) == 0xba010000) { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + if ((buff[4] & 0xc4) == 0x44) { + m_subtype = MEDIASUBTYPE_MPEG2_PROGRAM; + } else if ((buff[4] & 0xf1) == 0x21) { + m_subtype = MEDIASUBTYPE_MPEG1System; + } + + return !!(m_subtype != MEDIASUBTYPE_NULL); + } else if (*((DWORD*)&buff[0]) == 'SggO') { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_Ogg; + + return true; + } else if (*((DWORD*)&buff[0]) == 0xA3DF451A) { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_Matroska; + + return true; + } else if (*((DWORD*)&buff[0]) == 'FMR.') { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_RealMedia; + + return true; + } else if (*((DWORD*)&buff[0]) == 'FFIR' && *((DWORD*)&buff[8]) == ' IVA') { + m_llPosition = 0; + m_llLength = std::min(m_llLength, LONGLONG(*((DWORD*)&buff[4])) + 8); + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_Avi; + + return true; + } else if (*((DWORD*)&buff[4]) == 'voom' || *((DWORD*)&buff[4]) == 'tadm' + || *((DWORD*)&buff[4]) == 'pytf' && *((DWORD*)&buff[8]) == 'mosi' && *((DWORD*)&buff[16]) == '14pm') { + m_llPosition = 0; + m_llLength -= iSectorsRead * RAW_DATA_SIZE; + m_nFirstSector = iSectorsRead; + + m_subtype = MEDIASUBTYPE_QTMovie; + + return true; + } + } + + m_llPosition = 0; + + CRegKey majorkey; + CString majortype = _T("\\Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"); + if (ERROR_SUCCESS == majorkey.Open(HKEY_CLASSES_ROOT, majortype, KEY_READ)) { + TCHAR subtype[256 + 1]; + DWORD len = 256; + for (int i = 0; ERROR_SUCCESS == majorkey.EnumKey(i, subtype, &len); i++, len = 256) { + CRegKey subkey; + if (ERROR_SUCCESS != subkey.Open(HKEY_CLASSES_ROOT, majortype + _T("\\") + subtype, KEY_READ)) { + continue; + } + + for (int j = 0; true; j++) { + TCHAR number[10]; + _stprintf_s(number, _countof(number), _T("%d"), j); + + TCHAR pattern[256 + 1]; + ULONG lenValue = 256; + if (ERROR_SUCCESS != subkey.QueryStringValue(number, pattern, &lenValue)) { + break; + } + + CString p = pattern; + p += _T(','); + + __int64 offset = 0; + DWORD cb = 0; + CAtlArray mask, val; + + int nMatches = 0, nTries = 0; + + for (int k = 0, l; nTries >= 0 && (l = p.Find(',', k)) >= 0; k = l + 1, nTries++) { + CString s = p.Mid(k, l - k); + TRACE(s + '\n'); + + TCHAR* end = nullptr; + + switch (nTries & 3) { + case 0: + offset = _tcstol(s, &end, 10); + break; + case 1: + cb = _tcstol(s, &end, 10); + break; + case 2: + CStringToBin(s, mask); + break; + case 3: + CStringToBin(s, val); + break; + default: + ASSERT(FALSE); // Shouldn't happen + nTries = -1; + break; + } + + if (nTries >= 0 && (nTries & 3) == 3) { + if (cb > 0 && !val.IsEmpty() && cb == val.GetCount()) { + if (offset >= 0 && S_OK == SetPointer(offset) + || S_OK == SetPointer(m_llLength + offset)) { + CAutoVectorPtr pData; + if (pData.Allocate(cb)) { + DWORD BytesRead = 0; + if (S_OK == Read(pData, cb, 1, &BytesRead) && cb == BytesRead) { + if (mask.GetCount() < cb) { + size_t x = mask.GetCount(); + mask.SetCount(cb); + for (; x < cb; x++) { + mask[x] = 0xff; + } + } + + for (unsigned int x = 0; x < cb; x++) { + pData[x] &= (BYTE)mask[x]; + } + + if (memcmp(pData, val.GetData(), cb) == 0) { + nMatches++; + } + } + } + } + + offset = 0; + cb = 0; + mask.RemoveAll(); + val.RemoveAll(); + } + } + } + + if (nMatches > 0 && nMatches * 4 == nTries) { + m_subtype = GUIDFromCString(subtype); + return S_OK; + } + } + } + } + + return false; +} diff --git a/src/filters/reader/CDXAReader/CDXAReader.def b/src/filters/reader/CDXAReader/CDXAReader.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.def +++ b/src/filters/reader/CDXAReader/CDXAReader.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/reader/CDXAReader/CDXAReader.h b/src/filters/reader/CDXAReader/CDXAReader.h index bd9bae446db..145975abfae 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.h +++ b/src/filters/reader/CDXAReader/CDXAReader.h @@ -1,93 +1,93 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "AsyncReader/asyncio.h" -#include "AsyncReader/asyncrdr.h" - -#define CCDXAReaderName L"MPC-HC CDXA Reader" - -class CCDXAStream : public CAsyncStream -{ -private: - enum { - RIFFCDXA_HEADER_SIZE = 44, // usually... - RAW_SYNC_SIZE = 12, // 00 FF .. FF 00 - RAW_HEADER_SIZE = 4, - RAW_SUBHEADER_SIZE = 8, - RAW_DATA_SIZE = 2324, - RAW_EDC_SIZE = 4, - RAW_SECTOR_SIZE = 2352 - }; - - CCritSec m_csLock; - - HANDLE m_hFile; - LONGLONG m_llPosition, m_llLength; - int m_nFirstSector; - - int m_nBufferedSector; - BYTE m_sector[RAW_SECTOR_SIZE]; - - bool LookForMediaSubType(); - -public: - CCDXAStream(); - virtual ~CCDXAStream(); - - bool Load(const WCHAR* fnw); - - HRESULT SetPointer(LONGLONG llPos); - HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); - LONGLONG Size(LONGLONG* pSizeAvailable); - DWORD Alignment(); - void Lock(); - void Unlock(); - - GUID m_subtype; -}; - -class __declspec(uuid("D367878E-F3B8-4235-A968-F378EF1B9A44")) - CCDXAReader - : public CAsyncReader - , public IFileSourceFilter -{ - CCDXAStream m_stream; - CStringW m_fn; - -public: - CCDXAReader(IUnknown* pUnk, HRESULT* phr); - ~CCDXAReader(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // CBaseFilter - - STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); - - // IFileSourceFilter - - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "AsyncReader/asyncio.h" +#include "AsyncReader/asyncrdr.h" + +#define CCDXAReaderName L"MPC-HC CDXA Reader" + +class CCDXAStream : public CAsyncStream +{ +private: + enum { + RIFFCDXA_HEADER_SIZE = 44, // usually... + RAW_SYNC_SIZE = 12, // 00 FF .. FF 00 + RAW_HEADER_SIZE = 4, + RAW_SUBHEADER_SIZE = 8, + RAW_DATA_SIZE = 2324, + RAW_EDC_SIZE = 4, + RAW_SECTOR_SIZE = 2352 + }; + + CCritSec m_csLock; + + HANDLE m_hFile; + LONGLONG m_llPosition, m_llLength; + int m_nFirstSector; + + int m_nBufferedSector; + BYTE m_sector[RAW_SECTOR_SIZE]; + + bool LookForMediaSubType(); + +public: + CCDXAStream(); + virtual ~CCDXAStream(); + + bool Load(const WCHAR* fnw); + + HRESULT SetPointer(LONGLONG llPos); + HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); + LONGLONG Size(LONGLONG* pSizeAvailable); + DWORD Alignment(); + void Lock(); + void Unlock(); + + GUID m_subtype; +}; + +class __declspec(uuid("D367878E-F3B8-4235-A968-F378EF1B9A44")) + CCDXAReader + : public CAsyncReader + , public IFileSourceFilter +{ + CCDXAStream m_stream; + CStringW m_fn; + +public: + CCDXAReader(IUnknown* pUnk, HRESULT* phr); + ~CCDXAReader(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // CBaseFilter + + STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); + + // IFileSourceFilter + + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); +}; diff --git a/src/filters/reader/CDXAReader/CDXAReader.rc b/src/filters/reader/CDXAReader/CDXAReader.rc index e695cc122f5..7946b3f5e55 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.rc +++ b/src/filters/reader/CDXAReader/CDXAReader.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "CDXA Reader Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "CDXA Reader Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "CDXAReader.ax" - VALUE "ProductName", "CDXA Reader Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "CDXA Reader Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "CDXA Reader Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "CDXAReader.ax" + VALUE "ProductName", "CDXA Reader Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/reader/CDXAReader/CDXAReader.vcxproj b/src/filters/reader/CDXAReader/CDXAReader.vcxproj index cc00795704a..c593478c486 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.vcxproj +++ b/src/filters/reader/CDXAReader/CDXAReader.vcxproj @@ -1,127 +1,127 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {4D3B4FF4-535A-4201-AB7D-9AEC1E737A95} - CDXAReader - MFCProj - CDXAReader - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - CDXAReader.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {9f31d122-e84d-485a-a58d-09dad01a56ce} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {4D3B4FF4-535A-4201-AB7D-9AEC1E737A95} + CDXAReader + MFCProj + CDXAReader + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + CDXAReader.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {9f31d122-e84d-485a-a58d-09dad01a56ce} + + + + + \ No newline at end of file diff --git a/src/filters/reader/CDXAReader/CDXAReader.vcxproj.filters b/src/filters/reader/CDXAReader/CDXAReader.vcxproj.filters index 6b899deab44..47d4a3b5068 100644 --- a/src/filters/reader/CDXAReader/CDXAReader.vcxproj.filters +++ b/src/filters/reader/CDXAReader/CDXAReader.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {bee90cb9-7ace-4e7d-b77a-1b4d710b5a25} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {a9a7c9a3-58c8-46f9-92fb-16b5ffdbdef2} - h;hpp;hxx;hm;inl;inc - - - {5dd4b870-4b51-419e-82bb-72ca9bd24680} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {bee90cb9-7ace-4e7d-b77a-1b4d710b5a25} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {a9a7c9a3-58c8-46f9-92fb-16b5ffdbdef2} + h;hpp;hxx;hm;inl;inc + + + {5dd4b870-4b51-419e-82bb-72ca9bd24680} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/reader/CDXAReader/resource.h b/src/filters/reader/CDXAReader/resource.h index 142004466c2..fbfb65fad76 100644 --- a/src/filters/reader/CDXAReader/resource.h +++ b/src/filters/reader/CDXAReader/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by CDXAReader.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by CDXAReader.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/reader/CDXAReader/stdafx.cpp b/src/filters/reader/CDXAReader/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/reader/CDXAReader/stdafx.cpp +++ b/src/filters/reader/CDXAReader/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/reader/CDXAReader/stdafx.h b/src/filters/reader/CDXAReader/stdafx.h index 12bbe2db0a7..d8320f2c878 100644 --- a/src/filters/reader/CDXAReader/stdafx.h +++ b/src/filters/reader/CDXAReader/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/reader/VTSReader/VTSReader.cpp b/src/filters/reader/VTSReader/VTSReader.cpp index e5aa7a295f1..c1296539368 100644 --- a/src/filters/reader/VTSReader/VTSReader.cpp +++ b/src/filters/reader/VTSReader/VTSReader.cpp @@ -1,297 +1,297 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "../../../DeCSS/VobFile.h" -#include "VTSReader.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG2_PROGRAM}, -}; - -const AMOVIESETUP_PIN sudOpPin[] = { - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CVTSReader), VTSReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}"), - _T("0"), _T("0,12,,445644564944454F2D565453")); // "DVDVIDEO-VTS" - - SetRegKeyValue( - _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}"), - _T("Source Filter"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")); - - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")); - - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CVTSReader -// - -CVTSReader::CVTSReader(IUnknown* pUnk, HRESULT* phr) - : CAsyncReader(NAME("CVTSReader"), pUnk, &m_stream, phr, __uuidof(this)) -{ - if (phr) { - *phr = S_OK; - } -} - -CVTSReader::~CVTSReader() -{ -} - -STDMETHODIMP CVTSReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFileSourceFilter) - QI(ITrackInfo) - QI(IDSMChapterBag) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CVTSReader::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - - wcscpy_s(pInfo->achName, VTSReaderName); - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -// IFileSourceFilter - -STDMETHODIMP CVTSReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - if (!m_stream.Load(pszFileName)) { - return E_FAIL; - } - - ChapRemoveAll(); - for (int i = 0; i < m_stream.GetChaptersCount(); i++) { - CString chap; - chap.Format(_T("Chapter %d"), i + 1); - ChapAppend(m_stream.GetChapterOffset(i), chap); - } - - - m_fn = pszFileName; - - CMediaType mt; - mt.majortype = MEDIATYPE_Stream; - mt.subtype = MEDIASUBTYPE_MPEG2_PROGRAM; - m_mt = mt; - - return S_OK; -} - -STDMETHODIMP CVTSReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - - return S_OK; -} - -// ITrackInfo - -STDMETHODIMP_(UINT) CVTSReader::GetTrackCount() -{ - return 0; // Not implemented yet -} - -STDMETHODIMP_(BOOL) CVTSReader::GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill) -{ - return FALSE; // Not implemented yet -} - -STDMETHODIMP_(BOOL) CVTSReader::GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill) -{ - return FALSE; // Not implemented yet -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackName(UINT aTrackIdx) -{ - return m_stream.GetTrackName(aTrackIdx); // return stream's language -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecID(UINT aTrackIdx) -{ - return nullptr; // Not implemented yet -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecName(UINT aTrackIdx) -{ - return nullptr; // Not implemented yet -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecInfoURL(UINT aTrackIdx) -{ - return nullptr; // Not implemented yet -} - -STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecDownloadURL(UINT aTrackIdx) -{ - return nullptr; // Not implemented yet -} - -// CVTSStream - -CVTSStream::CVTSStream() : m_off(0) -{ - m_vob.Attach(DEBUG_NEW CVobFile()); -} - -CVTSStream::~CVTSStream() -{ -} - -bool CVTSStream::Load(const WCHAR* fnw) -{ - CAtlList sl; - return (m_vob && m_vob->Open(CString(fnw), sl) /*&& m_vob->IsDVD()*/); -} - -HRESULT CVTSStream::SetPointer(LONGLONG llPos) -{ - m_off = (int)(llPos & 2047); - int lba = (int)(llPos / 2048); - - return lba == m_vob->Seek(lba) ? S_OK : S_FALSE; -} - -HRESULT CVTSStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) -{ - CAutoLock lck(&m_csLock); - - DWORD len = dwBytesToRead; - BYTE* ptr = pbBuffer; - - TRY - while (len > 0) { - BYTE buff[2048]; - if (!m_vob->Read(buff)) { - break; - } - - int size = std::min(2048 - m_off, (int)std::min(len, 2048ul)); - - memcpy(ptr, &buff[m_off], size); - - m_off = (m_off + size) & 2047; - - if (m_off > 0) { - m_vob->Seek(m_vob->GetPosition() - 1); - } - - ptr += size; - len -= size; - } - - if (pdwBytesRead) { - *pdwBytesRead = DWORD(ptr - pbBuffer); - } - CATCH(CFileException, e) - return S_FALSE; - END_CATCH - - return S_OK; -} - -LONGLONG CVTSStream::Size(LONGLONG* pSizeAvailable) -{ - LONGLONG len = 2048i64 * m_vob->GetLength(); - if (pSizeAvailable) { - *pSizeAvailable = len; - } - return len; -} - -DWORD CVTSStream::Alignment() -{ - return 1; -} - -void CVTSStream::Lock() -{ - m_csLock.Lock(); -} - -void CVTSStream::Unlock() -{ - m_csLock.Unlock(); -} - -BSTR CVTSStream::GetTrackName(UINT aTrackIdx) -{ - return m_vob->GetTrackName(aTrackIdx); -} - -int CVTSStream::GetChaptersCount() -{ - return m_vob->GetChaptersCount(); -} - -REFERENCE_TIME CVTSStream::GetChapterOffset(UINT ChapterNumber) -{ - return m_vob->GetChapterOffset(ChapterNumber); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "../../../DeCSS/VobFile.h" +#include "VTSReader.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG2_PROGRAM}, +}; + +const AMOVIESETUP_PIN sudOpPin[] = { + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CVTSReader), VTSReaderName, MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}"), + _T("0"), _T("0,12,,445644564944454F2D565453")); // "DVDVIDEO-VTS" + + SetRegKeyValue( + _T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}"), + _T("Source Filter"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")); + + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + DeleteRegKey(_T("Media Type\\{e436eb83-524f-11ce-9f53-0020af0ba770}"), _T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")); + + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CVTSReader +// + +CVTSReader::CVTSReader(IUnknown* pUnk, HRESULT* phr) + : CAsyncReader(NAME("CVTSReader"), pUnk, &m_stream, phr, __uuidof(this)) +{ + if (phr) { + *phr = S_OK; + } +} + +CVTSReader::~CVTSReader() +{ +} + +STDMETHODIMP CVTSReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFileSourceFilter) + QI(ITrackInfo) + QI(IDSMChapterBag) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CVTSReader::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + + wcscpy_s(pInfo->achName, VTSReaderName); + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +// IFileSourceFilter + +STDMETHODIMP CVTSReader::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + if (!m_stream.Load(pszFileName)) { + return E_FAIL; + } + + ChapRemoveAll(); + for (int i = 0; i < m_stream.GetChaptersCount(); i++) { + CString chap; + chap.Format(_T("Chapter %d"), i + 1); + ChapAppend(m_stream.GetChapterOffset(i), chap); + } + + + m_fn = pszFileName; + + CMediaType mt; + mt.majortype = MEDIATYPE_Stream; + mt.subtype = MEDIASUBTYPE_MPEG2_PROGRAM; + m_mt = mt; + + return S_OK; +} + +STDMETHODIMP CVTSReader::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + + return S_OK; +} + +// ITrackInfo + +STDMETHODIMP_(UINT) CVTSReader::GetTrackCount() +{ + return 0; // Not implemented yet +} + +STDMETHODIMP_(BOOL) CVTSReader::GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill) +{ + return FALSE; // Not implemented yet +} + +STDMETHODIMP_(BOOL) CVTSReader::GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill) +{ + return FALSE; // Not implemented yet +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackName(UINT aTrackIdx) +{ + return m_stream.GetTrackName(aTrackIdx); // return stream's language +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecID(UINT aTrackIdx) +{ + return nullptr; // Not implemented yet +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecName(UINT aTrackIdx) +{ + return nullptr; // Not implemented yet +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecInfoURL(UINT aTrackIdx) +{ + return nullptr; // Not implemented yet +} + +STDMETHODIMP_(BSTR) CVTSReader::GetTrackCodecDownloadURL(UINT aTrackIdx) +{ + return nullptr; // Not implemented yet +} + +// CVTSStream + +CVTSStream::CVTSStream() : m_off(0) +{ + m_vob.Attach(DEBUG_NEW CVobFile()); +} + +CVTSStream::~CVTSStream() +{ +} + +bool CVTSStream::Load(const WCHAR* fnw) +{ + CAtlList sl; + return (m_vob && m_vob->Open(CString(fnw), sl) /*&& m_vob->IsDVD()*/); +} + +HRESULT CVTSStream::SetPointer(LONGLONG llPos) +{ + m_off = (int)(llPos & 2047); + int lba = (int)(llPos / 2048); + + return lba == m_vob->Seek(lba) ? S_OK : S_FALSE; +} + +HRESULT CVTSStream::Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead) +{ + CAutoLock lck(&m_csLock); + + DWORD len = dwBytesToRead; + BYTE* ptr = pbBuffer; + + TRY + while (len > 0) { + BYTE buff[2048]; + if (!m_vob->Read(buff)) { + break; + } + + int size = std::min(2048 - m_off, (int)std::min(len, 2048ul)); + + memcpy(ptr, &buff[m_off], size); + + m_off = (m_off + size) & 2047; + + if (m_off > 0) { + m_vob->Seek(m_vob->GetPosition() - 1); + } + + ptr += size; + len -= size; + } + + if (pdwBytesRead) { + *pdwBytesRead = DWORD(ptr - pbBuffer); + } + CATCH(CFileException, e) + return S_FALSE; + END_CATCH + + return S_OK; +} + +LONGLONG CVTSStream::Size(LONGLONG* pSizeAvailable) +{ + LONGLONG len = 2048i64 * m_vob->GetLength(); + if (pSizeAvailable) { + *pSizeAvailable = len; + } + return len; +} + +DWORD CVTSStream::Alignment() +{ + return 1; +} + +void CVTSStream::Lock() +{ + m_csLock.Lock(); +} + +void CVTSStream::Unlock() +{ + m_csLock.Unlock(); +} + +BSTR CVTSStream::GetTrackName(UINT aTrackIdx) +{ + return m_vob->GetTrackName(aTrackIdx); +} + +int CVTSStream::GetChaptersCount() +{ + return m_vob->GetChaptersCount(); +} + +REFERENCE_TIME CVTSStream::GetChapterOffset(UINT ChapterNumber) +{ + return m_vob->GetChapterOffset(ChapterNumber); +} diff --git a/src/filters/reader/VTSReader/VTSReader.def b/src/filters/reader/VTSReader/VTSReader.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/reader/VTSReader/VTSReader.def +++ b/src/filters/reader/VTSReader/VTSReader.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/reader/VTSReader/VTSReader.h b/src/filters/reader/VTSReader/VTSReader.h index c1a95d08d38..763f125f3e3 100644 --- a/src/filters/reader/VTSReader/VTSReader.h +++ b/src/filters/reader/VTSReader/VTSReader.h @@ -1,96 +1,96 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "AsyncReader/asyncio.h" -#include "AsyncReader/asyncrdr.h" - -#include "ITrackInfo.h" -#include "../../../DSUtil/DSMPropertyBag.h" - -#define VTSReaderName L"MPC-HC VTS Reader" - -class CVobFile; - -class CVTSStream : public CAsyncStream -{ -private: - CCritSec m_csLock; - - CAutoPtr m_vob; - int m_off; - -public: - CVTSStream(); - virtual ~CVTSStream(); - - bool Load(const WCHAR* fnw); - - HRESULT SetPointer(LONGLONG llPos); - HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); - LONGLONG Size(LONGLONG* pSizeAvailable); - DWORD Alignment(); - void Lock(); - void Unlock(); - - BSTR GetTrackName(UINT aTrackIdx); - int GetChaptersCount(); - REFERENCE_TIME GetChapterOffset(UINT ChapterNumber); -}; - -class __declspec(uuid("773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73")) - CVTSReader - : public CAsyncReader - , public IFileSourceFilter - , public ITrackInfo - , public IDSMChapterBagImpl -{ - CVTSStream m_stream; - CStringW m_fn; - -public: - CVTSReader(IUnknown* pUnk, HRESULT* phr); - ~CVTSReader(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // CBaseFilter - - STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); - - // IFileSourceFilter - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); - - // ITrackInfo - - STDMETHODIMP_(UINT) GetTrackCount(); - STDMETHODIMP_(BOOL) GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill); - STDMETHODIMP_(BOOL) GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill); - STDMETHODIMP_(BSTR) GetTrackName(UINT aTrackIdx); - STDMETHODIMP_(BSTR) GetTrackCodecID(UINT aTrackIdx); - STDMETHODIMP_(BSTR) GetTrackCodecName(UINT aTrackIdx); - STDMETHODIMP_(BSTR) GetTrackCodecInfoURL(UINT aTrackIdx); - STDMETHODIMP_(BSTR) GetTrackCodecDownloadURL(UINT aTrackIdx); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "AsyncReader/asyncio.h" +#include "AsyncReader/asyncrdr.h" + +#include "ITrackInfo.h" +#include "../../../DSUtil/DSMPropertyBag.h" + +#define VTSReaderName L"MPC-HC VTS Reader" + +class CVobFile; + +class CVTSStream : public CAsyncStream +{ +private: + CCritSec m_csLock; + + CAutoPtr m_vob; + int m_off; + +public: + CVTSStream(); + virtual ~CVTSStream(); + + bool Load(const WCHAR* fnw); + + HRESULT SetPointer(LONGLONG llPos); + HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead, BOOL bAlign, LPDWORD pdwBytesRead); + LONGLONG Size(LONGLONG* pSizeAvailable); + DWORD Alignment(); + void Lock(); + void Unlock(); + + BSTR GetTrackName(UINT aTrackIdx); + int GetChaptersCount(); + REFERENCE_TIME GetChapterOffset(UINT ChapterNumber); +}; + +class __declspec(uuid("773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73")) + CVTSReader + : public CAsyncReader + , public IFileSourceFilter + , public ITrackInfo + , public IDSMChapterBagImpl +{ + CVTSStream m_stream; + CStringW m_fn; + +public: + CVTSReader(IUnknown* pUnk, HRESULT* phr); + ~CVTSReader(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // CBaseFilter + + STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); + + // IFileSourceFilter + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); + + // ITrackInfo + + STDMETHODIMP_(UINT) GetTrackCount(); + STDMETHODIMP_(BOOL) GetTrackInfo(UINT aTrackIdx, struct TrackElement* pStructureToFill); + STDMETHODIMP_(BOOL) GetTrackExtendedInfo(UINT aTrackIdx, void* pStructureToFill); + STDMETHODIMP_(BSTR) GetTrackName(UINT aTrackIdx); + STDMETHODIMP_(BSTR) GetTrackCodecID(UINT aTrackIdx); + STDMETHODIMP_(BSTR) GetTrackCodecName(UINT aTrackIdx); + STDMETHODIMP_(BSTR) GetTrackCodecInfoURL(UINT aTrackIdx); + STDMETHODIMP_(BSTR) GetTrackCodecDownloadURL(UINT aTrackIdx); +}; diff --git a/src/filters/reader/VTSReader/VTSReader.rc b/src/filters/reader/VTSReader/VTSReader.rc index 60283ee822d..e76b362299d 100644 --- a/src/filters/reader/VTSReader/VTSReader.rc +++ b/src/filters/reader/VTSReader/VTSReader.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "VTS Reader Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "VTS Reader Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "VTSReader.ax" - VALUE "ProductName", "VTS Reader Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "VTS Reader Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "VTS Reader Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "VTSReader.ax" + VALUE "ProductName", "VTS Reader Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/reader/VTSReader/VTSReader.vcxproj b/src/filters/reader/VTSReader/VTSReader.vcxproj index 1c1768bf83a..9f960ef2c06 100644 --- a/src/filters/reader/VTSReader/VTSReader.vcxproj +++ b/src/filters/reader/VTSReader/VTSReader.vcxproj @@ -1,130 +1,130 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {664E726B-EEEE-403A-AC15-345D9C9E1375} - VTSReader - MFCProj - VTSReader - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - VTSReader.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - Create - - - - - - - - - true - - - - - - - true - - - - - {1a2dfd1a-3c6c-44d1-909d-294af646b575} - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {9f31d122-e84d-485a-a58d-09dad01a56ce} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {664E726B-EEEE-403A-AC15-345D9C9E1375} + VTSReader + MFCProj + VTSReader + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + VTSReader.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + Create + + + + + + + + + true + + + + + + + true + + + + + {1a2dfd1a-3c6c-44d1-909d-294af646b575} + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {9f31d122-e84d-485a-a58d-09dad01a56ce} + + + + + \ No newline at end of file diff --git a/src/filters/reader/VTSReader/VTSReader.vcxproj.filters b/src/filters/reader/VTSReader/VTSReader.vcxproj.filters index 68903cdd427..1f898d5d80a 100644 --- a/src/filters/reader/VTSReader/VTSReader.vcxproj.filters +++ b/src/filters/reader/VTSReader/VTSReader.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {6f84c2e5-5b7f-4a7e-8f4b-1f45a45a3078} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {92ae839d-6d37-4f6d-97e5-1e143db42aaf} - h;hpp;hxx;hm;inl;inc - - - {8d71235c-8fc1-4df3-a231-dc67993f1081} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {6f84c2e5-5b7f-4a7e-8f4b-1f45a45a3078} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {92ae839d-6d37-4f6d-97e5-1e143db42aaf} + h;hpp;hxx;hm;inl;inc + + + {8d71235c-8fc1-4df3-a231-dc67993f1081} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/reader/VTSReader/resource.h b/src/filters/reader/VTSReader/resource.h index 39ae18f4a39..c9290f108cf 100644 --- a/src/filters/reader/VTSReader/resource.h +++ b/src/filters/reader/VTSReader/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by VTSReader.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by VTSReader.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/reader/VTSReader/stdafx.cpp b/src/filters/reader/VTSReader/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/reader/VTSReader/stdafx.cpp +++ b/src/filters/reader/VTSReader/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/reader/VTSReader/stdafx.h b/src/filters/reader/VTSReader/stdafx.h index d8cc4bd3628..26a845cddf4 100644 --- a/src/filters/reader/VTSReader/stdafx.h +++ b/src/filters/reader/VTSReader/stdafx.h @@ -1,33 +1,33 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" diff --git a/src/filters/renderer/SyncClock/Interfaces.h b/src/filters/renderer/SyncClock/Interfaces.h index 471f9c801c9..b50c046b2a0 100644 --- a/src/filters/renderer/SyncClock/Interfaces.h +++ b/src/filters/renderer/SyncClock/Interfaces.h @@ -1,33 +1,33 @@ -/* - * (C) 2010-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 . - * - */ - -#pragma once - -const IID IID_ISyncClock = {0xa62888fb, 0x8e37, 0x44d2, {0x88, 0x50, 0xb3, 0xe3, 0xf2, 0xc1, 0x16, 0x9f}}; - -MIDL_INTERFACE("A62888FB-8E37-44d2-8850-B3E3F2C1169F") -ISyncClock: -public IUnknown { -public: - STDMETHOD(AdjustClock)(double adjustment) PURE; - STDMETHOD(SetBias)(double bias) PURE; - STDMETHOD(GetBias)(double * bias) PURE; - STDMETHOD(GetStartTime)(REFERENCE_TIME * startTime); -}; +/* + * (C) 2010-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 . + * + */ + +#pragma once + +const IID IID_ISyncClock = {0xa62888fb, 0x8e37, 0x44d2, {0x88, 0x50, 0xb3, 0xe3, 0xf2, 0xc1, 0x16, 0x9f}}; + +MIDL_INTERFACE("A62888FB-8E37-44d2-8850-B3E3F2C1169F") +ISyncClock: +public IUnknown { +public: + STDMETHOD(AdjustClock)(double adjustment) PURE; + STDMETHOD(SetBias)(double bias) PURE; + STDMETHOD(GetBias)(double * bias) PURE; + STDMETHOD(GetStartTime)(REFERENCE_TIME * startTime); +}; diff --git a/src/filters/renderer/SyncClock/SyncClock.cpp b/src/filters/renderer/SyncClock/SyncClock.cpp index 4e327460c65..6b2356c0cc3 100644 --- a/src/filters/renderer/SyncClock/SyncClock.cpp +++ b/src/filters/renderer/SyncClock/SyncClock.cpp @@ -1,120 +1,120 @@ -/* - * (C) 2010-2014 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 . - * - */ - -#include "stdafx.h" -#include "SyncClock.h" - -CSyncClockFilter::CSyncClockFilter(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseFilter(NAME("SyncClock"), nullptr, &m_Lock, CLSID_NULL) - , m_Clock(static_cast(this), phr) -{ -} - -CSyncClockFilter::~CSyncClockFilter() -{ -} - -STDMETHODIMP CSyncClockFilter::AdjustClock(double adjustment) -{ - m_Clock.adjustment = adjustment; - return S_OK; -} - -STDMETHODIMP CSyncClockFilter::SetBias(double bias) -{ - m_Clock.bias = bias; - return S_OK; -} - -STDMETHODIMP CSyncClockFilter::GetBias(double* bias) -{ - *bias = m_Clock.bias; - return S_OK; -} - -STDMETHODIMP CSyncClockFilter::GetStartTime(REFERENCE_TIME* startTime) -{ - *startTime = m_tStart; - return S_OK; -} - -STDMETHODIMP CSyncClockFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - if (riid == IID_IReferenceClock) { - return GetInterface(static_cast(&m_Clock), ppv); - } else if (riid == IID_ISyncClock) { - return GetInterface(static_cast(this), ppv); - } else { - return CBaseFilter::NonDelegatingQueryInterface(riid, ppv); - } -} - -int CSyncClockFilter::GetPinCount() -{ - return 0; -} - -CBasePin* CSyncClockFilter::GetPin(int i) -{ - UNREFERENCED_PARAMETER(i); - return nullptr; -} - -// CSyncClock methods -CSyncClock::CSyncClock(LPUNKNOWN pUnk, HRESULT* phr) - : CBaseReferenceClock(NAME("SyncClock"), pUnk, phr) - , adjustment(1.0) - , bias(1.0) - , m_rtPrivateTime(GetTicks100ns()) - , m_llPerfFrequency(0) - , m_rtPrevTime(m_rtPrivateTime) - , m_pCurrentRefClock(0) - , m_pPrevRefClock(0) -{ - QueryPerformanceFrequency((LARGE_INTEGER*)&m_llPerfFrequency); -} - -REFERENCE_TIME CSyncClock::GetPrivateTime() -{ - CAutoLock cObjectLock(this); - - REFERENCE_TIME rtTime = GetTicks100ns(); - - REFERENCE_TIME delta = rtTime - m_rtPrevTime; - // We ignore that rtTime may wrap around. Not gonna happen too often - m_rtPrevTime = rtTime; - - delta = (REFERENCE_TIME)((double)delta * adjustment * bias); - m_rtPrivateTime = m_rtPrivateTime + delta; - return m_rtPrivateTime; -} - -REFERENCE_TIME CSyncClock::GetTicks100ns() -{ - LONGLONG i64Ticks100ns; - if (m_llPerfFrequency != 0) { - QueryPerformanceCounter((LARGE_INTEGER*)&i64Ticks100ns); - i64Ticks100ns = LONGLONG((double(i64Ticks100ns) * 10000000) / double(m_llPerfFrequency) + 0.5); - return (REFERENCE_TIME)i64Ticks100ns; - } - return 0; -} +/* + * (C) 2010-2014 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 . + * + */ + +#include "stdafx.h" +#include "SyncClock.h" + +CSyncClockFilter::CSyncClockFilter(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseFilter(NAME("SyncClock"), nullptr, &m_Lock, CLSID_NULL) + , m_Clock(static_cast(this), phr) +{ +} + +CSyncClockFilter::~CSyncClockFilter() +{ +} + +STDMETHODIMP CSyncClockFilter::AdjustClock(double adjustment) +{ + m_Clock.adjustment = adjustment; + return S_OK; +} + +STDMETHODIMP CSyncClockFilter::SetBias(double bias) +{ + m_Clock.bias = bias; + return S_OK; +} + +STDMETHODIMP CSyncClockFilter::GetBias(double* bias) +{ + *bias = m_Clock.bias; + return S_OK; +} + +STDMETHODIMP CSyncClockFilter::GetStartTime(REFERENCE_TIME* startTime) +{ + *startTime = m_tStart; + return S_OK; +} + +STDMETHODIMP CSyncClockFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + if (riid == IID_IReferenceClock) { + return GetInterface(static_cast(&m_Clock), ppv); + } else if (riid == IID_ISyncClock) { + return GetInterface(static_cast(this), ppv); + } else { + return CBaseFilter::NonDelegatingQueryInterface(riid, ppv); + } +} + +int CSyncClockFilter::GetPinCount() +{ + return 0; +} + +CBasePin* CSyncClockFilter::GetPin(int i) +{ + UNREFERENCED_PARAMETER(i); + return nullptr; +} + +// CSyncClock methods +CSyncClock::CSyncClock(LPUNKNOWN pUnk, HRESULT* phr) + : CBaseReferenceClock(NAME("SyncClock"), pUnk, phr) + , adjustment(1.0) + , bias(1.0) + , m_rtPrivateTime(GetTicks100ns()) + , m_llPerfFrequency(0) + , m_rtPrevTime(m_rtPrivateTime) + , m_pCurrentRefClock(0) + , m_pPrevRefClock(0) +{ + QueryPerformanceFrequency((LARGE_INTEGER*)&m_llPerfFrequency); +} + +REFERENCE_TIME CSyncClock::GetPrivateTime() +{ + CAutoLock cObjectLock(this); + + REFERENCE_TIME rtTime = GetTicks100ns(); + + REFERENCE_TIME delta = rtTime - m_rtPrevTime; + // We ignore that rtTime may wrap around. Not gonna happen too often + m_rtPrevTime = rtTime; + + delta = (REFERENCE_TIME)((double)delta * adjustment * bias); + m_rtPrivateTime = m_rtPrivateTime + delta; + return m_rtPrivateTime; +} + +REFERENCE_TIME CSyncClock::GetTicks100ns() +{ + LONGLONG i64Ticks100ns; + if (m_llPerfFrequency != 0) { + QueryPerformanceCounter((LARGE_INTEGER*)&i64Ticks100ns); + i64Ticks100ns = LONGLONG((double(i64Ticks100ns) * 10000000) / double(m_llPerfFrequency) + 0.5); + return (REFERENCE_TIME)i64Ticks100ns; + } + return 0; +} diff --git a/src/filters/renderer/SyncClock/SyncClock.h b/src/filters/renderer/SyncClock/SyncClock.h index 3d1ff252ddd..40be493e985 100644 --- a/src/filters/renderer/SyncClock/SyncClock.h +++ b/src/filters/renderer/SyncClock/SyncClock.h @@ -1,71 +1,71 @@ -/* - * (C) 2010-2013, 2016 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 . - * - */ - -#pragma once - -#include "Interfaces.h" - -class CSyncClockFilter; - -class CSyncClock: public CBaseReferenceClock -{ - friend class CSyncClockFilter; -public: - CSyncClock(LPUNKNOWN pUnk, HRESULT* phr); - - REFERENCE_TIME GetPrivateTime(); - IUnknown* pUnk() { return static_cast(static_cast(this)); } - double adjustment; // For adjusting speed temporarily - double bias; // For changing speed permanently - -private: - REFERENCE_TIME m_rtPrivateTime; - LONGLONG m_llPerfFrequency; - REFERENCE_TIME m_rtPrevTime; - CCritSec m_csClock; - IReferenceClock* m_pCurrentRefClock; - IReferenceClock* m_pPrevRefClock; - REFERENCE_TIME GetTicks100ns(); -}; - -class __declspec(uuid("57797fe5-ee9b-4408-98a9-20b134e7e8f0")) - CSyncClockFilter: public ISyncClock, public CBaseFilter -{ -public: - CSyncClockFilter(LPUNKNOWN pUnk, HRESULT* phr); - virtual ~CSyncClockFilter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISyncClock - STDMETHODIMP AdjustClock(double adjustment); - STDMETHODIMP SetBias(double bias); - STDMETHODIMP GetBias(double* bias); - STDMETHODIMP GetStartTime(REFERENCE_TIME* startTime); - - // CBaseFilter methods - int GetPinCount(); - CBasePin* GetPin(int iPin); - -private: - CSyncClock m_Clock; - CCritSec m_Lock; -}; +/* + * (C) 2010-2013, 2016 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 . + * + */ + +#pragma once + +#include "Interfaces.h" + +class CSyncClockFilter; + +class CSyncClock: public CBaseReferenceClock +{ + friend class CSyncClockFilter; +public: + CSyncClock(LPUNKNOWN pUnk, HRESULT* phr); + + REFERENCE_TIME GetPrivateTime(); + IUnknown* pUnk() { return static_cast(static_cast(this)); } + double adjustment; // For adjusting speed temporarily + double bias; // For changing speed permanently + +private: + REFERENCE_TIME m_rtPrivateTime; + LONGLONG m_llPerfFrequency; + REFERENCE_TIME m_rtPrevTime; + CCritSec m_csClock; + IReferenceClock* m_pCurrentRefClock; + IReferenceClock* m_pPrevRefClock; + REFERENCE_TIME GetTicks100ns(); +}; + +class __declspec(uuid("57797fe5-ee9b-4408-98a9-20b134e7e8f0")) + CSyncClockFilter: public ISyncClock, public CBaseFilter +{ +public: + CSyncClockFilter(LPUNKNOWN pUnk, HRESULT* phr); + virtual ~CSyncClockFilter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISyncClock + STDMETHODIMP AdjustClock(double adjustment); + STDMETHODIMP SetBias(double bias); + STDMETHODIMP GetBias(double* bias); + STDMETHODIMP GetStartTime(REFERENCE_TIME* startTime); + + // CBaseFilter methods + int GetPinCount(); + CBasePin* GetPin(int iPin); + +private: + CSyncClock m_Clock; + CCritSec m_Lock; +}; diff --git a/src/filters/renderer/SyncClock/SyncClock.vcxproj b/src/filters/renderer/SyncClock/SyncClock.vcxproj index 3709dcc5908..2d0e93dd6ec 100644 --- a/src/filters/renderer/SyncClock/SyncClock.vcxproj +++ b/src/filters/renderer/SyncClock/SyncClock.vcxproj @@ -1,62 +1,62 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {0B63409D-674D-47F8-A84E-87DBB7783189} - SyncClock - MFCProj - SyncClock - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - Create - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0B63409D-674D-47F8-A84E-87DBB7783189} + SyncClock + MFCProj + SyncClock + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + Create + + + + + + + + + + + \ No newline at end of file diff --git a/src/filters/renderer/SyncClock/SyncClock.vcxproj.filters b/src/filters/renderer/SyncClock/SyncClock.vcxproj.filters index fcaaa752862..0703860a34c 100644 --- a/src/filters/renderer/SyncClock/SyncClock.vcxproj.filters +++ b/src/filters/renderer/SyncClock/SyncClock.vcxproj.filters @@ -1,32 +1,32 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/renderer/SyncClock/stdafx.cpp b/src/filters/renderer/SyncClock/stdafx.cpp index 3bf3e3572f9..42728ce2ef5 100644 --- a/src/filters/renderer/SyncClock/stdafx.cpp +++ b/src/filters/renderer/SyncClock/stdafx.cpp @@ -1,21 +1,21 @@ -/* - * (C) 2009-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 . - * - */ - -#include "stdafx.h" +/* + * (C) 2009-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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/renderer/SyncClock/stdafx.h b/src/filters/renderer/SyncClock/stdafx.h index 1a049dcf932..b0b8d199896 100644 --- a/src/filters/renderer/SyncClock/stdafx.h +++ b/src/filters/renderer/SyncClock/stdafx.h @@ -1,32 +1,32 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp b/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp index 5622d203158..aece023177e 100644 --- a/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp +++ b/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp @@ -1,321 +1,321 @@ -/* - * (C) 2006-2013, 2016 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 . - * - */ - -#include "stdafx.h" -#include "AllocatorCommon.h" -#include "../DSUtil/DSUtil.h" - -#include "VMR9AllocatorPresenter.h" -#include "DXRAllocatorPresenter.h" -#include "madVRAllocatorPresenter.h" -#include "EVRAllocatorPresenter.h" -#include "MPCVRAllocatorPresenter.h" - -bool IsVMR9InGraph(IFilterGraph* pFG) -{ - BeginEnumFilters(pFG, pEF, pBF); - if (CComQIPtr(pBF)) { - return true; - } - EndEnumFilters; - return false; -} - -// - -HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP) -{ - CheckPointer(ppAP, E_POINTER); - - *ppAP = nullptr; - - using namespace DSObjects; - - HRESULT hr = E_FAIL; - CString Error; - - if (IsEqualCLSID(clsid, CLSID_VMR9AllocatorPresenter)) { - *ppAP = DEBUG_NEW CVMR9AllocatorPresenter(hWnd, bFullscreen, hr, Error); - } else if (IsEqualCLSID(clsid, CLSID_DXRAllocatorPresenter)) { - *ppAP = DEBUG_NEW CDXRAllocatorPresenter(hWnd, hr, Error); - } else if (IsEqualCLSID(clsid, CLSID_madVRAllocatorPresenter)) { - *ppAP = DEBUG_NEW CmadVRAllocatorPresenter(hWnd, hr, Error); - } else if (IsEqualCLSID(clsid, CLSID_MPCVRAllocatorPresenter)) { - *ppAP = DEBUG_NEW CMPCVRAllocatorPresenter(hWnd, hr, Error); - } else { - return E_FAIL; - } - - if (*ppAP == nullptr) { - return E_OUTOFMEMORY; - } - - (*ppAP)->AddRef(); - - if (FAILED(hr)) { - Error += L"\n"; - Error += GetWindowsErrorMessage(hr, nullptr); - - MessageBox(hWnd, Error, L"Error creating DX9 allocation presenter", MB_OK | MB_ICONERROR); - (*ppAP)->Release(); - *ppAP = nullptr; - } else if (!Error.IsEmpty()) { - MessageBox(hWnd, Error, L"Warning creating DX9 allocation presenter", MB_OK | MB_ICONWARNING); - } - - return hr; -} - -HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP, bool isPreview) -{ - HRESULT hr = E_FAIL; - if (clsid == CLSID_EVRAllocatorPresenter) { - CString Error; - *ppAP = DEBUG_NEW DSObjects::CEVRAllocatorPresenter(hWnd, bFullscreen, hr, Error, isPreview); - if (*ppAP == nullptr) { - return E_OUTOFMEMORY; - } - (*ppAP)->AddRef(); - - if (FAILED(hr)) { - Error += L"\n"; - Error += GetWindowsErrorMessage(hr, nullptr); - MessageBox(hWnd, Error, L"Error creating EVR Custom renderer", MB_OK | MB_ICONERROR); - (*ppAP)->Release(); - *ppAP = nullptr; - } else if (!Error.IsEmpty()) { - MessageBox(hWnd, Error, L"Warning creating EVR Custom renderer", MB_OK | MB_ICONWARNING); - } - - } - - return hr; -} - -CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module) -{ - - switch (_Error) { - case D3DERR_WRONGTEXTUREFORMAT: - return _T("D3DERR_WRONGTEXTUREFORMAT"); - case D3DERR_UNSUPPORTEDCOLOROPERATION: - return _T("D3DERR_UNSUPPORTEDCOLOROPERATION"); - case D3DERR_UNSUPPORTEDCOLORARG: - return _T("D3DERR_UNSUPPORTEDCOLORARG"); - case D3DERR_UNSUPPORTEDALPHAOPERATION: - return _T("D3DERR_UNSUPPORTEDALPHAOPERATION"); - case D3DERR_UNSUPPORTEDALPHAARG: - return _T("D3DERR_UNSUPPORTEDALPHAARG"); - case D3DERR_TOOMANYOPERATIONS: - return _T("D3DERR_TOOMANYOPERATIONS"); - case D3DERR_CONFLICTINGTEXTUREFILTER: - return _T("D3DERR_CONFLICTINGTEXTUREFILTER"); - case D3DERR_UNSUPPORTEDFACTORVALUE: - return _T("D3DERR_UNSUPPORTEDFACTORVALUE"); - case D3DERR_CONFLICTINGRENDERSTATE: - return _T("D3DERR_CONFLICTINGRENDERSTATE"); - case D3DERR_UNSUPPORTEDTEXTUREFILTER: - return _T("D3DERR_UNSUPPORTEDTEXTUREFILTER"); - case D3DERR_CONFLICTINGTEXTUREPALETTE: - return _T("D3DERR_CONFLICTINGTEXTUREPALETTE"); - case D3DERR_DRIVERINTERNALERROR: - return _T("D3DERR_DRIVERINTERNALERROR"); - case D3DERR_NOTFOUND: - return _T("D3DERR_NOTFOUND"); - case D3DERR_MOREDATA: - return _T("D3DERR_MOREDATA"); - case D3DERR_DEVICELOST: - return _T("D3DERR_DEVICELOST"); - case D3DERR_DEVICENOTRESET: - return _T("D3DERR_DEVICENOTRESET"); - case D3DERR_NOTAVAILABLE: - return _T("D3DERR_NOTAVAILABLE"); - case D3DERR_OUTOFVIDEOMEMORY: - return _T("D3DERR_OUTOFVIDEOMEMORY"); - case D3DERR_INVALIDDEVICE: - return _T("D3DERR_INVALIDDEVICE"); - case D3DERR_INVALIDCALL: - return _T("D3DERR_INVALIDCALL"); - case D3DERR_DRIVERINVALIDCALL: - return _T("D3DERR_DRIVERINVALIDCALL"); - case D3DERR_WASSTILLDRAWING: - return _T("D3DERR_WASSTILLDRAWING"); - case D3DOK_NOAUTOGEN: - return _T("D3DOK_NOAUTOGEN"); - case D3DERR_DEVICEREMOVED: - return _T("D3DERR_DEVICEREMOVED"); - case S_NOT_RESIDENT: - return _T("S_NOT_RESIDENT"); - case S_RESIDENT_IN_SHARED_MEMORY: - return _T("S_RESIDENT_IN_SHARED_MEMORY"); - case S_PRESENT_MODE_CHANGED: - return _T("S_PRESENT_MODE_CHANGED"); - case S_PRESENT_OCCLUDED: - return _T("S_PRESENT_OCCLUDED"); - case D3DERR_DEVICEHUNG: - return _T("D3DERR_DEVICEHUNG"); - case E_UNEXPECTED: - return _T("E_UNEXPECTED"); - } - - CString errmsg; - LPVOID lpMsgBuf; - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, - _Module, _Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, nullptr)) { - errmsg = (LPCTSTR)lpMsgBuf; - LocalFree(lpMsgBuf); - } - CString Temp; - Temp.Format(L"0x%08lx ", _Error); - return Temp + errmsg; -} - -const wchar_t* GetD3DFormatStr(D3DFORMAT Format) -{ - switch (Format) { - case D3DFMT_R8G8B8: - return L"R8G8B8"; - case D3DFMT_A8R8G8B8: - return L"A8R8G8B8"; - case D3DFMT_X8R8G8B8: - return L"X8R8G8B8"; - case D3DFMT_R5G6B5: - return L"R5G6B5"; - case D3DFMT_X1R5G5B5: - return L"X1R5G5B5"; - case D3DFMT_A1R5G5B5: - return L"A1R5G5B5"; - case D3DFMT_A4R4G4B4: - return L"A4R4G4B4"; - case D3DFMT_R3G3B2: - return L"R3G3B2"; - case D3DFMT_A8: - return L"A8"; - case D3DFMT_A8R3G3B2: - return L"A8R3G3B2"; - case D3DFMT_X4R4G4B4: - return L"X4R4G4B4"; - case D3DFMT_A2B10G10R10: - return L"A2B10G10R10"; - case D3DFMT_A8B8G8R8: - return L"A8B8G8R8"; - case D3DFMT_X8B8G8R8: - return L"X8B8G8R8"; - case D3DFMT_G16R16: - return L"G16R16"; - case D3DFMT_A2R10G10B10: - return L"A2R10G10B10"; - case D3DFMT_A16B16G16R16: - return L"A16B16G16R16"; - case D3DFMT_A8P8: - return L"A8P8"; - case D3DFMT_P8: - return L"P8"; - case D3DFMT_L8: - return L"L8"; - case D3DFMT_A8L8: - return L"A8L8"; - case D3DFMT_A4L4: - return L"A4L4"; - case D3DFMT_V8U8: - return L"V8U8"; - case D3DFMT_L6V5U5: - return L"L6V5U5"; - case D3DFMT_X8L8V8U8: - return L"X8L8V8U8"; - case D3DFMT_Q8W8V8U8: - return L"Q8W8V8U8"; - case D3DFMT_V16U16: - return L"V16U16"; - case D3DFMT_A2W10V10U10: - return L"A2W10V10U10"; - case D3DFMT_UYVY: - return L"UYVY"; - case D3DFMT_R8G8_B8G8: - return L"R8G8_B8G8"; - case D3DFMT_YUY2: - return L"YUY2"; - case D3DFMT_G8R8_G8B8: - return L"G8R8_G8B8"; - case D3DFMT_DXT1: - return L"DXT1"; - case D3DFMT_DXT2: - return L"DXT2"; - case D3DFMT_DXT3: - return L"DXT3"; - case D3DFMT_DXT4: - return L"DXT4"; - case D3DFMT_DXT5: - return L"DXT5"; - case D3DFMT_D16_LOCKABLE: - return L"D16_LOCKABLE"; - case D3DFMT_D32: - return L"D32"; - case D3DFMT_D15S1: - return L"D15S1"; - case D3DFMT_D24S8: - return L"D24S8"; - case D3DFMT_D24X8: - return L"D24X8"; - case D3DFMT_D24X4S4: - return L"D24X4S4"; - case D3DFMT_D16: - return L"D16"; - case D3DFMT_D32F_LOCKABLE: - return L"D32F_LOCKABLE"; - case D3DFMT_D24FS8: - return L"D24FS8"; - case D3DFMT_D32_LOCKABLE: - return L"D32_LOCKABLE"; - case D3DFMT_S8_LOCKABLE: - return L"S8_LOCKABLE"; - case D3DFMT_L16: - return L"L16"; - case D3DFMT_VERTEXDATA: - return L"VERTEXDATA"; - case D3DFMT_INDEX16: - return L"INDEX16"; - case D3DFMT_INDEX32: - return L"INDEX32"; - case D3DFMT_Q16W16V16U16: - return L"Q16W16V16U16"; - case D3DFMT_MULTI2_ARGB8: - return L"MULTI2_ARGB8"; - case D3DFMT_R16F: - return L"R16F"; - case D3DFMT_G16R16F: - return L"G16R16F"; - case D3DFMT_A16B16G16R16F: - return L"A16B16G16R16F"; - case D3DFMT_R32F: - return L"R32F"; - case D3DFMT_G32R32F: - return L"G32R32F"; - case D3DFMT_A32B32G32R32F: - return L"A32B32G32R32F"; - case D3DFMT_CxV8U8: - return L"CxV8U8"; - case D3DFMT_A1: - return L"A1"; - case D3DFMT_BINARYBUFFER: - return L"BINARYBUFFER"; - } - return L"Unknown"; -} +/* + * (C) 2006-2013, 2016 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 . + * + */ + +#include "stdafx.h" +#include "AllocatorCommon.h" +#include "../DSUtil/DSUtil.h" + +#include "VMR9AllocatorPresenter.h" +#include "DXRAllocatorPresenter.h" +#include "madVRAllocatorPresenter.h" +#include "EVRAllocatorPresenter.h" +#include "MPCVRAllocatorPresenter.h" + +bool IsVMR9InGraph(IFilterGraph* pFG) +{ + BeginEnumFilters(pFG, pEF, pBF); + if (CComQIPtr(pBF)) { + return true; + } + EndEnumFilters; + return false; +} + +// + +HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP) +{ + CheckPointer(ppAP, E_POINTER); + + *ppAP = nullptr; + + using namespace DSObjects; + + HRESULT hr = E_FAIL; + CString Error; + + if (IsEqualCLSID(clsid, CLSID_VMR9AllocatorPresenter)) { + *ppAP = DEBUG_NEW CVMR9AllocatorPresenter(hWnd, bFullscreen, hr, Error); + } else if (IsEqualCLSID(clsid, CLSID_DXRAllocatorPresenter)) { + *ppAP = DEBUG_NEW CDXRAllocatorPresenter(hWnd, hr, Error); + } else if (IsEqualCLSID(clsid, CLSID_madVRAllocatorPresenter)) { + *ppAP = DEBUG_NEW CmadVRAllocatorPresenter(hWnd, hr, Error); + } else if (IsEqualCLSID(clsid, CLSID_MPCVRAllocatorPresenter)) { + *ppAP = DEBUG_NEW CMPCVRAllocatorPresenter(hWnd, hr, Error); + } else { + return E_FAIL; + } + + if (*ppAP == nullptr) { + return E_OUTOFMEMORY; + } + + (*ppAP)->AddRef(); + + if (FAILED(hr)) { + Error += L"\n"; + Error += GetWindowsErrorMessage(hr, nullptr); + + MessageBox(hWnd, Error, L"Error creating DX9 allocation presenter", MB_OK | MB_ICONERROR); + (*ppAP)->Release(); + *ppAP = nullptr; + } else if (!Error.IsEmpty()) { + MessageBox(hWnd, Error, L"Warning creating DX9 allocation presenter", MB_OK | MB_ICONWARNING); + } + + return hr; +} + +HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP, bool isPreview) +{ + HRESULT hr = E_FAIL; + if (clsid == CLSID_EVRAllocatorPresenter) { + CString Error; + *ppAP = DEBUG_NEW DSObjects::CEVRAllocatorPresenter(hWnd, bFullscreen, hr, Error, isPreview); + if (*ppAP == nullptr) { + return E_OUTOFMEMORY; + } + (*ppAP)->AddRef(); + + if (FAILED(hr)) { + Error += L"\n"; + Error += GetWindowsErrorMessage(hr, nullptr); + MessageBox(hWnd, Error, L"Error creating EVR Custom renderer", MB_OK | MB_ICONERROR); + (*ppAP)->Release(); + *ppAP = nullptr; + } else if (!Error.IsEmpty()) { + MessageBox(hWnd, Error, L"Warning creating EVR Custom renderer", MB_OK | MB_ICONWARNING); + } + + } + + return hr; +} + +CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module) +{ + + switch (_Error) { + case D3DERR_WRONGTEXTUREFORMAT: + return _T("D3DERR_WRONGTEXTUREFORMAT"); + case D3DERR_UNSUPPORTEDCOLOROPERATION: + return _T("D3DERR_UNSUPPORTEDCOLOROPERATION"); + case D3DERR_UNSUPPORTEDCOLORARG: + return _T("D3DERR_UNSUPPORTEDCOLORARG"); + case D3DERR_UNSUPPORTEDALPHAOPERATION: + return _T("D3DERR_UNSUPPORTEDALPHAOPERATION"); + case D3DERR_UNSUPPORTEDALPHAARG: + return _T("D3DERR_UNSUPPORTEDALPHAARG"); + case D3DERR_TOOMANYOPERATIONS: + return _T("D3DERR_TOOMANYOPERATIONS"); + case D3DERR_CONFLICTINGTEXTUREFILTER: + return _T("D3DERR_CONFLICTINGTEXTUREFILTER"); + case D3DERR_UNSUPPORTEDFACTORVALUE: + return _T("D3DERR_UNSUPPORTEDFACTORVALUE"); + case D3DERR_CONFLICTINGRENDERSTATE: + return _T("D3DERR_CONFLICTINGRENDERSTATE"); + case D3DERR_UNSUPPORTEDTEXTUREFILTER: + return _T("D3DERR_UNSUPPORTEDTEXTUREFILTER"); + case D3DERR_CONFLICTINGTEXTUREPALETTE: + return _T("D3DERR_CONFLICTINGTEXTUREPALETTE"); + case D3DERR_DRIVERINTERNALERROR: + return _T("D3DERR_DRIVERINTERNALERROR"); + case D3DERR_NOTFOUND: + return _T("D3DERR_NOTFOUND"); + case D3DERR_MOREDATA: + return _T("D3DERR_MOREDATA"); + case D3DERR_DEVICELOST: + return _T("D3DERR_DEVICELOST"); + case D3DERR_DEVICENOTRESET: + return _T("D3DERR_DEVICENOTRESET"); + case D3DERR_NOTAVAILABLE: + return _T("D3DERR_NOTAVAILABLE"); + case D3DERR_OUTOFVIDEOMEMORY: + return _T("D3DERR_OUTOFVIDEOMEMORY"); + case D3DERR_INVALIDDEVICE: + return _T("D3DERR_INVALIDDEVICE"); + case D3DERR_INVALIDCALL: + return _T("D3DERR_INVALIDCALL"); + case D3DERR_DRIVERINVALIDCALL: + return _T("D3DERR_DRIVERINVALIDCALL"); + case D3DERR_WASSTILLDRAWING: + return _T("D3DERR_WASSTILLDRAWING"); + case D3DOK_NOAUTOGEN: + return _T("D3DOK_NOAUTOGEN"); + case D3DERR_DEVICEREMOVED: + return _T("D3DERR_DEVICEREMOVED"); + case S_NOT_RESIDENT: + return _T("S_NOT_RESIDENT"); + case S_RESIDENT_IN_SHARED_MEMORY: + return _T("S_RESIDENT_IN_SHARED_MEMORY"); + case S_PRESENT_MODE_CHANGED: + return _T("S_PRESENT_MODE_CHANGED"); + case S_PRESENT_OCCLUDED: + return _T("S_PRESENT_OCCLUDED"); + case D3DERR_DEVICEHUNG: + return _T("D3DERR_DEVICEHUNG"); + case E_UNEXPECTED: + return _T("E_UNEXPECTED"); + } + + CString errmsg; + LPVOID lpMsgBuf; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, + _Module, _Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, nullptr)) { + errmsg = (LPCTSTR)lpMsgBuf; + LocalFree(lpMsgBuf); + } + CString Temp; + Temp.Format(L"0x%08lx ", _Error); + return Temp + errmsg; +} + +const wchar_t* GetD3DFormatStr(D3DFORMAT Format) +{ + switch (Format) { + case D3DFMT_R8G8B8: + return L"R8G8B8"; + case D3DFMT_A8R8G8B8: + return L"A8R8G8B8"; + case D3DFMT_X8R8G8B8: + return L"X8R8G8B8"; + case D3DFMT_R5G6B5: + return L"R5G6B5"; + case D3DFMT_X1R5G5B5: + return L"X1R5G5B5"; + case D3DFMT_A1R5G5B5: + return L"A1R5G5B5"; + case D3DFMT_A4R4G4B4: + return L"A4R4G4B4"; + case D3DFMT_R3G3B2: + return L"R3G3B2"; + case D3DFMT_A8: + return L"A8"; + case D3DFMT_A8R3G3B2: + return L"A8R3G3B2"; + case D3DFMT_X4R4G4B4: + return L"X4R4G4B4"; + case D3DFMT_A2B10G10R10: + return L"A2B10G10R10"; + case D3DFMT_A8B8G8R8: + return L"A8B8G8R8"; + case D3DFMT_X8B8G8R8: + return L"X8B8G8R8"; + case D3DFMT_G16R16: + return L"G16R16"; + case D3DFMT_A2R10G10B10: + return L"A2R10G10B10"; + case D3DFMT_A16B16G16R16: + return L"A16B16G16R16"; + case D3DFMT_A8P8: + return L"A8P8"; + case D3DFMT_P8: + return L"P8"; + case D3DFMT_L8: + return L"L8"; + case D3DFMT_A8L8: + return L"A8L8"; + case D3DFMT_A4L4: + return L"A4L4"; + case D3DFMT_V8U8: + return L"V8U8"; + case D3DFMT_L6V5U5: + return L"L6V5U5"; + case D3DFMT_X8L8V8U8: + return L"X8L8V8U8"; + case D3DFMT_Q8W8V8U8: + return L"Q8W8V8U8"; + case D3DFMT_V16U16: + return L"V16U16"; + case D3DFMT_A2W10V10U10: + return L"A2W10V10U10"; + case D3DFMT_UYVY: + return L"UYVY"; + case D3DFMT_R8G8_B8G8: + return L"R8G8_B8G8"; + case D3DFMT_YUY2: + return L"YUY2"; + case D3DFMT_G8R8_G8B8: + return L"G8R8_G8B8"; + case D3DFMT_DXT1: + return L"DXT1"; + case D3DFMT_DXT2: + return L"DXT2"; + case D3DFMT_DXT3: + return L"DXT3"; + case D3DFMT_DXT4: + return L"DXT4"; + case D3DFMT_DXT5: + return L"DXT5"; + case D3DFMT_D16_LOCKABLE: + return L"D16_LOCKABLE"; + case D3DFMT_D32: + return L"D32"; + case D3DFMT_D15S1: + return L"D15S1"; + case D3DFMT_D24S8: + return L"D24S8"; + case D3DFMT_D24X8: + return L"D24X8"; + case D3DFMT_D24X4S4: + return L"D24X4S4"; + case D3DFMT_D16: + return L"D16"; + case D3DFMT_D32F_LOCKABLE: + return L"D32F_LOCKABLE"; + case D3DFMT_D24FS8: + return L"D24FS8"; + case D3DFMT_D32_LOCKABLE: + return L"D32_LOCKABLE"; + case D3DFMT_S8_LOCKABLE: + return L"S8_LOCKABLE"; + case D3DFMT_L16: + return L"L16"; + case D3DFMT_VERTEXDATA: + return L"VERTEXDATA"; + case D3DFMT_INDEX16: + return L"INDEX16"; + case D3DFMT_INDEX32: + return L"INDEX32"; + case D3DFMT_Q16W16V16U16: + return L"Q16W16V16U16"; + case D3DFMT_MULTI2_ARGB8: + return L"MULTI2_ARGB8"; + case D3DFMT_R16F: + return L"R16F"; + case D3DFMT_G16R16F: + return L"G16R16F"; + case D3DFMT_A16B16G16R16F: + return L"A16B16G16R16F"; + case D3DFMT_R32F: + return L"R32F"; + case D3DFMT_G32R32F: + return L"G32R32F"; + case D3DFMT_A32B32G32R32F: + return L"A32B32G32R32F"; + case D3DFMT_CxV8U8: + return L"CxV8U8"; + case D3DFMT_A1: + return L"A1"; + case D3DFMT_BINARYBUFFER: + return L"BINARYBUFFER"; + } + return L"Unknown"; +} diff --git a/src/filters/renderer/VideoRenderers/AllocatorCommon.h b/src/filters/renderer/VideoRenderers/AllocatorCommon.h index 78b89480957..a58e7a37a2b 100644 --- a/src/filters/renderer/VideoRenderers/AllocatorCommon.h +++ b/src/filters/renderer/VideoRenderers/AllocatorCommon.h @@ -1,61 +1,61 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include -#include "../../../SubPic/ISubPic.h" -#include "PixelShaderCompiler.h" - -// {4E4834FA-22C2-40e2-9446-F77DD05D245E} -DEFINE_GUID(CLSID_VMR9AllocatorPresenter, - 0x4e4834fa, 0x22c2, 0x40e2, 0x94, 0x46, 0xf7, 0x7d, 0xd0, 0x5d, 0x24, 0x5e); - -// {B72EBDD4-831D-440f-A656-B48F5486CD82} -DEFINE_GUID(CLSID_DXRAllocatorPresenter, - 0xb72ebdd4, 0x831d, 0x440f, 0xa6, 0x56, 0xb4, 0x8f, 0x54, 0x86, 0xcd, 0x82); - -// {C7ED3100-9002-4595-9DCA-B30B30413429} -DEFINE_GUID(CLSID_madVRAllocatorPresenter, - 0xc7ed3100, 0x9002, 0x4595, 0x9d, 0xca, 0xb3, 0xb, 0x30, 0x41, 0x34, 0x29); - -DEFINE_GUID(CLSID_MPCVRAllocatorPresenter, - 0x28789E29, 0x5BDD, 0x4374, 0xAD, 0xEC, 0xAB, 0x2E, 0xB9, 0x21, 0x2C, 0x0D); - -DEFINE_GUID(CLSID_EVRAllocatorPresenter, - 0x7612b889, 0xe070, 0x4bcc, 0xb8, 0x8, 0x91, 0xcb, 0x79, 0x41, 0x74, 0xab); - -extern bool IsVMR9InGraph(IFilterGraph* pFG); -extern CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module); -extern const wchar_t* GetD3DFormatStr(D3DFORMAT Format); - -extern HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP); -extern HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP, bool isPreview = false); - -// Set and query D3DFullscreen mode. -interface __declspec(uuid("8EA1E899-B77D-4777-9F0E-66421BEA50F8")) - ID3DFullscreenControl : - public IUnknown -{ - STDMETHOD(SetD3DFullscreen)(bool fEnabled) PURE; - STDMETHOD(GetD3DFullscreen)(bool* pfEnabled) PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include +#include "../../../SubPic/ISubPic.h" +#include "PixelShaderCompiler.h" + +// {4E4834FA-22C2-40e2-9446-F77DD05D245E} +DEFINE_GUID(CLSID_VMR9AllocatorPresenter, + 0x4e4834fa, 0x22c2, 0x40e2, 0x94, 0x46, 0xf7, 0x7d, 0xd0, 0x5d, 0x24, 0x5e); + +// {B72EBDD4-831D-440f-A656-B48F5486CD82} +DEFINE_GUID(CLSID_DXRAllocatorPresenter, + 0xb72ebdd4, 0x831d, 0x440f, 0xa6, 0x56, 0xb4, 0x8f, 0x54, 0x86, 0xcd, 0x82); + +// {C7ED3100-9002-4595-9DCA-B30B30413429} +DEFINE_GUID(CLSID_madVRAllocatorPresenter, + 0xc7ed3100, 0x9002, 0x4595, 0x9d, 0xca, 0xb3, 0xb, 0x30, 0x41, 0x34, 0x29); + +DEFINE_GUID(CLSID_MPCVRAllocatorPresenter, + 0x28789E29, 0x5BDD, 0x4374, 0xAD, 0xEC, 0xAB, 0x2E, 0xB9, 0x21, 0x2C, 0x0D); + +DEFINE_GUID(CLSID_EVRAllocatorPresenter, + 0x7612b889, 0xe070, 0x4bcc, 0xb8, 0x8, 0x91, 0xcb, 0x79, 0x41, 0x74, 0xab); + +extern bool IsVMR9InGraph(IFilterGraph* pFG); +extern CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module); +extern const wchar_t* GetD3DFormatStr(D3DFORMAT Format); + +extern HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP); +extern HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP, bool isPreview = false); + +// Set and query D3DFullscreen mode. +interface __declspec(uuid("8EA1E899-B77D-4777-9F0E-66421BEA50F8")) + ID3DFullscreenControl : + public IUnknown +{ + STDMETHOD(SetD3DFullscreen)(bool fEnabled) PURE; + STDMETHOD(GetD3DFullscreen)(bool* pfEnabled) PURE; +}; diff --git a/src/filters/renderer/VideoRenderers/D3DFont.cpp b/src/filters/renderer/VideoRenderers/D3DFont.cpp index af6551b65d2..901dc32d762 100644 --- a/src/filters/renderer/VideoRenderers/D3DFont.cpp +++ b/src/filters/renderer/VideoRenderers/D3DFont.cpp @@ -1,877 +1,877 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include -#include -#include "d3dx9/d3dx9.h" -#include "D3DFont.h" -#include "../../../DSUtil/DSUtil.h" - -//----------------------------------------------------------------------------- -// Custom vertex types for rendering text -//----------------------------------------------------------------------------- -#define MAX_NUM_VERTICES 50 * 6 - -struct FONT2DVERTEX { - D3DXVECTOR4 p; - DWORD color; - float tu, tv; -}; - -struct FONT3DVERTEX { - D3DXVECTOR3 p; - D3DXVECTOR3 n; - float tu, tv; -}; - -#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1) -#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) - - -inline FONT2DVERTEX InitFont2DVertex(const D3DXVECTOR4& p, D3DCOLOR color, - float tu, float tv) -{ - FONT2DVERTEX v; - v.p = p; - v.color = color; - v.tu = tu; - v.tv = tv; - return v; -} - -inline FONT3DVERTEX InitFont3DVertex(const D3DXVECTOR3& p, const D3DXVECTOR3& n, - float tu, float tv) -{ - FONT3DVERTEX v; - v.p = p; - v.n = n; - v.tu = tu; - v.tv = tv; - return v; -} - - - -//----------------------------------------------------------------------------- -// Name: CD3DFont() -// Desc: Font class constructor -//----------------------------------------------------------------------------- -CD3DFont::CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags) -{ - _tcsncpy_s(m_strFontName, strFontName, _countof(m_strFontName)); - m_strFontName[_countof(m_strFontName) - 1] = _T('\0'); - m_dwFontHeight = dwHeight; - m_dwFontFlags = dwFlags; - m_dwSpacing = 0; - m_dwTexWidth = 0; - m_dwTexHeight = 0; - m_fTextScale = 0.0f; - ZeroMemory(m_fTexCoords, sizeof(m_fTexCoords)); - - m_pd3dDevice = nullptr; - m_pTexture = nullptr; - m_pVB = nullptr; - - m_pStateBlockSaved = nullptr; - m_pStateBlockDrawText = nullptr; -} - - - -//----------------------------------------------------------------------------- -// Name: ~CD3DFont() -// Desc: Font class destructor -//----------------------------------------------------------------------------- -CD3DFont::~CD3DFont() -{ - InvalidateDeviceObjects(); - DeleteDeviceObjects(); -} - - - -//----------------------------------------------------------------------------- -// Name: CreateGDIFont -// Desc: Create a font based on the current state of related member variables -// and return the handle (or null on error) -//----------------------------------------------------------------------------- -HRESULT CD3DFont::CreateGDIFont(HDC hDC, HFONT* pFont) -{ - // Create a font. By specifying ANTIALIASED_QUALITY, we might get an - // antialiased font, but this is not guaranteed. - int nHeight = -MulDiv(m_dwFontHeight, - (int)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), - 72); - DWORD dwBold = (m_dwFontFlags & D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL; - DWORD dwItalic = (m_dwFontFlags & D3DFONT_ITALIC) ? TRUE : FALSE; - *pFont = CreateFont(nHeight, 0, 0, 0, dwBold, dwItalic, - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, - VARIABLE_PITCH, m_strFontName); - - if (*pFont == nullptr) { - return E_FAIL; - } - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: PaintAlphabet -// Desc: Paint the printable characters for the given GDI font onto the -// provided device context. If the bMeasureOnly flag is set, no drawing -// will occur. -//----------------------------------------------------------------------------- -HRESULT CD3DFont::PaintAlphabet(HDC hDC, BOOL bMeasureOnly) -{ - SIZE size; - TCHAR str[2] = _T("x"); // One-character, null-terminated string - - // Calculate the spacing between characters based on line height - if (0 == GetTextExtentPoint32(hDC, str, 1, &size)) { - return E_FAIL; - } - m_dwSpacing = (DWORD) ceil(size.cy * 0.3f); - - // Set the starting point for the drawing - DWORD x = m_dwSpacing; - DWORD y = 0; - - // For each character, draw text on the DC and advance the current position - for (char c = 32; c < 127; c++) { - str[0] = c; - if (0 == GetTextExtentPoint32(hDC, str, 1, &size)) { - return E_FAIL; - } - - if ((DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth) { - x = m_dwSpacing; - y += size.cy + 1; - } - - // Check to see if there's room to write the character here - if (y + size.cy > m_dwTexHeight) { - return D3DERR_MOREDATA; - } - - if (!bMeasureOnly) { - // Perform the actual drawing - if (0 == ExtTextOut(hDC, x + 0, y + 0, ETO_OPAQUE, nullptr, str, 1, nullptr)) { - return E_FAIL; - } - - m_fTexCoords[c - 32][0] = ((float)(x + 0 - m_dwSpacing)) / m_dwTexWidth; - m_fTexCoords[c - 32][1] = ((float)(y + 0 + 0)) / m_dwTexHeight; - m_fTexCoords[c - 32][2] = ((float)(x + size.cx + m_dwSpacing)) / m_dwTexWidth; - m_fTexCoords[c - 32][3] = ((float)(y + size.cy + 0)) / m_dwTexHeight; - } - - x += size.cx + (2 * m_dwSpacing); - } - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: InitDeviceObjects() -// Desc: Initializes device-dependent objects, including the vertex buffer used -// for rendering text and the texture map which stores the font image. -//----------------------------------------------------------------------------- -HRESULT CD3DFont::InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice) -{ - HRESULT hr; - HFONT hFont = nullptr; - HFONT hFontOld = nullptr; - HDC hDC = nullptr; - HBITMAP hbmBitmap = nullptr; - HGDIOBJ hbmOld = nullptr; - - // Keep a local copy of the device - m_pd3dDevice = pd3dDevice; - - // Assume we will draw fonts into texture without scaling unless the - // required texture size is found to be larger than the device max - m_fTextScale = 1.0f; - - hDC = CreateCompatibleDC(nullptr); - SetMapMode(hDC, MM_TEXT); - - hr = CreateGDIFont(hDC, &hFont); - if (FAILED(hr)) { - goto LCleanReturn; - } - - hFontOld = (HFONT) SelectObject(hDC, hFont); - - // Calculate the dimensions for the smallest power-of-two texture which - // can hold all the printable characters - m_dwTexWidth = m_dwTexHeight = 128; - while (D3DERR_MOREDATA == (hr = PaintAlphabet(hDC, true))) { - m_dwTexWidth *= 2; - m_dwTexHeight *= 2; - } - - if (FAILED(hr)) { - goto LCleanReturn; - } - - // If requested texture is too big, use a smaller texture and smaller font, - // and scale up when rendering. - D3DCAPS9 d3dCaps; - m_pd3dDevice->GetDeviceCaps(&d3dCaps); - - if (m_dwTexWidth > d3dCaps.MaxTextureWidth) { - m_fTextScale = (float)d3dCaps.MaxTextureWidth / (float)m_dwTexWidth; - m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth; - - bool bFirstRun = true; // Flag clear after first run - - do { - // If we've already tried fitting the new text, the scale is still - // too large. Reduce and try again. - if (!bFirstRun) { - m_fTextScale *= 0.9f; - } - - // The font has to be scaled to fit on the maximum texture size; our - // current font is too big and needs to be recreated to scale. - DeleteObject(SelectObject(hDC, hFontOld)); - - hr = CreateGDIFont(hDC, &hFont); - if (FAILED(hr)) { - goto LCleanReturn; - } - - hFontOld = (HFONT) SelectObject(hDC, hFont); - - bFirstRun = false; - } while (D3DERR_MOREDATA == (hr = PaintAlphabet(hDC, true))); - } - - - // Create a new texture for the font - hr = m_pd3dDevice->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, - 0, D3DFMT_A4R4G4B4, - D3DPOOL_MANAGED, &m_pTexture, nullptr); - if (FAILED(hr)) { - goto LCleanReturn; - } - - // Prepare to create a bitmap - DWORD* pBitmapBits; - BITMAPINFO bmi; - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; - - // Create a bitmap for the font - hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, - (void**)&pBitmapBits, nullptr, 0); - - hbmOld = SelectObject(hDC, hbmBitmap); - - // Set text properties - SetTextColor(hDC, RGB(255, 255, 255)); - SetBkColor(hDC, 0x00000000); - SetTextAlign(hDC, TA_TOP); - - // Paint the alphabet onto the selected bitmap - hr = PaintAlphabet(hDC, false); - if (FAILED(hr)) { - goto LCleanReturn; - } - - // Lock the surface and write the alpha values for the set pixels - D3DLOCKED_RECT d3dlr; - m_pTexture->LockRect(0, &d3dlr, 0, 0); - BYTE* pDstRow = (BYTE*)d3dlr.pBits; - for (DWORD y = 0; y < m_dwTexHeight; y++) { - WORD* pDst16 = (WORD*)pDstRow; - for (DWORD x = 0; x < m_dwTexWidth; x++) { - // 4-bit measure of pixel intensity - BYTE bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4); - if (bAlpha > 0) { - *pDst16++ = (WORD)((bAlpha << 12) | 0x0fff); - } else { - *pDst16++ = 0x0000; - } - } - pDstRow += d3dlr.Pitch; - } - - hr = S_OK; - - // Done updating texture, so clean up used objects -LCleanReturn: - if (m_pTexture) { - m_pTexture->UnlockRect(0); - } - - SelectObject(hDC, hbmOld); - SelectObject(hDC, hFontOld); - DeleteObject(hbmBitmap); - DeleteObject(hFont); - DeleteDC(hDC); - - return hr; -} - - -//----------------------------------------------------------------------------- -// Name: RestoreDeviceObjects() -// Desc: -//----------------------------------------------------------------------------- -HRESULT CD3DFont::RestoreDeviceObjects() -{ - HRESULT hr; - - // Create vertex buffer for the letters - UINT vertexSize = std::max(sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX)); - if (FAILED(hr = m_pd3dDevice->CreateVertexBuffer(MAX_NUM_VERTICES * vertexSize, - D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, - D3DPOOL_DEFAULT, &m_pVB, nullptr))) { - return hr; - } - - bool bSupportsAlphaBlend = true; - LPDIRECT3D9 pd3d9 = nullptr; - if (SUCCEEDED(m_pd3dDevice->GetDirect3D(&pd3d9))) { - D3DCAPS9 Caps; - D3DDISPLAYMODE Mode; - LPDIRECT3DSURFACE9 pSurf = nullptr; - D3DSURFACE_DESC Desc; - m_pd3dDevice->GetDeviceCaps(&Caps); - m_pd3dDevice->GetDisplayMode(0, &Mode); - if (SUCCEEDED(m_pd3dDevice->GetRenderTarget(0, &pSurf))) { - pSurf->GetDesc(&Desc); - if (FAILED(pd3d9->CheckDeviceFormat(Caps.AdapterOrdinal, Caps.DeviceType, Mode.Format, - D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_SURFACE, - Desc.Format))) { - bSupportsAlphaBlend = false; - } - SAFE_RELEASE(pSurf); - } - SAFE_RELEASE(pd3d9); - } - - // Create the state blocks for rendering text - for (UINT which = 0; which < 2; which++) { - m_pd3dDevice->BeginStateBlock(); - m_pd3dDevice->SetTexture(0, m_pTexture); - - if (D3DFONT_ZENABLE & m_dwFontFlags) { - m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE); - } else { - m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); - } - - if (bSupportsAlphaBlend) { - m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - } else { - m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - } - m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); - m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x08); - m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); - m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); - m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); - m_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); - m_pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE); - m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE); - m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); - m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); - m_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); - m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, - D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | - D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); - m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); - m_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - if (which == 0) { - m_pd3dDevice->EndStateBlock(&m_pStateBlockSaved); - } else { - m_pd3dDevice->EndStateBlock(&m_pStateBlockDrawText); - } - } - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: InvalidateDeviceObjects() -// Desc: Destroys all device-dependent objects -//----------------------------------------------------------------------------- -HRESULT CD3DFont::InvalidateDeviceObjects() -{ - SAFE_RELEASE(m_pVB); - SAFE_RELEASE(m_pStateBlockSaved); - SAFE_RELEASE(m_pStateBlockDrawText); - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: DeleteDeviceObjects() -// Desc: Destroys all device-dependent objects -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DeleteDeviceObjects() -{ - SAFE_RELEASE(m_pTexture); - m_pd3dDevice = nullptr; - - return S_OK; -} - - - -//----------------------------------------------------------------------------- -// Name: GetTextExtent() -// Desc: Get the dimensions of a text string -//----------------------------------------------------------------------------- -HRESULT CD3DFont::GetTextExtent(const TCHAR* strText, SIZE* pSize) -{ - if (nullptr == strText || nullptr == pSize) { - return E_FAIL; - } - - float fRowWidth = 0.0f; - float fRowHeight = (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; - float fWidth = 0.0f; - float fHeight = fRowHeight; - - while (*strText) { - TCHAR c = *strText++; - - if (c == _T('\n')) { - fRowWidth = 0.0f; - fHeight += fRowHeight; - } - - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float tx2 = m_fTexCoords[c - 32][2]; - - fRowWidth += (tx2 - tx1) * m_dwTexWidth - 2 * m_dwSpacing; - - if (fRowWidth > fWidth) { - fWidth = fRowWidth; - } - } - - pSize->cx = (int)fWidth; - pSize->cy = (int)fHeight; - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: DrawTextScaled() -// Desc: Draws scaled 2D text. Note that x and y are in viewport coordinates -// (ranging from -1 to +1). fXScale and fYScale are the size fraction -// relative to the entire viewport. For example, a fXScale of 0.25 is -// 1/8th of the screen width. This allows you to output text at a fixed -// fraction of the viewport, even if the screen or window size changes. -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DrawTextScaled(float x, float y, float z, - float fXScale, float fYScale, DWORD dwColor, - const TCHAR* strText, DWORD dwFlags) -{ - if (m_pd3dDevice == nullptr) { - return E_FAIL; - } - - // Set up renderstate - m_pStateBlockSaved->Capture(); - m_pStateBlockDrawText->Apply(); - m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX); - m_pd3dDevice->SetPixelShader(nullptr); - m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); - - // Set filter states - if (dwFlags & D3DFONT_FILTERED) { - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - } - - D3DVIEWPORT9 vp; - m_pd3dDevice->GetViewport(&vp); - float fLineHeight = (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; - - // Center the text block in the viewport - if (dwFlags & D3DFONT_CENTERED_X) { - const TCHAR* strTextTmp = strText; - float xFinal = 0.0f; - - while (*strTextTmp) { - TCHAR c = *strTextTmp++; - - if (c == _T('\n')) { - break; // Isn't supported. - } - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float tx2 = m_fTexCoords[c - 32][2]; - - float w = (tx2 - tx1) * m_dwTexWidth; - - w *= (fXScale * vp.Height) / fLineHeight; - - xFinal += w - (2 * m_dwSpacing) * (fXScale * vp.Height) / fLineHeight; - } - - x = -xFinal / vp.Width; - } - if (dwFlags & D3DFONT_CENTERED_Y) { - y = -fLineHeight / vp.Height; - } - - float sx = (x + 1.0f) * vp.Width / 2; - float sy = (y + 1.0f) * vp.Height / 2; - float sz = z; - float rhw = 1.0f; - - // Adjust for character spacing - sx -= m_dwSpacing * (fXScale * vp.Height) / fLineHeight; - float fStartX = sx; - - // Fill vertex buffer - FONT2DVERTEX* pVertices; - DWORD dwNumTriangles = 0L; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - - while (*strText) { - TCHAR c = *strText++; - - if (c == _T('\n')) { - sx = fStartX; - sy += fYScale * vp.Height; - } - - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float ty1 = m_fTexCoords[c - 32][1]; - float tx2 = m_fTexCoords[c - 32][2]; - float ty2 = m_fTexCoords[c - 32][3]; - - float w = (tx2 - tx1) * m_dwTexWidth; - float h = (ty2 - ty1) * m_dwTexHeight; - - w *= (fXScale * vp.Height) / fLineHeight; - h *= (fYScale * vp.Height) / fLineHeight; - - if (c != _T(' ')) { - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx1, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx1, ty1); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx2, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx2, ty1); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx2, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx1, ty1); - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - dwNumTriangles = 0L; - } - } - - sx += w - (2 * m_dwSpacing) * (fXScale * vp.Height) / fLineHeight; - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if (dwNumTriangles > 0) { - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - } - - // Restore the modified renderstates - m_pStateBlockSaved->Apply(); - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: DrawText() -// Desc: Draws 2D text. Note that sx and sy are in pixels -//----------------------------------------------------------------------------- -HRESULT CD3DFont::DrawText(float sx, float sy, DWORD dwColor, - const TCHAR* strText, DWORD dwFlags) -{ - if (m_pd3dDevice == nullptr) { - return E_FAIL; - } - - // Setup renderstate - m_pStateBlockSaved->Capture(); - m_pStateBlockDrawText->Apply(); - m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX); - m_pd3dDevice->SetPixelShader(nullptr); - m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); - - // Set filter states - if (dwFlags & D3DFONT_FILTERED) { - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - } - - // Center the text block in the viewport - if (dwFlags & D3DFONT_CENTERED_X) { - D3DVIEWPORT9 vp; - m_pd3dDevice->GetViewport(&vp); - const TCHAR* strTextTmp = strText; - float xFinal = 0.0f; - - while (*strTextTmp) { - TCHAR c = *strTextTmp++; - - if (c == _T('\n')) { - break; // Isn't supported. - } - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float tx2 = m_fTexCoords[c - 32][2]; - - float w = (tx2 - tx1) * m_dwTexWidth / m_fTextScale; - - xFinal += w - (2 * m_dwSpacing); - } - - sx = (vp.Width - xFinal) / 2.0f; - } - if (dwFlags & D3DFONT_CENTERED_Y) { - D3DVIEWPORT9 vp; - m_pd3dDevice->GetViewport(&vp); - float fLineHeight = ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight); - sy = (vp.Height - fLineHeight) / 2; - } - - // Adjust for character spacing - sx -= m_dwSpacing; - float fStartX = sx; - - // Fill vertex buffer - FONT2DVERTEX* pVertices = nullptr; - DWORD dwNumTriangles = 0; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - - while (*strText) { - TCHAR c = *strText++; - - if (c == _T('\n')) { - sx = fStartX; - sy += (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; - } - - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float ty1 = m_fTexCoords[c - 32][1]; - float tx2 = m_fTexCoords[c - 32][2]; - float ty2 = m_fTexCoords[c - 32][3]; - - float w = (tx2 - tx1) * m_dwTexWidth / m_fTextScale; - float h = (ty2 - ty1) * m_dwTexHeight / m_fTextScale; - - if (c != _T(' ')) { - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty1); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty1); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty2); - *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty1); - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - pVertices = nullptr; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - dwNumTriangles = 0L; - } - } - - sx += w - (2 * m_dwSpacing); - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if (dwNumTriangles > 0) { - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - } - - // Restore the modified renderstates - m_pStateBlockSaved->Apply(); - - return S_OK; -} - - -//----------------------------------------------------------------------------- -// Name: Render3DText() -// Desc: Renders 3D text -//----------------------------------------------------------------------------- -HRESULT CD3DFont::Render3DText(const TCHAR* strText, DWORD dwFlags) -{ - if (m_pd3dDevice == nullptr) { - return E_FAIL; - } - - // Setup renderstate - m_pStateBlockSaved->Capture(); - m_pStateBlockDrawText->Apply(); - m_pd3dDevice->SetFVF(D3DFVF_FONT3DVERTEX); - m_pd3dDevice->SetPixelShader(nullptr); - m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT3DVERTEX)); - - // Set filter states - if (dwFlags & D3DFONT_FILTERED) { - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - } - - // Position for each text element - float x = 0.0f; - float y = 0.0f; - - // Center the text block at the origin (not the viewport) - if (dwFlags & D3DFONT_CENTERED_X) { - SIZE sz; - GetTextExtent(strText, &sz); - x = -(((float)sz.cx) / 10.0f) / 2.0f; - } - if (dwFlags & D3DFONT_CENTERED_Y) { - SIZE sz; - GetTextExtent(strText, &sz); - y = -(((float)sz.cy) / 10.0f) / 2.0f; - } - - // Turn off culling for two-sided text - if (dwFlags & D3DFONT_TWOSIDED) { - m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - } - - // Adjust for character spacing - x -= m_dwSpacing / 10.0f; - float fStartX = x; - TCHAR c; - - // Fill vertex buffer - FONT3DVERTEX* pVertices; - DWORD dwNumTriangles = 0L; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - - while ((c = *strText++) != 0) { - if (c == '\n') { - x = fStartX; - y -= (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight / 10.0f; - } - - if ((c - 32) < 0 || (c - 32) >= 128 - 32) { - continue; - } - - float tx1 = m_fTexCoords[c - 32][0]; - float ty1 = m_fTexCoords[c - 32][1]; - float tx2 = m_fTexCoords[c - 32][2]; - float ty2 = m_fTexCoords[c - 32][3]; - - float w = (tx2 - tx1) * m_dwTexWidth / (10.0f * m_fTextScale); - float h = (ty2 - ty1) * m_dwTexHeight / (10.0f * m_fTextScale); - - if (c != _T(' ')) { - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx1, ty2); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + h, 0), D3DXVECTOR3(0, 0, -1), tx1, ty1); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx2, ty2); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + h, 0), D3DXVECTOR3(0, 0, -1), tx2, ty1); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx2, ty2); - *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + h, 0), D3DXVECTOR3(0, 0, -1), tx1, ty1); - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - dwNumTriangles = 0L; - } - } - - x += w - (2 * m_dwSpacing) / 10.0f; - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if (dwNumTriangles > 0) { - m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - } - - // Restore the modified renderstates - m_pStateBlockSaved->Apply(); - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include +#include +#include "d3dx9/d3dx9.h" +#include "D3DFont.h" +#include "../../../DSUtil/DSUtil.h" + +//----------------------------------------------------------------------------- +// Custom vertex types for rendering text +//----------------------------------------------------------------------------- +#define MAX_NUM_VERTICES 50 * 6 + +struct FONT2DVERTEX { + D3DXVECTOR4 p; + DWORD color; + float tu, tv; +}; + +struct FONT3DVERTEX { + D3DXVECTOR3 p; + D3DXVECTOR3 n; + float tu, tv; +}; + +#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1) +#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1) + + +inline FONT2DVERTEX InitFont2DVertex(const D3DXVECTOR4& p, D3DCOLOR color, + float tu, float tv) +{ + FONT2DVERTEX v; + v.p = p; + v.color = color; + v.tu = tu; + v.tv = tv; + return v; +} + +inline FONT3DVERTEX InitFont3DVertex(const D3DXVECTOR3& p, const D3DXVECTOR3& n, + float tu, float tv) +{ + FONT3DVERTEX v; + v.p = p; + v.n = n; + v.tu = tu; + v.tv = tv; + return v; +} + + + +//----------------------------------------------------------------------------- +// Name: CD3DFont() +// Desc: Font class constructor +//----------------------------------------------------------------------------- +CD3DFont::CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags) +{ + _tcsncpy_s(m_strFontName, strFontName, _countof(m_strFontName)); + m_strFontName[_countof(m_strFontName) - 1] = _T('\0'); + m_dwFontHeight = dwHeight; + m_dwFontFlags = dwFlags; + m_dwSpacing = 0; + m_dwTexWidth = 0; + m_dwTexHeight = 0; + m_fTextScale = 0.0f; + ZeroMemory(m_fTexCoords, sizeof(m_fTexCoords)); + + m_pd3dDevice = nullptr; + m_pTexture = nullptr; + m_pVB = nullptr; + + m_pStateBlockSaved = nullptr; + m_pStateBlockDrawText = nullptr; +} + + + +//----------------------------------------------------------------------------- +// Name: ~CD3DFont() +// Desc: Font class destructor +//----------------------------------------------------------------------------- +CD3DFont::~CD3DFont() +{ + InvalidateDeviceObjects(); + DeleteDeviceObjects(); +} + + + +//----------------------------------------------------------------------------- +// Name: CreateGDIFont +// Desc: Create a font based on the current state of related member variables +// and return the handle (or null on error) +//----------------------------------------------------------------------------- +HRESULT CD3DFont::CreateGDIFont(HDC hDC, HFONT* pFont) +{ + // Create a font. By specifying ANTIALIASED_QUALITY, we might get an + // antialiased font, but this is not guaranteed. + int nHeight = -MulDiv(m_dwFontHeight, + (int)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), + 72); + DWORD dwBold = (m_dwFontFlags & D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL; + DWORD dwItalic = (m_dwFontFlags & D3DFONT_ITALIC) ? TRUE : FALSE; + *pFont = CreateFont(nHeight, 0, 0, 0, dwBold, dwItalic, + FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, + VARIABLE_PITCH, m_strFontName); + + if (*pFont == nullptr) { + return E_FAIL; + } + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: PaintAlphabet +// Desc: Paint the printable characters for the given GDI font onto the +// provided device context. If the bMeasureOnly flag is set, no drawing +// will occur. +//----------------------------------------------------------------------------- +HRESULT CD3DFont::PaintAlphabet(HDC hDC, BOOL bMeasureOnly) +{ + SIZE size; + TCHAR str[2] = _T("x"); // One-character, null-terminated string + + // Calculate the spacing between characters based on line height + if (0 == GetTextExtentPoint32(hDC, str, 1, &size)) { + return E_FAIL; + } + m_dwSpacing = (DWORD) ceil(size.cy * 0.3f); + + // Set the starting point for the drawing + DWORD x = m_dwSpacing; + DWORD y = 0; + + // For each character, draw text on the DC and advance the current position + for (char c = 32; c < 127; c++) { + str[0] = c; + if (0 == GetTextExtentPoint32(hDC, str, 1, &size)) { + return E_FAIL; + } + + if ((DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth) { + x = m_dwSpacing; + y += size.cy + 1; + } + + // Check to see if there's room to write the character here + if (y + size.cy > m_dwTexHeight) { + return D3DERR_MOREDATA; + } + + if (!bMeasureOnly) { + // Perform the actual drawing + if (0 == ExtTextOut(hDC, x + 0, y + 0, ETO_OPAQUE, nullptr, str, 1, nullptr)) { + return E_FAIL; + } + + m_fTexCoords[c - 32][0] = ((float)(x + 0 - m_dwSpacing)) / m_dwTexWidth; + m_fTexCoords[c - 32][1] = ((float)(y + 0 + 0)) / m_dwTexHeight; + m_fTexCoords[c - 32][2] = ((float)(x + size.cx + m_dwSpacing)) / m_dwTexWidth; + m_fTexCoords[c - 32][3] = ((float)(y + size.cy + 0)) / m_dwTexHeight; + } + + x += size.cx + (2 * m_dwSpacing); + } + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: InitDeviceObjects() +// Desc: Initializes device-dependent objects, including the vertex buffer used +// for rendering text and the texture map which stores the font image. +//----------------------------------------------------------------------------- +HRESULT CD3DFont::InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice) +{ + HRESULT hr; + HFONT hFont = nullptr; + HFONT hFontOld = nullptr; + HDC hDC = nullptr; + HBITMAP hbmBitmap = nullptr; + HGDIOBJ hbmOld = nullptr; + + // Keep a local copy of the device + m_pd3dDevice = pd3dDevice; + + // Assume we will draw fonts into texture without scaling unless the + // required texture size is found to be larger than the device max + m_fTextScale = 1.0f; + + hDC = CreateCompatibleDC(nullptr); + SetMapMode(hDC, MM_TEXT); + + hr = CreateGDIFont(hDC, &hFont); + if (FAILED(hr)) { + goto LCleanReturn; + } + + hFontOld = (HFONT) SelectObject(hDC, hFont); + + // Calculate the dimensions for the smallest power-of-two texture which + // can hold all the printable characters + m_dwTexWidth = m_dwTexHeight = 128; + while (D3DERR_MOREDATA == (hr = PaintAlphabet(hDC, true))) { + m_dwTexWidth *= 2; + m_dwTexHeight *= 2; + } + + if (FAILED(hr)) { + goto LCleanReturn; + } + + // If requested texture is too big, use a smaller texture and smaller font, + // and scale up when rendering. + D3DCAPS9 d3dCaps; + m_pd3dDevice->GetDeviceCaps(&d3dCaps); + + if (m_dwTexWidth > d3dCaps.MaxTextureWidth) { + m_fTextScale = (float)d3dCaps.MaxTextureWidth / (float)m_dwTexWidth; + m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth; + + bool bFirstRun = true; // Flag clear after first run + + do { + // If we've already tried fitting the new text, the scale is still + // too large. Reduce and try again. + if (!bFirstRun) { + m_fTextScale *= 0.9f; + } + + // The font has to be scaled to fit on the maximum texture size; our + // current font is too big and needs to be recreated to scale. + DeleteObject(SelectObject(hDC, hFontOld)); + + hr = CreateGDIFont(hDC, &hFont); + if (FAILED(hr)) { + goto LCleanReturn; + } + + hFontOld = (HFONT) SelectObject(hDC, hFont); + + bFirstRun = false; + } while (D3DERR_MOREDATA == (hr = PaintAlphabet(hDC, true))); + } + + + // Create a new texture for the font + hr = m_pd3dDevice->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, + 0, D3DFMT_A4R4G4B4, + D3DPOOL_MANAGED, &m_pTexture, nullptr); + if (FAILED(hr)) { + goto LCleanReturn; + } + + // Prepare to create a bitmap + DWORD* pBitmapBits; + BITMAPINFO bmi; + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = (int)m_dwTexWidth; + bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biBitCount = 32; + + // Create a bitmap for the font + hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, + (void**)&pBitmapBits, nullptr, 0); + + hbmOld = SelectObject(hDC, hbmBitmap); + + // Set text properties + SetTextColor(hDC, RGB(255, 255, 255)); + SetBkColor(hDC, 0x00000000); + SetTextAlign(hDC, TA_TOP); + + // Paint the alphabet onto the selected bitmap + hr = PaintAlphabet(hDC, false); + if (FAILED(hr)) { + goto LCleanReturn; + } + + // Lock the surface and write the alpha values for the set pixels + D3DLOCKED_RECT d3dlr; + m_pTexture->LockRect(0, &d3dlr, 0, 0); + BYTE* pDstRow = (BYTE*)d3dlr.pBits; + for (DWORD y = 0; y < m_dwTexHeight; y++) { + WORD* pDst16 = (WORD*)pDstRow; + for (DWORD x = 0; x < m_dwTexWidth; x++) { + // 4-bit measure of pixel intensity + BYTE bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4); + if (bAlpha > 0) { + *pDst16++ = (WORD)((bAlpha << 12) | 0x0fff); + } else { + *pDst16++ = 0x0000; + } + } + pDstRow += d3dlr.Pitch; + } + + hr = S_OK; + + // Done updating texture, so clean up used objects +LCleanReturn: + if (m_pTexture) { + m_pTexture->UnlockRect(0); + } + + SelectObject(hDC, hbmOld); + SelectObject(hDC, hFontOld); + DeleteObject(hbmBitmap); + DeleteObject(hFont); + DeleteDC(hDC); + + return hr; +} + + +//----------------------------------------------------------------------------- +// Name: RestoreDeviceObjects() +// Desc: +//----------------------------------------------------------------------------- +HRESULT CD3DFont::RestoreDeviceObjects() +{ + HRESULT hr; + + // Create vertex buffer for the letters + UINT vertexSize = std::max(sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX)); + if (FAILED(hr = m_pd3dDevice->CreateVertexBuffer(MAX_NUM_VERTICES * vertexSize, + D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, + D3DPOOL_DEFAULT, &m_pVB, nullptr))) { + return hr; + } + + bool bSupportsAlphaBlend = true; + LPDIRECT3D9 pd3d9 = nullptr; + if (SUCCEEDED(m_pd3dDevice->GetDirect3D(&pd3d9))) { + D3DCAPS9 Caps; + D3DDISPLAYMODE Mode; + LPDIRECT3DSURFACE9 pSurf = nullptr; + D3DSURFACE_DESC Desc; + m_pd3dDevice->GetDeviceCaps(&Caps); + m_pd3dDevice->GetDisplayMode(0, &Mode); + if (SUCCEEDED(m_pd3dDevice->GetRenderTarget(0, &pSurf))) { + pSurf->GetDesc(&Desc); + if (FAILED(pd3d9->CheckDeviceFormat(Caps.AdapterOrdinal, Caps.DeviceType, Mode.Format, + D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_SURFACE, + Desc.Format))) { + bSupportsAlphaBlend = false; + } + SAFE_RELEASE(pSurf); + } + SAFE_RELEASE(pd3d9); + } + + // Create the state blocks for rendering text + for (UINT which = 0; which < 2; which++) { + m_pd3dDevice->BeginStateBlock(); + m_pd3dDevice->SetTexture(0, m_pTexture); + + if (D3DFONT_ZENABLE & m_dwFontFlags) { + m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + } else { + m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + } + + if (bSupportsAlphaBlend) { + m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + } else { + m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x08); + m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); + m_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + m_pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE); + m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); + m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); + m_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, + D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | + D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); + m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + m_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + if (which == 0) { + m_pd3dDevice->EndStateBlock(&m_pStateBlockSaved); + } else { + m_pd3dDevice->EndStateBlock(&m_pStateBlockDrawText); + } + } + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: InvalidateDeviceObjects() +// Desc: Destroys all device-dependent objects +//----------------------------------------------------------------------------- +HRESULT CD3DFont::InvalidateDeviceObjects() +{ + SAFE_RELEASE(m_pVB); + SAFE_RELEASE(m_pStateBlockSaved); + SAFE_RELEASE(m_pStateBlockDrawText); + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: DeleteDeviceObjects() +// Desc: Destroys all device-dependent objects +//----------------------------------------------------------------------------- +HRESULT CD3DFont::DeleteDeviceObjects() +{ + SAFE_RELEASE(m_pTexture); + m_pd3dDevice = nullptr; + + return S_OK; +} + + + +//----------------------------------------------------------------------------- +// Name: GetTextExtent() +// Desc: Get the dimensions of a text string +//----------------------------------------------------------------------------- +HRESULT CD3DFont::GetTextExtent(const TCHAR* strText, SIZE* pSize) +{ + if (nullptr == strText || nullptr == pSize) { + return E_FAIL; + } + + float fRowWidth = 0.0f; + float fRowHeight = (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; + float fWidth = 0.0f; + float fHeight = fRowHeight; + + while (*strText) { + TCHAR c = *strText++; + + if (c == _T('\n')) { + fRowWidth = 0.0f; + fHeight += fRowHeight; + } + + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float tx2 = m_fTexCoords[c - 32][2]; + + fRowWidth += (tx2 - tx1) * m_dwTexWidth - 2 * m_dwSpacing; + + if (fRowWidth > fWidth) { + fWidth = fRowWidth; + } + } + + pSize->cx = (int)fWidth; + pSize->cy = (int)fHeight; + + return S_OK; +} + + +//----------------------------------------------------------------------------- +// Name: DrawTextScaled() +// Desc: Draws scaled 2D text. Note that x and y are in viewport coordinates +// (ranging from -1 to +1). fXScale and fYScale are the size fraction +// relative to the entire viewport. For example, a fXScale of 0.25 is +// 1/8th of the screen width. This allows you to output text at a fixed +// fraction of the viewport, even if the screen or window size changes. +//----------------------------------------------------------------------------- +HRESULT CD3DFont::DrawTextScaled(float x, float y, float z, + float fXScale, float fYScale, DWORD dwColor, + const TCHAR* strText, DWORD dwFlags) +{ + if (m_pd3dDevice == nullptr) { + return E_FAIL; + } + + // Set up renderstate + m_pStateBlockSaved->Capture(); + m_pStateBlockDrawText->Apply(); + m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX); + m_pd3dDevice->SetPixelShader(nullptr); + m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); + + // Set filter states + if (dwFlags & D3DFONT_FILTERED) { + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + + D3DVIEWPORT9 vp; + m_pd3dDevice->GetViewport(&vp); + float fLineHeight = (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; + + // Center the text block in the viewport + if (dwFlags & D3DFONT_CENTERED_X) { + const TCHAR* strTextTmp = strText; + float xFinal = 0.0f; + + while (*strTextTmp) { + TCHAR c = *strTextTmp++; + + if (c == _T('\n')) { + break; // Isn't supported. + } + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float tx2 = m_fTexCoords[c - 32][2]; + + float w = (tx2 - tx1) * m_dwTexWidth; + + w *= (fXScale * vp.Height) / fLineHeight; + + xFinal += w - (2 * m_dwSpacing) * (fXScale * vp.Height) / fLineHeight; + } + + x = -xFinal / vp.Width; + } + if (dwFlags & D3DFONT_CENTERED_Y) { + y = -fLineHeight / vp.Height; + } + + float sx = (x + 1.0f) * vp.Width / 2; + float sy = (y + 1.0f) * vp.Height / 2; + float sz = z; + float rhw = 1.0f; + + // Adjust for character spacing + sx -= m_dwSpacing * (fXScale * vp.Height) / fLineHeight; + float fStartX = sx; + + // Fill vertex buffer + FONT2DVERTEX* pVertices; + DWORD dwNumTriangles = 0L; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + + while (*strText) { + TCHAR c = *strText++; + + if (c == _T('\n')) { + sx = fStartX; + sy += fYScale * vp.Height; + } + + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float ty1 = m_fTexCoords[c - 32][1]; + float tx2 = m_fTexCoords[c - 32][2]; + float ty2 = m_fTexCoords[c - 32][3]; + + float w = (tx2 - tx1) * m_dwTexWidth; + float h = (ty2 - ty1) * m_dwTexHeight; + + w *= (fXScale * vp.Height) / fLineHeight; + h *= (fYScale * vp.Height) / fLineHeight; + + if (c != _T(' ')) { + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx1, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx1, ty1); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx2, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx2, ty1); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, sz, rhw), dwColor, tx2, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw), dwColor, tx1, ty1); + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { + // Unlock, render, and relock the vertex buffer + m_pVB->Unlock(); + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + dwNumTriangles = 0L; + } + } + + sx += w - (2 * m_dwSpacing) * (fXScale * vp.Height) / fLineHeight; + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if (dwNumTriangles > 0) { + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + } + + // Restore the modified renderstates + m_pStateBlockSaved->Apply(); + + return S_OK; +} + + +//----------------------------------------------------------------------------- +// Name: DrawText() +// Desc: Draws 2D text. Note that sx and sy are in pixels +//----------------------------------------------------------------------------- +HRESULT CD3DFont::DrawText(float sx, float sy, DWORD dwColor, + const TCHAR* strText, DWORD dwFlags) +{ + if (m_pd3dDevice == nullptr) { + return E_FAIL; + } + + // Setup renderstate + m_pStateBlockSaved->Capture(); + m_pStateBlockDrawText->Apply(); + m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX); + m_pd3dDevice->SetPixelShader(nullptr); + m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); + + // Set filter states + if (dwFlags & D3DFONT_FILTERED) { + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + + // Center the text block in the viewport + if (dwFlags & D3DFONT_CENTERED_X) { + D3DVIEWPORT9 vp; + m_pd3dDevice->GetViewport(&vp); + const TCHAR* strTextTmp = strText; + float xFinal = 0.0f; + + while (*strTextTmp) { + TCHAR c = *strTextTmp++; + + if (c == _T('\n')) { + break; // Isn't supported. + } + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float tx2 = m_fTexCoords[c - 32][2]; + + float w = (tx2 - tx1) * m_dwTexWidth / m_fTextScale; + + xFinal += w - (2 * m_dwSpacing); + } + + sx = (vp.Width - xFinal) / 2.0f; + } + if (dwFlags & D3DFONT_CENTERED_Y) { + D3DVIEWPORT9 vp; + m_pd3dDevice->GetViewport(&vp); + float fLineHeight = ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight); + sy = (vp.Height - fLineHeight) / 2; + } + + // Adjust for character spacing + sx -= m_dwSpacing; + float fStartX = sx; + + // Fill vertex buffer + FONT2DVERTEX* pVertices = nullptr; + DWORD dwNumTriangles = 0; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + + while (*strText) { + TCHAR c = *strText++; + + if (c == _T('\n')) { + sx = fStartX; + sy += (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight; + } + + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float ty1 = m_fTexCoords[c - 32][1]; + float tx2 = m_fTexCoords[c - 32][2]; + float ty2 = m_fTexCoords[c - 32][3]; + + float w = (tx2 - tx1) * m_dwTexWidth / m_fTextScale; + float h = (ty2 - ty1) * m_dwTexHeight / m_fTextScale; + + if (c != _T(' ')) { + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty1); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty1); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f), dwColor, tx2, ty2); + *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f), dwColor, tx1, ty1); + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { + // Unlock, render, and relock the vertex buffer + m_pVB->Unlock(); + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + pVertices = nullptr; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + dwNumTriangles = 0L; + } + } + + sx += w - (2 * m_dwSpacing); + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if (dwNumTriangles > 0) { + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + } + + // Restore the modified renderstates + m_pStateBlockSaved->Apply(); + + return S_OK; +} + + +//----------------------------------------------------------------------------- +// Name: Render3DText() +// Desc: Renders 3D text +//----------------------------------------------------------------------------- +HRESULT CD3DFont::Render3DText(const TCHAR* strText, DWORD dwFlags) +{ + if (m_pd3dDevice == nullptr) { + return E_FAIL; + } + + // Setup renderstate + m_pStateBlockSaved->Capture(); + m_pStateBlockDrawText->Apply(); + m_pd3dDevice->SetFVF(D3DFVF_FONT3DVERTEX); + m_pd3dDevice->SetPixelShader(nullptr); + m_pd3dDevice->SetStreamSource(0, m_pVB, 0, sizeof(FONT3DVERTEX)); + + // Set filter states + if (dwFlags & D3DFONT_FILTERED) { + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + } + + // Position for each text element + float x = 0.0f; + float y = 0.0f; + + // Center the text block at the origin (not the viewport) + if (dwFlags & D3DFONT_CENTERED_X) { + SIZE sz; + GetTextExtent(strText, &sz); + x = -(((float)sz.cx) / 10.0f) / 2.0f; + } + if (dwFlags & D3DFONT_CENTERED_Y) { + SIZE sz; + GetTextExtent(strText, &sz); + y = -(((float)sz.cy) / 10.0f) / 2.0f; + } + + // Turn off culling for two-sided text + if (dwFlags & D3DFONT_TWOSIDED) { + m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + // Adjust for character spacing + x -= m_dwSpacing / 10.0f; + float fStartX = x; + TCHAR c; + + // Fill vertex buffer + FONT3DVERTEX* pVertices; + DWORD dwNumTriangles = 0L; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + + while ((c = *strText++) != 0) { + if (c == '\n') { + x = fStartX; + y -= (m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight / 10.0f; + } + + if ((c - 32) < 0 || (c - 32) >= 128 - 32) { + continue; + } + + float tx1 = m_fTexCoords[c - 32][0]; + float ty1 = m_fTexCoords[c - 32][1]; + float tx2 = m_fTexCoords[c - 32][2]; + float ty2 = m_fTexCoords[c - 32][3]; + + float w = (tx2 - tx1) * m_dwTexWidth / (10.0f * m_fTextScale); + float h = (ty2 - ty1) * m_dwTexHeight / (10.0f * m_fTextScale); + + if (c != _T(' ')) { + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx1, ty2); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + h, 0), D3DXVECTOR3(0, 0, -1), tx1, ty1); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx2, ty2); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + h, 0), D3DXVECTOR3(0, 0, -1), tx2, ty1); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + w, y + 0, 0), D3DXVECTOR3(0, 0, -1), tx2, ty2); + *pVertices++ = InitFont3DVertex(D3DXVECTOR3(x + 0, y + h, 0), D3DXVECTOR3(0, 0, -1), tx1, ty1); + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { + // Unlock, render, and relock the vertex buffer + m_pVB->Unlock(); + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + dwNumTriangles = 0L; + } + } + + x += w - (2 * m_dwSpacing) / 10.0f; + } + + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if (dwNumTriangles > 0) { + m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + } + + // Restore the modified renderstates + m_pStateBlockSaved->Apply(); + + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/D3DFont.h b/src/filters/renderer/VideoRenderers/D3DFont.h index f5fdd129a6c..24f00bd7f11 100644 --- a/src/filters/renderer/VideoRenderers/D3DFont.h +++ b/src/filters/renderer/VideoRenderers/D3DFont.h @@ -1,78 +1,78 @@ -/* - * (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 . - * - */ - -#pragma once - -// Font creation flags -#define D3DFONT_BOLD 0x0001 -#define D3DFONT_ITALIC 0x0002 -#define D3DFONT_ZENABLE 0x0004 - -// Font rendering flags -#define D3DFONT_CENTERED_X 0x0001 -#define D3DFONT_CENTERED_Y 0x0002 -#define D3DFONT_TWOSIDED 0x0004 -#define D3DFONT_FILTERED 0x0008 - - -class CD3DFont -{ - TCHAR m_strFontName[80]; // Font properties - DWORD m_dwFontHeight; - DWORD m_dwFontFlags; - - LPDIRECT3DDEVICE9 m_pd3dDevice; // A D3DDevice used for rendering - LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font - LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text - DWORD m_dwTexWidth; // Texture dimensions - DWORD m_dwTexHeight; - float m_fTextScale; - float m_fTexCoords[128 - 32][4]; - DWORD m_dwSpacing; // Character pixel spacing per side - - // Stateblocks for setting and restoring render states - LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved; - LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText; - - HRESULT CreateGDIFont(HDC hDC, HFONT* pFont); - HRESULT PaintAlphabet(HDC hDC, BOOL bMeasureOnly = FALSE); - -public: - // 2D and 3D text drawing functions - HRESULT DrawText(float x, float y, DWORD dwColor, const TCHAR* strText, DWORD dwFlags = 0L); - HRESULT DrawTextScaled(float x, float y, float z, - float fXScale, float fYScale, DWORD dwColor, - const TCHAR* strText, DWORD dwFlags = 0L); - HRESULT Render3DText(const TCHAR* strText, DWORD dwFlags = 0L); - - // Function to get extent of text - HRESULT GetTextExtent(const TCHAR* strText, SIZE* pSize); - - // Initializing and destroying device-dependent objects - HRESULT InitDeviceObjects(IDirect3DDevice9* pd3dDevice); - HRESULT RestoreDeviceObjects(); - HRESULT InvalidateDeviceObjects(); - HRESULT DeleteDeviceObjects(); - - // Constructor / destructor - CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags = 0L); - ~CD3DFont(); -}; +/* + * (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 . + * + */ + +#pragma once + +// Font creation flags +#define D3DFONT_BOLD 0x0001 +#define D3DFONT_ITALIC 0x0002 +#define D3DFONT_ZENABLE 0x0004 + +// Font rendering flags +#define D3DFONT_CENTERED_X 0x0001 +#define D3DFONT_CENTERED_Y 0x0002 +#define D3DFONT_TWOSIDED 0x0004 +#define D3DFONT_FILTERED 0x0008 + + +class CD3DFont +{ + TCHAR m_strFontName[80]; // Font properties + DWORD m_dwFontHeight; + DWORD m_dwFontFlags; + + LPDIRECT3DDEVICE9 m_pd3dDevice; // A D3DDevice used for rendering + LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font + LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text + DWORD m_dwTexWidth; // Texture dimensions + DWORD m_dwTexHeight; + float m_fTextScale; + float m_fTexCoords[128 - 32][4]; + DWORD m_dwSpacing; // Character pixel spacing per side + + // Stateblocks for setting and restoring render states + LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved; + LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText; + + HRESULT CreateGDIFont(HDC hDC, HFONT* pFont); + HRESULT PaintAlphabet(HDC hDC, BOOL bMeasureOnly = FALSE); + +public: + // 2D and 3D text drawing functions + HRESULT DrawText(float x, float y, DWORD dwColor, const TCHAR* strText, DWORD dwFlags = 0L); + HRESULT DrawTextScaled(float x, float y, float z, + float fXScale, float fYScale, DWORD dwColor, + const TCHAR* strText, DWORD dwFlags = 0L); + HRESULT Render3DText(const TCHAR* strText, DWORD dwFlags = 0L); + + // Function to get extent of text + HRESULT GetTextExtent(const TCHAR* strText, SIZE* pSize); + + // Initializing and destroying device-dependent objects + HRESULT InitDeviceObjects(IDirect3DDevice9* pd3dDevice); + HRESULT RestoreDeviceObjects(); + HRESULT InvalidateDeviceObjects(); + HRESULT DeleteDeviceObjects(); + + // Constructor / destructor + CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags = 0L); + ~CD3DFont(); +}; diff --git a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp index 125637771d8..74124737945 100644 --- a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp @@ -1,2309 +1,2309 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "RenderersSettings.h" -#include "DX9AllocatorPresenter.h" -#include -#include "../../../SubPic/DX9SubPic.h" -#include "../../../SubPic/SubPicQueueImpl.h" -#include "IPinHook.h" -#include "FocusThread.h" -#include "../../../DSUtil/vd.h" -#include - -#define FRAMERATE_MAX_DELTA 3000 - -#define REFERENCE_WIDTH 1920 -#define FONT_HEIGHT 21 -#define BOLD_THRESHOLD 11 -#define TEXT_PADDING 2 -#define GRAPH_HEIGHT 360 -#define GRAPH_WIDTH 1000 - -using namespace DSObjects; - -#pragma warning(push) -#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized -// CDX9AllocatorPresenter -CDX9AllocatorPresenter::CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString& _Error, bool isPreview) - : CDX9RenderingEngine(hWnd, hr, &_Error) - , m_bAlternativeVSync(false) - , m_bCompositionEnabled(false) - , m_bIsEVR(bIsEVR) - , m_OrderedPaint(0) - , m_VSyncMode(0) - , m_bDesktopCompositionDisabled(false) - , m_bIsFullscreen(bFullscreen) - , fullScreenChanged(false) - , m_bNeedCheckSample(true) - , m_MainThreadId(0) - , m_bIsRendering(false) - , m_hDWMAPI(nullptr) - , m_pDwmIsCompositionEnabled(nullptr) - , m_pDwmEnableComposition(nullptr) - , m_pDirectDraw(nullptr) - , m_LastAdapterCheck(0) - , m_nTearingPos(0) - , m_VMR9AlphaBitmapWidthBytes(0) - , m_pD3DXLoadSurfaceFromMemory(nullptr) - , m_pD3DXLoadSurfaceFromSurface(nullptr) - , m_pD3DXCreateLine(nullptr) - , m_pD3DXCreateFont(nullptr) - , m_pD3DXCreateSprite(nullptr) - , m_nVMR9Surfaces(0) - , m_iVMR9Surface(0) - , m_nUsedBuffer(0) - , m_fAvrFps(0.0) - , m_fJitterStdDev(0.0) - , m_fJitterMean(0.0) - , m_fSyncOffsetStdDev(0.0) - , m_fSyncOffsetAvr(0.0) - , m_DetectedRefreshRate(0) - , m_DetectedRefreshTime(0.0) - , m_DetectedRefreshTimePrim(0) - , m_DetectedScanlineTime(0) - , m_DetectedScanlineTimePrim(0) - , m_DetectedScanlinesPerFrame(0.0) - , m_ldDetectedRefreshRateList() - , m_ldDetectedScanlineRateList() - , m_DetectedRefreshRatePos(0) - , m_bSyncStatsAvailable(false) - , m_pllJitter() - , m_pllSyncOffset() - , m_llLastPerf(0) - , m_JitterStdDev(0) - , m_MaxJitter(MINLONG64) - , m_MinJitter(MAXLONG64) - , m_MaxSyncOffset(0) - , m_MinSyncOffset(0) - , m_nNextJitter(0) - , m_nNextSyncOffset(0) - , m_rtTimePerFrame(0) - , m_DetectedFrameRate(0.0) - , m_DetectedFrameTime(0.0) - , m_DetectedFrameTimeStdDev(0.0) - , m_DetectedLock(false) - , m_DetectedFrameTimeHistory() - , m_DetectedFrameTimeHistoryHistory() - , m_DetectedFrameTimePos(0) - , m_bInterlaced(false) - , m_VBlankEndWait(0) - , m_VBlankStartWait(0) - , m_VBlankWaitTime(0) - , m_VBlankLockTime(0) - , m_VBlankMin(300000) - , m_VBlankMinCalc(300000) - , m_VBlankMax(0) - , m_VBlankEndPresent(-100000) - , m_VBlankStartMeasureTime(0) - , m_VBlankStartMeasure(0) - , m_PresentWaitTime(0) - , m_PresentWaitTimeMin(3000000000) - , m_PresentWaitTimeMax(0) - , m_PaintTime(0) - , m_PaintTimeMin(3000000000) - , m_PaintTimeMax(0) - , m_WaitForGPUTime(0) - , m_RasterStatusWaitTime(0) - , m_RasterStatusWaitTimeMin(3000000000) - , m_RasterStatusWaitTimeMax(0) - , m_RasterStatusWaitTimeMaxCalc(0) - , m_ClockDiffCalc(0.0) - , m_ClockDiffPrim(0.0) - , m_ClockDiff(0.0) - , m_TimeChangeHistory() - , m_ClockChangeHistory() - , m_ClockTimeChangeHistoryPos(0) - , m_ModeratedTimeSpeed(1.0) - , m_ModeratedTimeSpeedPrim(0.0) - , m_ModeratedTimeSpeedDiff(0.0) - , m_bCorrectedFrameTime(0) - , m_FrameTimeCorrection(0) - , m_LastFrameDuration(0) - , m_LastSampleTime(0) - , m_FocusThread(nullptr) - , m_hFocusWindow(nullptr) - , m_bIsPreview(isPreview) -{ - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - - if (FAILED(hr)) { - _Error += _T("ISubPicAllocatorPresenterImpl failed\n"); - return; - } - - HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); - - if (hDll) { - (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory"); - (FARPROC&)m_pD3DXLoadSurfaceFromSurface = GetProcAddress(hDll, "D3DXLoadSurfaceFromSurface"); - (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine"); - (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW"); - (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite"); - } else { - _Error += _T("Your system is missing the file d3dx9_43.dll\n\nTo acquire this file you must install \"DirectX End-User Runtime\" or update your MPC-HC installation."); - } - - m_hDWMAPI = LoadLibrary(L"dwmapi.dll"); - if (m_hDWMAPI) { - (FARPROC&)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled"); - (FARPROC&)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition"); - } - - Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); - if (m_pD3DEx) { - m_pD3D = m_pD3DEx; - } - - const CRenderersSettings& r = GetRenderersSettings(); - - if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { - m_bDesktopCompositionDisabled = true; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(0); - } - } else { - m_bDesktopCompositionDisabled = false; - } - - hr = CreateDevice(_Error); -} -#pragma warning(pop) - -CDX9AllocatorPresenter::~CDX9AllocatorPresenter() -{ - if (m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = false; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(1); - } - } - - m_pFont = nullptr; - m_pLine = nullptr; - m_pSprite = nullptr; - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - - m_pAlphaBitmapTexture.Release(); - CleanupRenderingEngine(); - - m_pD3D = nullptr; - m_pD3DEx = nullptr; - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - - if (m_FocusThread) { - m_FocusThread->PostThreadMessage(WM_QUIT, 0, 0); - if (WaitForSingleObject(m_FocusThread->m_hThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_FocusThread->m_hThread, 0xDEAD); - } - } - - if (m_hDWMAPI) { - FreeLibrary(m_hDWMAPI); - m_hDWMAPI = nullptr; - } -} - -void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed); - -#if 0 -class CRandom31 -{ -public: - - CRandom31() { - m_Seed = 12164; - } - - void f_SetSeed(int32 _Seed) { - m_Seed = _Seed; - } - int32 f_GetSeed() { - return m_Seed; - } - /* - Park and Miller's psuedo-random number generator. - */ - int32 m_Seed; - int32 f_Get() { - static const int32 A = 16807; - static const int32 M = 2147483647; // 2^31 - 1 - static const int32 q = M / A; // M / A - static const int32 r = M % A; // M % A - m_Seed = A * (m_Seed % q) - r * (m_Seed / q); - if (m_Seed < 0) { - m_Seed += M; - } - return m_Seed; - } - - static int32 fs_Max() { - return 2147483646; - } - - double f_GetFloat() { - return double(f_Get()) * (1.0 / double(fs_Max())); - } -}; - -class CVSyncEstimation -{ -private: - class CHistoryEntry - { - public: - CHistoryEntry() { - m_Time = 0; - m_ScanLine = -1; - } - LONGLONG m_Time; - int m_ScanLine; - }; - - class CSolution - { - public: - CSolution() { - m_ScanLines = 1000; - m_ScanLinesPerSecond = m_ScanLines * 100; - } - int m_ScanLines; - double m_ScanLinesPerSecond; - double m_SqrSum; - - void f_Mutate(double _Amount, CRandom31& _Random, int _MinScans) { - int ToDo = _Random.f_Get() % 10; - if (ToDo == 0) { - m_ScanLines = m_ScanLines / 2; - } else if (ToDo == 1) { - m_ScanLines = m_ScanLines * 2; - } - - m_ScanLines = m_ScanLines * (1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5); - m_ScanLines = max(m_ScanLines, _MinScans); - - if (ToDo == 2) { - m_ScanLinesPerSecond /= (_Random.f_Get() % 4) + 1; - } else if (ToDo == 3) { - m_ScanLinesPerSecond *= (_Random.f_Get() % 4) + 1; - } - - m_ScanLinesPerSecond *= 1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5; - } - - void f_SpawnInto(CSolution& _Other, CRandom31& _Random, int _MinScans) { - _Other = *this; - _Other.f_Mutate(_Random.f_GetFloat() * 0.1, _Random, _MinScans); - } - - static int fs_Compare(const void* _pFirst, const void* _pSecond) { - const CSolution* pFirst = (const CSolution*)_pFirst; - const CSolution* pSecond = (const CSolution*)_pSecond; - if (pFirst->m_SqrSum < pSecond->m_SqrSum) { - return -1; - } else if (pFirst->m_SqrSum > pSecond->m_SqrSum) { - return 1; - } - return 0; - } - - - }; - - enum { - ENumHistory = 128 - }; - - CHistoryEntry m_History[ENumHistory]; - int m_iHistory; - CSolution m_OldSolutions[2]; - - CRandom31 m_Random; - - - double fp_GetSquareSum(double _ScansPerSecond, double _ScanLines) { - double SquareSum = 0; - int nHistory = min(m_nHistory, ENumHistory); - int iHistory = m_iHistory - nHistory; - if (iHistory < 0) { - iHistory += ENumHistory; - } - for (int i = 1; i < nHistory; ++i) { - int iHistory0 = iHistory + i - 1; - int iHistory1 = iHistory + i; - if (iHistory0 < 0) { - iHistory0 += ENumHistory; - } - iHistory0 = iHistory0 % ENumHistory; - iHistory1 = iHistory1 % ENumHistory; - ASSERT(m_History[iHistory0].m_Time != 0); - ASSERT(m_History[iHistory1].m_Time != 0); - - double DeltaTime = (m_History[iHistory1].m_Time - m_History[iHistory0].m_Time) / 10000000.0; - double PredictedScanLine = m_History[iHistory0].m_ScanLine + DeltaTime * _ScansPerSecond; - PredictedScanLine = fmod(PredictedScanLine, _ScanLines); - double Delta = (m_History[iHistory1].m_ScanLine - PredictedScanLine); - double DeltaSqr = Delta * Delta; - SquareSum += DeltaSqr; - } - return SquareSum; - } - - int m_nHistory; -public: - - CVSyncEstimation() { - m_iHistory = 0; - m_nHistory = 0; - } - - void f_AddSample(int _ScanLine, LONGLONG _Time) { - m_History[m_iHistory].m_ScanLine = _ScanLine; - m_History[m_iHistory].m_Time = _Time; - ++m_nHistory; - m_iHistory = (m_iHistory + 1) % ENumHistory; - } - - void f_GetEstimation(double& _RefreshRate, int& _ScanLines, int _ScreenSizeY, int _WindowsRefreshRate) { - _RefreshRate = 0; - _ScanLines = 0; - - int iHistory = m_iHistory; - // We have a full history - if (m_nHistory > 10) { - for (int l = 0; l < 5; ++l) { - const int nSol = 3 + 5 + 5 + 3; - CSolution Solutions[nSol]; - - Solutions[0] = m_OldSolutions[0]; - Solutions[1] = m_OldSolutions[1]; - Solutions[2].m_ScanLines = _ScreenSizeY; - Solutions[2].m_ScanLinesPerSecond = _ScreenSizeY * _WindowsRefreshRate; - - int iStart = 3; - for (int i = iStart; i < iStart + 5; ++i) { - Solutions[0].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); - } - iStart += 5; - for (int i = iStart; i < iStart + 5; ++i) { - Solutions[1].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); - } - iStart += 5; - for (int i = iStart; i < iStart + 3; ++i) { - Solutions[2].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); - } - - int Start = 2; - if (l == 0) { - Start = 0; - } - for (int i = Start; i < nSol; ++i) { - Solutions[i].m_SqrSum = fp_GetSquareSum(Solutions[i].m_ScanLinesPerSecond, Solutions[i].m_ScanLines); - } - - qsort(Solutions, nSol, sizeof(Solutions[0]), &CSolution::fs_Compare); - for (int i = 0; i < 2; ++i) { - m_OldSolutions[i] = Solutions[i]; - } - } - - _ScanLines = m_OldSolutions[0].m_ScanLines + 0.5; - _RefreshRate = 1.0 / (m_OldSolutions[0].m_ScanLines / m_OldSolutions[0].m_ScanLinesPerSecond); - } else { - m_OldSolutions[0].m_ScanLines = _ScreenSizeY; - m_OldSolutions[1].m_ScanLines = _ScreenSizeY; - } - } -}; -#endif - -bool CDX9AllocatorPresenter::SettingsNeedResetDevice(CRenderersSettings& r) -{ - CRenderersSettings::CAdvRendererSettings& New = r.m_AdvRendSets; - CRenderersSettings::CAdvRendererSettings& Current = m_LastRendererSettings; - - bool bRet = false; - - bRet = bRet || New.bVMR9AlterativeVSync != Current.bVMR9AlterativeVSync; - bRet = bRet || New.bVMR9VSyncAccurate != Current.bVMR9VSyncAccurate; - - if (m_bIsFullscreen) { - bRet = bRet || New.bVMR9FullscreenGUISupport != Current.bVMR9FullscreenGUISupport; - } else { - if (Current.bVMRDisableDesktopComposition) { - if (!m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = true; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(0); - } - } - } else { - if (m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = false; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(1); - } - } - } - } - - if (m_bIsEVR) { - bRet = bRet || New.bEVRHighColorResolution != Current.bEVRHighColorResolution; - bRet = bRet || New.bEVRForceInputHighColorResolution != Current.bEVRForceInputHighColorResolution; - } - - m_LastRendererSettings = r.m_AdvRendSets; - - return bRet; -} - -HRESULT CDX9AllocatorPresenter::CreateDevice(CString& _Error) -{ - const CRenderersSettings& r = GetRenderersSettings(); - CRenderersData* rd = GetRenderersData(); - - m_VBlankEndWait = 0; - m_VBlankMin = 300000; - m_VBlankMinCalc = 300000; - m_VBlankMax = 0; - m_VBlankStartWait = 0; - m_VBlankWaitTime = 0; - m_VBlankLockTime = 0; - m_PresentWaitTime = 0; - m_PresentWaitTimeMin = 3000000000; - m_PresentWaitTimeMax = 0; - - m_LastRendererSettings = r.m_AdvRendSets; - - m_VBlankEndPresent = -100000; - m_VBlankStartMeasureTime = 0; - m_VBlankStartMeasure = 0; - - m_PaintTime = 0; - m_PaintTimeMin = 3000000000; - m_PaintTimeMax = 0; - - m_RasterStatusWaitTime = 0; - m_RasterStatusWaitTimeMin = 3000000000; - m_RasterStatusWaitTimeMax = 0; - m_RasterStatusWaitTimeMaxCalc = 0; - - m_ClockDiff = 0.0; - m_ClockDiffPrim = 0.0; - m_ClockDiffCalc = 0.0; - - m_ModeratedTimeSpeed = 1.0; - m_ModeratedTimeSpeedDiff = 0.0; - m_ModeratedTimeSpeedPrim = 0; - ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory)); - ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory)); - m_ClockTimeChangeHistoryPos = 0; - - m_pSprite = nullptr; - m_pLine = nullptr; - m_pFont = nullptr; - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - m_pDirectDraw = nullptr; - - m_bAlphaBitmapEnable = false; - m_pAlphaBitmapTexture.Release(); - ZeroMemory(&m_AlphaBitmapParams, sizeof(m_AlphaBitmapParams)); - - CleanupRenderingEngine(); - - UINT currentAdapter = GetAdapter(m_pD3D); - bool bTryToReset = (currentAdapter == m_CurrentAdapter); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - m_CurrentAdapter = currentAdapter; - } - - if (!m_pD3D) { - _Error += L"Failed to create D3D9\n"; - return E_UNEXPECTED; - } - - HRESULT hr = S_OK; - - /*// TODO : add NVIDIA PerfHUD !!! - - // Set default settings - UINT AdapterToUse=D3DADAPTER_DEFAULT; - D3DDEVTYPE DeviceType=D3DDEVTYPE_HAL; - - #if SHIPPING_VERSION - // When building a shipping version, disable PerfHUD (opt-out) - #else - // Look for 'NVIDIA PerfHUD' adapter - // If it is present, override default settings - for (UINT Adapter=0;AdapterGetAdapterCount();Adapter++) - { - D3DADAPTER_IDENTIFIER9 Identifier; - HRESULT Res; - - Res = g_pD3D->GetAdapterIdentifier(Adapter,0,&Identifier); - if (strstr(Identifier.Description,"PerfHUD") != 0) - { - AdapterToUse=Adapter; - DeviceType=D3DDEVTYPE_REF; - break; - } - } - #endif - - if (FAILED(g_pD3D->CreateDevice( AdapterToUse, DeviceType, hWnd, - D3DCREATE_HARDWARE_VERTEXPROCESSING, - &d3dpp, &g_pd3dDevice) ) ) - { - return E_FAIL; - } - */ - - - //#define ENABLE_DDRAWSYNC -#ifdef ENABLE_DDRAWSYNC - hr = DirectDrawCreate(nullptr, &m_pDirectDraw, nullptr); - if (hr == S_OK) { - hr = m_pDirectDraw->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL); - } -#endif - - D3DPRESENT_PARAMETERS pp; - ZeroMemory(&pp, sizeof(pp)); - - BOOL bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - - m_bCompositionEnabled = !!bCompositionEnabled; - m_bAlternativeVSync = r.m_AdvRendSets.bVMR9AlterativeVSync; - - // detect FP16 textures support - rd->m_bFP16Support = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_VOLUMETEXTURE, D3DFMT_A16B16G16R16F)); - - // detect FP32 textures support - rd->m_bFP32Support = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_VOLUMETEXTURE, D3DFMT_A32B32G32R32F)); - - // detect 10-bit textures support - rd->m_b10bitSupport = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, D3DFMT_A2R10G10B10)); - - // detect 10-bit device support - bool bHighColorSupport = SUCCEEDED(m_pD3D->CheckDeviceType(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_A2R10G10B10, D3DFMT_A2R10G10B10, FALSE)); - - // set settings that depend on hardware feature support - m_bForceInputHighColorResolution = r.m_AdvRendSets.bEVRForceInputHighColorResolution && m_bIsEVR && rd->m_b10bitSupport; - m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution && m_bIsEVR && rd->m_b10bitSupport && bHighColorSupport; - m_bFullFloatingPointProcessing = r.m_AdvRendSets.bVMR9FullFloatingPointProcessing && rd->m_bFP32Support; - m_bHalfFloatingPointProcessing = r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing && rd->m_bFP16Support && !m_bFullFloatingPointProcessing; - - // set color formats - if (m_bFullFloatingPointProcessing) { - m_SurfaceType = D3DFMT_A32B32G32R32F; - } else if (m_bHalfFloatingPointProcessing) { - m_SurfaceType = D3DFMT_A16B16G16R16F; - } else if (m_bForceInputHighColorResolution || m_bHighColorResolution) { - m_SurfaceType = D3DFMT_A2R10G10B10; - } else { - m_SurfaceType = D3DFMT_X8R8G8B8; - } - - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - - D3DDISPLAYMODEEX DisplayMode; - ZeroMemory(&DisplayMode, sizeof(DisplayMode)); - DisplayMode.Size = sizeof(DisplayMode); - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - - if (m_bIsFullscreen) { - if (m_bHighColorResolution) { - pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } else { - pp.BackBufferFormat = D3DFMT_X8R8G8B8; - } - pp.Windowed = false; - pp.BackBufferCount = 3; - pp.SwapEffect = D3DSWAPEFFECT_FLIP; - // there's no Desktop composition to take care of alternative vSync in exclusive mode, alternative vSync is therefore unused - pp.hDeviceWindow = m_hWnd; - pp.Flags = D3DPRESENTFLAG_VIDEO; - if (r.m_AdvRendSets.bVMR9FullscreenGUISupport && !m_bHighColorResolution) { - pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; - } - m_D3DDevExError = _T("No m_pD3DEx"); - - if (!m_FocusThread) { - m_FocusThread = (CFocusThread*)AfxBeginThread(RUNTIME_CLASS(CFocusThread), 0, 0, 0); - } - - HWND hFocusWindow = m_FocusThread->GetFocusWindow(); - bTryToReset &= (m_hFocusWindow == hFocusWindow || fullScreenChanged); - m_hFocusWindow = hFocusWindow; - - if (m_pD3DEx) { - CHECK_HR(m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr)); - - m_ScreenSize.SetSize(DisplayMode.Width, DisplayMode.Height); - m_BackBufferSize = m_ScreenSize; - - DisplayMode.Format = pp.BackBufferFormat; - pp.FullScreen_RefreshRateInHz = m_refreshRate = DisplayMode.RefreshRate; - pp.BackBufferWidth = m_BackBufferSize.cx; - pp.BackBufferHeight = m_BackBufferSize.cy; - - bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&pp, &DisplayMode)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - hr = m_pD3DEx->CreateDeviceEx( - m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS | D3DCREATE_NOWINDOWCHANGES, //D3DCREATE_MANAGED - &pp, &DisplayMode, &m_pD3DDevEx); - } - - if (FAILED(hr)) { - m_D3DDevExError = GetWindowsErrorMessage(hr, nullptr); - } else { - m_D3DDevExError.Empty(); - } - - if (m_pD3DDevEx) { - m_pD3DDev = m_pD3DDevEx; - m_BackbufferType = pp.BackBufferFormat; - m_DisplayType = DisplayMode.Format; - } - } - if (bTryToReset && m_pD3DDev && !m_pD3DDevEx) { - if (FAILED(hr = m_pD3DDev->Reset(&pp))) { - m_pD3DDev = nullptr; - } - } - if (!m_pD3DDev) { - CHECK_HR(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)); - d3ddm.Format = pp.BackBufferFormat; - - m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); - m_BackBufferSize = m_ScreenSize; - - pp.FullScreen_RefreshRateInHz = m_refreshRate = d3ddm.RefreshRate; - pp.BackBufferWidth = m_BackBufferSize.cx; - pp.BackBufferHeight = m_BackBufferSize.cy; - - hr = m_pD3D->CreateDevice( - m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_NOWINDOWCHANGES, //D3DCREATE_MANAGED - &pp, &m_pD3DDev); - m_DisplayType = d3ddm.Format; - m_BackbufferType = pp.BackBufferFormat; - } - if (m_pD3DDev && r.m_AdvRendSets.bVMR9FullscreenGUISupport && !m_bHighColorResolution) { - m_pD3DDev->SetDialogBoxMode(true); - //if (m_pD3DDev->SetDialogBoxMode(true) != S_OK) - // ExitProcess(0); - } - } else { - pp.Windowed = TRUE; - pp.hDeviceWindow = m_hWnd; - pp.SwapEffect = D3DSWAPEFFECT_COPY; - pp.Flags = D3DPRESENTFLAG_VIDEO; - pp.BackBufferCount = 1; - if (bCompositionEnabled || m_bAlternativeVSync) { - // Desktop composition takes care of the VSYNC - pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - } - - bTryToReset &= (m_hFocusWindow == m_hWnd || fullScreenChanged); - m_hFocusWindow = m_hWnd; - - if (m_pD3DEx) { - HRESULT getModeResult = m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); - - if (getModeResult == D3DERR_NOTAVAILABLE) { - m_pD3DEx = nullptr; - Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); - if (nullptr != m_pD3DEx) { - getModeResult = m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); - } - } - CHECK_HR(getModeResult); - - m_ScreenSize.SetSize(DisplayMode.Width, DisplayMode.Height); - m_refreshRate = DisplayMode.RefreshRate; - m_BackBufferSize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); - pp.BackBufferWidth = m_BackBufferSize.cx; - pp.BackBufferHeight = m_BackBufferSize.cy; - - bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&pp, nullptr)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - // We can get 0x8876086a here when switching from two displays to one display using Win + P (Windows 7) - // Cause: We might not reinitialize dx correctly during the switch - hr = m_pD3DEx->CreateDeviceEx( - m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS, //D3DCREATE_MANAGED - &pp, nullptr, &m_pD3DDevEx); - } - if (m_pD3DDevEx) { - m_pD3DDev = m_pD3DDevEx; - m_DisplayType = DisplayMode.Format; - } - } - if (bTryToReset && m_pD3DDev && !m_pD3DDevEx) { - if (FAILED(hr = m_pD3DDev->Reset(&pp))) { - m_pD3DDev = nullptr; - } - } - if (!m_pD3DDev) { - CHECK_HR(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)); - m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); - m_refreshRate = d3ddm.RefreshRate; - m_BackBufferSize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); - pp.BackBufferWidth = m_BackBufferSize.cx; - pp.BackBufferHeight = m_BackBufferSize.cy; - - hr = m_pD3D->CreateDevice( - m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED - &pp, &m_pD3DDev); - m_DisplayType = d3ddm.Format; - } - m_BackbufferType = pp.BackBufferFormat; - } - - if (m_pD3DDev) { - while (hr == D3DERR_DEVICELOST) { - TRACE(_T("D3DERR_DEVICELOST. Trying to Reset.\n")); - hr = m_pD3DDev->TestCooperativeLevel(); - } - if (hr == D3DERR_DEVICENOTRESET) { - TRACE(_T("D3DERR_DEVICENOTRESET\n")); - hr = m_pD3DDev->Reset(&pp); - } - - if (m_pD3DDevEx) { - m_pD3DDevEx->SetGPUThreadPriority(7); - } - } - - if (FAILED(hr)) { - _Error += L"CreateDevice failed\n"; - CStringW str; - str.Format(L"Error code: 0x%X\n", hr); - _Error += str; - - return hr; - } - - ASSERT(m_pD3DDev); - - if (m_ScreenSize.cx <= 0 || m_ScreenSize.cy <= 0) { - _Error += L"Invalid screen size\n"; - return E_FAIL; - } - - m_MainThreadId = GetCurrentThreadId(); - - // Get the device caps - ZeroMemory(&m_Caps, sizeof(m_Caps)); - m_pD3DDev->GetDeviceCaps(&m_Caps); - - // Initialize the rendering engine - InitRenderingEngine(); - - if (!m_bIsPreview) { - CComPtr pSubPicProvider; - if (m_pSubPicQueue) { - m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); - } - - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(m_pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); - } - - hr = S_OK; - if (!m_pSubPicQueue) { - CAutoLock cAutoLock(this); - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - m_pSubPicQueue->Invalidate(); - } - - if (FAILED(hr)) { - _Error += L"m_pSubPicQueue failed\n"; - - return hr; - } - - if (pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); - } - } - - m_LastAdapterCheck = rd->GetPerfCounter(); - - return S_OK; -} - -HRESULT CDX9AllocatorPresenter::AllocSurfaces() -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - return CreateVideoSurfaces(); -} - -void CDX9AllocatorPresenter::DeleteSurfaces() -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - FreeVideoSurfaces(); -} - -UINT CDX9AllocatorPresenter::GetAdapter(IDirect3D9* pD3D, bool bGetAdapter) -{ - if (m_hWnd == nullptr || pD3D == nullptr) { - return D3DADAPTER_DEFAULT; - } - - m_D3D9Device = _T(""); - - const CRenderersSettings& r = GetRenderersSettings(); - if (bGetAdapter && (pD3D->GetAdapterCount() > 1) && !r.D3D9RenderDevice.IsEmpty()) { - TCHAR strGUID[50]; - D3DADAPTER_IDENTIFIER9 adapterIdentifier; - - for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { - if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK) { - if ((::StringFromGUID2(adapterIdentifier.DeviceIdentifier, strGUID, 50) > 0) && (r.D3D9RenderDevice == strGUID)) { - m_D3D9Device = adapterIdentifier.Description; - return adp; - } - } - } - } - - HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); - if (hMonitor == nullptr) { - return D3DADAPTER_DEFAULT; - } - - for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { - HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp); - if (hAdpMon == hMonitor) { - if (bGetAdapter) { - D3DADAPTER_IDENTIFIER9 adapterIdentifier; - if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK) { - m_D3D9Device = adapterIdentifier.Description; - } - } - return adp; - } - } - - return D3DADAPTER_DEFAULT; -} - -DWORD CDX9AllocatorPresenter::GetVertexProcessing() -{ - HRESULT hr; - D3DCAPS9 caps; - - hr = m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &caps); - if (FAILED(hr)) { - return D3DCREATE_SOFTWARE_VERTEXPROCESSING; - } - - if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 || - caps.VertexShaderVersion < D3DVS_VERSION(2, 0)) { - return D3DCREATE_SOFTWARE_VERTEXPROCESSING; - } - - return D3DCREATE_HARDWARE_VERTEXPROCESSING; -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP CDX9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - return E_NOTIMPL; -} - -void CDX9AllocatorPresenter::CalculateJitter(LONGLONG PerfCounter) -{ - // Calculate the jitter! - LONGLONG llPerf = PerfCounter; - if ((m_rtTimePerFrame != 0) && (labs((long)(llPerf - m_llLastPerf)) < m_rtTimePerFrame * 3)) { - m_nNextJitter = (m_nNextJitter + 1) % NB_JITTER; - m_pllJitter[m_nNextJitter] = llPerf - m_llLastPerf; - - m_MaxJitter = MINLONG64; - m_MinJitter = MAXLONG64; - - // Calculate the real FPS - LONGLONG llJitterSum = 0; - LONGLONG llJitterSumAvg = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG Jitter = m_pllJitter[i]; - llJitterSum += Jitter; - llJitterSumAvg += Jitter; - } - double FrameTimeMean = double(llJitterSumAvg) / NB_JITTER; - m_fJitterMean = FrameTimeMean; - double DeviationSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG DevInt = m_pllJitter[i] - (LONGLONG)FrameTimeMean; - double Deviation = (double)DevInt; - DeviationSum += Deviation * Deviation; - m_MaxJitter = std::max(m_MaxJitter, DevInt); - m_MinJitter = std::min(m_MinJitter, DevInt); - } - double StdDev = sqrt(DeviationSum / NB_JITTER); - - m_fJitterStdDev = StdDev; - m_fAvrFps = 10000000.0 / (double(llJitterSum) / NB_JITTER); - } - - m_llLastPerf = llPerf; -} - -bool CDX9AllocatorPresenter::GetVBlank(int& _ScanLine, int& _bInVBlank, bool _bMeasureTime) -{ - LONGLONG llPerf = 0; - if (_bMeasureTime) { - llPerf = GetRenderersData()->GetPerfCounter(); - } - - int ScanLine = 0; - _ScanLine = 0; - _bInVBlank = 0; - - if (m_pDirectDraw) { - DWORD ScanLineGet = 0; - m_pDirectDraw->GetScanLine(&ScanLineGet); - BOOL InVBlank; - if (m_pDirectDraw->GetVerticalBlankStatus(&InVBlank) != S_OK) { - return false; - } - ScanLine = ScanLineGet; - _bInVBlank = InVBlank; - if (InVBlank) { - ScanLine = 0; - } - } else { - D3DRASTER_STATUS RasterStatus; - if (m_pD3DDev->GetRasterStatus(0, &RasterStatus) != S_OK) { - return false; - } - ScanLine = RasterStatus.ScanLine; - _bInVBlank = RasterStatus.InVBlank; - } - if (_bMeasureTime) { - m_VBlankMax = std::max(m_VBlankMax, ScanLine); - if (ScanLine != 0 && !_bInVBlank) { - m_VBlankMinCalc = std::min(m_VBlankMinCalc, ScanLine); - } - m_VBlankMin = m_VBlankMax - m_ScreenSize.cy; - } - if (_bInVBlank) { - _ScanLine = 0; - } else if (m_VBlankMin != 300000) { - _ScanLine = ScanLine - m_VBlankMin; - } else { - _ScanLine = ScanLine; - } - - if (_bMeasureTime) { - LONGLONG Time = GetRenderersData()->GetPerfCounter() - llPerf; - if (Time > 5000000) { // 0.5 sec - TRACE(_T("GetVBlank too long (%f sec)\n"), Time / 10000000.0); - } - m_RasterStatusWaitTimeMaxCalc = std::max(m_RasterStatusWaitTimeMaxCalc, Time); - } - - return true; -} - -bool CDX9AllocatorPresenter::WaitForVBlankRange(int& _RasterStart, int _RasterSize, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, HANDLE& lockOwner) -{ - if (_bMeasure) { - m_RasterStatusWaitTimeMaxCalc = 0; - } - bool bWaited = false; - int ScanLine = 0; - int InVBlank = 0; - LONGLONG llPerf = 0; - if (_bMeasure) { - llPerf = GetRenderersData()->GetPerfCounter(); - } - GetVBlank(ScanLine, InVBlank, _bMeasure); - if (_bMeasure) { - m_VBlankStartWait = ScanLine; - } - - static bool bOneWait = true; - if (bOneWait && _bMeasure) { - bOneWait = false; - // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate - int nInVBlank = 0; - for (;;) { - if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { - break; - } - - if (InVBlank && nInVBlank == 0) { - nInVBlank = 1; - } else if (!InVBlank && nInVBlank == 1) { - nInVBlank = 2; - } else if (InVBlank && nInVBlank == 2) { - nInVBlank = 3; - } else if (!InVBlank && nInVBlank == 3) { - break; - } - } - } - if (_bWaitIfInside) { - int ScanLineDiff = long(ScanLine) - _RasterStart; - if (ScanLineDiff > m_ScreenSize.cy / 2) { - ScanLineDiff -= m_ScreenSize.cy; - } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { - ScanLineDiff += m_ScreenSize.cy; - } - - if (ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) { - bWaited = true; - // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate - int LastLineDiff = ScanLineDiff; - for (;;) { - if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { - break; - } - ScanLineDiff = long(ScanLine) - _RasterStart; - if (ScanLineDiff > m_ScreenSize.cy / 2) { - ScanLineDiff -= m_ScreenSize.cy; - } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { - ScanLineDiff += m_ScreenSize.cy; - } - if (!(ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0)) { - break; - } - LastLineDiff = ScanLineDiff; - Sleep(1); // Just sleep - } - } - } - double RefreshRate = GetRefreshRate(); - LONG ScanLines = GetScanLines(); - int MinRange = std::max(std::min(long(0.0015 * ScanLines * RefreshRate + 0.5), ScanLines / 3l), 5l); // 1.5 ms or max 33 % of Time - int NoSleepStart = _RasterStart - MinRange; - int NoSleepRange = MinRange; - if (NoSleepStart < 0) { - NoSleepStart += m_ScreenSize.cy; - } - - int MinRange2 = std::max(std::min(long(0.0050 * ScanLines * RefreshRate + 0.5), ScanLines / 3l), 5l); // 5 ms or max 33 % of Time - int D3DDevLockStart = _RasterStart - MinRange2; - int D3DDevLockRange = MinRange2; - if (D3DDevLockStart < 0) { - D3DDevLockStart += m_ScreenSize.cy; - } - - int ScanLineDiff = ScanLine - _RasterStart; - if (ScanLineDiff > m_ScreenSize.cy / 2) { - ScanLineDiff -= m_ScreenSize.cy; - } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { - ScanLineDiff += m_ScreenSize.cy; - } - int LastLineDiff = ScanLineDiff; - - - int ScanLineDiffSleep = long(ScanLine) - NoSleepStart; - if (ScanLineDiffSleep > m_ScreenSize.cy / 2) { - ScanLineDiffSleep -= m_ScreenSize.cy; - } else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2) { - ScanLineDiffSleep += m_ScreenSize.cy; - } - int LastLineDiffSleep = ScanLineDiffSleep; - - - int ScanLineDiffLock = long(ScanLine) - D3DDevLockStart; - if (ScanLineDiffLock > m_ScreenSize.cy / 2) { - ScanLineDiffLock -= m_ScreenSize.cy; - } else if (ScanLineDiffLock < -m_ScreenSize.cy / 2) { - ScanLineDiffLock += m_ScreenSize.cy; - } - int LastLineDiffLock = ScanLineDiffLock; - - LONGLONG llPerfLock = 0; - - for (;;) { - if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { - break; - } - ScanLineDiff = long(ScanLine) - _RasterStart; - if (ScanLineDiff > m_ScreenSize.cy / 2) { - ScanLineDiff -= m_ScreenSize.cy; - } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { - ScanLineDiff += m_ScreenSize.cy; - } - if ((ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0)) { - break; - } - - LastLineDiff = ScanLineDiff; - - bWaited = true; - - ScanLineDiffLock = long(ScanLine) - D3DDevLockStart; - if (ScanLineDiffLock > m_ScreenSize.cy / 2) { - ScanLineDiffLock -= m_ScreenSize.cy; - } else if (ScanLineDiffLock < -m_ScreenSize.cy / 2) { - ScanLineDiffLock += m_ScreenSize.cy; - } - - if (((ScanLineDiffLock >= 0 && ScanLineDiffLock <= D3DDevLockRange) || (LastLineDiffLock < 0 && ScanLineDiffLock > 0))) { - if (!lockOwner && _bMeasure) { - llPerfLock = GetRenderersData()->GetPerfCounter(); - lockOwner = LockD3DDevice(); - } - } - LastLineDiffLock = ScanLineDiffLock; - - - ScanLineDiffSleep = long(ScanLine) - NoSleepStart; - if (ScanLineDiffSleep > m_ScreenSize.cy / 2) { - ScanLineDiffSleep -= m_ScreenSize.cy; - } else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2) { - ScanLineDiffSleep += m_ScreenSize.cy; - } - - if (!((ScanLineDiffSleep >= 0 && ScanLineDiffSleep <= NoSleepRange) || (LastLineDiffSleep < 0 && ScanLineDiffSleep > 0)) || !_bNeedAccurate) { - //TRACE(_T("%d\n"), RasterStatus.ScanLine); - Sleep(1); // Don't sleep for the last 1.5 ms scan lines, so we get maximum precision - } - LastLineDiffSleep = ScanLineDiffSleep; - } - _RasterStart = ScanLine; - if (_bMeasure) { - m_VBlankEndWait = ScanLine; - m_VBlankWaitTime = GetRenderersData()->GetPerfCounter() - llPerf; - - if (lockOwner) { - m_VBlankLockTime = GetRenderersData()->GetPerfCounter() - llPerfLock; - } else { - m_VBlankLockTime = 0; - } - - m_RasterStatusWaitTime = m_RasterStatusWaitTimeMaxCalc; - m_RasterStatusWaitTimeMin = std::min(m_RasterStatusWaitTimeMin, m_RasterStatusWaitTime); - m_RasterStatusWaitTimeMax = std::max(m_RasterStatusWaitTimeMax, m_RasterStatusWaitTime); - } - - return bWaited; -} - -int CDX9AllocatorPresenter::GetVBlackPos() -{ - BOOL bCompositionEnabled = m_bCompositionEnabled; - - int WaitRange = std::max(m_ScreenSize.cy / 40l, 5l); - if (!bCompositionEnabled) { - if (m_bAlternativeVSync) { - const CRenderersSettings& r = GetRenderersSettings(); - return r.m_AdvRendSets.iVMR9VSyncOffset; - } else { - int MinRange = std::max(std::min(long(0.005 * m_ScreenSize.cy * GetRefreshRate() + 0.5), m_ScreenSize.cy / 3l), 5l); // 5 ms or max 33 % of Time - int WaitFor = m_ScreenSize.cy - (MinRange + WaitRange); - return WaitFor; - } - } else { - int WaitFor = m_ScreenSize.cy / 2; - return WaitFor; - } -} - -bool CDX9AllocatorPresenter::WaitForVBlank(bool& _Waited, HANDLE& lockOwner) -{ - const CRenderersSettings& r = GetRenderersSettings(); - if (!r.m_AdvRendSets.bVMR9VSync) { - _Waited = true; - m_VBlankWaitTime = 0; - m_VBlankLockTime = 0; - m_VBlankEndWait = 0; - m_VBlankStartWait = 0; - return true; - } - //_Waited = true; - //return false; - - BOOL bCompositionEnabled = m_bCompositionEnabled; - int WaitFor = GetVBlackPos(); - - if (!bCompositionEnabled) { - if (m_bAlternativeVSync) { - _Waited = WaitForVBlankRange(WaitFor, 0, false, true, true, lockOwner); - return false; - } else { - _Waited = WaitForVBlankRange(WaitFor, 0, false, r.m_AdvRendSets.bVMR9VSyncAccurate, true, lockOwner); - return true; - } - } else { - // Instead we wait for VBlack after the present, this seems to fix the stuttering problem. It'r also possible to fix by removing the Sleep above, but that isn't an option. - WaitForVBlankRange(WaitFor, 0, false, r.m_AdvRendSets.bVMR9VSyncAccurate, true, lockOwner); - - return false; - } -} - -void CDX9AllocatorPresenter::UpdateAlphaBitmap() -{ - m_VMR9AlphaBitmapData.Free(); - - if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0) { - HBITMAP hBitmap = (HBITMAP)GetCurrentObject(m_VMR9AlphaBitmap.hdc, OBJ_BITMAP); - if (!hBitmap) { - return; - } - DIBSECTION info; - ZeroMemory(&info, sizeof(DIBSECTION)); - if (!::GetObject(hBitmap, sizeof(DIBSECTION), &info)) { - return; - } - - m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight); - m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes; - - if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight)) { - memcpy((BYTE*)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight); - } - } -} - -STDMETHODIMP_(bool) CDX9AllocatorPresenter::Paint(bool bAll) -{ - if (m_bPendingResetDevice) { - SendResetRequest(); - return false; - } - - CRenderersSettings& r = GetRenderersSettings(); - if (&r == nullptr) { - return false; - } - - //TRACE(_T("Thread: %d\n"), (LONG)((CRITICAL_SECTION &)m_RenderLock).OwningThread); - -#if 0 - if (TryEnterCriticalSection(&(CRITICAL_SECTION&)(*((CCritSec*)this)))) { - LeaveCriticalSection((&(CRITICAL_SECTION&)(*((CCritSec*)this)))); - } else { - __debugbreak(); - } -#endif - - CRenderersData* rd = GetRenderersData(); - - LONGLONG StartPaint = rd->GetPerfCounter(); - CAutoLock cRenderLock(&m_RenderLock); - - if (m_windowRect.right <= m_windowRect.left || m_windowRect.bottom <= m_windowRect.top - || m_nativeVideoSize.cx <= 0 || m_nativeVideoSize.cy <= 0 - || !m_pVideoSurface[m_nCurSurface]) { - if (m_OrderedPaint) { - --m_OrderedPaint; - } else { - //TRACE(_T("UNORDERED PAINT!!!!!!\n")); - } - - - return false; - } - - HRESULT hr; - - m_pD3DDev->BeginScene(); - - CComPtr pBackBuffer; - m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); - // FIXME: GetBackBuffer can fail, check return value and reset device - - // Clear the backbuffer - m_pD3DDev->SetRenderTarget(0, pBackBuffer); - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); - - CRect rSrcVid(CPoint(0, 0), GetVisibleVideoSize()); - CRect rDstVid(m_videoRect); - - CRect rSrcPri(CPoint(0, 0), m_windowRect.Size()); - CRect rDstPri(rSrcPri); - - // Render the current video frame - hr = RenderVideo(pBackBuffer, rSrcVid, rDstVid); - - if (FAILED(hr)) { - if (m_RenderingPath == RENDERING_PATH_STRETCHRECT) { - // Support ffdshow queueing - // m_pD3DDev->StretchRect may fail if ffdshow is using queue output samples. - // Here we don't want to show the black buffer. - if (m_OrderedPaint) { - --m_OrderedPaint; - } else { - //TRACE(_T("UNORDERED PAINT!!!!!!\n")); - } - - return false; - } - } - - if (!m_bIsPreview) { - // paint the text on the backbuffer - AlphaBltSubPic(rDstPri, rDstVid); - - // Casimir666 : show OSD - if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE) { - CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock); - CRect rcSrc(m_VMR9AlphaBitmap.rSrc); - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE*)m_VMR9AlphaBitmapData) { - if ((m_pD3DXLoadSurfaceFromMemory != nullptr) && - SUCCEEDED(hr = m_pD3DDev->CreateTexture(rcSrc.Width(), rcSrc.Height(), 1, - D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, &m_pOSDTexture, nullptr))) { - if (SUCCEEDED(hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface))) { - hr = m_pD3DXLoadSurfaceFromMemory(m_pOSDSurface, - nullptr, - nullptr, - (BYTE*)m_VMR9AlphaBitmapData, - D3DFMT_A8R8G8B8, - m_VMR9AlphaBitmapWidthBytes, - nullptr, - &m_VMR9AlphaBitmapRect, - D3DX_FILTER_NONE, - m_VMR9AlphaBitmap.clrSrcKey); - } - if (FAILED(hr)) { - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - } - } - } - m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE; - - } - - if (m_bAlphaBitmapEnable && m_pAlphaBitmapTexture) { - CRect rcDst(rSrcPri); - AlphaBlt(rSrcPri, rcDst, m_pAlphaBitmapTexture); - } - - if (rd->m_bResetStats) { - ResetStats(); - rd->m_bResetStats = false; - } - - if (rd->m_iDisplayStats) { - DrawStats(); - } - - if (m_pOSDTexture) { - AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture); - } - } - - m_pD3DDev->EndScene(); - - BOOL bCompositionEnabled = m_bCompositionEnabled; - - bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !r.m_AdvRendSets.bVMR9VSync; - - CComPtr pEventQueryFlushBeforeVSync; - m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQueryFlushBeforeVSync); - if (pEventQueryFlushBeforeVSync) { - pEventQueryFlushBeforeVSync->Issue(D3DISSUE_END); - } - - if (r.m_AdvRendSets.bVMRFlushGPUBeforeVSync && pEventQueryFlushBeforeVSync) { - LONGLONG llPerf = rd->GetPerfCounter(); - BOOL Data; - //Sleep(5); - LONGLONG FlushStartTime = rd->GetPerfCounter(); - while (S_FALSE == pEventQueryFlushBeforeVSync->GetData(&Data, sizeof(Data), D3DGETDATA_FLUSH)) { - if (!r.m_AdvRendSets.bVMRFlushGPUWait) { - break; - } - Sleep(1); - if (rd->GetPerfCounter() - FlushStartTime > 500000) { - break; // timeout after 50 ms - } - } - if (r.m_AdvRendSets.bVMRFlushGPUWait) { - m_WaitForGPUTime = rd->GetPerfCounter() - llPerf; - } else { - m_WaitForGPUTime = 0; - } - } else { - m_WaitForGPUTime = 0; - } - - if (bAll) { - m_PaintTime = (rd->GetPerfCounter() - StartPaint); - m_PaintTimeMin = std::min(m_PaintTimeMin, m_PaintTime); - m_PaintTimeMax = std::max(m_PaintTimeMax, m_PaintTime); - } - - bool bWaited = false; - HANDLE lockOwner = nullptr; - if (bAll) { - // Only sync to refresh when redrawing all - bool bTest = WaitForVBlank(bWaited, lockOwner); - ASSERT(bTest == bDoVSyncInPresent); - if (!bDoVSyncInPresent) { - LONGLONG Time = rd->GetPerfCounter(); - OnVBlankFinished(bAll, Time); - if (!m_bIsEVR || m_OrderedPaint) { - CalculateJitter(Time); - } - } - } - - // Create a device pointer m_pd3dDevice - - // Create a query object - { - CComPtr pEventQueryFlushAfterVSync; - m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQueryFlushAfterVSync); - - LONGLONG llPerf = rd->GetPerfCounter(); - CRect presentationSrcRect(rDstPri), presentationDestRect(m_windowRect); - // PresentEx() / Present() performs the clipping - // TODO: fix the race and uncomment the assert - //ASSERT(presentationSrcRect.Size() == presentationDestRect.Size()); - if (m_pD3DDevEx) { - if (m_bIsFullscreen) { - hr = m_pD3DDevEx->PresentEx(nullptr, nullptr, nullptr, nullptr, 0); - } else { - hr = m_pD3DDevEx->PresentEx(presentationSrcRect, presentationDestRect, nullptr, nullptr, 0); - } - } else { - if (m_bIsFullscreen) { - hr = m_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr); - } else { - hr = m_pD3DDev->Present(presentationSrcRect, presentationDestRect, nullptr, nullptr); - } - } - // Issue an End event - if (pEventQueryFlushAfterVSync) { - pEventQueryFlushAfterVSync->Issue(D3DISSUE_END); - } - - BOOL Data; - - if (r.m_AdvRendSets.bVMRFlushGPUAfterPresent && pEventQueryFlushAfterVSync) { - LONGLONG FlushStartTime = rd->GetPerfCounter(); - while (S_FALSE == pEventQueryFlushAfterVSync->GetData(&Data, sizeof(Data), D3DGETDATA_FLUSH)) { - if (!r.m_AdvRendSets.bVMRFlushGPUWait) { - break; - } - if (rd->GetPerfCounter() - FlushStartTime > 500000) { - break; // timeout after 50 ms - } - } - } - - int ScanLine; - int bInVBlank; - GetVBlank(ScanLine, bInVBlank, false); - - if (bAll && (!m_bIsEVR || m_OrderedPaint)) { - m_VBlankEndPresent = ScanLine; - } - - while (ScanLine == 0 || bInVBlank) { - GetVBlank(ScanLine, bInVBlank, false); - - } - m_VBlankStartMeasureTime = rd->GetPerfCounter(); - m_VBlankStartMeasure = ScanLine; - - if (bAll && bDoVSyncInPresent) { - m_PresentWaitTime = rd->GetPerfCounter() - llPerf; - m_PresentWaitTimeMin = std::min(m_PresentWaitTimeMin, m_PresentWaitTime); - m_PresentWaitTimeMax = std::max(m_PresentWaitTimeMax, m_PresentWaitTime); - } else { - m_PresentWaitTime = 0; - m_PresentWaitTimeMin = std::min(m_PresentWaitTimeMin, m_PresentWaitTime); - m_PresentWaitTimeMax = std::max(m_PresentWaitTimeMax, m_PresentWaitTime); - } - } - - if (bDoVSyncInPresent) { - LONGLONG Time = rd->GetPerfCounter(); - if (!m_bIsEVR || m_OrderedPaint) { - CalculateJitter(Time); - } - OnVBlankFinished(bAll, Time); - } - - if (lockOwner) { - UnlockD3DDevice(lockOwner); - } - - /*if (!bWaited) - { - bWaited = true; - WaitForVBlank(bWaited); - TRACE(_T("Double VBlank\n")); - ASSERT(bWaited); - if (!bDoVSyncInPresent) - { - CalculateJitter(); - OnVBlankFinished(bAll); - } - }*/ - - if (!m_bPendingResetDevice) { - bool fResetDevice = false; - - if (hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { - TRACE(_T("Reset Device: D3D Device Lost\n")); - fResetDevice = true; - } - - if (hr == S_PRESENT_MODE_CHANGED) { - TRACE(_T("Reset Device: D3D Device mode changed\n")); - fResetDevice = true; - } - - if (SettingsNeedResetDevice(r)) { - TRACE(_T("Reset Device: settings changed\n")); - fResetDevice = true; - } - - bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - if ((bCompositionEnabled != 0) != m_bCompositionEnabled) { - if (m_bIsFullscreen) { - m_bCompositionEnabled = (bCompositionEnabled != 0); - } else { - TRACE(_T("Reset Device: DWM composition changed\n")); - fResetDevice = true; - } - } - - if (r.fResetDevice) { - LONGLONG time = rd->GetPerfCounter(); - if (time > m_LastAdapterCheck + 20000000) { // check every 2 sec. - m_LastAdapterCheck = time; -#ifdef _DEBUG - D3DDEVICE_CREATION_PARAMETERS Parameters; - if (SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))) { - ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter); - } -#endif - if (m_CurrentAdapter != GetAdapter(m_pD3D)) { - TRACE(_T("Reset Device: D3D adapter changed\n")); - fResetDevice = true; - } -#ifdef _DEBUG - else { - ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D))); - } -#endif - } - } - - if (fResetDevice) { - m_bPendingResetDevice = true; - SendResetRequest(); - } - } - - if (m_OrderedPaint) { - --m_OrderedPaint; - } else { - //if (m_bIsEVR) - // TRACE(_T("UNORDERED PAINT!!!!!!\n")); - } - return true; -} - -double CDX9AllocatorPresenter::GetFrameTime() const -{ - if (m_DetectedLock) { - return m_DetectedFrameTime; - } - - return m_rtTimePerFrame / 10000000.0; -} - -double CDX9AllocatorPresenter::GetFrameRate() const -{ - if (m_DetectedLock) { - return m_DetectedFrameRate; - } - - return 10000000.0 / m_rtTimePerFrame; -} - -void CDX9AllocatorPresenter::SendResetRequest() -{ - if (!m_bDeviceResetRequested) { - m_bDeviceResetRequested = true; - AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE); - } -} - -STDMETHODIMP_(bool) CDX9AllocatorPresenter::ResetDevice() -{ - TRACE(_T("ResetDevice\n")); - ASSERT(m_MainThreadId == GetCurrentThreadId()); - - // In VMR-9 deleting the surfaces before we are told to is bad ! - // Can't comment out this because CDX9AllocatorPresenter is used by EVR Custom - // Why is EVR using a presenter for DX9 anyway ?! - DeleteSurfaces(); - - if (m_pD3DEx) { - m_pD3DEx.Release(); - m_pD3D = nullptr; - Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); - if (m_pD3DEx) { - m_pD3D = m_pD3DEx; - } else { - ASSERT(FALSE); - m_bDeviceResetRequested = false; - return false; - } - } - - HRESULT hr; - CString Error; - // TODO: Report error messages here - - // In VMR-9 'AllocSurfaces' call is redundant afaik because - // 'CreateDevice' calls 'm_pIVMRSurfAllocNotify->ChangeD3DDevice' which in turn calls - // 'CVMR9AllocatorPresenter::InitializeDevice' which calls 'AllocSurfaces' - if (FAILED(hr = CreateDevice(Error)) || FAILED(hr = AllocSurfaces())) { - // TODO: We should probably pause player -#ifdef _DEBUG - Error += GetWindowsErrorMessage(hr, nullptr); - TRACE(_T("D3D Reset Error\n%ws\n\n"), Error.GetBuffer()); -#endif - m_bDeviceResetRequested = false; - return false; - } - OnResetDevice(); - m_bDeviceResetRequested = false; - m_bPendingResetDevice = false; - - return true; -} - -STDMETHODIMP_(bool) CDX9AllocatorPresenter::DisplayChange() -{ - m_bPendingResetDevice = true; - SendResetRequest(); - return true; -} - -void CDX9AllocatorPresenter::ResetStats() -{ - CRenderersData* rd = GetRenderersData(); - LONGLONG Time = rd->GetPerfCounter(); - - m_PaintTime = 0; - m_PaintTimeMin = 3000000000; - m_PaintTimeMax = 0; - - m_RasterStatusWaitTime = 0; - m_RasterStatusWaitTimeMin = 3000000000; - m_RasterStatusWaitTimeMax = 0; - - m_MinSyncOffset = 0; - m_MaxSyncOffset = 0; - m_fSyncOffsetAvr = 0; - m_fSyncOffsetStdDev = 0; - - CalculateJitter(Time); -} - -void CDX9AllocatorPresenter::InitStats() -{ - ASSERT(m_pD3DDev); - static LONG currentHeight = 0; - int newHeight = lround(FONT_HEIGHT * (double(m_windowRect.Width()) / REFERENCE_WIDTH)); - - if (m_pD3DXCreateFont && (!m_pFont || currentHeight != newHeight)) { - m_pFont = nullptr; - if (newHeight <= 0) { - ASSERT(FALSE); - } - m_pD3DXCreateFont(m_pD3DDev, newHeight, 0, newHeight < BOLD_THRESHOLD ? FW_NORMAL : FW_BOLD, - 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, - FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont); - currentHeight = newHeight; - } - - if (m_pD3DXCreateSprite && !m_pSprite) { - m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite); - } - - if (m_pD3DXCreateLine && !m_pLine) { - m_pD3DXCreateLine(m_pD3DDev, &m_pLine); - } -} - -void CDX9AllocatorPresenter::DrawStats() -{ - const CRenderersData* rd = GetRenderersData(); - - int iDetailedStats; - switch (rd->m_iDisplayStats) { - case 1: - iDetailedStats = 2; - break; - case 2: - iDetailedStats = 1; - break; - case 3: - iDetailedStats = 0; - break; - default: - ASSERT(FALSE); - return; - } - - InitStats(); - const float textScale = float(m_windowRect.Width()) / REFERENCE_WIDTH; - const int lineHeight = lround((FONT_HEIGHT + TEXT_PADDING) * textScale); - - if (m_pFont && m_pSprite) { - auto drawText = [&](CRect & rc, const CString & strText) { - D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f); - D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f); - - RECT shadowRect = rc; - OffsetRect(&shadowRect, 2, 2); - - // Draw shadow - m_pFont->DrawText(m_pSprite, strText, -1, &shadowRect, DT_NOCLIP, Color0); - // Draw text - m_pFont->DrawText(m_pSprite, strText, -1, rc, DT_NOCLIP, Color1); - rc.OffsetRect(0, lineHeight); - }; - - const CRenderersSettings& r = GetRenderersSettings(); - LONGLONG llMaxJitter = m_MaxJitter; - LONGLONG llMinJitter = m_MinJitter; - LONGLONG llMaxSyncOffset = m_MaxSyncOffset; - LONGLONG llMinSyncOffset = m_MinSyncOffset; - CRect rc(lineHeight, lineHeight, 0, 0); - - m_pSprite->Begin(D3DXSPRITE_ALPHABLEND); - CString strText; - if (iDetailedStats > 1) { - if (m_bIsEVR) { - strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s) (%7.3f ms = %.03f%s, %2.03f StdDev) Clock: %1.4f %%", - m_fAvrFps, - double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), - m_bInterlaced ? L"I" : L"P", GetFrameTime() * 1000.0, GetFrameRate(), - m_DetectedLock ? L" L" : L"", m_DetectedFrameTimeStdDev / 10000.0, - m_ModeratedTimeSpeed * 100.0); - } else { - strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s)", - m_fAvrFps, - double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), - m_bInterlaced ? L"I" : L"P"); - } - } else { - strText.Format(L"Frame rate : %7.03f (%.03f%s)", m_fAvrFps, GetFrameRate(), m_DetectedLock ? L" L" : L""); - } - drawText(rc, strText); - - if (iDetailedStats > 1) { - strText = _T("Settings : "); - - if (m_bIsEVR) { - strText += _T("EVR "); - } else { - strText += _T("VMR9 "); - } - - if (m_bIsFullscreen) { - strText += _T("FS "); - } - if (r.m_AdvRendSets.bVMR9FullscreenGUISupport) { - strText += _T("FSGui "); - } - - if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { - strText += _T("DisDC "); - } - - if (m_bColorManagement) { - strText += _T("ColorMan "); - } - - if (r.m_AdvRendSets.bVMRFlushGPUBeforeVSync) { - strText += _T("GPUFlushBV "); - } - if (r.m_AdvRendSets.bVMRFlushGPUAfterPresent) { - strText += _T("GPUFlushAP "); - } - - if (r.m_AdvRendSets.bVMRFlushGPUWait) { - strText += _T("GPUFlushWt "); - } - - if (r.m_AdvRendSets.bVMR9VSync) { - strText += _T("VS "); - } - if (r.m_AdvRendSets.bVMR9AlterativeVSync) { - strText += _T("AltVS "); - } - if (r.m_AdvRendSets.bVMR9VSyncAccurate) { - strText += _T("AccVS "); - } - if (r.m_AdvRendSets.iVMR9VSyncOffset) { - strText.AppendFormat(_T("VSOfst(%d)"), r.m_AdvRendSets.iVMR9VSyncOffset); - } - - if (m_bFullFloatingPointProcessing) { - strText += _T("FullFP "); - } - - if (m_bHalfFloatingPointProcessing) { - strText += _T("HalfFP "); - } - - if (m_bIsEVR) { - if (m_bHighColorResolution) { - strText += _T("10bitOut "); - } - if (m_bForceInputHighColorResolution) { - strText += _T("For10bitIn "); - } - if (r.m_AdvRendSets.bEVREnableFrameTimeCorrection) { - strText += _T("FTC "); - } - if (r.m_AdvRendSets.iEVROutputRange == 0) { - strText += _T("0-255 "); - } else if (r.m_AdvRendSets.iEVROutputRange == 1) { - strText += _T("16-235 "); - } - } - - - drawText(rc, strText); - - strText.Format(L"Formats : Surface %s Backbuffer %s Display %s Device %s %s", - GetD3DFormatStr(m_SurfaceType), GetD3DFormatStr(m_BackbufferType), - GetD3DFormatStr(m_DisplayType), m_pD3DDevEx ? L"D3DDevEx" : L"D3DDev", - m_D3DDevExError.IsEmpty() ? _T("") : (_T("D3DExError: ") + m_D3DDevExError).GetString()); - drawText(rc, strText); - - if (m_bIsEVR) { - if (r.m_AdvRendSets.bVMR9VSync) { - strText.Format(_T("Refresh rate : %.05f Hz SL: %4d (%3u Hz) "), - m_DetectedRefreshRate, int(m_DetectedScanlinesPerFrame + 0.5), m_refreshRate); - } else { - strText.Format(_T("Refresh rate : %3u Hz "), m_refreshRate); - } - strText.AppendFormat(_T("Last Duration: %10.6f Corrected Frame Time: %s"), - double(m_LastFrameDuration) / 10000.0, m_bCorrectedFrameTime ? _T("Yes") : _T("No")); - drawText(rc, strText); - } - } - - if (m_bSyncStatsAvailable) { - if (iDetailedStats > 1) { - strText.Format(_T("Sync offset : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms, Avr = %7.3f ms, Mode = %d"), - (double(llMinSyncOffset) / 10000.0), (double(llMaxSyncOffset) / 10000.0), - m_fSyncOffsetStdDev / 10000.0, m_fSyncOffsetAvr / 10000.0, m_VSyncMode); - } else { - strText.Format(_T("Sync offset : Mode = %d"), m_VSyncMode); - } - drawText(rc, strText); - } - - if (iDetailedStats > 1) { - strText.Format(_T("Jitter : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms"), - (double(llMinJitter) / 10000.0), - (double(llMaxJitter) / 10000.0), - m_fJitterStdDev / 10000.0); - drawText(rc, strText); - } - - if (m_pAllocator && iDetailedStats > 1) { - CDX9SubPicAllocator* pAlloc = (CDX9SubPicAllocator*)m_pAllocator.p; - int nFree = 0; - int nAlloc = 0; - int nSubPic = 0; - REFERENCE_TIME rtQueueStart = 0; - REFERENCE_TIME rtQueueEnd = 0; - - if (m_pSubPicQueue) { - REFERENCE_TIME rtQueueNow = 0; - m_pSubPicQueue->GetStats(nSubPic, rtQueueNow, rtQueueStart, rtQueueEnd); - } - - pAlloc->GetStats(nFree, nAlloc); - strText.Format(_T("Subtitles : Free %d Allocated %d Buffered %d QueueStart %7.3f QueueEnd %7.3f"), - nFree, nAlloc, nSubPic, (double(rtQueueStart) / 10000000.0), - (double(rtQueueEnd) / 10000000.0)); - drawText(rc, strText); - } - - if (iDetailedStats > 1) { - if (m_VBlankEndPresent == -100000) { - strText.Format(_T("VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d"), - m_VBlankStartWait, m_VBlankEndWait, - (double(m_VBlankWaitTime) / 10000.0), - (double(m_VBlankLockTime) / 10000.0), - m_VBlankMin, m_VBlankMax - m_VBlankMin); - } else { - strText.Format(_T("VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d EndPresent %4d"), - m_VBlankStartWait, m_VBlankEndWait, - (double(m_VBlankWaitTime) / 10000.0), - (double(m_VBlankLockTime) / 10000.0), - m_VBlankMin, - m_VBlankMax - m_VBlankMin, - m_VBlankEndPresent); - } - } else { - if (m_VBlankEndPresent == -100000) { - strText.Format(_T("VBlank Wait : Start %4d End %4d"), m_VBlankStartWait, m_VBlankEndWait); - } else { - strText.Format(_T("VBlank Wait : Start %4d End %4d EP %4d"), m_VBlankStartWait, m_VBlankEndWait, - m_VBlankEndPresent); - } - } - drawText(rc, strText); - - BOOL bCompositionEnabled = m_bCompositionEnabled; - - bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !r.m_AdvRendSets.bVMR9VSync; - - if (iDetailedStats > 1 && bDoVSyncInPresent) { - strText.Format(_T("Present Wait : Wait %7.3f ms Min %7.3f ms Max %7.3f ms"), - (double(m_PresentWaitTime) / 10000.0), - (double(m_PresentWaitTimeMin) / 10000.0), - (double(m_PresentWaitTimeMax) / 10000.0)); - drawText(rc, strText); - } - - if (iDetailedStats > 1) { - if (m_WaitForGPUTime) { - strText.Format(_T("Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms GPU %7.3f ms"), - (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), - (double(m_PaintTimeMin) / 10000.0), - (double(m_PaintTimeMax) / 10000.0), - (double(m_WaitForGPUTime) / 10000.0)); - } else { - strText.Format(_T("Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms"), - (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), - (double(m_PaintTimeMin) / 10000.0), - (double(m_PaintTimeMax) / 10000.0)); - } - } else { - if (m_WaitForGPUTime) { - strText.Format(_T("Paint Time : Draw %7.3f ms GPU %7.3f ms"), - (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), - (double(m_WaitForGPUTime) / 10000.0)); - } else { - strText.Format(_T("Paint Time : Draw %7.3f ms"), - (double(m_PaintTime - m_WaitForGPUTime) / 10000.0)); - } - } - drawText(rc, strText); - - if (iDetailedStats > 1 && r.m_AdvRendSets.bVMR9VSync) { - strText.Format(_T("Raster Status: Wait %7.3f ms Min %7.3f ms Max %7.3f ms"), - (double(m_RasterStatusWaitTime) / 10000.0), - (double(m_RasterStatusWaitTimeMin) / 10000.0), - (double(m_RasterStatusWaitTimeMax) / 10000.0)); - drawText(rc, strText); - } - - if (iDetailedStats > 1) { - if (m_bIsEVR) { - strText.Format(_T("Buffering : Buffered %3ld Free %3ld Current Surface %3d"), - m_nUsedBuffer, m_nNbDXSurface - m_nUsedBuffer, m_nCurSurface); - } else { - strText.Format(_T("Buffering : VMR9Surfaces %3d VMR9Surface %3d"), - m_nVMR9Surfaces, m_iVMR9Surface); - } - } else { - strText.Format(_T("Buffered : %3ld"), m_nUsedBuffer); - } - drawText(rc, strText); - - - if (iDetailedStats > 1) { - strText.Format(_T("Video size : %ld x %ld (AR = %ld : %ld)"), - m_nativeVideoSize.cx, m_nativeVideoSize.cy, m_aspectRatio.cx, m_aspectRatio.cy); - drawText(rc, strText); - if (m_pVideoTexture[0] || m_pVideoSurface[0]) { - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (m_pVideoTexture[0]) { - m_pVideoTexture[0]->GetLevelDesc(0, &desc); - } else if (m_pVideoSurface[0]) { - m_pVideoSurface[0]->GetDesc(&desc); - } - - if (desc.Width != (UINT)m_nativeVideoSize.cx || desc.Height != (UINT)m_nativeVideoSize.cy) { - strText.Format(_T("Texture size : %u x %u"), desc.Width, desc.Height); - drawText(rc, strText); - } - } - - - drawText(rc, rd->m_strDXVAInfo); - - strText.Format(_T("DirectX SDK : %u"), rd->GetDXSdkRelease()); - drawText(rc, strText); - - if (!m_D3D9Device.IsEmpty()) { - strText = _T("Render device: ") + m_D3D9Device; - drawText(rc, strText); - } - - if (!m_Decoder.IsEmpty()) { - strText = _T("Decoder : ") + m_Decoder; - drawText(rc, strText); - } - - for (int i = 0; i < 6; i++) { - if (m_strStatsMsg[i][0]) { - drawText(rc, m_strStatsMsg[i]); - } - } - } - m_pSprite->End(); - } - - if (m_pLine && iDetailedStats) { - D3DXVECTOR2 points[NB_JITTER]; - const float graphWidth = GRAPH_WIDTH * textScale; - const float graphHeight = GRAPH_HEIGHT * textScale; - const float topLeftX = m_windowRect.Width() - (graphWidth + lineHeight); - const float topLeftY = m_windowRect.Height() - (graphHeight + lineHeight); - const float gridStepY = graphHeight / 24.0f; - const float gridStepX = graphWidth / NB_JITTER; - - // Draw background - DrawRect(RGB(0, 0, 0), 80, CRect(int(topLeftX), - int(topLeftY), - int(topLeftX + graphWidth), - int(topLeftY + graphHeight))); - - m_pLine->SetWidth(2.5f * textScale); - m_pLine->SetAntialias(TRUE); - m_pLine->Begin(); - - // Draw grid lines - for (int i = 1; i < 24; ++i) { - points[0].x = topLeftX; - points[0].y = topLeftY + i * gridStepY; - points[1].y = points[0].y; - - float lineLength; - D3DCOLOR color; - if (i % 12 == 0) { - lineLength = 1.0f; - color = D3DCOLOR_XRGB(100, 100, 255); - } else if (i % 4 == 0) { - lineLength = 0.96f; - color = D3DCOLOR_XRGB(100, 100, 180); - } else { - lineLength = 0.04f; - color = D3DCOLOR_XRGB(100, 100, 140); - } - points[1].x = topLeftX + graphWidth * lineLength; - m_pLine->Draw(points, 2, color); - } - - if (m_rtTimePerFrame) { - // Draw jitter - for (int i = 1; i <= NB_JITTER; ++i) { - int nIndex = (m_nNextJitter + i) % NB_JITTER; - if (nIndex < 0) { - nIndex += NB_JITTER; - ASSERT(FALSE); - } - float jitter = float(m_pllJitter[nIndex] - m_fJitterMean); - points[i - 1].x = topLeftX + i * gridStepX; - points[i - 1].y = topLeftY + (jitter * textScale / 2000.0f + graphHeight / 2.0f); - } - m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100)); - - if (m_bSyncStatsAvailable) { - // Draw sync offset - for (int i = 1; i <= NB_JITTER; ++i) { - int nIndex = (m_nNextSyncOffset + i) % NB_JITTER; - if (nIndex < 0) { - nIndex += NB_JITTER; - } - points[i - 1].x = topLeftX + i * gridStepX; - points[i - 1].y = topLeftY + (m_pllSyncOffset[nIndex] * textScale / 2000.0f + graphHeight / 2.0f); - } - m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100)); - } - } - m_pLine->End(); - } -} - -STDMETHODIMP CDX9AllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) -{ - CheckPointer(size, E_POINTER); - - // Keep a reference so that we can safely work on the surface - // without having to lock everything - CComPtr pVideoSurface; - { - CAutoLock cAutoLock(this); - CheckPointer(m_pVideoSurface[m_nCurSurface], E_FAIL); - pVideoSurface = m_pVideoSurface[m_nCurSurface]; - } - - HRESULT hr; - - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(hr = pVideoSurface->GetDesc(&desc))) { - return hr; - } - - CSize framesize = GetVideoSize(false); - const CSize dar = GetVideoSize(true); - - bool resize = false; - if (dar.cx > 0 && dar.cy > 0 && (dar.cx != desc.Width || dar.cy != desc.Height)) { - framesize.cx = MulDiv(framesize.cy, dar.cx, dar.cy); - resize = true; - desc.Width = framesize.cx; - desc.Height = framesize.cy; - } - - DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3); - if (!lpDib) { - *size = required; - return S_OK; - } - if (*size < required) { - return E_OUTOFMEMORY; - } - *size = required; - - CComPtr pSurface, tSurface; - // Convert to 8-bit when using 10-bit or full/half processing modes - if (desc.Format != D3DFMT_X8R8G8B8) { - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tSurface, nullptr)) - || FAILED(hr = m_pD3DXLoadSurfaceFromSurface(tSurface, nullptr, nullptr, pVideoSurface, nullptr, nullptr, D3DX_DEFAULT, 0))) { - return hr; - } - } else { - tSurface = pVideoSurface; - } - - if (resize) { - CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; - if (FAILED(hr = m_pD3DDevEx->CreateRenderTarget(framesize.cx, framesize.cy, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurface, nullptr)) - || FAILED(hr = m_pD3DDevEx->SetRenderTarget(0, pSurface)) - || FAILED(hr = Resize(pVideoTexture, { CPoint(0, 0), m_nativeVideoSize }, { CPoint(0, 0), framesize }))) { - return hr; - } - } else { - pSurface = tSurface; - } - - D3DLOCKED_RECT r; - if (FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { - // If this fails, we try to use a surface allocated from the system memory - CComPtr pInputSurface = pSurface; - pSurface = nullptr; - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, nullptr)) - || FAILED(hr = m_pD3DDev->GetRenderTargetData(pInputSurface, pSurface)) - || FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { - return hr; - } - } - - hr = CreateDIBFromSurfaceData(desc, r, lpDib); - - pSurface->UnlockRect(); - - return hr; -} - -STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) -{ - return SetPixelShader2(pSrcData, pTarget, false); -} - -STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) -{ - CAutoLock cRenderLock(&m_RenderLock); - - return SetCustomPixelShader(pSrcData, pTarget, bScreenSpace); -} - -STDMETHODIMP CDX9AllocatorPresenter::SetD3DFullscreen(bool fEnabled) -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - fullScreenChanged = (fEnabled != m_bIsFullscreen); - m_bIsFullscreen = fEnabled; - return S_OK; -} - -STDMETHODIMP CDX9AllocatorPresenter::GetD3DFullscreen(bool* pfEnabled) -{ - CheckPointer(pfEnabled, E_POINTER); - *pfEnabled = m_bIsFullscreen; - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "RenderersSettings.h" +#include "DX9AllocatorPresenter.h" +#include +#include "../../../SubPic/DX9SubPic.h" +#include "../../../SubPic/SubPicQueueImpl.h" +#include "IPinHook.h" +#include "FocusThread.h" +#include "../../../DSUtil/vd.h" +#include + +#define FRAMERATE_MAX_DELTA 3000 + +#define REFERENCE_WIDTH 1920 +#define FONT_HEIGHT 21 +#define BOLD_THRESHOLD 11 +#define TEXT_PADDING 2 +#define GRAPH_HEIGHT 360 +#define GRAPH_WIDTH 1000 + +using namespace DSObjects; + +#pragma warning(push) +#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized +// CDX9AllocatorPresenter +CDX9AllocatorPresenter::CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString& _Error, bool isPreview) + : CDX9RenderingEngine(hWnd, hr, &_Error) + , m_bAlternativeVSync(false) + , m_bCompositionEnabled(false) + , m_bIsEVR(bIsEVR) + , m_OrderedPaint(0) + , m_VSyncMode(0) + , m_bDesktopCompositionDisabled(false) + , m_bIsFullscreen(bFullscreen) + , fullScreenChanged(false) + , m_bNeedCheckSample(true) + , m_MainThreadId(0) + , m_bIsRendering(false) + , m_hDWMAPI(nullptr) + , m_pDwmIsCompositionEnabled(nullptr) + , m_pDwmEnableComposition(nullptr) + , m_pDirectDraw(nullptr) + , m_LastAdapterCheck(0) + , m_nTearingPos(0) + , m_VMR9AlphaBitmapWidthBytes(0) + , m_pD3DXLoadSurfaceFromMemory(nullptr) + , m_pD3DXLoadSurfaceFromSurface(nullptr) + , m_pD3DXCreateLine(nullptr) + , m_pD3DXCreateFont(nullptr) + , m_pD3DXCreateSprite(nullptr) + , m_nVMR9Surfaces(0) + , m_iVMR9Surface(0) + , m_nUsedBuffer(0) + , m_fAvrFps(0.0) + , m_fJitterStdDev(0.0) + , m_fJitterMean(0.0) + , m_fSyncOffsetStdDev(0.0) + , m_fSyncOffsetAvr(0.0) + , m_DetectedRefreshRate(0) + , m_DetectedRefreshTime(0.0) + , m_DetectedRefreshTimePrim(0) + , m_DetectedScanlineTime(0) + , m_DetectedScanlineTimePrim(0) + , m_DetectedScanlinesPerFrame(0.0) + , m_ldDetectedRefreshRateList() + , m_ldDetectedScanlineRateList() + , m_DetectedRefreshRatePos(0) + , m_bSyncStatsAvailable(false) + , m_pllJitter() + , m_pllSyncOffset() + , m_llLastPerf(0) + , m_JitterStdDev(0) + , m_MaxJitter(MINLONG64) + , m_MinJitter(MAXLONG64) + , m_MaxSyncOffset(0) + , m_MinSyncOffset(0) + , m_nNextJitter(0) + , m_nNextSyncOffset(0) + , m_rtTimePerFrame(0) + , m_DetectedFrameRate(0.0) + , m_DetectedFrameTime(0.0) + , m_DetectedFrameTimeStdDev(0.0) + , m_DetectedLock(false) + , m_DetectedFrameTimeHistory() + , m_DetectedFrameTimeHistoryHistory() + , m_DetectedFrameTimePos(0) + , m_bInterlaced(false) + , m_VBlankEndWait(0) + , m_VBlankStartWait(0) + , m_VBlankWaitTime(0) + , m_VBlankLockTime(0) + , m_VBlankMin(300000) + , m_VBlankMinCalc(300000) + , m_VBlankMax(0) + , m_VBlankEndPresent(-100000) + , m_VBlankStartMeasureTime(0) + , m_VBlankStartMeasure(0) + , m_PresentWaitTime(0) + , m_PresentWaitTimeMin(3000000000) + , m_PresentWaitTimeMax(0) + , m_PaintTime(0) + , m_PaintTimeMin(3000000000) + , m_PaintTimeMax(0) + , m_WaitForGPUTime(0) + , m_RasterStatusWaitTime(0) + , m_RasterStatusWaitTimeMin(3000000000) + , m_RasterStatusWaitTimeMax(0) + , m_RasterStatusWaitTimeMaxCalc(0) + , m_ClockDiffCalc(0.0) + , m_ClockDiffPrim(0.0) + , m_ClockDiff(0.0) + , m_TimeChangeHistory() + , m_ClockChangeHistory() + , m_ClockTimeChangeHistoryPos(0) + , m_ModeratedTimeSpeed(1.0) + , m_ModeratedTimeSpeedPrim(0.0) + , m_ModeratedTimeSpeedDiff(0.0) + , m_bCorrectedFrameTime(0) + , m_FrameTimeCorrection(0) + , m_LastFrameDuration(0) + , m_LastSampleTime(0) + , m_FocusThread(nullptr) + , m_hFocusWindow(nullptr) + , m_bIsPreview(isPreview) +{ + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + + if (FAILED(hr)) { + _Error += _T("ISubPicAllocatorPresenterImpl failed\n"); + return; + } + + HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); + + if (hDll) { + (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory"); + (FARPROC&)m_pD3DXLoadSurfaceFromSurface = GetProcAddress(hDll, "D3DXLoadSurfaceFromSurface"); + (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine"); + (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW"); + (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite"); + } else { + _Error += _T("Your system is missing the file d3dx9_43.dll\n\nTo acquire this file you must install \"DirectX End-User Runtime\" or update your MPC-HC installation."); + } + + m_hDWMAPI = LoadLibrary(L"dwmapi.dll"); + if (m_hDWMAPI) { + (FARPROC&)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled"); + (FARPROC&)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition"); + } + + Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); + if (m_pD3DEx) { + m_pD3D = m_pD3DEx; + } + + const CRenderersSettings& r = GetRenderersSettings(); + + if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { + m_bDesktopCompositionDisabled = true; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(0); + } + } else { + m_bDesktopCompositionDisabled = false; + } + + hr = CreateDevice(_Error); +} +#pragma warning(pop) + +CDX9AllocatorPresenter::~CDX9AllocatorPresenter() +{ + if (m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = false; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(1); + } + } + + m_pFont = nullptr; + m_pLine = nullptr; + m_pSprite = nullptr; + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + + m_pAlphaBitmapTexture.Release(); + CleanupRenderingEngine(); + + m_pD3D = nullptr; + m_pD3DEx = nullptr; + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + + if (m_FocusThread) { + m_FocusThread->PostThreadMessage(WM_QUIT, 0, 0); + if (WaitForSingleObject(m_FocusThread->m_hThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_FocusThread->m_hThread, 0xDEAD); + } + } + + if (m_hDWMAPI) { + FreeLibrary(m_hDWMAPI); + m_hDWMAPI = nullptr; + } +} + +void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed); + +#if 0 +class CRandom31 +{ +public: + + CRandom31() { + m_Seed = 12164; + } + + void f_SetSeed(int32 _Seed) { + m_Seed = _Seed; + } + int32 f_GetSeed() { + return m_Seed; + } + /* + Park and Miller's psuedo-random number generator. + */ + int32 m_Seed; + int32 f_Get() { + static const int32 A = 16807; + static const int32 M = 2147483647; // 2^31 - 1 + static const int32 q = M / A; // M / A + static const int32 r = M % A; // M % A + m_Seed = A * (m_Seed % q) - r * (m_Seed / q); + if (m_Seed < 0) { + m_Seed += M; + } + return m_Seed; + } + + static int32 fs_Max() { + return 2147483646; + } + + double f_GetFloat() { + return double(f_Get()) * (1.0 / double(fs_Max())); + } +}; + +class CVSyncEstimation +{ +private: + class CHistoryEntry + { + public: + CHistoryEntry() { + m_Time = 0; + m_ScanLine = -1; + } + LONGLONG m_Time; + int m_ScanLine; + }; + + class CSolution + { + public: + CSolution() { + m_ScanLines = 1000; + m_ScanLinesPerSecond = m_ScanLines * 100; + } + int m_ScanLines; + double m_ScanLinesPerSecond; + double m_SqrSum; + + void f_Mutate(double _Amount, CRandom31& _Random, int _MinScans) { + int ToDo = _Random.f_Get() % 10; + if (ToDo == 0) { + m_ScanLines = m_ScanLines / 2; + } else if (ToDo == 1) { + m_ScanLines = m_ScanLines * 2; + } + + m_ScanLines = m_ScanLines * (1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5); + m_ScanLines = max(m_ScanLines, _MinScans); + + if (ToDo == 2) { + m_ScanLinesPerSecond /= (_Random.f_Get() % 4) + 1; + } else if (ToDo == 3) { + m_ScanLinesPerSecond *= (_Random.f_Get() % 4) + 1; + } + + m_ScanLinesPerSecond *= 1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5; + } + + void f_SpawnInto(CSolution& _Other, CRandom31& _Random, int _MinScans) { + _Other = *this; + _Other.f_Mutate(_Random.f_GetFloat() * 0.1, _Random, _MinScans); + } + + static int fs_Compare(const void* _pFirst, const void* _pSecond) { + const CSolution* pFirst = (const CSolution*)_pFirst; + const CSolution* pSecond = (const CSolution*)_pSecond; + if (pFirst->m_SqrSum < pSecond->m_SqrSum) { + return -1; + } else if (pFirst->m_SqrSum > pSecond->m_SqrSum) { + return 1; + } + return 0; + } + + + }; + + enum { + ENumHistory = 128 + }; + + CHistoryEntry m_History[ENumHistory]; + int m_iHistory; + CSolution m_OldSolutions[2]; + + CRandom31 m_Random; + + + double fp_GetSquareSum(double _ScansPerSecond, double _ScanLines) { + double SquareSum = 0; + int nHistory = min(m_nHistory, ENumHistory); + int iHistory = m_iHistory - nHistory; + if (iHistory < 0) { + iHistory += ENumHistory; + } + for (int i = 1; i < nHistory; ++i) { + int iHistory0 = iHistory + i - 1; + int iHistory1 = iHistory + i; + if (iHistory0 < 0) { + iHistory0 += ENumHistory; + } + iHistory0 = iHistory0 % ENumHistory; + iHistory1 = iHistory1 % ENumHistory; + ASSERT(m_History[iHistory0].m_Time != 0); + ASSERT(m_History[iHistory1].m_Time != 0); + + double DeltaTime = (m_History[iHistory1].m_Time - m_History[iHistory0].m_Time) / 10000000.0; + double PredictedScanLine = m_History[iHistory0].m_ScanLine + DeltaTime * _ScansPerSecond; + PredictedScanLine = fmod(PredictedScanLine, _ScanLines); + double Delta = (m_History[iHistory1].m_ScanLine - PredictedScanLine); + double DeltaSqr = Delta * Delta; + SquareSum += DeltaSqr; + } + return SquareSum; + } + + int m_nHistory; +public: + + CVSyncEstimation() { + m_iHistory = 0; + m_nHistory = 0; + } + + void f_AddSample(int _ScanLine, LONGLONG _Time) { + m_History[m_iHistory].m_ScanLine = _ScanLine; + m_History[m_iHistory].m_Time = _Time; + ++m_nHistory; + m_iHistory = (m_iHistory + 1) % ENumHistory; + } + + void f_GetEstimation(double& _RefreshRate, int& _ScanLines, int _ScreenSizeY, int _WindowsRefreshRate) { + _RefreshRate = 0; + _ScanLines = 0; + + int iHistory = m_iHistory; + // We have a full history + if (m_nHistory > 10) { + for (int l = 0; l < 5; ++l) { + const int nSol = 3 + 5 + 5 + 3; + CSolution Solutions[nSol]; + + Solutions[0] = m_OldSolutions[0]; + Solutions[1] = m_OldSolutions[1]; + Solutions[2].m_ScanLines = _ScreenSizeY; + Solutions[2].m_ScanLinesPerSecond = _ScreenSizeY * _WindowsRefreshRate; + + int iStart = 3; + for (int i = iStart; i < iStart + 5; ++i) { + Solutions[0].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); + } + iStart += 5; + for (int i = iStart; i < iStart + 5; ++i) { + Solutions[1].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); + } + iStart += 5; + for (int i = iStart; i < iStart + 3; ++i) { + Solutions[2].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY); + } + + int Start = 2; + if (l == 0) { + Start = 0; + } + for (int i = Start; i < nSol; ++i) { + Solutions[i].m_SqrSum = fp_GetSquareSum(Solutions[i].m_ScanLinesPerSecond, Solutions[i].m_ScanLines); + } + + qsort(Solutions, nSol, sizeof(Solutions[0]), &CSolution::fs_Compare); + for (int i = 0; i < 2; ++i) { + m_OldSolutions[i] = Solutions[i]; + } + } + + _ScanLines = m_OldSolutions[0].m_ScanLines + 0.5; + _RefreshRate = 1.0 / (m_OldSolutions[0].m_ScanLines / m_OldSolutions[0].m_ScanLinesPerSecond); + } else { + m_OldSolutions[0].m_ScanLines = _ScreenSizeY; + m_OldSolutions[1].m_ScanLines = _ScreenSizeY; + } + } +}; +#endif + +bool CDX9AllocatorPresenter::SettingsNeedResetDevice(CRenderersSettings& r) +{ + CRenderersSettings::CAdvRendererSettings& New = r.m_AdvRendSets; + CRenderersSettings::CAdvRendererSettings& Current = m_LastRendererSettings; + + bool bRet = false; + + bRet = bRet || New.bVMR9AlterativeVSync != Current.bVMR9AlterativeVSync; + bRet = bRet || New.bVMR9VSyncAccurate != Current.bVMR9VSyncAccurate; + + if (m_bIsFullscreen) { + bRet = bRet || New.bVMR9FullscreenGUISupport != Current.bVMR9FullscreenGUISupport; + } else { + if (Current.bVMRDisableDesktopComposition) { + if (!m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = true; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(0); + } + } + } else { + if (m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = false; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(1); + } + } + } + } + + if (m_bIsEVR) { + bRet = bRet || New.bEVRHighColorResolution != Current.bEVRHighColorResolution; + bRet = bRet || New.bEVRForceInputHighColorResolution != Current.bEVRForceInputHighColorResolution; + } + + m_LastRendererSettings = r.m_AdvRendSets; + + return bRet; +} + +HRESULT CDX9AllocatorPresenter::CreateDevice(CString& _Error) +{ + const CRenderersSettings& r = GetRenderersSettings(); + CRenderersData* rd = GetRenderersData(); + + m_VBlankEndWait = 0; + m_VBlankMin = 300000; + m_VBlankMinCalc = 300000; + m_VBlankMax = 0; + m_VBlankStartWait = 0; + m_VBlankWaitTime = 0; + m_VBlankLockTime = 0; + m_PresentWaitTime = 0; + m_PresentWaitTimeMin = 3000000000; + m_PresentWaitTimeMax = 0; + + m_LastRendererSettings = r.m_AdvRendSets; + + m_VBlankEndPresent = -100000; + m_VBlankStartMeasureTime = 0; + m_VBlankStartMeasure = 0; + + m_PaintTime = 0; + m_PaintTimeMin = 3000000000; + m_PaintTimeMax = 0; + + m_RasterStatusWaitTime = 0; + m_RasterStatusWaitTimeMin = 3000000000; + m_RasterStatusWaitTimeMax = 0; + m_RasterStatusWaitTimeMaxCalc = 0; + + m_ClockDiff = 0.0; + m_ClockDiffPrim = 0.0; + m_ClockDiffCalc = 0.0; + + m_ModeratedTimeSpeed = 1.0; + m_ModeratedTimeSpeedDiff = 0.0; + m_ModeratedTimeSpeedPrim = 0; + ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory)); + ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory)); + m_ClockTimeChangeHistoryPos = 0; + + m_pSprite = nullptr; + m_pLine = nullptr; + m_pFont = nullptr; + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + m_pDirectDraw = nullptr; + + m_bAlphaBitmapEnable = false; + m_pAlphaBitmapTexture.Release(); + ZeroMemory(&m_AlphaBitmapParams, sizeof(m_AlphaBitmapParams)); + + CleanupRenderingEngine(); + + UINT currentAdapter = GetAdapter(m_pD3D); + bool bTryToReset = (currentAdapter == m_CurrentAdapter); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + m_CurrentAdapter = currentAdapter; + } + + if (!m_pD3D) { + _Error += L"Failed to create D3D9\n"; + return E_UNEXPECTED; + } + + HRESULT hr = S_OK; + + /*// TODO : add NVIDIA PerfHUD !!! + + // Set default settings + UINT AdapterToUse=D3DADAPTER_DEFAULT; + D3DDEVTYPE DeviceType=D3DDEVTYPE_HAL; + + #if SHIPPING_VERSION + // When building a shipping version, disable PerfHUD (opt-out) + #else + // Look for 'NVIDIA PerfHUD' adapter + // If it is present, override default settings + for (UINT Adapter=0;AdapterGetAdapterCount();Adapter++) + { + D3DADAPTER_IDENTIFIER9 Identifier; + HRESULT Res; + + Res = g_pD3D->GetAdapterIdentifier(Adapter,0,&Identifier); + if (strstr(Identifier.Description,"PerfHUD") != 0) + { + AdapterToUse=Adapter; + DeviceType=D3DDEVTYPE_REF; + break; + } + } + #endif + + if (FAILED(g_pD3D->CreateDevice( AdapterToUse, DeviceType, hWnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING, + &d3dpp, &g_pd3dDevice) ) ) + { + return E_FAIL; + } + */ + + + //#define ENABLE_DDRAWSYNC +#ifdef ENABLE_DDRAWSYNC + hr = DirectDrawCreate(nullptr, &m_pDirectDraw, nullptr); + if (hr == S_OK) { + hr = m_pDirectDraw->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL); + } +#endif + + D3DPRESENT_PARAMETERS pp; + ZeroMemory(&pp, sizeof(pp)); + + BOOL bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + + m_bCompositionEnabled = !!bCompositionEnabled; + m_bAlternativeVSync = r.m_AdvRendSets.bVMR9AlterativeVSync; + + // detect FP16 textures support + rd->m_bFP16Support = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_VOLUMETEXTURE, D3DFMT_A16B16G16R16F)); + + // detect FP32 textures support + rd->m_bFP32Support = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_VOLUMETEXTURE, D3DFMT_A32B32G32R32F)); + + // detect 10-bit textures support + rd->m_b10bitSupport = SUCCEEDED(m_pD3D->CheckDeviceFormat(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, D3DFMT_A2R10G10B10)); + + // detect 10-bit device support + bool bHighColorSupport = SUCCEEDED(m_pD3D->CheckDeviceType(m_CurrentAdapter, D3DDEVTYPE_HAL, D3DFMT_A2R10G10B10, D3DFMT_A2R10G10B10, FALSE)); + + // set settings that depend on hardware feature support + m_bForceInputHighColorResolution = r.m_AdvRendSets.bEVRForceInputHighColorResolution && m_bIsEVR && rd->m_b10bitSupport; + m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution && m_bIsEVR && rd->m_b10bitSupport && bHighColorSupport; + m_bFullFloatingPointProcessing = r.m_AdvRendSets.bVMR9FullFloatingPointProcessing && rd->m_bFP32Support; + m_bHalfFloatingPointProcessing = r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing && rd->m_bFP16Support && !m_bFullFloatingPointProcessing; + + // set color formats + if (m_bFullFloatingPointProcessing) { + m_SurfaceType = D3DFMT_A32B32G32R32F; + } else if (m_bHalfFloatingPointProcessing) { + m_SurfaceType = D3DFMT_A16B16G16R16F; + } else if (m_bForceInputHighColorResolution || m_bHighColorResolution) { + m_SurfaceType = D3DFMT_A2R10G10B10; + } else { + m_SurfaceType = D3DFMT_X8R8G8B8; + } + + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + + D3DDISPLAYMODEEX DisplayMode; + ZeroMemory(&DisplayMode, sizeof(DisplayMode)); + DisplayMode.Size = sizeof(DisplayMode); + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + + if (m_bIsFullscreen) { + if (m_bHighColorResolution) { + pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } else { + pp.BackBufferFormat = D3DFMT_X8R8G8B8; + } + pp.Windowed = false; + pp.BackBufferCount = 3; + pp.SwapEffect = D3DSWAPEFFECT_FLIP; + // there's no Desktop composition to take care of alternative vSync in exclusive mode, alternative vSync is therefore unused + pp.hDeviceWindow = m_hWnd; + pp.Flags = D3DPRESENTFLAG_VIDEO; + if (r.m_AdvRendSets.bVMR9FullscreenGUISupport && !m_bHighColorResolution) { + pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + } + m_D3DDevExError = _T("No m_pD3DEx"); + + if (!m_FocusThread) { + m_FocusThread = (CFocusThread*)AfxBeginThread(RUNTIME_CLASS(CFocusThread), 0, 0, 0); + } + + HWND hFocusWindow = m_FocusThread->GetFocusWindow(); + bTryToReset &= (m_hFocusWindow == hFocusWindow || fullScreenChanged); + m_hFocusWindow = hFocusWindow; + + if (m_pD3DEx) { + CHECK_HR(m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr)); + + m_ScreenSize.SetSize(DisplayMode.Width, DisplayMode.Height); + m_BackBufferSize = m_ScreenSize; + + DisplayMode.Format = pp.BackBufferFormat; + pp.FullScreen_RefreshRateInHz = m_refreshRate = DisplayMode.RefreshRate; + pp.BackBufferWidth = m_BackBufferSize.cx; + pp.BackBufferHeight = m_BackBufferSize.cy; + + bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&pp, &DisplayMode)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + hr = m_pD3DEx->CreateDeviceEx( + m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS | D3DCREATE_NOWINDOWCHANGES, //D3DCREATE_MANAGED + &pp, &DisplayMode, &m_pD3DDevEx); + } + + if (FAILED(hr)) { + m_D3DDevExError = GetWindowsErrorMessage(hr, nullptr); + } else { + m_D3DDevExError.Empty(); + } + + if (m_pD3DDevEx) { + m_pD3DDev = m_pD3DDevEx; + m_BackbufferType = pp.BackBufferFormat; + m_DisplayType = DisplayMode.Format; + } + } + if (bTryToReset && m_pD3DDev && !m_pD3DDevEx) { + if (FAILED(hr = m_pD3DDev->Reset(&pp))) { + m_pD3DDev = nullptr; + } + } + if (!m_pD3DDev) { + CHECK_HR(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)); + d3ddm.Format = pp.BackBufferFormat; + + m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); + m_BackBufferSize = m_ScreenSize; + + pp.FullScreen_RefreshRateInHz = m_refreshRate = d3ddm.RefreshRate; + pp.BackBufferWidth = m_BackBufferSize.cx; + pp.BackBufferHeight = m_BackBufferSize.cy; + + hr = m_pD3D->CreateDevice( + m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_NOWINDOWCHANGES, //D3DCREATE_MANAGED + &pp, &m_pD3DDev); + m_DisplayType = d3ddm.Format; + m_BackbufferType = pp.BackBufferFormat; + } + if (m_pD3DDev && r.m_AdvRendSets.bVMR9FullscreenGUISupport && !m_bHighColorResolution) { + m_pD3DDev->SetDialogBoxMode(true); + //if (m_pD3DDev->SetDialogBoxMode(true) != S_OK) + // ExitProcess(0); + } + } else { + pp.Windowed = TRUE; + pp.hDeviceWindow = m_hWnd; + pp.SwapEffect = D3DSWAPEFFECT_COPY; + pp.Flags = D3DPRESENTFLAG_VIDEO; + pp.BackBufferCount = 1; + if (bCompositionEnabled || m_bAlternativeVSync) { + // Desktop composition takes care of the VSYNC + pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } + + bTryToReset &= (m_hFocusWindow == m_hWnd || fullScreenChanged); + m_hFocusWindow = m_hWnd; + + if (m_pD3DEx) { + HRESULT getModeResult = m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); + + if (getModeResult == D3DERR_NOTAVAILABLE) { + m_pD3DEx = nullptr; + Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); + if (nullptr != m_pD3DEx) { + getModeResult = m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); + } + } + CHECK_HR(getModeResult); + + m_ScreenSize.SetSize(DisplayMode.Width, DisplayMode.Height); + m_refreshRate = DisplayMode.RefreshRate; + m_BackBufferSize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); + pp.BackBufferWidth = m_BackBufferSize.cx; + pp.BackBufferHeight = m_BackBufferSize.cy; + + bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&pp, nullptr)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + // We can get 0x8876086a here when switching from two displays to one display using Win + P (Windows 7) + // Cause: We might not reinitialize dx correctly during the switch + hr = m_pD3DEx->CreateDeviceEx( + m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS, //D3DCREATE_MANAGED + &pp, nullptr, &m_pD3DDevEx); + } + if (m_pD3DDevEx) { + m_pD3DDev = m_pD3DDevEx; + m_DisplayType = DisplayMode.Format; + } + } + if (bTryToReset && m_pD3DDev && !m_pD3DDevEx) { + if (FAILED(hr = m_pD3DDev->Reset(&pp))) { + m_pD3DDev = nullptr; + } + } + if (!m_pD3DDev) { + CHECK_HR(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)); + m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); + m_refreshRate = d3ddm.RefreshRate; + m_BackBufferSize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); + pp.BackBufferWidth = m_BackBufferSize.cx; + pp.BackBufferHeight = m_BackBufferSize.cy; + + hr = m_pD3D->CreateDevice( + m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + GetVertexProcessing() | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED + &pp, &m_pD3DDev); + m_DisplayType = d3ddm.Format; + } + m_BackbufferType = pp.BackBufferFormat; + } + + if (m_pD3DDev) { + while (hr == D3DERR_DEVICELOST) { + TRACE(_T("D3DERR_DEVICELOST. Trying to Reset.\n")); + hr = m_pD3DDev->TestCooperativeLevel(); + } + if (hr == D3DERR_DEVICENOTRESET) { + TRACE(_T("D3DERR_DEVICENOTRESET\n")); + hr = m_pD3DDev->Reset(&pp); + } + + if (m_pD3DDevEx) { + m_pD3DDevEx->SetGPUThreadPriority(7); + } + } + + if (FAILED(hr)) { + _Error += L"CreateDevice failed\n"; + CStringW str; + str.Format(L"Error code: 0x%X\n", hr); + _Error += str; + + return hr; + } + + ASSERT(m_pD3DDev); + + if (m_ScreenSize.cx <= 0 || m_ScreenSize.cy <= 0) { + _Error += L"Invalid screen size\n"; + return E_FAIL; + } + + m_MainThreadId = GetCurrentThreadId(); + + // Get the device caps + ZeroMemory(&m_Caps, sizeof(m_Caps)); + m_pD3DDev->GetDeviceCaps(&m_Caps); + + // Initialize the rendering engine + InitRenderingEngine(); + + if (!m_bIsPreview) { + CComPtr pSubPicProvider; + if (m_pSubPicQueue) { + m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); + } + + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(m_pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); + } + + hr = S_OK; + if (!m_pSubPicQueue) { + CAutoLock cAutoLock(this); + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + m_pSubPicQueue->Invalidate(); + } + + if (FAILED(hr)) { + _Error += L"m_pSubPicQueue failed\n"; + + return hr; + } + + if (pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); + } + } + + m_LastAdapterCheck = rd->GetPerfCounter(); + + return S_OK; +} + +HRESULT CDX9AllocatorPresenter::AllocSurfaces() +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + return CreateVideoSurfaces(); +} + +void CDX9AllocatorPresenter::DeleteSurfaces() +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + FreeVideoSurfaces(); +} + +UINT CDX9AllocatorPresenter::GetAdapter(IDirect3D9* pD3D, bool bGetAdapter) +{ + if (m_hWnd == nullptr || pD3D == nullptr) { + return D3DADAPTER_DEFAULT; + } + + m_D3D9Device = _T(""); + + const CRenderersSettings& r = GetRenderersSettings(); + if (bGetAdapter && (pD3D->GetAdapterCount() > 1) && !r.D3D9RenderDevice.IsEmpty()) { + TCHAR strGUID[50]; + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + + for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { + if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK) { + if ((::StringFromGUID2(adapterIdentifier.DeviceIdentifier, strGUID, 50) > 0) && (r.D3D9RenderDevice == strGUID)) { + m_D3D9Device = adapterIdentifier.Description; + return adp; + } + } + } + } + + HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor == nullptr) { + return D3DADAPTER_DEFAULT; + } + + for (UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp) { + HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp); + if (hAdpMon == hMonitor) { + if (bGetAdapter) { + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK) { + m_D3D9Device = adapterIdentifier.Description; + } + } + return adp; + } + } + + return D3DADAPTER_DEFAULT; +} + +DWORD CDX9AllocatorPresenter::GetVertexProcessing() +{ + HRESULT hr; + D3DCAPS9 caps; + + hr = m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &caps); + if (FAILED(hr)) { + return D3DCREATE_SOFTWARE_VERTEXPROCESSING; + } + + if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 || + caps.VertexShaderVersion < D3DVS_VERSION(2, 0)) { + return D3DCREATE_SOFTWARE_VERTEXPROCESSING; + } + + return D3DCREATE_HARDWARE_VERTEXPROCESSING; +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP CDX9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + return E_NOTIMPL; +} + +void CDX9AllocatorPresenter::CalculateJitter(LONGLONG PerfCounter) +{ + // Calculate the jitter! + LONGLONG llPerf = PerfCounter; + if ((m_rtTimePerFrame != 0) && (labs((long)(llPerf - m_llLastPerf)) < m_rtTimePerFrame * 3)) { + m_nNextJitter = (m_nNextJitter + 1) % NB_JITTER; + m_pllJitter[m_nNextJitter] = llPerf - m_llLastPerf; + + m_MaxJitter = MINLONG64; + m_MinJitter = MAXLONG64; + + // Calculate the real FPS + LONGLONG llJitterSum = 0; + LONGLONG llJitterSumAvg = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG Jitter = m_pllJitter[i]; + llJitterSum += Jitter; + llJitterSumAvg += Jitter; + } + double FrameTimeMean = double(llJitterSumAvg) / NB_JITTER; + m_fJitterMean = FrameTimeMean; + double DeviationSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG DevInt = m_pllJitter[i] - (LONGLONG)FrameTimeMean; + double Deviation = (double)DevInt; + DeviationSum += Deviation * Deviation; + m_MaxJitter = std::max(m_MaxJitter, DevInt); + m_MinJitter = std::min(m_MinJitter, DevInt); + } + double StdDev = sqrt(DeviationSum / NB_JITTER); + + m_fJitterStdDev = StdDev; + m_fAvrFps = 10000000.0 / (double(llJitterSum) / NB_JITTER); + } + + m_llLastPerf = llPerf; +} + +bool CDX9AllocatorPresenter::GetVBlank(int& _ScanLine, int& _bInVBlank, bool _bMeasureTime) +{ + LONGLONG llPerf = 0; + if (_bMeasureTime) { + llPerf = GetRenderersData()->GetPerfCounter(); + } + + int ScanLine = 0; + _ScanLine = 0; + _bInVBlank = 0; + + if (m_pDirectDraw) { + DWORD ScanLineGet = 0; + m_pDirectDraw->GetScanLine(&ScanLineGet); + BOOL InVBlank; + if (m_pDirectDraw->GetVerticalBlankStatus(&InVBlank) != S_OK) { + return false; + } + ScanLine = ScanLineGet; + _bInVBlank = InVBlank; + if (InVBlank) { + ScanLine = 0; + } + } else { + D3DRASTER_STATUS RasterStatus; + if (m_pD3DDev->GetRasterStatus(0, &RasterStatus) != S_OK) { + return false; + } + ScanLine = RasterStatus.ScanLine; + _bInVBlank = RasterStatus.InVBlank; + } + if (_bMeasureTime) { + m_VBlankMax = std::max(m_VBlankMax, ScanLine); + if (ScanLine != 0 && !_bInVBlank) { + m_VBlankMinCalc = std::min(m_VBlankMinCalc, ScanLine); + } + m_VBlankMin = m_VBlankMax - m_ScreenSize.cy; + } + if (_bInVBlank) { + _ScanLine = 0; + } else if (m_VBlankMin != 300000) { + _ScanLine = ScanLine - m_VBlankMin; + } else { + _ScanLine = ScanLine; + } + + if (_bMeasureTime) { + LONGLONG Time = GetRenderersData()->GetPerfCounter() - llPerf; + if (Time > 5000000) { // 0.5 sec + TRACE(_T("GetVBlank too long (%f sec)\n"), Time / 10000000.0); + } + m_RasterStatusWaitTimeMaxCalc = std::max(m_RasterStatusWaitTimeMaxCalc, Time); + } + + return true; +} + +bool CDX9AllocatorPresenter::WaitForVBlankRange(int& _RasterStart, int _RasterSize, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, HANDLE& lockOwner) +{ + if (_bMeasure) { + m_RasterStatusWaitTimeMaxCalc = 0; + } + bool bWaited = false; + int ScanLine = 0; + int InVBlank = 0; + LONGLONG llPerf = 0; + if (_bMeasure) { + llPerf = GetRenderersData()->GetPerfCounter(); + } + GetVBlank(ScanLine, InVBlank, _bMeasure); + if (_bMeasure) { + m_VBlankStartWait = ScanLine; + } + + static bool bOneWait = true; + if (bOneWait && _bMeasure) { + bOneWait = false; + // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate + int nInVBlank = 0; + for (;;) { + if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { + break; + } + + if (InVBlank && nInVBlank == 0) { + nInVBlank = 1; + } else if (!InVBlank && nInVBlank == 1) { + nInVBlank = 2; + } else if (InVBlank && nInVBlank == 2) { + nInVBlank = 3; + } else if (!InVBlank && nInVBlank == 3) { + break; + } + } + } + if (_bWaitIfInside) { + int ScanLineDiff = long(ScanLine) - _RasterStart; + if (ScanLineDiff > m_ScreenSize.cy / 2) { + ScanLineDiff -= m_ScreenSize.cy; + } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { + ScanLineDiff += m_ScreenSize.cy; + } + + if (ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) { + bWaited = true; + // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate + int LastLineDiff = ScanLineDiff; + for (;;) { + if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { + break; + } + ScanLineDiff = long(ScanLine) - _RasterStart; + if (ScanLineDiff > m_ScreenSize.cy / 2) { + ScanLineDiff -= m_ScreenSize.cy; + } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { + ScanLineDiff += m_ScreenSize.cy; + } + if (!(ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0)) { + break; + } + LastLineDiff = ScanLineDiff; + Sleep(1); // Just sleep + } + } + } + double RefreshRate = GetRefreshRate(); + LONG ScanLines = GetScanLines(); + int MinRange = std::max(std::min(long(0.0015 * ScanLines * RefreshRate + 0.5), ScanLines / 3l), 5l); // 1.5 ms or max 33 % of Time + int NoSleepStart = _RasterStart - MinRange; + int NoSleepRange = MinRange; + if (NoSleepStart < 0) { + NoSleepStart += m_ScreenSize.cy; + } + + int MinRange2 = std::max(std::min(long(0.0050 * ScanLines * RefreshRate + 0.5), ScanLines / 3l), 5l); // 5 ms or max 33 % of Time + int D3DDevLockStart = _RasterStart - MinRange2; + int D3DDevLockRange = MinRange2; + if (D3DDevLockStart < 0) { + D3DDevLockStart += m_ScreenSize.cy; + } + + int ScanLineDiff = ScanLine - _RasterStart; + if (ScanLineDiff > m_ScreenSize.cy / 2) { + ScanLineDiff -= m_ScreenSize.cy; + } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { + ScanLineDiff += m_ScreenSize.cy; + } + int LastLineDiff = ScanLineDiff; + + + int ScanLineDiffSleep = long(ScanLine) - NoSleepStart; + if (ScanLineDiffSleep > m_ScreenSize.cy / 2) { + ScanLineDiffSleep -= m_ScreenSize.cy; + } else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2) { + ScanLineDiffSleep += m_ScreenSize.cy; + } + int LastLineDiffSleep = ScanLineDiffSleep; + + + int ScanLineDiffLock = long(ScanLine) - D3DDevLockStart; + if (ScanLineDiffLock > m_ScreenSize.cy / 2) { + ScanLineDiffLock -= m_ScreenSize.cy; + } else if (ScanLineDiffLock < -m_ScreenSize.cy / 2) { + ScanLineDiffLock += m_ScreenSize.cy; + } + int LastLineDiffLock = ScanLineDiffLock; + + LONGLONG llPerfLock = 0; + + for (;;) { + if (!GetVBlank(ScanLine, InVBlank, _bMeasure)) { + break; + } + ScanLineDiff = long(ScanLine) - _RasterStart; + if (ScanLineDiff > m_ScreenSize.cy / 2) { + ScanLineDiff -= m_ScreenSize.cy; + } else if (ScanLineDiff < -m_ScreenSize.cy / 2) { + ScanLineDiff += m_ScreenSize.cy; + } + if ((ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0)) { + break; + } + + LastLineDiff = ScanLineDiff; + + bWaited = true; + + ScanLineDiffLock = long(ScanLine) - D3DDevLockStart; + if (ScanLineDiffLock > m_ScreenSize.cy / 2) { + ScanLineDiffLock -= m_ScreenSize.cy; + } else if (ScanLineDiffLock < -m_ScreenSize.cy / 2) { + ScanLineDiffLock += m_ScreenSize.cy; + } + + if (((ScanLineDiffLock >= 0 && ScanLineDiffLock <= D3DDevLockRange) || (LastLineDiffLock < 0 && ScanLineDiffLock > 0))) { + if (!lockOwner && _bMeasure) { + llPerfLock = GetRenderersData()->GetPerfCounter(); + lockOwner = LockD3DDevice(); + } + } + LastLineDiffLock = ScanLineDiffLock; + + + ScanLineDiffSleep = long(ScanLine) - NoSleepStart; + if (ScanLineDiffSleep > m_ScreenSize.cy / 2) { + ScanLineDiffSleep -= m_ScreenSize.cy; + } else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2) { + ScanLineDiffSleep += m_ScreenSize.cy; + } + + if (!((ScanLineDiffSleep >= 0 && ScanLineDiffSleep <= NoSleepRange) || (LastLineDiffSleep < 0 && ScanLineDiffSleep > 0)) || !_bNeedAccurate) { + //TRACE(_T("%d\n"), RasterStatus.ScanLine); + Sleep(1); // Don't sleep for the last 1.5 ms scan lines, so we get maximum precision + } + LastLineDiffSleep = ScanLineDiffSleep; + } + _RasterStart = ScanLine; + if (_bMeasure) { + m_VBlankEndWait = ScanLine; + m_VBlankWaitTime = GetRenderersData()->GetPerfCounter() - llPerf; + + if (lockOwner) { + m_VBlankLockTime = GetRenderersData()->GetPerfCounter() - llPerfLock; + } else { + m_VBlankLockTime = 0; + } + + m_RasterStatusWaitTime = m_RasterStatusWaitTimeMaxCalc; + m_RasterStatusWaitTimeMin = std::min(m_RasterStatusWaitTimeMin, m_RasterStatusWaitTime); + m_RasterStatusWaitTimeMax = std::max(m_RasterStatusWaitTimeMax, m_RasterStatusWaitTime); + } + + return bWaited; +} + +int CDX9AllocatorPresenter::GetVBlackPos() +{ + BOOL bCompositionEnabled = m_bCompositionEnabled; + + int WaitRange = std::max(m_ScreenSize.cy / 40l, 5l); + if (!bCompositionEnabled) { + if (m_bAlternativeVSync) { + const CRenderersSettings& r = GetRenderersSettings(); + return r.m_AdvRendSets.iVMR9VSyncOffset; + } else { + int MinRange = std::max(std::min(long(0.005 * m_ScreenSize.cy * GetRefreshRate() + 0.5), m_ScreenSize.cy / 3l), 5l); // 5 ms or max 33 % of Time + int WaitFor = m_ScreenSize.cy - (MinRange + WaitRange); + return WaitFor; + } + } else { + int WaitFor = m_ScreenSize.cy / 2; + return WaitFor; + } +} + +bool CDX9AllocatorPresenter::WaitForVBlank(bool& _Waited, HANDLE& lockOwner) +{ + const CRenderersSettings& r = GetRenderersSettings(); + if (!r.m_AdvRendSets.bVMR9VSync) { + _Waited = true; + m_VBlankWaitTime = 0; + m_VBlankLockTime = 0; + m_VBlankEndWait = 0; + m_VBlankStartWait = 0; + return true; + } + //_Waited = true; + //return false; + + BOOL bCompositionEnabled = m_bCompositionEnabled; + int WaitFor = GetVBlackPos(); + + if (!bCompositionEnabled) { + if (m_bAlternativeVSync) { + _Waited = WaitForVBlankRange(WaitFor, 0, false, true, true, lockOwner); + return false; + } else { + _Waited = WaitForVBlankRange(WaitFor, 0, false, r.m_AdvRendSets.bVMR9VSyncAccurate, true, lockOwner); + return true; + } + } else { + // Instead we wait for VBlack after the present, this seems to fix the stuttering problem. It'r also possible to fix by removing the Sleep above, but that isn't an option. + WaitForVBlankRange(WaitFor, 0, false, r.m_AdvRendSets.bVMR9VSyncAccurate, true, lockOwner); + + return false; + } +} + +void CDX9AllocatorPresenter::UpdateAlphaBitmap() +{ + m_VMR9AlphaBitmapData.Free(); + + if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0) { + HBITMAP hBitmap = (HBITMAP)GetCurrentObject(m_VMR9AlphaBitmap.hdc, OBJ_BITMAP); + if (!hBitmap) { + return; + } + DIBSECTION info; + ZeroMemory(&info, sizeof(DIBSECTION)); + if (!::GetObject(hBitmap, sizeof(DIBSECTION), &info)) { + return; + } + + m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight); + m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes; + + if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight)) { + memcpy((BYTE*)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight); + } + } +} + +STDMETHODIMP_(bool) CDX9AllocatorPresenter::Paint(bool bAll) +{ + if (m_bPendingResetDevice) { + SendResetRequest(); + return false; + } + + CRenderersSettings& r = GetRenderersSettings(); + if (&r == nullptr) { + return false; + } + + //TRACE(_T("Thread: %d\n"), (LONG)((CRITICAL_SECTION &)m_RenderLock).OwningThread); + +#if 0 + if (TryEnterCriticalSection(&(CRITICAL_SECTION&)(*((CCritSec*)this)))) { + LeaveCriticalSection((&(CRITICAL_SECTION&)(*((CCritSec*)this)))); + } else { + __debugbreak(); + } +#endif + + CRenderersData* rd = GetRenderersData(); + + LONGLONG StartPaint = rd->GetPerfCounter(); + CAutoLock cRenderLock(&m_RenderLock); + + if (m_windowRect.right <= m_windowRect.left || m_windowRect.bottom <= m_windowRect.top + || m_nativeVideoSize.cx <= 0 || m_nativeVideoSize.cy <= 0 + || !m_pVideoSurface[m_nCurSurface]) { + if (m_OrderedPaint) { + --m_OrderedPaint; + } else { + //TRACE(_T("UNORDERED PAINT!!!!!!\n")); + } + + + return false; + } + + HRESULT hr; + + m_pD3DDev->BeginScene(); + + CComPtr pBackBuffer; + m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); + // FIXME: GetBackBuffer can fail, check return value and reset device + + // Clear the backbuffer + m_pD3DDev->SetRenderTarget(0, pBackBuffer); + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); + + CRect rSrcVid(CPoint(0, 0), GetVisibleVideoSize()); + CRect rDstVid(m_videoRect); + + CRect rSrcPri(CPoint(0, 0), m_windowRect.Size()); + CRect rDstPri(rSrcPri); + + // Render the current video frame + hr = RenderVideo(pBackBuffer, rSrcVid, rDstVid); + + if (FAILED(hr)) { + if (m_RenderingPath == RENDERING_PATH_STRETCHRECT) { + // Support ffdshow queueing + // m_pD3DDev->StretchRect may fail if ffdshow is using queue output samples. + // Here we don't want to show the black buffer. + if (m_OrderedPaint) { + --m_OrderedPaint; + } else { + //TRACE(_T("UNORDERED PAINT!!!!!!\n")); + } + + return false; + } + } + + if (!m_bIsPreview) { + // paint the text on the backbuffer + AlphaBltSubPic(rDstPri, rDstVid); + + // Casimir666 : show OSD + if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE) { + CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock); + CRect rcSrc(m_VMR9AlphaBitmap.rSrc); + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE*)m_VMR9AlphaBitmapData) { + if ((m_pD3DXLoadSurfaceFromMemory != nullptr) && + SUCCEEDED(hr = m_pD3DDev->CreateTexture(rcSrc.Width(), rcSrc.Height(), 1, + D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, &m_pOSDTexture, nullptr))) { + if (SUCCEEDED(hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface))) { + hr = m_pD3DXLoadSurfaceFromMemory(m_pOSDSurface, + nullptr, + nullptr, + (BYTE*)m_VMR9AlphaBitmapData, + D3DFMT_A8R8G8B8, + m_VMR9AlphaBitmapWidthBytes, + nullptr, + &m_VMR9AlphaBitmapRect, + D3DX_FILTER_NONE, + m_VMR9AlphaBitmap.clrSrcKey); + } + if (FAILED(hr)) { + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + } + } + } + m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE; + + } + + if (m_bAlphaBitmapEnable && m_pAlphaBitmapTexture) { + CRect rcDst(rSrcPri); + AlphaBlt(rSrcPri, rcDst, m_pAlphaBitmapTexture); + } + + if (rd->m_bResetStats) { + ResetStats(); + rd->m_bResetStats = false; + } + + if (rd->m_iDisplayStats) { + DrawStats(); + } + + if (m_pOSDTexture) { + AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture); + } + } + + m_pD3DDev->EndScene(); + + BOOL bCompositionEnabled = m_bCompositionEnabled; + + bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !r.m_AdvRendSets.bVMR9VSync; + + CComPtr pEventQueryFlushBeforeVSync; + m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQueryFlushBeforeVSync); + if (pEventQueryFlushBeforeVSync) { + pEventQueryFlushBeforeVSync->Issue(D3DISSUE_END); + } + + if (r.m_AdvRendSets.bVMRFlushGPUBeforeVSync && pEventQueryFlushBeforeVSync) { + LONGLONG llPerf = rd->GetPerfCounter(); + BOOL Data; + //Sleep(5); + LONGLONG FlushStartTime = rd->GetPerfCounter(); + while (S_FALSE == pEventQueryFlushBeforeVSync->GetData(&Data, sizeof(Data), D3DGETDATA_FLUSH)) { + if (!r.m_AdvRendSets.bVMRFlushGPUWait) { + break; + } + Sleep(1); + if (rd->GetPerfCounter() - FlushStartTime > 500000) { + break; // timeout after 50 ms + } + } + if (r.m_AdvRendSets.bVMRFlushGPUWait) { + m_WaitForGPUTime = rd->GetPerfCounter() - llPerf; + } else { + m_WaitForGPUTime = 0; + } + } else { + m_WaitForGPUTime = 0; + } + + if (bAll) { + m_PaintTime = (rd->GetPerfCounter() - StartPaint); + m_PaintTimeMin = std::min(m_PaintTimeMin, m_PaintTime); + m_PaintTimeMax = std::max(m_PaintTimeMax, m_PaintTime); + } + + bool bWaited = false; + HANDLE lockOwner = nullptr; + if (bAll) { + // Only sync to refresh when redrawing all + bool bTest = WaitForVBlank(bWaited, lockOwner); + ASSERT(bTest == bDoVSyncInPresent); + if (!bDoVSyncInPresent) { + LONGLONG Time = rd->GetPerfCounter(); + OnVBlankFinished(bAll, Time); + if (!m_bIsEVR || m_OrderedPaint) { + CalculateJitter(Time); + } + } + } + + // Create a device pointer m_pd3dDevice + + // Create a query object + { + CComPtr pEventQueryFlushAfterVSync; + m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQueryFlushAfterVSync); + + LONGLONG llPerf = rd->GetPerfCounter(); + CRect presentationSrcRect(rDstPri), presentationDestRect(m_windowRect); + // PresentEx() / Present() performs the clipping + // TODO: fix the race and uncomment the assert + //ASSERT(presentationSrcRect.Size() == presentationDestRect.Size()); + if (m_pD3DDevEx) { + if (m_bIsFullscreen) { + hr = m_pD3DDevEx->PresentEx(nullptr, nullptr, nullptr, nullptr, 0); + } else { + hr = m_pD3DDevEx->PresentEx(presentationSrcRect, presentationDestRect, nullptr, nullptr, 0); + } + } else { + if (m_bIsFullscreen) { + hr = m_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr); + } else { + hr = m_pD3DDev->Present(presentationSrcRect, presentationDestRect, nullptr, nullptr); + } + } + // Issue an End event + if (pEventQueryFlushAfterVSync) { + pEventQueryFlushAfterVSync->Issue(D3DISSUE_END); + } + + BOOL Data; + + if (r.m_AdvRendSets.bVMRFlushGPUAfterPresent && pEventQueryFlushAfterVSync) { + LONGLONG FlushStartTime = rd->GetPerfCounter(); + while (S_FALSE == pEventQueryFlushAfterVSync->GetData(&Data, sizeof(Data), D3DGETDATA_FLUSH)) { + if (!r.m_AdvRendSets.bVMRFlushGPUWait) { + break; + } + if (rd->GetPerfCounter() - FlushStartTime > 500000) { + break; // timeout after 50 ms + } + } + } + + int ScanLine; + int bInVBlank; + GetVBlank(ScanLine, bInVBlank, false); + + if (bAll && (!m_bIsEVR || m_OrderedPaint)) { + m_VBlankEndPresent = ScanLine; + } + + while (ScanLine == 0 || bInVBlank) { + GetVBlank(ScanLine, bInVBlank, false); + + } + m_VBlankStartMeasureTime = rd->GetPerfCounter(); + m_VBlankStartMeasure = ScanLine; + + if (bAll && bDoVSyncInPresent) { + m_PresentWaitTime = rd->GetPerfCounter() - llPerf; + m_PresentWaitTimeMin = std::min(m_PresentWaitTimeMin, m_PresentWaitTime); + m_PresentWaitTimeMax = std::max(m_PresentWaitTimeMax, m_PresentWaitTime); + } else { + m_PresentWaitTime = 0; + m_PresentWaitTimeMin = std::min(m_PresentWaitTimeMin, m_PresentWaitTime); + m_PresentWaitTimeMax = std::max(m_PresentWaitTimeMax, m_PresentWaitTime); + } + } + + if (bDoVSyncInPresent) { + LONGLONG Time = rd->GetPerfCounter(); + if (!m_bIsEVR || m_OrderedPaint) { + CalculateJitter(Time); + } + OnVBlankFinished(bAll, Time); + } + + if (lockOwner) { + UnlockD3DDevice(lockOwner); + } + + /*if (!bWaited) + { + bWaited = true; + WaitForVBlank(bWaited); + TRACE(_T("Double VBlank\n")); + ASSERT(bWaited); + if (!bDoVSyncInPresent) + { + CalculateJitter(); + OnVBlankFinished(bAll); + } + }*/ + + if (!m_bPendingResetDevice) { + bool fResetDevice = false; + + if (hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) { + TRACE(_T("Reset Device: D3D Device Lost\n")); + fResetDevice = true; + } + + if (hr == S_PRESENT_MODE_CHANGED) { + TRACE(_T("Reset Device: D3D Device mode changed\n")); + fResetDevice = true; + } + + if (SettingsNeedResetDevice(r)) { + TRACE(_T("Reset Device: settings changed\n")); + fResetDevice = true; + } + + bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + if ((bCompositionEnabled != 0) != m_bCompositionEnabled) { + if (m_bIsFullscreen) { + m_bCompositionEnabled = (bCompositionEnabled != 0); + } else { + TRACE(_T("Reset Device: DWM composition changed\n")); + fResetDevice = true; + } + } + + if (r.fResetDevice) { + LONGLONG time = rd->GetPerfCounter(); + if (time > m_LastAdapterCheck + 20000000) { // check every 2 sec. + m_LastAdapterCheck = time; +#ifdef _DEBUG + D3DDEVICE_CREATION_PARAMETERS Parameters; + if (SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))) { + ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter); + } +#endif + if (m_CurrentAdapter != GetAdapter(m_pD3D)) { + TRACE(_T("Reset Device: D3D adapter changed\n")); + fResetDevice = true; + } +#ifdef _DEBUG + else { + ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D))); + } +#endif + } + } + + if (fResetDevice) { + m_bPendingResetDevice = true; + SendResetRequest(); + } + } + + if (m_OrderedPaint) { + --m_OrderedPaint; + } else { + //if (m_bIsEVR) + // TRACE(_T("UNORDERED PAINT!!!!!!\n")); + } + return true; +} + +double CDX9AllocatorPresenter::GetFrameTime() const +{ + if (m_DetectedLock) { + return m_DetectedFrameTime; + } + + return m_rtTimePerFrame / 10000000.0; +} + +double CDX9AllocatorPresenter::GetFrameRate() const +{ + if (m_DetectedLock) { + return m_DetectedFrameRate; + } + + return 10000000.0 / m_rtTimePerFrame; +} + +void CDX9AllocatorPresenter::SendResetRequest() +{ + if (!m_bDeviceResetRequested) { + m_bDeviceResetRequested = true; + AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE); + } +} + +STDMETHODIMP_(bool) CDX9AllocatorPresenter::ResetDevice() +{ + TRACE(_T("ResetDevice\n")); + ASSERT(m_MainThreadId == GetCurrentThreadId()); + + // In VMR-9 deleting the surfaces before we are told to is bad ! + // Can't comment out this because CDX9AllocatorPresenter is used by EVR Custom + // Why is EVR using a presenter for DX9 anyway ?! + DeleteSurfaces(); + + if (m_pD3DEx) { + m_pD3DEx.Release(); + m_pD3D = nullptr; + Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); + if (m_pD3DEx) { + m_pD3D = m_pD3DEx; + } else { + ASSERT(FALSE); + m_bDeviceResetRequested = false; + return false; + } + } + + HRESULT hr; + CString Error; + // TODO: Report error messages here + + // In VMR-9 'AllocSurfaces' call is redundant afaik because + // 'CreateDevice' calls 'm_pIVMRSurfAllocNotify->ChangeD3DDevice' which in turn calls + // 'CVMR9AllocatorPresenter::InitializeDevice' which calls 'AllocSurfaces' + if (FAILED(hr = CreateDevice(Error)) || FAILED(hr = AllocSurfaces())) { + // TODO: We should probably pause player +#ifdef _DEBUG + Error += GetWindowsErrorMessage(hr, nullptr); + TRACE(_T("D3D Reset Error\n%ws\n\n"), Error.GetBuffer()); +#endif + m_bDeviceResetRequested = false; + return false; + } + OnResetDevice(); + m_bDeviceResetRequested = false; + m_bPendingResetDevice = false; + + return true; +} + +STDMETHODIMP_(bool) CDX9AllocatorPresenter::DisplayChange() +{ + m_bPendingResetDevice = true; + SendResetRequest(); + return true; +} + +void CDX9AllocatorPresenter::ResetStats() +{ + CRenderersData* rd = GetRenderersData(); + LONGLONG Time = rd->GetPerfCounter(); + + m_PaintTime = 0; + m_PaintTimeMin = 3000000000; + m_PaintTimeMax = 0; + + m_RasterStatusWaitTime = 0; + m_RasterStatusWaitTimeMin = 3000000000; + m_RasterStatusWaitTimeMax = 0; + + m_MinSyncOffset = 0; + m_MaxSyncOffset = 0; + m_fSyncOffsetAvr = 0; + m_fSyncOffsetStdDev = 0; + + CalculateJitter(Time); +} + +void CDX9AllocatorPresenter::InitStats() +{ + ASSERT(m_pD3DDev); + static LONG currentHeight = 0; + int newHeight = lround(FONT_HEIGHT * (double(m_windowRect.Width()) / REFERENCE_WIDTH)); + + if (m_pD3DXCreateFont && (!m_pFont || currentHeight != newHeight)) { + m_pFont = nullptr; + if (newHeight <= 0) { + ASSERT(FALSE); + } + m_pD3DXCreateFont(m_pD3DDev, newHeight, 0, newHeight < BOLD_THRESHOLD ? FW_NORMAL : FW_BOLD, + 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, + FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont); + currentHeight = newHeight; + } + + if (m_pD3DXCreateSprite && !m_pSprite) { + m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite); + } + + if (m_pD3DXCreateLine && !m_pLine) { + m_pD3DXCreateLine(m_pD3DDev, &m_pLine); + } +} + +void CDX9AllocatorPresenter::DrawStats() +{ + const CRenderersData* rd = GetRenderersData(); + + int iDetailedStats; + switch (rd->m_iDisplayStats) { + case 1: + iDetailedStats = 2; + break; + case 2: + iDetailedStats = 1; + break; + case 3: + iDetailedStats = 0; + break; + default: + ASSERT(FALSE); + return; + } + + InitStats(); + const float textScale = float(m_windowRect.Width()) / REFERENCE_WIDTH; + const int lineHeight = lround((FONT_HEIGHT + TEXT_PADDING) * textScale); + + if (m_pFont && m_pSprite) { + auto drawText = [&](CRect & rc, const CString & strText) { + D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f); + D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f); + + RECT shadowRect = rc; + OffsetRect(&shadowRect, 2, 2); + + // Draw shadow + m_pFont->DrawText(m_pSprite, strText, -1, &shadowRect, DT_NOCLIP, Color0); + // Draw text + m_pFont->DrawText(m_pSprite, strText, -1, rc, DT_NOCLIP, Color1); + rc.OffsetRect(0, lineHeight); + }; + + const CRenderersSettings& r = GetRenderersSettings(); + LONGLONG llMaxJitter = m_MaxJitter; + LONGLONG llMinJitter = m_MinJitter; + LONGLONG llMaxSyncOffset = m_MaxSyncOffset; + LONGLONG llMinSyncOffset = m_MinSyncOffset; + CRect rc(lineHeight, lineHeight, 0, 0); + + m_pSprite->Begin(D3DXSPRITE_ALPHABLEND); + CString strText; + if (iDetailedStats > 1) { + if (m_bIsEVR) { + strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s) (%7.3f ms = %.03f%s, %2.03f StdDev) Clock: %1.4f %%", + m_fAvrFps, + double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), + m_bInterlaced ? L"I" : L"P", GetFrameTime() * 1000.0, GetFrameRate(), + m_DetectedLock ? L" L" : L"", m_DetectedFrameTimeStdDev / 10000.0, + m_ModeratedTimeSpeed * 100.0); + } else { + strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s)", + m_fAvrFps, + double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), + m_bInterlaced ? L"I" : L"P"); + } + } else { + strText.Format(L"Frame rate : %7.03f (%.03f%s)", m_fAvrFps, GetFrameRate(), m_DetectedLock ? L" L" : L""); + } + drawText(rc, strText); + + if (iDetailedStats > 1) { + strText = _T("Settings : "); + + if (m_bIsEVR) { + strText += _T("EVR "); + } else { + strText += _T("VMR9 "); + } + + if (m_bIsFullscreen) { + strText += _T("FS "); + } + if (r.m_AdvRendSets.bVMR9FullscreenGUISupport) { + strText += _T("FSGui "); + } + + if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { + strText += _T("DisDC "); + } + + if (m_bColorManagement) { + strText += _T("ColorMan "); + } + + if (r.m_AdvRendSets.bVMRFlushGPUBeforeVSync) { + strText += _T("GPUFlushBV "); + } + if (r.m_AdvRendSets.bVMRFlushGPUAfterPresent) { + strText += _T("GPUFlushAP "); + } + + if (r.m_AdvRendSets.bVMRFlushGPUWait) { + strText += _T("GPUFlushWt "); + } + + if (r.m_AdvRendSets.bVMR9VSync) { + strText += _T("VS "); + } + if (r.m_AdvRendSets.bVMR9AlterativeVSync) { + strText += _T("AltVS "); + } + if (r.m_AdvRendSets.bVMR9VSyncAccurate) { + strText += _T("AccVS "); + } + if (r.m_AdvRendSets.iVMR9VSyncOffset) { + strText.AppendFormat(_T("VSOfst(%d)"), r.m_AdvRendSets.iVMR9VSyncOffset); + } + + if (m_bFullFloatingPointProcessing) { + strText += _T("FullFP "); + } + + if (m_bHalfFloatingPointProcessing) { + strText += _T("HalfFP "); + } + + if (m_bIsEVR) { + if (m_bHighColorResolution) { + strText += _T("10bitOut "); + } + if (m_bForceInputHighColorResolution) { + strText += _T("For10bitIn "); + } + if (r.m_AdvRendSets.bEVREnableFrameTimeCorrection) { + strText += _T("FTC "); + } + if (r.m_AdvRendSets.iEVROutputRange == 0) { + strText += _T("0-255 "); + } else if (r.m_AdvRendSets.iEVROutputRange == 1) { + strText += _T("16-235 "); + } + } + + + drawText(rc, strText); + + strText.Format(L"Formats : Surface %s Backbuffer %s Display %s Device %s %s", + GetD3DFormatStr(m_SurfaceType), GetD3DFormatStr(m_BackbufferType), + GetD3DFormatStr(m_DisplayType), m_pD3DDevEx ? L"D3DDevEx" : L"D3DDev", + m_D3DDevExError.IsEmpty() ? _T("") : (_T("D3DExError: ") + m_D3DDevExError).GetString()); + drawText(rc, strText); + + if (m_bIsEVR) { + if (r.m_AdvRendSets.bVMR9VSync) { + strText.Format(_T("Refresh rate : %.05f Hz SL: %4d (%3u Hz) "), + m_DetectedRefreshRate, int(m_DetectedScanlinesPerFrame + 0.5), m_refreshRate); + } else { + strText.Format(_T("Refresh rate : %3u Hz "), m_refreshRate); + } + strText.AppendFormat(_T("Last Duration: %10.6f Corrected Frame Time: %s"), + double(m_LastFrameDuration) / 10000.0, m_bCorrectedFrameTime ? _T("Yes") : _T("No")); + drawText(rc, strText); + } + } + + if (m_bSyncStatsAvailable) { + if (iDetailedStats > 1) { + strText.Format(_T("Sync offset : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms, Avr = %7.3f ms, Mode = %d"), + (double(llMinSyncOffset) / 10000.0), (double(llMaxSyncOffset) / 10000.0), + m_fSyncOffsetStdDev / 10000.0, m_fSyncOffsetAvr / 10000.0, m_VSyncMode); + } else { + strText.Format(_T("Sync offset : Mode = %d"), m_VSyncMode); + } + drawText(rc, strText); + } + + if (iDetailedStats > 1) { + strText.Format(_T("Jitter : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms"), + (double(llMinJitter) / 10000.0), + (double(llMaxJitter) / 10000.0), + m_fJitterStdDev / 10000.0); + drawText(rc, strText); + } + + if (m_pAllocator && iDetailedStats > 1) { + CDX9SubPicAllocator* pAlloc = (CDX9SubPicAllocator*)m_pAllocator.p; + int nFree = 0; + int nAlloc = 0; + int nSubPic = 0; + REFERENCE_TIME rtQueueStart = 0; + REFERENCE_TIME rtQueueEnd = 0; + + if (m_pSubPicQueue) { + REFERENCE_TIME rtQueueNow = 0; + m_pSubPicQueue->GetStats(nSubPic, rtQueueNow, rtQueueStart, rtQueueEnd); + } + + pAlloc->GetStats(nFree, nAlloc); + strText.Format(_T("Subtitles : Free %d Allocated %d Buffered %d QueueStart %7.3f QueueEnd %7.3f"), + nFree, nAlloc, nSubPic, (double(rtQueueStart) / 10000000.0), + (double(rtQueueEnd) / 10000000.0)); + drawText(rc, strText); + } + + if (iDetailedStats > 1) { + if (m_VBlankEndPresent == -100000) { + strText.Format(_T("VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d"), + m_VBlankStartWait, m_VBlankEndWait, + (double(m_VBlankWaitTime) / 10000.0), + (double(m_VBlankLockTime) / 10000.0), + m_VBlankMin, m_VBlankMax - m_VBlankMin); + } else { + strText.Format(_T("VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d EndPresent %4d"), + m_VBlankStartWait, m_VBlankEndWait, + (double(m_VBlankWaitTime) / 10000.0), + (double(m_VBlankLockTime) / 10000.0), + m_VBlankMin, + m_VBlankMax - m_VBlankMin, + m_VBlankEndPresent); + } + } else { + if (m_VBlankEndPresent == -100000) { + strText.Format(_T("VBlank Wait : Start %4d End %4d"), m_VBlankStartWait, m_VBlankEndWait); + } else { + strText.Format(_T("VBlank Wait : Start %4d End %4d EP %4d"), m_VBlankStartWait, m_VBlankEndWait, + m_VBlankEndPresent); + } + } + drawText(rc, strText); + + BOOL bCompositionEnabled = m_bCompositionEnabled; + + bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !r.m_AdvRendSets.bVMR9VSync; + + if (iDetailedStats > 1 && bDoVSyncInPresent) { + strText.Format(_T("Present Wait : Wait %7.3f ms Min %7.3f ms Max %7.3f ms"), + (double(m_PresentWaitTime) / 10000.0), + (double(m_PresentWaitTimeMin) / 10000.0), + (double(m_PresentWaitTimeMax) / 10000.0)); + drawText(rc, strText); + } + + if (iDetailedStats > 1) { + if (m_WaitForGPUTime) { + strText.Format(_T("Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms GPU %7.3f ms"), + (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), + (double(m_PaintTimeMin) / 10000.0), + (double(m_PaintTimeMax) / 10000.0), + (double(m_WaitForGPUTime) / 10000.0)); + } else { + strText.Format(_T("Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms"), + (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), + (double(m_PaintTimeMin) / 10000.0), + (double(m_PaintTimeMax) / 10000.0)); + } + } else { + if (m_WaitForGPUTime) { + strText.Format(_T("Paint Time : Draw %7.3f ms GPU %7.3f ms"), + (double(m_PaintTime - m_WaitForGPUTime) / 10000.0), + (double(m_WaitForGPUTime) / 10000.0)); + } else { + strText.Format(_T("Paint Time : Draw %7.3f ms"), + (double(m_PaintTime - m_WaitForGPUTime) / 10000.0)); + } + } + drawText(rc, strText); + + if (iDetailedStats > 1 && r.m_AdvRendSets.bVMR9VSync) { + strText.Format(_T("Raster Status: Wait %7.3f ms Min %7.3f ms Max %7.3f ms"), + (double(m_RasterStatusWaitTime) / 10000.0), + (double(m_RasterStatusWaitTimeMin) / 10000.0), + (double(m_RasterStatusWaitTimeMax) / 10000.0)); + drawText(rc, strText); + } + + if (iDetailedStats > 1) { + if (m_bIsEVR) { + strText.Format(_T("Buffering : Buffered %3ld Free %3ld Current Surface %3d"), + m_nUsedBuffer, m_nNbDXSurface - m_nUsedBuffer, m_nCurSurface); + } else { + strText.Format(_T("Buffering : VMR9Surfaces %3d VMR9Surface %3d"), + m_nVMR9Surfaces, m_iVMR9Surface); + } + } else { + strText.Format(_T("Buffered : %3ld"), m_nUsedBuffer); + } + drawText(rc, strText); + + + if (iDetailedStats > 1) { + strText.Format(_T("Video size : %ld x %ld (AR = %ld : %ld)"), + m_nativeVideoSize.cx, m_nativeVideoSize.cy, m_aspectRatio.cx, m_aspectRatio.cy); + drawText(rc, strText); + if (m_pVideoTexture[0] || m_pVideoSurface[0]) { + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (m_pVideoTexture[0]) { + m_pVideoTexture[0]->GetLevelDesc(0, &desc); + } else if (m_pVideoSurface[0]) { + m_pVideoSurface[0]->GetDesc(&desc); + } + + if (desc.Width != (UINT)m_nativeVideoSize.cx || desc.Height != (UINT)m_nativeVideoSize.cy) { + strText.Format(_T("Texture size : %u x %u"), desc.Width, desc.Height); + drawText(rc, strText); + } + } + + + drawText(rc, rd->m_strDXVAInfo); + + strText.Format(_T("DirectX SDK : %u"), rd->GetDXSdkRelease()); + drawText(rc, strText); + + if (!m_D3D9Device.IsEmpty()) { + strText = _T("Render device: ") + m_D3D9Device; + drawText(rc, strText); + } + + if (!m_Decoder.IsEmpty()) { + strText = _T("Decoder : ") + m_Decoder; + drawText(rc, strText); + } + + for (int i = 0; i < 6; i++) { + if (m_strStatsMsg[i][0]) { + drawText(rc, m_strStatsMsg[i]); + } + } + } + m_pSprite->End(); + } + + if (m_pLine && iDetailedStats) { + D3DXVECTOR2 points[NB_JITTER]; + const float graphWidth = GRAPH_WIDTH * textScale; + const float graphHeight = GRAPH_HEIGHT * textScale; + const float topLeftX = m_windowRect.Width() - (graphWidth + lineHeight); + const float topLeftY = m_windowRect.Height() - (graphHeight + lineHeight); + const float gridStepY = graphHeight / 24.0f; + const float gridStepX = graphWidth / NB_JITTER; + + // Draw background + DrawRect(RGB(0, 0, 0), 80, CRect(int(topLeftX), + int(topLeftY), + int(topLeftX + graphWidth), + int(topLeftY + graphHeight))); + + m_pLine->SetWidth(2.5f * textScale); + m_pLine->SetAntialias(TRUE); + m_pLine->Begin(); + + // Draw grid lines + for (int i = 1; i < 24; ++i) { + points[0].x = topLeftX; + points[0].y = topLeftY + i * gridStepY; + points[1].y = points[0].y; + + float lineLength; + D3DCOLOR color; + if (i % 12 == 0) { + lineLength = 1.0f; + color = D3DCOLOR_XRGB(100, 100, 255); + } else if (i % 4 == 0) { + lineLength = 0.96f; + color = D3DCOLOR_XRGB(100, 100, 180); + } else { + lineLength = 0.04f; + color = D3DCOLOR_XRGB(100, 100, 140); + } + points[1].x = topLeftX + graphWidth * lineLength; + m_pLine->Draw(points, 2, color); + } + + if (m_rtTimePerFrame) { + // Draw jitter + for (int i = 1; i <= NB_JITTER; ++i) { + int nIndex = (m_nNextJitter + i) % NB_JITTER; + if (nIndex < 0) { + nIndex += NB_JITTER; + ASSERT(FALSE); + } + float jitter = float(m_pllJitter[nIndex] - m_fJitterMean); + points[i - 1].x = topLeftX + i * gridStepX; + points[i - 1].y = topLeftY + (jitter * textScale / 2000.0f + graphHeight / 2.0f); + } + m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100)); + + if (m_bSyncStatsAvailable) { + // Draw sync offset + for (int i = 1; i <= NB_JITTER; ++i) { + int nIndex = (m_nNextSyncOffset + i) % NB_JITTER; + if (nIndex < 0) { + nIndex += NB_JITTER; + } + points[i - 1].x = topLeftX + i * gridStepX; + points[i - 1].y = topLeftY + (m_pllSyncOffset[nIndex] * textScale / 2000.0f + graphHeight / 2.0f); + } + m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100)); + } + } + m_pLine->End(); + } +} + +STDMETHODIMP CDX9AllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) +{ + CheckPointer(size, E_POINTER); + + // Keep a reference so that we can safely work on the surface + // without having to lock everything + CComPtr pVideoSurface; + { + CAutoLock cAutoLock(this); + CheckPointer(m_pVideoSurface[m_nCurSurface], E_FAIL); + pVideoSurface = m_pVideoSurface[m_nCurSurface]; + } + + HRESULT hr; + + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(hr = pVideoSurface->GetDesc(&desc))) { + return hr; + } + + CSize framesize = GetVideoSize(false); + const CSize dar = GetVideoSize(true); + + bool resize = false; + if (dar.cx > 0 && dar.cy > 0 && (dar.cx != desc.Width || dar.cy != desc.Height)) { + framesize.cx = MulDiv(framesize.cy, dar.cx, dar.cy); + resize = true; + desc.Width = framesize.cx; + desc.Height = framesize.cy; + } + + DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3); + if (!lpDib) { + *size = required; + return S_OK; + } + if (*size < required) { + return E_OUTOFMEMORY; + } + *size = required; + + CComPtr pSurface, tSurface; + // Convert to 8-bit when using 10-bit or full/half processing modes + if (desc.Format != D3DFMT_X8R8G8B8) { + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tSurface, nullptr)) + || FAILED(hr = m_pD3DXLoadSurfaceFromSurface(tSurface, nullptr, nullptr, pVideoSurface, nullptr, nullptr, D3DX_DEFAULT, 0))) { + return hr; + } + } else { + tSurface = pVideoSurface; + } + + if (resize) { + CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; + if (FAILED(hr = m_pD3DDevEx->CreateRenderTarget(framesize.cx, framesize.cy, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurface, nullptr)) + || FAILED(hr = m_pD3DDevEx->SetRenderTarget(0, pSurface)) + || FAILED(hr = Resize(pVideoTexture, { CPoint(0, 0), m_nativeVideoSize }, { CPoint(0, 0), framesize }))) { + return hr; + } + } else { + pSurface = tSurface; + } + + D3DLOCKED_RECT r; + if (FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { + // If this fails, we try to use a surface allocated from the system memory + CComPtr pInputSurface = pSurface; + pSurface = nullptr; + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, nullptr)) + || FAILED(hr = m_pD3DDev->GetRenderTargetData(pInputSurface, pSurface)) + || FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { + return hr; + } + } + + hr = CreateDIBFromSurfaceData(desc, r, lpDib); + + pSurface->UnlockRect(); + + return hr; +} + +STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) +{ + return SetPixelShader2(pSrcData, pTarget, false); +} + +STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) +{ + CAutoLock cRenderLock(&m_RenderLock); + + return SetCustomPixelShader(pSrcData, pTarget, bScreenSpace); +} + +STDMETHODIMP CDX9AllocatorPresenter::SetD3DFullscreen(bool fEnabled) +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + fullScreenChanged = (fEnabled != m_bIsFullscreen); + m_bIsFullscreen = fEnabled; + return S_OK; +} + +STDMETHODIMP CDX9AllocatorPresenter::GetD3DFullscreen(bool* pfEnabled) +{ + CheckPointer(pfEnabled, E_POINTER); + *pfEnabled = m_bIsFullscreen; + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h index 06d18892a57..940e7badbb9 100644 --- a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h @@ -1,313 +1,313 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#pragma once - -#include "DX9RenderingEngine.h" -#include - -#define VMRBITMAP_UPDATE 0x80000000 -#define NB_JITTER 126 - -class CFocusThread; - -namespace DSObjects -{ - - class CDX9AllocatorPresenter - : public CDX9RenderingEngine - , public ID3DFullscreenControl - { - public: - CCritSec m_VMR9AlphaBitmapLock; - void UpdateAlphaBitmap(); - protected: - bool m_bAlternativeVSync; - bool m_bCompositionEnabled; - bool m_bIsEVR; - int m_OrderedPaint; - int m_VSyncMode; - bool m_bDesktopCompositionDisabled; - bool m_bIsFullscreen, fullScreenChanged; - bool m_bNeedCheckSample; - DWORD m_MainThreadId; - bool m_bIsPreview; - bool m_bIsRendering; - - CRenderersSettings::CAdvRendererSettings m_LastRendererSettings; - - HMODULE m_hDWMAPI; - - HRESULT(__stdcall* m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled); - HRESULT(__stdcall* m_pDwmEnableComposition)(UINT uCompositionAction); - - CCritSec m_RenderLock; - CComPtr m_pDirectDraw; - - HANDLE LockD3DDevice() { - if (m_pD3DDev) { - _RTL_CRITICAL_SECTION* pCritSec = (_RTL_CRITICAL_SECTION*)((size_t)m_pD3DDev.p + sizeof(size_t)); - - if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec)) - && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo)))) { - if (pCritSec->DebugInfo->CriticalSection == pCritSec) { - EnterCriticalSection(pCritSec); - return pCritSec->OwningThread; - } - } - } - return 0; - } - - void UnlockD3DDevice(HANDLE& lockOwner) { - if (m_pD3DDev) { - _RTL_CRITICAL_SECTION* pCritSec = (_RTL_CRITICAL_SECTION*)((size_t)m_pD3DDev.p + sizeof(size_t)); - - if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec)) - && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo)))) { - if (pCritSec->DebugInfo->CriticalSection == pCritSec && pCritSec->OwningThread == lockOwner) { - LeaveCriticalSection(pCritSec); - } - } - } - } - - CString m_D3DDevExError; - CComPtr m_pOSDTexture; - CComPtr m_pOSDSurface; - CComPtr m_pLine; - CComPtr m_pFont; - bool m_bAlphaBitmapEnable = false; - CComPtr m_pAlphaBitmapTexture; - MFVideoAlphaBitmapParams m_AlphaBitmapParams = {}; - - CComPtr m_pSprite; - - bool SettingsNeedResetDevice(CRenderersSettings& r); - - virtual HRESULT CreateDevice(CString& _Error); - virtual HRESULT AllocSurfaces(); - virtual void DeleteSurfaces(); - - LONGLONG m_LastAdapterCheck; - UINT GetAdapter(IDirect3D9* pD3D, bool bGetAdapter = true); - DWORD GetVertexProcessing(); - - bool GetVBlank(int& _ScanLine, int& _bInVBlank, bool _bMeasureTime); - bool WaitForVBlankRange(int& _RasterStart, int _RasterEnd, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, HANDLE& lockOwner); - bool WaitForVBlank(bool& _Waited, HANDLE& lockOwner); - int GetVBlackPos(); - void CalculateJitter(LONGLONG PerformanceCounter); - virtual void OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter) {} - - // Casimir666 - typedef HRESULT(WINAPI* D3DXLoadSurfaceFromMemoryPtr)( - LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY* pDestPalette, - CONST RECT* pDestRect, - LPCVOID pSrcMemory, - D3DFORMAT SrcFormat, - UINT SrcPitch, - CONST PALETTEENTRY* pSrcPalette, - CONST RECT* pSrcRect, - DWORD Filter, - D3DCOLOR ColorKey); - - typedef HRESULT(WINAPI* D3DXLoadSurfaceFromSurfacePtr)( - LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY* pDestPalette, - CONST RECT* pDestRect, - LPDIRECT3DSURFACE9 pSrcSurface, - CONST PALETTEENTRY* pSrcPalette, - CONST RECT* pSrcRect, - DWORD Filter, - D3DCOLOR ColorKey); - - typedef HRESULT(WINAPI* D3DXCreateLinePtr)(LPDIRECT3DDEVICE9 pDevice, LPD3DXLINE* ppLine); - - typedef HRESULT(WINAPI* D3DXCreateFontPtr)( - LPDIRECT3DDEVICE9 pDevice, - int Height, - UINT Width, - UINT Weight, - UINT MipLevels, - bool Italic, - DWORD CharSet, - DWORD OutputPrecision, - DWORD Quality, - DWORD PitchAndFamily, - LPCWSTR pFaceName, - LPD3DXFONT* ppFont); - - void InitStats(); - void ResetStats(); - void DrawStats(); - virtual void OnResetDevice() {}; - void SendResetRequest(); - - double GetFrameTime() const; - double GetFrameRate() const; - - - int m_nTearingPos; - VMR9AlphaBitmap m_VMR9AlphaBitmap; - CAutoVectorPtr m_VMR9AlphaBitmapData; - CRect m_VMR9AlphaBitmapRect; - int m_VMR9AlphaBitmapWidthBytes; - - D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory; - D3DXLoadSurfaceFromSurfacePtr m_pD3DXLoadSurfaceFromSurface; - D3DXCreateLinePtr m_pD3DXCreateLine; - D3DXCreateFontPtr m_pD3DXCreateFont; - HRESULT(__stdcall* m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); - - - - int m_nVMR9Surfaces; // Total number of DX Surfaces - int m_iVMR9Surface; - long m_nUsedBuffer; - - double m_fAvrFps; // Estimate the real FPS - double m_fJitterStdDev; // Estimate the Jitter std dev - double m_fJitterMean; - double m_fSyncOffsetStdDev; - double m_fSyncOffsetAvr; - double m_DetectedRefreshRate; - - CCritSec m_refreshRateLock; - double m_DetectedRefreshTime; - double m_DetectedRefreshTimePrim; - double m_DetectedScanlineTime; - double m_DetectedScanlineTimePrim; - double m_DetectedScanlinesPerFrame; - - double GetRefreshRate() const { - if (m_DetectedRefreshRate) { - return m_DetectedRefreshRate; - } - return m_refreshRate; - } - - LONG GetScanLines() const { - if (m_DetectedRefreshRate) { - return (LONG)m_DetectedScanlinesPerFrame; - } - return m_ScreenSize.cy; - } - - double m_ldDetectedRefreshRateList[100]; - double m_ldDetectedScanlineRateList[100]; - int m_DetectedRefreshRatePos; - bool m_bSyncStatsAvailable; - LONGLONG m_pllJitter [NB_JITTER]; // Jitter buffer for stats - LONGLONG m_pllSyncOffset [NB_JITTER]; // Jitter buffer for stats - LONGLONG m_llLastPerf; - LONGLONG m_JitterStdDev; - LONGLONG m_MaxJitter; - LONGLONG m_MinJitter; - LONGLONG m_MaxSyncOffset; - LONGLONG m_MinSyncOffset; - int m_nNextJitter; - int m_nNextSyncOffset; - REFERENCE_TIME m_rtTimePerFrame; - double m_DetectedFrameRate; - double m_DetectedFrameTime; - double m_DetectedFrameTimeStdDev; - bool m_DetectedLock; - LONGLONG m_DetectedFrameTimeHistory[60]; - double m_DetectedFrameTimeHistoryHistory[500]; - int m_DetectedFrameTimePos; - int m_bInterlaced; - - int m_VBlankEndWait; - int m_VBlankStartWait; - LONGLONG m_VBlankWaitTime; - LONGLONG m_VBlankLockTime; - int m_VBlankMin; - int m_VBlankMinCalc; - int m_VBlankMax; - int m_VBlankEndPresent; - LONGLONG m_VBlankStartMeasureTime; - int m_VBlankStartMeasure; - - LONGLONG m_PresentWaitTime; - LONGLONG m_PresentWaitTimeMin; - LONGLONG m_PresentWaitTimeMax; - - LONGLONG m_PaintTime; - LONGLONG m_PaintTimeMin; - LONGLONG m_PaintTimeMax; - - LONGLONG m_WaitForGPUTime; - - LONGLONG m_RasterStatusWaitTime; - LONGLONG m_RasterStatusWaitTimeMin; - LONGLONG m_RasterStatusWaitTimeMax; - LONGLONG m_RasterStatusWaitTimeMaxCalc; - - double m_ClockDiffCalc; - double m_ClockDiffPrim; - double m_ClockDiff; - - double m_TimeChangeHistory[100]; - double m_ClockChangeHistory[100]; - int m_ClockTimeChangeHistoryPos; - double m_ModeratedTimeSpeed; - double m_ModeratedTimeSpeedPrim; - double m_ModeratedTimeSpeedDiff; - - bool m_bCorrectedFrameTime; - int m_FrameTimeCorrection; - LONGLONG m_LastFrameDuration; - LONGLONG m_LastSampleTime; - - CString m_strStatsMsg[10]; - - CString m_D3D9Device; - - CString m_Decoder; - - CFocusThread* m_FocusThread; - HWND m_hFocusWindow; - - public: - CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString& _Error, bool isPreview = false); - ~CDX9AllocatorPresenter(); - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); - STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); - STDMETHODIMP_(bool) ResetDevice(); - STDMETHODIMP_(bool) DisplayChange(); - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() { - return m_bIsRendering; - } - - // ID3DFullscreenControl - STDMETHODIMP SetD3DFullscreen(bool fEnabled); - STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); - }; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#pragma once + +#include "DX9RenderingEngine.h" +#include + +#define VMRBITMAP_UPDATE 0x80000000 +#define NB_JITTER 126 + +class CFocusThread; + +namespace DSObjects +{ + + class CDX9AllocatorPresenter + : public CDX9RenderingEngine + , public ID3DFullscreenControl + { + public: + CCritSec m_VMR9AlphaBitmapLock; + void UpdateAlphaBitmap(); + protected: + bool m_bAlternativeVSync; + bool m_bCompositionEnabled; + bool m_bIsEVR; + int m_OrderedPaint; + int m_VSyncMode; + bool m_bDesktopCompositionDisabled; + bool m_bIsFullscreen, fullScreenChanged; + bool m_bNeedCheckSample; + DWORD m_MainThreadId; + bool m_bIsPreview; + bool m_bIsRendering; + + CRenderersSettings::CAdvRendererSettings m_LastRendererSettings; + + HMODULE m_hDWMAPI; + + HRESULT(__stdcall* m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled); + HRESULT(__stdcall* m_pDwmEnableComposition)(UINT uCompositionAction); + + CCritSec m_RenderLock; + CComPtr m_pDirectDraw; + + HANDLE LockD3DDevice() { + if (m_pD3DDev) { + _RTL_CRITICAL_SECTION* pCritSec = (_RTL_CRITICAL_SECTION*)((size_t)m_pD3DDev.p + sizeof(size_t)); + + if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec)) + && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo)))) { + if (pCritSec->DebugInfo->CriticalSection == pCritSec) { + EnterCriticalSection(pCritSec); + return pCritSec->OwningThread; + } + } + } + return 0; + } + + void UnlockD3DDevice(HANDLE& lockOwner) { + if (m_pD3DDev) { + _RTL_CRITICAL_SECTION* pCritSec = (_RTL_CRITICAL_SECTION*)((size_t)m_pD3DDev.p + sizeof(size_t)); + + if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec)) + && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo)))) { + if (pCritSec->DebugInfo->CriticalSection == pCritSec && pCritSec->OwningThread == lockOwner) { + LeaveCriticalSection(pCritSec); + } + } + } + } + + CString m_D3DDevExError; + CComPtr m_pOSDTexture; + CComPtr m_pOSDSurface; + CComPtr m_pLine; + CComPtr m_pFont; + bool m_bAlphaBitmapEnable = false; + CComPtr m_pAlphaBitmapTexture; + MFVideoAlphaBitmapParams m_AlphaBitmapParams = {}; + + CComPtr m_pSprite; + + bool SettingsNeedResetDevice(CRenderersSettings& r); + + virtual HRESULT CreateDevice(CString& _Error); + virtual HRESULT AllocSurfaces(); + virtual void DeleteSurfaces(); + + LONGLONG m_LastAdapterCheck; + UINT GetAdapter(IDirect3D9* pD3D, bool bGetAdapter = true); + DWORD GetVertexProcessing(); + + bool GetVBlank(int& _ScanLine, int& _bInVBlank, bool _bMeasureTime); + bool WaitForVBlankRange(int& _RasterStart, int _RasterEnd, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, HANDLE& lockOwner); + bool WaitForVBlank(bool& _Waited, HANDLE& lockOwner); + int GetVBlackPos(); + void CalculateJitter(LONGLONG PerformanceCounter); + virtual void OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter) {} + + // Casimir666 + typedef HRESULT(WINAPI* D3DXLoadSurfaceFromMemoryPtr)( + LPDIRECT3DSURFACE9 pDestSurface, + CONST PALETTEENTRY* pDestPalette, + CONST RECT* pDestRect, + LPCVOID pSrcMemory, + D3DFORMAT SrcFormat, + UINT SrcPitch, + CONST PALETTEENTRY* pSrcPalette, + CONST RECT* pSrcRect, + DWORD Filter, + D3DCOLOR ColorKey); + + typedef HRESULT(WINAPI* D3DXLoadSurfaceFromSurfacePtr)( + LPDIRECT3DSURFACE9 pDestSurface, + CONST PALETTEENTRY* pDestPalette, + CONST RECT* pDestRect, + LPDIRECT3DSURFACE9 pSrcSurface, + CONST PALETTEENTRY* pSrcPalette, + CONST RECT* pSrcRect, + DWORD Filter, + D3DCOLOR ColorKey); + + typedef HRESULT(WINAPI* D3DXCreateLinePtr)(LPDIRECT3DDEVICE9 pDevice, LPD3DXLINE* ppLine); + + typedef HRESULT(WINAPI* D3DXCreateFontPtr)( + LPDIRECT3DDEVICE9 pDevice, + int Height, + UINT Width, + UINT Weight, + UINT MipLevels, + bool Italic, + DWORD CharSet, + DWORD OutputPrecision, + DWORD Quality, + DWORD PitchAndFamily, + LPCWSTR pFaceName, + LPD3DXFONT* ppFont); + + void InitStats(); + void ResetStats(); + void DrawStats(); + virtual void OnResetDevice() {}; + void SendResetRequest(); + + double GetFrameTime() const; + double GetFrameRate() const; + + + int m_nTearingPos; + VMR9AlphaBitmap m_VMR9AlphaBitmap; + CAutoVectorPtr m_VMR9AlphaBitmapData; + CRect m_VMR9AlphaBitmapRect; + int m_VMR9AlphaBitmapWidthBytes; + + D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory; + D3DXLoadSurfaceFromSurfacePtr m_pD3DXLoadSurfaceFromSurface; + D3DXCreateLinePtr m_pD3DXCreateLine; + D3DXCreateFontPtr m_pD3DXCreateFont; + HRESULT(__stdcall* m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); + + + + int m_nVMR9Surfaces; // Total number of DX Surfaces + int m_iVMR9Surface; + long m_nUsedBuffer; + + double m_fAvrFps; // Estimate the real FPS + double m_fJitterStdDev; // Estimate the Jitter std dev + double m_fJitterMean; + double m_fSyncOffsetStdDev; + double m_fSyncOffsetAvr; + double m_DetectedRefreshRate; + + CCritSec m_refreshRateLock; + double m_DetectedRefreshTime; + double m_DetectedRefreshTimePrim; + double m_DetectedScanlineTime; + double m_DetectedScanlineTimePrim; + double m_DetectedScanlinesPerFrame; + + double GetRefreshRate() const { + if (m_DetectedRefreshRate) { + return m_DetectedRefreshRate; + } + return m_refreshRate; + } + + LONG GetScanLines() const { + if (m_DetectedRefreshRate) { + return (LONG)m_DetectedScanlinesPerFrame; + } + return m_ScreenSize.cy; + } + + double m_ldDetectedRefreshRateList[100]; + double m_ldDetectedScanlineRateList[100]; + int m_DetectedRefreshRatePos; + bool m_bSyncStatsAvailable; + LONGLONG m_pllJitter [NB_JITTER]; // Jitter buffer for stats + LONGLONG m_pllSyncOffset [NB_JITTER]; // Jitter buffer for stats + LONGLONG m_llLastPerf; + LONGLONG m_JitterStdDev; + LONGLONG m_MaxJitter; + LONGLONG m_MinJitter; + LONGLONG m_MaxSyncOffset; + LONGLONG m_MinSyncOffset; + int m_nNextJitter; + int m_nNextSyncOffset; + REFERENCE_TIME m_rtTimePerFrame; + double m_DetectedFrameRate; + double m_DetectedFrameTime; + double m_DetectedFrameTimeStdDev; + bool m_DetectedLock; + LONGLONG m_DetectedFrameTimeHistory[60]; + double m_DetectedFrameTimeHistoryHistory[500]; + int m_DetectedFrameTimePos; + int m_bInterlaced; + + int m_VBlankEndWait; + int m_VBlankStartWait; + LONGLONG m_VBlankWaitTime; + LONGLONG m_VBlankLockTime; + int m_VBlankMin; + int m_VBlankMinCalc; + int m_VBlankMax; + int m_VBlankEndPresent; + LONGLONG m_VBlankStartMeasureTime; + int m_VBlankStartMeasure; + + LONGLONG m_PresentWaitTime; + LONGLONG m_PresentWaitTimeMin; + LONGLONG m_PresentWaitTimeMax; + + LONGLONG m_PaintTime; + LONGLONG m_PaintTimeMin; + LONGLONG m_PaintTimeMax; + + LONGLONG m_WaitForGPUTime; + + LONGLONG m_RasterStatusWaitTime; + LONGLONG m_RasterStatusWaitTimeMin; + LONGLONG m_RasterStatusWaitTimeMax; + LONGLONG m_RasterStatusWaitTimeMaxCalc; + + double m_ClockDiffCalc; + double m_ClockDiffPrim; + double m_ClockDiff; + + double m_TimeChangeHistory[100]; + double m_ClockChangeHistory[100]; + int m_ClockTimeChangeHistoryPos; + double m_ModeratedTimeSpeed; + double m_ModeratedTimeSpeedPrim; + double m_ModeratedTimeSpeedDiff; + + bool m_bCorrectedFrameTime; + int m_FrameTimeCorrection; + LONGLONG m_LastFrameDuration; + LONGLONG m_LastSampleTime; + + CString m_strStatsMsg[10]; + + CString m_D3D9Device; + + CString m_Decoder; + + CFocusThread* m_FocusThread; + HWND m_hFocusWindow; + + public: + CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString& _Error, bool isPreview = false); + ~CDX9AllocatorPresenter(); + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); + STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); + STDMETHODIMP_(bool) ResetDevice(); + STDMETHODIMP_(bool) DisplayChange(); + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() { + return m_bIsRendering; + } + + // ID3DFullscreenControl + STDMETHODIMP SetD3DFullscreen(bool fEnabled); + STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); + }; +} diff --git a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp index 5f4e51c6a48..27a1e9cc907 100644 --- a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp +++ b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.cpp @@ -1,1755 +1,1755 @@ -/* - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#pragma warning(disable: 5033) // warning C5033: 'register' is no longer a supported storage class -#include "lcms2/library/include/lcms2.h" -#include "../../../mpc-hc/resource.h" -#include "Dither.h" -#include "DX9RenderingEngine.h" -#include "../../../mpc-hc/ColorProfileUtil.h" - -// UUID for vorpX hack -static const IID IID_D3D9VorpVideoCaptureTexture = { 0x8a49d79, 0x8646, 0x4867, { 0xb9, 0x34, 0x13, 0x12, 0xe4, 0x4b, 0x23, 0xdb } }; - -#pragma pack(push, 1) -template -struct MYD3DVERTEX { - float x, y, z, rhw; - struct { - float u, v; - } t[texcoords]; -}; - -template<> -struct MYD3DVERTEX<0> { - float x, y, z, rhw; - DWORD Diffuse; -}; -#pragma pack(pop) - -template -static void AdjustQuad(MYD3DVERTEX* v, double dx, double dy) -{ - float offset = 0.5; - - for (int i = 0; i < 4; i++) { - v[i].x -= offset; - v[i].y -= offset; - - for (int j = 0; j < std::max(texcoords - 1, 1); j++) { - v[i].t[j].u -= (float)(offset * dx); - v[i].t[j].v -= (float)(offset * dy); - } - - if constexpr(texcoords > 1) { - v[i].t[texcoords - 1].u -= offset; - v[i].t[texcoords - 1].v -= offset; - } - } -} - -template -static HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter) -{ - CheckPointer(pD3DDev, E_POINTER); - - DWORD FVF = 0; - - switch (texcoords) { - case 1: - FVF = D3DFVF_TEX1; - break; - case 2: - FVF = D3DFVF_TEX2; - break; - case 3: - FVF = D3DFVF_TEX3; - break; - case 4: - FVF = D3DFVF_TEX4; - break; - case 5: - FVF = D3DFVF_TEX5; - break; - case 6: - FVF = D3DFVF_TEX6; - break; - case 7: - FVF = D3DFVF_TEX7; - break; - case 8: - FVF = D3DFVF_TEX8; - break; - default: - return E_FAIL; - } - - pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); - - for (int i = 0; i < texcoords; i++) { - pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); - pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter); - pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - } - - // - - pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF); - //pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0])); - - MYD3DVERTEX tmp = v[2]; - v[2] = v[3]; - v[3] = tmp; - pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); - - // - - for (int i = 0; i < texcoords; i++) { - pD3DDev->SetTexture(i, nullptr); - } - - return S_OK; -} - - -using namespace DSObjects; - -CDX9RenderingEngine::CDX9RenderingEngine(HWND hWnd, HRESULT& hr, CString* _pError) - : CSubPicAllocatorPresenterImpl(hWnd, hr, _pError) - , m_CurrentAdapter(UINT_ERROR) - , m_BackbufferType(D3DFMT_UNKNOWN) - , m_DisplayType(D3DFMT_UNKNOWN) - , m_ScreenSize(0, 0) - , m_nNbDXSurface(1) - , m_nCurSurface(0) - , m_bHighColorResolution(false) - , m_bForceInputHighColorResolution(false) - , m_RenderingPath(RENDERING_PATH_DRAW) - , m_SurfaceType(D3DFMT_UNKNOWN) - , m_bFullFloatingPointProcessing(false) - , m_bHalfFloatingPointProcessing(false) - , m_bColorManagement(false) - , m_InputVideoSystem(VIDEO_SYSTEM_UNKNOWN) - , m_AmbientLight(AMBIENT_LIGHT_BRIGHT) - , m_RenderingIntent(COLOR_RENDERING_INTENT_PERCEPTUAL) - , m_ScreenSpacePassCount(1) - , m_ScreenSpacePassSrc(0) - , m_ScreenSpacePassDest(1) - , m_pRenderTarget(nullptr) - , m_BicubicA(0) - , m_bFinalPass(false) - , m_Lut3DSize(64) - , m_Lut3DEntryCount(64 * 64 * 64) - , m_StretchRectFilter(D3DTEXF_NONE) - , m_pD3DXFloat32To16Array(nullptr) -{ - ZeroMemory(&m_Caps, sizeof(m_Caps)); - HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); - m_bD3DX = hDll != nullptr; - - if (m_bD3DX) { - (FARPROC&)m_pD3DXFloat32To16Array = GetProcAddress(hDll, "D3DXFloat32To16Array"); - } -} - -void CDX9RenderingEngine::InitRenderingEngine() -{ - m_StretchRectFilter = D3DTEXF_LINEAR;// eliminate this chain ASAP - - // Initialize the pixel shader compiler - m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); - - // Initialize settings - m_BicubicA = 0; -} - -void CDX9RenderingEngine::CleanupRenderingEngine() -{ - m_pPSC.Free(); - - for (int i = 0; i < 4; i++) { - m_pResizerPixelShaders[i] = nullptr; - } - - CleanupFinalPass(); - - POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - pos = m_pCustomPixelShaders.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - - for (int i = 0; i < 2; i++) { - m_pTemporaryVideoTextures[i] = nullptr; - m_pTemporaryScreenSpaceTextures[i] = nullptr; - } -} - -HRESULT CDX9RenderingEngine::CreateVideoSurfaces() -{ - HRESULT hr; - const CRenderersSettings& r = GetRenderersSettings(); - - // Free previously allocated video surfaces - FreeVideoSurfaces(); - - // Free previously allocated temporary video textures, because the native video size might have been changed! - for (int i = 0; i < 2; i++) { - m_pTemporaryVideoTextures[i] = nullptr; - } - - CheckPointer(m_pD3DDev, E_POINTER); - - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { - int nTexturesNeeded = r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nNbDXSurface : 1; - - for (int i = 0; i < nTexturesNeeded; i++) { - if (FAILED(hr = m_pD3DDev->CreateTexture( - m_nativeVideoSize.cx, - m_nativeVideoSize.cy, 1, - D3DUSAGE_RENDERTARGET, - m_SurfaceType, - D3DPOOL_DEFAULT, - &m_pVideoTexture[i], - nullptr))) { - return hr; - } - - if (FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i]))) { - return hr; - } - } - - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D) { - m_RenderingPath = RENDERING_PATH_STRETCHRECT; - - for (int i = 0; i < m_nNbDXSurface; i++) { - m_pVideoTexture[i] = nullptr; - } - } else { - m_RenderingPath = RENDERING_PATH_DRAW; - } - } else { - m_RenderingPath = RENDERING_PATH_STRETCHRECT; - - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface( - m_nativeVideoSize.cx, m_nativeVideoSize.cy, - m_SurfaceType, - D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], nullptr))) { - return hr; - } - } - - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1, 0); - - return S_OK; -} - -void CDX9RenderingEngine::FreeVideoSurfaces() -{ - for (int i = 0; i < m_nNbDXSurface; i++) { - m_pVideoTexture[i] = nullptr; - m_pVideoSurface[i] = nullptr; - } -} - -HRESULT CDX9RenderingEngine::RenderVideo(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) -{ - if (destRect.IsRectEmpty()) { - return S_OK; - } - - if (m_RenderingPath == RENDERING_PATH_DRAW) { - return RenderVideoDrawPath(pRenderTarget, srcRect, destRect); - } else { - return RenderVideoStretchRectPath(pRenderTarget, srcRect, destRect); - } -} - -HRESULT CDX9RenderingEngine::RenderVideoDrawPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) -{ - HRESULT hr; - - // Return if the video texture is not initialized - if (m_pVideoTexture[m_nCurSurface] == 0) { - return S_OK; - } - - const CRenderersSettings& r = GetRenderersSettings(); - - // Initialize the processing pipeline - bool bCustomPixelShaders; - bool bResizerShaders; - bool bCustomScreenSpacePixelShaders; - bool bFinalPass; - - int screenSpacePassCount = 0; - DWORD iDX9Resizer = r.iDX9Resizer; - - if (m_bD3DX) { - // Final pass. Must be initialized first! - hr = InitFinalPass(); - if (SUCCEEDED(hr)) { - bFinalPass = m_bFinalPass; - } else { - bFinalPass = false; - } - - if (bFinalPass) { - ++screenSpacePassCount; - } - - // Resizers - float bicubicA = 0; - switch (iDX9Resizer) { - case 3: - bicubicA = -0.60f; - break; - case 4: - bicubicA = -0.751f; - break; // FIXME : 0.75 crash recent D3D, or eat CPU - case 5: - bicubicA = -1.00f; - break; - } - - hr = InitResizers(bicubicA); - bResizerShaders = SUCCEEDED(hr); - screenSpacePassCount += 1; // currently all resizers are 1-pass - - // Custom screen space pixel shaders - bCustomScreenSpacePixelShaders = !m_pCustomScreenSpacePixelShaders.IsEmpty(); - - if (bCustomScreenSpacePixelShaders) { - screenSpacePassCount += (int)m_pCustomScreenSpacePixelShaders.GetCount(); - } - - // Custom pixel shaders - bCustomPixelShaders = !m_pCustomPixelShaders.IsEmpty(); - - hr = InitTemporaryVideoTextures(std::min((int)m_pCustomPixelShaders.GetCount(), 2)); - if (FAILED(hr)) { - bCustomPixelShaders = false; - } - } else { - bCustomPixelShaders = false; - bResizerShaders = false; - bCustomScreenSpacePixelShaders = false; - bFinalPass = false; - } - - hr = InitScreenSpacePipeline(screenSpacePassCount, pRenderTarget); - if (FAILED(hr)) { - bCustomScreenSpacePixelShaders = false; - bFinalPass = false; - } - - // Apply the custom pixel shaders if there are any. Result: pVideoTexture - CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; - - if (bCustomPixelShaders) { - static __int64 counter = 0; - static long start = clock(); - - long stop = clock(); - long diff = stop - start; - - if (diff >= 10 * 60 * CLOCKS_PER_SEC) { - start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) - } - -#if 1 - D3DSURFACE_DESC desc; - m_pVideoTexture[m_nCurSurface]->GetLevelDesc(0, &desc); - - float fConstData[][4] = { - {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, - }; -#else - CSize VideoSize = GetVisibleVideoSize(); - - float fConstData[][4] = { - {(float)VideoSize.cx, (float)VideoSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / VideoSize.cx, 1.0f / VideoSize.cy, 0, 0}, - }; -#endif - - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - int src = 1; - int dest = 0; - bool first = true; - - POSITION pos = m_pCustomPixelShaders.GetHeadPosition(); - while (pos) { - CComPtr pTemporarySurface; - hr = m_pTemporaryVideoTextures[dest]->GetSurfaceLevel(0, &pTemporarySurface); - hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); - - CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); - if (!Shader.m_pPixelShader) { - Shader.Compile(m_pPSC); - } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); - - if (first) { - TextureCopy(m_pVideoTexture[m_nCurSurface]); - first = false; - } else { - TextureCopy(m_pTemporaryVideoTextures[src]); - } - - std::swap(src, dest); - } - - pVideoTexture = m_pTemporaryVideoTextures[src]; - } - - // Hack to send the pre-resize video texture to vorpX. - void* pVorpTex = pVideoTexture; // Prevent the pointer being overwritten. - m_pD3DDev->QueryInterface(IID_D3D9VorpVideoCaptureTexture, (void**)&pVorpTex); - - // Resize the frame - Vector dst[4]; - Transform(destRect, dst); - - hr = BeginScreenSpacePass(); - - if (m_ScreenSpacePassCount > 0) { - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); - } - - if (srcRect.Size() != destRect.Size()) { - if (iDX9Resizer == 0 || iDX9Resizer == 1 || !bResizerShaders) { - D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; - hr = TextureResize(pVideoTexture, dst, Filter, srcRect); - } else if (iDX9Resizer == 2) { - hr = TextureResizeBilinear(pVideoTexture, dst, srcRect); - } else if (iDX9Resizer >= 3) { - hr = TextureResizeBicubic1pass(pVideoTexture, dst, srcRect); - } - } else { - hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, srcRect); - } - - // Apply the custom screen size pixel shaders - if (bCustomScreenSpacePixelShaders) { - static __int64 counter = 555; - static long start = clock() + 333; - - long stop = clock() + 333; - long diff = stop - start; - - if (diff >= 10 * 60 * CLOCKS_PER_SEC) { - start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) - } - - float fConstData[][4] = { - {(float)m_TemporaryScreenSpaceTextureSize.cx, (float)m_TemporaryScreenSpaceTextureSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / m_TemporaryScreenSpaceTextureSize.cx, 1.0f / m_TemporaryScreenSpaceTextureSize.cy, 0, 0}, - }; - - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); - while (pos) { - BeginScreenSpacePass(); - - CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); - if (!Shader.m_pPixelShader) { - Shader.Compile(m_pPSC); - } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); - TextureCopy(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); - } - } - - // Final pass - if (bFinalPass) { - hr = BeginScreenSpacePass(); - hr = FinalPass(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); - } - - hr = m_pD3DDev->SetPixelShader(nullptr); - - return hr; -} - -HRESULT CDX9RenderingEngine::RenderVideoStretchRectPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) -{ - HRESULT hr; - - // Return if the render target or the video surface is not initialized - if (pRenderTarget == 0 || m_pVideoSurface[m_nCurSurface] == 0) { - return S_OK; - } - - CRect rSrcVid(srcRect); - CRect rDstVid(destRect); - - ClipToSurface(pRenderTarget, rSrcVid, rDstVid); // grrr - // IMPORTANT: rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect!!! - rSrcVid.left &= ~1; - rSrcVid.right &= ~1; - rSrcVid.top &= ~1; - rSrcVid.bottom &= ~1; - hr = m_pD3DDev->StretchRect(m_pVideoSurface[m_nCurSurface], rSrcVid, pRenderTarget, rDstVid, m_StretchRectFilter); - - return hr; -} - -HRESULT CDX9RenderingEngine::InitTemporaryVideoTextures(int count) -{ - HRESULT hr = S_OK; - - for (int i = 0; i < count; i++) { - if (m_pTemporaryVideoTextures[i] == nullptr) { - hr = m_pD3DDev->CreateTexture( - m_nativeVideoSize.cx, - m_nativeVideoSize.cy, - 1, - D3DUSAGE_RENDERTARGET, - m_SurfaceType, - D3DPOOL_DEFAULT, - &m_pTemporaryVideoTextures[i], - nullptr); - - if (FAILED(hr)) { - // Free all textures - for (int j = 0; j < 2; j++) { - m_pTemporaryVideoTextures[j] = nullptr; - } - - return hr; - } - } - } - - // Free unnecessary textures - for (int i = count; i < 2; i++) { - m_pTemporaryVideoTextures[i] = nullptr; - } - - return hr; -} - -HRESULT CDX9RenderingEngine::InitScreenSpacePipeline(int passCount, IDirect3DSurface9* pRenderTarget) -{ - m_pRenderTarget = pRenderTarget; - m_ScreenSpacePassCount = passCount; - m_ScreenSpacePassSrc = 0; - m_ScreenSpacePassDest = 1; - - HRESULT hr = InitTemporaryScreenSpaceTextures(std::min(passCount - 1, 2)); - - // If the initialized have failed, disable the pipeline - if (FAILED(hr)) { - m_ScreenSpacePassCount = 1; - } - - return hr; -} - -HRESULT CDX9RenderingEngine::InitTemporaryScreenSpaceTextures(int count) -{ - HRESULT hr = S_OK; - - for (int i = 0; i < count; i++) { - if (m_pTemporaryScreenSpaceTextures[i] == nullptr) { - m_TemporaryScreenSpaceTextureSize = CSize(std::min(std::max(m_BackBufferSize.cx, m_nativeVideoSize.cx), (long)m_Caps.MaxTextureWidth), - std::min(std::max(m_BackBufferSize.cy, m_nativeVideoSize.cy), (long)m_Caps.MaxTextureHeight)); - hr = m_pD3DDev->CreateTexture( - m_TemporaryScreenSpaceTextureSize.cx, - m_TemporaryScreenSpaceTextureSize.cy, - 1, - D3DUSAGE_RENDERTARGET, - m_SurfaceType, - D3DPOOL_DEFAULT, - &m_pTemporaryScreenSpaceTextures[i], - nullptr); - - if (FAILED(hr)) { - // Free all textures - for (int j = 0; j < 2; j++) { - m_pTemporaryScreenSpaceTextures[j] = nullptr; - } - - return hr; - } - } - } - - // Free unnecessary textures - for (int i = count; i < 2; i++) { - m_pTemporaryScreenSpaceTextures[i] = nullptr; - } - - return hr; -} - -HRESULT CDX9RenderingEngine::BeginScreenSpacePass() -{ - HRESULT hr; - - std::swap(m_ScreenSpacePassSrc, m_ScreenSpacePassDest); - --m_ScreenSpacePassCount; - - if (m_ScreenSpacePassCount > 0) { - CComPtr pTemporarySurface; - hr = m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassDest]->GetSurfaceLevel(0, &pTemporarySurface); - - if (SUCCEEDED(hr)) { - hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); - } - } else { - hr = m_pD3DDev->SetRenderTarget(0, m_pRenderTarget); - } - - return hr; -} - -HRESULT CDX9RenderingEngine::InitResizers(float bicubicA) -{ - HRESULT hr; - - // Check whether the resizer pixel shaders must be initialized - bool bInitRequired = false; - - if (bicubicA) { - for (int i = 0; i < 4; i++) { - if (!m_pResizerPixelShaders[i]) { - bInitRequired = true; - } - } - - if (m_BicubicA != bicubicA) { - bInitRequired = true; - } - } else { - if (!m_pResizerPixelShaders[0]) { - bInitRequired = true; - } - } - - if (!bInitRequired) { - return S_OK; - } - - // Initialize the resizer pixel shaders - m_BicubicA = bicubicA; - - for (int i = 0; i < _countof(m_pResizerPixelShaders); i++) { - m_pResizerPixelShaders[i] = nullptr; - } - - if (m_Caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { - return E_FAIL; - } - - LPCSTR pProfile = m_Caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; - - CStringA str; - if (!LoadResource(IDF_SHADER_RESIZER, str, _T("SHADER"))) { - return E_FAIL; - } - - CStringA A; - A.Format("(%f)", bicubicA); - str.Replace("_The_Value_Of_A_Is_Set_Here_", A); - - LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass_pass1", "main_bicubic2pass_pass2"}; - - ASSERT(_countof(pEntries) == _countof(m_pResizerPixelShaders)); - - for (int i = 0; i < _countof(pEntries); i++) { - CString ErrorMessage; - CString DissAssembly; - hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShaders[i], &DissAssembly, &ErrorMessage); - if (FAILED(hr)) { - TRACE(_T("%ws"), ErrorMessage.GetString()); - ASSERT(0); - return hr; - } - /* - if (i == 2 || i == 3) - { - const wchar_t *pStr = DissAssembly.GetString(); - TRACE(_T("DisAsm: %s\n"), pEntries[i]); - const wchar_t *pStrStart = pStr; - while (*pStr) - { - while (*pStr && *pStr != '\n') - ++pStr; - if (*pStr == '\n') - ++pStr; - if (*pStr == '\r') - ++pStr; - CString Test(pStrStart, pStr - pStrStart); - TRACE(_T("%ws"), Test.GetString()); - pStrStart = pStr; - } - } - */ - } - - return S_OK; -} - -HRESULT CDX9RenderingEngine::TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& srcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - float dx2 = 1.0f / w; - float dy2 = 1.0f / h; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, srcRect.left * dx2, srcRect.top * dy2}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, srcRect.right * dx2, srcRect.top * dy2}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, srcRect.left * dx2, srcRect.bottom * dy2}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, srcRect.right * dx2, srcRect.bottom * dy2}, - }; - - AdjustQuad(v, 0, 0); - - hr = m_pD3DDev->SetTexture(0, pTexture); - hr = m_pD3DDev->SetPixelShader(nullptr); - hr = TextureBlt(m_pD3DDev, v, filter); - - return hr; -} - -HRESULT CDX9RenderingEngine::TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway - const float dx = 1.0f / (float)desc.Width; - const float dy = 1.0f / (float)desc.Height; - const float tx0 = (float)srcRect.left; - const float tx1 = (float)srcRect.right; - const float ty0 = (float)srcRect.top; - const float ty1 = (float)srcRect.bottom; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, - }; - - AdjustQuad(v, 1.0, 1.0); - - hr = m_pD3DDev->SetTexture(0, pTexture); - - float fConstData[][4] = {{dx * 0.5f, dy * 0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - hr = m_pD3DDev->SetTexture(0, pTexture); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[0]); - - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - return hr; -} - -HRESULT CDX9RenderingEngine::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway - const float dx = 1.0f / (float)desc.Width; - const float dy = 1.0f / (float)desc.Height; - const float tx0 = (float)srcRect.left; - const float tx1 = (float)srcRect.right; - const float ty0 = (float)srcRect.top; - const float ty1 = (float)srcRect.bottom; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, - }; - - AdjustQuad(v, 1.0, 1.0); - - hr = m_pD3DDev->SetTexture(0, pTexture); - - float fConstData[][4] = {{dx * 0.5f, dy * 0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[1]); - - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - return hr; -} - -/* -// The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction. -HRESULT CDX9RenderingEngine::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect &srcRect) -{ - HRESULT hr; - - // rotated? - if (dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z - || dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x) - return TextureResizeBicubic1pass(pTexture, dst, srcRect); - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) - return E_FAIL; - - float Tex0_Width = desc.Width; - float Tex0_Height = desc.Height; - - double dx0 = 1.0/desc.Width; - UNREFERENCED_PARAMETER(dx0); - double dy0 = 1.0/desc.Height; - UNREFERENCED_PARAMETER(dy0); - - CSize SrcTextSize = CSize(desc.Width, desc.Height); - double w = (double)srcRect.Width(); - double h = (double)srcRect.Height(); - UNREFERENCED_PARAMETER(w); - - CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h); - - if (!m_pTemporaryScreenSpaceTextures[0] || FAILED(m_pTemporaryScreenSpaceTextures[0]->GetLevelDesc(0, &desc))) - return TextureResizeBicubic1pass(pTexture, dst, srcRect); - - float Tex1_Width = desc.Width; - float Tex1_Height = desc.Height; - - double dx1 = 1.0/desc.Width; - UNREFERENCED_PARAMETER(dx1); - double dy1 = 1.0/desc.Height; - UNREFERENCED_PARAMETER(dy1); - - double dw = (double)dst1.Width() / desc.Width; - UNREFERENCED_PARAMETER(dw); - double dh = (double)dst1.Height() / desc.Height; - UNREFERENCED_PARAMETER(dh); - - float dx2 = 1.0f/SrcTextSize.cx; - UNREFERENCED_PARAMETER(dx2); - float dy2 = 1.0f/SrcTextSize.cy; - UNREFERENCED_PARAMETER(dy2); - - float tx0 = srcRect.left; - float tx1 = srcRect.right; - float ty0 = srcRect.top; - float ty1 = srcRect.bottom; - - float tx0_2 = 0; - float tx1_2 = dst1.Width(); - float ty0_2 = 0; - float ty1_2 = h; - - // ASSERT(dst1.Height() == desc.Height); - - if (dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height) - // if (dst1.Width() != desc.Width || dst1.Height() != desc.Height) - return TextureResizeBicubic1pass(pTexture, dst, srcRect); - - MYD3DVERTEX<1> vx[] = - { - {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0}, - {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0}, - {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1}, - {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1}, - }; - - AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug here, create vertical lines ! TODO : why ?????? - - MYD3DVERTEX<1> vy[] = - { - {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2}, - {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2}, - {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2}, - {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2}, - }; - - - AdjustQuad(vy, 0.0, 1.0); // Casimir666 : bug here, create horizontal lines ! TODO : why ?????? - - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[2]); - { - float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - } - - hr = m_pD3DDev->SetTexture(0, pTexture); - - CComPtr pRTOld; - hr = m_pD3DDev->GetRenderTarget(0, &pRTOld); - - CComPtr pRT; - hr = m_pTemporaryScreenSpaceTextures[0]->GetSurfaceLevel(0, &pRT); - hr = m_pD3DDev->SetRenderTarget(0, pRT); - - hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT); - - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[3]); - { - float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - } - - hr = m_pD3DDev->SetTexture(0, m_pTemporaryScreenSpaceTextures[0]); - - hr = m_pD3DDev->SetRenderTarget(0, pRTOld); - - hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT); - return hr; -} -*/ - -HRESULT CDX9RenderingEngine::Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect) -{ - HRESULT hr = E_FAIL; - - const CRenderersSettings& r = GetRenderersSettings(); - - DWORD iDX9Resizer = r.iDX9Resizer; - Vector dst[4]; - Transform(destRect, dst); - - if (iDX9Resizer == 0 || iDX9Resizer == 1) { - D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; - hr = TextureResize(pTexture, dst, Filter, srcRect); - } else if (iDX9Resizer == 2) { - hr = TextureResizeBilinear(pTexture, dst, srcRect); - } else if (iDX9Resizer >= 3) { - hr = TextureResizeBicubic1pass(pTexture, dst, srcRect); - } - - return hr; -} - -HRESULT CDX9RenderingEngine::InitFinalPass() -{ - HRESULT hr; - - const CRenderersSettings& r = GetRenderersSettings(); - const CRenderersData* rd = GetRenderersData(); - - // Check whether the final pass must be initialized - bool bColorManagement = r.m_AdvRendSets.bVMR9ColorManagementEnable; - VideoSystem inputVideoSystem = static_cast(r.m_AdvRendSets.iVMR9ColorManagementInput); - AmbientLight ambientLight = static_cast(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight); - ColorRenderingIntent renderingIntent = static_cast(r.m_AdvRendSets.iVMR9ColorManagementIntent); - - bool bInitRequired = false; - - if (m_bColorManagement != bColorManagement) { - bInitRequired = true; - } - - if (m_bColorManagement && bColorManagement) { - if ((m_InputVideoSystem != inputVideoSystem) || - (m_RenderingIntent != renderingIntent) || - (m_AmbientLight != ambientLight)) { - bInitRequired = true; - } - } - - if (!m_bFinalPass) { - bInitRequired = true; - } - - if (!bInitRequired) { - return S_OK; - } - - // Check whether the final pass is supported by the hardware - m_bFinalPass = rd->m_bFP16Support; - if (!m_bFinalPass) { - return S_OK; - } - - // Update the settings - m_bColorManagement = bColorManagement; - m_InputVideoSystem = inputVideoSystem; - m_AmbientLight = ambientLight; - m_RenderingIntent = renderingIntent; - - // Check whether the final pass is required - m_bFinalPass = bColorManagement || m_bFullFloatingPointProcessing || m_bHalfFloatingPointProcessing || ((m_bForceInputHighColorResolution || m_bHighColorResolution) && (m_DisplayType != D3DFMT_A2R10G10B10)); - - if (!m_bFinalPass) { - return S_OK; - } - - // Initial cleanup - m_pLut3DTexture = nullptr; - m_pFinalPixelShader = nullptr; - - if (!m_pDitherTexture) { - // Create the dither texture - hr = m_pD3DDev->CreateTexture(DITHER_MATRIX_SIZE, DITHER_MATRIX_SIZE, - 1, - D3DUSAGE_DYNAMIC, - D3DFMT_A16B16G16R16F, - D3DPOOL_DEFAULT, - &m_pDitherTexture, - nullptr); - - if (FAILED(hr)) { - CleanupFinalPass(); - return hr; - } - - D3DLOCKED_RECT lockedRect; - hr = m_pDitherTexture->LockRect(0, &lockedRect, nullptr, D3DLOCK_DISCARD); - if (FAILED(hr)) { - CleanupFinalPass(); - return hr; - } - - char* outputRowIterator = static_cast(lockedRect.pBits); - for (int y = 0; y < DITHER_MATRIX_SIZE; y++) { - unsigned short* outputIterator = reinterpret_cast(outputRowIterator); - for (int x = 0; x < DITHER_MATRIX_SIZE; x++) { - for (int i = 0; i < 4; i++) { - *outputIterator++ = DITHER_MATRIX[y][x]; - } - } - - outputRowIterator += lockedRect.Pitch; - } - - hr = m_pDitherTexture->UnlockRect(0); - if (FAILED(hr)) { - CleanupFinalPass(); - return hr; - } - } - - // Initialize the color management if necessary - if (bColorManagement) { - // Get the ICC profile path - TCHAR* iccProfilePath = ColorProfileUtil::getIccProfilePath(m_hWnd); - - // Create the 3D LUT texture - m_Lut3DSize = 64; // 64x64x64 LUT is enough for high-quality color management - m_Lut3DEntryCount = m_Lut3DSize * m_Lut3DSize * m_Lut3DSize; - - hr = m_pD3DDev->CreateVolumeTexture(m_Lut3DSize, m_Lut3DSize, m_Lut3DSize, - 1, - D3DUSAGE_DYNAMIC, - D3DFMT_A16B16G16R16F, - D3DPOOL_DEFAULT, - &m_pLut3DTexture, - nullptr); - - if (FAILED(hr)) { - delete [] iccProfilePath; - CleanupFinalPass(); - return hr; - } - - float* lut3DFloat32 = DEBUG_NEW float[m_Lut3DEntryCount * 3]; - hr = CreateIccProfileLut(iccProfilePath, lut3DFloat32); - delete [] iccProfilePath; - if (FAILED(hr)) { - delete [] lut3DFloat32; - CleanupFinalPass(); - return hr; - } - - D3DXFLOAT16* lut3DFloat16 = DEBUG_NEW D3DXFLOAT16[m_Lut3DEntryCount * 3]; - m_pD3DXFloat32To16Array(lut3DFloat16, lut3DFloat32, m_Lut3DEntryCount * 3); - delete [] lut3DFloat32; - - const float oneFloat32 = 1.0f; - D3DXFLOAT16 oneFloat16; - m_pD3DXFloat32To16Array(&oneFloat16, &oneFloat32, 1); - - D3DLOCKED_BOX lockedBox; - hr = m_pLut3DTexture->LockBox(0, &lockedBox, nullptr, D3DLOCK_DISCARD); - if (FAILED(hr)) { - delete [] lut3DFloat16; - CleanupFinalPass(); - return hr; - } - - D3DXFLOAT16* lut3DFloat16Iterator = lut3DFloat16; - char* outputSliceIterator = static_cast(lockedBox.pBits); - for (int b = 0; b < m_Lut3DSize; b++) { - char* outputRowIterator = outputSliceIterator; - - for (int g = 0; g < m_Lut3DSize; g++) { - D3DXFLOAT16* outputIterator = reinterpret_cast(outputRowIterator); - - for (int i = 0; i < m_Lut3DSize; i++) { - // R, G, B - for (int j = 0; j < 3; j++) { - *outputIterator++ = *lut3DFloat16Iterator++; - } - - // A - *outputIterator++ = oneFloat16; - } - - outputRowIterator += lockedBox.RowPitch; - } - - outputSliceIterator += lockedBox.SlicePitch; - } - - hr = m_pLut3DTexture->UnlockBox(0); - delete [] lut3DFloat16; - if (FAILED(hr)) { - CleanupFinalPass(); - return hr; - } - } - - // Compile the final pixel shader - LPCSTR pProfile = m_Caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; - - CStringA shaderSourceCode; - if (!LoadResource(IDF_SHADER_FINAL, shaderSourceCode, _T("SHADER"))) { - CleanupFinalPass(); - return E_FAIL; - } - - int quantization; - if (m_DisplayType == D3DFMT_A2R10G10B10) { - quantization = 1023; // 10-bit - } else { - quantization = 255; // 8-bit - } - - CStringA quantizationString; - quantizationString.Format("%d.", quantization); - shaderSourceCode.Replace("_QUANTIZATION_VALUE_", quantizationString); - - CStringA lut3DEnabledString; - lut3DEnabledString.Format("%d", static_cast(bColorManagement)); - shaderSourceCode.Replace("_LUT3D_ENABLED_VALUE_", lut3DEnabledString); - - if (bColorManagement) { - CStringA lut3DSizeString; - lut3DSizeString.Format("%d.", m_Lut3DSize); - shaderSourceCode.Replace("_LUT3D_SIZE_VALUE_", lut3DSizeString); - } - - CString ErrorMessage; - CString DissAssembly; - hr = m_pPSC->CompileShader(shaderSourceCode, "main", pProfile, 0, &m_pFinalPixelShader, &DissAssembly, &ErrorMessage); - if (FAILED(hr)) { - TRACE(_T("%ws"), ErrorMessage.GetString()); - ASSERT(0); - CleanupFinalPass(); - return hr; - } - - return S_OK; -} - -void CDX9RenderingEngine::CleanupFinalPass() -{ - m_bFinalPass = false; - m_pDitherTexture = nullptr; - m_pLut3DTexture = nullptr; - m_pFinalPixelShader = nullptr; -} - -HRESULT CDX9RenderingEngine::CreateIccProfileLut(TCHAR* profilePath, float* lut3D) -{ - // Get the input video system - VideoSystem videoSystem; - - if (m_InputVideoSystem == VIDEO_SYSTEM_UNKNOWN) { - static const int ntscSizes[][2] = {{720, 480}, {720, 486}, {704, 480}}; - static const int palSizes[][2] = {{720, 576}, {704, 576}}; - - videoSystem = VIDEO_SYSTEM_HDTV; // default - - for (int i = 0; i < _countof(ntscSizes); i++) { - if (m_nativeVideoSize.cx == ntscSizes[i][0] && m_nativeVideoSize.cy == ntscSizes[i][1]) { - videoSystem = VIDEO_SYSTEM_SDTV_NTSC; - } - } - - for (int i = 0; i < _countof(palSizes); i++) { - if (m_nativeVideoSize.cx == palSizes[i][0] && m_nativeVideoSize.cy == palSizes[i][1]) { - videoSystem = VIDEO_SYSTEM_SDTV_PAL; - } - } - } else { - videoSystem = m_InputVideoSystem; - } - - // Get the gamma - double gamma; - - switch (m_AmbientLight) { - case AMBIENT_LIGHT_BRIGHT: - gamma = 2.2; - break; - - case AMBIENT_LIGHT_DIM: - gamma = 2.35; - break; - - case AMBIENT_LIGHT_DARK: - gamma = 2.4; - break; - - default: - return E_FAIL; - } - - // Get the rendering intent - cmsUInt32Number intent; - - switch (m_RenderingIntent) { - case COLOR_RENDERING_INTENT_PERCEPTUAL: - intent = INTENT_PERCEPTUAL; - break; - - case COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC: - intent = INTENT_RELATIVE_COLORIMETRIC; - break; - - case COLOR_RENDERING_INTENT_SATURATION: - intent = INTENT_SATURATION; - break; - - case COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC: - intent = INTENT_ABSOLUTE_COLORIMETRIC; - break; - - default: - return E_FAIL; - } - - // Set the input white point. It's D65 in all cases. - cmsCIExyY whitePoint; - - whitePoint.x = 0.312713; - whitePoint.y = 0.329016; - whitePoint.Y = 1.0; - - // Set the input primaries - cmsCIExyYTRIPLE primaries; - - switch (videoSystem) { - case VIDEO_SYSTEM_HDTV: - // Rec. 709 - primaries.Red.x = 0.64; - primaries.Red.y = 0.33; - primaries.Green.x = 0.30; - primaries.Green.y = 0.60; - primaries.Blue.x = 0.15; - primaries.Blue.y = 0.06; - break; - - case VIDEO_SYSTEM_SDTV_NTSC: - // SMPTE-C - primaries.Red.x = 0.630; - primaries.Red.y = 0.340; - primaries.Green.x = 0.310; - primaries.Green.y = 0.595; - primaries.Blue.x = 0.155; - primaries.Blue.y = 0.070; - break; - - case VIDEO_SYSTEM_SDTV_PAL: - // PAL/SECAM - primaries.Red.x = 0.64; - primaries.Red.y = 0.33; - primaries.Green.x = 0.29; - primaries.Green.y = 0.60; - primaries.Blue.x = 0.15; - primaries.Blue.y = 0.06; - break; - - default: - return E_FAIL; - } - - primaries.Red.Y = 1.0; - primaries.Green.Y = 1.0; - primaries.Blue.Y = 1.0; - - // Set the input gamma, which is the gamma of a reference studio display we want to simulate - // For more information, see the paper at http://www.poynton.com/notes/PU-PR-IS/Poynton-PU-PR-IS.pdf - cmsToneCurve* transferFunction = cmsBuildGamma(0, gamma); - - cmsToneCurve* transferFunctionRGB[3]; - for (int i = 0; i < 3; i++) { - transferFunctionRGB[i] = transferFunction; - } - - // Create the input profile - cmsHPROFILE hInputProfile = cmsCreateRGBProfile(&whitePoint, &primaries, transferFunctionRGB); - cmsFreeToneCurve(transferFunction); - - if (hInputProfile == nullptr) { - return E_FAIL; - } - - // Open the output profile - cmsHPROFILE hOutputProfile; - FILE* outputProfileStream = nullptr; - - if (profilePath != 0) { - if (_wfopen_s(&outputProfileStream, T2W(profilePath), L"rb") != 0) { - cmsCloseProfile(hInputProfile); - return E_FAIL; - } - - hOutputProfile = cmsOpenProfileFromStream(outputProfileStream, "r"); - } else { - hOutputProfile = cmsCreate_sRGBProfile(); - } - - if (hOutputProfile == nullptr) { - if (profilePath != 0) { - fclose(outputProfileStream); - } - - cmsCloseProfile(hInputProfile); - return E_FAIL; - } - - // Create the transform - cmsHTRANSFORM hTransform = cmsCreateTransform(hInputProfile, TYPE_RGB_16, hOutputProfile, TYPE_RGB_16, intent, cmsFLAGS_HIGHRESPRECALC); - - cmsCloseProfile(hOutputProfile); - - if (profilePath != 0) { - fclose(outputProfileStream); - } - - cmsCloseProfile(hInputProfile); - - if (hTransform == nullptr) { - return E_FAIL; - } - - uint16_t* lut3DOutput = nullptr; - uint16_t* lut3DInput = nullptr; - - try { - // Create the 3D LUT input - lut3DOutput = DEBUG_NEW uint16_t[m_Lut3DEntryCount * 3]; - lut3DInput = DEBUG_NEW uint16_t[m_Lut3DEntryCount * 3]; - - uint16_t* lut3DInputIterator = lut3DInput; - - for (int b = 0; b < m_Lut3DSize; b++) { - for (int g = 0; g < m_Lut3DSize; g++) { - for (int r = 0; r < m_Lut3DSize; r++) { - *lut3DInputIterator++ = uint16_t(r * 65535 / (m_Lut3DSize - 1)); - *lut3DInputIterator++ = uint16_t(g * 65535 / (m_Lut3DSize - 1)); - *lut3DInputIterator++ = uint16_t(b * 65535 / (m_Lut3DSize - 1)); - } - } - } - - // Do the transform - cmsDoTransform(hTransform, lut3DInput, lut3DOutput, m_Lut3DEntryCount); - - // Convert the output to floating point - for (int i = 0; i < m_Lut3DEntryCount * 3; i++) { - lut3D[i] = static_cast(lut3DOutput[i]) * (1.0f / 65535.0f); - } - - // Cleanup - delete [] lut3DOutput; - delete [] lut3DInput; - cmsDeleteTransform(hTransform); - } catch (...) { - // Cleanup - delete [] lut3DOutput; - delete [] lut3DInput; - cmsDeleteTransform(hTransform); - - return E_FAIL; - } - - return S_OK; -} - -HRESULT CDX9RenderingEngine::FinalPass(IDirect3DTexture9* pTexture) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - MYD3DVERTEX<1> v[] = { - {0, 0, 0.5f, 2.0f, 0, 0}, - {w, 0, 0.5f, 2.0f, 1, 0}, - {0, h, 0.5f, 2.0f, 0, 1}, - {w, h, 0.5f, 2.0f, 1, 1}, - }; - - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - - hr = m_pD3DDev->SetPixelShader(m_pFinalPixelShader); - - // Set sampler: image - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - - hr = m_pD3DDev->SetTexture(0, pTexture); - - // Set sampler: ditherMap - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); - hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); - - hr = m_pD3DDev->SetTexture(1, m_pDitherTexture); - - if (m_bColorManagement) { - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); - - hr = m_pD3DDev->SetTexture(2, m_pLut3DTexture); - } - - // Set constants - float fConstData[][4] = {{(float)w / DITHER_MATRIX_SIZE, (float)h / DITHER_MATRIX_SIZE, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - - hr = m_pD3DDev->SetTexture(1, nullptr); - - if (m_bColorManagement) { - hr = m_pD3DDev->SetTexture(2, nullptr); - } - - return hr; -} - -HRESULT CDX9RenderingEngine::TextureCopy(IDirect3DTexture9* pTexture) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - MYD3DVERTEX<1> v[] = { - {0, 0, 0.5f, 2.0f, 0, 0}, - {w, 0, 0.5f, 2.0f, 1, 0}, - {0, h, 0.5f, 2.0f, 0, 1}, - {w, h, 0.5f, 2.0f, 1, 1}, - }; - - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - - hr = m_pD3DDev->SetTexture(0, pTexture); - - // use D3DTEXF_LINEAR here if wanting to support hw linear sampling in pixel shaders - return TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); -} - -bool CDX9RenderingEngine::ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pSurface->GetDesc(&desc))) { - return false; - } - - int w = desc.Width, h = desc.Height; - int sw = s.Width(), sh = s.Height(); - int dw = d.Width(), dh = d.Height(); - - if (d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0 - || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) { - s.SetRectEmpty(); - d.SetRectEmpty(); - return true; - } - - if (d.right > w) { - s.right -= (d.right - w) * sw / dw; - d.right = w; - } - if (d.bottom > h) { - s.bottom -= (d.bottom - h) * sh / dh; - d.bottom = h; - } - if (d.left < 0) { - s.left += (0 - d.left) * sw / dw; - d.left = 0; - } - if (d.top < 0) { - s.top += (0 - d.top) * sh / dh; - d.top = 0; - } - - return true; -} - -HRESULT CDX9RenderingEngine::DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect) -{ - CheckPointer(m_pD3DDev, E_POINTER); - - DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color)); - MYD3DVERTEX<0> v[] = { - {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color}, - {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color}, - {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color}, - {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color}, - }; - - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - - HRESULT hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - //D3DRS_COLORVERTEX - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - - - hr = m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); - - hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE); - // hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0])); - - MYD3DVERTEX<0> tmp = v[2]; - v[2] = v[3]; - v[3] = tmp; - hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); - - return S_OK; -} - -HRESULT CDX9RenderingEngine::AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture) -{ - if (!pSrc || !pDst) { - return E_POINTER; - } - - CRect src(*pSrc), dst(*pDst); - - HRESULT hr; - - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile - // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly - // initialized and thus the subtitles weren't shown. - struct { - float x, y, z, rhw; - float tu, tv; - } pVertices[] = { - {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, - {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, - {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, - {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, - }; - - for (size_t i = 0; i < _countof(pVertices); i++) { - pVertices[i].x -= 0.5f; - pVertices[i].y -= 0.5f; - } - - hr = m_pD3DDev->SetTexture(0, pTexture); - - // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE - // so we need to provide default values in case GetRenderState fails - DWORD abe, sb, db; - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { - abe = FALSE; - } - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { - sb = D3DBLEND_ONE; - } - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { - db = D3DBLEND_ZERO; - } - - hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... - hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst - - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - - /*// - - D3DCAPS9 d3dcaps9; - hr = m_pD3DDev->GetDeviceCaps(&d3dcaps9); - if (d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS) - { - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS); - } - - */// - - hr = m_pD3DDev->SetPixelShader(nullptr); - - hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); - hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); - - // - - m_pD3DDev->SetTexture(0, nullptr); - - m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); - m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); - m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); - - return S_OK; -} - -HRESULT CDX9RenderingEngine::SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) -{ - CAtlList* pPixelShaders; - if (bScreenSpace) { - pPixelShaders = &m_pCustomScreenSpacePixelShaders; - } else { - pPixelShaders = &m_pCustomPixelShaders; - } - - if (!pSrcData && !pTarget) { - pPixelShaders->RemoveAll(); - if (m_pD3DDev) { - m_pD3DDev->SetPixelShader(nullptr); - } - return S_OK; - } - - if (!pSrcData) { - return E_INVALIDARG; - } - - CExternalPixelShader Shader; - Shader.m_SourceData = pSrcData; - Shader.m_SourceTarget = pTarget; - - if (Shader.m_SourceData.Find("$MinimumShaderProfile: ps_4_0") > 0 || Shader.m_SourceData.Find("$MinimumShaderProfile: ps_5_0") > 0) { - // incompatible shader - return E_INVALIDARG; - } - - CComPtr pPixelShader; - - HRESULT hr = Shader.Compile(m_pPSC); - if (FAILED(hr)) { - return hr; - } - - pPixelShaders->AddTail(Shader); - - Paint(false); - - return S_OK; -} +/* + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#pragma warning(disable: 5033) // warning C5033: 'register' is no longer a supported storage class +#include "lcms2/library/include/lcms2.h" +#include "../../../mpc-hc/resource.h" +#include "Dither.h" +#include "DX9RenderingEngine.h" +#include "../../../mpc-hc/ColorProfileUtil.h" + +// UUID for vorpX hack +static const IID IID_D3D9VorpVideoCaptureTexture = { 0x8a49d79, 0x8646, 0x4867, { 0xb9, 0x34, 0x13, 0x12, 0xe4, 0x4b, 0x23, 0xdb } }; + +#pragma pack(push, 1) +template +struct MYD3DVERTEX { + float x, y, z, rhw; + struct { + float u, v; + } t[texcoords]; +}; + +template<> +struct MYD3DVERTEX<0> { + float x, y, z, rhw; + DWORD Diffuse; +}; +#pragma pack(pop) + +template +static void AdjustQuad(MYD3DVERTEX* v, double dx, double dy) +{ + float offset = 0.5; + + for (int i = 0; i < 4; i++) { + v[i].x -= offset; + v[i].y -= offset; + + for (int j = 0; j < std::max(texcoords - 1, 1); j++) { + v[i].t[j].u -= (float)(offset * dx); + v[i].t[j].v -= (float)(offset * dy); + } + + if constexpr(texcoords > 1) { + v[i].t[texcoords - 1].u -= offset; + v[i].t[texcoords - 1].v -= offset; + } + } +} + +template +static HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter) +{ + CheckPointer(pD3DDev, E_POINTER); + + DWORD FVF = 0; + + switch (texcoords) { + case 1: + FVF = D3DFVF_TEX1; + break; + case 2: + FVF = D3DFVF_TEX2; + break; + case 3: + FVF = D3DFVF_TEX3; + break; + case 4: + FVF = D3DFVF_TEX4; + break; + case 5: + FVF = D3DFVF_TEX5; + break; + case 6: + FVF = D3DFVF_TEX6; + break; + case 7: + FVF = D3DFVF_TEX7; + break; + case 8: + FVF = D3DFVF_TEX8; + break; + default: + return E_FAIL; + } + + pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + + for (int i = 0; i < texcoords; i++) { + pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); + pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter); + pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + // + + pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF); + //pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0])); + + MYD3DVERTEX tmp = v[2]; + v[2] = v[3]; + v[3] = tmp; + pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); + + // + + for (int i = 0; i < texcoords; i++) { + pD3DDev->SetTexture(i, nullptr); + } + + return S_OK; +} + + +using namespace DSObjects; + +CDX9RenderingEngine::CDX9RenderingEngine(HWND hWnd, HRESULT& hr, CString* _pError) + : CSubPicAllocatorPresenterImpl(hWnd, hr, _pError) + , m_CurrentAdapter(UINT_ERROR) + , m_BackbufferType(D3DFMT_UNKNOWN) + , m_DisplayType(D3DFMT_UNKNOWN) + , m_ScreenSize(0, 0) + , m_nNbDXSurface(1) + , m_nCurSurface(0) + , m_bHighColorResolution(false) + , m_bForceInputHighColorResolution(false) + , m_RenderingPath(RENDERING_PATH_DRAW) + , m_SurfaceType(D3DFMT_UNKNOWN) + , m_bFullFloatingPointProcessing(false) + , m_bHalfFloatingPointProcessing(false) + , m_bColorManagement(false) + , m_InputVideoSystem(VIDEO_SYSTEM_UNKNOWN) + , m_AmbientLight(AMBIENT_LIGHT_BRIGHT) + , m_RenderingIntent(COLOR_RENDERING_INTENT_PERCEPTUAL) + , m_ScreenSpacePassCount(1) + , m_ScreenSpacePassSrc(0) + , m_ScreenSpacePassDest(1) + , m_pRenderTarget(nullptr) + , m_BicubicA(0) + , m_bFinalPass(false) + , m_Lut3DSize(64) + , m_Lut3DEntryCount(64 * 64 * 64) + , m_StretchRectFilter(D3DTEXF_NONE) + , m_pD3DXFloat32To16Array(nullptr) +{ + ZeroMemory(&m_Caps, sizeof(m_Caps)); + HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); + m_bD3DX = hDll != nullptr; + + if (m_bD3DX) { + (FARPROC&)m_pD3DXFloat32To16Array = GetProcAddress(hDll, "D3DXFloat32To16Array"); + } +} + +void CDX9RenderingEngine::InitRenderingEngine() +{ + m_StretchRectFilter = D3DTEXF_LINEAR;// eliminate this chain ASAP + + // Initialize the pixel shader compiler + m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); + + // Initialize settings + m_BicubicA = 0; +} + +void CDX9RenderingEngine::CleanupRenderingEngine() +{ + m_pPSC.Free(); + + for (int i = 0; i < 4; i++) { + m_pResizerPixelShaders[i] = nullptr; + } + + CleanupFinalPass(); + + POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + pos = m_pCustomPixelShaders.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + + for (int i = 0; i < 2; i++) { + m_pTemporaryVideoTextures[i] = nullptr; + m_pTemporaryScreenSpaceTextures[i] = nullptr; + } +} + +HRESULT CDX9RenderingEngine::CreateVideoSurfaces() +{ + HRESULT hr; + const CRenderersSettings& r = GetRenderersSettings(); + + // Free previously allocated video surfaces + FreeVideoSurfaces(); + + // Free previously allocated temporary video textures, because the native video size might have been changed! + for (int i = 0; i < 2; i++) { + m_pTemporaryVideoTextures[i] = nullptr; + } + + CheckPointer(m_pD3DDev, E_POINTER); + + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { + int nTexturesNeeded = r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nNbDXSurface : 1; + + for (int i = 0; i < nTexturesNeeded; i++) { + if (FAILED(hr = m_pD3DDev->CreateTexture( + m_nativeVideoSize.cx, + m_nativeVideoSize.cy, 1, + D3DUSAGE_RENDERTARGET, + m_SurfaceType, + D3DPOOL_DEFAULT, + &m_pVideoTexture[i], + nullptr))) { + return hr; + } + + if (FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i]))) { + return hr; + } + } + + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D) { + m_RenderingPath = RENDERING_PATH_STRETCHRECT; + + for (int i = 0; i < m_nNbDXSurface; i++) { + m_pVideoTexture[i] = nullptr; + } + } else { + m_RenderingPath = RENDERING_PATH_DRAW; + } + } else { + m_RenderingPath = RENDERING_PATH_STRETCHRECT; + + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface( + m_nativeVideoSize.cx, m_nativeVideoSize.cy, + m_SurfaceType, + D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], nullptr))) { + return hr; + } + } + + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1, 0); + + return S_OK; +} + +void CDX9RenderingEngine::FreeVideoSurfaces() +{ + for (int i = 0; i < m_nNbDXSurface; i++) { + m_pVideoTexture[i] = nullptr; + m_pVideoSurface[i] = nullptr; + } +} + +HRESULT CDX9RenderingEngine::RenderVideo(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) +{ + if (destRect.IsRectEmpty()) { + return S_OK; + } + + if (m_RenderingPath == RENDERING_PATH_DRAW) { + return RenderVideoDrawPath(pRenderTarget, srcRect, destRect); + } else { + return RenderVideoStretchRectPath(pRenderTarget, srcRect, destRect); + } +} + +HRESULT CDX9RenderingEngine::RenderVideoDrawPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) +{ + HRESULT hr; + + // Return if the video texture is not initialized + if (m_pVideoTexture[m_nCurSurface] == 0) { + return S_OK; + } + + const CRenderersSettings& r = GetRenderersSettings(); + + // Initialize the processing pipeline + bool bCustomPixelShaders; + bool bResizerShaders; + bool bCustomScreenSpacePixelShaders; + bool bFinalPass; + + int screenSpacePassCount = 0; + DWORD iDX9Resizer = r.iDX9Resizer; + + if (m_bD3DX) { + // Final pass. Must be initialized first! + hr = InitFinalPass(); + if (SUCCEEDED(hr)) { + bFinalPass = m_bFinalPass; + } else { + bFinalPass = false; + } + + if (bFinalPass) { + ++screenSpacePassCount; + } + + // Resizers + float bicubicA = 0; + switch (iDX9Resizer) { + case 3: + bicubicA = -0.60f; + break; + case 4: + bicubicA = -0.751f; + break; // FIXME : 0.75 crash recent D3D, or eat CPU + case 5: + bicubicA = -1.00f; + break; + } + + hr = InitResizers(bicubicA); + bResizerShaders = SUCCEEDED(hr); + screenSpacePassCount += 1; // currently all resizers are 1-pass + + // Custom screen space pixel shaders + bCustomScreenSpacePixelShaders = !m_pCustomScreenSpacePixelShaders.IsEmpty(); + + if (bCustomScreenSpacePixelShaders) { + screenSpacePassCount += (int)m_pCustomScreenSpacePixelShaders.GetCount(); + } + + // Custom pixel shaders + bCustomPixelShaders = !m_pCustomPixelShaders.IsEmpty(); + + hr = InitTemporaryVideoTextures(std::min((int)m_pCustomPixelShaders.GetCount(), 2)); + if (FAILED(hr)) { + bCustomPixelShaders = false; + } + } else { + bCustomPixelShaders = false; + bResizerShaders = false; + bCustomScreenSpacePixelShaders = false; + bFinalPass = false; + } + + hr = InitScreenSpacePipeline(screenSpacePassCount, pRenderTarget); + if (FAILED(hr)) { + bCustomScreenSpacePixelShaders = false; + bFinalPass = false; + } + + // Apply the custom pixel shaders if there are any. Result: pVideoTexture + CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; + + if (bCustomPixelShaders) { + static __int64 counter = 0; + static long start = clock(); + + long stop = clock(); + long diff = stop - start; + + if (diff >= 10 * 60 * CLOCKS_PER_SEC) { + start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) + } + +#if 1 + D3DSURFACE_DESC desc; + m_pVideoTexture[m_nCurSurface]->GetLevelDesc(0, &desc); + + float fConstData[][4] = { + {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, + }; +#else + CSize VideoSize = GetVisibleVideoSize(); + + float fConstData[][4] = { + {(float)VideoSize.cx, (float)VideoSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / VideoSize.cx, 1.0f / VideoSize.cy, 0, 0}, + }; +#endif + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + int src = 1; + int dest = 0; + bool first = true; + + POSITION pos = m_pCustomPixelShaders.GetHeadPosition(); + while (pos) { + CComPtr pTemporarySurface; + hr = m_pTemporaryVideoTextures[dest]->GetSurfaceLevel(0, &pTemporarySurface); + hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); + + CExternalPixelShader& Shader = m_pCustomPixelShaders.GetNext(pos); + if (!Shader.m_pPixelShader) { + Shader.Compile(m_pPSC); + } + hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + + if (first) { + TextureCopy(m_pVideoTexture[m_nCurSurface]); + first = false; + } else { + TextureCopy(m_pTemporaryVideoTextures[src]); + } + + std::swap(src, dest); + } + + pVideoTexture = m_pTemporaryVideoTextures[src]; + } + + // Hack to send the pre-resize video texture to vorpX. + void* pVorpTex = pVideoTexture; // Prevent the pointer being overwritten. + m_pD3DDev->QueryInterface(IID_D3D9VorpVideoCaptureTexture, (void**)&pVorpTex); + + // Resize the frame + Vector dst[4]; + Transform(destRect, dst); + + hr = BeginScreenSpacePass(); + + if (m_ScreenSpacePassCount > 0) { + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); + } + + if (srcRect.Size() != destRect.Size()) { + if (iDX9Resizer == 0 || iDX9Resizer == 1 || !bResizerShaders) { + D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; + hr = TextureResize(pVideoTexture, dst, Filter, srcRect); + } else if (iDX9Resizer == 2) { + hr = TextureResizeBilinear(pVideoTexture, dst, srcRect); + } else if (iDX9Resizer >= 3) { + hr = TextureResizeBicubic1pass(pVideoTexture, dst, srcRect); + } + } else { + hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, srcRect); + } + + // Apply the custom screen size pixel shaders + if (bCustomScreenSpacePixelShaders) { + static __int64 counter = 555; + static long start = clock() + 333; + + long stop = clock() + 333; + long diff = stop - start; + + if (diff >= 10 * 60 * CLOCKS_PER_SEC) { + start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) + } + + float fConstData[][4] = { + {(float)m_TemporaryScreenSpaceTextureSize.cx, (float)m_TemporaryScreenSpaceTextureSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / m_TemporaryScreenSpaceTextureSize.cx, 1.0f / m_TemporaryScreenSpaceTextureSize.cy, 0, 0}, + }; + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + POSITION pos = m_pCustomScreenSpacePixelShaders.GetHeadPosition(); + while (pos) { + BeginScreenSpacePass(); + + CExternalPixelShader& Shader = m_pCustomScreenSpacePixelShaders.GetNext(pos); + if (!Shader.m_pPixelShader) { + Shader.Compile(m_pPSC); + } + hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + TextureCopy(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); + } + } + + // Final pass + if (bFinalPass) { + hr = BeginScreenSpacePass(); + hr = FinalPass(m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassSrc]); + } + + hr = m_pD3DDev->SetPixelShader(nullptr); + + return hr; +} + +HRESULT CDX9RenderingEngine::RenderVideoStretchRectPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect) +{ + HRESULT hr; + + // Return if the render target or the video surface is not initialized + if (pRenderTarget == 0 || m_pVideoSurface[m_nCurSurface] == 0) { + return S_OK; + } + + CRect rSrcVid(srcRect); + CRect rDstVid(destRect); + + ClipToSurface(pRenderTarget, rSrcVid, rDstVid); // grrr + // IMPORTANT: rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect!!! + rSrcVid.left &= ~1; + rSrcVid.right &= ~1; + rSrcVid.top &= ~1; + rSrcVid.bottom &= ~1; + hr = m_pD3DDev->StretchRect(m_pVideoSurface[m_nCurSurface], rSrcVid, pRenderTarget, rDstVid, m_StretchRectFilter); + + return hr; +} + +HRESULT CDX9RenderingEngine::InitTemporaryVideoTextures(int count) +{ + HRESULT hr = S_OK; + + for (int i = 0; i < count; i++) { + if (m_pTemporaryVideoTextures[i] == nullptr) { + hr = m_pD3DDev->CreateTexture( + m_nativeVideoSize.cx, + m_nativeVideoSize.cy, + 1, + D3DUSAGE_RENDERTARGET, + m_SurfaceType, + D3DPOOL_DEFAULT, + &m_pTemporaryVideoTextures[i], + nullptr); + + if (FAILED(hr)) { + // Free all textures + for (int j = 0; j < 2; j++) { + m_pTemporaryVideoTextures[j] = nullptr; + } + + return hr; + } + } + } + + // Free unnecessary textures + for (int i = count; i < 2; i++) { + m_pTemporaryVideoTextures[i] = nullptr; + } + + return hr; +} + +HRESULT CDX9RenderingEngine::InitScreenSpacePipeline(int passCount, IDirect3DSurface9* pRenderTarget) +{ + m_pRenderTarget = pRenderTarget; + m_ScreenSpacePassCount = passCount; + m_ScreenSpacePassSrc = 0; + m_ScreenSpacePassDest = 1; + + HRESULT hr = InitTemporaryScreenSpaceTextures(std::min(passCount - 1, 2)); + + // If the initialized have failed, disable the pipeline + if (FAILED(hr)) { + m_ScreenSpacePassCount = 1; + } + + return hr; +} + +HRESULT CDX9RenderingEngine::InitTemporaryScreenSpaceTextures(int count) +{ + HRESULT hr = S_OK; + + for (int i = 0; i < count; i++) { + if (m_pTemporaryScreenSpaceTextures[i] == nullptr) { + m_TemporaryScreenSpaceTextureSize = CSize(std::min(std::max(m_BackBufferSize.cx, m_nativeVideoSize.cx), (long)m_Caps.MaxTextureWidth), + std::min(std::max(m_BackBufferSize.cy, m_nativeVideoSize.cy), (long)m_Caps.MaxTextureHeight)); + hr = m_pD3DDev->CreateTexture( + m_TemporaryScreenSpaceTextureSize.cx, + m_TemporaryScreenSpaceTextureSize.cy, + 1, + D3DUSAGE_RENDERTARGET, + m_SurfaceType, + D3DPOOL_DEFAULT, + &m_pTemporaryScreenSpaceTextures[i], + nullptr); + + if (FAILED(hr)) { + // Free all textures + for (int j = 0; j < 2; j++) { + m_pTemporaryScreenSpaceTextures[j] = nullptr; + } + + return hr; + } + } + } + + // Free unnecessary textures + for (int i = count; i < 2; i++) { + m_pTemporaryScreenSpaceTextures[i] = nullptr; + } + + return hr; +} + +HRESULT CDX9RenderingEngine::BeginScreenSpacePass() +{ + HRESULT hr; + + std::swap(m_ScreenSpacePassSrc, m_ScreenSpacePassDest); + --m_ScreenSpacePassCount; + + if (m_ScreenSpacePassCount > 0) { + CComPtr pTemporarySurface; + hr = m_pTemporaryScreenSpaceTextures[m_ScreenSpacePassDest]->GetSurfaceLevel(0, &pTemporarySurface); + + if (SUCCEEDED(hr)) { + hr = m_pD3DDev->SetRenderTarget(0, pTemporarySurface); + } + } else { + hr = m_pD3DDev->SetRenderTarget(0, m_pRenderTarget); + } + + return hr; +} + +HRESULT CDX9RenderingEngine::InitResizers(float bicubicA) +{ + HRESULT hr; + + // Check whether the resizer pixel shaders must be initialized + bool bInitRequired = false; + + if (bicubicA) { + for (int i = 0; i < 4; i++) { + if (!m_pResizerPixelShaders[i]) { + bInitRequired = true; + } + } + + if (m_BicubicA != bicubicA) { + bInitRequired = true; + } + } else { + if (!m_pResizerPixelShaders[0]) { + bInitRequired = true; + } + } + + if (!bInitRequired) { + return S_OK; + } + + // Initialize the resizer pixel shaders + m_BicubicA = bicubicA; + + for (int i = 0; i < _countof(m_pResizerPixelShaders); i++) { + m_pResizerPixelShaders[i] = nullptr; + } + + if (m_Caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { + return E_FAIL; + } + + LPCSTR pProfile = m_Caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; + + CStringA str; + if (!LoadResource(IDF_SHADER_RESIZER, str, _T("SHADER"))) { + return E_FAIL; + } + + CStringA A; + A.Format("(%f)", bicubicA); + str.Replace("_The_Value_Of_A_Is_Set_Here_", A); + + LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass_pass1", "main_bicubic2pass_pass2"}; + + ASSERT(_countof(pEntries) == _countof(m_pResizerPixelShaders)); + + for (int i = 0; i < _countof(pEntries); i++) { + CString ErrorMessage; + CString DissAssembly; + hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShaders[i], &DissAssembly, &ErrorMessage); + if (FAILED(hr)) { + TRACE(_T("%ws"), ErrorMessage.GetString()); + ASSERT(0); + return hr; + } + /* + if (i == 2 || i == 3) + { + const wchar_t *pStr = DissAssembly.GetString(); + TRACE(_T("DisAsm: %s\n"), pEntries[i]); + const wchar_t *pStrStart = pStr; + while (*pStr) + { + while (*pStr && *pStr != '\n') + ++pStr; + if (*pStr == '\n') + ++pStr; + if (*pStr == '\r') + ++pStr; + CString Test(pStrStart, pStr - pStrStart); + TRACE(_T("%ws"), Test.GetString()); + pStrStart = pStr; + } + } + */ + } + + return S_OK; +} + +HRESULT CDX9RenderingEngine::TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& srcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + float dx2 = 1.0f / w; + float dy2 = 1.0f / h; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, srcRect.left * dx2, srcRect.top * dy2}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, srcRect.right * dx2, srcRect.top * dy2}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, srcRect.left * dx2, srcRect.bottom * dy2}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, srcRect.right * dx2, srcRect.bottom * dy2}, + }; + + AdjustQuad(v, 0, 0); + + hr = m_pD3DDev->SetTexture(0, pTexture); + hr = m_pD3DDev->SetPixelShader(nullptr); + hr = TextureBlt(m_pD3DDev, v, filter); + + return hr; +} + +HRESULT CDX9RenderingEngine::TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway + const float dx = 1.0f / (float)desc.Width; + const float dy = 1.0f / (float)desc.Height; + const float tx0 = (float)srcRect.left; + const float tx1 = (float)srcRect.right; + const float ty0 = (float)srcRect.top; + const float ty1 = (float)srcRect.bottom; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, + }; + + AdjustQuad(v, 1.0, 1.0); + + hr = m_pD3DDev->SetTexture(0, pTexture); + + float fConstData[][4] = {{dx * 0.5f, dy * 0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + hr = m_pD3DDev->SetTexture(0, pTexture); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[0]); + + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + return hr; +} + +HRESULT CDX9RenderingEngine::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway + const float dx = 1.0f / (float)desc.Width; + const float dy = 1.0f / (float)desc.Height; + const float tx0 = (float)srcRect.left; + const float tx1 = (float)srcRect.right; + const float ty0 = (float)srcRect.top; + const float ty1 = (float)srcRect.bottom; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, + }; + + AdjustQuad(v, 1.0, 1.0); + + hr = m_pD3DDev->SetTexture(0, pTexture); + + float fConstData[][4] = {{dx * 0.5f, dy * 0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[1]); + + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + return hr; +} + +/* +// The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction. +HRESULT CDX9RenderingEngine::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect &srcRect) +{ + HRESULT hr; + + // rotated? + if (dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z + || dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x) + return TextureResizeBicubic1pass(pTexture, dst, srcRect); + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) + return E_FAIL; + + float Tex0_Width = desc.Width; + float Tex0_Height = desc.Height; + + double dx0 = 1.0/desc.Width; + UNREFERENCED_PARAMETER(dx0); + double dy0 = 1.0/desc.Height; + UNREFERENCED_PARAMETER(dy0); + + CSize SrcTextSize = CSize(desc.Width, desc.Height); + double w = (double)srcRect.Width(); + double h = (double)srcRect.Height(); + UNREFERENCED_PARAMETER(w); + + CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h); + + if (!m_pTemporaryScreenSpaceTextures[0] || FAILED(m_pTemporaryScreenSpaceTextures[0]->GetLevelDesc(0, &desc))) + return TextureResizeBicubic1pass(pTexture, dst, srcRect); + + float Tex1_Width = desc.Width; + float Tex1_Height = desc.Height; + + double dx1 = 1.0/desc.Width; + UNREFERENCED_PARAMETER(dx1); + double dy1 = 1.0/desc.Height; + UNREFERENCED_PARAMETER(dy1); + + double dw = (double)dst1.Width() / desc.Width; + UNREFERENCED_PARAMETER(dw); + double dh = (double)dst1.Height() / desc.Height; + UNREFERENCED_PARAMETER(dh); + + float dx2 = 1.0f/SrcTextSize.cx; + UNREFERENCED_PARAMETER(dx2); + float dy2 = 1.0f/SrcTextSize.cy; + UNREFERENCED_PARAMETER(dy2); + + float tx0 = srcRect.left; + float tx1 = srcRect.right; + float ty0 = srcRect.top; + float ty1 = srcRect.bottom; + + float tx0_2 = 0; + float tx1_2 = dst1.Width(); + float ty0_2 = 0; + float ty1_2 = h; + + // ASSERT(dst1.Height() == desc.Height); + + if (dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height) + // if (dst1.Width() != desc.Width || dst1.Height() != desc.Height) + return TextureResizeBicubic1pass(pTexture, dst, srcRect); + + MYD3DVERTEX<1> vx[] = + { + {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0}, + {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0}, + {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1}, + {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1}, + }; + + AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug here, create vertical lines ! TODO : why ?????? + + MYD3DVERTEX<1> vy[] = + { + {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2}, + {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2}, + {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2}, + {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2}, + }; + + + AdjustQuad(vy, 0.0, 1.0); // Casimir666 : bug here, create horizontal lines ! TODO : why ?????? + + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[2]); + { + float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + } + + hr = m_pD3DDev->SetTexture(0, pTexture); + + CComPtr pRTOld; + hr = m_pD3DDev->GetRenderTarget(0, &pRTOld); + + CComPtr pRT; + hr = m_pTemporaryScreenSpaceTextures[0]->GetSurfaceLevel(0, &pRT); + hr = m_pD3DDev->SetRenderTarget(0, pRT); + + hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT); + + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShaders[3]); + { + float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + } + + hr = m_pD3DDev->SetTexture(0, m_pTemporaryScreenSpaceTextures[0]); + + hr = m_pD3DDev->SetRenderTarget(0, pRTOld); + + hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT); + return hr; +} +*/ + +HRESULT CDX9RenderingEngine::Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect) +{ + HRESULT hr = E_FAIL; + + const CRenderersSettings& r = GetRenderersSettings(); + + DWORD iDX9Resizer = r.iDX9Resizer; + Vector dst[4]; + Transform(destRect, dst); + + if (iDX9Resizer == 0 || iDX9Resizer == 1) { + D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; + hr = TextureResize(pTexture, dst, Filter, srcRect); + } else if (iDX9Resizer == 2) { + hr = TextureResizeBilinear(pTexture, dst, srcRect); + } else if (iDX9Resizer >= 3) { + hr = TextureResizeBicubic1pass(pTexture, dst, srcRect); + } + + return hr; +} + +HRESULT CDX9RenderingEngine::InitFinalPass() +{ + HRESULT hr; + + const CRenderersSettings& r = GetRenderersSettings(); + const CRenderersData* rd = GetRenderersData(); + + // Check whether the final pass must be initialized + bool bColorManagement = r.m_AdvRendSets.bVMR9ColorManagementEnable; + VideoSystem inputVideoSystem = static_cast(r.m_AdvRendSets.iVMR9ColorManagementInput); + AmbientLight ambientLight = static_cast(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight); + ColorRenderingIntent renderingIntent = static_cast(r.m_AdvRendSets.iVMR9ColorManagementIntent); + + bool bInitRequired = false; + + if (m_bColorManagement != bColorManagement) { + bInitRequired = true; + } + + if (m_bColorManagement && bColorManagement) { + if ((m_InputVideoSystem != inputVideoSystem) || + (m_RenderingIntent != renderingIntent) || + (m_AmbientLight != ambientLight)) { + bInitRequired = true; + } + } + + if (!m_bFinalPass) { + bInitRequired = true; + } + + if (!bInitRequired) { + return S_OK; + } + + // Check whether the final pass is supported by the hardware + m_bFinalPass = rd->m_bFP16Support; + if (!m_bFinalPass) { + return S_OK; + } + + // Update the settings + m_bColorManagement = bColorManagement; + m_InputVideoSystem = inputVideoSystem; + m_AmbientLight = ambientLight; + m_RenderingIntent = renderingIntent; + + // Check whether the final pass is required + m_bFinalPass = bColorManagement || m_bFullFloatingPointProcessing || m_bHalfFloatingPointProcessing || ((m_bForceInputHighColorResolution || m_bHighColorResolution) && (m_DisplayType != D3DFMT_A2R10G10B10)); + + if (!m_bFinalPass) { + return S_OK; + } + + // Initial cleanup + m_pLut3DTexture = nullptr; + m_pFinalPixelShader = nullptr; + + if (!m_pDitherTexture) { + // Create the dither texture + hr = m_pD3DDev->CreateTexture(DITHER_MATRIX_SIZE, DITHER_MATRIX_SIZE, + 1, + D3DUSAGE_DYNAMIC, + D3DFMT_A16B16G16R16F, + D3DPOOL_DEFAULT, + &m_pDitherTexture, + nullptr); + + if (FAILED(hr)) { + CleanupFinalPass(); + return hr; + } + + D3DLOCKED_RECT lockedRect; + hr = m_pDitherTexture->LockRect(0, &lockedRect, nullptr, D3DLOCK_DISCARD); + if (FAILED(hr)) { + CleanupFinalPass(); + return hr; + } + + char* outputRowIterator = static_cast(lockedRect.pBits); + for (int y = 0; y < DITHER_MATRIX_SIZE; y++) { + unsigned short* outputIterator = reinterpret_cast(outputRowIterator); + for (int x = 0; x < DITHER_MATRIX_SIZE; x++) { + for (int i = 0; i < 4; i++) { + *outputIterator++ = DITHER_MATRIX[y][x]; + } + } + + outputRowIterator += lockedRect.Pitch; + } + + hr = m_pDitherTexture->UnlockRect(0); + if (FAILED(hr)) { + CleanupFinalPass(); + return hr; + } + } + + // Initialize the color management if necessary + if (bColorManagement) { + // Get the ICC profile path + TCHAR* iccProfilePath = ColorProfileUtil::getIccProfilePath(m_hWnd); + + // Create the 3D LUT texture + m_Lut3DSize = 64; // 64x64x64 LUT is enough for high-quality color management + m_Lut3DEntryCount = m_Lut3DSize * m_Lut3DSize * m_Lut3DSize; + + hr = m_pD3DDev->CreateVolumeTexture(m_Lut3DSize, m_Lut3DSize, m_Lut3DSize, + 1, + D3DUSAGE_DYNAMIC, + D3DFMT_A16B16G16R16F, + D3DPOOL_DEFAULT, + &m_pLut3DTexture, + nullptr); + + if (FAILED(hr)) { + delete [] iccProfilePath; + CleanupFinalPass(); + return hr; + } + + float* lut3DFloat32 = DEBUG_NEW float[m_Lut3DEntryCount * 3]; + hr = CreateIccProfileLut(iccProfilePath, lut3DFloat32); + delete [] iccProfilePath; + if (FAILED(hr)) { + delete [] lut3DFloat32; + CleanupFinalPass(); + return hr; + } + + D3DXFLOAT16* lut3DFloat16 = DEBUG_NEW D3DXFLOAT16[m_Lut3DEntryCount * 3]; + m_pD3DXFloat32To16Array(lut3DFloat16, lut3DFloat32, m_Lut3DEntryCount * 3); + delete [] lut3DFloat32; + + const float oneFloat32 = 1.0f; + D3DXFLOAT16 oneFloat16; + m_pD3DXFloat32To16Array(&oneFloat16, &oneFloat32, 1); + + D3DLOCKED_BOX lockedBox; + hr = m_pLut3DTexture->LockBox(0, &lockedBox, nullptr, D3DLOCK_DISCARD); + if (FAILED(hr)) { + delete [] lut3DFloat16; + CleanupFinalPass(); + return hr; + } + + D3DXFLOAT16* lut3DFloat16Iterator = lut3DFloat16; + char* outputSliceIterator = static_cast(lockedBox.pBits); + for (int b = 0; b < m_Lut3DSize; b++) { + char* outputRowIterator = outputSliceIterator; + + for (int g = 0; g < m_Lut3DSize; g++) { + D3DXFLOAT16* outputIterator = reinterpret_cast(outputRowIterator); + + for (int i = 0; i < m_Lut3DSize; i++) { + // R, G, B + for (int j = 0; j < 3; j++) { + *outputIterator++ = *lut3DFloat16Iterator++; + } + + // A + *outputIterator++ = oneFloat16; + } + + outputRowIterator += lockedBox.RowPitch; + } + + outputSliceIterator += lockedBox.SlicePitch; + } + + hr = m_pLut3DTexture->UnlockBox(0); + delete [] lut3DFloat16; + if (FAILED(hr)) { + CleanupFinalPass(); + return hr; + } + } + + // Compile the final pixel shader + LPCSTR pProfile = m_Caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; + + CStringA shaderSourceCode; + if (!LoadResource(IDF_SHADER_FINAL, shaderSourceCode, _T("SHADER"))) { + CleanupFinalPass(); + return E_FAIL; + } + + int quantization; + if (m_DisplayType == D3DFMT_A2R10G10B10) { + quantization = 1023; // 10-bit + } else { + quantization = 255; // 8-bit + } + + CStringA quantizationString; + quantizationString.Format("%d.", quantization); + shaderSourceCode.Replace("_QUANTIZATION_VALUE_", quantizationString); + + CStringA lut3DEnabledString; + lut3DEnabledString.Format("%d", static_cast(bColorManagement)); + shaderSourceCode.Replace("_LUT3D_ENABLED_VALUE_", lut3DEnabledString); + + if (bColorManagement) { + CStringA lut3DSizeString; + lut3DSizeString.Format("%d.", m_Lut3DSize); + shaderSourceCode.Replace("_LUT3D_SIZE_VALUE_", lut3DSizeString); + } + + CString ErrorMessage; + CString DissAssembly; + hr = m_pPSC->CompileShader(shaderSourceCode, "main", pProfile, 0, &m_pFinalPixelShader, &DissAssembly, &ErrorMessage); + if (FAILED(hr)) { + TRACE(_T("%ws"), ErrorMessage.GetString()); + ASSERT(0); + CleanupFinalPass(); + return hr; + } + + return S_OK; +} + +void CDX9RenderingEngine::CleanupFinalPass() +{ + m_bFinalPass = false; + m_pDitherTexture = nullptr; + m_pLut3DTexture = nullptr; + m_pFinalPixelShader = nullptr; +} + +HRESULT CDX9RenderingEngine::CreateIccProfileLut(TCHAR* profilePath, float* lut3D) +{ + // Get the input video system + VideoSystem videoSystem; + + if (m_InputVideoSystem == VIDEO_SYSTEM_UNKNOWN) { + static const int ntscSizes[][2] = {{720, 480}, {720, 486}, {704, 480}}; + static const int palSizes[][2] = {{720, 576}, {704, 576}}; + + videoSystem = VIDEO_SYSTEM_HDTV; // default + + for (int i = 0; i < _countof(ntscSizes); i++) { + if (m_nativeVideoSize.cx == ntscSizes[i][0] && m_nativeVideoSize.cy == ntscSizes[i][1]) { + videoSystem = VIDEO_SYSTEM_SDTV_NTSC; + } + } + + for (int i = 0; i < _countof(palSizes); i++) { + if (m_nativeVideoSize.cx == palSizes[i][0] && m_nativeVideoSize.cy == palSizes[i][1]) { + videoSystem = VIDEO_SYSTEM_SDTV_PAL; + } + } + } else { + videoSystem = m_InputVideoSystem; + } + + // Get the gamma + double gamma; + + switch (m_AmbientLight) { + case AMBIENT_LIGHT_BRIGHT: + gamma = 2.2; + break; + + case AMBIENT_LIGHT_DIM: + gamma = 2.35; + break; + + case AMBIENT_LIGHT_DARK: + gamma = 2.4; + break; + + default: + return E_FAIL; + } + + // Get the rendering intent + cmsUInt32Number intent; + + switch (m_RenderingIntent) { + case COLOR_RENDERING_INTENT_PERCEPTUAL: + intent = INTENT_PERCEPTUAL; + break; + + case COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC: + intent = INTENT_RELATIVE_COLORIMETRIC; + break; + + case COLOR_RENDERING_INTENT_SATURATION: + intent = INTENT_SATURATION; + break; + + case COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC: + intent = INTENT_ABSOLUTE_COLORIMETRIC; + break; + + default: + return E_FAIL; + } + + // Set the input white point. It's D65 in all cases. + cmsCIExyY whitePoint; + + whitePoint.x = 0.312713; + whitePoint.y = 0.329016; + whitePoint.Y = 1.0; + + // Set the input primaries + cmsCIExyYTRIPLE primaries; + + switch (videoSystem) { + case VIDEO_SYSTEM_HDTV: + // Rec. 709 + primaries.Red.x = 0.64; + primaries.Red.y = 0.33; + primaries.Green.x = 0.30; + primaries.Green.y = 0.60; + primaries.Blue.x = 0.15; + primaries.Blue.y = 0.06; + break; + + case VIDEO_SYSTEM_SDTV_NTSC: + // SMPTE-C + primaries.Red.x = 0.630; + primaries.Red.y = 0.340; + primaries.Green.x = 0.310; + primaries.Green.y = 0.595; + primaries.Blue.x = 0.155; + primaries.Blue.y = 0.070; + break; + + case VIDEO_SYSTEM_SDTV_PAL: + // PAL/SECAM + primaries.Red.x = 0.64; + primaries.Red.y = 0.33; + primaries.Green.x = 0.29; + primaries.Green.y = 0.60; + primaries.Blue.x = 0.15; + primaries.Blue.y = 0.06; + break; + + default: + return E_FAIL; + } + + primaries.Red.Y = 1.0; + primaries.Green.Y = 1.0; + primaries.Blue.Y = 1.0; + + // Set the input gamma, which is the gamma of a reference studio display we want to simulate + // For more information, see the paper at http://www.poynton.com/notes/PU-PR-IS/Poynton-PU-PR-IS.pdf + cmsToneCurve* transferFunction = cmsBuildGamma(0, gamma); + + cmsToneCurve* transferFunctionRGB[3]; + for (int i = 0; i < 3; i++) { + transferFunctionRGB[i] = transferFunction; + } + + // Create the input profile + cmsHPROFILE hInputProfile = cmsCreateRGBProfile(&whitePoint, &primaries, transferFunctionRGB); + cmsFreeToneCurve(transferFunction); + + if (hInputProfile == nullptr) { + return E_FAIL; + } + + // Open the output profile + cmsHPROFILE hOutputProfile; + FILE* outputProfileStream = nullptr; + + if (profilePath != 0) { + if (_wfopen_s(&outputProfileStream, T2W(profilePath), L"rb") != 0) { + cmsCloseProfile(hInputProfile); + return E_FAIL; + } + + hOutputProfile = cmsOpenProfileFromStream(outputProfileStream, "r"); + } else { + hOutputProfile = cmsCreate_sRGBProfile(); + } + + if (hOutputProfile == nullptr) { + if (profilePath != 0) { + fclose(outputProfileStream); + } + + cmsCloseProfile(hInputProfile); + return E_FAIL; + } + + // Create the transform + cmsHTRANSFORM hTransform = cmsCreateTransform(hInputProfile, TYPE_RGB_16, hOutputProfile, TYPE_RGB_16, intent, cmsFLAGS_HIGHRESPRECALC); + + cmsCloseProfile(hOutputProfile); + + if (profilePath != 0) { + fclose(outputProfileStream); + } + + cmsCloseProfile(hInputProfile); + + if (hTransform == nullptr) { + return E_FAIL; + } + + uint16_t* lut3DOutput = nullptr; + uint16_t* lut3DInput = nullptr; + + try { + // Create the 3D LUT input + lut3DOutput = DEBUG_NEW uint16_t[m_Lut3DEntryCount * 3]; + lut3DInput = DEBUG_NEW uint16_t[m_Lut3DEntryCount * 3]; + + uint16_t* lut3DInputIterator = lut3DInput; + + for (int b = 0; b < m_Lut3DSize; b++) { + for (int g = 0; g < m_Lut3DSize; g++) { + for (int r = 0; r < m_Lut3DSize; r++) { + *lut3DInputIterator++ = uint16_t(r * 65535 / (m_Lut3DSize - 1)); + *lut3DInputIterator++ = uint16_t(g * 65535 / (m_Lut3DSize - 1)); + *lut3DInputIterator++ = uint16_t(b * 65535 / (m_Lut3DSize - 1)); + } + } + } + + // Do the transform + cmsDoTransform(hTransform, lut3DInput, lut3DOutput, m_Lut3DEntryCount); + + // Convert the output to floating point + for (int i = 0; i < m_Lut3DEntryCount * 3; i++) { + lut3D[i] = static_cast(lut3DOutput[i]) * (1.0f / 65535.0f); + } + + // Cleanup + delete [] lut3DOutput; + delete [] lut3DInput; + cmsDeleteTransform(hTransform); + } catch (...) { + // Cleanup + delete [] lut3DOutput; + delete [] lut3DInput; + cmsDeleteTransform(hTransform); + + return E_FAIL; + } + + return S_OK; +} + +HRESULT CDX9RenderingEngine::FinalPass(IDirect3DTexture9* pTexture) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + MYD3DVERTEX<1> v[] = { + {0, 0, 0.5f, 2.0f, 0, 0}, + {w, 0, 0.5f, 2.0f, 1, 0}, + {0, h, 0.5f, 2.0f, 0, 1}, + {w, h, 0.5f, 2.0f, 1, 1}, + }; + + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + + hr = m_pD3DDev->SetPixelShader(m_pFinalPixelShader); + + // Set sampler: image + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + hr = m_pD3DDev->SetTexture(0, pTexture); + + // Set sampler: ditherMap + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + hr = m_pD3DDev->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + + hr = m_pD3DDev->SetTexture(1, m_pDitherTexture); + + if (m_bColorManagement) { + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(2, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); + + hr = m_pD3DDev->SetTexture(2, m_pLut3DTexture); + } + + // Set constants + float fConstData[][4] = {{(float)w / DITHER_MATRIX_SIZE, (float)h / DITHER_MATRIX_SIZE, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + + hr = m_pD3DDev->SetTexture(1, nullptr); + + if (m_bColorManagement) { + hr = m_pD3DDev->SetTexture(2, nullptr); + } + + return hr; +} + +HRESULT CDX9RenderingEngine::TextureCopy(IDirect3DTexture9* pTexture) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + MYD3DVERTEX<1> v[] = { + {0, 0, 0.5f, 2.0f, 0, 0}, + {w, 0, 0.5f, 2.0f, 1, 0}, + {0, h, 0.5f, 2.0f, 0, 1}, + {w, h, 0.5f, 2.0f, 1, 1}, + }; + + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + + hr = m_pD3DDev->SetTexture(0, pTexture); + + // use D3DTEXF_LINEAR here if wanting to support hw linear sampling in pixel shaders + return TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); +} + +bool CDX9RenderingEngine::ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pSurface->GetDesc(&desc))) { + return false; + } + + int w = desc.Width, h = desc.Height; + int sw = s.Width(), sh = s.Height(); + int dw = d.Width(), dh = d.Height(); + + if (d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0 + || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) { + s.SetRectEmpty(); + d.SetRectEmpty(); + return true; + } + + if (d.right > w) { + s.right -= (d.right - w) * sw / dw; + d.right = w; + } + if (d.bottom > h) { + s.bottom -= (d.bottom - h) * sh / dh; + d.bottom = h; + } + if (d.left < 0) { + s.left += (0 - d.left) * sw / dw; + d.left = 0; + } + if (d.top < 0) { + s.top += (0 - d.top) * sh / dh; + d.top = 0; + } + + return true; +} + +HRESULT CDX9RenderingEngine::DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect) +{ + CheckPointer(m_pD3DDev, E_POINTER); + + DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color)); + MYD3DVERTEX<0> v[] = { + {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color}, + {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color}, + {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color}, + {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color}, + }; + + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + + HRESULT hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + //D3DRS_COLORVERTEX + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + + hr = m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE); + // hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0])); + + MYD3DVERTEX<0> tmp = v[2]; + v[2] = v[3]; + v[3] = tmp; + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); + + return S_OK; +} + +HRESULT CDX9RenderingEngine::AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture) +{ + if (!pSrc || !pDst) { + return E_POINTER; + } + + CRect src(*pSrc), dst(*pDst); + + HRESULT hr; + + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile + // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly + // initialized and thus the subtitles weren't shown. + struct { + float x, y, z, rhw; + float tu, tv; + } pVertices[] = { + {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, + {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, + {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, + {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, + }; + + for (size_t i = 0; i < _countof(pVertices); i++) { + pVertices[i].x -= 0.5f; + pVertices[i].y -= 0.5f; + } + + hr = m_pD3DDev->SetTexture(0, pTexture); + + // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE + // so we need to provide default values in case GetRenderState fails + DWORD abe, sb, db; + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { + abe = FALSE; + } + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { + sb = D3DBLEND_ONE; + } + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { + db = D3DBLEND_ZERO; + } + + hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst + + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + /*// + + D3DCAPS9 d3dcaps9; + hr = m_pD3DDev->GetDeviceCaps(&d3dcaps9); + if (d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS) + { + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS); + } + + */// + + hr = m_pD3DDev->SetPixelShader(nullptr); + + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + + // + + m_pD3DDev->SetTexture(0, nullptr); + + m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); + m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); + m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); + + return S_OK; +} + +HRESULT CDX9RenderingEngine::SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) +{ + CAtlList* pPixelShaders; + if (bScreenSpace) { + pPixelShaders = &m_pCustomScreenSpacePixelShaders; + } else { + pPixelShaders = &m_pCustomPixelShaders; + } + + if (!pSrcData && !pTarget) { + pPixelShaders->RemoveAll(); + if (m_pD3DDev) { + m_pD3DDev->SetPixelShader(nullptr); + } + return S_OK; + } + + if (!pSrcData) { + return E_INVALIDARG; + } + + CExternalPixelShader Shader; + Shader.m_SourceData = pSrcData; + Shader.m_SourceTarget = pTarget; + + if (Shader.m_SourceData.Find("$MinimumShaderProfile: ps_4_0") > 0 || Shader.m_SourceData.Find("$MinimumShaderProfile: ps_5_0") > 0) { + // incompatible shader + return E_INVALIDARG; + } + + CComPtr pPixelShader; + + HRESULT hr = Shader.Compile(m_pPSC); + if (FAILED(hr)) { + return hr; + } + + pPixelShaders->AddTail(Shader); + + Paint(false); + + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h index 9f210947d1f..df4790451e7 100644 --- a/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h +++ b/src/filters/renderer/VideoRenderers/DX9RenderingEngine.h @@ -1,185 +1,185 @@ -/* - * (C) 2006-2013, 2016-2017 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 . - * - */ - -#pragma once - -#include "AllocatorCommon.h" -#include "RenderersSettings.h" -#include -#include "d3dx9/d3dx9.h" -#include "../SubPic/SubPicAllocatorPresenterImpl.h" - - -namespace DSObjects -{ - - class CDX9RenderingEngine - : public CSubPicAllocatorPresenterImpl - { - protected: - enum RenderingPath { - RENDERING_PATH_STRETCHRECT, - RENDERING_PATH_DRAW - }; - - static const int MAX_VIDEO_SURFACES = 60; - - // Variables initialized/managed by the allocator-presenter! - CComPtr m_pD3D; - CComPtr m_pD3DEx; - CComPtr m_pD3DDev; - CComPtr m_pD3DDevEx; - UINT m_CurrentAdapter; - D3DCAPS9 m_Caps; - D3DFORMAT m_BackbufferType; - D3DFORMAT m_DisplayType; - CSize m_ScreenSize; - CSize m_BackBufferSize; - int m_nNbDXSurface; // Total number of DX Surfaces - int m_nCurSurface; // Surface currently displayed - - bool m_bHighColorResolution; - bool m_bForceInputHighColorResolution; - - // Variables initialized/managed by this class but can be accessed by the allocator-presenter - bool m_bD3DX; - RenderingPath m_RenderingPath; - D3DFORMAT m_SurfaceType; - CComPtr m_pVideoTexture[MAX_VIDEO_SURFACES]; - CComPtr m_pVideoSurface[MAX_VIDEO_SURFACES]; - - bool m_bFullFloatingPointProcessing; - bool m_bHalfFloatingPointProcessing; - bool m_bColorManagement; - - CDX9RenderingEngine(HWND hWnd, HRESULT& hr, CString* _pError); - virtual ~CDX9RenderingEngine() = default; - - void InitRenderingEngine(); - void CleanupRenderingEngine(); - - HRESULT CreateVideoSurfaces(); - void FreeVideoSurfaces(); - - HRESULT RenderVideo(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); - - HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect); - HRESULT AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); - - HRESULT SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); - - - private: - class CExternalPixelShader - { - public: - CComPtr m_pPixelShader; - CStringA m_SourceData; - CStringA m_SourceTarget; - HRESULT Compile(CPixelShaderCompiler* pCompiler) { - HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); - if (FAILED(hr)) { - return hr; - } - - return S_OK; - } - }; - - // D3DX functions - typedef D3DXFLOAT16* (WINAPI* D3DXFloat32To16ArrayPtr)( - D3DXFLOAT16* pOut, - CONST float* pIn, - UINT n); - - - CAutoPtr m_pPSC; - - // Settings - VideoSystem m_InputVideoSystem; - AmbientLight m_AmbientLight; - ColorRenderingIntent m_RenderingIntent; - - // Custom pixel shaders - CAtlList m_pCustomPixelShaders; - CComPtr m_pTemporaryVideoTextures[2]; - - // Screen space pipeline - int m_ScreenSpacePassCount; - int m_ScreenSpacePassSrc; - int m_ScreenSpacePassDest; - CSize m_TemporaryScreenSpaceTextureSize; - CComPtr m_pTemporaryScreenSpaceTextures[2]; - IDirect3DSurface9* m_pRenderTarget; - - // Resizers - float m_BicubicA; - CComPtr m_pResizerPixelShaders[4]; // bl, bc1, bc2_1, bc2_2 - - // Final pass - bool m_bFinalPass; - int m_Lut3DSize; - int m_Lut3DEntryCount; - CComPtr m_pLut3DTexture; - CComPtr m_pDitherTexture; - CComPtr m_pFinalPixelShader; - - // Custom screen space pixel shaders - CAtlList m_pCustomScreenSpacePixelShaders; - - // StetchRect rendering path - D3DTEXTUREFILTERTYPE m_StretchRectFilter; - - // D3DX function pointers - D3DXFloat32To16ArrayPtr m_pD3DXFloat32To16Array; - - - // Video rendering paths - HRESULT RenderVideoDrawPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); - HRESULT RenderVideoStretchRectPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); - - // Custom pixel shaders - HRESULT InitTemporaryVideoTextures(int count); - - // Screen space pipeline - HRESULT InitScreenSpacePipeline(int passCount, IDirect3DSurface9* pRenderTarget); - HRESULT InitTemporaryScreenSpaceTextures(int count); - HRESULT BeginScreenSpacePass(); - - // Resizers - HRESULT InitResizers(float bicubicA); - HRESULT TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& srcRect); - HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect); - HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect); - //HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect &srcRect); - protected: - HRESULT Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect); - private: - // Final pass - HRESULT InitFinalPass(); - void CleanupFinalPass(); - HRESULT CreateIccProfileLut(TCHAR* profilePath, float* lut3D); - HRESULT FinalPass(IDirect3DTexture9* pTexture); - - HRESULT TextureCopy(IDirect3DTexture9* pTexture); - bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d); - }; - -} +/* + * (C) 2006-2013, 2016-2017 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 . + * + */ + +#pragma once + +#include "AllocatorCommon.h" +#include "RenderersSettings.h" +#include +#include "d3dx9/d3dx9.h" +#include "../SubPic/SubPicAllocatorPresenterImpl.h" + + +namespace DSObjects +{ + + class CDX9RenderingEngine + : public CSubPicAllocatorPresenterImpl + { + protected: + enum RenderingPath { + RENDERING_PATH_STRETCHRECT, + RENDERING_PATH_DRAW + }; + + static const int MAX_VIDEO_SURFACES = 60; + + // Variables initialized/managed by the allocator-presenter! + CComPtr m_pD3D; + CComPtr m_pD3DEx; + CComPtr m_pD3DDev; + CComPtr m_pD3DDevEx; + UINT m_CurrentAdapter; + D3DCAPS9 m_Caps; + D3DFORMAT m_BackbufferType; + D3DFORMAT m_DisplayType; + CSize m_ScreenSize; + CSize m_BackBufferSize; + int m_nNbDXSurface; // Total number of DX Surfaces + int m_nCurSurface; // Surface currently displayed + + bool m_bHighColorResolution; + bool m_bForceInputHighColorResolution; + + // Variables initialized/managed by this class but can be accessed by the allocator-presenter + bool m_bD3DX; + RenderingPath m_RenderingPath; + D3DFORMAT m_SurfaceType; + CComPtr m_pVideoTexture[MAX_VIDEO_SURFACES]; + CComPtr m_pVideoSurface[MAX_VIDEO_SURFACES]; + + bool m_bFullFloatingPointProcessing; + bool m_bHalfFloatingPointProcessing; + bool m_bColorManagement; + + CDX9RenderingEngine(HWND hWnd, HRESULT& hr, CString* _pError); + virtual ~CDX9RenderingEngine() = default; + + void InitRenderingEngine(); + void CleanupRenderingEngine(); + + HRESULT CreateVideoSurfaces(); + void FreeVideoSurfaces(); + + HRESULT RenderVideo(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); + + HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect); + HRESULT AlphaBlt(const RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); + + HRESULT SetCustomPixelShader(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); + + + private: + class CExternalPixelShader + { + public: + CComPtr m_pPixelShader; + CStringA m_SourceData; + CStringA m_SourceTarget; + HRESULT Compile(CPixelShaderCompiler* pCompiler) { + HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); + if (FAILED(hr)) { + return hr; + } + + return S_OK; + } + }; + + // D3DX functions + typedef D3DXFLOAT16* (WINAPI* D3DXFloat32To16ArrayPtr)( + D3DXFLOAT16* pOut, + CONST float* pIn, + UINT n); + + + CAutoPtr m_pPSC; + + // Settings + VideoSystem m_InputVideoSystem; + AmbientLight m_AmbientLight; + ColorRenderingIntent m_RenderingIntent; + + // Custom pixel shaders + CAtlList m_pCustomPixelShaders; + CComPtr m_pTemporaryVideoTextures[2]; + + // Screen space pipeline + int m_ScreenSpacePassCount; + int m_ScreenSpacePassSrc; + int m_ScreenSpacePassDest; + CSize m_TemporaryScreenSpaceTextureSize; + CComPtr m_pTemporaryScreenSpaceTextures[2]; + IDirect3DSurface9* m_pRenderTarget; + + // Resizers + float m_BicubicA; + CComPtr m_pResizerPixelShaders[4]; // bl, bc1, bc2_1, bc2_2 + + // Final pass + bool m_bFinalPass; + int m_Lut3DSize; + int m_Lut3DEntryCount; + CComPtr m_pLut3DTexture; + CComPtr m_pDitherTexture; + CComPtr m_pFinalPixelShader; + + // Custom screen space pixel shaders + CAtlList m_pCustomScreenSpacePixelShaders; + + // StetchRect rendering path + D3DTEXTUREFILTERTYPE m_StretchRectFilter; + + // D3DX function pointers + D3DXFloat32To16ArrayPtr m_pD3DXFloat32To16Array; + + + // Video rendering paths + HRESULT RenderVideoDrawPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); + HRESULT RenderVideoStretchRectPath(IDirect3DSurface9* pRenderTarget, const CRect& srcRect, const CRect& destRect); + + // Custom pixel shaders + HRESULT InitTemporaryVideoTextures(int count); + + // Screen space pipeline + HRESULT InitScreenSpacePipeline(int passCount, IDirect3DSurface9* pRenderTarget); + HRESULT InitTemporaryScreenSpaceTextures(int count); + HRESULT BeginScreenSpacePass(); + + // Resizers + HRESULT InitResizers(float bicubicA); + HRESULT TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& srcRect); + HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect); + HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& srcRect); + //HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect &srcRect); + protected: + HRESULT Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect); + private: + // Final pass + HRESULT InitFinalPass(); + void CleanupFinalPass(); + HRESULT CreateIccProfileLut(TCHAR* profilePath, float* lut3D); + HRESULT FinalPass(IDirect3DTexture9* pTexture); + + HRESULT TextureCopy(IDirect3DTexture9* pTexture); + bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d); + }; + +} diff --git a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp index 6435d5517e6..c421f65bce1 100644 --- a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp @@ -1,228 +1,228 @@ -/* - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "RenderersSettings.h" -#include "DXRAllocatorPresenter.h" -#include "../../../SubPic/DX9SubPic.h" -#include "../../../SubPic/SubPicQueueImpl.h" -#include "moreuuids.h" - -using namespace DSObjects; - -// -// CDXRAllocatorPresenter -// - -CDXRAllocatorPresenter::CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error) - : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) - , m_ScreenSize(0, 0) -{ - if (FAILED(hr)) { - _Error += L"ISubPicAllocatorPresenterImpl failed\n"; - return; - } - - hr = S_OK; -} - -CDXRAllocatorPresenter::~CDXRAllocatorPresenter() -{ - if (m_pSRCB) { - // nasty, but we have to let it know about our death somehow - ((CSubRenderCallback*)(ISubRenderCallback*)m_pSRCB)->SetDXRAP(nullptr); - } - - // the order is important here - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - m_pDXR = nullptr; -} - -STDMETHODIMP CDXRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - /* - if (riid == __uuidof(IVideoWindow)) - return GetInterface((IVideoWindow*)this, ppv); - if (riid == __uuidof(IBasicVideo)) - return GetInterface((IBasicVideo*)this, ppv); - if (riid == __uuidof(IBasicVideo2)) - return GetInterface((IBasicVideo2*)this, ppv); - */ - /* - if (riid == __uuidof(IVMRWindowlessControl)) - return GetInterface((IVMRWindowlessControl*)this, ppv); - */ - - if (riid != IID_IUnknown && m_pDXR) { - if (SUCCEEDED(m_pDXR->QueryInterface(riid, ppv))) { - return S_OK; - } - } - - return __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CDXRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev) -{ - HRESULT hr = S_OK; - - if (!pD3DDev) { - // release all resources - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - __super::SetPosition(CRect(), CRect()); - return hr; - } - - const CRenderersSettings& r = GetRenderersSettings(); - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(pD3DDev, m_maxSubtitleTextureSize, true); - if (!m_pAllocator) { - return E_FAIL; - } - } - - { - // Lock before check because m_pSubPicQueue might be initialized in CSubPicAllocatorPresenterImpl::Connect - CAutoLock cAutoLock(this); - if (!m_pSubPicQueue) { - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - this->Unlock(); - m_pSubPicQueue->Invalidate(); - } - } - - if (SUCCEEDED(hr) && m_pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); - } - - return hr; -} - -HRESULT CDXRAllocatorPresenter::Render( - REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, - int left, int top, int right, int bottom, int width, int height) -{ - CRect wndRect(0, 0, width, height); - CRect videoRect(left, top, right, bottom); - __super::SetPosition(wndRect, videoRect); // needed? should be already set by the player - SetTime(rtStart); - if (atpf > 0 && m_pSubPicQueue) { - m_pSubPicQueue->SetFPS(10000000.0 / atpf); - } - AlphaBltSubPic(wndRect, videoRect); - return S_OK; -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP CDXRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - - if (m_pDXR) { - return E_UNEXPECTED; - } - m_pDXR.CoCreateInstance(CLSID_DXR, GetOwner()); - if (!m_pDXR) { - return E_FAIL; - } - - CComQIPtr pSR = m_pDXR; - if (!pSR) { - m_pDXR = nullptr; - return E_FAIL; - } - - m_pSRCB = DEBUG_NEW CSubRenderCallback(this); - if (FAILED(pSR->SetCallback(m_pSRCB))) { - m_pDXR = nullptr; - return E_FAIL; - } - - (*ppRenderer = (IUnknown*)(INonDelegatingUnknown*)(this))->AddRef(); - - MONITORINFO mi; - mi.cbSize = sizeof(MONITORINFO); - if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { - m_ScreenSize.SetSize(mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top); - } - - return S_OK; -} - -STDMETHODIMP_(void) CDXRAllocatorPresenter::SetPosition(RECT w, RECT v) -{ - if (CComQIPtr pBV = m_pDXR) { - pBV->SetDefaultSourcePosition(); - pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top); - } - - if (CComQIPtr pVW = m_pDXR) { - pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top); - } - - SetVideoSize(GetVideoSize(false), GetVideoSize(true)); -} - -STDMETHODIMP_(SIZE) CDXRAllocatorPresenter::GetVideoSize(bool bCorrectAR) const -{ - SIZE size = {0, 0}; - - if (!bCorrectAR) { - if (CComQIPtr pBV = m_pDXR) { - pBV->GetVideoSize(&size.cx, &size.cy); - } - } else { - if (CComQIPtr pBV2 = m_pDXR) { - pBV2->GetPreferredAspectRatio(&size.cx, &size.cy); - } - } - - return size; -} - -STDMETHODIMP_(bool) CDXRAllocatorPresenter::Paint(bool bAll) -{ - return false; // TODO -} - -STDMETHODIMP CDXRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) -{ - HRESULT hr = E_NOTIMPL; - if (CComQIPtr pBV = m_pDXR) { - hr = pBV->GetCurrentImage((long*)size, (long*)lpDib); - } - return hr; -} - -STDMETHODIMP CDXRAllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) -{ - return E_NOTIMPL; // TODO -} +/* + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "RenderersSettings.h" +#include "DXRAllocatorPresenter.h" +#include "../../../SubPic/DX9SubPic.h" +#include "../../../SubPic/SubPicQueueImpl.h" +#include "moreuuids.h" + +using namespace DSObjects; + +// +// CDXRAllocatorPresenter +// + +CDXRAllocatorPresenter::CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error) + : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) + , m_ScreenSize(0, 0) +{ + if (FAILED(hr)) { + _Error += L"ISubPicAllocatorPresenterImpl failed\n"; + return; + } + + hr = S_OK; +} + +CDXRAllocatorPresenter::~CDXRAllocatorPresenter() +{ + if (m_pSRCB) { + // nasty, but we have to let it know about our death somehow + ((CSubRenderCallback*)(ISubRenderCallback*)m_pSRCB)->SetDXRAP(nullptr); + } + + // the order is important here + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + m_pDXR = nullptr; +} + +STDMETHODIMP CDXRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + /* + if (riid == __uuidof(IVideoWindow)) + return GetInterface((IVideoWindow*)this, ppv); + if (riid == __uuidof(IBasicVideo)) + return GetInterface((IBasicVideo*)this, ppv); + if (riid == __uuidof(IBasicVideo2)) + return GetInterface((IBasicVideo2*)this, ppv); + */ + /* + if (riid == __uuidof(IVMRWindowlessControl)) + return GetInterface((IVMRWindowlessControl*)this, ppv); + */ + + if (riid != IID_IUnknown && m_pDXR) { + if (SUCCEEDED(m_pDXR->QueryInterface(riid, ppv))) { + return S_OK; + } + } + + return __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CDXRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev) +{ + HRESULT hr = S_OK; + + if (!pD3DDev) { + // release all resources + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + __super::SetPosition(CRect(), CRect()); + return hr; + } + + const CRenderersSettings& r = GetRenderersSettings(); + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(pD3DDev, m_maxSubtitleTextureSize, true); + if (!m_pAllocator) { + return E_FAIL; + } + } + + { + // Lock before check because m_pSubPicQueue might be initialized in CSubPicAllocatorPresenterImpl::Connect + CAutoLock cAutoLock(this); + if (!m_pSubPicQueue) { + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + this->Unlock(); + m_pSubPicQueue->Invalidate(); + } + } + + if (SUCCEEDED(hr) && m_pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); + } + + return hr; +} + +HRESULT CDXRAllocatorPresenter::Render( + REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, + int left, int top, int right, int bottom, int width, int height) +{ + CRect wndRect(0, 0, width, height); + CRect videoRect(left, top, right, bottom); + __super::SetPosition(wndRect, videoRect); // needed? should be already set by the player + SetTime(rtStart); + if (atpf > 0 && m_pSubPicQueue) { + m_pSubPicQueue->SetFPS(10000000.0 / atpf); + } + AlphaBltSubPic(wndRect, videoRect); + return S_OK; +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP CDXRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + + if (m_pDXR) { + return E_UNEXPECTED; + } + m_pDXR.CoCreateInstance(CLSID_DXR, GetOwner()); + if (!m_pDXR) { + return E_FAIL; + } + + CComQIPtr pSR = m_pDXR; + if (!pSR) { + m_pDXR = nullptr; + return E_FAIL; + } + + m_pSRCB = DEBUG_NEW CSubRenderCallback(this); + if (FAILED(pSR->SetCallback(m_pSRCB))) { + m_pDXR = nullptr; + return E_FAIL; + } + + (*ppRenderer = (IUnknown*)(INonDelegatingUnknown*)(this))->AddRef(); + + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { + m_ScreenSize.SetSize(mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top); + } + + return S_OK; +} + +STDMETHODIMP_(void) CDXRAllocatorPresenter::SetPosition(RECT w, RECT v) +{ + if (CComQIPtr pBV = m_pDXR) { + pBV->SetDefaultSourcePosition(); + pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top); + } + + if (CComQIPtr pVW = m_pDXR) { + pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top); + } + + SetVideoSize(GetVideoSize(false), GetVideoSize(true)); +} + +STDMETHODIMP_(SIZE) CDXRAllocatorPresenter::GetVideoSize(bool bCorrectAR) const +{ + SIZE size = {0, 0}; + + if (!bCorrectAR) { + if (CComQIPtr pBV = m_pDXR) { + pBV->GetVideoSize(&size.cx, &size.cy); + } + } else { + if (CComQIPtr pBV2 = m_pDXR) { + pBV2->GetPreferredAspectRatio(&size.cx, &size.cy); + } + } + + return size; +} + +STDMETHODIMP_(bool) CDXRAllocatorPresenter::Paint(bool bAll) +{ + return false; // TODO +} + +STDMETHODIMP CDXRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) +{ + HRESULT hr = E_NOTIMPL; + if (CComQIPtr pBV = m_pDXR) { + hr = pBV->GetCurrentImage((long*)size, (long*)lpDib); + } + return hr; +} + +STDMETHODIMP CDXRAllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) +{ + return E_NOTIMPL; // TODO +} diff --git a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h index d8168673035..169b5017ed0 100644 --- a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h @@ -1,103 +1,103 @@ -/* - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "AllocatorCommon.h" -#include "../SubPic/SubPicAllocatorPresenterImpl.h" -#include "../SubPic/ISubRender.h" - -namespace DSObjects -{ - class CDXRAllocatorPresenter - : public CSubPicAllocatorPresenterImpl - { - class CSubRenderCallback : public CUnknown, public ISubRenderCallback, public CCritSec - { - CDXRAllocatorPresenter* m_pDXRAP; - - public: - CSubRenderCallback(CDXRAllocatorPresenter* pDXRAP) - : CUnknown(_T("CSubRender"), nullptr) - , m_pDXRAP(pDXRAP) { - } - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(ISubRenderCallback) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - void SetDXRAP(CDXRAllocatorPresenter* pDXRAP) { - CAutoLock cAutoLock(this); - m_pDXRAP = pDXRAP; - } - - // ISubRenderCallback - - STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev) { - CAutoLock cAutoLock(this); - return m_pDXRAP ? m_pDXRAP->SetDevice(pD3DDev) : E_UNEXPECTED; - } - - STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, int bottom, int width, int height) { - CAutoLock cAutoLock(this); - return m_pDXRAP ? m_pDXRAP->Render(rtStart, 0, 0, left, top, right, bottom, width, height) : E_UNEXPECTED; - } - - // ISubRendererCallback2 - - STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME AvgTimePerFrame, int left, int top, int right, int bottom, int width, int height) { - CAutoLock cAutoLock(this); - return m_pDXRAP ? m_pDXRAP->Render(rtStart, rtStop, AvgTimePerFrame, left, top, right, bottom, width, height) : E_UNEXPECTED; - } - }; - - CComPtr m_pDXR; - CComPtr m_pSRCB; - CSize m_ScreenSize; - - public: - CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error); - virtual ~CDXRAllocatorPresenter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT SetDevice(IDirect3DDevice9* pD3DDev); - HRESULT Render( - REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, - int left, int top, int bottom, int right, int width, int height); - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(void) SetPosition(RECT w, RECT v); - STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const; - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() { - return true; // We don't know so we always pretend to be rendering - } - }; -} +/* + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "AllocatorCommon.h" +#include "../SubPic/SubPicAllocatorPresenterImpl.h" +#include "../SubPic/ISubRender.h" + +namespace DSObjects +{ + class CDXRAllocatorPresenter + : public CSubPicAllocatorPresenterImpl + { + class CSubRenderCallback : public CUnknown, public ISubRenderCallback, public CCritSec + { + CDXRAllocatorPresenter* m_pDXRAP; + + public: + CSubRenderCallback(CDXRAllocatorPresenter* pDXRAP) + : CUnknown(_T("CSubRender"), nullptr) + , m_pDXRAP(pDXRAP) { + } + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(ISubRenderCallback) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + void SetDXRAP(CDXRAllocatorPresenter* pDXRAP) { + CAutoLock cAutoLock(this); + m_pDXRAP = pDXRAP; + } + + // ISubRenderCallback + + STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev) { + CAutoLock cAutoLock(this); + return m_pDXRAP ? m_pDXRAP->SetDevice(pD3DDev) : E_UNEXPECTED; + } + + STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, int bottom, int width, int height) { + CAutoLock cAutoLock(this); + return m_pDXRAP ? m_pDXRAP->Render(rtStart, 0, 0, left, top, right, bottom, width, height) : E_UNEXPECTED; + } + + // ISubRendererCallback2 + + STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME AvgTimePerFrame, int left, int top, int right, int bottom, int width, int height) { + CAutoLock cAutoLock(this); + return m_pDXRAP ? m_pDXRAP->Render(rtStart, rtStop, AvgTimePerFrame, left, top, right, bottom, width, height) : E_UNEXPECTED; + } + }; + + CComPtr m_pDXR; + CComPtr m_pSRCB; + CSize m_ScreenSize; + + public: + CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error); + virtual ~CDXRAllocatorPresenter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT SetDevice(IDirect3DDevice9* pD3DDev); + HRESULT Render( + REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, + int left, int top, int bottom, int right, int width, int height); + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(void) SetPosition(RECT w, RECT v); + STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const; + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() { + return true; // We don't know so we always pretend to be rendering + } + }; +} diff --git a/src/filters/renderer/VideoRenderers/Dither.cpp b/src/filters/renderer/VideoRenderers/Dither.cpp index d4dec88044e..3e1ce88ef18 100644 --- a/src/filters/renderer/VideoRenderers/Dither.cpp +++ b/src/filters/renderer/VideoRenderers/Dither.cpp @@ -1,90 +1,90 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "Dither.h" - -// Dither matrix in 16-bit floating point format -const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE] = { - 0x2c90, 0x38f4, 0x3bba, 0x29e0, 0x35f4, 0x3230, 0x3bbc, 0x3924, 0x3a46, 0x3644, 0x39e2, 0x370c, 0x3444, 0x3b1a, 0x3140, 0x39d2, - 0x385a, 0x3b24, 0x2c10, 0x38c6, 0x3808, 0x2780, 0x3bbe, 0x37f8, 0x350c, 0x3a6c, 0x3368, 0x3bc0, 0x3000, 0x3886, 0x31b0, 0x3554, - 0x3a94, 0x3618, 0x3430, 0x3a34, 0x3834, 0x39fe, 0x2740, 0x3758, 0x3494, 0x3b7a, 0x2700, 0x3958, 0x3858, 0x3a24, 0x364c, 0x3bc2, - 0x3278, 0x3a22, 0x353c, 0x39de, 0x3268, 0x3a98, 0x36fc, 0x2ed0, 0x39e0, 0x30f0, 0x381a, 0x3996, 0x35ac, 0x3af2, 0x39b8, 0x37bc, - 0x3250, 0x39dc, 0x3800, 0x30e8, 0x3b42, 0x34d4, 0x3970, 0x3afe, 0x3020, 0x3898, 0x33e8, 0x3b34, 0x2e10, 0x3320, 0x391a, 0x26c0, - 0x3784, 0x38de, 0x3060, 0x3b5c, 0x3600, 0x38e6, 0x3490, 0x3b2a, 0x387a, 0x365c, 0x3b3c, 0x2be0, 0x37ac, 0x33d8, 0x2680, 0x3b98, - 0x38d6, 0x2a60, 0x3b7e, 0x391e, 0x36d0, 0x2fe0, 0x3812, 0x32a0, 0x3a84, 0x36b0, 0x3a50, 0x357c, 0x37dc, 0x3b68, 0x3594, 0x3aca, - 0x344c, 0x3a7c, 0x3674, 0x3884, 0x2d30, 0x3a48, 0x3170, 0x398e, 0x2900, 0x3a30, 0x34bc, 0x38ea, 0x3b70, 0x3a3c, 0x3852, 0x3460, - 0x3b04, 0x37a0, 0x351c, 0x2d40, 0x3a80, 0x394e, 0x3b84, 0x3614, 0x3900, 0x2b20, 0x396c, 0x31b8, 0x38ca, 0x3a0c, 0x3038, 0x385c, - 0x39a2, 0x2c70, 0x3ba2, 0x3464, 0x3992, 0x36dc, 0x3bc4, 0x3580, 0x3824, 0x32d0, 0x3abc, 0x2ec0, 0x3560, 0x30f8, 0x3974, 0x3610, - 0x3a12, 0x3110, 0x3aaa, 0x38a2, 0x35e4, 0x341c, 0x28c0, 0x3a02, 0x34a8, 0x3b60, 0x3790, 0x3aa2, 0x2c40, 0x346c, 0x373c, 0x3bc6, - 0x32f0, 0x37e8, 0x391c, 0x3100, 0x3af6, 0x2640, 0x3868, 0x3098, 0x3b3e, 0x3944, 0x3620, 0x3870, 0x39da, 0x374c, 0x3bc8, 0x2e20, - 0x3804, 0x3932, 0x3660, 0x3260, 0x3bca, 0x38ce, 0x3ade, 0x382e, 0x30a0, 0x389e, 0x33a0, 0x363c, 0x3b86, 0x3910, 0x3a58, 0x2820, - 0x36a0, 0x3b28, 0x34e0, 0x3a40, 0x3768, 0x3510, 0x3a54, 0x390e, 0x36e8, 0x2ae0, 0x3bcc, 0x31a0, 0x3aa4, 0x2600, 0x38cc, 0x3400, - 0x3ac4, 0x2800, 0x3b4a, 0x39ee, 0x2cc0, 0x3764, 0x31c8, 0x35cc, 0x3bb6, 0x39a8, 0x2f30, 0x3a1e, 0x3816, 0x3160, 0x35b0, 0x389a, - 0x3a86, 0x3070, 0x3848, 0x2d70, 0x38ba, 0x3baa, 0x2e60, 0x3414, 0x3ae4, 0x3544, 0x3a06, 0x37fc, 0x347c, 0x36d8, 0x3b12, 0x35a4, - 0x3248, 0x3866, 0x34f8, 0x3814, 0x33f8, 0x39c2, 0x3a8a, 0x38e2, 0x25c0, 0x3720, 0x3b26, 0x3508, 0x2980, 0x39b4, 0x3b4c, 0x33a8, - 0x3976, 0x3534, 0x39c4, 0x3b40, 0x3604, 0x31c0, 0x397c, 0x37b0, 0x39d0, 0x3218, 0x38d8, 0x2e30, 0x3b52, 0x39bc, 0x2fa0, 0x3980, - 0x3b9a, 0x39d4, 0x2f40, 0x3960, 0x3b64, 0x3680, 0x2f60, 0x34c8, 0x3acc, 0x3228, 0x3850, 0x395c, 0x3bce, 0x354c, 0x3840, 0x2db0, - 0x37a4, 0x3bd0, 0x2580, 0x33c8, 0x392a, 0x3a82, 0x3530, 0x3b48, 0x2540, 0x3760, 0x3a42, 0x35dc, 0x3890, 0x3308, 0x3844, 0x3710, - 0x3418, 0x366c, 0x3a9a, 0x3590, 0x2500, 0x3888, 0x3bd2, 0x3984, 0x3668, 0x39e4, 0x345c, 0x2d20, 0x371c, 0x3288, 0x3aae, 0x39d6, - 0x31e0, 0x38c8, 0x36e4, 0x3ab2, 0x380c, 0x2b00, 0x389c, 0x3280, 0x392c, 0x3bd4, 0x33b8, 0x3ad6, 0x24c0, 0x3bd6, 0x3a32, 0x2c60, - 0x3b1c, 0x38aa, 0x3238, 0x3902, 0x3ae8, 0x3528, 0x3118, 0x3818, 0x2c50, 0x3ba0, 0x38bc, 0x3ad8, 0x3a20, 0x38f0, 0x2480, 0x36b4, - 0x3b02, 0x34b0, 0x3a00, 0x30a8, 0x3518, 0x3bd8, 0x3688, 0x3a92, 0x34b4, 0x36c0, 0x2f70, 0x3968, 0x3798, 0x3448, 0x35ec, 0x3930, - 0x3750, 0x2a40, 0x3bda, 0x3728, 0x32e8, 0x3a4a, 0x38d2, 0x3b38, 0x33d0, 0x3738, 0x30b8, 0x3628, 0x340c, 0x37d4, 0x3bb2, 0x3428, - 0x3934, 0x2b40, 0x3856, 0x3b0e, 0x3964, 0x31d0, 0x39b0, 0x2e80, 0x38d4, 0x3b1e, 0x3a28, 0x387e, 0x30e0, 0x39a0, 0x3ae2, 0x3208, - 0x3a56, 0x352c, 0x3a14, 0x2d90, 0x3978, 0x3794, 0x2960, 0x35e0, 0x39c6, 0x3a88, 0x3862, 0x3b76, 0x2e40, 0x3988, 0x3128, 0x3a4c, - 0x378c, 0x3b8e, 0x359c, 0x2ea0, 0x36ac, 0x383e, 0x3af8, 0x3404, 0x3780, 0x2a20, 0x3360, 0x3598, 0x3b90, 0x37d0, 0x2dd0, 0x3880, - 0x3358, 0x3946, 0x381c, 0x348c, 0x3b50, 0x3198, 0x3ad4, 0x3940, 0x3050, 0x3540, 0x2440, 0x39cc, 0x3770, 0x3b0a, 0x35d8, 0x386c, - 0x2f00, 0x3380, 0x3a5a, 0x3948, 0x3ba4, 0x2400, 0x35a0, 0x393e, 0x3ba6, 0x39ea, 0x3838, 0x3ab0, 0x27c0, 0x3a38, 0x3538, 0x3bb4, - 0x2380, 0x3b62, 0x30d8, 0x3a62, 0x360c, 0x388c, 0x342c, 0x37e0, 0x3bdc, 0x38f2, 0x3ad0, 0x3488, 0x3168, 0x38da, 0x2300, 0x39ca, - 0x3aee, 0x3630, 0x387c, 0x31a8, 0x34e4, 0x38b8, 0x3a3e, 0x2dc0, 0x3640, 0x3130, 0x34ec, 0x3972, 0x36ec, 0x3318, 0x3950, 0x3714, - 0x3914, 0x356c, 0x38b6, 0x376c, 0x2280, 0x3b9c, 0x39c8, 0x2d50, 0x35e8, 0x32c0, 0x3704, 0x388a, 0x3a64, 0x3558, 0x3bde, 0x3440, - 0x3724, 0x3982, 0x28e0, 0x3ada, 0x375c, 0x3b30, 0x3300, 0x384a, 0x3a74, 0x38e8, 0x3b66, 0x2ee0, 0x385e, 0x3b46, 0x2f90, 0x3ab8, - 0x3178, 0x3a52, 0x2e00, 0x3b08, 0x3918, 0x3150, 0x3678, 0x3aa6, 0x3922, 0x3b14, 0x2fd0, 0x3b8a, 0x2ce0, 0x39a4, 0x379c, 0x2fb0, - 0x3b5a, 0x3240, 0x3a2e, 0x3390, 0x3916, 0x2e90, 0x36c4, 0x3be0, 0x349c, 0x2200, 0x3694, 0x39b2, 0x3478, 0x39f0, 0x35c4, 0x3828, - 0x3be2, 0x36d4, 0x3994, 0x3548, 0x3328, 0x3a04, 0x3854, 0x3498, 0x28a0, 0x3810, 0x39fc, 0x3520, 0x3846, 0x32d8, 0x3ab4, 0x393c, - 0x3864, 0x35b4, 0x380e, 0x3be4, 0x3570, 0x3a96, 0x39ac, 0x3090, 0x3962, 0x37c0, 0x3a9e, 0x3120, 0x3be6, 0x2a00, 0x38f6, 0x3410, - 0x2180, 0x386e, 0x3088, 0x3b82, 0x37a8, 0x3ae6, 0x2f10, 0x3be8, 0x399a, 0x3634, 0x31e8, 0x3912, 0x3b06, 0x36f0, 0x2c30, 0x3504, - 0x3a76, 0x2aa0, 0x39e8, 0x3040, 0x3878, 0x2880, 0x383a, 0x35f8, 0x3aec, 0x32a8, 0x3936, 0x3550, 0x3892, 0x3740, 0x3aea, 0x398c, - 0x3a72, 0x34c4, 0x3a1c, 0x38ac, 0x2860, 0x3584, 0x38fa, 0x372c, 0x3388, 0x3a3a, 0x3b9e, 0x2100, 0x3420, 0x395a, 0x3bae, 0x37d8, - 0x3398, 0x3b6c, 0x3734, 0x34d0, 0x39c0, 0x3b78, 0x3474, 0x3a2c, 0x2b80, 0x3830, 0x3b56, 0x2cb0, 0x3a78, 0x33b0, 0x3018, 0x3650, - 0x30d0, 0x3b20, 0x3690, 0x3350, 0x39ae, 0x3a90, 0x3148, 0x3b44, 0x2cd0, 0x38a0, 0x355c, 0x382a, 0x3a8e, 0x35b8, 0x3190, 0x39ec, - 0x38c4, 0x3068, 0x3938, 0x3b2e, 0x32c8, 0x3748, 0x3008, 0x3894, 0x3bb8, 0x3438, 0x36c8, 0x3904, 0x35fc, 0x396e, 0x3bac, 0x38a6, - 0x397a, 0x37ec, 0x2ca0, 0x3bea, 0x3754, 0x34a4, 0x3836, 0x3956, 0x362c, 0x3b00, 0x30c0, 0x39a6, 0x2fc0, 0x38ae, 0x3abe, 0x2080, - 0x3684, 0x3a70, 0x3568, 0x2000, 0x38c2, 0x3af0, 0x3998, 0x368c, 0x30b0, 0x39ba, 0x3aa8, 0x3200, 0x3b16, 0x2d80, 0x377c, 0x3480, - 0x3b6e, 0x3270, 0x39fa, 0x386a, 0x2ff0, 0x3b10, 0x1f00, 0x3a44, 0x343c, 0x3802, 0x3a66, 0x34b8, 0x3bec, 0x3708, 0x3340, 0x3882, - 0x3bee, 0x3298, 0x3806, 0x3a08, 0x3638, 0x2d00, 0x34ac, 0x3a60, 0x38ee, 0x35c8, 0x29c0, 0x380a, 0x34f0, 0x38f8, 0x3aac, 0x1e00, - 0x3564, 0x38fe, 0x3468, 0x3ace, 0x35d0, 0x394a, 0x37b4, 0x31f8, 0x3bf0, 0x2bc0, 0x38d0, 0x36b8, 0x2940, 0x3926, 0x3b32, 0x35a8, - 0x2d60, 0x38e0, 0x3b58, 0x3078, 0x3a9c, 0x37e4, 0x3bf2, 0x2e50, 0x33f0, 0x3b72, 0x38b4, 0x39e6, 0x3bf4, 0x3290, 0x3670, 0x3a1a, - 0x3842, 0x3a68, 0x2920, 0x37c4, 0x32b8, 0x3b88, 0x34c0, 0x396a, 0x3664, 0x39b6, 0x3330, 0x3b5e, 0x39ce, 0x3484, 0x3080, 0x39aa, - 0x3a4e, 0x3700, 0x34e8, 0x395e, 0x3310, 0x3908, 0x3588, 0x384e, 0x3ac6, 0x3730, 0x3220, 0x3574, 0x2de0, 0x37f0, 0x399c, 0x2ef0, - 0x3188, 0x369c, 0x3bf6, 0x390a, 0x39f2, 0x2b60, 0x3872, 0x3aa0, 0x2df0, 0x3b0c, 0x37cc, 0x2da0, 0x382c, 0x3ae0, 0x38b0, 0x3788, - 0x33c0, 0x3afa, 0x2ba0, 0x3826, 0x3b6a, 0x1d00, 0x39f8, 0x3108, 0x3920, 0x1c00, 0x3a26, 0x3b22, 0x38ec, 0x3ac2, 0x3458, 0x3b7c, - 0x3a8c, 0x38a8, 0x34d8, 0x3048, 0x3654, 0x3adc, 0x3138, 0x3744, 0x3450, 0x38be, 0x34f4, 0x3a10, 0x3210, 0x35bc, 0x2840, 0x3b92, - 0x3058, 0x3986, 0x3698, 0x39d8, 0x3434, 0x36f8, 0x3b18, 0x3524, 0x3a7a, 0x35d4, 0x3822, 0x3408, 0x36bc, 0x2ac0, 0x3896, 0x3624, - 0x1a00, 0x3378, 0x3a16, 0x3b3a, 0x381e, 0x3338, 0x3906, 0x39f6, 0x3bf8, 0x3158, 0x3ad2, 0x36e0, 0x3bfa, 0x392e, 0x3a5c, 0x3648, - 0x38dc, 0x34cc, 0x3bfc, 0x30c8, 0x3ab6, 0x3942, 0x32b0, 0x38a4, 0x2d10, 0x3b96, 0x394c, 0x2f80, 0x3bfe, 0x3966, 0x3258, 0x39be, - 0x3bb0, 0x3928, 0x361c, 0x2c00, 0x3990, 0x3b8c, 0x3578, 0x2a80, 0x36cc, 0x3952, 0x1800, 0x388e, 0x33e0, 0x2f20, 0x384c, 0x31d8, - 0x3a18, 0x1400, 0x3876, 0x358c, 0x383c, 0x2c20, 0x3b80, 0x3774, 0x3a36, 0x3470, 0x31f0, 0x3a0a, 0x3832, 0x3514, 0x3a6a, 0x37f4, - 0x367c, 0x3028, 0x3ac8, 0x37b8, 0x34a0, 0x2f50, 0x3a5e, 0x3874, 0x3b36, 0x34fc, 0x3a6e, 0x35f0, 0x399e, 0x3aba, 0x3500, 0x3b74, - 0x37c8, 0x3ac0, 0x398a, 0x3010, 0x3a7e, 0x3658, 0x38e4, 0x3030, 0x3608, 0x3860, 0x3af4, 0x3718, 0x29a0, 0x3b2c, 0x2eb0, 0x3424, - 0x3a0e, 0x3820, 0x32f8, 0x3954, 0x3afc, 0x38c0, 0x36a4, 0x3370, 0x2e70, 0x38b2, 0x3180, 0x3ba8, 0x2c80, 0x3778, 0x390c, 0x2cf0, - 0x35c0, 0x32e0, 0x36f4, 0x3b94, 0x3454, 0x39f4, 0x3348, 0x397e, 0x3b4e, 0x0000, 0x38fc, 0x34dc, 0x3a2a, 0x36a8, 0x393a, 0x3b54, -}; +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "Dither.h" + +// Dither matrix in 16-bit floating point format +const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE] = { + 0x2c90, 0x38f4, 0x3bba, 0x29e0, 0x35f4, 0x3230, 0x3bbc, 0x3924, 0x3a46, 0x3644, 0x39e2, 0x370c, 0x3444, 0x3b1a, 0x3140, 0x39d2, + 0x385a, 0x3b24, 0x2c10, 0x38c6, 0x3808, 0x2780, 0x3bbe, 0x37f8, 0x350c, 0x3a6c, 0x3368, 0x3bc0, 0x3000, 0x3886, 0x31b0, 0x3554, + 0x3a94, 0x3618, 0x3430, 0x3a34, 0x3834, 0x39fe, 0x2740, 0x3758, 0x3494, 0x3b7a, 0x2700, 0x3958, 0x3858, 0x3a24, 0x364c, 0x3bc2, + 0x3278, 0x3a22, 0x353c, 0x39de, 0x3268, 0x3a98, 0x36fc, 0x2ed0, 0x39e0, 0x30f0, 0x381a, 0x3996, 0x35ac, 0x3af2, 0x39b8, 0x37bc, + 0x3250, 0x39dc, 0x3800, 0x30e8, 0x3b42, 0x34d4, 0x3970, 0x3afe, 0x3020, 0x3898, 0x33e8, 0x3b34, 0x2e10, 0x3320, 0x391a, 0x26c0, + 0x3784, 0x38de, 0x3060, 0x3b5c, 0x3600, 0x38e6, 0x3490, 0x3b2a, 0x387a, 0x365c, 0x3b3c, 0x2be0, 0x37ac, 0x33d8, 0x2680, 0x3b98, + 0x38d6, 0x2a60, 0x3b7e, 0x391e, 0x36d0, 0x2fe0, 0x3812, 0x32a0, 0x3a84, 0x36b0, 0x3a50, 0x357c, 0x37dc, 0x3b68, 0x3594, 0x3aca, + 0x344c, 0x3a7c, 0x3674, 0x3884, 0x2d30, 0x3a48, 0x3170, 0x398e, 0x2900, 0x3a30, 0x34bc, 0x38ea, 0x3b70, 0x3a3c, 0x3852, 0x3460, + 0x3b04, 0x37a0, 0x351c, 0x2d40, 0x3a80, 0x394e, 0x3b84, 0x3614, 0x3900, 0x2b20, 0x396c, 0x31b8, 0x38ca, 0x3a0c, 0x3038, 0x385c, + 0x39a2, 0x2c70, 0x3ba2, 0x3464, 0x3992, 0x36dc, 0x3bc4, 0x3580, 0x3824, 0x32d0, 0x3abc, 0x2ec0, 0x3560, 0x30f8, 0x3974, 0x3610, + 0x3a12, 0x3110, 0x3aaa, 0x38a2, 0x35e4, 0x341c, 0x28c0, 0x3a02, 0x34a8, 0x3b60, 0x3790, 0x3aa2, 0x2c40, 0x346c, 0x373c, 0x3bc6, + 0x32f0, 0x37e8, 0x391c, 0x3100, 0x3af6, 0x2640, 0x3868, 0x3098, 0x3b3e, 0x3944, 0x3620, 0x3870, 0x39da, 0x374c, 0x3bc8, 0x2e20, + 0x3804, 0x3932, 0x3660, 0x3260, 0x3bca, 0x38ce, 0x3ade, 0x382e, 0x30a0, 0x389e, 0x33a0, 0x363c, 0x3b86, 0x3910, 0x3a58, 0x2820, + 0x36a0, 0x3b28, 0x34e0, 0x3a40, 0x3768, 0x3510, 0x3a54, 0x390e, 0x36e8, 0x2ae0, 0x3bcc, 0x31a0, 0x3aa4, 0x2600, 0x38cc, 0x3400, + 0x3ac4, 0x2800, 0x3b4a, 0x39ee, 0x2cc0, 0x3764, 0x31c8, 0x35cc, 0x3bb6, 0x39a8, 0x2f30, 0x3a1e, 0x3816, 0x3160, 0x35b0, 0x389a, + 0x3a86, 0x3070, 0x3848, 0x2d70, 0x38ba, 0x3baa, 0x2e60, 0x3414, 0x3ae4, 0x3544, 0x3a06, 0x37fc, 0x347c, 0x36d8, 0x3b12, 0x35a4, + 0x3248, 0x3866, 0x34f8, 0x3814, 0x33f8, 0x39c2, 0x3a8a, 0x38e2, 0x25c0, 0x3720, 0x3b26, 0x3508, 0x2980, 0x39b4, 0x3b4c, 0x33a8, + 0x3976, 0x3534, 0x39c4, 0x3b40, 0x3604, 0x31c0, 0x397c, 0x37b0, 0x39d0, 0x3218, 0x38d8, 0x2e30, 0x3b52, 0x39bc, 0x2fa0, 0x3980, + 0x3b9a, 0x39d4, 0x2f40, 0x3960, 0x3b64, 0x3680, 0x2f60, 0x34c8, 0x3acc, 0x3228, 0x3850, 0x395c, 0x3bce, 0x354c, 0x3840, 0x2db0, + 0x37a4, 0x3bd0, 0x2580, 0x33c8, 0x392a, 0x3a82, 0x3530, 0x3b48, 0x2540, 0x3760, 0x3a42, 0x35dc, 0x3890, 0x3308, 0x3844, 0x3710, + 0x3418, 0x366c, 0x3a9a, 0x3590, 0x2500, 0x3888, 0x3bd2, 0x3984, 0x3668, 0x39e4, 0x345c, 0x2d20, 0x371c, 0x3288, 0x3aae, 0x39d6, + 0x31e0, 0x38c8, 0x36e4, 0x3ab2, 0x380c, 0x2b00, 0x389c, 0x3280, 0x392c, 0x3bd4, 0x33b8, 0x3ad6, 0x24c0, 0x3bd6, 0x3a32, 0x2c60, + 0x3b1c, 0x38aa, 0x3238, 0x3902, 0x3ae8, 0x3528, 0x3118, 0x3818, 0x2c50, 0x3ba0, 0x38bc, 0x3ad8, 0x3a20, 0x38f0, 0x2480, 0x36b4, + 0x3b02, 0x34b0, 0x3a00, 0x30a8, 0x3518, 0x3bd8, 0x3688, 0x3a92, 0x34b4, 0x36c0, 0x2f70, 0x3968, 0x3798, 0x3448, 0x35ec, 0x3930, + 0x3750, 0x2a40, 0x3bda, 0x3728, 0x32e8, 0x3a4a, 0x38d2, 0x3b38, 0x33d0, 0x3738, 0x30b8, 0x3628, 0x340c, 0x37d4, 0x3bb2, 0x3428, + 0x3934, 0x2b40, 0x3856, 0x3b0e, 0x3964, 0x31d0, 0x39b0, 0x2e80, 0x38d4, 0x3b1e, 0x3a28, 0x387e, 0x30e0, 0x39a0, 0x3ae2, 0x3208, + 0x3a56, 0x352c, 0x3a14, 0x2d90, 0x3978, 0x3794, 0x2960, 0x35e0, 0x39c6, 0x3a88, 0x3862, 0x3b76, 0x2e40, 0x3988, 0x3128, 0x3a4c, + 0x378c, 0x3b8e, 0x359c, 0x2ea0, 0x36ac, 0x383e, 0x3af8, 0x3404, 0x3780, 0x2a20, 0x3360, 0x3598, 0x3b90, 0x37d0, 0x2dd0, 0x3880, + 0x3358, 0x3946, 0x381c, 0x348c, 0x3b50, 0x3198, 0x3ad4, 0x3940, 0x3050, 0x3540, 0x2440, 0x39cc, 0x3770, 0x3b0a, 0x35d8, 0x386c, + 0x2f00, 0x3380, 0x3a5a, 0x3948, 0x3ba4, 0x2400, 0x35a0, 0x393e, 0x3ba6, 0x39ea, 0x3838, 0x3ab0, 0x27c0, 0x3a38, 0x3538, 0x3bb4, + 0x2380, 0x3b62, 0x30d8, 0x3a62, 0x360c, 0x388c, 0x342c, 0x37e0, 0x3bdc, 0x38f2, 0x3ad0, 0x3488, 0x3168, 0x38da, 0x2300, 0x39ca, + 0x3aee, 0x3630, 0x387c, 0x31a8, 0x34e4, 0x38b8, 0x3a3e, 0x2dc0, 0x3640, 0x3130, 0x34ec, 0x3972, 0x36ec, 0x3318, 0x3950, 0x3714, + 0x3914, 0x356c, 0x38b6, 0x376c, 0x2280, 0x3b9c, 0x39c8, 0x2d50, 0x35e8, 0x32c0, 0x3704, 0x388a, 0x3a64, 0x3558, 0x3bde, 0x3440, + 0x3724, 0x3982, 0x28e0, 0x3ada, 0x375c, 0x3b30, 0x3300, 0x384a, 0x3a74, 0x38e8, 0x3b66, 0x2ee0, 0x385e, 0x3b46, 0x2f90, 0x3ab8, + 0x3178, 0x3a52, 0x2e00, 0x3b08, 0x3918, 0x3150, 0x3678, 0x3aa6, 0x3922, 0x3b14, 0x2fd0, 0x3b8a, 0x2ce0, 0x39a4, 0x379c, 0x2fb0, + 0x3b5a, 0x3240, 0x3a2e, 0x3390, 0x3916, 0x2e90, 0x36c4, 0x3be0, 0x349c, 0x2200, 0x3694, 0x39b2, 0x3478, 0x39f0, 0x35c4, 0x3828, + 0x3be2, 0x36d4, 0x3994, 0x3548, 0x3328, 0x3a04, 0x3854, 0x3498, 0x28a0, 0x3810, 0x39fc, 0x3520, 0x3846, 0x32d8, 0x3ab4, 0x393c, + 0x3864, 0x35b4, 0x380e, 0x3be4, 0x3570, 0x3a96, 0x39ac, 0x3090, 0x3962, 0x37c0, 0x3a9e, 0x3120, 0x3be6, 0x2a00, 0x38f6, 0x3410, + 0x2180, 0x386e, 0x3088, 0x3b82, 0x37a8, 0x3ae6, 0x2f10, 0x3be8, 0x399a, 0x3634, 0x31e8, 0x3912, 0x3b06, 0x36f0, 0x2c30, 0x3504, + 0x3a76, 0x2aa0, 0x39e8, 0x3040, 0x3878, 0x2880, 0x383a, 0x35f8, 0x3aec, 0x32a8, 0x3936, 0x3550, 0x3892, 0x3740, 0x3aea, 0x398c, + 0x3a72, 0x34c4, 0x3a1c, 0x38ac, 0x2860, 0x3584, 0x38fa, 0x372c, 0x3388, 0x3a3a, 0x3b9e, 0x2100, 0x3420, 0x395a, 0x3bae, 0x37d8, + 0x3398, 0x3b6c, 0x3734, 0x34d0, 0x39c0, 0x3b78, 0x3474, 0x3a2c, 0x2b80, 0x3830, 0x3b56, 0x2cb0, 0x3a78, 0x33b0, 0x3018, 0x3650, + 0x30d0, 0x3b20, 0x3690, 0x3350, 0x39ae, 0x3a90, 0x3148, 0x3b44, 0x2cd0, 0x38a0, 0x355c, 0x382a, 0x3a8e, 0x35b8, 0x3190, 0x39ec, + 0x38c4, 0x3068, 0x3938, 0x3b2e, 0x32c8, 0x3748, 0x3008, 0x3894, 0x3bb8, 0x3438, 0x36c8, 0x3904, 0x35fc, 0x396e, 0x3bac, 0x38a6, + 0x397a, 0x37ec, 0x2ca0, 0x3bea, 0x3754, 0x34a4, 0x3836, 0x3956, 0x362c, 0x3b00, 0x30c0, 0x39a6, 0x2fc0, 0x38ae, 0x3abe, 0x2080, + 0x3684, 0x3a70, 0x3568, 0x2000, 0x38c2, 0x3af0, 0x3998, 0x368c, 0x30b0, 0x39ba, 0x3aa8, 0x3200, 0x3b16, 0x2d80, 0x377c, 0x3480, + 0x3b6e, 0x3270, 0x39fa, 0x386a, 0x2ff0, 0x3b10, 0x1f00, 0x3a44, 0x343c, 0x3802, 0x3a66, 0x34b8, 0x3bec, 0x3708, 0x3340, 0x3882, + 0x3bee, 0x3298, 0x3806, 0x3a08, 0x3638, 0x2d00, 0x34ac, 0x3a60, 0x38ee, 0x35c8, 0x29c0, 0x380a, 0x34f0, 0x38f8, 0x3aac, 0x1e00, + 0x3564, 0x38fe, 0x3468, 0x3ace, 0x35d0, 0x394a, 0x37b4, 0x31f8, 0x3bf0, 0x2bc0, 0x38d0, 0x36b8, 0x2940, 0x3926, 0x3b32, 0x35a8, + 0x2d60, 0x38e0, 0x3b58, 0x3078, 0x3a9c, 0x37e4, 0x3bf2, 0x2e50, 0x33f0, 0x3b72, 0x38b4, 0x39e6, 0x3bf4, 0x3290, 0x3670, 0x3a1a, + 0x3842, 0x3a68, 0x2920, 0x37c4, 0x32b8, 0x3b88, 0x34c0, 0x396a, 0x3664, 0x39b6, 0x3330, 0x3b5e, 0x39ce, 0x3484, 0x3080, 0x39aa, + 0x3a4e, 0x3700, 0x34e8, 0x395e, 0x3310, 0x3908, 0x3588, 0x384e, 0x3ac6, 0x3730, 0x3220, 0x3574, 0x2de0, 0x37f0, 0x399c, 0x2ef0, + 0x3188, 0x369c, 0x3bf6, 0x390a, 0x39f2, 0x2b60, 0x3872, 0x3aa0, 0x2df0, 0x3b0c, 0x37cc, 0x2da0, 0x382c, 0x3ae0, 0x38b0, 0x3788, + 0x33c0, 0x3afa, 0x2ba0, 0x3826, 0x3b6a, 0x1d00, 0x39f8, 0x3108, 0x3920, 0x1c00, 0x3a26, 0x3b22, 0x38ec, 0x3ac2, 0x3458, 0x3b7c, + 0x3a8c, 0x38a8, 0x34d8, 0x3048, 0x3654, 0x3adc, 0x3138, 0x3744, 0x3450, 0x38be, 0x34f4, 0x3a10, 0x3210, 0x35bc, 0x2840, 0x3b92, + 0x3058, 0x3986, 0x3698, 0x39d8, 0x3434, 0x36f8, 0x3b18, 0x3524, 0x3a7a, 0x35d4, 0x3822, 0x3408, 0x36bc, 0x2ac0, 0x3896, 0x3624, + 0x1a00, 0x3378, 0x3a16, 0x3b3a, 0x381e, 0x3338, 0x3906, 0x39f6, 0x3bf8, 0x3158, 0x3ad2, 0x36e0, 0x3bfa, 0x392e, 0x3a5c, 0x3648, + 0x38dc, 0x34cc, 0x3bfc, 0x30c8, 0x3ab6, 0x3942, 0x32b0, 0x38a4, 0x2d10, 0x3b96, 0x394c, 0x2f80, 0x3bfe, 0x3966, 0x3258, 0x39be, + 0x3bb0, 0x3928, 0x361c, 0x2c00, 0x3990, 0x3b8c, 0x3578, 0x2a80, 0x36cc, 0x3952, 0x1800, 0x388e, 0x33e0, 0x2f20, 0x384c, 0x31d8, + 0x3a18, 0x1400, 0x3876, 0x358c, 0x383c, 0x2c20, 0x3b80, 0x3774, 0x3a36, 0x3470, 0x31f0, 0x3a0a, 0x3832, 0x3514, 0x3a6a, 0x37f4, + 0x367c, 0x3028, 0x3ac8, 0x37b8, 0x34a0, 0x2f50, 0x3a5e, 0x3874, 0x3b36, 0x34fc, 0x3a6e, 0x35f0, 0x399e, 0x3aba, 0x3500, 0x3b74, + 0x37c8, 0x3ac0, 0x398a, 0x3010, 0x3a7e, 0x3658, 0x38e4, 0x3030, 0x3608, 0x3860, 0x3af4, 0x3718, 0x29a0, 0x3b2c, 0x2eb0, 0x3424, + 0x3a0e, 0x3820, 0x32f8, 0x3954, 0x3afc, 0x38c0, 0x36a4, 0x3370, 0x2e70, 0x38b2, 0x3180, 0x3ba8, 0x2c80, 0x3778, 0x390c, 0x2cf0, + 0x35c0, 0x32e0, 0x36f4, 0x3b94, 0x3454, 0x39f4, 0x3348, 0x397e, 0x3b4e, 0x0000, 0x38fc, 0x34dc, 0x3a2a, 0x36a8, 0x393a, 0x3b54, +}; diff --git a/src/filters/renderer/VideoRenderers/Dither.h b/src/filters/renderer/VideoRenderers/Dither.h index e6c961fff2f..8cfef960f21 100644 --- a/src/filters/renderer/VideoRenderers/Dither.h +++ b/src/filters/renderer/VideoRenderers/Dither.h @@ -1,24 +1,24 @@ -/* - * (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 . - * - */ - -#pragma once - -const int DITHER_MATRIX_SIZE = 32; -extern const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE]; +/* + * (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 . + * + */ + +#pragma once + +const int DITHER_MATRIX_SIZE = 32; +extern const unsigned short DITHER_MATRIX[DITHER_MATRIX_SIZE][DITHER_MATRIX_SIZE]; diff --git a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp index 7789bd8ba26..0df67bd07b9 100644 --- a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp @@ -1,2996 +1,2996 @@ -/* - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "EVRAllocatorPresenter.h" -#include "OuterEVR.h" -#include -#include "IPinHook.h" -#include "MacrovisionKicker.h" -#include "IMPCVideoDecFilter.h" -#include "Utils.h" -#include "Variables.h" - -#if (0) // Set to 1 to activate EVR traces -#define TRACE_EVR TRACE -#else -#define TRACE_EVR __noop -#endif - -#define MIN_FRAME_TIME 15000 - -enum EVR_STATS_MSG { - MSG_MIXERIN, - MSG_MIXEROUT -}; - -// Guid to tag IMFSample with a group id -static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } }; -// Guid to tag IMFSample with DirectX surface index -static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } }; - - -// === Helper functions -MFOffset MakeOffset(float v) -{ - MFOffset offset; - offset.value = short(v); - offset.fract = WORD(65536 * (v - offset.value)); - return offset; -} - -MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height) -{ - MFVideoArea area; - area.OffsetX = MakeOffset(x); - area.OffsetY = MakeOffset(y); - area.Area.cx = width; - area.Area.cy = height; - return area; -} - -using namespace DSObjects; - -CEVRAllocatorPresenter::CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error, bool isPreview) - : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, true, _Error, isPreview) - , m_ModeratedTime(0) - , m_ModeratedTimeLast(-1) - , m_ModeratedClockLast(-1) - , m_ModeratedTimer(0) - , m_LastClockState(MFCLOCK_STATE_INVALID) - , m_pOuterEVR(nullptr) - , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture) - , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0) - , m_BorderColor(RGB(0, 0, 0)) - , m_hEvtQuit(nullptr) - , m_bEvtQuit(0) - , m_hEvtFlush(nullptr) - , m_bEvtFlush(0) - , m_fUseInternalTimer(false) - , m_LastSetOutputRange(-1) - , m_bPendingRenegotiate(false) - , m_bPendingMediaFinished(false) - , m_hThread(nullptr) - , m_hGetMixerThread(nullptr) - , m_hVSyncThread(nullptr) - , m_nRenderState(Shutdown) - , m_nCurrentGroupId(0) - , m_bLastSampleOffsetValid(false) - , m_LastScheduledSampleTime(-1) - , m_LastScheduledSampleTimeFP(-1) - , m_LastScheduledUncorrectedSampleTime(-1) - , m_MaxSampleDuration(0) - , m_LastSampleOffset(0) - , m_LastPredictedSync(0) - , m_VSyncOffsetHistoryPos(0) - , m_nResetToken(0) - , m_nStepCount(0) - , m_bSignaledStarvation(false) - , m_StarvationClock(0) - , m_SampleFreeCallback(this, &CEVRAllocatorPresenter::OnSampleFree) - , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9") - , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer") - , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface") - , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType") - , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW") - , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority") - , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics") -{ - const CRenderersSettings& r = GetRenderersSettings(); - - ZeroMemory(m_VSyncOffsetHistory, sizeof(m_VSyncOffsetHistory)); - ResetStats(); - - if (FAILED(hr)) { - _Error += L"DX9AllocatorPresenter failed\n"; - return; - } - - if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) { - if (!fnDXVA2CreateDirect3DDeviceManager9) { - _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n"; - } - if (!fnMFCreateDXSurfaceBuffer) { - _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n"; - } - if (!fnMFCreateVideoSampleFromSurface) { - _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n"; - } - if (!fnMFCreateMediaType) { - _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n"; - } - hr = E_FAIL; - return; - } - - // Init DXVA manager - hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager); - if (SUCCEEDED(hr) && m_pD3DManager) { - hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); - if (FAILED(hr)) { - _Error += L"m_pD3DManager->ResetDevice failed\n"; - } - } else { - _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n"; - } - - - // Bufferize frame only with 3D texture! - if (!m_bIsPreview && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { - m_nNbDXSurface = std::max(std::min(r.iEvrBuffers, MAX_VIDEO_SURFACES), 4); - } else { - m_nNbDXSurface = 1; - } -} - -CEVRAllocatorPresenter::~CEVRAllocatorPresenter() -{ - StopWorkerThreads(); // If not already done... - m_pMediaType = nullptr; - m_pClock = nullptr; - m_pD3DManager = nullptr; - - if (m_bHookedNewSegment) { - UnhookNewSegment(); - } -} - -void CEVRAllocatorPresenter::ResetStats() -{ - m_pcFrames = 0; - m_nDroppedUpdate = 0; - m_pcFramesDrawn = 0; - m_piAvg = 0; - m_piDev = 0; -} - -HRESULT CEVRAllocatorPresenter::CheckShutdown() const -{ - if (m_nRenderState == Shutdown) { - return MF_E_SHUTDOWN; - } else { - return S_OK; - } -} - -void CEVRAllocatorPresenter::StartWorkerThreads() -{ - DWORD dwThreadId; - - if (m_nRenderState == Shutdown) { - m_hEvtQuit = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hEvtFlush = CreateEvent(nullptr, TRUE, FALSE, nullptr); - - m_hThread = ::CreateThread(nullptr, 0, PresentThread, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL); - m_hGetMixerThread = ::CreateThread(nullptr, 0, GetMixerThreadStatic, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hGetMixerThread, THREAD_PRIORITY_HIGHEST); - m_hVSyncThread = ::CreateThread(nullptr, 0, VSyncThreadStatic, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hVSyncThread, THREAD_PRIORITY_HIGHEST); - - m_nRenderState = Stopped; - TRACE_EVR("EVR: Worker threads started...\n"); - } -} - -void CEVRAllocatorPresenter::StopWorkerThreads() -{ - if (m_nRenderState != Shutdown) { - SetEvent(m_hEvtFlush); - m_bEvtFlush = true; - SetEvent(m_hEvtQuit); - m_bEvtQuit = true; - if (m_hThread && WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hThread, 0xDEAD); - } - if (m_hGetMixerThread && WaitForSingleObject(m_hGetMixerThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hGetMixerThread, 0xDEAD); - } - if (m_hVSyncThread && WaitForSingleObject(m_hVSyncThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hVSyncThread, 0xDEAD); - } - - SAFE_CLOSE_HANDLE(m_hThread); - SAFE_CLOSE_HANDLE(m_hGetMixerThread); - SAFE_CLOSE_HANDLE(m_hVSyncThread); - SAFE_CLOSE_HANDLE(m_hEvtFlush); - SAFE_CLOSE_HANDLE(m_hEvtQuit); - - m_bEvtFlush = false; - m_bEvtQuit = false; - - TRACE_EVR("EVR: Worker threads stopped...\n"); - } - m_nRenderState = Shutdown; -} - -STDMETHODIMP CEVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - - *ppRenderer = nullptr; - HRESULT hr = S_OK; - - CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; - - COuterEVR* pOuterEVR = DEBUG_NEW COuterEVR(NAME("COuterEVR"), pUnk, hr, &m_VMR9AlphaBitmap, this); - m_pOuterEVR = pOuterEVR; - - pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR); - CComQIPtr pBF = pUnk; - - if (FAILED(hr)) { - return E_FAIL; - } - - // Set EVR custom presenter - CComPtr pVP; - CComPtr pMFVR; - CComQIPtr pMFGS = pBF; - CComQIPtr pConfig = pBF; - if (SUCCEEDED(hr)) { - if (FAILED(pConfig->SetNumberOfStreams(m_bIsPreview?1:3))) { // TODO - maybe need other number of input stream ... - return E_FAIL; - } - } - - hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVR)); - - if (SUCCEEDED(hr)) { - hr = QueryInterface(IID_PPV_ARGS(&pVP)); - } - if (SUCCEEDED(hr)) { - hr = pMFVR->InitializeRenderer(nullptr, pVP); - } - - if (SUCCEEDED(hr)) { - if (!m_bIsPreview) { - CComPtr pPin = GetFirstPin(pBF); - if (HookNewSegment((IPinC*)(IPin*)pPin)) { - m_fUseInternalTimer = true; - m_bHookedNewSegment = true; - }; - } - *ppRenderer = pBF.Detach(); - } else { - *ppRenderer = nullptr; - } - - return hr; -} - -STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(bool bAll) -{ - return __super::Paint(bAll); -} - -STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(IMFSample* pMFSample) -{ - CAutoLock lock(&m_RenderLock); - - m_pCurrentlyDisplayedSample = pMFSample; - pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface); - - auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { - UINT32 nGroupId; - return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); - }; - ASSERT(sampleHasCurrentGroupId(pMFSample)); - - return Paint(true); -} - -STDMETHODIMP CEVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - HRESULT hr; - if (riid == __uuidof(IMFClockStateSink)) { - hr = GetInterface((IMFClockStateSink*)this, ppv); - } else if (riid == __uuidof(IMFVideoPresenter)) { - hr = GetInterface((IMFVideoPresenter*)this, ppv); - } else if (riid == __uuidof(IMFTopologyServiceLookupClient)) { - hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv); - } else if (riid == __uuidof(IMFVideoDeviceID)) { - hr = GetInterface((IMFVideoDeviceID*)this, ppv); - } else if (riid == __uuidof(IMFGetService)) { - hr = GetInterface((IMFGetService*)this, ppv); - } else if (riid == __uuidof(IMFAsyncCallback)) { - hr = GetInterface((IMFAsyncCallback*)this, ppv); - } else if (riid == __uuidof(IMFVideoDisplayControl)) { - hr = GetInterface((IMFVideoDisplayControl*)this, ppv); - } else if (riid == __uuidof(IMFVideoMixerBitmap)) { - hr = GetInterface((IMFVideoMixerBitmap*)this, ppv); - } else if (riid == __uuidof(IEVRTrustedVideoPlugin)) { - hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv); - } else if (riid == IID_IQualProp) { - hr = GetInterface((IQualProp*)this, ppv); - } else if (riid == __uuidof(IMFRateSupport)) { - hr = GetInterface((IMFRateSupport*)this, ppv); - } else if (riid == __uuidof(IDirect3DDeviceManager9)) - // hr = GetInterface((IDirect3DDeviceManager9*)this, ppv); - { - hr = m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppv); - } else if (riid == __uuidof(ID3DFullscreenControl)) { - hr = GetInterface((ID3DFullscreenControl*)this, ppv); - } else { - hr = __super::NonDelegatingQueryInterface(riid, ppv); - } - - return hr; -} - -// IMFClockStateSink -STDMETHODIMP CEVRAllocatorPresenter::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - - m_nRenderState = Started; - - TRACE_EVR("EVR: OnClockStart hnsSystemTime = %I64d, llClockStartOffset = %I64d\n", hnsSystemTime, llClockStartOffset); - m_ModeratedTimeLast = -1; - m_ModeratedClockLast = -1; - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::OnClockStop(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - - TRACE_EVR("EVR: OnClockStop hnsSystemTime = %I64d\n", hnsSystemTime); - m_nRenderState = Stopped; - - m_ModeratedClockLast = -1; - m_ModeratedTimeLast = -1; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::OnClockPause(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - - TRACE_EVR("EVR: OnClockPause hnsSystemTime = %I64d\n", hnsSystemTime); - if (!m_bSignaledStarvation) { - m_nRenderState = Paused; - } - m_ModeratedTimeLast = -1; - m_ModeratedClockLast = -1; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::OnClockRestart(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - - m_nRenderState = Started; - - m_ModeratedTimeLast = -1; - m_ModeratedClockLast = -1; - TRACE_EVR("EVR: OnClockRestart hnsSystemTime = %I64d\n", hnsSystemTime); - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::OnClockSetRate(MFTIME hnsSystemTime, float flRate) -{ - ASSERT(FALSE); - return E_NOTIMPL; -} - -// IBaseFilter delegate -bool CEVRAllocatorPresenter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue) -{ - CAutoLock lock(&m_SampleQueueLock); - - if (m_bSignaledStarvation) { - size_t nSamples = std::max(m_nNbDXSurface / 2, 1); - if ((m_ScheduledSamples.GetCount() < nSamples || m_LastSampleOffset < -m_rtTimePerFrame * 2) && !g_bNoDuration) { - *State = (FILTER_STATE)Paused; - _ReturnValue = VFW_S_STATE_INTERMEDIATE; - return true; - } - m_bSignaledStarvation = false; - } - return false; -} - -// IQualProp -STDMETHODIMP CEVRAllocatorPresenter::get_FramesDroppedInRenderer(int* pcFrames) -{ - *pcFrames = m_pcFrames; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_FramesDrawn(int* pcFramesDrawn) -{ - *pcFramesDrawn = m_pcFramesDrawn; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_AvgFrameRate(int* piAvgFrameRate) -{ - *piAvgFrameRate = (int)(m_fAvrFps * 100); - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_Jitter(int* iJitter) -{ - *iJitter = (int)((m_fJitterStdDev / 10000.0) + 0.5); - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_AvgSyncOffset(int* piAvg) -{ - *piAvg = (int)((m_fSyncOffsetAvr / 10000.0) + 0.5); - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::get_DevSyncOffset(int* piDev) -{ - *piDev = (int)((m_fSyncOffsetStdDev / 10000.0) + 0.5); - return S_OK; -} - -// IMFRateSupport - -STDMETHODIMP CEVRAllocatorPresenter::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) -{ - // TODO : not finished... - *pflRate = 0; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) -{ - HRESULT hr = S_OK; - float fMaxRate = 0.0f; - - CAutoLock lock(this); - - CheckPointer(pflRate, E_POINTER); - CHECK_HR(CheckShutdown()); - - // Get the maximum forward rate. - fMaxRate = GetMaxRate(fThin); - - // For reverse playback, swap the sign. - if (eDirection == MFRATE_REVERSE) { - fMaxRate = -fMaxRate; - } - - *pflRate = fMaxRate; - - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate) -{ - // fRate can be negative for reverse playback. - // pfNearestSupportedRate can be NULL. - - CAutoLock lock(this); - - HRESULT hr = S_OK; - float fMaxRate = 0.0f; - float fNearestRate = flRate; // Default. - - CheckPointer(pflNearestSupportedRate, E_POINTER); - CHECK_HR(CheckShutdown()); - - // Find the maximum forward rate. - fMaxRate = GetMaxRate(fThin); - - if (fabsf(flRate) > fMaxRate) { - // The (absolute) requested rate exceeds the maximum rate. - hr = MF_E_UNSUPPORTED_RATE; - - // The nearest supported rate is fMaxRate. - fNearestRate = fMaxRate; - if (flRate < 0) { - // For reverse playback, swap the sign. - fNearestRate = -fNearestRate; - } - } - - // Return the nearest supported rate if the caller requested it. - if (pflNearestSupportedRate != nullptr) { - *pflNearestSupportedRate = fNearestRate; - } - - return hr; -} - -float CEVRAllocatorPresenter::GetMaxRate(BOOL bThin) -{ - float fMaxRate = FLT_MAX; // Default. - UINT32 fpsNumerator = 0, fpsDenominator = 0; - - if (!bThin && (m_pMediaType != nullptr)) { - // Non-thinned: Use the frame rate and monitor refresh rate. - - // Frame rate: - MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE, - &fpsNumerator, &fpsDenominator); - - // Monitor refresh rate: - UINT MonitorRateHz = m_refreshRate; // D3DDISPLAYMODE - - if (fpsDenominator && fpsNumerator && MonitorRateHz) { - // Max Rate = Refresh Rate / Frame Rate - fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator); - } - } - return fMaxRate; -} - -void CEVRAllocatorPresenter::CompleteFrameStep(bool bCancel) -{ - if (m_nStepCount > 0) { - if (bCancel || (m_nStepCount == 1)) { - m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0); - m_nStepCount = 0; - } else { - m_nStepCount--; - } - } -} - -// IMFVideoPresenter -STDMETHODIMP CEVRAllocatorPresenter::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) -{ - HRESULT hr = S_OK; - CHECK_HR(CheckShutdown()); - - switch (eMessage) { - case MFVP_MESSAGE_BEGINSTREAMING: // The EVR switched from stopped to paused. The presenter should allocate resources - m_nRenderState = Paused; - ResetStats(); - TRACE_EVR("EVR: MFVP_MESSAGE_BEGINSTREAMING\n"); - break; - - case MFVP_MESSAGE_CANCELSTEP: // Cancels a frame step - TRACE_EVR("EVR: MFVP_MESSAGE_CANCELSTEP\n"); - CompleteFrameStep(true); - break; - - case MFVP_MESSAGE_ENDOFSTREAM: // All input streams have ended. - TRACE_EVR("EVR: MFVP_MESSAGE_ENDOFSTREAM\n"); - m_bPendingMediaFinished = true; - break; - - case MFVP_MESSAGE_ENDSTREAMING: // The EVR switched from running or paused to stopped. The presenter should free resources - m_nRenderState = Stopped; - TRACE_EVR("EVR: MFVP_MESSAGE_ENDSTREAMING\n"); - break; - - case MFVP_MESSAGE_FLUSH: // The presenter should discard any pending samples - SetEvent(m_hEvtFlush); - m_bEvtFlush = true; - TRACE_EVR("EVR: MFVP_MESSAGE_FLUSH\n"); - while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0) { - ; - } - break; - - case MFVP_MESSAGE_INVALIDATEMEDIATYPE: // The mixer's output format has changed. The EVR will initiate format negotiation, as described previously - /* - 1) The EVR sets the media type on the reference stream. - 2) The EVR calls IMFVideoPresenter::ProcessMessage on the presenter with the MFVP_MESSAGE_INVALIDATEMEDIATYPE message. - 3) The presenter sets the media type on the mixer's output stream. - 4) The EVR sets the media type on the substreams. - */ - m_bPendingRenegotiate = true; - while (m_bPendingRenegotiate) { - Sleep(1); - } - break; - - case MFVP_MESSAGE_PROCESSINPUTNOTIFY: // One input stream on the mixer has received a new sample - // GetImageFromMixer(); - break; - - case MFVP_MESSAGE_STEP: // Requests a frame step. - TRACE_EVR("EVR: MFVP_MESSAGE_STEP\n"); - m_nStepCount = (int)ulParam; - hr = S_OK; - break; - - default: - ASSERT(FALSE); - break; - } - return hr; -} - -HRESULT CEVRAllocatorPresenter::IsMediaTypeSupported(IMFMediaType* pMixerType) -{ - HRESULT hr; - - // We support only video types - GUID MajorType; - hr = pMixerType->GetMajorType(&MajorType); - - if (SUCCEEDED(hr)) { - if (MajorType != MFMediaType_Video) { - hr = MF_E_INVALIDMEDIATYPE; - } - } - - // We support only progressive formats - MFVideoInterlaceMode InterlaceMode = MFVideoInterlace_Unknown; - - if (SUCCEEDED(hr)) { - hr = pMixerType->GetUINT32(MF_MT_INTERLACE_MODE, (UINT32*)&InterlaceMode); - } - - if (SUCCEEDED(hr)) { - if (InterlaceMode != MFVideoInterlace_Progressive) { - hr = MF_E_INVALIDMEDIATYPE; - } - } - - // Check whether we support the surface format - int Merit = 0; - - if (SUCCEEDED(hr)) { - hr = GetMediaTypeMerit(pMixerType, &Merit); - } - - if (SUCCEEDED(hr)) { - if (Merit == 0) { - hr = MF_E_INVALIDMEDIATYPE; - } - } - - return hr; -} - -HRESULT CEVRAllocatorPresenter::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType) -{ - HRESULT hr; - IMFMediaType* pOptimalMediaType; - - CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType)); - CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType)); - - const GUID colorAttributes[] = { - MF_MT_VIDEO_LIGHTING, - MF_MT_VIDEO_PRIMARIES, - MF_MT_TRANSFER_FUNCTION, - MF_MT_YUV_MATRIX, - MF_MT_VIDEO_CHROMA_SITING - }; - - auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) { - PROPVARIANT val; - HRESULT hr = pFrom->GetItem(guidKey, &val); - - if (SUCCEEDED(hr)) { - hr = pTo->SetItem(guidKey, val); - PropVariantClear(&val); - } else if (hr == MF_E_ATTRIBUTENOTFOUND) { - hr = pTo->DeleteItem(guidKey); - } - return hr; - }; - - for (REFGUID guidKey : colorAttributes) { - if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) { - TRACE_EVR(_T("Copying color attribute %s failed: 0x%08x\n"), CComBSTR(guidKey), hr); - } - } - - pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0); - - const CRenderersSettings& r = GetRenderersSettings(); - - UINT32 nominalRange; - if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)) - && nominalRange == MFNominalRange_0_255) { - // EVR mixer always assumes 16-235 input. Bug? - // To keep untouched 0-255 range and avoid unwanted expansion we need to request 16-235 as output. - // To get 16-235 output we need to request 48-208 as output. - nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_48_208 : MFNominalRange_16_235; - } else { - nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255; - } - pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange); - m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange; - - ULARGE_INTEGER ui64Size; - pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart); - - CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart); - MFVideoArea Area = MakeArea(0, 0, videoSize.cx, videoSize.cy); - pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea)); - - ULARGE_INTEGER ui64AspectRatio; - pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart); - - UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart; - UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart; - UINT64 gcd = GCD(ui64ARx, ui64ARy); - if (gcd > 1) { - ui64ARx /= gcd; - ui64ARy /= gcd; - } - - CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy); - if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) { - SetVideoSize(videoSize, aspectRatio); - - // Notify the graph about the change - if (m_pSink) { - m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_nativeVideoSize.cx, m_nativeVideoSize.cy), 0); - } - } - - *ppType = pOptimalMediaType; - (*ppType)->AddRef(); - - return hr; -} - -HRESULT CEVRAllocatorPresenter::SetMediaType(IMFMediaType* pType) -{ - HRESULT hr = S_OK; - AM_MEDIA_TYPE* pAMMedia = nullptr; - - CHECK_HR(CheckShutdown()); - - if (!pType) { - // Release - RemoveAllSamples(); - DeleteSurfaces(); - CAutoLock lock(&m_MediaTypeLock); - m_pMediaType = nullptr; - return hr; - } - - DWORD dwFlags = 0; - if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) { - // Nothing to do - return hr; - } - - CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); - - hr = InitializeDevice(pType); - if (SUCCEEDED(hr)) { - CAutoLock lock(&m_MediaTypeLock); - m_pMediaType = pType; - - CString strTemp = GetMediaTypeName(pAMMedia->subtype); - strTemp.Replace(L"MEDIASUBTYPE_", L""); - CString strTemp1 = GetMediaTypeFormatDesc(pType); - strTemp1.Replace(L"D3DFMT_", L""); - m_strStatsMsg[MSG_MIXEROUT].Format(L"Mixer output : %-10s Type %-10s", strTemp.GetString(), strTemp1.GetString()); - } - - pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); - - return hr; -} - -HRESULT CEVRAllocatorPresenter::GetMediaTypeFourCC(IMFMediaType* pType, DWORD* pFourCC) -{ - CheckPointer(pFourCC, E_POINTER); - - HRESULT hr = S_OK; - GUID guidSubType = GUID_NULL; - - if (SUCCEEDED(hr)) { - hr = pType->GetGUID(MF_MT_SUBTYPE, &guidSubType); - } - - if (SUCCEEDED(hr)) { - *pFourCC = guidSubType.Data1; - } - - return hr; -} - -HRESULT CEVRAllocatorPresenter::GetMediaTypeMerit(IMFMediaType* pType, int* pMerit) -{ - DWORD Format; - HRESULT hr = GetMediaTypeFourCC(pType, &Format); - - if (SUCCEEDED(hr)) { - switch (Format) { - case FCC('AI44'): // Palettized, 4:4:4 - *pMerit = 31; - break; - case FCC('YVU9'): // 8-bit, 16:1:1 - *pMerit = 30; - break; - case FCC('NV11'): // 8-bit, 4:1:1 - *pMerit = 29; - break; - case FCC('Y41P'): - *pMerit = 28; - break; - case FCC('Y41T'): - *pMerit = 27; - break; - case FCC('P016'): // 4:2:0 - *pMerit = 26; - break; - case FCC('P010'): - *pMerit = 25; - break; - case FCC('IMC1'): - *pMerit = 24; - break; - case FCC('IMC3'): - *pMerit = 23; - break; - case FCC('IMC2'): - *pMerit = 22; - break; - case FCC('IMC4'): - *pMerit = 21; - break; - case FCC('YV12'): - *pMerit = 20; - break; - case FCC('NV12'): - *pMerit = 19; - break; - case FCC('I420'): - *pMerit = 18; - break; - case FCC('IYUV'): - *pMerit = 17; - break; - case FCC('Y216'): // 4:2:2 - *pMerit = 16; - break; - case FCC('v216'): - *pMerit = 15; - break; - case FCC('P216'): - *pMerit = 14; - break; - case FCC('Y210'): - *pMerit = 13; - break; - case FCC('v210'): - *pMerit = 12; - break; - case FCC('P210'): - *pMerit = 11; - break; - case FCC('YUY2'): - *pMerit = 10; - break; - case FCC('UYVY'): - *pMerit = 9; - break; - case FCC('Y42T'): - *pMerit = 8; - break; - case FCC('YVYU'): - *pMerit = 7; - break; - case FCC('Y416'): // 4:4:4 - *pMerit = 6; - break; - case FCC('Y410'): - *pMerit = 5; - break; - case FCC('v410'): - *pMerit = 4; - break; - case FCC('AYUV'): - *pMerit = 3; - break; - case D3DFMT_X8R8G8B8: - if (m_bForceInputHighColorResolution) { - *pMerit = 63; - } else { - *pMerit = 1; - } - break; - case D3DFMT_A8R8G8B8: // an accepted format, but fails on most surface types - case D3DFMT_A8B8G8R8: - case D3DFMT_X8B8G8R8: - case D3DFMT_R8G8B8: - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: - case D3DFMT_A1R5G5B5: - case D3DFMT_A4R4G4B4: - case D3DFMT_R3G3B2: - case D3DFMT_A8R3G3B2: - case D3DFMT_X4R4G4B4: - case D3DFMT_A8P8: - case D3DFMT_P8: - *pMerit = 0; - break; - default: - *pMerit = 2; - break; - } - } - - return hr; -} - -LPCTSTR FindD3DFormat(const D3DFORMAT Format); - -LPCTSTR CEVRAllocatorPresenter::GetMediaTypeFormatDesc(IMFMediaType* pMediaType) -{ - D3DFORMAT Format = D3DFMT_UNKNOWN; - GetMediaTypeFourCC(pMediaType, (DWORD*)&Format); - return FindD3DFormat(Format); -} - -HRESULT CEVRAllocatorPresenter::RenegotiateMediaType() -{ - HRESULT hr = S_OK; - - CComPtr pMixerType; - CComPtr pMixerInputType; - CComPtr pType; - - if (!m_pMixer) { - return MF_E_INVALIDREQUEST; - } - - CInterfaceArray ValidMixerTypes; - - // Get the mixer's input type - hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType); - if (SUCCEEDED(hr)) { - AM_MEDIA_TYPE* pMT; - hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT); - if (SUCCEEDED(hr)) { - m_inputMediaType = *pMT; - pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT); - } - } - - // Loop through all of the mixer's proposed output types. - DWORD iTypeIndex = 0; - while ((hr != MF_E_NO_MORE_TYPES)) { - pMixerType = nullptr; - pType = nullptr; - - // Step 1. Get the next media type supported by mixer. - hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType); - if (FAILED(hr)) { - break; - } - - // Step 2. Check if we support this media type. - if (SUCCEEDED(hr)) { - hr = IsMediaTypeSupported(pMixerType); - } - - if (SUCCEEDED(hr)) { - hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType); - } - - // Step 4. Check if the mixer will accept this media type. - if (SUCCEEDED(hr)) { - hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY); - } - - int Merit = 0; - if (SUCCEEDED(hr)) { - hr = GetMediaTypeMerit(pType, &Merit); - } - - if (SUCCEEDED(hr)) { - size_t nTypes = ValidMixerTypes.GetCount(); - size_t iInsertPos = 0; - for (size_t i = 0; i < nTypes; ++i) { - int ThisMerit; - GetMediaTypeMerit(ValidMixerTypes[i], &ThisMerit); - - if (Merit > ThisMerit) { - iInsertPos = i; - break; - } else { - iInsertPos = i + 1; - } - } - - ValidMixerTypes.InsertAt(iInsertPos, pType); - } - } - - - size_t nValidTypes = ValidMixerTypes.GetCount(); -#ifdef _DEBUG - for (size_t i = 0; i < nValidTypes; ++i) { - // Step 3. Adjust the mixer's type to match our requirements. - pType = ValidMixerTypes[i]; - TRACE_EVR("EVR: Valid mixer output type: %ws\n", GetMediaTypeFormatDesc(pType)); - } -#endif - for (size_t i = 0; i < nValidTypes; ++i) { - // Step 4. Adjust the mixer's type to match our requirements. - pType = ValidMixerTypes[i]; - - TRACE_EVR("EVR: Trying mixer output type: %ws\n", GetMediaTypeFormatDesc(pType)); - - // Step 5. Try to set the media type on ourselves. - hr = SetMediaType(pType); - - // Step 6. Set output media type on mixer. - if (SUCCEEDED(hr)) { - hr = m_pMixer->SetOutputType(0, pType, 0); - - // If something went wrong, clear the media type. - if (FAILED(hr)) { - SetMediaType(nullptr); - } else { - break; - } - } - } - - pMixerType = nullptr; - pType = nullptr; - return hr; -} - -bool CEVRAllocatorPresenter::GetImageFromMixer() -{ - MFT_OUTPUT_DATA_BUFFER dataBuffer; - HRESULT hr = S_OK; - DWORD dwStatus; - REFERENCE_TIME nsSampleTime; - LONGLONG llClockBefore = 0; - LONGLONG llClockAfter = 0; - LONGLONG llMixerLatency; - UINT dwSurface; - - bool bDoneSomething = false; - - auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { - UINT32 nGroupId; - return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); - }; - - while (SUCCEEDED(hr)) { - CComPtr pSample; - - if (FAILED(GetFreeSample(&pSample))) { - break; - } - - ZeroMemory(&dataBuffer, sizeof(dataBuffer)); - dataBuffer.pSample = pSample; - pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface); - ASSERT(sampleHasCurrentGroupId(pSample)); - - { - llClockBefore = GetRenderersData()->GetPerfCounter(); - if (!m_pMixer) { - ASSERT(FALSE); - break; - } - hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus); - llClockAfter = GetRenderersData()->GetPerfCounter(); - } - - if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { - AddToFreeList(pSample, false); - pSample = nullptr; // The sample should not be used after being queued - // Important: Release any events returned from the ProcessOutput method. - SAFE_RELEASE(dataBuffer.pEvents); - break; - } - - if (m_pSink) { - //CAutoLock autolock(this); We shouldn't need to lock here, m_pSink is thread safe - llMixerLatency = llClockAfter - llClockBefore; - m_pSink->Notify(EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0); - } - - pSample->GetSampleTime(&nsSampleTime); - REFERENCE_TIME nsDuration; - pSample->GetSampleDuration(&nsDuration); - - if (GetRenderersData()->m_bTearingTest) { - RECT rcTearing; - - rcTearing.left = m_nTearingPos; - rcTearing.top = 0; - rcTearing.right = rcTearing.left + 4; - rcTearing.bottom = m_nativeVideoSize.cy; - m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - - rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; - rcTearing.right = rcTearing.left + 4; - m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; - } - - TRACE_EVR("EVR: Get from Mixer : %u (%I64d) (%I64d)\n", dwSurface, nsSampleTime, m_rtTimePerFrame ? nsSampleTime / m_rtTimePerFrame : 0); - - if (SUCCEEDED(TrackSample(pSample))) { - AddToScheduledList(pSample, false); - pSample = nullptr; // The sample should not be used after being queued - bDoneSomething = true; - } else { - ASSERT(FALSE); - } - - // Important: Release any events returned from the ProcessOutput method. - SAFE_RELEASE(dataBuffer.pEvents); - - if (m_rtTimePerFrame == 0) { - break; - } - } - - return bDoneSomething; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType) -{ - HRESULT hr = S_OK; - CAutoLock lock(&m_MediaTypeLock); - - CheckPointer(ppMediaType, E_POINTER); - CHECK_HR(CheckShutdown()); - - if (!m_pMediaType) { - return MF_E_NOT_INITIALIZED; - } - - CHECK_HR(m_pMediaType->QueryInterface(IID_PPV_ARGS(ppMediaType))); - - return hr; -} - -// IMFTopologyServiceLookupClient -STDMETHODIMP CEVRAllocatorPresenter::InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup) -{ - HRESULT hr = S_OK; - DWORD dwObjects = 1; - - CAutoLock cThreadsLock(&m_ThreadsLock); - - TRACE_EVR("EVR: CEVRAllocatorPresenter::InitServicePointers\n"); - CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, - IID_PPV_ARGS(&m_pMixer), &dwObjects)); - - CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, - IID_PPV_ARGS(&m_pSink), &dwObjects)); - - pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, - IID_PPV_ARGS(&m_pClock), &dwObjects); - - - StartWorkerThreads(); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::ReleaseServicePointers() -{ - TRACE_EVR("EVR: CEVRAllocatorPresenter::ReleaseServicePointers\n"); - CAutoLock cThreadsLock(&m_ThreadsLock); - - StopWorkerThreads(); - - m_pMixer.Release(); - m_pSink.Release(); - m_pClock.Release(); - return S_OK; -} - -// IMFVideoDeviceID -STDMETHODIMP CEVRAllocatorPresenter::GetDeviceID(/* [out] */ __out IID* pDeviceID) -{ - CheckPointer(pDeviceID, E_POINTER); - *pDeviceID = IID_IDirect3DDevice9; - return S_OK; -} - -// IMFGetService -STDMETHODIMP CEVRAllocatorPresenter::GetService(/* [in] */ __RPC__in REFGUID guidService, - /* [in] */ __RPC__in REFIID riid, - /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject) -{ - if (guidService == MR_VIDEO_RENDER_SERVICE) { - return NonDelegatingQueryInterface(riid, ppvObject); - } else if (guidService == MR_VIDEO_ACCELERATION_SERVICE) { - return m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppvObject); - } - - return E_NOINTERFACE; -} - -// IMFAsyncCallback -STDMETHODIMP CEVRAllocatorPresenter::GetParameters(/* [out] */ __RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CEVRAllocatorPresenter::Invoke(/* [in] */ __RPC__in_opt IMFAsyncResult* pAsyncResult) -{ - return E_NOTIMPL; -} - -// IMFVideoDisplayControl -STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) -{ - if (pszVideo) { - pszVideo->cx = m_nativeVideoSize.cx; - pszVideo->cy = m_nativeVideoSize.cy; - } - if (pszARVideo) { - pszARVideo->cx = m_aspectRatio.cx; - pszARVideo->cy = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) -{ - if (pszMin) { - pszMin->cx = 1; - pszMin->cy = 1; - } - - if (pszMax) { - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - - if (SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D), &d3ddm))) { - pszMax->cx = d3ddm.Width; - pszMax->cy = d3ddm.Height; - } - } - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) -{ - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) -{ - // Always all source rectangle ? - if (pnrcSource) { - pnrcSource->left = 0.0; - pnrcSource->top = 0.0; - pnrcSource->right = 1.0; - pnrcSource->bottom = 1.0; - } - - if (prcDest) { - memcpy(prcDest, &m_videoRect, sizeof(m_videoRect)); //GetClientRect (m_hWnd, prcDest); - } - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetAspectRatioMode(DWORD dwAspectRatioMode) -{ - m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetAspectRatioMode(DWORD* pdwAspectRatioMode) -{ - CheckPointer(pdwAspectRatioMode, E_POINTER); - *pdwAspectRatioMode = m_dwVideoAspectRatioMode; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetVideoWindow(HWND hwndVideo) -{ - if (m_hWnd != hwndVideo) { - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_RenderLock); - - m_hWnd = hwndVideo; - m_bPendingResetDevice = true; - if (m_pSink) { - m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); - } - SendResetRequest(); - } - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetVideoWindow(HWND* phwndVideo) -{ - CheckPointer(phwndVideo, E_POINTER); - *phwndVideo = m_hWnd; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::RepaintVideo() -{ - Paint(true); - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetCurrentImage(BITMAPINFOHEADER *pBih, BYTE **pDib, DWORD *pcbDib, LONGLONG *pTimeStamp) -{ - if (!pBih || !pDib || !pcbDib) { - return E_POINTER; - } - CheckPointer(m_pD3DDevEx, E_ABORT); - - HRESULT hr = S_OK; - const unsigned width = m_windowRect.Width(); - const unsigned height = m_windowRect.Height(); - const unsigned len = width * height * 4; - - memset(pBih, 0, sizeof(BITMAPINFOHEADER)); - pBih->biSize = sizeof(BITMAPINFOHEADER); - pBih->biWidth = width; - pBih->biHeight = height; - pBih->biBitCount = 32; - pBih->biPlanes = 1; - pBih->biSizeImage = DIBSIZE(*pBih); - - BYTE* p = (BYTE*)CoTaskMemAlloc(len); // only this allocator can be used - if (!p) { - return E_OUTOFMEMORY; - } - - CComPtr pBackBuffer; - CComPtr pDestSurface; - D3DLOCKED_RECT r; - if (FAILED(hr = m_pD3DDevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)) - || FAILED(hr = m_pD3DDevEx->CreateRenderTarget(width, height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pDestSurface, nullptr)) - || (FAILED(hr = m_pD3DDevEx->StretchRect(pBackBuffer, m_windowRect, pDestSurface, nullptr, D3DTEXF_NONE))) - || (FAILED(hr = pDestSurface->LockRect(&r, nullptr, D3DLOCK_READONLY)))) { - CString Error = GetWindowsErrorMessage(hr, nullptr); - TRACE_EVR(L"CEVRAllocatorPresenter::GetCurrentImage failed : %s", S_OK == hr ? L"S_OK" : Error.GetBuffer()); - CoTaskMemFree(p); - return hr; - } - - RetrieveBitmapData(width, height, 32, p, (BYTE*)r.pBits, r.Pitch); - - pDestSurface->UnlockRect(); - - *pDib = p; - *pcbDib = len; - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetBorderColor(COLORREF Clr) -{ - m_BorderColor = Clr; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetBorderColor(COLORREF* pClr) -{ - CheckPointer(pClr, E_POINTER); - *pClr = m_BorderColor; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetRenderingPrefs(DWORD dwRenderFlags) -{ - m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetRenderingPrefs(DWORD* pdwRenderFlags) -{ - CheckPointer(pdwRenderFlags, E_POINTER); - *pdwRenderFlags = m_dwVideoRenderPrefs; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetFullscreen(BOOL fFullscreen) -{ - m_bIsFullscreen = !!fFullscreen; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetFullscreen(BOOL* pfFullscreen) -{ - CheckPointer(pfFullscreen, E_POINTER); - *pfFullscreen = m_bIsFullscreen; - return S_OK; -} - -// IMFVideoMixerBitmap -STDMETHODIMP CEVRAllocatorPresenter::ClearAlphaBitmap() -{ - CAutoLock cRenderLock(&m_RenderLock); - m_bAlphaBitmapEnable = false; - - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetAlphaBitmapParameters(MFVideoAlphaBitmapParams *pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock cRenderLock(&m_RenderLock); - - if (m_bAlphaBitmapEnable && m_pAlphaBitmapTexture) { - *pBmpParms = m_AlphaBitmapParams; // formal implementation, don't believe it - return S_OK; - } else { - return MF_E_NOT_INITIALIZED; - } -} - -STDMETHODIMP CEVRAllocatorPresenter::SetAlphaBitmap(const MFVideoAlphaBitmap *pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock cRenderLock(&m_RenderLock); - - CheckPointer(m_pD3DDevEx, E_ABORT); - HRESULT hr = S_OK; - - if (pBmpParms->GetBitmapFromDC && pBmpParms->bitmap.hdc) { - HBITMAP hBitmap = (HBITMAP)GetCurrentObject(pBmpParms->bitmap.hdc, OBJ_BITMAP); - if (!hBitmap) { - return E_INVALIDARG; - } - DIBSECTION info = { 0 }; - if (!::GetObjectW(hBitmap, sizeof(DIBSECTION), &info)) { - return E_INVALIDARG; - } - BITMAP& bm = info.dsBm; - if (!bm.bmWidth || !bm.bmHeight || bm.bmBitsPixel != 32 || !bm.bmBits) { - return E_INVALIDARG; - } - - if (m_pAlphaBitmapTexture) { - D3DSURFACE_DESC desc = {}; - m_pAlphaBitmapTexture->GetLevelDesc(0, &desc); - if (bm.bmWidth != desc.Width || bm.bmHeight != desc.Height) { - m_pAlphaBitmapTexture.Release(); - } - } - - if (!m_pAlphaBitmapTexture) { - hr = m_pD3DDevEx->CreateTexture(bm.bmWidth, bm.bmHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pAlphaBitmapTexture, nullptr); - } - - if (SUCCEEDED(hr)) { - CComPtr pSurface; - hr = m_pAlphaBitmapTexture->GetSurfaceLevel(0, &pSurface); - if (SUCCEEDED(hr)) { - D3DLOCKED_RECT lr; - hr = pSurface->LockRect(&lr, nullptr, D3DLOCK_DISCARD); - if (S_OK == hr) { - if (bm.bmWidthBytes == lr.Pitch) { - memcpy(lr.pBits, bm.bmBits, bm.bmWidthBytes * bm.bmHeight); - } - else { - LONG linesize = std::min(bm.bmWidthBytes, (LONG)lr.Pitch); - BYTE* src = (BYTE*)bm.bmBits; - BYTE* dst = (BYTE*)lr.pBits; - for (LONG y = 0; y < bm.bmHeight; ++y) { - memcpy(dst, src, linesize); - src += bm.bmWidthBytes; - dst += lr.Pitch; - } - } - hr = pSurface->UnlockRect(); - } - } - } - } else { - return E_INVALIDARG; - } - - m_bAlphaBitmapEnable = SUCCEEDED(hr) && m_pAlphaBitmapTexture; - - if (m_bAlphaBitmapEnable) { - hr = UpdateAlphaBitmapParameters(&pBmpParms->params); - } - - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams *pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock cRenderLock(&m_RenderLock); - - m_AlphaBitmapParams = *pBmpParms; // formal implementation, don't believe it - - return S_OK; -} - -// IEVRTrustedVideoPlugin -STDMETHODIMP CEVRAllocatorPresenter::IsInTrustedVideoMode(BOOL* pYes) -{ - CheckPointer(pYes, E_POINTER); - *pYes = TRUE; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::CanConstrict(BOOL* pYes) -{ - CheckPointer(pYes, E_POINTER); - *pYes = TRUE; - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::SetConstriction(DWORD dwKPix) -{ - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::DisableImageExport(BOOL bDisable) -{ - return S_OK; -} - - -// IDirect3DDeviceManager9 -STDMETHODIMP CEVRAllocatorPresenter::ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken) -{ - HRESULT hr = m_pD3DManager->ResetDevice(pDevice, resetToken); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::OpenDeviceHandle(HANDLE* phDevice) -{ - HRESULT hr = m_pD3DManager->OpenDeviceHandle(phDevice); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::CloseDeviceHandle(HANDLE hDevice) -{ - HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::TestDevice(HANDLE hDevice) -{ - HRESULT hr = m_pD3DManager->TestDevice(hDevice); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock) -{ - HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::UnlockDevice(HANDLE hDevice, BOOL fSaveState) -{ - HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState); - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetVideoService(HANDLE hDevice, REFIID riid, void** ppService) -{ - HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService); - - if (riid == __uuidof(IDirectXVideoDecoderService)) { - UINT nNbDecoder = 5; - GUID* pDecoderGuid; - IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService; - pDXVAVideoDecoder->GetDecoderDeviceGuids(&nNbDecoder, &pDecoderGuid); - } else if (riid == __uuidof(IDirectXVideoProcessorService)) { - IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService; - UNREFERENCED_PARAMETER(pDXVAProcessor); - } - - return hr; -} - -STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) -{ - // This function should be called... - ASSERT(FALSE); - - if (lpWidth) { - *lpWidth = m_nativeVideoSize.cx; - } - if (lpHeight) { - *lpHeight = m_nativeVideoSize.cy; - } - if (lpARWidth) { - *lpARWidth = m_aspectRatio.cx; - } - if (lpARHeight) { - *lpARHeight = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CEVRAllocatorPresenter::InitializeDevice(IMFMediaType* pMediaType) -{ - HRESULT hr; - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_RenderLock); - - RemoveAllSamples(); - DeleteSurfaces(); - - // Retrieve the surface size and format - UINT32 Width; - UINT32 Height; - hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &Width, &Height); - - D3DFORMAT Format; - if (SUCCEEDED(hr)) { - SetVideoSize(CSize(Width, Height), m_aspectRatio); - hr = GetMediaTypeFourCC(pMediaType, (DWORD*)&Format); - } - - if (SUCCEEDED(hr)) { - hr = AllocSurfaces(); - } - - if (SUCCEEDED(hr)) { - for (int i = 0; i < m_nNbDXSurface; i++) { - CComPtr pMFSample; - hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); - - if (SUCCEEDED(hr)) { - pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); - pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - m_FreeSamples.AddTail(pMFSample); - pMFSample = nullptr; // The sample should not be used after being queued - } - ASSERT(SUCCEEDED(hr)); - } - } - - return hr; -} - -DWORD WINAPI CEVRAllocatorPresenter::GetMixerThreadStatic(LPVOID lpParam) -{ - SetThreadName(DWORD(-1), "CEVRPresenter::MixerThread"); - CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; - pThis->GetMixerThread(); - return 0; -} - -DWORD WINAPI CEVRAllocatorPresenter::PresentThread(LPVOID lpParam) -{ - SetThreadName(DWORD(-1), "CEVRPresenter::PresentThread"); - CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; - pThis->RenderThread(); - return 0; -} - -bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt) -{ - if (pmt->formattype == FORMAT_VideoInfo) { - return false; - } else if (pmt->formattype == FORMAT_VideoInfo2) { - return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; - } else if (pmt->formattype == FORMAT_MPEGVideo) { - return false; - } else if (pmt->formattype == FORMAT_MPEG2Video) { - return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; - } else { - return false; - } -} - -void CEVRAllocatorPresenter::GetMixerThread() -{ - HANDLE hEvts[] = { m_hEvtQuit}; - bool bQuit = false; - TIMECAPS tc; - DWORD dwResolution; - - // Tell Multimedia Class Scheduler we are a playback thread (increase priority) - //HANDLE hAvrt = 0; - //if (pfAvSetMmThreadCharacteristicsW) { - // DWORD dwTaskIndex = 0; - // hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); - // if (pfAvSetMmThreadPriority) { - // pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); - // } - //} - - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - timeBeginPeriod(dwResolution); - - while (!bQuit) { - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); - switch (dwObject) { - case WAIT_OBJECT_0: - bQuit = true; - break; - case WAIT_TIMEOUT: { - bool bDoneSomething = false; - { - CAutoLock AutoLock(&m_ImageProcessingLock); - bDoneSomething = GetImageFromMixer(); - } - if (m_rtTimePerFrame == 0 && bDoneSomething) { - //CAutoLock lock(this); - //CAutoLock lock2(&m_ImageProcessingLock); - //CAutoLock cRenderLock(&m_RenderLock); - - // Use the code from VMR9 to get the movie fps, as this method is reliable. - CComPtr pPin; - CMediaType mt; - if ( - SUCCEEDED(m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) && - SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); - - m_bInterlaced = ExtractInterlaced(&mt); - - CComPtr pPinTo; - if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { - m_Decoder = GetFilterName(GetFilterFromPin(pPinTo)); - } - } - // If framerate not set by Video Decoder choose 23.97... - if (m_rtTimePerFrame == 0) { - m_rtTimePerFrame = 417166; - } - - // Update internal subtitle clock - if (m_fUseInternalTimer && m_pSubPicQueue) { - m_fps = 10000000.0 / m_rtTimePerFrame; - m_pSubPicQueue->SetFPS(m_fps); - } - } - } - break; - } - } - - timeEndPeriod(dwResolution); - // if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt); -} - -void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed) -{ - double xbiss = (-(ChangeSpeed) * (ValuePrim) - (Value - Target) * (ChangeSpeed * ChangeSpeed) * 0.25f); - ValuePrim += xbiss; - Value += ValuePrim; -} - -LONGLONG CEVRAllocatorPresenter::GetClockTime(LONGLONG PerformanceCounter) -{ - LONGLONG llClockTime; - MFTIME nsCurrentTime; - m_pClock->GetCorrelatedTime(0, &llClockTime, &nsCurrentTime); - DWORD Characteristics = 0; - m_pClock->GetClockCharacteristics(&Characteristics); - MFCLOCK_STATE State; - m_pClock->GetState(0, &State); - - if (!(Characteristics & MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ)) { - MFCLOCK_PROPERTIES Props; - if (m_pClock->GetProperties(&Props) == S_OK) { - llClockTime = (llClockTime * 10000000) / Props.qwClockFrequency; // Make 10 MHz - } - - } - LONGLONG llPerf = PerformanceCounter; - //return llClockTime + (llPerf - nsCurrentTime); - double Target = llClockTime + (llPerf - nsCurrentTime) * m_ModeratedTimeSpeed; - - bool bReset = false; - if (m_ModeratedTimeLast < 0 || State != m_LastClockState || m_ModeratedClockLast < 0) { - bReset = true; - m_ModeratedTimeLast = llPerf; - m_ModeratedClockLast = llClockTime; - } - - m_LastClockState = State; - - LONGLONG TimeChangeM = llPerf - m_ModeratedTimeLast; - LONGLONG ClockChangeM = llClockTime - m_ModeratedClockLast; - UNREFERENCED_PARAMETER(ClockChangeM); - - m_ModeratedTimeLast = llPerf; - m_ModeratedClockLast = llClockTime; - -#if 1 - - if (bReset) { - m_ModeratedTimeSpeed = 1.0; - m_ModeratedTimeSpeedPrim = 0.0; - ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory)); - ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory)); - m_ClockTimeChangeHistoryPos = 0; - } - if (TimeChangeM) { - int Pos = m_ClockTimeChangeHistoryPos % 100; - int nHistory = std::min(m_ClockTimeChangeHistoryPos, 100); - ++m_ClockTimeChangeHistoryPos; - if (nHistory > 50) { - int iLastPos = (Pos - (nHistory)) % 100; - if (iLastPos < 0) { - iLastPos += 100; - } - - double TimeChange = llPerf - m_TimeChangeHistory[iLastPos]; - double ClockChange = llClockTime - m_ClockChangeHistory[iLastPos]; - - double ClockSpeedTarget = ClockChange / TimeChange; - double ChangeSpeed = 0.1; - if (ClockSpeedTarget > m_ModeratedTimeSpeed) { - if (ClockSpeedTarget / m_ModeratedTimeSpeed > 0.1) { - ChangeSpeed = 0.1; - } else { - ChangeSpeed = 0.01; - } - } else { - if (m_ModeratedTimeSpeed / ClockSpeedTarget > 0.1) { - ChangeSpeed = 0.1; - } else { - ChangeSpeed = 0.01; - } - } - ModerateFloat(m_ModeratedTimeSpeed, ClockSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed); - //m_ModeratedTimeSpeed = TimeChange / ClockChange; - } - m_TimeChangeHistory[Pos] = (double)llPerf; - m_ClockChangeHistory[Pos] = (double)llClockTime; - } - - return (LONGLONG)Target; -#else - double EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed + m_ClockDiffCalc; - double Diff = Target - EstimateTime; - - // > 5 ms just set it - if ((fabs(Diff) > 50000.0 || bReset)) { - - // TRACE_EVR("EVR: Reset clock at diff: %f ms\n", (m_ModeratedTime - Target) /10000.0); - if (State == MFCLOCK_STATE_RUNNING) { - if (bReset) { - m_ModeratedTimeSpeed = 1.0; - m_ModeratedTimeSpeedPrim = 0.0; - m_ClockDiffCalc = 0; - m_ClockDiffPrim = 0; - m_ModeratedTime = Target; - m_ModeratedTimer = llPerf; - } else { - EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed; - Diff = Target - EstimateTime; - m_ClockDiffCalc = Diff; - m_ClockDiffPrim = 0; - } - } else { - m_ModeratedTimeSpeed = 0.0; - m_ModeratedTimeSpeedPrim = 0.0; - m_ClockDiffCalc = 0; - m_ClockDiffPrim = 0; - m_ModeratedTime = Target; - m_ModeratedTimer = llPerf; - } - } - - { - LONGLONG ModerateTime = 10000; - double ChangeSpeed = 1.00; - /*if (m_ModeratedTimeSpeedPrim != 0.0) - { - if (m_ModeratedTimeSpeedPrim < 0.1) - ChangeSpeed = 0.1; - }*/ - - int nModerate = 0; - double Change = 0; - while (m_ModeratedTimer < llPerf - ModerateTime) { - m_ModeratedTimer += ModerateTime; - m_ModeratedTime += double(ModerateTime) * m_ModeratedTimeSpeed; - - double TimerDiff = llPerf - m_ModeratedTimer; - - double Diff = (double)(m_ModeratedTime - (Target - TimerDiff)); - - double TimeSpeedTarget; - double AbsDiff = fabs(Diff); - TimeSpeedTarget = 1.0 - (Diff / 1000000.0); - // TimeSpeedTarget = m_ModeratedTimeSpeed - (Diff / 100000000000.0); - //if (AbsDiff > 20000.0) - // TimeSpeedTarget = 1.0 - (Diff / 1000000.0); - /*else if (AbsDiff > 5000.0) - TimeSpeedTarget = 1.0 - (Diff / 100000000.0); - else - TimeSpeedTarget = 1.0 - (Diff / 500000000.0);*/ - double StartMod = m_ModeratedTimeSpeed; - ModerateFloat(m_ModeratedTimeSpeed, TimeSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed); - m_ModeratedTimeSpeed = TimeSpeedTarget; - ++nModerate; - Change += m_ModeratedTimeSpeed - StartMod; - } - if (nModerate) { - m_ModeratedTimeSpeedDiff = Change / nModerate; - } - - double Ret = m_ModeratedTime + double(llPerf - m_ModeratedTimer) * m_ModeratedTimeSpeed; - double Diff = Target - Ret; - ModerateFloat(m_ClockDiffCalc, Diff, m_ClockDiffPrim, ChangeSpeed * 0.1); - - Ret += m_ClockDiffCalc; - Diff = Target - Ret; - m_ClockDiff = Diff; - return LONGLONG(Ret + 0.5); - } - - return Target; - return LONGLONG(m_ModeratedTime + 0.5); -#endif -} - -void CEVRAllocatorPresenter::OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter) -{ - // This function is meant to be called only from the rendering function - // so with the ownership on m_RenderLock. - if (!m_pCurrentlyDisplayedSample || !m_OrderedPaint || !bAll) { - return; - } - - LONGLONG llClockTime; - LONGLONG nsSampleTime; - LONGLONG SampleDuration = 0; - LONGLONG TimePerFrame = m_rtTimePerFrame; - if (!TimePerFrame) { - return; - } - - if (!m_bSignaledStarvation) { - llClockTime = GetClockTime(PerformanceCounter); - m_StarvationClock = llClockTime; - } else { - llClockTime = m_StarvationClock; - } - - if (SUCCEEDED(m_pCurrentlyDisplayedSample->GetSampleDuration(&SampleDuration))) { - // Some filters return invalid values, ignore them - if (SampleDuration > MIN_FRAME_TIME) { - TimePerFrame = SampleDuration; - } - } - - if (FAILED(m_pCurrentlyDisplayedSample->GetSampleTime(&nsSampleTime))) { - nsSampleTime = llClockTime; - } - - { - m_nNextSyncOffset = (m_nNextSyncOffset + 1) % NB_JITTER; - LONGLONG SyncOffset = nsSampleTime - llClockTime; - - m_pllSyncOffset[m_nNextSyncOffset] = SyncOffset; - //TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d \n", m_nCurSurface, m_VSyncMode, m_LastPredictedSync, -SyncOffset, m_LastPredictedSync - (-SyncOffset)); - - m_MaxSyncOffset = MINLONG64; - m_MinSyncOffset = MAXLONG64; - - LONGLONG AvrageSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG Offset = m_pllSyncOffset[i]; - AvrageSum += Offset; - m_MaxSyncOffset = std::max(m_MaxSyncOffset, Offset); - m_MinSyncOffset = std::min(m_MinSyncOffset, Offset); - } - double MeanOffset = double(AvrageSum) / NB_JITTER; - double DeviationSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - double Deviation = double(m_pllSyncOffset[i]) - MeanOffset; - DeviationSum += Deviation * Deviation; - } - double StdDev = sqrt(DeviationSum / NB_JITTER); - - m_fSyncOffsetAvr = MeanOffset; - m_bSyncStatsAvailable = true; - m_fSyncOffsetStdDev = StdDev; - } -} - -STDMETHODIMP_(bool) CEVRAllocatorPresenter::ResetDevice() -{ - CAutoLock cThreadsLock(&m_ThreadsLock); - - StopWorkerThreads(); - - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_RenderLock); - - RemoveAllSamples(); - - bool bResult = __super::ResetDevice(); - - for (int i = 0; i < m_nNbDXSurface; i++) { - CComPtr pMFSample; - HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); - - if (SUCCEEDED(hr)) { - pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); - pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - m_FreeSamples.AddTail(pMFSample); - pMFSample = nullptr; // The sample should not be used after being queued - } - ASSERT(SUCCEEDED(hr)); - } - - if (bResult) { - StartWorkerThreads(); - } - - return bResult; -} - -STDMETHODIMP_(bool) CEVRAllocatorPresenter::DisplayChange() -{ - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_RenderLock); - - bool bResult = __super::DisplayChange(); - - m_DetectedFrameRate = 0.0; - m_DetectedFrameTime = 0.0; - m_DetectedFrameTimeStdDev = 0.0; - m_DetectedLock = false; - ZeroMemory(m_DetectedFrameTimeHistory, sizeof(m_DetectedFrameTimeHistory)); - ZeroMemory(m_DetectedFrameTimeHistoryHistory, sizeof(m_DetectedFrameTimeHistoryHistory)); - m_DetectedFrameTimePos = 0; - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - ZeroMemory(m_ldDetectedRefreshRateList, sizeof(m_ldDetectedRefreshRateList)); - ZeroMemory(m_ldDetectedScanlineRateList, sizeof(m_ldDetectedScanlineRateList)); - m_DetectedRefreshRatePos = 0; - m_DetectedRefreshTimePrim = 0; - m_DetectedScanlineTime = 0; - m_DetectedScanlineTimePrim = 0; - m_DetectedRefreshRate = 0; - - ZeroMemory(m_pllJitter, sizeof(m_pllJitter)); - ZeroMemory(m_pllSyncOffset, sizeof(m_pllSyncOffset)); - m_nNextJitter = 0; - m_nNextSyncOffset = 0; - m_llLastPerf = 0; - m_fAvrFps = 0.0; - m_fJitterStdDev = 0.0; - m_fSyncOffsetStdDev = 0.0; - m_fSyncOffsetAvr = 0.0; - m_bSyncStatsAvailable = false; - - return bResult; -} - -void CEVRAllocatorPresenter::RenderThread() -{ - HANDLE hEvts[] = { m_hEvtQuit, m_hEvtFlush}; - bool bQuit = false, bForcePaint = false; - TIMECAPS tc; - MFTIME nsSampleTime; - LONGLONG llClockTime; - - // Tell Multimedia Class Scheduler we are a playback thread (increase priority) - HANDLE hAvrt = 0; - if (fnAvSetMmThreadCharacteristicsW) { - DWORD dwTaskIndex = 0; - hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); - if (fnAvSetMmThreadPriority) { - fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); - } - } - - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - VERIFY(timeBeginPeriod(dwResolution) == 0); - - auto checkPendingMediaFinished = [this]() { - if (m_bPendingMediaFinished && m_nRenderState != Stopped) { - CAutoLock lock(&m_SampleQueueLock); - if (m_ScheduledSamples.IsEmpty()) { - m_bPendingMediaFinished = false; - m_pSink->Notify(EC_COMPLETE, 0, 0); - TRACE_EVR("EVR: send EC_COMPLETE\n"); - } - } - }; - - const CRenderersSettings& r = GetRenderersSettings(); - - auto SubPicSetTime = [&] { - if (!g_bExternalSubtitleTime && !m_bIsPreview) { - CSubPicAllocatorPresenterImpl::SetTime(g_tSegmentStart + nsSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); - } - }; - - int NextSleepTime = 1; - while (!bQuit) { - LONGLONG llPerf = GetRenderersData()->GetPerfCounter(); - UNREFERENCED_PARAMETER(llPerf); - if (!r.m_AdvRendSets.bVMR9VSyncAccurate && NextSleepTime == 0) { - NextSleepTime = 1; - } - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, std::max(NextSleepTime < 0 ? 1 : NextSleepTime, 0)); - /* dwObject = WAIT_TIMEOUT; - if (m_bEvtFlush) - dwObject = WAIT_OBJECT_0 + 1; - else if (m_bEvtQuit) - dwObject = WAIT_OBJECT_0;*/ - // if (NextSleepTime) - // TRACE_EVR("EVR: Sleep: %7.3f\n", double(GetRenderersData()->GetPerfCounter()-llPerf) / 10000.0); - if (NextSleepTime > 1) { - NextSleepTime = 0; - } else if (NextSleepTime == 0) { - NextSleepTime = -1; - } - switch (dwObject) { - case WAIT_OBJECT_0: - bQuit = true; - break; - case WAIT_OBJECT_0 + 1: - // Flush pending samples! - FlushSamples(); - m_bEvtFlush = false; - ResetEvent(m_hEvtFlush); - bForcePaint = true; - TRACE_EVR("EVR: Flush done!\n"); - break; - - case WAIT_TIMEOUT: - - if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != r.m_AdvRendSets.iEVROutputRange || m_bPendingRenegotiate) { - FlushSamples(); - RenegotiateMediaType(); - m_bPendingRenegotiate = false; - } - if (m_bPendingResetDevice) { - SendResetRequest(); - } - - // Discard timer events if playback stop - //if ((dwObject == WAIT_OBJECT_0 + 3) && (m_nRenderState != Started)) continue; - - //TRACE_EVR ("EVR: RenderThread ==>> Waiting buffer\n"); - - //if (WaitForMultipleObjects (_countof(hEvtsBuff), hEvtsBuff, FALSE, INFINITE) == WAIT_OBJECT_0+2) - { - CComPtr pMFSample; - //LONGLONG llPerf2 = GetRenderersData()->GetPerfCounter(); - //UNREFERENCED_PARAMETER(llPerf2); - int nSamplesLeft = 0; - if (SUCCEEDED(GetScheduledSample(&pMFSample, nSamplesLeft))) { - //UINT32 nSurface; - //pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&nSurface); - - bool bValidSampleTime = true; - HRESULT hrGetSampleTime = pMFSample->GetSampleTime(&nsSampleTime); - if (hrGetSampleTime != S_OK || nsSampleTime == 0) { - bValidSampleTime = false; - } - // We assume that all samples have the same duration - LONGLONG SampleDuration = 0; - bool bValidSampleDuration = true; - HRESULT hrGetSampleDuration = pMFSample->GetSampleDuration(&SampleDuration); - // Some filters return invalid values, ignore them - if (hrGetSampleDuration != S_OK || SampleDuration <= MIN_FRAME_TIME) { - bValidSampleDuration = false; - } - - //TRACE_EVR("EVR: RenderThread ==>> Presenting surface %d (%I64d)\n", nSurface, nsSampleTime); - - bool bStepForward = false; - - if (m_nStepCount < 0) { - // Drop frame - TRACE_EVR("EVR: Dropped frame\n"); - m_pcFrames++; - bStepForward = true; - m_nStepCount = 0; - /* - } else if (m_nStepCount > 0) { - ++m_OrderedPaint; - SubPicSetTime(); - Paint(pMFSample); - m_nDroppedUpdate = 0; - CompleteFrameStep(false); - bStepForward = true; - */ - } else if (m_nRenderState == Started) { - LONGLONG CurrentCounter = GetRenderersData()->GetPerfCounter(); - // Calculate wake up timer - if (!m_bSignaledStarvation) { - llClockTime = GetClockTime(CurrentCounter); - m_StarvationClock = llClockTime; - } else { - llClockTime = m_StarvationClock; - } - - if (!bValidSampleTime) { - // Just play as fast as possible - bStepForward = true; - ++m_OrderedPaint; - SubPicSetTime(); - Paint(pMFSample); - } else { - LONGLONG TimePerFrame = (LONGLONG)(GetFrameTime() * 10000000.0); - LONGLONG SyncOffset = 0; - LONGLONG VSyncTime = 0; - LONGLONG TimeToNextVSync = -1; - bool bVSyncCorrection = false; - double DetectedRefreshTime; - double DetectedScanlinesPerFrame; - double DetectedScanlineTime; - int DetectedRefreshRatePos; - { - CAutoLock Lock(&m_refreshRateLock); - DetectedRefreshTime = m_DetectedRefreshTime; - DetectedRefreshRatePos = m_DetectedRefreshRatePos; - DetectedScanlinesPerFrame = m_DetectedScanlinesPerFrame; - DetectedScanlineTime = m_DetectedScanlineTime; - } - - if (DetectedRefreshRatePos < 20 || !DetectedRefreshTime || !DetectedScanlinesPerFrame) { - DetectedRefreshTime = 1.0 / m_refreshRate; - DetectedScanlinesPerFrame = m_ScreenSize.cy; - DetectedScanlineTime = DetectedRefreshTime / double(m_ScreenSize.cy); - } - - if (r.m_AdvRendSets.bVMR9VSync) { - bVSyncCorrection = true; - double TargetVSyncPos = GetVBlackPos(); - double RefreshLines = DetectedScanlinesPerFrame; - double ScanlinesPerSecond = 1.0 / DetectedScanlineTime; - double CurrentVSyncPos = fmod(double(m_VBlankStartMeasure) + ScanlinesPerSecond * ((CurrentCounter - m_VBlankStartMeasureTime) / 10000000.0), RefreshLines); - double LinesUntilVSync = 0; - //TargetVSyncPos -= ScanlinesPerSecond * (DrawTime/10000000.0); - //TargetVSyncPos -= 10; - TargetVSyncPos = fmod(TargetVSyncPos, RefreshLines); - if (TargetVSyncPos < 0) { - TargetVSyncPos += RefreshLines; - } - if (TargetVSyncPos > CurrentVSyncPos) { - LinesUntilVSync = TargetVSyncPos - CurrentVSyncPos; - } else { - LinesUntilVSync = (RefreshLines - CurrentVSyncPos) + TargetVSyncPos; - } - double TimeUntilVSync = LinesUntilVSync * DetectedScanlineTime; - TimeToNextVSync = (LONGLONG)(TimeUntilVSync * 10000000.0); - VSyncTime = (LONGLONG)(DetectedRefreshTime * 10000000.0); - - LONGLONG ClockTimeAtNextVSync = llClockTime + (LONGLONG)(TimeUntilVSync * 10000000.0 * m_ModeratedTimeSpeed); - - SyncOffset = (nsSampleTime - ClockTimeAtNextVSync); - - //if (SyncOffset < 0) - // TRACE_EVR("EVR: SyncOffset(%d): %I64d %I64d %I64d\n", m_nCurSurface, SyncOffset, TimePerFrame, VSyncTime); - } else { - SyncOffset = (nsSampleTime - llClockTime); - } - - //LONGLONG SyncOffset = nsSampleTime - llClockTime; - TRACE_EVR("EVR: SyncOffset: %I64d SampleFrame: %I64d ClockFrame: %I64d\n", SyncOffset, TimePerFrame != 0 ? nsSampleTime / TimePerFrame : 0, TimePerFrame != 0 ? llClockTime / TimePerFrame : 0); - if (bValidSampleDuration && !m_DetectedLock) { - TimePerFrame = SampleDuration; - } - - LONGLONG MinMargin = MIN_FRAME_TIME + std::min(LONGLONG(m_DetectedFrameTimeStdDev), 20000ll); - //if (m_FrameTimeCorrection) { - // MinMargin = MIN_FRAME_TIME; - //} else { - // MinMargin = MIN_FRAME_TIME + std::min(LONGLONG(m_DetectedFrameTimeStdDev), 20000ll); - //} - LONGLONG TimePerFrameMargin = std::min(std::max(TimePerFrame * 2l / 100l, MinMargin), TimePerFrame * 11l / 100l); // (0.02..0.11)TimePerFrame - LONGLONG TimePerFrameMargin0 = TimePerFrameMargin / 2; - LONGLONG TimePerFrameMargin1 = 0; - - if (m_DetectedLock && TimePerFrame < VSyncTime) { - VSyncTime = TimePerFrame; - } - - if (m_VSyncMode == 1) { - TimePerFrameMargin1 = -TimePerFrameMargin; - } else if (m_VSyncMode == 2) { - TimePerFrameMargin1 = TimePerFrameMargin; - } - - m_LastSampleOffset = SyncOffset; - m_bLastSampleOffsetValid = true; - - LONGLONG VSyncOffset0 = 0; - bool bDoVSyncCorrection = false; - if ((SyncOffset < -(TimePerFrame + TimePerFrameMargin0 - TimePerFrameMargin1)) && nSamplesLeft > 0) { // Only drop if we have something else to display at once - // Drop frame - TRACE_EVR("EVR: Dropped frame\n"); - m_pcFrames++; - bStepForward = true; - ++m_nDroppedUpdate; - NextSleepTime = 0; - //VSyncOffset0 = (-SyncOffset) - VSyncTime; - //VSyncOffset0 = (-SyncOffset) - VSyncTime + TimePerFrameMargin1; - //m_LastPredictedSync = VSyncOffset0; - bDoVSyncCorrection = false; - } else if (SyncOffset < TimePerFrameMargin1) { - - if (bVSyncCorrection) { - VSyncOffset0 = -SyncOffset; - bDoVSyncCorrection = true; - } - - // Paint and prepare for next frame - TRACE_EVR("EVR: Normalframe\n"); - m_nDroppedUpdate = 0; - bStepForward = true; - m_LastFrameDuration = nsSampleTime - m_LastSampleTime; - m_LastSampleTime = nsSampleTime; - m_LastPredictedSync = VSyncOffset0; - - if (m_nStepCount > 0) { - CompleteFrameStep(false); - } - - ++m_OrderedPaint; - - SubPicSetTime(); - Paint(pMFSample); - - NextSleepTime = 0; - m_pcFramesDrawn++; - } else { - if (TimeToNextVSync >= 0 && SyncOffset > 0) { - NextSleepTime = (int)(TimeToNextVSync / 10000 - 2); - } else { - NextSleepTime = (int)(SyncOffset / 10000 - 2); - } - - if (NextSleepTime > TimePerFrame) { - NextSleepTime = 1; - } - - if (NextSleepTime < 0) { - NextSleepTime = 0; - } - NextSleepTime = 1; - //TRACE_EVR ("EVR: Delay\n"); - } - - if (bDoVSyncCorrection) { - //LONGLONG VSyncOffset0 = (((SyncOffset) % VSyncTime) + VSyncTime) % VSyncTime; - LONGLONG Margin = TimePerFrameMargin; - - LONGLONG VSyncOffsetMin = 30000000000000; - LONGLONG VSyncOffsetMax = -30000000000000; - for (int i = 0; i < 5; ++i) { - VSyncOffsetMin = std::min(m_VSyncOffsetHistory[i], VSyncOffsetMin); - VSyncOffsetMax = std::max(m_VSyncOffsetHistory[i], VSyncOffsetMax); - } - - m_VSyncOffsetHistory[m_VSyncOffsetHistoryPos] = VSyncOffset0; - m_VSyncOffsetHistoryPos = (m_VSyncOffsetHistoryPos + 1) % 5; - - //LONGLONG VSyncTime2 = VSyncTime2 + (VSyncOffsetMax - VSyncOffsetMin); - //VSyncOffsetMin; = (((VSyncOffsetMin) % VSyncTime) + VSyncTime) % VSyncTime; - //VSyncOffsetMax = (((VSyncOffsetMax) % VSyncTime) + VSyncTime) % VSyncTime; - - //TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d %8I64d\n", m_nCurSurface, m_VSyncMode,VSyncOffset0, VSyncOffsetMin, VSyncOffsetMax, VSyncOffsetMax - VSyncOffsetMin); - - if (m_VSyncMode == 0) { - // 23.976 in 60 Hz - if (VSyncOffset0 < Margin && VSyncOffsetMax > (VSyncTime - Margin)) { - m_VSyncMode = 2; - } else if (VSyncOffset0 > (VSyncTime - Margin) && VSyncOffsetMin < Margin) { - m_VSyncMode = 1; - } - } else if (m_VSyncMode == 2) { - if (VSyncOffsetMin > (Margin)) { - m_VSyncMode = 0; - } - } else if (m_VSyncMode == 1) { - if (VSyncOffsetMax < (VSyncTime - Margin)) { - m_VSyncMode = 0; - } - } - } - } - } else if (m_nRenderState == Paused) { - if (bForcePaint) { - bStepForward = true; - // Ensure that the renderer is properly updated after seeking when paused - SubPicSetTime(); - Paint(pMFSample); - } - NextSleepTime = int(SampleDuration / 10000 - 2); - } - - if (bStepForward) { - m_MaxSampleDuration = std::max(SampleDuration, m_MaxSampleDuration); - checkPendingMediaFinished(); - } else { - AddToScheduledList(pMFSample, true); - pMFSample = nullptr; // The sample should not be used after being queued - } - - bForcePaint = false; - } else if (m_bLastSampleOffsetValid && m_LastSampleOffset < -10000000) { // Only starve if we are 1 seconds behind - if (m_nRenderState == Started && !g_bNoDuration) { - m_pSink->Notify(EC_STARVATION, 0, 0); - m_bSignaledStarvation = true; - } - } else { - checkPendingMediaFinished(); - } - } - //else - //{ - // TRACE_EVR ("EVR: RenderThread ==>> Flush before rendering frame!\n"); - //} - - break; - } - } - - timeEndPeriod(dwResolution); - if (fnAvRevertMmThreadCharacteristics) { - fnAvRevertMmThreadCharacteristics(hAvrt); - } -} - -void CEVRAllocatorPresenter::VSyncThread() -{ - HANDLE hEvts[] = { m_hEvtQuit}; - bool bQuit = false; - TIMECAPS tc; - DWORD dwResolution; - - // Tell Multimedia Class Scheduler we are a playback thread (increase priority) - //HANDLE hAvrt = 0; - //if (pfAvSetMmThreadCharacteristicsW) { - // DWORD dwTaskIndex = 0; - // hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); - // if (pfAvSetMmThreadPriority) { - // pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); - // } - //} - - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - timeBeginPeriod(dwResolution); - const CRenderersData* rd = GetRenderersData(); - const CRenderersSettings& r = GetRenderersSettings(); - - while (!bQuit) { - - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); - switch (dwObject) { - case WAIT_OBJECT_0: - bQuit = true; - break; - case WAIT_TIMEOUT: { - // Do our stuff - if (m_pD3DDev && r.m_AdvRendSets.bVMR9VSync) { - if (m_nRenderState == Started) { - int VSyncPos = GetVBlackPos(); - int WaitRange = std::max(m_ScreenSize.cy / 40l, 5l); - int MinRange = std::max(std::min(long(0.003 * m_ScreenSize.cy * m_refreshRate + 0.5), m_ScreenSize.cy / 3l), 5l); // 1.8 ms or max 33 % of Time - - VSyncPos += MinRange + WaitRange; - - VSyncPos = VSyncPos % m_ScreenSize.cy; - if (VSyncPos < 0) { - VSyncPos += m_ScreenSize.cy; - } - - int ScanLine = 0; - int StartScanLine = ScanLine; - UNREFERENCED_PARAMETER(StartScanLine); - int LastPos = ScanLine; - UNREFERENCED_PARAMETER(LastPos); - ScanLine = (VSyncPos + 1) % m_ScreenSize.cy; - if (ScanLine < 0) { - ScanLine += m_ScreenSize.cy; - } - int ScanLineMiddle = ScanLine + m_ScreenSize.cy / 2; - ScanLineMiddle = ScanLineMiddle % m_ScreenSize.cy; - if (ScanLineMiddle < 0) { - ScanLineMiddle += m_ScreenSize.cy; - } - - int ScanlineStart = ScanLine; - HANDLE lockOwner = nullptr; - WaitForVBlankRange(ScanlineStart, 5, true, true, false, lockOwner); - LONGLONG TimeStart = rd->GetPerfCounter(); - - WaitForVBlankRange(ScanLineMiddle, 5, true, true, false, lockOwner); - LONGLONG TimeMiddle = rd->GetPerfCounter(); - - int ScanlineEnd = ScanLine; - WaitForVBlankRange(ScanlineEnd, 5, true, true, false, lockOwner); - LONGLONG TimeEnd = rd->GetPerfCounter(); - - double nSeconds = (TimeEnd - TimeStart) / 10000000.0; - LONGLONG llDiffMiddle = TimeMiddle - TimeStart; - ASSERT(llDiffMiddle > 0); - - if (nSeconds > 0.003 && llDiffMiddle > 0) { - double dDiffMiddle = double(llDiffMiddle); - double dDiffEnd = double(TimeEnd - TimeMiddle); - - double dDiffDiff = dDiffEnd / dDiffMiddle; - if (dDiffDiff < 1.3 && dDiffDiff > (1 / 1.3)) { - double ScanLineSeconds; - double nScanLines; - if (ScanLineMiddle > ScanlineEnd) { - ScanLineSeconds = dDiffMiddle / 10000000.0; - nScanLines = ScanLineMiddle - ScanlineStart; - } else { - ScanLineSeconds = dDiffEnd / 10000000.0; - nScanLines = ScanlineEnd - ScanLineMiddle; - } - - double ScanLineTime = ScanLineSeconds / nScanLines; - - int iPos = m_DetectedRefreshRatePos % 100; - m_ldDetectedScanlineRateList[iPos] = ScanLineTime; - if (m_DetectedScanlineTime && ScanlineStart != ScanlineEnd) { - int Diff = ScanlineEnd - ScanlineStart; - nSeconds -= double(Diff) * m_DetectedScanlineTime; - } - m_ldDetectedRefreshRateList[iPos] = nSeconds; - double Average = 0; - double AverageScanline = 0; - int nPos = std::min(iPos + 1, 100); - for (int i = 0; i < nPos; ++i) { - Average += m_ldDetectedRefreshRateList[i]; - AverageScanline += m_ldDetectedScanlineRateList[i]; - } - - if (nPos) { - Average /= double(nPos); - AverageScanline /= double(nPos); - } else { - Average = 0; - AverageScanline = 0; - } - - double ThisValue = Average; - - if (Average > 0.0 && AverageScanline > 0.0) { - CAutoLock Lock(&m_refreshRateLock); - ++m_DetectedRefreshRatePos; - if (m_DetectedRefreshTime == 0 || m_DetectedRefreshTime / ThisValue > 1.01 || m_DetectedRefreshTime / ThisValue < 0.99) { - m_DetectedRefreshTime = ThisValue; - m_DetectedRefreshTimePrim = 0; - } - if (_isnan(m_DetectedRefreshTime)) { - m_DetectedRefreshTime = 0.0; - } - if (_isnan(m_DetectedRefreshTimePrim)) { - m_DetectedRefreshTimePrim = 0.0; - } - - ModerateFloat(m_DetectedRefreshTime, ThisValue, m_DetectedRefreshTimePrim, 1.5); - if (m_DetectedRefreshTime > 0.0) { - m_DetectedRefreshRate = 1.0 / m_DetectedRefreshTime; - } else { - m_DetectedRefreshRate = 0.0; - } - - if (m_DetectedScanlineTime == 0 || m_DetectedScanlineTime / AverageScanline > 1.01 || m_DetectedScanlineTime / AverageScanline < 0.99) { - m_DetectedScanlineTime = AverageScanline; - m_DetectedScanlineTimePrim = 0; - } - ModerateFloat(m_DetectedScanlineTime, AverageScanline, m_DetectedScanlineTimePrim, 1.5); - if (m_DetectedScanlineTime > 0.0) { - m_DetectedScanlinesPerFrame = m_DetectedRefreshTime / m_DetectedScanlineTime; - } else { - m_DetectedScanlinesPerFrame = 0; - } - } - //TRACE(_T("Refresh: %f\n"), RefreshRate); - } - } - } - } else { - m_DetectedRefreshRate = 0.0; - m_DetectedScanlinesPerFrame = 0.0; - } - } - break; - } - } - - timeEndPeriod(dwResolution); - //if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt); -} - -DWORD WINAPI CEVRAllocatorPresenter::VSyncThreadStatic(LPVOID lpParam) -{ - SetThreadName(DWORD(-1), "CEVRAllocatorPresenter::VSyncThread"); - CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; - pThis->VSyncThread(); - return 0; -} - -void CEVRAllocatorPresenter::OnResetDevice() -{ - // Reset DXVA Manager, and get new buffers - m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); - - // Not necessary, but Microsoft documentation say Presenter should send this message... - if (m_pSink) { - m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); - } -} - -void CEVRAllocatorPresenter::RemoveAllSamples() -{ - CAutoLock imageProcesssingLock(&m_ImageProcessingLock); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - - FlushSamples(); - m_FreeSamples.RemoveAll(); - m_LastScheduledUncorrectedSampleTime = -1; - m_nUsedBuffer = 0; - // Increment the group id to make sure old samples will really be deleted - m_nCurrentGroupId++; -} - -HRESULT CEVRAllocatorPresenter::GetFreeSample(IMFSample** ppSample) -{ - CAutoLock lock(&m_SampleQueueLock); - HRESULT hr = S_OK; - - if (!m_FreeSamples.IsEmpty()) { - m_nUsedBuffer++; - *ppSample = m_FreeSamples.RemoveHead().Detach(); - } else { - hr = MF_E_SAMPLEALLOCATOR_EMPTY; - } - - return hr; -} - -HRESULT CEVRAllocatorPresenter::GetScheduledSample(IMFSample** ppSample, int& count) -{ - CAutoLock lock(&m_SampleQueueLock); - HRESULT hr = S_OK; - - count = (int)m_ScheduledSamples.GetCount(); - if (count > 0) { - *ppSample = m_ScheduledSamples.RemoveHead().Detach(); - --count; - } else { - hr = MF_E_SAMPLEALLOCATOR_EMPTY; - } - - return hr; -} - -void CEVRAllocatorPresenter::AddToFreeList(IMFSample* pSample, bool bTail) -{ - CAutoLock lock(&m_SampleQueueLock); - - m_nUsedBuffer--; - if (bTail) { - m_FreeSamples.AddTail(pSample); - } else { - m_FreeSamples.AddHead(pSample); - } -} - -void CEVRAllocatorPresenter::AddToScheduledList(IMFSample* pSample, bool bSorted) -{ - CAutoLock lock(&m_SampleQueueLock); - - if (bSorted) { - // Insert sorted - /*POSITION Iterator = m_ScheduledSamples.GetHeadPosition(); - - LONGLONG NewSampleTime; - pSample->GetSampleTime(&NewSampleTime); - - while (Iterator != nullptr) - { - POSITION CurrentPos = Iterator; - IMFSample *pIter = m_ScheduledSamples.GetNext(Iterator); - LONGLONG SampleTime; - pIter->GetSampleTime(&SampleTime); - if (NewSampleTime < SampleTime) - { - m_ScheduledSamples.InsertBefore(CurrentPos, pSample); - return; - } - }*/ - - m_ScheduledSamples.AddHead(pSample); - } else { - const CRenderersSettings& r = GetRenderersSettings(); - double ForceFPS = 0.0; - //double ForceFPS = 59.94; - //double ForceFPS = 23.976; - if (ForceFPS != 0.0) { - m_rtTimePerFrame = (REFERENCE_TIME)(10000000.0 / ForceFPS); - } - LONGLONG Duration = m_rtTimePerFrame; - UNREFERENCED_PARAMETER(Duration); - LONGLONG PrevTime = m_LastScheduledUncorrectedSampleTime; - LONGLONG Time; - LONGLONG SetDuration; - pSample->GetSampleDuration(&SetDuration); - pSample->GetSampleTime(&Time); - m_LastScheduledUncorrectedSampleTime = Time; - - m_bCorrectedFrameTime = false; - - LONGLONG Diff2 = PrevTime - (LONGLONG)(m_LastScheduledSampleTimeFP * 10000000.0); - LONGLONG Diff = Time - PrevTime; - if (PrevTime == -1) { - Diff = 0; - } - if (Diff < 0) { - Diff = -Diff; - } - if (Diff2 < 0) { - Diff2 = -Diff2; - } - if (Diff < m_rtTimePerFrame * 8 && m_rtTimePerFrame && Diff2 < m_rtTimePerFrame * 8) { // Detect seeking - int iPos = (m_DetectedFrameTimePos++) % 60; - Diff = Time - PrevTime; - if (PrevTime == -1) { - Diff = 0; - } - m_DetectedFrameTimeHistory[iPos] = Diff; - - if (m_DetectedFrameTimePos >= 10) { - int nFrames = std::min(m_DetectedFrameTimePos, 60); - LONGLONG DectedSum = 0; - for (int i = 0; i < nFrames; ++i) { - DectedSum += m_DetectedFrameTimeHistory[i]; - } - - double Average = double(DectedSum) / double(nFrames); - double DeviationSum = 0.0; - for (int i = 0; i < nFrames; ++i) { - double Deviation = m_DetectedFrameTimeHistory[i] - Average; - DeviationSum += Deviation * Deviation; - } - - double StdDev = sqrt(DeviationSum / double(nFrames)); - - m_DetectedFrameTimeStdDev = StdDev; - - double DetectedRate = 1.0 / (double(DectedSum) / (nFrames * 10000000.0)); - double AllowedError = 0.0003; - - static double AllowedValues[] = {60.0, 59.94, 50.0, 48.0, 47.952, 30.0, 29.97, 25.0, 24.0, 23.976}; - - int nAllowed = _countof(AllowedValues); - for (int i = 0; i < nAllowed; ++i) { - if (fabs(1.0 - DetectedRate / AllowedValues[i]) < AllowedError) { - DetectedRate = AllowedValues[i]; - break; - } - } - - m_DetectedFrameTimeHistoryHistory[m_DetectedFrameTimePos % 500] = DetectedRate; - - class CAutoInt - { - public: - - int m_Int; - - CAutoInt() { - m_Int = 0; - } - CAutoInt(int _Other) { - m_Int = _Other; - } - - operator int () const { - return m_Int; - } - - CAutoInt& operator ++ () { - ++m_Int; - return *this; - } - }; - - - CMap Map; - - for (int i = 0; i < 500; ++i) { - ++Map[m_DetectedFrameTimeHistoryHistory[i]]; - } - - POSITION Pos = Map.GetStartPosition(); - double BestVal = 0.0; - int BestNum = 5; - while (Pos) { - double Key; - CAutoInt Value; - Map.GetNextAssoc(Pos, Key, Value); - if (Value.m_Int > BestNum && Key != 0.0) { - BestNum = Value.m_Int; - BestVal = Key; - } - } - - m_DetectedLock = false; - for (int i = 0; i < nAllowed; ++i) { - if (BestVal == AllowedValues[i]) { - m_DetectedLock = true; - break; - } - } - if (BestVal != 0.0) { - m_DetectedFrameRate = BestVal; - m_DetectedFrameTime = 1.0 / BestVal; - } - } - - LONGLONG PredictedNext = PrevTime + m_rtTimePerFrame; - LONGLONG PredictedDiff = PredictedNext - Time; - if (PredictedDiff < 0) { - PredictedDiff = -PredictedDiff; - } - - if (m_DetectedFrameTime != 0.0 - //&& PredictedDiff > MIN_FRAME_TIME - && m_DetectedLock && r.m_AdvRendSets.bEVREnableFrameTimeCorrection) { - double CurrentTime = Time / 10000000.0; - double LastTime = m_LastScheduledSampleTimeFP; - double PredictedTime = LastTime + m_DetectedFrameTime; - if (fabs(PredictedTime - CurrentTime) > 0.0015) { // 1.5 ms wrong, lets correct - CurrentTime = PredictedTime; - Time = (LONGLONG)(CurrentTime * 10000000.0); - pSample->SetSampleTime(Time); - pSample->SetSampleDuration(LONGLONG(m_DetectedFrameTime * 10000000.0)); - m_bCorrectedFrameTime = true; - m_FrameTimeCorrection = 30; - } - m_LastScheduledSampleTimeFP = CurrentTime; - } else { - m_LastScheduledSampleTimeFP = Time / 10000000.0; - } - } else { - m_LastScheduledSampleTimeFP = Time / 10000000.0; - if (Diff > m_rtTimePerFrame * 8) { - // Seek - m_bSignaledStarvation = false; - m_DetectedFrameTimePos = 0; - m_DetectedLock = false; - } - } - - // TRACE_EVR("EVR: Time: %f %f %f\n", Time / 10000000.0, SetDuration / 10000000.0, m_DetectedFrameRate); - if (!m_bCorrectedFrameTime && m_FrameTimeCorrection) { - --m_FrameTimeCorrection; - } - -#if 0 - if (Time <= m_LastScheduledUncorrectedSampleTime && m_LastScheduledSampleTime >= 0) { - PrevTime = m_LastScheduledSampleTime; - } - - m_bCorrectedFrameTime = false; - if (PrevTime != -1 && (Time >= PrevTime - ((Duration * 20) / 9) || Time == 0) || ForceFPS != 0.0) { - if (Time - PrevTime > ((Duration * 20) / 9) && Time - PrevTime < Duration * 8 || Time == 0 || ((Time - PrevTime) < (Duration / 11)) || ForceFPS != 0.0) { - // Error!!!! - Time = PrevTime + Duration; - pSample->SetSampleTime(Time); - pSample->SetSampleDuration(Duration); - m_bCorrectedFrameTime = true; - TRACE_EVR("EVR: Corrected invalid sample time\n"); - } - } - if (Time + Duration * 10 < m_LastScheduledSampleTime) { - // Flush when repeating movie - FlushSamplesInternal(); - } -#endif - -#if 0 - static LONGLONG LastDuration = 0; - LONGLONG SetDuration = m_rtTimePerFrame; - pSample->GetSampleDuration(&SetDuration); - if (SetDuration != LastDuration) { - TRACE_EVR("EVR: Old duration: %I64d New duration: %I64d\n", LastDuration, SetDuration); - } - LastDuration = SetDuration; -#endif - m_LastScheduledSampleTime = Time; - - m_ScheduledSamples.AddTail(pSample); - } -} - -void CEVRAllocatorPresenter::FlushSamples() -{ - CAutoLock lock(this); - CAutoLock lock2(&m_SampleQueueLock); - CAutoLock lock3(&m_RenderLock); - - m_pCurrentlyDisplayedSample = nullptr; - m_ScheduledSamples.RemoveAll(); - - m_LastSampleOffset = 0; - m_bLastSampleOffsetValid = false; - m_bSignaledStarvation = false; - m_LastScheduledSampleTime = -1; -} - -HRESULT CEVRAllocatorPresenter::TrackSample(IMFSample* pSample) -{ - HRESULT hr = E_FAIL; - if (CComQIPtr pTracked = pSample) { - hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr); - } - return hr; -} - -HRESULT CEVRAllocatorPresenter::OnSampleFree(IMFAsyncResult* pResult) -{ - CComPtr pObject; - HRESULT hr = pResult->GetObject(&pObject); - if (SUCCEEDED(hr)) { - if (CComQIPtr pSample = pObject) { - // Ignore the sample if it is from an old group - UINT32 nGroupId; - CAutoLock sampleQueueLock(&m_SampleQueueLock); - if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) { - AddToFreeList(pSample, true); - pSample = nullptr; // The sample should not be used after being queued - } - } - } - return hr; -} +/* + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "EVRAllocatorPresenter.h" +#include "OuterEVR.h" +#include +#include "IPinHook.h" +#include "MacrovisionKicker.h" +#include "IMPCVideoDecFilter.h" +#include "Utils.h" +#include "Variables.h" + +#if (0) // Set to 1 to activate EVR traces +#define TRACE_EVR TRACE +#else +#define TRACE_EVR __noop +#endif + +#define MIN_FRAME_TIME 15000 + +enum EVR_STATS_MSG { + MSG_MIXERIN, + MSG_MIXEROUT +}; + +// Guid to tag IMFSample with a group id +static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } }; +// Guid to tag IMFSample with DirectX surface index +static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } }; + + +// === Helper functions +MFOffset MakeOffset(float v) +{ + MFOffset offset; + offset.value = short(v); + offset.fract = WORD(65536 * (v - offset.value)); + return offset; +} + +MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height) +{ + MFVideoArea area; + area.OffsetX = MakeOffset(x); + area.OffsetY = MakeOffset(y); + area.Area.cx = width; + area.Area.cy = height; + return area; +} + +using namespace DSObjects; + +CEVRAllocatorPresenter::CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error, bool isPreview) + : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, true, _Error, isPreview) + , m_ModeratedTime(0) + , m_ModeratedTimeLast(-1) + , m_ModeratedClockLast(-1) + , m_ModeratedTimer(0) + , m_LastClockState(MFCLOCK_STATE_INVALID) + , m_pOuterEVR(nullptr) + , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture) + , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0) + , m_BorderColor(RGB(0, 0, 0)) + , m_hEvtQuit(nullptr) + , m_bEvtQuit(0) + , m_hEvtFlush(nullptr) + , m_bEvtFlush(0) + , m_fUseInternalTimer(false) + , m_LastSetOutputRange(-1) + , m_bPendingRenegotiate(false) + , m_bPendingMediaFinished(false) + , m_hThread(nullptr) + , m_hGetMixerThread(nullptr) + , m_hVSyncThread(nullptr) + , m_nRenderState(Shutdown) + , m_nCurrentGroupId(0) + , m_bLastSampleOffsetValid(false) + , m_LastScheduledSampleTime(-1) + , m_LastScheduledSampleTimeFP(-1) + , m_LastScheduledUncorrectedSampleTime(-1) + , m_MaxSampleDuration(0) + , m_LastSampleOffset(0) + , m_LastPredictedSync(0) + , m_VSyncOffsetHistoryPos(0) + , m_nResetToken(0) + , m_nStepCount(0) + , m_bSignaledStarvation(false) + , m_StarvationClock(0) + , m_SampleFreeCallback(this, &CEVRAllocatorPresenter::OnSampleFree) + , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9") + , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer") + , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface") + , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType") + , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW") + , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority") + , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics") +{ + const CRenderersSettings& r = GetRenderersSettings(); + + ZeroMemory(m_VSyncOffsetHistory, sizeof(m_VSyncOffsetHistory)); + ResetStats(); + + if (FAILED(hr)) { + _Error += L"DX9AllocatorPresenter failed\n"; + return; + } + + if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) { + if (!fnDXVA2CreateDirect3DDeviceManager9) { + _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n"; + } + if (!fnMFCreateDXSurfaceBuffer) { + _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n"; + } + if (!fnMFCreateVideoSampleFromSurface) { + _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n"; + } + if (!fnMFCreateMediaType) { + _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n"; + } + hr = E_FAIL; + return; + } + + // Init DXVA manager + hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager); + if (SUCCEEDED(hr) && m_pD3DManager) { + hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); + if (FAILED(hr)) { + _Error += L"m_pD3DManager->ResetDevice failed\n"; + } + } else { + _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n"; + } + + + // Bufferize frame only with 3D texture! + if (!m_bIsPreview && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { + m_nNbDXSurface = std::max(std::min(r.iEvrBuffers, MAX_VIDEO_SURFACES), 4); + } else { + m_nNbDXSurface = 1; + } +} + +CEVRAllocatorPresenter::~CEVRAllocatorPresenter() +{ + StopWorkerThreads(); // If not already done... + m_pMediaType = nullptr; + m_pClock = nullptr; + m_pD3DManager = nullptr; + + if (m_bHookedNewSegment) { + UnhookNewSegment(); + } +} + +void CEVRAllocatorPresenter::ResetStats() +{ + m_pcFrames = 0; + m_nDroppedUpdate = 0; + m_pcFramesDrawn = 0; + m_piAvg = 0; + m_piDev = 0; +} + +HRESULT CEVRAllocatorPresenter::CheckShutdown() const +{ + if (m_nRenderState == Shutdown) { + return MF_E_SHUTDOWN; + } else { + return S_OK; + } +} + +void CEVRAllocatorPresenter::StartWorkerThreads() +{ + DWORD dwThreadId; + + if (m_nRenderState == Shutdown) { + m_hEvtQuit = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hEvtFlush = CreateEvent(nullptr, TRUE, FALSE, nullptr); + + m_hThread = ::CreateThread(nullptr, 0, PresentThread, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL); + m_hGetMixerThread = ::CreateThread(nullptr, 0, GetMixerThreadStatic, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hGetMixerThread, THREAD_PRIORITY_HIGHEST); + m_hVSyncThread = ::CreateThread(nullptr, 0, VSyncThreadStatic, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hVSyncThread, THREAD_PRIORITY_HIGHEST); + + m_nRenderState = Stopped; + TRACE_EVR("EVR: Worker threads started...\n"); + } +} + +void CEVRAllocatorPresenter::StopWorkerThreads() +{ + if (m_nRenderState != Shutdown) { + SetEvent(m_hEvtFlush); + m_bEvtFlush = true; + SetEvent(m_hEvtQuit); + m_bEvtQuit = true; + if (m_hThread && WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hThread, 0xDEAD); + } + if (m_hGetMixerThread && WaitForSingleObject(m_hGetMixerThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hGetMixerThread, 0xDEAD); + } + if (m_hVSyncThread && WaitForSingleObject(m_hVSyncThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hVSyncThread, 0xDEAD); + } + + SAFE_CLOSE_HANDLE(m_hThread); + SAFE_CLOSE_HANDLE(m_hGetMixerThread); + SAFE_CLOSE_HANDLE(m_hVSyncThread); + SAFE_CLOSE_HANDLE(m_hEvtFlush); + SAFE_CLOSE_HANDLE(m_hEvtQuit); + + m_bEvtFlush = false; + m_bEvtQuit = false; + + TRACE_EVR("EVR: Worker threads stopped...\n"); + } + m_nRenderState = Shutdown; +} + +STDMETHODIMP CEVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + + *ppRenderer = nullptr; + HRESULT hr = S_OK; + + CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; + + COuterEVR* pOuterEVR = DEBUG_NEW COuterEVR(NAME("COuterEVR"), pUnk, hr, &m_VMR9AlphaBitmap, this); + m_pOuterEVR = pOuterEVR; + + pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR); + CComQIPtr pBF = pUnk; + + if (FAILED(hr)) { + return E_FAIL; + } + + // Set EVR custom presenter + CComPtr pVP; + CComPtr pMFVR; + CComQIPtr pMFGS = pBF; + CComQIPtr pConfig = pBF; + if (SUCCEEDED(hr)) { + if (FAILED(pConfig->SetNumberOfStreams(m_bIsPreview?1:3))) { // TODO - maybe need other number of input stream ... + return E_FAIL; + } + } + + hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVR)); + + if (SUCCEEDED(hr)) { + hr = QueryInterface(IID_PPV_ARGS(&pVP)); + } + if (SUCCEEDED(hr)) { + hr = pMFVR->InitializeRenderer(nullptr, pVP); + } + + if (SUCCEEDED(hr)) { + if (!m_bIsPreview) { + CComPtr pPin = GetFirstPin(pBF); + if (HookNewSegment((IPinC*)(IPin*)pPin)) { + m_fUseInternalTimer = true; + m_bHookedNewSegment = true; + }; + } + *ppRenderer = pBF.Detach(); + } else { + *ppRenderer = nullptr; + } + + return hr; +} + +STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(bool bAll) +{ + return __super::Paint(bAll); +} + +STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(IMFSample* pMFSample) +{ + CAutoLock lock(&m_RenderLock); + + m_pCurrentlyDisplayedSample = pMFSample; + pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface); + + auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { + UINT32 nGroupId; + return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); + }; + ASSERT(sampleHasCurrentGroupId(pMFSample)); + + return Paint(true); +} + +STDMETHODIMP CEVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + HRESULT hr; + if (riid == __uuidof(IMFClockStateSink)) { + hr = GetInterface((IMFClockStateSink*)this, ppv); + } else if (riid == __uuidof(IMFVideoPresenter)) { + hr = GetInterface((IMFVideoPresenter*)this, ppv); + } else if (riid == __uuidof(IMFTopologyServiceLookupClient)) { + hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv); + } else if (riid == __uuidof(IMFVideoDeviceID)) { + hr = GetInterface((IMFVideoDeviceID*)this, ppv); + } else if (riid == __uuidof(IMFGetService)) { + hr = GetInterface((IMFGetService*)this, ppv); + } else if (riid == __uuidof(IMFAsyncCallback)) { + hr = GetInterface((IMFAsyncCallback*)this, ppv); + } else if (riid == __uuidof(IMFVideoDisplayControl)) { + hr = GetInterface((IMFVideoDisplayControl*)this, ppv); + } else if (riid == __uuidof(IMFVideoMixerBitmap)) { + hr = GetInterface((IMFVideoMixerBitmap*)this, ppv); + } else if (riid == __uuidof(IEVRTrustedVideoPlugin)) { + hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv); + } else if (riid == IID_IQualProp) { + hr = GetInterface((IQualProp*)this, ppv); + } else if (riid == __uuidof(IMFRateSupport)) { + hr = GetInterface((IMFRateSupport*)this, ppv); + } else if (riid == __uuidof(IDirect3DDeviceManager9)) + // hr = GetInterface((IDirect3DDeviceManager9*)this, ppv); + { + hr = m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppv); + } else if (riid == __uuidof(ID3DFullscreenControl)) { + hr = GetInterface((ID3DFullscreenControl*)this, ppv); + } else { + hr = __super::NonDelegatingQueryInterface(riid, ppv); + } + + return hr; +} + +// IMFClockStateSink +STDMETHODIMP CEVRAllocatorPresenter::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + + m_nRenderState = Started; + + TRACE_EVR("EVR: OnClockStart hnsSystemTime = %I64d, llClockStartOffset = %I64d\n", hnsSystemTime, llClockStartOffset); + m_ModeratedTimeLast = -1; + m_ModeratedClockLast = -1; + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::OnClockStop(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + + TRACE_EVR("EVR: OnClockStop hnsSystemTime = %I64d\n", hnsSystemTime); + m_nRenderState = Stopped; + + m_ModeratedClockLast = -1; + m_ModeratedTimeLast = -1; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::OnClockPause(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + + TRACE_EVR("EVR: OnClockPause hnsSystemTime = %I64d\n", hnsSystemTime); + if (!m_bSignaledStarvation) { + m_nRenderState = Paused; + } + m_ModeratedTimeLast = -1; + m_ModeratedClockLast = -1; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::OnClockRestart(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + + m_nRenderState = Started; + + m_ModeratedTimeLast = -1; + m_ModeratedClockLast = -1; + TRACE_EVR("EVR: OnClockRestart hnsSystemTime = %I64d\n", hnsSystemTime); + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::OnClockSetRate(MFTIME hnsSystemTime, float flRate) +{ + ASSERT(FALSE); + return E_NOTIMPL; +} + +// IBaseFilter delegate +bool CEVRAllocatorPresenter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue) +{ + CAutoLock lock(&m_SampleQueueLock); + + if (m_bSignaledStarvation) { + size_t nSamples = std::max(m_nNbDXSurface / 2, 1); + if ((m_ScheduledSamples.GetCount() < nSamples || m_LastSampleOffset < -m_rtTimePerFrame * 2) && !g_bNoDuration) { + *State = (FILTER_STATE)Paused; + _ReturnValue = VFW_S_STATE_INTERMEDIATE; + return true; + } + m_bSignaledStarvation = false; + } + return false; +} + +// IQualProp +STDMETHODIMP CEVRAllocatorPresenter::get_FramesDroppedInRenderer(int* pcFrames) +{ + *pcFrames = m_pcFrames; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_FramesDrawn(int* pcFramesDrawn) +{ + *pcFramesDrawn = m_pcFramesDrawn; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_AvgFrameRate(int* piAvgFrameRate) +{ + *piAvgFrameRate = (int)(m_fAvrFps * 100); + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_Jitter(int* iJitter) +{ + *iJitter = (int)((m_fJitterStdDev / 10000.0) + 0.5); + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_AvgSyncOffset(int* piAvg) +{ + *piAvg = (int)((m_fSyncOffsetAvr / 10000.0) + 0.5); + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::get_DevSyncOffset(int* piDev) +{ + *piDev = (int)((m_fSyncOffsetStdDev / 10000.0) + 0.5); + return S_OK; +} + +// IMFRateSupport + +STDMETHODIMP CEVRAllocatorPresenter::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) +{ + // TODO : not finished... + *pflRate = 0; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) +{ + HRESULT hr = S_OK; + float fMaxRate = 0.0f; + + CAutoLock lock(this); + + CheckPointer(pflRate, E_POINTER); + CHECK_HR(CheckShutdown()); + + // Get the maximum forward rate. + fMaxRate = GetMaxRate(fThin); + + // For reverse playback, swap the sign. + if (eDirection == MFRATE_REVERSE) { + fMaxRate = -fMaxRate; + } + + *pflRate = fMaxRate; + + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate) +{ + // fRate can be negative for reverse playback. + // pfNearestSupportedRate can be NULL. + + CAutoLock lock(this); + + HRESULT hr = S_OK; + float fMaxRate = 0.0f; + float fNearestRate = flRate; // Default. + + CheckPointer(pflNearestSupportedRate, E_POINTER); + CHECK_HR(CheckShutdown()); + + // Find the maximum forward rate. + fMaxRate = GetMaxRate(fThin); + + if (fabsf(flRate) > fMaxRate) { + // The (absolute) requested rate exceeds the maximum rate. + hr = MF_E_UNSUPPORTED_RATE; + + // The nearest supported rate is fMaxRate. + fNearestRate = fMaxRate; + if (flRate < 0) { + // For reverse playback, swap the sign. + fNearestRate = -fNearestRate; + } + } + + // Return the nearest supported rate if the caller requested it. + if (pflNearestSupportedRate != nullptr) { + *pflNearestSupportedRate = fNearestRate; + } + + return hr; +} + +float CEVRAllocatorPresenter::GetMaxRate(BOOL bThin) +{ + float fMaxRate = FLT_MAX; // Default. + UINT32 fpsNumerator = 0, fpsDenominator = 0; + + if (!bThin && (m_pMediaType != nullptr)) { + // Non-thinned: Use the frame rate and monitor refresh rate. + + // Frame rate: + MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE, + &fpsNumerator, &fpsDenominator); + + // Monitor refresh rate: + UINT MonitorRateHz = m_refreshRate; // D3DDISPLAYMODE + + if (fpsDenominator && fpsNumerator && MonitorRateHz) { + // Max Rate = Refresh Rate / Frame Rate + fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator); + } + } + return fMaxRate; +} + +void CEVRAllocatorPresenter::CompleteFrameStep(bool bCancel) +{ + if (m_nStepCount > 0) { + if (bCancel || (m_nStepCount == 1)) { + m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0); + m_nStepCount = 0; + } else { + m_nStepCount--; + } + } +} + +// IMFVideoPresenter +STDMETHODIMP CEVRAllocatorPresenter::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) +{ + HRESULT hr = S_OK; + CHECK_HR(CheckShutdown()); + + switch (eMessage) { + case MFVP_MESSAGE_BEGINSTREAMING: // The EVR switched from stopped to paused. The presenter should allocate resources + m_nRenderState = Paused; + ResetStats(); + TRACE_EVR("EVR: MFVP_MESSAGE_BEGINSTREAMING\n"); + break; + + case MFVP_MESSAGE_CANCELSTEP: // Cancels a frame step + TRACE_EVR("EVR: MFVP_MESSAGE_CANCELSTEP\n"); + CompleteFrameStep(true); + break; + + case MFVP_MESSAGE_ENDOFSTREAM: // All input streams have ended. + TRACE_EVR("EVR: MFVP_MESSAGE_ENDOFSTREAM\n"); + m_bPendingMediaFinished = true; + break; + + case MFVP_MESSAGE_ENDSTREAMING: // The EVR switched from running or paused to stopped. The presenter should free resources + m_nRenderState = Stopped; + TRACE_EVR("EVR: MFVP_MESSAGE_ENDSTREAMING\n"); + break; + + case MFVP_MESSAGE_FLUSH: // The presenter should discard any pending samples + SetEvent(m_hEvtFlush); + m_bEvtFlush = true; + TRACE_EVR("EVR: MFVP_MESSAGE_FLUSH\n"); + while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0) { + ; + } + break; + + case MFVP_MESSAGE_INVALIDATEMEDIATYPE: // The mixer's output format has changed. The EVR will initiate format negotiation, as described previously + /* + 1) The EVR sets the media type on the reference stream. + 2) The EVR calls IMFVideoPresenter::ProcessMessage on the presenter with the MFVP_MESSAGE_INVALIDATEMEDIATYPE message. + 3) The presenter sets the media type on the mixer's output stream. + 4) The EVR sets the media type on the substreams. + */ + m_bPendingRenegotiate = true; + while (m_bPendingRenegotiate) { + Sleep(1); + } + break; + + case MFVP_MESSAGE_PROCESSINPUTNOTIFY: // One input stream on the mixer has received a new sample + // GetImageFromMixer(); + break; + + case MFVP_MESSAGE_STEP: // Requests a frame step. + TRACE_EVR("EVR: MFVP_MESSAGE_STEP\n"); + m_nStepCount = (int)ulParam; + hr = S_OK; + break; + + default: + ASSERT(FALSE); + break; + } + return hr; +} + +HRESULT CEVRAllocatorPresenter::IsMediaTypeSupported(IMFMediaType* pMixerType) +{ + HRESULT hr; + + // We support only video types + GUID MajorType; + hr = pMixerType->GetMajorType(&MajorType); + + if (SUCCEEDED(hr)) { + if (MajorType != MFMediaType_Video) { + hr = MF_E_INVALIDMEDIATYPE; + } + } + + // We support only progressive formats + MFVideoInterlaceMode InterlaceMode = MFVideoInterlace_Unknown; + + if (SUCCEEDED(hr)) { + hr = pMixerType->GetUINT32(MF_MT_INTERLACE_MODE, (UINT32*)&InterlaceMode); + } + + if (SUCCEEDED(hr)) { + if (InterlaceMode != MFVideoInterlace_Progressive) { + hr = MF_E_INVALIDMEDIATYPE; + } + } + + // Check whether we support the surface format + int Merit = 0; + + if (SUCCEEDED(hr)) { + hr = GetMediaTypeMerit(pMixerType, &Merit); + } + + if (SUCCEEDED(hr)) { + if (Merit == 0) { + hr = MF_E_INVALIDMEDIATYPE; + } + } + + return hr; +} + +HRESULT CEVRAllocatorPresenter::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType) +{ + HRESULT hr; + IMFMediaType* pOptimalMediaType; + + CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType)); + CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType)); + + const GUID colorAttributes[] = { + MF_MT_VIDEO_LIGHTING, + MF_MT_VIDEO_PRIMARIES, + MF_MT_TRANSFER_FUNCTION, + MF_MT_YUV_MATRIX, + MF_MT_VIDEO_CHROMA_SITING + }; + + auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) { + PROPVARIANT val; + HRESULT hr = pFrom->GetItem(guidKey, &val); + + if (SUCCEEDED(hr)) { + hr = pTo->SetItem(guidKey, val); + PropVariantClear(&val); + } else if (hr == MF_E_ATTRIBUTENOTFOUND) { + hr = pTo->DeleteItem(guidKey); + } + return hr; + }; + + for (REFGUID guidKey : colorAttributes) { + if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) { + TRACE_EVR(_T("Copying color attribute %s failed: 0x%08x\n"), CComBSTR(guidKey), hr); + } + } + + pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0); + + const CRenderersSettings& r = GetRenderersSettings(); + + UINT32 nominalRange; + if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)) + && nominalRange == MFNominalRange_0_255) { + // EVR mixer always assumes 16-235 input. Bug? + // To keep untouched 0-255 range and avoid unwanted expansion we need to request 16-235 as output. + // To get 16-235 output we need to request 48-208 as output. + nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_48_208 : MFNominalRange_16_235; + } else { + nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255; + } + pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange); + m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange; + + ULARGE_INTEGER ui64Size; + pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart); + + CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart); + MFVideoArea Area = MakeArea(0, 0, videoSize.cx, videoSize.cy); + pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea)); + + ULARGE_INTEGER ui64AspectRatio; + pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart); + + UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart; + UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart; + UINT64 gcd = GCD(ui64ARx, ui64ARy); + if (gcd > 1) { + ui64ARx /= gcd; + ui64ARy /= gcd; + } + + CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy); + if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) { + SetVideoSize(videoSize, aspectRatio); + + // Notify the graph about the change + if (m_pSink) { + m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_nativeVideoSize.cx, m_nativeVideoSize.cy), 0); + } + } + + *ppType = pOptimalMediaType; + (*ppType)->AddRef(); + + return hr; +} + +HRESULT CEVRAllocatorPresenter::SetMediaType(IMFMediaType* pType) +{ + HRESULT hr = S_OK; + AM_MEDIA_TYPE* pAMMedia = nullptr; + + CHECK_HR(CheckShutdown()); + + if (!pType) { + // Release + RemoveAllSamples(); + DeleteSurfaces(); + CAutoLock lock(&m_MediaTypeLock); + m_pMediaType = nullptr; + return hr; + } + + DWORD dwFlags = 0; + if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) { + // Nothing to do + return hr; + } + + CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); + + hr = InitializeDevice(pType); + if (SUCCEEDED(hr)) { + CAutoLock lock(&m_MediaTypeLock); + m_pMediaType = pType; + + CString strTemp = GetMediaTypeName(pAMMedia->subtype); + strTemp.Replace(L"MEDIASUBTYPE_", L""); + CString strTemp1 = GetMediaTypeFormatDesc(pType); + strTemp1.Replace(L"D3DFMT_", L""); + m_strStatsMsg[MSG_MIXEROUT].Format(L"Mixer output : %-10s Type %-10s", strTemp.GetString(), strTemp1.GetString()); + } + + pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); + + return hr; +} + +HRESULT CEVRAllocatorPresenter::GetMediaTypeFourCC(IMFMediaType* pType, DWORD* pFourCC) +{ + CheckPointer(pFourCC, E_POINTER); + + HRESULT hr = S_OK; + GUID guidSubType = GUID_NULL; + + if (SUCCEEDED(hr)) { + hr = pType->GetGUID(MF_MT_SUBTYPE, &guidSubType); + } + + if (SUCCEEDED(hr)) { + *pFourCC = guidSubType.Data1; + } + + return hr; +} + +HRESULT CEVRAllocatorPresenter::GetMediaTypeMerit(IMFMediaType* pType, int* pMerit) +{ + DWORD Format; + HRESULT hr = GetMediaTypeFourCC(pType, &Format); + + if (SUCCEEDED(hr)) { + switch (Format) { + case FCC('AI44'): // Palettized, 4:4:4 + *pMerit = 31; + break; + case FCC('YVU9'): // 8-bit, 16:1:1 + *pMerit = 30; + break; + case FCC('NV11'): // 8-bit, 4:1:1 + *pMerit = 29; + break; + case FCC('Y41P'): + *pMerit = 28; + break; + case FCC('Y41T'): + *pMerit = 27; + break; + case FCC('P016'): // 4:2:0 + *pMerit = 26; + break; + case FCC('P010'): + *pMerit = 25; + break; + case FCC('IMC1'): + *pMerit = 24; + break; + case FCC('IMC3'): + *pMerit = 23; + break; + case FCC('IMC2'): + *pMerit = 22; + break; + case FCC('IMC4'): + *pMerit = 21; + break; + case FCC('YV12'): + *pMerit = 20; + break; + case FCC('NV12'): + *pMerit = 19; + break; + case FCC('I420'): + *pMerit = 18; + break; + case FCC('IYUV'): + *pMerit = 17; + break; + case FCC('Y216'): // 4:2:2 + *pMerit = 16; + break; + case FCC('v216'): + *pMerit = 15; + break; + case FCC('P216'): + *pMerit = 14; + break; + case FCC('Y210'): + *pMerit = 13; + break; + case FCC('v210'): + *pMerit = 12; + break; + case FCC('P210'): + *pMerit = 11; + break; + case FCC('YUY2'): + *pMerit = 10; + break; + case FCC('UYVY'): + *pMerit = 9; + break; + case FCC('Y42T'): + *pMerit = 8; + break; + case FCC('YVYU'): + *pMerit = 7; + break; + case FCC('Y416'): // 4:4:4 + *pMerit = 6; + break; + case FCC('Y410'): + *pMerit = 5; + break; + case FCC('v410'): + *pMerit = 4; + break; + case FCC('AYUV'): + *pMerit = 3; + break; + case D3DFMT_X8R8G8B8: + if (m_bForceInputHighColorResolution) { + *pMerit = 63; + } else { + *pMerit = 1; + } + break; + case D3DFMT_A8R8G8B8: // an accepted format, but fails on most surface types + case D3DFMT_A8B8G8R8: + case D3DFMT_X8B8G8R8: + case D3DFMT_R8G8B8: + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + case D3DFMT_A4R4G4B4: + case D3DFMT_R3G3B2: + case D3DFMT_A8R3G3B2: + case D3DFMT_X4R4G4B4: + case D3DFMT_A8P8: + case D3DFMT_P8: + *pMerit = 0; + break; + default: + *pMerit = 2; + break; + } + } + + return hr; +} + +LPCTSTR FindD3DFormat(const D3DFORMAT Format); + +LPCTSTR CEVRAllocatorPresenter::GetMediaTypeFormatDesc(IMFMediaType* pMediaType) +{ + D3DFORMAT Format = D3DFMT_UNKNOWN; + GetMediaTypeFourCC(pMediaType, (DWORD*)&Format); + return FindD3DFormat(Format); +} + +HRESULT CEVRAllocatorPresenter::RenegotiateMediaType() +{ + HRESULT hr = S_OK; + + CComPtr pMixerType; + CComPtr pMixerInputType; + CComPtr pType; + + if (!m_pMixer) { + return MF_E_INVALIDREQUEST; + } + + CInterfaceArray ValidMixerTypes; + + // Get the mixer's input type + hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType); + if (SUCCEEDED(hr)) { + AM_MEDIA_TYPE* pMT; + hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT); + if (SUCCEEDED(hr)) { + m_inputMediaType = *pMT; + pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT); + } + } + + // Loop through all of the mixer's proposed output types. + DWORD iTypeIndex = 0; + while ((hr != MF_E_NO_MORE_TYPES)) { + pMixerType = nullptr; + pType = nullptr; + + // Step 1. Get the next media type supported by mixer. + hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType); + if (FAILED(hr)) { + break; + } + + // Step 2. Check if we support this media type. + if (SUCCEEDED(hr)) { + hr = IsMediaTypeSupported(pMixerType); + } + + if (SUCCEEDED(hr)) { + hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType); + } + + // Step 4. Check if the mixer will accept this media type. + if (SUCCEEDED(hr)) { + hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY); + } + + int Merit = 0; + if (SUCCEEDED(hr)) { + hr = GetMediaTypeMerit(pType, &Merit); + } + + if (SUCCEEDED(hr)) { + size_t nTypes = ValidMixerTypes.GetCount(); + size_t iInsertPos = 0; + for (size_t i = 0; i < nTypes; ++i) { + int ThisMerit; + GetMediaTypeMerit(ValidMixerTypes[i], &ThisMerit); + + if (Merit > ThisMerit) { + iInsertPos = i; + break; + } else { + iInsertPos = i + 1; + } + } + + ValidMixerTypes.InsertAt(iInsertPos, pType); + } + } + + + size_t nValidTypes = ValidMixerTypes.GetCount(); +#ifdef _DEBUG + for (size_t i = 0; i < nValidTypes; ++i) { + // Step 3. Adjust the mixer's type to match our requirements. + pType = ValidMixerTypes[i]; + TRACE_EVR("EVR: Valid mixer output type: %ws\n", GetMediaTypeFormatDesc(pType)); + } +#endif + for (size_t i = 0; i < nValidTypes; ++i) { + // Step 4. Adjust the mixer's type to match our requirements. + pType = ValidMixerTypes[i]; + + TRACE_EVR("EVR: Trying mixer output type: %ws\n", GetMediaTypeFormatDesc(pType)); + + // Step 5. Try to set the media type on ourselves. + hr = SetMediaType(pType); + + // Step 6. Set output media type on mixer. + if (SUCCEEDED(hr)) { + hr = m_pMixer->SetOutputType(0, pType, 0); + + // If something went wrong, clear the media type. + if (FAILED(hr)) { + SetMediaType(nullptr); + } else { + break; + } + } + } + + pMixerType = nullptr; + pType = nullptr; + return hr; +} + +bool CEVRAllocatorPresenter::GetImageFromMixer() +{ + MFT_OUTPUT_DATA_BUFFER dataBuffer; + HRESULT hr = S_OK; + DWORD dwStatus; + REFERENCE_TIME nsSampleTime; + LONGLONG llClockBefore = 0; + LONGLONG llClockAfter = 0; + LONGLONG llMixerLatency; + UINT dwSurface; + + bool bDoneSomething = false; + + auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { + UINT32 nGroupId; + return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); + }; + + while (SUCCEEDED(hr)) { + CComPtr pSample; + + if (FAILED(GetFreeSample(&pSample))) { + break; + } + + ZeroMemory(&dataBuffer, sizeof(dataBuffer)); + dataBuffer.pSample = pSample; + pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface); + ASSERT(sampleHasCurrentGroupId(pSample)); + + { + llClockBefore = GetRenderersData()->GetPerfCounter(); + if (!m_pMixer) { + ASSERT(FALSE); + break; + } + hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus); + llClockAfter = GetRenderersData()->GetPerfCounter(); + } + + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { + AddToFreeList(pSample, false); + pSample = nullptr; // The sample should not be used after being queued + // Important: Release any events returned from the ProcessOutput method. + SAFE_RELEASE(dataBuffer.pEvents); + break; + } + + if (m_pSink) { + //CAutoLock autolock(this); We shouldn't need to lock here, m_pSink is thread safe + llMixerLatency = llClockAfter - llClockBefore; + m_pSink->Notify(EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0); + } + + pSample->GetSampleTime(&nsSampleTime); + REFERENCE_TIME nsDuration; + pSample->GetSampleDuration(&nsDuration); + + if (GetRenderersData()->m_bTearingTest) { + RECT rcTearing; + + rcTearing.left = m_nTearingPos; + rcTearing.top = 0; + rcTearing.right = rcTearing.left + 4; + rcTearing.bottom = m_nativeVideoSize.cy; + m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + + rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; + rcTearing.right = rcTearing.left + 4; + m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; + } + + TRACE_EVR("EVR: Get from Mixer : %u (%I64d) (%I64d)\n", dwSurface, nsSampleTime, m_rtTimePerFrame ? nsSampleTime / m_rtTimePerFrame : 0); + + if (SUCCEEDED(TrackSample(pSample))) { + AddToScheduledList(pSample, false); + pSample = nullptr; // The sample should not be used after being queued + bDoneSomething = true; + } else { + ASSERT(FALSE); + } + + // Important: Release any events returned from the ProcessOutput method. + SAFE_RELEASE(dataBuffer.pEvents); + + if (m_rtTimePerFrame == 0) { + break; + } + } + + return bDoneSomething; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType) +{ + HRESULT hr = S_OK; + CAutoLock lock(&m_MediaTypeLock); + + CheckPointer(ppMediaType, E_POINTER); + CHECK_HR(CheckShutdown()); + + if (!m_pMediaType) { + return MF_E_NOT_INITIALIZED; + } + + CHECK_HR(m_pMediaType->QueryInterface(IID_PPV_ARGS(ppMediaType))); + + return hr; +} + +// IMFTopologyServiceLookupClient +STDMETHODIMP CEVRAllocatorPresenter::InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup) +{ + HRESULT hr = S_OK; + DWORD dwObjects = 1; + + CAutoLock cThreadsLock(&m_ThreadsLock); + + TRACE_EVR("EVR: CEVRAllocatorPresenter::InitServicePointers\n"); + CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, + IID_PPV_ARGS(&m_pMixer), &dwObjects)); + + CHECK_HR(pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, + IID_PPV_ARGS(&m_pSink), &dwObjects)); + + pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, + IID_PPV_ARGS(&m_pClock), &dwObjects); + + + StartWorkerThreads(); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::ReleaseServicePointers() +{ + TRACE_EVR("EVR: CEVRAllocatorPresenter::ReleaseServicePointers\n"); + CAutoLock cThreadsLock(&m_ThreadsLock); + + StopWorkerThreads(); + + m_pMixer.Release(); + m_pSink.Release(); + m_pClock.Release(); + return S_OK; +} + +// IMFVideoDeviceID +STDMETHODIMP CEVRAllocatorPresenter::GetDeviceID(/* [out] */ __out IID* pDeviceID) +{ + CheckPointer(pDeviceID, E_POINTER); + *pDeviceID = IID_IDirect3DDevice9; + return S_OK; +} + +// IMFGetService +STDMETHODIMP CEVRAllocatorPresenter::GetService(/* [in] */ __RPC__in REFGUID guidService, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject) +{ + if (guidService == MR_VIDEO_RENDER_SERVICE) { + return NonDelegatingQueryInterface(riid, ppvObject); + } else if (guidService == MR_VIDEO_ACCELERATION_SERVICE) { + return m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppvObject); + } + + return E_NOINTERFACE; +} + +// IMFAsyncCallback +STDMETHODIMP CEVRAllocatorPresenter::GetParameters(/* [out] */ __RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CEVRAllocatorPresenter::Invoke(/* [in] */ __RPC__in_opt IMFAsyncResult* pAsyncResult) +{ + return E_NOTIMPL; +} + +// IMFVideoDisplayControl +STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) +{ + if (pszVideo) { + pszVideo->cx = m_nativeVideoSize.cx; + pszVideo->cy = m_nativeVideoSize.cy; + } + if (pszARVideo) { + pszARVideo->cx = m_aspectRatio.cx; + pszARVideo->cy = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) +{ + if (pszMin) { + pszMin->cx = 1; + pszMin->cy = 1; + } + + if (pszMax) { + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + + if (SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D), &d3ddm))) { + pszMax->cx = d3ddm.Width; + pszMax->cy = d3ddm.Height; + } + } + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) +{ + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) +{ + // Always all source rectangle ? + if (pnrcSource) { + pnrcSource->left = 0.0; + pnrcSource->top = 0.0; + pnrcSource->right = 1.0; + pnrcSource->bottom = 1.0; + } + + if (prcDest) { + memcpy(prcDest, &m_videoRect, sizeof(m_videoRect)); //GetClientRect (m_hWnd, prcDest); + } + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetAspectRatioMode(DWORD dwAspectRatioMode) +{ + m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetAspectRatioMode(DWORD* pdwAspectRatioMode) +{ + CheckPointer(pdwAspectRatioMode, E_POINTER); + *pdwAspectRatioMode = m_dwVideoAspectRatioMode; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetVideoWindow(HWND hwndVideo) +{ + if (m_hWnd != hwndVideo) { + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_RenderLock); + + m_hWnd = hwndVideo; + m_bPendingResetDevice = true; + if (m_pSink) { + m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); + } + SendResetRequest(); + } + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetVideoWindow(HWND* phwndVideo) +{ + CheckPointer(phwndVideo, E_POINTER); + *phwndVideo = m_hWnd; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::RepaintVideo() +{ + Paint(true); + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetCurrentImage(BITMAPINFOHEADER *pBih, BYTE **pDib, DWORD *pcbDib, LONGLONG *pTimeStamp) +{ + if (!pBih || !pDib || !pcbDib) { + return E_POINTER; + } + CheckPointer(m_pD3DDevEx, E_ABORT); + + HRESULT hr = S_OK; + const unsigned width = m_windowRect.Width(); + const unsigned height = m_windowRect.Height(); + const unsigned len = width * height * 4; + + memset(pBih, 0, sizeof(BITMAPINFOHEADER)); + pBih->biSize = sizeof(BITMAPINFOHEADER); + pBih->biWidth = width; + pBih->biHeight = height; + pBih->biBitCount = 32; + pBih->biPlanes = 1; + pBih->biSizeImage = DIBSIZE(*pBih); + + BYTE* p = (BYTE*)CoTaskMemAlloc(len); // only this allocator can be used + if (!p) { + return E_OUTOFMEMORY; + } + + CComPtr pBackBuffer; + CComPtr pDestSurface; + D3DLOCKED_RECT r; + if (FAILED(hr = m_pD3DDevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)) + || FAILED(hr = m_pD3DDevEx->CreateRenderTarget(width, height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pDestSurface, nullptr)) + || (FAILED(hr = m_pD3DDevEx->StretchRect(pBackBuffer, m_windowRect, pDestSurface, nullptr, D3DTEXF_NONE))) + || (FAILED(hr = pDestSurface->LockRect(&r, nullptr, D3DLOCK_READONLY)))) { + CString Error = GetWindowsErrorMessage(hr, nullptr); + TRACE_EVR(L"CEVRAllocatorPresenter::GetCurrentImage failed : %s", S_OK == hr ? L"S_OK" : Error.GetBuffer()); + CoTaskMemFree(p); + return hr; + } + + RetrieveBitmapData(width, height, 32, p, (BYTE*)r.pBits, r.Pitch); + + pDestSurface->UnlockRect(); + + *pDib = p; + *pcbDib = len; + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetBorderColor(COLORREF Clr) +{ + m_BorderColor = Clr; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetBorderColor(COLORREF* pClr) +{ + CheckPointer(pClr, E_POINTER); + *pClr = m_BorderColor; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetRenderingPrefs(DWORD dwRenderFlags) +{ + m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetRenderingPrefs(DWORD* pdwRenderFlags) +{ + CheckPointer(pdwRenderFlags, E_POINTER); + *pdwRenderFlags = m_dwVideoRenderPrefs; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetFullscreen(BOOL fFullscreen) +{ + m_bIsFullscreen = !!fFullscreen; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetFullscreen(BOOL* pfFullscreen) +{ + CheckPointer(pfFullscreen, E_POINTER); + *pfFullscreen = m_bIsFullscreen; + return S_OK; +} + +// IMFVideoMixerBitmap +STDMETHODIMP CEVRAllocatorPresenter::ClearAlphaBitmap() +{ + CAutoLock cRenderLock(&m_RenderLock); + m_bAlphaBitmapEnable = false; + + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetAlphaBitmapParameters(MFVideoAlphaBitmapParams *pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock cRenderLock(&m_RenderLock); + + if (m_bAlphaBitmapEnable && m_pAlphaBitmapTexture) { + *pBmpParms = m_AlphaBitmapParams; // formal implementation, don't believe it + return S_OK; + } else { + return MF_E_NOT_INITIALIZED; + } +} + +STDMETHODIMP CEVRAllocatorPresenter::SetAlphaBitmap(const MFVideoAlphaBitmap *pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock cRenderLock(&m_RenderLock); + + CheckPointer(m_pD3DDevEx, E_ABORT); + HRESULT hr = S_OK; + + if (pBmpParms->GetBitmapFromDC && pBmpParms->bitmap.hdc) { + HBITMAP hBitmap = (HBITMAP)GetCurrentObject(pBmpParms->bitmap.hdc, OBJ_BITMAP); + if (!hBitmap) { + return E_INVALIDARG; + } + DIBSECTION info = { 0 }; + if (!::GetObjectW(hBitmap, sizeof(DIBSECTION), &info)) { + return E_INVALIDARG; + } + BITMAP& bm = info.dsBm; + if (!bm.bmWidth || !bm.bmHeight || bm.bmBitsPixel != 32 || !bm.bmBits) { + return E_INVALIDARG; + } + + if (m_pAlphaBitmapTexture) { + D3DSURFACE_DESC desc = {}; + m_pAlphaBitmapTexture->GetLevelDesc(0, &desc); + if (bm.bmWidth != desc.Width || bm.bmHeight != desc.Height) { + m_pAlphaBitmapTexture.Release(); + } + } + + if (!m_pAlphaBitmapTexture) { + hr = m_pD3DDevEx->CreateTexture(bm.bmWidth, bm.bmHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pAlphaBitmapTexture, nullptr); + } + + if (SUCCEEDED(hr)) { + CComPtr pSurface; + hr = m_pAlphaBitmapTexture->GetSurfaceLevel(0, &pSurface); + if (SUCCEEDED(hr)) { + D3DLOCKED_RECT lr; + hr = pSurface->LockRect(&lr, nullptr, D3DLOCK_DISCARD); + if (S_OK == hr) { + if (bm.bmWidthBytes == lr.Pitch) { + memcpy(lr.pBits, bm.bmBits, bm.bmWidthBytes * bm.bmHeight); + } + else { + LONG linesize = std::min(bm.bmWidthBytes, (LONG)lr.Pitch); + BYTE* src = (BYTE*)bm.bmBits; + BYTE* dst = (BYTE*)lr.pBits; + for (LONG y = 0; y < bm.bmHeight; ++y) { + memcpy(dst, src, linesize); + src += bm.bmWidthBytes; + dst += lr.Pitch; + } + } + hr = pSurface->UnlockRect(); + } + } + } + } else { + return E_INVALIDARG; + } + + m_bAlphaBitmapEnable = SUCCEEDED(hr) && m_pAlphaBitmapTexture; + + if (m_bAlphaBitmapEnable) { + hr = UpdateAlphaBitmapParameters(&pBmpParms->params); + } + + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams *pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock cRenderLock(&m_RenderLock); + + m_AlphaBitmapParams = *pBmpParms; // formal implementation, don't believe it + + return S_OK; +} + +// IEVRTrustedVideoPlugin +STDMETHODIMP CEVRAllocatorPresenter::IsInTrustedVideoMode(BOOL* pYes) +{ + CheckPointer(pYes, E_POINTER); + *pYes = TRUE; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::CanConstrict(BOOL* pYes) +{ + CheckPointer(pYes, E_POINTER); + *pYes = TRUE; + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::SetConstriction(DWORD dwKPix) +{ + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::DisableImageExport(BOOL bDisable) +{ + return S_OK; +} + + +// IDirect3DDeviceManager9 +STDMETHODIMP CEVRAllocatorPresenter::ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken) +{ + HRESULT hr = m_pD3DManager->ResetDevice(pDevice, resetToken); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::OpenDeviceHandle(HANDLE* phDevice) +{ + HRESULT hr = m_pD3DManager->OpenDeviceHandle(phDevice); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::CloseDeviceHandle(HANDLE hDevice) +{ + HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::TestDevice(HANDLE hDevice) +{ + HRESULT hr = m_pD3DManager->TestDevice(hDevice); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock) +{ + HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::UnlockDevice(HANDLE hDevice, BOOL fSaveState) +{ + HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState); + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetVideoService(HANDLE hDevice, REFIID riid, void** ppService) +{ + HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService); + + if (riid == __uuidof(IDirectXVideoDecoderService)) { + UINT nNbDecoder = 5; + GUID* pDecoderGuid; + IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService; + pDXVAVideoDecoder->GetDecoderDeviceGuids(&nNbDecoder, &pDecoderGuid); + } else if (riid == __uuidof(IDirectXVideoProcessorService)) { + IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService; + UNREFERENCED_PARAMETER(pDXVAProcessor); + } + + return hr; +} + +STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) +{ + // This function should be called... + ASSERT(FALSE); + + if (lpWidth) { + *lpWidth = m_nativeVideoSize.cx; + } + if (lpHeight) { + *lpHeight = m_nativeVideoSize.cy; + } + if (lpARWidth) { + *lpARWidth = m_aspectRatio.cx; + } + if (lpARHeight) { + *lpARHeight = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CEVRAllocatorPresenter::InitializeDevice(IMFMediaType* pMediaType) +{ + HRESULT hr; + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_RenderLock); + + RemoveAllSamples(); + DeleteSurfaces(); + + // Retrieve the surface size and format + UINT32 Width; + UINT32 Height; + hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &Width, &Height); + + D3DFORMAT Format; + if (SUCCEEDED(hr)) { + SetVideoSize(CSize(Width, Height), m_aspectRatio); + hr = GetMediaTypeFourCC(pMediaType, (DWORD*)&Format); + } + + if (SUCCEEDED(hr)) { + hr = AllocSurfaces(); + } + + if (SUCCEEDED(hr)) { + for (int i = 0; i < m_nNbDXSurface; i++) { + CComPtr pMFSample; + hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); + + if (SUCCEEDED(hr)) { + pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); + pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + m_FreeSamples.AddTail(pMFSample); + pMFSample = nullptr; // The sample should not be used after being queued + } + ASSERT(SUCCEEDED(hr)); + } + } + + return hr; +} + +DWORD WINAPI CEVRAllocatorPresenter::GetMixerThreadStatic(LPVOID lpParam) +{ + SetThreadName(DWORD(-1), "CEVRPresenter::MixerThread"); + CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; + pThis->GetMixerThread(); + return 0; +} + +DWORD WINAPI CEVRAllocatorPresenter::PresentThread(LPVOID lpParam) +{ + SetThreadName(DWORD(-1), "CEVRPresenter::PresentThread"); + CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; + pThis->RenderThread(); + return 0; +} + +bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt) +{ + if (pmt->formattype == FORMAT_VideoInfo) { + return false; + } else if (pmt->formattype == FORMAT_VideoInfo2) { + return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; + } else if (pmt->formattype == FORMAT_MPEGVideo) { + return false; + } else if (pmt->formattype == FORMAT_MPEG2Video) { + return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; + } else { + return false; + } +} + +void CEVRAllocatorPresenter::GetMixerThread() +{ + HANDLE hEvts[] = { m_hEvtQuit}; + bool bQuit = false; + TIMECAPS tc; + DWORD dwResolution; + + // Tell Multimedia Class Scheduler we are a playback thread (increase priority) + //HANDLE hAvrt = 0; + //if (pfAvSetMmThreadCharacteristicsW) { + // DWORD dwTaskIndex = 0; + // hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); + // if (pfAvSetMmThreadPriority) { + // pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); + // } + //} + + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + timeBeginPeriod(dwResolution); + + while (!bQuit) { + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); + switch (dwObject) { + case WAIT_OBJECT_0: + bQuit = true; + break; + case WAIT_TIMEOUT: { + bool bDoneSomething = false; + { + CAutoLock AutoLock(&m_ImageProcessingLock); + bDoneSomething = GetImageFromMixer(); + } + if (m_rtTimePerFrame == 0 && bDoneSomething) { + //CAutoLock lock(this); + //CAutoLock lock2(&m_ImageProcessingLock); + //CAutoLock cRenderLock(&m_RenderLock); + + // Use the code from VMR9 to get the movie fps, as this method is reliable. + CComPtr pPin; + CMediaType mt; + if ( + SUCCEEDED(m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) && + SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); + + m_bInterlaced = ExtractInterlaced(&mt); + + CComPtr pPinTo; + if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { + m_Decoder = GetFilterName(GetFilterFromPin(pPinTo)); + } + } + // If framerate not set by Video Decoder choose 23.97... + if (m_rtTimePerFrame == 0) { + m_rtTimePerFrame = 417166; + } + + // Update internal subtitle clock + if (m_fUseInternalTimer && m_pSubPicQueue) { + m_fps = 10000000.0 / m_rtTimePerFrame; + m_pSubPicQueue->SetFPS(m_fps); + } + } + } + break; + } + } + + timeEndPeriod(dwResolution); + // if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt); +} + +void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed) +{ + double xbiss = (-(ChangeSpeed) * (ValuePrim) - (Value - Target) * (ChangeSpeed * ChangeSpeed) * 0.25f); + ValuePrim += xbiss; + Value += ValuePrim; +} + +LONGLONG CEVRAllocatorPresenter::GetClockTime(LONGLONG PerformanceCounter) +{ + LONGLONG llClockTime; + MFTIME nsCurrentTime; + m_pClock->GetCorrelatedTime(0, &llClockTime, &nsCurrentTime); + DWORD Characteristics = 0; + m_pClock->GetClockCharacteristics(&Characteristics); + MFCLOCK_STATE State; + m_pClock->GetState(0, &State); + + if (!(Characteristics & MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ)) { + MFCLOCK_PROPERTIES Props; + if (m_pClock->GetProperties(&Props) == S_OK) { + llClockTime = (llClockTime * 10000000) / Props.qwClockFrequency; // Make 10 MHz + } + + } + LONGLONG llPerf = PerformanceCounter; + //return llClockTime + (llPerf - nsCurrentTime); + double Target = llClockTime + (llPerf - nsCurrentTime) * m_ModeratedTimeSpeed; + + bool bReset = false; + if (m_ModeratedTimeLast < 0 || State != m_LastClockState || m_ModeratedClockLast < 0) { + bReset = true; + m_ModeratedTimeLast = llPerf; + m_ModeratedClockLast = llClockTime; + } + + m_LastClockState = State; + + LONGLONG TimeChangeM = llPerf - m_ModeratedTimeLast; + LONGLONG ClockChangeM = llClockTime - m_ModeratedClockLast; + UNREFERENCED_PARAMETER(ClockChangeM); + + m_ModeratedTimeLast = llPerf; + m_ModeratedClockLast = llClockTime; + +#if 1 + + if (bReset) { + m_ModeratedTimeSpeed = 1.0; + m_ModeratedTimeSpeedPrim = 0.0; + ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory)); + ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory)); + m_ClockTimeChangeHistoryPos = 0; + } + if (TimeChangeM) { + int Pos = m_ClockTimeChangeHistoryPos % 100; + int nHistory = std::min(m_ClockTimeChangeHistoryPos, 100); + ++m_ClockTimeChangeHistoryPos; + if (nHistory > 50) { + int iLastPos = (Pos - (nHistory)) % 100; + if (iLastPos < 0) { + iLastPos += 100; + } + + double TimeChange = llPerf - m_TimeChangeHistory[iLastPos]; + double ClockChange = llClockTime - m_ClockChangeHistory[iLastPos]; + + double ClockSpeedTarget = ClockChange / TimeChange; + double ChangeSpeed = 0.1; + if (ClockSpeedTarget > m_ModeratedTimeSpeed) { + if (ClockSpeedTarget / m_ModeratedTimeSpeed > 0.1) { + ChangeSpeed = 0.1; + } else { + ChangeSpeed = 0.01; + } + } else { + if (m_ModeratedTimeSpeed / ClockSpeedTarget > 0.1) { + ChangeSpeed = 0.1; + } else { + ChangeSpeed = 0.01; + } + } + ModerateFloat(m_ModeratedTimeSpeed, ClockSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed); + //m_ModeratedTimeSpeed = TimeChange / ClockChange; + } + m_TimeChangeHistory[Pos] = (double)llPerf; + m_ClockChangeHistory[Pos] = (double)llClockTime; + } + + return (LONGLONG)Target; +#else + double EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed + m_ClockDiffCalc; + double Diff = Target - EstimateTime; + + // > 5 ms just set it + if ((fabs(Diff) > 50000.0 || bReset)) { + + // TRACE_EVR("EVR: Reset clock at diff: %f ms\n", (m_ModeratedTime - Target) /10000.0); + if (State == MFCLOCK_STATE_RUNNING) { + if (bReset) { + m_ModeratedTimeSpeed = 1.0; + m_ModeratedTimeSpeedPrim = 0.0; + m_ClockDiffCalc = 0; + m_ClockDiffPrim = 0; + m_ModeratedTime = Target; + m_ModeratedTimer = llPerf; + } else { + EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed; + Diff = Target - EstimateTime; + m_ClockDiffCalc = Diff; + m_ClockDiffPrim = 0; + } + } else { + m_ModeratedTimeSpeed = 0.0; + m_ModeratedTimeSpeedPrim = 0.0; + m_ClockDiffCalc = 0; + m_ClockDiffPrim = 0; + m_ModeratedTime = Target; + m_ModeratedTimer = llPerf; + } + } + + { + LONGLONG ModerateTime = 10000; + double ChangeSpeed = 1.00; + /*if (m_ModeratedTimeSpeedPrim != 0.0) + { + if (m_ModeratedTimeSpeedPrim < 0.1) + ChangeSpeed = 0.1; + }*/ + + int nModerate = 0; + double Change = 0; + while (m_ModeratedTimer < llPerf - ModerateTime) { + m_ModeratedTimer += ModerateTime; + m_ModeratedTime += double(ModerateTime) * m_ModeratedTimeSpeed; + + double TimerDiff = llPerf - m_ModeratedTimer; + + double Diff = (double)(m_ModeratedTime - (Target - TimerDiff)); + + double TimeSpeedTarget; + double AbsDiff = fabs(Diff); + TimeSpeedTarget = 1.0 - (Diff / 1000000.0); + // TimeSpeedTarget = m_ModeratedTimeSpeed - (Diff / 100000000000.0); + //if (AbsDiff > 20000.0) + // TimeSpeedTarget = 1.0 - (Diff / 1000000.0); + /*else if (AbsDiff > 5000.0) + TimeSpeedTarget = 1.0 - (Diff / 100000000.0); + else + TimeSpeedTarget = 1.0 - (Diff / 500000000.0);*/ + double StartMod = m_ModeratedTimeSpeed; + ModerateFloat(m_ModeratedTimeSpeed, TimeSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed); + m_ModeratedTimeSpeed = TimeSpeedTarget; + ++nModerate; + Change += m_ModeratedTimeSpeed - StartMod; + } + if (nModerate) { + m_ModeratedTimeSpeedDiff = Change / nModerate; + } + + double Ret = m_ModeratedTime + double(llPerf - m_ModeratedTimer) * m_ModeratedTimeSpeed; + double Diff = Target - Ret; + ModerateFloat(m_ClockDiffCalc, Diff, m_ClockDiffPrim, ChangeSpeed * 0.1); + + Ret += m_ClockDiffCalc; + Diff = Target - Ret; + m_ClockDiff = Diff; + return LONGLONG(Ret + 0.5); + } + + return Target; + return LONGLONG(m_ModeratedTime + 0.5); +#endif +} + +void CEVRAllocatorPresenter::OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter) +{ + // This function is meant to be called only from the rendering function + // so with the ownership on m_RenderLock. + if (!m_pCurrentlyDisplayedSample || !m_OrderedPaint || !bAll) { + return; + } + + LONGLONG llClockTime; + LONGLONG nsSampleTime; + LONGLONG SampleDuration = 0; + LONGLONG TimePerFrame = m_rtTimePerFrame; + if (!TimePerFrame) { + return; + } + + if (!m_bSignaledStarvation) { + llClockTime = GetClockTime(PerformanceCounter); + m_StarvationClock = llClockTime; + } else { + llClockTime = m_StarvationClock; + } + + if (SUCCEEDED(m_pCurrentlyDisplayedSample->GetSampleDuration(&SampleDuration))) { + // Some filters return invalid values, ignore them + if (SampleDuration > MIN_FRAME_TIME) { + TimePerFrame = SampleDuration; + } + } + + if (FAILED(m_pCurrentlyDisplayedSample->GetSampleTime(&nsSampleTime))) { + nsSampleTime = llClockTime; + } + + { + m_nNextSyncOffset = (m_nNextSyncOffset + 1) % NB_JITTER; + LONGLONG SyncOffset = nsSampleTime - llClockTime; + + m_pllSyncOffset[m_nNextSyncOffset] = SyncOffset; + //TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d \n", m_nCurSurface, m_VSyncMode, m_LastPredictedSync, -SyncOffset, m_LastPredictedSync - (-SyncOffset)); + + m_MaxSyncOffset = MINLONG64; + m_MinSyncOffset = MAXLONG64; + + LONGLONG AvrageSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG Offset = m_pllSyncOffset[i]; + AvrageSum += Offset; + m_MaxSyncOffset = std::max(m_MaxSyncOffset, Offset); + m_MinSyncOffset = std::min(m_MinSyncOffset, Offset); + } + double MeanOffset = double(AvrageSum) / NB_JITTER; + double DeviationSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + double Deviation = double(m_pllSyncOffset[i]) - MeanOffset; + DeviationSum += Deviation * Deviation; + } + double StdDev = sqrt(DeviationSum / NB_JITTER); + + m_fSyncOffsetAvr = MeanOffset; + m_bSyncStatsAvailable = true; + m_fSyncOffsetStdDev = StdDev; + } +} + +STDMETHODIMP_(bool) CEVRAllocatorPresenter::ResetDevice() +{ + CAutoLock cThreadsLock(&m_ThreadsLock); + + StopWorkerThreads(); + + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_RenderLock); + + RemoveAllSamples(); + + bool bResult = __super::ResetDevice(); + + for (int i = 0; i < m_nNbDXSurface; i++) { + CComPtr pMFSample; + HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); + + if (SUCCEEDED(hr)) { + pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); + pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + m_FreeSamples.AddTail(pMFSample); + pMFSample = nullptr; // The sample should not be used after being queued + } + ASSERT(SUCCEEDED(hr)); + } + + if (bResult) { + StartWorkerThreads(); + } + + return bResult; +} + +STDMETHODIMP_(bool) CEVRAllocatorPresenter::DisplayChange() +{ + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_RenderLock); + + bool bResult = __super::DisplayChange(); + + m_DetectedFrameRate = 0.0; + m_DetectedFrameTime = 0.0; + m_DetectedFrameTimeStdDev = 0.0; + m_DetectedLock = false; + ZeroMemory(m_DetectedFrameTimeHistory, sizeof(m_DetectedFrameTimeHistory)); + ZeroMemory(m_DetectedFrameTimeHistoryHistory, sizeof(m_DetectedFrameTimeHistoryHistory)); + m_DetectedFrameTimePos = 0; + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + ZeroMemory(m_ldDetectedRefreshRateList, sizeof(m_ldDetectedRefreshRateList)); + ZeroMemory(m_ldDetectedScanlineRateList, sizeof(m_ldDetectedScanlineRateList)); + m_DetectedRefreshRatePos = 0; + m_DetectedRefreshTimePrim = 0; + m_DetectedScanlineTime = 0; + m_DetectedScanlineTimePrim = 0; + m_DetectedRefreshRate = 0; + + ZeroMemory(m_pllJitter, sizeof(m_pllJitter)); + ZeroMemory(m_pllSyncOffset, sizeof(m_pllSyncOffset)); + m_nNextJitter = 0; + m_nNextSyncOffset = 0; + m_llLastPerf = 0; + m_fAvrFps = 0.0; + m_fJitterStdDev = 0.0; + m_fSyncOffsetStdDev = 0.0; + m_fSyncOffsetAvr = 0.0; + m_bSyncStatsAvailable = false; + + return bResult; +} + +void CEVRAllocatorPresenter::RenderThread() +{ + HANDLE hEvts[] = { m_hEvtQuit, m_hEvtFlush}; + bool bQuit = false, bForcePaint = false; + TIMECAPS tc; + MFTIME nsSampleTime; + LONGLONG llClockTime; + + // Tell Multimedia Class Scheduler we are a playback thread (increase priority) + HANDLE hAvrt = 0; + if (fnAvSetMmThreadCharacteristicsW) { + DWORD dwTaskIndex = 0; + hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); + if (fnAvSetMmThreadPriority) { + fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); + } + } + + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + VERIFY(timeBeginPeriod(dwResolution) == 0); + + auto checkPendingMediaFinished = [this]() { + if (m_bPendingMediaFinished && m_nRenderState != Stopped) { + CAutoLock lock(&m_SampleQueueLock); + if (m_ScheduledSamples.IsEmpty()) { + m_bPendingMediaFinished = false; + m_pSink->Notify(EC_COMPLETE, 0, 0); + TRACE_EVR("EVR: send EC_COMPLETE\n"); + } + } + }; + + const CRenderersSettings& r = GetRenderersSettings(); + + auto SubPicSetTime = [&] { + if (!g_bExternalSubtitleTime && !m_bIsPreview) { + CSubPicAllocatorPresenterImpl::SetTime(g_tSegmentStart + nsSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); + } + }; + + int NextSleepTime = 1; + while (!bQuit) { + LONGLONG llPerf = GetRenderersData()->GetPerfCounter(); + UNREFERENCED_PARAMETER(llPerf); + if (!r.m_AdvRendSets.bVMR9VSyncAccurate && NextSleepTime == 0) { + NextSleepTime = 1; + } + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, std::max(NextSleepTime < 0 ? 1 : NextSleepTime, 0)); + /* dwObject = WAIT_TIMEOUT; + if (m_bEvtFlush) + dwObject = WAIT_OBJECT_0 + 1; + else if (m_bEvtQuit) + dwObject = WAIT_OBJECT_0;*/ + // if (NextSleepTime) + // TRACE_EVR("EVR: Sleep: %7.3f\n", double(GetRenderersData()->GetPerfCounter()-llPerf) / 10000.0); + if (NextSleepTime > 1) { + NextSleepTime = 0; + } else if (NextSleepTime == 0) { + NextSleepTime = -1; + } + switch (dwObject) { + case WAIT_OBJECT_0: + bQuit = true; + break; + case WAIT_OBJECT_0 + 1: + // Flush pending samples! + FlushSamples(); + m_bEvtFlush = false; + ResetEvent(m_hEvtFlush); + bForcePaint = true; + TRACE_EVR("EVR: Flush done!\n"); + break; + + case WAIT_TIMEOUT: + + if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != r.m_AdvRendSets.iEVROutputRange || m_bPendingRenegotiate) { + FlushSamples(); + RenegotiateMediaType(); + m_bPendingRenegotiate = false; + } + if (m_bPendingResetDevice) { + SendResetRequest(); + } + + // Discard timer events if playback stop + //if ((dwObject == WAIT_OBJECT_0 + 3) && (m_nRenderState != Started)) continue; + + //TRACE_EVR ("EVR: RenderThread ==>> Waiting buffer\n"); + + //if (WaitForMultipleObjects (_countof(hEvtsBuff), hEvtsBuff, FALSE, INFINITE) == WAIT_OBJECT_0+2) + { + CComPtr pMFSample; + //LONGLONG llPerf2 = GetRenderersData()->GetPerfCounter(); + //UNREFERENCED_PARAMETER(llPerf2); + int nSamplesLeft = 0; + if (SUCCEEDED(GetScheduledSample(&pMFSample, nSamplesLeft))) { + //UINT32 nSurface; + //pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&nSurface); + + bool bValidSampleTime = true; + HRESULT hrGetSampleTime = pMFSample->GetSampleTime(&nsSampleTime); + if (hrGetSampleTime != S_OK || nsSampleTime == 0) { + bValidSampleTime = false; + } + // We assume that all samples have the same duration + LONGLONG SampleDuration = 0; + bool bValidSampleDuration = true; + HRESULT hrGetSampleDuration = pMFSample->GetSampleDuration(&SampleDuration); + // Some filters return invalid values, ignore them + if (hrGetSampleDuration != S_OK || SampleDuration <= MIN_FRAME_TIME) { + bValidSampleDuration = false; + } + + //TRACE_EVR("EVR: RenderThread ==>> Presenting surface %d (%I64d)\n", nSurface, nsSampleTime); + + bool bStepForward = false; + + if (m_nStepCount < 0) { + // Drop frame + TRACE_EVR("EVR: Dropped frame\n"); + m_pcFrames++; + bStepForward = true; + m_nStepCount = 0; + /* + } else if (m_nStepCount > 0) { + ++m_OrderedPaint; + SubPicSetTime(); + Paint(pMFSample); + m_nDroppedUpdate = 0; + CompleteFrameStep(false); + bStepForward = true; + */ + } else if (m_nRenderState == Started) { + LONGLONG CurrentCounter = GetRenderersData()->GetPerfCounter(); + // Calculate wake up timer + if (!m_bSignaledStarvation) { + llClockTime = GetClockTime(CurrentCounter); + m_StarvationClock = llClockTime; + } else { + llClockTime = m_StarvationClock; + } + + if (!bValidSampleTime) { + // Just play as fast as possible + bStepForward = true; + ++m_OrderedPaint; + SubPicSetTime(); + Paint(pMFSample); + } else { + LONGLONG TimePerFrame = (LONGLONG)(GetFrameTime() * 10000000.0); + LONGLONG SyncOffset = 0; + LONGLONG VSyncTime = 0; + LONGLONG TimeToNextVSync = -1; + bool bVSyncCorrection = false; + double DetectedRefreshTime; + double DetectedScanlinesPerFrame; + double DetectedScanlineTime; + int DetectedRefreshRatePos; + { + CAutoLock Lock(&m_refreshRateLock); + DetectedRefreshTime = m_DetectedRefreshTime; + DetectedRefreshRatePos = m_DetectedRefreshRatePos; + DetectedScanlinesPerFrame = m_DetectedScanlinesPerFrame; + DetectedScanlineTime = m_DetectedScanlineTime; + } + + if (DetectedRefreshRatePos < 20 || !DetectedRefreshTime || !DetectedScanlinesPerFrame) { + DetectedRefreshTime = 1.0 / m_refreshRate; + DetectedScanlinesPerFrame = m_ScreenSize.cy; + DetectedScanlineTime = DetectedRefreshTime / double(m_ScreenSize.cy); + } + + if (r.m_AdvRendSets.bVMR9VSync) { + bVSyncCorrection = true; + double TargetVSyncPos = GetVBlackPos(); + double RefreshLines = DetectedScanlinesPerFrame; + double ScanlinesPerSecond = 1.0 / DetectedScanlineTime; + double CurrentVSyncPos = fmod(double(m_VBlankStartMeasure) + ScanlinesPerSecond * ((CurrentCounter - m_VBlankStartMeasureTime) / 10000000.0), RefreshLines); + double LinesUntilVSync = 0; + //TargetVSyncPos -= ScanlinesPerSecond * (DrawTime/10000000.0); + //TargetVSyncPos -= 10; + TargetVSyncPos = fmod(TargetVSyncPos, RefreshLines); + if (TargetVSyncPos < 0) { + TargetVSyncPos += RefreshLines; + } + if (TargetVSyncPos > CurrentVSyncPos) { + LinesUntilVSync = TargetVSyncPos - CurrentVSyncPos; + } else { + LinesUntilVSync = (RefreshLines - CurrentVSyncPos) + TargetVSyncPos; + } + double TimeUntilVSync = LinesUntilVSync * DetectedScanlineTime; + TimeToNextVSync = (LONGLONG)(TimeUntilVSync * 10000000.0); + VSyncTime = (LONGLONG)(DetectedRefreshTime * 10000000.0); + + LONGLONG ClockTimeAtNextVSync = llClockTime + (LONGLONG)(TimeUntilVSync * 10000000.0 * m_ModeratedTimeSpeed); + + SyncOffset = (nsSampleTime - ClockTimeAtNextVSync); + + //if (SyncOffset < 0) + // TRACE_EVR("EVR: SyncOffset(%d): %I64d %I64d %I64d\n", m_nCurSurface, SyncOffset, TimePerFrame, VSyncTime); + } else { + SyncOffset = (nsSampleTime - llClockTime); + } + + //LONGLONG SyncOffset = nsSampleTime - llClockTime; + TRACE_EVR("EVR: SyncOffset: %I64d SampleFrame: %I64d ClockFrame: %I64d\n", SyncOffset, TimePerFrame != 0 ? nsSampleTime / TimePerFrame : 0, TimePerFrame != 0 ? llClockTime / TimePerFrame : 0); + if (bValidSampleDuration && !m_DetectedLock) { + TimePerFrame = SampleDuration; + } + + LONGLONG MinMargin = MIN_FRAME_TIME + std::min(LONGLONG(m_DetectedFrameTimeStdDev), 20000ll); + //if (m_FrameTimeCorrection) { + // MinMargin = MIN_FRAME_TIME; + //} else { + // MinMargin = MIN_FRAME_TIME + std::min(LONGLONG(m_DetectedFrameTimeStdDev), 20000ll); + //} + LONGLONG TimePerFrameMargin = std::min(std::max(TimePerFrame * 2l / 100l, MinMargin), TimePerFrame * 11l / 100l); // (0.02..0.11)TimePerFrame + LONGLONG TimePerFrameMargin0 = TimePerFrameMargin / 2; + LONGLONG TimePerFrameMargin1 = 0; + + if (m_DetectedLock && TimePerFrame < VSyncTime) { + VSyncTime = TimePerFrame; + } + + if (m_VSyncMode == 1) { + TimePerFrameMargin1 = -TimePerFrameMargin; + } else if (m_VSyncMode == 2) { + TimePerFrameMargin1 = TimePerFrameMargin; + } + + m_LastSampleOffset = SyncOffset; + m_bLastSampleOffsetValid = true; + + LONGLONG VSyncOffset0 = 0; + bool bDoVSyncCorrection = false; + if ((SyncOffset < -(TimePerFrame + TimePerFrameMargin0 - TimePerFrameMargin1)) && nSamplesLeft > 0) { // Only drop if we have something else to display at once + // Drop frame + TRACE_EVR("EVR: Dropped frame\n"); + m_pcFrames++; + bStepForward = true; + ++m_nDroppedUpdate; + NextSleepTime = 0; + //VSyncOffset0 = (-SyncOffset) - VSyncTime; + //VSyncOffset0 = (-SyncOffset) - VSyncTime + TimePerFrameMargin1; + //m_LastPredictedSync = VSyncOffset0; + bDoVSyncCorrection = false; + } else if (SyncOffset < TimePerFrameMargin1) { + + if (bVSyncCorrection) { + VSyncOffset0 = -SyncOffset; + bDoVSyncCorrection = true; + } + + // Paint and prepare for next frame + TRACE_EVR("EVR: Normalframe\n"); + m_nDroppedUpdate = 0; + bStepForward = true; + m_LastFrameDuration = nsSampleTime - m_LastSampleTime; + m_LastSampleTime = nsSampleTime; + m_LastPredictedSync = VSyncOffset0; + + if (m_nStepCount > 0) { + CompleteFrameStep(false); + } + + ++m_OrderedPaint; + + SubPicSetTime(); + Paint(pMFSample); + + NextSleepTime = 0; + m_pcFramesDrawn++; + } else { + if (TimeToNextVSync >= 0 && SyncOffset > 0) { + NextSleepTime = (int)(TimeToNextVSync / 10000 - 2); + } else { + NextSleepTime = (int)(SyncOffset / 10000 - 2); + } + + if (NextSleepTime > TimePerFrame) { + NextSleepTime = 1; + } + + if (NextSleepTime < 0) { + NextSleepTime = 0; + } + NextSleepTime = 1; + //TRACE_EVR ("EVR: Delay\n"); + } + + if (bDoVSyncCorrection) { + //LONGLONG VSyncOffset0 = (((SyncOffset) % VSyncTime) + VSyncTime) % VSyncTime; + LONGLONG Margin = TimePerFrameMargin; + + LONGLONG VSyncOffsetMin = 30000000000000; + LONGLONG VSyncOffsetMax = -30000000000000; + for (int i = 0; i < 5; ++i) { + VSyncOffsetMin = std::min(m_VSyncOffsetHistory[i], VSyncOffsetMin); + VSyncOffsetMax = std::max(m_VSyncOffsetHistory[i], VSyncOffsetMax); + } + + m_VSyncOffsetHistory[m_VSyncOffsetHistoryPos] = VSyncOffset0; + m_VSyncOffsetHistoryPos = (m_VSyncOffsetHistoryPos + 1) % 5; + + //LONGLONG VSyncTime2 = VSyncTime2 + (VSyncOffsetMax - VSyncOffsetMin); + //VSyncOffsetMin; = (((VSyncOffsetMin) % VSyncTime) + VSyncTime) % VSyncTime; + //VSyncOffsetMax = (((VSyncOffsetMax) % VSyncTime) + VSyncTime) % VSyncTime; + + //TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d %8I64d\n", m_nCurSurface, m_VSyncMode,VSyncOffset0, VSyncOffsetMin, VSyncOffsetMax, VSyncOffsetMax - VSyncOffsetMin); + + if (m_VSyncMode == 0) { + // 23.976 in 60 Hz + if (VSyncOffset0 < Margin && VSyncOffsetMax > (VSyncTime - Margin)) { + m_VSyncMode = 2; + } else if (VSyncOffset0 > (VSyncTime - Margin) && VSyncOffsetMin < Margin) { + m_VSyncMode = 1; + } + } else if (m_VSyncMode == 2) { + if (VSyncOffsetMin > (Margin)) { + m_VSyncMode = 0; + } + } else if (m_VSyncMode == 1) { + if (VSyncOffsetMax < (VSyncTime - Margin)) { + m_VSyncMode = 0; + } + } + } + } + } else if (m_nRenderState == Paused) { + if (bForcePaint) { + bStepForward = true; + // Ensure that the renderer is properly updated after seeking when paused + SubPicSetTime(); + Paint(pMFSample); + } + NextSleepTime = int(SampleDuration / 10000 - 2); + } + + if (bStepForward) { + m_MaxSampleDuration = std::max(SampleDuration, m_MaxSampleDuration); + checkPendingMediaFinished(); + } else { + AddToScheduledList(pMFSample, true); + pMFSample = nullptr; // The sample should not be used after being queued + } + + bForcePaint = false; + } else if (m_bLastSampleOffsetValid && m_LastSampleOffset < -10000000) { // Only starve if we are 1 seconds behind + if (m_nRenderState == Started && !g_bNoDuration) { + m_pSink->Notify(EC_STARVATION, 0, 0); + m_bSignaledStarvation = true; + } + } else { + checkPendingMediaFinished(); + } + } + //else + //{ + // TRACE_EVR ("EVR: RenderThread ==>> Flush before rendering frame!\n"); + //} + + break; + } + } + + timeEndPeriod(dwResolution); + if (fnAvRevertMmThreadCharacteristics) { + fnAvRevertMmThreadCharacteristics(hAvrt); + } +} + +void CEVRAllocatorPresenter::VSyncThread() +{ + HANDLE hEvts[] = { m_hEvtQuit}; + bool bQuit = false; + TIMECAPS tc; + DWORD dwResolution; + + // Tell Multimedia Class Scheduler we are a playback thread (increase priority) + //HANDLE hAvrt = 0; + //if (pfAvSetMmThreadCharacteristicsW) { + // DWORD dwTaskIndex = 0; + // hAvrt = pfAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); + // if (pfAvSetMmThreadPriority) { + // pfAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/); + // } + //} + + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + timeBeginPeriod(dwResolution); + const CRenderersData* rd = GetRenderersData(); + const CRenderersSettings& r = GetRenderersSettings(); + + while (!bQuit) { + + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); + switch (dwObject) { + case WAIT_OBJECT_0: + bQuit = true; + break; + case WAIT_TIMEOUT: { + // Do our stuff + if (m_pD3DDev && r.m_AdvRendSets.bVMR9VSync) { + if (m_nRenderState == Started) { + int VSyncPos = GetVBlackPos(); + int WaitRange = std::max(m_ScreenSize.cy / 40l, 5l); + int MinRange = std::max(std::min(long(0.003 * m_ScreenSize.cy * m_refreshRate + 0.5), m_ScreenSize.cy / 3l), 5l); // 1.8 ms or max 33 % of Time + + VSyncPos += MinRange + WaitRange; + + VSyncPos = VSyncPos % m_ScreenSize.cy; + if (VSyncPos < 0) { + VSyncPos += m_ScreenSize.cy; + } + + int ScanLine = 0; + int StartScanLine = ScanLine; + UNREFERENCED_PARAMETER(StartScanLine); + int LastPos = ScanLine; + UNREFERENCED_PARAMETER(LastPos); + ScanLine = (VSyncPos + 1) % m_ScreenSize.cy; + if (ScanLine < 0) { + ScanLine += m_ScreenSize.cy; + } + int ScanLineMiddle = ScanLine + m_ScreenSize.cy / 2; + ScanLineMiddle = ScanLineMiddle % m_ScreenSize.cy; + if (ScanLineMiddle < 0) { + ScanLineMiddle += m_ScreenSize.cy; + } + + int ScanlineStart = ScanLine; + HANDLE lockOwner = nullptr; + WaitForVBlankRange(ScanlineStart, 5, true, true, false, lockOwner); + LONGLONG TimeStart = rd->GetPerfCounter(); + + WaitForVBlankRange(ScanLineMiddle, 5, true, true, false, lockOwner); + LONGLONG TimeMiddle = rd->GetPerfCounter(); + + int ScanlineEnd = ScanLine; + WaitForVBlankRange(ScanlineEnd, 5, true, true, false, lockOwner); + LONGLONG TimeEnd = rd->GetPerfCounter(); + + double nSeconds = (TimeEnd - TimeStart) / 10000000.0; + LONGLONG llDiffMiddle = TimeMiddle - TimeStart; + ASSERT(llDiffMiddle > 0); + + if (nSeconds > 0.003 && llDiffMiddle > 0) { + double dDiffMiddle = double(llDiffMiddle); + double dDiffEnd = double(TimeEnd - TimeMiddle); + + double dDiffDiff = dDiffEnd / dDiffMiddle; + if (dDiffDiff < 1.3 && dDiffDiff > (1 / 1.3)) { + double ScanLineSeconds; + double nScanLines; + if (ScanLineMiddle > ScanlineEnd) { + ScanLineSeconds = dDiffMiddle / 10000000.0; + nScanLines = ScanLineMiddle - ScanlineStart; + } else { + ScanLineSeconds = dDiffEnd / 10000000.0; + nScanLines = ScanlineEnd - ScanLineMiddle; + } + + double ScanLineTime = ScanLineSeconds / nScanLines; + + int iPos = m_DetectedRefreshRatePos % 100; + m_ldDetectedScanlineRateList[iPos] = ScanLineTime; + if (m_DetectedScanlineTime && ScanlineStart != ScanlineEnd) { + int Diff = ScanlineEnd - ScanlineStart; + nSeconds -= double(Diff) * m_DetectedScanlineTime; + } + m_ldDetectedRefreshRateList[iPos] = nSeconds; + double Average = 0; + double AverageScanline = 0; + int nPos = std::min(iPos + 1, 100); + for (int i = 0; i < nPos; ++i) { + Average += m_ldDetectedRefreshRateList[i]; + AverageScanline += m_ldDetectedScanlineRateList[i]; + } + + if (nPos) { + Average /= double(nPos); + AverageScanline /= double(nPos); + } else { + Average = 0; + AverageScanline = 0; + } + + double ThisValue = Average; + + if (Average > 0.0 && AverageScanline > 0.0) { + CAutoLock Lock(&m_refreshRateLock); + ++m_DetectedRefreshRatePos; + if (m_DetectedRefreshTime == 0 || m_DetectedRefreshTime / ThisValue > 1.01 || m_DetectedRefreshTime / ThisValue < 0.99) { + m_DetectedRefreshTime = ThisValue; + m_DetectedRefreshTimePrim = 0; + } + if (_isnan(m_DetectedRefreshTime)) { + m_DetectedRefreshTime = 0.0; + } + if (_isnan(m_DetectedRefreshTimePrim)) { + m_DetectedRefreshTimePrim = 0.0; + } + + ModerateFloat(m_DetectedRefreshTime, ThisValue, m_DetectedRefreshTimePrim, 1.5); + if (m_DetectedRefreshTime > 0.0) { + m_DetectedRefreshRate = 1.0 / m_DetectedRefreshTime; + } else { + m_DetectedRefreshRate = 0.0; + } + + if (m_DetectedScanlineTime == 0 || m_DetectedScanlineTime / AverageScanline > 1.01 || m_DetectedScanlineTime / AverageScanline < 0.99) { + m_DetectedScanlineTime = AverageScanline; + m_DetectedScanlineTimePrim = 0; + } + ModerateFloat(m_DetectedScanlineTime, AverageScanline, m_DetectedScanlineTimePrim, 1.5); + if (m_DetectedScanlineTime > 0.0) { + m_DetectedScanlinesPerFrame = m_DetectedRefreshTime / m_DetectedScanlineTime; + } else { + m_DetectedScanlinesPerFrame = 0; + } + } + //TRACE(_T("Refresh: %f\n"), RefreshRate); + } + } + } + } else { + m_DetectedRefreshRate = 0.0; + m_DetectedScanlinesPerFrame = 0.0; + } + } + break; + } + } + + timeEndPeriod(dwResolution); + //if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt); +} + +DWORD WINAPI CEVRAllocatorPresenter::VSyncThreadStatic(LPVOID lpParam) +{ + SetThreadName(DWORD(-1), "CEVRAllocatorPresenter::VSyncThread"); + CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam; + pThis->VSyncThread(); + return 0; +} + +void CEVRAllocatorPresenter::OnResetDevice() +{ + // Reset DXVA Manager, and get new buffers + m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); + + // Not necessary, but Microsoft documentation say Presenter should send this message... + if (m_pSink) { + m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); + } +} + +void CEVRAllocatorPresenter::RemoveAllSamples() +{ + CAutoLock imageProcesssingLock(&m_ImageProcessingLock); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + + FlushSamples(); + m_FreeSamples.RemoveAll(); + m_LastScheduledUncorrectedSampleTime = -1; + m_nUsedBuffer = 0; + // Increment the group id to make sure old samples will really be deleted + m_nCurrentGroupId++; +} + +HRESULT CEVRAllocatorPresenter::GetFreeSample(IMFSample** ppSample) +{ + CAutoLock lock(&m_SampleQueueLock); + HRESULT hr = S_OK; + + if (!m_FreeSamples.IsEmpty()) { + m_nUsedBuffer++; + *ppSample = m_FreeSamples.RemoveHead().Detach(); + } else { + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + } + + return hr; +} + +HRESULT CEVRAllocatorPresenter::GetScheduledSample(IMFSample** ppSample, int& count) +{ + CAutoLock lock(&m_SampleQueueLock); + HRESULT hr = S_OK; + + count = (int)m_ScheduledSamples.GetCount(); + if (count > 0) { + *ppSample = m_ScheduledSamples.RemoveHead().Detach(); + --count; + } else { + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + } + + return hr; +} + +void CEVRAllocatorPresenter::AddToFreeList(IMFSample* pSample, bool bTail) +{ + CAutoLock lock(&m_SampleQueueLock); + + m_nUsedBuffer--; + if (bTail) { + m_FreeSamples.AddTail(pSample); + } else { + m_FreeSamples.AddHead(pSample); + } +} + +void CEVRAllocatorPresenter::AddToScheduledList(IMFSample* pSample, bool bSorted) +{ + CAutoLock lock(&m_SampleQueueLock); + + if (bSorted) { + // Insert sorted + /*POSITION Iterator = m_ScheduledSamples.GetHeadPosition(); + + LONGLONG NewSampleTime; + pSample->GetSampleTime(&NewSampleTime); + + while (Iterator != nullptr) + { + POSITION CurrentPos = Iterator; + IMFSample *pIter = m_ScheduledSamples.GetNext(Iterator); + LONGLONG SampleTime; + pIter->GetSampleTime(&SampleTime); + if (NewSampleTime < SampleTime) + { + m_ScheduledSamples.InsertBefore(CurrentPos, pSample); + return; + } + }*/ + + m_ScheduledSamples.AddHead(pSample); + } else { + const CRenderersSettings& r = GetRenderersSettings(); + double ForceFPS = 0.0; + //double ForceFPS = 59.94; + //double ForceFPS = 23.976; + if (ForceFPS != 0.0) { + m_rtTimePerFrame = (REFERENCE_TIME)(10000000.0 / ForceFPS); + } + LONGLONG Duration = m_rtTimePerFrame; + UNREFERENCED_PARAMETER(Duration); + LONGLONG PrevTime = m_LastScheduledUncorrectedSampleTime; + LONGLONG Time; + LONGLONG SetDuration; + pSample->GetSampleDuration(&SetDuration); + pSample->GetSampleTime(&Time); + m_LastScheduledUncorrectedSampleTime = Time; + + m_bCorrectedFrameTime = false; + + LONGLONG Diff2 = PrevTime - (LONGLONG)(m_LastScheduledSampleTimeFP * 10000000.0); + LONGLONG Diff = Time - PrevTime; + if (PrevTime == -1) { + Diff = 0; + } + if (Diff < 0) { + Diff = -Diff; + } + if (Diff2 < 0) { + Diff2 = -Diff2; + } + if (Diff < m_rtTimePerFrame * 8 && m_rtTimePerFrame && Diff2 < m_rtTimePerFrame * 8) { // Detect seeking + int iPos = (m_DetectedFrameTimePos++) % 60; + Diff = Time - PrevTime; + if (PrevTime == -1) { + Diff = 0; + } + m_DetectedFrameTimeHistory[iPos] = Diff; + + if (m_DetectedFrameTimePos >= 10) { + int nFrames = std::min(m_DetectedFrameTimePos, 60); + LONGLONG DectedSum = 0; + for (int i = 0; i < nFrames; ++i) { + DectedSum += m_DetectedFrameTimeHistory[i]; + } + + double Average = double(DectedSum) / double(nFrames); + double DeviationSum = 0.0; + for (int i = 0; i < nFrames; ++i) { + double Deviation = m_DetectedFrameTimeHistory[i] - Average; + DeviationSum += Deviation * Deviation; + } + + double StdDev = sqrt(DeviationSum / double(nFrames)); + + m_DetectedFrameTimeStdDev = StdDev; + + double DetectedRate = 1.0 / (double(DectedSum) / (nFrames * 10000000.0)); + double AllowedError = 0.0003; + + static double AllowedValues[] = {60.0, 59.94, 50.0, 48.0, 47.952, 30.0, 29.97, 25.0, 24.0, 23.976}; + + int nAllowed = _countof(AllowedValues); + for (int i = 0; i < nAllowed; ++i) { + if (fabs(1.0 - DetectedRate / AllowedValues[i]) < AllowedError) { + DetectedRate = AllowedValues[i]; + break; + } + } + + m_DetectedFrameTimeHistoryHistory[m_DetectedFrameTimePos % 500] = DetectedRate; + + class CAutoInt + { + public: + + int m_Int; + + CAutoInt() { + m_Int = 0; + } + CAutoInt(int _Other) { + m_Int = _Other; + } + + operator int () const { + return m_Int; + } + + CAutoInt& operator ++ () { + ++m_Int; + return *this; + } + }; + + + CMap Map; + + for (int i = 0; i < 500; ++i) { + ++Map[m_DetectedFrameTimeHistoryHistory[i]]; + } + + POSITION Pos = Map.GetStartPosition(); + double BestVal = 0.0; + int BestNum = 5; + while (Pos) { + double Key; + CAutoInt Value; + Map.GetNextAssoc(Pos, Key, Value); + if (Value.m_Int > BestNum && Key != 0.0) { + BestNum = Value.m_Int; + BestVal = Key; + } + } + + m_DetectedLock = false; + for (int i = 0; i < nAllowed; ++i) { + if (BestVal == AllowedValues[i]) { + m_DetectedLock = true; + break; + } + } + if (BestVal != 0.0) { + m_DetectedFrameRate = BestVal; + m_DetectedFrameTime = 1.0 / BestVal; + } + } + + LONGLONG PredictedNext = PrevTime + m_rtTimePerFrame; + LONGLONG PredictedDiff = PredictedNext - Time; + if (PredictedDiff < 0) { + PredictedDiff = -PredictedDiff; + } + + if (m_DetectedFrameTime != 0.0 + //&& PredictedDiff > MIN_FRAME_TIME + && m_DetectedLock && r.m_AdvRendSets.bEVREnableFrameTimeCorrection) { + double CurrentTime = Time / 10000000.0; + double LastTime = m_LastScheduledSampleTimeFP; + double PredictedTime = LastTime + m_DetectedFrameTime; + if (fabs(PredictedTime - CurrentTime) > 0.0015) { // 1.5 ms wrong, lets correct + CurrentTime = PredictedTime; + Time = (LONGLONG)(CurrentTime * 10000000.0); + pSample->SetSampleTime(Time); + pSample->SetSampleDuration(LONGLONG(m_DetectedFrameTime * 10000000.0)); + m_bCorrectedFrameTime = true; + m_FrameTimeCorrection = 30; + } + m_LastScheduledSampleTimeFP = CurrentTime; + } else { + m_LastScheduledSampleTimeFP = Time / 10000000.0; + } + } else { + m_LastScheduledSampleTimeFP = Time / 10000000.0; + if (Diff > m_rtTimePerFrame * 8) { + // Seek + m_bSignaledStarvation = false; + m_DetectedFrameTimePos = 0; + m_DetectedLock = false; + } + } + + // TRACE_EVR("EVR: Time: %f %f %f\n", Time / 10000000.0, SetDuration / 10000000.0, m_DetectedFrameRate); + if (!m_bCorrectedFrameTime && m_FrameTimeCorrection) { + --m_FrameTimeCorrection; + } + +#if 0 + if (Time <= m_LastScheduledUncorrectedSampleTime && m_LastScheduledSampleTime >= 0) { + PrevTime = m_LastScheduledSampleTime; + } + + m_bCorrectedFrameTime = false; + if (PrevTime != -1 && (Time >= PrevTime - ((Duration * 20) / 9) || Time == 0) || ForceFPS != 0.0) { + if (Time - PrevTime > ((Duration * 20) / 9) && Time - PrevTime < Duration * 8 || Time == 0 || ((Time - PrevTime) < (Duration / 11)) || ForceFPS != 0.0) { + // Error!!!! + Time = PrevTime + Duration; + pSample->SetSampleTime(Time); + pSample->SetSampleDuration(Duration); + m_bCorrectedFrameTime = true; + TRACE_EVR("EVR: Corrected invalid sample time\n"); + } + } + if (Time + Duration * 10 < m_LastScheduledSampleTime) { + // Flush when repeating movie + FlushSamplesInternal(); + } +#endif + +#if 0 + static LONGLONG LastDuration = 0; + LONGLONG SetDuration = m_rtTimePerFrame; + pSample->GetSampleDuration(&SetDuration); + if (SetDuration != LastDuration) { + TRACE_EVR("EVR: Old duration: %I64d New duration: %I64d\n", LastDuration, SetDuration); + } + LastDuration = SetDuration; +#endif + m_LastScheduledSampleTime = Time; + + m_ScheduledSamples.AddTail(pSample); + } +} + +void CEVRAllocatorPresenter::FlushSamples() +{ + CAutoLock lock(this); + CAutoLock lock2(&m_SampleQueueLock); + CAutoLock lock3(&m_RenderLock); + + m_pCurrentlyDisplayedSample = nullptr; + m_ScheduledSamples.RemoveAll(); + + m_LastSampleOffset = 0; + m_bLastSampleOffsetValid = false; + m_bSignaledStarvation = false; + m_LastScheduledSampleTime = -1; +} + +HRESULT CEVRAllocatorPresenter::TrackSample(IMFSample* pSample) +{ + HRESULT hr = E_FAIL; + if (CComQIPtr pTracked = pSample) { + hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr); + } + return hr; +} + +HRESULT CEVRAllocatorPresenter::OnSampleFree(IMFAsyncResult* pResult) +{ + CComPtr pObject; + HRESULT hr = pResult->GetObject(&pObject); + if (SUCCEEDED(hr)) { + if (CComQIPtr pSample = pObject) { + // Ignore the sample if it is from an old group + UINT32 nGroupId; + CAutoLock sampleQueueLock(&m_SampleQueueLock); + if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) { + AddToFreeList(pSample, true); + pSample = nullptr; // The sample should not be used after being queued + } + } + } + return hr; +} diff --git a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h index 3444f99ed3d..5f272b58346 100644 --- a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h @@ -1,280 +1,280 @@ -/* - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include "DX9AllocatorPresenter.h" -#include // API Media Foundation -#include -#include "../../../DSUtil/WinapiFunc.h" -#include "AsyncCallback.h" - -namespace DSObjects -{ - class COuterEVR; - - class CEVRAllocatorPresenter : - public CDX9AllocatorPresenter, - public IMFGetService, - public IMFTopologyServiceLookupClient, - public IMFVideoDeviceID, - public IMFVideoPresenter, - public IDirect3DDeviceManager9, - - public IMFAsyncCallback, - public IQualProp, - public IMFRateSupport, - public IMFVideoDisplayControl, - public IMFVideoMixerBitmap, - public IEVRTrustedVideoPlugin - /* public IMFVideoPositionMapper, // Non mandatory EVR Presenter Interfaces (see later...) */ - { - public: - CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error, bool isPreview=false); - ~CEVRAllocatorPresenter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); - STDMETHODIMP InitializeDevice(IMFMediaType* pMediaType); - STDMETHODIMP_(bool) ResetDevice(); - STDMETHODIMP_(bool) DisplayChange(); - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() { - return (m_nRenderState == Started); - } - - // IMFClockStateSink - STDMETHODIMP OnClockStart(/* [in] */ MFTIME hnsSystemTime, /* [in] */ LONGLONG llClockStartOffset); - STDMETHODIMP OnClockStop(/* [in] */ MFTIME hnsSystemTime); - STDMETHODIMP OnClockPause(/* [in] */ MFTIME hnsSystemTime); - STDMETHODIMP OnClockRestart(/* [in] */ MFTIME hnsSystemTime); - STDMETHODIMP OnClockSetRate(/* [in] */ MFTIME hnsSystemTime, /* [in] */ float flRate); - - // IBaseFilter delegate - bool GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue); - - // IQualProp (EVR statistics window) - STDMETHODIMP get_FramesDroppedInRenderer(int* pcFrames); - STDMETHODIMP get_FramesDrawn(int* pcFramesDrawn); - STDMETHODIMP get_AvgFrameRate(int* piAvgFrameRate); - STDMETHODIMP get_Jitter(int* iJitter); - STDMETHODIMP get_AvgSyncOffset(int* piAvg); - STDMETHODIMP get_DevSyncOffset(int* piDev); - - - // IMFRateSupport - STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); - STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); - STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate); - - float GetMaxRate(BOOL bThin); - - - // IMFVideoPresenter - STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam); - STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType); - - // IMFTopologyServiceLookupClient - STDMETHODIMP InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup); - STDMETHODIMP ReleaseServicePointers(); - - // IMFVideoDeviceID - STDMETHODIMP GetDeviceID(/* [out] */ __out IID* pDeviceID); - - // IMFGetService - STDMETHODIMP GetService(/* [in] */ __RPC__in REFGUID guidService, - /* [in] */ __RPC__in REFIID riid, - /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject); - - // IMFAsyncCallback - STDMETHODIMP GetParameters(/* [out] */ __RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue); - STDMETHODIMP Invoke(/* [in] */ __RPC__in_opt IMFAsyncResult* pAsyncResult); - - // IMFVideoDisplayControl - STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo); - STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax); - STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest); - STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest); - STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode); - STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode); - STDMETHODIMP SetVideoWindow(HWND hwndVideo); - STDMETHODIMP GetVideoWindow(HWND* phwndVideo); - STDMETHODIMP RepaintVideo(); - STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp); - STDMETHODIMP SetBorderColor(COLORREF Clr); - STDMETHODIMP GetBorderColor(COLORREF* pClr); - STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags); - STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags); - STDMETHODIMP SetFullscreen(BOOL fFullscreen); - STDMETHODIMP GetFullscreen(BOOL* pfFullscreen); - - // IMFVideoMixerBitmap - STDMETHODIMP ClearAlphaBitmap(); - STDMETHODIMP GetAlphaBitmapParameters(MFVideoAlphaBitmapParams *pBmpParms); - STDMETHODIMP SetAlphaBitmap(const MFVideoAlphaBitmap *pBmpParms); - STDMETHODIMP UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams *pBmpParms); - - // IEVRTrustedVideoPlugin - STDMETHODIMP IsInTrustedVideoMode(BOOL* pYes); - STDMETHODIMP CanConstrict(BOOL* pYes); - STDMETHODIMP SetConstriction(DWORD dwKPix); - STDMETHODIMP DisableImageExport(BOOL bDisable); - - // IDirect3DDeviceManager9 - STDMETHODIMP ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken); - STDMETHODIMP OpenDeviceHandle(HANDLE* phDevice); - STDMETHODIMP CloseDeviceHandle(HANDLE hDevice); - STDMETHODIMP TestDevice(HANDLE hDevice); - STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock); - STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState); - STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void** ppService); - - protected: - STDMETHODIMP_(bool) Paint(IMFSample* pMFSample); - void OnResetDevice(); - virtual void OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter); - - double m_ModeratedTime; - LONGLONG m_ModeratedTimeLast; - LONGLONG m_ModeratedClockLast; - LONGLONG m_ModeratedTimer; - MFCLOCK_STATE m_LastClockState; - LONGLONG GetClockTime(LONGLONG PerformanceCounter); - - private: - - enum RENDER_STATE { - Stopped = State_Stopped, - Paused = State_Paused, - Started = State_Running, - Shutdown = State_Running + 1 - }; - - COuterEVR* m_pOuterEVR; - CComPtr m_pClock; - CComPtr m_pD3DManager; - CComPtr m_pMixer; - CComPtr m_pSink; - CComPtr m_pMediaType; - MFVideoAspectRatioMode m_dwVideoAspectRatioMode; - MFVideoRenderPrefs m_dwVideoRenderPrefs; - COLORREF m_BorderColor; - - - HANDLE m_hEvtQuit; // Stop rendering thread event - bool m_bEvtQuit; - HANDLE m_hEvtFlush; // Discard all buffers - bool m_bEvtFlush; - - bool m_fUseInternalTimer; - INT32 m_LastSetOutputRange; - std::atomic_bool m_bPendingRenegotiate; - bool m_bPendingMediaFinished; - - HANDLE m_hThread; - HANDLE m_hGetMixerThread; - HANDLE m_hVSyncThread; - RENDER_STATE m_nRenderState; - - CCritSec m_SampleQueueLock; - CCritSec m_ImageProcessingLock; - CCritSec m_MediaTypeLock; - CCritSec m_ThreadsLock; - - UINT32 m_nCurrentGroupId; - CInterfaceList m_FreeSamples; - CInterfaceList m_ScheduledSamples; - CComPtr m_pCurrentlyDisplayedSample; - bool m_bLastSampleOffsetValid; - LONGLONG m_LastScheduledSampleTime; - double m_LastScheduledSampleTimeFP; - LONGLONG m_LastScheduledUncorrectedSampleTime; - LONGLONG m_MaxSampleDuration; - LONGLONG m_LastSampleOffset; - LONGLONG m_VSyncOffsetHistory[5]; - LONGLONG m_LastPredictedSync; - int m_VSyncOffsetHistoryPos; - - UINT m_nResetToken; - int m_nStepCount; - - bool m_bSignaledStarvation; - LONGLONG m_StarvationClock; - - // Stats variable for IQualProp - UINT m_pcFrames; - UINT m_nDroppedUpdate; - UINT m_pcFramesDrawn; // Retrieves the number of frames drawn since streaming started - UINT m_piAvg; - UINT m_piDev; - - - void GetMixerThread(); - static DWORD WINAPI GetMixerThreadStatic(LPVOID lpParam); - - bool GetImageFromMixer(); - void RenderThread(); - static DWORD WINAPI PresentThread(LPVOID lpParam); - void ResetStats(); - void StartWorkerThreads(); - void StopWorkerThreads(); - HRESULT CheckShutdown() const; - void CompleteFrameStep(bool bCancel); - static DWORD WINAPI VSyncThreadStatic(LPVOID lpParam); - void VSyncThread(); - - void RemoveAllSamples(); - HRESULT GetFreeSample(IMFSample** ppSample); - HRESULT GetScheduledSample(IMFSample** ppSample, int& count); - void AddToFreeList(IMFSample* pSample, bool bTail); - void AddToScheduledList(IMFSample* pSample, bool bSorted); - void FlushSamples(); - - HRESULT TrackSample(IMFSample* pSample); - - // Callback when a video sample is released. - HRESULT OnSampleFree(IMFAsyncResult* pResult); - AsyncCallback m_SampleFreeCallback; - - // === Media type negotiation functions - HRESULT RenegotiateMediaType(); - HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType); - HRESULT CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** pType); - HRESULT SetMediaType(IMFMediaType* pType); - HRESULT GetMediaTypeFourCC(IMFMediaType* pType, DWORD* pFourCC); - HRESULT GetMediaTypeMerit(IMFMediaType* pType, int* pMerit); - LPCTSTR GetMediaTypeFormatDesc(IMFMediaType* pMediaType); - - const WinapiFunc fnDXVA2CreateDirect3DDeviceManager9; - const WinapiFunc fnMFCreateDXSurfaceBuffer; - const WinapiFunc fnMFCreateVideoSampleFromSurface; - const WinapiFunc fnMFCreateMediaType; - - const WinapiFunc fnAvSetMmThreadCharacteristicsW; - const WinapiFunc fnAvSetMmThreadPriority; - const WinapiFunc fnAvRevertMmThreadCharacteristics; - }; - -} +/* + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include "DX9AllocatorPresenter.h" +#include // API Media Foundation +#include +#include "../../../DSUtil/WinapiFunc.h" +#include "AsyncCallback.h" + +namespace DSObjects +{ + class COuterEVR; + + class CEVRAllocatorPresenter : + public CDX9AllocatorPresenter, + public IMFGetService, + public IMFTopologyServiceLookupClient, + public IMFVideoDeviceID, + public IMFVideoPresenter, + public IDirect3DDeviceManager9, + + public IMFAsyncCallback, + public IQualProp, + public IMFRateSupport, + public IMFVideoDisplayControl, + public IMFVideoMixerBitmap, + public IEVRTrustedVideoPlugin + /* public IMFVideoPositionMapper, // Non mandatory EVR Presenter Interfaces (see later...) */ + { + public: + CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error, bool isPreview=false); + ~CEVRAllocatorPresenter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); + STDMETHODIMP InitializeDevice(IMFMediaType* pMediaType); + STDMETHODIMP_(bool) ResetDevice(); + STDMETHODIMP_(bool) DisplayChange(); + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() { + return (m_nRenderState == Started); + } + + // IMFClockStateSink + STDMETHODIMP OnClockStart(/* [in] */ MFTIME hnsSystemTime, /* [in] */ LONGLONG llClockStartOffset); + STDMETHODIMP OnClockStop(/* [in] */ MFTIME hnsSystemTime); + STDMETHODIMP OnClockPause(/* [in] */ MFTIME hnsSystemTime); + STDMETHODIMP OnClockRestart(/* [in] */ MFTIME hnsSystemTime); + STDMETHODIMP OnClockSetRate(/* [in] */ MFTIME hnsSystemTime, /* [in] */ float flRate); + + // IBaseFilter delegate + bool GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue); + + // IQualProp (EVR statistics window) + STDMETHODIMP get_FramesDroppedInRenderer(int* pcFrames); + STDMETHODIMP get_FramesDrawn(int* pcFramesDrawn); + STDMETHODIMP get_AvgFrameRate(int* piAvgFrameRate); + STDMETHODIMP get_Jitter(int* iJitter); + STDMETHODIMP get_AvgSyncOffset(int* piAvg); + STDMETHODIMP get_DevSyncOffset(int* piDev); + + + // IMFRateSupport + STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); + STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); + STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate); + + float GetMaxRate(BOOL bThin); + + + // IMFVideoPresenter + STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam); + STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType); + + // IMFTopologyServiceLookupClient + STDMETHODIMP InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup* pLookup); + STDMETHODIMP ReleaseServicePointers(); + + // IMFVideoDeviceID + STDMETHODIMP GetDeviceID(/* [out] */ __out IID* pDeviceID); + + // IMFGetService + STDMETHODIMP GetService(/* [in] */ __RPC__in REFGUID guidService, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt LPVOID* ppvObject); + + // IMFAsyncCallback + STDMETHODIMP GetParameters(/* [out] */ __RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue); + STDMETHODIMP Invoke(/* [in] */ __RPC__in_opt IMFAsyncResult* pAsyncResult); + + // IMFVideoDisplayControl + STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo); + STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax); + STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest); + STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest); + STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode); + STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode); + STDMETHODIMP SetVideoWindow(HWND hwndVideo); + STDMETHODIMP GetVideoWindow(HWND* phwndVideo); + STDMETHODIMP RepaintVideo(); + STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp); + STDMETHODIMP SetBorderColor(COLORREF Clr); + STDMETHODIMP GetBorderColor(COLORREF* pClr); + STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags); + STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags); + STDMETHODIMP SetFullscreen(BOOL fFullscreen); + STDMETHODIMP GetFullscreen(BOOL* pfFullscreen); + + // IMFVideoMixerBitmap + STDMETHODIMP ClearAlphaBitmap(); + STDMETHODIMP GetAlphaBitmapParameters(MFVideoAlphaBitmapParams *pBmpParms); + STDMETHODIMP SetAlphaBitmap(const MFVideoAlphaBitmap *pBmpParms); + STDMETHODIMP UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams *pBmpParms); + + // IEVRTrustedVideoPlugin + STDMETHODIMP IsInTrustedVideoMode(BOOL* pYes); + STDMETHODIMP CanConstrict(BOOL* pYes); + STDMETHODIMP SetConstriction(DWORD dwKPix); + STDMETHODIMP DisableImageExport(BOOL bDisable); + + // IDirect3DDeviceManager9 + STDMETHODIMP ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken); + STDMETHODIMP OpenDeviceHandle(HANDLE* phDevice); + STDMETHODIMP CloseDeviceHandle(HANDLE hDevice); + STDMETHODIMP TestDevice(HANDLE hDevice); + STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock); + STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState); + STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void** ppService); + + protected: + STDMETHODIMP_(bool) Paint(IMFSample* pMFSample); + void OnResetDevice(); + virtual void OnVBlankFinished(bool bAll, LONGLONG PerformanceCounter); + + double m_ModeratedTime; + LONGLONG m_ModeratedTimeLast; + LONGLONG m_ModeratedClockLast; + LONGLONG m_ModeratedTimer; + MFCLOCK_STATE m_LastClockState; + LONGLONG GetClockTime(LONGLONG PerformanceCounter); + + private: + + enum RENDER_STATE { + Stopped = State_Stopped, + Paused = State_Paused, + Started = State_Running, + Shutdown = State_Running + 1 + }; + + COuterEVR* m_pOuterEVR; + CComPtr m_pClock; + CComPtr m_pD3DManager; + CComPtr m_pMixer; + CComPtr m_pSink; + CComPtr m_pMediaType; + MFVideoAspectRatioMode m_dwVideoAspectRatioMode; + MFVideoRenderPrefs m_dwVideoRenderPrefs; + COLORREF m_BorderColor; + + + HANDLE m_hEvtQuit; // Stop rendering thread event + bool m_bEvtQuit; + HANDLE m_hEvtFlush; // Discard all buffers + bool m_bEvtFlush; + + bool m_fUseInternalTimer; + INT32 m_LastSetOutputRange; + std::atomic_bool m_bPendingRenegotiate; + bool m_bPendingMediaFinished; + + HANDLE m_hThread; + HANDLE m_hGetMixerThread; + HANDLE m_hVSyncThread; + RENDER_STATE m_nRenderState; + + CCritSec m_SampleQueueLock; + CCritSec m_ImageProcessingLock; + CCritSec m_MediaTypeLock; + CCritSec m_ThreadsLock; + + UINT32 m_nCurrentGroupId; + CInterfaceList m_FreeSamples; + CInterfaceList m_ScheduledSamples; + CComPtr m_pCurrentlyDisplayedSample; + bool m_bLastSampleOffsetValid; + LONGLONG m_LastScheduledSampleTime; + double m_LastScheduledSampleTimeFP; + LONGLONG m_LastScheduledUncorrectedSampleTime; + LONGLONG m_MaxSampleDuration; + LONGLONG m_LastSampleOffset; + LONGLONG m_VSyncOffsetHistory[5]; + LONGLONG m_LastPredictedSync; + int m_VSyncOffsetHistoryPos; + + UINT m_nResetToken; + int m_nStepCount; + + bool m_bSignaledStarvation; + LONGLONG m_StarvationClock; + + // Stats variable for IQualProp + UINT m_pcFrames; + UINT m_nDroppedUpdate; + UINT m_pcFramesDrawn; // Retrieves the number of frames drawn since streaming started + UINT m_piAvg; + UINT m_piDev; + + + void GetMixerThread(); + static DWORD WINAPI GetMixerThreadStatic(LPVOID lpParam); + + bool GetImageFromMixer(); + void RenderThread(); + static DWORD WINAPI PresentThread(LPVOID lpParam); + void ResetStats(); + void StartWorkerThreads(); + void StopWorkerThreads(); + HRESULT CheckShutdown() const; + void CompleteFrameStep(bool bCancel); + static DWORD WINAPI VSyncThreadStatic(LPVOID lpParam); + void VSyncThread(); + + void RemoveAllSamples(); + HRESULT GetFreeSample(IMFSample** ppSample); + HRESULT GetScheduledSample(IMFSample** ppSample, int& count); + void AddToFreeList(IMFSample* pSample, bool bTail); + void AddToScheduledList(IMFSample* pSample, bool bSorted); + void FlushSamples(); + + HRESULT TrackSample(IMFSample* pSample); + + // Callback when a video sample is released. + HRESULT OnSampleFree(IMFAsyncResult* pResult); + AsyncCallback m_SampleFreeCallback; + + // === Media type negotiation functions + HRESULT RenegotiateMediaType(); + HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType); + HRESULT CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** pType); + HRESULT SetMediaType(IMFMediaType* pType); + HRESULT GetMediaTypeFourCC(IMFMediaType* pType, DWORD* pFourCC); + HRESULT GetMediaTypeMerit(IMFMediaType* pType, int* pMerit); + LPCTSTR GetMediaTypeFormatDesc(IMFMediaType* pMediaType); + + const WinapiFunc fnDXVA2CreateDirect3DDeviceManager9; + const WinapiFunc fnMFCreateDXSurfaceBuffer; + const WinapiFunc fnMFCreateVideoSampleFromSurface; + const WinapiFunc fnMFCreateMediaType; + + const WinapiFunc fnAvSetMmThreadCharacteristicsW; + const WinapiFunc fnAvSetMmThreadPriority; + const WinapiFunc fnAvRevertMmThreadCharacteristics; + }; + +} diff --git a/src/filters/renderer/VideoRenderers/IPinHook.cpp b/src/filters/renderer/VideoRenderers/IPinHook.cpp index c52478ba305..2e973f4d1d4 100644 --- a/src/filters/renderer/VideoRenderers/IPinHook.cpp +++ b/src/filters/renderer/VideoRenderers/IPinHook.cpp @@ -1,294 +1,294 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" - -#include -#include -#include -#include "moreuuids.h" - -#include "IPinHook.h" -#include "AllocatorCommon.h" - -#include "../../../mpc-hc/FGFilterLAV.h" -#include "Variables.h" - -REFERENCE_TIME g_tSegmentStart = 0; -REFERENCE_TIME g_tSampleStart = 0; -extern double g_dRate; - -IPinCVtbl* g_pPinCVtbl_NewSegment = nullptr; -IPinCVtbl* g_pPinCVtbl_ReceiveConnection = nullptr; -IMemInputPinCVtbl* g_pMemInputPinCVtbl = nullptr; -IPinC* g_pPinC_NewSegment = nullptr; - -struct D3DFORMAT_TYPE { - int Format; - LPCTSTR Description; -}; - -const D3DFORMAT_TYPE D3DFormatType[] = { - { D3DFMT_UNKNOWN, _T("D3DFMT_UNKNOWN ") }, - { D3DFMT_R8G8B8, _T("D3DFMT_R8G8B8 ") }, - { D3DFMT_A8R8G8B8, _T("D3DFMT_A8R8G8B8 ") }, - { D3DFMT_X8R8G8B8, _T("D3DFMT_X8R8G8B8 ") }, - { D3DFMT_R5G6B5, _T("D3DFMT_R5G6B5 ") }, - { D3DFMT_X1R5G5B5, _T("D3DFMT_X1R5G5B5 ") }, - { D3DFMT_A1R5G5B5, _T("D3DFMT_A1R5G5B5 ") }, - { D3DFMT_A4R4G4B4, _T("D3DFMT_A4R4G4B4 ") }, - { D3DFMT_R3G3B2, _T("D3DFMT_R3G3B2 ") }, - { D3DFMT_A8, _T("D3DFMT_A8 ") }, - { D3DFMT_A8R3G3B2, _T("D3DFMT_A8R3G3B2 ") }, - { D3DFMT_X4R4G4B4, _T("D3DFMT_X4R4G4B4 ") }, - { D3DFMT_A2B10G10R10, _T("D3DFMT_A2B10G10R10 ") }, - { D3DFMT_A8B8G8R8, _T("D3DFMT_A8B8G8R8 ") }, - { D3DFMT_X8B8G8R8, _T("D3DFMT_X8B8G8R8 ") }, - { D3DFMT_G16R16, _T("D3DFMT_G16R16 ") }, - { D3DFMT_A2R10G10B10, _T("D3DFMT_A2R10G10B10 ") }, - { D3DFMT_A16B16G16R16, _T("D3DFMT_A16B16G16R16 ") }, - { D3DFMT_A8P8, _T("D3DFMT_A8P8 ") }, - { D3DFMT_P8, _T("D3DFMT_P8 ") }, - { D3DFMT_L8, _T("D3DFMT_L8 ") }, - { D3DFMT_A8L8, _T("D3DFMT_A8L8 ") }, - { D3DFMT_A4L4, _T("D3DFMT_A4L4 ") }, - { D3DFMT_X8L8V8U8, _T("D3DFMT_X8L8V8U8 ") }, - { D3DFMT_Q8W8V8U8, _T("D3DFMT_Q8W8V8U8 ") }, - { D3DFMT_V16U16, _T("D3DFMT_V16U16 ") }, - { D3DFMT_A2W10V10U10, _T("D3DFMT_A2W10V10U10 ") }, - { D3DFMT_UYVY, _T("D3DFMT_UYVY ") }, - { D3DFMT_R8G8_B8G8, _T("D3DFMT_R8G8_B8G8 ") }, - { D3DFMT_YUY2, _T("D3DFMT_YUY2 ") }, - { D3DFMT_G8R8_G8B8, _T("D3DFMT_G8R8_G8B8 ") }, - { D3DFMT_DXT1, _T("D3DFMT_DXT1 ") }, - { D3DFMT_DXT2, _T("D3DFMT_DXT2 ") }, - { D3DFMT_DXT3, _T("D3DFMT_DXT3 ") }, - { D3DFMT_DXT4, _T("D3DFMT_DXT4 ") }, - { D3DFMT_DXT5, _T("D3DFMT_DXT5 ") }, - { D3DFMT_D16_LOCKABLE, _T("D3DFMT_D16_LOCKABLE ") }, - { D3DFMT_D32, _T("D3DFMT_D32 ") }, - { D3DFMT_D15S1, _T("D3DFMT_D15S1 ") }, - { D3DFMT_D24S8, _T("D3DFMT_D24S8 ") }, - { D3DFMT_D24X8, _T("D3DFMT_D24X8 ") }, - { D3DFMT_D24X4S4, _T("D3DFMT_D24X4S4 ") }, - { D3DFMT_D16, _T("D3DFMT_D16 ") }, - { D3DFMT_D32F_LOCKABLE, _T("D3DFMT_D32F_LOCKABLE") }, - { D3DFMT_D24FS8, _T("D3DFMT_D24FS8 ") }, - { D3DFMT_L16, _T("D3DFMT_L16 ") }, - { D3DFMT_VERTEXDATA, _T("D3DFMT_VERTEXDATA ") }, - { D3DFMT_INDEX16, _T("D3DFMT_INDEX16 ") }, - { D3DFMT_INDEX32, _T("D3DFMT_INDEX32 ") }, - { D3DFMT_Q16W16V16U16, _T("D3DFMT_Q16W16V16U16 ") }, - - { MAKEFOURCC('N', 'V', '1', '2'), _T("D3DFMT_NV12") }, - { MAKEFOURCC('N', 'V', '2', '4'), _T("D3DFMT_NV24") }, -}; - -LPCTSTR FindD3DFormat(const D3DFORMAT Format) -{ - for (int i = 0; i < _countof(D3DFormatType); i++) { - if (Format == D3DFormatType[i].Format) { - return D3DFormatType[i].Description; - } - } - - return D3DFormatType[0].Description; -} - -// === DirectShow hooks -static HRESULT(STDMETHODCALLTYPE* NewSegmentOrg)(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) = nullptr; - -static HRESULT STDMETHODCALLTYPE NewSegmentMine(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) -{ - if (g_pPinC_NewSegment == This) { - g_tSegmentStart = tStart; - g_dRate = dRate; - } - - return NewSegmentOrg(This, tStart, tStop, dRate); -} - -static HRESULT(STDMETHODCALLTYPE* ReceiveConnectionOrg)(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt) = nullptr; - -static HRESULT STDMETHODCALLTYPE ReceiveConnectionMine(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt) -{ - // Force-reject P010 and P016 pixel formats due to Microsoft bug ... - if (pmt && (pmt->subtype == MEDIASUBTYPE_P010 || pmt->subtype == MEDIASUBTYPE_P016)) { - // ... but allow LAV Video Decoder to do that itself in order to support 10bit DXVA. - if (GetCLSID((IPin*)pConnector) != GUID_LAVVideo) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } - - return ReceiveConnectionOrg(This, pConnector, pmt); -} - - -static HRESULT(STDMETHODCALLTYPE* ReceiveOrg)(IMemInputPinC* This, IMediaSample* pSample) = nullptr; - -static HRESULT STDMETHODCALLTYPE ReceiveMine(IMemInputPinC* This, IMediaSample* pSample) -{ - REFERENCE_TIME rtStart, rtStop; - if (pSample && SUCCEEDED(pSample->GetTime(&rtStart, &rtStop))) { - g_tSampleStart = rtStart; - } - return ReceiveOrg(This, pSample); -} - -bool HookReceiveConnection(IBaseFilter* pBF) -{ - if (!pBF || g_pPinCVtbl_ReceiveConnection) { - return false; - } - - if (CComPtr pPin = GetFirstPin(pBF)) { - IPinC* pPinC = (IPinC*)(IPin*)pPin; - - DWORD flOldProtect = 0; - if (VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - if (ReceiveConnectionOrg == nullptr) { - ReceiveConnectionOrg = pPinC->lpVtbl->ReceiveConnection; - } - pPinC->lpVtbl->ReceiveConnection = ReceiveConnectionMine; - FlushInstructionCache(GetCurrentProcess(), pPinC->lpVtbl, sizeof(IPinCVtbl)); - VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); - g_pPinCVtbl_ReceiveConnection = pPinC->lpVtbl; - return true; - } else { - TRACE(_T("HookWorkAroundVideoDriversBug: Could not hook the VTable")); - ASSERT(FALSE); - } - } - return false; -} - -void UnhookReceiveConnection() -{ - // Unhook previous VTable - if (g_pPinCVtbl_ReceiveConnection) { - DWORD flOldProtect = 0; - if (VirtualProtect(g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - if (g_pPinCVtbl_ReceiveConnection->ReceiveConnection == ReceiveConnectionMine) { - g_pPinCVtbl_ReceiveConnection->ReceiveConnection = ReceiveConnectionOrg; - } - ReceiveConnectionOrg = nullptr; - FlushInstructionCache(GetCurrentProcess(), g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl)); - VirtualProtect(g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); - g_pPinCVtbl_ReceiveConnection = nullptr; - } else { - TRACE(_T("UnhookReceiveConnection: Could not unhook previous VTable")); - ASSERT(FALSE); - } - } -} - -void UnhookNewSegment() -{ - // Unhook previous VTables - if (g_pPinCVtbl_NewSegment) { - DWORD flOldProtect = 0; - if (VirtualProtect(g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - if (g_pPinCVtbl_NewSegment->NewSegment == NewSegmentMine) { - g_pPinCVtbl_NewSegment->NewSegment = NewSegmentOrg; - } - FlushInstructionCache(GetCurrentProcess(), g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl)); - VirtualProtect(g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); - g_pPinCVtbl_NewSegment = nullptr; - g_pPinC_NewSegment = nullptr; - NewSegmentOrg = nullptr; - } else { - TRACE(_T("UnhookNewSegment: Could not unhook g_pPinCVtbl VTable")); - ASSERT(FALSE); - } - } -} - -void UnhookReceive() -{ - // Unhook previous VTables - if (g_pMemInputPinCVtbl) { - DWORD flOldProtect = 0; - if (VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - if (g_pMemInputPinCVtbl->Receive == ReceiveMine) { - g_pMemInputPinCVtbl->Receive = ReceiveOrg; - } - FlushInstructionCache(GetCurrentProcess(), g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl)); - VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect); - g_pMemInputPinCVtbl = nullptr; - ReceiveOrg = nullptr; - } else { - TRACE(_T("UnhookReceive: Could not unhook g_pMemInputPinCVtbl VTable")); - ASSERT(FALSE); - } - } -} - -bool HookNewSegment(IPinC* pPinC) -{ - if (!pPinC || g_pPinCVtbl_NewSegment) { - return false; - } - - DWORD flOldProtect = 0; - if (VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - g_tSegmentStart = 0; - g_dRate = 1.0; - if (NewSegmentOrg == nullptr) { - NewSegmentOrg = pPinC->lpVtbl->NewSegment; - } - pPinC->lpVtbl->NewSegment = NewSegmentMine; // Function sets global variable(s) - FlushInstructionCache(GetCurrentProcess(), pPinC->lpVtbl, sizeof(IPinCVtbl)); - VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); - g_pPinCVtbl_NewSegment = pPinC->lpVtbl; - g_pPinC_NewSegment = pPinC; - return true; - } else { - TRACE(_T("HookNewSegment: Could not unhook VTable")); - ASSERT(FALSE); - } - - return false; -} - -bool HookReceive(IMemInputPinC* pMemInputPinC) -{ - if (!pMemInputPinC || g_pMemInputPinCVtbl) { - return false; - } - - DWORD flOldProtect = 0; - if (VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { - g_tSampleStart = 0; - if (ReceiveOrg == nullptr) { - ReceiveOrg = pMemInputPinC->lpVtbl->Receive; - } - pMemInputPinC->lpVtbl->Receive = ReceiveMine; // Function sets global variable(s) - FlushInstructionCache(GetCurrentProcess(), pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl)); - VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect); - g_pMemInputPinCVtbl = pMemInputPinC->lpVtbl; - return true; - } else { - TRACE(_T("HookReceive: Could not unhook VTable")); - ASSERT(FALSE); - } - - return false; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" + +#include +#include +#include +#include "moreuuids.h" + +#include "IPinHook.h" +#include "AllocatorCommon.h" + +#include "../../../mpc-hc/FGFilterLAV.h" +#include "Variables.h" + +REFERENCE_TIME g_tSegmentStart = 0; +REFERENCE_TIME g_tSampleStart = 0; +extern double g_dRate; + +IPinCVtbl* g_pPinCVtbl_NewSegment = nullptr; +IPinCVtbl* g_pPinCVtbl_ReceiveConnection = nullptr; +IMemInputPinCVtbl* g_pMemInputPinCVtbl = nullptr; +IPinC* g_pPinC_NewSegment = nullptr; + +struct D3DFORMAT_TYPE { + int Format; + LPCTSTR Description; +}; + +const D3DFORMAT_TYPE D3DFormatType[] = { + { D3DFMT_UNKNOWN, _T("D3DFMT_UNKNOWN ") }, + { D3DFMT_R8G8B8, _T("D3DFMT_R8G8B8 ") }, + { D3DFMT_A8R8G8B8, _T("D3DFMT_A8R8G8B8 ") }, + { D3DFMT_X8R8G8B8, _T("D3DFMT_X8R8G8B8 ") }, + { D3DFMT_R5G6B5, _T("D3DFMT_R5G6B5 ") }, + { D3DFMT_X1R5G5B5, _T("D3DFMT_X1R5G5B5 ") }, + { D3DFMT_A1R5G5B5, _T("D3DFMT_A1R5G5B5 ") }, + { D3DFMT_A4R4G4B4, _T("D3DFMT_A4R4G4B4 ") }, + { D3DFMT_R3G3B2, _T("D3DFMT_R3G3B2 ") }, + { D3DFMT_A8, _T("D3DFMT_A8 ") }, + { D3DFMT_A8R3G3B2, _T("D3DFMT_A8R3G3B2 ") }, + { D3DFMT_X4R4G4B4, _T("D3DFMT_X4R4G4B4 ") }, + { D3DFMT_A2B10G10R10, _T("D3DFMT_A2B10G10R10 ") }, + { D3DFMT_A8B8G8R8, _T("D3DFMT_A8B8G8R8 ") }, + { D3DFMT_X8B8G8R8, _T("D3DFMT_X8B8G8R8 ") }, + { D3DFMT_G16R16, _T("D3DFMT_G16R16 ") }, + { D3DFMT_A2R10G10B10, _T("D3DFMT_A2R10G10B10 ") }, + { D3DFMT_A16B16G16R16, _T("D3DFMT_A16B16G16R16 ") }, + { D3DFMT_A8P8, _T("D3DFMT_A8P8 ") }, + { D3DFMT_P8, _T("D3DFMT_P8 ") }, + { D3DFMT_L8, _T("D3DFMT_L8 ") }, + { D3DFMT_A8L8, _T("D3DFMT_A8L8 ") }, + { D3DFMT_A4L4, _T("D3DFMT_A4L4 ") }, + { D3DFMT_X8L8V8U8, _T("D3DFMT_X8L8V8U8 ") }, + { D3DFMT_Q8W8V8U8, _T("D3DFMT_Q8W8V8U8 ") }, + { D3DFMT_V16U16, _T("D3DFMT_V16U16 ") }, + { D3DFMT_A2W10V10U10, _T("D3DFMT_A2W10V10U10 ") }, + { D3DFMT_UYVY, _T("D3DFMT_UYVY ") }, + { D3DFMT_R8G8_B8G8, _T("D3DFMT_R8G8_B8G8 ") }, + { D3DFMT_YUY2, _T("D3DFMT_YUY2 ") }, + { D3DFMT_G8R8_G8B8, _T("D3DFMT_G8R8_G8B8 ") }, + { D3DFMT_DXT1, _T("D3DFMT_DXT1 ") }, + { D3DFMT_DXT2, _T("D3DFMT_DXT2 ") }, + { D3DFMT_DXT3, _T("D3DFMT_DXT3 ") }, + { D3DFMT_DXT4, _T("D3DFMT_DXT4 ") }, + { D3DFMT_DXT5, _T("D3DFMT_DXT5 ") }, + { D3DFMT_D16_LOCKABLE, _T("D3DFMT_D16_LOCKABLE ") }, + { D3DFMT_D32, _T("D3DFMT_D32 ") }, + { D3DFMT_D15S1, _T("D3DFMT_D15S1 ") }, + { D3DFMT_D24S8, _T("D3DFMT_D24S8 ") }, + { D3DFMT_D24X8, _T("D3DFMT_D24X8 ") }, + { D3DFMT_D24X4S4, _T("D3DFMT_D24X4S4 ") }, + { D3DFMT_D16, _T("D3DFMT_D16 ") }, + { D3DFMT_D32F_LOCKABLE, _T("D3DFMT_D32F_LOCKABLE") }, + { D3DFMT_D24FS8, _T("D3DFMT_D24FS8 ") }, + { D3DFMT_L16, _T("D3DFMT_L16 ") }, + { D3DFMT_VERTEXDATA, _T("D3DFMT_VERTEXDATA ") }, + { D3DFMT_INDEX16, _T("D3DFMT_INDEX16 ") }, + { D3DFMT_INDEX32, _T("D3DFMT_INDEX32 ") }, + { D3DFMT_Q16W16V16U16, _T("D3DFMT_Q16W16V16U16 ") }, + + { MAKEFOURCC('N', 'V', '1', '2'), _T("D3DFMT_NV12") }, + { MAKEFOURCC('N', 'V', '2', '4'), _T("D3DFMT_NV24") }, +}; + +LPCTSTR FindD3DFormat(const D3DFORMAT Format) +{ + for (int i = 0; i < _countof(D3DFormatType); i++) { + if (Format == D3DFormatType[i].Format) { + return D3DFormatType[i].Description; + } + } + + return D3DFormatType[0].Description; +} + +// === DirectShow hooks +static HRESULT(STDMETHODCALLTYPE* NewSegmentOrg)(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) = nullptr; + +static HRESULT STDMETHODCALLTYPE NewSegmentMine(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) +{ + if (g_pPinC_NewSegment == This) { + g_tSegmentStart = tStart; + g_dRate = dRate; + } + + return NewSegmentOrg(This, tStart, tStop, dRate); +} + +static HRESULT(STDMETHODCALLTYPE* ReceiveConnectionOrg)(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt) = nullptr; + +static HRESULT STDMETHODCALLTYPE ReceiveConnectionMine(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt) +{ + // Force-reject P010 and P016 pixel formats due to Microsoft bug ... + if (pmt && (pmt->subtype == MEDIASUBTYPE_P010 || pmt->subtype == MEDIASUBTYPE_P016)) { + // ... but allow LAV Video Decoder to do that itself in order to support 10bit DXVA. + if (GetCLSID((IPin*)pConnector) != GUID_LAVVideo) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } + + return ReceiveConnectionOrg(This, pConnector, pmt); +} + + +static HRESULT(STDMETHODCALLTYPE* ReceiveOrg)(IMemInputPinC* This, IMediaSample* pSample) = nullptr; + +static HRESULT STDMETHODCALLTYPE ReceiveMine(IMemInputPinC* This, IMediaSample* pSample) +{ + REFERENCE_TIME rtStart, rtStop; + if (pSample && SUCCEEDED(pSample->GetTime(&rtStart, &rtStop))) { + g_tSampleStart = rtStart; + } + return ReceiveOrg(This, pSample); +} + +bool HookReceiveConnection(IBaseFilter* pBF) +{ + if (!pBF || g_pPinCVtbl_ReceiveConnection) { + return false; + } + + if (CComPtr pPin = GetFirstPin(pBF)) { + IPinC* pPinC = (IPinC*)(IPin*)pPin; + + DWORD flOldProtect = 0; + if (VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + if (ReceiveConnectionOrg == nullptr) { + ReceiveConnectionOrg = pPinC->lpVtbl->ReceiveConnection; + } + pPinC->lpVtbl->ReceiveConnection = ReceiveConnectionMine; + FlushInstructionCache(GetCurrentProcess(), pPinC->lpVtbl, sizeof(IPinCVtbl)); + VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); + g_pPinCVtbl_ReceiveConnection = pPinC->lpVtbl; + return true; + } else { + TRACE(_T("HookWorkAroundVideoDriversBug: Could not hook the VTable")); + ASSERT(FALSE); + } + } + return false; +} + +void UnhookReceiveConnection() +{ + // Unhook previous VTable + if (g_pPinCVtbl_ReceiveConnection) { + DWORD flOldProtect = 0; + if (VirtualProtect(g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + if (g_pPinCVtbl_ReceiveConnection->ReceiveConnection == ReceiveConnectionMine) { + g_pPinCVtbl_ReceiveConnection->ReceiveConnection = ReceiveConnectionOrg; + } + ReceiveConnectionOrg = nullptr; + FlushInstructionCache(GetCurrentProcess(), g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl)); + VirtualProtect(g_pPinCVtbl_ReceiveConnection, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); + g_pPinCVtbl_ReceiveConnection = nullptr; + } else { + TRACE(_T("UnhookReceiveConnection: Could not unhook previous VTable")); + ASSERT(FALSE); + } + } +} + +void UnhookNewSegment() +{ + // Unhook previous VTables + if (g_pPinCVtbl_NewSegment) { + DWORD flOldProtect = 0; + if (VirtualProtect(g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + if (g_pPinCVtbl_NewSegment->NewSegment == NewSegmentMine) { + g_pPinCVtbl_NewSegment->NewSegment = NewSegmentOrg; + } + FlushInstructionCache(GetCurrentProcess(), g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl)); + VirtualProtect(g_pPinCVtbl_NewSegment, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); + g_pPinCVtbl_NewSegment = nullptr; + g_pPinC_NewSegment = nullptr; + NewSegmentOrg = nullptr; + } else { + TRACE(_T("UnhookNewSegment: Could not unhook g_pPinCVtbl VTable")); + ASSERT(FALSE); + } + } +} + +void UnhookReceive() +{ + // Unhook previous VTables + if (g_pMemInputPinCVtbl) { + DWORD flOldProtect = 0; + if (VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + if (g_pMemInputPinCVtbl->Receive == ReceiveMine) { + g_pMemInputPinCVtbl->Receive = ReceiveOrg; + } + FlushInstructionCache(GetCurrentProcess(), g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl)); + VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect); + g_pMemInputPinCVtbl = nullptr; + ReceiveOrg = nullptr; + } else { + TRACE(_T("UnhookReceive: Could not unhook g_pMemInputPinCVtbl VTable")); + ASSERT(FALSE); + } + } +} + +bool HookNewSegment(IPinC* pPinC) +{ + if (!pPinC || g_pPinCVtbl_NewSegment) { + return false; + } + + DWORD flOldProtect = 0; + if (VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + g_tSegmentStart = 0; + g_dRate = 1.0; + if (NewSegmentOrg == nullptr) { + NewSegmentOrg = pPinC->lpVtbl->NewSegment; + } + pPinC->lpVtbl->NewSegment = NewSegmentMine; // Function sets global variable(s) + FlushInstructionCache(GetCurrentProcess(), pPinC->lpVtbl, sizeof(IPinCVtbl)); + VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect); + g_pPinCVtbl_NewSegment = pPinC->lpVtbl; + g_pPinC_NewSegment = pPinC; + return true; + } else { + TRACE(_T("HookNewSegment: Could not unhook VTable")); + ASSERT(FALSE); + } + + return false; +} + +bool HookReceive(IMemInputPinC* pMemInputPinC) +{ + if (!pMemInputPinC || g_pMemInputPinCVtbl) { + return false; + } + + DWORD flOldProtect = 0; + if (VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), PAGE_EXECUTE_WRITECOPY, &flOldProtect)) { + g_tSampleStart = 0; + if (ReceiveOrg == nullptr) { + ReceiveOrg = pMemInputPinC->lpVtbl->Receive; + } + pMemInputPinC->lpVtbl->Receive = ReceiveMine; // Function sets global variable(s) + FlushInstructionCache(GetCurrentProcess(), pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl)); + VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect); + g_pMemInputPinCVtbl = pMemInputPinC->lpVtbl; + return true; + } else { + TRACE(_T("HookReceive: Could not unhook VTable")); + ASSERT(FALSE); + } + + return false; +} diff --git a/src/filters/renderer/VideoRenderers/IPinHook.h b/src/filters/renderer/VideoRenderers/IPinHook.h index bf7108b751c..ccaa75c3d6a 100644 --- a/src/filters/renderer/VideoRenderers/IPinHook.h +++ b/src/filters/renderer/VideoRenderers/IPinHook.h @@ -1,82 +1,82 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#pragma once - -interface IPinC; - -typedef struct IPinCVtbl { - BEGIN_INTERFACE - HRESULT(STDMETHODCALLTYPE* QueryInterface)(IPinC* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject); - ULONG(STDMETHODCALLTYPE* AddRef)(IPinC* This); - ULONG(STDMETHODCALLTYPE* Release)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* Connect)(IPinC* This, /* [in] */ IPinC* pReceivePin, /* [in] */ const AM_MEDIA_TYPE* pmt); - HRESULT(STDMETHODCALLTYPE* ReceiveConnection)(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt); - HRESULT(STDMETHODCALLTYPE* Disconnect)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* ConnectedTo)(IPinC* This, /* [out] */ IPinC** pPin); - HRESULT(STDMETHODCALLTYPE* ConnectionMediaType)(IPinC* This, /* [out] */ AM_MEDIA_TYPE* pmt); - HRESULT(STDMETHODCALLTYPE* QueryPinInfo)(IPinC* This, /* [out] */ PIN_INFO* pInfo); - HRESULT(STDMETHODCALLTYPE* QueryDirection)(IPinC* This, /* [out] */ PIN_DIRECTION* pPinDir); - HRESULT(STDMETHODCALLTYPE* QueryId)(IPinC* This, /* [out] */ LPWSTR* Id); - HRESULT(STDMETHODCALLTYPE* QueryAccept)(IPinC* This, /* [in] */ const AM_MEDIA_TYPE* pmt); - HRESULT(STDMETHODCALLTYPE* EnumMediaTypes)(IPinC* This, /* [out] */ IEnumMediaTypes** ppEnum); - HRESULT(STDMETHODCALLTYPE* QueryInternalConnections)(IPinC* This, /* [out] */ IPinC** apPin, /* [out][in] */ ULONG* nPin); - HRESULT(STDMETHODCALLTYPE* EndOfStream)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* BeginFlush)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* EndFlush)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* NewSegment)(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate); - END_INTERFACE -} IPinCVtbl; - -interface IPinC -{ - CONST_VTBL struct IPinCVtbl* lpVtbl; -}; - -interface IMemInputPinC; - -typedef struct IMemInputPinCVtbl { - BEGIN_INTERFACE - HRESULT(STDMETHODCALLTYPE* QueryInterface)(IPinC* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject); - ULONG(STDMETHODCALLTYPE* AddRef)(IPinC* This); - ULONG(STDMETHODCALLTYPE* Release)(IPinC* This); - HRESULT(STDMETHODCALLTYPE* GetAllocator)(IMemInputPinC* This, IMemAllocator** ppAllocator); - HRESULT(STDMETHODCALLTYPE* NotifyAllocator)(IMemInputPinC* This, IMemAllocator* pAllocator, BOOL bReadOnly); - HRESULT(STDMETHODCALLTYPE* GetAllocatorRequirements)(IMemInputPinC* This, ALLOCATOR_PROPERTIES* pProps); - HRESULT(STDMETHODCALLTYPE* Receive)(IMemInputPinC* This, IMediaSample* pSample); - HRESULT(STDMETHODCALLTYPE* ReceiveMultiple)(IMemInputPinC* This, IMediaSample** pSamples, long nSamples, long* nSamplesProcessed); - HRESULT(STDMETHODCALLTYPE* ReceiveCanBlock)(IMemInputPinC* This); - END_INTERFACE -} IMemInputPinCVtbl; - -interface IMemInputPinC -{ - CONST_VTBL struct IMemInputPinCVtbl* lpVtbl; -}; - -extern bool HookNewSegment(IPinC* pPinC); -extern bool HookReceive(IMemInputPinC* pMemInputPin); -extern void UnhookNewSegment(); -extern void UnhookReceive(); -extern REFERENCE_TIME g_tSegmentStart, g_tSampleStart, g_rtTimePerFrame; - -extern bool HookReceiveConnection(IBaseFilter* pBF); -extern void UnhookReceiveConnection(); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#pragma once + +interface IPinC; + +typedef struct IPinCVtbl { + BEGIN_INTERFACE + HRESULT(STDMETHODCALLTYPE* QueryInterface)(IPinC* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject); + ULONG(STDMETHODCALLTYPE* AddRef)(IPinC* This); + ULONG(STDMETHODCALLTYPE* Release)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* Connect)(IPinC* This, /* [in] */ IPinC* pReceivePin, /* [in] */ const AM_MEDIA_TYPE* pmt); + HRESULT(STDMETHODCALLTYPE* ReceiveConnection)(IPinC* This, /* [in] */ IPinC* pConnector, /* [in] */ const AM_MEDIA_TYPE* pmt); + HRESULT(STDMETHODCALLTYPE* Disconnect)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* ConnectedTo)(IPinC* This, /* [out] */ IPinC** pPin); + HRESULT(STDMETHODCALLTYPE* ConnectionMediaType)(IPinC* This, /* [out] */ AM_MEDIA_TYPE* pmt); + HRESULT(STDMETHODCALLTYPE* QueryPinInfo)(IPinC* This, /* [out] */ PIN_INFO* pInfo); + HRESULT(STDMETHODCALLTYPE* QueryDirection)(IPinC* This, /* [out] */ PIN_DIRECTION* pPinDir); + HRESULT(STDMETHODCALLTYPE* QueryId)(IPinC* This, /* [out] */ LPWSTR* Id); + HRESULT(STDMETHODCALLTYPE* QueryAccept)(IPinC* This, /* [in] */ const AM_MEDIA_TYPE* pmt); + HRESULT(STDMETHODCALLTYPE* EnumMediaTypes)(IPinC* This, /* [out] */ IEnumMediaTypes** ppEnum); + HRESULT(STDMETHODCALLTYPE* QueryInternalConnections)(IPinC* This, /* [out] */ IPinC** apPin, /* [out][in] */ ULONG* nPin); + HRESULT(STDMETHODCALLTYPE* EndOfStream)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* BeginFlush)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* EndFlush)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* NewSegment)(IPinC* This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate); + END_INTERFACE +} IPinCVtbl; + +interface IPinC +{ + CONST_VTBL struct IPinCVtbl* lpVtbl; +}; + +interface IMemInputPinC; + +typedef struct IMemInputPinCVtbl { + BEGIN_INTERFACE + HRESULT(STDMETHODCALLTYPE* QueryInterface)(IPinC* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject); + ULONG(STDMETHODCALLTYPE* AddRef)(IPinC* This); + ULONG(STDMETHODCALLTYPE* Release)(IPinC* This); + HRESULT(STDMETHODCALLTYPE* GetAllocator)(IMemInputPinC* This, IMemAllocator** ppAllocator); + HRESULT(STDMETHODCALLTYPE* NotifyAllocator)(IMemInputPinC* This, IMemAllocator* pAllocator, BOOL bReadOnly); + HRESULT(STDMETHODCALLTYPE* GetAllocatorRequirements)(IMemInputPinC* This, ALLOCATOR_PROPERTIES* pProps); + HRESULT(STDMETHODCALLTYPE* Receive)(IMemInputPinC* This, IMediaSample* pSample); + HRESULT(STDMETHODCALLTYPE* ReceiveMultiple)(IMemInputPinC* This, IMediaSample** pSamples, long nSamples, long* nSamplesProcessed); + HRESULT(STDMETHODCALLTYPE* ReceiveCanBlock)(IMemInputPinC* This); + END_INTERFACE +} IMemInputPinCVtbl; + +interface IMemInputPinC +{ + CONST_VTBL struct IMemInputPinCVtbl* lpVtbl; +}; + +extern bool HookNewSegment(IPinC* pPinC); +extern bool HookReceive(IMemInputPinC* pMemInputPin); +extern void UnhookNewSegment(); +extern void UnhookReceive(); +extern REFERENCE_TIME g_tSegmentStart, g_tSampleStart, g_rtTimePerFrame; + +extern bool HookReceiveConnection(IBaseFilter* pBF); +extern void UnhookReceiveConnection(); diff --git a/src/filters/renderer/VideoRenderers/IQTVideoSurface.h b/src/filters/renderer/VideoRenderers/IQTVideoSurface.h index 066be1a64db..6b23954b00f 100644 --- a/src/filters/renderer/VideoRenderers/IQTVideoSurface.h +++ b/src/filters/renderer/VideoRenderers/IQTVideoSurface.h @@ -1,34 +1,34 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2017 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 . - * - */ - -#pragma once - -// -// IQTVideoSurface -// - -interface __declspec(uuid("A6AE36F7-A6F2-4157-AF54-6599857E4E20")) - IQTVideoSurface : - public IUnknown -{ - STDMETHOD(BeginBlt)(const BITMAP& bm) PURE; - STDMETHOD(DoBlt)(const BITMAP& bm) PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2017 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 . + * + */ + +#pragma once + +// +// IQTVideoSurface +// + +interface __declspec(uuid("A6AE36F7-A6F2-4157-AF54-6599857E4E20")) + IQTVideoSurface : + public IUnknown +{ + STDMETHOD(BeginBlt)(const BITMAP& bm) PURE; + STDMETHOD(DoBlt)(const BITMAP& bm) PURE; +}; diff --git a/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp b/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp index 8715410a66f..8bf96ea5556 100644 --- a/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp +++ b/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp @@ -1,98 +1,98 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "MacrovisionKicker.h" - - -// -// CMacrovisionKicker -// - -CMacrovisionKicker::CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk) - : CUnknown(pName, pUnk) -{ -} - -CMacrovisionKicker::~CMacrovisionKicker() -{ -} - -void CMacrovisionKicker::SetInner(IUnknown* pUnk) -{ - m_pInner = pUnk; -} - -STDMETHODIMP CMacrovisionKicker::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - if (riid == __uuidof(IUnknown)) { - return __super::NonDelegatingQueryInterface(riid, ppv); - } - if (riid == __uuidof(IKsPropertySet) && CComQIPtr(m_pInner)) { - return GetInterface((IKsPropertySet*)this, ppv); - } - - HRESULT hr = m_pInner ? m_pInner->QueryInterface(riid, ppv) : E_NOINTERFACE; - - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IKsPropertySet - -STDMETHODIMP CMacrovisionKicker::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength) -{ - if (PropSet == AM_KSPROPSETID_CopyProt && (Id == AM_PROPERTY_COPY_MACROVISION || Id == AM_PROPERTY_COPY_DIGITAL_CP)) { - TRACE(_T("Bypassing macrovision DVD protection\n")); - return S_OK; - } - if (CComQIPtr pKsPS = m_pInner) { - return pKsPS->Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength); - } - return E_UNEXPECTED; -} - -STDMETHODIMP CMacrovisionKicker::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned) -{ - if (PropSet == AM_KSPROPSETID_CopyProt) { - if (Id == AM_PROPERTY_COPY_ANALOG_COMPONENT) { - if (pPropertyData && DataLength >= sizeof(ULONG) && pBytesReturned) { - *(ULONG*)pPropertyData = FALSE; - *pBytesReturned = sizeof(ULONG); - return S_OK; - } - return E_INVALIDARG; - } - } - if (CComQIPtr pKsPS = m_pInner) { - return pKsPS->Get(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength, pBytesReturned); - } - - return E_UNEXPECTED; -} - -STDMETHODIMP CMacrovisionKicker::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) -{ - if (CComQIPtr pKsPS = m_pInner) { - return pKsPS->QuerySupported(PropSet, Id, pTypeSupport); - } - - return E_UNEXPECTED; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "MacrovisionKicker.h" + + +// +// CMacrovisionKicker +// + +CMacrovisionKicker::CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk) + : CUnknown(pName, pUnk) +{ +} + +CMacrovisionKicker::~CMacrovisionKicker() +{ +} + +void CMacrovisionKicker::SetInner(IUnknown* pUnk) +{ + m_pInner = pUnk; +} + +STDMETHODIMP CMacrovisionKicker::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + if (riid == __uuidof(IUnknown)) { + return __super::NonDelegatingQueryInterface(riid, ppv); + } + if (riid == __uuidof(IKsPropertySet) && CComQIPtr(m_pInner)) { + return GetInterface((IKsPropertySet*)this, ppv); + } + + HRESULT hr = m_pInner ? m_pInner->QueryInterface(riid, ppv) : E_NOINTERFACE; + + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IKsPropertySet + +STDMETHODIMP CMacrovisionKicker::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength) +{ + if (PropSet == AM_KSPROPSETID_CopyProt && (Id == AM_PROPERTY_COPY_MACROVISION || Id == AM_PROPERTY_COPY_DIGITAL_CP)) { + TRACE(_T("Bypassing macrovision DVD protection\n")); + return S_OK; + } + if (CComQIPtr pKsPS = m_pInner) { + return pKsPS->Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength); + } + return E_UNEXPECTED; +} + +STDMETHODIMP CMacrovisionKicker::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned) +{ + if (PropSet == AM_KSPROPSETID_CopyProt) { + if (Id == AM_PROPERTY_COPY_ANALOG_COMPONENT) { + if (pPropertyData && DataLength >= sizeof(ULONG) && pBytesReturned) { + *(ULONG*)pPropertyData = FALSE; + *pBytesReturned = sizeof(ULONG); + return S_OK; + } + return E_INVALIDARG; + } + } + if (CComQIPtr pKsPS = m_pInner) { + return pKsPS->Get(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength, pBytesReturned); + } + + return E_UNEXPECTED; +} + +STDMETHODIMP CMacrovisionKicker::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) +{ + if (CComQIPtr pKsPS = m_pInner) { + return pKsPS->QuerySupported(PropSet, Id, pTypeSupport); + } + + return E_UNEXPECTED; +} diff --git a/src/filters/renderer/VideoRenderers/MacrovisionKicker.h b/src/filters/renderer/VideoRenderers/MacrovisionKicker.h index 566753a8bf9..628fa38d495 100644 --- a/src/filters/renderer/VideoRenderers/MacrovisionKicker.h +++ b/src/filters/renderer/VideoRenderers/MacrovisionKicker.h @@ -1,43 +1,43 @@ -/* - * (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 . - * - */ - -#pragma once - -class CMacrovisionKicker - : public CUnknown - , public IKsPropertySet -{ - CComPtr m_pInner; - -public: - CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk); - virtual ~CMacrovisionKicker(); - - void SetInner(IUnknown* pUnk); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IKsPropertySet - STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength); - STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned); - STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport); -}; +/* + * (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 . + * + */ + +#pragma once + +class CMacrovisionKicker + : public CUnknown + , public IKsPropertySet +{ + CComPtr m_pInner; + +public: + CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk); + virtual ~CMacrovisionKicker(); + + void SetInner(IUnknown* pUnk); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IKsPropertySet + STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength); + STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned); + STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport); +}; diff --git a/src/filters/renderer/VideoRenderers/OuterEVR.cpp b/src/filters/renderer/VideoRenderers/OuterEVR.cpp index 9dcf3331dd4..a3d65c24dba 100644 --- a/src/filters/renderer/VideoRenderers/OuterEVR.cpp +++ b/src/filters/renderer/VideoRenderers/OuterEVR.cpp @@ -1,154 +1,154 @@ -/* - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "AllocatorCommon.h" -#include "EVRAllocatorPresenter.h" -#include "OuterEVR.h" - -using namespace DSObjects; - -STDMETHODIMP COuterEVR::EnumPins(__out IEnumPins** ppEnum) -{ - if (m_pEVRBase) { - return m_pEVRBase->EnumPins(ppEnum); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::FindPin(LPCWSTR Id, __out IPin** ppPin) -{ - if (m_pEVRBase) { - return m_pEVRBase->FindPin(Id, ppPin); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::QueryFilterInfo(__out FILTER_INFO* pInfo) -{ - if (m_pEVRBase) { - return m_pEVRBase->QueryFilterInfo(pInfo); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName) -{ - if (m_pEVRBase) { - return m_pEVRBase->JoinFilterGraph(pGraph, pName); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::QueryVendorInfo(__out LPWSTR* pVendorInfo) -{ - if (m_pEVRBase) { - return m_pEVRBase->QueryVendorInfo(pVendorInfo); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::Stop() -{ - if (m_pEVRBase) { - return m_pEVRBase->Stop(); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::Pause() -{ - if (m_pEVRBase) { - return m_pEVRBase->Pause(); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::Run(REFERENCE_TIME tStart) -{ - if (m_pEVRBase) { - return m_pEVRBase->Run(tStart); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State) -{ - HRESULT ReturnValue; - if (m_pAllocatorPresenter->GetState(dwMilliSecsTimeout, State, ReturnValue)) { - return ReturnValue; - } - if (m_pEVRBase) { - return m_pEVRBase->GetState(dwMilliSecsTimeout, State); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::SetSyncSource(__in_opt IReferenceClock* pClock) -{ - if (m_pEVRBase) { - return m_pEVRBase->SetSyncSource(pClock); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::GetSyncSource(__deref_out_opt IReferenceClock** pClock) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetSyncSource(pClock); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::GetClassID(__RPC__out CLSID* pClassID) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetClassID(pClassID); - } - return E_NOTIMPL; -} - -STDMETHODIMP COuterEVR::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); - return S_OK; -} - -STDMETHODIMP COuterEVR::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} - -STDMETHODIMP COuterEVR::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} +/* + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "AllocatorCommon.h" +#include "EVRAllocatorPresenter.h" +#include "OuterEVR.h" + +using namespace DSObjects; + +STDMETHODIMP COuterEVR::EnumPins(__out IEnumPins** ppEnum) +{ + if (m_pEVRBase) { + return m_pEVRBase->EnumPins(ppEnum); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::FindPin(LPCWSTR Id, __out IPin** ppPin) +{ + if (m_pEVRBase) { + return m_pEVRBase->FindPin(Id, ppPin); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::QueryFilterInfo(__out FILTER_INFO* pInfo) +{ + if (m_pEVRBase) { + return m_pEVRBase->QueryFilterInfo(pInfo); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName) +{ + if (m_pEVRBase) { + return m_pEVRBase->JoinFilterGraph(pGraph, pName); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::QueryVendorInfo(__out LPWSTR* pVendorInfo) +{ + if (m_pEVRBase) { + return m_pEVRBase->QueryVendorInfo(pVendorInfo); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::Stop() +{ + if (m_pEVRBase) { + return m_pEVRBase->Stop(); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::Pause() +{ + if (m_pEVRBase) { + return m_pEVRBase->Pause(); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::Run(REFERENCE_TIME tStart) +{ + if (m_pEVRBase) { + return m_pEVRBase->Run(tStart); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State) +{ + HRESULT ReturnValue; + if (m_pAllocatorPresenter->GetState(dwMilliSecsTimeout, State, ReturnValue)) { + return ReturnValue; + } + if (m_pEVRBase) { + return m_pEVRBase->GetState(dwMilliSecsTimeout, State); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::SetSyncSource(__in_opt IReferenceClock* pClock) +{ + if (m_pEVRBase) { + return m_pEVRBase->SetSyncSource(pClock); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::GetSyncSource(__deref_out_opt IReferenceClock** pClock) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetSyncSource(pClock); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::GetClassID(__RPC__out CLSID* pClassID) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetClassID(pClassID); + } + return E_NOTIMPL; +} + +STDMETHODIMP COuterEVR::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); + return S_OK; +} + +STDMETHODIMP COuterEVR::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} + +STDMETHODIMP COuterEVR::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/OuterEVR.h b/src/filters/renderer/VideoRenderers/OuterEVR.h index b8e10dddf03..0209f558f21 100644 --- a/src/filters/renderer/VideoRenderers/OuterEVR.h +++ b/src/filters/renderer/VideoRenderers/OuterEVR.h @@ -1,91 +1,91 @@ -/* - * (C) 2006-2014 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 . - * - */ - -#pragma once - -/// === Outer EVR -namespace DSObjects -{ - class COuterEVR - : public CUnknown - , public IVMRMixerBitmap9 - , public IBaseFilter - { - CComPtr m_pEVR; - IBaseFilter* m_pEVRBase; - VMR9AlphaBitmap* m_pVMR9AlphaBitmap; - CEVRAllocatorPresenter* m_pAllocatorPresenter; - - public: - COuterEVR(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CEVRAllocatorPresenter* pAllocatorPresenter) : CUnknown(pName, pUnk) { - hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner()); - CComQIPtr pEVRBase = m_pEVR; - m_pEVRBase = pEVRBase; // Don't keep a second reference on the EVR filter - m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; - m_pAllocatorPresenter = pAllocatorPresenter; - } - - ~COuterEVR() {} - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - HRESULT hr; - - if (riid == __uuidof(IVMRMixerBitmap9)) { - return GetInterface((IVMRMixerBitmap9*)this, ppv); - } - if (riid == __uuidof(IMediaFilter)) { - return GetInterface((IMediaFilter*)this, ppv); - } - if (riid == __uuidof(IPersist)) { - return GetInterface((IPersist*)this, ppv); - } - if (riid == __uuidof(IBaseFilter)) { - return GetInterface((IBaseFilter*)this, ppv); - } - - hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE; - if (m_pEVR && FAILED(hr)) { - hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; - } - - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IBaseFilter - STDMETHODIMP EnumPins(__out IEnumPins** ppEnum); - STDMETHODIMP FindPin(LPCWSTR Id, __out IPin** ppPin); - STDMETHODIMP QueryFilterInfo(__out FILTER_INFO* pInfo); - STDMETHODIMP JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName); - STDMETHODIMP QueryVendorInfo(__out LPWSTR* pVendorInfo); - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME tStart); - STDMETHODIMP GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State); - STDMETHODIMP SetSyncSource(__in_opt IReferenceClock* pClock); - STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock** pClock); - STDMETHODIMP GetClassID(__RPC__out CLSID* pClassID); - - // IVMRMixerBitmap9 - STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); - }; -} +/* + * (C) 2006-2014 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 . + * + */ + +#pragma once + +/// === Outer EVR +namespace DSObjects +{ + class COuterEVR + : public CUnknown + , public IVMRMixerBitmap9 + , public IBaseFilter + { + CComPtr m_pEVR; + IBaseFilter* m_pEVRBase; + VMR9AlphaBitmap* m_pVMR9AlphaBitmap; + CEVRAllocatorPresenter* m_pAllocatorPresenter; + + public: + COuterEVR(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CEVRAllocatorPresenter* pAllocatorPresenter) : CUnknown(pName, pUnk) { + hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner()); + CComQIPtr pEVRBase = m_pEVR; + m_pEVRBase = pEVRBase; // Don't keep a second reference on the EVR filter + m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; + m_pAllocatorPresenter = pAllocatorPresenter; + } + + ~COuterEVR() {} + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + HRESULT hr; + + if (riid == __uuidof(IVMRMixerBitmap9)) { + return GetInterface((IVMRMixerBitmap9*)this, ppv); + } + if (riid == __uuidof(IMediaFilter)) { + return GetInterface((IMediaFilter*)this, ppv); + } + if (riid == __uuidof(IPersist)) { + return GetInterface((IPersist*)this, ppv); + } + if (riid == __uuidof(IBaseFilter)) { + return GetInterface((IBaseFilter*)this, ppv); + } + + hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE; + if (m_pEVR && FAILED(hr)) { + hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; + } + + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IBaseFilter + STDMETHODIMP EnumPins(__out IEnumPins** ppEnum); + STDMETHODIMP FindPin(LPCWSTR Id, __out IPin** ppPin); + STDMETHODIMP QueryFilterInfo(__out FILTER_INFO* pInfo); + STDMETHODIMP JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName); + STDMETHODIMP QueryVendorInfo(__out LPWSTR* pVendorInfo); + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME tStart); + STDMETHODIMP GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State); + STDMETHODIMP SetSyncSource(__in_opt IReferenceClock* pClock); + STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock** pClock); + STDMETHODIMP GetClassID(__RPC__out CLSID* pClassID); + + // IVMRMixerBitmap9 + STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); + }; +} diff --git a/src/filters/renderer/VideoRenderers/OuterVMR.cpp b/src/filters/renderer/VideoRenderers/OuterVMR.cpp index 1da243c44e6..c62b26c8234 100644 --- a/src/filters/renderer/VideoRenderers/OuterVMR.cpp +++ b/src/filters/renderer/VideoRenderers/OuterVMR.cpp @@ -1,170 +1,170 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "AllocatorCommon.h" -#include "VMR9AllocatorPresenter.h" -#include "OuterVMR.h" - -using namespace DSObjects; - -STDMETHODIMP COuterVMR9::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) -{ - if (CComQIPtr pWC9 = m_pVMR) { - return pWC9->GetNativeVideoSize(lpWidth, lpHeight, lpARWidth, lpARHeight); - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect) -{ - if (CComQIPtr pWC9 = m_pVMR) { - return pWC9->GetVideoPosition(lpSRCRect, lpDSTRect); - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::GetAspectRatioMode(DWORD* lpAspectRatioMode) -{ - if (CComQIPtr pWC9 = m_pVMR) { - *lpAspectRatioMode = VMR_ARMODE_NONE; - return S_OK; - } - - return E_NOTIMPL; -} - -// IVideoWindow -STDMETHODIMP COuterVMR9::get_Width(long* pWidth) -{ - if (CComQIPtr pWC9 = m_pVMR) { - CRect s, d; - HRESULT hr = pWC9->GetVideoPosition(&s, &d); - *pWidth = d.Width(); - return hr; - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::get_Height(long* pHeight) -{ - if (CComQIPtr pWC9 = m_pVMR) { - CRect s, d; - HRESULT hr = pWC9->GetVideoPosition(&s, &d); - *pHeight = d.Height(); - return hr; - } - - return E_NOTIMPL; -} - -// IBasicVideo2 -STDMETHODIMP COuterVMR9::GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - // DVD Nav. bug workaround fix - { - *pLeft = *pTop = 0; - return GetVideoSize(pWidth, pHeight); - } - /* - if (CComQIPtr pWC9 = m_pVMR) - { - CRect s, d; - HRESULT hr = pWC9->GetVideoPosition(&s, &d); - *pLeft = s.left; - *pTop = s.top; - *pWidth = s.Width(); - *pHeight = s.Height(); - return hr; - } - return E_NOTIMPL; - */ -} - -STDMETHODIMP COuterVMR9::GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - if (CComQIPtr pWC9 = m_pVMR) { - CRect s, d; - HRESULT hr = pWC9->GetVideoPosition(&s, &d); - *pLeft = d.left; - *pTop = d.top; - *pWidth = d.Width(); - *pHeight = d.Height(); - return hr; - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::GetVideoSize(long* pWidth, long* pHeight) -{ - if (CComQIPtr pWC9 = m_pVMR) { - LONG aw, ah; - //return pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah); - // DVD Nav. bug workaround fix - HRESULT hr = pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah); - *pWidth = *pHeight * aw / ah; - return hr; - } - - return E_NOTIMPL; -} - -STDMETHODIMP COuterVMR9::GetPreferredAspectRatio(long* plAspectX, long* plAspectY) -{ - if (CComQIPtr pWC9 = m_pVMR) { - LONG w, h; - return pWC9->GetNativeVideoSize(&w, &h, plAspectX, plAspectY); - } - - return E_NOTIMPL; -} - -// IVMRMixerBitmap9 -STDMETHODIMP COuterVMR9::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); - return S_OK; -} - -STDMETHODIMP COuterVMR9::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} - -STDMETHODIMP COuterVMR9::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "AllocatorCommon.h" +#include "VMR9AllocatorPresenter.h" +#include "OuterVMR.h" + +using namespace DSObjects; + +STDMETHODIMP COuterVMR9::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) +{ + if (CComQIPtr pWC9 = m_pVMR) { + return pWC9->GetNativeVideoSize(lpWidth, lpHeight, lpARWidth, lpARHeight); + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect) +{ + if (CComQIPtr pWC9 = m_pVMR) { + return pWC9->GetVideoPosition(lpSRCRect, lpDSTRect); + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::GetAspectRatioMode(DWORD* lpAspectRatioMode) +{ + if (CComQIPtr pWC9 = m_pVMR) { + *lpAspectRatioMode = VMR_ARMODE_NONE; + return S_OK; + } + + return E_NOTIMPL; +} + +// IVideoWindow +STDMETHODIMP COuterVMR9::get_Width(long* pWidth) +{ + if (CComQIPtr pWC9 = m_pVMR) { + CRect s, d; + HRESULT hr = pWC9->GetVideoPosition(&s, &d); + *pWidth = d.Width(); + return hr; + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::get_Height(long* pHeight) +{ + if (CComQIPtr pWC9 = m_pVMR) { + CRect s, d; + HRESULT hr = pWC9->GetVideoPosition(&s, &d); + *pHeight = d.Height(); + return hr; + } + + return E_NOTIMPL; +} + +// IBasicVideo2 +STDMETHODIMP COuterVMR9::GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + // DVD Nav. bug workaround fix + { + *pLeft = *pTop = 0; + return GetVideoSize(pWidth, pHeight); + } + /* + if (CComQIPtr pWC9 = m_pVMR) + { + CRect s, d; + HRESULT hr = pWC9->GetVideoPosition(&s, &d); + *pLeft = s.left; + *pTop = s.top; + *pWidth = s.Width(); + *pHeight = s.Height(); + return hr; + } + return E_NOTIMPL; + */ +} + +STDMETHODIMP COuterVMR9::GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + if (CComQIPtr pWC9 = m_pVMR) { + CRect s, d; + HRESULT hr = pWC9->GetVideoPosition(&s, &d); + *pLeft = d.left; + *pTop = d.top; + *pWidth = d.Width(); + *pHeight = d.Height(); + return hr; + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::GetVideoSize(long* pWidth, long* pHeight) +{ + if (CComQIPtr pWC9 = m_pVMR) { + LONG aw, ah; + //return pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah); + // DVD Nav. bug workaround fix + HRESULT hr = pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah); + *pWidth = *pHeight * aw / ah; + return hr; + } + + return E_NOTIMPL; +} + +STDMETHODIMP COuterVMR9::GetPreferredAspectRatio(long* plAspectX, long* plAspectY) +{ + if (CComQIPtr pWC9 = m_pVMR) { + LONG w, h; + return pWC9->GetNativeVideoSize(&w, &h, plAspectX, plAspectY); + } + + return E_NOTIMPL; +} + +// IVMRMixerBitmap9 +STDMETHODIMP COuterVMR9::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); + return S_OK; +} + +STDMETHODIMP COuterVMR9::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} + +STDMETHODIMP COuterVMR9::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/OuterVMR.h b/src/filters/renderer/VideoRenderers/OuterVMR.h index 3d01d5d6955..34fe9e8e325 100644 --- a/src/filters/renderer/VideoRenderers/OuterVMR.h +++ b/src/filters/renderer/VideoRenderers/OuterVMR.h @@ -1,201 +1,201 @@ -/* - * (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 . - * - */ - -#pragma once - -namespace DSObjects -{ - class COuterVMR9 - : public CUnknown - , public IVideoWindow - , public IBasicVideo2 - , public IVMRWindowlessControl - , public IVMRMixerBitmap9 - { - CComPtr m_pVMR; - VMR9AlphaBitmap* m_pVMR9AlphaBitmap; - CVMR9AllocatorPresenter* m_pAllocatorPresenter; - - public: - - COuterVMR9(const TCHAR* pName, LPUNKNOWN pUnk, VMR9AlphaBitmap* pVMR9AlphaBitmap, CVMR9AllocatorPresenter* pAllocatorPresenter) : CUnknown(pName, pUnk) { - m_pVMR.CoCreateInstance(CLSID_VideoMixingRenderer9, GetOwner()); - m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; - m_pAllocatorPresenter = pAllocatorPresenter; - } - - ~COuterVMR9() { - m_pVMR = nullptr; - } - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - HRESULT hr; - - // Casimir666 : in renderless mode, do the inlaying in place of VMR - if (riid == __uuidof(IVMRMixerBitmap9)) { - return GetInterface((IVMRMixerBitmap9*)this, ppv); - } - - hr = m_pVMR ? m_pVMR->QueryInterface(riid, ppv) : E_NOINTERFACE; - if (m_pVMR && FAILED(hr)) { - hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; - if (FAILED(hr)) { - if (riid == __uuidof(IVideoWindow)) { - return GetInterface((IVideoWindow*)this, ppv); - } - if (riid == __uuidof(IBasicVideo)) { - return GetInterface((IBasicVideo*)this, ppv); - } - if (riid == __uuidof(IBasicVideo2)) { - return GetInterface((IBasicVideo2*)this, ppv); - } - /*if (riid == __uuidof(IVMRWindowlessControl)) - return GetInterface((IVMRWindowlessControl*)this, ppv); - */ - } - } - - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IVMRWindowlessControl - - STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); - - STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) { return E_NOTIMPL; } - STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) { return E_NOTIMPL; } - STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) { return E_NOTIMPL; } - STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect); - - STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode); - STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode) { return E_NOTIMPL; } - STDMETHODIMP SetVideoClippingWindow(HWND hwnd) { return E_NOTIMPL; } - STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc) { return E_NOTIMPL; } - STDMETHODIMP DisplayModeChanged() { return E_NOTIMPL; } - STDMETHODIMP GetCurrentImage(BYTE** lpDib) { return E_NOTIMPL; } - STDMETHODIMP SetBorderColor(COLORREF Clr) { return E_NOTIMPL; } - STDMETHODIMP GetBorderColor(COLORREF* lpClr) { return E_NOTIMPL; } - STDMETHODIMP SetColorKey(COLORREF Clr) { return E_NOTIMPL; } - STDMETHODIMP GetColorKey(COLORREF* lpClr) { return E_NOTIMPL; } - - // IVideoWindow - STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } - STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; } - STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { - return E_NOTIMPL; - } - STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, - VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { - return E_NOTIMPL; - } - STDMETHODIMP put_Caption(BSTR strCaption) { return E_NOTIMPL; } - STDMETHODIMP get_Caption(BSTR* strCaption) { return E_NOTIMPL; } - STDMETHODIMP put_WindowStyle(long WindowStyle) { return E_NOTIMPL; } - STDMETHODIMP get_WindowStyle(long* WindowStyle) { return E_NOTIMPL; } - STDMETHODIMP put_WindowStyleEx(long WindowStyleEx) { return E_NOTIMPL; } - STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx) { return E_NOTIMPL; } - STDMETHODIMP put_AutoShow(long AutoShow) { return E_NOTIMPL; } - STDMETHODIMP get_AutoShow(long* AutoShow) { return E_NOTIMPL; } - STDMETHODIMP put_WindowState(long WindowState) { return E_NOTIMPL; } - STDMETHODIMP get_WindowState(long* WindowState) { return E_NOTIMPL; } - STDMETHODIMP put_BackgroundPalette(long BackgroundPalette) { return E_NOTIMPL; } - STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette) { return E_NOTIMPL; } - STDMETHODIMP put_Visible(long Visible) { return E_NOTIMPL; } - STDMETHODIMP get_Visible(long* pVisible) { return E_NOTIMPL; } - STDMETHODIMP put_Left(long Left) { return E_NOTIMPL; } - STDMETHODIMP get_Left(long* pLeft) { return E_NOTIMPL; } - STDMETHODIMP put_Width(long Width) { return E_NOTIMPL; } - STDMETHODIMP get_Width(long* pWidth); - - STDMETHODIMP put_Top(long Top) { return E_NOTIMPL; } - STDMETHODIMP get_Top(long* pTop) { return E_NOTIMPL; } - STDMETHODIMP put_Height(long Height) { return E_NOTIMPL; } - STDMETHODIMP get_Height(long* pHeight); - - STDMETHODIMP put_Owner(OAHWND Owner) { return E_NOTIMPL; } - STDMETHODIMP get_Owner(OAHWND* Owner) { return E_NOTIMPL; } - STDMETHODIMP put_MessageDrain(OAHWND Drain) { return E_NOTIMPL; } - STDMETHODIMP get_MessageDrain(OAHWND* Drain) { return E_NOTIMPL; } - STDMETHODIMP get_BorderColor(long* Color) { return E_NOTIMPL; } - STDMETHODIMP put_BorderColor(long Color) { return E_NOTIMPL; } - STDMETHODIMP get_FullScreenMode(long* FullScreenMode) { return E_NOTIMPL; } - STDMETHODIMP put_FullScreenMode(long FullScreenMode) { return E_NOTIMPL; } - STDMETHODIMP SetWindowForeground(long Focus) { return E_NOTIMPL; } - STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) { - return E_NOTIMPL; - } - STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } - STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) { - return E_NOTIMPL; - } - STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight) { return E_NOTIMPL; } - STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight) { return E_NOTIMPL; } - STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) { return E_NOTIMPL; } - STDMETHODIMP HideCursor(long HideCursor) { return E_NOTIMPL; } - STDMETHODIMP IsCursorHidden(long* CursorHidden) { return E_NOTIMPL; } - - // IBasicVideo2 - STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) { return E_NOTIMPL; } - STDMETHODIMP get_BitRate(long* pBitRate) { return E_NOTIMPL; } - STDMETHODIMP get_BitErrorRate(long* pBitErrorRate) { return E_NOTIMPL; } - STDMETHODIMP get_VideoWidth(long* pVideoWidth) { return E_NOTIMPL; } - STDMETHODIMP get_VideoHeight(long* pVideoHeight) { return E_NOTIMPL; } - STDMETHODIMP put_SourceLeft(long SourceLeft) { return E_NOTIMPL; } - STDMETHODIMP get_SourceLeft(long* pSourceLeft) { return E_NOTIMPL; } - STDMETHODIMP put_SourceWidth(long SourceWidth) { return E_NOTIMPL; } - STDMETHODIMP get_SourceWidth(long* pSourceWidth) { return E_NOTIMPL; } - STDMETHODIMP put_SourceTop(long SourceTop) { return E_NOTIMPL; } - STDMETHODIMP get_SourceTop(long* pSourceTop) { return E_NOTIMPL; } - STDMETHODIMP put_SourceHeight(long SourceHeight) { return E_NOTIMPL; } - STDMETHODIMP get_SourceHeight(long* pSourceHeight) { return E_NOTIMPL; } - STDMETHODIMP put_DestinationLeft(long DestinationLeft) { return E_NOTIMPL; } - STDMETHODIMP get_DestinationLeft(long* pDestinationLeft) { return E_NOTIMPL; } - STDMETHODIMP put_DestinationWidth(long DestinationWidth) { return E_NOTIMPL; } - STDMETHODIMP get_DestinationWidth(long* pDestinationWidth) { return E_NOTIMPL; } - STDMETHODIMP put_DestinationTop(long DestinationTop) { return E_NOTIMPL; } - STDMETHODIMP get_DestinationTop(long* pDestinationTop) { return E_NOTIMPL; } - STDMETHODIMP put_DestinationHeight(long DestinationHeight) { return E_NOTIMPL; } - STDMETHODIMP get_DestinationHeight(long* pDestinationHeight) { return E_NOTIMPL; } - STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } - STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - - STDMETHODIMP SetDefaultSourcePosition() { return E_NOTIMPL; } - STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } - STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - - STDMETHODIMP SetDefaultDestinationPosition() { return E_NOTIMPL; } - STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight); - - STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) { - return E_NOTIMPL; - } - STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage) { return E_NOTIMPL; } - STDMETHODIMP IsUsingDefaultSource() { return E_NOTIMPL; } - STDMETHODIMP IsUsingDefaultDestination() { return E_NOTIMPL; } - - STDMETHODIMP GetPreferredAspectRatio(long* plAspectX, long* plAspectY); - - // IVMRMixerBitmap9 - STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); - }; -} +/* + * (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 . + * + */ + +#pragma once + +namespace DSObjects +{ + class COuterVMR9 + : public CUnknown + , public IVideoWindow + , public IBasicVideo2 + , public IVMRWindowlessControl + , public IVMRMixerBitmap9 + { + CComPtr m_pVMR; + VMR9AlphaBitmap* m_pVMR9AlphaBitmap; + CVMR9AllocatorPresenter* m_pAllocatorPresenter; + + public: + + COuterVMR9(const TCHAR* pName, LPUNKNOWN pUnk, VMR9AlphaBitmap* pVMR9AlphaBitmap, CVMR9AllocatorPresenter* pAllocatorPresenter) : CUnknown(pName, pUnk) { + m_pVMR.CoCreateInstance(CLSID_VideoMixingRenderer9, GetOwner()); + m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; + m_pAllocatorPresenter = pAllocatorPresenter; + } + + ~COuterVMR9() { + m_pVMR = nullptr; + } + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + HRESULT hr; + + // Casimir666 : in renderless mode, do the inlaying in place of VMR + if (riid == __uuidof(IVMRMixerBitmap9)) { + return GetInterface((IVMRMixerBitmap9*)this, ppv); + } + + hr = m_pVMR ? m_pVMR->QueryInterface(riid, ppv) : E_NOINTERFACE; + if (m_pVMR && FAILED(hr)) { + hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; + if (FAILED(hr)) { + if (riid == __uuidof(IVideoWindow)) { + return GetInterface((IVideoWindow*)this, ppv); + } + if (riid == __uuidof(IBasicVideo)) { + return GetInterface((IBasicVideo*)this, ppv); + } + if (riid == __uuidof(IBasicVideo2)) { + return GetInterface((IBasicVideo2*)this, ppv); + } + /*if (riid == __uuidof(IVMRWindowlessControl)) + return GetInterface((IVMRWindowlessControl*)this, ppv); + */ + } + } + + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IVMRWindowlessControl + + STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); + + STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) { return E_NOTIMPL; } + STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) { return E_NOTIMPL; } + STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) { return E_NOTIMPL; } + STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect); + + STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode); + STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode) { return E_NOTIMPL; } + STDMETHODIMP SetVideoClippingWindow(HWND hwnd) { return E_NOTIMPL; } + STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc) { return E_NOTIMPL; } + STDMETHODIMP DisplayModeChanged() { return E_NOTIMPL; } + STDMETHODIMP GetCurrentImage(BYTE** lpDib) { return E_NOTIMPL; } + STDMETHODIMP SetBorderColor(COLORREF Clr) { return E_NOTIMPL; } + STDMETHODIMP GetBorderColor(COLORREF* lpClr) { return E_NOTIMPL; } + STDMETHODIMP SetColorKey(COLORREF Clr) { return E_NOTIMPL; } + STDMETHODIMP GetColorKey(COLORREF* lpClr) { return E_NOTIMPL; } + + // IVideoWindow + STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; } + STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; } + STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { + return E_NOTIMPL; + } + STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) { + return E_NOTIMPL; + } + STDMETHODIMP put_Caption(BSTR strCaption) { return E_NOTIMPL; } + STDMETHODIMP get_Caption(BSTR* strCaption) { return E_NOTIMPL; } + STDMETHODIMP put_WindowStyle(long WindowStyle) { return E_NOTIMPL; } + STDMETHODIMP get_WindowStyle(long* WindowStyle) { return E_NOTIMPL; } + STDMETHODIMP put_WindowStyleEx(long WindowStyleEx) { return E_NOTIMPL; } + STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx) { return E_NOTIMPL; } + STDMETHODIMP put_AutoShow(long AutoShow) { return E_NOTIMPL; } + STDMETHODIMP get_AutoShow(long* AutoShow) { return E_NOTIMPL; } + STDMETHODIMP put_WindowState(long WindowState) { return E_NOTIMPL; } + STDMETHODIMP get_WindowState(long* WindowState) { return E_NOTIMPL; } + STDMETHODIMP put_BackgroundPalette(long BackgroundPalette) { return E_NOTIMPL; } + STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette) { return E_NOTIMPL; } + STDMETHODIMP put_Visible(long Visible) { return E_NOTIMPL; } + STDMETHODIMP get_Visible(long* pVisible) { return E_NOTIMPL; } + STDMETHODIMP put_Left(long Left) { return E_NOTIMPL; } + STDMETHODIMP get_Left(long* pLeft) { return E_NOTIMPL; } + STDMETHODIMP put_Width(long Width) { return E_NOTIMPL; } + STDMETHODIMP get_Width(long* pWidth); + + STDMETHODIMP put_Top(long Top) { return E_NOTIMPL; } + STDMETHODIMP get_Top(long* pTop) { return E_NOTIMPL; } + STDMETHODIMP put_Height(long Height) { return E_NOTIMPL; } + STDMETHODIMP get_Height(long* pHeight); + + STDMETHODIMP put_Owner(OAHWND Owner) { return E_NOTIMPL; } + STDMETHODIMP get_Owner(OAHWND* Owner) { return E_NOTIMPL; } + STDMETHODIMP put_MessageDrain(OAHWND Drain) { return E_NOTIMPL; } + STDMETHODIMP get_MessageDrain(OAHWND* Drain) { return E_NOTIMPL; } + STDMETHODIMP get_BorderColor(long* Color) { return E_NOTIMPL; } + STDMETHODIMP put_BorderColor(long Color) { return E_NOTIMPL; } + STDMETHODIMP get_FullScreenMode(long* FullScreenMode) { return E_NOTIMPL; } + STDMETHODIMP put_FullScreenMode(long FullScreenMode) { return E_NOTIMPL; } + STDMETHODIMP SetWindowForeground(long Focus) { return E_NOTIMPL; } + STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) { + return E_NOTIMPL; + } + STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } + STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) { + return E_NOTIMPL; + } + STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight) { return E_NOTIMPL; } + STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight) { return E_NOTIMPL; } + STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) { return E_NOTIMPL; } + STDMETHODIMP HideCursor(long HideCursor) { return E_NOTIMPL; } + STDMETHODIMP IsCursorHidden(long* CursorHidden) { return E_NOTIMPL; } + + // IBasicVideo2 + STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) { return E_NOTIMPL; } + STDMETHODIMP get_BitRate(long* pBitRate) { return E_NOTIMPL; } + STDMETHODIMP get_BitErrorRate(long* pBitErrorRate) { return E_NOTIMPL; } + STDMETHODIMP get_VideoWidth(long* pVideoWidth) { return E_NOTIMPL; } + STDMETHODIMP get_VideoHeight(long* pVideoHeight) { return E_NOTIMPL; } + STDMETHODIMP put_SourceLeft(long SourceLeft) { return E_NOTIMPL; } + STDMETHODIMP get_SourceLeft(long* pSourceLeft) { return E_NOTIMPL; } + STDMETHODIMP put_SourceWidth(long SourceWidth) { return E_NOTIMPL; } + STDMETHODIMP get_SourceWidth(long* pSourceWidth) { return E_NOTIMPL; } + STDMETHODIMP put_SourceTop(long SourceTop) { return E_NOTIMPL; } + STDMETHODIMP get_SourceTop(long* pSourceTop) { return E_NOTIMPL; } + STDMETHODIMP put_SourceHeight(long SourceHeight) { return E_NOTIMPL; } + STDMETHODIMP get_SourceHeight(long* pSourceHeight) { return E_NOTIMPL; } + STDMETHODIMP put_DestinationLeft(long DestinationLeft) { return E_NOTIMPL; } + STDMETHODIMP get_DestinationLeft(long* pDestinationLeft) { return E_NOTIMPL; } + STDMETHODIMP put_DestinationWidth(long DestinationWidth) { return E_NOTIMPL; } + STDMETHODIMP get_DestinationWidth(long* pDestinationWidth) { return E_NOTIMPL; } + STDMETHODIMP put_DestinationTop(long DestinationTop) { return E_NOTIMPL; } + STDMETHODIMP get_DestinationTop(long* pDestinationTop) { return E_NOTIMPL; } + STDMETHODIMP put_DestinationHeight(long DestinationHeight) { return E_NOTIMPL; } + STDMETHODIMP get_DestinationHeight(long* pDestinationHeight) { return E_NOTIMPL; } + STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } + STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + + STDMETHODIMP SetDefaultSourcePosition() { return E_NOTIMPL; } + STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height) { return E_NOTIMPL; } + STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + + STDMETHODIMP SetDefaultDestinationPosition() { return E_NOTIMPL; } + STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight); + + STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) { + return E_NOTIMPL; + } + STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage) { return E_NOTIMPL; } + STDMETHODIMP IsUsingDefaultSource() { return E_NOTIMPL; } + STDMETHODIMP IsUsingDefaultDestination() { return E_NOTIMPL; } + + STDMETHODIMP GetPreferredAspectRatio(long* plAspectX, long* plAspectY); + + // IVMRMixerBitmap9 + STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); + }; +} diff --git a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp index ab1d69817a9..f117331d086 100644 --- a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp +++ b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp @@ -1,230 +1,230 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "PixelShaderCompiler.h" -#include "../../../mpc-hc/resource.h" -#include -#include - -CPixelShaderCompiler::CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent) - : m_hDll(nullptr) - , m_pD3DCompile(nullptr) - , m_pD3DDisassemble(nullptr) - , m_pD3DDev(pD3DDev) - , m_Cache(pD3DDev) -{ - static_assert(D3D_COMPILER_VERSION == MPC_D3D_COMPILER_VERSION, - "MPC_D3D_COMPILER_VERSION define used in the installer needs to be updated."); - m_hDll = LoadLibrary(D3DCOMPILER_DLL); - - if (m_hDll) { - m_pD3DCompile = (pD3DCompile)GetProcAddress(m_hDll, "D3DCompile"); - m_pD3DDisassemble = (pD3DDisassemble)GetProcAddress(m_hDll, "D3DDisassemble"); - } - - if (!fStaySilent) { - if (!m_hDll) { - CString msg; - msg.Format(IDS_SHADER_DLL_ERR_0, D3DCOMPILER_DLL); - AfxMessageBox(msg, MB_ICONWARNING | MB_OK); - } else if (!m_pD3DCompile || !m_pD3DDisassemble) { - CString msg; - msg.Format(IDS_SHADER_DLL_ERR_1, D3DCOMPILER_DLL); - AfxMessageBox(msg, MB_ICONWARNING | MB_OK); - } - } -} - -CPixelShaderCompiler::~CPixelShaderCompiler() -{ - if (m_hDll) { - VERIFY(FreeLibrary(m_hDll)); - } -} - -HRESULT CPixelShaderCompiler::InternalCompile( - LPCSTR pSrcData, - SIZE_T SrcDataSize, - LPCSTR pSourceName, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg) -{ - if (!m_pD3DCompile) { - return E_FAIL; - } - - if (pDisasm && !m_pD3DDisassemble) { - return E_FAIL; - } - - if (ppPixelShader && !m_pD3DDev) { - return E_FAIL; - } - - LPCSTR pSelProfile = pProfile; - if (!pSelProfile || *pSelProfile == '\0') { - D3DCAPS9 caps; - if (m_pD3DDev && m_pD3DDev->GetDeviceCaps(&caps) == D3D_OK) { - switch (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion)) { - case 2: - if (caps.PS20Caps.NumInstructionSlots < 512) { - pSelProfile = "ps_2_0"; - } else if (caps.PS20Caps.Caps > 0) { - pSelProfile = "ps_2_a"; - } else { - pSelProfile = "ps_2_b"; - } - break; - case 3: - pSelProfile = "ps_3_0"; - break; - } - } else { - ASSERT(FALSE); - } - } - - if (!pSelProfile || *pSelProfile == '\0') { - return E_FAIL; - } - - LPCSTR defProfile = "MPC_HC_SHADER_PROFILE"; - LPCSTR defProfileVal; - if (!strcmp(pSelProfile, "ps_2_0")) { - defProfileVal = "0"; - } else if (!strcmp(pSelProfile, "ps_2_b")) { - defProfileVal = "1"; - } else if (!strcmp(pSelProfile, "ps_2_a") || !strcmp(pSelProfile, "ps_2_sw")) { - defProfileVal = "2"; - } else if (!strcmp(pSelProfile, "ps_3_0") || !strcmp(pSelProfile, "ps_3_sw")) { - defProfileVal = "3"; - } else { - defProfileVal = "-1"; - } - - if (ppPixelShader && SUCCEEDED(m_Cache.CreatePixelShader(defProfileVal, pSrcData, SrcDataSize, ppPixelShader))) { - return S_OK; - } - - D3D_SHADER_MACRO macros[] = { { defProfile, defProfileVal }, { 0 } }; - - CComPtr pShaderBlob, pErrorBlob; - HRESULT hr = m_pD3DCompile(pSrcData, SrcDataSize, pSourceName, macros, nullptr, pEntrypoint, - pSelProfile, Flags, 0, &pShaderBlob, &pErrorBlob); - - if (pErrMsg) { - CStringA msg; - if (pErrorBlob) { - auto len = pErrorBlob->GetBufferSize(); - VERIFY(memcpy_s(msg.GetBufferSetLength((int)len), len, pErrorBlob->GetBufferPointer(), len) == 0); - msg.ReleaseBuffer((int)len); - } - *pErrMsg = msg; - } - - if (FAILED(hr)) { - return hr; - } - - if (ppPixelShader) { - hr = m_pD3DDev->CreatePixelShader((DWORD*)pShaderBlob->GetBufferPointer(), ppPixelShader); - if (FAILED(hr)) { - return hr; - } - - m_Cache.SavePixelShader(defProfileVal, pSrcData, SrcDataSize, - (void*)pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize()); - } - - if (pDisasm) { - CComPtr pDisasmBlob; - CStringA defs; - for (auto pMacro = macros; pMacro && pMacro->Name && pMacro->Definition; pMacro++) { - defs.Append("// #define "); - defs.Append(pMacro->Name); - defs.Append(" "); - defs.Append(pMacro->Definition); - defs.Append("\n"); - } - hr = m_pD3DDisassemble(pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), - 0, defs, &pDisasmBlob); - if (SUCCEEDED(hr)) { - CStringA disasm; - auto len = pDisasmBlob->GetBufferSize(); - VERIFY(memcpy_s(disasm.GetBufferSetLength((int)len), len, pDisasmBlob->GetBufferPointer(), len) == 0); - disasm.ReleaseBuffer((int)len); - *pDisasm = disasm; - } - } - - return S_OK; -} - -HRESULT CPixelShaderCompiler::CompileShader( - LPCSTR pSrcData, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg) -{ - return InternalCompile(pSrcData, strlen(pSrcData), nullptr, pEntrypoint, - pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); -} - -HRESULT CPixelShaderCompiler::CompileShaderFromFile( - LPCTSTR pSrcFile, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg) -{ - HRESULT ret = E_FAIL; - if (FILE* fp = _tfsopen(pSrcFile, _T("rb"), _SH_SECURE)) { - VERIFY(fseek(fp, 0, SEEK_END) == 0); - long size = ftell(fp); - rewind(fp); - if (size > 0) { - auto data = new (std::nothrow) char[(size_t)size]; - if (data) { - if (fread(data, size, 1, fp) == 1) { - ret = InternalCompile(data, (size_t)size, CT2A(pSrcFile), pEntrypoint, - pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); - } else { - ASSERT(FALSE); - } - delete[] data; - } else { - ASSERT(FALSE); - } - } - VERIFY(fclose(fp) == 0); - } - return ret; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "PixelShaderCompiler.h" +#include "../../../mpc-hc/resource.h" +#include +#include + +CPixelShaderCompiler::CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent) + : m_hDll(nullptr) + , m_pD3DCompile(nullptr) + , m_pD3DDisassemble(nullptr) + , m_pD3DDev(pD3DDev) + , m_Cache(pD3DDev) +{ + static_assert(D3D_COMPILER_VERSION == MPC_D3D_COMPILER_VERSION, + "MPC_D3D_COMPILER_VERSION define used in the installer needs to be updated."); + m_hDll = LoadLibrary(D3DCOMPILER_DLL); + + if (m_hDll) { + m_pD3DCompile = (pD3DCompile)GetProcAddress(m_hDll, "D3DCompile"); + m_pD3DDisassemble = (pD3DDisassemble)GetProcAddress(m_hDll, "D3DDisassemble"); + } + + if (!fStaySilent) { + if (!m_hDll) { + CString msg; + msg.Format(IDS_SHADER_DLL_ERR_0, D3DCOMPILER_DLL); + AfxMessageBox(msg, MB_ICONWARNING | MB_OK); + } else if (!m_pD3DCompile || !m_pD3DDisassemble) { + CString msg; + msg.Format(IDS_SHADER_DLL_ERR_1, D3DCOMPILER_DLL); + AfxMessageBox(msg, MB_ICONWARNING | MB_OK); + } + } +} + +CPixelShaderCompiler::~CPixelShaderCompiler() +{ + if (m_hDll) { + VERIFY(FreeLibrary(m_hDll)); + } +} + +HRESULT CPixelShaderCompiler::InternalCompile( + LPCSTR pSrcData, + SIZE_T SrcDataSize, + LPCSTR pSourceName, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm, + CString* pErrMsg) +{ + if (!m_pD3DCompile) { + return E_FAIL; + } + + if (pDisasm && !m_pD3DDisassemble) { + return E_FAIL; + } + + if (ppPixelShader && !m_pD3DDev) { + return E_FAIL; + } + + LPCSTR pSelProfile = pProfile; + if (!pSelProfile || *pSelProfile == '\0') { + D3DCAPS9 caps; + if (m_pD3DDev && m_pD3DDev->GetDeviceCaps(&caps) == D3D_OK) { + switch (D3DSHADER_VERSION_MAJOR(caps.PixelShaderVersion)) { + case 2: + if (caps.PS20Caps.NumInstructionSlots < 512) { + pSelProfile = "ps_2_0"; + } else if (caps.PS20Caps.Caps > 0) { + pSelProfile = "ps_2_a"; + } else { + pSelProfile = "ps_2_b"; + } + break; + case 3: + pSelProfile = "ps_3_0"; + break; + } + } else { + ASSERT(FALSE); + } + } + + if (!pSelProfile || *pSelProfile == '\0') { + return E_FAIL; + } + + LPCSTR defProfile = "MPC_HC_SHADER_PROFILE"; + LPCSTR defProfileVal; + if (!strcmp(pSelProfile, "ps_2_0")) { + defProfileVal = "0"; + } else if (!strcmp(pSelProfile, "ps_2_b")) { + defProfileVal = "1"; + } else if (!strcmp(pSelProfile, "ps_2_a") || !strcmp(pSelProfile, "ps_2_sw")) { + defProfileVal = "2"; + } else if (!strcmp(pSelProfile, "ps_3_0") || !strcmp(pSelProfile, "ps_3_sw")) { + defProfileVal = "3"; + } else { + defProfileVal = "-1"; + } + + if (ppPixelShader && SUCCEEDED(m_Cache.CreatePixelShader(defProfileVal, pSrcData, SrcDataSize, ppPixelShader))) { + return S_OK; + } + + D3D_SHADER_MACRO macros[] = { { defProfile, defProfileVal }, { 0 } }; + + CComPtr pShaderBlob, pErrorBlob; + HRESULT hr = m_pD3DCompile(pSrcData, SrcDataSize, pSourceName, macros, nullptr, pEntrypoint, + pSelProfile, Flags, 0, &pShaderBlob, &pErrorBlob); + + if (pErrMsg) { + CStringA msg; + if (pErrorBlob) { + auto len = pErrorBlob->GetBufferSize(); + VERIFY(memcpy_s(msg.GetBufferSetLength((int)len), len, pErrorBlob->GetBufferPointer(), len) == 0); + msg.ReleaseBuffer((int)len); + } + *pErrMsg = msg; + } + + if (FAILED(hr)) { + return hr; + } + + if (ppPixelShader) { + hr = m_pD3DDev->CreatePixelShader((DWORD*)pShaderBlob->GetBufferPointer(), ppPixelShader); + if (FAILED(hr)) { + return hr; + } + + m_Cache.SavePixelShader(defProfileVal, pSrcData, SrcDataSize, + (void*)pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize()); + } + + if (pDisasm) { + CComPtr pDisasmBlob; + CStringA defs; + for (auto pMacro = macros; pMacro && pMacro->Name && pMacro->Definition; pMacro++) { + defs.Append("// #define "); + defs.Append(pMacro->Name); + defs.Append(" "); + defs.Append(pMacro->Definition); + defs.Append("\n"); + } + hr = m_pD3DDisassemble(pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), + 0, defs, &pDisasmBlob); + if (SUCCEEDED(hr)) { + CStringA disasm; + auto len = pDisasmBlob->GetBufferSize(); + VERIFY(memcpy_s(disasm.GetBufferSetLength((int)len), len, pDisasmBlob->GetBufferPointer(), len) == 0); + disasm.ReleaseBuffer((int)len); + *pDisasm = disasm; + } + } + + return S_OK; +} + +HRESULT CPixelShaderCompiler::CompileShader( + LPCSTR pSrcData, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm, + CString* pErrMsg) +{ + return InternalCompile(pSrcData, strlen(pSrcData), nullptr, pEntrypoint, + pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); +} + +HRESULT CPixelShaderCompiler::CompileShaderFromFile( + LPCTSTR pSrcFile, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm, + CString* pErrMsg) +{ + HRESULT ret = E_FAIL; + if (FILE* fp = _tfsopen(pSrcFile, _T("rb"), _SH_SECURE)) { + VERIFY(fseek(fp, 0, SEEK_END) == 0); + long size = ftell(fp); + rewind(fp); + if (size > 0) { + auto data = new (std::nothrow) char[(size_t)size]; + if (data) { + if (fread(data, size, 1, fp) == 1) { + ret = InternalCompile(data, (size_t)size, CT2A(pSrcFile), pEntrypoint, + pProfile, Flags, ppPixelShader, pDisasm, pErrMsg); + } else { + ASSERT(FALSE); + } + delete[] data; + } else { + ASSERT(FALSE); + } + } + VERIFY(fclose(fp) == 0); + } + return ret; +} diff --git a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h index c5166205efd..5aab64950ec 100644 --- a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h +++ b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h @@ -1,70 +1,70 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#pragma once - -#include "PixelShaderCache.h" -#include - -class CPixelShaderCompiler -{ - HINSTANCE m_hDll; - - pD3DCompile m_pD3DCompile; - pD3DDisassemble m_pD3DDisassemble; - - CComPtr m_pD3DDev; - - CPixelShaderCache m_Cache; - - HRESULT InternalCompile( - LPCSTR pSrcData, - SIZE_T SrcDataSize, - LPCSTR pSourceName, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm, - CString* pErrMsg); - -public: - CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent = false); - ~CPixelShaderCompiler(); - - HRESULT CompileShader( - LPCSTR pSrcData, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm = nullptr, - CString* pErrMsg = nullptr); - - HRESULT CompileShaderFromFile( - LPCTSTR pSrcFile, - LPCSTR pEntrypoint, - LPCSTR pProfile, - DWORD Flags, - IDirect3DPixelShader9** ppPixelShader, - CString* pDisasm = nullptr, - CString* pErrMsg = nullptr); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#pragma once + +#include "PixelShaderCache.h" +#include + +class CPixelShaderCompiler +{ + HINSTANCE m_hDll; + + pD3DCompile m_pD3DCompile; + pD3DDisassemble m_pD3DDisassemble; + + CComPtr m_pD3DDev; + + CPixelShaderCache m_Cache; + + HRESULT InternalCompile( + LPCSTR pSrcData, + SIZE_T SrcDataSize, + LPCSTR pSourceName, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm, + CString* pErrMsg); + +public: + CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent = false); + ~CPixelShaderCompiler(); + + HRESULT CompileShader( + LPCSTR pSrcData, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm = nullptr, + CString* pErrMsg = nullptr); + + HRESULT CompileShaderFromFile( + LPCTSTR pSrcFile, + LPCSTR pEntrypoint, + LPCSTR pProfile, + DWORD Flags, + IDirect3DPixelShader9** ppPixelShader, + CString* pDisasm = nullptr, + CString* pErrMsg = nullptr); +}; diff --git a/src/filters/renderer/VideoRenderers/RenderersSettings.cpp b/src/filters/renderer/VideoRenderers/RenderersSettings.cpp index b07b4442c78..4002ba5e872 100644 --- a/src/filters/renderer/VideoRenderers/RenderersSettings.cpp +++ b/src/filters/renderer/VideoRenderers/RenderersSettings.cpp @@ -1,129 +1,129 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "RenderersSettings.h" -#include -#include -#include -#include "d3dx9/d3dx9.h" - -void CRenderersSettings::CAdvRendererSettings::SetDefault() -{ - bVMR9AlterativeVSync = false; - iVMR9VSyncOffset = 0; - bVMR9VSyncAccurate = false; - bVMR9FullscreenGUISupport = false; - bVMR9VSync = false; - bVMR9FullFloatingPointProcessing = false; - bVMR9HalfFloatingPointProcessing = false; - bVMR9ColorManagementEnable = false; - iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; - iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; - iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; - bVMRDisableDesktopComposition = false; - bVMRFlushGPUBeforeVSync = true; - bVMRFlushGPUAfterPresent = true; - bVMRFlushGPUWait = false; - bEVRHighColorResolution = false; - bEVRForceInputHighColorResolution = false; - bEVREnableFrameTimeCorrection = false; - iEVROutputRange = 0; - bSynchronizeVideo = false; - bSynchronizeDisplay = false; - bSynchronizeNearest = true; - iLineDelta = 0; - iColumnDelta = 0; - fCycleDelta = 0.0012; - fTargetSyncOffset = 12.0; - fControlLimit = 2.0; - bCacheShaders = false; - bDesktopSizeBackBuffer = false; -} - -void CRenderersSettings::CAdvRendererSettings::SetOptimal() -{ - bVMR9AlterativeVSync = true; - iVMR9VSyncOffset = 0; - bVMR9VSyncAccurate = true; - bVMR9FullscreenGUISupport = false; - bVMR9VSync = false; - bVMR9FullFloatingPointProcessing = false; - bVMR9HalfFloatingPointProcessing = false; - bVMR9ColorManagementEnable = false; - iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; - iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; - iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; - bVMRDisableDesktopComposition = false; - bVMRFlushGPUBeforeVSync = true; - bVMRFlushGPUAfterPresent = true; - bVMRFlushGPUWait = false; - bEVRHighColorResolution = false; - bEVRForceInputHighColorResolution = false; - bEVREnableFrameTimeCorrection = false; - iEVROutputRange = 0; - bSynchronizeVideo = false; - bSynchronizeDisplay = false; - bSynchronizeNearest = true; - iLineDelta = 0; - iColumnDelta = 0; - fCycleDelta = 0.0012; - fTargetSyncOffset = 12.0; - fControlLimit = 2.0; - bCacheShaders = false; -} - -///////////////////////////////////////////////////////////////////////////// -// CRenderersData construction - -CRenderersData::CRenderersData() - : m_hD3DX9Dll(nullptr) - , m_nDXSdkRelease(D3DX_SDK_VERSION) - , m_bTearingTest(false) - , m_iDisplayStats(0) - , m_bResetStats(false) - // Don't disable hardware features before initializing a renderer - , m_bFP16Support(true) - , m_bFP32Support(true) - , m_b10bitSupport(true) -{ - QueryPerformanceFrequency(&llPerfFrequency); -} - -LONGLONG CRenderersData::GetPerfCounter() const -{ - LARGE_INTEGER i64Ticks100ns; - - QueryPerformanceCounter(&i64Ticks100ns); - return llMulDiv(i64Ticks100ns.QuadPart, 10000000, llPerfFrequency.QuadPart, 0); -} - -HINSTANCE CRenderersData::GetD3X9Dll() -{ - // D3DX9 v43 is the latest available and will not get any update. We support only this specific version. - static_assert(D3DX_SDK_VERSION == MPC_DX_SDK_NUMBER, "Different D3DX9 version?"); - if (m_hD3DX9Dll == nullptr) { - m_strD3DX9Version.Format(_T("d3dx9_%u.dll"), D3DX_SDK_VERSION); - m_hD3DX9Dll = LoadLibrary(m_strD3DX9Version); - } - - return m_hD3DX9Dll; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "RenderersSettings.h" +#include +#include +#include +#include "d3dx9/d3dx9.h" + +void CRenderersSettings::CAdvRendererSettings::SetDefault() +{ + bVMR9AlterativeVSync = false; + iVMR9VSyncOffset = 0; + bVMR9VSyncAccurate = false; + bVMR9FullscreenGUISupport = false; + bVMR9VSync = false; + bVMR9FullFloatingPointProcessing = false; + bVMR9HalfFloatingPointProcessing = false; + bVMR9ColorManagementEnable = false; + iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; + iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; + iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; + bVMRDisableDesktopComposition = false; + bVMRFlushGPUBeforeVSync = true; + bVMRFlushGPUAfterPresent = true; + bVMRFlushGPUWait = false; + bEVRHighColorResolution = false; + bEVRForceInputHighColorResolution = false; + bEVREnableFrameTimeCorrection = false; + iEVROutputRange = 0; + bSynchronizeVideo = false; + bSynchronizeDisplay = false; + bSynchronizeNearest = true; + iLineDelta = 0; + iColumnDelta = 0; + fCycleDelta = 0.0012; + fTargetSyncOffset = 12.0; + fControlLimit = 2.0; + bCacheShaders = false; + bDesktopSizeBackBuffer = false; +} + +void CRenderersSettings::CAdvRendererSettings::SetOptimal() +{ + bVMR9AlterativeVSync = true; + iVMR9VSyncOffset = 0; + bVMR9VSyncAccurate = true; + bVMR9FullscreenGUISupport = false; + bVMR9VSync = false; + bVMR9FullFloatingPointProcessing = false; + bVMR9HalfFloatingPointProcessing = false; + bVMR9ColorManagementEnable = false; + iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; + iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; + iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; + bVMRDisableDesktopComposition = false; + bVMRFlushGPUBeforeVSync = true; + bVMRFlushGPUAfterPresent = true; + bVMRFlushGPUWait = false; + bEVRHighColorResolution = false; + bEVRForceInputHighColorResolution = false; + bEVREnableFrameTimeCorrection = false; + iEVROutputRange = 0; + bSynchronizeVideo = false; + bSynchronizeDisplay = false; + bSynchronizeNearest = true; + iLineDelta = 0; + iColumnDelta = 0; + fCycleDelta = 0.0012; + fTargetSyncOffset = 12.0; + fControlLimit = 2.0; + bCacheShaders = false; +} + +///////////////////////////////////////////////////////////////////////////// +// CRenderersData construction + +CRenderersData::CRenderersData() + : m_hD3DX9Dll(nullptr) + , m_nDXSdkRelease(D3DX_SDK_VERSION) + , m_bTearingTest(false) + , m_iDisplayStats(0) + , m_bResetStats(false) + // Don't disable hardware features before initializing a renderer + , m_bFP16Support(true) + , m_bFP32Support(true) + , m_b10bitSupport(true) +{ + QueryPerformanceFrequency(&llPerfFrequency); +} + +LONGLONG CRenderersData::GetPerfCounter() const +{ + LARGE_INTEGER i64Ticks100ns; + + QueryPerformanceCounter(&i64Ticks100ns); + return llMulDiv(i64Ticks100ns.QuadPart, 10000000, llPerfFrequency.QuadPart, 0); +} + +HINSTANCE CRenderersData::GetD3X9Dll() +{ + // D3DX9 v43 is the latest available and will not get any update. We support only this specific version. + static_assert(D3DX_SDK_VERSION == MPC_DX_SDK_NUMBER, "Different D3DX9 version?"); + if (m_hD3DX9Dll == nullptr) { + m_strD3DX9Version.Format(_T("d3dx9_%u.dll"), D3DX_SDK_VERSION); + m_hD3DX9Dll = LoadLibrary(m_strD3DX9Version); + } + + return m_hD3DX9Dll; +} diff --git a/src/filters/renderer/VideoRenderers/RenderersSettings.h b/src/filters/renderer/VideoRenderers/RenderersSettings.h index 7723f61c3fd..1ba0dc3457d 100644 --- a/src/filters/renderer/VideoRenderers/RenderersSettings.h +++ b/src/filters/renderer/VideoRenderers/RenderersSettings.h @@ -1,155 +1,155 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "../../../SubPic/SubPicQueueSettings.h" - -enum { - WM_REARRANGERENDERLESS = WM_APP + 1, - WM_RESET_DEVICE -}; - -#define WM_MYMOUSELAST WM_XBUTTONDBLCLK - -enum { - VIDRNDT_AP_SURFACE, - VIDRNDT_AP_TEXTURE2D, - VIDRNDT_AP_TEXTURE3D -}; - -enum VideoSystem { - VIDEO_SYSTEM_UNKNOWN, - VIDEO_SYSTEM_HDTV, - VIDEO_SYSTEM_SDTV_NTSC, - VIDEO_SYSTEM_SDTV_PAL -}; - -enum AmbientLight { - AMBIENT_LIGHT_BRIGHT, - AMBIENT_LIGHT_DIM, - AMBIENT_LIGHT_DARK -}; - -enum ColorRenderingIntent { - COLOR_RENDERING_INTENT_PERCEPTUAL, - COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, - COLOR_RENDERING_INTENT_SATURATION, - COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC -}; - -class CRenderersSettings -{ - -public: - bool fResetDevice; - - class CAdvRendererSettings - { - public: - CAdvRendererSettings() { SetDefault(); } - - bool bVMR9AlterativeVSync; - int iVMR9VSyncOffset; - bool bVMR9VSyncAccurate; - bool bVMR9FullscreenGUISupport; - bool bVMR9VSync; - bool bVMR9FullFloatingPointProcessing; - bool bVMR9HalfFloatingPointProcessing; - bool bVMR9ColorManagementEnable; - int iVMR9ColorManagementInput; - int iVMR9ColorManagementAmbientLight; - int iVMR9ColorManagementIntent; - bool bVMRDisableDesktopComposition; - bool bVMRFlushGPUBeforeVSync; - bool bVMRFlushGPUAfterPresent; - bool bVMRFlushGPUWait; - bool bDesktopSizeBackBuffer; - - // EVR - bool bEVRHighColorResolution; - bool bEVRForceInputHighColorResolution; - bool bEVREnableFrameTimeCorrection; - int iEVROutputRange; - - // SyncRenderer settings - bool bSynchronizeVideo; - bool bSynchronizeDisplay; - bool bSynchronizeNearest; - int iLineDelta; - int iColumnDelta; - double fCycleDelta; - double fTargetSyncOffset; - double fControlLimit; - - // Other settings - bool bCacheShaders; - CString sShaderCachePath; - - void SetDefault(); - void SetOptimal(); - }; - - CAdvRendererSettings m_AdvRendSets; - - int iAPSurfaceUsage; - int iDX9Resizer; - bool fVMR9MixerMode; - int iEvrBuffers; - - SubPicQueueSettings subPicQueueSettings; - - int subPicVerticalShift; - double fontScaleOverride; - - CString D3D9RenderDevice; - void UpdateData(bool fSave); -}; - -class CRenderersData -{ - HINSTANCE m_hD3DX9Dll; - const UINT m_nDXSdkRelease; - LARGE_INTEGER llPerfFrequency; - -public: - CRenderersData(); - - bool m_bTearingTest; - int m_iDisplayStats; - bool m_bResetStats; // Set to reset the presentation statistics - CString m_strD3DX9Version; - - // Hardware feature support - bool m_bFP16Support; - bool m_bFP32Support; - bool m_b10bitSupport; - CString m_strDXVAInfo; - - LONGLONG GetPerfCounter() const; - HINSTANCE GetD3X9Dll(); - UINT GetDXSdkRelease() const { return m_nDXSdkRelease; }; -}; - -extern CRenderersData* GetRenderersData(); -extern CRenderersSettings& GetRenderersSettings(); - -extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "../../../SubPic/SubPicQueueSettings.h" + +enum { + WM_REARRANGERENDERLESS = WM_APP + 1, + WM_RESET_DEVICE +}; + +#define WM_MYMOUSELAST WM_XBUTTONDBLCLK + +enum { + VIDRNDT_AP_SURFACE, + VIDRNDT_AP_TEXTURE2D, + VIDRNDT_AP_TEXTURE3D +}; + +enum VideoSystem { + VIDEO_SYSTEM_UNKNOWN, + VIDEO_SYSTEM_HDTV, + VIDEO_SYSTEM_SDTV_NTSC, + VIDEO_SYSTEM_SDTV_PAL +}; + +enum AmbientLight { + AMBIENT_LIGHT_BRIGHT, + AMBIENT_LIGHT_DIM, + AMBIENT_LIGHT_DARK +}; + +enum ColorRenderingIntent { + COLOR_RENDERING_INTENT_PERCEPTUAL, + COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, + COLOR_RENDERING_INTENT_SATURATION, + COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC +}; + +class CRenderersSettings +{ + +public: + bool fResetDevice; + + class CAdvRendererSettings + { + public: + CAdvRendererSettings() { SetDefault(); } + + bool bVMR9AlterativeVSync; + int iVMR9VSyncOffset; + bool bVMR9VSyncAccurate; + bool bVMR9FullscreenGUISupport; + bool bVMR9VSync; + bool bVMR9FullFloatingPointProcessing; + bool bVMR9HalfFloatingPointProcessing; + bool bVMR9ColorManagementEnable; + int iVMR9ColorManagementInput; + int iVMR9ColorManagementAmbientLight; + int iVMR9ColorManagementIntent; + bool bVMRDisableDesktopComposition; + bool bVMRFlushGPUBeforeVSync; + bool bVMRFlushGPUAfterPresent; + bool bVMRFlushGPUWait; + bool bDesktopSizeBackBuffer; + + // EVR + bool bEVRHighColorResolution; + bool bEVRForceInputHighColorResolution; + bool bEVREnableFrameTimeCorrection; + int iEVROutputRange; + + // SyncRenderer settings + bool bSynchronizeVideo; + bool bSynchronizeDisplay; + bool bSynchronizeNearest; + int iLineDelta; + int iColumnDelta; + double fCycleDelta; + double fTargetSyncOffset; + double fControlLimit; + + // Other settings + bool bCacheShaders; + CString sShaderCachePath; + + void SetDefault(); + void SetOptimal(); + }; + + CAdvRendererSettings m_AdvRendSets; + + int iAPSurfaceUsage; + int iDX9Resizer; + bool fVMR9MixerMode; + int iEvrBuffers; + + SubPicQueueSettings subPicQueueSettings; + + int subPicVerticalShift; + double fontScaleOverride; + + CString D3D9RenderDevice; + void UpdateData(bool fSave); +}; + +class CRenderersData +{ + HINSTANCE m_hD3DX9Dll; + const UINT m_nDXSdkRelease; + LARGE_INTEGER llPerfFrequency; + +public: + CRenderersData(); + + bool m_bTearingTest; + int m_iDisplayStats; + bool m_bResetStats; // Set to reset the presentation statistics + CString m_strD3DX9Version; + + // Hardware feature support + bool m_bFP16Support; + bool m_bFP32Support; + bool m_b10bitSupport; + CString m_strDXVAInfo; + + LONGLONG GetPerfCounter() const; + HINSTANCE GetD3X9Dll(); + UINT GetDXSdkRelease() const { return m_nDXSdkRelease; }; +}; + +extern CRenderersData* GetRenderersData(); +extern CRenderersSettings& GetRenderersSettings(); + +extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); diff --git a/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h index 0a6aa2c072d..b07d5d098b8 100644 --- a/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h @@ -1,33 +1,33 @@ -/* - * (C) 2010-2012, 2017 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 . - * - */ - -#pragma once - -// {F9F62627-E3EF-4a2e-B6C9-5D4C0DC3326B} -DEFINE_GUID(CLSID_SyncAllocatorPresenter, 0xf9f62627, 0xe3ef, 0x4a2e, 0xb6, 0xc9, 0x5d, 0x4c, 0xd, 0xc3, 0x32, 0x6b); - -interface __declspec(uuid("F891C2A9-1DFF-45e0-9129-30C0990C5A9F")) - ISyncClockAdviser : - public IUnknown -{ - STDMETHOD(AdviseSyncClock)(ISyncClock* sC) PURE; -}; - -HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP); +/* + * (C) 2010-2012, 2017 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 . + * + */ + +#pragma once + +// {F9F62627-E3EF-4a2e-B6C9-5D4C0DC3326B} +DEFINE_GUID(CLSID_SyncAllocatorPresenter, 0xf9f62627, 0xe3ef, 0x4a2e, 0xb6, 0xc9, 0x5d, 0x4c, 0xd, 0xc3, 0x32, 0x6b); + +interface __declspec(uuid("F891C2A9-1DFF-45e0-9129-30C0990C5A9F")) + ISyncClockAdviser : + public IUnknown +{ + STDMETHOD(AdviseSyncClock)(ISyncClock* sC) PURE; +}; + +HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP); diff --git a/src/filters/renderer/VideoRenderers/SyncRenderer.cpp b/src/filters/renderer/VideoRenderers/SyncRenderer.cpp index abc017d3a69..cd152a56d7f 100644 --- a/src/filters/renderer/VideoRenderers/SyncRenderer.cpp +++ b/src/filters/renderer/VideoRenderers/SyncRenderer.cpp @@ -1,4720 +1,4720 @@ -/* - * (C) 2010-2017 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 . - * - */ - -#include "stdafx.h" -#include "../SyncClock/Interfaces.h" -#include -#include -#include -#include "../../../mpc-hc/resource.h" -#include "../../../DSUtil/DSUtil.h" -#include "../../../DSUtil/WinAPIUtils.h" -#include // Required in CGenlock -#include -#include -#include "d3dx9/d3dx9.h" -#include -#include -#include -#include -#include "../../../SubPic/DX9SubPic.h" -#include "../../../SubPic/SubPicQueueImpl.h" -#include "moreuuids.h" -#include "MacrovisionKicker.h" -#include "IPinHook.h" -#include "PixelShaderCompiler.h" -#include "FocusThread.h" -#include "../../../DSUtil/vd.h" -#include - -#include -#include -#include "SyncRenderer.h" -#include "Utils.h" -#include "Variables.h" - -#if (0) // Set to 1 to activate SyncRenderer traces -#define TRACE_SR TRACE -#else -#define TRACE_SR __noop -#endif - - -#define REFERENCE_WIDTH 1920 -#define FONT_HEIGHT 21 -#define BOLD_THRESHOLD 11 -#define TEXT_PADDING 2 -#define GRAPH_HEIGHT 360 -#define GRAPH_WIDTH 1000 - -using namespace GothSync; - -extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); - -CBaseAP::CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) - : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) - , m_hDWMAPI(nullptr) - , m_pDwmIsCompositionEnabled(nullptr) - , m_pDwmEnableComposition(nullptr) - , m_pOuterEVR(nullptr) - , m_SurfaceType(D3DFMT_UNKNOWN) - , m_BackbufferType(D3DFMT_UNKNOWN) - , m_DisplayType(D3DFMT_UNKNOWN) - , m_filter(D3DTEXF_NONE) - , m_LastAdapterCheck(0) - , m_CurrentAdapter(UINT_ERROR) - , m_bicubicA(0) - , m_nTearingPos(0) - , m_VMR9AlphaBitmapWidthBytes() - , m_pD3DXLoadSurfaceFromMemory(nullptr) - , m_pD3DXLoadSurfaceFromSurface(nullptr) - , m_pD3DXCreateLine(nullptr) - , m_pD3DXCreateFont(nullptr) - , m_pD3DXCreateSprite(nullptr) - , m_nDXSurface(1) - , m_nVMR9Surfaces(0) - , m_iVMR9Surface(0) - , m_nCurSurface(0) - , m_nUsedBuffer(0) - , m_lNextSampleWait(1) - , m_bSnapToVSync(false) - , m_uScanLineEnteringPaint(0) - , m_llEstVBlankTime(0) - , m_fAvrFps(0.0) - , m_fJitterStdDev(0.0) - , m_fJitterMean(0) - , m_fSyncOffsetAvr(0.0) - , m_fSyncOffsetStdDev(0.0) - , m_bHighColorResolution(false) - , m_bCompositionEnabled(false) - , m_bDesktopCompositionDisabled(false) - , m_bIsFullscreen(bFullscreen) - , fullScreenChanged(false) - , m_bNeedCheckSample(true) - , m_dMainThreadId(0) - , m_ScreenSize(0, 0) - , m_dDetectedScanlineTime(0.0) - , m_dD3DRefreshCycle(0) - , m_dEstRefreshCycle(0.0) - , m_dFrameCycle(0.0) - , m_dOptimumDisplayCycle(0.0) - , m_dCycleDifference(1.0) - , m_pcFramesDropped(0) - , m_pcFramesDuplicated(0) - , m_pcFramesDrawn(0) - , m_nNextJitter(0) - , m_nNextSyncOffset(0) - , m_JitterStdDev(0) - , m_llLastSyncTime(LONGLONG_ERROR) - , m_MaxJitter(MINLONG64) - , m_MinJitter(MAXLONG64) - , m_MaxSyncOffset(MINLONG64) - , m_MinSyncOffset(MAXLONG64) - , m_uSyncGlitches(0) - , m_llSampleTime(0) - , m_llLastSampleTime(0) - , m_llHysteresis(0) - , m_lShiftToNearest(0) - , m_lShiftToNearestPrev(0) - , m_bVideoSlowerThanDisplay(0) - , m_rtTimePerFrame(0) - , m_bInterlaced(false) - , m_TextScale(1.0) - , m_pGenlock(nullptr) - , m_pAudioStats(nullptr) - , m_lAudioLag(0) - , m_lAudioLagMin(10000) - , m_lAudioLagMax(-10000) - , m_lAudioSlaveMode(0) - , m_FocusThread(nullptr) - , m_hFocusWindow(nullptr) -{ - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - ZeroMemory(&m_caps, sizeof(m_caps)); - ZeroMemory(&m_pp, sizeof(m_pp)); - - if (FAILED(hr)) { - _Error += _T("ISubPicAllocatorPresenterImpl failed\n"); - return; - } - - HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); - - if (hDll) { - (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory"); - (FARPROC&)m_pD3DXLoadSurfaceFromSurface = GetProcAddress(hDll, "D3DXLoadSurfaceFromSurface"); - (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine"); - (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW"); - (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite"); - } else { - _Error += _T("The installed DirectX End-User Runtime is outdated. Please download and install the "); - _Error += MPC_DX_SDK_MONTH _T(" ") MAKE_STR(MPC_DX_SDK_YEAR); - _Error += _T(" release or newer in order for MPC-HC to function properly.\n"); - } - - m_hDWMAPI = LoadLibrary(L"dwmapi.dll"); - if (m_hDWMAPI) { - (FARPROC&)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled"); - (FARPROC&)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition"); - } - - Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); - if (m_pD3DEx) { - m_pD3D = m_pD3DEx; - } - - const CRenderersSettings& r = GetRenderersSettings(); - if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { - m_bDesktopCompositionDisabled = true; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(0); - } - } else { - m_bDesktopCompositionDisabled = false; - } - - m_pGenlock = DEBUG_NEW CGenlock(r.m_AdvRendSets.fTargetSyncOffset, r.m_AdvRendSets.fControlLimit, r.m_AdvRendSets.iLineDelta, r.m_AdvRendSets.iColumnDelta, r.m_AdvRendSets.fCycleDelta, 0); // Must be done before CreateDXDevice - hr = CreateDXDevice(_Error); - ZeroMemory(m_pllJitter, sizeof(m_pllJitter)); - ZeroMemory(m_pllSyncOffset, sizeof(m_pllSyncOffset)); -} - -CBaseAP::~CBaseAP() -{ - if (m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = false; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(1); - } - } - - m_pFont = nullptr; - m_pLine = nullptr; - m_pSprite = nullptr; - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - m_pPSC.Free(); - m_pD3D = nullptr; - m_pD3DEx = nullptr; - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - - m_pAudioStats = nullptr; - SAFE_DELETE(m_pGenlock); - - if (m_FocusThread) { - m_FocusThread->PostThreadMessage(WM_QUIT, 0, 0); - if (WaitForSingleObject(m_FocusThread->m_hThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_FocusThread->m_hThread, 0xDEAD); - } - } - - if (m_hDWMAPI) { - FreeLibrary(m_hDWMAPI); - m_hDWMAPI = nullptr; - } -} - -template -void CBaseAP::AdjustQuad(MYD3DVERTEX* v, double dx, double dy) -{ - float offset = 0.5; - - for (int i = 0; i < 4; i++) { - v[i].x -= offset; - v[i].y -= offset; - - for (int j = 0; j < std::max(texcoords - 1, 1); j++) { - v[i].t[j].u -= (float)(offset * dx); - v[i].t[j].v -= (float)(offset * dy); - } - - if constexpr(texcoords > 1) { - v[i].t[texcoords - 1].u -= offset; - v[i].t[texcoords - 1].v -= offset; - } - } -} - -template -HRESULT CBaseAP::TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter = D3DTEXF_LINEAR) -{ - CheckPointer(pD3DDev, E_POINTER); - - DWORD FVF = 0; - switch (texcoords) { - case 1: - FVF = D3DFVF_TEX1; - break; - case 2: - FVF = D3DFVF_TEX2; - break; - case 3: - FVF = D3DFVF_TEX3; - break; - case 4: - FVF = D3DFVF_TEX4; - break; - case 5: - FVF = D3DFVF_TEX5; - break; - case 6: - FVF = D3DFVF_TEX6; - break; - case 7: - FVF = D3DFVF_TEX7; - break; - case 8: - FVF = D3DFVF_TEX8; - break; - default: - return E_FAIL; - } - - HRESULT hr; - hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); - - for (int i = 0; i < texcoords; i++) { - hr = pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); - hr = pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter); - hr = pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - } - - hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF); - - MYD3DVERTEX tmp = v[2]; - v[2] = v[3]; - v[3] = tmp; - hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); - - for (int i = 0; i < texcoords; i++) { - pD3DDev->SetTexture(i, nullptr); - } - - return S_OK; -} - -HRESULT CBaseAP::DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]) -{ - CheckPointer(pD3DDev, E_POINTER); - - HRESULT hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - hr = pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - hr = pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); - - hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); - - hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE); - - MYD3DVERTEX<0> tmp = v[2]; - v[2] = v[3]; - v[3] = tmp; - hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); - - return S_OK; -} - -MFOffset CBaseAP::GetOffset(float v) -{ - MFOffset offset; - offset.value = short(v); - offset.fract = WORD(65536 * (v - offset.value)); - return offset; -} - -MFVideoArea CBaseAP::GetArea(float x, float y, DWORD width, DWORD height) -{ - MFVideoArea area; - area.OffsetX = GetOffset(x); - area.OffsetY = GetOffset(y); - area.Area.cx = width; - area.Area.cy = height; - return area; -} - -void CBaseAP::ResetStats() -{ - m_pGenlock->ResetStats(); - m_lAudioLag = 0; - m_lAudioLagMin = 10000; - m_lAudioLagMax = -10000; - m_MinJitter = MAXLONG64; - m_MaxJitter = MINLONG64; - m_MinSyncOffset = MAXLONG64; - m_MaxSyncOffset = MINLONG64; - m_uSyncGlitches = 0; - m_pcFramesDropped = 0; - m_llLastSyncTime = LONGLONG_ERROR; -} - -bool CBaseAP::SettingsNeedResetDevice() -{ - CRenderersSettings& r = GetRenderersSettings(); - CRenderersSettings::CAdvRendererSettings& New = r.m_AdvRendSets; - CRenderersSettings::CAdvRendererSettings& Current = m_LastRendererSettings; - - bool bRet = false; - if (!m_bIsFullscreen) { - if (Current.bVMRDisableDesktopComposition) { - if (!m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = true; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(0); - } - } - } else { - if (m_bDesktopCompositionDisabled) { - m_bDesktopCompositionDisabled = false; - if (m_pDwmEnableComposition) { - m_pDwmEnableComposition(1); - } - } - } - } - bRet = bRet || New.bEVRHighColorResolution != Current.bEVRHighColorResolution; - m_LastRendererSettings = r.m_AdvRendSets; - return bRet; -} - -HRESULT CBaseAP::CreateDXDevice(CString& _Error) -{ - TRACE(_T("--> CBaseAP::CreateDXDevice on thread: %lu\n"), GetCurrentThreadId()); - const CRenderersSettings& r = GetRenderersSettings(); - m_LastRendererSettings = r.m_AdvRendSets; - HRESULT hr = E_FAIL; - - m_pFont = nullptr; - m_pSprite = nullptr; - m_pLine = nullptr; - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - - m_pPSC.Free(); - - m_pResizerPixelShader[0] = 0; - m_pResizerPixelShader[1] = 0; - m_pResizerPixelShader[2] = 0; - m_pResizerPixelShader[3] = 0; - - POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - pos = m_pPixelShaders.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - - UINT currentAdapter = GetAdapter(m_pD3D, m_hWnd); - bool bTryToReset = (currentAdapter == m_CurrentAdapter); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - m_CurrentAdapter = currentAdapter; - } - - if (!m_pD3D) { - _Error += L"Failed to create Direct3D device\n"; - return E_UNEXPECTED; - } - - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - if (FAILED(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)) - || d3ddm.Width <= 0 || d3ddm.Height <= 0) { - _Error += L"Can not retrieve display mode data\n"; - return E_UNEXPECTED; - } - - if (FAILED(m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &m_caps))) { - if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0) { - _Error += L"Video card does not have scanline access. Display synchronization is not possible.\n"; - return E_UNEXPECTED; - } - } - - m_refreshRate = d3ddm.RefreshRate; - m_dD3DRefreshCycle = 1000.0 / m_refreshRate; // In ms - m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); - m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height); - - BOOL bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - m_bCompositionEnabled = bCompositionEnabled != 0; - - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - - ZeroMemory(&m_pp, sizeof(m_pp)); - if (m_bIsFullscreen) { // Exclusive mode fullscreen - m_pp.Windowed = FALSE; - m_pp.BackBufferWidth = d3ddm.Width; - m_pp.BackBufferHeight = d3ddm.Height; - m_pp.hDeviceWindow = m_hWnd; - TRACE(_T("Wnd in CreateDXDevice: %p\n"), m_hWnd); - m_pp.BackBufferCount = 3; - m_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - m_pp.Flags = D3DPRESENTFLAG_VIDEO; - m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; - if (m_bHighColorResolution) { - if (FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false))) { - m_strStatsMsg[MSG_ERROR] = L"10 bit RGB is not supported by this graphics device in this resolution."; - m_bHighColorResolution = false; - } - } - - if (m_bHighColorResolution) { - m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } else { - m_pp.BackBufferFormat = d3ddm.Format; - } - - if (!m_FocusThread) { - m_FocusThread = (CFocusThread*)AfxBeginThread(RUNTIME_CLASS(CFocusThread), 0, 0, 0); - } - - HWND hFocusWindow = m_FocusThread->GetFocusWindow(); - bTryToReset &= (m_hFocusWindow == hFocusWindow || fullScreenChanged); - m_hFocusWindow = hFocusWindow; - - if (m_pD3DEx) { - D3DDISPLAYMODEEX DisplayMode; - ZeroMemory(&DisplayMode, sizeof(DisplayMode)); - DisplayMode.Size = sizeof(DisplayMode); - m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); - - DisplayMode.Format = m_pp.BackBufferFormat; - m_pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate; - - bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&m_pp, &DisplayMode)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - hr = m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS | D3DCREATE_NOWINDOWCHANGES, - &m_pp, &DisplayMode, &m_pD3DDevEx); - } - - if (m_pD3DDevEx) { - m_pD3DDev = m_pD3DDevEx; - m_BackbufferType = m_pp.BackBufferFormat; - m_DisplayType = DisplayMode.Format; - } - } else { - bTryToReset = bTryToReset && m_pD3DDev && SUCCEEDED(hr = m_pD3DDev->Reset(&m_pp)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - hr = m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_NOWINDOWCHANGES, - &m_pp, &m_pD3DDev); - } - TRACE(_T("Created full-screen device\n")); - if (m_pD3DDev) { - m_BackbufferType = m_pp.BackBufferFormat; - m_DisplayType = d3ddm.Format; - } - } - } else { // Windowed - m_pp.Windowed = TRUE; - m_pp.hDeviceWindow = m_hWnd; - m_pp.SwapEffect = D3DSWAPEFFECT_COPY; - m_pp.Flags = D3DPRESENTFLAG_VIDEO; - m_pp.BackBufferCount = 1; - CSize bbsize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); - m_pp.BackBufferWidth = bbsize.cx; - m_pp.BackBufferHeight = bbsize.cy; - m_BackbufferType = d3ddm.Format; - m_DisplayType = d3ddm.Format; - m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; - if (m_bHighColorResolution) { - if (FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false))) { - m_strStatsMsg[MSG_ERROR] = L"10 bit RGB is not supported by this graphics device in this resolution."; - m_bHighColorResolution = false; - } - } - - if (m_bHighColorResolution) { - m_BackbufferType = D3DFMT_A2R10G10B10; - m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } - if (bCompositionEnabled) { - // Desktop composition presents the whole desktop - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - } else { - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - } - - bTryToReset &= (m_hFocusWindow == m_hWnd || fullScreenChanged); - m_hFocusWindow = m_hWnd; - - if (m_pD3DEx) { - bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&m_pp, nullptr)); - - if (!bTryToReset) { - m_pD3DDev = nullptr; - m_pD3DDevEx = nullptr; - hr = m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS, - &m_pp, nullptr, &m_pD3DDevEx); - } - - if (m_pD3DDevEx) { - m_pD3DDev = m_pD3DDevEx; - } - } else { - if (bTryToReset) { - if (!m_pD3DDev || FAILED(hr = m_pD3DDev->Reset(&m_pp))) { - bTryToReset = false; - } - } - if (!bTryToReset) { - hr = m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, - D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED, - &m_pp, &m_pD3DDev); - } - TRACE(_T("Created windowed device\n")); - } - } - - if (m_pD3DDev) { - while (hr == D3DERR_DEVICELOST) { - TRACE(_T("D3DERR_DEVICELOST. Trying to Reset.\n")); - hr = m_pD3DDev->TestCooperativeLevel(); - } - if (hr == D3DERR_DEVICENOTRESET) { - TRACE(_T("D3DERR_DEVICENOTRESET\n")); - hr = m_pD3DDev->Reset(&m_pp); - } - - if (m_pD3DDevEx) { - m_pD3DDevEx->SetGPUThreadPriority(7); - } - } - - if (FAILED(hr)) { - _Error.AppendFormat(_T("CreateDevice failed: %s\n"), GetWindowsErrorMessage(hr, nullptr).GetString()); - - return hr; - } - - m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); - m_filter = D3DTEXF_NONE; - - if (m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR && m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR) { - m_filter = D3DTEXF_LINEAR; - } - - m_bicubicA = 0; - - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(m_pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); - } - - hr = S_OK; - - CComPtr pSubPicProvider; - if (m_pSubPicQueue) { - TRACE(_T("m_pSubPicQueue != nullptr\n")); - m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); - } - - if (!m_pSubPicQueue) { - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - m_pSubPicQueue->Invalidate(); - } - - if (FAILED(hr)) { - _Error += L"m_pSubPicQueue failed\n"; - return hr; - } - - if (pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); - } - - m_LastAdapterCheck = GetRenderersData()->GetPerfCounter(); - return S_OK; -} - -HRESULT CBaseAP::ResetDXDevice(CString& _Error) -{ - const CRenderersSettings& r = GetRenderersSettings(); - m_LastRendererSettings = r.m_AdvRendSets; - HRESULT hr = E_FAIL; - - hr = m_pD3DDev->TestCooperativeLevel(); - if ((hr != D3DERR_DEVICENOTRESET) && (hr != D3D_OK)) { - return hr; - } - - CComPtr rendererInputEnum; - std::vector> decoderOutput; - std::vector> rendererInput; - CFilterInfo filterInfo; - - bool disconnected = false; - - // Disconnect all pins to release video memory resources - if (m_pD3DDev) { - m_pOuterEVR->QueryFilterInfo(&filterInfo); - if (SUCCEEDED(m_pOuterEVR->EnumPins(&rendererInputEnum))) { - CComPtr input; - CComPtr output; - while (hr = rendererInputEnum->Next(1, &input.p, 0), hr == S_OK) { // Must have .p here - TRACE(_T("Pin found\n")); - input->ConnectedTo(&output.p); - if (output != nullptr) { - rendererInput.push_back(input); - decoderOutput.push_back(output); - } - input.Release(); - output.Release(); - } - } else { - return hr; - } - if (filterInfo.pGraph) { - for (size_t i = 0; i < decoderOutput.size(); i++) { - TRACE(_T("Disconnecting pin\n")); - filterInfo.pGraph->Disconnect(decoderOutput[i].p); - filterInfo.pGraph->Disconnect(rendererInput[i].p); - TRACE(_T("Pin disconnected\n")); - } - disconnected = true; - } - } - - // Release more resources - m_pSubPicQueue = nullptr; - m_pFont = nullptr; - m_pSprite = nullptr; - m_pLine = nullptr; - m_pPSC.Free(); - - m_pResizerPixelShader[0] = 0; - m_pResizerPixelShader[1] = 0; - m_pResizerPixelShader[2] = 0; - m_pResizerPixelShader[3] = 0; - - POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - pos = m_pPixelShaders.GetHeadPosition(); - while (pos) { - CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); - Shader.m_pPixelShader = nullptr; - } - - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - if (FAILED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D, m_hWnd), &d3ddm)) - || d3ddm.Width <= 0 || d3ddm.Height <= 0) { - _Error += L"Can not retrieve display mode data\n"; - return E_UNEXPECTED; - } - - m_refreshRate = d3ddm.RefreshRate; - m_dD3DRefreshCycle = 1000.0 / m_refreshRate; // In ms - m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); - m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height); - CSize szDesktopSize(GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)); - - ZeroMemory(&m_pp, sizeof(m_pp)); - - BOOL bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - m_bCompositionEnabled = bCompositionEnabled != 0; - m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; - - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - - if (m_bIsFullscreen) { // Exclusive mode fullscreen - m_pp.BackBufferWidth = d3ddm.Width; - m_pp.BackBufferHeight = d3ddm.Height; - if (m_bHighColorResolution) { - m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } else { - m_pp.BackBufferFormat = d3ddm.Format; - } - if (FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_pp.BackBufferFormat, m_pp.BackBufferFormat, false))) { - _Error += L"10 bit RGB is not supported by this graphics device in exclusive mode fullscreen.\n"; - return hr; - } - - D3DDISPLAYMODEEX DisplayMode; - ZeroMemory(&DisplayMode, sizeof(DisplayMode)); - DisplayMode.Size = sizeof(DisplayMode); - if (m_pD3DDevEx) { - m_pD3DEx->GetAdapterDisplayModeEx(GetAdapter(m_pD3DEx, m_hWnd), &DisplayMode, nullptr); - DisplayMode.Format = m_pp.BackBufferFormat; - m_pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate; - if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { - _Error += GetWindowsErrorMessage(hr, nullptr); - return hr; - } - } else if (m_pD3DDev) { - if (FAILED(m_pD3DDev->Reset(&m_pp))) { - _Error += GetWindowsErrorMessage(hr, nullptr); - return hr; - } - } else { - _Error += L"No device.\n"; - return hr; - } - m_BackbufferType = m_pp.BackBufferFormat; - m_DisplayType = d3ddm.Format; - } else { // Windowed - CSize bbsize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); - m_pp.BackBufferWidth = bbsize.cx; - m_pp.BackBufferHeight = bbsize.cy; - m_BackbufferType = d3ddm.Format; - m_DisplayType = d3ddm.Format; - if (m_bHighColorResolution) { - m_BackbufferType = D3DFMT_A2R10G10B10; - m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; - } - if (FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_pp.BackBufferFormat, m_pp.BackBufferFormat, false))) { - _Error += L"10 bit RGB is not supported by this graphics device in windowed mode.\n"; - return hr; - } - if (bCompositionEnabled) { - // Desktop composition presents the whole desktop - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - } else { - m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - } - if (m_pD3DDevEx) - if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { - _Error += GetWindowsErrorMessage(hr, nullptr); - return hr; - } else if (m_pD3DDev) - if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { - _Error += GetWindowsErrorMessage(hr, nullptr); - return hr; - } else { - _Error += L"No device.\n"; - return hr; - } - } - - if (disconnected) { - for (size_t i = 0; i < decoderOutput.size(); i++) { - if (FAILED(filterInfo.pGraph->ConnectDirect(decoderOutput[i].p, rendererInput[i].p, nullptr))) { - return hr; - } - } - } - - m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); - m_filter = D3DTEXF_NONE; - - if ((m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) - && (m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)) { - m_filter = D3DTEXF_LINEAR; - } - - m_bicubicA = 0; - - CComPtr pSubPicProvider; - if (m_pSubPicQueue) { - m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); - } - - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(m_pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); - } - - hr = S_OK; - if (!m_pSubPicQueue) { - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - m_pSubPicQueue->Invalidate(); - } - - if (FAILED(hr)) { - _Error += L"m_pSubPicQueue failed\n"; - - return hr; - } - - if (pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); - } - - m_pFont = nullptr; - m_pSprite = nullptr; - m_pLine = nullptr; - - return S_OK; -} - -HRESULT CBaseAP::AllocSurfaces(D3DFORMAT Format) -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_allocatorLock); - - CheckPointer(m_pD3DDev, E_POINTER); - - const CRenderersSettings& r = GetRenderersSettings(); - - for (int i = 0; i < m_nDXSurface + 2; i++) { - m_pVideoTexture[i] = nullptr; - m_pVideoSurface[i] = nullptr; - } - - m_pScreenSizeTemporaryTexture[0] = nullptr; - m_pScreenSizeTemporaryTexture[1] = nullptr; - m_SurfaceType = Format; - - HRESULT hr; - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { - int nTexturesNeeded = r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nDXSurface + 2 : 1; - - for (int i = 0; i < nTexturesNeeded; i++) { - if (FAILED(hr = m_pD3DDev->CreateTexture( - m_nativeVideoSize.cx, - m_nativeVideoSize.cy, - 1, - D3DUSAGE_RENDERTARGET, - Format, - D3DPOOL_DEFAULT, - &m_pVideoTexture[i], - nullptr))) { - return hr; - } - - if (FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i]))) { - return hr; - } - } - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D) { - for (int i = 0; i < m_nDXSurface + 2; i++) { - m_pVideoTexture[i] = nullptr; - } - } - } else { - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(m_nativeVideoSize.cx, m_nativeVideoSize.cy, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], nullptr))) { - return hr; - } - } - - hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], nullptr, 0); - return S_OK; -} - -void CBaseAP::DeleteSurfaces() -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_allocatorLock); - - for (int i = 0; i < m_nDXSurface + 2; i++) { - m_pVideoTexture[i] = nullptr; - m_pVideoSurface[i] = nullptr; - } -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP CBaseAP::CreateRenderer(IUnknown** ppRenderer) -{ - return E_NOTIMPL; -} - -bool CBaseAP::ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d) -{ - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pSurface->GetDesc(&desc))) { - return false; - } - - int w = desc.Width, h = desc.Height; - int sw = s.Width(), sh = s.Height(); - int dw = d.Width(), dh = d.Height(); - - if (d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0 - || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) { - s.SetRectEmpty(); - d.SetRectEmpty(); - return true; - } - if (d.right > w) { - s.right -= (d.right - w) * sw / dw; - d.right = w; - } - if (d.bottom > h) { - s.bottom -= (d.bottom - h) * sh / dh; - d.bottom = h; - } - if (d.left < 0) { - s.left += (0 - d.left) * sw / dw; - d.left = 0; - } - if (d.top < 0) { - s.top += (0 - d.top) * sh / dh; - d.top = 0; - } - return true; -} - -HRESULT CBaseAP::InitResizers(float bicubicA, bool bNeedScreenSizeTexture) -{ - HRESULT hr; - do { - if (bicubicA) { - if (!m_pResizerPixelShader[0]) { - break; - } - if (!m_pResizerPixelShader[1]) { - break; - } - if (!m_pResizerPixelShader[2]) { - break; - } - if (!m_pResizerPixelShader[3]) { - break; - } - if (m_bicubicA != bicubicA) { - break; - } - if (!m_pScreenSizeTemporaryTexture[0]) { - break; - } - if (bNeedScreenSizeTexture) { - if (!m_pScreenSizeTemporaryTexture[1]) { - break; - } - } - } else { - if (!m_pResizerPixelShader[0]) { - break; - } - if (bNeedScreenSizeTexture) { - if (!m_pScreenSizeTemporaryTexture[0]) { - break; - } - if (!m_pScreenSizeTemporaryTexture[1]) { - break; - } - } - } - return S_OK; - } while (0); - - m_bicubicA = bicubicA; - m_pScreenSizeTemporaryTexture[0] = nullptr; - m_pScreenSizeTemporaryTexture[1] = nullptr; - - for (int i = 0; i < _countof(m_pResizerPixelShader); i++) { - m_pResizerPixelShader[i] = nullptr; - } - - if (m_caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { - return E_FAIL; - } - - LPCSTR pProfile = m_caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; - - CStringA str; - if (!LoadResource(IDF_SHADER_RESIZER, str, _T("SHADER"))) { - return E_FAIL; - } - - CStringA A; - A.Format("(%f)", bicubicA); - str.Replace("_The_Value_Of_A_Is_Set_Here_", A); - - LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass_pass1", "main_bicubic2pass_pass2"}; - - ASSERT(_countof(pEntries) == _countof(m_pResizerPixelShader)); - for (int i = 0; i < _countof(pEntries); i++) { - CString ErrorMessage; - CString DissAssembly; - hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShader[i], &DissAssembly, &ErrorMessage); - if (FAILED(hr)) { - TRACE(_T("%ws"), ErrorMessage.GetString()); - ASSERT(0); - return hr; - } - } - if (m_bicubicA || bNeedScreenSizeTexture) { - if (FAILED(m_pD3DDev->CreateTexture( - std::min((DWORD)m_ScreenSize.cx, m_caps.MaxTextureWidth), - std::min((DWORD)std::max(m_ScreenSize.cy, m_nativeVideoSize.cy), m_caps.MaxTextureHeight), - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - &m_pScreenSizeTemporaryTexture[0], - nullptr))) { - ASSERT(0); - m_pScreenSizeTemporaryTexture[0] = nullptr; // will do 1 pass then - } - - if (FAILED(m_pD3DDev->CreateTexture( - std::min((DWORD)m_ScreenSize.cx, m_caps.MaxTextureWidth), - std::min((DWORD)std::max(m_ScreenSize.cy, m_nativeVideoSize.cy), m_caps.MaxTextureHeight), - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - &m_pScreenSizeTemporaryTexture[1], - nullptr))) { - ASSERT(0); - m_pScreenSizeTemporaryTexture[1] = nullptr; // will do 1 pass then - } - } - return S_OK; -} - -HRESULT CBaseAP::TextureCopy(IDirect3DTexture9* pTexture) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - MYD3DVERTEX<1> v[] = { - {0, 0, 0.5f, 2.0f, 0, 0}, - {w, 0, 0.5f, 2.0f, 1, 0}, - {0, h, 0.5f, 2.0f, 0, 1}, - {w, h, 0.5f, 2.0f, 1, 1}, - }; - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - hr = m_pD3DDev->SetTexture(0, pTexture); - return TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); -} - -HRESULT CBaseAP::DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect) -{ - DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color)); - MYD3DVERTEX<0> v[] = { - {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color}, - {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color}, - {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color}, - {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color}, - }; - for (int i = 0; i < _countof(v); i++) { - v[i].x -= 0.5; - v[i].y -= 0.5; - } - return DrawRectBase(m_pD3DDev, v); -} - -HRESULT CBaseAP::TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& SrcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - float dx2 = 1.0f / w; - float dy2 = 1.0f / h; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, SrcRect.left * dx2, SrcRect.top * dy2}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, SrcRect.right * dx2, SrcRect.top * dy2}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, SrcRect.left * dx2, SrcRect.bottom * dy2}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, SrcRect.right * dx2, SrcRect.bottom * dy2}, - }; - AdjustQuad(v, 0, 0); - hr = m_pD3DDev->SetTexture(0, pTexture); - hr = m_pD3DDev->SetPixelShader(nullptr); - hr = TextureBlt(m_pD3DDev, v, filter); - return hr; -} - -HRESULT CBaseAP::TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - float tx0 = (float)SrcRect.left; - float tx1 = (float)SrcRect.right; - float ty0 = (float)SrcRect.top; - float ty1 = (float)SrcRect.bottom; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, - }; - AdjustQuad(v, 1.0, 1.0); - float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - hr = m_pD3DDev->SetTexture(0, pTexture); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[0]); - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - m_pD3DDev->SetPixelShader(nullptr); - return hr; -} - -HRESULT CBaseAP::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) -{ - HRESULT hr; - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { - return E_FAIL; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - float tx0 = (float)SrcRect.left; - float tx1 = (float)SrcRect.right; - float ty0 = (float)SrcRect.top; - float ty1 = (float)SrcRect.bottom; - - MYD3DVERTEX<1> v[] = { - {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, - {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, - {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, - {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, - }; - AdjustQuad(v, 1.0, 1.0); - hr = m_pD3DDev->SetTexture(0, pTexture); - float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[1]); - hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); - m_pD3DDev->SetPixelShader(nullptr); - return hr; -} - -HRESULT CBaseAP::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) -{ - // The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction. - return TextureResizeBicubic1pass(pTexture, dst, SrcRect); - - /*HRESULT hr; - - // rotated? - if (dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z - || dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x) - return TextureResizeBicubic1pass(pTexture, dst, SrcRect); - - D3DSURFACE_DESC desc; - if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) - return E_FAIL; - - float Tex0_Width = desc.Width; - float Tex0_Height = desc.Height; - - CSize SrcTextSize = CSize(desc.Width, desc.Height); - double w = (double)SrcRect.Width(); - double h = (double)SrcRect.Height(); - UNREFERENCED_PARAMETER(w); - - CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h); - - if (!m_pScreenSizeTemporaryTexture[0] || FAILED(m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc))) - return TextureResizeBicubic1pass(pTexture, dst, SrcRect); - - float Tex1_Width = desc.Width; - float Tex1_Height = desc.Height; - - float tx0 = SrcRect.left; - float tx1 = SrcRect.right; - float ty0 = SrcRect.top; - float ty1 = SrcRect.bottom; - - float tx0_2 = 0; - float tx1_2 = dst1.Width(); - float ty0_2 = 0; - float ty1_2 = h; - - if (dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height) - return TextureResizeBicubic1pass(pTexture, dst, SrcRect); - - MYD3DVERTEX<1> vx[] = - { - {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0}, - {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0}, - {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1}, - {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1}, - }; - AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug here, create vertical lines ! TODO : why ?????? - MYD3DVERTEX<1> vy[] = - { - {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2}, - {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2}, - {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2}, - {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2}, - }; - AdjustQuad(vy, 0.0, 1.0); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[2]); - { - float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - } - hr = m_pD3DDev->SetTexture(0, pTexture); - CComPtr pRTOld; - hr = m_pD3DDev->GetRenderTarget(0, &pRTOld); - CComPtr pRT; - hr = m_pScreenSizeTemporaryTexture[0]->GetSurfaceLevel(0, &pRT); - hr = m_pD3DDev->SetRenderTarget(0, pRT); - hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT); - hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[3]); - { - float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}}; - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - } - hr = m_pD3DDev->SetTexture(0, m_pScreenSizeTemporaryTexture[0]); - hr = m_pD3DDev->SetRenderTarget(0, pRTOld); - hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT); - m_pD3DDev->SetPixelShader(nullptr); - return hr;*/ -} - -HRESULT CBaseAP::AlphaBlt(RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture) -{ - if (!pSrc || !pDst) { - return E_POINTER; - } - - CRect src(*pSrc), dst(*pDst); - - HRESULT hr; - - do { - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { - break; - } - - float w = (float)desc.Width; - float h = (float)desc.Height; - - // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile - // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly - // initialized and thus the subtitles weren't shown. - struct { - float x, y, z, rhw; - float tu, tv; - } pVertices[] = { - {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, - {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, - {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, - {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, - }; - - for (size_t i = 0; i < _countof(pVertices); i++) { - pVertices[i].x -= 0.5f; - pVertices[i].y -= 0.5f; - } - - hr = m_pD3DDev->SetTexture(0, pTexture); - - // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE - // so we need to provide default values in case GetRenderState fails - DWORD abe, sb, db; - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { - abe = FALSE; - } - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { - sb = D3DBLEND_ONE; - } - if (FAILED(m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { - db = D3DBLEND_ZERO; - } - - hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); - hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... - hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst - - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); - - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - - hr = m_pD3DDev->SetPixelShader(nullptr); - - hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); - hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); - - m_pD3DDev->SetTexture(0, nullptr); - - m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); - m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); - m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); - - return S_OK; - } while (0); - return E_FAIL; -} - -// Update the array m_pllJitter with a new vsync period. Calculate min, max and stddev. -void CBaseAP::SyncStats(LONGLONG syncTime) -{ - if (m_llLastSyncTime == LONGLONG_ERROR) { - m_llLastSyncTime = syncTime; - } - - m_nNextJitter = (m_nNextJitter + 1) % NB_JITTER; - LONGLONG jitter = syncTime - m_llLastSyncTime; - m_pllJitter[m_nNextJitter] = jitter; - double syncDeviation = (m_pllJitter[m_nNextJitter] - m_fJitterMean) / 10000.0; - if (abs(syncDeviation) > (GetDisplayCycle() / 2)) { - m_uSyncGlitches++; - } - - LONGLONG llJitterSum = 0; - LONGLONG llJitterSumAvg = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG Jitter = m_pllJitter[i]; - llJitterSum += Jitter; - llJitterSumAvg += Jitter; - } - m_fJitterMean = double(llJitterSumAvg) / NB_JITTER; - double DeviationSum = 0; - - for (int i = 0; i < NB_JITTER; i++) { - double deviation = m_pllJitter[i] - m_fJitterMean; - DeviationSum += deviation * deviation; - LONGLONG deviationInt = std::llround(deviation); - m_MaxJitter = std::max(m_MaxJitter, deviationInt); - m_MinJitter = std::min(m_MinJitter, deviationInt); - } - - m_fJitterStdDev = sqrt(DeviationSum / NB_JITTER); - m_fAvrFps = 10000000.0 / (double(llJitterSum) / NB_JITTER); - m_llLastSyncTime = syncTime; -} - -// Collect the difference between periodEnd and periodStart in an array, calculate mean and stddev. -void CBaseAP::SyncOffsetStats(LONGLONG syncOffset) -{ - m_nNextSyncOffset = (m_nNextSyncOffset + 1) % NB_JITTER; - m_pllSyncOffset[m_nNextSyncOffset] = syncOffset; - - LONGLONG AvrageSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - LONGLONG Offset = m_pllSyncOffset[i]; - AvrageSum += Offset; - m_MaxSyncOffset = std::max(m_MaxSyncOffset, Offset); - m_MinSyncOffset = std::min(m_MinSyncOffset, Offset); - } - double MeanOffset = double(AvrageSum) / NB_JITTER; - double DeviationSum = 0; - for (int i = 0; i < NB_JITTER; i++) { - double Deviation = double(m_pllSyncOffset[i]) - MeanOffset; - DeviationSum += Deviation * Deviation; - } - double StdDev = sqrt(DeviationSum / NB_JITTER); - - m_fSyncOffsetAvr = MeanOffset; - m_fSyncOffsetStdDev = StdDev; -} - -void CBaseAP::UpdateAlphaBitmap() -{ - m_VMR9AlphaBitmapData.Free(); - - if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0) { - HBITMAP hBitmap = (HBITMAP)GetCurrentObject(m_VMR9AlphaBitmap.hdc, OBJ_BITMAP); - if (!hBitmap) { - return; - } - DIBSECTION info; - ZeroMemory(&info, sizeof(DIBSECTION)); - if (!::GetObject(hBitmap, sizeof(DIBSECTION), &info)) { - return; - } - - m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight); - m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes; - - if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight)) { - memcpy((BYTE*)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight); - } - } -} - -// Present a sample (frame) using DirectX. -STDMETHODIMP_(bool) CBaseAP::Paint(bool bAll) -{ - if (m_bPendingResetDevice) { - SendResetRequest(); - return false; - } - - const CRenderersSettings& r = GetRenderersSettings(); - CRenderersData* rd = GetRenderersData(); - D3DRASTER_STATUS rasterStatus; - REFERENCE_TIME llCurRefTime = 0; - REFERENCE_TIME llSyncOffset = 0; - double dSyncOffset = 0.0; - - CAutoLock cRenderLock(&m_allocatorLock); - - // Estimate time for next vblank based on number of remaining lines in this frame. This algorithm seems to be - // accurate within one ms why there should not be any need for a more accurate one. The wiggly line seen - // when using sync to nearest and sync display is most likely due to inaccuracies in the audio-card-based - // reference clock. The wiggles are not seen with the perfcounter-based reference clock of the sync to video option. - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - m_uScanLineEnteringPaint = rasterStatus.ScanLine; - if (m_pRefClock) { - m_pRefClock->GetTime(&llCurRefTime); - } - int dScanLines = std::max(int(m_ScreenSize.cy - m_uScanLineEnteringPaint), 0); - dSyncOffset = dScanLines * m_dDetectedScanlineTime; // ms - llSyncOffset = REFERENCE_TIME(10000.0 * dSyncOffset); // Reference time units (100 ns) - m_llEstVBlankTime = llCurRefTime + llSyncOffset; // Estimated time for the start of next vblank - - if (m_windowRect.right <= m_windowRect.left || m_windowRect.bottom <= m_windowRect.top - || m_nativeVideoSize.cx <= 0 || m_nativeVideoSize.cy <= 0 - || !m_pVideoSurface[m_nCurSurface]) { - return false; - } - - HRESULT hr; - CRect rSrcVid(CPoint(0, 0), m_nativeVideoSize); - CRect rDstVid(m_videoRect); - CRect rSrcPri(CPoint(0, 0), m_windowRect.Size()); - CRect rDstPri(rSrcPri); - - m_pD3DDev->BeginScene(); - CComPtr pBackBuffer; - m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); - m_pD3DDev->SetRenderTarget(0, pBackBuffer); - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); - if (!rDstVid.IsRectEmpty()) { - if (m_pVideoTexture[m_nCurSurface]) { - CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; - - if (m_pVideoTexture[m_nDXSurface] && m_pVideoTexture[m_nDXSurface + 1] && !m_pPixelShaders.IsEmpty()) { - static __int64 counter = 0; - static long start = clock(); - - long stop = clock(); - long diff = stop - start; - - if (diff >= 10 * 60 * CLOCKS_PER_SEC) { - start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) - } - - int src = m_nCurSurface, dst = m_nDXSurface; - - D3DSURFACE_DESC desc; - m_pVideoTexture[src]->GetLevelDesc(0, &desc); - - float fConstData[][4] = { - {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, - }; - - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - CComPtr pRT; - hr = m_pD3DDev->GetRenderTarget(0, &pRT); - - POSITION pos = m_pPixelShaders.GetHeadPosition(); - while (pos) { - pVideoTexture = m_pVideoTexture[dst]; - - hr = m_pD3DDev->SetRenderTarget(0, m_pVideoSurface[dst]); - CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); - if (!Shader.m_pPixelShader) { - Shader.Compile(m_pPSC); - } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); - TextureCopy(m_pVideoTexture[src]); - - src = dst; - if (++dst >= m_nDXSurface + 2) { - dst = m_nDXSurface; - } - } - - hr = m_pD3DDev->SetRenderTarget(0, pRT); - hr = m_pD3DDev->SetPixelShader(nullptr); - } - - Vector dst[4]; - Transform(rDstVid, dst); - - DWORD iDX9Resizer = r.iDX9Resizer; - - float A = 0; - - switch (iDX9Resizer) { - case 3: - A = -0.60f; - break; - case 4: - A = -0.751f; - break; // FIXME : 0.75 crash recent D3D, or eat CPU - case 5: - A = -1.00f; - break; - } - bool bScreenSpacePixelShaders = !m_pPixelShadersScreenSpace.IsEmpty(); - - hr = InitResizers(A, bScreenSpacePixelShaders); - - if (!m_pScreenSizeTemporaryTexture[0] || !m_pScreenSizeTemporaryTexture[1]) { - bScreenSpacePixelShaders = false; - } - - if (bScreenSpacePixelShaders) { - CComPtr pRT; - hr = m_pScreenSizeTemporaryTexture[1]->GetSurfaceLevel(0, &pRT); - if (hr != S_OK) { - bScreenSpacePixelShaders = false; - } - if (bScreenSpacePixelShaders) { - hr = m_pD3DDev->SetRenderTarget(0, pRT); - if (hr != S_OK) { - bScreenSpacePixelShaders = false; - } - hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); - } - } - - if (rSrcVid.Size() != rDstVid.Size()) { - if (iDX9Resizer == 0 || iDX9Resizer == 1) { - D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; - hr = TextureResize(pVideoTexture, dst, Filter, rSrcVid); - } else if (iDX9Resizer == 2) { - hr = TextureResizeBilinear(pVideoTexture, dst, rSrcVid); - } else if (iDX9Resizer >= 3) { - hr = TextureResizeBicubic2pass(pVideoTexture, dst, rSrcVid); - } - } else { - hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, rSrcVid); - } - - if (bScreenSpacePixelShaders) { - static __int64 counter = 555; - static long start = clock() + 333; - - long stop = clock() + 333; - long diff = stop - start; - - if (diff >= 10 * 60 * CLOCKS_PER_SEC) { - start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) - } - - D3DSURFACE_DESC desc; - m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc); - - float fConstData[][4] = { - {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, - {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, - }; - - hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); - - int srcTexture = 1, dstTexture = 0; - - POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); - while (pos) { - if (m_pPixelShadersScreenSpace.GetTailPosition() == pos) { - m_pD3DDev->SetRenderTarget(0, pBackBuffer); - } else { - CComPtr pRT; - hr = m_pScreenSizeTemporaryTexture[dstTexture]->GetSurfaceLevel(0, &pRT); - m_pD3DDev->SetRenderTarget(0, pRT); - } - - CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); - if (!Shader.m_pPixelShader) { - Shader.Compile(m_pPSC); - } - hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); - TextureCopy(m_pScreenSizeTemporaryTexture[srcTexture]); - - std::swap(srcTexture, dstTexture); - } - - hr = m_pD3DDev->SetPixelShader(nullptr); - } - } else { - if (pBackBuffer) { - ClipToSurface(pBackBuffer, rSrcVid, rDstVid); - // rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect - rSrcVid.left &= ~1; - rSrcVid.right &= ~1; - rSrcVid.top &= ~1; - rSrcVid.bottom &= ~1; - hr = m_pD3DDev->StretchRect(m_pVideoSurface[m_nCurSurface], rSrcVid, pBackBuffer, rDstVid, m_filter); - if (FAILED(hr)) { - return false; - } - } - } - } - - AlphaBltSubPic(rDstPri, rDstVid); - - if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE) { - CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock); - CRect rcSrc(m_VMR9AlphaBitmap.rSrc); - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE*)m_VMR9AlphaBitmapData) { - if ((m_pD3DXLoadSurfaceFromMemory != nullptr) && - SUCCEEDED(hr = m_pD3DDev->CreateTexture( - rcSrc.Width(), - rcSrc.Height(), - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - &m_pOSDTexture, - nullptr))) { - if (SUCCEEDED(hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface))) { - hr = m_pD3DXLoadSurfaceFromMemory(m_pOSDSurface, nullptr, nullptr, (BYTE*)m_VMR9AlphaBitmapData, D3DFMT_A8R8G8B8, m_VMR9AlphaBitmapWidthBytes, - nullptr, &m_VMR9AlphaBitmapRect, D3DX_FILTER_NONE, m_VMR9AlphaBitmap.clrSrcKey); - } - if (FAILED(hr)) { - m_pOSDTexture = nullptr; - m_pOSDSurface = nullptr; - } - } - } - m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE; - } - if (rd->m_iDisplayStats) { - DrawStats(); - } - if (m_pOSDTexture) { - AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture); - } - m_pD3DDev->EndScene(); - - CRect presentationSrcRect(rDstPri), presentationDestRect(m_windowRect); - // PresentEx() / Present() performs the clipping - // TODO: fix the race and uncomment the assert - //ASSERT(presentationSrcRect.Size() == presentationDestRect.Size()); - if (m_pD3DDevEx) { - if (m_bIsFullscreen) { - hr = m_pD3DDevEx->PresentEx(nullptr, nullptr, nullptr, nullptr, 0); - } else { - hr = m_pD3DDevEx->PresentEx(presentationSrcRect, presentationDestRect, nullptr, nullptr, 0); - } - } else { - if (m_bIsFullscreen) { - hr = m_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr); - } else { - hr = m_pD3DDev->Present(presentationSrcRect, presentationDestRect, nullptr, nullptr); - } - } - if (FAILED(hr)) { - TRACE(_T("Device lost or something\n")); - } - // Calculate timing statistics - if (m_pRefClock) { - m_pRefClock->GetTime(&llCurRefTime); // To check if we called Present too late to hit the right vsync - } - m_llEstVBlankTime = std::max(m_llEstVBlankTime, llCurRefTime); // Sometimes the real value is larger than the estimated value (but never smaller) - if (rd->m_iDisplayStats < 3) { // Partial on-screen statistics - SyncStats(m_llEstVBlankTime); // Max of estimate and real. Sometimes Present may actually return immediately so we need the estimate as a lower bound - } - if (rd->m_iDisplayStats == 1) { // Full on-screen statistics - SyncOffsetStats(-llSyncOffset); // Minus because we want time to flow downward in the graph in DrawStats - } - - // Adjust sync - double frameCycle = (m_llSampleTime - m_llLastSampleTime) / 10000.0; - if (frameCycle < 0) { - frameCycle = 0.0; // Happens when searching. - } - - if (r.m_AdvRendSets.bSynchronizeVideo) { - m_pGenlock->ControlClock(dSyncOffset, frameCycle); - } else if (r.m_AdvRendSets.bSynchronizeDisplay) { - m_pGenlock->ControlDisplay(dSyncOffset, frameCycle); - } else { - m_pGenlock->UpdateStats(dSyncOffset, frameCycle); // No sync or sync to nearest neighbor - } - - m_dFrameCycle = m_pGenlock->frameCycleAvg; - m_dCycleDifference = GetCycleDifference(); - if (abs(m_dCycleDifference) < 0.05) { // If less than 5% speed difference - m_bSnapToVSync = true; - } else { - m_bSnapToVSync = false; - } - - // Check how well audio is matching rate (if at all) - DWORD tmp; - if (m_pAudioStats != nullptr) { - m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_ACCUMERROR, &m_lAudioLag, &tmp); - m_lAudioLagMin = std::min((long)m_lAudioLag, m_lAudioLagMin); - m_lAudioLagMax = std::max((long)m_lAudioLag, m_lAudioLagMax); - m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_MODE, &m_lAudioSlaveMode, &tmp); - } - - if (rd->m_bResetStats) { - ResetStats(); - rd->m_bResetStats = false; - } - - bool fResetDevice = m_bPendingResetDevice; - if (hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET || hr == S_PRESENT_MODE_CHANGED) { - fResetDevice = true; - } - if (SettingsNeedResetDevice()) { - fResetDevice = true; - } - - BOOL bCompositionEnabled = false; - if (m_pDwmIsCompositionEnabled) { - m_pDwmIsCompositionEnabled(&bCompositionEnabled); - } - if ((bCompositionEnabled != 0) != m_bCompositionEnabled) { - if (m_bIsFullscreen) { - m_bCompositionEnabled = (bCompositionEnabled != 0); - } else { - fResetDevice = true; - } - } - - if (r.fResetDevice) { - LONGLONG time = rd->GetPerfCounter(); - if (time > m_LastAdapterCheck + 20000000) { // check every 2 sec. - m_LastAdapterCheck = time; -#ifdef _DEBUG - D3DDEVICE_CREATION_PARAMETERS Parameters; - if (SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))) { - ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter); - } -#endif - if (m_CurrentAdapter != GetAdapter(m_pD3D, m_hWnd)) { - fResetDevice = true; - } -#ifdef _DEBUG - else { - ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D, m_hWnd))); - } -#endif - } - } - - if (fResetDevice) { - m_bPendingResetDevice = true; - SendResetRequest(); - } - return true; -} - -void CBaseAP::SendResetRequest() -{ - if (!m_bDeviceResetRequested) { - m_bDeviceResetRequested = true; - AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE); - } -} - -STDMETHODIMP_(bool) CBaseAP::ResetDevice() -{ - DeleteSurfaces(); - HRESULT hr; - CString Error; - if (FAILED(hr = CreateDXDevice(Error)) || FAILED(hr = AllocSurfaces())) { - m_bDeviceResetRequested = false; - return false; - } - m_pGenlock->SetMonitor(GetAdapter(m_pD3D, m_hWnd)); - m_pGenlock->GetTiming(); - OnResetDevice(); - m_bDeviceResetRequested = false; - m_bPendingResetDevice = false; - return true; -} - -STDMETHODIMP_(bool) CBaseAP::DisplayChange() -{ - m_bPendingResetDevice = true; - SendResetRequest(); - return true; -} - -void CBaseAP::InitStats() -{ - ASSERT(m_pD3DDev); - static LONG currentHeight = 0; - int newHeight = lround(FONT_HEIGHT * (double(m_windowRect.Width()) / REFERENCE_WIDTH)); - - if (m_pD3DXCreateFont && (!m_pFont || currentHeight != newHeight)) { - m_pFont = nullptr; - if (newHeight <= 0) { - ASSERT(FALSE); - } - m_pD3DXCreateFont(m_pD3DDev, newHeight, 0, newHeight < BOLD_THRESHOLD ? FW_NORMAL : FW_BOLD, - 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, - FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont); - currentHeight = newHeight; - } - - if (m_pD3DXCreateSprite && !m_pSprite) { - m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite); - } - - if (m_pD3DXCreateLine && !m_pLine) { - m_pD3DXCreateLine(m_pD3DDev, &m_pLine); - } -} - -void CBaseAP::DrawStats() -{ - const CRenderersData* rd = GetRenderersData(); - - InitStats(); - const float textScale = float(m_windowRect.Width()) / REFERENCE_WIDTH; - const int lineHeight = lround((FONT_HEIGHT + TEXT_PADDING) * textScale); - - // pApp->m_iDisplayStats = 1 for full stats, 2 for little less, 3 for basic, 0 for no stats - if (m_pFont && m_pSprite) { - auto drawText = [&](CRect & rc, const CString & strText) { - D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f); - D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f); - - RECT shadowRect = rc; - OffsetRect(&shadowRect, 2, 2); - - // Draw shadow - m_pFont->DrawText(m_pSprite, strText, -1, &shadowRect, DT_NOCLIP, Color0); - // Draw text - m_pFont->DrawText(m_pSprite, strText, -1, rc, DT_NOCLIP, Color1); - rc.OffsetRect(0, lineHeight); - }; - - const CRenderersSettings& r = GetRenderersSettings(); - LONGLONG llMaxJitter = m_MaxJitter; - LONGLONG llMinJitter = m_MinJitter; - CRect rc(lineHeight, lineHeight, 0, 0); - - m_pSprite->Begin(D3DXSPRITE_ALPHABLEND); - CString strText; - - strText.Format(_T("Frames drawn from stream start: %u | Sample time stamp: %ld ms"), - m_pcFramesDrawn, (LONG)(m_llSampleTime / 10000)); - drawText(rc, strText); - - if (rd->m_iDisplayStats == 1) { - strText.Format(_T("Frame cycle : %.3f ms [%.3f ms, %.3f ms] Actual %+5.3f ms [%+.3f ms, %+.3f ms]"), - m_dFrameCycle, m_pGenlock->minFrameCycle, m_pGenlock->maxFrameCycle, - m_fJitterMean / 10000.0, (double(llMinJitter) / 10000.0), - (double(llMaxJitter) / 10000.0)); - drawText(rc, strText); - - strText.Format(_T("Display cycle: Measured closest match %.3f ms Measured base %.3f ms"), - m_dOptimumDisplayCycle, m_dEstRefreshCycle); - drawText(rc, strText); - - strText.Format(_T("Frame rate : %.3f fps Actual frame rate: %.3f fps"), - 1000.0 / m_dFrameCycle, 10000000.0 / m_fJitterMean); - drawText(rc, strText); - - strText.Format(_T("Windows : Display cycle %.3f ms Display refresh rate %u Hz"), - m_dD3DRefreshCycle, m_refreshRate); - drawText(rc, strText); - - if (m_pGenlock->powerstripTimingExists) { - strText.Format(_T("Powerstrip : Display cycle %.3f ms Display refresh rate %.3f Hz"), - 1000.0 / m_pGenlock->curDisplayFreq, m_pGenlock->curDisplayFreq); - drawText(rc, strText); - } - - if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0) { - strText = _T("Scan line err: Graphics device does not support scan line access. No sync is possible"); - drawText(rc, strText); - } - -#ifdef _DEBUG - if (m_pD3DDevEx) { - CComPtr pSC; - HRESULT hr = m_pD3DDevEx->GetSwapChain(0, &pSC); - CComQIPtr pSCEx = pSC; - if (pSCEx) { - D3DPRESENTSTATS stats; - hr = pSCEx->GetPresentStats(&stats); - if (SUCCEEDED(hr)) { - strText = _T("Graphics device present stats:"); - drawText(rc, strText); - - strText.Format(_T(" PresentCount %u PresentRefreshCount %u SyncRefreshCount %u"), - stats.PresentCount, stats.PresentRefreshCount, stats.SyncRefreshCount); - drawText(rc, strText); - - LARGE_INTEGER Freq; - QueryPerformanceFrequency(&Freq); - Freq.QuadPart /= 1000; - strText.Format(_T(" SyncQPCTime %dms SyncGPUTime %dms"), - stats.SyncQPCTime.QuadPart / Freq.QuadPart, - stats.SyncGPUTime.QuadPart / Freq.QuadPart); - drawText(rc, strText); - } else { - strText = L"Graphics device does not support present stats"; - drawText(rc, strText); - } - } - } -#endif - - strText.Format(_T("Video size : %ld x %ld (AR = %ld : %ld) Display resolution %ld x %ld "), - m_nativeVideoSize.cx, m_nativeVideoSize.cy, m_aspectRatio.cx, m_aspectRatio.cy, - m_ScreenSize.cx, m_ScreenSize.cy); - drawText(rc, strText); - - if (r.m_AdvRendSets.bSynchronizeDisplay || r.m_AdvRendSets.bSynchronizeVideo) { - if (r.m_AdvRendSets.bSynchronizeDisplay && !m_pGenlock->PowerstripRunning()) { - strText = _T("Sync error : PowerStrip is not running. No display sync is possible."); - drawText(rc, strText); - } else { - strText.Format(_T("Sync adjust : %d | # of adjustments: %u"), - m_pGenlock->adjDelta, - (m_pGenlock->clockAdjustmentsMade + m_pGenlock->displayAdjustmentsMade) / 2); - drawText(rc, strText); - } - } - } - - strText.Format(_T("Sync offset : Average %3.1f ms [%.1f ms, %.1f ms] Target %3.1f ms"), - m_pGenlock->syncOffsetAvg, m_pGenlock->minSyncOffset, - m_pGenlock->maxSyncOffset, r.m_AdvRendSets.fTargetSyncOffset); - drawText(rc, strText); - - strText.Format(_T("Sync status : glitches %u, display-frame cycle mismatch: %7.3f %%, dropped frames %u"), - m_uSyncGlitches, 100 * m_dCycleDifference, m_pcFramesDropped); - drawText(rc, strText); - - if (rd->m_iDisplayStats == 1) { - if (m_pAudioStats && r.m_AdvRendSets.bSynchronizeVideo) { - strText.Format(_T("Audio lag : %3lu ms [%ld ms, %ld ms] | %s"), - m_lAudioLag, m_lAudioLagMin, m_lAudioLagMax, - (m_lAudioSlaveMode == 4) ? - _T("Audio renderer is matching rate (for analog sound output)") : - _T("Audio renderer is not matching rate")); - drawText(rc, strText); - } - - strText.Format(_T("Sample time : waiting %3ld ms"), m_lNextSampleWait); - if (r.m_AdvRendSets.bSynchronizeNearest) { - CString temp; - temp.Format(_T(" paint time correction: %3ld ms Hysteresis: %I64d"), - m_lShiftToNearest, m_llHysteresis / 10000); - strText += temp; - } - drawText(rc, strText); - - strText.Format(_T("Buffering : Buffered %3ld Free %3ld Current Surface %3d"), - m_nUsedBuffer, m_nDXSurface - m_nUsedBuffer, m_nCurSurface); - drawText(rc, strText); - - strText = _T("Settings : "); - - if (m_bIsFullscreen) { - strText += _T("D3DFS "); - } - if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { - strText += _T("DisDC "); - } - if (r.m_AdvRendSets.bSynchronizeVideo) { - strText += _T("SyncVideo "); - } - if (r.m_AdvRendSets.bSynchronizeDisplay) { - strText += _T("SyncDisplay "); - } - if (r.m_AdvRendSets.bSynchronizeNearest) { - strText += _T("SyncNearest "); - } - if (m_bHighColorResolution) { - strText += _T("10 bit "); - } - if (r.m_AdvRendSets.iEVROutputRange == 0) { - strText += _T("0-255 "); - } else if (r.m_AdvRendSets.iEVROutputRange == 1) { - strText += _T("16-235 "); - } - - drawText(rc, strText); - drawText(rc, rd->m_strDXVAInfo); - - strText.Format(L"DirectX SDK : %u", rd->GetDXSdkRelease()); - drawText(rc, strText); - - for (int i = 0; i < 6; i++) { - if (m_strStatsMsg[i][0]) { - drawText(rc, m_strStatsMsg[i]); - } - } - } - m_pSprite->End(); - } - - if (m_pLine && (rd->m_iDisplayStats < 3)) { - D3DXVECTOR2 points[NB_JITTER]; - const float graphWidth = GRAPH_WIDTH * textScale; - const float graphHeight = GRAPH_HEIGHT * textScale; - const float topLeftX = m_windowRect.Width() - (graphWidth + lineHeight); - const float topLeftY = m_windowRect.Height() - (graphHeight + lineHeight); - const float gridStepY = graphHeight / 24.0f; - const float gridStepX = graphWidth / NB_JITTER; - - // Draw background - DrawRect(RGB(0, 0, 0), 80, CRect(int(topLeftX), - int(topLeftY), - int(topLeftX + graphWidth), - int(topLeftY + graphHeight))); - - m_pLine->SetWidth(2.5f * textScale); - m_pLine->SetAntialias(TRUE); - m_pLine->Begin(); - - // Draw grid lines - for (int i = 1; i < 24; ++i) { - points[0].x = topLeftX; - points[0].y = topLeftY + i * gridStepY; - points[1].y = points[0].y; - - float lineLength; - D3DCOLOR color; - if (i % 12 == 0) { - lineLength = 1.0f; - color = D3DCOLOR_XRGB(100, 100, 255); - } else if (i % 4 == 0) { - lineLength = 0.96f; - color = D3DCOLOR_XRGB(100, 100, 180); - } else { - lineLength = 0.04f; - color = D3DCOLOR_XRGB(100, 100, 140); - } - points[1].x = topLeftX + graphWidth * lineLength; - m_pLine->Draw(points, 2, color); - } - - // Draw jitter - for (int i = 1; i <= NB_JITTER; ++i) { - int nIndex = (m_nNextJitter + i) % NB_JITTER; - if (nIndex < 0) { - nIndex += NB_JITTER; - ASSERT(FALSE); - } - float jitter = float(m_pllJitter[nIndex] - m_fJitterMean); - points[i - 1].x = topLeftX + i * gridStepX; - points[i - 1].y = topLeftY + (jitter * textScale / 2000.0f + graphHeight / 2.0f); - } - m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100)); - - if (rd->m_iDisplayStats == 1) { // Full on-screen statistics - // Draw sync offset - for (int i = 1; i <= NB_JITTER; ++i) { - int nIndex = (m_nNextSyncOffset + i) % NB_JITTER; - if (nIndex < 0) { - nIndex += NB_JITTER; - } - points[i - 1].x = topLeftX + i * gridStepX; - points[i - 1].y = topLeftY + (m_pllSyncOffset[nIndex] * textScale / 2000.0f + graphHeight / 2.0f); - } - m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100)); - } - m_pLine->End(); - } -} - -double CBaseAP::GetRefreshRate() -{ - if (m_pGenlock->powerstripTimingExists) { - return m_pGenlock->curDisplayFreq; - } else { - return (double)m_refreshRate; - } -} - -double CBaseAP::GetDisplayCycle() -{ - if (m_pGenlock->powerstripTimingExists) { - return 1000.0 / m_pGenlock->curDisplayFreq; - } else { - return (double)m_dD3DRefreshCycle; - } -} - -double CBaseAP::GetCycleDifference() -{ - double dBaseDisplayCycle = GetDisplayCycle(); - double minDiff = 1.0; - if (dBaseDisplayCycle == 0.0 || m_dFrameCycle == 0.0) { - return 1.0; - } else { - for (UINT i = 1; i <= 8; i++) { // Try a lot of multiples of the display frequency - double dDisplayCycle = i * dBaseDisplayCycle; - double diff = (dDisplayCycle - m_dFrameCycle) / m_dFrameCycle; - if (abs(diff) < abs(minDiff)) { - minDiff = diff; - m_dOptimumDisplayCycle = dDisplayCycle; - } - } - } - return minDiff; -} - -void CBaseAP::EstimateRefreshTimings() -{ - if (m_pD3DDev) { - const CRenderersData* rd = GetRenderersData(); - D3DRASTER_STATUS rasterStatus; - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - while (rasterStatus.ScanLine != 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - while (rasterStatus.ScanLine == 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - LONGLONG startTime = rd->GetPerfCounter(); - UINT startLine = rasterStatus.ScanLine; - LONGLONG endTime = 0; - UINT endLine = 0; - bool done = false; - while (!done) { // Estimate time for one scan line - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - UINT line = rasterStatus.ScanLine; - LONGLONG time = rd->GetPerfCounter(); - if (line > 0) { - endLine = line; - endTime = time; - } else { - done = true; - } - } - m_dDetectedScanlineTime = (endTime - startTime) / ((endLine - startLine) * 10000.0); - - // Estimate the display refresh rate from the vsyncs - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - while (rasterStatus.ScanLine != 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - // Now we're at the start of a vsync - startTime = rd->GetPerfCounter(); - UINT i; - for (i = 1; i <= 50; i++) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - while (rasterStatus.ScanLine == 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - while (rasterStatus.ScanLine != 0) { - m_pD3DDev->GetRasterStatus(0, &rasterStatus); - } - // Now we're at the next vsync - } - endTime = rd->GetPerfCounter(); - m_dEstRefreshCycle = (endTime - startTime) / ((i - 1) * 10000.0); - } -} - -bool CBaseAP::ExtractInterlaced(const AM_MEDIA_TYPE* pmt) -{ - if (pmt->formattype == FORMAT_VideoInfo) { - return false; - } else if (pmt->formattype == FORMAT_VideoInfo2) { - return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; - } else if (pmt->formattype == FORMAT_MPEGVideo) { - return false; - } else if (pmt->formattype == FORMAT_MPEG2Video) { - return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; - } else { - return false; - } -} - -HRESULT CBaseAP::Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect) { - HRESULT hr = E_FAIL; - - const CRenderersSettings& r = GetRenderersSettings(); - - DWORD iDX9Resizer = r.iDX9Resizer; - Vector dst[4]; - Transform(destRect, dst); - - if (iDX9Resizer == 0 || iDX9Resizer == 1) { - D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; - hr = TextureResize(pTexture, dst, Filter, srcRect); - } else if (iDX9Resizer == 2) { - hr = TextureResizeBilinear(pTexture, dst, srcRect); - } else if (iDX9Resizer >= 3) { - hr = TextureResizeBicubic1pass(pTexture, dst, srcRect); - } - - return hr; -} - -STDMETHODIMP CBaseAP::GetDIB(BYTE* lpDib, DWORD* size) -{ - CheckPointer(size, E_POINTER); - - // Keep a reference so that we can safely work on the surface - // without having to lock everything - CComPtr pVideoSurface; - { - CAutoLock cAutoLock(this); - CheckPointer(m_pVideoSurface[m_nCurSurface], E_FAIL); - pVideoSurface = m_pVideoSurface[m_nCurSurface]; - } - - HRESULT hr; - - D3DSURFACE_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - if (FAILED(hr = pVideoSurface->GetDesc(&desc))) { - return hr; - } - - CSize framesize = GetVideoSize(false); - const CSize dar = GetVideoSize(true); - - bool resize = false; - if (dar.cx > 0 && dar.cy > 0 && (dar.cx != desc.Width || dar.cy != desc.Height)) { - framesize.cx = MulDiv(framesize.cy, dar.cx, dar.cy); - resize = true; - desc.Width = framesize.cx; - desc.Height = framesize.cy; - } - - DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3); - if (!lpDib) { - *size = required; - return S_OK; - } - if (*size < required) { - return E_OUTOFMEMORY; - } - *size = required; - - CComPtr pSurface, tSurface; - // Convert to 8-bit when using 10-bit or full/half processing modes - if (desc.Format != D3DFMT_X8R8G8B8) { - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tSurface, nullptr)) - || FAILED(hr = m_pD3DXLoadSurfaceFromSurface(tSurface, nullptr, nullptr, pVideoSurface, nullptr, nullptr, D3DX_DEFAULT, 0))) { - return hr; - } - } else { - tSurface = pVideoSurface; - } - - if (resize) { - CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; - if (FAILED(hr = m_pD3DDevEx->CreateRenderTarget(framesize.cx, framesize.cy, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurface, nullptr)) - || FAILED(hr = m_pD3DDevEx->SetRenderTarget(0, pSurface)) - || FAILED(hr = Resize(pVideoTexture, { CPoint(0, 0), m_nativeVideoSize }, { CPoint(0, 0), framesize }))) { - return hr; - } - } else { - pSurface = tSurface; - } - - D3DLOCKED_RECT r; - if (FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { - // If this fails, we try to use a surface allocated from the system memory - CComPtr pInputSurface = pSurface; - pSurface = nullptr; - if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, nullptr)) - || FAILED(hr = m_pD3DDev->GetRenderTargetData(pInputSurface, pSurface)) - || FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { - return hr; - } - } - - hr = CreateDIBFromSurfaceData(desc, r, lpDib); - - pSurface->UnlockRect(); - - return hr; -} - -STDMETHODIMP CBaseAP::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) -{ - return SetPixelShader2(pSrcData, pTarget, false); -} - -STDMETHODIMP CBaseAP::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) -{ - CAutoLock cRenderLock(&m_allocatorLock); - - CAtlList* pPixelShaders; - if (bScreenSpace) { - pPixelShaders = &m_pPixelShadersScreenSpace; - } else { - pPixelShaders = &m_pPixelShaders; - } - - if (!pSrcData && !pTarget) { - pPixelShaders->RemoveAll(); - m_pD3DDev->SetPixelShader(nullptr); - return S_OK; - } - - if (!pSrcData) { - return E_INVALIDARG; - } - - CExternalPixelShader Shader; - Shader.m_SourceData = pSrcData; - Shader.m_SourceTarget = pTarget; - - CComPtr pPixelShader; - - HRESULT hr = Shader.Compile(m_pPSC); - if (FAILED(hr)) { - return hr; - } - - pPixelShaders->AddTail(Shader); - Paint(true); - return S_OK; -} - -CSyncAP::CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) - : CBaseAP(hWnd, bFullscreen, hr, _Error) - , m_LastClockState(MFCLOCK_STATE_INVALID) - , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture) - , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0) - , m_BorderColor(RGB(0, 0, 0)) - , m_hEvtQuit(nullptr) - , m_bEvtQuit(0) - , m_hEvtFlush(nullptr) - , m_bEvtFlush(0) - , m_hEvtSkip(nullptr) - , m_bEvtSkip(false) - , m_bUseInternalTimer(false) - , m_LastSetOutputRange(-1) - , m_bPendingRenegotiate(false) - , m_bPendingMediaFinished(false) - , m_bPrerolled(false) - , m_hRenderThread(nullptr) - , m_hMixerThread(nullptr) - , m_nRenderState(Shutdown) - , m_bStepping(false) - , m_nCurrentGroupId(0) - , m_nResetToken(0) - , m_nStepCount(0) - , m_SampleFreeCallback(this, &CSyncAP::OnSampleFree) - , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9") - , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer") - , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface") - , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType") - , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW") - , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority") - , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics") -{ - const CRenderersSettings& r = GetRenderersSettings(); - - if (FAILED(hr)) { - _Error += L"SyncAP failed\n"; - return; - } - - if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) { - if (!fnDXVA2CreateDirect3DDeviceManager9) { - _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n"; - } - if (!fnMFCreateDXSurfaceBuffer) { - _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n"; - } - if (!fnMFCreateVideoSampleFromSurface) { - _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n"; - } - if (!fnMFCreateMediaType) { - _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n"; - } - hr = E_FAIL; - return; - } - - // Init DXVA manager - hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager); - if (SUCCEEDED(hr) && m_pD3DManager) { - hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); - if (FAILED(hr)) { - _Error += L"m_pD3DManager->ResetDevice failed\n"; - } - } else { - _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n"; - } - - // Bufferize frame only with 3D texture - if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { - m_nDXSurface = std::max(std::min(r.iEvrBuffers, MAX_PICTURE_SLOTS - 2), 4); - } else { - m_nDXSurface = 1; - } - - m_pOuterEVR = nullptr; - m_lShiftToNearest = -1; // Illegal value to start with -} - -CSyncAP::~CSyncAP() -{ - StopWorkerThreads(); - m_pMediaType = nullptr; - m_pClock = nullptr; - m_pD3DManager = nullptr; - - if (m_bHookedNewSegment) { - UnhookNewSegment(); - } -} - -HRESULT CSyncAP::CheckShutdown() const -{ - if (m_nRenderState == Shutdown) { - return MF_E_SHUTDOWN; - } else { - return S_OK; - } -} - -void CSyncAP::StartWorkerThreads() -{ - DWORD dwThreadId; - if (m_nRenderState == Shutdown) { - m_hEvtQuit = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hEvtFlush = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hEvtSkip = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hMixerThread = ::CreateThread(nullptr, 0, MixerThreadStatic, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hMixerThread, THREAD_PRIORITY_HIGHEST); - m_hRenderThread = ::CreateThread(nullptr, 0, RenderThreadStatic, (LPVOID)this, 0, &dwThreadId); - SetThreadPriority(m_hRenderThread, THREAD_PRIORITY_TIME_CRITICAL); - m_nRenderState = Stopped; - } -} - -void CSyncAP::StopWorkerThreads() -{ - if (m_nRenderState != Shutdown) { - SetEvent(m_hEvtFlush); - m_bEvtFlush = true; - SetEvent(m_hEvtQuit); - m_bEvtQuit = true; - SetEvent(m_hEvtSkip); - m_bEvtSkip = true; - - if (m_hRenderThread && WaitForSingleObject(m_hRenderThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hRenderThread, 0xDEAD); - } - - SAFE_CLOSE_HANDLE(m_hRenderThread); - - if (m_hMixerThread && WaitForSingleObject(m_hMixerThread, 10000) == WAIT_TIMEOUT) { - ASSERT(FALSE); - TerminateThread(m_hMixerThread, 0xDEAD); - } - - SAFE_CLOSE_HANDLE(m_hMixerThread); - SAFE_CLOSE_HANDLE(m_hEvtFlush); - SAFE_CLOSE_HANDLE(m_hEvtQuit); - SAFE_CLOSE_HANDLE(m_hEvtSkip); - - m_bEvtFlush = false; - m_bEvtQuit = false; - m_bEvtSkip = false; - } - m_nRenderState = Shutdown; -} - -STDMETHODIMP CSyncAP::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - *ppRenderer = nullptr; - HRESULT hr = E_FAIL; - - do { - CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; - - CSyncRenderer* pOuterEVR = DEBUG_NEW CSyncRenderer(NAME("CSyncRenderer"), pUnk, hr, &m_VMR9AlphaBitmap, this); - m_pOuterEVR = pOuterEVR; - - pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR); - CComQIPtr pBF = pUnk; - - if (FAILED(hr)) { - break; - } - - // Set EVR custom presenter - CComPtr pVP; - CComPtr pMFVR; - CComQIPtr pMFGS = pBF; - CComQIPtr pConfig = pBF; - if (SUCCEEDED(hr)) { - if (FAILED(pConfig->SetNumberOfStreams(3))) { // TODO - maybe need other number of input stream ... - break; - } - } - - hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVR)); - - if (SUCCEEDED(hr)) { - hr = QueryInterface(IID_PPV_ARGS(&pVP)); - } - if (SUCCEEDED(hr)) { - hr = pMFVR->InitializeRenderer(nullptr, pVP); - } - - if (SUCCEEDED(hr)) { - CComPtr pPin = GetFirstPin(pBF); - if (HookNewSegment((IPinC*)(IPin*)pPin)) { - m_bUseInternalTimer = true; - m_bHookedNewSegment = true; - } - *ppRenderer = pBF.Detach(); - } else { - *ppRenderer = nullptr; - } - } while (0); - - return hr; -} - -STDMETHODIMP_(bool) CSyncAP::Paint(bool bAll) -{ - return __super::Paint(bAll); -} - -STDMETHODIMP_(bool) CSyncAP::Paint(IMFSample* pMFSample) -{ - m_pCurrentlyDisplayedSample = pMFSample; - pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface); - - auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { - UINT32 nGroupId; - return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); - }; - ASSERT(sampleHasCurrentGroupId(pMFSample)); - - return Paint(true); -} - -STDMETHODIMP CSyncAP::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - HRESULT hr; - if (riid == __uuidof(IMFClockStateSink)) { - hr = GetInterface((IMFClockStateSink*)this, ppv); - } else if (riid == __uuidof(IMFVideoPresenter)) { - hr = GetInterface((IMFVideoPresenter*)this, ppv); - } else if (riid == __uuidof(IMFTopologyServiceLookupClient)) { - hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv); - } else if (riid == __uuidof(IMFVideoDeviceID)) { - hr = GetInterface((IMFVideoDeviceID*)this, ppv); - } else if (riid == __uuidof(IMFGetService)) { - hr = GetInterface((IMFGetService*)this, ppv); - } else if (riid == __uuidof(IMFAsyncCallback)) { - hr = GetInterface((IMFAsyncCallback*)this, ppv); - } else if (riid == __uuidof(IMFVideoDisplayControl)) { - hr = GetInterface((IMFVideoDisplayControl*)this, ppv); - } else if (riid == __uuidof(IEVRTrustedVideoPlugin)) { - hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv); - } else if (riid == IID_IQualProp) { - hr = GetInterface((IQualProp*)this, ppv); - } else if (riid == __uuidof(IMFRateSupport)) { - hr = GetInterface((IMFRateSupport*)this, ppv); - } else if (riid == __uuidof(IDirect3DDeviceManager9)) { - hr = m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppv); - } else if (riid == __uuidof(ISyncClockAdviser)) { - hr = GetInterface((ISyncClockAdviser*)this, ppv); - } else if (riid == __uuidof(ID3DFullscreenControl)) { - hr = GetInterface((ID3DFullscreenControl*)this, ppv); - } else { - hr = __super::NonDelegatingQueryInterface(riid, ppv); - } - - return hr; -} - -// IMFClockStateSink -STDMETHODIMP CSyncAP::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - m_nRenderState = Started; - return S_OK; -} - -STDMETHODIMP CSyncAP::OnClockStop(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - m_nRenderState = Stopped; - return S_OK; -} - -STDMETHODIMP CSyncAP::OnClockPause(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - m_nRenderState = Paused; - return S_OK; -} - -STDMETHODIMP CSyncAP::OnClockRestart(MFTIME hnsSystemTime) -{ - HRESULT hr; - CHECK_HR(CheckShutdown()); - m_nRenderState = Started; - return S_OK; -} - -STDMETHODIMP CSyncAP::OnClockSetRate(MFTIME hnsSystemTime, float flRate) -{ - return E_NOTIMPL; -} - -// IBaseFilter delegate -bool CSyncAP::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue) -{ - CAutoLock lock(&m_SampleQueueLock); - switch (m_nRenderState) { - case Started: - *State = State_Running; - break; - case Paused: - *State = State_Paused; - break; - case Stopped: - *State = State_Stopped; - break; - default: - *State = State_Stopped; - _ReturnValue = E_FAIL; - } - _ReturnValue = S_OK; - return true; -} - -// IQualProp -STDMETHODIMP CSyncAP::get_FramesDroppedInRenderer(int* pcFrames) -{ - *pcFrames = m_pcFramesDropped; - return S_OK; -} - -STDMETHODIMP CSyncAP::get_FramesDrawn(int* pcFramesDrawn) -{ - *pcFramesDrawn = m_pcFramesDrawn; - return S_OK; -} - -STDMETHODIMP CSyncAP::get_AvgFrameRate(int* piAvgFrameRate) -{ - *piAvgFrameRate = (int)(m_fAvrFps * 100); - return S_OK; -} - -STDMETHODIMP CSyncAP::get_Jitter(int* iJitter) -{ - *iJitter = (int)((m_fJitterStdDev / 10000.0) + 0.5); - return S_OK; -} - -STDMETHODIMP CSyncAP::get_AvgSyncOffset(int* piAvg) -{ - *piAvg = (int)((m_fSyncOffsetAvr / 10000.0) + 0.5); - return S_OK; -} - -STDMETHODIMP CSyncAP::get_DevSyncOffset(int* piDev) -{ - *piDev = (int)((m_fSyncOffsetStdDev / 10000.0) + 0.5); - return S_OK; -} - -// IMFRateSupport -STDMETHODIMP CSyncAP::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) -{ - *pflRate = 0; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) -{ - HRESULT hr = S_OK; - float fMaxRate = 0.0f; - - CAutoLock lock(this); - - CheckPointer(pflRate, E_POINTER); - CHECK_HR(CheckShutdown()); - - // Get the maximum forward rate. - fMaxRate = GetMaxRate(fThin); - - // For reverse playback, swap the sign. - if (eDirection == MFRATE_REVERSE) { - fMaxRate = -fMaxRate; - } - - *pflRate = fMaxRate; - return hr; -} - -STDMETHODIMP CSyncAP::IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate) -{ - // fRate can be negative for reverse playback. - // pfNearestSupportedRate can be NULL. - CAutoLock lock(this); - HRESULT hr = S_OK; - float fMaxRate = 0.0f; - float fNearestRate = flRate; // Default. - - CheckPointer(pflNearestSupportedRate, E_POINTER); - CHECK_HR(CheckShutdown()); - - // Find the maximum forward rate. - fMaxRate = GetMaxRate(fThin); - - if (fabsf(flRate) > fMaxRate) { - // The (absolute) requested rate exceeds the maximum rate. - hr = MF_E_UNSUPPORTED_RATE; - - // The nearest supported rate is fMaxRate. - fNearestRate = fMaxRate; - if (flRate < 0) { - // For reverse playback, swap the sign. - fNearestRate = -fNearestRate; - } - } - // Return the nearest supported rate if the caller requested it. - if (pflNearestSupportedRate != nullptr) { - *pflNearestSupportedRate = fNearestRate; - } - return hr; -} - -float CSyncAP::GetMaxRate(BOOL bThin) -{ - float fMaxRate = FLT_MAX; // Default. - UINT32 fpsNumerator = 0, fpsDenominator = 0; - - if (!bThin && m_pMediaType) { - // Non-thinned: Use the frame rate and monitor refresh rate. - - // Frame rate: - MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE, - &fpsNumerator, &fpsDenominator); - - // Monitor refresh rate: - UINT MonitorRateHz = m_refreshRate; // D3DDISPLAYMODE - - if (fpsDenominator && fpsNumerator && MonitorRateHz) { - // Max Rate = Refresh Rate / Frame Rate - fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator); - } - } - return fMaxRate; -} - -void CSyncAP::CompleteFrameStep(bool bCancel) -{ - if (m_nStepCount > 0) { - if (bCancel || (m_nStepCount == 1)) { - m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0); - m_nStepCount = 0; - } else { - m_nStepCount--; - } - } -} - -// IMFVideoPresenter -STDMETHODIMP CSyncAP::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) -{ - HRESULT hr = S_OK; - CHECK_HR(CheckShutdown()); - - switch (eMessage) { - case MFVP_MESSAGE_BEGINSTREAMING: - hr = BeginStreaming(); - m_llHysteresis = 0; - m_lShiftToNearest = 0; - m_bStepping = false; - break; - - case MFVP_MESSAGE_CANCELSTEP: - m_bStepping = false; - CompleteFrameStep(true); - break; - - case MFVP_MESSAGE_ENDOFSTREAM: - m_bPendingMediaFinished = true; - break; - - case MFVP_MESSAGE_ENDSTREAMING: - m_pGenlock->ResetTiming(); - m_pRefClock = nullptr; - m_nRenderState = Stopped; - break; - - case MFVP_MESSAGE_FLUSH: - SetEvent(m_hEvtFlush); - m_bEvtFlush = true; - while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0) { - ; - } - break; - - case MFVP_MESSAGE_INVALIDATEMEDIATYPE: - m_bPendingRenegotiate = true; - while (m_bPendingRenegotiate) { - Sleep(1); - } - break; - - case MFVP_MESSAGE_PROCESSINPUTNOTIFY: - break; - - case MFVP_MESSAGE_STEP: - m_nStepCount = (int)ulParam; - m_bStepping = true; - break; - - default: - ASSERT(FALSE); - break; - } - return hr; -} - -HRESULT CSyncAP::IsMediaTypeSupported(IMFMediaType* pMixerType) -{ - HRESULT hr; - AM_MEDIA_TYPE* pAMMedia; - UINT nInterlaceMode; - - CHECK_HR(pMixerType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); - CHECK_HR(pMixerType->GetUINT32(MF_MT_INTERLACE_MODE, &nInterlaceMode)); - - if ((pAMMedia->majortype != MEDIATYPE_Video)) { - hr = MF_E_INVALIDMEDIATYPE; - } - pMixerType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); - return hr; -} - -HRESULT CSyncAP::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType) -{ - HRESULT hr; - IMFMediaType* pOptimalMediaType; - - CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType)); - CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType)); - - const GUID colorAttributes[] = { - MF_MT_VIDEO_LIGHTING, - MF_MT_VIDEO_PRIMARIES, - MF_MT_TRANSFER_FUNCTION, - MF_MT_YUV_MATRIX, - MF_MT_VIDEO_CHROMA_SITING - }; - - auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) { - PROPVARIANT val; - HRESULT hr = pFrom->GetItem(guidKey, &val); - - if (SUCCEEDED(hr)) { - hr = pTo->SetItem(guidKey, val); - PropVariantClear(&val); - } else if (hr == MF_E_ATTRIBUTENOTFOUND) { - hr = pTo->DeleteItem(guidKey); - } - return hr; - }; - - for (REFGUID guidKey : colorAttributes) { - if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) { - TRACE(_T("Copying color attribute %s failed: 0x%08x\n"), static_cast(CComBSTR(guidKey)), hr); - } - } - - pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0); - - const CRenderersSettings& r = GetRenderersSettings(); - - UINT32 nominalRange; - if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)) - && nominalRange == MFNominalRange_0_255) { - // EVR mixer always assumes 16-235 input. Bug? - // To keep untouched 0-255 range and avoid unwanted expansion we need to request 16-235 as output. - // To get 16-235 output we need to request 48-208 as output. - nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_48_208 : MFNominalRange_16_235; - } else { - nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255; - } - pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange); - m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange; - - ULARGE_INTEGER ui64Size; - pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart); - - CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart); - MFVideoArea Area = GetArea(0, 0, videoSize.cx, videoSize.cy); - pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea)); - - ULARGE_INTEGER ui64AspectRatio; - pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart); - - UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart; - UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart; - UINT64 gcd = GCD(ui64ARx, ui64ARy); - if (gcd > 1) { - ui64ARx /= gcd; - ui64ARy /= gcd; - } - CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy); - - if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) { - SetVideoSize(videoSize, aspectRatio); - - // Notify the graph about the change - if (m_pSink) { - m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_nativeVideoSize.cx, m_nativeVideoSize.cy), 0); - } - } - - *ppType = pOptimalMediaType; - (*ppType)->AddRef(); - - return hr; -} - -HRESULT CSyncAP::SetMediaType(IMFMediaType* pType) -{ - HRESULT hr = S_OK; - AM_MEDIA_TYPE* pAMMedia = nullptr; - CString strTemp; - - CHECK_HR(CheckShutdown()); - - if (pType == nullptr) { - // Release - RemoveAllSamples(); - DeleteSurfaces(); - CAutoLock lock(this); - m_pMediaType = nullptr; - return hr; - } - - DWORD dwFlags = 0; - if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) { - // Nothing to do - return hr; - } - - CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); - - hr = InitializeDevice(pAMMedia); - if (SUCCEEDED(hr)) { - CAutoLock lock(this); - m_pMediaType = pType; - - strTemp = GetMediaTypeName(pAMMedia->subtype); - strTemp.Replace(L"MEDIASUBTYPE_", L""); - m_strStatsMsg[MSG_MIXEROUT].Format(L"Mixer output : %s", strTemp.GetString()); - } - - pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); - - return hr; -} - -LONGLONG CSyncAP::GetMediaTypeMerit(IMFMediaType* pMediaType) -{ - AM_MEDIA_TYPE* pAMMedia = nullptr; - MFVIDEOFORMAT* VideoFormat; - - HRESULT hr; - CHECK_HR(pMediaType->GetRepresentation(FORMAT_MFVideoFormat, (void**)&pAMMedia)); - VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat; - - LONGLONG Merit = 0; - switch (VideoFormat->surfaceInfo.Format) { - case FCC('NV12'): - Merit = 90000000; - break; - case FCC('YV12'): - Merit = 80000000; - break; - case FCC('YUY2'): - Merit = 70000000; - break; - case FCC('UYVY'): - Merit = 60000000; - break; - - case D3DFMT_X8R8G8B8: // Never opt for RGB - case D3DFMT_A8R8G8B8: - case D3DFMT_R8G8B8: - case D3DFMT_R5G6B5: - Merit = 0; - break; - default: - Merit = 1000; - break; - } - pMediaType->FreeRepresentation(FORMAT_MFVideoFormat, (void*)pAMMedia); - return Merit; -} - -HRESULT CSyncAP::RenegotiateMediaType() -{ - HRESULT hr = S_OK; - - CComPtr pMixerType; - CComPtr pMixerInputType; - CComPtr pType; - - if (!m_pMixer) { - return MF_E_INVALIDREQUEST; - } - - // Get the mixer's input type - hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType); - if (SUCCEEDED(hr)) { - AM_MEDIA_TYPE* pMT; - hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT); - if (SUCCEEDED(hr)) { - m_inputMediaType = *pMT; - pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT); - } - } - - CInterfaceArray ValidMixerTypes; - // Loop through all of the mixer's proposed output types. - DWORD iTypeIndex = 0; - while ((hr != MF_E_NO_MORE_TYPES)) { - pMixerType = nullptr; - pType = nullptr; - - // Step 1. Get the next media type supported by mixer. - hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType); - if (FAILED(hr)) { - break; - } - // Step 2. Check if we support this media type. - if (SUCCEEDED(hr)) { - hr = IsMediaTypeSupported(pMixerType); - } - if (SUCCEEDED(hr)) { - hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType); - } - // Step 4. Check if the mixer will accept this media type. - if (SUCCEEDED(hr)) { - hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY); - } - if (SUCCEEDED(hr)) { - LONGLONG Merit = GetMediaTypeMerit(pType); - - size_t nTypes = ValidMixerTypes.GetCount(); - size_t iInsertPos = 0; - for (size_t i = 0; i < nTypes; ++i) { - LONGLONG ThisMerit = GetMediaTypeMerit(ValidMixerTypes[i]); - if (Merit > ThisMerit) { - iInsertPos = i; - break; - } else { - iInsertPos = i + 1; - } - } - ValidMixerTypes.InsertAt(iInsertPos, pType); - } - } - - size_t nValidTypes = ValidMixerTypes.GetCount(); - for (size_t i = 0; i < nValidTypes; ++i) { - pType = ValidMixerTypes[i]; - } - - for (size_t i = 0; i < nValidTypes; ++i) { - pType = ValidMixerTypes[i]; - hr = SetMediaType(pType); - if (SUCCEEDED(hr)) { - hr = m_pMixer->SetOutputType(0, pType, 0); - // If something went wrong, clear the media type. - if (FAILED(hr)) { - SetMediaType(nullptr); - } else { - break; - } - } - } - - pMixerType = nullptr; - pType = nullptr; - return hr; -} - -bool CSyncAP::GetSampleFromMixer() -{ - MFT_OUTPUT_DATA_BUFFER dataBuffer; - HRESULT hr = S_OK; - DWORD dwStatus; - LONGLONG llClockBefore = 0; - LONGLONG llClockAfter = 0; - LONGLONG llMixerLatency; - - UINT dwSurface; - bool newSample = false; - - auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { - UINT32 nGroupId; - return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); - }; - - while (SUCCEEDED(hr)) { // Get as many frames as there are and that we have samples for - CComPtr pSample; - if (FAILED(GetFreeSample(&pSample))) { // All samples are taken for the moment. Better luck next time - break; - } - - ZeroMemory(&dataBuffer, sizeof(dataBuffer)); - dataBuffer.pSample = pSample; - pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface); - ASSERT(sampleHasCurrentGroupId(pSample)); - - { - llClockBefore = GetRenderersData()->GetPerfCounter(); - hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus); - llClockAfter = GetRenderersData()->GetPerfCounter(); - } - - if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { // There are no samples left in the mixer - AddToFreeList(pSample, false); - pSample = nullptr; // The sample should not be used after being queued - // Important: Release any events returned from the ProcessOutput method. - SAFE_RELEASE(dataBuffer.pEvents); - break; - } - - if (m_pSink) { - llMixerLatency = llClockAfter - llClockBefore; - m_pSink->Notify(EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0); - } - - newSample = true; - - if (GetRenderersData()->m_bTearingTest) { - RECT rcTearing; - - rcTearing.left = m_nTearingPos; - rcTearing.top = 0; - rcTearing.right = rcTearing.left + 4; - rcTearing.bottom = m_nativeVideoSize.cy; - m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - - rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; - rcTearing.right = rcTearing.left + 4; - m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; - } - - if (SUCCEEDED(TrackSample(pSample))) { - AddToScheduledList(pSample, false); // Schedule, then go back to see if there is more where that came from - pSample = nullptr; // The sample should not be used after being queued - } else { - ASSERT(FALSE); - } - - // Important: Release any events returned from the ProcessOutput method. - SAFE_RELEASE(dataBuffer.pEvents); - } - return newSample; -} - -STDMETHODIMP CSyncAP::GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType) -{ - HRESULT hr = S_OK; - CAutoLock lock(this); - CheckPointer(ppMediaType, E_POINTER); - CHECK_HR(CheckShutdown()); - - if (!m_pMediaType) { - return MF_E_NOT_INITIALIZED; - } - - CHECK_HR(m_pMediaType->QueryInterface(IID_PPV_ARGS(ppMediaType))); - return hr; -} - -// IMFTopologyServiceLookupClient -STDMETHODIMP CSyncAP::InitServicePointers(__in IMFTopologyServiceLookup* pLookup) -{ - DWORD dwObjects = 1; - pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_pMixer), &dwObjects); - pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pSink), &dwObjects); - pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pClock), &dwObjects); - StartWorkerThreads(); - return S_OK; -} - -STDMETHODIMP CSyncAP::ReleaseServicePointers() -{ - StopWorkerThreads(); - m_pMixer = nullptr; - m_pSink = nullptr; - m_pClock = nullptr; - return S_OK; -} - -// IMFVideoDeviceID -STDMETHODIMP CSyncAP::GetDeviceID(__out IID* pDeviceID) -{ - CheckPointer(pDeviceID, E_POINTER); - *pDeviceID = IID_IDirect3DDevice9; - return S_OK; -} - -// IMFGetService -STDMETHODIMP CSyncAP::GetService(__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppvObject) -{ - if (guidService == MR_VIDEO_RENDER_SERVICE) { - return NonDelegatingQueryInterface(riid, ppvObject); - } else if (guidService == MR_VIDEO_ACCELERATION_SERVICE) { - return m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppvObject); - } - - return E_NOINTERFACE; -} - -// IMFAsyncCallback -STDMETHODIMP CSyncAP::GetParameters(__RPC__out DWORD* pdwFlags, __RPC__out DWORD* pdwQueue) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CSyncAP::Invoke(__RPC__in_opt IMFAsyncResult* pAsyncResult) -{ - return E_NOTIMPL; -} - -// IMFVideoDisplayControl -STDMETHODIMP CSyncAP::GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) -{ - if (pszVideo) { - pszVideo->cx = m_nativeVideoSize.cx; - pszVideo->cy = m_nativeVideoSize.cy; - } - if (pszARVideo) { - pszARVideo->cx = m_aspectRatio.cx; - pszARVideo->cy = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CSyncAP::GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) -{ - if (pszMin) { - pszMin->cx = 1; - pszMin->cy = 1; - } - - if (pszMax) { - D3DDISPLAYMODE d3ddm; - ZeroMemory(&d3ddm, sizeof(d3ddm)); - - if (SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D, m_hWnd), &d3ddm))) { - pszMax->cx = d3ddm.Width; - pszMax->cy = d3ddm.Height; - } - } - return S_OK; -} - -STDMETHODIMP CSyncAP::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) -{ - return S_OK; -} - -STDMETHODIMP CSyncAP::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) -{ - if (pnrcSource) { - pnrcSource->left = 0.0; - pnrcSource->top = 0.0; - pnrcSource->right = 1.0; - pnrcSource->bottom = 1.0; - } - if (prcDest) { - memcpy(prcDest, &m_videoRect, sizeof(m_videoRect)); //GetClientRect (m_hWnd, prcDest); - } - return S_OK; -} - -STDMETHODIMP CSyncAP::SetAspectRatioMode(DWORD dwAspectRatioMode) -{ - m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetAspectRatioMode(DWORD* pdwAspectRatioMode) -{ - CheckPointer(pdwAspectRatioMode, E_POINTER); - *pdwAspectRatioMode = m_dwVideoAspectRatioMode; - return S_OK; -} - -STDMETHODIMP CSyncAP::SetVideoWindow(HWND hwndVideo) -{ - if (m_hWnd != hwndVideo) { - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_allocatorLock); - - m_hWnd = hwndVideo; - m_bPendingResetDevice = true; - if (m_pSink) { - m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); - } - - SendResetRequest(); - } - return S_OK; -} - -STDMETHODIMP CSyncAP::GetVideoWindow(HWND* phwndVideo) -{ - CheckPointer(phwndVideo, E_POINTER); - *phwndVideo = m_hWnd; - return S_OK; -} - -STDMETHODIMP CSyncAP::RepaintVideo() -{ - Paint(true); - return S_OK; -} - -STDMETHODIMP CSyncAP::GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp) { - if (!pBih || !pDib || !pcbDib) { - return E_POINTER; - } - CheckPointer(m_pD3DDevEx, E_ABORT); - - HRESULT hr = S_OK; - const unsigned width = m_windowRect.Width(); - const unsigned height = m_windowRect.Height(); - const unsigned len = width * height * 4; - - memset(pBih, 0, sizeof(BITMAPINFOHEADER)); - pBih->biSize = sizeof(BITMAPINFOHEADER); - pBih->biWidth = width; - pBih->biHeight = height; - pBih->biBitCount = 32; - pBih->biPlanes = 1; - pBih->biSizeImage = DIBSIZE(*pBih); - - BYTE* p = (BYTE*)CoTaskMemAlloc(len); // only this allocator can be used - if (!p) { - return E_OUTOFMEMORY; - } - - CComPtr pBackBuffer; - CComPtr pDestSurface; - D3DLOCKED_RECT r; - if (FAILED(hr = m_pD3DDevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)) - || FAILED(hr = m_pD3DDevEx->CreateRenderTarget(width, height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pDestSurface, nullptr)) - || (FAILED(hr = m_pD3DDevEx->StretchRect(pBackBuffer, m_windowRect, pDestSurface, nullptr, D3DTEXF_NONE))) - || (FAILED(hr = pDestSurface->LockRect(&r, nullptr, D3DLOCK_READONLY)))) { - CString Error = GetWindowsErrorMessage(hr, nullptr); - TRACE_SR(L"CSyncAP::GetCurrentImage failed : %s", S_OK == hr ? L"S_OK" : Error.GetBuffer()); - CoTaskMemFree(p); - return hr; - } - - RetrieveBitmapData(width, height, 32, p ? (BYTE*)p : (BYTE*)(pBih + 1), (BYTE*)r.pBits, r.Pitch); - - pDestSurface->UnlockRect(); - - *pDib = p; - *pcbDib = len; - - return S_OK; -} - -STDMETHODIMP CSyncAP::SetBorderColor(COLORREF Clr) -{ - m_BorderColor = Clr; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetBorderColor(COLORREF* pClr) -{ - CheckPointer(pClr, E_POINTER); - *pClr = m_BorderColor; - return S_OK; -} - -STDMETHODIMP CSyncAP::SetRenderingPrefs(DWORD dwRenderFlags) -{ - m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetRenderingPrefs(DWORD* pdwRenderFlags) -{ - CheckPointer(pdwRenderFlags, E_POINTER); - *pdwRenderFlags = m_dwVideoRenderPrefs; - return S_OK; -} - -STDMETHODIMP CSyncAP::SetFullscreen(BOOL fFullscreen) -{ - m_bIsFullscreen = !!fFullscreen; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetFullscreen(BOOL* pfFullscreen) -{ - CheckPointer(pfFullscreen, E_POINTER); - *pfFullscreen = m_bIsFullscreen; - return S_OK; -} - -// IEVRTrustedVideoPlugin -STDMETHODIMP CSyncAP::IsInTrustedVideoMode(BOOL* pYes) -{ - CheckPointer(pYes, E_POINTER); - *pYes = TRUE; - return S_OK; -} - -STDMETHODIMP CSyncAP::CanConstrict(BOOL* pYes) -{ - CheckPointer(pYes, E_POINTER); - *pYes = TRUE; - return S_OK; -} - -STDMETHODIMP CSyncAP::SetConstriction(DWORD dwKPix) -{ - return S_OK; -} - -STDMETHODIMP CSyncAP::DisableImageExport(BOOL bDisable) -{ - return S_OK; -} - -// IDirect3DDeviceManager9 -STDMETHODIMP CSyncAP::ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken) -{ - HRESULT hr = m_pD3DManager->ResetDevice(pDevice, resetToken); - return hr; -} - -STDMETHODIMP CSyncAP::OpenDeviceHandle(HANDLE* phDevice) -{ - HRESULT hr = m_pD3DManager->OpenDeviceHandle(phDevice); - return hr; -} - -STDMETHODIMP CSyncAP::CloseDeviceHandle(HANDLE hDevice) -{ - HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice); - return hr; -} - -STDMETHODIMP CSyncAP::TestDevice(HANDLE hDevice) -{ - HRESULT hr = m_pD3DManager->TestDevice(hDevice); - return hr; -} - -STDMETHODIMP CSyncAP::LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock) -{ - HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock); - return hr; -} - -STDMETHODIMP CSyncAP::UnlockDevice(HANDLE hDevice, BOOL fSaveState) -{ - HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState); - return hr; -} - -STDMETHODIMP CSyncAP::GetVideoService(HANDLE hDevice, REFIID riid, void** ppService) -{ - HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService); - - if (riid == __uuidof(IDirectXVideoDecoderService)) { - UINT nNbDecoder = 5; - GUID* pDecoderGuid; - IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService; - pDXVAVideoDecoder->GetDecoderDeviceGuids(&nNbDecoder, &pDecoderGuid); - } else if (riid == __uuidof(IDirectXVideoProcessorService)) { - IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService; - UNREFERENCED_PARAMETER(pDXVAProcessor); - } - - return hr; -} - -STDMETHODIMP CSyncAP::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) -{ - // This function should be called... - ASSERT(FALSE); - - if (lpWidth) { - *lpWidth = m_nativeVideoSize.cx; - } - if (lpHeight) { - *lpHeight = m_nativeVideoSize.cy; - } - if (lpARWidth) { - *lpARWidth = m_aspectRatio.cx; - } - if (lpARHeight) { - *lpARHeight = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CSyncAP::InitializeDevice(AM_MEDIA_TYPE* pMediaType) -{ - HRESULT hr; - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_allocatorLock); - - RemoveAllSamples(); - DeleteSurfaces(); - - VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*) pMediaType->pbFormat; - int w = vih2->bmiHeader.biWidth; - int h = abs(vih2->bmiHeader.biHeight); - - SetVideoSize(CSize(w, h), m_aspectRatio); - if (m_bHighColorResolution) { - hr = AllocSurfaces(D3DFMT_A2R10G10B10); - } else { - hr = AllocSurfaces(D3DFMT_X8R8G8B8); - } - - for (int i = 0; i < m_nDXSurface; i++) { - CComPtr pMFSample; - hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); - if (SUCCEEDED(hr)) { - pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); - pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - m_FreeSamples.AddTail(pMFSample); - pMFSample = nullptr; // The sample should not be used after being queued - } - ASSERT(SUCCEEDED(hr)); - } - return hr; -} - -DWORD WINAPI CSyncAP::MixerThreadStatic(LPVOID lpParam) -{ - CSyncAP* pThis = (CSyncAP*) lpParam; - pThis->MixerThread(); - return 0; -} - -void CSyncAP::MixerThread() -{ - HANDLE hEvts[] = {m_hEvtQuit}; - bool bQuit = false; - TIMECAPS tc; - DWORD dwResolution; - - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - timeBeginPeriod(dwResolution); - - while (!bQuit) { - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); - switch (dwObject) { - case WAIT_OBJECT_0: - bQuit = true; - break; - case WAIT_TIMEOUT: { - bool bNewSample; - { - CAutoLock AutoLock(&m_ImageProcessingLock); - bNewSample = GetSampleFromMixer(); - } - - if (m_rtTimePerFrame == 0 && bNewSample) { - // Use the code from VMR9 to get the movie fps, as this method is reliable. - CComPtr pPin; - CMediaType mt; - if (SUCCEEDED(m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) && - SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); - - m_bInterlaced = ExtractInterlaced(&mt); - - if (m_rtTimePerFrame > 0) { - m_fps = 10000000.0 / m_rtTimePerFrame; - } - } - - // Update internal subtitle clock - if (m_bUseInternalTimer && m_pSubPicQueue) { - m_pSubPicQueue->SetFPS(m_fps); - } - } - } - break; - } - } - timeEndPeriod(dwResolution); -} - -DWORD WINAPI CSyncAP::RenderThreadStatic(LPVOID lpParam) -{ - CSyncAP* pThis = (CSyncAP*)lpParam; - pThis->RenderThread(); - return 0; -} - -// Get samples that have been received and queued up by MixerThread() and present them at the correct time by calling Paint(). -void CSyncAP::RenderThread() -{ - HANDLE hEvts[] = {m_hEvtQuit, m_hEvtFlush, m_hEvtSkip}; - bool bQuit = false; - TIMECAPS tc; - CComPtr pNewSample; // The sample next in line to be presented - - // Tell Multimedia Class Scheduler we are doing threaded playback (increase priority) - HANDLE hAvrt = 0; - if (fnAvSetMmThreadCharacteristicsW) { - DWORD dwTaskIndex = 0; - hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); - if (fnAvSetMmThreadPriority) { - fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH); - } - } - - // Set timer resolution - timeGetDevCaps(&tc, sizeof(TIMECAPS)); - DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); - VERIFY(timeBeginPeriod(dwResolution) == 0); - - auto SubPicSetTime = [&] { - if (!g_bExternalSubtitleTime) { - CSubPicAllocatorPresenterImpl::SetTime(g_tSegmentStart + m_llSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); - } - }; - - auto checkPendingMediaFinished = [this]() { - if (m_bPendingMediaFinished) { - CAutoLock lock(&m_SampleQueueLock); - if (m_ScheduledSamples.IsEmpty()) { - m_bPendingMediaFinished = false; - m_pSink->Notify(EC_COMPLETE, 0, 0); - } - } - }; - - while (!bQuit) { - m_lNextSampleWait = 1; // Default value for running this loop - int nSamplesLeft = 0; - bool stepForward = false; - LONG lDisplayCycle = (LONG)(GetDisplayCycle()); - LONG lDisplayCycle2 = (LONG)(GetDisplayCycle() / 2.0); // These are a couple of empirically determined constants used the control the "snap" function - LONG lDisplayCycle4 = (LONG)(GetDisplayCycle() / 4.0); - - const CRenderersSettings& r = GetRenderersSettings(); - double dTargetSyncOffset = (&r == nullptr) ? 12.0 : r.m_AdvRendSets.fTargetSyncOffset; - - if ((m_nRenderState == Started || !m_bPrerolled) && !pNewSample) { // If either streaming or the pre-roll sample and no sample yet fetched - if (SUCCEEDED(GetScheduledSample(&pNewSample, nSamplesLeft))) { // Get the next sample - m_llLastSampleTime = m_llSampleTime; - if (!m_bPrerolled) { - m_bPrerolled = true; // m_bPrerolled is a ticket to show one (1) frame immediately - m_lNextSampleWait = 0; // Present immediately - } else if (SUCCEEDED(pNewSample->GetSampleTime(&m_llSampleTime))) { // Get zero-based sample due time - if (m_llLastSampleTime == m_llSampleTime) { // In the rare case there are duplicate frames in the movie. There really shouldn't be but it happens. - checkPendingMediaFinished(); - pNewSample = nullptr; - m_lNextSampleWait = 0; - } else { - MFTIME llSystemTime; - LONGLONG llRefClockTime; - m_pClock->GetCorrelatedTime(0, &llRefClockTime, &llSystemTime); // Get zero-based reference clock time. llSystemTime is not used for anything here - m_lNextSampleWait = (LONG)((m_llSampleTime - llRefClockTime) / 10000); // Time left until sample is due, in ms - if (m_bStepping) { - m_lNextSampleWait = 0; - } else if (r.m_AdvRendSets.bSynchronizeNearest) { // Present at the closest "safe" occasion at dTargetSyncOffset ms before vsync to avoid tearing - if (m_lNextSampleWait < -lDisplayCycle) { // We have to allow slightly negative numbers at this stage. Otherwise we get "choking" when frame rate > refresh rate - SetEvent(m_hEvtSkip); - m_bEvtSkip = true; - } - REFERENCE_TIME rtRefClockTimeNow = 0; - if (m_pRefClock) { - m_pRefClock->GetTime(&rtRefClockTimeNow); // Reference clock time now - } - LONG lLastVsyncTime = (LONG)((m_llEstVBlankTime - rtRefClockTimeNow) / 10000); // Last vsync time relative to now - if (abs(lLastVsyncTime) > lDisplayCycle) { - lLastVsyncTime = - lDisplayCycle; // To even out glitches in the beginning - } - - LONGLONG llNextSampleWait = (LONGLONG)((lLastVsyncTime + GetDisplayCycle() - dTargetSyncOffset) * 10000); // Time from now util next safe time to Paint() - while ((llRefClockTime + llNextSampleWait) < (m_llSampleTime + m_llHysteresis)) { // While the proposed time is in the past of sample presentation time - llNextSampleWait = llNextSampleWait + (LONGLONG)(GetDisplayCycle() * 10000); // Try the next possible time, one display cycle ahead - } - m_lNextSampleWait = (LONG)(llNextSampleWait / 10000); - m_lShiftToNearestPrev = m_lShiftToNearest; - m_lShiftToNearest = (LONG)((llRefClockTime + llNextSampleWait - m_llSampleTime) / 10000); // The adjustment made to get to the sweet point in time, in ms - - // If m_lShiftToNearest is pushed a whole cycle into the future, then we are getting more frames - // than we can chew and we need to throw one away. We don't want to wait many cycles and skip many - // frames. - if (m_lShiftToNearest > (lDisplayCycle + 1)) { - SetEvent(m_hEvtSkip); - m_bEvtSkip = true; - } - - // We need to add a hysteresis to the control of the timing adjustment to avoid judder when - // presentation time is close to vsync and the renderer couldn't otherwise make up its mind - // whether to present before the vsync or after. That kind of indecisiveness leads to judder. - if (m_bSnapToVSync) { - - if ((m_lShiftToNearestPrev - m_lShiftToNearest) > lDisplayCycle2) { // If a step down in the m_lShiftToNearest function. Display slower than video. - m_bVideoSlowerThanDisplay = false; - m_llHysteresis = -(LONGLONG)lDisplayCycle4 * 10000; - } else if ((m_lShiftToNearest - m_lShiftToNearestPrev) > lDisplayCycle2) { // If a step up - m_bVideoSlowerThanDisplay = true; - m_llHysteresis = (LONGLONG)lDisplayCycle4 * 10000; - } else if ((m_lShiftToNearest < (3 * lDisplayCycle4)) && (m_lShiftToNearest > lDisplayCycle4)) { - m_llHysteresis = 0; // Reset when between 1/4 and 3/4 of the way either way - } - - if ((m_lShiftToNearest < lDisplayCycle2) && (m_llHysteresis > 0)) { - m_llHysteresis = 0; // Should never really be in this territory. - } - if (m_lShiftToNearest < 0) { - m_llHysteresis = 0; // A glitch might get us to a sticky state where both these numbers are negative. - } - if ((m_lShiftToNearest > lDisplayCycle2) && (m_llHysteresis < 0)) { - m_llHysteresis = 0; - } - } - } - - if (m_lNextSampleWait < 0) { // Skip late or duplicate sample. - SetEvent(m_hEvtSkip); - m_bEvtSkip = true; - } - - if (m_lNextSampleWait > 1000) { - m_lNextSampleWait = 1000; // So as to avoid full a full stop when sample is far in the future (shouldn't really happen). - } - } - } // if got new sample - } else { - checkPendingMediaFinished(); - } - } - // Wait for the next presentation time (m_lNextSampleWait) or some other event. - DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, (DWORD)m_lNextSampleWait); - switch (dwObject) { - case WAIT_OBJECT_0: // Quit - bQuit = true; - break; - - case WAIT_OBJECT_0 + 1: // Flush - checkPendingMediaFinished(); - pNewSample = nullptr; - FlushSamples(); - m_bEvtFlush = false; - ResetEvent(m_hEvtFlush); - m_bPrerolled = false; - m_lShiftToNearest = 0; - stepForward = true; - break; - - case WAIT_OBJECT_0 + 2: // Skip sample - m_pcFramesDropped++; - m_llSampleTime = m_llLastSampleTime; // This sample will never be shown - m_bEvtSkip = false; - ResetEvent(m_hEvtSkip); - stepForward = true; - break; - - case WAIT_TIMEOUT: // Time to show the sample or something - if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != r.m_AdvRendSets.iEVROutputRange || m_bPendingRenegotiate) { - checkPendingMediaFinished(); - pNewSample = nullptr; - FlushSamples(); - RenegotiateMediaType(); - m_bPendingRenegotiate = false; - } - - if (m_bPendingResetDevice) { - checkPendingMediaFinished(); - pNewSample = nullptr; - SendResetRequest(); - } else if (m_nStepCount < 0) { - m_nStepCount = 0; - m_pcFramesDropped++; - stepForward = true; - } else if (pNewSample && (m_nStepCount > 0)) { - SubPicSetTime(); - Paint(pNewSample); - CompleteFrameStep(false); - m_pcFramesDrawn++; - stepForward = true; - } else if (pNewSample && !m_bStepping) { // When a stepped frame is shown, a new one is fetched that we don't want to show here while stepping - SubPicSetTime(); - Paint(pNewSample); - m_pcFramesDrawn++; - stepForward = true; - } - break; - } // switch - if (stepForward) { - checkPendingMediaFinished(); - pNewSample = nullptr; - } - } // while - pNewSample = nullptr; - timeEndPeriod(dwResolution); - if (fnAvRevertMmThreadCharacteristics) { - fnAvRevertMmThreadCharacteristics(hAvrt); - } -} - -STDMETHODIMP_(bool) CSyncAP::ResetDevice() -{ - CAutoLock lock(this); - CAutoLock lock2(&m_ImageProcessingLock); - CAutoLock cRenderLock(&m_allocatorLock); - - RemoveAllSamples(); - - bool bResult = __super::ResetDevice(); - - for (int i = 0; i < m_nDXSurface; i++) { - CComPtr pMFSample; - HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); - if (SUCCEEDED(hr)) { - pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); - pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - m_FreeSamples.AddTail(pMFSample); - pMFSample = nullptr; // The sample should not be used after being queued - } - ASSERT(SUCCEEDED(hr)); - } - return bResult; -} - -void CSyncAP::OnResetDevice() -{ - TRACE(_T("--> CSyncAP::OnResetDevice on thread: %lu\n"), GetCurrentThreadId()); - m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); - if (m_pSink) { - m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); - } - CSize videoSize = GetVisibleVideoSize(); - if (m_pSink) { - m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(videoSize.cx, videoSize.cy), 0); - } -} - -void CSyncAP::RemoveAllSamples() -{ - CAutoLock imageProcesssingLock(&m_ImageProcessingLock); - CAutoLock sampleQueueLock(&m_SampleQueueLock); - - FlushSamples(); - m_ScheduledSamples.RemoveAll(); - m_FreeSamples.RemoveAll(); - m_nUsedBuffer = 0; - // Increment the group id to make sure old samples will really be deleted - m_nCurrentGroupId++; -} - -HRESULT CSyncAP::GetFreeSample(IMFSample** ppSample) -{ - CAutoLock lock(&m_SampleQueueLock); - HRESULT hr = S_OK; - - if (!m_FreeSamples.IsEmpty()) { - m_nUsedBuffer++; - *ppSample = m_FreeSamples.RemoveHead().Detach(); - } else { - hr = MF_E_SAMPLEALLOCATOR_EMPTY; - } - - return hr; -} - -HRESULT CSyncAP::GetScheduledSample(IMFSample** ppSample, int& count) -{ - CAutoLock lock(&m_SampleQueueLock); - HRESULT hr = S_OK; - - count = (int)m_ScheduledSamples.GetCount(); - if (count > 0) { - *ppSample = m_ScheduledSamples.RemoveHead().Detach(); - --count; - } else { - hr = MF_E_SAMPLEALLOCATOR_EMPTY; - } - - return hr; -} - -void CSyncAP::AddToFreeList(IMFSample* pSample, bool bTail) -{ - CAutoLock lock(&m_SampleQueueLock); - - m_nUsedBuffer--; - if (bTail) { - m_FreeSamples.AddTail(pSample); - } else { - m_FreeSamples.AddHead(pSample); - } -} - -void CSyncAP::AddToScheduledList(IMFSample* pSample, bool bSorted) -{ - CAutoLock lock(&m_SampleQueueLock); - - if (bSorted) { - m_ScheduledSamples.AddHead(pSample); - } else { - m_ScheduledSamples.AddTail(pSample); - } -} - -void CSyncAP::FlushSamples() -{ - CAutoLock lock(this); - CAutoLock lock2(&m_SampleQueueLock); - - m_bPrerolled = false; - m_pCurrentlyDisplayedSample = nullptr; - m_ScheduledSamples.RemoveAll(); -} - -HRESULT CSyncAP::TrackSample(IMFSample* pSample) -{ - HRESULT hr = E_FAIL; - if (CComQIPtr pTracked = pSample) { - hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr); - } - return hr; -} - -HRESULT CSyncAP::OnSampleFree(IMFAsyncResult* pResult) -{ - CComPtr pObject; - HRESULT hr = pResult->GetObject(&pObject); - if (SUCCEEDED(hr)) { - if (CComQIPtr pSample = pObject) { - // Ignore the sample if it is from an old group - UINT32 nGroupId; - CAutoLock sampleQueueLock(&m_SampleQueueLock); - if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) { - AddToFreeList(pSample, true); - pSample = nullptr; // The sample should not be used after being queued - } - } - } - return hr; -} - -HRESULT CSyncAP::AdviseSyncClock(ISyncClock* sC) -{ - return m_pGenlock->AdviseSyncClock(sC); -} - -HRESULT CSyncAP::BeginStreaming() -{ - m_pcFramesDropped = 0; - m_pcFramesDrawn = 0; - - CComPtr pEVR; - CFilterInfo filterInfo; - m_pOuterEVR->QueryInterface(IID_PPV_ARGS(&pEVR)); - pEVR->QueryFilterInfo(&filterInfo); - - BeginEnumFilters(filterInfo.pGraph, pEF, pBF); - if (CComQIPtr pAS = pBF) { - m_pAudioStats = pAS; - }; - EndEnumFilters; - - pEVR->GetSyncSource(&m_pRefClock); - m_pGenlock->SetMonitor(GetAdapter(m_pD3D, m_hWnd)); - m_pGenlock->GetTiming(); - - ResetStats(); - EstimateRefreshTimings(); - if (m_dFrameCycle > 0.0) { - m_dCycleDifference = GetCycleDifference(); // Might have moved to another display - } - - m_nRenderState = Paused; - - return S_OK; -} - -HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP) -{ - HRESULT hr = E_FAIL; - if (clsid == CLSID_SyncAllocatorPresenter) { - CString Error; - *ppAP = DEBUG_NEW CSyncAP(hWnd, bFullscreen, hr, Error); - (*ppAP)->AddRef(); - - if (FAILED(hr)) { - Error += L"\n"; - Error += GetWindowsErrorMessage(hr, nullptr); - MessageBox(hWnd, Error, L"Error creating EVR Sync", MB_OK | MB_ICONERROR); - (*ppAP)->Release(); - *ppAP = nullptr; - } else if (!Error.IsEmpty()) { - MessageBox(hWnd, Error, L"Warning creating EVR Sync", MB_OK | MB_ICONWARNING); - } - } - return hr; -} - -CSyncRenderer::CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP* pAllocatorPresenter): CUnknown(pName, pUnk) -{ - hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner()); - CComQIPtr pEVRBase = m_pEVR; - m_pEVRBase = pEVRBase; // Don't keep a second reference on the EVR filter - m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; - m_pAllocatorPresenter = pAllocatorPresenter; -} - -CSyncRenderer::~CSyncRenderer() -{ -} - -HRESULT STDMETHODCALLTYPE CSyncRenderer::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetState(dwMilliSecsTimeout, State); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::EnumPins(__out IEnumPins** ppEnum) -{ - if (m_pEVRBase) { - return m_pEVRBase->EnumPins(ppEnum); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::FindPin(LPCWSTR Id, __out IPin** ppPin) -{ - if (m_pEVRBase) { - return m_pEVRBase->FindPin(Id, ppPin); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::QueryFilterInfo(__out FILTER_INFO* pInfo) -{ - if (m_pEVRBase) { - return m_pEVRBase->QueryFilterInfo(pInfo); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName) -{ - if (m_pEVRBase) { - return m_pEVRBase->JoinFilterGraph(pGraph, pName); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::QueryVendorInfo(__out LPWSTR* pVendorInfo) -{ - if (m_pEVRBase) { - return m_pEVRBase->QueryVendorInfo(pVendorInfo); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::Stop() -{ - if (m_pEVRBase) { - return m_pEVRBase->Stop(); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::Pause() -{ - if (m_pEVRBase) { - return m_pEVRBase->Pause(); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::Run(REFERENCE_TIME tStart) -{ - if (m_pEVRBase) { - return m_pEVRBase->Run(tStart); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::SetSyncSource(__in_opt IReferenceClock* pClock) -{ - if (m_pEVRBase) { - return m_pEVRBase->SetSyncSource(pClock); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::GetSyncSource(__deref_out_opt IReferenceClock** pClock) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetSyncSource(pClock); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::GetClassID(__RPC__out CLSID* pClassID) -{ - if (m_pEVRBase) { - return m_pEVRBase->GetClassID(pClassID); - } - return E_NOTIMPL; -} - -STDMETHODIMP CSyncRenderer::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); - return S_OK; -} - -STDMETHODIMP CSyncRenderer::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} - -STDMETHODIMP CSyncRenderer::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) -{ - CheckPointer(pBmpParms, E_POINTER); - CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); - memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); - m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; - m_pAllocatorPresenter->UpdateAlphaBitmap(); - return S_OK; -} - -STDMETHODIMP CSyncRenderer::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - HRESULT hr; - - if (riid == __uuidof(IVMRMixerBitmap9)) { - return GetInterface((IVMRMixerBitmap9*)this, ppv); - } - - if (riid == __uuidof(IBaseFilter)) { - return GetInterface((IBaseFilter*)this, ppv); - } - - if (riid == __uuidof(IMediaFilter)) { - return GetInterface((IMediaFilter*)this, ppv); - } - if (riid == __uuidof(IPersist)) { - return GetInterface((IPersist*)this, ppv); - } - if (riid == __uuidof(IBaseFilter)) { - return GetInterface((IBaseFilter*)this, ppv); - } - - hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE; - if (m_pEVR && FAILED(hr)) { - hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; - } - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); -} - -CGenlock::CGenlock(double target, double limit, int lineD, int colD, double clockD, UINT mon) - : powerstripTimingExists(false) - , liveSource(false) - , adjDelta(0) // Number of rows used in display frequency adjustment, typically 1 (one) - , lineDelta(lineD) // Number of columns used in display frequency adjustment, typically 1 - 2 - , columnDelta(colD) // Delta used in clock speed adjustment. In fractions of 1.0. Typically around 0.001 - , cycleDelta(clockD) // The monitor to be adjusted if the display refresh rate is the controlled parameter - , displayAdjustmentsMade(0) - , clockAdjustmentsMade(0) - , totalLines(0) - , totalColumns(0) - , visibleLines(0) - , visibleColumns(0) - , syncOffsetFifo(64) - , frameCycleFifo(4) - , minSyncOffset(DBL_MAX) - , maxSyncOffset(DBL_MIN) - , syncOffsetAvg(0.0) - , minFrameCycle(DBL_MAX) - , maxFrameCycle(DBL_MIN) - , frameCycleAvg(0.0) - , pixelClock(0) - , displayFreqCruise(0.0) - , displayFreqSlower(0.0) - , displayFreqFaster(0.0) - , curDisplayFreq(0.0) - , controlLimit(limit) // How much sync offset is allowed to drift from target sync offset before control kicks in - , monitor(mon) - , psWnd(nullptr) - , displayTiming() - , displayTimingSave() - , lowSyncOffset(target - limit) - , targetSyncOffset(target) // Target sync offset, typically around 10 ms - , highSyncOffset(target + limit) -{ - ZeroMemory(faster, MAX_LOADSTRING); - ZeroMemory(cruise, MAX_LOADSTRING); - ZeroMemory(slower, MAX_LOADSTRING); - ZeroMemory(savedTiming, MAX_LOADSTRING); -} - -CGenlock::~CGenlock() -{ - ResetTiming(); - syncClock = nullptr; -}; - -BOOL CGenlock::PowerstripRunning() -{ - psWnd = FindWindow(_T("TPShidden"), nullptr); - if (!psWnd) { - return FALSE; // Powerstrip is not running - } else { - return TRUE; - } -} - -// Get the display timing parameters through PowerStrip (if running). -HRESULT CGenlock::GetTiming() -{ - ATOM getTiming; - LPARAM lParam = 0; - WPARAM wParam = monitor; - int i = 0; - int j = 0; - int params = 0; - TCHAR tmpStr[MAX_LOADSTRING] = _T(""); - - CAutoLock lock(&csGenlockLock); - if (!PowerstripRunning()) { - return E_FAIL; - } - - getTiming = static_cast(SendMessage(psWnd, UM_GETTIMING, wParam, lParam)); - GlobalGetAtomName(getTiming, savedTiming, MAX_LOADSTRING); - - while (params < TIMING_PARAM_CNT) { - while (savedTiming[i] != _T(',') && savedTiming[i] != _T('\0')) { - tmpStr[j++] = savedTiming[i]; - tmpStr[j] = _T('\0'); - i++; - } - i++; // Skip trailing comma - j = 0; - displayTiming[params] = _ttoi(tmpStr); - displayTimingSave[params] = displayTiming[params]; - params++; - } - - // The display update frequency is controlled by adding and subtracting pixels form the - // image. This is done by either subtracting columns or rows or both. Some displays like - // row adjustments and some column adjustments. One should probably not do both. - StringCchPrintf(faster, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), - displayTiming[0], - displayTiming[HFRONTPORCH] - columnDelta, - displayTiming[2], - displayTiming[3], - displayTiming[4], - displayTiming[VFRONTPORCH] - lineDelta, - displayTiming[6], - displayTiming[7], - displayTiming[PIXELCLOCK], - displayTiming[9] - ); - - // Nominal update frequency - StringCchPrintf(cruise, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), - displayTiming[0], - displayTiming[HFRONTPORCH], - displayTiming[2], - displayTiming[3], - displayTiming[4], - displayTiming[VFRONTPORCH], - displayTiming[6], - displayTiming[7], - displayTiming[PIXELCLOCK], - displayTiming[9] - ); - - // Lower than nominal update frequency - StringCchPrintf(slower, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), - displayTiming[0], - displayTiming[HFRONTPORCH] + columnDelta, - displayTiming[2], - displayTiming[3], - displayTiming[4], - displayTiming[VFRONTPORCH] + lineDelta, - displayTiming[6], - displayTiming[7], - displayTiming[PIXELCLOCK], - displayTiming[9] - ); - - totalColumns = displayTiming[HACTIVE] + displayTiming[HFRONTPORCH] + displayTiming[HSYNCWIDTH] + displayTiming[HBACKPORCH]; - totalLines = displayTiming[VACTIVE] + displayTiming[VFRONTPORCH] + displayTiming[VSYNCWIDTH] + displayTiming[VBACKPORCH]; - pixelClock = 1000 * displayTiming[PIXELCLOCK]; // Pixels/s - displayFreqCruise = (double)pixelClock / (totalLines * totalColumns); // Frames/s - displayFreqSlower = (double)pixelClock / ((totalLines + lineDelta) * (totalColumns + columnDelta)); - displayFreqFaster = (double)pixelClock / ((totalLines - lineDelta) * (totalColumns - columnDelta)); - curDisplayFreq = displayFreqCruise; - GlobalDeleteAtom(getTiming); - adjDelta = 0; - powerstripTimingExists = true; - return S_OK; -} - -// Reset display timing parameters to nominal. -HRESULT CGenlock::ResetTiming() -{ - CAutoLock lock(&csGenlockLock); - - if (!PowerstripRunning()) { - return E_FAIL; - } - - if (displayAdjustmentsMade > 0) { - ATOM setTiming = GlobalAddAtom(cruise); - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, monitor, (LPARAM)setTiming); - GlobalDeleteAtom(setTiming); - curDisplayFreq = displayFreqCruise; - } - adjDelta = 0; - return S_OK; -} - -// Reset reference clock speed to nominal. -HRESULT CGenlock::ResetClock() -{ - adjDelta = 0; - if (syncClock == nullptr) { - return E_FAIL; - } else { - return syncClock->AdjustClock(1.0); - } -} - -HRESULT CGenlock::SetTargetSyncOffset(double targetD) -{ - targetSyncOffset = targetD; - lowSyncOffset = targetD - controlLimit; - highSyncOffset = targetD + controlLimit; - return S_OK; -} - -HRESULT CGenlock::GetTargetSyncOffset(double* targetD) -{ - *targetD = targetSyncOffset; - return S_OK; -} - -HRESULT CGenlock::SetControlLimit(double cL) -{ - controlLimit = cL; - return S_OK; -} - -HRESULT CGenlock::GetControlLimit(double* cL) -{ - *cL = controlLimit; - return S_OK; -} - -HRESULT CGenlock::SetDisplayResolution(UINT columns, UINT lines) -{ - visibleColumns = columns; - visibleLines = lines; - return S_OK; -} - -HRESULT CGenlock::AdviseSyncClock(ISyncClock* sC) -{ - if (!sC) { - return E_FAIL; - } - if (syncClock) { - syncClock = nullptr; // Release any outstanding references if this is called repeatedly - } - syncClock = sC; - return S_OK; -} - -// Set the monitor to control. This is best done manually as not all monitors can be controlled -// so automatic detection of monitor to control might have unintended effects. -// The PowerStrip API uses zero-based monitor numbers, i.e. the default monitor is 0. -HRESULT CGenlock::SetMonitor(UINT mon) -{ - monitor = mon; - return S_OK; -} - -HRESULT CGenlock::ResetStats() -{ - CAutoLock lock(&csGenlockLock); - minSyncOffset = DBL_MAX; - maxSyncOffset = DBL_MIN; - minFrameCycle = DBL_MAX; - maxFrameCycle = DBL_MIN; - displayAdjustmentsMade = 0; - clockAdjustmentsMade = 0; - return S_OK; -} - -// Synchronize by adjusting display refresh rate -HRESULT CGenlock::ControlDisplay(double syncOffset, double frameCycle) -{ - LPARAM lParam = 0; - WPARAM wParam = monitor; - ATOM setTiming; - - const CRenderersSettings& r = GetRenderersSettings(); - targetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset; - lowSyncOffset = targetSyncOffset - r.m_AdvRendSets.fControlLimit; - highSyncOffset = targetSyncOffset + r.m_AdvRendSets.fControlLimit; - - syncOffsetAvg = syncOffsetFifo.Average(syncOffset); - minSyncOffset = std::min(minSyncOffset, syncOffset); - maxSyncOffset = std::max(maxSyncOffset, syncOffset); - frameCycleAvg = frameCycleFifo.Average(frameCycle); - minFrameCycle = std::min(minFrameCycle, frameCycle); - maxFrameCycle = std::max(maxFrameCycle, frameCycle); - - if (!PowerstripRunning() || !powerstripTimingExists) { - return E_FAIL; - } - // Adjust as seldom as possible by checking the current controlState before changing it. - if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1)) - // Speed up display refresh rate by subtracting pixels from the image. - { - adjDelta = 1; // Increase refresh rate - curDisplayFreq = displayFreqFaster; - setTiming = GlobalAddAtom(faster); - lParam = setTiming; - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); - GlobalDeleteAtom(setTiming); - displayAdjustmentsMade++; - } else - // Slow down display refresh rate by adding pixels to the image. - if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1)) { - adjDelta = -1; - curDisplayFreq = displayFreqSlower; - setTiming = GlobalAddAtom(slower); - lParam = setTiming; - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); - GlobalDeleteAtom(setTiming); - displayAdjustmentsMade++; - } else - // Cruise. - if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1)) { - adjDelta = 0; - curDisplayFreq = displayFreqCruise; - setTiming = GlobalAddAtom(cruise); - lParam = setTiming; - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); - GlobalDeleteAtom(setTiming); - displayAdjustmentsMade++; - } else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1)) { - adjDelta = 0; - curDisplayFreq = displayFreqCruise; - setTiming = GlobalAddAtom(cruise); - lParam = setTiming; - SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); - GlobalDeleteAtom(setTiming); - displayAdjustmentsMade++; - } - return S_OK; -} - -// Synchronize by adjusting reference clock rate (and therefore video FPS). -// Todo: check so that we don't have a live source -HRESULT CGenlock::ControlClock(double syncOffset, double frameCycle) -{ - const CRenderersSettings& r = GetRenderersSettings(); - targetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset; - lowSyncOffset = targetSyncOffset - r.m_AdvRendSets.fControlLimit; - highSyncOffset = targetSyncOffset + r.m_AdvRendSets.fControlLimit; - - syncOffsetAvg = syncOffsetFifo.Average(syncOffset); - minSyncOffset = std::min(minSyncOffset, syncOffset); - maxSyncOffset = std::max(maxSyncOffset, syncOffset); - frameCycleAvg = frameCycleFifo.Average(frameCycle); - minFrameCycle = std::min(minFrameCycle, frameCycle); - maxFrameCycle = std::max(maxFrameCycle, frameCycle); - - if (!syncClock) { - return E_FAIL; - } - // Adjust as seldom as possible by checking the current controlState before changing it. - if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1)) - // Slow down video stream. - { - adjDelta = 1; - syncClock->AdjustClock(1.0 - cycleDelta); // Makes the clock move slower by providing smaller increments - clockAdjustmentsMade++; - } else - // Speed up video stream. - if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1)) { - adjDelta = -1; - syncClock->AdjustClock(1.0 + cycleDelta); - clockAdjustmentsMade++; - } else - // Cruise. - if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1)) { - adjDelta = 0; - syncClock->AdjustClock(1.0); - clockAdjustmentsMade++; - } else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1)) { - adjDelta = 0; - syncClock->AdjustClock(1.0); - clockAdjustmentsMade++; - } - return S_OK; -} - -// Don't adjust anything, just update the syncOffset stats -HRESULT CGenlock::UpdateStats(double syncOffset, double frameCycle) -{ - syncOffsetAvg = syncOffsetFifo.Average(syncOffset); - minSyncOffset = std::min(minSyncOffset, syncOffset); - maxSyncOffset = std::max(maxSyncOffset, syncOffset); - frameCycleAvg = frameCycleFifo.Average(frameCycle); - minFrameCycle = std::min(minFrameCycle, frameCycle); - maxFrameCycle = std::max(maxFrameCycle, frameCycle); - return S_OK; -} - -STDMETHODIMP CSyncAP::SetD3DFullscreen(bool fEnabled) -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_allocatorLock); - - fullScreenChanged = (fEnabled != m_bIsFullscreen); - m_bIsFullscreen = fEnabled; - return S_OK; -} - -STDMETHODIMP CSyncAP::GetD3DFullscreen(bool* pfEnabled) -{ - CheckPointer(pfEnabled, E_POINTER); - *pfEnabled = m_bIsFullscreen; - return S_OK; -} +/* + * (C) 2010-2017 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 . + * + */ + +#include "stdafx.h" +#include "../SyncClock/Interfaces.h" +#include +#include +#include +#include "../../../mpc-hc/resource.h" +#include "../../../DSUtil/DSUtil.h" +#include "../../../DSUtil/WinAPIUtils.h" +#include // Required in CGenlock +#include +#include +#include "d3dx9/d3dx9.h" +#include +#include +#include +#include +#include "../../../SubPic/DX9SubPic.h" +#include "../../../SubPic/SubPicQueueImpl.h" +#include "moreuuids.h" +#include "MacrovisionKicker.h" +#include "IPinHook.h" +#include "PixelShaderCompiler.h" +#include "FocusThread.h" +#include "../../../DSUtil/vd.h" +#include + +#include +#include +#include "SyncRenderer.h" +#include "Utils.h" +#include "Variables.h" + +#if (0) // Set to 1 to activate SyncRenderer traces +#define TRACE_SR TRACE +#else +#define TRACE_SR __noop +#endif + + +#define REFERENCE_WIDTH 1920 +#define FONT_HEIGHT 21 +#define BOLD_THRESHOLD 11 +#define TEXT_PADDING 2 +#define GRAPH_HEIGHT 360 +#define GRAPH_WIDTH 1000 + +using namespace GothSync; + +extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); + +CBaseAP::CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) + : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) + , m_hDWMAPI(nullptr) + , m_pDwmIsCompositionEnabled(nullptr) + , m_pDwmEnableComposition(nullptr) + , m_pOuterEVR(nullptr) + , m_SurfaceType(D3DFMT_UNKNOWN) + , m_BackbufferType(D3DFMT_UNKNOWN) + , m_DisplayType(D3DFMT_UNKNOWN) + , m_filter(D3DTEXF_NONE) + , m_LastAdapterCheck(0) + , m_CurrentAdapter(UINT_ERROR) + , m_bicubicA(0) + , m_nTearingPos(0) + , m_VMR9AlphaBitmapWidthBytes() + , m_pD3DXLoadSurfaceFromMemory(nullptr) + , m_pD3DXLoadSurfaceFromSurface(nullptr) + , m_pD3DXCreateLine(nullptr) + , m_pD3DXCreateFont(nullptr) + , m_pD3DXCreateSprite(nullptr) + , m_nDXSurface(1) + , m_nVMR9Surfaces(0) + , m_iVMR9Surface(0) + , m_nCurSurface(0) + , m_nUsedBuffer(0) + , m_lNextSampleWait(1) + , m_bSnapToVSync(false) + , m_uScanLineEnteringPaint(0) + , m_llEstVBlankTime(0) + , m_fAvrFps(0.0) + , m_fJitterStdDev(0.0) + , m_fJitterMean(0) + , m_fSyncOffsetAvr(0.0) + , m_fSyncOffsetStdDev(0.0) + , m_bHighColorResolution(false) + , m_bCompositionEnabled(false) + , m_bDesktopCompositionDisabled(false) + , m_bIsFullscreen(bFullscreen) + , fullScreenChanged(false) + , m_bNeedCheckSample(true) + , m_dMainThreadId(0) + , m_ScreenSize(0, 0) + , m_dDetectedScanlineTime(0.0) + , m_dD3DRefreshCycle(0) + , m_dEstRefreshCycle(0.0) + , m_dFrameCycle(0.0) + , m_dOptimumDisplayCycle(0.0) + , m_dCycleDifference(1.0) + , m_pcFramesDropped(0) + , m_pcFramesDuplicated(0) + , m_pcFramesDrawn(0) + , m_nNextJitter(0) + , m_nNextSyncOffset(0) + , m_JitterStdDev(0) + , m_llLastSyncTime(LONGLONG_ERROR) + , m_MaxJitter(MINLONG64) + , m_MinJitter(MAXLONG64) + , m_MaxSyncOffset(MINLONG64) + , m_MinSyncOffset(MAXLONG64) + , m_uSyncGlitches(0) + , m_llSampleTime(0) + , m_llLastSampleTime(0) + , m_llHysteresis(0) + , m_lShiftToNearest(0) + , m_lShiftToNearestPrev(0) + , m_bVideoSlowerThanDisplay(0) + , m_rtTimePerFrame(0) + , m_bInterlaced(false) + , m_TextScale(1.0) + , m_pGenlock(nullptr) + , m_pAudioStats(nullptr) + , m_lAudioLag(0) + , m_lAudioLagMin(10000) + , m_lAudioLagMax(-10000) + , m_lAudioSlaveMode(0) + , m_FocusThread(nullptr) + , m_hFocusWindow(nullptr) +{ + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + ZeroMemory(&m_caps, sizeof(m_caps)); + ZeroMemory(&m_pp, sizeof(m_pp)); + + if (FAILED(hr)) { + _Error += _T("ISubPicAllocatorPresenterImpl failed\n"); + return; + } + + HINSTANCE hDll = GetRenderersData()->GetD3X9Dll(); + + if (hDll) { + (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory"); + (FARPROC&)m_pD3DXLoadSurfaceFromSurface = GetProcAddress(hDll, "D3DXLoadSurfaceFromSurface"); + (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine"); + (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW"); + (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite"); + } else { + _Error += _T("The installed DirectX End-User Runtime is outdated. Please download and install the "); + _Error += MPC_DX_SDK_MONTH _T(" ") MAKE_STR(MPC_DX_SDK_YEAR); + _Error += _T(" release or newer in order for MPC-HC to function properly.\n"); + } + + m_hDWMAPI = LoadLibrary(L"dwmapi.dll"); + if (m_hDWMAPI) { + (FARPROC&)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled"); + (FARPROC&)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition"); + } + + Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx); + if (m_pD3DEx) { + m_pD3D = m_pD3DEx; + } + + const CRenderersSettings& r = GetRenderersSettings(); + if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { + m_bDesktopCompositionDisabled = true; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(0); + } + } else { + m_bDesktopCompositionDisabled = false; + } + + m_pGenlock = DEBUG_NEW CGenlock(r.m_AdvRendSets.fTargetSyncOffset, r.m_AdvRendSets.fControlLimit, r.m_AdvRendSets.iLineDelta, r.m_AdvRendSets.iColumnDelta, r.m_AdvRendSets.fCycleDelta, 0); // Must be done before CreateDXDevice + hr = CreateDXDevice(_Error); + ZeroMemory(m_pllJitter, sizeof(m_pllJitter)); + ZeroMemory(m_pllSyncOffset, sizeof(m_pllSyncOffset)); +} + +CBaseAP::~CBaseAP() +{ + if (m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = false; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(1); + } + } + + m_pFont = nullptr; + m_pLine = nullptr; + m_pSprite = nullptr; + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + m_pPSC.Free(); + m_pD3D = nullptr; + m_pD3DEx = nullptr; + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + + m_pAudioStats = nullptr; + SAFE_DELETE(m_pGenlock); + + if (m_FocusThread) { + m_FocusThread->PostThreadMessage(WM_QUIT, 0, 0); + if (WaitForSingleObject(m_FocusThread->m_hThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_FocusThread->m_hThread, 0xDEAD); + } + } + + if (m_hDWMAPI) { + FreeLibrary(m_hDWMAPI); + m_hDWMAPI = nullptr; + } +} + +template +void CBaseAP::AdjustQuad(MYD3DVERTEX* v, double dx, double dy) +{ + float offset = 0.5; + + for (int i = 0; i < 4; i++) { + v[i].x -= offset; + v[i].y -= offset; + + for (int j = 0; j < std::max(texcoords - 1, 1); j++) { + v[i].t[j].u -= (float)(offset * dx); + v[i].t[j].v -= (float)(offset * dy); + } + + if constexpr(texcoords > 1) { + v[i].t[texcoords - 1].u -= offset; + v[i].t[texcoords - 1].v -= offset; + } + } +} + +template +HRESULT CBaseAP::TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter = D3DTEXF_LINEAR) +{ + CheckPointer(pD3DDev, E_POINTER); + + DWORD FVF = 0; + switch (texcoords) { + case 1: + FVF = D3DFVF_TEX1; + break; + case 2: + FVF = D3DFVF_TEX2; + break; + case 3: + FVF = D3DFVF_TEX3; + break; + case 4: + FVF = D3DFVF_TEX4; + break; + case 5: + FVF = D3DFVF_TEX5; + break; + case 6: + FVF = D3DFVF_TEX6; + break; + case 7: + FVF = D3DFVF_TEX7; + break; + case 8: + FVF = D3DFVF_TEX8; + break; + default: + return E_FAIL; + } + + HRESULT hr; + hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + + for (int i = 0; i < texcoords; i++) { + hr = pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter); + hr = pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter); + hr = pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + } + + hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF); + + MYD3DVERTEX tmp = v[2]; + v[2] = v[3]; + v[3] = tmp; + hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); + + for (int i = 0; i < texcoords; i++) { + pD3DDev->SetTexture(i, nullptr); + } + + return S_OK; +} + +HRESULT CBaseAP::DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]) +{ + CheckPointer(pD3DDev, E_POINTER); + + HRESULT hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + hr = pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + + hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + + hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE); + + MYD3DVERTEX<0> tmp = v[2]; + v[2] = v[3]; + v[3] = tmp; + hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0])); + + return S_OK; +} + +MFOffset CBaseAP::GetOffset(float v) +{ + MFOffset offset; + offset.value = short(v); + offset.fract = WORD(65536 * (v - offset.value)); + return offset; +} + +MFVideoArea CBaseAP::GetArea(float x, float y, DWORD width, DWORD height) +{ + MFVideoArea area; + area.OffsetX = GetOffset(x); + area.OffsetY = GetOffset(y); + area.Area.cx = width; + area.Area.cy = height; + return area; +} + +void CBaseAP::ResetStats() +{ + m_pGenlock->ResetStats(); + m_lAudioLag = 0; + m_lAudioLagMin = 10000; + m_lAudioLagMax = -10000; + m_MinJitter = MAXLONG64; + m_MaxJitter = MINLONG64; + m_MinSyncOffset = MAXLONG64; + m_MaxSyncOffset = MINLONG64; + m_uSyncGlitches = 0; + m_pcFramesDropped = 0; + m_llLastSyncTime = LONGLONG_ERROR; +} + +bool CBaseAP::SettingsNeedResetDevice() +{ + CRenderersSettings& r = GetRenderersSettings(); + CRenderersSettings::CAdvRendererSettings& New = r.m_AdvRendSets; + CRenderersSettings::CAdvRendererSettings& Current = m_LastRendererSettings; + + bool bRet = false; + if (!m_bIsFullscreen) { + if (Current.bVMRDisableDesktopComposition) { + if (!m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = true; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(0); + } + } + } else { + if (m_bDesktopCompositionDisabled) { + m_bDesktopCompositionDisabled = false; + if (m_pDwmEnableComposition) { + m_pDwmEnableComposition(1); + } + } + } + } + bRet = bRet || New.bEVRHighColorResolution != Current.bEVRHighColorResolution; + m_LastRendererSettings = r.m_AdvRendSets; + return bRet; +} + +HRESULT CBaseAP::CreateDXDevice(CString& _Error) +{ + TRACE(_T("--> CBaseAP::CreateDXDevice on thread: %lu\n"), GetCurrentThreadId()); + const CRenderersSettings& r = GetRenderersSettings(); + m_LastRendererSettings = r.m_AdvRendSets; + HRESULT hr = E_FAIL; + + m_pFont = nullptr; + m_pSprite = nullptr; + m_pLine = nullptr; + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + + m_pPSC.Free(); + + m_pResizerPixelShader[0] = 0; + m_pResizerPixelShader[1] = 0; + m_pResizerPixelShader[2] = 0; + m_pResizerPixelShader[3] = 0; + + POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + pos = m_pPixelShaders.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + + UINT currentAdapter = GetAdapter(m_pD3D, m_hWnd); + bool bTryToReset = (currentAdapter == m_CurrentAdapter); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + m_CurrentAdapter = currentAdapter; + } + + if (!m_pD3D) { + _Error += L"Failed to create Direct3D device\n"; + return E_UNEXPECTED; + } + + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + if (FAILED(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)) + || d3ddm.Width <= 0 || d3ddm.Height <= 0) { + _Error += L"Can not retrieve display mode data\n"; + return E_UNEXPECTED; + } + + if (FAILED(m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &m_caps))) { + if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0) { + _Error += L"Video card does not have scanline access. Display synchronization is not possible.\n"; + return E_UNEXPECTED; + } + } + + m_refreshRate = d3ddm.RefreshRate; + m_dD3DRefreshCycle = 1000.0 / m_refreshRate; // In ms + m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); + m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height); + + BOOL bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + m_bCompositionEnabled = bCompositionEnabled != 0; + + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + + ZeroMemory(&m_pp, sizeof(m_pp)); + if (m_bIsFullscreen) { // Exclusive mode fullscreen + m_pp.Windowed = FALSE; + m_pp.BackBufferWidth = d3ddm.Width; + m_pp.BackBufferHeight = d3ddm.Height; + m_pp.hDeviceWindow = m_hWnd; + TRACE(_T("Wnd in CreateDXDevice: %p\n"), m_hWnd); + m_pp.BackBufferCount = 3; + m_pp.SwapEffect = D3DSWAPEFFECT_DISCARD; + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + m_pp.Flags = D3DPRESENTFLAG_VIDEO; + m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; + if (m_bHighColorResolution) { + if (FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false))) { + m_strStatsMsg[MSG_ERROR] = L"10 bit RGB is not supported by this graphics device in this resolution."; + m_bHighColorResolution = false; + } + } + + if (m_bHighColorResolution) { + m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } else { + m_pp.BackBufferFormat = d3ddm.Format; + } + + if (!m_FocusThread) { + m_FocusThread = (CFocusThread*)AfxBeginThread(RUNTIME_CLASS(CFocusThread), 0, 0, 0); + } + + HWND hFocusWindow = m_FocusThread->GetFocusWindow(); + bTryToReset &= (m_hFocusWindow == hFocusWindow || fullScreenChanged); + m_hFocusWindow = hFocusWindow; + + if (m_pD3DEx) { + D3DDISPLAYMODEEX DisplayMode; + ZeroMemory(&DisplayMode, sizeof(DisplayMode)); + DisplayMode.Size = sizeof(DisplayMode); + m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, nullptr); + + DisplayMode.Format = m_pp.BackBufferFormat; + m_pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate; + + bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&m_pp, &DisplayMode)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + hr = m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS | D3DCREATE_NOWINDOWCHANGES, + &m_pp, &DisplayMode, &m_pD3DDevEx); + } + + if (m_pD3DDevEx) { + m_pD3DDev = m_pD3DDevEx; + m_BackbufferType = m_pp.BackBufferFormat; + m_DisplayType = DisplayMode.Format; + } + } else { + bTryToReset = bTryToReset && m_pD3DDev && SUCCEEDED(hr = m_pD3DDev->Reset(&m_pp)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + hr = m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_NOWINDOWCHANGES, + &m_pp, &m_pD3DDev); + } + TRACE(_T("Created full-screen device\n")); + if (m_pD3DDev) { + m_BackbufferType = m_pp.BackBufferFormat; + m_DisplayType = d3ddm.Format; + } + } + } else { // Windowed + m_pp.Windowed = TRUE; + m_pp.hDeviceWindow = m_hWnd; + m_pp.SwapEffect = D3DSWAPEFFECT_COPY; + m_pp.Flags = D3DPRESENTFLAG_VIDEO; + m_pp.BackBufferCount = 1; + CSize bbsize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); + m_pp.BackBufferWidth = bbsize.cx; + m_pp.BackBufferHeight = bbsize.cy; + m_BackbufferType = d3ddm.Format; + m_DisplayType = d3ddm.Format; + m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; + if (m_bHighColorResolution) { + if (FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false))) { + m_strStatsMsg[MSG_ERROR] = L"10 bit RGB is not supported by this graphics device in this resolution."; + m_bHighColorResolution = false; + } + } + + if (m_bHighColorResolution) { + m_BackbufferType = D3DFMT_A2R10G10B10; + m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } + if (bCompositionEnabled) { + // Desktop composition presents the whole desktop + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } else { + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + } + + bTryToReset &= (m_hFocusWindow == m_hWnd || fullScreenChanged); + m_hFocusWindow = m_hWnd; + + if (m_pD3DEx) { + bTryToReset = bTryToReset && m_pD3DDevEx && SUCCEEDED(hr = m_pD3DDevEx->ResetEx(&m_pp, nullptr)); + + if (!bTryToReset) { + m_pD3DDev = nullptr; + m_pD3DDevEx = nullptr; + hr = m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED | D3DCREATE_ENABLE_PRESENTSTATS, + &m_pp, nullptr, &m_pD3DDevEx); + } + + if (m_pD3DDevEx) { + m_pD3DDev = m_pD3DDevEx; + } + } else { + if (bTryToReset) { + if (!m_pD3DDev || FAILED(hr = m_pD3DDev->Reset(&m_pp))) { + bTryToReset = false; + } + } + if (!bTryToReset) { + hr = m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hFocusWindow, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE | D3DCREATE_MULTITHREADED, + &m_pp, &m_pD3DDev); + } + TRACE(_T("Created windowed device\n")); + } + } + + if (m_pD3DDev) { + while (hr == D3DERR_DEVICELOST) { + TRACE(_T("D3DERR_DEVICELOST. Trying to Reset.\n")); + hr = m_pD3DDev->TestCooperativeLevel(); + } + if (hr == D3DERR_DEVICENOTRESET) { + TRACE(_T("D3DERR_DEVICENOTRESET\n")); + hr = m_pD3DDev->Reset(&m_pp); + } + + if (m_pD3DDevEx) { + m_pD3DDevEx->SetGPUThreadPriority(7); + } + } + + if (FAILED(hr)) { + _Error.AppendFormat(_T("CreateDevice failed: %s\n"), GetWindowsErrorMessage(hr, nullptr).GetString()); + + return hr; + } + + m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); + m_filter = D3DTEXF_NONE; + + if (m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR && m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR) { + m_filter = D3DTEXF_LINEAR; + } + + m_bicubicA = 0; + + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(m_pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); + } + + hr = S_OK; + + CComPtr pSubPicProvider; + if (m_pSubPicQueue) { + TRACE(_T("m_pSubPicQueue != nullptr\n")); + m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); + } + + if (!m_pSubPicQueue) { + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + m_pSubPicQueue->Invalidate(); + } + + if (FAILED(hr)) { + _Error += L"m_pSubPicQueue failed\n"; + return hr; + } + + if (pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); + } + + m_LastAdapterCheck = GetRenderersData()->GetPerfCounter(); + return S_OK; +} + +HRESULT CBaseAP::ResetDXDevice(CString& _Error) +{ + const CRenderersSettings& r = GetRenderersSettings(); + m_LastRendererSettings = r.m_AdvRendSets; + HRESULT hr = E_FAIL; + + hr = m_pD3DDev->TestCooperativeLevel(); + if ((hr != D3DERR_DEVICENOTRESET) && (hr != D3D_OK)) { + return hr; + } + + CComPtr rendererInputEnum; + std::vector> decoderOutput; + std::vector> rendererInput; + CFilterInfo filterInfo; + + bool disconnected = false; + + // Disconnect all pins to release video memory resources + if (m_pD3DDev) { + m_pOuterEVR->QueryFilterInfo(&filterInfo); + if (SUCCEEDED(m_pOuterEVR->EnumPins(&rendererInputEnum))) { + CComPtr input; + CComPtr output; + while (hr = rendererInputEnum->Next(1, &input.p, 0), hr == S_OK) { // Must have .p here + TRACE(_T("Pin found\n")); + input->ConnectedTo(&output.p); + if (output != nullptr) { + rendererInput.push_back(input); + decoderOutput.push_back(output); + } + input.Release(); + output.Release(); + } + } else { + return hr; + } + if (filterInfo.pGraph) { + for (size_t i = 0; i < decoderOutput.size(); i++) { + TRACE(_T("Disconnecting pin\n")); + filterInfo.pGraph->Disconnect(decoderOutput[i].p); + filterInfo.pGraph->Disconnect(rendererInput[i].p); + TRACE(_T("Pin disconnected\n")); + } + disconnected = true; + } + } + + // Release more resources + m_pSubPicQueue = nullptr; + m_pFont = nullptr; + m_pSprite = nullptr; + m_pLine = nullptr; + m_pPSC.Free(); + + m_pResizerPixelShader[0] = 0; + m_pResizerPixelShader[1] = 0; + m_pResizerPixelShader[2] = 0; + m_pResizerPixelShader[3] = 0; + + POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + pos = m_pPixelShaders.GetHeadPosition(); + while (pos) { + CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); + Shader.m_pPixelShader = nullptr; + } + + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + if (FAILED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D, m_hWnd), &d3ddm)) + || d3ddm.Width <= 0 || d3ddm.Height <= 0) { + _Error += L"Can not retrieve display mode data\n"; + return E_UNEXPECTED; + } + + m_refreshRate = d3ddm.RefreshRate; + m_dD3DRefreshCycle = 1000.0 / m_refreshRate; // In ms + m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height); + m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height); + CSize szDesktopSize(GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)); + + ZeroMemory(&m_pp, sizeof(m_pp)); + + BOOL bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + m_bCompositionEnabled = bCompositionEnabled != 0; + m_bHighColorResolution = r.m_AdvRendSets.bEVRHighColorResolution; + + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + + if (m_bIsFullscreen) { // Exclusive mode fullscreen + m_pp.BackBufferWidth = d3ddm.Width; + m_pp.BackBufferHeight = d3ddm.Height; + if (m_bHighColorResolution) { + m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } else { + m_pp.BackBufferFormat = d3ddm.Format; + } + if (FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_pp.BackBufferFormat, m_pp.BackBufferFormat, false))) { + _Error += L"10 bit RGB is not supported by this graphics device in exclusive mode fullscreen.\n"; + return hr; + } + + D3DDISPLAYMODEEX DisplayMode; + ZeroMemory(&DisplayMode, sizeof(DisplayMode)); + DisplayMode.Size = sizeof(DisplayMode); + if (m_pD3DDevEx) { + m_pD3DEx->GetAdapterDisplayModeEx(GetAdapter(m_pD3DEx, m_hWnd), &DisplayMode, nullptr); + DisplayMode.Format = m_pp.BackBufferFormat; + m_pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate; + if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { + _Error += GetWindowsErrorMessage(hr, nullptr); + return hr; + } + } else if (m_pD3DDev) { + if (FAILED(m_pD3DDev->Reset(&m_pp))) { + _Error += GetWindowsErrorMessage(hr, nullptr); + return hr; + } + } else { + _Error += L"No device.\n"; + return hr; + } + m_BackbufferType = m_pp.BackBufferFormat; + m_DisplayType = d3ddm.Format; + } else { // Windowed + CSize bbsize = GetBackBufferSize(m_ScreenSize, largestScreen, r.m_AdvRendSets.bDesktopSizeBackBuffer); + m_pp.BackBufferWidth = bbsize.cx; + m_pp.BackBufferHeight = bbsize.cy; + m_BackbufferType = d3ddm.Format; + m_DisplayType = d3ddm.Format; + if (m_bHighColorResolution) { + m_BackbufferType = D3DFMT_A2R10G10B10; + m_pp.BackBufferFormat = D3DFMT_A2R10G10B10; + } + if (FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_pp.BackBufferFormat, m_pp.BackBufferFormat, false))) { + _Error += L"10 bit RGB is not supported by this graphics device in windowed mode.\n"; + return hr; + } + if (bCompositionEnabled) { + // Desktop composition presents the whole desktop + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } else { + m_pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + } + if (m_pD3DDevEx) + if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { + _Error += GetWindowsErrorMessage(hr, nullptr); + return hr; + } else if (m_pD3DDev) + if (FAILED(m_pD3DDevEx->Reset(&m_pp))) { + _Error += GetWindowsErrorMessage(hr, nullptr); + return hr; + } else { + _Error += L"No device.\n"; + return hr; + } + } + + if (disconnected) { + for (size_t i = 0; i < decoderOutput.size(); i++) { + if (FAILED(filterInfo.pGraph->ConnectDirect(decoderOutput[i].p, rendererInput[i].p, nullptr))) { + return hr; + } + } + } + + m_pPSC.Attach(DEBUG_NEW CPixelShaderCompiler(m_pD3DDev, true)); + m_filter = D3DTEXF_NONE; + + if ((m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) + && (m_caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)) { + m_filter = D3DTEXF_LINEAR; + } + + m_bicubicA = 0; + + CComPtr pSubPicProvider; + if (m_pSubPicQueue) { + m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider); + } + + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(m_pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(m_pD3DDev, m_maxSubtitleTextureSize, false); + } + + hr = S_OK; + if (!m_pSubPicQueue) { + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + m_pSubPicQueue->Invalidate(); + } + + if (FAILED(hr)) { + _Error += L"m_pSubPicQueue failed\n"; + + return hr; + } + + if (pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(pSubPicProvider); + } + + m_pFont = nullptr; + m_pSprite = nullptr; + m_pLine = nullptr; + + return S_OK; +} + +HRESULT CBaseAP::AllocSurfaces(D3DFORMAT Format) +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_allocatorLock); + + CheckPointer(m_pD3DDev, E_POINTER); + + const CRenderersSettings& r = GetRenderersSettings(); + + for (int i = 0; i < m_nDXSurface + 2; i++) { + m_pVideoTexture[i] = nullptr; + m_pVideoSurface[i] = nullptr; + } + + m_pScreenSizeTemporaryTexture[0] = nullptr; + m_pScreenSizeTemporaryTexture[1] = nullptr; + m_SurfaceType = Format; + + HRESULT hr; + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { + int nTexturesNeeded = r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nDXSurface + 2 : 1; + + for (int i = 0; i < nTexturesNeeded; i++) { + if (FAILED(hr = m_pD3DDev->CreateTexture( + m_nativeVideoSize.cx, + m_nativeVideoSize.cy, + 1, + D3DUSAGE_RENDERTARGET, + Format, + D3DPOOL_DEFAULT, + &m_pVideoTexture[i], + nullptr))) { + return hr; + } + + if (FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i]))) { + return hr; + } + } + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D) { + for (int i = 0; i < m_nDXSurface + 2; i++) { + m_pVideoTexture[i] = nullptr; + } + } + } else { + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(m_nativeVideoSize.cx, m_nativeVideoSize.cy, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], nullptr))) { + return hr; + } + } + + hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], nullptr, 0); + return S_OK; +} + +void CBaseAP::DeleteSurfaces() +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_allocatorLock); + + for (int i = 0; i < m_nDXSurface + 2; i++) { + m_pVideoTexture[i] = nullptr; + m_pVideoSurface[i] = nullptr; + } +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP CBaseAP::CreateRenderer(IUnknown** ppRenderer) +{ + return E_NOTIMPL; +} + +bool CBaseAP::ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d) +{ + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pSurface->GetDesc(&desc))) { + return false; + } + + int w = desc.Width, h = desc.Height; + int sw = s.Width(), sh = s.Height(); + int dw = d.Width(), dh = d.Height(); + + if (d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0 + || sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) { + s.SetRectEmpty(); + d.SetRectEmpty(); + return true; + } + if (d.right > w) { + s.right -= (d.right - w) * sw / dw; + d.right = w; + } + if (d.bottom > h) { + s.bottom -= (d.bottom - h) * sh / dh; + d.bottom = h; + } + if (d.left < 0) { + s.left += (0 - d.left) * sw / dw; + d.left = 0; + } + if (d.top < 0) { + s.top += (0 - d.top) * sh / dh; + d.top = 0; + } + return true; +} + +HRESULT CBaseAP::InitResizers(float bicubicA, bool bNeedScreenSizeTexture) +{ + HRESULT hr; + do { + if (bicubicA) { + if (!m_pResizerPixelShader[0]) { + break; + } + if (!m_pResizerPixelShader[1]) { + break; + } + if (!m_pResizerPixelShader[2]) { + break; + } + if (!m_pResizerPixelShader[3]) { + break; + } + if (m_bicubicA != bicubicA) { + break; + } + if (!m_pScreenSizeTemporaryTexture[0]) { + break; + } + if (bNeedScreenSizeTexture) { + if (!m_pScreenSizeTemporaryTexture[1]) { + break; + } + } + } else { + if (!m_pResizerPixelShader[0]) { + break; + } + if (bNeedScreenSizeTexture) { + if (!m_pScreenSizeTemporaryTexture[0]) { + break; + } + if (!m_pScreenSizeTemporaryTexture[1]) { + break; + } + } + } + return S_OK; + } while (0); + + m_bicubicA = bicubicA; + m_pScreenSizeTemporaryTexture[0] = nullptr; + m_pScreenSizeTemporaryTexture[1] = nullptr; + + for (int i = 0; i < _countof(m_pResizerPixelShader); i++) { + m_pResizerPixelShader[i] = nullptr; + } + + if (m_caps.PixelShaderVersion < D3DPS_VERSION(2, 0)) { + return E_FAIL; + } + + LPCSTR pProfile = m_caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0"; + + CStringA str; + if (!LoadResource(IDF_SHADER_RESIZER, str, _T("SHADER"))) { + return E_FAIL; + } + + CStringA A; + A.Format("(%f)", bicubicA); + str.Replace("_The_Value_Of_A_Is_Set_Here_", A); + + LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass_pass1", "main_bicubic2pass_pass2"}; + + ASSERT(_countof(pEntries) == _countof(m_pResizerPixelShader)); + for (int i = 0; i < _countof(pEntries); i++) { + CString ErrorMessage; + CString DissAssembly; + hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShader[i], &DissAssembly, &ErrorMessage); + if (FAILED(hr)) { + TRACE(_T("%ws"), ErrorMessage.GetString()); + ASSERT(0); + return hr; + } + } + if (m_bicubicA || bNeedScreenSizeTexture) { + if (FAILED(m_pD3DDev->CreateTexture( + std::min((DWORD)m_ScreenSize.cx, m_caps.MaxTextureWidth), + std::min((DWORD)std::max(m_ScreenSize.cy, m_nativeVideoSize.cy), m_caps.MaxTextureHeight), + 1, + D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + &m_pScreenSizeTemporaryTexture[0], + nullptr))) { + ASSERT(0); + m_pScreenSizeTemporaryTexture[0] = nullptr; // will do 1 pass then + } + + if (FAILED(m_pD3DDev->CreateTexture( + std::min((DWORD)m_ScreenSize.cx, m_caps.MaxTextureWidth), + std::min((DWORD)std::max(m_ScreenSize.cy, m_nativeVideoSize.cy), m_caps.MaxTextureHeight), + 1, + D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + &m_pScreenSizeTemporaryTexture[1], + nullptr))) { + ASSERT(0); + m_pScreenSizeTemporaryTexture[1] = nullptr; // will do 1 pass then + } + } + return S_OK; +} + +HRESULT CBaseAP::TextureCopy(IDirect3DTexture9* pTexture) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + MYD3DVERTEX<1> v[] = { + {0, 0, 0.5f, 2.0f, 0, 0}, + {w, 0, 0.5f, 2.0f, 1, 0}, + {0, h, 0.5f, 2.0f, 0, 1}, + {w, h, 0.5f, 2.0f, 1, 1}, + }; + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + hr = m_pD3DDev->SetTexture(0, pTexture); + return TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); +} + +HRESULT CBaseAP::DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect) +{ + DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color)); + MYD3DVERTEX<0> v[] = { + {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color}, + {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color}, + {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color}, + {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color}, + }; + for (int i = 0; i < _countof(v); i++) { + v[i].x -= 0.5; + v[i].y -= 0.5; + } + return DrawRectBase(m_pD3DDev, v); +} + +HRESULT CBaseAP::TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& SrcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + float dx2 = 1.0f / w; + float dy2 = 1.0f / h; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, SrcRect.left * dx2, SrcRect.top * dy2}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, SrcRect.right * dx2, SrcRect.top * dy2}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, SrcRect.left * dx2, SrcRect.bottom * dy2}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, SrcRect.right * dx2, SrcRect.bottom * dy2}, + }; + AdjustQuad(v, 0, 0); + hr = m_pD3DDev->SetTexture(0, pTexture); + hr = m_pD3DDev->SetPixelShader(nullptr); + hr = TextureBlt(m_pD3DDev, v, filter); + return hr; +} + +HRESULT CBaseAP::TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + float tx0 = (float)SrcRect.left; + float tx1 = (float)SrcRect.right; + float ty0 = (float)SrcRect.top; + float ty1 = (float)SrcRect.bottom; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, + }; + AdjustQuad(v, 1.0, 1.0); + float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + hr = m_pD3DDev->SetTexture(0, pTexture); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[0]); + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + m_pD3DDev->SetPixelShader(nullptr); + return hr; +} + +HRESULT CBaseAP::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) +{ + HRESULT hr; + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) { + return E_FAIL; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + float tx0 = (float)SrcRect.left; + float tx1 = (float)SrcRect.right; + float ty0 = (float)SrcRect.top; + float ty1 = (float)SrcRect.bottom; + + MYD3DVERTEX<1> v[] = { + {dst[0].x, dst[0].y, dst[0].z, 1.0f / dst[0].z, tx0, ty0}, + {dst[1].x, dst[1].y, dst[1].z, 1.0f / dst[1].z, tx1, ty0}, + {dst[2].x, dst[2].y, dst[2].z, 1.0f / dst[2].z, tx0, ty1}, + {dst[3].x, dst[3].y, dst[3].z, 1.0f / dst[3].z, tx1, ty1}, + }; + AdjustQuad(v, 1.0, 1.0); + hr = m_pD3DDev->SetTexture(0, pTexture); + float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[1]); + hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT); + m_pD3DDev->SetPixelShader(nullptr); + return hr; +} + +HRESULT CBaseAP::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect) +{ + // The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction. + return TextureResizeBicubic1pass(pTexture, dst, SrcRect); + + /*HRESULT hr; + + // rotated? + if (dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z + || dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x) + return TextureResizeBicubic1pass(pTexture, dst, SrcRect); + + D3DSURFACE_DESC desc; + if (!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc))) + return E_FAIL; + + float Tex0_Width = desc.Width; + float Tex0_Height = desc.Height; + + CSize SrcTextSize = CSize(desc.Width, desc.Height); + double w = (double)SrcRect.Width(); + double h = (double)SrcRect.Height(); + UNREFERENCED_PARAMETER(w); + + CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h); + + if (!m_pScreenSizeTemporaryTexture[0] || FAILED(m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc))) + return TextureResizeBicubic1pass(pTexture, dst, SrcRect); + + float Tex1_Width = desc.Width; + float Tex1_Height = desc.Height; + + float tx0 = SrcRect.left; + float tx1 = SrcRect.right; + float ty0 = SrcRect.top; + float ty1 = SrcRect.bottom; + + float tx0_2 = 0; + float tx1_2 = dst1.Width(); + float ty0_2 = 0; + float ty1_2 = h; + + if (dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height) + return TextureResizeBicubic1pass(pTexture, dst, SrcRect); + + MYD3DVERTEX<1> vx[] = + { + {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0}, + {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0}, + {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1}, + {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1}, + }; + AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug here, create vertical lines ! TODO : why ?????? + MYD3DVERTEX<1> vy[] = + { + {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2}, + {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2}, + {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2}, + {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2}, + }; + AdjustQuad(vy, 0.0, 1.0); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[2]); + { + float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + } + hr = m_pD3DDev->SetTexture(0, pTexture); + CComPtr pRTOld; + hr = m_pD3DDev->GetRenderTarget(0, &pRTOld); + CComPtr pRT; + hr = m_pScreenSizeTemporaryTexture[0]->GetSurfaceLevel(0, &pRT); + hr = m_pD3DDev->SetRenderTarget(0, pRT); + hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT); + hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[3]); + { + float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}}; + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + } + hr = m_pD3DDev->SetTexture(0, m_pScreenSizeTemporaryTexture[0]); + hr = m_pD3DDev->SetRenderTarget(0, pRTOld); + hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT); + m_pD3DDev->SetPixelShader(nullptr); + return hr;*/ +} + +HRESULT CBaseAP::AlphaBlt(RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture) +{ + if (!pSrc || !pDst) { + return E_POINTER; + } + + CRect src(*pSrc), dst(*pDst); + + HRESULT hr; + + do { + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(pTexture->GetLevelDesc(0, &desc)) /*|| desc.Type != D3DRTYPE_TEXTURE*/) { + break; + } + + float w = (float)desc.Width; + float h = (float)desc.Height; + + // Be careful with the code that follows. Some compilers (e.g. Visual Studio 2012) used to miscompile + // it in some cases (namely x64 with optimizations /O2 /Ot). This bug led pVertices not to be correctly + // initialized and thus the subtitles weren't shown. + struct { + float x, y, z, rhw; + float tu, tv; + } pVertices[] = { + {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h}, + {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h}, + {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h}, + {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h}, + }; + + for (size_t i = 0; i < _countof(pVertices); i++) { + pVertices[i].x -= 0.5f; + pVertices[i].y -= 0.5f; + } + + hr = m_pD3DDev->SetTexture(0, pTexture); + + // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE + // so we need to provide default values in case GetRenderState fails + DWORD abe, sb, db; + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe))) { + abe = FALSE; + } + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb))) { + sb = D3DBLEND_ONE; + } + if (FAILED(m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db))) { + db = D3DBLEND_ZERO; + } + + hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE); + hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ... + hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst + + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + + hr = m_pD3DDev->SetPixelShader(nullptr); + + hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0])); + + m_pD3DDev->SetTexture(0, nullptr); + + m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe); + m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb); + m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db); + + return S_OK; + } while (0); + return E_FAIL; +} + +// Update the array m_pllJitter with a new vsync period. Calculate min, max and stddev. +void CBaseAP::SyncStats(LONGLONG syncTime) +{ + if (m_llLastSyncTime == LONGLONG_ERROR) { + m_llLastSyncTime = syncTime; + } + + m_nNextJitter = (m_nNextJitter + 1) % NB_JITTER; + LONGLONG jitter = syncTime - m_llLastSyncTime; + m_pllJitter[m_nNextJitter] = jitter; + double syncDeviation = (m_pllJitter[m_nNextJitter] - m_fJitterMean) / 10000.0; + if (abs(syncDeviation) > (GetDisplayCycle() / 2)) { + m_uSyncGlitches++; + } + + LONGLONG llJitterSum = 0; + LONGLONG llJitterSumAvg = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG Jitter = m_pllJitter[i]; + llJitterSum += Jitter; + llJitterSumAvg += Jitter; + } + m_fJitterMean = double(llJitterSumAvg) / NB_JITTER; + double DeviationSum = 0; + + for (int i = 0; i < NB_JITTER; i++) { + double deviation = m_pllJitter[i] - m_fJitterMean; + DeviationSum += deviation * deviation; + LONGLONG deviationInt = std::llround(deviation); + m_MaxJitter = std::max(m_MaxJitter, deviationInt); + m_MinJitter = std::min(m_MinJitter, deviationInt); + } + + m_fJitterStdDev = sqrt(DeviationSum / NB_JITTER); + m_fAvrFps = 10000000.0 / (double(llJitterSum) / NB_JITTER); + m_llLastSyncTime = syncTime; +} + +// Collect the difference between periodEnd and periodStart in an array, calculate mean and stddev. +void CBaseAP::SyncOffsetStats(LONGLONG syncOffset) +{ + m_nNextSyncOffset = (m_nNextSyncOffset + 1) % NB_JITTER; + m_pllSyncOffset[m_nNextSyncOffset] = syncOffset; + + LONGLONG AvrageSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + LONGLONG Offset = m_pllSyncOffset[i]; + AvrageSum += Offset; + m_MaxSyncOffset = std::max(m_MaxSyncOffset, Offset); + m_MinSyncOffset = std::min(m_MinSyncOffset, Offset); + } + double MeanOffset = double(AvrageSum) / NB_JITTER; + double DeviationSum = 0; + for (int i = 0; i < NB_JITTER; i++) { + double Deviation = double(m_pllSyncOffset[i]) - MeanOffset; + DeviationSum += Deviation * Deviation; + } + double StdDev = sqrt(DeviationSum / NB_JITTER); + + m_fSyncOffsetAvr = MeanOffset; + m_fSyncOffsetStdDev = StdDev; +} + +void CBaseAP::UpdateAlphaBitmap() +{ + m_VMR9AlphaBitmapData.Free(); + + if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0) { + HBITMAP hBitmap = (HBITMAP)GetCurrentObject(m_VMR9AlphaBitmap.hdc, OBJ_BITMAP); + if (!hBitmap) { + return; + } + DIBSECTION info; + ZeroMemory(&info, sizeof(DIBSECTION)); + if (!::GetObject(hBitmap, sizeof(DIBSECTION), &info)) { + return; + } + + m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight); + m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes; + + if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight)) { + memcpy((BYTE*)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight); + } + } +} + +// Present a sample (frame) using DirectX. +STDMETHODIMP_(bool) CBaseAP::Paint(bool bAll) +{ + if (m_bPendingResetDevice) { + SendResetRequest(); + return false; + } + + const CRenderersSettings& r = GetRenderersSettings(); + CRenderersData* rd = GetRenderersData(); + D3DRASTER_STATUS rasterStatus; + REFERENCE_TIME llCurRefTime = 0; + REFERENCE_TIME llSyncOffset = 0; + double dSyncOffset = 0.0; + + CAutoLock cRenderLock(&m_allocatorLock); + + // Estimate time for next vblank based on number of remaining lines in this frame. This algorithm seems to be + // accurate within one ms why there should not be any need for a more accurate one. The wiggly line seen + // when using sync to nearest and sync display is most likely due to inaccuracies in the audio-card-based + // reference clock. The wiggles are not seen with the perfcounter-based reference clock of the sync to video option. + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + m_uScanLineEnteringPaint = rasterStatus.ScanLine; + if (m_pRefClock) { + m_pRefClock->GetTime(&llCurRefTime); + } + int dScanLines = std::max(int(m_ScreenSize.cy - m_uScanLineEnteringPaint), 0); + dSyncOffset = dScanLines * m_dDetectedScanlineTime; // ms + llSyncOffset = REFERENCE_TIME(10000.0 * dSyncOffset); // Reference time units (100 ns) + m_llEstVBlankTime = llCurRefTime + llSyncOffset; // Estimated time for the start of next vblank + + if (m_windowRect.right <= m_windowRect.left || m_windowRect.bottom <= m_windowRect.top + || m_nativeVideoSize.cx <= 0 || m_nativeVideoSize.cy <= 0 + || !m_pVideoSurface[m_nCurSurface]) { + return false; + } + + HRESULT hr; + CRect rSrcVid(CPoint(0, 0), m_nativeVideoSize); + CRect rDstVid(m_videoRect); + CRect rSrcPri(CPoint(0, 0), m_windowRect.Size()); + CRect rDstPri(rSrcPri); + + m_pD3DDev->BeginScene(); + CComPtr pBackBuffer; + m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); + m_pD3DDev->SetRenderTarget(0, pBackBuffer); + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); + if (!rDstVid.IsRectEmpty()) { + if (m_pVideoTexture[m_nCurSurface]) { + CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; + + if (m_pVideoTexture[m_nDXSurface] && m_pVideoTexture[m_nDXSurface + 1] && !m_pPixelShaders.IsEmpty()) { + static __int64 counter = 0; + static long start = clock(); + + long stop = clock(); + long diff = stop - start; + + if (diff >= 10 * 60 * CLOCKS_PER_SEC) { + start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) + } + + int src = m_nCurSurface, dst = m_nDXSurface; + + D3DSURFACE_DESC desc; + m_pVideoTexture[src]->GetLevelDesc(0, &desc); + + float fConstData[][4] = { + {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, + }; + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + CComPtr pRT; + hr = m_pD3DDev->GetRenderTarget(0, &pRT); + + POSITION pos = m_pPixelShaders.GetHeadPosition(); + while (pos) { + pVideoTexture = m_pVideoTexture[dst]; + + hr = m_pD3DDev->SetRenderTarget(0, m_pVideoSurface[dst]); + CExternalPixelShader& Shader = m_pPixelShaders.GetNext(pos); + if (!Shader.m_pPixelShader) { + Shader.Compile(m_pPSC); + } + hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + TextureCopy(m_pVideoTexture[src]); + + src = dst; + if (++dst >= m_nDXSurface + 2) { + dst = m_nDXSurface; + } + } + + hr = m_pD3DDev->SetRenderTarget(0, pRT); + hr = m_pD3DDev->SetPixelShader(nullptr); + } + + Vector dst[4]; + Transform(rDstVid, dst); + + DWORD iDX9Resizer = r.iDX9Resizer; + + float A = 0; + + switch (iDX9Resizer) { + case 3: + A = -0.60f; + break; + case 4: + A = -0.751f; + break; // FIXME : 0.75 crash recent D3D, or eat CPU + case 5: + A = -1.00f; + break; + } + bool bScreenSpacePixelShaders = !m_pPixelShadersScreenSpace.IsEmpty(); + + hr = InitResizers(A, bScreenSpacePixelShaders); + + if (!m_pScreenSizeTemporaryTexture[0] || !m_pScreenSizeTemporaryTexture[1]) { + bScreenSpacePixelShaders = false; + } + + if (bScreenSpacePixelShaders) { + CComPtr pRT; + hr = m_pScreenSizeTemporaryTexture[1]->GetSurfaceLevel(0, &pRT); + if (hr != S_OK) { + bScreenSpacePixelShaders = false; + } + if (bScreenSpacePixelShaders) { + hr = m_pD3DDev->SetRenderTarget(0, pRT); + if (hr != S_OK) { + bScreenSpacePixelShaders = false; + } + hr = m_pD3DDev->Clear(0, nullptr, D3DCLEAR_TARGET, 0, 1.0f, 0); + } + } + + if (rSrcVid.Size() != rDstVid.Size()) { + if (iDX9Resizer == 0 || iDX9Resizer == 1) { + D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; + hr = TextureResize(pVideoTexture, dst, Filter, rSrcVid); + } else if (iDX9Resizer == 2) { + hr = TextureResizeBilinear(pVideoTexture, dst, rSrcVid); + } else if (iDX9Resizer >= 3) { + hr = TextureResizeBicubic2pass(pVideoTexture, dst, rSrcVid); + } + } else { + hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, rSrcVid); + } + + if (bScreenSpacePixelShaders) { + static __int64 counter = 555; + static long start = clock() + 333; + + long stop = clock() + 333; + long diff = stop - start; + + if (diff >= 10 * 60 * CLOCKS_PER_SEC) { + start = stop; // reset after 10 min (ps float has its limits in both range and accuracy) + } + + D3DSURFACE_DESC desc; + m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc); + + float fConstData[][4] = { + {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC}, + {1.0f / desc.Width, 1.0f / desc.Height, 0, 0}, + }; + + hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, _countof(fConstData)); + + int srcTexture = 1, dstTexture = 0; + + POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition(); + while (pos) { + if (m_pPixelShadersScreenSpace.GetTailPosition() == pos) { + m_pD3DDev->SetRenderTarget(0, pBackBuffer); + } else { + CComPtr pRT; + hr = m_pScreenSizeTemporaryTexture[dstTexture]->GetSurfaceLevel(0, &pRT); + m_pD3DDev->SetRenderTarget(0, pRT); + } + + CExternalPixelShader& Shader = m_pPixelShadersScreenSpace.GetNext(pos); + if (!Shader.m_pPixelShader) { + Shader.Compile(m_pPSC); + } + hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader); + TextureCopy(m_pScreenSizeTemporaryTexture[srcTexture]); + + std::swap(srcTexture, dstTexture); + } + + hr = m_pD3DDev->SetPixelShader(nullptr); + } + } else { + if (pBackBuffer) { + ClipToSurface(pBackBuffer, rSrcVid, rDstVid); + // rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect + rSrcVid.left &= ~1; + rSrcVid.right &= ~1; + rSrcVid.top &= ~1; + rSrcVid.bottom &= ~1; + hr = m_pD3DDev->StretchRect(m_pVideoSurface[m_nCurSurface], rSrcVid, pBackBuffer, rDstVid, m_filter); + if (FAILED(hr)) { + return false; + } + } + } + } + + AlphaBltSubPic(rDstPri, rDstVid); + + if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE) { + CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock); + CRect rcSrc(m_VMR9AlphaBitmap.rSrc); + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE*)m_VMR9AlphaBitmapData) { + if ((m_pD3DXLoadSurfaceFromMemory != nullptr) && + SUCCEEDED(hr = m_pD3DDev->CreateTexture( + rcSrc.Width(), + rcSrc.Height(), + 1, + D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + &m_pOSDTexture, + nullptr))) { + if (SUCCEEDED(hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface))) { + hr = m_pD3DXLoadSurfaceFromMemory(m_pOSDSurface, nullptr, nullptr, (BYTE*)m_VMR9AlphaBitmapData, D3DFMT_A8R8G8B8, m_VMR9AlphaBitmapWidthBytes, + nullptr, &m_VMR9AlphaBitmapRect, D3DX_FILTER_NONE, m_VMR9AlphaBitmap.clrSrcKey); + } + if (FAILED(hr)) { + m_pOSDTexture = nullptr; + m_pOSDSurface = nullptr; + } + } + } + m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE; + } + if (rd->m_iDisplayStats) { + DrawStats(); + } + if (m_pOSDTexture) { + AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture); + } + m_pD3DDev->EndScene(); + + CRect presentationSrcRect(rDstPri), presentationDestRect(m_windowRect); + // PresentEx() / Present() performs the clipping + // TODO: fix the race and uncomment the assert + //ASSERT(presentationSrcRect.Size() == presentationDestRect.Size()); + if (m_pD3DDevEx) { + if (m_bIsFullscreen) { + hr = m_pD3DDevEx->PresentEx(nullptr, nullptr, nullptr, nullptr, 0); + } else { + hr = m_pD3DDevEx->PresentEx(presentationSrcRect, presentationDestRect, nullptr, nullptr, 0); + } + } else { + if (m_bIsFullscreen) { + hr = m_pD3DDev->Present(nullptr, nullptr, nullptr, nullptr); + } else { + hr = m_pD3DDev->Present(presentationSrcRect, presentationDestRect, nullptr, nullptr); + } + } + if (FAILED(hr)) { + TRACE(_T("Device lost or something\n")); + } + // Calculate timing statistics + if (m_pRefClock) { + m_pRefClock->GetTime(&llCurRefTime); // To check if we called Present too late to hit the right vsync + } + m_llEstVBlankTime = std::max(m_llEstVBlankTime, llCurRefTime); // Sometimes the real value is larger than the estimated value (but never smaller) + if (rd->m_iDisplayStats < 3) { // Partial on-screen statistics + SyncStats(m_llEstVBlankTime); // Max of estimate and real. Sometimes Present may actually return immediately so we need the estimate as a lower bound + } + if (rd->m_iDisplayStats == 1) { // Full on-screen statistics + SyncOffsetStats(-llSyncOffset); // Minus because we want time to flow downward in the graph in DrawStats + } + + // Adjust sync + double frameCycle = (m_llSampleTime - m_llLastSampleTime) / 10000.0; + if (frameCycle < 0) { + frameCycle = 0.0; // Happens when searching. + } + + if (r.m_AdvRendSets.bSynchronizeVideo) { + m_pGenlock->ControlClock(dSyncOffset, frameCycle); + } else if (r.m_AdvRendSets.bSynchronizeDisplay) { + m_pGenlock->ControlDisplay(dSyncOffset, frameCycle); + } else { + m_pGenlock->UpdateStats(dSyncOffset, frameCycle); // No sync or sync to nearest neighbor + } + + m_dFrameCycle = m_pGenlock->frameCycleAvg; + m_dCycleDifference = GetCycleDifference(); + if (abs(m_dCycleDifference) < 0.05) { // If less than 5% speed difference + m_bSnapToVSync = true; + } else { + m_bSnapToVSync = false; + } + + // Check how well audio is matching rate (if at all) + DWORD tmp; + if (m_pAudioStats != nullptr) { + m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_ACCUMERROR, &m_lAudioLag, &tmp); + m_lAudioLagMin = std::min((long)m_lAudioLag, m_lAudioLagMin); + m_lAudioLagMax = std::max((long)m_lAudioLag, m_lAudioLagMax); + m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_MODE, &m_lAudioSlaveMode, &tmp); + } + + if (rd->m_bResetStats) { + ResetStats(); + rd->m_bResetStats = false; + } + + bool fResetDevice = m_bPendingResetDevice; + if (hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET || hr == S_PRESENT_MODE_CHANGED) { + fResetDevice = true; + } + if (SettingsNeedResetDevice()) { + fResetDevice = true; + } + + BOOL bCompositionEnabled = false; + if (m_pDwmIsCompositionEnabled) { + m_pDwmIsCompositionEnabled(&bCompositionEnabled); + } + if ((bCompositionEnabled != 0) != m_bCompositionEnabled) { + if (m_bIsFullscreen) { + m_bCompositionEnabled = (bCompositionEnabled != 0); + } else { + fResetDevice = true; + } + } + + if (r.fResetDevice) { + LONGLONG time = rd->GetPerfCounter(); + if (time > m_LastAdapterCheck + 20000000) { // check every 2 sec. + m_LastAdapterCheck = time; +#ifdef _DEBUG + D3DDEVICE_CREATION_PARAMETERS Parameters; + if (SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))) { + ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter); + } +#endif + if (m_CurrentAdapter != GetAdapter(m_pD3D, m_hWnd)) { + fResetDevice = true; + } +#ifdef _DEBUG + else { + ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D, m_hWnd))); + } +#endif + } + } + + if (fResetDevice) { + m_bPendingResetDevice = true; + SendResetRequest(); + } + return true; +} + +void CBaseAP::SendResetRequest() +{ + if (!m_bDeviceResetRequested) { + m_bDeviceResetRequested = true; + AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE); + } +} + +STDMETHODIMP_(bool) CBaseAP::ResetDevice() +{ + DeleteSurfaces(); + HRESULT hr; + CString Error; + if (FAILED(hr = CreateDXDevice(Error)) || FAILED(hr = AllocSurfaces())) { + m_bDeviceResetRequested = false; + return false; + } + m_pGenlock->SetMonitor(GetAdapter(m_pD3D, m_hWnd)); + m_pGenlock->GetTiming(); + OnResetDevice(); + m_bDeviceResetRequested = false; + m_bPendingResetDevice = false; + return true; +} + +STDMETHODIMP_(bool) CBaseAP::DisplayChange() +{ + m_bPendingResetDevice = true; + SendResetRequest(); + return true; +} + +void CBaseAP::InitStats() +{ + ASSERT(m_pD3DDev); + static LONG currentHeight = 0; + int newHeight = lround(FONT_HEIGHT * (double(m_windowRect.Width()) / REFERENCE_WIDTH)); + + if (m_pD3DXCreateFont && (!m_pFont || currentHeight != newHeight)) { + m_pFont = nullptr; + if (newHeight <= 0) { + ASSERT(FALSE); + } + m_pD3DXCreateFont(m_pD3DDev, newHeight, 0, newHeight < BOLD_THRESHOLD ? FW_NORMAL : FW_BOLD, + 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, + FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont); + currentHeight = newHeight; + } + + if (m_pD3DXCreateSprite && !m_pSprite) { + m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite); + } + + if (m_pD3DXCreateLine && !m_pLine) { + m_pD3DXCreateLine(m_pD3DDev, &m_pLine); + } +} + +void CBaseAP::DrawStats() +{ + const CRenderersData* rd = GetRenderersData(); + + InitStats(); + const float textScale = float(m_windowRect.Width()) / REFERENCE_WIDTH; + const int lineHeight = lround((FONT_HEIGHT + TEXT_PADDING) * textScale); + + // pApp->m_iDisplayStats = 1 for full stats, 2 for little less, 3 for basic, 0 for no stats + if (m_pFont && m_pSprite) { + auto drawText = [&](CRect & rc, const CString & strText) { + D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f); + D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f); + + RECT shadowRect = rc; + OffsetRect(&shadowRect, 2, 2); + + // Draw shadow + m_pFont->DrawText(m_pSprite, strText, -1, &shadowRect, DT_NOCLIP, Color0); + // Draw text + m_pFont->DrawText(m_pSprite, strText, -1, rc, DT_NOCLIP, Color1); + rc.OffsetRect(0, lineHeight); + }; + + const CRenderersSettings& r = GetRenderersSettings(); + LONGLONG llMaxJitter = m_MaxJitter; + LONGLONG llMinJitter = m_MinJitter; + CRect rc(lineHeight, lineHeight, 0, 0); + + m_pSprite->Begin(D3DXSPRITE_ALPHABLEND); + CString strText; + + strText.Format(_T("Frames drawn from stream start: %u | Sample time stamp: %ld ms"), + m_pcFramesDrawn, (LONG)(m_llSampleTime / 10000)); + drawText(rc, strText); + + if (rd->m_iDisplayStats == 1) { + strText.Format(_T("Frame cycle : %.3f ms [%.3f ms, %.3f ms] Actual %+5.3f ms [%+.3f ms, %+.3f ms]"), + m_dFrameCycle, m_pGenlock->minFrameCycle, m_pGenlock->maxFrameCycle, + m_fJitterMean / 10000.0, (double(llMinJitter) / 10000.0), + (double(llMaxJitter) / 10000.0)); + drawText(rc, strText); + + strText.Format(_T("Display cycle: Measured closest match %.3f ms Measured base %.3f ms"), + m_dOptimumDisplayCycle, m_dEstRefreshCycle); + drawText(rc, strText); + + strText.Format(_T("Frame rate : %.3f fps Actual frame rate: %.3f fps"), + 1000.0 / m_dFrameCycle, 10000000.0 / m_fJitterMean); + drawText(rc, strText); + + strText.Format(_T("Windows : Display cycle %.3f ms Display refresh rate %u Hz"), + m_dD3DRefreshCycle, m_refreshRate); + drawText(rc, strText); + + if (m_pGenlock->powerstripTimingExists) { + strText.Format(_T("Powerstrip : Display cycle %.3f ms Display refresh rate %.3f Hz"), + 1000.0 / m_pGenlock->curDisplayFreq, m_pGenlock->curDisplayFreq); + drawText(rc, strText); + } + + if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0) { + strText = _T("Scan line err: Graphics device does not support scan line access. No sync is possible"); + drawText(rc, strText); + } + +#ifdef _DEBUG + if (m_pD3DDevEx) { + CComPtr pSC; + HRESULT hr = m_pD3DDevEx->GetSwapChain(0, &pSC); + CComQIPtr pSCEx = pSC; + if (pSCEx) { + D3DPRESENTSTATS stats; + hr = pSCEx->GetPresentStats(&stats); + if (SUCCEEDED(hr)) { + strText = _T("Graphics device present stats:"); + drawText(rc, strText); + + strText.Format(_T(" PresentCount %u PresentRefreshCount %u SyncRefreshCount %u"), + stats.PresentCount, stats.PresentRefreshCount, stats.SyncRefreshCount); + drawText(rc, strText); + + LARGE_INTEGER Freq; + QueryPerformanceFrequency(&Freq); + Freq.QuadPart /= 1000; + strText.Format(_T(" SyncQPCTime %dms SyncGPUTime %dms"), + stats.SyncQPCTime.QuadPart / Freq.QuadPart, + stats.SyncGPUTime.QuadPart / Freq.QuadPart); + drawText(rc, strText); + } else { + strText = L"Graphics device does not support present stats"; + drawText(rc, strText); + } + } + } +#endif + + strText.Format(_T("Video size : %ld x %ld (AR = %ld : %ld) Display resolution %ld x %ld "), + m_nativeVideoSize.cx, m_nativeVideoSize.cy, m_aspectRatio.cx, m_aspectRatio.cy, + m_ScreenSize.cx, m_ScreenSize.cy); + drawText(rc, strText); + + if (r.m_AdvRendSets.bSynchronizeDisplay || r.m_AdvRendSets.bSynchronizeVideo) { + if (r.m_AdvRendSets.bSynchronizeDisplay && !m_pGenlock->PowerstripRunning()) { + strText = _T("Sync error : PowerStrip is not running. No display sync is possible."); + drawText(rc, strText); + } else { + strText.Format(_T("Sync adjust : %d | # of adjustments: %u"), + m_pGenlock->adjDelta, + (m_pGenlock->clockAdjustmentsMade + m_pGenlock->displayAdjustmentsMade) / 2); + drawText(rc, strText); + } + } + } + + strText.Format(_T("Sync offset : Average %3.1f ms [%.1f ms, %.1f ms] Target %3.1f ms"), + m_pGenlock->syncOffsetAvg, m_pGenlock->minSyncOffset, + m_pGenlock->maxSyncOffset, r.m_AdvRendSets.fTargetSyncOffset); + drawText(rc, strText); + + strText.Format(_T("Sync status : glitches %u, display-frame cycle mismatch: %7.3f %%, dropped frames %u"), + m_uSyncGlitches, 100 * m_dCycleDifference, m_pcFramesDropped); + drawText(rc, strText); + + if (rd->m_iDisplayStats == 1) { + if (m_pAudioStats && r.m_AdvRendSets.bSynchronizeVideo) { + strText.Format(_T("Audio lag : %3lu ms [%ld ms, %ld ms] | %s"), + m_lAudioLag, m_lAudioLagMin, m_lAudioLagMax, + (m_lAudioSlaveMode == 4) ? + _T("Audio renderer is matching rate (for analog sound output)") : + _T("Audio renderer is not matching rate")); + drawText(rc, strText); + } + + strText.Format(_T("Sample time : waiting %3ld ms"), m_lNextSampleWait); + if (r.m_AdvRendSets.bSynchronizeNearest) { + CString temp; + temp.Format(_T(" paint time correction: %3ld ms Hysteresis: %I64d"), + m_lShiftToNearest, m_llHysteresis / 10000); + strText += temp; + } + drawText(rc, strText); + + strText.Format(_T("Buffering : Buffered %3ld Free %3ld Current Surface %3d"), + m_nUsedBuffer, m_nDXSurface - m_nUsedBuffer, m_nCurSurface); + drawText(rc, strText); + + strText = _T("Settings : "); + + if (m_bIsFullscreen) { + strText += _T("D3DFS "); + } + if (r.m_AdvRendSets.bVMRDisableDesktopComposition) { + strText += _T("DisDC "); + } + if (r.m_AdvRendSets.bSynchronizeVideo) { + strText += _T("SyncVideo "); + } + if (r.m_AdvRendSets.bSynchronizeDisplay) { + strText += _T("SyncDisplay "); + } + if (r.m_AdvRendSets.bSynchronizeNearest) { + strText += _T("SyncNearest "); + } + if (m_bHighColorResolution) { + strText += _T("10 bit "); + } + if (r.m_AdvRendSets.iEVROutputRange == 0) { + strText += _T("0-255 "); + } else if (r.m_AdvRendSets.iEVROutputRange == 1) { + strText += _T("16-235 "); + } + + drawText(rc, strText); + drawText(rc, rd->m_strDXVAInfo); + + strText.Format(L"DirectX SDK : %u", rd->GetDXSdkRelease()); + drawText(rc, strText); + + for (int i = 0; i < 6; i++) { + if (m_strStatsMsg[i][0]) { + drawText(rc, m_strStatsMsg[i]); + } + } + } + m_pSprite->End(); + } + + if (m_pLine && (rd->m_iDisplayStats < 3)) { + D3DXVECTOR2 points[NB_JITTER]; + const float graphWidth = GRAPH_WIDTH * textScale; + const float graphHeight = GRAPH_HEIGHT * textScale; + const float topLeftX = m_windowRect.Width() - (graphWidth + lineHeight); + const float topLeftY = m_windowRect.Height() - (graphHeight + lineHeight); + const float gridStepY = graphHeight / 24.0f; + const float gridStepX = graphWidth / NB_JITTER; + + // Draw background + DrawRect(RGB(0, 0, 0), 80, CRect(int(topLeftX), + int(topLeftY), + int(topLeftX + graphWidth), + int(topLeftY + graphHeight))); + + m_pLine->SetWidth(2.5f * textScale); + m_pLine->SetAntialias(TRUE); + m_pLine->Begin(); + + // Draw grid lines + for (int i = 1; i < 24; ++i) { + points[0].x = topLeftX; + points[0].y = topLeftY + i * gridStepY; + points[1].y = points[0].y; + + float lineLength; + D3DCOLOR color; + if (i % 12 == 0) { + lineLength = 1.0f; + color = D3DCOLOR_XRGB(100, 100, 255); + } else if (i % 4 == 0) { + lineLength = 0.96f; + color = D3DCOLOR_XRGB(100, 100, 180); + } else { + lineLength = 0.04f; + color = D3DCOLOR_XRGB(100, 100, 140); + } + points[1].x = topLeftX + graphWidth * lineLength; + m_pLine->Draw(points, 2, color); + } + + // Draw jitter + for (int i = 1; i <= NB_JITTER; ++i) { + int nIndex = (m_nNextJitter + i) % NB_JITTER; + if (nIndex < 0) { + nIndex += NB_JITTER; + ASSERT(FALSE); + } + float jitter = float(m_pllJitter[nIndex] - m_fJitterMean); + points[i - 1].x = topLeftX + i * gridStepX; + points[i - 1].y = topLeftY + (jitter * textScale / 2000.0f + graphHeight / 2.0f); + } + m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100)); + + if (rd->m_iDisplayStats == 1) { // Full on-screen statistics + // Draw sync offset + for (int i = 1; i <= NB_JITTER; ++i) { + int nIndex = (m_nNextSyncOffset + i) % NB_JITTER; + if (nIndex < 0) { + nIndex += NB_JITTER; + } + points[i - 1].x = topLeftX + i * gridStepX; + points[i - 1].y = topLeftY + (m_pllSyncOffset[nIndex] * textScale / 2000.0f + graphHeight / 2.0f); + } + m_pLine->Draw(points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100)); + } + m_pLine->End(); + } +} + +double CBaseAP::GetRefreshRate() +{ + if (m_pGenlock->powerstripTimingExists) { + return m_pGenlock->curDisplayFreq; + } else { + return (double)m_refreshRate; + } +} + +double CBaseAP::GetDisplayCycle() +{ + if (m_pGenlock->powerstripTimingExists) { + return 1000.0 / m_pGenlock->curDisplayFreq; + } else { + return (double)m_dD3DRefreshCycle; + } +} + +double CBaseAP::GetCycleDifference() +{ + double dBaseDisplayCycle = GetDisplayCycle(); + double minDiff = 1.0; + if (dBaseDisplayCycle == 0.0 || m_dFrameCycle == 0.0) { + return 1.0; + } else { + for (UINT i = 1; i <= 8; i++) { // Try a lot of multiples of the display frequency + double dDisplayCycle = i * dBaseDisplayCycle; + double diff = (dDisplayCycle - m_dFrameCycle) / m_dFrameCycle; + if (abs(diff) < abs(minDiff)) { + minDiff = diff; + m_dOptimumDisplayCycle = dDisplayCycle; + } + } + } + return minDiff; +} + +void CBaseAP::EstimateRefreshTimings() +{ + if (m_pD3DDev) { + const CRenderersData* rd = GetRenderersData(); + D3DRASTER_STATUS rasterStatus; + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + while (rasterStatus.ScanLine != 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + while (rasterStatus.ScanLine == 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + LONGLONG startTime = rd->GetPerfCounter(); + UINT startLine = rasterStatus.ScanLine; + LONGLONG endTime = 0; + UINT endLine = 0; + bool done = false; + while (!done) { // Estimate time for one scan line + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + UINT line = rasterStatus.ScanLine; + LONGLONG time = rd->GetPerfCounter(); + if (line > 0) { + endLine = line; + endTime = time; + } else { + done = true; + } + } + m_dDetectedScanlineTime = (endTime - startTime) / ((endLine - startLine) * 10000.0); + + // Estimate the display refresh rate from the vsyncs + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + while (rasterStatus.ScanLine != 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + // Now we're at the start of a vsync + startTime = rd->GetPerfCounter(); + UINT i; + for (i = 1; i <= 50; i++) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + while (rasterStatus.ScanLine == 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + while (rasterStatus.ScanLine != 0) { + m_pD3DDev->GetRasterStatus(0, &rasterStatus); + } + // Now we're at the next vsync + } + endTime = rd->GetPerfCounter(); + m_dEstRefreshCycle = (endTime - startTime) / ((i - 1) * 10000.0); + } +} + +bool CBaseAP::ExtractInterlaced(const AM_MEDIA_TYPE* pmt) +{ + if (pmt->formattype == FORMAT_VideoInfo) { + return false; + } else if (pmt->formattype == FORMAT_VideoInfo2) { + return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; + } else if (pmt->formattype == FORMAT_MPEGVideo) { + return false; + } else if (pmt->formattype == FORMAT_MPEG2Video) { + return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0; + } else { + return false; + } +} + +HRESULT CBaseAP::Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect) { + HRESULT hr = E_FAIL; + + const CRenderersSettings& r = GetRenderersSettings(); + + DWORD iDX9Resizer = r.iDX9Resizer; + Vector dst[4]; + Transform(destRect, dst); + + if (iDX9Resizer == 0 || iDX9Resizer == 1) { + D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR; + hr = TextureResize(pTexture, dst, Filter, srcRect); + } else if (iDX9Resizer == 2) { + hr = TextureResizeBilinear(pTexture, dst, srcRect); + } else if (iDX9Resizer >= 3) { + hr = TextureResizeBicubic1pass(pTexture, dst, srcRect); + } + + return hr; +} + +STDMETHODIMP CBaseAP::GetDIB(BYTE* lpDib, DWORD* size) +{ + CheckPointer(size, E_POINTER); + + // Keep a reference so that we can safely work on the surface + // without having to lock everything + CComPtr pVideoSurface; + { + CAutoLock cAutoLock(this); + CheckPointer(m_pVideoSurface[m_nCurSurface], E_FAIL); + pVideoSurface = m_pVideoSurface[m_nCurSurface]; + } + + HRESULT hr; + + D3DSURFACE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + if (FAILED(hr = pVideoSurface->GetDesc(&desc))) { + return hr; + } + + CSize framesize = GetVideoSize(false); + const CSize dar = GetVideoSize(true); + + bool resize = false; + if (dar.cx > 0 && dar.cy > 0 && (dar.cx != desc.Width || dar.cy != desc.Height)) { + framesize.cx = MulDiv(framesize.cy, dar.cx, dar.cy); + resize = true; + desc.Width = framesize.cx; + desc.Height = framesize.cy; + } + + DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3); + if (!lpDib) { + *size = required; + return S_OK; + } + if (*size < required) { + return E_OUTOFMEMORY; + } + *size = required; + + CComPtr pSurface, tSurface; + // Convert to 8-bit when using 10-bit or full/half processing modes + if (desc.Format != D3DFMT_X8R8G8B8) { + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tSurface, nullptr)) + || FAILED(hr = m_pD3DXLoadSurfaceFromSurface(tSurface, nullptr, nullptr, pVideoSurface, nullptr, nullptr, D3DX_DEFAULT, 0))) { + return hr; + } + } else { + tSurface = pVideoSurface; + } + + if (resize) { + CComPtr pVideoTexture = m_pVideoTexture[m_nCurSurface]; + if (FAILED(hr = m_pD3DDevEx->CreateRenderTarget(framesize.cx, framesize.cy, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pSurface, nullptr)) + || FAILED(hr = m_pD3DDevEx->SetRenderTarget(0, pSurface)) + || FAILED(hr = Resize(pVideoTexture, { CPoint(0, 0), m_nativeVideoSize }, { CPoint(0, 0), framesize }))) { + return hr; + } + } else { + pSurface = tSurface; + } + + D3DLOCKED_RECT r; + if (FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { + // If this fails, we try to use a surface allocated from the system memory + CComPtr pInputSurface = pSurface; + pSurface = nullptr; + if (FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, nullptr)) + || FAILED(hr = m_pD3DDev->GetRenderTargetData(pInputSurface, pSurface)) + || FAILED(hr = pSurface->LockRect(&r, nullptr, D3DLOCK_READONLY))) { + return hr; + } + } + + hr = CreateDIBFromSurfaceData(desc, r, lpDib); + + pSurface->UnlockRect(); + + return hr; +} + +STDMETHODIMP CBaseAP::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) +{ + return SetPixelShader2(pSrcData, pTarget, false); +} + +STDMETHODIMP CBaseAP::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) +{ + CAutoLock cRenderLock(&m_allocatorLock); + + CAtlList* pPixelShaders; + if (bScreenSpace) { + pPixelShaders = &m_pPixelShadersScreenSpace; + } else { + pPixelShaders = &m_pPixelShaders; + } + + if (!pSrcData && !pTarget) { + pPixelShaders->RemoveAll(); + m_pD3DDev->SetPixelShader(nullptr); + return S_OK; + } + + if (!pSrcData) { + return E_INVALIDARG; + } + + CExternalPixelShader Shader; + Shader.m_SourceData = pSrcData; + Shader.m_SourceTarget = pTarget; + + CComPtr pPixelShader; + + HRESULT hr = Shader.Compile(m_pPSC); + if (FAILED(hr)) { + return hr; + } + + pPixelShaders->AddTail(Shader); + Paint(true); + return S_OK; +} + +CSyncAP::CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) + : CBaseAP(hWnd, bFullscreen, hr, _Error) + , m_LastClockState(MFCLOCK_STATE_INVALID) + , m_dwVideoAspectRatioMode(MFVideoARMode_PreservePicture) + , m_dwVideoRenderPrefs((MFVideoRenderPrefs)0) + , m_BorderColor(RGB(0, 0, 0)) + , m_hEvtQuit(nullptr) + , m_bEvtQuit(0) + , m_hEvtFlush(nullptr) + , m_bEvtFlush(0) + , m_hEvtSkip(nullptr) + , m_bEvtSkip(false) + , m_bUseInternalTimer(false) + , m_LastSetOutputRange(-1) + , m_bPendingRenegotiate(false) + , m_bPendingMediaFinished(false) + , m_bPrerolled(false) + , m_hRenderThread(nullptr) + , m_hMixerThread(nullptr) + , m_nRenderState(Shutdown) + , m_bStepping(false) + , m_nCurrentGroupId(0) + , m_nResetToken(0) + , m_nStepCount(0) + , m_SampleFreeCallback(this, &CSyncAP::OnSampleFree) + , fnDXVA2CreateDirect3DDeviceManager9(_T("dxva2.dll"), "DXVA2CreateDirect3DDeviceManager9") + , fnMFCreateDXSurfaceBuffer(_T("evr.dll"), "MFCreateDXSurfaceBuffer") + , fnMFCreateVideoSampleFromSurface(_T("evr.dll"), "MFCreateVideoSampleFromSurface") + , fnMFCreateMediaType(_T("mfplat.dll"), "MFCreateMediaType") + , fnAvSetMmThreadCharacteristicsW(_T("avrt.dll"), "AvSetMmThreadCharacteristicsW") + , fnAvSetMmThreadPriority(_T("avrt.dll"), "AvSetMmThreadPriority") + , fnAvRevertMmThreadCharacteristics(_T("avrt.dll"), "AvRevertMmThreadCharacteristics") +{ + const CRenderersSettings& r = GetRenderersSettings(); + + if (FAILED(hr)) { + _Error += L"SyncAP failed\n"; + return; + } + + if (!fnDXVA2CreateDirect3DDeviceManager9 || !fnMFCreateDXSurfaceBuffer || !fnMFCreateVideoSampleFromSurface || !fnMFCreateMediaType) { + if (!fnDXVA2CreateDirect3DDeviceManager9) { + _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n"; + } + if (!fnMFCreateDXSurfaceBuffer) { + _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n"; + } + if (!fnMFCreateVideoSampleFromSurface) { + _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n"; + } + if (!fnMFCreateMediaType) { + _Error += L"Could not find MFCreateMediaType (mfplat.dll)\n"; + } + hr = E_FAIL; + return; + } + + // Init DXVA manager + hr = fnDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager); + if (SUCCEEDED(hr) && m_pD3DManager) { + hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); + if (FAILED(hr)) { + _Error += L"m_pD3DManager->ResetDevice failed\n"; + } + } else { + _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n"; + } + + // Bufferize frame only with 3D texture + if (r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) { + m_nDXSurface = std::max(std::min(r.iEvrBuffers, MAX_PICTURE_SLOTS - 2), 4); + } else { + m_nDXSurface = 1; + } + + m_pOuterEVR = nullptr; + m_lShiftToNearest = -1; // Illegal value to start with +} + +CSyncAP::~CSyncAP() +{ + StopWorkerThreads(); + m_pMediaType = nullptr; + m_pClock = nullptr; + m_pD3DManager = nullptr; + + if (m_bHookedNewSegment) { + UnhookNewSegment(); + } +} + +HRESULT CSyncAP::CheckShutdown() const +{ + if (m_nRenderState == Shutdown) { + return MF_E_SHUTDOWN; + } else { + return S_OK; + } +} + +void CSyncAP::StartWorkerThreads() +{ + DWORD dwThreadId; + if (m_nRenderState == Shutdown) { + m_hEvtQuit = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hEvtFlush = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hEvtSkip = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hMixerThread = ::CreateThread(nullptr, 0, MixerThreadStatic, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hMixerThread, THREAD_PRIORITY_HIGHEST); + m_hRenderThread = ::CreateThread(nullptr, 0, RenderThreadStatic, (LPVOID)this, 0, &dwThreadId); + SetThreadPriority(m_hRenderThread, THREAD_PRIORITY_TIME_CRITICAL); + m_nRenderState = Stopped; + } +} + +void CSyncAP::StopWorkerThreads() +{ + if (m_nRenderState != Shutdown) { + SetEvent(m_hEvtFlush); + m_bEvtFlush = true; + SetEvent(m_hEvtQuit); + m_bEvtQuit = true; + SetEvent(m_hEvtSkip); + m_bEvtSkip = true; + + if (m_hRenderThread && WaitForSingleObject(m_hRenderThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hRenderThread, 0xDEAD); + } + + SAFE_CLOSE_HANDLE(m_hRenderThread); + + if (m_hMixerThread && WaitForSingleObject(m_hMixerThread, 10000) == WAIT_TIMEOUT) { + ASSERT(FALSE); + TerminateThread(m_hMixerThread, 0xDEAD); + } + + SAFE_CLOSE_HANDLE(m_hMixerThread); + SAFE_CLOSE_HANDLE(m_hEvtFlush); + SAFE_CLOSE_HANDLE(m_hEvtQuit); + SAFE_CLOSE_HANDLE(m_hEvtSkip); + + m_bEvtFlush = false; + m_bEvtQuit = false; + m_bEvtSkip = false; + } + m_nRenderState = Shutdown; +} + +STDMETHODIMP CSyncAP::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + *ppRenderer = nullptr; + HRESULT hr = E_FAIL; + + do { + CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; + + CSyncRenderer* pOuterEVR = DEBUG_NEW CSyncRenderer(NAME("CSyncRenderer"), pUnk, hr, &m_VMR9AlphaBitmap, this); + m_pOuterEVR = pOuterEVR; + + pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR); + CComQIPtr pBF = pUnk; + + if (FAILED(hr)) { + break; + } + + // Set EVR custom presenter + CComPtr pVP; + CComPtr pMFVR; + CComQIPtr pMFGS = pBF; + CComQIPtr pConfig = pBF; + if (SUCCEEDED(hr)) { + if (FAILED(pConfig->SetNumberOfStreams(3))) { // TODO - maybe need other number of input stream ... + break; + } + } + + hr = pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVR)); + + if (SUCCEEDED(hr)) { + hr = QueryInterface(IID_PPV_ARGS(&pVP)); + } + if (SUCCEEDED(hr)) { + hr = pMFVR->InitializeRenderer(nullptr, pVP); + } + + if (SUCCEEDED(hr)) { + CComPtr pPin = GetFirstPin(pBF); + if (HookNewSegment((IPinC*)(IPin*)pPin)) { + m_bUseInternalTimer = true; + m_bHookedNewSegment = true; + } + *ppRenderer = pBF.Detach(); + } else { + *ppRenderer = nullptr; + } + } while (0); + + return hr; +} + +STDMETHODIMP_(bool) CSyncAP::Paint(bool bAll) +{ + return __super::Paint(bAll); +} + +STDMETHODIMP_(bool) CSyncAP::Paint(IMFSample* pMFSample) +{ + m_pCurrentlyDisplayedSample = pMFSample; + pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface); + + auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { + UINT32 nGroupId; + return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); + }; + ASSERT(sampleHasCurrentGroupId(pMFSample)); + + return Paint(true); +} + +STDMETHODIMP CSyncAP::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + HRESULT hr; + if (riid == __uuidof(IMFClockStateSink)) { + hr = GetInterface((IMFClockStateSink*)this, ppv); + } else if (riid == __uuidof(IMFVideoPresenter)) { + hr = GetInterface((IMFVideoPresenter*)this, ppv); + } else if (riid == __uuidof(IMFTopologyServiceLookupClient)) { + hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv); + } else if (riid == __uuidof(IMFVideoDeviceID)) { + hr = GetInterface((IMFVideoDeviceID*)this, ppv); + } else if (riid == __uuidof(IMFGetService)) { + hr = GetInterface((IMFGetService*)this, ppv); + } else if (riid == __uuidof(IMFAsyncCallback)) { + hr = GetInterface((IMFAsyncCallback*)this, ppv); + } else if (riid == __uuidof(IMFVideoDisplayControl)) { + hr = GetInterface((IMFVideoDisplayControl*)this, ppv); + } else if (riid == __uuidof(IEVRTrustedVideoPlugin)) { + hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv); + } else if (riid == IID_IQualProp) { + hr = GetInterface((IQualProp*)this, ppv); + } else if (riid == __uuidof(IMFRateSupport)) { + hr = GetInterface((IMFRateSupport*)this, ppv); + } else if (riid == __uuidof(IDirect3DDeviceManager9)) { + hr = m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppv); + } else if (riid == __uuidof(ISyncClockAdviser)) { + hr = GetInterface((ISyncClockAdviser*)this, ppv); + } else if (riid == __uuidof(ID3DFullscreenControl)) { + hr = GetInterface((ID3DFullscreenControl*)this, ppv); + } else { + hr = __super::NonDelegatingQueryInterface(riid, ppv); + } + + return hr; +} + +// IMFClockStateSink +STDMETHODIMP CSyncAP::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + m_nRenderState = Started; + return S_OK; +} + +STDMETHODIMP CSyncAP::OnClockStop(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + m_nRenderState = Stopped; + return S_OK; +} + +STDMETHODIMP CSyncAP::OnClockPause(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + m_nRenderState = Paused; + return S_OK; +} + +STDMETHODIMP CSyncAP::OnClockRestart(MFTIME hnsSystemTime) +{ + HRESULT hr; + CHECK_HR(CheckShutdown()); + m_nRenderState = Started; + return S_OK; +} + +STDMETHODIMP CSyncAP::OnClockSetRate(MFTIME hnsSystemTime, float flRate) +{ + return E_NOTIMPL; +} + +// IBaseFilter delegate +bool CSyncAP::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue) +{ + CAutoLock lock(&m_SampleQueueLock); + switch (m_nRenderState) { + case Started: + *State = State_Running; + break; + case Paused: + *State = State_Paused; + break; + case Stopped: + *State = State_Stopped; + break; + default: + *State = State_Stopped; + _ReturnValue = E_FAIL; + } + _ReturnValue = S_OK; + return true; +} + +// IQualProp +STDMETHODIMP CSyncAP::get_FramesDroppedInRenderer(int* pcFrames) +{ + *pcFrames = m_pcFramesDropped; + return S_OK; +} + +STDMETHODIMP CSyncAP::get_FramesDrawn(int* pcFramesDrawn) +{ + *pcFramesDrawn = m_pcFramesDrawn; + return S_OK; +} + +STDMETHODIMP CSyncAP::get_AvgFrameRate(int* piAvgFrameRate) +{ + *piAvgFrameRate = (int)(m_fAvrFps * 100); + return S_OK; +} + +STDMETHODIMP CSyncAP::get_Jitter(int* iJitter) +{ + *iJitter = (int)((m_fJitterStdDev / 10000.0) + 0.5); + return S_OK; +} + +STDMETHODIMP CSyncAP::get_AvgSyncOffset(int* piAvg) +{ + *piAvg = (int)((m_fSyncOffsetAvr / 10000.0) + 0.5); + return S_OK; +} + +STDMETHODIMP CSyncAP::get_DevSyncOffset(int* piDev) +{ + *piDev = (int)((m_fSyncOffsetStdDev / 10000.0) + 0.5); + return S_OK; +} + +// IMFRateSupport +STDMETHODIMP CSyncAP::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) +{ + *pflRate = 0; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate) +{ + HRESULT hr = S_OK; + float fMaxRate = 0.0f; + + CAutoLock lock(this); + + CheckPointer(pflRate, E_POINTER); + CHECK_HR(CheckShutdown()); + + // Get the maximum forward rate. + fMaxRate = GetMaxRate(fThin); + + // For reverse playback, swap the sign. + if (eDirection == MFRATE_REVERSE) { + fMaxRate = -fMaxRate; + } + + *pflRate = fMaxRate; + return hr; +} + +STDMETHODIMP CSyncAP::IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate) +{ + // fRate can be negative for reverse playback. + // pfNearestSupportedRate can be NULL. + CAutoLock lock(this); + HRESULT hr = S_OK; + float fMaxRate = 0.0f; + float fNearestRate = flRate; // Default. + + CheckPointer(pflNearestSupportedRate, E_POINTER); + CHECK_HR(CheckShutdown()); + + // Find the maximum forward rate. + fMaxRate = GetMaxRate(fThin); + + if (fabsf(flRate) > fMaxRate) { + // The (absolute) requested rate exceeds the maximum rate. + hr = MF_E_UNSUPPORTED_RATE; + + // The nearest supported rate is fMaxRate. + fNearestRate = fMaxRate; + if (flRate < 0) { + // For reverse playback, swap the sign. + fNearestRate = -fNearestRate; + } + } + // Return the nearest supported rate if the caller requested it. + if (pflNearestSupportedRate != nullptr) { + *pflNearestSupportedRate = fNearestRate; + } + return hr; +} + +float CSyncAP::GetMaxRate(BOOL bThin) +{ + float fMaxRate = FLT_MAX; // Default. + UINT32 fpsNumerator = 0, fpsDenominator = 0; + + if (!bThin && m_pMediaType) { + // Non-thinned: Use the frame rate and monitor refresh rate. + + // Frame rate: + MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE, + &fpsNumerator, &fpsDenominator); + + // Monitor refresh rate: + UINT MonitorRateHz = m_refreshRate; // D3DDISPLAYMODE + + if (fpsDenominator && fpsNumerator && MonitorRateHz) { + // Max Rate = Refresh Rate / Frame Rate + fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator); + } + } + return fMaxRate; +} + +void CSyncAP::CompleteFrameStep(bool bCancel) +{ + if (m_nStepCount > 0) { + if (bCancel || (m_nStepCount == 1)) { + m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0); + m_nStepCount = 0; + } else { + m_nStepCount--; + } + } +} + +// IMFVideoPresenter +STDMETHODIMP CSyncAP::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) +{ + HRESULT hr = S_OK; + CHECK_HR(CheckShutdown()); + + switch (eMessage) { + case MFVP_MESSAGE_BEGINSTREAMING: + hr = BeginStreaming(); + m_llHysteresis = 0; + m_lShiftToNearest = 0; + m_bStepping = false; + break; + + case MFVP_MESSAGE_CANCELSTEP: + m_bStepping = false; + CompleteFrameStep(true); + break; + + case MFVP_MESSAGE_ENDOFSTREAM: + m_bPendingMediaFinished = true; + break; + + case MFVP_MESSAGE_ENDSTREAMING: + m_pGenlock->ResetTiming(); + m_pRefClock = nullptr; + m_nRenderState = Stopped; + break; + + case MFVP_MESSAGE_FLUSH: + SetEvent(m_hEvtFlush); + m_bEvtFlush = true; + while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0) { + ; + } + break; + + case MFVP_MESSAGE_INVALIDATEMEDIATYPE: + m_bPendingRenegotiate = true; + while (m_bPendingRenegotiate) { + Sleep(1); + } + break; + + case MFVP_MESSAGE_PROCESSINPUTNOTIFY: + break; + + case MFVP_MESSAGE_STEP: + m_nStepCount = (int)ulParam; + m_bStepping = true; + break; + + default: + ASSERT(FALSE); + break; + } + return hr; +} + +HRESULT CSyncAP::IsMediaTypeSupported(IMFMediaType* pMixerType) +{ + HRESULT hr; + AM_MEDIA_TYPE* pAMMedia; + UINT nInterlaceMode; + + CHECK_HR(pMixerType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); + CHECK_HR(pMixerType->GetUINT32(MF_MT_INTERLACE_MODE, &nInterlaceMode)); + + if ((pAMMedia->majortype != MEDIATYPE_Video)) { + hr = MF_E_INVALIDMEDIATYPE; + } + pMixerType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); + return hr; +} + +HRESULT CSyncAP::CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType) +{ + HRESULT hr; + IMFMediaType* pOptimalMediaType; + + CHECK_HR(fnMFCreateMediaType(&pOptimalMediaType)); + CHECK_HR(pMixerProposedType->CopyAllItems(pOptimalMediaType)); + + const GUID colorAttributes[] = { + MF_MT_VIDEO_LIGHTING, + MF_MT_VIDEO_PRIMARIES, + MF_MT_TRANSFER_FUNCTION, + MF_MT_YUV_MATRIX, + MF_MT_VIDEO_CHROMA_SITING + }; + + auto copyAttribute = [](IMFAttributes * pFrom, IMFAttributes * pTo, REFGUID guidKey) { + PROPVARIANT val; + HRESULT hr = pFrom->GetItem(guidKey, &val); + + if (SUCCEEDED(hr)) { + hr = pTo->SetItem(guidKey, val); + PropVariantClear(&val); + } else if (hr == MF_E_ATTRIBUTENOTFOUND) { + hr = pTo->DeleteItem(guidKey); + } + return hr; + }; + + for (REFGUID guidKey : colorAttributes) { + if (FAILED(hr = copyAttribute(pMixerInputType, pOptimalMediaType, guidKey))) { + TRACE(_T("Copying color attribute %s failed: 0x%08x\n"), static_cast(CComBSTR(guidKey)), hr); + } + } + + pOptimalMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0); + + const CRenderersSettings& r = GetRenderersSettings(); + + UINT32 nominalRange; + if (SUCCEEDED(pMixerInputType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange)) + && nominalRange == MFNominalRange_0_255) { + // EVR mixer always assumes 16-235 input. Bug? + // To keep untouched 0-255 range and avoid unwanted expansion we need to request 16-235 as output. + // To get 16-235 output we need to request 48-208 as output. + nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_48_208 : MFNominalRange_16_235; + } else { + nominalRange = (r.m_AdvRendSets.iEVROutputRange == 1) ? MFNominalRange_16_235 : MFNominalRange_0_255; + } + pOptimalMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, nominalRange); + m_LastSetOutputRange = r.m_AdvRendSets.iEVROutputRange; + + ULARGE_INTEGER ui64Size; + pOptimalMediaType->GetUINT64(MF_MT_FRAME_SIZE, &ui64Size.QuadPart); + + CSize videoSize((LONG)ui64Size.HighPart, (LONG)ui64Size.LowPart); + MFVideoArea Area = GetArea(0, 0, videoSize.cx, videoSize.cy); + pOptimalMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea)); + + ULARGE_INTEGER ui64AspectRatio; + pOptimalMediaType->GetUINT64(MF_MT_PIXEL_ASPECT_RATIO, &ui64AspectRatio.QuadPart); + + UINT64 ui64ARx = UINT64(ui64AspectRatio.HighPart) * ui64Size.HighPart; + UINT64 ui64ARy = UINT64(ui64AspectRatio.LowPart) * ui64Size.LowPart; + UINT64 gcd = GCD(ui64ARx, ui64ARy); + if (gcd > 1) { + ui64ARx /= gcd; + ui64ARy /= gcd; + } + CSize aspectRatio((LONG)ui64ARx, (LONG)ui64ARy); + + if (videoSize != m_nativeVideoSize || aspectRatio != m_aspectRatio) { + SetVideoSize(videoSize, aspectRatio); + + // Notify the graph about the change + if (m_pSink) { + m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(m_nativeVideoSize.cx, m_nativeVideoSize.cy), 0); + } + } + + *ppType = pOptimalMediaType; + (*ppType)->AddRef(); + + return hr; +} + +HRESULT CSyncAP::SetMediaType(IMFMediaType* pType) +{ + HRESULT hr = S_OK; + AM_MEDIA_TYPE* pAMMedia = nullptr; + CString strTemp; + + CHECK_HR(CheckShutdown()); + + if (pType == nullptr) { + // Release + RemoveAllSamples(); + DeleteSurfaces(); + CAutoLock lock(this); + m_pMediaType = nullptr; + return hr; + } + + DWORD dwFlags = 0; + if (m_pMediaType && m_pMediaType->IsEqual(pType, &dwFlags) == S_OK) { + // Nothing to do + return hr; + } + + CHECK_HR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia)); + + hr = InitializeDevice(pAMMedia); + if (SUCCEEDED(hr)) { + CAutoLock lock(this); + m_pMediaType = pType; + + strTemp = GetMediaTypeName(pAMMedia->subtype); + strTemp.Replace(L"MEDIASUBTYPE_", L""); + m_strStatsMsg[MSG_MIXEROUT].Format(L"Mixer output : %s", strTemp.GetString()); + } + + pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia); + + return hr; +} + +LONGLONG CSyncAP::GetMediaTypeMerit(IMFMediaType* pMediaType) +{ + AM_MEDIA_TYPE* pAMMedia = nullptr; + MFVIDEOFORMAT* VideoFormat; + + HRESULT hr; + CHECK_HR(pMediaType->GetRepresentation(FORMAT_MFVideoFormat, (void**)&pAMMedia)); + VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat; + + LONGLONG Merit = 0; + switch (VideoFormat->surfaceInfo.Format) { + case FCC('NV12'): + Merit = 90000000; + break; + case FCC('YV12'): + Merit = 80000000; + break; + case FCC('YUY2'): + Merit = 70000000; + break; + case FCC('UYVY'): + Merit = 60000000; + break; + + case D3DFMT_X8R8G8B8: // Never opt for RGB + case D3DFMT_A8R8G8B8: + case D3DFMT_R8G8B8: + case D3DFMT_R5G6B5: + Merit = 0; + break; + default: + Merit = 1000; + break; + } + pMediaType->FreeRepresentation(FORMAT_MFVideoFormat, (void*)pAMMedia); + return Merit; +} + +HRESULT CSyncAP::RenegotiateMediaType() +{ + HRESULT hr = S_OK; + + CComPtr pMixerType; + CComPtr pMixerInputType; + CComPtr pType; + + if (!m_pMixer) { + return MF_E_INVALIDREQUEST; + } + + // Get the mixer's input type + hr = m_pMixer->GetInputCurrentType(0, &pMixerInputType); + if (SUCCEEDED(hr)) { + AM_MEDIA_TYPE* pMT; + hr = pMixerInputType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pMT); + if (SUCCEEDED(hr)) { + m_inputMediaType = *pMT; + pMixerInputType->FreeRepresentation(FORMAT_VideoInfo2, pMT); + } + } + + CInterfaceArray ValidMixerTypes; + // Loop through all of the mixer's proposed output types. + DWORD iTypeIndex = 0; + while ((hr != MF_E_NO_MORE_TYPES)) { + pMixerType = nullptr; + pType = nullptr; + + // Step 1. Get the next media type supported by mixer. + hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType); + if (FAILED(hr)) { + break; + } + // Step 2. Check if we support this media type. + if (SUCCEEDED(hr)) { + hr = IsMediaTypeSupported(pMixerType); + } + if (SUCCEEDED(hr)) { + hr = CreateOptimalOutputType(pMixerType, pMixerInputType, &pType); + } + // Step 4. Check if the mixer will accept this media type. + if (SUCCEEDED(hr)) { + hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY); + } + if (SUCCEEDED(hr)) { + LONGLONG Merit = GetMediaTypeMerit(pType); + + size_t nTypes = ValidMixerTypes.GetCount(); + size_t iInsertPos = 0; + for (size_t i = 0; i < nTypes; ++i) { + LONGLONG ThisMerit = GetMediaTypeMerit(ValidMixerTypes[i]); + if (Merit > ThisMerit) { + iInsertPos = i; + break; + } else { + iInsertPos = i + 1; + } + } + ValidMixerTypes.InsertAt(iInsertPos, pType); + } + } + + size_t nValidTypes = ValidMixerTypes.GetCount(); + for (size_t i = 0; i < nValidTypes; ++i) { + pType = ValidMixerTypes[i]; + } + + for (size_t i = 0; i < nValidTypes; ++i) { + pType = ValidMixerTypes[i]; + hr = SetMediaType(pType); + if (SUCCEEDED(hr)) { + hr = m_pMixer->SetOutputType(0, pType, 0); + // If something went wrong, clear the media type. + if (FAILED(hr)) { + SetMediaType(nullptr); + } else { + break; + } + } + } + + pMixerType = nullptr; + pType = nullptr; + return hr; +} + +bool CSyncAP::GetSampleFromMixer() +{ + MFT_OUTPUT_DATA_BUFFER dataBuffer; + HRESULT hr = S_OK; + DWORD dwStatus; + LONGLONG llClockBefore = 0; + LONGLONG llClockAfter = 0; + LONGLONG llMixerLatency; + + UINT dwSurface; + bool newSample = false; + + auto sampleHasCurrentGroupId = [this](IMFSample * pSample) { + UINT32 nGroupId; + return (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId); + }; + + while (SUCCEEDED(hr)) { // Get as many frames as there are and that we have samples for + CComPtr pSample; + if (FAILED(GetFreeSample(&pSample))) { // All samples are taken for the moment. Better luck next time + break; + } + + ZeroMemory(&dataBuffer, sizeof(dataBuffer)); + dataBuffer.pSample = pSample; + pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface); + ASSERT(sampleHasCurrentGroupId(pSample)); + + { + llClockBefore = GetRenderersData()->GetPerfCounter(); + hr = m_pMixer->ProcessOutput(0, 1, &dataBuffer, &dwStatus); + llClockAfter = GetRenderersData()->GetPerfCounter(); + } + + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { // There are no samples left in the mixer + AddToFreeList(pSample, false); + pSample = nullptr; // The sample should not be used after being queued + // Important: Release any events returned from the ProcessOutput method. + SAFE_RELEASE(dataBuffer.pEvents); + break; + } + + if (m_pSink) { + llMixerLatency = llClockAfter - llClockBefore; + m_pSink->Notify(EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0); + } + + newSample = true; + + if (GetRenderersData()->m_bTearingTest) { + RECT rcTearing; + + rcTearing.left = m_nTearingPos; + rcTearing.top = 0; + rcTearing.right = rcTearing.left + 4; + rcTearing.bottom = m_nativeVideoSize.cy; + m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + + rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; + rcTearing.right = rcTearing.left + 4; + m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; + } + + if (SUCCEEDED(TrackSample(pSample))) { + AddToScheduledList(pSample, false); // Schedule, then go back to see if there is more where that came from + pSample = nullptr; // The sample should not be used after being queued + } else { + ASSERT(FALSE); + } + + // Important: Release any events returned from the ProcessOutput method. + SAFE_RELEASE(dataBuffer.pEvents); + } + return newSample; +} + +STDMETHODIMP CSyncAP::GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType) +{ + HRESULT hr = S_OK; + CAutoLock lock(this); + CheckPointer(ppMediaType, E_POINTER); + CHECK_HR(CheckShutdown()); + + if (!m_pMediaType) { + return MF_E_NOT_INITIALIZED; + } + + CHECK_HR(m_pMediaType->QueryInterface(IID_PPV_ARGS(ppMediaType))); + return hr; +} + +// IMFTopologyServiceLookupClient +STDMETHODIMP CSyncAP::InitServicePointers(__in IMFTopologyServiceLookup* pLookup) +{ + DWORD dwObjects = 1; + pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_pMixer), &dwObjects); + pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pSink), &dwObjects); + pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pClock), &dwObjects); + StartWorkerThreads(); + return S_OK; +} + +STDMETHODIMP CSyncAP::ReleaseServicePointers() +{ + StopWorkerThreads(); + m_pMixer = nullptr; + m_pSink = nullptr; + m_pClock = nullptr; + return S_OK; +} + +// IMFVideoDeviceID +STDMETHODIMP CSyncAP::GetDeviceID(__out IID* pDeviceID) +{ + CheckPointer(pDeviceID, E_POINTER); + *pDeviceID = IID_IDirect3DDevice9; + return S_OK; +} + +// IMFGetService +STDMETHODIMP CSyncAP::GetService(__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppvObject) +{ + if (guidService == MR_VIDEO_RENDER_SERVICE) { + return NonDelegatingQueryInterface(riid, ppvObject); + } else if (guidService == MR_VIDEO_ACCELERATION_SERVICE) { + return m_pD3DManager->QueryInterface(__uuidof(IDirect3DDeviceManager9), (void**) ppvObject); + } + + return E_NOINTERFACE; +} + +// IMFAsyncCallback +STDMETHODIMP CSyncAP::GetParameters(__RPC__out DWORD* pdwFlags, __RPC__out DWORD* pdwQueue) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CSyncAP::Invoke(__RPC__in_opt IMFAsyncResult* pAsyncResult) +{ + return E_NOTIMPL; +} + +// IMFVideoDisplayControl +STDMETHODIMP CSyncAP::GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) +{ + if (pszVideo) { + pszVideo->cx = m_nativeVideoSize.cx; + pszVideo->cy = m_nativeVideoSize.cy; + } + if (pszARVideo) { + pszARVideo->cx = m_aspectRatio.cx; + pszARVideo->cy = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CSyncAP::GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) +{ + if (pszMin) { + pszMin->cx = 1; + pszMin->cy = 1; + } + + if (pszMax) { + D3DDISPLAYMODE d3ddm; + ZeroMemory(&d3ddm, sizeof(d3ddm)); + + if (SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D, m_hWnd), &d3ddm))) { + pszMax->cx = d3ddm.Width; + pszMax->cy = d3ddm.Height; + } + } + return S_OK; +} + +STDMETHODIMP CSyncAP::SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) +{ + return S_OK; +} + +STDMETHODIMP CSyncAP::GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) +{ + if (pnrcSource) { + pnrcSource->left = 0.0; + pnrcSource->top = 0.0; + pnrcSource->right = 1.0; + pnrcSource->bottom = 1.0; + } + if (prcDest) { + memcpy(prcDest, &m_videoRect, sizeof(m_videoRect)); //GetClientRect (m_hWnd, prcDest); + } + return S_OK; +} + +STDMETHODIMP CSyncAP::SetAspectRatioMode(DWORD dwAspectRatioMode) +{ + m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetAspectRatioMode(DWORD* pdwAspectRatioMode) +{ + CheckPointer(pdwAspectRatioMode, E_POINTER); + *pdwAspectRatioMode = m_dwVideoAspectRatioMode; + return S_OK; +} + +STDMETHODIMP CSyncAP::SetVideoWindow(HWND hwndVideo) +{ + if (m_hWnd != hwndVideo) { + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_allocatorLock); + + m_hWnd = hwndVideo; + m_bPendingResetDevice = true; + if (m_pSink) { + m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); + } + + SendResetRequest(); + } + return S_OK; +} + +STDMETHODIMP CSyncAP::GetVideoWindow(HWND* phwndVideo) +{ + CheckPointer(phwndVideo, E_POINTER); + *phwndVideo = m_hWnd; + return S_OK; +} + +STDMETHODIMP CSyncAP::RepaintVideo() +{ + Paint(true); + return S_OK; +} + +STDMETHODIMP CSyncAP::GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp) { + if (!pBih || !pDib || !pcbDib) { + return E_POINTER; + } + CheckPointer(m_pD3DDevEx, E_ABORT); + + HRESULT hr = S_OK; + const unsigned width = m_windowRect.Width(); + const unsigned height = m_windowRect.Height(); + const unsigned len = width * height * 4; + + memset(pBih, 0, sizeof(BITMAPINFOHEADER)); + pBih->biSize = sizeof(BITMAPINFOHEADER); + pBih->biWidth = width; + pBih->biHeight = height; + pBih->biBitCount = 32; + pBih->biPlanes = 1; + pBih->biSizeImage = DIBSIZE(*pBih); + + BYTE* p = (BYTE*)CoTaskMemAlloc(len); // only this allocator can be used + if (!p) { + return E_OUTOFMEMORY; + } + + CComPtr pBackBuffer; + CComPtr pDestSurface; + D3DLOCKED_RECT r; + if (FAILED(hr = m_pD3DDevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)) + || FAILED(hr = m_pD3DDevEx->CreateRenderTarget(width, height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pDestSurface, nullptr)) + || (FAILED(hr = m_pD3DDevEx->StretchRect(pBackBuffer, m_windowRect, pDestSurface, nullptr, D3DTEXF_NONE))) + || (FAILED(hr = pDestSurface->LockRect(&r, nullptr, D3DLOCK_READONLY)))) { + CString Error = GetWindowsErrorMessage(hr, nullptr); + TRACE_SR(L"CSyncAP::GetCurrentImage failed : %s", S_OK == hr ? L"S_OK" : Error.GetBuffer()); + CoTaskMemFree(p); + return hr; + } + + RetrieveBitmapData(width, height, 32, p ? (BYTE*)p : (BYTE*)(pBih + 1), (BYTE*)r.pBits, r.Pitch); + + pDestSurface->UnlockRect(); + + *pDib = p; + *pcbDib = len; + + return S_OK; +} + +STDMETHODIMP CSyncAP::SetBorderColor(COLORREF Clr) +{ + m_BorderColor = Clr; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetBorderColor(COLORREF* pClr) +{ + CheckPointer(pClr, E_POINTER); + *pClr = m_BorderColor; + return S_OK; +} + +STDMETHODIMP CSyncAP::SetRenderingPrefs(DWORD dwRenderFlags) +{ + m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetRenderingPrefs(DWORD* pdwRenderFlags) +{ + CheckPointer(pdwRenderFlags, E_POINTER); + *pdwRenderFlags = m_dwVideoRenderPrefs; + return S_OK; +} + +STDMETHODIMP CSyncAP::SetFullscreen(BOOL fFullscreen) +{ + m_bIsFullscreen = !!fFullscreen; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetFullscreen(BOOL* pfFullscreen) +{ + CheckPointer(pfFullscreen, E_POINTER); + *pfFullscreen = m_bIsFullscreen; + return S_OK; +} + +// IEVRTrustedVideoPlugin +STDMETHODIMP CSyncAP::IsInTrustedVideoMode(BOOL* pYes) +{ + CheckPointer(pYes, E_POINTER); + *pYes = TRUE; + return S_OK; +} + +STDMETHODIMP CSyncAP::CanConstrict(BOOL* pYes) +{ + CheckPointer(pYes, E_POINTER); + *pYes = TRUE; + return S_OK; +} + +STDMETHODIMP CSyncAP::SetConstriction(DWORD dwKPix) +{ + return S_OK; +} + +STDMETHODIMP CSyncAP::DisableImageExport(BOOL bDisable) +{ + return S_OK; +} + +// IDirect3DDeviceManager9 +STDMETHODIMP CSyncAP::ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken) +{ + HRESULT hr = m_pD3DManager->ResetDevice(pDevice, resetToken); + return hr; +} + +STDMETHODIMP CSyncAP::OpenDeviceHandle(HANDLE* phDevice) +{ + HRESULT hr = m_pD3DManager->OpenDeviceHandle(phDevice); + return hr; +} + +STDMETHODIMP CSyncAP::CloseDeviceHandle(HANDLE hDevice) +{ + HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice); + return hr; +} + +STDMETHODIMP CSyncAP::TestDevice(HANDLE hDevice) +{ + HRESULT hr = m_pD3DManager->TestDevice(hDevice); + return hr; +} + +STDMETHODIMP CSyncAP::LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock) +{ + HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock); + return hr; +} + +STDMETHODIMP CSyncAP::UnlockDevice(HANDLE hDevice, BOOL fSaveState) +{ + HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState); + return hr; +} + +STDMETHODIMP CSyncAP::GetVideoService(HANDLE hDevice, REFIID riid, void** ppService) +{ + HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService); + + if (riid == __uuidof(IDirectXVideoDecoderService)) { + UINT nNbDecoder = 5; + GUID* pDecoderGuid; + IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService; + pDXVAVideoDecoder->GetDecoderDeviceGuids(&nNbDecoder, &pDecoderGuid); + } else if (riid == __uuidof(IDirectXVideoProcessorService)) { + IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService; + UNREFERENCED_PARAMETER(pDXVAProcessor); + } + + return hr; +} + +STDMETHODIMP CSyncAP::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) +{ + // This function should be called... + ASSERT(FALSE); + + if (lpWidth) { + *lpWidth = m_nativeVideoSize.cx; + } + if (lpHeight) { + *lpHeight = m_nativeVideoSize.cy; + } + if (lpARWidth) { + *lpARWidth = m_aspectRatio.cx; + } + if (lpARHeight) { + *lpARHeight = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CSyncAP::InitializeDevice(AM_MEDIA_TYPE* pMediaType) +{ + HRESULT hr; + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_allocatorLock); + + RemoveAllSamples(); + DeleteSurfaces(); + + VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*) pMediaType->pbFormat; + int w = vih2->bmiHeader.biWidth; + int h = abs(vih2->bmiHeader.biHeight); + + SetVideoSize(CSize(w, h), m_aspectRatio); + if (m_bHighColorResolution) { + hr = AllocSurfaces(D3DFMT_A2R10G10B10); + } else { + hr = AllocSurfaces(D3DFMT_X8R8G8B8); + } + + for (int i = 0; i < m_nDXSurface; i++) { + CComPtr pMFSample; + hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); + if (SUCCEEDED(hr)) { + pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); + pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + m_FreeSamples.AddTail(pMFSample); + pMFSample = nullptr; // The sample should not be used after being queued + } + ASSERT(SUCCEEDED(hr)); + } + return hr; +} + +DWORD WINAPI CSyncAP::MixerThreadStatic(LPVOID lpParam) +{ + CSyncAP* pThis = (CSyncAP*) lpParam; + pThis->MixerThread(); + return 0; +} + +void CSyncAP::MixerThread() +{ + HANDLE hEvts[] = {m_hEvtQuit}; + bool bQuit = false; + TIMECAPS tc; + DWORD dwResolution; + + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + timeBeginPeriod(dwResolution); + + while (!bQuit) { + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, 1); + switch (dwObject) { + case WAIT_OBJECT_0: + bQuit = true; + break; + case WAIT_TIMEOUT: { + bool bNewSample; + { + CAutoLock AutoLock(&m_ImageProcessingLock); + bNewSample = GetSampleFromMixer(); + } + + if (m_rtTimePerFrame == 0 && bNewSample) { + // Use the code from VMR9 to get the movie fps, as this method is reliable. + CComPtr pPin; + CMediaType mt; + if (SUCCEEDED(m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) && + SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); + + m_bInterlaced = ExtractInterlaced(&mt); + + if (m_rtTimePerFrame > 0) { + m_fps = 10000000.0 / m_rtTimePerFrame; + } + } + + // Update internal subtitle clock + if (m_bUseInternalTimer && m_pSubPicQueue) { + m_pSubPicQueue->SetFPS(m_fps); + } + } + } + break; + } + } + timeEndPeriod(dwResolution); +} + +DWORD WINAPI CSyncAP::RenderThreadStatic(LPVOID lpParam) +{ + CSyncAP* pThis = (CSyncAP*)lpParam; + pThis->RenderThread(); + return 0; +} + +// Get samples that have been received and queued up by MixerThread() and present them at the correct time by calling Paint(). +void CSyncAP::RenderThread() +{ + HANDLE hEvts[] = {m_hEvtQuit, m_hEvtFlush, m_hEvtSkip}; + bool bQuit = false; + TIMECAPS tc; + CComPtr pNewSample; // The sample next in line to be presented + + // Tell Multimedia Class Scheduler we are doing threaded playback (increase priority) + HANDLE hAvrt = 0; + if (fnAvSetMmThreadCharacteristicsW) { + DWORD dwTaskIndex = 0; + hAvrt = fnAvSetMmThreadCharacteristicsW(L"Playback", &dwTaskIndex); + if (fnAvSetMmThreadPriority) { + fnAvSetMmThreadPriority(hAvrt, AVRT_PRIORITY_HIGH); + } + } + + // Set timer resolution + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + DWORD dwResolution = std::min(std::max(tc.wPeriodMin, 0u), tc.wPeriodMax); + VERIFY(timeBeginPeriod(dwResolution) == 0); + + auto SubPicSetTime = [&] { + if (!g_bExternalSubtitleTime) { + CSubPicAllocatorPresenterImpl::SetTime(g_tSegmentStart + m_llSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); + } + }; + + auto checkPendingMediaFinished = [this]() { + if (m_bPendingMediaFinished) { + CAutoLock lock(&m_SampleQueueLock); + if (m_ScheduledSamples.IsEmpty()) { + m_bPendingMediaFinished = false; + m_pSink->Notify(EC_COMPLETE, 0, 0); + } + } + }; + + while (!bQuit) { + m_lNextSampleWait = 1; // Default value for running this loop + int nSamplesLeft = 0; + bool stepForward = false; + LONG lDisplayCycle = (LONG)(GetDisplayCycle()); + LONG lDisplayCycle2 = (LONG)(GetDisplayCycle() / 2.0); // These are a couple of empirically determined constants used the control the "snap" function + LONG lDisplayCycle4 = (LONG)(GetDisplayCycle() / 4.0); + + const CRenderersSettings& r = GetRenderersSettings(); + double dTargetSyncOffset = (&r == nullptr) ? 12.0 : r.m_AdvRendSets.fTargetSyncOffset; + + if ((m_nRenderState == Started || !m_bPrerolled) && !pNewSample) { // If either streaming or the pre-roll sample and no sample yet fetched + if (SUCCEEDED(GetScheduledSample(&pNewSample, nSamplesLeft))) { // Get the next sample + m_llLastSampleTime = m_llSampleTime; + if (!m_bPrerolled) { + m_bPrerolled = true; // m_bPrerolled is a ticket to show one (1) frame immediately + m_lNextSampleWait = 0; // Present immediately + } else if (SUCCEEDED(pNewSample->GetSampleTime(&m_llSampleTime))) { // Get zero-based sample due time + if (m_llLastSampleTime == m_llSampleTime) { // In the rare case there are duplicate frames in the movie. There really shouldn't be but it happens. + checkPendingMediaFinished(); + pNewSample = nullptr; + m_lNextSampleWait = 0; + } else { + MFTIME llSystemTime; + LONGLONG llRefClockTime; + m_pClock->GetCorrelatedTime(0, &llRefClockTime, &llSystemTime); // Get zero-based reference clock time. llSystemTime is not used for anything here + m_lNextSampleWait = (LONG)((m_llSampleTime - llRefClockTime) / 10000); // Time left until sample is due, in ms + if (m_bStepping) { + m_lNextSampleWait = 0; + } else if (r.m_AdvRendSets.bSynchronizeNearest) { // Present at the closest "safe" occasion at dTargetSyncOffset ms before vsync to avoid tearing + if (m_lNextSampleWait < -lDisplayCycle) { // We have to allow slightly negative numbers at this stage. Otherwise we get "choking" when frame rate > refresh rate + SetEvent(m_hEvtSkip); + m_bEvtSkip = true; + } + REFERENCE_TIME rtRefClockTimeNow = 0; + if (m_pRefClock) { + m_pRefClock->GetTime(&rtRefClockTimeNow); // Reference clock time now + } + LONG lLastVsyncTime = (LONG)((m_llEstVBlankTime - rtRefClockTimeNow) / 10000); // Last vsync time relative to now + if (abs(lLastVsyncTime) > lDisplayCycle) { + lLastVsyncTime = - lDisplayCycle; // To even out glitches in the beginning + } + + LONGLONG llNextSampleWait = (LONGLONG)((lLastVsyncTime + GetDisplayCycle() - dTargetSyncOffset) * 10000); // Time from now util next safe time to Paint() + while ((llRefClockTime + llNextSampleWait) < (m_llSampleTime + m_llHysteresis)) { // While the proposed time is in the past of sample presentation time + llNextSampleWait = llNextSampleWait + (LONGLONG)(GetDisplayCycle() * 10000); // Try the next possible time, one display cycle ahead + } + m_lNextSampleWait = (LONG)(llNextSampleWait / 10000); + m_lShiftToNearestPrev = m_lShiftToNearest; + m_lShiftToNearest = (LONG)((llRefClockTime + llNextSampleWait - m_llSampleTime) / 10000); // The adjustment made to get to the sweet point in time, in ms + + // If m_lShiftToNearest is pushed a whole cycle into the future, then we are getting more frames + // than we can chew and we need to throw one away. We don't want to wait many cycles and skip many + // frames. + if (m_lShiftToNearest > (lDisplayCycle + 1)) { + SetEvent(m_hEvtSkip); + m_bEvtSkip = true; + } + + // We need to add a hysteresis to the control of the timing adjustment to avoid judder when + // presentation time is close to vsync and the renderer couldn't otherwise make up its mind + // whether to present before the vsync or after. That kind of indecisiveness leads to judder. + if (m_bSnapToVSync) { + + if ((m_lShiftToNearestPrev - m_lShiftToNearest) > lDisplayCycle2) { // If a step down in the m_lShiftToNearest function. Display slower than video. + m_bVideoSlowerThanDisplay = false; + m_llHysteresis = -(LONGLONG)lDisplayCycle4 * 10000; + } else if ((m_lShiftToNearest - m_lShiftToNearestPrev) > lDisplayCycle2) { // If a step up + m_bVideoSlowerThanDisplay = true; + m_llHysteresis = (LONGLONG)lDisplayCycle4 * 10000; + } else if ((m_lShiftToNearest < (3 * lDisplayCycle4)) && (m_lShiftToNearest > lDisplayCycle4)) { + m_llHysteresis = 0; // Reset when between 1/4 and 3/4 of the way either way + } + + if ((m_lShiftToNearest < lDisplayCycle2) && (m_llHysteresis > 0)) { + m_llHysteresis = 0; // Should never really be in this territory. + } + if (m_lShiftToNearest < 0) { + m_llHysteresis = 0; // A glitch might get us to a sticky state where both these numbers are negative. + } + if ((m_lShiftToNearest > lDisplayCycle2) && (m_llHysteresis < 0)) { + m_llHysteresis = 0; + } + } + } + + if (m_lNextSampleWait < 0) { // Skip late or duplicate sample. + SetEvent(m_hEvtSkip); + m_bEvtSkip = true; + } + + if (m_lNextSampleWait > 1000) { + m_lNextSampleWait = 1000; // So as to avoid full a full stop when sample is far in the future (shouldn't really happen). + } + } + } // if got new sample + } else { + checkPendingMediaFinished(); + } + } + // Wait for the next presentation time (m_lNextSampleWait) or some other event. + DWORD dwObject = WaitForMultipleObjects(_countof(hEvts), hEvts, FALSE, (DWORD)m_lNextSampleWait); + switch (dwObject) { + case WAIT_OBJECT_0: // Quit + bQuit = true; + break; + + case WAIT_OBJECT_0 + 1: // Flush + checkPendingMediaFinished(); + pNewSample = nullptr; + FlushSamples(); + m_bEvtFlush = false; + ResetEvent(m_hEvtFlush); + m_bPrerolled = false; + m_lShiftToNearest = 0; + stepForward = true; + break; + + case WAIT_OBJECT_0 + 2: // Skip sample + m_pcFramesDropped++; + m_llSampleTime = m_llLastSampleTime; // This sample will never be shown + m_bEvtSkip = false; + ResetEvent(m_hEvtSkip); + stepForward = true; + break; + + case WAIT_TIMEOUT: // Time to show the sample or something + if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != r.m_AdvRendSets.iEVROutputRange || m_bPendingRenegotiate) { + checkPendingMediaFinished(); + pNewSample = nullptr; + FlushSamples(); + RenegotiateMediaType(); + m_bPendingRenegotiate = false; + } + + if (m_bPendingResetDevice) { + checkPendingMediaFinished(); + pNewSample = nullptr; + SendResetRequest(); + } else if (m_nStepCount < 0) { + m_nStepCount = 0; + m_pcFramesDropped++; + stepForward = true; + } else if (pNewSample && (m_nStepCount > 0)) { + SubPicSetTime(); + Paint(pNewSample); + CompleteFrameStep(false); + m_pcFramesDrawn++; + stepForward = true; + } else if (pNewSample && !m_bStepping) { // When a stepped frame is shown, a new one is fetched that we don't want to show here while stepping + SubPicSetTime(); + Paint(pNewSample); + m_pcFramesDrawn++; + stepForward = true; + } + break; + } // switch + if (stepForward) { + checkPendingMediaFinished(); + pNewSample = nullptr; + } + } // while + pNewSample = nullptr; + timeEndPeriod(dwResolution); + if (fnAvRevertMmThreadCharacteristics) { + fnAvRevertMmThreadCharacteristics(hAvrt); + } +} + +STDMETHODIMP_(bool) CSyncAP::ResetDevice() +{ + CAutoLock lock(this); + CAutoLock lock2(&m_ImageProcessingLock); + CAutoLock cRenderLock(&m_allocatorLock); + + RemoveAllSamples(); + + bool bResult = __super::ResetDevice(); + + for (int i = 0; i < m_nDXSurface; i++) { + CComPtr pMFSample; + HRESULT hr = fnMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample); + if (SUCCEEDED(hr)) { + pMFSample->SetUINT32(GUID_GROUP_ID, m_nCurrentGroupId); + pMFSample->SetUINT32(GUID_SURFACE_INDEX, i); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + m_FreeSamples.AddTail(pMFSample); + pMFSample = nullptr; // The sample should not be used after being queued + } + ASSERT(SUCCEEDED(hr)); + } + return bResult; +} + +void CSyncAP::OnResetDevice() +{ + TRACE(_T("--> CSyncAP::OnResetDevice on thread: %lu\n"), GetCurrentThreadId()); + m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken); + if (m_pSink) { + m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0); + } + CSize videoSize = GetVisibleVideoSize(); + if (m_pSink) { + m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(videoSize.cx, videoSize.cy), 0); + } +} + +void CSyncAP::RemoveAllSamples() +{ + CAutoLock imageProcesssingLock(&m_ImageProcessingLock); + CAutoLock sampleQueueLock(&m_SampleQueueLock); + + FlushSamples(); + m_ScheduledSamples.RemoveAll(); + m_FreeSamples.RemoveAll(); + m_nUsedBuffer = 0; + // Increment the group id to make sure old samples will really be deleted + m_nCurrentGroupId++; +} + +HRESULT CSyncAP::GetFreeSample(IMFSample** ppSample) +{ + CAutoLock lock(&m_SampleQueueLock); + HRESULT hr = S_OK; + + if (!m_FreeSamples.IsEmpty()) { + m_nUsedBuffer++; + *ppSample = m_FreeSamples.RemoveHead().Detach(); + } else { + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + } + + return hr; +} + +HRESULT CSyncAP::GetScheduledSample(IMFSample** ppSample, int& count) +{ + CAutoLock lock(&m_SampleQueueLock); + HRESULT hr = S_OK; + + count = (int)m_ScheduledSamples.GetCount(); + if (count > 0) { + *ppSample = m_ScheduledSamples.RemoveHead().Detach(); + --count; + } else { + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + } + + return hr; +} + +void CSyncAP::AddToFreeList(IMFSample* pSample, bool bTail) +{ + CAutoLock lock(&m_SampleQueueLock); + + m_nUsedBuffer--; + if (bTail) { + m_FreeSamples.AddTail(pSample); + } else { + m_FreeSamples.AddHead(pSample); + } +} + +void CSyncAP::AddToScheduledList(IMFSample* pSample, bool bSorted) +{ + CAutoLock lock(&m_SampleQueueLock); + + if (bSorted) { + m_ScheduledSamples.AddHead(pSample); + } else { + m_ScheduledSamples.AddTail(pSample); + } +} + +void CSyncAP::FlushSamples() +{ + CAutoLock lock(this); + CAutoLock lock2(&m_SampleQueueLock); + + m_bPrerolled = false; + m_pCurrentlyDisplayedSample = nullptr; + m_ScheduledSamples.RemoveAll(); +} + +HRESULT CSyncAP::TrackSample(IMFSample* pSample) +{ + HRESULT hr = E_FAIL; + if (CComQIPtr pTracked = pSample) { + hr = pTracked->SetAllocator(&m_SampleFreeCallback, nullptr); + } + return hr; +} + +HRESULT CSyncAP::OnSampleFree(IMFAsyncResult* pResult) +{ + CComPtr pObject; + HRESULT hr = pResult->GetObject(&pObject); + if (SUCCEEDED(hr)) { + if (CComQIPtr pSample = pObject) { + // Ignore the sample if it is from an old group + UINT32 nGroupId; + CAutoLock sampleQueueLock(&m_SampleQueueLock); + if (SUCCEEDED(pSample->GetUINT32(GUID_GROUP_ID, &nGroupId)) && nGroupId == m_nCurrentGroupId) { + AddToFreeList(pSample, true); + pSample = nullptr; // The sample should not be used after being queued + } + } + } + return hr; +} + +HRESULT CSyncAP::AdviseSyncClock(ISyncClock* sC) +{ + return m_pGenlock->AdviseSyncClock(sC); +} + +HRESULT CSyncAP::BeginStreaming() +{ + m_pcFramesDropped = 0; + m_pcFramesDrawn = 0; + + CComPtr pEVR; + CFilterInfo filterInfo; + m_pOuterEVR->QueryInterface(IID_PPV_ARGS(&pEVR)); + pEVR->QueryFilterInfo(&filterInfo); + + BeginEnumFilters(filterInfo.pGraph, pEF, pBF); + if (CComQIPtr pAS = pBF) { + m_pAudioStats = pAS; + }; + EndEnumFilters; + + pEVR->GetSyncSource(&m_pRefClock); + m_pGenlock->SetMonitor(GetAdapter(m_pD3D, m_hWnd)); + m_pGenlock->GetTiming(); + + ResetStats(); + EstimateRefreshTimings(); + if (m_dFrameCycle > 0.0) { + m_dCycleDifference = GetCycleDifference(); // Might have moved to another display + } + + m_nRenderState = Paused; + + return S_OK; +} + +HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP) +{ + HRESULT hr = E_FAIL; + if (clsid == CLSID_SyncAllocatorPresenter) { + CString Error; + *ppAP = DEBUG_NEW CSyncAP(hWnd, bFullscreen, hr, Error); + (*ppAP)->AddRef(); + + if (FAILED(hr)) { + Error += L"\n"; + Error += GetWindowsErrorMessage(hr, nullptr); + MessageBox(hWnd, Error, L"Error creating EVR Sync", MB_OK | MB_ICONERROR); + (*ppAP)->Release(); + *ppAP = nullptr; + } else if (!Error.IsEmpty()) { + MessageBox(hWnd, Error, L"Warning creating EVR Sync", MB_OK | MB_ICONWARNING); + } + } + return hr; +} + +CSyncRenderer::CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP* pAllocatorPresenter): CUnknown(pName, pUnk) +{ + hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner()); + CComQIPtr pEVRBase = m_pEVR; + m_pEVRBase = pEVRBase; // Don't keep a second reference on the EVR filter + m_pVMR9AlphaBitmap = pVMR9AlphaBitmap; + m_pAllocatorPresenter = pAllocatorPresenter; +} + +CSyncRenderer::~CSyncRenderer() +{ +} + +HRESULT STDMETHODCALLTYPE CSyncRenderer::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetState(dwMilliSecsTimeout, State); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::EnumPins(__out IEnumPins** ppEnum) +{ + if (m_pEVRBase) { + return m_pEVRBase->EnumPins(ppEnum); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::FindPin(LPCWSTR Id, __out IPin** ppPin) +{ + if (m_pEVRBase) { + return m_pEVRBase->FindPin(Id, ppPin); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::QueryFilterInfo(__out FILTER_INFO* pInfo) +{ + if (m_pEVRBase) { + return m_pEVRBase->QueryFilterInfo(pInfo); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName) +{ + if (m_pEVRBase) { + return m_pEVRBase->JoinFilterGraph(pGraph, pName); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::QueryVendorInfo(__out LPWSTR* pVendorInfo) +{ + if (m_pEVRBase) { + return m_pEVRBase->QueryVendorInfo(pVendorInfo); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::Stop() +{ + if (m_pEVRBase) { + return m_pEVRBase->Stop(); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::Pause() +{ + if (m_pEVRBase) { + return m_pEVRBase->Pause(); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::Run(REFERENCE_TIME tStart) +{ + if (m_pEVRBase) { + return m_pEVRBase->Run(tStart); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::SetSyncSource(__in_opt IReferenceClock* pClock) +{ + if (m_pEVRBase) { + return m_pEVRBase->SetSyncSource(pClock); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::GetSyncSource(__deref_out_opt IReferenceClock** pClock) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetSyncSource(pClock); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::GetClassID(__RPC__out CLSID* pClassID) +{ + if (m_pEVRBase) { + return m_pEVRBase->GetClassID(pClassID); + } + return E_NOTIMPL; +} + +STDMETHODIMP CSyncRenderer::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap)); + return S_OK; +} + +STDMETHODIMP CSyncRenderer::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} + +STDMETHODIMP CSyncRenderer::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms) +{ + CheckPointer(pBmpParms, E_POINTER); + CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock); + memcpy(m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap)); + m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE; + m_pAllocatorPresenter->UpdateAlphaBitmap(); + return S_OK; +} + +STDMETHODIMP CSyncRenderer::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + HRESULT hr; + + if (riid == __uuidof(IVMRMixerBitmap9)) { + return GetInterface((IVMRMixerBitmap9*)this, ppv); + } + + if (riid == __uuidof(IBaseFilter)) { + return GetInterface((IBaseFilter*)this, ppv); + } + + if (riid == __uuidof(IMediaFilter)) { + return GetInterface((IMediaFilter*)this, ppv); + } + if (riid == __uuidof(IPersist)) { + return GetInterface((IPersist*)this, ppv); + } + if (riid == __uuidof(IBaseFilter)) { + return GetInterface((IBaseFilter*)this, ppv); + } + + hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE; + if (m_pEVR && FAILED(hr)) { + hr = m_pAllocatorPresenter ? m_pAllocatorPresenter->QueryInterface(riid, ppv) : E_NOINTERFACE; + } + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); +} + +CGenlock::CGenlock(double target, double limit, int lineD, int colD, double clockD, UINT mon) + : powerstripTimingExists(false) + , liveSource(false) + , adjDelta(0) // Number of rows used in display frequency adjustment, typically 1 (one) + , lineDelta(lineD) // Number of columns used in display frequency adjustment, typically 1 - 2 + , columnDelta(colD) // Delta used in clock speed adjustment. In fractions of 1.0. Typically around 0.001 + , cycleDelta(clockD) // The monitor to be adjusted if the display refresh rate is the controlled parameter + , displayAdjustmentsMade(0) + , clockAdjustmentsMade(0) + , totalLines(0) + , totalColumns(0) + , visibleLines(0) + , visibleColumns(0) + , syncOffsetFifo(64) + , frameCycleFifo(4) + , minSyncOffset(DBL_MAX) + , maxSyncOffset(DBL_MIN) + , syncOffsetAvg(0.0) + , minFrameCycle(DBL_MAX) + , maxFrameCycle(DBL_MIN) + , frameCycleAvg(0.0) + , pixelClock(0) + , displayFreqCruise(0.0) + , displayFreqSlower(0.0) + , displayFreqFaster(0.0) + , curDisplayFreq(0.0) + , controlLimit(limit) // How much sync offset is allowed to drift from target sync offset before control kicks in + , monitor(mon) + , psWnd(nullptr) + , displayTiming() + , displayTimingSave() + , lowSyncOffset(target - limit) + , targetSyncOffset(target) // Target sync offset, typically around 10 ms + , highSyncOffset(target + limit) +{ + ZeroMemory(faster, MAX_LOADSTRING); + ZeroMemory(cruise, MAX_LOADSTRING); + ZeroMemory(slower, MAX_LOADSTRING); + ZeroMemory(savedTiming, MAX_LOADSTRING); +} + +CGenlock::~CGenlock() +{ + ResetTiming(); + syncClock = nullptr; +}; + +BOOL CGenlock::PowerstripRunning() +{ + psWnd = FindWindow(_T("TPShidden"), nullptr); + if (!psWnd) { + return FALSE; // Powerstrip is not running + } else { + return TRUE; + } +} + +// Get the display timing parameters through PowerStrip (if running). +HRESULT CGenlock::GetTiming() +{ + ATOM getTiming; + LPARAM lParam = 0; + WPARAM wParam = monitor; + int i = 0; + int j = 0; + int params = 0; + TCHAR tmpStr[MAX_LOADSTRING] = _T(""); + + CAutoLock lock(&csGenlockLock); + if (!PowerstripRunning()) { + return E_FAIL; + } + + getTiming = static_cast(SendMessage(psWnd, UM_GETTIMING, wParam, lParam)); + GlobalGetAtomName(getTiming, savedTiming, MAX_LOADSTRING); + + while (params < TIMING_PARAM_CNT) { + while (savedTiming[i] != _T(',') && savedTiming[i] != _T('\0')) { + tmpStr[j++] = savedTiming[i]; + tmpStr[j] = _T('\0'); + i++; + } + i++; // Skip trailing comma + j = 0; + displayTiming[params] = _ttoi(tmpStr); + displayTimingSave[params] = displayTiming[params]; + params++; + } + + // The display update frequency is controlled by adding and subtracting pixels form the + // image. This is done by either subtracting columns or rows or both. Some displays like + // row adjustments and some column adjustments. One should probably not do both. + StringCchPrintf(faster, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), + displayTiming[0], + displayTiming[HFRONTPORCH] - columnDelta, + displayTiming[2], + displayTiming[3], + displayTiming[4], + displayTiming[VFRONTPORCH] - lineDelta, + displayTiming[6], + displayTiming[7], + displayTiming[PIXELCLOCK], + displayTiming[9] + ); + + // Nominal update frequency + StringCchPrintf(cruise, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), + displayTiming[0], + displayTiming[HFRONTPORCH], + displayTiming[2], + displayTiming[3], + displayTiming[4], + displayTiming[VFRONTPORCH], + displayTiming[6], + displayTiming[7], + displayTiming[PIXELCLOCK], + displayTiming[9] + ); + + // Lower than nominal update frequency + StringCchPrintf(slower, MAX_LOADSTRING, _T("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\0"), + displayTiming[0], + displayTiming[HFRONTPORCH] + columnDelta, + displayTiming[2], + displayTiming[3], + displayTiming[4], + displayTiming[VFRONTPORCH] + lineDelta, + displayTiming[6], + displayTiming[7], + displayTiming[PIXELCLOCK], + displayTiming[9] + ); + + totalColumns = displayTiming[HACTIVE] + displayTiming[HFRONTPORCH] + displayTiming[HSYNCWIDTH] + displayTiming[HBACKPORCH]; + totalLines = displayTiming[VACTIVE] + displayTiming[VFRONTPORCH] + displayTiming[VSYNCWIDTH] + displayTiming[VBACKPORCH]; + pixelClock = 1000 * displayTiming[PIXELCLOCK]; // Pixels/s + displayFreqCruise = (double)pixelClock / (totalLines * totalColumns); // Frames/s + displayFreqSlower = (double)pixelClock / ((totalLines + lineDelta) * (totalColumns + columnDelta)); + displayFreqFaster = (double)pixelClock / ((totalLines - lineDelta) * (totalColumns - columnDelta)); + curDisplayFreq = displayFreqCruise; + GlobalDeleteAtom(getTiming); + adjDelta = 0; + powerstripTimingExists = true; + return S_OK; +} + +// Reset display timing parameters to nominal. +HRESULT CGenlock::ResetTiming() +{ + CAutoLock lock(&csGenlockLock); + + if (!PowerstripRunning()) { + return E_FAIL; + } + + if (displayAdjustmentsMade > 0) { + ATOM setTiming = GlobalAddAtom(cruise); + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, monitor, (LPARAM)setTiming); + GlobalDeleteAtom(setTiming); + curDisplayFreq = displayFreqCruise; + } + adjDelta = 0; + return S_OK; +} + +// Reset reference clock speed to nominal. +HRESULT CGenlock::ResetClock() +{ + adjDelta = 0; + if (syncClock == nullptr) { + return E_FAIL; + } else { + return syncClock->AdjustClock(1.0); + } +} + +HRESULT CGenlock::SetTargetSyncOffset(double targetD) +{ + targetSyncOffset = targetD; + lowSyncOffset = targetD - controlLimit; + highSyncOffset = targetD + controlLimit; + return S_OK; +} + +HRESULT CGenlock::GetTargetSyncOffset(double* targetD) +{ + *targetD = targetSyncOffset; + return S_OK; +} + +HRESULT CGenlock::SetControlLimit(double cL) +{ + controlLimit = cL; + return S_OK; +} + +HRESULT CGenlock::GetControlLimit(double* cL) +{ + *cL = controlLimit; + return S_OK; +} + +HRESULT CGenlock::SetDisplayResolution(UINT columns, UINT lines) +{ + visibleColumns = columns; + visibleLines = lines; + return S_OK; +} + +HRESULT CGenlock::AdviseSyncClock(ISyncClock* sC) +{ + if (!sC) { + return E_FAIL; + } + if (syncClock) { + syncClock = nullptr; // Release any outstanding references if this is called repeatedly + } + syncClock = sC; + return S_OK; +} + +// Set the monitor to control. This is best done manually as not all monitors can be controlled +// so automatic detection of monitor to control might have unintended effects. +// The PowerStrip API uses zero-based monitor numbers, i.e. the default monitor is 0. +HRESULT CGenlock::SetMonitor(UINT mon) +{ + monitor = mon; + return S_OK; +} + +HRESULT CGenlock::ResetStats() +{ + CAutoLock lock(&csGenlockLock); + minSyncOffset = DBL_MAX; + maxSyncOffset = DBL_MIN; + minFrameCycle = DBL_MAX; + maxFrameCycle = DBL_MIN; + displayAdjustmentsMade = 0; + clockAdjustmentsMade = 0; + return S_OK; +} + +// Synchronize by adjusting display refresh rate +HRESULT CGenlock::ControlDisplay(double syncOffset, double frameCycle) +{ + LPARAM lParam = 0; + WPARAM wParam = monitor; + ATOM setTiming; + + const CRenderersSettings& r = GetRenderersSettings(); + targetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset; + lowSyncOffset = targetSyncOffset - r.m_AdvRendSets.fControlLimit; + highSyncOffset = targetSyncOffset + r.m_AdvRendSets.fControlLimit; + + syncOffsetAvg = syncOffsetFifo.Average(syncOffset); + minSyncOffset = std::min(minSyncOffset, syncOffset); + maxSyncOffset = std::max(maxSyncOffset, syncOffset); + frameCycleAvg = frameCycleFifo.Average(frameCycle); + minFrameCycle = std::min(minFrameCycle, frameCycle); + maxFrameCycle = std::max(maxFrameCycle, frameCycle); + + if (!PowerstripRunning() || !powerstripTimingExists) { + return E_FAIL; + } + // Adjust as seldom as possible by checking the current controlState before changing it. + if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1)) + // Speed up display refresh rate by subtracting pixels from the image. + { + adjDelta = 1; // Increase refresh rate + curDisplayFreq = displayFreqFaster; + setTiming = GlobalAddAtom(faster); + lParam = setTiming; + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); + GlobalDeleteAtom(setTiming); + displayAdjustmentsMade++; + } else + // Slow down display refresh rate by adding pixels to the image. + if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1)) { + adjDelta = -1; + curDisplayFreq = displayFreqSlower; + setTiming = GlobalAddAtom(slower); + lParam = setTiming; + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); + GlobalDeleteAtom(setTiming); + displayAdjustmentsMade++; + } else + // Cruise. + if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1)) { + adjDelta = 0; + curDisplayFreq = displayFreqCruise; + setTiming = GlobalAddAtom(cruise); + lParam = setTiming; + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); + GlobalDeleteAtom(setTiming); + displayAdjustmentsMade++; + } else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1)) { + adjDelta = 0; + curDisplayFreq = displayFreqCruise; + setTiming = GlobalAddAtom(cruise); + lParam = setTiming; + SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam); + GlobalDeleteAtom(setTiming); + displayAdjustmentsMade++; + } + return S_OK; +} + +// Synchronize by adjusting reference clock rate (and therefore video FPS). +// Todo: check so that we don't have a live source +HRESULT CGenlock::ControlClock(double syncOffset, double frameCycle) +{ + const CRenderersSettings& r = GetRenderersSettings(); + targetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset; + lowSyncOffset = targetSyncOffset - r.m_AdvRendSets.fControlLimit; + highSyncOffset = targetSyncOffset + r.m_AdvRendSets.fControlLimit; + + syncOffsetAvg = syncOffsetFifo.Average(syncOffset); + minSyncOffset = std::min(minSyncOffset, syncOffset); + maxSyncOffset = std::max(maxSyncOffset, syncOffset); + frameCycleAvg = frameCycleFifo.Average(frameCycle); + minFrameCycle = std::min(minFrameCycle, frameCycle); + maxFrameCycle = std::max(maxFrameCycle, frameCycle); + + if (!syncClock) { + return E_FAIL; + } + // Adjust as seldom as possible by checking the current controlState before changing it. + if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1)) + // Slow down video stream. + { + adjDelta = 1; + syncClock->AdjustClock(1.0 - cycleDelta); // Makes the clock move slower by providing smaller increments + clockAdjustmentsMade++; + } else + // Speed up video stream. + if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1)) { + adjDelta = -1; + syncClock->AdjustClock(1.0 + cycleDelta); + clockAdjustmentsMade++; + } else + // Cruise. + if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1)) { + adjDelta = 0; + syncClock->AdjustClock(1.0); + clockAdjustmentsMade++; + } else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1)) { + adjDelta = 0; + syncClock->AdjustClock(1.0); + clockAdjustmentsMade++; + } + return S_OK; +} + +// Don't adjust anything, just update the syncOffset stats +HRESULT CGenlock::UpdateStats(double syncOffset, double frameCycle) +{ + syncOffsetAvg = syncOffsetFifo.Average(syncOffset); + minSyncOffset = std::min(minSyncOffset, syncOffset); + maxSyncOffset = std::max(maxSyncOffset, syncOffset); + frameCycleAvg = frameCycleFifo.Average(frameCycle); + minFrameCycle = std::min(minFrameCycle, frameCycle); + maxFrameCycle = std::max(maxFrameCycle, frameCycle); + return S_OK; +} + +STDMETHODIMP CSyncAP::SetD3DFullscreen(bool fEnabled) +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_allocatorLock); + + fullScreenChanged = (fEnabled != m_bIsFullscreen); + m_bIsFullscreen = fEnabled; + return S_OK; +} + +STDMETHODIMP CSyncAP::GetD3DFullscreen(bool* pfEnabled) +{ + CheckPointer(pfEnabled, E_POINTER); + *pfEnabled = m_bIsFullscreen; + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/SyncRenderer.h b/src/filters/renderer/VideoRenderers/SyncRenderer.h index 8ec1120e38c..f0f176b8ab9 100644 --- a/src/filters/renderer/VideoRenderers/SyncRenderer.h +++ b/src/filters/renderer/VideoRenderers/SyncRenderer.h @@ -1,686 +1,686 @@ -/* - * (C) 2010-2015, 2017 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 . - * - */ - -#pragma once - -#include "../../../SubPic/ISubPic.h" -#include "RenderersSettings.h" -#include "SyncAllocatorPresenter.h" -#include "AllocatorCommon.h" -#include "../../../DSUtil/WinapiFunc.h" -#include -#include -#include "d3dx9/d3dx9.h" - -#define VMRBITMAP_UPDATE 0x80000000 -#define MAX_PICTURE_SLOTS (60 + 2) // Last 2 for pixels shader! -#define NB_JITTER 126 -#include "AsyncCallback.h" - -class CFocusThread; - -// Possible messages to the PowerStrip API. PowerStrip is used to control -// the display frequency in one of the video - display synchronization modes. -// Powerstrip can also through a CGenlock object give very accurate timing data -// (given) that the gfx board is supported by PS. -#define UM_SETCUSTOMTIMING (WM_USER + 200) -#define UM_SETREFRESHRATE (WM_USER + 201) -#define UM_SETPOLARITY (WM_USER + 202) -#define UM_REMOTECONTROL (WM_USER + 210) -#define UM_SETGAMMARAMP (WM_USER + 203) -#define UM_CREATERESOLUTION (WM_USER + 204) -#define UM_GETTIMING (WM_USER + 205) -#define UM_SETCUSTOMTIMINGFAST (WM_USER + 211) // Sets timing without writing to file. Faster - -#define PositiveHorizontalPolarity 0x00 -#define PositiveVerticalPolarity 0x00 -#define NegativeHorizontalPolarity 0x02 -#define NegativeVerticalPolarity 0x04 -#define HideTrayIcon 0x00 -#define ShowTrayIcon 0x01 -#define ClosePowerStrip 0x63 - -#define HACTIVE 0 -#define HFRONTPORCH 1 -#define HSYNCWIDTH 2 -#define HBACKPORCH 3 -#define VACTIVE 4 -#define VFRONTPORCH 5 -#define VSYNCWIDTH 6 -#define VBACKPORCH 7 -#define PIXELCLOCK 8 -#define UNKNOWN 9 - -// Guid to tag IMFSample with a group id -static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } }; -// Guid to tag IMFSample with DirectX surface index -static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } }; - -namespace GothSync -{ - enum EVR_STATS_MSG { - MSG_MIXERIN, - MSG_MIXEROUT, - MSG_ERROR - }; - -#pragma pack(push, 1) - - template - struct MYD3DVERTEX { - float x, y, z, rhw; - struct { - float u, v; - } t[texcoords]; - }; - - template<> - struct MYD3DVERTEX<0> { - float x, y, z, rhw; - DWORD Diffuse; - }; - -#pragma pack(pop) - - class CGenlock; - class CSyncRenderer; - - // Base allocator-presenter - class CBaseAP: - public CSubPicAllocatorPresenterImpl - { - protected: - CRenderersSettings::CAdvRendererSettings m_LastRendererSettings; - - HMODULE m_hDWMAPI; - HRESULT(__stdcall* m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled); - HRESULT(__stdcall* m_pDwmEnableComposition)(UINT uCompositionAction); - - CCritSec m_allocatorLock; - CComPtr m_pD3DEx; - CComPtr m_pD3D; - CComPtr m_pD3DDevEx; - CComPtr m_pD3DDev; - - CComPtr m_pVideoTexture[MAX_PICTURE_SLOTS]; - CComPtr m_pVideoSurface[MAX_PICTURE_SLOTS]; - CComPtr m_pOSDTexture; - CComPtr m_pOSDSurface; - CComPtr m_pLine; - CComPtr m_pFont; - CComPtr m_pSprite; - CSyncRenderer* m_pOuterEVR; - - class CExternalPixelShader - { - public: - CComPtr m_pPixelShader; - CStringA m_SourceData; - CStringA m_SourceTarget; - HRESULT Compile(CPixelShaderCompiler* pCompiler) { - HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); - if (FAILED(hr)) { - return hr; - } - return S_OK; - } - }; - - CAutoPtr m_pPSC; - CAtlList m_pPixelShaders; - CAtlList m_pPixelShadersScreenSpace; - CComPtr m_pResizerPixelShader[4]; // bl, bc1, bc2_1, bc2_2 - CComPtr m_pScreenSizeTemporaryTexture[2]; - - D3DFORMAT m_SurfaceType; - D3DFORMAT m_BackbufferType; - D3DFORMAT m_DisplayType; - D3DTEXTUREFILTERTYPE m_filter; - D3DCAPS9 m_caps; - D3DPRESENT_PARAMETERS m_pp; - - bool SettingsNeedResetDevice(); - void SendResetRequest(); - virtual HRESULT CreateDXDevice(CString& _Error); - virtual HRESULT ResetDXDevice(CString& _Error); - virtual HRESULT AllocSurfaces(D3DFORMAT Format = D3DFMT_A8R8G8B8); - virtual void DeleteSurfaces(); - - LONGLONG m_LastAdapterCheck; - UINT m_CurrentAdapter; - - float m_bicubicA; - HRESULT InitResizers(float bicubicA, bool bNeedScreenSizeTexture); - - // Functions to trace timing performance - void SyncStats(LONGLONG syncTime); - void SyncOffsetStats(LONGLONG syncOffset); - void InitStats(); - void DrawStats(); - - template - void AdjustQuad(MYD3DVERTEX* v, double dx, double dy); - template - HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter); - MFOffset GetOffset(float v); - MFVideoArea GetArea(float x, float y, DWORD width, DWORD height); - bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d); - - HRESULT DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]); - HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect); - HRESULT TextureCopy(IDirect3DTexture9* pTexture); - HRESULT TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& SrcRect); - HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); - HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); - HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); - HRESULT Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect); - - typedef HRESULT(WINAPI* D3DXLoadSurfaceFromMemoryPtr)( - LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY* pDestPalette, - CONST RECT* pDestRect, - LPCVOID pSrcMemory, - D3DFORMAT SrcFormat, - UINT SrcPitch, - CONST PALETTEENTRY* pSrcPalette, - CONST RECT* pSrcRect, - DWORD Filter, - D3DCOLOR ColorKey); - - typedef HRESULT(WINAPI* D3DXLoadSurfaceFromSurfacePtr)( - LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY* pDestPalette, - CONST RECT* pDestRect, - LPDIRECT3DSURFACE9 pSrcSurface, - CONST PALETTEENTRY* pSrcPalette, - CONST RECT* pSrcRect, - DWORD Filter, - D3DCOLOR ColorKey); - - typedef HRESULT(WINAPI* D3DXCreateLinePtr) - (LPDIRECT3DDEVICE9 pDevice, - LPD3DXLINE* ppLine); - - typedef HRESULT(WINAPI* D3DXCreateFontPtr)( - LPDIRECT3DDEVICE9 pDevice, - int Height, - UINT Width, - UINT Weight, - UINT MipLevels, - bool Italic, - DWORD CharSet, - DWORD OutputPrecision, - DWORD Quality, - DWORD PitchAndFamily, - LPCWSTR pFaceName, - LPD3DXFONT* ppFont); - - HRESULT AlphaBlt(RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); - - virtual void OnResetDevice() {}; - - int m_nTearingPos; - VMR9AlphaBitmap m_VMR9AlphaBitmap; - CAutoVectorPtr m_VMR9AlphaBitmapData; - CRect m_VMR9AlphaBitmapRect; - int m_VMR9AlphaBitmapWidthBytes; - - D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory; - D3DXLoadSurfaceFromSurfacePtr m_pD3DXLoadSurfaceFromSurface; - D3DXCreateLinePtr m_pD3DXCreateLine; - D3DXCreateFontPtr m_pD3DXCreateFont; - HRESULT(__stdcall* m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); - - int m_nDXSurface; // Total number of DX Surfaces - int m_nVMR9Surfaces; - int m_iVMR9Surface; - int m_nCurSurface; // Surface currently displayed - long m_nUsedBuffer; - - LONG m_lNextSampleWait; // Waiting time for next sample in EVR - bool m_bSnapToVSync; // True if framerate is low enough so that snap to vsync makes sense - - UINT m_uScanLineEnteringPaint; // The active scan line when entering Paint() - REFERENCE_TIME m_llEstVBlankTime; // Next vblank start time in reference clock "coordinates" - - double m_fAvrFps; // Estimate the true FPS as given by the distance between vsyncs when a frame has been presented - double m_fJitterStdDev; // VSync estimate std dev - double m_fJitterMean; // Means time between two syncpulses when a frame has been presented (i.e. when Paint() has been called - - double m_fSyncOffsetAvr; // Means time between the call of Paint() and vsync. To avoid tearing this should be several ms at least - double m_fSyncOffsetStdDev; // The std dev of the above - - bool m_bHighColorResolution; - bool m_bCompositionEnabled; - bool m_bDesktopCompositionDisabled; - bool m_bIsFullscreen, fullScreenChanged; - bool m_bNeedCheckSample; - DWORD m_dMainThreadId; - - CSize m_ScreenSize; - - // Display and frame rates and cycles - double m_dDetectedScanlineTime; // Time for one (horizontal) scan line. Extracted at stream start and used to calculate vsync time - double m_dD3DRefreshCycle; // Display refresh cycle ms - double m_dEstRefreshCycle; // As estimated from scan lines - double m_dFrameCycle; // Average sample time, extracted from the samples themselves - // double m_fps is defined in ISubPic.h - double m_dOptimumDisplayCycle; // The display cycle that is closest to the frame rate. A multiple of the actual display cycle - double m_dCycleDifference; // Difference in video and display cycle time relative to the video cycle time - - UINT m_pcFramesDropped; - UINT m_pcFramesDuplicated; - UINT m_pcFramesDrawn; - - LONGLONG m_pllJitter [NB_JITTER]; // Vertical sync time stats - LONGLONG m_pllSyncOffset [NB_JITTER]; // Sync offset time stats - int m_nNextJitter; - int m_nNextSyncOffset; - LONGLONG m_JitterStdDev; - - LONGLONG m_llLastSyncTime; - - LONGLONG m_MaxJitter; - LONGLONG m_MinJitter; - LONGLONG m_MaxSyncOffset; - LONGLONG m_MinSyncOffset; - UINT m_uSyncGlitches; - - LONGLONG m_llSampleTime, m_llLastSampleTime; // Present time for the current sample - LONGLONG m_llHysteresis; - LONG m_lShiftToNearest, m_lShiftToNearestPrev; - bool m_bVideoSlowerThanDisplay; - - REFERENCE_TIME m_rtTimePerFrame; - bool m_bInterlaced; - double m_TextScale; - CString m_strStatsMsg[10]; - - CGenlock* m_pGenlock; // The video - display synchronizer class - CComPtr m_pRefClock; // The reference clock. Used in Paint() - CComPtr m_pAudioStats; // Audio statistics from audio renderer. To check so that audio is in sync - DWORD m_lAudioLag; // Time difference between audio and video when the audio renderer is matching rate to the external reference clock - long m_lAudioLagMin, m_lAudioLagMax; // The accumulated difference between the audio renderer and the master clock - DWORD m_lAudioSlaveMode; // To check whether the audio renderer matches rate with SyncClock (returns the value 4 if it does) - - double GetRefreshRate(); // Get the best estimate of the display refresh rate in Hz - double GetDisplayCycle(); // Get the best estimate of the display cycle time in milliseconds - double GetCycleDifference(); // Get the difference in video and display cycle times. - void EstimateRefreshTimings(); // Estimate the times for one scan line and one frame respectively from the actual refresh data - bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt); - - CFocusThread* m_FocusThread; - HWND m_hFocusWindow; - - public: - CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); - ~CBaseAP(); - - CCritSec m_VMR9AlphaBitmapLock; - void UpdateAlphaBitmap(); - void ResetStats(); - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); - STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); - STDMETHODIMP_(bool) ResetDevice(); - STDMETHODIMP_(bool) DisplayChange(); - }; - - class CSyncAP: - public CBaseAP, - public IMFGetService, - public IMFTopologyServiceLookupClient, - public IMFVideoDeviceID, - public IMFVideoPresenter, - public IDirect3DDeviceManager9, - public IMFAsyncCallback, - public IQualProp, - public IMFRateSupport, - public IMFVideoDisplayControl, - public IEVRTrustedVideoPlugin, - public ISyncClockAdviser, - public ID3DFullscreenControl - { - public: - CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); - ~CSyncAP(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(bool) Paint(bool bAll); - STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); - STDMETHODIMP InitializeDevice(AM_MEDIA_TYPE* pMediaType); - STDMETHODIMP_(bool) ResetDevice(); - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() { - return (m_nRenderState == Started); - } - - // IMFClockStateSink - STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset); - STDMETHODIMP OnClockStop(MFTIME hnsSystemTime); - STDMETHODIMP OnClockPause(MFTIME hnsSystemTime); - STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime); - STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate); - - // IBaseFilter delegate - bool GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue); - - // IQualProp (EVR statistics window). These are incompletely implemented currently - STDMETHODIMP get_FramesDroppedInRenderer(int* pcFrames); - STDMETHODIMP get_FramesDrawn(int* pcFramesDrawn); - STDMETHODIMP get_AvgFrameRate(int* piAvgFrameRate); - STDMETHODIMP get_Jitter(int* iJitter); - STDMETHODIMP get_AvgSyncOffset(int* piAvg); - STDMETHODIMP get_DevSyncOffset(int* piDev); - - // IMFRateSupport - STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); - STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); - STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate); - float GetMaxRate(BOOL bThin); - - // IMFVideoPresenter - STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam); - STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType); - - // IMFTopologyServiceLookupClient - STDMETHODIMP InitServicePointers(__in IMFTopologyServiceLookup* pLookup); - STDMETHODIMP ReleaseServicePointers(); - - // IMFVideoDeviceID - STDMETHODIMP GetDeviceID(__out IID* pDeviceID); - - // IMFGetService - STDMETHODIMP GetService(__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppvObject); - - // IMFAsyncCallback - STDMETHODIMP GetParameters(__RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue); - STDMETHODIMP Invoke(__RPC__in_opt IMFAsyncResult* pAsyncResult); - - // IMFVideoDisplayControl - STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo); - STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax); - STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest); - STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest); - STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode); - STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode); - STDMETHODIMP SetVideoWindow(HWND hwndVideo); - STDMETHODIMP GetVideoWindow(HWND* phwndVideo); - STDMETHODIMP RepaintVideo(); - STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp); - STDMETHODIMP SetBorderColor(COLORREF Clr); - STDMETHODIMP GetBorderColor(COLORREF* pClr); - STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags); - STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags); - STDMETHODIMP SetFullscreen(BOOL fFullscreen); - STDMETHODIMP GetFullscreen(BOOL* pfFullscreen); - - // IEVRTrustedVideoPlugin - STDMETHODIMP IsInTrustedVideoMode(BOOL* pYes); - STDMETHODIMP CanConstrict(BOOL* pYes); - STDMETHODIMP SetConstriction(DWORD dwKPix); - STDMETHODIMP DisableImageExport(BOOL bDisable); - - // IDirect3DDeviceManager9 - STDMETHODIMP ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken); - STDMETHODIMP OpenDeviceHandle(HANDLE* phDevice); - STDMETHODIMP CloseDeviceHandle(HANDLE hDevice); - STDMETHODIMP TestDevice(HANDLE hDevice); - STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock); - STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState); - STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void** ppService); - - // ID3DFullscreenControl - STDMETHODIMP SetD3DFullscreen(bool fEnabled); - STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); - - protected: - STDMETHODIMP_(bool) Paint(IMFSample* pMFSample); - void OnResetDevice(); - MFCLOCK_STATE m_LastClockState; - - private: - enum RENDER_STATE { - Started = State_Running, - Stopped = State_Stopped, - Paused = State_Paused, - Shutdown = State_Running + 1 - }; - - CComPtr m_pClock; - CComPtr m_pD3DManager; - CComPtr m_pMixer; - CComPtr m_pSink; - CComPtr m_pMediaType; - MFVideoAspectRatioMode m_dwVideoAspectRatioMode; - MFVideoRenderPrefs m_dwVideoRenderPrefs; - COLORREF m_BorderColor; - - HANDLE m_hEvtQuit; // Stop rendering thread event - bool m_bEvtQuit; - HANDLE m_hEvtFlush; // Discard all buffers - bool m_bEvtFlush; - HANDLE m_hEvtSkip; // Skip frame - bool m_bEvtSkip; - - bool m_bUseInternalTimer; - INT32 m_LastSetOutputRange; - std::atomic_bool m_bPendingRenegotiate; - bool m_bPendingMediaFinished; - bool m_bPrerolled; // true if first sample has been displayed. - - HANDLE m_hRenderThread; - HANDLE m_hMixerThread; - RENDER_STATE m_nRenderState; - bool m_bStepping; - - CCritSec m_SampleQueueLock; - CCritSec m_ImageProcessingLock; - - UINT32 m_nCurrentGroupId; - CInterfaceList m_FreeSamples; - CInterfaceList m_ScheduledSamples; - CComPtr m_pCurrentlyDisplayedSample; - UINT m_nResetToken; - int m_nStepCount; - - bool GetSampleFromMixer(); - void MixerThread(); - static DWORD WINAPI MixerThreadStatic(LPVOID lpParam); - void RenderThread(); - static DWORD WINAPI RenderThreadStatic(LPVOID lpParam); - - void StartWorkerThreads(); - void StopWorkerThreads(); - HRESULT CheckShutdown() const; - void CompleteFrameStep(bool bCancel); - - void RemoveAllSamples(); - STDMETHODIMP AdviseSyncClock(ISyncClock* sC); - HRESULT BeginStreaming(); - HRESULT GetFreeSample(IMFSample** ppSample); - HRESULT GetScheduledSample(IMFSample** ppSample, int& count); - void AddToFreeList(IMFSample* pSample, bool bTail); - void AddToScheduledList(IMFSample* pSample, bool bSorted); - void FlushSamples(); - - HRESULT TrackSample(IMFSample* pSample); - - // Callback when a video sample is released. - HRESULT OnSampleFree(IMFAsyncResult* pResult); - AsyncCallback m_SampleFreeCallback; - - LONGLONG GetMediaTypeMerit(IMFMediaType* pMediaType); - HRESULT RenegotiateMediaType(); - HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType); - HRESULT CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType); - HRESULT SetMediaType(IMFMediaType* pType); - - const WinapiFunc fnDXVA2CreateDirect3DDeviceManager9; - const WinapiFunc fnMFCreateDXSurfaceBuffer; - const WinapiFunc fnMFCreateVideoSampleFromSurface; - const WinapiFunc fnMFCreateMediaType; - - const WinapiFunc fnAvSetMmThreadCharacteristicsW; - const WinapiFunc fnAvSetMmThreadPriority; - const WinapiFunc fnAvRevertMmThreadCharacteristics; - }; - - class CSyncRenderer: - public CUnknown, - public IVMRMixerBitmap9, - public IBaseFilter - { - CComPtr m_pEVR; - IBaseFilter* m_pEVRBase; - VMR9AlphaBitmap* m_pVMR9AlphaBitmap; - CSyncAP* m_pAllocatorPresenter; - - public: - CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP* pAllocatorPresenter); - ~CSyncRenderer(); - - // IBaseFilter - virtual HRESULT STDMETHODCALLTYPE EnumPins(__out IEnumPins** ppEnum); - virtual HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, __out IPin** ppPin); - virtual HRESULT STDMETHODCALLTYPE QueryFilterInfo(__out FILTER_INFO* pInfo); - virtual HRESULT STDMETHODCALLTYPE JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName); - virtual HRESULT STDMETHODCALLTYPE QueryVendorInfo(__out LPWSTR* pVendorInfo); - virtual HRESULT STDMETHODCALLTYPE Stop(); - virtual HRESULT STDMETHODCALLTYPE Pause(); - virtual HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); - virtual HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State); - virtual HRESULT STDMETHODCALLTYPE SetSyncSource(__in_opt IReferenceClock* pClock); - virtual HRESULT STDMETHODCALLTYPE GetSyncSource(__deref_out_opt IReferenceClock** pClock); - virtual HRESULT STDMETHODCALLTYPE GetClassID(__RPC__out CLSID* pClassID); - - // IVMRMixerBitmap9 - STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); - STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); - - DECLARE_IUNKNOWN; - virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid, void** ppvObject); - }; - - class CGenlock - { - public: - class MovingAverage - { - public: - MovingAverage(size_t size) - : fifoSize(size) - , fifo(fifoSize) - , oldestSample(0) - , sum(0.0) { - } - - double Average(double sample) { - sum = sum + sample - fifo[oldestSample]; - fifo[oldestSample] = sample; - oldestSample++; - if (oldestSample == fifoSize) { - oldestSample = 0; - } - return sum / fifoSize; - } - - private: - size_t fifoSize; - std::vector fifo; - size_t oldestSample; - double sum; - }; - - CGenlock(double target, double limit, int rowD, int colD, double clockD, UINT mon); - CGenlock(const CGenlock&) = delete; - ~CGenlock(); - - CGenlock& operator=(const CGenlock&) = delete; - - BOOL PowerstripRunning(); // TRUE if PowerStrip is running - HRESULT GetTiming(); // Get the string representing the display's current timing parameters - HRESULT ResetTiming(); // Reset timing to what was last registered by GetTiming() - HRESULT ResetClock(); // Reset reference clock speed to nominal - HRESULT SetTargetSyncOffset(double targetD); - HRESULT GetTargetSyncOffset(double* targetD); - HRESULT SetControlLimit(double cL); - HRESULT GetControlLimit(double* cL); - HRESULT SetDisplayResolution(UINT columns, UINT lines); - HRESULT AdviseSyncClock(ISyncClock* sC); - HRESULT SetMonitor(UINT mon); // Set the number of the monitor to synchronize - HRESULT ResetStats(); // Reset timing statistics - - HRESULT ControlDisplay(double syncOffset, double frameCycle); // Adjust the frequency of the display if needed - HRESULT ControlClock(double syncOffset, double frameCycle); // Adjust the frequency of the clock if needed - HRESULT UpdateStats(double syncOffset, double frameCycle); // Don't adjust anything, just update the syncOffset stats - - bool powerstripTimingExists; // true if display timing has been got through Powerstrip - bool liveSource; // true if live source -> display sync is the only option - int adjDelta; // -1 for display slower in relation to video, 0 for keep, 1 for faster - int lineDelta; // The number of rows added or subtracted when adjusting display fps - int columnDelta; // The number of colums added or subtracted when adjusting display fps - double cycleDelta; // Adjustment factor for cycle time as fraction of nominal value - UINT displayAdjustmentsMade; // The number of adjustments made to display refresh rate - UINT clockAdjustmentsMade; // The number of adjustments made to clock frequency - - UINT totalLines, totalColumns; // Including the porches and sync widths - UINT visibleLines, visibleColumns; // The nominal resolution - MovingAverage syncOffsetFifo; - MovingAverage frameCycleFifo; - double minSyncOffset, maxSyncOffset; - double syncOffsetAvg; // Average of the above - double minFrameCycle, maxFrameCycle; - double frameCycleAvg; - - UINT pixelClock; // In pixels/s - double displayFreqCruise; // Nominal display frequency in frames/s - double displayFreqSlower; - double displayFreqFaster; - double curDisplayFreq; // Current (adjusted) display frequency - double controlLimit; // How much the sync offset is allowed to drift from target sync offset - WPARAM monitor; // The monitor to be controlled. 0-based. - CComPtr syncClock; // Interface to an adjustable reference clock - - private: - HWND psWnd; // PowerStrip window - const static int TIMING_PARAM_CNT = 10; - const static int MAX_LOADSTRING = 100; - std::array displayTiming; // Display timing parameters - std::array displayTimingSave; // So that we can reset the display at exit - TCHAR faster[MAX_LOADSTRING]; // String corresponding to faster display frequency - TCHAR cruise[MAX_LOADSTRING]; // String corresponding to nominal display frequency - TCHAR slower[MAX_LOADSTRING]; // String corresponding to slower display frequency - TCHAR savedTiming[MAX_LOADSTRING]; // String version of saved timing (to be restored upon exit) - double lowSyncOffset; // The closest we want to let the scheduled render time to get to the next vsync. In % of the frame time - double targetSyncOffset; // Where we want the scheduled render time to be in relation to the next vsync - double highSyncOffset; // The furthers we want to let the scheduled render time to get to the next vsync - CCritSec csGenlockLock; - }; -} +/* + * (C) 2010-2015, 2017 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 . + * + */ + +#pragma once + +#include "../../../SubPic/ISubPic.h" +#include "RenderersSettings.h" +#include "SyncAllocatorPresenter.h" +#include "AllocatorCommon.h" +#include "../../../DSUtil/WinapiFunc.h" +#include +#include +#include "d3dx9/d3dx9.h" + +#define VMRBITMAP_UPDATE 0x80000000 +#define MAX_PICTURE_SLOTS (60 + 2) // Last 2 for pixels shader! +#define NB_JITTER 126 +#include "AsyncCallback.h" + +class CFocusThread; + +// Possible messages to the PowerStrip API. PowerStrip is used to control +// the display frequency in one of the video - display synchronization modes. +// Powerstrip can also through a CGenlock object give very accurate timing data +// (given) that the gfx board is supported by PS. +#define UM_SETCUSTOMTIMING (WM_USER + 200) +#define UM_SETREFRESHRATE (WM_USER + 201) +#define UM_SETPOLARITY (WM_USER + 202) +#define UM_REMOTECONTROL (WM_USER + 210) +#define UM_SETGAMMARAMP (WM_USER + 203) +#define UM_CREATERESOLUTION (WM_USER + 204) +#define UM_GETTIMING (WM_USER + 205) +#define UM_SETCUSTOMTIMINGFAST (WM_USER + 211) // Sets timing without writing to file. Faster + +#define PositiveHorizontalPolarity 0x00 +#define PositiveVerticalPolarity 0x00 +#define NegativeHorizontalPolarity 0x02 +#define NegativeVerticalPolarity 0x04 +#define HideTrayIcon 0x00 +#define ShowTrayIcon 0x01 +#define ClosePowerStrip 0x63 + +#define HACTIVE 0 +#define HFRONTPORCH 1 +#define HSYNCWIDTH 2 +#define HBACKPORCH 3 +#define VACTIVE 4 +#define VFRONTPORCH 5 +#define VSYNCWIDTH 6 +#define VBACKPORCH 7 +#define PIXELCLOCK 8 +#define UNKNOWN 9 + +// Guid to tag IMFSample with a group id +static const GUID GUID_GROUP_ID = { 0x309e32cc, 0x9b23, 0x4c6c, { 0x86, 0x63, 0xcd, 0xd9, 0xad, 0x49, 0x7f, 0x8a } }; +// Guid to tag IMFSample with DirectX surface index +static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } }; + +namespace GothSync +{ + enum EVR_STATS_MSG { + MSG_MIXERIN, + MSG_MIXEROUT, + MSG_ERROR + }; + +#pragma pack(push, 1) + + template + struct MYD3DVERTEX { + float x, y, z, rhw; + struct { + float u, v; + } t[texcoords]; + }; + + template<> + struct MYD3DVERTEX<0> { + float x, y, z, rhw; + DWORD Diffuse; + }; + +#pragma pack(pop) + + class CGenlock; + class CSyncRenderer; + + // Base allocator-presenter + class CBaseAP: + public CSubPicAllocatorPresenterImpl + { + protected: + CRenderersSettings::CAdvRendererSettings m_LastRendererSettings; + + HMODULE m_hDWMAPI; + HRESULT(__stdcall* m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled); + HRESULT(__stdcall* m_pDwmEnableComposition)(UINT uCompositionAction); + + CCritSec m_allocatorLock; + CComPtr m_pD3DEx; + CComPtr m_pD3D; + CComPtr m_pD3DDevEx; + CComPtr m_pD3DDev; + + CComPtr m_pVideoTexture[MAX_PICTURE_SLOTS]; + CComPtr m_pVideoSurface[MAX_PICTURE_SLOTS]; + CComPtr m_pOSDTexture; + CComPtr m_pOSDSurface; + CComPtr m_pLine; + CComPtr m_pFont; + CComPtr m_pSprite; + CSyncRenderer* m_pOuterEVR; + + class CExternalPixelShader + { + public: + CComPtr m_pPixelShader; + CStringA m_SourceData; + CStringA m_SourceTarget; + HRESULT Compile(CPixelShaderCompiler* pCompiler) { + HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader); + if (FAILED(hr)) { + return hr; + } + return S_OK; + } + }; + + CAutoPtr m_pPSC; + CAtlList m_pPixelShaders; + CAtlList m_pPixelShadersScreenSpace; + CComPtr m_pResizerPixelShader[4]; // bl, bc1, bc2_1, bc2_2 + CComPtr m_pScreenSizeTemporaryTexture[2]; + + D3DFORMAT m_SurfaceType; + D3DFORMAT m_BackbufferType; + D3DFORMAT m_DisplayType; + D3DTEXTUREFILTERTYPE m_filter; + D3DCAPS9 m_caps; + D3DPRESENT_PARAMETERS m_pp; + + bool SettingsNeedResetDevice(); + void SendResetRequest(); + virtual HRESULT CreateDXDevice(CString& _Error); + virtual HRESULT ResetDXDevice(CString& _Error); + virtual HRESULT AllocSurfaces(D3DFORMAT Format = D3DFMT_A8R8G8B8); + virtual void DeleteSurfaces(); + + LONGLONG m_LastAdapterCheck; + UINT m_CurrentAdapter; + + float m_bicubicA; + HRESULT InitResizers(float bicubicA, bool bNeedScreenSizeTexture); + + // Functions to trace timing performance + void SyncStats(LONGLONG syncTime); + void SyncOffsetStats(LONGLONG syncOffset); + void InitStats(); + void DrawStats(); + + template + void AdjustQuad(MYD3DVERTEX* v, double dx, double dy); + template + HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter); + MFOffset GetOffset(float v); + MFVideoArea GetArea(float x, float y, DWORD width, DWORD height); + bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d); + + HRESULT DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]); + HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect& _Rect); + HRESULT TextureCopy(IDirect3DTexture9* pTexture); + HRESULT TextureResize(IDirect3DTexture9* pTexture, const Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect& SrcRect); + HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); + HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); + HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, const Vector dst[4], const CRect& SrcRect); + HRESULT Resize(IDirect3DTexture9* pTexture, const CRect& srcRect, const CRect& destRect); + + typedef HRESULT(WINAPI* D3DXLoadSurfaceFromMemoryPtr)( + LPDIRECT3DSURFACE9 pDestSurface, + CONST PALETTEENTRY* pDestPalette, + CONST RECT* pDestRect, + LPCVOID pSrcMemory, + D3DFORMAT SrcFormat, + UINT SrcPitch, + CONST PALETTEENTRY* pSrcPalette, + CONST RECT* pSrcRect, + DWORD Filter, + D3DCOLOR ColorKey); + + typedef HRESULT(WINAPI* D3DXLoadSurfaceFromSurfacePtr)( + LPDIRECT3DSURFACE9 pDestSurface, + CONST PALETTEENTRY* pDestPalette, + CONST RECT* pDestRect, + LPDIRECT3DSURFACE9 pSrcSurface, + CONST PALETTEENTRY* pSrcPalette, + CONST RECT* pSrcRect, + DWORD Filter, + D3DCOLOR ColorKey); + + typedef HRESULT(WINAPI* D3DXCreateLinePtr) + (LPDIRECT3DDEVICE9 pDevice, + LPD3DXLINE* ppLine); + + typedef HRESULT(WINAPI* D3DXCreateFontPtr)( + LPDIRECT3DDEVICE9 pDevice, + int Height, + UINT Width, + UINT Weight, + UINT MipLevels, + bool Italic, + DWORD CharSet, + DWORD OutputPrecision, + DWORD Quality, + DWORD PitchAndFamily, + LPCWSTR pFaceName, + LPD3DXFONT* ppFont); + + HRESULT AlphaBlt(RECT* pSrc, const RECT* pDst, IDirect3DTexture9* pTexture); + + virtual void OnResetDevice() {}; + + int m_nTearingPos; + VMR9AlphaBitmap m_VMR9AlphaBitmap; + CAutoVectorPtr m_VMR9AlphaBitmapData; + CRect m_VMR9AlphaBitmapRect; + int m_VMR9AlphaBitmapWidthBytes; + + D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory; + D3DXLoadSurfaceFromSurfacePtr m_pD3DXLoadSurfaceFromSurface; + D3DXCreateLinePtr m_pD3DXCreateLine; + D3DXCreateFontPtr m_pD3DXCreateFont; + HRESULT(__stdcall* m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE* ppSprite); + + int m_nDXSurface; // Total number of DX Surfaces + int m_nVMR9Surfaces; + int m_iVMR9Surface; + int m_nCurSurface; // Surface currently displayed + long m_nUsedBuffer; + + LONG m_lNextSampleWait; // Waiting time for next sample in EVR + bool m_bSnapToVSync; // True if framerate is low enough so that snap to vsync makes sense + + UINT m_uScanLineEnteringPaint; // The active scan line when entering Paint() + REFERENCE_TIME m_llEstVBlankTime; // Next vblank start time in reference clock "coordinates" + + double m_fAvrFps; // Estimate the true FPS as given by the distance between vsyncs when a frame has been presented + double m_fJitterStdDev; // VSync estimate std dev + double m_fJitterMean; // Means time between two syncpulses when a frame has been presented (i.e. when Paint() has been called + + double m_fSyncOffsetAvr; // Means time between the call of Paint() and vsync. To avoid tearing this should be several ms at least + double m_fSyncOffsetStdDev; // The std dev of the above + + bool m_bHighColorResolution; + bool m_bCompositionEnabled; + bool m_bDesktopCompositionDisabled; + bool m_bIsFullscreen, fullScreenChanged; + bool m_bNeedCheckSample; + DWORD m_dMainThreadId; + + CSize m_ScreenSize; + + // Display and frame rates and cycles + double m_dDetectedScanlineTime; // Time for one (horizontal) scan line. Extracted at stream start and used to calculate vsync time + double m_dD3DRefreshCycle; // Display refresh cycle ms + double m_dEstRefreshCycle; // As estimated from scan lines + double m_dFrameCycle; // Average sample time, extracted from the samples themselves + // double m_fps is defined in ISubPic.h + double m_dOptimumDisplayCycle; // The display cycle that is closest to the frame rate. A multiple of the actual display cycle + double m_dCycleDifference; // Difference in video and display cycle time relative to the video cycle time + + UINT m_pcFramesDropped; + UINT m_pcFramesDuplicated; + UINT m_pcFramesDrawn; + + LONGLONG m_pllJitter [NB_JITTER]; // Vertical sync time stats + LONGLONG m_pllSyncOffset [NB_JITTER]; // Sync offset time stats + int m_nNextJitter; + int m_nNextSyncOffset; + LONGLONG m_JitterStdDev; + + LONGLONG m_llLastSyncTime; + + LONGLONG m_MaxJitter; + LONGLONG m_MinJitter; + LONGLONG m_MaxSyncOffset; + LONGLONG m_MinSyncOffset; + UINT m_uSyncGlitches; + + LONGLONG m_llSampleTime, m_llLastSampleTime; // Present time for the current sample + LONGLONG m_llHysteresis; + LONG m_lShiftToNearest, m_lShiftToNearestPrev; + bool m_bVideoSlowerThanDisplay; + + REFERENCE_TIME m_rtTimePerFrame; + bool m_bInterlaced; + double m_TextScale; + CString m_strStatsMsg[10]; + + CGenlock* m_pGenlock; // The video - display synchronizer class + CComPtr m_pRefClock; // The reference clock. Used in Paint() + CComPtr m_pAudioStats; // Audio statistics from audio renderer. To check so that audio is in sync + DWORD m_lAudioLag; // Time difference between audio and video when the audio renderer is matching rate to the external reference clock + long m_lAudioLagMin, m_lAudioLagMax; // The accumulated difference between the audio renderer and the master clock + DWORD m_lAudioSlaveMode; // To check whether the audio renderer matches rate with SyncClock (returns the value 4 if it does) + + double GetRefreshRate(); // Get the best estimate of the display refresh rate in Hz + double GetDisplayCycle(); // Get the best estimate of the display cycle time in milliseconds + double GetCycleDifference(); // Get the difference in video and display cycle times. + void EstimateRefreshTimings(); // Estimate the times for one scan line and one frame respectively from the actual refresh data + bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt); + + CFocusThread* m_FocusThread; + HWND m_hFocusWindow; + + public: + CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); + ~CBaseAP(); + + CCritSec m_VMR9AlphaBitmapLock; + void UpdateAlphaBitmap(); + void ResetStats(); + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size); + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget); + STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace); + STDMETHODIMP_(bool) ResetDevice(); + STDMETHODIMP_(bool) DisplayChange(); + }; + + class CSyncAP: + public CBaseAP, + public IMFGetService, + public IMFTopologyServiceLookupClient, + public IMFVideoDeviceID, + public IMFVideoPresenter, + public IDirect3DDeviceManager9, + public IMFAsyncCallback, + public IQualProp, + public IMFRateSupport, + public IMFVideoDisplayControl, + public IEVRTrustedVideoPlugin, + public ISyncClockAdviser, + public ID3DFullscreenControl + { + public: + CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); + ~CSyncAP(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(bool) Paint(bool bAll); + STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); + STDMETHODIMP InitializeDevice(AM_MEDIA_TYPE* pMediaType); + STDMETHODIMP_(bool) ResetDevice(); + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() { + return (m_nRenderState == Started); + } + + // IMFClockStateSink + STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset); + STDMETHODIMP OnClockStop(MFTIME hnsSystemTime); + STDMETHODIMP OnClockPause(MFTIME hnsSystemTime); + STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime); + STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate); + + // IBaseFilter delegate + bool GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State, HRESULT& _ReturnValue); + + // IQualProp (EVR statistics window). These are incompletely implemented currently + STDMETHODIMP get_FramesDroppedInRenderer(int* pcFrames); + STDMETHODIMP get_FramesDrawn(int* pcFramesDrawn); + STDMETHODIMP get_AvgFrameRate(int* piAvgFrameRate); + STDMETHODIMP get_Jitter(int* iJitter); + STDMETHODIMP get_AvgSyncOffset(int* piAvg); + STDMETHODIMP get_DevSyncOffset(int* piDev); + + // IMFRateSupport + STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); + STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float* pflRate); + STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float* pflNearestSupportedRate); + float GetMaxRate(BOOL bThin); + + // IMFVideoPresenter + STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam); + STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType** ppMediaType); + + // IMFTopologyServiceLookupClient + STDMETHODIMP InitServicePointers(__in IMFTopologyServiceLookup* pLookup); + STDMETHODIMP ReleaseServicePointers(); + + // IMFVideoDeviceID + STDMETHODIMP GetDeviceID(__out IID* pDeviceID); + + // IMFGetService + STDMETHODIMP GetService(__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppvObject); + + // IMFAsyncCallback + STDMETHODIMP GetParameters(__RPC__out DWORD* pdwFlags, /* [out] */ __RPC__out DWORD* pdwQueue); + STDMETHODIMP Invoke(__RPC__in_opt IMFAsyncResult* pAsyncResult); + + // IMFVideoDisplayControl + STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo); + STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax); + STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest); + STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest); + STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode); + STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode); + STDMETHODIMP SetVideoWindow(HWND hwndVideo); + STDMETHODIMP GetVideoWindow(HWND* phwndVideo); + STDMETHODIMP RepaintVideo(); + STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp); + STDMETHODIMP SetBorderColor(COLORREF Clr); + STDMETHODIMP GetBorderColor(COLORREF* pClr); + STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags); + STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags); + STDMETHODIMP SetFullscreen(BOOL fFullscreen); + STDMETHODIMP GetFullscreen(BOOL* pfFullscreen); + + // IEVRTrustedVideoPlugin + STDMETHODIMP IsInTrustedVideoMode(BOOL* pYes); + STDMETHODIMP CanConstrict(BOOL* pYes); + STDMETHODIMP SetConstriction(DWORD dwKPix); + STDMETHODIMP DisableImageExport(BOOL bDisable); + + // IDirect3DDeviceManager9 + STDMETHODIMP ResetDevice(IDirect3DDevice9* pDevice, UINT resetToken); + STDMETHODIMP OpenDeviceHandle(HANDLE* phDevice); + STDMETHODIMP CloseDeviceHandle(HANDLE hDevice); + STDMETHODIMP TestDevice(HANDLE hDevice); + STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9** ppDevice, BOOL fBlock); + STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState); + STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void** ppService); + + // ID3DFullscreenControl + STDMETHODIMP SetD3DFullscreen(bool fEnabled); + STDMETHODIMP GetD3DFullscreen(bool* pfEnabled); + + protected: + STDMETHODIMP_(bool) Paint(IMFSample* pMFSample); + void OnResetDevice(); + MFCLOCK_STATE m_LastClockState; + + private: + enum RENDER_STATE { + Started = State_Running, + Stopped = State_Stopped, + Paused = State_Paused, + Shutdown = State_Running + 1 + }; + + CComPtr m_pClock; + CComPtr m_pD3DManager; + CComPtr m_pMixer; + CComPtr m_pSink; + CComPtr m_pMediaType; + MFVideoAspectRatioMode m_dwVideoAspectRatioMode; + MFVideoRenderPrefs m_dwVideoRenderPrefs; + COLORREF m_BorderColor; + + HANDLE m_hEvtQuit; // Stop rendering thread event + bool m_bEvtQuit; + HANDLE m_hEvtFlush; // Discard all buffers + bool m_bEvtFlush; + HANDLE m_hEvtSkip; // Skip frame + bool m_bEvtSkip; + + bool m_bUseInternalTimer; + INT32 m_LastSetOutputRange; + std::atomic_bool m_bPendingRenegotiate; + bool m_bPendingMediaFinished; + bool m_bPrerolled; // true if first sample has been displayed. + + HANDLE m_hRenderThread; + HANDLE m_hMixerThread; + RENDER_STATE m_nRenderState; + bool m_bStepping; + + CCritSec m_SampleQueueLock; + CCritSec m_ImageProcessingLock; + + UINT32 m_nCurrentGroupId; + CInterfaceList m_FreeSamples; + CInterfaceList m_ScheduledSamples; + CComPtr m_pCurrentlyDisplayedSample; + UINT m_nResetToken; + int m_nStepCount; + + bool GetSampleFromMixer(); + void MixerThread(); + static DWORD WINAPI MixerThreadStatic(LPVOID lpParam); + void RenderThread(); + static DWORD WINAPI RenderThreadStatic(LPVOID lpParam); + + void StartWorkerThreads(); + void StopWorkerThreads(); + HRESULT CheckShutdown() const; + void CompleteFrameStep(bool bCancel); + + void RemoveAllSamples(); + STDMETHODIMP AdviseSyncClock(ISyncClock* sC); + HRESULT BeginStreaming(); + HRESULT GetFreeSample(IMFSample** ppSample); + HRESULT GetScheduledSample(IMFSample** ppSample, int& count); + void AddToFreeList(IMFSample* pSample, bool bTail); + void AddToScheduledList(IMFSample* pSample, bool bSorted); + void FlushSamples(); + + HRESULT TrackSample(IMFSample* pSample); + + // Callback when a video sample is released. + HRESULT OnSampleFree(IMFAsyncResult* pResult); + AsyncCallback m_SampleFreeCallback; + + LONGLONG GetMediaTypeMerit(IMFMediaType* pMediaType); + HRESULT RenegotiateMediaType(); + HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType); + HRESULT CreateOptimalOutputType(IMFMediaType* pMixerProposedType, IMFMediaType* pMixerInputType, IMFMediaType** ppType); + HRESULT SetMediaType(IMFMediaType* pType); + + const WinapiFunc fnDXVA2CreateDirect3DDeviceManager9; + const WinapiFunc fnMFCreateDXSurfaceBuffer; + const WinapiFunc fnMFCreateVideoSampleFromSurface; + const WinapiFunc fnMFCreateMediaType; + + const WinapiFunc fnAvSetMmThreadCharacteristicsW; + const WinapiFunc fnAvSetMmThreadPriority; + const WinapiFunc fnAvRevertMmThreadCharacteristics; + }; + + class CSyncRenderer: + public CUnknown, + public IVMRMixerBitmap9, + public IBaseFilter + { + CComPtr m_pEVR; + IBaseFilter* m_pEVRBase; + VMR9AlphaBitmap* m_pVMR9AlphaBitmap; + CSyncAP* m_pAllocatorPresenter; + + public: + CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP* pAllocatorPresenter); + ~CSyncRenderer(); + + // IBaseFilter + virtual HRESULT STDMETHODCALLTYPE EnumPins(__out IEnumPins** ppEnum); + virtual HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, __out IPin** ppPin); + virtual HRESULT STDMETHODCALLTYPE QueryFilterInfo(__out FILTER_INFO* pInfo); + virtual HRESULT STDMETHODCALLTYPE JoinFilterGraph(__in_opt IFilterGraph* pGraph, __in_opt LPCWSTR pName); + virtual HRESULT STDMETHODCALLTYPE QueryVendorInfo(__out LPWSTR* pVendorInfo); + virtual HRESULT STDMETHODCALLTYPE Stop(); + virtual HRESULT STDMETHODCALLTYPE Pause(); + virtual HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); + virtual HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE* State); + virtual HRESULT STDMETHODCALLTYPE SetSyncSource(__in_opt IReferenceClock* pClock); + virtual HRESULT STDMETHODCALLTYPE GetSyncSource(__deref_out_opt IReferenceClock** pClock); + virtual HRESULT STDMETHODCALLTYPE GetClassID(__RPC__out CLSID* pClassID); + + // IVMRMixerBitmap9 + STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms); + STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms); + + DECLARE_IUNKNOWN; + virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid, void** ppvObject); + }; + + class CGenlock + { + public: + class MovingAverage + { + public: + MovingAverage(size_t size) + : fifoSize(size) + , fifo(fifoSize) + , oldestSample(0) + , sum(0.0) { + } + + double Average(double sample) { + sum = sum + sample - fifo[oldestSample]; + fifo[oldestSample] = sample; + oldestSample++; + if (oldestSample == fifoSize) { + oldestSample = 0; + } + return sum / fifoSize; + } + + private: + size_t fifoSize; + std::vector fifo; + size_t oldestSample; + double sum; + }; + + CGenlock(double target, double limit, int rowD, int colD, double clockD, UINT mon); + CGenlock(const CGenlock&) = delete; + ~CGenlock(); + + CGenlock& operator=(const CGenlock&) = delete; + + BOOL PowerstripRunning(); // TRUE if PowerStrip is running + HRESULT GetTiming(); // Get the string representing the display's current timing parameters + HRESULT ResetTiming(); // Reset timing to what was last registered by GetTiming() + HRESULT ResetClock(); // Reset reference clock speed to nominal + HRESULT SetTargetSyncOffset(double targetD); + HRESULT GetTargetSyncOffset(double* targetD); + HRESULT SetControlLimit(double cL); + HRESULT GetControlLimit(double* cL); + HRESULT SetDisplayResolution(UINT columns, UINT lines); + HRESULT AdviseSyncClock(ISyncClock* sC); + HRESULT SetMonitor(UINT mon); // Set the number of the monitor to synchronize + HRESULT ResetStats(); // Reset timing statistics + + HRESULT ControlDisplay(double syncOffset, double frameCycle); // Adjust the frequency of the display if needed + HRESULT ControlClock(double syncOffset, double frameCycle); // Adjust the frequency of the clock if needed + HRESULT UpdateStats(double syncOffset, double frameCycle); // Don't adjust anything, just update the syncOffset stats + + bool powerstripTimingExists; // true if display timing has been got through Powerstrip + bool liveSource; // true if live source -> display sync is the only option + int adjDelta; // -1 for display slower in relation to video, 0 for keep, 1 for faster + int lineDelta; // The number of rows added or subtracted when adjusting display fps + int columnDelta; // The number of colums added or subtracted when adjusting display fps + double cycleDelta; // Adjustment factor for cycle time as fraction of nominal value + UINT displayAdjustmentsMade; // The number of adjustments made to display refresh rate + UINT clockAdjustmentsMade; // The number of adjustments made to clock frequency + + UINT totalLines, totalColumns; // Including the porches and sync widths + UINT visibleLines, visibleColumns; // The nominal resolution + MovingAverage syncOffsetFifo; + MovingAverage frameCycleFifo; + double minSyncOffset, maxSyncOffset; + double syncOffsetAvg; // Average of the above + double minFrameCycle, maxFrameCycle; + double frameCycleAvg; + + UINT pixelClock; // In pixels/s + double displayFreqCruise; // Nominal display frequency in frames/s + double displayFreqSlower; + double displayFreqFaster; + double curDisplayFreq; // Current (adjusted) display frequency + double controlLimit; // How much the sync offset is allowed to drift from target sync offset + WPARAM monitor; // The monitor to be controlled. 0-based. + CComPtr syncClock; // Interface to an adjustable reference clock + + private: + HWND psWnd; // PowerStrip window + const static int TIMING_PARAM_CNT = 10; + const static int MAX_LOADSTRING = 100; + std::array displayTiming; // Display timing parameters + std::array displayTimingSave; // So that we can reset the display at exit + TCHAR faster[MAX_LOADSTRING]; // String corresponding to faster display frequency + TCHAR cruise[MAX_LOADSTRING]; // String corresponding to nominal display frequency + TCHAR slower[MAX_LOADSTRING]; // String corresponding to slower display frequency + TCHAR savedTiming[MAX_LOADSTRING]; // String version of saved timing (to be restored upon exit) + double lowSyncOffset; // The closest we want to let the scheduled render time to get to the next vsync. In % of the frame time + double targetSyncOffset; // Where we want the scheduled render time to be in relation to the next vsync + double highSyncOffset; // The furthers we want to let the scheduled render time to get to the next vsync + CCritSec csGenlockLock; + }; +} diff --git a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp index cc029075d75..3d2a01dddc0 100644 --- a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp @@ -1,582 +1,582 @@ -/* - * (C) 2006-2014, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "RenderersSettings.h" -#include "VMR9AllocatorPresenter.h" -#include "OuterVMR.h" -#include "IPinHook.h" -#include "MacrovisionKicker.h" -#include "Variables.h" - -// ISubPicAllocatorPresenter - - -using namespace DSObjects; - -// -// CVMR9AllocatorPresenter -// - -#define MY_USER_ID 0x6ABE51 - -CVMR9AllocatorPresenter::CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) - : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, false, _Error) - , m_fUseInternalTimer(false) - , m_rtPrevStart(-1) -{ -} - -CVMR9AllocatorPresenter::~CVMR9AllocatorPresenter() -{ - if (m_bHookedNewSegment) { - UnhookNewSegment(); - } - if (m_bHookedReceive) { - UnhookReceive(); - } -} - -STDMETHODIMP CVMR9AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IVMRSurfaceAllocator9) - QI(IVMRImagePresenter9) - QI(IVMRWindowlessControl9) - QI(ID3DFullscreenControl) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CVMR9AllocatorPresenter::CreateDevice(CString& _Error) -{ - HRESULT hr = __super::CreateDevice(_Error); - if (FAILED(hr)) { - return hr; - } - - if (m_pIVMRSurfAllocNotify) { - HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(m_CurrentAdapter); - if (FAILED(hr = m_pIVMRSurfAllocNotify->ChangeD3DDevice(m_pD3DDev, hMonitor))) { - _Error += L"m_pIVMRSurfAllocNotify->ChangeD3DDevice failed"; - return hr; //return false; - } - } - - return hr; -} - -void CVMR9AllocatorPresenter::DeleteSurfaces() -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - m_pSurfaces.RemoveAll(); - - return __super::DeleteSurfaces(); -} - -STDMETHODIMP CVMR9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - *ppRenderer = nullptr; - - CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; - - COuterVMR9* pOuter = DEBUG_NEW COuterVMR9(NAME("COuterVMR9"), pUnk, &m_VMR9AlphaBitmap, this); - - pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuter); - CComQIPtr pBF = pUnk; - - CComPtr pPin = GetFirstPin(pBF); - if (!m_bIsPreview) { - if (HookNewSegment((IPinC*)(IPin*)pPin)) { - m_bHookedNewSegment = true; - CComQIPtr pMemInputPin = pPin; - if (HookReceive((IMemInputPinC*)(IMemInputPin*)pMemInputPin)) { - m_fUseInternalTimer = true; - m_bHookedReceive = true; - } - } - } - - CComQIPtr pConfig = pBF; - if (!pConfig) { - return E_FAIL; - } - - const CRenderersSettings& r = GetRenderersSettings(); - - if (r.fVMR9MixerMode) { - if (FAILED(pConfig->SetNumberOfStreams(1))) { - return E_FAIL; - } - - if (CComQIPtr pMC = pBF) { - DWORD dwPrefs; - pMC->GetMixingPrefs(&dwPrefs); - - // See http://msdn.microsoft.com/en-us/library/dd390928(VS.85).aspx - dwPrefs |= MixerPref9_NonSquareMixing; - dwPrefs |= MixerPref9_NoDecimation; - pMC->SetMixingPrefs(dwPrefs); - } - } - - if (FAILED(pConfig->SetRenderingMode(VMR9Mode_Renderless))) { - return E_FAIL; - } - - CComQIPtr pSAN = pBF; - if (!pSAN) { - return E_FAIL; - } - - if (FAILED(pSAN->AdviseSurfaceAllocator(MY_USER_ID, static_cast(this))) - || FAILED(AdviseNotify(pSAN))) { - return E_FAIL; - } - - *ppRenderer = (IUnknown*)pBF.Detach(); - - return S_OK; -} - -STDMETHODIMP_(void) CVMR9AllocatorPresenter::SetTime(REFERENCE_TIME rtNow) -{ - __super::SetTime(rtNow); -} - -// IVMRSurfaceAllocator9 - -STDMETHODIMP CVMR9AllocatorPresenter::InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers) -{ - CAutoLock lock(this); - CAutoLock cRenderLock(&m_RenderLock); - - if (!lpAllocInfo || !lpNumBuffers) { - return E_POINTER; - } - - if (!m_pIVMRSurfAllocNotify) { - return E_FAIL; - } - - // WTF: Is this some kind of forgotten debug code ? - if ((GetAsyncKeyState(VK_CONTROL) & 0x80000000)) - if (lpAllocInfo->Format == '21VY' || lpAllocInfo->Format == '024I') { - return E_FAIL; - } - - // The surfaces should already be free when InitializeDevice is called - DeleteSurfaces(); - - DWORD nOriginal = *lpNumBuffers; - - if (*lpNumBuffers == 1) { - *lpNumBuffers = 4; - m_nVMR9Surfaces = 4; - } else { - m_nVMR9Surfaces = 0; - } - m_pSurfaces.SetCount(*lpNumBuffers); - - int w = lpAllocInfo->dwWidth; - int h = abs((int)lpAllocInfo->dwHeight); - - HRESULT hr; - - if (lpAllocInfo->dwFlags & VMR9AllocFlag_3DRenderTarget) { - lpAllocInfo->dwFlags |= VMR9AllocFlag_TextureSurface; - } - - hr = m_pIVMRSurfAllocNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, &m_pSurfaces[0]); - if (FAILED(hr)) { - return hr; - } - - m_pSurfaces.SetCount(*lpNumBuffers); - - m_bNeedCheckSample = true; - CSize VideoSize(w, h); - CSize AspectRatio(lpAllocInfo->szAspectRatio.cx, lpAllocInfo->szAspectRatio.cy); - SetVideoSize(VideoSize, AspectRatio); - - if (FAILED(hr = AllocSurfaces())) { - return hr; - } - - if (!(lpAllocInfo->dwFlags & VMR9AllocFlag_TextureSurface)) { - // test if the colorspace is acceptable - if (FAILED(hr = m_pD3DDev->StretchRect(m_pSurfaces[0], nullptr, m_pVideoSurface[m_nCurSurface], nullptr, D3DTEXF_NONE))) { - DeleteSurfaces(); - return E_FAIL; - } - } - - hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], nullptr, 0); - - if (m_nVMR9Surfaces && m_nVMR9Surfaces != (int)*lpNumBuffers) { - m_nVMR9Surfaces = *lpNumBuffers; - } - *lpNumBuffers = std::min(nOriginal, *lpNumBuffers); - m_iVMR9Surface = 0; - - return hr; -} - -STDMETHODIMP CVMR9AllocatorPresenter::TerminateDevice(DWORD_PTR dwUserID) -{ - // We should not free the surfaces until we are told to ! - // Thats what TerminateDevice is for - DeleteSurfaces(); - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface) -{ - CheckPointer(lplpSurface, E_POINTER); - - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - /* - SurfaceIndex = 0 - m_pSurfaces.GetCount() = 0 - - Scenario: - Thread 1: - Wait on m_RenderLock in this function - Thread 2: - Have m_RenderLock and removes all m_pSurfaces - (Happens by calling ex CDX9AllocatorPresenter::ResetDevice) - - When thread 2 releases the lock thread 1 gets it and boom! - - Possible solution: Adding object lock and moving m_RenderLock to try to fix this threading issue. - This problem occurs when moving the window from display a to display b. - - NOTE: This is just a workaround. - CDX9AllocatorPresenter doesn't follow the rules which is why this happened. - And it is used by EVR custom (which it really shouldn't) so i can't easily fix it without breaking EVR custom. - */ - if (SurfaceIndex >= m_pSurfaces.GetCount()) { - return E_FAIL; - } - - if (m_nVMR9Surfaces) { - ++m_iVMR9Surface; - m_iVMR9Surface = m_iVMR9Surface % m_nVMR9Surfaces; - *lplpSurface = m_pSurfaces[m_iVMR9Surface + SurfaceIndex]; - (*lplpSurface)->AddRef(); - } else { - m_iVMR9Surface = SurfaceIndex; - *lplpSurface = m_pSurfaces[SurfaceIndex]; - (*lplpSurface)->AddRef(); - } - - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify) -{ - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - m_pIVMRSurfAllocNotify = lpIVMRSurfAllocNotify; - - HRESULT hr; - HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D)); - if (FAILED(hr = m_pIVMRSurfAllocNotify->SetD3DDevice(m_pD3DDev, hMonitor))) { - return hr; - } - - return S_OK; -} - -// IVMRImagePresenter9 - -STDMETHODIMP CVMR9AllocatorPresenter::StartPresenting(DWORD_PTR dwUserID) -{ - if (!m_bPendingResetDevice) { - ASSERT(m_pD3DDev); - } - - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - CComPtr pVMR9; - CComPtr pPin; - if (SUCCEEDED(m_pIVMRSurfAllocNotify->QueryInterface(IID_PPV_ARGS(&pVMR9))) && - SUCCEEDED(pVMR9->FindPin(L"VMR Input0", &pPin))) { - VERIFY(SUCCEEDED(pPin->ConnectionMediaType(&m_inputMediaType))); - } - - m_bIsRendering = true; - - return m_pD3DDev ? S_OK : E_FAIL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::StopPresenting(DWORD_PTR dwUserID) -{ - m_bIsRendering = false; - - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo) -{ - SetThreadName(DWORD(-1), "CVMR9AllocatorPresenter"); - CheckPointer(m_pIVMRSurfAllocNotify, E_UNEXPECTED); - - if (m_rtTimePerFrame == 0 || m_bNeedCheckSample) { - m_bNeedCheckSample = false; - CComPtr pVMR9; - CComPtr pPin; - CMediaType mt; - - if (SUCCEEDED(m_pIVMRSurfAllocNotify->QueryInterface(IID_PPV_ARGS(&pVMR9))) && - SUCCEEDED(pVMR9->FindPin(L"VMR Input0", &pPin)) && - SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); - - CSize NativeVideoSize = m_nativeVideoSize; - CSize AspectRatio = m_aspectRatio; - if (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_MPEGVideo) { - VIDEOINFOHEADER* vh = (VIDEOINFOHEADER*)mt.pbFormat; - - NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight)); - if (vh->rcTarget.right - vh->rcTarget.left > 0) { - NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left; - } else if (vh->rcSource.right - vh->rcSource.left > 0) { - NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left; - } - - if (vh->rcTarget.bottom - vh->rcTarget.top > 0) { - NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top; - } else if (vh->rcSource.bottom - vh->rcSource.top > 0) { - NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top; - } - } else if (mt.formattype == FORMAT_VideoInfo2 || mt.formattype == FORMAT_MPEG2Video) { - VIDEOINFOHEADER2* vh = (VIDEOINFOHEADER2*)mt.pbFormat; - - if (vh->dwPictAspectRatioX && vh->dwPictAspectRatioY) { - AspectRatio = CSize(vh->dwPictAspectRatioX, vh->dwPictAspectRatioY); - } - - NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight)); - if (vh->rcTarget.right - vh->rcTarget.left > 0) { - NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left; - } else if (vh->rcSource.right - vh->rcSource.left > 0) { - NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left; - } - - if (vh->rcTarget.bottom - vh->rcTarget.top > 0) { - NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top; - } else if (vh->rcSource.bottom - vh->rcSource.top > 0) { - NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top; - } - } - if (m_nativeVideoSize != NativeVideoSize || m_aspectRatio != AspectRatio) { - SetVideoSize(NativeVideoSize, AspectRatio); - AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS); - } - } - // If framerate not set by Video Decoder choose 23.976 - if (m_rtTimePerFrame == 0) { - m_rtTimePerFrame = 417083; - //ASSERT(FALSE); - } - - m_fps = 10000000.0 / m_rtTimePerFrame; - } - - if (!lpPresInfo || !lpPresInfo->lpSurf) { - return E_POINTER; - } - - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - if (m_pSubPicQueue) { - m_pSubPicQueue->SetFPS(m_fps); - - if (m_fUseInternalTimer && !g_bExternalSubtitleTime) { - REFERENCE_TIME rtCurFrameTime = lpPresInfo->rtEnd - lpPresInfo->rtStart; - REFERENCE_TIME rtSampleTime = 0; - // check if present timestamps are valid, rtStart can be invalid after a seek, while rtEnd always seems to be correct - // rtStart is reliable when rtEnd equals duration of two frames (+2 ms because timestamps are sometimes rounded to ms values) - // or if frame duration seems normal - if (lpPresInfo->rtEnd > lpPresInfo->rtStart && (lpPresInfo->rtEnd >= 2 * m_rtTimePerFrame + 20000LL || abs(rtCurFrameTime - m_rtTimePerFrame) < 10000LL)) { - rtSampleTime = lpPresInfo->rtStart; - //TRACE(_T("VMR9: Present %s -> %s | g_tSampleStart %s | g_tSegmentStart %s | rtCurFrameTime %ld\n"), ReftimeToString(lpPresInfo->rtStart).GetString(), ReftimeToString(lpPresInfo->rtEnd).GetString(), ReftimeToString(g_tSampleStart).GetString(), ReftimeToString(g_tSegmentStart).GetString(), rtCurFrameTime); - } else { - if (lpPresInfo->rtEnd > m_rtTimePerFrame) { - rtSampleTime = lpPresInfo->rtEnd - m_rtTimePerFrame; - } - //TRACE(_T("VMR9: Present %s -> %s INVALID! | g_tSampleStart %s | g_tSegmentStart %s | m_rtTimePerFrame %ld\n"), ReftimeToString(lpPresInfo->rtStart).GetString(), ReftimeToString(lpPresInfo->rtEnd).GetString(), ReftimeToString(g_tSampleStart).GetString(), ReftimeToString(g_tSegmentStart).GetString(), m_rtTimePerFrame); - } - __super::SetTime(g_tSegmentStart + rtSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); - } - } - - CSize ar(lpPresInfo->szAspectRatio.cx, lpPresInfo->szAspectRatio.cy); - if (ar != m_aspectRatio) { - SetVideoSize(m_nativeVideoSize, ar); - AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS); - } - - if (!m_bPendingResetDevice) { - CComPtr pTexture; - lpPresInfo->lpSurf->GetContainer(IID_PPV_ARGS(&pTexture)); - - if (pTexture) { - m_pVideoSurface[m_nCurSurface] = lpPresInfo->lpSurf; - if (m_pVideoTexture[m_nCurSurface]) { - m_pVideoTexture[m_nCurSurface] = pTexture; - } - } else { - m_pD3DDev->StretchRect(lpPresInfo->lpSurf, nullptr, m_pVideoSurface[m_nCurSurface], nullptr, D3DTEXF_NONE); - } - - // Tear test bars - if (GetRenderersData()->m_bTearingTest) { - RECT rcTearing; - - rcTearing.left = m_nTearingPos; - rcTearing.top = 0; - rcTearing.right = rcTearing.left + 4; - rcTearing.bottom = m_nativeVideoSize.cy; - m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - - rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; - rcTearing.right = rcTearing.left + 4; - m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); - - m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; - } - } - - Paint(true); - - return S_OK; -} - -// IVMRWindowlessControl9 -// -// It is only implemented (partially) for the dvd navigator's -// menu handling, which needs to know a few things about the -// location of our window. - -STDMETHODIMP CVMR9AllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) -{ - if (lpWidth) { - *lpWidth = m_nativeVideoSize.cx; - } - if (lpHeight) { - *lpHeight = m_nativeVideoSize.cy; - } - if (lpARWidth) { - *lpARWidth = m_aspectRatio.cx; - } - if (lpARHeight) { - *lpARHeight = m_aspectRatio.cy; - } - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) -{ - return E_NOTIMPL; // we have our own method for this -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect) -{ - CopyRect(lpSRCRect, CRect(CPoint(0, 0), GetVisibleVideoSize())); - CopyRect(lpDSTRect, &m_videoRect); - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetAspectRatioMode(DWORD* lpAspectRatioMode) -{ - if (lpAspectRatioMode) { - *lpAspectRatioMode = AM_ARMODE_STRETCHED; - } - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::SetAspectRatioMode(DWORD AspectRatioMode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::SetVideoClippingWindow(HWND hwnd) -{ - if (m_hWnd != hwnd) { - CAutoLock cAutoLock(this); - CAutoLock cRenderLock(&m_RenderLock); - - m_hWnd = hwnd; - m_bPendingResetDevice = true; - SendResetRequest(); - } - return S_OK; -} - -STDMETHODIMP CVMR9AllocatorPresenter::RepaintVideo(HWND hwnd, HDC hdc) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::DisplayModeChanged() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetCurrentImage(BYTE** lpDib) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::SetBorderColor(COLORREF Clr) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CVMR9AllocatorPresenter::GetBorderColor(COLORREF* lpClr) -{ - if (lpClr) { - *lpClr = 0; - } - return S_OK; -} +/* + * (C) 2006-2014, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "RenderersSettings.h" +#include "VMR9AllocatorPresenter.h" +#include "OuterVMR.h" +#include "IPinHook.h" +#include "MacrovisionKicker.h" +#include "Variables.h" + +// ISubPicAllocatorPresenter + + +using namespace DSObjects; + +// +// CVMR9AllocatorPresenter +// + +#define MY_USER_ID 0x6ABE51 + +CVMR9AllocatorPresenter::CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error) + : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, false, _Error) + , m_fUseInternalTimer(false) + , m_rtPrevStart(-1) +{ +} + +CVMR9AllocatorPresenter::~CVMR9AllocatorPresenter() +{ + if (m_bHookedNewSegment) { + UnhookNewSegment(); + } + if (m_bHookedReceive) { + UnhookReceive(); + } +} + +STDMETHODIMP CVMR9AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IVMRSurfaceAllocator9) + QI(IVMRImagePresenter9) + QI(IVMRWindowlessControl9) + QI(ID3DFullscreenControl) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CVMR9AllocatorPresenter::CreateDevice(CString& _Error) +{ + HRESULT hr = __super::CreateDevice(_Error); + if (FAILED(hr)) { + return hr; + } + + if (m_pIVMRSurfAllocNotify) { + HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(m_CurrentAdapter); + if (FAILED(hr = m_pIVMRSurfAllocNotify->ChangeD3DDevice(m_pD3DDev, hMonitor))) { + _Error += L"m_pIVMRSurfAllocNotify->ChangeD3DDevice failed"; + return hr; //return false; + } + } + + return hr; +} + +void CVMR9AllocatorPresenter::DeleteSurfaces() +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + m_pSurfaces.RemoveAll(); + + return __super::DeleteSurfaces(); +} + +STDMETHODIMP CVMR9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + *ppRenderer = nullptr; + + CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; + + COuterVMR9* pOuter = DEBUG_NEW COuterVMR9(NAME("COuterVMR9"), pUnk, &m_VMR9AlphaBitmap, this); + + pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuter); + CComQIPtr pBF = pUnk; + + CComPtr pPin = GetFirstPin(pBF); + if (!m_bIsPreview) { + if (HookNewSegment((IPinC*)(IPin*)pPin)) { + m_bHookedNewSegment = true; + CComQIPtr pMemInputPin = pPin; + if (HookReceive((IMemInputPinC*)(IMemInputPin*)pMemInputPin)) { + m_fUseInternalTimer = true; + m_bHookedReceive = true; + } + } + } + + CComQIPtr pConfig = pBF; + if (!pConfig) { + return E_FAIL; + } + + const CRenderersSettings& r = GetRenderersSettings(); + + if (r.fVMR9MixerMode) { + if (FAILED(pConfig->SetNumberOfStreams(1))) { + return E_FAIL; + } + + if (CComQIPtr pMC = pBF) { + DWORD dwPrefs; + pMC->GetMixingPrefs(&dwPrefs); + + // See http://msdn.microsoft.com/en-us/library/dd390928(VS.85).aspx + dwPrefs |= MixerPref9_NonSquareMixing; + dwPrefs |= MixerPref9_NoDecimation; + pMC->SetMixingPrefs(dwPrefs); + } + } + + if (FAILED(pConfig->SetRenderingMode(VMR9Mode_Renderless))) { + return E_FAIL; + } + + CComQIPtr pSAN = pBF; + if (!pSAN) { + return E_FAIL; + } + + if (FAILED(pSAN->AdviseSurfaceAllocator(MY_USER_ID, static_cast(this))) + || FAILED(AdviseNotify(pSAN))) { + return E_FAIL; + } + + *ppRenderer = (IUnknown*)pBF.Detach(); + + return S_OK; +} + +STDMETHODIMP_(void) CVMR9AllocatorPresenter::SetTime(REFERENCE_TIME rtNow) +{ + __super::SetTime(rtNow); +} + +// IVMRSurfaceAllocator9 + +STDMETHODIMP CVMR9AllocatorPresenter::InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers) +{ + CAutoLock lock(this); + CAutoLock cRenderLock(&m_RenderLock); + + if (!lpAllocInfo || !lpNumBuffers) { + return E_POINTER; + } + + if (!m_pIVMRSurfAllocNotify) { + return E_FAIL; + } + + // WTF: Is this some kind of forgotten debug code ? + if ((GetAsyncKeyState(VK_CONTROL) & 0x80000000)) + if (lpAllocInfo->Format == '21VY' || lpAllocInfo->Format == '024I') { + return E_FAIL; + } + + // The surfaces should already be free when InitializeDevice is called + DeleteSurfaces(); + + DWORD nOriginal = *lpNumBuffers; + + if (*lpNumBuffers == 1) { + *lpNumBuffers = 4; + m_nVMR9Surfaces = 4; + } else { + m_nVMR9Surfaces = 0; + } + m_pSurfaces.SetCount(*lpNumBuffers); + + int w = lpAllocInfo->dwWidth; + int h = abs((int)lpAllocInfo->dwHeight); + + HRESULT hr; + + if (lpAllocInfo->dwFlags & VMR9AllocFlag_3DRenderTarget) { + lpAllocInfo->dwFlags |= VMR9AllocFlag_TextureSurface; + } + + hr = m_pIVMRSurfAllocNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, &m_pSurfaces[0]); + if (FAILED(hr)) { + return hr; + } + + m_pSurfaces.SetCount(*lpNumBuffers); + + m_bNeedCheckSample = true; + CSize VideoSize(w, h); + CSize AspectRatio(lpAllocInfo->szAspectRatio.cx, lpAllocInfo->szAspectRatio.cy); + SetVideoSize(VideoSize, AspectRatio); + + if (FAILED(hr = AllocSurfaces())) { + return hr; + } + + if (!(lpAllocInfo->dwFlags & VMR9AllocFlag_TextureSurface)) { + // test if the colorspace is acceptable + if (FAILED(hr = m_pD3DDev->StretchRect(m_pSurfaces[0], nullptr, m_pVideoSurface[m_nCurSurface], nullptr, D3DTEXF_NONE))) { + DeleteSurfaces(); + return E_FAIL; + } + } + + hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], nullptr, 0); + + if (m_nVMR9Surfaces && m_nVMR9Surfaces != (int)*lpNumBuffers) { + m_nVMR9Surfaces = *lpNumBuffers; + } + *lpNumBuffers = std::min(nOriginal, *lpNumBuffers); + m_iVMR9Surface = 0; + + return hr; +} + +STDMETHODIMP CVMR9AllocatorPresenter::TerminateDevice(DWORD_PTR dwUserID) +{ + // We should not free the surfaces until we are told to ! + // Thats what TerminateDevice is for + DeleteSurfaces(); + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface) +{ + CheckPointer(lplpSurface, E_POINTER); + + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + /* + SurfaceIndex = 0 + m_pSurfaces.GetCount() = 0 + + Scenario: + Thread 1: + Wait on m_RenderLock in this function + Thread 2: + Have m_RenderLock and removes all m_pSurfaces + (Happens by calling ex CDX9AllocatorPresenter::ResetDevice) + + When thread 2 releases the lock thread 1 gets it and boom! + + Possible solution: Adding object lock and moving m_RenderLock to try to fix this threading issue. + This problem occurs when moving the window from display a to display b. + + NOTE: This is just a workaround. + CDX9AllocatorPresenter doesn't follow the rules which is why this happened. + And it is used by EVR custom (which it really shouldn't) so i can't easily fix it without breaking EVR custom. + */ + if (SurfaceIndex >= m_pSurfaces.GetCount()) { + return E_FAIL; + } + + if (m_nVMR9Surfaces) { + ++m_iVMR9Surface; + m_iVMR9Surface = m_iVMR9Surface % m_nVMR9Surfaces; + *lplpSurface = m_pSurfaces[m_iVMR9Surface + SurfaceIndex]; + (*lplpSurface)->AddRef(); + } else { + m_iVMR9Surface = SurfaceIndex; + *lplpSurface = m_pSurfaces[SurfaceIndex]; + (*lplpSurface)->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify) +{ + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + m_pIVMRSurfAllocNotify = lpIVMRSurfAllocNotify; + + HRESULT hr; + HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D)); + if (FAILED(hr = m_pIVMRSurfAllocNotify->SetD3DDevice(m_pD3DDev, hMonitor))) { + return hr; + } + + return S_OK; +} + +// IVMRImagePresenter9 + +STDMETHODIMP CVMR9AllocatorPresenter::StartPresenting(DWORD_PTR dwUserID) +{ + if (!m_bPendingResetDevice) { + ASSERT(m_pD3DDev); + } + + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + CComPtr pVMR9; + CComPtr pPin; + if (SUCCEEDED(m_pIVMRSurfAllocNotify->QueryInterface(IID_PPV_ARGS(&pVMR9))) && + SUCCEEDED(pVMR9->FindPin(L"VMR Input0", &pPin))) { + VERIFY(SUCCEEDED(pPin->ConnectionMediaType(&m_inputMediaType))); + } + + m_bIsRendering = true; + + return m_pD3DDev ? S_OK : E_FAIL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::StopPresenting(DWORD_PTR dwUserID) +{ + m_bIsRendering = false; + + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo) +{ + SetThreadName(DWORD(-1), "CVMR9AllocatorPresenter"); + CheckPointer(m_pIVMRSurfAllocNotify, E_UNEXPECTED); + + if (m_rtTimePerFrame == 0 || m_bNeedCheckSample) { + m_bNeedCheckSample = false; + CComPtr pVMR9; + CComPtr pPin; + CMediaType mt; + + if (SUCCEEDED(m_pIVMRSurfAllocNotify->QueryInterface(IID_PPV_ARGS(&pVMR9))) && + SUCCEEDED(pVMR9->FindPin(L"VMR Input0", &pPin)) && + SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame); + + CSize NativeVideoSize = m_nativeVideoSize; + CSize AspectRatio = m_aspectRatio; + if (mt.formattype == FORMAT_VideoInfo || mt.formattype == FORMAT_MPEGVideo) { + VIDEOINFOHEADER* vh = (VIDEOINFOHEADER*)mt.pbFormat; + + NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight)); + if (vh->rcTarget.right - vh->rcTarget.left > 0) { + NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left; + } else if (vh->rcSource.right - vh->rcSource.left > 0) { + NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left; + } + + if (vh->rcTarget.bottom - vh->rcTarget.top > 0) { + NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top; + } else if (vh->rcSource.bottom - vh->rcSource.top > 0) { + NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top; + } + } else if (mt.formattype == FORMAT_VideoInfo2 || mt.formattype == FORMAT_MPEG2Video) { + VIDEOINFOHEADER2* vh = (VIDEOINFOHEADER2*)mt.pbFormat; + + if (vh->dwPictAspectRatioX && vh->dwPictAspectRatioY) { + AspectRatio = CSize(vh->dwPictAspectRatioX, vh->dwPictAspectRatioY); + } + + NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight)); + if (vh->rcTarget.right - vh->rcTarget.left > 0) { + NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left; + } else if (vh->rcSource.right - vh->rcSource.left > 0) { + NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left; + } + + if (vh->rcTarget.bottom - vh->rcTarget.top > 0) { + NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top; + } else if (vh->rcSource.bottom - vh->rcSource.top > 0) { + NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top; + } + } + if (m_nativeVideoSize != NativeVideoSize || m_aspectRatio != AspectRatio) { + SetVideoSize(NativeVideoSize, AspectRatio); + AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS); + } + } + // If framerate not set by Video Decoder choose 23.976 + if (m_rtTimePerFrame == 0) { + m_rtTimePerFrame = 417083; + //ASSERT(FALSE); + } + + m_fps = 10000000.0 / m_rtTimePerFrame; + } + + if (!lpPresInfo || !lpPresInfo->lpSurf) { + return E_POINTER; + } + + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + if (m_pSubPicQueue) { + m_pSubPicQueue->SetFPS(m_fps); + + if (m_fUseInternalTimer && !g_bExternalSubtitleTime) { + REFERENCE_TIME rtCurFrameTime = lpPresInfo->rtEnd - lpPresInfo->rtStart; + REFERENCE_TIME rtSampleTime = 0; + // check if present timestamps are valid, rtStart can be invalid after a seek, while rtEnd always seems to be correct + // rtStart is reliable when rtEnd equals duration of two frames (+2 ms because timestamps are sometimes rounded to ms values) + // or if frame duration seems normal + if (lpPresInfo->rtEnd > lpPresInfo->rtStart && (lpPresInfo->rtEnd >= 2 * m_rtTimePerFrame + 20000LL || abs(rtCurFrameTime - m_rtTimePerFrame) < 10000LL)) { + rtSampleTime = lpPresInfo->rtStart; + //TRACE(_T("VMR9: Present %s -> %s | g_tSampleStart %s | g_tSegmentStart %s | rtCurFrameTime %ld\n"), ReftimeToString(lpPresInfo->rtStart).GetString(), ReftimeToString(lpPresInfo->rtEnd).GetString(), ReftimeToString(g_tSampleStart).GetString(), ReftimeToString(g_tSegmentStart).GetString(), rtCurFrameTime); + } else { + if (lpPresInfo->rtEnd > m_rtTimePerFrame) { + rtSampleTime = lpPresInfo->rtEnd - m_rtTimePerFrame; + } + //TRACE(_T("VMR9: Present %s -> %s INVALID! | g_tSampleStart %s | g_tSegmentStart %s | m_rtTimePerFrame %ld\n"), ReftimeToString(lpPresInfo->rtStart).GetString(), ReftimeToString(lpPresInfo->rtEnd).GetString(), ReftimeToString(g_tSampleStart).GetString(), ReftimeToString(g_tSegmentStart).GetString(), m_rtTimePerFrame); + } + __super::SetTime(g_tSegmentStart + rtSampleTime * (g_bExternalSubtitle ? g_dRate : 1)); + } + } + + CSize ar(lpPresInfo->szAspectRatio.cx, lpPresInfo->szAspectRatio.cy); + if (ar != m_aspectRatio) { + SetVideoSize(m_nativeVideoSize, ar); + AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS); + } + + if (!m_bPendingResetDevice) { + CComPtr pTexture; + lpPresInfo->lpSurf->GetContainer(IID_PPV_ARGS(&pTexture)); + + if (pTexture) { + m_pVideoSurface[m_nCurSurface] = lpPresInfo->lpSurf; + if (m_pVideoTexture[m_nCurSurface]) { + m_pVideoTexture[m_nCurSurface] = pTexture; + } + } else { + m_pD3DDev->StretchRect(lpPresInfo->lpSurf, nullptr, m_pVideoSurface[m_nCurSurface], nullptr, D3DTEXF_NONE); + } + + // Tear test bars + if (GetRenderersData()->m_bTearingTest) { + RECT rcTearing; + + rcTearing.left = m_nTearingPos; + rcTearing.top = 0; + rcTearing.right = rcTearing.left + 4; + rcTearing.bottom = m_nativeVideoSize.cy; + m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + + rcTearing.left = (rcTearing.right + 15) % m_nativeVideoSize.cx; + rcTearing.right = rcTearing.left + 4; + m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB(255, 255, 0, 0)); + + m_nTearingPos = (m_nTearingPos + 7) % m_nativeVideoSize.cx; + } + } + + Paint(true); + + return S_OK; +} + +// IVMRWindowlessControl9 +// +// It is only implemented (partially) for the dvd navigator's +// menu handling, which needs to know a few things about the +// location of our window. + +STDMETHODIMP CVMR9AllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight) +{ + if (lpWidth) { + *lpWidth = m_nativeVideoSize.cx; + } + if (lpHeight) { + *lpHeight = m_nativeVideoSize.cy; + } + if (lpARWidth) { + *lpARWidth = m_aspectRatio.cx; + } + if (lpARHeight) { + *lpARHeight = m_aspectRatio.cy; + } + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) +{ + return E_NOTIMPL; // we have our own method for this +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect) +{ + CopyRect(lpSRCRect, CRect(CPoint(0, 0), GetVisibleVideoSize())); + CopyRect(lpDSTRect, &m_videoRect); + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetAspectRatioMode(DWORD* lpAspectRatioMode) +{ + if (lpAspectRatioMode) { + *lpAspectRatioMode = AM_ARMODE_STRETCHED; + } + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::SetAspectRatioMode(DWORD AspectRatioMode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::SetVideoClippingWindow(HWND hwnd) +{ + if (m_hWnd != hwnd) { + CAutoLock cAutoLock(this); + CAutoLock cRenderLock(&m_RenderLock); + + m_hWnd = hwnd; + m_bPendingResetDevice = true; + SendResetRequest(); + } + return S_OK; +} + +STDMETHODIMP CVMR9AllocatorPresenter::RepaintVideo(HWND hwnd, HDC hdc) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::DisplayModeChanged() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetCurrentImage(BYTE** lpDib) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::SetBorderColor(COLORREF Clr) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CVMR9AllocatorPresenter::GetBorderColor(COLORREF* lpClr) +{ + if (lpClr) { + *lpClr = 0; + } + return S_OK; +} diff --git a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h index 84c58f1b3fd..de339f0210a 100644 --- a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h @@ -1,80 +1,80 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "DX9AllocatorPresenter.h" - -namespace DSObjects -{ - class CVMR9AllocatorPresenter - : public CDX9AllocatorPresenter - , public IVMRSurfaceAllocator9 - , public IVMRImagePresenter9 - , public IVMRWindowlessControl9 - { - protected: - CComPtr m_pIVMRSurfAllocNotify; - CInterfaceArray m_pSurfaces; - - HRESULT CreateDevice(CString& _Error); - void DeleteSurfaces(); - - bool m_fUseInternalTimer; - REFERENCE_TIME m_rtPrevStart; - - public: - CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); - ~CVMR9AllocatorPresenter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); - STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow); - - // IVMRSurfaceAllocator9 - STDMETHODIMP InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers); - STDMETHODIMP TerminateDevice(DWORD_PTR dwID); - STDMETHODIMP GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface); - STDMETHODIMP AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify); - - // IVMRImagePresenter9 - STDMETHODIMP StartPresenting(DWORD_PTR dwUserID); - STDMETHODIMP StopPresenting(DWORD_PTR dwUserID); - STDMETHODIMP PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo); - - // IVMRWindowlessControl9 - STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); - STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight); - STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight); - STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect); - STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect); - STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode); - STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode); - STDMETHODIMP SetVideoClippingWindow(HWND hwnd); - STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc); - STDMETHODIMP DisplayModeChanged(); - STDMETHODIMP GetCurrentImage(BYTE** lpDib); - STDMETHODIMP SetBorderColor(COLORREF Clr); - STDMETHODIMP GetBorderColor(COLORREF* lpClr); - }; -} +/* + * (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 . + * + */ + +#pragma once + +#include "DX9AllocatorPresenter.h" + +namespace DSObjects +{ + class CVMR9AllocatorPresenter + : public CDX9AllocatorPresenter + , public IVMRSurfaceAllocator9 + , public IVMRImagePresenter9 + , public IVMRWindowlessControl9 + { + protected: + CComPtr m_pIVMRSurfAllocNotify; + CInterfaceArray m_pSurfaces; + + HRESULT CreateDevice(CString& _Error); + void DeleteSurfaces(); + + bool m_fUseInternalTimer; + REFERENCE_TIME m_rtPrevStart; + + public: + CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString& _Error); + ~CVMR9AllocatorPresenter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer); + STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow); + + // IVMRSurfaceAllocator9 + STDMETHODIMP InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers); + STDMETHODIMP TerminateDevice(DWORD_PTR dwID); + STDMETHODIMP GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface); + STDMETHODIMP AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify); + + // IVMRImagePresenter9 + STDMETHODIMP StartPresenting(DWORD_PTR dwUserID); + STDMETHODIMP StopPresenting(DWORD_PTR dwUserID); + STDMETHODIMP PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo); + + // IVMRWindowlessControl9 + STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight); + STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight); + STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight); + STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect); + STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect); + STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode); + STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode); + STDMETHODIMP SetVideoClippingWindow(HWND hwnd); + STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc); + STDMETHODIMP DisplayModeChanged(); + STDMETHODIMP GetCurrentImage(BYTE** lpDib); + STDMETHODIMP SetBorderColor(COLORREF Clr); + STDMETHODIMP GetBorderColor(COLORREF* lpClr); + }; +} diff --git a/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj b/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj index a41fadd9579..6c4e3d6f9b5 100644 --- a/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj +++ b/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj @@ -1,106 +1,106 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {FB565A7A-50DC-4A0D-852D-5E7F74DAB82C} - VideoRenderers - MFCProj - VideoRenderers - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - $(IncludePath);$(DXSDK_DIR)Include - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {FB565A7A-50DC-4A0D-852D-5E7F74DAB82C} + VideoRenderers + MFCProj + VideoRenderers + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + $(IncludePath);$(DXSDK_DIR)Include + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj.filters b/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj.filters index 60592c01d72..275d6df73e4 100644 --- a/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj.filters +++ b/src/filters/renderer/VideoRenderers/VideoRenderers.vcxproj.filters @@ -1,155 +1,155 @@ - - - - - {91abd446-f660-4356-a9fe-c6f7f9dee6cb} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {48be6b66-cd30-4af5-b7d8-22839d28baaa} - h;hpp;hxx;hm;inl - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {91abd446-f660-4356-a9fe-c6f7f9dee6cb} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {48be6b66-cd30-4af5-b7d8-22839d28baaa} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp index 0d71621a0b0..fd54422cc7f 100644 --- a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp +++ b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp @@ -1,299 +1,299 @@ -/* - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "madVRAllocatorPresenter.h" -#include "../../../SubPic/DX9SubPic.h" -#include "../../../SubPic/SubPicQueueImpl.h" -#include "RenderersSettings.h" -#include -#include -#include "IPinHook.h" -#include "Variables.h" -#include "Utils.h" - -using namespace DSObjects; - -CmadVRAllocatorPresenter::CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error) - : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) -{ - if (FAILED(hr)) { - _Error += L"ISubPicAllocatorPresenterImpl failed\n"; - return; - } - - hr = S_OK; -} - -CmadVRAllocatorPresenter::~CmadVRAllocatorPresenter() -{ - // the order is important here - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - m_pMVR = nullptr; - - if (m_bHookedNewSegment) { - UnhookNewSegment(); - } -} - -STDMETHODIMP CmadVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - if (riid != IID_IUnknown && m_pMVR) { - if (SUCCEEDED(m_pMVR->QueryInterface(riid, ppv))) { - return S_OK; - } - } - - return QI(ISubRenderCallback) - QI(ISubRenderCallback2) - QI(ISubRenderCallback3) - QI(ISubRenderCallback4) - QI(ISubPicAllocatorPresenter3) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// ISubRenderCallback - -HRESULT CmadVRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev) -{ - if (!pD3DDev) { - // release all resources - m_pSubPicQueue = nullptr; - m_pAllocator = nullptr; - __super::SetPosition(CRect(), CRect()); - return S_OK; - } - - const CRenderersSettings& r = GetRenderersSettings(); - CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); - InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); - - if (m_pAllocator) { - m_pAllocator->ChangeDevice(pD3DDev); - } else { - m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(pD3DDev, m_maxSubtitleTextureSize, true); - } - - HRESULT hr = S_OK; - if (!m_pSubPicQueue) { - CAutoLock cAutoLock(this); - m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 - ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) - : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); - } else { - m_pSubPicQueue->Invalidate(); - } - - if (SUCCEEDED(hr) && m_pSubPicProvider) { - m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); - } - - return hr; -} - -// ISubRenderCallback3 - -HRESULT CmadVRAllocatorPresenter::RenderEx3(REFERENCE_TIME rtStart, - REFERENCE_TIME /*rtStop*/, - REFERENCE_TIME atpf, - RECT croppedVideoRect, - RECT /*originalVideoRect*/, - RECT viewportRect, - const double videoStretchFactor /*= 1.0*/, - int xOffsetInPixels /*= 0*/, DWORD flags /*= 0*/) -{ - CheckPointer(m_pSubPicQueue, E_UNEXPECTED); - - __super::SetPosition(viewportRect, croppedVideoRect); - if (!g_bExternalSubtitleTime) { - if (g_bExternalSubtitle && g_dRate != 0.0) { - const REFERENCE_TIME sampleTime = rtStart - g_tSegmentStart; - SetTime(g_tSegmentStart + sampleTime * g_dRate); - } else { - SetTime(rtStart); - } - } - if (atpf > 0 && m_pSubPicQueue) { - m_fps = 10000000.0 / atpf; - m_pSubPicQueue->SetFPS(m_fps); - } - AlphaBltSubPic(viewportRect, croppedVideoRect, nullptr, videoStretchFactor, xOffsetInPixels); - return S_OK; -} - -// ISubPicAllocatorPresenter - -STDMETHODIMP CmadVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) -{ - CheckPointer(ppRenderer, E_POINTER); - ASSERT(!m_pMVR); - - HRESULT hr = S_FALSE; - - CHECK_HR(m_pMVR.CoCreateInstance(CLSID_madVR, GetOwner())); - - if (CComQIPtr pSR = m_pMVR) { - VERIFY(SUCCEEDED(pSR->SetCallback(this))); - } - - (*ppRenderer = (IUnknown*)(INonDelegatingUnknown*)(this))->AddRef(); - - CComQIPtr pBF = m_pMVR; - CComPtr pPin = GetFirstPin(pBF); - m_bHookedNewSegment = HookNewSegment((IPinC*)(IPin*)pPin); - - return S_OK; -} - -STDMETHODIMP_(void) CmadVRAllocatorPresenter::SetPosition(RECT w, RECT v) -{ - if (CComQIPtr pBV = m_pMVR) { - pBV->SetDefaultSourcePosition(); - pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top); - } - - if (CComQIPtr pVW = m_pMVR) { - pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top); - } - - SetVideoSize(GetVideoSize(false), GetVideoSize(true)); -} - -STDMETHODIMP CmadVRAllocatorPresenter::SetRotation(int rotation) -{ - if (AngleStep90(rotation)) { - HRESULT hr = E_NOTIMPL; - int curRotation = rotation; - if (CComQIPtr pMVRI = m_pMVR) { - pMVRI->GetInt("rotation", &curRotation); - } - if (CComQIPtr pMVRC = m_pMVR) { - hr = pMVRC->SendCommandInt("rotate", rotation); - if (SUCCEEDED(hr) && curRotation != rotation) { - hr = pMVRC->SendCommand("redraw"); - } - } - return hr; - } - return E_INVALIDARG; -} - -STDMETHODIMP_(int) CmadVRAllocatorPresenter::GetRotation() -{ - if (CComQIPtr pMVRI = m_pMVR) { - int rotation = 0; - if (SUCCEEDED(pMVRI->GetInt("rotation", &rotation))) { - return rotation; - } - } - return 0; -} - -STDMETHODIMP_(SIZE) CmadVRAllocatorPresenter::GetVideoSize(bool bCorrectAR) const -{ - CSize size = { 0, 0 }; - - if (!bCorrectAR) { - if (CComQIPtr pBV = m_pMVR) { - // Final size of the video, after all scaling and cropping operations - // This is also aspect ratio adjusted - pBV->GetVideoSize(&size.cx, &size.cy); - } - } else { - if (CComQIPtr pBV2 = m_pMVR) { - pBV2->GetPreferredAspectRatio(&size.cx, &size.cy); - } - } - - return size; -} - -STDMETHODIMP_(bool) CmadVRAllocatorPresenter::Paint(bool /*bAll*/) -{ - if (CComQIPtr pMVRC = m_pMVR) { - return SUCCEEDED(pMVRC->SendCommand("redraw")); - } - return false; -} - -STDMETHODIMP CmadVRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) -{ - HRESULT hr = E_NOTIMPL; - if (CComQIPtr pBV = m_pMVR) { - hr = pBV->GetCurrentImage((long*)size, (long*)lpDib); - } - return hr; -} - -STDMETHODIMP CmadVRAllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) -{ - HRESULT hr = E_NOTIMPL; - - if (CComQIPtr pMVREPS = m_pMVR) { - if (!pSrcData && !pTarget) { - hr = pMVREPS->ClearPixelShaders(bScreenSpace ? ShaderStage_PostScale : ShaderStage_PreScale); - } else { - hr = pMVREPS->AddPixelShader(pSrcData, pTarget, bScreenSpace ? ShaderStage_PostScale : ShaderStage_PreScale, nullptr); - } - } - - return hr; -} - -// ISubPicAllocatorPresenter2 - -STDMETHODIMP_(bool) CmadVRAllocatorPresenter::IsRendering() -{ - if (CComQIPtr pMVRI = m_pMVR) { - int playbackState; - if (SUCCEEDED(pMVRI->GetInt("playbackState", &playbackState))) { - return playbackState == State_Running; - } - } - return false; -} -// ISubPicAllocatorPresenter3 - -STDMETHODIMP CmadVRAllocatorPresenter::ClearPixelShaders(int target) -{ - ASSERT(TARGET_FRAME == ShaderStage_PreScale && TARGET_SCREEN == ShaderStage_PostScale); - HRESULT hr = E_NOTIMPL; - - if (CComQIPtr pMVREPS = m_pMVR) { - hr = pMVREPS->ClearPixelShaders(target); - } - return hr; -} - -STDMETHODIMP CmadVRAllocatorPresenter::AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) -{ - ASSERT(TARGET_FRAME == ShaderStage_PreScale && TARGET_SCREEN == ShaderStage_PostScale); - HRESULT hr = E_NOTIMPL; - - if (CComQIPtr pMVREPS = m_pMVR) { - hr = pMVREPS->AddPixelShader(sourceCode, profile, target, nullptr); - } - return hr; -} - -STDMETHODIMP_(bool) CmadVRAllocatorPresenter::ToggleStats() { - return false; -} +/* + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "madVRAllocatorPresenter.h" +#include "../../../SubPic/DX9SubPic.h" +#include "../../../SubPic/SubPicQueueImpl.h" +#include "RenderersSettings.h" +#include +#include +#include "IPinHook.h" +#include "Variables.h" +#include "Utils.h" + +using namespace DSObjects; + +CmadVRAllocatorPresenter::CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error) + : CSubPicAllocatorPresenterImpl(hWnd, hr, &_Error) +{ + if (FAILED(hr)) { + _Error += L"ISubPicAllocatorPresenterImpl failed\n"; + return; + } + + hr = S_OK; +} + +CmadVRAllocatorPresenter::~CmadVRAllocatorPresenter() +{ + // the order is important here + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + m_pMVR = nullptr; + + if (m_bHookedNewSegment) { + UnhookNewSegment(); + } +} + +STDMETHODIMP CmadVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + if (riid != IID_IUnknown && m_pMVR) { + if (SUCCEEDED(m_pMVR->QueryInterface(riid, ppv))) { + return S_OK; + } + } + + return QI(ISubRenderCallback) + QI(ISubRenderCallback2) + QI(ISubRenderCallback3) + QI(ISubRenderCallback4) + QI(ISubPicAllocatorPresenter3) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// ISubRenderCallback + +HRESULT CmadVRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev) +{ + if (!pD3DDev) { + // release all resources + m_pSubPicQueue = nullptr; + m_pAllocator = nullptr; + __super::SetPosition(CRect(), CRect()); + return S_OK; + } + + const CRenderersSettings& r = GetRenderersSettings(); + CSize largestScreen = GetLargestScreenSize(CSize(2560, 1440)); + InitMaxSubtitleTextureSize(r.subPicQueueSettings.nMaxResX, r.subPicQueueSettings.nMaxResY, largestScreen); + + if (m_pAllocator) { + m_pAllocator->ChangeDevice(pD3DDev); + } else { + m_pAllocator = DEBUG_NEW CDX9SubPicAllocator(pD3DDev, m_maxSubtitleTextureSize, true); + } + + HRESULT hr = S_OK; + if (!m_pSubPicQueue) { + CAutoLock cAutoLock(this); + m_pSubPicQueue = r.subPicQueueSettings.nSize > 0 + ? (ISubPicQueue*)DEBUG_NEW CSubPicQueue(r.subPicQueueSettings, m_pAllocator, &hr) + : (ISubPicQueue*)DEBUG_NEW CSubPicQueueNoThread(r.subPicQueueSettings, m_pAllocator, &hr); + } else { + m_pSubPicQueue->Invalidate(); + } + + if (SUCCEEDED(hr) && m_pSubPicProvider) { + m_pSubPicQueue->SetSubPicProvider(m_pSubPicProvider); + } + + return hr; +} + +// ISubRenderCallback3 + +HRESULT CmadVRAllocatorPresenter::RenderEx3(REFERENCE_TIME rtStart, + REFERENCE_TIME /*rtStop*/, + REFERENCE_TIME atpf, + RECT croppedVideoRect, + RECT /*originalVideoRect*/, + RECT viewportRect, + const double videoStretchFactor /*= 1.0*/, + int xOffsetInPixels /*= 0*/, DWORD flags /*= 0*/) +{ + CheckPointer(m_pSubPicQueue, E_UNEXPECTED); + + __super::SetPosition(viewportRect, croppedVideoRect); + if (!g_bExternalSubtitleTime) { + if (g_bExternalSubtitle && g_dRate != 0.0) { + const REFERENCE_TIME sampleTime = rtStart - g_tSegmentStart; + SetTime(g_tSegmentStart + sampleTime * g_dRate); + } else { + SetTime(rtStart); + } + } + if (atpf > 0 && m_pSubPicQueue) { + m_fps = 10000000.0 / atpf; + m_pSubPicQueue->SetFPS(m_fps); + } + AlphaBltSubPic(viewportRect, croppedVideoRect, nullptr, videoStretchFactor, xOffsetInPixels); + return S_OK; +} + +// ISubPicAllocatorPresenter + +STDMETHODIMP CmadVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer) +{ + CheckPointer(ppRenderer, E_POINTER); + ASSERT(!m_pMVR); + + HRESULT hr = S_FALSE; + + CHECK_HR(m_pMVR.CoCreateInstance(CLSID_madVR, GetOwner())); + + if (CComQIPtr pSR = m_pMVR) { + VERIFY(SUCCEEDED(pSR->SetCallback(this))); + } + + (*ppRenderer = (IUnknown*)(INonDelegatingUnknown*)(this))->AddRef(); + + CComQIPtr pBF = m_pMVR; + CComPtr pPin = GetFirstPin(pBF); + m_bHookedNewSegment = HookNewSegment((IPinC*)(IPin*)pPin); + + return S_OK; +} + +STDMETHODIMP_(void) CmadVRAllocatorPresenter::SetPosition(RECT w, RECT v) +{ + if (CComQIPtr pBV = m_pMVR) { + pBV->SetDefaultSourcePosition(); + pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top); + } + + if (CComQIPtr pVW = m_pMVR) { + pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top); + } + + SetVideoSize(GetVideoSize(false), GetVideoSize(true)); +} + +STDMETHODIMP CmadVRAllocatorPresenter::SetRotation(int rotation) +{ + if (AngleStep90(rotation)) { + HRESULT hr = E_NOTIMPL; + int curRotation = rotation; + if (CComQIPtr pMVRI = m_pMVR) { + pMVRI->GetInt("rotation", &curRotation); + } + if (CComQIPtr pMVRC = m_pMVR) { + hr = pMVRC->SendCommandInt("rotate", rotation); + if (SUCCEEDED(hr) && curRotation != rotation) { + hr = pMVRC->SendCommand("redraw"); + } + } + return hr; + } + return E_INVALIDARG; +} + +STDMETHODIMP_(int) CmadVRAllocatorPresenter::GetRotation() +{ + if (CComQIPtr pMVRI = m_pMVR) { + int rotation = 0; + if (SUCCEEDED(pMVRI->GetInt("rotation", &rotation))) { + return rotation; + } + } + return 0; +} + +STDMETHODIMP_(SIZE) CmadVRAllocatorPresenter::GetVideoSize(bool bCorrectAR) const +{ + CSize size = { 0, 0 }; + + if (!bCorrectAR) { + if (CComQIPtr pBV = m_pMVR) { + // Final size of the video, after all scaling and cropping operations + // This is also aspect ratio adjusted + pBV->GetVideoSize(&size.cx, &size.cy); + } + } else { + if (CComQIPtr pBV2 = m_pMVR) { + pBV2->GetPreferredAspectRatio(&size.cx, &size.cy); + } + } + + return size; +} + +STDMETHODIMP_(bool) CmadVRAllocatorPresenter::Paint(bool /*bAll*/) +{ + if (CComQIPtr pMVRC = m_pMVR) { + return SUCCEEDED(pMVRC->SendCommand("redraw")); + } + return false; +} + +STDMETHODIMP CmadVRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size) +{ + HRESULT hr = E_NOTIMPL; + if (CComQIPtr pBV = m_pMVR) { + hr = pBV->GetCurrentImage((long*)size, (long*)lpDib); + } + return hr; +} + +STDMETHODIMP CmadVRAllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) +{ + HRESULT hr = E_NOTIMPL; + + if (CComQIPtr pMVREPS = m_pMVR) { + if (!pSrcData && !pTarget) { + hr = pMVREPS->ClearPixelShaders(bScreenSpace ? ShaderStage_PostScale : ShaderStage_PreScale); + } else { + hr = pMVREPS->AddPixelShader(pSrcData, pTarget, bScreenSpace ? ShaderStage_PostScale : ShaderStage_PreScale, nullptr); + } + } + + return hr; +} + +// ISubPicAllocatorPresenter2 + +STDMETHODIMP_(bool) CmadVRAllocatorPresenter::IsRendering() +{ + if (CComQIPtr pMVRI = m_pMVR) { + int playbackState; + if (SUCCEEDED(pMVRI->GetInt("playbackState", &playbackState))) { + return playbackState == State_Running; + } + } + return false; +} +// ISubPicAllocatorPresenter3 + +STDMETHODIMP CmadVRAllocatorPresenter::ClearPixelShaders(int target) +{ + ASSERT(TARGET_FRAME == ShaderStage_PreScale && TARGET_SCREEN == ShaderStage_PostScale); + HRESULT hr = E_NOTIMPL; + + if (CComQIPtr pMVREPS = m_pMVR) { + hr = pMVREPS->ClearPixelShaders(target); + } + return hr; +} + +STDMETHODIMP CmadVRAllocatorPresenter::AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) +{ + ASSERT(TARGET_FRAME == ShaderStage_PreScale && TARGET_SCREEN == ShaderStage_PostScale); + HRESULT hr = E_NOTIMPL; + + if (CComQIPtr pMVREPS = m_pMVR) { + hr = pMVREPS->AddPixelShader(sourceCode, profile, target, nullptr); + } + return hr; +} + +STDMETHODIMP_(bool) CmadVRAllocatorPresenter::ToggleStats() { + return false; +} diff --git a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h index 9cb736c6af2..089c7b3d355 100644 --- a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h +++ b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h @@ -1,89 +1,89 @@ -/* - * (C) 2006-2016 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 . - * - */ - -#pragma once - -#include "../SubPic/SubPicAllocatorPresenterImpl.h" -#include "../SubPic/ISubRender.h" - -namespace DSObjects -{ - class CmadVRAllocatorPresenter : public CSubPicAllocatorPresenterImpl, ISubRenderCallback4 - { - CComPtr m_pMVR; - public: - CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error); - virtual ~CmadVRAllocatorPresenter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override; - - // ISubRenderCallback - STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev) override; - STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, - int bottom, int width, int height) override { - return RenderEx(rtStart, 0, 0, left, top, right, bottom, width, height); - } - - // ISubRenderCallback2 - STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, - int left, int top, int right, int bottom, int width, int height) override { - return RenderEx2(rtStart, rtStop, atpf, { left, top, right, bottom }, - { left, top, right, bottom }, { 0, 0, width, height }); - } - - // ISubRenderCallback3 - STDMETHODIMP RenderEx2(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME atpf, RECT croppedVideoRect, - RECT originalVideoRect, RECT viewportRect, - const double videoStretchFactor = 1.0) override { - return RenderEx3(std::move(rtStart), std::move(rtStop), std::move(atpf), std::move(croppedVideoRect), - std::move(originalVideoRect), std::move(viewportRect), std::move(videoStretchFactor)); - } - - // ISubRenderCallback4 - STDMETHODIMP RenderEx3(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, - REFERENCE_TIME atpf, RECT croppedVideoRect, - RECT originalVideoRect, RECT viewportRect, - const double videoStretchFactor = 1.0, - int xOffsetInPixels = 0, DWORD flags = 0) override; - - // ISubPicAllocatorPresenter - STDMETHODIMP CreateRenderer(IUnknown** ppRenderer) override; - STDMETHODIMP_(void) SetPosition(RECT w, RECT v) override; - STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const override; - STDMETHODIMP_(bool) Paint(bool bAll) override; - STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size) override; - STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) override { - return SetPixelShader2(pSrcData, pTarget, false); - } - STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) override; - - // ISubPicAllocatorPresenter2 - STDMETHODIMP_(bool) IsRendering() override; - // ISubPicAllocatorPresenter3 - STDMETHODIMP SetRotation(int rotation) override; - STDMETHODIMP_(int) GetRotation() override; - STDMETHODIMP_(int) GetPixelShaderMode() override { return 9; } - STDMETHODIMP ClearPixelShaders(int target) override; - STDMETHODIMP AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) override; - STDMETHODIMP_(bool) ToggleStats() override; - }; -} +/* + * (C) 2006-2016 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 . + * + */ + +#pragma once + +#include "../SubPic/SubPicAllocatorPresenterImpl.h" +#include "../SubPic/ISubRender.h" + +namespace DSObjects +{ + class CmadVRAllocatorPresenter : public CSubPicAllocatorPresenterImpl, ISubRenderCallback4 + { + CComPtr m_pMVR; + public: + CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString& _Error); + virtual ~CmadVRAllocatorPresenter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override; + + // ISubRenderCallback + STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev) override; + STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, + int bottom, int width, int height) override { + return RenderEx(rtStart, 0, 0, left, top, right, bottom, width, height); + } + + // ISubRenderCallback2 + STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf, + int left, int top, int right, int bottom, int width, int height) override { + return RenderEx2(rtStart, rtStop, atpf, { left, top, right, bottom }, + { left, top, right, bottom }, { 0, 0, width, height }); + } + + // ISubRenderCallback3 + STDMETHODIMP RenderEx2(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME atpf, RECT croppedVideoRect, + RECT originalVideoRect, RECT viewportRect, + const double videoStretchFactor = 1.0) override { + return RenderEx3(std::move(rtStart), std::move(rtStop), std::move(atpf), std::move(croppedVideoRect), + std::move(originalVideoRect), std::move(viewportRect), std::move(videoStretchFactor)); + } + + // ISubRenderCallback4 + STDMETHODIMP RenderEx3(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, + REFERENCE_TIME atpf, RECT croppedVideoRect, + RECT originalVideoRect, RECT viewportRect, + const double videoStretchFactor = 1.0, + int xOffsetInPixels = 0, DWORD flags = 0) override; + + // ISubPicAllocatorPresenter + STDMETHODIMP CreateRenderer(IUnknown** ppRenderer) override; + STDMETHODIMP_(void) SetPosition(RECT w, RECT v) override; + STDMETHODIMP_(SIZE) GetVideoSize(bool bCorrectAR) const override; + STDMETHODIMP_(bool) Paint(bool bAll) override; + STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size) override; + STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget) override { + return SetPixelShader2(pSrcData, pTarget, false); + } + STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace) override; + + // ISubPicAllocatorPresenter2 + STDMETHODIMP_(bool) IsRendering() override; + // ISubPicAllocatorPresenter3 + STDMETHODIMP SetRotation(int rotation) override; + STDMETHODIMP_(int) GetRotation() override; + STDMETHODIMP_(int) GetPixelShaderMode() override { return 9; } + STDMETHODIMP ClearPixelShaders(int target) override; + STDMETHODIMP AddPixelShader(int target, LPCWSTR name, LPCSTR profile, LPCSTR sourceCode) override; + STDMETHODIMP_(bool) ToggleStats() override; + }; +} diff --git a/src/filters/renderer/VideoRenderers/stdafx.cpp b/src/filters/renderer/VideoRenderers/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/renderer/VideoRenderers/stdafx.cpp +++ b/src/filters/renderer/VideoRenderers/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/renderer/VideoRenderers/stdafx.h b/src/filters/renderer/VideoRenderers/stdafx.h index 01abc636047..dee6132a0c6 100644 --- a/src/filters/renderer/VideoRenderers/stdafx.h +++ b/src/filters/renderer/VideoRenderers/stdafx.h @@ -1,36 +1,36 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include -#include "BaseClasses/streams.h" -#include -#include - -#include "../../../DSUtil/DSUtil.h" - -#define CHECK_HR(exp) { if (FAILED(hr = exp)) return hr; } +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include +#include "BaseClasses/streams.h" +#include +#include + +#include "../../../DSUtil/DSUtil.h" + +#define CHECK_HR(exp) { if (FAILED(hr = exp)) return hr; } diff --git a/src/filters/source/BaseSource/BaseSource.cpp b/src/filters/source/BaseSource/BaseSource.cpp index c145096e814..df2549943e3 100644 --- a/src/filters/source/BaseSource/BaseSource.cpp +++ b/src/filters/source/BaseSource/BaseSource.cpp @@ -1,192 +1,192 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "BaseSource.h" -#include "../../../DSUtil/DSUtil.h" - -// -// CBaseSource -// - -// -// CBaseStream -// - -CBaseStream::CBaseStream(TCHAR* name, CSource* pParent, HRESULT* phr) - : CSourceStream(name, phr, pParent, L"Output") - , CSourceSeeking(name, (IPin*)this, phr, &m_cSharedState) - , m_AvgTimePerFrame(0) - , m_rtSampleTime(0) - , m_rtPosition(0) - , m_bDiscontinuity(FALSE) - , m_bFlushing(FALSE) -{ - CAutoLock cAutoLock(&m_cSharedState); - m_rtDuration = m_rtStop = 0; -} - -CBaseStream::~CBaseStream() -{ - CAutoLock cAutoLock(&m_cSharedState); -} - -STDMETHODIMP CBaseStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) - : CSourceStream::NonDelegatingQueryInterface(riid, ppv); -} - -void CBaseStream::UpdateFromSeek() -{ - if (ThreadExists()) { - // next time around the loop, the worker thread will - // pick up the position change. - // We need to flush all the existing data - we must do that here - // as our thread will probably be blocked in GetBuffer otherwise - - m_bFlushing = TRUE; - - DeliverBeginFlush(); - // make sure we have stopped pushing - Stop(); - // complete the flush - DeliverEndFlush(); - - m_bFlushing = FALSE; - - // restart - Run(); - } -} - -HRESULT CBaseStream::SetRate(double dRate) -{ - if (dRate <= 0) { - return E_INVALIDARG; - } - - { - CAutoLock lock(CSourceSeeking::m_pLock); - m_dRateSeeking = dRate; - } - - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CBaseStream::OnThreadStartPlay() -{ - m_bDiscontinuity = TRUE; - return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); -} - -HRESULT CBaseStream::ChangeStart() -{ - { - CAutoLock lock(CSourceSeeking::m_pLock); - m_rtSampleTime = 0; - m_rtPosition = m_rtStart; - } - - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CBaseStream::ChangeStop() -{ - { - CAutoLock lock(CSourceSeeking::m_pLock); - if (m_rtPosition < m_rtStop) { - return S_OK; - } - } - - // We're already past the new stop time -- better flush the graph. - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CBaseStream::OnThreadCreate() -{ - CAutoLock cAutoLockShared(&m_cSharedState); - - m_rtSampleTime = 0; - m_rtPosition = m_rtStart; - - return CSourceStream::OnThreadCreate(); -} - -HRESULT CBaseStream::FillBuffer(IMediaSample* pSample) -{ - { - HRESULT hr; - CAutoLock cAutoLockShared(&m_cSharedState); - - if (m_rtPosition >= m_rtStop) { - return S_FALSE; - } - - BYTE* pOut = nullptr; - if (FAILED(hr = pSample->GetPointer(&pOut)) || !pOut) { - return S_FALSE; - } - - int nFrame = (int)(m_rtPosition / m_AvgTimePerFrame); - - long len = pSample->GetSize(); - - hr = FillBuffer(pSample, nFrame, pOut, len); - if (hr != S_OK) { - return hr; - } - - pSample->SetActualDataLength(len); - - REFERENCE_TIME rtStart, rtStop; - // The sample times are modified by the current rate. - rtStart = static_cast(m_rtSampleTime / m_dRateSeeking); - rtStop = rtStart + static_cast(m_AvgTimePerFrame / m_dRateSeeking); - pSample->SetTime(&rtStart, &rtStop); - - m_rtSampleTime += m_AvgTimePerFrame; - m_rtPosition += m_AvgTimePerFrame; - } - - pSample->SetSyncPoint(TRUE); - - if (m_bDiscontinuity) { - pSample->SetDiscontinuity(TRUE); - m_bDiscontinuity = FALSE; - } - - return S_OK; -} - -STDMETHODIMP CBaseStream::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "BaseSource.h" +#include "../../../DSUtil/DSUtil.h" + +// +// CBaseSource +// + +// +// CBaseStream +// + +CBaseStream::CBaseStream(TCHAR* name, CSource* pParent, HRESULT* phr) + : CSourceStream(name, phr, pParent, L"Output") + , CSourceSeeking(name, (IPin*)this, phr, &m_cSharedState) + , m_AvgTimePerFrame(0) + , m_rtSampleTime(0) + , m_rtPosition(0) + , m_bDiscontinuity(FALSE) + , m_bFlushing(FALSE) +{ + CAutoLock cAutoLock(&m_cSharedState); + m_rtDuration = m_rtStop = 0; +} + +CBaseStream::~CBaseStream() +{ + CAutoLock cAutoLock(&m_cSharedState); +} + +STDMETHODIMP CBaseStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) + : CSourceStream::NonDelegatingQueryInterface(riid, ppv); +} + +void CBaseStream::UpdateFromSeek() +{ + if (ThreadExists()) { + // next time around the loop, the worker thread will + // pick up the position change. + // We need to flush all the existing data - we must do that here + // as our thread will probably be blocked in GetBuffer otherwise + + m_bFlushing = TRUE; + + DeliverBeginFlush(); + // make sure we have stopped pushing + Stop(); + // complete the flush + DeliverEndFlush(); + + m_bFlushing = FALSE; + + // restart + Run(); + } +} + +HRESULT CBaseStream::SetRate(double dRate) +{ + if (dRate <= 0) { + return E_INVALIDARG; + } + + { + CAutoLock lock(CSourceSeeking::m_pLock); + m_dRateSeeking = dRate; + } + + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CBaseStream::OnThreadStartPlay() +{ + m_bDiscontinuity = TRUE; + return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); +} + +HRESULT CBaseStream::ChangeStart() +{ + { + CAutoLock lock(CSourceSeeking::m_pLock); + m_rtSampleTime = 0; + m_rtPosition = m_rtStart; + } + + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CBaseStream::ChangeStop() +{ + { + CAutoLock lock(CSourceSeeking::m_pLock); + if (m_rtPosition < m_rtStop) { + return S_OK; + } + } + + // We're already past the new stop time -- better flush the graph. + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CBaseStream::OnThreadCreate() +{ + CAutoLock cAutoLockShared(&m_cSharedState); + + m_rtSampleTime = 0; + m_rtPosition = m_rtStart; + + return CSourceStream::OnThreadCreate(); +} + +HRESULT CBaseStream::FillBuffer(IMediaSample* pSample) +{ + { + HRESULT hr; + CAutoLock cAutoLockShared(&m_cSharedState); + + if (m_rtPosition >= m_rtStop) { + return S_FALSE; + } + + BYTE* pOut = nullptr; + if (FAILED(hr = pSample->GetPointer(&pOut)) || !pOut) { + return S_FALSE; + } + + int nFrame = (int)(m_rtPosition / m_AvgTimePerFrame); + + long len = pSample->GetSize(); + + hr = FillBuffer(pSample, nFrame, pOut, len); + if (hr != S_OK) { + return hr; + } + + pSample->SetActualDataLength(len); + + REFERENCE_TIME rtStart, rtStop; + // The sample times are modified by the current rate. + rtStart = static_cast(m_rtSampleTime / m_dRateSeeking); + rtStop = rtStart + static_cast(m_AvgTimePerFrame / m_dRateSeeking); + pSample->SetTime(&rtStart, &rtStop); + + m_rtSampleTime += m_AvgTimePerFrame; + m_rtPosition += m_AvgTimePerFrame; + } + + pSample->SetSyncPoint(TRUE); + + if (m_bDiscontinuity) { + pSample->SetDiscontinuity(TRUE); + m_bDiscontinuity = FALSE; + } + + return S_OK; +} + +STDMETHODIMP CBaseStream::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} diff --git a/src/filters/source/BaseSource/BaseSource.h b/src/filters/source/BaseSource/BaseSource.h index d24977ba73b..548fe2c093a 100644 --- a/src/filters/source/BaseSource/BaseSource.h +++ b/src/filters/source/BaseSource/BaseSource.h @@ -1,130 +1,130 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2014 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 . - * - */ - -#pragma once - -#include "../../../DSUtil/DSUtil.h" - -template -class CBaseSource - : public CSource - , public IFileSourceFilter - , public IAMFilterMiscFlags -{ -protected: - CStringW m_fn; - -public: - CBaseSource(TCHAR* name, LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) - : CSource(name, lpunk, clsid) { - if (phr) { - *phr = S_OK; - } - } - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - CheckPointer(ppv, E_POINTER); - - return - QI(IFileSourceFilter) - QI(IAMFilterMiscFlags) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IFileSourceFilter - - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) { - // TODO: destroy any already existing pins and create new, now we are just going die nicely instead of doing it :) - if (GetPinCount() > 0) { - return VFW_E_ALREADY_CONNECTED; - } - - HRESULT hr = S_OK; - if (!(DEBUG_NEW TStream(pszFileName, this, &hr))) { - return E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - return hr; - } - - m_fn = pszFileName; - - return S_OK; - } - - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) { - CheckPointer(ppszFileName, E_POINTER); - - size_t nCount = m_fn.GetLength() + 1; - *ppszFileName = (LPOLESTR)CoTaskMemAlloc(nCount * sizeof(WCHAR)); - if (!(*ppszFileName)) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, nCount, m_fn); - - return S_OK; - } - - // IAMFilterMiscFlags - - STDMETHODIMP_(ULONG) GetMiscFlags() { - return AM_FILTER_MISC_FLAGS_IS_SOURCE; - } -}; - -class CBaseStream - : public CSourceStream - , public CSourceSeeking -{ -protected: - CCritSec m_cSharedState; - - REFERENCE_TIME m_AvgTimePerFrame; - REFERENCE_TIME m_rtSampleTime, m_rtPosition; - - BOOL m_bDiscontinuity, m_bFlushing; - - HRESULT OnThreadStartPlay(); - HRESULT OnThreadCreate(); - -private: - void UpdateFromSeek(); - STDMETHODIMP SetRate(double dRate); - - HRESULT ChangeStart(); - HRESULT ChangeStop(); - HRESULT ChangeRate() { return S_OK; } - -public: - CBaseStream(TCHAR* name, CSource* pParent, HRESULT* phr); - virtual ~CBaseStream(); - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT FillBuffer(IMediaSample* pSample); - - virtual HRESULT FillBuffer(IMediaSample* pSample, int nFrame, BYTE* pOut, long& len /*in+out*/) = 0; - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2014 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 . + * + */ + +#pragma once + +#include "../../../DSUtil/DSUtil.h" + +template +class CBaseSource + : public CSource + , public IFileSourceFilter + , public IAMFilterMiscFlags +{ +protected: + CStringW m_fn; + +public: + CBaseSource(TCHAR* name, LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) + : CSource(name, lpunk, clsid) { + if (phr) { + *phr = S_OK; + } + } + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + CheckPointer(ppv, E_POINTER); + + return + QI(IFileSourceFilter) + QI(IAMFilterMiscFlags) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IFileSourceFilter + + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) { + // TODO: destroy any already existing pins and create new, now we are just going die nicely instead of doing it :) + if (GetPinCount() > 0) { + return VFW_E_ALREADY_CONNECTED; + } + + HRESULT hr = S_OK; + if (!(DEBUG_NEW TStream(pszFileName, this, &hr))) { + return E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + return hr; + } + + m_fn = pszFileName; + + return S_OK; + } + + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) { + CheckPointer(ppszFileName, E_POINTER); + + size_t nCount = m_fn.GetLength() + 1; + *ppszFileName = (LPOLESTR)CoTaskMemAlloc(nCount * sizeof(WCHAR)); + if (!(*ppszFileName)) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, nCount, m_fn); + + return S_OK; + } + + // IAMFilterMiscFlags + + STDMETHODIMP_(ULONG) GetMiscFlags() { + return AM_FILTER_MISC_FLAGS_IS_SOURCE; + } +}; + +class CBaseStream + : public CSourceStream + , public CSourceSeeking +{ +protected: + CCritSec m_cSharedState; + + REFERENCE_TIME m_AvgTimePerFrame; + REFERENCE_TIME m_rtSampleTime, m_rtPosition; + + BOOL m_bDiscontinuity, m_bFlushing; + + HRESULT OnThreadStartPlay(); + HRESULT OnThreadCreate(); + +private: + void UpdateFromSeek(); + STDMETHODIMP SetRate(double dRate); + + HRESULT ChangeStart(); + HRESULT ChangeStop(); + HRESULT ChangeRate() { return S_OK; } + +public: + CBaseStream(TCHAR* name, CSource* pParent, HRESULT* phr); + virtual ~CBaseStream(); + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT FillBuffer(IMediaSample* pSample); + + virtual HRESULT FillBuffer(IMediaSample* pSample, int nFrame, BYTE* pOut, long& len /*in+out*/) = 0; + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; diff --git a/src/filters/source/BaseSource/BaseSource.vcxproj b/src/filters/source/BaseSource/BaseSource.vcxproj index 8d7a4ab760d..22eb871f703 100644 --- a/src/filters/source/BaseSource/BaseSource.vcxproj +++ b/src/filters/source/BaseSource/BaseSource.vcxproj @@ -1,66 +1,66 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F50E74C2-5BE7-4C9B-B1E7-6CA19CFAD34E} - BaseSource - MFCProj - BaseSource - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - Create - - - - - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F50E74C2-5BE7-4C9B-B1E7-6CA19CFAD34E} + BaseSource + MFCProj + BaseSource + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + Create + + + + + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/filters/source/BaseSource/BaseSource.vcxproj.filters b/src/filters/source/BaseSource/BaseSource.vcxproj.filters index c6f97d0aa21..5bb15a89444 100644 --- a/src/filters/source/BaseSource/BaseSource.vcxproj.filters +++ b/src/filters/source/BaseSource/BaseSource.vcxproj.filters @@ -1,29 +1,29 @@ - - - - - {d55d7ca3-f025-4f7c-bfa1-01bb4db7f6cd} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {76184793-16c1-467e-90ad-b83f2bab29f7} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - + + + + + {d55d7ca3-f025-4f7c-bfa1-01bb4db7f6cd} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {76184793-16c1-467e-90ad-b83f2bab29f7} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/filters/source/BaseSource/stdafx.cpp b/src/filters/source/BaseSource/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/source/BaseSource/stdafx.cpp +++ b/src/filters/source/BaseSource/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/source/BaseSource/stdafx.h b/src/filters/source/BaseSource/stdafx.h index a8517b3e334..619304dd68e 100644 --- a/src/filters/source/BaseSource/stdafx.h +++ b/src/filters/source/BaseSource/stdafx.h @@ -1,35 +1,35 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/source/SubtitleSource/SubtitleSource.cpp b/src/filters/source/SubtitleSource/SubtitleSource.cpp index 5305853feba..ee9a0a87969 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.cpp +++ b/src/filters/source/SubtitleSource/SubtitleSource.cpp @@ -1,801 +1,801 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "SubtitleSource.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -static int _WIDTH = 640; -static int _HEIGHT = 480; -static int _ATPF = 400000; - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Subtitle, &MEDIASUBTYPE_NULL}, - {&MEDIATYPE_Text, &MEDIASUBTYPE_NULL}, - {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB32}, -}; - -const AMOVIESETUP_PIN sudOpPin[] = { - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}, -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CSubtitleSourceASCII), L"MPC-HC SubtitleSource (S_TEXT/ASCII)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceUTF8), L"MPC-HC SubtitleSource (S_TEXT/UTF8)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceSSA), L"MPC-HC SubtitleSource (S_TEXT/SSA)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceASS), L"MPC-HC SubtitleSource (S_TEXT/ASS)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceUSF), L"MPC-HC SubtitleSource (S_TEXT/USF)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourcePreview), L"MPC-HC SubtitleSource (Preview)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, - {&__uuidof(CSubtitleSourceARGB), L"MPC-HC SubtitleSource (ARGB)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, - {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, - {sudFilter[2].strName, sudFilter[2].clsID, CreateInstance, nullptr, &sudFilter[2]}, - {sudFilter[3].strName, sudFilter[3].clsID, CreateInstance, nullptr, &sudFilter[3]}, - // {sudFilter[4].strName, sudFilter[4].clsID, CreateInstance, nullptr, &sudFilter[4]}, - {sudFilter[5].strName, sudFilter[5].clsID, CreateInstance, nullptr, &sudFilter[5]}, - {sudFilter[6].strName, sudFilter[6].clsID, CreateInstance, nullptr, &sudFilter[6]}, -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - /*CString clsid = CStringFromGUID(__uuidof(CSubtitleSourcePreview)); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".sub"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".srt"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".smi"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".ssa"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".ass"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".xss"), - _T("Source Filter"), clsid); - - SetRegKeyValue( - _T("Media Type\\Extensions"), _T(".usf"), - _T("Source Filter"), clsid);*/ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - DeleteRegKey(_T("Media Type\\Extensions"), _T(".sub")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".srt")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".smi")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".ssa")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".ass")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".xss")); - DeleteRegKey(_T("Media Type\\Extensions"), _T(".usf")); - /**/ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -class CSubtitleSourceApp : public CFilterApp -{ -public: - BOOL InitInstance() { - if (!__super::InitInstance()) { - return FALSE; - } - - _WIDTH = GetProfileInt(_T("SubtitleSource"), _T("w"), 640); - _HEIGHT = GetProfileInt(_T("SubtitleSource"), _T("h"), 480); - _ATPF = GetProfileInt(_T("SubtitleSource"), _T("atpf"), 400000); - if (_ATPF <= 0) { - _ATPF = 400000; - } - WriteProfileInt(_T("SubtitleSource"), _T("w"), _WIDTH); - WriteProfileInt(_T("SubtitleSource"), _T("h"), _HEIGHT); - WriteProfileInt(_T("SubtitleSource"), _T("atpf"), _ATPF); - - return TRUE; - } -}; - -CSubtitleSourceApp theApp; - -#endif - -// -// CSubtitleSource -// - -CSubtitleSource::CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) - : CSource(NAME("CSubtitleSource"), lpunk, clsid) -{ -} - -CSubtitleSource::~CSubtitleSource() -{ -} - -STDMETHODIMP CSubtitleSource::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFileSourceFilter) - QI(IAMFilterMiscFlags) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IFileSourceFilter - -STDMETHODIMP CSubtitleSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) -{ - if (GetPinCount() > 0) { - return VFW_E_ALREADY_CONNECTED; - } - - HRESULT hr = S_OK; - if (!(DEBUG_NEW CSubtitleStream(pszFileName, this, &hr))) { - return E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - return hr; - } - - m_fn = pszFileName; - - return S_OK; -} - -STDMETHODIMP CSubtitleSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) -{ - CheckPointer(ppszFileName, E_POINTER); - - *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); - if (!*ppszFileName) { - return E_OUTOFMEMORY; - } - - wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); - - return S_OK; -} - -// IAMFilterMiscFlags - -ULONG CSubtitleSource::GetMiscFlags() -{ - return AM_FILTER_MISC_FLAGS_IS_SOURCE; -} - -STDMETHODIMP CSubtitleSource::QueryFilterInfo(FILTER_INFO* pInfo) -{ - CheckPointer(pInfo, E_POINTER); - ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); - wcscpy_s(pInfo->achName, SubtitleSourceName); - pInfo->pGraph = m_pGraph; - if (m_pGraph) { - m_pGraph->AddRef(); - } - - return S_OK; -} - -// -// CSubtitleStream -// - -CSubtitleStream::CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr) - : CSourceStream(NAME("SubtitleStream"), phr, pParent, L"Output") - , CSourceSeeking(NAME("SubtitleStream"), (IPin*)this, phr, &m_cSharedState) - , m_nPosition(0) - , m_bDiscontinuity(FALSE) - , m_bFlushing(FALSE) - , m_rts(nullptr) -{ - CAutoLock cAutoLock(&m_cSharedState); - - CString fn(wfn); - - if (!m_rts.Open(fn, DEFAULT_CHARSET)) { - *phr = E_FAIL; - return; - } - - m_rts.CreateDefaultStyle(DEFAULT_CHARSET); - m_rts.ConvertToTimeBased(25); - m_rts.Sort(); - - m_rtDuration = 0; - for (size_t i = 0, cnt = m_rts.GetCount(); i < cnt; i++) { - m_rtDuration = std::max(m_rtDuration, 10000i64 * m_rts[i].end); - } - - m_rtStop = m_rtDuration; - - *phr = m_rtDuration > 0 ? S_OK : E_FAIL; -} - -CSubtitleStream::~CSubtitleStream() -{ - CAutoLock cAutoLock(&m_cSharedState); -} - -STDMETHODIMP CSubtitleStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) //GetInterface((IMediaSeeking*)this, ppv) - : CSourceStream::NonDelegatingQueryInterface(riid, ppv); -} - -void CSubtitleStream::UpdateFromSeek() -{ - if (ThreadExists()) { - // next time around the loop, the worker thread will - // pick up the position change. - // We need to flush all the existing data - we must do that here - // as our thread will probably be blocked in GetBuffer otherwise - - m_bFlushing = TRUE; - - DeliverBeginFlush(); - // make sure we have stopped pushing - Stop(); - // complete the flush - DeliverEndFlush(); - - m_bFlushing = FALSE; - - // restart - Run(); - } -} - -HRESULT CSubtitleStream::SetRate(double dRate) -{ - if (dRate <= 0) { - return E_INVALIDARG; - } - - { - CAutoLock lock(CSourceSeeking::m_pLock); - m_dRateSeeking = dRate; - } - - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CSubtitleStream::OnThreadStartPlay() -{ - m_bDiscontinuity = TRUE; - return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); -} - -HRESULT CSubtitleStream::ChangeStart() -{ - { - CAutoLock lock(CSourceSeeking::m_pLock); - - OnThreadCreate(); - /*if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) - { - m_nPosition = (int)(m_rtStart/10000)*1/1000; - } - else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) - { - int m_nSegments = 0; - if (!m_rts.SearchSubs((int)(m_rtStart/10000), 25, &m_nPosition, &m_nSegments)) - m_nPosition = m_nSegments; - } - else - { - m_nPosition = m_rts.SearchSub((int)(m_rtStart/10000), 25); - if (m_nPosition < 0) m_nPosition = 0; - else if (m_rts[m_nPosition].end <= (int)(m_rtStart/10000)) m_nPosition++; - }*/ - } - - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CSubtitleStream::ChangeStop() -{ - /*{ - CAutoLock lock(CSourceSeeking::m_pLock); - if (m_rtPosition < m_rtStop) - return S_OK; - }*/ - // We're already past the new stop time -- better flush the graph. - UpdateFromSeek(); - - return S_OK; -} - -HRESULT CSubtitleStream::OnThreadCreate() -{ - CAutoLock cAutoLockShared(&m_cSharedState); - - if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { - m_nPosition = (int)(m_rtStart / _ATPF); - } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { - int m_nSegments = 0; - if (!m_rts.SearchSubs((int)(m_rtStart / 10000), 10000000.0 / _ATPF, &m_nPosition, &m_nSegments)) { - m_nPosition = m_nSegments; - } - } else { - m_nPosition = m_rts.SearchSub((int)(m_rtStart / 10000), 25); - if (m_nPosition < 0) { - m_nPosition = 0; - } else if (m_rts[m_nPosition].end <= (int)(m_rtStart / 10000)) { - m_nPosition++; - } - } - - return CSourceStream::OnThreadCreate(); -} - -HRESULT CSubtitleStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) -{ - //CAutoLock cAutoLock(m_pFilter->pStateLock()); - - ASSERT(pAlloc); - ASSERT(pProperties); - - HRESULT hr = NOERROR; - - if (m_mt.majortype == MEDIATYPE_Video) { - pProperties->cBuffers = 2; - pProperties->cbBuffer = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader.biSizeImage; - } else { - pProperties->cBuffers = 1; - pProperties->cbBuffer = 0x10000; - } - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { - return hr; - } - - if (Actual.cbBuffer < pProperties->cbBuffer) { - return E_FAIL; - } - ASSERT(Actual.cBuffers == pProperties->cBuffers); - - return NOERROR; -} - -HRESULT CSubtitleStream::FillBuffer(IMediaSample* pSample) -{ - { - CAutoLock cAutoLockShared(&m_cSharedState); - - BYTE* pData = nullptr; - if (FAILED(pSample->GetPointer(&pData)) || !pData) { - return S_FALSE; - } - - AM_MEDIA_TYPE* pmt; - if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { - CMediaType mt(*pmt); - SetMediaType(&mt); - DeleteMediaType(pmt); - } - - int len = 0; - REFERENCE_TIME rtStart, rtStop; - - if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { - rtStart = (REFERENCE_TIME)((m_nPosition * _ATPF - m_rtStart) / m_dRateSeeking); - rtStop = (REFERENCE_TIME)(((m_nPosition + 1) * _ATPF - m_rtStart) / m_dRateSeeking); - if (m_rtStart + rtStart >= m_rtDuration) { - return S_FALSE; - } - - BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; - - SubPicDesc spd; - spd.w = _WIDTH; - spd.h = _HEIGHT; - spd.bpp = 32; - spd.pitch = bmi.biWidth * 4; - spd.bits = pData; - - len = spd.h * spd.pitch; - - for (int y = 0; y < spd.h; y++) { - memsetd((DWORD*)(pData + spd.pitch * y), 0xff000000, spd.w * 4); - } - - RECT bbox; - m_rts.Render(spd, m_nPosition * _ATPF, 10000000.0 / _ATPF, bbox); - - for (int y = 0; y < spd.h; y++) { - DWORD* p = (DWORD*)(pData + spd.pitch * y); - for (int x = 0; x < spd.w; x++, p++) { - *p = (0xff000000 - (*p & 0xff000000)) | (*p & 0xffffff); - } - } - } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { - const STSSegment* stss = m_rts.GetSegment(m_nPosition); - if (!stss) { - return S_FALSE; - } - - BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; - - SubPicDesc spd; - spd.w = _WIDTH; - spd.h = _HEIGHT; - spd.bpp = 32; - spd.pitch = bmi.biWidth * 4; - spd.bits = pData; - - len = spd.h * spd.pitch; - - for (int y = 0; y < spd.h; y++) { - DWORD c1 = 0xff606060, c2 = 0xffa0a0a0; - if (y & 32) { - c1 ^= c2, c2 ^= c1, c1 ^= c2; - } - DWORD* p = (DWORD*)(pData + spd.pitch * y); - for (int x = 0; x < spd.w; x += 32, p += 32) { - memsetd(p, (x & 32) ? c1 : c2, std::min(spd.w - x, 32) * 4); - } - } - - RECT bbox; - m_rts.Render(spd, 10000i64 * (stss->start + stss->end) / 2, 10000000.0 / _ATPF, bbox); - - rtStart = (REFERENCE_TIME)((10000i64 * stss->start - m_rtStart) / m_dRateSeeking); - rtStop = (REFERENCE_TIME)((10000i64 * stss->end - m_rtStart) / m_dRateSeeking); - } else { - if ((size_t)m_nPosition >= m_rts.GetCount()) { - return S_FALSE; - } - - STSEntry& stse = m_rts[m_nPosition]; - - if (stse.start >= m_rtStop / 10000) { - return S_FALSE; - } - - if (m_mt.majortype == MEDIATYPE_Subtitle && m_mt.subtype == MEDIASUBTYPE_UTF8) { - CStringA str = UTF16To8(m_rts.GetStrW(m_nPosition, false)); - memcpy((char*)pData, str, len = str.GetLength()); - } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS)) { - CStringW line; - line.Format(L"%d,%d,%s,%s,%d,%d,%d,%s,%s", - stse.readorder, stse.layer, stse.style.GetString(), stse.actor.GetString(), - stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, - stse.effect.GetString(), m_rts.GetStrW(m_nPosition, true).GetString()); - - CStringA str = UTF16To8(line); - memcpy((char*)pData, str, len = str.GetLength()); - } else if (m_mt.majortype == MEDIATYPE_Text && m_mt.subtype == MEDIASUBTYPE_NULL) { - CStringA str = m_rts.GetStrA(m_nPosition, false); - memcpy((char*)pData, str, len = str.GetLength()); - } else { - return S_FALSE; - } - - rtStart = (REFERENCE_TIME)((10000i64 * stse.start - m_rtStart) / m_dRateSeeking); - rtStop = (REFERENCE_TIME)((10000i64 * stse.end - m_rtStart) / m_dRateSeeking); - } - - pSample->SetTime(&rtStart, &rtStop); - pSample->SetActualDataLength(len); - - m_nPosition++; - } - - pSample->SetSyncPoint(TRUE); - - if (m_bDiscontinuity) { - pSample->SetDiscontinuity(TRUE); - m_bDiscontinuity = FALSE; - } - - return S_OK; -} - -HRESULT CSubtitleStream::GetMediaType(CMediaType* pmt) -{ - return (static_cast(m_pFilter))->GetMediaType(pmt); -} - -HRESULT CSubtitleStream::CheckMediaType(const CMediaType* pmt) -{ - CAutoLock lock(m_pFilter->pStateLock()); - - CMediaType mt; - GetMediaType(&mt); - - if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { - return NOERROR; - } - - return E_FAIL; -} - -STDMETHODIMP CSubtitleStream::Notify(IBaseFilter* pSender, Quality q) -{ - return E_NOTIMPL; -} - -// -// CSubtitleSourceASCII -// - -CSubtitleSourceASCII::CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceASCII::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Text); - pmt->SetSubtype(&MEDIASUBTYPE_NULL); - pmt->SetFormatType(&FORMAT_None); - pmt->ResetFormatBuffer(); - - return NOERROR; -} - -// -// CSubtitleSourceUTF8 -// - -CSubtitleSourceUTF8::CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceUTF8::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Subtitle); - pmt->SetSubtype(&MEDIASUBTYPE_UTF8); - pmt->SetFormatType(&FORMAT_SubtitleInfo); - SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); - ZeroMemory(psi, pmt->FormatLength()); - strcpy_s(psi->IsoLang, "eng"); - - return NOERROR; -} - -// -// CSubtitleSourceSSA -// - -CSubtitleSourceSSA::CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceSSA::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Subtitle); - pmt->SetSubtype(&MEDIASUBTYPE_SSA); - pmt->SetFormatType(&FORMAT_SubtitleInfo); - - CSimpleTextSubtitle sts; - sts.Open(CString(m_fn), DEFAULT_CHARSET); - sts.RemoveAll(); - - CFile f; - TCHAR path[MAX_PATH], fn[MAX_PATH]; - if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { - return E_FAIL; - } - - _tremove(fn); - - _tcscat_s(fn, _T(".ssa")); - - if (!sts.SaveAs(fn, Subtitle::SSA, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { - return E_FAIL; - } - - int len = (int)f.GetLength() - 3; - f.Seek(3, CFile::begin); - - SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); - ZeroMemory(psi, pmt->FormatLength()); - psi->dwOffset = sizeof(SUBTITLEINFO); - strcpy_s(psi->IsoLang, "eng"); - f.Read(pmt->pbFormat + psi->dwOffset, len); - f.Close(); - - _tremove(fn); - - return NOERROR; -} - -// -// CSubtitleSourceASS -// - -CSubtitleSourceASS::CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceASS::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Subtitle); - pmt->SetSubtype(&MEDIASUBTYPE_ASS); - pmt->SetFormatType(&FORMAT_SubtitleInfo); - - CSimpleTextSubtitle sts; - sts.Open(CString(m_fn), DEFAULT_CHARSET); - sts.RemoveAll(); - - CFile f; - TCHAR path[MAX_PATH], fn[MAX_PATH]; - if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { - return E_FAIL; - } - - _tremove(fn); - - _tcscat_s(fn, _T(".ass")); - - if (!sts.SaveAs(fn, Subtitle::ASS, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { - return E_FAIL; - } - - int len = (int)f.GetLength(); - - SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); - ZeroMemory(psi, pmt->FormatLength()); - psi->dwOffset = sizeof(SUBTITLEINFO); - strcpy_s(psi->IsoLang, "eng"); - f.Read(pmt->pbFormat + psi->dwOffset, len); - f.Close(); - - _tremove(fn); - - return NOERROR; -} - -// -// CSubtitleSourceUSF -// - -CSubtitleSourceUSF::CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceUSF::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Subtitle); - pmt->SetSubtype(&MEDIASUBTYPE_USF); - pmt->SetFormatType(&FORMAT_SubtitleInfo); - SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); - ZeroMemory(psi, pmt->FormatLength()); - strcpy_s(psi->IsoLang, "eng"); - // TODO: ... - - return NOERROR; -} - -// -// CSubtitleSourcePreview -// - -CSubtitleSourcePreview::CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourcePreview::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Video); - pmt->SetSubtype(&MEDIASUBTYPE_RGB32); - pmt->SetFormatType(&FORMAT_VideoInfo); - VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); - ZeroMemory(pvih, pmt->FormatLength()); - pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); - pvih->bmiHeader.biWidth = _WIDTH; - pvih->bmiHeader.biHeight = _HEIGHT; - pvih->bmiHeader.biBitCount = 32; - pvih->bmiHeader.biCompression = BI_RGB; - pvih->bmiHeader.biPlanes = 1; - pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth * abs(pvih->bmiHeader.biHeight) * pvih->bmiHeader.biBitCount >> 3; - - return NOERROR; -} - -// -// CSubtitleSourceARGB -// - -CSubtitleSourceARGB::CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr) - : CSubtitleSource(lpunk, phr, __uuidof(this)) -{ -} - -HRESULT CSubtitleSourceARGB::GetMediaType(CMediaType* pmt) -{ - CAutoLock cAutoLock(pStateLock()); - - pmt->InitMediaType(); - pmt->SetType(&MEDIATYPE_Video); - pmt->SetSubtype(&MEDIASUBTYPE_ARGB32); - pmt->SetFormatType(&FORMAT_VideoInfo); - VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); - ZeroMemory(pvih, pmt->FormatLength()); - pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); - // TODO: read w,h,fps from a config file or registry - pvih->bmiHeader.biWidth = _WIDTH; - pvih->bmiHeader.biHeight = _HEIGHT; - pvih->bmiHeader.biBitCount = 32; - pvih->bmiHeader.biCompression = BI_RGB; - pvih->bmiHeader.biPlanes = 1; - pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth * abs(pvih->bmiHeader.biHeight) * pvih->bmiHeader.biBitCount >> 3; - - return NOERROR; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "SubtitleSource.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +static int _WIDTH = 640; +static int _HEIGHT = 480; +static int _ATPF = 400000; + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Subtitle, &MEDIASUBTYPE_NULL}, + {&MEDIATYPE_Text, &MEDIASUBTYPE_NULL}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB32}, +}; + +const AMOVIESETUP_PIN sudOpPin[] = { + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}, +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CSubtitleSourceASCII), L"MPC-HC SubtitleSource (S_TEXT/ASCII)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceUTF8), L"MPC-HC SubtitleSource (S_TEXT/UTF8)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceSSA), L"MPC-HC SubtitleSource (S_TEXT/SSA)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceASS), L"MPC-HC SubtitleSource (S_TEXT/ASS)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceUSF), L"MPC-HC SubtitleSource (S_TEXT/USF)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourcePreview), L"MPC-HC SubtitleSource (Preview)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, + {&__uuidof(CSubtitleSourceARGB), L"MPC-HC SubtitleSource (ARGB)", MERIT_NORMAL, _countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, + {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, + {sudFilter[2].strName, sudFilter[2].clsID, CreateInstance, nullptr, &sudFilter[2]}, + {sudFilter[3].strName, sudFilter[3].clsID, CreateInstance, nullptr, &sudFilter[3]}, + // {sudFilter[4].strName, sudFilter[4].clsID, CreateInstance, nullptr, &sudFilter[4]}, + {sudFilter[5].strName, sudFilter[5].clsID, CreateInstance, nullptr, &sudFilter[5]}, + {sudFilter[6].strName, sudFilter[6].clsID, CreateInstance, nullptr, &sudFilter[6]}, +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + /*CString clsid = CStringFromGUID(__uuidof(CSubtitleSourcePreview)); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".sub"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".srt"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".smi"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".ssa"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".ass"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".xss"), + _T("Source Filter"), clsid); + + SetRegKeyValue( + _T("Media Type\\Extensions"), _T(".usf"), + _T("Source Filter"), clsid);*/ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + DeleteRegKey(_T("Media Type\\Extensions"), _T(".sub")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".srt")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".smi")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".ssa")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".ass")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".xss")); + DeleteRegKey(_T("Media Type\\Extensions"), _T(".usf")); + /**/ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +class CSubtitleSourceApp : public CFilterApp +{ +public: + BOOL InitInstance() { + if (!__super::InitInstance()) { + return FALSE; + } + + _WIDTH = GetProfileInt(_T("SubtitleSource"), _T("w"), 640); + _HEIGHT = GetProfileInt(_T("SubtitleSource"), _T("h"), 480); + _ATPF = GetProfileInt(_T("SubtitleSource"), _T("atpf"), 400000); + if (_ATPF <= 0) { + _ATPF = 400000; + } + WriteProfileInt(_T("SubtitleSource"), _T("w"), _WIDTH); + WriteProfileInt(_T("SubtitleSource"), _T("h"), _HEIGHT); + WriteProfileInt(_T("SubtitleSource"), _T("atpf"), _ATPF); + + return TRUE; + } +}; + +CSubtitleSourceApp theApp; + +#endif + +// +// CSubtitleSource +// + +CSubtitleSource::CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) + : CSource(NAME("CSubtitleSource"), lpunk, clsid) +{ +} + +CSubtitleSource::~CSubtitleSource() +{ +} + +STDMETHODIMP CSubtitleSource::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFileSourceFilter) + QI(IAMFilterMiscFlags) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IFileSourceFilter + +STDMETHODIMP CSubtitleSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) +{ + if (GetPinCount() > 0) { + return VFW_E_ALREADY_CONNECTED; + } + + HRESULT hr = S_OK; + if (!(DEBUG_NEW CSubtitleStream(pszFileName, this, &hr))) { + return E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + return hr; + } + + m_fn = pszFileName; + + return S_OK; +} + +STDMETHODIMP CSubtitleSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) +{ + CheckPointer(ppszFileName, E_POINTER); + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); + if (!*ppszFileName) { + return E_OUTOFMEMORY; + } + + wcscpy_s(*ppszFileName, m_fn.GetLength() + 1, m_fn); + + return S_OK; +} + +// IAMFilterMiscFlags + +ULONG CSubtitleSource::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_SOURCE; +} + +STDMETHODIMP CSubtitleSource::QueryFilterInfo(FILTER_INFO* pInfo) +{ + CheckPointer(pInfo, E_POINTER); + ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); + wcscpy_s(pInfo->achName, SubtitleSourceName); + pInfo->pGraph = m_pGraph; + if (m_pGraph) { + m_pGraph->AddRef(); + } + + return S_OK; +} + +// +// CSubtitleStream +// + +CSubtitleStream::CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr) + : CSourceStream(NAME("SubtitleStream"), phr, pParent, L"Output") + , CSourceSeeking(NAME("SubtitleStream"), (IPin*)this, phr, &m_cSharedState) + , m_nPosition(0) + , m_bDiscontinuity(FALSE) + , m_bFlushing(FALSE) + , m_rts(nullptr) +{ + CAutoLock cAutoLock(&m_cSharedState); + + CString fn(wfn); + + if (!m_rts.Open(fn, DEFAULT_CHARSET)) { + *phr = E_FAIL; + return; + } + + m_rts.CreateDefaultStyle(DEFAULT_CHARSET); + m_rts.ConvertToTimeBased(25); + m_rts.Sort(); + + m_rtDuration = 0; + for (size_t i = 0, cnt = m_rts.GetCount(); i < cnt; i++) { + m_rtDuration = std::max(m_rtDuration, 10000i64 * m_rts[i].end); + } + + m_rtStop = m_rtDuration; + + *phr = m_rtDuration > 0 ? S_OK : E_FAIL; +} + +CSubtitleStream::~CSubtitleStream() +{ + CAutoLock cAutoLock(&m_cSharedState); +} + +STDMETHODIMP CSubtitleStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) //GetInterface((IMediaSeeking*)this, ppv) + : CSourceStream::NonDelegatingQueryInterface(riid, ppv); +} + +void CSubtitleStream::UpdateFromSeek() +{ + if (ThreadExists()) { + // next time around the loop, the worker thread will + // pick up the position change. + // We need to flush all the existing data - we must do that here + // as our thread will probably be blocked in GetBuffer otherwise + + m_bFlushing = TRUE; + + DeliverBeginFlush(); + // make sure we have stopped pushing + Stop(); + // complete the flush + DeliverEndFlush(); + + m_bFlushing = FALSE; + + // restart + Run(); + } +} + +HRESULT CSubtitleStream::SetRate(double dRate) +{ + if (dRate <= 0) { + return E_INVALIDARG; + } + + { + CAutoLock lock(CSourceSeeking::m_pLock); + m_dRateSeeking = dRate; + } + + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CSubtitleStream::OnThreadStartPlay() +{ + m_bDiscontinuity = TRUE; + return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); +} + +HRESULT CSubtitleStream::ChangeStart() +{ + { + CAutoLock lock(CSourceSeeking::m_pLock); + + OnThreadCreate(); + /*if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) + { + m_nPosition = (int)(m_rtStart/10000)*1/1000; + } + else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) + { + int m_nSegments = 0; + if (!m_rts.SearchSubs((int)(m_rtStart/10000), 25, &m_nPosition, &m_nSegments)) + m_nPosition = m_nSegments; + } + else + { + m_nPosition = m_rts.SearchSub((int)(m_rtStart/10000), 25); + if (m_nPosition < 0) m_nPosition = 0; + else if (m_rts[m_nPosition].end <= (int)(m_rtStart/10000)) m_nPosition++; + }*/ + } + + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CSubtitleStream::ChangeStop() +{ + /*{ + CAutoLock lock(CSourceSeeking::m_pLock); + if (m_rtPosition < m_rtStop) + return S_OK; + }*/ + // We're already past the new stop time -- better flush the graph. + UpdateFromSeek(); + + return S_OK; +} + +HRESULT CSubtitleStream::OnThreadCreate() +{ + CAutoLock cAutoLockShared(&m_cSharedState); + + if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { + m_nPosition = (int)(m_rtStart / _ATPF); + } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { + int m_nSegments = 0; + if (!m_rts.SearchSubs((int)(m_rtStart / 10000), 10000000.0 / _ATPF, &m_nPosition, &m_nSegments)) { + m_nPosition = m_nSegments; + } + } else { + m_nPosition = m_rts.SearchSub((int)(m_rtStart / 10000), 25); + if (m_nPosition < 0) { + m_nPosition = 0; + } else if (m_rts[m_nPosition].end <= (int)(m_rtStart / 10000)) { + m_nPosition++; + } + } + + return CSourceStream::OnThreadCreate(); +} + +HRESULT CSubtitleStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) +{ + //CAutoLock cAutoLock(m_pFilter->pStateLock()); + + ASSERT(pAlloc); + ASSERT(pProperties); + + HRESULT hr = NOERROR; + + if (m_mt.majortype == MEDIATYPE_Video) { + pProperties->cBuffers = 2; + pProperties->cbBuffer = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader.biSizeImage; + } else { + pProperties->cBuffers = 1; + pProperties->cbBuffer = 0x10000; + } + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { + return hr; + } + + if (Actual.cbBuffer < pProperties->cbBuffer) { + return E_FAIL; + } + ASSERT(Actual.cBuffers == pProperties->cBuffers); + + return NOERROR; +} + +HRESULT CSubtitleStream::FillBuffer(IMediaSample* pSample) +{ + { + CAutoLock cAutoLockShared(&m_cSharedState); + + BYTE* pData = nullptr; + if (FAILED(pSample->GetPointer(&pData)) || !pData) { + return S_FALSE; + } + + AM_MEDIA_TYPE* pmt; + if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { + CMediaType mt(*pmt); + SetMediaType(&mt); + DeleteMediaType(pmt); + } + + int len = 0; + REFERENCE_TIME rtStart, rtStop; + + if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { + rtStart = (REFERENCE_TIME)((m_nPosition * _ATPF - m_rtStart) / m_dRateSeeking); + rtStop = (REFERENCE_TIME)(((m_nPosition + 1) * _ATPF - m_rtStart) / m_dRateSeeking); + if (m_rtStart + rtStart >= m_rtDuration) { + return S_FALSE; + } + + BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; + + SubPicDesc spd; + spd.w = _WIDTH; + spd.h = _HEIGHT; + spd.bpp = 32; + spd.pitch = bmi.biWidth * 4; + spd.bits = pData; + + len = spd.h * spd.pitch; + + for (int y = 0; y < spd.h; y++) { + memsetd((DWORD*)(pData + spd.pitch * y), 0xff000000, spd.w * 4); + } + + RECT bbox; + m_rts.Render(spd, m_nPosition * _ATPF, 10000000.0 / _ATPF, bbox); + + for (int y = 0; y < spd.h; y++) { + DWORD* p = (DWORD*)(pData + spd.pitch * y); + for (int x = 0; x < spd.w; x++, p++) { + *p = (0xff000000 - (*p & 0xff000000)) | (*p & 0xffffff); + } + } + } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { + const STSSegment* stss = m_rts.GetSegment(m_nPosition); + if (!stss) { + return S_FALSE; + } + + BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; + + SubPicDesc spd; + spd.w = _WIDTH; + spd.h = _HEIGHT; + spd.bpp = 32; + spd.pitch = bmi.biWidth * 4; + spd.bits = pData; + + len = spd.h * spd.pitch; + + for (int y = 0; y < spd.h; y++) { + DWORD c1 = 0xff606060, c2 = 0xffa0a0a0; + if (y & 32) { + c1 ^= c2, c2 ^= c1, c1 ^= c2; + } + DWORD* p = (DWORD*)(pData + spd.pitch * y); + for (int x = 0; x < spd.w; x += 32, p += 32) { + memsetd(p, (x & 32) ? c1 : c2, std::min(spd.w - x, 32) * 4); + } + } + + RECT bbox; + m_rts.Render(spd, 10000i64 * (stss->start + stss->end) / 2, 10000000.0 / _ATPF, bbox); + + rtStart = (REFERENCE_TIME)((10000i64 * stss->start - m_rtStart) / m_dRateSeeking); + rtStop = (REFERENCE_TIME)((10000i64 * stss->end - m_rtStart) / m_dRateSeeking); + } else { + if ((size_t)m_nPosition >= m_rts.GetCount()) { + return S_FALSE; + } + + STSEntry& stse = m_rts[m_nPosition]; + + if (stse.start >= m_rtStop / 10000) { + return S_FALSE; + } + + if (m_mt.majortype == MEDIATYPE_Subtitle && m_mt.subtype == MEDIASUBTYPE_UTF8) { + CStringA str = UTF16To8(m_rts.GetStrW(m_nPosition, false)); + memcpy((char*)pData, str, len = str.GetLength()); + } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS)) { + CStringW line; + line.Format(L"%d,%d,%s,%s,%d,%d,%d,%s,%s", + stse.readorder, stse.layer, stse.style.GetString(), stse.actor.GetString(), + stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top + stse.marginRect.bottom) / 2, + stse.effect.GetString(), m_rts.GetStrW(m_nPosition, true).GetString()); + + CStringA str = UTF16To8(line); + memcpy((char*)pData, str, len = str.GetLength()); + } else if (m_mt.majortype == MEDIATYPE_Text && m_mt.subtype == MEDIASUBTYPE_NULL) { + CStringA str = m_rts.GetStrA(m_nPosition, false); + memcpy((char*)pData, str, len = str.GetLength()); + } else { + return S_FALSE; + } + + rtStart = (REFERENCE_TIME)((10000i64 * stse.start - m_rtStart) / m_dRateSeeking); + rtStop = (REFERENCE_TIME)((10000i64 * stse.end - m_rtStart) / m_dRateSeeking); + } + + pSample->SetTime(&rtStart, &rtStop); + pSample->SetActualDataLength(len); + + m_nPosition++; + } + + pSample->SetSyncPoint(TRUE); + + if (m_bDiscontinuity) { + pSample->SetDiscontinuity(TRUE); + m_bDiscontinuity = FALSE; + } + + return S_OK; +} + +HRESULT CSubtitleStream::GetMediaType(CMediaType* pmt) +{ + return (static_cast(m_pFilter))->GetMediaType(pmt); +} + +HRESULT CSubtitleStream::CheckMediaType(const CMediaType* pmt) +{ + CAutoLock lock(m_pFilter->pStateLock()); + + CMediaType mt; + GetMediaType(&mt); + + if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { + return NOERROR; + } + + return E_FAIL; +} + +STDMETHODIMP CSubtitleStream::Notify(IBaseFilter* pSender, Quality q) +{ + return E_NOTIMPL; +} + +// +// CSubtitleSourceASCII +// + +CSubtitleSourceASCII::CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceASCII::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Text); + pmt->SetSubtype(&MEDIASUBTYPE_NULL); + pmt->SetFormatType(&FORMAT_None); + pmt->ResetFormatBuffer(); + + return NOERROR; +} + +// +// CSubtitleSourceUTF8 +// + +CSubtitleSourceUTF8::CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceUTF8::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Subtitle); + pmt->SetSubtype(&MEDIASUBTYPE_UTF8); + pmt->SetFormatType(&FORMAT_SubtitleInfo); + SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); + ZeroMemory(psi, pmt->FormatLength()); + strcpy_s(psi->IsoLang, "eng"); + + return NOERROR; +} + +// +// CSubtitleSourceSSA +// + +CSubtitleSourceSSA::CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceSSA::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Subtitle); + pmt->SetSubtype(&MEDIASUBTYPE_SSA); + pmt->SetFormatType(&FORMAT_SubtitleInfo); + + CSimpleTextSubtitle sts; + sts.Open(CString(m_fn), DEFAULT_CHARSET); + sts.RemoveAll(); + + CFile f; + TCHAR path[MAX_PATH], fn[MAX_PATH]; + if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { + return E_FAIL; + } + + _tremove(fn); + + _tcscat_s(fn, _T(".ssa")); + + if (!sts.SaveAs(fn, Subtitle::SSA, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { + return E_FAIL; + } + + int len = (int)f.GetLength() - 3; + f.Seek(3, CFile::begin); + + SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); + ZeroMemory(psi, pmt->FormatLength()); + psi->dwOffset = sizeof(SUBTITLEINFO); + strcpy_s(psi->IsoLang, "eng"); + f.Read(pmt->pbFormat + psi->dwOffset, len); + f.Close(); + + _tremove(fn); + + return NOERROR; +} + +// +// CSubtitleSourceASS +// + +CSubtitleSourceASS::CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceASS::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Subtitle); + pmt->SetSubtype(&MEDIASUBTYPE_ASS); + pmt->SetFormatType(&FORMAT_SubtitleInfo); + + CSimpleTextSubtitle sts; + sts.Open(CString(m_fn), DEFAULT_CHARSET); + sts.RemoveAll(); + + CFile f; + TCHAR path[MAX_PATH], fn[MAX_PATH]; + if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { + return E_FAIL; + } + + _tremove(fn); + + _tcscat_s(fn, _T(".ass")); + + if (!sts.SaveAs(fn, Subtitle::ASS, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { + return E_FAIL; + } + + int len = (int)f.GetLength(); + + SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); + ZeroMemory(psi, pmt->FormatLength()); + psi->dwOffset = sizeof(SUBTITLEINFO); + strcpy_s(psi->IsoLang, "eng"); + f.Read(pmt->pbFormat + psi->dwOffset, len); + f.Close(); + + _tremove(fn); + + return NOERROR; +} + +// +// CSubtitleSourceUSF +// + +CSubtitleSourceUSF::CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceUSF::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Subtitle); + pmt->SetSubtype(&MEDIASUBTYPE_USF); + pmt->SetFormatType(&FORMAT_SubtitleInfo); + SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); + ZeroMemory(psi, pmt->FormatLength()); + strcpy_s(psi->IsoLang, "eng"); + // TODO: ... + + return NOERROR; +} + +// +// CSubtitleSourcePreview +// + +CSubtitleSourcePreview::CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourcePreview::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Video); + pmt->SetSubtype(&MEDIASUBTYPE_RGB32); + pmt->SetFormatType(&FORMAT_VideoInfo); + VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); + ZeroMemory(pvih, pmt->FormatLength()); + pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); + pvih->bmiHeader.biWidth = _WIDTH; + pvih->bmiHeader.biHeight = _HEIGHT; + pvih->bmiHeader.biBitCount = 32; + pvih->bmiHeader.biCompression = BI_RGB; + pvih->bmiHeader.biPlanes = 1; + pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth * abs(pvih->bmiHeader.biHeight) * pvih->bmiHeader.biBitCount >> 3; + + return NOERROR; +} + +// +// CSubtitleSourceARGB +// + +CSubtitleSourceARGB::CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr) + : CSubtitleSource(lpunk, phr, __uuidof(this)) +{ +} + +HRESULT CSubtitleSourceARGB::GetMediaType(CMediaType* pmt) +{ + CAutoLock cAutoLock(pStateLock()); + + pmt->InitMediaType(); + pmt->SetType(&MEDIATYPE_Video); + pmt->SetSubtype(&MEDIASUBTYPE_ARGB32); + pmt->SetFormatType(&FORMAT_VideoInfo); + VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); + ZeroMemory(pvih, pmt->FormatLength()); + pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); + // TODO: read w,h,fps from a config file or registry + pvih->bmiHeader.biWidth = _WIDTH; + pvih->bmiHeader.biHeight = _HEIGHT; + pvih->bmiHeader.biBitCount = 32; + pvih->bmiHeader.biCompression = BI_RGB; + pvih->bmiHeader.biPlanes = 1; + pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth * abs(pvih->bmiHeader.biHeight) * pvih->bmiHeader.biBitCount >> 3; + + return NOERROR; +} diff --git a/src/filters/source/SubtitleSource/SubtitleSource.def b/src/filters/source/SubtitleSource/SubtitleSource.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.def +++ b/src/filters/source/SubtitleSource/SubtitleSource.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/source/SubtitleSource/SubtitleSource.h b/src/filters/source/SubtitleSource/SubtitleSource.h index 379ba8d7102..b8e7382a994 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.h +++ b/src/filters/source/SubtitleSource/SubtitleSource.h @@ -1,155 +1,155 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "../../../Subtitles/RTS.h" - -#define SubtitleSourceName L"MPC-HC Subtitle Source" - -class CSubtitleSource - : public CSource - , public IFileSourceFilter - , public IAMFilterMiscFlags -{ -protected: - CStringW m_fn; - -public: - CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid); - virtual ~CSubtitleSource(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IFileSourceFilter - STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); - - // IAMFilterMiscFlags - STDMETHODIMP_(ULONG) GetMiscFlags(); - - virtual HRESULT GetMediaType(CMediaType* pmt) = 0; - - // CBaseFilter - STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); -}; - -class CSubtitleStream - : public CSourceStream - , public CSourceSeeking -{ - CCritSec m_cSharedState; - - int m_nPosition; - - BOOL m_bDiscontinuity, m_bFlushing; - - HRESULT OnThreadStartPlay(); - HRESULT OnThreadCreate(); - - void UpdateFromSeek(); - STDMETHODIMP SetRate(double dRate); - - HRESULT ChangeStart(); - HRESULT ChangeStop(); - HRESULT ChangeRate() { return S_OK; } - -protected: - CRenderedTextSubtitle m_rts; - -public: - CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr); - virtual ~CSubtitleStream(); - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT DecideBufferSize(IMemAllocator* pIMemAlloc, ALLOCATOR_PROPERTIES* pProperties); - HRESULT FillBuffer(IMediaSample* pSample); - HRESULT GetMediaType(CMediaType* pmt); - HRESULT CheckMediaType(const CMediaType* pmt); - - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); -}; - -class __declspec(uuid("E44CA3B5-A0FF-41A0-AF16-42429B1095EA")) - CSubtitleSourceASCII : public CSubtitleSource -{ -public: - CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("87864E0F-7073-4E39-B802-143DE0ED4964")) - CSubtitleSourceUTF8 : public CSubtitleSource -{ -public: - CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("18316B1A-5877-4CC4-85FD-EDE65CD489EC")) - CSubtitleSourceSSA : public CSubtitleSource -{ -public: - CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("416782BC-1D87-48C0-8F65-F113A5CB8E15")) - CSubtitleSourceASS : public CSubtitleSource -{ -public: - CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("D7215AFC-DFE6-483B-9AF3-6BBECFF14CF4")) - CSubtitleSourceUSF : public CSubtitleSource -{ -public: - CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("932E75D4-BBD4-4A0F-9071-6728FBDC4C98")) - CSubtitleSourcePreview : public CSubtitleSource -{ -public: - CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; - -class __declspec(uuid("CF0D7280-527D-415E-BA02-56017484D73E")) - CSubtitleSourceARGB : public CSubtitleSource -{ -public: - CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr); - - HRESULT GetMediaType(CMediaType* pmt); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "../../../Subtitles/RTS.h" + +#define SubtitleSourceName L"MPC-HC Subtitle Source" + +class CSubtitleSource + : public CSource + , public IFileSourceFilter + , public IAMFilterMiscFlags +{ +protected: + CStringW m_fn; + +public: + CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid); + virtual ~CSubtitleSource(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IFileSourceFilter + STDMETHODIMP Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt); + + // IAMFilterMiscFlags + STDMETHODIMP_(ULONG) GetMiscFlags(); + + virtual HRESULT GetMediaType(CMediaType* pmt) = 0; + + // CBaseFilter + STDMETHODIMP QueryFilterInfo(FILTER_INFO* pInfo); +}; + +class CSubtitleStream + : public CSourceStream + , public CSourceSeeking +{ + CCritSec m_cSharedState; + + int m_nPosition; + + BOOL m_bDiscontinuity, m_bFlushing; + + HRESULT OnThreadStartPlay(); + HRESULT OnThreadCreate(); + + void UpdateFromSeek(); + STDMETHODIMP SetRate(double dRate); + + HRESULT ChangeStart(); + HRESULT ChangeStop(); + HRESULT ChangeRate() { return S_OK; } + +protected: + CRenderedTextSubtitle m_rts; + +public: + CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr); + virtual ~CSubtitleStream(); + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT DecideBufferSize(IMemAllocator* pIMemAlloc, ALLOCATOR_PROPERTIES* pProperties); + HRESULT FillBuffer(IMediaSample* pSample); + HRESULT GetMediaType(CMediaType* pmt); + HRESULT CheckMediaType(const CMediaType* pmt); + + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); +}; + +class __declspec(uuid("E44CA3B5-A0FF-41A0-AF16-42429B1095EA")) + CSubtitleSourceASCII : public CSubtitleSource +{ +public: + CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("87864E0F-7073-4E39-B802-143DE0ED4964")) + CSubtitleSourceUTF8 : public CSubtitleSource +{ +public: + CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("18316B1A-5877-4CC4-85FD-EDE65CD489EC")) + CSubtitleSourceSSA : public CSubtitleSource +{ +public: + CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("416782BC-1D87-48C0-8F65-F113A5CB8E15")) + CSubtitleSourceASS : public CSubtitleSource +{ +public: + CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("D7215AFC-DFE6-483B-9AF3-6BBECFF14CF4")) + CSubtitleSourceUSF : public CSubtitleSource +{ +public: + CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("932E75D4-BBD4-4A0F-9071-6728FBDC4C98")) + CSubtitleSourcePreview : public CSubtitleSource +{ +public: + CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; + +class __declspec(uuid("CF0D7280-527D-415E-BA02-56017484D73E")) + CSubtitleSourceARGB : public CSubtitleSource +{ +public: + CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr); + + HRESULT GetMediaType(CMediaType* pmt); +}; diff --git a/src/filters/source/SubtitleSource/SubtitleSource.rc b/src/filters/source/SubtitleSource/SubtitleSource.rc index 5e2e430d87f..47de809a7f9 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.rc +++ b/src/filters/source/SubtitleSource/SubtitleSource.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "SubtitleSource Filter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "SubtitleSource Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "SubtitleSource.ax" - VALUE "ProductName", "SubtitleSource Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "SubtitleSource Filter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "SubtitleSource Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "SubtitleSource.ax" + VALUE "ProductName", "SubtitleSource Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/source/SubtitleSource/SubtitleSource.vcxproj b/src/filters/source/SubtitleSource/SubtitleSource.vcxproj index 3836a388d2b..af365f1865e 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.vcxproj +++ b/src/filters/source/SubtitleSource/SubtitleSource.vcxproj @@ -1,133 +1,133 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {8F998497-9C51-4FAA-83E4-1D85B22CBA13} - SubtitleSource - MFCProj - SubtitleSource - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;..\..\..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - comsuppw.lib;Vfw32.lib;%(AdditionalDependencies) - SubtitleSource.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - Create - - - - - - - - - true - - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {d514ea4d-eafb-47a9-a437-a582ca571251} - - - {5e56335f-0fb1-4eea-b240-d8dc5e0608e4} - - - {da8461c4-7683-4360-9372-2a9e0f1795c2} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {8F998497-9C51-4FAA-83E4-1D85B22CBA13} + SubtitleSource + MFCProj + SubtitleSource + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;..\..\..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + comsuppw.lib;Vfw32.lib;%(AdditionalDependencies) + SubtitleSource.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + Create + + + + + + + + + true + + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {d514ea4d-eafb-47a9-a437-a582ca571251} + + + {5e56335f-0fb1-4eea-b240-d8dc5e0608e4} + + + {da8461c4-7683-4360-9372-2a9e0f1795c2} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/source/SubtitleSource/SubtitleSource.vcxproj.filters b/src/filters/source/SubtitleSource/SubtitleSource.vcxproj.filters index 1b24192f8e1..1e69995e668 100644 --- a/src/filters/source/SubtitleSource/SubtitleSource.vcxproj.filters +++ b/src/filters/source/SubtitleSource/SubtitleSource.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {02ec0f4b-6c0b-4d12-b1f0-0cbc16c2b813} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {dab25e34-5059-453a-8973-39482d61dbc4} - h;hpp;hxx;hm;inl;inc - - - {e6e3e6a0-c068-410d-a040-01813e3bd6aa} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {02ec0f4b-6c0b-4d12-b1f0-0cbc16c2b813} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {dab25e34-5059-453a-8973-39482d61dbc4} + h;hpp;hxx;hm;inl;inc + + + {e6e3e6a0-c068-410d-a040-01813e3bd6aa} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/source/SubtitleSource/resource.h b/src/filters/source/SubtitleSource/resource.h index b56787c1e85..a1c36076f0b 100644 --- a/src/filters/source/SubtitleSource/resource.h +++ b/src/filters/source/SubtitleSource/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by SubtitleSource.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SubtitleSource.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/source/SubtitleSource/stdafx.cpp b/src/filters/source/SubtitleSource/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/source/SubtitleSource/stdafx.cpp +++ b/src/filters/source/SubtitleSource/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/source/SubtitleSource/stdafx.h b/src/filters/source/SubtitleSource/stdafx.h index 12bbe2db0a7..d8320f2c878 100644 --- a/src/filters/source/SubtitleSource/stdafx.h +++ b/src/filters/source/SubtitleSource/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/stdafx.cpp b/src/filters/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/stdafx.cpp +++ b/src/filters/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/stdafx.h b/src/filters/stdafx.h index 9499f547031..8ee094e9596 100644 --- a/src/filters/stdafx.h +++ b/src/filters/stdafx.h @@ -1,43 +1,43 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include -namespace Gdiplus -{ - using std::min; - using std::max; -}; -#include - -#include -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include +namespace Gdiplus +{ + using std::min; + using std::max; +}; +#include + +#include +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/switcher/AudioSwitcher/Audio.cpp b/src/filters/switcher/AudioSwitcher/Audio.cpp index cb2c99a103f..1313d82ea2f 100644 --- a/src/filters/switcher/AudioSwitcher/Audio.cpp +++ b/src/filters/switcher/AudioSwitcher/Audio.cpp @@ -1,322 +1,322 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ -// originally from virtualdub - -#include "stdafx.h" -#include -#include -#include "Audio.h" - -static long audio_pointsample_8(void* dst, void* src, long accum, long samp_frac, long cnt) -{ - unsigned char* d = (unsigned char*)dst; - unsigned char* s = (unsigned char*)src; - - do { - *d++ = s[accum >> 19]; - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static long audio_pointsample_16(void* dst, void* src, long accum, long samp_frac, long cnt) -{ - unsigned short* d = (unsigned short*)dst; - unsigned short* s = (unsigned short*)src; - - do { - *d++ = s[accum >> 19]; - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static long audio_pointsample_32(void* dst, void* src, long accum, long samp_frac, long cnt) -{ - unsigned long* d = (unsigned long*)dst; - unsigned long* s = (unsigned long*)src; - - do { - *d++ = s[accum >> 19]; - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static long audio_downsample_mono8(void* dst, void* src, long* filter_bank, int filter_width, long accum, long samp_frac, long cnt) -{ - unsigned char* d = (unsigned char*)dst; - unsigned char* s = (unsigned char*)src; - - do { - long sum = 0; - int w; - long* fb_ptr; - unsigned char* s_ptr; - - w = filter_width; - fb_ptr = filter_bank + filter_width * ((accum >> 11) & 0xff); - s_ptr = s + (accum >> 19); - do { - sum += *fb_ptr++ * (int) * s_ptr++; - } while (--w); - - if (sum < 0) { - *d++ = 0; - } else if (sum > 0x3fffff) { - *d++ = 0xff; - } else { - *d++ = (unsigned char)((sum + 0x2000) >> 14); - } - - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static long audio_downsample_mono16(void* dst, void* src, long* filter_bank, int filter_width, long accum, long samp_frac, long cnt) -{ - signed short* d = (signed short*)dst; - signed short* s = (signed short*)src; - - do { - long sum = 0; - int w; - long* fb_ptr; - signed short* s_ptr; - - w = filter_width; - fb_ptr = filter_bank + filter_width * ((accum >> 11) & 0xff); - s_ptr = s + (accum >> 19); - do { - sum += *fb_ptr++ * (int) * s_ptr++; - } while (--w); - - if (sum < -0x20000000) { - *d++ = -0x8000; - } else if (sum > 0x1fffffff) { - *d++ = 0x7fff; - } else { - *d++ = (signed short)((sum + 0x2000) >> 14); - } - - accum += samp_frac; - } while (--cnt); - - return accum; -} - -static int permute_index(int a, int b) -{ - return (b - (a >> 8) - 1) + (a & 255) * b; -} - -static void make_downsample_filter(long* filter_bank, int filter_width, long samp_frac) -{ - int i, j; - double filt_max; - double filtwidth_frac; - - filtwidth_frac = samp_frac / 2048.0; - - filter_bank[filter_width - 1] = 0; - - filt_max = (16384.0 * 524288.0) / samp_frac; - - for (i = 0; i < 128 * filter_width; i++) { - int y = 0; - double d = i / filtwidth_frac; - - if (d < 1.0) { - y = (int)(0.5 + filt_max * (1.0 - d)); - } - - filter_bank[permute_index(128 * filter_width + i, filter_width)] - = filter_bank[permute_index(128 * filter_width - i, filter_width)] - = y; - } - - // Normalize the filter to correct for integer roundoff errors - - for (i = 0; i < 256 * filter_width; i += filter_width) { - int v = 0; - for (j = 0; j < filter_width; j++) { - v += filter_bank[i + j]; - } - - //_RPT2(0,"error[%02x] = %04x\n", i/filter_width, 0x4000 - v); - - v = (0x4000 - v) / filter_width; - for (j = 0; j < filter_width; j++) { - filter_bank[i + j] += v; - } - } - - // _CrtCheckMemory(); -} - -AudioStreamResampler::AudioStreamResampler(int bps, long orig_rate, long new_rate, bool fHighQuality) - : ptsampleRout(audio_pointsample_16) - , dnsampleRout(audio_downsample_mono16) - , samp_frac(0x80000) - , accum(0) - , holdover(0) - , filter_bank(nullptr) - , filter_width(1) - , bps(bps) -{ - if (bps == 1) { - ptsampleRout = audio_pointsample_8; - dnsampleRout = audio_downsample_mono8; - } else if (bps >= 2) { - ptsampleRout = audio_pointsample_16; - dnsampleRout = audio_downsample_mono16; - } else { - return; - } - - // orig_rate > new_rate! - samp_frac = MulDiv(orig_rate, 0x80000, new_rate); - - // If this is a high-quality downsample, allocate memory for the filter bank - if (fHighQuality) { - if (samp_frac > 0x80000) { - // HQ downsample: allocate filter bank - - filter_width = ((samp_frac + 0x7ffff) >> 19) << 1 << 1; - - filter_bank = DEBUG_NEW long[filter_width * 256]; - if (!filter_bank) { - filter_width = 1; - return; - } - - make_downsample_filter(filter_bank, filter_width, samp_frac); - - // Clear lower samples - - memset(cbuffer, bps >= 2 ? 0 : 0x80, bps * filter_width); - - holdover = filter_width / 2; - } - } -} - -AudioStreamResampler::~AudioStreamResampler() -{ - delete [] filter_bank; -} - -long AudioStreamResampler::Downsample(void* input, long samplesIn, void* output, long samplesOut) -{ - long lActualSamples = 0; - - // Downsampling is even worse because we have overlap to the left and to the - // right of the interpolated point. - // - // We need (n/2) points to the left and (n/2-1) points to the right. - - while (samplesIn > 0 && samplesOut > 0) { - long srcSamples, dstSamples; - int nhold; - - // Figure out how many source samples we need. - // - // To do this, compute the highest fixed-point accumulator we'll reach. - // Truncate that, and add the filter width. Then subtract however many - // samples are sitting at the bottom of the buffer. - - srcSamples = (long)(((__int64)samp_frac * (samplesOut - 1) + accum) >> 19) + filter_width - holdover; - - // Don't exceed the buffer (BUFFER_SIZE - holdover). - - if (srcSamples > BUFFER_SIZE - holdover) { - srcSamples = BUFFER_SIZE - holdover; - } - - // Read into buffer. - - srcSamples = std::min(srcSamples, samplesIn); - if (!srcSamples) { - break; - } - - memcpy((char*)cbuffer + holdover * bps, (char*)input, srcSamples * bps); - input = (void*)((char*)input + srcSamples * bps); - - // Figure out how many destination samples we'll get out of what we - // read. We'll have (srcSamples+holdover) bytes, so the maximum - // fixed-pt accumulator we can hit is - // (srcSamples+holdover-filter_width)<<16 + 0xffff. - - dstSamples = (((__int64)(srcSamples + holdover - filter_width) << 19) + 0x7ffff - accum) / samp_frac + 1; - - if (dstSamples > samplesOut) { - dstSamples = samplesOut; - } - - if (dstSamples >= 1) { - if (filter_bank) { - accum = dnsampleRout(output, cbuffer, filter_bank, filter_width, accum, samp_frac, dstSamples); - } else { - accum = ptsampleRout(output, cbuffer, accum, samp_frac, dstSamples); - } - - output = (void*)((char*)output + bps * dstSamples); - lActualSamples += dstSamples; - samplesOut -= dstSamples; - } - - // We're "shifting" the new samples down to the bottom by discarding - // all the samples in the buffer, so adjust the fixed-pt accum - // accordingly. - - accum -= ((srcSamples + holdover) << 19); - - // Oops, did we need some of those? - // - // If accum=0, we need (n/2) samples back. accum>=0x10000 is fewer, - // accum<0 is more. - - nhold = - (accum >> 19); - - //ASSERT(nhold <= (filter_width / 2)); - - if (nhold > 0) { - memmove(cbuffer, (char*)cbuffer + bps * (srcSamples + holdover - nhold), bps * nhold); - holdover = nhold; - accum += nhold << 19; - } else { - holdover = 0; - } - - //ASSERT(accum >= 0); - } - - int Bytes = lActualSamples * bps; - UNREFERENCED_PARAMETER(Bytes); - - return lActualSamples; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ +// originally from virtualdub + +#include "stdafx.h" +#include +#include +#include "Audio.h" + +static long audio_pointsample_8(void* dst, void* src, long accum, long samp_frac, long cnt) +{ + unsigned char* d = (unsigned char*)dst; + unsigned char* s = (unsigned char*)src; + + do { + *d++ = s[accum >> 19]; + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static long audio_pointsample_16(void* dst, void* src, long accum, long samp_frac, long cnt) +{ + unsigned short* d = (unsigned short*)dst; + unsigned short* s = (unsigned short*)src; + + do { + *d++ = s[accum >> 19]; + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static long audio_pointsample_32(void* dst, void* src, long accum, long samp_frac, long cnt) +{ + unsigned long* d = (unsigned long*)dst; + unsigned long* s = (unsigned long*)src; + + do { + *d++ = s[accum >> 19]; + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static long audio_downsample_mono8(void* dst, void* src, long* filter_bank, int filter_width, long accum, long samp_frac, long cnt) +{ + unsigned char* d = (unsigned char*)dst; + unsigned char* s = (unsigned char*)src; + + do { + long sum = 0; + int w; + long* fb_ptr; + unsigned char* s_ptr; + + w = filter_width; + fb_ptr = filter_bank + filter_width * ((accum >> 11) & 0xff); + s_ptr = s + (accum >> 19); + do { + sum += *fb_ptr++ * (int) * s_ptr++; + } while (--w); + + if (sum < 0) { + *d++ = 0; + } else if (sum > 0x3fffff) { + *d++ = 0xff; + } else { + *d++ = (unsigned char)((sum + 0x2000) >> 14); + } + + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static long audio_downsample_mono16(void* dst, void* src, long* filter_bank, int filter_width, long accum, long samp_frac, long cnt) +{ + signed short* d = (signed short*)dst; + signed short* s = (signed short*)src; + + do { + long sum = 0; + int w; + long* fb_ptr; + signed short* s_ptr; + + w = filter_width; + fb_ptr = filter_bank + filter_width * ((accum >> 11) & 0xff); + s_ptr = s + (accum >> 19); + do { + sum += *fb_ptr++ * (int) * s_ptr++; + } while (--w); + + if (sum < -0x20000000) { + *d++ = -0x8000; + } else if (sum > 0x1fffffff) { + *d++ = 0x7fff; + } else { + *d++ = (signed short)((sum + 0x2000) >> 14); + } + + accum += samp_frac; + } while (--cnt); + + return accum; +} + +static int permute_index(int a, int b) +{ + return (b - (a >> 8) - 1) + (a & 255) * b; +} + +static void make_downsample_filter(long* filter_bank, int filter_width, long samp_frac) +{ + int i, j; + double filt_max; + double filtwidth_frac; + + filtwidth_frac = samp_frac / 2048.0; + + filter_bank[filter_width - 1] = 0; + + filt_max = (16384.0 * 524288.0) / samp_frac; + + for (i = 0; i < 128 * filter_width; i++) { + int y = 0; + double d = i / filtwidth_frac; + + if (d < 1.0) { + y = (int)(0.5 + filt_max * (1.0 - d)); + } + + filter_bank[permute_index(128 * filter_width + i, filter_width)] + = filter_bank[permute_index(128 * filter_width - i, filter_width)] + = y; + } + + // Normalize the filter to correct for integer roundoff errors + + for (i = 0; i < 256 * filter_width; i += filter_width) { + int v = 0; + for (j = 0; j < filter_width; j++) { + v += filter_bank[i + j]; + } + + //_RPT2(0,"error[%02x] = %04x\n", i/filter_width, 0x4000 - v); + + v = (0x4000 - v) / filter_width; + for (j = 0; j < filter_width; j++) { + filter_bank[i + j] += v; + } + } + + // _CrtCheckMemory(); +} + +AudioStreamResampler::AudioStreamResampler(int bps, long orig_rate, long new_rate, bool fHighQuality) + : ptsampleRout(audio_pointsample_16) + , dnsampleRout(audio_downsample_mono16) + , samp_frac(0x80000) + , accum(0) + , holdover(0) + , filter_bank(nullptr) + , filter_width(1) + , bps(bps) +{ + if (bps == 1) { + ptsampleRout = audio_pointsample_8; + dnsampleRout = audio_downsample_mono8; + } else if (bps >= 2) { + ptsampleRout = audio_pointsample_16; + dnsampleRout = audio_downsample_mono16; + } else { + return; + } + + // orig_rate > new_rate! + samp_frac = MulDiv(orig_rate, 0x80000, new_rate); + + // If this is a high-quality downsample, allocate memory for the filter bank + if (fHighQuality) { + if (samp_frac > 0x80000) { + // HQ downsample: allocate filter bank + + filter_width = ((samp_frac + 0x7ffff) >> 19) << 1 << 1; + + filter_bank = DEBUG_NEW long[filter_width * 256]; + if (!filter_bank) { + filter_width = 1; + return; + } + + make_downsample_filter(filter_bank, filter_width, samp_frac); + + // Clear lower samples + + memset(cbuffer, bps >= 2 ? 0 : 0x80, bps * filter_width); + + holdover = filter_width / 2; + } + } +} + +AudioStreamResampler::~AudioStreamResampler() +{ + delete [] filter_bank; +} + +long AudioStreamResampler::Downsample(void* input, long samplesIn, void* output, long samplesOut) +{ + long lActualSamples = 0; + + // Downsampling is even worse because we have overlap to the left and to the + // right of the interpolated point. + // + // We need (n/2) points to the left and (n/2-1) points to the right. + + while (samplesIn > 0 && samplesOut > 0) { + long srcSamples, dstSamples; + int nhold; + + // Figure out how many source samples we need. + // + // To do this, compute the highest fixed-point accumulator we'll reach. + // Truncate that, and add the filter width. Then subtract however many + // samples are sitting at the bottom of the buffer. + + srcSamples = (long)(((__int64)samp_frac * (samplesOut - 1) + accum) >> 19) + filter_width - holdover; + + // Don't exceed the buffer (BUFFER_SIZE - holdover). + + if (srcSamples > BUFFER_SIZE - holdover) { + srcSamples = BUFFER_SIZE - holdover; + } + + // Read into buffer. + + srcSamples = std::min(srcSamples, samplesIn); + if (!srcSamples) { + break; + } + + memcpy((char*)cbuffer + holdover * bps, (char*)input, srcSamples * bps); + input = (void*)((char*)input + srcSamples * bps); + + // Figure out how many destination samples we'll get out of what we + // read. We'll have (srcSamples+holdover) bytes, so the maximum + // fixed-pt accumulator we can hit is + // (srcSamples+holdover-filter_width)<<16 + 0xffff. + + dstSamples = (((__int64)(srcSamples + holdover - filter_width) << 19) + 0x7ffff - accum) / samp_frac + 1; + + if (dstSamples > samplesOut) { + dstSamples = samplesOut; + } + + if (dstSamples >= 1) { + if (filter_bank) { + accum = dnsampleRout(output, cbuffer, filter_bank, filter_width, accum, samp_frac, dstSamples); + } else { + accum = ptsampleRout(output, cbuffer, accum, samp_frac, dstSamples); + } + + output = (void*)((char*)output + bps * dstSamples); + lActualSamples += dstSamples; + samplesOut -= dstSamples; + } + + // We're "shifting" the new samples down to the bottom by discarding + // all the samples in the buffer, so adjust the fixed-pt accum + // accordingly. + + accum -= ((srcSamples + holdover) << 19); + + // Oops, did we need some of those? + // + // If accum=0, we need (n/2) samples back. accum>=0x10000 is fewer, + // accum<0 is more. + + nhold = - (accum >> 19); + + //ASSERT(nhold <= (filter_width / 2)); + + if (nhold > 0) { + memmove(cbuffer, (char*)cbuffer + bps * (srcSamples + holdover - nhold), bps * nhold); + holdover = nhold; + accum += nhold << 19; + } else { + holdover = 0; + } + + //ASSERT(accum >= 0); + } + + int Bytes = lActualSamples * bps; + UNREFERENCED_PARAMETER(Bytes); + + return lActualSamples; +} diff --git a/src/filters/switcher/AudioSwitcher/Audio.h b/src/filters/switcher/AudioSwitcher/Audio.h index 49185070a14..a9bc552c358 100644 --- a/src/filters/switcher/AudioSwitcher/Audio.h +++ b/src/filters/switcher/AudioSwitcher/Audio.h @@ -1,50 +1,50 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -typedef long(*AudioPointSampler)(void*, void*, long, long, long); -typedef long(*AudioDownSampler)(void*, void*, long*, int, long, long, long); - -class AudioStreamResampler -{ -private: - AudioPointSampler ptsampleRout; - AudioDownSampler dnsampleRout; - long samp_frac; - long accum; - int holdover; - long* filter_bank; - int filter_width; - - enum { BUFFER_SIZE = 512 }; - BYTE cbuffer[4 * BUFFER_SIZE]; - int bps; - -public: - AudioStreamResampler(int bps, long orig_rate, long new_rate, bool fHighQuality); - ~AudioStreamResampler(); - - AudioStreamResampler(const AudioStreamResampler&) = delete; - AudioStreamResampler& operator=(const AudioStreamResampler&) = delete; - - long Downsample(void* input, long samplesIn, void* output, long samplesOut); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +typedef long(*AudioPointSampler)(void*, void*, long, long, long); +typedef long(*AudioDownSampler)(void*, void*, long*, int, long, long, long); + +class AudioStreamResampler +{ +private: + AudioPointSampler ptsampleRout; + AudioDownSampler dnsampleRout; + long samp_frac; + long accum; + int holdover; + long* filter_bank; + int filter_width; + + enum { BUFFER_SIZE = 512 }; + BYTE cbuffer[4 * BUFFER_SIZE]; + int bps; + +public: + AudioStreamResampler(int bps, long orig_rate, long new_rate, bool fHighQuality); + ~AudioStreamResampler(); + + AudioStreamResampler(const AudioStreamResampler&) = delete; + AudioStreamResampler& operator=(const AudioStreamResampler&) = delete; + + long Downsample(void* input, long samplesIn, void* output, long samplesOut); +}; diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.cpp b/src/filters/switcher/AudioSwitcher/AudioSwitcher.cpp index fd92526d235..080e1ded4b4 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.cpp +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.cpp @@ -1,755 +1,755 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include -#include "AudioSwitcher.h" -#include "Audio.h" -#include "../../../DSUtil/DSUtil.h" -#include "../../../DSUtil/AudioTools.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -#define NORMALIZATION_REGAIN_STEP 0.06 // +6%/s -#define NORMALIZATION_REGAIN_THRESHOLD 0.75 - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL} -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL} -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CAudioSwitcherFilter), AudioSwitcherName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CAudioSwitcherFilter -// - -CAudioSwitcherFilter::CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr) - : CStreamSwitcherFilter(lpunk, phr, __uuidof(this)) - , m_fCustomChannelMapping(false) - , m_fDownSampleTo441(false) - , m_rtAudioTimeShift(0) - , m_fNormalize(false) - , m_fNormalizeRecover(false) - , m_nMaxNormFactor(4.0) - , m_boostFactor(1.0) - , m_normalizeFactor(m_nMaxNormFactor) - , m_rtNextStart(0) - , m_rtNextStop(1) - , m_rtSegmentStart(0) -{ - ZeroMemory(m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); - - if (phr) { - if (FAILED(*phr)) { - return; - } else { - *phr = S_OK; - } - } -} - -STDMETHODIMP CAudioSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IAudioSwitcherFilter) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CAudioSwitcherFilter::CheckMediaType(const CMediaType* pmt) -{ - if (pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->pbFormat) { - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pmt->pbFormat; - WORD wBitsPerSample = wfe->wBitsPerSample; - WORD wFormatTag = wfe->wFormatTag; - if (wfe->nChannels > 2 && wFormatTag != WAVE_FORMAT_EXTENSIBLE) { - return VFW_E_INVALIDMEDIATYPE; // iviaudio tries to fool us - } - if (wfe->nSamplesPerSec == 0) { - ASSERT(false); - return VFW_E_INVALIDMEDIATYPE; - } - if (wBitsPerSample == 8 || wBitsPerSample == 16 || wBitsPerSample == 24 || wBitsPerSample == 32) { - if (wFormatTag == WAVE_FORMAT_PCM || wFormatTag == WAVE_FORMAT_IEEE_FLOAT || wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF || wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - return S_OK; - } - } - } - return VFW_E_TYPE_NOT_ACCEPTED; -} - -template -__forceinline void mix(DWORD mask, int ch, int bps, BYTE* src, BYTE* dst) -{ - U sum = 0; - - for (int i = 0, j = ch; i < j; i++) { - if (mask & (1 << i)) { - sum += *(T*)&src[bps * i]; - } - } - - if (sum < Umin) { - sum = Umin; - } else if (sum > Umax) { - sum = Umax; - } - - *(T*)dst = (T)sum; -} - -template<> -__forceinline void mix(DWORD mask, int ch, int bps, BYTE* src, BYTE* dst) -{ - INT64 sum = 0; - - for (int i = 0, j = ch; i < j; i++) { - if (mask & (1 << i)) { - int tmp; - memcpy((BYTE*)&tmp + 1, &src[bps * i], 3); - sum += tmp >> 8; - } - } - - sum = std::min(std::max(sum, INT24_MIN), INT24_MAX); - - memcpy(dst, (BYTE*)&sum, 3); -} - -template -__forceinline void mix4(DWORD mask, BYTE* src, BYTE* dst) -{ - U sum = 0; - int bps = sizeof T; - - if (mask & (1 << 0)) { - sum += *(T*)&src[bps * 0]; - } - if (mask & (1 << 1)) { - sum += *(T*)&src[bps * 1]; - } - if (mask & (1 << 2)) { - sum += *(T*)&src[bps * 2]; - } - if (mask & (1 << 3)) { - sum += *(T*)&src[bps * 3]; - } - - if (sum < Umin) { - sum = Umin; - } else if (sum > Umax) { - sum = Umax; - } - - *(T*)dst = (T)sum; -} - -template -T clamp(double s, T smin, T smax) -{ - if (s < -1.0) { - s = -1.0; - } else if (s > 1.0) { - s = 1.0; - } - T t = (T)(s * smax); - if (t < smin) { - t = smin; - } else if (t > smax) { - t = smax; - } - return t; -} - -HRESULT CAudioSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - CStreamSwitcherInputPin* pInPin = GetInputPin(); - CStreamSwitcherOutputPin* pOutPin = GetOutputPin(); - if (!pInPin || !pOutPin) { - return __super::Transform(pIn, pOut); - } - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; - WAVEFORMATEX* wfeout = (WAVEFORMATEX*)pOutPin->CurrentMediaType().pbFormat; - WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe; - - int bps = wfe->wBitsPerSample >> 3; - - int len = pIn->GetActualDataLength() / (bps * wfe->nChannels); - if (len < 0 || wfe->nSamplesPerSec == 0 || !wfeout) { - return S_FALSE; - } - int lenout = (UINT64)len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec; - - REFERENCE_TIME rtStart, rtStop; - if (SUCCEEDED(pIn->GetTime(&rtStart, &rtStop))) { - rtStart += m_rtAudioTimeShift; - rtStop += m_rtAudioTimeShift; - pOut->SetTime(&rtStart, &rtStop); - - m_rtNextStart = rtStart; - m_rtNextStop = rtStop; - } else { - pOut->SetTime(&m_rtNextStart, &m_rtNextStop); - } - - REFERENCE_TIME rtDur = 10000000i64 * len / wfe->nSamplesPerSec; - - m_rtNextStart += rtDur; - m_rtNextStop += rtDur; - - if (m_normalizeFactor < 1.0 && pIn->IsDiscontinuity() == S_OK) { - m_normalizeFactor = std::max(1.0, m_nMaxNormFactor * 0.5); - } - - WORD tag = wfe->wFormatTag; - bool fPCM = tag == WAVE_FORMAT_PCM || tag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM; - bool fFloat = tag == WAVE_FORMAT_IEEE_FLOAT || tag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - if (!fPCM && !fFloat) { - return __super::Transform(pIn, pOut); - } - - BYTE* pDataIn = nullptr; - BYTE* pDataOut = nullptr; - - HRESULT hr; - if (FAILED(hr = pIn->GetPointer(&pDataIn))) { - return hr; - } - if (FAILED(hr = pOut->GetPointer(&pDataOut))) { - return hr; - } - - if (!pDataIn || !pDataOut) { - return S_FALSE; - } - // len = 0 doesn't mean it's failed, return S_OK otherwise might screw the sound - if (len == 0) { - pOut->SetActualDataLength(0); - return S_OK; - } - - bool bDownSampleTo441 = (m_fDownSampleTo441 - && wfe->nSamplesPerSec > 44100 && wfeout->nSamplesPerSec == 44100 - && wfe->wBitsPerSample <= 16 && fPCM); - - if (bDownSampleTo441 && m_pResamplers.GetCount() < wfeout->nChannels) { - ASSERT(false); - m_pResamplers.RemoveAll(); - for (int i = 0; i < wfeout->nChannels; i++) { - CAutoPtr pResampler; - pResampler.Attach(DEBUG_NEW AudioStreamResampler(wfeout->wBitsPerSample >> 3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true)); - m_pResamplers.Add(pResampler); - } - } - - BYTE* pTmp = nullptr; - BYTE* pDst = nullptr; - if (bDownSampleTo441 && m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { - pDst = pTmp = DEBUG_NEW BYTE[size_t(len) * size_t(bps) * wfeout->nChannels]; - } else { - pDst = pDataOut; - } - - if (m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { - size_t channelsCount = m_chs[wfe->nChannels - 1].GetCount(); - ASSERT(channelsCount == 0 || wfeout->nChannels == channelsCount); - - int srcstep = bps * wfe->nChannels; - int dststep = bps * wfeout->nChannels; - int channels = wfe->nChannels; - - if (channelsCount > 0 && wfeout->nChannels == channelsCount) { - for (int i = 0; i < wfeout->nChannels; i++) { - DWORD mask = m_chs[wfe->nChannels - 1][i].Channel; - - BYTE* src = pDataIn; - BYTE* dst = &pDst[bps * i]; - - if (fPCM) { - if (wfe->wBitsPerSample == 8) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix(mask, channels, bps, src, dst); - } - } else if (wfe->wBitsPerSample == 16) { - if (wfe->nChannels != 4 || wfeout->nChannels != 4) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix(mask, channels, bps, src, dst); - } - } else { // most popular channels count - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix4(mask, src, dst); - } - } - } else if (wfe->wBitsPerSample == 24) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix(mask, channels, bps, src, dst); - } - } else if (wfe->wBitsPerSample == 32) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix(mask, channels, bps, src, dst); - } - } - } else if (fFloat) { - if (wfe->wBitsPerSample == 32) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix < float, double, -1, 1 > (mask, channels, bps, src, dst); - } - } else if (wfe->wBitsPerSample == 64) { - for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { - mix < double, double, -1, 1 > (mask, channels, bps, src, dst); - } - } - } - } - } else { - ZeroMemory(pDataOut, pOut->GetSize()); - } - } else { - HRESULT hr2; - if (S_OK != (hr2 = __super::Transform(pIn, pOut))) { - return hr2; - } - } - - if (bDownSampleTo441) { - if (BYTE* buff = DEBUG_NEW BYTE[len * bps]) { - for (int ch = 0; ch < wfeout->nChannels; ch++) { - ZeroMemory(buff, len * bps); - - for (int i = 0; i < len; i++) { - memcpy(buff + i * bps, (char*)pDst + (ch + i * wfeout->nChannels)*bps, bps); - } - - m_pResamplers[ch]->Downsample(buff, len, buff, lenout); - - for (int i = 0; i < lenout; i++) { - memcpy((char*)pDataOut + (ch + i * wfeout->nChannels)*bps, buff + i * bps, bps); - } - } - - delete [] buff; - } - - delete [] pTmp; - } - - if (m_fNormalize || m_boostFactor > 1) { - size_t samples = size_t(lenout) * wfeout->nChannels; - double sample_mul = 1.0; - - if (m_fNormalize) { - double sample_max = 0.0; - - // calculate max peak - if (fPCM) { - int32_t maxpeak = 0; - if (wfe->wBitsPerSample == 8) { - for (size_t i = 0; i < samples; i++) { - int32_t peak = abs((int8_t)(pDataOut[i] ^ 0x80)); - if (peak > maxpeak) { - maxpeak = peak; - } - } - sample_max = (double)maxpeak / INT8_MAX; - } else if (wfe->wBitsPerSample == 16) { - for (size_t i = 0; i < samples; i++) { - int32_t peak = abs(((int16_t*)pDataOut)[i]); - if (peak > maxpeak) { - maxpeak = peak; - } - } - sample_max = (double)maxpeak / INT16_MAX; - } else if (wfe->wBitsPerSample == 24) { - for (size_t i = 0; i < samples; i++) { - int32_t peak = 0; - BYTE* p = (BYTE*)(&peak); - p[1] = pDataOut[i * 3]; - p[2] = pDataOut[i * 3 + 1]; - p[3] = pDataOut[i * 3 + 2]; - peak = abs(peak); - if (peak > maxpeak) { - maxpeak = peak; - } - } - sample_max = (double)maxpeak / INT32_MAX; - } else if (wfe->wBitsPerSample == 32) { - for (size_t i = 0; i < samples; i++) { - int32_t peak = abs(((int32_t*)pDataOut)[i]); - if (peak > maxpeak) { - maxpeak = peak; - } - } - sample_max = (double)maxpeak / INT32_MAX; - } - } else if (fFloat) { - if (wfe->wBitsPerSample == 32) { - for (size_t i = 0; i < samples; i++) { - double sample = (double)abs(((float*)pDataOut)[i]); - if (sample > sample_max) { - sample_max = sample; - } - } - } else if (wfe->wBitsPerSample == 64) { - for (size_t i = 0; i < samples; i++) { - double sample = (double)abs(((double*)pDataOut)[i]); - if (sample > sample_max) { - sample_max = sample; - } - } - } - } - - double normFact = 1.0 / sample_max; - if (m_normalizeFactor > normFact) { - m_normalizeFactor = normFact; - } else { - if (m_fNormalizeRecover) { - // we don't regain if we are too close of the maximum - if (sample_max * m_normalizeFactor < NORMALIZATION_REGAIN_THRESHOLD) { - m_normalizeFactor += NORMALIZATION_REGAIN_STEP * rtDur / 10000000; // the step is per second so we weight it with the duration - } - } else if (m_normalizeFactor < 0.8 && normFact >= 1.0) { - // recover from overflow situation (audio glitch?) - m_normalizeFactor += NORMALIZATION_REGAIN_STEP * rtDur / 10000000; - } - } - - if (m_normalizeFactor > m_nMaxNormFactor) { - m_normalizeFactor = m_nMaxNormFactor; - } - - sample_mul = m_normalizeFactor; - } - - if (m_boostFactor > 1.0) { - sample_mul *= m_boostFactor; - } - - if (sample_mul != 1.0) { - if (fPCM) { - if (wfe->wBitsPerSample == 8) { - gain_uint8(sample_mul, samples, (uint8_t*)pDataOut); - } else if (wfe->wBitsPerSample == 16) { - gain_int16(sample_mul, samples, (int16_t*)pDataOut); - } else if (wfe->wBitsPerSample == 24) { - gain_int24(sample_mul, samples, pDataOut); - } else if (wfe->wBitsPerSample == 32) { - gain_int32(sample_mul, samples, (int32_t*)pDataOut); - } - } else if (fFloat) { - if (wfe->wBitsPerSample == 32) { - gain_float(sample_mul, samples, (float*)pDataOut); - } else if (wfe->wBitsPerSample == 64) { - gain_double(sample_mul, samples, (double*)pDataOut); - } - } - } - } - - pOut->SetActualDataLength(lenout * bps * wfeout->nChannels); - - return S_OK; -} - -CMediaType CAudioSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer) -{ - CStreamSwitcherInputPin* pInPin = GetInputPin(); - CStreamSwitcherOutputPin* pOutPin = GetOutputPin(); - if (!pInPin || !pOutPin || ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) { - return __super::CreateNewOutputMediaType(mt, cbBuffer); - } - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; - - if (m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { - m_chs[wfe->nChannels - 1].RemoveAll(); - - DWORD mask = DWORD((__int64(1) << wfe->nChannels) - 1); - for (int i = 0; i < AS_MAX_CHANNELS; i++) { - if (m_pSpeakerToChannelMap[wfe->nChannels - 1][i]&mask) { - ChMap cm = {1u << i, m_pSpeakerToChannelMap[wfe->nChannels - 1][i]}; - m_chs[wfe->nChannels - 1].Add(cm); - } - } - - if (!m_chs[wfe->nChannels - 1].IsEmpty()) { - mt.ReallocFormatBuffer(sizeof(WAVEFORMATEXTENSIBLE)); - WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)mt.pbFormat; - wfex->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - wfex->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wfex->Samples.wValidBitsPerSample = wfe->wBitsPerSample; - wfex->SubFormat = - wfe->wFormatTag == WAVE_FORMAT_PCM ? KSDATAFORMAT_SUBTYPE_PCM : - wfe->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : - wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? ((WAVEFORMATEXTENSIBLE*)wfe)->SubFormat : - KSDATAFORMAT_SUBTYPE_PCM; // can't happen - - wfex->dwChannelMask = 0; - for (size_t i = 0; i < m_chs[wfe->nChannels - 1].GetCount(); i++) { - wfex->dwChannelMask |= m_chs[wfe->nChannels - 1][i].Speaker; - } - - wfex->Format.nChannels = (WORD)m_chs[wfe->nChannels - 1].GetCount(); - wfex->Format.nBlockAlign = wfex->Format.nChannels * wfex->Format.wBitsPerSample >> 3; - wfex->Format.nAvgBytesPerSec = wfex->Format.nBlockAlign * wfex->Format.nSamplesPerSec; - } - } - - WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mt.pbFormat; - - if (m_fDownSampleTo441) { - if (wfeout->nSamplesPerSec > 44100 && wfeout->wBitsPerSample <= 16) { - wfeout->nSamplesPerSec = 44100; - wfeout->nAvgBytesPerSec = wfeout->nBlockAlign * wfeout->nSamplesPerSec; - } - } - - int bps = wfe->wBitsPerSample >> 3; - int len = cbBuffer / (bps * wfe->nChannels); - int lenout = (UINT64)len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec; - cbBuffer = lenout * bps * wfeout->nChannels; - - // mt.lSampleSize = (ULONG)max(mt.lSampleSize, wfe->nAvgBytesPerSec * rtLen / 10000000i64); - // mt.lSampleSize = (mt.lSampleSize + (wfe->nBlockAlign-1)) & ~(wfe->nBlockAlign-1); - - return mt; -} - -void CAudioSwitcherFilter::OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut) -{ - const WAVEFORMATEX* wfe = (WAVEFORMATEX*)mtIn.pbFormat; - const WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mtOut.pbFormat; - - m_pResamplers.RemoveAll(); - for (int i = 0; i < wfeout->nChannels; i++) { - CAutoPtr pResampler; - pResampler.Attach(DEBUG_NEW AudioStreamResampler(wfeout->wBitsPerSample >> 3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true)); - m_pResamplers.Add(pResampler); - } - - TRACE(_T("CAudioSwitcherFilter::OnNewOutputMediaType\n")); - m_normalizeFactor = m_nMaxNormFactor; -} - -HRESULT CAudioSwitcherFilter::DeliverEndFlush() -{ - TRACE(_T("CAudioSwitcherFilter::DeliverEndFlush\n")); - - return __super::DeliverEndFlush(); -} - -HRESULT CAudioSwitcherFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - TRACE(_T("CAudioSwitcherFilter::DeliverNewSegment\n")); - - if (m_fNormalizeRecover && m_normalizeFactor < m_nMaxNormFactor) { - // regain after large jump - if (tStart == 0LL || std::abs(tStart - m_rtSegmentStart - m_rtNextStart) >= 600000000LL) { - m_normalizeFactor = std::max(m_normalizeFactor, std::max(1.0, m_nMaxNormFactor * 0.5)); - } - } - m_rtSegmentStart = tStart; - - return __super::DeliverNewSegment(tStart, tStop, dRate); -} - -// IAudioSwitcherFilter - -STDMETHODIMP CAudioSwitcherFilter::GetInputSpeakerConfig(DWORD* pdwChannelMask) -{ - CheckPointer(pdwChannelMask, E_POINTER); - - *pdwChannelMask = 0; - - CStreamSwitcherInputPin* pInPin = GetInputPin(); - if (!pInPin || !pInPin->IsConnected()) { - return E_UNEXPECTED; - } - - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; - - if (wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe; - *pdwChannelMask = wfex->dwChannelMask; - } else { - *pdwChannelMask = 0/*wfe->nChannels == 1 ? 4 : wfe->nChannels == 2 ? 3 : 0*/; - } - - return S_OK; -} - -STDMETHODIMP CAudioSwitcherFilter::GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) -{ - if (pfCustomChannelMapping) { - *pfCustomChannelMapping = m_fCustomChannelMapping; - } - memcpy(pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); - - return S_OK; -} - -STDMETHODIMP CAudioSwitcherFilter::SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) -{ - if (m_State == State_Stopped - || m_fCustomChannelMapping != fCustomChannelMapping - || memcmp(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap))) { - PauseGraph; - - CStreamSwitcherInputPin* pInput = GetInputPin(); - - SelectInput(nullptr); - - m_fCustomChannelMapping = fCustomChannelMapping; - memcpy(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); - - SelectInput(pInput); - - ResumeGraph; - } - - return S_OK; -} - -STDMETHODIMP_(int) CAudioSwitcherFilter::GetNumberOfInputChannels() -{ - CStreamSwitcherInputPin* pInPin = GetInputPin(); - return pInPin ? ((WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat)->nChannels : 0; -} - -STDMETHODIMP_(bool) CAudioSwitcherFilter::IsDownSamplingTo441Enabled() -{ - return m_fDownSampleTo441; -} - -STDMETHODIMP CAudioSwitcherFilter::EnableDownSamplingTo441(bool fEnable) -{ - if (m_fDownSampleTo441 != fEnable) { - PauseGraph; - m_fDownSampleTo441 = fEnable; - ResumeGraph; - } - - return S_OK; -} - -STDMETHODIMP_(REFERENCE_TIME) CAudioSwitcherFilter::GetAudioTimeShift() -{ - return m_rtAudioTimeShift; -} - -STDMETHODIMP CAudioSwitcherFilter::SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift) -{ - m_rtAudioTimeShift = rtAudioTimeShift; - return S_OK; -} - -// Deprecated -STDMETHODIMP CAudioSwitcherFilter::GetNormalizeBoost(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB) -{ - fNormalize = m_fNormalize; - fNormalizeRecover = m_fNormalizeRecover; - boost_dB = float(20.0 * log10(m_boostFactor)); - return S_OK; -} - -// Deprecated -STDMETHODIMP CAudioSwitcherFilter::SetNormalizeBoost(bool fNormalize, bool fNormalizeRecover, float boost_dB) -{ - if (m_fNormalize != fNormalize) { - m_normalizeFactor = m_nMaxNormFactor; - } - m_fNormalize = fNormalize; - m_fNormalizeRecover = fNormalizeRecover; - m_boostFactor = pow(10.0, boost_dB / 20.0); - return S_OK; -} - -STDMETHODIMP CAudioSwitcherFilter::GetNormalizeBoost2(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& boost) -{ - fNormalize = m_fNormalize; - nMaxNormFactor = UINT(100.0 * m_nMaxNormFactor + 0.5); - fNormalizeRecover = m_fNormalizeRecover; - boost = UINT(100.0 * m_boostFactor + 0.5) - 100; - return S_OK; -} - -STDMETHODIMP CAudioSwitcherFilter::SetNormalizeBoost2(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT boost) -{ - m_fNormalize = fNormalize; - m_nMaxNormFactor = nMaxNormFactor / 100.0; - m_fNormalizeRecover = fNormalizeRecover; - m_boostFactor = 1.0 + boost / 100.0; - if (m_fNormalize != fNormalize) { - m_normalizeFactor = m_nMaxNormFactor; - } - return S_OK; -} - -// IAMStreamSelect - -STDMETHODIMP CAudioSwitcherFilter::Enable(long lIndex, DWORD dwFlags) -{ - HRESULT hr = __super::Enable(lIndex, dwFlags); - if (S_OK == hr) { - m_normalizeFactor = m_nMaxNormFactor; - } - return hr; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include +#include "AudioSwitcher.h" +#include "Audio.h" +#include "../../../DSUtil/DSUtil.h" +#include "../../../DSUtil/AudioTools.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +#define NORMALIZATION_REGAIN_STEP 0.06 // +6%/s +#define NORMALIZATION_REGAIN_THRESHOLD 0.75 + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL} +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL} +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CAudioSwitcherFilter), AudioSwitcherName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CAudioSwitcherFilter +// + +CAudioSwitcherFilter::CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr) + : CStreamSwitcherFilter(lpunk, phr, __uuidof(this)) + , m_fCustomChannelMapping(false) + , m_fDownSampleTo441(false) + , m_rtAudioTimeShift(0) + , m_fNormalize(false) + , m_fNormalizeRecover(false) + , m_nMaxNormFactor(4.0) + , m_boostFactor(1.0) + , m_normalizeFactor(m_nMaxNormFactor) + , m_rtNextStart(0) + , m_rtNextStop(1) + , m_rtSegmentStart(0) +{ + ZeroMemory(m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); + + if (phr) { + if (FAILED(*phr)) { + return; + } else { + *phr = S_OK; + } + } +} + +STDMETHODIMP CAudioSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IAudioSwitcherFilter) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CAudioSwitcherFilter::CheckMediaType(const CMediaType* pmt) +{ + if (pmt->majortype == MEDIATYPE_Audio && pmt->formattype == FORMAT_WaveFormatEx && pmt->pbFormat) { + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pmt->pbFormat; + WORD wBitsPerSample = wfe->wBitsPerSample; + WORD wFormatTag = wfe->wFormatTag; + if (wfe->nChannels > 2 && wFormatTag != WAVE_FORMAT_EXTENSIBLE) { + return VFW_E_INVALIDMEDIATYPE; // iviaudio tries to fool us + } + if (wfe->nSamplesPerSec == 0) { + ASSERT(false); + return VFW_E_INVALIDMEDIATYPE; + } + if (wBitsPerSample == 8 || wBitsPerSample == 16 || wBitsPerSample == 24 || wBitsPerSample == 32) { + if (wFormatTag == WAVE_FORMAT_PCM || wFormatTag == WAVE_FORMAT_IEEE_FLOAT || wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF || wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + return S_OK; + } + } + } + return VFW_E_TYPE_NOT_ACCEPTED; +} + +template +__forceinline void mix(DWORD mask, int ch, int bps, BYTE* src, BYTE* dst) +{ + U sum = 0; + + for (int i = 0, j = ch; i < j; i++) { + if (mask & (1 << i)) { + sum += *(T*)&src[bps * i]; + } + } + + if (sum < Umin) { + sum = Umin; + } else if (sum > Umax) { + sum = Umax; + } + + *(T*)dst = (T)sum; +} + +template<> +__forceinline void mix(DWORD mask, int ch, int bps, BYTE* src, BYTE* dst) +{ + INT64 sum = 0; + + for (int i = 0, j = ch; i < j; i++) { + if (mask & (1 << i)) { + int tmp; + memcpy((BYTE*)&tmp + 1, &src[bps * i], 3); + sum += tmp >> 8; + } + } + + sum = std::min(std::max(sum, INT24_MIN), INT24_MAX); + + memcpy(dst, (BYTE*)&sum, 3); +} + +template +__forceinline void mix4(DWORD mask, BYTE* src, BYTE* dst) +{ + U sum = 0; + int bps = sizeof T; + + if (mask & (1 << 0)) { + sum += *(T*)&src[bps * 0]; + } + if (mask & (1 << 1)) { + sum += *(T*)&src[bps * 1]; + } + if (mask & (1 << 2)) { + sum += *(T*)&src[bps * 2]; + } + if (mask & (1 << 3)) { + sum += *(T*)&src[bps * 3]; + } + + if (sum < Umin) { + sum = Umin; + } else if (sum > Umax) { + sum = Umax; + } + + *(T*)dst = (T)sum; +} + +template +T clamp(double s, T smin, T smax) +{ + if (s < -1.0) { + s = -1.0; + } else if (s > 1.0) { + s = 1.0; + } + T t = (T)(s * smax); + if (t < smin) { + t = smin; + } else if (t > smax) { + t = smax; + } + return t; +} + +HRESULT CAudioSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + CStreamSwitcherInputPin* pInPin = GetInputPin(); + CStreamSwitcherOutputPin* pOutPin = GetOutputPin(); + if (!pInPin || !pOutPin) { + return __super::Transform(pIn, pOut); + } + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; + WAVEFORMATEX* wfeout = (WAVEFORMATEX*)pOutPin->CurrentMediaType().pbFormat; + WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe; + + int bps = wfe->wBitsPerSample >> 3; + + int len = pIn->GetActualDataLength() / (bps * wfe->nChannels); + if (len < 0 || wfe->nSamplesPerSec == 0 || !wfeout) { + return S_FALSE; + } + int lenout = (UINT64)len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec; + + REFERENCE_TIME rtStart, rtStop; + if (SUCCEEDED(pIn->GetTime(&rtStart, &rtStop))) { + rtStart += m_rtAudioTimeShift; + rtStop += m_rtAudioTimeShift; + pOut->SetTime(&rtStart, &rtStop); + + m_rtNextStart = rtStart; + m_rtNextStop = rtStop; + } else { + pOut->SetTime(&m_rtNextStart, &m_rtNextStop); + } + + REFERENCE_TIME rtDur = 10000000i64 * len / wfe->nSamplesPerSec; + + m_rtNextStart += rtDur; + m_rtNextStop += rtDur; + + if (m_normalizeFactor < 1.0 && pIn->IsDiscontinuity() == S_OK) { + m_normalizeFactor = std::max(1.0, m_nMaxNormFactor * 0.5); + } + + WORD tag = wfe->wFormatTag; + bool fPCM = tag == WAVE_FORMAT_PCM || tag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM; + bool fFloat = tag == WAVE_FORMAT_IEEE_FLOAT || tag == WAVE_FORMAT_EXTENSIBLE && wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + if (!fPCM && !fFloat) { + return __super::Transform(pIn, pOut); + } + + BYTE* pDataIn = nullptr; + BYTE* pDataOut = nullptr; + + HRESULT hr; + if (FAILED(hr = pIn->GetPointer(&pDataIn))) { + return hr; + } + if (FAILED(hr = pOut->GetPointer(&pDataOut))) { + return hr; + } + + if (!pDataIn || !pDataOut) { + return S_FALSE; + } + // len = 0 doesn't mean it's failed, return S_OK otherwise might screw the sound + if (len == 0) { + pOut->SetActualDataLength(0); + return S_OK; + } + + bool bDownSampleTo441 = (m_fDownSampleTo441 + && wfe->nSamplesPerSec > 44100 && wfeout->nSamplesPerSec == 44100 + && wfe->wBitsPerSample <= 16 && fPCM); + + if (bDownSampleTo441 && m_pResamplers.GetCount() < wfeout->nChannels) { + ASSERT(false); + m_pResamplers.RemoveAll(); + for (int i = 0; i < wfeout->nChannels; i++) { + CAutoPtr pResampler; + pResampler.Attach(DEBUG_NEW AudioStreamResampler(wfeout->wBitsPerSample >> 3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true)); + m_pResamplers.Add(pResampler); + } + } + + BYTE* pTmp = nullptr; + BYTE* pDst = nullptr; + if (bDownSampleTo441 && m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { + pDst = pTmp = DEBUG_NEW BYTE[size_t(len) * size_t(bps) * wfeout->nChannels]; + } else { + pDst = pDataOut; + } + + if (m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { + size_t channelsCount = m_chs[wfe->nChannels - 1].GetCount(); + ASSERT(channelsCount == 0 || wfeout->nChannels == channelsCount); + + int srcstep = bps * wfe->nChannels; + int dststep = bps * wfeout->nChannels; + int channels = wfe->nChannels; + + if (channelsCount > 0 && wfeout->nChannels == channelsCount) { + for (int i = 0; i < wfeout->nChannels; i++) { + DWORD mask = m_chs[wfe->nChannels - 1][i].Channel; + + BYTE* src = pDataIn; + BYTE* dst = &pDst[bps * i]; + + if (fPCM) { + if (wfe->wBitsPerSample == 8) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix(mask, channels, bps, src, dst); + } + } else if (wfe->wBitsPerSample == 16) { + if (wfe->nChannels != 4 || wfeout->nChannels != 4) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix(mask, channels, bps, src, dst); + } + } else { // most popular channels count + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix4(mask, src, dst); + } + } + } else if (wfe->wBitsPerSample == 24) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix(mask, channels, bps, src, dst); + } + } else if (wfe->wBitsPerSample == 32) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix(mask, channels, bps, src, dst); + } + } + } else if (fFloat) { + if (wfe->wBitsPerSample == 32) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix < float, double, -1, 1 > (mask, channels, bps, src, dst); + } + } else if (wfe->wBitsPerSample == 64) { + for (int k = 0; k < len; k++, src += srcstep, dst += dststep) { + mix < double, double, -1, 1 > (mask, channels, bps, src, dst); + } + } + } + } + } else { + ZeroMemory(pDataOut, pOut->GetSize()); + } + } else { + HRESULT hr2; + if (S_OK != (hr2 = __super::Transform(pIn, pOut))) { + return hr2; + } + } + + if (bDownSampleTo441) { + if (BYTE* buff = DEBUG_NEW BYTE[len * bps]) { + for (int ch = 0; ch < wfeout->nChannels; ch++) { + ZeroMemory(buff, len * bps); + + for (int i = 0; i < len; i++) { + memcpy(buff + i * bps, (char*)pDst + (ch + i * wfeout->nChannels)*bps, bps); + } + + m_pResamplers[ch]->Downsample(buff, len, buff, lenout); + + for (int i = 0; i < lenout; i++) { + memcpy((char*)pDataOut + (ch + i * wfeout->nChannels)*bps, buff + i * bps, bps); + } + } + + delete [] buff; + } + + delete [] pTmp; + } + + if (m_fNormalize || m_boostFactor > 1) { + size_t samples = size_t(lenout) * wfeout->nChannels; + double sample_mul = 1.0; + + if (m_fNormalize) { + double sample_max = 0.0; + + // calculate max peak + if (fPCM) { + int32_t maxpeak = 0; + if (wfe->wBitsPerSample == 8) { + for (size_t i = 0; i < samples; i++) { + int32_t peak = abs((int8_t)(pDataOut[i] ^ 0x80)); + if (peak > maxpeak) { + maxpeak = peak; + } + } + sample_max = (double)maxpeak / INT8_MAX; + } else if (wfe->wBitsPerSample == 16) { + for (size_t i = 0; i < samples; i++) { + int32_t peak = abs(((int16_t*)pDataOut)[i]); + if (peak > maxpeak) { + maxpeak = peak; + } + } + sample_max = (double)maxpeak / INT16_MAX; + } else if (wfe->wBitsPerSample == 24) { + for (size_t i = 0; i < samples; i++) { + int32_t peak = 0; + BYTE* p = (BYTE*)(&peak); + p[1] = pDataOut[i * 3]; + p[2] = pDataOut[i * 3 + 1]; + p[3] = pDataOut[i * 3 + 2]; + peak = abs(peak); + if (peak > maxpeak) { + maxpeak = peak; + } + } + sample_max = (double)maxpeak / INT32_MAX; + } else if (wfe->wBitsPerSample == 32) { + for (size_t i = 0; i < samples; i++) { + int32_t peak = abs(((int32_t*)pDataOut)[i]); + if (peak > maxpeak) { + maxpeak = peak; + } + } + sample_max = (double)maxpeak / INT32_MAX; + } + } else if (fFloat) { + if (wfe->wBitsPerSample == 32) { + for (size_t i = 0; i < samples; i++) { + double sample = (double)abs(((float*)pDataOut)[i]); + if (sample > sample_max) { + sample_max = sample; + } + } + } else if (wfe->wBitsPerSample == 64) { + for (size_t i = 0; i < samples; i++) { + double sample = (double)abs(((double*)pDataOut)[i]); + if (sample > sample_max) { + sample_max = sample; + } + } + } + } + + double normFact = 1.0 / sample_max; + if (m_normalizeFactor > normFact) { + m_normalizeFactor = normFact; + } else { + if (m_fNormalizeRecover) { + // we don't regain if we are too close of the maximum + if (sample_max * m_normalizeFactor < NORMALIZATION_REGAIN_THRESHOLD) { + m_normalizeFactor += NORMALIZATION_REGAIN_STEP * rtDur / 10000000; // the step is per second so we weight it with the duration + } + } else if (m_normalizeFactor < 0.8 && normFact >= 1.0) { + // recover from overflow situation (audio glitch?) + m_normalizeFactor += NORMALIZATION_REGAIN_STEP * rtDur / 10000000; + } + } + + if (m_normalizeFactor > m_nMaxNormFactor) { + m_normalizeFactor = m_nMaxNormFactor; + } + + sample_mul = m_normalizeFactor; + } + + if (m_boostFactor > 1.0) { + sample_mul *= m_boostFactor; + } + + if (sample_mul != 1.0) { + if (fPCM) { + if (wfe->wBitsPerSample == 8) { + gain_uint8(sample_mul, samples, (uint8_t*)pDataOut); + } else if (wfe->wBitsPerSample == 16) { + gain_int16(sample_mul, samples, (int16_t*)pDataOut); + } else if (wfe->wBitsPerSample == 24) { + gain_int24(sample_mul, samples, pDataOut); + } else if (wfe->wBitsPerSample == 32) { + gain_int32(sample_mul, samples, (int32_t*)pDataOut); + } + } else if (fFloat) { + if (wfe->wBitsPerSample == 32) { + gain_float(sample_mul, samples, (float*)pDataOut); + } else if (wfe->wBitsPerSample == 64) { + gain_double(sample_mul, samples, (double*)pDataOut); + } + } + } + } + + pOut->SetActualDataLength(lenout * bps * wfeout->nChannels); + + return S_OK; +} + +CMediaType CAudioSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer) +{ + CStreamSwitcherInputPin* pInPin = GetInputPin(); + CStreamSwitcherOutputPin* pOutPin = GetOutputPin(); + if (!pInPin || !pOutPin || ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3_SPDIF) { + return __super::CreateNewOutputMediaType(mt, cbBuffer); + } + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; + + if (m_fCustomChannelMapping && wfe->nChannels <= AS_MAX_CHANNELS) { + m_chs[wfe->nChannels - 1].RemoveAll(); + + DWORD mask = DWORD((__int64(1) << wfe->nChannels) - 1); + for (int i = 0; i < AS_MAX_CHANNELS; i++) { + if (m_pSpeakerToChannelMap[wfe->nChannels - 1][i]&mask) { + ChMap cm = {1u << i, m_pSpeakerToChannelMap[wfe->nChannels - 1][i]}; + m_chs[wfe->nChannels - 1].Add(cm); + } + } + + if (!m_chs[wfe->nChannels - 1].IsEmpty()) { + mt.ReallocFormatBuffer(sizeof(WAVEFORMATEXTENSIBLE)); + WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)mt.pbFormat; + wfex->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + wfex->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfex->Samples.wValidBitsPerSample = wfe->wBitsPerSample; + wfex->SubFormat = + wfe->wFormatTag == WAVE_FORMAT_PCM ? KSDATAFORMAT_SUBTYPE_PCM : + wfe->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : + wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE ? ((WAVEFORMATEXTENSIBLE*)wfe)->SubFormat : + KSDATAFORMAT_SUBTYPE_PCM; // can't happen + + wfex->dwChannelMask = 0; + for (size_t i = 0; i < m_chs[wfe->nChannels - 1].GetCount(); i++) { + wfex->dwChannelMask |= m_chs[wfe->nChannels - 1][i].Speaker; + } + + wfex->Format.nChannels = (WORD)m_chs[wfe->nChannels - 1].GetCount(); + wfex->Format.nBlockAlign = wfex->Format.nChannels * wfex->Format.wBitsPerSample >> 3; + wfex->Format.nAvgBytesPerSec = wfex->Format.nBlockAlign * wfex->Format.nSamplesPerSec; + } + } + + WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mt.pbFormat; + + if (m_fDownSampleTo441) { + if (wfeout->nSamplesPerSec > 44100 && wfeout->wBitsPerSample <= 16) { + wfeout->nSamplesPerSec = 44100; + wfeout->nAvgBytesPerSec = wfeout->nBlockAlign * wfeout->nSamplesPerSec; + } + } + + int bps = wfe->wBitsPerSample >> 3; + int len = cbBuffer / (bps * wfe->nChannels); + int lenout = (UINT64)len * wfeout->nSamplesPerSec / wfe->nSamplesPerSec; + cbBuffer = lenout * bps * wfeout->nChannels; + + // mt.lSampleSize = (ULONG)max(mt.lSampleSize, wfe->nAvgBytesPerSec * rtLen / 10000000i64); + // mt.lSampleSize = (mt.lSampleSize + (wfe->nBlockAlign-1)) & ~(wfe->nBlockAlign-1); + + return mt; +} + +void CAudioSwitcherFilter::OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut) +{ + const WAVEFORMATEX* wfe = (WAVEFORMATEX*)mtIn.pbFormat; + const WAVEFORMATEX* wfeout = (WAVEFORMATEX*)mtOut.pbFormat; + + m_pResamplers.RemoveAll(); + for (int i = 0; i < wfeout->nChannels; i++) { + CAutoPtr pResampler; + pResampler.Attach(DEBUG_NEW AudioStreamResampler(wfeout->wBitsPerSample >> 3, wfe->nSamplesPerSec, wfeout->nSamplesPerSec, true)); + m_pResamplers.Add(pResampler); + } + + TRACE(_T("CAudioSwitcherFilter::OnNewOutputMediaType\n")); + m_normalizeFactor = m_nMaxNormFactor; +} + +HRESULT CAudioSwitcherFilter::DeliverEndFlush() +{ + TRACE(_T("CAudioSwitcherFilter::DeliverEndFlush\n")); + + return __super::DeliverEndFlush(); +} + +HRESULT CAudioSwitcherFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + TRACE(_T("CAudioSwitcherFilter::DeliverNewSegment\n")); + + if (m_fNormalizeRecover && m_normalizeFactor < m_nMaxNormFactor) { + // regain after large jump + if (tStart == 0LL || std::abs(tStart - m_rtSegmentStart - m_rtNextStart) >= 600000000LL) { + m_normalizeFactor = std::max(m_normalizeFactor, std::max(1.0, m_nMaxNormFactor * 0.5)); + } + } + m_rtSegmentStart = tStart; + + return __super::DeliverNewSegment(tStart, tStop, dRate); +} + +// IAudioSwitcherFilter + +STDMETHODIMP CAudioSwitcherFilter::GetInputSpeakerConfig(DWORD* pdwChannelMask) +{ + CheckPointer(pdwChannelMask, E_POINTER); + + *pdwChannelMask = 0; + + CStreamSwitcherInputPin* pInPin = GetInputPin(); + if (!pInPin || !pInPin->IsConnected()) { + return E_UNEXPECTED; + } + + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat; + + if (wfe->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)wfe; + *pdwChannelMask = wfex->dwChannelMask; + } else { + *pdwChannelMask = 0/*wfe->nChannels == 1 ? 4 : wfe->nChannels == 2 ? 3 : 0*/; + } + + return S_OK; +} + +STDMETHODIMP CAudioSwitcherFilter::GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) +{ + if (pfCustomChannelMapping) { + *pfCustomChannelMapping = m_fCustomChannelMapping; + } + memcpy(pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); + + return S_OK; +} + +STDMETHODIMP CAudioSwitcherFilter::SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) +{ + if (m_State == State_Stopped + || m_fCustomChannelMapping != fCustomChannelMapping + || memcmp(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap))) { + PauseGraph; + + CStreamSwitcherInputPin* pInput = GetInputPin(); + + SelectInput(nullptr); + + m_fCustomChannelMapping = fCustomChannelMapping; + memcpy(m_pSpeakerToChannelMap, pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); + + SelectInput(pInput); + + ResumeGraph; + } + + return S_OK; +} + +STDMETHODIMP_(int) CAudioSwitcherFilter::GetNumberOfInputChannels() +{ + CStreamSwitcherInputPin* pInPin = GetInputPin(); + return pInPin ? ((WAVEFORMATEX*)pInPin->CurrentMediaType().pbFormat)->nChannels : 0; +} + +STDMETHODIMP_(bool) CAudioSwitcherFilter::IsDownSamplingTo441Enabled() +{ + return m_fDownSampleTo441; +} + +STDMETHODIMP CAudioSwitcherFilter::EnableDownSamplingTo441(bool fEnable) +{ + if (m_fDownSampleTo441 != fEnable) { + PauseGraph; + m_fDownSampleTo441 = fEnable; + ResumeGraph; + } + + return S_OK; +} + +STDMETHODIMP_(REFERENCE_TIME) CAudioSwitcherFilter::GetAudioTimeShift() +{ + return m_rtAudioTimeShift; +} + +STDMETHODIMP CAudioSwitcherFilter::SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift) +{ + m_rtAudioTimeShift = rtAudioTimeShift; + return S_OK; +} + +// Deprecated +STDMETHODIMP CAudioSwitcherFilter::GetNormalizeBoost(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB) +{ + fNormalize = m_fNormalize; + fNormalizeRecover = m_fNormalizeRecover; + boost_dB = float(20.0 * log10(m_boostFactor)); + return S_OK; +} + +// Deprecated +STDMETHODIMP CAudioSwitcherFilter::SetNormalizeBoost(bool fNormalize, bool fNormalizeRecover, float boost_dB) +{ + if (m_fNormalize != fNormalize) { + m_normalizeFactor = m_nMaxNormFactor; + } + m_fNormalize = fNormalize; + m_fNormalizeRecover = fNormalizeRecover; + m_boostFactor = pow(10.0, boost_dB / 20.0); + return S_OK; +} + +STDMETHODIMP CAudioSwitcherFilter::GetNormalizeBoost2(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& boost) +{ + fNormalize = m_fNormalize; + nMaxNormFactor = UINT(100.0 * m_nMaxNormFactor + 0.5); + fNormalizeRecover = m_fNormalizeRecover; + boost = UINT(100.0 * m_boostFactor + 0.5) - 100; + return S_OK; +} + +STDMETHODIMP CAudioSwitcherFilter::SetNormalizeBoost2(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT boost) +{ + m_fNormalize = fNormalize; + m_nMaxNormFactor = nMaxNormFactor / 100.0; + m_fNormalizeRecover = fNormalizeRecover; + m_boostFactor = 1.0 + boost / 100.0; + if (m_fNormalize != fNormalize) { + m_normalizeFactor = m_nMaxNormFactor; + } + return S_OK; +} + +// IAMStreamSelect + +STDMETHODIMP CAudioSwitcherFilter::Enable(long lIndex, DWORD dwFlags) +{ + HRESULT hr = __super::Enable(lIndex, dwFlags); + if (S_OK == hr) { + m_normalizeFactor = m_nMaxNormFactor; + } + return hr; +} diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.def b/src/filters/switcher/AudioSwitcher/AudioSwitcher.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.def +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.h b/src/filters/switcher/AudioSwitcher/AudioSwitcher.h index b7a00918b76..9d6957c1898 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.h +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.h @@ -1,104 +1,104 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include "StreamSwitcher.h" - -#define AudioSwitcherName L"MPC-HC AudioSwitcher" -#define AS_MAX_CHANNELS 18 - - -interface __declspec(uuid("CEDB2890-53AE-4231-91A3-B0AAFCD1DBDE")) - IAudioSwitcherFilter : - public IUnknown -{ - STDMETHOD(GetInputSpeakerConfig)(DWORD* pdwChannelMask) PURE; - STDMETHOD(GetSpeakerConfig)(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) PURE; - STDMETHOD(SetSpeakerConfig)(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) PURE; - STDMETHOD_(int, GetNumberOfInputChannels)() PURE; - STDMETHOD_(bool, IsDownSamplingTo441Enabled)() PURE; - STDMETHOD(EnableDownSamplingTo441)(bool fEnable) PURE; - STDMETHOD_(REFERENCE_TIME, GetAudioTimeShift)() PURE; - STDMETHOD(SetAudioTimeShift)(REFERENCE_TIME rtAudioTimeShift) PURE; - // Deprecated - STDMETHOD(GetNormalizeBoost)(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB) PURE; - // Deprecated - STDMETHOD(SetNormalizeBoost)(bool fNormalize, bool fNormalizeRecover, float boost_dB) PURE; - STDMETHOD(GetNormalizeBoost2)(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& nBoost) PURE; - STDMETHOD(SetNormalizeBoost2)(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT nBoost) PURE; -}; - -class AudioStreamResampler; - -class __declspec(uuid("18C16B08-6497-420e-AD14-22D21C2CEAB7")) - CAudioSwitcherFilter : public CStreamSwitcherFilter, public IAudioSwitcherFilter -{ - struct ChMap { - DWORD Speaker, Channel; - }; - CAtlArray m_chs[AS_MAX_CHANNELS]; - - bool m_fCustomChannelMapping; - DWORD m_pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]; - bool m_fDownSampleTo441; - REFERENCE_TIME m_rtAudioTimeShift; - CAutoPtrArray m_pResamplers; - bool m_fNormalize, m_fNormalizeRecover; - double m_nMaxNormFactor, m_boostFactor; - double m_normalizeFactor; - - REFERENCE_TIME m_rtNextStart, m_rtNextStop; - REFERENCE_TIME m_rtSegmentStart; - -public: - CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - CMediaType CreateNewOutputMediaType(CMediaType mt, long& cbBuffer); - void OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut); - - HRESULT DeliverEndFlush(); - HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - - // IAudioSwitcherFilter - STDMETHODIMP GetInputSpeakerConfig(DWORD* pdwChannelMask); - STDMETHODIMP GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]); - STDMETHODIMP SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]); - STDMETHODIMP_(int) GetNumberOfInputChannels(); - STDMETHODIMP_(bool) IsDownSamplingTo441Enabled(); - STDMETHODIMP EnableDownSamplingTo441(bool fEnable); - STDMETHODIMP_(REFERENCE_TIME) GetAudioTimeShift(); - STDMETHODIMP SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift); - // Deprecated - STDMETHODIMP GetNormalizeBoost(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB); - // Deprecated - STDMETHODIMP SetNormalizeBoost(bool fNormalize, bool fNormalizeRecover, float boost_dB); - STDMETHODIMP GetNormalizeBoost2(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& nBoost); - STDMETHODIMP SetNormalizeBoost2(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT nBoost); - - // IAMStreamSelect - STDMETHODIMP Enable(long lIndex, DWORD dwFlags); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include "StreamSwitcher.h" + +#define AudioSwitcherName L"MPC-HC AudioSwitcher" +#define AS_MAX_CHANNELS 18 + + +interface __declspec(uuid("CEDB2890-53AE-4231-91A3-B0AAFCD1DBDE")) + IAudioSwitcherFilter : + public IUnknown +{ + STDMETHOD(GetInputSpeakerConfig)(DWORD* pdwChannelMask) PURE; + STDMETHOD(GetSpeakerConfig)(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) PURE; + STDMETHOD(SetSpeakerConfig)(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]) PURE; + STDMETHOD_(int, GetNumberOfInputChannels)() PURE; + STDMETHOD_(bool, IsDownSamplingTo441Enabled)() PURE; + STDMETHOD(EnableDownSamplingTo441)(bool fEnable) PURE; + STDMETHOD_(REFERENCE_TIME, GetAudioTimeShift)() PURE; + STDMETHOD(SetAudioTimeShift)(REFERENCE_TIME rtAudioTimeShift) PURE; + // Deprecated + STDMETHOD(GetNormalizeBoost)(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB) PURE; + // Deprecated + STDMETHOD(SetNormalizeBoost)(bool fNormalize, bool fNormalizeRecover, float boost_dB) PURE; + STDMETHOD(GetNormalizeBoost2)(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& nBoost) PURE; + STDMETHOD(SetNormalizeBoost2)(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT nBoost) PURE; +}; + +class AudioStreamResampler; + +class __declspec(uuid("18C16B08-6497-420e-AD14-22D21C2CEAB7")) + CAudioSwitcherFilter : public CStreamSwitcherFilter, public IAudioSwitcherFilter +{ + struct ChMap { + DWORD Speaker, Channel; + }; + CAtlArray m_chs[AS_MAX_CHANNELS]; + + bool m_fCustomChannelMapping; + DWORD m_pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]; + bool m_fDownSampleTo441; + REFERENCE_TIME m_rtAudioTimeShift; + CAutoPtrArray m_pResamplers; + bool m_fNormalize, m_fNormalizeRecover; + double m_nMaxNormFactor, m_boostFactor; + double m_normalizeFactor; + + REFERENCE_TIME m_rtNextStart, m_rtNextStop; + REFERENCE_TIME m_rtSegmentStart; + +public: + CAudioSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + CMediaType CreateNewOutputMediaType(CMediaType mt, long& cbBuffer); + void OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut); + + HRESULT DeliverEndFlush(); + HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + // IAudioSwitcherFilter + STDMETHODIMP GetInputSpeakerConfig(DWORD* pdwChannelMask); + STDMETHODIMP GetSpeakerConfig(bool* pfCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]); + STDMETHODIMP SetSpeakerConfig(bool fCustomChannelMapping, DWORD pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]); + STDMETHODIMP_(int) GetNumberOfInputChannels(); + STDMETHODIMP_(bool) IsDownSamplingTo441Enabled(); + STDMETHODIMP EnableDownSamplingTo441(bool fEnable); + STDMETHODIMP_(REFERENCE_TIME) GetAudioTimeShift(); + STDMETHODIMP SetAudioTimeShift(REFERENCE_TIME rtAudioTimeShift); + // Deprecated + STDMETHODIMP GetNormalizeBoost(bool& fNormalize, bool& fNormalizeRecover, float& boost_dB); + // Deprecated + STDMETHODIMP SetNormalizeBoost(bool fNormalize, bool fNormalizeRecover, float boost_dB); + STDMETHODIMP GetNormalizeBoost2(bool& fNormalize, UINT& nMaxNormFactor, bool& fNormalizeRecover, UINT& nBoost); + STDMETHODIMP SetNormalizeBoost2(bool fNormalize, UINT nMaxNormFactor, bool fNormalizeRecover, UINT nBoost); + + // IAMStreamSelect + STDMETHODIMP Enable(long lIndex, DWORD dwFlags); +}; diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.rc b/src/filters/switcher/AudioSwitcher/AudioSwitcher.rc index b4c7b52f357..d9ae4e1f42a 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.rc +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "AudioSwitcher" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "AudioSwitcher" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "AudioSwitcher.ax" - VALUE "ProductName", "AudioSwitcher" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "AudioSwitcher" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "AudioSwitcher" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "AudioSwitcher.ax" + VALUE "ProductName", "AudioSwitcher" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj b/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj index 9df5e639df8..c3f3dde56c2 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj @@ -1,128 +1,128 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {D8DB3E7E-D50E-4EC3-A9B9-DAD18F5FE466} - AudioSwitcher - MFCProj - AudioSwitcher - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - Vfw32.lib;%(AdditionalDependencies) - AudioSwitcher.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - - Create - - - - - - - - - - - true - - - - - - - true - - - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {D8DB3E7E-D50E-4EC3-A9B9-DAD18F5FE466} + AudioSwitcher + MFCProj + AudioSwitcher + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + Vfw32.lib;%(AdditionalDependencies) + AudioSwitcher.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + + Create + + + + + + + + + + + true + + + + + + + true + + + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj.filters b/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj.filters index 689b8f22e10..0e4f0567c9d 100644 --- a/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj.filters +++ b/src/filters/switcher/AudioSwitcher/AudioSwitcher.vcxproj.filters @@ -1,57 +1,57 @@ - - - - - {5d72cb26-7cb5-4089-8afe-a1675cca05bd} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {fad8eff1-05e1-4e43-b055-d246fd3761a6} - h;hpp;hxx;hm;inl;inc - - - {706cf01d-dbd5-4702-985f-1c65f75baa5e} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {5d72cb26-7cb5-4089-8afe-a1675cca05bd} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {fad8eff1-05e1-4e43-b055-d246fd3761a6} + h;hpp;hxx;hm;inl;inc + + + {706cf01d-dbd5-4702-985f-1c65f75baa5e} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/switcher/AudioSwitcher/StreamSwitcher.cpp b/src/filters/switcher/AudioSwitcher/StreamSwitcher.cpp index 62c59c8eac6..2af29151f26 100644 --- a/src/filters/switcher/AudioSwitcher/StreamSwitcher.cpp +++ b/src/filters/switcher/AudioSwitcher/StreamSwitcher.cpp @@ -1,1640 +1,1640 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "StreamSwitcher.h" -#include "../../../DSUtil/DSUtil.h" -#include "../../../DSUtil/PathUtils.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -#define BLOCKSTREAM - -// -// CStreamSwitcherPassThru -// - -CStreamSwitcherPassThru::CStreamSwitcherPassThru(LPUNKNOWN pUnk, HRESULT* phr, CStreamSwitcherFilter* pFilter) - : CMediaPosition(NAME("CStreamSwitcherPassThru"), pUnk) - , m_pFilter(pFilter) -{ -} - -STDMETHODIMP CStreamSwitcherPassThru::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = nullptr; - - return - QI(IMediaSeeking) - CMediaPosition::NonDelegatingQueryInterface(riid, ppv); -} - -template -HRESULT GetPeer(CStreamSwitcherFilter* pFilter, T** ppT) -{ - *ppT = nullptr; - - CBasePin* pPin = pFilter->GetInputPin(); - if (!pPin) { - return E_NOTIMPL; - } - - CComPtr pConnected; - if (FAILED(pPin->ConnectedTo(&pConnected))) { - return E_NOTIMPL; - } - - if (CComQIPtr pT = pConnected) { - *ppT = pT.Detach(); - return S_OK; - } - - return E_NOTIMPL; -} - - -#define CallPeerSeeking(call) \ - CComPtr pMS; \ - if (FAILED(GetPeer(m_pFilter, &pMS))) \ - return E_NOTIMPL; \ - return pMS->##call; - -#define CallPeer(call) \ - CComPtr pMP; \ - if (FAILED(GetPeer(m_pFilter, &pMP))) \ - return E_NOTIMPL; \ - return pMP->##call; - -#define CallPeerSeekingAll(call) \ - HRESULT hr = E_NOTIMPL; \ - POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); \ - while (pos) { \ - CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); \ - CComPtr pConnected; \ - if (FAILED(pPin->ConnectedTo(&pConnected))) \ - continue; \ - if (CComQIPtr pMS = pConnected) { \ - HRESULT hr2 = pMS->call; \ - if (pPin == m_pFilter->GetInputPin()) \ - hr = hr2; \ - } \ - } \ - return hr; - -#define CallPeerAll(call) \ - HRESULT hr = E_NOTIMPL; \ - POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); \ - while (pos) { \ - CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); \ - CComPtr pConnected; \ - if (FAILED(pPin->ConnectedTo(&pConnected))) \ - continue; \ - if (CComQIPtr pMP = pConnected) { \ - HRESULT hr2 = pMP->call; \ - if (pPin == m_pFilter->GetInputPin()) \ - hr = hr2; \ - } \ - } \ - return hr; - - -// IMediaSeeking - -STDMETHODIMP CStreamSwitcherPassThru::GetCapabilities(DWORD* pCaps) -{ - CallPeerSeeking(GetCapabilities(pCaps)); -} - -STDMETHODIMP CStreamSwitcherPassThru::CheckCapabilities(DWORD* pCaps) -{ - CallPeerSeeking(CheckCapabilities(pCaps)); -} - -STDMETHODIMP CStreamSwitcherPassThru::IsFormatSupported(const GUID* pFormat) -{ - CallPeerSeeking(IsFormatSupported(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::QueryPreferredFormat(GUID* pFormat) -{ - CallPeerSeeking(QueryPreferredFormat(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::SetTimeFormat(const GUID* pFormat) -{ - CallPeerSeeking(SetTimeFormat(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetTimeFormat(GUID* pFormat) -{ - CallPeerSeeking(GetTimeFormat(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::IsUsingTimeFormat(const GUID* pFormat) -{ - CallPeerSeeking(IsUsingTimeFormat(pFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - CallPeerSeeking(ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat)); -} - -STDMETHODIMP CStreamSwitcherPassThru::SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, LONGLONG* pStop, DWORD StopFlags) -{ - CallPeerSeekingAll(SetPositions(pCurrent, CurrentFlags, pStop, StopFlags)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - CallPeerSeeking(GetPositions(pCurrent, pStop)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetCurrentPosition(LONGLONG* pCurrent) -{ - CallPeerSeeking(GetCurrentPosition(pCurrent)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetStopPosition(LONGLONG* pStop) -{ - CallPeerSeeking(GetStopPosition(pStop)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetDuration(LONGLONG* pDuration) -{ - CallPeerSeeking(GetDuration(pDuration)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetPreroll(LONGLONG* pllPreroll) -{ - CallPeerSeeking(GetPreroll(pllPreroll)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - CallPeerSeeking(GetAvailable(pEarliest, pLatest)); -} - -STDMETHODIMP CStreamSwitcherPassThru::GetRate(double* pdRate) -{ - CallPeerSeeking(GetRate(pdRate)); -} - -STDMETHODIMP CStreamSwitcherPassThru::SetRate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - CallPeerSeekingAll(SetRate(dRate)); -} - -// IMediaPosition - -STDMETHODIMP CStreamSwitcherPassThru::get_Duration(REFTIME* plength) -{ - CallPeer(get_Duration(plength)); -} - -STDMETHODIMP CStreamSwitcherPassThru::get_CurrentPosition(REFTIME* pllTime) -{ - CallPeer(get_CurrentPosition(pllTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::put_CurrentPosition(REFTIME llTime) -{ - CallPeerAll(put_CurrentPosition(llTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::get_StopTime(REFTIME* pllTime) -{ - CallPeer(get_StopTime(pllTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::put_StopTime(REFTIME llTime) -{ - CallPeerAll(put_StopTime(llTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::get_PrerollTime(REFTIME* pllTime) -{ - CallPeer(get_PrerollTime(pllTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::put_PrerollTime(REFTIME llTime) -{ - CallPeerAll(put_PrerollTime(llTime)); -} - -STDMETHODIMP CStreamSwitcherPassThru::get_Rate(double* pdRate) -{ - CallPeer(get_Rate(pdRate)); -} - -STDMETHODIMP CStreamSwitcherPassThru::put_Rate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - CallPeerAll(put_Rate(dRate)); -} - -STDMETHODIMP CStreamSwitcherPassThru::CanSeekForward(LONG* pCanSeekForward) -{ - CallPeer(CanSeekForward(pCanSeekForward)); -} - -STDMETHODIMP CStreamSwitcherPassThru::CanSeekBackward(LONG* pCanSeekBackward) -{ - CallPeer(CanSeekBackward(pCanSeekBackward)); -} - -// -// CStreamSwitcherAllocator -// - -CStreamSwitcherAllocator::CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr) - : CMemAllocator(NAME("CStreamSwitcherAllocator"), nullptr, phr) - , m_pPin(pPin) - , m_fMediaTypeChanged(false) -{ - ASSERT(phr); - ASSERT(pPin); -} - -#ifdef _DEBUG -CStreamSwitcherAllocator::~CStreamSwitcherAllocator() -{ - ASSERT(m_bCommitted == FALSE); -} -#endif - -STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingAddRef() -{ - return m_pPin->m_pFilter->AddRef(); -} - -STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingRelease() -{ - return m_pPin->m_pFilter->Release(); -} - -STDMETHODIMP CStreamSwitcherAllocator::GetBuffer( - IMediaSample** ppBuffer, - REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, - DWORD dwFlags) -{ - HRESULT hr = VFW_E_NOT_COMMITTED; - - if (!m_bCommitted) { - return hr; - } - /* - TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() + %x\n"), this); - m_pPin->m_evBlock.Wait(); - TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() - %x\n"), this); - */ - if (m_fMediaTypeChanged) { - if (!m_pPin || !m_pPin->m_pFilter) { - return hr; - } - - CStreamSwitcherOutputPin* pOut = (static_cast(m_pPin->m_pFilter))->GetOutputPin(); - if (!pOut || !pOut->CurrentAllocator()) { - return hr; - } - - ALLOCATOR_PROPERTIES Properties, Actual; - if (FAILED(pOut->CurrentAllocator()->GetProperties(&Actual))) { - return hr; - } - if (FAILED(GetProperties(&Properties))) { - return hr; - } - - if (!m_bCommitted || Properties.cbBuffer < Actual.cbBuffer) { - Properties.cbBuffer = Actual.cbBuffer; - if (FAILED(Decommit())) { - return hr; - } - if (FAILED(SetProperties(&Properties, &Actual))) { - return hr; - } - if (FAILED(Commit())) { - return hr; - } - ASSERT(Actual.cbBuffer >= Properties.cbBuffer); - if (Actual.cbBuffer < Properties.cbBuffer) { - return hr; - } - } - } - - hr = CMemAllocator::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags); - - if (m_fMediaTypeChanged && SUCCEEDED(hr)) { - (*ppBuffer)->SetMediaType(&m_mt); - m_fMediaTypeChanged = false; - } - - return hr; -} - -void CStreamSwitcherAllocator::NotifyMediaType(const CMediaType& mt) -{ - CopyMediaType(&m_mt, &mt); - m_fMediaTypeChanged = true; -} - - -// -// CStreamSwitcherInputPin -// - -CStreamSwitcherInputPin::CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName) - : CBaseInputPin(NAME("CStreamSwitcherInputPin"), pFilter, &pFilter->m_csState, phr, pName) - , m_Allocator(this, phr) - , m_bSampleSkipped(FALSE) - , m_bQualityChanged(FALSE) - , m_bUsingOwnAllocator(FALSE) - , m_evBlock(TRUE) - , m_fCanBlock(false) - , m_hNotifyEvent(nullptr) - , m_bFirstSampleReceived(false) -{ - m_bCanReconnectWhenActive = true; -} - -class __declspec(uuid("138130AF-A79B-45D5-B4AA-87697457BA87")) - NeroAudioDecoder {}; - -STDMETHODIMP CStreamSwitcherInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IStreamSwitcherInputPin) - IsConnected() && GetCLSID(GetFilterFromPin(GetConnected())) == __uuidof(NeroAudioDecoder) && QI(IPinConnection) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IPinConnection - -STDMETHODIMP CStreamSwitcherInputPin::DynamicQueryAccept(const AM_MEDIA_TYPE* pmt) -{ - return QueryAccept(pmt); -} - -STDMETHODIMP CStreamSwitcherInputPin::NotifyEndOfStream(HANDLE hNotifyEvent) -{ - if (m_hNotifyEvent) { - SetEvent(m_hNotifyEvent); - } - m_hNotifyEvent = hNotifyEvent; - return S_OK; -} - -STDMETHODIMP CStreamSwitcherInputPin::IsEndPin() -{ - return S_OK; -} - -STDMETHODIMP CStreamSwitcherInputPin::DynamicDisconnect() -{ - CAutoLock cAutoLock(&m_csReceive); - Disconnect(); - return S_OK; -} - -// IStreamSwitcherInputPin - -STDMETHODIMP_(bool) CStreamSwitcherInputPin::IsActive() -{ - // TODO: lock onto something here - return (this == (static_cast(m_pFilter))->GetInputPin()); -} - -// - -HRESULT CStreamSwitcherInputPin::QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt) -{ - HRESULT hr = S_OK; - - CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); - - if (pOut && pOut->IsConnected()) { - if (CComPtr pPC = pOut->CurrentPinConnection()) { - hr = pPC->DynamicQueryAccept(pmt); - if (hr == S_OK) { - return S_OK; - } - } - - hr = pOut->GetConnected()->QueryAccept(pmt); - } - - return hr; -} - -void CStreamSwitcherInputPin::Block(bool fBlock) -{ - if (fBlock) { - m_evBlock.Reset(); - } else { - m_evBlock.Set(); - } -} - -HRESULT CStreamSwitcherInputPin::InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample) -{ - if (!pInSample || !ppOutSample) { - return E_POINTER; - } - - CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); - ASSERT(pOut->GetConnected()); - - CComPtr pOutSample; - - DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; - - if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { - dwFlags |= AM_GBF_NOTASYNCPOINT; - } - - HRESULT hr = pOut->GetDeliveryBuffer(&pOutSample, - (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) ? &m_SampleProps.tStart : nullptr, - (m_SampleProps.dwSampleFlags & AM_SAMPLE_STOPVALID) ? &m_SampleProps.tStop : nullptr, - dwFlags); - - if (FAILED(hr)) { - return hr; - } - - if (!pOutSample) { - return E_FAIL; - } - - if (CComQIPtr pOutSample2 = pOutSample) { - AM_SAMPLE2_PROPERTIES OutProps; - EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps))); - OutProps.dwTypeSpecificFlags = m_SampleProps.dwTypeSpecificFlags; - OutProps.dwSampleFlags = - (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | - (m_SampleProps.dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); - - OutProps.tStart = m_SampleProps.tStart; - OutProps.tStop = m_SampleProps.tStop; - OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); - - pOutSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps); - if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - m_bSampleSkipped = FALSE; - } - } else { - if (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) { - pOutSample->SetTime(&m_SampleProps.tStart, &m_SampleProps.tStop); - } - - if (m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { - pOutSample->SetSyncPoint(TRUE); - } - - if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - pOutSample->SetDiscontinuity(TRUE); - m_bSampleSkipped = FALSE; - } - - LONGLONG MediaStart, MediaEnd; - if (pInSample->GetMediaTime(&MediaStart, &MediaEnd) == NOERROR) { - pOutSample->SetMediaTime(&MediaStart, &MediaEnd); - } - } - - *ppOutSample = pOutSample.Detach(); - - return S_OK; -} - -// pure virtual - -HRESULT CStreamSwitcherInputPin::CheckMediaType(const CMediaType* pmt) -{ - return (static_cast(m_pFilter))->CheckMediaType(pmt); -} - -// virtual - -HRESULT CStreamSwitcherInputPin::CheckConnect(IPin* pPin) -{ - return (IPin*)(static_cast(m_pFilter))->GetOutputPin() == pPin - ? E_FAIL - : __super::CheckConnect(pPin); -} - -HRESULT CStreamSwitcherInputPin::CompleteConnect(IPin* pReceivePin) -{ - HRESULT hr = __super::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - (static_cast(m_pFilter))->CompleteConnect(PINDIR_INPUT, this, pReceivePin); - - m_fCanBlock = false; - bool fForkedSomewhere = false; - - CStringW streamName; - CStringW pinName; - - IPin* pPin = (IPin*)this; - IBaseFilter* pBF = (IBaseFilter*)m_pFilter; - - pPin = GetUpStreamPin(pBF, pPin); - if (pPin) { - pBF = GetFilterFromPin(pPin); - } - while (pPin && pBF) { - if (IsSplitter(pBF)) { - pinName = GetPinName(pPin); - } - - CLSID clsid = GetCLSID(pBF); - if (clsid == CLSID_AviSplitter || clsid == CLSID_OggSplitter) { - m_fCanBlock = true; - } - - int nIn, nOut, nInC, nOutC; - CountPins(pBF, nIn, nOut, nInC, nOutC); - fForkedSomewhere = fForkedSomewhere || nIn > 1 || nOut > 1; - - DWORD cStreams = 0; - CStringW streamSSName; - if (CComQIPtr pSSF = pBF) { - hr = pSSF->Count(&cStreams); - if (SUCCEEDED(hr)) { - for (int i = 0; i < (int)cStreams; i++) { - CComHeapPtr pszNameSS; - AM_MEDIA_TYPE* pmt = nullptr; - LCID lcid = 0; - - hr = pSSF->Info(i, &pmt, nullptr, &lcid, nullptr, &pszNameSS, nullptr, nullptr); - if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { - m_pSSF = pSSF; - DeleteMediaType(pmt); - streamSSName = pszNameSS; - break; - } - DeleteMediaType(pmt); - } - } - } - - if (CComQIPtr pFSF = pBF) { - CComHeapPtr fileName; - AM_MEDIA_TYPE mt; - - if (SUCCEEDED(pFSF->GetCurFile(&fileName, &mt)) && fileName) { - streamName = fileName; - if (streamName.Find(L"googlevideo.com") > 0 || (PathUtils::IsURL(streamName) && streamName.GetLength() > 50)) { //we don't like these URLs - streamName = streamSSName; - if (streamName.GetLength() <= 0) { - streamName = L"Online Audio Stream"; - } - } else { - streamName.Replace('\\', '/'); - CStringW fn = streamName.Mid(streamName.ReverseFind('/') + 1); - if (!fn.IsEmpty()) { - streamName = fn; - } - - // Haali & LAVFSplitter return only one "Audio" pin name, cause CMainFrame::OnInitMenuPopup lookup find the wrong popmenu, - // add space at the end to prevent this, internal filter never return "Audio" only. - if (!pinName.IsEmpty()) { - streamName = pinName + L" "; - } - } - - WCHAR* pName = DEBUG_NEW WCHAR[streamName.GetLength() + 1]; - if (pName) { - wcscpy_s(pName, streamName.GetLength() + 1, streamName); - if (m_pName) { - delete[] m_pName; - } - m_pName = pName; - if (cStreams == 1) { // Simple external track, no need to use the info from IAMStreamSelect - m_pSSF.Release(); - } - } - } - - break; - } - - pPin = GetFirstPin(pBF); - - pPin = GetUpStreamPin(pBF, pPin); - if (pPin) { - pBF = GetFilterFromPin(pPin); - } - } - - if (!fForkedSomewhere) { - m_fCanBlock = true; - } - - m_hNotifyEvent = nullptr; - - return S_OK; -} - -HRESULT CStreamSwitcherInputPin::Active() -{ - Block(!IsActive()); - - return __super::Active(); -} - -HRESULT CStreamSwitcherInputPin::Inactive() -{ - Block(false); - - return __super::Inactive(); -} - -// IPin - -STDMETHODIMP CStreamSwitcherInputPin::QueryAccept(const AM_MEDIA_TYPE* pmt) -{ - HRESULT hr = __super::QueryAccept(pmt); - if (S_OK != hr) { - return hr; - } - - return QueryAcceptDownstream(pmt); -} - -STDMETHODIMP CStreamSwitcherInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) -{ - // FIXME: this locked up once - // CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csReceive); - - HRESULT hr; - if (S_OK != (hr = QueryAcceptDownstream(pmt))) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - - if (m_Connected && m_Connected != pConnector) { - return VFW_E_ALREADY_CONNECTED; - } - - SAFE_RELEASE(m_Connected); - - return SUCCEEDED(__super::ReceiveConnection(pConnector, pmt)) ? S_OK : E_FAIL; -} - -STDMETHODIMP CStreamSwitcherInputPin::GetAllocator(IMemAllocator** ppAllocator) -{ - CheckPointer(ppAllocator, E_POINTER); - - if (m_pAllocator == nullptr) { - (m_pAllocator = &m_Allocator)->AddRef(); - } - - (*ppAllocator = m_pAllocator)->AddRef(); - - return NOERROR; -} - -STDMETHODIMP CStreamSwitcherInputPin::NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly) -{ - HRESULT hr = __super::NotifyAllocator(pAllocator, bReadOnly); - if (FAILED(hr)) { - return hr; - } - - m_bUsingOwnAllocator = (pAllocator == (IMemAllocator*)&m_Allocator); - - return S_OK; -} - -STDMETHODIMP CStreamSwitcherInputPin::BeginFlush() -{ - CAutoLock cAutoLock(&(static_cast(m_pFilter))->m_csState); - - HRESULT hr; - - CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); - - CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); - if (!IsConnected() || !pOut || !pOut->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - if (FAILED(hr = __super::BeginFlush())) { - return hr; - } - - return IsActive() ? pSSF->DeliverBeginFlush() : (Block(false), S_OK); -} - -STDMETHODIMP CStreamSwitcherInputPin::EndFlush() -{ - CAutoLock cAutoLock(&(static_cast(m_pFilter))->m_csState); - - HRESULT hr; - - CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); - - CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); - if (!IsConnected() || !pOut || !pOut->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - if (FAILED(hr = __super::EndFlush())) { - return hr; - } - - return IsActive() ? pSSF->DeliverEndFlush() : (Block(true), S_OK); -} - -STDMETHODIMP CStreamSwitcherInputPin::EndOfStream() -{ - CAutoLock cAutoLock(&m_csReceive); - - CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); - - CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); - if (!IsConnected() || !pOut || !pOut->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - if (m_hNotifyEvent) { - SetEvent(m_hNotifyEvent), m_hNotifyEvent = nullptr; - return S_OK; - } - - if (!m_bFirstSampleReceived) { - pSSF->Stop(); - } - return IsActive() ? pSSF->DeliverEndOfStream() : S_OK; -} - -// IMemInputPin - -STDMETHODIMP CStreamSwitcherInputPin::Receive(IMediaSample* pSample) -{ - m_bFirstSampleReceived = true; - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { - const CMediaType mt(*pmt); - DeleteMediaType(pmt), pmt = nullptr; - SetMediaType(&mt); - } - - // DAMN!!!!!! this doesn't work if the stream we are blocking - // shares the same thread with another stream, mpeg splitters - // are usually like that. Our nicely built up multithreaded - // strategy is useless because of this, ARRRRRRGHHHHHH. - -#ifdef BLOCKSTREAM - if (m_fCanBlock) { - m_evBlock.Wait(); - } -#endif - - if (!IsActive()) { -#ifdef BLOCKSTREAM - if (m_fCanBlock) { - return S_FALSE; - } -#endif - - TRACE(_T("&^$#@ : a stupid fix for this stupid problem\n")); - //Sleep(32); - return E_FAIL; // a stupid fix for this stupid problem - } - - CAutoLock cAutoLock(&m_csReceive); - - CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); - ASSERT(pOut->GetConnected()); - - HRESULT hr = __super::Receive(pSample); - if (S_OK != hr) { - return hr; - } - - if (m_SampleProps.dwStreamId != AM_STREAM_MEDIA) { - return pOut->Deliver(pSample); - } - - // - - ALLOCATOR_PROPERTIES props, actual; - m_pAllocator->GetProperties(&props); - IMemAllocator* cur_alloc = pOut->CurrentAllocator(); - if (!cur_alloc) { - ASSERT(false); - return E_FAIL; - } - cur_alloc->GetProperties(&actual); - - REFERENCE_TIME rtStart = 0, rtStop = 0; - if (S_OK == pSample->GetTime(&rtStart, &rtStop)) { - // - } - - long cbBuffer = pSample->GetActualDataLength(); - - CMediaType mtOut = m_mt; - mtOut = (static_cast(m_pFilter))->CreateNewOutputMediaType(mtOut, cbBuffer); - - bool fTypeChanged = false; - - if (mtOut != pOut->CurrentMediaType() || cbBuffer > actual.cbBuffer) { - fTypeChanged = true; - - m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED/*|AM_SAMPLE_DATADISCONTINUITY|AM_SAMPLE_TIMEDISCONTINUITY*/; - - if (props.cBuffers < 8 && mtOut.majortype == MEDIATYPE_Audio) { - props.cBuffers = 8; - } - - props.cbBuffer = cbBuffer; - - if (actual.cbAlign != props.cbAlign - || actual.cbPrefix != props.cbPrefix - || actual.cBuffers < props.cBuffers - || actual.cbBuffer < props.cbBuffer) { - pOut->DeliverBeginFlush(); - pOut->DeliverEndFlush(); - pOut->CurrentAllocator()->Decommit(); - pOut->CurrentAllocator()->SetProperties(&props, &actual); - pOut->CurrentAllocator()->Commit(); - } - } - - CComPtr pOutSample; - if (FAILED(InitializeOutputSample(pSample, &pOutSample))) { - return E_FAIL; - } - - pmt = nullptr; - if (SUCCEEDED(pOutSample->GetMediaType(&pmt)) && pmt) { - const CMediaType mt(*pmt); - DeleteMediaType(pmt), pmt = nullptr; - // TODO - ASSERT(0); - } - - if (fTypeChanged) { - pOut->SetMediaType(&mtOut); - (static_cast(m_pFilter))->OnNewOutputMediaType(m_mt, mtOut); - pOutSample->SetMediaType(&mtOut); - } - - // Transform - - hr = (static_cast(m_pFilter))->Transform(pSample, pOutSample); - - if (S_OK == hr) { - hr = pOut->Deliver(pOutSample); - m_bSampleSkipped = FALSE; - } else if (S_FALSE == hr) { - hr = S_OK; - pOutSample = nullptr; - m_bSampleSkipped = TRUE; - - if (!m_bQualityChanged) { - m_pFilter->NotifyEvent(EC_QUALITY_CHANGE, 0, 0); - m_bQualityChanged = TRUE; - } - } - - return hr; -} - -STDMETHODIMP CStreamSwitcherInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - if (!IsConnected() || !IsActive()) { - return S_OK; - } - - CAutoLock cAutoLock(&m_csReceive); - - CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); - - CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); - if (!pOut || !pOut->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - return pSSF->DeliverNewSegment(tStart, tStop, dRate); -} - -// -// CStreamSwitcherOutputPin -// - -CStreamSwitcherOutputPin::CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr) - : CBaseOutputPin(NAME("CStreamSwitcherOutputPin"), pFilter, &pFilter->m_csState, phr, L"Out") -{ - // m_bCanReconnectWhenActive = true; -} - -STDMETHODIMP CStreamSwitcherOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - ValidateReadWritePtr(ppv, sizeof(PVOID)); - *ppv = nullptr; - - if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { - if (m_pStreamSwitcherPassThru == nullptr) { - HRESULT hr = S_OK; - m_pStreamSwitcherPassThru = (IUnknown*)(INonDelegatingUnknown*) - DEBUG_NEW CStreamSwitcherPassThru(GetOwner(), &hr, static_cast(m_pFilter)); - - if (!m_pStreamSwitcherPassThru) { - return E_OUTOFMEMORY; - } - if (FAILED(hr)) { - return hr; - } - } - - return m_pStreamSwitcherPassThru->QueryInterface(riid, ppv); - } - /* - else if (riid == IID_IStreamBuilder) - { - return GetInterface((IStreamBuilder*)this, ppv); - } - */ - return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CStreamSwitcherOutputPin::QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt) -{ - HRESULT hr = S_FALSE; - - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - - if (pIn && pIn->IsConnected() && (pIn->IsUsingOwnAllocator() || pIn->CurrentMediaType() == *pmt)) { - if (CComQIPtr pPinTo = pIn->GetConnected()) { - if (S_OK != (hr = pPinTo->QueryAccept(pmt))) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } else { - return E_FAIL; - } - } - - return hr; -} - -// pure virtual - -HRESULT CStreamSwitcherOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - if (!pIn || !pIn->IsConnected()) { - return E_UNEXPECTED; - } - - CComPtr pAllocatorIn; - pIn->GetAllocator(&pAllocatorIn); - if (!pAllocatorIn) { - return E_UNEXPECTED; - } - - HRESULT hr; - if (FAILED(hr = pAllocatorIn->GetProperties(pProperties))) { - return hr; - } - - if (pProperties->cBuffers < 8 && pIn->CurrentMediaType().majortype == MEDIATYPE_Audio) { - pProperties->cBuffers = 8; - } - - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -// virtual - -class __declspec(uuid("AEFA5024-215A-4FC7-97A4-1043C86FD0B8")) - MatrixMixer {}; - -HRESULT CStreamSwitcherOutputPin::CheckConnect(IPin* pPin) -{ - CComPtr pBF = GetFilterFromPin(pPin); - - return - IsAudioWaveRenderer(pBF) || GetCLSID(pBF) == __uuidof(MatrixMixer) - ? __super::CheckConnect(pPin) - : E_FAIL; - - // return CComQIPtr(pPin) ? CBaseOutputPin::CheckConnect(pPin) : E_NOINTERFACE; - // return CBaseOutputPin::CheckConnect(pPin); -} - -HRESULT CStreamSwitcherOutputPin::BreakConnect() -{ - m_pPinConnection = nullptr; - return __super::BreakConnect(); -} - -HRESULT CStreamSwitcherOutputPin::CompleteConnect(IPin* pReceivePin) -{ - m_pPinConnection = CComQIPtr(pReceivePin); - HRESULT hr = __super::CompleteConnect(pReceivePin); - - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - CMediaType mt; - if (SUCCEEDED(hr) && pIn && pIn->IsConnected() - && SUCCEEDED(pIn->GetConnected()->ConnectionMediaType(&mt)) && m_mt != mt) { - if (pIn->GetConnected()->QueryAccept(&m_mt) == S_OK) { - hr = m_pFilter->ReconnectPin(pIn->GetConnected(), &m_mt); - } else { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } - } - - return hr; -} - -HRESULT CStreamSwitcherOutputPin::CheckMediaType(const CMediaType* pmt) -{ - return (static_cast(m_pFilter))->CheckMediaType(pmt); -} - -HRESULT CStreamSwitcherOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - if (!pIn || !pIn->IsConnected()) { - return E_UNEXPECTED; - } - - CComPtr pEM; - if (FAILED(pIn->GetConnected()->EnumMediaTypes(&pEM))) { - return VFW_S_NO_MORE_ITEMS; - } - - if (iPosition > 0 && FAILED(pEM->Skip(iPosition))) { - return VFW_S_NO_MORE_ITEMS; - } - - AM_MEDIA_TYPE* tmp = nullptr; - if (S_OK != pEM->Next(1, &tmp, nullptr) || !tmp) { - return VFW_S_NO_MORE_ITEMS; - } - - CopyMediaType(pmt, tmp); - DeleteMediaType(tmp); - /* - if (iPosition < 0) return E_INVALIDARG; - if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; - - CopyMediaType(pmt, &pIn->CurrentMediaType()); - */ - return S_OK; -} - -// IPin - -STDMETHODIMP CStreamSwitcherOutputPin::QueryAccept(const AM_MEDIA_TYPE* pmt) -{ - HRESULT hr = __super::QueryAccept(pmt); - if (S_OK != hr) { - return hr; - } - - return QueryAcceptUpstream(pmt); -} - -// IQualityControl - -STDMETHODIMP CStreamSwitcherOutputPin::Notify(IBaseFilter* pSender, Quality q) -{ - CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); - if (!pIn || !pIn->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - return pIn->PassNotify(q); -} - -// IStreamBuilder - -STDMETHODIMP CStreamSwitcherOutputPin::Render(IPin* ppinOut, IGraphBuilder* pGraph) -{ - CComPtr pBF; - pBF.CoCreateInstance(CLSID_DSoundRender); - if (!pBF || FAILED(pGraph->AddFilter(pBF, L"Default DirectSound Device"))) { - return E_FAIL; - } - - if (FAILED(pGraph->ConnectDirect(ppinOut, GetFirstDisconnectedPin(pBF, PINDIR_INPUT), nullptr))) { - pGraph->RemoveFilter(pBF); - return E_FAIL; - } - - return S_OK; -} - -STDMETHODIMP CStreamSwitcherOutputPin::Backout(IPin* ppinOut, IGraphBuilder* pGraph) -{ - return S_OK; -} - -// -// CStreamSwitcherFilter -// - -CStreamSwitcherFilter::CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) - : CBaseFilter(NAME("CStreamSwitcherFilter"), lpunk, &m_csState, clsid) - , m_pInput(nullptr) - , m_pOutput(nullptr) -{ - if (phr) { - *phr = S_OK; - } - - HRESULT hr = S_OK; - - do { - CAutoPtr pInput; - CAutoPtr pOutput; - - hr = S_OK; - pInput.Attach(DEBUG_NEW CStreamSwitcherInputPin(this, &hr, L"Channel 1")); - if (!pInput || FAILED(hr)) { - break; - } - - hr = S_OK; - pOutput.Attach(DEBUG_NEW CStreamSwitcherOutputPin(this, &hr)); - if (!pOutput || FAILED(hr)) { - break; - } - - CAutoLock cAutoLock(&m_csPins); - - m_pInputs.AddHead(m_pInput = pInput.Detach()); - m_pOutput = pOutput.Detach(); - - return; - } while (false); - - if (phr) { - *phr = E_FAIL; - } -} - -CStreamSwitcherFilter::~CStreamSwitcherFilter() -{ - CAutoLock cAutoLock(&m_csPins); - - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - delete m_pInputs.GetNext(pos); - } - m_pInputs.RemoveAll(); - m_pInput = nullptr; - - delete m_pOutput; - m_pOutput = nullptr; -} - -STDMETHODIMP CStreamSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IAMStreamSelect) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// - -int CStreamSwitcherFilter::GetPinCount() -{ - CAutoLock cAutoLock(&m_csPins); - - return (1 + (int)m_pInputs.GetCount()); -} - -CBasePin* CStreamSwitcherFilter::GetPin(int n) -{ - CAutoLock cAutoLock(&m_csPins); - - if (n < 0 || n >= GetPinCount()) { - return nullptr; - } else if (n == 0) { - return m_pOutput; - } else { - return m_pInputs.GetAt(m_pInputs.FindIndex(n - 1)); - } -} - -int CStreamSwitcherFilter::GetConnectedInputPinCount() -{ - CAutoLock cAutoLock(&m_csPins); - - int nConnected = 0; - POSITION pos = m_pInputs.GetHeadPosition(); - - while (pos) { - if (m_pInputs.GetNext(pos)->IsConnected()) { - nConnected++; - } - } - - return nConnected; -} - -CStreamSwitcherInputPin* CStreamSwitcherFilter::GetConnectedInputPin(int n) -{ - if (n >= 0) { - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos); - if (pPin->IsConnected()) { - if (n == 0) { - return pPin; - } - n--; - } - } - } - - return nullptr; -} - -CStreamSwitcherInputPin* CStreamSwitcherFilter::GetInputPin() -{ - return m_pInput; -} - -CStreamSwitcherOutputPin* CStreamSwitcherFilter::GetOutputPin() -{ - return m_pOutput; -} - -// - -HRESULT CStreamSwitcherFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin) -{ - if (dir == PINDIR_INPUT) { - CAutoLock cAutoLock(&m_csPins); - - int nConnected = GetConnectedInputPinCount(); - - if (nConnected == 1) { - m_pInput = static_cast(pPin); - } - - if ((size_t)nConnected == m_pInputs.GetCount()) { - CStringW name; - name.Format(L"Channel %ld", ++m_PinVersion); - - HRESULT hr = S_OK; - CStreamSwitcherInputPin* pInputPin = DEBUG_NEW CStreamSwitcherInputPin(this, &hr, name); - if (!pInputPin || FAILED(hr)) { - delete pInputPin; - return E_FAIL; - } - m_pInputs.AddTail(pInputPin); - } - } - - return S_OK; -} - -// this should be very thread safe, I hope it is, it must be... :) - -void CStreamSwitcherFilter::SelectInput(CStreamSwitcherInputPin* pInput) -{ - // make sure no input thinks it is active - m_pInput = nullptr; - - // release blocked GetBuffer in our own allocator & block all Receive - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos); - pPin->Block(false); - // a few Receive calls can arrive here, but since m_pInput == nullptr neighter of them gets delivered - pPin->Block(true); - } - - // this will let waiting GetBuffer() calls go on inside our Receive() - if (m_pOutput) { - m_pOutput->DeliverBeginFlush(); - m_pOutput->DeliverEndFlush(); - } - - if (!pInput) { - return; - } - - // set new input - m_pInput = pInput; - - // let it go - m_pInput->Block(false); -} - -// - -HRESULT CStreamSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - BYTE* pDataIn = nullptr; - BYTE* pDataOut = nullptr; - - HRESULT hr; - if (FAILED(hr = pIn->GetPointer(&pDataIn))) { - return hr; - } - if (FAILED(hr = pOut->GetPointer(&pDataOut))) { - return hr; - } - - long len = pIn->GetActualDataLength(); - long size = pOut->GetSize(); - - if (!pDataIn || !pDataOut /*|| len > size || len <= 0*/) { - return S_FALSE; // FIXME - } - - memcpy(pDataOut, pDataIn, std::min(len, size)); - pOut->SetActualDataLength(std::min(len, size)); - - return S_OK; -} - -CMediaType CStreamSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer) -{ - return mt; -} - -HRESULT CStreamSwitcherFilter::DeliverEndOfStream() -{ - return m_pOutput ? m_pOutput->DeliverEndOfStream() : E_FAIL; -} - -HRESULT CStreamSwitcherFilter::DeliverBeginFlush() -{ - return m_pOutput ? m_pOutput->DeliverBeginFlush() : E_FAIL; -} - -HRESULT CStreamSwitcherFilter::DeliverEndFlush() -{ - return m_pOutput ? m_pOutput->DeliverEndFlush() : E_FAIL; -} - -HRESULT CStreamSwitcherFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - return m_pOutput ? m_pOutput->DeliverNewSegment(tStart, tStop, dRate) : E_FAIL; -} - -// IAMStreamSelect - -STDMETHODIMP CStreamSwitcherFilter::Count(DWORD* pcStreams) -{ - CheckPointer(pcStreams, E_POINTER); - - CAutoLock cAutoLock(&m_csPins); - - *pcStreams = 0; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos) { - CStreamSwitcherInputPin* pInputPin = m_pInputs.GetNext(pos); - - if (pInputPin->IsConnected()) { - if (CComPtr pSSF = pInputPin->GetStreamSelectionFilter()) { - DWORD cStreams = 0; - HRESULT hr = pSSF->Count(&cStreams); - if (SUCCEEDED(hr)) { - for (int i = 0; i < (int)cStreams; i++) { - AM_MEDIA_TYPE* pmt = nullptr; - hr = pSSF->Info(i, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { - (*pcStreams)++; - } - DeleteMediaType(pmt); - } - } - } else { - (*pcStreams)++; - } - } - } - - return S_OK; -} - -STDMETHODIMP CStreamSwitcherFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) -{ - CAutoLock cAutoLock(&m_csPins); - - IUnknown* pObject = nullptr; - bool bFound = false; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos && !bFound) { - CStreamSwitcherInputPin* pInputPin = m_pInputs.GetNext(pos); - - if (pInputPin->IsConnected()) { - if (CComPtr pSSF = pInputPin->GetStreamSelectionFilter()) { - DWORD cStreams = 0; - HRESULT hr = pSSF->Count(&cStreams); - if (SUCCEEDED(hr)) { - for (int i = 0; i < (int)cStreams; i++) { - AM_MEDIA_TYPE* pmt = nullptr; - DWORD dwFlags; - LPWSTR pszName = nullptr; - hr = pSSF->Info(i, &pmt, &dwFlags, plcid, nullptr, &pszName, nullptr, nullptr); - if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { - if (lIndex == 0) { - bFound = true; - pObject = pSSF; - - if (ppmt) { - *ppmt = pmt; - } else { - DeleteMediaType(pmt); - } - - if (pdwFlags) { - *pdwFlags = (m_pInput == pInputPin) ? dwFlags : 0; - } - - if (pdwGroup) { - *pdwGroup = 1; - } - - if (ppszName) { - *ppszName = pszName; - } else { - CoTaskMemFree(pszName); - } - - break; - } else { - lIndex--; - } - } - DeleteMediaType(pmt); - CoTaskMemFree(pszName); - } - } - } else if (lIndex == 0) { - bFound = true; - - if (ppmt) { - bool found = false; - CComPtr pPinUpstream; - if (SUCCEEDED(m_pInput->ConnectedTo(&pPinUpstream)) && pPinUpstream) { - // find audio input pin of upstream filter - if (CComQIPtr pBF = GetFilterFromPin(pPinUpstream)) { - BeginEnumPins(pBF, pEP, pPin) { - CMediaTypeEx mt; - PIN_DIRECTION dir; - if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (mt.majortype == MEDIATYPE_Audio) { - *ppmt = CreateMediaType(&mt); - found = true; - break; - } - } - } - EndEnumPins; - } - } - if (!found) { - *ppmt = CreateMediaType(&m_pInput->CurrentMediaType()); - } - } - - if (pdwFlags) { - *pdwFlags = (m_pInput == pInputPin) ? AMSTREAMSELECTINFO_EXCLUSIVE : 0; - } - - if (plcid) { - *plcid = 0; - } - - if (pdwGroup) { - *pdwGroup = 1; - } - - if (ppszName) { - *ppszName = (WCHAR*)CoTaskMemAlloc((wcslen(pInputPin->Name()) + 1) * sizeof(WCHAR)); - if (*ppszName) { - wcscpy_s(*ppszName, wcslen(pInputPin->Name()) + 1, pInputPin->Name()); - } - } - } else { - lIndex--; - } - } - } - - if (!bFound) { - return E_INVALIDARG; - } - - if (ppObject) { - *ppObject = pObject; - if (pObject) { - pObject->AddRef(); - } - } - - if (ppUnk) { - *ppUnk = nullptr; - } - - return S_OK; -} - -STDMETHODIMP CStreamSwitcherFilter::Enable(long lIndex, DWORD dwFlags) -{ - if (dwFlags != AMSTREAMSELECTENABLE_ENABLE) { - return E_NOTIMPL; - } - - PauseGraph; - - bool bFound = false; - int i = 0; - CStreamSwitcherInputPin* pNewInputPin = nullptr; - POSITION pos = m_pInputs.GetHeadPosition(); - while (pos && !bFound) { - pNewInputPin = m_pInputs.GetNext(pos); - - if (pNewInputPin->IsConnected()) { - if (CComPtr pSSF = pNewInputPin->GetStreamSelectionFilter()) { - DWORD cStreams = 0; - HRESULT hr = pSSF->Count(&cStreams); - if (SUCCEEDED(hr)) { - for (i = 0; i < (int)cStreams; i++) { - AM_MEDIA_TYPE* pmt = nullptr; - hr = pSSF->Info(i, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { - if (lIndex == 0) { - bFound = true; - DeleteMediaType(pmt); - break; - } else { - lIndex--; - } - } - DeleteMediaType(pmt); - } - } - } else if (lIndex == 0) { - bFound = true; - } else { - lIndex--; - } - } - } - - if (!bFound) { - return E_INVALIDARG; - } - - SelectInput(pNewInputPin); - - if (CComPtr pSSF = pNewInputPin->GetStreamSelectionFilter()) { - pSSF->Enable(i, dwFlags); - } - - ResumeGraph; - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "StreamSwitcher.h" +#include "../../../DSUtil/DSUtil.h" +#include "../../../DSUtil/PathUtils.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +#define BLOCKSTREAM + +// +// CStreamSwitcherPassThru +// + +CStreamSwitcherPassThru::CStreamSwitcherPassThru(LPUNKNOWN pUnk, HRESULT* phr, CStreamSwitcherFilter* pFilter) + : CMediaPosition(NAME("CStreamSwitcherPassThru"), pUnk) + , m_pFilter(pFilter) +{ +} + +STDMETHODIMP CStreamSwitcherPassThru::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = nullptr; + + return + QI(IMediaSeeking) + CMediaPosition::NonDelegatingQueryInterface(riid, ppv); +} + +template +HRESULT GetPeer(CStreamSwitcherFilter* pFilter, T** ppT) +{ + *ppT = nullptr; + + CBasePin* pPin = pFilter->GetInputPin(); + if (!pPin) { + return E_NOTIMPL; + } + + CComPtr pConnected; + if (FAILED(pPin->ConnectedTo(&pConnected))) { + return E_NOTIMPL; + } + + if (CComQIPtr pT = pConnected) { + *ppT = pT.Detach(); + return S_OK; + } + + return E_NOTIMPL; +} + + +#define CallPeerSeeking(call) \ + CComPtr pMS; \ + if (FAILED(GetPeer(m_pFilter, &pMS))) \ + return E_NOTIMPL; \ + return pMS->##call; + +#define CallPeer(call) \ + CComPtr pMP; \ + if (FAILED(GetPeer(m_pFilter, &pMP))) \ + return E_NOTIMPL; \ + return pMP->##call; + +#define CallPeerSeekingAll(call) \ + HRESULT hr = E_NOTIMPL; \ + POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); \ + while (pos) { \ + CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); \ + CComPtr pConnected; \ + if (FAILED(pPin->ConnectedTo(&pConnected))) \ + continue; \ + if (CComQIPtr pMS = pConnected) { \ + HRESULT hr2 = pMS->call; \ + if (pPin == m_pFilter->GetInputPin()) \ + hr = hr2; \ + } \ + } \ + return hr; + +#define CallPeerAll(call) \ + HRESULT hr = E_NOTIMPL; \ + POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); \ + while (pos) { \ + CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); \ + CComPtr pConnected; \ + if (FAILED(pPin->ConnectedTo(&pConnected))) \ + continue; \ + if (CComQIPtr pMP = pConnected) { \ + HRESULT hr2 = pMP->call; \ + if (pPin == m_pFilter->GetInputPin()) \ + hr = hr2; \ + } \ + } \ + return hr; + + +// IMediaSeeking + +STDMETHODIMP CStreamSwitcherPassThru::GetCapabilities(DWORD* pCaps) +{ + CallPeerSeeking(GetCapabilities(pCaps)); +} + +STDMETHODIMP CStreamSwitcherPassThru::CheckCapabilities(DWORD* pCaps) +{ + CallPeerSeeking(CheckCapabilities(pCaps)); +} + +STDMETHODIMP CStreamSwitcherPassThru::IsFormatSupported(const GUID* pFormat) +{ + CallPeerSeeking(IsFormatSupported(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::QueryPreferredFormat(GUID* pFormat) +{ + CallPeerSeeking(QueryPreferredFormat(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::SetTimeFormat(const GUID* pFormat) +{ + CallPeerSeeking(SetTimeFormat(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetTimeFormat(GUID* pFormat) +{ + CallPeerSeeking(GetTimeFormat(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::IsUsingTimeFormat(const GUID* pFormat) +{ + CallPeerSeeking(IsUsingTimeFormat(pFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + CallPeerSeeking(ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat)); +} + +STDMETHODIMP CStreamSwitcherPassThru::SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, LONGLONG* pStop, DWORD StopFlags) +{ + CallPeerSeekingAll(SetPositions(pCurrent, CurrentFlags, pStop, StopFlags)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + CallPeerSeeking(GetPositions(pCurrent, pStop)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetCurrentPosition(LONGLONG* pCurrent) +{ + CallPeerSeeking(GetCurrentPosition(pCurrent)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetStopPosition(LONGLONG* pStop) +{ + CallPeerSeeking(GetStopPosition(pStop)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetDuration(LONGLONG* pDuration) +{ + CallPeerSeeking(GetDuration(pDuration)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetPreroll(LONGLONG* pllPreroll) +{ + CallPeerSeeking(GetPreroll(pllPreroll)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + CallPeerSeeking(GetAvailable(pEarliest, pLatest)); +} + +STDMETHODIMP CStreamSwitcherPassThru::GetRate(double* pdRate) +{ + CallPeerSeeking(GetRate(pdRate)); +} + +STDMETHODIMP CStreamSwitcherPassThru::SetRate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + CallPeerSeekingAll(SetRate(dRate)); +} + +// IMediaPosition + +STDMETHODIMP CStreamSwitcherPassThru::get_Duration(REFTIME* plength) +{ + CallPeer(get_Duration(plength)); +} + +STDMETHODIMP CStreamSwitcherPassThru::get_CurrentPosition(REFTIME* pllTime) +{ + CallPeer(get_CurrentPosition(pllTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::put_CurrentPosition(REFTIME llTime) +{ + CallPeerAll(put_CurrentPosition(llTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::get_StopTime(REFTIME* pllTime) +{ + CallPeer(get_StopTime(pllTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::put_StopTime(REFTIME llTime) +{ + CallPeerAll(put_StopTime(llTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::get_PrerollTime(REFTIME* pllTime) +{ + CallPeer(get_PrerollTime(pllTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::put_PrerollTime(REFTIME llTime) +{ + CallPeerAll(put_PrerollTime(llTime)); +} + +STDMETHODIMP CStreamSwitcherPassThru::get_Rate(double* pdRate) +{ + CallPeer(get_Rate(pdRate)); +} + +STDMETHODIMP CStreamSwitcherPassThru::put_Rate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + CallPeerAll(put_Rate(dRate)); +} + +STDMETHODIMP CStreamSwitcherPassThru::CanSeekForward(LONG* pCanSeekForward) +{ + CallPeer(CanSeekForward(pCanSeekForward)); +} + +STDMETHODIMP CStreamSwitcherPassThru::CanSeekBackward(LONG* pCanSeekBackward) +{ + CallPeer(CanSeekBackward(pCanSeekBackward)); +} + +// +// CStreamSwitcherAllocator +// + +CStreamSwitcherAllocator::CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr) + : CMemAllocator(NAME("CStreamSwitcherAllocator"), nullptr, phr) + , m_pPin(pPin) + , m_fMediaTypeChanged(false) +{ + ASSERT(phr); + ASSERT(pPin); +} + +#ifdef _DEBUG +CStreamSwitcherAllocator::~CStreamSwitcherAllocator() +{ + ASSERT(m_bCommitted == FALSE); +} +#endif + +STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingAddRef() +{ + return m_pPin->m_pFilter->AddRef(); +} + +STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingRelease() +{ + return m_pPin->m_pFilter->Release(); +} + +STDMETHODIMP CStreamSwitcherAllocator::GetBuffer( + IMediaSample** ppBuffer, + REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, + DWORD dwFlags) +{ + HRESULT hr = VFW_E_NOT_COMMITTED; + + if (!m_bCommitted) { + return hr; + } + /* + TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() + %x\n"), this); + m_pPin->m_evBlock.Wait(); + TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() - %x\n"), this); + */ + if (m_fMediaTypeChanged) { + if (!m_pPin || !m_pPin->m_pFilter) { + return hr; + } + + CStreamSwitcherOutputPin* pOut = (static_cast(m_pPin->m_pFilter))->GetOutputPin(); + if (!pOut || !pOut->CurrentAllocator()) { + return hr; + } + + ALLOCATOR_PROPERTIES Properties, Actual; + if (FAILED(pOut->CurrentAllocator()->GetProperties(&Actual))) { + return hr; + } + if (FAILED(GetProperties(&Properties))) { + return hr; + } + + if (!m_bCommitted || Properties.cbBuffer < Actual.cbBuffer) { + Properties.cbBuffer = Actual.cbBuffer; + if (FAILED(Decommit())) { + return hr; + } + if (FAILED(SetProperties(&Properties, &Actual))) { + return hr; + } + if (FAILED(Commit())) { + return hr; + } + ASSERT(Actual.cbBuffer >= Properties.cbBuffer); + if (Actual.cbBuffer < Properties.cbBuffer) { + return hr; + } + } + } + + hr = CMemAllocator::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags); + + if (m_fMediaTypeChanged && SUCCEEDED(hr)) { + (*ppBuffer)->SetMediaType(&m_mt); + m_fMediaTypeChanged = false; + } + + return hr; +} + +void CStreamSwitcherAllocator::NotifyMediaType(const CMediaType& mt) +{ + CopyMediaType(&m_mt, &mt); + m_fMediaTypeChanged = true; +} + + +// +// CStreamSwitcherInputPin +// + +CStreamSwitcherInputPin::CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName) + : CBaseInputPin(NAME("CStreamSwitcherInputPin"), pFilter, &pFilter->m_csState, phr, pName) + , m_Allocator(this, phr) + , m_bSampleSkipped(FALSE) + , m_bQualityChanged(FALSE) + , m_bUsingOwnAllocator(FALSE) + , m_evBlock(TRUE) + , m_fCanBlock(false) + , m_hNotifyEvent(nullptr) + , m_bFirstSampleReceived(false) +{ + m_bCanReconnectWhenActive = true; +} + +class __declspec(uuid("138130AF-A79B-45D5-B4AA-87697457BA87")) + NeroAudioDecoder {}; + +STDMETHODIMP CStreamSwitcherInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IStreamSwitcherInputPin) + IsConnected() && GetCLSID(GetFilterFromPin(GetConnected())) == __uuidof(NeroAudioDecoder) && QI(IPinConnection) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IPinConnection + +STDMETHODIMP CStreamSwitcherInputPin::DynamicQueryAccept(const AM_MEDIA_TYPE* pmt) +{ + return QueryAccept(pmt); +} + +STDMETHODIMP CStreamSwitcherInputPin::NotifyEndOfStream(HANDLE hNotifyEvent) +{ + if (m_hNotifyEvent) { + SetEvent(m_hNotifyEvent); + } + m_hNotifyEvent = hNotifyEvent; + return S_OK; +} + +STDMETHODIMP CStreamSwitcherInputPin::IsEndPin() +{ + return S_OK; +} + +STDMETHODIMP CStreamSwitcherInputPin::DynamicDisconnect() +{ + CAutoLock cAutoLock(&m_csReceive); + Disconnect(); + return S_OK; +} + +// IStreamSwitcherInputPin + +STDMETHODIMP_(bool) CStreamSwitcherInputPin::IsActive() +{ + // TODO: lock onto something here + return (this == (static_cast(m_pFilter))->GetInputPin()); +} + +// + +HRESULT CStreamSwitcherInputPin::QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt) +{ + HRESULT hr = S_OK; + + CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); + + if (pOut && pOut->IsConnected()) { + if (CComPtr pPC = pOut->CurrentPinConnection()) { + hr = pPC->DynamicQueryAccept(pmt); + if (hr == S_OK) { + return S_OK; + } + } + + hr = pOut->GetConnected()->QueryAccept(pmt); + } + + return hr; +} + +void CStreamSwitcherInputPin::Block(bool fBlock) +{ + if (fBlock) { + m_evBlock.Reset(); + } else { + m_evBlock.Set(); + } +} + +HRESULT CStreamSwitcherInputPin::InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample) +{ + if (!pInSample || !ppOutSample) { + return E_POINTER; + } + + CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); + ASSERT(pOut->GetConnected()); + + CComPtr pOutSample; + + DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; + + if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { + dwFlags |= AM_GBF_NOTASYNCPOINT; + } + + HRESULT hr = pOut->GetDeliveryBuffer(&pOutSample, + (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) ? &m_SampleProps.tStart : nullptr, + (m_SampleProps.dwSampleFlags & AM_SAMPLE_STOPVALID) ? &m_SampleProps.tStop : nullptr, + dwFlags); + + if (FAILED(hr)) { + return hr; + } + + if (!pOutSample) { + return E_FAIL; + } + + if (CComQIPtr pOutSample2 = pOutSample) { + AM_SAMPLE2_PROPERTIES OutProps; + EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps))); + OutProps.dwTypeSpecificFlags = m_SampleProps.dwTypeSpecificFlags; + OutProps.dwSampleFlags = + (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | + (m_SampleProps.dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); + + OutProps.tStart = m_SampleProps.tStart; + OutProps.tStop = m_SampleProps.tStop; + OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); + + pOutSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps); + if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + m_bSampleSkipped = FALSE; + } + } else { + if (m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) { + pOutSample->SetTime(&m_SampleProps.tStart, &m_SampleProps.tStop); + } + + if (m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { + pOutSample->SetSyncPoint(TRUE); + } + + if (m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + pOutSample->SetDiscontinuity(TRUE); + m_bSampleSkipped = FALSE; + } + + LONGLONG MediaStart, MediaEnd; + if (pInSample->GetMediaTime(&MediaStart, &MediaEnd) == NOERROR) { + pOutSample->SetMediaTime(&MediaStart, &MediaEnd); + } + } + + *ppOutSample = pOutSample.Detach(); + + return S_OK; +} + +// pure virtual + +HRESULT CStreamSwitcherInputPin::CheckMediaType(const CMediaType* pmt) +{ + return (static_cast(m_pFilter))->CheckMediaType(pmt); +} + +// virtual + +HRESULT CStreamSwitcherInputPin::CheckConnect(IPin* pPin) +{ + return (IPin*)(static_cast(m_pFilter))->GetOutputPin() == pPin + ? E_FAIL + : __super::CheckConnect(pPin); +} + +HRESULT CStreamSwitcherInputPin::CompleteConnect(IPin* pReceivePin) +{ + HRESULT hr = __super::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + (static_cast(m_pFilter))->CompleteConnect(PINDIR_INPUT, this, pReceivePin); + + m_fCanBlock = false; + bool fForkedSomewhere = false; + + CStringW streamName; + CStringW pinName; + + IPin* pPin = (IPin*)this; + IBaseFilter* pBF = (IBaseFilter*)m_pFilter; + + pPin = GetUpStreamPin(pBF, pPin); + if (pPin) { + pBF = GetFilterFromPin(pPin); + } + while (pPin && pBF) { + if (IsSplitter(pBF)) { + pinName = GetPinName(pPin); + } + + CLSID clsid = GetCLSID(pBF); + if (clsid == CLSID_AviSplitter || clsid == CLSID_OggSplitter) { + m_fCanBlock = true; + } + + int nIn, nOut, nInC, nOutC; + CountPins(pBF, nIn, nOut, nInC, nOutC); + fForkedSomewhere = fForkedSomewhere || nIn > 1 || nOut > 1; + + DWORD cStreams = 0; + CStringW streamSSName; + if (CComQIPtr pSSF = pBF) { + hr = pSSF->Count(&cStreams); + if (SUCCEEDED(hr)) { + for (int i = 0; i < (int)cStreams; i++) { + CComHeapPtr pszNameSS; + AM_MEDIA_TYPE* pmt = nullptr; + LCID lcid = 0; + + hr = pSSF->Info(i, &pmt, nullptr, &lcid, nullptr, &pszNameSS, nullptr, nullptr); + if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { + m_pSSF = pSSF; + DeleteMediaType(pmt); + streamSSName = pszNameSS; + break; + } + DeleteMediaType(pmt); + } + } + } + + if (CComQIPtr pFSF = pBF) { + CComHeapPtr fileName; + AM_MEDIA_TYPE mt; + + if (SUCCEEDED(pFSF->GetCurFile(&fileName, &mt)) && fileName) { + streamName = fileName; + if (streamName.Find(L"googlevideo.com") > 0 || (PathUtils::IsURL(streamName) && streamName.GetLength() > 50)) { //we don't like these URLs + streamName = streamSSName; + if (streamName.GetLength() <= 0) { + streamName = L"Online Audio Stream"; + } + } else { + streamName.Replace('\\', '/'); + CStringW fn = streamName.Mid(streamName.ReverseFind('/') + 1); + if (!fn.IsEmpty()) { + streamName = fn; + } + + // Haali & LAVFSplitter return only one "Audio" pin name, cause CMainFrame::OnInitMenuPopup lookup find the wrong popmenu, + // add space at the end to prevent this, internal filter never return "Audio" only. + if (!pinName.IsEmpty()) { + streamName = pinName + L" "; + } + } + + WCHAR* pName = DEBUG_NEW WCHAR[streamName.GetLength() + 1]; + if (pName) { + wcscpy_s(pName, streamName.GetLength() + 1, streamName); + if (m_pName) { + delete[] m_pName; + } + m_pName = pName; + if (cStreams == 1) { // Simple external track, no need to use the info from IAMStreamSelect + m_pSSF.Release(); + } + } + } + + break; + } + + pPin = GetFirstPin(pBF); + + pPin = GetUpStreamPin(pBF, pPin); + if (pPin) { + pBF = GetFilterFromPin(pPin); + } + } + + if (!fForkedSomewhere) { + m_fCanBlock = true; + } + + m_hNotifyEvent = nullptr; + + return S_OK; +} + +HRESULT CStreamSwitcherInputPin::Active() +{ + Block(!IsActive()); + + return __super::Active(); +} + +HRESULT CStreamSwitcherInputPin::Inactive() +{ + Block(false); + + return __super::Inactive(); +} + +// IPin + +STDMETHODIMP CStreamSwitcherInputPin::QueryAccept(const AM_MEDIA_TYPE* pmt) +{ + HRESULT hr = __super::QueryAccept(pmt); + if (S_OK != hr) { + return hr; + } + + return QueryAcceptDownstream(pmt); +} + +STDMETHODIMP CStreamSwitcherInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) +{ + // FIXME: this locked up once + // CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csReceive); + + HRESULT hr; + if (S_OK != (hr = QueryAcceptDownstream(pmt))) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + + if (m_Connected && m_Connected != pConnector) { + return VFW_E_ALREADY_CONNECTED; + } + + SAFE_RELEASE(m_Connected); + + return SUCCEEDED(__super::ReceiveConnection(pConnector, pmt)) ? S_OK : E_FAIL; +} + +STDMETHODIMP CStreamSwitcherInputPin::GetAllocator(IMemAllocator** ppAllocator) +{ + CheckPointer(ppAllocator, E_POINTER); + + if (m_pAllocator == nullptr) { + (m_pAllocator = &m_Allocator)->AddRef(); + } + + (*ppAllocator = m_pAllocator)->AddRef(); + + return NOERROR; +} + +STDMETHODIMP CStreamSwitcherInputPin::NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly) +{ + HRESULT hr = __super::NotifyAllocator(pAllocator, bReadOnly); + if (FAILED(hr)) { + return hr; + } + + m_bUsingOwnAllocator = (pAllocator == (IMemAllocator*)&m_Allocator); + + return S_OK; +} + +STDMETHODIMP CStreamSwitcherInputPin::BeginFlush() +{ + CAutoLock cAutoLock(&(static_cast(m_pFilter))->m_csState); + + HRESULT hr; + + CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); + + CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); + if (!IsConnected() || !pOut || !pOut->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + if (FAILED(hr = __super::BeginFlush())) { + return hr; + } + + return IsActive() ? pSSF->DeliverBeginFlush() : (Block(false), S_OK); +} + +STDMETHODIMP CStreamSwitcherInputPin::EndFlush() +{ + CAutoLock cAutoLock(&(static_cast(m_pFilter))->m_csState); + + HRESULT hr; + + CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); + + CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); + if (!IsConnected() || !pOut || !pOut->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + if (FAILED(hr = __super::EndFlush())) { + return hr; + } + + return IsActive() ? pSSF->DeliverEndFlush() : (Block(true), S_OK); +} + +STDMETHODIMP CStreamSwitcherInputPin::EndOfStream() +{ + CAutoLock cAutoLock(&m_csReceive); + + CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); + + CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); + if (!IsConnected() || !pOut || !pOut->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + if (m_hNotifyEvent) { + SetEvent(m_hNotifyEvent), m_hNotifyEvent = nullptr; + return S_OK; + } + + if (!m_bFirstSampleReceived) { + pSSF->Stop(); + } + return IsActive() ? pSSF->DeliverEndOfStream() : S_OK; +} + +// IMemInputPin + +STDMETHODIMP CStreamSwitcherInputPin::Receive(IMediaSample* pSample) +{ + m_bFirstSampleReceived = true; + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { + const CMediaType mt(*pmt); + DeleteMediaType(pmt), pmt = nullptr; + SetMediaType(&mt); + } + + // DAMN!!!!!! this doesn't work if the stream we are blocking + // shares the same thread with another stream, mpeg splitters + // are usually like that. Our nicely built up multithreaded + // strategy is useless because of this, ARRRRRRGHHHHHH. + +#ifdef BLOCKSTREAM + if (m_fCanBlock) { + m_evBlock.Wait(); + } +#endif + + if (!IsActive()) { +#ifdef BLOCKSTREAM + if (m_fCanBlock) { + return S_FALSE; + } +#endif + + TRACE(_T("&^$#@ : a stupid fix for this stupid problem\n")); + //Sleep(32); + return E_FAIL; // a stupid fix for this stupid problem + } + + CAutoLock cAutoLock(&m_csReceive); + + CStreamSwitcherOutputPin* pOut = (static_cast(m_pFilter))->GetOutputPin(); + ASSERT(pOut->GetConnected()); + + HRESULT hr = __super::Receive(pSample); + if (S_OK != hr) { + return hr; + } + + if (m_SampleProps.dwStreamId != AM_STREAM_MEDIA) { + return pOut->Deliver(pSample); + } + + // + + ALLOCATOR_PROPERTIES props, actual; + m_pAllocator->GetProperties(&props); + IMemAllocator* cur_alloc = pOut->CurrentAllocator(); + if (!cur_alloc) { + ASSERT(false); + return E_FAIL; + } + cur_alloc->GetProperties(&actual); + + REFERENCE_TIME rtStart = 0, rtStop = 0; + if (S_OK == pSample->GetTime(&rtStart, &rtStop)) { + // + } + + long cbBuffer = pSample->GetActualDataLength(); + + CMediaType mtOut = m_mt; + mtOut = (static_cast(m_pFilter))->CreateNewOutputMediaType(mtOut, cbBuffer); + + bool fTypeChanged = false; + + if (mtOut != pOut->CurrentMediaType() || cbBuffer > actual.cbBuffer) { + fTypeChanged = true; + + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED/*|AM_SAMPLE_DATADISCONTINUITY|AM_SAMPLE_TIMEDISCONTINUITY*/; + + if (props.cBuffers < 8 && mtOut.majortype == MEDIATYPE_Audio) { + props.cBuffers = 8; + } + + props.cbBuffer = cbBuffer; + + if (actual.cbAlign != props.cbAlign + || actual.cbPrefix != props.cbPrefix + || actual.cBuffers < props.cBuffers + || actual.cbBuffer < props.cbBuffer) { + pOut->DeliverBeginFlush(); + pOut->DeliverEndFlush(); + pOut->CurrentAllocator()->Decommit(); + pOut->CurrentAllocator()->SetProperties(&props, &actual); + pOut->CurrentAllocator()->Commit(); + } + } + + CComPtr pOutSample; + if (FAILED(InitializeOutputSample(pSample, &pOutSample))) { + return E_FAIL; + } + + pmt = nullptr; + if (SUCCEEDED(pOutSample->GetMediaType(&pmt)) && pmt) { + const CMediaType mt(*pmt); + DeleteMediaType(pmt), pmt = nullptr; + // TODO + ASSERT(0); + } + + if (fTypeChanged) { + pOut->SetMediaType(&mtOut); + (static_cast(m_pFilter))->OnNewOutputMediaType(m_mt, mtOut); + pOutSample->SetMediaType(&mtOut); + } + + // Transform + + hr = (static_cast(m_pFilter))->Transform(pSample, pOutSample); + + if (S_OK == hr) { + hr = pOut->Deliver(pOutSample); + m_bSampleSkipped = FALSE; + } else if (S_FALSE == hr) { + hr = S_OK; + pOutSample = nullptr; + m_bSampleSkipped = TRUE; + + if (!m_bQualityChanged) { + m_pFilter->NotifyEvent(EC_QUALITY_CHANGE, 0, 0); + m_bQualityChanged = TRUE; + } + } + + return hr; +} + +STDMETHODIMP CStreamSwitcherInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + if (!IsConnected() || !IsActive()) { + return S_OK; + } + + CAutoLock cAutoLock(&m_csReceive); + + CStreamSwitcherFilter* pSSF = static_cast(m_pFilter); + + CStreamSwitcherOutputPin* pOut = pSSF->GetOutputPin(); + if (!pOut || !pOut->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + return pSSF->DeliverNewSegment(tStart, tStop, dRate); +} + +// +// CStreamSwitcherOutputPin +// + +CStreamSwitcherOutputPin::CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr) + : CBaseOutputPin(NAME("CStreamSwitcherOutputPin"), pFilter, &pFilter->m_csState, phr, L"Out") +{ + // m_bCanReconnectWhenActive = true; +} + +STDMETHODIMP CStreamSwitcherOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + ValidateReadWritePtr(ppv, sizeof(PVOID)); + *ppv = nullptr; + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + if (m_pStreamSwitcherPassThru == nullptr) { + HRESULT hr = S_OK; + m_pStreamSwitcherPassThru = (IUnknown*)(INonDelegatingUnknown*) + DEBUG_NEW CStreamSwitcherPassThru(GetOwner(), &hr, static_cast(m_pFilter)); + + if (!m_pStreamSwitcherPassThru) { + return E_OUTOFMEMORY; + } + if (FAILED(hr)) { + return hr; + } + } + + return m_pStreamSwitcherPassThru->QueryInterface(riid, ppv); + } + /* + else if (riid == IID_IStreamBuilder) + { + return GetInterface((IStreamBuilder*)this, ppv); + } + */ + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CStreamSwitcherOutputPin::QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt) +{ + HRESULT hr = S_FALSE; + + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + + if (pIn && pIn->IsConnected() && (pIn->IsUsingOwnAllocator() || pIn->CurrentMediaType() == *pmt)) { + if (CComQIPtr pPinTo = pIn->GetConnected()) { + if (S_OK != (hr = pPinTo->QueryAccept(pmt))) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } else { + return E_FAIL; + } + } + + return hr; +} + +// pure virtual + +HRESULT CStreamSwitcherOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + if (!pIn || !pIn->IsConnected()) { + return E_UNEXPECTED; + } + + CComPtr pAllocatorIn; + pIn->GetAllocator(&pAllocatorIn); + if (!pAllocatorIn) { + return E_UNEXPECTED; + } + + HRESULT hr; + if (FAILED(hr = pAllocatorIn->GetProperties(pProperties))) { + return hr; + } + + if (pProperties->cBuffers < 8 && pIn->CurrentMediaType().majortype == MEDIATYPE_Audio) { + pProperties->cBuffers = 8; + } + + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +// virtual + +class __declspec(uuid("AEFA5024-215A-4FC7-97A4-1043C86FD0B8")) + MatrixMixer {}; + +HRESULT CStreamSwitcherOutputPin::CheckConnect(IPin* pPin) +{ + CComPtr pBF = GetFilterFromPin(pPin); + + return + IsAudioWaveRenderer(pBF) || GetCLSID(pBF) == __uuidof(MatrixMixer) + ? __super::CheckConnect(pPin) + : E_FAIL; + + // return CComQIPtr(pPin) ? CBaseOutputPin::CheckConnect(pPin) : E_NOINTERFACE; + // return CBaseOutputPin::CheckConnect(pPin); +} + +HRESULT CStreamSwitcherOutputPin::BreakConnect() +{ + m_pPinConnection = nullptr; + return __super::BreakConnect(); +} + +HRESULT CStreamSwitcherOutputPin::CompleteConnect(IPin* pReceivePin) +{ + m_pPinConnection = CComQIPtr(pReceivePin); + HRESULT hr = __super::CompleteConnect(pReceivePin); + + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + CMediaType mt; + if (SUCCEEDED(hr) && pIn && pIn->IsConnected() + && SUCCEEDED(pIn->GetConnected()->ConnectionMediaType(&mt)) && m_mt != mt) { + if (pIn->GetConnected()->QueryAccept(&m_mt) == S_OK) { + hr = m_pFilter->ReconnectPin(pIn->GetConnected(), &m_mt); + } else { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + } + + return hr; +} + +HRESULT CStreamSwitcherOutputPin::CheckMediaType(const CMediaType* pmt) +{ + return (static_cast(m_pFilter))->CheckMediaType(pmt); +} + +HRESULT CStreamSwitcherOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + if (!pIn || !pIn->IsConnected()) { + return E_UNEXPECTED; + } + + CComPtr pEM; + if (FAILED(pIn->GetConnected()->EnumMediaTypes(&pEM))) { + return VFW_S_NO_MORE_ITEMS; + } + + if (iPosition > 0 && FAILED(pEM->Skip(iPosition))) { + return VFW_S_NO_MORE_ITEMS; + } + + AM_MEDIA_TYPE* tmp = nullptr; + if (S_OK != pEM->Next(1, &tmp, nullptr) || !tmp) { + return VFW_S_NO_MORE_ITEMS; + } + + CopyMediaType(pmt, tmp); + DeleteMediaType(tmp); + /* + if (iPosition < 0) return E_INVALIDARG; + if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; + + CopyMediaType(pmt, &pIn->CurrentMediaType()); + */ + return S_OK; +} + +// IPin + +STDMETHODIMP CStreamSwitcherOutputPin::QueryAccept(const AM_MEDIA_TYPE* pmt) +{ + HRESULT hr = __super::QueryAccept(pmt); + if (S_OK != hr) { + return hr; + } + + return QueryAcceptUpstream(pmt); +} + +// IQualityControl + +STDMETHODIMP CStreamSwitcherOutputPin::Notify(IBaseFilter* pSender, Quality q) +{ + CStreamSwitcherInputPin* pIn = (static_cast(m_pFilter))->GetInputPin(); + if (!pIn || !pIn->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + return pIn->PassNotify(q); +} + +// IStreamBuilder + +STDMETHODIMP CStreamSwitcherOutputPin::Render(IPin* ppinOut, IGraphBuilder* pGraph) +{ + CComPtr pBF; + pBF.CoCreateInstance(CLSID_DSoundRender); + if (!pBF || FAILED(pGraph->AddFilter(pBF, L"Default DirectSound Device"))) { + return E_FAIL; + } + + if (FAILED(pGraph->ConnectDirect(ppinOut, GetFirstDisconnectedPin(pBF, PINDIR_INPUT), nullptr))) { + pGraph->RemoveFilter(pBF); + return E_FAIL; + } + + return S_OK; +} + +STDMETHODIMP CStreamSwitcherOutputPin::Backout(IPin* ppinOut, IGraphBuilder* pGraph) +{ + return S_OK; +} + +// +// CStreamSwitcherFilter +// + +CStreamSwitcherFilter::CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) + : CBaseFilter(NAME("CStreamSwitcherFilter"), lpunk, &m_csState, clsid) + , m_pInput(nullptr) + , m_pOutput(nullptr) +{ + if (phr) { + *phr = S_OK; + } + + HRESULT hr = S_OK; + + do { + CAutoPtr pInput; + CAutoPtr pOutput; + + hr = S_OK; + pInput.Attach(DEBUG_NEW CStreamSwitcherInputPin(this, &hr, L"Channel 1")); + if (!pInput || FAILED(hr)) { + break; + } + + hr = S_OK; + pOutput.Attach(DEBUG_NEW CStreamSwitcherOutputPin(this, &hr)); + if (!pOutput || FAILED(hr)) { + break; + } + + CAutoLock cAutoLock(&m_csPins); + + m_pInputs.AddHead(m_pInput = pInput.Detach()); + m_pOutput = pOutput.Detach(); + + return; + } while (false); + + if (phr) { + *phr = E_FAIL; + } +} + +CStreamSwitcherFilter::~CStreamSwitcherFilter() +{ + CAutoLock cAutoLock(&m_csPins); + + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + delete m_pInputs.GetNext(pos); + } + m_pInputs.RemoveAll(); + m_pInput = nullptr; + + delete m_pOutput; + m_pOutput = nullptr; +} + +STDMETHODIMP CStreamSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IAMStreamSelect) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// + +int CStreamSwitcherFilter::GetPinCount() +{ + CAutoLock cAutoLock(&m_csPins); + + return (1 + (int)m_pInputs.GetCount()); +} + +CBasePin* CStreamSwitcherFilter::GetPin(int n) +{ + CAutoLock cAutoLock(&m_csPins); + + if (n < 0 || n >= GetPinCount()) { + return nullptr; + } else if (n == 0) { + return m_pOutput; + } else { + return m_pInputs.GetAt(m_pInputs.FindIndex(n - 1)); + } +} + +int CStreamSwitcherFilter::GetConnectedInputPinCount() +{ + CAutoLock cAutoLock(&m_csPins); + + int nConnected = 0; + POSITION pos = m_pInputs.GetHeadPosition(); + + while (pos) { + if (m_pInputs.GetNext(pos)->IsConnected()) { + nConnected++; + } + } + + return nConnected; +} + +CStreamSwitcherInputPin* CStreamSwitcherFilter::GetConnectedInputPin(int n) +{ + if (n >= 0) { + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos); + if (pPin->IsConnected()) { + if (n == 0) { + return pPin; + } + n--; + } + } + } + + return nullptr; +} + +CStreamSwitcherInputPin* CStreamSwitcherFilter::GetInputPin() +{ + return m_pInput; +} + +CStreamSwitcherOutputPin* CStreamSwitcherFilter::GetOutputPin() +{ + return m_pOutput; +} + +// + +HRESULT CStreamSwitcherFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin) +{ + if (dir == PINDIR_INPUT) { + CAutoLock cAutoLock(&m_csPins); + + int nConnected = GetConnectedInputPinCount(); + + if (nConnected == 1) { + m_pInput = static_cast(pPin); + } + + if ((size_t)nConnected == m_pInputs.GetCount()) { + CStringW name; + name.Format(L"Channel %ld", ++m_PinVersion); + + HRESULT hr = S_OK; + CStreamSwitcherInputPin* pInputPin = DEBUG_NEW CStreamSwitcherInputPin(this, &hr, name); + if (!pInputPin || FAILED(hr)) { + delete pInputPin; + return E_FAIL; + } + m_pInputs.AddTail(pInputPin); + } + } + + return S_OK; +} + +// this should be very thread safe, I hope it is, it must be... :) + +void CStreamSwitcherFilter::SelectInput(CStreamSwitcherInputPin* pInput) +{ + // make sure no input thinks it is active + m_pInput = nullptr; + + // release blocked GetBuffer in our own allocator & block all Receive + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos); + pPin->Block(false); + // a few Receive calls can arrive here, but since m_pInput == nullptr neighter of them gets delivered + pPin->Block(true); + } + + // this will let waiting GetBuffer() calls go on inside our Receive() + if (m_pOutput) { + m_pOutput->DeliverBeginFlush(); + m_pOutput->DeliverEndFlush(); + } + + if (!pInput) { + return; + } + + // set new input + m_pInput = pInput; + + // let it go + m_pInput->Block(false); +} + +// + +HRESULT CStreamSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + BYTE* pDataIn = nullptr; + BYTE* pDataOut = nullptr; + + HRESULT hr; + if (FAILED(hr = pIn->GetPointer(&pDataIn))) { + return hr; + } + if (FAILED(hr = pOut->GetPointer(&pDataOut))) { + return hr; + } + + long len = pIn->GetActualDataLength(); + long size = pOut->GetSize(); + + if (!pDataIn || !pDataOut /*|| len > size || len <= 0*/) { + return S_FALSE; // FIXME + } + + memcpy(pDataOut, pDataIn, std::min(len, size)); + pOut->SetActualDataLength(std::min(len, size)); + + return S_OK; +} + +CMediaType CStreamSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer) +{ + return mt; +} + +HRESULT CStreamSwitcherFilter::DeliverEndOfStream() +{ + return m_pOutput ? m_pOutput->DeliverEndOfStream() : E_FAIL; +} + +HRESULT CStreamSwitcherFilter::DeliverBeginFlush() +{ + return m_pOutput ? m_pOutput->DeliverBeginFlush() : E_FAIL; +} + +HRESULT CStreamSwitcherFilter::DeliverEndFlush() +{ + return m_pOutput ? m_pOutput->DeliverEndFlush() : E_FAIL; +} + +HRESULT CStreamSwitcherFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + return m_pOutput ? m_pOutput->DeliverNewSegment(tStart, tStop, dRate) : E_FAIL; +} + +// IAMStreamSelect + +STDMETHODIMP CStreamSwitcherFilter::Count(DWORD* pcStreams) +{ + CheckPointer(pcStreams, E_POINTER); + + CAutoLock cAutoLock(&m_csPins); + + *pcStreams = 0; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos) { + CStreamSwitcherInputPin* pInputPin = m_pInputs.GetNext(pos); + + if (pInputPin->IsConnected()) { + if (CComPtr pSSF = pInputPin->GetStreamSelectionFilter()) { + DWORD cStreams = 0; + HRESULT hr = pSSF->Count(&cStreams); + if (SUCCEEDED(hr)) { + for (int i = 0; i < (int)cStreams; i++) { + AM_MEDIA_TYPE* pmt = nullptr; + hr = pSSF->Info(i, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { + (*pcStreams)++; + } + DeleteMediaType(pmt); + } + } + } else { + (*pcStreams)++; + } + } + } + + return S_OK; +} + +STDMETHODIMP CStreamSwitcherFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) +{ + CAutoLock cAutoLock(&m_csPins); + + IUnknown* pObject = nullptr; + bool bFound = false; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos && !bFound) { + CStreamSwitcherInputPin* pInputPin = m_pInputs.GetNext(pos); + + if (pInputPin->IsConnected()) { + if (CComPtr pSSF = pInputPin->GetStreamSelectionFilter()) { + DWORD cStreams = 0; + HRESULT hr = pSSF->Count(&cStreams); + if (SUCCEEDED(hr)) { + for (int i = 0; i < (int)cStreams; i++) { + AM_MEDIA_TYPE* pmt = nullptr; + DWORD dwFlags; + LPWSTR pszName = nullptr; + hr = pSSF->Info(i, &pmt, &dwFlags, plcid, nullptr, &pszName, nullptr, nullptr); + if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { + if (lIndex == 0) { + bFound = true; + pObject = pSSF; + + if (ppmt) { + *ppmt = pmt; + } else { + DeleteMediaType(pmt); + } + + if (pdwFlags) { + *pdwFlags = (m_pInput == pInputPin) ? dwFlags : 0; + } + + if (pdwGroup) { + *pdwGroup = 1; + } + + if (ppszName) { + *ppszName = pszName; + } else { + CoTaskMemFree(pszName); + } + + break; + } else { + lIndex--; + } + } + DeleteMediaType(pmt); + CoTaskMemFree(pszName); + } + } + } else if (lIndex == 0) { + bFound = true; + + if (ppmt) { + bool found = false; + CComPtr pPinUpstream; + if (SUCCEEDED(m_pInput->ConnectedTo(&pPinUpstream)) && pPinUpstream) { + // find audio input pin of upstream filter + if (CComQIPtr pBF = GetFilterFromPin(pPinUpstream)) { + BeginEnumPins(pBF, pEP, pPin) { + CMediaTypeEx mt; + PIN_DIRECTION dir; + if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (mt.majortype == MEDIATYPE_Audio) { + *ppmt = CreateMediaType(&mt); + found = true; + break; + } + } + } + EndEnumPins; + } + } + if (!found) { + *ppmt = CreateMediaType(&m_pInput->CurrentMediaType()); + } + } + + if (pdwFlags) { + *pdwFlags = (m_pInput == pInputPin) ? AMSTREAMSELECTINFO_EXCLUSIVE : 0; + } + + if (plcid) { + *plcid = 0; + } + + if (pdwGroup) { + *pdwGroup = 1; + } + + if (ppszName) { + *ppszName = (WCHAR*)CoTaskMemAlloc((wcslen(pInputPin->Name()) + 1) * sizeof(WCHAR)); + if (*ppszName) { + wcscpy_s(*ppszName, wcslen(pInputPin->Name()) + 1, pInputPin->Name()); + } + } + } else { + lIndex--; + } + } + } + + if (!bFound) { + return E_INVALIDARG; + } + + if (ppObject) { + *ppObject = pObject; + if (pObject) { + pObject->AddRef(); + } + } + + if (ppUnk) { + *ppUnk = nullptr; + } + + return S_OK; +} + +STDMETHODIMP CStreamSwitcherFilter::Enable(long lIndex, DWORD dwFlags) +{ + if (dwFlags != AMSTREAMSELECTENABLE_ENABLE) { + return E_NOTIMPL; + } + + PauseGraph; + + bool bFound = false; + int i = 0; + CStreamSwitcherInputPin* pNewInputPin = nullptr; + POSITION pos = m_pInputs.GetHeadPosition(); + while (pos && !bFound) { + pNewInputPin = m_pInputs.GetNext(pos); + + if (pNewInputPin->IsConnected()) { + if (CComPtr pSSF = pNewInputPin->GetStreamSelectionFilter()) { + DWORD cStreams = 0; + HRESULT hr = pSSF->Count(&cStreams); + if (SUCCEEDED(hr)) { + for (i = 0; i < (int)cStreams; i++) { + AM_MEDIA_TYPE* pmt = nullptr; + hr = pSSF->Info(i, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + if (SUCCEEDED(hr) && pmt && pmt->majortype == MEDIATYPE_Audio) { + if (lIndex == 0) { + bFound = true; + DeleteMediaType(pmt); + break; + } else { + lIndex--; + } + } + DeleteMediaType(pmt); + } + } + } else if (lIndex == 0) { + bFound = true; + } else { + lIndex--; + } + } + } + + if (!bFound) { + return E_INVALIDARG; + } + + SelectInput(pNewInputPin); + + if (CComPtr pSSF = pNewInputPin->GetStreamSelectionFilter()) { + pSSF->Enable(i, dwFlags); + } + + ResumeGraph; + + return S_OK; +} diff --git a/src/filters/switcher/AudioSwitcher/StreamSwitcher.h b/src/filters/switcher/AudioSwitcher/StreamSwitcher.h index 54cdfab6454..f2091c515a4 100644 --- a/src/filters/switcher/AudioSwitcher/StreamSwitcher.h +++ b/src/filters/switcher/AudioSwitcher/StreamSwitcher.h @@ -1,269 +1,269 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include -#include - -class CStreamSwitcherFilter; - -class CStreamSwitcherPassThru : public IMediaSeeking, public CMediaPosition -{ -protected: - CStreamSwitcherFilter* m_pFilter; - -public: - CStreamSwitcherPassThru(LPUNKNOWN, HRESULT* phr, CStreamSwitcherFilter* pFilter); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IMediaSeeking methods - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, - LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, - LONGLONG* pStop, DWORD StopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - - // IMediaPosition properties - STDMETHODIMP get_Duration(REFTIME* plength); - STDMETHODIMP put_CurrentPosition(REFTIME llTime); - STDMETHODIMP get_StopTime(REFTIME* pllTime); - STDMETHODIMP put_StopTime(REFTIME llTime); - STDMETHODIMP get_PrerollTime(REFTIME* pllTime); - STDMETHODIMP put_PrerollTime(REFTIME llTime); - STDMETHODIMP get_Rate(double* pdRate); - STDMETHODIMP put_Rate(double dRate); - STDMETHODIMP get_CurrentPosition(REFTIME* pllTime); - STDMETHODIMP CanSeekForward(LONG* pCanSeekForward); - STDMETHODIMP CanSeekBackward(LONG* pCanSeekBackward); -}; - -class CStreamSwitcherInputPin; - -class CStreamSwitcherAllocator : public CMemAllocator -{ -protected: - CStreamSwitcherInputPin* m_pPin; - - CMediaType m_mt; - bool m_fMediaTypeChanged; - -public: - CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr); -#ifdef _DEBUG - ~CStreamSwitcherAllocator(); -#endif - - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - - STDMETHODIMP GetBuffer( - IMediaSample** ppBuffer, - REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, - DWORD dwFlags); - - void NotifyMediaType(const CMediaType& mt); -}; - -interface __declspec(uuid("DA395FA3-4A3E-4D85-805E-0BEFF53D4BCD")) - IStreamSwitcherInputPin : - public IUnknown -{ - STDMETHOD_(bool, IsActive)() PURE; -}; - -class CStreamSwitcherInputPin : public CBaseInputPin, public IPinConnection, public IStreamSwitcherInputPin -{ - friend class CStreamSwitcherAllocator; - - CStreamSwitcherAllocator m_Allocator; - - BOOL m_bSampleSkipped; - BOOL m_bQualityChanged; - BOOL m_bUsingOwnAllocator; - - CAMEvent m_evBlock; - bool m_fCanBlock; - bool m_bFirstSampleReceived; - HRESULT Active(); - HRESULT Inactive(); - - HRESULT QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt); - - HRESULT InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample); - - HANDLE m_hNotifyEvent; - - CComPtr m_pSSF; - -public: - CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - CMediaType& CurrentMediaType() { return m_mt; } - IMemAllocator* CurrentAllocator() { return m_pAllocator; } - - bool IsUsingOwnAllocator() { return m_bUsingOwnAllocator == TRUE; } - - void Block(bool fBlock); - - CCritSec m_csReceive; - - CComPtr GetStreamSelectionFilter() { return m_pSSF; } - - // pure virtual - HRESULT CheckMediaType(const CMediaType* pmt); - - // virtual - HRESULT CheckConnect(IPin* pPin); - HRESULT CompleteConnect(IPin* pReceivePin); - - // IPin - STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* pmt); - STDMETHODIMP ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator); - STDMETHODIMP NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - STDMETHODIMP EndOfStream(); - - // IMemInputPin - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - - // IPinConnection - STDMETHODIMP DynamicQueryAccept(const AM_MEDIA_TYPE* pmt); - STDMETHODIMP NotifyEndOfStream(HANDLE hNotifyEvent); - STDMETHODIMP IsEndPin(); - STDMETHODIMP DynamicDisconnect(); - - // IStreamSwitcherInputPin - STDMETHODIMP_(bool) IsActive(); -}; - -class CStreamSwitcherOutputPin : public CBaseOutputPin, public IStreamBuilder -{ - CComPtr m_pStreamSwitcherPassThru; - CComPtr m_pPinConnection; - - HRESULT QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt); - -public: - CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - CMediaType& CurrentMediaType() { return m_mt; } - IMemAllocator* CurrentAllocator() { return m_pAllocator; } - IPinConnection* CurrentPinConnection() { return m_pPinConnection; } - - // pure virtual - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - - // virtual - HRESULT CheckConnect(IPin* pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin* pReceivePin); - - HRESULT CheckMediaType(const CMediaType* pmt); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - - // IPin - STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* pmt); - - // IQualityControl - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); - - // IStreamBuilder - STDMETHODIMP Render(IPin* ppinOut, IGraphBuilder* pGraph); - STDMETHODIMP Backout(IPin* ppinOut, IGraphBuilder* pGraph); -}; - -class CStreamSwitcherFilter : public CBaseFilter, public IAMStreamSelect -{ - friend class CStreamSwitcherInputPin; - friend class CStreamSwitcherOutputPin; - friend class CStreamSwitcherPassThru; - - CAtlList m_pInputs; - CStreamSwitcherInputPin* m_pInput; - CStreamSwitcherOutputPin* m_pOutput; - - CCritSec m_csState, m_csPins; - - HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin); - -protected: - void SelectInput(CStreamSwitcherInputPin* pInput); - -public: - CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid); - virtual ~CStreamSwitcherFilter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - int GetPinCount(); - CBasePin* GetPin(int n); - - int GetConnectedInputPinCount(); - CStreamSwitcherInputPin* GetConnectedInputPin(int n); - CStreamSwitcherInputPin* GetInputPin(); - CStreamSwitcherOutputPin* GetOutputPin(); - - // override these - virtual HRESULT CheckMediaType(const CMediaType* pmt) = 0; - virtual HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - virtual CMediaType CreateNewOutputMediaType(CMediaType mt, long& cbBuffer); - virtual void OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut) {} - - // and maybe these - virtual HRESULT DeliverEndOfStream(); - virtual HRESULT DeliverBeginFlush(); - virtual HRESULT DeliverEndFlush(); - virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - - // IAMStreamSelect - STDMETHODIMP Count(DWORD* pcStreams); - STDMETHODIMP Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, - LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, - IUnknown** ppObject, IUnknown** ppUnk); - STDMETHODIMP Enable(long lIndex, DWORD dwFlags); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include +#include + +class CStreamSwitcherFilter; + +class CStreamSwitcherPassThru : public IMediaSeeking, public CMediaPosition +{ +protected: + CStreamSwitcherFilter* m_pFilter; + +public: + CStreamSwitcherPassThru(LPUNKNOWN, HRESULT* phr, CStreamSwitcherFilter* pFilter); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IMediaSeeking methods + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, + LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, + LONGLONG* pStop, DWORD StopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + + // IMediaPosition properties + STDMETHODIMP get_Duration(REFTIME* plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(REFTIME* pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(REFTIME* pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(double* pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP get_CurrentPosition(REFTIME* pllTime); + STDMETHODIMP CanSeekForward(LONG* pCanSeekForward); + STDMETHODIMP CanSeekBackward(LONG* pCanSeekBackward); +}; + +class CStreamSwitcherInputPin; + +class CStreamSwitcherAllocator : public CMemAllocator +{ +protected: + CStreamSwitcherInputPin* m_pPin; + + CMediaType m_mt; + bool m_fMediaTypeChanged; + +public: + CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr); +#ifdef _DEBUG + ~CStreamSwitcherAllocator(); +#endif + + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + + STDMETHODIMP GetBuffer( + IMediaSample** ppBuffer, + REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, + DWORD dwFlags); + + void NotifyMediaType(const CMediaType& mt); +}; + +interface __declspec(uuid("DA395FA3-4A3E-4D85-805E-0BEFF53D4BCD")) + IStreamSwitcherInputPin : + public IUnknown +{ + STDMETHOD_(bool, IsActive)() PURE; +}; + +class CStreamSwitcherInputPin : public CBaseInputPin, public IPinConnection, public IStreamSwitcherInputPin +{ + friend class CStreamSwitcherAllocator; + + CStreamSwitcherAllocator m_Allocator; + + BOOL m_bSampleSkipped; + BOOL m_bQualityChanged; + BOOL m_bUsingOwnAllocator; + + CAMEvent m_evBlock; + bool m_fCanBlock; + bool m_bFirstSampleReceived; + HRESULT Active(); + HRESULT Inactive(); + + HRESULT QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt); + + HRESULT InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample); + + HANDLE m_hNotifyEvent; + + CComPtr m_pSSF; + +public: + CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + CMediaType& CurrentMediaType() { return m_mt; } + IMemAllocator* CurrentAllocator() { return m_pAllocator; } + + bool IsUsingOwnAllocator() { return m_bUsingOwnAllocator == TRUE; } + + void Block(bool fBlock); + + CCritSec m_csReceive; + + CComPtr GetStreamSelectionFilter() { return m_pSSF; } + + // pure virtual + HRESULT CheckMediaType(const CMediaType* pmt); + + // virtual + HRESULT CheckConnect(IPin* pPin); + HRESULT CompleteConnect(IPin* pReceivePin); + + // IPin + STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* pmt); + STDMETHODIMP ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator); + STDMETHODIMP NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + STDMETHODIMP EndOfStream(); + + // IMemInputPin + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + // IPinConnection + STDMETHODIMP DynamicQueryAccept(const AM_MEDIA_TYPE* pmt); + STDMETHODIMP NotifyEndOfStream(HANDLE hNotifyEvent); + STDMETHODIMP IsEndPin(); + STDMETHODIMP DynamicDisconnect(); + + // IStreamSwitcherInputPin + STDMETHODIMP_(bool) IsActive(); +}; + +class CStreamSwitcherOutputPin : public CBaseOutputPin, public IStreamBuilder +{ + CComPtr m_pStreamSwitcherPassThru; + CComPtr m_pPinConnection; + + HRESULT QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt); + +public: + CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + CMediaType& CurrentMediaType() { return m_mt; } + IMemAllocator* CurrentAllocator() { return m_pAllocator; } + IPinConnection* CurrentPinConnection() { return m_pPinConnection; } + + // pure virtual + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + + // virtual + HRESULT CheckConnect(IPin* pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin* pReceivePin); + + HRESULT CheckMediaType(const CMediaType* pmt); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + + // IPin + STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE* pmt); + + // IQualityControl + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q); + + // IStreamBuilder + STDMETHODIMP Render(IPin* ppinOut, IGraphBuilder* pGraph); + STDMETHODIMP Backout(IPin* ppinOut, IGraphBuilder* pGraph); +}; + +class CStreamSwitcherFilter : public CBaseFilter, public IAMStreamSelect +{ + friend class CStreamSwitcherInputPin; + friend class CStreamSwitcherOutputPin; + friend class CStreamSwitcherPassThru; + + CAtlList m_pInputs; + CStreamSwitcherInputPin* m_pInput; + CStreamSwitcherOutputPin* m_pOutput; + + CCritSec m_csState, m_csPins; + + HRESULT CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin); + +protected: + void SelectInput(CStreamSwitcherInputPin* pInput); + +public: + CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid); + virtual ~CStreamSwitcherFilter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + int GetPinCount(); + CBasePin* GetPin(int n); + + int GetConnectedInputPinCount(); + CStreamSwitcherInputPin* GetConnectedInputPin(int n); + CStreamSwitcherInputPin* GetInputPin(); + CStreamSwitcherOutputPin* GetOutputPin(); + + // override these + virtual HRESULT CheckMediaType(const CMediaType* pmt) = 0; + virtual HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + virtual CMediaType CreateNewOutputMediaType(CMediaType mt, long& cbBuffer); + virtual void OnNewOutputMediaType(const CMediaType& mtIn, const CMediaType& mtOut) {} + + // and maybe these + virtual HRESULT DeliverEndOfStream(); + virtual HRESULT DeliverBeginFlush(); + virtual HRESULT DeliverEndFlush(); + virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + + // IAMStreamSelect + STDMETHODIMP Count(DWORD* pcStreams); + STDMETHODIMP Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, + LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, + IUnknown** ppObject, IUnknown** ppUnk); + STDMETHODIMP Enable(long lIndex, DWORD dwFlags); +}; diff --git a/src/filters/switcher/AudioSwitcher/resource.h b/src/filters/switcher/AudioSwitcher/resource.h index 2b00562fdee..7eb4f1a1480 100644 --- a/src/filters/switcher/AudioSwitcher/resource.h +++ b/src/filters/switcher/AudioSwitcher/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by AudioSwitcher.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by AudioSwitcher.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/switcher/AudioSwitcher/stdafx.cpp b/src/filters/switcher/AudioSwitcher/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/switcher/AudioSwitcher/stdafx.cpp +++ b/src/filters/switcher/AudioSwitcher/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/switcher/AudioSwitcher/stdafx.h b/src/filters/switcher/AudioSwitcher/stdafx.h index f0c534cd5b2..0406bee9e05 100644 --- a/src/filters/switcher/AudioSwitcher/stdafx.h +++ b/src/filters/switcher/AudioSwitcher/stdafx.h @@ -1,36 +1,36 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include - -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include + +#include diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.cpp b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.cpp index 3aad88550e7..fd99fcda64b 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.cpp +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.cpp @@ -1,512 +1,512 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "AVI2AC3Filter.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER -#include -#endif -#include "moreuuids.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DOLBY_AC3}, - {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DTS}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CAVI2AC3Filter), AVI2AC3FilterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CAVI2AC3Filter -// - -CAVI2AC3Filter::CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr) - : CTransformFilter(NAME("CAVI2AC3Filter"), lpunk, __uuidof(this)) -{ - if (phr) { - *phr = S_OK; - } -} - -CAVI2AC3Filter::~CAVI2AC3Filter() -{ -} - -HRESULT CAVI2AC3Filter::Transform(IMediaSample* pSample, IMediaSample* pOutSample) -{ - HRESULT hr; - - BYTE* pIn = nullptr; - if (FAILED(hr = pSample->GetPointer(&pIn))) { - return hr; - } - BYTE* pInOrg = pIn; - - long len = pSample->GetActualDataLength(); - if (len <= 0) { - return S_FALSE; - } - - BYTE* pOut = nullptr; - if (FAILED(hr = pOutSample->GetPointer(&pOut))) { - return hr; - } - BYTE* pOutOrg = pOut; - - long size = pOutSample->GetSize(); - - if ((CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) - && (CheckWAVEAC3(&m_pOutput->CurrentMediaType()) || CheckWAVEDTS(&m_pOutput->CurrentMediaType()))) { - if (*(DWORD*)pIn == 0xBA010000) { - pIn += 14; - } - - if (*(DWORD*)pIn == 0xBD010000) { - pIn += 8 + 1 + pIn[8] + 1 + 3; - } - - len -= long(pInOrg - pIn); - - if (size < len) { - return E_FAIL; - } - - memcpy(pOut, pIn, len); - pOut += len; - } else if ((CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) - && (CheckAC3(&m_pOutput->CurrentMediaType()) || CheckDTS(&m_pOutput->CurrentMediaType()))) { - if ((m_pOutput->CurrentMediaType().majortype == MEDIATYPE_DVD_ENCRYPTED_PACK - || m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES) - && (len + 12 + 3) >= 0x10000) { // damn, this can happen if the interleave time is too big - REFERENCE_TIME rtStart = 0, rtStop = 1; - bool fHasTime = (S_OK == pSample->GetTime(&rtStart, &rtStop)); - - bool fDiscontinuity = (S_OK == pOutSample->IsDiscontinuity()); - - long pos = 0; - while (pos < len) { - int curlen = std::min(len - pos, 2013l); - pos += 2013; - - CComPtr pNewOutSample; - hr = InitializeOutputSample(pSample, &pNewOutSample); - - if (fDiscontinuity) { - if (fHasTime) { - rtStop = rtStart + (rtStop - rtStart) * curlen / len; - pNewOutSample->SetTime(&rtStart, &rtStop); - } - - fDiscontinuity = false; - } else { - pNewOutSample->SetTime(nullptr, nullptr); - pNewOutSample->SetDiscontinuity(FALSE); - } - - BYTE* pNewOut = nullptr; - if (FAILED(hr = pNewOutSample->GetPointer(&pNewOut))) { - return hr; - } - BYTE* pNewOutOrg = pNewOut; - - long newSize = pNewOutSample->GetSize(); - - const GUID* majortype = &m_pOutput->CurrentMediaType().majortype; - const GUID* subtype = &m_pOutput->CurrentMediaType().subtype; - - if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { - if (newSize < curlen + 32 + 3) { - return E_FAIL; - } - - BYTE PESHeader[] = { - 0x00, 0x00, 0x01, 0xBA, // PES id - 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0) - 0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits) - }; - - memcpy(pNewOut, &PESHeader, sizeof(PESHeader)); - pNewOut += sizeof(PESHeader); - - majortype = &MEDIATYPE_MPEG2_PES; - } - - if (*majortype == MEDIATYPE_MPEG2_PES) { - if (newSize < curlen + 20 + 3) { - return E_FAIL; - } - - BYTE Private1Header[] = { - 0x00, 0x00, 0x01, 0xBD, // private stream 1 id - 0x07, 0xEC, // packet length (TODO: modify it later) - 0x81, 0x80, // marker, original, PTS - flags - 0x08, // packet data starting offset - 0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0) - 0xFF, 0xFF, 0xFF, // stuffing - 0x80, // stream id (0) - 0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back) - }; - - int packetlen = curlen + 12 + 3; - ASSERT(packetlen <= 0xffff); - Private1Header[4] = (packetlen >> 8) & 0xff; - Private1Header[5] = packetlen & 0xff; - - if (*subtype == MEDIASUBTYPE_DTS) { - Private1Header[17] += 8; - } - - if (*subtype == MEDIASUBTYPE_DOLBY_AC3) { - for (int i = 0; i < curlen; i++) { - if (*(DWORD*)&pIn[i] == 0x770B) { - i++; - Private1Header[19] = (i >> 8) & 0xff; - Private1Header[20] = i & 0xff; - break; - } - } - } else if (*subtype == MEDIASUBTYPE_DTS) { - for (int i = 0; i < curlen; i++) { - if (*(DWORD*)&pIn[i] == 0x0180FE7F) { - i++; - Private1Header[19] = (i >> 8) & 0xff; - Private1Header[20] = i & 0xff; - break; - } - } - } - - memcpy(pNewOut, &Private1Header, sizeof(Private1Header)); - pNewOut += sizeof(Private1Header); - - majortype = &MEDIATYPE_Audio; - } - - if (*majortype == MEDIATYPE_Audio) { - if (newSize < curlen) { - return E_FAIL; - } - memcpy(pNewOut, pIn, curlen); - pIn += curlen; - pNewOut += curlen; - } - - pNewOutSample->SetActualDataLength(long(pNewOut - pNewOutOrg)); - - m_pOutput->Deliver(pNewOutSample); - } - - return S_FALSE; - } else { // phew, we can do the easier way - const GUID* majortype = &m_pOutput->CurrentMediaType().majortype; - const GUID* subtype = &m_pOutput->CurrentMediaType().subtype; - - if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { - if (size < len + 32 + 3) { - return E_FAIL; - } - - BYTE PESHeader[] = { - 0x00, 0x00, 0x01, 0xBA, // PES id - 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0) - 0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits) - }; - - memcpy(pOut, &PESHeader, sizeof(PESHeader)); - pOut += sizeof(PESHeader); - - majortype = &MEDIATYPE_MPEG2_PES; - } - - if (*majortype == MEDIATYPE_MPEG2_PES) { - if (size < len + 20 + 3) { - return E_FAIL; - } - - BYTE Private1Header[] = { - 0x00, 0x00, 0x01, 0xBD, // private stream 1 id - 0x07, 0xEC, // packet length (TODO: modify it later) - 0x81, 0x80, // marker, original, PTS - flags - 0x08, // packet data starting offset - 0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0) - 0xFF, 0xFF, 0xFF, // stuffing - 0x80, // stream id (0) - 0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back) - }; - - int packetlen = len + 12 + 3; - ASSERT(packetlen <= 0xffff); - Private1Header[4] = (packetlen >> 8) & 0xff; - Private1Header[5] = packetlen & 0xff; - - if (*subtype == MEDIASUBTYPE_DTS) { - Private1Header[17] += 8; - } - - memcpy(pOut, &Private1Header, sizeof(Private1Header)); - pOut += sizeof(Private1Header); - - majortype = &MEDIATYPE_Audio; - } - - if (*majortype == MEDIATYPE_Audio) { - if (size < len) { - return E_FAIL; - } - - memcpy(pOut, pIn, len); - pIn += len; - pOut += len; - } - } - } else { - return E_FAIL; - } - - pOutSample->SetActualDataLength(int(pOut - pOutOrg)); - - return S_OK; -} - -bool CAVI2AC3Filter::CheckAC3(const CMediaType* pmt) -{ - return (pmt->majortype == MEDIATYPE_Audio - || pmt->majortype == MEDIATYPE_MPEG2_PES - || pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) - && pmt->subtype == MEDIASUBTYPE_DOLBY_AC3; -} - -bool CAVI2AC3Filter::CheckDTS(const CMediaType* pmt) -{ - return (pmt->majortype == MEDIATYPE_Audio - || pmt->majortype == MEDIATYPE_MPEG2_PES - || pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) - && pmt->subtype == MEDIASUBTYPE_DTS; -} - -bool CAVI2AC3Filter::CheckWAVEAC3(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Audio - && pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 - && pmt->formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3; -} - -bool CAVI2AC3Filter::CheckWAVEDTS(const CMediaType* pmt) -{ - return pmt->majortype == MEDIATYPE_Audio - && pmt->subtype == MEDIASUBTYPE_WAVE_DTS - && pmt->formattype == FORMAT_WaveFormatEx - && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS; -} - -HRESULT CAVI2AC3Filter::CheckInputType(const CMediaType* mtIn) -{ - bool fWaveFormatEx = !!(mtIn->formattype == FORMAT_WaveFormatEx); - - return CheckAC3(mtIn) && fWaveFormatEx || CheckDTS(mtIn) && fWaveFormatEx - || CheckWAVEAC3(mtIn) || CheckWAVEDTS(mtIn) - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CAVI2AC3Filter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return CheckAC3(mtIn) && CheckWAVEAC3(mtOut) - || CheckWAVEAC3(mtIn) && CheckAC3(mtOut) - || CheckDTS(mtIn) && CheckWAVEDTS(mtOut) - || CheckWAVEDTS(mtIn) && CheckDTS(mtOut) - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CAVI2AC3Filter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - CComPtr pAllocatorIn; - m_pInput->GetAllocator(&pAllocatorIn); - if (!pAllocatorIn) { - return E_UNEXPECTED; - } - - pAllocatorIn->GetProperties(pProperties); - - pProperties->cBuffers = 2; - pProperties->cbBuffer = std::max(pProperties->cbBuffer, 1024l * 1024l); // this should be enough... - pProperties->cbAlign = 1; - pProperties->cbPrefix = 0; - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -HRESULT CAVI2AC3Filter::GetMediaType(int iPosition, CMediaType* pMediaType) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - const GUID& majortype = m_pInput->CurrentMediaType().majortype; - const GUID& subtype = m_pInput->CurrentMediaType().subtype; - UNREFERENCED_PARAMETER(majortype); - - if (CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) { - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - pMediaType->majortype = MEDIATYPE_Audio; - - pMediaType->formattype = FORMAT_WaveFormatEx; - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX)); - ZeroMemory(wfe, sizeof(WAVEFORMATEX)); - wfe->cbSize = sizeof(WAVEFORMATEX); - wfe->nAvgBytesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nAvgBytesPerSec; - wfe->nSamplesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nSamplesPerSec; - wfe->wBitsPerSample = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->wBitsPerSample; - wfe->nChannels = 2; - wfe->nBlockAlign = 1; - - if (subtype == MEDIASUBTYPE_DOLBY_AC3) { - pMediaType->subtype = MEDIASUBTYPE_WAVE_DOLBY_AC3; - wfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3; - } else if (subtype == MEDIASUBTYPE_DTS) { - pMediaType->subtype = MEDIASUBTYPE_WAVE_DTS; - wfe->wFormatTag = WAVE_FORMAT_DVD_DTS; - } else { - return E_INVALIDARG; - } - } else if (CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) { - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 4) { - return VFW_S_NO_MORE_ITEMS; - } - - if (subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3) { - pMediaType->subtype = MEDIASUBTYPE_DOLBY_AC3; - - pMediaType->formattype = FORMAT_WaveFormatEx; - DOLBYAC3WAVEFORMAT* wfe = (DOLBYAC3WAVEFORMAT*)pMediaType->AllocFormatBuffer(sizeof(DOLBYAC3WAVEFORMAT)); - ZeroMemory(wfe, sizeof(DOLBYAC3WAVEFORMAT)); - // unfortunately we can't tell what we are going to get in transform, - // so we just set the most common values and hope that the ac3 decoder - // is flexible enough (it is usually :) to find out these from the bitstream - wfe->wfx.cbSize = sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX); - wfe->wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3; - wfe->wfx.nSamplesPerSec = 48000; - wfe->wfx.nChannels = 6; - wfe->bBigEndian = TRUE; - } else if (subtype == MEDIASUBTYPE_WAVE_DTS) { - pMediaType->subtype = MEDIASUBTYPE_DTS; - - pMediaType->formattype = FORMAT_WaveFormatEx; - WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX)); - ZeroMemory(wfe, sizeof(WAVEFORMATEX)); - // same case as with ac3, but this time we don't even know the structure - wfe->cbSize = sizeof(WAVEFORMATEX); - wfe->wFormatTag = WAVE_FORMAT_PCM; - wfe->nSamplesPerSec = 48000; - wfe->nChannels = 6; - } else { - return E_INVALIDARG; - } - - switch (iPosition) { - case 0: - pMediaType->majortype = MEDIATYPE_Audio; - break; - case 1: - pMediaType->ResetFormatBuffer(); - pMediaType->formattype = FORMAT_None; - // no break - case 2: - pMediaType->majortype = MEDIATYPE_MPEG2_PES; - break; - case 3: - pMediaType->ResetFormatBuffer(); - pMediaType->formattype = FORMAT_None; - // no break - case 4: - pMediaType->majortype = MEDIATYPE_DVD_ENCRYPTED_PACK; - break; - default: - ASSERT(FALSE); // Shouldn't happen - return E_INVALIDARG; - } - } else { - return VFW_S_NO_MORE_ITEMS; - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "AVI2AC3Filter.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER +#include +#endif +#include "moreuuids.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DOLBY_AC3}, + {&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DTS}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CAVI2AC3Filter), AVI2AC3FilterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CAVI2AC3Filter +// + +CAVI2AC3Filter::CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr) + : CTransformFilter(NAME("CAVI2AC3Filter"), lpunk, __uuidof(this)) +{ + if (phr) { + *phr = S_OK; + } +} + +CAVI2AC3Filter::~CAVI2AC3Filter() +{ +} + +HRESULT CAVI2AC3Filter::Transform(IMediaSample* pSample, IMediaSample* pOutSample) +{ + HRESULT hr; + + BYTE* pIn = nullptr; + if (FAILED(hr = pSample->GetPointer(&pIn))) { + return hr; + } + BYTE* pInOrg = pIn; + + long len = pSample->GetActualDataLength(); + if (len <= 0) { + return S_FALSE; + } + + BYTE* pOut = nullptr; + if (FAILED(hr = pOutSample->GetPointer(&pOut))) { + return hr; + } + BYTE* pOutOrg = pOut; + + long size = pOutSample->GetSize(); + + if ((CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) + && (CheckWAVEAC3(&m_pOutput->CurrentMediaType()) || CheckWAVEDTS(&m_pOutput->CurrentMediaType()))) { + if (*(DWORD*)pIn == 0xBA010000) { + pIn += 14; + } + + if (*(DWORD*)pIn == 0xBD010000) { + pIn += 8 + 1 + pIn[8] + 1 + 3; + } + + len -= long(pInOrg - pIn); + + if (size < len) { + return E_FAIL; + } + + memcpy(pOut, pIn, len); + pOut += len; + } else if ((CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) + && (CheckAC3(&m_pOutput->CurrentMediaType()) || CheckDTS(&m_pOutput->CurrentMediaType()))) { + if ((m_pOutput->CurrentMediaType().majortype == MEDIATYPE_DVD_ENCRYPTED_PACK + || m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES) + && (len + 12 + 3) >= 0x10000) { // damn, this can happen if the interleave time is too big + REFERENCE_TIME rtStart = 0, rtStop = 1; + bool fHasTime = (S_OK == pSample->GetTime(&rtStart, &rtStop)); + + bool fDiscontinuity = (S_OK == pOutSample->IsDiscontinuity()); + + long pos = 0; + while (pos < len) { + int curlen = std::min(len - pos, 2013l); + pos += 2013; + + CComPtr pNewOutSample; + hr = InitializeOutputSample(pSample, &pNewOutSample); + + if (fDiscontinuity) { + if (fHasTime) { + rtStop = rtStart + (rtStop - rtStart) * curlen / len; + pNewOutSample->SetTime(&rtStart, &rtStop); + } + + fDiscontinuity = false; + } else { + pNewOutSample->SetTime(nullptr, nullptr); + pNewOutSample->SetDiscontinuity(FALSE); + } + + BYTE* pNewOut = nullptr; + if (FAILED(hr = pNewOutSample->GetPointer(&pNewOut))) { + return hr; + } + BYTE* pNewOutOrg = pNewOut; + + long newSize = pNewOutSample->GetSize(); + + const GUID* majortype = &m_pOutput->CurrentMediaType().majortype; + const GUID* subtype = &m_pOutput->CurrentMediaType().subtype; + + if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { + if (newSize < curlen + 32 + 3) { + return E_FAIL; + } + + BYTE PESHeader[] = { + 0x00, 0x00, 0x01, 0xBA, // PES id + 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0) + 0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits) + }; + + memcpy(pNewOut, &PESHeader, sizeof(PESHeader)); + pNewOut += sizeof(PESHeader); + + majortype = &MEDIATYPE_MPEG2_PES; + } + + if (*majortype == MEDIATYPE_MPEG2_PES) { + if (newSize < curlen + 20 + 3) { + return E_FAIL; + } + + BYTE Private1Header[] = { + 0x00, 0x00, 0x01, 0xBD, // private stream 1 id + 0x07, 0xEC, // packet length (TODO: modify it later) + 0x81, 0x80, // marker, original, PTS - flags + 0x08, // packet data starting offset + 0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0) + 0xFF, 0xFF, 0xFF, // stuffing + 0x80, // stream id (0) + 0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back) + }; + + int packetlen = curlen + 12 + 3; + ASSERT(packetlen <= 0xffff); + Private1Header[4] = (packetlen >> 8) & 0xff; + Private1Header[5] = packetlen & 0xff; + + if (*subtype == MEDIASUBTYPE_DTS) { + Private1Header[17] += 8; + } + + if (*subtype == MEDIASUBTYPE_DOLBY_AC3) { + for (int i = 0; i < curlen; i++) { + if (*(DWORD*)&pIn[i] == 0x770B) { + i++; + Private1Header[19] = (i >> 8) & 0xff; + Private1Header[20] = i & 0xff; + break; + } + } + } else if (*subtype == MEDIASUBTYPE_DTS) { + for (int i = 0; i < curlen; i++) { + if (*(DWORD*)&pIn[i] == 0x0180FE7F) { + i++; + Private1Header[19] = (i >> 8) & 0xff; + Private1Header[20] = i & 0xff; + break; + } + } + } + + memcpy(pNewOut, &Private1Header, sizeof(Private1Header)); + pNewOut += sizeof(Private1Header); + + majortype = &MEDIATYPE_Audio; + } + + if (*majortype == MEDIATYPE_Audio) { + if (newSize < curlen) { + return E_FAIL; + } + memcpy(pNewOut, pIn, curlen); + pIn += curlen; + pNewOut += curlen; + } + + pNewOutSample->SetActualDataLength(long(pNewOut - pNewOutOrg)); + + m_pOutput->Deliver(pNewOutSample); + } + + return S_FALSE; + } else { // phew, we can do the easier way + const GUID* majortype = &m_pOutput->CurrentMediaType().majortype; + const GUID* subtype = &m_pOutput->CurrentMediaType().subtype; + + if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) { + if (size < len + 32 + 3) { + return E_FAIL; + } + + BYTE PESHeader[] = { + 0x00, 0x00, 0x01, 0xBA, // PES id + 0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0) + 0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits) + }; + + memcpy(pOut, &PESHeader, sizeof(PESHeader)); + pOut += sizeof(PESHeader); + + majortype = &MEDIATYPE_MPEG2_PES; + } + + if (*majortype == MEDIATYPE_MPEG2_PES) { + if (size < len + 20 + 3) { + return E_FAIL; + } + + BYTE Private1Header[] = { + 0x00, 0x00, 0x01, 0xBD, // private stream 1 id + 0x07, 0xEC, // packet length (TODO: modify it later) + 0x81, 0x80, // marker, original, PTS - flags + 0x08, // packet data starting offset + 0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0) + 0xFF, 0xFF, 0xFF, // stuffing + 0x80, // stream id (0) + 0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back) + }; + + int packetlen = len + 12 + 3; + ASSERT(packetlen <= 0xffff); + Private1Header[4] = (packetlen >> 8) & 0xff; + Private1Header[5] = packetlen & 0xff; + + if (*subtype == MEDIASUBTYPE_DTS) { + Private1Header[17] += 8; + } + + memcpy(pOut, &Private1Header, sizeof(Private1Header)); + pOut += sizeof(Private1Header); + + majortype = &MEDIATYPE_Audio; + } + + if (*majortype == MEDIATYPE_Audio) { + if (size < len) { + return E_FAIL; + } + + memcpy(pOut, pIn, len); + pIn += len; + pOut += len; + } + } + } else { + return E_FAIL; + } + + pOutSample->SetActualDataLength(int(pOut - pOutOrg)); + + return S_OK; +} + +bool CAVI2AC3Filter::CheckAC3(const CMediaType* pmt) +{ + return (pmt->majortype == MEDIATYPE_Audio + || pmt->majortype == MEDIATYPE_MPEG2_PES + || pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) + && pmt->subtype == MEDIASUBTYPE_DOLBY_AC3; +} + +bool CAVI2AC3Filter::CheckDTS(const CMediaType* pmt) +{ + return (pmt->majortype == MEDIATYPE_Audio + || pmt->majortype == MEDIATYPE_MPEG2_PES + || pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) + && pmt->subtype == MEDIASUBTYPE_DTS; +} + +bool CAVI2AC3Filter::CheckWAVEAC3(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Audio + && pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 + && pmt->formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3; +} + +bool CAVI2AC3Filter::CheckWAVEDTS(const CMediaType* pmt) +{ + return pmt->majortype == MEDIATYPE_Audio + && pmt->subtype == MEDIASUBTYPE_WAVE_DTS + && pmt->formattype == FORMAT_WaveFormatEx + && ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS; +} + +HRESULT CAVI2AC3Filter::CheckInputType(const CMediaType* mtIn) +{ + bool fWaveFormatEx = !!(mtIn->formattype == FORMAT_WaveFormatEx); + + return CheckAC3(mtIn) && fWaveFormatEx || CheckDTS(mtIn) && fWaveFormatEx + || CheckWAVEAC3(mtIn) || CheckWAVEDTS(mtIn) + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CAVI2AC3Filter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return CheckAC3(mtIn) && CheckWAVEAC3(mtOut) + || CheckWAVEAC3(mtIn) && CheckAC3(mtOut) + || CheckDTS(mtIn) && CheckWAVEDTS(mtOut) + || CheckWAVEDTS(mtIn) && CheckDTS(mtOut) + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CAVI2AC3Filter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + CComPtr pAllocatorIn; + m_pInput->GetAllocator(&pAllocatorIn); + if (!pAllocatorIn) { + return E_UNEXPECTED; + } + + pAllocatorIn->GetProperties(pProperties); + + pProperties->cBuffers = 2; + pProperties->cbBuffer = std::max(pProperties->cbBuffer, 1024l * 1024l); // this should be enough... + pProperties->cbAlign = 1; + pProperties->cbPrefix = 0; + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +HRESULT CAVI2AC3Filter::GetMediaType(int iPosition, CMediaType* pMediaType) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + const GUID& majortype = m_pInput->CurrentMediaType().majortype; + const GUID& subtype = m_pInput->CurrentMediaType().subtype; + UNREFERENCED_PARAMETER(majortype); + + if (CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) { + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + pMediaType->majortype = MEDIATYPE_Audio; + + pMediaType->formattype = FORMAT_WaveFormatEx; + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX)); + ZeroMemory(wfe, sizeof(WAVEFORMATEX)); + wfe->cbSize = sizeof(WAVEFORMATEX); + wfe->nAvgBytesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nAvgBytesPerSec; + wfe->nSamplesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nSamplesPerSec; + wfe->wBitsPerSample = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->wBitsPerSample; + wfe->nChannels = 2; + wfe->nBlockAlign = 1; + + if (subtype == MEDIASUBTYPE_DOLBY_AC3) { + pMediaType->subtype = MEDIASUBTYPE_WAVE_DOLBY_AC3; + wfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3; + } else if (subtype == MEDIASUBTYPE_DTS) { + pMediaType->subtype = MEDIASUBTYPE_WAVE_DTS; + wfe->wFormatTag = WAVE_FORMAT_DVD_DTS; + } else { + return E_INVALIDARG; + } + } else if (CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) { + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 4) { + return VFW_S_NO_MORE_ITEMS; + } + + if (subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3) { + pMediaType->subtype = MEDIASUBTYPE_DOLBY_AC3; + + pMediaType->formattype = FORMAT_WaveFormatEx; + DOLBYAC3WAVEFORMAT* wfe = (DOLBYAC3WAVEFORMAT*)pMediaType->AllocFormatBuffer(sizeof(DOLBYAC3WAVEFORMAT)); + ZeroMemory(wfe, sizeof(DOLBYAC3WAVEFORMAT)); + // unfortunately we can't tell what we are going to get in transform, + // so we just set the most common values and hope that the ac3 decoder + // is flexible enough (it is usually :) to find out these from the bitstream + wfe->wfx.cbSize = sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX); + wfe->wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3; + wfe->wfx.nSamplesPerSec = 48000; + wfe->wfx.nChannels = 6; + wfe->bBigEndian = TRUE; + } else if (subtype == MEDIASUBTYPE_WAVE_DTS) { + pMediaType->subtype = MEDIASUBTYPE_DTS; + + pMediaType->formattype = FORMAT_WaveFormatEx; + WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX)); + ZeroMemory(wfe, sizeof(WAVEFORMATEX)); + // same case as with ac3, but this time we don't even know the structure + wfe->cbSize = sizeof(WAVEFORMATEX); + wfe->wFormatTag = WAVE_FORMAT_PCM; + wfe->nSamplesPerSec = 48000; + wfe->nChannels = 6; + } else { + return E_INVALIDARG; + } + + switch (iPosition) { + case 0: + pMediaType->majortype = MEDIATYPE_Audio; + break; + case 1: + pMediaType->ResetFormatBuffer(); + pMediaType->formattype = FORMAT_None; + // no break + case 2: + pMediaType->majortype = MEDIATYPE_MPEG2_PES; + break; + case 3: + pMediaType->ResetFormatBuffer(); + pMediaType->formattype = FORMAT_None; + // no break + case 4: + pMediaType->majortype = MEDIATYPE_DVD_ENCRYPTED_PACK; + break; + default: + ASSERT(FALSE); // Shouldn't happen + return E_INVALIDARG; + } + } else { + return VFW_S_NO_MORE_ITEMS; + } + + return S_OK; +} diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.def b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.def +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.h b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.h index 421c7a4f3bc..59a889845a3 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.h +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.h @@ -1,67 +1,67 @@ -/* - * (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 . - * - */ - -#pragma once - -#define AVI2AC3FilterName L"MPC-HC AVI<->AC3/DTS" - -/* AC3 audio - - wFormatTag WAVE_FORMAT_DOLBY_AC3 - nChannels 1 -6 channels valid - nSamplesPerSec 48000, 44100, 32000 - nAvgByesPerSec 4000 to 80000 - nBlockAlign 128 - 3840 - wBitsPerSample Up to 24 bits - (in the original) - -*/ - -typedef struct tagDOLBYAC3WAVEFORMAT { - WAVEFORMATEX wfx; - BYTE bBigEndian; // TRUE = Big Endian, FALSE little endian - BYTE bsid; - BYTE lfeon; - BYTE copyrightb; - BYTE nAuxBitsCode; // Aux bits per frame -} DOLBYAC3WAVEFORMAT; - -// -// CAVI2AC3Filter -// - -class __declspec(uuid("93230DD0-7B3C-4efb-AFBB-DC380FEC9E6B")) - CAVI2AC3Filter : public CTransformFilter -{ - bool CheckAC3(const CMediaType* pmt); - bool CheckDTS(const CMediaType* pmt); - bool CheckWAVEAC3(const CMediaType* pmt); - bool CheckWAVEDTS(const CMediaType* pmt); - -public: - CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr); - virtual ~CAVI2AC3Filter(); - - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); -}; +/* + * (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 . + * + */ + +#pragma once + +#define AVI2AC3FilterName L"MPC-HC AVI<->AC3/DTS" + +/* AC3 audio + + wFormatTag WAVE_FORMAT_DOLBY_AC3 + nChannels 1 -6 channels valid + nSamplesPerSec 48000, 44100, 32000 + nAvgByesPerSec 4000 to 80000 + nBlockAlign 128 - 3840 + wBitsPerSample Up to 24 bits - (in the original) + +*/ + +typedef struct tagDOLBYAC3WAVEFORMAT { + WAVEFORMATEX wfx; + BYTE bBigEndian; // TRUE = Big Endian, FALSE little endian + BYTE bsid; + BYTE lfeon; + BYTE copyrightb; + BYTE nAuxBitsCode; // Aux bits per frame +} DOLBYAC3WAVEFORMAT; + +// +// CAVI2AC3Filter +// + +class __declspec(uuid("93230DD0-7B3C-4efb-AFBB-DC380FEC9E6B")) + CAVI2AC3Filter : public CTransformFilter +{ + bool CheckAC3(const CMediaType* pmt); + bool CheckDTS(const CMediaType* pmt); + bool CheckWAVEAC3(const CMediaType* pmt); + bool CheckWAVEDTS(const CMediaType* pmt); + +public: + CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr); + virtual ~CAVI2AC3Filter(); + + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); +}; diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.rc b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.rc index 00e54d563e1..f61dca6467c 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.rc +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "AVI <-> AC3/DTS Converter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "AVI2AC3Filter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "AVI2AC3Filter.ax" - VALUE "ProductName", "AVI2AC3Filter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "AVI <-> AC3/DTS Converter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "AVI2AC3Filter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "AVI2AC3Filter.ax" + VALUE "ProductName", "AVI2AC3Filter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj index 36f594b9a94..c3ca52f5a34 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj @@ -1,114 +1,114 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {339A4575-E25B-45D6-94A1-D835891740B8} - AVI2AC3Filter - MFCProj - AVI2AC3Filter - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - AVI2AC3Filter.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {339A4575-E25B-45D6-94A1-D835891740B8} + AVI2AC3Filter + MFCProj + AVI2AC3Filter + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + AVI2AC3Filter.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj.filters b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj.filters index b865009bdf5..801dac2147f 100644 --- a/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj.filters +++ b/src/filters/transform/AVI2AC3Filter/AVI2AC3Filter.vcxproj.filters @@ -1,46 +1,46 @@ - - - - - {00cf5f87-ccb3-495d-aa71-5c96741443af} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {315d7e31-e679-4814-b1b1-291189683016} - h;hpp;hxx;hm;inl;inc - - - {f2e1cd40-0b89-445b-b583-0220959f7205} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {00cf5f87-ccb3-495d-aa71-5c96741443af} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {315d7e31-e679-4814-b1b1-291189683016} + h;hpp;hxx;hm;inl;inc + + + {f2e1cd40-0b89-445b-b583-0220959f7205} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/transform/AVI2AC3Filter/resource.h b/src/filters/transform/AVI2AC3Filter/resource.h index e24ec65f345..fba14bf5a69 100644 --- a/src/filters/transform/AVI2AC3Filter/resource.h +++ b/src/filters/transform/AVI2AC3Filter/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by AVI2AC3Filter.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by AVI2AC3Filter.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/transform/AVI2AC3Filter/stdafx.cpp b/src/filters/transform/AVI2AC3Filter/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/transform/AVI2AC3Filter/stdafx.cpp +++ b/src/filters/transform/AVI2AC3Filter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/transform/AVI2AC3Filter/stdafx.h b/src/filters/transform/AVI2AC3Filter/stdafx.h index 12bbe2db0a7..d8320f2c878 100644 --- a/src/filters/transform/AVI2AC3Filter/stdafx.h +++ b/src/filters/transform/AVI2AC3Filter/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/transform/BufferFilter/BufferFilter.cpp b/src/filters/transform/BufferFilter/BufferFilter.cpp index 392f69e55ef..1ccb796508f 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.cpp +++ b/src/filters/transform/BufferFilter/BufferFilter.cpp @@ -1,372 +1,372 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "BufferFilter.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CBufferFilter), BufferFilterName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CBufferFilter -// - -CBufferFilter::CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr) - : CTransformFilter(NAME("CBufferFilter"), lpunk, __uuidof(this)) - , m_nSamplesToBuffer(2) -{ - HRESULT hr = S_OK; - - do { - m_pInput = DEBUG_NEW CTransformInputPin(NAME("Transform input pin"), this, &hr, L"In"); - if (!m_pInput) { - hr = E_OUTOFMEMORY; - } - if (FAILED(hr)) { - break; - } - - m_pOutput = DEBUG_NEW CBufferFilterOutputPin(this, &hr); - if (!m_pOutput) { - hr = E_OUTOFMEMORY; - } - if (FAILED(hr)) { - delete m_pInput; - m_pInput = nullptr; - break; - } - } while (false); - - if (phr) { - *phr = hr; - } -} - -CBufferFilter::~CBufferFilter() -{ -} - -STDMETHODIMP CBufferFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IBufferFilter) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IBufferFilter - -STDMETHODIMP CBufferFilter::SetBuffers(int nBuffers) -{ - if (!m_pOutput) { - return E_FAIL; - } - - if (m_pOutput->IsConnected()) { // TODO: allow "on-the-fly" changes - return VFW_E_ALREADY_CONNECTED; - } - - m_nSamplesToBuffer = nBuffers; - - return S_OK; -} - -STDMETHODIMP_(int) CBufferFilter::GetBuffers() -{ - return m_nSamplesToBuffer; -} - -STDMETHODIMP_(int) CBufferFilter::GetFreeBuffers() -{ - CBufferFilterOutputPin* pPin = static_cast(m_pOutput); - return (pPin && pPin->m_pOutputQueue ? (m_nSamplesToBuffer - pPin->m_pOutputQueue->GetQueueCount()) : 0); -} - -STDMETHODIMP CBufferFilter::SetPriority(DWORD dwPriority) -{ - CBufferFilterOutputPin* pPin = static_cast(m_pOutput); - return (pPin && pPin->m_pOutputQueue ? (pPin->m_pOutputQueue->SetPriority(dwPriority) ? S_OK : E_FAIL) : E_UNEXPECTED); -} - -// - -HRESULT CBufferFilter::Receive(IMediaSample* pSample) -{ - ASSERT(pSample); - CheckPointer(pSample, E_POINTER); - ASSERT(m_pOutput); - CheckPointer(m_pOutput, E_POINTER); - - /* Check for other streams and pass them on */ - AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps(); - if (pProps->dwStreamId != AM_STREAM_MEDIA) { - return m_pOutput->Deliver(pSample); - } - - HRESULT hr; - IMediaSample* pOutSample; - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - // Start timing the transform (if PERF is defined) - MSR_START(m_idTransform); - - // have the derived class transform the data - - hr = Transform(pSample, pOutSample); - - // Stop the clock and log it (if PERF is defined) - MSR_STOP(m_idTransform); - - if (FAILED(hr)) { - DbgLog((LOG_TRACE, 1, _T("Error from transform"))); - } else { - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pOutSample); - m_bSampleSkipped = FALSE; // last thing no longer dropped - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this cause because returning S_FALSE - // from Receive() means that this is the end of the stream and no more data should - // be sent. - if (S_FALSE == hr) { - - // Release the sample before calling notify to avoid - // deadlocks if the sample holds a lock on the system - // such as DirectDraw buffers do - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - NotifyEvent(EC_QUALITY_CHANGE, 0, 0); - m_bQualityChanged = TRUE; - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - - return hr; -} - -HRESULT CBufferFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - BYTE* pDataIn = nullptr; - BYTE* pDataOut = nullptr; - - long len = pIn->GetActualDataLength(); - long size = pOut->GetSize(); - - if (FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn || FAILED(pOut->GetPointer(&pDataOut)) || !pDataOut - || len > size || len <= 0) { - return S_FALSE; - } - - memcpy(pDataOut, pDataIn, std::min(len, size)); - - pOut->SetActualDataLength(std::min(len, size)); - - return S_OK; -} - -HRESULT CBufferFilter::CheckInputType(const CMediaType* mtIn) -{ - return S_OK; -} - -HRESULT CBufferFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return mtIn->MatchesPartial(mtOut) ? S_OK : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CBufferFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - CComPtr pAllocatorIn; - m_pInput->GetAllocator(&pAllocatorIn); - if (!pAllocatorIn) { - return E_UNEXPECTED; - } - - pAllocatorIn->GetProperties(pProperties); - - pProperties->cBuffers = std::max(m_nSamplesToBuffer, pProperties->cBuffers); - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -HRESULT CBufferFilter::GetMediaType(int iPosition, CMediaType* pMediaType) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - // TODO: offer all input types from upstream and allow reconnection at least in stopped state - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - CopyMediaType(pMediaType, &m_pInput->CurrentMediaType()); - - return S_OK; -} - -HRESULT CBufferFilter::StopStreaming() -{ - CBufferFilterOutputPin* pPin = static_cast(m_pOutput); - if (m_pInput && pPin && pPin->m_pOutputQueue) { - while (!m_pInput->IsFlushing() && pPin->m_pOutputQueue->GetQueueCount() > 0) { - Sleep(50); - } - } - - return __super::StopStreaming(); -} - -// -// CBufferFilterOutputPin -// - -CBufferFilterOutputPin::CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr) - : CTransformOutputPin(NAME("CBufferFilterOutputPin"), pFilter, phr, L"Out") -{ -} - -HRESULT CBufferFilterOutputPin::Active() -{ - CAutoLock lock_it(m_pLock); - - if (m_Connected && !m_pOutputQueue) { - HRESULT hr = NOERROR; - - m_pOutputQueue.Attach(DEBUG_NEW CBufferFilterOutputQueue(m_Connected, &hr)); - if (!m_pOutputQueue) { - hr = E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - m_pOutputQueue.Free(); - return hr; - } - } - - return __super::Active(); -} - -HRESULT CBufferFilterOutputPin::Inactive() -{ - CAutoLock lock_it(m_pLock); - m_pOutputQueue.Free(); - return __super::Inactive(); -} - -HRESULT CBufferFilterOutputPin::Deliver(IMediaSample* pMediaSample) -{ - if (!m_pOutputQueue) { - return NOERROR; - } - pMediaSample->AddRef(); - return m_pOutputQueue->Receive(pMediaSample); -} - -HRESULT CBufferFilterOutputPin::DeliverEndOfStream() -{ - CallQueue(EOS()); -} - -HRESULT CBufferFilterOutputPin::DeliverBeginFlush() -{ - CallQueue(BeginFlush()); -} - -HRESULT CBufferFilterOutputPin::DeliverEndFlush() -{ - CallQueue(EndFlush()); -} - -HRESULT CBufferFilterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - CallQueue(NewSegment(tStart, tStop, dRate)); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "BufferFilter.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CBufferFilter), BufferFilterName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory} +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]} +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CBufferFilter +// + +CBufferFilter::CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr) + : CTransformFilter(NAME("CBufferFilter"), lpunk, __uuidof(this)) + , m_nSamplesToBuffer(2) +{ + HRESULT hr = S_OK; + + do { + m_pInput = DEBUG_NEW CTransformInputPin(NAME("Transform input pin"), this, &hr, L"In"); + if (!m_pInput) { + hr = E_OUTOFMEMORY; + } + if (FAILED(hr)) { + break; + } + + m_pOutput = DEBUG_NEW CBufferFilterOutputPin(this, &hr); + if (!m_pOutput) { + hr = E_OUTOFMEMORY; + } + if (FAILED(hr)) { + delete m_pInput; + m_pInput = nullptr; + break; + } + } while (false); + + if (phr) { + *phr = hr; + } +} + +CBufferFilter::~CBufferFilter() +{ +} + +STDMETHODIMP CBufferFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IBufferFilter) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IBufferFilter + +STDMETHODIMP CBufferFilter::SetBuffers(int nBuffers) +{ + if (!m_pOutput) { + return E_FAIL; + } + + if (m_pOutput->IsConnected()) { // TODO: allow "on-the-fly" changes + return VFW_E_ALREADY_CONNECTED; + } + + m_nSamplesToBuffer = nBuffers; + + return S_OK; +} + +STDMETHODIMP_(int) CBufferFilter::GetBuffers() +{ + return m_nSamplesToBuffer; +} + +STDMETHODIMP_(int) CBufferFilter::GetFreeBuffers() +{ + CBufferFilterOutputPin* pPin = static_cast(m_pOutput); + return (pPin && pPin->m_pOutputQueue ? (m_nSamplesToBuffer - pPin->m_pOutputQueue->GetQueueCount()) : 0); +} + +STDMETHODIMP CBufferFilter::SetPriority(DWORD dwPriority) +{ + CBufferFilterOutputPin* pPin = static_cast(m_pOutput); + return (pPin && pPin->m_pOutputQueue ? (pPin->m_pOutputQueue->SetPriority(dwPriority) ? S_OK : E_FAIL) : E_UNEXPECTED); +} + +// + +HRESULT CBufferFilter::Receive(IMediaSample* pSample) +{ + ASSERT(pSample); + CheckPointer(pSample, E_POINTER); + ASSERT(m_pOutput); + CheckPointer(m_pOutput, E_POINTER); + + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->Deliver(pSample); + } + + HRESULT hr; + IMediaSample* pOutSample; + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + // Start timing the transform (if PERF is defined) + MSR_START(m_idTransform); + + // have the derived class transform the data + + hr = Transform(pSample, pOutSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransform); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE, 1, _T("Error from transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pOutSample); + m_bSampleSkipped = FALSE; // last thing no longer dropped + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // Release the sample before calling notify to avoid + // deadlocks if the sample holds a lock on the system + // such as DirectDraw buffers do + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE, 0, 0); + m_bQualityChanged = TRUE; + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + + return hr; +} + +HRESULT CBufferFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + BYTE* pDataIn = nullptr; + BYTE* pDataOut = nullptr; + + long len = pIn->GetActualDataLength(); + long size = pOut->GetSize(); + + if (FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn || FAILED(pOut->GetPointer(&pDataOut)) || !pDataOut + || len > size || len <= 0) { + return S_FALSE; + } + + memcpy(pDataOut, pDataIn, std::min(len, size)); + + pOut->SetActualDataLength(std::min(len, size)); + + return S_OK; +} + +HRESULT CBufferFilter::CheckInputType(const CMediaType* mtIn) +{ + return S_OK; +} + +HRESULT CBufferFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return mtIn->MatchesPartial(mtOut) ? S_OK : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CBufferFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + CComPtr pAllocatorIn; + m_pInput->GetAllocator(&pAllocatorIn); + if (!pAllocatorIn) { + return E_UNEXPECTED; + } + + pAllocatorIn->GetProperties(pProperties); + + pProperties->cBuffers = std::max(m_nSamplesToBuffer, pProperties->cBuffers); + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +HRESULT CBufferFilter::GetMediaType(int iPosition, CMediaType* pMediaType) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + // TODO: offer all input types from upstream and allow reconnection at least in stopped state + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + CopyMediaType(pMediaType, &m_pInput->CurrentMediaType()); + + return S_OK; +} + +HRESULT CBufferFilter::StopStreaming() +{ + CBufferFilterOutputPin* pPin = static_cast(m_pOutput); + if (m_pInput && pPin && pPin->m_pOutputQueue) { + while (!m_pInput->IsFlushing() && pPin->m_pOutputQueue->GetQueueCount() > 0) { + Sleep(50); + } + } + + return __super::StopStreaming(); +} + +// +// CBufferFilterOutputPin +// + +CBufferFilterOutputPin::CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr) + : CTransformOutputPin(NAME("CBufferFilterOutputPin"), pFilter, phr, L"Out") +{ +} + +HRESULT CBufferFilterOutputPin::Active() +{ + CAutoLock lock_it(m_pLock); + + if (m_Connected && !m_pOutputQueue) { + HRESULT hr = NOERROR; + + m_pOutputQueue.Attach(DEBUG_NEW CBufferFilterOutputQueue(m_Connected, &hr)); + if (!m_pOutputQueue) { + hr = E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + m_pOutputQueue.Free(); + return hr; + } + } + + return __super::Active(); +} + +HRESULT CBufferFilterOutputPin::Inactive() +{ + CAutoLock lock_it(m_pLock); + m_pOutputQueue.Free(); + return __super::Inactive(); +} + +HRESULT CBufferFilterOutputPin::Deliver(IMediaSample* pMediaSample) +{ + if (!m_pOutputQueue) { + return NOERROR; + } + pMediaSample->AddRef(); + return m_pOutputQueue->Receive(pMediaSample); +} + +HRESULT CBufferFilterOutputPin::DeliverEndOfStream() +{ + CallQueue(EOS()); +} + +HRESULT CBufferFilterOutputPin::DeliverBeginFlush() +{ + CallQueue(BeginFlush()); +} + +HRESULT CBufferFilterOutputPin::DeliverEndFlush() +{ + CallQueue(EndFlush()); +} + +HRESULT CBufferFilterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + CallQueue(NewSegment(tStart, tStop, dRate)); +} diff --git a/src/filters/transform/BufferFilter/BufferFilter.def b/src/filters/transform/BufferFilter/BufferFilter.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.def +++ b/src/filters/transform/BufferFilter/BufferFilter.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/transform/BufferFilter/BufferFilter.h b/src/filters/transform/BufferFilter/BufferFilter.h index c253ed22d42..3df9fbf125d 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.h +++ b/src/filters/transform/BufferFilter/BufferFilter.h @@ -1,99 +1,99 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include - -#define BufferFilterName L"MPC-HC Buffer Filter" - -interface __declspec(uuid("63EF0035-3FFE-4c41-9230-4346E028BE20")) - IBufferFilter : - public IUnknown -{ - STDMETHOD(SetBuffers)(int nBuffers) PURE; - STDMETHOD_(int, GetBuffers)() PURE; - STDMETHOD_(int, GetFreeBuffers)() PURE; - STDMETHOD(SetPriority)(DWORD dwPriority = THREAD_PRIORITY_NORMAL) PURE; -}; - -class __declspec(uuid("DA2B3D77-2F29-4fd2-AC99-DEE4A8A13BF0")) - CBufferFilter : public CTransformFilter, public IBufferFilter -{ - int m_nSamplesToBuffer; - -public: - CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr); - virtual ~CBufferFilter(); - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IBufferFilter - STDMETHODIMP SetBuffers(int nBuffers); - STDMETHODIMP_(int) GetBuffers(); - STDMETHODIMP_(int) GetFreeBuffers(); - STDMETHODIMP SetPriority(DWORD dwPriority = THREAD_PRIORITY_NORMAL); - - HRESULT Receive(IMediaSample* pSample); - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); - HRESULT StopStreaming(); -}; - -class CBufferFilterOutputPin : public CTransformOutputPin -{ - class CBufferFilterOutputQueue : public COutputQueue - { - public: - CBufferFilterOutputQueue(IPin* pInputPin, HRESULT* phr, - DWORD dwPriority = THREAD_PRIORITY_NORMAL, - BOOL bAuto = FALSE, BOOL bQueue = TRUE, - LONG lBatchSize = 1, BOOL bBatchExact = FALSE, - LONG lListSize = DEFAULTCACHE, - bool bFlushingOpt = false) - : COutputQueue(pInputPin, phr, bAuto, bQueue, lBatchSize, bBatchExact, lListSize, dwPriority, bFlushingOpt) { - } - - int GetQueueCount() { return m_List ? m_List->GetCount() : -1; } - - bool SetPriority(DWORD dwPriority) { - return m_hThread ? !!::SetThreadPriority(m_hThread, dwPriority) : false; - } - }; - -public: - CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr); - - CAutoPtr m_pOutputQueue; - - HRESULT Active(); - HRESULT Inactive(); - - HRESULT Deliver(IMediaSample* pMediaSample); - HRESULT DeliverEndOfStream(); - HRESULT DeliverBeginFlush(); - HRESULT DeliverEndFlush(); - HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include + +#define BufferFilterName L"MPC-HC Buffer Filter" + +interface __declspec(uuid("63EF0035-3FFE-4c41-9230-4346E028BE20")) + IBufferFilter : + public IUnknown +{ + STDMETHOD(SetBuffers)(int nBuffers) PURE; + STDMETHOD_(int, GetBuffers)() PURE; + STDMETHOD_(int, GetFreeBuffers)() PURE; + STDMETHOD(SetPriority)(DWORD dwPriority = THREAD_PRIORITY_NORMAL) PURE; +}; + +class __declspec(uuid("DA2B3D77-2F29-4fd2-AC99-DEE4A8A13BF0")) + CBufferFilter : public CTransformFilter, public IBufferFilter +{ + int m_nSamplesToBuffer; + +public: + CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr); + virtual ~CBufferFilter(); + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IBufferFilter + STDMETHODIMP SetBuffers(int nBuffers); + STDMETHODIMP_(int) GetBuffers(); + STDMETHODIMP_(int) GetFreeBuffers(); + STDMETHODIMP SetPriority(DWORD dwPriority = THREAD_PRIORITY_NORMAL); + + HRESULT Receive(IMediaSample* pSample); + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); + HRESULT StopStreaming(); +}; + +class CBufferFilterOutputPin : public CTransformOutputPin +{ + class CBufferFilterOutputQueue : public COutputQueue + { + public: + CBufferFilterOutputQueue(IPin* pInputPin, HRESULT* phr, + DWORD dwPriority = THREAD_PRIORITY_NORMAL, + BOOL bAuto = FALSE, BOOL bQueue = TRUE, + LONG lBatchSize = 1, BOOL bBatchExact = FALSE, + LONG lListSize = DEFAULTCACHE, + bool bFlushingOpt = false) + : COutputQueue(pInputPin, phr, bAuto, bQueue, lBatchSize, bBatchExact, lListSize, dwPriority, bFlushingOpt) { + } + + int GetQueueCount() { return m_List ? m_List->GetCount() : -1; } + + bool SetPriority(DWORD dwPriority) { + return m_hThread ? !!::SetThreadPriority(m_hThread, dwPriority) : false; + } + }; + +public: + CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr); + + CAutoPtr m_pOutputQueue; + + HRESULT Active(); + HRESULT Inactive(); + + HRESULT Deliver(IMediaSample* pMediaSample); + HRESULT DeliverEndOfStream(); + HRESULT DeliverBeginFlush(); + HRESULT DeliverEndFlush(); + HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); +}; diff --git a/src/filters/transform/BufferFilter/BufferFilter.rc b/src/filters/transform/BufferFilter/BufferFilter.rc index ca8b9de15cb..28ab46df900 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.rc +++ b/src/filters/transform/BufferFilter/BufferFilter.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "BufferFilter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "BufferFilter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "BufferFilter.ax" - VALUE "ProductName", "BufferFilter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "BufferFilter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "BufferFilter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "BufferFilter.ax" + VALUE "ProductName", "BufferFilter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/transform/BufferFilter/BufferFilter.vcxproj b/src/filters/transform/BufferFilter/BufferFilter.vcxproj index 87446141864..e4b8547f330 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.vcxproj +++ b/src/filters/transform/BufferFilter/BufferFilter.vcxproj @@ -1,114 +1,114 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {9DCFD02A-16A0-4766-BC18-66163E21929D} - BufferFilter - MFCProj - BufferFilter - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - BufferFilter.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {9DCFD02A-16A0-4766-BC18-66163E21929D} + BufferFilter + MFCProj + BufferFilter + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + BufferFilter.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/transform/BufferFilter/BufferFilter.vcxproj.filters b/src/filters/transform/BufferFilter/BufferFilter.vcxproj.filters index 00d84c07e07..06d3f156d68 100644 --- a/src/filters/transform/BufferFilter/BufferFilter.vcxproj.filters +++ b/src/filters/transform/BufferFilter/BufferFilter.vcxproj.filters @@ -1,45 +1,45 @@ - - - - - {9b46af16-2931-44b3-981b-5a22b3ba715b} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {c2ac36f0-4a7c-472d-9399-044ccd8a0c19} - h;hpp;hxx;hm;inl;inc - - - {d1339141-4475-4353-a628-f09883acf731} - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {9b46af16-2931-44b3-981b-5a22b3ba715b} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2ac36f0-4a7c-472d-9399-044ccd8a0c19} + h;hpp;hxx;hm;inl;inc + + + {d1339141-4475-4353-a628-f09883acf731} + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/transform/BufferFilter/resource.h b/src/filters/transform/BufferFilter/resource.h index f0a39ebf9c8..b51a6af76c2 100644 --- a/src/filters/transform/BufferFilter/resource.h +++ b/src/filters/transform/BufferFilter/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by BufferFilter.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by BufferFilter.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/transform/BufferFilter/stdafx.cpp b/src/filters/transform/BufferFilter/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/transform/BufferFilter/stdafx.cpp +++ b/src/filters/transform/BufferFilter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/transform/BufferFilter/stdafx.h b/src/filters/transform/BufferFilter/stdafx.h index 12bbe2db0a7..d8320f2c878 100644 --- a/src/filters/transform/BufferFilter/stdafx.h +++ b/src/filters/transform/BufferFilter/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.cpp b/src/filters/transform/DeCSSFilter/DeCSSFilter.cpp index 70bf82d6bd8..a3e01c5a146 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.cpp +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.cpp @@ -1,259 +1,259 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "DeCSSFilter.h" -#include "../../../DeCSS/DeCSSInputPin.h" -#include "../../../DSUtil/DSUtil.h" - -#ifdef STANDALONE_FILTER - -#include -#include "moreuuids.h" - -const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { - {&MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { - {&MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_NULL}, - {&MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_NULL}, -}; - -const AMOVIESETUP_PIN sudpPins[] = { - {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, - {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} -}; - -const AMOVIESETUP_FILTER sudFilter[] = { - {&__uuidof(CDeCSSFilter), DeCSSFilterName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, -}; - -CFactoryTemplate g_Templates[] = { - {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, -}; - -int g_cTemplates = _countof(g_Templates); - -STDAPI DllRegisterServer() -{ - return AMovieDllRegisterServer2(TRUE); -} - -STDAPI DllUnregisterServer() -{ - return AMovieDllRegisterServer2(FALSE); -} - -#include "../../FilterApp.h" - -CFilterApp theApp; - -#endif - -// -// CDeCSSFilter -// - -class CKsPSInputPin : public CDeCSSInputPin -{ -public: - CKsPSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName) - : CDeCSSInputPin(pObjectName, pFilter, phr, pName) { - } - - // IKsPropertySet - STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength) { - if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { - return pKsPS->Set(PropSet, Id, InstanceData, InstanceLength, PropertyData, DataLength); - } - return E_NOTIMPL; - } - STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG* pBytesReturned) { - if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { - return pKsPS->Get(PropSet, Id, InstanceData, InstanceLength, PropertyData, DataLength, pBytesReturned); - } - return E_NOTIMPL; - } - STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) { - if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { - return pKsPS->QuerySupported(PropSet, Id, pTypeSupport); - } - return E_NOTIMPL; - } -}; - -CDeCSSFilter::CDeCSSFilter(LPUNKNOWN lpunk, HRESULT* phr) - : CTransformFilter(NAME("CDeCSSFilter"), lpunk, __uuidof(this)) -{ - HRESULT hr; - if (!phr) { - phr = &hr; - } - *phr = S_OK; - - m_pInput = DEBUG_NEW CKsPSInputPin(NAME("CKsPSInputPin"), this, phr, L"In"); - if (!m_pInput) { - *phr = E_OUTOFMEMORY; - } - if (FAILED(*phr)) { - return; - } - - m_pOutput = DEBUG_NEW CTransformOutputPin(NAME("CTransformOutputPin"), this, phr, L"Out"); - if (!m_pOutput) { - *phr = E_OUTOFMEMORY; - } - if (FAILED(*phr)) { - delete m_pInput; - m_pInput = nullptr; - return; - } -} - -CDeCSSFilter::~CDeCSSFilter() -{ -} - -HRESULT CDeCSSFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - AM_MEDIA_TYPE* pmt; - if (SUCCEEDED(pIn->GetMediaType(&pmt)) && pmt) { - CMediaType mt = *pmt; - m_pInput->SetMediaType(&mt); - mt.majortype = m_pOutput->CurrentMediaType().majortype; - m_pOutput->SetMediaType(&mt); - pOut->SetMediaType(&mt); - DeleteMediaType(pmt); - } - - BYTE* pDataIn = nullptr; - BYTE* pDataOut = nullptr; - - HRESULT hr; - if (FAILED(hr = pIn->GetPointer(&pDataIn)) || FAILED(hr = pOut->GetPointer(&pDataOut))) { - return hr; - } - - long len = pIn->GetActualDataLength(); - long size = pOut->GetSize(); - - if (len == 0 || pDataIn == nullptr) { // format changes do not carry any data - pOut->SetActualDataLength(0); - return S_OK; - } - - if (m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES) { - if (*(DWORD*)pDataIn == 0xBA010000) { - len -= 14; - pDataIn += 14; - if (int stuffing = (pDataIn[-1] & 7)) { - len -= stuffing; - pDataIn += stuffing; - } - } - if (len <= 0) { - return S_FALSE; - } - if (*(DWORD*)pDataIn == 0xBB010000) { - len -= 4; - pDataIn += 4; - int hdrlen = ((pDataIn[0] << 8) | pDataIn[1]) + 2; - len -= hdrlen; - pDataIn += hdrlen; - } - if (len <= 0) { - return S_FALSE; - } - } - - if (!pDataIn || !pDataOut || len > size || len < 0) { - return S_FALSE; - } - - memcpy(pDataOut, pDataIn, std::min(len, size)); - pOut->SetActualDataLength(std::min(len, size)); - - return S_OK; -} - -HRESULT CDeCSSFilter::CheckInputType(const CMediaType* mtIn) -{ - return mtIn->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CDeCSSFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return SUCCEEDED(CheckInputType(mtIn)) - && mtOut->majortype == MEDIATYPE_MPEG2_PACK || mtOut->majortype == MEDIATYPE_MPEG2_PES - ? S_OK - : VFW_E_TYPE_NOT_ACCEPTED; -} - -HRESULT CDeCSSFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - pProperties->cbAlign = 1; - pProperties->cBuffers = 1; - pProperties->cbBuffer = 2048; - pProperties->cbPrefix = 0; - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -HRESULT CDeCSSFilter::GetMediaType(int iPosition, CMediaType* pmt) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 1) { - return VFW_S_NO_MORE_ITEMS; - } - - CopyMediaType(pmt, &m_pInput->CurrentMediaType()); - if (iPosition == 0) { - pmt->majortype = MEDIATYPE_MPEG2_PACK; - } - if (iPosition == 1) { - pmt->majortype = MEDIATYPE_MPEG2_PES; - } - - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "DeCSSFilter.h" +#include "../../../DeCSS/DeCSSInputPin.h" +#include "../../../DSUtil/DSUtil.h" + +#ifdef STANDALONE_FILTER + +#include +#include "moreuuids.h" + +const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { + {&MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { + {&MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_NULL}, + {&MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_NULL}, +}; + +const AMOVIESETUP_PIN sudpPins[] = { + {const_cast(L"Input"), FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn}, + {const_cast(L"Output"), FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut} +}; + +const AMOVIESETUP_FILTER sudFilter[] = { + {&__uuidof(CDeCSSFilter), DeCSSFilterName, MERIT_DO_NOT_USE, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, +}; + +CFactoryTemplate g_Templates[] = { + {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, +}; + +int g_cTemplates = _countof(g_Templates); + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2(TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2(FALSE); +} + +#include "../../FilterApp.h" + +CFilterApp theApp; + +#endif + +// +// CDeCSSFilter +// + +class CKsPSInputPin : public CDeCSSInputPin +{ +public: + CKsPSInputPin(LPCTSTR pObjectName, CTransformFilter* pFilter, HRESULT* phr, LPCWSTR pName) + : CDeCSSInputPin(pObjectName, pFilter, phr, pName) { + } + + // IKsPropertySet + STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength) { + if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { + return pKsPS->Set(PropSet, Id, InstanceData, InstanceLength, PropertyData, DataLength); + } + return E_NOTIMPL; + } + STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID InstanceData, ULONG InstanceLength, LPVOID PropertyData, ULONG DataLength, ULONG* pBytesReturned) { + if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { + return pKsPS->Get(PropSet, Id, InstanceData, InstanceLength, PropertyData, DataLength, pBytesReturned); + } + return E_NOTIMPL; + } + STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport) { + if (CComQIPtr pKsPS = (static_cast(m_pFilter))->m_pOutput->GetConnected()) { + return pKsPS->QuerySupported(PropSet, Id, pTypeSupport); + } + return E_NOTIMPL; + } +}; + +CDeCSSFilter::CDeCSSFilter(LPUNKNOWN lpunk, HRESULT* phr) + : CTransformFilter(NAME("CDeCSSFilter"), lpunk, __uuidof(this)) +{ + HRESULT hr; + if (!phr) { + phr = &hr; + } + *phr = S_OK; + + m_pInput = DEBUG_NEW CKsPSInputPin(NAME("CKsPSInputPin"), this, phr, L"In"); + if (!m_pInput) { + *phr = E_OUTOFMEMORY; + } + if (FAILED(*phr)) { + return; + } + + m_pOutput = DEBUG_NEW CTransformOutputPin(NAME("CTransformOutputPin"), this, phr, L"Out"); + if (!m_pOutput) { + *phr = E_OUTOFMEMORY; + } + if (FAILED(*phr)) { + delete m_pInput; + m_pInput = nullptr; + return; + } +} + +CDeCSSFilter::~CDeCSSFilter() +{ +} + +HRESULT CDeCSSFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + AM_MEDIA_TYPE* pmt; + if (SUCCEEDED(pIn->GetMediaType(&pmt)) && pmt) { + CMediaType mt = *pmt; + m_pInput->SetMediaType(&mt); + mt.majortype = m_pOutput->CurrentMediaType().majortype; + m_pOutput->SetMediaType(&mt); + pOut->SetMediaType(&mt); + DeleteMediaType(pmt); + } + + BYTE* pDataIn = nullptr; + BYTE* pDataOut = nullptr; + + HRESULT hr; + if (FAILED(hr = pIn->GetPointer(&pDataIn)) || FAILED(hr = pOut->GetPointer(&pDataOut))) { + return hr; + } + + long len = pIn->GetActualDataLength(); + long size = pOut->GetSize(); + + if (len == 0 || pDataIn == nullptr) { // format changes do not carry any data + pOut->SetActualDataLength(0); + return S_OK; + } + + if (m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES) { + if (*(DWORD*)pDataIn == 0xBA010000) { + len -= 14; + pDataIn += 14; + if (int stuffing = (pDataIn[-1] & 7)) { + len -= stuffing; + pDataIn += stuffing; + } + } + if (len <= 0) { + return S_FALSE; + } + if (*(DWORD*)pDataIn == 0xBB010000) { + len -= 4; + pDataIn += 4; + int hdrlen = ((pDataIn[0] << 8) | pDataIn[1]) + 2; + len -= hdrlen; + pDataIn += hdrlen; + } + if (len <= 0) { + return S_FALSE; + } + } + + if (!pDataIn || !pDataOut || len > size || len < 0) { + return S_FALSE; + } + + memcpy(pDataOut, pDataIn, std::min(len, size)); + pOut->SetActualDataLength(std::min(len, size)); + + return S_OK; +} + +HRESULT CDeCSSFilter::CheckInputType(const CMediaType* mtIn) +{ + return mtIn->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CDeCSSFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return SUCCEEDED(CheckInputType(mtIn)) + && mtOut->majortype == MEDIATYPE_MPEG2_PACK || mtOut->majortype == MEDIATYPE_MPEG2_PES + ? S_OK + : VFW_E_TYPE_NOT_ACCEPTED; +} + +HRESULT CDeCSSFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + pProperties->cbAlign = 1; + pProperties->cBuffers = 1; + pProperties->cbBuffer = 2048; + pProperties->cbPrefix = 0; + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +HRESULT CDeCSSFilter::GetMediaType(int iPosition, CMediaType* pmt) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 1) { + return VFW_S_NO_MORE_ITEMS; + } + + CopyMediaType(pmt, &m_pInput->CurrentMediaType()); + if (iPosition == 0) { + pmt->majortype = MEDIATYPE_MPEG2_PACK; + } + if (iPosition == 1) { + pmt->majortype = MEDIATYPE_MPEG2_PES; + } + + return S_OK; +} diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.def b/src/filters/transform/DeCSSFilter/DeCSSFilter.def index 8b4dcdde858..6492e5cd656 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.def +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.def @@ -1,5 +1,5 @@ -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.h b/src/filters/transform/DeCSSFilter/DeCSSFilter.h index ed1fd9f9848..0b800efc48a 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.h +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.h @@ -1,40 +1,40 @@ -/* - * (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 . - * - */ - -#pragma once - -#define DeCSSFilterName L"MPC-HC DeCSSFilter" - -class __declspec(uuid("7B3BD419-FE03-4820-BE94-A22A4F844895")) - CDeCSSFilter : public CTransformFilter -{ - friend class CKsPSInputPin; - -public: - CDeCSSFilter(LPUNKNOWN lpunk, HRESULT* phr); - virtual ~CDeCSSFilter(); - - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); -}; +/* + * (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 . + * + */ + +#pragma once + +#define DeCSSFilterName L"MPC-HC DeCSSFilter" + +class __declspec(uuid("7B3BD419-FE03-4820-BE94-A22A4F844895")) + CDeCSSFilter : public CTransformFilter +{ + friend class CKsPSInputPin; + +public: + CDeCSSFilter(LPUNKNOWN lpunk, HRESULT* phr); + virtual ~CDeCSSFilter(); + + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); +}; diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.rc b/src/filters/transform/DeCSSFilter/DeCSSFilter.rc index 90940bdec22..152af2b3855 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.rc +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.rc @@ -1,102 +1,102 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", MPC_VERSION_COMMENTS - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "DeCSSFilter" - VALUE "FileVersion", MPC_VERSION_STR_FULL - VALUE "InternalName", "DeCSSFilter" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "DeCSSFilter.ax" - VALUE "ProductName", "DeCSSFilter" - VALUE "ProductVersion", MPC_VERSION_STR_FULL - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", MPC_VERSION_COMMENTS + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "DeCSSFilter" + VALUE "FileVersion", MPC_VERSION_STR_FULL + VALUE "InternalName", "DeCSSFilter" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "DeCSSFilter.ax" + VALUE "ProductName", "DeCSSFilter" + VALUE "ProductVersion", MPC_VERSION_STR_FULL + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj b/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj index be71938ac84..7b5f000b9e1 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj @@ -1,117 +1,117 @@ - - - - - Debug Filter - Win32 - - - Debug Filter - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Filter - Win32 - - - Release Filter - x64 - - - Release - Win32 - - - Release - x64 - - - - {F6B06383-3FFD-403B-9867-4AA82A20AA83} - DeCSSFilter - MFCProj - DeCSSFilter - - - - - StaticLibrary - Static - Unicode - - - DynamicLibrary - - - - - - - - - - - .ax - - - - ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) - - - - - _LIB;%(PreprocessorDefinitions) - - - - - DeCSSFilter.def - - - ..\..\..\..\include;%(AdditionalIncludeDirectories) - - - - - - Create - - - - - - - - - true - - - - - - true - - - - - {1a2dfd1a-3c6c-44d1-909d-294af646b575} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - - - + + + + + Debug Filter + Win32 + + + Debug Filter + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Filter + Win32 + + + Release Filter + x64 + + + Release + Win32 + + + Release + x64 + + + + {F6B06383-3FFD-403B-9867-4AA82A20AA83} + DeCSSFilter + MFCProj + DeCSSFilter + + + + + StaticLibrary + Static + Unicode + + + DynamicLibrary + + + + + + + + + + + .ax + + + + ..\..\..\..\include;..\..\..\thirdparty;%(AdditionalIncludeDirectories) + + + + + _LIB;%(PreprocessorDefinitions) + + + + + DeCSSFilter.def + + + ..\..\..\..\include;%(AdditionalIncludeDirectories) + + + + + + Create + + + + + + + + + true + + + + + + true + + + + + {1a2dfd1a-3c6c-44d1-909d-294af646b575} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + + + \ No newline at end of file diff --git a/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj.filters b/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj.filters index da5ab1f53ea..f5eda45944c 100644 --- a/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj.filters +++ b/src/filters/transform/DeCSSFilter/DeCSSFilter.vcxproj.filters @@ -1,45 +1,45 @@ - - - - - {8b808ee2-0f72-4075-8ecb-82a22d4466ae} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {f3d45f80-2532-40ae-894e-b22166f99365} - h;hpp;hxx;hm;inl;inc - - - {21573b71-7374-4d8d-9e54-3e990fae2c15} - - - - - Source Files - - - Source Files - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - + + + + + {8b808ee2-0f72-4075-8ecb-82a22d4466ae} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {f3d45f80-2532-40ae-894e-b22166f99365} + h;hpp;hxx;hm;inl;inc + + + {21573b71-7374-4d8d-9e54-3e990fae2c15} + + + + + Source Files + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + \ No newline at end of file diff --git a/src/filters/transform/DeCSSFilter/resource.h b/src/filters/transform/DeCSSFilter/resource.h index a84767ddee6..e745510abb1 100644 --- a/src/filters/transform/DeCSSFilter/resource.h +++ b/src/filters/transform/DeCSSFilter/resource.h @@ -1,14 +1,14 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by DeCSSFilter.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DeCSSFilter.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/filters/transform/DeCSSFilter/stdafx.cpp b/src/filters/transform/DeCSSFilter/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/filters/transform/DeCSSFilter/stdafx.cpp +++ b/src/filters/transform/DeCSSFilter/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/filters/transform/DeCSSFilter/stdafx.h b/src/filters/transform/DeCSSFilter/stdafx.h index 12bbe2db0a7..d8320f2c878 100644 --- a/src/filters/transform/DeCSSFilter/stdafx.h +++ b/src/filters/transform/DeCSSFilter/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "../../../DSUtil/SharedInclude.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include -#include // MFC core and standard components - -#include "BaseClasses/streams.h" -#include +/* + * (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 . + * + */ + +#pragma once + +#include "../../../DSUtil/SharedInclude.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include // MFC core and standard components + +#include "BaseClasses/streams.h" +#include diff --git a/src/filters/transform/VSFilter/IDirectVobSub.h b/src/filters/transform/VSFilter/IDirectVobSub.h index dccd0880cf1..9d4a6f65305 100644 --- a/src/filters/transform/VSFilter/IDirectVobSub.h +++ b/src/filters/transform/VSFilter/IDirectVobSub.h @@ -1,194 +1,194 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#pragma once - -#include "../../../Subtitles/STS.h" - -#ifdef __cplusplus -extern "C" { -#endif - -interface __declspec(uuid("EBE1FB08-3957-47ca-AF13-5827E5442E56")) - IDirectVobSub : - public IUnknown -{ - STDMETHOD(get_FileName)(THIS_ WCHAR* fn) PURE; // fn should point to a buffer allocated to at least the length of MAX_PATH (=260) - - STDMETHOD(put_FileName)(THIS_ WCHAR* fn) PURE; - - STDMETHOD(get_LanguageCount)(THIS_ int* nLangs) PURE; - - STDMETHOD(get_LanguageName)(THIS_ int iLanguage, WCHAR** ppName) PURE; // the returned *ppName is allocated with CoTaskMemAlloc - - STDMETHOD(get_SelectedLanguage)(THIS_ int* iSelected) PURE; - - STDMETHOD(put_SelectedLanguage)(THIS_ int iSelected) PURE; - - STDMETHOD(get_HideSubtitles)(THIS_ bool* fHideSubtitles) PURE; - - STDMETHOD(put_HideSubtitles)(THIS_ bool fHideSubtitles) PURE; - - // deprecated - STDMETHOD(get_PreBuffering)(THIS_ bool* fDoPreBuffering) PURE; - - // deprecated - STDMETHOD(put_PreBuffering)(THIS_ bool fDoPreBuffering) PURE; - - STDMETHOD(get_Placement)(THIS_ bool* fOverridePlacement, int* xperc, int* yperc) PURE; - - STDMETHOD(put_Placement)(THIS_ bool fOverridePlacement, int xperc, int yperc) PURE; - - STDMETHOD(get_VobSubSettings)(THIS_ bool* fBuffer, bool* fOnlyShowForcedSubs, bool* fPolygonize) PURE; - - STDMETHOD(put_VobSubSettings)(THIS_ bool fBuffer, bool fOnlyShowForcedSubs, bool fPolygonize) PURE; - - // depending on lflen, lf must point to LOGFONTA or LOGFONTW - STDMETHOD(get_TextSettings)(THIS_ void* lf, int lflen, COLORREF* color, bool* fShadow, bool* fOutline, bool* fAdvancedRenderer) PURE; - - STDMETHOD(put_TextSettings)(THIS_ void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer) PURE; - - STDMETHOD(get_Flip)(THIS_ bool* fPicture, bool* fSubtitles) PURE; - - STDMETHOD(put_Flip)(THIS_ bool fPicture, bool fSubtitles) PURE; - - STDMETHOD(get_OSD)(THIS_ bool* fOSD) PURE; - - STDMETHOD(put_OSD)(THIS_ bool fOSD) PURE; - - STDMETHOD(get_SaveFullPath)(THIS_ bool* fSaveFullPath) PURE; - - STDMETHOD(put_SaveFullPath)(THIS_ bool fSaveFullPath) PURE; - - STDMETHOD(get_SubtitleTiming)(THIS_ int* delay, int* speedmul, int* speeddiv) PURE; - - STDMETHOD(put_SubtitleTiming)(THIS_ int delay, int speedmul, int speeddiv) PURE; - - STDMETHOD(get_MediaFPS)(THIS_ bool* fEnabled, double* fps) PURE; - - STDMETHOD(put_MediaFPS)(THIS_ bool fEnabled, double fps) PURE; - - // no longer supported - - STDMETHOD(get_ColorFormat)(THIS_ int* iPosition) PURE; - - STDMETHOD(put_ColorFormat)(THIS_ int iPosition) PURE; - - - STDMETHOD(get_ZoomRect)(THIS_ NORMALIZEDRECT* rect) PURE; - - STDMETHOD(put_ZoomRect)(THIS_ NORMALIZEDRECT* rect) PURE; - - - STDMETHOD(UpdateRegistry)(THIS_) PURE; - - - STDMETHOD(HasConfigDialog)(THIS_ int iSelected) PURE; - - STDMETHOD(ShowConfigDialog)(THIS_ int iSelected, HWND hWndParent) PURE; // if available, this will popup a child dialog allowing the user to edit the style options - - - STDMETHOD(IsSubtitleReloaderLocked)(THIS_ bool* fLocked) PURE; - - STDMETHOD(LockSubtitleReloader)(THIS_ bool fLock) PURE; - - STDMETHOD(get_SubtitleReloader)(THIS_ bool* fDisabled) PURE; - - STDMETHOD(put_SubtitleReloader)(THIS_ bool fDisable) PURE; - - // horizontal: 0 - disabled, 1 - mod32 extension (width = (width + 31) & ~31) - // vertical: 0 - disabled, 1 - 16:9, 2 - 4:3, 0x80 - crop (use crop together with 16:9 or 4:3, eg 0x81 will crop to 16:9 if the picture was taller) - // resx2: 0 - disabled, 1 - enabled, 2 - depends on the original resolution - // resx2minw: resolution doubler will be used if width * height <= resx2minw * resx2minh (resx2minw * resx2minh equals to 384 * 288 by default) - STDMETHOD(get_ExtendPicture)(THIS_ int* horizontal, int* vertical, int* resx2, int* resx2minw, int* resx2minh) PURE; - - STDMETHOD(put_ExtendPicture)(THIS_ int horizontal, int vertical, int resx2, int resx2minw, int resx2minh) PURE; - - // level: 0 - when needed, 1 - always, 2 - disabled - STDMETHOD(get_LoadSettings)(THIS_ int* level, bool* fExternalLoad, bool* fWebLoad, bool* fEmbeddedLoad) PURE; - - STDMETHOD(put_LoadSettings)(THIS_ int level, bool fExternalLoad, bool fWebLoad, bool fEmbeddedLoad) PURE; - - STDMETHOD(get_SubPictToBuffer)(THIS_ unsigned int* uSubPictToBuffer) PURE; - - STDMETHOD(put_SubPictToBuffer)(THIS_ unsigned int uSubPictToBuffer) PURE; - - STDMETHOD(get_AnimWhenBuffering)(THIS_ bool* fAnimWhenBuffering) PURE; - - STDMETHOD(put_AnimWhenBuffering)(THIS_ bool fAnimWhenBuffering) PURE; -}; - -interface __declspec(uuid("FE6EC6A0-21CA-4970-9EF0-B296F7F38AF0")) - ISubClock : - public IUnknown -{ - STDMETHOD(SetTime)(REFERENCE_TIME rt) PURE; - STDMETHOD_(REFERENCE_TIME, GetTime)() PURE; -}; - -interface __declspec(uuid("0665B760-FBC1-46C3-A35F-E471527C96A4")) - ISubClock2 : - public ISubClock -{ - STDMETHOD(SetAvgTimePerFrame)(REFERENCE_TIME rt) PURE; - STDMETHOD(GetAvgTimePerFrame)(REFERENCE_TIME* prt) PURE; // return S_OK only if *prt was set and is valid -}; - -interface __declspec(uuid("AB52FC9C-2415-4dca-BC1C-8DCC2EAE8150")) - IDirectVobSub2 : - public IDirectVobSub -{ - STDMETHOD(AdviseSubClock)(THIS_ ISubClock* pSubClock) PURE; - - STDMETHOD_(bool, get_Forced)(THIS_) PURE; - - STDMETHOD(put_Forced)(THIS_ bool fForced) PURE; - - STDMETHOD(get_TextSettings)(THIS_ STSStyle* pDefStyle) PURE; - - STDMETHOD(put_TextSettings)(THIS_ STSStyle* pDefStyle) PURE; - - STDMETHOD(get_AspectRatioSettings)(THIS_ CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType) PURE; - - STDMETHOD(put_AspectRatioSettings)(THIS_ CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType) PURE; -}; - -interface __declspec(uuid("4484A031-713F-4893-8C24-4505C56E8915")) - IDirectVobSub3 : - public IDirectVobSub2 -{ - STDMETHOD_(bool, get_DisableSubtitleAnimation)(THIS_) PURE; - STDMETHOD(put_DisableSubtitleAnimation)(THIS_ bool bDisableSubtitleAnimation) PURE; - - STDMETHOD_(int, get_RenderAtWhenAnimationIsDisabled)(THIS_) PURE; - STDMETHOD(put_RenderAtWhenAnimationIsDisabled)(THIS_ int nRenderAtWhenAnimationIsDisabled) PURE; - - STDMETHOD_(int, get_AnimationRate)(THIS_) PURE; - STDMETHOD(put_AnimationRate)(THIS_ int nAnimationRate) PURE; - - STDMETHOD_(bool, get_AllowDroppingSubpic)(THIS_) PURE; - STDMETHOD(put_AllowDroppingSubpic)(THIS_ bool bAllowDroppingSubpic) PURE; -}; - - -#ifdef __cplusplus -} -#endif +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#pragma once + +#include "../../../Subtitles/STS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +interface __declspec(uuid("EBE1FB08-3957-47ca-AF13-5827E5442E56")) + IDirectVobSub : + public IUnknown +{ + STDMETHOD(get_FileName)(THIS_ WCHAR* fn) PURE; // fn should point to a buffer allocated to at least the length of MAX_PATH (=260) + + STDMETHOD(put_FileName)(THIS_ WCHAR* fn) PURE; + + STDMETHOD(get_LanguageCount)(THIS_ int* nLangs) PURE; + + STDMETHOD(get_LanguageName)(THIS_ int iLanguage, WCHAR** ppName) PURE; // the returned *ppName is allocated with CoTaskMemAlloc + + STDMETHOD(get_SelectedLanguage)(THIS_ int* iSelected) PURE; + + STDMETHOD(put_SelectedLanguage)(THIS_ int iSelected) PURE; + + STDMETHOD(get_HideSubtitles)(THIS_ bool* fHideSubtitles) PURE; + + STDMETHOD(put_HideSubtitles)(THIS_ bool fHideSubtitles) PURE; + + // deprecated + STDMETHOD(get_PreBuffering)(THIS_ bool* fDoPreBuffering) PURE; + + // deprecated + STDMETHOD(put_PreBuffering)(THIS_ bool fDoPreBuffering) PURE; + + STDMETHOD(get_Placement)(THIS_ bool* fOverridePlacement, int* xperc, int* yperc) PURE; + + STDMETHOD(put_Placement)(THIS_ bool fOverridePlacement, int xperc, int yperc) PURE; + + STDMETHOD(get_VobSubSettings)(THIS_ bool* fBuffer, bool* fOnlyShowForcedSubs, bool* fPolygonize) PURE; + + STDMETHOD(put_VobSubSettings)(THIS_ bool fBuffer, bool fOnlyShowForcedSubs, bool fPolygonize) PURE; + + // depending on lflen, lf must point to LOGFONTA or LOGFONTW + STDMETHOD(get_TextSettings)(THIS_ void* lf, int lflen, COLORREF* color, bool* fShadow, bool* fOutline, bool* fAdvancedRenderer) PURE; + + STDMETHOD(put_TextSettings)(THIS_ void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer) PURE; + + STDMETHOD(get_Flip)(THIS_ bool* fPicture, bool* fSubtitles) PURE; + + STDMETHOD(put_Flip)(THIS_ bool fPicture, bool fSubtitles) PURE; + + STDMETHOD(get_OSD)(THIS_ bool* fOSD) PURE; + + STDMETHOD(put_OSD)(THIS_ bool fOSD) PURE; + + STDMETHOD(get_SaveFullPath)(THIS_ bool* fSaveFullPath) PURE; + + STDMETHOD(put_SaveFullPath)(THIS_ bool fSaveFullPath) PURE; + + STDMETHOD(get_SubtitleTiming)(THIS_ int* delay, int* speedmul, int* speeddiv) PURE; + + STDMETHOD(put_SubtitleTiming)(THIS_ int delay, int speedmul, int speeddiv) PURE; + + STDMETHOD(get_MediaFPS)(THIS_ bool* fEnabled, double* fps) PURE; + + STDMETHOD(put_MediaFPS)(THIS_ bool fEnabled, double fps) PURE; + + // no longer supported + + STDMETHOD(get_ColorFormat)(THIS_ int* iPosition) PURE; + + STDMETHOD(put_ColorFormat)(THIS_ int iPosition) PURE; + + + STDMETHOD(get_ZoomRect)(THIS_ NORMALIZEDRECT* rect) PURE; + + STDMETHOD(put_ZoomRect)(THIS_ NORMALIZEDRECT* rect) PURE; + + + STDMETHOD(UpdateRegistry)(THIS_) PURE; + + + STDMETHOD(HasConfigDialog)(THIS_ int iSelected) PURE; + + STDMETHOD(ShowConfigDialog)(THIS_ int iSelected, HWND hWndParent) PURE; // if available, this will popup a child dialog allowing the user to edit the style options + + + STDMETHOD(IsSubtitleReloaderLocked)(THIS_ bool* fLocked) PURE; + + STDMETHOD(LockSubtitleReloader)(THIS_ bool fLock) PURE; + + STDMETHOD(get_SubtitleReloader)(THIS_ bool* fDisabled) PURE; + + STDMETHOD(put_SubtitleReloader)(THIS_ bool fDisable) PURE; + + // horizontal: 0 - disabled, 1 - mod32 extension (width = (width + 31) & ~31) + // vertical: 0 - disabled, 1 - 16:9, 2 - 4:3, 0x80 - crop (use crop together with 16:9 or 4:3, eg 0x81 will crop to 16:9 if the picture was taller) + // resx2: 0 - disabled, 1 - enabled, 2 - depends on the original resolution + // resx2minw: resolution doubler will be used if width * height <= resx2minw * resx2minh (resx2minw * resx2minh equals to 384 * 288 by default) + STDMETHOD(get_ExtendPicture)(THIS_ int* horizontal, int* vertical, int* resx2, int* resx2minw, int* resx2minh) PURE; + + STDMETHOD(put_ExtendPicture)(THIS_ int horizontal, int vertical, int resx2, int resx2minw, int resx2minh) PURE; + + // level: 0 - when needed, 1 - always, 2 - disabled + STDMETHOD(get_LoadSettings)(THIS_ int* level, bool* fExternalLoad, bool* fWebLoad, bool* fEmbeddedLoad) PURE; + + STDMETHOD(put_LoadSettings)(THIS_ int level, bool fExternalLoad, bool fWebLoad, bool fEmbeddedLoad) PURE; + + STDMETHOD(get_SubPictToBuffer)(THIS_ unsigned int* uSubPictToBuffer) PURE; + + STDMETHOD(put_SubPictToBuffer)(THIS_ unsigned int uSubPictToBuffer) PURE; + + STDMETHOD(get_AnimWhenBuffering)(THIS_ bool* fAnimWhenBuffering) PURE; + + STDMETHOD(put_AnimWhenBuffering)(THIS_ bool fAnimWhenBuffering) PURE; +}; + +interface __declspec(uuid("FE6EC6A0-21CA-4970-9EF0-B296F7F38AF0")) + ISubClock : + public IUnknown +{ + STDMETHOD(SetTime)(REFERENCE_TIME rt) PURE; + STDMETHOD_(REFERENCE_TIME, GetTime)() PURE; +}; + +interface __declspec(uuid("0665B760-FBC1-46C3-A35F-E471527C96A4")) + ISubClock2 : + public ISubClock +{ + STDMETHOD(SetAvgTimePerFrame)(REFERENCE_TIME rt) PURE; + STDMETHOD(GetAvgTimePerFrame)(REFERENCE_TIME* prt) PURE; // return S_OK only if *prt was set and is valid +}; + +interface __declspec(uuid("AB52FC9C-2415-4dca-BC1C-8DCC2EAE8150")) + IDirectVobSub2 : + public IDirectVobSub +{ + STDMETHOD(AdviseSubClock)(THIS_ ISubClock* pSubClock) PURE; + + STDMETHOD_(bool, get_Forced)(THIS_) PURE; + + STDMETHOD(put_Forced)(THIS_ bool fForced) PURE; + + STDMETHOD(get_TextSettings)(THIS_ STSStyle* pDefStyle) PURE; + + STDMETHOD(put_TextSettings)(THIS_ STSStyle* pDefStyle) PURE; + + STDMETHOD(get_AspectRatioSettings)(THIS_ CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType) PURE; + + STDMETHOD(put_AspectRatioSettings)(THIS_ CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType) PURE; +}; + +interface __declspec(uuid("4484A031-713F-4893-8C24-4505C56E8915")) + IDirectVobSub3 : + public IDirectVobSub2 +{ + STDMETHOD_(bool, get_DisableSubtitleAnimation)(THIS_) PURE; + STDMETHOD(put_DisableSubtitleAnimation)(THIS_ bool bDisableSubtitleAnimation) PURE; + + STDMETHOD_(int, get_RenderAtWhenAnimationIsDisabled)(THIS_) PURE; + STDMETHOD(put_RenderAtWhenAnimationIsDisabled)(THIS_ int nRenderAtWhenAnimationIsDisabled) PURE; + + STDMETHOD_(int, get_AnimationRate)(THIS_) PURE; + STDMETHOD(put_AnimationRate)(THIS_ int nAnimationRate) PURE; + + STDMETHOD_(bool, get_AllowDroppingSubpic)(THIS_) PURE; + STDMETHOD(put_AllowDroppingSubpic)(THIS_ bool bAllowDroppingSubpic) PURE; +}; + + +#ifdef __cplusplus +} +#endif diff --git a/src/mpc-hc/AboutDlg.cpp b/src/mpc-hc/AboutDlg.cpp index bcce29e8329..2c31af5a483 100644 --- a/src/mpc-hc/AboutDlg.cpp +++ b/src/mpc-hc/AboutDlg.cpp @@ -1,340 +1,340 @@ -/* - * (C) 2012-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "AboutDlg.h" -#include "mpc-hc_config.h" -#ifndef MPCHC_LITE -#include "FGFilterLAV.h" -#endif -#include "mplayerc.h" -#include "FileVersionInfo.h" -#include "PathUtils.h" -#include "VersionInfo.h" -#include -#include "Monitors.h" - - -///////////////////////////////////////////////////////////////////////////// -// CAboutDlg dialog used for App About - -CAboutDlg::CAboutDlg() : CMPCThemeDialog(CAboutDlg::IDD, NULL) -{ - //{{AFX_DATA_INIT(CAboutDlg) - //}}AFX_DATA_INIT -} - -CAboutDlg::~CAboutDlg() -{ -} - -BOOL CAboutDlg::OnInitDialog() -{ - // Get the default text before it is overwritten by the call to __super::OnInitDialog() -#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)); - - m_appname = _T("MPC-HC"); - if (VersionInfo::Is64Bit()) { - m_appname += _T(" (64-bit)"); - } -#ifdef MPCHC_LITE - m_appname += _T(" (Lite)"); -#endif -#ifdef _DEBUG - m_appname += _T(" (Debug)"); -#endif - - m_homepage.Format(_T("%s"), WEBSITE_URL); - - m_strBuildNumber = VersionInfo::GetFullVersionString(); - - m_LAVFilters.Format(IDS_STRING_COLON, _T("LAV Filters")); -#ifndef MPCHC_LITE - CString LAVFiltersVersion = CFGFilterLAV::GetVersion(); - if (!LAVFiltersVersion.IsEmpty()) { - m_LAVFiltersVersion = LAVFiltersVersion; - } -#endif - - m_buildDate = VersionInfo::GetBuildDateString(); - -#pragma warning(push) -#pragma warning(disable: 4996) - OSVERSIONINFOEX osVersion = { sizeof(OSVERSIONINFOEX) }; - GetVersionEx(reinterpret_cast(&osVersion)); -#pragma warning(pop) - - if (osVersion.dwMajorVersion == 10 && osVersion.dwMinorVersion == 0) { - if (IsWindowsServer()) { - if (osVersion.dwBuildNumber > 20348) { - m_OSName = _T("Windows Server"); - } else if (osVersion.dwBuildNumber == 20348) { - m_OSName = _T("Windows Server 2022"); - } else if (osVersion.dwBuildNumber >= 19042) { - m_OSName = _T("Windows Server, version 20H2"); - } else if (osVersion.dwBuildNumber >= 19041) { - m_OSName = _T("Windows Server, version 2004"); - } else if (osVersion.dwBuildNumber >= 18363) { - m_OSName = _T("Windows Server, version 1909"); - } else if (osVersion.dwBuildNumber >= 18362) { - m_OSName = _T("Windows Server, version 1903"); - } else if (osVersion.dwBuildNumber >= 17763) { - m_OSName = _T("Windows Server 2019"); - } else { - m_OSName = _T("Windows Server 2016"); - } - } else { - if (osVersion.dwBuildNumber > 22631) { - m_OSName = _T("Windows 11"); - } else if (osVersion.dwBuildNumber == 22631) { - m_OSName = _T("Windows 11 (Build 23H2)"); - } else if (osVersion.dwBuildNumber >= 22621) { - m_OSName = _T("Windows 11 (Build 22H2)"); - } else if (osVersion.dwBuildNumber >= 22000) { - m_OSName = _T("Windows 11 (Build 21H2)"); - } else if (osVersion.dwBuildNumber >= 19046) { - m_OSName = _T("Windows 10"); - } else if (osVersion.dwBuildNumber == 19045) { - m_OSName = _T("Windows 10 (Build 22H2)"); - } else if (osVersion.dwBuildNumber == 19044) { - m_OSName = _T("Windows 10 (Build 21H2)"); - } else if (osVersion.dwBuildNumber == 19043) { - m_OSName = _T("Windows 10 (Build 21H1)"); - } else if (osVersion.dwBuildNumber == 19042) { - m_OSName = _T("Windows 10 (Build 20H2)"); - } else if (osVersion.dwBuildNumber == 19041) { - m_OSName = _T("Windows 10 (Build 2004)"); - } else if (osVersion.dwBuildNumber >= 18363) { - m_OSName = _T("Windows 10 (Build 1909)"); - } else if (osVersion.dwBuildNumber == 18362) { - m_OSName = _T("Windows 10 (Build 1903)"); - } else if (osVersion.dwBuildNumber >= 17763) { - m_OSName = _T("Windows 10 (Build 1809)"); - } else if (osVersion.dwBuildNumber >= 17134) { - m_OSName = _T("Windows 10 (Build 1803)"); - } else if (osVersion.dwBuildNumber >= 16299) { - m_OSName = _T("Windows 10 (Build 1709)"); - } else if (osVersion.dwBuildNumber >= 15063) { - m_OSName = _T("Windows 10 (Build 1703)"); - } else if (osVersion.dwBuildNumber >= 14393) { - m_OSName = _T("Windows 10 (Build 1607)"); - } else if (osVersion.dwBuildNumber >= 10586) { - m_OSName = _T("Windows 10 (Build 1511)"); - } else if (osVersion.dwBuildNumber >= 10240) { - m_OSName = _T("Windows 10 (Build 1507)"); - } else { - m_OSName = _T("Windows 10"); - } - } - } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 3) { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server 2012 R2"); - } else { - m_OSName = _T("Windows 8.1"); - } - } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 2) { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server 2012"); - } else { - m_OSName = _T("Windows 8"); - } - } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 1) { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server 2008 R2"); - } else { - m_OSName = _T("Windows 7"); - } - } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 0) { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server 2008"); - } else { - m_OSName = _T("Windows Vista"); - } - } else { - if (IsWindowsServer()) { - m_OSName = _T("Windows Server"); - } else { - m_OSName = _T("Windows NT"); - } - } - if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion < 2 && osVersion.szCSDVersion[0]) { - m_OSName.AppendFormat(_T(" (%s)"), osVersion.szCSDVersion); - } - m_OSVersion.Format(_T("%1u.%1u.%u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber); - -#if !defined(_WIN64) - // 32-bit programs run on both 32-bit and 64-bit Windows - // so must sniff - BOOL f64 = FALSE; - if (IsWow64Process(GetCurrentProcess(), &f64) && f64) -#endif - { - m_OSVersion += _T(" (64-bit)"); - } - - UpdateData(FALSE); - - GetDlgItem(IDOK)->SetFocus(); - fulfillThemeReqs(); - - 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_HOMEPAGE_LINK, m_homepage); - DDX_Text(pDX, IDC_VERSION, m_strBuildNumber); - DDX_Text(pDX, IDC_STATIC5, m_LAVFilters); -#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, CMPCThemeDialog) - //{{AFX_MSG_MAP(CAboutDlg) - // No message handlers - //}}AFX_MSG_MAP - ON_NOTIFY(NM_CLICK, IDC_HOMEPAGE_LINK, OnHomepage) - 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::OnCopyToClipboard() -{ - CStringW info = m_appname + _T("\r\n"); - info += CString(_T('-'), m_appname.GetLength()) + _T("\r\n\r\n"); - info += _T("Build information:\r\n"); - info += _T(" Version: ") + m_strBuildNumber + _T("\r\n"); - info += _T(" Build date: ") + m_buildDate + _T("\r\n\r\n"); -#ifndef MPCHC_LITE - info += _T("LAV Filters:\r\n"); - info += _T(" LAV Splitter: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::SPLITTER) + _T("\r\n"); - info += _T(" LAV Video: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::VIDEO_DECODER) + _T("\r\n"); - info += _T(" LAV Audio: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::AUDIO_DECODER) + _T("\r\n"); - info += _T(" FFmpeg compiler: ") + VersionInfo::GetGCCVersion() + _T("\r\n\r\n"); -#endif - info += _T("Operating system:\r\n"); - info += _T(" Name: ") + m_OSName + _T("\r\n"); - info += _T(" Version: ") + m_OSVersion + _T("\r\n\r\n"); - - info += _T("Hardware:\r\n"); - - CRegKey key; - if (key.Open(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) { - ULONG nChars = 0; - if (key.QueryStringValue(_T("ProcessorNameString"), nullptr, &nChars) == ERROR_SUCCESS) { - CString cpuName; - if (key.QueryStringValue(_T("ProcessorNameString"), cpuName.GetBuffer(nChars), &nChars) == ERROR_SUCCESS) { - cpuName.ReleaseBuffer(nChars); - cpuName.Trim(); - info.AppendFormat(_T(" CPU: %s\r\n"), cpuName.GetString()); - } - } - } - - IDirect3D9* pD3D9 = Direct3DCreate9(D3D_SDK_VERSION); - if (pD3D9) { - for (UINT adapter = 0, adapterCount = pD3D9->GetAdapterCount(); adapter < adapterCount; adapter++) { - D3DADAPTER_IDENTIFIER9 adapterIdentifier; - if (pD3D9->GetAdapterIdentifier(adapter, 0, &adapterIdentifier) == D3D_OK) { - CString deviceName = adapterIdentifier.Description; - deviceName.Trim(); - - if (adapterCount > 1) { - info.AppendFormat(_T(" GPU%u: %s"), adapter + 1, deviceName.GetString()); - } else { - info.AppendFormat(_T(" GPU: %s"), deviceName.GetString()); - } - if (adapterIdentifier.DriverVersion.QuadPart) { - info.AppendFormat(_T(" (driver version: %s)"), - FileVersionInfo::FormatVersionString(adapterIdentifier.DriverVersion.LowPart, adapterIdentifier.DriverVersion.HighPart).GetString()); - } - info += _T("\r\n"); - } - } - pD3D9->Release(); - } - - auto &s = AfxGetAppSettings(); - CMonitors monitors; - - CStringW currentMonitorName; - monitors.GetNearestMonitor(AfxGetMainWnd()).GetName(currentMonitorName); - - CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); - - for (int i = 0; i < monitors.GetCount(); i++) { - CMonitor monitor = monitors.GetMonitor(i); - - if (monitor.IsMonitor()) { - CStringW displayName, deviceName; - monitor.GetNames(displayName, deviceName); - CStringW str = displayName; - - if (!deviceName.IsEmpty()) { - str.Append(L" - " + deviceName); - } - - int bpp = monitor.GetBitsPerPixel(); - CRect mr; - monitor.GetMonitorRect(mr); - int dpi = DpiHelper::GetDPIForMonitor(monitor); - CString dpis; - if (dpi > 0) { - dpis.Format(L" %i DPI", dpi); - } - str.AppendFormat(L" [%ix%i %i-bit%s]", mr.Width(), mr.Height(), bpp, dpis.GetString()); - if (displayName == currentMonitorName) { - str.AppendFormat(L" - [%s]", ResStr(IDS_FULLSCREENMONITOR_CURRENT).GetString()); - } - info.AppendFormat(L" Monitor: %s\r\n", str.GetString()); - } - } - info += _T("\r\nText:\r\n"); - double textScaleFactor = DpiHelper::GetTextScaleFactor(); - info.AppendFormat(L" Scale Factor: %f\r\n", textScaleFactor); - int cp = GetACP(); - info.AppendFormat(L" Ansi Codepage: %i\r\n", cp); - - CClipboard clipboard(this); - VERIFY(clipboard.SetText(info)); -} +/* + * (C) 2012-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "AboutDlg.h" +#include "mpc-hc_config.h" +#ifndef MPCHC_LITE +#include "FGFilterLAV.h" +#endif +#include "mplayerc.h" +#include "FileVersionInfo.h" +#include "PathUtils.h" +#include "VersionInfo.h" +#include +#include "Monitors.h" + + +///////////////////////////////////////////////////////////////////////////// +// CAboutDlg dialog used for App About + +CAboutDlg::CAboutDlg() : CMPCThemeDialog(CAboutDlg::IDD, NULL) +{ + //{{AFX_DATA_INIT(CAboutDlg) + //}}AFX_DATA_INIT +} + +CAboutDlg::~CAboutDlg() +{ +} + +BOOL CAboutDlg::OnInitDialog() +{ + // Get the default text before it is overwritten by the call to __super::OnInitDialog() +#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)); + + m_appname = _T("MPC-HC"); + if (VersionInfo::Is64Bit()) { + m_appname += _T(" (64-bit)"); + } +#ifdef MPCHC_LITE + m_appname += _T(" (Lite)"); +#endif +#ifdef _DEBUG + m_appname += _T(" (Debug)"); +#endif + + m_homepage.Format(_T("%s"), WEBSITE_URL); + + m_strBuildNumber = VersionInfo::GetFullVersionString(); + + m_LAVFilters.Format(IDS_STRING_COLON, _T("LAV Filters")); +#ifndef MPCHC_LITE + CString LAVFiltersVersion = CFGFilterLAV::GetVersion(); + if (!LAVFiltersVersion.IsEmpty()) { + m_LAVFiltersVersion = LAVFiltersVersion; + } +#endif + + m_buildDate = VersionInfo::GetBuildDateString(); + +#pragma warning(push) +#pragma warning(disable: 4996) + OSVERSIONINFOEX osVersion = { sizeof(OSVERSIONINFOEX) }; + GetVersionEx(reinterpret_cast(&osVersion)); +#pragma warning(pop) + + if (osVersion.dwMajorVersion == 10 && osVersion.dwMinorVersion == 0) { + if (IsWindowsServer()) { + if (osVersion.dwBuildNumber > 20348) { + m_OSName = _T("Windows Server"); + } else if (osVersion.dwBuildNumber == 20348) { + m_OSName = _T("Windows Server 2022"); + } else if (osVersion.dwBuildNumber >= 19042) { + m_OSName = _T("Windows Server, version 20H2"); + } else if (osVersion.dwBuildNumber >= 19041) { + m_OSName = _T("Windows Server, version 2004"); + } else if (osVersion.dwBuildNumber >= 18363) { + m_OSName = _T("Windows Server, version 1909"); + } else if (osVersion.dwBuildNumber >= 18362) { + m_OSName = _T("Windows Server, version 1903"); + } else if (osVersion.dwBuildNumber >= 17763) { + m_OSName = _T("Windows Server 2019"); + } else { + m_OSName = _T("Windows Server 2016"); + } + } else { + if (osVersion.dwBuildNumber > 22631) { + m_OSName = _T("Windows 11"); + } else if (osVersion.dwBuildNumber == 22631) { + m_OSName = _T("Windows 11 (Build 23H2)"); + } else if (osVersion.dwBuildNumber >= 22621) { + m_OSName = _T("Windows 11 (Build 22H2)"); + } else if (osVersion.dwBuildNumber >= 22000) { + m_OSName = _T("Windows 11 (Build 21H2)"); + } else if (osVersion.dwBuildNumber >= 19046) { + m_OSName = _T("Windows 10"); + } else if (osVersion.dwBuildNumber == 19045) { + m_OSName = _T("Windows 10 (Build 22H2)"); + } else if (osVersion.dwBuildNumber == 19044) { + m_OSName = _T("Windows 10 (Build 21H2)"); + } else if (osVersion.dwBuildNumber == 19043) { + m_OSName = _T("Windows 10 (Build 21H1)"); + } else if (osVersion.dwBuildNumber == 19042) { + m_OSName = _T("Windows 10 (Build 20H2)"); + } else if (osVersion.dwBuildNumber == 19041) { + m_OSName = _T("Windows 10 (Build 2004)"); + } else if (osVersion.dwBuildNumber >= 18363) { + m_OSName = _T("Windows 10 (Build 1909)"); + } else if (osVersion.dwBuildNumber == 18362) { + m_OSName = _T("Windows 10 (Build 1903)"); + } else if (osVersion.dwBuildNumber >= 17763) { + m_OSName = _T("Windows 10 (Build 1809)"); + } else if (osVersion.dwBuildNumber >= 17134) { + m_OSName = _T("Windows 10 (Build 1803)"); + } else if (osVersion.dwBuildNumber >= 16299) { + m_OSName = _T("Windows 10 (Build 1709)"); + } else if (osVersion.dwBuildNumber >= 15063) { + m_OSName = _T("Windows 10 (Build 1703)"); + } else if (osVersion.dwBuildNumber >= 14393) { + m_OSName = _T("Windows 10 (Build 1607)"); + } else if (osVersion.dwBuildNumber >= 10586) { + m_OSName = _T("Windows 10 (Build 1511)"); + } else if (osVersion.dwBuildNumber >= 10240) { + m_OSName = _T("Windows 10 (Build 1507)"); + } else { + m_OSName = _T("Windows 10"); + } + } + } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 3) { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server 2012 R2"); + } else { + m_OSName = _T("Windows 8.1"); + } + } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 2) { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server 2012"); + } else { + m_OSName = _T("Windows 8"); + } + } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 1) { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server 2008 R2"); + } else { + m_OSName = _T("Windows 7"); + } + } else if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion == 0) { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server 2008"); + } else { + m_OSName = _T("Windows Vista"); + } + } else { + if (IsWindowsServer()) { + m_OSName = _T("Windows Server"); + } else { + m_OSName = _T("Windows NT"); + } + } + if (osVersion.dwMajorVersion == 6 && osVersion.dwMinorVersion < 2 && osVersion.szCSDVersion[0]) { + m_OSName.AppendFormat(_T(" (%s)"), osVersion.szCSDVersion); + } + m_OSVersion.Format(_T("%1u.%1u.%u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber); + +#if !defined(_WIN64) + // 32-bit programs run on both 32-bit and 64-bit Windows + // so must sniff + BOOL f64 = FALSE; + if (IsWow64Process(GetCurrentProcess(), &f64) && f64) +#endif + { + m_OSVersion += _T(" (64-bit)"); + } + + UpdateData(FALSE); + + GetDlgItem(IDOK)->SetFocus(); + fulfillThemeReqs(); + + 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_HOMEPAGE_LINK, m_homepage); + DDX_Text(pDX, IDC_VERSION, m_strBuildNumber); + DDX_Text(pDX, IDC_STATIC5, m_LAVFilters); +#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, CMPCThemeDialog) + //{{AFX_MSG_MAP(CAboutDlg) + // No message handlers + //}}AFX_MSG_MAP + ON_NOTIFY(NM_CLICK, IDC_HOMEPAGE_LINK, OnHomepage) + 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::OnCopyToClipboard() +{ + CStringW info = m_appname + _T("\r\n"); + info += CString(_T('-'), m_appname.GetLength()) + _T("\r\n\r\n"); + info += _T("Build information:\r\n"); + info += _T(" Version: ") + m_strBuildNumber + _T("\r\n"); + info += _T(" Build date: ") + m_buildDate + _T("\r\n\r\n"); +#ifndef MPCHC_LITE + info += _T("LAV Filters:\r\n"); + info += _T(" LAV Splitter: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::SPLITTER) + _T("\r\n"); + info += _T(" LAV Video: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::VIDEO_DECODER) + _T("\r\n"); + info += _T(" LAV Audio: ") + CFGFilterLAV::GetVersion(CFGFilterLAV::AUDIO_DECODER) + _T("\r\n"); + info += _T(" FFmpeg compiler: ") + VersionInfo::GetGCCVersion() + _T("\r\n\r\n"); +#endif + info += _T("Operating system:\r\n"); + info += _T(" Name: ") + m_OSName + _T("\r\n"); + info += _T(" Version: ") + m_OSVersion + _T("\r\n\r\n"); + + info += _T("Hardware:\r\n"); + + CRegKey key; + if (key.Open(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) { + ULONG nChars = 0; + if (key.QueryStringValue(_T("ProcessorNameString"), nullptr, &nChars) == ERROR_SUCCESS) { + CString cpuName; + if (key.QueryStringValue(_T("ProcessorNameString"), cpuName.GetBuffer(nChars), &nChars) == ERROR_SUCCESS) { + cpuName.ReleaseBuffer(nChars); + cpuName.Trim(); + info.AppendFormat(_T(" CPU: %s\r\n"), cpuName.GetString()); + } + } + } + + IDirect3D9* pD3D9 = Direct3DCreate9(D3D_SDK_VERSION); + if (pD3D9) { + for (UINT adapter = 0, adapterCount = pD3D9->GetAdapterCount(); adapter < adapterCount; adapter++) { + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + if (pD3D9->GetAdapterIdentifier(adapter, 0, &adapterIdentifier) == D3D_OK) { + CString deviceName = adapterIdentifier.Description; + deviceName.Trim(); + + if (adapterCount > 1) { + info.AppendFormat(_T(" GPU%u: %s"), adapter + 1, deviceName.GetString()); + } else { + info.AppendFormat(_T(" GPU: %s"), deviceName.GetString()); + } + if (adapterIdentifier.DriverVersion.QuadPart) { + info.AppendFormat(_T(" (driver version: %s)"), + FileVersionInfo::FormatVersionString(adapterIdentifier.DriverVersion.LowPart, adapterIdentifier.DriverVersion.HighPart).GetString()); + } + info += _T("\r\n"); + } + } + pD3D9->Release(); + } + + auto &s = AfxGetAppSettings(); + CMonitors monitors; + + CStringW currentMonitorName; + monitors.GetNearestMonitor(AfxGetMainWnd()).GetName(currentMonitorName); + + CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); + + for (int i = 0; i < monitors.GetCount(); i++) { + CMonitor monitor = monitors.GetMonitor(i); + + if (monitor.IsMonitor()) { + CStringW displayName, deviceName; + monitor.GetNames(displayName, deviceName); + CStringW str = displayName; + + if (!deviceName.IsEmpty()) { + str.Append(L" - " + deviceName); + } + + int bpp = monitor.GetBitsPerPixel(); + CRect mr; + monitor.GetMonitorRect(mr); + int dpi = DpiHelper::GetDPIForMonitor(monitor); + CString dpis; + if (dpi > 0) { + dpis.Format(L" %i DPI", dpi); + } + str.AppendFormat(L" [%ix%i %i-bit%s]", mr.Width(), mr.Height(), bpp, dpis.GetString()); + if (displayName == currentMonitorName) { + str.AppendFormat(L" - [%s]", ResStr(IDS_FULLSCREENMONITOR_CURRENT).GetString()); + } + info.AppendFormat(L" Monitor: %s\r\n", str.GetString()); + } + } + info += _T("\r\nText:\r\n"); + double textScaleFactor = DpiHelper::GetTextScaleFactor(); + info.AppendFormat(L" Scale Factor: %f\r\n", textScaleFactor); + int cp = GetACP(); + info.AppendFormat(L" Ansi Codepage: %i\r\n", cp); + + CClipboard clipboard(this); + VERIFY(clipboard.SetText(info)); +} diff --git a/src/mpc-hc/AboutDlg.h b/src/mpc-hc/AboutDlg.h index f8e24d5c648..791da4c429b 100644 --- a/src/mpc-hc/AboutDlg.h +++ b/src/mpc-hc/AboutDlg.h @@ -1,67 +1,67 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "resource.h" -#include "CMPCThemeDialog.h" - -class CAboutDlg : public CMPCThemeDialog -{ - CStatic m_icon; - - CString m_appname; - CString m_homepage; - - CString m_strBuildNumber; - CString m_LAVFilters; -#ifndef MPCHC_LITE - CString m_LAVFiltersVersion; -#endif - CString m_buildDate; - - CString m_OSName; - CString m_OSVersion; - -public: - CAboutDlg(); - virtual ~CAboutDlg(); - - virtual BOOL OnInitDialog(); - - // 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 - - // Implementation -protected: - //{{AFX_MSG(CAboutDlg) - afx_msg void OnCopyToClipboard(); - afx_msg void OnHomepage(NMHDR* pNMHDR, LRESULT* pResult); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; +/* + * (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 . + * + */ + +#pragma once + +#include "resource.h" +#include "CMPCThemeDialog.h" + +class CAboutDlg : public CMPCThemeDialog +{ + CStatic m_icon; + + CString m_appname; + CString m_homepage; + + CString m_strBuildNumber; + CString m_LAVFilters; +#ifndef MPCHC_LITE + CString m_LAVFiltersVersion; +#endif + CString m_buildDate; + + CString m_OSName; + CString m_OSVersion; + +public: + CAboutDlg(); + virtual ~CAboutDlg(); + + virtual BOOL OnInitDialog(); + + // 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 + + // Implementation +protected: + //{{AFX_MSG(CAboutDlg) + afx_msg void OnCopyToClipboard(); + afx_msg void OnHomepage(NMHDR* pNMHDR, LRESULT* pResult); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; diff --git a/src/mpc-hc/AppSettings.cpp b/src/mpc-hc/AppSettings.cpp index 6b6223d2562..608f1b982cb 100644 --- a/src/mpc-hc/AppSettings.cpp +++ b/src/mpc-hc/AppSettings.cpp @@ -1,3869 +1,3869 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "AppSettings.h" -#include "CrashReporter.h" -#include "FGFilter.h" -#include "FakeFilterMapper2.h" -#include "FileAssoc.h" -#include "ExceptionHandler.h" -#include "PathUtils.h" -#include "Translations.h" -#include "UpdateChecker.h" -#include "WinAPIUtils.h" -#include "moreuuids.h" -#include "mplayerc.h" -#include "../thirdparty/sanear/src/Factory.h" -#include -#include -#include -#include "date/date.h" -#include "PPageExternalFilters.h" -#include "../VideoRenderers/MPCVRAllocatorPresenter.h" -std::map CAppSettings::CommandIDToWMCMD; - -#pragma warning(push) -#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized -CAppSettings::CAppSettings() - : bInitialized(false) - , nCLSwitches(0) - , rtShift(0) - , rtStart(0) - , lDVDTitle(0) - , lDVDChapter(0) - , iMonitor(0) - , fShowDebugInfo(false) - , iAdminOption(0) - , fAllowMultipleInst(false) - , fTrayIcon(false) - , fShowOSD(true) - , fShowCurrentTimeInOSD(false) - , nOSDTransparency(64) - , nOSDBorder(1) - , fLimitWindowProportions(false) - , fSnapToDesktopEdges(false) - , fHideCDROMsSubMenu(false) - , dwPriority(NORMAL_PRIORITY_CLASS) - , iTitleBarTextStyle(1) - , fTitleBarTextTitle(false) - , fKeepHistory(true) - , iRecentFilesNumber(100) - , MRU(L"MediaHistory", iRecentFilesNumber) - , MRUDub(0, _T("Recent Dub List"), _T("Dub%d"), 20) - , fRememberDVDPos(false) - , fRememberFilePos(false) - , iRememberPosForLongerThan(5) - , bRememberPosForAudioFiles(true) - , bRememberExternalPlaylistPos(true) - , bRememberTrackSelection(true) - , bRememberPlaylistItems(true) - , fRememberWindowPos(false) - , fRememberWindowSize(false) - , rcLastWindowPos(CRect(100, 100, 500, 400)) - , fSavePnSZoom(false) - , dZoomX(1.0) - , dZoomY(1.0) - , fAssociatedWithIcons(true) - , hAccel(nullptr) - , fWinLirc(false) - , fUIce(false) - , fGlobalMedia(true) - , nLogoId(-1) - , fLogoExternal(false) - , fLogoColorProfileEnabled(false) - , fEnableWebServer(false) - , nWebServerPort(13579) - , nCmdlnWebServerPort(-1) - , fWebServerUseCompression(true) - , fWebServerLocalhostOnly(false) - , bWebUIEnablePreview(false) - , fWebServerPrintDebugInfo(false) - , nVolume(100) - , fMute(false) - , nBalance(0) - , nLoops(1) - , fLoopForever(false) - , eLoopMode(LoopMode::PLAYLIST) - , fRememberZoomLevel(true) - , nAutoFitFactorMin(75) - , nAutoFitFactorMax(75) - , iZoomLevel(1) - , fEnableWorkerThreadForOpening(true) - , fReportFailedPins(true) - , fAutoloadAudio(true) - , fBlockVSFilter(true) - , bBlockRDP(false) - , nVolumeStep(5) - , nSpeedStep(0) - , nDefaultToolbarSize(24) - , eAfterPlayback(AfterPlayback::DO_NOTHING) - , fUseDVDPath(false) - , idMenuLang(0) - , idAudioLang(0) - , idSubtitlesLang(0) - , fClosedCaptions(false) - , iDSVideoRendererType(VIDRNDT_DS_DEFAULT) - , fD3DFullscreen(false) - , fLaunchfullscreen(false) - , bHideFullscreenControls(true) - , eHideFullscreenControlsPolicy(HideFullscreenControlsPolicy::SHOW_WHEN_HOVERED) - , uHideFullscreenControlsDelay(0) - , bHideFullscreenDockedPanels(true) - , fExitFullScreenAtTheEnd(true) - , iDefaultCaptureDevice(0) - , iAnalogCountry(1) - , iBDAScanFreqStart(474000) - , iBDAScanFreqEnd(858000) - , iBDABandwidth(8) - , iBDASymbolRate(0) - , fBDAUseOffset(false) - , iBDAOffset(166) - , fBDAIgnoreEncryptedChannels(false) - , nDVBLastChannel(INT_ERROR) - , nDVBRebuildFilterGraph(DVB_REBUILD_FG_WHEN_SWITCHING) - , nDVBStopFilterGraph(DVB_STOP_FG_WHEN_SWITCHING) - , SrcFilters() - , TraFilters() - , fEnableAudioSwitcher(true) - , fAudioNormalize(false) - , nAudioMaxNormFactor(400) - , fAudioNormalizeRecover(true) - , nAudioBoost(0) - , fDownSampleTo441(false) - , fAudioTimeShift(false) - , iAudioTimeShift(0) - , fCustomChannelMapping(false) - , nSpeakerChannels(2) - , pSpeakerToChannelMap() - , fOverridePlacement(false) - , nHorPos(50) - , nVerPos(90) - , bSubtitleARCompensation(true) - , nSubDelayStep(500) - , bPreferDefaultForcedSubtitles(true) - , fPrioritizeExternalSubtitles(true) - , fDisableInternalSubtitles(true) - , bAllowOverridingExternalSplitterChoice(false) - , bAutoDownloadSubtitles(false) - , bAutoSaveDownloadedSubtitles(false) - , nAutoDownloadScoreMovies(0x16) - , nAutoDownloadScoreSeries(0x18) - , bAutoUploadSubtitles(false) - , bPreferHearingImpairedSubtitles(false) - , bMPCTheme(true) - , bWindows10DarkThemeActive(false) - , bWindows10AccentColorsEnabled(false) - , iModernSeekbarHeight(DEF_MODERN_SEEKBAR_HEIGHT) - , eModernThemeMode(CMPCTheme::ModernThemeMode::WINDOWSDEFAULT) - , iFullscreenDelay(MIN_FULLSCREEN_DELAY) - , iVerticalAlignVideo(verticalAlignVideoType::ALIGN_MIDDLE) - , nJumpDistS(DEFAULT_JUMPDISTANCE_1) - , nJumpDistM(DEFAULT_JUMPDISTANCE_2) - , nJumpDistL(DEFAULT_JUMPDISTANCE_3) - , bFastSeek(true) - , eFastSeekMethod(FASTSEEK_NEAREST_KEYFRAME) - , fShowChapters(true) - , bNotifySkype(false) - , fPreventMinimize(false) - , bUseEnhancedTaskBar(true) - , fLCDSupport(false) - , fSeekPreview(false) - , iSeekPreviewSize(15) - , fUseSearchInFolder(false) - , fUseSeekbarHover(true) - , nHoverPosition(TIME_TOOLTIP_ABOVE_SEEKBAR) - , nOSDSize(0) - , bHideWindowedMousePointer(true) - , iBrightness(0) - , iContrast(0) - , iHue(0) - , iSaturation(0) - , nUpdaterAutoCheck(-1) - , nUpdaterDelay(7) - , eCaptionMenuMode(MODE_SHOWCAPTIONMENU) - , fHideNavigation(false) - , nCS(CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR) - , language(LANGID(-1)) - , fEnableSubtitles(true) - , bSubtitleOverrideDefaultStyle(false) - , bSubtitleOverrideAllStyles(false) - , iDefaultVideoSize(DVS_FROMINSIDE) - , fKeepAspectRatio(true) - , fCompMonDeskARDiff(false) - , iOnTop(0) - , bFavRememberPos(true) - , bFavRelativeDrive(false) - , bFavRememberABMarks(false) - , iThumbRows(4) - , iThumbCols(4) - , iThumbWidth(1024) - , bSubSaveExternalStyleFile(false) - , bShufflePlaylistItems(false) - , bHidePlaylistFullScreen(false) - , nLastWindowType(SIZE_RESTORED) - , nLastUsedPage(0) - , fRemainingTime(false) - , bHighPrecisionTimer(false) - , bTimerShowPercentage(false) - , fLastFullScreen(false) - , fEnableEDLEditor(false) - , hMasterWnd(nullptr) - , bHideWindowedControls(false) - , nJpegQuality(90) - , bEnableCoverArt(true) - , nCoverArtSizeLimit(600) - , bEnableLogging(false) - , bUseLegacyToolbar(false) - , iLAVGPUDevice(DWORD_MAX) - , nCmdVolume(0) - , eSubtitleRenderer(SubtitleRenderer::INTERNAL) - , bUseYDL(true) - , iYDLMaxHeight(1440) - , iYDLVideoFormat(0) - , iYDLAudioFormat(0) - , bYDLAudioOnly(false) - , sYDLExePath(_T("")) - , sYDLCommandLine(_T("")) - , bSnapShotSubtitles(true) - , bSnapShotKeepVideoExtension(true) - , bEnableCrashReporter(true) - , nStreamPosPollerInterval(100) - , bShowLangInStatusbar(false) - , bShowFPSInStatusbar(false) - , bShowABMarksInStatusbar(false) - , bShowVideoInfoInStatusbar(true) - , bShowAudioFormatInStatusbar(true) -#if USE_LIBASS - , bRenderSSAUsingLibass(false) - , bRenderSRTUsingLibass(false) -#endif - , bAddLangCodeWhenSaveSubtitles(false) - , bUseTitleInRecentFileList(true) - , sYDLSubsPreference() - , bUseAutomaticCaptions(false) - , bLockNoPause(false) - , bPreventDisplaySleep(true) - , bUseSMTC(false) - , iReloadAfterLongPause(0) - , bOpenRecPanelWhenOpeningDevice(true) - , lastQuickOpenPath(L"") - , lastFileSaveCopyPath(L"") - , lastFileOpenDirPath(L"") - , externalPlayListPath(L"") - , iRedirectOpenToAppendThreshold(1000) - , bFullscreenSeparateControls(true) - , bAlwaysUseShortMenu(false) - , iStillVideoDuration(10) - , iMouseLeftUpDelay(0) - , bUseFreeType(false) - , bUseMediainfoLoadFileDuration(false) - , bCaptureDeinterlace(false) - , bPauseWhileDraggingSeekbar(true) - , bConfirmFileDelete(true) -{ - // Internal source filter -#if INTERNAL_SOURCEFILTER_AC3 - SrcFiltersKeys[SRC_AC3] = FilterKey(_T("SRC_AC3"), true); -#endif -#if INTERNAL_SOURCEFILTER_ASF - SrcFiltersKeys[SRC_ASF] = FilterKey(_T("SRC_ASF"), false); -#endif -#if INTERNAL_SOURCEFILTER_AVI - SrcFiltersKeys[SRC_AVI] = FilterKey(_T("SRC_AVI"), true); -#endif -#if INTERNAL_SOURCEFILTER_AVS - SrcFiltersKeys[SRC_AVS] = FilterKey(_T("SRC_AVS"), true); -#endif -#if INTERNAL_SOURCEFILTER_DTS - SrcFiltersKeys[SRC_DTS] = FilterKey(_T("SRC_DTS"), true); -#endif -#if INTERNAL_SOURCEFILTER_FLAC - SrcFiltersKeys[SRC_FLAC] = FilterKey(_T("SRC_FLAC"), true); -#endif -#if INTERNAL_SOURCEFILTER_FLIC - SrcFiltersKeys[SRC_FLIC] = FilterKey(_T("SRC_FLIC"), true); -#endif -#if INTERNAL_SOURCEFILTER_FLV - SrcFiltersKeys[SRC_FLV] = FilterKey(_T("SRC_FLV"), true); -#endif -#if INTERNAL_SOURCEFILTER_GIF - SrcFiltersKeys[SRC_GIF] = FilterKey(_T("SRC_GIF"), true); -#endif -#if INTERNAL_SOURCEFILTER_HTTP - SrcFiltersKeys[SRC_HTTP] = FilterKey(_T("SRC_HTTP"), true); -#endif -#if INTERNAL_SOURCEFILTER_MATROSKA - SrcFiltersKeys[SRC_MATROSKA] = FilterKey(_T("SRC_MATROSKA"), true); -#endif -#if INTERNAL_SOURCEFILTER_MISC - SrcFiltersKeys[SRC_MISC] = FilterKey(_T("SRC_MISC"), true); -#endif -#if INTERNAL_SOURCEFILTER_MMS - SrcFiltersKeys[SRC_MMS] = FilterKey(_T("SRC_MMS"), true); -#endif -#if INTERNAL_SOURCEFILTER_MP4 - SrcFiltersKeys[SRC_MP4] = FilterKey(_T("SRC_MP4"), true); -#endif -#if INTERNAL_SOURCEFILTER_MPEGAUDIO - SrcFiltersKeys[SRC_MPA] = FilterKey(_T("SRC_MPA"), true); -#endif -#if INTERNAL_SOURCEFILTER_MPEG - SrcFiltersKeys[SRC_MPEG] = FilterKey(_T("SRC_MPEG"), true); - SrcFiltersKeys[SRC_MPEGTS] = FilterKey(_T("SRC_MPEGTS"), true); -#endif -#if INTERNAL_SOURCEFILTER_OGG - SrcFiltersKeys[SRC_OGG] = FilterKey(_T("SRC_OGG"), true); -#endif -#if INTERNAL_SOURCEFILTER_REALMEDIA - SrcFiltersKeys[SRC_REALMEDIA] = FilterKey(_T("SRC_REALMEDIA"), true); -#endif -#if INTERNAL_SOURCEFILTER_RTMP - SrcFiltersKeys[SRC_RTMP] = FilterKey(_T("SRC_RTMP"), true); -#endif -#if INTERNAL_SOURCEFILTER_RTP - SrcFiltersKeys[SRC_RTP] = FilterKey(_T("SRC_RTP"), true); -#endif -#if INTERNAL_SOURCEFILTER_RTSP - SrcFiltersKeys[SRC_RTSP] = FilterKey(_T("SRC_RTSP"), true); -#endif -#if INTERNAL_SOURCEFILTER_RTSP - SrcFiltersKeys[SRC_UDP] = FilterKey(_T("SRC_UDP"), true); -#endif -#if INTERNAL_SOURCEFILTER_WTV - SrcFiltersKeys[SRC_WTV] = FilterKey(_T("SRC_WTV"), true); -#endif -#if INTERNAL_SOURCEFILTER_CDDA - SrcFiltersKeys[SRC_CDDA] = FilterKey(_T("SRC_CDDA"), true); -#endif -#if INTERNAL_SOURCEFILTER_CDXA - SrcFiltersKeys[SRC_CDXA] = FilterKey(_T("SRC_CDXA"), true); -#endif -#if INTERNAL_SOURCEFILTER_DSM - SrcFiltersKeys[SRC_DSM] = FilterKey(_T("SRC_DSM"), true); -#endif -#if INTERNAL_SOURCEFILTER_RFS - SrcFiltersKeys[SRC_RFS] = FilterKey(_T("SRC_RFS"), true); -#endif -#if INTERNAL_SOURCEFILTER_VTS - SrcFiltersKeys[SRC_VTS] = FilterKey(_T("SRC_VTS"), true); -#endif - - // Internal decoders -#if INTERNAL_DECODER_MPEG1 - TraFiltersKeys[TRA_MPEG1] = FilterKey(_T("TRA_MPEG1"), true); -#endif -#if INTERNAL_DECODER_MPEG2 - TraFiltersKeys[TRA_MPEG2] = FilterKey(_T("TRA_MPEG2"), true); -#endif -#if INTERNAL_DECODER_REALVIDEO - TraFiltersKeys[TRA_RV] = FilterKey(_T("TRA_RV"), true); -#endif -#if INTERNAL_DECODER_REALAUDIO - TraFiltersKeys[TRA_RA] = FilterKey(_T("TRA_RA"), true); -#endif -#if INTERNAL_DECODER_MPEGAUDIO - TraFiltersKeys[TRA_MPA] = FilterKey(_T("TRA_MPA"), true); -#endif -#if INTERNAL_DECODER_DTS - TraFiltersKeys[TRA_DTS] = FilterKey(_T("TRA_DTS"), true); -#endif -#if INTERNAL_DECODER_LPCM - TraFiltersKeys[TRA_LPCM] = FilterKey(_T("TRA_LPCM"), true); -#endif -#if INTERNAL_DECODER_AC3 - TraFiltersKeys[TRA_AC3] = FilterKey(_T("TRA_AC3"), true); -#endif -#if INTERNAL_DECODER_AAC - TraFiltersKeys[TRA_AAC] = FilterKey(_T("TRA_AAC"), true); -#endif -#if INTERNAL_DECODER_ALAC - TraFiltersKeys[TRA_ALAC] = FilterKey(_T("TRA_ALAC"), true); -#endif -#if INTERNAL_DECODER_ALS - TraFiltersKeys[TRA_ALS] = FilterKey(_T("TRA_ALS"), true); -#endif -#if INTERNAL_DECODER_PS2AUDIO - TraFiltersKeys[TRA_PS2AUD] = FilterKey(_T("TRA_PS2AUD"), true); -#endif -#if INTERNAL_DECODER_VORBIS - TraFiltersKeys[TRA_VORBIS] = FilterKey(_T("TRA_VORBIS"), true); -#endif -#if INTERNAL_DECODER_FLAC - TraFiltersKeys[TRA_FLAC] = FilterKey(_T("TRA_FLAC"), true); -#endif -#if INTERNAL_DECODER_NELLYMOSER - TraFiltersKeys[TRA_NELLY] = FilterKey(_T("TRA_NELLY"), true); -#endif -#if INTERNAL_DECODER_AMR - TraFiltersKeys[TRA_AMR] = FilterKey(_T("TRA_AMR"), true); -#endif -#if INTERNAL_DECODER_OPUS - TraFiltersKeys[TRA_OPUS] = FilterKey(_T("TRA_OPUS"), true); -#endif -#if INTERNAL_DECODER_WMA - TraFiltersKeys[TRA_WMA] = FilterKey(_T("TRA_WMA"), false); -#endif -#if INTERNAL_DECODER_WMAPRO - TraFiltersKeys[TRA_WMAPRO] = FilterKey(_T("TRA_WMAPRO"), false); -#endif -#if INTERNAL_DECODER_WMALL - TraFiltersKeys[TRA_WMALL] = FilterKey(_T("TRA_WMALL"), false); -#endif -#if INTERNAL_DECODER_G726 - TraFiltersKeys[TRA_G726] = FilterKey(_T("TRA_G726"), true); -#endif -#if INTERNAL_DECODER_G729 - TraFiltersKeys[TRA_G729] = FilterKey(_T("TRA_G729"), true); -#endif -#if INTERNAL_DECODER_OTHERAUDIO - TraFiltersKeys[TRA_OTHERAUDIO] = FilterKey(_T("TRA_OTHERAUDIO"), true); -#endif -#if INTERNAL_DECODER_PCM - TraFiltersKeys[TRA_PCM] = FilterKey(_T("TRA_PCM"), true); -#endif -#if INTERNAL_DECODER_H264 - TraFiltersKeys[TRA_H264] = FilterKey(_T("TRA_H264"), true); -#endif -#if INTERNAL_DECODER_HEVC - TraFiltersKeys[TRA_HEVC] = FilterKey(_T("TRA_HEVC"), true); -#endif -#if INTERNAL_DECODER_VVC - TraFiltersKeys[TRA_VVC] = FilterKey(_T("TRA_VVC"), true); -#endif -#if INTERNAL_DECODER_AV1 - TraFiltersKeys[TRA_AV1] = FilterKey(_T("TRA_AV1"), true); -#endif -#if INTERNAL_DECODER_VC1 - TraFiltersKeys[TRA_VC1] = FilterKey(_T("TRA_VC1"), true); -#endif -#if INTERNAL_DECODER_FLV - TraFiltersKeys[TRA_FLV4] = FilterKey(_T("TRA_FLV4"), true); -#endif -#if INTERNAL_DECODER_VP356 - TraFiltersKeys[TRA_VP356] = FilterKey(_T("TRA_VP356"), true); -#endif -#if INTERNAL_DECODER_VP8 - TraFiltersKeys[TRA_VP8] = FilterKey(_T("TRA_VP8"), true); -#endif -#if INTERNAL_DECODER_VP9 - TraFiltersKeys[TRA_VP9] = FilterKey(_T("TRA_VP9"), true); -#endif -#if INTERNAL_DECODER_XVID - TraFiltersKeys[TRA_XVID] = FilterKey(_T("TRA_XVID"), true); -#endif -#if INTERNAL_DECODER_DIVX - TraFiltersKeys[TRA_DIVX] = FilterKey(_T("TRA_DIVX"), true); -#endif -#if INTERNAL_DECODER_MSMPEG4 - TraFiltersKeys[TRA_MSMPEG4] = FilterKey(_T("TRA_MSMPEG4"), true); -#endif -#if INTERNAL_DECODER_WMV - TraFiltersKeys[TRA_WMV] = FilterKey(_T("TRA_WMV"), false); -#endif -#if INTERNAL_DECODER_SVQ - TraFiltersKeys[TRA_SVQ3] = FilterKey(_T("TRA_SVQ3"), true); -#endif -#if INTERNAL_DECODER_H263 - TraFiltersKeys[TRA_H263] = FilterKey(_T("TRA_H263"), true); -#endif -#if INTERNAL_DECODER_THEORA - TraFiltersKeys[TRA_THEORA] = FilterKey(_T("TRA_THEORA"), true); -#endif -#if INTERNAL_DECODER_AMVV - TraFiltersKeys[TRA_AMVV] = FilterKey(_T("TRA_AMVV"), true); -#endif -#if INTERNAL_DECODER_MJPEG - TraFiltersKeys[TRA_MJPEG] = FilterKey(_T("TRA_MJPEG"), true); -#endif -#if INTERNAL_DECODER_INDEO - TraFiltersKeys[TRA_INDEO] = FilterKey(_T("TRA_INDEO"), true); -#endif -#if INTERNAL_DECODER_SCREEN - TraFiltersKeys[TRA_SCREEN] = FilterKey(_T("TRA_SCREEN"), true); -#endif -#if INTERNAL_DECODER_FLIC - TraFiltersKeys[TRA_FLIC] = FilterKey(_T("TRA_FLIC"), true); -#endif -#if INTERNAL_DECODER_MSVIDEO - TraFiltersKeys[TRA_MSVIDEO] = FilterKey(_T("TRA_MSVIDEO"), true); -#endif -#if INTERNAL_DECODER_V210_V410 - TraFiltersKeys[TRA_V210_V410] = FilterKey(_T("TRA_V210_V410"), false); -#endif -#if INTERNAL_DECODER_PRORES - TraFiltersKeys[TRA_PRORES] = FilterKey(_T("TRA_PRORES"), true); -#endif -#if INTERNAL_DECODER_DNXHD - TraFiltersKeys[TRA_DNXHD] = FilterKey(_T("TRA_DNXHD"), true); -#endif -#if INTERNAL_DECODER_OTHERVIDEO - TraFiltersKeys[TRA_OTHERVIDEO] = FilterKey(_T("TRA_OTHERVIDEO"), true); -#endif - - ZeroMemory(&DVDPosition, sizeof(DVDPosition)); - - ENSURE(SUCCEEDED(SaneAudioRenderer::Factory::CreateSettings(&sanear))); - - // Mouse - nMouseLeftClick = ID_PLAY_PLAYPAUSE; - nMouseLeftDblClick = ID_VIEW_FULLSCREEN; - nMouseRightClick = ID_MENU_PLAYER_SHORT; - MouseMiddleClick = { 0, 0, 0, 0 }; - MouseX1Click = { ID_NAVIGATE_SKIPBACK, 0, 0, 0 }; - MouseX2Click = { ID_NAVIGATE_SKIPFORWARD, 0, 0, 0 }; - MouseWheelUp = { ID_VOLUME_UP, ID_PLAY_SEEKFORWARDLARGE, 0, ID_PLAY_SEEKFORWARDLARGE }; - MouseWheelDown = { ID_VOLUME_DOWN, ID_PLAY_SEEKBACKWARDLARGE, 0, ID_PLAY_SEEKBACKWARDLARGE }; - MouseWheelLeft = { 0, 0, 0, 0 }; - MouseWheelRight = { 0, 0, 0, 0 }; - bMouseLeftClickOpenRecent = false; - bMouseEasyMove = true; - -} -#pragma warning(pop) - -/* Note: the mouse commands in this list are no longer being used. Mouse binding are now stored elsewhere. - * They are included for backwards compatibility. - */ -static constexpr wmcmd_base default_wmcmds[] = { - { ID_FILE_OPENQUICK, 'Q', FCONTROL, IDS_MPLAYERC_0 }, - { ID_FILE_OPENMEDIA, 'O', FCONTROL, IDS_AG_OPEN_FILE }, - { ID_FILE_OPENDVDBD, 'D', FCONTROL, IDS_AG_OPEN_DVD }, - { ID_FILE_OPENDEVICE, 'V', FCONTROL, IDS_AG_OPEN_DEVICE }, - { ID_FILE_OPENDIRECTORY, 0, 0, IDS_AG_OPENDIRECTORY }, - { ID_FILE_REOPEN, 'E', FCONTROL, IDS_AG_REOPEN }, - { ID_FILE_RECYCLE, VK_DELETE, 0, IDS_FILE_RECYCLE }, - { ID_FILE_SAVE_COPY, 0, 0, IDS_AG_SAVE_COPY }, - { ID_FILE_SAVE_IMAGE, 'I', FALT, IDS_AG_SAVE_IMAGE }, - { ID_FILE_SAVE_IMAGE_AUTO, VK_F5, 0, IDS_MPLAYERC_6 }, - { ID_FILE_SAVE_THUMBNAILS, 0, 0, IDS_FILE_SAVE_THUMBNAILS }, - { ID_FILE_SUBTITLES_LOAD, 'L', FCONTROL, IDS_AG_LOAD_SUBTITLES }, - { ID_FILE_SUBTITLES_SAVE, 'S', FCONTROL, IDS_AG_SAVE_SUBTITLES }, - { ID_FILE_SUBTITLES_DOWNLOAD, 'D', 0, IDS_SUBTITLES_DOWNLOAD }, - { ID_FILE_CLOSE_AND_RESTORE, 'C', FCONTROL, IDS_AG_CLOSE }, - { ID_FILE_PROPERTIES, VK_F10, FSHIFT, IDS_AG_PROPERTIES }, - { ID_FILE_OPEN_LOCATION, VK_F10, FCONTROL | FSHIFT, IDS_AG_OPEN_FILE_LOCATION }, - { ID_FILE_EXIT, 'X', FALT, IDS_AG_EXIT }, - { ID_PLAY_PLAYPAUSE, VK_SPACE, 0, IDS_AG_PLAYPAUSE, APPCOMMAND_MEDIA_PLAY_PAUSE, wmcmd::LUP }, - { ID_PLAY_PLAY, 0, 0, IDS_AG_PLAY, APPCOMMAND_MEDIA_PLAY }, - { ID_PLAY_PAUSE, 0, 0, IDS_AG_PAUSE, APPCOMMAND_MEDIA_PAUSE }, - { ID_PLAY_STOP, VK_OEM_PERIOD, 0, IDS_AG_STOP, APPCOMMAND_MEDIA_STOP }, - { ID_PLAY_FRAMESTEP, VK_RIGHT, FCONTROL, IDS_AG_FRAMESTEP }, - { ID_PLAY_FRAMESTEP_BACK, VK_LEFT, FCONTROL, IDS_MPLAYERC_16 }, - { ID_NAVIGATE_GOTO, 'G', FCONTROL, IDS_AG_GO_TO }, - { ID_PLAY_INCRATE, VK_UP, FCONTROL, IDS_AG_INCREASE_RATE }, - { ID_PLAY_DECRATE, VK_DOWN, FCONTROL, IDS_AG_DECREASE_RATE }, - { ID_PLAY_RESETRATE, 'R', FCONTROL, IDS_AG_RESET_RATE }, - { ID_PLAY_INCAUDDELAY, VK_ADD, 0, IDS_MPLAYERC_21 }, - { ID_PLAY_DECAUDDELAY, VK_SUBTRACT, 0, IDS_MPLAYERC_22 }, - { ID_PLAY_SEEKFORWARDSMALL, 0, 0, IDS_MPLAYERC_23 }, - { ID_PLAY_SEEKBACKWARDSMALL, 0, 0, IDS_MPLAYERC_24 }, - { ID_PLAY_SEEKFORWARDMED, VK_RIGHT, 0, IDS_MPLAYERC_25 }, - { ID_PLAY_SEEKBACKWARDMED, VK_LEFT, 0, IDS_MPLAYERC_26 }, - { ID_PLAY_SEEKFORWARDLARGE, 0, 0, IDS_MPLAYERC_27, 0, wmcmd::WUP, FVIRTKEY | FCONTROL }, - { ID_PLAY_SEEKBACKWARDLARGE, 0, 0, IDS_MPLAYERC_28, 0, wmcmd::WDOWN, FVIRTKEY | FCONTROL }, - { ID_PLAY_SEEKKEYFORWARD, VK_RIGHT, FSHIFT, IDS_MPLAYERC_29 }, - { ID_PLAY_SEEKKEYBACKWARD, VK_LEFT, FSHIFT, IDS_MPLAYERC_30 }, - { ID_PLAY_SEEKSET, VK_HOME, 0, IDS_AG_SEEKSET }, - { ID_PLAY_REPEAT_FOREVER, 0, 0, IDS_PLAYLOOP_FOREVER }, - { ID_PLAY_REPEAT_ONEFILE, 0, 0, IDS_PLAYLOOPMODE_FILE }, - { ID_PLAY_REPEAT_WHOLEPLAYLIST, 0, 0, IDS_PLAYLOOPMODE_PLAYLIST }, - { ID_PLAY_REPEAT_AB, 0, 0, IDS_PLAYLOOPMODE_AB }, - { ID_PLAY_REPEAT_AB_MARK_A, VK_OEM_4, 0, IDS_PLAYLOOPMODE_AB_MARK_A }, - { ID_PLAY_REPEAT_AB_MARK_B, VK_OEM_6, 0, IDS_PLAYLOOPMODE_AB_MARK_B }, - { ID_NAVIGATE_SKIPFORWARD, VK_NEXT, 0, IDS_AG_NEXT, APPCOMMAND_MEDIA_NEXTTRACK, wmcmd::X2DOWN }, - { ID_NAVIGATE_SKIPBACK, VK_PRIOR, 0, IDS_AG_PREVIOUS, APPCOMMAND_MEDIA_PREVIOUSTRACK, wmcmd::X1DOWN }, - { ID_NAVIGATE_SKIPFORWARDFILE, VK_NEXT, FCONTROL, IDS_AG_NEXT_FILE }, - { ID_NAVIGATE_SKIPBACKFILE, VK_PRIOR, FCONTROL, IDS_AG_PREVIOUS_FILE }, - { ID_NAVIGATE_TUNERSCAN, 'T', FSHIFT, IDS_NAVIGATE_TUNERSCAN }, - { ID_FAVORITES_QUICKADDFAVORITE, 'Q', FSHIFT, IDS_FAVORITES_QUICKADDFAVORITE }, - { ID_FAVORITES_ORGANIZE, 0, 0, IDS_FAVORITES_ORGANIZE }, - { ID_VIEW_CAPTIONMENU, '0', FCONTROL, IDS_AG_TOGGLE_CAPTION }, - { ID_VIEW_SEEKER, '1', FCONTROL, IDS_AG_TOGGLE_SEEKER }, - { ID_VIEW_CONTROLS, '2', FCONTROL, IDS_AG_TOGGLE_CONTROLS }, - { ID_VIEW_INFORMATION, '3', FCONTROL, IDS_AG_TOGGLE_INFO }, - { ID_VIEW_STATISTICS, '4', FCONTROL, IDS_AG_TOGGLE_STATS }, - { ID_VIEW_STATUS, '5', FCONTROL, IDS_AG_TOGGLE_STATUS }, - { ID_VIEW_SUBRESYNC, '6', FCONTROL, IDS_AG_TOGGLE_SUBRESYNC }, - { ID_VIEW_PLAYLIST, '7', FCONTROL, IDS_AG_TOGGLE_PLAYLIST }, - { ID_VIEW_CAPTURE, '8', FCONTROL, IDS_AG_TOGGLE_CAPTURE }, - { ID_VIEW_NAVIGATION, '9', FCONTROL, IDS_AG_TOGGLE_NAVIGATION }, - { ID_VIEW_DEBUGSHADERS, 0, 0, IDS_AG_TOGGLE_DEBUGSHADERS }, - { ID_PRESIZE_SHADERS_TOGGLE, 'P', FCONTROL, IDS_PRESIZE_SHADERS_TOGGLE }, - { ID_POSTSIZE_SHADERS_TOGGLE, 'P', FCONTROL | FALT, IDS_POSTSIZE_SHADERS_TOGGLE }, - { ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE, 0, 0, IDS_AG_TOGGLE_DEFAULT_SUBTITLE_STYLE }, - { ID_VIEW_PRESETS_MINIMAL, '1', 0, IDS_AG_VIEW_MINIMAL }, - { ID_VIEW_PRESETS_COMPACT, '2', 0, IDS_AG_VIEW_COMPACT }, - { ID_VIEW_PRESETS_NORMAL, '3', 0, IDS_AG_VIEW_NORMAL }, - { ID_VIEW_FULLSCREEN, VK_RETURN, FALT, IDS_AG_FULLSCREEN, 0, wmcmd::LDBLCLK }, - { ID_VIEW_FULLSCREEN_SECONDARY, VK_F11, 0, IDS_MPLAYERC_39 }, - { ID_VIEW_ZOOM_25, VK_OEM_3, FALT, IDS_AG_ZOOM_25 }, /* VK_OEM_3 is `~ on US keyboards*/ - { ID_VIEW_ZOOM_50, '1', FALT, IDS_AG_ZOOM_50 }, - { ID_VIEW_ZOOM_100, '2', FALT, IDS_AG_ZOOM_100 }, - { ID_VIEW_ZOOM_200, '3', FALT, IDS_AG_ZOOM_200 }, - { ID_VIEW_ZOOM_AUTOFIT, '4', FALT, IDS_AG_ZOOM_AUTO_FIT }, - { ID_VIEW_ZOOM_AUTOFIT_LARGER, '5', FALT, IDS_AG_ZOOM_AUTO_FIT_LARGER }, - { ID_VIEW_ZOOM_ADD, 0, 0, IDS_AG_ZOOM_ADD }, - { ID_VIEW_ZOOM_SUB, 0, 0, IDS_AG_ZOOM_SUB }, - { ID_ASPECTRATIO_NEXT, 0, 0, IDS_AG_NEXT_AR_PRESET }, - { ID_VIEW_VF_HALF, 0, 0, IDS_AG_VIDFRM_HALF }, - { ID_VIEW_VF_NORMAL, 0, 0, IDS_AG_VIDFRM_NORMAL }, - { ID_VIEW_VF_DOUBLE, 0, 0, IDS_AG_VIDFRM_DOUBLE }, - { ID_VIEW_VF_STRETCH, 0, 0, IDS_AG_VIDFRM_STRETCH }, - { ID_VIEW_VF_FROMINSIDE, 0, 0, IDS_AG_VIDFRM_INSIDE }, - { ID_VIEW_VF_ZOOM1, 0, 0, IDS_AG_VIDFRM_ZOOM1 }, - { ID_VIEW_VF_ZOOM2, 0, 0, IDS_AG_VIDFRM_ZOOM2 }, - { ID_VIEW_VF_FROMOUTSIDE, 0, 0, IDS_AG_VIDFRM_OUTSIDE }, - { ID_VIEW_VF_SWITCHZOOM, 0, 0, IDS_AG_VIDFRM_SWITCHZOOM }, - { ID_ONTOP_ALWAYS, 'A', FCONTROL, IDS_AG_ALWAYS_ON_TOP }, - { ID_VIEW_RESET, VK_NUMPAD5, 0, IDS_AG_PNS_RESET }, - { ID_VIEW_INCSIZE, VK_NUMPAD9, 0, IDS_AG_PNS_INC_SIZE }, - { ID_VIEW_INCWIDTH, VK_NUMPAD6, 0, IDS_AG_PNS_INC_WIDTH }, - { ID_VIEW_INCHEIGHT, VK_NUMPAD8, 0, IDS_MPLAYERC_47 }, - { ID_VIEW_DECSIZE, VK_NUMPAD1, 0, IDS_AG_PNS_DEC_SIZE }, - { ID_VIEW_DECWIDTH, VK_NUMPAD4, 0, IDS_AG_PNS_DEC_WIDTH }, - { ID_VIEW_DECHEIGHT, VK_NUMPAD2, 0, IDS_MPLAYERC_50 }, - { ID_PANSCAN_CENTER, VK_NUMPAD5, FCONTROL, IDS_AG_PNS_CENTER }, - { ID_PANSCAN_MOVELEFT, VK_NUMPAD4, FCONTROL, IDS_AG_PNS_LEFT }, - { ID_PANSCAN_MOVERIGHT, VK_NUMPAD6, FCONTROL, IDS_AG_PNS_RIGHT }, - { ID_PANSCAN_MOVEUP, VK_NUMPAD8, FCONTROL, IDS_AG_PNS_UP }, - { ID_PANSCAN_MOVEDOWN, VK_NUMPAD2, FCONTROL, IDS_AG_PNS_DOWN }, - { ID_PANSCAN_MOVEUPLEFT, VK_NUMPAD7, FCONTROL, IDS_AG_PNS_UPLEFT }, - { ID_PANSCAN_MOVEUPRIGHT, VK_NUMPAD9, FCONTROL, IDS_AG_PNS_UPRIGHT }, - { ID_PANSCAN_MOVEDOWNLEFT, VK_NUMPAD1, FCONTROL, IDS_AG_PNS_DOWNLEFT }, - { ID_PANSCAN_MOVEDOWNRIGHT, VK_NUMPAD3, FCONTROL, IDS_MPLAYERC_59 }, - { ID_PANSCAN_ROTATEXP, VK_NUMPAD8, FALT, IDS_AG_PNS_ROTATEX_P }, - { ID_PANSCAN_ROTATEXM, VK_NUMPAD2, FALT, IDS_AG_PNS_ROTATEX_M }, - { ID_PANSCAN_ROTATEYP, VK_NUMPAD4, FALT, IDS_AG_PNS_ROTATEY_P }, - { ID_PANSCAN_ROTATEYM, VK_NUMPAD6, FALT, IDS_AG_PNS_ROTATEY_M }, - { ID_PANSCAN_ROTATEZP, VK_NUMPAD1, FALT, IDS_AG_PNS_ROTATEZ_P }, - { ID_PANSCAN_ROTATEZM, VK_NUMPAD3, FALT, IDS_AG_PNS_ROTATEZ_M }, - { ID_VOLUME_UP, VK_UP, 0, IDS_AG_VOLUME_UP, 0, wmcmd::WUP }, - { ID_VOLUME_DOWN, VK_DOWN, 0, IDS_AG_VOLUME_DOWN, 0, wmcmd::WDOWN }, - { ID_VOLUME_MUTE, 'M', FCONTROL, IDS_AG_VOLUME_MUTE, 0 }, - { ID_VOLUME_BOOST_INC, 0, 0, IDS_VOLUME_BOOST_INC }, - { ID_VOLUME_BOOST_DEC, 0, 0, IDS_VOLUME_BOOST_DEC }, - { ID_VOLUME_BOOST_MIN, 0, 0, IDS_VOLUME_BOOST_MIN }, - { ID_VOLUME_BOOST_MAX, 0, 0, IDS_VOLUME_BOOST_MAX }, - { ID_CUSTOM_CHANNEL_MAPPING, 0, 0, IDS_CUSTOM_CHANNEL_MAPPING }, - { ID_NORMALIZE, 0, 0, IDS_NORMALIZE }, - { ID_REGAIN_VOLUME, 0, 0, IDS_REGAIN_VOLUME }, - { ID_COLOR_BRIGHTNESS_INC, 0, 0, IDS_BRIGHTNESS_INC }, - { ID_COLOR_BRIGHTNESS_DEC, 0, 0, IDS_BRIGHTNESS_DEC }, - { ID_COLOR_CONTRAST_INC, 0, 0, IDS_CONTRAST_INC }, - { ID_COLOR_CONTRAST_DEC, 0, 0, IDS_CONTRAST_DEC }, - { ID_COLOR_HUE_INC, 0, 0, IDS_HUE_INC }, - { ID_COLOR_HUE_DEC, 0, 0, IDS_HUE_DEC }, - { ID_COLOR_SATURATION_INC, 0, 0, IDS_SATURATION_INC }, - { ID_COLOR_SATURATION_DEC, 0, 0, IDS_SATURATION_DEC }, - { ID_COLOR_RESET, 0, 0, IDS_RESET_COLOR }, - { ID_NAVIGATE_TITLEMENU, 'T', FALT, IDS_MPLAYERC_63 }, - { ID_NAVIGATE_ROOTMENU, 'R', FALT, IDS_AG_DVD_ROOT_MENU }, - { ID_NAVIGATE_SUBPICTUREMENU, 0, 0, IDS_MPLAYERC_65 }, - { ID_NAVIGATE_AUDIOMENU, 0, 0, IDS_MPLAYERC_66 }, - { ID_NAVIGATE_ANGLEMENU, 0, 0, IDS_MPLAYERC_67 }, - { ID_NAVIGATE_CHAPTERMENU, 0, 0, IDS_MPLAYERC_68 }, - { ID_NAVIGATE_MENU_LEFT, VK_LEFT, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_LEFT }, - { ID_NAVIGATE_MENU_RIGHT, VK_RIGHT, FCONTROL | FSHIFT, IDS_MPLAYERC_70 }, - { ID_NAVIGATE_MENU_UP, VK_UP, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_UP }, - { ID_NAVIGATE_MENU_DOWN, VK_DOWN, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_DOWN }, - { ID_NAVIGATE_MENU_ACTIVATE, 0, 0, IDS_MPLAYERC_73 }, - { ID_NAVIGATE_MENU_BACK, 0, 0, IDS_AG_DVD_MENU_BACK }, - { ID_NAVIGATE_MENU_LEAVE, 0, 0, IDS_MPLAYERC_75 }, - { ID_BOSS, 'B', 0, IDS_AG_BOSS_KEY }, - { ID_MENU_PLAYER_SHORT, VK_APPS, 0, IDS_MPLAYERC_77, 0, wmcmd::RUP }, - { ID_MENU_PLAYER_LONG, 0, 0, IDS_MPLAYERC_78 }, - { ID_MENU_FILTERS, 0, 0, IDS_AG_FILTERS_MENU }, - { ID_VIEW_OPTIONS, 'O', 0, IDS_AG_OPTIONS }, - { ID_STREAM_AUDIO_NEXT, 'A', 0, IDS_AG_NEXT_AUDIO }, - { ID_STREAM_AUDIO_PREV, 'A', FSHIFT, IDS_AG_PREV_AUDIO }, - { ID_STREAM_SUB_NEXT, 'S', 0, IDS_AG_NEXT_SUBTITLE }, - { ID_STREAM_SUB_PREV, 'S', FSHIFT, IDS_AG_PREV_SUBTITLE }, - { ID_STREAM_SUB_ONOFF, 'W', 0, IDS_MPLAYERC_85 }, - { ID_SUBTITLES_SUBITEM_START + 2, 0, 0, IDS_MPLAYERC_86 }, - { ID_DVD_ANGLE_NEXT, 0, 0, IDS_MPLAYERC_91 }, - { ID_DVD_ANGLE_PREV, 0, 0, IDS_MPLAYERC_92 }, - { ID_DVD_AUDIO_NEXT, 0, 0, IDS_MPLAYERC_93 }, - { ID_DVD_AUDIO_PREV, 0, 0, IDS_MPLAYERC_94 }, - { ID_DVD_SUB_NEXT, 0, 0, IDS_MPLAYERC_95 }, - { ID_DVD_SUB_PREV, 0, 0, IDS_MPLAYERC_96 }, - { ID_DVD_SUB_ONOFF, 0, 0, IDS_MPLAYERC_97 }, - { ID_VIEW_TEARING_TEST, 0, 0, IDS_AG_TEARING_TEST }, - { ID_VIEW_OSD_DISPLAY_TIME, 'I', FCONTROL, IDS_OSD_DISPLAY_CURRENT_TIME }, - { ID_VIEW_OSD_SHOW_FILENAME, 'N', 0, IDS_OSD_SHOW_FILENAME }, - { ID_SHADERS_PRESET_NEXT, 0, 0, IDS_AG_SHADERS_PRESET_NEXT }, - { ID_SHADERS_PRESET_PREV, 0, 0, IDS_AG_SHADERS_PRESET_PREV }, - { ID_D3DFULLSCREEN_TOGGLE, 0, 0, IDS_MPLAYERC_99 }, - { ID_GOTO_PREV_SUB, 'Y', 0, IDS_MPLAYERC_100 }, - { ID_GOTO_NEXT_SUB, 'U', 0, IDS_MPLAYERC_101 }, - { ID_SUBRESYNC_SHIFT_DOWN, VK_NEXT, FALT, IDS_MPLAYERC_102 }, - { ID_SUBRESYNC_SHIFT_UP, VK_PRIOR, FALT, IDS_MPLAYERC_103 }, - { ID_VIEW_DISPLAY_RENDERER_STATS, 'J', FCONTROL, IDS_OSD_DISPLAY_RENDERER_STATS }, - { ID_VIEW_RESET_RENDERER_STATS, 'R', FCONTROL | FALT, IDS_OSD_RESET_RENDERER_STATS }, - { ID_VIEW_VSYNC, 'V', 0, IDS_AG_VSYNC }, - { ID_VIEW_ENABLEFRAMETIMECORRECTION, 0, 0, IDS_AG_ENABLEFRAMETIMECORRECTION }, - { ID_VIEW_VSYNCACCURATE, 'V', FCONTROL | FALT, IDS_AG_VSYNCACCURATE }, - { ID_VIEW_VSYNCOFFSET_DECREASE, VK_UP, FCONTROL | FALT, IDS_AG_VSYNCOFFSET_DECREASE }, - { ID_VIEW_VSYNCOFFSET_INCREASE, VK_DOWN, FCONTROL | FALT, IDS_AG_VSYNCOFFSET_INCREASE }, - { ID_SUB_DELAY_DOWN, VK_F1, 0, IDS_MPLAYERC_104 }, - { ID_SUB_DELAY_UP, VK_F2, 0, IDS_MPLAYERC_105 }, - { ID_SUB_POS_DOWN, VK_SUBTRACT, FCONTROL | FSHIFT, IDS_SUB_POS_DOWN }, - { ID_SUB_POS_UP, VK_ADD, FCONTROL | FSHIFT, IDS_SUB_POS_UP }, - { ID_SUB_FONT_SIZE_DEC, VK_SUBTRACT, FCONTROL, IDS_SUB_FONT_SIZE_DEC }, - { ID_SUB_FONT_SIZE_INC, VK_ADD, FCONTROL, IDS_SUB_FONT_SIZE_INC }, - - { ID_AFTERPLAYBACK_DONOTHING, 0, 0, IDS_AFTERPLAYBACK_DONOTHING }, - { ID_AFTERPLAYBACK_PLAYNEXT, 0, 0, IDS_AFTERPLAYBACK_PLAYNEXT }, - { ID_AFTERPLAYBACK_MONITOROFF, 0, 0, IDS_AFTERPLAYBACK_MONITOROFF }, - { ID_AFTERPLAYBACK_EXIT, 0, 0, IDS_AFTERPLAYBACK_EXIT }, - { ID_AFTERPLAYBACK_STANDBY, 0, 0, IDS_AFTERPLAYBACK_STANDBY }, - { ID_AFTERPLAYBACK_HIBERNATE, 0, 0, IDS_AFTERPLAYBACK_HIBERNATE }, - { ID_AFTERPLAYBACK_SHUTDOWN, 0, 0, IDS_AFTERPLAYBACK_SHUTDOWN }, - { ID_AFTERPLAYBACK_LOGOFF, 0, 0, IDS_AFTERPLAYBACK_LOGOFF }, - { ID_AFTERPLAYBACK_LOCK, 0, 0, IDS_AFTERPLAYBACK_LOCK }, - - { ID_VIEW_EDITLISTEDITOR, 0, 0, IDS_AG_TOGGLE_EDITLISTEDITOR }, - { ID_EDL_IN, 0, 0, IDS_AG_EDL_IN }, - { ID_EDL_OUT, 0, 0, IDS_AG_EDL_OUT }, - { ID_EDL_NEWCLIP, 0, 0, IDS_AG_EDL_NEW_CLIP }, - { ID_EDL_SAVE, 0, 0, IDS_AG_EDL_SAVE }, - - { ID_PLAYLIST_TOGGLE_SHUFFLE, 0, 0, IDS_PLAYLIST_TOGGLE_SHUFFLE }, - { ID_AUDIOSHIFT_ONOFF, 0, 0, IDS_AUDIOSHIFT_ONOFF }, -}; - -void CAppSettings::CreateCommands() -{ - for (const auto& wc : default_wmcmds) { - wmcmd w = wmcmd(wc); - w.fVirt |= FVIRTKEY | FNOINVERT; - CommandIDToWMCMD[wc.cmd] = &wc; - wmcmds.AddTail(w); - } - ASSERT(wmcmds.GetCount() <= ACCEL_LIST_SIZE); -} - -CAppSettings::~CAppSettings() -{ - if (hAccel) { - DestroyAcceleratorTable(hAccel); - } -} - -bool CAppSettings::IsD3DFullscreen() const -{ - if (iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || iDSVideoRendererType == VIDRNDT_DS_SYNC) { - return fD3DFullscreen || (nCLSwitches & CLSW_D3DFULLSCREEN); - } else { - return false; - } -} - -bool CAppSettings::IsISRAutoLoadEnabled() const -{ - return eSubtitleRenderer == SubtitleRenderer::INTERNAL && - IsSubtitleRendererSupported(eSubtitleRenderer, iDSVideoRendererType); -} - -CAppSettings::SubtitleRenderer CAppSettings::GetSubtitleRenderer() const -{ - switch (eSubtitleRenderer) { - case SubtitleRenderer::INTERNAL: - return IsSubtitleRendererSupported(SubtitleRenderer::INTERNAL, iDSVideoRendererType) ? eSubtitleRenderer : SubtitleRenderer::VS_FILTER; - case SubtitleRenderer::XY_SUB_FILTER: - return IsSubtitleRendererSupported(SubtitleRenderer::XY_SUB_FILTER, iDSVideoRendererType) ? eSubtitleRenderer : SubtitleRenderer::VS_FILTER; - default: - return eSubtitleRenderer; - } -} - -bool CAppSettings::IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer) -{ - switch (eSubtitleRenderer) { - case SubtitleRenderer::INTERNAL: - return true; - case SubtitleRenderer::VS_FILTER: - return IsCLSIDRegistered(CLSID_VSFilter); - case SubtitleRenderer::XY_SUB_FILTER: - return IsCLSIDRegistered(CLSID_XySubFilter); - case SubtitleRenderer::NONE: - return true; - default: - ASSERT(FALSE); - return false; - } -} - -bool CAppSettings::IsSubtitleRendererSupported(SubtitleRenderer eSubtitleRenderer, int videoRenderer) -{ - switch (eSubtitleRenderer) { - case SubtitleRenderer::INTERNAL: - switch (videoRenderer) { - case VIDRNDT_DS_VMR9RENDERLESS: - case VIDRNDT_DS_EVR_CUSTOM: - case VIDRNDT_DS_DXR: - case VIDRNDT_DS_SYNC: - case VIDRNDT_DS_MADVR: - case VIDRNDT_DS_MPCVR: - return true; - } - break; - - case SubtitleRenderer::VS_FILTER: - return true; - - case SubtitleRenderer::XY_SUB_FILTER: - switch (videoRenderer) { - case VIDRNDT_DS_VMR9RENDERLESS: - case VIDRNDT_DS_EVR_CUSTOM: - case VIDRNDT_DS_SYNC: - case VIDRNDT_DS_MADVR: - case VIDRNDT_DS_MPCVR: - return true; - } - break; - case SubtitleRenderer::NONE: - return true; - - default: - ASSERT(FALSE); - } - - return false; -} - -bool CAppSettings::IsVideoRendererAvailable(int iVideoRendererType) -{ - switch (iVideoRendererType) { - case VIDRNDT_DS_DXR: - return IsCLSIDRegistered(CLSID_DXR); - case VIDRNDT_DS_EVR: - case VIDRNDT_DS_EVR_CUSTOM: - case VIDRNDT_DS_SYNC: - return IsCLSIDRegistered(CLSID_EnhancedVideoRenderer); - case VIDRNDT_DS_MADVR: - return IsCLSIDRegistered(CLSID_madVR); - case VIDRNDT_DS_MPCVR: - return IsCLSIDRegistered(CLSID_MPCVR) || DSObjects::CMPCVRAllocatorPresenter::HasInternalMPCVRFilter(); -#ifdef _WIN64 - case VIDRNDT_DS_OVERLAYMIXER: - return false; -#endif - default: - return true; - } -} - -bool CAppSettings::IsInitialized() const -{ - return bInitialized; -} - -CString CAppSettings::SelectedAudioRenderer() const -{ - CString strResult; - if (!AfxGetMyApp()->m_AudioRendererDisplayName_CL.IsEmpty()) { - strResult = AfxGetMyApp()->m_AudioRendererDisplayName_CL; - } else { - strResult = AfxGetAppSettings().strAudioRendererDisplayName; - } - - return strResult; -} - -void CAppSettings::ClearRecentFiles() { - MRU.RemoveAll(); - - for (int i = MRUDub.GetSize() - 1; i >= 0; i--) { - MRUDub.Remove(i); - } - MRUDub.WriteList(); - - // Empty the Windows "Recent" jump list - CComPtr pDests; - HRESULT hr = pDests.CoCreateInstance(CLSID_ApplicationDestinations, nullptr, CLSCTX_INPROC_SERVER); - if (SUCCEEDED(hr)) { - pDests->RemoveAllDestinations(); - } -} - -void CAppSettings::SaveSettings(bool write_full_history /* = false */) -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - if (!bInitialized) { - return; - } - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECAPTIONMENU, eCaptionMenuMode); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDENAVIGATION, fHideNavigation); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CONTROLSTATE, nCS); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTVIDEOFRAME, iDefaultVideoSize); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPASPECTRATIO, fKeepAspectRatio); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COMPMONDESKARDIFF, fCompMonDeskARDiff); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUME, nVolume); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BALANCE, nBalance); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUMESTEP, nVolumeStep); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPEEDSTEP, nSpeedStep); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MUTE, fMute); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPNUM, nLoops); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP, fLoopForever); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPMODE, static_cast(eLoopMode)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ZOOM, iZoomLevel); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, fAllowMultipleInst); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTSTYLE, iTitleBarTextStyle); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTTITLE, fTitleBarTextTitle); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ONTOP, iOnTop); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TRAYICON, fTrayIcon); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOZOOM, fRememberZoomLevel); - pApp->WriteProfileStringW(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR, NULL); //remove old form factor - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MIN, nAutoFitFactorMin); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MAX, nAutoFitFactorMax); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AFTER_PLAYBACK, static_cast(eAfterPlayback)); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS, bHideFullscreenControls)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_POLICY, - static_cast(eHideFullscreenControlsPolicy))); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_DELAY, uHideFullscreenControlsDelay)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_DOCKED_PANELS, bHideFullscreenDockedPanels)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_CONTROLS, bHideWindowedControls)); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_MOUSE_POINTER, bHideWindowedMousePointer)); - - // Auto-change fullscreen mode - SaveSettingsAutoChangeFullScreenMode(); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_EXITFULLSCREENATTHEEND, fExitFullScreenAtTheEnd); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWPOS, fRememberWindowPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWSIZE, fRememberWindowSize); - if (fRememberWindowSize || fRememberWindowPos) { - pApp->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_LASTWINDOWRECT, (BYTE*)&rcLastWindowPos, sizeof(rcLastWindowPos)); - } - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTWINDOWTYPE, nLastWindowType); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTFULLSCREEN, fLastFullScreen); - - if (fSavePnSZoom) { - CString str; - str.Format(_T("%.3f,%.3f"), dZoomX, dZoomY); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM, str); - } else { - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM, nullptr); - } - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPTODESKTOPEDGES, fSnapToDesktopEdges); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_X, sizeAspectRatio.cx); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_Y, sizeAspectRatio.cy); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPHISTORY, fKeepHistory); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RECENT_FILES_NUMBER, iRecentFilesNumber); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, iDSVideoRendererType); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHUFFLEPLAYLISTITEMS, bShufflePlaylistItems); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERPLAYLISTITEMS, bRememberPlaylistItems); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDEPLAYLISTFULLSCREEN, bHidePlaylistFullScreen); - pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERPOS, bFavRememberPos); - pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_RELATIVEDRIVE, bFavRelativeDrive); - pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERABMARKS, bFavRememberABMarks); - - UpdateRenderersData(true); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUDIORENDERERTYPE, CString(strAudioRendererDisplayName)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOLOADAUDIO, fAutoloadAudio); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER, CString(strSubtitlesLanguageOrder)); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER, CString(strAudiosLanguageOrder)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKVSFILTER, fBlockVSFilter); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKRDP, bBlockRDP); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWORKERTHREADFOROPENING, fEnableWorkerThreadForOpening); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REPORTFAILEDPINS, fReportFailedPins); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_DVDPATH, strDVDPath); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USEDVDPATH, fUseDVDPath); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MENULANG, idMenuLang); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOLANG, idAudioLang); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANG, idSubtitlesLang); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_OPENTYPELANGHINT, CString(strOpenTypeLangHint)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_FREETYPE, bUseFreeType); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_MEDIAINFO_LOAD_FILE_DURATION, bUseMediainfoLoadFileDuration); -#if USE_LIBASS - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSSAUSINGLIBASS, bRenderSSAUsingLibass); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSRTUSINGLIBASS, bRenderSRTUsingLibass); -#endif - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CLOSEDCAPTIONS, fClosedCaptions); - CString style; - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SPSTYLE, style <<= subtitlesDefStyle); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPOVERRIDEPLACEMENT, fOverridePlacement); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPHORPOS, nHorPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPVERPOS, nVerPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLEARCOMPENSATION, bSubtitleARCompensation); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBDELAYINTERVAL, nSubDelayStep); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLESUBTITLES, fEnableSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREFER_FORCED_DEFAULT_SUBTITLES, bPreferDefaultForcedSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITIZEEXTERNALSUBTITLES, fPrioritizeExternalSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLEINTERNALSUBTITLES, fDisableInternalSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_OVERRIDING_EXT_SPLITTER, bAllowOverridingExternalSplitterChoice); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLES, bAutoDownloadSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOSAVEDOWNLOADEDSUBTITLES, bAutoSaveDownloadedSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCOREMOVIES, nAutoDownloadScoreMovies); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCORESERIES, nAutoDownloadScoreSeries); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLESEXCLUDE, strAutoDownloadSubtitlesExclude); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOUPLOADSUBTITLES, bAutoUploadSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREFERHEARINGIMPAIREDSUBTITLES, bPreferHearingImpairedSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MPCTHEME, bMPCTheme); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNSEEKBARHEIGHT, iModernSeekbarHeight); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNTHEMEMODE, static_cast(eModernThemeMode)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_DELAY, iFullscreenDelay); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VERTICALALIGNVIDEO, static_cast(iVerticalAlignVideo)); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESPROVIDERS, strSubtitlesProviders); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLEPATHS, strSubtitlePaths); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_DEFAULT_STYLE, bSubtitleOverrideDefaultStyle); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_ALL_STYLES, bSubtitleOverrideAllStyles); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOSWITCHER, fEnableAudioSwitcher); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOTIMESHIFT, fAudioTimeShift); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOTIMESHIFT, iAudioTimeShift); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DOWNSAMPLETO441, fDownSampleTo441); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CUSTOMCHANNELMAPPING, fCustomChannelMapping); - pApp->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_SPEAKERTOCHANNELMAPPING, (BYTE*)pSpeakerToChannelMap, sizeof(pSpeakerToChannelMap)); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZE, fAudioNormalize); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOMAXNORMFACTOR, nAudioMaxNormFactor); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZERECOVER, fAudioNormalizeRecover); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, nAudioBoost); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPEAKERCHANNELS, nSpeakerChannels); - - // Multi-monitor code - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITOR, CString(strFullScreenMonitorID)); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITORDEVICE, CString(strFullScreenMonitorDeviceName)); - - // Mouse - CStringW str; - str.Format(L"%u", nMouseLeftClick); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT, str); - str.Format(L"%u", nMouseLeftDblClick); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT_DBLCLICK, str); - str.Format(L"%u", nMouseRightClick); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_RIGHT, str); - str.Format(L"%u;%u;%u;%u", MouseMiddleClick.normal, MouseMiddleClick.ctrl, MouseMiddleClick.shift, MouseMiddleClick.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_MIDDLE, str); - str.Format(L"%u;%u;%u;%u", MouseX1Click.normal, MouseX1Click.ctrl, MouseX1Click.shift, MouseX1Click.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X1, str); - str.Format(L"%u;%u;%u;%u", MouseX2Click.normal, MouseX2Click.ctrl, MouseX2Click.shift, MouseX2Click.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X2, str); - str.Format(L"%u;%u;%u;%u", MouseWheelUp.normal, MouseWheelUp.ctrl, MouseWheelUp.shift, MouseWheelUp.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_UP, str); - str.Format(L"%u;%u;%u;%u", MouseWheelDown.normal, MouseWheelDown.ctrl, MouseWheelDown.shift, MouseWheelDown.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_DOWN, str); - str.Format(L"%u;%u;%u;%u", MouseWheelLeft.normal, MouseWheelLeft.ctrl, MouseWheelLeft.shift, MouseWheelLeft.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_LEFT, str); - str.Format(L"%u;%u;%u;%u", MouseWheelRight.normal, MouseWheelRight.ctrl, MouseWheelRight.shift, MouseWheelRight.rbtn); - pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_RIGHT, str); - - - // Prevent Minimize when in Fullscreen mode on non default monitor - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_MINIMIZE, fPreventMinimize); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENHANCED_TASKBAR, bUseEnhancedTaskBar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEARCH_IN_FOLDER, fUseSearchInFolder); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TIME_TOOLTIP, fUseSeekbarHover); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_TOOLTIP_POSITION, nHoverPosition); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MPC_OSD_SIZE, nOSDSize); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_MPC_OSD_FONT, strOSDFont); - - // Associated types with icon or not... - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASSOCIATED_WITH_ICON, fAssociatedWithIcons); - // Last Open Dir - //pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_LAST_OPEN_DIR, strLastOpenDir); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_D3DFULLSCREEN, fD3DFullscreen); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_BRIGHTNESS, iBrightness); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_CONTRAST, iContrast); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_HUE, iHue); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_SATURATION, iSaturation); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOWOSD, fShowOSD); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CURRENT_TIME_OSD, fShowCurrentTimeInOSD); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_TRANSPARENCY, nOSDTransparency); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_BORDER, nOSDBorder); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEEDLEDITOR, fEnableEDLEditor); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LANGUAGE, language); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK, bFastSeek); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK_METHOD, eFastSeekMethod); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CHAPTERS, fShowChapters); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, fLCDSupport); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW, fSeekPreview); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW_SIZE, iSeekPreviewSize); - - - // Save analog capture settings - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, iDefaultCaptureDevice); - pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, strAnalogVideo); - pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, strAnalogAudio); - pApp->WriteProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, iAnalogCountry); - - // Save digital capture settings (BDA) - pApp->WriteProfileString(IDS_R_DVB, nullptr, nullptr); // Ensure the section is cleared before saving the new settings - - //pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER, strBDANetworkProvider); - pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER, strBDATuner); - pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER, strBDAReceiver); - //pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD, strBDAStandard); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, iBDAScanFreqStart); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, iBDAScanFreqEnd); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, iBDABandwidth); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SYMBOLRATE, iBDASymbolRate); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_USE_OFFSET, fBDAUseOffset); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_OFFSET, iBDAOffset); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_IGNORE_ENCRYPTED_CHANNELS, fBDAIgnoreEncryptedChannels); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, nDVBLastChannel); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, nDVBRebuildFilterGraph); - pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, nDVBStopFilterGraph); - - for (size_t i = 0; i < m_DVBChannels.size(); i++) { - CString numChannel; - numChannel.Format(_T("%Iu"), i); - pApp->WriteProfileString(IDS_R_DVB, numChannel, m_DVBChannels[i].ToString()); - } - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DVDPOS, fRememberDVDPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS, fRememberFilePos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSLONGER, iRememberPosForLongerThan); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSAUDIO, bRememberPosForAudioFiles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_PLAYLIST, bRememberExternalPlaylistPos); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_TRACK_SELECTION, bRememberTrackSelection); - - pApp->WriteProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, nullptr, nullptr); - for (INT_PTR i = 0, j = m_pnspresets.GetCount(); i < j; i++) { - CString str; - str.Format(_T("Preset%Id"), i); - pApp->WriteProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, str, m_pnspresets[i]); - } - - pApp->WriteProfileString(IDS_R_COMMANDS, nullptr, nullptr); - POSITION pos = wmcmds.GetHeadPosition(); - for (int i = 0; pos;) { - const wmcmd& wc = wmcmds.GetNext(pos); - if (wc.IsModified()) { - CString str; - str.Format(_T("CommandMod%d"), i); - // mouse and mouseVirt are written twice for backwards compatibility with old versions - CString str2; - str2.Format(_T("%hu %hx %hx \"%S\" %d %hhu %u %hhu %hhu %hhu"), - wc.cmd, (WORD)wc.fVirt, wc.key, wc.rmcmd.GetString(), - wc.rmrepcnt, wc.mouse, wc.appcmd, wc.mouse, wc.mouseVirt, wc.mouseVirt); - pApp->WriteProfileString(IDS_R_COMMANDS, str, str2); - i++; - } - } - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WINLIRC, fWinLirc); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WINLIRCADDR, strWinLircAddr); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UICE, fUIce); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_UICEADDR, strUIceAddr); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GLOBALMEDIA, fGlobalMedia); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTS, nJumpDistS); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTM, nJumpDistM); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTL, nJumpDistL); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LIMITWINDOWPROPORTIONS, fLimitWindowProportions); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTUSEDPAGE, nLastUsedPage); - - m_Formats.UpdateData(true); - - // Internal filters - for (int f = 0; f < SRC_LAST; f++) { - pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, SrcFiltersKeys[f].name, SrcFilters[f]); - } - for (int f = 0; f < TRA_LAST; f++) { - pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, TraFiltersKeys[f].name, TraFilters[f]); - } - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_LOGOFILE, strLogoFileName); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOID, nLogoId); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOEXT, fLogoExternal); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOCOLORPROFILE, fLogoColorProfileEnabled); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECDROMSSUBMENU, fHideCDROMsSubMenu); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITY, dwPriority); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LAUNCHFULLSCREEN, fLaunchfullscreen); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWEBSERVER, fEnableWebServer); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPORT, nWebServerPort); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERUSECOMPRESSION, fWebServerUseCompression); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERLOCALHOSTONLY, fWebServerLocalhostOnly); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBUI_ENABLE_PREVIEW, bWebUIEnablePreview); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPRINTDEBUGINFO, fWebServerPrintDebugInfo); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBROOT, strWebRoot); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBDEFINDEX, strWebDefIndex); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBSERVERCGI, strWebServerCGI); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTPATH, strSnapshotPath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTEXT, strSnapshotExt); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTSUBTITLES, bSnapShotSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTKEEPVIDEOEXTENSION, bSnapShotKeepVideoExtension); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBROWS, iThumbRows); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBCOLS, iThumbCols); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBWIDTH, iThumbWidth); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBSAVEEXTERNALSTYLEFILE, bSubSaveExternalStyleFile)); - { - // Save the list of extra (non-default) shader files - VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_EXTRA, m_ShadersExtraList.ToString())); - // Save shader selection - CString strPre, strPost; - m_Shaders.GetCurrentPreset().ToStrings(strPre, strPost); - VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_PRERESIZE, strPre)); - VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_POSTRESIZE, strPost)); - // Save shader presets - int i = 0; - CString iStr; - pApp->WriteProfileString(IDS_R_SHADER_PRESETS, nullptr, nullptr); - for (const auto& pair : m_Shaders.GetPresets()) { - iStr.Format(_T("%d"), i++); - pair.second.ToStrings(strPre, strPost); - VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, iStr, pair.first)); - VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_PRERESIZE + iStr, strPre)); - VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_POSTRESIZE + iStr, strPost)); - } - // Save selected preset name - CString name; - m_Shaders.GetCurrentPresetName(name); - VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_LASTPRESET, name)); - } - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADER, bToggleShader); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADERSSCREENSPACE, bToggleShaderScreenSpace); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMAINING_TIME, fRemainingTime); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIGH_PRECISION_TIMER, bHighPrecisionTimer); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIMER_SHOW_PERCENTAGE, bTimerShowPercentage); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_AUTO_CHECK, nUpdaterAutoCheck); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_DELAY, nUpdaterDelay); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_NOTIFY_SKYPE, bNotifySkype); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JPEG_QUALITY, nJpegQuality); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART, bEnableCoverArt); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART_SIZE_LIMIT, nCoverArtSizeLimit); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGGING, bEnableLogging); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_LEGACY_TOOLBAR, bUseLegacyToolbar); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, - static_cast(eSubtitleRenderer))); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTTOOLBARSIZE, nDefaultToolbarSize); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_POSITION, bSaveImagePosition); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_CURRENTTIME, bSaveImageCurrentTime); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_INACCURATE_FASTSEEK, bAllowInaccurateFastseek); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP_FOLDER_NEXT_FILE, bLoopFolderOnPlayNextFile); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOCK_NOPAUSE, bLockNoPause); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_DISPLAY_SLEEP, bPreventDisplaySleep); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_SMTC, bUseSMTC); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RELOAD_AFTER_LONG_PAUSE, iReloadAfterLongPause); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OPEN_REC_PANEL_WHEN_OPENING_DEVICE, bOpenRecPanelWhenOpeningDevice); - - { - CComHeapPtr pDeviceId; - BOOL bExclusive; - UINT32 uBufferDuration; - if (SUCCEEDED(sanear->GetOutputDevice(&pDeviceId, &bExclusive, &uBufferDuration))) { - pApp->WriteProfileString(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_ID, pDeviceId); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_EXCLUSIVE, bExclusive); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_BUFFER, uBufferDuration); - } - - BOOL bCrossfeedEnabled = sanear->GetCrossfeedEnabled(); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_ENABLED, bCrossfeedEnabled); - - UINT32 uCutoffFrequency, uCrossfeedLevel; - sanear->GetCrossfeedSettings(&uCutoffFrequency, &uCrossfeedLevel); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ, uCutoffFrequency); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, uCrossfeedLevel); - - BOOL bIgnoreSystemChannelMixer = sanear->GetIgnoreSystemChannelMixer(); - pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_IGNORE_SYSTEM_MIXER, bIgnoreSystemChannelMixer); - } - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_YDL, bUseYDL); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, iYDLMaxHeight); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_VIDEO_FORMAT, iYDLVideoFormat); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_FORMAT, iYDLAudioFormat); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, bYDLAudioOnly); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_EXEPATH, sYDLExePath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_COMMAND_LINE, sYDLCommandLine); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLE_CRASH_REPORTER, bEnableCrashReporter); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_REFRESH_INTERVAL, nStreamPosPollerInterval); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_LANG_STATUSBAR, bShowLangInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_FPS_STATUSBAR, bShowFPSInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_ABMARKS_STATUSBAR, bShowABMarksInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_VIDEOINFO_STATUSBAR, bShowVideoInfoInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_AUDIOFORMAT_STATUSBAR, bShowAudioFormatInStatusbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ADD_LANGCODE_WHEN_SAVE_SUBTITLES, bAddLangCodeWhenSaveSubtitles); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TITLE_IN_RECENT_FILE_LIST, bUseTitleInRecentFileList); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_SUBS_PREFERENCE, sYDLSubsPreference); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_AUTOMATIC_CAPTIONS, bUseAutomaticCaptions); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_QUICKOPEN_PATH, lastQuickOpenPath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_FILESAVECOPY_PATH, lastFileSaveCopyPath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_FILEOPENDIR_PATH, lastFileOpenDirPath); - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_EXTERNAL_PLAYLIST_PATH, externalPlayListPath); - - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REDIRECT_OPEN_TO_APPEND_THRESHOLD, iRedirectOpenToAppendThreshold); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_SEPARATE_CONTROLS, bFullscreenSeparateControls); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALWAYS_USE_SHORT_MENU, bAlwaysUseShortMenu); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_STILL_VIDEO_DURATION, iStillVideoDuration); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MOUSE_LEFTUP_DELAY, iMouseLeftUpDelay); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CAPTURE_DEINTERLACE, bCaptureDeinterlace); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PAUSE_WHILE_DRAGGING_SEEKBAR, bPauseWhileDraggingSeekbar); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CONFIRM_FILE_DELETE, bConfirmFileDelete); - - if (fKeepHistory && write_full_history) { - MRU.SaveMediaHistory(); - } - - pApp->FlushProfile(); -} - -void CAppSettings::PurgeMediaHistory(size_t maxsize) { - CStringW section = L"MediaHistory"; - auto timeToHash = LoadHistoryHashes(section, L"LastUpdated"); - size_t entries = timeToHash.size(); - if (entries > maxsize) { - for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { - if (entries > maxsize) { - PurgeExpiredHash(section, iter->second); - entries--; - } else { - break; - } - } - } -} - -void CAppSettings::PurgePlaylistHistory(size_t maxsize) { - CStringW section = L"PlaylistHistory"; - auto timeToHash = LoadHistoryHashes(section, L"LastUpdated"); - size_t entries = timeToHash.size(); - if (entries > maxsize) { - for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { - if (entries > maxsize) { - PurgeExpiredHash(section, iter->second); - entries--; - } else { - break; - } - } - } -} - -std::multimap CAppSettings::LoadHistoryHashes(CStringW section, CStringW dateField) { - auto pApp = AfxGetMyApp(); - auto hashes = pApp->GetSectionSubKeys(section); - - std::multimap timeToHash; - for (auto const& hash : hashes) { - CStringW lastOpened, subSection; - subSection.Format(L"%s\\%s", section, static_cast(hash)); - lastOpened = pApp->GetProfileStringW(subSection, dateField, L"0000-00-00T00:00:00.0Z"); - if (!lastOpened.IsEmpty()) { - timeToHash.insert(std::pair(lastOpened, hash)); - } - } - return timeToHash; -} - -void CAppSettings::PurgeExpiredHash(CStringW section, CStringW hash) { - auto pApp = AfxGetMyApp(); - CStringW subSection; - subSection.Format(L"%s\\%s", section, static_cast(hash)); - pApp->WriteProfileString(subSection, nullptr, nullptr); -} - -void CAppSettings::LoadExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey /*= IDS_R_EXTERNAL_FILTERS*/) -{ - CWinApp* pApp = AfxGetApp(); - ASSERT(pApp); - - for (unsigned int i = 0; ; i++) { - CString key; - key.Format(_T("%s\\%04u"), baseKey, i); - - CAutoPtr f(DEBUG_NEW FilterOverride); - - f->fDisabled = !pApp->GetProfileInt(key, _T("Enabled"), FALSE); - - UINT j = pApp->GetProfileInt(key, _T("SourceType"), -1); - if (j == 0) { - f->type = FilterOverride::REGISTERED; - f->dispname = CStringW(pApp->GetProfileString(key, _T("DisplayName"))); - f->name = pApp->GetProfileString(key, _T("Name")); - CString clsid_str = pApp->GetProfileString(key, _T("CLSID")); - if (clsid_str.IsEmpty() && f->dispname.GetLength() == 88 && f->dispname.Left(1) == L"@") { - clsid_str = f->dispname.Right(38); - } - if (clsid_str.GetLength() == 38) { - f->clsid = GUIDFromCString(clsid_str); - } - } else if (j == 1) { - f->type = FilterOverride::EXTERNAL; - f->path = pApp->GetProfileString(key, _T("Path")); - f->name = pApp->GetProfileString(key, _T("Name")); - f->clsid = GUIDFromCString(pApp->GetProfileString(key, _T("CLSID"))); - } else { - pApp->WriteProfileString(key, nullptr, 0); - break; - } - - if (IgnoreExternalFilter(f->clsid)) { - continue; - } - - f->backup.RemoveAll(); - for (unsigned int k = 0; ; k++) { - CString val; - val.Format(_T("org%04u"), k); - CString guid = pApp->GetProfileString(key, val); - if (guid.IsEmpty()) { - break; - } - f->backup.AddTail(GUIDFromCString(guid)); - } - - f->guids.RemoveAll(); - for (unsigned int k = 0; ; k++) { - CString val; - val.Format(_T("mod%04u"), k); - CString guid = pApp->GetProfileString(key, val); - if (guid.IsEmpty()) { - break; - } - f->guids.AddTail(GUIDFromCString(guid)); - } - - f->iLoadType = (int)pApp->GetProfileInt(key, _T("LoadType"), -1); - if (f->iLoadType < 0) { - break; - } - - f->dwMerit = pApp->GetProfileInt(key, _T("Merit"), MERIT_DO_NOT_USE + 1); - - filters.AddTail(f); - } -} - -void CAppSettings::SaveExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey /*= IDS_R_EXTERNAL_FILTERS*/) -{ - // Saving External Filter settings takes a long time. Use only when really necessary. - CWinApp* pApp = AfxGetApp(); - ASSERT(pApp); - - // Remove the old keys - for (unsigned int i = 0; ; i++) { - CString key; - key.Format(_T("%s\\%04u"), baseKey, i); - int j = pApp->GetProfileInt(key, _T("Enabled"), -1); - pApp->WriteProfileString(key, nullptr, nullptr); - if (j < 0) { - break; - } - } - - unsigned int k = 0; - POSITION pos = filters.GetHeadPosition(); - while (pos) { - FilterOverride* f = filters.GetNext(pos); - - if (f->fTemporary) { - continue; - } - - CString key; - key.Format(_T("%s\\%04u"), baseKey, k); - - pApp->WriteProfileInt(key, _T("SourceType"), (int)f->type); - pApp->WriteProfileInt(key, _T("Enabled"), (int)!f->fDisabled); - pApp->WriteProfileString(key, _T("Name"), f->name); - pApp->WriteProfileString(key, _T("CLSID"), CStringFromGUID(f->clsid)); - if (f->type == FilterOverride::REGISTERED) { - pApp->WriteProfileString(key, _T("DisplayName"), CString(f->dispname)); - } else if (f->type == FilterOverride::EXTERNAL) { - pApp->WriteProfileString(key, _T("Path"), f->path); - } - POSITION pos2 = f->backup.GetHeadPosition(); - for (unsigned int i = 0; pos2; i++) { - CString val; - val.Format(_T("org%04u"), i); - pApp->WriteProfileString(key, val, CStringFromGUID(f->backup.GetNext(pos2))); - } - pos2 = f->guids.GetHeadPosition(); - for (unsigned int i = 0; pos2; i++) { - CString val; - val.Format(_T("mod%04u"), i); - pApp->WriteProfileString(key, val, CStringFromGUID(f->guids.GetNext(pos2))); - } - pApp->WriteProfileInt(key, _T("LoadType"), f->iLoadType); - pApp->WriteProfileInt(key, _T("Merit"), f->dwMerit); - - k++; - } -} - -void CAppSettings::SaveSettingsAutoChangeFullScreenMode() -{ - auto pApp = AfxGetMyApp(); - ASSERT(pApp); - - // Ensure the section is cleared before saving the new settings - for (size_t i = 0;; i++) { - CString section; - section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); - - // WriteProfileString doesn't return false when INI is used and the section doesn't exist - // so instead check for the a value inside that section - if (!pApp->HasProfileEntry(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED)) { - break; - } else { - VERIFY(pApp->WriteProfileString(section, nullptr, nullptr)); - } - } - pApp->WriteProfileString(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, nullptr, nullptr); - - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_ENABLE, autoChangeFSMode.bEnabled)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_APPLYDEFMODEATFSEXIT, autoChangeFSMode.bApplyDefaultModeAtFSExit)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_RESTORERESAFTEREXIT, autoChangeFSMode.bRestoreResAfterProgExit)); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_DELAY, (int)autoChangeFSMode.uDelay)); - - for (size_t i = 0; i < autoChangeFSMode.modes.size(); i++) { - const auto& mode = autoChangeFSMode.modes[i]; - CString section; - section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); - - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED, mode.bChecked)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTART, std::lround(mode.dFrameRateStart * 1000000))); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTOP, std::lround(mode.dFrameRateStop * 1000000))); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_AUDIODELAY, mode.msAudioDelay)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_BPP, mode.dm.bpp)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FREQ, mode.dm.freq)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEX, mode.dm.size.cx)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEY, mode.dm.size.cy)); - VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FLAGS, (int)mode.dm.dwDisplayFlags)); - } -} - -void CAppSettings::LoadSettings() -{ - CWinApp* pApp = AfxGetApp(); - ASSERT(pApp); - - UINT len; - BYTE* ptr = nullptr; - - if (bInitialized) { - return; - } - - // Set interface language first! - language = (LANGID)pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LANGUAGE, -1); - if (language == LANGID(-1)) { - language = Translations::SetDefaultLanguage(); - } else if (language != 0) { - if (language <= 23) { - // We must be updating from a really old version, use the default language - language = Translations::SetDefaultLanguage(); - } else if (!Translations::SetLanguage(language, false)) { - // In case of error, reset the language to English - language = 0; - } - } - - CreateCommands(); - - eCaptionMenuMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECAPTIONMENU, MODE_SHOWCAPTIONMENU)); - fHideNavigation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDENAVIGATION, FALSE); - nCS = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CONTROLSTATE, CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR); - iDefaultVideoSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTVIDEOFRAME, DVS_FROMINSIDE); - fKeepAspectRatio = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPASPECTRATIO, TRUE); - fCompMonDeskARDiff = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COMPMONDESKARDIFF, FALSE); - nVolume = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUME, 100); - nBalance = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BALANCE, 0); - fMute = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MUTE, FALSE); - nLoops = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPNUM, 1); - fLoopForever = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP, FALSE); - eLoopMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPMODE, static_cast(LoopMode::PLAYLIST))); - iZoomLevel = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ZOOM, 1); - iDSVideoRendererType = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, - IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS); - nVolumeStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUMESTEP, 5); - nSpeedStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPEEDSTEP, 0); - if (nSpeedStep > 75) { - nSpeedStep = 75; - } - - UpdateRenderersData(false); - - strAudioRendererDisplayName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIORENDERERTYPE); - fAutoloadAudio = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOLOADAUDIO, TRUE); - strSubtitlesLanguageOrder = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER); - strAudiosLanguageOrder = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER); - fBlockVSFilter = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKVSFILTER, TRUE); - bBlockRDP = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKRDP, FALSE); - fEnableWorkerThreadForOpening = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWORKERTHREADFOROPENING, TRUE); - fReportFailedPins = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REPORTFAILEDPINS, TRUE); - fAllowMultipleInst = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, FALSE); - iTitleBarTextStyle = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTSTYLE, 1); - fTitleBarTextTitle = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTTITLE, FALSE); - iOnTop = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ONTOP, 0); - fTrayIcon = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TRAYICON, FALSE); - fRememberZoomLevel = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOZOOM, TRUE); - int tAutoFitFactor = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR, 0); //if found, old fit factor will be default for min/max - nAutoFitFactorMin = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MIN, tAutoFitFactor ? tAutoFitFactor : DEF_MIN_AUTOFIT_SCALE_FACTOR); //otherwise default min to DEF_MIN_AUTOFIT_SCALE_FACTOR - nAutoFitFactorMax = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MAX, tAutoFitFactor ? tAutoFitFactor : DEF_MAX_AUTOFIT_SCALE_FACTOR); //otherwise default max to DEF_MAX_AUTOFIT_SCALE_FACTOR - nAutoFitFactorMin = std::max(std::min(nAutoFitFactorMin, nAutoFitFactorMax), MIN_AUTOFIT_SCALE_FACTOR); - nAutoFitFactorMax = std::min(std::max(nAutoFitFactorMin, nAutoFitFactorMax), MAX_AUTOFIT_SCALE_FACTOR); - - eAfterPlayback = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AFTER_PLAYBACK, 0)); - - bHideFullscreenControls = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS, TRUE); - eHideFullscreenControlsPolicy = - static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_POLICY, 1)); - uHideFullscreenControlsDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_DELAY, 0); - bHideFullscreenDockedPanels = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_DOCKED_PANELS, TRUE); - bHideWindowedControls = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_CONTROLS, FALSE); - - bHideWindowedMousePointer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_MOUSE_POINTER, TRUE); - - // Multi-monitor code - strFullScreenMonitorID = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITOR); - strFullScreenMonitorDeviceName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITORDEVICE); - - // Mouse - CStringW str; - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT); - swscanf_s(str, L"%u", &nMouseLeftClick); - if (nMouseLeftClick != 0 && nMouseLeftClick != ID_PLAY_PLAYPAUSE && nMouseLeftClick != ID_VIEW_FULLSCREEN) { - nMouseLeftClick = ID_PLAY_PLAYPAUSE; - } - - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT_DBLCLICK); - swscanf_s(str, L"%u", &nMouseLeftDblClick); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_RIGHT); - swscanf_s(str, L"%u", &nMouseRightClick); - - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_MIDDLE); - swscanf_s(str, L"%u;%u;%u;%u", &MouseMiddleClick.normal, &MouseMiddleClick.ctrl, &MouseMiddleClick.shift, &MouseMiddleClick.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X1); - swscanf_s(str, L"%u;%u;%u;%u", &MouseX1Click.normal, &MouseX1Click.ctrl, &MouseX1Click.shift, &MouseX1Click.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X2); - swscanf_s(str, L"%u;%u;%u;%u", &MouseX2Click.normal, &MouseX2Click.ctrl, &MouseX2Click.shift, &MouseX2Click.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_UP); - swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelUp.normal, &MouseWheelUp.ctrl, &MouseWheelUp.shift, &MouseWheelUp.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_DOWN); - swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelDown.normal, &MouseWheelDown.ctrl, &MouseWheelDown.shift, &MouseWheelDown.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_LEFT); - swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelLeft.normal, &MouseWheelLeft.ctrl, &MouseWheelLeft.shift, &MouseWheelLeft.rbtn); - str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_RIGHT); - swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelRight.normal, &MouseWheelRight.ctrl, &MouseWheelRight.shift, &MouseWheelRight.rbtn); - - - // Prevent Minimize when in fullscreen mode on non default monitor - fPreventMinimize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_MINIMIZE, FALSE); - bUseEnhancedTaskBar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENHANCED_TASKBAR, TRUE); - fUseSearchInFolder = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEARCH_IN_FOLDER, TRUE); - fUseSeekbarHover = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TIME_TOOLTIP, TRUE); - nHoverPosition = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_TOOLTIP_POSITION, TIME_TOOLTIP_ABOVE_SEEKBAR); - nOSDSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MPC_OSD_SIZE, 18); - LOGFONT lf; - GetMessageFont(&lf); - strOSDFont = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_MPC_OSD_FONT, lf.lfFaceName); - if (strOSDFont.IsEmpty() || strOSDFont.GetLength() >= LF_FACESIZE) { - strOSDFont = lf.lfFaceName; - } - - // Associated types with icon or not... - fAssociatedWithIcons = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASSOCIATED_WITH_ICON, TRUE); - // Last Open Dir - //strLastOpenDir = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_LAST_OPEN_DIR, _T("C:\\")); - - fAudioTimeShift = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOTIMESHIFT, FALSE); - iAudioTimeShift = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOTIMESHIFT, 0); - - // Auto-change fullscreen mode - autoChangeFSMode.bEnabled = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_ENABLE, FALSE); - autoChangeFSMode.bApplyDefaultModeAtFSExit = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_APPLYDEFMODEATFSEXIT, FALSE); - autoChangeFSMode.bRestoreResAfterProgExit = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_RESTORERESAFTEREXIT, TRUE); - autoChangeFSMode.uDelay = pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_DELAY, 0); - - autoChangeFSMode.modes.clear(); - for (size_t i = 0;; i++) { - CString section; - section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); - - int iChecked = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED, INT_ERROR); - if (iChecked == INT_ERROR) { - break; - } - - double dFrameRateStart = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTART, 0) / 1000000.0; - double dFrameRateStop = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTOP, 0) / 1000000.0; - int msAudioDelay = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_AUDIODELAY, fAudioTimeShift ? iAudioTimeShift : 0); - DisplayMode dm; - dm.bValid = true; - dm.bpp = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_BPP, 0); - dm.freq = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FREQ, 0); - dm.size.cx = (LONG)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEX, 0); - dm.size.cy = (LONG)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEY, 0); - dm.dwDisplayFlags = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FLAGS, 0); - - autoChangeFSMode.modes.emplace_back(!!iChecked, dFrameRateStart, dFrameRateStop, msAudioDelay, std::move(dm)); - } - - fExitFullScreenAtTheEnd = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_EXITFULLSCREENATTHEEND, TRUE); - - fRememberWindowPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWPOS, FALSE); - fRememberWindowSize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWSIZE, FALSE); - str = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM); - if (_stscanf_s(str, _T("%lf,%lf"), &dZoomX, &dZoomY) == 2 && - dZoomX >= 0.196 && dZoomX <= 5.0 && - dZoomY >= 0.196 && dZoomY <= 5.0) { - fSavePnSZoom = true; - } else { - fSavePnSZoom = false; - dZoomX = 1.0; - dZoomY = 1.0; - } - fSnapToDesktopEdges = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPTODESKTOPEDGES, FALSE); - sizeAspectRatio.cx = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_X, 0); - sizeAspectRatio.cy = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_Y, 0); - - fKeepHistory = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPHISTORY, TRUE); - fileAssoc.SetNoRecentDocs(!fKeepHistory); - iRecentFilesNumber = std::max(0, (int)pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RECENT_FILES_NUMBER, 100)); - MRU.SetSize(iRecentFilesNumber); - - if (pApp->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_LASTWINDOWRECT, &ptr, &len)) { - if (len == sizeof(CRect)) { - memcpy(&rcLastWindowPos, ptr, sizeof(CRect)); - if (rcLastWindowPos.Width() < 250 || rcLastWindowPos.Height() < 80) { - rcLastWindowPos = CRect(100, 100, 500, 400); - } - } - delete[] ptr; - } - nLastWindowType = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTWINDOWTYPE, SIZE_RESTORED); - fLastFullScreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTFULLSCREEN, FALSE); - - bShufflePlaylistItems = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHUFFLEPLAYLISTITEMS, FALSE); - bRememberPlaylistItems = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERPLAYLISTITEMS, TRUE); - bHidePlaylistFullScreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDEPLAYLISTFULLSCREEN, FALSE); - bFavRememberPos = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERPOS, TRUE); - bFavRelativeDrive = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_RELATIVEDRIVE, FALSE); - bFavRememberABMarks = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERABMARKS, FALSE); - - strDVDPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_DVDPATH); - fUseDVDPath = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USEDVDPATH, FALSE); - idMenuLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MENULANG, 0); - idAudioLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOLANG, 0); - idSubtitlesLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANG, 0); -#if USE_LIBASS - bRenderSSAUsingLibass = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSSAUSINGLIBASS, FALSE); - bRenderSRTUsingLibass = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSRTUSINGLIBASS, FALSE); -#endif - CT2A tmpLangHint(pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_OPENTYPELANGHINT, _T(""))); - strOpenTypeLangHint = tmpLangHint; - bUseFreeType = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_FREETYPE, FALSE); - bUseMediainfoLoadFileDuration = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_MEDIAINFO_LOAD_FILE_DURATION, FALSE); - bCaptureDeinterlace = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CAPTURE_DEINTERLACE, FALSE); - bPauseWhileDraggingSeekbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PAUSE_WHILE_DRAGGING_SEEKBAR, TRUE); - bConfirmFileDelete = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CONFIRM_FILE_DELETE, TRUE); - - fClosedCaptions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CLOSEDCAPTIONS, FALSE); - { - CString temp = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SPSTYLE); - subtitlesDefStyle <<= temp; - if (temp.IsEmpty()) { // Position the text subtitles relative to the video frame by default - subtitlesDefStyle.relativeTo = STSStyle::AUTO; - } - } - fOverridePlacement = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPOVERRIDEPLACEMENT, FALSE); - nHorPos = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPHORPOS, 50); - nVerPos = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPVERPOS, 90); - bSubtitleARCompensation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLEARCOMPENSATION, TRUE); - nSubDelayStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBDELAYINTERVAL, 500); - if (nSubDelayStep < 10) { - nSubDelayStep = 500; - } - - fEnableSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLESUBTITLES, TRUE); - bPreferDefaultForcedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREFER_FORCED_DEFAULT_SUBTITLES, TRUE); - fPrioritizeExternalSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITIZEEXTERNALSUBTITLES, TRUE); - fDisableInternalSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLEINTERNALSUBTITLES, FALSE); - bAllowOverridingExternalSplitterChoice = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_OVERRIDING_EXT_SPLITTER, FALSE); - bAutoDownloadSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLES, FALSE); - bAutoSaveDownloadedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOSAVEDOWNLOADEDSUBTITLES, FALSE); - nAutoDownloadScoreMovies = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCOREMOVIES, 0x16); - nAutoDownloadScoreSeries = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCORESERIES, 0x18); - strAutoDownloadSubtitlesExclude = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLESEXCLUDE); - bAutoUploadSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOUPLOADSUBTITLES, FALSE); - bPreferHearingImpairedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREFERHEARINGIMPAIREDSUBTITLES, FALSE); - bMPCTheme = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MPCTHEME, TRUE); - if (IsWindows10OrGreater()) { - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"), KEY_READ)) { - DWORD useTheme = (DWORD)-1; - if (ERROR_SUCCESS == key.QueryDWORDValue(_T("AppsUseLightTheme"), useTheme)) { - if (0 == useTheme) { - bWindows10DarkThemeActive = true; - } - } - } - if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\DWM"), KEY_READ)) { - DWORD useColorPrevalence = (DWORD)-1; - if (ERROR_SUCCESS == key.QueryDWORDValue(_T("ColorPrevalence"), useColorPrevalence)) { - if (1 == useColorPrevalence) { - bWindows10AccentColorsEnabled = true; - } - } - } - } - iModernSeekbarHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNSEEKBARHEIGHT, DEF_MODERN_SEEKBAR_HEIGHT); - if (iModernSeekbarHeight < MIN_MODERN_SEEKBAR_HEIGHT || iModernSeekbarHeight > MAX_MODERN_SEEKBAR_HEIGHT) { - iModernSeekbarHeight = DEF_MODERN_SEEKBAR_HEIGHT; - } - - eModernThemeMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNTHEMEMODE, static_cast(CMPCTheme::ModernThemeMode::WINDOWSDEFAULT))); - - iFullscreenDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_DELAY, MIN_FULLSCREEN_DELAY); - if (iFullscreenDelay < MIN_FULLSCREEN_DELAY || iFullscreenDelay > MAX_FULLSCREEN_DELAY) { - iFullscreenDelay = MIN_FULLSCREEN_DELAY; - } - - int tVertAlign = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VERTICALALIGNVIDEO, static_cast(verticalAlignVideoType::ALIGN_MIDDLE)); - if (tVertAlign < static_cast(verticalAlignVideoType::ALIGN_MIDDLE) || tVertAlign > static_cast(verticalAlignVideoType::ALIGN_BOTTOM)) { - tVertAlign = static_cast(verticalAlignVideoType::ALIGN_MIDDLE); - } - iVerticalAlignVideo = static_cast(tVertAlign); - - strSubtitlesProviders = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESPROVIDERS, _T("<|OpenSubtitles2|||1|0|><|podnapisi|||1|0|><|Napisy24|||0|0|>")); - strSubtitlePaths = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLEPATHS, DEFAULT_SUBTITLE_PATHS); - bSubtitleOverrideDefaultStyle = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_DEFAULT_STYLE, FALSE); - bSubtitleOverrideAllStyles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_ALL_STYLES, FALSE); - - fEnableAudioSwitcher = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOSWITCHER, TRUE); - fDownSampleTo441 = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DOWNSAMPLETO441, FALSE); - fCustomChannelMapping = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CUSTOMCHANNELMAPPING, FALSE); - - BOOL bResult = pApp->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_SPEAKERTOCHANNELMAPPING, &ptr, &len); - if (bResult && len == sizeof(pSpeakerToChannelMap)) { - memcpy(pSpeakerToChannelMap, ptr, sizeof(pSpeakerToChannelMap)); - } else { - ZeroMemory(pSpeakerToChannelMap, sizeof(pSpeakerToChannelMap)); - for (int j = 0; j < 18; j++) { - for (int i = 0; i <= j; i++) { - pSpeakerToChannelMap[j][i] = 1 << i; - } - } - - pSpeakerToChannelMap[0][0] = 1 << 0; - pSpeakerToChannelMap[0][1] = 1 << 0; - - pSpeakerToChannelMap[3][0] = 1 << 0; - pSpeakerToChannelMap[3][1] = 1 << 1; - pSpeakerToChannelMap[3][2] = 0; - pSpeakerToChannelMap[3][3] = 0; - pSpeakerToChannelMap[3][4] = 1 << 2; - pSpeakerToChannelMap[3][5] = 1 << 3; - - pSpeakerToChannelMap[4][0] = 1 << 0; - pSpeakerToChannelMap[4][1] = 1 << 1; - pSpeakerToChannelMap[4][2] = 1 << 2; - pSpeakerToChannelMap[4][3] = 0; - pSpeakerToChannelMap[4][4] = 1 << 3; - pSpeakerToChannelMap[4][5] = 1 << 4; - } - if (bResult) { - delete [] ptr; - } - - fAudioNormalize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZE, FALSE); - nAudioMaxNormFactor = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOMAXNORMFACTOR, 400); - fAudioNormalizeRecover = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZERECOVER, TRUE); - nAudioBoost = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, 0); - - nSpeakerChannels = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPEAKERCHANNELS, 2); - - // External filters - LoadExternalFilters(m_filters); - - m_pnspresets.RemoveAll(); - - for (int i = 0; i < (ID_PANNSCAN_PRESETS_END - ID_PANNSCAN_PRESETS_START); i++) { - CString str2; - str2.Format(_T("Preset%d"), i); - str2 = pApp->GetProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, str2); - if (str2.IsEmpty()) { - break; - } - m_pnspresets.Add(str2); - } - - if (m_pnspresets.IsEmpty()) { - const double _4p3 = 4.0 / 3.0; - const double _16p9 = 16.0 / 9.0; - const double _185p1 = 1.85 / 1.0; - const double _235p1 = 2.35 / 1.0; - UNREFERENCED_PARAMETER(_185p1); - - CString str2; - str2.Format(IDS_SCALE_16_9, 0.5, 0.5, /*_4p3 / _4p3 =*/ 1.0, _16p9 / _4p3); - m_pnspresets.Add(str2); - str2.Format(IDS_SCALE_WIDESCREEN, 0.5, 0.5, _16p9 / _4p3, _16p9 / _4p3); - m_pnspresets.Add(str2); - str2.Format(IDS_SCALE_ULTRAWIDE, 0.5, 0.5, _235p1 / _4p3, _235p1 / _4p3); - m_pnspresets.Add(str2); - } - - for (int i = 0; i < wmcmds.GetCount(); i++) { - CString str2; - str2.Format(_T("CommandMod%d"), i); - str2 = pApp->GetProfileString(IDS_R_COMMANDS, str2); - if (str2.IsEmpty()) { - break; - } - - wmcmd tmp; - int n; - int fVirt = 0; - BYTE ignore; - if (5 > (n = _stscanf_s(str2, _T("%hu %x %hx %S %d %hhu %u %hhu %hhu %hhu"), - &tmp.cmd, &fVirt, &tmp.key, tmp.rmcmd.GetBuffer(128), 128, - &tmp.rmrepcnt, &tmp.mouse, &tmp.appcmd, &ignore, - &tmp.mouseVirt, &ignore))) { - break; - } - tmp.rmcmd.ReleaseBuffer(); - if (n >= 2) { - tmp.fVirt = (BYTE)fVirt; - } - if (POSITION pos = wmcmds.Find(tmp)) { - wmcmd& wc = wmcmds.GetAt(pos); - wc.cmd = tmp.cmd; - wc.fVirt = tmp.fVirt; - wc.key = tmp.key; - if (n >= 6) { - wc.mouse = tmp.mouse; - } - if (n >= 7) { - wc.appcmd = tmp.appcmd; - } - if (n >= 9) { - wc.mouseVirt = tmp.mouseVirt; - } - wc.rmcmd = tmp.rmcmd.Trim('\"'); - wc.rmrepcnt = tmp.rmrepcnt; - } - } - - CAtlArray pAccel; - pAccel.SetCount(ACCEL_LIST_SIZE); - int accel_count = 0; - POSITION pos = wmcmds.GetHeadPosition(); - for (int i = 0; pos; i++) { - ACCEL x = wmcmds.GetNext(pos); - if (x.key > 0) { - pAccel[accel_count] = x; - accel_count++; - } - } - hAccel = CreateAcceleratorTable(pAccel.GetData(), accel_count); - - strWinLircAddr = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WINLIRCADDR, _T("127.0.0.1:8765")); - fWinLirc = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WINLIRC, FALSE); - strUIceAddr = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_UICEADDR, _T("127.0.0.1:1234")); - fUIce = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UICE, FALSE); - fGlobalMedia = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_GLOBALMEDIA, TRUE); - - nJumpDistS = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTS, DEFAULT_JUMPDISTANCE_1); - nJumpDistM = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTM, DEFAULT_JUMPDISTANCE_2); - nJumpDistL = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTL, DEFAULT_JUMPDISTANCE_3); - fLimitWindowProportions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LIMITWINDOWPROPORTIONS, FALSE); - - m_Formats.UpdateData(false); - - // Internal filters - for (int f = 0; f < SRC_LAST; f++) { - SrcFilters[f] = !!pApp->GetProfileInt(IDS_R_INTERNAL_FILTERS, SrcFiltersKeys[f].name, SrcFiltersKeys[f].bDefault); - } - for (int f = 0; f < TRA_LAST; f++) { - TraFilters[f] = !!pApp->GetProfileInt(IDS_R_INTERNAL_FILTERS, TraFiltersKeys[f].name, TraFiltersKeys[f].bDefault); - } - - strLogoFileName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_LOGOFILE); - nLogoId = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOID, -1); - fLogoExternal = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOEXT, FALSE); - fLogoColorProfileEnabled = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOCOLORPROFILE, FALSE); - - fHideCDROMsSubMenu = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECDROMSSUBMENU, FALSE); - - dwPriority = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITY, NORMAL_PRIORITY_CLASS); - ::SetPriorityClass(::GetCurrentProcess(), dwPriority); - fLaunchfullscreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LAUNCHFULLSCREEN, FALSE); - - fEnableWebServer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWEBSERVER, FALSE); - nWebServerPort = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPORT, 13579); - fWebServerUseCompression = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERUSECOMPRESSION, TRUE); - fWebServerLocalhostOnly = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERLOCALHOSTONLY, FALSE); - bWebUIEnablePreview = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBUI_ENABLE_PREVIEW, FALSE); - fWebServerPrintDebugInfo = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPRINTDEBUGINFO, FALSE); - strWebRoot = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBROOT, _T("*./webroot")); - strWebDefIndex = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBDEFINDEX, _T("index.html;index.php")); - strWebServerCGI = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBSERVERCGI); - - CString MyPictures; - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), KEY_READ)) { - ULONG lenValue = 1024; - if (ERROR_SUCCESS == key.QueryStringValue(_T("My Pictures"), MyPictures.GetBuffer((int)lenValue), &lenValue)) { - MyPictures.ReleaseBufferSetLength((int)lenValue); - } else { - MyPictures.Empty(); - } - } - strSnapshotPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTPATH, MyPictures); - strSnapshotExt = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTEXT, _T(".jpg")); - bSnapShotSubtitles = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTSUBTITLES, TRUE); - bSnapShotKeepVideoExtension = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTKEEPVIDEOEXTENSION, TRUE); - - iThumbRows = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBROWS, 4); - iThumbCols = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBCOLS, 4); - iThumbWidth = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBWIDTH, 1024); - - bSubSaveExternalStyleFile = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBSAVEEXTERNALSTYLEFILE, FALSE); - nLastUsedPage = WORD(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTUSEDPAGE, 0)); - - { - // Load the list of extra (non-default) shader files - m_ShadersExtraList = ShaderList(pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_EXTRA)); - // Load shader selection - m_Shaders.SetCurrentPreset(ShaderPreset(pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_PRERESIZE), - pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_POSTRESIZE))); - // Load shader presets - ShaderSelection::ShaderPresetMap presets; - for (int i = 0;; i++) { - CString iStr; - iStr.Format(_T("%d"), i); - CString name = pApp->GetProfileString(IDS_R_SHADER_PRESETS, iStr); - if (name.IsEmpty()) { - break; - } - presets.emplace(name, ShaderPreset(pApp->GetProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_PRERESIZE + iStr), - pApp->GetProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_POSTRESIZE + iStr))); - } - m_Shaders.SetPresets(presets); - // Load last shader preset name - CString name = pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_LASTPRESET); - if (!name.IsEmpty()) { - m_Shaders.SetCurrentPreset(name); - } - } - - fD3DFullscreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_D3DFULLSCREEN, FALSE); - - iBrightness = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_BRIGHTNESS, 0); - iContrast = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_CONTRAST, 0); - iHue = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_HUE, 0); - iSaturation = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_SATURATION, 0); - - fShowOSD = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOWOSD, TRUE); - fShowCurrentTimeInOSD = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CURRENT_TIME_OSD, FALSE); - - nOSDTransparency = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_TRANSPARENCY, 64); - nOSDBorder = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_BORDER, 1); - - fEnableEDLEditor = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEEDLEDITOR, FALSE); - bFastSeek = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK, TRUE); - eFastSeekMethod = static_cast( - pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK_METHOD, FASTSEEK_NEAREST_KEYFRAME)); - fShowChapters = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CHAPTERS, TRUE); - - - fLCDSupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, FALSE); - - fSeekPreview = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW, FALSE); - iSeekPreviewSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW_SIZE, 15); - if (iSeekPreviewSize < 5) iSeekPreviewSize = 5; - if (iSeekPreviewSize > 40) iSeekPreviewSize = 40; - - // Save analog capture settings - iDefaultCaptureDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, 0); - strAnalogVideo = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, _T("dummy")); - strAnalogAudio = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, _T("dummy")); - iAnalogCountry = pApp->GetProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, 1); - - //strBDANetworkProvider = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER); - strBDATuner = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER); - strBDAReceiver = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER); - //sBDAStandard = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD); - iBDAScanFreqStart = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, 474000); - iBDAScanFreqEnd = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, 858000); - iBDABandwidth = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, 8); - iBDASymbolRate = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SYMBOLRATE, 0); - fBDAUseOffset = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_USE_OFFSET, FALSE); - iBDAOffset = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_OFFSET, 166); - fBDAIgnoreEncryptedChannels = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_IGNORE_ENCRYPTED_CHANNELS, FALSE); - nDVBLastChannel = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, INT_ERROR); - nDVBRebuildFilterGraph = (DVB_RebuildFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, DVB_STOP_FG_ALWAYS); - nDVBStopFilterGraph = (DVB_StopFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, DVB_STOP_FG_ALWAYS); - - for (int iChannel = 0; ; iChannel++) { - CString strTemp; - strTemp.Format(_T("%d"), iChannel); - CString strChannel = pApp->GetProfileString(IDS_R_DVB, strTemp); - if (strChannel.IsEmpty()) { - break; - } - try { - m_DVBChannels.emplace_back(strChannel); - } catch (CException* e) { - // The tokenisation can fail if the input string was invalid - TRACE(_T("Failed to parse a DVB channel from string \"%s\""), strChannel.GetString()); - ASSERT(FALSE); - e->Delete(); - } - } - - // playback positions for last played files - fRememberFilePos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS, FALSE); - iRememberPosForLongerThan = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSLONGER, 5); - bRememberPosForAudioFiles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSAUDIO, TRUE); - if (iRememberPosForLongerThan < 0) { - iRememberPosForLongerThan = 5; - } - bRememberExternalPlaylistPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_PLAYLIST, TRUE); - bRememberTrackSelection = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_TRACK_SELECTION, TRUE); - - // playback positions for last played DVDs - fRememberDVDPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DVDPOS, FALSE); - - bToggleShader = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADER, TRUE); - bToggleShaderScreenSpace = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADERSSCREENSPACE, TRUE); - - fRemainingTime = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMAINING_TIME, FALSE); - bHighPrecisionTimer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIGH_PRECISION_TIMER, FALSE); - bTimerShowPercentage = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIMER_SHOW_PERCENTAGE, FALSE); - - nUpdaterAutoCheck = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_AUTO_CHECK, AUTOUPDATE_UNKNOWN); - nUpdaterDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_DELAY, 7); - if (nUpdaterDelay < 1) { - nUpdaterDelay = 1; - } - - bNotifySkype = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_NOTIFY_SKYPE, FALSE); - - nJpegQuality = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JPEG_QUALITY, 90); - if (nJpegQuality < 20 || nJpegQuality > 100) { - nJpegQuality = 90; - } - - bEnableCoverArt = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART, TRUE); - nCoverArtSizeLimit = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART_SIZE_LIMIT, 600); - - bEnableLogging = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGGING, FALSE); - bUseLegacyToolbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_LEGACY_TOOLBAR, FALSE); - - eSubtitleRenderer = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, static_cast(SubtitleRenderer::INTERNAL))); - if (eSubtitleRenderer == SubtitleRenderer::RESERVED) { - eSubtitleRenderer = SubtitleRenderer::INTERNAL; - bRenderSSAUsingLibass = true; - } - - nDefaultToolbarSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTTOOLBARSIZE, 24); - - bSaveImagePosition = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_POSITION, TRUE); - bSaveImageCurrentTime = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_CURRENTTIME, FALSE); - - bAllowInaccurateFastseek = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_INACCURATE_FASTSEEK, TRUE); - bLoopFolderOnPlayNextFile = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP_FOLDER_NEXT_FILE, FALSE); - - bLockNoPause = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOCK_NOPAUSE, FALSE); - bPreventDisplaySleep = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_DISPLAY_SLEEP, TRUE); - bUseSMTC = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_SMTC, FALSE); - iReloadAfterLongPause = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RELOAD_AFTER_LONG_PAUSE, 0); - bOpenRecPanelWhenOpeningDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OPEN_REC_PANEL_WHEN_OPENING_DEVICE, TRUE); - - sanear->SetOutputDevice(pApp->GetProfileString(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_ID), - pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_EXCLUSIVE, FALSE), - pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_BUFFER, - SaneAudioRenderer::ISettings::OUTPUT_DEVICE_BUFFER_DEFAULT_MS)); - - sanear->SetCrossfeedEnabled(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_ENABLED, FALSE)); - - sanear->SetCrossfeedSettings(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ, - SaneAudioRenderer::ISettings::CROSSFEED_CUTOFF_FREQ_CMOY), - pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, - SaneAudioRenderer::ISettings::CROSSFEED_LEVEL_CMOY)); - - sanear->SetIgnoreSystemChannelMixer(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_IGNORE_SYSTEM_MIXER, TRUE)); - - bUseYDL = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_YDL, TRUE); - iYDLMaxHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, 1440); - iYDLVideoFormat = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_VIDEO_FORMAT, 0); - iYDLAudioFormat = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_FORMAT, 0); - bYDLAudioOnly = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, FALSE); - sYDLExePath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_EXEPATH, _T("")); - sYDLCommandLine = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_COMMAND_LINE, _T("")); - - bEnableCrashReporter = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLE_CRASH_REPORTER, TRUE); - - nStreamPosPollerInterval = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_REFRESH_INTERVAL, 100); - bShowLangInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_LANG_STATUSBAR, FALSE); - bShowFPSInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_FPS_STATUSBAR, FALSE); - bShowABMarksInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_ABMARKS_STATUSBAR, FALSE); - bShowVideoInfoInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_VIDEOINFO_STATUSBAR, TRUE); - bShowAudioFormatInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_AUDIOFORMAT_STATUSBAR, TRUE); - - bAddLangCodeWhenSaveSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ADD_LANGCODE_WHEN_SAVE_SUBTITLES, FALSE); - bUseTitleInRecentFileList = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TITLE_IN_RECENT_FILE_LIST, TRUE); - sYDLSubsPreference = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_SUBS_PREFERENCE, _T("")); - bUseAutomaticCaptions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_AUTOMATIC_CAPTIONS, FALSE); - - lastQuickOpenPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_QUICKOPEN_PATH, L""); - lastFileSaveCopyPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_FILESAVECOPY_PATH, L""); - lastFileOpenDirPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_FILEOPENDIR_PATH, L""); - externalPlayListPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_EXTERNAL_PLAYLIST_PATH, L""); - - iRedirectOpenToAppendThreshold = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REDIRECT_OPEN_TO_APPEND_THRESHOLD, 1000); - bFullscreenSeparateControls = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_SEPARATE_CONTROLS, TRUE); - bAlwaysUseShortMenu = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALWAYS_USE_SHORT_MENU, FALSE); - iStillVideoDuration = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_STILL_VIDEO_DURATION, 10); - iMouseLeftUpDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MOUSE_LEFTUP_DELAY, 0); - - if (bMPCTheme) { - CMPCTheme::InitializeColors(eModernThemeMode); - } - // GUI theme can be used now - static_cast(AfxGetApp())->m_bThemeLoaded = bMPCTheme; - - if (fLaunchfullscreen && slFiles.GetCount() > 0) { - nCLSwitches |= CLSW_FULLSCREEN; - } - - bInitialized = true; -} - -bool CAppSettings::GetAllowMultiInst() const -{ - return !!AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, FALSE); -} - -void CAppSettings::UpdateRenderersData(bool fSave) -{ - CWinApp* pApp = AfxGetApp(); - CRenderersSettings& r = m_RenderersSettings; - CRenderersSettings::CAdvRendererSettings& ars = r.m_AdvRendSets; - - if (fSave) { - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_APSURACEFUSAGE, r.iAPSurfaceUsage); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DX9_RESIZER, r.iDX9Resizer); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VMR9MIXERMODE, r.fVMR9MixerMode); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRAlternateVSync"), ars.bVMR9AlterativeVSync); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSyncOffset"), ars.iVMR9VSyncOffset); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSyncAccurate2"), ars.bVMR9VSyncAccurate); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFullscreenGUISupport"), ars.bVMR9FullscreenGUISupport); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSync"), ars.bVMR9VSync); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRDisableDesktopComposition"), ars.bVMRDisableDesktopComposition); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFullFloatingPointProcessing2"), ars.bVMR9FullFloatingPointProcessing); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRHalfFloatingPointProcessing"), ars.bVMR9HalfFloatingPointProcessing); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementEnable"), ars.bVMR9ColorManagementEnable); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementInput"), ars.iVMR9ColorManagementInput); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementAmbientLight"), ars.iVMR9ColorManagementAmbientLight); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementIntent"), ars.iVMR9ColorManagementIntent); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVROutputRange"), ars.iEVROutputRange); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVRHighColorRes"), ars.bEVRHighColorResolution); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVRForceInputHighColorRes"), ars.bEVRForceInputHighColorResolution); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVREnableFrameTimeCorrection"), ars.bEVREnableFrameTimeCorrection); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUBeforeVSync"), ars.bVMRFlushGPUBeforeVSync); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUAfterPresent"), ars.bVMRFlushGPUAfterPresent); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUWait"), ars.bVMRFlushGPUWait); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("DesktopSizeBackBuffer"), ars.bDesktopSizeBackBuffer); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeClock"), ars.bSynchronizeVideo); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeDisplay"), ars.bSynchronizeDisplay); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeNearest"), ars.bSynchronizeNearest); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("LineDelta"), ars.iLineDelta); - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("ColumnDelta"), ars.iColumnDelta); - - pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("CycleDelta"), (LPBYTE) & (ars.fCycleDelta), sizeof(ars.fCycleDelta)); - pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("TargetSyncOffset"), (LPBYTE) & (ars.fTargetSyncOffset), sizeof(ars.fTargetSyncOffset)); - pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("ControlLimit"), (LPBYTE) & (ars.fControlLimit), sizeof(ars.fControlLimit)); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CACHESHADERS, ars.bCacheShaders); - - pApp->WriteProfileInt(IDS_R_SETTINGS, _T("ResetDevice"), r.fResetDevice); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCSIZE, r.subPicQueueSettings.nSize); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESX, r.subPicQueueSettings.nMaxResX); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESY, r.subPicQueueSettings.nMaxResY); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, r.subPicQueueSettings.bDisableSubtitleAnimation); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDER_AT_WHEN_ANIM_DISABLED, r.subPicQueueSettings.nRenderAtWhenAnimationIsDisabled); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_ANIMATION_RATE, r.subPicQueueSettings.nAnimationRate); - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_DROPPING_SUBPIC, r.subPicQueueSettings.bAllowDroppingSubpic); - - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_EVR_BUFFERS, r.iEvrBuffers); - - pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_D3D9RENDERDEVICE, r.D3D9RenderDevice); - } else { - r.iAPSurfaceUsage = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_APSURACEFUSAGE, VIDRNDT_AP_TEXTURE3D); - r.iDX9Resizer = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DX9_RESIZER, 1); - r.fVMR9MixerMode = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VMR9MIXERMODE, TRUE); - - CRenderersSettings::CAdvRendererSettings DefaultSettings; - ars.bVMR9AlterativeVSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRAlternateVSync"), DefaultSettings.bVMR9AlterativeVSync); - ars.iVMR9VSyncOffset = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSyncOffset"), DefaultSettings.iVMR9VSyncOffset); - ars.bVMR9VSyncAccurate = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSyncAccurate2"), DefaultSettings.bVMR9VSyncAccurate); - ars.bVMR9FullscreenGUISupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFullscreenGUISupport"), DefaultSettings.bVMR9FullscreenGUISupport); - ars.bEVRHighColorResolution = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVRHighColorRes"), DefaultSettings.bEVRHighColorResolution); - ars.bEVRForceInputHighColorResolution = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVRForceInputHighColorRes"), DefaultSettings.bEVRForceInputHighColorResolution); - ars.bEVREnableFrameTimeCorrection = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVREnableFrameTimeCorrection"), DefaultSettings.bEVREnableFrameTimeCorrection); - ars.bVMR9VSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSync"), DefaultSettings.bVMR9VSync); - ars.bVMRDisableDesktopComposition = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRDisableDesktopComposition"), DefaultSettings.bVMRDisableDesktopComposition); - ars.bVMR9FullFloatingPointProcessing = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFullFloatingPointProcessing2"), DefaultSettings.bVMR9FullFloatingPointProcessing); - ars.bVMR9HalfFloatingPointProcessing = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRHalfFloatingPointProcessing"), DefaultSettings.bVMR9HalfFloatingPointProcessing); - - ars.bVMR9ColorManagementEnable = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementEnable"), DefaultSettings.bVMR9ColorManagementEnable); - ars.iVMR9ColorManagementInput = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementInput"), DefaultSettings.iVMR9ColorManagementInput); - ars.iVMR9ColorManagementAmbientLight = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementAmbientLight"), DefaultSettings.iVMR9ColorManagementAmbientLight); - ars.iVMR9ColorManagementIntent = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementIntent"), DefaultSettings.iVMR9ColorManagementIntent); - - ars.iEVROutputRange = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVROutputRange"), DefaultSettings.iEVROutputRange); - - ars.bVMRFlushGPUBeforeVSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUBeforeVSync"), DefaultSettings.bVMRFlushGPUBeforeVSync); - ars.bVMRFlushGPUAfterPresent = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUAfterPresent"), DefaultSettings.bVMRFlushGPUAfterPresent); - ars.bVMRFlushGPUWait = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUWait"), DefaultSettings.bVMRFlushGPUWait); - - ars.bDesktopSizeBackBuffer = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("DesktopSizeBackBuffer"), DefaultSettings.bDesktopSizeBackBuffer); - - ars.bSynchronizeVideo = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeClock"), DefaultSettings.bSynchronizeVideo); - ars.bSynchronizeDisplay = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeDisplay"), DefaultSettings.bSynchronizeDisplay); - ars.bSynchronizeNearest = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeNearest"), DefaultSettings.bSynchronizeNearest); - ars.iLineDelta = pApp->GetProfileInt(IDS_R_SETTINGS, _T("LineDelta"), DefaultSettings.iLineDelta); - ars.iColumnDelta = pApp->GetProfileInt(IDS_R_SETTINGS, _T("ColumnDelta"), DefaultSettings.iColumnDelta); - - double* dPtr; - UINT dSize; - if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("CycleDelta"), (LPBYTE*)&dPtr, &dSize)) { - ars.fCycleDelta = *dPtr; - delete [] dPtr; - } - - if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("TargetSyncOffset"), (LPBYTE*)&dPtr, &dSize)) { - ars.fTargetSyncOffset = *dPtr; - delete [] dPtr; - } - if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("ControlLimit"), (LPBYTE*)&dPtr, &dSize)) { - ars.fControlLimit = *dPtr; - delete [] dPtr; - } - - ars.bCacheShaders = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CACHESHADERS, DefaultSettings.bCacheShaders); - if (AfxGetMyApp()->GetAppSavePath(ars.sShaderCachePath)) { - ars.sShaderCachePath = PathUtils::CombinePaths(ars.sShaderCachePath, IDS_R_SHADER_CACHE); - } - - r.fResetDevice = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("ResetDevice"), FALSE); - - r.subPicQueueSettings.nSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCSIZE, 0); - r.subPicQueueSettings.nMaxResX = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESX, 2560); - r.subPicQueueSettings.nMaxResY = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESY, 1440); - if (r.subPicQueueSettings.nMaxResX < 600 || r.subPicQueueSettings.nMaxResY < 480) { - r.subPicQueueSettings.nMaxResX = 2560; - r.subPicQueueSettings.nMaxResY = 1440; - } - r.subPicQueueSettings.bDisableSubtitleAnimation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, FALSE); - r.subPicQueueSettings.nRenderAtWhenAnimationIsDisabled = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDER_AT_WHEN_ANIM_DISABLED, 50); - r.subPicQueueSettings.nAnimationRate = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_ANIMATION_RATE, 100); - r.subPicQueueSettings.bAllowDroppingSubpic = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_DROPPING_SUBPIC, TRUE); - - r.subPicVerticalShift = 0; - r.fontScaleOverride = 1.0; - - r.iEvrBuffers = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_EVR_BUFFERS, 5); - r.D3D9RenderDevice = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_D3D9RENDERDEVICE); - } -} - -__int64 CAppSettings::ConvertTimeToMSec(const CString& time) const -{ - __int64 Sec = 0; - __int64 mSec = 0; - __int64 mult = 1; - - int pos = time.GetLength() - 1; - if (pos < 3) { - return 0; - } - - while (pos >= 0) { - TCHAR ch = time[pos]; - if (ch == '.') { - mSec = Sec * 1000 / mult; - Sec = 0; - mult = 1; - } else if (ch == ':') { - mult = mult * 6 / 10; - } else if (ch >= '0' && ch <= '9') { - Sec += (ch - '0') * mult; - mult *= 10; - } else { - mSec = Sec = 0; - break; - } - pos--; - } - return Sec * 1000 + mSec; -} - -void CAppSettings::ExtractDVDStartPos(CString& strParam) -{ - int i = 0, j = 0; - for (CString token = strParam.Tokenize(_T("#"), i); - j < 3 && !token.IsEmpty(); - token = strParam.Tokenize(_T("#"), i), j++) { - switch (j) { - case 0: - lDVDTitle = token.IsEmpty() ? 0 : (ULONG)_wtol(token); - break; - case 1: - if (token.Find(':') > 0) { - UINT h = 0, m = 0, s = 0, f = 0; - int nRead = _stscanf_s(token, _T("%02u:%02u:%02u.%03u"), &h, &m, &s, &f); - if (nRead >= 3) { - DVDPosition.bHours = (BYTE)h; - DVDPosition.bMinutes = (BYTE)m; - DVDPosition.bSeconds = (BYTE)s; - DVDPosition.bFrames = (BYTE)f; - } - } else { - lDVDChapter = token.IsEmpty() ? 0 : (ULONG)_wtol(token); - } - break; - } - } -} - -CString CAppSettings::ParseFileName(CString const& param) -{ - if (param.Find(_T(":")) < 0 && param.Left(2) != L"\\\\") { - // Try to transform relative pathname into full pathname - CString fullPathName; - DWORD dwLen = GetFullPathName(param, 2048, fullPathName.GetBuffer(2048), nullptr); - if (dwLen > 0 && dwLen < 2048) { - fullPathName.ReleaseBuffer(dwLen); - - if (!fullPathName.IsEmpty() && PathUtils::Exists(fullPathName)) { - return fullPathName; - } - } - } else { - CString fullPathName = param; - ExtendMaxPathLengthIfNeeded(fullPathName); - return fullPathName; - } - - return param; -} - -void CAppSettings::ParseCommandLine(CAtlList& cmdln) -{ - UINT64 existingAfterPlaybackCL = nCLSwitches & CLSW_AFTERPLAYBACK_MASK; - nCLSwitches = 0; - slFiles.RemoveAll(); - slDubs.RemoveAll(); - slSubs.RemoveAll(); - slFilters.RemoveAll(); - rtStart = 0; - rtShift = 0; - lDVDTitle = 0; - lDVDChapter = 0; - ZeroMemory(&DVDPosition, sizeof(DVDPosition)); - iAdminOption = 0; - sizeFixedWindow.SetSize(0, 0); - fixedWindowPosition = NO_FIXED_POSITION; - iMonitor = 0; - strPnSPreset.Empty(); - - POSITION pos = cmdln.GetHeadPosition(); - while (pos) { - const CString& param = cmdln.GetNext(pos); - if (param.IsEmpty()) { - continue; - } - - if ((param[0] == '-' || param[0] == '/') && param.GetLength() > 1) { - CString sw = param.Mid(1).MakeLower(); - if (sw == _T("open")) { - nCLSwitches |= CLSW_OPEN; - } else if (sw == _T("play")) { - nCLSwitches |= CLSW_PLAY; - } else if (sw == _T("fullscreen")) { - nCLSwitches |= CLSW_FULLSCREEN; - } else if (sw == _T("minimized")) { - nCLSwitches |= CLSW_MINIMIZED; - } else if (sw == _T("new")) { - nCLSwitches |= CLSW_NEW; - } else if (sw == _T("help") || sw == _T("h") || sw == _T("?")) { - nCLSwitches |= CLSW_HELP; - } else if (sw == _T("dub") && pos) { - slDubs.AddTail(ParseFileName(cmdln.GetNext(pos))); - } else if (sw == _T("dubdelay") && pos) { - CString strFile = ParseFileName(cmdln.GetNext(pos)); - int nPos = strFile.Find(_T("DELAY")); - if (nPos != -1) { - rtShift = 10000i64 * _tstol(strFile.Mid(nPos + 6)); - } - slDubs.AddTail(strFile); - } else if (sw == _T("sub") && pos) { - slSubs.AddTail(ParseFileName(cmdln.GetNext(pos))); - } else if (sw == _T("filter") && pos) { - slFilters.AddTail(cmdln.GetNext(pos)); - } else if (sw == _T("dvd")) { - nCLSwitches |= CLSW_DVD; - } else if (sw == _T("dvdpos") && pos) { - ExtractDVDStartPos(cmdln.GetNext(pos)); - } else if (sw == _T("cd")) { - nCLSwitches |= CLSW_CD; - } else if (sw == _T("device")) { - nCLSwitches |= CLSW_DEVICE; - } else if (sw == _T("add")) { - nCLSwitches |= CLSW_ADD; - } else if (sw == _T("randomize")) { - nCLSwitches |= CLSW_RANDOMIZE; - } else if (sw == _T("volume") && pos) { - int setVolumeVal = _ttoi(cmdln.GetNext(pos)); - if (setVolumeVal >= 0 && setVolumeVal <= 100) { - nCmdVolume = setVolumeVal; - nCLSwitches |= CLSW_VOLUME; - } else { - nCLSwitches |= CLSW_UNRECOGNIZEDSWITCH; - } - } else if (sw == _T("regvid")) { - nCLSwitches |= CLSW_REGEXTVID; - } else if (sw == _T("regaud")) { - nCLSwitches |= CLSW_REGEXTAUD; - } else if (sw == _T("regpl")) { - nCLSwitches |= CLSW_REGEXTPL; - } else if (sw == _T("regall")) { - nCLSwitches |= (CLSW_REGEXTVID | CLSW_REGEXTAUD | CLSW_REGEXTPL); - } else if (sw == _T("unregall")) { - nCLSwitches |= CLSW_UNREGEXT; - } else if (sw == _T("unregvid")) { - nCLSwitches |= CLSW_UNREGEXT; /* keep for compatibility with old versions */ - } else if (sw == _T("unregaud")) { - nCLSwitches |= CLSW_UNREGEXT; /* keep for compatibility with old versions */ - } else if (sw == _T("iconsassoc")) { - nCLSwitches |= CLSW_ICONSASSOC; - } else if (sw == _T("start") && pos) { - rtStart = 10000i64 * _tcstol(cmdln.GetNext(pos), nullptr, 10); - nCLSwitches |= CLSW_STARTVALID; - } else if (sw == _T("startpos") && pos) { - rtStart = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); - nCLSwitches |= CLSW_STARTVALID; - } else if (sw == _T("nofocus")) { - nCLSwitches |= CLSW_NOFOCUS; - } else if (sw == _T("close")) { - nCLSwitches |= CLSW_CLOSE; - } else if (sw == _T("standby")) { - nCLSwitches |= CLSW_STANDBY; - } else if (sw == _T("hibernate")) { - nCLSwitches |= CLSW_HIBERNATE; - } else if (sw == _T("shutdown")) { - nCLSwitches |= CLSW_SHUTDOWN; - } else if (sw == _T("logoff")) { - nCLSwitches |= CLSW_LOGOFF; - } else if (sw == _T("lock")) { - nCLSwitches |= CLSW_LOCK; - } else if (sw == _T("d3dfs")) { - nCLSwitches |= CLSW_D3DFULLSCREEN; - } else if (sw == _T("adminoption") && pos) { - nCLSwitches |= CLSW_ADMINOPTION; - iAdminOption = _ttoi(cmdln.GetNext(pos)); - } else if (sw == _T("slave") && pos) { - nCLSwitches |= CLSW_SLAVE; - hMasterWnd = (HWND)IntToPtr(_ttoi(cmdln.GetNext(pos))); - } else if (sw == _T("fixedsize") && pos) { - CAtlList sl; - // Optional arguments for the main window's position - Explode(cmdln.GetNext(pos), sl, ',', 4); - if (sl.GetCount() == 4) { - fixedWindowPosition.SetPoint(_ttol(sl.GetAt(sl.FindIndex(2))), _ttol(sl.GetAt(sl.FindIndex(3))) ); - } - if (sl.GetCount() >= 2) { - sizeFixedWindow.SetSize(_ttol(sl.GetAt(sl.FindIndex(0))), _ttol(sl.GetAt(sl.FindIndex(1))) ); - if (sizeFixedWindow.cx > 0 && sizeFixedWindow.cy > 0) { - nCLSwitches |= CLSW_FIXEDSIZE; - } - } - } else if (sw == _T("viewpreset") && pos) { - int viewPreset = _ttoi(cmdln.GetNext(pos)); - switch (viewPreset) { - case 1: - nCLSwitches |= CLSW_PRESET1; - break; - case 2: - nCLSwitches |= CLSW_PRESET2; - break; - case 3: - nCLSwitches |= CLSW_PRESET3; - break; - default: - nCLSwitches |= CLSW_UNRECOGNIZEDSWITCH; - break; - } - } else if (sw == _T("monitor") && pos) { - iMonitor = _tcstol(cmdln.GetNext(pos), nullptr, 10); - nCLSwitches |= CLSW_MONITOR; - } else if (sw == _T("pns") && pos) { - strPnSPreset = cmdln.GetNext(pos); - } else if (sw == _T("webport") && pos) { - int tmpport = _tcstol(cmdln.GetNext(pos), nullptr, 10); - if (tmpport >= 0 && tmpport <= 65535) { - nCmdlnWebServerPort = tmpport; - } - } else if (sw == _T("debug")) { - fShowDebugInfo = true; - } else if (sw == _T("nocrashreporter")) { -#if USE_DRDUMP_CRASH_REPORTER - if (CrashReporter::IsEnabled()) { - CrashReporter::Disable(); - MPCExceptionHandler::Enable(); - } -#endif - } else if (sw == _T("audiorenderer") && pos) { - SetAudioRenderer(_ttoi(cmdln.GetNext(pos))); - } else if (sw == _T("shaderpreset") && pos) { - m_Shaders.SetCurrentPreset(cmdln.GetNext(pos)); - } else if (sw == _T("reset")) { - nCLSwitches |= CLSW_RESET; - } else if (sw == _T("mute")) { - nCLSwitches |= CLSW_MUTE; - } else if (sw == _T("monitoroff")) { - nCLSwitches |= CLSW_MONITOROFF; - } else if (sw == _T("playnext")) { - nCLSwitches |= CLSW_PLAYNEXT; - } else if (sw == _T("hwgpu") && pos) { - iLAVGPUDevice = _tcstol(cmdln.GetNext(pos), nullptr, 10); - } else if (sw == _T("configlavsplitter")) { - nCLSwitches |= CLSW_CONFIGLAVSPLITTER; - } else if (sw == _T("configlavaudio")) { - nCLSwitches |= CLSW_CONFIGLAVAUDIO; - } else if (sw == _T("configlavvideo")) { - nCLSwitches |= CLSW_CONFIGLAVVIDEO; - } else if (sw == L"ab_start" && pos) { - abRepeat.positionA = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); - } else if (sw == L"ab_end" && pos) { - abRepeat.positionB = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); - } else if (sw == L"thumbnails") { - nCLSwitches |= CLSW_THUMBNAILS | CLSW_NEW; - } else { - nCLSwitches |= CLSW_HELP | CLSW_UNRECOGNIZEDSWITCH; - } - } else { - if (param == _T("-")) { // Special case: standard input - slFiles.AddTail(_T("pipe://stdin")); - } else { - const_cast(param) = ParseFileName(param); - slFiles.AddTail(param); - } - } - } - - if (abRepeat.positionA && abRepeat.positionB && abRepeat.positionA >= abRepeat.positionB) { - abRepeat.positionA = 0; - abRepeat.positionB = 0; - } - if (abRepeat.positionA > rtStart || (abRepeat.positionB && abRepeat.positionB < rtStart)) { - rtStart = abRepeat.positionA; - nCLSwitches |= CLSW_STARTVALID; - } - - if (0 == (nCLSwitches & CLSW_AFTERPLAYBACK_MASK)) { //no changes to playback mask, so let's preserve existing - nCLSwitches |= existingAfterPlaybackCL; - } -} - -void CAppSettings::GetFav(favtype ft, CAtlList& sl) const -{ - sl.RemoveAll(); - - CString root; - - switch (ft) { - case FAV_FILE: - root = IDS_R_FAVFILES; - break; - case FAV_DVD: - root = IDS_R_FAVDVDS; - break; - case FAV_DEVICE: - root = IDS_R_FAVDEVICES; - break; - default: - return; - } - - for (int i = 0; ; i++) { - CString s; - s.Format(_T("Name%d"), i); - s = AfxGetApp()->GetProfileString(root, s); - if (s.IsEmpty()) { - break; - } - sl.AddTail(s); - } -} - -void CAppSettings::SetFav(favtype ft, CAtlList& sl) -{ - CString root; - - switch (ft) { - case FAV_FILE: - root = IDS_R_FAVFILES; - break; - case FAV_DVD: - root = IDS_R_FAVDVDS; - break; - case FAV_DEVICE: - root = IDS_R_FAVDEVICES; - break; - default: - return; - } - - AfxGetApp()->WriteProfileString(root, nullptr, nullptr); - - int i = 0; - POSITION pos = sl.GetHeadPosition(); - while (pos) { - CString s; - s.Format(_T("Name%d"), i++); - AfxGetApp()->WriteProfileString(root, s, sl.GetNext(pos)); - } -} - -void CAppSettings::AddFav(favtype ft, CString s) -{ - CAtlList sl; - GetFav(ft, sl); - if (sl.Find(s)) { - return; - } - sl.AddTail(s); - SetFav(ft, sl); -} - -CBDAChannel* CAppSettings::FindChannelByPref(int nPrefNumber) -{ - auto it = find_if(m_DVBChannels.begin(), m_DVBChannels.end(), [&](CBDAChannel const & channel) { - return channel.GetPrefNumber() == nPrefNumber; - }); - - return it != m_DVBChannels.end() ? &(*it) : nullptr; -} - -// Settings::CRecentFileAndURLList -CAppSettings::CRecentFileAndURLList::CRecentFileAndURLList(UINT nStart, LPCTSTR lpszSection, - LPCTSTR lpszEntryFormat, int nSize, - int nMaxDispLen) - : CRecentFileList(nStart, lpszSection, lpszEntryFormat, nSize, nMaxDispLen) -{ -} - -extern BOOL AFXAPI AfxComparePath(LPCTSTR lpszPath1, LPCTSTR lpszPath2); - -void CAppSettings::CRecentFileAndURLList::Add(LPCTSTR lpszPathName) -{ - ASSERT(m_arrNames != nullptr); - ASSERT(lpszPathName != nullptr); - ASSERT(AfxIsValidString(lpszPathName)); - - if (m_nSize <= 0 || CString(lpszPathName).MakeLower().Find(_T("@device:")) >= 0) { - return; - } - - CString pathName = lpszPathName; - - bool fURL = PathUtils::IsURL(pathName); - - // fully qualify the path name - if (!fURL) { - pathName = MakeFullPath(pathName); - } - - // update the MRU list, if an existing MRU string matches file name - int iMRU; - for (iMRU = 0; iMRU < m_nSize - 1; iMRU++) { - if ((fURL && !_tcscmp(m_arrNames[iMRU], pathName)) - || AfxComparePath(m_arrNames[iMRU], pathName)) { - break; // iMRU will point to matching entry - } - } - // move MRU strings before this one down - for (; iMRU > 0; iMRU--) { - ASSERT(iMRU > 0); - ASSERT(iMRU < m_nSize); - m_arrNames[iMRU] = m_arrNames[iMRU - 1]; - } - // place this one at the beginning - m_arrNames[0] = pathName; -} - -void CAppSettings::CRecentFileAndURLList::SetSize(int nSize) -{ - ENSURE_ARG(nSize >= 0); - - if (m_nSize != nSize) { - CString* arrNames = DEBUG_NEW CString[nSize]; - int nSizeToCopy = std::min(m_nSize, nSize); - for (int i = 0; i < nSizeToCopy; i++) { - arrNames[i] = m_arrNames[i]; - } - delete [] m_arrNames; - m_arrNames = arrNames; - m_nSize = nSize; - } -} - -#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) -CStringW getShortHash(PBYTE bytes, ULONG size) { - BCRYPT_ALG_HANDLE algHandle = nullptr; - BCRYPT_HASH_HANDLE hashHandle = nullptr; - - PBYTE hash = nullptr; - DWORD hashLen = 0; - DWORD cbResult = 0; - ULONG dwFlags = 0; - const int shortHashLen = 12; - - NTSTATUS stat; - CStringW shortHash = L""; - - stat = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_SHA1_ALGORITHM, nullptr, 0); - if (NT_SUCCESS(stat)) { - stat = BCryptGetProperty(algHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hashLen, sizeof(hashLen), &cbResult, dwFlags); - if (NT_SUCCESS(stat)) { - hash = (PBYTE)HeapAlloc(GetProcessHeap(), dwFlags, hashLen); - if (nullptr != hash) { - stat = BCryptCreateHash(algHandle, &hashHandle, nullptr, 0, nullptr, 0, dwFlags); - if (NT_SUCCESS(stat)) { - stat = BCryptHashData(hashHandle, bytes, size, dwFlags); - if (NT_SUCCESS(stat)) { - stat = BCryptFinishHash(hashHandle, hash, hashLen, 0); - if (NT_SUCCESS(stat)) { - DWORD hashStrLen = 0; - if (CryptBinaryToStringW(hash, hashLen, CRYPT_STRING_BASE64, nullptr, &hashStrLen) && hashStrLen > 0) { - CStringW longHash; - if (CryptBinaryToStringW(hash, hashLen, CRYPT_STRING_BASE64, longHash.GetBuffer(hashStrLen - 1), &hashStrLen)) { - longHash.ReleaseBuffer(hashStrLen); - shortHash = longHash.Left(shortHashLen); - } else { - longHash.ReleaseBuffer(); - } - } - } - } - } - } - } - } - - if (nullptr != hash) { - HeapFree(GetProcessHeap(), dwFlags, hash); - } - - if (nullptr != hashHandle) { - BCryptDestroyHash(hashHandle); - } - - if (nullptr != algHandle) { - BCryptCloseAlgorithmProvider(algHandle, dwFlags); - } - - return shortHash; -} - -CStringW getRFEHash(CStringW fn) { - fn.MakeLower(); - CStringW hash = getShortHash((PBYTE)fn.GetString(), fn.GetLength() * sizeof(WCHAR)); - if (hash.IsEmpty()) { - ASSERT(FALSE); - hash = fn.Right(30); - hash.Replace(L"\\", L"/"); - } - return hash; -} - -CStringW getRFEHash(ULONGLONG llDVDGuid) { - CStringW hash; - hash.Format(L"DVD%llu", llDVDGuid); - return hash; -} - -CStringW getRFEHash(RecentFileEntry &r) { - CStringW fn; - if (r.DVDPosition.llDVDGuid) { - return getRFEHash(r.DVDPosition.llDVDGuid); - } else { - fn = r.fns.GetHead(); - return getRFEHash(fn); - } -} - -/* -void CAppSettings::CRecentFileListWithMoreInfo::Remove(size_t nIndex) { - if (nIndex >= 0 && nIndex < rfe_array.GetCount()) { - auto pApp = AfxGetMyApp(); - CStringW& hash = rfe_array[nIndex].hash; - if (!hash.IsEmpty()) { - pApp->RemoveProfileKey(m_section, hash); - } - rfe_array.RemoveAt(nIndex); - rfe_array.FreeExtra(); - } - if (nIndex == 0 && rfe_array.GetCount() == 0) { - // list was cleared - current_rfe_hash.Empty(); - } -} -*/ - -void CAppSettings::CRecentFileListWithMoreInfo::Add(LPCTSTR fn) { - RecentFileEntry r; - LoadMediaHistoryEntryFN(fn, r); - Add(r, true); -} - -void CAppSettings::CRecentFileListWithMoreInfo::Add(LPCTSTR fn, ULONGLONG llDVDGuid) { - RecentFileEntry r; - LoadMediaHistoryEntryDVD(llDVDGuid, fn, r); - Add(r, true); -} - -bool CAppSettings::CRecentFileListWithMoreInfo::GetCurrentIndex(size_t& idx) { - for (int i = 0; i < rfe_array.GetCount(); i++) { - if (rfe_array[i].hash == current_rfe_hash) { - idx = i; - return true; - } - } - return false; -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentFilePosition(REFERENCE_TIME time, bool forcePersist /* = false */) { - size_t idx; - if (GetCurrentIndex(idx)) { - rfe_array[idx].filePosition = time; - if (forcePersist || std::abs(persistedFilePosition - time) > 300000000) { - WriteMediaHistoryEntry(rfe_array[idx]); - } - } -} - -REFERENCE_TIME CAppSettings::CRecentFileListWithMoreInfo::GetCurrentFilePosition() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].filePosition; - } - return 0; -} - -ABRepeat CAppSettings::CRecentFileListWithMoreInfo::GetCurrentABRepeat() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].abRepeat; - } - return ABRepeat(); -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentDVDTimecode(DVD_HMSF_TIMECODE* time) { - size_t idx; - if (GetCurrentIndex(idx)) { - DVD_POSITION* dvdPosition = &rfe_array[idx].DVDPosition; - if (dvdPosition) { - memcpy(&dvdPosition->timecode, (void*)time, sizeof(DVD_HMSF_TIMECODE)); - } - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentDVDTitle(DWORD title) { - size_t idx; - if (GetCurrentIndex(idx)) { - DVD_POSITION* dvdPosition = &rfe_array[idx].DVDPosition; - if (dvdPosition) { - dvdPosition->lTitle = title; - } - } -} - -DVD_POSITION CAppSettings::CRecentFileListWithMoreInfo::GetCurrentDVDPosition() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].DVDPosition; - } - return DVD_POSITION(); -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentAudioTrack(int audioIndex) { - size_t idx; - if (GetCurrentIndex(idx)) { - if (rfe_array[idx].AudioTrackIndex != audioIndex) { - rfe_array[idx].AudioTrackIndex = audioIndex; - WriteMediaHistoryAudioIndex(rfe_array[idx]); - } - } -} - -int CAppSettings::CRecentFileListWithMoreInfo::GetCurrentAudioTrack() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].AudioTrackIndex; - } - return -1; -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentSubtitleTrack(int subIndex) { - size_t idx; - if (GetCurrentIndex(idx)) { - if (rfe_array[idx].SubtitleTrackIndex != subIndex) { - rfe_array[idx].SubtitleTrackIndex = subIndex; - WriteMediaHistorySubtitleIndex(rfe_array[idx]); - } - } -} - -int CAppSettings::CRecentFileListWithMoreInfo::GetCurrentSubtitleTrack() { - size_t idx; - if (GetCurrentIndex(idx)) { - return rfe_array[idx].SubtitleTrackIndex; - } - return -1; -} - -void CAppSettings::CRecentFileListWithMoreInfo::AddSubToCurrent(CStringW subpath) { - size_t idx; - if (GetCurrentIndex(idx)) { - bool found = rfe_array[idx].subs.Find(subpath); - if (!found) { - rfe_array[idx].subs.AddHead(subpath); - WriteMediaHistoryEntry(rfe_array[idx]); - } - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::SetCurrentTitle(CStringW title) { - size_t idx; - if (GetCurrentIndex(idx)) { - rfe_array[idx].title = title; - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentABRepeat(ABRepeat abRepeat) { - size_t idx; - if (GetCurrentIndex(idx)) { - rfe_array[idx].abRepeat = abRepeat; - WriteMediaHistoryEntry(rfe_array[idx]); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::WriteCurrentEntry() { - size_t idx; - if (!current_rfe_hash.IsEmpty() && GetCurrentIndex(idx)) { - WriteMediaHistoryEntry(rfe_array[idx]); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::Add(RecentFileEntry r, bool current_open) { - if (r.fns.GetCount() < 1) { - return; - } - if (CString(r.fns.GetHead()).MakeLower().Find(_T("@device:")) >= 0) { - return; - } - - if (r.hash.IsEmpty()) { - r.hash = getRFEHash(r); - } - for (size_t i = 0; i < rfe_array.GetCount(); i++) { - if (r.hash == rfe_array[i].hash) { - rfe_array.RemoveAt(i); //do not call Remove as it will purge reg key. we are just resorting - break; - } - } - WriteMediaHistoryEntry(r, true); - - rfe_array.InsertAt(0, r); - if (current_open) { - current_rfe_hash = r.hash; - persistedFilePosition = r.filePosition; - } - - // purge obsolete entry - if (rfe_array.GetCount() > m_maxSize) { - CStringW hash = rfe_array.GetAt(m_maxSize).hash; - if (!hash.IsEmpty()) { - CStringW subSection; - subSection.Format(L"%s\\%s", m_section, static_cast(hash)); - auto pApp = AfxGetMyApp(); - pApp->WriteProfileString(subSection, nullptr, nullptr); - } - rfe_array.SetCount(m_maxSize); - } - rfe_array.FreeExtra(); -} - -static void DeserializeHex(LPCTSTR strVal, BYTE* pBuffer, int nBufSize) { - long lRes; - - for (int i = 0; i < nBufSize; i++) { - _stscanf_s(strVal + (i * 2), _T("%02lx"), &lRes); - pBuffer[i] = (BYTE)lRes; - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::ReadLegacyMediaHistory(std::map& filenameToIndex) { - rfe_array.RemoveAll(); - auto pApp = AfxGetMyApp(); - LPCWSTR legacySection = L"Recent File List"; - int dvdCount = 0; - for (size_t i = 1; i <= m_maxSize; i++) { - CStringW t; - t.Format(_T("File%zu"), i); - CStringW fn = pApp->GetProfileStringW(legacySection, t); - if (fn.IsEmpty()) { - break; - } - t.Format(_T("Title%zu"), i); - CStringW title = pApp->GetProfileStringW(legacySection, t); - t.Format(_T("Cue%zu"), i); - CStringW cue = pApp->GetProfileStringW(legacySection, t); - RecentFileEntry r; - r.fns.AddTail(fn); - r.title = title; - r.cue = cue; - int k = 2; - for (;; k++) { - t.Format(_T("File%zu,%d"), i, k); - CStringW ft = pApp->GetProfileStringW(legacySection, t); - if (ft.IsEmpty()) break; - r.fns.AddTail(ft); - } - k = 1; - for (;; k++) { - t.Format(_T("Sub%zu,%d"), i, k); - CStringW st = pApp->GetProfileStringW(legacySection, t); - if (st.IsEmpty()) break; - r.subs.AddTail(st); - } - if (fn.Right(9) == L"\\VIDEO_TS") { //try to find the dvd position from index - CStringW strDVDPos; - strDVDPos.Format(_T("DVD Position %d"), dvdCount++); - CStringW strValue = pApp->GetProfileString(IDS_R_SETTINGS, strDVDPos, _T("")); - - if (!strValue.IsEmpty()) { - if (strValue.GetLength() / 2 == sizeof(DVD_POSITION)) { - DeserializeHex(strValue, (BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); - } - } - rfe_array.Add(r); - } else { - filenameToIndex[r.fns.GetHead()] = rfe_array.Add(r); - } - } - rfe_array.FreeExtra(); -} - -static CString SerializeHex(const BYTE* pBuffer, int nBufSize) { - CString strTemp; - CString strResult; - - for (int i = 0; i < nBufSize; i++) { - strTemp.Format(_T("%02x"), pBuffer[i]); - strResult += strTemp; - } - - return strResult; -} - -void CAppSettings::CRecentFileListWithMoreInfo::ReadLegacyMediaPosition(std::map& filenameToIndex) { - auto pApp = AfxGetMyApp(); - bool hasNextEntry = true; - CStringW strFilename; - CStringW strFilePos; - - for (int i = 0; i < 1000 && hasNextEntry; i++) { - strFilename.Format(_T("File Name %d"), i); - CStringW strFile = pApp->GetProfileString(IDS_R_SETTINGS, strFilename); - - if (strFile.IsEmpty()) { - hasNextEntry = false; - } else { - strFilePos.Format(_T("File Position %d"), i); - if (filenameToIndex.count(strFile)) { - size_t index = filenameToIndex[strFile]; - if (index < rfe_array.GetCount()) { - CStringW strValue = pApp->GetProfileString(IDS_R_SETTINGS, strFilePos); - rfe_array.GetAt(index).filePosition = _tstoi64(strValue); - } - } - // remove old values - pApp->WriteProfileString(IDS_R_SETTINGS, strFilename, nullptr); - pApp->WriteProfileString(IDS_R_SETTINGS, strFilePos, nullptr); - } - } -} - -bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntryFN(CStringW fn, RecentFileEntry& r) { - CStringW hash = getRFEHash(fn); - if (!LoadMediaHistoryEntry(hash, r)) { - r.hash = hash; - r.fns.AddHead(fn); //otherwise add a new entry - return false; - } - return true; -} - -bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntryDVD(ULONGLONG llDVDGuid, CStringW fn, RecentFileEntry& r) { - CStringW hash = getRFEHash(llDVDGuid); - if (!LoadMediaHistoryEntry(hash, r)) { - r.hash = hash; - r.fns.AddHead(fn); //otherwise add a new entry - r.DVDPosition.llDVDGuid = llDVDGuid; - return false; - } - return true; -} - -bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntry(CStringW hash, RecentFileEntry &r) { - auto pApp = AfxGetMyApp(); - CStringW fn, subSection, t; - - subSection.Format(L"%s\\%s", m_section, static_cast(hash)); - - fn = pApp->GetProfileStringW(subSection, L"Filename", L""); - if (fn.IsEmpty()) { - return false; - } - - DWORD filePosition = pApp->GetProfileIntW(subSection, L"FilePosition", 0); - CStringW dvdPosition = pApp->GetProfileStringW(subSection, L"DVDPosition", L""); - - r.hash = hash; - r.fns.AddHead(fn); - r.title = pApp->GetProfileStringW(subSection, L"Title", L""); - r.cue = pApp->GetProfileStringW(subSection, L"Cue", L""); - r.filePosition = filePosition * 10000LL; - if (!dvdPosition.IsEmpty()) { - if (dvdPosition.GetLength() / 2 == sizeof(DVD_POSITION)) { - DeserializeHex(dvdPosition, (BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); - } - } - r.abRepeat.positionA = pApp->GetProfileIntW(subSection, L"abRepeat.positionA", 0) * 10000LL; - r.abRepeat.positionB = pApp->GetProfileIntW(subSection, L"abRepeat.positionB", 0) * 10000LL; - r.abRepeat.dvdTitle = pApp->GetProfileIntW(subSection, L"abRepeat.dvdTitle", -1); - - int k = 2; - for (;; k++) { - t.Format(_T("Filename%03d"), k); - CStringW ft = pApp->GetProfileStringW(subSection, t); - if (ft.IsEmpty()) { - break; - } - r.fns.AddTail(ft); - } - k = 1; - for (;; k++) { - t.Format(_T("Sub%03d"), k); - CStringW st = pApp->GetProfileStringW(subSection, t); - if (st.IsEmpty()) { - break; - } - r.subs.AddTail(st); - } - - r.AudioTrackIndex = pApp->GetProfileIntW(subSection, L"AudioTrackIndex", -1); - r.SubtitleTrackIndex = pApp->GetProfileIntW(subSection, L"SubtitleTrackIndex", -1); - return true; -} - -void CAppSettings::CRecentFileListWithMoreInfo::ReadMediaHistory() { - auto pApp = AfxGetMyApp(); - - int lastAddedStored = pApp->GetProfileIntW(m_section, L"LastAdded", 0); - if (lastAddedStored != 0 && lastAddedStored == rfe_last_added || rfe_last_added == 1) { - return; - } - listModifySequence++; - - size_t maxsize = AfxGetAppSettings().fKeepHistory ? m_maxSize : 0; - - std::list hashes = pApp->GetSectionSubKeys(m_section); - - if (hashes.empty()) { - if (maxsize > 0) { - MigrateLegacyHistory(); - hashes = pApp->GetSectionSubKeys(m_section); - } else { - rfe_last_added = 1; - rfe_array.RemoveAll(); - return; - } - } - - auto timeToHash = CAppSettings::LoadHistoryHashes(m_section, L"LastOpened"); - - rfe_array.RemoveAll(); - int entries = 0; - for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { - bool purge_rfe = true; - CStringW hash = iter->second; - if (entries < maxsize) { - RecentFileEntry r; - r.lastOpened = iter->first; - if (LoadMediaHistoryEntry(hash, r)) { - rfe_array.Add(r); - purge_rfe = false; - entries++; - } - } - if (purge_rfe) { //purge entry - CAppSettings::PurgeExpiredHash(m_section, hash); - } - } - rfe_array.FreeExtra(); - - if (lastAddedStored == 0 && m_maxSize > 0) { - rfe_last_added = 1; // history read, but nothing new added yet - pApp->WriteProfileInt(m_section, L"LastAdded", rfe_last_added); - } else { - rfe_last_added = lastAddedStored; - } - - // The playlist history size is not managed elsewhere - CAppSettings::PurgePlaylistHistory(maxsize); -} - -void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistoryAudioIndex(RecentFileEntry& r) { - auto pApp = AfxGetMyApp(); - - if (r.hash.IsEmpty()) { - r.hash = getRFEHash(r.fns.GetHead()); - } - - CStringW subSection, t; - subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); - - if (r.AudioTrackIndex != -1) { - pApp->WriteProfileInt(subSection, L"AudioTrackIndex", int(r.AudioTrackIndex)); - } else { - pApp->WriteProfileStringW(subSection, L"AudioTrackIndex", nullptr); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistorySubtitleIndex(RecentFileEntry& r) { - auto pApp = AfxGetMyApp(); - - if (r.hash.IsEmpty()) { - r.hash = getRFEHash(r.fns.GetHead()); - } - - CStringW subSection, t; - subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); - - if (r.SubtitleTrackIndex != -1) { - pApp->WriteProfileInt(subSection, L"SubtitleTrackIndex", int(r.SubtitleTrackIndex)); - } else { - pApp->WriteProfileStringW(subSection, L"SubtitleTrackIndex", nullptr); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistoryEntry(RecentFileEntry& r, bool updateLastOpened /* = false */) { - auto pApp = AfxGetMyApp(); - - if (r.hash.IsEmpty()) { - r.hash = getRFEHash(r.fns.GetHead()); - } - - CStringW subSection, t; - subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); - - CString storedFilename = pApp->GetProfileStringW(subSection, L"Filename", L""); - bool isNewEntry = storedFilename.IsEmpty(); - if (isNewEntry || storedFilename != r.fns.GetHead()) { - pApp->WriteProfileStringW(subSection, L"Filename", r.fns.GetHead()); - } - - if (r.fns.GetCount() > 1) { - int k = 2; - POSITION p(r.fns.GetHeadPosition()); - r.fns.GetNext(p); - while (p != nullptr) { - CString fn = r.fns.GetNext(p); - t.Format(L"Filename%03d", k); - pApp->WriteProfileStringW(subSection, t, fn); - k++; - } - } - if (!r.title.IsEmpty()) { - t = L"Title"; - pApp->WriteProfileStringW(subSection, t, r.title); - } - if (!r.cue.IsEmpty()) { - t = L"Cue"; - pApp->WriteProfileStringW(subSection, t, r.cue); - } - if (r.subs.GetCount() > 0) { - int k = 1; - POSITION p(r.subs.GetHeadPosition()); - while (p != nullptr) { - CString fn = r.subs.GetNext(p); - t.Format(L"Sub%03d", k); - pApp->WriteProfileStringW(subSection, t, fn); - k++; - } - } - if (r.DVDPosition.llDVDGuid) { - t = L"DVDPosition"; - CStringW strValue = SerializeHex((BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); - pApp->WriteProfileStringW(subSection, t, strValue); - } else { - t = L"FilePosition"; - pApp->WriteProfileInt(subSection, t, int(r.filePosition / 10000LL)); - persistedFilePosition = r.filePosition; - } - if (r.abRepeat.positionA) { - pApp->WriteProfileInt(subSection, L"abRepeat.positionA", int(r.abRepeat.positionA / 10000LL)); - } else { - pApp->WriteProfileStringW(subSection, L"abRepeat.positionA", nullptr); - } - if (r.abRepeat.positionB) { - pApp->WriteProfileInt(subSection, L"abRepeat.positionB", int(r.abRepeat.positionB / 10000LL)); - } else { - pApp->WriteProfileStringW(subSection, L"abRepeat.positionB", nullptr); - } - if (r.abRepeat && r.abRepeat.dvdTitle != -1) { - pApp->WriteProfileInt(subSection, L"abRepeat.dvdTitle", int(r.abRepeat.dvdTitle)); - } else { - pApp->WriteProfileStringW(subSection, L"abRepeat.dvdTitle", nullptr); - } - - if (r.AudioTrackIndex != -1) { - pApp->WriteProfileInt(subSection, L"AudioTrackIndex", int(r.AudioTrackIndex)); - } else { - pApp->WriteProfileStringW(subSection, L"AudioTrackIndex", nullptr); - } - - if (r.SubtitleTrackIndex != -1) { - pApp->WriteProfileInt(subSection, L"SubtitleTrackIndex", int(r.SubtitleTrackIndex)); - } else { - pApp->WriteProfileStringW(subSection, L"SubtitleTrackIndex", nullptr); - } - - if (updateLastOpened || isNewEntry || r.lastOpened.IsEmpty()) { - auto now = std::chrono::system_clock::now(); - auto nowISO = date::format(L"%FT%TZ", date::floor(now)); - r.lastOpened = CStringW(nowISO.c_str()); - pApp->WriteProfileStringW(subSection, L"LastOpened", r.lastOpened); - if (isNewEntry) { - rfe_last_added = (int)std::chrono::time_point_cast(now).time_since_epoch().count(); - pApp->WriteProfileInt(m_section, L"LastAdded", rfe_last_added); - } - } - listModifySequence++; -} - -void CAppSettings::CRecentFileListWithMoreInfo::SaveMediaHistory() { - if (rfe_array.GetCount()) { - //go in reverse in case we are setting last opened when migrating history (makes last appear oldest) - for (size_t i = rfe_array.GetCount() - 1, j = 0; j < m_maxSize && j < rfe_array.GetCount(); i--, j++) { - auto& r = rfe_array.GetAt(i); - WriteMediaHistoryEntry(r); - } - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::MigrateLegacyHistory() { - auto pApp = AfxGetMyApp(); - std::map filenameToIndex; - ReadLegacyMediaHistory(filenameToIndex); - ReadLegacyMediaPosition(filenameToIndex); - SaveMediaHistory(); - LPCWSTR legacySection = L"Recent File List"; - pApp->WriteProfileString(legacySection, nullptr, nullptr); -} - -void CAppSettings::CRecentFileListWithMoreInfo::SetSize(size_t nSize) { - m_maxSize = nSize; - if (rfe_array.GetCount() > m_maxSize) { - rfe_array.SetCount(m_maxSize); - PurgeMediaHistory(m_maxSize); - PurgePlaylistHistory(m_maxSize); - // to force update of recent files menu - listModifySequence++; - } - rfe_array.FreeExtra(); - - if (nSize == 0) { - current_rfe_hash.Empty(); - } -} - -void CAppSettings::CRecentFileListWithMoreInfo::RemoveAll() { - SetSize(0); -} - -bool CAppSettings::IsVSFilterInstalled() -{ - return IsCLSIDRegistered(CLSID_VSFilter); -} - -void CAppSettings::UpdateSettings() -{ - auto pApp = AfxGetMyApp(); - ASSERT(pApp); - - UINT version = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_R_VERSION, 0); - if (version >= APPSETTINGS_VERSION) { - return; // Nothing to update - } - - // Use lambda expressions to copy data entries - auto copyInt = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { - if (pApp->HasProfileEntry(oldSection, oldEntry)) { - int old = pApp->GetProfileInt(oldSection, oldEntry, 0); - VERIFY(pApp->WriteProfileInt(newSection, newEntry, old)); - } - }; - auto copyStr = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { - if (pApp->HasProfileEntry(oldSection, oldEntry)) { - CString old = pApp->GetProfileString(oldSection, oldEntry); - VERIFY(pApp->WriteProfileString(newSection, newEntry, old)); - } - }; - auto copyBin = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { - UINT len; - BYTE* old; - if (pApp->GetProfileBinary(oldSection, oldEntry, &old, &len)) { - VERIFY(pApp->WriteProfileBinary(newSection, newEntry, old, len)); - delete [] old; - } - }; - - - // Migrate to the latest version, these cases should fall through - // so that all incremental updates are applied. - switch (version) { - case 0: { - UINT nAudioBoostTmp = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, -1); - if (nAudioBoostTmp == UINT(-1)) { - double dAudioBoost_dB = _tstof(pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, _T("0"))); - if (dAudioBoost_dB < 0 || dAudioBoost_dB > 10) { - dAudioBoost_dB = 0; - } - nAudioBoostTmp = UINT(100 * pow(10.0, dAudioBoost_dB / 20.0) + 0.5) - 100; - } - if (nAudioBoostTmp > 300) { // Max boost is 300% - nAudioBoostTmp = 300; - } - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, nAudioBoostTmp); - } - { - const CString section(_T("Settings")); - copyInt(section, _T("Remember DVD Pos"), section, _T("RememberDVDPos")); - copyInt(section, _T("Remember File Pos"), section, _T("RememberFilePos")); - copyInt(section, _T("Show OSD"), section, _T("ShowOSD")); - copyStr(section, _T("Shaders List"), section, _T("ShadersList")); - copyInt(section, _T("OSD_Size"), section, _T("OSDSize")); - copyStr(section, _T("OSD_Font"), section, _T("OSDFont")); - copyInt(section, _T("gotoluf"), section, _T("GoToLastUsed")); - copyInt(section, _T("fps"), section, _T("GoToFPS")); - } - { - // Copy DVB section - const CString oldSection(_T("DVB configuration")); - const CString newSection(_T("DVBConfiguration")); - //copyStr(oldSection, _T("BDANetworkProvider"), newSection, _T("BDANetworkProvider")); - copyStr(oldSection, _T("BDATuner"), newSection, _T("BDATuner")); - copyStr(oldSection, _T("BDAReceiver"), newSection, _T("BDAReceiver")); - copyInt(oldSection, _T("BDAScanFreqStart"), newSection, _T("BDAScanFreqStart")); - copyInt(oldSection, _T("BDAScanFreqEnd"), newSection, _T("BDAScanFreqEnd")); - copyInt(oldSection, _T("BDABandWidth"), newSection, _T("BDABandWidth")); - copyInt(oldSection, _T("BDAUseOffset"), newSection, _T("BDAUseOffset")); - copyInt(oldSection, _T("BDAOffset"), newSection, _T("BDAOffset")); - copyInt(oldSection, _T("BDAIgnoreEncryptedChannels"), newSection, _T("BDAIgnoreEncryptedChannels")); - copyInt(oldSection, _T("LastChannel"), newSection, _T("LastChannel")); - copyInt(oldSection, _T("RebuildFilterGraph"), newSection, _T("RebuildFilterGraph")); - copyInt(oldSection, _T("StopFilterGraph"), newSection, _T("StopFilterGraph")); - for (int iChannel = 0; ; iChannel++) { - CString strTemp, strChannel; - strTemp.Format(_T("%d"), iChannel); - if (!pApp->HasProfileEntry(oldSection, strTemp)) { - break; - } - strChannel = pApp->GetProfileString(oldSection, strTemp); - if (strChannel.IsEmpty()) { - break; - } - VERIFY(pApp->WriteProfileString(newSection, strTemp, strChannel)); - } - } - [[fallthrough]]; - case 1: { - // Internal decoding of WMV 1/2/3 is now disabled by default so we reinitialize its value - pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, _T("TRA_WMV"), FALSE); - } - [[fallthrough]]; - case 2: { - const CString section(_T("Settings")); - if (pApp->HasProfileEntry(section, _T("FullScreenCtrls")) && - pApp->HasProfileEntry(section, _T("FullScreenCtrlsTimeOut"))) { - bool bHide = true; - int nHidePolicy = 0; - int nTimeout = -1; - if (!pApp->GetProfileInt(section, _T("FullScreenCtrls"), 0)) { - // hide always - } else { - nTimeout = pApp->GetProfileInt(section, _T("FullScreenCtrlsTimeOut"), 0); - if (nTimeout < 0) { - // show always - bHide = false; - } else if (nTimeout == 0) { - // show when hovered - nHidePolicy = 1; - } else { - // show when mouse moved - nHidePolicy = 2; - } - } - VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControls"), bHide)); - if (nTimeout >= 0) { - VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControlsPolicy"), nHidePolicy)); - VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControlsDelay"), nTimeout * 1000)); - } - } - } - [[fallthrough]]; - case 3: { -#pragma pack(push, 1) - struct dispmode { - bool fValid; - CSize size; - int bpp, freq; - DWORD dmDisplayFlags; - }; - - struct fpsmode { - double vfr_from; - double vfr_to; - bool fChecked; - dispmode dmFSRes; - bool fIsData; - }; - - struct AChFR { - bool bEnabled; - fpsmode dmFullscreenRes[30]; - bool bApplyDefault; - }; //AutoChangeFullscrRes -#pragma pack(pop) - - LPBYTE ptr; - UINT len; - bool bSetDefault = true; - if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("FullscreenRes"), &ptr, &len)) { - if (len == sizeof(AChFR)) { - AChFR autoChangeFullscrRes; - memcpy(&autoChangeFullscrRes, ptr, sizeof(AChFR)); - - autoChangeFSMode.bEnabled = autoChangeFullscrRes.bEnabled; - autoChangeFSMode.bApplyDefaultModeAtFSExit = autoChangeFullscrRes.bApplyDefault; - - for (size_t i = 0; i < _countof(autoChangeFullscrRes.dmFullscreenRes); i++) { - const auto& modeOld = autoChangeFullscrRes.dmFullscreenRes[i]; - // The old settings could be corrupted quite easily so be careful when converting them - if (modeOld.fIsData - && modeOld.vfr_from >= 0.0 && modeOld.vfr_from <= 126.0 - && modeOld.vfr_to >= 0.0 && modeOld.vfr_to <= 126.0 - && modeOld.dmFSRes.fValid - && modeOld.dmFSRes.bpp == 32 - && modeOld.dmFSRes.size.cx >= 640 && modeOld.dmFSRes.size.cx < 10000 - && modeOld.dmFSRes.size.cy >= 380 && modeOld.dmFSRes.size.cy < 10000 - && modeOld.dmFSRes.freq > 0 && modeOld.dmFSRes.freq < 1000) { - DisplayMode dm; - dm.bValid = true; - dm.size = modeOld.dmFSRes.size; - dm.bpp = 32; - dm.freq = modeOld.dmFSRes.freq; - dm.dwDisplayFlags = modeOld.dmFSRes.dmDisplayFlags & DM_INTERLACED; - - autoChangeFSMode.modes.emplace_back(modeOld.fChecked, modeOld.vfr_from, modeOld.vfr_to, 0, std::move(dm)); - } - } - - bSetDefault = autoChangeFSMode.modes.empty() || autoChangeFSMode.modes[0].dFrameRateStart != 0.0 || autoChangeFSMode.modes[0].dFrameRateStop != 0.0; - } - delete [] ptr; - } - - if (bSetDefault) { - autoChangeFSMode.bEnabled = false; - autoChangeFSMode.bApplyDefaultModeAtFSExit = false; - autoChangeFSMode.modes.clear(); - } - autoChangeFSMode.bRestoreResAfterProgExit = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("RestoreResAfterExit"), TRUE); - autoChangeFSMode.uDelay = pApp->GetProfileInt(IDS_R_SETTINGS, _T("FullscreenResDelay"), 0); - - SaveSettingsAutoChangeFullScreenMode(); - } - [[fallthrough]]; - case 4: { - bool bDisableSubtitleAnimation = !pApp->GetProfileInt(IDS_R_SETTINGS, _T("SPCAllowAnimationWhenBuffering"), TRUE); - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, bDisableSubtitleAnimation)); - } - [[fallthrough]]; - case 5: - copyInt(IDS_R_INTERNAL_FILTERS, _T("SRC_DTSAC3"), IDS_R_INTERNAL_FILTERS, _T("SRC_DTS")); - copyInt(IDS_R_INTERNAL_FILTERS, _T("SRC_DTSAC3"), IDS_R_INTERNAL_FILTERS, _T("SRC_AC3")); - [[fallthrough]]; - case 6: { - SubtitleRenderer subrenderer = SubtitleRenderer::INTERNAL; - if (!pApp->GetProfileInt(IDS_R_SETTINGS, _T("AutoloadSubtitles"), TRUE)) { - if (IsSubtitleRendererRegistered(SubtitleRenderer::VS_FILTER)) { - subrenderer = SubtitleRenderer::VS_FILTER; - } - if (IsSubtitleRendererRegistered(SubtitleRenderer::XY_SUB_FILTER)) { - int renderer = IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS; - renderer = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, renderer); - if (IsSubtitleRendererSupported(SubtitleRenderer::XY_SUB_FILTER, renderer)) { - subrenderer = SubtitleRenderer::XY_SUB_FILTER; - } - } - } - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, static_cast(subrenderer))); - } - [[fallthrough]]; - case 7: - // Update the settings after the removal of DirectX 7 renderers - switch (pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_DEFAULT)) { - case 3: // VIDRNDT_DS_VMR7WINDOWED - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_VMR9WINDOWED)); - break; - case 5: // VIDRNDT_DS_VMR7RENDERLESS - VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_VMR9RENDERLESS)); - break; - } - [[fallthrough]]; - default: - pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_R_VERSION, APPSETTINGS_VERSION); - } -} - -// RenderersSettings.h - -CRenderersData* GetRenderersData() { - return &AfxGetMyApp()->m_Renderers; -} - -CRenderersSettings& GetRenderersSettings() { - auto& s = AfxGetAppSettings(); - if (s.m_RenderersSettings.subPicQueueSettings.nSize > 0) { - // queue does not work properly with libass - if (s.bRenderSSAUsingLibass || s.bRenderSRTUsingLibass) { - s.m_RenderersSettings.subPicQueueSettings.nSize = 0; - } - } - return s.m_RenderersSettings; -} - -void CAppSettings::SavePlayListPosition(CStringW playlistPath, UINT position) { - auto pApp = AfxGetMyApp(); - ASSERT(pApp); - - auto hash = getRFEHash(playlistPath); - - CStringW subSection, t; - subSection.Format(L"%s\\%s", L"PlaylistHistory", static_cast(hash)); - pApp->WriteProfileInt(subSection, L"Position", position); - - auto now = std::chrono::system_clock::now(); - auto nowISO = date::format(L"%FT%TZ", date::floor(now)); - CStringW lastUpdated = CStringW(nowISO.c_str()); - pApp->WriteProfileStringW(subSection, L"LastUpdated", lastUpdated); -} - -UINT CAppSettings::GetSavedPlayListPosition(CStringW playlistPath) { - auto pApp = AfxGetMyApp(); - ASSERT(pApp); - - auto hash = getRFEHash(playlistPath); - - CStringW subSection, t; - subSection.Format(L"%s\\%s", L"PlaylistHistory", static_cast(hash)); - UINT position = pApp->GetProfileIntW(subSection, L"Position", -1); - if (position != (UINT)-1) { - return position; - } - return 0; -} - -// SubRendererSettings.h - -// Todo: move individual members of AppSettings into SubRendererSettings struct and use this function to get a reference to it -SubRendererSettings GetSubRendererSettings() { - const auto& s = AfxGetAppSettings(); - SubRendererSettings srs; - srs.defaultStyle = s.subtitlesDefStyle; - srs.overrideDefaultStyle = s.bSubtitleOverrideDefaultStyle || s.bSubtitleOverrideAllStyles; - srs.overrideAllStyles = s.bSubtitleOverrideAllStyles; -#if USE_LIBASS - srs.renderSSAUsingLibass = s.bRenderSSAUsingLibass; - srs.renderSRTUsingLibass = s.bRenderSRTUsingLibass; -#endif - OpenTypeLang::CStringAtoHintStr(srs.openTypeLangHint, s.strOpenTypeLangHint); - return srs; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "AppSettings.h" +#include "CrashReporter.h" +#include "FGFilter.h" +#include "FakeFilterMapper2.h" +#include "FileAssoc.h" +#include "ExceptionHandler.h" +#include "PathUtils.h" +#include "Translations.h" +#include "UpdateChecker.h" +#include "WinAPIUtils.h" +#include "moreuuids.h" +#include "mplayerc.h" +#include "../thirdparty/sanear/src/Factory.h" +#include +#include +#include +#include "date/date.h" +#include "PPageExternalFilters.h" +#include "../VideoRenderers/MPCVRAllocatorPresenter.h" +std::map CAppSettings::CommandIDToWMCMD; + +#pragma warning(push) +#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized +CAppSettings::CAppSettings() + : bInitialized(false) + , nCLSwitches(0) + , rtShift(0) + , rtStart(0) + , lDVDTitle(0) + , lDVDChapter(0) + , iMonitor(0) + , fShowDebugInfo(false) + , iAdminOption(0) + , fAllowMultipleInst(false) + , fTrayIcon(false) + , fShowOSD(true) + , fShowCurrentTimeInOSD(false) + , nOSDTransparency(64) + , nOSDBorder(1) + , fLimitWindowProportions(false) + , fSnapToDesktopEdges(false) + , fHideCDROMsSubMenu(false) + , dwPriority(NORMAL_PRIORITY_CLASS) + , iTitleBarTextStyle(1) + , fTitleBarTextTitle(false) + , fKeepHistory(true) + , iRecentFilesNumber(100) + , MRU(L"MediaHistory", iRecentFilesNumber) + , MRUDub(0, _T("Recent Dub List"), _T("Dub%d"), 20) + , fRememberDVDPos(false) + , fRememberFilePos(false) + , iRememberPosForLongerThan(5) + , bRememberPosForAudioFiles(true) + , bRememberExternalPlaylistPos(true) + , bRememberTrackSelection(true) + , bRememberPlaylistItems(true) + , fRememberWindowPos(false) + , fRememberWindowSize(false) + , rcLastWindowPos(CRect(100, 100, 500, 400)) + , fSavePnSZoom(false) + , dZoomX(1.0) + , dZoomY(1.0) + , fAssociatedWithIcons(true) + , hAccel(nullptr) + , fWinLirc(false) + , fUIce(false) + , fGlobalMedia(true) + , nLogoId(-1) + , fLogoExternal(false) + , fLogoColorProfileEnabled(false) + , fEnableWebServer(false) + , nWebServerPort(13579) + , nCmdlnWebServerPort(-1) + , fWebServerUseCompression(true) + , fWebServerLocalhostOnly(false) + , bWebUIEnablePreview(false) + , fWebServerPrintDebugInfo(false) + , nVolume(100) + , fMute(false) + , nBalance(0) + , nLoops(1) + , fLoopForever(false) + , eLoopMode(LoopMode::PLAYLIST) + , fRememberZoomLevel(true) + , nAutoFitFactorMin(75) + , nAutoFitFactorMax(75) + , iZoomLevel(1) + , fEnableWorkerThreadForOpening(true) + , fReportFailedPins(true) + , fAutoloadAudio(true) + , fBlockVSFilter(true) + , bBlockRDP(false) + , nVolumeStep(5) + , nSpeedStep(0) + , nDefaultToolbarSize(24) + , eAfterPlayback(AfterPlayback::DO_NOTHING) + , fUseDVDPath(false) + , idMenuLang(0) + , idAudioLang(0) + , idSubtitlesLang(0) + , fClosedCaptions(false) + , iDSVideoRendererType(VIDRNDT_DS_DEFAULT) + , fD3DFullscreen(false) + , fLaunchfullscreen(false) + , bHideFullscreenControls(true) + , eHideFullscreenControlsPolicy(HideFullscreenControlsPolicy::SHOW_WHEN_HOVERED) + , uHideFullscreenControlsDelay(0) + , bHideFullscreenDockedPanels(true) + , fExitFullScreenAtTheEnd(true) + , iDefaultCaptureDevice(0) + , iAnalogCountry(1) + , iBDAScanFreqStart(474000) + , iBDAScanFreqEnd(858000) + , iBDABandwidth(8) + , iBDASymbolRate(0) + , fBDAUseOffset(false) + , iBDAOffset(166) + , fBDAIgnoreEncryptedChannels(false) + , nDVBLastChannel(INT_ERROR) + , nDVBRebuildFilterGraph(DVB_REBUILD_FG_WHEN_SWITCHING) + , nDVBStopFilterGraph(DVB_STOP_FG_WHEN_SWITCHING) + , SrcFilters() + , TraFilters() + , fEnableAudioSwitcher(true) + , fAudioNormalize(false) + , nAudioMaxNormFactor(400) + , fAudioNormalizeRecover(true) + , nAudioBoost(0) + , fDownSampleTo441(false) + , fAudioTimeShift(false) + , iAudioTimeShift(0) + , fCustomChannelMapping(false) + , nSpeakerChannels(2) + , pSpeakerToChannelMap() + , fOverridePlacement(false) + , nHorPos(50) + , nVerPos(90) + , bSubtitleARCompensation(true) + , nSubDelayStep(500) + , bPreferDefaultForcedSubtitles(true) + , fPrioritizeExternalSubtitles(true) + , fDisableInternalSubtitles(true) + , bAllowOverridingExternalSplitterChoice(false) + , bAutoDownloadSubtitles(false) + , bAutoSaveDownloadedSubtitles(false) + , nAutoDownloadScoreMovies(0x16) + , nAutoDownloadScoreSeries(0x18) + , bAutoUploadSubtitles(false) + , bPreferHearingImpairedSubtitles(false) + , bMPCTheme(true) + , bWindows10DarkThemeActive(false) + , bWindows10AccentColorsEnabled(false) + , iModernSeekbarHeight(DEF_MODERN_SEEKBAR_HEIGHT) + , eModernThemeMode(CMPCTheme::ModernThemeMode::WINDOWSDEFAULT) + , iFullscreenDelay(MIN_FULLSCREEN_DELAY) + , iVerticalAlignVideo(verticalAlignVideoType::ALIGN_MIDDLE) + , nJumpDistS(DEFAULT_JUMPDISTANCE_1) + , nJumpDistM(DEFAULT_JUMPDISTANCE_2) + , nJumpDistL(DEFAULT_JUMPDISTANCE_3) + , bFastSeek(true) + , eFastSeekMethod(FASTSEEK_NEAREST_KEYFRAME) + , fShowChapters(true) + , bNotifySkype(false) + , fPreventMinimize(false) + , bUseEnhancedTaskBar(true) + , fLCDSupport(false) + , fSeekPreview(false) + , iSeekPreviewSize(15) + , fUseSearchInFolder(false) + , fUseSeekbarHover(true) + , nHoverPosition(TIME_TOOLTIP_ABOVE_SEEKBAR) + , nOSDSize(0) + , bHideWindowedMousePointer(true) + , iBrightness(0) + , iContrast(0) + , iHue(0) + , iSaturation(0) + , nUpdaterAutoCheck(-1) + , nUpdaterDelay(7) + , eCaptionMenuMode(MODE_SHOWCAPTIONMENU) + , fHideNavigation(false) + , nCS(CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR) + , language(LANGID(-1)) + , fEnableSubtitles(true) + , bSubtitleOverrideDefaultStyle(false) + , bSubtitleOverrideAllStyles(false) + , iDefaultVideoSize(DVS_FROMINSIDE) + , fKeepAspectRatio(true) + , fCompMonDeskARDiff(false) + , iOnTop(0) + , bFavRememberPos(true) + , bFavRelativeDrive(false) + , bFavRememberABMarks(false) + , iThumbRows(4) + , iThumbCols(4) + , iThumbWidth(1024) + , bSubSaveExternalStyleFile(false) + , bShufflePlaylistItems(false) + , bHidePlaylistFullScreen(false) + , nLastWindowType(SIZE_RESTORED) + , nLastUsedPage(0) + , fRemainingTime(false) + , bHighPrecisionTimer(false) + , bTimerShowPercentage(false) + , fLastFullScreen(false) + , fEnableEDLEditor(false) + , hMasterWnd(nullptr) + , bHideWindowedControls(false) + , nJpegQuality(90) + , bEnableCoverArt(true) + , nCoverArtSizeLimit(600) + , bEnableLogging(false) + , bUseLegacyToolbar(false) + , iLAVGPUDevice(DWORD_MAX) + , nCmdVolume(0) + , eSubtitleRenderer(SubtitleRenderer::INTERNAL) + , bUseYDL(true) + , iYDLMaxHeight(1440) + , iYDLVideoFormat(0) + , iYDLAudioFormat(0) + , bYDLAudioOnly(false) + , sYDLExePath(_T("")) + , sYDLCommandLine(_T("")) + , bSnapShotSubtitles(true) + , bSnapShotKeepVideoExtension(true) + , bEnableCrashReporter(true) + , nStreamPosPollerInterval(100) + , bShowLangInStatusbar(false) + , bShowFPSInStatusbar(false) + , bShowABMarksInStatusbar(false) + , bShowVideoInfoInStatusbar(true) + , bShowAudioFormatInStatusbar(true) +#if USE_LIBASS + , bRenderSSAUsingLibass(false) + , bRenderSRTUsingLibass(false) +#endif + , bAddLangCodeWhenSaveSubtitles(false) + , bUseTitleInRecentFileList(true) + , sYDLSubsPreference() + , bUseAutomaticCaptions(false) + , bLockNoPause(false) + , bPreventDisplaySleep(true) + , bUseSMTC(false) + , iReloadAfterLongPause(0) + , bOpenRecPanelWhenOpeningDevice(true) + , lastQuickOpenPath(L"") + , lastFileSaveCopyPath(L"") + , lastFileOpenDirPath(L"") + , externalPlayListPath(L"") + , iRedirectOpenToAppendThreshold(1000) + , bFullscreenSeparateControls(true) + , bAlwaysUseShortMenu(false) + , iStillVideoDuration(10) + , iMouseLeftUpDelay(0) + , bUseFreeType(false) + , bUseMediainfoLoadFileDuration(false) + , bCaptureDeinterlace(false) + , bPauseWhileDraggingSeekbar(true) + , bConfirmFileDelete(true) +{ + // Internal source filter +#if INTERNAL_SOURCEFILTER_AC3 + SrcFiltersKeys[SRC_AC3] = FilterKey(_T("SRC_AC3"), true); +#endif +#if INTERNAL_SOURCEFILTER_ASF + SrcFiltersKeys[SRC_ASF] = FilterKey(_T("SRC_ASF"), false); +#endif +#if INTERNAL_SOURCEFILTER_AVI + SrcFiltersKeys[SRC_AVI] = FilterKey(_T("SRC_AVI"), true); +#endif +#if INTERNAL_SOURCEFILTER_AVS + SrcFiltersKeys[SRC_AVS] = FilterKey(_T("SRC_AVS"), true); +#endif +#if INTERNAL_SOURCEFILTER_DTS + SrcFiltersKeys[SRC_DTS] = FilterKey(_T("SRC_DTS"), true); +#endif +#if INTERNAL_SOURCEFILTER_FLAC + SrcFiltersKeys[SRC_FLAC] = FilterKey(_T("SRC_FLAC"), true); +#endif +#if INTERNAL_SOURCEFILTER_FLIC + SrcFiltersKeys[SRC_FLIC] = FilterKey(_T("SRC_FLIC"), true); +#endif +#if INTERNAL_SOURCEFILTER_FLV + SrcFiltersKeys[SRC_FLV] = FilterKey(_T("SRC_FLV"), true); +#endif +#if INTERNAL_SOURCEFILTER_GIF + SrcFiltersKeys[SRC_GIF] = FilterKey(_T("SRC_GIF"), true); +#endif +#if INTERNAL_SOURCEFILTER_HTTP + SrcFiltersKeys[SRC_HTTP] = FilterKey(_T("SRC_HTTP"), true); +#endif +#if INTERNAL_SOURCEFILTER_MATROSKA + SrcFiltersKeys[SRC_MATROSKA] = FilterKey(_T("SRC_MATROSKA"), true); +#endif +#if INTERNAL_SOURCEFILTER_MISC + SrcFiltersKeys[SRC_MISC] = FilterKey(_T("SRC_MISC"), true); +#endif +#if INTERNAL_SOURCEFILTER_MMS + SrcFiltersKeys[SRC_MMS] = FilterKey(_T("SRC_MMS"), true); +#endif +#if INTERNAL_SOURCEFILTER_MP4 + SrcFiltersKeys[SRC_MP4] = FilterKey(_T("SRC_MP4"), true); +#endif +#if INTERNAL_SOURCEFILTER_MPEGAUDIO + SrcFiltersKeys[SRC_MPA] = FilterKey(_T("SRC_MPA"), true); +#endif +#if INTERNAL_SOURCEFILTER_MPEG + SrcFiltersKeys[SRC_MPEG] = FilterKey(_T("SRC_MPEG"), true); + SrcFiltersKeys[SRC_MPEGTS] = FilterKey(_T("SRC_MPEGTS"), true); +#endif +#if INTERNAL_SOURCEFILTER_OGG + SrcFiltersKeys[SRC_OGG] = FilterKey(_T("SRC_OGG"), true); +#endif +#if INTERNAL_SOURCEFILTER_REALMEDIA + SrcFiltersKeys[SRC_REALMEDIA] = FilterKey(_T("SRC_REALMEDIA"), true); +#endif +#if INTERNAL_SOURCEFILTER_RTMP + SrcFiltersKeys[SRC_RTMP] = FilterKey(_T("SRC_RTMP"), true); +#endif +#if INTERNAL_SOURCEFILTER_RTP + SrcFiltersKeys[SRC_RTP] = FilterKey(_T("SRC_RTP"), true); +#endif +#if INTERNAL_SOURCEFILTER_RTSP + SrcFiltersKeys[SRC_RTSP] = FilterKey(_T("SRC_RTSP"), true); +#endif +#if INTERNAL_SOURCEFILTER_RTSP + SrcFiltersKeys[SRC_UDP] = FilterKey(_T("SRC_UDP"), true); +#endif +#if INTERNAL_SOURCEFILTER_WTV + SrcFiltersKeys[SRC_WTV] = FilterKey(_T("SRC_WTV"), true); +#endif +#if INTERNAL_SOURCEFILTER_CDDA + SrcFiltersKeys[SRC_CDDA] = FilterKey(_T("SRC_CDDA"), true); +#endif +#if INTERNAL_SOURCEFILTER_CDXA + SrcFiltersKeys[SRC_CDXA] = FilterKey(_T("SRC_CDXA"), true); +#endif +#if INTERNAL_SOURCEFILTER_DSM + SrcFiltersKeys[SRC_DSM] = FilterKey(_T("SRC_DSM"), true); +#endif +#if INTERNAL_SOURCEFILTER_RFS + SrcFiltersKeys[SRC_RFS] = FilterKey(_T("SRC_RFS"), true); +#endif +#if INTERNAL_SOURCEFILTER_VTS + SrcFiltersKeys[SRC_VTS] = FilterKey(_T("SRC_VTS"), true); +#endif + + // Internal decoders +#if INTERNAL_DECODER_MPEG1 + TraFiltersKeys[TRA_MPEG1] = FilterKey(_T("TRA_MPEG1"), true); +#endif +#if INTERNAL_DECODER_MPEG2 + TraFiltersKeys[TRA_MPEG2] = FilterKey(_T("TRA_MPEG2"), true); +#endif +#if INTERNAL_DECODER_REALVIDEO + TraFiltersKeys[TRA_RV] = FilterKey(_T("TRA_RV"), true); +#endif +#if INTERNAL_DECODER_REALAUDIO + TraFiltersKeys[TRA_RA] = FilterKey(_T("TRA_RA"), true); +#endif +#if INTERNAL_DECODER_MPEGAUDIO + TraFiltersKeys[TRA_MPA] = FilterKey(_T("TRA_MPA"), true); +#endif +#if INTERNAL_DECODER_DTS + TraFiltersKeys[TRA_DTS] = FilterKey(_T("TRA_DTS"), true); +#endif +#if INTERNAL_DECODER_LPCM + TraFiltersKeys[TRA_LPCM] = FilterKey(_T("TRA_LPCM"), true); +#endif +#if INTERNAL_DECODER_AC3 + TraFiltersKeys[TRA_AC3] = FilterKey(_T("TRA_AC3"), true); +#endif +#if INTERNAL_DECODER_AAC + TraFiltersKeys[TRA_AAC] = FilterKey(_T("TRA_AAC"), true); +#endif +#if INTERNAL_DECODER_ALAC + TraFiltersKeys[TRA_ALAC] = FilterKey(_T("TRA_ALAC"), true); +#endif +#if INTERNAL_DECODER_ALS + TraFiltersKeys[TRA_ALS] = FilterKey(_T("TRA_ALS"), true); +#endif +#if INTERNAL_DECODER_PS2AUDIO + TraFiltersKeys[TRA_PS2AUD] = FilterKey(_T("TRA_PS2AUD"), true); +#endif +#if INTERNAL_DECODER_VORBIS + TraFiltersKeys[TRA_VORBIS] = FilterKey(_T("TRA_VORBIS"), true); +#endif +#if INTERNAL_DECODER_FLAC + TraFiltersKeys[TRA_FLAC] = FilterKey(_T("TRA_FLAC"), true); +#endif +#if INTERNAL_DECODER_NELLYMOSER + TraFiltersKeys[TRA_NELLY] = FilterKey(_T("TRA_NELLY"), true); +#endif +#if INTERNAL_DECODER_AMR + TraFiltersKeys[TRA_AMR] = FilterKey(_T("TRA_AMR"), true); +#endif +#if INTERNAL_DECODER_OPUS + TraFiltersKeys[TRA_OPUS] = FilterKey(_T("TRA_OPUS"), true); +#endif +#if INTERNAL_DECODER_WMA + TraFiltersKeys[TRA_WMA] = FilterKey(_T("TRA_WMA"), false); +#endif +#if INTERNAL_DECODER_WMAPRO + TraFiltersKeys[TRA_WMAPRO] = FilterKey(_T("TRA_WMAPRO"), false); +#endif +#if INTERNAL_DECODER_WMALL + TraFiltersKeys[TRA_WMALL] = FilterKey(_T("TRA_WMALL"), false); +#endif +#if INTERNAL_DECODER_G726 + TraFiltersKeys[TRA_G726] = FilterKey(_T("TRA_G726"), true); +#endif +#if INTERNAL_DECODER_G729 + TraFiltersKeys[TRA_G729] = FilterKey(_T("TRA_G729"), true); +#endif +#if INTERNAL_DECODER_OTHERAUDIO + TraFiltersKeys[TRA_OTHERAUDIO] = FilterKey(_T("TRA_OTHERAUDIO"), true); +#endif +#if INTERNAL_DECODER_PCM + TraFiltersKeys[TRA_PCM] = FilterKey(_T("TRA_PCM"), true); +#endif +#if INTERNAL_DECODER_H264 + TraFiltersKeys[TRA_H264] = FilterKey(_T("TRA_H264"), true); +#endif +#if INTERNAL_DECODER_HEVC + TraFiltersKeys[TRA_HEVC] = FilterKey(_T("TRA_HEVC"), true); +#endif +#if INTERNAL_DECODER_VVC + TraFiltersKeys[TRA_VVC] = FilterKey(_T("TRA_VVC"), true); +#endif +#if INTERNAL_DECODER_AV1 + TraFiltersKeys[TRA_AV1] = FilterKey(_T("TRA_AV1"), true); +#endif +#if INTERNAL_DECODER_VC1 + TraFiltersKeys[TRA_VC1] = FilterKey(_T("TRA_VC1"), true); +#endif +#if INTERNAL_DECODER_FLV + TraFiltersKeys[TRA_FLV4] = FilterKey(_T("TRA_FLV4"), true); +#endif +#if INTERNAL_DECODER_VP356 + TraFiltersKeys[TRA_VP356] = FilterKey(_T("TRA_VP356"), true); +#endif +#if INTERNAL_DECODER_VP8 + TraFiltersKeys[TRA_VP8] = FilterKey(_T("TRA_VP8"), true); +#endif +#if INTERNAL_DECODER_VP9 + TraFiltersKeys[TRA_VP9] = FilterKey(_T("TRA_VP9"), true); +#endif +#if INTERNAL_DECODER_XVID + TraFiltersKeys[TRA_XVID] = FilterKey(_T("TRA_XVID"), true); +#endif +#if INTERNAL_DECODER_DIVX + TraFiltersKeys[TRA_DIVX] = FilterKey(_T("TRA_DIVX"), true); +#endif +#if INTERNAL_DECODER_MSMPEG4 + TraFiltersKeys[TRA_MSMPEG4] = FilterKey(_T("TRA_MSMPEG4"), true); +#endif +#if INTERNAL_DECODER_WMV + TraFiltersKeys[TRA_WMV] = FilterKey(_T("TRA_WMV"), false); +#endif +#if INTERNAL_DECODER_SVQ + TraFiltersKeys[TRA_SVQ3] = FilterKey(_T("TRA_SVQ3"), true); +#endif +#if INTERNAL_DECODER_H263 + TraFiltersKeys[TRA_H263] = FilterKey(_T("TRA_H263"), true); +#endif +#if INTERNAL_DECODER_THEORA + TraFiltersKeys[TRA_THEORA] = FilterKey(_T("TRA_THEORA"), true); +#endif +#if INTERNAL_DECODER_AMVV + TraFiltersKeys[TRA_AMVV] = FilterKey(_T("TRA_AMVV"), true); +#endif +#if INTERNAL_DECODER_MJPEG + TraFiltersKeys[TRA_MJPEG] = FilterKey(_T("TRA_MJPEG"), true); +#endif +#if INTERNAL_DECODER_INDEO + TraFiltersKeys[TRA_INDEO] = FilterKey(_T("TRA_INDEO"), true); +#endif +#if INTERNAL_DECODER_SCREEN + TraFiltersKeys[TRA_SCREEN] = FilterKey(_T("TRA_SCREEN"), true); +#endif +#if INTERNAL_DECODER_FLIC + TraFiltersKeys[TRA_FLIC] = FilterKey(_T("TRA_FLIC"), true); +#endif +#if INTERNAL_DECODER_MSVIDEO + TraFiltersKeys[TRA_MSVIDEO] = FilterKey(_T("TRA_MSVIDEO"), true); +#endif +#if INTERNAL_DECODER_V210_V410 + TraFiltersKeys[TRA_V210_V410] = FilterKey(_T("TRA_V210_V410"), false); +#endif +#if INTERNAL_DECODER_PRORES + TraFiltersKeys[TRA_PRORES] = FilterKey(_T("TRA_PRORES"), true); +#endif +#if INTERNAL_DECODER_DNXHD + TraFiltersKeys[TRA_DNXHD] = FilterKey(_T("TRA_DNXHD"), true); +#endif +#if INTERNAL_DECODER_OTHERVIDEO + TraFiltersKeys[TRA_OTHERVIDEO] = FilterKey(_T("TRA_OTHERVIDEO"), true); +#endif + + ZeroMemory(&DVDPosition, sizeof(DVDPosition)); + + ENSURE(SUCCEEDED(SaneAudioRenderer::Factory::CreateSettings(&sanear))); + + // Mouse + nMouseLeftClick = ID_PLAY_PLAYPAUSE; + nMouseLeftDblClick = ID_VIEW_FULLSCREEN; + nMouseRightClick = ID_MENU_PLAYER_SHORT; + MouseMiddleClick = { 0, 0, 0, 0 }; + MouseX1Click = { ID_NAVIGATE_SKIPBACK, 0, 0, 0 }; + MouseX2Click = { ID_NAVIGATE_SKIPFORWARD, 0, 0, 0 }; + MouseWheelUp = { ID_VOLUME_UP, ID_PLAY_SEEKFORWARDLARGE, 0, ID_PLAY_SEEKFORWARDLARGE }; + MouseWheelDown = { ID_VOLUME_DOWN, ID_PLAY_SEEKBACKWARDLARGE, 0, ID_PLAY_SEEKBACKWARDLARGE }; + MouseWheelLeft = { 0, 0, 0, 0 }; + MouseWheelRight = { 0, 0, 0, 0 }; + bMouseLeftClickOpenRecent = false; + bMouseEasyMove = true; + +} +#pragma warning(pop) + +/* Note: the mouse commands in this list are no longer being used. Mouse binding are now stored elsewhere. + * They are included for backwards compatibility. + */ +static constexpr wmcmd_base default_wmcmds[] = { + { ID_FILE_OPENQUICK, 'Q', FCONTROL, IDS_MPLAYERC_0 }, + { ID_FILE_OPENMEDIA, 'O', FCONTROL, IDS_AG_OPEN_FILE }, + { ID_FILE_OPENDVDBD, 'D', FCONTROL, IDS_AG_OPEN_DVD }, + { ID_FILE_OPENDEVICE, 'V', FCONTROL, IDS_AG_OPEN_DEVICE }, + { ID_FILE_OPENDIRECTORY, 0, 0, IDS_AG_OPENDIRECTORY }, + { ID_FILE_REOPEN, 'E', FCONTROL, IDS_AG_REOPEN }, + { ID_FILE_RECYCLE, VK_DELETE, 0, IDS_FILE_RECYCLE }, + { ID_FILE_SAVE_COPY, 0, 0, IDS_AG_SAVE_COPY }, + { ID_FILE_SAVE_IMAGE, 'I', FALT, IDS_AG_SAVE_IMAGE }, + { ID_FILE_SAVE_IMAGE_AUTO, VK_F5, 0, IDS_MPLAYERC_6 }, + { ID_FILE_SAVE_THUMBNAILS, 0, 0, IDS_FILE_SAVE_THUMBNAILS }, + { ID_FILE_SUBTITLES_LOAD, 'L', FCONTROL, IDS_AG_LOAD_SUBTITLES }, + { ID_FILE_SUBTITLES_SAVE, 'S', FCONTROL, IDS_AG_SAVE_SUBTITLES }, + { ID_FILE_SUBTITLES_DOWNLOAD, 'D', 0, IDS_SUBTITLES_DOWNLOAD }, + { ID_FILE_CLOSE_AND_RESTORE, 'C', FCONTROL, IDS_AG_CLOSE }, + { ID_FILE_PROPERTIES, VK_F10, FSHIFT, IDS_AG_PROPERTIES }, + { ID_FILE_OPEN_LOCATION, VK_F10, FCONTROL | FSHIFT, IDS_AG_OPEN_FILE_LOCATION }, + { ID_FILE_EXIT, 'X', FALT, IDS_AG_EXIT }, + { ID_PLAY_PLAYPAUSE, VK_SPACE, 0, IDS_AG_PLAYPAUSE, APPCOMMAND_MEDIA_PLAY_PAUSE, wmcmd::LUP }, + { ID_PLAY_PLAY, 0, 0, IDS_AG_PLAY, APPCOMMAND_MEDIA_PLAY }, + { ID_PLAY_PAUSE, 0, 0, IDS_AG_PAUSE, APPCOMMAND_MEDIA_PAUSE }, + { ID_PLAY_STOP, VK_OEM_PERIOD, 0, IDS_AG_STOP, APPCOMMAND_MEDIA_STOP }, + { ID_PLAY_FRAMESTEP, VK_RIGHT, FCONTROL, IDS_AG_FRAMESTEP }, + { ID_PLAY_FRAMESTEP_BACK, VK_LEFT, FCONTROL, IDS_MPLAYERC_16 }, + { ID_NAVIGATE_GOTO, 'G', FCONTROL, IDS_AG_GO_TO }, + { ID_PLAY_INCRATE, VK_UP, FCONTROL, IDS_AG_INCREASE_RATE }, + { ID_PLAY_DECRATE, VK_DOWN, FCONTROL, IDS_AG_DECREASE_RATE }, + { ID_PLAY_RESETRATE, 'R', FCONTROL, IDS_AG_RESET_RATE }, + { ID_PLAY_INCAUDDELAY, VK_ADD, 0, IDS_MPLAYERC_21 }, + { ID_PLAY_DECAUDDELAY, VK_SUBTRACT, 0, IDS_MPLAYERC_22 }, + { ID_PLAY_SEEKFORWARDSMALL, 0, 0, IDS_MPLAYERC_23 }, + { ID_PLAY_SEEKBACKWARDSMALL, 0, 0, IDS_MPLAYERC_24 }, + { ID_PLAY_SEEKFORWARDMED, VK_RIGHT, 0, IDS_MPLAYERC_25 }, + { ID_PLAY_SEEKBACKWARDMED, VK_LEFT, 0, IDS_MPLAYERC_26 }, + { ID_PLAY_SEEKFORWARDLARGE, 0, 0, IDS_MPLAYERC_27, 0, wmcmd::WUP, FVIRTKEY | FCONTROL }, + { ID_PLAY_SEEKBACKWARDLARGE, 0, 0, IDS_MPLAYERC_28, 0, wmcmd::WDOWN, FVIRTKEY | FCONTROL }, + { ID_PLAY_SEEKKEYFORWARD, VK_RIGHT, FSHIFT, IDS_MPLAYERC_29 }, + { ID_PLAY_SEEKKEYBACKWARD, VK_LEFT, FSHIFT, IDS_MPLAYERC_30 }, + { ID_PLAY_SEEKSET, VK_HOME, 0, IDS_AG_SEEKSET }, + { ID_PLAY_REPEAT_FOREVER, 0, 0, IDS_PLAYLOOP_FOREVER }, + { ID_PLAY_REPEAT_ONEFILE, 0, 0, IDS_PLAYLOOPMODE_FILE }, + { ID_PLAY_REPEAT_WHOLEPLAYLIST, 0, 0, IDS_PLAYLOOPMODE_PLAYLIST }, + { ID_PLAY_REPEAT_AB, 0, 0, IDS_PLAYLOOPMODE_AB }, + { ID_PLAY_REPEAT_AB_MARK_A, VK_OEM_4, 0, IDS_PLAYLOOPMODE_AB_MARK_A }, + { ID_PLAY_REPEAT_AB_MARK_B, VK_OEM_6, 0, IDS_PLAYLOOPMODE_AB_MARK_B }, + { ID_NAVIGATE_SKIPFORWARD, VK_NEXT, 0, IDS_AG_NEXT, APPCOMMAND_MEDIA_NEXTTRACK, wmcmd::X2DOWN }, + { ID_NAVIGATE_SKIPBACK, VK_PRIOR, 0, IDS_AG_PREVIOUS, APPCOMMAND_MEDIA_PREVIOUSTRACK, wmcmd::X1DOWN }, + { ID_NAVIGATE_SKIPFORWARDFILE, VK_NEXT, FCONTROL, IDS_AG_NEXT_FILE }, + { ID_NAVIGATE_SKIPBACKFILE, VK_PRIOR, FCONTROL, IDS_AG_PREVIOUS_FILE }, + { ID_NAVIGATE_TUNERSCAN, 'T', FSHIFT, IDS_NAVIGATE_TUNERSCAN }, + { ID_FAVORITES_QUICKADDFAVORITE, 'Q', FSHIFT, IDS_FAVORITES_QUICKADDFAVORITE }, + { ID_FAVORITES_ORGANIZE, 0, 0, IDS_FAVORITES_ORGANIZE }, + { ID_VIEW_CAPTIONMENU, '0', FCONTROL, IDS_AG_TOGGLE_CAPTION }, + { ID_VIEW_SEEKER, '1', FCONTROL, IDS_AG_TOGGLE_SEEKER }, + { ID_VIEW_CONTROLS, '2', FCONTROL, IDS_AG_TOGGLE_CONTROLS }, + { ID_VIEW_INFORMATION, '3', FCONTROL, IDS_AG_TOGGLE_INFO }, + { ID_VIEW_STATISTICS, '4', FCONTROL, IDS_AG_TOGGLE_STATS }, + { ID_VIEW_STATUS, '5', FCONTROL, IDS_AG_TOGGLE_STATUS }, + { ID_VIEW_SUBRESYNC, '6', FCONTROL, IDS_AG_TOGGLE_SUBRESYNC }, + { ID_VIEW_PLAYLIST, '7', FCONTROL, IDS_AG_TOGGLE_PLAYLIST }, + { ID_VIEW_CAPTURE, '8', FCONTROL, IDS_AG_TOGGLE_CAPTURE }, + { ID_VIEW_NAVIGATION, '9', FCONTROL, IDS_AG_TOGGLE_NAVIGATION }, + { ID_VIEW_DEBUGSHADERS, 0, 0, IDS_AG_TOGGLE_DEBUGSHADERS }, + { ID_PRESIZE_SHADERS_TOGGLE, 'P', FCONTROL, IDS_PRESIZE_SHADERS_TOGGLE }, + { ID_POSTSIZE_SHADERS_TOGGLE, 'P', FCONTROL | FALT, IDS_POSTSIZE_SHADERS_TOGGLE }, + { ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE, 0, 0, IDS_AG_TOGGLE_DEFAULT_SUBTITLE_STYLE }, + { ID_VIEW_PRESETS_MINIMAL, '1', 0, IDS_AG_VIEW_MINIMAL }, + { ID_VIEW_PRESETS_COMPACT, '2', 0, IDS_AG_VIEW_COMPACT }, + { ID_VIEW_PRESETS_NORMAL, '3', 0, IDS_AG_VIEW_NORMAL }, + { ID_VIEW_FULLSCREEN, VK_RETURN, FALT, IDS_AG_FULLSCREEN, 0, wmcmd::LDBLCLK }, + { ID_VIEW_FULLSCREEN_SECONDARY, VK_F11, 0, IDS_MPLAYERC_39 }, + { ID_VIEW_ZOOM_25, VK_OEM_3, FALT, IDS_AG_ZOOM_25 }, /* VK_OEM_3 is `~ on US keyboards*/ + { ID_VIEW_ZOOM_50, '1', FALT, IDS_AG_ZOOM_50 }, + { ID_VIEW_ZOOM_100, '2', FALT, IDS_AG_ZOOM_100 }, + { ID_VIEW_ZOOM_200, '3', FALT, IDS_AG_ZOOM_200 }, + { ID_VIEW_ZOOM_AUTOFIT, '4', FALT, IDS_AG_ZOOM_AUTO_FIT }, + { ID_VIEW_ZOOM_AUTOFIT_LARGER, '5', FALT, IDS_AG_ZOOM_AUTO_FIT_LARGER }, + { ID_VIEW_ZOOM_ADD, 0, 0, IDS_AG_ZOOM_ADD }, + { ID_VIEW_ZOOM_SUB, 0, 0, IDS_AG_ZOOM_SUB }, + { ID_ASPECTRATIO_NEXT, 0, 0, IDS_AG_NEXT_AR_PRESET }, + { ID_VIEW_VF_HALF, 0, 0, IDS_AG_VIDFRM_HALF }, + { ID_VIEW_VF_NORMAL, 0, 0, IDS_AG_VIDFRM_NORMAL }, + { ID_VIEW_VF_DOUBLE, 0, 0, IDS_AG_VIDFRM_DOUBLE }, + { ID_VIEW_VF_STRETCH, 0, 0, IDS_AG_VIDFRM_STRETCH }, + { ID_VIEW_VF_FROMINSIDE, 0, 0, IDS_AG_VIDFRM_INSIDE }, + { ID_VIEW_VF_ZOOM1, 0, 0, IDS_AG_VIDFRM_ZOOM1 }, + { ID_VIEW_VF_ZOOM2, 0, 0, IDS_AG_VIDFRM_ZOOM2 }, + { ID_VIEW_VF_FROMOUTSIDE, 0, 0, IDS_AG_VIDFRM_OUTSIDE }, + { ID_VIEW_VF_SWITCHZOOM, 0, 0, IDS_AG_VIDFRM_SWITCHZOOM }, + { ID_ONTOP_ALWAYS, 'A', FCONTROL, IDS_AG_ALWAYS_ON_TOP }, + { ID_VIEW_RESET, VK_NUMPAD5, 0, IDS_AG_PNS_RESET }, + { ID_VIEW_INCSIZE, VK_NUMPAD9, 0, IDS_AG_PNS_INC_SIZE }, + { ID_VIEW_INCWIDTH, VK_NUMPAD6, 0, IDS_AG_PNS_INC_WIDTH }, + { ID_VIEW_INCHEIGHT, VK_NUMPAD8, 0, IDS_MPLAYERC_47 }, + { ID_VIEW_DECSIZE, VK_NUMPAD1, 0, IDS_AG_PNS_DEC_SIZE }, + { ID_VIEW_DECWIDTH, VK_NUMPAD4, 0, IDS_AG_PNS_DEC_WIDTH }, + { ID_VIEW_DECHEIGHT, VK_NUMPAD2, 0, IDS_MPLAYERC_50 }, + { ID_PANSCAN_CENTER, VK_NUMPAD5, FCONTROL, IDS_AG_PNS_CENTER }, + { ID_PANSCAN_MOVELEFT, VK_NUMPAD4, FCONTROL, IDS_AG_PNS_LEFT }, + { ID_PANSCAN_MOVERIGHT, VK_NUMPAD6, FCONTROL, IDS_AG_PNS_RIGHT }, + { ID_PANSCAN_MOVEUP, VK_NUMPAD8, FCONTROL, IDS_AG_PNS_UP }, + { ID_PANSCAN_MOVEDOWN, VK_NUMPAD2, FCONTROL, IDS_AG_PNS_DOWN }, + { ID_PANSCAN_MOVEUPLEFT, VK_NUMPAD7, FCONTROL, IDS_AG_PNS_UPLEFT }, + { ID_PANSCAN_MOVEUPRIGHT, VK_NUMPAD9, FCONTROL, IDS_AG_PNS_UPRIGHT }, + { ID_PANSCAN_MOVEDOWNLEFT, VK_NUMPAD1, FCONTROL, IDS_AG_PNS_DOWNLEFT }, + { ID_PANSCAN_MOVEDOWNRIGHT, VK_NUMPAD3, FCONTROL, IDS_MPLAYERC_59 }, + { ID_PANSCAN_ROTATEXP, VK_NUMPAD8, FALT, IDS_AG_PNS_ROTATEX_P }, + { ID_PANSCAN_ROTATEXM, VK_NUMPAD2, FALT, IDS_AG_PNS_ROTATEX_M }, + { ID_PANSCAN_ROTATEYP, VK_NUMPAD4, FALT, IDS_AG_PNS_ROTATEY_P }, + { ID_PANSCAN_ROTATEYM, VK_NUMPAD6, FALT, IDS_AG_PNS_ROTATEY_M }, + { ID_PANSCAN_ROTATEZP, VK_NUMPAD1, FALT, IDS_AG_PNS_ROTATEZ_P }, + { ID_PANSCAN_ROTATEZM, VK_NUMPAD3, FALT, IDS_AG_PNS_ROTATEZ_M }, + { ID_VOLUME_UP, VK_UP, 0, IDS_AG_VOLUME_UP, 0, wmcmd::WUP }, + { ID_VOLUME_DOWN, VK_DOWN, 0, IDS_AG_VOLUME_DOWN, 0, wmcmd::WDOWN }, + { ID_VOLUME_MUTE, 'M', FCONTROL, IDS_AG_VOLUME_MUTE, 0 }, + { ID_VOLUME_BOOST_INC, 0, 0, IDS_VOLUME_BOOST_INC }, + { ID_VOLUME_BOOST_DEC, 0, 0, IDS_VOLUME_BOOST_DEC }, + { ID_VOLUME_BOOST_MIN, 0, 0, IDS_VOLUME_BOOST_MIN }, + { ID_VOLUME_BOOST_MAX, 0, 0, IDS_VOLUME_BOOST_MAX }, + { ID_CUSTOM_CHANNEL_MAPPING, 0, 0, IDS_CUSTOM_CHANNEL_MAPPING }, + { ID_NORMALIZE, 0, 0, IDS_NORMALIZE }, + { ID_REGAIN_VOLUME, 0, 0, IDS_REGAIN_VOLUME }, + { ID_COLOR_BRIGHTNESS_INC, 0, 0, IDS_BRIGHTNESS_INC }, + { ID_COLOR_BRIGHTNESS_DEC, 0, 0, IDS_BRIGHTNESS_DEC }, + { ID_COLOR_CONTRAST_INC, 0, 0, IDS_CONTRAST_INC }, + { ID_COLOR_CONTRAST_DEC, 0, 0, IDS_CONTRAST_DEC }, + { ID_COLOR_HUE_INC, 0, 0, IDS_HUE_INC }, + { ID_COLOR_HUE_DEC, 0, 0, IDS_HUE_DEC }, + { ID_COLOR_SATURATION_INC, 0, 0, IDS_SATURATION_INC }, + { ID_COLOR_SATURATION_DEC, 0, 0, IDS_SATURATION_DEC }, + { ID_COLOR_RESET, 0, 0, IDS_RESET_COLOR }, + { ID_NAVIGATE_TITLEMENU, 'T', FALT, IDS_MPLAYERC_63 }, + { ID_NAVIGATE_ROOTMENU, 'R', FALT, IDS_AG_DVD_ROOT_MENU }, + { ID_NAVIGATE_SUBPICTUREMENU, 0, 0, IDS_MPLAYERC_65 }, + { ID_NAVIGATE_AUDIOMENU, 0, 0, IDS_MPLAYERC_66 }, + { ID_NAVIGATE_ANGLEMENU, 0, 0, IDS_MPLAYERC_67 }, + { ID_NAVIGATE_CHAPTERMENU, 0, 0, IDS_MPLAYERC_68 }, + { ID_NAVIGATE_MENU_LEFT, VK_LEFT, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_LEFT }, + { ID_NAVIGATE_MENU_RIGHT, VK_RIGHT, FCONTROL | FSHIFT, IDS_MPLAYERC_70 }, + { ID_NAVIGATE_MENU_UP, VK_UP, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_UP }, + { ID_NAVIGATE_MENU_DOWN, VK_DOWN, FCONTROL | FSHIFT, IDS_AG_DVD_MENU_DOWN }, + { ID_NAVIGATE_MENU_ACTIVATE, 0, 0, IDS_MPLAYERC_73 }, + { ID_NAVIGATE_MENU_BACK, 0, 0, IDS_AG_DVD_MENU_BACK }, + { ID_NAVIGATE_MENU_LEAVE, 0, 0, IDS_MPLAYERC_75 }, + { ID_BOSS, 'B', 0, IDS_AG_BOSS_KEY }, + { ID_MENU_PLAYER_SHORT, VK_APPS, 0, IDS_MPLAYERC_77, 0, wmcmd::RUP }, + { ID_MENU_PLAYER_LONG, 0, 0, IDS_MPLAYERC_78 }, + { ID_MENU_FILTERS, 0, 0, IDS_AG_FILTERS_MENU }, + { ID_VIEW_OPTIONS, 'O', 0, IDS_AG_OPTIONS }, + { ID_STREAM_AUDIO_NEXT, 'A', 0, IDS_AG_NEXT_AUDIO }, + { ID_STREAM_AUDIO_PREV, 'A', FSHIFT, IDS_AG_PREV_AUDIO }, + { ID_STREAM_SUB_NEXT, 'S', 0, IDS_AG_NEXT_SUBTITLE }, + { ID_STREAM_SUB_PREV, 'S', FSHIFT, IDS_AG_PREV_SUBTITLE }, + { ID_STREAM_SUB_ONOFF, 'W', 0, IDS_MPLAYERC_85 }, + { ID_SUBTITLES_SUBITEM_START + 2, 0, 0, IDS_MPLAYERC_86 }, + { ID_DVD_ANGLE_NEXT, 0, 0, IDS_MPLAYERC_91 }, + { ID_DVD_ANGLE_PREV, 0, 0, IDS_MPLAYERC_92 }, + { ID_DVD_AUDIO_NEXT, 0, 0, IDS_MPLAYERC_93 }, + { ID_DVD_AUDIO_PREV, 0, 0, IDS_MPLAYERC_94 }, + { ID_DVD_SUB_NEXT, 0, 0, IDS_MPLAYERC_95 }, + { ID_DVD_SUB_PREV, 0, 0, IDS_MPLAYERC_96 }, + { ID_DVD_SUB_ONOFF, 0, 0, IDS_MPLAYERC_97 }, + { ID_VIEW_TEARING_TEST, 0, 0, IDS_AG_TEARING_TEST }, + { ID_VIEW_OSD_DISPLAY_TIME, 'I', FCONTROL, IDS_OSD_DISPLAY_CURRENT_TIME }, + { ID_VIEW_OSD_SHOW_FILENAME, 'N', 0, IDS_OSD_SHOW_FILENAME }, + { ID_SHADERS_PRESET_NEXT, 0, 0, IDS_AG_SHADERS_PRESET_NEXT }, + { ID_SHADERS_PRESET_PREV, 0, 0, IDS_AG_SHADERS_PRESET_PREV }, + { ID_D3DFULLSCREEN_TOGGLE, 0, 0, IDS_MPLAYERC_99 }, + { ID_GOTO_PREV_SUB, 'Y', 0, IDS_MPLAYERC_100 }, + { ID_GOTO_NEXT_SUB, 'U', 0, IDS_MPLAYERC_101 }, + { ID_SUBRESYNC_SHIFT_DOWN, VK_NEXT, FALT, IDS_MPLAYERC_102 }, + { ID_SUBRESYNC_SHIFT_UP, VK_PRIOR, FALT, IDS_MPLAYERC_103 }, + { ID_VIEW_DISPLAY_RENDERER_STATS, 'J', FCONTROL, IDS_OSD_DISPLAY_RENDERER_STATS }, + { ID_VIEW_RESET_RENDERER_STATS, 'R', FCONTROL | FALT, IDS_OSD_RESET_RENDERER_STATS }, + { ID_VIEW_VSYNC, 'V', 0, IDS_AG_VSYNC }, + { ID_VIEW_ENABLEFRAMETIMECORRECTION, 0, 0, IDS_AG_ENABLEFRAMETIMECORRECTION }, + { ID_VIEW_VSYNCACCURATE, 'V', FCONTROL | FALT, IDS_AG_VSYNCACCURATE }, + { ID_VIEW_VSYNCOFFSET_DECREASE, VK_UP, FCONTROL | FALT, IDS_AG_VSYNCOFFSET_DECREASE }, + { ID_VIEW_VSYNCOFFSET_INCREASE, VK_DOWN, FCONTROL | FALT, IDS_AG_VSYNCOFFSET_INCREASE }, + { ID_SUB_DELAY_DOWN, VK_F1, 0, IDS_MPLAYERC_104 }, + { ID_SUB_DELAY_UP, VK_F2, 0, IDS_MPLAYERC_105 }, + { ID_SUB_POS_DOWN, VK_SUBTRACT, FCONTROL | FSHIFT, IDS_SUB_POS_DOWN }, + { ID_SUB_POS_UP, VK_ADD, FCONTROL | FSHIFT, IDS_SUB_POS_UP }, + { ID_SUB_FONT_SIZE_DEC, VK_SUBTRACT, FCONTROL, IDS_SUB_FONT_SIZE_DEC }, + { ID_SUB_FONT_SIZE_INC, VK_ADD, FCONTROL, IDS_SUB_FONT_SIZE_INC }, + + { ID_AFTERPLAYBACK_DONOTHING, 0, 0, IDS_AFTERPLAYBACK_DONOTHING }, + { ID_AFTERPLAYBACK_PLAYNEXT, 0, 0, IDS_AFTERPLAYBACK_PLAYNEXT }, + { ID_AFTERPLAYBACK_MONITOROFF, 0, 0, IDS_AFTERPLAYBACK_MONITOROFF }, + { ID_AFTERPLAYBACK_EXIT, 0, 0, IDS_AFTERPLAYBACK_EXIT }, + { ID_AFTERPLAYBACK_STANDBY, 0, 0, IDS_AFTERPLAYBACK_STANDBY }, + { ID_AFTERPLAYBACK_HIBERNATE, 0, 0, IDS_AFTERPLAYBACK_HIBERNATE }, + { ID_AFTERPLAYBACK_SHUTDOWN, 0, 0, IDS_AFTERPLAYBACK_SHUTDOWN }, + { ID_AFTERPLAYBACK_LOGOFF, 0, 0, IDS_AFTERPLAYBACK_LOGOFF }, + { ID_AFTERPLAYBACK_LOCK, 0, 0, IDS_AFTERPLAYBACK_LOCK }, + + { ID_VIEW_EDITLISTEDITOR, 0, 0, IDS_AG_TOGGLE_EDITLISTEDITOR }, + { ID_EDL_IN, 0, 0, IDS_AG_EDL_IN }, + { ID_EDL_OUT, 0, 0, IDS_AG_EDL_OUT }, + { ID_EDL_NEWCLIP, 0, 0, IDS_AG_EDL_NEW_CLIP }, + { ID_EDL_SAVE, 0, 0, IDS_AG_EDL_SAVE }, + + { ID_PLAYLIST_TOGGLE_SHUFFLE, 0, 0, IDS_PLAYLIST_TOGGLE_SHUFFLE }, + { ID_AUDIOSHIFT_ONOFF, 0, 0, IDS_AUDIOSHIFT_ONOFF }, +}; + +void CAppSettings::CreateCommands() +{ + for (const auto& wc : default_wmcmds) { + wmcmd w = wmcmd(wc); + w.fVirt |= FVIRTKEY | FNOINVERT; + CommandIDToWMCMD[wc.cmd] = &wc; + wmcmds.AddTail(w); + } + ASSERT(wmcmds.GetCount() <= ACCEL_LIST_SIZE); +} + +CAppSettings::~CAppSettings() +{ + if (hAccel) { + DestroyAcceleratorTable(hAccel); + } +} + +bool CAppSettings::IsD3DFullscreen() const +{ + if (iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || iDSVideoRendererType == VIDRNDT_DS_SYNC) { + return fD3DFullscreen || (nCLSwitches & CLSW_D3DFULLSCREEN); + } else { + return false; + } +} + +bool CAppSettings::IsISRAutoLoadEnabled() const +{ + return eSubtitleRenderer == SubtitleRenderer::INTERNAL && + IsSubtitleRendererSupported(eSubtitleRenderer, iDSVideoRendererType); +} + +CAppSettings::SubtitleRenderer CAppSettings::GetSubtitleRenderer() const +{ + switch (eSubtitleRenderer) { + case SubtitleRenderer::INTERNAL: + return IsSubtitleRendererSupported(SubtitleRenderer::INTERNAL, iDSVideoRendererType) ? eSubtitleRenderer : SubtitleRenderer::VS_FILTER; + case SubtitleRenderer::XY_SUB_FILTER: + return IsSubtitleRendererSupported(SubtitleRenderer::XY_SUB_FILTER, iDSVideoRendererType) ? eSubtitleRenderer : SubtitleRenderer::VS_FILTER; + default: + return eSubtitleRenderer; + } +} + +bool CAppSettings::IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer) +{ + switch (eSubtitleRenderer) { + case SubtitleRenderer::INTERNAL: + return true; + case SubtitleRenderer::VS_FILTER: + return IsCLSIDRegistered(CLSID_VSFilter); + case SubtitleRenderer::XY_SUB_FILTER: + return IsCLSIDRegistered(CLSID_XySubFilter); + case SubtitleRenderer::NONE: + return true; + default: + ASSERT(FALSE); + return false; + } +} + +bool CAppSettings::IsSubtitleRendererSupported(SubtitleRenderer eSubtitleRenderer, int videoRenderer) +{ + switch (eSubtitleRenderer) { + case SubtitleRenderer::INTERNAL: + switch (videoRenderer) { + case VIDRNDT_DS_VMR9RENDERLESS: + case VIDRNDT_DS_EVR_CUSTOM: + case VIDRNDT_DS_DXR: + case VIDRNDT_DS_SYNC: + case VIDRNDT_DS_MADVR: + case VIDRNDT_DS_MPCVR: + return true; + } + break; + + case SubtitleRenderer::VS_FILTER: + return true; + + case SubtitleRenderer::XY_SUB_FILTER: + switch (videoRenderer) { + case VIDRNDT_DS_VMR9RENDERLESS: + case VIDRNDT_DS_EVR_CUSTOM: + case VIDRNDT_DS_SYNC: + case VIDRNDT_DS_MADVR: + case VIDRNDT_DS_MPCVR: + return true; + } + break; + case SubtitleRenderer::NONE: + return true; + + default: + ASSERT(FALSE); + } + + return false; +} + +bool CAppSettings::IsVideoRendererAvailable(int iVideoRendererType) +{ + switch (iVideoRendererType) { + case VIDRNDT_DS_DXR: + return IsCLSIDRegistered(CLSID_DXR); + case VIDRNDT_DS_EVR: + case VIDRNDT_DS_EVR_CUSTOM: + case VIDRNDT_DS_SYNC: + return IsCLSIDRegistered(CLSID_EnhancedVideoRenderer); + case VIDRNDT_DS_MADVR: + return IsCLSIDRegistered(CLSID_madVR); + case VIDRNDT_DS_MPCVR: + return IsCLSIDRegistered(CLSID_MPCVR) || DSObjects::CMPCVRAllocatorPresenter::HasInternalMPCVRFilter(); +#ifdef _WIN64 + case VIDRNDT_DS_OVERLAYMIXER: + return false; +#endif + default: + return true; + } +} + +bool CAppSettings::IsInitialized() const +{ + return bInitialized; +} + +CString CAppSettings::SelectedAudioRenderer() const +{ + CString strResult; + if (!AfxGetMyApp()->m_AudioRendererDisplayName_CL.IsEmpty()) { + strResult = AfxGetMyApp()->m_AudioRendererDisplayName_CL; + } else { + strResult = AfxGetAppSettings().strAudioRendererDisplayName; + } + + return strResult; +} + +void CAppSettings::ClearRecentFiles() { + MRU.RemoveAll(); + + for (int i = MRUDub.GetSize() - 1; i >= 0; i--) { + MRUDub.Remove(i); + } + MRUDub.WriteList(); + + // Empty the Windows "Recent" jump list + CComPtr pDests; + HRESULT hr = pDests.CoCreateInstance(CLSID_ApplicationDestinations, nullptr, CLSCTX_INPROC_SERVER); + if (SUCCEEDED(hr)) { + pDests->RemoveAllDestinations(); + } +} + +void CAppSettings::SaveSettings(bool write_full_history /* = false */) +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + if (!bInitialized) { + return; + } + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECAPTIONMENU, eCaptionMenuMode); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDENAVIGATION, fHideNavigation); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CONTROLSTATE, nCS); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTVIDEOFRAME, iDefaultVideoSize); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPASPECTRATIO, fKeepAspectRatio); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COMPMONDESKARDIFF, fCompMonDeskARDiff); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUME, nVolume); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BALANCE, nBalance); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUMESTEP, nVolumeStep); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPEEDSTEP, nSpeedStep); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MUTE, fMute); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPNUM, nLoops); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP, fLoopForever); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPMODE, static_cast(eLoopMode)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ZOOM, iZoomLevel); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, fAllowMultipleInst); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTSTYLE, iTitleBarTextStyle); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTTITLE, fTitleBarTextTitle); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ONTOP, iOnTop); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TRAYICON, fTrayIcon); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOZOOM, fRememberZoomLevel); + pApp->WriteProfileStringW(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR, NULL); //remove old form factor + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MIN, nAutoFitFactorMin); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MAX, nAutoFitFactorMax); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AFTER_PLAYBACK, static_cast(eAfterPlayback)); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS, bHideFullscreenControls)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_POLICY, + static_cast(eHideFullscreenControlsPolicy))); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_DELAY, uHideFullscreenControlsDelay)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_DOCKED_PANELS, bHideFullscreenDockedPanels)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_CONTROLS, bHideWindowedControls)); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_MOUSE_POINTER, bHideWindowedMousePointer)); + + // Auto-change fullscreen mode + SaveSettingsAutoChangeFullScreenMode(); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_EXITFULLSCREENATTHEEND, fExitFullScreenAtTheEnd); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWPOS, fRememberWindowPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWSIZE, fRememberWindowSize); + if (fRememberWindowSize || fRememberWindowPos) { + pApp->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_LASTWINDOWRECT, (BYTE*)&rcLastWindowPos, sizeof(rcLastWindowPos)); + } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTWINDOWTYPE, nLastWindowType); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTFULLSCREEN, fLastFullScreen); + + if (fSavePnSZoom) { + CString str; + str.Format(_T("%.3f,%.3f"), dZoomX, dZoomY); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM, str); + } else { + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM, nullptr); + } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPTODESKTOPEDGES, fSnapToDesktopEdges); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_X, sizeAspectRatio.cx); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_Y, sizeAspectRatio.cy); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPHISTORY, fKeepHistory); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RECENT_FILES_NUMBER, iRecentFilesNumber); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, iDSVideoRendererType); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHUFFLEPLAYLISTITEMS, bShufflePlaylistItems); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERPLAYLISTITEMS, bRememberPlaylistItems); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDEPLAYLISTFULLSCREEN, bHidePlaylistFullScreen); + pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERPOS, bFavRememberPos); + pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_RELATIVEDRIVE, bFavRelativeDrive); + pApp->WriteProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERABMARKS, bFavRememberABMarks); + + UpdateRenderersData(true); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUDIORENDERERTYPE, CString(strAudioRendererDisplayName)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOLOADAUDIO, fAutoloadAudio); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER, CString(strSubtitlesLanguageOrder)); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER, CString(strAudiosLanguageOrder)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKVSFILTER, fBlockVSFilter); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKRDP, bBlockRDP); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWORKERTHREADFOROPENING, fEnableWorkerThreadForOpening); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REPORTFAILEDPINS, fReportFailedPins); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_DVDPATH, strDVDPath); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USEDVDPATH, fUseDVDPath); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MENULANG, idMenuLang); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOLANG, idAudioLang); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANG, idSubtitlesLang); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_OPENTYPELANGHINT, CString(strOpenTypeLangHint)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_FREETYPE, bUseFreeType); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_MEDIAINFO_LOAD_FILE_DURATION, bUseMediainfoLoadFileDuration); +#if USE_LIBASS + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSSAUSINGLIBASS, bRenderSSAUsingLibass); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSRTUSINGLIBASS, bRenderSRTUsingLibass); +#endif + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CLOSEDCAPTIONS, fClosedCaptions); + CString style; + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SPSTYLE, style <<= subtitlesDefStyle); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPOVERRIDEPLACEMENT, fOverridePlacement); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPHORPOS, nHorPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPVERPOS, nVerPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLEARCOMPENSATION, bSubtitleARCompensation); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBDELAYINTERVAL, nSubDelayStep); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLESUBTITLES, fEnableSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREFER_FORCED_DEFAULT_SUBTITLES, bPreferDefaultForcedSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITIZEEXTERNALSUBTITLES, fPrioritizeExternalSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLEINTERNALSUBTITLES, fDisableInternalSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_OVERRIDING_EXT_SPLITTER, bAllowOverridingExternalSplitterChoice); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLES, bAutoDownloadSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOSAVEDOWNLOADEDSUBTITLES, bAutoSaveDownloadedSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCOREMOVIES, nAutoDownloadScoreMovies); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCORESERIES, nAutoDownloadScoreSeries); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLESEXCLUDE, strAutoDownloadSubtitlesExclude); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOUPLOADSUBTITLES, bAutoUploadSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREFERHEARINGIMPAIREDSUBTITLES, bPreferHearingImpairedSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MPCTHEME, bMPCTheme); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNSEEKBARHEIGHT, iModernSeekbarHeight); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNTHEMEMODE, static_cast(eModernThemeMode)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_DELAY, iFullscreenDelay); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VERTICALALIGNVIDEO, static_cast(iVerticalAlignVideo)); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESPROVIDERS, strSubtitlesProviders); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLEPATHS, strSubtitlePaths); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_DEFAULT_STYLE, bSubtitleOverrideDefaultStyle); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_ALL_STYLES, bSubtitleOverrideAllStyles); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOSWITCHER, fEnableAudioSwitcher); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOTIMESHIFT, fAudioTimeShift); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOTIMESHIFT, iAudioTimeShift); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DOWNSAMPLETO441, fDownSampleTo441); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CUSTOMCHANNELMAPPING, fCustomChannelMapping); + pApp->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_SPEAKERTOCHANNELMAPPING, (BYTE*)pSpeakerToChannelMap, sizeof(pSpeakerToChannelMap)); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZE, fAudioNormalize); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOMAXNORMFACTOR, nAudioMaxNormFactor); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZERECOVER, fAudioNormalizeRecover); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, nAudioBoost); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPEAKERCHANNELS, nSpeakerChannels); + + // Multi-monitor code + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITOR, CString(strFullScreenMonitorID)); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITORDEVICE, CString(strFullScreenMonitorDeviceName)); + + // Mouse + CStringW str; + str.Format(L"%u", nMouseLeftClick); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT, str); + str.Format(L"%u", nMouseLeftDblClick); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT_DBLCLICK, str); + str.Format(L"%u", nMouseRightClick); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_RIGHT, str); + str.Format(L"%u;%u;%u;%u", MouseMiddleClick.normal, MouseMiddleClick.ctrl, MouseMiddleClick.shift, MouseMiddleClick.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_MIDDLE, str); + str.Format(L"%u;%u;%u;%u", MouseX1Click.normal, MouseX1Click.ctrl, MouseX1Click.shift, MouseX1Click.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X1, str); + str.Format(L"%u;%u;%u;%u", MouseX2Click.normal, MouseX2Click.ctrl, MouseX2Click.shift, MouseX2Click.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X2, str); + str.Format(L"%u;%u;%u;%u", MouseWheelUp.normal, MouseWheelUp.ctrl, MouseWheelUp.shift, MouseWheelUp.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_UP, str); + str.Format(L"%u;%u;%u;%u", MouseWheelDown.normal, MouseWheelDown.ctrl, MouseWheelDown.shift, MouseWheelDown.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_DOWN, str); + str.Format(L"%u;%u;%u;%u", MouseWheelLeft.normal, MouseWheelLeft.ctrl, MouseWheelLeft.shift, MouseWheelLeft.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_LEFT, str); + str.Format(L"%u;%u;%u;%u", MouseWheelRight.normal, MouseWheelRight.ctrl, MouseWheelRight.shift, MouseWheelRight.rbtn); + pApp->WriteProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_RIGHT, str); + + + // Prevent Minimize when in Fullscreen mode on non default monitor + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_MINIMIZE, fPreventMinimize); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENHANCED_TASKBAR, bUseEnhancedTaskBar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEARCH_IN_FOLDER, fUseSearchInFolder); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TIME_TOOLTIP, fUseSeekbarHover); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_TOOLTIP_POSITION, nHoverPosition); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MPC_OSD_SIZE, nOSDSize); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_MPC_OSD_FONT, strOSDFont); + + // Associated types with icon or not... + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ASSOCIATED_WITH_ICON, fAssociatedWithIcons); + // Last Open Dir + //pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_LAST_OPEN_DIR, strLastOpenDir); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_D3DFULLSCREEN, fD3DFullscreen); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_BRIGHTNESS, iBrightness); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_CONTRAST, iContrast); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_HUE, iHue); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_SATURATION, iSaturation); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOWOSD, fShowOSD); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CURRENT_TIME_OSD, fShowCurrentTimeInOSD); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_TRANSPARENCY, nOSDTransparency); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_BORDER, nOSDBorder); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEEDLEDITOR, fEnableEDLEditor); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LANGUAGE, language); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK, bFastSeek); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK_METHOD, eFastSeekMethod); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CHAPTERS, fShowChapters); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, fLCDSupport); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW, fSeekPreview); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW_SIZE, iSeekPreviewSize); + + + // Save analog capture settings + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, iDefaultCaptureDevice); + pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, strAnalogVideo); + pApp->WriteProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, strAnalogAudio); + pApp->WriteProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, iAnalogCountry); + + // Save digital capture settings (BDA) + pApp->WriteProfileString(IDS_R_DVB, nullptr, nullptr); // Ensure the section is cleared before saving the new settings + + //pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER, strBDANetworkProvider); + pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER, strBDATuner); + pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER, strBDAReceiver); + //pApp->WriteProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD, strBDAStandard); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, iBDAScanFreqStart); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, iBDAScanFreqEnd); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, iBDABandwidth); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_SYMBOLRATE, iBDASymbolRate); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_USE_OFFSET, fBDAUseOffset); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_OFFSET, iBDAOffset); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_BDA_IGNORE_ENCRYPTED_CHANNELS, fBDAIgnoreEncryptedChannels); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, nDVBLastChannel); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, nDVBRebuildFilterGraph); + pApp->WriteProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, nDVBStopFilterGraph); + + for (size_t i = 0; i < m_DVBChannels.size(); i++) { + CString numChannel; + numChannel.Format(_T("%Iu"), i); + pApp->WriteProfileString(IDS_R_DVB, numChannel, m_DVBChannels[i].ToString()); + } + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DVDPOS, fRememberDVDPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS, fRememberFilePos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSLONGER, iRememberPosForLongerThan); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSAUDIO, bRememberPosForAudioFiles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_PLAYLIST, bRememberExternalPlaylistPos); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_TRACK_SELECTION, bRememberTrackSelection); + + pApp->WriteProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, nullptr, nullptr); + for (INT_PTR i = 0, j = m_pnspresets.GetCount(); i < j; i++) { + CString str; + str.Format(_T("Preset%Id"), i); + pApp->WriteProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, str, m_pnspresets[i]); + } + + pApp->WriteProfileString(IDS_R_COMMANDS, nullptr, nullptr); + POSITION pos = wmcmds.GetHeadPosition(); + for (int i = 0; pos;) { + const wmcmd& wc = wmcmds.GetNext(pos); + if (wc.IsModified()) { + CString str; + str.Format(_T("CommandMod%d"), i); + // mouse and mouseVirt are written twice for backwards compatibility with old versions + CString str2; + str2.Format(_T("%hu %hx %hx \"%S\" %d %hhu %u %hhu %hhu %hhu"), + wc.cmd, (WORD)wc.fVirt, wc.key, wc.rmcmd.GetString(), + wc.rmrepcnt, wc.mouse, wc.appcmd, wc.mouse, wc.mouseVirt, wc.mouseVirt); + pApp->WriteProfileString(IDS_R_COMMANDS, str, str2); + i++; + } + } + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WINLIRC, fWinLirc); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WINLIRCADDR, strWinLircAddr); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UICE, fUIce); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_UICEADDR, strUIceAddr); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GLOBALMEDIA, fGlobalMedia); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTS, nJumpDistS); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTM, nJumpDistM); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTL, nJumpDistL); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LIMITWINDOWPROPORTIONS, fLimitWindowProportions); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LASTUSEDPAGE, nLastUsedPage); + + m_Formats.UpdateData(true); + + // Internal filters + for (int f = 0; f < SRC_LAST; f++) { + pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, SrcFiltersKeys[f].name, SrcFilters[f]); + } + for (int f = 0; f < TRA_LAST; f++) { + pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, TraFiltersKeys[f].name, TraFilters[f]); + } + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_LOGOFILE, strLogoFileName); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOID, nLogoId); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOEXT, fLogoExternal); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOCOLORPROFILE, fLogoColorProfileEnabled); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECDROMSSUBMENU, fHideCDROMsSubMenu); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITY, dwPriority); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LAUNCHFULLSCREEN, fLaunchfullscreen); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWEBSERVER, fEnableWebServer); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPORT, nWebServerPort); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERUSECOMPRESSION, fWebServerUseCompression); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERLOCALHOSTONLY, fWebServerLocalhostOnly); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBUI_ENABLE_PREVIEW, bWebUIEnablePreview); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPRINTDEBUGINFO, fWebServerPrintDebugInfo); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBROOT, strWebRoot); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBDEFINDEX, strWebDefIndex); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_WEBSERVERCGI, strWebServerCGI); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTPATH, strSnapshotPath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTEXT, strSnapshotExt); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTSUBTITLES, bSnapShotSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTKEEPVIDEOEXTENSION, bSnapShotKeepVideoExtension); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBROWS, iThumbRows); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBCOLS, iThumbCols); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBWIDTH, iThumbWidth); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBSAVEEXTERNALSTYLEFILE, bSubSaveExternalStyleFile)); + { + // Save the list of extra (non-default) shader files + VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_EXTRA, m_ShadersExtraList.ToString())); + // Save shader selection + CString strPre, strPost; + m_Shaders.GetCurrentPreset().ToStrings(strPre, strPost); + VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_PRERESIZE, strPre)); + VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_POSTRESIZE, strPost)); + // Save shader presets + int i = 0; + CString iStr; + pApp->WriteProfileString(IDS_R_SHADER_PRESETS, nullptr, nullptr); + for (const auto& pair : m_Shaders.GetPresets()) { + iStr.Format(_T("%d"), i++); + pair.second.ToStrings(strPre, strPost); + VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, iStr, pair.first)); + VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_PRERESIZE + iStr, strPre)); + VERIFY(pApp->WriteProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_POSTRESIZE + iStr, strPost)); + } + // Save selected preset name + CString name; + m_Shaders.GetCurrentPresetName(name); + VERIFY(pApp->WriteProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_LASTPRESET, name)); + } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADER, bToggleShader); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADERSSCREENSPACE, bToggleShaderScreenSpace); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REMAINING_TIME, fRemainingTime); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_HIGH_PRECISION_TIMER, bHighPrecisionTimer); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIMER_SHOW_PERCENTAGE, bTimerShowPercentage); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_AUTO_CHECK, nUpdaterAutoCheck); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_DELAY, nUpdaterDelay); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_NOTIFY_SKYPE, bNotifySkype); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_JPEG_QUALITY, nJpegQuality); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART, bEnableCoverArt); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART_SIZE_LIMIT, nCoverArtSizeLimit); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOGGING, bEnableLogging); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_LEGACY_TOOLBAR, bUseLegacyToolbar); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, + static_cast(eSubtitleRenderer))); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTTOOLBARSIZE, nDefaultToolbarSize); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_POSITION, bSaveImagePosition); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_CURRENTTIME, bSaveImageCurrentTime); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_INACCURATE_FASTSEEK, bAllowInaccurateFastseek); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP_FOLDER_NEXT_FILE, bLoopFolderOnPlayNextFile); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_LOCK_NOPAUSE, bLockNoPause); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_DISPLAY_SLEEP, bPreventDisplaySleep); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_SMTC, bUseSMTC); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RELOAD_AFTER_LONG_PAUSE, iReloadAfterLongPause); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_OPEN_REC_PANEL_WHEN_OPENING_DEVICE, bOpenRecPanelWhenOpeningDevice); + + { + CComHeapPtr pDeviceId; + BOOL bExclusive; + UINT32 uBufferDuration; + if (SUCCEEDED(sanear->GetOutputDevice(&pDeviceId, &bExclusive, &uBufferDuration))) { + pApp->WriteProfileString(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_ID, pDeviceId); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_EXCLUSIVE, bExclusive); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_BUFFER, uBufferDuration); + } + + BOOL bCrossfeedEnabled = sanear->GetCrossfeedEnabled(); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_ENABLED, bCrossfeedEnabled); + + UINT32 uCutoffFrequency, uCrossfeedLevel; + sanear->GetCrossfeedSettings(&uCutoffFrequency, &uCrossfeedLevel); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ, uCutoffFrequency); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, uCrossfeedLevel); + + BOOL bIgnoreSystemChannelMixer = sanear->GetIgnoreSystemChannelMixer(); + pApp->WriteProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_IGNORE_SYSTEM_MIXER, bIgnoreSystemChannelMixer); + } + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_YDL, bUseYDL); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, iYDLMaxHeight); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_VIDEO_FORMAT, iYDLVideoFormat); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_FORMAT, iYDLAudioFormat); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, bYDLAudioOnly); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_EXEPATH, sYDLExePath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_COMMAND_LINE, sYDLCommandLine); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLE_CRASH_REPORTER, bEnableCrashReporter); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_REFRESH_INTERVAL, nStreamPosPollerInterval); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_LANG_STATUSBAR, bShowLangInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_FPS_STATUSBAR, bShowFPSInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_ABMARKS_STATUSBAR, bShowABMarksInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_VIDEOINFO_STATUSBAR, bShowVideoInfoInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_AUDIOFORMAT_STATUSBAR, bShowAudioFormatInStatusbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ADD_LANGCODE_WHEN_SAVE_SUBTITLES, bAddLangCodeWhenSaveSubtitles); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TITLE_IN_RECENT_FILE_LIST, bUseTitleInRecentFileList); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_YDL_SUBS_PREFERENCE, sYDLSubsPreference); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_USE_AUTOMATIC_CAPTIONS, bUseAutomaticCaptions); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_QUICKOPEN_PATH, lastQuickOpenPath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_FILESAVECOPY_PATH, lastFileSaveCopyPath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_LAST_FILEOPENDIR_PATH, lastFileOpenDirPath); + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_EXTERNAL_PLAYLIST_PATH, externalPlayListPath); + + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_REDIRECT_OPEN_TO_APPEND_THRESHOLD, iRedirectOpenToAppendThreshold); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_SEPARATE_CONTROLS, bFullscreenSeparateControls); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALWAYS_USE_SHORT_MENU, bAlwaysUseShortMenu); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_STILL_VIDEO_DURATION, iStillVideoDuration); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_MOUSE_LEFTUP_DELAY, iMouseLeftUpDelay); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CAPTURE_DEINTERLACE, bCaptureDeinterlace); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_PAUSE_WHILE_DRAGGING_SEEKBAR, bPauseWhileDraggingSeekbar); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CONFIRM_FILE_DELETE, bConfirmFileDelete); + + if (fKeepHistory && write_full_history) { + MRU.SaveMediaHistory(); + } + + pApp->FlushProfile(); +} + +void CAppSettings::PurgeMediaHistory(size_t maxsize) { + CStringW section = L"MediaHistory"; + auto timeToHash = LoadHistoryHashes(section, L"LastUpdated"); + size_t entries = timeToHash.size(); + if (entries > maxsize) { + for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { + if (entries > maxsize) { + PurgeExpiredHash(section, iter->second); + entries--; + } else { + break; + } + } + } +} + +void CAppSettings::PurgePlaylistHistory(size_t maxsize) { + CStringW section = L"PlaylistHistory"; + auto timeToHash = LoadHistoryHashes(section, L"LastUpdated"); + size_t entries = timeToHash.size(); + if (entries > maxsize) { + for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { + if (entries > maxsize) { + PurgeExpiredHash(section, iter->second); + entries--; + } else { + break; + } + } + } +} + +std::multimap CAppSettings::LoadHistoryHashes(CStringW section, CStringW dateField) { + auto pApp = AfxGetMyApp(); + auto hashes = pApp->GetSectionSubKeys(section); + + std::multimap timeToHash; + for (auto const& hash : hashes) { + CStringW lastOpened, subSection; + subSection.Format(L"%s\\%s", section, static_cast(hash)); + lastOpened = pApp->GetProfileStringW(subSection, dateField, L"0000-00-00T00:00:00.0Z"); + if (!lastOpened.IsEmpty()) { + timeToHash.insert(std::pair(lastOpened, hash)); + } + } + return timeToHash; +} + +void CAppSettings::PurgeExpiredHash(CStringW section, CStringW hash) { + auto pApp = AfxGetMyApp(); + CStringW subSection; + subSection.Format(L"%s\\%s", section, static_cast(hash)); + pApp->WriteProfileString(subSection, nullptr, nullptr); +} + +void CAppSettings::LoadExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey /*= IDS_R_EXTERNAL_FILTERS*/) +{ + CWinApp* pApp = AfxGetApp(); + ASSERT(pApp); + + for (unsigned int i = 0; ; i++) { + CString key; + key.Format(_T("%s\\%04u"), baseKey, i); + + CAutoPtr f(DEBUG_NEW FilterOverride); + + f->fDisabled = !pApp->GetProfileInt(key, _T("Enabled"), FALSE); + + UINT j = pApp->GetProfileInt(key, _T("SourceType"), -1); + if (j == 0) { + f->type = FilterOverride::REGISTERED; + f->dispname = CStringW(pApp->GetProfileString(key, _T("DisplayName"))); + f->name = pApp->GetProfileString(key, _T("Name")); + CString clsid_str = pApp->GetProfileString(key, _T("CLSID")); + if (clsid_str.IsEmpty() && f->dispname.GetLength() == 88 && f->dispname.Left(1) == L"@") { + clsid_str = f->dispname.Right(38); + } + if (clsid_str.GetLength() == 38) { + f->clsid = GUIDFromCString(clsid_str); + } + } else if (j == 1) { + f->type = FilterOverride::EXTERNAL; + f->path = pApp->GetProfileString(key, _T("Path")); + f->name = pApp->GetProfileString(key, _T("Name")); + f->clsid = GUIDFromCString(pApp->GetProfileString(key, _T("CLSID"))); + } else { + pApp->WriteProfileString(key, nullptr, 0); + break; + } + + if (IgnoreExternalFilter(f->clsid)) { + continue; + } + + f->backup.RemoveAll(); + for (unsigned int k = 0; ; k++) { + CString val; + val.Format(_T("org%04u"), k); + CString guid = pApp->GetProfileString(key, val); + if (guid.IsEmpty()) { + break; + } + f->backup.AddTail(GUIDFromCString(guid)); + } + + f->guids.RemoveAll(); + for (unsigned int k = 0; ; k++) { + CString val; + val.Format(_T("mod%04u"), k); + CString guid = pApp->GetProfileString(key, val); + if (guid.IsEmpty()) { + break; + } + f->guids.AddTail(GUIDFromCString(guid)); + } + + f->iLoadType = (int)pApp->GetProfileInt(key, _T("LoadType"), -1); + if (f->iLoadType < 0) { + break; + } + + f->dwMerit = pApp->GetProfileInt(key, _T("Merit"), MERIT_DO_NOT_USE + 1); + + filters.AddTail(f); + } +} + +void CAppSettings::SaveExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey /*= IDS_R_EXTERNAL_FILTERS*/) +{ + // Saving External Filter settings takes a long time. Use only when really necessary. + CWinApp* pApp = AfxGetApp(); + ASSERT(pApp); + + // Remove the old keys + for (unsigned int i = 0; ; i++) { + CString key; + key.Format(_T("%s\\%04u"), baseKey, i); + int j = pApp->GetProfileInt(key, _T("Enabled"), -1); + pApp->WriteProfileString(key, nullptr, nullptr); + if (j < 0) { + break; + } + } + + unsigned int k = 0; + POSITION pos = filters.GetHeadPosition(); + while (pos) { + FilterOverride* f = filters.GetNext(pos); + + if (f->fTemporary) { + continue; + } + + CString key; + key.Format(_T("%s\\%04u"), baseKey, k); + + pApp->WriteProfileInt(key, _T("SourceType"), (int)f->type); + pApp->WriteProfileInt(key, _T("Enabled"), (int)!f->fDisabled); + pApp->WriteProfileString(key, _T("Name"), f->name); + pApp->WriteProfileString(key, _T("CLSID"), CStringFromGUID(f->clsid)); + if (f->type == FilterOverride::REGISTERED) { + pApp->WriteProfileString(key, _T("DisplayName"), CString(f->dispname)); + } else if (f->type == FilterOverride::EXTERNAL) { + pApp->WriteProfileString(key, _T("Path"), f->path); + } + POSITION pos2 = f->backup.GetHeadPosition(); + for (unsigned int i = 0; pos2; i++) { + CString val; + val.Format(_T("org%04u"), i); + pApp->WriteProfileString(key, val, CStringFromGUID(f->backup.GetNext(pos2))); + } + pos2 = f->guids.GetHeadPosition(); + for (unsigned int i = 0; pos2; i++) { + CString val; + val.Format(_T("mod%04u"), i); + pApp->WriteProfileString(key, val, CStringFromGUID(f->guids.GetNext(pos2))); + } + pApp->WriteProfileInt(key, _T("LoadType"), f->iLoadType); + pApp->WriteProfileInt(key, _T("Merit"), f->dwMerit); + + k++; + } +} + +void CAppSettings::SaveSettingsAutoChangeFullScreenMode() +{ + auto pApp = AfxGetMyApp(); + ASSERT(pApp); + + // Ensure the section is cleared before saving the new settings + for (size_t i = 0;; i++) { + CString section; + section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); + + // WriteProfileString doesn't return false when INI is used and the section doesn't exist + // so instead check for the a value inside that section + if (!pApp->HasProfileEntry(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED)) { + break; + } else { + VERIFY(pApp->WriteProfileString(section, nullptr, nullptr)); + } + } + pApp->WriteProfileString(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, nullptr, nullptr); + + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_ENABLE, autoChangeFSMode.bEnabled)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_APPLYDEFMODEATFSEXIT, autoChangeFSMode.bApplyDefaultModeAtFSExit)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_RESTORERESAFTEREXIT, autoChangeFSMode.bRestoreResAfterProgExit)); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_DELAY, (int)autoChangeFSMode.uDelay)); + + for (size_t i = 0; i < autoChangeFSMode.modes.size(); i++) { + const auto& mode = autoChangeFSMode.modes[i]; + CString section; + section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); + + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED, mode.bChecked)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTART, std::lround(mode.dFrameRateStart * 1000000))); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTOP, std::lround(mode.dFrameRateStop * 1000000))); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_AUDIODELAY, mode.msAudioDelay)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_BPP, mode.dm.bpp)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FREQ, mode.dm.freq)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEX, mode.dm.size.cx)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEY, mode.dm.size.cy)); + VERIFY(pApp->WriteProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FLAGS, (int)mode.dm.dwDisplayFlags)); + } +} + +void CAppSettings::LoadSettings() +{ + CWinApp* pApp = AfxGetApp(); + ASSERT(pApp); + + UINT len; + BYTE* ptr = nullptr; + + if (bInitialized) { + return; + } + + // Set interface language first! + language = (LANGID)pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LANGUAGE, -1); + if (language == LANGID(-1)) { + language = Translations::SetDefaultLanguage(); + } else if (language != 0) { + if (language <= 23) { + // We must be updating from a really old version, use the default language + language = Translations::SetDefaultLanguage(); + } else if (!Translations::SetLanguage(language, false)) { + // In case of error, reset the language to English + language = 0; + } + } + + CreateCommands(); + + eCaptionMenuMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECAPTIONMENU, MODE_SHOWCAPTIONMENU)); + fHideNavigation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDENAVIGATION, FALSE); + nCS = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CONTROLSTATE, CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR); + iDefaultVideoSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTVIDEOFRAME, DVS_FROMINSIDE); + fKeepAspectRatio = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPASPECTRATIO, TRUE); + fCompMonDeskARDiff = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COMPMONDESKARDIFF, FALSE); + nVolume = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUME, 100); + nBalance = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BALANCE, 0); + fMute = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MUTE, FALSE); + nLoops = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPNUM, 1); + fLoopForever = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP, FALSE); + eLoopMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOPMODE, static_cast(LoopMode::PLAYLIST))); + iZoomLevel = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ZOOM, 1); + iDSVideoRendererType = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, + IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS); + nVolumeStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VOLUMESTEP, 5); + nSpeedStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPEEDSTEP, 0); + if (nSpeedStep > 75) { + nSpeedStep = 75; + } + + UpdateRenderersData(false); + + strAudioRendererDisplayName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIORENDERERTYPE); + fAutoloadAudio = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOLOADAUDIO, TRUE); + strSubtitlesLanguageOrder = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER); + strAudiosLanguageOrder = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER); + fBlockVSFilter = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKVSFILTER, TRUE); + bBlockRDP = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_BLOCKRDP, FALSE); + fEnableWorkerThreadForOpening = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWORKERTHREADFOROPENING, TRUE); + fReportFailedPins = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REPORTFAILEDPINS, TRUE); + fAllowMultipleInst = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, FALSE); + iTitleBarTextStyle = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTSTYLE, 1); + fTitleBarTextTitle = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TITLEBARTEXTTITLE, FALSE); + iOnTop = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ONTOP, 0); + fTrayIcon = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TRAYICON, FALSE); + fRememberZoomLevel = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOZOOM, TRUE); + int tAutoFitFactor = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR, 0); //if found, old fit factor will be default for min/max + nAutoFitFactorMin = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MIN, tAutoFitFactor ? tAutoFitFactor : DEF_MIN_AUTOFIT_SCALE_FACTOR); //otherwise default min to DEF_MIN_AUTOFIT_SCALE_FACTOR + nAutoFitFactorMax = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOFITFACTOR_MAX, tAutoFitFactor ? tAutoFitFactor : DEF_MAX_AUTOFIT_SCALE_FACTOR); //otherwise default max to DEF_MAX_AUTOFIT_SCALE_FACTOR + nAutoFitFactorMin = std::max(std::min(nAutoFitFactorMin, nAutoFitFactorMax), MIN_AUTOFIT_SCALE_FACTOR); + nAutoFitFactorMax = std::min(std::max(nAutoFitFactorMin, nAutoFitFactorMax), MAX_AUTOFIT_SCALE_FACTOR); + + eAfterPlayback = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AFTER_PLAYBACK, 0)); + + bHideFullscreenControls = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS, TRUE); + eHideFullscreenControlsPolicy = + static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_POLICY, 1)); + uHideFullscreenControlsDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_CONTROLS_DELAY, 0); + bHideFullscreenDockedPanels = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_FULLSCREEN_DOCKED_PANELS, TRUE); + bHideWindowedControls = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_CONTROLS, FALSE); + + bHideWindowedMousePointer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDE_WINDOWED_MOUSE_POINTER, TRUE); + + // Multi-monitor code + strFullScreenMonitorID = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITOR); + strFullScreenMonitorDeviceName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_FULLSCREENMONITORDEVICE); + + // Mouse + CStringW str; + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT); + swscanf_s(str, L"%u", &nMouseLeftClick); + if (nMouseLeftClick != 0 && nMouseLeftClick != ID_PLAY_PLAYPAUSE && nMouseLeftClick != ID_VIEW_FULLSCREEN) { + nMouseLeftClick = ID_PLAY_PLAYPAUSE; + } + + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_LEFT_DBLCLICK); + swscanf_s(str, L"%u", &nMouseLeftDblClick); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_RIGHT); + swscanf_s(str, L"%u", &nMouseRightClick); + + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_MIDDLE); + swscanf_s(str, L"%u;%u;%u;%u", &MouseMiddleClick.normal, &MouseMiddleClick.ctrl, &MouseMiddleClick.shift, &MouseMiddleClick.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X1); + swscanf_s(str, L"%u;%u;%u;%u", &MouseX1Click.normal, &MouseX1Click.ctrl, &MouseX1Click.shift, &MouseX1Click.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_BTN_X2); + swscanf_s(str, L"%u;%u;%u;%u", &MouseX2Click.normal, &MouseX2Click.ctrl, &MouseX2Click.shift, &MouseX2Click.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_UP); + swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelUp.normal, &MouseWheelUp.ctrl, &MouseWheelUp.shift, &MouseWheelUp.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_DOWN); + swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelDown.normal, &MouseWheelDown.ctrl, &MouseWheelDown.shift, &MouseWheelDown.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_LEFT); + swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelLeft.normal, &MouseWheelLeft.ctrl, &MouseWheelLeft.shift, &MouseWheelLeft.rbtn); + str = pApp->GetProfileString(IDS_R_MOUSE, IDS_RS_MOUSE_WHEEL_RIGHT); + swscanf_s(str, L"%u;%u;%u;%u", &MouseWheelRight.normal, &MouseWheelRight.ctrl, &MouseWheelRight.shift, &MouseWheelRight.rbtn); + + + // Prevent Minimize when in fullscreen mode on non default monitor + fPreventMinimize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_MINIMIZE, FALSE); + bUseEnhancedTaskBar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENHANCED_TASKBAR, TRUE); + fUseSearchInFolder = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEARCH_IN_FOLDER, TRUE); + fUseSeekbarHover = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TIME_TOOLTIP, TRUE); + nHoverPosition = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_TOOLTIP_POSITION, TIME_TOOLTIP_ABOVE_SEEKBAR); + nOSDSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MPC_OSD_SIZE, 18); + LOGFONT lf; + GetMessageFont(&lf); + strOSDFont = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_MPC_OSD_FONT, lf.lfFaceName); + if (strOSDFont.IsEmpty() || strOSDFont.GetLength() >= LF_FACESIZE) { + strOSDFont = lf.lfFaceName; + } + + // Associated types with icon or not... + fAssociatedWithIcons = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASSOCIATED_WITH_ICON, TRUE); + // Last Open Dir + //strLastOpenDir = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_LAST_OPEN_DIR, _T("C:\\")); + + fAudioTimeShift = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOTIMESHIFT, FALSE); + iAudioTimeShift = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOTIMESHIFT, 0); + + // Auto-change fullscreen mode + autoChangeFSMode.bEnabled = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_ENABLE, FALSE); + autoChangeFSMode.bApplyDefaultModeAtFSExit = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_APPLYDEFMODEATFSEXIT, FALSE); + autoChangeFSMode.bRestoreResAfterProgExit = !!pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_RESTORERESAFTEREXIT, TRUE); + autoChangeFSMode.uDelay = pApp->GetProfileInt(IDS_R_SETTINGS_FULLSCREEN_AUTOCHANGE_MODE, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_DELAY, 0); + + autoChangeFSMode.modes.clear(); + for (size_t i = 0;; i++) { + CString section; + section.Format(IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE, i); + + int iChecked = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_CHECKED, INT_ERROR); + if (iChecked == INT_ERROR) { + break; + } + + double dFrameRateStart = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTART, 0) / 1000000.0; + double dFrameRateStop = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_FRAMERATESTOP, 0) / 1000000.0; + int msAudioDelay = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_AUDIODELAY, fAudioTimeShift ? iAudioTimeShift : 0); + DisplayMode dm; + dm.bValid = true; + dm.bpp = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_BPP, 0); + dm.freq = (int)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FREQ, 0); + dm.size.cx = (LONG)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEX, 0); + dm.size.cy = (LONG)pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_SIZEY, 0); + dm.dwDisplayFlags = pApp->GetProfileInt(section, IDS_RS_FULLSCREEN_AUTOCHANGE_MODE_MODE_DM_FLAGS, 0); + + autoChangeFSMode.modes.emplace_back(!!iChecked, dFrameRateStart, dFrameRateStop, msAudioDelay, std::move(dm)); + } + + fExitFullScreenAtTheEnd = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_EXITFULLSCREENATTHEEND, TRUE); + + fRememberWindowPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWPOS, FALSE); + fRememberWindowSize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERWINDOWSIZE, FALSE); + str = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_PANSCANZOOM); + if (_stscanf_s(str, _T("%lf,%lf"), &dZoomX, &dZoomY) == 2 && + dZoomX >= 0.196 && dZoomX <= 5.0 && + dZoomY >= 0.196 && dZoomY <= 5.0) { + fSavePnSZoom = true; + } else { + fSavePnSZoom = false; + dZoomX = 1.0; + dZoomY = 1.0; + } + fSnapToDesktopEdges = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPTODESKTOPEDGES, FALSE); + sizeAspectRatio.cx = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_X, 0); + sizeAspectRatio.cy = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ASPECTRATIO_Y, 0); + + fKeepHistory = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_KEEPHISTORY, TRUE); + fileAssoc.SetNoRecentDocs(!fKeepHistory); + iRecentFilesNumber = std::max(0, (int)pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RECENT_FILES_NUMBER, 100)); + MRU.SetSize(iRecentFilesNumber); + + if (pApp->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_LASTWINDOWRECT, &ptr, &len)) { + if (len == sizeof(CRect)) { + memcpy(&rcLastWindowPos, ptr, sizeof(CRect)); + if (rcLastWindowPos.Width() < 250 || rcLastWindowPos.Height() < 80) { + rcLastWindowPos = CRect(100, 100, 500, 400); + } + } + delete[] ptr; + } + nLastWindowType = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTWINDOWTYPE, SIZE_RESTORED); + fLastFullScreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTFULLSCREEN, FALSE); + + bShufflePlaylistItems = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHUFFLEPLAYLISTITEMS, FALSE); + bRememberPlaylistItems = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMEMBERPLAYLISTITEMS, TRUE); + bHidePlaylistFullScreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDEPLAYLISTFULLSCREEN, FALSE); + bFavRememberPos = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERPOS, TRUE); + bFavRelativeDrive = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_RELATIVEDRIVE, FALSE); + bFavRememberABMarks = !!pApp->GetProfileInt(IDS_R_FAVORITES, IDS_RS_FAV_REMEMBERABMARKS, FALSE); + + strDVDPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_DVDPATH); + fUseDVDPath = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USEDVDPATH, FALSE); + idMenuLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MENULANG, 0); + idAudioLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOLANG, 0); + idSubtitlesLang = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANG, 0); +#if USE_LIBASS + bRenderSSAUsingLibass = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSSAUSINGLIBASS, FALSE); + bRenderSRTUsingLibass = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDERSRTUSINGLIBASS, FALSE); +#endif + CT2A tmpLangHint(pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_OPENTYPELANGHINT, _T(""))); + strOpenTypeLangHint = tmpLangHint; + bUseFreeType = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_FREETYPE, FALSE); + bUseMediainfoLoadFileDuration = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_MEDIAINFO_LOAD_FILE_DURATION, FALSE); + bCaptureDeinterlace = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CAPTURE_DEINTERLACE, FALSE); + bPauseWhileDraggingSeekbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PAUSE_WHILE_DRAGGING_SEEKBAR, TRUE); + bConfirmFileDelete = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CONFIRM_FILE_DELETE, TRUE); + + fClosedCaptions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CLOSEDCAPTIONS, FALSE); + { + CString temp = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SPSTYLE); + subtitlesDefStyle <<= temp; + if (temp.IsEmpty()) { // Position the text subtitles relative to the video frame by default + subtitlesDefStyle.relativeTo = STSStyle::AUTO; + } + } + fOverridePlacement = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPOVERRIDEPLACEMENT, FALSE); + nHorPos = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPHORPOS, 50); + nVerPos = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPVERPOS, 90); + bSubtitleARCompensation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLEARCOMPENSATION, TRUE); + nSubDelayStep = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBDELAYINTERVAL, 500); + if (nSubDelayStep < 10) { + nSubDelayStep = 500; + } + + fEnableSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLESUBTITLES, TRUE); + bPreferDefaultForcedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREFER_FORCED_DEFAULT_SUBTITLES, TRUE); + fPrioritizeExternalSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITIZEEXTERNALSUBTITLES, TRUE); + fDisableInternalSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLEINTERNALSUBTITLES, FALSE); + bAllowOverridingExternalSplitterChoice = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_OVERRIDING_EXT_SPLITTER, FALSE); + bAutoDownloadSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLES, FALSE); + bAutoSaveDownloadedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOSAVEDOWNLOADEDSUBTITLES, FALSE); + nAutoDownloadScoreMovies = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCOREMOVIES, 0x16); + nAutoDownloadScoreSeries = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSCORESERIES, 0x18); + strAutoDownloadSubtitlesExclude = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUTODOWNLOADSUBTITLESEXCLUDE); + bAutoUploadSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUTOUPLOADSUBTITLES, FALSE); + bPreferHearingImpairedSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREFERHEARINGIMPAIREDSUBTITLES, FALSE); + bMPCTheme = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MPCTHEME, TRUE); + if (IsWindows10OrGreater()) { + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"), KEY_READ)) { + DWORD useTheme = (DWORD)-1; + if (ERROR_SUCCESS == key.QueryDWORDValue(_T("AppsUseLightTheme"), useTheme)) { + if (0 == useTheme) { + bWindows10DarkThemeActive = true; + } + } + } + if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\DWM"), KEY_READ)) { + DWORD useColorPrevalence = (DWORD)-1; + if (ERROR_SUCCESS == key.QueryDWORDValue(_T("ColorPrevalence"), useColorPrevalence)) { + if (1 == useColorPrevalence) { + bWindows10AccentColorsEnabled = true; + } + } + } + } + iModernSeekbarHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNSEEKBARHEIGHT, DEF_MODERN_SEEKBAR_HEIGHT); + if (iModernSeekbarHeight < MIN_MODERN_SEEKBAR_HEIGHT || iModernSeekbarHeight > MAX_MODERN_SEEKBAR_HEIGHT) { + iModernSeekbarHeight = DEF_MODERN_SEEKBAR_HEIGHT; + } + + eModernThemeMode = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MODERNTHEMEMODE, static_cast(CMPCTheme::ModernThemeMode::WINDOWSDEFAULT))); + + iFullscreenDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_DELAY, MIN_FULLSCREEN_DELAY); + if (iFullscreenDelay < MIN_FULLSCREEN_DELAY || iFullscreenDelay > MAX_FULLSCREEN_DELAY) { + iFullscreenDelay = MIN_FULLSCREEN_DELAY; + } + + int tVertAlign = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VERTICALALIGNVIDEO, static_cast(verticalAlignVideoType::ALIGN_MIDDLE)); + if (tVertAlign < static_cast(verticalAlignVideoType::ALIGN_MIDDLE) || tVertAlign > static_cast(verticalAlignVideoType::ALIGN_BOTTOM)) { + tVertAlign = static_cast(verticalAlignVideoType::ALIGN_MIDDLE); + } + iVerticalAlignVideo = static_cast(tVertAlign); + + strSubtitlesProviders = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESPROVIDERS, _T("<|OpenSubtitles2|||1|0|><|podnapisi|||1|0|><|Napisy24|||0|0|>")); + strSubtitlePaths = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLEPATHS, DEFAULT_SUBTITLE_PATHS); + bSubtitleOverrideDefaultStyle = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_DEFAULT_STYLE, FALSE); + bSubtitleOverrideAllStyles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OVERRIDE_ALL_STYLES, FALSE); + + fEnableAudioSwitcher = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEAUDIOSWITCHER, TRUE); + fDownSampleTo441 = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DOWNSAMPLETO441, FALSE); + fCustomChannelMapping = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CUSTOMCHANNELMAPPING, FALSE); + + BOOL bResult = pApp->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_SPEAKERTOCHANNELMAPPING, &ptr, &len); + if (bResult && len == sizeof(pSpeakerToChannelMap)) { + memcpy(pSpeakerToChannelMap, ptr, sizeof(pSpeakerToChannelMap)); + } else { + ZeroMemory(pSpeakerToChannelMap, sizeof(pSpeakerToChannelMap)); + for (int j = 0; j < 18; j++) { + for (int i = 0; i <= j; i++) { + pSpeakerToChannelMap[j][i] = 1 << i; + } + } + + pSpeakerToChannelMap[0][0] = 1 << 0; + pSpeakerToChannelMap[0][1] = 1 << 0; + + pSpeakerToChannelMap[3][0] = 1 << 0; + pSpeakerToChannelMap[3][1] = 1 << 1; + pSpeakerToChannelMap[3][2] = 0; + pSpeakerToChannelMap[3][3] = 0; + pSpeakerToChannelMap[3][4] = 1 << 2; + pSpeakerToChannelMap[3][5] = 1 << 3; + + pSpeakerToChannelMap[4][0] = 1 << 0; + pSpeakerToChannelMap[4][1] = 1 << 1; + pSpeakerToChannelMap[4][2] = 1 << 2; + pSpeakerToChannelMap[4][3] = 0; + pSpeakerToChannelMap[4][4] = 1 << 3; + pSpeakerToChannelMap[4][5] = 1 << 4; + } + if (bResult) { + delete [] ptr; + } + + fAudioNormalize = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZE, FALSE); + nAudioMaxNormFactor = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOMAXNORMFACTOR, 400); + fAudioNormalizeRecover = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIONORMALIZERECOVER, TRUE); + nAudioBoost = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, 0); + + nSpeakerChannels = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPEAKERCHANNELS, 2); + + // External filters + LoadExternalFilters(m_filters); + + m_pnspresets.RemoveAll(); + + for (int i = 0; i < (ID_PANNSCAN_PRESETS_END - ID_PANNSCAN_PRESETS_START); i++) { + CString str2; + str2.Format(_T("Preset%d"), i); + str2 = pApp->GetProfileString(IDS_R_SETTINGS _T("\\") IDS_RS_PNSPRESETS, str2); + if (str2.IsEmpty()) { + break; + } + m_pnspresets.Add(str2); + } + + if (m_pnspresets.IsEmpty()) { + const double _4p3 = 4.0 / 3.0; + const double _16p9 = 16.0 / 9.0; + const double _185p1 = 1.85 / 1.0; + const double _235p1 = 2.35 / 1.0; + UNREFERENCED_PARAMETER(_185p1); + + CString str2; + str2.Format(IDS_SCALE_16_9, 0.5, 0.5, /*_4p3 / _4p3 =*/ 1.0, _16p9 / _4p3); + m_pnspresets.Add(str2); + str2.Format(IDS_SCALE_WIDESCREEN, 0.5, 0.5, _16p9 / _4p3, _16p9 / _4p3); + m_pnspresets.Add(str2); + str2.Format(IDS_SCALE_ULTRAWIDE, 0.5, 0.5, _235p1 / _4p3, _235p1 / _4p3); + m_pnspresets.Add(str2); + } + + for (int i = 0; i < wmcmds.GetCount(); i++) { + CString str2; + str2.Format(_T("CommandMod%d"), i); + str2 = pApp->GetProfileString(IDS_R_COMMANDS, str2); + if (str2.IsEmpty()) { + break; + } + + wmcmd tmp; + int n; + int fVirt = 0; + BYTE ignore; + if (5 > (n = _stscanf_s(str2, _T("%hu %x %hx %S %d %hhu %u %hhu %hhu %hhu"), + &tmp.cmd, &fVirt, &tmp.key, tmp.rmcmd.GetBuffer(128), 128, + &tmp.rmrepcnt, &tmp.mouse, &tmp.appcmd, &ignore, + &tmp.mouseVirt, &ignore))) { + break; + } + tmp.rmcmd.ReleaseBuffer(); + if (n >= 2) { + tmp.fVirt = (BYTE)fVirt; + } + if (POSITION pos = wmcmds.Find(tmp)) { + wmcmd& wc = wmcmds.GetAt(pos); + wc.cmd = tmp.cmd; + wc.fVirt = tmp.fVirt; + wc.key = tmp.key; + if (n >= 6) { + wc.mouse = tmp.mouse; + } + if (n >= 7) { + wc.appcmd = tmp.appcmd; + } + if (n >= 9) { + wc.mouseVirt = tmp.mouseVirt; + } + wc.rmcmd = tmp.rmcmd.Trim('\"'); + wc.rmrepcnt = tmp.rmrepcnt; + } + } + + CAtlArray pAccel; + pAccel.SetCount(ACCEL_LIST_SIZE); + int accel_count = 0; + POSITION pos = wmcmds.GetHeadPosition(); + for (int i = 0; pos; i++) { + ACCEL x = wmcmds.GetNext(pos); + if (x.key > 0) { + pAccel[accel_count] = x; + accel_count++; + } + } + hAccel = CreateAcceleratorTable(pAccel.GetData(), accel_count); + + strWinLircAddr = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WINLIRCADDR, _T("127.0.0.1:8765")); + fWinLirc = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WINLIRC, FALSE); + strUIceAddr = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_UICEADDR, _T("127.0.0.1:1234")); + fUIce = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UICE, FALSE); + fGlobalMedia = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_GLOBALMEDIA, TRUE); + + nJumpDistS = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTS, DEFAULT_JUMPDISTANCE_1); + nJumpDistM = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTM, DEFAULT_JUMPDISTANCE_2); + nJumpDistL = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JUMPDISTL, DEFAULT_JUMPDISTANCE_3); + fLimitWindowProportions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LIMITWINDOWPROPORTIONS, FALSE); + + m_Formats.UpdateData(false); + + // Internal filters + for (int f = 0; f < SRC_LAST; f++) { + SrcFilters[f] = !!pApp->GetProfileInt(IDS_R_INTERNAL_FILTERS, SrcFiltersKeys[f].name, SrcFiltersKeys[f].bDefault); + } + for (int f = 0; f < TRA_LAST; f++) { + TraFilters[f] = !!pApp->GetProfileInt(IDS_R_INTERNAL_FILTERS, TraFiltersKeys[f].name, TraFiltersKeys[f].bDefault); + } + + strLogoFileName = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_LOGOFILE); + nLogoId = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOID, -1); + fLogoExternal = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOEXT, FALSE); + fLogoColorProfileEnabled = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGOCOLORPROFILE, FALSE); + + fHideCDROMsSubMenu = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIDECDROMSSUBMENU, FALSE); + + dwPriority = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PRIORITY, NORMAL_PRIORITY_CLASS); + ::SetPriorityClass(::GetCurrentProcess(), dwPriority); + fLaunchfullscreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LAUNCHFULLSCREEN, FALSE); + + fEnableWebServer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEWEBSERVER, FALSE); + nWebServerPort = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPORT, 13579); + fWebServerUseCompression = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERUSECOMPRESSION, TRUE); + fWebServerLocalhostOnly = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERLOCALHOSTONLY, FALSE); + bWebUIEnablePreview = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBUI_ENABLE_PREVIEW, FALSE); + fWebServerPrintDebugInfo = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_WEBSERVERPRINTDEBUGINFO, FALSE); + strWebRoot = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBROOT, _T("*./webroot")); + strWebDefIndex = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBDEFINDEX, _T("index.html;index.php")); + strWebServerCGI = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_WEBSERVERCGI); + + CString MyPictures; + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), KEY_READ)) { + ULONG lenValue = 1024; + if (ERROR_SUCCESS == key.QueryStringValue(_T("My Pictures"), MyPictures.GetBuffer((int)lenValue), &lenValue)) { + MyPictures.ReleaseBufferSetLength((int)lenValue); + } else { + MyPictures.Empty(); + } + } + strSnapshotPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTPATH, MyPictures); + strSnapshotExt = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_SNAPSHOTEXT, _T(".jpg")); + bSnapShotSubtitles = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTSUBTITLES, TRUE); + bSnapShotKeepVideoExtension = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SNAPSHOTKEEPVIDEOEXTENSION, TRUE); + + iThumbRows = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBROWS, 4); + iThumbCols = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBCOLS, 4); + iThumbWidth = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_THUMBWIDTH, 1024); + + bSubSaveExternalStyleFile = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBSAVEEXTERNALSTYLEFILE, FALSE); + nLastUsedPage = WORD(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LASTUSEDPAGE, 0)); + + { + // Load the list of extra (non-default) shader files + m_ShadersExtraList = ShaderList(pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_EXTRA)); + // Load shader selection + m_Shaders.SetCurrentPreset(ShaderPreset(pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_PRERESIZE), + pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_POSTRESIZE))); + // Load shader presets + ShaderSelection::ShaderPresetMap presets; + for (int i = 0;; i++) { + CString iStr; + iStr.Format(_T("%d"), i); + CString name = pApp->GetProfileString(IDS_R_SHADER_PRESETS, iStr); + if (name.IsEmpty()) { + break; + } + presets.emplace(name, ShaderPreset(pApp->GetProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_PRERESIZE + iStr), + pApp->GetProfileString(IDS_R_SHADER_PRESETS, IDS_RS_SHADERS_POSTRESIZE + iStr))); + } + m_Shaders.SetPresets(presets); + // Load last shader preset name + CString name = pApp->GetProfileString(IDS_R_SHADERS, IDS_RS_SHADERS_LASTPRESET); + if (!name.IsEmpty()) { + m_Shaders.SetCurrentPreset(name); + } + } + + fD3DFullscreen = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_D3DFULLSCREEN, FALSE); + + iBrightness = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_BRIGHTNESS, 0); + iContrast = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_CONTRAST, 0); + iHue = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_HUE, 0); + iSaturation = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COLOR_SATURATION, 0); + + fShowOSD = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOWOSD, TRUE); + fShowCurrentTimeInOSD = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CURRENT_TIME_OSD, FALSE); + + nOSDTransparency = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_TRANSPARENCY, 64); + nOSDBorder = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OSD_BORDER, 1); + + fEnableEDLEditor = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLEEDLEDITOR, FALSE); + bFastSeek = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK, TRUE); + eFastSeekMethod = static_cast( + pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FASTSEEK_METHOD, FASTSEEK_NEAREST_KEYFRAME)); + fShowChapters = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_CHAPTERS, TRUE); + + + fLCDSupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LCD_SUPPORT, FALSE); + + fSeekPreview = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW, FALSE); + iSeekPreviewSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SEEKPREVIEW_SIZE, 15); + if (iSeekPreviewSize < 5) iSeekPreviewSize = 5; + if (iSeekPreviewSize > 40) iSeekPreviewSize = 40; + + // Save analog capture settings + iDefaultCaptureDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULT_CAPTURE, 0); + strAnalogVideo = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_VIDEO_DISP_NAME, _T("dummy")); + strAnalogAudio = pApp->GetProfileString(IDS_R_CAPTURE, IDS_RS_AUDIO_DISP_NAME, _T("dummy")); + iAnalogCountry = pApp->GetProfileInt(IDS_R_CAPTURE, IDS_RS_COUNTRY, 1); + + //strBDANetworkProvider = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_NETWORKPROVIDER); + strBDATuner = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_TUNER); + strBDAReceiver = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_RECEIVER); + //sBDAStandard = pApp->GetProfileString(IDS_R_DVB, IDS_RS_BDA_STANDARD); + iBDAScanFreqStart = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_START, 474000); + iBDAScanFreqEnd = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SCAN_FREQ_END, 858000); + iBDABandwidth = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_BANDWIDTH, 8); + iBDASymbolRate = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_SYMBOLRATE, 0); + fBDAUseOffset = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_USE_OFFSET, FALSE); + iBDAOffset = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_OFFSET, 166); + fBDAIgnoreEncryptedChannels = !!pApp->GetProfileInt(IDS_R_DVB, IDS_RS_BDA_IGNORE_ENCRYPTED_CHANNELS, FALSE); + nDVBLastChannel = pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_LAST_CHANNEL, INT_ERROR); + nDVBRebuildFilterGraph = (DVB_RebuildFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_REBUILD_FG, DVB_STOP_FG_ALWAYS); + nDVBStopFilterGraph = (DVB_StopFilterGraph) pApp->GetProfileInt(IDS_R_DVB, IDS_RS_DVB_STOP_FG, DVB_STOP_FG_ALWAYS); + + for (int iChannel = 0; ; iChannel++) { + CString strTemp; + strTemp.Format(_T("%d"), iChannel); + CString strChannel = pApp->GetProfileString(IDS_R_DVB, strTemp); + if (strChannel.IsEmpty()) { + break; + } + try { + m_DVBChannels.emplace_back(strChannel); + } catch (CException* e) { + // The tokenisation can fail if the input string was invalid + TRACE(_T("Failed to parse a DVB channel from string \"%s\""), strChannel.GetString()); + ASSERT(FALSE); + e->Delete(); + } + } + + // playback positions for last played files + fRememberFilePos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS, FALSE); + iRememberPosForLongerThan = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSLONGER, 5); + bRememberPosForAudioFiles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOSAUDIO, TRUE); + if (iRememberPosForLongerThan < 0) { + iRememberPosForLongerThan = 5; + } + bRememberExternalPlaylistPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_PLAYLIST, TRUE); + bRememberTrackSelection = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FILEPOS_TRACK_SELECTION, TRUE); + + // playback positions for last played DVDs + fRememberDVDPos = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DVDPOS, FALSE); + + bToggleShader = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADER, TRUE); + bToggleShaderScreenSpace = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TOGGLESHADERSSCREENSPACE, TRUE); + + fRemainingTime = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REMAINING_TIME, FALSE); + bHighPrecisionTimer = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_HIGH_PRECISION_TIMER, FALSE); + bTimerShowPercentage = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIMER_SHOW_PERCENTAGE, FALSE); + + nUpdaterAutoCheck = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_AUTO_CHECK, AUTOUPDATE_UNKNOWN); + nUpdaterDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_UPDATER_DELAY, 7); + if (nUpdaterDelay < 1) { + nUpdaterDelay = 1; + } + + bNotifySkype = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_NOTIFY_SKYPE, FALSE); + + nJpegQuality = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_JPEG_QUALITY, 90); + if (nJpegQuality < 20 || nJpegQuality > 100) { + nJpegQuality = 90; + } + + bEnableCoverArt = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART, TRUE); + nCoverArtSizeLimit = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_COVER_ART_SIZE_LIMIT, 600); + + bEnableLogging = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOGGING, FALSE); + bUseLegacyToolbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_LEGACY_TOOLBAR, FALSE); + + eSubtitleRenderer = static_cast(pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, static_cast(SubtitleRenderer::INTERNAL))); + if (eSubtitleRenderer == SubtitleRenderer::RESERVED) { + eSubtitleRenderer = SubtitleRenderer::INTERNAL; + bRenderSSAUsingLibass = true; + } + + nDefaultToolbarSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DEFAULTTOOLBARSIZE, 24); + + bSaveImagePosition = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_POSITION, TRUE); + bSaveImageCurrentTime = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SAVEIMAGE_CURRENTTIME, FALSE); + + bAllowInaccurateFastseek = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_INACCURATE_FASTSEEK, TRUE); + bLoopFolderOnPlayNextFile = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOOP_FOLDER_NEXT_FILE, FALSE); + + bLockNoPause = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_LOCK_NOPAUSE, FALSE); + bPreventDisplaySleep = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_PREVENT_DISPLAY_SLEEP, TRUE); + bUseSMTC = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_SMTC, FALSE); + iReloadAfterLongPause = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RELOAD_AFTER_LONG_PAUSE, 0); + bOpenRecPanelWhenOpeningDevice = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_OPEN_REC_PANEL_WHEN_OPENING_DEVICE, TRUE); + + sanear->SetOutputDevice(pApp->GetProfileString(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_ID), + pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_EXCLUSIVE, FALSE), + pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_DEVICE_BUFFER, + SaneAudioRenderer::ISettings::OUTPUT_DEVICE_BUFFER_DEFAULT_MS)); + + sanear->SetCrossfeedEnabled(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_ENABLED, FALSE)); + + sanear->SetCrossfeedSettings(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_CUTOFF_FREQ, + SaneAudioRenderer::ISettings::CROSSFEED_CUTOFF_FREQ_CMOY), + pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_CROSSFEED_LEVEL, + SaneAudioRenderer::ISettings::CROSSFEED_LEVEL_CMOY)); + + sanear->SetIgnoreSystemChannelMixer(pApp->GetProfileInt(IDS_R_SANEAR, IDS_RS_SANEAR_IGNORE_SYSTEM_MIXER, TRUE)); + + bUseYDL = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_YDL, TRUE); + iYDLMaxHeight = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_MAX_HEIGHT, 1440); + iYDLVideoFormat = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_VIDEO_FORMAT, 0); + iYDLAudioFormat = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_FORMAT, 0); + bYDLAudioOnly = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_YDL_AUDIO_ONLY, FALSE); + sYDLExePath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_EXEPATH, _T("")); + sYDLCommandLine = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_COMMAND_LINE, _T("")); + + bEnableCrashReporter = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ENABLE_CRASH_REPORTER, TRUE); + + nStreamPosPollerInterval = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_TIME_REFRESH_INTERVAL, 100); + bShowLangInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_LANG_STATUSBAR, FALSE); + bShowFPSInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_FPS_STATUSBAR, FALSE); + bShowABMarksInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_ABMARKS_STATUSBAR, FALSE); + bShowVideoInfoInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_VIDEOINFO_STATUSBAR, TRUE); + bShowAudioFormatInStatusbar = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SHOW_AUDIOFORMAT_STATUSBAR, TRUE); + + bAddLangCodeWhenSaveSubtitles = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ADD_LANGCODE_WHEN_SAVE_SUBTITLES, FALSE); + bUseTitleInRecentFileList = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_TITLE_IN_RECENT_FILE_LIST, TRUE); + sYDLSubsPreference = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_YDL_SUBS_PREFERENCE, _T("")); + bUseAutomaticCaptions = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_USE_AUTOMATIC_CAPTIONS, FALSE); + + lastQuickOpenPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_QUICKOPEN_PATH, L""); + lastFileSaveCopyPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_FILESAVECOPY_PATH, L""); + lastFileOpenDirPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_LAST_FILEOPENDIR_PATH, L""); + externalPlayListPath = pApp->GetProfileString(IDS_R_SETTINGS, IDS_EXTERNAL_PLAYLIST_PATH, L""); + + iRedirectOpenToAppendThreshold = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_REDIRECT_OPEN_TO_APPEND_THRESHOLD, 1000); + bFullscreenSeparateControls = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_FULLSCREEN_SEPARATE_CONTROLS, TRUE); + bAlwaysUseShortMenu = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALWAYS_USE_SHORT_MENU, FALSE); + iStillVideoDuration = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_STILL_VIDEO_DURATION, 10); + iMouseLeftUpDelay = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MOUSE_LEFTUP_DELAY, 0); + + if (bMPCTheme) { + CMPCTheme::InitializeColors(eModernThemeMode); + } + // GUI theme can be used now + static_cast(AfxGetApp())->m_bThemeLoaded = bMPCTheme; + + if (fLaunchfullscreen && slFiles.GetCount() > 0) { + nCLSwitches |= CLSW_FULLSCREEN; + } + + bInitialized = true; +} + +bool CAppSettings::GetAllowMultiInst() const +{ + return !!AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_MULTIINST, FALSE); +} + +void CAppSettings::UpdateRenderersData(bool fSave) +{ + CWinApp* pApp = AfxGetApp(); + CRenderersSettings& r = m_RenderersSettings; + CRenderersSettings::CAdvRendererSettings& ars = r.m_AdvRendSets; + + if (fSave) { + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_APSURACEFUSAGE, r.iAPSurfaceUsage); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DX9_RESIZER, r.iDX9Resizer); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_VMR9MIXERMODE, r.fVMR9MixerMode); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRAlternateVSync"), ars.bVMR9AlterativeVSync); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSyncOffset"), ars.iVMR9VSyncOffset); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSyncAccurate2"), ars.bVMR9VSyncAccurate); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFullscreenGUISupport"), ars.bVMR9FullscreenGUISupport); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRVSync"), ars.bVMR9VSync); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRDisableDesktopComposition"), ars.bVMRDisableDesktopComposition); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFullFloatingPointProcessing2"), ars.bVMR9FullFloatingPointProcessing); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRHalfFloatingPointProcessing"), ars.bVMR9HalfFloatingPointProcessing); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementEnable"), ars.bVMR9ColorManagementEnable); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementInput"), ars.iVMR9ColorManagementInput); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementAmbientLight"), ars.iVMR9ColorManagementAmbientLight); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementIntent"), ars.iVMR9ColorManagementIntent); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVROutputRange"), ars.iEVROutputRange); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVRHighColorRes"), ars.bEVRHighColorResolution); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVRForceInputHighColorRes"), ars.bEVRForceInputHighColorResolution); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("EVREnableFrameTimeCorrection"), ars.bEVREnableFrameTimeCorrection); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUBeforeVSync"), ars.bVMRFlushGPUBeforeVSync); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUAfterPresent"), ars.bVMRFlushGPUAfterPresent); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUWait"), ars.bVMRFlushGPUWait); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("DesktopSizeBackBuffer"), ars.bDesktopSizeBackBuffer); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeClock"), ars.bSynchronizeVideo); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeDisplay"), ars.bSynchronizeDisplay); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("SynchronizeNearest"), ars.bSynchronizeNearest); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("LineDelta"), ars.iLineDelta); + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("ColumnDelta"), ars.iColumnDelta); + + pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("CycleDelta"), (LPBYTE) & (ars.fCycleDelta), sizeof(ars.fCycleDelta)); + pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("TargetSyncOffset"), (LPBYTE) & (ars.fTargetSyncOffset), sizeof(ars.fTargetSyncOffset)); + pApp->WriteProfileBinary(IDS_R_SETTINGS, _T("ControlLimit"), (LPBYTE) & (ars.fControlLimit), sizeof(ars.fControlLimit)); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_CACHESHADERS, ars.bCacheShaders); + + pApp->WriteProfileInt(IDS_R_SETTINGS, _T("ResetDevice"), r.fResetDevice); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCSIZE, r.subPicQueueSettings.nSize); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESX, r.subPicQueueSettings.nMaxResX); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESY, r.subPicQueueSettings.nMaxResY); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, r.subPicQueueSettings.bDisableSubtitleAnimation); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_RENDER_AT_WHEN_ANIM_DISABLED, r.subPicQueueSettings.nRenderAtWhenAnimationIsDisabled); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_ANIMATION_RATE, r.subPicQueueSettings.nAnimationRate); + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_DROPPING_SUBPIC, r.subPicQueueSettings.bAllowDroppingSubpic); + + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_EVR_BUFFERS, r.iEvrBuffers); + + pApp->WriteProfileString(IDS_R_SETTINGS, IDS_RS_D3D9RENDERDEVICE, r.D3D9RenderDevice); + } else { + r.iAPSurfaceUsage = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_APSURACEFUSAGE, VIDRNDT_AP_TEXTURE3D); + r.iDX9Resizer = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DX9_RESIZER, 1); + r.fVMR9MixerMode = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_VMR9MIXERMODE, TRUE); + + CRenderersSettings::CAdvRendererSettings DefaultSettings; + ars.bVMR9AlterativeVSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRAlternateVSync"), DefaultSettings.bVMR9AlterativeVSync); + ars.iVMR9VSyncOffset = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSyncOffset"), DefaultSettings.iVMR9VSyncOffset); + ars.bVMR9VSyncAccurate = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSyncAccurate2"), DefaultSettings.bVMR9VSyncAccurate); + ars.bVMR9FullscreenGUISupport = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFullscreenGUISupport"), DefaultSettings.bVMR9FullscreenGUISupport); + ars.bEVRHighColorResolution = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVRHighColorRes"), DefaultSettings.bEVRHighColorResolution); + ars.bEVRForceInputHighColorResolution = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVRForceInputHighColorRes"), DefaultSettings.bEVRForceInputHighColorResolution); + ars.bEVREnableFrameTimeCorrection = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVREnableFrameTimeCorrection"), DefaultSettings.bEVREnableFrameTimeCorrection); + ars.bVMR9VSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRVSync"), DefaultSettings.bVMR9VSync); + ars.bVMRDisableDesktopComposition = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRDisableDesktopComposition"), DefaultSettings.bVMRDisableDesktopComposition); + ars.bVMR9FullFloatingPointProcessing = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFullFloatingPointProcessing2"), DefaultSettings.bVMR9FullFloatingPointProcessing); + ars.bVMR9HalfFloatingPointProcessing = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRHalfFloatingPointProcessing"), DefaultSettings.bVMR9HalfFloatingPointProcessing); + + ars.bVMR9ColorManagementEnable = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementEnable"), DefaultSettings.bVMR9ColorManagementEnable); + ars.iVMR9ColorManagementInput = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementInput"), DefaultSettings.iVMR9ColorManagementInput); + ars.iVMR9ColorManagementAmbientLight = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementAmbientLight"), DefaultSettings.iVMR9ColorManagementAmbientLight); + ars.iVMR9ColorManagementIntent = pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRColorManagementIntent"), DefaultSettings.iVMR9ColorManagementIntent); + + ars.iEVROutputRange = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("EVROutputRange"), DefaultSettings.iEVROutputRange); + + ars.bVMRFlushGPUBeforeVSync = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUBeforeVSync"), DefaultSettings.bVMRFlushGPUBeforeVSync); + ars.bVMRFlushGPUAfterPresent = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUAfterPresent"), DefaultSettings.bVMRFlushGPUAfterPresent); + ars.bVMRFlushGPUWait = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("VMRFlushGPUWait"), DefaultSettings.bVMRFlushGPUWait); + + ars.bDesktopSizeBackBuffer = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("DesktopSizeBackBuffer"), DefaultSettings.bDesktopSizeBackBuffer); + + ars.bSynchronizeVideo = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeClock"), DefaultSettings.bSynchronizeVideo); + ars.bSynchronizeDisplay = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeDisplay"), DefaultSettings.bSynchronizeDisplay); + ars.bSynchronizeNearest = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("SynchronizeNearest"), DefaultSettings.bSynchronizeNearest); + ars.iLineDelta = pApp->GetProfileInt(IDS_R_SETTINGS, _T("LineDelta"), DefaultSettings.iLineDelta); + ars.iColumnDelta = pApp->GetProfileInt(IDS_R_SETTINGS, _T("ColumnDelta"), DefaultSettings.iColumnDelta); + + double* dPtr; + UINT dSize; + if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("CycleDelta"), (LPBYTE*)&dPtr, &dSize)) { + ars.fCycleDelta = *dPtr; + delete [] dPtr; + } + + if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("TargetSyncOffset"), (LPBYTE*)&dPtr, &dSize)) { + ars.fTargetSyncOffset = *dPtr; + delete [] dPtr; + } + if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("ControlLimit"), (LPBYTE*)&dPtr, &dSize)) { + ars.fControlLimit = *dPtr; + delete [] dPtr; + } + + ars.bCacheShaders = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_CACHESHADERS, DefaultSettings.bCacheShaders); + if (AfxGetMyApp()->GetAppSavePath(ars.sShaderCachePath)) { + ars.sShaderCachePath = PathUtils::CombinePaths(ars.sShaderCachePath, IDS_R_SHADER_CACHE); + } + + r.fResetDevice = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("ResetDevice"), FALSE); + + r.subPicQueueSettings.nSize = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCSIZE, 0); + r.subPicQueueSettings.nMaxResX = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESX, 2560); + r.subPicQueueSettings.nMaxResY = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SPCMAXRESY, 1440); + if (r.subPicQueueSettings.nMaxResX < 600 || r.subPicQueueSettings.nMaxResY < 480) { + r.subPicQueueSettings.nMaxResX = 2560; + r.subPicQueueSettings.nMaxResY = 1440; + } + r.subPicQueueSettings.bDisableSubtitleAnimation = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, FALSE); + r.subPicQueueSettings.nRenderAtWhenAnimationIsDisabled = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_RENDER_AT_WHEN_ANIM_DISABLED, 50); + r.subPicQueueSettings.nAnimationRate = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_ANIMATION_RATE, 100); + r.subPicQueueSettings.bAllowDroppingSubpic = !!pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ALLOW_DROPPING_SUBPIC, TRUE); + + r.subPicVerticalShift = 0; + r.fontScaleOverride = 1.0; + + r.iEvrBuffers = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_EVR_BUFFERS, 5); + r.D3D9RenderDevice = pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_D3D9RENDERDEVICE); + } +} + +__int64 CAppSettings::ConvertTimeToMSec(const CString& time) const +{ + __int64 Sec = 0; + __int64 mSec = 0; + __int64 mult = 1; + + int pos = time.GetLength() - 1; + if (pos < 3) { + return 0; + } + + while (pos >= 0) { + TCHAR ch = time[pos]; + if (ch == '.') { + mSec = Sec * 1000 / mult; + Sec = 0; + mult = 1; + } else if (ch == ':') { + mult = mult * 6 / 10; + } else if (ch >= '0' && ch <= '9') { + Sec += (ch - '0') * mult; + mult *= 10; + } else { + mSec = Sec = 0; + break; + } + pos--; + } + return Sec * 1000 + mSec; +} + +void CAppSettings::ExtractDVDStartPos(CString& strParam) +{ + int i = 0, j = 0; + for (CString token = strParam.Tokenize(_T("#"), i); + j < 3 && !token.IsEmpty(); + token = strParam.Tokenize(_T("#"), i), j++) { + switch (j) { + case 0: + lDVDTitle = token.IsEmpty() ? 0 : (ULONG)_wtol(token); + break; + case 1: + if (token.Find(':') > 0) { + UINT h = 0, m = 0, s = 0, f = 0; + int nRead = _stscanf_s(token, _T("%02u:%02u:%02u.%03u"), &h, &m, &s, &f); + if (nRead >= 3) { + DVDPosition.bHours = (BYTE)h; + DVDPosition.bMinutes = (BYTE)m; + DVDPosition.bSeconds = (BYTE)s; + DVDPosition.bFrames = (BYTE)f; + } + } else { + lDVDChapter = token.IsEmpty() ? 0 : (ULONG)_wtol(token); + } + break; + } + } +} + +CString CAppSettings::ParseFileName(CString const& param) +{ + if (param.Find(_T(":")) < 0 && param.Left(2) != L"\\\\") { + // Try to transform relative pathname into full pathname + CString fullPathName; + DWORD dwLen = GetFullPathName(param, 2048, fullPathName.GetBuffer(2048), nullptr); + if (dwLen > 0 && dwLen < 2048) { + fullPathName.ReleaseBuffer(dwLen); + + if (!fullPathName.IsEmpty() && PathUtils::Exists(fullPathName)) { + return fullPathName; + } + } + } else { + CString fullPathName = param; + ExtendMaxPathLengthIfNeeded(fullPathName); + return fullPathName; + } + + return param; +} + +void CAppSettings::ParseCommandLine(CAtlList& cmdln) +{ + UINT64 existingAfterPlaybackCL = nCLSwitches & CLSW_AFTERPLAYBACK_MASK; + nCLSwitches = 0; + slFiles.RemoveAll(); + slDubs.RemoveAll(); + slSubs.RemoveAll(); + slFilters.RemoveAll(); + rtStart = 0; + rtShift = 0; + lDVDTitle = 0; + lDVDChapter = 0; + ZeroMemory(&DVDPosition, sizeof(DVDPosition)); + iAdminOption = 0; + sizeFixedWindow.SetSize(0, 0); + fixedWindowPosition = NO_FIXED_POSITION; + iMonitor = 0; + strPnSPreset.Empty(); + + POSITION pos = cmdln.GetHeadPosition(); + while (pos) { + const CString& param = cmdln.GetNext(pos); + if (param.IsEmpty()) { + continue; + } + + if ((param[0] == '-' || param[0] == '/') && param.GetLength() > 1) { + CString sw = param.Mid(1).MakeLower(); + if (sw == _T("open")) { + nCLSwitches |= CLSW_OPEN; + } else if (sw == _T("play")) { + nCLSwitches |= CLSW_PLAY; + } else if (sw == _T("fullscreen")) { + nCLSwitches |= CLSW_FULLSCREEN; + } else if (sw == _T("minimized")) { + nCLSwitches |= CLSW_MINIMIZED; + } else if (sw == _T("new")) { + nCLSwitches |= CLSW_NEW; + } else if (sw == _T("help") || sw == _T("h") || sw == _T("?")) { + nCLSwitches |= CLSW_HELP; + } else if (sw == _T("dub") && pos) { + slDubs.AddTail(ParseFileName(cmdln.GetNext(pos))); + } else if (sw == _T("dubdelay") && pos) { + CString strFile = ParseFileName(cmdln.GetNext(pos)); + int nPos = strFile.Find(_T("DELAY")); + if (nPos != -1) { + rtShift = 10000i64 * _tstol(strFile.Mid(nPos + 6)); + } + slDubs.AddTail(strFile); + } else if (sw == _T("sub") && pos) { + slSubs.AddTail(ParseFileName(cmdln.GetNext(pos))); + } else if (sw == _T("filter") && pos) { + slFilters.AddTail(cmdln.GetNext(pos)); + } else if (sw == _T("dvd")) { + nCLSwitches |= CLSW_DVD; + } else if (sw == _T("dvdpos") && pos) { + ExtractDVDStartPos(cmdln.GetNext(pos)); + } else if (sw == _T("cd")) { + nCLSwitches |= CLSW_CD; + } else if (sw == _T("device")) { + nCLSwitches |= CLSW_DEVICE; + } else if (sw == _T("add")) { + nCLSwitches |= CLSW_ADD; + } else if (sw == _T("randomize")) { + nCLSwitches |= CLSW_RANDOMIZE; + } else if (sw == _T("volume") && pos) { + int setVolumeVal = _ttoi(cmdln.GetNext(pos)); + if (setVolumeVal >= 0 && setVolumeVal <= 100) { + nCmdVolume = setVolumeVal; + nCLSwitches |= CLSW_VOLUME; + } else { + nCLSwitches |= CLSW_UNRECOGNIZEDSWITCH; + } + } else if (sw == _T("regvid")) { + nCLSwitches |= CLSW_REGEXTVID; + } else if (sw == _T("regaud")) { + nCLSwitches |= CLSW_REGEXTAUD; + } else if (sw == _T("regpl")) { + nCLSwitches |= CLSW_REGEXTPL; + } else if (sw == _T("regall")) { + nCLSwitches |= (CLSW_REGEXTVID | CLSW_REGEXTAUD | CLSW_REGEXTPL); + } else if (sw == _T("unregall")) { + nCLSwitches |= CLSW_UNREGEXT; + } else if (sw == _T("unregvid")) { + nCLSwitches |= CLSW_UNREGEXT; /* keep for compatibility with old versions */ + } else if (sw == _T("unregaud")) { + nCLSwitches |= CLSW_UNREGEXT; /* keep for compatibility with old versions */ + } else if (sw == _T("iconsassoc")) { + nCLSwitches |= CLSW_ICONSASSOC; + } else if (sw == _T("start") && pos) { + rtStart = 10000i64 * _tcstol(cmdln.GetNext(pos), nullptr, 10); + nCLSwitches |= CLSW_STARTVALID; + } else if (sw == _T("startpos") && pos) { + rtStart = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); + nCLSwitches |= CLSW_STARTVALID; + } else if (sw == _T("nofocus")) { + nCLSwitches |= CLSW_NOFOCUS; + } else if (sw == _T("close")) { + nCLSwitches |= CLSW_CLOSE; + } else if (sw == _T("standby")) { + nCLSwitches |= CLSW_STANDBY; + } else if (sw == _T("hibernate")) { + nCLSwitches |= CLSW_HIBERNATE; + } else if (sw == _T("shutdown")) { + nCLSwitches |= CLSW_SHUTDOWN; + } else if (sw == _T("logoff")) { + nCLSwitches |= CLSW_LOGOFF; + } else if (sw == _T("lock")) { + nCLSwitches |= CLSW_LOCK; + } else if (sw == _T("d3dfs")) { + nCLSwitches |= CLSW_D3DFULLSCREEN; + } else if (sw == _T("adminoption") && pos) { + nCLSwitches |= CLSW_ADMINOPTION; + iAdminOption = _ttoi(cmdln.GetNext(pos)); + } else if (sw == _T("slave") && pos) { + nCLSwitches |= CLSW_SLAVE; + hMasterWnd = (HWND)IntToPtr(_ttoi(cmdln.GetNext(pos))); + } else if (sw == _T("fixedsize") && pos) { + CAtlList sl; + // Optional arguments for the main window's position + Explode(cmdln.GetNext(pos), sl, ',', 4); + if (sl.GetCount() == 4) { + fixedWindowPosition.SetPoint(_ttol(sl.GetAt(sl.FindIndex(2))), _ttol(sl.GetAt(sl.FindIndex(3))) ); + } + if (sl.GetCount() >= 2) { + sizeFixedWindow.SetSize(_ttol(sl.GetAt(sl.FindIndex(0))), _ttol(sl.GetAt(sl.FindIndex(1))) ); + if (sizeFixedWindow.cx > 0 && sizeFixedWindow.cy > 0) { + nCLSwitches |= CLSW_FIXEDSIZE; + } + } + } else if (sw == _T("viewpreset") && pos) { + int viewPreset = _ttoi(cmdln.GetNext(pos)); + switch (viewPreset) { + case 1: + nCLSwitches |= CLSW_PRESET1; + break; + case 2: + nCLSwitches |= CLSW_PRESET2; + break; + case 3: + nCLSwitches |= CLSW_PRESET3; + break; + default: + nCLSwitches |= CLSW_UNRECOGNIZEDSWITCH; + break; + } + } else if (sw == _T("monitor") && pos) { + iMonitor = _tcstol(cmdln.GetNext(pos), nullptr, 10); + nCLSwitches |= CLSW_MONITOR; + } else if (sw == _T("pns") && pos) { + strPnSPreset = cmdln.GetNext(pos); + } else if (sw == _T("webport") && pos) { + int tmpport = _tcstol(cmdln.GetNext(pos), nullptr, 10); + if (tmpport >= 0 && tmpport <= 65535) { + nCmdlnWebServerPort = tmpport; + } + } else if (sw == _T("debug")) { + fShowDebugInfo = true; + } else if (sw == _T("nocrashreporter")) { +#if USE_DRDUMP_CRASH_REPORTER + if (CrashReporter::IsEnabled()) { + CrashReporter::Disable(); + MPCExceptionHandler::Enable(); + } +#endif + } else if (sw == _T("audiorenderer") && pos) { + SetAudioRenderer(_ttoi(cmdln.GetNext(pos))); + } else if (sw == _T("shaderpreset") && pos) { + m_Shaders.SetCurrentPreset(cmdln.GetNext(pos)); + } else if (sw == _T("reset")) { + nCLSwitches |= CLSW_RESET; + } else if (sw == _T("mute")) { + nCLSwitches |= CLSW_MUTE; + } else if (sw == _T("monitoroff")) { + nCLSwitches |= CLSW_MONITOROFF; + } else if (sw == _T("playnext")) { + nCLSwitches |= CLSW_PLAYNEXT; + } else if (sw == _T("hwgpu") && pos) { + iLAVGPUDevice = _tcstol(cmdln.GetNext(pos), nullptr, 10); + } else if (sw == _T("configlavsplitter")) { + nCLSwitches |= CLSW_CONFIGLAVSPLITTER; + } else if (sw == _T("configlavaudio")) { + nCLSwitches |= CLSW_CONFIGLAVAUDIO; + } else if (sw == _T("configlavvideo")) { + nCLSwitches |= CLSW_CONFIGLAVVIDEO; + } else if (sw == L"ab_start" && pos) { + abRepeat.positionA = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); + } else if (sw == L"ab_end" && pos) { + abRepeat.positionB = 10000i64 * ConvertTimeToMSec(cmdln.GetNext(pos)); + } else if (sw == L"thumbnails") { + nCLSwitches |= CLSW_THUMBNAILS | CLSW_NEW; + } else { + nCLSwitches |= CLSW_HELP | CLSW_UNRECOGNIZEDSWITCH; + } + } else { + if (param == _T("-")) { // Special case: standard input + slFiles.AddTail(_T("pipe://stdin")); + } else { + const_cast(param) = ParseFileName(param); + slFiles.AddTail(param); + } + } + } + + if (abRepeat.positionA && abRepeat.positionB && abRepeat.positionA >= abRepeat.positionB) { + abRepeat.positionA = 0; + abRepeat.positionB = 0; + } + if (abRepeat.positionA > rtStart || (abRepeat.positionB && abRepeat.positionB < rtStart)) { + rtStart = abRepeat.positionA; + nCLSwitches |= CLSW_STARTVALID; + } + + if (0 == (nCLSwitches & CLSW_AFTERPLAYBACK_MASK)) { //no changes to playback mask, so let's preserve existing + nCLSwitches |= existingAfterPlaybackCL; + } +} + +void CAppSettings::GetFav(favtype ft, CAtlList& sl) const +{ + sl.RemoveAll(); + + CString root; + + switch (ft) { + case FAV_FILE: + root = IDS_R_FAVFILES; + break; + case FAV_DVD: + root = IDS_R_FAVDVDS; + break; + case FAV_DEVICE: + root = IDS_R_FAVDEVICES; + break; + default: + return; + } + + for (int i = 0; ; i++) { + CString s; + s.Format(_T("Name%d"), i); + s = AfxGetApp()->GetProfileString(root, s); + if (s.IsEmpty()) { + break; + } + sl.AddTail(s); + } +} + +void CAppSettings::SetFav(favtype ft, CAtlList& sl) +{ + CString root; + + switch (ft) { + case FAV_FILE: + root = IDS_R_FAVFILES; + break; + case FAV_DVD: + root = IDS_R_FAVDVDS; + break; + case FAV_DEVICE: + root = IDS_R_FAVDEVICES; + break; + default: + return; + } + + AfxGetApp()->WriteProfileString(root, nullptr, nullptr); + + int i = 0; + POSITION pos = sl.GetHeadPosition(); + while (pos) { + CString s; + s.Format(_T("Name%d"), i++); + AfxGetApp()->WriteProfileString(root, s, sl.GetNext(pos)); + } +} + +void CAppSettings::AddFav(favtype ft, CString s) +{ + CAtlList sl; + GetFav(ft, sl); + if (sl.Find(s)) { + return; + } + sl.AddTail(s); + SetFav(ft, sl); +} + +CBDAChannel* CAppSettings::FindChannelByPref(int nPrefNumber) +{ + auto it = find_if(m_DVBChannels.begin(), m_DVBChannels.end(), [&](CBDAChannel const & channel) { + return channel.GetPrefNumber() == nPrefNumber; + }); + + return it != m_DVBChannels.end() ? &(*it) : nullptr; +} + +// Settings::CRecentFileAndURLList +CAppSettings::CRecentFileAndURLList::CRecentFileAndURLList(UINT nStart, LPCTSTR lpszSection, + LPCTSTR lpszEntryFormat, int nSize, + int nMaxDispLen) + : CRecentFileList(nStart, lpszSection, lpszEntryFormat, nSize, nMaxDispLen) +{ +} + +extern BOOL AFXAPI AfxComparePath(LPCTSTR lpszPath1, LPCTSTR lpszPath2); + +void CAppSettings::CRecentFileAndURLList::Add(LPCTSTR lpszPathName) +{ + ASSERT(m_arrNames != nullptr); + ASSERT(lpszPathName != nullptr); + ASSERT(AfxIsValidString(lpszPathName)); + + if (m_nSize <= 0 || CString(lpszPathName).MakeLower().Find(_T("@device:")) >= 0) { + return; + } + + CString pathName = lpszPathName; + + bool fURL = PathUtils::IsURL(pathName); + + // fully qualify the path name + if (!fURL) { + pathName = MakeFullPath(pathName); + } + + // update the MRU list, if an existing MRU string matches file name + int iMRU; + for (iMRU = 0; iMRU < m_nSize - 1; iMRU++) { + if ((fURL && !_tcscmp(m_arrNames[iMRU], pathName)) + || AfxComparePath(m_arrNames[iMRU], pathName)) { + break; // iMRU will point to matching entry + } + } + // move MRU strings before this one down + for (; iMRU > 0; iMRU--) { + ASSERT(iMRU > 0); + ASSERT(iMRU < m_nSize); + m_arrNames[iMRU] = m_arrNames[iMRU - 1]; + } + // place this one at the beginning + m_arrNames[0] = pathName; +} + +void CAppSettings::CRecentFileAndURLList::SetSize(int nSize) +{ + ENSURE_ARG(nSize >= 0); + + if (m_nSize != nSize) { + CString* arrNames = DEBUG_NEW CString[nSize]; + int nSizeToCopy = std::min(m_nSize, nSize); + for (int i = 0; i < nSizeToCopy; i++) { + arrNames[i] = m_arrNames[i]; + } + delete [] m_arrNames; + m_arrNames = arrNames; + m_nSize = nSize; + } +} + +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +CStringW getShortHash(PBYTE bytes, ULONG size) { + BCRYPT_ALG_HANDLE algHandle = nullptr; + BCRYPT_HASH_HANDLE hashHandle = nullptr; + + PBYTE hash = nullptr; + DWORD hashLen = 0; + DWORD cbResult = 0; + ULONG dwFlags = 0; + const int shortHashLen = 12; + + NTSTATUS stat; + CStringW shortHash = L""; + + stat = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_SHA1_ALGORITHM, nullptr, 0); + if (NT_SUCCESS(stat)) { + stat = BCryptGetProperty(algHandle, BCRYPT_HASH_LENGTH, (PBYTE)&hashLen, sizeof(hashLen), &cbResult, dwFlags); + if (NT_SUCCESS(stat)) { + hash = (PBYTE)HeapAlloc(GetProcessHeap(), dwFlags, hashLen); + if (nullptr != hash) { + stat = BCryptCreateHash(algHandle, &hashHandle, nullptr, 0, nullptr, 0, dwFlags); + if (NT_SUCCESS(stat)) { + stat = BCryptHashData(hashHandle, bytes, size, dwFlags); + if (NT_SUCCESS(stat)) { + stat = BCryptFinishHash(hashHandle, hash, hashLen, 0); + if (NT_SUCCESS(stat)) { + DWORD hashStrLen = 0; + if (CryptBinaryToStringW(hash, hashLen, CRYPT_STRING_BASE64, nullptr, &hashStrLen) && hashStrLen > 0) { + CStringW longHash; + if (CryptBinaryToStringW(hash, hashLen, CRYPT_STRING_BASE64, longHash.GetBuffer(hashStrLen - 1), &hashStrLen)) { + longHash.ReleaseBuffer(hashStrLen); + shortHash = longHash.Left(shortHashLen); + } else { + longHash.ReleaseBuffer(); + } + } + } + } + } + } + } + } + + if (nullptr != hash) { + HeapFree(GetProcessHeap(), dwFlags, hash); + } + + if (nullptr != hashHandle) { + BCryptDestroyHash(hashHandle); + } + + if (nullptr != algHandle) { + BCryptCloseAlgorithmProvider(algHandle, dwFlags); + } + + return shortHash; +} + +CStringW getRFEHash(CStringW fn) { + fn.MakeLower(); + CStringW hash = getShortHash((PBYTE)fn.GetString(), fn.GetLength() * sizeof(WCHAR)); + if (hash.IsEmpty()) { + ASSERT(FALSE); + hash = fn.Right(30); + hash.Replace(L"\\", L"/"); + } + return hash; +} + +CStringW getRFEHash(ULONGLONG llDVDGuid) { + CStringW hash; + hash.Format(L"DVD%llu", llDVDGuid); + return hash; +} + +CStringW getRFEHash(RecentFileEntry &r) { + CStringW fn; + if (r.DVDPosition.llDVDGuid) { + return getRFEHash(r.DVDPosition.llDVDGuid); + } else { + fn = r.fns.GetHead(); + return getRFEHash(fn); + } +} + +/* +void CAppSettings::CRecentFileListWithMoreInfo::Remove(size_t nIndex) { + if (nIndex >= 0 && nIndex < rfe_array.GetCount()) { + auto pApp = AfxGetMyApp(); + CStringW& hash = rfe_array[nIndex].hash; + if (!hash.IsEmpty()) { + pApp->RemoveProfileKey(m_section, hash); + } + rfe_array.RemoveAt(nIndex); + rfe_array.FreeExtra(); + } + if (nIndex == 0 && rfe_array.GetCount() == 0) { + // list was cleared + current_rfe_hash.Empty(); + } +} +*/ + +void CAppSettings::CRecentFileListWithMoreInfo::Add(LPCTSTR fn) { + RecentFileEntry r; + LoadMediaHistoryEntryFN(fn, r); + Add(r, true); +} + +void CAppSettings::CRecentFileListWithMoreInfo::Add(LPCTSTR fn, ULONGLONG llDVDGuid) { + RecentFileEntry r; + LoadMediaHistoryEntryDVD(llDVDGuid, fn, r); + Add(r, true); +} + +bool CAppSettings::CRecentFileListWithMoreInfo::GetCurrentIndex(size_t& idx) { + for (int i = 0; i < rfe_array.GetCount(); i++) { + if (rfe_array[i].hash == current_rfe_hash) { + idx = i; + return true; + } + } + return false; +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentFilePosition(REFERENCE_TIME time, bool forcePersist /* = false */) { + size_t idx; + if (GetCurrentIndex(idx)) { + rfe_array[idx].filePosition = time; + if (forcePersist || std::abs(persistedFilePosition - time) > 300000000) { + WriteMediaHistoryEntry(rfe_array[idx]); + } + } +} + +REFERENCE_TIME CAppSettings::CRecentFileListWithMoreInfo::GetCurrentFilePosition() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].filePosition; + } + return 0; +} + +ABRepeat CAppSettings::CRecentFileListWithMoreInfo::GetCurrentABRepeat() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].abRepeat; + } + return ABRepeat(); +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentDVDTimecode(DVD_HMSF_TIMECODE* time) { + size_t idx; + if (GetCurrentIndex(idx)) { + DVD_POSITION* dvdPosition = &rfe_array[idx].DVDPosition; + if (dvdPosition) { + memcpy(&dvdPosition->timecode, (void*)time, sizeof(DVD_HMSF_TIMECODE)); + } + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentDVDTitle(DWORD title) { + size_t idx; + if (GetCurrentIndex(idx)) { + DVD_POSITION* dvdPosition = &rfe_array[idx].DVDPosition; + if (dvdPosition) { + dvdPosition->lTitle = title; + } + } +} + +DVD_POSITION CAppSettings::CRecentFileListWithMoreInfo::GetCurrentDVDPosition() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].DVDPosition; + } + return DVD_POSITION(); +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentAudioTrack(int audioIndex) { + size_t idx; + if (GetCurrentIndex(idx)) { + if (rfe_array[idx].AudioTrackIndex != audioIndex) { + rfe_array[idx].AudioTrackIndex = audioIndex; + WriteMediaHistoryAudioIndex(rfe_array[idx]); + } + } +} + +int CAppSettings::CRecentFileListWithMoreInfo::GetCurrentAudioTrack() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].AudioTrackIndex; + } + return -1; +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentSubtitleTrack(int subIndex) { + size_t idx; + if (GetCurrentIndex(idx)) { + if (rfe_array[idx].SubtitleTrackIndex != subIndex) { + rfe_array[idx].SubtitleTrackIndex = subIndex; + WriteMediaHistorySubtitleIndex(rfe_array[idx]); + } + } +} + +int CAppSettings::CRecentFileListWithMoreInfo::GetCurrentSubtitleTrack() { + size_t idx; + if (GetCurrentIndex(idx)) { + return rfe_array[idx].SubtitleTrackIndex; + } + return -1; +} + +void CAppSettings::CRecentFileListWithMoreInfo::AddSubToCurrent(CStringW subpath) { + size_t idx; + if (GetCurrentIndex(idx)) { + bool found = rfe_array[idx].subs.Find(subpath); + if (!found) { + rfe_array[idx].subs.AddHead(subpath); + WriteMediaHistoryEntry(rfe_array[idx]); + } + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::SetCurrentTitle(CStringW title) { + size_t idx; + if (GetCurrentIndex(idx)) { + rfe_array[idx].title = title; + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::UpdateCurrentABRepeat(ABRepeat abRepeat) { + size_t idx; + if (GetCurrentIndex(idx)) { + rfe_array[idx].abRepeat = abRepeat; + WriteMediaHistoryEntry(rfe_array[idx]); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::WriteCurrentEntry() { + size_t idx; + if (!current_rfe_hash.IsEmpty() && GetCurrentIndex(idx)) { + WriteMediaHistoryEntry(rfe_array[idx]); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::Add(RecentFileEntry r, bool current_open) { + if (r.fns.GetCount() < 1) { + return; + } + if (CString(r.fns.GetHead()).MakeLower().Find(_T("@device:")) >= 0) { + return; + } + + if (r.hash.IsEmpty()) { + r.hash = getRFEHash(r); + } + for (size_t i = 0; i < rfe_array.GetCount(); i++) { + if (r.hash == rfe_array[i].hash) { + rfe_array.RemoveAt(i); //do not call Remove as it will purge reg key. we are just resorting + break; + } + } + WriteMediaHistoryEntry(r, true); + + rfe_array.InsertAt(0, r); + if (current_open) { + current_rfe_hash = r.hash; + persistedFilePosition = r.filePosition; + } + + // purge obsolete entry + if (rfe_array.GetCount() > m_maxSize) { + CStringW hash = rfe_array.GetAt(m_maxSize).hash; + if (!hash.IsEmpty()) { + CStringW subSection; + subSection.Format(L"%s\\%s", m_section, static_cast(hash)); + auto pApp = AfxGetMyApp(); + pApp->WriteProfileString(subSection, nullptr, nullptr); + } + rfe_array.SetCount(m_maxSize); + } + rfe_array.FreeExtra(); +} + +static void DeserializeHex(LPCTSTR strVal, BYTE* pBuffer, int nBufSize) { + long lRes; + + for (int i = 0; i < nBufSize; i++) { + _stscanf_s(strVal + (i * 2), _T("%02lx"), &lRes); + pBuffer[i] = (BYTE)lRes; + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::ReadLegacyMediaHistory(std::map& filenameToIndex) { + rfe_array.RemoveAll(); + auto pApp = AfxGetMyApp(); + LPCWSTR legacySection = L"Recent File List"; + int dvdCount = 0; + for (size_t i = 1; i <= m_maxSize; i++) { + CStringW t; + t.Format(_T("File%zu"), i); + CStringW fn = pApp->GetProfileStringW(legacySection, t); + if (fn.IsEmpty()) { + break; + } + t.Format(_T("Title%zu"), i); + CStringW title = pApp->GetProfileStringW(legacySection, t); + t.Format(_T("Cue%zu"), i); + CStringW cue = pApp->GetProfileStringW(legacySection, t); + RecentFileEntry r; + r.fns.AddTail(fn); + r.title = title; + r.cue = cue; + int k = 2; + for (;; k++) { + t.Format(_T("File%zu,%d"), i, k); + CStringW ft = pApp->GetProfileStringW(legacySection, t); + if (ft.IsEmpty()) break; + r.fns.AddTail(ft); + } + k = 1; + for (;; k++) { + t.Format(_T("Sub%zu,%d"), i, k); + CStringW st = pApp->GetProfileStringW(legacySection, t); + if (st.IsEmpty()) break; + r.subs.AddTail(st); + } + if (fn.Right(9) == L"\\VIDEO_TS") { //try to find the dvd position from index + CStringW strDVDPos; + strDVDPos.Format(_T("DVD Position %d"), dvdCount++); + CStringW strValue = pApp->GetProfileString(IDS_R_SETTINGS, strDVDPos, _T("")); + + if (!strValue.IsEmpty()) { + if (strValue.GetLength() / 2 == sizeof(DVD_POSITION)) { + DeserializeHex(strValue, (BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); + } + } + rfe_array.Add(r); + } else { + filenameToIndex[r.fns.GetHead()] = rfe_array.Add(r); + } + } + rfe_array.FreeExtra(); +} + +static CString SerializeHex(const BYTE* pBuffer, int nBufSize) { + CString strTemp; + CString strResult; + + for (int i = 0; i < nBufSize; i++) { + strTemp.Format(_T("%02x"), pBuffer[i]); + strResult += strTemp; + } + + return strResult; +} + +void CAppSettings::CRecentFileListWithMoreInfo::ReadLegacyMediaPosition(std::map& filenameToIndex) { + auto pApp = AfxGetMyApp(); + bool hasNextEntry = true; + CStringW strFilename; + CStringW strFilePos; + + for (int i = 0; i < 1000 && hasNextEntry; i++) { + strFilename.Format(_T("File Name %d"), i); + CStringW strFile = pApp->GetProfileString(IDS_R_SETTINGS, strFilename); + + if (strFile.IsEmpty()) { + hasNextEntry = false; + } else { + strFilePos.Format(_T("File Position %d"), i); + if (filenameToIndex.count(strFile)) { + size_t index = filenameToIndex[strFile]; + if (index < rfe_array.GetCount()) { + CStringW strValue = pApp->GetProfileString(IDS_R_SETTINGS, strFilePos); + rfe_array.GetAt(index).filePosition = _tstoi64(strValue); + } + } + // remove old values + pApp->WriteProfileString(IDS_R_SETTINGS, strFilename, nullptr); + pApp->WriteProfileString(IDS_R_SETTINGS, strFilePos, nullptr); + } + } +} + +bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntryFN(CStringW fn, RecentFileEntry& r) { + CStringW hash = getRFEHash(fn); + if (!LoadMediaHistoryEntry(hash, r)) { + r.hash = hash; + r.fns.AddHead(fn); //otherwise add a new entry + return false; + } + return true; +} + +bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntryDVD(ULONGLONG llDVDGuid, CStringW fn, RecentFileEntry& r) { + CStringW hash = getRFEHash(llDVDGuid); + if (!LoadMediaHistoryEntry(hash, r)) { + r.hash = hash; + r.fns.AddHead(fn); //otherwise add a new entry + r.DVDPosition.llDVDGuid = llDVDGuid; + return false; + } + return true; +} + +bool CAppSettings::CRecentFileListWithMoreInfo::LoadMediaHistoryEntry(CStringW hash, RecentFileEntry &r) { + auto pApp = AfxGetMyApp(); + CStringW fn, subSection, t; + + subSection.Format(L"%s\\%s", m_section, static_cast(hash)); + + fn = pApp->GetProfileStringW(subSection, L"Filename", L""); + if (fn.IsEmpty()) { + return false; + } + + DWORD filePosition = pApp->GetProfileIntW(subSection, L"FilePosition", 0); + CStringW dvdPosition = pApp->GetProfileStringW(subSection, L"DVDPosition", L""); + + r.hash = hash; + r.fns.AddHead(fn); + r.title = pApp->GetProfileStringW(subSection, L"Title", L""); + r.cue = pApp->GetProfileStringW(subSection, L"Cue", L""); + r.filePosition = filePosition * 10000LL; + if (!dvdPosition.IsEmpty()) { + if (dvdPosition.GetLength() / 2 == sizeof(DVD_POSITION)) { + DeserializeHex(dvdPosition, (BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); + } + } + r.abRepeat.positionA = pApp->GetProfileIntW(subSection, L"abRepeat.positionA", 0) * 10000LL; + r.abRepeat.positionB = pApp->GetProfileIntW(subSection, L"abRepeat.positionB", 0) * 10000LL; + r.abRepeat.dvdTitle = pApp->GetProfileIntW(subSection, L"abRepeat.dvdTitle", -1); + + int k = 2; + for (;; k++) { + t.Format(_T("Filename%03d"), k); + CStringW ft = pApp->GetProfileStringW(subSection, t); + if (ft.IsEmpty()) { + break; + } + r.fns.AddTail(ft); + } + k = 1; + for (;; k++) { + t.Format(_T("Sub%03d"), k); + CStringW st = pApp->GetProfileStringW(subSection, t); + if (st.IsEmpty()) { + break; + } + r.subs.AddTail(st); + } + + r.AudioTrackIndex = pApp->GetProfileIntW(subSection, L"AudioTrackIndex", -1); + r.SubtitleTrackIndex = pApp->GetProfileIntW(subSection, L"SubtitleTrackIndex", -1); + return true; +} + +void CAppSettings::CRecentFileListWithMoreInfo::ReadMediaHistory() { + auto pApp = AfxGetMyApp(); + + int lastAddedStored = pApp->GetProfileIntW(m_section, L"LastAdded", 0); + if (lastAddedStored != 0 && lastAddedStored == rfe_last_added || rfe_last_added == 1) { + return; + } + listModifySequence++; + + size_t maxsize = AfxGetAppSettings().fKeepHistory ? m_maxSize : 0; + + std::list hashes = pApp->GetSectionSubKeys(m_section); + + if (hashes.empty()) { + if (maxsize > 0) { + MigrateLegacyHistory(); + hashes = pApp->GetSectionSubKeys(m_section); + } else { + rfe_last_added = 1; + rfe_array.RemoveAll(); + return; + } + } + + auto timeToHash = CAppSettings::LoadHistoryHashes(m_section, L"LastOpened"); + + rfe_array.RemoveAll(); + int entries = 0; + for (auto iter = timeToHash.rbegin(); iter != timeToHash.rend(); ++iter) { + bool purge_rfe = true; + CStringW hash = iter->second; + if (entries < maxsize) { + RecentFileEntry r; + r.lastOpened = iter->first; + if (LoadMediaHistoryEntry(hash, r)) { + rfe_array.Add(r); + purge_rfe = false; + entries++; + } + } + if (purge_rfe) { //purge entry + CAppSettings::PurgeExpiredHash(m_section, hash); + } + } + rfe_array.FreeExtra(); + + if (lastAddedStored == 0 && m_maxSize > 0) { + rfe_last_added = 1; // history read, but nothing new added yet + pApp->WriteProfileInt(m_section, L"LastAdded", rfe_last_added); + } else { + rfe_last_added = lastAddedStored; + } + + // The playlist history size is not managed elsewhere + CAppSettings::PurgePlaylistHistory(maxsize); +} + +void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistoryAudioIndex(RecentFileEntry& r) { + auto pApp = AfxGetMyApp(); + + if (r.hash.IsEmpty()) { + r.hash = getRFEHash(r.fns.GetHead()); + } + + CStringW subSection, t; + subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); + + if (r.AudioTrackIndex != -1) { + pApp->WriteProfileInt(subSection, L"AudioTrackIndex", int(r.AudioTrackIndex)); + } else { + pApp->WriteProfileStringW(subSection, L"AudioTrackIndex", nullptr); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistorySubtitleIndex(RecentFileEntry& r) { + auto pApp = AfxGetMyApp(); + + if (r.hash.IsEmpty()) { + r.hash = getRFEHash(r.fns.GetHead()); + } + + CStringW subSection, t; + subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); + + if (r.SubtitleTrackIndex != -1) { + pApp->WriteProfileInt(subSection, L"SubtitleTrackIndex", int(r.SubtitleTrackIndex)); + } else { + pApp->WriteProfileStringW(subSection, L"SubtitleTrackIndex", nullptr); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::WriteMediaHistoryEntry(RecentFileEntry& r, bool updateLastOpened /* = false */) { + auto pApp = AfxGetMyApp(); + + if (r.hash.IsEmpty()) { + r.hash = getRFEHash(r.fns.GetHead()); + } + + CStringW subSection, t; + subSection.Format(L"%s\\%s", m_section, static_cast(r.hash)); + + CString storedFilename = pApp->GetProfileStringW(subSection, L"Filename", L""); + bool isNewEntry = storedFilename.IsEmpty(); + if (isNewEntry || storedFilename != r.fns.GetHead()) { + pApp->WriteProfileStringW(subSection, L"Filename", r.fns.GetHead()); + } + + if (r.fns.GetCount() > 1) { + int k = 2; + POSITION p(r.fns.GetHeadPosition()); + r.fns.GetNext(p); + while (p != nullptr) { + CString fn = r.fns.GetNext(p); + t.Format(L"Filename%03d", k); + pApp->WriteProfileStringW(subSection, t, fn); + k++; + } + } + if (!r.title.IsEmpty()) { + t = L"Title"; + pApp->WriteProfileStringW(subSection, t, r.title); + } + if (!r.cue.IsEmpty()) { + t = L"Cue"; + pApp->WriteProfileStringW(subSection, t, r.cue); + } + if (r.subs.GetCount() > 0) { + int k = 1; + POSITION p(r.subs.GetHeadPosition()); + while (p != nullptr) { + CString fn = r.subs.GetNext(p); + t.Format(L"Sub%03d", k); + pApp->WriteProfileStringW(subSection, t, fn); + k++; + } + } + if (r.DVDPosition.llDVDGuid) { + t = L"DVDPosition"; + CStringW strValue = SerializeHex((BYTE*)&r.DVDPosition, sizeof(DVD_POSITION)); + pApp->WriteProfileStringW(subSection, t, strValue); + } else { + t = L"FilePosition"; + pApp->WriteProfileInt(subSection, t, int(r.filePosition / 10000LL)); + persistedFilePosition = r.filePosition; + } + if (r.abRepeat.positionA) { + pApp->WriteProfileInt(subSection, L"abRepeat.positionA", int(r.abRepeat.positionA / 10000LL)); + } else { + pApp->WriteProfileStringW(subSection, L"abRepeat.positionA", nullptr); + } + if (r.abRepeat.positionB) { + pApp->WriteProfileInt(subSection, L"abRepeat.positionB", int(r.abRepeat.positionB / 10000LL)); + } else { + pApp->WriteProfileStringW(subSection, L"abRepeat.positionB", nullptr); + } + if (r.abRepeat && r.abRepeat.dvdTitle != -1) { + pApp->WriteProfileInt(subSection, L"abRepeat.dvdTitle", int(r.abRepeat.dvdTitle)); + } else { + pApp->WriteProfileStringW(subSection, L"abRepeat.dvdTitle", nullptr); + } + + if (r.AudioTrackIndex != -1) { + pApp->WriteProfileInt(subSection, L"AudioTrackIndex", int(r.AudioTrackIndex)); + } else { + pApp->WriteProfileStringW(subSection, L"AudioTrackIndex", nullptr); + } + + if (r.SubtitleTrackIndex != -1) { + pApp->WriteProfileInt(subSection, L"SubtitleTrackIndex", int(r.SubtitleTrackIndex)); + } else { + pApp->WriteProfileStringW(subSection, L"SubtitleTrackIndex", nullptr); + } + + if (updateLastOpened || isNewEntry || r.lastOpened.IsEmpty()) { + auto now = std::chrono::system_clock::now(); + auto nowISO = date::format(L"%FT%TZ", date::floor(now)); + r.lastOpened = CStringW(nowISO.c_str()); + pApp->WriteProfileStringW(subSection, L"LastOpened", r.lastOpened); + if (isNewEntry) { + rfe_last_added = (int)std::chrono::time_point_cast(now).time_since_epoch().count(); + pApp->WriteProfileInt(m_section, L"LastAdded", rfe_last_added); + } + } + listModifySequence++; +} + +void CAppSettings::CRecentFileListWithMoreInfo::SaveMediaHistory() { + if (rfe_array.GetCount()) { + //go in reverse in case we are setting last opened when migrating history (makes last appear oldest) + for (size_t i = rfe_array.GetCount() - 1, j = 0; j < m_maxSize && j < rfe_array.GetCount(); i--, j++) { + auto& r = rfe_array.GetAt(i); + WriteMediaHistoryEntry(r); + } + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::MigrateLegacyHistory() { + auto pApp = AfxGetMyApp(); + std::map filenameToIndex; + ReadLegacyMediaHistory(filenameToIndex); + ReadLegacyMediaPosition(filenameToIndex); + SaveMediaHistory(); + LPCWSTR legacySection = L"Recent File List"; + pApp->WriteProfileString(legacySection, nullptr, nullptr); +} + +void CAppSettings::CRecentFileListWithMoreInfo::SetSize(size_t nSize) { + m_maxSize = nSize; + if (rfe_array.GetCount() > m_maxSize) { + rfe_array.SetCount(m_maxSize); + PurgeMediaHistory(m_maxSize); + PurgePlaylistHistory(m_maxSize); + // to force update of recent files menu + listModifySequence++; + } + rfe_array.FreeExtra(); + + if (nSize == 0) { + current_rfe_hash.Empty(); + } +} + +void CAppSettings::CRecentFileListWithMoreInfo::RemoveAll() { + SetSize(0); +} + +bool CAppSettings::IsVSFilterInstalled() +{ + return IsCLSIDRegistered(CLSID_VSFilter); +} + +void CAppSettings::UpdateSettings() +{ + auto pApp = AfxGetMyApp(); + ASSERT(pApp); + + UINT version = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_R_VERSION, 0); + if (version >= APPSETTINGS_VERSION) { + return; // Nothing to update + } + + // Use lambda expressions to copy data entries + auto copyInt = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { + if (pApp->HasProfileEntry(oldSection, oldEntry)) { + int old = pApp->GetProfileInt(oldSection, oldEntry, 0); + VERIFY(pApp->WriteProfileInt(newSection, newEntry, old)); + } + }; + auto copyStr = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { + if (pApp->HasProfileEntry(oldSection, oldEntry)) { + CString old = pApp->GetProfileString(oldSection, oldEntry); + VERIFY(pApp->WriteProfileString(newSection, newEntry, old)); + } + }; + auto copyBin = [pApp](LPCTSTR oldSection, LPCTSTR oldEntry, LPCTSTR newSection, LPCTSTR newEntry) { + UINT len; + BYTE* old; + if (pApp->GetProfileBinary(oldSection, oldEntry, &old, &len)) { + VERIFY(pApp->WriteProfileBinary(newSection, newEntry, old, len)); + delete [] old; + } + }; + + + // Migrate to the latest version, these cases should fall through + // so that all incremental updates are applied. + switch (version) { + case 0: { + UINT nAudioBoostTmp = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, -1); + if (nAudioBoostTmp == UINT(-1)) { + double dAudioBoost_dB = _tstof(pApp->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, _T("0"))); + if (dAudioBoost_dB < 0 || dAudioBoost_dB > 10) { + dAudioBoost_dB = 0; + } + nAudioBoostTmp = UINT(100 * pow(10.0, dAudioBoost_dB / 20.0) + 0.5) - 100; + } + if (nAudioBoostTmp > 300) { // Max boost is 300% + nAudioBoostTmp = 300; + } + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_AUDIOBOOST, nAudioBoostTmp); + } + { + const CString section(_T("Settings")); + copyInt(section, _T("Remember DVD Pos"), section, _T("RememberDVDPos")); + copyInt(section, _T("Remember File Pos"), section, _T("RememberFilePos")); + copyInt(section, _T("Show OSD"), section, _T("ShowOSD")); + copyStr(section, _T("Shaders List"), section, _T("ShadersList")); + copyInt(section, _T("OSD_Size"), section, _T("OSDSize")); + copyStr(section, _T("OSD_Font"), section, _T("OSDFont")); + copyInt(section, _T("gotoluf"), section, _T("GoToLastUsed")); + copyInt(section, _T("fps"), section, _T("GoToFPS")); + } + { + // Copy DVB section + const CString oldSection(_T("DVB configuration")); + const CString newSection(_T("DVBConfiguration")); + //copyStr(oldSection, _T("BDANetworkProvider"), newSection, _T("BDANetworkProvider")); + copyStr(oldSection, _T("BDATuner"), newSection, _T("BDATuner")); + copyStr(oldSection, _T("BDAReceiver"), newSection, _T("BDAReceiver")); + copyInt(oldSection, _T("BDAScanFreqStart"), newSection, _T("BDAScanFreqStart")); + copyInt(oldSection, _T("BDAScanFreqEnd"), newSection, _T("BDAScanFreqEnd")); + copyInt(oldSection, _T("BDABandWidth"), newSection, _T("BDABandWidth")); + copyInt(oldSection, _T("BDAUseOffset"), newSection, _T("BDAUseOffset")); + copyInt(oldSection, _T("BDAOffset"), newSection, _T("BDAOffset")); + copyInt(oldSection, _T("BDAIgnoreEncryptedChannels"), newSection, _T("BDAIgnoreEncryptedChannels")); + copyInt(oldSection, _T("LastChannel"), newSection, _T("LastChannel")); + copyInt(oldSection, _T("RebuildFilterGraph"), newSection, _T("RebuildFilterGraph")); + copyInt(oldSection, _T("StopFilterGraph"), newSection, _T("StopFilterGraph")); + for (int iChannel = 0; ; iChannel++) { + CString strTemp, strChannel; + strTemp.Format(_T("%d"), iChannel); + if (!pApp->HasProfileEntry(oldSection, strTemp)) { + break; + } + strChannel = pApp->GetProfileString(oldSection, strTemp); + if (strChannel.IsEmpty()) { + break; + } + VERIFY(pApp->WriteProfileString(newSection, strTemp, strChannel)); + } + } + [[fallthrough]]; + case 1: { + // Internal decoding of WMV 1/2/3 is now disabled by default so we reinitialize its value + pApp->WriteProfileInt(IDS_R_INTERNAL_FILTERS, _T("TRA_WMV"), FALSE); + } + [[fallthrough]]; + case 2: { + const CString section(_T("Settings")); + if (pApp->HasProfileEntry(section, _T("FullScreenCtrls")) && + pApp->HasProfileEntry(section, _T("FullScreenCtrlsTimeOut"))) { + bool bHide = true; + int nHidePolicy = 0; + int nTimeout = -1; + if (!pApp->GetProfileInt(section, _T("FullScreenCtrls"), 0)) { + // hide always + } else { + nTimeout = pApp->GetProfileInt(section, _T("FullScreenCtrlsTimeOut"), 0); + if (nTimeout < 0) { + // show always + bHide = false; + } else if (nTimeout == 0) { + // show when hovered + nHidePolicy = 1; + } else { + // show when mouse moved + nHidePolicy = 2; + } + } + VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControls"), bHide)); + if (nTimeout >= 0) { + VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControlsPolicy"), nHidePolicy)); + VERIFY(pApp->WriteProfileInt(section, _T("HideFullscreenControlsDelay"), nTimeout * 1000)); + } + } + } + [[fallthrough]]; + case 3: { +#pragma pack(push, 1) + struct dispmode { + bool fValid; + CSize size; + int bpp, freq; + DWORD dmDisplayFlags; + }; + + struct fpsmode { + double vfr_from; + double vfr_to; + bool fChecked; + dispmode dmFSRes; + bool fIsData; + }; + + struct AChFR { + bool bEnabled; + fpsmode dmFullscreenRes[30]; + bool bApplyDefault; + }; //AutoChangeFullscrRes +#pragma pack(pop) + + LPBYTE ptr; + UINT len; + bool bSetDefault = true; + if (pApp->GetProfileBinary(IDS_R_SETTINGS, _T("FullscreenRes"), &ptr, &len)) { + if (len == sizeof(AChFR)) { + AChFR autoChangeFullscrRes; + memcpy(&autoChangeFullscrRes, ptr, sizeof(AChFR)); + + autoChangeFSMode.bEnabled = autoChangeFullscrRes.bEnabled; + autoChangeFSMode.bApplyDefaultModeAtFSExit = autoChangeFullscrRes.bApplyDefault; + + for (size_t i = 0; i < _countof(autoChangeFullscrRes.dmFullscreenRes); i++) { + const auto& modeOld = autoChangeFullscrRes.dmFullscreenRes[i]; + // The old settings could be corrupted quite easily so be careful when converting them + if (modeOld.fIsData + && modeOld.vfr_from >= 0.0 && modeOld.vfr_from <= 126.0 + && modeOld.vfr_to >= 0.0 && modeOld.vfr_to <= 126.0 + && modeOld.dmFSRes.fValid + && modeOld.dmFSRes.bpp == 32 + && modeOld.dmFSRes.size.cx >= 640 && modeOld.dmFSRes.size.cx < 10000 + && modeOld.dmFSRes.size.cy >= 380 && modeOld.dmFSRes.size.cy < 10000 + && modeOld.dmFSRes.freq > 0 && modeOld.dmFSRes.freq < 1000) { + DisplayMode dm; + dm.bValid = true; + dm.size = modeOld.dmFSRes.size; + dm.bpp = 32; + dm.freq = modeOld.dmFSRes.freq; + dm.dwDisplayFlags = modeOld.dmFSRes.dmDisplayFlags & DM_INTERLACED; + + autoChangeFSMode.modes.emplace_back(modeOld.fChecked, modeOld.vfr_from, modeOld.vfr_to, 0, std::move(dm)); + } + } + + bSetDefault = autoChangeFSMode.modes.empty() || autoChangeFSMode.modes[0].dFrameRateStart != 0.0 || autoChangeFSMode.modes[0].dFrameRateStop != 0.0; + } + delete [] ptr; + } + + if (bSetDefault) { + autoChangeFSMode.bEnabled = false; + autoChangeFSMode.bApplyDefaultModeAtFSExit = false; + autoChangeFSMode.modes.clear(); + } + autoChangeFSMode.bRestoreResAfterProgExit = !!pApp->GetProfileInt(IDS_R_SETTINGS, _T("RestoreResAfterExit"), TRUE); + autoChangeFSMode.uDelay = pApp->GetProfileInt(IDS_R_SETTINGS, _T("FullscreenResDelay"), 0); + + SaveSettingsAutoChangeFullScreenMode(); + } + [[fallthrough]]; + case 4: { + bool bDisableSubtitleAnimation = !pApp->GetProfileInt(IDS_R_SETTINGS, _T("SPCAllowAnimationWhenBuffering"), TRUE); + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DISABLE_SUBTITLE_ANIMATION, bDisableSubtitleAnimation)); + } + [[fallthrough]]; + case 5: + copyInt(IDS_R_INTERNAL_FILTERS, _T("SRC_DTSAC3"), IDS_R_INTERNAL_FILTERS, _T("SRC_DTS")); + copyInt(IDS_R_INTERNAL_FILTERS, _T("SRC_DTSAC3"), IDS_R_INTERNAL_FILTERS, _T("SRC_AC3")); + [[fallthrough]]; + case 6: { + SubtitleRenderer subrenderer = SubtitleRenderer::INTERNAL; + if (!pApp->GetProfileInt(IDS_R_SETTINGS, _T("AutoloadSubtitles"), TRUE)) { + if (IsSubtitleRendererRegistered(SubtitleRenderer::VS_FILTER)) { + subrenderer = SubtitleRenderer::VS_FILTER; + } + if (IsSubtitleRendererRegistered(SubtitleRenderer::XY_SUB_FILTER)) { + int renderer = IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS; + renderer = pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, renderer); + if (IsSubtitleRendererSupported(SubtitleRenderer::XY_SUB_FILTER, renderer)) { + subrenderer = SubtitleRenderer::XY_SUB_FILTER; + } + } + } + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_SUBTITLE_RENDERER, static_cast(subrenderer))); + } + [[fallthrough]]; + case 7: + // Update the settings after the removal of DirectX 7 renderers + switch (pApp->GetProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_DEFAULT)) { + case 3: // VIDRNDT_DS_VMR7WINDOWED + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_VMR9WINDOWED)); + break; + case 5: // VIDRNDT_DS_VMR7RENDERLESS + VERIFY(pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_DSVIDEORENDERERTYPE, VIDRNDT_DS_VMR9RENDERLESS)); + break; + } + [[fallthrough]]; + default: + pApp->WriteProfileInt(IDS_R_SETTINGS, IDS_R_VERSION, APPSETTINGS_VERSION); + } +} + +// RenderersSettings.h + +CRenderersData* GetRenderersData() { + return &AfxGetMyApp()->m_Renderers; +} + +CRenderersSettings& GetRenderersSettings() { + auto& s = AfxGetAppSettings(); + if (s.m_RenderersSettings.subPicQueueSettings.nSize > 0) { + // queue does not work properly with libass + if (s.bRenderSSAUsingLibass || s.bRenderSRTUsingLibass) { + s.m_RenderersSettings.subPicQueueSettings.nSize = 0; + } + } + return s.m_RenderersSettings; +} + +void CAppSettings::SavePlayListPosition(CStringW playlistPath, UINT position) { + auto pApp = AfxGetMyApp(); + ASSERT(pApp); + + auto hash = getRFEHash(playlistPath); + + CStringW subSection, t; + subSection.Format(L"%s\\%s", L"PlaylistHistory", static_cast(hash)); + pApp->WriteProfileInt(subSection, L"Position", position); + + auto now = std::chrono::system_clock::now(); + auto nowISO = date::format(L"%FT%TZ", date::floor(now)); + CStringW lastUpdated = CStringW(nowISO.c_str()); + pApp->WriteProfileStringW(subSection, L"LastUpdated", lastUpdated); +} + +UINT CAppSettings::GetSavedPlayListPosition(CStringW playlistPath) { + auto pApp = AfxGetMyApp(); + ASSERT(pApp); + + auto hash = getRFEHash(playlistPath); + + CStringW subSection, t; + subSection.Format(L"%s\\%s", L"PlaylistHistory", static_cast(hash)); + UINT position = pApp->GetProfileIntW(subSection, L"Position", -1); + if (position != (UINT)-1) { + return position; + } + return 0; +} + +// SubRendererSettings.h + +// Todo: move individual members of AppSettings into SubRendererSettings struct and use this function to get a reference to it +SubRendererSettings GetSubRendererSettings() { + const auto& s = AfxGetAppSettings(); + SubRendererSettings srs; + srs.defaultStyle = s.subtitlesDefStyle; + srs.overrideDefaultStyle = s.bSubtitleOverrideDefaultStyle || s.bSubtitleOverrideAllStyles; + srs.overrideAllStyles = s.bSubtitleOverrideAllStyles; +#if USE_LIBASS + srs.renderSSAUsingLibass = s.bRenderSSAUsingLibass; + srs.renderSRTUsingLibass = s.bRenderSRTUsingLibass; +#endif + OpenTypeLang::CStringAtoHintStr(srs.openTypeLangHint, s.strOpenTypeLangHint); + return srs; +} diff --git a/src/mpc-hc/AppSettings.h b/src/mpc-hc/AppSettings.h index 64efcac850b..1ab8e4dc6d7 100644 --- a/src/mpc-hc/AppSettings.h +++ b/src/mpc-hc/AppSettings.h @@ -1,1076 +1,1076 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#pragma once -#include "mpc-hc_config.h" -#include "../Subtitles/STS.h" -#include "../filters/switcher/AudioSwitcher/AudioSwitcher.h" -#include "../thirdparty/sanear/src/Interfaces.h" -#include "DVBChannel.h" -#include "FileAssoc.h" -#include "FilterEnum.h" -#include "MediaFormats.h" -#include "../filters/renderer/VideoRenderers/RenderersSettings.h" -#include "SettingsDefines.h" -#include "Shaders.h" -#include "../Subtitles/SubRendererSettings.h" -#include -#include -#include "CMPCTheme.h" - - -class FilterOverride; - -// flags for CAppSettings::nCS -enum { - CS_NONE = 0, - CS_SEEKBAR = 1, - CS_TOOLBAR = CS_SEEKBAR << 1, - CS_INFOBAR = CS_TOOLBAR << 1, - CS_STATSBAR = CS_INFOBAR << 1, - CS_STATUSBAR = CS_STATSBAR << 1, - CS_LAST = CS_STATUSBAR -}; - -enum : UINT64 { - CLSW_NONE = 0, - CLSW_OPEN = 1, - CLSW_PLAY = CLSW_OPEN << 1, - CLSW_CLOSE = CLSW_PLAY << 1, - CLSW_STANDBY = CLSW_CLOSE << 1, - CLSW_HIBERNATE = CLSW_STANDBY << 1, - CLSW_SHUTDOWN = CLSW_HIBERNATE << 1, - CLSW_LOGOFF = CLSW_SHUTDOWN << 1, - CLSW_LOCK = CLSW_LOGOFF << 1, - CLSW_MONITOROFF = CLSW_LOCK << 1, - CLSW_PLAYNEXT = CLSW_MONITOROFF << 1, - CLSW_DONOTHING = CLSW_PLAYNEXT << 1, - CLSW_AFTERPLAYBACK_MASK = CLSW_CLOSE | CLSW_STANDBY | CLSW_SHUTDOWN | CLSW_HIBERNATE | CLSW_LOGOFF | CLSW_LOCK | CLSW_MONITOROFF | CLSW_PLAYNEXT | CLSW_DONOTHING, - CLSW_FULLSCREEN = CLSW_DONOTHING << 1, - CLSW_NEW = CLSW_FULLSCREEN << 1, - CLSW_HELP = CLSW_NEW << 1, - CLSW_DVD = CLSW_HELP << 1, - CLSW_CD = CLSW_DVD << 1, - CLSW_DEVICE = CLSW_CD << 1, - CLSW_ADD = CLSW_DEVICE << 1, - CLSW_RANDOMIZE = CLSW_ADD << 1, - CLSW_MINIMIZED = CLSW_RANDOMIZE << 1, - CLSW_REGEXTVID = CLSW_MINIMIZED << 1, - CLSW_REGEXTAUD = CLSW_REGEXTVID << 1, - CLSW_REGEXTPL = CLSW_REGEXTAUD << 1, - CLSW_UNREGEXT = CLSW_REGEXTPL << 1, - CLSW_ICONSASSOC = CLSW_UNREGEXT << 1, - CLSW_STARTVALID = CLSW_ICONSASSOC << 1, - CLSW_NOFOCUS = CLSW_STARTVALID << 1, - CLSW_FIXEDSIZE = CLSW_NOFOCUS << 1, - CLSW_MONITOR = CLSW_FIXEDSIZE << 1, - CLSW_D3DFULLSCREEN = CLSW_MONITOR << 1, - CLSW_ADMINOPTION = CLSW_D3DFULLSCREEN << 1, - CLSW_SLAVE = CLSW_ADMINOPTION << 1, - CLSW_AUDIORENDERER = CLSW_SLAVE << 1, - CLSW_RESET = CLSW_AUDIORENDERER << 1, - CLSW_PRESET1 = CLSW_RESET << 1, - CLSW_PRESET2 = CLSW_PRESET1 << 1, - CLSW_PRESET3 = CLSW_PRESET2 << 1, - CLSW_CONFIGLAVSPLITTER = CLSW_PRESET3 << 1, - CLSW_CONFIGLAVAUDIO = CLSW_CONFIGLAVSPLITTER << 1, - CLSW_CONFIGLAVVIDEO = CLSW_CONFIGLAVAUDIO << 1, - CLSW_MUTE = CLSW_CONFIGLAVVIDEO << 1, - CLSW_VOLUME = CLSW_MUTE << 1, - CLSW_THUMBNAILS = CLSW_VOLUME << 1, - CLSW_UNRECOGNIZEDSWITCH = CLSW_THUMBNAILS << 1, // 47 -}; - -enum MpcCaptionState { - MODE_SHOWCAPTIONMENU, - MODE_HIDEMENU, - MODE_FRAMEONLY, - MODE_BORDERLESS, - MODE_COUNT -}; // flags for Caption & Menu Mode - -enum { - VIDRNDT_DS_DEFAULT = 0, - VIDRNDT_DS_OVERLAYMIXER = 2, - VIDRNDT_DS_VMR9WINDOWED = 4, - VIDRNDT_DS_VMR9RENDERLESS = 6, - VIDRNDT_DS_DXR = 7, - VIDRNDT_DS_NULL_COMP = 8, - VIDRNDT_DS_NULL_UNCOMP = 9, - VIDRNDT_DS_EVR = 10, - VIDRNDT_DS_EVR_CUSTOM = 11, - VIDRNDT_DS_MADVR = 12, - VIDRNDT_DS_SYNC = 13, - VIDRNDT_DS_MPCVR = 14, -}; - -// Enumeration for MCE remote control (careful : add 0x010000 for all keys!) -enum MCE_RAW_INPUT { - MCE_DETAILS = 0x010209, - MCE_GUIDE = 0x01008D, - MCE_TVJUMP = 0x010025, - MCE_STANDBY = 0x010082, - MCE_OEM1 = 0x010080, - MCE_OEM2 = 0x010081, - MCE_MYTV = 0x010046, - MCE_MYVIDEOS = 0x01004A, - MCE_MYPICTURES = 0x010049, - MCE_MYMUSIC = 0x010047, - MCE_RECORDEDTV = 0x010048, - MCE_DVDANGLE = 0x01004B, - MCE_DVDAUDIO = 0x01004C, - MCE_DVDMENU = 0x010024, - MCE_DVDSUBTITLE = 0x01004D, - MCE_RED = 0x01005B, - MCE_GREEN = 0x01005C, - MCE_YELLOW = 0x01005D, - MCE_BLUE = 0x01005E, - MCE_MEDIA_NEXTTRACK = 0x0100B5, - MCE_MEDIA_PREVIOUSTRACK = 0x0100B6 -}; - -#define AUDRNDT_NULL_COMP _T("Null Audio Renderer (Any)") -#define AUDRNDT_NULL_UNCOMP _T("Null Audio Renderer (Uncompressed)") -#define AUDRNDT_INTERNAL _T("Internal Audio Renderer") // Use this as device name for SaneAR -#define AUDRNDT_SANEAR _T("SaneAR Audio Renderer") // This only as title -#define AUDRNDT_MPC L"MPC Audio Renderer" - - -#define DEFAULT_SUBTITLE_PATHS _T(".;.\\subtitles;.\\subs") -#define DEFAULT_JUMPDISTANCE_1 1000 -#define DEFAULT_JUMPDISTANCE_2 5000 -#define DEFAULT_JUMPDISTANCE_3 20000 - -#define MIN_AUTOFIT_SCALE_FACTOR 25 -#define MAX_AUTOFIT_SCALE_FACTOR 100 -#define DEF_MIN_AUTOFIT_SCALE_FACTOR 40 -#define DEF_MAX_AUTOFIT_SCALE_FACTOR 80 - -#define NO_FIXED_POSITION CPoint(INT_MIN, INT_MIN) - -enum dvstype { - DVS_HALF, - DVS_NORMAL, - DVS_DOUBLE, - DVS_STRETCH, - DVS_FROMINSIDE, - DVS_FROMOUTSIDE, - DVS_ZOOM1, - DVS_ZOOM2 -}; - -enum favtype { - FAV_FILE, - FAV_DVD, - FAV_DEVICE -}; - -enum { - TIME_TOOLTIP_ABOVE_SEEKBAR, - TIME_TOOLTIP_BELOW_SEEKBAR -}; - -enum DVB_RebuildFilterGraph { - DVB_REBUILD_FG_NEVER = 0, - DVB_REBUILD_FG_WHEN_SWITCHING, - DVB_REBUILD_FG_ALWAYS -}; - -enum DVB_StopFilterGraph { - DVB_STOP_FG_NEVER = 0, - DVB_STOP_FG_WHEN_SWITCHING, - DVB_STOP_FG_ALWAYS -}; - -struct ShaderC { - CString label; - CString profile; - CString srcdata; - ULONGLONG length = 0; - FILETIME ftwrite = {0,0}; - - bool Match(LPCWSTR _label, const bool _bD3D11) const { - return (label.CompareNoCase(_label) == 0 && (_bD3D11 == (profile == "ps_4_0"))); - } -}; - -struct DisplayMode { - bool bValid = false; - CSize size; - int bpp = 0, freq = 0; - DWORD dwDisplayFlags = 0; - - bool operator == (const DisplayMode& dm) const { - return (bValid == dm.bValid && size == dm.size && bpp == dm.bpp && freq == dm.freq && dwDisplayFlags == dm.dwDisplayFlags); - }; - - bool operator < (const DisplayMode& dm) const { - bool bRet = false; - - // Ignore bValid when sorting - if (size.cx < dm.size.cx) { - bRet = true; - } else if (size.cx == dm.size.cx) { - if (size.cy < dm.size.cy) { - bRet = true; - } else if (size.cy == dm.size.cy) { - if (freq < dm.freq) { - bRet = true; - } else if (freq == dm.freq) { - if (bpp < dm.bpp) { - bRet = true; - } else if (bpp == dm.bpp) { - bRet = (dwDisplayFlags & DM_INTERLACED) && !(dm.dwDisplayFlags & DM_INTERLACED); - } - } - } - } - - return bRet; - }; -}; - -struct AutoChangeMode { - AutoChangeMode(bool _bChecked, double _dFrameRateStart, double _dFrameRateStop, int _msAudioDelay, DisplayMode _dm) - : bChecked(_bChecked) - , dFrameRateStart(_dFrameRateStart) - , dFrameRateStop(_dFrameRateStop) - , msAudioDelay(_msAudioDelay) - , dm(std::move(_dm)) { - } - - bool bChecked; - double dFrameRateStart; - double dFrameRateStop; - int msAudioDelay; - DisplayMode dm; -}; - -struct AutoChangeFullscreenMode { - bool bEnabled = false; - std::vector modes; - bool bApplyDefaultModeAtFSExit = false; - bool bRestoreResAfterProgExit = true; - unsigned uDelay = 0u; -}; - -#define ACCEL_LIST_SIZE 201 - -struct wmcmd_base : public ACCEL { - BYTE mouse; - BYTE mouseVirt; - DWORD dwname; - UINT appcmd; - - enum : BYTE { - NONE, - LDOWN, - LUP, - LDBLCLK, - MDOWN, - MUP, - MDBLCLK, - RDOWN, - RUP, - RDBLCLK, - X1DOWN, - X1UP, - X1DBLCLK, - X2DOWN, - X2UP, - X2DBLCLK, - WUP, - WDOWN, - WRIGHT, - WLEFT, - LAST - }; - - wmcmd_base() - : ACCEL( { - 0, 0, 0 - }) - , mouse(NONE) - , mouseVirt(0) - , dwname(0) - , appcmd(0) {} - - constexpr wmcmd_base(WORD _cmd, WORD _key, BYTE _fVirt, DWORD _dwname, UINT _appcmd = 0, BYTE _mouse = NONE, BYTE _mouseVirt = 0) - : ACCEL{ _fVirt, _key, _cmd } - , mouse(_mouse) - , mouseVirt(_mouseVirt) - , dwname(_dwname) - , appcmd(_appcmd) {} - - constexpr wmcmd_base(const wmcmd_base&) = default; - constexpr wmcmd_base(wmcmd_base&&) = default; - wmcmd_base& operator=(const wmcmd_base&) = default; - wmcmd_base& operator=(wmcmd_base&&) = default; -}; - -class wmcmd : public wmcmd_base -{ - const wmcmd_base* default_cmd = nullptr; - -public: - CStringA rmcmd; - int rmrepcnt = 5; - - wmcmd() = default; - wmcmd& operator=(const wmcmd&) = default; - wmcmd& operator=(wmcmd&&) = default; - - explicit wmcmd(const wmcmd_base& cmd) - : wmcmd_base(cmd) - , default_cmd(&cmd) - , rmrepcnt(5) { - } - - bool operator == (const wmcmd& wc) const { - return cmd > 0 && cmd == wc.cmd; - } - - CString GetName() const { - return ResStr(dwname); - } - - void Restore() { - ASSERT(default_cmd); - *static_cast(this) = *static_cast(default_cmd); - appcmd = default_cmd->appcmd; - mouse = default_cmd->mouse; - mouseVirt = default_cmd->mouseVirt; - rmcmd.Empty(); - rmrepcnt = 5; - } - - bool IsModified() const { - ASSERT(default_cmd); - return memcmp(static_cast(this), static_cast(default_cmd), sizeof(ACCEL)) || - appcmd != default_cmd->appcmd || - mouse != default_cmd->mouse || - mouseVirt != default_cmd->mouseVirt || - !rmcmd.IsEmpty() || - rmrepcnt != 5; - } -}; - -class CRemoteCtrlClient : public CAsyncSocket -{ -protected: - CCritSec m_csLock; - CWnd* m_pWnd; - enum { - DISCONNECTED, - CONNECTED, - CONNECTING - } m_nStatus; - CString m_addr; - - virtual void OnConnect(int nErrorCode); - virtual void OnClose(int nErrorCode); - virtual void OnReceive(int nErrorCode); - - virtual void OnCommand(CStringA str) = 0; - - void ExecuteCommand(CStringA cmd, int repcnt); - -public: - CRemoteCtrlClient(); - void SetHWND(HWND hWnd); - void Connect(CString addr); - void DisConnect(); - int GetStatus() const { - return m_nStatus; - } -}; - -class CWinLircClient : public CRemoteCtrlClient -{ -protected: - virtual void OnCommand(CStringA str); - -public: - CWinLircClient(); -}; - -class CUIceClient : public CRemoteCtrlClient -{ -protected: - virtual void OnCommand(CStringA str); - -public: - CUIceClient(); -}; - -#define APPSETTINGS_VERSION 8 - -struct DVD_POSITION { - ULONGLONG llDVDGuid = 0; - ULONG lTitle = 0; - DVD_HMSF_TIMECODE timecode = { 0 }; -}; - -struct ABRepeat { - ABRepeat() : positionA(0), positionB(0), dvdTitle(-1) {} - operator bool() const { return positionA || positionB; }; - REFERENCE_TIME positionA, positionB; - ULONG dvdTitle; //whatever title they saved last will be the only one we remember -}; - -class RecentFileEntry { -public: - RecentFileEntry() {} - void InitEntry(const RecentFileEntry& r) { - hash = r.hash; - cue = r.cue; - title = r.title; - lastOpened = r.lastOpened; - filePosition = r.filePosition; - DVDPosition = r.DVDPosition; - fns.RemoveAll(); - subs.RemoveAll(); - fns.AddHeadList(&r.fns); - subs.AddHeadList(&r.subs); - abRepeat = r.abRepeat; - AudioTrackIndex = r.AudioTrackIndex; - SubtitleTrackIndex = r.SubtitleTrackIndex; - } - RecentFileEntry(const RecentFileEntry &r) { - InitEntry(r); - } - - CStringW hash; - CString title; - CString lastOpened; - CAtlList fns; - CString cue; - CAtlList subs; - REFERENCE_TIME filePosition=0; - DVD_POSITION DVDPosition = {}; - ABRepeat abRepeat; - int AudioTrackIndex = -1; - int SubtitleTrackIndex = -1; - - void operator=(const RecentFileEntry &r) { - InitEntry(r); - } -}; - -class CAppSettings -{ - bool bInitialized = false; - - 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 - - void SetSize(int nSize); - }; - - class CRecentFileListWithMoreInfo - { - public: - CRecentFileListWithMoreInfo(LPCTSTR lpszSection, int nSize) - : m_section(lpszSection) - , m_maxSize(nSize) - , current_rfe_hash(L"") - {} - - CAtlArray rfe_array; - size_t m_maxSize; - LPCTSTR m_section; - REFERENCE_TIME persistedFilePosition = 0; - CString current_rfe_hash; - int rfe_last_added = 0; - int listModifySequence = 0; - - int GetSize() { - return (int)rfe_array.GetCount(); - } - - RecentFileEntry& operator[](size_t nIndex) { - ASSERT(nIndex >= 0 && nIndex < rfe_array.GetCount()); - return rfe_array[nIndex]; - } - - //void Remove(size_t nIndex); - void Add(LPCTSTR fn); - void Add(LPCTSTR fn, ULONGLONG llDVDGuid); - void Add(RecentFileEntry r, bool current_open = false); - bool GetCurrentIndex(size_t& idx); - void UpdateCurrentFilePosition(REFERENCE_TIME time, bool forcePersist = false); - REFERENCE_TIME GetCurrentFilePosition(); - ABRepeat GetCurrentABRepeat(); - void UpdateCurrentDVDTimecode(DVD_HMSF_TIMECODE *time); - void UpdateCurrentDVDTitle(DWORD title); - DVD_POSITION GetCurrentDVDPosition(); - void UpdateCurrentAudioTrack(int audioIndex); - int GetCurrentAudioTrack(); - void UpdateCurrentSubtitleTrack(int audioIndex); - int GetCurrentSubtitleTrack(); - void AddSubToCurrent(CStringW subpath); - void SetCurrentTitle(CStringW subpath); - void UpdateCurrentABRepeat(ABRepeat abRepeat); - void WriteCurrentEntry(); - void ReadMediaHistory(); - void WriteMediaHistoryAudioIndex(RecentFileEntry& r); - void WriteMediaHistorySubtitleIndex(RecentFileEntry& r); - void WriteMediaHistoryEntry(RecentFileEntry& r, bool updateLastOpened = false); - void SaveMediaHistory(); - void ReadLegacyMediaHistory(std::map &filenameToIndex); - void ReadLegacyMediaPosition(std::map &filenameToIndex); - bool LoadMediaHistoryEntryFN(CStringW fn, RecentFileEntry& r); - bool LoadMediaHistoryEntryDVD(ULONGLONG llDVDGuid, CStringW fn, RecentFileEntry& r); - bool LoadMediaHistoryEntry(CStringW hash, RecentFileEntry& r); - void MigrateLegacyHistory(); - void SetSize(size_t nSize); - void RemoveAll(); - }; - -public: - // cmdline params - UINT64 nCLSwitches; - CAtlList slFiles, slDubs, slSubs, slFilters; - static std::map CommandIDToWMCMD; - - // Initial position (used by command line flags) - REFERENCE_TIME rtShift; - REFERENCE_TIME rtStart; - ABRepeat abRepeat; - ULONG lDVDTitle; - ULONG lDVDChapter; - DVD_HMSF_TIMECODE DVDPosition; - - CSize sizeFixedWindow; - CPoint fixedWindowPosition; - bool HasFixedWindowSize() const { - return sizeFixedWindow.cx > 0 || sizeFixedWindow.cy > 0; - } - //int iFixedWidth, iFixedHeight; - int iMonitor; - - CString ParseFileName(CString const& param); - void ParseCommandLine(CAtlList& cmdln); - - // Added a Debug display to the screen (/debug option) - bool fShowDebugInfo; - int iAdminOption; - - - // Player - bool fAllowMultipleInst; - bool fTrayIcon; - bool fShowOSD; - bool fShowCurrentTimeInOSD; - int nOSDTransparency; - int nOSDBorder; - - bool fLimitWindowProportions; - bool fSnapToDesktopEdges; - bool fHideCDROMsSubMenu; - DWORD dwPriority; - int iTitleBarTextStyle; - bool fTitleBarTextTitle; - bool fKeepHistory; - int iRecentFilesNumber; - CRecentFileListWithMoreInfo MRU; - CRecentFileAndURLList MRUDub; - bool fRememberDVDPos; - bool fRememberFilePos; - int iRememberPosForLongerThan; - bool bRememberPosForAudioFiles; - bool bRememberExternalPlaylistPos; - bool bRememberTrackSelection; - bool bRememberPlaylistItems; - bool fRememberWindowPos; - CRect rcLastWindowPos; - bool fRememberWindowSize; - bool fSavePnSZoom; - double dZoomX; - double dZoomY; - - // Formats - CMediaFormats m_Formats; - bool fAssociatedWithIcons; - - // Keys - CList wmcmds; - HACCEL hAccel; - bool fWinLirc; - CString strWinLircAddr; - CWinLircClient WinLircClient; - bool fUIce; - CString strUIceAddr; - CUIceClient UIceClient; - bool fGlobalMedia; - - // Mouse - UINT nMouseLeftClick; - bool bMouseLeftClickOpenRecent; - UINT nMouseLeftDblClick; - bool bMouseEasyMove; - UINT nMouseRightClick; - struct MOUSE_ASSIGNMENT { - UINT normal; - UINT ctrl; - UINT shift; - UINT rbtn; - }; - MOUSE_ASSIGNMENT MouseMiddleClick; - MOUSE_ASSIGNMENT MouseX1Click; - MOUSE_ASSIGNMENT MouseX2Click; - MOUSE_ASSIGNMENT MouseWheelUp; - MOUSE_ASSIGNMENT MouseWheelDown; - MOUSE_ASSIGNMENT MouseWheelLeft; - MOUSE_ASSIGNMENT MouseWheelRight; - - // Logo - int nLogoId; - bool fLogoExternal; - BOOL fLogoColorProfileEnabled; - CString strLogoFileName; - - // Web Inteface - bool fEnableWebServer; - int nWebServerPort; - int nCmdlnWebServerPort; - bool fWebServerUseCompression; - bool fWebServerLocalhostOnly; - bool bWebUIEnablePreview; - bool fWebServerPrintDebugInfo; - CString strWebRoot, strWebDefIndex; - CString strWebServerCGI; - - // Playback - int nVolume; - bool fMute; - int nBalance; - int nLoops; - bool fLoopForever; - - enum class LoopMode { - FILE, - PLAYLIST - } eLoopMode; - - bool fRememberZoomLevel; - int nAutoFitFactorMin; - int nAutoFitFactorMax; - int iZoomLevel; - CStringW strAudiosLanguageOrder; - CStringW strSubtitlesLanguageOrder; - bool fEnableWorkerThreadForOpening; - bool fReportFailedPins; - bool fAutoloadAudio; - bool fBlockVSFilter; - bool bBlockRDP; - UINT nVolumeStep; - UINT nSpeedStep; - int nDefaultToolbarSize; - bool bSaveImagePosition; - bool bSaveImageCurrentTime; - bool bAllowInaccurateFastseek; - bool bLoopFolderOnPlayNextFile; - bool bLockNoPause; - bool bPreventDisplaySleep; - bool bUseSMTC; - int iReloadAfterLongPause; - bool bOpenRecPanelWhenOpeningDevice; - - enum class AfterPlayback { - DO_NOTHING, - PLAY_NEXT, - REWIND, - MONITOROFF, - CLOSE, - EXIT - } eAfterPlayback; - - // DVD - bool fUseDVDPath; - CString strDVDPath; - LCID idMenuLang, idAudioLang, idSubtitlesLang; - bool fClosedCaptions; - - // Output - CRenderersSettings m_RenderersSettings; - int iDSVideoRendererType; - - CStringW strAudioRendererDisplayName; - bool fD3DFullscreen; - - // Fullscreen - bool fLaunchfullscreen; - bool bHideFullscreenControls; - enum class HideFullscreenControlsPolicy { - SHOW_NEVER, - SHOW_WHEN_HOVERED, - SHOW_WHEN_CURSOR_MOVED, - } eHideFullscreenControlsPolicy; - unsigned uHideFullscreenControlsDelay; - bool bHideFullscreenDockedPanels; - bool fExitFullScreenAtTheEnd; - CStringW strFullScreenMonitorID; - CStringW strFullScreenMonitorDeviceName; - AutoChangeFullscreenMode autoChangeFSMode; - - // 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; - int iBDASymbolRate; - bool fBDAUseOffset; - int iBDAOffset; - bool fBDAIgnoreEncryptedChannels; - int nDVBLastChannel; - std::vector m_DVBChannels; - DVB_RebuildFilterGraph nDVBRebuildFilterGraph; - DVB_StopFilterGraph nDVBStopFilterGraph; - - // Internal Filters - bool SrcFilters[SRC_LAST + !SRC_LAST]; - bool TraFilters[TRA_LAST + !TRA_LAST]; - - // Audio Switcher - bool 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 m_filters; - - // Subtitles - bool fOverridePlacement; - int nHorPos, nVerPos; - bool bSubtitleARCompensation; - int nSubDelayStep; - - // Default Style - STSStyle subtitlesDefStyle; - - // Misc - bool bPreferDefaultForcedSubtitles; - bool fPrioritizeExternalSubtitles; - bool fDisableInternalSubtitles; - bool bAllowOverridingExternalSplitterChoice; - bool bAutoDownloadSubtitles; - bool bAutoSaveDownloadedSubtitles; - int nAutoDownloadScoreMovies; - int nAutoDownloadScoreSeries; - CString strAutoDownloadSubtitlesExclude; - bool bAutoUploadSubtitles; - bool bPreferHearingImpairedSubtitles; -#if USE_LIBASS - bool bRenderSSAUsingLibass; - bool bRenderSRTUsingLibass; -#endif - bool bMPCTheme; - bool bWindows10DarkThemeActive; - bool bWindows10AccentColorsEnabled; - int iModernSeekbarHeight; - - CMPCTheme::ModernThemeMode eModernThemeMode; - - int iFullscreenDelay; - - enum class verticalAlignVideoType { - ALIGN_MIDDLE, - ALIGN_TOP, - ALIGN_BOTTOM - } eVerticalAlignVideoType; - verticalAlignVideoType iVerticalAlignVideo; - - CString strSubtitlesProviders; - CString strSubtitlePaths; - - // Tweaks - int nJumpDistS; - int nJumpDistM; - int nJumpDistL; - bool bFastSeek; - enum { FASTSEEK_LATEST_KEYFRAME, FASTSEEK_NEAREST_KEYFRAME } eFastSeekMethod; - bool fShowChapters; - bool bNotifySkype; - bool fPreventMinimize; - bool bUseEnhancedTaskBar; - bool fLCDSupport; - bool fSeekPreview; - int iSeekPreviewSize; - bool fUseSearchInFolder; - bool fUseSeekbarHover; - int nHoverPosition; - CString strOSDFont; - int nOSDSize; - bool bHideWindowedMousePointer; - - // Miscellaneous - int iBrightness; - int iContrast; - int iHue; - int iSaturation; - int nUpdaterAutoCheck; - int nUpdaterDelay; - - // MENUS - // View - MpcCaptionState eCaptionMenuMode; - bool fHideNavigation; - UINT nCS; // Control state for toolbars - // Language - LANGID language; - // Subtitles menu - bool fEnableSubtitles; - bool bSubtitleOverrideDefaultStyle; - bool bSubtitleOverrideAllStyles; - // Video Frame - int iDefaultVideoSize; - bool fKeepAspectRatio; - bool fCompMonDeskARDiff; - // Pan&Scan - CString strPnSPreset; - CStringArray m_pnspresets; - // On top menu - int iOnTop; - - // WINDOWS - // Add Favorite - bool bFavRememberPos; - bool bFavRelativeDrive; - bool bFavRememberABMarks; - // Save Image... - CString strSnapshotPath, strSnapshotExt; - bool bSnapShotSubtitles; - bool bSnapShotKeepVideoExtension; - // Save Thumbnails... - int iThumbRows, iThumbCols, iThumbWidth; - // Save Subtitle - bool bSubSaveExternalStyleFile; - // Shaders - bool bToggleShader; - bool bToggleShaderScreenSpace; - ShaderList m_ShadersExtraList; - ShaderSelection m_Shaders; - // Playlist (contex menu) - bool bShufflePlaylistItems; - bool bHidePlaylistFullScreen; - - // OTHER STATES - //CStringW strLastOpenDir; - UINT nLastWindowType; - WORD nLastUsedPage; - bool fRemainingTime; - bool bHighPrecisionTimer; - bool bTimerShowPercentage; - bool fLastFullScreen; - - bool fEnableEDLEditor; - - HWND hMasterWnd; - - bool bHideWindowedControls; - - int nJpegQuality; - - bool bEnableCoverArt; - int nCoverArtSizeLimit; - - bool bEnableLogging; - bool bUseLegacyToolbar; - - bool IsD3DFullscreen() const; - CString SelectedAudioRenderer() const; - bool IsISRAutoLoadEnabled() const; - bool IsInitialized() const; - static bool IsVideoRendererAvailable(int iVideoRendererType); - - CFileAssoc fileAssoc; - - CComPtr sanear; - - DWORD iLAVGPUDevice; - unsigned nCmdVolume; - - enum class SubtitleRenderer { - INTERNAL, - VS_FILTER, - XY_SUB_FILTER, - RESERVED, // unused - NONE, - }; - - SubtitleRenderer GetSubtitleRenderer() const; - void SetSubtitleRenderer(SubtitleRenderer renderer) { - eSubtitleRenderer = renderer; - } - - static bool IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer); - - static bool IsSubtitleRendererSupported(SubtitleRenderer eSubtitleRenderer, int videoRenderer); - - CSize GetAspectRatioOverride() const { - ASSERT(fKeepAspectRatio && "Keep Aspect Ratio option have to be enabled if override value is used."); - return sizeAspectRatio; - }; - void SetAspectRatioOverride(const CSize& ar) { - sizeAspectRatio = ar; - } - - // YoutubeDL settings - bool bUseYDL; - int iYDLMaxHeight; - int iYDLVideoFormat; - int iYDLAudioFormat; - bool bYDLAudioOnly; - CString sYDLExePath; - CString sYDLCommandLine; - - bool bEnableCrashReporter; - - int nStreamPosPollerInterval; - bool bShowLangInStatusbar; - bool bShowFPSInStatusbar; - bool bShowABMarksInStatusbar; - bool bShowVideoInfoInStatusbar; - bool bShowAudioFormatInStatusbar; - - bool bAddLangCodeWhenSaveSubtitles; - bool bUseTitleInRecentFileList; - bool bUseSubsFromYDL; - CString sYDLSubsPreference; - bool bUseAutomaticCaptions; - bool bUseFreeType; - bool bUseMediainfoLoadFileDuration; - bool bPauseWhileDraggingSeekbar; - CStringA strOpenTypeLangHint; - - CStringW lastQuickOpenPath; - CStringW lastFileSaveCopyPath; - CStringW lastFileOpenDirPath; - CStringW externalPlayListPath; - - int iRedirectOpenToAppendThreshold; - bool bFullscreenSeparateControls; - bool bAlwaysUseShortMenu; - int iStillVideoDuration; - int iMouseLeftUpDelay; - - bool bCaptureDeinterlace; - bool bConfirmFileDelete; - -private: - struct FilterKey { - CString name; - bool bDefault; - - FilterKey() - : name() - , bDefault(false) { - } - - FilterKey(CString name, bool bDefault) - : name(name) - , bDefault(bDefault) { - } - }; - - FilterKey SrcFiltersKeys[SRC_LAST + !SRC_LAST]; - FilterKey TraFiltersKeys[TRA_LAST + !TRA_LAST]; - - __int64 ConvertTimeToMSec(const CString& time) const; - void ExtractDVDStartPos(CString& strParam); - - void CreateCommands(); - - void SaveExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS); - void LoadExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS); - void ConvertOldExternalFiltersList(); - - void SaveSettingsAutoChangeFullScreenMode(); - - void UpdateRenderersData(bool fSave); - - SubtitleRenderer eSubtitleRenderer; - CSize sizeAspectRatio; - -public: - CAppSettings(); - CAppSettings(const CAppSettings&) = delete; - ~CAppSettings(); - - CAppSettings& operator = (const CAppSettings&) = delete; - - void SaveSettings(bool write_full_history = false); - void ClearRecentFiles(); - static void PurgeMediaHistory(size_t maxsize = 0); - static void PurgePlaylistHistory(size_t maxsize = 0); - static std::multimap LoadHistoryHashes(CStringW section, CStringW dateField); - static void PurgeExpiredHash(CStringW section, CStringW hash); - void LoadSettings(); - void SaveExternalFilters() { - if (bInitialized) { - SaveExternalFilters(m_filters); - } - }; - void UpdateSettings(); - - void SavePlayListPosition(CStringW playlistPath, UINT position); - - UINT GetSavedPlayListPosition(CStringW playlistPath); - - void SetAsUninitialized() { - bInitialized = false; - }; - - void GetFav(favtype ft, CAtlList& sl) const; - void SetFav(favtype ft, CAtlList& sl); - void AddFav(favtype ft, CString s); - - CBDAChannel* FindChannelByPref(int nPrefNumber); - - bool GetAllowMultiInst() const; - - static bool IsVSFilterInstalled(); -}; - +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#pragma once +#include "mpc-hc_config.h" +#include "../Subtitles/STS.h" +#include "../filters/switcher/AudioSwitcher/AudioSwitcher.h" +#include "../thirdparty/sanear/src/Interfaces.h" +#include "DVBChannel.h" +#include "FileAssoc.h" +#include "FilterEnum.h" +#include "MediaFormats.h" +#include "../filters/renderer/VideoRenderers/RenderersSettings.h" +#include "SettingsDefines.h" +#include "Shaders.h" +#include "../Subtitles/SubRendererSettings.h" +#include +#include +#include "CMPCTheme.h" + + +class FilterOverride; + +// flags for CAppSettings::nCS +enum { + CS_NONE = 0, + CS_SEEKBAR = 1, + CS_TOOLBAR = CS_SEEKBAR << 1, + CS_INFOBAR = CS_TOOLBAR << 1, + CS_STATSBAR = CS_INFOBAR << 1, + CS_STATUSBAR = CS_STATSBAR << 1, + CS_LAST = CS_STATUSBAR +}; + +enum : UINT64 { + CLSW_NONE = 0, + CLSW_OPEN = 1, + CLSW_PLAY = CLSW_OPEN << 1, + CLSW_CLOSE = CLSW_PLAY << 1, + CLSW_STANDBY = CLSW_CLOSE << 1, + CLSW_HIBERNATE = CLSW_STANDBY << 1, + CLSW_SHUTDOWN = CLSW_HIBERNATE << 1, + CLSW_LOGOFF = CLSW_SHUTDOWN << 1, + CLSW_LOCK = CLSW_LOGOFF << 1, + CLSW_MONITOROFF = CLSW_LOCK << 1, + CLSW_PLAYNEXT = CLSW_MONITOROFF << 1, + CLSW_DONOTHING = CLSW_PLAYNEXT << 1, + CLSW_AFTERPLAYBACK_MASK = CLSW_CLOSE | CLSW_STANDBY | CLSW_SHUTDOWN | CLSW_HIBERNATE | CLSW_LOGOFF | CLSW_LOCK | CLSW_MONITOROFF | CLSW_PLAYNEXT | CLSW_DONOTHING, + CLSW_FULLSCREEN = CLSW_DONOTHING << 1, + CLSW_NEW = CLSW_FULLSCREEN << 1, + CLSW_HELP = CLSW_NEW << 1, + CLSW_DVD = CLSW_HELP << 1, + CLSW_CD = CLSW_DVD << 1, + CLSW_DEVICE = CLSW_CD << 1, + CLSW_ADD = CLSW_DEVICE << 1, + CLSW_RANDOMIZE = CLSW_ADD << 1, + CLSW_MINIMIZED = CLSW_RANDOMIZE << 1, + CLSW_REGEXTVID = CLSW_MINIMIZED << 1, + CLSW_REGEXTAUD = CLSW_REGEXTVID << 1, + CLSW_REGEXTPL = CLSW_REGEXTAUD << 1, + CLSW_UNREGEXT = CLSW_REGEXTPL << 1, + CLSW_ICONSASSOC = CLSW_UNREGEXT << 1, + CLSW_STARTVALID = CLSW_ICONSASSOC << 1, + CLSW_NOFOCUS = CLSW_STARTVALID << 1, + CLSW_FIXEDSIZE = CLSW_NOFOCUS << 1, + CLSW_MONITOR = CLSW_FIXEDSIZE << 1, + CLSW_D3DFULLSCREEN = CLSW_MONITOR << 1, + CLSW_ADMINOPTION = CLSW_D3DFULLSCREEN << 1, + CLSW_SLAVE = CLSW_ADMINOPTION << 1, + CLSW_AUDIORENDERER = CLSW_SLAVE << 1, + CLSW_RESET = CLSW_AUDIORENDERER << 1, + CLSW_PRESET1 = CLSW_RESET << 1, + CLSW_PRESET2 = CLSW_PRESET1 << 1, + CLSW_PRESET3 = CLSW_PRESET2 << 1, + CLSW_CONFIGLAVSPLITTER = CLSW_PRESET3 << 1, + CLSW_CONFIGLAVAUDIO = CLSW_CONFIGLAVSPLITTER << 1, + CLSW_CONFIGLAVVIDEO = CLSW_CONFIGLAVAUDIO << 1, + CLSW_MUTE = CLSW_CONFIGLAVVIDEO << 1, + CLSW_VOLUME = CLSW_MUTE << 1, + CLSW_THUMBNAILS = CLSW_VOLUME << 1, + CLSW_UNRECOGNIZEDSWITCH = CLSW_THUMBNAILS << 1, // 47 +}; + +enum MpcCaptionState { + MODE_SHOWCAPTIONMENU, + MODE_HIDEMENU, + MODE_FRAMEONLY, + MODE_BORDERLESS, + MODE_COUNT +}; // flags for Caption & Menu Mode + +enum { + VIDRNDT_DS_DEFAULT = 0, + VIDRNDT_DS_OVERLAYMIXER = 2, + VIDRNDT_DS_VMR9WINDOWED = 4, + VIDRNDT_DS_VMR9RENDERLESS = 6, + VIDRNDT_DS_DXR = 7, + VIDRNDT_DS_NULL_COMP = 8, + VIDRNDT_DS_NULL_UNCOMP = 9, + VIDRNDT_DS_EVR = 10, + VIDRNDT_DS_EVR_CUSTOM = 11, + VIDRNDT_DS_MADVR = 12, + VIDRNDT_DS_SYNC = 13, + VIDRNDT_DS_MPCVR = 14, +}; + +// Enumeration for MCE remote control (careful : add 0x010000 for all keys!) +enum MCE_RAW_INPUT { + MCE_DETAILS = 0x010209, + MCE_GUIDE = 0x01008D, + MCE_TVJUMP = 0x010025, + MCE_STANDBY = 0x010082, + MCE_OEM1 = 0x010080, + MCE_OEM2 = 0x010081, + MCE_MYTV = 0x010046, + MCE_MYVIDEOS = 0x01004A, + MCE_MYPICTURES = 0x010049, + MCE_MYMUSIC = 0x010047, + MCE_RECORDEDTV = 0x010048, + MCE_DVDANGLE = 0x01004B, + MCE_DVDAUDIO = 0x01004C, + MCE_DVDMENU = 0x010024, + MCE_DVDSUBTITLE = 0x01004D, + MCE_RED = 0x01005B, + MCE_GREEN = 0x01005C, + MCE_YELLOW = 0x01005D, + MCE_BLUE = 0x01005E, + MCE_MEDIA_NEXTTRACK = 0x0100B5, + MCE_MEDIA_PREVIOUSTRACK = 0x0100B6 +}; + +#define AUDRNDT_NULL_COMP _T("Null Audio Renderer (Any)") +#define AUDRNDT_NULL_UNCOMP _T("Null Audio Renderer (Uncompressed)") +#define AUDRNDT_INTERNAL _T("Internal Audio Renderer") // Use this as device name for SaneAR +#define AUDRNDT_SANEAR _T("SaneAR Audio Renderer") // This only as title +#define AUDRNDT_MPC L"MPC Audio Renderer" + + +#define DEFAULT_SUBTITLE_PATHS _T(".;.\\subtitles;.\\subs") +#define DEFAULT_JUMPDISTANCE_1 1000 +#define DEFAULT_JUMPDISTANCE_2 5000 +#define DEFAULT_JUMPDISTANCE_3 20000 + +#define MIN_AUTOFIT_SCALE_FACTOR 25 +#define MAX_AUTOFIT_SCALE_FACTOR 100 +#define DEF_MIN_AUTOFIT_SCALE_FACTOR 40 +#define DEF_MAX_AUTOFIT_SCALE_FACTOR 80 + +#define NO_FIXED_POSITION CPoint(INT_MIN, INT_MIN) + +enum dvstype { + DVS_HALF, + DVS_NORMAL, + DVS_DOUBLE, + DVS_STRETCH, + DVS_FROMINSIDE, + DVS_FROMOUTSIDE, + DVS_ZOOM1, + DVS_ZOOM2 +}; + +enum favtype { + FAV_FILE, + FAV_DVD, + FAV_DEVICE +}; + +enum { + TIME_TOOLTIP_ABOVE_SEEKBAR, + TIME_TOOLTIP_BELOW_SEEKBAR +}; + +enum DVB_RebuildFilterGraph { + DVB_REBUILD_FG_NEVER = 0, + DVB_REBUILD_FG_WHEN_SWITCHING, + DVB_REBUILD_FG_ALWAYS +}; + +enum DVB_StopFilterGraph { + DVB_STOP_FG_NEVER = 0, + DVB_STOP_FG_WHEN_SWITCHING, + DVB_STOP_FG_ALWAYS +}; + +struct ShaderC { + CString label; + CString profile; + CString srcdata; + ULONGLONG length = 0; + FILETIME ftwrite = {0,0}; + + bool Match(LPCWSTR _label, const bool _bD3D11) const { + return (label.CompareNoCase(_label) == 0 && (_bD3D11 == (profile == "ps_4_0"))); + } +}; + +struct DisplayMode { + bool bValid = false; + CSize size; + int bpp = 0, freq = 0; + DWORD dwDisplayFlags = 0; + + bool operator == (const DisplayMode& dm) const { + return (bValid == dm.bValid && size == dm.size && bpp == dm.bpp && freq == dm.freq && dwDisplayFlags == dm.dwDisplayFlags); + }; + + bool operator < (const DisplayMode& dm) const { + bool bRet = false; + + // Ignore bValid when sorting + if (size.cx < dm.size.cx) { + bRet = true; + } else if (size.cx == dm.size.cx) { + if (size.cy < dm.size.cy) { + bRet = true; + } else if (size.cy == dm.size.cy) { + if (freq < dm.freq) { + bRet = true; + } else if (freq == dm.freq) { + if (bpp < dm.bpp) { + bRet = true; + } else if (bpp == dm.bpp) { + bRet = (dwDisplayFlags & DM_INTERLACED) && !(dm.dwDisplayFlags & DM_INTERLACED); + } + } + } + } + + return bRet; + }; +}; + +struct AutoChangeMode { + AutoChangeMode(bool _bChecked, double _dFrameRateStart, double _dFrameRateStop, int _msAudioDelay, DisplayMode _dm) + : bChecked(_bChecked) + , dFrameRateStart(_dFrameRateStart) + , dFrameRateStop(_dFrameRateStop) + , msAudioDelay(_msAudioDelay) + , dm(std::move(_dm)) { + } + + bool bChecked; + double dFrameRateStart; + double dFrameRateStop; + int msAudioDelay; + DisplayMode dm; +}; + +struct AutoChangeFullscreenMode { + bool bEnabled = false; + std::vector modes; + bool bApplyDefaultModeAtFSExit = false; + bool bRestoreResAfterProgExit = true; + unsigned uDelay = 0u; +}; + +#define ACCEL_LIST_SIZE 201 + +struct wmcmd_base : public ACCEL { + BYTE mouse; + BYTE mouseVirt; + DWORD dwname; + UINT appcmd; + + enum : BYTE { + NONE, + LDOWN, + LUP, + LDBLCLK, + MDOWN, + MUP, + MDBLCLK, + RDOWN, + RUP, + RDBLCLK, + X1DOWN, + X1UP, + X1DBLCLK, + X2DOWN, + X2UP, + X2DBLCLK, + WUP, + WDOWN, + WRIGHT, + WLEFT, + LAST + }; + + wmcmd_base() + : ACCEL( { + 0, 0, 0 + }) + , mouse(NONE) + , mouseVirt(0) + , dwname(0) + , appcmd(0) {} + + constexpr wmcmd_base(WORD _cmd, WORD _key, BYTE _fVirt, DWORD _dwname, UINT _appcmd = 0, BYTE _mouse = NONE, BYTE _mouseVirt = 0) + : ACCEL{ _fVirt, _key, _cmd } + , mouse(_mouse) + , mouseVirt(_mouseVirt) + , dwname(_dwname) + , appcmd(_appcmd) {} + + constexpr wmcmd_base(const wmcmd_base&) = default; + constexpr wmcmd_base(wmcmd_base&&) = default; + wmcmd_base& operator=(const wmcmd_base&) = default; + wmcmd_base& operator=(wmcmd_base&&) = default; +}; + +class wmcmd : public wmcmd_base +{ + const wmcmd_base* default_cmd = nullptr; + +public: + CStringA rmcmd; + int rmrepcnt = 5; + + wmcmd() = default; + wmcmd& operator=(const wmcmd&) = default; + wmcmd& operator=(wmcmd&&) = default; + + explicit wmcmd(const wmcmd_base& cmd) + : wmcmd_base(cmd) + , default_cmd(&cmd) + , rmrepcnt(5) { + } + + bool operator == (const wmcmd& wc) const { + return cmd > 0 && cmd == wc.cmd; + } + + CString GetName() const { + return ResStr(dwname); + } + + void Restore() { + ASSERT(default_cmd); + *static_cast(this) = *static_cast(default_cmd); + appcmd = default_cmd->appcmd; + mouse = default_cmd->mouse; + mouseVirt = default_cmd->mouseVirt; + rmcmd.Empty(); + rmrepcnt = 5; + } + + bool IsModified() const { + ASSERT(default_cmd); + return memcmp(static_cast(this), static_cast(default_cmd), sizeof(ACCEL)) || + appcmd != default_cmd->appcmd || + mouse != default_cmd->mouse || + mouseVirt != default_cmd->mouseVirt || + !rmcmd.IsEmpty() || + rmrepcnt != 5; + } +}; + +class CRemoteCtrlClient : public CAsyncSocket +{ +protected: + CCritSec m_csLock; + CWnd* m_pWnd; + enum { + DISCONNECTED, + CONNECTED, + CONNECTING + } m_nStatus; + CString m_addr; + + virtual void OnConnect(int nErrorCode); + virtual void OnClose(int nErrorCode); + virtual void OnReceive(int nErrorCode); + + virtual void OnCommand(CStringA str) = 0; + + void ExecuteCommand(CStringA cmd, int repcnt); + +public: + CRemoteCtrlClient(); + void SetHWND(HWND hWnd); + void Connect(CString addr); + void DisConnect(); + int GetStatus() const { + return m_nStatus; + } +}; + +class CWinLircClient : public CRemoteCtrlClient +{ +protected: + virtual void OnCommand(CStringA str); + +public: + CWinLircClient(); +}; + +class CUIceClient : public CRemoteCtrlClient +{ +protected: + virtual void OnCommand(CStringA str); + +public: + CUIceClient(); +}; + +#define APPSETTINGS_VERSION 8 + +struct DVD_POSITION { + ULONGLONG llDVDGuid = 0; + ULONG lTitle = 0; + DVD_HMSF_TIMECODE timecode = { 0 }; +}; + +struct ABRepeat { + ABRepeat() : positionA(0), positionB(0), dvdTitle(-1) {} + operator bool() const { return positionA || positionB; }; + REFERENCE_TIME positionA, positionB; + ULONG dvdTitle; //whatever title they saved last will be the only one we remember +}; + +class RecentFileEntry { +public: + RecentFileEntry() {} + void InitEntry(const RecentFileEntry& r) { + hash = r.hash; + cue = r.cue; + title = r.title; + lastOpened = r.lastOpened; + filePosition = r.filePosition; + DVDPosition = r.DVDPosition; + fns.RemoveAll(); + subs.RemoveAll(); + fns.AddHeadList(&r.fns); + subs.AddHeadList(&r.subs); + abRepeat = r.abRepeat; + AudioTrackIndex = r.AudioTrackIndex; + SubtitleTrackIndex = r.SubtitleTrackIndex; + } + RecentFileEntry(const RecentFileEntry &r) { + InitEntry(r); + } + + CStringW hash; + CString title; + CString lastOpened; + CAtlList fns; + CString cue; + CAtlList subs; + REFERENCE_TIME filePosition=0; + DVD_POSITION DVDPosition = {}; + ABRepeat abRepeat; + int AudioTrackIndex = -1; + int SubtitleTrackIndex = -1; + + void operator=(const RecentFileEntry &r) { + InitEntry(r); + } +}; + +class CAppSettings +{ + bool bInitialized = false; + + 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 + + void SetSize(int nSize); + }; + + class CRecentFileListWithMoreInfo + { + public: + CRecentFileListWithMoreInfo(LPCTSTR lpszSection, int nSize) + : m_section(lpszSection) + , m_maxSize(nSize) + , current_rfe_hash(L"") + {} + + CAtlArray rfe_array; + size_t m_maxSize; + LPCTSTR m_section; + REFERENCE_TIME persistedFilePosition = 0; + CString current_rfe_hash; + int rfe_last_added = 0; + int listModifySequence = 0; + + int GetSize() { + return (int)rfe_array.GetCount(); + } + + RecentFileEntry& operator[](size_t nIndex) { + ASSERT(nIndex >= 0 && nIndex < rfe_array.GetCount()); + return rfe_array[nIndex]; + } + + //void Remove(size_t nIndex); + void Add(LPCTSTR fn); + void Add(LPCTSTR fn, ULONGLONG llDVDGuid); + void Add(RecentFileEntry r, bool current_open = false); + bool GetCurrentIndex(size_t& idx); + void UpdateCurrentFilePosition(REFERENCE_TIME time, bool forcePersist = false); + REFERENCE_TIME GetCurrentFilePosition(); + ABRepeat GetCurrentABRepeat(); + void UpdateCurrentDVDTimecode(DVD_HMSF_TIMECODE *time); + void UpdateCurrentDVDTitle(DWORD title); + DVD_POSITION GetCurrentDVDPosition(); + void UpdateCurrentAudioTrack(int audioIndex); + int GetCurrentAudioTrack(); + void UpdateCurrentSubtitleTrack(int audioIndex); + int GetCurrentSubtitleTrack(); + void AddSubToCurrent(CStringW subpath); + void SetCurrentTitle(CStringW subpath); + void UpdateCurrentABRepeat(ABRepeat abRepeat); + void WriteCurrentEntry(); + void ReadMediaHistory(); + void WriteMediaHistoryAudioIndex(RecentFileEntry& r); + void WriteMediaHistorySubtitleIndex(RecentFileEntry& r); + void WriteMediaHistoryEntry(RecentFileEntry& r, bool updateLastOpened = false); + void SaveMediaHistory(); + void ReadLegacyMediaHistory(std::map &filenameToIndex); + void ReadLegacyMediaPosition(std::map &filenameToIndex); + bool LoadMediaHistoryEntryFN(CStringW fn, RecentFileEntry& r); + bool LoadMediaHistoryEntryDVD(ULONGLONG llDVDGuid, CStringW fn, RecentFileEntry& r); + bool LoadMediaHistoryEntry(CStringW hash, RecentFileEntry& r); + void MigrateLegacyHistory(); + void SetSize(size_t nSize); + void RemoveAll(); + }; + +public: + // cmdline params + UINT64 nCLSwitches; + CAtlList slFiles, slDubs, slSubs, slFilters; + static std::map CommandIDToWMCMD; + + // Initial position (used by command line flags) + REFERENCE_TIME rtShift; + REFERENCE_TIME rtStart; + ABRepeat abRepeat; + ULONG lDVDTitle; + ULONG lDVDChapter; + DVD_HMSF_TIMECODE DVDPosition; + + CSize sizeFixedWindow; + CPoint fixedWindowPosition; + bool HasFixedWindowSize() const { + return sizeFixedWindow.cx > 0 || sizeFixedWindow.cy > 0; + } + //int iFixedWidth, iFixedHeight; + int iMonitor; + + CString ParseFileName(CString const& param); + void ParseCommandLine(CAtlList& cmdln); + + // Added a Debug display to the screen (/debug option) + bool fShowDebugInfo; + int iAdminOption; + + + // Player + bool fAllowMultipleInst; + bool fTrayIcon; + bool fShowOSD; + bool fShowCurrentTimeInOSD; + int nOSDTransparency; + int nOSDBorder; + + bool fLimitWindowProportions; + bool fSnapToDesktopEdges; + bool fHideCDROMsSubMenu; + DWORD dwPriority; + int iTitleBarTextStyle; + bool fTitleBarTextTitle; + bool fKeepHistory; + int iRecentFilesNumber; + CRecentFileListWithMoreInfo MRU; + CRecentFileAndURLList MRUDub; + bool fRememberDVDPos; + bool fRememberFilePos; + int iRememberPosForLongerThan; + bool bRememberPosForAudioFiles; + bool bRememberExternalPlaylistPos; + bool bRememberTrackSelection; + bool bRememberPlaylistItems; + bool fRememberWindowPos; + CRect rcLastWindowPos; + bool fRememberWindowSize; + bool fSavePnSZoom; + double dZoomX; + double dZoomY; + + // Formats + CMediaFormats m_Formats; + bool fAssociatedWithIcons; + + // Keys + CList wmcmds; + HACCEL hAccel; + bool fWinLirc; + CString strWinLircAddr; + CWinLircClient WinLircClient; + bool fUIce; + CString strUIceAddr; + CUIceClient UIceClient; + bool fGlobalMedia; + + // Mouse + UINT nMouseLeftClick; + bool bMouseLeftClickOpenRecent; + UINT nMouseLeftDblClick; + bool bMouseEasyMove; + UINT nMouseRightClick; + struct MOUSE_ASSIGNMENT { + UINT normal; + UINT ctrl; + UINT shift; + UINT rbtn; + }; + MOUSE_ASSIGNMENT MouseMiddleClick; + MOUSE_ASSIGNMENT MouseX1Click; + MOUSE_ASSIGNMENT MouseX2Click; + MOUSE_ASSIGNMENT MouseWheelUp; + MOUSE_ASSIGNMENT MouseWheelDown; + MOUSE_ASSIGNMENT MouseWheelLeft; + MOUSE_ASSIGNMENT MouseWheelRight; + + // Logo + int nLogoId; + bool fLogoExternal; + BOOL fLogoColorProfileEnabled; + CString strLogoFileName; + + // Web Inteface + bool fEnableWebServer; + int nWebServerPort; + int nCmdlnWebServerPort; + bool fWebServerUseCompression; + bool fWebServerLocalhostOnly; + bool bWebUIEnablePreview; + bool fWebServerPrintDebugInfo; + CString strWebRoot, strWebDefIndex; + CString strWebServerCGI; + + // Playback + int nVolume; + bool fMute; + int nBalance; + int nLoops; + bool fLoopForever; + + enum class LoopMode { + FILE, + PLAYLIST + } eLoopMode; + + bool fRememberZoomLevel; + int nAutoFitFactorMin; + int nAutoFitFactorMax; + int iZoomLevel; + CStringW strAudiosLanguageOrder; + CStringW strSubtitlesLanguageOrder; + bool fEnableWorkerThreadForOpening; + bool fReportFailedPins; + bool fAutoloadAudio; + bool fBlockVSFilter; + bool bBlockRDP; + UINT nVolumeStep; + UINT nSpeedStep; + int nDefaultToolbarSize; + bool bSaveImagePosition; + bool bSaveImageCurrentTime; + bool bAllowInaccurateFastseek; + bool bLoopFolderOnPlayNextFile; + bool bLockNoPause; + bool bPreventDisplaySleep; + bool bUseSMTC; + int iReloadAfterLongPause; + bool bOpenRecPanelWhenOpeningDevice; + + enum class AfterPlayback { + DO_NOTHING, + PLAY_NEXT, + REWIND, + MONITOROFF, + CLOSE, + EXIT + } eAfterPlayback; + + // DVD + bool fUseDVDPath; + CString strDVDPath; + LCID idMenuLang, idAudioLang, idSubtitlesLang; + bool fClosedCaptions; + + // Output + CRenderersSettings m_RenderersSettings; + int iDSVideoRendererType; + + CStringW strAudioRendererDisplayName; + bool fD3DFullscreen; + + // Fullscreen + bool fLaunchfullscreen; + bool bHideFullscreenControls; + enum class HideFullscreenControlsPolicy { + SHOW_NEVER, + SHOW_WHEN_HOVERED, + SHOW_WHEN_CURSOR_MOVED, + } eHideFullscreenControlsPolicy; + unsigned uHideFullscreenControlsDelay; + bool bHideFullscreenDockedPanels; + bool fExitFullScreenAtTheEnd; + CStringW strFullScreenMonitorID; + CStringW strFullScreenMonitorDeviceName; + AutoChangeFullscreenMode autoChangeFSMode; + + // 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; + int iBDASymbolRate; + bool fBDAUseOffset; + int iBDAOffset; + bool fBDAIgnoreEncryptedChannels; + int nDVBLastChannel; + std::vector m_DVBChannels; + DVB_RebuildFilterGraph nDVBRebuildFilterGraph; + DVB_StopFilterGraph nDVBStopFilterGraph; + + // Internal Filters + bool SrcFilters[SRC_LAST + !SRC_LAST]; + bool TraFilters[TRA_LAST + !TRA_LAST]; + + // Audio Switcher + bool 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 m_filters; + + // Subtitles + bool fOverridePlacement; + int nHorPos, nVerPos; + bool bSubtitleARCompensation; + int nSubDelayStep; + + // Default Style + STSStyle subtitlesDefStyle; + + // Misc + bool bPreferDefaultForcedSubtitles; + bool fPrioritizeExternalSubtitles; + bool fDisableInternalSubtitles; + bool bAllowOverridingExternalSplitterChoice; + bool bAutoDownloadSubtitles; + bool bAutoSaveDownloadedSubtitles; + int nAutoDownloadScoreMovies; + int nAutoDownloadScoreSeries; + CString strAutoDownloadSubtitlesExclude; + bool bAutoUploadSubtitles; + bool bPreferHearingImpairedSubtitles; +#if USE_LIBASS + bool bRenderSSAUsingLibass; + bool bRenderSRTUsingLibass; +#endif + bool bMPCTheme; + bool bWindows10DarkThemeActive; + bool bWindows10AccentColorsEnabled; + int iModernSeekbarHeight; + + CMPCTheme::ModernThemeMode eModernThemeMode; + + int iFullscreenDelay; + + enum class verticalAlignVideoType { + ALIGN_MIDDLE, + ALIGN_TOP, + ALIGN_BOTTOM + } eVerticalAlignVideoType; + verticalAlignVideoType iVerticalAlignVideo; + + CString strSubtitlesProviders; + CString strSubtitlePaths; + + // Tweaks + int nJumpDistS; + int nJumpDistM; + int nJumpDistL; + bool bFastSeek; + enum { FASTSEEK_LATEST_KEYFRAME, FASTSEEK_NEAREST_KEYFRAME } eFastSeekMethod; + bool fShowChapters; + bool bNotifySkype; + bool fPreventMinimize; + bool bUseEnhancedTaskBar; + bool fLCDSupport; + bool fSeekPreview; + int iSeekPreviewSize; + bool fUseSearchInFolder; + bool fUseSeekbarHover; + int nHoverPosition; + CString strOSDFont; + int nOSDSize; + bool bHideWindowedMousePointer; + + // Miscellaneous + int iBrightness; + int iContrast; + int iHue; + int iSaturation; + int nUpdaterAutoCheck; + int nUpdaterDelay; + + // MENUS + // View + MpcCaptionState eCaptionMenuMode; + bool fHideNavigation; + UINT nCS; // Control state for toolbars + // Language + LANGID language; + // Subtitles menu + bool fEnableSubtitles; + bool bSubtitleOverrideDefaultStyle; + bool bSubtitleOverrideAllStyles; + // Video Frame + int iDefaultVideoSize; + bool fKeepAspectRatio; + bool fCompMonDeskARDiff; + // Pan&Scan + CString strPnSPreset; + CStringArray m_pnspresets; + // On top menu + int iOnTop; + + // WINDOWS + // Add Favorite + bool bFavRememberPos; + bool bFavRelativeDrive; + bool bFavRememberABMarks; + // Save Image... + CString strSnapshotPath, strSnapshotExt; + bool bSnapShotSubtitles; + bool bSnapShotKeepVideoExtension; + // Save Thumbnails... + int iThumbRows, iThumbCols, iThumbWidth; + // Save Subtitle + bool bSubSaveExternalStyleFile; + // Shaders + bool bToggleShader; + bool bToggleShaderScreenSpace; + ShaderList m_ShadersExtraList; + ShaderSelection m_Shaders; + // Playlist (contex menu) + bool bShufflePlaylistItems; + bool bHidePlaylistFullScreen; + + // OTHER STATES + //CStringW strLastOpenDir; + UINT nLastWindowType; + WORD nLastUsedPage; + bool fRemainingTime; + bool bHighPrecisionTimer; + bool bTimerShowPercentage; + bool fLastFullScreen; + + bool fEnableEDLEditor; + + HWND hMasterWnd; + + bool bHideWindowedControls; + + int nJpegQuality; + + bool bEnableCoverArt; + int nCoverArtSizeLimit; + + bool bEnableLogging; + bool bUseLegacyToolbar; + + bool IsD3DFullscreen() const; + CString SelectedAudioRenderer() const; + bool IsISRAutoLoadEnabled() const; + bool IsInitialized() const; + static bool IsVideoRendererAvailable(int iVideoRendererType); + + CFileAssoc fileAssoc; + + CComPtr sanear; + + DWORD iLAVGPUDevice; + unsigned nCmdVolume; + + enum class SubtitleRenderer { + INTERNAL, + VS_FILTER, + XY_SUB_FILTER, + RESERVED, // unused + NONE, + }; + + SubtitleRenderer GetSubtitleRenderer() const; + void SetSubtitleRenderer(SubtitleRenderer renderer) { + eSubtitleRenderer = renderer; + } + + static bool IsSubtitleRendererRegistered(SubtitleRenderer eSubtitleRenderer); + + static bool IsSubtitleRendererSupported(SubtitleRenderer eSubtitleRenderer, int videoRenderer); + + CSize GetAspectRatioOverride() const { + ASSERT(fKeepAspectRatio && "Keep Aspect Ratio option have to be enabled if override value is used."); + return sizeAspectRatio; + }; + void SetAspectRatioOverride(const CSize& ar) { + sizeAspectRatio = ar; + } + + // YoutubeDL settings + bool bUseYDL; + int iYDLMaxHeight; + int iYDLVideoFormat; + int iYDLAudioFormat; + bool bYDLAudioOnly; + CString sYDLExePath; + CString sYDLCommandLine; + + bool bEnableCrashReporter; + + int nStreamPosPollerInterval; + bool bShowLangInStatusbar; + bool bShowFPSInStatusbar; + bool bShowABMarksInStatusbar; + bool bShowVideoInfoInStatusbar; + bool bShowAudioFormatInStatusbar; + + bool bAddLangCodeWhenSaveSubtitles; + bool bUseTitleInRecentFileList; + bool bUseSubsFromYDL; + CString sYDLSubsPreference; + bool bUseAutomaticCaptions; + bool bUseFreeType; + bool bUseMediainfoLoadFileDuration; + bool bPauseWhileDraggingSeekbar; + CStringA strOpenTypeLangHint; + + CStringW lastQuickOpenPath; + CStringW lastFileSaveCopyPath; + CStringW lastFileOpenDirPath; + CStringW externalPlayListPath; + + int iRedirectOpenToAppendThreshold; + bool bFullscreenSeparateControls; + bool bAlwaysUseShortMenu; + int iStillVideoDuration; + int iMouseLeftUpDelay; + + bool bCaptureDeinterlace; + bool bConfirmFileDelete; + +private: + struct FilterKey { + CString name; + bool bDefault; + + FilterKey() + : name() + , bDefault(false) { + } + + FilterKey(CString name, bool bDefault) + : name(name) + , bDefault(bDefault) { + } + }; + + FilterKey SrcFiltersKeys[SRC_LAST + !SRC_LAST]; + FilterKey TraFiltersKeys[TRA_LAST + !TRA_LAST]; + + __int64 ConvertTimeToMSec(const CString& time) const; + void ExtractDVDStartPos(CString& strParam); + + void CreateCommands(); + + void SaveExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS); + void LoadExternalFilters(CAutoPtrList& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS); + void ConvertOldExternalFiltersList(); + + void SaveSettingsAutoChangeFullScreenMode(); + + void UpdateRenderersData(bool fSave); + + SubtitleRenderer eSubtitleRenderer; + CSize sizeAspectRatio; + +public: + CAppSettings(); + CAppSettings(const CAppSettings&) = delete; + ~CAppSettings(); + + CAppSettings& operator = (const CAppSettings&) = delete; + + void SaveSettings(bool write_full_history = false); + void ClearRecentFiles(); + static void PurgeMediaHistory(size_t maxsize = 0); + static void PurgePlaylistHistory(size_t maxsize = 0); + static std::multimap LoadHistoryHashes(CStringW section, CStringW dateField); + static void PurgeExpiredHash(CStringW section, CStringW hash); + void LoadSettings(); + void SaveExternalFilters() { + if (bInitialized) { + SaveExternalFilters(m_filters); + } + }; + void UpdateSettings(); + + void SavePlayListPosition(CStringW playlistPath, UINT position); + + UINT GetSavedPlayListPosition(CStringW playlistPath); + + void SetAsUninitialized() { + bInitialized = false; + }; + + void GetFav(favtype ft, CAtlList& sl) const; + void SetFav(favtype ft, CAtlList& sl); + void AddFav(favtype ft, CString s); + + CBDAChannel* FindChannelByPref(int nPrefNumber); + + bool GetAllowMultiInst() const; + + static bool IsVSFilterInstalled(); +}; + diff --git a/src/mpc-hc/AuthDlg.cpp b/src/mpc-hc/AuthDlg.cpp index f31ba0fbf36..ddb06bd249f 100644 --- a/src/mpc-hc/AuthDlg.cpp +++ b/src/mpc-hc/AuthDlg.cpp @@ -1,92 +1,92 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "AuthDlg.h" - -// We need to dynamically link to the functions provided by CredUI.lib in order -// to be able to use the features available to the OS. -#include -#include "WinApiFunc.h" - -HRESULT PromptForCredentials(HWND hWnd, const CString& strCaptionText, const CString& strMessageText, CString& strDomain, CString& strUsername, CString& strPassword, BOOL* bSave) -{ - CREDUI_INFO info = { sizeof(info) }; - info.hwndParent = hWnd; - info.pszCaptionText = strCaptionText.Left(CREDUI_MAX_CAPTION_LENGTH); - info.pszMessageText = strMessageText.Left(CREDUI_MAX_MESSAGE_LENGTH); - - DWORD dwUsername = CREDUI_MAX_USERNAME_LENGTH + 1; - DWORD dwPassword = CREDUI_MAX_PASSWORD_LENGTH + 1; - DWORD dwDomain = CREDUI_MAX_GENERIC_TARGET_LENGTH + 1; - - // Define CredUI.dll functions for Windows Vista+ - const WinapiFunc - fnCredPackAuthenticationBufferW = { _T("CREDUI.DLL"), "CredPackAuthenticationBufferW" }; - - const WinapiFunc - fnCredUIPromptForWindowsCredentialsW = { _T("CREDUI.DLL"), "CredUIPromptForWindowsCredentialsW" }; - - const WinapiFunc - fnCredUnPackAuthenticationBufferW = { _T("CREDUI.DLL"), "CredUnPackAuthenticationBufferW" }; - - if (fnCredPackAuthenticationBufferW && fnCredUIPromptForWindowsCredentialsW && fnCredUnPackAuthenticationBufferW) { - PVOID pvInAuthBlob = nullptr; - ULONG cbInAuthBlob = 0; - PVOID pvAuthBlob = nullptr; - ULONG cbAuthBlob = 0; - ULONG ulAuthPackage = 0; - - // Call CredPackAuthenticationBufferW once to determine the size, in bytes, of the authentication buffer. - if (strUsername.GetLength()) { - BOOL bResult = fnCredPackAuthenticationBufferW(0, (LPTSTR)(LPCTSTR)strUsername, (LPTSTR)(LPCTSTR)strPassword, nullptr, &cbInAuthBlob); - if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - if ((pvInAuthBlob = CoTaskMemAlloc(cbInAuthBlob)) != nullptr) { - VERIFY(fnCredPackAuthenticationBufferW(0, (LPTSTR)(LPCTSTR)strUsername, (LPTSTR)(LPCTSTR)strPassword, (PBYTE)pvInAuthBlob, &cbInAuthBlob)); - } - } - } - const DWORD dwFlags = CREDUIWIN_GENERIC | CREDUIWIN_ENUMERATE_CURRENT_USER | (bSave ? CREDUIWIN_CHECKBOX : 0); - DWORD dwResult = fnCredUIPromptForWindowsCredentialsW(&info, 0, &ulAuthPackage, pvInAuthBlob, cbInAuthBlob, &pvAuthBlob, &cbAuthBlob, bSave, dwFlags); - if (dwResult == ERROR_SUCCESS) { - VERIFY(fnCredUnPackAuthenticationBufferW(0, pvAuthBlob, cbAuthBlob, strUsername.GetBufferSetLength(dwUsername), &dwUsername, strDomain.GetBufferSetLength(dwDomain), &dwDomain, strPassword.GetBufferSetLength(dwPassword), &dwPassword)); - strUsername.ReleaseBuffer(); - strPassword.ReleaseBuffer(); - strDomain.ReleaseBuffer(); - } - - // Delete the input authentication byte array. - if (pvInAuthBlob) { - SecureZeroMemory(pvInAuthBlob, cbInAuthBlob); - CoTaskMemFree(pvInAuthBlob); - pvInAuthBlob = nullptr; - } - // Delete the output authentication byte array. - if (pvAuthBlob) { - SecureZeroMemory(pvAuthBlob, cbAuthBlob); - CoTaskMemFree(pvAuthBlob); - pvAuthBlob = nullptr; - } - return dwResult; // ERROR_SUCCESS / ERROR_CANCELLED - } - - return ERROR_CALL_NOT_IMPLEMENTED; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "AuthDlg.h" + +// We need to dynamically link to the functions provided by CredUI.lib in order +// to be able to use the features available to the OS. +#include +#include "WinApiFunc.h" + +HRESULT PromptForCredentials(HWND hWnd, const CString& strCaptionText, const CString& strMessageText, CString& strDomain, CString& strUsername, CString& strPassword, BOOL* bSave) +{ + CREDUI_INFO info = { sizeof(info) }; + info.hwndParent = hWnd; + info.pszCaptionText = strCaptionText.Left(CREDUI_MAX_CAPTION_LENGTH); + info.pszMessageText = strMessageText.Left(CREDUI_MAX_MESSAGE_LENGTH); + + DWORD dwUsername = CREDUI_MAX_USERNAME_LENGTH + 1; + DWORD dwPassword = CREDUI_MAX_PASSWORD_LENGTH + 1; + DWORD dwDomain = CREDUI_MAX_GENERIC_TARGET_LENGTH + 1; + + // Define CredUI.dll functions for Windows Vista+ + const WinapiFunc + fnCredPackAuthenticationBufferW = { _T("CREDUI.DLL"), "CredPackAuthenticationBufferW" }; + + const WinapiFunc + fnCredUIPromptForWindowsCredentialsW = { _T("CREDUI.DLL"), "CredUIPromptForWindowsCredentialsW" }; + + const WinapiFunc + fnCredUnPackAuthenticationBufferW = { _T("CREDUI.DLL"), "CredUnPackAuthenticationBufferW" }; + + if (fnCredPackAuthenticationBufferW && fnCredUIPromptForWindowsCredentialsW && fnCredUnPackAuthenticationBufferW) { + PVOID pvInAuthBlob = nullptr; + ULONG cbInAuthBlob = 0; + PVOID pvAuthBlob = nullptr; + ULONG cbAuthBlob = 0; + ULONG ulAuthPackage = 0; + + // Call CredPackAuthenticationBufferW once to determine the size, in bytes, of the authentication buffer. + if (strUsername.GetLength()) { + BOOL bResult = fnCredPackAuthenticationBufferW(0, (LPTSTR)(LPCTSTR)strUsername, (LPTSTR)(LPCTSTR)strPassword, nullptr, &cbInAuthBlob); + if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + if ((pvInAuthBlob = CoTaskMemAlloc(cbInAuthBlob)) != nullptr) { + VERIFY(fnCredPackAuthenticationBufferW(0, (LPTSTR)(LPCTSTR)strUsername, (LPTSTR)(LPCTSTR)strPassword, (PBYTE)pvInAuthBlob, &cbInAuthBlob)); + } + } + } + const DWORD dwFlags = CREDUIWIN_GENERIC | CREDUIWIN_ENUMERATE_CURRENT_USER | (bSave ? CREDUIWIN_CHECKBOX : 0); + DWORD dwResult = fnCredUIPromptForWindowsCredentialsW(&info, 0, &ulAuthPackage, pvInAuthBlob, cbInAuthBlob, &pvAuthBlob, &cbAuthBlob, bSave, dwFlags); + if (dwResult == ERROR_SUCCESS) { + VERIFY(fnCredUnPackAuthenticationBufferW(0, pvAuthBlob, cbAuthBlob, strUsername.GetBufferSetLength(dwUsername), &dwUsername, strDomain.GetBufferSetLength(dwDomain), &dwDomain, strPassword.GetBufferSetLength(dwPassword), &dwPassword)); + strUsername.ReleaseBuffer(); + strPassword.ReleaseBuffer(); + strDomain.ReleaseBuffer(); + } + + // Delete the input authentication byte array. + if (pvInAuthBlob) { + SecureZeroMemory(pvInAuthBlob, cbInAuthBlob); + CoTaskMemFree(pvInAuthBlob); + pvInAuthBlob = nullptr; + } + // Delete the output authentication byte array. + if (pvAuthBlob) { + SecureZeroMemory(pvAuthBlob, cbAuthBlob); + CoTaskMemFree(pvAuthBlob); + pvAuthBlob = nullptr; + } + return dwResult; // ERROR_SUCCESS / ERROR_CANCELLED + } + + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/src/mpc-hc/AuthDlg.h b/src/mpc-hc/AuthDlg.h index b440df5e63b..288c4bd384e 100644 --- a/src/mpc-hc/AuthDlg.h +++ b/src/mpc-hc/AuthDlg.h @@ -1,26 +1,26 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include - -HRESULT PromptForCredentials(HWND hWnd, const CString& strCaptionText, const CString& strMessageText, CString& strDomain, CString& strUsername, CString& strPassword, BOOL* bSave); +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include + +HRESULT PromptForCredentials(HWND hWnd, const CString& strCaptionText, const CString& strMessageText, CString& strDomain, CString& strUsername, CString& strPassword, BOOL* bSave); diff --git a/src/mpc-hc/BaseGraph.cpp b/src/mpc-hc/BaseGraph.cpp index f77ed1a0f99..c5d117c7c20 100644 --- a/src/mpc-hc/BaseGraph.cpp +++ b/src/mpc-hc/BaseGraph.cpp @@ -1,909 +1,909 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "BaseGraph.h" -#include "DSUtil.h" - - -// -// CPlayerWindow -// - -BOOL CPlayerWindow::PreCreateWindow(CREATESTRUCT& cs) -{ - if (!CWnd::PreCreateWindow(cs)) { - return FALSE; - } - - cs.style &= ~WS_BORDER; - cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, - ::LoadCursor(nullptr, IDC_HAND), nullptr, nullptr); - - return TRUE; -} - -BEGIN_MESSAGE_MAP(CPlayerWindow, CWnd) - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -BOOL CPlayerWindow::OnEraseBkgnd(CDC* pDC) -{ - for (CWnd* pChild = GetWindow(GW_CHILD); pChild; pChild = pChild->GetNextWindow()) { - if (!pChild->IsWindowVisible()) { - continue; - } - - CRect r; - pChild->GetClientRect(&r); - pChild->MapWindowPoints(this, &r); - pDC->ExcludeClipRect(&r); - } - - CRect r; - GetClientRect(&r); - pDC->FillSolidRect(&r, 0); - - return TRUE; -} - -// -// CBaseGraph -// - -CBaseGraph::CBaseGraph() - : CUnknown(NAME("CBaseGraph"), nullptr) - , m_hNotifyWnd(0) - , m_lNotifyMsg(0) - , m_lNotifyInstData(0) -{ -} - -CBaseGraph::~CBaseGraph() -{ -} - -STDMETHODIMP CBaseGraph::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFilterGraph) - QI(IGraphBuilder) - QI(IFilterGraph2) - QI(IGraphBuilder2) - QI(IMediaControl) - QI(IMediaSeeking) - QI(IMediaEventEx) - QI(IVideoWindow) - QI(IBasicVideo) - QI(IBasicAudio) - QI(IAMOpenProgress) - QI(IGraphEngine) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CBaseGraph::ClearMessageQueue() -{ - while (!m_msgqueue.IsEmpty()) { - GMSG msg = m_msgqueue.RemoveHead(); - FreeEventParams(msg.m_lEventCode, msg.m_lParam1, msg.m_lParam2); - } -} - -void CBaseGraph::NotifyEvent(long lEventCode, LONG_PTR lParam1, LONG_PTR lParam2) -{ - if (!m_hNotifyWnd) { - return; - } - - GMSG msg; - msg.m_lEventCode = lEventCode; - msg.m_lParam1 = lParam1; - msg.m_lParam2 = lParam2; - m_msgqueue.AddTail(msg); - - PostMessage((HWND)m_hNotifyWnd, m_lNotifyMsg, (WPARAM)0, m_lNotifyInstData); -} - -// IDispatch -STDMETHODIMP CBaseGraph::GetTypeInfoCount(UINT* pctinfo) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) -{ - return E_NOTIMPL; -} - -// IFilterGraph -STDMETHODIMP CBaseGraph::AddFilter(IBaseFilter* pFilter, LPCWSTR pName) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RemoveFilter(IBaseFilter* pFilter) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::EnumFilters(IEnumFilters** ppEnum) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConnectDirect(IPin* ppinOut, IPin* ppinIn, const AM_MEDIA_TYPE* pmt) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Reconnect(IPin* ppin) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Disconnect(IPin* ppin) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetDefaultSyncSource() -{ - return E_NOTIMPL; -} - -// IGraphBuilder -STDMETHODIMP CBaseGraph::Connect(IPin* ppinOut, IPin* ppinIn) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Render(IPin* ppinOut) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - *ppFilter = nullptr; - return RenderFile(lpcwstrFileName, nullptr); -}//E_NOTIMPL;} - -STDMETHODIMP CBaseGraph::SetLogFile(DWORD_PTR hFile) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Abort() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ShouldOperationContinue() -{ - return E_NOTIMPL; -} - -// IFilterGraph2 -STDMETHODIMP CBaseGraph::AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext) -{ - return E_NOTIMPL; -} - -// IGraphBuilder2 -STDMETHODIMP CBaseGraph::IsPinDirection(IPin* pPin, PIN_DIRECTION dir) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::IsPinConnected(IPin* pPin) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConnectFilter(IBaseFilter* pBF, IPin* pPinIn) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConnectFilter(IPin* pPinOut, IBaseFilter* pBF) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::NukeDownstream(IUnknown* pUnk) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::FindInterface(REFIID iid, void** ppv, BOOL bRemove) -{ - return QueryInterface(iid, ppv); -} - -STDMETHODIMP CBaseGraph::AddToROT() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RemoveFromROT() -{ - return E_NOTIMPL; -} - -// IMediaControl -STDMETHODIMP CBaseGraph::Run() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Pause() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::Stop() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetState(LONG msTimeout, OAFilterState* pfs) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RenderFile(BSTR strFilename) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::AddSourceFilter(BSTR strFilename, IDispatch** ppUnk) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_FilterCollection(IDispatch** ppUnk) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_RegFilterCollection(IDispatch** ppUnk) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::StopWhenReady() -{ - return Stop(); -} - -// IMediaEvent -STDMETHODIMP CBaseGraph::GetEventHandle(OAEVENT* hEvent) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetEvent(long* lEventCode, LONG_PTR* lParam1, LONG_PTR* lParam2, long msTimeout) -{ - if (m_msgqueue.IsEmpty()) { - return E_FAIL; - } - - GMSG msg = m_msgqueue.RemoveHead(); - if (lEventCode) { - *lEventCode = msg.m_lEventCode; - } - if (lParam1) { - *lParam1 = msg.m_lParam1; - } - if (lParam2) { - *lParam2 = msg.m_lParam2; - } - - return S_OK; -} - -STDMETHODIMP CBaseGraph::WaitForCompletion(long msTimeout, long* pEvCode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::CancelDefaultHandling(long lEvCode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::RestoreDefaultHandling(long lEvCode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::FreeEventParams(long lEvCode, LONG_PTR lParam1, LONG_PTR lParam2) -{ - if (EC_BG_ERROR == lEvCode) { - if (lParam1) { - CoTaskMemFree((void*)lParam1); - } - } - - return S_OK; -} - -// IMediaEventEx -STDMETHODIMP CBaseGraph::SetNotifyWindow(OAHWND hwnd, long lMsg, LONG_PTR lInstanceData) -{ - m_hNotifyWnd = hwnd; - m_lNotifyMsg = lMsg; - m_lNotifyInstData = lInstanceData; - - if (!IsWindow((HWND)m_hNotifyWnd)) { - m_hNotifyWnd = 0; - return E_FAIL; - } - - return S_OK; -} - -STDMETHODIMP CBaseGraph::SetNotifyFlags(long lNoNotifyFlags) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetNotifyFlags(long* lplNoNotifyFlags) -{ - return E_NOTIMPL; -} - -// IMediaSeeking -STDMETHODIMP CBaseGraph::GetCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - *pCapabilities = AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetCurrentPos | AM_SEEKING_CanGetDuration; - - return S_OK; -} - -STDMETHODIMP CBaseGraph::CheckCapabilities(DWORD* pCapabilities) -{ - CheckPointer(pCapabilities, E_POINTER); - - if (*pCapabilities == 0) { - return S_OK; - } - - DWORD caps; - GetCapabilities(&caps); - - DWORD caps2 = caps & *pCapabilities; - - return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseGraph::IsFormatSupported(const GUID* pFormat) -{ - return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -STDMETHODIMP CBaseGraph::QueryPreferredFormat(GUID* pFormat) -{ - return GetTimeFormat(pFormat); -} - -STDMETHODIMP CBaseGraph::GetTimeFormat(GUID* pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - - return S_OK; -} - -STDMETHODIMP CBaseGraph::IsUsingTimeFormat(const GUID* pFormat) -{ - return IsFormatSupported(pFormat); -} - -STDMETHODIMP CBaseGraph::SetTimeFormat(const GUID* pFormat) -{ - return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; -} - -STDMETHODIMP CBaseGraph::GetDuration(LONGLONG* pDuration) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetStopPosition(LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetCurrentPosition(LONGLONG* pCurrent) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetRate(double dRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetRate(double* pdRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetPreroll(LONGLONG* pllPreroll) -{ - return E_NOTIMPL; -} - -// IVideoWindow -STDMETHODIMP CBaseGraph::put_Caption(BSTR strCaption) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Caption(BSTR* strCaption) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_WindowStyle(long WindowStyle) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_WindowStyle(long* WindowStyle) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_WindowStyleEx(long WindowStyleEx) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_WindowStyleEx(long* WindowStyleEx) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_AutoShow(long AutoShow) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_AutoShow(long* AutoShow) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_WindowState(long WindowState) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_WindowState(long* WindowState) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_BackgroundPalette(long BackgroundPalette) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_BackgroundPalette(long* pBackgroundPalette) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Visible(long Visible) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Visible(long* pVisible) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Left(long Left) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Left(long* pLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Width(long Width) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Width(long* pWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Top(long Top) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Top(long* pTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Height(long Height) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Height(long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Owner(OAHWND Owner) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Owner(OAHWND* Owner) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_MessageDrain(OAHWND Drain) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_MessageDrain(OAHWND* Drain) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_BorderColor(long* Color) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_BorderColor(long Color) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_FullScreenMode(long* FullScreenMode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_FullScreenMode(long FullScreenMode) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetWindowForeground(long Focus) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetWindowPosition(long Left, long Top, long Width, long Height) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetMinIdealImageSize(long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetMaxIdealImageSize(long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::HideCursor(long HideCursor) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::IsCursorHidden(long* CursorHidden) -{ - return E_NOTIMPL; -} - -// IBasicVideo -STDMETHODIMP CBaseGraph::get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_BitRate(long* pBitRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_BitErrorRate(long* pBitErrorRate) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_VideoWidth(long* pVideoWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_VideoHeight(long* pVideoHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_SourceLeft(long SourceLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_SourceLeft(long* pSourceLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_SourceWidth(long SourceWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_SourceWidth(long* pSourceWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_SourceTop(long SourceTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_SourceTop(long* pSourceTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_SourceHeight(long SourceHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_SourceHeight(long* pSourceHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_DestinationLeft(long DestinationLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_DestinationLeft(long* pDestinationLeft) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_DestinationWidth(long DestinationWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_DestinationWidth(long* pDestinationWidth) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_DestinationTop(long DestinationTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_DestinationTop(long* pDestinationTop) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_DestinationHeight(long DestinationHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_DestinationHeight(long* pDestinationHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetSourcePosition(long Left, long Top, long Width, long Height) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetDefaultSourcePosition() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetDestinationPosition(long Left, long Top, long Width, long Height) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::SetDefaultDestinationPosition() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetVideoSize(long* pWidth, long* pHeight) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::GetCurrentImage(long* pBufferSize, long* pDIBImage) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::IsUsingDefaultSource() -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::IsUsingDefaultDestination() -{ - return E_NOTIMPL; -} - -// IBasicAudio -STDMETHODIMP CBaseGraph::put_Volume(long lVolume) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Volume(long* plVolume) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::put_Balance(long lBalance) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::get_Balance(long* plBalance) -{ - return E_NOTIMPL; -} - -// IAMOpenProgress -STDMETHODIMP CBaseGraph::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CBaseGraph::AbortOperation() -{ - return E_NOTIMPL; -} - -// IGraphEngine -STDMETHODIMP_(engine_t) CBaseGraph::GetEngine() -{ - return DirectShow; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "BaseGraph.h" +#include "DSUtil.h" + + +// +// CPlayerWindow +// + +BOOL CPlayerWindow::PreCreateWindow(CREATESTRUCT& cs) +{ + if (!CWnd::PreCreateWindow(cs)) { + return FALSE; + } + + cs.style &= ~WS_BORDER; + cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + ::LoadCursor(nullptr, IDC_HAND), nullptr, nullptr); + + return TRUE; +} + +BEGIN_MESSAGE_MAP(CPlayerWindow, CWnd) + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +BOOL CPlayerWindow::OnEraseBkgnd(CDC* pDC) +{ + for (CWnd* pChild = GetWindow(GW_CHILD); pChild; pChild = pChild->GetNextWindow()) { + if (!pChild->IsWindowVisible()) { + continue; + } + + CRect r; + pChild->GetClientRect(&r); + pChild->MapWindowPoints(this, &r); + pDC->ExcludeClipRect(&r); + } + + CRect r; + GetClientRect(&r); + pDC->FillSolidRect(&r, 0); + + return TRUE; +} + +// +// CBaseGraph +// + +CBaseGraph::CBaseGraph() + : CUnknown(NAME("CBaseGraph"), nullptr) + , m_hNotifyWnd(0) + , m_lNotifyMsg(0) + , m_lNotifyInstData(0) +{ +} + +CBaseGraph::~CBaseGraph() +{ +} + +STDMETHODIMP CBaseGraph::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFilterGraph) + QI(IGraphBuilder) + QI(IFilterGraph2) + QI(IGraphBuilder2) + QI(IMediaControl) + QI(IMediaSeeking) + QI(IMediaEventEx) + QI(IVideoWindow) + QI(IBasicVideo) + QI(IBasicAudio) + QI(IAMOpenProgress) + QI(IGraphEngine) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CBaseGraph::ClearMessageQueue() +{ + while (!m_msgqueue.IsEmpty()) { + GMSG msg = m_msgqueue.RemoveHead(); + FreeEventParams(msg.m_lEventCode, msg.m_lParam1, msg.m_lParam2); + } +} + +void CBaseGraph::NotifyEvent(long lEventCode, LONG_PTR lParam1, LONG_PTR lParam2) +{ + if (!m_hNotifyWnd) { + return; + } + + GMSG msg; + msg.m_lEventCode = lEventCode; + msg.m_lParam1 = lParam1; + msg.m_lParam2 = lParam2; + m_msgqueue.AddTail(msg); + + PostMessage((HWND)m_hNotifyWnd, m_lNotifyMsg, (WPARAM)0, m_lNotifyInstData); +} + +// IDispatch +STDMETHODIMP CBaseGraph::GetTypeInfoCount(UINT* pctinfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + return E_NOTIMPL; +} + +// IFilterGraph +STDMETHODIMP CBaseGraph::AddFilter(IBaseFilter* pFilter, LPCWSTR pName) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RemoveFilter(IBaseFilter* pFilter) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::EnumFilters(IEnumFilters** ppEnum) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConnectDirect(IPin* ppinOut, IPin* ppinIn, const AM_MEDIA_TYPE* pmt) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Reconnect(IPin* ppin) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Disconnect(IPin* ppin) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetDefaultSyncSource() +{ + return E_NOTIMPL; +} + +// IGraphBuilder +STDMETHODIMP CBaseGraph::Connect(IPin* ppinOut, IPin* ppinIn) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Render(IPin* ppinOut) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + *ppFilter = nullptr; + return RenderFile(lpcwstrFileName, nullptr); +}//E_NOTIMPL;} + +STDMETHODIMP CBaseGraph::SetLogFile(DWORD_PTR hFile) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Abort() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ShouldOperationContinue() +{ + return E_NOTIMPL; +} + +// IFilterGraph2 +STDMETHODIMP CBaseGraph::AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext) +{ + return E_NOTIMPL; +} + +// IGraphBuilder2 +STDMETHODIMP CBaseGraph::IsPinDirection(IPin* pPin, PIN_DIRECTION dir) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::IsPinConnected(IPin* pPin) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConnectFilter(IBaseFilter* pBF, IPin* pPinIn) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConnectFilter(IPin* pPinOut, IBaseFilter* pBF) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::NukeDownstream(IUnknown* pUnk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::FindInterface(REFIID iid, void** ppv, BOOL bRemove) +{ + return QueryInterface(iid, ppv); +} + +STDMETHODIMP CBaseGraph::AddToROT() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RemoveFromROT() +{ + return E_NOTIMPL; +} + +// IMediaControl +STDMETHODIMP CBaseGraph::Run() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Pause() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::Stop() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetState(LONG msTimeout, OAFilterState* pfs) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RenderFile(BSTR strFilename) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::AddSourceFilter(BSTR strFilename, IDispatch** ppUnk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_FilterCollection(IDispatch** ppUnk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_RegFilterCollection(IDispatch** ppUnk) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::StopWhenReady() +{ + return Stop(); +} + +// IMediaEvent +STDMETHODIMP CBaseGraph::GetEventHandle(OAEVENT* hEvent) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetEvent(long* lEventCode, LONG_PTR* lParam1, LONG_PTR* lParam2, long msTimeout) +{ + if (m_msgqueue.IsEmpty()) { + return E_FAIL; + } + + GMSG msg = m_msgqueue.RemoveHead(); + if (lEventCode) { + *lEventCode = msg.m_lEventCode; + } + if (lParam1) { + *lParam1 = msg.m_lParam1; + } + if (lParam2) { + *lParam2 = msg.m_lParam2; + } + + return S_OK; +} + +STDMETHODIMP CBaseGraph::WaitForCompletion(long msTimeout, long* pEvCode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::CancelDefaultHandling(long lEvCode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::RestoreDefaultHandling(long lEvCode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::FreeEventParams(long lEvCode, LONG_PTR lParam1, LONG_PTR lParam2) +{ + if (EC_BG_ERROR == lEvCode) { + if (lParam1) { + CoTaskMemFree((void*)lParam1); + } + } + + return S_OK; +} + +// IMediaEventEx +STDMETHODIMP CBaseGraph::SetNotifyWindow(OAHWND hwnd, long lMsg, LONG_PTR lInstanceData) +{ + m_hNotifyWnd = hwnd; + m_lNotifyMsg = lMsg; + m_lNotifyInstData = lInstanceData; + + if (!IsWindow((HWND)m_hNotifyWnd)) { + m_hNotifyWnd = 0; + return E_FAIL; + } + + return S_OK; +} + +STDMETHODIMP CBaseGraph::SetNotifyFlags(long lNoNotifyFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetNotifyFlags(long* lplNoNotifyFlags) +{ + return E_NOTIMPL; +} + +// IMediaSeeking +STDMETHODIMP CBaseGraph::GetCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + *pCapabilities = AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetCurrentPos | AM_SEEKING_CanGetDuration; + + return S_OK; +} + +STDMETHODIMP CBaseGraph::CheckCapabilities(DWORD* pCapabilities) +{ + CheckPointer(pCapabilities, E_POINTER); + + if (*pCapabilities == 0) { + return S_OK; + } + + DWORD caps; + GetCapabilities(&caps); + + DWORD caps2 = caps & *pCapabilities; + + return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseGraph::IsFormatSupported(const GUID* pFormat) +{ + return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +STDMETHODIMP CBaseGraph::QueryPreferredFormat(GUID* pFormat) +{ + return GetTimeFormat(pFormat); +} + +STDMETHODIMP CBaseGraph::GetTimeFormat(GUID* pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + + return S_OK; +} + +STDMETHODIMP CBaseGraph::IsUsingTimeFormat(const GUID* pFormat) +{ + return IsFormatSupported(pFormat); +} + +STDMETHODIMP CBaseGraph::SetTimeFormat(const GUID* pFormat) +{ + return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG; +} + +STDMETHODIMP CBaseGraph::GetDuration(LONGLONG* pDuration) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetStopPosition(LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetCurrentPosition(LONGLONG* pCurrent) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetRate(double dRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetRate(double* pdRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetPreroll(LONGLONG* pllPreroll) +{ + return E_NOTIMPL; +} + +// IVideoWindow +STDMETHODIMP CBaseGraph::put_Caption(BSTR strCaption) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Caption(BSTR* strCaption) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_WindowStyle(long WindowStyle) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_WindowStyle(long* WindowStyle) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_WindowStyleEx(long WindowStyleEx) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_WindowStyleEx(long* WindowStyleEx) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_AutoShow(long AutoShow) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_AutoShow(long* AutoShow) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_WindowState(long WindowState) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_WindowState(long* WindowState) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_BackgroundPalette(long BackgroundPalette) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_BackgroundPalette(long* pBackgroundPalette) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Visible(long Visible) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Visible(long* pVisible) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Left(long Left) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Left(long* pLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Width(long Width) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Width(long* pWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Top(long Top) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Top(long* pTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Height(long Height) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Height(long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Owner(OAHWND Owner) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Owner(OAHWND* Owner) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_MessageDrain(OAHWND Drain) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_MessageDrain(OAHWND* Drain) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_BorderColor(long* Color) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_BorderColor(long Color) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_FullScreenMode(long* FullScreenMode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_FullScreenMode(long FullScreenMode) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetWindowForeground(long Focus) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetWindowPosition(long Left, long Top, long Width, long Height) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetMinIdealImageSize(long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetMaxIdealImageSize(long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::HideCursor(long HideCursor) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::IsCursorHidden(long* CursorHidden) +{ + return E_NOTIMPL; +} + +// IBasicVideo +STDMETHODIMP CBaseGraph::get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_BitRate(long* pBitRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_BitErrorRate(long* pBitErrorRate) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_VideoWidth(long* pVideoWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_VideoHeight(long* pVideoHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_SourceLeft(long SourceLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_SourceLeft(long* pSourceLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_SourceWidth(long SourceWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_SourceWidth(long* pSourceWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_SourceTop(long SourceTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_SourceTop(long* pSourceTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_SourceHeight(long SourceHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_SourceHeight(long* pSourceHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_DestinationLeft(long DestinationLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_DestinationLeft(long* pDestinationLeft) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_DestinationWidth(long DestinationWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_DestinationWidth(long* pDestinationWidth) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_DestinationTop(long DestinationTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_DestinationTop(long* pDestinationTop) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_DestinationHeight(long DestinationHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_DestinationHeight(long* pDestinationHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetSourcePosition(long Left, long Top, long Width, long Height) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetDefaultSourcePosition() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetDestinationPosition(long Left, long Top, long Width, long Height) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::SetDefaultDestinationPosition() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetVideoSize(long* pWidth, long* pHeight) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::GetCurrentImage(long* pBufferSize, long* pDIBImage) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::IsUsingDefaultSource() +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::IsUsingDefaultDestination() +{ + return E_NOTIMPL; +} + +// IBasicAudio +STDMETHODIMP CBaseGraph::put_Volume(long lVolume) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Volume(long* plVolume) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::put_Balance(long lBalance) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::get_Balance(long* plBalance) +{ + return E_NOTIMPL; +} + +// IAMOpenProgress +STDMETHODIMP CBaseGraph::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CBaseGraph::AbortOperation() +{ + return E_NOTIMPL; +} + +// IGraphEngine +STDMETHODIMP_(engine_t) CBaseGraph::GetEngine() +{ + return DirectShow; +} diff --git a/src/mpc-hc/BaseGraph.h b/src/mpc-hc/BaseGraph.h index 0b76c68fdf9..1f388f0ecf7 100644 --- a/src/mpc-hc/BaseGraph.h +++ b/src/mpc-hc/BaseGraph.h @@ -1,261 +1,261 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include "IGraphBuilder2.h" - - -class CPlayerWindow : public CWnd -{ -public: - CPlayerWindow() {} - -protected: - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - DECLARE_MESSAGE_MAP() -}; - -enum engine_t { - DirectShow = 0, - ShockWave = 3 -}; - -interface __declspec(uuid("B110CDE5-6331-4118-8AAF-A870D6F7E2E4")) - IGraphEngine : - public IUnknown -{ - STDMETHOD_(engine_t, GetEngine)() PURE; -}; - -enum { - EC_BG_AUDIO_CHANGED = EC_USER + 1, - EC_BG_ERROR -}; - -class CBaseGraph - : public CUnknown - , public IGraphBuilder2 - , public IMediaControl - , public IMediaEventEx - , public IMediaSeeking - , public IVideoWindow - , public IBasicVideo - , public IBasicAudio - , public IAMOpenProgress - , public IGraphEngine -{ - OAHWND m_hNotifyWnd; - long m_lNotifyMsg; - LONG_PTR m_lNotifyInstData; - - struct GMSG { - long m_lEventCode; - LONG_PTR m_lParam1, m_lParam2; - }; - CList m_msgqueue; - -protected: - void ClearMessageQueue(); - -public: - CBaseGraph(); - virtual ~CBaseGraph(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - void NotifyEvent(long lEventCode, LONG_PTR lParam1 = 0, LONG_PTR lParam2 = 0); - -protected: - // IDispatch - STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); - STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo); - STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId); - STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr); - - // IFilterGraph - STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); - STDMETHODIMP RemoveFilter(IBaseFilter* pFilter); - STDMETHODIMP EnumFilters(IEnumFilters** ppEnum); - STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter); - STDMETHODIMP ConnectDirect(IPin* ppinOut, IPin* ppinIn, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP Reconnect(IPin* ppin); - STDMETHODIMP Disconnect(IPin* ppin); - STDMETHODIMP SetDefaultSyncSource(); - - // IGraphBuilder - STDMETHODIMP Connect(IPin* ppinOut, IPin* ppinIn); - STDMETHODIMP Render(IPin* ppinOut); - STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); - STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - STDMETHODIMP SetLogFile(DWORD_PTR hFile); - STDMETHODIMP Abort(); - STDMETHODIMP ShouldOperationContinue(); - - // IFilterGraph2 - STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext); - - // IGraphBuilder2 - STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir); - STDMETHODIMP IsPinConnected(IPin* pPin); - STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn); - STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF); - STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP NukeDownstream(IUnknown* pUnk); - STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove); - STDMETHODIMP AddToROT(); - STDMETHODIMP RemoveFromROT(); - - // IMediaControl - STDMETHODIMP Run(); - STDMETHODIMP Pause(); - STDMETHODIMP Stop(); - STDMETHODIMP GetState(LONG msTimeout, OAFilterState* pfs); - STDMETHODIMP RenderFile(BSTR strFilename); - STDMETHODIMP AddSourceFilter(BSTR strFilename, IDispatch** ppUnk); - STDMETHODIMP get_FilterCollection(IDispatch** ppUnk); - STDMETHODIMP get_RegFilterCollection(IDispatch** ppUnk); - STDMETHODIMP StopWhenReady(); - - // IMediaEvent - STDMETHODIMP GetEventHandle(OAEVENT* hEvent); - STDMETHODIMP GetEvent(long* lEventCode, LONG_PTR* lParam1, LONG_PTR* lParam2, long msTimeout); - STDMETHODIMP WaitForCompletion(long msTimeout, long* pEvCode); - STDMETHODIMP CancelDefaultHandling(long lEvCode); - STDMETHODIMP RestoreDefaultHandling(long lEvCode); - STDMETHODIMP FreeEventParams(long lEvCode, LONG_PTR lParam1, LONG_PTR lParam2); - - // IMediaEventEx - STDMETHODIMP SetNotifyWindow(OAHWND hwnd, long lMsg, LONG_PTR lInstanceData); - STDMETHODIMP SetNotifyFlags(long lNoNotifyFlags); - STDMETHODIMP GetNotifyFlags(long* lplNoNotifyFlags); - - // IMediaSeeking - STDMETHODIMP GetCapabilities(DWORD* pCapabilities); - STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); - STDMETHODIMP IsFormatSupported(const GUID* pFormat); - STDMETHODIMP QueryPreferredFormat(GUID* pFormat); - STDMETHODIMP GetTimeFormat(GUID* pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); - STDMETHODIMP SetTimeFormat(const GUID* pFormat); - STDMETHODIMP GetDuration(LONGLONG* pDuration); - STDMETHODIMP GetStopPosition(LONGLONG* pStop); - STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); - STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat); - STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags); - STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); - STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); - STDMETHODIMP SetRate(double dRate); - STDMETHODIMP GetRate(double* pdRate); - STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); - - // IVideoWindow - STDMETHODIMP put_Caption(BSTR strCaption); - STDMETHODIMP get_Caption(BSTR* strCaption); - STDMETHODIMP put_WindowStyle(long WindowStyle); - STDMETHODIMP get_WindowStyle(long* WindowStyle); - STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); - STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx); - STDMETHODIMP put_AutoShow(long AutoShow); - STDMETHODIMP get_AutoShow(long* AutoShow); - STDMETHODIMP put_WindowState(long WindowState); - STDMETHODIMP get_WindowState(long* WindowState); - STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); - STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette); - STDMETHODIMP put_Visible(long Visible); - STDMETHODIMP get_Visible(long* pVisible); - STDMETHODIMP put_Left(long Left); - STDMETHODIMP get_Left(long* pLeft); - STDMETHODIMP put_Width(long Width); - STDMETHODIMP get_Width(long* pWidth); - STDMETHODIMP put_Top(long Top); - STDMETHODIMP get_Top(long* pTop); - STDMETHODIMP put_Height(long Height); - STDMETHODIMP get_Height(long* pHeight); - STDMETHODIMP put_Owner(OAHWND Owner); - STDMETHODIMP get_Owner(OAHWND* Owner); - STDMETHODIMP put_MessageDrain(OAHWND Drain); - STDMETHODIMP get_MessageDrain(OAHWND* Drain); - STDMETHODIMP get_BorderColor(long* Color); - STDMETHODIMP put_BorderColor(long Color); - STDMETHODIMP get_FullScreenMode(long* FullScreenMode); - STDMETHODIMP put_FullScreenMode(long FullScreenMode); - STDMETHODIMP SetWindowForeground(long Focus); - STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam); - STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height); - STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight); - STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight); - STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - STDMETHODIMP HideCursor(long HideCursor); - STDMETHODIMP IsCursorHidden(long* CursorHidden); - - // IBasicVideo - STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame); - STDMETHODIMP get_BitRate(long* pBitRate); - STDMETHODIMP get_BitErrorRate(long* pBitErrorRate); - STDMETHODIMP get_VideoWidth(long* pVideoWidth); - STDMETHODIMP get_VideoHeight(long* pVideoHeight); - STDMETHODIMP put_SourceLeft(long SourceLeft); - STDMETHODIMP get_SourceLeft(long* pSourceLeft); - STDMETHODIMP put_SourceWidth(long SourceWidth); - STDMETHODIMP get_SourceWidth(long* pSourceWidth); - STDMETHODIMP put_SourceTop(long SourceTop); - STDMETHODIMP get_SourceTop(long* pSourceTop); - STDMETHODIMP put_SourceHeight(long SourceHeight); - STDMETHODIMP get_SourceHeight(long* pSourceHeight); - STDMETHODIMP put_DestinationLeft(long DestinationLeft); - STDMETHODIMP get_DestinationLeft(long* pDestinationLeft); - STDMETHODIMP put_DestinationWidth(long DestinationWidth); - STDMETHODIMP get_DestinationWidth(long* pDestinationWidth); - STDMETHODIMP put_DestinationTop(long DestinationTop); - STDMETHODIMP get_DestinationTop(long* pDestinationTop); - STDMETHODIMP put_DestinationHeight(long DestinationHeight); - STDMETHODIMP get_DestinationHeight(long* pDestinationHeight); - STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height); - STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - STDMETHODIMP SetDefaultSourcePosition(); - STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height); - STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); - STDMETHODIMP SetDefaultDestinationPosition(); - STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight); - STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette); - STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage); - STDMETHODIMP IsUsingDefaultSource(); - STDMETHODIMP IsUsingDefaultDestination(); - - // IBasicAudio - STDMETHODIMP put_Volume(long lVolume); - STDMETHODIMP get_Volume(long* plVolume); - STDMETHODIMP put_Balance(long lBalance); - STDMETHODIMP get_Balance(long* plBalance); - - // IAMOpenProgress - STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent); - STDMETHODIMP AbortOperation(); - - // IGraphEngine - STDMETHODIMP_(engine_t) GetEngine(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include "IGraphBuilder2.h" + + +class CPlayerWindow : public CWnd +{ +public: + CPlayerWindow() {} + +protected: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + DECLARE_MESSAGE_MAP() +}; + +enum engine_t { + DirectShow = 0, + ShockWave = 3 +}; + +interface __declspec(uuid("B110CDE5-6331-4118-8AAF-A870D6F7E2E4")) + IGraphEngine : + public IUnknown +{ + STDMETHOD_(engine_t, GetEngine)() PURE; +}; + +enum { + EC_BG_AUDIO_CHANGED = EC_USER + 1, + EC_BG_ERROR +}; + +class CBaseGraph + : public CUnknown + , public IGraphBuilder2 + , public IMediaControl + , public IMediaEventEx + , public IMediaSeeking + , public IVideoWindow + , public IBasicVideo + , public IBasicAudio + , public IAMOpenProgress + , public IGraphEngine +{ + OAHWND m_hNotifyWnd; + long m_lNotifyMsg; + LONG_PTR m_lNotifyInstData; + + struct GMSG { + long m_lEventCode; + LONG_PTR m_lParam1, m_lParam2; + }; + CList m_msgqueue; + +protected: + void ClearMessageQueue(); + +public: + CBaseGraph(); + virtual ~CBaseGraph(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + void NotifyEvent(long lEventCode, LONG_PTR lParam1 = 0, LONG_PTR lParam2 = 0); + +protected: + // IDispatch + STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); + STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo); + STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId); + STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr); + + // IFilterGraph + STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); + STDMETHODIMP RemoveFilter(IBaseFilter* pFilter); + STDMETHODIMP EnumFilters(IEnumFilters** ppEnum); + STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter); + STDMETHODIMP ConnectDirect(IPin* ppinOut, IPin* ppinIn, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP Reconnect(IPin* ppin); + STDMETHODIMP Disconnect(IPin* ppin); + STDMETHODIMP SetDefaultSyncSource(); + + // IGraphBuilder + STDMETHODIMP Connect(IPin* ppinOut, IPin* ppinIn); + STDMETHODIMP Render(IPin* ppinOut); + STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); + STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + STDMETHODIMP SetLogFile(DWORD_PTR hFile); + STDMETHODIMP Abort(); + STDMETHODIMP ShouldOperationContinue(); + + // IFilterGraph2 + STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext); + + // IGraphBuilder2 + STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir); + STDMETHODIMP IsPinConnected(IPin* pPin); + STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn); + STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF); + STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP NukeDownstream(IUnknown* pUnk); + STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove); + STDMETHODIMP AddToROT(); + STDMETHODIMP RemoveFromROT(); + + // IMediaControl + STDMETHODIMP Run(); + STDMETHODIMP Pause(); + STDMETHODIMP Stop(); + STDMETHODIMP GetState(LONG msTimeout, OAFilterState* pfs); + STDMETHODIMP RenderFile(BSTR strFilename); + STDMETHODIMP AddSourceFilter(BSTR strFilename, IDispatch** ppUnk); + STDMETHODIMP get_FilterCollection(IDispatch** ppUnk); + STDMETHODIMP get_RegFilterCollection(IDispatch** ppUnk); + STDMETHODIMP StopWhenReady(); + + // IMediaEvent + STDMETHODIMP GetEventHandle(OAEVENT* hEvent); + STDMETHODIMP GetEvent(long* lEventCode, LONG_PTR* lParam1, LONG_PTR* lParam2, long msTimeout); + STDMETHODIMP WaitForCompletion(long msTimeout, long* pEvCode); + STDMETHODIMP CancelDefaultHandling(long lEvCode); + STDMETHODIMP RestoreDefaultHandling(long lEvCode); + STDMETHODIMP FreeEventParams(long lEvCode, LONG_PTR lParam1, LONG_PTR lParam2); + + // IMediaEventEx + STDMETHODIMP SetNotifyWindow(OAHWND hwnd, long lMsg, LONG_PTR lInstanceData); + STDMETHODIMP SetNotifyFlags(long lNoNotifyFlags); + STDMETHODIMP GetNotifyFlags(long* lplNoNotifyFlags); + + // IMediaSeeking + STDMETHODIMP GetCapabilities(DWORD* pCapabilities); + STDMETHODIMP CheckCapabilities(DWORD* pCapabilities); + STDMETHODIMP IsFormatSupported(const GUID* pFormat); + STDMETHODIMP QueryPreferredFormat(GUID* pFormat); + STDMETHODIMP GetTimeFormat(GUID* pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID* pFormat); + STDMETHODIMP SetTimeFormat(const GUID* pFormat); + STDMETHODIMP GetDuration(LONGLONG* pDuration); + STDMETHODIMP GetStopPosition(LONGLONG* pStop); + STDMETHODIMP GetCurrentPosition(LONGLONG* pCurrent); + STDMETHODIMP ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat); + STDMETHODIMP SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags); + STDMETHODIMP GetPositions(LONGLONG* pCurrent, LONGLONG* pStop); + STDMETHODIMP GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest); + STDMETHODIMP SetRate(double dRate); + STDMETHODIMP GetRate(double* pdRate); + STDMETHODIMP GetPreroll(LONGLONG* pllPreroll); + + // IVideoWindow + STDMETHODIMP put_Caption(BSTR strCaption); + STDMETHODIMP get_Caption(BSTR* strCaption); + STDMETHODIMP put_WindowStyle(long WindowStyle); + STDMETHODIMP get_WindowStyle(long* WindowStyle); + STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); + STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx); + STDMETHODIMP put_AutoShow(long AutoShow); + STDMETHODIMP get_AutoShow(long* AutoShow); + STDMETHODIMP put_WindowState(long WindowState); + STDMETHODIMP get_WindowState(long* WindowState); + STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); + STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette); + STDMETHODIMP put_Visible(long Visible); + STDMETHODIMP get_Visible(long* pVisible); + STDMETHODIMP put_Left(long Left); + STDMETHODIMP get_Left(long* pLeft); + STDMETHODIMP put_Width(long Width); + STDMETHODIMP get_Width(long* pWidth); + STDMETHODIMP put_Top(long Top); + STDMETHODIMP get_Top(long* pTop); + STDMETHODIMP put_Height(long Height); + STDMETHODIMP get_Height(long* pHeight); + STDMETHODIMP put_Owner(OAHWND Owner); + STDMETHODIMP get_Owner(OAHWND* Owner); + STDMETHODIMP put_MessageDrain(OAHWND Drain); + STDMETHODIMP get_MessageDrain(OAHWND* Drain); + STDMETHODIMP get_BorderColor(long* Color); + STDMETHODIMP put_BorderColor(long Color); + STDMETHODIMP get_FullScreenMode(long* FullScreenMode); + STDMETHODIMP put_FullScreenMode(long FullScreenMode); + STDMETHODIMP SetWindowForeground(long Focus); + STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam); + STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height); + STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight); + STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight); + STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + STDMETHODIMP HideCursor(long HideCursor); + STDMETHODIMP IsCursorHidden(long* CursorHidden); + + // IBasicVideo + STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame); + STDMETHODIMP get_BitRate(long* pBitRate); + STDMETHODIMP get_BitErrorRate(long* pBitErrorRate); + STDMETHODIMP get_VideoWidth(long* pVideoWidth); + STDMETHODIMP get_VideoHeight(long* pVideoHeight); + STDMETHODIMP put_SourceLeft(long SourceLeft); + STDMETHODIMP get_SourceLeft(long* pSourceLeft); + STDMETHODIMP put_SourceWidth(long SourceWidth); + STDMETHODIMP get_SourceWidth(long* pSourceWidth); + STDMETHODIMP put_SourceTop(long SourceTop); + STDMETHODIMP get_SourceTop(long* pSourceTop); + STDMETHODIMP put_SourceHeight(long SourceHeight); + STDMETHODIMP get_SourceHeight(long* pSourceHeight); + STDMETHODIMP put_DestinationLeft(long DestinationLeft); + STDMETHODIMP get_DestinationLeft(long* pDestinationLeft); + STDMETHODIMP put_DestinationWidth(long DestinationWidth); + STDMETHODIMP get_DestinationWidth(long* pDestinationWidth); + STDMETHODIMP put_DestinationTop(long DestinationTop); + STDMETHODIMP get_DestinationTop(long* pDestinationTop); + STDMETHODIMP put_DestinationHeight(long DestinationHeight); + STDMETHODIMP get_DestinationHeight(long* pDestinationHeight); + STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height); + STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + STDMETHODIMP SetDefaultSourcePosition(); + STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height); + STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight); + STDMETHODIMP SetDefaultDestinationPosition(); + STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight); + STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette); + STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage); + STDMETHODIMP IsUsingDefaultSource(); + STDMETHODIMP IsUsingDefaultDestination(); + + // IBasicAudio + STDMETHODIMP put_Volume(long lVolume); + STDMETHODIMP get_Volume(long* plVolume); + STDMETHODIMP put_Balance(long lBalance); + STDMETHODIMP get_Balance(long* plBalance); + + // IAMOpenProgress + STDMETHODIMP QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent); + STDMETHODIMP AbortOperation(); + + // IGraphEngine + STDMETHODIMP_(engine_t) GetEngine(); +}; diff --git a/src/mpc-hc/CMPCTheme.cpp b/src/mpc-hc/CMPCTheme.cpp index 7e60883e2c5..b4d7b0eee3d 100755 --- a/src/mpc-hc/CMPCTheme.cpp +++ b/src/mpc-hc/CMPCTheme.cpp @@ -1,697 +1,697 @@ -#include "stdafx.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - -#define RGBGS(x) ((COLORREF)(((BYTE)(x)|((WORD)((BYTE)(x))<<8))|(((DWORD)(BYTE)(x))<<16))) - -const int CMPCTheme::GroupBoxTextIndent = 8; -bool CMPCTheme::drawThemedControls = false; -COLORREF CMPCTheme::CloseHoverColor = RGB(232, 17, 35); -COLORREF CMPCTheme::ClosePushColor = RGB(139, 10, 20); -COLORREF CMPCTheme::DebugColorRed = RGB(255, 0, 0); -COLORREF CMPCTheme::DebugColorYellow = RGB(255, 255, 0); -COLORREF CMPCTheme::DebugColorGreen = RGB(0, 255, 0); -COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedTextColor = RGB(255, 255, 255); -COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedBGColor = RGB(56, 56, 56); -COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedEditBorderColor = RGB(155, 155, 155); -COLORREF CMPCTheme::W10DarkThemeTitlebarBGColor = RGB(0, 0, 0); -COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveBGColor = RGB(43, 43, 43); -COLORREF CMPCTheme::W10DarkThemeTitlebarFGColor = RGB(255, 255, 255); -COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveFGColor = RGB(170, 170, 170); -COLORREF CMPCTheme::W10DarkThemeTitlebarIconPenColor = RGB(255, 255, 255); -COLORREF CMPCTheme::W10DarkThemeTitlebarControlHoverBGColor = RGB(43, 43, 43); -COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveControlHoverBGColor = RGB(65, 65, 65); -COLORREF CMPCTheme::W10DarkThemeTitlebarControlPushedBGColor = RGB(70, 70, 70); -COLORREF CMPCTheme::W10DarkThemeWindowBorderColor = RGB(57, 57, 57); - - - -COLORREF CMPCTheme::MenuBGColor; -COLORREF CMPCTheme::MenubarBGColor; -COLORREF CMPCTheme::WindowBGColor; -COLORREF CMPCTheme::ControlAreaBGColor; - -COLORREF CMPCTheme::ContentBGColor; -COLORREF CMPCTheme::ContentSelectedColor; -COLORREF CMPCTheme::PlayerBGColor; - -COLORREF CMPCTheme::HighLightColor; - -COLORREF CMPCTheme::MenuSelectedColor; -COLORREF CMPCTheme::MenubarSelectedBGColor; -COLORREF CMPCTheme::MenuSeparatorColor; -COLORREF CMPCTheme::MenuItemDisabledColor; -//COLORREF CMPCTheme::MenuItemUnfocusedColor; -COLORREF CMPCTheme::MainMenuBorderColor; - -COLORREF CMPCTheme::TextFGColor; -COLORREF CMPCTheme::TextFGColorFade; -COLORREF CMPCTheme::PropPageCaptionFGColor; -COLORREF CMPCTheme::ContentTextDisabledFGColorFade; -COLORREF CMPCTheme::ContentTextDisabledFGColorFade2; //even more faded, used for NA text on CListCtrl/audio switcher - -COLORREF CMPCTheme::SubmenuColor; - -COLORREF CMPCTheme::WindowBorderColorLight; -COLORREF CMPCTheme::WindowBorderColorDim; -COLORREF CMPCTheme::NoBorderColor; -COLORREF CMPCTheme::GripperPatternColor; //visual studio, since explorer has no grippers - -COLORREF CMPCTheme::ScrollBGColor; -COLORREF CMPCTheme::ScrollProgressColor; -COLORREF CMPCTheme::ScrollThumbColor; -COLORREF CMPCTheme::ScrollThumbHoverColor; -COLORREF CMPCTheme::ScrollThumbDragColor; -COLORREF CMPCTheme::ScrollButtonArrowColor; -COLORREF CMPCTheme::ScrollButtonArrowClickColor; -COLORREF CMPCTheme::ScrollButtonHoverColor; -COLORREF CMPCTheme::ScrollButtonClickColor; - -COLORREF CMPCTheme::InlineEditBorderColor; -COLORREF CMPCTheme::TooltipBorderColor; - -COLORREF CMPCTheme::GroupBoxBorderColor; - -COLORREF CMPCTheme::PlayerButtonHotColor; -COLORREF CMPCTheme::PlayerButtonCheckedColor; -COLORREF CMPCTheme::PlayerButtonClickedColor; -COLORREF CMPCTheme::PlayerButtonBorderColor; - -COLORREF CMPCTheme::ButtonBorderOuterColor; -COLORREF CMPCTheme::ButtonBorderInnerFocusedColor; -COLORREF CMPCTheme::ButtonBorderInnerColor; -COLORREF CMPCTheme::ButtonBorderSelectedKBFocusColor; -COLORREF CMPCTheme::ButtonBorderHoverKBFocusColor; -COLORREF CMPCTheme::ButtonBorderKBFocusColor; -COLORREF CMPCTheme::ButtonFillColor; -COLORREF CMPCTheme::ButtonFillHoverColor; -COLORREF CMPCTheme::ButtonFillSelectedColor; -COLORREF CMPCTheme::ButtonDisabledFGColor; - -COLORREF CMPCTheme::CheckboxBorderColor; -COLORREF CMPCTheme::CheckboxBGColor; -COLORREF CMPCTheme::CheckboxBorderHoverColor; -COLORREF CMPCTheme::CheckboxBGHoverColor; - -COLORREF CMPCTheme::ImageDisabledColor; - -COLORREF CMPCTheme::SliderChannelColor; - -COLORREF CMPCTheme::EditBorderColor; - -COLORREF CMPCTheme::TreeCtrlLineColor; -COLORREF CMPCTheme::TreeCtrlHoverColor; -COLORREF CMPCTheme::TreeCtrlFocusColor; - -COLORREF CMPCTheme::CheckColor; - -COLORREF CMPCTheme::ColumnHeaderHotColor; - -COLORREF CMPCTheme::StaticEtchedColor; - -COLORREF CMPCTheme::ListCtrlDisabledBGColor; -COLORREF CMPCTheme::ListCtrlGridColor; -COLORREF CMPCTheme::ListCtrlErrorColor; -COLORREF CMPCTheme::HeaderCtrlGridColor; -COLORREF CMPCTheme::AudioSwitcherGridColor; - -COLORREF CMPCTheme::TabCtrlBorderColor; -COLORREF CMPCTheme::TabCtrlInactiveColor; - - -COLORREF CMPCTheme::StatusBarBGColor; -COLORREF CMPCTheme::StatusBarSeparatorColor; - - -COLORREF CMPCTheme::ProgressBarBGColor; -COLORREF CMPCTheme::ProgressBarColor; - -COLORREF CMPCTheme::SubresyncFadeText1; -COLORREF CMPCTheme::SubresyncFadeText2; -COLORREF CMPCTheme::SubresyncActiveFadeText; -COLORREF CMPCTheme::SubresyncHLColor1; -COLORREF CMPCTheme::SubresyncHLColor2; -COLORREF CMPCTheme::SubresyncGridSepColor; - -COLORREF CMPCTheme::ActivePlayListItemColor; -COLORREF CMPCTheme::ActivePlayListItemHLColor; -COLORREF CMPCTheme::StaticLinkColor; - -COLORREF CMPCTheme::SeekbarCurrentPositionColor; -COLORREF CMPCTheme::SeekbarChapterColor; -COLORREF CMPCTheme::SeekbarABColor; - -wchar_t* const CMPCTheme::uiTextFont = L"Segoe UI"; -wchar_t* const CMPCTheme::uiStaticTextFont = L"Segoe UI Semilight"; -wchar_t* const CMPCTheme::uiSymbolFont = L"MS UI Gothic"; - - -const int CMPCTheme::gripPatternLong = 5; -const int CMPCTheme::gripPatternShort = 4; - - -const BYTE CMPCTheme::GripperBitsH[10] = { - 0x80, 0x00, - 0x00, 0x00, - 0x20, 0x00, - 0x00, 0x00, - 0x80, 0x00, -}; - -const BYTE CMPCTheme::GripperBitsV[8] = { - 0x88, 0x00, - 0x00, 0x00, - 0x20, 0x00, - 0x00, 0x00, -}; - -const COLORREF CMPCTheme::ComboboxArrowColor = RGB(200, 200, 200); -const COLORREF CMPCTheme::ComboboxArrowColorDisabled = RGB(100, 100, 100); - -const COLORREF CMPCTheme::HeaderCtrlSortArrowColor = RGB(200, 200, 200); - - -const BYTE CMPCTheme::CheckBits[14] = { - 0x02, 0x00, - 0x06, 0x00, - 0x8E, 0x00, - 0xDC, 0x00, - 0xF8, 0x00, - 0x70, 0x00, - 0x20, 0x00, -}; - -const int CMPCTheme::CheckWidth = 7; -const int CMPCTheme::CheckHeight = 7; - - -const UINT CMPCTheme::ThemeCheckBoxes[5] = { - IDB_DT_CB_96, - IDB_DT_CB_120, - IDB_DT_CB_144, - IDB_DT_CB_144, - IDB_DT_CB_192, -}; - -const UINT CMPCTheme::ThemeRadios[5] = { - IDB_DT_RADIO_96, - IDB_DT_RADIO_120, - IDB_DT_RADIO_144, - IDB_DT_RADIO_144, - IDB_DT_RADIO_192, -}; - -const UINT CMPCTheme::ThemeGrippers[5] = { - IDB_GRIPPER_96, - IDB_GRIPPER_120, - IDB_GRIPPER_144, - IDB_GRIPPER_168, - IDB_GRIPPER_192, -}; - -const std::vector CMPCTheme::minimizeIcon96({ - {2, 6, newPath}, - {11, 6, closePath}, -}); - -const std::vector CMPCTheme::minimizeIcon120({ - {3, 7, newPath}, - {14, 7, closePath}, -}); - -const std::vector CMPCTheme::minimizeIcon144({ - {4, 9, newPath}, - {18, 9, closePath}, -}); - -//same size as 144, but centered better -const std::vector CMPCTheme::minimizeIcon168({ - {2, 9, newPath}, - {16, 9, closePath}, -}); - -const std::vector CMPCTheme::minimizeIcon192({ - {5.5, 12.5, newPath}, - {23.5, 12.5, closePath}, -}); - -const std::vector CMPCTheme::restoreIcon96({ - {2, 4, newPath}, - {9, 4, linePath}, - {9, 11, linePath}, - {2, 11, linePath}, - {2, 4, linePath}, - {4, 4, newPath}, - {4, 2, linePath}, - {11, 2, linePath}, - {11, 9, linePath}, - {9, 9, linePath} -}); - -const std::vector CMPCTheme::restoreIcon120({ - {2, 4, newPath}, - {11, 4, linePath}, - {11, 13, linePath}, - {2, 13, linePath}, - {2, 4, linePath}, - {4, 4, newPath}, - {4, 2, linePath}, - {13, 2, linePath}, - {13, 11, linePath}, - {11, 11, linePath}, -}); - -const std::vector CMPCTheme::restoreIcon144({ - {2, 5, newPath}, - {13, 5, linePath}, - {13, 16, linePath}, - {2, 16, linePath}, - {2, 5, linePath}, - {5, 5, newPath}, - {5, 2, linePath}, - {16, 2, linePath}, - {16, 13, linePath}, - {13, 13, linePath}, -}); - -const std::vector CMPCTheme::restoreIcon168 = CMPCTheme::restoreIcon144; - -const std::vector CMPCTheme::restoreIcon192({ - { 3.5, 7.5, newPath}, - { 17.5, 7.5, linePath }, - { 17.5, 21.5, linePath }, - { 3.5, 21.5, linePath }, - { 3.5, 7.5, linePath }, - { 7.5, 7.5, newPath }, - { 7.5, 3.5, linePath }, - { 21.5, 3.5, linePath }, - { 21.5, 17.5, linePath }, - { 17.5, 17.5, linePath }, -}); - -const std::vector CMPCTheme::maximizeIcon96({ - {1, 1, newPath}, - {1, 10, linePath}, - {10, 10, linePath}, - {10, 1, linePath}, - {1, 1, linePath} -}); - -const std::vector CMPCTheme::maximizeIcon120({ - {2, 2, newPath}, - {2, 13, linePath}, - {13, 13, linePath}, - {13, 2, linePath}, - {2, 2, linePath}, -}); - -const std::vector CMPCTheme::maximizeIcon144({ - {2, 2, newPath}, - {2, 16, linePath}, - {16, 16, linePath}, - {16, 2, linePath}, - {2, 2, linePath}, -}); - -const std::vector CMPCTheme::maximizeIcon168 = CMPCTheme::maximizeIcon144; - -const std::vector CMPCTheme::maximizeIcon192({ - {3.5, 3.5, newPath}, - {3.5, 21.5, linePath}, - {21.5, 21.5, linePath}, - {21.5, 3.5, linePath}, - {3.5, 3.5, linePath}, -}); - -const std::vector CMPCTheme::closeIcon96({ - {1, 1, newPath}, - {10, 10, closePath}, - {1, 10, newPath}, - {10, 1, closePath} -}); - -const std::vector CMPCTheme::closeIcon120({ - {2, 2, newPath}, - {13, 13, linePath}, - {2, 13, newPath}, - {13, 2, linePath}, -}); - -const std::vector CMPCTheme::closeIcon144({ - {2, 2, newPath}, - {16, 16, linePath}, - {2, 16, newPath}, - {16, 2, linePath}, -}); - -const std::vector CMPCTheme::closeIcon168 = CMPCTheme::closeIcon144; - -const std::vector CMPCTheme::closeIcon192({ - {3.5, 3.5, newPath}, - {21.5, 21.5, linePath}, - {3.5, 21.5, newPath}, - {21.5, 3.5, linePath}, -}); - -//windows10 centers the icon "path" on the button, inside a frame -//sometimes this frame is centered, but at different dpis it's misaligned by 1-2 pixels -//we use the width/height of the frame to tweak the "center" position -const int CMPCTheme::W10TitlebarIconPathHeight[5] = { - 12, - 15, //should be 16, but to match windows 10 - 18, //should be 19 - 18, //should be 19 - 26, -}; - -const int CMPCTheme::W10TitlebarIconPathWidth[5] = { - 12, - 17, //should be 16, but to match windows 10 - 19, - 19, - 28, -}; - -const float CMPCTheme::W10TitlebarIconPathThickness[5] = { - 1, - 1, - 1, - 1, - 2, -}; - -const int CMPCTheme::W10TitlebarButtonWidth[5] = { - 45, - 58, - 69, - 80, - 91, -}; - -const int CMPCTheme::W10TitlebarButtonSpacing[5] = { - 1, - 1, - 2, - 1, //makes no sense, but spacing goes back to 1 - 2, -}; - -const int CMPCTheme::ToolbarIconPathDimension[5] = { - 7, - 9, - 11, - 12, - 14, -}; - -const int CMPCTheme::ToolbarHideButtonDimensions[5] = { - 11, - 14, - 17, - 20, - 22, -}; - -const int CMPCTheme::ToolbarGripperHeight[5] = { - 5, - 6, - 8, - 9, - 10, -}; - -const std::vector CMPCTheme::hideIcon96({ - {0, 0, newPath}, - {6, 6, linePath}, - {0, 6, newPath}, - {6, 0, linePath} -}); - -const std::vector CMPCTheme::hideIcon120({ - {0, 0, newPath}, - {8, 8, linePath}, - {0, 8, newPath}, - {8, 0, linePath}, -}); - -const std::vector CMPCTheme::hideIcon144({ - {0, 0, newPath}, - {10, 10, linePath}, - {0, 10, newPath}, - {10, 0, linePath}, -}); - -const std::vector CMPCTheme::hideIcon168({ - {0, 0, newPath}, - {11, 11, linePath}, - {0, 11, newPath}, - {11, 0, linePath}, -}); - -const std::vector CMPCTheme::hideIcon192({ - {0, 0, newPath}, - {13, 13, linePath}, - {0, 13, newPath}, - {13, 0, linePath}, -}); - - -void CMPCTheme::InitializeColors(ModernThemeMode themeMode) { - if (themeMode == ModernThemeMode::WINDOWSDEFAULT) { - if (AfxGetAppSettings().bWindows10DarkThemeActive) { - themeMode = ModernThemeMode::DARK; - } else { - themeMode = ModernThemeMode::LIGHT; - } - } - - if (themeMode == ModernThemeMode::DARK) { - drawThemedControls = true; - - MenuBGColor = RGB(43, 43, 43); - MenubarBGColor = RGB(43, 43, 43); - WindowBGColor = RGB(25, 25, 25); - ControlAreaBGColor = RGB(56, 56, 56); - - ContentBGColor = RGB(32, 32, 32); - ContentSelectedColor = RGB(119, 119, 119); - PlayerBGColor = RGB(32, 32, 32); - - HighLightColor = GetSysColor(COLOR_HIGHLIGHT); - - MenuSelectedColor = RGB(65, 65, 65); - MenubarSelectedBGColor = RGB(65, 65, 65); - MenuSeparatorColor = RGB(128, 128, 128); - MenuItemDisabledColor = RGB(109, 109, 109); - MainMenuBorderColor = RGB(32, 32, 32); - - TextFGColor = RGB(255, 255, 255); - PropPageCaptionFGColor = RGBGS(255); - TextFGColorFade = RGB(200, 200, 200); - ContentTextDisabledFGColorFade = RGB(109, 109, 109); - ContentTextDisabledFGColorFade2 = RGB(60, 60, 60); //even more faded, used for NA text on CListCtrl/audio switcher - - SubmenuColor = RGB(191, 191, 191); - - WindowBorderColorLight = RGB(99, 99, 99); - WindowBorderColorDim = RGB(43, 43, 43); - NoBorderColor = RGB(0, 0, 0); - GripperPatternColor = RGB(70, 70, 74); //visual studio dark, since explorer has no grippers - - ScrollBGColor = RGB(23, 23, 23); - ScrollProgressColor = RGB(60, 60, 60); - ScrollThumbColor = RGB(77, 77, 77); - ScrollThumbHoverColor = RGB(144, 144, 144); - ScrollThumbDragColor = RGB(183, 183, 183); - ScrollButtonArrowColor = RGB(103, 103, 103); - ScrollButtonArrowClickColor = RGBGS(103); - ScrollButtonHoverColor = RGB(55, 55, 55); - ScrollButtonClickColor = RGB(166, 166, 166); - - InlineEditBorderColor = RGB(255, 255, 255); - TooltipBorderColor = RGB(118, 118, 118); - - GroupBoxBorderColor = RGB(118, 118, 118); - - PlayerButtonHotColor = RGB(43, 43, 43); - PlayerButtonCheckedColor = RGB(66, 66, 66); - PlayerButtonClickedColor = RGB(55, 55, 55); - PlayerButtonBorderColor = RGB(0, 0, 0); - - ButtonBorderOuterColor = RGB(240, 240, 240); - ButtonBorderInnerFocusedColor = RGB(255, 255, 255); - ButtonBorderInnerColor = RGB(155, 155, 155); - ButtonBorderSelectedKBFocusColor = RGB(150, 150, 150); - ButtonBorderHoverKBFocusColor = RGB(181, 181, 181); - ButtonBorderKBFocusColor = RGB(195, 195, 195); - ButtonFillColor = RGB(51, 51, 51); - ButtonFillHoverColor = RGB(69, 69, 69); - ButtonFillSelectedColor = RGB(102, 102, 102); - ButtonDisabledFGColor = RGB(109, 109, 109); - - CheckboxBorderColor = RGB(137, 137, 137); - CheckboxBGColor = RGB(0, 0, 0); - CheckboxBorderHoverColor = RGB(121, 121, 121); - CheckboxBGHoverColor = RGB(8, 8, 8); - - ImageDisabledColor = RGB(109, 109, 109); - - SliderChannelColor = RGB(109, 109, 109); - - EditBorderColor = RGB(106, 106, 106); - - TreeCtrlLineColor = RGB(106, 106, 106); - TreeCtrlHoverColor = RGB(77, 77, 77); - TreeCtrlFocusColor = RGB(98, 98, 98); - - CheckColor = RGB(222, 222, 222); - - ColumnHeaderHotColor = RGB(67, 67, 67); - - StaticEtchedColor = RGB(65, 65, 65); - - ListCtrlDisabledBGColor = RGB(40, 40, 40); - ListCtrlGridColor = RGB(43, 43, 43); - ListCtrlErrorColor = RGB(242, 13, 13); - HeaderCtrlGridColor = RGB(99, 99, 99); - AudioSwitcherGridColor = RGB(99, 99, 99); - - TabCtrlBorderColor = RGB(99, 99, 99); - TabCtrlInactiveColor = RGB(40, 40, 40); - - - StatusBarBGColor = RGB(51, 51, 51); - StatusBarSeparatorColor = RGB(247, 247, 247); - - ProgressBarBGColor = RGB(0, 0, 0); - ProgressBarColor = RGB(75, 75, 75); - - SubresyncFadeText1 = RGB(190, 190, 190); - SubresyncFadeText2 = RGB(160, 160, 160); - SubresyncActiveFadeText = RGB(215, 215, 215); - SubresyncHLColor1 = RGB(100, 100, 100); - SubresyncHLColor2 = RGB(80, 80, 80); - SubresyncGridSepColor = RGB(220, 220, 220); - - ActivePlayListItemColor = RGB(38, 160, 218); - ActivePlayListItemHLColor = RGB(0, 40, 110); - StaticLinkColor = RGB(38, 160, 218); - - SeekbarCurrentPositionColor = RGB(38, 160, 218); - SeekbarChapterColor = RGB(100, 100, 100); - SeekbarABColor = RGB(242, 13, 13); - } else { - MenuBGColor = RGBGS(238); - MenubarBGColor = RGBGS(255); - WindowBGColor = RGBGS(255); - ControlAreaBGColor = RGBGS(240); - - ContentBGColor = RGBGS(255); - ContentSelectedColor = RGB(0, 120, 215); - PlayerBGColor = RGBGS(255); - - HighLightColor = GetSysColor(COLOR_HIGHLIGHT); - - MenuSelectedColor = RGBGS(255); - MenubarSelectedBGColor = RGBGS(238); - MenuSeparatorColor = RGBGS(145); - MenuItemDisabledColor = RGBGS(109); - MainMenuBorderColor = RGBGS(255); - - TextFGColor = RGBGS(0); - PropPageCaptionFGColor = RGBGS(245); - TextFGColorFade = RGBGS(109); - ContentTextDisabledFGColorFade = RGBGS(176); - ContentTextDisabledFGColorFade2 = RGBGS(224); //even more faded, used for NA text on CListCtrl/audio switcher - - SubmenuColor = RGBGS(0); - - WindowBorderColorLight = RGB(130, 135, 144); - WindowBorderColorDim = RGB(48, 56, 62); - NoBorderColor = RGBGS(0); - GripperPatternColor = RGB(153, 153, 153); //visual studio light, since explorer has no grippers - - ScrollBGColor = RGBGS(240); - ScrollProgressColor = RGB(130, 215, 146); - ScrollThumbColor = RGBGS(205); - ScrollThumbHoverColor = RGBGS(166); - ScrollThumbDragColor = RGBGS(119); - ScrollButtonArrowColor = RGBGS(96); - ScrollButtonArrowClickColor = RGBGS(255); - ScrollButtonHoverColor = RGBGS(218); - ScrollButtonClickColor = RGBGS(96); - - InlineEditBorderColor = RGBGS(0); - TooltipBorderColor = RGBGS(118); - - GroupBoxBorderColor = RGB(130, 135, 144); - - PlayerButtonHotColor = RGB(232, 239, 247); - PlayerButtonCheckedColor = RGB(205, 228, 252); - PlayerButtonClickedColor = RGB(201, 224, 247); - PlayerButtonBorderColor = RGB(98, 162, 228); - - - ButtonBorderOuterColor = RGBGS(173); - ButtonBorderInnerFocusedColor = RGB(0, 120, 215); - ButtonBorderInnerColor = RGBGS(173); - ButtonBorderSelectedKBFocusColor = RGB(60, 20, 7); - ButtonBorderHoverKBFocusColor = RGB(21, 1, 11); - ButtonBorderKBFocusColor = RGBGS(17); - ButtonFillColor = RGBGS(225); - ButtonFillHoverColor = RGB(229, 241, 251); - ButtonFillSelectedColor = RGB(204, 228, 247); - ButtonDisabledFGColor = RGBGS(204); - - CheckboxBorderColor = RGB(97, 121, 160); - CheckboxBGColor = RGBGS(255); - CheckboxBorderHoverColor = RGB(38, 160, 218); - CheckboxBGHoverColor = RGBGS(255); - - ImageDisabledColor = RGBGS(128); - - SliderChannelColor = RGBGS(128); - - EditBorderColor = RGB(106, 106, 106); - - TreeCtrlLineColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - TreeCtrlHoverColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - TreeCtrlFocusColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - CheckColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - ColumnHeaderHotColor = RGB(217, 235, 239); - - StaticEtchedColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - ListCtrlDisabledBGColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - ListCtrlGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - ListCtrlErrorColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - HeaderCtrlGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - AudioSwitcherGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - TabCtrlBorderColor = RGBGS(227); - TabCtrlInactiveColor = RGBGS(246); - - StatusBarBGColor = RGBGS(240); - StatusBarSeparatorColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - ProgressBarBGColor = RGBGS(255); - ProgressBarColor = RGB(130, 215, 146); - - SubresyncFadeText1 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncFadeText2 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncActiveFadeText = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncHLColor1 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncHLColor2 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - SubresyncGridSepColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - ActivePlayListItemColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - ActivePlayListItemHLColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - StaticLinkColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used - - SeekbarCurrentPositionColor = RGB(38, 160, 218); - SeekbarChapterColor = RGB(100, 100, 100); - SeekbarABColor = RGB(242, 13, 13); - } -} +#include "stdafx.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + +#define RGBGS(x) ((COLORREF)(((BYTE)(x)|((WORD)((BYTE)(x))<<8))|(((DWORD)(BYTE)(x))<<16))) + +const int CMPCTheme::GroupBoxTextIndent = 8; +bool CMPCTheme::drawThemedControls = false; +COLORREF CMPCTheme::CloseHoverColor = RGB(232, 17, 35); +COLORREF CMPCTheme::ClosePushColor = RGB(139, 10, 20); +COLORREF CMPCTheme::DebugColorRed = RGB(255, 0, 0); +COLORREF CMPCTheme::DebugColorYellow = RGB(255, 255, 0); +COLORREF CMPCTheme::DebugColorGreen = RGB(0, 255, 0); +COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedTextColor = RGB(255, 255, 255); +COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedBGColor = RGB(56, 56, 56); +COLORREF CMPCTheme::W10DarkThemeFileDialogInjectedEditBorderColor = RGB(155, 155, 155); +COLORREF CMPCTheme::W10DarkThemeTitlebarBGColor = RGB(0, 0, 0); +COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveBGColor = RGB(43, 43, 43); +COLORREF CMPCTheme::W10DarkThemeTitlebarFGColor = RGB(255, 255, 255); +COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveFGColor = RGB(170, 170, 170); +COLORREF CMPCTheme::W10DarkThemeTitlebarIconPenColor = RGB(255, 255, 255); +COLORREF CMPCTheme::W10DarkThemeTitlebarControlHoverBGColor = RGB(43, 43, 43); +COLORREF CMPCTheme::W10DarkThemeTitlebarInactiveControlHoverBGColor = RGB(65, 65, 65); +COLORREF CMPCTheme::W10DarkThemeTitlebarControlPushedBGColor = RGB(70, 70, 70); +COLORREF CMPCTheme::W10DarkThemeWindowBorderColor = RGB(57, 57, 57); + + + +COLORREF CMPCTheme::MenuBGColor; +COLORREF CMPCTheme::MenubarBGColor; +COLORREF CMPCTheme::WindowBGColor; +COLORREF CMPCTheme::ControlAreaBGColor; + +COLORREF CMPCTheme::ContentBGColor; +COLORREF CMPCTheme::ContentSelectedColor; +COLORREF CMPCTheme::PlayerBGColor; + +COLORREF CMPCTheme::HighLightColor; + +COLORREF CMPCTheme::MenuSelectedColor; +COLORREF CMPCTheme::MenubarSelectedBGColor; +COLORREF CMPCTheme::MenuSeparatorColor; +COLORREF CMPCTheme::MenuItemDisabledColor; +//COLORREF CMPCTheme::MenuItemUnfocusedColor; +COLORREF CMPCTheme::MainMenuBorderColor; + +COLORREF CMPCTheme::TextFGColor; +COLORREF CMPCTheme::TextFGColorFade; +COLORREF CMPCTheme::PropPageCaptionFGColor; +COLORREF CMPCTheme::ContentTextDisabledFGColorFade; +COLORREF CMPCTheme::ContentTextDisabledFGColorFade2; //even more faded, used for NA text on CListCtrl/audio switcher + +COLORREF CMPCTheme::SubmenuColor; + +COLORREF CMPCTheme::WindowBorderColorLight; +COLORREF CMPCTheme::WindowBorderColorDim; +COLORREF CMPCTheme::NoBorderColor; +COLORREF CMPCTheme::GripperPatternColor; //visual studio, since explorer has no grippers + +COLORREF CMPCTheme::ScrollBGColor; +COLORREF CMPCTheme::ScrollProgressColor; +COLORREF CMPCTheme::ScrollThumbColor; +COLORREF CMPCTheme::ScrollThumbHoverColor; +COLORREF CMPCTheme::ScrollThumbDragColor; +COLORREF CMPCTheme::ScrollButtonArrowColor; +COLORREF CMPCTheme::ScrollButtonArrowClickColor; +COLORREF CMPCTheme::ScrollButtonHoverColor; +COLORREF CMPCTheme::ScrollButtonClickColor; + +COLORREF CMPCTheme::InlineEditBorderColor; +COLORREF CMPCTheme::TooltipBorderColor; + +COLORREF CMPCTheme::GroupBoxBorderColor; + +COLORREF CMPCTheme::PlayerButtonHotColor; +COLORREF CMPCTheme::PlayerButtonCheckedColor; +COLORREF CMPCTheme::PlayerButtonClickedColor; +COLORREF CMPCTheme::PlayerButtonBorderColor; + +COLORREF CMPCTheme::ButtonBorderOuterColor; +COLORREF CMPCTheme::ButtonBorderInnerFocusedColor; +COLORREF CMPCTheme::ButtonBorderInnerColor; +COLORREF CMPCTheme::ButtonBorderSelectedKBFocusColor; +COLORREF CMPCTheme::ButtonBorderHoverKBFocusColor; +COLORREF CMPCTheme::ButtonBorderKBFocusColor; +COLORREF CMPCTheme::ButtonFillColor; +COLORREF CMPCTheme::ButtonFillHoverColor; +COLORREF CMPCTheme::ButtonFillSelectedColor; +COLORREF CMPCTheme::ButtonDisabledFGColor; + +COLORREF CMPCTheme::CheckboxBorderColor; +COLORREF CMPCTheme::CheckboxBGColor; +COLORREF CMPCTheme::CheckboxBorderHoverColor; +COLORREF CMPCTheme::CheckboxBGHoverColor; + +COLORREF CMPCTheme::ImageDisabledColor; + +COLORREF CMPCTheme::SliderChannelColor; + +COLORREF CMPCTheme::EditBorderColor; + +COLORREF CMPCTheme::TreeCtrlLineColor; +COLORREF CMPCTheme::TreeCtrlHoverColor; +COLORREF CMPCTheme::TreeCtrlFocusColor; + +COLORREF CMPCTheme::CheckColor; + +COLORREF CMPCTheme::ColumnHeaderHotColor; + +COLORREF CMPCTheme::StaticEtchedColor; + +COLORREF CMPCTheme::ListCtrlDisabledBGColor; +COLORREF CMPCTheme::ListCtrlGridColor; +COLORREF CMPCTheme::ListCtrlErrorColor; +COLORREF CMPCTheme::HeaderCtrlGridColor; +COLORREF CMPCTheme::AudioSwitcherGridColor; + +COLORREF CMPCTheme::TabCtrlBorderColor; +COLORREF CMPCTheme::TabCtrlInactiveColor; + + +COLORREF CMPCTheme::StatusBarBGColor; +COLORREF CMPCTheme::StatusBarSeparatorColor; + + +COLORREF CMPCTheme::ProgressBarBGColor; +COLORREF CMPCTheme::ProgressBarColor; + +COLORREF CMPCTheme::SubresyncFadeText1; +COLORREF CMPCTheme::SubresyncFadeText2; +COLORREF CMPCTheme::SubresyncActiveFadeText; +COLORREF CMPCTheme::SubresyncHLColor1; +COLORREF CMPCTheme::SubresyncHLColor2; +COLORREF CMPCTheme::SubresyncGridSepColor; + +COLORREF CMPCTheme::ActivePlayListItemColor; +COLORREF CMPCTheme::ActivePlayListItemHLColor; +COLORREF CMPCTheme::StaticLinkColor; + +COLORREF CMPCTheme::SeekbarCurrentPositionColor; +COLORREF CMPCTheme::SeekbarChapterColor; +COLORREF CMPCTheme::SeekbarABColor; + +wchar_t* const CMPCTheme::uiTextFont = L"Segoe UI"; +wchar_t* const CMPCTheme::uiStaticTextFont = L"Segoe UI Semilight"; +wchar_t* const CMPCTheme::uiSymbolFont = L"MS UI Gothic"; + + +const int CMPCTheme::gripPatternLong = 5; +const int CMPCTheme::gripPatternShort = 4; + + +const BYTE CMPCTheme::GripperBitsH[10] = { + 0x80, 0x00, + 0x00, 0x00, + 0x20, 0x00, + 0x00, 0x00, + 0x80, 0x00, +}; + +const BYTE CMPCTheme::GripperBitsV[8] = { + 0x88, 0x00, + 0x00, 0x00, + 0x20, 0x00, + 0x00, 0x00, +}; + +const COLORREF CMPCTheme::ComboboxArrowColor = RGB(200, 200, 200); +const COLORREF CMPCTheme::ComboboxArrowColorDisabled = RGB(100, 100, 100); + +const COLORREF CMPCTheme::HeaderCtrlSortArrowColor = RGB(200, 200, 200); + + +const BYTE CMPCTheme::CheckBits[14] = { + 0x02, 0x00, + 0x06, 0x00, + 0x8E, 0x00, + 0xDC, 0x00, + 0xF8, 0x00, + 0x70, 0x00, + 0x20, 0x00, +}; + +const int CMPCTheme::CheckWidth = 7; +const int CMPCTheme::CheckHeight = 7; + + +const UINT CMPCTheme::ThemeCheckBoxes[5] = { + IDB_DT_CB_96, + IDB_DT_CB_120, + IDB_DT_CB_144, + IDB_DT_CB_144, + IDB_DT_CB_192, +}; + +const UINT CMPCTheme::ThemeRadios[5] = { + IDB_DT_RADIO_96, + IDB_DT_RADIO_120, + IDB_DT_RADIO_144, + IDB_DT_RADIO_144, + IDB_DT_RADIO_192, +}; + +const UINT CMPCTheme::ThemeGrippers[5] = { + IDB_GRIPPER_96, + IDB_GRIPPER_120, + IDB_GRIPPER_144, + IDB_GRIPPER_168, + IDB_GRIPPER_192, +}; + +const std::vector CMPCTheme::minimizeIcon96({ + {2, 6, newPath}, + {11, 6, closePath}, +}); + +const std::vector CMPCTheme::minimizeIcon120({ + {3, 7, newPath}, + {14, 7, closePath}, +}); + +const std::vector CMPCTheme::minimizeIcon144({ + {4, 9, newPath}, + {18, 9, closePath}, +}); + +//same size as 144, but centered better +const std::vector CMPCTheme::minimizeIcon168({ + {2, 9, newPath}, + {16, 9, closePath}, +}); + +const std::vector CMPCTheme::minimizeIcon192({ + {5.5, 12.5, newPath}, + {23.5, 12.5, closePath}, +}); + +const std::vector CMPCTheme::restoreIcon96({ + {2, 4, newPath}, + {9, 4, linePath}, + {9, 11, linePath}, + {2, 11, linePath}, + {2, 4, linePath}, + {4, 4, newPath}, + {4, 2, linePath}, + {11, 2, linePath}, + {11, 9, linePath}, + {9, 9, linePath} +}); + +const std::vector CMPCTheme::restoreIcon120({ + {2, 4, newPath}, + {11, 4, linePath}, + {11, 13, linePath}, + {2, 13, linePath}, + {2, 4, linePath}, + {4, 4, newPath}, + {4, 2, linePath}, + {13, 2, linePath}, + {13, 11, linePath}, + {11, 11, linePath}, +}); + +const std::vector CMPCTheme::restoreIcon144({ + {2, 5, newPath}, + {13, 5, linePath}, + {13, 16, linePath}, + {2, 16, linePath}, + {2, 5, linePath}, + {5, 5, newPath}, + {5, 2, linePath}, + {16, 2, linePath}, + {16, 13, linePath}, + {13, 13, linePath}, +}); + +const std::vector CMPCTheme::restoreIcon168 = CMPCTheme::restoreIcon144; + +const std::vector CMPCTheme::restoreIcon192({ + { 3.5, 7.5, newPath}, + { 17.5, 7.5, linePath }, + { 17.5, 21.5, linePath }, + { 3.5, 21.5, linePath }, + { 3.5, 7.5, linePath }, + { 7.5, 7.5, newPath }, + { 7.5, 3.5, linePath }, + { 21.5, 3.5, linePath }, + { 21.5, 17.5, linePath }, + { 17.5, 17.5, linePath }, +}); + +const std::vector CMPCTheme::maximizeIcon96({ + {1, 1, newPath}, + {1, 10, linePath}, + {10, 10, linePath}, + {10, 1, linePath}, + {1, 1, linePath} +}); + +const std::vector CMPCTheme::maximizeIcon120({ + {2, 2, newPath}, + {2, 13, linePath}, + {13, 13, linePath}, + {13, 2, linePath}, + {2, 2, linePath}, +}); + +const std::vector CMPCTheme::maximizeIcon144({ + {2, 2, newPath}, + {2, 16, linePath}, + {16, 16, linePath}, + {16, 2, linePath}, + {2, 2, linePath}, +}); + +const std::vector CMPCTheme::maximizeIcon168 = CMPCTheme::maximizeIcon144; + +const std::vector CMPCTheme::maximizeIcon192({ + {3.5, 3.5, newPath}, + {3.5, 21.5, linePath}, + {21.5, 21.5, linePath}, + {21.5, 3.5, linePath}, + {3.5, 3.5, linePath}, +}); + +const std::vector CMPCTheme::closeIcon96({ + {1, 1, newPath}, + {10, 10, closePath}, + {1, 10, newPath}, + {10, 1, closePath} +}); + +const std::vector CMPCTheme::closeIcon120({ + {2, 2, newPath}, + {13, 13, linePath}, + {2, 13, newPath}, + {13, 2, linePath}, +}); + +const std::vector CMPCTheme::closeIcon144({ + {2, 2, newPath}, + {16, 16, linePath}, + {2, 16, newPath}, + {16, 2, linePath}, +}); + +const std::vector CMPCTheme::closeIcon168 = CMPCTheme::closeIcon144; + +const std::vector CMPCTheme::closeIcon192({ + {3.5, 3.5, newPath}, + {21.5, 21.5, linePath}, + {3.5, 21.5, newPath}, + {21.5, 3.5, linePath}, +}); + +//windows10 centers the icon "path" on the button, inside a frame +//sometimes this frame is centered, but at different dpis it's misaligned by 1-2 pixels +//we use the width/height of the frame to tweak the "center" position +const int CMPCTheme::W10TitlebarIconPathHeight[5] = { + 12, + 15, //should be 16, but to match windows 10 + 18, //should be 19 + 18, //should be 19 + 26, +}; + +const int CMPCTheme::W10TitlebarIconPathWidth[5] = { + 12, + 17, //should be 16, but to match windows 10 + 19, + 19, + 28, +}; + +const float CMPCTheme::W10TitlebarIconPathThickness[5] = { + 1, + 1, + 1, + 1, + 2, +}; + +const int CMPCTheme::W10TitlebarButtonWidth[5] = { + 45, + 58, + 69, + 80, + 91, +}; + +const int CMPCTheme::W10TitlebarButtonSpacing[5] = { + 1, + 1, + 2, + 1, //makes no sense, but spacing goes back to 1 + 2, +}; + +const int CMPCTheme::ToolbarIconPathDimension[5] = { + 7, + 9, + 11, + 12, + 14, +}; + +const int CMPCTheme::ToolbarHideButtonDimensions[5] = { + 11, + 14, + 17, + 20, + 22, +}; + +const int CMPCTheme::ToolbarGripperHeight[5] = { + 5, + 6, + 8, + 9, + 10, +}; + +const std::vector CMPCTheme::hideIcon96({ + {0, 0, newPath}, + {6, 6, linePath}, + {0, 6, newPath}, + {6, 0, linePath} +}); + +const std::vector CMPCTheme::hideIcon120({ + {0, 0, newPath}, + {8, 8, linePath}, + {0, 8, newPath}, + {8, 0, linePath}, +}); + +const std::vector CMPCTheme::hideIcon144({ + {0, 0, newPath}, + {10, 10, linePath}, + {0, 10, newPath}, + {10, 0, linePath}, +}); + +const std::vector CMPCTheme::hideIcon168({ + {0, 0, newPath}, + {11, 11, linePath}, + {0, 11, newPath}, + {11, 0, linePath}, +}); + +const std::vector CMPCTheme::hideIcon192({ + {0, 0, newPath}, + {13, 13, linePath}, + {0, 13, newPath}, + {13, 0, linePath}, +}); + + +void CMPCTheme::InitializeColors(ModernThemeMode themeMode) { + if (themeMode == ModernThemeMode::WINDOWSDEFAULT) { + if (AfxGetAppSettings().bWindows10DarkThemeActive) { + themeMode = ModernThemeMode::DARK; + } else { + themeMode = ModernThemeMode::LIGHT; + } + } + + if (themeMode == ModernThemeMode::DARK) { + drawThemedControls = true; + + MenuBGColor = RGB(43, 43, 43); + MenubarBGColor = RGB(43, 43, 43); + WindowBGColor = RGB(25, 25, 25); + ControlAreaBGColor = RGB(56, 56, 56); + + ContentBGColor = RGB(32, 32, 32); + ContentSelectedColor = RGB(119, 119, 119); + PlayerBGColor = RGB(32, 32, 32); + + HighLightColor = GetSysColor(COLOR_HIGHLIGHT); + + MenuSelectedColor = RGB(65, 65, 65); + MenubarSelectedBGColor = RGB(65, 65, 65); + MenuSeparatorColor = RGB(128, 128, 128); + MenuItemDisabledColor = RGB(109, 109, 109); + MainMenuBorderColor = RGB(32, 32, 32); + + TextFGColor = RGB(255, 255, 255); + PropPageCaptionFGColor = RGBGS(255); + TextFGColorFade = RGB(200, 200, 200); + ContentTextDisabledFGColorFade = RGB(109, 109, 109); + ContentTextDisabledFGColorFade2 = RGB(60, 60, 60); //even more faded, used for NA text on CListCtrl/audio switcher + + SubmenuColor = RGB(191, 191, 191); + + WindowBorderColorLight = RGB(99, 99, 99); + WindowBorderColorDim = RGB(43, 43, 43); + NoBorderColor = RGB(0, 0, 0); + GripperPatternColor = RGB(70, 70, 74); //visual studio dark, since explorer has no grippers + + ScrollBGColor = RGB(23, 23, 23); + ScrollProgressColor = RGB(60, 60, 60); + ScrollThumbColor = RGB(77, 77, 77); + ScrollThumbHoverColor = RGB(144, 144, 144); + ScrollThumbDragColor = RGB(183, 183, 183); + ScrollButtonArrowColor = RGB(103, 103, 103); + ScrollButtonArrowClickColor = RGBGS(103); + ScrollButtonHoverColor = RGB(55, 55, 55); + ScrollButtonClickColor = RGB(166, 166, 166); + + InlineEditBorderColor = RGB(255, 255, 255); + TooltipBorderColor = RGB(118, 118, 118); + + GroupBoxBorderColor = RGB(118, 118, 118); + + PlayerButtonHotColor = RGB(43, 43, 43); + PlayerButtonCheckedColor = RGB(66, 66, 66); + PlayerButtonClickedColor = RGB(55, 55, 55); + PlayerButtonBorderColor = RGB(0, 0, 0); + + ButtonBorderOuterColor = RGB(240, 240, 240); + ButtonBorderInnerFocusedColor = RGB(255, 255, 255); + ButtonBorderInnerColor = RGB(155, 155, 155); + ButtonBorderSelectedKBFocusColor = RGB(150, 150, 150); + ButtonBorderHoverKBFocusColor = RGB(181, 181, 181); + ButtonBorderKBFocusColor = RGB(195, 195, 195); + ButtonFillColor = RGB(51, 51, 51); + ButtonFillHoverColor = RGB(69, 69, 69); + ButtonFillSelectedColor = RGB(102, 102, 102); + ButtonDisabledFGColor = RGB(109, 109, 109); + + CheckboxBorderColor = RGB(137, 137, 137); + CheckboxBGColor = RGB(0, 0, 0); + CheckboxBorderHoverColor = RGB(121, 121, 121); + CheckboxBGHoverColor = RGB(8, 8, 8); + + ImageDisabledColor = RGB(109, 109, 109); + + SliderChannelColor = RGB(109, 109, 109); + + EditBorderColor = RGB(106, 106, 106); + + TreeCtrlLineColor = RGB(106, 106, 106); + TreeCtrlHoverColor = RGB(77, 77, 77); + TreeCtrlFocusColor = RGB(98, 98, 98); + + CheckColor = RGB(222, 222, 222); + + ColumnHeaderHotColor = RGB(67, 67, 67); + + StaticEtchedColor = RGB(65, 65, 65); + + ListCtrlDisabledBGColor = RGB(40, 40, 40); + ListCtrlGridColor = RGB(43, 43, 43); + ListCtrlErrorColor = RGB(242, 13, 13); + HeaderCtrlGridColor = RGB(99, 99, 99); + AudioSwitcherGridColor = RGB(99, 99, 99); + + TabCtrlBorderColor = RGB(99, 99, 99); + TabCtrlInactiveColor = RGB(40, 40, 40); + + + StatusBarBGColor = RGB(51, 51, 51); + StatusBarSeparatorColor = RGB(247, 247, 247); + + ProgressBarBGColor = RGB(0, 0, 0); + ProgressBarColor = RGB(75, 75, 75); + + SubresyncFadeText1 = RGB(190, 190, 190); + SubresyncFadeText2 = RGB(160, 160, 160); + SubresyncActiveFadeText = RGB(215, 215, 215); + SubresyncHLColor1 = RGB(100, 100, 100); + SubresyncHLColor2 = RGB(80, 80, 80); + SubresyncGridSepColor = RGB(220, 220, 220); + + ActivePlayListItemColor = RGB(38, 160, 218); + ActivePlayListItemHLColor = RGB(0, 40, 110); + StaticLinkColor = RGB(38, 160, 218); + + SeekbarCurrentPositionColor = RGB(38, 160, 218); + SeekbarChapterColor = RGB(100, 100, 100); + SeekbarABColor = RGB(242, 13, 13); + } else { + MenuBGColor = RGBGS(238); + MenubarBGColor = RGBGS(255); + WindowBGColor = RGBGS(255); + ControlAreaBGColor = RGBGS(240); + + ContentBGColor = RGBGS(255); + ContentSelectedColor = RGB(0, 120, 215); + PlayerBGColor = RGBGS(255); + + HighLightColor = GetSysColor(COLOR_HIGHLIGHT); + + MenuSelectedColor = RGBGS(255); + MenubarSelectedBGColor = RGBGS(238); + MenuSeparatorColor = RGBGS(145); + MenuItemDisabledColor = RGBGS(109); + MainMenuBorderColor = RGBGS(255); + + TextFGColor = RGBGS(0); + PropPageCaptionFGColor = RGBGS(245); + TextFGColorFade = RGBGS(109); + ContentTextDisabledFGColorFade = RGBGS(176); + ContentTextDisabledFGColorFade2 = RGBGS(224); //even more faded, used for NA text on CListCtrl/audio switcher + + SubmenuColor = RGBGS(0); + + WindowBorderColorLight = RGB(130, 135, 144); + WindowBorderColorDim = RGB(48, 56, 62); + NoBorderColor = RGBGS(0); + GripperPatternColor = RGB(153, 153, 153); //visual studio light, since explorer has no grippers + + ScrollBGColor = RGBGS(240); + ScrollProgressColor = RGB(130, 215, 146); + ScrollThumbColor = RGBGS(205); + ScrollThumbHoverColor = RGBGS(166); + ScrollThumbDragColor = RGBGS(119); + ScrollButtonArrowColor = RGBGS(96); + ScrollButtonArrowClickColor = RGBGS(255); + ScrollButtonHoverColor = RGBGS(218); + ScrollButtonClickColor = RGBGS(96); + + InlineEditBorderColor = RGBGS(0); + TooltipBorderColor = RGBGS(118); + + GroupBoxBorderColor = RGB(130, 135, 144); + + PlayerButtonHotColor = RGB(232, 239, 247); + PlayerButtonCheckedColor = RGB(205, 228, 252); + PlayerButtonClickedColor = RGB(201, 224, 247); + PlayerButtonBorderColor = RGB(98, 162, 228); + + + ButtonBorderOuterColor = RGBGS(173); + ButtonBorderInnerFocusedColor = RGB(0, 120, 215); + ButtonBorderInnerColor = RGBGS(173); + ButtonBorderSelectedKBFocusColor = RGB(60, 20, 7); + ButtonBorderHoverKBFocusColor = RGB(21, 1, 11); + ButtonBorderKBFocusColor = RGBGS(17); + ButtonFillColor = RGBGS(225); + ButtonFillHoverColor = RGB(229, 241, 251); + ButtonFillSelectedColor = RGB(204, 228, 247); + ButtonDisabledFGColor = RGBGS(204); + + CheckboxBorderColor = RGB(97, 121, 160); + CheckboxBGColor = RGBGS(255); + CheckboxBorderHoverColor = RGB(38, 160, 218); + CheckboxBGHoverColor = RGBGS(255); + + ImageDisabledColor = RGBGS(128); + + SliderChannelColor = RGBGS(128); + + EditBorderColor = RGB(106, 106, 106); + + TreeCtrlLineColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + TreeCtrlHoverColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + TreeCtrlFocusColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + CheckColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + ColumnHeaderHotColor = RGB(217, 235, 239); + + StaticEtchedColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + ListCtrlDisabledBGColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + ListCtrlGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + ListCtrlErrorColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + HeaderCtrlGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + AudioSwitcherGridColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + TabCtrlBorderColor = RGBGS(227); + TabCtrlInactiveColor = RGBGS(246); + + StatusBarBGColor = RGBGS(240); + StatusBarSeparatorColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + ProgressBarBGColor = RGBGS(255); + ProgressBarColor = RGB(130, 215, 146); + + SubresyncFadeText1 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncFadeText2 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncActiveFadeText = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncHLColor1 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncHLColor2 = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + SubresyncGridSepColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + ActivePlayListItemColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + ActivePlayListItemHLColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + StaticLinkColor = RGB(255, 0, 0); //not implemented for light theme, default windows controls used + + SeekbarCurrentPositionColor = RGB(38, 160, 218); + SeekbarChapterColor = RGB(100, 100, 100); + SeekbarABColor = RGB(242, 13, 13); + } +} diff --git a/src/mpc-hc/CMPCTheme.h b/src/mpc-hc/CMPCTheme.h index a94b0c70d02..12c30b8a404 100755 --- a/src/mpc-hc/CMPCTheme.h +++ b/src/mpc-hc/CMPCTheme.h @@ -1,195 +1,195 @@ -#pragma once - -class CMPCTheme -{ -public: - enum class ModernThemeMode { - DARK, - LIGHT, - WINDOWSDEFAULT - }; - - static COLORREF MenuBGColor; - static COLORREF MenubarBGColor; - static COLORREF WindowBGColor; //used in explorer for left nav - static COLORREF ControlAreaBGColor; //used in file open dialog for button / file selection bg - static COLORREF ContentBGColor; //used in explorer for bg of file list - static COLORREF ContentSelectedColor; //used in explorer for bg of file list - static COLORREF PlayerBGColor; - static COLORREF HighLightColor; - - static COLORREF MenuSelectedColor; - static COLORREF MenubarSelectedBGColor; - static COLORREF MenuItemDisabledColor; - static COLORREF MainMenuBorderColor; - static COLORREF MenuSeparatorColor; - - static COLORREF TextFGColor; - static COLORREF TextFGColorFade; - static COLORREF PropPageCaptionFGColor; - static COLORREF ContentTextDisabledFGColorFade; - static COLORREF ContentTextDisabledFGColorFade2; - static COLORREF SubmenuColor; - static COLORREF CloseHoverColor; - static COLORREF ClosePushColor; - static COLORREF CloseColor; - static COLORREF WindowBorderColorLight; - static COLORREF WindowBorderColorDim; - static COLORREF NoBorderColor; - static COLORREF GripperPatternColor; - - static COLORREF ScrollBGColor; - static COLORREF ScrollProgressColor; - static COLORREF ScrollThumbColor; - static COLORREF ScrollThumbHoverColor; - static COLORREF ScrollThumbDragColor; - static COLORREF ScrollButtonArrowColor; - static COLORREF ScrollButtonArrowClickColor; - static COLORREF ScrollButtonHoverColor; - static COLORREF ScrollButtonClickColor; - - static COLORREF InlineEditBorderColor; - static COLORREF TooltipBorderColor; - - static COLORREF GroupBoxBorderColor; - - static COLORREF DebugColorRed; - static COLORREF DebugColorYellow; - static COLORREF DebugColorGreen; - - static COLORREF PlayerButtonHotColor; - static COLORREF PlayerButtonCheckedColor; - static COLORREF PlayerButtonClickedColor; - static COLORREF PlayerButtonBorderColor; - - static COLORREF ButtonBorderOuterColor; - static COLORREF ButtonBorderInnerFocusedColor; - static COLORREF ButtonBorderInnerColor; - static COLORREF ButtonBorderSelectedKBFocusColor; - static COLORREF ButtonBorderHoverKBFocusColor; - static COLORREF ButtonBorderKBFocusColor; - static COLORREF ButtonFillColor; - static COLORREF ButtonFillHoverColor; - static COLORREF ButtonFillSelectedColor; - static COLORREF ButtonDisabledFGColor; - - static COLORREF CheckboxBorderColor; - static COLORREF CheckboxBGColor; - static COLORREF CheckboxBorderHoverColor; - static COLORREF CheckboxBGHoverColor; - - static COLORREF ImageDisabledColor; - - static COLORREF SliderChannelColor; - - static COLORREF EditBorderColor; - - static COLORREF TreeCtrlLineColor; - static COLORREF TreeCtrlHoverColor; - static COLORREF TreeCtrlFocusColor; - - static COLORREF CheckColor; - - static COLORREF ColumnHeaderHotColor; - - static COLORREF StaticEtchedColor; - - static COLORREF ListCtrlDisabledBGColor; - static COLORREF ListCtrlGridColor; - static COLORREF ListCtrlErrorColor; - static COLORREF HeaderCtrlGridColor; - static COLORREF AudioSwitcherGridColor; - - static COLORREF TabCtrlBorderColor; - static COLORREF TabCtrlInactiveColor; - - static COLORREF StatusBarBGColor; - static COLORREF StatusBarSeparatorColor; - static COLORREF StatusBarEditBorderColor; - - static COLORREF W10DarkThemeFileDialogInjectedTextColor; - static COLORREF W10DarkThemeFileDialogInjectedBGColor; - static COLORREF W10DarkThemeFileDialogInjectedEditBorderColor; - static COLORREF W10DarkThemeTitlebarBGColor; - static COLORREF W10DarkThemeTitlebarInactiveBGColor; - static COLORREF W10DarkThemeTitlebarFGColor; - static COLORREF W10DarkThemeTitlebarInactiveFGColor; - static COLORREF W10DarkThemeTitlebarIconPenColor; - static COLORREF W10DarkThemeTitlebarControlHoverBGColor; - static COLORREF W10DarkThemeTitlebarInactiveControlHoverBGColor; - static COLORREF W10DarkThemeTitlebarControlPushedBGColor; - static COLORREF W10DarkThemeWindowBorderColor; - - static COLORREF ProgressBarBGColor; - static COLORREF ProgressBarColor; - - static COLORREF SubresyncFadeText1; - static COLORREF SubresyncFadeText2; - static COLORREF SubresyncActiveFadeText; - static COLORREF SubresyncHLColor1; - static COLORREF SubresyncHLColor2; - static COLORREF SubresyncGridSepColor; - - static COLORREF ActivePlayListItemColor; - static COLORREF ActivePlayListItemHLColor; - static COLORREF StaticLinkColor; - static COLORREF SeekbarCurrentPositionColor; - static COLORREF SeekbarChapterColor; - static COLORREF SeekbarABColor; - - static const int GroupBoxTextIndent; - - - static const BYTE GripperBitsH[10]; - static const BYTE GripperBitsV[8]; - static const int gripPatternShort; - static const int gripPatternLong; - - static wchar_t* const uiTextFont; - static wchar_t* const uiStaticTextFont; - static wchar_t* const uiSymbolFont; - - - static const COLORREF ComboboxArrowColor; - static const COLORREF ComboboxArrowColorDisabled; - - static const COLORREF HeaderCtrlSortArrowColor; - - static const BYTE CheckBits[14]; - static const int CheckWidth; - static const int CheckHeight; - - const static UINT ThemeCheckBoxes[5]; - const static UINT ThemeRadios[5]; - const static UINT ThemeGrippers[5]; - - enum pathState { - linePath, - newPath, - closePath - }; - - struct pathPoint { - float x; - float y; - pathState state; - }; - static const std::vector minimizeIcon96, minimizeIcon120, minimizeIcon144, minimizeIcon168, minimizeIcon192; - static const std::vector maximizeIcon96, maximizeIcon120, maximizeIcon144, maximizeIcon168, maximizeIcon192; - static const std::vector restoreIcon96, restoreIcon120, restoreIcon144, restoreIcon168, restoreIcon192; - static const std::vector closeIcon96, closeIcon120, closeIcon144, closeIcon168, closeIcon192; - static const std::vector hideIcon96, hideIcon120, hideIcon144, hideIcon168, hideIcon192; - static const int CMPCTheme::W10TitlebarIconPathHeight[5]; - static const int CMPCTheme::W10TitlebarIconPathWidth[5]; - static const float CMPCTheme::W10TitlebarIconPathThickness[5]; - static const int CMPCTheme::W10TitlebarButtonWidth[5]; - static const int CMPCTheme::W10TitlebarButtonSpacing[5]; - static const int CMPCTheme::ToolbarIconPathDimension[5]; - static const int CMPCTheme::ToolbarGripperHeight[5]; - static const int CMPCTheme::ToolbarHideButtonDimensions[5]; - - - static bool drawThemedControls; - - static void InitializeColors(ModernThemeMode themeMode); -}; +#pragma once + +class CMPCTheme +{ +public: + enum class ModernThemeMode { + DARK, + LIGHT, + WINDOWSDEFAULT + }; + + static COLORREF MenuBGColor; + static COLORREF MenubarBGColor; + static COLORREF WindowBGColor; //used in explorer for left nav + static COLORREF ControlAreaBGColor; //used in file open dialog for button / file selection bg + static COLORREF ContentBGColor; //used in explorer for bg of file list + static COLORREF ContentSelectedColor; //used in explorer for bg of file list + static COLORREF PlayerBGColor; + static COLORREF HighLightColor; + + static COLORREF MenuSelectedColor; + static COLORREF MenubarSelectedBGColor; + static COLORREF MenuItemDisabledColor; + static COLORREF MainMenuBorderColor; + static COLORREF MenuSeparatorColor; + + static COLORREF TextFGColor; + static COLORREF TextFGColorFade; + static COLORREF PropPageCaptionFGColor; + static COLORREF ContentTextDisabledFGColorFade; + static COLORREF ContentTextDisabledFGColorFade2; + static COLORREF SubmenuColor; + static COLORREF CloseHoverColor; + static COLORREF ClosePushColor; + static COLORREF CloseColor; + static COLORREF WindowBorderColorLight; + static COLORREF WindowBorderColorDim; + static COLORREF NoBorderColor; + static COLORREF GripperPatternColor; + + static COLORREF ScrollBGColor; + static COLORREF ScrollProgressColor; + static COLORREF ScrollThumbColor; + static COLORREF ScrollThumbHoverColor; + static COLORREF ScrollThumbDragColor; + static COLORREF ScrollButtonArrowColor; + static COLORREF ScrollButtonArrowClickColor; + static COLORREF ScrollButtonHoverColor; + static COLORREF ScrollButtonClickColor; + + static COLORREF InlineEditBorderColor; + static COLORREF TooltipBorderColor; + + static COLORREF GroupBoxBorderColor; + + static COLORREF DebugColorRed; + static COLORREF DebugColorYellow; + static COLORREF DebugColorGreen; + + static COLORREF PlayerButtonHotColor; + static COLORREF PlayerButtonCheckedColor; + static COLORREF PlayerButtonClickedColor; + static COLORREF PlayerButtonBorderColor; + + static COLORREF ButtonBorderOuterColor; + static COLORREF ButtonBorderInnerFocusedColor; + static COLORREF ButtonBorderInnerColor; + static COLORREF ButtonBorderSelectedKBFocusColor; + static COLORREF ButtonBorderHoverKBFocusColor; + static COLORREF ButtonBorderKBFocusColor; + static COLORREF ButtonFillColor; + static COLORREF ButtonFillHoverColor; + static COLORREF ButtonFillSelectedColor; + static COLORREF ButtonDisabledFGColor; + + static COLORREF CheckboxBorderColor; + static COLORREF CheckboxBGColor; + static COLORREF CheckboxBorderHoverColor; + static COLORREF CheckboxBGHoverColor; + + static COLORREF ImageDisabledColor; + + static COLORREF SliderChannelColor; + + static COLORREF EditBorderColor; + + static COLORREF TreeCtrlLineColor; + static COLORREF TreeCtrlHoverColor; + static COLORREF TreeCtrlFocusColor; + + static COLORREF CheckColor; + + static COLORREF ColumnHeaderHotColor; + + static COLORREF StaticEtchedColor; + + static COLORREF ListCtrlDisabledBGColor; + static COLORREF ListCtrlGridColor; + static COLORREF ListCtrlErrorColor; + static COLORREF HeaderCtrlGridColor; + static COLORREF AudioSwitcherGridColor; + + static COLORREF TabCtrlBorderColor; + static COLORREF TabCtrlInactiveColor; + + static COLORREF StatusBarBGColor; + static COLORREF StatusBarSeparatorColor; + static COLORREF StatusBarEditBorderColor; + + static COLORREF W10DarkThemeFileDialogInjectedTextColor; + static COLORREF W10DarkThemeFileDialogInjectedBGColor; + static COLORREF W10DarkThemeFileDialogInjectedEditBorderColor; + static COLORREF W10DarkThemeTitlebarBGColor; + static COLORREF W10DarkThemeTitlebarInactiveBGColor; + static COLORREF W10DarkThemeTitlebarFGColor; + static COLORREF W10DarkThemeTitlebarInactiveFGColor; + static COLORREF W10DarkThemeTitlebarIconPenColor; + static COLORREF W10DarkThemeTitlebarControlHoverBGColor; + static COLORREF W10DarkThemeTitlebarInactiveControlHoverBGColor; + static COLORREF W10DarkThemeTitlebarControlPushedBGColor; + static COLORREF W10DarkThemeWindowBorderColor; + + static COLORREF ProgressBarBGColor; + static COLORREF ProgressBarColor; + + static COLORREF SubresyncFadeText1; + static COLORREF SubresyncFadeText2; + static COLORREF SubresyncActiveFadeText; + static COLORREF SubresyncHLColor1; + static COLORREF SubresyncHLColor2; + static COLORREF SubresyncGridSepColor; + + static COLORREF ActivePlayListItemColor; + static COLORREF ActivePlayListItemHLColor; + static COLORREF StaticLinkColor; + static COLORREF SeekbarCurrentPositionColor; + static COLORREF SeekbarChapterColor; + static COLORREF SeekbarABColor; + + static const int GroupBoxTextIndent; + + + static const BYTE GripperBitsH[10]; + static const BYTE GripperBitsV[8]; + static const int gripPatternShort; + static const int gripPatternLong; + + static wchar_t* const uiTextFont; + static wchar_t* const uiStaticTextFont; + static wchar_t* const uiSymbolFont; + + + static const COLORREF ComboboxArrowColor; + static const COLORREF ComboboxArrowColorDisabled; + + static const COLORREF HeaderCtrlSortArrowColor; + + static const BYTE CheckBits[14]; + static const int CheckWidth; + static const int CheckHeight; + + const static UINT ThemeCheckBoxes[5]; + const static UINT ThemeRadios[5]; + const static UINT ThemeGrippers[5]; + + enum pathState { + linePath, + newPath, + closePath + }; + + struct pathPoint { + float x; + float y; + pathState state; + }; + static const std::vector minimizeIcon96, minimizeIcon120, minimizeIcon144, minimizeIcon168, minimizeIcon192; + static const std::vector maximizeIcon96, maximizeIcon120, maximizeIcon144, maximizeIcon168, maximizeIcon192; + static const std::vector restoreIcon96, restoreIcon120, restoreIcon144, restoreIcon168, restoreIcon192; + static const std::vector closeIcon96, closeIcon120, closeIcon144, closeIcon168, closeIcon192; + static const std::vector hideIcon96, hideIcon120, hideIcon144, hideIcon168, hideIcon192; + static const int CMPCTheme::W10TitlebarIconPathHeight[5]; + static const int CMPCTheme::W10TitlebarIconPathWidth[5]; + static const float CMPCTheme::W10TitlebarIconPathThickness[5]; + static const int CMPCTheme::W10TitlebarButtonWidth[5]; + static const int CMPCTheme::W10TitlebarButtonSpacing[5]; + static const int CMPCTheme::ToolbarIconPathDimension[5]; + static const int CMPCTheme::ToolbarGripperHeight[5]; + static const int CMPCTheme::ToolbarHideButtonDimensions[5]; + + + static bool drawThemedControls; + + static void InitializeColors(ModernThemeMode themeMode); +}; diff --git a/src/mpc-hc/CMPCThemeButton.cpp b/src/mpc-hc/CMPCThemeButton.cpp index 57c0116bcd4..94e1e1d314d 100755 --- a/src/mpc-hc/CMPCThemeButton.cpp +++ b/src/mpc-hc/CMPCThemeButton.cpp @@ -1,191 +1,191 @@ -#include "stdafx.h" -#include "CMPCThemeButton.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -CMPCThemeButton::CMPCThemeButton() -{ - if (AppIsThemeLoaded()) { - m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT; //just setting this to get hovering working - } - drawShield = false; -} - -CMPCThemeButton::~CMPCThemeButton() -{ -} - -void CMPCThemeButton::PreSubclassWindow() //bypass CMFCButton impl since it will enable ownerdraw. also clear CS_DBLCLKS class style, due to mfcbutton requirements -{ - InitStyle(GetStyle()); - CButton::PreSubclassWindow(); - DWORD classStyle = ::GetClassLongPtr(m_hWnd, GCL_STYLE); - classStyle &= ~(CS_DBLCLKS); - ::SetClassLongPtr(m_hWnd, GCL_STYLE, classStyle); -} - -BOOL CMPCThemeButton::PreCreateWindow(CREATESTRUCT& cs) //bypass CMFCButton impl since it will enable ownerdraw. also clear CS_DBLCLKS class style, due to mfcbutton requirements -{ - InitStyle(cs.style); - if (!CButton::PreCreateWindow(cs)) { - return FALSE; - } - DWORD classStyle = ::GetClassLongPtr(m_hWnd, GCL_STYLE); - classStyle &= ~(CS_DBLCLKS); - ::SetClassLongPtr(m_hWnd, GCL_STYLE, classStyle); - return TRUE; -} - - -IMPLEMENT_DYNAMIC(CMPCThemeButton, CMFCButton) -BEGIN_MESSAGE_MAP(CMPCThemeButton, CMFCButton) - ON_WM_SETFONT() - ON_WM_GETFONT() - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeButton::OnNMCustomdraw) - ON_MESSAGE(BCM_SETSHIELD, &setShieldIcon) -END_MESSAGE_MAP() - -LRESULT CMPCThemeButton::setShieldIcon(WPARAM wParam, LPARAM lParam) -{ - drawShield = (BOOL)lParam; - return 1; //pass it along -} - -void CMPCThemeButton::drawButtonBase(CDC* pDC, CRect rect, CString strText, bool selected, bool highLighted, bool focused, bool disabled, bool thin, bool shield, HWND accelWindow) -{ - CBrush fb, fb2; - fb.CreateSolidBrush(CMPCTheme::ButtonBorderOuterColor); - - if (!thin) { //some small buttons look very ugly with the full border. make up our own solution - pDC->FrameRect(rect, &fb); - rect.DeflateRect(1, 1); - } - COLORREF bg = CMPCTheme::ButtonFillColor, dottedClr = CMPCTheme::ButtonBorderKBFocusColor; - - if (selected) {//mouse down - fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - bg = CMPCTheme::ButtonFillSelectedColor; - dottedClr = CMPCTheme::ButtonBorderSelectedKBFocusColor; - } else if (highLighted) { - fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - bg = CMPCTheme::ButtonFillHoverColor; - dottedClr = CMPCTheme::ButtonBorderHoverKBFocusColor; - } else if (focused) { - fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerFocusedColor); - } else { - fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - } - - pDC->FrameRect(rect, &fb2); - rect.DeflateRect(1, 1); - pDC->FillSolidRect(rect, bg); - - - if (focused) { - rect.DeflateRect(1, 1); - COLORREF oldTextFGColor = pDC->SetTextColor(dottedClr); - COLORREF oldBGColor = pDC->SetBkColor(bg); - CBrush* dotted = pDC->GetHalftoneBrush(); - pDC->FrameRect(rect, dotted); - DeleteObject(dotted); - pDC->SetTextColor(oldTextFGColor); - pDC->SetBkColor(oldBGColor); - } - - if (!strText.IsEmpty()) { - int nMode = pDC->SetBkMode(TRANSPARENT); - - COLORREF oldTextFGColor; - if (disabled) { - oldTextFGColor = pDC->SetTextColor(CMPCTheme::ButtonDisabledFGColor); - } else { - oldTextFGColor = pDC->SetTextColor(CMPCTheme::TextFGColor); - } - - UINT format = DT_CENTER | DT_VCENTER | DT_SINGLELINE; - if (shield) { - int iconsize = MulDiv(pDC->GetDeviceCaps(LOGPIXELSX), 1, 6); - int shieldY = rect.top + (rect.Height() - iconsize) / 2 + 1; - CRect centerRect = rect; - pDC->DrawTextW(strText, rect, format | DT_CALCRECT); - rect.top = centerRect.top; - rect.bottom = centerRect.bottom; - rect.OffsetRect((centerRect.Width() - rect.Width() + iconsize) / 2, 0); - int shieldX = rect.left - iconsize - 1; - HICON hShieldIcon = (HICON)LoadImage(0, IDI_SHIELD, IMAGE_ICON, iconsize, iconsize, LR_SHARED); - if (hShieldIcon) { - DrawIconEx(pDC->GetSafeHdc(), shieldX, shieldY, hShieldIcon, iconsize, iconsize, 0, NULL, DI_NORMAL); - } - } - - if (accelWindow && (::SendMessage(accelWindow, WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { - format |= DT_HIDEPREFIX; - } - pDC->DrawTextW(strText, rect, format); - - pDC->SetTextColor(oldTextFGColor); - pDC->SetBkMode(nMode); - } - fb.DeleteObject(); - fb2.DeleteObject(); -} - -#define max(a,b) (((a) > (b)) ? (a) : (b)) -void CMPCThemeButton::drawButton(HDC hdc, CRect rect, UINT state) -{ - CDC* pDC = CDC::FromHandle(hdc); - - CString strText; - GetWindowText(strText); - bool selected = ODS_SELECTED == (state & ODS_SELECTED); - bool focused = ODS_FOCUS == (state & ODS_FOCUS); - bool disabled = ODS_DISABLED == (state & ODS_DISABLED); - - BUTTON_IMAGELIST imgList; - GetImageList(&imgList); - CImageList* images = CImageList::FromHandlePermanent(imgList.himl); - //bool thin = (images != nullptr); //thin borders for image buttons - bool thin = true; - - - drawButtonBase(pDC, rect, strText, selected, IsHighlighted(), focused, disabled, thin, drawShield, m_hWnd); - - int imageIndex = 0; //Normal - if (disabled) { - imageIndex = 1; - } - - if (images != nullptr) { //assume centered - IMAGEINFO ii; - if (images->GetImageCount() <= imageIndex) { - imageIndex = 0; - } - images->GetImageInfo(imageIndex, &ii); - int width = ii.rcImage.right - ii.rcImage.left; - int height = ii.rcImage.bottom - ii.rcImage.top; - rect.DeflateRect((rect.Width() - width) / 2, max(0, (rect.Height() - height) / 2)); - images->Draw(pDC, imageIndex, rect.TopLeft(), ILD_NORMAL); - } -} - -void CMPCThemeButton::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); - *pResult = CDRF_DODEFAULT; - if (AppIsThemeLoaded()) { - if (pNMCD->dwDrawStage == CDDS_PREERASE) { - drawButton(pNMCD->hdc, pNMCD->rc, pNMCD->uItemState); - *pResult = CDRF_SKIPDEFAULT; - } - } -} -void CMPCThemeButton::OnSetFont(CFont* pFont, BOOL bRedraw) -{ - Default(); //bypass the MFCButton font impl since we don't always draw this button ourselves (classic mode) -} - -HFONT CMPCThemeButton::OnGetFont() -{ - return (HFONT)Default(); -} +#include "stdafx.h" +#include "CMPCThemeButton.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +CMPCThemeButton::CMPCThemeButton() +{ + if (AppIsThemeLoaded()) { + m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT; //just setting this to get hovering working + } + drawShield = false; +} + +CMPCThemeButton::~CMPCThemeButton() +{ +} + +void CMPCThemeButton::PreSubclassWindow() //bypass CMFCButton impl since it will enable ownerdraw. also clear CS_DBLCLKS class style, due to mfcbutton requirements +{ + InitStyle(GetStyle()); + CButton::PreSubclassWindow(); + DWORD classStyle = ::GetClassLongPtr(m_hWnd, GCL_STYLE); + classStyle &= ~(CS_DBLCLKS); + ::SetClassLongPtr(m_hWnd, GCL_STYLE, classStyle); +} + +BOOL CMPCThemeButton::PreCreateWindow(CREATESTRUCT& cs) //bypass CMFCButton impl since it will enable ownerdraw. also clear CS_DBLCLKS class style, due to mfcbutton requirements +{ + InitStyle(cs.style); + if (!CButton::PreCreateWindow(cs)) { + return FALSE; + } + DWORD classStyle = ::GetClassLongPtr(m_hWnd, GCL_STYLE); + classStyle &= ~(CS_DBLCLKS); + ::SetClassLongPtr(m_hWnd, GCL_STYLE, classStyle); + return TRUE; +} + + +IMPLEMENT_DYNAMIC(CMPCThemeButton, CMFCButton) +BEGIN_MESSAGE_MAP(CMPCThemeButton, CMFCButton) + ON_WM_SETFONT() + ON_WM_GETFONT() + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeButton::OnNMCustomdraw) + ON_MESSAGE(BCM_SETSHIELD, &setShieldIcon) +END_MESSAGE_MAP() + +LRESULT CMPCThemeButton::setShieldIcon(WPARAM wParam, LPARAM lParam) +{ + drawShield = (BOOL)lParam; + return 1; //pass it along +} + +void CMPCThemeButton::drawButtonBase(CDC* pDC, CRect rect, CString strText, bool selected, bool highLighted, bool focused, bool disabled, bool thin, bool shield, HWND accelWindow) +{ + CBrush fb, fb2; + fb.CreateSolidBrush(CMPCTheme::ButtonBorderOuterColor); + + if (!thin) { //some small buttons look very ugly with the full border. make up our own solution + pDC->FrameRect(rect, &fb); + rect.DeflateRect(1, 1); + } + COLORREF bg = CMPCTheme::ButtonFillColor, dottedClr = CMPCTheme::ButtonBorderKBFocusColor; + + if (selected) {//mouse down + fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + bg = CMPCTheme::ButtonFillSelectedColor; + dottedClr = CMPCTheme::ButtonBorderSelectedKBFocusColor; + } else if (highLighted) { + fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + bg = CMPCTheme::ButtonFillHoverColor; + dottedClr = CMPCTheme::ButtonBorderHoverKBFocusColor; + } else if (focused) { + fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerFocusedColor); + } else { + fb2.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + } + + pDC->FrameRect(rect, &fb2); + rect.DeflateRect(1, 1); + pDC->FillSolidRect(rect, bg); + + + if (focused) { + rect.DeflateRect(1, 1); + COLORREF oldTextFGColor = pDC->SetTextColor(dottedClr); + COLORREF oldBGColor = pDC->SetBkColor(bg); + CBrush* dotted = pDC->GetHalftoneBrush(); + pDC->FrameRect(rect, dotted); + DeleteObject(dotted); + pDC->SetTextColor(oldTextFGColor); + pDC->SetBkColor(oldBGColor); + } + + if (!strText.IsEmpty()) { + int nMode = pDC->SetBkMode(TRANSPARENT); + + COLORREF oldTextFGColor; + if (disabled) { + oldTextFGColor = pDC->SetTextColor(CMPCTheme::ButtonDisabledFGColor); + } else { + oldTextFGColor = pDC->SetTextColor(CMPCTheme::TextFGColor); + } + + UINT format = DT_CENTER | DT_VCENTER | DT_SINGLELINE; + if (shield) { + int iconsize = MulDiv(pDC->GetDeviceCaps(LOGPIXELSX), 1, 6); + int shieldY = rect.top + (rect.Height() - iconsize) / 2 + 1; + CRect centerRect = rect; + pDC->DrawTextW(strText, rect, format | DT_CALCRECT); + rect.top = centerRect.top; + rect.bottom = centerRect.bottom; + rect.OffsetRect((centerRect.Width() - rect.Width() + iconsize) / 2, 0); + int shieldX = rect.left - iconsize - 1; + HICON hShieldIcon = (HICON)LoadImage(0, IDI_SHIELD, IMAGE_ICON, iconsize, iconsize, LR_SHARED); + if (hShieldIcon) { + DrawIconEx(pDC->GetSafeHdc(), shieldX, shieldY, hShieldIcon, iconsize, iconsize, 0, NULL, DI_NORMAL); + } + } + + if (accelWindow && (::SendMessage(accelWindow, WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { + format |= DT_HIDEPREFIX; + } + pDC->DrawTextW(strText, rect, format); + + pDC->SetTextColor(oldTextFGColor); + pDC->SetBkMode(nMode); + } + fb.DeleteObject(); + fb2.DeleteObject(); +} + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +void CMPCThemeButton::drawButton(HDC hdc, CRect rect, UINT state) +{ + CDC* pDC = CDC::FromHandle(hdc); + + CString strText; + GetWindowText(strText); + bool selected = ODS_SELECTED == (state & ODS_SELECTED); + bool focused = ODS_FOCUS == (state & ODS_FOCUS); + bool disabled = ODS_DISABLED == (state & ODS_DISABLED); + + BUTTON_IMAGELIST imgList; + GetImageList(&imgList); + CImageList* images = CImageList::FromHandlePermanent(imgList.himl); + //bool thin = (images != nullptr); //thin borders for image buttons + bool thin = true; + + + drawButtonBase(pDC, rect, strText, selected, IsHighlighted(), focused, disabled, thin, drawShield, m_hWnd); + + int imageIndex = 0; //Normal + if (disabled) { + imageIndex = 1; + } + + if (images != nullptr) { //assume centered + IMAGEINFO ii; + if (images->GetImageCount() <= imageIndex) { + imageIndex = 0; + } + images->GetImageInfo(imageIndex, &ii); + int width = ii.rcImage.right - ii.rcImage.left; + int height = ii.rcImage.bottom - ii.rcImage.top; + rect.DeflateRect((rect.Width() - width) / 2, max(0, (rect.Height() - height) / 2)); + images->Draw(pDC, imageIndex, rect.TopLeft(), ILD_NORMAL); + } +} + +void CMPCThemeButton::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); + *pResult = CDRF_DODEFAULT; + if (AppIsThemeLoaded()) { + if (pNMCD->dwDrawStage == CDDS_PREERASE) { + drawButton(pNMCD->hdc, pNMCD->rc, pNMCD->uItemState); + *pResult = CDRF_SKIPDEFAULT; + } + } +} +void CMPCThemeButton::OnSetFont(CFont* pFont, BOOL bRedraw) +{ + Default(); //bypass the MFCButton font impl since we don't always draw this button ourselves (classic mode) +} + +HFONT CMPCThemeButton::OnGetFont() +{ + return (HFONT)Default(); +} diff --git a/src/mpc-hc/CMPCThemeButton.h b/src/mpc-hc/CMPCThemeButton.h index 42d68741871..c682ee420fc 100755 --- a/src/mpc-hc/CMPCThemeButton.h +++ b/src/mpc-hc/CMPCThemeButton.h @@ -1,22 +1,22 @@ -#pragma once - -class CMPCThemeButton : public CMFCButton -{ -protected: - void drawButton(HDC hdc, CRect rect, UINT state); - CFont font; - bool drawShield; -public: - CMPCThemeButton(); - virtual ~CMPCThemeButton(); - void PreSubclassWindow(); - BOOL PreCreateWindow(CREATESTRUCT& cs); - LRESULT setShieldIcon(WPARAM wParam, LPARAM lParam); - static void drawButtonBase(CDC* pDC, CRect rect, CString strText, bool selected, bool highLighted, bool focused, bool disabled, bool thin, bool shield, HWND accelWindow=nullptr); - DECLARE_DYNAMIC(CMPCThemeButton) - DECLARE_MESSAGE_MAP() - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnSetFont(CFont* pFont, BOOL bRedraw); - afx_msg HFONT OnGetFont(); -}; - +#pragma once + +class CMPCThemeButton : public CMFCButton +{ +protected: + void drawButton(HDC hdc, CRect rect, UINT state); + CFont font; + bool drawShield; +public: + CMPCThemeButton(); + virtual ~CMPCThemeButton(); + void PreSubclassWindow(); + BOOL PreCreateWindow(CREATESTRUCT& cs); + LRESULT setShieldIcon(WPARAM wParam, LPARAM lParam); + static void drawButtonBase(CDC* pDC, CRect rect, CString strText, bool selected, bool highLighted, bool focused, bool disabled, bool thin, bool shield, HWND accelWindow=nullptr); + DECLARE_DYNAMIC(CMPCThemeButton) + DECLARE_MESSAGE_MAP() + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnSetFont(CFont* pFont, BOOL bRedraw); + afx_msg HFONT OnGetFont(); +}; + diff --git a/src/mpc-hc/CMPCThemeCmdUIDialog.cpp b/src/mpc-hc/CMPCThemeCmdUIDialog.cpp index 48a219e88a7..b7f1991a858 100755 --- a/src/mpc-hc/CMPCThemeCmdUIDialog.cpp +++ b/src/mpc-hc/CMPCThemeCmdUIDialog.cpp @@ -1,45 +1,45 @@ -#include "stdafx.h" -#include "CMPCThemeCmdUIDialog.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - - -CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog() -{ -} - -CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog(UINT nIDTemplate, CWnd* pParent): CCmdUIDialog(nIDTemplate, pParent) -{ -} - -CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent): CCmdUIDialog(lpszTemplateName, pParent) -{ -} - - -CMPCThemeCmdUIDialog::~CMPCThemeCmdUIDialog() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeCmdUIDialog, CCmdUIDialog) -BEGIN_MESSAGE_MAP(CMPCThemeCmdUIDialog, CCmdUIDialog) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - -BOOL CMPCThemeCmdUIDialog::OnInitDialog() -{ - BOOL ret = __super::OnInitDialog(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return ret; -} - - -HBRUSH CMPCThemeCmdUIDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppNeedsThemedControls()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} +#include "stdafx.h" +#include "CMPCThemeCmdUIDialog.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + + +CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog() +{ +} + +CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog(UINT nIDTemplate, CWnd* pParent): CCmdUIDialog(nIDTemplate, pParent) +{ +} + +CMPCThemeCmdUIDialog::CMPCThemeCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent): CCmdUIDialog(lpszTemplateName, pParent) +{ +} + + +CMPCThemeCmdUIDialog::~CMPCThemeCmdUIDialog() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeCmdUIDialog, CCmdUIDialog) +BEGIN_MESSAGE_MAP(CMPCThemeCmdUIDialog, CCmdUIDialog) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + +BOOL CMPCThemeCmdUIDialog::OnInitDialog() +{ + BOOL ret = __super::OnInitDialog(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return ret; +} + + +HBRUSH CMPCThemeCmdUIDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppNeedsThemedControls()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} diff --git a/src/mpc-hc/CMPCThemeCmdUIDialog.h b/src/mpc-hc/CMPCThemeCmdUIDialog.h index 52fd70ec466..6ebe57a520b 100755 --- a/src/mpc-hc/CMPCThemeCmdUIDialog.h +++ b/src/mpc-hc/CMPCThemeCmdUIDialog.h @@ -1,21 +1,21 @@ -#pragma once -#include "..\CmdUI\CmdUI.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeGroupBox.h" -#include "CMPCThemeLinkCtrl.h" -#include "CMPCThemeUtil.h" -class CMPCThemeCmdUIDialog : public CCmdUIDialog, public CMPCThemeUtil -{ -public: - CMPCThemeCmdUIDialog(); - CMPCThemeCmdUIDialog(UINT nIDTemplate, CWnd* pParent = nullptr); - CMPCThemeCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); - virtual ~CMPCThemeCmdUIDialog(); - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - BOOL OnInitDialog(); - DECLARE_DYNAMIC(CMPCThemeCmdUIDialog) - DECLARE_MESSAGE_MAP() -public: - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -}; - +#pragma once +#include "..\CmdUI\CmdUI.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeGroupBox.h" +#include "CMPCThemeLinkCtrl.h" +#include "CMPCThemeUtil.h" +class CMPCThemeCmdUIDialog : public CCmdUIDialog, public CMPCThemeUtil +{ +public: + CMPCThemeCmdUIDialog(); + CMPCThemeCmdUIDialog(UINT nIDTemplate, CWnd* pParent = nullptr); + CMPCThemeCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); + virtual ~CMPCThemeCmdUIDialog(); + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + BOOL OnInitDialog(); + DECLARE_DYNAMIC(CMPCThemeCmdUIDialog) + DECLARE_MESSAGE_MAP() +public: + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +}; + diff --git a/src/mpc-hc/CMPCThemeComPropertyPage.cpp b/src/mpc-hc/CMPCThemeComPropertyPage.cpp index 3bb9608cc07..305167fa436 100755 --- a/src/mpc-hc/CMPCThemeComPropertyPage.cpp +++ b/src/mpc-hc/CMPCThemeComPropertyPage.cpp @@ -1,46 +1,46 @@ -#include "stdafx.h" -#include "CMPCThemeComPropertyPage.h" -#include "moreuuids.h" - -CLSID CMPCThemeComPropertyPage::dialogClsid = GUID_NULL; - -CMPCThemeComPropertyPage::CMPCThemeComPropertyPage(IPropertyPage* pPage) : CComPropertyPage(pPage) -{ - -} - -CMPCThemeComPropertyPage::~CMPCThemeComPropertyPage() -{ - dialogClsid = GUID_NULL; -} - -BOOL CMPCThemeComPropertyPage::OnInitDialog() -{ - __super::OnInitDialog(); - - if (dialogClsid == CLSID_MPCVR) { - fulfillThemeReqs(CMPCThemeUtil::SpecialThemeCases::ExternalPropertyPageWithDefaultButton); - } else if (dialogClsid == CLSID_Generic_WDM_FilterProxy) { - fulfillThemeReqs(CMPCThemeUtil::SpecialThemeCases::ExternalPropertyPageWithAnalogCaptureSliders); - } else { - fulfillThemeReqs(); - } - return 0; -} - -IMPLEMENT_DYNAMIC(CMPCThemeComPropertyPage, CComPropertyPage) -BEGIN_MESSAGE_MAP(CMPCThemeComPropertyPage, CComPropertyPage) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeComPropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} +#include "stdafx.h" +#include "CMPCThemeComPropertyPage.h" +#include "moreuuids.h" + +CLSID CMPCThemeComPropertyPage::dialogClsid = GUID_NULL; + +CMPCThemeComPropertyPage::CMPCThemeComPropertyPage(IPropertyPage* pPage) : CComPropertyPage(pPage) +{ + +} + +CMPCThemeComPropertyPage::~CMPCThemeComPropertyPage() +{ + dialogClsid = GUID_NULL; +} + +BOOL CMPCThemeComPropertyPage::OnInitDialog() +{ + __super::OnInitDialog(); + + if (dialogClsid == CLSID_MPCVR) { + fulfillThemeReqs(CMPCThemeUtil::SpecialThemeCases::ExternalPropertyPageWithDefaultButton); + } else if (dialogClsid == CLSID_Generic_WDM_FilterProxy) { + fulfillThemeReqs(CMPCThemeUtil::SpecialThemeCases::ExternalPropertyPageWithAnalogCaptureSliders); + } else { + fulfillThemeReqs(); + } + return 0; +} + +IMPLEMENT_DYNAMIC(CMPCThemeComPropertyPage, CComPropertyPage) +BEGIN_MESSAGE_MAP(CMPCThemeComPropertyPage, CComPropertyPage) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeComPropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} diff --git a/src/mpc-hc/CMPCThemeComPropertyPage.h b/src/mpc-hc/CMPCThemeComPropertyPage.h index 1ab69f42b86..7106e3f5a9f 100755 --- a/src/mpc-hc/CMPCThemeComPropertyPage.h +++ b/src/mpc-hc/CMPCThemeComPropertyPage.h @@ -1,21 +1,21 @@ -#pragma once -#include "ComPropertyPage.h" -#include "CMPCThemeUtil.h" -class CMPCThemeComPropertyPage : public CComPropertyPage, public CMPCThemeUtil -{ -public: - CMPCThemeComPropertyPage(IPropertyPage* pPage); - virtual ~CMPCThemeComPropertyPage(); - - - void fulfillThemeReqs(SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase) { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this, specialCase); }; - static void SetDialogType(CLSID clsid) { dialogClsid = clsid; }; - DECLARE_DYNAMIC(CMPCThemeComPropertyPage) - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - virtual BOOL OnInitDialog(); - static CLSID dialogClsid; -}; - +#pragma once +#include "ComPropertyPage.h" +#include "CMPCThemeUtil.h" +class CMPCThemeComPropertyPage : public CComPropertyPage, public CMPCThemeUtil +{ +public: + CMPCThemeComPropertyPage(IPropertyPage* pPage); + virtual ~CMPCThemeComPropertyPage(); + + + void fulfillThemeReqs(SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase) { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this, specialCase); }; + static void SetDialogType(CLSID clsid) { dialogClsid = clsid; }; + DECLARE_DYNAMIC(CMPCThemeComPropertyPage) + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + virtual BOOL OnInitDialog(); + static CLSID dialogClsid; +}; + diff --git a/src/mpc-hc/CMPCThemeComboBox.cpp b/src/mpc-hc/CMPCThemeComboBox.cpp index 5b6a42b22ee..72e807ca51a 100644 --- a/src/mpc-hc/CMPCThemeComboBox.cpp +++ b/src/mpc-hc/CMPCThemeComboBox.cpp @@ -1,300 +1,300 @@ -#include "stdafx.h" -#include "CMPCThemeComboBox.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#undef SubclassWindow - -IMPLEMENT_DYNAMIC(CMPCThemeComboBox, CComboBox) - -BEGIN_MESSAGE_MAP(CMPCThemeComboBox, CComboBox) - ON_WM_PAINT() - ON_WM_SETFOCUS() - ON_WM_MOUSEMOVE() - ON_WM_MOUSELEAVE() - ON_WM_LBUTTONUP() - ON_WM_LBUTTONDOWN() - ON_WM_CREATE() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -CMPCThemeComboBox::CMPCThemeComboBox() - :CComboBox(), - isHover(false), - hasThemedControls(false) -{ -} - -void CMPCThemeComboBox::doDraw(CDC& dc, CString strText, CRect rText, COLORREF bkColor, COLORREF fgColor, bool drawDotted) -{ - COLORREF crOldTextColor = dc.GetTextColor(); - COLORREF crOldBkColor = dc.GetBkColor(); - - dc.SetBkColor(bkColor); - dc.SetTextColor(fgColor); - - CRect textRect = rText; - //textRect.left += 3; - - CFont* font = GetFont(); - CFont* pOldFont = dc.SelectObject(font); - dc.DrawTextW(strText, &textRect, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); - dc.SelectObject(pOldFont); - - if (drawDotted) { - dc.SetTextColor(bkColor ^ 0xffffff); - CBrush* dotted = dc.GetHalftoneBrush(); - dc.FrameRect(rText, dotted); - DeleteObject(dotted); - } - - dc.SetTextColor(crOldTextColor); - dc.SetBkColor(crOldBkColor); -} - -CMPCThemeComboBox::~CMPCThemeComboBox() -{ -} - -void CMPCThemeComboBox::themeControls() -{ - if (AppNeedsThemedControls()) { - if (CMPCThemeUtil::canUseWin10DarkTheme() && !hasThemedControls) { - COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - if (GetComboBoxInfo(&info)) { - SetWindowTheme(info.hwndList, L"DarkMode_Explorer", NULL); - DWORD dropdownType = GetStyle() & 3; - if (CBS_DROPDOWN == dropdownType || CBS_SIMPLE == dropdownType) { - cbEdit.SubclassWindow(info.hwndItem); - } - - hasThemedControls = true; - } - } - } -} - -void CMPCThemeComboBox::PreSubclassWindow() -{ - themeControls(); -} - - -void CMPCThemeComboBox::drawComboArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect) -{ - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - Gdiplus::Color clr; - clr.SetFromCOLORREF(arrowClr); - - int dpi = dpiWindow.DPIX(); - float steps; - - if (dpi < 120) { - steps = 3.5; - } else if (dpi < 144) { - steps = 4; - } else if (dpi < 168) { - steps = 5; - } else if (dpi < 192) { - steps = 5; - } else { - steps = 6; - } - - int xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - int yPos = arrowRect.top + (arrowRect.Height() - (steps + 1)) / 2; - - Gdiplus::Graphics gfx(dc.m_hDC); - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x4); - Gdiplus::Pen pen(clr, 1); - for (int i = 0; i < 2; i++) { - Gdiplus::GraphicsPath path; - Gdiplus::PointF vertices[3]; - - vertices[0] = Gdiplus::PointF(xPos, yPos); - vertices[1] = Gdiplus::PointF(steps + xPos, yPos + steps); - vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos); - - path.AddLines(vertices, 3); - gfx.DrawPath(&pen, &path); - } -} - - -void CMPCThemeComboBox::OnPaint() -{ - if (AppNeedsThemedControls()) { - CPaintDC dc(this); - CRect r, rBorder, rText, rBG, rSelect, rDownArrow; - GetClientRect(r); - CString strText; - GetWindowText(strText); - - COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - GetComboBoxInfo(&info); - CWnd* pCBEdit = GetDlgItem(1001); - - CBrush fb; - bool isFocused, drawDotted = false; - - if (pCBEdit) { - CRect editRect; - pCBEdit->GetWindowRect(editRect); - ScreenToClient(editRect); - dc.ExcludeClipRect(editRect); - isFocused = (nullptr != info.hwndItem && ::GetFocus() == info.hwndItem); - if (isFocused) { - fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerFocusedColor); - } else { - fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - } - } else { - isFocused = (GetFocus() == this); - if (isFocused) { - drawDotted = true; - } - fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); - } - - COLORREF bkColor, fgColor = CMPCTheme::TextFGColor, arrowColor = CMPCTheme::ComboboxArrowColor; - if ((nullptr != info.hwndList && ::IsWindowVisible(info.hwndList)) || info.stateButton == STATE_SYSTEM_PRESSED) { //always looks the same once the list is open - bkColor = CMPCTheme::ButtonFillSelectedColor; - drawDotted = false; - } else if (info.stateButton == 0 && isHover) { //not pressed and hovered - bkColor = CMPCTheme::ButtonFillHoverColor; - } else if (!IsWindowEnabled()) { - bkColor = CMPCTheme::ButtonFillColor; - fgColor = CMPCTheme::ButtonDisabledFGColor; - arrowColor = CMPCTheme::ComboboxArrowColorDisabled; - } else { - bkColor = CMPCTheme::ButtonFillColor; - } - - rBG = r; - rBG.DeflateRect(1, 1); - if (pCBEdit) { - CRect tB(info.rcButton); - dc.FillSolidRect(tB, bkColor); - rBG.right = info.rcButton.left - 1; - CMPCThemeUtil::drawParentDialogBGClr(this, &dc, rBG, true); - rBG.left = rBG.right; - rBG.right += 1; - dc.FillSolidRect(rBG, CMPCTheme::ButtonBorderInnerColor); - } else { - dc.FillSolidRect(rBG, bkColor); - rText = r; - rText.right = info.rcItem.right; - rText.DeflateRect(3, 3); - doDraw(dc, strText, rText, bkColor, fgColor, drawDotted); - } - - rDownArrow = info.rcButton; - drawComboArrow(dc, arrowColor, rDownArrow); - - rBorder = r; - dc.FrameRect(rBorder, &fb); - fb.DeleteObject(); - } else { - CComboBox::OnPaint(); - } -} - - -void CMPCThemeComboBox::OnSetFocus(CWnd* pOldWnd) -{ - CComboBox::OnSetFocus(pOldWnd); - //Invalidate(); -} - -void CMPCThemeComboBox::checkHover(UINT nFlags, CPoint point, bool invalidate) -{ - CRect r; - bool oldHover = isHover; - CPoint ptScreen = point; - ClientToScreen(&ptScreen); - - CWnd* pCBEdit = GetDlgItem(1001); - if (pCBEdit) { //we only hover on the button, because the edit covers most of the combobox (except one pixel, which we don't want to check, as it causes flicker) - COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; - GetComboBoxInfo(&info); - r = info.rcButton; - } else { - GetClientRect(r); - } - - if (r.PtInRect(point) && WindowFromPoint(ptScreen)->GetSafeHwnd() == GetSafeHwnd()) { - isHover = true; - } else { - isHover = false; - } - if (isHover != oldHover && invalidate) { - Invalidate(); - } - -} - -void CMPCThemeComboBox::OnMouseMove(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point); - CComboBox::OnMouseMove(nFlags, point); -} - - -void CMPCThemeComboBox::OnMouseLeave() -{ - checkHover(0, CPoint(-1, -1)); - CComboBox::OnMouseLeave(); -} - - -void CMPCThemeComboBox::OnLButtonUp(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point, false); - CComboBox::OnLButtonUp(nFlags, point); -} - - -void CMPCThemeComboBox::OnLButtonDown(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point); - CComboBox::OnLButtonDown(nFlags, point); -} - - -int CMPCThemeComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (__super::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - themeControls(); - - return 0; -} - - -BOOL CMPCThemeComboBox::OnEraseBkgnd(CDC* pDC) { - return TRUE; -} - -int CMPCThemeComboBox::SetCurSel(int nSelect) { //note, this is NOT virtual, and only works for explicit subclass - int cur = GetCurSel(); - if (cur != nSelect) { - int ret = __super::SetCurSel(nSelect); - RedrawWindow(); - return ret; - } else { - return nSelect; - } -} - -void CMPCThemeComboBox::SelectByItemData(DWORD_PTR data) { - for (int i = 0; i < GetCount(); i++) { - if (GetItemData(i) == data) { - SetCurSel(i); //calls CMPCThemeComboBox::SetCurSel - break; - } - } -} +#include "stdafx.h" +#include "CMPCThemeComboBox.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#undef SubclassWindow + +IMPLEMENT_DYNAMIC(CMPCThemeComboBox, CComboBox) + +BEGIN_MESSAGE_MAP(CMPCThemeComboBox, CComboBox) + ON_WM_PAINT() + ON_WM_SETFOCUS() + ON_WM_MOUSEMOVE() + ON_WM_MOUSELEAVE() + ON_WM_LBUTTONUP() + ON_WM_LBUTTONDOWN() + ON_WM_CREATE() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +CMPCThemeComboBox::CMPCThemeComboBox() + :CComboBox(), + isHover(false), + hasThemedControls(false) +{ +} + +void CMPCThemeComboBox::doDraw(CDC& dc, CString strText, CRect rText, COLORREF bkColor, COLORREF fgColor, bool drawDotted) +{ + COLORREF crOldTextColor = dc.GetTextColor(); + COLORREF crOldBkColor = dc.GetBkColor(); + + dc.SetBkColor(bkColor); + dc.SetTextColor(fgColor); + + CRect textRect = rText; + //textRect.left += 3; + + CFont* font = GetFont(); + CFont* pOldFont = dc.SelectObject(font); + dc.DrawTextW(strText, &textRect, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); + dc.SelectObject(pOldFont); + + if (drawDotted) { + dc.SetTextColor(bkColor ^ 0xffffff); + CBrush* dotted = dc.GetHalftoneBrush(); + dc.FrameRect(rText, dotted); + DeleteObject(dotted); + } + + dc.SetTextColor(crOldTextColor); + dc.SetBkColor(crOldBkColor); +} + +CMPCThemeComboBox::~CMPCThemeComboBox() +{ +} + +void CMPCThemeComboBox::themeControls() +{ + if (AppNeedsThemedControls()) { + if (CMPCThemeUtil::canUseWin10DarkTheme() && !hasThemedControls) { + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; + if (GetComboBoxInfo(&info)) { + SetWindowTheme(info.hwndList, L"DarkMode_Explorer", NULL); + DWORD dropdownType = GetStyle() & 3; + if (CBS_DROPDOWN == dropdownType || CBS_SIMPLE == dropdownType) { + cbEdit.SubclassWindow(info.hwndItem); + } + + hasThemedControls = true; + } + } + } +} + +void CMPCThemeComboBox::PreSubclassWindow() +{ + themeControls(); +} + + +void CMPCThemeComboBox::drawComboArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect) +{ + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + Gdiplus::Color clr; + clr.SetFromCOLORREF(arrowClr); + + int dpi = dpiWindow.DPIX(); + float steps; + + if (dpi < 120) { + steps = 3.5; + } else if (dpi < 144) { + steps = 4; + } else if (dpi < 168) { + steps = 5; + } else if (dpi < 192) { + steps = 5; + } else { + steps = 6; + } + + int xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + int yPos = arrowRect.top + (arrowRect.Height() - (steps + 1)) / 2; + + Gdiplus::Graphics gfx(dc.m_hDC); + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x4); + Gdiplus::Pen pen(clr, 1); + for (int i = 0; i < 2; i++) { + Gdiplus::GraphicsPath path; + Gdiplus::PointF vertices[3]; + + vertices[0] = Gdiplus::PointF(xPos, yPos); + vertices[1] = Gdiplus::PointF(steps + xPos, yPos + steps); + vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos); + + path.AddLines(vertices, 3); + gfx.DrawPath(&pen, &path); + } +} + + +void CMPCThemeComboBox::OnPaint() +{ + if (AppNeedsThemedControls()) { + CPaintDC dc(this); + CRect r, rBorder, rText, rBG, rSelect, rDownArrow; + GetClientRect(r); + CString strText; + GetWindowText(strText); + + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; + GetComboBoxInfo(&info); + CWnd* pCBEdit = GetDlgItem(1001); + + CBrush fb; + bool isFocused, drawDotted = false; + + if (pCBEdit) { + CRect editRect; + pCBEdit->GetWindowRect(editRect); + ScreenToClient(editRect); + dc.ExcludeClipRect(editRect); + isFocused = (nullptr != info.hwndItem && ::GetFocus() == info.hwndItem); + if (isFocused) { + fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerFocusedColor); + } else { + fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + } + } else { + isFocused = (GetFocus() == this); + if (isFocused) { + drawDotted = true; + } + fb.CreateSolidBrush(CMPCTheme::ButtonBorderInnerColor); + } + + COLORREF bkColor, fgColor = CMPCTheme::TextFGColor, arrowColor = CMPCTheme::ComboboxArrowColor; + if ((nullptr != info.hwndList && ::IsWindowVisible(info.hwndList)) || info.stateButton == STATE_SYSTEM_PRESSED) { //always looks the same once the list is open + bkColor = CMPCTheme::ButtonFillSelectedColor; + drawDotted = false; + } else if (info.stateButton == 0 && isHover) { //not pressed and hovered + bkColor = CMPCTheme::ButtonFillHoverColor; + } else if (!IsWindowEnabled()) { + bkColor = CMPCTheme::ButtonFillColor; + fgColor = CMPCTheme::ButtonDisabledFGColor; + arrowColor = CMPCTheme::ComboboxArrowColorDisabled; + } else { + bkColor = CMPCTheme::ButtonFillColor; + } + + rBG = r; + rBG.DeflateRect(1, 1); + if (pCBEdit) { + CRect tB(info.rcButton); + dc.FillSolidRect(tB, bkColor); + rBG.right = info.rcButton.left - 1; + CMPCThemeUtil::drawParentDialogBGClr(this, &dc, rBG, true); + rBG.left = rBG.right; + rBG.right += 1; + dc.FillSolidRect(rBG, CMPCTheme::ButtonBorderInnerColor); + } else { + dc.FillSolidRect(rBG, bkColor); + rText = r; + rText.right = info.rcItem.right; + rText.DeflateRect(3, 3); + doDraw(dc, strText, rText, bkColor, fgColor, drawDotted); + } + + rDownArrow = info.rcButton; + drawComboArrow(dc, arrowColor, rDownArrow); + + rBorder = r; + dc.FrameRect(rBorder, &fb); + fb.DeleteObject(); + } else { + CComboBox::OnPaint(); + } +} + + +void CMPCThemeComboBox::OnSetFocus(CWnd* pOldWnd) +{ + CComboBox::OnSetFocus(pOldWnd); + //Invalidate(); +} + +void CMPCThemeComboBox::checkHover(UINT nFlags, CPoint point, bool invalidate) +{ + CRect r; + bool oldHover = isHover; + CPoint ptScreen = point; + ClientToScreen(&ptScreen); + + CWnd* pCBEdit = GetDlgItem(1001); + if (pCBEdit) { //we only hover on the button, because the edit covers most of the combobox (except one pixel, which we don't want to check, as it causes flicker) + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; + GetComboBoxInfo(&info); + r = info.rcButton; + } else { + GetClientRect(r); + } + + if (r.PtInRect(point) && WindowFromPoint(ptScreen)->GetSafeHwnd() == GetSafeHwnd()) { + isHover = true; + } else { + isHover = false; + } + if (isHover != oldHover && invalidate) { + Invalidate(); + } + +} + +void CMPCThemeComboBox::OnMouseMove(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point); + CComboBox::OnMouseMove(nFlags, point); +} + + +void CMPCThemeComboBox::OnMouseLeave() +{ + checkHover(0, CPoint(-1, -1)); + CComboBox::OnMouseLeave(); +} + + +void CMPCThemeComboBox::OnLButtonUp(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point, false); + CComboBox::OnLButtonUp(nFlags, point); +} + + +void CMPCThemeComboBox::OnLButtonDown(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point); + CComboBox::OnLButtonDown(nFlags, point); +} + + +int CMPCThemeComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (__super::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + themeControls(); + + return 0; +} + + +BOOL CMPCThemeComboBox::OnEraseBkgnd(CDC* pDC) { + return TRUE; +} + +int CMPCThemeComboBox::SetCurSel(int nSelect) { //note, this is NOT virtual, and only works for explicit subclass + int cur = GetCurSel(); + if (cur != nSelect) { + int ret = __super::SetCurSel(nSelect); + RedrawWindow(); + return ret; + } else { + return nSelect; + } +} + +void CMPCThemeComboBox::SelectByItemData(DWORD_PTR data) { + for (int i = 0; i < GetCount(); i++) { + if (GetItemData(i) == data) { + SetCurSel(i); //calls CMPCThemeComboBox::SetCurSel + break; + } + } +} diff --git a/src/mpc-hc/CMPCThemeComboBox.h b/src/mpc-hc/CMPCThemeComboBox.h index 67136b5ece9..6ffde8f3c98 100755 --- a/src/mpc-hc/CMPCThemeComboBox.h +++ b/src/mpc-hc/CMPCThemeComboBox.h @@ -1,33 +1,33 @@ -#pragma once -#include -#include "CMPCThemeEdit.h" -class CMPCThemeComboBox : - public CComboBox -{ - DECLARE_DYNAMIC(CMPCThemeComboBox) -private: - bool isHover; - bool hasThemedControls; - CBrush bgBrush; - CMPCThemeEdit cbEdit; -public: - CMPCThemeComboBox(); - void doDraw(CDC& dc, CString strText, CRect r, COLORREF bkColor, COLORREF fgColor, bool drawDotted); - virtual ~CMPCThemeComboBox(); - void themeControls(); - void PreSubclassWindow(); - void drawComboArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect); - void checkHover(UINT nFlags, CPoint point, bool invalidate = true); - int SetCurSel(int nSelect); - void SelectByItemData(DWORD_PTR data); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg void OnSetFocus(CWnd* pOldWnd); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; - +#pragma once +#include +#include "CMPCThemeEdit.h" +class CMPCThemeComboBox : + public CComboBox +{ + DECLARE_DYNAMIC(CMPCThemeComboBox) +private: + bool isHover; + bool hasThemedControls; + CBrush bgBrush; + CMPCThemeEdit cbEdit; +public: + CMPCThemeComboBox(); + void doDraw(CDC& dc, CString strText, CRect r, COLORREF bkColor, COLORREF fgColor, bool drawDotted); + virtual ~CMPCThemeComboBox(); + void themeControls(); + void PreSubclassWindow(); + void drawComboArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect); + void checkHover(UINT nFlags, CPoint point, bool invalidate = true); + int SetCurSel(int nSelect); + void SelectByItemData(DWORD_PTR data); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; + diff --git a/src/mpc-hc/CMPCThemeDialog.cpp b/src/mpc-hc/CMPCThemeDialog.cpp index cd70c757eb9..460cd01b730 100755 --- a/src/mpc-hc/CMPCThemeDialog.cpp +++ b/src/mpc-hc/CMPCThemeDialog.cpp @@ -1,67 +1,67 @@ -#include "stdafx.h" -#include "CMPCThemeDialog.h" -#include "CMPCTheme.h" -#include "mplayerc.h" -#undef SubclassWindow - - -CMPCThemeDialog::CMPCThemeDialog(bool isDummy /* = false */) -{ - this->isDummy = isDummy; -} - -CMPCThemeDialog::CMPCThemeDialog(UINT nIDTemplate, CWnd* pParentWnd) : CDialog(nIDTemplate, pParentWnd) -{ -} - - -CMPCThemeDialog::~CMPCThemeDialog() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeDialog, CDialog) - -BEGIN_MESSAGE_MAP(CMPCThemeDialog, CDialog) - ON_COMMAND_EX(IDOK, OnOK_EX) - ON_WM_CTLCOLOR() - ON_WM_HSCROLL() -END_MESSAGE_MAP() - -BOOL CMPCThemeDialog::OnInitDialog() -{ - BOOL ret = __super::OnInitDialog(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return ret; -} - -HBRUSH CMPCThemeDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} -BOOL CMPCThemeDialog::PreTranslateMessage(MSG* pMsg) { - if (isDummy) { - return FALSE; - } else { - return CDialog::PreTranslateMessage(pMsg); - } -} - -void CMPCThemeDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { - __super::OnHScroll(nSBCode, nPos, pScrollBar); - if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase && nSBCode == TB_THUMBPOSITION) { - UpdateAnalogCaptureDeviceSlider(pScrollBar); - } -} - -BOOL CMPCThemeDialog::OnOK_EX(UINT nId) { - if (ToolbarCustomizeDialog == specialCase) { //the toolbar customize dialog has assigned 1==IDOK to the "add" button, which CDialog interprets as `EndDialog(IDOK)` - return FALSE; - } - __super::OnOK(); - return TRUE; -} +#include "stdafx.h" +#include "CMPCThemeDialog.h" +#include "CMPCTheme.h" +#include "mplayerc.h" +#undef SubclassWindow + + +CMPCThemeDialog::CMPCThemeDialog(bool isDummy /* = false */) +{ + this->isDummy = isDummy; +} + +CMPCThemeDialog::CMPCThemeDialog(UINT nIDTemplate, CWnd* pParentWnd) : CDialog(nIDTemplate, pParentWnd) +{ +} + + +CMPCThemeDialog::~CMPCThemeDialog() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeDialog, CDialog) + +BEGIN_MESSAGE_MAP(CMPCThemeDialog, CDialog) + ON_COMMAND_EX(IDOK, OnOK_EX) + ON_WM_CTLCOLOR() + ON_WM_HSCROLL() +END_MESSAGE_MAP() + +BOOL CMPCThemeDialog::OnInitDialog() +{ + BOOL ret = __super::OnInitDialog(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return ret; +} + +HBRUSH CMPCThemeDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} +BOOL CMPCThemeDialog::PreTranslateMessage(MSG* pMsg) { + if (isDummy) { + return FALSE; + } else { + return CDialog::PreTranslateMessage(pMsg); + } +} + +void CMPCThemeDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { + __super::OnHScroll(nSBCode, nPos, pScrollBar); + if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase && nSBCode == TB_THUMBPOSITION) { + UpdateAnalogCaptureDeviceSlider(pScrollBar); + } +} + +BOOL CMPCThemeDialog::OnOK_EX(UINT nId) { + if (ToolbarCustomizeDialog == specialCase) { //the toolbar customize dialog has assigned 1==IDOK to the "add" button, which CDialog interprets as `EndDialog(IDOK)` + return FALSE; + } + __super::OnOK(); + return TRUE; +} diff --git a/src/mpc-hc/CMPCThemeDialog.h b/src/mpc-hc/CMPCThemeDialog.h index fe1165883ee..bfaae9bfce1 100755 --- a/src/mpc-hc/CMPCThemeDialog.h +++ b/src/mpc-hc/CMPCThemeDialog.h @@ -1,29 +1,29 @@ -#pragma once -#include -#include "CMPCThemeButton.h" -#include "CMPCThemeGroupBox.h" -#include "CMPCThemeLinkCtrl.h" -#include "CMPCThemeUtil.h" - -class CMPCThemeDialog : - public CDialog, public CMPCThemeUtil -{ -public: - CMPCThemeDialog(bool isDummy = false); - explicit CMPCThemeDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); - virtual ~CMPCThemeDialog(); - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - BOOL OnInitDialog(); - void SetSpecialCase(CMPCThemeUtil::SpecialThemeCases specialCase) { this->specialCase = specialCase; } - DECLARE_DYNAMIC(CMPCThemeDialog) - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - BOOL PreTranslateMessage(MSG* pMsg); - virtual BOOL OnOK_EX(UINT nId); -private: - bool isDummy = false; - CMPCThemeUtil::SpecialThemeCases specialCase = NoSpecialCase; -public: - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); -}; - +#pragma once +#include +#include "CMPCThemeButton.h" +#include "CMPCThemeGroupBox.h" +#include "CMPCThemeLinkCtrl.h" +#include "CMPCThemeUtil.h" + +class CMPCThemeDialog : + public CDialog, public CMPCThemeUtil +{ +public: + CMPCThemeDialog(bool isDummy = false); + explicit CMPCThemeDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); + virtual ~CMPCThemeDialog(); + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + BOOL OnInitDialog(); + void SetSpecialCase(CMPCThemeUtil::SpecialThemeCases specialCase) { this->specialCase = specialCase; } + DECLARE_DYNAMIC(CMPCThemeDialog) + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL OnOK_EX(UINT nId); +private: + bool isDummy = false; + CMPCThemeUtil::SpecialThemeCases specialCase = NoSpecialCase; +public: + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); +}; + diff --git a/src/mpc-hc/CMPCThemeDockBar.cpp b/src/mpc-hc/CMPCThemeDockBar.cpp index 2167166eba3..47a7eb33df2 100755 --- a/src/mpc-hc/CMPCThemeDockBar.cpp +++ b/src/mpc-hc/CMPCThemeDockBar.cpp @@ -1,62 +1,62 @@ -#include "stdafx.h" -#include "CMPCThemeDockBar.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - -IMPLEMENT_DYNAMIC(CMPCThemeDockBar, CDockBar) -BEGIN_MESSAGE_MAP(CMPCThemeDockBar, CDockBar) - ON_WM_ERASEBKGND() - ON_WM_NCPAINT() -END_MESSAGE_MAP() - -CMPCThemeDockBar::CMPCThemeDockBar() -{ -} - - -CMPCThemeDockBar::~CMPCThemeDockBar() -{ -} - - -BOOL CMPCThemeDockBar::OnEraseBkgnd(CDC* pDC) -{ - if (!AppIsThemeLoaded()) { - return __super::OnEraseBkgnd(pDC); - } - - CBrush backBrush(CMPCTheme::WindowBGColor); - - CBrush* pOldBrush = pDC->SelectObject(&backBrush); - CRect rect; - pDC->GetClipBox(&rect); - - pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); - pDC->SelectObject(pOldBrush); - - return TRUE; -} - - -void CMPCThemeDockBar::OnNcPaint() -{ - if (!AppIsThemeLoaded()) { - __super::OnNcPaint(); - return; - } - - CWindowDC dc(this); // the HDC will be released by the destructor - - CRect rcClient, rcWindow; - GetClientRect(rcClient); - GetWindowRect(rcWindow); - ScreenToClient(rcWindow); - rcClient.OffsetRect(-rcWindow.TopLeft()); - rcWindow.OffsetRect(-rcWindow.TopLeft()); - - CRect rcDraw = rcWindow; - - dc.IntersectClipRect(rcWindow); - dc.ExcludeClipRect(rcClient); - dc.FillSolidRect(rcDraw, CMPCTheme::WindowBGColor); -} +#include "stdafx.h" +#include "CMPCThemeDockBar.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + +IMPLEMENT_DYNAMIC(CMPCThemeDockBar, CDockBar) +BEGIN_MESSAGE_MAP(CMPCThemeDockBar, CDockBar) + ON_WM_ERASEBKGND() + ON_WM_NCPAINT() +END_MESSAGE_MAP() + +CMPCThemeDockBar::CMPCThemeDockBar() +{ +} + + +CMPCThemeDockBar::~CMPCThemeDockBar() +{ +} + + +BOOL CMPCThemeDockBar::OnEraseBkgnd(CDC* pDC) +{ + if (!AppIsThemeLoaded()) { + return __super::OnEraseBkgnd(pDC); + } + + CBrush backBrush(CMPCTheme::WindowBGColor); + + CBrush* pOldBrush = pDC->SelectObject(&backBrush); + CRect rect; + pDC->GetClipBox(&rect); + + pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); + pDC->SelectObject(pOldBrush); + + return TRUE; +} + + +void CMPCThemeDockBar::OnNcPaint() +{ + if (!AppIsThemeLoaded()) { + __super::OnNcPaint(); + return; + } + + CWindowDC dc(this); // the HDC will be released by the destructor + + CRect rcClient, rcWindow; + GetClientRect(rcClient); + GetWindowRect(rcWindow); + ScreenToClient(rcWindow); + rcClient.OffsetRect(-rcWindow.TopLeft()); + rcWindow.OffsetRect(-rcWindow.TopLeft()); + + CRect rcDraw = rcWindow; + + dc.IntersectClipRect(rcWindow); + dc.ExcludeClipRect(rcClient); + dc.FillSolidRect(rcDraw, CMPCTheme::WindowBGColor); +} diff --git a/src/mpc-hc/CMPCThemeDockBar.h b/src/mpc-hc/CMPCThemeDockBar.h index b3a355f9287..eb9042abf45 100755 --- a/src/mpc-hc/CMPCThemeDockBar.h +++ b/src/mpc-hc/CMPCThemeDockBar.h @@ -1,15 +1,15 @@ -#pragma once -#include -class CMPCThemeDockBar : public CDockBar -{ - DECLARE_DYNAMIC(CMPCThemeDockBar) -public: - CMPCThemeDockBar(); - virtual ~CMPCThemeDockBar(); -protected: - DECLARE_MESSAGE_MAP() -public: - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnNcPaint(); -}; - +#pragma once +#include +class CMPCThemeDockBar : public CDockBar +{ + DECLARE_DYNAMIC(CMPCThemeDockBar) +public: + CMPCThemeDockBar(); + virtual ~CMPCThemeDockBar(); +protected: + DECLARE_MESSAGE_MAP() +public: + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnNcPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeEdit.cpp b/src/mpc-hc/CMPCThemeEdit.cpp index 615a7897402..eb8df670002 100755 --- a/src/mpc-hc/CMPCThemeEdit.cpp +++ b/src/mpc-hc/CMPCThemeEdit.cpp @@ -1,437 +1,437 @@ -#include "stdafx.h" -#include "CMPCThemeEdit.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#include "CMPCThemeMenu.h" -#include - -std::unique_ptr editMenu; -CMPCThemeEdit::CMPCThemeEdit() -{ - buddy = nullptr; - themedSBHelper = nullptr; - isFileDialogChild = false; - //horizontal scrollbar broken for CEdit, we must theme ourselves - // if (!CMPCThemeUtil::canUseWin10DarkTheme()()) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - // } -} - -CMPCThemeEdit::~CMPCThemeEdit() -{ - if (nullptr != themedSBHelper) { - delete themedSBHelper; - } -} - -IMPLEMENT_DYNAMIC(CMPCThemeEdit, CEdit) -BEGIN_MESSAGE_MAP(CMPCThemeEdit, CEdit) - ON_WM_NCPAINT() - ON_WM_MOUSEWHEEL() - ON_WM_VSCROLL() - ON_WM_HSCROLL() - ON_WM_KEYDOWN() - ON_WM_WINDOWPOSCHANGED() - ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, ResizeSupport) - ON_MESSAGE(WM_CONTEXTMENU, OnContextMenu) - ON_WM_MEASUREITEM() -END_MESSAGE_MAP() - -void CMPCThemeEdit::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { - if (lpMeasureItemStruct->CtlType == ODT_MENU && editMenu) { - editMenu->MeasureItem(lpMeasureItemStruct); - return; - } - - CEdit::OnMeasureItem(nIDCtl, lpMeasureItemStruct); -} - -//on Edit class, cbWndExtra allocates space for a pointer, which points to this data -struct PRIVATEWNDDATA { - LONG_PTR ptr1; - DWORD D04, D08; - DWORD textLength; - DWORD D10; - DWORD startSelection, endSelection, cursorPosition; - DWORD DW1[5]; - LONG_PTR ptr2; - DWORD hwnd; //32-bit storage, even on 64-bit (HWND is wrong size) - DWORD DW2[7]; - DWORD parentHwnd; //32-bit storage, even on 64-bit (HWND is wrong size) - DWORD D3; - LONG_PTR ptr3; - DWORD D4; - DWORD flags; //EDIT control flags -}; - -//ContextMenu constants -#define ENABLE_UNICODE_CONTROL_CHARS 0x40000000 -#define IDS_OPEN_IME 0x1052 -#define IDS_CLOSE_IME 0x1053 -#define IDS_IME_RECONVERSION 0x1056 -#define ID_CONTEXT_MENU_IME 0x2711 -#define ID_CONTEXT_MENU_RECONVERSION 0x2713 -#define SCS_FEATURES_NEEDED (SCS_CAP_MAKEREAD | SCS_CAP_SETRECONVERTSTRING) -#define EDIT_CONTEXT_MENU 1 - -bool IsBidiLocale() { - DWORD layout; - //see https://web.archive.org/web/20131013052748/http://blogs.msdn.com/b/michkap/archive/2012/01/13/10256391.aspx - if (GetLocaleInfoW(GetUserDefaultUILanguage(), LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, (LPWSTR)&layout, 2)) { - if (layout == 1) { - return true; - } - } - return false; -} - -std::array UnicodeChars = { - 0x200D, //ZWJ -- Zero width &joiner - 0x200C, //ZWNJ -- Zero width &non-joiner - 0x200E, //RLM -- &Right-to-left mark - 0x200F, //LRM -- &Left-to-right mark - 0x202A, //LRE -- Start of left-to-right embedding - 0x202B, //RLE -- Start of right-to-left embedding - 0x202D, //LRO -- Start of left-to-right override - 0x202E, //RLO -- Start of right-to-left override - 0x202C, //PDF -- Pop directional formatting - 0x206E, //NADS -- National digit shapes substitution - 0x206F, //NODS -- Nominal (European) digit shapes - 0x206B, //ASS -- Activate symmetric swapping - 0x206A, //ISS -- Inhibit symmetric swapping - 0x206D, //AAFS -- Activate Arabic form shaping - 0x206C, //IAFS -- Inhibit Arabic form shaping - 0x001E, //RS -- Record Separator (Block separator) - 0x001F, //US -- Unit Separator (Segment separator) -}; - -void CMPCThemeEdit::SetCompWindowPos(HIMC himc, UINT start) { - COMPOSITIONFORM cf = { CFS_POINT, PosFromChar(start), {0} }; - ImmSetCompositionWindow(himc, &cf); -} - -LRESULT CMPCThemeEdit::OnContextMenu(WPARAM wParam, LPARAM lParam) { - if (AppIsThemeLoaded()) { - if (GetFocus() != this) { - SetFocus(); - } - HMODULE g_hinst = GetModuleHandleW(L"comctl32.dll"); - if (g_hinst) { - HMENU menu = LoadMenuW(g_hinst, (LPCWSTR)EDIT_CONTEXT_MENU); - if (menu) { - HMENU popup = GetSubMenu(menu, 0); - if (popup) { - CPoint pt; - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - - DWORD rtlStyle = WS_EX_RTLREADING | WS_EX_RIGHT; - bool isRTL = (GetExStyle() & rtlStyle); - - bool supportUnicodeControl = false, showControlChars = false; - PRIVATEWNDDATA *pwd = (PRIVATEWNDDATA *)GetWindowLongPtrW(m_hWnd, 0); - if (pwd && pwd->hwnd == static_cast((LONG_PTR)m_hWnd)) { //sanity check - supportUnicodeControl = true; - showControlChars = (pwd->flags & ENABLE_UNICODE_CONTROL_CHARS); - } - - if (pt.x == -1 && pt.y == -1) { //VK_APPS - CRect rc; - GetClientRect(&rc); - - pt.x = rc.left + (rc.right - rc.left) / 2; - pt.y = rc.top + (rc.bottom - rc.top) / 2; - ClientToScreen(&pt); - } - - UINT start = HIWORD(GetSel()); - UINT end = LOWORD(GetSel()); - DWORD style = GetStyle(); - bool isPasswordField = (style & ES_PASSWORD); - CStringW str; - GetWindowTextW(str); - - - if (end < start) { - std::swap(end, start); - } - int selectionLength = end - start; - - editMenu = std::make_unique(); - editMenu->setOSMenu(true); - editMenu->Attach(popup); - editMenu->EnableMenuItem(EM_UNDO, MF_BYCOMMAND | (CanUndo() && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); - editMenu->EnableMenuItem(WM_CUT, MF_BYCOMMAND | (selectionLength && !isPasswordField && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); - editMenu->EnableMenuItem(WM_COPY, MF_BYCOMMAND | (selectionLength && !isPasswordField ? MF_ENABLED : MF_GRAYED)); - editMenu->EnableMenuItem(WM_PASTE, MF_BYCOMMAND | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); - editMenu->EnableMenuItem(WM_CLEAR, MF_BYCOMMAND | (selectionLength && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); //delete - editMenu->EnableMenuItem(EM_SETSEL, MF_BYCOMMAND | (start || (end != str.GetLength()) ? MF_ENABLED : MF_GRAYED)); //select all - editMenu->EnableMenuItem(WM_APP, MF_BYCOMMAND | MF_ENABLED); //RTL - editMenu->CheckMenuItem(WM_APP, MF_BYCOMMAND | (isRTL ? MF_CHECKED : MF_UNCHECKED)); - - if (supportUnicodeControl) { - editMenu->EnableMenuItem(WM_APP + 1, MF_BYCOMMAND | MF_ENABLED); //show unicode control chars - editMenu->CheckMenuItem(WM_APP + 1, MF_BYCOMMAND | (showControlChars ? MF_CHECKED : MF_UNCHECKED)); - } - - //enable all unicode char inserts - for (UINT idx = WM_APP + 0x2; idx <= WM_APP + 0x13; idx++) { - editMenu->EnableMenuItem(idx, MF_BYCOMMAND | MF_ENABLED); - } - - HIMC himc = nullptr; - HKL hkl = GetKeyboardLayout(NULL); - if (ImmIsIME(hkl)) { - himc = ImmGetContext(this->m_hWnd); - if (himc) { - bool checked = false, enabled = true; - MENUITEMINFOW mii = { sizeof(MENUITEMINFOW) }; - mii.fMask = MIIM_ID | MIIM_STRING; - mii.wID = ID_CONTEXT_MENU_IME; - CStringW miS; - bool strLoaded; - - if (::ImmGetOpenStatus(himc)) { - strLoaded = miS.LoadStringW(g_hinst, IDS_CLOSE_IME); - } else { - strLoaded = miS.LoadStringW(g_hinst, IDS_OPEN_IME); - } - - if (strLoaded) { - mii.dwTypeData = (LPWSTR)miS.GetString(); - mii.cch = (UINT)wcslen(mii.dwTypeData); - - editMenu->InsertMenuItemW(editMenu->GetMenuItemCount(), &mii); - } - - strLoaded = miS.LoadStringW(g_hinst, IDS_IME_RECONVERSION); - if (strLoaded) { - mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE; - mii.dwTypeData = (LPWSTR)miS.GetString(); - mii.cch = (UINT)wcslen(mii.dwTypeData); - mii.wID = ID_CONTEXT_MENU_RECONVERSION; - bool supportsReconversion = (ImmGetProperty(hkl, IGP_SETCOMPSTR) & SCS_FEATURES_NEEDED) == SCS_FEATURES_NEEDED; - if (!supportsReconversion || !selectionLength || isPasswordField) { - mii.fState = MFS_DISABLED; - } else { - mii.fState = MFS_ENABLED; - } - editMenu->InsertMenuItemW(editMenu->GetMenuItemCount(), &mii); - } - } - } - editMenu->fulfillThemeReqs(); - - UINT cmd = editMenu->TrackPopupMenu((IsBidiLocale() ? TPM_LAYOUTRTL : TPM_LEFTALIGN) | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, pt.x, pt.y, this); - - switch (cmd) { - case EM_UNDO: - case WM_CUT: - case WM_COPY: - case WM_PASTE: - case WM_CLEAR: - SendMessageW(cmd, 0, 0); - break; - case EM_SETSEL: - SendMessageW(EM_SETSEL, 0, -1); - break; - case WM_APP: //RTL - ModifyStyleEx(isRTL ? rtlStyle : 0, isRTL ? 0 : rtlStyle); - break; - case WM_APP + 1: //show unicode control chars - if (pwd) { - pwd->flags ^= ENABLE_UNICODE_CONTROL_CHARS; - Invalidate(); - } - break; - case ID_CONTEXT_MENU_IME: //IME - if (himc) { - ImmSetOpenStatus(himc, !ImmGetOpenStatus(himc)); - } - break; - case ID_CONTEXT_MENU_RECONVERSION: - if (himc) { - CStringW selected; - selected = str.Mid(start, end - start); - const size_t text_memory_byte = sizeof(wchar_t) * (selected.GetLength() + 1); - const size_t memory_block_size = sizeof(RECONVERTSTRING) + text_memory_byte; - std::unique_ptr memory_block{ new (std::nothrow) BYTE[memory_block_size] }; - if (memory_block) { - SetCompWindowPos(himc, start); - RECONVERTSTRING* reconv{ reinterpret_cast(memory_block.get()) }; - reconv->dwSize = (DWORD)memory_block_size; - reconv->dwVersion = 0; - reconv->dwStrLen = selected.GetLength(); - reconv->dwStrOffset = sizeof(RECONVERTSTRING); - reconv->dwCompStrLen = selected.GetLength(); - reconv->dwCompStrOffset = 0; - reconv->dwTargetStrLen = selected.GetLength(); - reconv->dwTargetStrOffset = reconv->dwCompStrOffset; - wchar_t* text{ reinterpret_cast(memory_block.get() + sizeof(RECONVERTSTRING)) }; - memcpy_s(text, text_memory_byte, selected.GetBuffer(), text_memory_byte); - ImmSetCompositionStringW(himc, SCS_QUERYRECONVERTSTRING, (LPVOID)memory_block.get(), (DWORD)memory_block_size, nullptr, 0); - ImmSetCompositionStringW(himc, SCS_SETRECONVERTSTRING, (LPVOID)memory_block.get(), (DWORD)memory_block_size, nullptr, 0); - } - } - default: - int idx = cmd - (WM_APP + 0x2); - if (idx >= 0 && idx < UnicodeChars.size()) { - SendMessageW(WM_CHAR, UnicodeChars[idx], 0); break; //US -- Unit Separator (Segment separator) - } - break; - } - - if (himc) { - ::ImmReleaseContext(this->m_hWnd, himc); - } - editMenu.reset(); - return 0; - } - } - } - } - return Default(); -} - -bool CMPCThemeEdit::IsScrollable() { - return 0 != (GetStyle() & (WS_VSCROLL | WS_HSCROLL)); -} - -//this message is sent by resizablelib -//we prevent clipping for multi-line edits due to using regions which conflict with resizablelib clipping -LRESULT CMPCThemeEdit::ResizeSupport(WPARAM wParam, LPARAM lParam) { - if (AppNeedsThemedControls() && IsScrollable()) { - if (wParam == RSZSUP_QUERYPROPERTIES) { - LPRESIZEPROPERTIES props = (LPRESIZEPROPERTIES)lParam; - props->bAskClipping = false; - props->bCachedLikesClipping = false; - return TRUE; - } - } - return FALSE; -} - -void CMPCThemeEdit::OnWindowPosChanged(WINDOWPOS* lpwndpos) { - if (AppNeedsThemedControls()) { - if (themedSBHelper && IsScrollable()) { - themedSBHelper->OnWindowPosChanged(); - } - } - return __super::OnWindowPosChanged(lpwndpos); -} - -void CMPCThemeEdit::PreSubclassWindow() -{ - if (AppIsThemeLoaded()) { - CRect r; - GetClientRect(r); - r.DeflateRect(2, 2); //some default padding for those spaceless fonts - SetRect(r); - if (CMPCThemeUtil::canUseWin10DarkTheme()) { - SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); - } else { - SetWindowTheme(GetSafeHwnd(), L"", NULL); - } - } else { - __super::PreSubclassWindow(); - } -} - - - -void CMPCThemeEdit::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - if (IsScrollable()) { //scrollable edit will be treated like a window, not a field - if (nullptr != themedSBHelper) { - themedSBHelper->themedNcPaintWithSB(); - } else { - CMPCThemeScrollBarHelper::themedNcPaint(this, this); - } - } else { - CWindowDC dc(this); - - CRect rect; - GetWindowRect(&rect); - rect.OffsetRect(-rect.left, -rect.top); - - //note: rc file with style "NOT WS_BORDER" will remove the default of WS_EX_CLIENTEDGE from EDITTEXT - //WS_BORDER itself is not typically present - auto stEx = GetExStyle(); - if (0 != (GetStyle() & WS_BORDER) || 0 != (GetExStyle() & WS_EX_CLIENTEDGE)) { - CBrush brush; - if (isFileDialogChild) {//special case for edits injected to file dialog - brush.CreateSolidBrush(CMPCTheme::W10DarkThemeFileDialogInjectedEditBorderColor); - } else { - brush.CreateSolidBrush(CMPCTheme::EditBorderColor); - } - - dc.FrameRect(&rect, &brush); - brush.DeleteObject(); - } - - //added code to draw the inner rect for the border. we shrunk the draw rect for border spacing earlier - //normally, the bg of the dialog is sufficient, but in the case of ResizableDialog, it clips the anchored - //windows, which leaves unpainted area just inside our border - rect.DeflateRect(1, 1); - CMPCThemeUtil::drawParentDialogBGClr(this, &dc, rect, false); - - if (nullptr != buddy) { - buddy->Invalidate(); - } - } - - } else { - __super::OnNcPaint(); - } -} - -void CMPCThemeEdit::SetFixedWidthFont(CFont& f) -{ - if (AppIsThemeLoaded()) { - CWindowDC dc(this); - if (CMPCThemeUtil::getFixedFont(font, &dc, this)) { - SetFont(&font); - } else { - SetFont(&f); - } - } else { - SetFont(&f); - } -} - -BOOL CMPCThemeEdit::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) -{ - __super::OnMouseWheel(nFlags, zDelta, pt); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - ScreenToClient(&pt); - return TRUE; -} - -void CMPCThemeEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - __super::OnVScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - -void CMPCThemeEdit::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - __super::OnHScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - - -void CMPCThemeEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - __super::OnKeyDown(nChar, nRepCnt, nFlags); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} +#include "stdafx.h" +#include "CMPCThemeEdit.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#include "CMPCThemeMenu.h" +#include + +std::unique_ptr editMenu; +CMPCThemeEdit::CMPCThemeEdit() +{ + buddy = nullptr; + themedSBHelper = nullptr; + isFileDialogChild = false; + //horizontal scrollbar broken for CEdit, we must theme ourselves + // if (!CMPCThemeUtil::canUseWin10DarkTheme()()) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + // } +} + +CMPCThemeEdit::~CMPCThemeEdit() +{ + if (nullptr != themedSBHelper) { + delete themedSBHelper; + } +} + +IMPLEMENT_DYNAMIC(CMPCThemeEdit, CEdit) +BEGIN_MESSAGE_MAP(CMPCThemeEdit, CEdit) + ON_WM_NCPAINT() + ON_WM_MOUSEWHEEL() + ON_WM_VSCROLL() + ON_WM_HSCROLL() + ON_WM_KEYDOWN() + ON_WM_WINDOWPOSCHANGED() + ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, ResizeSupport) + ON_MESSAGE(WM_CONTEXTMENU, OnContextMenu) + ON_WM_MEASUREITEM() +END_MESSAGE_MAP() + +void CMPCThemeEdit::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { + if (lpMeasureItemStruct->CtlType == ODT_MENU && editMenu) { + editMenu->MeasureItem(lpMeasureItemStruct); + return; + } + + CEdit::OnMeasureItem(nIDCtl, lpMeasureItemStruct); +} + +//on Edit class, cbWndExtra allocates space for a pointer, which points to this data +struct PRIVATEWNDDATA { + LONG_PTR ptr1; + DWORD D04, D08; + DWORD textLength; + DWORD D10; + DWORD startSelection, endSelection, cursorPosition; + DWORD DW1[5]; + LONG_PTR ptr2; + DWORD hwnd; //32-bit storage, even on 64-bit (HWND is wrong size) + DWORD DW2[7]; + DWORD parentHwnd; //32-bit storage, even on 64-bit (HWND is wrong size) + DWORD D3; + LONG_PTR ptr3; + DWORD D4; + DWORD flags; //EDIT control flags +}; + +//ContextMenu constants +#define ENABLE_UNICODE_CONTROL_CHARS 0x40000000 +#define IDS_OPEN_IME 0x1052 +#define IDS_CLOSE_IME 0x1053 +#define IDS_IME_RECONVERSION 0x1056 +#define ID_CONTEXT_MENU_IME 0x2711 +#define ID_CONTEXT_MENU_RECONVERSION 0x2713 +#define SCS_FEATURES_NEEDED (SCS_CAP_MAKEREAD | SCS_CAP_SETRECONVERTSTRING) +#define EDIT_CONTEXT_MENU 1 + +bool IsBidiLocale() { + DWORD layout; + //see https://web.archive.org/web/20131013052748/http://blogs.msdn.com/b/michkap/archive/2012/01/13/10256391.aspx + if (GetLocaleInfoW(GetUserDefaultUILanguage(), LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, (LPWSTR)&layout, 2)) { + if (layout == 1) { + return true; + } + } + return false; +} + +std::array UnicodeChars = { + 0x200D, //ZWJ -- Zero width &joiner + 0x200C, //ZWNJ -- Zero width &non-joiner + 0x200E, //RLM -- &Right-to-left mark + 0x200F, //LRM -- &Left-to-right mark + 0x202A, //LRE -- Start of left-to-right embedding + 0x202B, //RLE -- Start of right-to-left embedding + 0x202D, //LRO -- Start of left-to-right override + 0x202E, //RLO -- Start of right-to-left override + 0x202C, //PDF -- Pop directional formatting + 0x206E, //NADS -- National digit shapes substitution + 0x206F, //NODS -- Nominal (European) digit shapes + 0x206B, //ASS -- Activate symmetric swapping + 0x206A, //ISS -- Inhibit symmetric swapping + 0x206D, //AAFS -- Activate Arabic form shaping + 0x206C, //IAFS -- Inhibit Arabic form shaping + 0x001E, //RS -- Record Separator (Block separator) + 0x001F, //US -- Unit Separator (Segment separator) +}; + +void CMPCThemeEdit::SetCompWindowPos(HIMC himc, UINT start) { + COMPOSITIONFORM cf = { CFS_POINT, PosFromChar(start), {0} }; + ImmSetCompositionWindow(himc, &cf); +} + +LRESULT CMPCThemeEdit::OnContextMenu(WPARAM wParam, LPARAM lParam) { + if (AppIsThemeLoaded()) { + if (GetFocus() != this) { + SetFocus(); + } + HMODULE g_hinst = GetModuleHandleW(L"comctl32.dll"); + if (g_hinst) { + HMENU menu = LoadMenuW(g_hinst, (LPCWSTR)EDIT_CONTEXT_MENU); + if (menu) { + HMENU popup = GetSubMenu(menu, 0); + if (popup) { + CPoint pt; + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + + DWORD rtlStyle = WS_EX_RTLREADING | WS_EX_RIGHT; + bool isRTL = (GetExStyle() & rtlStyle); + + bool supportUnicodeControl = false, showControlChars = false; + PRIVATEWNDDATA *pwd = (PRIVATEWNDDATA *)GetWindowLongPtrW(m_hWnd, 0); + if (pwd && pwd->hwnd == static_cast((LONG_PTR)m_hWnd)) { //sanity check + supportUnicodeControl = true; + showControlChars = (pwd->flags & ENABLE_UNICODE_CONTROL_CHARS); + } + + if (pt.x == -1 && pt.y == -1) { //VK_APPS + CRect rc; + GetClientRect(&rc); + + pt.x = rc.left + (rc.right - rc.left) / 2; + pt.y = rc.top + (rc.bottom - rc.top) / 2; + ClientToScreen(&pt); + } + + UINT start = HIWORD(GetSel()); + UINT end = LOWORD(GetSel()); + DWORD style = GetStyle(); + bool isPasswordField = (style & ES_PASSWORD); + CStringW str; + GetWindowTextW(str); + + + if (end < start) { + std::swap(end, start); + } + int selectionLength = end - start; + + editMenu = std::make_unique(); + editMenu->setOSMenu(true); + editMenu->Attach(popup); + editMenu->EnableMenuItem(EM_UNDO, MF_BYCOMMAND | (CanUndo() && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); + editMenu->EnableMenuItem(WM_CUT, MF_BYCOMMAND | (selectionLength && !isPasswordField && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); + editMenu->EnableMenuItem(WM_COPY, MF_BYCOMMAND | (selectionLength && !isPasswordField ? MF_ENABLED : MF_GRAYED)); + editMenu->EnableMenuItem(WM_PASTE, MF_BYCOMMAND | (IsClipboardFormatAvailable(CF_UNICODETEXT) && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); + editMenu->EnableMenuItem(WM_CLEAR, MF_BYCOMMAND | (selectionLength && !(style & ES_READONLY) ? MF_ENABLED : MF_GRAYED)); //delete + editMenu->EnableMenuItem(EM_SETSEL, MF_BYCOMMAND | (start || (end != str.GetLength()) ? MF_ENABLED : MF_GRAYED)); //select all + editMenu->EnableMenuItem(WM_APP, MF_BYCOMMAND | MF_ENABLED); //RTL + editMenu->CheckMenuItem(WM_APP, MF_BYCOMMAND | (isRTL ? MF_CHECKED : MF_UNCHECKED)); + + if (supportUnicodeControl) { + editMenu->EnableMenuItem(WM_APP + 1, MF_BYCOMMAND | MF_ENABLED); //show unicode control chars + editMenu->CheckMenuItem(WM_APP + 1, MF_BYCOMMAND | (showControlChars ? MF_CHECKED : MF_UNCHECKED)); + } + + //enable all unicode char inserts + for (UINT idx = WM_APP + 0x2; idx <= WM_APP + 0x13; idx++) { + editMenu->EnableMenuItem(idx, MF_BYCOMMAND | MF_ENABLED); + } + + HIMC himc = nullptr; + HKL hkl = GetKeyboardLayout(NULL); + if (ImmIsIME(hkl)) { + himc = ImmGetContext(this->m_hWnd); + if (himc) { + bool checked = false, enabled = true; + MENUITEMINFOW mii = { sizeof(MENUITEMINFOW) }; + mii.fMask = MIIM_ID | MIIM_STRING; + mii.wID = ID_CONTEXT_MENU_IME; + CStringW miS; + bool strLoaded; + + if (::ImmGetOpenStatus(himc)) { + strLoaded = miS.LoadStringW(g_hinst, IDS_CLOSE_IME); + } else { + strLoaded = miS.LoadStringW(g_hinst, IDS_OPEN_IME); + } + + if (strLoaded) { + mii.dwTypeData = (LPWSTR)miS.GetString(); + mii.cch = (UINT)wcslen(mii.dwTypeData); + + editMenu->InsertMenuItemW(editMenu->GetMenuItemCount(), &mii); + } + + strLoaded = miS.LoadStringW(g_hinst, IDS_IME_RECONVERSION); + if (strLoaded) { + mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE; + mii.dwTypeData = (LPWSTR)miS.GetString(); + mii.cch = (UINT)wcslen(mii.dwTypeData); + mii.wID = ID_CONTEXT_MENU_RECONVERSION; + bool supportsReconversion = (ImmGetProperty(hkl, IGP_SETCOMPSTR) & SCS_FEATURES_NEEDED) == SCS_FEATURES_NEEDED; + if (!supportsReconversion || !selectionLength || isPasswordField) { + mii.fState = MFS_DISABLED; + } else { + mii.fState = MFS_ENABLED; + } + editMenu->InsertMenuItemW(editMenu->GetMenuItemCount(), &mii); + } + } + } + editMenu->fulfillThemeReqs(); + + UINT cmd = editMenu->TrackPopupMenu((IsBidiLocale() ? TPM_LAYOUTRTL : TPM_LEFTALIGN) | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, pt.x, pt.y, this); + + switch (cmd) { + case EM_UNDO: + case WM_CUT: + case WM_COPY: + case WM_PASTE: + case WM_CLEAR: + SendMessageW(cmd, 0, 0); + break; + case EM_SETSEL: + SendMessageW(EM_SETSEL, 0, -1); + break; + case WM_APP: //RTL + ModifyStyleEx(isRTL ? rtlStyle : 0, isRTL ? 0 : rtlStyle); + break; + case WM_APP + 1: //show unicode control chars + if (pwd) { + pwd->flags ^= ENABLE_UNICODE_CONTROL_CHARS; + Invalidate(); + } + break; + case ID_CONTEXT_MENU_IME: //IME + if (himc) { + ImmSetOpenStatus(himc, !ImmGetOpenStatus(himc)); + } + break; + case ID_CONTEXT_MENU_RECONVERSION: + if (himc) { + CStringW selected; + selected = str.Mid(start, end - start); + const size_t text_memory_byte = sizeof(wchar_t) * (selected.GetLength() + 1); + const size_t memory_block_size = sizeof(RECONVERTSTRING) + text_memory_byte; + std::unique_ptr memory_block{ new (std::nothrow) BYTE[memory_block_size] }; + if (memory_block) { + SetCompWindowPos(himc, start); + RECONVERTSTRING* reconv{ reinterpret_cast(memory_block.get()) }; + reconv->dwSize = (DWORD)memory_block_size; + reconv->dwVersion = 0; + reconv->dwStrLen = selected.GetLength(); + reconv->dwStrOffset = sizeof(RECONVERTSTRING); + reconv->dwCompStrLen = selected.GetLength(); + reconv->dwCompStrOffset = 0; + reconv->dwTargetStrLen = selected.GetLength(); + reconv->dwTargetStrOffset = reconv->dwCompStrOffset; + wchar_t* text{ reinterpret_cast(memory_block.get() + sizeof(RECONVERTSTRING)) }; + memcpy_s(text, text_memory_byte, selected.GetBuffer(), text_memory_byte); + ImmSetCompositionStringW(himc, SCS_QUERYRECONVERTSTRING, (LPVOID)memory_block.get(), (DWORD)memory_block_size, nullptr, 0); + ImmSetCompositionStringW(himc, SCS_SETRECONVERTSTRING, (LPVOID)memory_block.get(), (DWORD)memory_block_size, nullptr, 0); + } + } + default: + int idx = cmd - (WM_APP + 0x2); + if (idx >= 0 && idx < UnicodeChars.size()) { + SendMessageW(WM_CHAR, UnicodeChars[idx], 0); break; //US -- Unit Separator (Segment separator) + } + break; + } + + if (himc) { + ::ImmReleaseContext(this->m_hWnd, himc); + } + editMenu.reset(); + return 0; + } + } + } + } + return Default(); +} + +bool CMPCThemeEdit::IsScrollable() { + return 0 != (GetStyle() & (WS_VSCROLL | WS_HSCROLL)); +} + +//this message is sent by resizablelib +//we prevent clipping for multi-line edits due to using regions which conflict with resizablelib clipping +LRESULT CMPCThemeEdit::ResizeSupport(WPARAM wParam, LPARAM lParam) { + if (AppNeedsThemedControls() && IsScrollable()) { + if (wParam == RSZSUP_QUERYPROPERTIES) { + LPRESIZEPROPERTIES props = (LPRESIZEPROPERTIES)lParam; + props->bAskClipping = false; + props->bCachedLikesClipping = false; + return TRUE; + } + } + return FALSE; +} + +void CMPCThemeEdit::OnWindowPosChanged(WINDOWPOS* lpwndpos) { + if (AppNeedsThemedControls()) { + if (themedSBHelper && IsScrollable()) { + themedSBHelper->OnWindowPosChanged(); + } + } + return __super::OnWindowPosChanged(lpwndpos); +} + +void CMPCThemeEdit::PreSubclassWindow() +{ + if (AppIsThemeLoaded()) { + CRect r; + GetClientRect(r); + r.DeflateRect(2, 2); //some default padding for those spaceless fonts + SetRect(r); + if (CMPCThemeUtil::canUseWin10DarkTheme()) { + SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); + } else { + SetWindowTheme(GetSafeHwnd(), L"", NULL); + } + } else { + __super::PreSubclassWindow(); + } +} + + + +void CMPCThemeEdit::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + if (IsScrollable()) { //scrollable edit will be treated like a window, not a field + if (nullptr != themedSBHelper) { + themedSBHelper->themedNcPaintWithSB(); + } else { + CMPCThemeScrollBarHelper::themedNcPaint(this, this); + } + } else { + CWindowDC dc(this); + + CRect rect; + GetWindowRect(&rect); + rect.OffsetRect(-rect.left, -rect.top); + + //note: rc file with style "NOT WS_BORDER" will remove the default of WS_EX_CLIENTEDGE from EDITTEXT + //WS_BORDER itself is not typically present + auto stEx = GetExStyle(); + if (0 != (GetStyle() & WS_BORDER) || 0 != (GetExStyle() & WS_EX_CLIENTEDGE)) { + CBrush brush; + if (isFileDialogChild) {//special case for edits injected to file dialog + brush.CreateSolidBrush(CMPCTheme::W10DarkThemeFileDialogInjectedEditBorderColor); + } else { + brush.CreateSolidBrush(CMPCTheme::EditBorderColor); + } + + dc.FrameRect(&rect, &brush); + brush.DeleteObject(); + } + + //added code to draw the inner rect for the border. we shrunk the draw rect for border spacing earlier + //normally, the bg of the dialog is sufficient, but in the case of ResizableDialog, it clips the anchored + //windows, which leaves unpainted area just inside our border + rect.DeflateRect(1, 1); + CMPCThemeUtil::drawParentDialogBGClr(this, &dc, rect, false); + + if (nullptr != buddy) { + buddy->Invalidate(); + } + } + + } else { + __super::OnNcPaint(); + } +} + +void CMPCThemeEdit::SetFixedWidthFont(CFont& f) +{ + if (AppIsThemeLoaded()) { + CWindowDC dc(this); + if (CMPCThemeUtil::getFixedFont(font, &dc, this)) { + SetFont(&font); + } else { + SetFont(&f); + } + } else { + SetFont(&f); + } +} + +BOOL CMPCThemeEdit::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + __super::OnMouseWheel(nFlags, zDelta, pt); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + ScreenToClient(&pt); + return TRUE; +} + +void CMPCThemeEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + __super::OnVScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + +void CMPCThemeEdit::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + __super::OnHScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + + +void CMPCThemeEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + __super::OnKeyDown(nChar, nRepCnt, nFlags); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} diff --git a/src/mpc-hc/CMPCThemeEdit.h b/src/mpc-hc/CMPCThemeEdit.h index 5b19b63b7c4..2c72cfbc8e2 100755 --- a/src/mpc-hc/CMPCThemeEdit.h +++ b/src/mpc-hc/CMPCThemeEdit.h @@ -1,39 +1,39 @@ -#pragma once -#include -#include "CMPCThemeScrollBarHelper.h" -#include - -class CMPCThemeEdit : public CEdit - , public CMPCThemeScrollable -{ -public: - DECLARE_DYNAMIC(CMPCThemeEdit) - CMPCThemeEdit(); - virtual ~CMPCThemeEdit(); - void PreSubclassWindow(); - void setBuddy(CWnd* buddyWindow) { this->buddy = buddyWindow; }; - void setFileDialogChild(bool set) { isFileDialogChild = set; }; - void SetFixedWidthFont(CFont& f); - bool IsScrollable(); -protected: - CWnd* buddy; - CMPCThemeScrollBarHelper* themedSBHelper; - CFont font; - bool isFileDialogChild; - void SetCompWindowPos(HIMC himc, UINT start); - - DECLARE_MESSAGE_MAP() - - afx_msg LRESULT ResizeSupport(WPARAM wParam, LPARAM lParam); - afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); - afx_msg void OnNcPaint(); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); -public: - afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); - afx_msg LRESULT OnContextMenu(WPARAM wParam, LPARAM lParam); - afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); -}; - - +#pragma once +#include +#include "CMPCThemeScrollBarHelper.h" +#include + +class CMPCThemeEdit : public CEdit + , public CMPCThemeScrollable +{ +public: + DECLARE_DYNAMIC(CMPCThemeEdit) + CMPCThemeEdit(); + virtual ~CMPCThemeEdit(); + void PreSubclassWindow(); + void setBuddy(CWnd* buddyWindow) { this->buddy = buddyWindow; }; + void setFileDialogChild(bool set) { isFileDialogChild = set; }; + void SetFixedWidthFont(CFont& f); + bool IsScrollable(); +protected: + CWnd* buddy; + CMPCThemeScrollBarHelper* themedSBHelper; + CFont font; + bool isFileDialogChild; + void SetCompWindowPos(HIMC himc, UINT start); + + DECLARE_MESSAGE_MAP() + + afx_msg LRESULT ResizeSupport(WPARAM wParam, LPARAM lParam); + afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); + afx_msg void OnNcPaint(); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); +public: + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg LRESULT OnContextMenu(WPARAM wParam, LPARAM lParam); + afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); +}; + + diff --git a/src/mpc-hc/CMPCThemeFrameUtil.cpp b/src/mpc-hc/CMPCThemeFrameUtil.cpp index 6818e0322b2..685379185b8 100644 --- a/src/mpc-hc/CMPCThemeFrameUtil.cpp +++ b/src/mpc-hc/CMPCThemeFrameUtil.cpp @@ -1,7 +1,7 @@ -#include "stdafx.h" -#include "CMPCThemeFrameUtil.h" - -CMPCThemeFrameUtil::CMPCThemeFrameUtil(CWnd* _self) -{ - self = _self; -} +#include "stdafx.h" +#include "CMPCThemeFrameUtil.h" + +CMPCThemeFrameUtil::CMPCThemeFrameUtil(CWnd* _self) +{ + self = _self; +} diff --git a/src/mpc-hc/CMPCThemeFrameUtil.h b/src/mpc-hc/CMPCThemeFrameUtil.h index 4b2aa15f13c..177a4b54a28 100644 --- a/src/mpc-hc/CMPCThemeFrameUtil.h +++ b/src/mpc-hc/CMPCThemeFrameUtil.h @@ -1,14 +1,14 @@ -#pragma once -#include "stdafx.h" -#include "CMPCTheme.h" -class CMPCThemeFrameUtil -{ - -public: - CWnd* self; - CMPCThemeFrameUtil(CWnd* self); - bool IsWindowForeground() { return self == self->GetActiveWindow(); }; - bool IsWindowZoomed() { return self->IsZoomed(); }; - BOOL PostWindowMessage(UINT Msg, WPARAM wParam, LPARAM lParam) { return self->PostMessage(Msg, wParam, lParam); }; -}; - +#pragma once +#include "stdafx.h" +#include "CMPCTheme.h" +class CMPCThemeFrameUtil +{ + +public: + CWnd* self; + CMPCThemeFrameUtil(CWnd* self); + bool IsWindowForeground() { return self == self->GetActiveWindow(); }; + bool IsWindowZoomed() { return self->IsZoomed(); }; + BOOL PostWindowMessage(UINT Msg, WPARAM wParam, LPARAM lParam) { return self->PostMessage(Msg, wParam, lParam); }; +}; + diff --git a/src/mpc-hc/CMPCThemeFrameWnd.cpp b/src/mpc-hc/CMPCThemeFrameWnd.cpp index 04b256dc5d1..9df3e3ff8cc 100644 --- a/src/mpc-hc/CMPCThemeFrameWnd.cpp +++ b/src/mpc-hc/CMPCThemeFrameWnd.cpp @@ -1,450 +1,450 @@ -//deprecated in favor of setWindowCompositionAttribute--undocumented Windows 10 API - -#include "stdafx.h" -#include "VersionHelpersInternal.h" -#include "CMPCThemeFrameWnd.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#include "SVGImage.h" -#include -#include <../src/mfc/oleimpl2.h> - -IMPLEMENT_DYNAMIC(CMPCThemeFrameWnd, CFrameWnd) - -BEGIN_MESSAGE_MAP(CMPCThemeFrameWnd, CFrameWnd) - ON_WM_CREATE() - ON_WM_ACTIVATE() - ON_WM_PAINT() - ON_WM_NCCALCSIZE() - ON_WM_SHOWWINDOW() - ON_WM_NCHITTEST() - ON_WM_NCMOUSELEAVE() -END_MESSAGE_MAP() - -CMPCThemeFrameWnd::CMPCThemeFrameWnd(): - CMPCThemeFrameUtil(this), - minimizeButton(SC_MINIMIZE), - maximizeButton(SC_MAXIMIZE), - closeButton(SC_CLOSE), - currentFrameState(frameNormal), - titleBarInfo( -{ - 0 -}), -drawCustomFrame(false), -titlebarHeight(30) //sane default, should be updated as soon as created -{ -} - -CMPCThemeFrameWnd::~CMPCThemeFrameWnd() -{ - if (closeButton.m_hWnd) { - closeButton.DestroyWindow(); - } - if (minimizeButton.m_hWnd) { - minimizeButton.DestroyWindow(); - } - if (maximizeButton.m_hWnd) { - maximizeButton.DestroyWindow(); - } -} - -LRESULT CMPCThemeFrameWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (drawCustomFrame) { - if (uMsg == WM_WINDOWPOSCHANGING && - (WS_THICKFRAME) == (GetStyle() & (WS_THICKFRAME | WS_CAPTION)) && - currentFrameState != frameThemedTopBorder) { - WINDOWPOS* wp = (WINDOWPOS*)lParam; - if (nullptr != wp) { - wp->flags |= SWP_NOREDRAW; //prevents corruption of the border when disabling caption - } - } - } - return __super::WindowProc(uMsg, wParam, lParam); -} - -void CMPCThemeFrameWnd::RecalcLayout(BOOL bNotify) -{ - if (drawCustomFrame) { - recalcTitleBar(); - int clientTop = 0; - if (currentFrameState == frameThemedCaption) { - CRect titleBarRect = getTitleBarRect(); - clientTop = titleBarRect.bottom; - if (GetMenuBarState() == AFX_MBS_VISIBLE) { - clientTop += GetSystemMetrics(SM_CYMENU); - } - - CRect sysMenuIconRect = getSysMenuIconRect(); - CRect closeRect, maximizeRect, minimizeRect; - GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); - - if (IsWindow(closeButton.m_hWnd)) { - closeButton.MoveWindow(closeRect, TRUE); - closeButton.ShowWindow(SW_SHOW); - } - if (IsWindow(minimizeButton.m_hWnd)) { - minimizeButton.MoveWindow(minimizeRect, TRUE); - minimizeButton.ShowWindow(SW_SHOW); - } - if (IsWindow(maximizeButton.m_hWnd)) { - maximizeButton.MoveWindow(maximizeRect, TRUE); - maximizeButton.ShowWindow(SW_SHOW); - } - } else { - m_rectBorder.top = borders.top; - if (IsWindow(closeButton.m_hWnd)) { - closeButton.ShowWindow(SW_HIDE); - } - if (IsWindow(minimizeButton.m_hWnd)) { - minimizeButton.ShowWindow(SW_HIDE); - } - if (IsWindow(maximizeButton.m_hWnd)) { - maximizeButton.ShowWindow(SW_HIDE); - } - } - - //begin standard CFrameWnd::RecalcLayout code - if (m_bInRecalcLayout) { - return; - } - - m_bInRecalcLayout = TRUE; - // clear idle flags for recalc layout if called elsewhere - if (m_nIdleFlags & idleNotify) { - bNotify = TRUE; - } - m_nIdleFlags &= ~(idleLayout | idleNotify); - - // call the layout hook -- OLE support uses this hook - if (bNotify && m_pNotifyHook != NULL) { - m_pNotifyHook->OnRecalcLayout(); - } - - // reposition all the child windows (regardless of ID) - if (GetStyle() & FWS_SNAPTOBARS) { - CRect rect(0, 0, 32767, 32767); - RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, - &rect, &rect, FALSE); - RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, - &m_rectBorder, &rect, TRUE); - CalcWindowRect(&rect); - SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); - } else { - //begin mpc-hc code to to position inside virtual client rect - CRect cr; - GetClientRect(cr); - cr.top = clientTop; - //end mpc-hc code to to position inside virtual client rect - RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder, &cr /* mpc-hc, pass virtual client rect */); - } - m_bInRecalcLayout = FALSE; - //end CFrameWnd::RecalcLayout code - - - Invalidate(TRUE); - RedrawWindow(); - } else { - __super::RecalcLayout(bNotify); - } -} - -void CMPCThemeFrameWnd::SetMenuBarVisibility(DWORD dwStyle) -{ - __super::SetMenuBarVisibility(dwStyle); - if (currentFrameState == frameThemedCaption && 0 != (dwStyle & AFX_MBS_VISIBLE)) { - Invalidate(); - DrawMenuBar(); - } -} - -BOOL CMPCThemeFrameWnd::SetMenuBarState(DWORD dwState) -{ - BOOL ret = __super::SetMenuBarState(dwState); - if (ret && currentFrameState == frameThemedCaption) { - RecalcLayout(); - DrawMenuBar(); - } - return ret; -} - -CRect CMPCThemeFrameWnd::getTitleBarRect() -{ - CRect cr; - GetClientRect(cr); - CRect wr; - GetClientRect(wr); - - if (IsZoomed()) { - cr.top += borders.top + 1; //invisible area when maximized - cr.bottom = cr.top + titlebarHeight; - } else { - cr.top += 1; //border - cr.bottom = cr.top + titlebarHeight; - } - return cr; -} - -CRect CMPCThemeFrameWnd::getSysMenuIconRect() -{ - CRect sysMenuIconRect, cr; - cr = getTitleBarRect(); - - DpiHelper dpiWindow; - dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); - int iconsize = MulDiv(dpiWindow.DPIX(), 1, 6); - sysMenuIconRect.top = cr.top + (cr.Height() - iconsize) / 2 + 1; - sysMenuIconRect.bottom = sysMenuIconRect.top + iconsize; - sysMenuIconRect.left = (dpiWindow.ScaleX(30) - iconsize) / 2 + 1; - sysMenuIconRect.right = sysMenuIconRect.left + iconsize; - return sysMenuIconRect; -} - -bool CMPCThemeFrameWnd::checkFrame(LONG style) -{ - frameState oldState = currentFrameState; - currentFrameState = frameNormal; - if (drawCustomFrame) { - if ((WS_THICKFRAME | WS_CAPTION) == (style & (WS_THICKFRAME | WS_CAPTION))) { - currentFrameState = frameThemedCaption; - } else if ((WS_THICKFRAME) == (style & (WS_THICKFRAME | WS_CAPTION))) { - currentFrameState = frameThemedTopBorder; - } - } - return (oldState == currentFrameState); -} - -int CMPCThemeFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (drawCustomFrame) { - int res = CWnd::OnCreate(lpCreateStruct); - - if (res == -1) { - return -1; - } - - RECT r = { 0, 0, 0, 0 }; - - closeButton.Create(_T("Close Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1001); - closeButton.setParentFrame(this); - - minimizeButton.Create(_T("Minimize Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1002); - minimizeButton.setParentFrame(this); - - maximizeButton.Create(_T("Maximize Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1003); - maximizeButton.setParentFrame(this); - - return res; - } else { - return __super::OnCreate(lpCreateStruct); - } -} - -void CMPCThemeFrameWnd::GetIconRects(CRect titlebarRect, CRect& closeRect, CRect& maximizeRect, CRect& minimizeRect) -{ - DpiHelper dpi; - dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); - - int closeRightX; - if (IsZoomed()) { - closeRightX = titlebarRect.right - 2; - } else { - closeRightX = titlebarRect.right; - } - - int iconHeight; - if (IsZoomed()) { //works at 96dpi, 120dpi, 144dpi, 168dpi, 192dpi - iconHeight = titlebarRect.Height() - 2; - } else { - iconHeight = titlebarRect.Height() - 1; - } - int buttonWidth = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarButtonWidth); - int buttonSpacing = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarButtonSpacing); - CRect buttonDimRect(0, 0, buttonWidth, iconHeight); - closeRect = CRect(closeRightX - buttonDimRect.Width(), titlebarRect.top, closeRightX, titlebarRect.top + buttonDimRect.Height()); - maximizeRect = CRect(closeRect.left - buttonSpacing - buttonDimRect.Width(), titlebarRect.top, closeRect.left - buttonSpacing, titlebarRect.top + buttonDimRect.Height()); - minimizeRect = CRect(maximizeRect.left - buttonSpacing - buttonDimRect.Width(), titlebarRect.top, maximizeRect.left - buttonSpacing, titlebarRect.top + buttonDimRect.Height()); -} - -void CMPCThemeFrameWnd::OnPaint() -{ - if (currentFrameState != frameNormal) { - CRect closeRect, maximizeRect, minimizeRect; - CRect titleBarRect = getTitleBarRect(); - GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); - - CPaintDC dc(this); - - CDC dcMem; - CBitmap bmMem; - CRect memRect = { 0, 0, titleBarRect.right, titleBarRect.bottom }; - CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, memRect); - - CRect topBorderRect = { titleBarRect.left, titleBarRect.top - 1, titleBarRect.right, titleBarRect.top }; - dcMem.FillSolidRect(topBorderRect, CMPCTheme::W10DarkThemeWindowBorderColor); - - COLORREF titleBarColor; - if (IsWindowForeground()) { - titleBarColor = CMPCTheme::W10DarkThemeTitlebarBGColor; - } else { - titleBarColor = CMPCTheme::W10DarkThemeTitlebarInactiveBGColor; - } - - - dcMem.FillSolidRect(titleBarRect, titleBarColor); - - if (currentFrameState == frameThemedCaption) { - - CFont f; - CMPCThemeUtil::getFontByType(f, this, CMPCThemeUtil::CaptionFont); - dcMem.SelectObject(f); - - CRect captionRect = titleBarRect; - DpiHelper dpi; - dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); - - CRect sysMenuIconRect = getSysMenuIconRect(); - int sysIconDim = sysMenuIconRect.Width(); - - captionRect.left += sysMenuIconRect.right + dpi.ScaleX(4); - captionRect.right = minimizeRect.left - dpi.ScaleX(4); - - CFont font; - CMPCThemeUtil::getFontByType(font, this, CMPCThemeUtil::CaptionFont); - dcMem.SetBkColor(titleBarColor); - dcMem.SetTextColor(CMPCTheme::W10DarkThemeTitlebarFGColor); - CString windowText; - GetWindowText(windowText); - dcMem.DrawTextW(windowText, captionRect, DT_LEFT | DT_WORD_ELLIPSIS | DT_VCENTER | DT_SINGLELINE); - - HICON icon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(m_nIDHelp), IMAGE_ICON, sysIconDim, sysIconDim, LR_SHARED); - ::DrawIconEx(dcMem.m_hDC, sysMenuIconRect.left, sysMenuIconRect.top, icon, 0, 0, 0, nullptr, DI_NORMAL); - } - - CMPCThemeUtil::flushMemDC(&dc, dcMem, memRect); - - if (m_pCtrlCont != NULL) { - m_pCtrlCont->OnPaint(&dc); - } - Default(); - } else { - Default(); - } - -} - -void CMPCThemeFrameWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) -{ - if (AppIsThemeLoaded() && IsWindows10OrGreater() && !AfxGetAppSettings().bWindows10AccentColorsEnabled) { - drawCustomFrame = true; - } else { - drawCustomFrame = false; - } - - if (drawCustomFrame) { - if (currentFrameState != frameNormal) { - if (bCalcValidRects) { - if (currentFrameState == frameThemedCaption) { - lpncsp->rgrc[0].left += borders.left + 1; - lpncsp->rgrc[0].right -= borders.right + 1; - lpncsp->rgrc[0].bottom -= borders.bottom + 1; - } else { - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - lpncsp->rgrc[0].top -= 6; - } - } else { - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - } - } else { - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - } - recalcFrame(); //framechanged--if necessary we recalculate everything; if done internally this should be a no-op - } else { - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - } -} - -void CMPCThemeFrameWnd::recalcFrame() -{ - if (!checkFrame(GetStyle())) { - borders = { 0, 0, 0, 0 }; - UINT style = GetStyle(); - if (0 != (style & WS_THICKFRAME)) { - AdjustWindowRectEx(&borders, style & ~WS_CAPTION, FALSE, NULL); - borders.left = abs(borders.left); - borders.top = abs(borders.top); - } else if (0 != (style & WS_BORDER)) { - borders = { 1, 1, 1, 1 }; - } - SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); - } -} - -void CMPCThemeFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) -{ - if (drawCustomFrame) { - if (titleBarInfo.cbSize == 0) { //only check this once, as it can be wrong later - titleBarInfo = { sizeof(TITLEBARINFO) }; - GetTitleBarInfo(&titleBarInfo); - } - recalcFrame(); - CWnd::OnActivate(nState, pWndOther, bMinimized); - Invalidate(TRUE); - } else { - __super::OnActivate(nState, pWndOther, bMinimized); - } -} - -LRESULT CMPCThemeFrameWnd::OnNcHitTest(CPoint point) -{ - if (currentFrameState == frameThemedCaption) { - LRESULT result = 0; - - result = CWnd::OnNcHitTest(point); - if (result == HTCLIENT) { - ScreenToClient(&point); - if (point.y < borders.top) { - return HTTOP; - } else if (point.y < titlebarHeight) { - CRect sysMenuIconRect = getSysMenuIconRect(); - CRect closeRect, maximizeRect, minimizeRect; - CRect titleBarRect = getTitleBarRect(); - GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); - - if (sysMenuIconRect.PtInRect(point)) { - return HTSYSMENU; - } else if (closeRect.PtInRect(point) || minimizeRect.PtInRect(point) || maximizeRect.PtInRect(point)) { - return HTNOWHERE; - } else { - return HTCAPTION; - } - } else if (point.y < titlebarHeight + GetSystemMetrics(SM_CYMENU)) { - return HTMENU; - } - } - return result; - } else { - return __super::OnNcHitTest(point); - } -} - -void CMPCThemeFrameWnd::OnNcMouseLeave() -{ - if (currentFrameState == frameThemedCaption) { - CWnd::OnNcMouseLeave(); - } else { - __super::OnNcMouseLeave(); - } -} - -void CMPCThemeFrameWnd::recalcTitleBar() -{ - titlebarHeight = CRect(titleBarInfo.rcTitleBar).Height() + borders.top; - if (IsZoomed()) { - titlebarHeight -= borders.top; - } -} - +//deprecated in favor of setWindowCompositionAttribute--undocumented Windows 10 API + +#include "stdafx.h" +#include "VersionHelpersInternal.h" +#include "CMPCThemeFrameWnd.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#include "SVGImage.h" +#include +#include <../src/mfc/oleimpl2.h> + +IMPLEMENT_DYNAMIC(CMPCThemeFrameWnd, CFrameWnd) + +BEGIN_MESSAGE_MAP(CMPCThemeFrameWnd, CFrameWnd) + ON_WM_CREATE() + ON_WM_ACTIVATE() + ON_WM_PAINT() + ON_WM_NCCALCSIZE() + ON_WM_SHOWWINDOW() + ON_WM_NCHITTEST() + ON_WM_NCMOUSELEAVE() +END_MESSAGE_MAP() + +CMPCThemeFrameWnd::CMPCThemeFrameWnd(): + CMPCThemeFrameUtil(this), + minimizeButton(SC_MINIMIZE), + maximizeButton(SC_MAXIMIZE), + closeButton(SC_CLOSE), + currentFrameState(frameNormal), + titleBarInfo( +{ + 0 +}), +drawCustomFrame(false), +titlebarHeight(30) //sane default, should be updated as soon as created +{ +} + +CMPCThemeFrameWnd::~CMPCThemeFrameWnd() +{ + if (closeButton.m_hWnd) { + closeButton.DestroyWindow(); + } + if (minimizeButton.m_hWnd) { + minimizeButton.DestroyWindow(); + } + if (maximizeButton.m_hWnd) { + maximizeButton.DestroyWindow(); + } +} + +LRESULT CMPCThemeFrameWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (drawCustomFrame) { + if (uMsg == WM_WINDOWPOSCHANGING && + (WS_THICKFRAME) == (GetStyle() & (WS_THICKFRAME | WS_CAPTION)) && + currentFrameState != frameThemedTopBorder) { + WINDOWPOS* wp = (WINDOWPOS*)lParam; + if (nullptr != wp) { + wp->flags |= SWP_NOREDRAW; //prevents corruption of the border when disabling caption + } + } + } + return __super::WindowProc(uMsg, wParam, lParam); +} + +void CMPCThemeFrameWnd::RecalcLayout(BOOL bNotify) +{ + if (drawCustomFrame) { + recalcTitleBar(); + int clientTop = 0; + if (currentFrameState == frameThemedCaption) { + CRect titleBarRect = getTitleBarRect(); + clientTop = titleBarRect.bottom; + if (GetMenuBarState() == AFX_MBS_VISIBLE) { + clientTop += GetSystemMetrics(SM_CYMENU); + } + + CRect sysMenuIconRect = getSysMenuIconRect(); + CRect closeRect, maximizeRect, minimizeRect; + GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); + + if (IsWindow(closeButton.m_hWnd)) { + closeButton.MoveWindow(closeRect, TRUE); + closeButton.ShowWindow(SW_SHOW); + } + if (IsWindow(minimizeButton.m_hWnd)) { + minimizeButton.MoveWindow(minimizeRect, TRUE); + minimizeButton.ShowWindow(SW_SHOW); + } + if (IsWindow(maximizeButton.m_hWnd)) { + maximizeButton.MoveWindow(maximizeRect, TRUE); + maximizeButton.ShowWindow(SW_SHOW); + } + } else { + m_rectBorder.top = borders.top; + if (IsWindow(closeButton.m_hWnd)) { + closeButton.ShowWindow(SW_HIDE); + } + if (IsWindow(minimizeButton.m_hWnd)) { + minimizeButton.ShowWindow(SW_HIDE); + } + if (IsWindow(maximizeButton.m_hWnd)) { + maximizeButton.ShowWindow(SW_HIDE); + } + } + + //begin standard CFrameWnd::RecalcLayout code + if (m_bInRecalcLayout) { + return; + } + + m_bInRecalcLayout = TRUE; + // clear idle flags for recalc layout if called elsewhere + if (m_nIdleFlags & idleNotify) { + bNotify = TRUE; + } + m_nIdleFlags &= ~(idleLayout | idleNotify); + + // call the layout hook -- OLE support uses this hook + if (bNotify && m_pNotifyHook != NULL) { + m_pNotifyHook->OnRecalcLayout(); + } + + // reposition all the child windows (regardless of ID) + if (GetStyle() & FWS_SNAPTOBARS) { + CRect rect(0, 0, 32767, 32767); + RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, + &rect, &rect, FALSE); + RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, + &m_rectBorder, &rect, TRUE); + CalcWindowRect(&rect); + SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); + } else { + //begin mpc-hc code to to position inside virtual client rect + CRect cr; + GetClientRect(cr); + cr.top = clientTop; + //end mpc-hc code to to position inside virtual client rect + RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder, &cr /* mpc-hc, pass virtual client rect */); + } + m_bInRecalcLayout = FALSE; + //end CFrameWnd::RecalcLayout code + + + Invalidate(TRUE); + RedrawWindow(); + } else { + __super::RecalcLayout(bNotify); + } +} + +void CMPCThemeFrameWnd::SetMenuBarVisibility(DWORD dwStyle) +{ + __super::SetMenuBarVisibility(dwStyle); + if (currentFrameState == frameThemedCaption && 0 != (dwStyle & AFX_MBS_VISIBLE)) { + Invalidate(); + DrawMenuBar(); + } +} + +BOOL CMPCThemeFrameWnd::SetMenuBarState(DWORD dwState) +{ + BOOL ret = __super::SetMenuBarState(dwState); + if (ret && currentFrameState == frameThemedCaption) { + RecalcLayout(); + DrawMenuBar(); + } + return ret; +} + +CRect CMPCThemeFrameWnd::getTitleBarRect() +{ + CRect cr; + GetClientRect(cr); + CRect wr; + GetClientRect(wr); + + if (IsZoomed()) { + cr.top += borders.top + 1; //invisible area when maximized + cr.bottom = cr.top + titlebarHeight; + } else { + cr.top += 1; //border + cr.bottom = cr.top + titlebarHeight; + } + return cr; +} + +CRect CMPCThemeFrameWnd::getSysMenuIconRect() +{ + CRect sysMenuIconRect, cr; + cr = getTitleBarRect(); + + DpiHelper dpiWindow; + dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); + int iconsize = MulDiv(dpiWindow.DPIX(), 1, 6); + sysMenuIconRect.top = cr.top + (cr.Height() - iconsize) / 2 + 1; + sysMenuIconRect.bottom = sysMenuIconRect.top + iconsize; + sysMenuIconRect.left = (dpiWindow.ScaleX(30) - iconsize) / 2 + 1; + sysMenuIconRect.right = sysMenuIconRect.left + iconsize; + return sysMenuIconRect; +} + +bool CMPCThemeFrameWnd::checkFrame(LONG style) +{ + frameState oldState = currentFrameState; + currentFrameState = frameNormal; + if (drawCustomFrame) { + if ((WS_THICKFRAME | WS_CAPTION) == (style & (WS_THICKFRAME | WS_CAPTION))) { + currentFrameState = frameThemedCaption; + } else if ((WS_THICKFRAME) == (style & (WS_THICKFRAME | WS_CAPTION))) { + currentFrameState = frameThemedTopBorder; + } + } + return (oldState == currentFrameState); +} + +int CMPCThemeFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (drawCustomFrame) { + int res = CWnd::OnCreate(lpCreateStruct); + + if (res == -1) { + return -1; + } + + RECT r = { 0, 0, 0, 0 }; + + closeButton.Create(_T("Close Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1001); + closeButton.setParentFrame(this); + + minimizeButton.Create(_T("Minimize Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1002); + minimizeButton.setParentFrame(this); + + maximizeButton.Create(_T("Maximize Button"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, r, this, 1003); + maximizeButton.setParentFrame(this); + + return res; + } else { + return __super::OnCreate(lpCreateStruct); + } +} + +void CMPCThemeFrameWnd::GetIconRects(CRect titlebarRect, CRect& closeRect, CRect& maximizeRect, CRect& minimizeRect) +{ + DpiHelper dpi; + dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); + + int closeRightX; + if (IsZoomed()) { + closeRightX = titlebarRect.right - 2; + } else { + closeRightX = titlebarRect.right; + } + + int iconHeight; + if (IsZoomed()) { //works at 96dpi, 120dpi, 144dpi, 168dpi, 192dpi + iconHeight = titlebarRect.Height() - 2; + } else { + iconHeight = titlebarRect.Height() - 1; + } + int buttonWidth = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarButtonWidth); + int buttonSpacing = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarButtonSpacing); + CRect buttonDimRect(0, 0, buttonWidth, iconHeight); + closeRect = CRect(closeRightX - buttonDimRect.Width(), titlebarRect.top, closeRightX, titlebarRect.top + buttonDimRect.Height()); + maximizeRect = CRect(closeRect.left - buttonSpacing - buttonDimRect.Width(), titlebarRect.top, closeRect.left - buttonSpacing, titlebarRect.top + buttonDimRect.Height()); + minimizeRect = CRect(maximizeRect.left - buttonSpacing - buttonDimRect.Width(), titlebarRect.top, maximizeRect.left - buttonSpacing, titlebarRect.top + buttonDimRect.Height()); +} + +void CMPCThemeFrameWnd::OnPaint() +{ + if (currentFrameState != frameNormal) { + CRect closeRect, maximizeRect, minimizeRect; + CRect titleBarRect = getTitleBarRect(); + GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); + + CPaintDC dc(this); + + CDC dcMem; + CBitmap bmMem; + CRect memRect = { 0, 0, titleBarRect.right, titleBarRect.bottom }; + CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, memRect); + + CRect topBorderRect = { titleBarRect.left, titleBarRect.top - 1, titleBarRect.right, titleBarRect.top }; + dcMem.FillSolidRect(topBorderRect, CMPCTheme::W10DarkThemeWindowBorderColor); + + COLORREF titleBarColor; + if (IsWindowForeground()) { + titleBarColor = CMPCTheme::W10DarkThemeTitlebarBGColor; + } else { + titleBarColor = CMPCTheme::W10DarkThemeTitlebarInactiveBGColor; + } + + + dcMem.FillSolidRect(titleBarRect, titleBarColor); + + if (currentFrameState == frameThemedCaption) { + + CFont f; + CMPCThemeUtil::getFontByType(f, this, CMPCThemeUtil::CaptionFont); + dcMem.SelectObject(f); + + CRect captionRect = titleBarRect; + DpiHelper dpi; + dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); + + CRect sysMenuIconRect = getSysMenuIconRect(); + int sysIconDim = sysMenuIconRect.Width(); + + captionRect.left += sysMenuIconRect.right + dpi.ScaleX(4); + captionRect.right = minimizeRect.left - dpi.ScaleX(4); + + CFont font; + CMPCThemeUtil::getFontByType(font, this, CMPCThemeUtil::CaptionFont); + dcMem.SetBkColor(titleBarColor); + dcMem.SetTextColor(CMPCTheme::W10DarkThemeTitlebarFGColor); + CString windowText; + GetWindowText(windowText); + dcMem.DrawTextW(windowText, captionRect, DT_LEFT | DT_WORD_ELLIPSIS | DT_VCENTER | DT_SINGLELINE); + + HICON icon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(m_nIDHelp), IMAGE_ICON, sysIconDim, sysIconDim, LR_SHARED); + ::DrawIconEx(dcMem.m_hDC, sysMenuIconRect.left, sysMenuIconRect.top, icon, 0, 0, 0, nullptr, DI_NORMAL); + } + + CMPCThemeUtil::flushMemDC(&dc, dcMem, memRect); + + if (m_pCtrlCont != NULL) { + m_pCtrlCont->OnPaint(&dc); + } + Default(); + } else { + Default(); + } + +} + +void CMPCThemeFrameWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) +{ + if (AppIsThemeLoaded() && IsWindows10OrGreater() && !AfxGetAppSettings().bWindows10AccentColorsEnabled) { + drawCustomFrame = true; + } else { + drawCustomFrame = false; + } + + if (drawCustomFrame) { + if (currentFrameState != frameNormal) { + if (bCalcValidRects) { + if (currentFrameState == frameThemedCaption) { + lpncsp->rgrc[0].left += borders.left + 1; + lpncsp->rgrc[0].right -= borders.right + 1; + lpncsp->rgrc[0].bottom -= borders.bottom + 1; + } else { + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + lpncsp->rgrc[0].top -= 6; + } + } else { + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + } + } else { + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + } + recalcFrame(); //framechanged--if necessary we recalculate everything; if done internally this should be a no-op + } else { + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + } +} + +void CMPCThemeFrameWnd::recalcFrame() +{ + if (!checkFrame(GetStyle())) { + borders = { 0, 0, 0, 0 }; + UINT style = GetStyle(); + if (0 != (style & WS_THICKFRAME)) { + AdjustWindowRectEx(&borders, style & ~WS_CAPTION, FALSE, NULL); + borders.left = abs(borders.left); + borders.top = abs(borders.top); + } else if (0 != (style & WS_BORDER)) { + borders = { 1, 1, 1, 1 }; + } + SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + } +} + +void CMPCThemeFrameWnd::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) +{ + if (drawCustomFrame) { + if (titleBarInfo.cbSize == 0) { //only check this once, as it can be wrong later + titleBarInfo = { sizeof(TITLEBARINFO) }; + GetTitleBarInfo(&titleBarInfo); + } + recalcFrame(); + CWnd::OnActivate(nState, pWndOther, bMinimized); + Invalidate(TRUE); + } else { + __super::OnActivate(nState, pWndOther, bMinimized); + } +} + +LRESULT CMPCThemeFrameWnd::OnNcHitTest(CPoint point) +{ + if (currentFrameState == frameThemedCaption) { + LRESULT result = 0; + + result = CWnd::OnNcHitTest(point); + if (result == HTCLIENT) { + ScreenToClient(&point); + if (point.y < borders.top) { + return HTTOP; + } else if (point.y < titlebarHeight) { + CRect sysMenuIconRect = getSysMenuIconRect(); + CRect closeRect, maximizeRect, minimizeRect; + CRect titleBarRect = getTitleBarRect(); + GetIconRects(titleBarRect, closeRect, maximizeRect, minimizeRect); + + if (sysMenuIconRect.PtInRect(point)) { + return HTSYSMENU; + } else if (closeRect.PtInRect(point) || minimizeRect.PtInRect(point) || maximizeRect.PtInRect(point)) { + return HTNOWHERE; + } else { + return HTCAPTION; + } + } else if (point.y < titlebarHeight + GetSystemMetrics(SM_CYMENU)) { + return HTMENU; + } + } + return result; + } else { + return __super::OnNcHitTest(point); + } +} + +void CMPCThemeFrameWnd::OnNcMouseLeave() +{ + if (currentFrameState == frameThemedCaption) { + CWnd::OnNcMouseLeave(); + } else { + __super::OnNcMouseLeave(); + } +} + +void CMPCThemeFrameWnd::recalcTitleBar() +{ + titlebarHeight = CRect(titleBarInfo.rcTitleBar).Height() + borders.top; + if (IsZoomed()) { + titlebarHeight -= borders.top; + } +} + diff --git a/src/mpc-hc/CMPCThemeFrameWnd.h b/src/mpc-hc/CMPCThemeFrameWnd.h index e6a47a44acc..ebe50a48747 100644 --- a/src/mpc-hc/CMPCThemeFrameWnd.h +++ b/src/mpc-hc/CMPCThemeFrameWnd.h @@ -1,49 +1,49 @@ -#pragma once -#include -#include "CMPCTheme.h" -#include "CMPCThemeFrameUtil.h" -#include "CMPCThemeTitleBarControlButton.h" - -class CMPCThemeFrameWnd : - public CFrameWnd, - public CMPCThemeFrameUtil -{ -public: - CMPCThemeFrameWnd(); -protected: - DECLARE_DYNAMIC(CMPCThemeFrameWnd) -public: - virtual ~CMPCThemeFrameWnd(); - LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); - virtual void RecalcLayout(BOOL bNotify = TRUE); - virtual void SetMenuBarVisibility(DWORD dwStyle); - BOOL SetMenuBarState(DWORD dwState); - CRect getTitleBarRect(); - CRect getSysMenuIconRect(); -protected: - CRect borders; - int titlebarHeight; - void recalcTitleBar(); - CMPCThemeTitleBarControlButton minimizeButton, maximizeButton, closeButton; - void GetIconRects(CRect titlebarRect, CRect& closeRect, CRect& maximizeRect, CRect& minimizeRect); - bool checkFrame(LONG style); - void recalcFrame(); - enum frameState { - frameNormal, - frameThemedCaption, - frameThemedTopBorder, - }; -private: - TITLEBARINFO titleBarInfo; - frameState currentFrameState; - bool drawCustomFrame; -public: - DECLARE_MESSAGE_MAP() - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); - afx_msg void OnPaint(); - afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg void OnNcMouseLeave(); -}; - +#pragma once +#include +#include "CMPCTheme.h" +#include "CMPCThemeFrameUtil.h" +#include "CMPCThemeTitleBarControlButton.h" + +class CMPCThemeFrameWnd : + public CFrameWnd, + public CMPCThemeFrameUtil +{ +public: + CMPCThemeFrameWnd(); +protected: + DECLARE_DYNAMIC(CMPCThemeFrameWnd) +public: + virtual ~CMPCThemeFrameWnd(); + LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam); + virtual void RecalcLayout(BOOL bNotify = TRUE); + virtual void SetMenuBarVisibility(DWORD dwStyle); + BOOL SetMenuBarState(DWORD dwState); + CRect getTitleBarRect(); + CRect getSysMenuIconRect(); +protected: + CRect borders; + int titlebarHeight; + void recalcTitleBar(); + CMPCThemeTitleBarControlButton minimizeButton, maximizeButton, closeButton; + void GetIconRects(CRect titlebarRect, CRect& closeRect, CRect& maximizeRect, CRect& minimizeRect); + bool checkFrame(LONG style); + void recalcFrame(); + enum frameState { + frameNormal, + frameThemedCaption, + frameThemedTopBorder, + }; +private: + TITLEBARINFO titleBarInfo; + frameState currentFrameState; + bool drawCustomFrame; +public: + DECLARE_MESSAGE_MAP() + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); + afx_msg void OnPaint(); + afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg void OnNcMouseLeave(); +}; + diff --git a/src/mpc-hc/CMPCThemeGroupBox.cpp b/src/mpc-hc/CMPCThemeGroupBox.cpp index b8f58744eb5..60af3e65c99 100644 --- a/src/mpc-hc/CMPCThemeGroupBox.cpp +++ b/src/mpc-hc/CMPCThemeGroupBox.cpp @@ -1,106 +1,106 @@ -#include "stdafx.h" -#include "CMPCThemeGroupBox.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -IMPLEMENT_DYNAMIC(CMPCThemeGroupBox, CStatic) - -CMPCThemeGroupBox::CMPCThemeGroupBox() - :manuallySetFont(nullptr) -{ - -} - - -CMPCThemeGroupBox::~CMPCThemeGroupBox() -{ -} - -BEGIN_MESSAGE_MAP(CMPCThemeGroupBox, CStatic) - ON_WM_PAINT() - ON_WM_ENABLE() - ON_MESSAGE(WM_SETFONT, OnSetFont) - ON_MESSAGE(WM_GETFONT, OnGetFont) -END_MESSAGE_MAP() - - -void CMPCThemeGroupBox::OnPaint() -{ - if (AppNeedsThemedControls()) { - - CPaintDC dc(this); - - CRect r, rborder, rtext; - GetClientRect(r); - HDC hDC = ::GetDC(NULL); - CString text; - GetWindowText(text); - - CFont* font = GetFont(); - - CSize cs = CMPCThemeUtil::GetTextSize(_T("W"), hDC, font); - ::ReleaseDC(NULL, hDC); - - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::GroupBoxBorderColor); - rborder = r; - rborder.top += cs.cy / 2; - dc.FrameRect(rborder, &fb); - - if (!text.IsEmpty()) { - COLORREF oldClr; - //see https://stackoverflow.com/questions/26481189/how-to-make-the-group-box-text-to-be-disabled-when-group-box-is-disabled - //even if common controls doesn't always honor disabled group boxes, we can in the themed version - if (IsWindowEnabled()) { - oldClr = dc.SetTextColor(CMPCTheme::TextFGColor); - } else { - oldClr = dc.SetTextColor(CMPCTheme::ContentTextDisabledFGColorFade); - } - COLORREF oldBkClr = dc.SetBkColor(CMPCTheme::WindowBGColor); - CFont* pOldFont = dc.SelectObject(font); - - rtext = r; - rtext.left += CMPCTheme::GroupBoxTextIndent; - - text += _T(" "); //seems to be the default behavior - dc.DrawTextW(text, rtext, DT_TOP | DT_LEFT | DT_SINGLELINE | DT_EDITCONTROL); // DT_NOPREFIX not needed - - dc.SelectObject(pOldFont); - dc.SetTextColor(oldClr); - dc.SetBkColor(oldBkClr); - } - fb.DeleteObject(); - ::ReleaseDC(NULL, hDC); - } else { - __super::OnPaint(); - } -} - -void CMPCThemeGroupBox::OnEnable(BOOL bEnable) { - if (AppNeedsThemedControls()) { - SetRedraw(FALSE); - __super::OnEnable(bEnable); - SetRedraw(TRUE); - Invalidate(); //WM_PAINT not handled when enabling/disabling - RedrawWindow(); - } else { - __super::OnEnable(bEnable); - } -} - -LRESULT CMPCThemeGroupBox::OnSetFont(WPARAM wParam, LPARAM lParam) { - manuallySetFont = (HFONT)wParam; - if ((BOOL)lParam) { - Invalidate(); - } - return 0; -} - -LRESULT CMPCThemeGroupBox::OnGetFont(WPARAM wParam, LPARAM lParam) { - if (manuallySetFont) { - return (LRESULT)manuallySetFont; - } else { - return (LRESULT)Default(); - } -} +#include "stdafx.h" +#include "CMPCThemeGroupBox.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +IMPLEMENT_DYNAMIC(CMPCThemeGroupBox, CStatic) + +CMPCThemeGroupBox::CMPCThemeGroupBox() + :manuallySetFont(nullptr) +{ + +} + + +CMPCThemeGroupBox::~CMPCThemeGroupBox() +{ +} + +BEGIN_MESSAGE_MAP(CMPCThemeGroupBox, CStatic) + ON_WM_PAINT() + ON_WM_ENABLE() + ON_MESSAGE(WM_SETFONT, OnSetFont) + ON_MESSAGE(WM_GETFONT, OnGetFont) +END_MESSAGE_MAP() + + +void CMPCThemeGroupBox::OnPaint() +{ + if (AppNeedsThemedControls()) { + + CPaintDC dc(this); + + CRect r, rborder, rtext; + GetClientRect(r); + HDC hDC = ::GetDC(NULL); + CString text; + GetWindowText(text); + + CFont* font = GetFont(); + + CSize cs = CMPCThemeUtil::GetTextSize(_T("W"), hDC, font); + ::ReleaseDC(NULL, hDC); + + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::GroupBoxBorderColor); + rborder = r; + rborder.top += cs.cy / 2; + dc.FrameRect(rborder, &fb); + + if (!text.IsEmpty()) { + COLORREF oldClr; + //see https://stackoverflow.com/questions/26481189/how-to-make-the-group-box-text-to-be-disabled-when-group-box-is-disabled + //even if common controls doesn't always honor disabled group boxes, we can in the themed version + if (IsWindowEnabled()) { + oldClr = dc.SetTextColor(CMPCTheme::TextFGColor); + } else { + oldClr = dc.SetTextColor(CMPCTheme::ContentTextDisabledFGColorFade); + } + COLORREF oldBkClr = dc.SetBkColor(CMPCTheme::WindowBGColor); + CFont* pOldFont = dc.SelectObject(font); + + rtext = r; + rtext.left += CMPCTheme::GroupBoxTextIndent; + + text += _T(" "); //seems to be the default behavior + dc.DrawTextW(text, rtext, DT_TOP | DT_LEFT | DT_SINGLELINE | DT_EDITCONTROL); // DT_NOPREFIX not needed + + dc.SelectObject(pOldFont); + dc.SetTextColor(oldClr); + dc.SetBkColor(oldBkClr); + } + fb.DeleteObject(); + ::ReleaseDC(NULL, hDC); + } else { + __super::OnPaint(); + } +} + +void CMPCThemeGroupBox::OnEnable(BOOL bEnable) { + if (AppNeedsThemedControls()) { + SetRedraw(FALSE); + __super::OnEnable(bEnable); + SetRedraw(TRUE); + Invalidate(); //WM_PAINT not handled when enabling/disabling + RedrawWindow(); + } else { + __super::OnEnable(bEnable); + } +} + +LRESULT CMPCThemeGroupBox::OnSetFont(WPARAM wParam, LPARAM lParam) { + manuallySetFont = (HFONT)wParam; + if ((BOOL)lParam) { + Invalidate(); + } + return 0; +} + +LRESULT CMPCThemeGroupBox::OnGetFont(WPARAM wParam, LPARAM lParam) { + if (manuallySetFont) { + return (LRESULT)manuallySetFont; + } else { + return (LRESULT)Default(); + } +} diff --git a/src/mpc-hc/CMPCThemeGroupBox.h b/src/mpc-hc/CMPCThemeGroupBox.h index 14759011dff..cee7657b01c 100755 --- a/src/mpc-hc/CMPCThemeGroupBox.h +++ b/src/mpc-hc/CMPCThemeGroupBox.h @@ -1,18 +1,18 @@ -#pragma once -#include -class CMPCThemeGroupBox : public CStatic -{ - DECLARE_DYNAMIC(CMPCThemeGroupBox) -public: - CMPCThemeGroupBox(); - virtual ~CMPCThemeGroupBox(); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg void OnEnable(BOOL bEnable); - //CStatic does not implement WM_SETFONT. Needed for manually created GroupBox - afx_msg LRESULT OnSetFont(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnGetFont(WPARAM wParam, LPARAM lParam); -protected: - HFONT manuallySetFont; -}; - +#pragma once +#include +class CMPCThemeGroupBox : public CStatic +{ + DECLARE_DYNAMIC(CMPCThemeGroupBox) +public: + CMPCThemeGroupBox(); + virtual ~CMPCThemeGroupBox(); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg void OnEnable(BOOL bEnable); + //CStatic does not implement WM_SETFONT. Needed for manually created GroupBox + afx_msg LRESULT OnSetFont(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnGetFont(WPARAM wParam, LPARAM lParam); +protected: + HFONT manuallySetFont; +}; + diff --git a/src/mpc-hc/CMPCThemeHeaderCtrl.cpp b/src/mpc-hc/CMPCThemeHeaderCtrl.cpp index 4c93f79dfe7..60fee2c0431 100755 --- a/src/mpc-hc/CMPCThemeHeaderCtrl.cpp +++ b/src/mpc-hc/CMPCThemeHeaderCtrl.cpp @@ -1,272 +1,272 @@ -#include "stdafx.h" -#include "CMPCThemeHeaderCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "DpiHelper.h" -#include "mplayerc.h" - -CMPCThemeHeaderCtrl::CMPCThemeHeaderCtrl() -{ - hotItem = -2; -} - - -CMPCThemeHeaderCtrl::~CMPCThemeHeaderCtrl() -{ -} -BEGIN_MESSAGE_MAP(CMPCThemeHeaderCtrl, CHeaderCtrl) - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeHeaderCtrl::OnNMCustomdraw) - ON_NOTIFY(HDN_TRACKA, 0, &CMPCThemeHeaderCtrl::OnHdnTrack) - ON_NOTIFY(HDN_TRACKW, 0, &CMPCThemeHeaderCtrl::OnHdnTrack) - ON_WM_MOUSEMOVE() - ON_WM_MOUSELEAVE() - ON_WM_PAINT() -END_MESSAGE_MAP() - -void CMPCThemeHeaderCtrl::drawSortArrow(CDC* dc, COLORREF arrowClr, CRect arrowRect, bool ascending) -{ - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - Gdiplus::Color clr; - clr.SetFromCOLORREF(arrowClr); - - int dpi = dpiWindow.DPIX(); - float steps; - - if (dpi < 120) { - steps = 3.5; - } else if (dpi < 144) { - steps = 4; - } else if (dpi < 168) { - steps = 5; - } else if (dpi < 192) { - steps = 5; - } else { - steps = 6; - } - - int xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - int yPos = arrowRect.top; - - Gdiplus::Graphics gfx(dc->m_hDC); - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x4); - Gdiplus::Pen pen(clr, 1); - for (int i = 0; i < 2; i++) { - Gdiplus::GraphicsPath path; - Gdiplus::PointF vertices[3]; - - if (ascending) { - vertices[0] = Gdiplus::PointF(xPos, yPos); - vertices[1] = Gdiplus::PointF(steps + xPos, yPos + steps); - vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos); - } else { - vertices[0] = Gdiplus::PointF(xPos, yPos + steps); - vertices[1] = Gdiplus::PointF(steps + xPos, yPos); - vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos + steps); - } - - path.AddLines(vertices, 3); - gfx.DrawPath(&pen, &path); - } -} - -void CMPCThemeHeaderCtrl::drawItem(int nItem, CRect rText, CDC* pDC) -{ - - COLORREF textColor = CMPCTheme::TextFGColor; - COLORREF bgColor = CMPCTheme::ContentBGColor; - - COLORREF oldTextColor = pDC->GetTextColor(); - COLORREF oldBkColor = pDC->GetBkColor(); - - CRect rGrid; - rGrid = rText; - - - rGrid.top -= 1; - rGrid.bottom -= 1; - - CPoint ptCursor; - ::GetCursorPos(&ptCursor); - ScreenToClient(&ptCursor); - checkHot(ptCursor); - - if (nItem == hotItem) { - bgColor = CMPCTheme::ColumnHeaderHotColor; - } - pDC->FillSolidRect(rGrid, bgColor); - - CPen gridPen, *oldPen; - gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::HeaderCtrlGridColor); - oldPen = pDC->SelectObject(&gridPen); - if (nItem != 0) { - //we will draw left border, which lines up with grid. this differs from native widget - //which draws the right border which consequently does not line up with the grid (ugly) - //we only draw the left border starting from the second column - pDC->MoveTo(rGrid.left, rGrid.top); - pDC->LineTo(rGrid.left, rGrid.bottom); - } else { - pDC->MoveTo(rGrid.left, rGrid.bottom); - } - pDC->LineTo(rGrid.BottomRight()); - //pDC->LineTo(rGrid.right, rGrid.top); - pDC->SelectObject(oldPen); - - if (nItem != -1) { - HDITEM hditem = { 0 }; - hditem.mask = HDI_FORMAT | HDI_TEXT | HDI_STATE; - const int c_cchBuffer = 1024; - TCHAR lpBuffer[c_cchBuffer]; - hditem.pszText = lpBuffer; - hditem.cchTextMax = c_cchBuffer; - - GetItem(nItem, &hditem); - int align = hditem.fmt & HDF_JUSTIFYMASK; - UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX; - if (align == HDF_CENTER) { - textFormat |= DT_CENTER; - } else if (align == HDF_LEFT) { - textFormat |= DT_LEFT; - rText.left += 6; - } else { - textFormat |= DT_RIGHT; - rText.right -= 6; - } - CString text = hditem.pszText; - pDC->SetTextColor(textColor); - pDC->SetBkColor(bgColor); - - CMPCThemeUtil::DrawBufferedText(pDC, text, rText, textFormat); - if (hditem.fmt & HDF_SORTUP) { - drawSortArrow(pDC, CMPCTheme::HeaderCtrlSortArrowColor, rText, true); - } else if (hditem.fmt & HDF_SORTDOWN) { - drawSortArrow(pDC, CMPCTheme::HeaderCtrlSortArrowColor, rText, false); - } - } - - pDC->SetTextColor(oldTextColor); - pDC->SetBkColor(oldBkColor); - gridPen.DeleteObject(); -} - -/* custom draw doesn't handle empty areas! code is no longer used in favor of OnPaint() */ -void CMPCThemeHeaderCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); - - *pResult = CDRF_DODEFAULT; - if (AppIsThemeLoaded()) { - if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT) { - *pResult = CDRF_NOTIFYITEMDRAW; - } else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { - int nItem = pLVCD->nmcd.dwItemSpec; - CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); - CRect rText; - GetItemRect(nItem, rText); - - drawItem(nItem, rText, pDC); - *pResult = CDRF_SKIPDEFAULT; - } - } -} - - -void CMPCThemeHeaderCtrl::OnHdnTrack(NMHDR* pNMHDR, LRESULT* pResult) -{ - // LPNMHEADER phdr = reinterpret_cast(pNMHDR); - *pResult = 0; -} - -void CMPCThemeHeaderCtrl::checkHot(CPoint point) -{ - HDHITTESTINFO hdHitTestInfo; - hdHitTestInfo.pt = point; - - int prevHotItem = hotItem; - hotItem = (int)SendMessage(HDM_HITTEST, 0, (LPARAM)&hdHitTestInfo); - - if ((hdHitTestInfo.flags & HHT_ONHEADER) == 0) { - hotItem = -2; - } - if (hotItem != prevHotItem) { - RedrawWindow(); - } -} - - -void CMPCThemeHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - if ((nFlags & MK_LBUTTON) == 0) { - checkHot(point); - } - - __super::OnMouseMove(nFlags, point); -} - -void CMPCThemeHeaderCtrl::OnMouseLeave() -{ - if (hotItem >= 0) { - hotItem = -1; - RedrawWindow(); - } - __super::OnMouseLeave(); -} - - -#define max(a,b) (((a) > (b)) ? (a) : (b)) -void CMPCThemeHeaderCtrl::OnPaint() -{ - if (GetStyle() & HDS_FILTERBAR) { - Default(); - return; - } - - CPaintDC dc(this); // device context for painting - CMemDC memDC(dc, this); - CDC* pDC = &memDC.GetDC(); - CFont* font = GetFont(); - CFont* pOldFont = pDC->SelectObject(font); - - CRect rectClip; - dc.GetClipBox(rectClip); - - CRect rect; - GetClientRect(rect); - - CRect rectItem; - int nCount = GetItemCount(); - - int xMax = 0; - - for (int i = 0; i < nCount; i++) { - CPoint ptCursor; - ::GetCursorPos(&ptCursor); - ScreenToClient(&ptCursor); - - GetItemRect(i, rectItem); - - CRgn rgnClip; - rgnClip.CreateRectRgnIndirect(&rectItem); - pDC->SelectClipRgn(&rgnClip); - - // Draw item: - drawItem(i, rectItem, pDC); - - pDC->SelectClipRgn(NULL); - - xMax = max(xMax, rectItem.right); - } - - // Draw "tail border": - if (nCount == 0) { - rectItem = rect; - rectItem.right++; - } else { - rectItem.left = xMax; - rectItem.right = rect.right + 1; - } - - drawItem(-1, rectItem, pDC); - pDC->SelectObject(pOldFont); -} +#include "stdafx.h" +#include "CMPCThemeHeaderCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "DpiHelper.h" +#include "mplayerc.h" + +CMPCThemeHeaderCtrl::CMPCThemeHeaderCtrl() +{ + hotItem = -2; +} + + +CMPCThemeHeaderCtrl::~CMPCThemeHeaderCtrl() +{ +} +BEGIN_MESSAGE_MAP(CMPCThemeHeaderCtrl, CHeaderCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeHeaderCtrl::OnNMCustomdraw) + ON_NOTIFY(HDN_TRACKA, 0, &CMPCThemeHeaderCtrl::OnHdnTrack) + ON_NOTIFY(HDN_TRACKW, 0, &CMPCThemeHeaderCtrl::OnHdnTrack) + ON_WM_MOUSEMOVE() + ON_WM_MOUSELEAVE() + ON_WM_PAINT() +END_MESSAGE_MAP() + +void CMPCThemeHeaderCtrl::drawSortArrow(CDC* dc, COLORREF arrowClr, CRect arrowRect, bool ascending) +{ + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + Gdiplus::Color clr; + clr.SetFromCOLORREF(arrowClr); + + int dpi = dpiWindow.DPIX(); + float steps; + + if (dpi < 120) { + steps = 3.5; + } else if (dpi < 144) { + steps = 4; + } else if (dpi < 168) { + steps = 5; + } else if (dpi < 192) { + steps = 5; + } else { + steps = 6; + } + + int xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + int yPos = arrowRect.top; + + Gdiplus::Graphics gfx(dc->m_hDC); + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x4); + Gdiplus::Pen pen(clr, 1); + for (int i = 0; i < 2; i++) { + Gdiplus::GraphicsPath path; + Gdiplus::PointF vertices[3]; + + if (ascending) { + vertices[0] = Gdiplus::PointF(xPos, yPos); + vertices[1] = Gdiplus::PointF(steps + xPos, yPos + steps); + vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos); + } else { + vertices[0] = Gdiplus::PointF(xPos, yPos + steps); + vertices[1] = Gdiplus::PointF(steps + xPos, yPos); + vertices[2] = Gdiplus::PointF(steps * 2 + xPos, yPos + steps); + } + + path.AddLines(vertices, 3); + gfx.DrawPath(&pen, &path); + } +} + +void CMPCThemeHeaderCtrl::drawItem(int nItem, CRect rText, CDC* pDC) +{ + + COLORREF textColor = CMPCTheme::TextFGColor; + COLORREF bgColor = CMPCTheme::ContentBGColor; + + COLORREF oldTextColor = pDC->GetTextColor(); + COLORREF oldBkColor = pDC->GetBkColor(); + + CRect rGrid; + rGrid = rText; + + + rGrid.top -= 1; + rGrid.bottom -= 1; + + CPoint ptCursor; + ::GetCursorPos(&ptCursor); + ScreenToClient(&ptCursor); + checkHot(ptCursor); + + if (nItem == hotItem) { + bgColor = CMPCTheme::ColumnHeaderHotColor; + } + pDC->FillSolidRect(rGrid, bgColor); + + CPen gridPen, *oldPen; + gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::HeaderCtrlGridColor); + oldPen = pDC->SelectObject(&gridPen); + if (nItem != 0) { + //we will draw left border, which lines up with grid. this differs from native widget + //which draws the right border which consequently does not line up with the grid (ugly) + //we only draw the left border starting from the second column + pDC->MoveTo(rGrid.left, rGrid.top); + pDC->LineTo(rGrid.left, rGrid.bottom); + } else { + pDC->MoveTo(rGrid.left, rGrid.bottom); + } + pDC->LineTo(rGrid.BottomRight()); + //pDC->LineTo(rGrid.right, rGrid.top); + pDC->SelectObject(oldPen); + + if (nItem != -1) { + HDITEM hditem = { 0 }; + hditem.mask = HDI_FORMAT | HDI_TEXT | HDI_STATE; + const int c_cchBuffer = 1024; + TCHAR lpBuffer[c_cchBuffer]; + hditem.pszText = lpBuffer; + hditem.cchTextMax = c_cchBuffer; + + GetItem(nItem, &hditem); + int align = hditem.fmt & HDF_JUSTIFYMASK; + UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX; + if (align == HDF_CENTER) { + textFormat |= DT_CENTER; + } else if (align == HDF_LEFT) { + textFormat |= DT_LEFT; + rText.left += 6; + } else { + textFormat |= DT_RIGHT; + rText.right -= 6; + } + CString text = hditem.pszText; + pDC->SetTextColor(textColor); + pDC->SetBkColor(bgColor); + + CMPCThemeUtil::DrawBufferedText(pDC, text, rText, textFormat); + if (hditem.fmt & HDF_SORTUP) { + drawSortArrow(pDC, CMPCTheme::HeaderCtrlSortArrowColor, rText, true); + } else if (hditem.fmt & HDF_SORTDOWN) { + drawSortArrow(pDC, CMPCTheme::HeaderCtrlSortArrowColor, rText, false); + } + } + + pDC->SetTextColor(oldTextColor); + pDC->SetBkColor(oldBkColor); + gridPen.DeleteObject(); +} + +/* custom draw doesn't handle empty areas! code is no longer used in favor of OnPaint() */ +void CMPCThemeHeaderCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); + + *pResult = CDRF_DODEFAULT; + if (AppIsThemeLoaded()) { + if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT) { + *pResult = CDRF_NOTIFYITEMDRAW; + } else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { + int nItem = pLVCD->nmcd.dwItemSpec; + CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); + CRect rText; + GetItemRect(nItem, rText); + + drawItem(nItem, rText, pDC); + *pResult = CDRF_SKIPDEFAULT; + } + } +} + + +void CMPCThemeHeaderCtrl::OnHdnTrack(NMHDR* pNMHDR, LRESULT* pResult) +{ + // LPNMHEADER phdr = reinterpret_cast(pNMHDR); + *pResult = 0; +} + +void CMPCThemeHeaderCtrl::checkHot(CPoint point) +{ + HDHITTESTINFO hdHitTestInfo; + hdHitTestInfo.pt = point; + + int prevHotItem = hotItem; + hotItem = (int)SendMessage(HDM_HITTEST, 0, (LPARAM)&hdHitTestInfo); + + if ((hdHitTestInfo.flags & HHT_ONHEADER) == 0) { + hotItem = -2; + } + if (hotItem != prevHotItem) { + RedrawWindow(); + } +} + + +void CMPCThemeHeaderCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + if ((nFlags & MK_LBUTTON) == 0) { + checkHot(point); + } + + __super::OnMouseMove(nFlags, point); +} + +void CMPCThemeHeaderCtrl::OnMouseLeave() +{ + if (hotItem >= 0) { + hotItem = -1; + RedrawWindow(); + } + __super::OnMouseLeave(); +} + + +#define max(a,b) (((a) > (b)) ? (a) : (b)) +void CMPCThemeHeaderCtrl::OnPaint() +{ + if (GetStyle() & HDS_FILTERBAR) { + Default(); + return; + } + + CPaintDC dc(this); // device context for painting + CMemDC memDC(dc, this); + CDC* pDC = &memDC.GetDC(); + CFont* font = GetFont(); + CFont* pOldFont = pDC->SelectObject(font); + + CRect rectClip; + dc.GetClipBox(rectClip); + + CRect rect; + GetClientRect(rect); + + CRect rectItem; + int nCount = GetItemCount(); + + int xMax = 0; + + for (int i = 0; i < nCount; i++) { + CPoint ptCursor; + ::GetCursorPos(&ptCursor); + ScreenToClient(&ptCursor); + + GetItemRect(i, rectItem); + + CRgn rgnClip; + rgnClip.CreateRectRgnIndirect(&rectItem); + pDC->SelectClipRgn(&rgnClip); + + // Draw item: + drawItem(i, rectItem, pDC); + + pDC->SelectClipRgn(NULL); + + xMax = max(xMax, rectItem.right); + } + + // Draw "tail border": + if (nCount == 0) { + rectItem = rect; + rectItem.right++; + } else { + rectItem.left = xMax; + rectItem.right = rect.right + 1; + } + + drawItem(-1, rectItem, pDC); + pDC->SelectObject(pOldFont); +} diff --git a/src/mpc-hc/CMPCThemeHeaderCtrl.h b/src/mpc-hc/CMPCThemeHeaderCtrl.h index 839200f735d..b58daf4d243 100755 --- a/src/mpc-hc/CMPCThemeHeaderCtrl.h +++ b/src/mpc-hc/CMPCThemeHeaderCtrl.h @@ -1,21 +1,21 @@ -#pragma once -#include -class CMPCThemeHeaderCtrl : - public CHeaderCtrl -{ -protected: - int hotItem; - void checkHot(CPoint point); - void drawSortArrow(CDC* dc, COLORREF arrowClr, CRect arrowRect, bool ascending); - void drawItem(int nItem, CRect rText, CDC* pDC); -public: - CMPCThemeHeaderCtrl(); - virtual ~CMPCThemeHeaderCtrl(); - DECLARE_MESSAGE_MAP() - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnHdnTrack(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg void OnPaint(); -}; - +#pragma once +#include +class CMPCThemeHeaderCtrl : + public CHeaderCtrl +{ +protected: + int hotItem; + void checkHot(CPoint point); + void drawSortArrow(CDC* dc, COLORREF arrowClr, CRect arrowRect, bool ascending); + void drawItem(int nItem, CRect rText, CDC* pDC); +public: + CMPCThemeHeaderCtrl(); + virtual ~CMPCThemeHeaderCtrl(); + DECLARE_MESSAGE_MAP() + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnHdnTrack(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeInlineEdit.cpp b/src/mpc-hc/CMPCThemeInlineEdit.cpp index 5c38d90de48..3f4fe0f61b4 100755 --- a/src/mpc-hc/CMPCThemeInlineEdit.cpp +++ b/src/mpc-hc/CMPCThemeInlineEdit.cpp @@ -1,69 +1,69 @@ -#include "stdafx.h" -#include "CMPCThemeInlineEdit.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - -CMPCThemeInlineEdit::CMPCThemeInlineEdit(): - overrideX(0) - ,overrideMaxWidth(-1) - ,offsetEnabled(false) -{ - m_brBkgnd.CreateSolidBrush(CMPCTheme::ContentBGColor); -} - - -CMPCThemeInlineEdit::~CMPCThemeInlineEdit() -{ - m_brBkgnd.DeleteObject(); -} -void CMPCThemeInlineEdit::setOverridePos(int x, int maxWidth) { - overrideX = x; - overrideMaxWidth = maxWidth; - offsetEnabled = true; -} -BEGIN_MESSAGE_MAP(CMPCThemeInlineEdit, CEdit) - ON_WM_CTLCOLOR_REFLECT() - ON_WM_WINDOWPOSCHANGED() - ON_WM_PAINT() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeInlineEdit::CtlColor(CDC* pDC, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::ContentBGColor); - return m_brBkgnd; - } else { - return NULL; - } -} - - -void CMPCThemeInlineEdit::OnWindowPosChanged(WINDOWPOS* lpwndpos) { - if (offsetEnabled && overrideX != lpwndpos->x) { - lpwndpos->cx = overrideMaxWidth == -1 ? lpwndpos->cx : std::min(lpwndpos->cx, overrideMaxWidth); - SetWindowPos(nullptr, overrideX, lpwndpos->y, lpwndpos->cx, lpwndpos->cy, SWP_NOZORDER); - } - CEdit::OnWindowPosChanged(lpwndpos); -} - -void CMPCThemeInlineEdit::OnPaint() { - if (AppIsThemeLoaded()) { - CPaintDC dc(this); - - CRect rect; - GetClientRect(&rect); - - CBrush brush; - brush.CreateSolidBrush(CMPCTheme::InlineEditBorderColor); - dc.FrameRect(&rect, &brush); - brush.DeleteObject(); - - rect.DeflateRect(1, 1); - CBrush bgBrush(CMPCTheme::ContentBGColor); - dc.FrameRect(rect, &bgBrush); - } else { - __super::OnPaint(); - } -} +#include "stdafx.h" +#include "CMPCThemeInlineEdit.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + +CMPCThemeInlineEdit::CMPCThemeInlineEdit(): + overrideX(0) + ,overrideMaxWidth(-1) + ,offsetEnabled(false) +{ + m_brBkgnd.CreateSolidBrush(CMPCTheme::ContentBGColor); +} + + +CMPCThemeInlineEdit::~CMPCThemeInlineEdit() +{ + m_brBkgnd.DeleteObject(); +} +void CMPCThemeInlineEdit::setOverridePos(int x, int maxWidth) { + overrideX = x; + overrideMaxWidth = maxWidth; + offsetEnabled = true; +} +BEGIN_MESSAGE_MAP(CMPCThemeInlineEdit, CEdit) + ON_WM_CTLCOLOR_REFLECT() + ON_WM_WINDOWPOSCHANGED() + ON_WM_PAINT() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeInlineEdit::CtlColor(CDC* pDC, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::ContentBGColor); + return m_brBkgnd; + } else { + return NULL; + } +} + + +void CMPCThemeInlineEdit::OnWindowPosChanged(WINDOWPOS* lpwndpos) { + if (offsetEnabled && overrideX != lpwndpos->x) { + lpwndpos->cx = overrideMaxWidth == -1 ? lpwndpos->cx : std::min(lpwndpos->cx, overrideMaxWidth); + SetWindowPos(nullptr, overrideX, lpwndpos->y, lpwndpos->cx, lpwndpos->cy, SWP_NOZORDER); + } + CEdit::OnWindowPosChanged(lpwndpos); +} + +void CMPCThemeInlineEdit::OnPaint() { + if (AppIsThemeLoaded()) { + CPaintDC dc(this); + + CRect rect; + GetClientRect(&rect); + + CBrush brush; + brush.CreateSolidBrush(CMPCTheme::InlineEditBorderColor); + dc.FrameRect(&rect, &brush); + brush.DeleteObject(); + + rect.DeflateRect(1, 1); + CBrush bgBrush(CMPCTheme::ContentBGColor); + dc.FrameRect(rect, &bgBrush); + } else { + __super::OnPaint(); + } +} diff --git a/src/mpc-hc/CMPCThemeInlineEdit.h b/src/mpc-hc/CMPCThemeInlineEdit.h index fafd97c2f14..fcbb1e07038 100755 --- a/src/mpc-hc/CMPCThemeInlineEdit.h +++ b/src/mpc-hc/CMPCThemeInlineEdit.h @@ -1,21 +1,21 @@ -#pragma once -#include -class CMPCThemeInlineEdit : - public CEdit -{ -public: - CMPCThemeInlineEdit(); - virtual ~CMPCThemeInlineEdit(); - CBrush m_brBkgnd; - void setOverridePos(int x, int maxWidth); - DECLARE_MESSAGE_MAP() - afx_msg void OnNcPaint(); - afx_msg HBRUSH CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/); - afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); -private: - int overrideX, overrideMaxWidth; - bool offsetEnabled; -public: - afx_msg void OnPaint(); -}; - +#pragma once +#include +class CMPCThemeInlineEdit : + public CEdit +{ +public: + CMPCThemeInlineEdit(); + virtual ~CMPCThemeInlineEdit(); + CBrush m_brBkgnd; + void setOverridePos(int x, int maxWidth); + DECLARE_MESSAGE_MAP() + afx_msg void OnNcPaint(); + afx_msg HBRUSH CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/); + afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); +private: + int overrideX, overrideMaxWidth; + bool offsetEnabled; +public: + afx_msg void OnPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeLinkCtrl.cpp b/src/mpc-hc/CMPCThemeLinkCtrl.cpp index cf5a9c13264..bfec5d15c84 100755 --- a/src/mpc-hc/CMPCThemeLinkCtrl.cpp +++ b/src/mpc-hc/CMPCThemeLinkCtrl.cpp @@ -1,35 +1,35 @@ -#include "stdafx.h" -#include "CMPCThemeLinkCtrl.h" -#include "CMPCTheme.h" - - -CMPCThemeLinkCtrl::CMPCThemeLinkCtrl() -{ - -} - - -CMPCThemeLinkCtrl::~CMPCThemeLinkCtrl() -{ -} -BEGIN_MESSAGE_MAP(CMPCThemeLinkCtrl, CLinkCtrl) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeLinkCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH hbr = CLinkCtrl::OnCtlColor(pDC, pWnd, nCtlColor); - - pDC->SetTextColor(CMPCTheme::TextFGColor); - return hbr; -} - -void CMPCThemeLinkCtrl::PreSubclassWindow() -{ - LITEM item = { 0 }; - item.mask = LIF_ITEMINDEX | LIF_STATE; - item.state = LIS_DEFAULTCOLORS; - item.stateMask = LIS_DEFAULTCOLORS; - SetItem(&item); -} +#include "stdafx.h" +#include "CMPCThemeLinkCtrl.h" +#include "CMPCTheme.h" + + +CMPCThemeLinkCtrl::CMPCThemeLinkCtrl() +{ + +} + + +CMPCThemeLinkCtrl::~CMPCThemeLinkCtrl() +{ +} +BEGIN_MESSAGE_MAP(CMPCThemeLinkCtrl, CLinkCtrl) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeLinkCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH hbr = CLinkCtrl::OnCtlColor(pDC, pWnd, nCtlColor); + + pDC->SetTextColor(CMPCTheme::TextFGColor); + return hbr; +} + +void CMPCThemeLinkCtrl::PreSubclassWindow() +{ + LITEM item = { 0 }; + item.mask = LIF_ITEMINDEX | LIF_STATE; + item.state = LIS_DEFAULTCOLORS; + item.stateMask = LIS_DEFAULTCOLORS; + SetItem(&item); +} diff --git a/src/mpc-hc/CMPCThemeLinkCtrl.h b/src/mpc-hc/CMPCThemeLinkCtrl.h index 99bfb3c1848..087c7cce02b 100755 --- a/src/mpc-hc/CMPCThemeLinkCtrl.h +++ b/src/mpc-hc/CMPCThemeLinkCtrl.h @@ -1,13 +1,13 @@ -#pragma once -#include -class CMPCThemeLinkCtrl : - public CLinkCtrl -{ -public: - CMPCThemeLinkCtrl(); - virtual ~CMPCThemeLinkCtrl(); - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - virtual void PreSubclassWindow(); -}; - +#pragma once +#include +class CMPCThemeLinkCtrl : + public CLinkCtrl +{ +public: + CMPCThemeLinkCtrl(); + virtual ~CMPCThemeLinkCtrl(); + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + virtual void PreSubclassWindow(); +}; + diff --git a/src/mpc-hc/CMPCThemeListBox.cpp b/src/mpc-hc/CMPCThemeListBox.cpp index e4f8b2d5a8b..a636d54c9d9 100755 --- a/src/mpc-hc/CMPCThemeListBox.cpp +++ b/src/mpc-hc/CMPCThemeListBox.cpp @@ -1,224 +1,224 @@ -#include "stdafx.h" -#include "CMPCThemeListBox.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -IMPLEMENT_DYNAMIC(CMPCThemeListBox, CListBox) - -CMPCThemeListBox::CMPCThemeListBox() - :customizeToolBar(nullptr) -{ - themedToolTipCid = (UINT_PTR) - 1; - themedSBHelper = nullptr; - if (!CMPCThemeUtil::canUseWin10DarkTheme()) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - } -} - - -CMPCThemeListBox::~CMPCThemeListBox() -{ - if (nullptr != themedSBHelper) { - delete themedSBHelper; - } -} - -BEGIN_MESSAGE_MAP(CMPCThemeListBox, CListBox) - ON_WM_NCPAINT() - ON_WM_MOUSEWHEEL() - ON_WM_TIMER() - ON_WM_VSCROLL() - ON_CONTROL_REFLECT_EX(LBN_SELCHANGE, &CMPCThemeListBox::OnLbnSelchange) - ON_WM_MOUSEMOVE() - ON_WM_SIZE() -END_MESSAGE_MAP() - - -void CMPCThemeListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CDC dc; - if (lpDrawItemStruct->itemID == -1) { - return; - } - dc.Attach(lpDrawItemStruct->hDC); - - int buttonID = (int16_t)LOWORD(lpDrawItemStruct->itemData); - - CRect rc(lpDrawItemStruct->rcItem); - - COLORREF crOldTextColor = dc.GetTextColor(); - COLORREF crOldBkColor = dc.GetBkColor(); - - if ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED)) { - dc.SetTextColor(CMPCTheme::TextFGColor); - dc.SetBkColor(CMPCTheme::ContentSelectedColor); - dc.FillSolidRect(&rc, CMPCTheme::ContentSelectedColor); - } else { - dc.SetTextColor(CMPCTheme::TextFGColor); - dc.SetBkColor(CMPCTheme::ContentBGColor); - dc.FillSolidRect(&rc, CMPCTheme::ContentBGColor); - } - - if (customizeToolBar) { - if (buttonID != -1) { - auto list = customizeToolBar->GetToolBarCtrl().GetImageList(); - IMAGEINFO ii; - list->GetImageInfo(buttonID, &ii); - CRect rci(ii.rcImage); - int border = (rc.Height() - rci.Height()) / 2; - border = border < 0 ? 0 : border; - list->Draw(&dc, buttonID, rc.TopLeft() + CPoint(border, border), ILD_NORMAL); - } - rc.left += rc.Height(); - } - - rc.left += 3; - - CString strText; - GetText(lpDrawItemStruct->itemID, strText); - - CFont* font = GetFont(); - CFont* pOldFont = dc.SelectObject(font); - dc.DrawTextW(strText, strText.GetLength(), &rc, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); - - dc.SetTextColor(crOldTextColor); - dc.SetBkColor(crOldBkColor); - dc.SelectObject(pOldFont); - - dc.Detach(); -} - - -void CMPCThemeListBox::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->themedNcPaintWithSB(); - } else { - CMPCThemeScrollBarHelper::themedNcPaint(this, this); - } - } else { - __super::OnNcPaint(); - } -} - -BOOL CMPCThemeListBox::PreTranslateMessage(MSG* pMsg) -{ - if (AppNeedsThemedControls()) { - themedToolTip.RelayEvent(pMsg); - } - return CListBox::PreTranslateMessage(pMsg); -} - -void CMPCThemeListBox::PreSubclassWindow() -{ - CListBox::PreSubclassWindow(); - if (AppNeedsThemedControls()) { - if (CMPCThemeUtil::canUseWin10DarkTheme()) { - SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); - } else { - SetWindowTheme(GetSafeHwnd(), L"", NULL); - } - if (nullptr == themedToolTip.m_hWnd) { - themedToolTip.Create(this, TTS_ALWAYSTIP); - } - themedToolTip.enableFlickerHelper(); - } -} - - -BOOL CMPCThemeListBox::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) -{ - CListBox::OnMouseWheel(nFlags, zDelta, pt); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - ScreenToClient(&pt); - updateToolTip(pt); - return TRUE; -} - -void CMPCThemeListBox::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - CListBox::OnVScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - -BOOL CMPCThemeListBox::OnLbnSelchange() -{ - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - return FALSE; //allow non-reflection handling -} - - -void CMPCThemeListBox::updateToolTip(CPoint point) -{ - if (AppNeedsThemedControls() && nullptr != themedToolTip) { - TOOLINFO ti = { 0 }; - UINT_PTR tid = OnToolHitTest(point, &ti); - //OnToolHitTest returns -1 on failure but doesn't update uId to match - - if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool - if (themedToolTip.GetToolCount() > 0) { - themedToolTip.DelTool(this); - themedToolTip.Activate(FALSE); - } - themedToolTipCid = (UINT_PTR) - 1; - } - - if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { - - themedToolTipCid = ti.uId; - - CRect cr; - GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate - - themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); - themedToolTip.Activate(TRUE); - } - } -} - - -void CMPCThemeListBox::OnMouseMove(UINT nFlags, CPoint point) -{ - updateToolTip(point); -} - -void CMPCThemeListBox::setIntegralHeight() -{ - CWindowDC dc(this); - CFont* font = GetFont(); - CFont* pOldFont = dc.SelectObject(font); - CRect r(0, 0, 99, 99); - CString test = _T("W"); - dc.DrawText(test, test.GetLength(), &r, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); - SetItemHeight(0, r.Height()); - - dc.SelectObject(pOldFont); -} - -void CMPCThemeListBox::OnSize(UINT nType, int cx, int cy) -{ - CListBox::OnSize(nType, cx, cy); -} - -void CMPCThemeListBox::EnsureVisible(int index) { - CRect r; - GetClientRect(&r); - int lbHeight = r.Height(); - - int height=0; - for (int i = index; i >= 0; i--) { - height += GetItemHeight(i); - if (height > lbHeight) { - SetTopIndex(i + 1); - return; - } - } -} +#include "stdafx.h" +#include "CMPCThemeListBox.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +IMPLEMENT_DYNAMIC(CMPCThemeListBox, CListBox) + +CMPCThemeListBox::CMPCThemeListBox() + :customizeToolBar(nullptr) +{ + themedToolTipCid = (UINT_PTR) - 1; + themedSBHelper = nullptr; + if (!CMPCThemeUtil::canUseWin10DarkTheme()) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + } +} + + +CMPCThemeListBox::~CMPCThemeListBox() +{ + if (nullptr != themedSBHelper) { + delete themedSBHelper; + } +} + +BEGIN_MESSAGE_MAP(CMPCThemeListBox, CListBox) + ON_WM_NCPAINT() + ON_WM_MOUSEWHEEL() + ON_WM_TIMER() + ON_WM_VSCROLL() + ON_CONTROL_REFLECT_EX(LBN_SELCHANGE, &CMPCThemeListBox::OnLbnSelchange) + ON_WM_MOUSEMOVE() + ON_WM_SIZE() +END_MESSAGE_MAP() + + +void CMPCThemeListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC dc; + if (lpDrawItemStruct->itemID == -1) { + return; + } + dc.Attach(lpDrawItemStruct->hDC); + + int buttonID = (int16_t)LOWORD(lpDrawItemStruct->itemData); + + CRect rc(lpDrawItemStruct->rcItem); + + COLORREF crOldTextColor = dc.GetTextColor(); + COLORREF crOldBkColor = dc.GetBkColor(); + + if ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED)) { + dc.SetTextColor(CMPCTheme::TextFGColor); + dc.SetBkColor(CMPCTheme::ContentSelectedColor); + dc.FillSolidRect(&rc, CMPCTheme::ContentSelectedColor); + } else { + dc.SetTextColor(CMPCTheme::TextFGColor); + dc.SetBkColor(CMPCTheme::ContentBGColor); + dc.FillSolidRect(&rc, CMPCTheme::ContentBGColor); + } + + if (customizeToolBar) { + if (buttonID != -1) { + auto list = customizeToolBar->GetToolBarCtrl().GetImageList(); + IMAGEINFO ii; + list->GetImageInfo(buttonID, &ii); + CRect rci(ii.rcImage); + int border = (rc.Height() - rci.Height()) / 2; + border = border < 0 ? 0 : border; + list->Draw(&dc, buttonID, rc.TopLeft() + CPoint(border, border), ILD_NORMAL); + } + rc.left += rc.Height(); + } + + rc.left += 3; + + CString strText; + GetText(lpDrawItemStruct->itemID, strText); + + CFont* font = GetFont(); + CFont* pOldFont = dc.SelectObject(font); + dc.DrawTextW(strText, strText.GetLength(), &rc, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX); + + dc.SetTextColor(crOldTextColor); + dc.SetBkColor(crOldBkColor); + dc.SelectObject(pOldFont); + + dc.Detach(); +} + + +void CMPCThemeListBox::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->themedNcPaintWithSB(); + } else { + CMPCThemeScrollBarHelper::themedNcPaint(this, this); + } + } else { + __super::OnNcPaint(); + } +} + +BOOL CMPCThemeListBox::PreTranslateMessage(MSG* pMsg) +{ + if (AppNeedsThemedControls()) { + themedToolTip.RelayEvent(pMsg); + } + return CListBox::PreTranslateMessage(pMsg); +} + +void CMPCThemeListBox::PreSubclassWindow() +{ + CListBox::PreSubclassWindow(); + if (AppNeedsThemedControls()) { + if (CMPCThemeUtil::canUseWin10DarkTheme()) { + SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); + } else { + SetWindowTheme(GetSafeHwnd(), L"", NULL); + } + if (nullptr == themedToolTip.m_hWnd) { + themedToolTip.Create(this, TTS_ALWAYSTIP); + } + themedToolTip.enableFlickerHelper(); + } +} + + +BOOL CMPCThemeListBox::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + CListBox::OnMouseWheel(nFlags, zDelta, pt); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + ScreenToClient(&pt); + updateToolTip(pt); + return TRUE; +} + +void CMPCThemeListBox::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + CListBox::OnVScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + +BOOL CMPCThemeListBox::OnLbnSelchange() +{ + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + return FALSE; //allow non-reflection handling +} + + +void CMPCThemeListBox::updateToolTip(CPoint point) +{ + if (AppNeedsThemedControls() && nullptr != themedToolTip) { + TOOLINFO ti = { 0 }; + UINT_PTR tid = OnToolHitTest(point, &ti); + //OnToolHitTest returns -1 on failure but doesn't update uId to match + + if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool + if (themedToolTip.GetToolCount() > 0) { + themedToolTip.DelTool(this); + themedToolTip.Activate(FALSE); + } + themedToolTipCid = (UINT_PTR) - 1; + } + + if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { + + themedToolTipCid = ti.uId; + + CRect cr; + GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate + + themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); + themedToolTip.Activate(TRUE); + } + } +} + + +void CMPCThemeListBox::OnMouseMove(UINT nFlags, CPoint point) +{ + updateToolTip(point); +} + +void CMPCThemeListBox::setIntegralHeight() +{ + CWindowDC dc(this); + CFont* font = GetFont(); + CFont* pOldFont = dc.SelectObject(font); + CRect r(0, 0, 99, 99); + CString test = _T("W"); + dc.DrawText(test, test.GetLength(), &r, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); + SetItemHeight(0, r.Height()); + + dc.SelectObject(pOldFont); +} + +void CMPCThemeListBox::OnSize(UINT nType, int cx, int cy) +{ + CListBox::OnSize(nType, cx, cy); +} + +void CMPCThemeListBox::EnsureVisible(int index) { + CRect r; + GetClientRect(&r); + int lbHeight = r.Height(); + + int height=0; + for (int i = index; i >= 0; i--) { + height += GetItemHeight(i); + if (height > lbHeight) { + SetTopIndex(i + 1); + return; + } + } +} diff --git a/src/mpc-hc/CMPCThemeListBox.h b/src/mpc-hc/CMPCThemeListBox.h index f5f74e88d06..ad38d24013d 100755 --- a/src/mpc-hc/CMPCThemeListBox.h +++ b/src/mpc-hc/CMPCThemeListBox.h @@ -1,37 +1,37 @@ -#pragma once -#include -#include "CMPCThemeScrollBar.h" -#include "CMPCThemeToolTipCtrl.h" -#include "CMPCThemeScrollBarHelper.h" - -class CMPCThemeListBox : - public CListBox, public CMPCThemeScrollable -{ - DECLARE_DYNAMIC(CMPCThemeListBox) -private: - CMPCThemeScrollBar vertSB; - CMPCThemeToolTipCtrl themedToolTip; - UINT_PTR themedToolTipCid; - CMPCThemeScrollBarHelper* themedSBHelper; - CToolBar* customizeToolBar; -protected: - virtual void PreSubclassWindow(); -public: - CMPCThemeListBox(); - virtual ~CMPCThemeListBox(); - virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); - BOOL PreTranslateMessage(MSG* pMsg); - DECLARE_MESSAGE_MAP() - afx_msg void OnNcPaint(); -public: - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg BOOL OnLbnSelchange(); - void updateToolTip(CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - void setIntegralHeight(); - afx_msg void OnSize(UINT nType, int cx, int cy); - void EnsureVisible(int index); - void SetCustomizeToolbar(CToolBar* tb) { customizeToolBar = tb; }; -}; - +#pragma once +#include +#include "CMPCThemeScrollBar.h" +#include "CMPCThemeToolTipCtrl.h" +#include "CMPCThemeScrollBarHelper.h" + +class CMPCThemeListBox : + public CListBox, public CMPCThemeScrollable +{ + DECLARE_DYNAMIC(CMPCThemeListBox) +private: + CMPCThemeScrollBar vertSB; + CMPCThemeToolTipCtrl themedToolTip; + UINT_PTR themedToolTipCid; + CMPCThemeScrollBarHelper* themedSBHelper; + CToolBar* customizeToolBar; +protected: + virtual void PreSubclassWindow(); +public: + CMPCThemeListBox(); + virtual ~CMPCThemeListBox(); + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + BOOL PreTranslateMessage(MSG* pMsg); + DECLARE_MESSAGE_MAP() + afx_msg void OnNcPaint(); +public: + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg BOOL OnLbnSelchange(); + void updateToolTip(CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + void setIntegralHeight(); + afx_msg void OnSize(UINT nType, int cx, int cy); + void EnsureVisible(int index); + void SetCustomizeToolbar(CToolBar* tb) { customizeToolBar = tb; }; +}; + diff --git a/src/mpc-hc/CMPCThemeMaskedEdit.cpp b/src/mpc-hc/CMPCThemeMaskedEdit.cpp index 900372e6691..e3159e3ae43 100755 --- a/src/mpc-hc/CMPCThemeMaskedEdit.cpp +++ b/src/mpc-hc/CMPCThemeMaskedEdit.cpp @@ -1,51 +1,51 @@ -#include "stdafx.h" -#include "CMPCThemeMaskedEdit.h" -#include "mplayerc.h" -#include "CMPCTheme.h" - -CMPCThemeMaskedEdit::CMPCThemeMaskedEdit() -{ -} - - -CMPCThemeMaskedEdit::~CMPCThemeMaskedEdit() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeMaskedEdit, CMFCMaskedEdit) -BEGIN_MESSAGE_MAP(CMPCThemeMaskedEdit, CMFCMaskedEdit) - ON_WM_NCPAINT() -END_MESSAGE_MAP() - - -void CMPCThemeMaskedEdit::PreSubclassWindow() -{ - if (AppIsThemeLoaded()) { - ModifyStyleEx(WS_EX_CLIENTEDGE, WS_EX_STATICEDGE, SWP_FRAMECHANGED); - CRect r; - GetClientRect(r); - r.DeflateRect(2, 2); //some default padding for those spaceless fonts - SetRect(r); - } else { - __super::PreSubclassWindow(); - } -} - -void CMPCThemeMaskedEdit::OnNcPaint() -{ - if (AppIsThemeLoaded()) { - CWindowDC dc(this); - - CRect rect; - GetWindowRect(&rect); - rect.OffsetRect(-rect.left, -rect.top); - - CBrush brush; - brush.CreateSolidBrush(CMPCTheme::EditBorderColor); - - dc.FrameRect(&rect, &brush); - brush.DeleteObject(); - } else { - __super::OnNcPaint(); - } -} +#include "stdafx.h" +#include "CMPCThemeMaskedEdit.h" +#include "mplayerc.h" +#include "CMPCTheme.h" + +CMPCThemeMaskedEdit::CMPCThemeMaskedEdit() +{ +} + + +CMPCThemeMaskedEdit::~CMPCThemeMaskedEdit() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeMaskedEdit, CMFCMaskedEdit) +BEGIN_MESSAGE_MAP(CMPCThemeMaskedEdit, CMFCMaskedEdit) + ON_WM_NCPAINT() +END_MESSAGE_MAP() + + +void CMPCThemeMaskedEdit::PreSubclassWindow() +{ + if (AppIsThemeLoaded()) { + ModifyStyleEx(WS_EX_CLIENTEDGE, WS_EX_STATICEDGE, SWP_FRAMECHANGED); + CRect r; + GetClientRect(r); + r.DeflateRect(2, 2); //some default padding for those spaceless fonts + SetRect(r); + } else { + __super::PreSubclassWindow(); + } +} + +void CMPCThemeMaskedEdit::OnNcPaint() +{ + if (AppIsThemeLoaded()) { + CWindowDC dc(this); + + CRect rect; + GetWindowRect(&rect); + rect.OffsetRect(-rect.left, -rect.top); + + CBrush brush; + brush.CreateSolidBrush(CMPCTheme::EditBorderColor); + + dc.FrameRect(&rect, &brush); + brush.DeleteObject(); + } else { + __super::OnNcPaint(); + } +} diff --git a/src/mpc-hc/CMPCThemeMaskedEdit.h b/src/mpc-hc/CMPCThemeMaskedEdit.h index bc33027e8f8..51349205ba7 100755 --- a/src/mpc-hc/CMPCThemeMaskedEdit.h +++ b/src/mpc-hc/CMPCThemeMaskedEdit.h @@ -1,18 +1,18 @@ -#pragma once -#include -class CMPCThemeMaskedEdit : - public CMFCMaskedEdit -{ - DECLARE_DYNAMIC(CMPCThemeMaskedEdit) -public: - CMPCThemeMaskedEdit(); - virtual ~CMPCThemeMaskedEdit(); - void PreSubclassWindow(); -protected: - CFont font; - - DECLARE_MESSAGE_MAP() - afx_msg void OnNcPaint(); - -}; - +#pragma once +#include +class CMPCThemeMaskedEdit : + public CMFCMaskedEdit +{ + DECLARE_DYNAMIC(CMPCThemeMaskedEdit) +public: + CMPCThemeMaskedEdit(); + virtual ~CMPCThemeMaskedEdit(); + void PreSubclassWindow(); +protected: + CFont font; + + DECLARE_MESSAGE_MAP() + afx_msg void OnNcPaint(); + +}; + diff --git a/src/mpc-hc/CMPCThemeMenu.cpp b/src/mpc-hc/CMPCThemeMenu.cpp index c58daa13b48..ffabac9d16e 100644 --- a/src/mpc-hc/CMPCThemeMenu.cpp +++ b/src/mpc-hc/CMPCThemeMenu.cpp @@ -1,590 +1,590 @@ -#include "stdafx.h" -#include "CMPCThemeMenu.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include -#include "AppSettings.h" -#include "PPageAccelTbl.h" -#include "mplayerc.h" - -std::map CMPCThemeMenu::subMenuIDs; -HBRUSH CMPCThemeMenu::bgBrush = 0; -HBRUSH CMPCThemeMenu::bgMenubarBrush = 0; -CFont CMPCThemeMenu::font; -CFont CMPCThemeMenu::symbolFont; -CFont CMPCThemeMenu::bulletFont; -CFont CMPCThemeMenu::checkFont; -bool CMPCThemeMenu::hasDimensions = false; -int CMPCThemeMenu::subMenuPadding; -int CMPCThemeMenu::iconSpacing; -int CMPCThemeMenu::iconPadding; -int CMPCThemeMenu::rowPadding; -int CMPCThemeMenu::separatorPadding; -int CMPCThemeMenu::separatorHeight; -int CMPCThemeMenu::postTextSpacing; -int CMPCThemeMenu::accelSpacing; -CCritSec CMPCThemeMenu::resourceLock; -std::mutex CMPCThemeMenu::submenuMutex; - -IMPLEMENT_DYNAMIC(CMPCThemeMenu, CMenu); -CMPCThemeMenu::CMPCThemeMenu() -{ -} - -CMPCThemeMenu::~CMPCThemeMenu() -{ - { - std::lock_guard guard(submenuMutex); - std::map::iterator itr = subMenuIDs.begin(); - while (itr != subMenuIDs.end()) { - if (itr->second == this) { - itr = subMenuIDs.erase(itr); - } else { - ++itr; - } - } - } - - for (u_int i = 0; i < allocatedItems.size(); i++) { - delete allocatedItems[i]; - } - for (u_int i = 0; i < allocatedMenus.size(); i++) { - allocatedMenus[i]->Detach(); - delete allocatedMenus[i]; - } -} - -void CMPCThemeMenu::initDimensions() -{ - if (!hasDimensions) { - DpiHelper dpi = DpiHelper(); - dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); - - subMenuPadding = dpi.ScaleX(20); - iconSpacing = dpi.ScaleX(22); - iconPadding = dpi.ScaleX(10); - rowPadding = dpi.ScaleY(4) + 3; //windows 10 explorer has paddings of 7,8,9,9,11--this yields 7,8,9,10,11 - separatorPadding = dpi.ScaleX(8); - separatorHeight = dpi.ScaleX(7); - postTextSpacing = dpi.ScaleX(20); - accelSpacing = dpi.ScaleX(30); - { - CAutoLock cAutoLock(&resourceLock); - if (font.m_hObject) { - font.DeleteObject(); - } - CMPCThemeUtil::getFontByType(font, AfxGetMainWnd(), CMPCThemeUtil::MenuFont); - if (symbolFont.m_hObject) { - symbolFont.DeleteObject(); - } - CMPCThemeUtil::getFontByFace(symbolFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 14, FW_BOLD); - if (bulletFont.m_hObject) { - bulletFont.DeleteObject(); - } - CMPCThemeUtil::getFontByFace(bulletFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 6, FW_REGULAR); - if (checkFont.m_hObject) { - checkFont.DeleteObject(); - } - CMPCThemeUtil::getFontByFace(checkFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 10, FW_REGULAR); - } - hasDimensions = true; - } -} - -UINT CMPCThemeMenu::findID(UINT& nPos, bool byCommand) -{ - int iMaxItems = GetMenuItemCount(); - - UINT nID; - if (byCommand) { - nID = nPos; - bool found = false; - for (int j = 0; j < iMaxItems; j++) { - if (nID == GetMenuItemID(j)) { - nPos = j; - found = true; - break; - } - } - if (!found) { - return (UINT) - 1; - } - } else { - nID = GetMenuItemID(nPos); - if (nID == 0xFFFFFFFF) { //submenu, have to find the old-fashioned way - MENUITEMINFO mii = { sizeof(mii) }; - mii.fMask = MIIM_ID; - GetMenuItemInfo(nPos, &mii, TRUE); - nID = mii.wID; - } - } - return nID; -} - -void CMPCThemeMenu::cleanupItem(UINT nPosition, UINT nFlags) -{ - if (AppIsThemeLoaded()) { - MENUITEMINFO tInfo = { sizeof(MENUITEMINFO) }; - tInfo.fMask = MIIM_DATA; - GetMenuItemInfo(nPosition, &tInfo, 0 != (nFlags & MF_BYPOSITION)); - MenuObject* pObject = (MenuObject*)tInfo.dwItemData; - if (std::find(allocatedItems.begin(), allocatedItems.end(), pObject) != allocatedItems.end()) { - allocatedItems.erase(std::remove(allocatedItems.begin(), allocatedItems.end(), pObject), allocatedItems.end()); - delete pObject; - } - } -} - -BOOL CMPCThemeMenu::DeleteMenu(UINT nPosition, UINT nFlags) -{ - cleanupItem(nPosition, nFlags); - return CMenu::DeleteMenu(nPosition, nFlags); -} - -BOOL CMPCThemeMenu::RemoveMenu(UINT nPosition, UINT nFlags) -{ - cleanupItem(nPosition, nFlags); - if (nFlags & MF_BYPOSITION) { - CMenu *t = GetSubMenu(nPosition); - if (t) { - t->Detach(); - if (std::find(allocatedMenus.begin(), allocatedMenus.end(), t) != allocatedMenus.end()) { - allocatedMenus.erase(std::remove(allocatedMenus.begin(), allocatedMenus.end(), t), allocatedMenus.end()); - delete t; - } - } - } - return CMenu::RemoveMenu(nPosition, nFlags); -} - -BOOL CMPCThemeMenu::SetThemedMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos) { - bool rebuildData = false; - bool isMenuBar = false; - if (AppIsThemeLoaded()) { - MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; - mii.fMask = MIIM_DATA; - CMenu::GetMenuItemInfo(uItem, &mii, fByPos); - rebuildData = (0 != (lpMenuItemInfo->fMask & (MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING))); - if (mii.dwItemData && rebuildData) { - MenuObject* tm = (MenuObject*)mii.dwItemData; - isMenuBar = tm->isMenubar; - lpMenuItemInfo->fMask |= MIIM_DATA; - lpMenuItemInfo->dwItemData = 0; - cleanupItem(uItem, fByPos ? MF_BYPOSITION : MF_BYCOMMAND); - } - } - - BOOL ret = CMenu::SetMenuItemInfo(uItem, lpMenuItemInfo, fByPos); - - if (rebuildData) { - fulfillThemeReqsItem((UINT)uItem, !fByPos, isMenuBar); - } - return ret; -} - -BOOL CMPCThemeMenu::SetThemedMenuItemInfo(CMenu* menu, UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos) { - if (menu) { - if (AppIsThemeLoaded()) { - CMPCThemeMenu *tMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, menu); - if (nullptr != tMenu) { - return tMenu->SetThemedMenuItemInfo(uItem, lpMenuItemInfo, fByPos); - } - } else { - return menu->SetMenuItemInfo(uItem, lpMenuItemInfo, fByPos); - } - } - return 0; -} - -BOOL CMPCThemeMenu::AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, LPCTSTR lpszNewItem) -{ - BOOL ret = CMenu::AppendMenu(nFlags, nIDNewItem, lpszNewItem); - UINT numItems = GetMenuItemCount(); - if (numItems > 0) { - //this guarantees we will find the item just inserted, in case id is not unique (0) - fulfillThemeReqsItem(numItems - 1); - } - return ret; -} - -void CMPCThemeMenu::fulfillThemeReqs(bool isMenubar) -{ - if (AppIsThemeLoaded()) { - MENUINFO oldInfo = { sizeof(MENUINFO) }; - oldInfo.fMask = MIM_STYLE; - GetMenuInfo(&oldInfo); - - MENUINFO MenuInfo = { 0 }; - MenuInfo.cbSize = sizeof(MENUINFO); - MenuInfo.fMask = MIM_BACKGROUND | MIM_STYLE | MIM_APPLYTOSUBMENUS; - MenuInfo.dwStyle = oldInfo.dwStyle; - if (!bgBrush) { - bgBrush = ::CreateSolidBrush(CMPCTheme::MenuBGColor); - } - if (!bgMenubarBrush) { - bgMenubarBrush = ::CreateSolidBrush(CMPCTheme::MenubarBGColor); - } - if (isMenubar) { - MenuInfo.hbrBack = bgMenubarBrush; - } else { - MenuInfo.hbrBack = bgBrush; - } - SetMenuInfo(&MenuInfo); - - int iMaxItems = GetMenuItemCount(); - for (int i = 0; i < iMaxItems; i++) { - CString nameHolder; - MenuObject* pObject = DEBUG_NEW MenuObject; - allocatedItems.push_back(pObject); - pObject->m_hIcon = NULL; - pObject->isMenubar = isMenubar; - if (i == 0) { - pObject->isFirstMenuInMenuBar = true; - } - - GetMenuString(i, pObject->m_strCaption, MF_BYPOSITION); - - UINT nID = GetMenuItemID(i); - if (!isOSMenu) { - pObject->m_strAccel = CPPageAccelTbl::MakeAccelShortcutLabel(nID); - } - - subMenuIDs[nID] = this; - - MENUITEMINFO tInfo; - ZeroMemory(&tInfo, sizeof(MENUITEMINFO)); - tInfo.fMask = MIIM_FTYPE; - tInfo.cbSize = sizeof(MENUITEMINFO); - GetMenuItemInfo(i, &tInfo, true); - - if (tInfo.fType & MFT_SEPARATOR) { - pObject->isSeparator = true; - } - - MENUITEMINFO mInfo; - ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); - - mInfo.fMask = MIIM_FTYPE | MIIM_DATA; - mInfo.fType = MFT_OWNERDRAW | tInfo.fType; - mInfo.cbSize = sizeof(MENUITEMINFO); - mInfo.dwItemData = (ULONG_PTR)pObject; - CMenu::SetMenuItemInfo(i, &mInfo, true); - - CMenu* t = GetSubMenu(i); - if (nullptr != t) { - CMPCThemeMenu* pSubMenu; - pSubMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, t); - if (!pSubMenu) { - pSubMenu = DEBUG_NEW CMPCThemeMenu; - pSubMenu->setOSMenu(isOSMenu); - allocatedMenus.push_back(pSubMenu); - pSubMenu->Attach(t->Detach()); - } - pSubMenu->fulfillThemeReqs(); - } - } - } -} - -void CMPCThemeMenu::fulfillThemeReqsItem(UINT i, bool byCommand, bool isMenuBar) -{ - if (AppIsThemeLoaded()) { - MENUITEMINFO tInfo = { sizeof(MENUITEMINFO) }; - tInfo.fMask = MIIM_DATA | MIIM_FTYPE; - GetMenuItemInfo(i, &tInfo, !byCommand); - if (NULL == tInfo.dwItemData) { - CString nameHolder; - MenuObject* pObject = DEBUG_NEW MenuObject; - allocatedItems.push_back(pObject); - pObject->m_hIcon = NULL; - pObject->isMenubar = isMenuBar; - - UINT posOrCmd = byCommand ? MF_BYCOMMAND : MF_BYPOSITION; - - GetMenuString(i, pObject->m_strCaption, posOrCmd); - - UINT nPos = i; - UINT nID = findID(nPos, byCommand); - if (nID == -1) { - return; - } - - pObject->m_strAccel = CPPageAccelTbl::MakeAccelShortcutLabel(nID); - - subMenuIDs[nID] = this; - - if (tInfo.fType & MFT_SEPARATOR) { - pObject->isSeparator = true; - } - - MENUITEMINFO mInfo; - ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); - - mInfo.fMask = MIIM_FTYPE | MIIM_DATA; - mInfo.fType = MFT_OWNERDRAW | tInfo.fType; - mInfo.cbSize = sizeof(MENUITEMINFO); - mInfo.dwItemData = (ULONG_PTR)pObject; - CMenu::SetMenuItemInfo(nPos, &mInfo, true); - - CMenu* t = GetSubMenu(nPos); - if (nullptr != t) { - CMPCThemeMenu* pSubMenu; - pSubMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, t); - if (!pSubMenu) { - pSubMenu = DEBUG_NEW CMPCThemeMenu; - pSubMenu->setOSMenu(isOSMenu); - allocatedMenus.push_back(pSubMenu); - pSubMenu->Attach(t->Detach()); - } - pSubMenu->fulfillThemeReqs(); - } - } - } -} - -void CMPCThemeMenu::fulfillThemeReqsItem(CMenu* parent, UINT i, bool byCommand) -{ - CMPCThemeMenu* t; - if ((t = DYNAMIC_DOWNCAST(CMPCThemeMenu, parent)) != nullptr) { - t->fulfillThemeReqsItem(i, byCommand); - } -} - -UINT CMPCThemeMenu::getPosFromID(CMenu* parent, UINT nID) -{ - int iMaxItems = parent->GetMenuItemCount(); - for (int j = 0; j < iMaxItems; j++) { - if (nID == parent->GetMenuItemID(j)) { - return j; - } - } - return (UINT) - 1; -} - -CMPCThemeMenu* CMPCThemeMenu::getParentMenu(UINT itemID) -{ - if (subMenuIDs.count(itemID) == 1) { - CMPCThemeMenu* m = subMenuIDs.at(itemID); - /* // checks if submenu for overriding of onmeasureitem (win32 limitation). - // but mpc-hc doesn't set up some submenus until later - // which is too late for measureitem to take place - // so we return all items for measuring - MENUITEMINFO mInfo; - ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); - mInfo.fMask = MIIM_SUBMENU; - mInfo.cbSize = sizeof(MENUITEMINFO); - m->GetMenuItemInfo(itemID, &mInfo); - if (mInfo.hSubMenu) // */ - return m; - } - - return nullptr; -} - -void CMPCThemeMenu::GetRects(RECT rcItem, CRect& rectFull, CRect& rectM, CRect& rectIcon, CRect& rectText, CRect& rectArrow) -{ - rectFull.CopyRect(&rcItem); - rectM = rectFull; - rectIcon.SetRect(rectM.left, rectM.top, rectM.left + iconSpacing, rectM.bottom); - rectText.SetRect(rectM.left + iconSpacing + iconPadding, rectM.top, rectM.right - subMenuPadding, rectM.bottom); - rectArrow.SetRect(rectM.right - subMenuPadding, rectM.top, rectM.right, rectM.bottom); -} - -void CMPCThemeMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CAutoLock cAutoLock(&resourceLock); //make sure our resources are protected - if (font.m_hObject) { - MenuObject* menuObject = (MenuObject*)lpDrawItemStruct->itemData; - - MENUITEMINFO mInfo = { sizeof(MENUITEMINFO) }; - - mInfo.fMask = MIIM_FTYPE | MIIM_SUBMENU; - if (lpDrawItemStruct->itemID) { - GetMenuItemInfo(lpDrawItemStruct->itemID, &mInfo); - } else { - //itemID=0 is default for anything inserted without specifying ID (separator). - //result can be finding the first separator rather than a valid item with id=0 - MENUITEMINFO byDataInfo = { sizeof(MENUITEMINFO) }; - byDataInfo.fMask = MIIM_DATA | MIIM_ID; - for (int a = 0; a < GetMenuItemCount(); a++) { - GetMenuItemInfo((UINT)a, &byDataInfo, true); - if (byDataInfo.wID == 0 && byDataInfo.dwItemData == lpDrawItemStruct->itemData) { - GetMenuItemInfo((UINT)a, &mInfo, true); - break; - } - } - } - - CRect rectFull; - CRect rectM; - CRect rectIcon; - CRect rectText; - CRect rectArrow; - - GetRects(lpDrawItemStruct->rcItem, rectFull, rectM, rectIcon, rectText, rectArrow); - - UINT captionAlign = DT_LEFT; - - COLORREF ArrowColor = CMPCTheme::SubmenuColor; - COLORREF TextFGColor; - COLORREF TextBGColor; - COLORREF TextSelectColor; - - if (menuObject->isMenubar) { - TextBGColor = CMPCTheme::MenubarBGColor; - TextSelectColor = CMPCTheme::MenubarSelectedBGColor; - } else { - TextBGColor = CMPCTheme::MenuBGColor; - TextSelectColor = CMPCTheme::MenuSelectedColor; - } - - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - - if ((lpDrawItemStruct->itemState & ODS_DISABLED)) { - TextFGColor = CMPCTheme::MenuItemDisabledColor; - ArrowColor = CMPCTheme::MenuItemDisabledColor; - } else if (menuObject->isMenubar && GetForegroundWindow() != AfxGetMainWnd()->m_hWnd) { - TextFGColor = CMPCTheme::TextFGColorFade; - } else { - TextFGColor = CMPCTheme::TextFGColor; - } - - int oldBKMode = pDC->SetBkMode(TRANSPARENT); - pDC->FillSolidRect(&rectM, TextBGColor); - - if (menuObject->isMenubar) { - if (menuObject->isFirstMenuInMenuBar) { //clean up white borders - CRect wndSize; - ::GetClientRect(AfxGetMainWnd()->m_hWnd, &wndSize); - - CRect rectBorder(rectM.left, rectM.bottom, rectM.left + wndSize.Width(), rectM.bottom + 1); - pDC->FillSolidRect(&rectBorder, CMPCTheme::MainMenuBorderColor); - ExcludeClipRect(lpDrawItemStruct->hDC, rectBorder.left, rectBorder.top, rectBorder.right, rectBorder.bottom); - } - rectM = rectFull; - rectText = rectFull; - captionAlign = DT_CENTER; - } - - if (mInfo.fType & MFT_SEPARATOR) { - int centerOffset = (separatorHeight - 1) / 2; - CRect rectSeparator(rectM.left + separatorPadding, rectM.top + centerOffset, rectM.right - separatorPadding, rectM.top + centerOffset + 1); - pDC->FillSolidRect(&rectSeparator, CMPCTheme::MenuSeparatorColor); - } else { - COLORREF oldTextFGColor = pDC->SetTextColor(TextFGColor); - - CFont* pOldFont = pDC->GetCurrentFont(); - pDC->SelectObject(&font); - if ((lpDrawItemStruct->itemState & (ODS_SELECTED | ODS_HOTLIGHT)) && (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) { - pDC->FillSolidRect(&rectM, TextSelectColor); - } - CString left, right; - GetStrings(menuObject, left, right); - - UINT accelStyle = 0; - if (lpDrawItemStruct->itemState & ODS_NOACCEL) { //removing single &s before drawtext - accelStyle = DT_HIDEPREFIX; - } - pDC->DrawTextW(left, rectText, DT_VCENTER | captionAlign | DT_SINGLELINE | accelStyle); - - if (!menuObject->isMenubar) { - - if (right.GetLength() > 0) { - pDC->DrawTextW(right, rectText, DT_VCENTER | DT_RIGHT | DT_SINGLELINE | accelStyle); - } - - if (mInfo.hSubMenu) { - pDC->SelectObject(&symbolFont); - pDC->SetTextColor(ArrowColor); - pDC->DrawTextW(TEXT(">"), rectArrow, DT_VCENTER | DT_CENTER | DT_SINGLELINE); - } - - if (lpDrawItemStruct->itemState & ODS_CHECKED) { - CString check; - if (mInfo.fType & MFT_RADIOCHECK) { - check = TEXT("\u25CF"); //bullet - pDC->SelectObject(&bulletFont); - } else { - check = TEXT("\u2714"); //checkmark - pDC->SelectObject(&checkFont); - } - pDC->SetTextColor(TextFGColor); - pDC->DrawTextW(check, rectIcon, DT_VCENTER | DT_CENTER | DT_SINGLELINE); - } - } - - pDC->SetBkMode(oldBKMode); - pDC->SetTextColor(oldTextFGColor); - pDC->SelectObject(pOldFont); - } - ExcludeClipRect(lpDrawItemStruct->hDC, rectFull.left, rectFull.top, rectFull.right, rectFull.bottom); - } -} - -void CMPCThemeMenu::GetStrings(MenuObject* mo, CString& left, CString& right) -{ - if (mo->m_strAccel.GetLength() > 0) { - left = mo->m_strCaption; - right = mo->m_strAccel; - } else { - CString text = mo->m_strCaption; - if (!AfxExtractSubString(left, text, 0, _T('\t'))) { - left = _T(""); - } - if (!AfxExtractSubString(right, text, 1, _T('\t'))) { - right = _T(""); - } - } -} - -void CMPCThemeMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) -{ - initDimensions(); //should happen before drawitem - CAutoLock cAutoLock(&resourceLock); //make sure our resources are protected - - HWND mainWnd = AfxGetMainWnd()->GetSafeHwnd(); - HDC hDC = ::GetDC(mainWnd); - MenuObject* mo = (MenuObject*)lpMeasureItemStruct->itemData; - - if (mo->isSeparator) { - lpMeasureItemStruct->itemWidth = 0; - lpMeasureItemStruct->itemHeight = separatorHeight; - } else if (hDC) { - CSize height = CMPCThemeUtil::GetTextSize(_T("W"), hDC, &font); - if (mo->isMenubar) { - CSize cs = CMPCThemeUtil::GetTextSize(mo->m_strCaption, hDC, &font); - lpMeasureItemStruct->itemWidth = cs.cx; - lpMeasureItemStruct->itemHeight = height.cy + rowPadding; - } else { - CString left, right; - GetStrings(mo, left, right); - CSize cs = CMPCThemeUtil::GetTextSize(left, hDC, &font); - lpMeasureItemStruct->itemHeight = height.cy + rowPadding; - lpMeasureItemStruct->itemWidth = iconSpacing + postTextSpacing + subMenuPadding + cs.cx; - if (right.GetLength() > 0) { - CSize csAccel = CMPCThemeUtil::GetTextSize(right, hDC, &font); - lpMeasureItemStruct->itemWidth += accelSpacing + csAccel.cx; - } - } - } - ::ReleaseDC(mainWnd, hDC); -} - -CMPCThemeMenu* CMPCThemeMenu::GetSubMenu(int nPos) -{ - return (CMPCThemeMenu*) CMenu::GetSubMenu(nPos); -} - -void CMPCThemeMenu::updateItem(CCmdUI* pCmdUI) -{ - CMenu* cm = pCmdUI->m_pMenu; - - if (DYNAMIC_DOWNCAST(CMPCThemeMenu, cm)) { - MENUITEMINFO mInfo = { sizeof(MENUITEMINFO) }; - mInfo.fMask = MIIM_DATA; - VERIFY(cm->GetMenuItemInfo(pCmdUI->m_nID, &mInfo)); - - MenuObject* menuObject = (MenuObject*)mInfo.dwItemData; - cm->GetMenuString(pCmdUI->m_nID, menuObject->m_strCaption, MF_BYCOMMAND); - } -} +#include "stdafx.h" +#include "CMPCThemeMenu.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include +#include "AppSettings.h" +#include "PPageAccelTbl.h" +#include "mplayerc.h" + +std::map CMPCThemeMenu::subMenuIDs; +HBRUSH CMPCThemeMenu::bgBrush = 0; +HBRUSH CMPCThemeMenu::bgMenubarBrush = 0; +CFont CMPCThemeMenu::font; +CFont CMPCThemeMenu::symbolFont; +CFont CMPCThemeMenu::bulletFont; +CFont CMPCThemeMenu::checkFont; +bool CMPCThemeMenu::hasDimensions = false; +int CMPCThemeMenu::subMenuPadding; +int CMPCThemeMenu::iconSpacing; +int CMPCThemeMenu::iconPadding; +int CMPCThemeMenu::rowPadding; +int CMPCThemeMenu::separatorPadding; +int CMPCThemeMenu::separatorHeight; +int CMPCThemeMenu::postTextSpacing; +int CMPCThemeMenu::accelSpacing; +CCritSec CMPCThemeMenu::resourceLock; +std::mutex CMPCThemeMenu::submenuMutex; + +IMPLEMENT_DYNAMIC(CMPCThemeMenu, CMenu); +CMPCThemeMenu::CMPCThemeMenu() +{ +} + +CMPCThemeMenu::~CMPCThemeMenu() +{ + { + std::lock_guard guard(submenuMutex); + std::map::iterator itr = subMenuIDs.begin(); + while (itr != subMenuIDs.end()) { + if (itr->second == this) { + itr = subMenuIDs.erase(itr); + } else { + ++itr; + } + } + } + + for (u_int i = 0; i < allocatedItems.size(); i++) { + delete allocatedItems[i]; + } + for (u_int i = 0; i < allocatedMenus.size(); i++) { + allocatedMenus[i]->Detach(); + delete allocatedMenus[i]; + } +} + +void CMPCThemeMenu::initDimensions() +{ + if (!hasDimensions) { + DpiHelper dpi = DpiHelper(); + dpi.Override(AfxGetMainWnd()->GetSafeHwnd()); + + subMenuPadding = dpi.ScaleX(20); + iconSpacing = dpi.ScaleX(22); + iconPadding = dpi.ScaleX(10); + rowPadding = dpi.ScaleY(4) + 3; //windows 10 explorer has paddings of 7,8,9,9,11--this yields 7,8,9,10,11 + separatorPadding = dpi.ScaleX(8); + separatorHeight = dpi.ScaleX(7); + postTextSpacing = dpi.ScaleX(20); + accelSpacing = dpi.ScaleX(30); + { + CAutoLock cAutoLock(&resourceLock); + if (font.m_hObject) { + font.DeleteObject(); + } + CMPCThemeUtil::getFontByType(font, AfxGetMainWnd(), CMPCThemeUtil::MenuFont); + if (symbolFont.m_hObject) { + symbolFont.DeleteObject(); + } + CMPCThemeUtil::getFontByFace(symbolFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 14, FW_BOLD); + if (bulletFont.m_hObject) { + bulletFont.DeleteObject(); + } + CMPCThemeUtil::getFontByFace(bulletFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 6, FW_REGULAR); + if (checkFont.m_hObject) { + checkFont.DeleteObject(); + } + CMPCThemeUtil::getFontByFace(checkFont, AfxGetMainWnd(), CMPCTheme::uiSymbolFont, 10, FW_REGULAR); + } + hasDimensions = true; + } +} + +UINT CMPCThemeMenu::findID(UINT& nPos, bool byCommand) +{ + int iMaxItems = GetMenuItemCount(); + + UINT nID; + if (byCommand) { + nID = nPos; + bool found = false; + for (int j = 0; j < iMaxItems; j++) { + if (nID == GetMenuItemID(j)) { + nPos = j; + found = true; + break; + } + } + if (!found) { + return (UINT) - 1; + } + } else { + nID = GetMenuItemID(nPos); + if (nID == 0xFFFFFFFF) { //submenu, have to find the old-fashioned way + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_ID; + GetMenuItemInfo(nPos, &mii, TRUE); + nID = mii.wID; + } + } + return nID; +} + +void CMPCThemeMenu::cleanupItem(UINT nPosition, UINT nFlags) +{ + if (AppIsThemeLoaded()) { + MENUITEMINFO tInfo = { sizeof(MENUITEMINFO) }; + tInfo.fMask = MIIM_DATA; + GetMenuItemInfo(nPosition, &tInfo, 0 != (nFlags & MF_BYPOSITION)); + MenuObject* pObject = (MenuObject*)tInfo.dwItemData; + if (std::find(allocatedItems.begin(), allocatedItems.end(), pObject) != allocatedItems.end()) { + allocatedItems.erase(std::remove(allocatedItems.begin(), allocatedItems.end(), pObject), allocatedItems.end()); + delete pObject; + } + } +} + +BOOL CMPCThemeMenu::DeleteMenu(UINT nPosition, UINT nFlags) +{ + cleanupItem(nPosition, nFlags); + return CMenu::DeleteMenu(nPosition, nFlags); +} + +BOOL CMPCThemeMenu::RemoveMenu(UINT nPosition, UINT nFlags) +{ + cleanupItem(nPosition, nFlags); + if (nFlags & MF_BYPOSITION) { + CMenu *t = GetSubMenu(nPosition); + if (t) { + t->Detach(); + if (std::find(allocatedMenus.begin(), allocatedMenus.end(), t) != allocatedMenus.end()) { + allocatedMenus.erase(std::remove(allocatedMenus.begin(), allocatedMenus.end(), t), allocatedMenus.end()); + delete t; + } + } + } + return CMenu::RemoveMenu(nPosition, nFlags); +} + +BOOL CMPCThemeMenu::SetThemedMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos) { + bool rebuildData = false; + bool isMenuBar = false; + if (AppIsThemeLoaded()) { + MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; + mii.fMask = MIIM_DATA; + CMenu::GetMenuItemInfo(uItem, &mii, fByPos); + rebuildData = (0 != (lpMenuItemInfo->fMask & (MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING))); + if (mii.dwItemData && rebuildData) { + MenuObject* tm = (MenuObject*)mii.dwItemData; + isMenuBar = tm->isMenubar; + lpMenuItemInfo->fMask |= MIIM_DATA; + lpMenuItemInfo->dwItemData = 0; + cleanupItem(uItem, fByPos ? MF_BYPOSITION : MF_BYCOMMAND); + } + } + + BOOL ret = CMenu::SetMenuItemInfo(uItem, lpMenuItemInfo, fByPos); + + if (rebuildData) { + fulfillThemeReqsItem((UINT)uItem, !fByPos, isMenuBar); + } + return ret; +} + +BOOL CMPCThemeMenu::SetThemedMenuItemInfo(CMenu* menu, UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos) { + if (menu) { + if (AppIsThemeLoaded()) { + CMPCThemeMenu *tMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, menu); + if (nullptr != tMenu) { + return tMenu->SetThemedMenuItemInfo(uItem, lpMenuItemInfo, fByPos); + } + } else { + return menu->SetMenuItemInfo(uItem, lpMenuItemInfo, fByPos); + } + } + return 0; +} + +BOOL CMPCThemeMenu::AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, LPCTSTR lpszNewItem) +{ + BOOL ret = CMenu::AppendMenu(nFlags, nIDNewItem, lpszNewItem); + UINT numItems = GetMenuItemCount(); + if (numItems > 0) { + //this guarantees we will find the item just inserted, in case id is not unique (0) + fulfillThemeReqsItem(numItems - 1); + } + return ret; +} + +void CMPCThemeMenu::fulfillThemeReqs(bool isMenubar) +{ + if (AppIsThemeLoaded()) { + MENUINFO oldInfo = { sizeof(MENUINFO) }; + oldInfo.fMask = MIM_STYLE; + GetMenuInfo(&oldInfo); + + MENUINFO MenuInfo = { 0 }; + MenuInfo.cbSize = sizeof(MENUINFO); + MenuInfo.fMask = MIM_BACKGROUND | MIM_STYLE | MIM_APPLYTOSUBMENUS; + MenuInfo.dwStyle = oldInfo.dwStyle; + if (!bgBrush) { + bgBrush = ::CreateSolidBrush(CMPCTheme::MenuBGColor); + } + if (!bgMenubarBrush) { + bgMenubarBrush = ::CreateSolidBrush(CMPCTheme::MenubarBGColor); + } + if (isMenubar) { + MenuInfo.hbrBack = bgMenubarBrush; + } else { + MenuInfo.hbrBack = bgBrush; + } + SetMenuInfo(&MenuInfo); + + int iMaxItems = GetMenuItemCount(); + for (int i = 0; i < iMaxItems; i++) { + CString nameHolder; + MenuObject* pObject = DEBUG_NEW MenuObject; + allocatedItems.push_back(pObject); + pObject->m_hIcon = NULL; + pObject->isMenubar = isMenubar; + if (i == 0) { + pObject->isFirstMenuInMenuBar = true; + } + + GetMenuString(i, pObject->m_strCaption, MF_BYPOSITION); + + UINT nID = GetMenuItemID(i); + if (!isOSMenu) { + pObject->m_strAccel = CPPageAccelTbl::MakeAccelShortcutLabel(nID); + } + + subMenuIDs[nID] = this; + + MENUITEMINFO tInfo; + ZeroMemory(&tInfo, sizeof(MENUITEMINFO)); + tInfo.fMask = MIIM_FTYPE; + tInfo.cbSize = sizeof(MENUITEMINFO); + GetMenuItemInfo(i, &tInfo, true); + + if (tInfo.fType & MFT_SEPARATOR) { + pObject->isSeparator = true; + } + + MENUITEMINFO mInfo; + ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); + + mInfo.fMask = MIIM_FTYPE | MIIM_DATA; + mInfo.fType = MFT_OWNERDRAW | tInfo.fType; + mInfo.cbSize = sizeof(MENUITEMINFO); + mInfo.dwItemData = (ULONG_PTR)pObject; + CMenu::SetMenuItemInfo(i, &mInfo, true); + + CMenu* t = GetSubMenu(i); + if (nullptr != t) { + CMPCThemeMenu* pSubMenu; + pSubMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, t); + if (!pSubMenu) { + pSubMenu = DEBUG_NEW CMPCThemeMenu; + pSubMenu->setOSMenu(isOSMenu); + allocatedMenus.push_back(pSubMenu); + pSubMenu->Attach(t->Detach()); + } + pSubMenu->fulfillThemeReqs(); + } + } + } +} + +void CMPCThemeMenu::fulfillThemeReqsItem(UINT i, bool byCommand, bool isMenuBar) +{ + if (AppIsThemeLoaded()) { + MENUITEMINFO tInfo = { sizeof(MENUITEMINFO) }; + tInfo.fMask = MIIM_DATA | MIIM_FTYPE; + GetMenuItemInfo(i, &tInfo, !byCommand); + if (NULL == tInfo.dwItemData) { + CString nameHolder; + MenuObject* pObject = DEBUG_NEW MenuObject; + allocatedItems.push_back(pObject); + pObject->m_hIcon = NULL; + pObject->isMenubar = isMenuBar; + + UINT posOrCmd = byCommand ? MF_BYCOMMAND : MF_BYPOSITION; + + GetMenuString(i, pObject->m_strCaption, posOrCmd); + + UINT nPos = i; + UINT nID = findID(nPos, byCommand); + if (nID == -1) { + return; + } + + pObject->m_strAccel = CPPageAccelTbl::MakeAccelShortcutLabel(nID); + + subMenuIDs[nID] = this; + + if (tInfo.fType & MFT_SEPARATOR) { + pObject->isSeparator = true; + } + + MENUITEMINFO mInfo; + ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); + + mInfo.fMask = MIIM_FTYPE | MIIM_DATA; + mInfo.fType = MFT_OWNERDRAW | tInfo.fType; + mInfo.cbSize = sizeof(MENUITEMINFO); + mInfo.dwItemData = (ULONG_PTR)pObject; + CMenu::SetMenuItemInfo(nPos, &mInfo, true); + + CMenu* t = GetSubMenu(nPos); + if (nullptr != t) { + CMPCThemeMenu* pSubMenu; + pSubMenu = DYNAMIC_DOWNCAST(CMPCThemeMenu, t); + if (!pSubMenu) { + pSubMenu = DEBUG_NEW CMPCThemeMenu; + pSubMenu->setOSMenu(isOSMenu); + allocatedMenus.push_back(pSubMenu); + pSubMenu->Attach(t->Detach()); + } + pSubMenu->fulfillThemeReqs(); + } + } + } +} + +void CMPCThemeMenu::fulfillThemeReqsItem(CMenu* parent, UINT i, bool byCommand) +{ + CMPCThemeMenu* t; + if ((t = DYNAMIC_DOWNCAST(CMPCThemeMenu, parent)) != nullptr) { + t->fulfillThemeReqsItem(i, byCommand); + } +} + +UINT CMPCThemeMenu::getPosFromID(CMenu* parent, UINT nID) +{ + int iMaxItems = parent->GetMenuItemCount(); + for (int j = 0; j < iMaxItems; j++) { + if (nID == parent->GetMenuItemID(j)) { + return j; + } + } + return (UINT) - 1; +} + +CMPCThemeMenu* CMPCThemeMenu::getParentMenu(UINT itemID) +{ + if (subMenuIDs.count(itemID) == 1) { + CMPCThemeMenu* m = subMenuIDs.at(itemID); + /* // checks if submenu for overriding of onmeasureitem (win32 limitation). + // but mpc-hc doesn't set up some submenus until later + // which is too late for measureitem to take place + // so we return all items for measuring + MENUITEMINFO mInfo; + ZeroMemory(&mInfo, sizeof(MENUITEMINFO)); + mInfo.fMask = MIIM_SUBMENU; + mInfo.cbSize = sizeof(MENUITEMINFO); + m->GetMenuItemInfo(itemID, &mInfo); + if (mInfo.hSubMenu) // */ + return m; + } + + return nullptr; +} + +void CMPCThemeMenu::GetRects(RECT rcItem, CRect& rectFull, CRect& rectM, CRect& rectIcon, CRect& rectText, CRect& rectArrow) +{ + rectFull.CopyRect(&rcItem); + rectM = rectFull; + rectIcon.SetRect(rectM.left, rectM.top, rectM.left + iconSpacing, rectM.bottom); + rectText.SetRect(rectM.left + iconSpacing + iconPadding, rectM.top, rectM.right - subMenuPadding, rectM.bottom); + rectArrow.SetRect(rectM.right - subMenuPadding, rectM.top, rectM.right, rectM.bottom); +} + +void CMPCThemeMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CAutoLock cAutoLock(&resourceLock); //make sure our resources are protected + if (font.m_hObject) { + MenuObject* menuObject = (MenuObject*)lpDrawItemStruct->itemData; + + MENUITEMINFO mInfo = { sizeof(MENUITEMINFO) }; + + mInfo.fMask = MIIM_FTYPE | MIIM_SUBMENU; + if (lpDrawItemStruct->itemID) { + GetMenuItemInfo(lpDrawItemStruct->itemID, &mInfo); + } else { + //itemID=0 is default for anything inserted without specifying ID (separator). + //result can be finding the first separator rather than a valid item with id=0 + MENUITEMINFO byDataInfo = { sizeof(MENUITEMINFO) }; + byDataInfo.fMask = MIIM_DATA | MIIM_ID; + for (int a = 0; a < GetMenuItemCount(); a++) { + GetMenuItemInfo((UINT)a, &byDataInfo, true); + if (byDataInfo.wID == 0 && byDataInfo.dwItemData == lpDrawItemStruct->itemData) { + GetMenuItemInfo((UINT)a, &mInfo, true); + break; + } + } + } + + CRect rectFull; + CRect rectM; + CRect rectIcon; + CRect rectText; + CRect rectArrow; + + GetRects(lpDrawItemStruct->rcItem, rectFull, rectM, rectIcon, rectText, rectArrow); + + UINT captionAlign = DT_LEFT; + + COLORREF ArrowColor = CMPCTheme::SubmenuColor; + COLORREF TextFGColor; + COLORREF TextBGColor; + COLORREF TextSelectColor; + + if (menuObject->isMenubar) { + TextBGColor = CMPCTheme::MenubarBGColor; + TextSelectColor = CMPCTheme::MenubarSelectedBGColor; + } else { + TextBGColor = CMPCTheme::MenuBGColor; + TextSelectColor = CMPCTheme::MenuSelectedColor; + } + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + + if ((lpDrawItemStruct->itemState & ODS_DISABLED)) { + TextFGColor = CMPCTheme::MenuItemDisabledColor; + ArrowColor = CMPCTheme::MenuItemDisabledColor; + } else if (menuObject->isMenubar && GetForegroundWindow() != AfxGetMainWnd()->m_hWnd) { + TextFGColor = CMPCTheme::TextFGColorFade; + } else { + TextFGColor = CMPCTheme::TextFGColor; + } + + int oldBKMode = pDC->SetBkMode(TRANSPARENT); + pDC->FillSolidRect(&rectM, TextBGColor); + + if (menuObject->isMenubar) { + if (menuObject->isFirstMenuInMenuBar) { //clean up white borders + CRect wndSize; + ::GetClientRect(AfxGetMainWnd()->m_hWnd, &wndSize); + + CRect rectBorder(rectM.left, rectM.bottom, rectM.left + wndSize.Width(), rectM.bottom + 1); + pDC->FillSolidRect(&rectBorder, CMPCTheme::MainMenuBorderColor); + ExcludeClipRect(lpDrawItemStruct->hDC, rectBorder.left, rectBorder.top, rectBorder.right, rectBorder.bottom); + } + rectM = rectFull; + rectText = rectFull; + captionAlign = DT_CENTER; + } + + if (mInfo.fType & MFT_SEPARATOR) { + int centerOffset = (separatorHeight - 1) / 2; + CRect rectSeparator(rectM.left + separatorPadding, rectM.top + centerOffset, rectM.right - separatorPadding, rectM.top + centerOffset + 1); + pDC->FillSolidRect(&rectSeparator, CMPCTheme::MenuSeparatorColor); + } else { + COLORREF oldTextFGColor = pDC->SetTextColor(TextFGColor); + + CFont* pOldFont = pDC->GetCurrentFont(); + pDC->SelectObject(&font); + if ((lpDrawItemStruct->itemState & (ODS_SELECTED | ODS_HOTLIGHT)) && (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) { + pDC->FillSolidRect(&rectM, TextSelectColor); + } + CString left, right; + GetStrings(menuObject, left, right); + + UINT accelStyle = 0; + if (lpDrawItemStruct->itemState & ODS_NOACCEL) { //removing single &s before drawtext + accelStyle = DT_HIDEPREFIX; + } + pDC->DrawTextW(left, rectText, DT_VCENTER | captionAlign | DT_SINGLELINE | accelStyle); + + if (!menuObject->isMenubar) { + + if (right.GetLength() > 0) { + pDC->DrawTextW(right, rectText, DT_VCENTER | DT_RIGHT | DT_SINGLELINE | accelStyle); + } + + if (mInfo.hSubMenu) { + pDC->SelectObject(&symbolFont); + pDC->SetTextColor(ArrowColor); + pDC->DrawTextW(TEXT(">"), rectArrow, DT_VCENTER | DT_CENTER | DT_SINGLELINE); + } + + if (lpDrawItemStruct->itemState & ODS_CHECKED) { + CString check; + if (mInfo.fType & MFT_RADIOCHECK) { + check = TEXT("\u25CF"); //bullet + pDC->SelectObject(&bulletFont); + } else { + check = TEXT("\u2714"); //checkmark + pDC->SelectObject(&checkFont); + } + pDC->SetTextColor(TextFGColor); + pDC->DrawTextW(check, rectIcon, DT_VCENTER | DT_CENTER | DT_SINGLELINE); + } + } + + pDC->SetBkMode(oldBKMode); + pDC->SetTextColor(oldTextFGColor); + pDC->SelectObject(pOldFont); + } + ExcludeClipRect(lpDrawItemStruct->hDC, rectFull.left, rectFull.top, rectFull.right, rectFull.bottom); + } +} + +void CMPCThemeMenu::GetStrings(MenuObject* mo, CString& left, CString& right) +{ + if (mo->m_strAccel.GetLength() > 0) { + left = mo->m_strCaption; + right = mo->m_strAccel; + } else { + CString text = mo->m_strCaption; + if (!AfxExtractSubString(left, text, 0, _T('\t'))) { + left = _T(""); + } + if (!AfxExtractSubString(right, text, 1, _T('\t'))) { + right = _T(""); + } + } +} + +void CMPCThemeMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) +{ + initDimensions(); //should happen before drawitem + CAutoLock cAutoLock(&resourceLock); //make sure our resources are protected + + HWND mainWnd = AfxGetMainWnd()->GetSafeHwnd(); + HDC hDC = ::GetDC(mainWnd); + MenuObject* mo = (MenuObject*)lpMeasureItemStruct->itemData; + + if (mo->isSeparator) { + lpMeasureItemStruct->itemWidth = 0; + lpMeasureItemStruct->itemHeight = separatorHeight; + } else if (hDC) { + CSize height = CMPCThemeUtil::GetTextSize(_T("W"), hDC, &font); + if (mo->isMenubar) { + CSize cs = CMPCThemeUtil::GetTextSize(mo->m_strCaption, hDC, &font); + lpMeasureItemStruct->itemWidth = cs.cx; + lpMeasureItemStruct->itemHeight = height.cy + rowPadding; + } else { + CString left, right; + GetStrings(mo, left, right); + CSize cs = CMPCThemeUtil::GetTextSize(left, hDC, &font); + lpMeasureItemStruct->itemHeight = height.cy + rowPadding; + lpMeasureItemStruct->itemWidth = iconSpacing + postTextSpacing + subMenuPadding + cs.cx; + if (right.GetLength() > 0) { + CSize csAccel = CMPCThemeUtil::GetTextSize(right, hDC, &font); + lpMeasureItemStruct->itemWidth += accelSpacing + csAccel.cx; + } + } + } + ::ReleaseDC(mainWnd, hDC); +} + +CMPCThemeMenu* CMPCThemeMenu::GetSubMenu(int nPos) +{ + return (CMPCThemeMenu*) CMenu::GetSubMenu(nPos); +} + +void CMPCThemeMenu::updateItem(CCmdUI* pCmdUI) +{ + CMenu* cm = pCmdUI->m_pMenu; + + if (DYNAMIC_DOWNCAST(CMPCThemeMenu, cm)) { + MENUITEMINFO mInfo = { sizeof(MENUITEMINFO) }; + mInfo.fMask = MIIM_DATA; + VERIFY(cm->GetMenuItemInfo(pCmdUI->m_nID, &mInfo)); + + MenuObject* menuObject = (MenuObject*)mInfo.dwItemData; + cm->GetMenuString(pCmdUI->m_nID, menuObject->m_strCaption, MF_BYCOMMAND); + } +} diff --git a/src/mpc-hc/CMPCThemeMenu.h b/src/mpc-hc/CMPCThemeMenu.h index 28125ab9e83..ecc97f4573b 100644 --- a/src/mpc-hc/CMPCThemeMenu.h +++ b/src/mpc-hc/CMPCThemeMenu.h @@ -1,63 +1,63 @@ -#pragma once -#include - -struct MenuObject { - HICON m_hIcon; - CString m_strCaption; - CString m_strAccel; - bool isMenubar = false; - bool isSeparator = false; - bool isFirstMenuInMenuBar = false; -}; - - - -class CMPCThemeMenu : public CMenu -{ - DECLARE_DYNAMIC(CMPCThemeMenu) -public: - CMPCThemeMenu(); - virtual ~CMPCThemeMenu(); - - void fulfillThemeReqs(bool menubar = false); - void fulfillThemeReqsItem(UINT i, bool byCommand = false, bool isMenuBar = false); - static void fulfillThemeReqsItem(CMenu* parent, UINT i, bool byCommand = false); - static UINT getPosFromID(CMenu* parent, UINT nID); - static CMPCThemeMenu* getParentMenu(UINT itemID); - virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); - void GetStrings(MenuObject* mo, CString& left, CString& right); - virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); - virtual BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL); - virtual BOOL DeleteMenu(UINT nPosition, UINT nFlags); - virtual BOOL RemoveMenu(UINT nPosition, UINT nFlags); - virtual BOOL SetThemedMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE); - static BOOL SetThemedMenuItemInfo(CMenu *menu, UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE); - CMPCThemeMenu* GetSubMenu(int nPos); - static void updateItem(CCmdUI* pCmdUI); - static void clearDimensions() { hasDimensions = false; }; - void setOSMenu(bool isOSMenu) { this->isOSMenu = isOSMenu; }; -protected: - static std::map subMenuIDs; - std::vector allocatedItems; - std::vector allocatedMenus; - void initDimensions(); - UINT findID(UINT& i, bool byCommand); - void cleanupItem(UINT nPosition, UINT nFlags); - bool isOSMenu = false; - - void GetRects(RECT rcItem, CRect& rectFull, CRect& rectM, CRect& rectIcon, CRect& rectText, CRect& rectArrow); - static bool hasDimensions; - static int subMenuPadding; - static int iconSpacing; - static int iconPadding; - static int rowPadding; - static int separatorPadding; - static int separatorHeight; - static int postTextSpacing; - static int accelSpacing; - static HBRUSH bgBrush, bgMenubarBrush; - static CFont font, symbolFont, bulletFont, checkFont; - static CCritSec resourceLock; - static std::mutex submenuMutex; -}; - +#pragma once +#include + +struct MenuObject { + HICON m_hIcon; + CString m_strCaption; + CString m_strAccel; + bool isMenubar = false; + bool isSeparator = false; + bool isFirstMenuInMenuBar = false; +}; + + + +class CMPCThemeMenu : public CMenu +{ + DECLARE_DYNAMIC(CMPCThemeMenu) +public: + CMPCThemeMenu(); + virtual ~CMPCThemeMenu(); + + void fulfillThemeReqs(bool menubar = false); + void fulfillThemeReqsItem(UINT i, bool byCommand = false, bool isMenuBar = false); + static void fulfillThemeReqsItem(CMenu* parent, UINT i, bool byCommand = false); + static UINT getPosFromID(CMenu* parent, UINT nID); + static CMPCThemeMenu* getParentMenu(UINT itemID); + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + void GetStrings(MenuObject* mo, CString& left, CString& right); + virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); + virtual BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL); + virtual BOOL DeleteMenu(UINT nPosition, UINT nFlags); + virtual BOOL RemoveMenu(UINT nPosition, UINT nFlags); + virtual BOOL SetThemedMenuItemInfo(UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE); + static BOOL SetThemedMenuItemInfo(CMenu *menu, UINT uItem, LPMENUITEMINFO lpMenuItemInfo, BOOL fByPos = FALSE); + CMPCThemeMenu* GetSubMenu(int nPos); + static void updateItem(CCmdUI* pCmdUI); + static void clearDimensions() { hasDimensions = false; }; + void setOSMenu(bool isOSMenu) { this->isOSMenu = isOSMenu; }; +protected: + static std::map subMenuIDs; + std::vector allocatedItems; + std::vector allocatedMenus; + void initDimensions(); + UINT findID(UINT& i, bool byCommand); + void cleanupItem(UINT nPosition, UINT nFlags); + bool isOSMenu = false; + + void GetRects(RECT rcItem, CRect& rectFull, CRect& rectM, CRect& rectIcon, CRect& rectText, CRect& rectArrow); + static bool hasDimensions; + static int subMenuPadding; + static int iconSpacing; + static int iconPadding; + static int rowPadding; + static int separatorPadding; + static int separatorHeight; + static int postTextSpacing; + static int accelSpacing; + static HBRUSH bgBrush, bgMenubarBrush; + static CFont font, symbolFont, bulletFont, checkFont; + static CCritSec resourceLock; + static std::mutex submenuMutex; +}; + diff --git a/src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp b/src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp index 9b62367301b..a58289d99f5 100644 --- a/src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp +++ b/src/mpc-hc/CMPCThemeMiniDockFrameWnd.cpp @@ -1,21 +1,21 @@ -#include "stdafx.h" -#include "CMPCThemeMiniDockFrameWnd.h" -#include "CMPCThemeUtil.h" - -IMPLEMENT_DYNCREATE(CMPCThemeMiniDockFrameWnd, CMiniDockFrameWnd) - -BEGIN_MESSAGE_MAP(CMPCThemeMiniDockFrameWnd, CMiniDockFrameWnd) - ON_WM_CREATE() -END_MESSAGE_MAP() - - -int CMPCThemeMiniDockFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (CMiniDockFrameWnd::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - CMPCThemeUtil::enableWindows10DarkFrame(this); - - return 0; -} +#include "stdafx.h" +#include "CMPCThemeMiniDockFrameWnd.h" +#include "CMPCThemeUtil.h" + +IMPLEMENT_DYNCREATE(CMPCThemeMiniDockFrameWnd, CMiniDockFrameWnd) + +BEGIN_MESSAGE_MAP(CMPCThemeMiniDockFrameWnd, CMiniDockFrameWnd) + ON_WM_CREATE() +END_MESSAGE_MAP() + + +int CMPCThemeMiniDockFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CMiniDockFrameWnd::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + CMPCThemeUtil::enableWindows10DarkFrame(this); + + return 0; +} diff --git a/src/mpc-hc/CMPCThemeMiniDockFrameWnd.h b/src/mpc-hc/CMPCThemeMiniDockFrameWnd.h index b2a5ceed78f..5dde75a7aad 100644 --- a/src/mpc-hc/CMPCThemeMiniDockFrameWnd.h +++ b/src/mpc-hc/CMPCThemeMiniDockFrameWnd.h @@ -1,12 +1,12 @@ -#pragma once -#include - -class CMPCThemeMiniDockFrameWnd: - CMiniDockFrameWnd -{ - DECLARE_DYNCREATE(CMPCThemeMiniDockFrameWnd) -public: - DECLARE_MESSAGE_MAP() - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); -}; - +#pragma once +#include + +class CMPCThemeMiniDockFrameWnd: + CMiniDockFrameWnd +{ + DECLARE_DYNCREATE(CMPCThemeMiniDockFrameWnd) +public: + DECLARE_MESSAGE_MAP() + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); +}; + diff --git a/src/mpc-hc/CMPCThemeMsgBox.cpp b/src/mpc-hc/CMPCThemeMsgBox.cpp index 8f77e241f0c..e44fd7082b5 100755 --- a/src/mpc-hc/CMPCThemeMsgBox.cpp +++ b/src/mpc-hc/CMPCThemeMsgBox.cpp @@ -1,82 +1,82 @@ -#include "stdafx.h" -#include "CMPCThemeMsgBox.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - - -CMPCThemeMsgBox::CMPCThemeMsgBox(CWnd* pParent, CString strMessage, CString strTitle, UINT nStyle, UINT nHelp) - : CMessageBoxDialog(pParent, strMessage, strTitle, nStyle, nHelp) -{ -} - -CMPCThemeMsgBox::CMPCThemeMsgBox(CWnd* pParent, UINT nMessageID, UINT nTitleID, UINT nStyle, UINT nHelp) - : CMessageBoxDialog(pParent, nMessageID, nTitleID, nStyle, nHelp) -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeMsgBox, CMessageBoxDialog) - -CMPCThemeMsgBox::~CMPCThemeMsgBox() -{ -} - -BOOL CMPCThemeMsgBox::OnInitDialog() -{ - BOOL ret = __super::OnInitDialog(); - fulfillThemeReqs(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return ret; -} - -BEGIN_MESSAGE_MAP(CMPCThemeMsgBox, CMessageBoxDialog) - ON_WM_CTLCOLOR() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeMsgBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} - - -BOOL CMPCThemeMsgBox::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - CRect rect, messageArea, buttonArea; - GetClientRect(&rect); - messageArea = rect; - buttonArea = rect; - messageArea.bottom = buttonAreaY; - buttonArea.top = buttonAreaY; - pDC->FillSolidRect(messageArea, CMPCTheme::WindowBGColor); - pDC->FillSolidRect(buttonArea, CMPCTheme::StatusBarBGColor); - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} - -BOOL CMPCThemeMsgBox::MessageBoxW(CWnd* parent, LPCWSTR lpText) -{ - return CMPCThemeMsgBox::MessageBox(parent, lpText, NULL, MB_OK); -} - -BOOL CMPCThemeMsgBox::MessageBoxW(CWnd* parent, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) -{ - if (AppNeedsThemedControls()) { - CMPCThemeMsgBox dlgMessage(parent, lpText, lpCaption, uType, NULL); - return (BOOL)dlgMessage.DoModal(); - } else { - if (parent) { - return parent->MessageBoxW(lpText, lpCaption, uType); - } else { - return ::MessageBoxW(NULL, lpText, lpCaption, uType); - } - } -} +#include "stdafx.h" +#include "CMPCThemeMsgBox.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + + +CMPCThemeMsgBox::CMPCThemeMsgBox(CWnd* pParent, CString strMessage, CString strTitle, UINT nStyle, UINT nHelp) + : CMessageBoxDialog(pParent, strMessage, strTitle, nStyle, nHelp) +{ +} + +CMPCThemeMsgBox::CMPCThemeMsgBox(CWnd* pParent, UINT nMessageID, UINT nTitleID, UINT nStyle, UINT nHelp) + : CMessageBoxDialog(pParent, nMessageID, nTitleID, nStyle, nHelp) +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeMsgBox, CMessageBoxDialog) + +CMPCThemeMsgBox::~CMPCThemeMsgBox() +{ +} + +BOOL CMPCThemeMsgBox::OnInitDialog() +{ + BOOL ret = __super::OnInitDialog(); + fulfillThemeReqs(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return ret; +} + +BEGIN_MESSAGE_MAP(CMPCThemeMsgBox, CMessageBoxDialog) + ON_WM_CTLCOLOR() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeMsgBox::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} + + +BOOL CMPCThemeMsgBox::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + CRect rect, messageArea, buttonArea; + GetClientRect(&rect); + messageArea = rect; + buttonArea = rect; + messageArea.bottom = buttonAreaY; + buttonArea.top = buttonAreaY; + pDC->FillSolidRect(messageArea, CMPCTheme::WindowBGColor); + pDC->FillSolidRect(buttonArea, CMPCTheme::StatusBarBGColor); + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} + +BOOL CMPCThemeMsgBox::MessageBoxW(CWnd* parent, LPCWSTR lpText) +{ + return CMPCThemeMsgBox::MessageBox(parent, lpText, NULL, MB_OK); +} + +BOOL CMPCThemeMsgBox::MessageBoxW(CWnd* parent, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) +{ + if (AppNeedsThemedControls()) { + CMPCThemeMsgBox dlgMessage(parent, lpText, lpCaption, uType, NULL); + return (BOOL)dlgMessage.DoModal(); + } else { + if (parent) { + return parent->MessageBoxW(lpText, lpCaption, uType); + } else { + return ::MessageBoxW(NULL, lpText, lpCaption, uType); + } + } +} diff --git a/src/mpc-hc/CMPCThemeMsgBox.h b/src/mpc-hc/CMPCThemeMsgBox.h index 0fda73e97c0..195fdee320c 100755 --- a/src/mpc-hc/CMPCThemeMsgBox.h +++ b/src/mpc-hc/CMPCThemeMsgBox.h @@ -1,20 +1,20 @@ -#pragma once -#include "MessageBoxDialog/MessageBoxDialog.h" -#include "CMPCThemeUtil.h" - -class CMPCThemeMsgBox : public CMessageBoxDialog, public CMPCThemeUtil -{ -public: - CMPCThemeMsgBox(CWnd* pParent, CString strMessage, CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0); - CMPCThemeMsgBox(CWnd* pParent, UINT nMessageID, UINT nTitleID = 0, UINT nStyle = MB_OK, UINT nHelp = 0); - DECLARE_DYNAMIC(CMPCThemeMsgBox) - virtual ~CMPCThemeMsgBox(); - BOOL OnInitDialog(); - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - static BOOL MessageBoxW(CWnd* parent, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); - static BOOL MessageBoxW(CWnd* parent, LPCWSTR lpText); - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; - +#pragma once +#include "MessageBoxDialog/MessageBoxDialog.h" +#include "CMPCThemeUtil.h" + +class CMPCThemeMsgBox : public CMessageBoxDialog, public CMPCThemeUtil +{ +public: + CMPCThemeMsgBox(CWnd* pParent, CString strMessage, CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0); + CMPCThemeMsgBox(CWnd* pParent, UINT nMessageID, UINT nTitleID = 0, UINT nStyle = MB_OK, UINT nHelp = 0); + DECLARE_DYNAMIC(CMPCThemeMsgBox) + virtual ~CMPCThemeMsgBox(); + BOOL OnInitDialog(); + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + static BOOL MessageBoxW(CWnd* parent, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); + static BOOL MessageBoxW(CWnd* parent, LPCWSTR lpText); + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; + diff --git a/src/mpc-hc/CMPCThemePPageBase.cpp b/src/mpc-hc/CMPCThemePPageBase.cpp index 48caf8c829d..4f2f95430af 100755 --- a/src/mpc-hc/CMPCThemePPageBase.cpp +++ b/src/mpc-hc/CMPCThemePPageBase.cpp @@ -1,89 +1,89 @@ -#include "stdafx.h" -#include "CMPCThemePPageBase.h" -#include "CMPCTheme.h" -#include "ImageGrayer.h" -#include "mplayerc.h" - -IMPLEMENT_DYNAMIC(CMPCThemePPageBase, CPPageBase) - -CMPCThemePPageBase::CMPCThemePPageBase(UINT nIDTemplate, UINT nIDCaption) - : CPPageBase(nIDTemplate, nIDCaption) -{ -} - - -CMPCThemePPageBase::~CMPCThemePPageBase() -{ -} - -BOOL CMPCThemePPageBase::OnInitDialog() -{ - __super::OnInitDialog(); - fulfillThemeReqs(); - return 0; -} - -void CMPCThemePPageBase::SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle) -{ - if (AppIsThemeLoaded()) { - if (!m_buttonIcons.count(iconDef)) { - CImage img, imgEnabled, imgDisabled; - if (iconDef.svgTargetWidth) { - SVGImage::LoadIconDef(iconDef, img); - } else { - img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); - } - - ImageGrayer::UpdateColor(img, imgEnabled, false, colorStyle); - ImageGrayer::UpdateColor(img, imgDisabled, true, colorStyle); - - CImageList& imageList = m_buttonIcons[iconDef]; - imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 2, 0); - imageList.Add(CBitmap::FromHandle(imgEnabled), nullptr); - imageList.Add(CBitmap::FromHandle(imgDisabled), nullptr); - } - - BUTTON_IMAGELIST buttonImageList; - buttonImageList.himl = m_buttonIcons[iconDef]; - buttonImageList.margin = { 0, 0, 0, 0 }; - buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; - static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); - } else { - CPPageBase::SetButtonIcon(nIDButton, iconDef); - } -} - - -BEGIN_MESSAGE_MAP(CMPCThemePPageBase, CPPageBase) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemePPageBase::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} - -BOOL CMPCThemePPageBase::PreTranslateMessage(MSG* pMsg) { - RelayThemedDialogTooltip(pMsg); - return __super::PreTranslateMessage(pMsg); -} - -CPPageBase* CMPCThemePPageBase::FindSiblingPage(CRuntimeClass* pClass) { - CPropertySheet* parent = (CPropertySheet*)GetParent(); - int count = parent->GetPageCount(); - for (int i = 0; i < count; i++) { - CPropertyPage* page = parent->GetPage(i); - CPPageBase *pb = (CPPageBase*)AfxDynamicDownCast(pClass, page); - if (::IsWindow(pb->GetSafeHwnd())) { - return pb; - } - } - return nullptr; -} +#include "stdafx.h" +#include "CMPCThemePPageBase.h" +#include "CMPCTheme.h" +#include "ImageGrayer.h" +#include "mplayerc.h" + +IMPLEMENT_DYNAMIC(CMPCThemePPageBase, CPPageBase) + +CMPCThemePPageBase::CMPCThemePPageBase(UINT nIDTemplate, UINT nIDCaption) + : CPPageBase(nIDTemplate, nIDCaption) +{ +} + + +CMPCThemePPageBase::~CMPCThemePPageBase() +{ +} + +BOOL CMPCThemePPageBase::OnInitDialog() +{ + __super::OnInitDialog(); + fulfillThemeReqs(); + return 0; +} + +void CMPCThemePPageBase::SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle) +{ + if (AppIsThemeLoaded()) { + if (!m_buttonIcons.count(iconDef)) { + CImage img, imgEnabled, imgDisabled; + if (iconDef.svgTargetWidth) { + SVGImage::LoadIconDef(iconDef, img); + } else { + img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); + } + + ImageGrayer::UpdateColor(img, imgEnabled, false, colorStyle); + ImageGrayer::UpdateColor(img, imgDisabled, true, colorStyle); + + CImageList& imageList = m_buttonIcons[iconDef]; + imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 2, 0); + imageList.Add(CBitmap::FromHandle(imgEnabled), nullptr); + imageList.Add(CBitmap::FromHandle(imgDisabled), nullptr); + } + + BUTTON_IMAGELIST buttonImageList; + buttonImageList.himl = m_buttonIcons[iconDef]; + buttonImageList.margin = { 0, 0, 0, 0 }; + buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; + static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); + } else { + CPPageBase::SetButtonIcon(nIDButton, iconDef); + } +} + + +BEGIN_MESSAGE_MAP(CMPCThemePPageBase, CPPageBase) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemePPageBase::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} + +BOOL CMPCThemePPageBase::PreTranslateMessage(MSG* pMsg) { + RelayThemedDialogTooltip(pMsg); + return __super::PreTranslateMessage(pMsg); +} + +CPPageBase* CMPCThemePPageBase::FindSiblingPage(CRuntimeClass* pClass) { + CPropertySheet* parent = (CPropertySheet*)GetParent(); + int count = parent->GetPageCount(); + for (int i = 0; i < count; i++) { + CPropertyPage* page = parent->GetPage(i); + CPPageBase *pb = (CPPageBase*)AfxDynamicDownCast(pClass, page); + if (::IsWindow(pb->GetSafeHwnd())) { + return pb; + } + } + return nullptr; +} diff --git a/src/mpc-hc/CMPCThemePPageBase.h b/src/mpc-hc/CMPCThemePPageBase.h index a7daab3c3f7..28d0cd2c917 100755 --- a/src/mpc-hc/CMPCThemePPageBase.h +++ b/src/mpc-hc/CMPCThemePPageBase.h @@ -1,24 +1,24 @@ -#pragma once -#include "PPageBase.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeUtil.h" -#include "ImageGrayer.h" -class CMPCThemePPageBase : - public CPPageBase, public CMPCThemeUtil -{ - DECLARE_DYNAMIC(CMPCThemePPageBase) -public: - CMPCThemePPageBase(UINT nIDTemplate, UINT nIDCaption); - virtual ~CMPCThemePPageBase(); - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - virtual BOOL OnInitDialog(); - virtual void AdjustDynamicWidgets() {}; - void SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle = ImageGrayer::mpcMono); - BOOL PreTranslateMessage(MSG* pMsg); - CPPageBase* FindSiblingPage(CRuntimeClass* pClass); -}; - +#pragma once +#include "PPageBase.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeUtil.h" +#include "ImageGrayer.h" +class CMPCThemePPageBase : + public CPPageBase, public CMPCThemeUtil +{ + DECLARE_DYNAMIC(CMPCThemePPageBase) +public: + CMPCThemePPageBase(UINT nIDTemplate, UINT nIDCaption); + virtual ~CMPCThemePPageBase(); + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + virtual BOOL OnInitDialog(); + virtual void AdjustDynamicWidgets() {}; + void SetMPCThemeButtonIcon(UINT nIDButton, IconDef iconDef, ImageGrayer::mpcColorStyle colorStyle = ImageGrayer::mpcMono); + BOOL PreTranslateMessage(MSG* pMsg); + CPPageBase* FindSiblingPage(CRuntimeClass* pClass); +}; + diff --git a/src/mpc-hc/CMPCThemePlayerBar.cpp b/src/mpc-hc/CMPCThemePlayerBar.cpp index b23a8448f91..00f3fb3f0bd 100755 --- a/src/mpc-hc/CMPCThemePlayerBar.cpp +++ b/src/mpc-hc/CMPCThemePlayerBar.cpp @@ -1,141 +1,141 @@ -#include "stdafx.h" -#include "CMPCThemePlayerBar.h" -#include "mplayerc.h" -#include "CMPCTheme.h" -#include "MainFrm.h" - -CMPCThemePlayerBar::CMPCThemePlayerBar(CMainFrame* pMainFrame) - :m_pMainFrame(pMainFrame) -{ - InitializeSize(); -} - -CMPCThemePlayerBar::~CMPCThemePlayerBar() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemePlayerBar, CPlayerBar) - -BEGIN_MESSAGE_MAP(CMPCThemePlayerBar, CPlayerBar) - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -void CMPCThemePlayerBar::InitializeSize() { - auto& dpi = m_pMainFrame->m_dpi; - int buttonDim = CMPCThemeUtil::getConstantByDPI(m_pMainFrame, CMPCTheme::ToolbarHideButtonDimensions); - m_cyGripper = buttonDim + dpi.ScaleX(2); - m_biHide.SetDpiSize(CSize(buttonDim, buttonDim)); -} - -BOOL CMPCThemePlayerBar::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - CRect rect; - pDC->GetClipBox(&rect); - pDC->FillSolidRect(rect.left, rect.top, rect.Width(), rect.Height(), CMPCTheme::WindowBGColor); - - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} - -void CMPCThemePlayerBar::paintHideButton(CDC* pDC, CSCBButton b) //derived from CSCBButton::Paint -{ - CRect rc = b.GetRect(); - - if (b.bPushed) { - pDC->FillSolidRect(rc, CMPCTheme::ClosePushColor); - } else if (b.bRaised) { - pDC->FillSolidRect(rc, CMPCTheme::CloseHoverColor); - } - - auto& dpi = m_pMainFrame->m_dpi; - - CMPCThemeUtil::drawToolbarHideButton(pDC, this, rc, CMPCThemeUtil::getIconPathByDPI(m_pMainFrame, TOOLBAR_HIDE_ICON), dpi.ScaleFactorX(), true, b.bPushed||b.bRaised); -} - -void CMPCThemePlayerBar::NcCalcClient(LPRECT pRc, UINT nDockBarID) { //derived from CSizingControlBarG::NcCalcClient to support DPI changes - CRect rcBar(pRc); // save the bar rect - - // subtract edges - baseCSizingControlBarG::NcCalcClient(pRc, nDockBarID); - - if (!HasGripper()) - return; - - CRect rc(pRc); // the client rect as calculated by the base class - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ClientToScreen(rcBar); - GetParent()->ClientToScreen(rc); - - BOOL bHorz = (nDockBarID == AFX_IDW_DOCKBAR_TOP) || - (nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); - - if (bHorz) - rc.DeflateRect(m_cyGripper, 0, 0, 0); - else - rc.DeflateRect(0, m_cyGripper, 0, 0); - - auto& dpi = m_pMainFrame->m_dpi; - - // set position for the "x" (hide bar) button - CPoint ptOrgBtn; - if (bHorz) - ptOrgBtn = CPoint(rc.left - dpi.ScaleX(13), rc.top); - else - ptOrgBtn = CPoint(rc.right - dpi.ScaleX(12), rc.top - dpi.ScaleY(13)); - - m_biHide.Move(ptOrgBtn - rcBar.TopLeft()); - - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ScreenToClient(&rc); - - *pRc = rc; - -} - -void CMPCThemePlayerBar::NcPaintGripper(CDC* pDC, CRect rcClient) //derived from CSizingControlBarG base implementation -{ - if (!AppIsThemeLoaded()) { - __super::NcPaintGripper(pDC, rcClient); - return; - } - - if (!HasGripper()) { - return; - } - - CRect gripper = rcClient; - CRect rcbtn = m_biHide.GetRect(); - BOOL bHorz = IsHorzDocked(); - CBitmap patternBMP; - - gripper.DeflateRect(1, 1); - int gripperHeight = CMPCThemeUtil::getConstantByDPI(m_pMainFrame, CMPCTheme::ToolbarGripperHeight); - - if (bHorz) { // gripper at left - gripper.left = rcbtn.left + (rcbtn.Width() - gripperHeight) / 2; - gripper.top = rcbtn.bottom + 3; - } else { // gripper at top - gripper.top = rcbtn.top + (rcbtn.Height() - gripperHeight) / 2; - gripper.right = rcbtn.left - 3; - } - CMPCThemeUtil::drawGripper(this, m_pMainFrame, gripper, pDC, bHorz); - - paintHideButton(pDC, m_biHide); -} - -void CMPCThemePlayerBar::mpc_fillNcBG(CDC* mdc, CRect rcDraw) -{ - if (AppIsThemeLoaded()) { - if (IsFloating()) { - rcDraw.DeflateRect(1, 1); - } - mdc->FillSolidRect(rcDraw, CMPCTheme::WindowBGColor); - } else { - __super::mpc_fillNcBG(mdc, rcDraw); - } -} +#include "stdafx.h" +#include "CMPCThemePlayerBar.h" +#include "mplayerc.h" +#include "CMPCTheme.h" +#include "MainFrm.h" + +CMPCThemePlayerBar::CMPCThemePlayerBar(CMainFrame* pMainFrame) + :m_pMainFrame(pMainFrame) +{ + InitializeSize(); +} + +CMPCThemePlayerBar::~CMPCThemePlayerBar() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemePlayerBar, CPlayerBar) + +BEGIN_MESSAGE_MAP(CMPCThemePlayerBar, CPlayerBar) + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +void CMPCThemePlayerBar::InitializeSize() { + auto& dpi = m_pMainFrame->m_dpi; + int buttonDim = CMPCThemeUtil::getConstantByDPI(m_pMainFrame, CMPCTheme::ToolbarHideButtonDimensions); + m_cyGripper = buttonDim + dpi.ScaleX(2); + m_biHide.SetDpiSize(CSize(buttonDim, buttonDim)); +} + +BOOL CMPCThemePlayerBar::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + CRect rect; + pDC->GetClipBox(&rect); + pDC->FillSolidRect(rect.left, rect.top, rect.Width(), rect.Height(), CMPCTheme::WindowBGColor); + + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} + +void CMPCThemePlayerBar::paintHideButton(CDC* pDC, CSCBButton b) //derived from CSCBButton::Paint +{ + CRect rc = b.GetRect(); + + if (b.bPushed) { + pDC->FillSolidRect(rc, CMPCTheme::ClosePushColor); + } else if (b.bRaised) { + pDC->FillSolidRect(rc, CMPCTheme::CloseHoverColor); + } + + auto& dpi = m_pMainFrame->m_dpi; + + CMPCThemeUtil::drawToolbarHideButton(pDC, this, rc, CMPCThemeUtil::getIconPathByDPI(m_pMainFrame, TOOLBAR_HIDE_ICON), dpi.ScaleFactorX(), true, b.bPushed||b.bRaised); +} + +void CMPCThemePlayerBar::NcCalcClient(LPRECT pRc, UINT nDockBarID) { //derived from CSizingControlBarG::NcCalcClient to support DPI changes + CRect rcBar(pRc); // save the bar rect + + // subtract edges + baseCSizingControlBarG::NcCalcClient(pRc, nDockBarID); + + if (!HasGripper()) + return; + + CRect rc(pRc); // the client rect as calculated by the base class + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ClientToScreen(rcBar); + GetParent()->ClientToScreen(rc); + + BOOL bHorz = (nDockBarID == AFX_IDW_DOCKBAR_TOP) || + (nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); + + if (bHorz) + rc.DeflateRect(m_cyGripper, 0, 0, 0); + else + rc.DeflateRect(0, m_cyGripper, 0, 0); + + auto& dpi = m_pMainFrame->m_dpi; + + // set position for the "x" (hide bar) button + CPoint ptOrgBtn; + if (bHorz) + ptOrgBtn = CPoint(rc.left - dpi.ScaleX(13), rc.top); + else + ptOrgBtn = CPoint(rc.right - dpi.ScaleX(12), rc.top - dpi.ScaleY(13)); + + m_biHide.Move(ptOrgBtn - rcBar.TopLeft()); + + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ScreenToClient(&rc); + + *pRc = rc; + +} + +void CMPCThemePlayerBar::NcPaintGripper(CDC* pDC, CRect rcClient) //derived from CSizingControlBarG base implementation +{ + if (!AppIsThemeLoaded()) { + __super::NcPaintGripper(pDC, rcClient); + return; + } + + if (!HasGripper()) { + return; + } + + CRect gripper = rcClient; + CRect rcbtn = m_biHide.GetRect(); + BOOL bHorz = IsHorzDocked(); + CBitmap patternBMP; + + gripper.DeflateRect(1, 1); + int gripperHeight = CMPCThemeUtil::getConstantByDPI(m_pMainFrame, CMPCTheme::ToolbarGripperHeight); + + if (bHorz) { // gripper at left + gripper.left = rcbtn.left + (rcbtn.Width() - gripperHeight) / 2; + gripper.top = rcbtn.bottom + 3; + } else { // gripper at top + gripper.top = rcbtn.top + (rcbtn.Height() - gripperHeight) / 2; + gripper.right = rcbtn.left - 3; + } + CMPCThemeUtil::drawGripper(this, m_pMainFrame, gripper, pDC, bHorz); + + paintHideButton(pDC, m_biHide); +} + +void CMPCThemePlayerBar::mpc_fillNcBG(CDC* mdc, CRect rcDraw) +{ + if (AppIsThemeLoaded()) { + if (IsFloating()) { + rcDraw.DeflateRect(1, 1); + } + mdc->FillSolidRect(rcDraw, CMPCTheme::WindowBGColor); + } else { + __super::mpc_fillNcBG(mdc, rcDraw); + } +} diff --git a/src/mpc-hc/CMPCThemePlayerBar.h b/src/mpc-hc/CMPCThemePlayerBar.h index 2e08d7a0698..2ce7ea6261f 100755 --- a/src/mpc-hc/CMPCThemePlayerBar.h +++ b/src/mpc-hc/CMPCThemePlayerBar.h @@ -1,22 +1,22 @@ -#pragma once -#include "PlayerBar.h" - -class CMainFrame; -class CMPCThemePlayerBar : public CPlayerBar -{ -public: - CMPCThemePlayerBar(CMainFrame* pMainFrame); - virtual ~CMPCThemePlayerBar(); - DECLARE_DYNAMIC(CMPCThemePlayerBar) - - void NcPaintGripper(CDC* pDC, CRect rcClient); - void mpc_fillNcBG(CDC* mdc, CRect rcDraw); - DECLARE_MESSAGE_MAP() - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - void InitializeSize(); - void paintHideButton(CDC* pDC, CSCBButton b); - virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); -protected: - CMainFrame* m_pMainFrame; -}; - +#pragma once +#include "PlayerBar.h" + +class CMainFrame; +class CMPCThemePlayerBar : public CPlayerBar +{ +public: + CMPCThemePlayerBar(CMainFrame* pMainFrame); + virtual ~CMPCThemePlayerBar(); + DECLARE_DYNAMIC(CMPCThemePlayerBar) + + void NcPaintGripper(CDC* pDC, CRect rcClient); + void mpc_fillNcBG(CDC* mdc, CRect rcDraw); + DECLARE_MESSAGE_MAP() + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + void InitializeSize(); + void paintHideButton(CDC* pDC, CSCBButton b); + virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); +protected: + CMainFrame* m_pMainFrame; +}; + diff --git a/src/mpc-hc/CMPCThemePlayerListCtrl.cpp b/src/mpc-hc/CMPCThemePlayerListCtrl.cpp index a4991af900c..4d18569a186 100755 --- a/src/mpc-hc/CMPCThemePlayerListCtrl.cpp +++ b/src/mpc-hc/CMPCThemePlayerListCtrl.cpp @@ -1,633 +1,633 @@ -#include "stdafx.h" -#include "CMPCThemePlayerListCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#undef SubclassWindow - -CMPCThemePlayerListCtrl::CMPCThemePlayerListCtrl() : CListCtrl() -{ - themeGridLines = false; - fullRowSelect = false; - themedSBHelper = nullptr; - hasCheckedColors = false; - hasCBImages = false; - customThemeInterface = nullptr; - if (!CMPCThemeUtil::canUseWin10DarkTheme()) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - } -} - - -CMPCThemePlayerListCtrl::~CMPCThemePlayerListCtrl() -{ - if (nullptr != themedSBHelper) { - delete themedSBHelper; - } -} - - -void CMPCThemePlayerListCtrl::PreSubclassWindow() -{ - if (!AppNeedsThemedControls()) { - EnableToolTips(TRUE); - } else { - if (CMPCThemeUtil::canUseWin10DarkTheme()) { - SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); - } else { - SetWindowTheme(GetSafeHwnd(), L"", NULL); - } - CToolTipCtrl* t = GetToolTips(); - if (nullptr != t) { - lvsToolTip.SubclassWindow(t->m_hWnd); - } - subclassHeader(); - } - CListCtrl::PreSubclassWindow(); -} - -IMPLEMENT_DYNAMIC(CMPCThemePlayerListCtrl, CListCtrl) - -BEGIN_MESSAGE_MAP(CMPCThemePlayerListCtrl, CListCtrl) - ON_WM_NCPAINT() - ON_WM_CREATE() - ON_NOTIFY_REFLECT_EX(LVN_ENDSCROLL, OnLvnEndScroll) - ON_WM_MOUSEMOVE() - ON_WM_MOUSEWHEEL() - ON_WM_NCCALCSIZE() - ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, OnCustomDraw) - ON_WM_ERASEBKGND() - ON_WM_CTLCOLOR() - ON_NOTIFY_EX(HDN_ENDTRACKA, 0, &OnHdnEndtrack) - ON_NOTIFY_EX(HDN_ENDTRACKW, 0, &OnHdnEndtrack) - ON_NOTIFY_REFLECT_EX(LVN_ITEMCHANGED, &OnLvnItemchanged) - ON_MESSAGE(PLAYER_PLAYLIST_UPDATE_SCROLLBAR, OnDelayed_UpdateScrollbar) - ON_WM_WINDOWPOSCHANGED() -END_MESSAGE_MAP() - -void CMPCThemePlayerListCtrl::OnWindowPosChanged(WINDOWPOS* lpwndpos) { - if (AppNeedsThemedControls()) { - if (themedSBHelper && 0 != (GetStyle() & (WS_VSCROLL | WS_HSCROLL))) { - themedSBHelper->OnWindowPosChanged(); - } - } - return __super::OnWindowPosChanged(lpwndpos); -} - - -void CMPCThemePlayerListCtrl::subclassHeader() -{ - CHeaderCtrl* t = GetHeaderCtrl(); - if (nullptr != t && IsWindow(t->m_hWnd) && themedHdrCtrl.m_hWnd == NULL) { - themedHdrCtrl.SubclassWindow(t->GetSafeHwnd()); - } -} - -void CMPCThemePlayerListCtrl::setAdditionalStyles(DWORD styles) -{ - if (AppNeedsThemedControls()) { - DWORD stylesToAdd = styles, stylesToRemove = 0; - if (styles & LVS_EX_GRIDLINES) { - stylesToAdd &= ~LVS_EX_GRIDLINES; - stylesToRemove |= LVS_EX_GRIDLINES; - themeGridLines = true; - } - if (styles & LVS_EX_FULLROWSELECT) { - //we need these to remain, or else other columns may not get refreshed on a selection change. - //no regressions observed yet, but unclear why we removed this style for custom draw previously - //error was observed with playersubresyncbar - // stylesToAdd &= ~LVS_EX_FULLROWSELECT; - // stylesToRemove |= LVS_EX_FULLROWSELECT; - fullRowSelect = true; - } - if (styles & LVS_EX_DOUBLEBUFFER) { //we will buffer ourselves - stylesToAdd &= ~LVS_EX_DOUBLEBUFFER; - stylesToRemove |= LVS_EX_DOUBLEBUFFER; - } - SetExtendedStyle((GetExtendedStyle() | stylesToAdd) & ~stylesToRemove); - } else { - SetExtendedStyle(GetExtendedStyle() | styles); - } -} - -void CMPCThemePlayerListCtrl::setHasCBImages(bool on) -{ - hasCBImages = on; -} - -void CMPCThemePlayerListCtrl::setItemTextWithDefaultFlag(int nItem, int nSubItem, LPCTSTR lpszText, bool flagged) -{ - SetItemText(nItem, nSubItem, lpszText); - setFlaggedItem(nItem, flagged); -} - -void CMPCThemePlayerListCtrl::setFlaggedItem(int iItem, bool flagged) -{ - flaggedItems[iItem] = flagged; -} - -bool CMPCThemePlayerListCtrl::getFlaggedItem(int iItem) -{ - auto it = flaggedItems.find(iItem); - if (it != flaggedItems.end()) { - return it->second; - } else { - return false; - } -} - -void CMPCThemePlayerListCtrl::DoDPIChanged() -{ - if (listMPCThemeFontBold.m_hObject) { - listMPCThemeFontBold.DeleteObject(); - } - -} - - -BOOL CMPCThemePlayerListCtrl::PreTranslateMessage(MSG* pMsg) -{ - if (AppNeedsThemedControls()) { - if (!IsWindow(themedToolTip.m_hWnd)) { - themedToolTip.Create(this, TTS_ALWAYSTIP); - themedToolTip.enableFlickerHelper(); - } - if (IsWindow(themedToolTip.m_hWnd)) { - themedToolTip.RelayEvent(pMsg); - } - } - return __super::PreTranslateMessage(pMsg); -} - -void CMPCThemePlayerListCtrl::setCheckedColors(COLORREF checkedBG, COLORREF checkedText, COLORREF uncheckedText) -{ - checkedBGClr = checkedBG; - checkedTextClr = checkedText; - uncheckedTextClr = uncheckedText; - hasCheckedColors = true; -} - -void CMPCThemePlayerListCtrl::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->themedNcPaintWithSB(); - } else { - CMPCThemeScrollBarHelper::themedNcPaint(this, this); - } - } else { - __super::OnNcPaint(); - } -} - - -int CMPCThemePlayerListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (__super::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - if (AppNeedsThemedControls()) { - SetBkColor(CMPCTheme::ContentBGColor); - subclassHeader(); - } - - return 0; -} - -BOOL CMPCThemePlayerListCtrl::OnLvnEndScroll(NMHDR* pNMHDR, LRESULT* pResult) -{ - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - *pResult = 0; - } - return FALSE; -} - -void CMPCThemePlayerListCtrl::updateSB() -{ - if (nullptr != themedSBHelper) { - themedSBHelper->hideNativeScrollBars(); - } -} - -void CMPCThemePlayerListCtrl::updateScrollInfo(bool invalidate /*=false*/) -{ - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(invalidate); - } -} - -LRESULT CMPCThemePlayerListCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (AppNeedsThemedControls() && nullptr != themedSBHelper) { - if (themedSBHelper->WindowProc(this, message, wParam, lParam)) { - return 1; - } - } - return __super::WindowProc(message, wParam, lParam); -} - -void CMPCThemePlayerListCtrl::updateToolTip(CPoint point) -{ - if (AppNeedsThemedControls() && nullptr != themedToolTip) { - TOOLINFO ti = { 0 }; - UINT_PTR tid = OnToolHitTest(point, &ti); - //OnToolHitTest returns -1 on failure but doesn't update uId to match - - if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool - if (themedToolTip.GetToolCount() > 0) { - themedToolTip.DelTool(this); - themedToolTip.Activate(FALSE); - } - themedToolTipCid = (UINT_PTR) - 1; - } - - if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { - - themedToolTipCid = ti.uId; - - CRect cr; - GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate - - themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); - themedToolTip.Activate(TRUE); - } - } -} - -void CMPCThemePlayerListCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - __super::OnMouseMove(nFlags, point); - updateToolTip(point); -} - - -BOOL CMPCThemePlayerListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) -{ - BOOL ret = __super::OnMouseWheel(nFlags, zDelta, pt); - ScreenToClient(&pt); - updateToolTip(pt); - return ret; -} - - -void CMPCThemePlayerListCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) -{ - __super::OnNcCalcSize(bCalcValidRects, lpncsp); - if (AppNeedsThemedControls()) { - if (GetStyle() & WS_HSCROLL && nullptr == themedSBHelper) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - } - ::PostMessage(m_hWnd, PLAYER_PLAYLIST_UPDATE_SCROLLBAR, (WPARAM)0, (LPARAM)TRUE); - } -} - -void CMPCThemePlayerListCtrl::drawItem(CDC* pDC, int nItem, int nSubItem) -{ - if (IsItemVisible(nItem)) { - - CRect rect, rRow, rIcon, rText, rTextBG, rectDC, rClient; - GetClientRect(rClient); - GetItemRect(nItem, rRow, LVIR_BOUNDS); - GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rText); - GetSubItemRect(nItem, nSubItem, LVIR_ICON, rIcon); - GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect); - DWORD dwStyle = GetStyle() & LVS_TYPEMASK; - - if (0 == nSubItem) { //getsubitemrect gives whole row for 0/LVIR_BOUNDS. but LVIR_LABEL is limited to text bounds. MSDN undocumented behavior - rect.right = rText.right; - } - - //issubitemvisible - if (rClient.left <= rect.right && rClient.right >= rect.left && rClient.top <= rect.bottom && rClient.bottom >= rect.top) { - COLORREF textColor = CMPCTheme::TextFGColor; - COLORREF bgColor = CMPCTheme::ContentBGColor; - COLORREF selectedBGColor = CMPCTheme::ContentSelectedColor; - - COLORREF oldTextColor = pDC->GetTextColor(); - COLORREF oldBkColor = pDC->GetBkColor(); - - CString text = GetItemText(nItem, nSubItem); - if (nullptr != customThemeInterface) { //subclasses can override colors here - bool overrideSelectedBG = false; - customThemeInterface->GetCustomTextColors(nItem, nSubItem, textColor, bgColor, overrideSelectedBG); - if (overrideSelectedBG) { - selectedBGColor = bgColor; - } - } - - pDC->SetTextColor(textColor); - pDC->SetBkColor(bgColor); - - rectDC = rRow; - CDC dcMem; - CBitmap bmMem; - CMPCThemeUtil::initMemDC(pDC, dcMem, bmMem, rectDC); - rect.OffsetRect(-rectDC.TopLeft()); - rText.OffsetRect(-rectDC.TopLeft()); - rIcon.OffsetRect(-rectDC.TopLeft()); - rRow.OffsetRect(-rectDC.TopLeft()); - - if (!IsWindowEnabled() && 0 == nSubItem) { //no gridlines, bg for full row - dcMem.FillSolidRect(rRow, CMPCTheme::ListCtrlDisabledBGColor); - } else { - dcMem.FillSolidRect(rect, CMPCTheme::ContentBGColor); //no flicker because we have a memory dc - } - - rTextBG = rText; - CHeaderCtrl* hdrCtrl = GetHeaderCtrl(); - int align = DT_LEFT; - if (nullptr != hdrCtrl) { - HDITEM hditem = { 0 }; - hditem.mask = HDI_FORMAT; - hdrCtrl->GetItem(nSubItem, &hditem); - align = hditem.fmt & HDF_JUSTIFYMASK; - } - UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX; - if (align == HDF_CENTER) { - textFormat |= DT_CENTER; - } else if (align == HDF_LEFT) { - textFormat |= DT_LEFT; - if (nSubItem == 0) {//less indent for first column - rText.left += 2; - } else { - rText.left += 6; - } - } else { - textFormat |= DT_RIGHT; - rText.right -= 6; - } - - bool isChecked = false; - int contentLeft = rText.left; - if (rIcon.Width() > 0) { - LVITEM lvi = { 0 }; - lvi.iItem = nItem; - lvi.iSubItem = 0; - lvi.mask = LVIF_IMAGE; - GetItem(&lvi); - - if (nSubItem == 0) { - contentLeft = rIcon.left; - if (hasCBImages) { //draw manually to match theme - rIcon.DeflateRect(0, 0, 1, 0); - if (rIcon.Height() > rIcon.Width()) { - rIcon.DeflateRect(0, (rIcon.Height() - rIcon.Width()) / 2); //as tall as wide - } - - CMPCThemeUtil::drawCheckBox(GetParent(), lvi.iImage, false, false, rIcon, &dcMem); - } else { - if (dwStyle == LVS_ICON) { - } else if (dwStyle == LVS_SMALLICON || dwStyle == LVS_LIST || dwStyle == LVS_REPORT) { - CImageList* ilist = GetImageList(LVSIL_SMALL); - int cx, cy; - ImageList_GetIconSize(ilist->m_hImageList, &cx, &cy); - rIcon.top += (rIcon.Height() - cy) / 2; - ilist->Draw(&dcMem, lvi.iImage, rIcon.TopLeft(), ILD_TRANSPARENT); - } - } - if (align == HDF_LEFT) { - rText.left += 2; //more ident after image - } - } - } - if (0 != (GetExtendedStyle() & LVS_EX_CHECKBOXES) && INDEXTOSTATEIMAGEMASK(0) != GetItemState(nItem, LVIS_STATEIMAGEMASK)) { - isChecked = (TRUE == GetCheck(nItem)); - if (nSubItem == 0) { - int cbSize = GetSystemMetrics(SM_CXMENUCHECK); - int cbYMargin = (rect.Height() - cbSize - 1) / 2; - int cbXMargin = (contentLeft - rect.left - cbSize) / 2; - CRect rcb = { rect.left + cbXMargin, rect.top + cbYMargin, rect.left + cbXMargin + cbSize, rect.top + cbYMargin + cbSize }; - CMPCThemeUtil::drawCheckBox(GetParent(), isChecked, false, true, rcb, &dcMem); - } - } - - if (IsWindowEnabled()) { - bool selected = false; - if (GetItemState(nItem, LVIS_SELECTED) == LVIS_SELECTED && (nSubItem == 0 || fullRowSelect) && (GetStyle() & LVS_SHOWSELALWAYS || GetFocus() == this)) { - bgColor = selectedBGColor; - if (LVS_REPORT != dwStyle) { //in list mode we don't fill the "whole" column - CRect tmp = rText; - dcMem.DrawTextW(text, tmp, textFormat | DT_CALCRECT); //end of string - rTextBG.right = tmp.right + (rText.left - rTextBG.left); //end of string plus same indent from the left side - } - selected = true; - } else if (hasCheckedColors) { - if (isChecked && checkedBGClr != -1) { - bgColor = checkedBGClr; - } - if (isChecked && checkedTextClr != -1) { - dcMem.SetTextColor(checkedTextClr); - } - if (!isChecked && uncheckedTextClr != -1) { - dcMem.SetTextColor(uncheckedTextClr); - } - } - dcMem.FillSolidRect(rTextBG, bgColor); - - if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { - CRect rGrid = rect; - rGrid.bottom -= 1; - CPen gridPenV, gridPenH, *oldPen; - if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { - COLORREF horzGridColor, vertGridColor; - customThemeInterface->GetCustomGridColors(nItem, horzGridColor, vertGridColor); - gridPenV.CreatePen(PS_SOLID, 1, vertGridColor); - gridPenH.CreatePen(PS_SOLID, 1, horzGridColor); - } else { - gridPenV.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); - gridPenH.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); - } - - oldPen = dcMem.SelectObject(&gridPenV); - if (nSubItem != 0) { - dcMem.MoveTo(rGrid.TopLeft()); - dcMem.LineTo(rGrid.left, rGrid.bottom); - } else { - dcMem.MoveTo(rGrid.left, rGrid.bottom); - } - - dcMem.SelectObject(&gridPenH); - dcMem.LineTo(rGrid.BottomRight()); - - dcMem.SelectObject(&gridPenV); - dcMem.LineTo(rGrid.right, rGrid.top); - - dcMem.SelectObject(oldPen); - gridPenV.DeleteObject(); - gridPenH.DeleteObject(); - } else if (selected) { - CBrush borderBG; - borderBG.CreateSolidBrush(CMPCTheme::ListCtrlDisabledBGColor); - dcMem.FrameRect(rTextBG, &borderBG); - borderBG.DeleteObject(); - } - } - - if (getFlaggedItem(nItem)) { //could be a setting, but flagged items are bold for now - if (!listMPCThemeFontBold.m_hObject) { - listMPCThemeFont = GetFont(); - LOGFONT lf; - listMPCThemeFont->GetLogFont(&lf); - lf.lfWeight = FW_BOLD; - listMPCThemeFontBold.CreateFontIndirect(&lf); - } - - dcMem.SelectObject(listMPCThemeFontBold); - } - dcMem.DrawTextW(text, rText, textFormat); - CMPCThemeUtil::flushMemDC(pDC, dcMem, rectDC); - pDC->SetTextColor(oldTextColor); - pDC->SetBkColor(oldBkColor); - } - } -} - -BOOL CMPCThemePlayerListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - if (AppNeedsThemedControls()) { - NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); - - *pResult = CDRF_DODEFAULT; - if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT) { - if (nullptr != customThemeInterface) { - customThemeInterface->DoCustomPrePaint(); - } - *pResult = CDRF_NOTIFYITEMDRAW; - } else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { - DWORD dwStyle = GetStyle() & LVS_TYPEMASK; - if (LVS_REPORT == dwStyle) { - *pResult = CDRF_NOTIFYSUBITEMDRAW; - } else { - int nItem = static_cast(pLVCD->nmcd.dwItemSpec); - CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); - drawItem(pDC, nItem, 0); - *pResult = CDRF_SKIPDEFAULT; - } - } else if (pLVCD->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM)) { - if (GetStyle() & LVS_OWNERDRAWFIXED) { - //found that for ownerdraw routines, we can end up here and draw both ways on hover/tooltip. this should prevent it - *pResult = CDRF_DODEFAULT; - } else { - int nItem = static_cast(pLVCD->nmcd.dwItemSpec); - if (IsItemVisible(nItem)) { - int nSubItem = pLVCD->iSubItem; - CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); - drawItem(pDC, nItem, nSubItem); - } - *pResult = CDRF_SKIPDEFAULT; - } - } - return TRUE; - } - return FALSE; -} - - -BOOL CMPCThemePlayerListCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppNeedsThemedControls()) { - CRect r; - GetClientRect(r); - int dcState = pDC->SaveDC(); - for (int y = 0; y < GetItemCount(); y++) { - CRect clip; - GetItemRect(y, clip, LVIR_BOUNDS); - pDC->ExcludeClipRect(clip); - } - pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); - - if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { - - CPen gridPen, *oldPen; - gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); - oldPen = pDC->SelectObject(&gridPen); - - if (GetItemCount() > 0) { - CRect gr; - for (int x = 0; x < themedHdrCtrl.GetItemCount(); x++) { - themedHdrCtrl.GetItemRect(x, gr); - pDC->MoveTo(gr.right, r.top); - pDC->LineTo(gr.right, r.bottom); - } - gr.bottom = 0; - for (int y = 0; y < GetItemCount() || gr.bottom < r.bottom; y++) { - if (y >= GetItemCount()) { - gr.OffsetRect(0, gr.Height()); - } else { - GetItemRect(y, gr, LVIR_BOUNDS); - } - { - CPen horzPen; - pDC->MoveTo(r.left, gr.bottom - 1); - if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { - COLORREF horzGridColor, tmp; - customThemeInterface->GetCustomGridColors(y, horzGridColor, tmp); - horzPen.CreatePen(PS_SOLID, 1, horzGridColor); - pDC->SelectObject(&horzPen); - pDC->LineTo(r.right, gr.bottom - 1); - pDC->SelectObject(&gridPen); - horzPen.DeleteObject(); - } else { - pDC->LineTo(r.right, gr.bottom - 1); - } - } - } - } - pDC->SelectObject(oldPen); - gridPen.DeleteObject(); - } - pDC->RestoreDC(dcState); - } else { - return __super::OnEraseBkgnd(pDC); - } - return TRUE; -} - - -HBRUSH CMPCThemePlayerListCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} - - -BOOL CMPCThemePlayerListCtrl::OnHdnEndtrack(UINT id, NMHDR* pNMHDR, LRESULT* pResult) -{ - // LPNMHEADER phdr = reinterpret_cast(pNMHDR); - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - } - *pResult = 0; - - //we don't want to prevent this event from being processed - //it's used when "show windows contents while dragging" is false, - //to draw the outline of the resized column - return FALSE; -} - -LRESULT CMPCThemePlayerListCtrl::OnDelayed_UpdateScrollbar(WPARAM, LPARAM invalidate) -{ - updateScrollInfo((bool)invalidate); - return 0; -} - -BOOL CMPCThemePlayerListCtrl::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) -{ - //LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); - if (AppNeedsThemedControls()) { - ::PostMessage(m_hWnd, PLAYER_PLAYLIST_UPDATE_SCROLLBAR, (WPARAM)0, (LPARAM)0); - } - *pResult = 0; - return FALSE; -} +#include "stdafx.h" +#include "CMPCThemePlayerListCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#undef SubclassWindow + +CMPCThemePlayerListCtrl::CMPCThemePlayerListCtrl() : CListCtrl() +{ + themeGridLines = false; + fullRowSelect = false; + themedSBHelper = nullptr; + hasCheckedColors = false; + hasCBImages = false; + customThemeInterface = nullptr; + if (!CMPCThemeUtil::canUseWin10DarkTheme()) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + } +} + + +CMPCThemePlayerListCtrl::~CMPCThemePlayerListCtrl() +{ + if (nullptr != themedSBHelper) { + delete themedSBHelper; + } +} + + +void CMPCThemePlayerListCtrl::PreSubclassWindow() +{ + if (!AppNeedsThemedControls()) { + EnableToolTips(TRUE); + } else { + if (CMPCThemeUtil::canUseWin10DarkTheme()) { + SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); + } else { + SetWindowTheme(GetSafeHwnd(), L"", NULL); + } + CToolTipCtrl* t = GetToolTips(); + if (nullptr != t) { + lvsToolTip.SubclassWindow(t->m_hWnd); + } + subclassHeader(); + } + CListCtrl::PreSubclassWindow(); +} + +IMPLEMENT_DYNAMIC(CMPCThemePlayerListCtrl, CListCtrl) + +BEGIN_MESSAGE_MAP(CMPCThemePlayerListCtrl, CListCtrl) + ON_WM_NCPAINT() + ON_WM_CREATE() + ON_NOTIFY_REFLECT_EX(LVN_ENDSCROLL, OnLvnEndScroll) + ON_WM_MOUSEMOVE() + ON_WM_MOUSEWHEEL() + ON_WM_NCCALCSIZE() + ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, OnCustomDraw) + ON_WM_ERASEBKGND() + ON_WM_CTLCOLOR() + ON_NOTIFY_EX(HDN_ENDTRACKA, 0, &OnHdnEndtrack) + ON_NOTIFY_EX(HDN_ENDTRACKW, 0, &OnHdnEndtrack) + ON_NOTIFY_REFLECT_EX(LVN_ITEMCHANGED, &OnLvnItemchanged) + ON_MESSAGE(PLAYER_PLAYLIST_UPDATE_SCROLLBAR, OnDelayed_UpdateScrollbar) + ON_WM_WINDOWPOSCHANGED() +END_MESSAGE_MAP() + +void CMPCThemePlayerListCtrl::OnWindowPosChanged(WINDOWPOS* lpwndpos) { + if (AppNeedsThemedControls()) { + if (themedSBHelper && 0 != (GetStyle() & (WS_VSCROLL | WS_HSCROLL))) { + themedSBHelper->OnWindowPosChanged(); + } + } + return __super::OnWindowPosChanged(lpwndpos); +} + + +void CMPCThemePlayerListCtrl::subclassHeader() +{ + CHeaderCtrl* t = GetHeaderCtrl(); + if (nullptr != t && IsWindow(t->m_hWnd) && themedHdrCtrl.m_hWnd == NULL) { + themedHdrCtrl.SubclassWindow(t->GetSafeHwnd()); + } +} + +void CMPCThemePlayerListCtrl::setAdditionalStyles(DWORD styles) +{ + if (AppNeedsThemedControls()) { + DWORD stylesToAdd = styles, stylesToRemove = 0; + if (styles & LVS_EX_GRIDLINES) { + stylesToAdd &= ~LVS_EX_GRIDLINES; + stylesToRemove |= LVS_EX_GRIDLINES; + themeGridLines = true; + } + if (styles & LVS_EX_FULLROWSELECT) { + //we need these to remain, or else other columns may not get refreshed on a selection change. + //no regressions observed yet, but unclear why we removed this style for custom draw previously + //error was observed with playersubresyncbar + // stylesToAdd &= ~LVS_EX_FULLROWSELECT; + // stylesToRemove |= LVS_EX_FULLROWSELECT; + fullRowSelect = true; + } + if (styles & LVS_EX_DOUBLEBUFFER) { //we will buffer ourselves + stylesToAdd &= ~LVS_EX_DOUBLEBUFFER; + stylesToRemove |= LVS_EX_DOUBLEBUFFER; + } + SetExtendedStyle((GetExtendedStyle() | stylesToAdd) & ~stylesToRemove); + } else { + SetExtendedStyle(GetExtendedStyle() | styles); + } +} + +void CMPCThemePlayerListCtrl::setHasCBImages(bool on) +{ + hasCBImages = on; +} + +void CMPCThemePlayerListCtrl::setItemTextWithDefaultFlag(int nItem, int nSubItem, LPCTSTR lpszText, bool flagged) +{ + SetItemText(nItem, nSubItem, lpszText); + setFlaggedItem(nItem, flagged); +} + +void CMPCThemePlayerListCtrl::setFlaggedItem(int iItem, bool flagged) +{ + flaggedItems[iItem] = flagged; +} + +bool CMPCThemePlayerListCtrl::getFlaggedItem(int iItem) +{ + auto it = flaggedItems.find(iItem); + if (it != flaggedItems.end()) { + return it->second; + } else { + return false; + } +} + +void CMPCThemePlayerListCtrl::DoDPIChanged() +{ + if (listMPCThemeFontBold.m_hObject) { + listMPCThemeFontBold.DeleteObject(); + } + +} + + +BOOL CMPCThemePlayerListCtrl::PreTranslateMessage(MSG* pMsg) +{ + if (AppNeedsThemedControls()) { + if (!IsWindow(themedToolTip.m_hWnd)) { + themedToolTip.Create(this, TTS_ALWAYSTIP); + themedToolTip.enableFlickerHelper(); + } + if (IsWindow(themedToolTip.m_hWnd)) { + themedToolTip.RelayEvent(pMsg); + } + } + return __super::PreTranslateMessage(pMsg); +} + +void CMPCThemePlayerListCtrl::setCheckedColors(COLORREF checkedBG, COLORREF checkedText, COLORREF uncheckedText) +{ + checkedBGClr = checkedBG; + checkedTextClr = checkedText; + uncheckedTextClr = uncheckedText; + hasCheckedColors = true; +} + +void CMPCThemePlayerListCtrl::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->themedNcPaintWithSB(); + } else { + CMPCThemeScrollBarHelper::themedNcPaint(this, this); + } + } else { + __super::OnNcPaint(); + } +} + + +int CMPCThemePlayerListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (__super::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + if (AppNeedsThemedControls()) { + SetBkColor(CMPCTheme::ContentBGColor); + subclassHeader(); + } + + return 0; +} + +BOOL CMPCThemePlayerListCtrl::OnLvnEndScroll(NMHDR* pNMHDR, LRESULT* pResult) +{ + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + *pResult = 0; + } + return FALSE; +} + +void CMPCThemePlayerListCtrl::updateSB() +{ + if (nullptr != themedSBHelper) { + themedSBHelper->hideNativeScrollBars(); + } +} + +void CMPCThemePlayerListCtrl::updateScrollInfo(bool invalidate /*=false*/) +{ + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(invalidate); + } +} + +LRESULT CMPCThemePlayerListCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (AppNeedsThemedControls() && nullptr != themedSBHelper) { + if (themedSBHelper->WindowProc(this, message, wParam, lParam)) { + return 1; + } + } + return __super::WindowProc(message, wParam, lParam); +} + +void CMPCThemePlayerListCtrl::updateToolTip(CPoint point) +{ + if (AppNeedsThemedControls() && nullptr != themedToolTip) { + TOOLINFO ti = { 0 }; + UINT_PTR tid = OnToolHitTest(point, &ti); + //OnToolHitTest returns -1 on failure but doesn't update uId to match + + if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool + if (themedToolTip.GetToolCount() > 0) { + themedToolTip.DelTool(this); + themedToolTip.Activate(FALSE); + } + themedToolTipCid = (UINT_PTR) - 1; + } + + if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { + + themedToolTipCid = ti.uId; + + CRect cr; + GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate + + themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); + themedToolTip.Activate(TRUE); + } + } +} + +void CMPCThemePlayerListCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + __super::OnMouseMove(nFlags, point); + updateToolTip(point); +} + + +BOOL CMPCThemePlayerListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + BOOL ret = __super::OnMouseWheel(nFlags, zDelta, pt); + ScreenToClient(&pt); + updateToolTip(pt); + return ret; +} + + +void CMPCThemePlayerListCtrl::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) +{ + __super::OnNcCalcSize(bCalcValidRects, lpncsp); + if (AppNeedsThemedControls()) { + if (GetStyle() & WS_HSCROLL && nullptr == themedSBHelper) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + } + ::PostMessage(m_hWnd, PLAYER_PLAYLIST_UPDATE_SCROLLBAR, (WPARAM)0, (LPARAM)TRUE); + } +} + +void CMPCThemePlayerListCtrl::drawItem(CDC* pDC, int nItem, int nSubItem) +{ + if (IsItemVisible(nItem)) { + + CRect rect, rRow, rIcon, rText, rTextBG, rectDC, rClient; + GetClientRect(rClient); + GetItemRect(nItem, rRow, LVIR_BOUNDS); + GetSubItemRect(nItem, nSubItem, LVIR_LABEL, rText); + GetSubItemRect(nItem, nSubItem, LVIR_ICON, rIcon); + GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect); + DWORD dwStyle = GetStyle() & LVS_TYPEMASK; + + if (0 == nSubItem) { //getsubitemrect gives whole row for 0/LVIR_BOUNDS. but LVIR_LABEL is limited to text bounds. MSDN undocumented behavior + rect.right = rText.right; + } + + //issubitemvisible + if (rClient.left <= rect.right && rClient.right >= rect.left && rClient.top <= rect.bottom && rClient.bottom >= rect.top) { + COLORREF textColor = CMPCTheme::TextFGColor; + COLORREF bgColor = CMPCTheme::ContentBGColor; + COLORREF selectedBGColor = CMPCTheme::ContentSelectedColor; + + COLORREF oldTextColor = pDC->GetTextColor(); + COLORREF oldBkColor = pDC->GetBkColor(); + + CString text = GetItemText(nItem, nSubItem); + if (nullptr != customThemeInterface) { //subclasses can override colors here + bool overrideSelectedBG = false; + customThemeInterface->GetCustomTextColors(nItem, nSubItem, textColor, bgColor, overrideSelectedBG); + if (overrideSelectedBG) { + selectedBGColor = bgColor; + } + } + + pDC->SetTextColor(textColor); + pDC->SetBkColor(bgColor); + + rectDC = rRow; + CDC dcMem; + CBitmap bmMem; + CMPCThemeUtil::initMemDC(pDC, dcMem, bmMem, rectDC); + rect.OffsetRect(-rectDC.TopLeft()); + rText.OffsetRect(-rectDC.TopLeft()); + rIcon.OffsetRect(-rectDC.TopLeft()); + rRow.OffsetRect(-rectDC.TopLeft()); + + if (!IsWindowEnabled() && 0 == nSubItem) { //no gridlines, bg for full row + dcMem.FillSolidRect(rRow, CMPCTheme::ListCtrlDisabledBGColor); + } else { + dcMem.FillSolidRect(rect, CMPCTheme::ContentBGColor); //no flicker because we have a memory dc + } + + rTextBG = rText; + CHeaderCtrl* hdrCtrl = GetHeaderCtrl(); + int align = DT_LEFT; + if (nullptr != hdrCtrl) { + HDITEM hditem = { 0 }; + hditem.mask = HDI_FORMAT; + hdrCtrl->GetItem(nSubItem, &hditem); + align = hditem.fmt & HDF_JUSTIFYMASK; + } + UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX; + if (align == HDF_CENTER) { + textFormat |= DT_CENTER; + } else if (align == HDF_LEFT) { + textFormat |= DT_LEFT; + if (nSubItem == 0) {//less indent for first column + rText.left += 2; + } else { + rText.left += 6; + } + } else { + textFormat |= DT_RIGHT; + rText.right -= 6; + } + + bool isChecked = false; + int contentLeft = rText.left; + if (rIcon.Width() > 0) { + LVITEM lvi = { 0 }; + lvi.iItem = nItem; + lvi.iSubItem = 0; + lvi.mask = LVIF_IMAGE; + GetItem(&lvi); + + if (nSubItem == 0) { + contentLeft = rIcon.left; + if (hasCBImages) { //draw manually to match theme + rIcon.DeflateRect(0, 0, 1, 0); + if (rIcon.Height() > rIcon.Width()) { + rIcon.DeflateRect(0, (rIcon.Height() - rIcon.Width()) / 2); //as tall as wide + } + + CMPCThemeUtil::drawCheckBox(GetParent(), lvi.iImage, false, false, rIcon, &dcMem); + } else { + if (dwStyle == LVS_ICON) { + } else if (dwStyle == LVS_SMALLICON || dwStyle == LVS_LIST || dwStyle == LVS_REPORT) { + CImageList* ilist = GetImageList(LVSIL_SMALL); + int cx, cy; + ImageList_GetIconSize(ilist->m_hImageList, &cx, &cy); + rIcon.top += (rIcon.Height() - cy) / 2; + ilist->Draw(&dcMem, lvi.iImage, rIcon.TopLeft(), ILD_TRANSPARENT); + } + } + if (align == HDF_LEFT) { + rText.left += 2; //more ident after image + } + } + } + if (0 != (GetExtendedStyle() & LVS_EX_CHECKBOXES) && INDEXTOSTATEIMAGEMASK(0) != GetItemState(nItem, LVIS_STATEIMAGEMASK)) { + isChecked = (TRUE == GetCheck(nItem)); + if (nSubItem == 0) { + int cbSize = GetSystemMetrics(SM_CXMENUCHECK); + int cbYMargin = (rect.Height() - cbSize - 1) / 2; + int cbXMargin = (contentLeft - rect.left - cbSize) / 2; + CRect rcb = { rect.left + cbXMargin, rect.top + cbYMargin, rect.left + cbXMargin + cbSize, rect.top + cbYMargin + cbSize }; + CMPCThemeUtil::drawCheckBox(GetParent(), isChecked, false, true, rcb, &dcMem); + } + } + + if (IsWindowEnabled()) { + bool selected = false; + if (GetItemState(nItem, LVIS_SELECTED) == LVIS_SELECTED && (nSubItem == 0 || fullRowSelect) && (GetStyle() & LVS_SHOWSELALWAYS || GetFocus() == this)) { + bgColor = selectedBGColor; + if (LVS_REPORT != dwStyle) { //in list mode we don't fill the "whole" column + CRect tmp = rText; + dcMem.DrawTextW(text, tmp, textFormat | DT_CALCRECT); //end of string + rTextBG.right = tmp.right + (rText.left - rTextBG.left); //end of string plus same indent from the left side + } + selected = true; + } else if (hasCheckedColors) { + if (isChecked && checkedBGClr != -1) { + bgColor = checkedBGClr; + } + if (isChecked && checkedTextClr != -1) { + dcMem.SetTextColor(checkedTextClr); + } + if (!isChecked && uncheckedTextClr != -1) { + dcMem.SetTextColor(uncheckedTextClr); + } + } + dcMem.FillSolidRect(rTextBG, bgColor); + + if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { + CRect rGrid = rect; + rGrid.bottom -= 1; + CPen gridPenV, gridPenH, *oldPen; + if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { + COLORREF horzGridColor, vertGridColor; + customThemeInterface->GetCustomGridColors(nItem, horzGridColor, vertGridColor); + gridPenV.CreatePen(PS_SOLID, 1, vertGridColor); + gridPenH.CreatePen(PS_SOLID, 1, horzGridColor); + } else { + gridPenV.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); + gridPenH.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); + } + + oldPen = dcMem.SelectObject(&gridPenV); + if (nSubItem != 0) { + dcMem.MoveTo(rGrid.TopLeft()); + dcMem.LineTo(rGrid.left, rGrid.bottom); + } else { + dcMem.MoveTo(rGrid.left, rGrid.bottom); + } + + dcMem.SelectObject(&gridPenH); + dcMem.LineTo(rGrid.BottomRight()); + + dcMem.SelectObject(&gridPenV); + dcMem.LineTo(rGrid.right, rGrid.top); + + dcMem.SelectObject(oldPen); + gridPenV.DeleteObject(); + gridPenH.DeleteObject(); + } else if (selected) { + CBrush borderBG; + borderBG.CreateSolidBrush(CMPCTheme::ListCtrlDisabledBGColor); + dcMem.FrameRect(rTextBG, &borderBG); + borderBG.DeleteObject(); + } + } + + if (getFlaggedItem(nItem)) { //could be a setting, but flagged items are bold for now + if (!listMPCThemeFontBold.m_hObject) { + listMPCThemeFont = GetFont(); + LOGFONT lf; + listMPCThemeFont->GetLogFont(&lf); + lf.lfWeight = FW_BOLD; + listMPCThemeFontBold.CreateFontIndirect(&lf); + } + + dcMem.SelectObject(listMPCThemeFontBold); + } + dcMem.DrawTextW(text, rText, textFormat); + CMPCThemeUtil::flushMemDC(pDC, dcMem, rectDC); + pDC->SetTextColor(oldTextColor); + pDC->SetBkColor(oldBkColor); + } + } +} + +BOOL CMPCThemePlayerListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + if (AppNeedsThemedControls()) { + NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); + + *pResult = CDRF_DODEFAULT; + if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT) { + if (nullptr != customThemeInterface) { + customThemeInterface->DoCustomPrePaint(); + } + *pResult = CDRF_NOTIFYITEMDRAW; + } else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { + DWORD dwStyle = GetStyle() & LVS_TYPEMASK; + if (LVS_REPORT == dwStyle) { + *pResult = CDRF_NOTIFYSUBITEMDRAW; + } else { + int nItem = static_cast(pLVCD->nmcd.dwItemSpec); + CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); + drawItem(pDC, nItem, 0); + *pResult = CDRF_SKIPDEFAULT; + } + } else if (pLVCD->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM)) { + if (GetStyle() & LVS_OWNERDRAWFIXED) { + //found that for ownerdraw routines, we can end up here and draw both ways on hover/tooltip. this should prevent it + *pResult = CDRF_DODEFAULT; + } else { + int nItem = static_cast(pLVCD->nmcd.dwItemSpec); + if (IsItemVisible(nItem)) { + int nSubItem = pLVCD->iSubItem; + CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc); + drawItem(pDC, nItem, nSubItem); + } + *pResult = CDRF_SKIPDEFAULT; + } + } + return TRUE; + } + return FALSE; +} + + +BOOL CMPCThemePlayerListCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppNeedsThemedControls()) { + CRect r; + GetClientRect(r); + int dcState = pDC->SaveDC(); + for (int y = 0; y < GetItemCount(); y++) { + CRect clip; + GetItemRect(y, clip, LVIR_BOUNDS); + pDC->ExcludeClipRect(clip); + } + pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); + + if (themeGridLines || (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid())) { + + CPen gridPen, *oldPen; + gridPen.CreatePen(PS_SOLID, 1, CMPCTheme::ListCtrlGridColor); + oldPen = pDC->SelectObject(&gridPen); + + if (GetItemCount() > 0) { + CRect gr; + for (int x = 0; x < themedHdrCtrl.GetItemCount(); x++) { + themedHdrCtrl.GetItemRect(x, gr); + pDC->MoveTo(gr.right, r.top); + pDC->LineTo(gr.right, r.bottom); + } + gr.bottom = 0; + for (int y = 0; y < GetItemCount() || gr.bottom < r.bottom; y++) { + if (y >= GetItemCount()) { + gr.OffsetRect(0, gr.Height()); + } else { + GetItemRect(y, gr, LVIR_BOUNDS); + } + { + CPen horzPen; + pDC->MoveTo(r.left, gr.bottom - 1); + if (nullptr != customThemeInterface && customThemeInterface->UseCustomGrid()) { + COLORREF horzGridColor, tmp; + customThemeInterface->GetCustomGridColors(y, horzGridColor, tmp); + horzPen.CreatePen(PS_SOLID, 1, horzGridColor); + pDC->SelectObject(&horzPen); + pDC->LineTo(r.right, gr.bottom - 1); + pDC->SelectObject(&gridPen); + horzPen.DeleteObject(); + } else { + pDC->LineTo(r.right, gr.bottom - 1); + } + } + } + } + pDC->SelectObject(oldPen); + gridPen.DeleteObject(); + } + pDC->RestoreDC(dcState); + } else { + return __super::OnEraseBkgnd(pDC); + } + return TRUE; +} + + +HBRUSH CMPCThemePlayerListCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} + + +BOOL CMPCThemePlayerListCtrl::OnHdnEndtrack(UINT id, NMHDR* pNMHDR, LRESULT* pResult) +{ + // LPNMHEADER phdr = reinterpret_cast(pNMHDR); + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + } + *pResult = 0; + + //we don't want to prevent this event from being processed + //it's used when "show windows contents while dragging" is false, + //to draw the outline of the resized column + return FALSE; +} + +LRESULT CMPCThemePlayerListCtrl::OnDelayed_UpdateScrollbar(WPARAM, LPARAM invalidate) +{ + updateScrollInfo((bool)invalidate); + return 0; +} + +BOOL CMPCThemePlayerListCtrl::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + //LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); + if (AppNeedsThemedControls()) { + ::PostMessage(m_hWnd, PLAYER_PLAYLIST_UPDATE_SCROLLBAR, (WPARAM)0, (LPARAM)0); + } + *pResult = 0; + return FALSE; +} diff --git a/src/mpc-hc/CMPCThemePlayerListCtrl.h b/src/mpc-hc/CMPCThemePlayerListCtrl.h index a59fb3c9aa5..0624e60a36d 100755 --- a/src/mpc-hc/CMPCThemePlayerListCtrl.h +++ b/src/mpc-hc/CMPCThemePlayerListCtrl.h @@ -1,74 +1,74 @@ -#pragma once -#include "CMPCThemeScrollBarHelper.h" -#include "CMPCThemeToolTipCtrl.h" -#include "CMPCThemeUtil.h" -#include "CMPCThemeHeaderCtrl.h" - -//undocumented state changes for LVS_EX_CHECKBOXES -#define LVIS_UNCHECKED 0x1000 -#define LVIS_CHECKED 0x2000 - -class CMPCThemeListCtrlCustomInterface -{ -public: - virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) = 0; - virtual void DoCustomPrePaint() = 0; - virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) = 0; - virtual bool UseCustomGrid() { return true; }; -}; - -class CMPCThemePlayerListCtrl : public CListCtrl, CMPCThemeUtil, CMPCThemeScrollable -{ -public: - CMPCThemePlayerListCtrl(); - virtual ~CMPCThemePlayerListCtrl(); - DECLARE_DYNAMIC(CMPCThemePlayerListCtrl) - - void updateSB(); - void updateScrollInfo(bool invalidate = false); - LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - void updateToolTip(CPoint point); - virtual BOOL PreTranslateMessage(MSG* pMsg); - void setCheckedColors(COLORREF checkedBG, COLORREF checkedText, COLORREF uncheckedText); - void subclassHeader(); - void setAdditionalStyles(DWORD styles); - void setHasCBImages(bool on); - void setItemTextWithDefaultFlag(int nItem, int nSubItem, LPCTSTR lpszText, bool flagged); - void setFlaggedItem(int iItem, bool flagged); - bool getFlaggedItem(int iItem); - void setColorInterface(CMPCThemeListCtrlCustomInterface* iface) { customThemeInterface = iface; }; - void DoDPIChanged(); - - DECLARE_MESSAGE_MAP() - afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); - afx_msg void OnNcPaint(); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg BOOL OnLvnEndScroll(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); - afx_msg BOOL OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - CMPCThemeScrollBarHelper* themedSBHelper; - CMPCThemeToolTipCtrl themedToolTip, lvsToolTip; - UINT_PTR themedToolTipCid; - COLORREF checkedBGClr, checkedTextClr, uncheckedTextClr; - std::map flaggedItems; - bool hasCheckedColors; - bool hasCBImages; - bool themeGridLines; - bool fullRowSelect; - CMPCThemeHeaderCtrl themedHdrCtrl; - CFont* listMPCThemeFont, listMPCThemeFontBold; - CMPCThemeListCtrlCustomInterface* customThemeInterface; - void drawItem(CDC* pDC, int nItem, int nSubItem); - virtual void PreSubclassWindow(); -public: - void doDefault() { Default(); }; - afx_msg BOOL OnHdnEndtrack(UINT id, NMHDR* pNMHDR, LRESULT* pResult); - afx_msg LRESULT OnDelayed_UpdateScrollbar(WPARAM, LPARAM); - afx_msg BOOL OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); -}; - +#pragma once +#include "CMPCThemeScrollBarHelper.h" +#include "CMPCThemeToolTipCtrl.h" +#include "CMPCThemeUtil.h" +#include "CMPCThemeHeaderCtrl.h" + +//undocumented state changes for LVS_EX_CHECKBOXES +#define LVIS_UNCHECKED 0x1000 +#define LVIS_CHECKED 0x2000 + +class CMPCThemeListCtrlCustomInterface +{ +public: + virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) = 0; + virtual void DoCustomPrePaint() = 0; + virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) = 0; + virtual bool UseCustomGrid() { return true; }; +}; + +class CMPCThemePlayerListCtrl : public CListCtrl, CMPCThemeUtil, CMPCThemeScrollable +{ +public: + CMPCThemePlayerListCtrl(); + virtual ~CMPCThemePlayerListCtrl(); + DECLARE_DYNAMIC(CMPCThemePlayerListCtrl) + + void updateSB(); + void updateScrollInfo(bool invalidate = false); + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + void updateToolTip(CPoint point); + virtual BOOL PreTranslateMessage(MSG* pMsg); + void setCheckedColors(COLORREF checkedBG, COLORREF checkedText, COLORREF uncheckedText); + void subclassHeader(); + void setAdditionalStyles(DWORD styles); + void setHasCBImages(bool on); + void setItemTextWithDefaultFlag(int nItem, int nSubItem, LPCTSTR lpszText, bool flagged); + void setFlaggedItem(int iItem, bool flagged); + bool getFlaggedItem(int iItem); + void setColorInterface(CMPCThemeListCtrlCustomInterface* iface) { customThemeInterface = iface; }; + void DoDPIChanged(); + + DECLARE_MESSAGE_MAP() + afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos); + afx_msg void OnNcPaint(); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg BOOL OnLvnEndScroll(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); + afx_msg BOOL OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + CMPCThemeScrollBarHelper* themedSBHelper; + CMPCThemeToolTipCtrl themedToolTip, lvsToolTip; + UINT_PTR themedToolTipCid; + COLORREF checkedBGClr, checkedTextClr, uncheckedTextClr; + std::map flaggedItems; + bool hasCheckedColors; + bool hasCBImages; + bool themeGridLines; + bool fullRowSelect; + CMPCThemeHeaderCtrl themedHdrCtrl; + CFont* listMPCThemeFont, listMPCThemeFontBold; + CMPCThemeListCtrlCustomInterface* customThemeInterface; + void drawItem(CDC* pDC, int nItem, int nSubItem); + virtual void PreSubclassWindow(); +public: + void doDefault() { Default(); }; + afx_msg BOOL OnHdnEndtrack(UINT id, NMHDR* pNMHDR, LRESULT* pResult); + afx_msg LRESULT OnDelayed_UpdateScrollbar(WPARAM, LPARAM); + afx_msg BOOL OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); +}; + diff --git a/src/mpc-hc/CMPCThemePropPageFrame.cpp b/src/mpc-hc/CMPCThemePropPageFrame.cpp index ac05e806341..b4534b508f9 100755 --- a/src/mpc-hc/CMPCThemePropPageFrame.cpp +++ b/src/mpc-hc/CMPCThemePropPageFrame.cpp @@ -1,98 +1,98 @@ -#include "stdafx.h" -#include "CMPCThemePropPageFrame.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "TreePropSheet/PropPageFrameDefault.h" -#include "../DSUtil/WinAPIUtils.h" - -CBrush CMPCThemePropPageFrame::mpcThemeBorderBrush; - -CMPCThemePropPageFrame::CMPCThemePropPageFrame() : CPropPageFrameDefault() -{ - if (nullptr == mpcThemeBorderBrush.m_hObject) { - mpcThemeBorderBrush.CreateSolidBrush(CMPCTheme::WindowBorderColorLight); - } -} - - -CMPCThemePropPageFrame::~CMPCThemePropPageFrame() -{ -} - -BEGIN_MESSAGE_MAP(CMPCThemePropPageFrame, CPropPageFrameDefault) - ON_WM_PAINT() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - - -BOOL CMPCThemePropPageFrame::Create(DWORD dwWindowStyle, const RECT& rect, CWnd* pwndParent, UINT nID) -{ - return CWnd::Create( - AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), 0), - _T("MPCTheme Page Frame"), - dwWindowStyle, rect, pwndParent, nID); -} - -CWnd* CMPCThemePropPageFrame::GetWnd() -{ - return static_cast(this); -} - -void CMPCThemePropPageFrame::DrawCaption(CDC* pDC, CRect rect, LPCTSTR lpszCaption, HICON hIcon) -{ - COLORREF clrLeft = CMPCTheme::ContentSelectedColor; - COLORREF clrRight = CMPCTheme::ContentBGColor; - FillGradientRectH(pDC, rect, clrLeft, clrRight); - - rect.left += 2; - - COLORREF clrPrev = pDC->SetTextColor(CMPCTheme::PropPageCaptionFGColor); - int nBkStyle = pDC->SetBkMode(TRANSPARENT); - - LOGFONT lf; - GetMessageFont(&lf); - lf.lfHeight = static_cast(-.8f * rect.Height()); - lf.lfWeight = FW_BOLD; - CFont f; - f.CreateFontIndirectW(&lf); - CFont* oldFont = pDC->SelectObject(&f); - - TEXTMETRIC GDIMetrics; - GetTextMetricsW(pDC->GetSafeHdc(), &GDIMetrics); - while (GDIMetrics.tmHeight > rect.Height() && abs(lf.lfHeight) > 10) { - pDC->SelectObject(oldFont); - f.DeleteObject(); - lf.lfHeight++; - f.CreateFontIndirectW(&lf); - pDC->SelectObject(&f); - GetTextMetricsW(pDC->GetSafeHdc(), &GDIMetrics); - } - - - rect.top -= GDIMetrics.tmDescent - 1; - - pDC->DrawTextW(lpszCaption, rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); // DT_NOPREFIX not needed - - pDC->SetTextColor(clrPrev); - pDC->SelectObject(oldFont); - pDC->SetBkMode(nBkStyle); -} - -void CMPCThemePropPageFrame::OnPaint() -{ - CPaintDC dc(this); - Draw(&dc); -} - -BOOL CMPCThemePropPageFrame::OnEraseBkgnd(CDC* pDC) -{ - bool ret = CMPCThemeUtil::MPCThemeEraseBkgnd(pDC, this, CTLCOLOR_DLG); - if (ret) { - CRect rect; - GetClientRect(rect); - pDC->FrameRect(rect, &mpcThemeBorderBrush); - return ret; - } else { - return __super::OnEraseBkgnd(pDC); - } -} +#include "stdafx.h" +#include "CMPCThemePropPageFrame.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "TreePropSheet/PropPageFrameDefault.h" +#include "../DSUtil/WinAPIUtils.h" + +CBrush CMPCThemePropPageFrame::mpcThemeBorderBrush; + +CMPCThemePropPageFrame::CMPCThemePropPageFrame() : CPropPageFrameDefault() +{ + if (nullptr == mpcThemeBorderBrush.m_hObject) { + mpcThemeBorderBrush.CreateSolidBrush(CMPCTheme::WindowBorderColorLight); + } +} + + +CMPCThemePropPageFrame::~CMPCThemePropPageFrame() +{ +} + +BEGIN_MESSAGE_MAP(CMPCThemePropPageFrame, CPropPageFrameDefault) + ON_WM_PAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + +BOOL CMPCThemePropPageFrame::Create(DWORD dwWindowStyle, const RECT& rect, CWnd* pwndParent, UINT nID) +{ + return CWnd::Create( + AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), 0), + _T("MPCTheme Page Frame"), + dwWindowStyle, rect, pwndParent, nID); +} + +CWnd* CMPCThemePropPageFrame::GetWnd() +{ + return static_cast(this); +} + +void CMPCThemePropPageFrame::DrawCaption(CDC* pDC, CRect rect, LPCTSTR lpszCaption, HICON hIcon) +{ + COLORREF clrLeft = CMPCTheme::ContentSelectedColor; + COLORREF clrRight = CMPCTheme::ContentBGColor; + FillGradientRectH(pDC, rect, clrLeft, clrRight); + + rect.left += 2; + + COLORREF clrPrev = pDC->SetTextColor(CMPCTheme::PropPageCaptionFGColor); + int nBkStyle = pDC->SetBkMode(TRANSPARENT); + + LOGFONT lf; + GetMessageFont(&lf); + lf.lfHeight = static_cast(-.8f * rect.Height()); + lf.lfWeight = FW_BOLD; + CFont f; + f.CreateFontIndirectW(&lf); + CFont* oldFont = pDC->SelectObject(&f); + + TEXTMETRIC GDIMetrics; + GetTextMetricsW(pDC->GetSafeHdc(), &GDIMetrics); + while (GDIMetrics.tmHeight > rect.Height() && abs(lf.lfHeight) > 10) { + pDC->SelectObject(oldFont); + f.DeleteObject(); + lf.lfHeight++; + f.CreateFontIndirectW(&lf); + pDC->SelectObject(&f); + GetTextMetricsW(pDC->GetSafeHdc(), &GDIMetrics); + } + + + rect.top -= GDIMetrics.tmDescent - 1; + + pDC->DrawTextW(lpszCaption, rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); // DT_NOPREFIX not needed + + pDC->SetTextColor(clrPrev); + pDC->SelectObject(oldFont); + pDC->SetBkMode(nBkStyle); +} + +void CMPCThemePropPageFrame::OnPaint() +{ + CPaintDC dc(this); + Draw(&dc); +} + +BOOL CMPCThemePropPageFrame::OnEraseBkgnd(CDC* pDC) +{ + bool ret = CMPCThemeUtil::MPCThemeEraseBkgnd(pDC, this, CTLCOLOR_DLG); + if (ret) { + CRect rect; + GetClientRect(rect); + pDC->FrameRect(rect, &mpcThemeBorderBrush); + return ret; + } else { + return __super::OnEraseBkgnd(pDC); + } +} diff --git a/src/mpc-hc/CMPCThemePropPageFrame.h b/src/mpc-hc/CMPCThemePropPageFrame.h index 875a53b5317..0c5c659727e 100755 --- a/src/mpc-hc/CMPCThemePropPageFrame.h +++ b/src/mpc-hc/CMPCThemePropPageFrame.h @@ -1,19 +1,19 @@ -#pragma once -#include "TreePropSheet/PropPageFrameDefault.h" -class CMPCThemePropPageFrame : public TreePropSheet::CPropPageFrameDefault -{ -public: - CMPCThemePropPageFrame(); - virtual ~CMPCThemePropPageFrame(); - virtual BOOL Create(DWORD dwWindowStyle, const RECT& rect, CWnd* pwndParent, UINT nID); - virtual CWnd* GetWnd(); - - virtual void DrawCaption(CDC* pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); - - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - DECLARE_MESSAGE_MAP() -protected: - static CBrush mpcThemeBorderBrush; -}; - +#pragma once +#include "TreePropSheet/PropPageFrameDefault.h" +class CMPCThemePropPageFrame : public TreePropSheet::CPropPageFrameDefault +{ +public: + CMPCThemePropPageFrame(); + virtual ~CMPCThemePropPageFrame(); + virtual BOOL Create(DWORD dwWindowStyle, const RECT& rect, CWnd* pwndParent, UINT nID); + virtual CWnd* GetWnd(); + + virtual void DrawCaption(CDC* pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); + + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + DECLARE_MESSAGE_MAP() +protected: + static CBrush mpcThemeBorderBrush; +}; + diff --git a/src/mpc-hc/CMPCThemePropertyPage.cpp b/src/mpc-hc/CMPCThemePropertyPage.cpp index 286ec5ab1ba..2166286c9c5 100755 --- a/src/mpc-hc/CMPCThemePropertyPage.cpp +++ b/src/mpc-hc/CMPCThemePropertyPage.cpp @@ -1,36 +1,36 @@ -#include "stdafx.h" -#include "CMPCThemePropertyPage.h" - -CMPCThemePropertyPage::CMPCThemePropertyPage(UINT nIDTemplate, UINT nIDCaption) - : CPropertyPage(nIDTemplate, nIDCaption) -{ - -} - -CMPCThemePropertyPage::~CMPCThemePropertyPage() -{ -} - -BOOL CMPCThemePropertyPage::OnInitDialog() -{ - __super::OnInitDialog(); - fulfillThemeReqs(); - return 0; -} - -IMPLEMENT_DYNAMIC(CMPCThemePropertyPage, CPropertyPage) -BEGIN_MESSAGE_MAP(CMPCThemePropertyPage, CPropertyPage) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemePropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH ret; - ret = getCtlColor(pDC, pWnd, nCtlColor); - if (nullptr != ret) { - return ret; - } else { - return __super::OnCtlColor(pDC, pWnd, nCtlColor); - } -} +#include "stdafx.h" +#include "CMPCThemePropertyPage.h" + +CMPCThemePropertyPage::CMPCThemePropertyPage(UINT nIDTemplate, UINT nIDCaption) + : CPropertyPage(nIDTemplate, nIDCaption) +{ + +} + +CMPCThemePropertyPage::~CMPCThemePropertyPage() +{ +} + +BOOL CMPCThemePropertyPage::OnInitDialog() +{ + __super::OnInitDialog(); + fulfillThemeReqs(); + return 0; +} + +IMPLEMENT_DYNAMIC(CMPCThemePropertyPage, CPropertyPage) +BEGIN_MESSAGE_MAP(CMPCThemePropertyPage, CPropertyPage) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemePropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH ret; + ret = getCtlColor(pDC, pWnd, nCtlColor); + if (nullptr != ret) { + return ret; + } else { + return __super::OnCtlColor(pDC, pWnd, nCtlColor); + } +} diff --git a/src/mpc-hc/CMPCThemePropertyPage.h b/src/mpc-hc/CMPCThemePropertyPage.h index 08ed45b2122..3b81ce021e5 100755 --- a/src/mpc-hc/CMPCThemePropertyPage.h +++ b/src/mpc-hc/CMPCThemePropertyPage.h @@ -1,19 +1,19 @@ -#pragma once -#include "CMPCThemeUtil.h" -class CMPCThemePropertyPage : public CPropertyPage, public CMPCThemeUtil -{ -public: - CMPCThemePropertyPage(UINT nIDTemplate, UINT nIDCaption); - virtual ~CMPCThemePropertyPage(); - - - void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; - DECLARE_DYNAMIC(CMPCThemePropertyPage) - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - virtual BOOL OnInitDialog(); - -}; - +#pragma once +#include "CMPCThemeUtil.h" +class CMPCThemePropertyPage : public CPropertyPage, public CMPCThemeUtil +{ +public: + CMPCThemePropertyPage(UINT nIDTemplate, UINT nIDCaption); + virtual ~CMPCThemePropertyPage(); + + + void fulfillThemeReqs() { CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); }; + DECLARE_DYNAMIC(CMPCThemePropertyPage) + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + virtual BOOL OnInitDialog(); + +}; + diff --git a/src/mpc-hc/CMPCThemePropertySheet.cpp b/src/mpc-hc/CMPCThemePropertySheet.cpp index 84e1ec0ad3d..17b77a65219 100755 --- a/src/mpc-hc/CMPCThemePropertySheet.cpp +++ b/src/mpc-hc/CMPCThemePropertySheet.cpp @@ -1,66 +1,66 @@ -#include "stdafx.h" -#include "CMPCThemePropertySheet.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - - -CMPCThemePropertySheet::CMPCThemePropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) - : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) - ,isModal(false) -{ -} - -CMPCThemePropertySheet::CMPCThemePropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) - : CPropertySheet(pszCaption, pParentWnd, iSelectPage) - ,isModal(false) -{ -} - -CMPCThemePropertySheet::~CMPCThemePropertySheet() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemePropertySheet, CPropertySheet) -BEGIN_MESSAGE_MAP(CMPCThemePropertySheet, CPropertySheet) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - -BOOL CMPCThemePropertySheet::OnInitDialog() -{ - BOOL bResult = __super::OnInitDialog(); - fulfillThemeReqs(); - return bResult; -} - -void CMPCThemePropertySheet::fulfillThemeReqs() -{ - if (AppNeedsThemedControls()) { - CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); - if (isModal) { //propsheets not normally modal, but if so... - CMPCThemeUtil::enableWindows10DarkFrame(this); - } - } -} - -HBRUSH CMPCThemePropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppNeedsThemedControls()) { - LRESULT lResult; - if (pWnd->SendChildNotifyLastMsg(&lResult)) { - return (HBRUSH)lResult; - } - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::ControlAreaBGColor); - return controlAreaBrush; - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} - -INT_PTR CMPCThemePropertySheet::DoModal() { - isModal = true; - PreDoModalRTL(&m_psh); - return __super::DoModal(); -} +#include "stdafx.h" +#include "CMPCThemePropertySheet.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + + +CMPCThemePropertySheet::CMPCThemePropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) + : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) + ,isModal(false) +{ +} + +CMPCThemePropertySheet::CMPCThemePropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) + : CPropertySheet(pszCaption, pParentWnd, iSelectPage) + ,isModal(false) +{ +} + +CMPCThemePropertySheet::~CMPCThemePropertySheet() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemePropertySheet, CPropertySheet) +BEGIN_MESSAGE_MAP(CMPCThemePropertySheet, CPropertySheet) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + +BOOL CMPCThemePropertySheet::OnInitDialog() +{ + BOOL bResult = __super::OnInitDialog(); + fulfillThemeReqs(); + return bResult; +} + +void CMPCThemePropertySheet::fulfillThemeReqs() +{ + if (AppNeedsThemedControls()) { + CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); + if (isModal) { //propsheets not normally modal, but if so... + CMPCThemeUtil::enableWindows10DarkFrame(this); + } + } +} + +HBRUSH CMPCThemePropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppNeedsThemedControls()) { + LRESULT lResult; + if (pWnd->SendChildNotifyLastMsg(&lResult)) { + return (HBRUSH)lResult; + } + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::ControlAreaBGColor); + return controlAreaBrush; + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} + +INT_PTR CMPCThemePropertySheet::DoModal() { + isModal = true; + PreDoModalRTL(&m_psh); + return __super::DoModal(); +} diff --git a/src/mpc-hc/CMPCThemePropertySheet.h b/src/mpc-hc/CMPCThemePropertySheet.h index 8da67ed9ef4..432a9268613 100755 --- a/src/mpc-hc/CMPCThemePropertySheet.h +++ b/src/mpc-hc/CMPCThemePropertySheet.h @@ -1,25 +1,25 @@ -#pragma once -#include -#include "CMPCThemeUtil.h" - - -class CMPCThemePropertySheet : - public CPropertySheet - , public CMPCThemeUtil -{ - DECLARE_DYNAMIC(CMPCThemePropertySheet) - -public: - CMPCThemePropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); - CMPCThemePropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); - virtual ~CMPCThemePropertySheet(); - - virtual BOOL OnInitDialog(); - void fulfillThemeReqs(); - virtual INT_PTR DoModal(); //override to handle RTL without using SetWindowLongPtr - - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - bool isModal; -}; - +#pragma once +#include +#include "CMPCThemeUtil.h" + + +class CMPCThemePropertySheet : + public CPropertySheet + , public CMPCThemeUtil +{ + DECLARE_DYNAMIC(CMPCThemePropertySheet) + +public: + CMPCThemePropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + CMPCThemePropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + virtual ~CMPCThemePropertySheet(); + + virtual BOOL OnInitDialog(); + void fulfillThemeReqs(); + virtual INT_PTR DoModal(); //override to handle RTL without using SetWindowLongPtr + + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + bool isModal; +}; + diff --git a/src/mpc-hc/CMPCThemeRadioOrCheck.cpp b/src/mpc-hc/CMPCThemeRadioOrCheck.cpp index 8a41f971b17..dd571c28061 100755 --- a/src/mpc-hc/CMPCThemeRadioOrCheck.cpp +++ b/src/mpc-hc/CMPCThemeRadioOrCheck.cpp @@ -1,274 +1,274 @@ -#include "stdafx.h" -#include "CMPCThemeRadioOrCheck.h" -#include "CMPCTheme.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeUtil.h" -#include "VersionHelpersInternal.h" -#include "DpiHelper.h" -#include "mplayerc.h" - -CMPCThemeRadioOrCheck::CMPCThemeRadioOrCheck() -{ - isHover = false; - buttonType = RadioOrCheck::unknownType; - isFileDialogChild = false; - buttonStyle = 0; - isAuto = false; -} - - -CMPCThemeRadioOrCheck::~CMPCThemeRadioOrCheck() -{ -} - -void CMPCThemeRadioOrCheck::PreSubclassWindow() -{ - DWORD winButtonType = (GetButtonStyle() & BS_TYPEMASK); - - if (BS_RADIOBUTTON == winButtonType || BS_AUTORADIOBUTTON == winButtonType) { - buttonType = radioType; - isAuto = BS_AUTORADIOBUTTON == winButtonType; - } else if (BS_3STATE == winButtonType || BS_AUTO3STATE == winButtonType) { - buttonType = threeStateType; - isAuto = BS_AUTO3STATE == winButtonType; - } else if (BS_CHECKBOX == winButtonType || BS_AUTOCHECKBOX == winButtonType) { - buttonType = checkType; - isAuto = BS_AUTOCHECKBOX == winButtonType; - } - ASSERT(buttonType != unknownType); - - buttonStyle = GetWindowLongPtr(GetSafeHwnd(), GWL_STYLE); - CButton::PreSubclassWindow(); -} - -IMPLEMENT_DYNAMIC(CMPCThemeRadioOrCheck, CButton) -BEGIN_MESSAGE_MAP(CMPCThemeRadioOrCheck, CButton) - ON_WM_MOUSEMOVE() - ON_WM_MOUSELEAVE() - ON_WM_PAINT() - ON_WM_ENABLE() - ON_WM_ERASEBKGND() - ON_WM_UPDATEUISTATE() -END_MESSAGE_MAP() - - -void CMPCThemeRadioOrCheck::OnPaint() -{ - if (AppIsThemeLoaded() && CMPCTheme::drawThemedControls) { - CPaintDC dc(this); - CRect rectItem; - GetClientRect(rectItem); - - COLORREF oldBkColor = dc.GetBkColor(); - COLORREF oldTextColor = dc.GetTextColor(); - - bool isDisabled = !IsWindowEnabled(); - bool isFocused = (GetFocus() == this); - - LRESULT checkState = SendMessage(BM_GETCHECK); - - CString sTitle; - GetWindowText(sTitle); - - - if (0 != (buttonStyle & BS_PUSHLIKE)) { - CFont* oFont, *font = GetFont(); - oFont = dc.SelectObject(font); - CMPCThemeButton::drawButtonBase(&dc, rectItem, sTitle, checkState != BST_UNCHECKED, isHover, isFocused, checkState == BST_INDETERMINATE, false, false, m_hWnd); - dc.SelectObject(oFont); - } else { - CRect rectCheck; - int cbWidth; - int cbHeight; - if (IsWindows8OrGreater()) { - DpiHelper dpiWindow; - dpiWindow.Override(this->GetSafeHwnd()); - cbWidth = dpiWindow.GetSystemMetricsDPI(SM_CXMENUCHECK); - cbHeight = dpiWindow.GetSystemMetricsDPI(SM_CYMENUCHECK); - } else { - cbWidth = ::GetSystemMetrics(SM_CXMENUCHECK); - cbHeight = ::GetSystemMetrics(SM_CYMENUCHECK); - } - - if (buttonStyle & BS_LEFTTEXT) { - rectCheck.left = rectItem.right - cbWidth; - rectCheck.right = rectCheck.left + cbWidth; - rectItem.right = rectCheck.left - 2; - } else { - rectCheck.left = rectItem.left; - rectCheck.right = rectCheck.left + cbWidth; - rectItem.left = rectCheck.right + 2; - } - - rectCheck.top = (rectItem.Height() - cbHeight) / 2; - rectCheck.bottom = rectCheck.top + cbHeight; - - if (buttonType == checkType) { - CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc); - } else if (buttonType == threeStateType) { - CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc); - } else if (buttonType == radioType) { - CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc, true); - } - - if (!sTitle.IsEmpty()) { - CRect centerRect = rectItem; - CFont* pOldFont, *font = GetFont(); - pOldFont = dc.SelectObject(font); - - UINT uFormat = 0; - if (buttonStyle & BS_MULTILINE) { - uFormat |= DT_WORDBREAK; - } else { - uFormat |= DT_SINGLELINE; - } - - if (buttonStyle & BS_VCENTER) { - uFormat |= DT_VCENTER; - } - - if ((buttonStyle & BS_CENTER) == BS_CENTER) { - uFormat |= DT_CENTER; - dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed - rectItem.OffsetRect((centerRect.Width() - rectItem.Width()) / 2, - (centerRect.Height() - rectItem.Height()) / 2); - } else if ((buttonStyle & BS_RIGHT) == BS_RIGHT) { - uFormat |= DT_RIGHT; - dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed - rectItem.OffsetRect(centerRect.Width() - rectItem.Width(), - (centerRect.Height() - rectItem.Height()) / 2); - } else { // if ((buttonStyle & BS_LEFT) == BS_LEFT) { - uFormat |= DT_LEFT; - dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed - rectItem.OffsetRect(0, (centerRect.Height() - rectItem.Height()) / 2); - } - - if (isFileDialogChild) { - CMPCThemeUtil::getCtlColorFileDialog(dc.GetSafeHdc(), CTLCOLOR_BTN); - } else { - dc.SetBkColor(CMPCTheme::WindowBGColor); - } - - CRect focusRect = rectItem; - focusRect.InflateRect(0, 0); - if (buttonStyle & BS_MULTILINE) { //needed to clear old select for multi-line - HBRUSH hb = CMPCThemeUtil::getParentDialogBGClr(this, &dc); - CBrush cb; - cb.Attach(hb); - dc.FrameRect(focusRect, &cb); - cb.Detach(); - } - - if (isDisabled) { - dc.SetTextColor(CMPCTheme::ButtonDisabledFGColor); - dc.DrawTextW(sTitle, -1, &rectItem, uFormat); // DT_NOPREFIX not needed - } else { - dc.SetTextColor(CMPCTheme::TextFGColor); - dc.DrawTextW(sTitle, -1, &rectItem, uFormat); // DT_NOPREFIX not needed - } - dc.SelectObject(pOldFont); - - if (isFocused) { - dc.SetTextColor(CMPCTheme::ButtonBorderKBFocusColor); //no example of this in explorer, but white seems too harsh - CBrush* dotted = dc.GetHalftoneBrush(); - dc.FrameRect(focusRect, dotted); - DeleteObject(dotted); - } - - } - } - - dc.SetBkColor(oldBkColor); - dc.SetTextColor(oldTextColor); - } else { - CButton::OnPaint(); - } -} - -void CMPCThemeRadioOrCheck::OnSetFocus(CWnd* pOldWnd) -{ - CButton::OnSetFocus(pOldWnd); - Invalidate(); -} - -void CMPCThemeRadioOrCheck::checkHover(UINT nFlags, CPoint point, bool invalidate) -{ - CRect r; - GetClientRect(r); - bool oldHover = isHover; - CPoint ptScreen = point; - ClientToScreen(&ptScreen); - - if (r.PtInRect(point) && WindowFromPoint(ptScreen)->GetSafeHwnd() == GetSafeHwnd()) { - isHover = true; - } else { - isHover = false; - } - if (isHover != oldHover && invalidate) { - Invalidate(); - } - -} - -void CMPCThemeRadioOrCheck::OnMouseMove(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point); - CButton::OnMouseMove(nFlags, point); -} - - -void CMPCThemeRadioOrCheck::OnMouseLeave() -{ - checkHover(0, CPoint(-1, -1)); - CButton::OnMouseLeave(); -} - - -void CMPCThemeRadioOrCheck::OnLButtonUp(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point, false); - CButton::OnLButtonUp(nFlags, point); -} - - -void CMPCThemeRadioOrCheck::OnLButtonDown(UINT nFlags, CPoint point) -{ - checkHover(nFlags, point); - CButton::OnLButtonDown(nFlags, point); -} - - - -void CMPCThemeRadioOrCheck::OnEnable(BOOL bEnable) -{ - if (AppIsThemeLoaded()) { - SetRedraw(FALSE); - __super::OnEnable(bEnable); - SetRedraw(TRUE); - Invalidate(); //WM_PAINT not handled when enabling/disabling - } else { - __super::OnEnable(bEnable); - } -} - - -BOOL CMPCThemeRadioOrCheck::OnEraseBkgnd(CDC* pDC) -{ - CRect r; - GetClientRect(r); - if (isFileDialogChild) { - HBRUSH hBrush = CMPCThemeUtil::getCtlColorFileDialog(pDC->GetSafeHdc(), CTLCOLOR_BTN); - ::FillRect(pDC->GetSafeHdc(), r, hBrush); - } else { - CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); - } - return TRUE; -} - - -void CMPCThemeRadioOrCheck::OnUpdateUIState(UINT nAction, UINT nUIElement) { - if (nUIElement & UISF_HIDEACCEL) { - Invalidate(); - } - return __super::OnUpdateUIState(nAction, nUIElement); -} +#include "stdafx.h" +#include "CMPCThemeRadioOrCheck.h" +#include "CMPCTheme.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeUtil.h" +#include "VersionHelpersInternal.h" +#include "DpiHelper.h" +#include "mplayerc.h" + +CMPCThemeRadioOrCheck::CMPCThemeRadioOrCheck() +{ + isHover = false; + buttonType = RadioOrCheck::unknownType; + isFileDialogChild = false; + buttonStyle = 0; + isAuto = false; +} + + +CMPCThemeRadioOrCheck::~CMPCThemeRadioOrCheck() +{ +} + +void CMPCThemeRadioOrCheck::PreSubclassWindow() +{ + DWORD winButtonType = (GetButtonStyle() & BS_TYPEMASK); + + if (BS_RADIOBUTTON == winButtonType || BS_AUTORADIOBUTTON == winButtonType) { + buttonType = radioType; + isAuto = BS_AUTORADIOBUTTON == winButtonType; + } else if (BS_3STATE == winButtonType || BS_AUTO3STATE == winButtonType) { + buttonType = threeStateType; + isAuto = BS_AUTO3STATE == winButtonType; + } else if (BS_CHECKBOX == winButtonType || BS_AUTOCHECKBOX == winButtonType) { + buttonType = checkType; + isAuto = BS_AUTOCHECKBOX == winButtonType; + } + ASSERT(buttonType != unknownType); + + buttonStyle = GetWindowLongPtr(GetSafeHwnd(), GWL_STYLE); + CButton::PreSubclassWindow(); +} + +IMPLEMENT_DYNAMIC(CMPCThemeRadioOrCheck, CButton) +BEGIN_MESSAGE_MAP(CMPCThemeRadioOrCheck, CButton) + ON_WM_MOUSEMOVE() + ON_WM_MOUSELEAVE() + ON_WM_PAINT() + ON_WM_ENABLE() + ON_WM_ERASEBKGND() + ON_WM_UPDATEUISTATE() +END_MESSAGE_MAP() + + +void CMPCThemeRadioOrCheck::OnPaint() +{ + if (AppIsThemeLoaded() && CMPCTheme::drawThemedControls) { + CPaintDC dc(this); + CRect rectItem; + GetClientRect(rectItem); + + COLORREF oldBkColor = dc.GetBkColor(); + COLORREF oldTextColor = dc.GetTextColor(); + + bool isDisabled = !IsWindowEnabled(); + bool isFocused = (GetFocus() == this); + + LRESULT checkState = SendMessage(BM_GETCHECK); + + CString sTitle; + GetWindowText(sTitle); + + + if (0 != (buttonStyle & BS_PUSHLIKE)) { + CFont* oFont, *font = GetFont(); + oFont = dc.SelectObject(font); + CMPCThemeButton::drawButtonBase(&dc, rectItem, sTitle, checkState != BST_UNCHECKED, isHover, isFocused, checkState == BST_INDETERMINATE, false, false, m_hWnd); + dc.SelectObject(oFont); + } else { + CRect rectCheck; + int cbWidth; + int cbHeight; + if (IsWindows8OrGreater()) { + DpiHelper dpiWindow; + dpiWindow.Override(this->GetSafeHwnd()); + cbWidth = dpiWindow.GetSystemMetricsDPI(SM_CXMENUCHECK); + cbHeight = dpiWindow.GetSystemMetricsDPI(SM_CYMENUCHECK); + } else { + cbWidth = ::GetSystemMetrics(SM_CXMENUCHECK); + cbHeight = ::GetSystemMetrics(SM_CYMENUCHECK); + } + + if (buttonStyle & BS_LEFTTEXT) { + rectCheck.left = rectItem.right - cbWidth; + rectCheck.right = rectCheck.left + cbWidth; + rectItem.right = rectCheck.left - 2; + } else { + rectCheck.left = rectItem.left; + rectCheck.right = rectCheck.left + cbWidth; + rectItem.left = rectCheck.right + 2; + } + + rectCheck.top = (rectItem.Height() - cbHeight) / 2; + rectCheck.bottom = rectCheck.top + cbHeight; + + if (buttonType == checkType) { + CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc); + } else if (buttonType == threeStateType) { + CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc); + } else if (buttonType == radioType) { + CMPCThemeUtil::drawCheckBox(GetParent(), checkState, isHover, true, rectCheck, &dc, true); + } + + if (!sTitle.IsEmpty()) { + CRect centerRect = rectItem; + CFont* pOldFont, *font = GetFont(); + pOldFont = dc.SelectObject(font); + + UINT uFormat = 0; + if (buttonStyle & BS_MULTILINE) { + uFormat |= DT_WORDBREAK; + } else { + uFormat |= DT_SINGLELINE; + } + + if (buttonStyle & BS_VCENTER) { + uFormat |= DT_VCENTER; + } + + if ((buttonStyle & BS_CENTER) == BS_CENTER) { + uFormat |= DT_CENTER; + dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed + rectItem.OffsetRect((centerRect.Width() - rectItem.Width()) / 2, + (centerRect.Height() - rectItem.Height()) / 2); + } else if ((buttonStyle & BS_RIGHT) == BS_RIGHT) { + uFormat |= DT_RIGHT; + dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed + rectItem.OffsetRect(centerRect.Width() - rectItem.Width(), + (centerRect.Height() - rectItem.Height()) / 2); + } else { // if ((buttonStyle & BS_LEFT) == BS_LEFT) { + uFormat |= DT_LEFT; + dc.DrawTextW(sTitle, -1, &rectItem, uFormat | DT_CALCRECT); // DT_NOPREFIX not needed + rectItem.OffsetRect(0, (centerRect.Height() - rectItem.Height()) / 2); + } + + if (isFileDialogChild) { + CMPCThemeUtil::getCtlColorFileDialog(dc.GetSafeHdc(), CTLCOLOR_BTN); + } else { + dc.SetBkColor(CMPCTheme::WindowBGColor); + } + + CRect focusRect = rectItem; + focusRect.InflateRect(0, 0); + if (buttonStyle & BS_MULTILINE) { //needed to clear old select for multi-line + HBRUSH hb = CMPCThemeUtil::getParentDialogBGClr(this, &dc); + CBrush cb; + cb.Attach(hb); + dc.FrameRect(focusRect, &cb); + cb.Detach(); + } + + if (isDisabled) { + dc.SetTextColor(CMPCTheme::ButtonDisabledFGColor); + dc.DrawTextW(sTitle, -1, &rectItem, uFormat); // DT_NOPREFIX not needed + } else { + dc.SetTextColor(CMPCTheme::TextFGColor); + dc.DrawTextW(sTitle, -1, &rectItem, uFormat); // DT_NOPREFIX not needed + } + dc.SelectObject(pOldFont); + + if (isFocused) { + dc.SetTextColor(CMPCTheme::ButtonBorderKBFocusColor); //no example of this in explorer, but white seems too harsh + CBrush* dotted = dc.GetHalftoneBrush(); + dc.FrameRect(focusRect, dotted); + DeleteObject(dotted); + } + + } + } + + dc.SetBkColor(oldBkColor); + dc.SetTextColor(oldTextColor); + } else { + CButton::OnPaint(); + } +} + +void CMPCThemeRadioOrCheck::OnSetFocus(CWnd* pOldWnd) +{ + CButton::OnSetFocus(pOldWnd); + Invalidate(); +} + +void CMPCThemeRadioOrCheck::checkHover(UINT nFlags, CPoint point, bool invalidate) +{ + CRect r; + GetClientRect(r); + bool oldHover = isHover; + CPoint ptScreen = point; + ClientToScreen(&ptScreen); + + if (r.PtInRect(point) && WindowFromPoint(ptScreen)->GetSafeHwnd() == GetSafeHwnd()) { + isHover = true; + } else { + isHover = false; + } + if (isHover != oldHover && invalidate) { + Invalidate(); + } + +} + +void CMPCThemeRadioOrCheck::OnMouseMove(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point); + CButton::OnMouseMove(nFlags, point); +} + + +void CMPCThemeRadioOrCheck::OnMouseLeave() +{ + checkHover(0, CPoint(-1, -1)); + CButton::OnMouseLeave(); +} + + +void CMPCThemeRadioOrCheck::OnLButtonUp(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point, false); + CButton::OnLButtonUp(nFlags, point); +} + + +void CMPCThemeRadioOrCheck::OnLButtonDown(UINT nFlags, CPoint point) +{ + checkHover(nFlags, point); + CButton::OnLButtonDown(nFlags, point); +} + + + +void CMPCThemeRadioOrCheck::OnEnable(BOOL bEnable) +{ + if (AppIsThemeLoaded()) { + SetRedraw(FALSE); + __super::OnEnable(bEnable); + SetRedraw(TRUE); + Invalidate(); //WM_PAINT not handled when enabling/disabling + } else { + __super::OnEnable(bEnable); + } +} + + +BOOL CMPCThemeRadioOrCheck::OnEraseBkgnd(CDC* pDC) +{ + CRect r; + GetClientRect(r); + if (isFileDialogChild) { + HBRUSH hBrush = CMPCThemeUtil::getCtlColorFileDialog(pDC->GetSafeHdc(), CTLCOLOR_BTN); + ::FillRect(pDC->GetSafeHdc(), r, hBrush); + } else { + CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); + } + return TRUE; +} + + +void CMPCThemeRadioOrCheck::OnUpdateUIState(UINT nAction, UINT nUIElement) { + if (nUIElement & UISF_HIDEACCEL) { + Invalidate(); + } + return __super::OnUpdateUIState(nAction, nUIElement); +} diff --git a/src/mpc-hc/CMPCThemeRadioOrCheck.h b/src/mpc-hc/CMPCThemeRadioOrCheck.h index c4d2ac6cd46..6918b79f926 100755 --- a/src/mpc-hc/CMPCThemeRadioOrCheck.h +++ b/src/mpc-hc/CMPCThemeRadioOrCheck.h @@ -1,38 +1,38 @@ -#pragma once -#include -class CMPCThemeRadioOrCheck : public CButton -{ -public: - CMPCThemeRadioOrCheck(); - virtual ~CMPCThemeRadioOrCheck(); - void PreSubclassWindow(); -private: - bool isHover; - BOOL isAuto; - CBrush bgBrush; - DWORD buttonStyle; - enum RadioOrCheck { - radioType, - checkType, - threeStateType, - unknownType - }; - RadioOrCheck buttonType; -protected: - bool isFileDialogChild; - DECLARE_DYNAMIC(CMPCThemeRadioOrCheck) - DECLARE_MESSAGE_MAP() - afx_msg void OnSetFocus(CWnd* pOldWnd); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - void checkHover(UINT nFlags, CPoint point, bool invalidate = true); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); -public: - afx_msg void OnPaint(); - afx_msg void OnEnable(BOOL bEnable); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - void setFileDialogChild(bool set) { isFileDialogChild = set; }; - afx_msg void OnUpdateUIState(UINT nAction, UINT nUIElement); -}; - +#pragma once +#include +class CMPCThemeRadioOrCheck : public CButton +{ +public: + CMPCThemeRadioOrCheck(); + virtual ~CMPCThemeRadioOrCheck(); + void PreSubclassWindow(); +private: + bool isHover; + BOOL isAuto; + CBrush bgBrush; + DWORD buttonStyle; + enum RadioOrCheck { + radioType, + checkType, + threeStateType, + unknownType + }; + RadioOrCheck buttonType; +protected: + bool isFileDialogChild; + DECLARE_DYNAMIC(CMPCThemeRadioOrCheck) + DECLARE_MESSAGE_MAP() + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + void checkHover(UINT nFlags, CPoint point, bool invalidate = true); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); +public: + afx_msg void OnPaint(); + afx_msg void OnEnable(BOOL bEnable); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + void setFileDialogChild(bool set) { isFileDialogChild = set; }; + afx_msg void OnUpdateUIState(UINT nAction, UINT nUIElement); +}; + diff --git a/src/mpc-hc/CMPCThemeResizableDialog.cpp b/src/mpc-hc/CMPCThemeResizableDialog.cpp index 5138288f3bd..170438e8704 100755 --- a/src/mpc-hc/CMPCThemeResizableDialog.cpp +++ b/src/mpc-hc/CMPCThemeResizableDialog.cpp @@ -1,51 +1,51 @@ -#include "stdafx.h" -#include "CMPCThemeResizableDialog.h" -#include "CMPCTheme.h" -#include "mplayerc.h" - -CMPCThemeResizableDialog::CMPCThemeResizableDialog() -{ -} - -CMPCThemeResizableDialog::CMPCThemeResizableDialog(UINT nIDTemplate, CWnd* pParent): CResizableDialog(nIDTemplate, pParent) -{ -} - -CMPCThemeResizableDialog::CMPCThemeResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParent): CResizableDialog(lpszTemplateName, pParent) -{ -} - - -CMPCThemeResizableDialog::~CMPCThemeResizableDialog() -{ -} - -BOOL CMPCThemeResizableDialog::OnInitDialog() { - BOOL ret = CResizableDialog::OnInitDialog(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return ret; -} - -void CMPCThemeResizableDialog::fulfillThemeReqs() -{ - if (AppNeedsThemedControls()) { - CMPCThemeUtil::enableWindows10DarkFrame(this); - SetSizeGripBkMode(TRANSPARENT); //fix for gripper in mpc theme - CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); - } -} - -BEGIN_MESSAGE_MAP(CMPCThemeResizableDialog, CResizableDialog) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeResizableDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} +#include "stdafx.h" +#include "CMPCThemeResizableDialog.h" +#include "CMPCTheme.h" +#include "mplayerc.h" + +CMPCThemeResizableDialog::CMPCThemeResizableDialog() +{ +} + +CMPCThemeResizableDialog::CMPCThemeResizableDialog(UINT nIDTemplate, CWnd* pParent): CResizableDialog(nIDTemplate, pParent) +{ +} + +CMPCThemeResizableDialog::CMPCThemeResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParent): CResizableDialog(lpszTemplateName, pParent) +{ +} + + +CMPCThemeResizableDialog::~CMPCThemeResizableDialog() +{ +} + +BOOL CMPCThemeResizableDialog::OnInitDialog() { + BOOL ret = CResizableDialog::OnInitDialog(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return ret; +} + +void CMPCThemeResizableDialog::fulfillThemeReqs() +{ + if (AppNeedsThemedControls()) { + CMPCThemeUtil::enableWindows10DarkFrame(this); + SetSizeGripBkMode(TRANSPARENT); //fix for gripper in mpc theme + CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); + } +} + +BEGIN_MESSAGE_MAP(CMPCThemeResizableDialog, CResizableDialog) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeResizableDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} diff --git a/src/mpc-hc/CMPCThemeResizableDialog.h b/src/mpc-hc/CMPCThemeResizableDialog.h index 96e304c9898..712990f542e 100755 --- a/src/mpc-hc/CMPCThemeResizableDialog.h +++ b/src/mpc-hc/CMPCThemeResizableDialog.h @@ -1,19 +1,19 @@ -#pragma once -#include "CMPCThemeButton.h" -#include "CMPCThemeGroupBox.h" -#include "CMPCThemeLinkCtrl.h" -#include "CMPCThemeUtil.h" -class CMPCThemeResizableDialog : public CResizableDialog, public CMPCThemeUtil -{ -public: - CMPCThemeResizableDialog(); - CMPCThemeResizableDialog(UINT nIDTemplate, CWnd* pParent = nullptr); - CMPCThemeResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); - virtual ~CMPCThemeResizableDialog(); - BOOL OnInitDialog(); - void fulfillThemeReqs(); - DECLARE_MESSAGE_MAP() -public: - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -}; - +#pragma once +#include "CMPCThemeButton.h" +#include "CMPCThemeGroupBox.h" +#include "CMPCThemeLinkCtrl.h" +#include "CMPCThemeUtil.h" +class CMPCThemeResizableDialog : public CResizableDialog, public CMPCThemeUtil +{ +public: + CMPCThemeResizableDialog(); + CMPCThemeResizableDialog(UINT nIDTemplate, CWnd* pParent = nullptr); + CMPCThemeResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParent = nullptr); + virtual ~CMPCThemeResizableDialog(); + BOOL OnInitDialog(); + void fulfillThemeReqs(); + DECLARE_MESSAGE_MAP() +public: + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +}; + diff --git a/src/mpc-hc/CMPCThemeScrollBar.cpp b/src/mpc-hc/CMPCThemeScrollBar.cpp index 064eb055751..56abb7f19d6 100755 --- a/src/mpc-hc/CMPCThemeScrollBar.cpp +++ b/src/mpc-hc/CMPCThemeScrollBar.cpp @@ -1,280 +1,280 @@ -#include "stdafx.h" -#include "DpiHelper.h" -#include "CMPCThemeScrollBar.h" -#include "CMPCTheme.h" -#include "CMPCThemeListBox.h" -#include "CMPCThemeEdit.h" - -IMPLEMENT_DYNAMIC(CMPCThemeScrollBar, CXeScrollBarBase) - -BEGIN_MESSAGE_MAP(CMPCThemeScrollBar, CXeScrollBarBase) - // ON_WM_MOUSEWHEEL() -END_MESSAGE_MAP() - -CMPCThemeScrollBar::CMPCThemeScrollBar(): - haveInitScrollInfo(false) - , disableNoScroll(false) -{ -} - - -CMPCThemeScrollBar::~CMPCThemeScrollBar() -{ -} - -void CMPCThemeScrollBar::drawSBArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation) -{ - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - Gdiplus::Graphics gfx(dc.m_hDC); - Gdiplus::Color clr; - clr.SetFromCOLORREF(arrowClr); - - int dpi = dpiWindow.DPIX(); - - int xPos; - int yPos; - int xsign, ysign; - int rows, steps; - - if (dpi < 120) { - rows = 3; - steps = 3; - } else if (dpi < 144) { - rows = 3; - steps = 4; - } else if (dpi < 168) { - rows = 4; - steps = 5; - } else if (dpi < 192) { - rows = 4; - steps = 5; - } else { - rows = 4; - steps = 5; - } - - float shortDim = steps + rows; - int indent; - switch (orientation) { - case arrowLeft: - indent = ceil((arrowRect.Width() - shortDim) / 2); - xPos = arrowRect.right - indent - 1; //left and right arrows are pegged to the inside edge - yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; - xsign = -1; - ysign = 1; - break; - case arrowRight: - indent = ceil((arrowRect.Width() - shortDim) / 2); - yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; - xPos = arrowRect.left + indent; //left and right arrows are pegged to the inside edge - xsign = 1; - ysign = 1; - break; - case arrowTop: - xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - indent = ceil((arrowRect.Height() - shortDim) / 2); - yPos = arrowRect.top + indent + shortDim - 1; //top and bottom arrows are pegged to the top edge - xsign = 1; - ysign = -1; - break; - case arrowBottom: - default: - xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - indent = ceil((arrowRect.Height() - shortDim) / 2); - yPos = arrowRect.top + indent; //top and bottom arrows are pegged to the top edge - xsign = 1; - ysign = 1; - break; - } - - gfx.SetSmoothingMode(Gdiplus::SmoothingModeNone); - Gdiplus::Pen pen(clr, 1); - for (int i = 0; i < rows; i++) { - if (orientation == arrowLeft || orientation == arrowRight) { - gfx.DrawLine(&pen, xPos + i * xsign, yPos, xPos + (steps + i) * xsign, steps * ysign + yPos); - gfx.DrawLine(&pen, xPos + (steps + i) * xsign, steps * ysign + yPos, xPos + i * xsign, (steps * 2) * ysign + yPos); - } else { - gfx.DrawLine(&pen, xPos, yPos + i * ysign, steps * xsign + xPos, yPos + (steps + i) * ysign); - gfx.DrawLine(&pen, steps * xsign + xPos, yPos + (steps + i) * ysign, (steps * 2) * xsign + xPos, yPos + i * ysign); - } - } - -} - - -void CMPCThemeScrollBar::DrawScrollBar(CDC* pDC) -{ - CRect rcC; - GetClientRect(&rcC); - - // Draw to memory DC - CDC dcMem; - dcMem.CreateCompatibleDC(pDC); - CBitmap bmMem; - bmMem.CreateCompatibleBitmap(pDC, rcC.Width(), rcC.Height()); - CBitmap* pOldBm = dcMem.SelectObject(&bmMem); - - - CBrush brushBG(CMPCTheme::ScrollBGColor); - dcMem.FillRect(rcC, &brushBG); - - CBrush brushChannel(CMPCTheme::ScrollBGColor); - - XSB_EDRAWELEM eState; - const CRect* prcElem = 0; - stXSB_AREA stArea; - - for (int nElem = eTLbutton; nElem <= eThumb; nElem++) { - stArea.eArea = (eXSB_AREA)nElem; - - prcElem = GetUIelementDrawState(stArea.eArea, eState); - if (!prcElem || eState == eNotDrawn) { // Rect empty or area not drawn? - continue; - } - - CRect butRect = prcElem; - if (m_bHorizontal) { - butRect.top += 1; - butRect.bottom -= 1; - } else { - butRect.left += 1; - butRect.right -= 1; - } - - - if (stArea.IsButton()) { - CBrush brushButton; - COLORREF buttonClr = RGB(0, 0, 0); - COLORREF buttonFGClr = CMPCTheme::ScrollButtonArrowColor; - switch (eState) { - case eDisabled: - //no example found of disabled dark scrollbar, but when disabled, button bg = scroll bg - //(see notepad for example of disabled non-dark--bg color matches disabled button) - buttonClr = CMPCTheme::ScrollBGColor; - break; - case eNormal: - buttonClr = CMPCTheme::ScrollBGColor; - break; - case eDown: - buttonClr = CMPCTheme::ScrollButtonClickColor; - buttonFGClr = CMPCTheme::ScrollButtonArrowClickColor; - break; - case eHot: - buttonClr = CMPCTheme::ScrollButtonHoverColor; - break; - default: - ASSERT(FALSE); // Unknown state! - } - brushButton.CreateSolidBrush(buttonClr); - dcMem.FillRect(butRect, &brushButton); - brushButton.DeleteObject(); - - if (m_bHorizontal) { - if (nElem == eTLbutton) { //top or left - drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowLeft); - } else { - drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowRight); - } - } else { - if (nElem == eTLbutton) { //top or left - drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowTop); - } else { - drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowBottom); - } - } - - } else if (stArea.IsChannel()) { - if (m_bHorizontal) { - dcMem.FillRect(prcElem, &brushChannel); - } else { - dcMem.FillRect(prcElem, &brushChannel); - } - } else { // Is thumb - CBrush brushThumb; - switch (eState) { - case eDisabled: - //no example found of disabled dark scrollbar, but when disabled, we will hide the thumb entirely. put bg color here for now - brushThumb.CreateSolidBrush(CMPCTheme::ScrollBGColor); - break; - case eNormal: - brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbColor); - break; - case eDown: - brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbDragColor); - break; - case eHot: - brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbHoverColor); - break; - default: - ASSERT(FALSE); // Unknown state! - } - dcMem.FillRect(butRect, &brushThumb); - brushThumb.DeleteObject(); - } - } - - pDC->BitBlt(0, 0, rcC.Width(), rcC.Height(), &dcMem, 0, 0, SRCCOPY); - - dcMem.SelectObject(pOldBm); - bmMem.DeleteObject(); -} - -void CMPCThemeScrollBar::SendScrollMsg(WORD wSBcode, WORD wHiWPARAM /*= 0*/) -{ - ASSERT(::IsWindow(m_hWnd)); - if (nullptr != m_scrollWindow && ::IsWindow(m_scrollWindow->m_hWnd)) { - if (SB_ENDSCROLL != wSBcode) { - m_scrollWindow->SendMessage((m_bHorizontal) ? WM_HSCROLL : WM_VSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); - } - } else if (nullptr != m_pParent && ::IsWindow(m_pParent->m_hWnd)) { - m_pParent->SendMessage((m_bHorizontal) ? WM_HSCROLL : WM_VSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); - } -} - -void CMPCThemeScrollBar::setScrollWindow(CWnd* window) -{ - this->m_scrollWindow = window; - if (DYNAMIC_DOWNCAST(CMPCThemeEdit, window)) { - disableNoScroll = true; - } else if (DYNAMIC_DOWNCAST(CMPCThemeListBox, window)) { - disableNoScroll = 0 != (window->GetStyle() & LBS_DISABLENOSCROLL); - } -} - -void CMPCThemeScrollBar::updateScrollInfo() -{ - if (GetStyle() & WS_VISIBLE) { - SCROLLINFO si = { 0 }, siSelf = { 0 }; - si.cbSize = sizeof(SCROLLINFO); - si.fMask = SIF_ALL; - m_scrollWindow->GetScrollInfo(m_bHorizontal ? SB_HORZ : SB_VERT, &si); - siSelf.cbSize = sizeof(SCROLLINFO); - siSelf.fMask = SIF_ALL; - GetScrollInfo(&siSelf); - if (si.nMax != siSelf.nMax || si.nMin != siSelf.nMin || si.nPos != siSelf.nPos || si.nPage != siSelf.nPage || !haveInitScrollInfo) { - if (disableNoScroll) { - si.fMask |= SIF_DISABLENOSCROLL; - } - SetScrollInfo(&si); - haveInitScrollInfo = true; - } - } -} - -BOOL CMPCThemeScrollBar::PreTranslateMessage(MSG* pMsg) -{ - switch (pMsg->message) { - case WM_MOUSEWHEEL: - //windows with integrated scrollbars handle mousewheel messages themselves - //we have to send it manually since our parent is not the scrollwindow - if (nullptr != m_scrollWindow && ::IsWindow(m_scrollWindow->m_hWnd)) { - m_scrollWindow->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam); - return TRUE; - } - break; - } - return __super::PreTranslateMessage(pMsg); -} - +#include "stdafx.h" +#include "DpiHelper.h" +#include "CMPCThemeScrollBar.h" +#include "CMPCTheme.h" +#include "CMPCThemeListBox.h" +#include "CMPCThemeEdit.h" + +IMPLEMENT_DYNAMIC(CMPCThemeScrollBar, CXeScrollBarBase) + +BEGIN_MESSAGE_MAP(CMPCThemeScrollBar, CXeScrollBarBase) + // ON_WM_MOUSEWHEEL() +END_MESSAGE_MAP() + +CMPCThemeScrollBar::CMPCThemeScrollBar(): + haveInitScrollInfo(false) + , disableNoScroll(false) +{ +} + + +CMPCThemeScrollBar::~CMPCThemeScrollBar() +{ +} + +void CMPCThemeScrollBar::drawSBArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation) +{ + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + Gdiplus::Graphics gfx(dc.m_hDC); + Gdiplus::Color clr; + clr.SetFromCOLORREF(arrowClr); + + int dpi = dpiWindow.DPIX(); + + int xPos; + int yPos; + int xsign, ysign; + int rows, steps; + + if (dpi < 120) { + rows = 3; + steps = 3; + } else if (dpi < 144) { + rows = 3; + steps = 4; + } else if (dpi < 168) { + rows = 4; + steps = 5; + } else if (dpi < 192) { + rows = 4; + steps = 5; + } else { + rows = 4; + steps = 5; + } + + float shortDim = steps + rows; + int indent; + switch (orientation) { + case arrowLeft: + indent = ceil((arrowRect.Width() - shortDim) / 2); + xPos = arrowRect.right - indent - 1; //left and right arrows are pegged to the inside edge + yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; + xsign = -1; + ysign = 1; + break; + case arrowRight: + indent = ceil((arrowRect.Width() - shortDim) / 2); + yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; + xPos = arrowRect.left + indent; //left and right arrows are pegged to the inside edge + xsign = 1; + ysign = 1; + break; + case arrowTop: + xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + indent = ceil((arrowRect.Height() - shortDim) / 2); + yPos = arrowRect.top + indent + shortDim - 1; //top and bottom arrows are pegged to the top edge + xsign = 1; + ysign = -1; + break; + case arrowBottom: + default: + xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + indent = ceil((arrowRect.Height() - shortDim) / 2); + yPos = arrowRect.top + indent; //top and bottom arrows are pegged to the top edge + xsign = 1; + ysign = 1; + break; + } + + gfx.SetSmoothingMode(Gdiplus::SmoothingModeNone); + Gdiplus::Pen pen(clr, 1); + for (int i = 0; i < rows; i++) { + if (orientation == arrowLeft || orientation == arrowRight) { + gfx.DrawLine(&pen, xPos + i * xsign, yPos, xPos + (steps + i) * xsign, steps * ysign + yPos); + gfx.DrawLine(&pen, xPos + (steps + i) * xsign, steps * ysign + yPos, xPos + i * xsign, (steps * 2) * ysign + yPos); + } else { + gfx.DrawLine(&pen, xPos, yPos + i * ysign, steps * xsign + xPos, yPos + (steps + i) * ysign); + gfx.DrawLine(&pen, steps * xsign + xPos, yPos + (steps + i) * ysign, (steps * 2) * xsign + xPos, yPos + i * ysign); + } + } + +} + + +void CMPCThemeScrollBar::DrawScrollBar(CDC* pDC) +{ + CRect rcC; + GetClientRect(&rcC); + + // Draw to memory DC + CDC dcMem; + dcMem.CreateCompatibleDC(pDC); + CBitmap bmMem; + bmMem.CreateCompatibleBitmap(pDC, rcC.Width(), rcC.Height()); + CBitmap* pOldBm = dcMem.SelectObject(&bmMem); + + + CBrush brushBG(CMPCTheme::ScrollBGColor); + dcMem.FillRect(rcC, &brushBG); + + CBrush brushChannel(CMPCTheme::ScrollBGColor); + + XSB_EDRAWELEM eState; + const CRect* prcElem = 0; + stXSB_AREA stArea; + + for (int nElem = eTLbutton; nElem <= eThumb; nElem++) { + stArea.eArea = (eXSB_AREA)nElem; + + prcElem = GetUIelementDrawState(stArea.eArea, eState); + if (!prcElem || eState == eNotDrawn) { // Rect empty or area not drawn? + continue; + } + + CRect butRect = prcElem; + if (m_bHorizontal) { + butRect.top += 1; + butRect.bottom -= 1; + } else { + butRect.left += 1; + butRect.right -= 1; + } + + + if (stArea.IsButton()) { + CBrush brushButton; + COLORREF buttonClr = RGB(0, 0, 0); + COLORREF buttonFGClr = CMPCTheme::ScrollButtonArrowColor; + switch (eState) { + case eDisabled: + //no example found of disabled dark scrollbar, but when disabled, button bg = scroll bg + //(see notepad for example of disabled non-dark--bg color matches disabled button) + buttonClr = CMPCTheme::ScrollBGColor; + break; + case eNormal: + buttonClr = CMPCTheme::ScrollBGColor; + break; + case eDown: + buttonClr = CMPCTheme::ScrollButtonClickColor; + buttonFGClr = CMPCTheme::ScrollButtonArrowClickColor; + break; + case eHot: + buttonClr = CMPCTheme::ScrollButtonHoverColor; + break; + default: + ASSERT(FALSE); // Unknown state! + } + brushButton.CreateSolidBrush(buttonClr); + dcMem.FillRect(butRect, &brushButton); + brushButton.DeleteObject(); + + if (m_bHorizontal) { + if (nElem == eTLbutton) { //top or left + drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowLeft); + } else { + drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowRight); + } + } else { + if (nElem == eTLbutton) { //top or left + drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowTop); + } else { + drawSBArrow(dcMem, CMPCTheme::ScrollButtonArrowColor, butRect, arrowOrientation::arrowBottom); + } + } + + } else if (stArea.IsChannel()) { + if (m_bHorizontal) { + dcMem.FillRect(prcElem, &brushChannel); + } else { + dcMem.FillRect(prcElem, &brushChannel); + } + } else { // Is thumb + CBrush brushThumb; + switch (eState) { + case eDisabled: + //no example found of disabled dark scrollbar, but when disabled, we will hide the thumb entirely. put bg color here for now + brushThumb.CreateSolidBrush(CMPCTheme::ScrollBGColor); + break; + case eNormal: + brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbColor); + break; + case eDown: + brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbDragColor); + break; + case eHot: + brushThumb.CreateSolidBrush(CMPCTheme::ScrollThumbHoverColor); + break; + default: + ASSERT(FALSE); // Unknown state! + } + dcMem.FillRect(butRect, &brushThumb); + brushThumb.DeleteObject(); + } + } + + pDC->BitBlt(0, 0, rcC.Width(), rcC.Height(), &dcMem, 0, 0, SRCCOPY); + + dcMem.SelectObject(pOldBm); + bmMem.DeleteObject(); +} + +void CMPCThemeScrollBar::SendScrollMsg(WORD wSBcode, WORD wHiWPARAM /*= 0*/) +{ + ASSERT(::IsWindow(m_hWnd)); + if (nullptr != m_scrollWindow && ::IsWindow(m_scrollWindow->m_hWnd)) { + if (SB_ENDSCROLL != wSBcode) { + m_scrollWindow->SendMessage((m_bHorizontal) ? WM_HSCROLL : WM_VSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); + } + } else if (nullptr != m_pParent && ::IsWindow(m_pParent->m_hWnd)) { + m_pParent->SendMessage((m_bHorizontal) ? WM_HSCROLL : WM_VSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); + } +} + +void CMPCThemeScrollBar::setScrollWindow(CWnd* window) +{ + this->m_scrollWindow = window; + if (DYNAMIC_DOWNCAST(CMPCThemeEdit, window)) { + disableNoScroll = true; + } else if (DYNAMIC_DOWNCAST(CMPCThemeListBox, window)) { + disableNoScroll = 0 != (window->GetStyle() & LBS_DISABLENOSCROLL); + } +} + +void CMPCThemeScrollBar::updateScrollInfo() +{ + if (GetStyle() & WS_VISIBLE) { + SCROLLINFO si = { 0 }, siSelf = { 0 }; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_ALL; + m_scrollWindow->GetScrollInfo(m_bHorizontal ? SB_HORZ : SB_VERT, &si); + siSelf.cbSize = sizeof(SCROLLINFO); + siSelf.fMask = SIF_ALL; + GetScrollInfo(&siSelf); + if (si.nMax != siSelf.nMax || si.nMin != siSelf.nMin || si.nPos != siSelf.nPos || si.nPage != siSelf.nPage || !haveInitScrollInfo) { + if (disableNoScroll) { + si.fMask |= SIF_DISABLENOSCROLL; + } + SetScrollInfo(&si); + haveInitScrollInfo = true; + } + } +} + +BOOL CMPCThemeScrollBar::PreTranslateMessage(MSG* pMsg) +{ + switch (pMsg->message) { + case WM_MOUSEWHEEL: + //windows with integrated scrollbars handle mousewheel messages themselves + //we have to send it manually since our parent is not the scrollwindow + if (nullptr != m_scrollWindow && ::IsWindow(m_scrollWindow->m_hWnd)) { + m_scrollWindow->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam); + return TRUE; + } + break; + } + return __super::PreTranslateMessage(pMsg); +} + diff --git a/src/mpc-hc/CMPCThemeScrollBar.h b/src/mpc-hc/CMPCThemeScrollBar.h index 077b114479a..8c2502b27be 100755 --- a/src/mpc-hc/CMPCThemeScrollBar.h +++ b/src/mpc-hc/CMPCThemeScrollBar.h @@ -1,31 +1,31 @@ -#pragma once -#include -#include "XeScrollBar/XeScrollBarBase.h" - -class CMPCThemeScrollBar : public CXeScrollBarBase -{ - DECLARE_DYNAMIC(CMPCThemeScrollBar) -public: - CMPCThemeScrollBar(); - virtual ~CMPCThemeScrollBar(); - enum arrowOrientation { - arrowLeft, - arrowRight, - arrowTop, - arrowBottom - }; - void DrawScrollBar(CDC* pDC); - virtual void SendScrollMsg(WORD wSBcode, WORD wHiWPARAM); - void setScrollWindow(CWnd* window); - void updateScrollInfo(); - BOOL PreTranslateMessage(MSG* pMsg); - void updateScrollInfo(int nPos); -protected: - CWnd* m_scrollWindow; //real parent is window we overlay the SB - DECLARE_MESSAGE_MAP() - UINT scrollLines; - bool haveInitScrollInfo; - bool disableNoScroll; - void drawSBArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation); -}; - +#pragma once +#include +#include "XeScrollBar/XeScrollBarBase.h" + +class CMPCThemeScrollBar : public CXeScrollBarBase +{ + DECLARE_DYNAMIC(CMPCThemeScrollBar) +public: + CMPCThemeScrollBar(); + virtual ~CMPCThemeScrollBar(); + enum arrowOrientation { + arrowLeft, + arrowRight, + arrowTop, + arrowBottom + }; + void DrawScrollBar(CDC* pDC); + virtual void SendScrollMsg(WORD wSBcode, WORD wHiWPARAM); + void setScrollWindow(CWnd* window); + void updateScrollInfo(); + BOOL PreTranslateMessage(MSG* pMsg); + void updateScrollInfo(int nPos); +protected: + CWnd* m_scrollWindow; //real parent is window we overlay the SB + DECLARE_MESSAGE_MAP() + UINT scrollLines; + bool haveInitScrollInfo; + bool disableNoScroll; + void drawSBArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation); +}; + diff --git a/src/mpc-hc/CMPCThemeScrollBarHelper.cpp b/src/mpc-hc/CMPCThemeScrollBarHelper.cpp index 6ba4fda95b8..2adeaa9f8f3 100644 --- a/src/mpc-hc/CMPCThemeScrollBarHelper.cpp +++ b/src/mpc-hc/CMPCThemeScrollBarHelper.cpp @@ -1,348 +1,348 @@ -#include "stdafx.h" -#include "CMPCThemeScrollBarHelper.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" - -CMPCThemeScrollBarHelper::CMPCThemeScrollBarHelper(CWnd* scrollWindow) - :helperInfo(nullptr) - ,setWindowRegionActive(false) -{ - window = scrollWindow; - pParent = nullptr; -} - - -CMPCThemeScrollBarHelper::~CMPCThemeScrollBarHelper() -{ -} - -void CMPCThemeScrollBarHelper::createThemedScrollBars() -{ - pParent = window->GetParent(); - ScrollBarHelperInfo i(window); - if (nullptr != pParent && IsWindow(pParent->m_hWnd)) { - if (i.canVSB && !IsWindow(vertSB.m_hWnd)) { - VERIFY(vertSB.Create(SBS_VERT | WS_CHILD | - WS_VISIBLE, CRect(0, 0, 0, 0), pParent, 0)); - vertSB.setScrollWindow(window); //we want messages from this SB - } - - if (i.canHSB && !IsWindow(horzSB.m_hWnd)) { - VERIFY(horzSB.Create(SBS_HORZ | WS_CHILD | - WS_VISIBLE, CRect(0, 0, 0, 0), pParent, 0)); - horzSB.setScrollWindow(window); //we want messages from this SB - } - } - hideNativeScrollBars(); -} - -void CMPCThemeScrollBarHelper::OnWindowPosChanged() { - { - std::lock_guard lck(helperMutex); - //this is to prevent recursive calls to OnWindowPos due to SetWindowRgn - if (!setWindowRegionActive) { - hideNativeScrollBars(); - } - } -} - -void CMPCThemeScrollBarHelper::setWindowRegionExclusive(HRGN h) { - { - std::lock_guard lck(helperMutex); - setWindowRegionActive = true; - } - window->SetWindowRgn(h, false); - { - std::lock_guard lck(helperMutex); - setWindowRegionActive = false; - } -} - -void CMPCThemeScrollBarHelper::hideNativeScrollBars() -{ - - if (!CMPCThemeUtil::IsWindowVisibleAndRendered(window)) { - return; - } - - bool windowChanged = helperInfo.UpdateHelperInfo(window); - - ScrollBarHelperInfo& i = helperInfo; - CRect wr = i.wr; - CRect horzRect, vertRect; - bool needsRegion = false; - - if (IsWindow(vertSB.m_hWnd)) { - if (i.canVSB) { - int width = i.sbThickness, height = wr.bottom - wr.top - 2 * i.borderThickness - (i.canHSB ? i.sbThickness : 0); - needsRegion = true; - - vertRect = CRect(CPoint(i.wrOnParent.right - width - i.borderThickness, i.wrOnParent.top + i.borderThickness), CSize(width, height)); - vertSB.MoveWindow(vertRect); - vertSB.ShowWindow(SW_SHOW); - updateScrollInfo(); - } else { - if (vertSB.IsWindowVisible()) { - CRect sbWR; - vertSB.GetWindowRect(sbWR); - vertSB.ShowWindow(SW_HIDE); - window->ScreenToClient(sbWR); - window->RedrawWindow(sbWR, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); - } - } - } - - if (IsWindow(horzSB.m_hWnd)) { - if (i.canHSB) { - int height = i.sbThickness, width = wr.right - wr.left - 2 * i.borderThickness - (i.canVSB ? i.sbThickness : 0); - needsRegion = true; - - horzRect = CRect(CPoint(i.wrOnParent.left + i.borderThickness, i.wrOnParent.bottom - height - i.borderThickness), CSize(width, height)); - horzSB.MoveWindow(horzRect); - horzSB.ShowWindow(SW_SHOW); - updateScrollInfo(); - } else { - if (horzSB.IsWindowVisible()) { - CRect sbWR; - horzSB.GetWindowRect(sbWR); - horzSB.ShowWindow(SW_HIDE); - window->ScreenToClient(sbWR); - window->RedrawWindow(sbWR, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); - } - } - } - if (needsRegion) { - if (windowChanged) { - HRGN contentRgn = CreateRectRgn(wr.left, wr.top, wr.right, wr.bottom); - if (!vertRect.IsRectEmpty()) { - ::MapWindowPoints(pParent->GetSafeHwnd(), window->GetSafeHwnd(), (LPPOINT)&vertRect, 2); - vertRect += helperInfo.clientOffset; - HRGN vertRgn = CreateRectRgnIndirect(vertRect); - CombineRgn(contentRgn, contentRgn, vertRgn, RGN_DIFF); - } - if (!horzRect.IsRectEmpty()) { - ::MapWindowPoints(pParent->GetSafeHwnd(), window->GetSafeHwnd(), (LPPOINT)&horzRect, 2); - horzRect += helperInfo.clientOffset; - HRGN horzRgn = CreateRectRgnIndirect(horzRect); - CombineRgn(contentRgn, contentRgn, horzRgn, RGN_DIFF); - } - setWindowRegionExclusive(contentRgn); - } - } else { - setWindowRegionExclusive(NULL); - } -} - -void CMPCThemeScrollBarHelper::updateScrollInfo(bool invalidate /*=false*/) -{ - if (IsWindow(vertSB.m_hWnd)) { - vertSB.updateScrollInfo(); - if (invalidate) { - vertSB.Invalidate(); - } - } - if (IsWindow(horzSB.m_hWnd)) { - horzSB.updateScrollInfo(); - if (invalidate) { - horzSB.Invalidate(); - } - } -} - - -//clistctrl does not seem to scroll when receiving thumb messages, so we handle them here -//this will allow the scrollbar to update as well -//inspired by flyhigh https://www.codeproject.com/Articles/14724/Replace-a-Window-s-Internal-Scrollbar-with-a-custo -//changed to avoid glitchy redraws and only update the scrollbar that has been changed -bool CMPCThemeScrollBarHelper::WindowProc(CListCtrl* list, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_VSCROLL || message == WM_HSCROLL) { - WORD sbCode = LOWORD(wParam); - if (sbCode == SB_THUMBTRACK || sbCode == SB_THUMBPOSITION) { - SCROLLINFO siv = { 0 }; - siv.cbSize = sizeof(SCROLLINFO); - siv.fMask = SIF_ALL; - SCROLLINFO sih = siv; - int nPos = HIWORD(wParam); - CRect rcClient; - list->GetClientRect(&rcClient); - - SIZE sizeAll; - SIZE size = { 0, 0 }; - if (WM_VSCROLL == message) { - list->GetScrollInfo(SB_VERT, &siv); - if (siv.nPage == 0) { - sizeAll.cy = rcClient.bottom; - } else { - sizeAll.cy = rcClient.bottom * (siv.nMax + 1) / siv.nPage; - } - size.cy = sizeAll.cy * (nPos - siv.nPos) / (siv.nMax + 1); - } else { - list->GetScrollInfo(SB_HORZ, &sih); - if (sih.nPage == 0) { - sizeAll.cx = rcClient.right; - } else { - sizeAll.cx = rcClient.right * (sih.nMax + 1) / sih.nPage; - } - size.cx = sizeAll.cx * (nPos - sih.nPos) / (sih.nMax + 1); - } - //adipose: this code is needed to prevent listctrl glitchy drawing. - //scroll sends a cascade of redraws which are untenable during a thumb drag - //only one redraw per scroll call this way - if (nullptr != pParent && IsWindow(pParent->m_hWnd)) { - pParent->SetRedraw(FALSE); - list->Scroll(size); - pParent->SetRedraw(); - list->Invalidate(); - CHeaderCtrl* hdrCtrl = list->GetHeaderCtrl(); - if (nullptr != hdrCtrl) { - hdrCtrl->Invalidate(); - } - } - return true; //processed - } - } - return false; -} - -bool CMPCThemeScrollBarHelper::WindowProc(CTreeCtrl* tree, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_VSCROLL || message == WM_HSCROLL) { - WORD sbCode = LOWORD(wParam); - if (sbCode == SB_THUMBTRACK || sbCode == SB_THUMBPOSITION) { - SCROLLINFO siv = { 0 }; - siv.cbSize = sizeof(SCROLLINFO); - siv.fMask = SIF_ALL; - SCROLLINFO sih = siv; - int nPos = HIWORD(wParam); - CRect rcClient; - tree->GetClientRect(&rcClient); - tree->GetScrollInfo(SB_VERT, &siv); - tree->GetScrollInfo(SB_HORZ, &sih); - - WPARAM wp = (WPARAM) - 1; - int lines = 0; - if (WM_VSCROLL == message) { - wp = nPos < siv.nPos ? SB_LINEUP : SB_LINEDOWN; - lines = abs(nPos - siv.nPos); - } else { - wp = nPos < sih.nPos ? SB_LINELEFT : SB_LINERIGHT; - lines = abs(nPos - sih.nPos); - } - - if (-1 != wp && nullptr != pParent && IsWindow(pParent->m_hWnd)) { - pParent->SetRedraw(FALSE); - while (lines-- > 0) { - tree->SendMessage(message, wp, 0); - } - pParent->SetRedraw(); - tree->Invalidate(); - } - return true; //processed - } - } - return false; -} - -void CMPCThemeScrollBarHelper::themedNcPaintWithSB() -{ - createThemedScrollBars(); - doNcPaint(window); -} - -void CMPCThemeScrollBarHelper::themedNcPaint(CWnd* window, CMPCThemeScrollable* swindow) -{ - if (window->GetStyle() & WS_HSCROLL) { - SCROLLBARINFO sbHorz = { sizeof(SCROLLBARINFO) }; - if (window->GetScrollBarInfo(OBJID_HSCROLL, &sbHorz)) { - if (0 == (sbHorz.rgstate[0] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_UNAVAILABLE))) { - swindow->doDefault(); //required to get the horz sb buttons to draw in listctrl - } - } - } - - doNcPaint(window); - if (window->GetStyle() & WS_VSCROLL) { - window->SetScrollPos(SB_VERT, window->GetScrollPos(SB_VERT), TRUE); - } -} - -ScrollBarHelperInfo::ScrollBarHelperInfo(CWnd* w): - wr(), corner(), wrOnParent() - ,sbThickness(0), borderThickness(0) - ,canVSB(false), canHSB(false), needsSBCorner(false) -{ - if (w && w->m_hWnd && IsWindow(w->m_hWnd)) { - w->GetWindowRect(wr); - - wrOnParent = wr; - CWnd* pParent = w->GetParent(); - if (nullptr != pParent) { - pParent->ScreenToClient(wrOnParent); - } - - wr.OffsetRect(-wr.left, -wr.top); - - sbThickness = GetSystemMetrics(SM_CXVSCROLL); - clientOffset = CMPCThemeUtil::GetRegionOffset(w); - borderThickness = clientOffset.x; - - auto style = w->GetStyle(); - //we have to draw vertical scrollbar because ncpaint is overridden to handle horizontal scrollbar - //windows dark theme horizontal scrollbar is broken - //exceptions: SB simply disappears if window is less than border thickness - canVSB = 0 != (style & WS_VSCROLL) && sbThickness < wr.Width() - borderThickness * 2; - canHSB = 0 != (style & WS_HSCROLL) && sbThickness < wr.Height() - borderThickness * 2; - needsSBCorner = (style & (WS_VSCROLL | WS_HSCROLL)) == (WS_VSCROLL | WS_HSCROLL) && canVSB && canHSB; - corner = { wr.right - sbThickness - borderThickness, wr.bottom - sbThickness - borderThickness, wr.right - borderThickness, wr.bottom - borderThickness }; - } -} - -bool ScrollBarHelperInfo::UpdateHelperInfo(CWnd* w) { - ScrollBarHelperInfo tmp(w); - if (tmp == *this) { - return false; - } - *this = tmp; - return true; -} - -bool ScrollBarHelperInfo::operator==(ScrollBarHelperInfo& other) { - return other.borderThickness == borderThickness && other.sbThickness == sbThickness //dimensions - && other.wr == wr && other.wrOnParent == wrOnParent && other.corner == corner //rects - && other.clientOffset == clientOffset - && other.canHSB == canHSB && other.canVSB == canVSB && other.needsSBCorner == needsSBCorner //bools - ; -} - -void CMPCThemeScrollBarHelper::doNcPaint(CWnd* window) -{ - HRGN currentRgn = CreateRectRgn(0, 0, 0, 0); - int rType = window->GetWindowRgn(currentRgn); - window->SetWindowRgn(NULL, false); - - CWindowDC dc(window); - int oldDC = dc.SaveDC(); - - CRect clip; - ScrollBarHelperInfo i(window); - - CRect &wr = i.wr; - - clip = wr; //client rect is insufficient to clip scrollbars - clip.DeflateRect(i.borderThickness, i.borderThickness); - dc.ExcludeClipRect(clip); - CBrush brush(CMPCTheme::WindowBorderColorLight); //color used for column sep in explorer - dc.FillSolidRect(wr, CMPCTheme::ContentBGColor); - dc.FrameRect(wr, &brush); - - dc.RestoreDC(oldDC); - if (i.needsSBCorner) { - dc.FillSolidRect(i.corner, CMPCTheme::ContentBGColor); - } - - if (rType == COMPLEXREGION || rType == SIMPLEREGION) { - window->SetWindowRgn(currentRgn, false); - } -} - +#include "stdafx.h" +#include "CMPCThemeScrollBarHelper.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" + +CMPCThemeScrollBarHelper::CMPCThemeScrollBarHelper(CWnd* scrollWindow) + :helperInfo(nullptr) + ,setWindowRegionActive(false) +{ + window = scrollWindow; + pParent = nullptr; +} + + +CMPCThemeScrollBarHelper::~CMPCThemeScrollBarHelper() +{ +} + +void CMPCThemeScrollBarHelper::createThemedScrollBars() +{ + pParent = window->GetParent(); + ScrollBarHelperInfo i(window); + if (nullptr != pParent && IsWindow(pParent->m_hWnd)) { + if (i.canVSB && !IsWindow(vertSB.m_hWnd)) { + VERIFY(vertSB.Create(SBS_VERT | WS_CHILD | + WS_VISIBLE, CRect(0, 0, 0, 0), pParent, 0)); + vertSB.setScrollWindow(window); //we want messages from this SB + } + + if (i.canHSB && !IsWindow(horzSB.m_hWnd)) { + VERIFY(horzSB.Create(SBS_HORZ | WS_CHILD | + WS_VISIBLE, CRect(0, 0, 0, 0), pParent, 0)); + horzSB.setScrollWindow(window); //we want messages from this SB + } + } + hideNativeScrollBars(); +} + +void CMPCThemeScrollBarHelper::OnWindowPosChanged() { + { + std::lock_guard lck(helperMutex); + //this is to prevent recursive calls to OnWindowPos due to SetWindowRgn + if (!setWindowRegionActive) { + hideNativeScrollBars(); + } + } +} + +void CMPCThemeScrollBarHelper::setWindowRegionExclusive(HRGN h) { + { + std::lock_guard lck(helperMutex); + setWindowRegionActive = true; + } + window->SetWindowRgn(h, false); + { + std::lock_guard lck(helperMutex); + setWindowRegionActive = false; + } +} + +void CMPCThemeScrollBarHelper::hideNativeScrollBars() +{ + + if (!CMPCThemeUtil::IsWindowVisibleAndRendered(window)) { + return; + } + + bool windowChanged = helperInfo.UpdateHelperInfo(window); + + ScrollBarHelperInfo& i = helperInfo; + CRect wr = i.wr; + CRect horzRect, vertRect; + bool needsRegion = false; + + if (IsWindow(vertSB.m_hWnd)) { + if (i.canVSB) { + int width = i.sbThickness, height = wr.bottom - wr.top - 2 * i.borderThickness - (i.canHSB ? i.sbThickness : 0); + needsRegion = true; + + vertRect = CRect(CPoint(i.wrOnParent.right - width - i.borderThickness, i.wrOnParent.top + i.borderThickness), CSize(width, height)); + vertSB.MoveWindow(vertRect); + vertSB.ShowWindow(SW_SHOW); + updateScrollInfo(); + } else { + if (vertSB.IsWindowVisible()) { + CRect sbWR; + vertSB.GetWindowRect(sbWR); + vertSB.ShowWindow(SW_HIDE); + window->ScreenToClient(sbWR); + window->RedrawWindow(sbWR, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + } + } + } + + if (IsWindow(horzSB.m_hWnd)) { + if (i.canHSB) { + int height = i.sbThickness, width = wr.right - wr.left - 2 * i.borderThickness - (i.canVSB ? i.sbThickness : 0); + needsRegion = true; + + horzRect = CRect(CPoint(i.wrOnParent.left + i.borderThickness, i.wrOnParent.bottom - height - i.borderThickness), CSize(width, height)); + horzSB.MoveWindow(horzRect); + horzSB.ShowWindow(SW_SHOW); + updateScrollInfo(); + } else { + if (horzSB.IsWindowVisible()) { + CRect sbWR; + horzSB.GetWindowRect(sbWR); + horzSB.ShowWindow(SW_HIDE); + window->ScreenToClient(sbWR); + window->RedrawWindow(sbWR, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); + } + } + } + if (needsRegion) { + if (windowChanged) { + HRGN contentRgn = CreateRectRgn(wr.left, wr.top, wr.right, wr.bottom); + if (!vertRect.IsRectEmpty()) { + ::MapWindowPoints(pParent->GetSafeHwnd(), window->GetSafeHwnd(), (LPPOINT)&vertRect, 2); + vertRect += helperInfo.clientOffset; + HRGN vertRgn = CreateRectRgnIndirect(vertRect); + CombineRgn(contentRgn, contentRgn, vertRgn, RGN_DIFF); + } + if (!horzRect.IsRectEmpty()) { + ::MapWindowPoints(pParent->GetSafeHwnd(), window->GetSafeHwnd(), (LPPOINT)&horzRect, 2); + horzRect += helperInfo.clientOffset; + HRGN horzRgn = CreateRectRgnIndirect(horzRect); + CombineRgn(contentRgn, contentRgn, horzRgn, RGN_DIFF); + } + setWindowRegionExclusive(contentRgn); + } + } else { + setWindowRegionExclusive(NULL); + } +} + +void CMPCThemeScrollBarHelper::updateScrollInfo(bool invalidate /*=false*/) +{ + if (IsWindow(vertSB.m_hWnd)) { + vertSB.updateScrollInfo(); + if (invalidate) { + vertSB.Invalidate(); + } + } + if (IsWindow(horzSB.m_hWnd)) { + horzSB.updateScrollInfo(); + if (invalidate) { + horzSB.Invalidate(); + } + } +} + + +//clistctrl does not seem to scroll when receiving thumb messages, so we handle them here +//this will allow the scrollbar to update as well +//inspired by flyhigh https://www.codeproject.com/Articles/14724/Replace-a-Window-s-Internal-Scrollbar-with-a-custo +//changed to avoid glitchy redraws and only update the scrollbar that has been changed +bool CMPCThemeScrollBarHelper::WindowProc(CListCtrl* list, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_VSCROLL || message == WM_HSCROLL) { + WORD sbCode = LOWORD(wParam); + if (sbCode == SB_THUMBTRACK || sbCode == SB_THUMBPOSITION) { + SCROLLINFO siv = { 0 }; + siv.cbSize = sizeof(SCROLLINFO); + siv.fMask = SIF_ALL; + SCROLLINFO sih = siv; + int nPos = HIWORD(wParam); + CRect rcClient; + list->GetClientRect(&rcClient); + + SIZE sizeAll; + SIZE size = { 0, 0 }; + if (WM_VSCROLL == message) { + list->GetScrollInfo(SB_VERT, &siv); + if (siv.nPage == 0) { + sizeAll.cy = rcClient.bottom; + } else { + sizeAll.cy = rcClient.bottom * (siv.nMax + 1) / siv.nPage; + } + size.cy = sizeAll.cy * (nPos - siv.nPos) / (siv.nMax + 1); + } else { + list->GetScrollInfo(SB_HORZ, &sih); + if (sih.nPage == 0) { + sizeAll.cx = rcClient.right; + } else { + sizeAll.cx = rcClient.right * (sih.nMax + 1) / sih.nPage; + } + size.cx = sizeAll.cx * (nPos - sih.nPos) / (sih.nMax + 1); + } + //adipose: this code is needed to prevent listctrl glitchy drawing. + //scroll sends a cascade of redraws which are untenable during a thumb drag + //only one redraw per scroll call this way + if (nullptr != pParent && IsWindow(pParent->m_hWnd)) { + pParent->SetRedraw(FALSE); + list->Scroll(size); + pParent->SetRedraw(); + list->Invalidate(); + CHeaderCtrl* hdrCtrl = list->GetHeaderCtrl(); + if (nullptr != hdrCtrl) { + hdrCtrl->Invalidate(); + } + } + return true; //processed + } + } + return false; +} + +bool CMPCThemeScrollBarHelper::WindowProc(CTreeCtrl* tree, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_VSCROLL || message == WM_HSCROLL) { + WORD sbCode = LOWORD(wParam); + if (sbCode == SB_THUMBTRACK || sbCode == SB_THUMBPOSITION) { + SCROLLINFO siv = { 0 }; + siv.cbSize = sizeof(SCROLLINFO); + siv.fMask = SIF_ALL; + SCROLLINFO sih = siv; + int nPos = HIWORD(wParam); + CRect rcClient; + tree->GetClientRect(&rcClient); + tree->GetScrollInfo(SB_VERT, &siv); + tree->GetScrollInfo(SB_HORZ, &sih); + + WPARAM wp = (WPARAM) - 1; + int lines = 0; + if (WM_VSCROLL == message) { + wp = nPos < siv.nPos ? SB_LINEUP : SB_LINEDOWN; + lines = abs(nPos - siv.nPos); + } else { + wp = nPos < sih.nPos ? SB_LINELEFT : SB_LINERIGHT; + lines = abs(nPos - sih.nPos); + } + + if (-1 != wp && nullptr != pParent && IsWindow(pParent->m_hWnd)) { + pParent->SetRedraw(FALSE); + while (lines-- > 0) { + tree->SendMessage(message, wp, 0); + } + pParent->SetRedraw(); + tree->Invalidate(); + } + return true; //processed + } + } + return false; +} + +void CMPCThemeScrollBarHelper::themedNcPaintWithSB() +{ + createThemedScrollBars(); + doNcPaint(window); +} + +void CMPCThemeScrollBarHelper::themedNcPaint(CWnd* window, CMPCThemeScrollable* swindow) +{ + if (window->GetStyle() & WS_HSCROLL) { + SCROLLBARINFO sbHorz = { sizeof(SCROLLBARINFO) }; + if (window->GetScrollBarInfo(OBJID_HSCROLL, &sbHorz)) { + if (0 == (sbHorz.rgstate[0] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_UNAVAILABLE))) { + swindow->doDefault(); //required to get the horz sb buttons to draw in listctrl + } + } + } + + doNcPaint(window); + if (window->GetStyle() & WS_VSCROLL) { + window->SetScrollPos(SB_VERT, window->GetScrollPos(SB_VERT), TRUE); + } +} + +ScrollBarHelperInfo::ScrollBarHelperInfo(CWnd* w): + wr(), corner(), wrOnParent() + ,sbThickness(0), borderThickness(0) + ,canVSB(false), canHSB(false), needsSBCorner(false) +{ + if (w && w->m_hWnd && IsWindow(w->m_hWnd)) { + w->GetWindowRect(wr); + + wrOnParent = wr; + CWnd* pParent = w->GetParent(); + if (nullptr != pParent) { + pParent->ScreenToClient(wrOnParent); + } + + wr.OffsetRect(-wr.left, -wr.top); + + sbThickness = GetSystemMetrics(SM_CXVSCROLL); + clientOffset = CMPCThemeUtil::GetRegionOffset(w); + borderThickness = clientOffset.x; + + auto style = w->GetStyle(); + //we have to draw vertical scrollbar because ncpaint is overridden to handle horizontal scrollbar + //windows dark theme horizontal scrollbar is broken + //exceptions: SB simply disappears if window is less than border thickness + canVSB = 0 != (style & WS_VSCROLL) && sbThickness < wr.Width() - borderThickness * 2; + canHSB = 0 != (style & WS_HSCROLL) && sbThickness < wr.Height() - borderThickness * 2; + needsSBCorner = (style & (WS_VSCROLL | WS_HSCROLL)) == (WS_VSCROLL | WS_HSCROLL) && canVSB && canHSB; + corner = { wr.right - sbThickness - borderThickness, wr.bottom - sbThickness - borderThickness, wr.right - borderThickness, wr.bottom - borderThickness }; + } +} + +bool ScrollBarHelperInfo::UpdateHelperInfo(CWnd* w) { + ScrollBarHelperInfo tmp(w); + if (tmp == *this) { + return false; + } + *this = tmp; + return true; +} + +bool ScrollBarHelperInfo::operator==(ScrollBarHelperInfo& other) { + return other.borderThickness == borderThickness && other.sbThickness == sbThickness //dimensions + && other.wr == wr && other.wrOnParent == wrOnParent && other.corner == corner //rects + && other.clientOffset == clientOffset + && other.canHSB == canHSB && other.canVSB == canVSB && other.needsSBCorner == needsSBCorner //bools + ; +} + +void CMPCThemeScrollBarHelper::doNcPaint(CWnd* window) +{ + HRGN currentRgn = CreateRectRgn(0, 0, 0, 0); + int rType = window->GetWindowRgn(currentRgn); + window->SetWindowRgn(NULL, false); + + CWindowDC dc(window); + int oldDC = dc.SaveDC(); + + CRect clip; + ScrollBarHelperInfo i(window); + + CRect &wr = i.wr; + + clip = wr; //client rect is insufficient to clip scrollbars + clip.DeflateRect(i.borderThickness, i.borderThickness); + dc.ExcludeClipRect(clip); + CBrush brush(CMPCTheme::WindowBorderColorLight); //color used for column sep in explorer + dc.FillSolidRect(wr, CMPCTheme::ContentBGColor); + dc.FrameRect(wr, &brush); + + dc.RestoreDC(oldDC); + if (i.needsSBCorner) { + dc.FillSolidRect(i.corner, CMPCTheme::ContentBGColor); + } + + if (rType == COMPLEXREGION || rType == SIMPLEREGION) { + window->SetWindowRgn(currentRgn, false); + } +} + diff --git a/src/mpc-hc/CMPCThemeScrollBarHelper.h b/src/mpc-hc/CMPCThemeScrollBarHelper.h index 282b0ece944..44619bcec7b 100755 --- a/src/mpc-hc/CMPCThemeScrollBarHelper.h +++ b/src/mpc-hc/CMPCThemeScrollBarHelper.h @@ -1,51 +1,51 @@ -#pragma once -#include "CMPCThemeScrollBar.h" -#include -class CMPCThemeTreeCtrl; - -class CMPCThemeScrollable -{ -public: - CMPCThemeScrollable() {}; - ~CMPCThemeScrollable() {}; - virtual void doDefault() {}; -}; - -class ScrollBarHelperInfo { -public: - ScrollBarHelperInfo(CWnd* w); - bool UpdateHelperInfo(CWnd* w); - bool operator==(ScrollBarHelperInfo& lhs); - bool operator!=(ScrollBarHelperInfo& lhs) { return !operator==(lhs); } - CRect wr, corner, wrOnParent; - CPoint clientOffset; - int sbThickness; - int borderThickness; - bool canVSB; - bool canHSB; - bool needsSBCorner; -}; - -class CMPCThemeScrollBarHelper -{ -protected: - CWnd* window, *pParent; - CMPCThemeScrollBar vertSB, horzSB; - ScrollBarHelperInfo helperInfo; - std::recursive_mutex helperMutex; - bool setWindowRegionActive; - static void doNcPaint(CWnd* window); -public: - CMPCThemeScrollBarHelper(CWnd* scrollWindow); - ~CMPCThemeScrollBarHelper(); - void createThemedScrollBars(); - void OnWindowPosChanged(); - void setWindowRegionExclusive(HRGN h); - void hideNativeScrollBars(); - void updateScrollInfo(bool invalidate = false); - bool WindowProc(CListCtrl* list, UINT message, WPARAM wParam, LPARAM lParam); - bool WindowProc(CTreeCtrl* tree, UINT message, WPARAM wParam, LPARAM lParam); - void themedNcPaintWithSB(); - static void themedNcPaint(CWnd* window, CMPCThemeScrollable* swindow); -}; - +#pragma once +#include "CMPCThemeScrollBar.h" +#include +class CMPCThemeTreeCtrl; + +class CMPCThemeScrollable +{ +public: + CMPCThemeScrollable() {}; + ~CMPCThemeScrollable() {}; + virtual void doDefault() {}; +}; + +class ScrollBarHelperInfo { +public: + ScrollBarHelperInfo(CWnd* w); + bool UpdateHelperInfo(CWnd* w); + bool operator==(ScrollBarHelperInfo& lhs); + bool operator!=(ScrollBarHelperInfo& lhs) { return !operator==(lhs); } + CRect wr, corner, wrOnParent; + CPoint clientOffset; + int sbThickness; + int borderThickness; + bool canVSB; + bool canHSB; + bool needsSBCorner; +}; + +class CMPCThemeScrollBarHelper +{ +protected: + CWnd* window, *pParent; + CMPCThemeScrollBar vertSB, horzSB; + ScrollBarHelperInfo helperInfo; + std::recursive_mutex helperMutex; + bool setWindowRegionActive; + static void doNcPaint(CWnd* window); +public: + CMPCThemeScrollBarHelper(CWnd* scrollWindow); + ~CMPCThemeScrollBarHelper(); + void createThemedScrollBars(); + void OnWindowPosChanged(); + void setWindowRegionExclusive(HRGN h); + void hideNativeScrollBars(); + void updateScrollInfo(bool invalidate = false); + bool WindowProc(CListCtrl* list, UINT message, WPARAM wParam, LPARAM lParam); + bool WindowProc(CTreeCtrl* tree, UINT message, WPARAM wParam, LPARAM lParam); + void themedNcPaintWithSB(); + static void themedNcPaint(CWnd* window, CMPCThemeScrollable* swindow); +}; + diff --git a/src/mpc-hc/CMPCThemeSliderCtrl.cpp b/src/mpc-hc/CMPCThemeSliderCtrl.cpp index 080ad31522f..7e214c239a8 100755 --- a/src/mpc-hc/CMPCThemeSliderCtrl.cpp +++ b/src/mpc-hc/CMPCThemeSliderCtrl.cpp @@ -1,201 +1,201 @@ -#include "stdafx.h" -#include "CMPCThemeSliderCtrl.h" -#include "CMPCTheme.h" -#include "mplayerc.h" -#undef SubclassWindow - -CMPCThemeSliderCtrl::CMPCThemeSliderCtrl() - : m_bDrag(false), m_bHover(false), lockToZero(false) -{ - -} - - -CMPCThemeSliderCtrl::~CMPCThemeSliderCtrl() -{ -} - -void CMPCThemeSliderCtrl::PreSubclassWindow() -{ - if (AppIsThemeLoaded()) { - CToolTipCtrl* pTip = GetToolTips(); - if (nullptr != pTip) { - themedToolTip.SubclassWindow(pTip->m_hWnd); - } - } -} - -IMPLEMENT_DYNAMIC(CMPCThemeSliderCtrl, CSliderCtrl) - -BEGIN_MESSAGE_MAP(CMPCThemeSliderCtrl, CSliderCtrl) - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeSliderCtrl::OnNMCustomdraw) - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONUP() - ON_WM_MOUSELEAVE() - ON_WM_MOUSEWHEEL() -END_MESSAGE_MAP() - - -void CMPCThemeSliderCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); - LRESULT lr = CDRF_DODEFAULT; - - if (AppIsThemeLoaded()) { - switch (pNMCD->dwDrawStage) { - case CDDS_PREPAINT: - lr = CDRF_NOTIFYITEMDRAW; - break; - - case CDDS_ITEMPREPAINT: - - if (pNMCD->dwItemSpec == TBCD_CHANNEL) { - CDC dc; - dc.Attach(pNMCD->hdc); - - CRect rect; - GetClientRect(rect); - dc.FillSolidRect(&rect, CMPCTheme::WindowBGColor); - - CRect channelRect; - GetChannelRect(channelRect); - CRect thumbRect; - GetThumbRect(thumbRect); - - CRect r; - if (TBS_VERT == (GetStyle() & TBS_VERT)) { - channelRect = CRect(channelRect.top, channelRect.left, channelRect.bottom, channelRect.right); //for vertical, channelrect returns 90deg rotated dimensions - channelRect.NormalizeRect(); - CopyRect(&pNMCD->rc, CRect(thumbRect.left + 2, channelRect.top, thumbRect.right - 3, channelRect.bottom - 2)); - CopyRect(r, &pNMCD->rc); - r.DeflateRect(6, 0, 6, 0); - } - else { - CopyRect(&pNMCD->rc, CRect(channelRect.left, thumbRect.top + 2, channelRect.right - 2, thumbRect.bottom - 3)); - CopyRect(r, &pNMCD->rc); - r.DeflateRect(0, 6, 0, 6); - } - - - dc.FillSolidRect(r, CMPCTheme::SliderChannelColor); - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - - dc.Detach(); - lr = CDRF_SKIPDEFAULT; - } else if (pNMCD->dwItemSpec == TBCD_THUMB) { - CDC dc; - dc.Attach(pNMCD->hdc); - pNMCD->rc.bottom--; - CRect r(pNMCD->rc); - r.DeflateRect(0, 0, 1, 0); - - CBrush fb; - if (m_bDrag) { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbDragColor); - } else if (m_bHover) { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbHoverColor); - } else { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbColor); - } - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - - dc.Detach(); - lr = CDRF_SKIPDEFAULT; - } - - break; - }; - } - - *pResult = lr; -} - -void CMPCThemeSliderCtrl::invalidateThumb() -{ - int max = GetRangeMax(); - SetRangeMax(max, TRUE); -} - - -void CMPCThemeSliderCtrl::checkHover(CPoint point) -{ - CRect thumbRect; - GetThumbRect(thumbRect); - bool oldHover = m_bHover; - m_bHover = false; - if (thumbRect.PtInRect(point)) { - m_bHover = true; - } - - if (m_bHover != oldHover) { - invalidateThumb(); - } -} - -void CMPCThemeSliderCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - checkHover(point); - CSliderCtrl::OnMouseMove(nFlags, point); -} - - -void CMPCThemeSliderCtrl::OnLButtonUp(UINT nFlags, CPoint point) -{ - m_bDrag = false; - invalidateThumb(); - checkHover(point); - CSliderCtrl::OnLButtonUp(nFlags, point); -} - - -void CMPCThemeSliderCtrl::OnMouseLeave() -{ - checkHover(CPoint(-1, -1)); - CSliderCtrl::OnMouseLeave(); -} - - -void CMPCThemeSliderCtrl::SendScrollMsg(WORD wSBcode, WORD wHiWPARAM /*= 0*/) { - ASSERT(::IsWindow(m_hWnd)); - CWnd* m_pParent = GetParent(); - if (m_pParent && ::IsWindow(m_pParent->m_hWnd)) { - bool isVert = GetStyle() & TBS_VERT; - m_pParent->SendMessage(isVert ? WM_VSCROLL : WM_HSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); - } -} - -BOOL CMPCThemeSliderCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { - if (lockToZero) { - WORD wSBcode = 0xFFFF; - int dir = 1; - if (zDelta >= WHEEL_DELTA) { - wSBcode = SB_LINEUP; - } else if (zDelta <= -WHEEL_DELTA) { - wSBcode = SB_LINEDOWN; - dir = -1; - zDelta = -zDelta; - } - if (wSBcode != 0xFFFF) { - int scrollIncrememt = (GetRangeMax() - GetRangeMin()) / 50; - do { - SendScrollMsg(wSBcode); - int curPos = GetPos(); - int newPos = curPos + dir * scrollIncrememt; - if (abs(newPos) < abs(scrollIncrememt) && SGN(newPos) != SGN(curPos)) { //we crossed zero and are in between +/- scrollIncrement - newPos = 0; - } - SetPos(newPos); - } while ((zDelta -= WHEEL_DELTA) >= WHEEL_DELTA); - SendScrollMsg(SB_ENDSCROLL); - } - - return 1; // Message was processed. (was 0, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 1 if scrolling enabled - } else { - return CSliderCtrl::OnMouseWheel(nFlags, zDelta, pt); - } -} +#include "stdafx.h" +#include "CMPCThemeSliderCtrl.h" +#include "CMPCTheme.h" +#include "mplayerc.h" +#undef SubclassWindow + +CMPCThemeSliderCtrl::CMPCThemeSliderCtrl() + : m_bDrag(false), m_bHover(false), lockToZero(false) +{ + +} + + +CMPCThemeSliderCtrl::~CMPCThemeSliderCtrl() +{ +} + +void CMPCThemeSliderCtrl::PreSubclassWindow() +{ + if (AppIsThemeLoaded()) { + CToolTipCtrl* pTip = GetToolTips(); + if (nullptr != pTip) { + themedToolTip.SubclassWindow(pTip->m_hWnd); + } + } +} + +IMPLEMENT_DYNAMIC(CMPCThemeSliderCtrl, CSliderCtrl) + +BEGIN_MESSAGE_MAP(CMPCThemeSliderCtrl, CSliderCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeSliderCtrl::OnNMCustomdraw) + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONUP() + ON_WM_MOUSELEAVE() + ON_WM_MOUSEWHEEL() +END_MESSAGE_MAP() + + +void CMPCThemeSliderCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); + LRESULT lr = CDRF_DODEFAULT; + + if (AppIsThemeLoaded()) { + switch (pNMCD->dwDrawStage) { + case CDDS_PREPAINT: + lr = CDRF_NOTIFYITEMDRAW; + break; + + case CDDS_ITEMPREPAINT: + + if (pNMCD->dwItemSpec == TBCD_CHANNEL) { + CDC dc; + dc.Attach(pNMCD->hdc); + + CRect rect; + GetClientRect(rect); + dc.FillSolidRect(&rect, CMPCTheme::WindowBGColor); + + CRect channelRect; + GetChannelRect(channelRect); + CRect thumbRect; + GetThumbRect(thumbRect); + + CRect r; + if (TBS_VERT == (GetStyle() & TBS_VERT)) { + channelRect = CRect(channelRect.top, channelRect.left, channelRect.bottom, channelRect.right); //for vertical, channelrect returns 90deg rotated dimensions + channelRect.NormalizeRect(); + CopyRect(&pNMCD->rc, CRect(thumbRect.left + 2, channelRect.top, thumbRect.right - 3, channelRect.bottom - 2)); + CopyRect(r, &pNMCD->rc); + r.DeflateRect(6, 0, 6, 0); + } + else { + CopyRect(&pNMCD->rc, CRect(channelRect.left, thumbRect.top + 2, channelRect.right - 2, thumbRect.bottom - 3)); + CopyRect(r, &pNMCD->rc); + r.DeflateRect(0, 6, 0, 6); + } + + + dc.FillSolidRect(r, CMPCTheme::SliderChannelColor); + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + + dc.Detach(); + lr = CDRF_SKIPDEFAULT; + } else if (pNMCD->dwItemSpec == TBCD_THUMB) { + CDC dc; + dc.Attach(pNMCD->hdc); + pNMCD->rc.bottom--; + CRect r(pNMCD->rc); + r.DeflateRect(0, 0, 1, 0); + + CBrush fb; + if (m_bDrag) { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbDragColor); + } else if (m_bHover) { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbHoverColor); + } else { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbColor); + } + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + + dc.Detach(); + lr = CDRF_SKIPDEFAULT; + } + + break; + }; + } + + *pResult = lr; +} + +void CMPCThemeSliderCtrl::invalidateThumb() +{ + int max = GetRangeMax(); + SetRangeMax(max, TRUE); +} + + +void CMPCThemeSliderCtrl::checkHover(CPoint point) +{ + CRect thumbRect; + GetThumbRect(thumbRect); + bool oldHover = m_bHover; + m_bHover = false; + if (thumbRect.PtInRect(point)) { + m_bHover = true; + } + + if (m_bHover != oldHover) { + invalidateThumb(); + } +} + +void CMPCThemeSliderCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + checkHover(point); + CSliderCtrl::OnMouseMove(nFlags, point); +} + + +void CMPCThemeSliderCtrl::OnLButtonUp(UINT nFlags, CPoint point) +{ + m_bDrag = false; + invalidateThumb(); + checkHover(point); + CSliderCtrl::OnLButtonUp(nFlags, point); +} + + +void CMPCThemeSliderCtrl::OnMouseLeave() +{ + checkHover(CPoint(-1, -1)); + CSliderCtrl::OnMouseLeave(); +} + + +void CMPCThemeSliderCtrl::SendScrollMsg(WORD wSBcode, WORD wHiWPARAM /*= 0*/) { + ASSERT(::IsWindow(m_hWnd)); + CWnd* m_pParent = GetParent(); + if (m_pParent && ::IsWindow(m_pParent->m_hWnd)) { + bool isVert = GetStyle() & TBS_VERT; + m_pParent->SendMessage(isVert ? WM_VSCROLL : WM_HSCROLL, MAKELONG(wSBcode, wHiWPARAM), (LPARAM)m_hWnd); + } +} + +BOOL CMPCThemeSliderCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { + if (lockToZero) { + WORD wSBcode = 0xFFFF; + int dir = 1; + if (zDelta >= WHEEL_DELTA) { + wSBcode = SB_LINEUP; + } else if (zDelta <= -WHEEL_DELTA) { + wSBcode = SB_LINEDOWN; + dir = -1; + zDelta = -zDelta; + } + if (wSBcode != 0xFFFF) { + int scrollIncrememt = (GetRangeMax() - GetRangeMin()) / 50; + do { + SendScrollMsg(wSBcode); + int curPos = GetPos(); + int newPos = curPos + dir * scrollIncrememt; + if (abs(newPos) < abs(scrollIncrememt) && SGN(newPos) != SGN(curPos)) { //we crossed zero and are in between +/- scrollIncrement + newPos = 0; + } + SetPos(newPos); + } while ((zDelta -= WHEEL_DELTA) >= WHEEL_DELTA); + SendScrollMsg(SB_ENDSCROLL); + } + + return 1; // Message was processed. (was 0, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 1 if scrolling enabled + } else { + return CSliderCtrl::OnMouseWheel(nFlags, zDelta, pt); + } +} diff --git a/src/mpc-hc/CMPCThemeSliderCtrl.h b/src/mpc-hc/CMPCThemeSliderCtrl.h index 0f5db77a87c..31b0165fceb 100755 --- a/src/mpc-hc/CMPCThemeSliderCtrl.h +++ b/src/mpc-hc/CMPCThemeSliderCtrl.h @@ -1,28 +1,28 @@ -#pragma once -#include -#include "CMPCThemeToolTipCtrl.h" - -class CMPCThemeSliderCtrl : public CSliderCtrl -{ -public: - CMPCThemeSliderCtrl(); - virtual ~CMPCThemeSliderCtrl(); - virtual void PreSubclassWindow(); - DECLARE_DYNAMIC(CMPCThemeSliderCtrl) - DECLARE_MESSAGE_MAP() -protected: - CBrush bgBrush; - bool m_bDrag, m_bHover, lockToZero; - CMPCThemeToolTipCtrl themedToolTip; -public: - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - void invalidateThumb(); - void checkHover(CPoint point); - void SendScrollMsg(WORD wSBcode, WORD wHiWPARAM = 0); - void SetLockToZero(bool enable = true) { lockToZero = enable; }; - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); -}; - +#pragma once +#include +#include "CMPCThemeToolTipCtrl.h" + +class CMPCThemeSliderCtrl : public CSliderCtrl +{ +public: + CMPCThemeSliderCtrl(); + virtual ~CMPCThemeSliderCtrl(); + virtual void PreSubclassWindow(); + DECLARE_DYNAMIC(CMPCThemeSliderCtrl) + DECLARE_MESSAGE_MAP() +protected: + CBrush bgBrush; + bool m_bDrag, m_bHover, lockToZero; + CMPCThemeToolTipCtrl themedToolTip; +public: + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + void invalidateThumb(); + void checkHover(CPoint point); + void SendScrollMsg(WORD wSBcode, WORD wHiWPARAM = 0); + void SetLockToZero(bool enable = true) { lockToZero = enable; }; + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); +}; + diff --git a/src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp b/src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp index dec930635c2..493e121b276 100755 --- a/src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp +++ b/src/mpc-hc/CMPCThemeSpinButtonCtrl.cpp @@ -1,236 +1,236 @@ -#include "stdafx.h" -#include "DpiHelper.h" -#include "CMPCThemeSpinButtonCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeEdit.h" -#include "mplayerc.h" - -CMPCThemeSpinButtonCtrl::CMPCThemeSpinButtonCtrl() -{ -} - - -CMPCThemeSpinButtonCtrl::~CMPCThemeSpinButtonCtrl() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeSpinButtonCtrl, CSpinButtonCtrl) -BEGIN_MESSAGE_MAP(CMPCThemeSpinButtonCtrl, CSpinButtonCtrl) - ON_WM_PAINT() - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONDOWN() - ON_WM_LBUTTONUP() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - - -void CMPCThemeSpinButtonCtrl::drawSpinArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation) -{ - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - Gdiplus::Graphics gfx(dc.m_hDC); - Gdiplus::Color clr; - clr.SetFromCOLORREF(arrowClr); - - int dpi = dpiWindow.DPIX(); - float steps; - - if (dpi < 120) { - steps = 2; - } else if (dpi < 144) { - steps = 3; - } else if (dpi < 168) { - steps = 4; - } else if (dpi < 192) { - steps = 4; - } else { - steps = 4.5; - } - - int xPos; - int yPos; - int xsign, ysign; - switch (orientation) { - case arrowLeft: - xPos = arrowRect.right - (arrowRect.Width() - (steps)) / 2; - yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; - xsign = -1; - ysign = 1; - break; - case arrowRight: - xPos = arrowRect.left + (arrowRect.Width() - (steps + 1)) / 2; - yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; - xsign = 1; - ysign = 1; - break; - case arrowTop: - xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - yPos = arrowRect.bottom - (arrowRect.Height() - (steps)) / 2; - xsign = 1; - ysign = -1; - break; - case arrowBottom: - default: - xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; - yPos = arrowRect.top + (arrowRect.Height() - (steps + 1)) / 2; - xsign = 1; - ysign = 1; - break; - } - - Gdiplus::PointF vertices[3]; - - if (orientation == arrowLeft || orientation == arrowRight) { - vertices[0] = Gdiplus::PointF(xPos, yPos); - vertices[1] = Gdiplus::PointF(xPos + steps * xsign, yPos + steps * ysign); - vertices[2] = Gdiplus::PointF(xPos, yPos + steps * 2 * ysign); - } else { - vertices[0] = Gdiplus::PointF(xPos, yPos); - vertices[1] = Gdiplus::PointF(xPos + steps * xsign, yPos + steps * ysign); - vertices[2] = Gdiplus::PointF(xPos + steps * 2 * xsign, yPos); - } - - Gdiplus::Pen pen(clr, 1); - - if (floor(steps) != steps) { - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); - } else { - gfx.SetSmoothingMode(Gdiplus::SmoothingModeNone); - } - - gfx.DrawPolygon(&pen, vertices, 3); - - Gdiplus::SolidBrush brush(clr); - gfx.FillPolygon(&brush, vertices, 3); -} - -void CMPCThemeSpinButtonCtrl::OnPaint() -{ - if (AppIsThemeLoaded()) { - CWnd* buddy = GetBuddy(); - bool hasBuddy = false; - CMPCThemeEdit* buddyEdit; - if (nullptr != buddy && nullptr != (buddyEdit = DYNAMIC_DOWNCAST(CMPCThemeEdit, buddy))) { - buddyEdit->setBuddy(this); //we need to know about the buddy spin ctrl to clip it in ncpaint :-/ - hasBuddy = true; - } - - CPaintDC dc(this); - CRect rectItem; - GetClientRect(rectItem); - - COLORREF bgClr = CMPCTheme::ContentBGColor; - - - CBrush borderBrush(CMPCTheme::EditBorderColor); - CBrush butBorderBrush(CMPCTheme::ButtonBorderInnerColor); - - dc.FillSolidRect(rectItem, bgClr); - - bool horz = 0 != (GetStyle() & UDS_HORZ); - if (horz) { - if (hasBuddy) { - dc.ExcludeClipRect(1, 0, rectItem.Width() - 1, 1); //don't get top edge of rect - dc.FrameRect(rectItem, &borderBrush); - } - } else { - if (hasBuddy) { - dc.ExcludeClipRect(0, 1, 1, rectItem.Height() - 1); //don't get left edge of rect - dc.FrameRect(rectItem, &borderBrush); - } - } - - int buddySpacing = hasBuddy ? 1 : 0; - for (int firstOrSecond = 0; firstOrSecond < 2; firstOrSecond++) { - CRect butRect = rectItem; - if (horz) { - butRect.DeflateRect(1, 1, 1, 1 + buddySpacing); - if (0 == firstOrSecond) {//left or top - butRect.right -= butRect.Width() / 2; - } else { - butRect.left += butRect.Width() / 2; - } - butRect.DeflateRect(1, 0); - } else { - butRect.DeflateRect(1, 1, 1 + buddySpacing, 1); - if (0 == firstOrSecond) {//left or top - butRect.bottom -= butRect.Height() / 2; - } else { - butRect.top += butRect.Height() / 2; - } - butRect.DeflateRect(0, 1); - } - - - if (butRect.PtInRect(downPos)) { - bgClr = CMPCTheme::ButtonFillSelectedColor; - } else { - bgClr = CMPCTheme::ButtonFillColor; - } - - dc.FillSolidRect(butRect, bgClr); - dc.FrameRect(butRect, &butBorderBrush); - - COLORREF arrowColor; - if (IsWindowEnabled()) { - arrowColor = CMPCTheme::TextFGColor; - } else { - arrowColor = CMPCTheme::ButtonDisabledFGColor; - } - - if (horz) { - if (0 == firstOrSecond) { //left - drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowLeft); - } else { - drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowRight); - } - } else { - if (0 == firstOrSecond) { //top - drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowTop); - } else { - drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowBottom); - } - } - } - - } else { - __super::OnPaint(); - } - -} - - -void CMPCThemeSpinButtonCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - CSpinButtonCtrl::OnMouseMove(nFlags, point); - if (MK_LBUTTON & nFlags) { - downPos = point; - } else { - downPos = CPoint(-1, -1); - } -} - - -void CMPCThemeSpinButtonCtrl::OnLButtonDown(UINT nFlags, CPoint point) -{ - CSpinButtonCtrl::OnLButtonDown(nFlags, point); - downPos = point; -} - - -void CMPCThemeSpinButtonCtrl::OnLButtonUp(UINT nFlags, CPoint point) -{ - CSpinButtonCtrl::OnLButtonUp(nFlags, point); - downPos = CPoint(-1, -1); -} - - -BOOL CMPCThemeSpinButtonCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} +#include "stdafx.h" +#include "DpiHelper.h" +#include "CMPCThemeSpinButtonCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeEdit.h" +#include "mplayerc.h" + +CMPCThemeSpinButtonCtrl::CMPCThemeSpinButtonCtrl() +{ +} + + +CMPCThemeSpinButtonCtrl::~CMPCThemeSpinButtonCtrl() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeSpinButtonCtrl, CSpinButtonCtrl) +BEGIN_MESSAGE_MAP(CMPCThemeSpinButtonCtrl, CSpinButtonCtrl) + ON_WM_PAINT() + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + +void CMPCThemeSpinButtonCtrl::drawSpinArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation) +{ + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + Gdiplus::Graphics gfx(dc.m_hDC); + Gdiplus::Color clr; + clr.SetFromCOLORREF(arrowClr); + + int dpi = dpiWindow.DPIX(); + float steps; + + if (dpi < 120) { + steps = 2; + } else if (dpi < 144) { + steps = 3; + } else if (dpi < 168) { + steps = 4; + } else if (dpi < 192) { + steps = 4; + } else { + steps = 4.5; + } + + int xPos; + int yPos; + int xsign, ysign; + switch (orientation) { + case arrowLeft: + xPos = arrowRect.right - (arrowRect.Width() - (steps)) / 2; + yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; + xsign = -1; + ysign = 1; + break; + case arrowRight: + xPos = arrowRect.left + (arrowRect.Width() - (steps + 1)) / 2; + yPos = arrowRect.top + (arrowRect.Height() - (steps * 2 + 1)) / 2; + xsign = 1; + ysign = 1; + break; + case arrowTop: + xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + yPos = arrowRect.bottom - (arrowRect.Height() - (steps)) / 2; + xsign = 1; + ysign = -1; + break; + case arrowBottom: + default: + xPos = arrowRect.left + (arrowRect.Width() - (steps * 2 + 1)) / 2; + yPos = arrowRect.top + (arrowRect.Height() - (steps + 1)) / 2; + xsign = 1; + ysign = 1; + break; + } + + Gdiplus::PointF vertices[3]; + + if (orientation == arrowLeft || orientation == arrowRight) { + vertices[0] = Gdiplus::PointF(xPos, yPos); + vertices[1] = Gdiplus::PointF(xPos + steps * xsign, yPos + steps * ysign); + vertices[2] = Gdiplus::PointF(xPos, yPos + steps * 2 * ysign); + } else { + vertices[0] = Gdiplus::PointF(xPos, yPos); + vertices[1] = Gdiplus::PointF(xPos + steps * xsign, yPos + steps * ysign); + vertices[2] = Gdiplus::PointF(xPos + steps * 2 * xsign, yPos); + } + + Gdiplus::Pen pen(clr, 1); + + if (floor(steps) != steps) { + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); + } else { + gfx.SetSmoothingMode(Gdiplus::SmoothingModeNone); + } + + gfx.DrawPolygon(&pen, vertices, 3); + + Gdiplus::SolidBrush brush(clr); + gfx.FillPolygon(&brush, vertices, 3); +} + +void CMPCThemeSpinButtonCtrl::OnPaint() +{ + if (AppIsThemeLoaded()) { + CWnd* buddy = GetBuddy(); + bool hasBuddy = false; + CMPCThemeEdit* buddyEdit; + if (nullptr != buddy && nullptr != (buddyEdit = DYNAMIC_DOWNCAST(CMPCThemeEdit, buddy))) { + buddyEdit->setBuddy(this); //we need to know about the buddy spin ctrl to clip it in ncpaint :-/ + hasBuddy = true; + } + + CPaintDC dc(this); + CRect rectItem; + GetClientRect(rectItem); + + COLORREF bgClr = CMPCTheme::ContentBGColor; + + + CBrush borderBrush(CMPCTheme::EditBorderColor); + CBrush butBorderBrush(CMPCTheme::ButtonBorderInnerColor); + + dc.FillSolidRect(rectItem, bgClr); + + bool horz = 0 != (GetStyle() & UDS_HORZ); + if (horz) { + if (hasBuddy) { + dc.ExcludeClipRect(1, 0, rectItem.Width() - 1, 1); //don't get top edge of rect + dc.FrameRect(rectItem, &borderBrush); + } + } else { + if (hasBuddy) { + dc.ExcludeClipRect(0, 1, 1, rectItem.Height() - 1); //don't get left edge of rect + dc.FrameRect(rectItem, &borderBrush); + } + } + + int buddySpacing = hasBuddy ? 1 : 0; + for (int firstOrSecond = 0; firstOrSecond < 2; firstOrSecond++) { + CRect butRect = rectItem; + if (horz) { + butRect.DeflateRect(1, 1, 1, 1 + buddySpacing); + if (0 == firstOrSecond) {//left or top + butRect.right -= butRect.Width() / 2; + } else { + butRect.left += butRect.Width() / 2; + } + butRect.DeflateRect(1, 0); + } else { + butRect.DeflateRect(1, 1, 1 + buddySpacing, 1); + if (0 == firstOrSecond) {//left or top + butRect.bottom -= butRect.Height() / 2; + } else { + butRect.top += butRect.Height() / 2; + } + butRect.DeflateRect(0, 1); + } + + + if (butRect.PtInRect(downPos)) { + bgClr = CMPCTheme::ButtonFillSelectedColor; + } else { + bgClr = CMPCTheme::ButtonFillColor; + } + + dc.FillSolidRect(butRect, bgClr); + dc.FrameRect(butRect, &butBorderBrush); + + COLORREF arrowColor; + if (IsWindowEnabled()) { + arrowColor = CMPCTheme::TextFGColor; + } else { + arrowColor = CMPCTheme::ButtonDisabledFGColor; + } + + if (horz) { + if (0 == firstOrSecond) { //left + drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowLeft); + } else { + drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowRight); + } + } else { + if (0 == firstOrSecond) { //top + drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowTop); + } else { + drawSpinArrow(dc, arrowColor, butRect, arrowOrientation::arrowBottom); + } + } + } + + } else { + __super::OnPaint(); + } + +} + + +void CMPCThemeSpinButtonCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + CSpinButtonCtrl::OnMouseMove(nFlags, point); + if (MK_LBUTTON & nFlags) { + downPos = point; + } else { + downPos = CPoint(-1, -1); + } +} + + +void CMPCThemeSpinButtonCtrl::OnLButtonDown(UINT nFlags, CPoint point) +{ + CSpinButtonCtrl::OnLButtonDown(nFlags, point); + downPos = point; +} + + +void CMPCThemeSpinButtonCtrl::OnLButtonUp(UINT nFlags, CPoint point) +{ + CSpinButtonCtrl::OnLButtonUp(nFlags, point); + downPos = CPoint(-1, -1); +} + + +BOOL CMPCThemeSpinButtonCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} diff --git a/src/mpc-hc/CMPCThemeSpinButtonCtrl.h b/src/mpc-hc/CMPCThemeSpinButtonCtrl.h index b1835d58b82..8abdfda0ed0 100755 --- a/src/mpc-hc/CMPCThemeSpinButtonCtrl.h +++ b/src/mpc-hc/CMPCThemeSpinButtonCtrl.h @@ -1,27 +1,27 @@ -#pragma once -#include -class CMPCThemeSpinButtonCtrl : public CSpinButtonCtrl -{ -public: - CMPCThemeSpinButtonCtrl(); - virtual ~CMPCThemeSpinButtonCtrl(); - DECLARE_DYNAMIC(CMPCThemeSpinButtonCtrl) - enum arrowOrientation { - arrowLeft, - arrowRight, - arrowTop, - arrowBottom - }; - - - DECLARE_MESSAGE_MAP() - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -protected: - CPoint downPos; - void drawSpinArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation); - void OnPaint(); -}; - +#pragma once +#include +class CMPCThemeSpinButtonCtrl : public CSpinButtonCtrl +{ +public: + CMPCThemeSpinButtonCtrl(); + virtual ~CMPCThemeSpinButtonCtrl(); + DECLARE_DYNAMIC(CMPCThemeSpinButtonCtrl) + enum arrowOrientation { + arrowLeft, + arrowRight, + arrowTop, + arrowBottom + }; + + + DECLARE_MESSAGE_MAP() + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +protected: + CPoint downPos; + void drawSpinArrow(CDC& dc, COLORREF arrowClr, CRect arrowRect, arrowOrientation orientation); + void OnPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeStatic.cpp b/src/mpc-hc/CMPCThemeStatic.cpp index d332ded6bb5..cd81363d984 100755 --- a/src/mpc-hc/CMPCThemeStatic.cpp +++ b/src/mpc-hc/CMPCThemeStatic.cpp @@ -1,179 +1,179 @@ -#include "stdafx.h" -#include "CMPCThemeStatic.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -CMPCThemeStatic::CMPCThemeStatic() -{ - isFileDialogChild = false; -} - - -CMPCThemeStatic::~CMPCThemeStatic() -{ -} -IMPLEMENT_DYNAMIC(CMPCThemeStatic, CStatic) -BEGIN_MESSAGE_MAP(CMPCThemeStatic, CStatic) - ON_WM_PAINT() - ON_WM_NCPAINT() - ON_WM_ENABLE() - ON_WM_ERASEBKGND() - ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, ResizeSupport) -END_MESSAGE_MAP() - -//this message is sent by resizablelib -//we prevent clipping for statics as they don't get redrawn correctly after erasing -LRESULT CMPCThemeStatic::ResizeSupport(WPARAM wParam, LPARAM lParam) { - if (AppNeedsThemedControls()) { - if (wParam == RSZSUP_QUERYPROPERTIES) { - LPRESIZEPROPERTIES props = (LPRESIZEPROPERTIES)lParam; - props->bAskClipping = false; - props->bCachedLikesClipping = false; - return TRUE; - } - } - return FALSE; -} - -void CMPCThemeStatic::OnPaint() -{ - if (AppNeedsThemedControls()) { - CPaintDC dc(this); - - CString sTitle; - GetWindowText(sTitle); - CRect rectItem; - GetClientRect(rectItem); - dc.SetBkMode(TRANSPARENT); - - COLORREF oldBkColor = dc.GetBkColor(); - COLORREF oldTextColor = dc.GetTextColor(); - - bool isDisabled = !IsWindowEnabled(); - UINT style = GetStyle(); - - if (!sTitle.IsEmpty()) { - bool canWrap = sTitle.Find(_T("\n")) != -1; - - CFont* font = GetFont(); - CFont* pOldFont = dc.SelectObject(font); - - UINT uFormat = 0; - if (style & SS_LEFTNOWORDWRAP) { - if (!canWrap) { - uFormat |= DT_SINGLELINE; - } - } else { - uFormat |= DT_WORDBREAK; - } - - if (0 != (style & SS_CENTERIMAGE) && !canWrap) { - //If the static control contains a single line of text, the text is centered vertically in the client area of the control. msdn - uFormat |= DT_SINGLELINE; - uFormat |= DT_VCENTER; - } else { - uFormat |= DT_TOP; - } - - if ((style & SS_CENTER) == SS_CENTER) { - uFormat |= DT_CENTER; - } else if ((style & SS_RIGHT) == SS_RIGHT) { - uFormat |= DT_RIGHT; - } else { // if ((style & SS_LEFT) == SS_LEFT || (style & SS_LEFTNOWORDWRAP) == SS_LEFTNOWORDWRAP) { - uFormat |= DT_LEFT; - } - - UINT ellipsisStyle = (style & SS_ELLIPSISMASK); - if (ellipsisStyle == SS_PATHELLIPSIS) { - uFormat |= DT_PATH_ELLIPSIS; - } else if (ellipsisStyle == SS_ENDELLIPSIS) { - uFormat |= DT_END_ELLIPSIS; - } else if (ellipsisStyle == SS_WORDELLIPSIS) { - uFormat |= DT_WORD_ELLIPSIS; - } - - if ((SendMessage(WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { - uFormat |= DT_HIDEPREFIX; - } - - dc.SetBkColor(CMPCTheme::WindowBGColor); - if (isDisabled) { - dc.SetTextColor(CMPCTheme::ButtonDisabledFGColor); - dc.DrawTextW(sTitle, -1, &rectItem, uFormat); - } else { - dc.SetTextColor(CMPCTheme::TextFGColor); - dc.DrawTextW(sTitle, -1, &rectItem, uFormat); - } - dc.SelectObject(pOldFont); - dc.SetBkColor(oldBkColor); - dc.SetTextColor(oldTextColor); - } - } else { - __super::OnPaint(); - } -} - - -void CMPCThemeStatic::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - CDC* pDC = GetWindowDC(); - - CRect rect; - GetWindowRect(&rect); - rect.OffsetRect(-rect.left, -rect.top); - DWORD type = GetStyle() & SS_TYPEMASK; - - if (SS_ETCHEDHORZ == type || SS_ETCHEDVERT == type) { //etched lines assumed - rect.DeflateRect(0, 0, 1, 1); //make it thinner - CBrush brush(CMPCTheme::StaticEtchedColor); - pDC->FillSolidRect(rect, CMPCTheme::StaticEtchedColor); - } else if (SS_ETCHEDFRAME == type) { //etched border - CBrush brush(CMPCTheme::StaticEtchedColor); - pDC->FrameRect(rect, &brush); - } else { //not supported yet - } - - ReleaseDC(pDC); - } else { - CStatic::OnNcPaint(); - } -} - -void CMPCThemeStatic::OnEnable(BOOL bEnable) -{ - if (AppNeedsThemedControls()) { - SetRedraw(FALSE); - __super::OnEnable(bEnable); - SetRedraw(TRUE); - CWnd* parent = GetParent(); - if (nullptr != parent) { - CRect wr; - GetWindowRect(wr); - parent->ScreenToClient(wr); - parent->InvalidateRect(wr, TRUE); - } else { - Invalidate(); - } - } else { - __super::OnEnable(bEnable); - } -} - -BOOL CMPCThemeStatic::OnEraseBkgnd(CDC* pDC) -{ - if (AppNeedsThemedControls()) { - CRect r; - GetClientRect(r); - if (isFileDialogChild) { - HBRUSH hBrush = CMPCThemeUtil::getCtlColorFileDialog(pDC->GetSafeHdc(), CTLCOLOR_STATIC); - ::FillRect(pDC->GetSafeHdc(), r, hBrush); - } else { - CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); - } - return TRUE; - } else { - return CStatic::OnEraseBkgnd(pDC); - } -} +#include "stdafx.h" +#include "CMPCThemeStatic.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +CMPCThemeStatic::CMPCThemeStatic() +{ + isFileDialogChild = false; +} + + +CMPCThemeStatic::~CMPCThemeStatic() +{ +} +IMPLEMENT_DYNAMIC(CMPCThemeStatic, CStatic) +BEGIN_MESSAGE_MAP(CMPCThemeStatic, CStatic) + ON_WM_PAINT() + ON_WM_NCPAINT() + ON_WM_ENABLE() + ON_WM_ERASEBKGND() + ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, ResizeSupport) +END_MESSAGE_MAP() + +//this message is sent by resizablelib +//we prevent clipping for statics as they don't get redrawn correctly after erasing +LRESULT CMPCThemeStatic::ResizeSupport(WPARAM wParam, LPARAM lParam) { + if (AppNeedsThemedControls()) { + if (wParam == RSZSUP_QUERYPROPERTIES) { + LPRESIZEPROPERTIES props = (LPRESIZEPROPERTIES)lParam; + props->bAskClipping = false; + props->bCachedLikesClipping = false; + return TRUE; + } + } + return FALSE; +} + +void CMPCThemeStatic::OnPaint() +{ + if (AppNeedsThemedControls()) { + CPaintDC dc(this); + + CString sTitle; + GetWindowText(sTitle); + CRect rectItem; + GetClientRect(rectItem); + dc.SetBkMode(TRANSPARENT); + + COLORREF oldBkColor = dc.GetBkColor(); + COLORREF oldTextColor = dc.GetTextColor(); + + bool isDisabled = !IsWindowEnabled(); + UINT style = GetStyle(); + + if (!sTitle.IsEmpty()) { + bool canWrap = sTitle.Find(_T("\n")) != -1; + + CFont* font = GetFont(); + CFont* pOldFont = dc.SelectObject(font); + + UINT uFormat = 0; + if (style & SS_LEFTNOWORDWRAP) { + if (!canWrap) { + uFormat |= DT_SINGLELINE; + } + } else { + uFormat |= DT_WORDBREAK; + } + + if (0 != (style & SS_CENTERIMAGE) && !canWrap) { + //If the static control contains a single line of text, the text is centered vertically in the client area of the control. msdn + uFormat |= DT_SINGLELINE; + uFormat |= DT_VCENTER; + } else { + uFormat |= DT_TOP; + } + + if ((style & SS_CENTER) == SS_CENTER) { + uFormat |= DT_CENTER; + } else if ((style & SS_RIGHT) == SS_RIGHT) { + uFormat |= DT_RIGHT; + } else { // if ((style & SS_LEFT) == SS_LEFT || (style & SS_LEFTNOWORDWRAP) == SS_LEFTNOWORDWRAP) { + uFormat |= DT_LEFT; + } + + UINT ellipsisStyle = (style & SS_ELLIPSISMASK); + if (ellipsisStyle == SS_PATHELLIPSIS) { + uFormat |= DT_PATH_ELLIPSIS; + } else if (ellipsisStyle == SS_ENDELLIPSIS) { + uFormat |= DT_END_ELLIPSIS; + } else if (ellipsisStyle == SS_WORDELLIPSIS) { + uFormat |= DT_WORD_ELLIPSIS; + } + + if ((SendMessage(WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { + uFormat |= DT_HIDEPREFIX; + } + + dc.SetBkColor(CMPCTheme::WindowBGColor); + if (isDisabled) { + dc.SetTextColor(CMPCTheme::ButtonDisabledFGColor); + dc.DrawTextW(sTitle, -1, &rectItem, uFormat); + } else { + dc.SetTextColor(CMPCTheme::TextFGColor); + dc.DrawTextW(sTitle, -1, &rectItem, uFormat); + } + dc.SelectObject(pOldFont); + dc.SetBkColor(oldBkColor); + dc.SetTextColor(oldTextColor); + } + } else { + __super::OnPaint(); + } +} + + +void CMPCThemeStatic::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + CDC* pDC = GetWindowDC(); + + CRect rect; + GetWindowRect(&rect); + rect.OffsetRect(-rect.left, -rect.top); + DWORD type = GetStyle() & SS_TYPEMASK; + + if (SS_ETCHEDHORZ == type || SS_ETCHEDVERT == type) { //etched lines assumed + rect.DeflateRect(0, 0, 1, 1); //make it thinner + CBrush brush(CMPCTheme::StaticEtchedColor); + pDC->FillSolidRect(rect, CMPCTheme::StaticEtchedColor); + } else if (SS_ETCHEDFRAME == type) { //etched border + CBrush brush(CMPCTheme::StaticEtchedColor); + pDC->FrameRect(rect, &brush); + } else { //not supported yet + } + + ReleaseDC(pDC); + } else { + CStatic::OnNcPaint(); + } +} + +void CMPCThemeStatic::OnEnable(BOOL bEnable) +{ + if (AppNeedsThemedControls()) { + SetRedraw(FALSE); + __super::OnEnable(bEnable); + SetRedraw(TRUE); + CWnd* parent = GetParent(); + if (nullptr != parent) { + CRect wr; + GetWindowRect(wr); + parent->ScreenToClient(wr); + parent->InvalidateRect(wr, TRUE); + } else { + Invalidate(); + } + } else { + __super::OnEnable(bEnable); + } +} + +BOOL CMPCThemeStatic::OnEraseBkgnd(CDC* pDC) +{ + if (AppNeedsThemedControls()) { + CRect r; + GetClientRect(r); + if (isFileDialogChild) { + HBRUSH hBrush = CMPCThemeUtil::getCtlColorFileDialog(pDC->GetSafeHdc(), CTLCOLOR_STATIC); + ::FillRect(pDC->GetSafeHdc(), r, hBrush); + } else { + CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); + } + return TRUE; + } else { + return CStatic::OnEraseBkgnd(pDC); + } +} diff --git a/src/mpc-hc/CMPCThemeStatic.h b/src/mpc-hc/CMPCThemeStatic.h index 1f9ff71a127..0a01379d536 100755 --- a/src/mpc-hc/CMPCThemeStatic.h +++ b/src/mpc-hc/CMPCThemeStatic.h @@ -1,21 +1,21 @@ -#pragma once -#include -class CMPCThemeStatic : - public CStatic -{ - DECLARE_DYNAMIC(CMPCThemeStatic) -public: - - CMPCThemeStatic(); - virtual ~CMPCThemeStatic(); - void setFileDialogChild(bool set) { isFileDialogChild = set; }; - DECLARE_MESSAGE_MAP() - afx_msg LRESULT ResizeSupport(WPARAM wParam, LPARAM lParam); - afx_msg void OnPaint(); - afx_msg void OnNcPaint(); - afx_msg void OnEnable(BOOL bEnable); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -protected: - bool isFileDialogChild; -}; - +#pragma once +#include +class CMPCThemeStatic : + public CStatic +{ + DECLARE_DYNAMIC(CMPCThemeStatic) +public: + + CMPCThemeStatic(); + virtual ~CMPCThemeStatic(); + void setFileDialogChild(bool set) { isFileDialogChild = set; }; + DECLARE_MESSAGE_MAP() + afx_msg LRESULT ResizeSupport(WPARAM wParam, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg void OnNcPaint(); + afx_msg void OnEnable(BOOL bEnable); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +protected: + bool isFileDialogChild; +}; + diff --git a/src/mpc-hc/CMPCThemeStaticLink.cpp b/src/mpc-hc/CMPCThemeStaticLink.cpp index 1ed69ca9c4f..6106a5306da 100755 --- a/src/mpc-hc/CMPCThemeStaticLink.cpp +++ b/src/mpc-hc/CMPCThemeStaticLink.cpp @@ -1,99 +1,99 @@ -#include "stdafx.h" -#include "CMPCThemeStaticLink.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -CMPCThemeStaticLink::CMPCThemeStaticLink(LPCTSTR lpText, bool bDeleteOnDestroy) : CStaticLink(lpText, bDeleteOnDestroy) -{ -} - -CMPCThemeStaticLink::~CMPCThemeStaticLink() -{ -} - - -IMPLEMENT_DYNAMIC(CMPCThemeStaticLink, CStaticLink) - -BEGIN_MESSAGE_MAP(CMPCThemeStaticLink, CStaticLink) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_WM_CTLCOLOR_REFLECT() - ON_WM_ENABLE() -END_MESSAGE_MAP() - - - -void CMPCThemeStaticLink::OnPaint() -{ - if (AppIsThemeLoaded()) { //only reason for custom paint is disabled statics do not honor ctlcolor and draw greyed text which looks terrible on other bgs - CPaintDC dc(this); // device context for painting - COLORREF oldBkClr = dc.GetBkColor(); - COLORREF oldTextClr = dc.GetTextColor(); - int oldBkMode = dc.GetBkMode(); - - dc.SetBkMode(TRANSPARENT); - - CRect r; - - CString text; - GetWindowText(text); - DWORD format = 0; - DWORD style = GetStyle(); - if (style & SS_RIGHT) { - format |= DT_RIGHT; - } else if (style & SS_CENTER) { - format |= DT_CENTER; - } //else DT_LEFT is default - - if (style & SS_CENTERIMAGE) { //applies to text, too - format |= DT_VCENTER; - } - - if ((SendMessage(WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { - format |= DT_HIDEPREFIX; - } - - if (!IsWindowEnabled()) { - dc.SetTextColor(CMPCTheme::ContentTextDisabledFGColorFade); - } else { - dc.SetTextColor(CMPCTheme::StaticLinkColor); - } - CFont* font = GetFont(); - CFont* oldFont = dc.SelectObject(font); - dc.DrawTextW(text, r, format | DT_CALCRECT); - CMPCThemeUtil::drawParentDialogBGClr(this, &dc, r); - dc.DrawTextW(text, r, format); - - dc.SelectObject(oldFont); - dc.SetBkColor(oldBkClr); - dc.SetTextColor(oldTextClr); - dc.SetBkMode(oldBkMode); - } else { - __super::OnPaint(); - } -} - - -HBRUSH CMPCThemeStaticLink::CtlColor(CDC* pDC, UINT nCtlColor) //avoid overridden cstaticlink ctlcolor -{ - if (AppIsThemeLoaded()) { - return NULL; - } else { - return __super::CtlColor(pDC, nCtlColor); - } -} - - -void CMPCThemeStaticLink::OnEnable(BOOL bEnable) -{ - if (AppIsThemeLoaded()) { - SetRedraw(FALSE); - __super::OnEnable(bEnable); - SetRedraw(TRUE); - Invalidate(); //WM_PAINT not handled when enabling/disabling - RedrawWindow(); - } else { - __super::OnEnable(bEnable); - } -} +#include "stdafx.h" +#include "CMPCThemeStaticLink.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +CMPCThemeStaticLink::CMPCThemeStaticLink(LPCTSTR lpText, bool bDeleteOnDestroy) : CStaticLink(lpText, bDeleteOnDestroy) +{ +} + +CMPCThemeStaticLink::~CMPCThemeStaticLink() +{ +} + + +IMPLEMENT_DYNAMIC(CMPCThemeStaticLink, CStaticLink) + +BEGIN_MESSAGE_MAP(CMPCThemeStaticLink, CStaticLink) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_CTLCOLOR_REFLECT() + ON_WM_ENABLE() +END_MESSAGE_MAP() + + + +void CMPCThemeStaticLink::OnPaint() +{ + if (AppIsThemeLoaded()) { //only reason for custom paint is disabled statics do not honor ctlcolor and draw greyed text which looks terrible on other bgs + CPaintDC dc(this); // device context for painting + COLORREF oldBkClr = dc.GetBkColor(); + COLORREF oldTextClr = dc.GetTextColor(); + int oldBkMode = dc.GetBkMode(); + + dc.SetBkMode(TRANSPARENT); + + CRect r; + + CString text; + GetWindowText(text); + DWORD format = 0; + DWORD style = GetStyle(); + if (style & SS_RIGHT) { + format |= DT_RIGHT; + } else if (style & SS_CENTER) { + format |= DT_CENTER; + } //else DT_LEFT is default + + if (style & SS_CENTERIMAGE) { //applies to text, too + format |= DT_VCENTER; + } + + if ((SendMessage(WM_QUERYUISTATE, 0, 0) & UISF_HIDEACCEL) != 0) { + format |= DT_HIDEPREFIX; + } + + if (!IsWindowEnabled()) { + dc.SetTextColor(CMPCTheme::ContentTextDisabledFGColorFade); + } else { + dc.SetTextColor(CMPCTheme::StaticLinkColor); + } + CFont* font = GetFont(); + CFont* oldFont = dc.SelectObject(font); + dc.DrawTextW(text, r, format | DT_CALCRECT); + CMPCThemeUtil::drawParentDialogBGClr(this, &dc, r); + dc.DrawTextW(text, r, format); + + dc.SelectObject(oldFont); + dc.SetBkColor(oldBkClr); + dc.SetTextColor(oldTextClr); + dc.SetBkMode(oldBkMode); + } else { + __super::OnPaint(); + } +} + + +HBRUSH CMPCThemeStaticLink::CtlColor(CDC* pDC, UINT nCtlColor) //avoid overridden cstaticlink ctlcolor +{ + if (AppIsThemeLoaded()) { + return NULL; + } else { + return __super::CtlColor(pDC, nCtlColor); + } +} + + +void CMPCThemeStaticLink::OnEnable(BOOL bEnable) +{ + if (AppIsThemeLoaded()) { + SetRedraw(FALSE); + __super::OnEnable(bEnable); + SetRedraw(TRUE); + Invalidate(); //WM_PAINT not handled when enabling/disabling + RedrawWindow(); + } else { + __super::OnEnable(bEnable); + } +} diff --git a/src/mpc-hc/CMPCThemeStaticLink.h b/src/mpc-hc/CMPCThemeStaticLink.h index fd8f6a2fcee..5d5bbe6cea5 100755 --- a/src/mpc-hc/CMPCThemeStaticLink.h +++ b/src/mpc-hc/CMPCThemeStaticLink.h @@ -1,18 +1,18 @@ -#pragma once -#include "StaticLink.h" -#include "CMPCThemeUtil.h" -class CMPCThemeStaticLink : - public CStaticLink, public CMPCThemeUtil -{ -protected: - CBrush bgBrush; -public: - DECLARE_DYNAMIC(CMPCThemeStaticLink) - CMPCThemeStaticLink(LPCTSTR lpText = nullptr, bool bDeleteOnDestroy = false); - virtual ~CMPCThemeStaticLink(); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor); - afx_msg void OnEnable(BOOL bEnable); -}; - +#pragma once +#include "StaticLink.h" +#include "CMPCThemeUtil.h" +class CMPCThemeStaticLink : + public CStaticLink, public CMPCThemeUtil +{ +protected: + CBrush bgBrush; +public: + DECLARE_DYNAMIC(CMPCThemeStaticLink) + CMPCThemeStaticLink(LPCTSTR lpText = nullptr, bool bDeleteOnDestroy = false); + virtual ~CMPCThemeStaticLink(); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor); + afx_msg void OnEnable(BOOL bEnable); +}; + diff --git a/src/mpc-hc/CMPCThemeStatusBar.cpp b/src/mpc-hc/CMPCThemeStatusBar.cpp index 63a2bdba787..6b6412bcb69 100755 --- a/src/mpc-hc/CMPCThemeStatusBar.cpp +++ b/src/mpc-hc/CMPCThemeStatusBar.cpp @@ -1,123 +1,123 @@ -#include "stdafx.h" -#include "CMPCThemeStatusBar.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" - -CMPCThemeStatusBar::CMPCThemeStatusBar() -{ -} - - -CMPCThemeStatusBar::~CMPCThemeStatusBar() -{ -} - -void CMPCThemeStatusBar::PreSubclassWindow() -{ - if (AppIsThemeLoaded()) { - ModifyStyleEx(WS_BORDER, WS_EX_STATICEDGE, 0); - } else { - __super::PreSubclassWindow(); - } -} - - -BEGIN_MESSAGE_MAP(CMPCThemeStatusBar, CStatusBar) - ON_WM_NCPAINT() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -void CMPCThemeStatusBar::SetText(LPCTSTR lpszText, int nPane, int nType) -{ - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - - if (AppIsThemeLoaded()) { - ctrl.SetText(_T(""), nPane, SBT_OWNERDRAW); - texts[nPane] = lpszText; - Invalidate(); - } else { - ctrl.SetText(lpszText, nPane, nType); - } -} - -BOOL CMPCThemeStatusBar::SetParts(int nParts, int* pWidths) -{ - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - numParts = nParts; - return ctrl.SetParts(nParts, pWidths); -} - -int CMPCThemeStatusBar::GetParts(int nParts, int* pParts) -{ - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - return ctrl.GetParts(nParts, pParts); -} - -BOOL CMPCThemeStatusBar::GetRect(int nPane, LPRECT lpRect) -{ - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - return ctrl.GetRect(nPane, lpRect); -} - - -void CMPCThemeStatusBar::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CDC dc; - dc.Attach(lpDrawItemStruct->hDC); - CRect rect(&lpDrawItemStruct->rcItem); - int item = lpDrawItemStruct->itemID; - dc.SetBkColor(CMPCTheme::StatusBarBGColor); - dc.SetTextColor(CMPCTheme::TextFGColor); - CFont font; - if (CMPCThemeUtil::getFontByType(font, this, CMPCThemeUtil::MessageFont)) { - dc.SelectObject(&font); - } - dc.FillSolidRect(rect, CMPCTheme::StatusBarBGColor); - rect.left += 4; - dc.DrawTextW(texts[item], rect, DT_NOPREFIX); - if (item < numParts - 1) { //draw a separator - CRect separator(rect.right, rect.top, rect.right + 1, rect.bottom); - dc.OffsetClipRgn(1, 0); //separator is 1 pixel beyond our rect - dc.FillSolidRect(separator, CMPCTheme::StatusBarSeparatorColor); - } - dc.Detach(); -} - - -void CMPCThemeStatusBar::OnNcPaint() -{ - if (!AppIsThemeLoaded()) { - return __super::OnNcPaint(); - } else { - CWindowDC dc(this); - - CRect rcWindow; - GetWindowRect(rcWindow); - ScreenToClient(rcWindow); - rcWindow.OffsetRect(-rcWindow.TopLeft()); - CStatusBarCtrl& ctrl = GetStatusBarCtrl(); - - int nHorz, nVert, nSpacing; - GetStatusBarCtrl().GetBorders(nHorz, nVert, nSpacing); - for (int item = 0; item < numParts; item++) { //don't touch the status bar elements; they are painted in DrawItem - CRect rc; - if (GetRect(item, rc)) { - rc.DeflateRect(1, 1, item < numParts - 1 ? 0 : 1, 1); //the rects provided to DrawItem exclude the border - dc.ExcludeClipRect(rc); - } - } - dc.FillSolidRect(rcWindow, CMPCTheme::StatusBarBGColor); - dc.SelectClipRgn(nullptr); - } -} - - -BOOL CMPCThemeStatusBar::OnEraseBkgnd(CDC* pDC) -{ - if (!AppIsThemeLoaded()) { - return __super::OnEraseBkgnd(pDC); - } else { - return TRUE; - } -} +#include "stdafx.h" +#include "CMPCThemeStatusBar.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" + +CMPCThemeStatusBar::CMPCThemeStatusBar() +{ +} + + +CMPCThemeStatusBar::~CMPCThemeStatusBar() +{ +} + +void CMPCThemeStatusBar::PreSubclassWindow() +{ + if (AppIsThemeLoaded()) { + ModifyStyleEx(WS_BORDER, WS_EX_STATICEDGE, 0); + } else { + __super::PreSubclassWindow(); + } +} + + +BEGIN_MESSAGE_MAP(CMPCThemeStatusBar, CStatusBar) + ON_WM_NCPAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +void CMPCThemeStatusBar::SetText(LPCTSTR lpszText, int nPane, int nType) +{ + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + + if (AppIsThemeLoaded()) { + ctrl.SetText(_T(""), nPane, SBT_OWNERDRAW); + texts[nPane] = lpszText; + Invalidate(); + } else { + ctrl.SetText(lpszText, nPane, nType); + } +} + +BOOL CMPCThemeStatusBar::SetParts(int nParts, int* pWidths) +{ + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + numParts = nParts; + return ctrl.SetParts(nParts, pWidths); +} + +int CMPCThemeStatusBar::GetParts(int nParts, int* pParts) +{ + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + return ctrl.GetParts(nParts, pParts); +} + +BOOL CMPCThemeStatusBar::GetRect(int nPane, LPRECT lpRect) +{ + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + return ctrl.GetRect(nPane, lpRect); +} + + +void CMPCThemeStatusBar::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC dc; + dc.Attach(lpDrawItemStruct->hDC); + CRect rect(&lpDrawItemStruct->rcItem); + int item = lpDrawItemStruct->itemID; + dc.SetBkColor(CMPCTheme::StatusBarBGColor); + dc.SetTextColor(CMPCTheme::TextFGColor); + CFont font; + if (CMPCThemeUtil::getFontByType(font, this, CMPCThemeUtil::MessageFont)) { + dc.SelectObject(&font); + } + dc.FillSolidRect(rect, CMPCTheme::StatusBarBGColor); + rect.left += 4; + dc.DrawTextW(texts[item], rect, DT_NOPREFIX); + if (item < numParts - 1) { //draw a separator + CRect separator(rect.right, rect.top, rect.right + 1, rect.bottom); + dc.OffsetClipRgn(1, 0); //separator is 1 pixel beyond our rect + dc.FillSolidRect(separator, CMPCTheme::StatusBarSeparatorColor); + } + dc.Detach(); +} + + +void CMPCThemeStatusBar::OnNcPaint() +{ + if (!AppIsThemeLoaded()) { + return __super::OnNcPaint(); + } else { + CWindowDC dc(this); + + CRect rcWindow; + GetWindowRect(rcWindow); + ScreenToClient(rcWindow); + rcWindow.OffsetRect(-rcWindow.TopLeft()); + CStatusBarCtrl& ctrl = GetStatusBarCtrl(); + + int nHorz, nVert, nSpacing; + GetStatusBarCtrl().GetBorders(nHorz, nVert, nSpacing); + for (int item = 0; item < numParts; item++) { //don't touch the status bar elements; they are painted in DrawItem + CRect rc; + if (GetRect(item, rc)) { + rc.DeflateRect(1, 1, item < numParts - 1 ? 0 : 1, 1); //the rects provided to DrawItem exclude the border + dc.ExcludeClipRect(rc); + } + } + dc.FillSolidRect(rcWindow, CMPCTheme::StatusBarBGColor); + dc.SelectClipRgn(nullptr); + } +} + + +BOOL CMPCThemeStatusBar::OnEraseBkgnd(CDC* pDC) +{ + if (!AppIsThemeLoaded()) { + return __super::OnEraseBkgnd(pDC); + } else { + return TRUE; + } +} diff --git a/src/mpc-hc/CMPCThemeStatusBar.h b/src/mpc-hc/CMPCThemeStatusBar.h index 7a2806fae53..1a5fa1d1a8c 100755 --- a/src/mpc-hc/CMPCThemeStatusBar.h +++ b/src/mpc-hc/CMPCThemeStatusBar.h @@ -1,23 +1,23 @@ -#pragma once -#include -class CMPCThemeStatusBar : - public CStatusBar -{ -public: - CMPCThemeStatusBar(); - virtual ~CMPCThemeStatusBar(); - void PreSubclassWindow(); - void SetText(LPCTSTR lpszText, int nPane, int nType); - BOOL SetParts(int nParts, int* pWidths); - int GetParts(int nParts, int* pParts); - BOOL GetRect(int nPane, LPRECT lpRect); - void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); - DECLARE_MESSAGE_MAP() -protected: - std::map texts; - int numParts; -public: - afx_msg void OnNcPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; - +#pragma once +#include +class CMPCThemeStatusBar : + public CStatusBar +{ +public: + CMPCThemeStatusBar(); + virtual ~CMPCThemeStatusBar(); + void PreSubclassWindow(); + void SetText(LPCTSTR lpszText, int nPane, int nType); + BOOL SetParts(int nParts, int* pWidths); + int GetParts(int nParts, int* pParts); + BOOL GetRect(int nPane, LPRECT lpRect); + void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + DECLARE_MESSAGE_MAP() +protected: + std::map texts; + int numParts; +public: + afx_msg void OnNcPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; + diff --git a/src/mpc-hc/CMPCThemeTabCtrl.cpp b/src/mpc-hc/CMPCThemeTabCtrl.cpp index f8f7f3fe4c0..b82a32654a3 100755 --- a/src/mpc-hc/CMPCThemeTabCtrl.cpp +++ b/src/mpc-hc/CMPCThemeTabCtrl.cpp @@ -1,200 +1,200 @@ -#include "stdafx.h" -#include "CMPCThemeTabCtrl.h" -#include "mplayerc.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" - - -CMPCThemeTabCtrl::CMPCThemeTabCtrl(): CTabCtrl() -{ -} - -CMPCThemeTabCtrl::~CMPCThemeTabCtrl() -{ -} - -void CMPCThemeTabCtrl::PreSubclassWindow() -{ -} - -IMPLEMENT_DYNAMIC(CMPCThemeTabCtrl, CTabCtrl) -BEGIN_MESSAGE_MAP(CMPCThemeTabCtrl, CTabCtrl) - ON_WM_CTLCOLOR() - ON_WM_ERASEBKGND() - ON_WM_PAINT() -END_MESSAGE_MAP() - - -HBRUSH CMPCThemeTabCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - return getCtlColor(pDC, pWnd, nCtlColor); - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} - -void CMPCThemeTabCtrl::doDrawItem(int nItem, CRect rText, bool isSelected, CDC* pDC) -{ - if (nItem != -1) { - TCITEM tcitem = { 0 }; - tcitem.mask = TCIF_TEXT | TCIF_STATE; - const int c_cchBuffer = 1024; - TCHAR lpBuffer[c_cchBuffer]; - tcitem.pszText = lpBuffer; - tcitem.cchTextMax = c_cchBuffer; - - GetItem(nItem, &tcitem); - - COLORREF oldTextColor = pDC->GetTextColor(); - COLORREF oldBkColor = pDC->GetBkColor(); - - COLORREF textColor = CMPCTheme::TextFGColor; - COLORREF bgColor; - - CRect rBorder; - rBorder = rText; - - int leftY, rightY; - if (!isSelected) { - bgColor = CMPCTheme::TabCtrlInactiveColor; - rightY = rBorder.bottom; - } else { - bgColor = CMPCTheme::WindowBGColor; - rightY = rBorder.bottom - 1; - } - - if (nItem != 0) { - leftY = rBorder.bottom - 2; //starts above the horizontal border - } else { - leftY = rBorder.bottom - 1; //starts on the border to connect with the main border - } - - pDC->FillSolidRect(rBorder, bgColor); - - CPen borderPen, *oldPen; - borderPen.CreatePen(PS_SOLID, 1, CMPCTheme::TabCtrlBorderColor); - oldPen = pDC->SelectObject(&borderPen); - pDC->MoveTo(rBorder.left, leftY); - pDC->LineTo(rBorder.left, rBorder.top); - pDC->LineTo(rBorder.right, rBorder.top); - pDC->LineTo(rBorder.right, rightY); //non-inclusive - - pDC->SelectObject(oldPen); - borderPen.DeleteObject(); - - CPoint ptCursor; - ::GetCursorPos(&ptCursor); - ScreenToClient(&ptCursor); - - UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS; - textFormat |= DT_LEFT; - rText.left += 6; - - CString text = tcitem.pszText; - pDC->SetTextColor(textColor); - pDC->SetBkColor(bgColor); - - CMPCThemeUtil::DrawBufferedText(pDC, text, rText, textFormat); - - pDC->SetTextColor(oldTextColor); - pDC->SetBkColor(oldBkColor); - } - -} - -void CMPCThemeTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CDC dc; - dc.Attach(lpDrawItemStruct->hDC); - doDrawItem(lpDrawItemStruct->itemID, lpDrawItemStruct->rcItem, 0 != (lpDrawItemStruct->itemState & ODS_SELECTED), &dc); - dc.Detach(); -} - -BOOL CMPCThemeTabCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - CRect r; - GetClientRect(r); - CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); - } - return TRUE; -} - -void CMPCThemeTabCtrl::OnPaint() -{ - if (AppIsThemeLoaded()) { - CPaintDC dc(this); // device context for painting - int oldDC = dc.SaveDC(); - CRect rClient, rContent, rectDC; - GetClientRect(rClient); - rectDC = rClient; - - CDC dcMem; - CBitmap bmMem; - CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, rectDC); - rClient.OffsetRect(-rectDC.TopLeft()); - - dcMem.SelectObject(GetFont()); - - DRAWITEMSTRUCT dItemStruct; - dItemStruct.CtlType = ODT_TAB; - dItemStruct.CtlID = GetDlgCtrlID(); - dItemStruct.hwndItem = GetSafeHwnd(); - dItemStruct.hDC = dcMem.GetSafeHdc(); - dItemStruct.itemAction = ODA_DRAWENTIRE; - dItemStruct.rcItem = rClient; - - rContent = dItemStruct.rcItem; - AdjustRect(FALSE, rContent); - dItemStruct.rcItem.top = rContent.top - 2; - - COLORREF oldTextColor = dcMem.GetTextColor(); - COLORREF oldBkColor = dcMem.GetBkColor(); - - CBrush contentFrameBrush; - contentFrameBrush.CreateSolidBrush(CMPCTheme::TabCtrlBorderColor); - rContent.InflateRect(1, 1); - dcMem.FrameRect(rContent, &CMPCThemeUtil::windowBrush); - rContent.InflateRect(1, 1); - dcMem.FrameRect(rContent, &contentFrameBrush); - contentBrush.DeleteObject(); - - dcMem.SetTextColor(oldTextColor); - dcMem.SetBkColor(oldBkColor); - - - int nTab = GetItemCount(); - int nSel = GetCurSel(); - - if (!nTab) { - return; - } - - while (nTab--) { - if (nTab != nSel) { - dItemStruct.itemID = nTab; - dItemStruct.itemState = 0; - - VERIFY(GetItemRect(nTab, &dItemStruct.rcItem)); - DrawItem(&dItemStruct); - } - } - - dItemStruct.itemID = nSel; - dItemStruct.itemState = ODS_SELECTED; - - VERIFY(GetItemRect(nSel, &dItemStruct.rcItem)); - - dItemStruct.rcItem.bottom += 2; - dItemStruct.rcItem.top -= 2; - DrawItem(&dItemStruct); - - CMPCThemeUtil::flushMemDC(&dc, dcMem, rectDC); - dc.RestoreDC(oldDC); - } else { - __super::OnPaint(); - } -} - +#include "stdafx.h" +#include "CMPCThemeTabCtrl.h" +#include "mplayerc.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" + + +CMPCThemeTabCtrl::CMPCThemeTabCtrl(): CTabCtrl() +{ +} + +CMPCThemeTabCtrl::~CMPCThemeTabCtrl() +{ +} + +void CMPCThemeTabCtrl::PreSubclassWindow() +{ +} + +IMPLEMENT_DYNAMIC(CMPCThemeTabCtrl, CTabCtrl) +BEGIN_MESSAGE_MAP(CMPCThemeTabCtrl, CTabCtrl) + ON_WM_CTLCOLOR() + ON_WM_ERASEBKGND() + ON_WM_PAINT() +END_MESSAGE_MAP() + + +HBRUSH CMPCThemeTabCtrl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + return getCtlColor(pDC, pWnd, nCtlColor); + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} + +void CMPCThemeTabCtrl::doDrawItem(int nItem, CRect rText, bool isSelected, CDC* pDC) +{ + if (nItem != -1) { + TCITEM tcitem = { 0 }; + tcitem.mask = TCIF_TEXT | TCIF_STATE; + const int c_cchBuffer = 1024; + TCHAR lpBuffer[c_cchBuffer]; + tcitem.pszText = lpBuffer; + tcitem.cchTextMax = c_cchBuffer; + + GetItem(nItem, &tcitem); + + COLORREF oldTextColor = pDC->GetTextColor(); + COLORREF oldBkColor = pDC->GetBkColor(); + + COLORREF textColor = CMPCTheme::TextFGColor; + COLORREF bgColor; + + CRect rBorder; + rBorder = rText; + + int leftY, rightY; + if (!isSelected) { + bgColor = CMPCTheme::TabCtrlInactiveColor; + rightY = rBorder.bottom; + } else { + bgColor = CMPCTheme::WindowBGColor; + rightY = rBorder.bottom - 1; + } + + if (nItem != 0) { + leftY = rBorder.bottom - 2; //starts above the horizontal border + } else { + leftY = rBorder.bottom - 1; //starts on the border to connect with the main border + } + + pDC->FillSolidRect(rBorder, bgColor); + + CPen borderPen, *oldPen; + borderPen.CreatePen(PS_SOLID, 1, CMPCTheme::TabCtrlBorderColor); + oldPen = pDC->SelectObject(&borderPen); + pDC->MoveTo(rBorder.left, leftY); + pDC->LineTo(rBorder.left, rBorder.top); + pDC->LineTo(rBorder.right, rBorder.top); + pDC->LineTo(rBorder.right, rightY); //non-inclusive + + pDC->SelectObject(oldPen); + borderPen.DeleteObject(); + + CPoint ptCursor; + ::GetCursorPos(&ptCursor); + ScreenToClient(&ptCursor); + + UINT textFormat = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS; + textFormat |= DT_LEFT; + rText.left += 6; + + CString text = tcitem.pszText; + pDC->SetTextColor(textColor); + pDC->SetBkColor(bgColor); + + CMPCThemeUtil::DrawBufferedText(pDC, text, rText, textFormat); + + pDC->SetTextColor(oldTextColor); + pDC->SetBkColor(oldBkColor); + } + +} + +void CMPCThemeTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC dc; + dc.Attach(lpDrawItemStruct->hDC); + doDrawItem(lpDrawItemStruct->itemID, lpDrawItemStruct->rcItem, 0 != (lpDrawItemStruct->itemState & ODS_SELECTED), &dc); + dc.Detach(); +} + +BOOL CMPCThemeTabCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + CRect r; + GetClientRect(r); + CMPCThemeUtil::drawParentDialogBGClr(this, pDC, r); + } + return TRUE; +} + +void CMPCThemeTabCtrl::OnPaint() +{ + if (AppIsThemeLoaded()) { + CPaintDC dc(this); // device context for painting + int oldDC = dc.SaveDC(); + CRect rClient, rContent, rectDC; + GetClientRect(rClient); + rectDC = rClient; + + CDC dcMem; + CBitmap bmMem; + CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, rectDC); + rClient.OffsetRect(-rectDC.TopLeft()); + + dcMem.SelectObject(GetFont()); + + DRAWITEMSTRUCT dItemStruct; + dItemStruct.CtlType = ODT_TAB; + dItemStruct.CtlID = GetDlgCtrlID(); + dItemStruct.hwndItem = GetSafeHwnd(); + dItemStruct.hDC = dcMem.GetSafeHdc(); + dItemStruct.itemAction = ODA_DRAWENTIRE; + dItemStruct.rcItem = rClient; + + rContent = dItemStruct.rcItem; + AdjustRect(FALSE, rContent); + dItemStruct.rcItem.top = rContent.top - 2; + + COLORREF oldTextColor = dcMem.GetTextColor(); + COLORREF oldBkColor = dcMem.GetBkColor(); + + CBrush contentFrameBrush; + contentFrameBrush.CreateSolidBrush(CMPCTheme::TabCtrlBorderColor); + rContent.InflateRect(1, 1); + dcMem.FrameRect(rContent, &CMPCThemeUtil::windowBrush); + rContent.InflateRect(1, 1); + dcMem.FrameRect(rContent, &contentFrameBrush); + contentBrush.DeleteObject(); + + dcMem.SetTextColor(oldTextColor); + dcMem.SetBkColor(oldBkColor); + + + int nTab = GetItemCount(); + int nSel = GetCurSel(); + + if (!nTab) { + return; + } + + while (nTab--) { + if (nTab != nSel) { + dItemStruct.itemID = nTab; + dItemStruct.itemState = 0; + + VERIFY(GetItemRect(nTab, &dItemStruct.rcItem)); + DrawItem(&dItemStruct); + } + } + + dItemStruct.itemID = nSel; + dItemStruct.itemState = ODS_SELECTED; + + VERIFY(GetItemRect(nSel, &dItemStruct.rcItem)); + + dItemStruct.rcItem.bottom += 2; + dItemStruct.rcItem.top -= 2; + DrawItem(&dItemStruct); + + CMPCThemeUtil::flushMemDC(&dc, dcMem, rectDC); + dc.RestoreDC(oldDC); + } else { + __super::OnPaint(); + } +} + diff --git a/src/mpc-hc/CMPCThemeTabCtrl.h b/src/mpc-hc/CMPCThemeTabCtrl.h index a3b3f64f5df..771c9482a62 100755 --- a/src/mpc-hc/CMPCThemeTabCtrl.h +++ b/src/mpc-hc/CMPCThemeTabCtrl.h @@ -1,21 +1,21 @@ -#pragma once -#include "stdafx.h" -#include "CMPCThemeUtil.h" - -class CMPCThemeTabCtrl : public CTabCtrl, public CMPCThemeUtil -{ -public: - CMPCThemeTabCtrl(); - virtual ~CMPCThemeTabCtrl(); - void PreSubclassWindow(); - DECLARE_DYNAMIC(CMPCThemeTabCtrl) - DECLARE_MESSAGE_MAP() - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); -protected: - void doDrawItem(int nItem, CRect rText, bool isSelected, CDC* pDC); - void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); -public: - BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnPaint(); -}; - +#pragma once +#include "stdafx.h" +#include "CMPCThemeUtil.h" + +class CMPCThemeTabCtrl : public CTabCtrl, public CMPCThemeUtil +{ +public: + CMPCThemeTabCtrl(); + virtual ~CMPCThemeTabCtrl(); + void PreSubclassWindow(); + DECLARE_DYNAMIC(CMPCThemeTabCtrl) + DECLARE_MESSAGE_MAP() + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); +protected: + void doDrawItem(int nItem, CRect rText, bool isSelected, CDC* pDC); + void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); +public: + BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnPaint(); +}; + diff --git a/src/mpc-hc/CMPCThemeTitleBarControlButton.cpp b/src/mpc-hc/CMPCThemeTitleBarControlButton.cpp index d467305514f..938f4b05100 100644 --- a/src/mpc-hc/CMPCThemeTitleBarControlButton.cpp +++ b/src/mpc-hc/CMPCThemeTitleBarControlButton.cpp @@ -1,133 +1,133 @@ -#include "stdafx.h" -#include "mplayerc.h" -#include "CMPCThemeTitleBarControlButton.h" -#include "CMPCThemeUtil.h" - -BEGIN_MESSAGE_MAP(CMPCThemeTitleBarControlButton, CMFCButton) - ON_WM_PAINT() - ON_CONTROL_REFLECT(BN_CLICKED, &CMPCThemeTitleBarControlButton::OnBnClicked) -END_MESSAGE_MAP() - -CMPCThemeTitleBarControlButton::CMPCThemeTitleBarControlButton(WPARAM _buttonType) : CMFCButton() - , parent(nullptr) -{ - this->buttonType = _buttonType; - switch (buttonType) { - case SC_CLOSE: - hoverColor = CMPCTheme::CloseHoverColor; - pushedColor = CMPCTheme::ClosePushColor; - hoverInactiveColor = CMPCTheme::CloseHoverColor; - break; - case SC_MINIMIZE: - case SC_MAXIMIZE: - default: - hoverColor = CMPCTheme::W10DarkThemeTitlebarControlHoverBGColor; - pushedColor = CMPCTheme::W10DarkThemeTitlebarControlPushedBGColor; - hoverInactiveColor = CMPCTheme::W10DarkThemeTitlebarInactiveControlHoverBGColor; - break; - } -} - - -void CMPCThemeTitleBarControlButton::setParentFrame(CMPCThemeFrameUtil* _parent) -{ - this->parent = _parent; -} - -WPARAM CMPCThemeTitleBarControlButton::getButtonType() -{ - if (buttonType == SC_MAXIMIZE && parent->IsWindowZoomed()) { - return SC_RESTORE; - } - return buttonType; -} - -void CMPCThemeTitleBarControlButton::drawTitleBarButton(CDC* pDC, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias) -{ - int iconWidth = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarIconPathWidth); - int iconHeight = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarIconPathHeight); - float penThickness = CMPCThemeUtil::getConstantFByDPI(this, CMPCTheme::W10TitlebarIconPathThickness); - CRect pathRect = { - iconRect.left + (iconRect.Width() - iconWidth) / 2, - iconRect.top + (iconRect.Height() - iconHeight) / 2, - iconWidth, - iconHeight - }; - - Gdiplus::Graphics gfx(pDC->m_hDC); - if (antiAlias) { - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x8); - } - Gdiplus::Color lineClr; - lineClr.SetFromCOLORREF(CMPCTheme::W10DarkThemeTitlebarIconPenColor); - Gdiplus::Pen iPen(lineClr, penThickness); - if (penThickness >= 2) { - iPen.SetLineCap(Gdiplus::LineCapSquare, Gdiplus::LineCapSquare, Gdiplus::DashCapFlat); - } - Gdiplus::REAL lastX = 0, lastY = 0; - for (u_int i = 0; i < icon.size(); i++) { - CMPCTheme::pathPoint p = icon[i]; - Gdiplus::REAL x = (Gdiplus::REAL)(pathRect.left + p.x); - Gdiplus::REAL y = (Gdiplus::REAL)(pathRect.top + p.y); - if (p.state == CMPCTheme::newPath) { - lastX = x; - lastY = y; - } else if ((p.state == CMPCTheme::linePath || p.state == CMPCTheme::closePath) && i > 0) { - gfx.DrawLine(&iPen, lastX, lastY, x, y); - if (antiAlias && penThickness < 2) { - gfx.DrawLine(&iPen, lastX, lastY, x, y); //draw again to brighten the AA diagonals - } - lastX = x; - lastY = y; - } - } -} - - -void CMPCThemeTitleBarControlButton::OnPaint() -{ - CPaintDC dc(this); // device context for painting - CRect cr; - GetClientRect(cr); - if (IsPushed()) { - dc.FillSolidRect(cr, pushedColor); - } else if (IsHighlighted()) { - if (parent->IsWindowForeground()) { - dc.FillSolidRect(cr, hoverColor); - } else { - dc.FillSolidRect(cr, hoverInactiveColor); - } - } else { - if (nullptr != parent) { - COLORREF tbColor; - if (parent->IsWindowForeground()) { - tbColor = CMPCTheme::W10DarkThemeTitlebarBGColor; - } else { - tbColor = CMPCTheme::W10DarkThemeTitlebarInactiveBGColor; - } - dc.FillSolidRect(cr, tbColor); - } - } - DpiHelper dpiWindow; - dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); - drawTitleBarButton(&dc, cr, CMPCThemeUtil::getIconPathByDPI(this), dpiWindow.ScaleFactorX(), true); -} - -void CMPCThemeTitleBarControlButton::OnBnClicked() -{ - switch (buttonType) { - case SC_CLOSE: - parent->PostWindowMessage(WM_CLOSE, 0, 0); - break; - case SC_MINIMIZE: - parent->PostWindowMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); - break; - case SC_MAXIMIZE: - if (parent->IsWindowZoomed()) { - parent->PostWindowMessage(WM_SYSCOMMAND, SC_RESTORE, 0); - } else { - parent->PostWindowMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); - } - break; - } -} +#include "stdafx.h" +#include "mplayerc.h" +#include "CMPCThemeTitleBarControlButton.h" +#include "CMPCThemeUtil.h" + +BEGIN_MESSAGE_MAP(CMPCThemeTitleBarControlButton, CMFCButton) + ON_WM_PAINT() + ON_CONTROL_REFLECT(BN_CLICKED, &CMPCThemeTitleBarControlButton::OnBnClicked) +END_MESSAGE_MAP() + +CMPCThemeTitleBarControlButton::CMPCThemeTitleBarControlButton(WPARAM _buttonType) : CMFCButton() + , parent(nullptr) +{ + this->buttonType = _buttonType; + switch (buttonType) { + case SC_CLOSE: + hoverColor = CMPCTheme::CloseHoverColor; + pushedColor = CMPCTheme::ClosePushColor; + hoverInactiveColor = CMPCTheme::CloseHoverColor; + break; + case SC_MINIMIZE: + case SC_MAXIMIZE: + default: + hoverColor = CMPCTheme::W10DarkThemeTitlebarControlHoverBGColor; + pushedColor = CMPCTheme::W10DarkThemeTitlebarControlPushedBGColor; + hoverInactiveColor = CMPCTheme::W10DarkThemeTitlebarInactiveControlHoverBGColor; + break; + } +} + + +void CMPCThemeTitleBarControlButton::setParentFrame(CMPCThemeFrameUtil* _parent) +{ + this->parent = _parent; +} + +WPARAM CMPCThemeTitleBarControlButton::getButtonType() +{ + if (buttonType == SC_MAXIMIZE && parent->IsWindowZoomed()) { + return SC_RESTORE; + } + return buttonType; +} + +void CMPCThemeTitleBarControlButton::drawTitleBarButton(CDC* pDC, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias) +{ + int iconWidth = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarIconPathWidth); + int iconHeight = CMPCThemeUtil::getConstantByDPI(this, CMPCTheme::W10TitlebarIconPathHeight); + float penThickness = CMPCThemeUtil::getConstantFByDPI(this, CMPCTheme::W10TitlebarIconPathThickness); + CRect pathRect = { + iconRect.left + (iconRect.Width() - iconWidth) / 2, + iconRect.top + (iconRect.Height() - iconHeight) / 2, + iconWidth, + iconHeight + }; + + Gdiplus::Graphics gfx(pDC->m_hDC); + if (antiAlias) { + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x8); + } + Gdiplus::Color lineClr; + lineClr.SetFromCOLORREF(CMPCTheme::W10DarkThemeTitlebarIconPenColor); + Gdiplus::Pen iPen(lineClr, penThickness); + if (penThickness >= 2) { + iPen.SetLineCap(Gdiplus::LineCapSquare, Gdiplus::LineCapSquare, Gdiplus::DashCapFlat); + } + Gdiplus::REAL lastX = 0, lastY = 0; + for (u_int i = 0; i < icon.size(); i++) { + CMPCTheme::pathPoint p = icon[i]; + Gdiplus::REAL x = (Gdiplus::REAL)(pathRect.left + p.x); + Gdiplus::REAL y = (Gdiplus::REAL)(pathRect.top + p.y); + if (p.state == CMPCTheme::newPath) { + lastX = x; + lastY = y; + } else if ((p.state == CMPCTheme::linePath || p.state == CMPCTheme::closePath) && i > 0) { + gfx.DrawLine(&iPen, lastX, lastY, x, y); + if (antiAlias && penThickness < 2) { + gfx.DrawLine(&iPen, lastX, lastY, x, y); //draw again to brighten the AA diagonals + } + lastX = x; + lastY = y; + } + } +} + + +void CMPCThemeTitleBarControlButton::OnPaint() +{ + CPaintDC dc(this); // device context for painting + CRect cr; + GetClientRect(cr); + if (IsPushed()) { + dc.FillSolidRect(cr, pushedColor); + } else if (IsHighlighted()) { + if (parent->IsWindowForeground()) { + dc.FillSolidRect(cr, hoverColor); + } else { + dc.FillSolidRect(cr, hoverInactiveColor); + } + } else { + if (nullptr != parent) { + COLORREF tbColor; + if (parent->IsWindowForeground()) { + tbColor = CMPCTheme::W10DarkThemeTitlebarBGColor; + } else { + tbColor = CMPCTheme::W10DarkThemeTitlebarInactiveBGColor; + } + dc.FillSolidRect(cr, tbColor); + } + } + DpiHelper dpiWindow; + dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); + drawTitleBarButton(&dc, cr, CMPCThemeUtil::getIconPathByDPI(this), dpiWindow.ScaleFactorX(), true); +} + +void CMPCThemeTitleBarControlButton::OnBnClicked() +{ + switch (buttonType) { + case SC_CLOSE: + parent->PostWindowMessage(WM_CLOSE, 0, 0); + break; + case SC_MINIMIZE: + parent->PostWindowMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); + break; + case SC_MAXIMIZE: + if (parent->IsWindowZoomed()) { + parent->PostWindowMessage(WM_SYSCOMMAND, SC_RESTORE, 0); + } else { + parent->PostWindowMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0); + } + break; + } +} diff --git a/src/mpc-hc/CMPCThemeTitleBarControlButton.h b/src/mpc-hc/CMPCThemeTitleBarControlButton.h index 39fcaaf39c6..1ab7b472b55 100644 --- a/src/mpc-hc/CMPCThemeTitleBarControlButton.h +++ b/src/mpc-hc/CMPCThemeTitleBarControlButton.h @@ -1,21 +1,21 @@ -#pragma once -#include "CMPCThemeFrameUtil.h" - -class CMPCThemeTitleBarControlButton : - public CMFCButton -{ -public: - CMPCThemeTitleBarControlButton(WPARAM _buttonType); - void setParentFrame(CMPCThemeFrameUtil* parent); - WPARAM getButtonType(); -protected: - void drawTitleBarButton(CDC* pDC, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias = false); - WPARAM buttonType; - COLORREF hoverColor, pushedColor, hoverInactiveColor; - CMPCThemeFrameUtil* parent; -public: - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg void OnBnClicked(); -}; - +#pragma once +#include "CMPCThemeFrameUtil.h" + +class CMPCThemeTitleBarControlButton : + public CMFCButton +{ +public: + CMPCThemeTitleBarControlButton(WPARAM _buttonType); + void setParentFrame(CMPCThemeFrameUtil* parent); + WPARAM getButtonType(); +protected: + void drawTitleBarButton(CDC* pDC, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias = false); + WPARAM buttonType; + COLORREF hoverColor, pushedColor, hoverInactiveColor; + CMPCThemeFrameUtil* parent; +public: + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg void OnBnClicked(); +}; + diff --git a/src/mpc-hc/CMPCThemeToolTipCtrl.cpp b/src/mpc-hc/CMPCThemeToolTipCtrl.cpp index 22cf808b07b..1ff7bf3eddc 100644 --- a/src/mpc-hc/CMPCThemeToolTipCtrl.cpp +++ b/src/mpc-hc/CMPCThemeToolTipCtrl.cpp @@ -1,263 +1,263 @@ -#include "stdafx.h" -#include "CMPCThemeToolTipCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include -#include "mplayerc.h" - - -CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrl() -{ - this->useFlickerHelper = false; - this->helper = nullptr; - BOOL notBasicMode; - DwmIsCompositionEnabled(¬BasicMode); - basicMode = !notBasicMode; -} - - -CMPCThemeToolTipCtrl::~CMPCThemeToolTipCtrl() -{ - if (nullptr != helper) { - helper->DestroyWindow(); - delete helper; - } -} - -void CMPCThemeToolTipCtrl::enableFlickerHelper() -{ - if (IsAppThemed() && IsThemeActive() && !basicMode) { //in classic/basic mode, the helper gets wiped out by the fade, so we disable it - this->useFlickerHelper = true; - } -} - -IMPLEMENT_DYNAMIC(CMPCThemeToolTipCtrl, CToolTipCtrl) -BEGIN_MESSAGE_MAP(CMPCThemeToolTipCtrl, CToolTipCtrl) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_WM_CREATE() - ON_WM_MOVE() - ON_WM_SHOWWINDOW() - ON_WM_SIZE() - ON_WM_WINDOWPOSCHANGING() -END_MESSAGE_MAP() - -void CMPCThemeToolTipCtrl::drawText(CDC& dc, CMPCThemeToolTipCtrl* tt, CRect& rect, bool calcRect) -{ - CFont* font = tt->GetFont(); - CFont* pOldFont = dc.SelectObject(font); - - CString text; - tt->GetWindowText(text); - int maxWidth = tt->GetMaxTipWidth(); - int calcStyle = 0; - if (calcRect) { - calcStyle = DT_CALCRECT; - } - rect.DeflateRect(6, 2); - if (maxWidth == -1) { - if (calcRect) { - dc.DrawTextW(text, rect, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | calcStyle); - } else { - dc.DrawTextW(text, rect, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_NOPREFIX); - } - } else { - dc.DrawTextW(text, rect, DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | calcStyle); - } - rect.InflateRect(6, 2); //when calculating, put it back - if (!calcStyle) { - tt->lastDrawRect = rect; - } - - dc.SelectObject(pOldFont); -} - -void CMPCThemeToolTipCtrl::paintTT(CDC& dc, CMPCThemeToolTipCtrl* tt) -{ - CRect r; - tt->GetClientRect(r); - - dc.FillSolidRect(r, CMPCTheme::MenuBGColor); - - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::TooltipBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - COLORREF oldClr = dc.SetTextColor(CMPCTheme::TextFGColor); - drawText(dc, tt, r, false); - dc.SetTextColor(oldClr); -} - -void CMPCThemeToolTipCtrl::OnPaint() -{ - if (AppIsThemeLoaded()) { - CPaintDC dc(this); - if (useFlickerHelper) { //helper will paint - return; - } - paintTT(dc, this); - } else { - __super::OnPaint(); - } -} - - -BOOL CMPCThemeToolTipCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppIsThemeLoaded()) { - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} - - -int CMPCThemeToolTipCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (CToolTipCtrl::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - if (AppIsThemeLoaded()) { - makeHelper(); - } - return 0; -} - -void CMPCThemeToolTipCtrl::makeHelper() -{ - if (!useFlickerHelper) { - return; - } - - if (nullptr != helper) { - delete helper; - helper = nullptr; - } - CRect r; - GetClientRect(r); - if (r.Size() == CSize(0, 0)) { - return; - } - ClientToScreen(r); - - helper = DEBUG_NEW CMPCThemeToolTipCtrlHelper(this); - //do it the long way since no menu for parent - helper->CreateEx(NULL, AfxRegisterWndClass(0), NULL, WS_POPUP | WS_DISABLED, - r.left, r.top, r.right - r.left, r.bottom - r.top, - GetParent()->GetSafeHwnd(), NULL, NULL); - helper->Invalidate(); - helper->ShowWindow(SW_SHOWNOACTIVATE); -} - -void CMPCThemeToolTipCtrl::RedrawIfVisible() { - if (::IsWindow(m_hWnd) && IsWindowVisible()) { - CWindowDC dc(this); - CRect wr; - drawText(dc, this, wr, true); - if (wr != lastDrawRect) { - Update(); - } else { - RedrawWindow(); - } - } -} - -BEGIN_MESSAGE_MAP(CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper, CWnd) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_WM_NCCALCSIZE() -END_MESSAGE_MAP() - - -CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::CMPCThemeToolTipCtrlHelper(CMPCThemeToolTipCtrl* tt) -{ - this->tt = tt; -} - -CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::~CMPCThemeToolTipCtrlHelper() -{ - DestroyWindow(); -} - -void CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::OnPaint() -{ - CPaintDC dc(this); - CMPCThemeToolTipCtrl::paintTT(dc, tt); -} - - -BOOL CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::OnEraseBkgnd(CDC* pDC) -{ - return TRUE; -} - -void CMPCThemeToolTipCtrl::OnMove(int x, int y) -{ - CToolTipCtrl::OnMove(x, y); - if (AppIsThemeLoaded()) { - makeHelper(); - } -} - - -void CMPCThemeToolTipCtrl::OnShowWindow(BOOL bShow, UINT nStatus) -{ - - CToolTipCtrl::OnShowWindow(bShow, nStatus); - if (AppIsThemeLoaded()) { - if (!bShow) { - if (helper != nullptr) { - delete helper; - helper = nullptr; - } - } - } -} - -void CMPCThemeToolTipCtrl::OnSize(UINT nType, int cx, int cy) -{ - CToolTipCtrl::OnSize(nType, cx, cy); - if (AppIsThemeLoaded()) { - makeHelper(); - } -} - - -void CMPCThemeToolTipCtrl::OnWindowPosChanging(WINDOWPOS* lpwndpos) -{ - CToolTipCtrl::OnWindowPosChanging(lpwndpos); - if (AppIsThemeLoaded()) { - //hack to make it fit if fonts differ from parent. can be manually avoided - //if the parent widget is set to same font (see CMPCThemePlayerListCtrl using MessageFont now) - CString text; - GetWindowText(text); - if (text.GetLength() > 0 && GetMaxTipWidth() == -1) { - CWindowDC dc(this); - - CRect cr; - drawText(dc, this, cr, true);//calculate crect required to fit the text - - lpwndpos->cx = cr.Width(); - lpwndpos->cy = cr.Height(); - } - } -} - -//tooltip rules for how to hover on parent window -//by default tooltipctrl will simply hover at the mouse position, -//unlike the tooltips created with EnableTooltips which center below the window -//(in all cases tested-slider, combobox, edit) -void CMPCThemeToolTipCtrl::SetHoverPosition(CWnd* parent) { - if (IsWindow(parent->GetSafeHwnd())) { - CRect parentRect, ttRect; - parent->GetWindowRect(parentRect); - GetWindowRect(ttRect); - int centerOffset = (parentRect.left + parentRect.right - ttRect.left - ttRect.right) / 2; - ttRect.right += centerOffset; - ttRect.left += centerOffset; - ttRect.bottom += (parentRect.bottom - ttRect.top); - ttRect.top = parentRect.bottom; - MoveWindow(ttRect); - } -} +#include "stdafx.h" +#include "CMPCThemeToolTipCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include +#include "mplayerc.h" + + +CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrl() +{ + this->useFlickerHelper = false; + this->helper = nullptr; + BOOL notBasicMode; + DwmIsCompositionEnabled(¬BasicMode); + basicMode = !notBasicMode; +} + + +CMPCThemeToolTipCtrl::~CMPCThemeToolTipCtrl() +{ + if (nullptr != helper) { + helper->DestroyWindow(); + delete helper; + } +} + +void CMPCThemeToolTipCtrl::enableFlickerHelper() +{ + if (IsAppThemed() && IsThemeActive() && !basicMode) { //in classic/basic mode, the helper gets wiped out by the fade, so we disable it + this->useFlickerHelper = true; + } +} + +IMPLEMENT_DYNAMIC(CMPCThemeToolTipCtrl, CToolTipCtrl) +BEGIN_MESSAGE_MAP(CMPCThemeToolTipCtrl, CToolTipCtrl) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_CREATE() + ON_WM_MOVE() + ON_WM_SHOWWINDOW() + ON_WM_SIZE() + ON_WM_WINDOWPOSCHANGING() +END_MESSAGE_MAP() + +void CMPCThemeToolTipCtrl::drawText(CDC& dc, CMPCThemeToolTipCtrl* tt, CRect& rect, bool calcRect) +{ + CFont* font = tt->GetFont(); + CFont* pOldFont = dc.SelectObject(font); + + CString text; + tt->GetWindowText(text); + int maxWidth = tt->GetMaxTipWidth(); + int calcStyle = 0; + if (calcRect) { + calcStyle = DT_CALCRECT; + } + rect.DeflateRect(6, 2); + if (maxWidth == -1) { + if (calcRect) { + dc.DrawTextW(text, rect, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | calcStyle); + } else { + dc.DrawTextW(text, rect, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_NOPREFIX); + } + } else { + dc.DrawTextW(text, rect, DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | calcStyle); + } + rect.InflateRect(6, 2); //when calculating, put it back + if (!calcStyle) { + tt->lastDrawRect = rect; + } + + dc.SelectObject(pOldFont); +} + +void CMPCThemeToolTipCtrl::paintTT(CDC& dc, CMPCThemeToolTipCtrl* tt) +{ + CRect r; + tt->GetClientRect(r); + + dc.FillSolidRect(r, CMPCTheme::MenuBGColor); + + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::TooltipBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + COLORREF oldClr = dc.SetTextColor(CMPCTheme::TextFGColor); + drawText(dc, tt, r, false); + dc.SetTextColor(oldClr); +} + +void CMPCThemeToolTipCtrl::OnPaint() +{ + if (AppIsThemeLoaded()) { + CPaintDC dc(this); + if (useFlickerHelper) { //helper will paint + return; + } + paintTT(dc, this); + } else { + __super::OnPaint(); + } +} + + +BOOL CMPCThemeToolTipCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppIsThemeLoaded()) { + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} + + +int CMPCThemeToolTipCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CToolTipCtrl::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + if (AppIsThemeLoaded()) { + makeHelper(); + } + return 0; +} + +void CMPCThemeToolTipCtrl::makeHelper() +{ + if (!useFlickerHelper) { + return; + } + + if (nullptr != helper) { + delete helper; + helper = nullptr; + } + CRect r; + GetClientRect(r); + if (r.Size() == CSize(0, 0)) { + return; + } + ClientToScreen(r); + + helper = DEBUG_NEW CMPCThemeToolTipCtrlHelper(this); + //do it the long way since no menu for parent + helper->CreateEx(NULL, AfxRegisterWndClass(0), NULL, WS_POPUP | WS_DISABLED, + r.left, r.top, r.right - r.left, r.bottom - r.top, + GetParent()->GetSafeHwnd(), NULL, NULL); + helper->Invalidate(); + helper->ShowWindow(SW_SHOWNOACTIVATE); +} + +void CMPCThemeToolTipCtrl::RedrawIfVisible() { + if (::IsWindow(m_hWnd) && IsWindowVisible()) { + CWindowDC dc(this); + CRect wr; + drawText(dc, this, wr, true); + if (wr != lastDrawRect) { + Update(); + } else { + RedrawWindow(); + } + } +} + +BEGIN_MESSAGE_MAP(CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper, CWnd) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_NCCALCSIZE() +END_MESSAGE_MAP() + + +CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::CMPCThemeToolTipCtrlHelper(CMPCThemeToolTipCtrl* tt) +{ + this->tt = tt; +} + +CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::~CMPCThemeToolTipCtrlHelper() +{ + DestroyWindow(); +} + +void CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::OnPaint() +{ + CPaintDC dc(this); + CMPCThemeToolTipCtrl::paintTT(dc, tt); +} + + +BOOL CMPCThemeToolTipCtrl::CMPCThemeToolTipCtrlHelper::OnEraseBkgnd(CDC* pDC) +{ + return TRUE; +} + +void CMPCThemeToolTipCtrl::OnMove(int x, int y) +{ + CToolTipCtrl::OnMove(x, y); + if (AppIsThemeLoaded()) { + makeHelper(); + } +} + + +void CMPCThemeToolTipCtrl::OnShowWindow(BOOL bShow, UINT nStatus) +{ + + CToolTipCtrl::OnShowWindow(bShow, nStatus); + if (AppIsThemeLoaded()) { + if (!bShow) { + if (helper != nullptr) { + delete helper; + helper = nullptr; + } + } + } +} + +void CMPCThemeToolTipCtrl::OnSize(UINT nType, int cx, int cy) +{ + CToolTipCtrl::OnSize(nType, cx, cy); + if (AppIsThemeLoaded()) { + makeHelper(); + } +} + + +void CMPCThemeToolTipCtrl::OnWindowPosChanging(WINDOWPOS* lpwndpos) +{ + CToolTipCtrl::OnWindowPosChanging(lpwndpos); + if (AppIsThemeLoaded()) { + //hack to make it fit if fonts differ from parent. can be manually avoided + //if the parent widget is set to same font (see CMPCThemePlayerListCtrl using MessageFont now) + CString text; + GetWindowText(text); + if (text.GetLength() > 0 && GetMaxTipWidth() == -1) { + CWindowDC dc(this); + + CRect cr; + drawText(dc, this, cr, true);//calculate crect required to fit the text + + lpwndpos->cx = cr.Width(); + lpwndpos->cy = cr.Height(); + } + } +} + +//tooltip rules for how to hover on parent window +//by default tooltipctrl will simply hover at the mouse position, +//unlike the tooltips created with EnableTooltips which center below the window +//(in all cases tested-slider, combobox, edit) +void CMPCThemeToolTipCtrl::SetHoverPosition(CWnd* parent) { + if (IsWindow(parent->GetSafeHwnd())) { + CRect parentRect, ttRect; + parent->GetWindowRect(parentRect); + GetWindowRect(ttRect); + int centerOffset = (parentRect.left + parentRect.right - ttRect.left - ttRect.right) / 2; + ttRect.right += centerOffset; + ttRect.left += centerOffset; + ttRect.bottom += (parentRect.bottom - ttRect.top); + ttRect.top = parentRect.bottom; + MoveWindow(ttRect); + } +} diff --git a/src/mpc-hc/CMPCThemeToolTipCtrl.h b/src/mpc-hc/CMPCThemeToolTipCtrl.h index 0df2cd05b43..4280e3e479b 100755 --- a/src/mpc-hc/CMPCThemeToolTipCtrl.h +++ b/src/mpc-hc/CMPCThemeToolTipCtrl.h @@ -1,45 +1,45 @@ -#pragma once -#include - -class CMPCThemeToolTipCtrl; - - -class CMPCThemeToolTipCtrl : public CToolTipCtrl -{ - class CMPCThemeToolTipCtrlHelper : public CWnd - { - private: - CMPCThemeToolTipCtrl* tt; - public: - CMPCThemeToolTipCtrlHelper(CMPCThemeToolTipCtrl* tt); - virtual ~CMPCThemeToolTipCtrlHelper(); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - }; - - - DECLARE_DYNAMIC(CMPCThemeToolTipCtrl) -private: - bool useFlickerHelper, basicMode; - CMPCThemeToolTipCtrlHelper* helper; - void makeHelper(); - CRect lastDrawRect; -public: - CMPCThemeToolTipCtrl(); - virtual ~CMPCThemeToolTipCtrl(); - void enableFlickerHelper(); - static void drawText(CDC& dc, CMPCThemeToolTipCtrl* tt, CRect& rect, bool calcRect = false); - static void paintTT(CDC& dc, CMPCThemeToolTipCtrl* tt); - void SetHoverPosition(CWnd* parent); - void RedrawIfVisible(); - DECLARE_MESSAGE_MAP() - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnMove(int x, int y); - afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); -}; - +#pragma once +#include + +class CMPCThemeToolTipCtrl; + + +class CMPCThemeToolTipCtrl : public CToolTipCtrl +{ + class CMPCThemeToolTipCtrlHelper : public CWnd + { + private: + CMPCThemeToolTipCtrl* tt; + public: + CMPCThemeToolTipCtrlHelper(CMPCThemeToolTipCtrl* tt); + virtual ~CMPCThemeToolTipCtrlHelper(); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + }; + + + DECLARE_DYNAMIC(CMPCThemeToolTipCtrl) +private: + bool useFlickerHelper, basicMode; + CMPCThemeToolTipCtrlHelper* helper; + void makeHelper(); + CRect lastDrawRect; +public: + CMPCThemeToolTipCtrl(); + virtual ~CMPCThemeToolTipCtrl(); + void enableFlickerHelper(); + static void drawText(CDC& dc, CMPCThemeToolTipCtrl* tt, CRect& rect, bool calcRect = false); + static void paintTT(CDC& dc, CMPCThemeToolTipCtrl* tt); + void SetHoverPosition(CWnd* parent); + void RedrawIfVisible(); + DECLARE_MESSAGE_MAP() + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnMove(int x, int y); + afx_msg void OnShowWindow(BOOL bShow, UINT nStatus); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); +}; + diff --git a/src/mpc-hc/CMPCThemeTreeCtrl.cpp b/src/mpc-hc/CMPCThemeTreeCtrl.cpp index 21fcebf5c8e..7b297093007 100755 --- a/src/mpc-hc/CMPCThemeTreeCtrl.cpp +++ b/src/mpc-hc/CMPCThemeTreeCtrl.cpp @@ -1,244 +1,244 @@ -#include "stdafx.h" -#include "CMPCThemeTreeCtrl.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "mplayerc.h" -#undef SubclassWindow - - -CMPCThemeTreeCtrl::CMPCThemeTreeCtrl(): - themedSBHelper(nullptr), - themedToolTipCid((UINT_PTR) - 1) -{ - if (AppNeedsThemedControls()) { - m_brBkgnd.CreateSolidBrush(CMPCTheme::InlineEditBorderColor); - if (!CMPCThemeUtil::canUseWin10DarkTheme()) { - themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); - } - } - -} - -CMPCThemeTreeCtrl::~CMPCThemeTreeCtrl() -{ - if (nullptr != themedSBHelper) { - delete themedSBHelper; - } - m_brBkgnd.DeleteObject(); -} - -BOOL CMPCThemeTreeCtrl::PreCreateWindow(CREATESTRUCT& cs) -{ - if (AppNeedsThemedControls()) { - cs.dwExStyle |= WS_EX_CLIENTEDGE; - } - return __super::PreCreateWindow(cs); -} - -void CMPCThemeTreeCtrl::fulfillThemeReqs() -{ - if (AppNeedsThemedControls()) { - if (CMPCThemeUtil::canUseWin10DarkTheme()) { - SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); - } else { - SetWindowTheme(GetSafeHwnd(), L"", NULL); - } - SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); //necessary to prevent significant flicker - - SetLineColor(CMPCTheme::TreeCtrlLineColor); - if (nullptr == tvsTooltip.m_hWnd) { - CToolTipCtrl* t = GetToolTips(); - if (nullptr != t) { - tvsTooltip.SubclassWindow(t->m_hWnd); - } - } - } else { - //adipose--enabling this cuts down on a very minor flicker in classic mode; - //the duplicate line above is necessary due to a non-default bg. - //treat as a separate line of code to be clear that this one is "optional" while the other is not - SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); //optional - } -} - -BEGIN_MESSAGE_MAP(CMPCThemeTreeCtrl, CTreeCtrl) - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeTreeCtrl::OnNMCustomdraw) - ON_WM_ERASEBKGND() - ON_WM_DRAWITEM() - ON_WM_NCPAINT() - ON_WM_MOUSEMOVE() - ON_WM_MOUSEWHEEL() - ON_WM_VSCROLL() - ON_WM_HSCROLL() -END_MESSAGE_MAP() -IMPLEMENT_DYNAMIC(CMPCThemeTreeCtrl, CTreeCtrl) - -BOOL CMPCThemeTreeCtrl::PreTranslateMessage(MSG* pMsg) -{ - if (AppNeedsThemedControls()) { - if (!IsWindow(themedToolTip.m_hWnd)) { - themedToolTip.Create(this, TTS_ALWAYSTIP); - themedToolTip.enableFlickerHelper(); - } - if (IsWindow(themedToolTip.m_hWnd)) { - themedToolTip.RelayEvent(pMsg); - } - } - return __super::PreTranslateMessage(pMsg); -} - -void CMPCThemeTreeCtrl::updateToolTip(CPoint point) -{ - if (AppNeedsThemedControls() && nullptr != themedToolTip) { - TOOLINFO ti = { 0 }; - UINT_PTR tid = OnToolHitTest(point, &ti); - //OnToolHitTest returns -1 on failure but doesn't update uId to match - - if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool - if (themedToolTip.GetToolCount() > 0) { - themedToolTip.DelTool(this); - themedToolTip.Activate(FALSE); - } - themedToolTipCid = (UINT_PTR) - 1; - } - - if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { - - themedToolTipCid = ti.uId; - - CRect cr; - GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate - - themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); - themedToolTip.Activate(TRUE); - } - } -} - -void CMPCThemeTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - __super::OnMouseMove(nFlags, point); - updateToolTip(point); -} - -void CMPCThemeTreeCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); - NMTVCUSTOMDRAW* pstCD = reinterpret_cast(pNMHDR); - *pResult = CDRF_DODEFAULT; - - if (AppNeedsThemedControls()) { - - bool isFocus, isHot; - switch (pNMCD->dwDrawStage) { - case CDDS_PREPAINT: { - *pResult = CDRF_NOTIFYITEMDRAW; - CDC dc; - dc.Attach(pNMCD->hdc); - dc.FillSolidRect(&pNMCD->rc, CMPCTheme::ContentBGColor); - //doEraseBkgnd(&dc); - dc.Detach(); - break; - } - case CDDS_ITEMPREPAINT: - isFocus = 0 != (pNMCD->uItemState & CDIS_FOCUS); - isHot = 0 != (pNMCD->uItemState & CDIS_HOT); - - //regular theme is a bit ugly but better than Explorer theme. we clear the focus states to control the highlight ourselves - if (!CMPCThemeUtil::canUseWin10DarkTheme()) { - pNMCD->uItemState &= ~(CDIS_FOCUS | CDIS_HOT | CDIS_SELECTED); - } - - if (isFocus) { - pstCD->clrTextBk = CMPCTheme::TreeCtrlFocusColor; - } else if (isHot) { - pstCD->clrTextBk = CMPCTheme::TreeCtrlHoverColor; - } else { - pstCD->clrTextBk = CMPCTheme::ContentBGColor; - } - if (0 == (pNMCD->uItemState & CDIS_DISABLED) && IsWindowEnabled()) { - pstCD->clrText = CMPCTheme::TextFGColor; - } else { - pstCD->clrText = CMPCTheme::ButtonDisabledFGColor; - } - *pResult = CDRF_DODEFAULT; - break; - default: - pResult = CDRF_DODEFAULT; - break; - } - } else { - __super::OnPaint(); - } -} - -void CMPCThemeTreeCtrl::doEraseBkgnd(CDC* pDC) -{ - CRect r; - GetWindowRect(r); - r.OffsetRect(-r.left, -r.top); - pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); -} - -BOOL CMPCThemeTreeCtrl::OnEraseBkgnd(CDC* pDC) -{ - if (AppNeedsThemedControls()) { - //doEraseBkgnd(pDC); //we do this in the custom draw prepaint step now, to allow double buffering to work - return TRUE; - } else { - return __super::OnEraseBkgnd(pDC); - } -} - - -void CMPCThemeTreeCtrl::OnNcPaint() -{ - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->themedNcPaintWithSB(); - } else { - CMPCThemeScrollBarHelper::themedNcPaint(this, this); - } - } else { - __super::OnNcPaint(); - } -} - -//no end scroll notification for treectrl, so handle mousewheel, v and h scrolls :-/ -BOOL CMPCThemeTreeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) -{ - BOOL ret = __super::OnMouseWheel(nFlags, zDelta, pt); - if (AppNeedsThemedControls()) { - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } - ScreenToClient(&pt); - updateToolTip(pt); - } - return ret; -} - -void CMPCThemeTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - __super::OnVScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - -void CMPCThemeTreeCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - __super::OnHScroll(nSBCode, nPos, pScrollBar); - if (nullptr != themedSBHelper) { - themedSBHelper->updateScrollInfo(); - } -} - -LRESULT CMPCThemeTreeCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (AppNeedsThemedControls() && nullptr != themedSBHelper) { - if (themedSBHelper->WindowProc(this, message, wParam, lParam)) { - return 1; - } - } - return __super::WindowProc(message, wParam, lParam); -} +#include "stdafx.h" +#include "CMPCThemeTreeCtrl.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "mplayerc.h" +#undef SubclassWindow + + +CMPCThemeTreeCtrl::CMPCThemeTreeCtrl(): + themedSBHelper(nullptr), + themedToolTipCid((UINT_PTR) - 1) +{ + if (AppNeedsThemedControls()) { + m_brBkgnd.CreateSolidBrush(CMPCTheme::InlineEditBorderColor); + if (!CMPCThemeUtil::canUseWin10DarkTheme()) { + themedSBHelper = DEBUG_NEW CMPCThemeScrollBarHelper(this); + } + } + +} + +CMPCThemeTreeCtrl::~CMPCThemeTreeCtrl() +{ + if (nullptr != themedSBHelper) { + delete themedSBHelper; + } + m_brBkgnd.DeleteObject(); +} + +BOOL CMPCThemeTreeCtrl::PreCreateWindow(CREATESTRUCT& cs) +{ + if (AppNeedsThemedControls()) { + cs.dwExStyle |= WS_EX_CLIENTEDGE; + } + return __super::PreCreateWindow(cs); +} + +void CMPCThemeTreeCtrl::fulfillThemeReqs() +{ + if (AppNeedsThemedControls()) { + if (CMPCThemeUtil::canUseWin10DarkTheme()) { + SetWindowTheme(GetSafeHwnd(), L"DarkMode_Explorer", NULL); + } else { + SetWindowTheme(GetSafeHwnd(), L"", NULL); + } + SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); //necessary to prevent significant flicker + + SetLineColor(CMPCTheme::TreeCtrlLineColor); + if (nullptr == tvsTooltip.m_hWnd) { + CToolTipCtrl* t = GetToolTips(); + if (nullptr != t) { + tvsTooltip.SubclassWindow(t->m_hWnd); + } + } + } else { + //adipose--enabling this cuts down on a very minor flicker in classic mode; + //the duplicate line above is necessary due to a non-default bg. + //treat as a separate line of code to be clear that this one is "optional" while the other is not + SetExtendedStyle(TVS_EX_DOUBLEBUFFER, TVS_EX_DOUBLEBUFFER); //optional + } +} + +BEGIN_MESSAGE_MAP(CMPCThemeTreeCtrl, CTreeCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CMPCThemeTreeCtrl::OnNMCustomdraw) + ON_WM_ERASEBKGND() + ON_WM_DRAWITEM() + ON_WM_NCPAINT() + ON_WM_MOUSEMOVE() + ON_WM_MOUSEWHEEL() + ON_WM_VSCROLL() + ON_WM_HSCROLL() +END_MESSAGE_MAP() +IMPLEMENT_DYNAMIC(CMPCThemeTreeCtrl, CTreeCtrl) + +BOOL CMPCThemeTreeCtrl::PreTranslateMessage(MSG* pMsg) +{ + if (AppNeedsThemedControls()) { + if (!IsWindow(themedToolTip.m_hWnd)) { + themedToolTip.Create(this, TTS_ALWAYSTIP); + themedToolTip.enableFlickerHelper(); + } + if (IsWindow(themedToolTip.m_hWnd)) { + themedToolTip.RelayEvent(pMsg); + } + } + return __super::PreTranslateMessage(pMsg); +} + +void CMPCThemeTreeCtrl::updateToolTip(CPoint point) +{ + if (AppNeedsThemedControls() && nullptr != themedToolTip) { + TOOLINFO ti = { 0 }; + UINT_PTR tid = OnToolHitTest(point, &ti); + //OnToolHitTest returns -1 on failure but doesn't update uId to match + + if (tid == -1 || themedToolTipCid != ti.uId) { //if no tooltip, or id has changed, remove old tool + if (themedToolTip.GetToolCount() > 0) { + themedToolTip.DelTool(this); + themedToolTip.Activate(FALSE); + } + themedToolTipCid = (UINT_PTR) - 1; + } + + if (tid != -1 && themedToolTipCid != ti.uId && 0 != ti.uId) { + + themedToolTipCid = ti.uId; + + CRect cr; + GetClientRect(&cr); //we reset the tooltip every time we move anyway, so this rect is adequate + + themedToolTip.AddTool(this, LPSTR_TEXTCALLBACK, &cr, ti.uId); + themedToolTip.Activate(TRUE); + } + } +} + +void CMPCThemeTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + __super::OnMouseMove(nFlags, point); + updateToolTip(point); +} + +void CMPCThemeTreeCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); + NMTVCUSTOMDRAW* pstCD = reinterpret_cast(pNMHDR); + *pResult = CDRF_DODEFAULT; + + if (AppNeedsThemedControls()) { + + bool isFocus, isHot; + switch (pNMCD->dwDrawStage) { + case CDDS_PREPAINT: { + *pResult = CDRF_NOTIFYITEMDRAW; + CDC dc; + dc.Attach(pNMCD->hdc); + dc.FillSolidRect(&pNMCD->rc, CMPCTheme::ContentBGColor); + //doEraseBkgnd(&dc); + dc.Detach(); + break; + } + case CDDS_ITEMPREPAINT: + isFocus = 0 != (pNMCD->uItemState & CDIS_FOCUS); + isHot = 0 != (pNMCD->uItemState & CDIS_HOT); + + //regular theme is a bit ugly but better than Explorer theme. we clear the focus states to control the highlight ourselves + if (!CMPCThemeUtil::canUseWin10DarkTheme()) { + pNMCD->uItemState &= ~(CDIS_FOCUS | CDIS_HOT | CDIS_SELECTED); + } + + if (isFocus) { + pstCD->clrTextBk = CMPCTheme::TreeCtrlFocusColor; + } else if (isHot) { + pstCD->clrTextBk = CMPCTheme::TreeCtrlHoverColor; + } else { + pstCD->clrTextBk = CMPCTheme::ContentBGColor; + } + if (0 == (pNMCD->uItemState & CDIS_DISABLED) && IsWindowEnabled()) { + pstCD->clrText = CMPCTheme::TextFGColor; + } else { + pstCD->clrText = CMPCTheme::ButtonDisabledFGColor; + } + *pResult = CDRF_DODEFAULT; + break; + default: + pResult = CDRF_DODEFAULT; + break; + } + } else { + __super::OnPaint(); + } +} + +void CMPCThemeTreeCtrl::doEraseBkgnd(CDC* pDC) +{ + CRect r; + GetWindowRect(r); + r.OffsetRect(-r.left, -r.top); + pDC->FillSolidRect(r, CMPCTheme::ContentBGColor); +} + +BOOL CMPCThemeTreeCtrl::OnEraseBkgnd(CDC* pDC) +{ + if (AppNeedsThemedControls()) { + //doEraseBkgnd(pDC); //we do this in the custom draw prepaint step now, to allow double buffering to work + return TRUE; + } else { + return __super::OnEraseBkgnd(pDC); + } +} + + +void CMPCThemeTreeCtrl::OnNcPaint() +{ + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->themedNcPaintWithSB(); + } else { + CMPCThemeScrollBarHelper::themedNcPaint(this, this); + } + } else { + __super::OnNcPaint(); + } +} + +//no end scroll notification for treectrl, so handle mousewheel, v and h scrolls :-/ +BOOL CMPCThemeTreeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + BOOL ret = __super::OnMouseWheel(nFlags, zDelta, pt); + if (AppNeedsThemedControls()) { + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } + ScreenToClient(&pt); + updateToolTip(pt); + } + return ret; +} + +void CMPCThemeTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + __super::OnVScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + +void CMPCThemeTreeCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + __super::OnHScroll(nSBCode, nPos, pScrollBar); + if (nullptr != themedSBHelper) { + themedSBHelper->updateScrollInfo(); + } +} + +LRESULT CMPCThemeTreeCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (AppNeedsThemedControls() && nullptr != themedSBHelper) { + if (themedSBHelper->WindowProc(this, message, wParam, lParam)) { + return 1; + } + } + return __super::WindowProc(message, wParam, lParam); +} diff --git a/src/mpc-hc/CMPCThemeTreeCtrl.h b/src/mpc-hc/CMPCThemeTreeCtrl.h index 48527e1ef2f..5ce6368db6a 100755 --- a/src/mpc-hc/CMPCThemeTreeCtrl.h +++ b/src/mpc-hc/CMPCThemeTreeCtrl.h @@ -1,36 +1,36 @@ -#pragma once -#include -#include "CMPCThemeScrollBarHelper.h" -#include "CMPCThemeToolTipCtrl.h" - -class CMPCThemeTreeCtrl : public CTreeCtrl - , public CMPCThemeScrollable -{ -public: - CMPCThemeTreeCtrl(); - virtual ~CMPCThemeTreeCtrl(); - BOOL PreCreateWindow(CREATESTRUCT& cs); - void fulfillThemeReqs(); - LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - void updateToolTip(CPoint point); - BOOL PreTranslateMessage(MSG* pMsg); - DECLARE_DYNAMIC(CMPCThemeTreeCtrl) - DECLARE_MESSAGE_MAP() - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnNcPaint(); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); -protected: - CBrush m_brBkgnd; - CFont font; - CMPCThemeScrollBarHelper* themedSBHelper; - CMPCThemeToolTipCtrl themedToolTip, tvsTooltip; - UINT_PTR themedToolTipCid; - void doEraseBkgnd(CDC* pDC); -public: - void doDefault() { Default(); } - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); -}; - +#pragma once +#include +#include "CMPCThemeScrollBarHelper.h" +#include "CMPCThemeToolTipCtrl.h" + +class CMPCThemeTreeCtrl : public CTreeCtrl + , public CMPCThemeScrollable +{ +public: + CMPCThemeTreeCtrl(); + virtual ~CMPCThemeTreeCtrl(); + BOOL PreCreateWindow(CREATESTRUCT& cs); + void fulfillThemeReqs(); + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + void updateToolTip(CPoint point); + BOOL PreTranslateMessage(MSG* pMsg); + DECLARE_DYNAMIC(CMPCThemeTreeCtrl) + DECLARE_MESSAGE_MAP() + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnNcPaint(); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); +protected: + CBrush m_brBkgnd; + CFont font; + CMPCThemeScrollBarHelper* themedSBHelper; + CMPCThemeToolTipCtrl themedToolTip, tvsTooltip; + UINT_PTR themedToolTipCid; + void doEraseBkgnd(CDC* pDC); +public: + void doDefault() { Default(); } + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); +}; + diff --git a/src/mpc-hc/CMPCThemeUtil.cpp b/src/mpc-hc/CMPCThemeUtil.cpp index 530d79f1b1f..53259dabff7 100755 --- a/src/mpc-hc/CMPCThemeUtil.cpp +++ b/src/mpc-hc/CMPCThemeUtil.cpp @@ -1,1301 +1,1301 @@ -#include "stdafx.h" -#include "CMPCThemeUtil.h" -#include "CMPCTheme.h" -#include "mplayerc.h" -#include "MainFrm.h" -#include "CMPCThemeStatic.h" -#include "CMPCThemeDialog.h" -#include "CMPCThemeSliderCtrl.h" -#include "CMPCThemeTabCtrl.h" -#include "VersionHelpersInternal.h" -#include "CMPCThemeTitleBarControlButton.h" -#include "CMPCThemeInternalPropertyPageWnd.h" -#include "CMPCThemeWin10Api.h" -#include "Translations.h" -#include "ImageGrayer.h" -#include "CMPCThemePropPageButton.h" -#undef SubclassWindow - -CBrush CMPCThemeUtil::contentBrush; -CBrush CMPCThemeUtil::windowBrush; -CBrush CMPCThemeUtil::controlAreaBrush; -CBrush CMPCThemeUtil::W10DarkThemeFileDialogInjectedBGBrush; -NONCLIENTMETRICS CMPCThemeUtil::nonClientMetrics = { 0 }; -bool CMPCThemeUtil::metricsNeedCalculation = true; - -CMPCThemeUtil::CMPCThemeUtil(): - themedDialogToolTipParent(nullptr) -{ -} - -CMPCThemeUtil::~CMPCThemeUtil() -{ - for (u_int i = 0; i < allocatedWindows.size(); i++) { - delete allocatedWindows[i]; - } -} - -void CMPCThemeUtil::subClassTBCustomizeDialog(CWnd* wnd, CToolBar* customizeToolBar) -{ - CWnd* c = CWnd::FromHandle(themableDialogHandle); - CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(); - pObject->SetSpecialCase(ToolbarCustomizeDialog); - makeThemed(pObject, c); - fulfillThemeReqs(c, ToolbarCustomizeDialog, customizeToolBar); - - ::RedrawWindow(themableDialogHandle, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_ERASE); - - if (AfxGetAppSettings().bWindows10DarkThemeActive) { - enableWindows10DarkFrame(pObject); - //force titlebar redraw - c->SendMessage(WM_NCACTIVATE, FALSE); - c->SendMessage(WM_NCACTIVATE, TRUE); - } -} - -void CMPCThemeUtil::fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase /* = 0 */, CWnd* otherWindow /* = nullptr */) -{ - if (AppIsThemeLoaded()) { - - initHelperObjects(); - - CWnd* pChild = wnd->GetWindow(GW_CHILD); - while (pChild) { - LRESULT lRes = pChild->SendMessage(WM_GETDLGCODE, 0, 0); - CWnd* tChild = pChild; - pChild = pChild->GetNextWindow(); //increment before any unsubclassing - CString runtimeClass = tChild->GetRuntimeClass()->m_lpszClassName; - TCHAR windowClass[MAX_PATH]; - ::GetClassName(tChild->GetSafeHwnd(), windowClass, _countof(windowClass)); - DWORD style = tChild->GetStyle(); - DWORD buttonType = (style & BS_TYPEMASK); - DWORD staticStyle = (style & SS_TYPEMASK); - CString windowTitle; - - if (tChild->m_hWnd) { - tChild->GetWindowText(windowTitle); - } - bool canSubclass = (CWnd::FromHandlePermanent(tChild->GetSafeHwnd()) == NULL); //refuse to subclass if already subclassed. in this case the member class should be updated rather than dynamically subclassing - - if (canSubclass) { - if (DLGC_BUTTON == (lRes & DLGC_BUTTON)) { - if (DLGC_DEFPUSHBUTTON == (lRes & DLGC_DEFPUSHBUTTON) || DLGC_UNDEFPUSHBUTTON == (lRes & DLGC_UNDEFPUSHBUTTON)) { - CMPCThemeButton* pObject; - if (specialCase == ExternalPropertyPageWithDefaultButton && windowTitle == "Default" && AppNeedsThemedControls()) { - pObject = DEBUG_NEW CMPCThemePropPageButton(); - } else { - pObject = DEBUG_NEW CMPCThemeButton(); - } - makeThemed(pObject, tChild); - } else if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX)) { - CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); - makeThemed(pObject, tChild); - } else if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_3STATE || buttonType == BS_AUTO3STATE)) { - CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); - makeThemed(pObject, tChild); - } else if (DLGC_RADIOBUTTON == (lRes & DLGC_RADIOBUTTON) && (buttonType == BS_RADIOBUTTON || buttonType == BS_AUTORADIOBUTTON)) { - CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); - makeThemed(pObject, tChild); - } else { //what other buttons? - // int a = 1; - } - } else if (0 == _tcsicmp(windowClass, WC_SCROLLBAR)) { - } else if (0 == _tcsicmp(windowClass, WC_BUTTON) && buttonType == BS_GROUPBOX) { - CMPCThemeGroupBox* pObject = DEBUG_NEW CMPCThemeGroupBox(); - makeThemed(pObject, tChild); - SetWindowTheme(tChild->GetSafeHwnd(), L"", L""); - } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_ICON == staticStyle) { //don't touch icons for now - } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_BITMAP == staticStyle) { //don't touch BITMAPS for now - } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_OWNERDRAW == staticStyle) { //don't touch OWNERDRAW for now - } else if (0 == _tcsicmp(windowClass, WC_STATIC) && (staticStyle < SS_OWNERDRAW || SS_ETCHEDHORZ == staticStyle || SS_ETCHEDVERT == staticStyle || SS_ETCHEDFRAME == staticStyle)) { - LITEM li = { 0 }; - li.mask = LIF_ITEMINDEX | LIF_ITEMID; - if (::SendMessage(tChild->GetSafeHwnd(), LM_GETITEM, 0, (LPARAM)& li)) { //we appear to have a linkctrl - CMPCThemeLinkCtrl* pObject = DEBUG_NEW CMPCThemeLinkCtrl(); - makeThemed(pObject, tChild); - } else { - CMPCThemeStatic* pObject = DEBUG_NEW CMPCThemeStatic(); - if (0 == (style & SS_LEFTNOWORDWRAP) && 0 == windowTitle.Left(20).Compare(_T("Select which output "))) { - //this is a hack for LAVFilters to avoid wrapping the statics - //FIXME by upstreaming a change to dialog layout of lavfilters, or by developing a dynamic re-layout engine - CRect wr; - tChild->GetWindowRect(wr); - wnd->ScreenToClient(wr); - wr.right += 5; - tChild->MoveWindow(wr); - } - makeThemed(pObject, tChild); - if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase && 0x416 == GetDlgCtrlID(tChild->m_hWnd)) { - CStringW str; - pObject->GetWindowTextW(str); - str.Replace(L" \r\n ", L"\r\n"); //this prevents double-wrapping due to the space wrapping before the carriage return - pObject->SetWindowTextW(str); - pObject->ModifyStyle(0, TBS_DOWNISLEFT); - } - } - } else if (0 == _tcsicmp(windowClass, WC_EDIT)) { - CMPCThemeEdit* pObject = DEBUG_NEW CMPCThemeEdit(); - makeThemed(pObject, tChild); - } else if (0 == _tcsicmp(windowClass, UPDOWN_CLASS)) { - CMPCThemeSpinButtonCtrl* pObject = DEBUG_NEW CMPCThemeSpinButtonCtrl(); - makeThemed(pObject, tChild); - } else if (0 == _tcsicmp(windowClass, _T("#32770"))) { //dialog class - CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(windowTitle == ""); - pObject->SetSpecialCase(specialCase); - makeThemed(pObject, tChild); - } else if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { - CMPCThemeComboBox* pObject = DEBUG_NEW CMPCThemeComboBox(); - makeThemed(pObject, tChild); - } else if (0 == _tcsicmp(windowClass, WC_LISTBOX)) { - CMPCThemeListBox* pObject = DEBUG_NEW CMPCThemeListBox(); - makeThemed(pObject, tChild); - if (specialCase == ToolbarCustomizeDialog) { - pObject->SetCustomizeToolbar ((CToolBar*)otherWindow); - } - } else if (0 == _tcsicmp(windowClass, TRACKBAR_CLASS)) { - CMPCThemeSliderCtrl* pObject = DEBUG_NEW CMPCThemeSliderCtrl(); - makeThemed(pObject, tChild); - if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase) { - pObject->ModifyStyle(0, TBS_DOWNISLEFT); - } - } else if (0 == _tcsicmp(windowClass, WC_TABCONTROL)) { - CMPCThemeTabCtrl* pObject = DEBUG_NEW CMPCThemeTabCtrl(); - makeThemed(pObject, tChild); - } else if (windowTitle == _T("CInternalPropertyPageWnd")) { //only seems to be needed for windows from external filters? - CMPCThemeInternalPropertyPageWnd* pObject = DEBUG_NEW CMPCThemeInternalPropertyPageWnd(); - makeThemed(pObject, tChild); - } - } - if (0 == _tcsicmp(windowClass, _T("#32770"))) { //dialog class - fulfillThemeReqs(tChild, specialCase); - } else if (windowTitle == _T("CInternalPropertyPageWnd")) { //internal window encompassing property pages - fulfillThemeReqs(tChild); - } - } - } -} - -void CMPCThemeUtil::initHelperObjects() -{ - if (contentBrush.m_hObject == nullptr) { - contentBrush.CreateSolidBrush(CMPCTheme::ContentBGColor); - } - if (windowBrush.m_hObject == nullptr) { - windowBrush.CreateSolidBrush(CMPCTheme::WindowBGColor); - } - if (controlAreaBrush.m_hObject == nullptr) { - controlAreaBrush.CreateSolidBrush(CMPCTheme::ControlAreaBGColor); - } - if (W10DarkThemeFileDialogInjectedBGBrush.m_hObject == nullptr) { - W10DarkThemeFileDialogInjectedBGBrush.CreateSolidBrush(CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); - } -} - -void CMPCThemeUtil::makeThemed(CWnd* pObject, CWnd* tChild) -{ - allocatedWindows.push_back(pObject); - pObject->SubclassWindow(tChild->GetSafeHwnd()); -} - -void CMPCThemeUtil::EnableThemedDialogTooltips(CDialog* wnd) -{ - if (AppIsThemeLoaded()) { - if (themedDialogToolTip.m_hWnd) { - themedDialogToolTip.DestroyWindow(); - } - themedDialogToolTipParent = wnd; - themedDialogToolTip.Create(wnd, TTS_NOPREFIX | TTS_ALWAYSTIP); - themedDialogToolTip.Activate(TRUE); - themedDialogToolTip.SetDelayTime(TTDT_AUTOPOP, 10000); - //enable tooltips for all child windows - CWnd* pChild = wnd->GetWindow(GW_CHILD); - while (pChild) { - themedDialogToolTip.AddTool(pChild, LPSTR_TEXTCALLBACK); - pChild = pChild->GetNextWindow(); - } - } else { - wnd->EnableToolTips(TRUE); - } -} - -void CMPCThemeUtil::RedrawDialogTooltipIfVisible() { - if (AppIsThemeLoaded() && themedDialogToolTip.m_hWnd) { - themedDialogToolTip.RedrawIfVisible(); - } else { - AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState(); - CToolTipCtrl* pToolTip = pModuleThreadState->m_pToolTip; - if (pToolTip && ::IsWindow(pToolTip->m_hWnd) && pToolTip->IsWindowVisible()) { - pToolTip->Update(); - } - } -} - -void CMPCThemeUtil::PlaceThemedDialogTooltip(UINT_PTR nID) -{ - if (AppIsThemeLoaded() && IsWindow(themedDialogToolTip)) { - if (::IsWindow(themedDialogToolTipParent->GetSafeHwnd())) { - CWnd* controlWnd = themedDialogToolTipParent->GetDlgItem(nID); - themedDialogToolTip.SetHoverPosition(controlWnd); - } - } -} - -void CMPCThemeUtil::RelayThemedDialogTooltip(MSG* pMsg) -{ - if (AppIsThemeLoaded() && IsWindow(themedDialogToolTip)) { - themedDialogToolTip.RelayEvent(pMsg); - } -} - -LRESULT CALLBACK wndProcFileDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - WNDPROC wndProcSink = NULL; - wndProcSink = (WNDPROC)GetProp(hWnd, _T("WNDPROC_SINK")); - if (!wndProcSink) { - return 0; - } - if (WM_CTLCOLOREDIT == uMsg) { - return (LRESULT)CMPCThemeUtil::getCtlColorFileDialog((HDC)wParam, CTLCOLOR_EDIT); - } - return ::CallWindowProc(wndProcSink, hWnd, uMsg, wParam, lParam); -} - -void CMPCThemeUtil::subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass) { - if (0 == wcsicmp(childWindowClass, WC_STATIC)) { - CWnd* c = CWnd::FromHandle(widget); - c->UnsubclassWindow(); - CMPCThemeStatic* pObject = DEBUG_NEW CMPCThemeStatic(); - pObject->setFileDialogChild(true); - allocatedWindows.push_back(pObject); - pObject->SubclassWindow(widget); - } else if (0 == wcsicmp(childWindowClass, WC_BUTTON)) { - CWnd* c = CWnd::FromHandle(widget); - DWORD style = c->GetStyle(); - DWORD buttonType = (style & BS_TYPEMASK); - if (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX) { - c->UnsubclassWindow(); - CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); - pObject->setFileDialogChild(true); - allocatedWindows.push_back(pObject); - pObject->SubclassWindow(widget); - } - } else if (0 == wcsicmp(childWindowClass, WC_EDIT)) { - CWnd* c = CWnd::FromHandle(widget); - c->UnsubclassWindow(); - CMPCThemeEdit* pObject = DEBUG_NEW CMPCThemeEdit(); - pObject->setFileDialogChild(true); - allocatedWindows.push_back(pObject); - pObject->SubclassWindow(widget); - if (nullptr == GetProp(parent, _T("WNDPROC_SINK"))) { - LONG_PTR wndProcOld = ::SetWindowLongPtr(parent, GWLP_WNDPROC, (LONG_PTR)wndProcFileDialog); - SetProp(parent, _T("WNDPROC_SINK"), (HANDLE)wndProcOld); - } - } -} - -void CMPCThemeUtil::subClassFileDialog(CWnd* wnd) { - if (AfxGetAppSettings().bWindows10DarkThemeActive) { - initHelperObjects(); - - HWND duiview = ::FindWindowExW(themableDialogHandle, NULL, L"DUIViewWndClassName", NULL); - HWND duihwnd = ::FindWindowExW(duiview, NULL, L"DirectUIHWND", NULL); - - if (duihwnd) { //we found the FileDialog - if (dialogProminentControlStringID) { //if this is set, we assume there is a single prominent control (note, it's in the filedialog main window) - subClassFileDialogRecurse(wnd, themableDialogHandle, ProminentControlIDWidget); - } else { - subClassFileDialogRecurse(wnd, duihwnd, RecurseSinkWidgets); - } - themableDialogHandle = nullptr; - ::RedrawWindow(duiview, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); - } - } -} - -void CMPCThemeUtil::subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType) { - HWND pChild = ::GetWindow(hWnd, GW_CHILD); - while (pChild) { - WCHAR childWindowClass[MAX_PATH]; - ::GetClassName(pChild, childWindowClass, _countof(childWindowClass)); - if (searchType == RecurseSinkWidgets) { - if (0 == wcsicmp(childWindowClass, L"FloatNotifySink")) { //children are the injected controls - subClassFileDialogRecurse(wnd, pChild, ThemeAllChildren); //recurse and theme all children of sink - } - } else if (searchType == ThemeAllChildren) { - subClassFileDialogWidgets(pChild, hWnd, childWindowClass); - } else if (searchType == ProminentControlIDWidget){ - WCHAR str[MAX_PATH]; - ::GetWindowText(pChild, str, _countof(str)); - if (0 == wcsicmp(str, ResStr(dialogProminentControlStringID))) { - subClassFileDialogWidgets(pChild, hWnd, childWindowClass); - return; - } - } - pChild = ::GetNextWindow(pChild, GW_HWNDNEXT); - } -} - -void CMPCThemeUtil::redrawAllThemedWidgets() { - for (auto w : allocatedWindows) { - w->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); - } -} - -AFX_STATIC DLGITEMTEMPLATE* AFXAPI _AfxFindNextDlgItem(DLGITEMTEMPLATE* pItem, BOOL bDialogEx); -AFX_STATIC DLGITEMTEMPLATE* AFXAPI _AfxFindFirstDlgItem(const DLGTEMPLATE* pTemplate); - -AFX_STATIC inline BOOL IsDialogEx(const DLGTEMPLATE* pTemplate) -{ - return ((_DialogSplitHelper::DLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF; -} - -static inline WORD& DlgTemplateItemCount(DLGTEMPLATE* pTemplate) -{ - if (IsDialogEx(pTemplate)) { - return reinterpret_cast<_DialogSplitHelper::DLGTEMPLATEEX*>(pTemplate)->cDlgItems; - } else { - return pTemplate->cdit; - } -} - -static inline const WORD& DlgTemplateItemCount(const DLGTEMPLATE* pTemplate) -{ - if (IsDialogEx(pTemplate)) { - return reinterpret_cast(pTemplate)->cDlgItems; - } else { - return pTemplate->cdit; - } -} - -bool CMPCThemeUtil::ModifyTemplates(CPropertySheet* sheet, CRuntimeClass* pageClass, DWORD id, DWORD addStyle, DWORD removeStyle) -{ - if (AppIsThemeLoaded()) { - PROPSHEETHEADER m_psh = sheet->m_psh; - for (int i = 0; i < sheet->GetPageCount(); i++) { - CPropertyPage* pPage = sheet->GetPage(i); - if (nullptr == AfxDynamicDownCast(pageClass, pPage)) { - continue; - } - PROPSHEETPAGE* tpsp = &pPage->m_psp; - - const DLGTEMPLATE* pTemplate; - if (tpsp->dwFlags & PSP_DLGINDIRECT) { - pTemplate = tpsp->pResource; - } else { - HRSRC hResource = ::FindResource(tpsp->hInstance, tpsp->pszTemplate, RT_DIALOG); - if (hResource == NULL) { - return false; - } - HGLOBAL hTemplate = LoadResource(tpsp->hInstance, hResource); - if (hTemplate == NULL) { - return false; - } - pTemplate = (LPCDLGTEMPLATE)LockResource(hTemplate); - if (pTemplate == NULL) { - return false; - } - } - - if (afxOccManager != NULL) { - DLGITEMTEMPLATE* pItem = _AfxFindFirstDlgItem(pTemplate); - DLGITEMTEMPLATE* pNextItem; - BOOL bDialogEx = IsDialogEx(pTemplate); - - int iItem, iItems = DlgTemplateItemCount(pTemplate); - - for (iItem = 0; iItem < iItems; iItem++) { - pNextItem = _AfxFindNextDlgItem(pItem, bDialogEx); - DWORD dwOldProtect, tp; - if (bDialogEx) { - _DialogSplitHelper::DLGITEMTEMPLATEEX* pItemEx = (_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem; - if (pItemEx->id == id) { - if (VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), PAGE_READWRITE, &dwOldProtect)) { - pItemEx->style |= addStyle; - pItemEx->style &= ~removeStyle; - VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), dwOldProtect, &tp); - } - } - } else { - if (pItem->id == id) { - if (VirtualProtect(&pItem->style, sizeof(pItem->style), PAGE_READWRITE, &dwOldProtect)) { - pItem->style |= addStyle; - pItem->style &= ~removeStyle; - VirtualProtect(&pItem->style, sizeof(pItem->style), dwOldProtect, &tp); - } - } - } - pItem = pNextItem; - } - } - } - } - return true; -} - -void CMPCThemeUtil::enableFileDialogHook() -{ - CMainFrame* pMainFrame = AfxGetMainFrame(); - pMainFrame->enableFileDialogHook(this); -} - -HBRUSH CMPCThemeUtil::getCtlColorFileDialog(HDC hDC, UINT nCtlColor) -{ - initHelperObjects(); - if (CTLCOLOR_EDIT == nCtlColor) { - ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); - ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); - return W10DarkThemeFileDialogInjectedBGBrush; - } else if (CTLCOLOR_STATIC == nCtlColor) { - ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); - ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); - return W10DarkThemeFileDialogInjectedBGBrush; - } else if (CTLCOLOR_BTN == nCtlColor) { - ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); - ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); - return W10DarkThemeFileDialogInjectedBGBrush; - } else { - return NULL; - } -} - -HBRUSH CMPCThemeUtil::getCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - initHelperObjects(); - LRESULT lResult; - if (pWnd->SendChildNotifyLastMsg(&lResult)) { - return (HBRUSH)lResult; - } - if (CTLCOLOR_LISTBOX == nCtlColor) { - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::ContentBGColor); - return contentBrush; - } else { - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::WindowBGColor); - return windowBrush; - } - } - return nullptr; -} - -bool CMPCThemeUtil::MPCThemeEraseBkgnd(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppIsThemeLoaded()) { - CRect rect; - pWnd->GetClientRect(rect); - if (CTLCOLOR_DLG == nCtlColor) { //only supported "class" for now - pDC->FillSolidRect(rect, CMPCTheme::WindowBGColor); - } else { - return false; - } - return true; - } else { - return false; - } -} - -bool CMPCThemeUtil::getFontByFace(CFont& font, CWnd* wnd, wchar_t* fontName, int size, LONG weight) -{ - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - - if (!wnd) { - wnd = AfxGetMainWnd(); - } - - DpiHelper dpiWindow; - - dpiWindow.Override(wnd->GetSafeHwnd()); - lf.lfHeight = -MulDiv(size, dpiWindow.DPIY(), 72); - - lf.lfQuality = CLEARTYPE_QUALITY; - - //lf.lfQuality = ANTIALIASED_QUALITY; - lf.lfWeight = weight; - wcsncpy_s(lf.lfFaceName, fontName, LF_FACESIZE); - - return font.CreateFontIndirect(&lf); -} - -bool CMPCThemeUtil::getFixedFont(CFont& font, CDC* pDC, CWnd* wnd) -{ - if (!wnd) { - wnd = AfxGetMainWnd(); - } - - DpiHelper dpiWindow; - dpiWindow.Override(wnd->GetSafeHwnd()); - - LOGFONT tlf; - memset(&tlf, 0, sizeof(LOGFONT)); - tlf.lfHeight = -MulDiv(10, dpiWindow.DPIY(), 72); - tlf.lfQuality = CLEARTYPE_QUALITY; - tlf.lfWeight = FW_REGULAR; - wcsncpy_s(tlf.lfFaceName, _T("Consolas"), LF_FACESIZE); - return font.CreateFontIndirect(&tlf); -} - -bool CMPCThemeUtil::getFontByType(CFont& font, CWnd* wnd, int type, bool underline, bool bold) -{ - /* adipose: works poorly for dialogs as they cannot be scaled to fit zoomed fonts, only use for menus and status bars*/ - GetMetrics(); - - if (!wnd) { - wnd = AfxGetMainWnd(); - } - - //metrics will have the right fonts for the main window, but current window may be on another screen - DpiHelper dpiWindow, dpiMain; - dpiWindow.Override(wnd->GetSafeHwnd()); - dpiMain.Override(AfxGetMainWnd()->GetSafeHwnd()); - - LOGFONT* lf; - if (type == CaptionFont) { - lf = &nonClientMetrics.lfCaptionFont; - } else if (type == SmallCaptionFont) { - lf = &nonClientMetrics.lfSmCaptionFont; - } else if (type == MenuFont) { - lf = &nonClientMetrics.lfMenuFont; - } else if (type == StatusFont) { - lf = &nonClientMetrics.lfStatusFont; - } else if (type == MessageFont || type == DialogFont) { - lf = &nonClientMetrics.lfMessageFont; -#if 0 - } else if (type == DialogFont) { //hack for compatibility with MS SHell Dlg (8) used in dialogs - DpiHelper dpiWindow; - dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); - - LOGFONT tlf; - memset(&tlf, 0, sizeof(LOGFONT)); - tlf.lfHeight = -MulDiv(8, dpiWindow.DPIY(), 72); - tlf.lfQuality = CLEARTYPE_QUALITY; - tlf.lfWeight = FW_REGULAR; - wcsncpy_s(tlf.lfFaceName, m.lfMessageFont.lfFaceName, LF_FACESIZE); - //wcsncpy_s(tlf.lfFaceName, _T("MS Shell Dlg"), LF_FACESIZE); - lf = &tlf; -#endif - } else { - lf = &nonClientMetrics.lfMessageFont; - } - - int newHeight = MulDiv(lf->lfHeight, dpiWindow.DPIY(), dpiMain.DPIY()); - if (underline || bold || newHeight != lf->lfHeight) { - LOGFONT tlf; - memset(&tlf, 0, sizeof(LOGFONT)); - tlf.lfHeight = newHeight; - tlf.lfQuality = lf->lfQuality; - tlf.lfWeight = lf->lfWeight; - wcsncpy_s(tlf.lfFaceName, lf->lfFaceName, LF_FACESIZE); - tlf.lfUnderline = underline; - if (bold) { - tlf.lfWeight = FW_BOLD; - } - return font.CreateFontIndirect(&tlf); - } else { - return font.CreateFontIndirect(lf); - } -} - -CSize CMPCThemeUtil::GetTextSize(CString str, CDC* pDC, CFont* font) -{ - CFont* pOldFont = pDC->SelectObject(font); - - CRect r = { 0, 0, 0, 0 }; - pDC->DrawTextW(str, r, DT_SINGLELINE | DT_CALCRECT); - CSize cs = r.Size(); - pDC->SelectObject(pOldFont); - return cs; -} - -CSize CMPCThemeUtil::GetTextSize(CString str, HDC hDC, CFont* font) -{ - CDC* pDC = CDC::FromHandle(hDC); - return GetTextSize(str, pDC, font); -} - -CSize CMPCThemeUtil::GetTextSize(CString str, HDC hDC, CWnd *wnd, int type) -{ - CDC* pDC = CDC::FromHandle(hDC); - CFont font; - getFontByType(font, wnd, type); - - return GetTextSize(str, pDC, &font); -} - -CSize CMPCThemeUtil::GetTextSizeDiff(CString str, HDC hDC, CWnd* wnd, int type, CFont* curFont) -{ - CSize cs = GetTextSize(str, hDC, wnd, type); - CDC* cDC = CDC::FromHandle(hDC); - CFont* pOldFont = cDC->SelectObject(curFont); - CSize curCs = cDC->GetTextExtent(str); - cDC->SelectObject(pOldFont); - - return cs - curCs; -} - -void CMPCThemeUtil::GetMetrics(bool reset /* = false */) -{ - NONCLIENTMETRICS *m = &nonClientMetrics; - if (m->cbSize == 0 || metricsNeedCalculation || reset) { - m->cbSize = sizeof(NONCLIENTMETRICS); - ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), m, 0); - if (AfxGetMainWnd() == nullptr) {//this used to happen when CPreView::OnCreate was calling ScaleFont, should no longer occur - return; //we can do nothing more if main window not found yet, and metricsNeedCalculation will remain set - } - - DpiHelper dpi, dpiWindow; - dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); - - //getclientmetrics is ignorant of per window DPI - if (dpi.ScaleFactorY() != dpiWindow.ScaleFactorY()) { - m->lfCaptionFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfCaptionFont.lfHeight); - m->lfSmCaptionFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfSmCaptionFont.lfHeight); - m->lfMenuFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfMenuFont.lfHeight); - m->lfStatusFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfStatusFont.lfHeight); - m->lfMessageFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfMessageFont.lfHeight); - } - metricsNeedCalculation = false; - } -} - -void CMPCThemeUtil::initMemDC(CDC* pDC, CDC& dcMem, CBitmap& bmMem, CRect rect) -{ - dcMem.CreateCompatibleDC(pDC); - dcMem.SetBkColor(pDC->GetBkColor()); - dcMem.SetTextColor(pDC->GetTextColor()); - dcMem.SetBkMode(pDC->GetBkMode()); - dcMem.SelectObject(pDC->GetCurrentFont()); - - bmMem.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); - dcMem.SelectObject(&bmMem); - dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect.left, rect.top, SRCCOPY); -} - -void CMPCThemeUtil::flushMemDC(CDC* pDC, CDC& dcMem, CRect rect) -{ - pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); -} - - -void CMPCThemeUtil::DrawBufferedText(CDC* pDC, CString text, CRect rect, UINT format) -{ - CDC dcMem; - dcMem.CreateCompatibleDC(pDC); - dcMem.SetBkColor(pDC->GetBkColor()); - dcMem.SetTextColor(pDC->GetTextColor()); - dcMem.SetBkMode(pDC->GetBkMode()); - dcMem.SelectObject(pDC->GetCurrentFont()); - - CBitmap bmMem; - bmMem.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); - dcMem.SelectObject(&bmMem); - dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect.left, rect.top, SRCCOPY); - - CRect tr = rect; - tr.OffsetRect(-tr.left, -tr.top); - dcMem.DrawTextW(text, tr, format); - - pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); -} - -void CMPCThemeUtil::Draw2BitTransparent(CDC& dc, int left, int top, int width, int height, CBitmap& bmp, COLORREF fgColor) -{ - COLORREF crOldTextColor = dc.GetTextColor(); - COLORREF crOldBkColor = dc.GetBkColor(); - - CDC dcBMP; - dcBMP.CreateCompatibleDC(&dc); - - dcBMP.SelectObject(bmp); - dc.BitBlt(left, top, width, height, &dcBMP, 0, 0, SRCINVERT); //SRCINVERT works to create mask from 2-bit image. same result as bitblt with text=0 and bk=0xffffff - dc.SetBkColor(fgColor); //paint: foreground color (1 in 2 bit) - dc.SetTextColor(RGB(0, 0, 0)); //paint: black where transparent - dc.BitBlt(left, top, width, height, &dcBMP, 0, 0, SRCPAINT); - - dc.SetTextColor(crOldTextColor); - dc.SetBkColor(crOldBkColor); -} - -#if 0 -void CMPCThemeUtil::dbg(CString text, ...) -{ - va_list args; - va_start(args, text); - CString output; - output.FormatV(text, args); - OutputDebugString(output); - OutputDebugString(_T("\n")); - va_end(args); -} -#endif - -float CMPCThemeUtil::getConstantFByDPI(CWnd* window, const float* constants) -{ - int index; - DpiHelper dpiWindow; - dpiWindow.Override(window->GetSafeHwnd()); - int dpi = dpiWindow.DPIX(); - - if (dpi < 120) { - index = 0; - } else if (dpi < 144) { - index = 1; - } else if (dpi < 168) { - index = 2; - } else if (dpi < 192) { - index = 3; - } else { - index = 4; - } - - return constants[index]; -} - -int CMPCThemeUtil::getConstantByDPI(CWnd* window, const int* constants) -{ - int index; - DpiHelper dpiWindow; - dpiWindow.Override(window->GetSafeHwnd()); - int dpi = dpiWindow.DPIX(); - - if (dpi < 120) { - index = 0; - } else if (dpi < 144) { - index = 1; - } else if (dpi < 168) { - index = 2; - } else if (dpi < 192) { - index = 3; - } else { - index = 4; - } - - return constants[index]; -} - -UINT CMPCThemeUtil::getResourceByDPI(CWnd* window, CDC* pDC, const UINT* resources) -{ - int index; - //int dpi = pDC->GetDeviceCaps(LOGPIXELSX); - DpiHelper dpiWindow; - dpiWindow.Override(window->GetSafeHwnd()); - int dpi = dpiWindow.DPIX(); - - if (dpi < 120) { - index = 0; - } else if (dpi < 144) { - index = 1; - } else if (dpi < 168) { - index = 2; - } else if (dpi < 192) { - index = 3; - } else { - index = 4; - } - - return resources[index]; -} - -const std::vector CMPCThemeUtil::getIconPathByDPI(CWnd* wnd, WPARAM buttonType) { - DpiHelper dpiWindow; - dpiWindow.Override(wnd->GetSafeHwnd()); - - int dpi = dpiWindow.DPIX(); - switch (buttonType) { - case SC_MINIMIZE: - if (dpi < 120) { - return CMPCTheme::minimizeIcon96; - } else if (dpi < 144) { - return CMPCTheme::minimizeIcon120; - } else if (dpi < 168) { - return CMPCTheme::minimizeIcon144; - } else if (dpi < 192) { - return CMPCTheme::minimizeIcon168; - } else { - return CMPCTheme::minimizeIcon192; - } - case SC_RESTORE: - if (dpi < 120) { - return CMPCTheme::restoreIcon96; - } else if (dpi < 144) { - return CMPCTheme::restoreIcon120; - } else if (dpi < 168) { - return CMPCTheme::restoreIcon144; - } else if (dpi < 192) { - return CMPCTheme::restoreIcon168; - } else { - return CMPCTheme::restoreIcon192; - } - case SC_MAXIMIZE: - if (dpi < 120) { - return CMPCTheme::maximizeIcon96; - } else if (dpi < 144) { - return CMPCTheme::maximizeIcon120; - } else if (dpi < 168) { - return CMPCTheme::maximizeIcon144; - } else if (dpi < 192) { - return CMPCTheme::maximizeIcon168; - } else { - return CMPCTheme::maximizeIcon192; - } - case TOOLBAR_HIDE_ICON: - if (dpi < 120) { - return CMPCTheme::hideIcon96; - } else if (dpi < 144) { - return CMPCTheme::hideIcon120; - } else if (dpi < 168) { - return CMPCTheme::hideIcon144; - } else if (dpi < 192) { - return CMPCTheme::hideIcon168; - } else { - return CMPCTheme::hideIcon192; - } - case SC_CLOSE: - default: - if (dpi < 120) { - return CMPCTheme::closeIcon96; - } else if (dpi < 144) { - return CMPCTheme::closeIcon120; - } else if (dpi < 168) { - return CMPCTheme::closeIcon144; - } else if (dpi < 192) { - return CMPCTheme::closeIcon168; - } else { - return CMPCTheme::closeIcon192; - } - } -} - -//MapDialogRect deficiencies: -// 1. Caches results for windows even after they receive a DPI change -// 2. for templateless dialogs (e.g., MessageBoxDialog.cpp), the caching requires a reboot to fix -// 3. Does not honor selected font -// 4. For PropSheet, always uses "MS Shell Dlg" no matter what the sheet has selected in the .rc -void CMPCThemeUtil::MapDialogRect2(CDialog* wnd, CRect& r) { - CDC* pDC; - if (wnd && (pDC = wnd->GetDC())) { - CFont msgFont; - if (!getFontByType(msgFont, wnd, CMPCThemeUtil::MessageFont)) { - //if (!getFontByFace(msgFont, wnd, L"MS Shell Dlg", 9)){ - return; - } - - CFont* oldFont = pDC->SelectObject(&msgFont); - - //average character dimensions: https://web.archive.org/web/20131208002908/http://support.microsoft.com/kb/125681 - TEXTMETRICW tm; - SIZE size; - pDC->GetTextMetricsW(&tm); - GetTextExtentPoint32W(pDC->GetSafeHdc(), L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size); - pDC->SelectObject(oldFont); - int avgWidth = (size.cx / 26 + 1) / 2; - int avgHeight = (WORD)tm.tmHeight; - - //MapDialogRect definition: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapdialogrect - r.left = MulDiv(r.left, avgWidth, 4); - r.right = MulDiv(r.right, avgWidth, 4); - r.top = MulDiv(r.top, avgHeight, 8); - r.bottom = MulDiv(r.bottom, avgHeight, 8); - } -} - -const std::vector CMPCThemeUtil::getIconPathByDPI(CMPCThemeTitleBarControlButton* button) -{ - return getIconPathByDPI(button, button->getButtonType()); -} - -void CMPCThemeUtil::drawToolbarHideButton(CDC* pDC, CWnd* window, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias, bool hover) { - int iconWidth = CMPCThemeUtil::getConstantByDPI(window, CMPCTheme::ToolbarIconPathDimension); - int iconHeight = iconWidth; - float penThickness = 1; - CPoint ul(iconRect.left + (iconRect.Width() - iconWidth) / 2, iconRect.top + (iconRect.Height() - iconHeight) / 2); - CRect pathRect = { - ul.x, - ul.y, - ul.x + iconWidth, - ul.y + iconHeight - }; - - Gdiplus::Graphics gfx(pDC->m_hDC); - if (antiAlias) { - gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x8); - } - Gdiplus::Color lineClr; - - if (hover) { //draw like a win10 icon - lineClr.SetFromCOLORREF(CMPCTheme::W10DarkThemeTitlebarIconPenColor); - } else { //draw in fg color as there is no button bg - lineClr.SetFromCOLORREF(CMPCTheme::TextFGColor); - } - Gdiplus::Pen iPen(lineClr, penThickness); - if (penThickness >= 2) { - iPen.SetLineCap(Gdiplus::LineCapSquare, Gdiplus::LineCapSquare, Gdiplus::DashCapFlat); - } - Gdiplus::REAL lastX = 0, lastY = 0; - for (u_int i = 0; i < icon.size(); i++) { - CMPCTheme::pathPoint p = icon[i]; - Gdiplus::REAL x = (Gdiplus::REAL)(pathRect.left + p.x); - Gdiplus::REAL y = (Gdiplus::REAL)(pathRect.top + p.y); - if (p.state == CMPCTheme::newPath) { - lastX = x; - lastY = y; - } else if ((p.state == CMPCTheme::linePath || p.state == CMPCTheme::closePath) && i > 0) { - gfx.DrawLine(&iPen, lastX, lastY, x, y); - if (antiAlias && penThickness < 2) { - gfx.DrawLine(&iPen, lastX, lastY, x, y); //draw again to brighten the AA diagonals - } - lastX = x; - lastY = y; - } - } -} - -void CMPCThemeUtil::drawGripper(CWnd* window, CWnd* dpiRefWnd, CRect rectGripper, CDC* pDC, bool rot90) { - CPngImage image; - image.Load(getResourceByDPI(dpiRefWnd, pDC, CMPCTheme::ThemeGrippers), AfxGetInstanceHandle()); - CImage gripperTemplate, gripperColorized; - gripperTemplate.Attach((HBITMAP)image.Detach()); - ImageGrayer::Colorize(gripperTemplate, gripperColorized, CMPCTheme::GripperPatternColor, CMPCTheme::WindowBGColor, rot90); - - CDC mDC; - mDC.CreateCompatibleDC(pDC); - mDC.SelectObject(gripperColorized); - - CDC dcMem; - CBitmap bmMem; - initMemDC(pDC, dcMem, bmMem, rectGripper); - if (rot90) { - for (int a = 0; a < rectGripper.Height(); a += gripperColorized.GetHeight()) { - dcMem.BitBlt(0, a, gripperColorized.GetWidth(), gripperColorized.GetHeight(), &mDC, 0, 0, SRCCOPY); - } - } else { - for (int a = 0; a < rectGripper.Width(); a += gripperColorized.GetWidth()) { - dcMem.BitBlt(a, 0, gripperColorized.GetWidth(), gripperColorized.GetHeight(), &mDC, 0, 0, SRCCOPY); - } - } - flushMemDC(pDC, dcMem, rectGripper); -} - - -void CMPCThemeUtil::drawCheckBox(CWnd* window, UINT checkState, bool isHover, bool useSystemSize, CRect rectCheck, CDC* pDC, bool isRadio) -{ - COLORREF borderClr, bgClr; - COLORREF oldBkClr = pDC->GetBkColor(), oldTextClr = pDC->GetTextColor(); - if (isHover) { - borderClr = CMPCTheme::CheckboxBorderHoverColor; - bgClr = CMPCTheme::CheckboxBGHoverColor; - } else { - borderClr = CMPCTheme::CheckboxBorderColor; - bgClr = CMPCTheme::CheckboxBGColor; - } - - if (useSystemSize) { - CPngImage image; - image.Load(getResourceByDPI(window, pDC, isRadio ? CMPCTheme::ThemeRadios : CMPCTheme::ThemeCheckBoxes), AfxGetInstanceHandle()); - BITMAP bm; - image.GetBitmap(&bm); - int size = bm.bmHeight; - - CDC mDC; - mDC.CreateCompatibleDC(pDC); - mDC.SelectObject(image); - int index; - if (isRadio) { - index = RadioRegular; - if (checkState) { - index += 1; - } - if (isHover) { - index += 2; - } - } else { - index = CheckBoxRegular; - if (isHover) { - index += 1; - } - } - CRect drawRect(0, 0, size, size); - //drawRect.OffsetRect(rectCheck.left + (rectCheck.Width() - size) / 2, rectCheck.top + (rectCheck.Height() - size) / 2); - drawRect.OffsetRect(rectCheck.left, rectCheck.top + (rectCheck.Height() - size) / 2); - - if (!isRadio && checkState != BST_CHECKED) { //we can draw this w/o BMPs - CBrush brush(borderClr); - pDC->FrameRect(drawRect, &brush); - drawRect.DeflateRect(1, 1); - pDC->FillSolidRect(drawRect, bgClr); - if (checkState == BST_INDETERMINATE) { - drawRect.DeflateRect(2, 2); - pDC->FillSolidRect(drawRect, CMPCTheme::CheckColor); - } - } else { - int left = index * size; - pDC->BitBlt(drawRect.left, drawRect.top, drawRect.Width(), drawRect.Height(), &mDC, left, 0, SRCCOPY); - } - } else { - CBrush brush(borderClr); - pDC->FrameRect(rectCheck, &brush); - rectCheck.DeflateRect(1, 1); - pDC->FillSolidRect(rectCheck, bgClr); - if (BST_CHECKED == checkState) { - CBitmap checkBMP; - CDC dcCheckBMP; - dcCheckBMP.CreateCompatibleDC(pDC); - - int left, top, width, height; - width = CMPCTheme::CheckWidth; - height = CMPCTheme::CheckHeight; - left = rectCheck.left + (rectCheck.Width() - width) / 2; - top = rectCheck.top + (rectCheck.Height() - height) / 2; - checkBMP.CreateBitmap(width, height, 1, 1, CMPCTheme::CheckBits); - dcCheckBMP.SelectObject(&checkBMP); - - pDC->SetBkColor(CMPCTheme::CheckColor); - pDC->SetTextColor(bgClr); - pDC->BitBlt(left, top, width, height, &dcCheckBMP, 0, 0, SRCCOPY); - } else if (BST_INDETERMINATE == checkState) { - rectCheck.DeflateRect(2, 2); - pDC->FillSolidRect(rectCheck, CMPCTheme::CheckColor); - } - } - pDC->SetBkColor(oldBkClr); - pDC->SetTextColor(oldTextClr); -} - -bool CMPCThemeUtil::canUseWin10DarkTheme() -{ - if (AppNeedsThemedControls()) { - // return false; //FIXME. return false to test behavior for OS < Win10 1809 - RTL_OSVERSIONINFOW osvi = GetRealOSVersion(); - bool ret = (osvi.dwMajorVersion = 10 && osvi.dwMajorVersion >= 0 && osvi.dwBuildNumber >= 17763); //dark theme first available in win 10 1809 - return ret; - } - return false; -} - -UINT CMPCThemeUtil::defaultLogo() -{ - return IDF_LOGO4; -} - -struct AFX_CTLCOLOR { - HWND hWnd; - HDC hDC; - UINT nCtlType; -}; - -HBRUSH CMPCThemeUtil::getParentDialogBGClr(CWnd* wnd, CDC* pDC) { - WPARAM w = (WPARAM)pDC; - AFX_CTLCOLOR ctl; - ctl.hWnd = wnd->GetSafeHwnd(); - ctl.nCtlType = CTLCOLOR_DLG; - ctl.hDC = pDC->GetSafeHdc(); - CWnd* parent = wnd->GetParent(); - if (nullptr == parent) { - parent = wnd; - } - HBRUSH bg = (HBRUSH)parent->SendMessage(WM_CTLCOLORDLG, w, (LPARAM)&ctl); - return bg; -} - -void CMPCThemeUtil::drawParentDialogBGClr(CWnd* wnd, CDC* pDC, CRect r, bool fill) -{ - CBrush brush; - HBRUSH bg = getParentDialogBGClr(wnd, pDC); - brush.Attach(bg); - if (fill) { - pDC->FillRect(r, &brush); - } else { - pDC->FrameRect(r, &brush); - } - brush.Detach(); -} - -void CMPCThemeUtil::fulfillThemeReqs(CProgressCtrl* ctl) -{ - if (AppIsThemeLoaded()) { - SetWindowTheme(ctl->GetSafeHwnd(), _T(""), _T("")); - ctl->SetBarColor(CMPCTheme::ProgressBarColor); - ctl->SetBkColor(CMPCTheme::ProgressBarBGColor); - } - ctl->UpdateWindow(); -} - -void CMPCThemeUtil::enableWindows10DarkFrame(CWnd* window) -{ - if (canUseWin10DarkTheme()) { - HMODULE hUser = GetModuleHandleA("user32.dll"); - if (hUser) { - pfnSetWindowCompositionAttribute setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(hUser, "SetWindowCompositionAttribute"); - if (setWindowCompositionAttribute) { - ACCENT_POLICY accent = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 }; - WINDOWCOMPOSITIONATTRIBDATA data; - data.Attrib = WCA_USEDARKMODECOLORS; - data.pvData = &accent; - data.cbData = sizeof(accent); - setWindowCompositionAttribute(window->GetSafeHwnd(), &data); - } - } - } -} - -int CALLBACK PropSheetCallBackRTL(HWND hWnd, UINT message, LPARAM lParam) { - switch (message) { - case PSCB_PRECREATE: - { - //arabic or hebrew - if (Translations::IsLangRTL(AfxGetAppSettings().language)) { - LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam; - lpTemplate->dwExtendedStyle |= WS_EX_LAYOUTRTL; - } - } - break; - } - return 0; -} - -void CMPCThemeUtil::PreDoModalRTL(LPPROPSHEETHEADERW m_psh) { - //see RTLWindowsLayoutCbtFilterHook and Translations::SetLanguage. - //We handle here to avoid Windows 11 bug with SetWindowLongPtr - m_psh->dwFlags |= PSH_USECALLBACK; - m_psh->pfnCallback = PropSheetCallBackRTL; -} - -//Regions are relative to upper left of WINDOW rect (not client) -CPoint CMPCThemeUtil::GetRegionOffset(CWnd* window) { - CRect twr, tcr; - window->GetWindowRect(twr); - window->GetClientRect(tcr); - ::MapWindowPoints(window->GetSafeHwnd(), nullptr, (LPPOINT)&tcr, 2); - CPoint offset = tcr.TopLeft() - twr.TopLeft(); - return offset; -} - -void CMPCThemeUtil::AdjustDynamicWidgetPair(CWnd* window, int leftWidget, int rightWidget, WidgetPairType lType, WidgetPairType rType) { - if (window && IsWindow(window->m_hWnd)) { - DpiHelper dpiWindow; - dpiWindow.Override(window->GetSafeHwnd()); - LONG dynamicSpace = dpiWindow.ScaleX(5); - - - - CWnd* leftW = window->GetDlgItem(leftWidget); - CWnd* rightW = window->GetDlgItem(rightWidget); - - WidgetPairType ll = lType; - WidgetPairType rr = rType; - - if (true || lType == WidgetPairAuto) { - LRESULT lRes = leftW->SendMessage(WM_GETDLGCODE, 0, 0); - DWORD buttonType = (leftW->GetStyle() & BS_TYPEMASK); - - if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX)) { - lType = WidgetPairCheckBox; - } else { //we only support checkbox or text on the left, just assume it's text now - lType = WidgetPairText; - } - } - - if (true || rType == WidgetPairAuto) { - TCHAR windowClass[MAX_PATH]; - ::GetClassName(rightW->GetSafeHwnd(), windowClass, _countof(windowClass)); - - if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { - rType = WidgetPairCombo; - } else { //we only support combo or edit on the right, just assume it's edit now - rType = WidgetPairEdit; - } - } - - if (leftW && rightW && IsWindow(leftW->m_hWnd) && IsWindow(rightW->m_hWnd)) { - CRect l, r; - LONG leftWantsRight, rightWantsLeft; - - leftW->GetWindowRect(l); - leftW->GetOwner()->ScreenToClient(l); - rightW->GetWindowRect(r); - rightW->GetOwner()->ScreenToClient(r); - CDC* lpDC = leftW->GetDC(); - CFont* pFont = leftW->GetFont(); - leftWantsRight = l.right; - rightWantsLeft = r.left; - { - int left = l.left; - if (lType == WidgetPairCheckBox) { - left += dpiWindow.GetSystemMetricsDPI(SM_CXMENUCHECK) + 2; - } - - CFont* pOldFont = lpDC->SelectObject(pFont); - TEXTMETRIC tm; - lpDC->GetTextMetricsW(&tm); - - CString str; - leftW->GetWindowTextW(str); - CSize szText = lpDC->GetTextExtent(str); - lpDC->SelectObject(pOldFont); - - leftWantsRight = left + szText.cx + tm.tmAveCharWidth; - leftW->ReleaseDC(lpDC); - } - - { - if (rType == WidgetPairCombo) { - //int wantWidth = (int)::SendMessage(rightW->m_hWnd, CB_GETDROPPEDWIDTH, 0, 0); - CComboBox *cb = DYNAMIC_DOWNCAST(CComboBox, rightW); - if (cb) { - int wantWidth = CorrectComboListWidth(*cb); - if (wantWidth != CB_ERR) { - rightWantsLeft = r.right - wantWidth - GetSystemMetrics(SM_CXVSCROLL); - } - } - } - } - CRect cl = l, cr = r; - if (leftWantsRight > rightWantsLeft - dynamicSpace //overlaps; we will assume defaults are best - || (leftWantsRight < l.right && rightWantsLeft > r.left) // there is no need to resize - || (lType == WidgetPairText && DT_RIGHT == (leftW->GetStyle() & DT_RIGHT)) ) //right aligned text not supported, as the right edge is fixed - { - //do nothing - } else { - l.right = leftWantsRight; - //if necessary space would shrink the right widget, instead get as close to original size as possible - //this minimizes noticeable layout changes - r.left = std::min(rightWantsLeft, std::max(l.right + dynamicSpace, r.left)); - } - if ((lType == WidgetPairText || lType == WidgetPairCheckBox) && (rType == WidgetPairCombo || rType == WidgetPairEdit)) { - l.top = r.top; - l.bottom += r.Height() - l.Height(); - leftW->ModifyStyle(0, SS_CENTERIMAGE); - } - - if (l != cl) { - leftW->MoveWindow(l); - } - if (r != cr) { - rightW->MoveWindow(r); - } - } - } -} - -void CMPCThemeUtil::UpdateAnalogCaptureDeviceSlider(CScrollBar* pScrollBar) { - if (pScrollBar && ::IsWindow(pScrollBar->m_hWnd)) { - if (CSliderCtrl* slider = DYNAMIC_DOWNCAST(CSliderCtrl, pScrollBar)) { - slider->SendMessage(WM_KEYUP, VK_LEFT, 1); //does not move the slider, only forces current position to be registered - } - } -} - -bool CMPCThemeUtil::IsWindowVisibleAndRendered(CWnd* window) { - if (!window || !IsWindow(window->m_hWnd) || !window->IsWindowVisible()) { - return false; - } else { - CRect r; - HDC hdc = GetWindowDC(window->m_hWnd); - GetClipBox(hdc, &r); - if (r.IsRectEmpty()) { - return false; - } - } - return true; -} +#include "stdafx.h" +#include "CMPCThemeUtil.h" +#include "CMPCTheme.h" +#include "mplayerc.h" +#include "MainFrm.h" +#include "CMPCThemeStatic.h" +#include "CMPCThemeDialog.h" +#include "CMPCThemeSliderCtrl.h" +#include "CMPCThemeTabCtrl.h" +#include "VersionHelpersInternal.h" +#include "CMPCThemeTitleBarControlButton.h" +#include "CMPCThemeInternalPropertyPageWnd.h" +#include "CMPCThemeWin10Api.h" +#include "Translations.h" +#include "ImageGrayer.h" +#include "CMPCThemePropPageButton.h" +#undef SubclassWindow + +CBrush CMPCThemeUtil::contentBrush; +CBrush CMPCThemeUtil::windowBrush; +CBrush CMPCThemeUtil::controlAreaBrush; +CBrush CMPCThemeUtil::W10DarkThemeFileDialogInjectedBGBrush; +NONCLIENTMETRICS CMPCThemeUtil::nonClientMetrics = { 0 }; +bool CMPCThemeUtil::metricsNeedCalculation = true; + +CMPCThemeUtil::CMPCThemeUtil(): + themedDialogToolTipParent(nullptr) +{ +} + +CMPCThemeUtil::~CMPCThemeUtil() +{ + for (u_int i = 0; i < allocatedWindows.size(); i++) { + delete allocatedWindows[i]; + } +} + +void CMPCThemeUtil::subClassTBCustomizeDialog(CWnd* wnd, CToolBar* customizeToolBar) +{ + CWnd* c = CWnd::FromHandle(themableDialogHandle); + CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(); + pObject->SetSpecialCase(ToolbarCustomizeDialog); + makeThemed(pObject, c); + fulfillThemeReqs(c, ToolbarCustomizeDialog, customizeToolBar); + + ::RedrawWindow(themableDialogHandle, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_ERASE); + + if (AfxGetAppSettings().bWindows10DarkThemeActive) { + enableWindows10DarkFrame(pObject); + //force titlebar redraw + c->SendMessage(WM_NCACTIVATE, FALSE); + c->SendMessage(WM_NCACTIVATE, TRUE); + } +} + +void CMPCThemeUtil::fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase /* = 0 */, CWnd* otherWindow /* = nullptr */) +{ + if (AppIsThemeLoaded()) { + + initHelperObjects(); + + CWnd* pChild = wnd->GetWindow(GW_CHILD); + while (pChild) { + LRESULT lRes = pChild->SendMessage(WM_GETDLGCODE, 0, 0); + CWnd* tChild = pChild; + pChild = pChild->GetNextWindow(); //increment before any unsubclassing + CString runtimeClass = tChild->GetRuntimeClass()->m_lpszClassName; + TCHAR windowClass[MAX_PATH]; + ::GetClassName(tChild->GetSafeHwnd(), windowClass, _countof(windowClass)); + DWORD style = tChild->GetStyle(); + DWORD buttonType = (style & BS_TYPEMASK); + DWORD staticStyle = (style & SS_TYPEMASK); + CString windowTitle; + + if (tChild->m_hWnd) { + tChild->GetWindowText(windowTitle); + } + bool canSubclass = (CWnd::FromHandlePermanent(tChild->GetSafeHwnd()) == NULL); //refuse to subclass if already subclassed. in this case the member class should be updated rather than dynamically subclassing + + if (canSubclass) { + if (DLGC_BUTTON == (lRes & DLGC_BUTTON)) { + if (DLGC_DEFPUSHBUTTON == (lRes & DLGC_DEFPUSHBUTTON) || DLGC_UNDEFPUSHBUTTON == (lRes & DLGC_UNDEFPUSHBUTTON)) { + CMPCThemeButton* pObject; + if (specialCase == ExternalPropertyPageWithDefaultButton && windowTitle == "Default" && AppNeedsThemedControls()) { + pObject = DEBUG_NEW CMPCThemePropPageButton(); + } else { + pObject = DEBUG_NEW CMPCThemeButton(); + } + makeThemed(pObject, tChild); + } else if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX)) { + CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); + makeThemed(pObject, tChild); + } else if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_3STATE || buttonType == BS_AUTO3STATE)) { + CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); + makeThemed(pObject, tChild); + } else if (DLGC_RADIOBUTTON == (lRes & DLGC_RADIOBUTTON) && (buttonType == BS_RADIOBUTTON || buttonType == BS_AUTORADIOBUTTON)) { + CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); + makeThemed(pObject, tChild); + } else { //what other buttons? + // int a = 1; + } + } else if (0 == _tcsicmp(windowClass, WC_SCROLLBAR)) { + } else if (0 == _tcsicmp(windowClass, WC_BUTTON) && buttonType == BS_GROUPBOX) { + CMPCThemeGroupBox* pObject = DEBUG_NEW CMPCThemeGroupBox(); + makeThemed(pObject, tChild); + SetWindowTheme(tChild->GetSafeHwnd(), L"", L""); + } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_ICON == staticStyle) { //don't touch icons for now + } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_BITMAP == staticStyle) { //don't touch BITMAPS for now + } else if (0 == _tcsicmp(windowClass, WC_STATIC) && SS_OWNERDRAW == staticStyle) { //don't touch OWNERDRAW for now + } else if (0 == _tcsicmp(windowClass, WC_STATIC) && (staticStyle < SS_OWNERDRAW || SS_ETCHEDHORZ == staticStyle || SS_ETCHEDVERT == staticStyle || SS_ETCHEDFRAME == staticStyle)) { + LITEM li = { 0 }; + li.mask = LIF_ITEMINDEX | LIF_ITEMID; + if (::SendMessage(tChild->GetSafeHwnd(), LM_GETITEM, 0, (LPARAM)& li)) { //we appear to have a linkctrl + CMPCThemeLinkCtrl* pObject = DEBUG_NEW CMPCThemeLinkCtrl(); + makeThemed(pObject, tChild); + } else { + CMPCThemeStatic* pObject = DEBUG_NEW CMPCThemeStatic(); + if (0 == (style & SS_LEFTNOWORDWRAP) && 0 == windowTitle.Left(20).Compare(_T("Select which output "))) { + //this is a hack for LAVFilters to avoid wrapping the statics + //FIXME by upstreaming a change to dialog layout of lavfilters, or by developing a dynamic re-layout engine + CRect wr; + tChild->GetWindowRect(wr); + wnd->ScreenToClient(wr); + wr.right += 5; + tChild->MoveWindow(wr); + } + makeThemed(pObject, tChild); + if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase && 0x416 == GetDlgCtrlID(tChild->m_hWnd)) { + CStringW str; + pObject->GetWindowTextW(str); + str.Replace(L" \r\n ", L"\r\n"); //this prevents double-wrapping due to the space wrapping before the carriage return + pObject->SetWindowTextW(str); + pObject->ModifyStyle(0, TBS_DOWNISLEFT); + } + } + } else if (0 == _tcsicmp(windowClass, WC_EDIT)) { + CMPCThemeEdit* pObject = DEBUG_NEW CMPCThemeEdit(); + makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, UPDOWN_CLASS)) { + CMPCThemeSpinButtonCtrl* pObject = DEBUG_NEW CMPCThemeSpinButtonCtrl(); + makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, _T("#32770"))) { //dialog class + CMPCThemeDialog* pObject = DEBUG_NEW CMPCThemeDialog(windowTitle == ""); + pObject->SetSpecialCase(specialCase); + makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { + CMPCThemeComboBox* pObject = DEBUG_NEW CMPCThemeComboBox(); + makeThemed(pObject, tChild); + } else if (0 == _tcsicmp(windowClass, WC_LISTBOX)) { + CMPCThemeListBox* pObject = DEBUG_NEW CMPCThemeListBox(); + makeThemed(pObject, tChild); + if (specialCase == ToolbarCustomizeDialog) { + pObject->SetCustomizeToolbar ((CToolBar*)otherWindow); + } + } else if (0 == _tcsicmp(windowClass, TRACKBAR_CLASS)) { + CMPCThemeSliderCtrl* pObject = DEBUG_NEW CMPCThemeSliderCtrl(); + makeThemed(pObject, tChild); + if (ExternalPropertyPageWithAnalogCaptureSliders == specialCase) { + pObject->ModifyStyle(0, TBS_DOWNISLEFT); + } + } else if (0 == _tcsicmp(windowClass, WC_TABCONTROL)) { + CMPCThemeTabCtrl* pObject = DEBUG_NEW CMPCThemeTabCtrl(); + makeThemed(pObject, tChild); + } else if (windowTitle == _T("CInternalPropertyPageWnd")) { //only seems to be needed for windows from external filters? + CMPCThemeInternalPropertyPageWnd* pObject = DEBUG_NEW CMPCThemeInternalPropertyPageWnd(); + makeThemed(pObject, tChild); + } + } + if (0 == _tcsicmp(windowClass, _T("#32770"))) { //dialog class + fulfillThemeReqs(tChild, specialCase); + } else if (windowTitle == _T("CInternalPropertyPageWnd")) { //internal window encompassing property pages + fulfillThemeReqs(tChild); + } + } + } +} + +void CMPCThemeUtil::initHelperObjects() +{ + if (contentBrush.m_hObject == nullptr) { + contentBrush.CreateSolidBrush(CMPCTheme::ContentBGColor); + } + if (windowBrush.m_hObject == nullptr) { + windowBrush.CreateSolidBrush(CMPCTheme::WindowBGColor); + } + if (controlAreaBrush.m_hObject == nullptr) { + controlAreaBrush.CreateSolidBrush(CMPCTheme::ControlAreaBGColor); + } + if (W10DarkThemeFileDialogInjectedBGBrush.m_hObject == nullptr) { + W10DarkThemeFileDialogInjectedBGBrush.CreateSolidBrush(CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); + } +} + +void CMPCThemeUtil::makeThemed(CWnd* pObject, CWnd* tChild) +{ + allocatedWindows.push_back(pObject); + pObject->SubclassWindow(tChild->GetSafeHwnd()); +} + +void CMPCThemeUtil::EnableThemedDialogTooltips(CDialog* wnd) +{ + if (AppIsThemeLoaded()) { + if (themedDialogToolTip.m_hWnd) { + themedDialogToolTip.DestroyWindow(); + } + themedDialogToolTipParent = wnd; + themedDialogToolTip.Create(wnd, TTS_NOPREFIX | TTS_ALWAYSTIP); + themedDialogToolTip.Activate(TRUE); + themedDialogToolTip.SetDelayTime(TTDT_AUTOPOP, 10000); + //enable tooltips for all child windows + CWnd* pChild = wnd->GetWindow(GW_CHILD); + while (pChild) { + themedDialogToolTip.AddTool(pChild, LPSTR_TEXTCALLBACK); + pChild = pChild->GetNextWindow(); + } + } else { + wnd->EnableToolTips(TRUE); + } +} + +void CMPCThemeUtil::RedrawDialogTooltipIfVisible() { + if (AppIsThemeLoaded() && themedDialogToolTip.m_hWnd) { + themedDialogToolTip.RedrawIfVisible(); + } else { + AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState(); + CToolTipCtrl* pToolTip = pModuleThreadState->m_pToolTip; + if (pToolTip && ::IsWindow(pToolTip->m_hWnd) && pToolTip->IsWindowVisible()) { + pToolTip->Update(); + } + } +} + +void CMPCThemeUtil::PlaceThemedDialogTooltip(UINT_PTR nID) +{ + if (AppIsThemeLoaded() && IsWindow(themedDialogToolTip)) { + if (::IsWindow(themedDialogToolTipParent->GetSafeHwnd())) { + CWnd* controlWnd = themedDialogToolTipParent->GetDlgItem(nID); + themedDialogToolTip.SetHoverPosition(controlWnd); + } + } +} + +void CMPCThemeUtil::RelayThemedDialogTooltip(MSG* pMsg) +{ + if (AppIsThemeLoaded() && IsWindow(themedDialogToolTip)) { + themedDialogToolTip.RelayEvent(pMsg); + } +} + +LRESULT CALLBACK wndProcFileDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC wndProcSink = NULL; + wndProcSink = (WNDPROC)GetProp(hWnd, _T("WNDPROC_SINK")); + if (!wndProcSink) { + return 0; + } + if (WM_CTLCOLOREDIT == uMsg) { + return (LRESULT)CMPCThemeUtil::getCtlColorFileDialog((HDC)wParam, CTLCOLOR_EDIT); + } + return ::CallWindowProc(wndProcSink, hWnd, uMsg, wParam, lParam); +} + +void CMPCThemeUtil::subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass) { + if (0 == wcsicmp(childWindowClass, WC_STATIC)) { + CWnd* c = CWnd::FromHandle(widget); + c->UnsubclassWindow(); + CMPCThemeStatic* pObject = DEBUG_NEW CMPCThemeStatic(); + pObject->setFileDialogChild(true); + allocatedWindows.push_back(pObject); + pObject->SubclassWindow(widget); + } else if (0 == wcsicmp(childWindowClass, WC_BUTTON)) { + CWnd* c = CWnd::FromHandle(widget); + DWORD style = c->GetStyle(); + DWORD buttonType = (style & BS_TYPEMASK); + if (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX) { + c->UnsubclassWindow(); + CMPCThemeRadioOrCheck* pObject = DEBUG_NEW CMPCThemeRadioOrCheck(); + pObject->setFileDialogChild(true); + allocatedWindows.push_back(pObject); + pObject->SubclassWindow(widget); + } + } else if (0 == wcsicmp(childWindowClass, WC_EDIT)) { + CWnd* c = CWnd::FromHandle(widget); + c->UnsubclassWindow(); + CMPCThemeEdit* pObject = DEBUG_NEW CMPCThemeEdit(); + pObject->setFileDialogChild(true); + allocatedWindows.push_back(pObject); + pObject->SubclassWindow(widget); + if (nullptr == GetProp(parent, _T("WNDPROC_SINK"))) { + LONG_PTR wndProcOld = ::SetWindowLongPtr(parent, GWLP_WNDPROC, (LONG_PTR)wndProcFileDialog); + SetProp(parent, _T("WNDPROC_SINK"), (HANDLE)wndProcOld); + } + } +} + +void CMPCThemeUtil::subClassFileDialog(CWnd* wnd) { + if (AfxGetAppSettings().bWindows10DarkThemeActive) { + initHelperObjects(); + + HWND duiview = ::FindWindowExW(themableDialogHandle, NULL, L"DUIViewWndClassName", NULL); + HWND duihwnd = ::FindWindowExW(duiview, NULL, L"DirectUIHWND", NULL); + + if (duihwnd) { //we found the FileDialog + if (dialogProminentControlStringID) { //if this is set, we assume there is a single prominent control (note, it's in the filedialog main window) + subClassFileDialogRecurse(wnd, themableDialogHandle, ProminentControlIDWidget); + } else { + subClassFileDialogRecurse(wnd, duihwnd, RecurseSinkWidgets); + } + themableDialogHandle = nullptr; + ::RedrawWindow(duiview, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); + } + } +} + +void CMPCThemeUtil::subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType) { + HWND pChild = ::GetWindow(hWnd, GW_CHILD); + while (pChild) { + WCHAR childWindowClass[MAX_PATH]; + ::GetClassName(pChild, childWindowClass, _countof(childWindowClass)); + if (searchType == RecurseSinkWidgets) { + if (0 == wcsicmp(childWindowClass, L"FloatNotifySink")) { //children are the injected controls + subClassFileDialogRecurse(wnd, pChild, ThemeAllChildren); //recurse and theme all children of sink + } + } else if (searchType == ThemeAllChildren) { + subClassFileDialogWidgets(pChild, hWnd, childWindowClass); + } else if (searchType == ProminentControlIDWidget){ + WCHAR str[MAX_PATH]; + ::GetWindowText(pChild, str, _countof(str)); + if (0 == wcsicmp(str, ResStr(dialogProminentControlStringID))) { + subClassFileDialogWidgets(pChild, hWnd, childWindowClass); + return; + } + } + pChild = ::GetNextWindow(pChild, GW_HWNDNEXT); + } +} + +void CMPCThemeUtil::redrawAllThemedWidgets() { + for (auto w : allocatedWindows) { + w->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } +} + +AFX_STATIC DLGITEMTEMPLATE* AFXAPI _AfxFindNextDlgItem(DLGITEMTEMPLATE* pItem, BOOL bDialogEx); +AFX_STATIC DLGITEMTEMPLATE* AFXAPI _AfxFindFirstDlgItem(const DLGTEMPLATE* pTemplate); + +AFX_STATIC inline BOOL IsDialogEx(const DLGTEMPLATE* pTemplate) +{ + return ((_DialogSplitHelper::DLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF; +} + +static inline WORD& DlgTemplateItemCount(DLGTEMPLATE* pTemplate) +{ + if (IsDialogEx(pTemplate)) { + return reinterpret_cast<_DialogSplitHelper::DLGTEMPLATEEX*>(pTemplate)->cDlgItems; + } else { + return pTemplate->cdit; + } +} + +static inline const WORD& DlgTemplateItemCount(const DLGTEMPLATE* pTemplate) +{ + if (IsDialogEx(pTemplate)) { + return reinterpret_cast(pTemplate)->cDlgItems; + } else { + return pTemplate->cdit; + } +} + +bool CMPCThemeUtil::ModifyTemplates(CPropertySheet* sheet, CRuntimeClass* pageClass, DWORD id, DWORD addStyle, DWORD removeStyle) +{ + if (AppIsThemeLoaded()) { + PROPSHEETHEADER m_psh = sheet->m_psh; + for (int i = 0; i < sheet->GetPageCount(); i++) { + CPropertyPage* pPage = sheet->GetPage(i); + if (nullptr == AfxDynamicDownCast(pageClass, pPage)) { + continue; + } + PROPSHEETPAGE* tpsp = &pPage->m_psp; + + const DLGTEMPLATE* pTemplate; + if (tpsp->dwFlags & PSP_DLGINDIRECT) { + pTemplate = tpsp->pResource; + } else { + HRSRC hResource = ::FindResource(tpsp->hInstance, tpsp->pszTemplate, RT_DIALOG); + if (hResource == NULL) { + return false; + } + HGLOBAL hTemplate = LoadResource(tpsp->hInstance, hResource); + if (hTemplate == NULL) { + return false; + } + pTemplate = (LPCDLGTEMPLATE)LockResource(hTemplate); + if (pTemplate == NULL) { + return false; + } + } + + if (afxOccManager != NULL) { + DLGITEMTEMPLATE* pItem = _AfxFindFirstDlgItem(pTemplate); + DLGITEMTEMPLATE* pNextItem; + BOOL bDialogEx = IsDialogEx(pTemplate); + + int iItem, iItems = DlgTemplateItemCount(pTemplate); + + for (iItem = 0; iItem < iItems; iItem++) { + pNextItem = _AfxFindNextDlgItem(pItem, bDialogEx); + DWORD dwOldProtect, tp; + if (bDialogEx) { + _DialogSplitHelper::DLGITEMTEMPLATEEX* pItemEx = (_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem; + if (pItemEx->id == id) { + if (VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), PAGE_READWRITE, &dwOldProtect)) { + pItemEx->style |= addStyle; + pItemEx->style &= ~removeStyle; + VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), dwOldProtect, &tp); + } + } + } else { + if (pItem->id == id) { + if (VirtualProtect(&pItem->style, sizeof(pItem->style), PAGE_READWRITE, &dwOldProtect)) { + pItem->style |= addStyle; + pItem->style &= ~removeStyle; + VirtualProtect(&pItem->style, sizeof(pItem->style), dwOldProtect, &tp); + } + } + } + pItem = pNextItem; + } + } + } + } + return true; +} + +void CMPCThemeUtil::enableFileDialogHook() +{ + CMainFrame* pMainFrame = AfxGetMainFrame(); + pMainFrame->enableFileDialogHook(this); +} + +HBRUSH CMPCThemeUtil::getCtlColorFileDialog(HDC hDC, UINT nCtlColor) +{ + initHelperObjects(); + if (CTLCOLOR_EDIT == nCtlColor) { + ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); + ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); + return W10DarkThemeFileDialogInjectedBGBrush; + } else if (CTLCOLOR_STATIC == nCtlColor) { + ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); + ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); + return W10DarkThemeFileDialogInjectedBGBrush; + } else if (CTLCOLOR_BTN == nCtlColor) { + ::SetTextColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedTextColor); + ::SetBkColor(hDC, CMPCTheme::W10DarkThemeFileDialogInjectedBGColor); + return W10DarkThemeFileDialogInjectedBGBrush; + } else { + return NULL; + } +} + +HBRUSH CMPCThemeUtil::getCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + initHelperObjects(); + LRESULT lResult; + if (pWnd->SendChildNotifyLastMsg(&lResult)) { + return (HBRUSH)lResult; + } + if (CTLCOLOR_LISTBOX == nCtlColor) { + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::ContentBGColor); + return contentBrush; + } else { + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::WindowBGColor); + return windowBrush; + } + } + return nullptr; +} + +bool CMPCThemeUtil::MPCThemeEraseBkgnd(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppIsThemeLoaded()) { + CRect rect; + pWnd->GetClientRect(rect); + if (CTLCOLOR_DLG == nCtlColor) { //only supported "class" for now + pDC->FillSolidRect(rect, CMPCTheme::WindowBGColor); + } else { + return false; + } + return true; + } else { + return false; + } +} + +bool CMPCThemeUtil::getFontByFace(CFont& font, CWnd* wnd, wchar_t* fontName, int size, LONG weight) +{ + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + + if (!wnd) { + wnd = AfxGetMainWnd(); + } + + DpiHelper dpiWindow; + + dpiWindow.Override(wnd->GetSafeHwnd()); + lf.lfHeight = -MulDiv(size, dpiWindow.DPIY(), 72); + + lf.lfQuality = CLEARTYPE_QUALITY; + + //lf.lfQuality = ANTIALIASED_QUALITY; + lf.lfWeight = weight; + wcsncpy_s(lf.lfFaceName, fontName, LF_FACESIZE); + + return font.CreateFontIndirect(&lf); +} + +bool CMPCThemeUtil::getFixedFont(CFont& font, CDC* pDC, CWnd* wnd) +{ + if (!wnd) { + wnd = AfxGetMainWnd(); + } + + DpiHelper dpiWindow; + dpiWindow.Override(wnd->GetSafeHwnd()); + + LOGFONT tlf; + memset(&tlf, 0, sizeof(LOGFONT)); + tlf.lfHeight = -MulDiv(10, dpiWindow.DPIY(), 72); + tlf.lfQuality = CLEARTYPE_QUALITY; + tlf.lfWeight = FW_REGULAR; + wcsncpy_s(tlf.lfFaceName, _T("Consolas"), LF_FACESIZE); + return font.CreateFontIndirect(&tlf); +} + +bool CMPCThemeUtil::getFontByType(CFont& font, CWnd* wnd, int type, bool underline, bool bold) +{ + /* adipose: works poorly for dialogs as they cannot be scaled to fit zoomed fonts, only use for menus and status bars*/ + GetMetrics(); + + if (!wnd) { + wnd = AfxGetMainWnd(); + } + + //metrics will have the right fonts for the main window, but current window may be on another screen + DpiHelper dpiWindow, dpiMain; + dpiWindow.Override(wnd->GetSafeHwnd()); + dpiMain.Override(AfxGetMainWnd()->GetSafeHwnd()); + + LOGFONT* lf; + if (type == CaptionFont) { + lf = &nonClientMetrics.lfCaptionFont; + } else if (type == SmallCaptionFont) { + lf = &nonClientMetrics.lfSmCaptionFont; + } else if (type == MenuFont) { + lf = &nonClientMetrics.lfMenuFont; + } else if (type == StatusFont) { + lf = &nonClientMetrics.lfStatusFont; + } else if (type == MessageFont || type == DialogFont) { + lf = &nonClientMetrics.lfMessageFont; +#if 0 + } else if (type == DialogFont) { //hack for compatibility with MS SHell Dlg (8) used in dialogs + DpiHelper dpiWindow; + dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); + + LOGFONT tlf; + memset(&tlf, 0, sizeof(LOGFONT)); + tlf.lfHeight = -MulDiv(8, dpiWindow.DPIY(), 72); + tlf.lfQuality = CLEARTYPE_QUALITY; + tlf.lfWeight = FW_REGULAR; + wcsncpy_s(tlf.lfFaceName, m.lfMessageFont.lfFaceName, LF_FACESIZE); + //wcsncpy_s(tlf.lfFaceName, _T("MS Shell Dlg"), LF_FACESIZE); + lf = &tlf; +#endif + } else { + lf = &nonClientMetrics.lfMessageFont; + } + + int newHeight = MulDiv(lf->lfHeight, dpiWindow.DPIY(), dpiMain.DPIY()); + if (underline || bold || newHeight != lf->lfHeight) { + LOGFONT tlf; + memset(&tlf, 0, sizeof(LOGFONT)); + tlf.lfHeight = newHeight; + tlf.lfQuality = lf->lfQuality; + tlf.lfWeight = lf->lfWeight; + wcsncpy_s(tlf.lfFaceName, lf->lfFaceName, LF_FACESIZE); + tlf.lfUnderline = underline; + if (bold) { + tlf.lfWeight = FW_BOLD; + } + return font.CreateFontIndirect(&tlf); + } else { + return font.CreateFontIndirect(lf); + } +} + +CSize CMPCThemeUtil::GetTextSize(CString str, CDC* pDC, CFont* font) +{ + CFont* pOldFont = pDC->SelectObject(font); + + CRect r = { 0, 0, 0, 0 }; + pDC->DrawTextW(str, r, DT_SINGLELINE | DT_CALCRECT); + CSize cs = r.Size(); + pDC->SelectObject(pOldFont); + return cs; +} + +CSize CMPCThemeUtil::GetTextSize(CString str, HDC hDC, CFont* font) +{ + CDC* pDC = CDC::FromHandle(hDC); + return GetTextSize(str, pDC, font); +} + +CSize CMPCThemeUtil::GetTextSize(CString str, HDC hDC, CWnd *wnd, int type) +{ + CDC* pDC = CDC::FromHandle(hDC); + CFont font; + getFontByType(font, wnd, type); + + return GetTextSize(str, pDC, &font); +} + +CSize CMPCThemeUtil::GetTextSizeDiff(CString str, HDC hDC, CWnd* wnd, int type, CFont* curFont) +{ + CSize cs = GetTextSize(str, hDC, wnd, type); + CDC* cDC = CDC::FromHandle(hDC); + CFont* pOldFont = cDC->SelectObject(curFont); + CSize curCs = cDC->GetTextExtent(str); + cDC->SelectObject(pOldFont); + + return cs - curCs; +} + +void CMPCThemeUtil::GetMetrics(bool reset /* = false */) +{ + NONCLIENTMETRICS *m = &nonClientMetrics; + if (m->cbSize == 0 || metricsNeedCalculation || reset) { + m->cbSize = sizeof(NONCLIENTMETRICS); + ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), m, 0); + if (AfxGetMainWnd() == nullptr) {//this used to happen when CPreView::OnCreate was calling ScaleFont, should no longer occur + return; //we can do nothing more if main window not found yet, and metricsNeedCalculation will remain set + } + + DpiHelper dpi, dpiWindow; + dpiWindow.Override(AfxGetMainWnd()->GetSafeHwnd()); + + //getclientmetrics is ignorant of per window DPI + if (dpi.ScaleFactorY() != dpiWindow.ScaleFactorY()) { + m->lfCaptionFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfCaptionFont.lfHeight); + m->lfSmCaptionFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfSmCaptionFont.lfHeight); + m->lfMenuFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfMenuFont.lfHeight); + m->lfStatusFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfStatusFont.lfHeight); + m->lfMessageFont.lfHeight = dpiWindow.ScaleSystemToOverrideY(m->lfMessageFont.lfHeight); + } + metricsNeedCalculation = false; + } +} + +void CMPCThemeUtil::initMemDC(CDC* pDC, CDC& dcMem, CBitmap& bmMem, CRect rect) +{ + dcMem.CreateCompatibleDC(pDC); + dcMem.SetBkColor(pDC->GetBkColor()); + dcMem.SetTextColor(pDC->GetTextColor()); + dcMem.SetBkMode(pDC->GetBkMode()); + dcMem.SelectObject(pDC->GetCurrentFont()); + + bmMem.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); + dcMem.SelectObject(&bmMem); + dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect.left, rect.top, SRCCOPY); +} + +void CMPCThemeUtil::flushMemDC(CDC* pDC, CDC& dcMem, CRect rect) +{ + pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); +} + + +void CMPCThemeUtil::DrawBufferedText(CDC* pDC, CString text, CRect rect, UINT format) +{ + CDC dcMem; + dcMem.CreateCompatibleDC(pDC); + dcMem.SetBkColor(pDC->GetBkColor()); + dcMem.SetTextColor(pDC->GetTextColor()); + dcMem.SetBkMode(pDC->GetBkMode()); + dcMem.SelectObject(pDC->GetCurrentFont()); + + CBitmap bmMem; + bmMem.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); + dcMem.SelectObject(&bmMem); + dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect.left, rect.top, SRCCOPY); + + CRect tr = rect; + tr.OffsetRect(-tr.left, -tr.top); + dcMem.DrawTextW(text, tr, format); + + pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); +} + +void CMPCThemeUtil::Draw2BitTransparent(CDC& dc, int left, int top, int width, int height, CBitmap& bmp, COLORREF fgColor) +{ + COLORREF crOldTextColor = dc.GetTextColor(); + COLORREF crOldBkColor = dc.GetBkColor(); + + CDC dcBMP; + dcBMP.CreateCompatibleDC(&dc); + + dcBMP.SelectObject(bmp); + dc.BitBlt(left, top, width, height, &dcBMP, 0, 0, SRCINVERT); //SRCINVERT works to create mask from 2-bit image. same result as bitblt with text=0 and bk=0xffffff + dc.SetBkColor(fgColor); //paint: foreground color (1 in 2 bit) + dc.SetTextColor(RGB(0, 0, 0)); //paint: black where transparent + dc.BitBlt(left, top, width, height, &dcBMP, 0, 0, SRCPAINT); + + dc.SetTextColor(crOldTextColor); + dc.SetBkColor(crOldBkColor); +} + +#if 0 +void CMPCThemeUtil::dbg(CString text, ...) +{ + va_list args; + va_start(args, text); + CString output; + output.FormatV(text, args); + OutputDebugString(output); + OutputDebugString(_T("\n")); + va_end(args); +} +#endif + +float CMPCThemeUtil::getConstantFByDPI(CWnd* window, const float* constants) +{ + int index; + DpiHelper dpiWindow; + dpiWindow.Override(window->GetSafeHwnd()); + int dpi = dpiWindow.DPIX(); + + if (dpi < 120) { + index = 0; + } else if (dpi < 144) { + index = 1; + } else if (dpi < 168) { + index = 2; + } else if (dpi < 192) { + index = 3; + } else { + index = 4; + } + + return constants[index]; +} + +int CMPCThemeUtil::getConstantByDPI(CWnd* window, const int* constants) +{ + int index; + DpiHelper dpiWindow; + dpiWindow.Override(window->GetSafeHwnd()); + int dpi = dpiWindow.DPIX(); + + if (dpi < 120) { + index = 0; + } else if (dpi < 144) { + index = 1; + } else if (dpi < 168) { + index = 2; + } else if (dpi < 192) { + index = 3; + } else { + index = 4; + } + + return constants[index]; +} + +UINT CMPCThemeUtil::getResourceByDPI(CWnd* window, CDC* pDC, const UINT* resources) +{ + int index; + //int dpi = pDC->GetDeviceCaps(LOGPIXELSX); + DpiHelper dpiWindow; + dpiWindow.Override(window->GetSafeHwnd()); + int dpi = dpiWindow.DPIX(); + + if (dpi < 120) { + index = 0; + } else if (dpi < 144) { + index = 1; + } else if (dpi < 168) { + index = 2; + } else if (dpi < 192) { + index = 3; + } else { + index = 4; + } + + return resources[index]; +} + +const std::vector CMPCThemeUtil::getIconPathByDPI(CWnd* wnd, WPARAM buttonType) { + DpiHelper dpiWindow; + dpiWindow.Override(wnd->GetSafeHwnd()); + + int dpi = dpiWindow.DPIX(); + switch (buttonType) { + case SC_MINIMIZE: + if (dpi < 120) { + return CMPCTheme::minimizeIcon96; + } else if (dpi < 144) { + return CMPCTheme::minimizeIcon120; + } else if (dpi < 168) { + return CMPCTheme::minimizeIcon144; + } else if (dpi < 192) { + return CMPCTheme::minimizeIcon168; + } else { + return CMPCTheme::minimizeIcon192; + } + case SC_RESTORE: + if (dpi < 120) { + return CMPCTheme::restoreIcon96; + } else if (dpi < 144) { + return CMPCTheme::restoreIcon120; + } else if (dpi < 168) { + return CMPCTheme::restoreIcon144; + } else if (dpi < 192) { + return CMPCTheme::restoreIcon168; + } else { + return CMPCTheme::restoreIcon192; + } + case SC_MAXIMIZE: + if (dpi < 120) { + return CMPCTheme::maximizeIcon96; + } else if (dpi < 144) { + return CMPCTheme::maximizeIcon120; + } else if (dpi < 168) { + return CMPCTheme::maximizeIcon144; + } else if (dpi < 192) { + return CMPCTheme::maximizeIcon168; + } else { + return CMPCTheme::maximizeIcon192; + } + case TOOLBAR_HIDE_ICON: + if (dpi < 120) { + return CMPCTheme::hideIcon96; + } else if (dpi < 144) { + return CMPCTheme::hideIcon120; + } else if (dpi < 168) { + return CMPCTheme::hideIcon144; + } else if (dpi < 192) { + return CMPCTheme::hideIcon168; + } else { + return CMPCTheme::hideIcon192; + } + case SC_CLOSE: + default: + if (dpi < 120) { + return CMPCTheme::closeIcon96; + } else if (dpi < 144) { + return CMPCTheme::closeIcon120; + } else if (dpi < 168) { + return CMPCTheme::closeIcon144; + } else if (dpi < 192) { + return CMPCTheme::closeIcon168; + } else { + return CMPCTheme::closeIcon192; + } + } +} + +//MapDialogRect deficiencies: +// 1. Caches results for windows even after they receive a DPI change +// 2. for templateless dialogs (e.g., MessageBoxDialog.cpp), the caching requires a reboot to fix +// 3. Does not honor selected font +// 4. For PropSheet, always uses "MS Shell Dlg" no matter what the sheet has selected in the .rc +void CMPCThemeUtil::MapDialogRect2(CDialog* wnd, CRect& r) { + CDC* pDC; + if (wnd && (pDC = wnd->GetDC())) { + CFont msgFont; + if (!getFontByType(msgFont, wnd, CMPCThemeUtil::MessageFont)) { + //if (!getFontByFace(msgFont, wnd, L"MS Shell Dlg", 9)){ + return; + } + + CFont* oldFont = pDC->SelectObject(&msgFont); + + //average character dimensions: https://web.archive.org/web/20131208002908/http://support.microsoft.com/kb/125681 + TEXTMETRICW tm; + SIZE size; + pDC->GetTextMetricsW(&tm); + GetTextExtentPoint32W(pDC->GetSafeHdc(), L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size); + pDC->SelectObject(oldFont); + int avgWidth = (size.cx / 26 + 1) / 2; + int avgHeight = (WORD)tm.tmHeight; + + //MapDialogRect definition: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapdialogrect + r.left = MulDiv(r.left, avgWidth, 4); + r.right = MulDiv(r.right, avgWidth, 4); + r.top = MulDiv(r.top, avgHeight, 8); + r.bottom = MulDiv(r.bottom, avgHeight, 8); + } +} + +const std::vector CMPCThemeUtil::getIconPathByDPI(CMPCThemeTitleBarControlButton* button) +{ + return getIconPathByDPI(button, button->getButtonType()); +} + +void CMPCThemeUtil::drawToolbarHideButton(CDC* pDC, CWnd* window, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias, bool hover) { + int iconWidth = CMPCThemeUtil::getConstantByDPI(window, CMPCTheme::ToolbarIconPathDimension); + int iconHeight = iconWidth; + float penThickness = 1; + CPoint ul(iconRect.left + (iconRect.Width() - iconWidth) / 2, iconRect.top + (iconRect.Height() - iconHeight) / 2); + CRect pathRect = { + ul.x, + ul.y, + ul.x + iconWidth, + ul.y + iconHeight + }; + + Gdiplus::Graphics gfx(pDC->m_hDC); + if (antiAlias) { + gfx.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias8x8); + } + Gdiplus::Color lineClr; + + if (hover) { //draw like a win10 icon + lineClr.SetFromCOLORREF(CMPCTheme::W10DarkThemeTitlebarIconPenColor); + } else { //draw in fg color as there is no button bg + lineClr.SetFromCOLORREF(CMPCTheme::TextFGColor); + } + Gdiplus::Pen iPen(lineClr, penThickness); + if (penThickness >= 2) { + iPen.SetLineCap(Gdiplus::LineCapSquare, Gdiplus::LineCapSquare, Gdiplus::DashCapFlat); + } + Gdiplus::REAL lastX = 0, lastY = 0; + for (u_int i = 0; i < icon.size(); i++) { + CMPCTheme::pathPoint p = icon[i]; + Gdiplus::REAL x = (Gdiplus::REAL)(pathRect.left + p.x); + Gdiplus::REAL y = (Gdiplus::REAL)(pathRect.top + p.y); + if (p.state == CMPCTheme::newPath) { + lastX = x; + lastY = y; + } else if ((p.state == CMPCTheme::linePath || p.state == CMPCTheme::closePath) && i > 0) { + gfx.DrawLine(&iPen, lastX, lastY, x, y); + if (antiAlias && penThickness < 2) { + gfx.DrawLine(&iPen, lastX, lastY, x, y); //draw again to brighten the AA diagonals + } + lastX = x; + lastY = y; + } + } +} + +void CMPCThemeUtil::drawGripper(CWnd* window, CWnd* dpiRefWnd, CRect rectGripper, CDC* pDC, bool rot90) { + CPngImage image; + image.Load(getResourceByDPI(dpiRefWnd, pDC, CMPCTheme::ThemeGrippers), AfxGetInstanceHandle()); + CImage gripperTemplate, gripperColorized; + gripperTemplate.Attach((HBITMAP)image.Detach()); + ImageGrayer::Colorize(gripperTemplate, gripperColorized, CMPCTheme::GripperPatternColor, CMPCTheme::WindowBGColor, rot90); + + CDC mDC; + mDC.CreateCompatibleDC(pDC); + mDC.SelectObject(gripperColorized); + + CDC dcMem; + CBitmap bmMem; + initMemDC(pDC, dcMem, bmMem, rectGripper); + if (rot90) { + for (int a = 0; a < rectGripper.Height(); a += gripperColorized.GetHeight()) { + dcMem.BitBlt(0, a, gripperColorized.GetWidth(), gripperColorized.GetHeight(), &mDC, 0, 0, SRCCOPY); + } + } else { + for (int a = 0; a < rectGripper.Width(); a += gripperColorized.GetWidth()) { + dcMem.BitBlt(a, 0, gripperColorized.GetWidth(), gripperColorized.GetHeight(), &mDC, 0, 0, SRCCOPY); + } + } + flushMemDC(pDC, dcMem, rectGripper); +} + + +void CMPCThemeUtil::drawCheckBox(CWnd* window, UINT checkState, bool isHover, bool useSystemSize, CRect rectCheck, CDC* pDC, bool isRadio) +{ + COLORREF borderClr, bgClr; + COLORREF oldBkClr = pDC->GetBkColor(), oldTextClr = pDC->GetTextColor(); + if (isHover) { + borderClr = CMPCTheme::CheckboxBorderHoverColor; + bgClr = CMPCTheme::CheckboxBGHoverColor; + } else { + borderClr = CMPCTheme::CheckboxBorderColor; + bgClr = CMPCTheme::CheckboxBGColor; + } + + if (useSystemSize) { + CPngImage image; + image.Load(getResourceByDPI(window, pDC, isRadio ? CMPCTheme::ThemeRadios : CMPCTheme::ThemeCheckBoxes), AfxGetInstanceHandle()); + BITMAP bm; + image.GetBitmap(&bm); + int size = bm.bmHeight; + + CDC mDC; + mDC.CreateCompatibleDC(pDC); + mDC.SelectObject(image); + int index; + if (isRadio) { + index = RadioRegular; + if (checkState) { + index += 1; + } + if (isHover) { + index += 2; + } + } else { + index = CheckBoxRegular; + if (isHover) { + index += 1; + } + } + CRect drawRect(0, 0, size, size); + //drawRect.OffsetRect(rectCheck.left + (rectCheck.Width() - size) / 2, rectCheck.top + (rectCheck.Height() - size) / 2); + drawRect.OffsetRect(rectCheck.left, rectCheck.top + (rectCheck.Height() - size) / 2); + + if (!isRadio && checkState != BST_CHECKED) { //we can draw this w/o BMPs + CBrush brush(borderClr); + pDC->FrameRect(drawRect, &brush); + drawRect.DeflateRect(1, 1); + pDC->FillSolidRect(drawRect, bgClr); + if (checkState == BST_INDETERMINATE) { + drawRect.DeflateRect(2, 2); + pDC->FillSolidRect(drawRect, CMPCTheme::CheckColor); + } + } else { + int left = index * size; + pDC->BitBlt(drawRect.left, drawRect.top, drawRect.Width(), drawRect.Height(), &mDC, left, 0, SRCCOPY); + } + } else { + CBrush brush(borderClr); + pDC->FrameRect(rectCheck, &brush); + rectCheck.DeflateRect(1, 1); + pDC->FillSolidRect(rectCheck, bgClr); + if (BST_CHECKED == checkState) { + CBitmap checkBMP; + CDC dcCheckBMP; + dcCheckBMP.CreateCompatibleDC(pDC); + + int left, top, width, height; + width = CMPCTheme::CheckWidth; + height = CMPCTheme::CheckHeight; + left = rectCheck.left + (rectCheck.Width() - width) / 2; + top = rectCheck.top + (rectCheck.Height() - height) / 2; + checkBMP.CreateBitmap(width, height, 1, 1, CMPCTheme::CheckBits); + dcCheckBMP.SelectObject(&checkBMP); + + pDC->SetBkColor(CMPCTheme::CheckColor); + pDC->SetTextColor(bgClr); + pDC->BitBlt(left, top, width, height, &dcCheckBMP, 0, 0, SRCCOPY); + } else if (BST_INDETERMINATE == checkState) { + rectCheck.DeflateRect(2, 2); + pDC->FillSolidRect(rectCheck, CMPCTheme::CheckColor); + } + } + pDC->SetBkColor(oldBkClr); + pDC->SetTextColor(oldTextClr); +} + +bool CMPCThemeUtil::canUseWin10DarkTheme() +{ + if (AppNeedsThemedControls()) { + // return false; //FIXME. return false to test behavior for OS < Win10 1809 + RTL_OSVERSIONINFOW osvi = GetRealOSVersion(); + bool ret = (osvi.dwMajorVersion = 10 && osvi.dwMajorVersion >= 0 && osvi.dwBuildNumber >= 17763); //dark theme first available in win 10 1809 + return ret; + } + return false; +} + +UINT CMPCThemeUtil::defaultLogo() +{ + return IDF_LOGO4; +} + +struct AFX_CTLCOLOR { + HWND hWnd; + HDC hDC; + UINT nCtlType; +}; + +HBRUSH CMPCThemeUtil::getParentDialogBGClr(CWnd* wnd, CDC* pDC) { + WPARAM w = (WPARAM)pDC; + AFX_CTLCOLOR ctl; + ctl.hWnd = wnd->GetSafeHwnd(); + ctl.nCtlType = CTLCOLOR_DLG; + ctl.hDC = pDC->GetSafeHdc(); + CWnd* parent = wnd->GetParent(); + if (nullptr == parent) { + parent = wnd; + } + HBRUSH bg = (HBRUSH)parent->SendMessage(WM_CTLCOLORDLG, w, (LPARAM)&ctl); + return bg; +} + +void CMPCThemeUtil::drawParentDialogBGClr(CWnd* wnd, CDC* pDC, CRect r, bool fill) +{ + CBrush brush; + HBRUSH bg = getParentDialogBGClr(wnd, pDC); + brush.Attach(bg); + if (fill) { + pDC->FillRect(r, &brush); + } else { + pDC->FrameRect(r, &brush); + } + brush.Detach(); +} + +void CMPCThemeUtil::fulfillThemeReqs(CProgressCtrl* ctl) +{ + if (AppIsThemeLoaded()) { + SetWindowTheme(ctl->GetSafeHwnd(), _T(""), _T("")); + ctl->SetBarColor(CMPCTheme::ProgressBarColor); + ctl->SetBkColor(CMPCTheme::ProgressBarBGColor); + } + ctl->UpdateWindow(); +} + +void CMPCThemeUtil::enableWindows10DarkFrame(CWnd* window) +{ + if (canUseWin10DarkTheme()) { + HMODULE hUser = GetModuleHandleA("user32.dll"); + if (hUser) { + pfnSetWindowCompositionAttribute setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(hUser, "SetWindowCompositionAttribute"); + if (setWindowCompositionAttribute) { + ACCENT_POLICY accent = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 }; + WINDOWCOMPOSITIONATTRIBDATA data; + data.Attrib = WCA_USEDARKMODECOLORS; + data.pvData = &accent; + data.cbData = sizeof(accent); + setWindowCompositionAttribute(window->GetSafeHwnd(), &data); + } + } + } +} + +int CALLBACK PropSheetCallBackRTL(HWND hWnd, UINT message, LPARAM lParam) { + switch (message) { + case PSCB_PRECREATE: + { + //arabic or hebrew + if (Translations::IsLangRTL(AfxGetAppSettings().language)) { + LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam; + lpTemplate->dwExtendedStyle |= WS_EX_LAYOUTRTL; + } + } + break; + } + return 0; +} + +void CMPCThemeUtil::PreDoModalRTL(LPPROPSHEETHEADERW m_psh) { + //see RTLWindowsLayoutCbtFilterHook and Translations::SetLanguage. + //We handle here to avoid Windows 11 bug with SetWindowLongPtr + m_psh->dwFlags |= PSH_USECALLBACK; + m_psh->pfnCallback = PropSheetCallBackRTL; +} + +//Regions are relative to upper left of WINDOW rect (not client) +CPoint CMPCThemeUtil::GetRegionOffset(CWnd* window) { + CRect twr, tcr; + window->GetWindowRect(twr); + window->GetClientRect(tcr); + ::MapWindowPoints(window->GetSafeHwnd(), nullptr, (LPPOINT)&tcr, 2); + CPoint offset = tcr.TopLeft() - twr.TopLeft(); + return offset; +} + +void CMPCThemeUtil::AdjustDynamicWidgetPair(CWnd* window, int leftWidget, int rightWidget, WidgetPairType lType, WidgetPairType rType) { + if (window && IsWindow(window->m_hWnd)) { + DpiHelper dpiWindow; + dpiWindow.Override(window->GetSafeHwnd()); + LONG dynamicSpace = dpiWindow.ScaleX(5); + + + + CWnd* leftW = window->GetDlgItem(leftWidget); + CWnd* rightW = window->GetDlgItem(rightWidget); + + WidgetPairType ll = lType; + WidgetPairType rr = rType; + + if (true || lType == WidgetPairAuto) { + LRESULT lRes = leftW->SendMessage(WM_GETDLGCODE, 0, 0); + DWORD buttonType = (leftW->GetStyle() & BS_TYPEMASK); + + if (DLGC_BUTTON == (lRes & DLGC_BUTTON) && (buttonType == BS_CHECKBOX || buttonType == BS_AUTOCHECKBOX)) { + lType = WidgetPairCheckBox; + } else { //we only support checkbox or text on the left, just assume it's text now + lType = WidgetPairText; + } + } + + if (true || rType == WidgetPairAuto) { + TCHAR windowClass[MAX_PATH]; + ::GetClassName(rightW->GetSafeHwnd(), windowClass, _countof(windowClass)); + + if (0 == _tcsicmp(windowClass, WC_COMBOBOX)) { + rType = WidgetPairCombo; + } else { //we only support combo or edit on the right, just assume it's edit now + rType = WidgetPairEdit; + } + } + + if (leftW && rightW && IsWindow(leftW->m_hWnd) && IsWindow(rightW->m_hWnd)) { + CRect l, r; + LONG leftWantsRight, rightWantsLeft; + + leftW->GetWindowRect(l); + leftW->GetOwner()->ScreenToClient(l); + rightW->GetWindowRect(r); + rightW->GetOwner()->ScreenToClient(r); + CDC* lpDC = leftW->GetDC(); + CFont* pFont = leftW->GetFont(); + leftWantsRight = l.right; + rightWantsLeft = r.left; + { + int left = l.left; + if (lType == WidgetPairCheckBox) { + left += dpiWindow.GetSystemMetricsDPI(SM_CXMENUCHECK) + 2; + } + + CFont* pOldFont = lpDC->SelectObject(pFont); + TEXTMETRIC tm; + lpDC->GetTextMetricsW(&tm); + + CString str; + leftW->GetWindowTextW(str); + CSize szText = lpDC->GetTextExtent(str); + lpDC->SelectObject(pOldFont); + + leftWantsRight = left + szText.cx + tm.tmAveCharWidth; + leftW->ReleaseDC(lpDC); + } + + { + if (rType == WidgetPairCombo) { + //int wantWidth = (int)::SendMessage(rightW->m_hWnd, CB_GETDROPPEDWIDTH, 0, 0); + CComboBox *cb = DYNAMIC_DOWNCAST(CComboBox, rightW); + if (cb) { + int wantWidth = CorrectComboListWidth(*cb); + if (wantWidth != CB_ERR) { + rightWantsLeft = r.right - wantWidth - GetSystemMetrics(SM_CXVSCROLL); + } + } + } + } + CRect cl = l, cr = r; + if (leftWantsRight > rightWantsLeft - dynamicSpace //overlaps; we will assume defaults are best + || (leftWantsRight < l.right && rightWantsLeft > r.left) // there is no need to resize + || (lType == WidgetPairText && DT_RIGHT == (leftW->GetStyle() & DT_RIGHT)) ) //right aligned text not supported, as the right edge is fixed + { + //do nothing + } else { + l.right = leftWantsRight; + //if necessary space would shrink the right widget, instead get as close to original size as possible + //this minimizes noticeable layout changes + r.left = std::min(rightWantsLeft, std::max(l.right + dynamicSpace, r.left)); + } + if ((lType == WidgetPairText || lType == WidgetPairCheckBox) && (rType == WidgetPairCombo || rType == WidgetPairEdit)) { + l.top = r.top; + l.bottom += r.Height() - l.Height(); + leftW->ModifyStyle(0, SS_CENTERIMAGE); + } + + if (l != cl) { + leftW->MoveWindow(l); + } + if (r != cr) { + rightW->MoveWindow(r); + } + } + } +} + +void CMPCThemeUtil::UpdateAnalogCaptureDeviceSlider(CScrollBar* pScrollBar) { + if (pScrollBar && ::IsWindow(pScrollBar->m_hWnd)) { + if (CSliderCtrl* slider = DYNAMIC_DOWNCAST(CSliderCtrl, pScrollBar)) { + slider->SendMessage(WM_KEYUP, VK_LEFT, 1); //does not move the slider, only forces current position to be registered + } + } +} + +bool CMPCThemeUtil::IsWindowVisibleAndRendered(CWnd* window) { + if (!window || !IsWindow(window->m_hWnd) || !window->IsWindowVisible()) { + return false; + } else { + CRect r; + HDC hdc = GetWindowDC(window->m_hWnd); + GetClipBox(hdc, &r); + if (r.IsRectEmpty()) { + return false; + } + } + return true; +} diff --git a/src/mpc-hc/CMPCThemeUtil.h b/src/mpc-hc/CMPCThemeUtil.h index ae83776a717..cfd45d5fe1a 100644 --- a/src/mpc-hc/CMPCThemeUtil.h +++ b/src/mpc-hc/CMPCThemeUtil.h @@ -1,135 +1,135 @@ -#pragma once -#include -#include -#include -#include -#include "CMPCTheme.h" -#include "CMPCThemeToolTipCtrl.h" - -#define TOOLBAR_HIDE_ICON 0xF900 - -class CMPCThemeTitleBarControlButton; -int CALLBACK PropSheetCallBackRTL(HWND hWnd, UINT message, LPARAM lParam); - -class CMPCThemeUtil -{ -public: - enum SpecialThemeCases { - NoSpecialCase = 0, - ExternalPropertyPageWithDefaultButton, - ExternalPropertyPageWithAnalogCaptureSliders, - ToolbarCustomizeDialog - }; - - enum WidgetPairType { - WidgetPairAuto = 0 - , WidgetPairCheckBox - , WidgetPairCombo - , WidgetPairText - , WidgetPairEdit - }; - - CMPCThemeUtil(); - virtual ~CMPCThemeUtil(); - - static bool ModifyTemplates(CPropertySheet* sheet, CRuntimeClass* pageClass, DWORD id, DWORD addStyle, DWORD removeStyle = 0); - - - static HBRUSH getCtlColorFileDialog(HDC hDC, UINT nCtlColor); - static HBRUSH getCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - static bool MPCThemeEraseBkgnd(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - - enum FileDialogWidgetSearch { - RecurseSinkWidgets - ,ThemeAllChildren - ,ProminentControlIDWidget - }; - - HWND themableDialogHandle = nullptr; - void enableFileDialogHook(); - void subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType); - void subClassFileDialog(CWnd* wnd); - void subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass); - void redrawAllThemedWidgets(); - void subClassTBCustomizeDialog(CWnd* wnd, CToolBar* tb); -protected: - int dialogProminentControlStringID = 0; - - static CBrush contentBrush, windowBrush, controlAreaBrush, W10DarkThemeFileDialogInjectedBGBrush; - static NONCLIENTMETRICS nonClientMetrics; - std::vector allocatedWindows; - - void fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase, CWnd* otherWindow = nullptr); - static void initHelperObjects(); - void makeThemed(CWnd* pObject, CWnd* tChild); - - //replaces tooltip from EnableTooltips() - CMPCThemeToolTipCtrl themedDialogToolTip; - CDialog* themedDialogToolTipParent; - void EnableThemedDialogTooltips(CDialog* wnd); - void PlaceThemedDialogTooltip(UINT_PTR nID); - void RelayThemedDialogTooltip(MSG* pMsg); - void RedrawDialogTooltipIfVisible(); - static bool metricsNeedCalculation; -public: - static bool getFontByFace(CFont& font, CWnd *wnd, wchar_t* fontName, int size, LONG weight = FW_REGULAR); - static bool getFixedFont(CFont& font, CDC* pDC, CWnd* wnd); - static bool getFontByType(CFont& font, CWnd* wnd, int type, bool underline = false, bool bold = false); - enum fontType { - CaptionFont, - SmallCaptionFont, - MenuFont, - StatusFont, - MessageFont, - DialogFont, - }; - - static CSize GetTextSize(CString str, HDC hDC, CFont* font); - static CSize GetTextSize(CString str, CDC* pDC, CFont* font); - static CSize GetTextSize(CString str, HDC hDC, CWnd* wnd, int type); - static CSize GetTextSizeDiff(CString str, HDC hDC, CWnd* wnd, int type, CFont* curFont); - - - static void GetMetrics(bool reset = false); - static void initMemDC(CDC* pDC, CDC& dcMem, CBitmap& bmMem, CRect rect); - static void flushMemDC(CDC* pDC, CDC& dcMem, CRect rect); - static void DrawBufferedText(CDC* pDC, CString text, CRect rect, UINT format); - static void Draw2BitTransparent(CDC& dc, int left, int top, int width, int height, CBitmap& bmp, COLORREF fgColor); - static void dbg(CString text, ...); - static float getConstantFByDPI(CWnd* window, const float* constants); - static int getConstantByDPI(CWnd* window, const int* constants); - static UINT getResourceByDPI(CWnd* window, CDC* pDC, const UINT* resources); - static void MapDialogRect2(CDialog* wnd, CRect& r); - static const std::vector getIconPathByDPI(CMPCThemeTitleBarControlButton* button); - static const std::vector getIconPathByDPI(CWnd* wnd, WPARAM buttonType); - static void drawCheckBox(CWnd* window, UINT checkState, bool isHover, bool useSystemSize, CRect rectCheck, CDC* pDC, bool isRadio = false); - static void drawGripper(CWnd* window, CWnd* dpiRefWnd, CRect rectGripper, CDC* pDC, bool rot90); - static void drawToolbarHideButton(CDC* pDC, CWnd* window, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias, bool hover); - static bool canUseWin10DarkTheme(); - static UINT defaultLogo(); - static HBRUSH getParentDialogBGClr(CWnd* wnd, CDC* pDC); - static void drawParentDialogBGClr(CWnd* wnd, CDC* pDC, CRect r, bool fill = true); - static void fulfillThemeReqs(CProgressCtrl* ctl); - static void enableWindows10DarkFrame(CWnd* window); - static void AdjustDynamicWidgetPair(CWnd* window, int left, int right, WidgetPairType lType = WidgetPairAuto, WidgetPairType rType = WidgetPairAuto); - static void UpdateAnalogCaptureDeviceSlider(CScrollBar* pScrollBar); - static bool IsWindowVisibleAndRendered(CWnd* window); - - void PreDoModalRTL(LPPROPSHEETHEADERW m_psh); - - static CPoint GetRegionOffset(CWnd* window); - - enum CheckBoxStyle { - CheckBoxRegular = 0, - CheckBoxHover = 1, - }; - - enum RadioStyle { - RadioRegular = 0, - RadioRegularSet = 1, - RadioHover = 2, - RadioHoverSet = 3 - }; -}; - - +#pragma once +#include +#include +#include +#include +#include "CMPCTheme.h" +#include "CMPCThemeToolTipCtrl.h" + +#define TOOLBAR_HIDE_ICON 0xF900 + +class CMPCThemeTitleBarControlButton; +int CALLBACK PropSheetCallBackRTL(HWND hWnd, UINT message, LPARAM lParam); + +class CMPCThemeUtil +{ +public: + enum SpecialThemeCases { + NoSpecialCase = 0, + ExternalPropertyPageWithDefaultButton, + ExternalPropertyPageWithAnalogCaptureSliders, + ToolbarCustomizeDialog + }; + + enum WidgetPairType { + WidgetPairAuto = 0 + , WidgetPairCheckBox + , WidgetPairCombo + , WidgetPairText + , WidgetPairEdit + }; + + CMPCThemeUtil(); + virtual ~CMPCThemeUtil(); + + static bool ModifyTemplates(CPropertySheet* sheet, CRuntimeClass* pageClass, DWORD id, DWORD addStyle, DWORD removeStyle = 0); + + + static HBRUSH getCtlColorFileDialog(HDC hDC, UINT nCtlColor); + static HBRUSH getCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + static bool MPCThemeEraseBkgnd(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + + enum FileDialogWidgetSearch { + RecurseSinkWidgets + ,ThemeAllChildren + ,ProminentControlIDWidget + }; + + HWND themableDialogHandle = nullptr; + void enableFileDialogHook(); + void subClassFileDialogRecurse(CWnd* wnd, HWND hWnd, FileDialogWidgetSearch searchType); + void subClassFileDialog(CWnd* wnd); + void subClassFileDialogWidgets(HWND widget, HWND parent, wchar_t* childWindowClass); + void redrawAllThemedWidgets(); + void subClassTBCustomizeDialog(CWnd* wnd, CToolBar* tb); +protected: + int dialogProminentControlStringID = 0; + + static CBrush contentBrush, windowBrush, controlAreaBrush, W10DarkThemeFileDialogInjectedBGBrush; + static NONCLIENTMETRICS nonClientMetrics; + std::vector allocatedWindows; + + void fulfillThemeReqs(CWnd* wnd, SpecialThemeCases specialCase = SpecialThemeCases::NoSpecialCase, CWnd* otherWindow = nullptr); + static void initHelperObjects(); + void makeThemed(CWnd* pObject, CWnd* tChild); + + //replaces tooltip from EnableTooltips() + CMPCThemeToolTipCtrl themedDialogToolTip; + CDialog* themedDialogToolTipParent; + void EnableThemedDialogTooltips(CDialog* wnd); + void PlaceThemedDialogTooltip(UINT_PTR nID); + void RelayThemedDialogTooltip(MSG* pMsg); + void RedrawDialogTooltipIfVisible(); + static bool metricsNeedCalculation; +public: + static bool getFontByFace(CFont& font, CWnd *wnd, wchar_t* fontName, int size, LONG weight = FW_REGULAR); + static bool getFixedFont(CFont& font, CDC* pDC, CWnd* wnd); + static bool getFontByType(CFont& font, CWnd* wnd, int type, bool underline = false, bool bold = false); + enum fontType { + CaptionFont, + SmallCaptionFont, + MenuFont, + StatusFont, + MessageFont, + DialogFont, + }; + + static CSize GetTextSize(CString str, HDC hDC, CFont* font); + static CSize GetTextSize(CString str, CDC* pDC, CFont* font); + static CSize GetTextSize(CString str, HDC hDC, CWnd* wnd, int type); + static CSize GetTextSizeDiff(CString str, HDC hDC, CWnd* wnd, int type, CFont* curFont); + + + static void GetMetrics(bool reset = false); + static void initMemDC(CDC* pDC, CDC& dcMem, CBitmap& bmMem, CRect rect); + static void flushMemDC(CDC* pDC, CDC& dcMem, CRect rect); + static void DrawBufferedText(CDC* pDC, CString text, CRect rect, UINT format); + static void Draw2BitTransparent(CDC& dc, int left, int top, int width, int height, CBitmap& bmp, COLORREF fgColor); + static void dbg(CString text, ...); + static float getConstantFByDPI(CWnd* window, const float* constants); + static int getConstantByDPI(CWnd* window, const int* constants); + static UINT getResourceByDPI(CWnd* window, CDC* pDC, const UINT* resources); + static void MapDialogRect2(CDialog* wnd, CRect& r); + static const std::vector getIconPathByDPI(CMPCThemeTitleBarControlButton* button); + static const std::vector getIconPathByDPI(CWnd* wnd, WPARAM buttonType); + static void drawCheckBox(CWnd* window, UINT checkState, bool isHover, bool useSystemSize, CRect rectCheck, CDC* pDC, bool isRadio = false); + static void drawGripper(CWnd* window, CWnd* dpiRefWnd, CRect rectGripper, CDC* pDC, bool rot90); + static void drawToolbarHideButton(CDC* pDC, CWnd* window, CRect iconRect, std::vector icon, double dpiScaling, bool antiAlias, bool hover); + static bool canUseWin10DarkTheme(); + static UINT defaultLogo(); + static HBRUSH getParentDialogBGClr(CWnd* wnd, CDC* pDC); + static void drawParentDialogBGClr(CWnd* wnd, CDC* pDC, CRect r, bool fill = true); + static void fulfillThemeReqs(CProgressCtrl* ctl); + static void enableWindows10DarkFrame(CWnd* window); + static void AdjustDynamicWidgetPair(CWnd* window, int left, int right, WidgetPairType lType = WidgetPairAuto, WidgetPairType rType = WidgetPairAuto); + static void UpdateAnalogCaptureDeviceSlider(CScrollBar* pScrollBar); + static bool IsWindowVisibleAndRendered(CWnd* window); + + void PreDoModalRTL(LPPROPSHEETHEADERW m_psh); + + static CPoint GetRegionOffset(CWnd* window); + + enum CheckBoxStyle { + CheckBoxRegular = 0, + CheckBoxHover = 1, + }; + + enum RadioStyle { + RadioRegular = 0, + RadioRegularSet = 1, + RadioHover = 2, + RadioHoverSet = 3 + }; +}; + + diff --git a/src/mpc-hc/CMPCThemeWin10Api.h b/src/mpc-hc/CMPCThemeWin10Api.h index bc8f008835b..6a925ef9ae3 100644 --- a/src/mpc-hc/CMPCThemeWin10Api.h +++ b/src/mpc-hc/CMPCThemeWin10Api.h @@ -1,60 +1,60 @@ -#pragma once - -typedef enum _WINDOWCOMPOSITIONATTRIB { - WCA_UNDEFINED = 0, - WCA_NCRENDERING_ENABLED = 1, - WCA_NCRENDERING_POLICY = 2, - WCA_TRANSITIONS_FORCEDISABLED = 3, - WCA_ALLOW_NCPAINT = 4, - WCA_CAPTION_BUTTON_BOUNDS = 5, - WCA_NONCLIENT_RTL_LAYOUT = 6, - WCA_FORCE_ICONIC_REPRESENTATION = 7, - WCA_EXTENDED_FRAME_BOUNDS = 8, - WCA_HAS_ICONIC_BITMAP = 9, - WCA_THEME_ATTRIBUTES = 10, - WCA_NCRENDERING_EXILED = 11, - WCA_NCADORNMENTINFO = 12, - WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, - WCA_VIDEO_OVERLAY_ACTIVE = 14, - WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, - WCA_DISALLOW_PEEK = 16, - WCA_CLOAK = 17, - WCA_CLOAKED = 18, - WCA_ACCENT_POLICY = 19, - WCA_FREEZE_REPRESENTATION = 20, - WCA_EVER_UNCLOAKED = 21, - WCA_VISUAL_OWNER = 22, - WCA_HOLOGRAPHIC = 23, - WCA_EXCLUDED_FROM_DDA = 24, - WCA_PASSIVEUPDATEMODE = 25, - WCA_USEDARKMODECOLORS = 26, - WCA_LAST = 27 -} WINDOWCOMPOSITIONATTRIB; - -typedef struct _WINDOWCOMPOSITIONATTRIBDATA { - WINDOWCOMPOSITIONATTRIB Attrib; - PVOID pvData; - SIZE_T cbData; -} WINDOWCOMPOSITIONATTRIBDATA; - -typedef enum _ACCENT_STATE { - ACCENT_DISABLED = 0, - ACCENT_ENABLE_GRADIENT = 1, - ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, - ACCENT_ENABLE_BLURBEHIND = 3, - ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803 - ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809 - ACCENT_INVALID_STATE = 6 -} ACCENT_STATE; - -typedef struct _ACCENT_POLICY { - ACCENT_STATE AccentState; - DWORD AccentFlags; - DWORD GradientColor; - DWORD AnimationId; -} ACCENT_POLICY; - -typedef BOOL(WINAPI* pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); - -typedef BOOL(WINAPI* pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); - +#pragma once + +typedef enum _WINDOWCOMPOSITIONATTRIB { + WCA_UNDEFINED = 0, + WCA_NCRENDERING_ENABLED = 1, + WCA_NCRENDERING_POLICY = 2, + WCA_TRANSITIONS_FORCEDISABLED = 3, + WCA_ALLOW_NCPAINT = 4, + WCA_CAPTION_BUTTON_BOUNDS = 5, + WCA_NONCLIENT_RTL_LAYOUT = 6, + WCA_FORCE_ICONIC_REPRESENTATION = 7, + WCA_EXTENDED_FRAME_BOUNDS = 8, + WCA_HAS_ICONIC_BITMAP = 9, + WCA_THEME_ATTRIBUTES = 10, + WCA_NCRENDERING_EXILED = 11, + WCA_NCADORNMENTINFO = 12, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, + WCA_VIDEO_OVERLAY_ACTIVE = 14, + WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, + WCA_DISALLOW_PEEK = 16, + WCA_CLOAK = 17, + WCA_CLOAKED = 18, + WCA_ACCENT_POLICY = 19, + WCA_FREEZE_REPRESENTATION = 20, + WCA_EVER_UNCLOAKED = 21, + WCA_VISUAL_OWNER = 22, + WCA_HOLOGRAPHIC = 23, + WCA_EXCLUDED_FROM_DDA = 24, + WCA_PASSIVEUPDATEMODE = 25, + WCA_USEDARKMODECOLORS = 26, + WCA_LAST = 27 +} WINDOWCOMPOSITIONATTRIB; + +typedef struct _WINDOWCOMPOSITIONATTRIBDATA { + WINDOWCOMPOSITIONATTRIB Attrib; + PVOID pvData; + SIZE_T cbData; +} WINDOWCOMPOSITIONATTRIBDATA; + +typedef enum _ACCENT_STATE { + ACCENT_DISABLED = 0, + ACCENT_ENABLE_GRADIENT = 1, + ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, + ACCENT_ENABLE_BLURBEHIND = 3, + ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803 + ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809 + ACCENT_INVALID_STATE = 6 +} ACCENT_STATE; + +typedef struct _ACCENT_POLICY { + ACCENT_STATE AccentState; + DWORD AccentFlags; + DWORD GradientColor; + DWORD AnimationId; +} ACCENT_POLICY; + +typedef BOOL(WINAPI* pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); + +typedef BOOL(WINAPI* pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); + diff --git a/src/mpc-hc/CShockwaveFlash.cpp b/src/mpc-hc/CShockwaveFlash.cpp index aa1286d45e3..538799df1dc 100644 --- a/src/mpc-hc/CShockwaveFlash.cpp +++ b/src/mpc-hc/CShockwaveFlash.cpp @@ -1,29 +1,29 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "CShockwaveFlash.h" - - -///////////////////////////////////////////////////////////////////////////// -// CShockwaveFlash - -IMPLEMENT_DYNCREATE(CShockwaveFlash, CWnd) +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "CShockwaveFlash.h" + + +///////////////////////////////////////////////////////////////////////////// +// CShockwaveFlash + +IMPLEMENT_DYNCREATE(CShockwaveFlash, CWnd) diff --git a/src/mpc-hc/CShockwaveFlash.h b/src/mpc-hc/CShockwaveFlash.h index 4864542430b..ed89145c230 100644 --- a/src/mpc-hc/CShockwaveFlash.h +++ b/src/mpc-hc/CShockwaveFlash.h @@ -1,383 +1,383 @@ -/* - * (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 . - * - */ - -#pragma once - -///////////////////////////////////////////////////////////////////////////// -// CShockwaveFlash - -class CShockwaveFlash : public CWnd -{ -protected: - DECLARE_DYNCREATE(CShockwaveFlash) -public: - CLSID const& GetClsid() { - static CLSID const clsid - = { 0xD27CDB6E, 0xAE6D, 0x11CF, { 0x96, 0xB8, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } }; - return clsid; - } - virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, - const RECT& rect, CWnd* pParentWnd, UINT nID, - CCreateContext* pContext = nullptr) { - return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); - } - - BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, - UINT nID, CFile* pPersist = nullptr, BOOL bStorage = FALSE, - BSTR bstrLicKey = nullptr) { - return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID, - pPersist, bStorage, bstrLicKey); - } - - // Attributes -public: - - // Operations -public: - - long get_ReadyState() { - long result; - InvokeHelper(DISPID_READYSTATE, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - long get_TotalFrames() { - long result; - InvokeHelper(0x7c, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - BOOL get_Playing() { - BOOL result; - InvokeHelper(0x7d, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_Playing(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x7d, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_Quality() { - long result; - InvokeHelper(0x69, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_Quality(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x69, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_ScaleMode() { - long result; - InvokeHelper(0x78, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_ScaleMode(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x78, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_AlignMode() { - long result; - InvokeHelper(0x79, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_AlignMode(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x79, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_BackgroundColor() { - long result; - InvokeHelper(0x7b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_BackgroundColor(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x7b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - BOOL get_Loop() { - BOOL result; - InvokeHelper(0x6a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_Loop(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x6a, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_Movie() { - CString result; - InvokeHelper(0x66, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_Movie(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x66, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - long get_FrameNum() { - long result; - InvokeHelper(0x6b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); - return result; - } - void put_FrameNum(long newValue) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x6b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - void SetZoomRect(long left, long top, long right, long bottom) { - static BYTE parms[] = VTS_I4 VTS_I4 VTS_I4 VTS_I4; - InvokeHelper(0x6d, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, left, top, right, bottom); - } - void Zoom(long factor) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x76, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, factor); - } - void Pan(long x, long y, long mode) { - static BYTE parms[] = VTS_I4 VTS_I4 VTS_I4; - InvokeHelper(0x77, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, x, y, mode); - } - void Play() { - InvokeHelper(0x70, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void Stop() { - InvokeHelper(0x71, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void Back() { - InvokeHelper(0x72, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void Forward() { - InvokeHelper(0x73, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void Rewind() { - InvokeHelper(0x74, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void StopPlay() { - InvokeHelper(0x7e, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); - } - void GotoFrame(long FrameNum) { - static BYTE parms[] = VTS_I4; - InvokeHelper(0x7f, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, FrameNum); - } - long CurrentFrame() { - long result; - InvokeHelper(0x80, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); - return result; - } - BOOL IsPlaying() { - BOOL result; - InvokeHelper(0x81, DISPATCH_METHOD, VT_BOOL, (void*)&result, nullptr); - return result; - } - long PercentLoaded() { - long result; - InvokeHelper(0x82, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); - return result; - } - BOOL FrameLoaded(long FrameNum) { - BOOL result; - static BYTE parms[] = VTS_I4; - InvokeHelper(0x83, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms, FrameNum); - return result; - } - long FlashVersion() { - long result; - InvokeHelper(0x84, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); - return result; - } - CString get_WMode() { - CString result; - InvokeHelper(0x85, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_WMode(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x85, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_SAlign() { - CString result; - InvokeHelper(0x86, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_SAlign(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x86, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - BOOL get_Menu() { - BOOL result; - InvokeHelper(0x87, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_Menu(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x87, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_Base() { - CString result; - InvokeHelper(0x88, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_Base(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x88, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_Scale() { - CString result; - InvokeHelper(0x89, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_Scale(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x89, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - BOOL get_DeviceFont() { - BOOL result; - InvokeHelper(0x8a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_DeviceFont(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x8a, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - BOOL get_EmbedMovie() { - BOOL result; - InvokeHelper(0x8b, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); - return result; - } - void put_EmbedMovie(BOOL newValue) { - static BYTE parms[] = VTS_BOOL; - InvokeHelper(0x8b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_BGColor() { - CString result; - InvokeHelper(0x8c, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_BGColor(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x8c, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_Quality2() { - CString result; - InvokeHelper(0x8d, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_Quality2(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x8d, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - void LoadMovie(long layer, LPCTSTR url) { - static BYTE parms[] = VTS_I4 VTS_BSTR; - InvokeHelper(0x8e, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, layer, url); - } - void TGotoFrame(LPCTSTR target, long FrameNum) { - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0x8f, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, FrameNum); - } - void TGotoLabel(LPCTSTR target, LPCTSTR label) { - static BYTE parms[] = VTS_BSTR VTS_BSTR; - InvokeHelper(0x90, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, label); - } - long TCurrentFrame(LPCTSTR target) { - long result; - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x91, DISPATCH_METHOD, VT_I4, (void*)&result, parms, target); - return result; - } - CString TCurrentLabel(LPCTSTR target) { - CString result; - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x92, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, target); - return result; - } - void TPlay(LPCTSTR target) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x93, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target); - } - void TStopPlay(LPCTSTR target) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x94, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target); - } - void SetVariable(LPCTSTR name, LPCTSTR value) { - static BYTE parms[] = VTS_BSTR VTS_BSTR; - InvokeHelper(0x97, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, name, value); - } - CString GetVariable(LPCTSTR name) { - CString result; - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x98, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, name); - return result; - } - void TSetProperty(LPCTSTR target, long property, LPCTSTR value) { - static BYTE parms[] = VTS_BSTR VTS_I4 VTS_BSTR; - InvokeHelper(0x99, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, property, value); - } - CString TGetProperty(LPCTSTR target, long property) { - CString result; - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0x9a, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, target, property); - return result; - } - void TCallFrame(LPCTSTR target, long FrameNum) { - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0x9b, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, FrameNum); - } - void TCallLabel(LPCTSTR target, LPCTSTR label) { - static BYTE parms[] = VTS_BSTR VTS_BSTR; - InvokeHelper(0x9c, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, label); - } - void TSetPropertyNum(LPCTSTR target, long property, double value) { - static BYTE parms[] = VTS_BSTR VTS_I4 VTS_R8; - InvokeHelper(0x9d, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, property, value); - } - double TGetPropertyNum(LPCTSTR target, long property) { - double result; - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0x9e, DISPATCH_METHOD, VT_R8, (void*)&result, parms, target, property); - return result; - } - double TGetPropertyAsNumber(LPCTSTR target, long property) { - double result; - static BYTE parms[] = VTS_BSTR VTS_I4; - InvokeHelper(0xac, DISPATCH_METHOD, VT_R8, (void*)&result, parms, target, property); - return result; - } - CString get_SWRemote() { - CString result; - InvokeHelper(0x9f, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_SWRemote(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0x9f, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_FlashVars() { - CString result; - InvokeHelper(0xaa, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_FlashVars(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0xaa, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - CString get_AllowScriptAccess() { - CString result; - InvokeHelper(0xab, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); - return result; - } - void put_AllowScriptAccess(LPCTSTR newValue) { - static BYTE parms[] = VTS_BSTR; - InvokeHelper(0xab, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); - } - -}; +/* + * (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 . + * + */ + +#pragma once + +///////////////////////////////////////////////////////////////////////////// +// CShockwaveFlash + +class CShockwaveFlash : public CWnd +{ +protected: + DECLARE_DYNCREATE(CShockwaveFlash) +public: + CLSID const& GetClsid() { + static CLSID const clsid + = { 0xD27CDB6E, 0xAE6D, 0x11CF, { 0x96, 0xB8, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } }; + return clsid; + } + virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, UINT nID, + CCreateContext* pContext = nullptr) { + return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); + } + + BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, + UINT nID, CFile* pPersist = nullptr, BOOL bStorage = FALSE, + BSTR bstrLicKey = nullptr) { + return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID, + pPersist, bStorage, bstrLicKey); + } + + // Attributes +public: + + // Operations +public: + + long get_ReadyState() { + long result; + InvokeHelper(DISPID_READYSTATE, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + long get_TotalFrames() { + long result; + InvokeHelper(0x7c, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + BOOL get_Playing() { + BOOL result; + InvokeHelper(0x7d, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_Playing(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x7d, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_Quality() { + long result; + InvokeHelper(0x69, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_Quality(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x69, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_ScaleMode() { + long result; + InvokeHelper(0x78, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_ScaleMode(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x78, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_AlignMode() { + long result; + InvokeHelper(0x79, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_AlignMode(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x79, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_BackgroundColor() { + long result; + InvokeHelper(0x7b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_BackgroundColor(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x7b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + BOOL get_Loop() { + BOOL result; + InvokeHelper(0x6a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_Loop(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x6a, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_Movie() { + CString result; + InvokeHelper(0x66, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_Movie(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x66, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + long get_FrameNum() { + long result; + InvokeHelper(0x6b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, nullptr); + return result; + } + void put_FrameNum(long newValue) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x6b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + void SetZoomRect(long left, long top, long right, long bottom) { + static BYTE parms[] = VTS_I4 VTS_I4 VTS_I4 VTS_I4; + InvokeHelper(0x6d, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, left, top, right, bottom); + } + void Zoom(long factor) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x76, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, factor); + } + void Pan(long x, long y, long mode) { + static BYTE parms[] = VTS_I4 VTS_I4 VTS_I4; + InvokeHelper(0x77, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, x, y, mode); + } + void Play() { + InvokeHelper(0x70, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void Stop() { + InvokeHelper(0x71, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void Back() { + InvokeHelper(0x72, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void Forward() { + InvokeHelper(0x73, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void Rewind() { + InvokeHelper(0x74, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void StopPlay() { + InvokeHelper(0x7e, DISPATCH_METHOD, VT_EMPTY, nullptr, nullptr); + } + void GotoFrame(long FrameNum) { + static BYTE parms[] = VTS_I4; + InvokeHelper(0x7f, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, FrameNum); + } + long CurrentFrame() { + long result; + InvokeHelper(0x80, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); + return result; + } + BOOL IsPlaying() { + BOOL result; + InvokeHelper(0x81, DISPATCH_METHOD, VT_BOOL, (void*)&result, nullptr); + return result; + } + long PercentLoaded() { + long result; + InvokeHelper(0x82, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); + return result; + } + BOOL FrameLoaded(long FrameNum) { + BOOL result; + static BYTE parms[] = VTS_I4; + InvokeHelper(0x83, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms, FrameNum); + return result; + } + long FlashVersion() { + long result; + InvokeHelper(0x84, DISPATCH_METHOD, VT_I4, (void*)&result, nullptr); + return result; + } + CString get_WMode() { + CString result; + InvokeHelper(0x85, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_WMode(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x85, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_SAlign() { + CString result; + InvokeHelper(0x86, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_SAlign(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x86, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + BOOL get_Menu() { + BOOL result; + InvokeHelper(0x87, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_Menu(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x87, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_Base() { + CString result; + InvokeHelper(0x88, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_Base(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x88, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_Scale() { + CString result; + InvokeHelper(0x89, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_Scale(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x89, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + BOOL get_DeviceFont() { + BOOL result; + InvokeHelper(0x8a, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_DeviceFont(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x8a, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + BOOL get_EmbedMovie() { + BOOL result; + InvokeHelper(0x8b, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, nullptr); + return result; + } + void put_EmbedMovie(BOOL newValue) { + static BYTE parms[] = VTS_BOOL; + InvokeHelper(0x8b, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_BGColor() { + CString result; + InvokeHelper(0x8c, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_BGColor(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x8c, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_Quality2() { + CString result; + InvokeHelper(0x8d, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_Quality2(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x8d, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + void LoadMovie(long layer, LPCTSTR url) { + static BYTE parms[] = VTS_I4 VTS_BSTR; + InvokeHelper(0x8e, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, layer, url); + } + void TGotoFrame(LPCTSTR target, long FrameNum) { + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0x8f, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, FrameNum); + } + void TGotoLabel(LPCTSTR target, LPCTSTR label) { + static BYTE parms[] = VTS_BSTR VTS_BSTR; + InvokeHelper(0x90, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, label); + } + long TCurrentFrame(LPCTSTR target) { + long result; + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x91, DISPATCH_METHOD, VT_I4, (void*)&result, parms, target); + return result; + } + CString TCurrentLabel(LPCTSTR target) { + CString result; + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x92, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, target); + return result; + } + void TPlay(LPCTSTR target) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x93, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target); + } + void TStopPlay(LPCTSTR target) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x94, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target); + } + void SetVariable(LPCTSTR name, LPCTSTR value) { + static BYTE parms[] = VTS_BSTR VTS_BSTR; + InvokeHelper(0x97, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, name, value); + } + CString GetVariable(LPCTSTR name) { + CString result; + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x98, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, name); + return result; + } + void TSetProperty(LPCTSTR target, long property, LPCTSTR value) { + static BYTE parms[] = VTS_BSTR VTS_I4 VTS_BSTR; + InvokeHelper(0x99, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, property, value); + } + CString TGetProperty(LPCTSTR target, long property) { + CString result; + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0x9a, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms, target, property); + return result; + } + void TCallFrame(LPCTSTR target, long FrameNum) { + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0x9b, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, FrameNum); + } + void TCallLabel(LPCTSTR target, LPCTSTR label) { + static BYTE parms[] = VTS_BSTR VTS_BSTR; + InvokeHelper(0x9c, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, label); + } + void TSetPropertyNum(LPCTSTR target, long property, double value) { + static BYTE parms[] = VTS_BSTR VTS_I4 VTS_R8; + InvokeHelper(0x9d, DISPATCH_METHOD, VT_EMPTY, nullptr, parms, target, property, value); + } + double TGetPropertyNum(LPCTSTR target, long property) { + double result; + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0x9e, DISPATCH_METHOD, VT_R8, (void*)&result, parms, target, property); + return result; + } + double TGetPropertyAsNumber(LPCTSTR target, long property) { + double result; + static BYTE parms[] = VTS_BSTR VTS_I4; + InvokeHelper(0xac, DISPATCH_METHOD, VT_R8, (void*)&result, parms, target, property); + return result; + } + CString get_SWRemote() { + CString result; + InvokeHelper(0x9f, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_SWRemote(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0x9f, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_FlashVars() { + CString result; + InvokeHelper(0xaa, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_FlashVars(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0xaa, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + CString get_AllowScriptAccess() { + CString result; + InvokeHelper(0xab, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, nullptr); + return result; + } + void put_AllowScriptAccess(LPCTSTR newValue) { + static BYTE parms[] = VTS_BSTR; + InvokeHelper(0xab, DISPATCH_PROPERTYPUT, VT_EMPTY, nullptr, parms, newValue); + } + +}; diff --git a/src/mpc-hc/ChildView.cpp b/src/mpc-hc/ChildView.cpp index 0e30405f295..dad9e948cf3 100644 --- a/src/mpc-hc/ChildView.cpp +++ b/src/mpc-hc/ChildView.cpp @@ -1,207 +1,207 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "ChildView.h" -#include "MainFrm.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "ColorProfileUtil.h" - -CChildView::CChildView(CMainFrame* pMainFrame) - : CMouseWndWithArtView(pMainFrame) - , m_bSwitchingFullscreen(false) - , m_bFirstMedia(true) -{ - GetEventd().Connect(m_eventc, { - MpcEvent::SWITCHING_TO_FULLSCREEN, - MpcEvent::SWITCHED_TO_FULLSCREEN, - MpcEvent::SWITCHING_FROM_FULLSCREEN, - MpcEvent::SWITCHED_FROM_FULLSCREEN, - MpcEvent::MEDIA_LOADED, - }, std::bind(&CChildView::EventCallback, this, std::placeholders::_1)); -} - -CChildView::~CChildView() -{ -} - -void CChildView::EventCallback(MpcEvent ev) -{ - switch (ev) { - case MpcEvent::SWITCHING_TO_FULLSCREEN: - case MpcEvent::SWITCHING_FROM_FULLSCREEN: - m_bSwitchingFullscreen = true; - break; - case MpcEvent::SWITCHED_TO_FULLSCREEN: - case MpcEvent::SWITCHED_FROM_FULLSCREEN: - m_bSwitchingFullscreen = false; - break; - case MpcEvent::MEDIA_LOADED: - m_bFirstMedia = false; - break; - default: - ASSERT(FALSE); - } -} - -BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) -{ - if (!CWnd::PreCreateWindow(cs)) { - return FALSE; - } - - cs.style &= ~WS_BORDER; - cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, - ::LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), nullptr); - - return TRUE; -} - -BOOL CChildView::PreTranslateMessage(MSG* pMsg) -{ - // filter interactive video controls mouse messages - if (pMsg->hwnd != m_hWnd && - pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST && - m_pMainFrame->IsInteractiveVideo()) { - switch (pMsg->message) { - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - // let them through, interactive video controls will handle those - break; - case WM_MOUSEMOVE: { - // duplicate those - CPoint point(pMsg->lParam); - ::MapWindowPoints(pMsg->hwnd, m_hWnd, &point, 1); - VERIFY(PostMessage(pMsg->message, pMsg->wParam, MAKELPARAM(point.x, point.y))); - break; - } - default: { - // and handle others in this class - CPoint point(pMsg->lParam); - ::MapWindowPoints(pMsg->hwnd, m_hWnd, &point, 1); - pMsg->lParam = MAKELPARAM(point.x, point.y); - pMsg->hwnd = m_hWnd; - } - } - } - return CWnd::PreTranslateMessage(pMsg); -} - -IMPLEMENT_DYNAMIC(CChildView, CMouseWnd) - -BEGIN_MESSAGE_MAP(CChildView, CMouseWnd) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_WM_SIZE() - ON_WM_NCHITTEST() - ON_WM_NCLBUTTONDOWN() -END_MESSAGE_MAP() - -void CChildView::OnPaint() -{ - CPaintDC dc(this); - m_pMainFrame->RepaintVideo(); -} - -void CChildView::OnSize(UINT nType, int cx, int cy) -{ - __super::OnSize(nType, cx, cy); - if (!m_bSwitchingFullscreen) { - m_pMainFrame->MoveVideoWindow(); - } - m_pMainFrame->UpdateThumbnailClip(); -} - -LRESULT CChildView::OnNcHitTest(CPoint point) -{ - LRESULT ret = CWnd::OnNcHitTest(point); - if (!m_pMainFrame->IsFullScreenMainFrame() && m_pMainFrame->IsFrameLessWindow()) { - CRect rcFrame; - GetWindowRect(&rcFrame); - CRect rcClient(rcFrame); - rcClient.InflateRect(-GetSystemMetrics(SM_CXSIZEFRAME), -GetSystemMetrics(SM_CYSIZEFRAME)); - - if (rcFrame.PtInRect(point)) { - if (point.x > rcClient.right) { - if (point.y < rcClient.top) { - ret = HTTOPRIGHT; - } else if (point.y > rcClient.bottom) { - ret = HTBOTTOMRIGHT; - } else { - ret = HTRIGHT; - } - } else if (point.x < rcClient.left) { - if (point.y < rcClient.top) { - ret = HTTOPLEFT; - } else if (point.y > rcClient.bottom) { - ret = HTBOTTOMLEFT; - } else { - ret = HTLEFT; - } - } else if (point.y < rcClient.top) { - ret = HTTOP; - } else if (point.y > rcClient.bottom) { - ret = HTBOTTOM; - } - } - } - return ret; -} - -void CChildView::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - BYTE flag = 0; - switch (nHitTest) { - case HTTOP: - flag = WMSZ_TOP; - break; - case HTTOPLEFT: - flag = WMSZ_TOPLEFT; - break; - case HTTOPRIGHT: - flag = WMSZ_TOPRIGHT; - break; - case HTLEFT: - flag = WMSZ_LEFT; - break; - case HTRIGHT: - flag = WMSZ_RIGHT; - break; - case HTBOTTOM: - flag = WMSZ_BOTTOM; - break; - case HTBOTTOMLEFT: - flag = WMSZ_BOTTOMLEFT; - break; - case HTBOTTOMRIGHT: - flag = WMSZ_BOTTOMRIGHT; - break; - } - if (flag) { - m_pMainFrame->SendMessage(WM_SYSCOMMAND, SC_SIZE | flag, MAKELPARAM(point.x, point.y)); - } -} - -BOOL CChildView::OnEraseBkgnd(CDC* pDC) { - return __super::OnEraseBkgnd(pDC); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "ChildView.h" +#include "MainFrm.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "ColorProfileUtil.h" + +CChildView::CChildView(CMainFrame* pMainFrame) + : CMouseWndWithArtView(pMainFrame) + , m_bSwitchingFullscreen(false) + , m_bFirstMedia(true) +{ + GetEventd().Connect(m_eventc, { + MpcEvent::SWITCHING_TO_FULLSCREEN, + MpcEvent::SWITCHED_TO_FULLSCREEN, + MpcEvent::SWITCHING_FROM_FULLSCREEN, + MpcEvent::SWITCHED_FROM_FULLSCREEN, + MpcEvent::MEDIA_LOADED, + }, std::bind(&CChildView::EventCallback, this, std::placeholders::_1)); +} + +CChildView::~CChildView() +{ +} + +void CChildView::EventCallback(MpcEvent ev) +{ + switch (ev) { + case MpcEvent::SWITCHING_TO_FULLSCREEN: + case MpcEvent::SWITCHING_FROM_FULLSCREEN: + m_bSwitchingFullscreen = true; + break; + case MpcEvent::SWITCHED_TO_FULLSCREEN: + case MpcEvent::SWITCHED_FROM_FULLSCREEN: + m_bSwitchingFullscreen = false; + break; + case MpcEvent::MEDIA_LOADED: + m_bFirstMedia = false; + break; + default: + ASSERT(FALSE); + } +} + +BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) +{ + if (!CWnd::PreCreateWindow(cs)) { + return FALSE; + } + + cs.style &= ~WS_BORDER; + cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, + ::LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), nullptr); + + return TRUE; +} + +BOOL CChildView::PreTranslateMessage(MSG* pMsg) +{ + // filter interactive video controls mouse messages + if (pMsg->hwnd != m_hWnd && + pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST && + m_pMainFrame->IsInteractiveVideo()) { + switch (pMsg->message) { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + // let them through, interactive video controls will handle those + break; + case WM_MOUSEMOVE: { + // duplicate those + CPoint point(pMsg->lParam); + ::MapWindowPoints(pMsg->hwnd, m_hWnd, &point, 1); + VERIFY(PostMessage(pMsg->message, pMsg->wParam, MAKELPARAM(point.x, point.y))); + break; + } + default: { + // and handle others in this class + CPoint point(pMsg->lParam); + ::MapWindowPoints(pMsg->hwnd, m_hWnd, &point, 1); + pMsg->lParam = MAKELPARAM(point.x, point.y); + pMsg->hwnd = m_hWnd; + } + } + } + return CWnd::PreTranslateMessage(pMsg); +} + +IMPLEMENT_DYNAMIC(CChildView, CMouseWnd) + +BEGIN_MESSAGE_MAP(CChildView, CMouseWnd) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_WM_SIZE() + ON_WM_NCHITTEST() + ON_WM_NCLBUTTONDOWN() +END_MESSAGE_MAP() + +void CChildView::OnPaint() +{ + CPaintDC dc(this); + m_pMainFrame->RepaintVideo(); +} + +void CChildView::OnSize(UINT nType, int cx, int cy) +{ + __super::OnSize(nType, cx, cy); + if (!m_bSwitchingFullscreen) { + m_pMainFrame->MoveVideoWindow(); + } + m_pMainFrame->UpdateThumbnailClip(); +} + +LRESULT CChildView::OnNcHitTest(CPoint point) +{ + LRESULT ret = CWnd::OnNcHitTest(point); + if (!m_pMainFrame->IsFullScreenMainFrame() && m_pMainFrame->IsFrameLessWindow()) { + CRect rcFrame; + GetWindowRect(&rcFrame); + CRect rcClient(rcFrame); + rcClient.InflateRect(-GetSystemMetrics(SM_CXSIZEFRAME), -GetSystemMetrics(SM_CYSIZEFRAME)); + + if (rcFrame.PtInRect(point)) { + if (point.x > rcClient.right) { + if (point.y < rcClient.top) { + ret = HTTOPRIGHT; + } else if (point.y > rcClient.bottom) { + ret = HTBOTTOMRIGHT; + } else { + ret = HTRIGHT; + } + } else if (point.x < rcClient.left) { + if (point.y < rcClient.top) { + ret = HTTOPLEFT; + } else if (point.y > rcClient.bottom) { + ret = HTBOTTOMLEFT; + } else { + ret = HTLEFT; + } + } else if (point.y < rcClient.top) { + ret = HTTOP; + } else if (point.y > rcClient.bottom) { + ret = HTBOTTOM; + } + } + } + return ret; +} + +void CChildView::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + BYTE flag = 0; + switch (nHitTest) { + case HTTOP: + flag = WMSZ_TOP; + break; + case HTTOPLEFT: + flag = WMSZ_TOPLEFT; + break; + case HTTOPRIGHT: + flag = WMSZ_TOPRIGHT; + break; + case HTLEFT: + flag = WMSZ_LEFT; + break; + case HTRIGHT: + flag = WMSZ_RIGHT; + break; + case HTBOTTOM: + flag = WMSZ_BOTTOM; + break; + case HTBOTTOMLEFT: + flag = WMSZ_BOTTOMLEFT; + break; + case HTBOTTOMRIGHT: + flag = WMSZ_BOTTOMRIGHT; + break; + } + if (flag) { + m_pMainFrame->SendMessage(WM_SYSCOMMAND, SC_SIZE | flag, MAKELPARAM(point.x, point.y)); + } +} + +BOOL CChildView::OnEraseBkgnd(CDC* pDC) { + return __super::OnEraseBkgnd(pDC); +} diff --git a/src/mpc-hc/ChildView.h b/src/mpc-hc/ChildView.h index e01a81c629b..577a70f885a 100644 --- a/src/mpc-hc/ChildView.h +++ b/src/mpc-hc/ChildView.h @@ -1,53 +1,53 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -#include "MouseWndWithArtView.h" - -class CChildView : public CMouseWndWithArtView -{ - bool m_bSwitchingFullscreen; - bool m_bFirstMedia; - - EventClient m_eventc; - - void EventCallback(MpcEvent ev); - -public: - CChildView(CMainFrame* pMainFrm); - virtual ~CChildView(); - - DECLARE_DYNAMIC(CChildView) - -protected: - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - virtual BOOL PreTranslateMessage(MSG* pMsg); - - DECLARE_MESSAGE_MAP() - - afx_msg void OnPaint(); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); -public: - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +#include "MouseWndWithArtView.h" + +class CChildView : public CMouseWndWithArtView +{ + bool m_bSwitchingFullscreen; + bool m_bFirstMedia; + + EventClient m_eventc; + + void EventCallback(MpcEvent ev); + +public: + CChildView(CMainFrame* pMainFrm); + virtual ~CChildView(); + + DECLARE_DYNAMIC(CChildView) + +protected: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnPaint(); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); +public: + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; diff --git a/src/mpc-hc/ColorButton.cpp b/src/mpc-hc/ColorButton.cpp index d3697608bc5..997f539cc97 100644 --- a/src/mpc-hc/ColorButton.cpp +++ b/src/mpc-hc/ColorButton.cpp @@ -1,96 +1,96 @@ -/* - * (C) 2014 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "ColorButton.h" -#include "CMPCTheme.h" - -CColorButton::CColorButton() -{ - Initialize(); -} - -void CColorButton::SetColor(COLORREF color) -{ - if (m_color != color) { - m_color = color; - Invalidate(); - } -} - -void CColorButton::Initialize() -{ - if (m_bInitialized) { - m_penInside.DeleteObject(); - m_penBorder.DeleteObject(); - m_penBorderFocus.DeleteObject(); - } else { - m_bInitialized = true; - } - - if (AppIsThemeLoaded()) { - VERIFY(m_penInside.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::NoBorderColor)); - VERIFY(m_penBorder.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::ButtonBorderOuterColor)); - VERIFY(m_penBorderFocus.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::ButtonBorderInnerFocusedColor)); - } else { - VERIFY(m_penInside.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_BTNFACE))); - VERIFY(m_penBorder.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_BTNSHADOW))); - VERIFY(m_penBorderFocus.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_HIGHLIGHT))); - } -} - -void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - if (pDC) { - CRect rect; - GetClientRect(rect); - CPen& borderPen = (lpDrawItemStruct->itemState & ODS_FOCUS) ? m_penBorderFocus : m_penBorder; - CPen* pOldPen = pDC->SelectObject(&borderPen); - pDC->Rectangle(rect); - pDC->SelectObject(&m_penInside); - rect.DeflateRect(1, 1); - pDC->Rectangle(rect); - rect.DeflateRect(1, 1); - pDC->FillSolidRect(rect, m_color); - pDC->SelectObject(pOldPen); - } else { - ASSERT(FALSE); - } -} - -BEGIN_MESSAGE_MAP(CColorButton, CButton) - ON_WM_SETCURSOR() -END_MESSAGE_MAP() - -BOOL CColorButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) -{ - UNREFERENCED_PARAMETER(pWnd); - UNREFERENCED_PARAMETER(nHitTest); - UNREFERENCED_PARAMETER(message); - - if (IsWindowEnabled()) { - ::SetCursor(m_cursor); - return TRUE; - } - - return FALSE; -} +/* + * (C) 2014 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "ColorButton.h" +#include "CMPCTheme.h" + +CColorButton::CColorButton() +{ + Initialize(); +} + +void CColorButton::SetColor(COLORREF color) +{ + if (m_color != color) { + m_color = color; + Invalidate(); + } +} + +void CColorButton::Initialize() +{ + if (m_bInitialized) { + m_penInside.DeleteObject(); + m_penBorder.DeleteObject(); + m_penBorderFocus.DeleteObject(); + } else { + m_bInitialized = true; + } + + if (AppIsThemeLoaded()) { + VERIFY(m_penInside.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::NoBorderColor)); + VERIFY(m_penBorder.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::ButtonBorderOuterColor)); + VERIFY(m_penBorderFocus.CreatePen(PS_INSIDEFRAME, 1, CMPCTheme::ButtonBorderInnerFocusedColor)); + } else { + VERIFY(m_penInside.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_BTNFACE))); + VERIFY(m_penBorder.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_BTNSHADOW))); + VERIFY(m_penBorderFocus.CreatePen(PS_INSIDEFRAME, 1, GetSysColor(COLOR_HIGHLIGHT))); + } +} + +void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + if (pDC) { + CRect rect; + GetClientRect(rect); + CPen& borderPen = (lpDrawItemStruct->itemState & ODS_FOCUS) ? m_penBorderFocus : m_penBorder; + CPen* pOldPen = pDC->SelectObject(&borderPen); + pDC->Rectangle(rect); + pDC->SelectObject(&m_penInside); + rect.DeflateRect(1, 1); + pDC->Rectangle(rect); + rect.DeflateRect(1, 1); + pDC->FillSolidRect(rect, m_color); + pDC->SelectObject(pOldPen); + } else { + ASSERT(FALSE); + } +} + +BEGIN_MESSAGE_MAP(CColorButton, CButton) + ON_WM_SETCURSOR() +END_MESSAGE_MAP() + +BOOL CColorButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + UNREFERENCED_PARAMETER(pWnd); + UNREFERENCED_PARAMETER(nHitTest); + UNREFERENCED_PARAMETER(message); + + if (IsWindowEnabled()) { + ::SetCursor(m_cursor); + return TRUE; + } + + return FALSE; +} diff --git a/src/mpc-hc/ComPropertyPage.cpp b/src/mpc-hc/ComPropertyPage.cpp index 20f8962562b..7ff8b3f3435 100644 --- a/src/mpc-hc/ComPropertyPage.cpp +++ b/src/mpc-hc/ComPropertyPage.cpp @@ -1,104 +1,104 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "ComPropertyPage.h" -#include "ComPropertySheet.h" - - -// CComPropertyPage dialog - -IMPLEMENT_DYNAMIC(CComPropertyPage, CPropertyPage) -CComPropertyPage::CComPropertyPage(IPropertyPage* pPage) - : CPropertyPage(CComPropertyPage::IDD), m_pPage(pPage) -{ - PROPPAGEINFO ppi; - m_pPage->GetPageInfo(&ppi); - m_pPSP->pszTitle = (m_strCaption = ppi.pszTitle); - m_psp.dwFlags |= PSP_USETITLE; -} - -CComPropertyPage::~CComPropertyPage() -{ -} - -void CComPropertyPage::DoDataExchange(CDataExchange* pDX) -{ - CPropertyPage::DoDataExchange(pDX); -} - -BOOL CComPropertyPage::OnInitDialog() -{ - CPropertyPage::OnInitDialog(); - - CRect r; - PROPPAGEINFO ppi; - m_pPage->GetPageInfo(&ppi); - r = CRect(CPoint(0, 0), ppi.size); - m_pPage->Activate(m_hWnd, r, FALSE); - m_pPage->Show(SW_SHOW); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CComPropertyPage::OnDestroy() -{ - CPropertyPage::OnDestroy(); - m_pPage->Deactivate(); -} - -BOOL CComPropertyPage::OnSetActive() -{ - SetModified(S_OK == m_pPage->IsPageDirty()); - - CWnd* pParent = GetParent(); - if (pParent->IsKindOf(RUNTIME_CLASS(CComPropertySheet))) { - CComPropertySheet* pSheet = static_cast(pParent); - pSheet->OnActivated(this); - } - - return CPropertyPage::OnSetActive(); -} - -BOOL CComPropertyPage::OnKillActive() -{ - SetModified(FALSE); - return CPropertyPage::OnKillActive(); -} - - -BEGIN_MESSAGE_MAP(CComPropertyPage, CPropertyPage) - ON_WM_DESTROY() -END_MESSAGE_MAP() - - -// CComPropertyPage message handlers - -void CComPropertyPage::OnOK() -{ - if (S_OK == m_pPage->IsPageDirty()) { - m_pPage->Apply(); - } - SetModified(FALSE); - CPropertyPage::OnOK(); -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "ComPropertyPage.h" +#include "ComPropertySheet.h" + + +// CComPropertyPage dialog + +IMPLEMENT_DYNAMIC(CComPropertyPage, CPropertyPage) +CComPropertyPage::CComPropertyPage(IPropertyPage* pPage) + : CPropertyPage(CComPropertyPage::IDD), m_pPage(pPage) +{ + PROPPAGEINFO ppi; + m_pPage->GetPageInfo(&ppi); + m_pPSP->pszTitle = (m_strCaption = ppi.pszTitle); + m_psp.dwFlags |= PSP_USETITLE; +} + +CComPropertyPage::~CComPropertyPage() +{ +} + +void CComPropertyPage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); +} + +BOOL CComPropertyPage::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + + CRect r; + PROPPAGEINFO ppi; + m_pPage->GetPageInfo(&ppi); + r = CRect(CPoint(0, 0), ppi.size); + m_pPage->Activate(m_hWnd, r, FALSE); + m_pPage->Show(SW_SHOW); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CComPropertyPage::OnDestroy() +{ + CPropertyPage::OnDestroy(); + m_pPage->Deactivate(); +} + +BOOL CComPropertyPage::OnSetActive() +{ + SetModified(S_OK == m_pPage->IsPageDirty()); + + CWnd* pParent = GetParent(); + if (pParent->IsKindOf(RUNTIME_CLASS(CComPropertySheet))) { + CComPropertySheet* pSheet = static_cast(pParent); + pSheet->OnActivated(this); + } + + return CPropertyPage::OnSetActive(); +} + +BOOL CComPropertyPage::OnKillActive() +{ + SetModified(FALSE); + return CPropertyPage::OnKillActive(); +} + + +BEGIN_MESSAGE_MAP(CComPropertyPage, CPropertyPage) + ON_WM_DESTROY() +END_MESSAGE_MAP() + + +// CComPropertyPage message handlers + +void CComPropertyPage::OnOK() +{ + if (S_OK == m_pPage->IsPageDirty()) { + m_pPage->Apply(); + } + SetModified(FALSE); + CPropertyPage::OnOK(); +} diff --git a/src/mpc-hc/ComPropertyPage.h b/src/mpc-hc/ComPropertyPage.h index 6eb4e9a3d76..ead6c4e228c 100644 --- a/src/mpc-hc/ComPropertyPage.h +++ b/src/mpc-hc/ComPropertyPage.h @@ -1,52 +1,52 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "resource.h" - -// CComPropertyPage dialog - -class CComPropertyPage : public CPropertyPage -{ - DECLARE_DYNAMIC(CComPropertyPage) - - CComPtr m_pPage; - -public: - CComPropertyPage(IPropertyPage* pPage); - virtual ~CComPropertyPage(); - - // Dialog Data - enum { IDD = IDD_COMPROPERTYPAGE }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnSetActive(); - virtual BOOL OnKillActive(); - - DECLARE_MESSAGE_MAP() - -public: - virtual BOOL OnInitDialog(); - afx_msg void OnDestroy(); - virtual void OnOK(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "resource.h" + +// CComPropertyPage dialog + +class CComPropertyPage : public CPropertyPage +{ + DECLARE_DYNAMIC(CComPropertyPage) + + CComPtr m_pPage; + +public: + CComPropertyPage(IPropertyPage* pPage); + virtual ~CComPropertyPage(); + + // Dialog Data + enum { IDD = IDD_COMPROPERTYPAGE }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnSetActive(); + virtual BOOL OnKillActive(); + + DECLARE_MESSAGE_MAP() + +public: + virtual BOOL OnInitDialog(); + afx_msg void OnDestroy(); + virtual void OnOK(); +}; diff --git a/src/mpc-hc/ComPropertySheet.cpp b/src/mpc-hc/ComPropertySheet.cpp index 4c6b262ff3b..7af7e7a4239 100644 --- a/src/mpc-hc/ComPropertySheet.cpp +++ b/src/mpc-hc/ComPropertySheet.cpp @@ -1,287 +1,287 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "ComPropertySheet.h" -#include "DSUtil.h" -#include "../filters/InternalPropertyPage.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" - -// CComPropertyPageSite - -class CComPropertyPageSite : public CUnknown, public IPropertyPageSite -{ - IComPropertyPageDirty* m_pPPD; - -public: - CComPropertyPageSite(IComPropertyPageDirty* pPPD) : CUnknown(NAME("CComPropertyPageSite"), nullptr), m_pPPD(pPPD) {} - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(IPropertyPageSite) - __super::NonDelegatingQueryInterface(riid, ppv); - } - - // IPropertyPageSite - STDMETHODIMP OnStatusChange(DWORD flags) { - if (m_pPPD) { - if (flags & PROPPAGESTATUS_DIRTY) { - m_pPPD->OnSetDirty(true); - } - if (flags & PROPPAGESTATUS_CLEAN) { - m_pPPD->OnSetDirty(false); - } - } - return S_OK; - } - STDMETHODIMP GetLocaleID(LCID* pLocaleID) { - CheckPointer(pLocaleID, E_POINTER); - *pLocaleID = ::GetUserDefaultLCID(); - return S_OK; - } - STDMETHODIMP GetPageContainer(IUnknown** ppUnk) { - return E_NOTIMPL; - } - STDMETHODIMP TranslateAccelerator(LPMSG pMsg) { - return E_NOTIMPL; - } -}; - -// CComPropertySheet - -IMPLEMENT_DYNAMIC(CComPropertySheet, CPropertySheet) -CComPropertySheet::CComPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) - : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) -{ - m_pSite = DEBUG_NEW CComPropertyPageSite(this); - m_size.SetSize(0, 0); -} - -CComPropertySheet::CComPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) - : CPropertySheet(pszCaption, pParentWnd, iSelectPage) -{ - m_pSite = DEBUG_NEW CComPropertyPageSite(this); - m_size.SetSize(0, 0); -} - -CComPropertySheet::~CComPropertySheet() -{ -} - -int CComPropertySheet::AddPages(ISpecifyPropertyPages* pSPP, bool internalfilter /*= false*/, ULONG uIgnorePage /*= -1*/) -{ - if (!pSPP) { - return 0; - } - - CAUUID caGUID; - caGUID.pElems = nullptr; - if (FAILED(pSPP->GetPages(&caGUID)) || caGUID.pElems == nullptr) { - return 0; - } - - IUnknown* lpUnk = nullptr; - if (FAILED(pSPP->QueryInterface(&lpUnk))) { - return 0; - } - - m_spp.AddTail(pSPP); - - CComQIPtr pSPP2 = pSPP; - CComQIPtr pPersist = pSPP; - - ULONG nPages = 0; - for (ULONG i = 0; i < caGUID.cElems; i++) { - CComPtr pPage; - - HRESULT hr = E_FAIL; - - if (pSPP2) { - hr = pSPP2->CreatePage(caGUID.pElems[i], &pPage); - } - - if (FAILED(hr) && internalfilter && !pPage && pPersist) { - hr = LoadExternalPropertyPage(pPersist, caGUID.pElems[i], &pPage); - } - - if (FAILED(hr) && !pPage) { - hr = pPage.CoCreateInstance(caGUID.pElems[i]); - } - - if (FAILED(hr) && !internalfilter && !pPage && pPersist) { - hr = LoadExternalPropertyPage(pPersist, caGUID.pElems[i], &pPage); - } - - if (SUCCEEDED(hr) && i != uIgnorePage) { - if (AddPage(pPage, lpUnk)) { - nPages++; - } - } - } - - CoTaskMemFree(caGUID.pElems); - lpUnk->Release(); - - return nPages; -} - -bool CComPropertySheet::AddPage(IPropertyPage* pPage, IUnknown* pUnk) -{ - if (!pPage || !pUnk) { - return false; - } - - pPage->SetPageSite(m_pSite); - pPage->SetObjects(1, &pUnk); - PROPPAGEINFO ppi; - pPage->GetPageInfo(&ppi); - m_size.cx = std::max(m_size.cx, ppi.size.cx); - m_size.cy = std::max(m_size.cy, ppi.size.cy); - CAutoPtr p(DEBUG_NEW CMPCThemeComPropertyPage(pPage)); - __super::AddPage(p); - m_pages.AddTail(p); - - return true; -} - -void CComPropertySheet::OnActivated(CPropertyPage* pPage) -{ - if (!pPage) { - return; - } - - CRect bounds(30000, 30000, -30000, -30000); - - CRect wr, cr; - GetWindowRect(wr); - GetClientRect(cr); - CSize ws = wr.Size(); - - CRect twr, tcr; - CTabCtrl* pTC = (CTabCtrl*)GetDlgItem(AFX_IDC_TAB_CONTROL); - pTC->GetWindowRect(twr); - pTC->GetClientRect(tcr); - CSize tws = twr.Size(); - - if (CWnd* pChild = pPage->GetWindow(GW_CHILD)) { - pChild->ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0); - pChild->ModifyStyleEx(WS_EX_DLGMODALFRAME, WS_EX_CONTROLPARENT); - - for (CWnd* pGrandChild = pChild->GetWindow(GW_CHILD); pGrandChild; pGrandChild = pGrandChild->GetNextWindow()) { - if (!(pGrandChild->GetStyle()&WS_VISIBLE)) { - continue; - } - - CRect r; - pGrandChild->GetWindowRect(&r); - pChild->ScreenToClient(r); - bounds |= r; - } - } - - bounds |= CRect(0, 0, 0, 0); - bounds.SetRect(0, 0, bounds.right + std::max(bounds.left, 4l), bounds.bottom + std::max(bounds.top, 4l)); - - CRect r = CRect(CPoint(0, 0), bounds.Size()); - pTC->AdjustRect(TRUE, r); - r.SetRect(twr.TopLeft(), twr.TopLeft() + r.Size()); - ScreenToClient(r); - pTC->MoveWindow(r); - pTC->ModifyStyle(TCS_MULTILINE, TCS_SINGLELINE); - - CSize diff = r.Size() - tws; - - if (!bounds.IsRectEmpty()) { - if (CWnd* pChild = pPage->GetWindow(GW_CHILD)) { - pChild->MoveWindow(bounds); - } - CRect r2 = twr; - pTC->AdjustRect(FALSE, r2); - ScreenToClient(r2); - pPage->MoveWindow(CRect(r2.TopLeft(), bounds.Size())); - } - - int _afxPropSheetButtons[] = { IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP }; - for (int i = 0; i < _countof(_afxPropSheetButtons); i++) { - if (CWnd* pWnd = GetDlgItem(_afxPropSheetButtons[i])) { - pWnd->GetWindowRect(r); - ScreenToClient(r); - pWnd->MoveWindow(CRect(r.TopLeft() + diff, r.Size())); - } - } - - MoveWindow(CRect(wr.TopLeft(), ws + diff)); - - Invalidate(); -} - - -BEGIN_MESSAGE_MAP(CComPropertySheet, CPropertySheet) - ON_WM_CTLCOLOR() -END_MESSAGE_MAP() - - -// CComPropertySheet message handlers - -BOOL CComPropertySheet::OnInitDialog() -{ - BOOL bResult = (BOOL)Default();//CPropertySheet::OnInitDialog(); - - if (!(GetStyle() & WS_CHILD)) { - CenterWindow(); - } - - fulfillThemeReqs(); - CMPCThemeUtil::enableWindows10DarkFrame(this); - return bResult; -} - -void CComPropertySheet::fulfillThemeReqs() -{ - if (AppNeedsThemedControls()) { - CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); - } -} - -HBRUSH CComPropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - if (AppNeedsThemedControls()) { - LRESULT lResult; - if (pWnd->SendChildNotifyLastMsg(&lResult)) { - return (HBRUSH)lResult; - } - pDC->SetTextColor(CMPCTheme::TextFGColor); - pDC->SetBkColor(CMPCTheme::ControlAreaBGColor); - return controlAreaBrush; - } else { - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - return hbr; - } -} - - -INT_PTR CComPropertySheet::DoModal() { - PreDoModalRTL(&m_psh); - return __super::DoModal(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "ComPropertySheet.h" +#include "DSUtil.h" +#include "../filters/InternalPropertyPage.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" + +// CComPropertyPageSite + +class CComPropertyPageSite : public CUnknown, public IPropertyPageSite +{ + IComPropertyPageDirty* m_pPPD; + +public: + CComPropertyPageSite(IComPropertyPageDirty* pPPD) : CUnknown(NAME("CComPropertyPageSite"), nullptr), m_pPPD(pPPD) {} + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(IPropertyPageSite) + __super::NonDelegatingQueryInterface(riid, ppv); + } + + // IPropertyPageSite + STDMETHODIMP OnStatusChange(DWORD flags) { + if (m_pPPD) { + if (flags & PROPPAGESTATUS_DIRTY) { + m_pPPD->OnSetDirty(true); + } + if (flags & PROPPAGESTATUS_CLEAN) { + m_pPPD->OnSetDirty(false); + } + } + return S_OK; + } + STDMETHODIMP GetLocaleID(LCID* pLocaleID) { + CheckPointer(pLocaleID, E_POINTER); + *pLocaleID = ::GetUserDefaultLCID(); + return S_OK; + } + STDMETHODIMP GetPageContainer(IUnknown** ppUnk) { + return E_NOTIMPL; + } + STDMETHODIMP TranslateAccelerator(LPMSG pMsg) { + return E_NOTIMPL; + } +}; + +// CComPropertySheet + +IMPLEMENT_DYNAMIC(CComPropertySheet, CPropertySheet) +CComPropertySheet::CComPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) + : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) +{ + m_pSite = DEBUG_NEW CComPropertyPageSite(this); + m_size.SetSize(0, 0); +} + +CComPropertySheet::CComPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) + : CPropertySheet(pszCaption, pParentWnd, iSelectPage) +{ + m_pSite = DEBUG_NEW CComPropertyPageSite(this); + m_size.SetSize(0, 0); +} + +CComPropertySheet::~CComPropertySheet() +{ +} + +int CComPropertySheet::AddPages(ISpecifyPropertyPages* pSPP, bool internalfilter /*= false*/, ULONG uIgnorePage /*= -1*/) +{ + if (!pSPP) { + return 0; + } + + CAUUID caGUID; + caGUID.pElems = nullptr; + if (FAILED(pSPP->GetPages(&caGUID)) || caGUID.pElems == nullptr) { + return 0; + } + + IUnknown* lpUnk = nullptr; + if (FAILED(pSPP->QueryInterface(&lpUnk))) { + return 0; + } + + m_spp.AddTail(pSPP); + + CComQIPtr pSPP2 = pSPP; + CComQIPtr pPersist = pSPP; + + ULONG nPages = 0; + for (ULONG i = 0; i < caGUID.cElems; i++) { + CComPtr pPage; + + HRESULT hr = E_FAIL; + + if (pSPP2) { + hr = pSPP2->CreatePage(caGUID.pElems[i], &pPage); + } + + if (FAILED(hr) && internalfilter && !pPage && pPersist) { + hr = LoadExternalPropertyPage(pPersist, caGUID.pElems[i], &pPage); + } + + if (FAILED(hr) && !pPage) { + hr = pPage.CoCreateInstance(caGUID.pElems[i]); + } + + if (FAILED(hr) && !internalfilter && !pPage && pPersist) { + hr = LoadExternalPropertyPage(pPersist, caGUID.pElems[i], &pPage); + } + + if (SUCCEEDED(hr) && i != uIgnorePage) { + if (AddPage(pPage, lpUnk)) { + nPages++; + } + } + } + + CoTaskMemFree(caGUID.pElems); + lpUnk->Release(); + + return nPages; +} + +bool CComPropertySheet::AddPage(IPropertyPage* pPage, IUnknown* pUnk) +{ + if (!pPage || !pUnk) { + return false; + } + + pPage->SetPageSite(m_pSite); + pPage->SetObjects(1, &pUnk); + PROPPAGEINFO ppi; + pPage->GetPageInfo(&ppi); + m_size.cx = std::max(m_size.cx, ppi.size.cx); + m_size.cy = std::max(m_size.cy, ppi.size.cy); + CAutoPtr p(DEBUG_NEW CMPCThemeComPropertyPage(pPage)); + __super::AddPage(p); + m_pages.AddTail(p); + + return true; +} + +void CComPropertySheet::OnActivated(CPropertyPage* pPage) +{ + if (!pPage) { + return; + } + + CRect bounds(30000, 30000, -30000, -30000); + + CRect wr, cr; + GetWindowRect(wr); + GetClientRect(cr); + CSize ws = wr.Size(); + + CRect twr, tcr; + CTabCtrl* pTC = (CTabCtrl*)GetDlgItem(AFX_IDC_TAB_CONTROL); + pTC->GetWindowRect(twr); + pTC->GetClientRect(tcr); + CSize tws = twr.Size(); + + if (CWnd* pChild = pPage->GetWindow(GW_CHILD)) { + pChild->ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0); + pChild->ModifyStyleEx(WS_EX_DLGMODALFRAME, WS_EX_CONTROLPARENT); + + for (CWnd* pGrandChild = pChild->GetWindow(GW_CHILD); pGrandChild; pGrandChild = pGrandChild->GetNextWindow()) { + if (!(pGrandChild->GetStyle()&WS_VISIBLE)) { + continue; + } + + CRect r; + pGrandChild->GetWindowRect(&r); + pChild->ScreenToClient(r); + bounds |= r; + } + } + + bounds |= CRect(0, 0, 0, 0); + bounds.SetRect(0, 0, bounds.right + std::max(bounds.left, 4l), bounds.bottom + std::max(bounds.top, 4l)); + + CRect r = CRect(CPoint(0, 0), bounds.Size()); + pTC->AdjustRect(TRUE, r); + r.SetRect(twr.TopLeft(), twr.TopLeft() + r.Size()); + ScreenToClient(r); + pTC->MoveWindow(r); + pTC->ModifyStyle(TCS_MULTILINE, TCS_SINGLELINE); + + CSize diff = r.Size() - tws; + + if (!bounds.IsRectEmpty()) { + if (CWnd* pChild = pPage->GetWindow(GW_CHILD)) { + pChild->MoveWindow(bounds); + } + CRect r2 = twr; + pTC->AdjustRect(FALSE, r2); + ScreenToClient(r2); + pPage->MoveWindow(CRect(r2.TopLeft(), bounds.Size())); + } + + int _afxPropSheetButtons[] = { IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP }; + for (int i = 0; i < _countof(_afxPropSheetButtons); i++) { + if (CWnd* pWnd = GetDlgItem(_afxPropSheetButtons[i])) { + pWnd->GetWindowRect(r); + ScreenToClient(r); + pWnd->MoveWindow(CRect(r.TopLeft() + diff, r.Size())); + } + } + + MoveWindow(CRect(wr.TopLeft(), ws + diff)); + + Invalidate(); +} + + +BEGIN_MESSAGE_MAP(CComPropertySheet, CPropertySheet) + ON_WM_CTLCOLOR() +END_MESSAGE_MAP() + + +// CComPropertySheet message handlers + +BOOL CComPropertySheet::OnInitDialog() +{ + BOOL bResult = (BOOL)Default();//CPropertySheet::OnInitDialog(); + + if (!(GetStyle() & WS_CHILD)) { + CenterWindow(); + } + + fulfillThemeReqs(); + CMPCThemeUtil::enableWindows10DarkFrame(this); + return bResult; +} + +void CComPropertySheet::fulfillThemeReqs() +{ + if (AppNeedsThemedControls()) { + CMPCThemeUtil::fulfillThemeReqs((CWnd*)this); + } +} + +HBRUSH CComPropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + if (AppNeedsThemedControls()) { + LRESULT lResult; + if (pWnd->SendChildNotifyLastMsg(&lResult)) { + return (HBRUSH)lResult; + } + pDC->SetTextColor(CMPCTheme::TextFGColor); + pDC->SetBkColor(CMPCTheme::ControlAreaBGColor); + return controlAreaBrush; + } else { + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + return hbr; + } +} + + +INT_PTR CComPropertySheet::DoModal() { + PreDoModalRTL(&m_psh); + return __super::DoModal(); +} diff --git a/src/mpc-hc/ComPropertySheet.h b/src/mpc-hc/ComPropertySheet.h index a01be194f2a..027deee5c0d 100644 --- a/src/mpc-hc/ComPropertySheet.h +++ b/src/mpc-hc/ComPropertySheet.h @@ -1,70 +1,70 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2017 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 . - * - */ - -#pragma once - -#include "CMPCThemeComPropertyPage.h" -#include "CMPCThemeUtil.h" - -interface IComPropertyPageDirty -{ - virtual void OnSetDirty(bool fDirty) = 0; -}; - -// CComPropertySheet - -class CComPropertySheet : public CPropertySheet - , public IComPropertyPageDirty - , public CMPCThemeUtil -{ - DECLARE_DYNAMIC(CComPropertySheet) - - CComPtr m_pSite; - CInterfaceList m_spp; - CAutoPtrList m_pages; - CSize m_size; - -public: - CComPropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); - CComPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); - virtual ~CComPropertySheet(); - - int AddPages(ISpecifyPropertyPages* pSPP, bool internalfilter = false, ULONG uIgnorePage = ULONG(-1)); - bool AddPage(IPropertyPage* pPage, IUnknown* pUnk); - - void OnActivated(CPropertyPage* pPage); - - // IComPropertyPageDirty - void OnSetDirty(bool fDirty) { - if (CPropertyPage* p = GetActivePage()) { - p->SetModified(fDirty); - } - } - - virtual BOOL OnInitDialog(); - void fulfillThemeReqs(); - virtual INT_PTR DoModal(); //override to handle RTL without using SetWindowLongPtr - - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - -protected: - DECLARE_MESSAGE_MAP() -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2017 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 . + * + */ + +#pragma once + +#include "CMPCThemeComPropertyPage.h" +#include "CMPCThemeUtil.h" + +interface IComPropertyPageDirty +{ + virtual void OnSetDirty(bool fDirty) = 0; +}; + +// CComPropertySheet + +class CComPropertySheet : public CPropertySheet + , public IComPropertyPageDirty + , public CMPCThemeUtil +{ + DECLARE_DYNAMIC(CComPropertySheet) + + CComPtr m_pSite; + CInterfaceList m_spp; + CAutoPtrList m_pages; + CSize m_size; + +public: + CComPropertySheet(UINT nIDCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + CComPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd = nullptr, UINT iSelectPage = 0); + virtual ~CComPropertySheet(); + + int AddPages(ISpecifyPropertyPages* pSPP, bool internalfilter = false, ULONG uIgnorePage = ULONG(-1)); + bool AddPage(IPropertyPage* pPage, IUnknown* pUnk); + + void OnActivated(CPropertyPage* pPage); + + // IComPropertyPageDirty + void OnSetDirty(bool fDirty) { + if (CPropertyPage* p = GetActivePage()) { + p->SetModified(fDirty); + } + } + + virtual BOOL OnInitDialog(); + void fulfillThemeReqs(); + virtual INT_PTR DoModal(); //override to handle RTL without using SetWindowLongPtr + + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + +protected: + DECLARE_MESSAGE_MAP() +}; diff --git a/src/mpc-hc/DVBChannel.cpp b/src/mpc-hc/DVBChannel.cpp index 98bfc1db8b1..ffc4a8a4837 100644 --- a/src/mpc-hc/DVBChannel.cpp +++ b/src/mpc-hc/DVBChannel.cpp @@ -1,310 +1,310 @@ -/* - * (C) 2009-2017 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 . - * - */ - - -#include "stdafx.h" -#include "DVBChannel.h" -#include "ISOLang.h" -#include "mplayerc.h" - - -LCID BDAStreamInfo::GetLCID() const -{ - return ISOLang::ISO6392ToLcid(CStringA(sLanguage)); -}; - -CBDAChannel::CBDAChannel(CString strChannel) -{ - FromString(strChannel); -} - -void CBDAChannel::FromString(CString strValue) -{ - int i = 0; - - int nVersion = _tstol(strValue.Tokenize(_T("|"), i)); - // We don't try to parse versions newer than the one we support - if (nVersion > FORMAT_VERSION_CURRENT) { - AfxThrowInvalidArgException(); - } - - m_strName = strValue.Tokenize(_T("|"), i); - m_ulFrequency = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulBandwidth = (nVersion > FORMAT_VERSION_4) ? _tstol(strValue.Tokenize(_T("|"), i)) - : AfxGetAppSettings().iBDABandwidth * 1000; - m_ulSymbolRate = (nVersion > FORMAT_VERSION_5) ? _tstol(strValue.Tokenize(_T("|"), i)) - : AfxGetAppSettings().iBDASymbolRate; - m_nPrefNumber = _tstol(strValue.Tokenize(_T("|"), i)); - m_nOriginNumber = _tstol(strValue.Tokenize(_T("|"), i)); - if (nVersion > FORMAT_VERSION_0) { - m_bEncrypted = !!_tstol(strValue.Tokenize(_T("|"), i)); - } - if (nVersion > FORMAT_VERSION_1) { - m_bNowNextFlag = !!_tstol(strValue.Tokenize(_T("|"), i)); - } - m_ulONID = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulTSID = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulSID = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulPMT = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulPCR = _tstol(strValue.Tokenize(_T("|"), i)); - m_ulVideoPID = _tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoType = (BDA_STREAM_TYPE) _tstol(strValue.Tokenize(_T("|"), i)); - m_nAudioCount = _tstol(strValue.Tokenize(_T("|"), i)); - if (nVersion > FORMAT_VERSION_1) { - m_nDefaultAudio = _tstol(strValue.Tokenize(_T("|"), i)); - } - m_nSubtitleCount = _tstol(strValue.Tokenize(_T("|"), i)); - if (nVersion > FORMAT_VERSION_2) { - m_nDefaultSubtitle = _tstol(strValue.Tokenize(_T("|"), i)); - } - - for (int j = 0; j < m_nAudioCount; j++) { - m_Audios[j].ulPID = _tstol(strValue.Tokenize(_T("|"), i)); - m_Audios[j].nType = (BDA_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_Audios[j].nPesType = (PES_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_Audios[j].sLanguage = strValue.Tokenize(_T("|"), i); - } - - for (int j = 0; j < m_nSubtitleCount; j++) { - m_Subtitles[j].ulPID = _tstol(strValue.Tokenize(_T("|"), i)); - m_Subtitles[j].nType = (BDA_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_Subtitles[j].nPesType = (PES_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_Subtitles[j].sLanguage = strValue.Tokenize(_T("|"), i); - } - - if (nVersion > FORMAT_VERSION_3) { - m_nVideoFps = (BDA_FPS_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoChroma = (BDA_CHROMA_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoWidth = _tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoHeight = _tstol(strValue.Tokenize(_T("|"), i)); - m_nVideoAR = (BDA_AspectRatio_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); - } -} - -CString CBDAChannel::ToString() const -{ - auto substituteEmpty = [](const CString & lang) -> CString { - if (lang.IsEmpty()) - { - return _T(" "); - } - return lang; - }; - - CString strValue; - strValue.AppendFormat(_T("%d|%s|%lu|%lu|%lu|%d|%d|%d|%d|%lu|%lu|%lu|%lu|%lu|%lu|%d|%d|%d|%d|%d"), - FORMAT_VERSION_CURRENT, - m_strName.GetString(), - m_ulFrequency, - m_ulBandwidth, - m_ulSymbolRate, - m_nPrefNumber, - m_nOriginNumber, - m_bEncrypted, - m_bNowNextFlag, - m_ulONID, - m_ulTSID, - m_ulSID, - m_ulPMT, - m_ulPCR, - m_ulVideoPID, - m_nVideoType, - m_nAudioCount, - m_nDefaultAudio, - m_nSubtitleCount, - m_nDefaultSubtitle); - - for (int i = 0; i < m_nAudioCount; i++) { - strValue.AppendFormat(_T("|%lu|%d|%d|%s"), m_Audios[i].ulPID, m_Audios[i].nType, m_Audios[i].nPesType, substituteEmpty(m_Audios[i].sLanguage).GetString()); - } - - for (int i = 0; i < m_nSubtitleCount; i++) { - strValue.AppendFormat(_T("|%lu|%d|%d|%s"), m_Subtitles[i].ulPID, m_Subtitles[i].nType, m_Subtitles[i].nPesType, substituteEmpty(m_Subtitles[i].sLanguage).GetString()); - } - - strValue.AppendFormat(_T("|%d|%d|%lu|%lu|%d"), - m_nVideoFps, - m_nVideoChroma, - m_nVideoWidth, - m_nVideoHeight, - m_nVideoAR); - - return strValue; -} - -CStringA CBDAChannel::ToJSON() const -{ - CStringA jsonChannel; - jsonChannel.Format("{ \"index\" : %d, \"name\" : \"%s\" }", - m_nPrefNumber, - EscapeJSONString(UTF16To8(m_strName)).GetString()); - return jsonChannel; -} - -void CBDAChannel::AddStreamInfo(ULONG ulPID, BDA_STREAM_TYPE nType, PES_STREAM_TYPE nPesType, LPCTSTR strLanguage) -{ - switch (nType) { - case BDA_MPV: - case BDA_H264: - case BDA_HEVC: - m_ulVideoPID = ulPID; - m_nVideoType = nType; - break; - case BDA_MPA: - case BDA_AC3: - case BDA_EAC3: - case BDA_ADTS: - case BDA_LATM: - if (m_nAudioCount < BDA_MAX_AUDIO) { - m_Audios[m_nAudioCount].ulPID = ulPID; - m_Audios[m_nAudioCount].nType = nType; - m_Audios[m_nAudioCount].nPesType = nPesType; - m_Audios[m_nAudioCount].sLanguage = strLanguage; - m_nAudioCount++; - } - break; - case BDA_SUBTITLE: - if (m_nSubtitleCount < BDA_MAX_SUBTITLE) { - m_Subtitles[m_nSubtitleCount].ulPID = ulPID; - m_Subtitles[m_nSubtitleCount].nType = nType; - m_Subtitles[m_nSubtitleCount].nPesType = nPesType; - m_Subtitles[m_nSubtitleCount].sLanguage = strLanguage; - m_nSubtitleCount++; - } - break; - } -} - -REFERENCE_TIME CBDAChannel::GetAvgTimePerFrame() -{ - REFERENCE_TIME Value; - switch (m_nVideoFps) { - case BDA_FPS_23_976: - Value = 417084; - break; - case BDA_FPS_24_0: - Value = 416667; - break; - case BDA_FPS_25_0: - Value = 400000; - break; - case BDA_FPS_29_97: - Value = 333667; - break; - case BDA_FPS_30_0: - Value = 333333; - break; - case BDA_FPS_50_0: - Value = 200000; - break; - case BDA_FPS_59_94: - Value = 166834; - break; - case BDA_FPS_60_0: - Value = 166667; - break; - default: - Value = 0; - break; - } - return Value; -} - -CString CBDAChannel::GetVideoFpsDesc() -{ - CString strValue; - switch (m_nVideoFps) { - case BDA_FPS_23_976: - strValue = _T("23.976"); - break; - case BDA_FPS_24_0: - strValue = _T("24.000"); - break; - case BDA_FPS_25_0: - strValue = _T("25.000"); - break; - case BDA_FPS_29_97: - strValue = _T("29.970"); - break; - case BDA_FPS_30_0: - strValue = _T("30.000"); - break; - case BDA_FPS_50_0: - strValue = _T("50.000"); - break; - case BDA_FPS_59_94: - strValue = _T("59.940"); - break; - case BDA_FPS_60_0: - strValue = _T("60.000"); - break; - default: - strValue = _T(" -"); - break; - } - return strValue; - -} - -DWORD CBDAChannel::GetVideoARx() -{ - DWORD Value; - switch (GetVideoAR()) { - case BDA_AR_1: - Value = 1; - break; - case BDA_AR_3_4: - Value = 4; - break; - case BDA_AR_9_16: - Value = 16; - break; - case BDA_AR_1_2_21: - Value = 221; - break; - default: - Value = 0; - break; - } - return Value; -} - -DWORD CBDAChannel::GetVideoARy() -{ - DWORD Value; - switch (GetVideoAR()) { - case BDA_AR_1: - Value = 1; - break; - case BDA_AR_3_4: - Value = 3; - break; - case BDA_AR_9_16: - Value = 9; - break; - case BDA_AR_1_2_21: - Value = 100; - break; - default: - Value = 0; - break; - } - return Value; -} +/* + * (C) 2009-2017 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 . + * + */ + + +#include "stdafx.h" +#include "DVBChannel.h" +#include "ISOLang.h" +#include "mplayerc.h" + + +LCID BDAStreamInfo::GetLCID() const +{ + return ISOLang::ISO6392ToLcid(CStringA(sLanguage)); +}; + +CBDAChannel::CBDAChannel(CString strChannel) +{ + FromString(strChannel); +} + +void CBDAChannel::FromString(CString strValue) +{ + int i = 0; + + int nVersion = _tstol(strValue.Tokenize(_T("|"), i)); + // We don't try to parse versions newer than the one we support + if (nVersion > FORMAT_VERSION_CURRENT) { + AfxThrowInvalidArgException(); + } + + m_strName = strValue.Tokenize(_T("|"), i); + m_ulFrequency = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulBandwidth = (nVersion > FORMAT_VERSION_4) ? _tstol(strValue.Tokenize(_T("|"), i)) + : AfxGetAppSettings().iBDABandwidth * 1000; + m_ulSymbolRate = (nVersion > FORMAT_VERSION_5) ? _tstol(strValue.Tokenize(_T("|"), i)) + : AfxGetAppSettings().iBDASymbolRate; + m_nPrefNumber = _tstol(strValue.Tokenize(_T("|"), i)); + m_nOriginNumber = _tstol(strValue.Tokenize(_T("|"), i)); + if (nVersion > FORMAT_VERSION_0) { + m_bEncrypted = !!_tstol(strValue.Tokenize(_T("|"), i)); + } + if (nVersion > FORMAT_VERSION_1) { + m_bNowNextFlag = !!_tstol(strValue.Tokenize(_T("|"), i)); + } + m_ulONID = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulTSID = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulSID = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulPMT = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulPCR = _tstol(strValue.Tokenize(_T("|"), i)); + m_ulVideoPID = _tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoType = (BDA_STREAM_TYPE) _tstol(strValue.Tokenize(_T("|"), i)); + m_nAudioCount = _tstol(strValue.Tokenize(_T("|"), i)); + if (nVersion > FORMAT_VERSION_1) { + m_nDefaultAudio = _tstol(strValue.Tokenize(_T("|"), i)); + } + m_nSubtitleCount = _tstol(strValue.Tokenize(_T("|"), i)); + if (nVersion > FORMAT_VERSION_2) { + m_nDefaultSubtitle = _tstol(strValue.Tokenize(_T("|"), i)); + } + + for (int j = 0; j < m_nAudioCount; j++) { + m_Audios[j].ulPID = _tstol(strValue.Tokenize(_T("|"), i)); + m_Audios[j].nType = (BDA_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_Audios[j].nPesType = (PES_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_Audios[j].sLanguage = strValue.Tokenize(_T("|"), i); + } + + for (int j = 0; j < m_nSubtitleCount; j++) { + m_Subtitles[j].ulPID = _tstol(strValue.Tokenize(_T("|"), i)); + m_Subtitles[j].nType = (BDA_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_Subtitles[j].nPesType = (PES_STREAM_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_Subtitles[j].sLanguage = strValue.Tokenize(_T("|"), i); + } + + if (nVersion > FORMAT_VERSION_3) { + m_nVideoFps = (BDA_FPS_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoChroma = (BDA_CHROMA_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoWidth = _tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoHeight = _tstol(strValue.Tokenize(_T("|"), i)); + m_nVideoAR = (BDA_AspectRatio_TYPE)_tstol(strValue.Tokenize(_T("|"), i)); + } +} + +CString CBDAChannel::ToString() const +{ + auto substituteEmpty = [](const CString & lang) -> CString { + if (lang.IsEmpty()) + { + return _T(" "); + } + return lang; + }; + + CString strValue; + strValue.AppendFormat(_T("%d|%s|%lu|%lu|%lu|%d|%d|%d|%d|%lu|%lu|%lu|%lu|%lu|%lu|%d|%d|%d|%d|%d"), + FORMAT_VERSION_CURRENT, + m_strName.GetString(), + m_ulFrequency, + m_ulBandwidth, + m_ulSymbolRate, + m_nPrefNumber, + m_nOriginNumber, + m_bEncrypted, + m_bNowNextFlag, + m_ulONID, + m_ulTSID, + m_ulSID, + m_ulPMT, + m_ulPCR, + m_ulVideoPID, + m_nVideoType, + m_nAudioCount, + m_nDefaultAudio, + m_nSubtitleCount, + m_nDefaultSubtitle); + + for (int i = 0; i < m_nAudioCount; i++) { + strValue.AppendFormat(_T("|%lu|%d|%d|%s"), m_Audios[i].ulPID, m_Audios[i].nType, m_Audios[i].nPesType, substituteEmpty(m_Audios[i].sLanguage).GetString()); + } + + for (int i = 0; i < m_nSubtitleCount; i++) { + strValue.AppendFormat(_T("|%lu|%d|%d|%s"), m_Subtitles[i].ulPID, m_Subtitles[i].nType, m_Subtitles[i].nPesType, substituteEmpty(m_Subtitles[i].sLanguage).GetString()); + } + + strValue.AppendFormat(_T("|%d|%d|%lu|%lu|%d"), + m_nVideoFps, + m_nVideoChroma, + m_nVideoWidth, + m_nVideoHeight, + m_nVideoAR); + + return strValue; +} + +CStringA CBDAChannel::ToJSON() const +{ + CStringA jsonChannel; + jsonChannel.Format("{ \"index\" : %d, \"name\" : \"%s\" }", + m_nPrefNumber, + EscapeJSONString(UTF16To8(m_strName)).GetString()); + return jsonChannel; +} + +void CBDAChannel::AddStreamInfo(ULONG ulPID, BDA_STREAM_TYPE nType, PES_STREAM_TYPE nPesType, LPCTSTR strLanguage) +{ + switch (nType) { + case BDA_MPV: + case BDA_H264: + case BDA_HEVC: + m_ulVideoPID = ulPID; + m_nVideoType = nType; + break; + case BDA_MPA: + case BDA_AC3: + case BDA_EAC3: + case BDA_ADTS: + case BDA_LATM: + if (m_nAudioCount < BDA_MAX_AUDIO) { + m_Audios[m_nAudioCount].ulPID = ulPID; + m_Audios[m_nAudioCount].nType = nType; + m_Audios[m_nAudioCount].nPesType = nPesType; + m_Audios[m_nAudioCount].sLanguage = strLanguage; + m_nAudioCount++; + } + break; + case BDA_SUBTITLE: + if (m_nSubtitleCount < BDA_MAX_SUBTITLE) { + m_Subtitles[m_nSubtitleCount].ulPID = ulPID; + m_Subtitles[m_nSubtitleCount].nType = nType; + m_Subtitles[m_nSubtitleCount].nPesType = nPesType; + m_Subtitles[m_nSubtitleCount].sLanguage = strLanguage; + m_nSubtitleCount++; + } + break; + } +} + +REFERENCE_TIME CBDAChannel::GetAvgTimePerFrame() +{ + REFERENCE_TIME Value; + switch (m_nVideoFps) { + case BDA_FPS_23_976: + Value = 417084; + break; + case BDA_FPS_24_0: + Value = 416667; + break; + case BDA_FPS_25_0: + Value = 400000; + break; + case BDA_FPS_29_97: + Value = 333667; + break; + case BDA_FPS_30_0: + Value = 333333; + break; + case BDA_FPS_50_0: + Value = 200000; + break; + case BDA_FPS_59_94: + Value = 166834; + break; + case BDA_FPS_60_0: + Value = 166667; + break; + default: + Value = 0; + break; + } + return Value; +} + +CString CBDAChannel::GetVideoFpsDesc() +{ + CString strValue; + switch (m_nVideoFps) { + case BDA_FPS_23_976: + strValue = _T("23.976"); + break; + case BDA_FPS_24_0: + strValue = _T("24.000"); + break; + case BDA_FPS_25_0: + strValue = _T("25.000"); + break; + case BDA_FPS_29_97: + strValue = _T("29.970"); + break; + case BDA_FPS_30_0: + strValue = _T("30.000"); + break; + case BDA_FPS_50_0: + strValue = _T("50.000"); + break; + case BDA_FPS_59_94: + strValue = _T("59.940"); + break; + case BDA_FPS_60_0: + strValue = _T("60.000"); + break; + default: + strValue = _T(" -"); + break; + } + return strValue; + +} + +DWORD CBDAChannel::GetVideoARx() +{ + DWORD Value; + switch (GetVideoAR()) { + case BDA_AR_1: + Value = 1; + break; + case BDA_AR_3_4: + Value = 4; + break; + case BDA_AR_9_16: + Value = 16; + break; + case BDA_AR_1_2_21: + Value = 221; + break; + default: + Value = 0; + break; + } + return Value; +} + +DWORD CBDAChannel::GetVideoARy() +{ + DWORD Value; + switch (GetVideoAR()) { + case BDA_AR_1: + Value = 1; + break; + case BDA_AR_3_4: + Value = 3; + break; + case BDA_AR_9_16: + Value = 9; + break; + case BDA_AR_1_2_21: + Value = 100; + break; + default: + Value = 0; + break; + } + return Value; +} diff --git a/src/mpc-hc/DVBChannel.h b/src/mpc-hc/DVBChannel.h index d6866e34d8b..af89625e92a 100644 --- a/src/mpc-hc/DVBChannel.h +++ b/src/mpc-hc/DVBChannel.h @@ -1,221 +1,221 @@ -/* - * (C) 2009-2016 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 . - * - */ - -#pragma once - -#include -#include - -#define FORMAT_VERSION_0 0 -#define FORMAT_VERSION_1 1 -#define FORMAT_VERSION_2 2 -#define FORMAT_VERSION_3 3 -#define FORMAT_VERSION_4 4 -#define FORMAT_VERSION_5 5 -#define FORMAT_VERSION_CURRENT 6 - -#define BDA_MAX_AUDIO 10 -#define BDA_MAX_SUBTITLE 10 - -struct EventDescriptor { - CString eventName; - CString eventDesc; - time_t startTime = 0; - time_t duration = 0; - CString strStartTime; - CString strEndTime; - std::vector> extendedDescriptorsItems; - CString extendedDescriptorsText; - int parentalRating = -1; - CString content; -}; - -enum BDA_STREAM_TYPE { - BDA_MPV = 0x00, - BDA_H264 = 0x01, - BDA_MPA = 0x02, - BDA_AC3 = 0x03, - BDA_EAC3 = 0x04, - BDA_HEVC = 0x05, - BDA_ADTS = 0x10, - BDA_LATM = 0x11, - BDA_PSI = 0x80, - BDA_TIF = 0x81, - BDA_EPG = 0x82, - BDA_SUB = 0x83, - BDA_SUBTITLE = 0xFE, - BDA_UNKNOWN = 0xFF -}; - -enum BDA_CHROMA_TYPE { - BDA_Chroma_NONE = 0x00, - BDA_Chroma_4_2_0 = 0x01, - BDA_Chroma_4_2_2 = 0x02, - BDA_Chroma_4_4_4 = 0x03 -}; - -enum BDA_FPS_TYPE { - BDA_FPS_NONE = 0x00, - BDA_FPS_23_976 = 0x01, - BDA_FPS_24_0 = 0x02, - BDA_FPS_25_0 = 0x03, - BDA_FPS_29_97 = 0x04, - BDA_FPS_30_0 = 0x05, - BDA_FPS_50_0 = 0x06, - BDA_FPS_59_94 = 0x07, - BDA_FPS_60_0 = 0x08 -}; - -enum BDA_AspectRatio_TYPE { - BDA_AR_NULL = 0x00, - BDA_AR_1 = 0x01, - BDA_AR_3_4 = 0x02, - BDA_AR_9_16 = 0x03, - BDA_AR_1_2_21 = 0x04 -}; - -struct BDAStreamInfo { - ULONG ulPID = 0; - BDA_STREAM_TYPE nType = BDA_UNKNOWN; - PES_STREAM_TYPE nPesType = INVALID; - CString sLanguage; - - LCID GetLCID() const; -}; - -class CBDAChannel -{ -public: - CBDAChannel() = default; - CBDAChannel(CString strChannel); - ~CBDAChannel() = default; - - CString ToString() const; - /** - * @brief Output a JSON representation of a BDA channel. - * @note The object contains two elements : "index", which corresponds to - * @c m_nPrefNumber, and "name", which contains @c m_strName. - * @returns A string representing a JSON object containing the - * aforementioned elements. - */ - CStringA ToJSON() const; - - LPCTSTR GetName() const { return m_strName; }; - ULONG GetFrequency() const { return m_ulFrequency; }; - ULONG GetBandwidth() const { return m_ulBandwidth; } - ULONG GetSymbolRate() const { return m_ulSymbolRate; } - int GetPrefNumber() const { return m_nPrefNumber; }; - int GetOriginNumber() const { return m_nOriginNumber; }; - ULONG GetONID() const { return m_ulONID; }; - ULONG GetTSID() const { return m_ulTSID; }; - ULONG GetSID() const { return m_ulSID; }; - ULONG GetPMT() const { return m_ulPMT; }; - ULONG GetPCR() const { return m_ulPCR; }; - ULONG GetVideoPID() const { return m_ulVideoPID; }; - BDA_FPS_TYPE GetVideoFps() const { return m_nVideoFps; } - CString GetVideoFpsDesc(); - BDA_CHROMA_TYPE GetVideoChroma() const { return m_nVideoChroma; } - ULONG GetVideoWidth() const {return m_nVideoWidth; } - ULONG GetVideoHeight() const {return m_nVideoHeight; } - BDA_AspectRatio_TYPE GetVideoAR() {return m_nVideoAR; } - DWORD GetVideoARx(); - DWORD GetVideoARy(); - BDA_STREAM_TYPE GetVideoType() const { return m_nVideoType; } - ULONG GetDefaultAudioPID() const { return m_Audios[GetDefaultAudio()].ulPID; }; - BDA_STREAM_TYPE GetDefaultAudioType() const { return m_Audios[GetDefaultAudio()].nType; } - ULONG GetDefaultSubtitlePID() const { return m_Subtitles[GetDefaultSubtitle()].ulPID; }; - int GetAudioCount() const { return m_nAudioCount; }; - int GetDefaultAudio() const { return m_nDefaultAudio; }; - int GetSubtitleCount() const { return m_nSubtitleCount; }; - int GetDefaultSubtitle() const { return m_nDefaultSubtitle; }; - BDAStreamInfo* GetAudio(int nIndex) { return &m_Audios[nIndex]; }; - const BDAStreamInfo* GetAudio(int nIndex) const { return &m_Audios[nIndex]; }; - BDAStreamInfo* GetSubtitle(int nIndex) { return &m_Subtitles[nIndex]; }; - const BDAStreamInfo* GetSubtitle(int nIndex) const { return &m_Subtitles[nIndex]; }; - bool HasName() const { return !m_strName.IsEmpty(); }; - bool IsEncrypted() const { return m_bEncrypted; }; - bool GetNowNextFlag() const { return m_bNowNextFlag; }; - REFERENCE_TIME GetAvgTimePerFrame(); - - void SetName(LPCTSTR Value) { m_strName = Value; }; - void SetFrequency(ULONG Value) { m_ulFrequency = Value; }; - void SetBandwidth(ULONG ulBandwidth) { m_ulBandwidth = ulBandwidth; } - void SetSymbolRate(ULONG ulSymbolRate) { m_ulSymbolRate = ulSymbolRate; } - void SetPrefNumber(int Value) { m_nPrefNumber = Value; }; - void SetOriginNumber(int Value) { m_nOriginNumber = Value; }; - void SetEncrypted(bool Value) { m_bEncrypted = Value; }; - void SetNowNextFlag(bool Value) { m_bNowNextFlag = Value; }; - void SetONID(ULONG Value) { m_ulONID = Value; }; - void SetTSID(ULONG Value) { m_ulTSID = Value; }; - void SetSID(ULONG Value) { m_ulSID = Value; }; - void SetPMT(ULONG Value) { m_ulPMT = Value; }; - void SetPCR(ULONG Value) { m_ulPCR = Value; }; - void SetVideoPID(ULONG Value) { m_ulVideoPID = Value; }; - void SetVideoFps(BDA_FPS_TYPE Value) { m_nVideoFps = Value; }; - void SetVideoChroma(BDA_CHROMA_TYPE Value) { m_nVideoChroma = Value; }; - void SetVideoWidth(ULONG Value) { m_nVideoWidth = Value; }; - void SetVideoHeight(ULONG Value) { m_nVideoHeight = Value; }; - void SetVideoAR(BDA_AspectRatio_TYPE Value) { m_nVideoAR = Value; }; - void SetDefaultAudio(int Value) { m_nDefaultAudio = Value; } - void SetDefaultSubtitle(int Value) { m_nDefaultSubtitle = Value; } - - void AddStreamInfo(ULONG ulPID, BDA_STREAM_TYPE nType, PES_STREAM_TYPE nPesType, LPCTSTR strLanguage); - - bool operator < (CBDAChannel const& channel) const { - int aOriginNumber = GetOriginNumber(); - int bOriginNumber = channel.GetOriginNumber(); - return (aOriginNumber == 0 && bOriginNumber == 0) ? GetPrefNumber() < channel.GetPrefNumber() : (aOriginNumber == 0 || bOriginNumber == 0) ? bOriginNumber == 0 : aOriginNumber < bOriginNumber; - } - - // Returns true for channels with the same place, doesn't necessarily need to be equal (i.e if internal streams were updated) - bool operator==(CBDAChannel const& channel) const { - return GetPMT() == channel.GetPMT() && GetFrequency() == channel.GetFrequency(); - } - -private: - CString m_strName; - ULONG m_ulFrequency = 0; - ULONG m_ulBandwidth = 0; - ULONG m_ulSymbolRate = 0; - int m_nPrefNumber = 0; - int m_nOriginNumber = 0; - bool m_bEncrypted = false; - bool m_bNowNextFlag = false; - ULONG m_ulONID = 0; - ULONG m_ulTSID = 0; - ULONG m_ulSID = 0; - ULONG m_ulPMT = 0; - ULONG m_ulPCR = 0; - ULONG m_ulVideoPID = 0; - BDA_STREAM_TYPE m_nVideoType = BDA_MPV; - BDA_FPS_TYPE m_nVideoFps = BDA_FPS_25_0; - BDA_CHROMA_TYPE m_nVideoChroma = BDA_Chroma_4_2_0; - ULONG m_nVideoWidth = 0; - ULONG m_nVideoHeight = 0; - BDA_AspectRatio_TYPE m_nVideoAR = BDA_AR_NULL; - int m_nAudioCount = 0; - int m_nDefaultAudio = 0; - int m_nSubtitleCount = 0; - int m_nDefaultSubtitle = -1; - std::array m_Audios; - std::array m_Subtitles; - - void FromString(CString strValue); -}; +/* + * (C) 2009-2016 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 . + * + */ + +#pragma once + +#include +#include + +#define FORMAT_VERSION_0 0 +#define FORMAT_VERSION_1 1 +#define FORMAT_VERSION_2 2 +#define FORMAT_VERSION_3 3 +#define FORMAT_VERSION_4 4 +#define FORMAT_VERSION_5 5 +#define FORMAT_VERSION_CURRENT 6 + +#define BDA_MAX_AUDIO 10 +#define BDA_MAX_SUBTITLE 10 + +struct EventDescriptor { + CString eventName; + CString eventDesc; + time_t startTime = 0; + time_t duration = 0; + CString strStartTime; + CString strEndTime; + std::vector> extendedDescriptorsItems; + CString extendedDescriptorsText; + int parentalRating = -1; + CString content; +}; + +enum BDA_STREAM_TYPE { + BDA_MPV = 0x00, + BDA_H264 = 0x01, + BDA_MPA = 0x02, + BDA_AC3 = 0x03, + BDA_EAC3 = 0x04, + BDA_HEVC = 0x05, + BDA_ADTS = 0x10, + BDA_LATM = 0x11, + BDA_PSI = 0x80, + BDA_TIF = 0x81, + BDA_EPG = 0x82, + BDA_SUB = 0x83, + BDA_SUBTITLE = 0xFE, + BDA_UNKNOWN = 0xFF +}; + +enum BDA_CHROMA_TYPE { + BDA_Chroma_NONE = 0x00, + BDA_Chroma_4_2_0 = 0x01, + BDA_Chroma_4_2_2 = 0x02, + BDA_Chroma_4_4_4 = 0x03 +}; + +enum BDA_FPS_TYPE { + BDA_FPS_NONE = 0x00, + BDA_FPS_23_976 = 0x01, + BDA_FPS_24_0 = 0x02, + BDA_FPS_25_0 = 0x03, + BDA_FPS_29_97 = 0x04, + BDA_FPS_30_0 = 0x05, + BDA_FPS_50_0 = 0x06, + BDA_FPS_59_94 = 0x07, + BDA_FPS_60_0 = 0x08 +}; + +enum BDA_AspectRatio_TYPE { + BDA_AR_NULL = 0x00, + BDA_AR_1 = 0x01, + BDA_AR_3_4 = 0x02, + BDA_AR_9_16 = 0x03, + BDA_AR_1_2_21 = 0x04 +}; + +struct BDAStreamInfo { + ULONG ulPID = 0; + BDA_STREAM_TYPE nType = BDA_UNKNOWN; + PES_STREAM_TYPE nPesType = INVALID; + CString sLanguage; + + LCID GetLCID() const; +}; + +class CBDAChannel +{ +public: + CBDAChannel() = default; + CBDAChannel(CString strChannel); + ~CBDAChannel() = default; + + CString ToString() const; + /** + * @brief Output a JSON representation of a BDA channel. + * @note The object contains two elements : "index", which corresponds to + * @c m_nPrefNumber, and "name", which contains @c m_strName. + * @returns A string representing a JSON object containing the + * aforementioned elements. + */ + CStringA ToJSON() const; + + LPCTSTR GetName() const { return m_strName; }; + ULONG GetFrequency() const { return m_ulFrequency; }; + ULONG GetBandwidth() const { return m_ulBandwidth; } + ULONG GetSymbolRate() const { return m_ulSymbolRate; } + int GetPrefNumber() const { return m_nPrefNumber; }; + int GetOriginNumber() const { return m_nOriginNumber; }; + ULONG GetONID() const { return m_ulONID; }; + ULONG GetTSID() const { return m_ulTSID; }; + ULONG GetSID() const { return m_ulSID; }; + ULONG GetPMT() const { return m_ulPMT; }; + ULONG GetPCR() const { return m_ulPCR; }; + ULONG GetVideoPID() const { return m_ulVideoPID; }; + BDA_FPS_TYPE GetVideoFps() const { return m_nVideoFps; } + CString GetVideoFpsDesc(); + BDA_CHROMA_TYPE GetVideoChroma() const { return m_nVideoChroma; } + ULONG GetVideoWidth() const {return m_nVideoWidth; } + ULONG GetVideoHeight() const {return m_nVideoHeight; } + BDA_AspectRatio_TYPE GetVideoAR() {return m_nVideoAR; } + DWORD GetVideoARx(); + DWORD GetVideoARy(); + BDA_STREAM_TYPE GetVideoType() const { return m_nVideoType; } + ULONG GetDefaultAudioPID() const { return m_Audios[GetDefaultAudio()].ulPID; }; + BDA_STREAM_TYPE GetDefaultAudioType() const { return m_Audios[GetDefaultAudio()].nType; } + ULONG GetDefaultSubtitlePID() const { return m_Subtitles[GetDefaultSubtitle()].ulPID; }; + int GetAudioCount() const { return m_nAudioCount; }; + int GetDefaultAudio() const { return m_nDefaultAudio; }; + int GetSubtitleCount() const { return m_nSubtitleCount; }; + int GetDefaultSubtitle() const { return m_nDefaultSubtitle; }; + BDAStreamInfo* GetAudio(int nIndex) { return &m_Audios[nIndex]; }; + const BDAStreamInfo* GetAudio(int nIndex) const { return &m_Audios[nIndex]; }; + BDAStreamInfo* GetSubtitle(int nIndex) { return &m_Subtitles[nIndex]; }; + const BDAStreamInfo* GetSubtitle(int nIndex) const { return &m_Subtitles[nIndex]; }; + bool HasName() const { return !m_strName.IsEmpty(); }; + bool IsEncrypted() const { return m_bEncrypted; }; + bool GetNowNextFlag() const { return m_bNowNextFlag; }; + REFERENCE_TIME GetAvgTimePerFrame(); + + void SetName(LPCTSTR Value) { m_strName = Value; }; + void SetFrequency(ULONG Value) { m_ulFrequency = Value; }; + void SetBandwidth(ULONG ulBandwidth) { m_ulBandwidth = ulBandwidth; } + void SetSymbolRate(ULONG ulSymbolRate) { m_ulSymbolRate = ulSymbolRate; } + void SetPrefNumber(int Value) { m_nPrefNumber = Value; }; + void SetOriginNumber(int Value) { m_nOriginNumber = Value; }; + void SetEncrypted(bool Value) { m_bEncrypted = Value; }; + void SetNowNextFlag(bool Value) { m_bNowNextFlag = Value; }; + void SetONID(ULONG Value) { m_ulONID = Value; }; + void SetTSID(ULONG Value) { m_ulTSID = Value; }; + void SetSID(ULONG Value) { m_ulSID = Value; }; + void SetPMT(ULONG Value) { m_ulPMT = Value; }; + void SetPCR(ULONG Value) { m_ulPCR = Value; }; + void SetVideoPID(ULONG Value) { m_ulVideoPID = Value; }; + void SetVideoFps(BDA_FPS_TYPE Value) { m_nVideoFps = Value; }; + void SetVideoChroma(BDA_CHROMA_TYPE Value) { m_nVideoChroma = Value; }; + void SetVideoWidth(ULONG Value) { m_nVideoWidth = Value; }; + void SetVideoHeight(ULONG Value) { m_nVideoHeight = Value; }; + void SetVideoAR(BDA_AspectRatio_TYPE Value) { m_nVideoAR = Value; }; + void SetDefaultAudio(int Value) { m_nDefaultAudio = Value; } + void SetDefaultSubtitle(int Value) { m_nDefaultSubtitle = Value; } + + void AddStreamInfo(ULONG ulPID, BDA_STREAM_TYPE nType, PES_STREAM_TYPE nPesType, LPCTSTR strLanguage); + + bool operator < (CBDAChannel const& channel) const { + int aOriginNumber = GetOriginNumber(); + int bOriginNumber = channel.GetOriginNumber(); + return (aOriginNumber == 0 && bOriginNumber == 0) ? GetPrefNumber() < channel.GetPrefNumber() : (aOriginNumber == 0 || bOriginNumber == 0) ? bOriginNumber == 0 : aOriginNumber < bOriginNumber; + } + + // Returns true for channels with the same place, doesn't necessarily need to be equal (i.e if internal streams were updated) + bool operator==(CBDAChannel const& channel) const { + return GetPMT() == channel.GetPMT() && GetFrequency() == channel.GetFrequency(); + } + +private: + CString m_strName; + ULONG m_ulFrequency = 0; + ULONG m_ulBandwidth = 0; + ULONG m_ulSymbolRate = 0; + int m_nPrefNumber = 0; + int m_nOriginNumber = 0; + bool m_bEncrypted = false; + bool m_bNowNextFlag = false; + ULONG m_ulONID = 0; + ULONG m_ulTSID = 0; + ULONG m_ulSID = 0; + ULONG m_ulPMT = 0; + ULONG m_ulPCR = 0; + ULONG m_ulVideoPID = 0; + BDA_STREAM_TYPE m_nVideoType = BDA_MPV; + BDA_FPS_TYPE m_nVideoFps = BDA_FPS_25_0; + BDA_CHROMA_TYPE m_nVideoChroma = BDA_Chroma_4_2_0; + ULONG m_nVideoWidth = 0; + ULONG m_nVideoHeight = 0; + BDA_AspectRatio_TYPE m_nVideoAR = BDA_AR_NULL; + int m_nAudioCount = 0; + int m_nDefaultAudio = 0; + int m_nSubtitleCount = 0; + int m_nDefaultSubtitle = -1; + std::array m_Audios; + std::array m_Subtitles; + + void FromString(CString strValue); +}; diff --git a/src/mpc-hc/DeinterlacerFilter.cpp b/src/mpc-hc/DeinterlacerFilter.cpp index 938e542f624..615ae25ca71 100644 --- a/src/mpc-hc/DeinterlacerFilter.cpp +++ b/src/mpc-hc/DeinterlacerFilter.cpp @@ -1,170 +1,170 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#include "stdafx.h" -#include "DeinterlacerFilter.h" -#include "MediaTypes.h" -#include "moreuuids.h" - - -CDeinterlacerFilter::CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr) - : CTransformFilter(NAME("CDeinterlacerFilter"), punk, __uuidof(CDeinterlacerFilter)) -{ - if (phr) { - *phr = S_OK; - } -} - -HRESULT CDeinterlacerFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin) -{ - return GetCLSID(pPin) == __uuidof(*this) ? E_FAIL : S_OK; -} - -HRESULT CDeinterlacerFilter::CheckInputType(const CMediaType* mtIn) -{ - if (mtIn->majortype != MEDIATYPE_Video) { - return E_FAIL; - } - if (mtIn->formattype == FORMAT_VideoInfo2) { - VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mtIn->pbFormat; - if (!(vih2->dwInterlaceFlags & AMINTERLACE_IsInterlaced)) { - return E_FAIL; - } - } - - BITMAPINFOHEADER bih; - if (!ExtractBIH(mtIn, &bih) || bih.biWidth == 0 || bih.biHeight <= 288) { - return E_FAIL; - } - - return mtIn->subtype == MEDIASUBTYPE_YUY2 || mtIn->subtype == MEDIASUBTYPE_UYVY - || mtIn->subtype == MEDIASUBTYPE_I420 || mtIn->subtype == MEDIASUBTYPE_YV12 || mtIn->subtype == MEDIASUBTYPE_IYUV - ? S_OK - : E_FAIL; -} - -HRESULT CDeinterlacerFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) -{ - return mtIn->subtype == mtOut->subtype ? S_OK : E_FAIL; -} - -HRESULT CDeinterlacerFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) -{ - HRESULT hr; - - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pOut->GetMediaType(&pmt)) && pmt) { - CMediaType mt = *pmt; - m_pOutput->SetMediaType(&mt); - DeleteMediaType(pmt); - } - - BYTE* pDataIn = nullptr; - if (FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn) { - return S_FALSE; - } - - BYTE* pDataOut = nullptr; - if (FAILED(hr = pOut->GetPointer(&pDataOut)) || !pDataOut) { - return hr; - } - - const CMediaType& mtIn = m_pInput->CurrentMediaType(); - const CMediaType& mtOut = m_pOutput->CurrentMediaType(); - - BITMAPINFOHEADER bihIn, bihOut; - ExtractBIH(&mtIn, &bihIn); - ExtractBIH(&mtOut, &bihOut); - - bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3; - bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3; - bool fFlip = fInputFlipped != fOutputFlipped; - - int bppIn = !(bihIn.biBitCount & 7) ? bihIn.biBitCount : 8; - int bppOut = !(bihOut.biBitCount & 7) ? bihOut.biBitCount : 8; - int pitchIn = bihIn.biWidth * bppIn >> 3; - int pitchOut = bihOut.biWidth * bppOut >> 3; - - if (fFlip) { - pitchOut = -pitchOut; - } - - if (mtIn.subtype == MEDIASUBTYPE_YUY2 || mtIn.subtype == MEDIASUBTYPE_UYVY) { - DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); - } else if (mtIn.subtype == MEDIASUBTYPE_I420 || mtIn.subtype == MEDIASUBTYPE_YV12 || mtIn.subtype == MEDIASUBTYPE_IYUV) { - DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); - - int sizeIn = bihIn.biHeight * pitchIn, sizeOut = abs(bihOut.biHeight) * pitchOut; - pitchIn /= 2; - pitchOut /= 2; - bihIn.biHeight /= 2; - pDataIn += sizeIn; - pDataOut += sizeOut; - DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); - - pDataIn += sizeIn / 4; - pDataOut += sizeOut / 4; - DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); - } - - return S_OK; -} - -HRESULT CDeinterlacerFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - BITMAPINFOHEADER bih; - ExtractBIH(&m_pOutput->CurrentMediaType(), &bih); - - pProperties->cBuffers = 1; - pProperties->cbBuffer = bih.biSizeImage; - pProperties->cbAlign = 1; - pProperties->cbPrefix = 0; - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR; -} - -HRESULT CDeinterlacerFilter::GetMediaType(int iPosition, CMediaType* pmt) -{ - if (m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - *pmt = m_pInput->CurrentMediaType(); - CorrectMediaType(pmt); - return S_OK; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#include "stdafx.h" +#include "DeinterlacerFilter.h" +#include "MediaTypes.h" +#include "moreuuids.h" + + +CDeinterlacerFilter::CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr) + : CTransformFilter(NAME("CDeinterlacerFilter"), punk, __uuidof(CDeinterlacerFilter)) +{ + if (phr) { + *phr = S_OK; + } +} + +HRESULT CDeinterlacerFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin) +{ + return GetCLSID(pPin) == __uuidof(*this) ? E_FAIL : S_OK; +} + +HRESULT CDeinterlacerFilter::CheckInputType(const CMediaType* mtIn) +{ + if (mtIn->majortype != MEDIATYPE_Video) { + return E_FAIL; + } + if (mtIn->formattype == FORMAT_VideoInfo2) { + VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)mtIn->pbFormat; + if (!(vih2->dwInterlaceFlags & AMINTERLACE_IsInterlaced)) { + return E_FAIL; + } + } + + BITMAPINFOHEADER bih; + if (!ExtractBIH(mtIn, &bih) || bih.biWidth == 0 || bih.biHeight <= 288) { + return E_FAIL; + } + + return mtIn->subtype == MEDIASUBTYPE_YUY2 || mtIn->subtype == MEDIASUBTYPE_UYVY + || mtIn->subtype == MEDIASUBTYPE_I420 || mtIn->subtype == MEDIASUBTYPE_YV12 || mtIn->subtype == MEDIASUBTYPE_IYUV + ? S_OK + : E_FAIL; +} + +HRESULT CDeinterlacerFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) +{ + return mtIn->subtype == mtOut->subtype ? S_OK : E_FAIL; +} + +HRESULT CDeinterlacerFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) +{ + HRESULT hr; + + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pOut->GetMediaType(&pmt)) && pmt) { + CMediaType mt = *pmt; + m_pOutput->SetMediaType(&mt); + DeleteMediaType(pmt); + } + + BYTE* pDataIn = nullptr; + if (FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn) { + return S_FALSE; + } + + BYTE* pDataOut = nullptr; + if (FAILED(hr = pOut->GetPointer(&pDataOut)) || !pDataOut) { + return hr; + } + + const CMediaType& mtIn = m_pInput->CurrentMediaType(); + const CMediaType& mtOut = m_pOutput->CurrentMediaType(); + + BITMAPINFOHEADER bihIn, bihOut; + ExtractBIH(&mtIn, &bihIn); + ExtractBIH(&mtOut, &bihOut); + + bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3; + bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3; + bool fFlip = fInputFlipped != fOutputFlipped; + + int bppIn = !(bihIn.biBitCount & 7) ? bihIn.biBitCount : 8; + int bppOut = !(bihOut.biBitCount & 7) ? bihOut.biBitCount : 8; + int pitchIn = bihIn.biWidth * bppIn >> 3; + int pitchOut = bihOut.biWidth * bppOut >> 3; + + if (fFlip) { + pitchOut = -pitchOut; + } + + if (mtIn.subtype == MEDIASUBTYPE_YUY2 || mtIn.subtype == MEDIASUBTYPE_UYVY) { + DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); + } else if (mtIn.subtype == MEDIASUBTYPE_I420 || mtIn.subtype == MEDIASUBTYPE_YV12 || mtIn.subtype == MEDIASUBTYPE_IYUV) { + DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); + + int sizeIn = bihIn.biHeight * pitchIn, sizeOut = abs(bihOut.biHeight) * pitchOut; + pitchIn /= 2; + pitchOut /= 2; + bihIn.biHeight /= 2; + pDataIn += sizeIn; + pDataOut += sizeOut; + DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); + + pDataIn += sizeIn / 4; + pDataOut += sizeOut / 4; + DeinterlaceBlend(pDataOut, pDataIn, pitchIn, bihIn.biHeight, pitchOut, pitchIn); + } + + return S_OK; +} + +HRESULT CDeinterlacerFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + BITMAPINFOHEADER bih; + ExtractBIH(&m_pOutput->CurrentMediaType(), &bih); + + pProperties->cBuffers = 1; + pProperties->cbBuffer = bih.biSizeImage; + pProperties->cbAlign = 1; + pProperties->cbPrefix = 0; + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR; +} + +HRESULT CDeinterlacerFilter::GetMediaType(int iPosition, CMediaType* pmt) +{ + if (m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + *pmt = m_pInput->CurrentMediaType(); + CorrectMediaType(pmt); + return S_OK; +} diff --git a/src/mpc-hc/DeinterlacerFilter.h b/src/mpc-hc/DeinterlacerFilter.h index 74b76012f3d..30ed0d6bccf 100644 --- a/src/mpc-hc/DeinterlacerFilter.h +++ b/src/mpc-hc/DeinterlacerFilter.h @@ -1,37 +1,37 @@ -/* - * (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 . - * - */ - -#pragma once - -class __declspec(uuid("96F3E0BE-1BA4-4E79-973D-191FE425C86B")) - CDeinterlacerFilter : public CTransformFilter -{ -protected: - HRESULT CheckConnect(PIN_DIRECTION dir, IPin* pPin); - HRESULT CheckInputType(const CMediaType* mtIn); - HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); - HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - -public: - CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr); -}; +/* + * (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 . + * + */ + +#pragma once + +class __declspec(uuid("96F3E0BE-1BA4-4E79-973D-191FE425C86B")) + CDeinterlacerFilter : public CTransformFilter +{ +protected: + HRESULT CheckConnect(PIN_DIRECTION dir, IPin* pPin); + HRESULT CheckInputType(const CMediaType* mtIn); + HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); + HRESULT Transform(IMediaSample* pIn, IMediaSample* pOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + +public: + CDeinterlacerFilter(LPUNKNOWN punk, HRESULT* phr); +}; diff --git a/src/mpc-hc/EditListEditor.cpp b/src/mpc-hc/EditListEditor.cpp index 4ebc48a1ad9..c88eda78a7b 100644 --- a/src/mpc-hc/EditListEditor.cpp +++ b/src/mpc-hc/EditListEditor.cpp @@ -1,662 +1,662 @@ -/* - * (C) 2009-2018 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 . - * - */ - -#include "stdafx.h" -#include "resource.h" -#include "EditListEditor.h" -#include "DSUtil.h" - - -CClip::CClip() - : m_rtIn(_I64_MIN) - , m_rtOut(_I64_MIN) -{ -} - -CClip::~CClip() -{ -} - -void CClip::SetIn(LPCTSTR strVal) -{ - m_rtIn = StringToReftime(strVal); -} - -void CClip::SetOut(LPCTSTR strVal) -{ - m_rtOut = StringToReftime(strVal); -} - -void CClip::SetIn(REFERENCE_TIME rtVal) -{ - m_rtIn = rtVal; - if (m_rtIn > m_rtOut) { - m_rtOut = _I64_MIN; - } -}; - -void CClip::SetOut(REFERENCE_TIME rtVal) -{ - m_rtOut = rtVal; - if (m_rtIn > m_rtOut) { - m_rtIn = _I64_MIN; - } -}; - -CString CClip::GetIn() const -{ - return m_rtIn == _I64_MIN ? CString() : ReftimeToString(m_rtIn); -} - -CString CClip::GetOut() const -{ - return m_rtOut == _I64_MIN ? CString() : ReftimeToString(m_rtOut); -} - -IMPLEMENT_DYNAMIC(CEditListEditor, CPlayerBar) -CEditListEditor::CEditListEditor() - : m_curPos(nullptr) - , m_bDragging(FALSE) - , m_nDragIndex(-1) - , m_nDropIndex(-1) - , m_pDragImage(nullptr) - , m_bFileOpen(false) -{ -} - -CEditListEditor::~CEditListEditor() -{ - SaveEditListToFile(); -} - -BEGIN_MESSAGE_MAP(CEditListEditor, CPlayerBar) - ON_WM_SIZE() - ON_NOTIFY(LVN_ITEMCHANGED, IDC_EDITLIST, OnLvnItemchanged) - ON_NOTIFY(LVN_KEYDOWN, IDC_EDITLIST, OnLvnKeyDown) - ON_WM_DRAWITEM() - ON_NOTIFY(LVN_BEGINDRAG, IDC_EDITLIST, OnBeginDrag) - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONUP() - ON_WM_TIMER() - ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_EDITLIST, OnBeginlabeleditList) - ON_NOTIFY(LVN_DOLABELEDIT, IDC_EDITLIST, OnDolabeleditList) - ON_NOTIFY(LVN_ENDLABELEDIT, IDC_EDITLIST, OnEndlabeleditList) -END_MESSAGE_MAP() - -BOOL CEditListEditor::Create(CWnd* pParentWnd, UINT defDockBarID) -{ - if (!__super::Create(ResStr(IDS_EDIT_LIST_EDITOR), pParentWnd, ID_VIEW_EDITLISTEDITOR, defDockBarID, _T("Edit List Editor"))) { - return FALSE; - } - - m_stUsers.Create(_T("User :"), WS_VISIBLE | WS_CHILD, CRect(5, 5, 100, 21), this, 0); - m_cbUsers.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(90, 0, 260, 21), this, 0); - FillCombo(_T("Users.txt"), m_cbUsers, false); - - m_stHotFolders.Create(_T("Hot folder :"), WS_VISIBLE | WS_CHILD, CRect(5, 35, 100, 51), this, 0); - m_cbHotFolders.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(90, 30, 260, 21), this, 0); - FillCombo(_T("HotFolders.txt"), m_cbHotFolders, true); - - m_list.CreateEx( - WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP - | LVS_OWNERDRAWFIXED - | LVS_REPORT | LVS_SINGLESEL | LVS_AUTOARRANGE | LVS_NOSORTHEADER, - CRect(0, 0, 100, 100), this, IDC_EDITLIST); - - m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); - - m_list.InsertColumn(COL_IN, _T("Nb."), LVCFMT_LEFT, 35); - m_list.InsertColumn(COL_IN, _T("In"), LVCFMT_LEFT, 100); - m_list.InsertColumn(COL_OUT, _T("Out"), LVCFMT_LEFT, 100); - m_list.InsertColumn(COL_NAME, _T("Name"), LVCFMT_LEFT, 150); - - m_fakeImageList.Create(1, 16, ILC_COLOR4, 10, 10); - m_list.SetImageList(&m_fakeImageList, LVSIL_SMALL); - - return TRUE; -} - -void CEditListEditor::ReloadTranslatableResources() -{ - SetWindowText(ResStr(IDS_EDIT_LIST_EDITOR)); -} - -void CEditListEditor::OnSize(UINT nType, int cx, int cy) -{ - __super::OnSize(nType, cx, cy); - - ResizeListColumn(); -} - -void CEditListEditor::ResizeListColumn() -{ - if (::IsWindow(m_list.m_hWnd)) { - CRect r; - GetClientRect(r); - r.DeflateRect(2, 2); - - r.top += 60; - m_list.SetRedraw(FALSE); - m_list.MoveWindow(r); - m_list.GetClientRect(r); - m_list.SetRedraw(TRUE); - } -} - -void CEditListEditor::SaveEditListToFile() -{ - if ((m_bFileOpen || !m_editList.IsEmpty()) && !m_strFileName.IsEmpty()) { - CStdioFile editListFile; - if (editListFile.Open(m_strFileName, CFile::modeCreate | CFile::modeWrite)) { - CString strLine; - int nIndex; - CString strUser; - CString strHotFolders; - - nIndex = m_cbUsers.GetCurSel(); - if (nIndex >= 0) { - m_cbUsers.GetLBText(nIndex, strUser); - } - - nIndex = m_cbHotFolders.GetCurSel(); - if (nIndex >= 0) { - m_cbHotFolders.GetLBText(nIndex, strHotFolders); - } - - POSITION pos = m_editList.GetHeadPosition(); - for (int i = 0; pos; i++, m_editList.GetNext(pos)) { - CClip& CurClip = m_editList.GetAt(pos); - - if (CurClip.HaveIn() && CurClip.HaveOut()) { - strLine.Format(_T("%s\t%s\t%s\t%s\t%s\n"), CurClip.GetIn().GetString(), CurClip.GetOut().GetString(), CurClip.GetName().GetString(), strUser.GetString(), strHotFolders.GetString()); - editListFile.WriteString(strLine); - } - } - - editListFile.Close(); - } - } -} - -void CEditListEditor::CloseFile() -{ - SaveEditListToFile(); - m_editList.RemoveAll(); - m_list.DeleteAllItems(); - m_curPos = nullptr; - m_strFileName.Empty(); - m_bFileOpen = false; - m_cbHotFolders.SetCurSel(0); -} - -void CEditListEditor::OpenFile(LPCTSTR lpFileName) -{ - CString strLine; - CStdioFile editListFile; - CString strUser; - CString strHotFolders; - - CloseFile(); - m_strFileName.Format(_T("%s.edl"), lpFileName); - - if (editListFile.Open(m_strFileName, CFile::modeRead)) { - m_bFileOpen = true; - while (editListFile.ReadString(strLine)) { - //int nPos = 0; - CString strIn; // = strLine.Tokenize(_T(" \t"), nPos); - CString strOut; // = strLine.Tokenize(_T(" \t"), nPos); - CString strName; // = strLine.Tokenize(_T(" \t"), nPos); - - AfxExtractSubString(strIn, strLine, 0, _T('\t')); - AfxExtractSubString(strOut, strLine, 1, _T('\t')); - AfxExtractSubString(strName, strLine, 2, _T('\t')); - if (strUser.IsEmpty()) { - AfxExtractSubString(strUser, strLine, 3, _T('\t')); - SelectCombo(strUser, m_cbUsers); - } - if (strHotFolders.IsEmpty()) { - AfxExtractSubString(strHotFolders, strLine, 4, _T('\t')); - SelectCombo(strHotFolders, m_cbHotFolders); - } - - if (!strIn.IsEmpty() && !strOut.IsEmpty()) { - CClip NewClip; - NewClip.SetIn(strIn); - NewClip.SetOut(strOut); - NewClip.SetName(strName); - - InsertClip(nullptr, NewClip); - } - } - - editListFile.Close(); - } else { - m_bFileOpen = false; - } - - if (m_nameList.IsEmpty()) { - CStdioFile nameFile; - CString str; - if (nameFile.Open(_T("EditListNames.txt"), CFile::modeRead)) { - while (nameFile.ReadString(str)) { - m_nameList.Add(str); - } - nameFile.Close(); - } - } -} - -void CEditListEditor::SetIn(REFERENCE_TIME rtIn) -{ - if (m_curPos) { - CClip& curClip = m_editList.GetAt(m_curPos); - - curClip.SetIn(rtIn); - m_list.Invalidate(); - } -} - -void CEditListEditor::SetOut(REFERENCE_TIME rtOut) -{ - if (m_curPos) { - CClip& curClip = m_editList.GetAt(m_curPos); - - curClip.SetOut(rtOut); - m_list.Invalidate(); - } -} - -void CEditListEditor::NewClip(REFERENCE_TIME rtVal) -{ - CClip newClip; - newClip.SetIn(rtVal); - - if (m_curPos) { - CClip& curClip = m_editList.GetAt(m_curPos); - - if (curClip.HaveIn()) { - if (!curClip.HaveOut()) { - curClip.SetOut(rtVal); - } - } - } - m_curPos = InsertClip(m_curPos, newClip); - m_list.Invalidate(); -} - -void CEditListEditor::Save() -{ - SaveEditListToFile(); -} - -POSITION CEditListEditor::InsertClip(POSITION pos, CClip& newClip) -{ - LVITEM lv; - POSITION newClipPos; - - if (pos == nullptr) { - newClipPos = m_editList.AddTail(newClip); - } else { - newClipPos = m_editList.InsertAfter(pos, newClip); - } - - lv.mask = LVIF_STATE | LVIF_TEXT; - lv.iItem = FindIndex(pos); - lv.iSubItem = 0; - lv.pszText = const_cast(_T("")); - lv.state = m_list.GetItemCount() == 0 ? LVIS_SELECTED : 0; - m_list.InsertItem(&lv); - - return newClipPos; -} - -int CEditListEditor::FindIndex(const POSITION pos) const -{ - int iItem = 0; - POSITION curPos = m_editList.GetHeadPosition(); - while (curPos && curPos != pos) { - m_editList.GetNext(curPos); - iItem++; - } - return iItem; -} - -int CEditListEditor::FindNameIndex(LPCTSTR strName) const -{ - int nResult = -1; - - for (int i = 0; i < m_nameList.GetCount(); i++) { - const CString& curName = m_nameList.GetAt(i); - - if (curName == strName) { - nResult = i; - break; - } - } - - return nResult; -} - -void CEditListEditor::FillCombo(LPCTSTR strFileName, CComboBox& combo, bool bAllowNull) -{ - CStdioFile nameFile; - CString str; - if (nameFile.Open(strFileName, CFile::modeRead)) { - if (bAllowNull) { - combo.AddString(_T("")); - } - - while (nameFile.ReadString(str)) { - combo.AddString(str); - } - nameFile.Close(); - } -} - -void CEditListEditor::SelectCombo(LPCTSTR strValue, CComboBox& combo) -{ - for (int i = 0; i < combo.GetCount(); i++) { - CString strTemp; - combo.GetLBText(i, strTemp); - if (strTemp == strValue) { - combo.SetCurSel(i); - break; - } - } -} - -void CEditListEditor::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - if (nIDCtl != IDC_EDITLIST) { - return; - } - - int nItem = lpDrawItemStruct->itemID; - CRect rcItem = lpDrawItemStruct->rcItem; - POSITION pos = m_editList.FindIndex(nItem); - - if (pos) { - bool fSelected = (pos == m_curPos); - UNREFERENCED_PARAMETER(fSelected); - CClip& curClip = m_editList.GetAt(pos); - CString strTemp; - - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - - if (!!m_list.GetItemState(nItem, LVIS_SELECTED)) { - FillRect(pDC->m_hDC, rcItem, CBrush(0xf1dacc)); - FrameRect(pDC->m_hDC, rcItem, CBrush(0xc56a31)); - } else { - FillRect(pDC->m_hDC, rcItem, CBrush(GetSysColor(COLOR_WINDOW))); - } - - COLORREF textcolor = RGB(0, 0, 0); - if (!curClip.HaveIn() || !curClip.HaveOut()) { - textcolor = RGB(255, 0, 0); - } - - for (int i = 0; i < COL_MAX; i++) { - m_list.GetSubItemRect(nItem, i, LVIR_LABEL, rcItem); - pDC->SetTextColor(textcolor); - switch (i) { - case COL_INDEX: - strTemp.Format(_T("%d"), nItem + 1); - pDC->DrawText(strTemp, rcItem, DT_CENTER | DT_VCENTER); - break; - case COL_IN: - pDC->DrawText(curClip.GetIn(), rcItem, DT_CENTER | DT_VCENTER); - break; - case COL_OUT: - pDC->DrawText(curClip.GetOut(), rcItem, DT_CENTER | DT_VCENTER); - break; - case COL_NAME: - pDC->DrawText(curClip.GetName(), rcItem, DT_LEFT | DT_VCENTER); - break; - } - } - } -} - -void CEditListEditor::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); - - if (pNMLV->iItem >= 0) { - m_curPos = m_editList.FindIndex(pNMLV->iItem); - } -} - -void CEditListEditor::OnLvnKeyDown(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMLVKEYDOWN pLVKeyDown = reinterpret_cast(pNMHDR); - - *pResult = FALSE; - - if (pLVKeyDown->wVKey == VK_DELETE) { - POSITION pos = m_list.GetFirstSelectedItemPosition(); - POSITION clipPos; - int nItem = -1; - while (pos) { - nItem = m_list.GetNextSelectedItem(pos); - clipPos = m_editList.FindIndex(nItem); - if (clipPos) { - m_editList.RemoveAt(clipPos); - } - m_list.DeleteItem(nItem); - } - if (nItem != -1) { - m_list.SetItemState(std::min(nItem, m_list.GetItemCount() - 1), LVIS_SELECTED, LVIS_SELECTED); - } - m_list.Invalidate(); - } -} - -void CEditListEditor::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) -{ - ModifyStyle(WS_EX_ACCEPTFILES, 0); - - m_nDragIndex = ((LPNMLISTVIEW)pNMHDR)->iItem; - - CPoint p(0, 0); - m_pDragImage = m_list.CreateDragImageEx(&p); - - CPoint p2 = ((LPNMLISTVIEW)pNMHDR)->ptAction; - - m_pDragImage->BeginDrag(0, p2 - p); - m_pDragImage->DragEnter(GetDesktopWindow(), ((LPNMLISTVIEW)pNMHDR)->ptAction); - - m_bDragging = TRUE; - m_nDropIndex = -1; - - SetCapture(); -} - -void CEditListEditor::OnMouseMove(UINT nFlags, CPoint point) -{ - if (m_bDragging) { - m_ptDropPoint = point; - ClientToScreen(&m_ptDropPoint); - - m_pDragImage->DragMove(m_ptDropPoint); - m_pDragImage->DragShowNolock(FALSE); - - WindowFromPoint(m_ptDropPoint)->ScreenToClient(&m_ptDropPoint); - - m_pDragImage->DragShowNolock(TRUE); - - { - int iOverItem = m_list.HitTest(m_ptDropPoint); - int iTopItem = m_list.GetTopIndex(); - int iBottomItem = m_list.GetBottomIndex(); - - if (iOverItem == iTopItem && iTopItem != 0) { // top of list - SetTimer(1, 100, nullptr); - } else { - KillTimer(1); - } - - if (iOverItem >= iBottomItem && iBottomItem != (m_list.GetItemCount() - 1)) { // bottom of list - SetTimer(2, 100, nullptr); - } else { - KillTimer(2); - } - } - } - - __super::OnMouseMove(nFlags, point); -} - -void CEditListEditor::OnTimer(UINT_PTR nIDEvent) -{ - int iTopItem = m_list.GetTopIndex(); - int iBottomItem = iTopItem + m_list.GetCountPerPage() - 1; - - if (m_bDragging) { - m_pDragImage->DragShowNolock(FALSE); - - if (nIDEvent == 1) { - m_list.EnsureVisible(iTopItem - 1, false); - m_list.UpdateWindow(); - if (m_list.GetTopIndex() == 0) { - KillTimer(1); - } - } else if (nIDEvent == 2) { - m_list.EnsureVisible(iBottomItem + 1, false); - m_list.UpdateWindow(); - if (m_list.GetBottomIndex() == (m_list.GetItemCount() - 1)) { - KillTimer(2); - } - } - - m_pDragImage->DragShowNolock(TRUE); - } - - __super::OnTimer(nIDEvent); -} - -void CEditListEditor::OnLButtonUp(UINT nFlags, CPoint point) -{ - if (m_bDragging) { - ::ReleaseCapture(); - - m_bDragging = FALSE; - m_pDragImage->DragLeave(GetDesktopWindow()); - m_pDragImage->EndDrag(); - - delete m_pDragImage; - m_pDragImage = nullptr; - - KillTimer(1); - KillTimer(2); - - CPoint pt(point); - ClientToScreen(&pt); - - if (WindowFromPoint(pt) == &m_list) { - DropItemOnList(); - } - } - - ModifyStyle(0, WS_EX_ACCEPTFILES); - - __super::OnLButtonUp(nFlags, point); -} - -void CEditListEditor::DropItemOnList() -{ - m_ptDropPoint.y -= 10; - m_nDropIndex = m_list.HitTest(CPoint(10, m_ptDropPoint.y)); - - POSITION dragPos = m_editList.FindIndex(m_nDragIndex); - POSITION dropPos = m_editList.FindIndex(m_nDropIndex); - if (dragPos && dropPos) { - CClip& dragClip = m_editList.GetAt(dragPos); - m_editList.InsertAfter(dropPos, dragClip); - m_editList.RemoveAt(dragPos); - m_list.Invalidate(); - } -} - -void CEditListEditor::OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (pItem->iItem < 0) { - return; - } - - if (pItem->iSubItem == COL_NAME) { - *pResult = TRUE; - } -} - -void CEditListEditor::OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (pItem->iItem < 0) { - return; - } - - if (m_curPos && pItem->iSubItem == COL_NAME) { - CClip& curClip = m_editList.GetAt(m_curPos); - int nSel = FindNameIndex(curClip.GetName()); - - CAtlList sl; - for (int i = 0; i < m_nameList.GetCount(); i++) { - sl.AddTail(m_nameList.GetAt(i)); - } - m_list.ShowInPlaceComboBox(pItem->iItem, pItem->iSubItem, sl, nSel, true); - - *pResult = TRUE; - } -} - -void CEditListEditor::OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (!m_list.m_fInPlaceDirty) { - return; - } - - if (pItem->iItem < 0) { - return; - } - - CString& curName = m_nameList.GetAt(pItem->lParam); - - if (m_curPos && pItem->iSubItem == COL_NAME) { - CClip& curClip = m_editList.GetAt(m_curPos); - curClip.SetName(curName); - - *pResult = TRUE; - } -} +/* + * (C) 2009-2018 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 . + * + */ + +#include "stdafx.h" +#include "resource.h" +#include "EditListEditor.h" +#include "DSUtil.h" + + +CClip::CClip() + : m_rtIn(_I64_MIN) + , m_rtOut(_I64_MIN) +{ +} + +CClip::~CClip() +{ +} + +void CClip::SetIn(LPCTSTR strVal) +{ + m_rtIn = StringToReftime(strVal); +} + +void CClip::SetOut(LPCTSTR strVal) +{ + m_rtOut = StringToReftime(strVal); +} + +void CClip::SetIn(REFERENCE_TIME rtVal) +{ + m_rtIn = rtVal; + if (m_rtIn > m_rtOut) { + m_rtOut = _I64_MIN; + } +}; + +void CClip::SetOut(REFERENCE_TIME rtVal) +{ + m_rtOut = rtVal; + if (m_rtIn > m_rtOut) { + m_rtIn = _I64_MIN; + } +}; + +CString CClip::GetIn() const +{ + return m_rtIn == _I64_MIN ? CString() : ReftimeToString(m_rtIn); +} + +CString CClip::GetOut() const +{ + return m_rtOut == _I64_MIN ? CString() : ReftimeToString(m_rtOut); +} + +IMPLEMENT_DYNAMIC(CEditListEditor, CPlayerBar) +CEditListEditor::CEditListEditor() + : m_curPos(nullptr) + , m_bDragging(FALSE) + , m_nDragIndex(-1) + , m_nDropIndex(-1) + , m_pDragImage(nullptr) + , m_bFileOpen(false) +{ +} + +CEditListEditor::~CEditListEditor() +{ + SaveEditListToFile(); +} + +BEGIN_MESSAGE_MAP(CEditListEditor, CPlayerBar) + ON_WM_SIZE() + ON_NOTIFY(LVN_ITEMCHANGED, IDC_EDITLIST, OnLvnItemchanged) + ON_NOTIFY(LVN_KEYDOWN, IDC_EDITLIST, OnLvnKeyDown) + ON_WM_DRAWITEM() + ON_NOTIFY(LVN_BEGINDRAG, IDC_EDITLIST, OnBeginDrag) + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONUP() + ON_WM_TIMER() + ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_EDITLIST, OnBeginlabeleditList) + ON_NOTIFY(LVN_DOLABELEDIT, IDC_EDITLIST, OnDolabeleditList) + ON_NOTIFY(LVN_ENDLABELEDIT, IDC_EDITLIST, OnEndlabeleditList) +END_MESSAGE_MAP() + +BOOL CEditListEditor::Create(CWnd* pParentWnd, UINT defDockBarID) +{ + if (!__super::Create(ResStr(IDS_EDIT_LIST_EDITOR), pParentWnd, ID_VIEW_EDITLISTEDITOR, defDockBarID, _T("Edit List Editor"))) { + return FALSE; + } + + m_stUsers.Create(_T("User :"), WS_VISIBLE | WS_CHILD, CRect(5, 5, 100, 21), this, 0); + m_cbUsers.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(90, 0, 260, 21), this, 0); + FillCombo(_T("Users.txt"), m_cbUsers, false); + + m_stHotFolders.Create(_T("Hot folder :"), WS_VISIBLE | WS_CHILD, CRect(5, 35, 100, 51), this, 0); + m_cbHotFolders.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, CRect(90, 30, 260, 21), this, 0); + FillCombo(_T("HotFolders.txt"), m_cbHotFolders, true); + + m_list.CreateEx( + WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP + | LVS_OWNERDRAWFIXED + | LVS_REPORT | LVS_SINGLESEL | LVS_AUTOARRANGE | LVS_NOSORTHEADER, + CRect(0, 0, 100, 100), this, IDC_EDITLIST); + + m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); + + m_list.InsertColumn(COL_IN, _T("Nb."), LVCFMT_LEFT, 35); + m_list.InsertColumn(COL_IN, _T("In"), LVCFMT_LEFT, 100); + m_list.InsertColumn(COL_OUT, _T("Out"), LVCFMT_LEFT, 100); + m_list.InsertColumn(COL_NAME, _T("Name"), LVCFMT_LEFT, 150); + + m_fakeImageList.Create(1, 16, ILC_COLOR4, 10, 10); + m_list.SetImageList(&m_fakeImageList, LVSIL_SMALL); + + return TRUE; +} + +void CEditListEditor::ReloadTranslatableResources() +{ + SetWindowText(ResStr(IDS_EDIT_LIST_EDITOR)); +} + +void CEditListEditor::OnSize(UINT nType, int cx, int cy) +{ + __super::OnSize(nType, cx, cy); + + ResizeListColumn(); +} + +void CEditListEditor::ResizeListColumn() +{ + if (::IsWindow(m_list.m_hWnd)) { + CRect r; + GetClientRect(r); + r.DeflateRect(2, 2); + + r.top += 60; + m_list.SetRedraw(FALSE); + m_list.MoveWindow(r); + m_list.GetClientRect(r); + m_list.SetRedraw(TRUE); + } +} + +void CEditListEditor::SaveEditListToFile() +{ + if ((m_bFileOpen || !m_editList.IsEmpty()) && !m_strFileName.IsEmpty()) { + CStdioFile editListFile; + if (editListFile.Open(m_strFileName, CFile::modeCreate | CFile::modeWrite)) { + CString strLine; + int nIndex; + CString strUser; + CString strHotFolders; + + nIndex = m_cbUsers.GetCurSel(); + if (nIndex >= 0) { + m_cbUsers.GetLBText(nIndex, strUser); + } + + nIndex = m_cbHotFolders.GetCurSel(); + if (nIndex >= 0) { + m_cbHotFolders.GetLBText(nIndex, strHotFolders); + } + + POSITION pos = m_editList.GetHeadPosition(); + for (int i = 0; pos; i++, m_editList.GetNext(pos)) { + CClip& CurClip = m_editList.GetAt(pos); + + if (CurClip.HaveIn() && CurClip.HaveOut()) { + strLine.Format(_T("%s\t%s\t%s\t%s\t%s\n"), CurClip.GetIn().GetString(), CurClip.GetOut().GetString(), CurClip.GetName().GetString(), strUser.GetString(), strHotFolders.GetString()); + editListFile.WriteString(strLine); + } + } + + editListFile.Close(); + } + } +} + +void CEditListEditor::CloseFile() +{ + SaveEditListToFile(); + m_editList.RemoveAll(); + m_list.DeleteAllItems(); + m_curPos = nullptr; + m_strFileName.Empty(); + m_bFileOpen = false; + m_cbHotFolders.SetCurSel(0); +} + +void CEditListEditor::OpenFile(LPCTSTR lpFileName) +{ + CString strLine; + CStdioFile editListFile; + CString strUser; + CString strHotFolders; + + CloseFile(); + m_strFileName.Format(_T("%s.edl"), lpFileName); + + if (editListFile.Open(m_strFileName, CFile::modeRead)) { + m_bFileOpen = true; + while (editListFile.ReadString(strLine)) { + //int nPos = 0; + CString strIn; // = strLine.Tokenize(_T(" \t"), nPos); + CString strOut; // = strLine.Tokenize(_T(" \t"), nPos); + CString strName; // = strLine.Tokenize(_T(" \t"), nPos); + + AfxExtractSubString(strIn, strLine, 0, _T('\t')); + AfxExtractSubString(strOut, strLine, 1, _T('\t')); + AfxExtractSubString(strName, strLine, 2, _T('\t')); + if (strUser.IsEmpty()) { + AfxExtractSubString(strUser, strLine, 3, _T('\t')); + SelectCombo(strUser, m_cbUsers); + } + if (strHotFolders.IsEmpty()) { + AfxExtractSubString(strHotFolders, strLine, 4, _T('\t')); + SelectCombo(strHotFolders, m_cbHotFolders); + } + + if (!strIn.IsEmpty() && !strOut.IsEmpty()) { + CClip NewClip; + NewClip.SetIn(strIn); + NewClip.SetOut(strOut); + NewClip.SetName(strName); + + InsertClip(nullptr, NewClip); + } + } + + editListFile.Close(); + } else { + m_bFileOpen = false; + } + + if (m_nameList.IsEmpty()) { + CStdioFile nameFile; + CString str; + if (nameFile.Open(_T("EditListNames.txt"), CFile::modeRead)) { + while (nameFile.ReadString(str)) { + m_nameList.Add(str); + } + nameFile.Close(); + } + } +} + +void CEditListEditor::SetIn(REFERENCE_TIME rtIn) +{ + if (m_curPos) { + CClip& curClip = m_editList.GetAt(m_curPos); + + curClip.SetIn(rtIn); + m_list.Invalidate(); + } +} + +void CEditListEditor::SetOut(REFERENCE_TIME rtOut) +{ + if (m_curPos) { + CClip& curClip = m_editList.GetAt(m_curPos); + + curClip.SetOut(rtOut); + m_list.Invalidate(); + } +} + +void CEditListEditor::NewClip(REFERENCE_TIME rtVal) +{ + CClip newClip; + newClip.SetIn(rtVal); + + if (m_curPos) { + CClip& curClip = m_editList.GetAt(m_curPos); + + if (curClip.HaveIn()) { + if (!curClip.HaveOut()) { + curClip.SetOut(rtVal); + } + } + } + m_curPos = InsertClip(m_curPos, newClip); + m_list.Invalidate(); +} + +void CEditListEditor::Save() +{ + SaveEditListToFile(); +} + +POSITION CEditListEditor::InsertClip(POSITION pos, CClip& newClip) +{ + LVITEM lv; + POSITION newClipPos; + + if (pos == nullptr) { + newClipPos = m_editList.AddTail(newClip); + } else { + newClipPos = m_editList.InsertAfter(pos, newClip); + } + + lv.mask = LVIF_STATE | LVIF_TEXT; + lv.iItem = FindIndex(pos); + lv.iSubItem = 0; + lv.pszText = const_cast(_T("")); + lv.state = m_list.GetItemCount() == 0 ? LVIS_SELECTED : 0; + m_list.InsertItem(&lv); + + return newClipPos; +} + +int CEditListEditor::FindIndex(const POSITION pos) const +{ + int iItem = 0; + POSITION curPos = m_editList.GetHeadPosition(); + while (curPos && curPos != pos) { + m_editList.GetNext(curPos); + iItem++; + } + return iItem; +} + +int CEditListEditor::FindNameIndex(LPCTSTR strName) const +{ + int nResult = -1; + + for (int i = 0; i < m_nameList.GetCount(); i++) { + const CString& curName = m_nameList.GetAt(i); + + if (curName == strName) { + nResult = i; + break; + } + } + + return nResult; +} + +void CEditListEditor::FillCombo(LPCTSTR strFileName, CComboBox& combo, bool bAllowNull) +{ + CStdioFile nameFile; + CString str; + if (nameFile.Open(strFileName, CFile::modeRead)) { + if (bAllowNull) { + combo.AddString(_T("")); + } + + while (nameFile.ReadString(str)) { + combo.AddString(str); + } + nameFile.Close(); + } +} + +void CEditListEditor::SelectCombo(LPCTSTR strValue, CComboBox& combo) +{ + for (int i = 0; i < combo.GetCount(); i++) { + CString strTemp; + combo.GetLBText(i, strTemp); + if (strTemp == strValue) { + combo.SetCurSel(i); + break; + } + } +} + +void CEditListEditor::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (nIDCtl != IDC_EDITLIST) { + return; + } + + int nItem = lpDrawItemStruct->itemID; + CRect rcItem = lpDrawItemStruct->rcItem; + POSITION pos = m_editList.FindIndex(nItem); + + if (pos) { + bool fSelected = (pos == m_curPos); + UNREFERENCED_PARAMETER(fSelected); + CClip& curClip = m_editList.GetAt(pos); + CString strTemp; + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + + if (!!m_list.GetItemState(nItem, LVIS_SELECTED)) { + FillRect(pDC->m_hDC, rcItem, CBrush(0xf1dacc)); + FrameRect(pDC->m_hDC, rcItem, CBrush(0xc56a31)); + } else { + FillRect(pDC->m_hDC, rcItem, CBrush(GetSysColor(COLOR_WINDOW))); + } + + COLORREF textcolor = RGB(0, 0, 0); + if (!curClip.HaveIn() || !curClip.HaveOut()) { + textcolor = RGB(255, 0, 0); + } + + for (int i = 0; i < COL_MAX; i++) { + m_list.GetSubItemRect(nItem, i, LVIR_LABEL, rcItem); + pDC->SetTextColor(textcolor); + switch (i) { + case COL_INDEX: + strTemp.Format(_T("%d"), nItem + 1); + pDC->DrawText(strTemp, rcItem, DT_CENTER | DT_VCENTER); + break; + case COL_IN: + pDC->DrawText(curClip.GetIn(), rcItem, DT_CENTER | DT_VCENTER); + break; + case COL_OUT: + pDC->DrawText(curClip.GetOut(), rcItem, DT_CENTER | DT_VCENTER); + break; + case COL_NAME: + pDC->DrawText(curClip.GetName(), rcItem, DT_LEFT | DT_VCENTER); + break; + } + } + } +} + +void CEditListEditor::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); + + if (pNMLV->iItem >= 0) { + m_curPos = m_editList.FindIndex(pNMLV->iItem); + } +} + +void CEditListEditor::OnLvnKeyDown(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLVKEYDOWN pLVKeyDown = reinterpret_cast(pNMHDR); + + *pResult = FALSE; + + if (pLVKeyDown->wVKey == VK_DELETE) { + POSITION pos = m_list.GetFirstSelectedItemPosition(); + POSITION clipPos; + int nItem = -1; + while (pos) { + nItem = m_list.GetNextSelectedItem(pos); + clipPos = m_editList.FindIndex(nItem); + if (clipPos) { + m_editList.RemoveAt(clipPos); + } + m_list.DeleteItem(nItem); + } + if (nItem != -1) { + m_list.SetItemState(std::min(nItem, m_list.GetItemCount() - 1), LVIS_SELECTED, LVIS_SELECTED); + } + m_list.Invalidate(); + } +} + +void CEditListEditor::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) +{ + ModifyStyle(WS_EX_ACCEPTFILES, 0); + + m_nDragIndex = ((LPNMLISTVIEW)pNMHDR)->iItem; + + CPoint p(0, 0); + m_pDragImage = m_list.CreateDragImageEx(&p); + + CPoint p2 = ((LPNMLISTVIEW)pNMHDR)->ptAction; + + m_pDragImage->BeginDrag(0, p2 - p); + m_pDragImage->DragEnter(GetDesktopWindow(), ((LPNMLISTVIEW)pNMHDR)->ptAction); + + m_bDragging = TRUE; + m_nDropIndex = -1; + + SetCapture(); +} + +void CEditListEditor::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_bDragging) { + m_ptDropPoint = point; + ClientToScreen(&m_ptDropPoint); + + m_pDragImage->DragMove(m_ptDropPoint); + m_pDragImage->DragShowNolock(FALSE); + + WindowFromPoint(m_ptDropPoint)->ScreenToClient(&m_ptDropPoint); + + m_pDragImage->DragShowNolock(TRUE); + + { + int iOverItem = m_list.HitTest(m_ptDropPoint); + int iTopItem = m_list.GetTopIndex(); + int iBottomItem = m_list.GetBottomIndex(); + + if (iOverItem == iTopItem && iTopItem != 0) { // top of list + SetTimer(1, 100, nullptr); + } else { + KillTimer(1); + } + + if (iOverItem >= iBottomItem && iBottomItem != (m_list.GetItemCount() - 1)) { // bottom of list + SetTimer(2, 100, nullptr); + } else { + KillTimer(2); + } + } + } + + __super::OnMouseMove(nFlags, point); +} + +void CEditListEditor::OnTimer(UINT_PTR nIDEvent) +{ + int iTopItem = m_list.GetTopIndex(); + int iBottomItem = iTopItem + m_list.GetCountPerPage() - 1; + + if (m_bDragging) { + m_pDragImage->DragShowNolock(FALSE); + + if (nIDEvent == 1) { + m_list.EnsureVisible(iTopItem - 1, false); + m_list.UpdateWindow(); + if (m_list.GetTopIndex() == 0) { + KillTimer(1); + } + } else if (nIDEvent == 2) { + m_list.EnsureVisible(iBottomItem + 1, false); + m_list.UpdateWindow(); + if (m_list.GetBottomIndex() == (m_list.GetItemCount() - 1)) { + KillTimer(2); + } + } + + m_pDragImage->DragShowNolock(TRUE); + } + + __super::OnTimer(nIDEvent); +} + +void CEditListEditor::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (m_bDragging) { + ::ReleaseCapture(); + + m_bDragging = FALSE; + m_pDragImage->DragLeave(GetDesktopWindow()); + m_pDragImage->EndDrag(); + + delete m_pDragImage; + m_pDragImage = nullptr; + + KillTimer(1); + KillTimer(2); + + CPoint pt(point); + ClientToScreen(&pt); + + if (WindowFromPoint(pt) == &m_list) { + DropItemOnList(); + } + } + + ModifyStyle(0, WS_EX_ACCEPTFILES); + + __super::OnLButtonUp(nFlags, point); +} + +void CEditListEditor::DropItemOnList() +{ + m_ptDropPoint.y -= 10; + m_nDropIndex = m_list.HitTest(CPoint(10, m_ptDropPoint.y)); + + POSITION dragPos = m_editList.FindIndex(m_nDragIndex); + POSITION dropPos = m_editList.FindIndex(m_nDropIndex); + if (dragPos && dropPos) { + CClip& dragClip = m_editList.GetAt(dragPos); + m_editList.InsertAfter(dropPos, dragClip); + m_editList.RemoveAt(dragPos); + m_list.Invalidate(); + } +} + +void CEditListEditor::OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (pItem->iItem < 0) { + return; + } + + if (pItem->iSubItem == COL_NAME) { + *pResult = TRUE; + } +} + +void CEditListEditor::OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (pItem->iItem < 0) { + return; + } + + if (m_curPos && pItem->iSubItem == COL_NAME) { + CClip& curClip = m_editList.GetAt(m_curPos); + int nSel = FindNameIndex(curClip.GetName()); + + CAtlList sl; + for (int i = 0; i < m_nameList.GetCount(); i++) { + sl.AddTail(m_nameList.GetAt(i)); + } + m_list.ShowInPlaceComboBox(pItem->iItem, pItem->iSubItem, sl, nSel, true); + + *pResult = TRUE; + } +} + +void CEditListEditor::OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (!m_list.m_fInPlaceDirty) { + return; + } + + if (pItem->iItem < 0) { + return; + } + + CString& curName = m_nameList.GetAt(pItem->lParam); + + if (m_curPos && pItem->iSubItem == COL_NAME) { + CClip& curClip = m_editList.GetAt(m_curPos); + curClip.SetName(curName); + + *pResult = TRUE; + } +} diff --git a/src/mpc-hc/EditListEditor.h b/src/mpc-hc/EditListEditor.h index 261698cb890..26c3b40dc01 100644 --- a/src/mpc-hc/EditListEditor.h +++ b/src/mpc-hc/EditListEditor.h @@ -1,121 +1,121 @@ -/* - * (C) 2009-2014 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 . - * - */ - -#pragma once - -#include "PlayerBar.h" -#include "PlayerListCtrl.h" - - -class CClip -{ -private: - REFERENCE_TIME m_rtIn; - REFERENCE_TIME m_rtOut; - CString m_strName; - -public: - CClip(); - ~CClip(); - - bool HaveIn() const { return m_rtIn != _I64_MIN; }; - bool HaveOut() const { return m_rtOut != _I64_MIN; }; - - void SetIn(LPCTSTR strVal); - void SetOut(LPCTSTR strVal); - void SetIn(REFERENCE_TIME rtVal); - void SetOut(REFERENCE_TIME rtVal); - void SetName(LPCTSTR strName) { m_strName = strName; }; - - CString GetIn() const; - CString GetOut() const; - CString GetName() const { return m_strName; }; -}; - -class CEditListEditor : public CPlayerBar -{ - DECLARE_DYNAMIC(CEditListEditor) - -private: - enum { - COL_INDEX, - COL_IN, - COL_OUT, - COL_NAME, - COL_MAX - }; - - CPlayerListCtrl m_list; - CStatic m_stUsers; - CComboBox m_cbUsers; - CStatic m_stHotFolders; - CComboBox m_cbHotFolders; - CImageList m_fakeImageList; - POSITION m_curPos; - BOOL m_bDragging; - int m_nDragIndex; - int m_nDropIndex; - CPoint m_ptDropPoint; - CImageList* m_pDragImage; - - CString m_strFileName; - bool m_bFileOpen; - CList m_editList; - CArray m_nameList; - - void SaveEditListToFile(); - void ResizeListColumn(); - POSITION InsertClip(POSITION pos, CClip& newClip); - void DropItemOnList(); - int FindIndex(const POSITION pos) const; - int FindNameIndex(LPCTSTR strName) const; - void FillCombo(LPCTSTR strFileName, CComboBox& combo, bool bAllowNull); - void SelectCombo(LPCTSTR strValue, CComboBox& combo); - -public: - CEditListEditor(); - ~CEditListEditor(); - - BOOL Create(CWnd* pParentWnd, UINT defDockBarID); - - virtual void ReloadTranslatableResources(); - - void CloseFile(); - void OpenFile(LPCTSTR lpFileName); - void SetIn(REFERENCE_TIME rtIn); - void SetOut(REFERENCE_TIME rtOut); - void NewClip(REFERENCE_TIME rtVal); - void Save(); - -protected: - DECLARE_MESSAGE_MAP() - - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnLvnKeyDown(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); - afx_msg void OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnTimer(UINT_PTR nIDEvent); - afx_msg void OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult); -}; +/* + * (C) 2009-2014 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 . + * + */ + +#pragma once + +#include "PlayerBar.h" +#include "PlayerListCtrl.h" + + +class CClip +{ +private: + REFERENCE_TIME m_rtIn; + REFERENCE_TIME m_rtOut; + CString m_strName; + +public: + CClip(); + ~CClip(); + + bool HaveIn() const { return m_rtIn != _I64_MIN; }; + bool HaveOut() const { return m_rtOut != _I64_MIN; }; + + void SetIn(LPCTSTR strVal); + void SetOut(LPCTSTR strVal); + void SetIn(REFERENCE_TIME rtVal); + void SetOut(REFERENCE_TIME rtVal); + void SetName(LPCTSTR strName) { m_strName = strName; }; + + CString GetIn() const; + CString GetOut() const; + CString GetName() const { return m_strName; }; +}; + +class CEditListEditor : public CPlayerBar +{ + DECLARE_DYNAMIC(CEditListEditor) + +private: + enum { + COL_INDEX, + COL_IN, + COL_OUT, + COL_NAME, + COL_MAX + }; + + CPlayerListCtrl m_list; + CStatic m_stUsers; + CComboBox m_cbUsers; + CStatic m_stHotFolders; + CComboBox m_cbHotFolders; + CImageList m_fakeImageList; + POSITION m_curPos; + BOOL m_bDragging; + int m_nDragIndex; + int m_nDropIndex; + CPoint m_ptDropPoint; + CImageList* m_pDragImage; + + CString m_strFileName; + bool m_bFileOpen; + CList m_editList; + CArray m_nameList; + + void SaveEditListToFile(); + void ResizeListColumn(); + POSITION InsertClip(POSITION pos, CClip& newClip); + void DropItemOnList(); + int FindIndex(const POSITION pos) const; + int FindNameIndex(LPCTSTR strName) const; + void FillCombo(LPCTSTR strFileName, CComboBox& combo, bool bAllowNull); + void SelectCombo(LPCTSTR strValue, CComboBox& combo); + +public: + CEditListEditor(); + ~CEditListEditor(); + + BOOL Create(CWnd* pParentWnd, UINT defDockBarID); + + virtual void ReloadTranslatableResources(); + + void CloseFile(); + void OpenFile(LPCTSTR lpFileName); + void SetIn(REFERENCE_TIME rtIn); + void SetOut(REFERENCE_TIME rtOut); + void NewClip(REFERENCE_TIME rtVal); + void Save(); + +protected: + DECLARE_MESSAGE_MAP() + + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnLvnKeyDown(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); + afx_msg void OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnTimer(UINT_PTR nIDEvent); + afx_msg void OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult); +}; diff --git a/src/mpc-hc/EditWithButton.cpp b/src/mpc-hc/EditWithButton.cpp index e31c5ba79c6..64c038672b7 100644 --- a/src/mpc-hc/EditWithButton.cpp +++ b/src/mpc-hc/EditWithButton.cpp @@ -1,363 +1,363 @@ -#include "stdafx.h" -#include "EditWithButton.h" - -#define WM_EDITWITHBUTTON_RECALCNCSIZE (WM_USER + 200) // arbitrary number. hopefully no conflicts - - -// CEditWithButton_Base --------------------------------------------------------------------------- - -CEditWithButton_Base::CEditWithButton_Base() - : m_TopBorder(0) - , m_BottomBorder(0) - , m_LeftBorder(0) - , m_RightBorder(0) - , m_ButtonWidth(1) - , m_IsButtonPressed(false) - , m_IsMouseActive(false) - , m_IsButtonHot(false) -{ -} - -BEGIN_MESSAGE_MAP(CEditWithButton_Base, CEdit) - ON_WM_NCCALCSIZE() - ON_WM_NCPAINT() - ON_WM_NCLBUTTONDOWN() - ON_WM_MOUSEMOVE() - ON_WM_NCMOUSEMOVE() - ON_WM_NCMOUSELEAVE() - ON_WM_LBUTTONUP() - ON_WM_NCHITTEST() - ON_MESSAGE(WM_EDITWITHBUTTON_RECALCNCSIZE, OnRecalcNcSize) - ON_WM_NCDESTROY() - ON_WM_ENABLE() - ON_MESSAGE(EM_SETREADONLY, OnSetReadOnly) -END_MESSAGE_MAP() - -CRect CEditWithButton_Base::GetButtonRect(const CRect& rectWindow) const -{ - CRect rectButton(rectWindow); - rectButton.top += m_TopBorder; - rectButton.bottom -= m_BottomBorder; - rectButton.right -= m_RightBorder; - rectButton.left = rectButton.right - m_ButtonWidth; - - // take into account any scrollbars in the edit control - if (rectButton.right > rectButton.left) { - rectButton.OffsetRect(m_RightBorder - m_LeftBorder, 0); - } - - return rectButton; -} - -int CEditWithButton_Base::GetButtonThemeState() const -{ - if (GetStyle() & (ES_READONLY | WS_DISABLED)) { - return PBS_DISABLED; - } else if (m_IsButtonPressed) { - return PBS_PRESSED; - } else if (m_IsButtonHot) { - return PBS_HOT; - } else { - return PBS_NORMAL; - } -} - -void CEditWithButton_Base::DrawButton(CRect rectButton) -{ - CWindowDC dc(this); - - HTHEME hButtonTheme = OpenThemeData(m_hWnd, _T("Button")); - if (hButtonTheme) { - int ButtonState = GetButtonThemeState(); - - // If necessary, first fill with the edit control's background color. - if (IsThemeBackgroundPartiallyTransparent(hButtonTheme, BP_PUSHBUTTON, ButtonState)) { - HTHEME hEditTheme = OpenThemeDataEx(m_hWnd, _T("Edit"), OTD_NONCLIENT); - - COLORREF BgColor = GetThemeSysColor(hEditTheme, (GetStyle() & (ES_READONLY | WS_DISABLED)) ? COLOR_3DFACE : COLOR_WINDOW); - dc.FillSolidRect(rectButton, BgColor); - - CloseThemeData(hEditTheme); - } - - DrawThemeBackground(hButtonTheme, dc, BP_PUSHBUTTON, ButtonState, rectButton, nullptr); - - DrawButtonContent(dc, rectButton, hButtonTheme); - - CloseThemeData(hButtonTheme); - } else { - UINT uState = DFCS_BUTTONPUSH; - if (GetStyle() & (ES_READONLY | WS_DISABLED)) { - uState |= DFCS_INACTIVE; - } else if (m_IsButtonPressed) { - uState |= DFCS_PUSHED; - } - dc.DrawFrameControl(rectButton, DFC_BUTTON, uState); - - // If the button is in a pressed state, then contents should move slightly as part of the "push" effect. - if (m_IsButtonPressed) { - rectButton.OffsetRect(1, 1); - } - - DrawButtonContent(dc, rectButton, nullptr); - } -} - -void CEditWithButton_Base::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) -{ - CRect rectOld = lpncsp->rgrc[0]; - - // Let the default processing setup space of the usual screen elements (borders, etc) - CEdit::OnNcCalcSize(bCalcValidRects, lpncsp); - - // Store the current size of the borders, so we know where to put the button - m_TopBorder = lpncsp->rgrc[0].top - rectOld.top; - m_BottomBorder = rectOld.bottom - lpncsp->rgrc[0].bottom; - m_LeftBorder = lpncsp->rgrc[0].left - rectOld.left; - m_RightBorder = rectOld.right - lpncsp->rgrc[0].right; - - m_ButtonWidth = CalculateButtonWidth(); - - // Deflate the right side, making room for our button - lpncsp->rgrc[0].right -= m_ButtonWidth; -} - -void CEditWithButton_Base::OnNcPaint() -{ - // Allow default processing - CEdit::OnNcPaint(); - - CRect rectWindow; - GetWindowRect(rectWindow); - // Adjust coords to start at 0,0 - rectWindow.OffsetRect(-rectWindow.TopLeft()); - - CRect rectButton = GetButtonRect(rectWindow); - - DrawButton(rectButton); -} - -void CEditWithButton_Base::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - if (!(GetStyle() & (ES_READONLY | WS_DISABLED))) { - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - if (rectButton.PtInRect(point)) { - SetCapture(); - - m_IsButtonPressed = true; - m_IsMouseActive = true; - - // Redraw the button to reflect the change - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - } - } - - CEdit::OnNcLButtonDown(nHitTest, point); -} - -void CEditWithButton_Base::OnMouseMove(UINT nFlags, CPoint point) -{ - if (m_IsMouseActive) { - ClientToScreen(&point); - - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - bool OldState = m_IsButtonPressed; - - m_IsButtonPressed = rectButton.PtInRect(point) != FALSE; - - // If the button state has changed, redraw it to reflect the change - if (OldState != m_IsButtonPressed) { - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - } - } - - CEdit::OnMouseMove(nFlags, point); -} - -void CEditWithButton_Base::OnNcMouseMove(UINT nHitTest, CPoint point) -{ - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - bool OldState = m_IsButtonHot; - m_IsButtonHot = rectButton.PtInRect(point) != FALSE; - // If the button state has changed, redraw it to reflect the change - if (OldState != m_IsButtonHot) { - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - // If the state has changed to hot, register to get the WM_NCMOUSELEAVE notification. - if (m_IsButtonHot) { - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(tme); - tme.dwFlags = TME_LEAVE | TME_NONCLIENT; - tme.hwndTrack = m_hWnd; - tme.dwHoverTime = HOVER_DEFAULT; - _TrackMouseEvent(&tme); - } - } - - CEdit::OnNcMouseMove(nHitTest, point); -} - -void CEditWithButton_Base::OnNcMouseLeave() -{ - CPoint point; - GetCursorPos(&point); - - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - // We may get this message either when the mouse actually leaves the client area - // or when the user clicks the mouse on the button. So we must check whether or - // not the cursor has actually left the button area. If so, then update the hot - // state and prompt a redraw of the button. - if (!rectButton.PtInRect(point)) { - m_IsButtonHot = false; - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - } - - CEdit::OnNcMouseLeave(); -} - -void CEditWithButton_Base::OnLButtonUp(UINT nFlags, CPoint point) -{ - if (m_IsMouseActive) { - ReleaseCapture(); - - ClientToScreen(&point); - - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - // Reset the button to a "normal" state. - m_IsButtonHot = false; - m_IsButtonPressed = false; - m_IsMouseActive = false; - - // Redraw the button to reflect the changes. - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - // Run the on-click logic if appropriate. - if (rectButton.PtInRect(point)) { - OnLeftClick(); - } - } - - CEdit::OnLButtonUp(nFlags, point); -} - -LRESULT CEditWithButton_Base::OnNcHitTest(CPoint point) -{ - CRect rectWindow; - GetWindowRect(rectWindow); - CRect rectButton = GetButtonRect(rectWindow); - - if (rectButton.PtInRect(point)) { - return HTBORDER; - } - - return CEdit::OnNcHitTest(point); -} - -void CEditWithButton_Base::PreSubclassWindow() -{ - CEdit::PreSubclassWindow(); - - // Because our WindowProc is not yet in place, we need to post a message - PostMessage(WM_EDITWITHBUTTON_RECALCNCSIZE); -} - -LRESULT CEditWithButton_Base::OnRecalcNcSize(WPARAM wParam, LPARAM lParam) -{ - // Prompt a WM_NCCALCSIZE to be issued - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - return 0; -} - -void CEditWithButton_Base::OnEnable(BOOL bEnable) -{ - // Let all the default handling happen. - CEdit::OnEnable(bEnable); - - // Prompt the button area to redraw. - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); -} - -LRESULT CEditWithButton_Base::OnSetReadOnly(WPARAM wParam, LPARAM lParam) -{ - // Let all the default handling happen. - LRESULT r = DefWindowProc(EM_SETREADONLY, wParam, lParam); - - // Prompt the button area to redraw. - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - - return r; -} - -void CEditWithButton_Base::OnLeftClick() -{ - PostMessage(EDIT_BUTTON_LEFTCLICKED); -} - - - -// CEditWithButton -------------------------------------------------------------------------------- - -CEditWithButton::CEditWithButton(LPCTSTR pszButtonText) - : m_ButtonText(pszButtonText) -{ -} - -CString CEditWithButton::GetButtonText() const -{ - return m_ButtonText; -} - -void CEditWithButton::SetButtonText(LPCTSTR buttonText) -{ - m_ButtonText = buttonText; - - // If this is a live window, then prompt the button area to redraw. - if (IsWindow(m_hWnd)) { - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); - } -} - -void CEditWithButton::DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme) -{ - CFont* pOldFont = dc.SelectObject(GetFont()); - - if (hButtonTheme) { - DrawThemeText(hButtonTheme, dc.m_hDC, BP_PUSHBUTTON, GetButtonThemeState(), - m_ButtonText, m_ButtonText.GetLength(), - DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, rectButton); - } else { - if (GetStyle() & (ES_READONLY | WS_DISABLED)) { - dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); - } - - dc.SetBkMode(TRANSPARENT); - dc.DrawText(m_ButtonText, m_ButtonText.GetLength(), - rectButton, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } - - dc.SelectObject(pOldFont); -} - -int CEditWithButton::CalculateButtonWidth() -{ - CWindowDC dc(this); - return dc.GetTextExtent(' ' + m_ButtonText + ' ').cx; - // Note: For readability, we need some space between the text and the side borders of the button. - // A simple way to accomplish this is to pad the string with spaces when calculating the width. -} +#include "stdafx.h" +#include "EditWithButton.h" + +#define WM_EDITWITHBUTTON_RECALCNCSIZE (WM_USER + 200) // arbitrary number. hopefully no conflicts + + +// CEditWithButton_Base --------------------------------------------------------------------------- + +CEditWithButton_Base::CEditWithButton_Base() + : m_TopBorder(0) + , m_BottomBorder(0) + , m_LeftBorder(0) + , m_RightBorder(0) + , m_ButtonWidth(1) + , m_IsButtonPressed(false) + , m_IsMouseActive(false) + , m_IsButtonHot(false) +{ +} + +BEGIN_MESSAGE_MAP(CEditWithButton_Base, CEdit) + ON_WM_NCCALCSIZE() + ON_WM_NCPAINT() + ON_WM_NCLBUTTONDOWN() + ON_WM_MOUSEMOVE() + ON_WM_NCMOUSEMOVE() + ON_WM_NCMOUSELEAVE() + ON_WM_LBUTTONUP() + ON_WM_NCHITTEST() + ON_MESSAGE(WM_EDITWITHBUTTON_RECALCNCSIZE, OnRecalcNcSize) + ON_WM_NCDESTROY() + ON_WM_ENABLE() + ON_MESSAGE(EM_SETREADONLY, OnSetReadOnly) +END_MESSAGE_MAP() + +CRect CEditWithButton_Base::GetButtonRect(const CRect& rectWindow) const +{ + CRect rectButton(rectWindow); + rectButton.top += m_TopBorder; + rectButton.bottom -= m_BottomBorder; + rectButton.right -= m_RightBorder; + rectButton.left = rectButton.right - m_ButtonWidth; + + // take into account any scrollbars in the edit control + if (rectButton.right > rectButton.left) { + rectButton.OffsetRect(m_RightBorder - m_LeftBorder, 0); + } + + return rectButton; +} + +int CEditWithButton_Base::GetButtonThemeState() const +{ + if (GetStyle() & (ES_READONLY | WS_DISABLED)) { + return PBS_DISABLED; + } else if (m_IsButtonPressed) { + return PBS_PRESSED; + } else if (m_IsButtonHot) { + return PBS_HOT; + } else { + return PBS_NORMAL; + } +} + +void CEditWithButton_Base::DrawButton(CRect rectButton) +{ + CWindowDC dc(this); + + HTHEME hButtonTheme = OpenThemeData(m_hWnd, _T("Button")); + if (hButtonTheme) { + int ButtonState = GetButtonThemeState(); + + // If necessary, first fill with the edit control's background color. + if (IsThemeBackgroundPartiallyTransparent(hButtonTheme, BP_PUSHBUTTON, ButtonState)) { + HTHEME hEditTheme = OpenThemeDataEx(m_hWnd, _T("Edit"), OTD_NONCLIENT); + + COLORREF BgColor = GetThemeSysColor(hEditTheme, (GetStyle() & (ES_READONLY | WS_DISABLED)) ? COLOR_3DFACE : COLOR_WINDOW); + dc.FillSolidRect(rectButton, BgColor); + + CloseThemeData(hEditTheme); + } + + DrawThemeBackground(hButtonTheme, dc, BP_PUSHBUTTON, ButtonState, rectButton, nullptr); + + DrawButtonContent(dc, rectButton, hButtonTheme); + + CloseThemeData(hButtonTheme); + } else { + UINT uState = DFCS_BUTTONPUSH; + if (GetStyle() & (ES_READONLY | WS_DISABLED)) { + uState |= DFCS_INACTIVE; + } else if (m_IsButtonPressed) { + uState |= DFCS_PUSHED; + } + dc.DrawFrameControl(rectButton, DFC_BUTTON, uState); + + // If the button is in a pressed state, then contents should move slightly as part of the "push" effect. + if (m_IsButtonPressed) { + rectButton.OffsetRect(1, 1); + } + + DrawButtonContent(dc, rectButton, nullptr); + } +} + +void CEditWithButton_Base::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) +{ + CRect rectOld = lpncsp->rgrc[0]; + + // Let the default processing setup space of the usual screen elements (borders, etc) + CEdit::OnNcCalcSize(bCalcValidRects, lpncsp); + + // Store the current size of the borders, so we know where to put the button + m_TopBorder = lpncsp->rgrc[0].top - rectOld.top; + m_BottomBorder = rectOld.bottom - lpncsp->rgrc[0].bottom; + m_LeftBorder = lpncsp->rgrc[0].left - rectOld.left; + m_RightBorder = rectOld.right - lpncsp->rgrc[0].right; + + m_ButtonWidth = CalculateButtonWidth(); + + // Deflate the right side, making room for our button + lpncsp->rgrc[0].right -= m_ButtonWidth; +} + +void CEditWithButton_Base::OnNcPaint() +{ + // Allow default processing + CEdit::OnNcPaint(); + + CRect rectWindow; + GetWindowRect(rectWindow); + // Adjust coords to start at 0,0 + rectWindow.OffsetRect(-rectWindow.TopLeft()); + + CRect rectButton = GetButtonRect(rectWindow); + + DrawButton(rectButton); +} + +void CEditWithButton_Base::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + if (!(GetStyle() & (ES_READONLY | WS_DISABLED))) { + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + if (rectButton.PtInRect(point)) { + SetCapture(); + + m_IsButtonPressed = true; + m_IsMouseActive = true; + + // Redraw the button to reflect the change + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + CEdit::OnNcLButtonDown(nHitTest, point); +} + +void CEditWithButton_Base::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_IsMouseActive) { + ClientToScreen(&point); + + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + bool OldState = m_IsButtonPressed; + + m_IsButtonPressed = rectButton.PtInRect(point) != FALSE; + + // If the button state has changed, redraw it to reflect the change + if (OldState != m_IsButtonPressed) { + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } + } + + CEdit::OnMouseMove(nFlags, point); +} + +void CEditWithButton_Base::OnNcMouseMove(UINT nHitTest, CPoint point) +{ + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + bool OldState = m_IsButtonHot; + m_IsButtonHot = rectButton.PtInRect(point) != FALSE; + // If the button state has changed, redraw it to reflect the change + if (OldState != m_IsButtonHot) { + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + // If the state has changed to hot, register to get the WM_NCMOUSELEAVE notification. + if (m_IsButtonHot) { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE | TME_NONCLIENT; + tme.hwndTrack = m_hWnd; + tme.dwHoverTime = HOVER_DEFAULT; + _TrackMouseEvent(&tme); + } + } + + CEdit::OnNcMouseMove(nHitTest, point); +} + +void CEditWithButton_Base::OnNcMouseLeave() +{ + CPoint point; + GetCursorPos(&point); + + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + // We may get this message either when the mouse actually leaves the client area + // or when the user clicks the mouse on the button. So we must check whether or + // not the cursor has actually left the button area. If so, then update the hot + // state and prompt a redraw of the button. + if (!rectButton.PtInRect(point)) { + m_IsButtonHot = false; + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } + + CEdit::OnNcMouseLeave(); +} + +void CEditWithButton_Base::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (m_IsMouseActive) { + ReleaseCapture(); + + ClientToScreen(&point); + + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + // Reset the button to a "normal" state. + m_IsButtonHot = false; + m_IsButtonPressed = false; + m_IsMouseActive = false; + + // Redraw the button to reflect the changes. + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + // Run the on-click logic if appropriate. + if (rectButton.PtInRect(point)) { + OnLeftClick(); + } + } + + CEdit::OnLButtonUp(nFlags, point); +} + +LRESULT CEditWithButton_Base::OnNcHitTest(CPoint point) +{ + CRect rectWindow; + GetWindowRect(rectWindow); + CRect rectButton = GetButtonRect(rectWindow); + + if (rectButton.PtInRect(point)) { + return HTBORDER; + } + + return CEdit::OnNcHitTest(point); +} + +void CEditWithButton_Base::PreSubclassWindow() +{ + CEdit::PreSubclassWindow(); + + // Because our WindowProc is not yet in place, we need to post a message + PostMessage(WM_EDITWITHBUTTON_RECALCNCSIZE); +} + +LRESULT CEditWithButton_Base::OnRecalcNcSize(WPARAM wParam, LPARAM lParam) +{ + // Prompt a WM_NCCALCSIZE to be issued + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + return 0; +} + +void CEditWithButton_Base::OnEnable(BOOL bEnable) +{ + // Let all the default handling happen. + CEdit::OnEnable(bEnable); + + // Prompt the button area to redraw. + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); +} + +LRESULT CEditWithButton_Base::OnSetReadOnly(WPARAM wParam, LPARAM lParam) +{ + // Let all the default handling happen. + LRESULT r = DefWindowProc(EM_SETREADONLY, wParam, lParam); + + // Prompt the button area to redraw. + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + + return r; +} + +void CEditWithButton_Base::OnLeftClick() +{ + PostMessage(EDIT_BUTTON_LEFTCLICKED); +} + + + +// CEditWithButton -------------------------------------------------------------------------------- + +CEditWithButton::CEditWithButton(LPCTSTR pszButtonText) + : m_ButtonText(pszButtonText) +{ +} + +CString CEditWithButton::GetButtonText() const +{ + return m_ButtonText; +} + +void CEditWithButton::SetButtonText(LPCTSTR buttonText) +{ + m_ButtonText = buttonText; + + // If this is a live window, then prompt the button area to redraw. + if (IsWindow(m_hWnd)) { + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } +} + +void CEditWithButton::DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme) +{ + CFont* pOldFont = dc.SelectObject(GetFont()); + + if (hButtonTheme) { + DrawThemeText(hButtonTheme, dc.m_hDC, BP_PUSHBUTTON, GetButtonThemeState(), + m_ButtonText, m_ButtonText.GetLength(), + DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, rectButton); + } else { + if (GetStyle() & (ES_READONLY | WS_DISABLED)) { + dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); + } + + dc.SetBkMode(TRANSPARENT); + dc.DrawText(m_ButtonText, m_ButtonText.GetLength(), + rectButton, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + + dc.SelectObject(pOldFont); +} + +int CEditWithButton::CalculateButtonWidth() +{ + CWindowDC dc(this); + return dc.GetTextExtent(' ' + m_ButtonText + ' ').cx; + // Note: For readability, we need some space between the text and the side borders of the button. + // A simple way to accomplish this is to pad the string with spaces when calculating the width. +} diff --git a/src/mpc-hc/EditWithButton.h b/src/mpc-hc/EditWithButton.h index 7582a58ac37..9ef99cbf689 100644 --- a/src/mpc-hc/EditWithButton.h +++ b/src/mpc-hc/EditWithButton.h @@ -1,113 +1,113 @@ -/* - Edit With Button - - This class acts mostly like a normal Edit Box except that it provides a button to the right - side of the control. Clicking the button invokes the virutal OnLeftClick method. If that - has not been overridden in a derived classes then it sends the EDIT_BUTTON_LEFTCLICKED - message to the parent window. - - CEditWithButton_Base contains most of the code to make this work but cannot be instantiated - itself. A derived class must override DrawButtonContent and CalculateButtonWidth to determine - what is actually drawn for the button. - - CEditWithButton is a derived class that handles the simplest form of a button where a plain - text string is displayed on the button. - - Other classes could be derived to draw other kinds of buttons. -*/ -#pragma once - -#include -#include "UxTheme.h" - - -// May be sent to the parent window when the edit control's button is clicked. -// wParam will be set to the ID of the control that sent the message. -#define EDIT_BUTTON_LEFTCLICKED (WM_APP + 842) // arbitrary number, change if necessary - - -// CEditWithButton_Base --------------------------------------------------------------------------- -// This is the base class from which others derive to implement specific kinds of buttons. -class CEditWithButton_Base : public CEdit -{ -public: - CEditWithButton_Base(); - - // Called when a left click is detected. The default implementation will send a - // EDIT_BUTTON_LEFTCLICKED message to the parent window. Derived classes - // could override this to handle the event themselves, and so are not required - // to call this base implementation. - virtual void OnLeftClick(); - -protected: - afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); - afx_msg void OnNcPaint(); - afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point); - afx_msg void OnNcMouseLeave(); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg LRESULT OnNcHitTest(CPoint point); - virtual void PreSubclassWindow(); - afx_msg LRESULT OnRecalcNcSize(WPARAM wParam, LPARAM lParam); - afx_msg void OnEnable(BOOL bEnable); - afx_msg LRESULT OnSetReadOnly(WPARAM wParam, LPARAM lParam); - DECLARE_MESSAGE_MAP() - - // Given the rectangle of the control window, this returns the rect that the button will occupy. - CRect GetButtonRect(const CRect& rectWindow) const; - - // Translates the current button state in a value that could be used by DrawThemeBackground. - int GetButtonThemeState() const; - - // Called when the button needs to be drawn. - // The default implementation draws the button frame, adjusts the rect if - // the button is pressed, and then calls DrawButtonContent to render the - // contents of the button. - virtual void DrawButton(CRect rectButton); - - // Called when the button contents (anything inside the button's border) needs to - // be drawn. The rect will have already been adjusted if the button is pressed. - // The content must be drawn using the given device context within the given rect. - virtual void DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme) = 0; - - // Called when the button's width needs to be (re)calculated. - // This must return the width in pixels. - virtual int CalculateButtonWidth() = 0; - -private: - - int m_TopBorder; - int m_BottomBorder; - int m_LeftBorder; - int m_RightBorder; - - int m_ButtonWidth; // stores the button's width in pixels (so that we don't have to re-calculate it) - - bool m_IsButtonPressed; - bool m_IsMouseActive; - - bool m_IsButtonHot; -}; - - -// CEditWithButton -------------------------------------------------------------------------------- -// This implements a button containing plain text. -class CEditWithButton : public CEditWithButton_Base -{ -public: - // The given text will be displayed in the button. - explicit CEditWithButton(LPCTSTR pszButtonText = _T("...")); - - // Gets/Sets the button text. - CString GetButtonText() const; - void SetButtonText(LPCTSTR buttonText); - -private: - - virtual void DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme); - - virtual int CalculateButtonWidth(); - - CString m_ButtonText; -}; +/* + Edit With Button + + This class acts mostly like a normal Edit Box except that it provides a button to the right + side of the control. Clicking the button invokes the virutal OnLeftClick method. If that + has not been overridden in a derived classes then it sends the EDIT_BUTTON_LEFTCLICKED + message to the parent window. + + CEditWithButton_Base contains most of the code to make this work but cannot be instantiated + itself. A derived class must override DrawButtonContent and CalculateButtonWidth to determine + what is actually drawn for the button. + + CEditWithButton is a derived class that handles the simplest form of a button where a plain + text string is displayed on the button. + + Other classes could be derived to draw other kinds of buttons. +*/ +#pragma once + +#include +#include "UxTheme.h" + + +// May be sent to the parent window when the edit control's button is clicked. +// wParam will be set to the ID of the control that sent the message. +#define EDIT_BUTTON_LEFTCLICKED (WM_APP + 842) // arbitrary number, change if necessary + + +// CEditWithButton_Base --------------------------------------------------------------------------- +// This is the base class from which others derive to implement specific kinds of buttons. +class CEditWithButton_Base : public CEdit +{ +public: + CEditWithButton_Base(); + + // Called when a left click is detected. The default implementation will send a + // EDIT_BUTTON_LEFTCLICKED message to the parent window. Derived classes + // could override this to handle the event themselves, and so are not required + // to call this base implementation. + virtual void OnLeftClick(); + +protected: + afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp); + afx_msg void OnNcPaint(); + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point); + afx_msg void OnNcMouseLeave(); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg LRESULT OnNcHitTest(CPoint point); + virtual void PreSubclassWindow(); + afx_msg LRESULT OnRecalcNcSize(WPARAM wParam, LPARAM lParam); + afx_msg void OnEnable(BOOL bEnable); + afx_msg LRESULT OnSetReadOnly(WPARAM wParam, LPARAM lParam); + DECLARE_MESSAGE_MAP() + + // Given the rectangle of the control window, this returns the rect that the button will occupy. + CRect GetButtonRect(const CRect& rectWindow) const; + + // Translates the current button state in a value that could be used by DrawThemeBackground. + int GetButtonThemeState() const; + + // Called when the button needs to be drawn. + // The default implementation draws the button frame, adjusts the rect if + // the button is pressed, and then calls DrawButtonContent to render the + // contents of the button. + virtual void DrawButton(CRect rectButton); + + // Called when the button contents (anything inside the button's border) needs to + // be drawn. The rect will have already been adjusted if the button is pressed. + // The content must be drawn using the given device context within the given rect. + virtual void DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme) = 0; + + // Called when the button's width needs to be (re)calculated. + // This must return the width in pixels. + virtual int CalculateButtonWidth() = 0; + +private: + + int m_TopBorder; + int m_BottomBorder; + int m_LeftBorder; + int m_RightBorder; + + int m_ButtonWidth; // stores the button's width in pixels (so that we don't have to re-calculate it) + + bool m_IsButtonPressed; + bool m_IsMouseActive; + + bool m_IsButtonHot; +}; + + +// CEditWithButton -------------------------------------------------------------------------------- +// This implements a button containing plain text. +class CEditWithButton : public CEditWithButton_Base +{ +public: + // The given text will be displayed in the button. + explicit CEditWithButton(LPCTSTR pszButtonText = _T("...")); + + // Gets/Sets the button text. + CString GetButtonText() const; + void SetButtonText(LPCTSTR buttonText); + +private: + + virtual void DrawButtonContent(CDC& dc, CRect rectButton, HTHEME hButtonTheme); + + virtual int CalculateButtonWidth(); + + CString m_ButtonText; +}; diff --git a/src/mpc-hc/ExceptionHandler.cpp b/src/mpc-hc/ExceptionHandler.cpp index bb1aaf3c655..1760e9837a4 100644 --- a/src/mpc-hc/ExceptionHandler.cpp +++ b/src/mpc-hc/ExceptionHandler.cpp @@ -1,213 +1,213 @@ -/* - * (C) 2017 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 . - * - */ - -#include "stdafx.h" -#include "ExceptionHandler.h" -#include -#include -#include -#include "mplayerc.h" - -#ifndef _DEBUG - -LPCWSTR GetExceptionName(DWORD code) -{ - switch (code) { - case EXCEPTION_ACCESS_VIOLATION: - return _T("ACCESS VIOLATION"); - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - return _T("ARRAY BOUNDS EXCEEDED"); - case EXCEPTION_BREAKPOINT: - return _T("BREAKPOINT"); - case EXCEPTION_DATATYPE_MISALIGNMENT: - return _T("DATATYPE MISALIGNMENT"); - case EXCEPTION_FLT_DENORMAL_OPERAND: - return _T("FLT DENORMAL OPERAND"); - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - return _T("FLT DIVIDE BY ZERO"); - case EXCEPTION_FLT_INEXACT_RESULT: - return _T("FLT INEXACT RESULT"); - case EXCEPTION_FLT_INVALID_OPERATION: - return _T("FLT INVALID OPERATION"); - case EXCEPTION_FLT_OVERFLOW: - return _T("FLT OVERFLOW"); - case EXCEPTION_FLT_STACK_CHECK: - return _T("FLT STACK CHECK"); - case EXCEPTION_FLT_UNDERFLOW: - return _T("FLT UNDERFLOW"); - case EXCEPTION_GUARD_PAGE: - return _T("GUARD PAGE"); - case EXCEPTION_ILLEGAL_INSTRUCTION: - return _T("ILLEGAL_INSTRUCTION"); - case EXCEPTION_IN_PAGE_ERROR: - return _T("IN PAGE ERROR"); - case EXCEPTION_INT_DIVIDE_BY_ZERO: - return _T("INT DIVIDE BY ZERO"); - case EXCEPTION_INT_OVERFLOW: - return _T("INT OVERFLOW"); - case EXCEPTION_INVALID_DISPOSITION: - return _T("INVALID DISPOSITION"); - case EXCEPTION_INVALID_HANDLE: - return _T("INVALID HANDLE"); - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - return _T("NONCONTINUABLE EXCEPTION"); - case EXCEPTION_PRIV_INSTRUCTION: - return _T("PRIV INSTRUCTION"); - case EXCEPTION_SINGLE_STEP: - return _T("SINGLE STEP"); - case EXCEPTION_STACK_OVERFLOW: - return _T("STACK OVERFLOW"); - case 0xE06D7363: - return _T("UNDEFINED C++ EXCEPTION"); - default: - return _T("[UNKNOWN]"); - } -} - -HMODULE GetExceptionModule(LPVOID address, LPWSTR moduleName) -{ - HMODULE moduleList[1024]; - DWORD sizeNeeded = 0; - if (!EnumProcessModules(GetCurrentProcess(), moduleList, sizeof(moduleList), &sizeNeeded) || sizeNeeded > sizeof(moduleList)) { - return nullptr; - } - - int curModule = -1; - for (DWORD i = 0; i < (sizeNeeded / sizeof(HMODULE)); ++i) { - if (moduleList[i] < address) { - if (curModule == -1) { - curModule = i; - } else { - if (moduleList[curModule] < moduleList[i]) { - curModule = i; - } - } - } - } - - if (curModule == -1) { - return nullptr; - } - - if (!GetModuleFileName(moduleList[curModule], moduleName, MAX_PATH)) { - return nullptr; - } - - return moduleList[curModule]; -} - -void HandleCommonException(LPEXCEPTION_POINTERS exceptionInfo) -{ - wchar_t message[MAX_PATH + 255]; - wchar_t module[MAX_PATH]; - const wchar_t* moduleName = GetExceptionModule(exceptionInfo->ExceptionRecord->ExceptionAddress, module) ? module : _T("[UNKNOWN]"); - - const uintptr_t codeBase = uintptr_t(GetModuleHandle(nullptr)); - const uintptr_t offset = uintptr_t(exceptionInfo->ExceptionRecord->ExceptionAddress) - codeBase; - - swprintf_s(message, _countof(message), _T(\ - "An error has occurred. MPC-HC will close now.\n\n"\ - "Exception:\n%s\n\n"\ - "Crashing module:\n%s\n"\ - "Offset: 0x%" PRIXPTR ", Codebase: 0x%" PRIXPTR "\n\n"), - GetExceptionName(exceptionInfo->ExceptionRecord->ExceptionCode), - moduleName, - offset, - codeBase); - - MessageBox(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), message, _T("Unexpected error"), MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_SYSTEMMODAL); -} - -void HandleAccessViolation(LPEXCEPTION_POINTERS exceptionInfo) -{ - wchar_t message[MAX_PATH + 255]; - wchar_t module[MAX_PATH]; - const wchar_t* moduleName = GetExceptionModule(exceptionInfo->ExceptionRecord->ExceptionAddress, module) ? module : _T("[UNKNOWN]"); - - const uintptr_t codeBase = uintptr_t(GetModuleHandle(nullptr)); - const uintptr_t offset = uintptr_t(exceptionInfo->ExceptionRecord->ExceptionAddress) - codeBase; - - const wchar_t* accessType; - switch (exceptionInfo->ExceptionRecord->ExceptionInformation[0]) { - case 0: - accessType = _T("read"); - break; - case 1: - accessType = _T("write"); - break; - case 2: - accessType = _T("execute"); - break; - default: - accessType = _T("[UNKNOWN]"); - break; - } - - swprintf_s(message, _countof(message), _T(\ - "An error has occurred. MPC-HC will close now.\n\n"\ - "Exception:\n%s\n\n"\ - "Crashing module:\n%s\n"\ - "Offset: 0x%" PRIXPTR ", Codebase: 0x%" PRIXPTR "\n"\ - "The thread %lu tried to %s memory at address 0x%" PRIXPTR "\n\n"), - GetExceptionName(exceptionInfo->ExceptionRecord->ExceptionCode), - moduleName, - offset, - codeBase, - GetCurrentThreadId(), - accessType, - exceptionInfo->ExceptionRecord->ExceptionInformation[1]); - - MessageBox(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), message, _T("Unexpected error"), MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_SYSTEMMODAL); -} - -LONG WINAPI UnhandledException(LPEXCEPTION_POINTERS exceptionInfo) -{ -#if 1 - if (AfxGetMyApp()->m_fClosingState) { - return EXCEPTION_EXECUTE_HANDLER; - } -#endif - - switch (exceptionInfo->ExceptionRecord->ExceptionCode) { - case EXCEPTION_ACCESS_VIOLATION: - HandleAccessViolation(exceptionInfo); - break; - default: - HandleCommonException(exceptionInfo); - break; - } - - return EXCEPTION_EXECUTE_HANDLER; -} -#endif - -void MPCExceptionHandler::Enable() -{ -#ifndef _DEBUG - SetUnhandledExceptionFilter(UnhandledException); -#endif -}; - -void MPCExceptionHandler::Disable() -{ -#ifndef _DEBUG - SetUnhandledExceptionFilter(nullptr); -#endif -}; +/* + * (C) 2017 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 . + * + */ + +#include "stdafx.h" +#include "ExceptionHandler.h" +#include +#include +#include +#include "mplayerc.h" + +#ifndef _DEBUG + +LPCWSTR GetExceptionName(DWORD code) +{ + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + return _T("ACCESS VIOLATION"); + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return _T("ARRAY BOUNDS EXCEEDED"); + case EXCEPTION_BREAKPOINT: + return _T("BREAKPOINT"); + case EXCEPTION_DATATYPE_MISALIGNMENT: + return _T("DATATYPE MISALIGNMENT"); + case EXCEPTION_FLT_DENORMAL_OPERAND: + return _T("FLT DENORMAL OPERAND"); + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return _T("FLT DIVIDE BY ZERO"); + case EXCEPTION_FLT_INEXACT_RESULT: + return _T("FLT INEXACT RESULT"); + case EXCEPTION_FLT_INVALID_OPERATION: + return _T("FLT INVALID OPERATION"); + case EXCEPTION_FLT_OVERFLOW: + return _T("FLT OVERFLOW"); + case EXCEPTION_FLT_STACK_CHECK: + return _T("FLT STACK CHECK"); + case EXCEPTION_FLT_UNDERFLOW: + return _T("FLT UNDERFLOW"); + case EXCEPTION_GUARD_PAGE: + return _T("GUARD PAGE"); + case EXCEPTION_ILLEGAL_INSTRUCTION: + return _T("ILLEGAL_INSTRUCTION"); + case EXCEPTION_IN_PAGE_ERROR: + return _T("IN PAGE ERROR"); + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return _T("INT DIVIDE BY ZERO"); + case EXCEPTION_INT_OVERFLOW: + return _T("INT OVERFLOW"); + case EXCEPTION_INVALID_DISPOSITION: + return _T("INVALID DISPOSITION"); + case EXCEPTION_INVALID_HANDLE: + return _T("INVALID HANDLE"); + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return _T("NONCONTINUABLE EXCEPTION"); + case EXCEPTION_PRIV_INSTRUCTION: + return _T("PRIV INSTRUCTION"); + case EXCEPTION_SINGLE_STEP: + return _T("SINGLE STEP"); + case EXCEPTION_STACK_OVERFLOW: + return _T("STACK OVERFLOW"); + case 0xE06D7363: + return _T("UNDEFINED C++ EXCEPTION"); + default: + return _T("[UNKNOWN]"); + } +} + +HMODULE GetExceptionModule(LPVOID address, LPWSTR moduleName) +{ + HMODULE moduleList[1024]; + DWORD sizeNeeded = 0; + if (!EnumProcessModules(GetCurrentProcess(), moduleList, sizeof(moduleList), &sizeNeeded) || sizeNeeded > sizeof(moduleList)) { + return nullptr; + } + + int curModule = -1; + for (DWORD i = 0; i < (sizeNeeded / sizeof(HMODULE)); ++i) { + if (moduleList[i] < address) { + if (curModule == -1) { + curModule = i; + } else { + if (moduleList[curModule] < moduleList[i]) { + curModule = i; + } + } + } + } + + if (curModule == -1) { + return nullptr; + } + + if (!GetModuleFileName(moduleList[curModule], moduleName, MAX_PATH)) { + return nullptr; + } + + return moduleList[curModule]; +} + +void HandleCommonException(LPEXCEPTION_POINTERS exceptionInfo) +{ + wchar_t message[MAX_PATH + 255]; + wchar_t module[MAX_PATH]; + const wchar_t* moduleName = GetExceptionModule(exceptionInfo->ExceptionRecord->ExceptionAddress, module) ? module : _T("[UNKNOWN]"); + + const uintptr_t codeBase = uintptr_t(GetModuleHandle(nullptr)); + const uintptr_t offset = uintptr_t(exceptionInfo->ExceptionRecord->ExceptionAddress) - codeBase; + + swprintf_s(message, _countof(message), _T(\ + "An error has occurred. MPC-HC will close now.\n\n"\ + "Exception:\n%s\n\n"\ + "Crashing module:\n%s\n"\ + "Offset: 0x%" PRIXPTR ", Codebase: 0x%" PRIXPTR "\n\n"), + GetExceptionName(exceptionInfo->ExceptionRecord->ExceptionCode), + moduleName, + offset, + codeBase); + + MessageBox(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), message, _T("Unexpected error"), MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_SYSTEMMODAL); +} + +void HandleAccessViolation(LPEXCEPTION_POINTERS exceptionInfo) +{ + wchar_t message[MAX_PATH + 255]; + wchar_t module[MAX_PATH]; + const wchar_t* moduleName = GetExceptionModule(exceptionInfo->ExceptionRecord->ExceptionAddress, module) ? module : _T("[UNKNOWN]"); + + const uintptr_t codeBase = uintptr_t(GetModuleHandle(nullptr)); + const uintptr_t offset = uintptr_t(exceptionInfo->ExceptionRecord->ExceptionAddress) - codeBase; + + const wchar_t* accessType; + switch (exceptionInfo->ExceptionRecord->ExceptionInformation[0]) { + case 0: + accessType = _T("read"); + break; + case 1: + accessType = _T("write"); + break; + case 2: + accessType = _T("execute"); + break; + default: + accessType = _T("[UNKNOWN]"); + break; + } + + swprintf_s(message, _countof(message), _T(\ + "An error has occurred. MPC-HC will close now.\n\n"\ + "Exception:\n%s\n\n"\ + "Crashing module:\n%s\n"\ + "Offset: 0x%" PRIXPTR ", Codebase: 0x%" PRIXPTR "\n"\ + "The thread %lu tried to %s memory at address 0x%" PRIXPTR "\n\n"), + GetExceptionName(exceptionInfo->ExceptionRecord->ExceptionCode), + moduleName, + offset, + codeBase, + GetCurrentThreadId(), + accessType, + exceptionInfo->ExceptionRecord->ExceptionInformation[1]); + + MessageBox(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), message, _T("Unexpected error"), MB_OK | MB_TOPMOST | MB_SETFOREGROUND | MB_SYSTEMMODAL); +} + +LONG WINAPI UnhandledException(LPEXCEPTION_POINTERS exceptionInfo) +{ +#if 1 + if (AfxGetMyApp()->m_fClosingState) { + return EXCEPTION_EXECUTE_HANDLER; + } +#endif + + switch (exceptionInfo->ExceptionRecord->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + HandleAccessViolation(exceptionInfo); + break; + default: + HandleCommonException(exceptionInfo); + break; + } + + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +void MPCExceptionHandler::Enable() +{ +#ifndef _DEBUG + SetUnhandledExceptionFilter(UnhandledException); +#endif +}; + +void MPCExceptionHandler::Disable() +{ +#ifndef _DEBUG + SetUnhandledExceptionFilter(nullptr); +#endif +}; diff --git a/src/mpc-hc/ExceptionHandler.h b/src/mpc-hc/ExceptionHandler.h index e1094b74576..b776997f267 100644 --- a/src/mpc-hc/ExceptionHandler.h +++ b/src/mpc-hc/ExceptionHandler.h @@ -1,27 +1,27 @@ -/* - * (C) 2017 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 . - * - */ - -#pragma once - -namespace MPCExceptionHandler -{ - void Enable(); - void Disable(); -}; +/* + * (C) 2017 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 . + * + */ + +#pragma once + +namespace MPCExceptionHandler +{ + void Enable(); + void Disable(); +}; diff --git a/src/mpc-hc/FGFilter.cpp b/src/mpc-hc/FGFilter.cpp index 8954c933044..72ab9ba32e0 100644 --- a/src/mpc-hc/FGFilter.cpp +++ b/src/mpc-hc/FGFilter.cpp @@ -1,778 +1,778 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include "FGFilter.h" -#include "MainFrm.h" -#include "DSUtil.h" -#include "IPinHook.h" // For the NVIDIA driver bug work-around -#include "uuids.h" -#include "moreuuids.h" -#include - -#include -#include "AllocatorCommon.h" -#include "SyncAllocatorPresenter.h" - -#define LOG_FILTER_INSERT 0 - -#if !TRACE_GRAPH_BUILD -#undef TRACE -#define TRACE(...) -#endif - -// -// CFGFilter -// - -CFGFilter::CFGFilter(const CLSID& clsid, CStringW name, UINT64 merit) - : m_clsid(clsid) - , m_name(name) -{ - m_merit.val = merit; -} - -CFGFilter::~CFGFilter() -{ -} - -const CAtlList& CFGFilter::GetTypes() const -{ - return m_types; -} - -void CFGFilter::SetTypes(const CAtlList& types) -{ - m_types.RemoveAll(); - m_types.AddTailList(&types); -} - -void CFGFilter::AddType(const GUID& majortype, const GUID& subtype) -{ - m_types.AddTail(majortype); - m_types.AddTail(subtype); -} - -bool CFGFilter::CheckTypes(const CAtlArray& types, bool fExactMatch) -{ - POSITION pos = m_types.GetHeadPosition(); - while (pos) { - const GUID& majortype = m_types.GetNext(pos); - if (!pos) { - ASSERT(0); - break; - } - const GUID& subtype = m_types.GetNext(pos); - - for (int i = 0, len = types.GetCount() & ~1; i < len; i += 2) { - if (fExactMatch) { - if (majortype == types[i] && majortype != GUID_NULL - && subtype == types[i + 1] && subtype != GUID_NULL) { - return true; - } - } else { - if ((majortype == GUID_NULL || types[i] == GUID_NULL || majortype == types[i]) - && (subtype == GUID_NULL || types[i + 1] == GUID_NULL || subtype == types[i + 1])) { - return true; - } - } - } - } - - return false; -} - -// -// CFGFilterRegistry -// - -CFGFilterRegistry::CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit) - : CFGFilter(GUID_NULL, L"", merit) - , m_pMoniker(pMoniker) -{ - if (!m_pMoniker) { - return; - } - - CComHeapPtr str; - if (FAILED(m_pMoniker->GetDisplayName(0, 0, &str))) { - return; - } - m_DisplayName = m_name = str; - - QueryProperties(); - - if (merit != MERIT64_DO_USE) { - m_merit.val = merit; - } -} - -CFGFilterRegistry::CFGFilterRegistry(CStringW DisplayName, UINT64 merit) - : CFGFilter(GUID_NULL, L"", merit) - , m_DisplayName(DisplayName) -{ - if (m_DisplayName.IsEmpty()) { - return; - } - - CComPtr pBC; - CreateBindCtx(0, &pBC); - - ULONG chEaten; - if (S_OK != MkParseDisplayName(pBC, CComBSTR(m_DisplayName), &chEaten, &m_pMoniker)) { - return; - } - - QueryProperties(); - - if (merit != MERIT64_DO_USE) { - m_merit.val = merit; - } -} - -void CFGFilterRegistry::QueryProperties() -{ - ASSERT(m_pMoniker); - CComPtr pPB; - if (SUCCEEDED(m_pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)))) { - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - m_name = var.bstrVal; - var.Clear(); - } - - if (SUCCEEDED(pPB->Read(_T("CLSID"), &var, nullptr))) { - CLSIDFromString(var.bstrVal, &m_clsid); - var.Clear(); - } - - if (SUCCEEDED(pPB->Read(_T("FilterData"), &var, nullptr))) { - BSTR* pstr; - if (SUCCEEDED(SafeArrayAccessData(var.parray, (void**)&pstr))) { - ExtractFilterData((BYTE*)pstr, var.parray->cbElements * (var.parray->rgsabound[0].cElements)); - SafeArrayUnaccessData(var.parray); - } - - var.Clear(); - } - } -} - -CFGFilterRegistry::CFGFilterRegistry(const CLSID& clsid, UINT64 merit) - : CFGFilter(clsid, L"", merit) -{ - if (m_clsid == GUID_NULL) { - return; - } - - CString guid = CStringFromGUID(m_clsid); - - CRegKey key; - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + guid, KEY_READ)) { - ULONG nChars = 0; - if (ERROR_SUCCESS == key.QueryStringValue(nullptr, nullptr, &nChars)) { - CString name; - if (ERROR_SUCCESS == key.QueryStringValue(nullptr, name.GetBuffer(nChars), &nChars)) { - name.ReleaseBuffer(nChars); - m_name = name; - } - } - - key.Close(); - } - - CRegKey catkey; - - if (ERROR_SUCCESS == catkey.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance"), KEY_READ)) { - if (ERROR_SUCCESS != key.Open(catkey, guid, KEY_READ)) { - // illiminable pack uses the name of the filter and not the clsid, have to enum all keys to find it... - - FILETIME ft; - TCHAR buff[256]; - DWORD len = _countof(buff); - for (DWORD i = 0; ERROR_SUCCESS == catkey.EnumKey(i, buff, &len, &ft); i++, len = _countof(buff)) { - if (ERROR_SUCCESS == key.Open(catkey, buff, KEY_READ)) { - TCHAR clsidString[256]; - len = _countof(clsidString); - if (ERROR_SUCCESS == key.QueryStringValue(_T("CLSID"), clsidString, &len) - && GUIDFromCString(clsidString) == m_clsid) { - break; - } - - key.Close(); - } - } - } - - if (key) { - ULONG nChars = 0; - if (ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), nullptr, &nChars)) { - CString name; - if (ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), name.GetBuffer(nChars), &nChars)) { - name.ReleaseBuffer(nChars); - m_name = name; - } - } - - ULONG nBytes = 0; - if (ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), nullptr, &nBytes)) { - CAutoVectorPtr buff; - if (buff.Allocate(nBytes) && ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), buff, &nBytes)) { - ExtractFilterData(buff, nBytes); - } - } - - key.Close(); - } - } - - if (merit != MERIT64_DO_USE) { - m_merit.val = merit; - } -} - -HRESULT CFGFilterRegistry::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - CheckPointer(ppBF, E_POINTER); - - HRESULT hr = E_FAIL; - - if (m_pMoniker) { - if (SUCCEEDED(hr = m_pMoniker->BindToObject(0, 0, IID_PPV_ARGS(ppBF)))) { - m_clsid = ::GetCLSID(*ppBF); - } - } else if (m_clsid != GUID_NULL) { - CComQIPtr pBF; - - if (FAILED(pBF.CoCreateInstance(m_clsid))) { - return E_FAIL; - } - - *ppBF = pBF.Detach(); - - hr = S_OK; - } - - return hr; -}; - -interface __declspec(uuid("97f7c4d4-547b-4a5f-8332-536430ad2e4d")) - IAMFilterData : - public IUnknown -{ - STDMETHOD(ParseFilterData)(BYTE* rgbFilterData, ULONG cb, BYTE** prgbRegFilter2) PURE; - STDMETHOD(CreateFilterData)(REGFILTER2* prf2, BYTE** prgbFilterData, ULONG* pcb) PURE; -}; - -void CFGFilterRegistry::ExtractFilterData(BYTE* p, UINT len) -{ - CComPtr pFD; - BYTE* ptr = nullptr; - - if (SUCCEEDED(pFD.CoCreateInstance(CLSID_FilterMapper2)) - && SUCCEEDED(pFD->ParseFilterData(p, len, (BYTE**)&ptr))) { - REGFILTER2* prf = (REGFILTER2*) * (WPARAM*)ptr; // this is f*cked up - - m_merit.mid = prf->dwMerit; - - if (prf->dwVersion == 1) { - for (UINT i = 0; i < prf->cPins; i++) { - if (prf->rgPins[i].bOutput) { - continue; - } - - for (UINT j = 0; j < prf->rgPins[i].nMediaTypes; j++) { - if (!prf->rgPins[i].lpMediaType[j].clsMajorType || !prf->rgPins[i].lpMediaType[j].clsMinorType) { - break; - } - - const REGPINTYPES& rpt = prf->rgPins[i].lpMediaType[j]; - AddType(*rpt.clsMajorType, *rpt.clsMinorType); - } - } - } else if (prf->dwVersion == 2) { - for (UINT i = 0; i < prf->cPins2; i++) { - if (prf->rgPins2[i].dwFlags & REG_PINFLAG_B_OUTPUT) { - continue; - } - - for (UINT j = 0; j < prf->rgPins2[i].nMediaTypes; j++) { - if (!prf->rgPins2[i].lpMediaType[j].clsMajorType || !prf->rgPins2[i].lpMediaType[j].clsMinorType) { - break; - } - - const REGPINTYPES& rpt = prf->rgPins2[i].lpMediaType[j]; - AddType(*rpt.clsMajorType, *rpt.clsMinorType); - } - } - } - - CoTaskMemFree(prf); - } else { - BYTE* base = p; - -#define ChkLen(size) if (p - base + size > (int)len) return; - - ChkLen(4) - if (*(DWORD*)p != 0x00000002) { - return; // only version 2 supported, no samples found for 1 - } - p += 4; - - ChkLen(4) - m_merit.mid = *(DWORD*)p; - p += 4; - - m_types.RemoveAll(); - - ChkLen(8) - DWORD nPins = *(DWORD*)p; - p += 8; - while (nPins-- > 0) { - ChkLen(1) - BYTE n = *p - 0x30; - p++; - UNREFERENCED_PARAMETER(n); - - ChkLen(2) - WORD pi = *(WORD*)p; - p += 2; - ASSERT(pi == 'ip'); - UNREFERENCED_PARAMETER(pi); - - ChkLen(1) - BYTE x33 = *p; - p++; - ASSERT(x33 == 0x33); - UNREFERENCED_PARAMETER(x33); - - ChkLen(8) - bool fOutput = !!(*p & REG_PINFLAG_B_OUTPUT); - p += 8; - - ChkLen(12) - DWORD nTypes = *(DWORD*)p; - p += 12; - while (nTypes-- > 0) { - ChkLen(1) - n = *p - 0x30; - p++; - UNREFERENCED_PARAMETER(n); - - ChkLen(2) - WORD ty = *(WORD*)p; - p += 2; - ASSERT(ty == 'yt'); - UNREFERENCED_PARAMETER(ty); - - ChkLen(5) - x33 = *p; - p++; - ASSERT(x33 == 0x33); - UNREFERENCED_PARAMETER(x33); - p += 4; - - ChkLen(8) - if (*(DWORD*)p < (DWORD)(p - base + 8) || *(DWORD*)p >= len - || *(DWORD*)(p + 4) < (DWORD)(p - base + 8) || *(DWORD*)(p + 4) >= len) { - p += 8; - continue; - } - - GUID majortype, subtype; - memcpy(&majortype, &base[*(DWORD*)p], sizeof(GUID)); - p += 4; - if (!fOutput) { - AddType(majortype, subtype); - } - } - } - -#undef ChkLen - } -} - -// -// CFGFilterFile -// - -CFGFilterFile::CFGFilterFile(const CLSID& clsid, CString path, CStringW name, UINT64 merit) - : CFGFilter(clsid, name, merit) - , m_path(path) - , m_hInst(nullptr) -{ -} - -HRESULT CFGFilterFile::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - CheckPointer(ppBF, E_POINTER); - - return LoadExternalFilter(m_path, m_clsid, ppBF); -} - -// -// CFGFilterVideoRenderer -// - -CFGFilterVideoRenderer::CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name, UINT64 merit, bool preview) - : CFGFilter(clsid, name, merit) - , m_hWnd(hWnd) - , m_bHasHookReceiveConnection(false) - , m_bIsPreview(preview) -{ - bool mpcvr = (clsid == CLSID_MPCVR || clsid == CLSID_MPCVRAllocatorPresenter); - bool madvr = (clsid == CLSID_madVR || clsid == CLSID_madVRAllocatorPresenter); - bool evr = (clsid == CLSID_EnhancedVideoRenderer || clsid == CLSID_EVRAllocatorPresenter || clsid == CLSID_SyncAllocatorPresenter); - - // List is based on filter registration data from madVR. - // ToDo: Some subtypes might only work with madVR. Figure out which ones and add them conditionally for extra efficiency. - - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV12); // 0 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_NV12); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yv12); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_nv12); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM1); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM3); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM4); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_NV21); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_IYUV); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_I420); // 10 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUY2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuy2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YVYU); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYVY); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_uyvy); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_cyuv); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYNV); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYNY); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_HDYC); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_uyv1); // 20 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_2Vu1); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_VDTZ); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUV2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuv2); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_2vuy); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_2Vuy); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuvu); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuvs); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV16); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_I422); // 30 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y422); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_V422); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y42B); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P422); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUNV); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_VYUY); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVUI); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_AYUV); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV24); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_I444); // 40 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v308); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v408); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB24); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB32); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_24BG); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_BGRA); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ABGR); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGBA); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB0); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_0RGB); // 50 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_b48r); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_RBA64); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_64RBA); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_b64a); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P010); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P210); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y210); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v210); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y410); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v410); // 60 - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P016); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_P216); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y216); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v216); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y416); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_v416); // 66 - - if (mpcvr) { - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y8); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y16); - } - - if (mpcvr || evr) { - AddType(MEDIATYPE_Video, MEDIASUBTYPE_ARGB32); - AddType(MEDIATYPE_Video, MEDIASUBTYPE_A2R10G10B10); - } -} - -CFGFilterVideoRenderer::~CFGFilterVideoRenderer() -{ - if (m_bHasHookReceiveConnection) { - UnhookReceiveConnection(); - } -} - -HRESULT CFGFilterVideoRenderer::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - TRACE(_T("--> CFGFilterVideoRenderer::Create on thread: %lu\n"), GetCurrentThreadId()); - CheckPointer(ppBF, E_POINTER); - - HRESULT hr; - CComPtr pCAP; - - auto isD3DFullScreenMode = []() { - auto pMainFrame = dynamic_cast(AfxGetApp()->m_pMainWnd); - ASSERT(pMainFrame); - return pMainFrame && pMainFrame->IsD3DFullScreenMode(); - }; - - if (m_clsid == CLSID_EVRAllocatorPresenter) { - CheckNoLog(CreateEVR(m_clsid, m_hWnd, !m_bIsPreview && isD3DFullScreenMode(), &pCAP, m_bIsPreview)); - } else if (m_clsid == CLSID_SyncAllocatorPresenter) { - CheckNoLog(CreateSyncRenderer(m_clsid, m_hWnd, isD3DFullScreenMode(), &pCAP)); - } else if (m_clsid == CLSID_MPCVRAllocatorPresenter || m_clsid == CLSID_madVRAllocatorPresenter || - m_clsid == CLSID_VMR9AllocatorPresenter || m_clsid == CLSID_DXRAllocatorPresenter) { - CheckNoLog(CreateAP9(m_clsid, m_hWnd, isD3DFullScreenMode(), &pCAP)); - } else { - CComPtr pBF; - CheckNoLog(pBF.CoCreateInstance(m_clsid)); - - if (m_clsid == CLSID_EnhancedVideoRenderer) { - CComQIPtr pConfig = pBF; - pConfig->SetNumberOfStreams(m_bIsPreview ? 1 : 3); - - if (CComQIPtr pMFGS = pBF) { - CComPtr pMFVDC; - if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVDC)))) { - pMFVDC->SetVideoWindow(m_hWnd); - if (m_bIsPreview) { - pMFVDC->SetRenderingPrefs(MFVideoRenderPrefs_DoNotRepaintOnStop); - } - } - } - } else if (m_clsid == CLSID_VideoMixingRenderer9) { - if (m_bIsPreview) { - CComQIPtr pConfig = pBF; - - if (pConfig) { - pConfig->SetRenderingMode(VMR9Mode_Windowless); - CComQIPtr pControl = pBF; - if (pControl) { - pControl->SetVideoClippingWindow(m_hWnd); - } - } - } - } - - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pMPC = pPin) { - pUnks.AddTail(pMPC); - break; - } - } - EndEnumPins; - - *ppBF = pBF.Detach(); - } - - if (pCAP) { - CComPtr pRenderer; - CheckNoLog(pCAP->CreateRenderer(&pRenderer)); - - *ppBF = CComQIPtr(pRenderer).Detach(); - - if (m_clsid == CLSID_MPCVRAllocatorPresenter) { - auto pMainFrame = (CMainFrame*)(AfxGetApp()->m_pMainWnd); - if (pMainFrame && pMainFrame->HasDedicatedFSVideoWindow()) { - if (CComQIPtr pD3DFSC = *ppBF) { - pD3DFSC->SetD3DFullscreen(true); - } - } - // renderer supports calling IVideoWindow::put_Owner before the pins are connected - if (CComQIPtr pVW = *ppBF) { - VERIFY(SUCCEEDED(pVW->put_Owner((OAHWND)m_hWnd))); - } - } else if (m_clsid == CLSID_madVRAllocatorPresenter) { - if (CComQIPtr pMVRSR = pCAP) { - VERIFY(SUCCEEDED(pMVRSR->DisableSubclassing())); - } - // renderer supports calling IVideoWindow::put_Owner before the pins are connected - if (CComQIPtr pVW = *ppBF) { - VERIFY(SUCCEEDED(pVW->put_Owner((OAHWND)m_hWnd))); - } - } - - pUnks.AddTail(pCAP); - if (CComQIPtr pCAP2 = pCAP) { - pUnks.AddTail(pCAP2); - } - if (CComQIPtr pCAP3 = pCAP) { - pUnks.AddTail(pCAP3); - } - } - - CheckPointer(*ppBF, E_FAIL); - - if (!m_bIsPreview && (m_clsid == CLSID_EnhancedVideoRenderer || m_clsid == CLSID_EVRAllocatorPresenter || m_clsid == CLSID_SyncAllocatorPresenter || m_clsid == CLSID_VMR9AllocatorPresenter)) { - m_bHasHookReceiveConnection = HookReceiveConnection(*ppBF); - } - - return hr; -} - -// -// CFGFilterList -// - -CFGFilterList::CFGFilterList() -{ -} - -CFGFilterList::~CFGFilterList() -{ - RemoveAll(); -} - -void CFGFilterList::RemoveAll() -{ - while (!m_filters.IsEmpty()) { - const filter_t& f = m_filters.RemoveHead(); - if (f.autodelete) { - delete f.pFGF; - } - } - - m_sortedfilters.RemoveAll(); -} - -void CFGFilterList::Insert(CFGFilter* pFGF, int group, bool exactmatch, bool autodelete) -{ - bool bInsert = true; - -#if DEBUG & LOG_FILTER_INSERT - bool do_log = pFGF->GetMerit() != MERIT64_DO_NOT_USE; - if (do_log) { - TRACE(_T("FGM: Inserting %d %d %016I64x %s\n"), group, exactmatch, pFGF->GetMerit(), - pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()).GetString() : CString(pFGF->GetName()).GetString()); - } -#endif - - CLSID insert_clsid = pFGF->GetCLSID(); - - POSITION pos = m_filters.GetHeadPosition(); - while (pos) { - filter_t& f = m_filters.GetNext(pos); - - if (pFGF == f.pFGF) { - bInsert = false; -#if DEBUG & LOG_FILTER_INSERT - if (do_log) { - TRACE(_T("FGM: ^ duplicate (exact)\n")); - } -#endif - break; - } - - // Filters are inserted in this order: - // 1) Internal filters - // 2) Renderers - // 3) Overrides - // 4) Registry - - if (insert_clsid != GUID_NULL && insert_clsid == f.pFGF->GetCLSID()) { - // Exact same filter if name also identical. Name is different for the internal filters, and those should be handled as different filters. - // Blacklisted filters can have empty name. - if (f.pFGF->GetMerit() == MERIT64_DO_NOT_USE || pFGF->GetName() == f.pFGF->GetName()) { - bInsert = false; -#if DEBUG & LOG_FILTER_INSERT - if (do_log) { - TRACE(_T("FGM: ^ duplicate\n")); - } -#endif - break; - } - } - - if (group != f.group) { - continue; - } - - CFGFilterRegistry* pFGFR = dynamic_cast(pFGF); - if (pFGFR && pFGFR->GetMoniker()) { - CFGFilterRegistry* pFGFR2 = dynamic_cast(f.pFGF); - if (pFGFR2 && pFGFR2->GetMoniker() && S_OK == pFGFR->GetMoniker()->IsEqual(pFGFR2->GetMoniker())) { - bInsert = false; -#if DEBUG & LOG_FILTER_INSERT - if (do_log) { - TRACE(_T("FGM: ^ duplicate (moniker)\n")); - } -#endif - break; - } - } - } - - if (bInsert) { - filter_t f = {(int)m_filters.GetCount(), pFGF, group, exactmatch, autodelete}; - m_filters.AddTail(f); - - m_sortedfilters.RemoveAll(); - } else if (autodelete) { - delete pFGF; - } -} - -POSITION CFGFilterList::GetHeadPosition() -{ - if (m_sortedfilters.IsEmpty()) { - CAtlArray sort; - sort.SetCount(m_filters.GetCount()); - POSITION pos = m_filters.GetHeadPosition(); - for (int i = 0; pos; i++) { - sort[i] = m_filters.GetNext(pos); - } - std::sort(sort.GetData(), sort.GetData() + sort.GetCount()); - for (size_t i = 0; i < sort.GetCount(); i++) { - if (sort[i].pFGF->GetMerit() >= MERIT64_DO_USE) { - m_sortedfilters.AddTail(sort[i].pFGF); - } - } - -#ifdef _DEBUG - TRACE(_T("FGM: Sorting filters\n")); - pos = m_sortedfilters.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_sortedfilters.GetNext(pos); - TRACE(_T("FGM: - %016I64x '%s'\n"), pFGF->GetMerit(), pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()).GetString() : CString(pFGF->GetName()).GetString()); - } -#endif - } - - return m_sortedfilters.GetHeadPosition(); -} - -CFGFilter* CFGFilterList::GetNext(POSITION& pos) -{ - return m_sortedfilters.GetNext(pos); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include "FGFilter.h" +#include "MainFrm.h" +#include "DSUtil.h" +#include "IPinHook.h" // For the NVIDIA driver bug work-around +#include "uuids.h" +#include "moreuuids.h" +#include + +#include +#include "AllocatorCommon.h" +#include "SyncAllocatorPresenter.h" + +#define LOG_FILTER_INSERT 0 + +#if !TRACE_GRAPH_BUILD +#undef TRACE +#define TRACE(...) +#endif + +// +// CFGFilter +// + +CFGFilter::CFGFilter(const CLSID& clsid, CStringW name, UINT64 merit) + : m_clsid(clsid) + , m_name(name) +{ + m_merit.val = merit; +} + +CFGFilter::~CFGFilter() +{ +} + +const CAtlList& CFGFilter::GetTypes() const +{ + return m_types; +} + +void CFGFilter::SetTypes(const CAtlList& types) +{ + m_types.RemoveAll(); + m_types.AddTailList(&types); +} + +void CFGFilter::AddType(const GUID& majortype, const GUID& subtype) +{ + m_types.AddTail(majortype); + m_types.AddTail(subtype); +} + +bool CFGFilter::CheckTypes(const CAtlArray& types, bool fExactMatch) +{ + POSITION pos = m_types.GetHeadPosition(); + while (pos) { + const GUID& majortype = m_types.GetNext(pos); + if (!pos) { + ASSERT(0); + break; + } + const GUID& subtype = m_types.GetNext(pos); + + for (int i = 0, len = types.GetCount() & ~1; i < len; i += 2) { + if (fExactMatch) { + if (majortype == types[i] && majortype != GUID_NULL + && subtype == types[i + 1] && subtype != GUID_NULL) { + return true; + } + } else { + if ((majortype == GUID_NULL || types[i] == GUID_NULL || majortype == types[i]) + && (subtype == GUID_NULL || types[i + 1] == GUID_NULL || subtype == types[i + 1])) { + return true; + } + } + } + } + + return false; +} + +// +// CFGFilterRegistry +// + +CFGFilterRegistry::CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit) + : CFGFilter(GUID_NULL, L"", merit) + , m_pMoniker(pMoniker) +{ + if (!m_pMoniker) { + return; + } + + CComHeapPtr str; + if (FAILED(m_pMoniker->GetDisplayName(0, 0, &str))) { + return; + } + m_DisplayName = m_name = str; + + QueryProperties(); + + if (merit != MERIT64_DO_USE) { + m_merit.val = merit; + } +} + +CFGFilterRegistry::CFGFilterRegistry(CStringW DisplayName, UINT64 merit) + : CFGFilter(GUID_NULL, L"", merit) + , m_DisplayName(DisplayName) +{ + if (m_DisplayName.IsEmpty()) { + return; + } + + CComPtr pBC; + CreateBindCtx(0, &pBC); + + ULONG chEaten; + if (S_OK != MkParseDisplayName(pBC, CComBSTR(m_DisplayName), &chEaten, &m_pMoniker)) { + return; + } + + QueryProperties(); + + if (merit != MERIT64_DO_USE) { + m_merit.val = merit; + } +} + +void CFGFilterRegistry::QueryProperties() +{ + ASSERT(m_pMoniker); + CComPtr pPB; + if (SUCCEEDED(m_pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)))) { + CComVariant var; + if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + m_name = var.bstrVal; + var.Clear(); + } + + if (SUCCEEDED(pPB->Read(_T("CLSID"), &var, nullptr))) { + CLSIDFromString(var.bstrVal, &m_clsid); + var.Clear(); + } + + if (SUCCEEDED(pPB->Read(_T("FilterData"), &var, nullptr))) { + BSTR* pstr; + if (SUCCEEDED(SafeArrayAccessData(var.parray, (void**)&pstr))) { + ExtractFilterData((BYTE*)pstr, var.parray->cbElements * (var.parray->rgsabound[0].cElements)); + SafeArrayUnaccessData(var.parray); + } + + var.Clear(); + } + } +} + +CFGFilterRegistry::CFGFilterRegistry(const CLSID& clsid, UINT64 merit) + : CFGFilter(clsid, L"", merit) +{ + if (m_clsid == GUID_NULL) { + return; + } + + CString guid = CStringFromGUID(m_clsid); + + CRegKey key; + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + guid, KEY_READ)) { + ULONG nChars = 0; + if (ERROR_SUCCESS == key.QueryStringValue(nullptr, nullptr, &nChars)) { + CString name; + if (ERROR_SUCCESS == key.QueryStringValue(nullptr, name.GetBuffer(nChars), &nChars)) { + name.ReleaseBuffer(nChars); + m_name = name; + } + } + + key.Close(); + } + + CRegKey catkey; + + if (ERROR_SUCCESS == catkey.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance"), KEY_READ)) { + if (ERROR_SUCCESS != key.Open(catkey, guid, KEY_READ)) { + // illiminable pack uses the name of the filter and not the clsid, have to enum all keys to find it... + + FILETIME ft; + TCHAR buff[256]; + DWORD len = _countof(buff); + for (DWORD i = 0; ERROR_SUCCESS == catkey.EnumKey(i, buff, &len, &ft); i++, len = _countof(buff)) { + if (ERROR_SUCCESS == key.Open(catkey, buff, KEY_READ)) { + TCHAR clsidString[256]; + len = _countof(clsidString); + if (ERROR_SUCCESS == key.QueryStringValue(_T("CLSID"), clsidString, &len) + && GUIDFromCString(clsidString) == m_clsid) { + break; + } + + key.Close(); + } + } + } + + if (key) { + ULONG nChars = 0; + if (ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), nullptr, &nChars)) { + CString name; + if (ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), name.GetBuffer(nChars), &nChars)) { + name.ReleaseBuffer(nChars); + m_name = name; + } + } + + ULONG nBytes = 0; + if (ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), nullptr, &nBytes)) { + CAutoVectorPtr buff; + if (buff.Allocate(nBytes) && ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), buff, &nBytes)) { + ExtractFilterData(buff, nBytes); + } + } + + key.Close(); + } + } + + if (merit != MERIT64_DO_USE) { + m_merit.val = merit; + } +} + +HRESULT CFGFilterRegistry::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + CheckPointer(ppBF, E_POINTER); + + HRESULT hr = E_FAIL; + + if (m_pMoniker) { + if (SUCCEEDED(hr = m_pMoniker->BindToObject(0, 0, IID_PPV_ARGS(ppBF)))) { + m_clsid = ::GetCLSID(*ppBF); + } + } else if (m_clsid != GUID_NULL) { + CComQIPtr pBF; + + if (FAILED(pBF.CoCreateInstance(m_clsid))) { + return E_FAIL; + } + + *ppBF = pBF.Detach(); + + hr = S_OK; + } + + return hr; +}; + +interface __declspec(uuid("97f7c4d4-547b-4a5f-8332-536430ad2e4d")) + IAMFilterData : + public IUnknown +{ + STDMETHOD(ParseFilterData)(BYTE* rgbFilterData, ULONG cb, BYTE** prgbRegFilter2) PURE; + STDMETHOD(CreateFilterData)(REGFILTER2* prf2, BYTE** prgbFilterData, ULONG* pcb) PURE; +}; + +void CFGFilterRegistry::ExtractFilterData(BYTE* p, UINT len) +{ + CComPtr pFD; + BYTE* ptr = nullptr; + + if (SUCCEEDED(pFD.CoCreateInstance(CLSID_FilterMapper2)) + && SUCCEEDED(pFD->ParseFilterData(p, len, (BYTE**)&ptr))) { + REGFILTER2* prf = (REGFILTER2*) * (WPARAM*)ptr; // this is f*cked up + + m_merit.mid = prf->dwMerit; + + if (prf->dwVersion == 1) { + for (UINT i = 0; i < prf->cPins; i++) { + if (prf->rgPins[i].bOutput) { + continue; + } + + for (UINT j = 0; j < prf->rgPins[i].nMediaTypes; j++) { + if (!prf->rgPins[i].lpMediaType[j].clsMajorType || !prf->rgPins[i].lpMediaType[j].clsMinorType) { + break; + } + + const REGPINTYPES& rpt = prf->rgPins[i].lpMediaType[j]; + AddType(*rpt.clsMajorType, *rpt.clsMinorType); + } + } + } else if (prf->dwVersion == 2) { + for (UINT i = 0; i < prf->cPins2; i++) { + if (prf->rgPins2[i].dwFlags & REG_PINFLAG_B_OUTPUT) { + continue; + } + + for (UINT j = 0; j < prf->rgPins2[i].nMediaTypes; j++) { + if (!prf->rgPins2[i].lpMediaType[j].clsMajorType || !prf->rgPins2[i].lpMediaType[j].clsMinorType) { + break; + } + + const REGPINTYPES& rpt = prf->rgPins2[i].lpMediaType[j]; + AddType(*rpt.clsMajorType, *rpt.clsMinorType); + } + } + } + + CoTaskMemFree(prf); + } else { + BYTE* base = p; + +#define ChkLen(size) if (p - base + size > (int)len) return; + + ChkLen(4) + if (*(DWORD*)p != 0x00000002) { + return; // only version 2 supported, no samples found for 1 + } + p += 4; + + ChkLen(4) + m_merit.mid = *(DWORD*)p; + p += 4; + + m_types.RemoveAll(); + + ChkLen(8) + DWORD nPins = *(DWORD*)p; + p += 8; + while (nPins-- > 0) { + ChkLen(1) + BYTE n = *p - 0x30; + p++; + UNREFERENCED_PARAMETER(n); + + ChkLen(2) + WORD pi = *(WORD*)p; + p += 2; + ASSERT(pi == 'ip'); + UNREFERENCED_PARAMETER(pi); + + ChkLen(1) + BYTE x33 = *p; + p++; + ASSERT(x33 == 0x33); + UNREFERENCED_PARAMETER(x33); + + ChkLen(8) + bool fOutput = !!(*p & REG_PINFLAG_B_OUTPUT); + p += 8; + + ChkLen(12) + DWORD nTypes = *(DWORD*)p; + p += 12; + while (nTypes-- > 0) { + ChkLen(1) + n = *p - 0x30; + p++; + UNREFERENCED_PARAMETER(n); + + ChkLen(2) + WORD ty = *(WORD*)p; + p += 2; + ASSERT(ty == 'yt'); + UNREFERENCED_PARAMETER(ty); + + ChkLen(5) + x33 = *p; + p++; + ASSERT(x33 == 0x33); + UNREFERENCED_PARAMETER(x33); + p += 4; + + ChkLen(8) + if (*(DWORD*)p < (DWORD)(p - base + 8) || *(DWORD*)p >= len + || *(DWORD*)(p + 4) < (DWORD)(p - base + 8) || *(DWORD*)(p + 4) >= len) { + p += 8; + continue; + } + + GUID majortype, subtype; + memcpy(&majortype, &base[*(DWORD*)p], sizeof(GUID)); + p += 4; + if (!fOutput) { + AddType(majortype, subtype); + } + } + } + +#undef ChkLen + } +} + +// +// CFGFilterFile +// + +CFGFilterFile::CFGFilterFile(const CLSID& clsid, CString path, CStringW name, UINT64 merit) + : CFGFilter(clsid, name, merit) + , m_path(path) + , m_hInst(nullptr) +{ +} + +HRESULT CFGFilterFile::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + CheckPointer(ppBF, E_POINTER); + + return LoadExternalFilter(m_path, m_clsid, ppBF); +} + +// +// CFGFilterVideoRenderer +// + +CFGFilterVideoRenderer::CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name, UINT64 merit, bool preview) + : CFGFilter(clsid, name, merit) + , m_hWnd(hWnd) + , m_bHasHookReceiveConnection(false) + , m_bIsPreview(preview) +{ + bool mpcvr = (clsid == CLSID_MPCVR || clsid == CLSID_MPCVRAllocatorPresenter); + bool madvr = (clsid == CLSID_madVR || clsid == CLSID_madVRAllocatorPresenter); + bool evr = (clsid == CLSID_EnhancedVideoRenderer || clsid == CLSID_EVRAllocatorPresenter || clsid == CLSID_SyncAllocatorPresenter); + + // List is based on filter registration data from madVR. + // ToDo: Some subtypes might only work with madVR. Figure out which ones and add them conditionally for extra efficiency. + + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV12); // 0 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_NV12); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yv12); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_nv12); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM1); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM3); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ICM4); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_NV21); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_IYUV); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_I420); // 10 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUY2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuy2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YVYU); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYVY); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_uyvy); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_cyuv); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYNV); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_UYNY); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_HDYC); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_uyv1); // 20 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_2Vu1); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_VDTZ); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUV2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuv2); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_2vuy); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_2Vuy); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuvu); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_yuvs); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV16); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_I422); // 30 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y422); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_V422); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y42B); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P422); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YUNV); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_VYUY); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVUI); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_AYUV); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_YV24); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_I444); // 40 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v308); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v408); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB24); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB32); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_24BG); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_BGRA); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ABGR); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGBA); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RGB0); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_0RGB); // 50 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_b48r); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_RBA64); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_64RBA); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_b64a); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P010); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P210); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y210); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v210); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y410); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v410); // 60 + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P016); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_P216); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y216); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v216); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y416); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_v416); // 66 + + if (mpcvr) { + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y8); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_Y16); + } + + if (mpcvr || evr) { + AddType(MEDIATYPE_Video, MEDIASUBTYPE_ARGB32); + AddType(MEDIATYPE_Video, MEDIASUBTYPE_A2R10G10B10); + } +} + +CFGFilterVideoRenderer::~CFGFilterVideoRenderer() +{ + if (m_bHasHookReceiveConnection) { + UnhookReceiveConnection(); + } +} + +HRESULT CFGFilterVideoRenderer::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + TRACE(_T("--> CFGFilterVideoRenderer::Create on thread: %lu\n"), GetCurrentThreadId()); + CheckPointer(ppBF, E_POINTER); + + HRESULT hr; + CComPtr pCAP; + + auto isD3DFullScreenMode = []() { + auto pMainFrame = dynamic_cast(AfxGetApp()->m_pMainWnd); + ASSERT(pMainFrame); + return pMainFrame && pMainFrame->IsD3DFullScreenMode(); + }; + + if (m_clsid == CLSID_EVRAllocatorPresenter) { + CheckNoLog(CreateEVR(m_clsid, m_hWnd, !m_bIsPreview && isD3DFullScreenMode(), &pCAP, m_bIsPreview)); + } else if (m_clsid == CLSID_SyncAllocatorPresenter) { + CheckNoLog(CreateSyncRenderer(m_clsid, m_hWnd, isD3DFullScreenMode(), &pCAP)); + } else if (m_clsid == CLSID_MPCVRAllocatorPresenter || m_clsid == CLSID_madVRAllocatorPresenter || + m_clsid == CLSID_VMR9AllocatorPresenter || m_clsid == CLSID_DXRAllocatorPresenter) { + CheckNoLog(CreateAP9(m_clsid, m_hWnd, isD3DFullScreenMode(), &pCAP)); + } else { + CComPtr pBF; + CheckNoLog(pBF.CoCreateInstance(m_clsid)); + + if (m_clsid == CLSID_EnhancedVideoRenderer) { + CComQIPtr pConfig = pBF; + pConfig->SetNumberOfStreams(m_bIsPreview ? 1 : 3); + + if (CComQIPtr pMFGS = pBF) { + CComPtr pMFVDC; + if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVDC)))) { + pMFVDC->SetVideoWindow(m_hWnd); + if (m_bIsPreview) { + pMFVDC->SetRenderingPrefs(MFVideoRenderPrefs_DoNotRepaintOnStop); + } + } + } + } else if (m_clsid == CLSID_VideoMixingRenderer9) { + if (m_bIsPreview) { + CComQIPtr pConfig = pBF; + + if (pConfig) { + pConfig->SetRenderingMode(VMR9Mode_Windowless); + CComQIPtr pControl = pBF; + if (pControl) { + pControl->SetVideoClippingWindow(m_hWnd); + } + } + } + } + + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pMPC = pPin) { + pUnks.AddTail(pMPC); + break; + } + } + EndEnumPins; + + *ppBF = pBF.Detach(); + } + + if (pCAP) { + CComPtr pRenderer; + CheckNoLog(pCAP->CreateRenderer(&pRenderer)); + + *ppBF = CComQIPtr(pRenderer).Detach(); + + if (m_clsid == CLSID_MPCVRAllocatorPresenter) { + auto pMainFrame = (CMainFrame*)(AfxGetApp()->m_pMainWnd); + if (pMainFrame && pMainFrame->HasDedicatedFSVideoWindow()) { + if (CComQIPtr pD3DFSC = *ppBF) { + pD3DFSC->SetD3DFullscreen(true); + } + } + // renderer supports calling IVideoWindow::put_Owner before the pins are connected + if (CComQIPtr pVW = *ppBF) { + VERIFY(SUCCEEDED(pVW->put_Owner((OAHWND)m_hWnd))); + } + } else if (m_clsid == CLSID_madVRAllocatorPresenter) { + if (CComQIPtr pMVRSR = pCAP) { + VERIFY(SUCCEEDED(pMVRSR->DisableSubclassing())); + } + // renderer supports calling IVideoWindow::put_Owner before the pins are connected + if (CComQIPtr pVW = *ppBF) { + VERIFY(SUCCEEDED(pVW->put_Owner((OAHWND)m_hWnd))); + } + } + + pUnks.AddTail(pCAP); + if (CComQIPtr pCAP2 = pCAP) { + pUnks.AddTail(pCAP2); + } + if (CComQIPtr pCAP3 = pCAP) { + pUnks.AddTail(pCAP3); + } + } + + CheckPointer(*ppBF, E_FAIL); + + if (!m_bIsPreview && (m_clsid == CLSID_EnhancedVideoRenderer || m_clsid == CLSID_EVRAllocatorPresenter || m_clsid == CLSID_SyncAllocatorPresenter || m_clsid == CLSID_VMR9AllocatorPresenter)) { + m_bHasHookReceiveConnection = HookReceiveConnection(*ppBF); + } + + return hr; +} + +// +// CFGFilterList +// + +CFGFilterList::CFGFilterList() +{ +} + +CFGFilterList::~CFGFilterList() +{ + RemoveAll(); +} + +void CFGFilterList::RemoveAll() +{ + while (!m_filters.IsEmpty()) { + const filter_t& f = m_filters.RemoveHead(); + if (f.autodelete) { + delete f.pFGF; + } + } + + m_sortedfilters.RemoveAll(); +} + +void CFGFilterList::Insert(CFGFilter* pFGF, int group, bool exactmatch, bool autodelete) +{ + bool bInsert = true; + +#if DEBUG & LOG_FILTER_INSERT + bool do_log = pFGF->GetMerit() != MERIT64_DO_NOT_USE; + if (do_log) { + TRACE(_T("FGM: Inserting %d %d %016I64x %s\n"), group, exactmatch, pFGF->GetMerit(), + pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()).GetString() : CString(pFGF->GetName()).GetString()); + } +#endif + + CLSID insert_clsid = pFGF->GetCLSID(); + + POSITION pos = m_filters.GetHeadPosition(); + while (pos) { + filter_t& f = m_filters.GetNext(pos); + + if (pFGF == f.pFGF) { + bInsert = false; +#if DEBUG & LOG_FILTER_INSERT + if (do_log) { + TRACE(_T("FGM: ^ duplicate (exact)\n")); + } +#endif + break; + } + + // Filters are inserted in this order: + // 1) Internal filters + // 2) Renderers + // 3) Overrides + // 4) Registry + + if (insert_clsid != GUID_NULL && insert_clsid == f.pFGF->GetCLSID()) { + // Exact same filter if name also identical. Name is different for the internal filters, and those should be handled as different filters. + // Blacklisted filters can have empty name. + if (f.pFGF->GetMerit() == MERIT64_DO_NOT_USE || pFGF->GetName() == f.pFGF->GetName()) { + bInsert = false; +#if DEBUG & LOG_FILTER_INSERT + if (do_log) { + TRACE(_T("FGM: ^ duplicate\n")); + } +#endif + break; + } + } + + if (group != f.group) { + continue; + } + + CFGFilterRegistry* pFGFR = dynamic_cast(pFGF); + if (pFGFR && pFGFR->GetMoniker()) { + CFGFilterRegistry* pFGFR2 = dynamic_cast(f.pFGF); + if (pFGFR2 && pFGFR2->GetMoniker() && S_OK == pFGFR->GetMoniker()->IsEqual(pFGFR2->GetMoniker())) { + bInsert = false; +#if DEBUG & LOG_FILTER_INSERT + if (do_log) { + TRACE(_T("FGM: ^ duplicate (moniker)\n")); + } +#endif + break; + } + } + } + + if (bInsert) { + filter_t f = {(int)m_filters.GetCount(), pFGF, group, exactmatch, autodelete}; + m_filters.AddTail(f); + + m_sortedfilters.RemoveAll(); + } else if (autodelete) { + delete pFGF; + } +} + +POSITION CFGFilterList::GetHeadPosition() +{ + if (m_sortedfilters.IsEmpty()) { + CAtlArray sort; + sort.SetCount(m_filters.GetCount()); + POSITION pos = m_filters.GetHeadPosition(); + for (int i = 0; pos; i++) { + sort[i] = m_filters.GetNext(pos); + } + std::sort(sort.GetData(), sort.GetData() + sort.GetCount()); + for (size_t i = 0; i < sort.GetCount(); i++) { + if (sort[i].pFGF->GetMerit() >= MERIT64_DO_USE) { + m_sortedfilters.AddTail(sort[i].pFGF); + } + } + +#ifdef _DEBUG + TRACE(_T("FGM: Sorting filters\n")); + pos = m_sortedfilters.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_sortedfilters.GetNext(pos); + TRACE(_T("FGM: - %016I64x '%s'\n"), pFGF->GetMerit(), pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()).GetString() : CString(pFGF->GetName()).GetString()); + } +#endif + } + + return m_sortedfilters.GetHeadPosition(); +} + +CFGFilter* CFGFilterList::GetNext(POSITION& pos) +{ + return m_sortedfilters.GetNext(pos); +} diff --git a/src/mpc-hc/FGFilter.h b/src/mpc-hc/FGFilter.h index 772326e88af..0d34d1dd95a 100644 --- a/src/mpc-hc/FGFilter.h +++ b/src/mpc-hc/FGFilter.h @@ -1,193 +1,193 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015, 2017 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 . - * - */ - -#pragma once - -#define MERIT64(merit) (((UINT64)(merit)) << 16) -#define MERIT64_DO_NOT_USE MERIT64(MERIT_DO_NOT_USE) -#define MERIT64_DO_USE MERIT64(MERIT_DO_NOT_USE + 1) -#define MERIT64_UNLIKELY (MERIT64(MERIT_UNLIKELY)) -#define MERIT64_NORMAL (MERIT64(MERIT_NORMAL)) -#define MERIT64_PREFERRED (MERIT64(MERIT_PREFERRED)) -#define MERIT64_ABOVE_DSHOW (MERIT64(1) << 32) - -#define LowMeritSuffix L" (low merit)" -#define LowMerit(x) (CStringW(x) + LowMeritSuffix) - - -class CFGFilter -{ -protected: - CLSID m_clsid; - CStringW m_name; - struct { - union { - UINT64 val; - struct { - UINT64 low: 16, mid: 32, high: 16; - }; - }; - } m_merit; - CAtlList m_types; - -public: - CFGFilter(const CLSID& clsid, CStringW name = L"", UINT64 merit = MERIT64_DO_USE); - virtual ~CFGFilter(); - - CLSID GetCLSID() const { return m_clsid; } - CStringW GetName() const { return m_name; } - UINT64 GetMerit() const { return m_merit.val; } - DWORD GetMeritForDirectShow() const { return m_merit.mid; } - const CAtlList& GetTypes() const; - void SetTypes(const CAtlList& types); - void AddType(const GUID& majortype, const GUID& subtype); - bool CheckTypes(const CAtlArray& types, bool fExactMatch); - - CAtlList m_protocols, m_extensions, m_chkbytes; // TODO: subtype? - - virtual HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks) = 0; -}; - -class CFGFilterRegistry : public CFGFilter -{ -protected: - CStringW m_DisplayName; - CComPtr m_pMoniker; - - void ExtractFilterData(BYTE* p, UINT len); - -public: - CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit = MERIT64_DO_USE); - CFGFilterRegistry(CStringW DisplayName, UINT64 merit = MERIT64_DO_USE); - CFGFilterRegistry(const CLSID& clsid, UINT64 merit = MERIT64_DO_USE); - - CStringW GetDisplayName() { return m_DisplayName; } - IMoniker* GetMoniker() { return m_pMoniker; } - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); -private: - void QueryProperties(); -}; - -template -class CFGFilterInternal : public CFGFilter -{ -public: - CFGFilterInternal(CStringW name = L"", UINT64 merit = MERIT64_DO_USE) : CFGFilter(__uuidof(T), name, merit) {} - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks) { - CheckPointer(ppBF, E_POINTER); - - HRESULT hr = S_OK; - CComPtr pBF = DEBUG_NEW T(nullptr, &hr); - if (FAILED(hr)) { - return hr; - } - - *ppBF = pBF.Detach(); - - return hr; - } -}; - -class CFGFilterFile : public CFGFilter -{ -protected: - CString m_path; - HINSTANCE m_hInst; - -public: - CFGFilterFile(const CLSID& clsid, CString path, CStringW name = L"", UINT64 merit = MERIT64_DO_USE); - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); -}; - -class CFGFilterVideoRenderer : public CFGFilter -{ -protected: - HWND m_hWnd; - bool m_bHasHookReceiveConnection; - bool m_bIsPreview; - -public: - CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name = L"", UINT64 merit = MERIT64_DO_USE, bool preview = false); - virtual ~CFGFilterVideoRenderer(); - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); -}; - -class CFGFilterList -{ - struct filter_t { - int index; - CFGFilter* pFGF; - int group; - bool exactmatch, autodelete; - - bool operator <(const filter_t& rhs) const { - if (group != rhs.group) { - return group < rhs.group; - } - - if (pFGF->GetMerit() != rhs.pFGF->GetMerit()) { - return pFGF->GetMerit() > rhs.pFGF->GetMerit(); - } - - if (pFGF->GetCLSID() == rhs.pFGF->GetCLSID()) { - CFGFilterFile* fgfa = dynamic_cast(pFGF); - CFGFilterFile* fgfb = dynamic_cast(rhs.pFGF); - - if (fgfa && !fgfb) { - return true; - } - if (!fgfa && fgfb) { - return false; - } - } - - if (exactmatch && !rhs.exactmatch) { - return true; - } - if (!exactmatch && rhs.exactmatch) { - return false; - } - - if (index != rhs.index) { - return index < rhs.index; - } - - return false; - } - }; - CAtlList m_filters; - CAtlList m_sortedfilters; - -public: - CFGFilterList(); - virtual ~CFGFilterList(); - - bool IsEmpty() { return m_filters.IsEmpty(); } - void RemoveAll(); - void Insert(CFGFilter* pFGF, int group, bool exactmatch = false, bool autodelete = true); - - POSITION GetHeadPosition(); - CFGFilter* GetNext(POSITION& pos); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015, 2017 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 . + * + */ + +#pragma once + +#define MERIT64(merit) (((UINT64)(merit)) << 16) +#define MERIT64_DO_NOT_USE MERIT64(MERIT_DO_NOT_USE) +#define MERIT64_DO_USE MERIT64(MERIT_DO_NOT_USE + 1) +#define MERIT64_UNLIKELY (MERIT64(MERIT_UNLIKELY)) +#define MERIT64_NORMAL (MERIT64(MERIT_NORMAL)) +#define MERIT64_PREFERRED (MERIT64(MERIT_PREFERRED)) +#define MERIT64_ABOVE_DSHOW (MERIT64(1) << 32) + +#define LowMeritSuffix L" (low merit)" +#define LowMerit(x) (CStringW(x) + LowMeritSuffix) + + +class CFGFilter +{ +protected: + CLSID m_clsid; + CStringW m_name; + struct { + union { + UINT64 val; + struct { + UINT64 low: 16, mid: 32, high: 16; + }; + }; + } m_merit; + CAtlList m_types; + +public: + CFGFilter(const CLSID& clsid, CStringW name = L"", UINT64 merit = MERIT64_DO_USE); + virtual ~CFGFilter(); + + CLSID GetCLSID() const { return m_clsid; } + CStringW GetName() const { return m_name; } + UINT64 GetMerit() const { return m_merit.val; } + DWORD GetMeritForDirectShow() const { return m_merit.mid; } + const CAtlList& GetTypes() const; + void SetTypes(const CAtlList& types); + void AddType(const GUID& majortype, const GUID& subtype); + bool CheckTypes(const CAtlArray& types, bool fExactMatch); + + CAtlList m_protocols, m_extensions, m_chkbytes; // TODO: subtype? + + virtual HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks) = 0; +}; + +class CFGFilterRegistry : public CFGFilter +{ +protected: + CStringW m_DisplayName; + CComPtr m_pMoniker; + + void ExtractFilterData(BYTE* p, UINT len); + +public: + CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit = MERIT64_DO_USE); + CFGFilterRegistry(CStringW DisplayName, UINT64 merit = MERIT64_DO_USE); + CFGFilterRegistry(const CLSID& clsid, UINT64 merit = MERIT64_DO_USE); + + CStringW GetDisplayName() { return m_DisplayName; } + IMoniker* GetMoniker() { return m_pMoniker; } + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); +private: + void QueryProperties(); +}; + +template +class CFGFilterInternal : public CFGFilter +{ +public: + CFGFilterInternal(CStringW name = L"", UINT64 merit = MERIT64_DO_USE) : CFGFilter(__uuidof(T), name, merit) {} + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks) { + CheckPointer(ppBF, E_POINTER); + + HRESULT hr = S_OK; + CComPtr pBF = DEBUG_NEW T(nullptr, &hr); + if (FAILED(hr)) { + return hr; + } + + *ppBF = pBF.Detach(); + + return hr; + } +}; + +class CFGFilterFile : public CFGFilter +{ +protected: + CString m_path; + HINSTANCE m_hInst; + +public: + CFGFilterFile(const CLSID& clsid, CString path, CStringW name = L"", UINT64 merit = MERIT64_DO_USE); + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); +}; + +class CFGFilterVideoRenderer : public CFGFilter +{ +protected: + HWND m_hWnd; + bool m_bHasHookReceiveConnection; + bool m_bIsPreview; + +public: + CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name = L"", UINT64 merit = MERIT64_DO_USE, bool preview = false); + virtual ~CFGFilterVideoRenderer(); + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList& pUnks); +}; + +class CFGFilterList +{ + struct filter_t { + int index; + CFGFilter* pFGF; + int group; + bool exactmatch, autodelete; + + bool operator <(const filter_t& rhs) const { + if (group != rhs.group) { + return group < rhs.group; + } + + if (pFGF->GetMerit() != rhs.pFGF->GetMerit()) { + return pFGF->GetMerit() > rhs.pFGF->GetMerit(); + } + + if (pFGF->GetCLSID() == rhs.pFGF->GetCLSID()) { + CFGFilterFile* fgfa = dynamic_cast(pFGF); + CFGFilterFile* fgfb = dynamic_cast(rhs.pFGF); + + if (fgfa && !fgfb) { + return true; + } + if (!fgfa && fgfb) { + return false; + } + } + + if (exactmatch && !rhs.exactmatch) { + return true; + } + if (!exactmatch && rhs.exactmatch) { + return false; + } + + if (index != rhs.index) { + return index < rhs.index; + } + + return false; + } + }; + CAtlList m_filters; + CAtlList m_sortedfilters; + +public: + CFGFilterList(); + virtual ~CFGFilterList(); + + bool IsEmpty() { return m_filters.IsEmpty(); } + void RemoveAll(); + void Insert(CFGFilter* pFGF, int group, bool exactmatch = false, bool autodelete = true); + + POSITION GetHeadPosition(); + CFGFilter* GetNext(POSITION& pos); +}; diff --git a/src/mpc-hc/FGFilterLAV.cpp b/src/mpc-hc/FGFilterLAV.cpp index 0be53d61dfa..d8967a6592f 100644 --- a/src/mpc-hc/FGFilterLAV.cpp +++ b/src/mpc-hc/FGFilterLAV.cpp @@ -1,1274 +1,1274 @@ -/* - * (C) 2013-2018 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "PathUtils.h" -#include "../filters/InternalPropertyPage.h" -#include "../filters/PinInfoWnd.h" -#include - -#include -#include "FGFilterLAV.h" - -#define LAV_FILTERS_VERSION(major, minor, rev, commit) ((QWORD)(major) << 48 | (QWORD)(minor) << 32 | (QWORD)(rev) << 16 | (QWORD)(commit)) - -#ifndef _WIN64 -#define LAVFILTERS_DIR _T("LAVFilters\\") -#else -#define LAVFILTERS_DIR _T("LAVFilters64\\") -#endif - -// -// CFGFilterLAV -// - -CList CFGFilterLAV::s_instances; -QWORD CFGFilterLAV::lav_version = 0; - -CFGFilterLAV::CFGFilterLAV(const CLSID& clsid, CString path, CStringW name, bool bAddLowMeritSuffix, UINT64 merit, bool bIsPreview) - : isPreview(bIsPreview) - , CFGFilterFile(clsid, path, name + (bAddLowMeritSuffix ? LowMeritSuffix : L""), merit) -{ -} - -CString CFGFilterLAV::GetFilterPath(LAVFILTER_TYPE filterType) -{ - // Default path - CString filterPath = PathUtils::CombinePaths(PathUtils::GetProgramPath(), LAVFILTERS_DIR); - CLSID filterCLSID; - - switch (filterType) { - case SPLITTER: - case SPLITTER_SOURCE: - filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVSplitterBase::filename); - filterCLSID = GUID_LAVSplitter; - break; - case VIDEO_DECODER: - filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVVideo::filename); - filterCLSID = GUID_LAVVideo; - break; - case AUDIO_DECODER: - filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVAudio::filename); - filterCLSID = GUID_LAVAudio; - break; - default: - ASSERT(FALSE); // This should never happen - break; - } - -#if ENABLE_LOAD_EXTERNAL_LAVF_AS_INTERNAL - // Check that the filter's version is correct - if (!CheckVersion(filterPath)) { - // If not, check if a registered version of the filter is available. - filterPath = ::GetFilterPath(filterCLSID); - // and if it can be used - if (!CheckVersion(filterPath)) { - filterPath = _T(""); - } - } -#endif - - return filterPath; -} - -bool CFGFilterLAV::CheckVersion(CString filterPath) -{ - QWORD fversion = FileVersionInfo::GetFileVersionNum(filterPath); - if (fversion >= 0 && (lav_version == 0 || lav_version > fversion)) { - lav_version = fversion; - } - - return fversion >= LAV_FILTERS_VERSION(0, 68, 0, 0); -} - -CString CFGFilterLAV::GetVersion(LAVFILTER_TYPE filterType /*= INVALID*/) -{ - CStringList paths; - - if (filterType == INVALID) { - paths.AddTail(GetFilterPath(SPLITTER)); - paths.AddTail(GetFilterPath(VIDEO_DECODER)); - paths.AddTail(GetFilterPath(AUDIO_DECODER)); - } else { - paths.AddTail(GetFilterPath(filterType)); - } - - QWORD uiVersionMin = UINT64_MAX; - QWORD uiVersionMax = 0ui64; - CString strVersionMin, strVersionMax; - POSITION pos = paths.GetHeadPosition(); - while (pos) { - CString& path = paths.GetNext(pos); - - QWORD version = FileVersionInfo::GetFileVersionNum(path); - if (version) { - if (version < uiVersionMin) { - uiVersionMin = version; - strVersionMin = FileVersionInfo::FormatVersionString(version); - } - if (version > uiVersionMax) { - uiVersionMax = version; - strVersionMax = FileVersionInfo::FormatVersionString(version); - } - } - } - - CString version; - if (uiVersionMin != UINT64_MAX) { - version = strVersionMin; - if (uiVersionMax != uiVersionMin) { - version.AppendFormat(_T(" - %s"), strVersionMax.GetString()); - } - } - - return version; -} - -CFGFilterLAV* CFGFilterLAV::CreateFilter(LAVFILTER_TYPE filterType, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) -{ - CFGFilterLAV* filter = nullptr; - - CString filterPath = GetFilterPath(filterType); - - switch (filterType) { - case SPLITTER: - filter = DEBUG_NEW CFGFilterLAVSplitter(filterPath, merit, bAddLowMeritSuffix, bIsPreview); - break; - case SPLITTER_SOURCE: - filter = DEBUG_NEW CFGFilterLAVSplitterSource(filterPath, merit, bAddLowMeritSuffix, bIsPreview); - break; - case VIDEO_DECODER: - filter = DEBUG_NEW CFGFilterLAVVideo(filterPath, merit, bAddLowMeritSuffix, bIsPreview); - break; - case AUDIO_DECODER: - filter = DEBUG_NEW CFGFilterLAVAudio(filterPath, merit, bAddLowMeritSuffix, bIsPreview); - break; - default: - ASSERT(FALSE); // This should never happen - break; - } - - return filter; -} - -CFGFilterLAV* CFGFilterLAV::CreateFilterPreview(LAVFILTER_TYPE filterType, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/) { - CFGFilterLAV* filter = CreateFilter(filterType, merit, bAddLowMeritSuffix, true); - - return filter; -} - - -bool CFGFilterLAV::IsInternalInstance(IBaseFilter* pBF, LAVFILTER_TYPE* pLAVFilterType /*= nullptr*/) -{ - bool bIsInternalInstance = (s_instances.Find(pBF) != nullptr); - - if (bIsInternalInstance && pLAVFilterType) { - CLSID clsid; - *pLAVFilterType = INVALID; - - if (SUCCEEDED(pBF->GetClassID(&clsid))) { - if (clsid == GUID_LAVSplitter) { - *pLAVFilterType = SPLITTER; - } else if (clsid == GUID_LAVSplitterSource) { - *pLAVFilterType = SPLITTER_SOURCE; - } else if (clsid == GUID_LAVVideo) { - *pLAVFilterType = VIDEO_DECODER; - } else if (clsid == GUID_LAVAudio) { - *pLAVFilterType = AUDIO_DECODER; - } - } - } - - return bIsInternalInstance; -} - -HRESULT CFGFilterLAV::PropertyPageCallback(IBaseFilter* pBF) -{ - CheckPointer(pBF, E_POINTER); - - CComPropertySheet ps(IDS_PROPSHEET_PROPERTIES, AfxGetMyApp()->GetMainWnd()); - - // Find out which internal filter we are opening the property page for - CFGFilterLAV::LAVFILTER_TYPE LAVFilterType = CFGFilterLAV::INVALID; - if (!CFGFilterLAV::IsInternalInstance(pBF, &LAVFilterType)) { - return E_UNEXPECTED; - } - - HRESULT hr = E_FAIL; - if (CComQIPtr pSPP = pBF) { - ps.AddPages(pSPP, (LAVFilterType != CFGFilterLAV::AUDIO_DECODER) ? 1 : 2); - } - - CComPtr pPP = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr); - ps.AddPage(pPP, pBF); - - if (ps.GetPageCount() > 1) { - ps.DoModal(); - - if (CComQIPtr pLAVFSettings = pBF) { - CFGFilterLAVSplitterBase::Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get current settings from LAVSplitter - settings.SaveSettings(); // Save them to the registry/ini - } - } else if (CComQIPtr pLAVVideoSettings = pBF) { - CFGFilterLAVVideo::Settings settings; - if (settings.GetSettings(pLAVVideoSettings)) { // Get current settings from LAVVideo - settings.SaveSettings(); // Save them to the registry/ini - } - } else if (CComQIPtr pLAVAudioSettings = pBF) { - CFGFilterLAVAudio::Settings settings; - if (settings.GetSettings(pLAVAudioSettings)) { // Get current settings from LAVAudio - settings.SaveSettings(); // Save them to the registry/ini - } - } - - hr = S_OK; - } - - return hr; -} - -// -// CFGFilterLAVSplitterBase -// - -const CString CFGFilterLAVSplitterBase::filename = _T("LAVSplitter.ax"); - -CFGFilterLAVSplitterBase::CFGFilterLAVSplitterBase(CString path, const CLSID& clsid, CStringW name, bool bAddLowMeritSuffix, UINT64 merit, bool bIsPreview) - : CFGFilterLAV(clsid, path, name, bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -HRESULT CFGFilterLAVSplitterBase::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - HRESULT hr = __super::Create(ppBF, pUnks); - - if (SUCCEEDED(hr)) { - if (!CheckVersion(m_path)) { - hr = E_FAIL; - } else if (CComQIPtr pLAVFSettings = *ppBF) { - // Take control over LAVSplitter's settings, the settings are reseted to default values - hr = pLAVFSettings->SetRuntimeConfig(TRUE); - - if (SUCCEEDED(hr)) { - if (isPreview) { - pLAVFSettings->SetMaxQueueMemSize(20); - pLAVFSettings->SetMaxQueueSize(50); - pLAVFSettings->SetSubstreamsEnabled(false); - pLAVFSettings->SetSubtitleMode(LAVSubtitleMode_NoSubs); - } else { - Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVSplitter - settings.LoadSettings(); // Load our current settings from registry/ini - settings.SetSettings(pLAVFSettings); // Set our settings in LAVSplitter - } - } - - SetEnabledDisabledFormats(pLAVFSettings); - - // Keep track of LAVFilters instances in runtime mode - s_instances.AddTail(*ppBF); - } - } else { - hr = E_NOINTERFACE; - } - } - - return hr; -} - -void CFGFilterLAVSplitterBase::SetEnabledDisabledFormats(CComQIPtr pLAVFSettings) -{ - // "*" is a special case and means all formats are enabled - if (m_enabledFormats.IsEmpty() || m_enabledFormats.GetHead() != "*") { - // We turn off all formats by default to ensure that we won't hijack other filters - LPSTR* formats; - UINT nFormats; - if (SUCCEEDED(pLAVFSettings->GetFormats(&formats, &nFormats))) { - for (UINT i = 0; i < nFormats; i++) { - pLAVFSettings->SetFormatEnabled(formats[i], FALSE); - // Free the memory immediately since we won't need it later - CoTaskMemFree(formats[i]); - } - CoTaskMemFree(formats); - } - // We turn on only the formats specified explicitly - POSITION pos = m_enabledFormats.GetHeadPosition(); - while (pos) { - const CStringA& format = m_enabledFormats.GetNext(pos); - pLAVFSettings->SetFormatEnabled(format, TRUE); - } - } - - // Explicitly disabled formats - POSITION pos = m_disabledFormats.GetHeadPosition(); - while (pos) { - const CStringA& format = m_disabledFormats.GetNext(pos); - pLAVFSettings->SetFormatEnabled(format, FALSE); - } -} - -void CFGFilterLAVSplitterBase::ShowPropertyPages(CWnd* pParendWnd) -{ - CFGFilterLAV::ShowPropertyPages(pParendWnd); -} - -void CFGFilterLAVSplitterBase::Settings::LoadSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("TrayIcon"), bTrayIcon); - - prefAudioLangs = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefAudioLangs"), prefAudioLangs.c_str()); - prefSubLangs = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefSubLangs"), prefSubLangs.c_str()); - subtitleAdvanced = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleAdvanced"), subtitleAdvanced.c_str()); - - subtitleMode = (LAVSubtitleMode)pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleMode"), subtitleMode); - - bPGSForcedStream = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSForcedStream"), bPGSForcedStream); - - bPGSOnlyForced = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSOnlyForced"), bPGSOnlyForced); - - iVC1Mode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("vc1TimestampMode"), iVC1Mode); - - bSubstreams = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("substreams"), bSubstreams); - - bMatroskaExternalSegments = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("MatroskaExternalSegments"), bMatroskaExternalSegments); - - bStreamSwitchReselectSubs = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchReselectSubs"), bStreamSwitchReselectSubs); - - bStreamSwitchRemoveAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchRemoveAudio"), bStreamSwitchRemoveAudio); - - bPreferHighQualityAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PreferHighQualityAudio"), bPreferHighQualityAudio); - - bImpairedAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("ImpairedAudio"), bImpairedAudio); - - dwQueueMaxMemSize = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxSize"), dwQueueMaxMemSize); - - dwQueueMaxPackets = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxPackets"), dwQueueMaxPackets); - - dwNetworkAnalysisDuration = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("NetworkAnalysisDuration"), dwNetworkAnalysisDuration); -} - -void CFGFilterLAVSplitterBase::Settings::SaveSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("TrayIcon"), bTrayIcon); - - pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefAudioLangs"), prefAudioLangs.c_str()); - pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefSubLangs"), prefSubLangs.c_str()); - pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleAdvanced"), subtitleAdvanced.c_str()); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleMode"), subtitleMode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSForcedStream"), bPGSForcedStream); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSOnlyForced"), bPGSOnlyForced); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("vc1TimestampMode"), iVC1Mode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("substreams"), bSubstreams); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("MatroskaExternalSegments"), bMatroskaExternalSegments); - - if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchReselectSubs"), bStreamSwitchReselectSubs); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchRemoveAudio"), bStreamSwitchRemoveAudio); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PreferHighQualityAudio"), bPreferHighQualityAudio); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("ImpairedAudio"), bImpairedAudio); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxSize"), dwQueueMaxMemSize); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxPackets"), dwQueueMaxPackets); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("NetworkAnalysisDuration"), dwNetworkAnalysisDuration); -} - -bool CFGFilterLAVSplitterBase::Settings::GetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - bTrayIcon = pLAVFSettings->GetTrayIcon(); - - HRESULT hr; - LPWSTR lpwstr = nullptr; - hr = pLAVFSettings->GetPreferredLanguages(&lpwstr); - if (SUCCEEDED(hr) && lpwstr) { - prefAudioLangs = lpwstr; - CoTaskMemFree(lpwstr); - } - lpwstr = nullptr; - hr = pLAVFSettings->GetPreferredSubtitleLanguages(&lpwstr); - if (SUCCEEDED(hr) && lpwstr) { - prefSubLangs = lpwstr; - CoTaskMemFree(lpwstr); - } - lpwstr = nullptr; - hr = pLAVFSettings->GetAdvancedSubtitleConfig(&lpwstr); - if (SUCCEEDED(hr) && lpwstr) { - subtitleAdvanced = lpwstr; - CoTaskMemFree(lpwstr); - } - - subtitleMode = pLAVFSettings->GetSubtitleMode(); - - bPGSForcedStream = pLAVFSettings->GetPGSForcedStream(); - - bPGSOnlyForced = pLAVFSettings->GetPGSOnlyForced(); - - iVC1Mode = pLAVFSettings->GetVC1TimestampMode(); - - bSubstreams = pLAVFSettings->GetSubstreamsEnabled(); - - bMatroskaExternalSegments = pLAVFSettings->GetLoadMatroskaExternalSegments(); - - if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { - bStreamSwitchReselectSubs = pLAVFSettings->GetStreamSwitchReselectSubtitles(); - } else { - bStreamSwitchReselectSubs = FALSE; - } - - bStreamSwitchRemoveAudio = pLAVFSettings->GetStreamSwitchRemoveAudio(); - - bImpairedAudio = pLAVFSettings->GetUseAudioForHearingVisuallyImpaired(); - - bPreferHighQualityAudio = pLAVFSettings->GetPreferHighQualityAudioStreams(); - - dwQueueMaxMemSize = pLAVFSettings->GetMaxQueueMemSize(); - - dwQueueMaxPackets = pLAVFSettings->GetMaxQueueSize(); - - dwNetworkAnalysisDuration = pLAVFSettings->GetNetworkStreamAnalysisDuration(); - - return true; -} - -bool CFGFilterLAVSplitterBase::Settings::SetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - pLAVFSettings->SetTrayIcon(bTrayIcon); - - pLAVFSettings->SetPreferredLanguages(prefAudioLangs.c_str()); - pLAVFSettings->SetPreferredSubtitleLanguages(prefSubLangs.c_str()); - pLAVFSettings->SetAdvancedSubtitleConfig(subtitleAdvanced.c_str()); - - pLAVFSettings->SetSubtitleMode(subtitleMode); - - pLAVFSettings->SetPGSForcedStream(bPGSForcedStream); - - pLAVFSettings->SetPGSOnlyForced(bPGSOnlyForced); - - pLAVFSettings->SetVC1TimestampMode(iVC1Mode); - - pLAVFSettings->SetSubstreamsEnabled(bSubstreams); - - pLAVFSettings->SetLoadMatroskaExternalSegments(bMatroskaExternalSegments); - - if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { - pLAVFSettings->SetStreamSwitchReselectSubtitles(bStreamSwitchReselectSubs); - } - - pLAVFSettings->SetStreamSwitchRemoveAudio(bStreamSwitchRemoveAudio); - - pLAVFSettings->SetUseAudioForHearingVisuallyImpaired(bImpairedAudio); - - pLAVFSettings->SetPreferHighQualityAudioStreams(bPreferHighQualityAudio); - - pLAVFSettings->SetMaxQueueMemSize(dwQueueMaxMemSize); - - pLAVFSettings->SetMaxQueueSize(dwQueueMaxPackets); - - pLAVFSettings->SetNetworkStreamAnalysisDuration(dwNetworkAnalysisDuration); - - // Custom interface available only in patched build, will be removed after it's upstreamed - if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { - pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); - } - - return true; -} - -// -// CFGFilterLAVSplitter -// - -CFGFilterLAVSplitter::CFGFilterLAVSplitter(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) - : CFGFilterLAVSplitterBase(path, GUID_LAVSplitter, L"LAV Splitter (internal)", bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -// -// CFGFilterLAVSplitterSource -// - -CFGFilterLAVSplitterSource::CFGFilterLAVSplitterSource(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) - : CFGFilterLAVSplitterBase(path, GUID_LAVSplitterSource, L"LAV Splitter Source (internal)", bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -// -// CFGFilterLAVVideo -// - -const CString CFGFilterLAVVideo::filename = _T("LAVVideo.ax"); - -CFGFilterLAVVideo::CFGFilterLAVVideo(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) - : CFGFilterLAV(GUID_LAVVideo, path, L"LAV Video Decoder (internal)", bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -HRESULT CFGFilterLAVVideo::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - HRESULT hr = __super::Create(ppBF, pUnks); - - if (SUCCEEDED(hr)) { - if (!CheckVersion(m_path)) { - hr = E_FAIL; - } else if (CComQIPtr pLAVFSettings = *ppBF) { - // Take control over LAVVideo's settings, the settings are reseted to default values - hr = pLAVFSettings->SetRuntimeConfig(TRUE); - - if (SUCCEEDED(hr)) { - if (isPreview) { - pLAVFSettings->SetNumThreads(2); - pLAVFSettings->SetPixelFormat(LAVOutPixFmt_P010, false); - pLAVFSettings->SetPixelFormat(LAVOutPixFmt_P016, false); - } else { - Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVVideo - settings.LoadSettings(); // Load our current settings from registry/ini - settings.SetSettings(pLAVFSettings); // Set our settings in LAVVideo - } - } - // Keep track of LAVFilters instances in runtime mode - s_instances.AddTail(*ppBF); - } - } else { - hr = E_NOINTERFACE; - } - } - - return hr; -} - -void CFGFilterLAVVideo::ShowPropertyPages(CWnd* pParendWnd) -{ - CFGFilterLAV::ShowPropertyPages(pParendWnd); -} - -LPCTSTR CFGFilterLAVVideo::GetUserFriendlyDecoderName(const LPCWSTR decoderName) -{ - static constexpr std::pair userFriendlyDecoderNames[] = { - std::make_pair(L"avcodec", _T("FFmpeg")), - std::make_pair(L"dxva2n", _T("DXVA2 Native")), - std::make_pair(L"dxva2cb", _T("DXVA2 Copy-back")), - std::make_pair(L"dxva2cb direct", _T("DXVA2 Copy-back (Direct)")), - std::make_pair(L"cuvid", _T("NVIDIA CUVID")), - std::make_pair(L"quicksync", _T("Intel QuickSync")), - std::make_pair(L"d3d11 cb direct", _T("D3D11 Copy-back (Direct)")), - std::make_pair(L"d3d11 cb", _T("D3D11 Copy-back")), - std::make_pair(L"d3d11 native", _T("D3D11 Native")), - std::make_pair(L"msdk mvc hw", _T("Intel H.264 (MVC 3D)")), - }; - - for (const auto& name : userFriendlyDecoderNames) { - if (wcscmp(decoderName, name.first) == 0) { - return name.second; - } - } - - return decoderName; -} - -static LPCTSTR pixFmtSettingsMap[LAVOutPixFmt_NB] = { - _T("yv12"), _T("nv12"), _T("yuy2"), _T("uyvy"), _T("ayuv"), _T("p010"), _T("p210"), _T("y410"), - _T("p016"), _T("p216"), _T("y416"), _T("rgb32"), _T("rgb24"), _T("v210"), _T("v410"), _T("yv16"), - _T("yv24"), _T("rgb48") -}; - -# define PCIV_INTEL 0x8086 -# define PCIV_AMD 0x1002 -# define PCIV_NVIDIA 0x10de -# define PCIV_QUALCOMM 0x4351 -# define PCIV_MICROSOFT 0x1414 - -bool GetGPUDetailsD3D9(DWORD* vendorid, DWORD* deviceid, DWORD* pixelshaderversion) { - bool result = false; - try { - IDirect3D9Ex* pD3D = nullptr; - HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D); - if (hr == D3D_OK && pD3D) { - UINT count = pD3D->GetAdapterCount(); - if (count > 0) { - D3DCAPS9 caps; - hr = pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); - if (hr == D3D_OK) { - *pixelshaderversion = caps.PixelShaderVersion & 0xFFFF; - } - D3DADAPTER_IDENTIFIER9 aid9; - hr = pD3D->GetAdapterIdentifier(0, 0, &aid9); - if (hr == D3D_OK) { - *vendorid = aid9.VendorId; - *deviceid = aid9.DeviceId; - result = true; - } - } - pD3D->Release(); - } - } catch (...) { - } - return result; -} - -#if 0 -#include - -bool SupportsD3D11VA() -{ - bool result = false; - try { - ID3D11Device* pDevice = nullptr; - ID3D11DeviceContext* pContext = nullptr; - D3D_FEATURE_LEVEL fl_available; - D3D_FEATURE_LEVEL fl_list[] = { D3D_FEATURE_LEVEL_11_1 }; - HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, fl_list, _countof(fl_list), D3D11_SDK_VERSION, &pDevice, &fl_available, &pContext); - if (hr == S_OK) { - if (fl_available >= D3D_FEATURE_LEVEL_11_1) { - result = true; - } - } - } catch (...) { - } - return result; -} -#endif - -// GPUs which have (slow) partial acceleration of HEVC -bool IntelHEVCBlacklist(DWORD deviceid) { - bool result = false; - - switch (deviceid) { - case 0x0412: // Haswell - case 0x0416: - case 0x041a: - case 0x041e: - case 0x0a16: - case 0x0a1e: - case 0x0a26: - case 0x0a2e: - case 0x0c02: - case 0x0c06: - case 0x0c12: - case 0x0c16: - case 0x0c22: - case 0x0c26: - case 0x0d06: - case 0x0d16: - case 0x0d22: - case 0x0d26: - case 0x1612: // Broadwell - case 0x1616: - case 0x161a: - case 0x161b: - case 0x161d: - case 0x161e: - case 0x1622: - case 0x1626: - case 0x162a: - case 0x162b: - case 0x162d: - case 0x162e: - result = true; - } - - return result; -} - -void CFGFilterLAVVideo::Settings::LoadSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("TrayIcon"), bTrayIcon); - - dwStreamAR = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("StreamAR"), dwStreamAR); - - dwNumThreads = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("NumThreads"), dwNumThreads); - - dwDeintFieldOrder = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintFieldOrder"), dwDeintFieldOrder); - - deintMode = (LAVDeintMode)pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintMode"), deintMode); - - dwRGBRange = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("RGBRange"), dwRGBRange); - - dwSWDeintMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintMode"), dwSWDeintMode); - - dwSWDeintOutput = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintOutput"), dwSWDeintOutput); - - dwDitherMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DitherMode"), dwDitherMode); - - for (int i = 0; i < LAVOutPixFmt_NB; ++i) { - bPixFmts[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_OUTPUTFORMAT, pixFmtSettingsMap[i], bPixFmts[i]); - } - - dwHWAccel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), -1); - if (dwHWAccel == DWORD(-1)) { - // Detect GPU and decide if HWA should be used - // ToDo: if MPCVR is used as renderer, check registry if it uses D3D11 and then use D3D11 decoding (if supported) - dwHWAccel = HWAccel_None; - DWORD vendorid = 0; - DWORD deviceid = 0; - DWORD pixelshaderversion = 0; - if (GetGPUDetailsD3D9(&vendorid, &deviceid, &pixelshaderversion)) { - if (pixelshaderversion >= 0x300) { - if (vendorid == PCIV_NVIDIA || vendorid == PCIV_INTEL || vendorid == PCIV_AMD || vendorid == PCIV_QUALCOMM) { - dwHWAccel = HWAccel_DXVA2Native; - if (vendorid == PCIV_INTEL && IntelHEVCBlacklist(deviceid)) { - bHWFormats[HWCodec_HEVC] = false; - } - } - } - } - } - - bHWFormats[HWCodec_H264] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264"), bHWFormats[HWCodec_H264]); - bHWFormats[HWCodec_VC1] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vc1"), bHWFormats[HWCodec_VC1]); - bHWFormats[HWCodec_MPEG2] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg2"), bHWFormats[HWCodec_MPEG2]); - bHWFormats[HWCodec_MPEG4] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg4"), bHWFormats[HWCodec_MPEG4]); - bHWFormats[HWCodec_MPEG2DVD] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("dvd"), bHWFormats[HWCodec_MPEG2DVD]); - bHWFormats[HWCodec_HEVC] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("hevc"), bHWFormats[HWCodec_HEVC]); - bHWFormats[HWCodec_VP9] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vp9"), bHWFormats[HWCodec_VP9]); - bHWFormats[HWCodec_H264MVC] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264mvc"), bHWFormats[HWCodec_H264MVC]); - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 1, 87)) { - bHWFormats[HWCodec_AV1] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("av1"), bHWFormats[HWCodec_AV1]); - } - - dwHWAccelResFlags = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWResFlags"), dwHWAccelResFlags); - - dwHWDeintMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintMode"), dwHWDeintMode); - - dwHWDeintOutput = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintOutput"), dwHWDeintOutput); - - if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { - dwHWAccelDeviceDXVA2 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2"), dwHWAccelDeviceDXVA2); - dwHWAccelDeviceDXVA2Desc = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2Desc"), dwHWAccelDeviceDXVA2Desc); - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { - dwHWAccelDeviceD3D11 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11"), dwHWAccelDeviceD3D11); - dwHWAccelDeviceD3D11Desc = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11Desc"), dwHWAccelDeviceD3D11Desc); - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { - bHWAccelCUVIDXVA = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelCUVIDXVA"), bHWAccelCUVIDXVA); - } -} - -void CFGFilterLAVVideo::Settings::SaveSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("TrayIcon"), bTrayIcon); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("StreamAR"), dwStreamAR); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("NumThreads"), dwNumThreads); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintFieldOrder"), dwDeintFieldOrder); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintMode"), deintMode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("RGBRange"), dwRGBRange); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintMode"), dwSWDeintMode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintOutput"), dwSWDeintOutput); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DitherMode"), dwDitherMode); - - for (int i = 0; i < LAVOutPixFmt_NB; ++i) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_OUTPUTFORMAT, pixFmtSettingsMap[i], bPixFmts[i]); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), dwHWAccel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264"), bHWFormats[HWCodec_H264]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vc1"), bHWFormats[HWCodec_VC1]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg2"), bHWFormats[HWCodec_MPEG2]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg4"), bHWFormats[HWCodec_MPEG4]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("dvd"), bHWFormats[HWCodec_MPEG2DVD]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("hevc"), bHWFormats[HWCodec_HEVC]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vp9"), bHWFormats[HWCodec_VP9]); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264mvc"), bHWFormats[HWCodec_H264MVC]); - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 1, 87)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("av1"), bHWFormats[HWCodec_AV1]); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWResFlags"), dwHWAccelResFlags); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintMode"), dwHWDeintMode); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintOutput"), dwHWDeintOutput); - - if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2"), dwHWAccelDeviceDXVA2); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2Desc"), dwHWAccelDeviceDXVA2Desc); - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11"), dwHWAccelDeviceD3D11); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11Desc"), dwHWAccelDeviceD3D11Desc); - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelCUVIDXVA"), bHWAccelCUVIDXVA); - } -} - -bool CFGFilterLAVVideo::Settings::GetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - bTrayIcon = pLAVFSettings->GetTrayIcon(); - - dwStreamAR = pLAVFSettings->GetStreamAR(); - - dwNumThreads = pLAVFSettings->GetNumThreads(); - - dwDeintFieldOrder = pLAVFSettings->GetDeintFieldOrder(); - - deintMode = pLAVFSettings->GetDeinterlacingMode(); - - dwRGBRange = pLAVFSettings->GetRGBOutputRange(); - - dwSWDeintMode = pLAVFSettings->GetSWDeintMode(); - - dwSWDeintOutput = pLAVFSettings->GetSWDeintOutput(); - - dwDitherMode = pLAVFSettings->GetDitherMode(); - - for (int i = 0; i < LAVOutPixFmt_NB; ++i) { - bPixFmts[i] = pLAVFSettings->GetPixelFormat((LAVOutPixFmts)i); - } - - dwHWAccel = pLAVFSettings->GetHWAccel(); - - for (int i = 0; i < HWCodec_NB; ++i) { - bHWFormats[i] = pLAVFSettings->GetHWAccelCodec((LAVVideoHWCodec)i); - } - - dwHWAccelResFlags = pLAVFSettings->GetHWAccelResolutionFlags(); - - dwHWDeintMode = pLAVFSettings->GetHWAccelDeintMode(); - - dwHWDeintOutput = pLAVFSettings->GetHWAccelDeintOutput(); - - if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { - dwHWAccelDeviceDXVA2 = pLAVFSettings->GetHWAccelDeviceIndex(HWAccel_DXVA2CopyBack, &dwHWAccelDeviceDXVA2Desc); - } else { - dwHWAccelDeviceDXVA2 = LAVHWACCEL_DEVICE_DEFAULT; - dwHWAccelDeviceDXVA2Desc = 0; - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { - dwHWAccelDeviceD3D11 = pLAVFSettings->GetHWAccelDeviceIndex(HWAccel_D3D11, &dwHWAccelDeviceD3D11Desc); - } else { - dwHWAccelDeviceD3D11 = LAVHWACCEL_DEVICE_DEFAULT; - dwHWAccelDeviceD3D11Desc = 0; - } - - if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { - bHWAccelCUVIDXVA = pLAVFSettings->GetHWAccelDeintHQ(); - } else { - bHWAccelCUVIDXVA = TRUE; - } - - return true; -} - -bool CFGFilterLAVVideo::Settings::SetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - pLAVFSettings->SetTrayIcon(bTrayIcon); - - pLAVFSettings->SetStreamAR(dwStreamAR); - - pLAVFSettings->SetNumThreads(dwNumThreads); - - pLAVFSettings->SetDeintFieldOrder((LAVDeintFieldOrder)dwDeintFieldOrder); - - pLAVFSettings->SetDeinterlacingMode(deintMode); - - pLAVFSettings->SetRGBOutputRange(dwRGBRange); - - pLAVFSettings->SetSWDeintMode((LAVSWDeintModes)dwSWDeintMode); - - pLAVFSettings->SetSWDeintOutput((LAVDeintOutput)dwSWDeintOutput); - - pLAVFSettings->SetDitherMode((LAVDitherMode)dwDitherMode); - - for (int i = 0; i < LAVOutPixFmt_NB; ++i) { - pLAVFSettings->SetPixelFormat((LAVOutPixFmts)i, bPixFmts[i]); - } - - pLAVFSettings->SetHWAccel((LAVHWAccel)dwHWAccel); - - for (int i = 0; i < HWCodec_NB; ++i) { - pLAVFSettings->SetHWAccelCodec((LAVVideoHWCodec)i, bHWFormats[i]); - } - - pLAVFSettings->SetHWAccelResolutionFlags(dwHWAccelResFlags); - - pLAVFSettings->SetHWAccelDeintMode((LAVHWDeintModes)dwHWDeintMode); - - pLAVFSettings->SetHWAccelDeintOutput((LAVDeintOutput)dwHWDeintOutput); - - if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { - pLAVFSettings->SetHWAccelDeviceIndex(HWAccel_DXVA2CopyBack, dwHWAccelDeviceDXVA2, dwHWAccelDeviceDXVA2Desc); - } - if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { - pLAVFSettings->SetHWAccelDeviceIndex(HWAccel_D3D11, dwHWAccelDeviceD3D11, dwHWAccelDeviceD3D11Desc); - } - if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { - pLAVFSettings->SetHWAccelDeintHQ(bHWAccelCUVIDXVA); - } - - // Force RV1/2 and v210/v410 enabled, the user can control it from our own options - pLAVFSettings->SetFormatConfiguration(Codec_RV12, TRUE); - pLAVFSettings->SetFormatConfiguration(Codec_v210, TRUE); - // Enable Cinepack and QPEG so that they can be used in low-merit mode - pLAVFSettings->SetFormatConfiguration(Codec_Cinepak, TRUE); - pLAVFSettings->SetFormatConfiguration(Codec_QPEG, TRUE); - - // Custom interface available only in patched build, will be removed after it's upstreamed - if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { - pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); - } - - if (AfxGetAppSettings().iLAVGPUDevice != DWORD_MAX) { - pLAVFSettings->SetGPUDeviceIndex(AfxGetAppSettings().iLAVGPUDevice); - } - - return true; -} - - -// -// CFGFilterLAVAudio -// - -const CString CFGFilterLAVAudio::filename = _T("LAVAudio.ax"); - -CFGFilterLAVAudio::CFGFilterLAVAudio(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) - : CFGFilterLAV(GUID_LAVAudio, path, L"LAV Audio Decoder (internal)", bAddLowMeritSuffix, merit, bIsPreview) -{ -} - -HRESULT CFGFilterLAVAudio::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) -{ - HRESULT hr = __super::Create(ppBF, pUnks); - - if (SUCCEEDED(hr)) { - if (!CheckVersion(m_path)) { - hr = E_FAIL; - } else if (CComQIPtr pLAVFSettings = *ppBF) { - // Take control over LAVAudio's settings, the settings are reseted to default values - hr = pLAVFSettings->SetRuntimeConfig(TRUE); - - if (SUCCEEDED(hr)) { - if (!isPreview) { - Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVAudio - settings.LoadSettings(); // Load our current settings from registry/ini - settings.SetSettings(pLAVFSettings); // Set our settings in LAVAudio - } - } - // Keep track of LAVFilters instances in runtime mode - s_instances.AddTail(*ppBF); - } - } else { - hr = E_NOINTERFACE; - } - } - - return hr; -} - -void CFGFilterLAVAudio::ShowPropertyPages(CWnd* pParendWnd) -{ - CFGFilterLAV::ShowPropertyPages(pParendWnd); -} - -static LPCTSTR bitstreamingCodecs[Bitstream_NB] = { - _T("ac3"), _T("eac3"), _T("truehd"), _T("dts"), _T("dtshd") -}; - -static LPCTSTR sampleFormats[SampleFormat_Bitstream] = { - _T("s16"), _T("s24"), _T("s32"), _T("u8"), _T("fp32") -}; - -void CFGFilterLAVAudio::Settings::LoadSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("TrayIcon"), bTrayIcon); - - bDRCEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCEnabled"), bDRCEnabled); - - iDRCLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCLevel"), iDRCLevel); - - bDTSHDFraming = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DTSHDFraming"), bDTSHDFraming); - - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { - bBitstreamingFallback = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("BitstreamingFallback"), bBitstreamingFallback); - } - - bAutoAVSync = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AutoAVSync"), bAutoAVSync); - - bExpandMono = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("ExpandMono"), bExpandMono); - - bExpand61 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Expand61"), bExpand61); - - bOutputStandardLayout = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("OutputStandardLayout"), bOutputStandardLayout); - - bOutput51Legacy = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Output51Legacy"), bOutput51Legacy); - - bMixingEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Mixing"), bMixingEnabled); - - dwMixingLayout = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLayout"), dwMixingLayout); - - dwMixingFlags = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingFlags"), dwMixingFlags); - - dwMixingMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingMode"), dwMixingMode); - - dwMixingCenterLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingCenterLevel"), dwMixingCenterLevel); - - dwMixingSurroundLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingSurroundLevel"), dwMixingSurroundLevel); - - dwMixingLFELevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLFELevel"), dwMixingLFELevel); - - bAudioDelayEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelayEnabled"), bAudioDelayEnabled); - - iAudioDelay = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelay"), iAudioDelay); - - for (int i = 0; i < Bitstream_NB; ++i) { - CString key = CString(_T("Bitstreaming_")) + bitstreamingCodecs[i]; - bBitstream[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bBitstream[i]); - } - - for (int i = 0; i < SampleFormat_Bitstream; ++i) { - CString key = CString(_T("SampleFormat_")) + sampleFormats[i]; - bSampleFormats[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bSampleFormats[i]); - } - - bSampleConvertDither = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("SampleConvertDither"), bSampleConvertDither); -} - -void CFGFilterLAVAudio::Settings::SaveSettings() -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - ASSERT(pApp); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("TrayIcon"), bTrayIcon); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCEnabled"), bDRCEnabled); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCLevel"), iDRCLevel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DTSHDFraming"), bDTSHDFraming); - - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("BitstreamingFallback"), bBitstreamingFallback); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AutoAVSync"), bAutoAVSync); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("ExpandMono"), bExpandMono); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Expand61"), bExpand61); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("OutputStandardLayout"), bOutputStandardLayout); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Output51Legacy"), bOutput51Legacy); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Mixing"), bMixingEnabled); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLayout"), dwMixingLayout); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingFlags"), dwMixingFlags); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingMode"), dwMixingMode); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingCenterLevel"), dwMixingCenterLevel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingSurroundLevel"), dwMixingSurroundLevel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLFELevel"), dwMixingLFELevel); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelayEnabled"), bAudioDelayEnabled); - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelay"), iAudioDelay); - - for (int i = 0; i < Bitstream_NB; ++i) { - CString key = CString(_T("Bitstreaming_")) + bitstreamingCodecs[i]; - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bBitstream[i]); - } - - for (int i = 0; i < SampleFormat_Bitstream; ++i) { - CString key = CString(_T("SampleFormat_")) + sampleFormats[i]; - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bSampleFormats[i]); - } - - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("SampleConvertDither"), bSampleConvertDither); -} - -bool CFGFilterLAVAudio::Settings::GetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - bTrayIcon = pLAVFSettings->GetTrayIcon(); - - pLAVFSettings->GetDRC(&bDRCEnabled, &iDRCLevel); - - bDTSHDFraming = pLAVFSettings->GetDTSHDFraming(); - - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { - bBitstreamingFallback = pLAVFSettings->GetBitstreamingFallback(); - } else { - bBitstreamingFallback = FALSE; - } - - bAutoAVSync = pLAVFSettings->GetAutoAVSync(); - - bExpandMono = pLAVFSettings->GetExpandMono(); - - bExpand61 = pLAVFSettings->GetExpand61(); - - bOutputStandardLayout = pLAVFSettings->GetOutputStandardLayout(); - - bOutput51Legacy = pLAVFSettings->GetOutput51LegacyLayout(); - - bMixingEnabled = pLAVFSettings->GetMixingEnabled(); - - dwMixingLayout = pLAVFSettings->GetMixingLayout(); - - dwMixingFlags = pLAVFSettings->GetMixingFlags(); - - dwMixingMode = pLAVFSettings->GetMixingMode(); - - pLAVFSettings->GetMixingLevels(&dwMixingCenterLevel, &dwMixingSurroundLevel, &dwMixingLFELevel); - - pLAVFSettings->GetAudioDelay(&bAudioDelayEnabled, &iAudioDelay); - - for (int i = 0; i < Bitstream_NB; ++i) { - bBitstream[i] = pLAVFSettings->GetBitstreamConfig((LAVBitstreamCodec)i); - } - - for (int i = 0; i < SampleFormat_Bitstream; ++i) { - bSampleFormats[i] = pLAVFSettings->GetSampleFormat((LAVAudioSampleFormat)i); - } - - bSampleConvertDither = pLAVFSettings->GetSampleConvertDithering(); - - return true; -} - -bool CFGFilterLAVAudio::Settings::SetSettings(CComQIPtr pLAVFSettings) -{ - if (!pLAVFSettings) { - return false; - } - - pLAVFSettings->SetTrayIcon(bTrayIcon); - - pLAVFSettings->SetDRC(bDRCEnabled, iDRCLevel); - - pLAVFSettings->SetDTSHDFraming(bDTSHDFraming); - - if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { - pLAVFSettings->SetBitstreamingFallback(bBitstreamingFallback); - } - - pLAVFSettings->SetAutoAVSync(bAutoAVSync); - - pLAVFSettings->SetExpandMono(bExpandMono); - - pLAVFSettings->SetExpand61(bExpand61); - - pLAVFSettings->SetOutputStandardLayout(bOutputStandardLayout); - - pLAVFSettings->SetOutput51LegacyLayout(bOutput51Legacy); - - pLAVFSettings->SetMixingEnabled(bMixingEnabled); - - pLAVFSettings->SetMixingLayout(dwMixingLayout); - - pLAVFSettings->SetMixingFlags(dwMixingFlags); - - pLAVFSettings->SetMixingMode((LAVAudioMixingMode)dwMixingMode); - - pLAVFSettings->SetMixingLevels(dwMixingCenterLevel, dwMixingSurroundLevel, dwMixingLFELevel); - - pLAVFSettings->SetAudioDelay(bAudioDelayEnabled, iAudioDelay); - - for (int i = 0; i < Bitstream_NB; ++i) { - pLAVFSettings->SetBitstreamConfig((LAVBitstreamCodec)i, bBitstream[i]); - } - - for (int i = 0; i < SampleFormat_Bitstream; ++i) { - pLAVFSettings->SetSampleFormat((LAVAudioSampleFormat)i, bSampleFormats[i]); - } - - pLAVFSettings->SetSampleConvertDithering(bSampleConvertDither); - - // The internal LAV Audio Decoder will not be registered to handle WMA formats - // since the system decoder is preferred. However we can still enable those - // formats internally so that they are used in low-merit mode. - pLAVFSettings->SetFormatConfiguration(Codec_WMA2, TRUE); - pLAVFSettings->SetFormatConfiguration(Codec_WMAPRO, TRUE); - pLAVFSettings->SetFormatConfiguration(Codec_WMALL, TRUE); - - // Custom interface available only in patched build, will be removed after it's upstreamed - if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { - pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); - } - - return true; -} +/* + * (C) 2013-2018 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "PathUtils.h" +#include "../filters/InternalPropertyPage.h" +#include "../filters/PinInfoWnd.h" +#include + +#include +#include "FGFilterLAV.h" + +#define LAV_FILTERS_VERSION(major, minor, rev, commit) ((QWORD)(major) << 48 | (QWORD)(minor) << 32 | (QWORD)(rev) << 16 | (QWORD)(commit)) + +#ifndef _WIN64 +#define LAVFILTERS_DIR _T("LAVFilters\\") +#else +#define LAVFILTERS_DIR _T("LAVFilters64\\") +#endif + +// +// CFGFilterLAV +// + +CList CFGFilterLAV::s_instances; +QWORD CFGFilterLAV::lav_version = 0; + +CFGFilterLAV::CFGFilterLAV(const CLSID& clsid, CString path, CStringW name, bool bAddLowMeritSuffix, UINT64 merit, bool bIsPreview) + : isPreview(bIsPreview) + , CFGFilterFile(clsid, path, name + (bAddLowMeritSuffix ? LowMeritSuffix : L""), merit) +{ +} + +CString CFGFilterLAV::GetFilterPath(LAVFILTER_TYPE filterType) +{ + // Default path + CString filterPath = PathUtils::CombinePaths(PathUtils::GetProgramPath(), LAVFILTERS_DIR); + CLSID filterCLSID; + + switch (filterType) { + case SPLITTER: + case SPLITTER_SOURCE: + filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVSplitterBase::filename); + filterCLSID = GUID_LAVSplitter; + break; + case VIDEO_DECODER: + filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVVideo::filename); + filterCLSID = GUID_LAVVideo; + break; + case AUDIO_DECODER: + filterPath = PathUtils::CombinePaths(filterPath, CFGFilterLAVAudio::filename); + filterCLSID = GUID_LAVAudio; + break; + default: + ASSERT(FALSE); // This should never happen + break; + } + +#if ENABLE_LOAD_EXTERNAL_LAVF_AS_INTERNAL + // Check that the filter's version is correct + if (!CheckVersion(filterPath)) { + // If not, check if a registered version of the filter is available. + filterPath = ::GetFilterPath(filterCLSID); + // and if it can be used + if (!CheckVersion(filterPath)) { + filterPath = _T(""); + } + } +#endif + + return filterPath; +} + +bool CFGFilterLAV::CheckVersion(CString filterPath) +{ + QWORD fversion = FileVersionInfo::GetFileVersionNum(filterPath); + if (fversion >= 0 && (lav_version == 0 || lav_version > fversion)) { + lav_version = fversion; + } + + return fversion >= LAV_FILTERS_VERSION(0, 68, 0, 0); +} + +CString CFGFilterLAV::GetVersion(LAVFILTER_TYPE filterType /*= INVALID*/) +{ + CStringList paths; + + if (filterType == INVALID) { + paths.AddTail(GetFilterPath(SPLITTER)); + paths.AddTail(GetFilterPath(VIDEO_DECODER)); + paths.AddTail(GetFilterPath(AUDIO_DECODER)); + } else { + paths.AddTail(GetFilterPath(filterType)); + } + + QWORD uiVersionMin = UINT64_MAX; + QWORD uiVersionMax = 0ui64; + CString strVersionMin, strVersionMax; + POSITION pos = paths.GetHeadPosition(); + while (pos) { + CString& path = paths.GetNext(pos); + + QWORD version = FileVersionInfo::GetFileVersionNum(path); + if (version) { + if (version < uiVersionMin) { + uiVersionMin = version; + strVersionMin = FileVersionInfo::FormatVersionString(version); + } + if (version > uiVersionMax) { + uiVersionMax = version; + strVersionMax = FileVersionInfo::FormatVersionString(version); + } + } + } + + CString version; + if (uiVersionMin != UINT64_MAX) { + version = strVersionMin; + if (uiVersionMax != uiVersionMin) { + version.AppendFormat(_T(" - %s"), strVersionMax.GetString()); + } + } + + return version; +} + +CFGFilterLAV* CFGFilterLAV::CreateFilter(LAVFILTER_TYPE filterType, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) +{ + CFGFilterLAV* filter = nullptr; + + CString filterPath = GetFilterPath(filterType); + + switch (filterType) { + case SPLITTER: + filter = DEBUG_NEW CFGFilterLAVSplitter(filterPath, merit, bAddLowMeritSuffix, bIsPreview); + break; + case SPLITTER_SOURCE: + filter = DEBUG_NEW CFGFilterLAVSplitterSource(filterPath, merit, bAddLowMeritSuffix, bIsPreview); + break; + case VIDEO_DECODER: + filter = DEBUG_NEW CFGFilterLAVVideo(filterPath, merit, bAddLowMeritSuffix, bIsPreview); + break; + case AUDIO_DECODER: + filter = DEBUG_NEW CFGFilterLAVAudio(filterPath, merit, bAddLowMeritSuffix, bIsPreview); + break; + default: + ASSERT(FALSE); // This should never happen + break; + } + + return filter; +} + +CFGFilterLAV* CFGFilterLAV::CreateFilterPreview(LAVFILTER_TYPE filterType, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/) { + CFGFilterLAV* filter = CreateFilter(filterType, merit, bAddLowMeritSuffix, true); + + return filter; +} + + +bool CFGFilterLAV::IsInternalInstance(IBaseFilter* pBF, LAVFILTER_TYPE* pLAVFilterType /*= nullptr*/) +{ + bool bIsInternalInstance = (s_instances.Find(pBF) != nullptr); + + if (bIsInternalInstance && pLAVFilterType) { + CLSID clsid; + *pLAVFilterType = INVALID; + + if (SUCCEEDED(pBF->GetClassID(&clsid))) { + if (clsid == GUID_LAVSplitter) { + *pLAVFilterType = SPLITTER; + } else if (clsid == GUID_LAVSplitterSource) { + *pLAVFilterType = SPLITTER_SOURCE; + } else if (clsid == GUID_LAVVideo) { + *pLAVFilterType = VIDEO_DECODER; + } else if (clsid == GUID_LAVAudio) { + *pLAVFilterType = AUDIO_DECODER; + } + } + } + + return bIsInternalInstance; +} + +HRESULT CFGFilterLAV::PropertyPageCallback(IBaseFilter* pBF) +{ + CheckPointer(pBF, E_POINTER); + + CComPropertySheet ps(IDS_PROPSHEET_PROPERTIES, AfxGetMyApp()->GetMainWnd()); + + // Find out which internal filter we are opening the property page for + CFGFilterLAV::LAVFILTER_TYPE LAVFilterType = CFGFilterLAV::INVALID; + if (!CFGFilterLAV::IsInternalInstance(pBF, &LAVFilterType)) { + return E_UNEXPECTED; + } + + HRESULT hr = E_FAIL; + if (CComQIPtr pSPP = pBF) { + ps.AddPages(pSPP, (LAVFilterType != CFGFilterLAV::AUDIO_DECODER) ? 1 : 2); + } + + CComPtr pPP = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr); + ps.AddPage(pPP, pBF); + + if (ps.GetPageCount() > 1) { + ps.DoModal(); + + if (CComQIPtr pLAVFSettings = pBF) { + CFGFilterLAVSplitterBase::Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get current settings from LAVSplitter + settings.SaveSettings(); // Save them to the registry/ini + } + } else if (CComQIPtr pLAVVideoSettings = pBF) { + CFGFilterLAVVideo::Settings settings; + if (settings.GetSettings(pLAVVideoSettings)) { // Get current settings from LAVVideo + settings.SaveSettings(); // Save them to the registry/ini + } + } else if (CComQIPtr pLAVAudioSettings = pBF) { + CFGFilterLAVAudio::Settings settings; + if (settings.GetSettings(pLAVAudioSettings)) { // Get current settings from LAVAudio + settings.SaveSettings(); // Save them to the registry/ini + } + } + + hr = S_OK; + } + + return hr; +} + +// +// CFGFilterLAVSplitterBase +// + +const CString CFGFilterLAVSplitterBase::filename = _T("LAVSplitter.ax"); + +CFGFilterLAVSplitterBase::CFGFilterLAVSplitterBase(CString path, const CLSID& clsid, CStringW name, bool bAddLowMeritSuffix, UINT64 merit, bool bIsPreview) + : CFGFilterLAV(clsid, path, name, bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +HRESULT CFGFilterLAVSplitterBase::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + HRESULT hr = __super::Create(ppBF, pUnks); + + if (SUCCEEDED(hr)) { + if (!CheckVersion(m_path)) { + hr = E_FAIL; + } else if (CComQIPtr pLAVFSettings = *ppBF) { + // Take control over LAVSplitter's settings, the settings are reseted to default values + hr = pLAVFSettings->SetRuntimeConfig(TRUE); + + if (SUCCEEDED(hr)) { + if (isPreview) { + pLAVFSettings->SetMaxQueueMemSize(20); + pLAVFSettings->SetMaxQueueSize(50); + pLAVFSettings->SetSubstreamsEnabled(false); + pLAVFSettings->SetSubtitleMode(LAVSubtitleMode_NoSubs); + } else { + Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVSplitter + settings.LoadSettings(); // Load our current settings from registry/ini + settings.SetSettings(pLAVFSettings); // Set our settings in LAVSplitter + } + } + + SetEnabledDisabledFormats(pLAVFSettings); + + // Keep track of LAVFilters instances in runtime mode + s_instances.AddTail(*ppBF); + } + } else { + hr = E_NOINTERFACE; + } + } + + return hr; +} + +void CFGFilterLAVSplitterBase::SetEnabledDisabledFormats(CComQIPtr pLAVFSettings) +{ + // "*" is a special case and means all formats are enabled + if (m_enabledFormats.IsEmpty() || m_enabledFormats.GetHead() != "*") { + // We turn off all formats by default to ensure that we won't hijack other filters + LPSTR* formats; + UINT nFormats; + if (SUCCEEDED(pLAVFSettings->GetFormats(&formats, &nFormats))) { + for (UINT i = 0; i < nFormats; i++) { + pLAVFSettings->SetFormatEnabled(formats[i], FALSE); + // Free the memory immediately since we won't need it later + CoTaskMemFree(formats[i]); + } + CoTaskMemFree(formats); + } + // We turn on only the formats specified explicitly + POSITION pos = m_enabledFormats.GetHeadPosition(); + while (pos) { + const CStringA& format = m_enabledFormats.GetNext(pos); + pLAVFSettings->SetFormatEnabled(format, TRUE); + } + } + + // Explicitly disabled formats + POSITION pos = m_disabledFormats.GetHeadPosition(); + while (pos) { + const CStringA& format = m_disabledFormats.GetNext(pos); + pLAVFSettings->SetFormatEnabled(format, FALSE); + } +} + +void CFGFilterLAVSplitterBase::ShowPropertyPages(CWnd* pParendWnd) +{ + CFGFilterLAV::ShowPropertyPages(pParendWnd); +} + +void CFGFilterLAVSplitterBase::Settings::LoadSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("TrayIcon"), bTrayIcon); + + prefAudioLangs = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefAudioLangs"), prefAudioLangs.c_str()); + prefSubLangs = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefSubLangs"), prefSubLangs.c_str()); + subtitleAdvanced = pApp->GetProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleAdvanced"), subtitleAdvanced.c_str()); + + subtitleMode = (LAVSubtitleMode)pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleMode"), subtitleMode); + + bPGSForcedStream = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSForcedStream"), bPGSForcedStream); + + bPGSOnlyForced = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSOnlyForced"), bPGSOnlyForced); + + iVC1Mode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("vc1TimestampMode"), iVC1Mode); + + bSubstreams = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("substreams"), bSubstreams); + + bMatroskaExternalSegments = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("MatroskaExternalSegments"), bMatroskaExternalSegments); + + bStreamSwitchReselectSubs = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchReselectSubs"), bStreamSwitchReselectSubs); + + bStreamSwitchRemoveAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchRemoveAudio"), bStreamSwitchRemoveAudio); + + bPreferHighQualityAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PreferHighQualityAudio"), bPreferHighQualityAudio); + + bImpairedAudio = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("ImpairedAudio"), bImpairedAudio); + + dwQueueMaxMemSize = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxSize"), dwQueueMaxMemSize); + + dwQueueMaxPackets = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxPackets"), dwQueueMaxPackets); + + dwNetworkAnalysisDuration = pApp->GetProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("NetworkAnalysisDuration"), dwNetworkAnalysisDuration); +} + +void CFGFilterLAVSplitterBase::Settings::SaveSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("TrayIcon"), bTrayIcon); + + pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefAudioLangs"), prefAudioLangs.c_str()); + pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("prefSubLangs"), prefSubLangs.c_str()); + pApp->WriteProfileString(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleAdvanced"), subtitleAdvanced.c_str()); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("subtitleMode"), subtitleMode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSForcedStream"), bPGSForcedStream); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PGSOnlyForced"), bPGSOnlyForced); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("vc1TimestampMode"), iVC1Mode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("substreams"), bSubstreams); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("MatroskaExternalSegments"), bMatroskaExternalSegments); + + if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchReselectSubs"), bStreamSwitchReselectSubs); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("StreamSwitchRemoveAudio"), bStreamSwitchRemoveAudio); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("PreferHighQualityAudio"), bPreferHighQualityAudio); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("ImpairedAudio"), bImpairedAudio); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxSize"), dwQueueMaxMemSize); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("QueueMaxPackets"), dwQueueMaxPackets); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVSPLITTER, _T("NetworkAnalysisDuration"), dwNetworkAnalysisDuration); +} + +bool CFGFilterLAVSplitterBase::Settings::GetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + bTrayIcon = pLAVFSettings->GetTrayIcon(); + + HRESULT hr; + LPWSTR lpwstr = nullptr; + hr = pLAVFSettings->GetPreferredLanguages(&lpwstr); + if (SUCCEEDED(hr) && lpwstr) { + prefAudioLangs = lpwstr; + CoTaskMemFree(lpwstr); + } + lpwstr = nullptr; + hr = pLAVFSettings->GetPreferredSubtitleLanguages(&lpwstr); + if (SUCCEEDED(hr) && lpwstr) { + prefSubLangs = lpwstr; + CoTaskMemFree(lpwstr); + } + lpwstr = nullptr; + hr = pLAVFSettings->GetAdvancedSubtitleConfig(&lpwstr); + if (SUCCEEDED(hr) && lpwstr) { + subtitleAdvanced = lpwstr; + CoTaskMemFree(lpwstr); + } + + subtitleMode = pLAVFSettings->GetSubtitleMode(); + + bPGSForcedStream = pLAVFSettings->GetPGSForcedStream(); + + bPGSOnlyForced = pLAVFSettings->GetPGSOnlyForced(); + + iVC1Mode = pLAVFSettings->GetVC1TimestampMode(); + + bSubstreams = pLAVFSettings->GetSubstreamsEnabled(); + + bMatroskaExternalSegments = pLAVFSettings->GetLoadMatroskaExternalSegments(); + + if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { + bStreamSwitchReselectSubs = pLAVFSettings->GetStreamSwitchReselectSubtitles(); + } else { + bStreamSwitchReselectSubs = FALSE; + } + + bStreamSwitchRemoveAudio = pLAVFSettings->GetStreamSwitchRemoveAudio(); + + bImpairedAudio = pLAVFSettings->GetUseAudioForHearingVisuallyImpaired(); + + bPreferHighQualityAudio = pLAVFSettings->GetPreferHighQualityAudioStreams(); + + dwQueueMaxMemSize = pLAVFSettings->GetMaxQueueMemSize(); + + dwQueueMaxPackets = pLAVFSettings->GetMaxQueueSize(); + + dwNetworkAnalysisDuration = pLAVFSettings->GetNetworkStreamAnalysisDuration(); + + return true; +} + +bool CFGFilterLAVSplitterBase::Settings::SetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + pLAVFSettings->SetTrayIcon(bTrayIcon); + + pLAVFSettings->SetPreferredLanguages(prefAudioLangs.c_str()); + pLAVFSettings->SetPreferredSubtitleLanguages(prefSubLangs.c_str()); + pLAVFSettings->SetAdvancedSubtitleConfig(subtitleAdvanced.c_str()); + + pLAVFSettings->SetSubtitleMode(subtitleMode); + + pLAVFSettings->SetPGSForcedStream(bPGSForcedStream); + + pLAVFSettings->SetPGSOnlyForced(bPGSOnlyForced); + + pLAVFSettings->SetVC1TimestampMode(iVC1Mode); + + pLAVFSettings->SetSubstreamsEnabled(bSubstreams); + + pLAVFSettings->SetLoadMatroskaExternalSegments(bMatroskaExternalSegments); + + if (lav_version >= LAV_FILTERS_VERSION(0, 75, 1, 44)) { + pLAVFSettings->SetStreamSwitchReselectSubtitles(bStreamSwitchReselectSubs); + } + + pLAVFSettings->SetStreamSwitchRemoveAudio(bStreamSwitchRemoveAudio); + + pLAVFSettings->SetUseAudioForHearingVisuallyImpaired(bImpairedAudio); + + pLAVFSettings->SetPreferHighQualityAudioStreams(bPreferHighQualityAudio); + + pLAVFSettings->SetMaxQueueMemSize(dwQueueMaxMemSize); + + pLAVFSettings->SetMaxQueueSize(dwQueueMaxPackets); + + pLAVFSettings->SetNetworkStreamAnalysisDuration(dwNetworkAnalysisDuration); + + // Custom interface available only in patched build, will be removed after it's upstreamed + if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { + pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); + } + + return true; +} + +// +// CFGFilterLAVSplitter +// + +CFGFilterLAVSplitter::CFGFilterLAVSplitter(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) + : CFGFilterLAVSplitterBase(path, GUID_LAVSplitter, L"LAV Splitter (internal)", bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +// +// CFGFilterLAVSplitterSource +// + +CFGFilterLAVSplitterSource::CFGFilterLAVSplitterSource(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) + : CFGFilterLAVSplitterBase(path, GUID_LAVSplitterSource, L"LAV Splitter Source (internal)", bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +// +// CFGFilterLAVVideo +// + +const CString CFGFilterLAVVideo::filename = _T("LAVVideo.ax"); + +CFGFilterLAVVideo::CFGFilterLAVVideo(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) + : CFGFilterLAV(GUID_LAVVideo, path, L"LAV Video Decoder (internal)", bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +HRESULT CFGFilterLAVVideo::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + HRESULT hr = __super::Create(ppBF, pUnks); + + if (SUCCEEDED(hr)) { + if (!CheckVersion(m_path)) { + hr = E_FAIL; + } else if (CComQIPtr pLAVFSettings = *ppBF) { + // Take control over LAVVideo's settings, the settings are reseted to default values + hr = pLAVFSettings->SetRuntimeConfig(TRUE); + + if (SUCCEEDED(hr)) { + if (isPreview) { + pLAVFSettings->SetNumThreads(2); + pLAVFSettings->SetPixelFormat(LAVOutPixFmt_P010, false); + pLAVFSettings->SetPixelFormat(LAVOutPixFmt_P016, false); + } else { + Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVVideo + settings.LoadSettings(); // Load our current settings from registry/ini + settings.SetSettings(pLAVFSettings); // Set our settings in LAVVideo + } + } + // Keep track of LAVFilters instances in runtime mode + s_instances.AddTail(*ppBF); + } + } else { + hr = E_NOINTERFACE; + } + } + + return hr; +} + +void CFGFilterLAVVideo::ShowPropertyPages(CWnd* pParendWnd) +{ + CFGFilterLAV::ShowPropertyPages(pParendWnd); +} + +LPCTSTR CFGFilterLAVVideo::GetUserFriendlyDecoderName(const LPCWSTR decoderName) +{ + static constexpr std::pair userFriendlyDecoderNames[] = { + std::make_pair(L"avcodec", _T("FFmpeg")), + std::make_pair(L"dxva2n", _T("DXVA2 Native")), + std::make_pair(L"dxva2cb", _T("DXVA2 Copy-back")), + std::make_pair(L"dxva2cb direct", _T("DXVA2 Copy-back (Direct)")), + std::make_pair(L"cuvid", _T("NVIDIA CUVID")), + std::make_pair(L"quicksync", _T("Intel QuickSync")), + std::make_pair(L"d3d11 cb direct", _T("D3D11 Copy-back (Direct)")), + std::make_pair(L"d3d11 cb", _T("D3D11 Copy-back")), + std::make_pair(L"d3d11 native", _T("D3D11 Native")), + std::make_pair(L"msdk mvc hw", _T("Intel H.264 (MVC 3D)")), + }; + + for (const auto& name : userFriendlyDecoderNames) { + if (wcscmp(decoderName, name.first) == 0) { + return name.second; + } + } + + return decoderName; +} + +static LPCTSTR pixFmtSettingsMap[LAVOutPixFmt_NB] = { + _T("yv12"), _T("nv12"), _T("yuy2"), _T("uyvy"), _T("ayuv"), _T("p010"), _T("p210"), _T("y410"), + _T("p016"), _T("p216"), _T("y416"), _T("rgb32"), _T("rgb24"), _T("v210"), _T("v410"), _T("yv16"), + _T("yv24"), _T("rgb48") +}; + +# define PCIV_INTEL 0x8086 +# define PCIV_AMD 0x1002 +# define PCIV_NVIDIA 0x10de +# define PCIV_QUALCOMM 0x4351 +# define PCIV_MICROSOFT 0x1414 + +bool GetGPUDetailsD3D9(DWORD* vendorid, DWORD* deviceid, DWORD* pixelshaderversion) { + bool result = false; + try { + IDirect3D9Ex* pD3D = nullptr; + HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D); + if (hr == D3D_OK && pD3D) { + UINT count = pD3D->GetAdapterCount(); + if (count > 0) { + D3DCAPS9 caps; + hr = pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); + if (hr == D3D_OK) { + *pixelshaderversion = caps.PixelShaderVersion & 0xFFFF; + } + D3DADAPTER_IDENTIFIER9 aid9; + hr = pD3D->GetAdapterIdentifier(0, 0, &aid9); + if (hr == D3D_OK) { + *vendorid = aid9.VendorId; + *deviceid = aid9.DeviceId; + result = true; + } + } + pD3D->Release(); + } + } catch (...) { + } + return result; +} + +#if 0 +#include + +bool SupportsD3D11VA() +{ + bool result = false; + try { + ID3D11Device* pDevice = nullptr; + ID3D11DeviceContext* pContext = nullptr; + D3D_FEATURE_LEVEL fl_available; + D3D_FEATURE_LEVEL fl_list[] = { D3D_FEATURE_LEVEL_11_1 }; + HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, fl_list, _countof(fl_list), D3D11_SDK_VERSION, &pDevice, &fl_available, &pContext); + if (hr == S_OK) { + if (fl_available >= D3D_FEATURE_LEVEL_11_1) { + result = true; + } + } + } catch (...) { + } + return result; +} +#endif + +// GPUs which have (slow) partial acceleration of HEVC +bool IntelHEVCBlacklist(DWORD deviceid) { + bool result = false; + + switch (deviceid) { + case 0x0412: // Haswell + case 0x0416: + case 0x041a: + case 0x041e: + case 0x0a16: + case 0x0a1e: + case 0x0a26: + case 0x0a2e: + case 0x0c02: + case 0x0c06: + case 0x0c12: + case 0x0c16: + case 0x0c22: + case 0x0c26: + case 0x0d06: + case 0x0d16: + case 0x0d22: + case 0x0d26: + case 0x1612: // Broadwell + case 0x1616: + case 0x161a: + case 0x161b: + case 0x161d: + case 0x161e: + case 0x1622: + case 0x1626: + case 0x162a: + case 0x162b: + case 0x162d: + case 0x162e: + result = true; + } + + return result; +} + +void CFGFilterLAVVideo::Settings::LoadSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("TrayIcon"), bTrayIcon); + + dwStreamAR = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("StreamAR"), dwStreamAR); + + dwNumThreads = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("NumThreads"), dwNumThreads); + + dwDeintFieldOrder = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintFieldOrder"), dwDeintFieldOrder); + + deintMode = (LAVDeintMode)pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintMode"), deintMode); + + dwRGBRange = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("RGBRange"), dwRGBRange); + + dwSWDeintMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintMode"), dwSWDeintMode); + + dwSWDeintOutput = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintOutput"), dwSWDeintOutput); + + dwDitherMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DitherMode"), dwDitherMode); + + for (int i = 0; i < LAVOutPixFmt_NB; ++i) { + bPixFmts[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_OUTPUTFORMAT, pixFmtSettingsMap[i], bPixFmts[i]); + } + + dwHWAccel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), -1); + if (dwHWAccel == DWORD(-1)) { + // Detect GPU and decide if HWA should be used + // ToDo: if MPCVR is used as renderer, check registry if it uses D3D11 and then use D3D11 decoding (if supported) + dwHWAccel = HWAccel_None; + DWORD vendorid = 0; + DWORD deviceid = 0; + DWORD pixelshaderversion = 0; + if (GetGPUDetailsD3D9(&vendorid, &deviceid, &pixelshaderversion)) { + if (pixelshaderversion >= 0x300) { + if (vendorid == PCIV_NVIDIA || vendorid == PCIV_INTEL || vendorid == PCIV_AMD || vendorid == PCIV_QUALCOMM) { + dwHWAccel = HWAccel_DXVA2Native; + if (vendorid == PCIV_INTEL && IntelHEVCBlacklist(deviceid)) { + bHWFormats[HWCodec_HEVC] = false; + } + } + } + } + } + + bHWFormats[HWCodec_H264] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264"), bHWFormats[HWCodec_H264]); + bHWFormats[HWCodec_VC1] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vc1"), bHWFormats[HWCodec_VC1]); + bHWFormats[HWCodec_MPEG2] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg2"), bHWFormats[HWCodec_MPEG2]); + bHWFormats[HWCodec_MPEG4] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg4"), bHWFormats[HWCodec_MPEG4]); + bHWFormats[HWCodec_MPEG2DVD] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("dvd"), bHWFormats[HWCodec_MPEG2DVD]); + bHWFormats[HWCodec_HEVC] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("hevc"), bHWFormats[HWCodec_HEVC]); + bHWFormats[HWCodec_VP9] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vp9"), bHWFormats[HWCodec_VP9]); + bHWFormats[HWCodec_H264MVC] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264mvc"), bHWFormats[HWCodec_H264MVC]); + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 1, 87)) { + bHWFormats[HWCodec_AV1] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("av1"), bHWFormats[HWCodec_AV1]); + } + + dwHWAccelResFlags = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWResFlags"), dwHWAccelResFlags); + + dwHWDeintMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintMode"), dwHWDeintMode); + + dwHWDeintOutput = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintOutput"), dwHWDeintOutput); + + if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { + dwHWAccelDeviceDXVA2 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2"), dwHWAccelDeviceDXVA2); + dwHWAccelDeviceDXVA2Desc = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2Desc"), dwHWAccelDeviceDXVA2Desc); + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { + dwHWAccelDeviceD3D11 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11"), dwHWAccelDeviceD3D11); + dwHWAccelDeviceD3D11Desc = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11Desc"), dwHWAccelDeviceD3D11Desc); + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { + bHWAccelCUVIDXVA = pApp->GetProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelCUVIDXVA"), bHWAccelCUVIDXVA); + } +} + +void CFGFilterLAVVideo::Settings::SaveSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("TrayIcon"), bTrayIcon); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("StreamAR"), dwStreamAR); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("NumThreads"), dwNumThreads); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintFieldOrder"), dwDeintFieldOrder); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DeintMode"), deintMode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("RGBRange"), dwRGBRange); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintMode"), dwSWDeintMode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("SWDeintOutput"), dwSWDeintOutput); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO, _T("DitherMode"), dwDitherMode); + + for (int i = 0; i < LAVOutPixFmt_NB; ++i) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_OUTPUTFORMAT, pixFmtSettingsMap[i], bPixFmts[i]); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), dwHWAccel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264"), bHWFormats[HWCodec_H264]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vc1"), bHWFormats[HWCodec_VC1]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg2"), bHWFormats[HWCodec_MPEG2]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("mpeg4"), bHWFormats[HWCodec_MPEG4]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("dvd"), bHWFormats[HWCodec_MPEG2DVD]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("hevc"), bHWFormats[HWCodec_HEVC]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("vp9"), bHWFormats[HWCodec_VP9]); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("h264mvc"), bHWFormats[HWCodec_H264MVC]); + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 1, 87)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("av1"), bHWFormats[HWCodec_AV1]); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWResFlags"), dwHWAccelResFlags); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintMode"), dwHWDeintMode); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWDeintOutput"), dwHWDeintOutput); + + if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2"), dwHWAccelDeviceDXVA2); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceDXVA2Desc"), dwHWAccelDeviceDXVA2Desc); + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11"), dwHWAccelDeviceD3D11); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelDeviceD3D11Desc"), dwHWAccelDeviceD3D11Desc); + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccelCUVIDXVA"), bHWAccelCUVIDXVA); + } +} + +bool CFGFilterLAVVideo::Settings::GetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + bTrayIcon = pLAVFSettings->GetTrayIcon(); + + dwStreamAR = pLAVFSettings->GetStreamAR(); + + dwNumThreads = pLAVFSettings->GetNumThreads(); + + dwDeintFieldOrder = pLAVFSettings->GetDeintFieldOrder(); + + deintMode = pLAVFSettings->GetDeinterlacingMode(); + + dwRGBRange = pLAVFSettings->GetRGBOutputRange(); + + dwSWDeintMode = pLAVFSettings->GetSWDeintMode(); + + dwSWDeintOutput = pLAVFSettings->GetSWDeintOutput(); + + dwDitherMode = pLAVFSettings->GetDitherMode(); + + for (int i = 0; i < LAVOutPixFmt_NB; ++i) { + bPixFmts[i] = pLAVFSettings->GetPixelFormat((LAVOutPixFmts)i); + } + + dwHWAccel = pLAVFSettings->GetHWAccel(); + + for (int i = 0; i < HWCodec_NB; ++i) { + bHWFormats[i] = pLAVFSettings->GetHWAccelCodec((LAVVideoHWCodec)i); + } + + dwHWAccelResFlags = pLAVFSettings->GetHWAccelResolutionFlags(); + + dwHWDeintMode = pLAVFSettings->GetHWAccelDeintMode(); + + dwHWDeintOutput = pLAVFSettings->GetHWAccelDeintOutput(); + + if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { + dwHWAccelDeviceDXVA2 = pLAVFSettings->GetHWAccelDeviceIndex(HWAccel_DXVA2CopyBack, &dwHWAccelDeviceDXVA2Desc); + } else { + dwHWAccelDeviceDXVA2 = LAVHWACCEL_DEVICE_DEFAULT; + dwHWAccelDeviceDXVA2Desc = 0; + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { + dwHWAccelDeviceD3D11 = pLAVFSettings->GetHWAccelDeviceIndex(HWAccel_D3D11, &dwHWAccelDeviceD3D11Desc); + } else { + dwHWAccelDeviceD3D11 = LAVHWACCEL_DEVICE_DEFAULT; + dwHWAccelDeviceD3D11Desc = 0; + } + + if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { + bHWAccelCUVIDXVA = pLAVFSettings->GetHWAccelDeintHQ(); + } else { + bHWAccelCUVIDXVA = TRUE; + } + + return true; +} + +bool CFGFilterLAVVideo::Settings::SetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + pLAVFSettings->SetTrayIcon(bTrayIcon); + + pLAVFSettings->SetStreamAR(dwStreamAR); + + pLAVFSettings->SetNumThreads(dwNumThreads); + + pLAVFSettings->SetDeintFieldOrder((LAVDeintFieldOrder)dwDeintFieldOrder); + + pLAVFSettings->SetDeinterlacingMode(deintMode); + + pLAVFSettings->SetRGBOutputRange(dwRGBRange); + + pLAVFSettings->SetSWDeintMode((LAVSWDeintModes)dwSWDeintMode); + + pLAVFSettings->SetSWDeintOutput((LAVDeintOutput)dwSWDeintOutput); + + pLAVFSettings->SetDitherMode((LAVDitherMode)dwDitherMode); + + for (int i = 0; i < LAVOutPixFmt_NB; ++i) { + pLAVFSettings->SetPixelFormat((LAVOutPixFmts)i, bPixFmts[i]); + } + + pLAVFSettings->SetHWAccel((LAVHWAccel)dwHWAccel); + + for (int i = 0; i < HWCodec_NB; ++i) { + pLAVFSettings->SetHWAccelCodec((LAVVideoHWCodec)i, bHWFormats[i]); + } + + pLAVFSettings->SetHWAccelResolutionFlags(dwHWAccelResFlags); + + pLAVFSettings->SetHWAccelDeintMode((LAVHWDeintModes)dwHWDeintMode); + + pLAVFSettings->SetHWAccelDeintOutput((LAVDeintOutput)dwHWDeintOutput); + + if (lav_version >= LAV_FILTERS_VERSION(0, 69, 0, 0)) { + pLAVFSettings->SetHWAccelDeviceIndex(HWAccel_DXVA2CopyBack, dwHWAccelDeviceDXVA2, dwHWAccelDeviceDXVA2Desc); + } + if (lav_version >= LAV_FILTERS_VERSION(0, 71, 0, 0)) { + pLAVFSettings->SetHWAccelDeviceIndex(HWAccel_D3D11, dwHWAccelDeviceD3D11, dwHWAccelDeviceD3D11Desc); + } + if (lav_version >= LAV_FILTERS_VERSION(0, 70, 0, 0)) { + pLAVFSettings->SetHWAccelDeintHQ(bHWAccelCUVIDXVA); + } + + // Force RV1/2 and v210/v410 enabled, the user can control it from our own options + pLAVFSettings->SetFormatConfiguration(Codec_RV12, TRUE); + pLAVFSettings->SetFormatConfiguration(Codec_v210, TRUE); + // Enable Cinepack and QPEG so that they can be used in low-merit mode + pLAVFSettings->SetFormatConfiguration(Codec_Cinepak, TRUE); + pLAVFSettings->SetFormatConfiguration(Codec_QPEG, TRUE); + + // Custom interface available only in patched build, will be removed after it's upstreamed + if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { + pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); + } + + if (AfxGetAppSettings().iLAVGPUDevice != DWORD_MAX) { + pLAVFSettings->SetGPUDeviceIndex(AfxGetAppSettings().iLAVGPUDevice); + } + + return true; +} + + +// +// CFGFilterLAVAudio +// + +const CString CFGFilterLAVAudio::filename = _T("LAVAudio.ax"); + +CFGFilterLAVAudio::CFGFilterLAVAudio(CString path, UINT64 merit /*= MERIT64_DO_USE*/, bool bAddLowMeritSuffix /*= false*/, bool bIsPreview /*= false*/) + : CFGFilterLAV(GUID_LAVAudio, path, L"LAV Audio Decoder (internal)", bAddLowMeritSuffix, merit, bIsPreview) +{ +} + +HRESULT CFGFilterLAVAudio::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) +{ + HRESULT hr = __super::Create(ppBF, pUnks); + + if (SUCCEEDED(hr)) { + if (!CheckVersion(m_path)) { + hr = E_FAIL; + } else if (CComQIPtr pLAVFSettings = *ppBF) { + // Take control over LAVAudio's settings, the settings are reseted to default values + hr = pLAVFSettings->SetRuntimeConfig(TRUE); + + if (SUCCEEDED(hr)) { + if (!isPreview) { + Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get default settings from LAVAudio + settings.LoadSettings(); // Load our current settings from registry/ini + settings.SetSettings(pLAVFSettings); // Set our settings in LAVAudio + } + } + // Keep track of LAVFilters instances in runtime mode + s_instances.AddTail(*ppBF); + } + } else { + hr = E_NOINTERFACE; + } + } + + return hr; +} + +void CFGFilterLAVAudio::ShowPropertyPages(CWnd* pParendWnd) +{ + CFGFilterLAV::ShowPropertyPages(pParendWnd); +} + +static LPCTSTR bitstreamingCodecs[Bitstream_NB] = { + _T("ac3"), _T("eac3"), _T("truehd"), _T("dts"), _T("dtshd") +}; + +static LPCTSTR sampleFormats[SampleFormat_Bitstream] = { + _T("s16"), _T("s24"), _T("s32"), _T("u8"), _T("fp32") +}; + +void CFGFilterLAVAudio::Settings::LoadSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + bTrayIcon = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("TrayIcon"), bTrayIcon); + + bDRCEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCEnabled"), bDRCEnabled); + + iDRCLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCLevel"), iDRCLevel); + + bDTSHDFraming = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DTSHDFraming"), bDTSHDFraming); + + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { + bBitstreamingFallback = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("BitstreamingFallback"), bBitstreamingFallback); + } + + bAutoAVSync = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AutoAVSync"), bAutoAVSync); + + bExpandMono = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("ExpandMono"), bExpandMono); + + bExpand61 = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Expand61"), bExpand61); + + bOutputStandardLayout = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("OutputStandardLayout"), bOutputStandardLayout); + + bOutput51Legacy = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Output51Legacy"), bOutput51Legacy); + + bMixingEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Mixing"), bMixingEnabled); + + dwMixingLayout = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLayout"), dwMixingLayout); + + dwMixingFlags = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingFlags"), dwMixingFlags); + + dwMixingMode = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingMode"), dwMixingMode); + + dwMixingCenterLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingCenterLevel"), dwMixingCenterLevel); + + dwMixingSurroundLevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingSurroundLevel"), dwMixingSurroundLevel); + + dwMixingLFELevel = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLFELevel"), dwMixingLFELevel); + + bAudioDelayEnabled = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelayEnabled"), bAudioDelayEnabled); + + iAudioDelay = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelay"), iAudioDelay); + + for (int i = 0; i < Bitstream_NB; ++i) { + CString key = CString(_T("Bitstreaming_")) + bitstreamingCodecs[i]; + bBitstream[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bBitstream[i]); + } + + for (int i = 0; i < SampleFormat_Bitstream; ++i) { + CString key = CString(_T("SampleFormat_")) + sampleFormats[i]; + bSampleFormats[i] = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bSampleFormats[i]); + } + + bSampleConvertDither = pApp->GetProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("SampleConvertDither"), bSampleConvertDither); +} + +void CFGFilterLAVAudio::Settings::SaveSettings() +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + ASSERT(pApp); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("TrayIcon"), bTrayIcon); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCEnabled"), bDRCEnabled); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DRCLevel"), iDRCLevel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("DTSHDFraming"), bDTSHDFraming); + + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("BitstreamingFallback"), bBitstreamingFallback); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AutoAVSync"), bAutoAVSync); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("ExpandMono"), bExpandMono); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Expand61"), bExpand61); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("OutputStandardLayout"), bOutputStandardLayout); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Output51Legacy"), bOutput51Legacy); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("Mixing"), bMixingEnabled); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLayout"), dwMixingLayout); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingFlags"), dwMixingFlags); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingMode"), dwMixingMode); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingCenterLevel"), dwMixingCenterLevel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingSurroundLevel"), dwMixingSurroundLevel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("MixingLFELevel"), dwMixingLFELevel); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelayEnabled"), bAudioDelayEnabled); + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("AudioDelay"), iAudioDelay); + + for (int i = 0; i < Bitstream_NB; ++i) { + CString key = CString(_T("Bitstreaming_")) + bitstreamingCodecs[i]; + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bBitstream[i]); + } + + for (int i = 0; i < SampleFormat_Bitstream; ++i) { + CString key = CString(_T("SampleFormat_")) + sampleFormats[i]; + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, key, bSampleFormats[i]); + } + + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVAUDIO, _T("SampleConvertDither"), bSampleConvertDither); +} + +bool CFGFilterLAVAudio::Settings::GetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + bTrayIcon = pLAVFSettings->GetTrayIcon(); + + pLAVFSettings->GetDRC(&bDRCEnabled, &iDRCLevel); + + bDTSHDFraming = pLAVFSettings->GetDTSHDFraming(); + + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { + bBitstreamingFallback = pLAVFSettings->GetBitstreamingFallback(); + } else { + bBitstreamingFallback = FALSE; + } + + bAutoAVSync = pLAVFSettings->GetAutoAVSync(); + + bExpandMono = pLAVFSettings->GetExpandMono(); + + bExpand61 = pLAVFSettings->GetExpand61(); + + bOutputStandardLayout = pLAVFSettings->GetOutputStandardLayout(); + + bOutput51Legacy = pLAVFSettings->GetOutput51LegacyLayout(); + + bMixingEnabled = pLAVFSettings->GetMixingEnabled(); + + dwMixingLayout = pLAVFSettings->GetMixingLayout(); + + dwMixingFlags = pLAVFSettings->GetMixingFlags(); + + dwMixingMode = pLAVFSettings->GetMixingMode(); + + pLAVFSettings->GetMixingLevels(&dwMixingCenterLevel, &dwMixingSurroundLevel, &dwMixingLFELevel); + + pLAVFSettings->GetAudioDelay(&bAudioDelayEnabled, &iAudioDelay); + + for (int i = 0; i < Bitstream_NB; ++i) { + bBitstream[i] = pLAVFSettings->GetBitstreamConfig((LAVBitstreamCodec)i); + } + + for (int i = 0; i < SampleFormat_Bitstream; ++i) { + bSampleFormats[i] = pLAVFSettings->GetSampleFormat((LAVAudioSampleFormat)i); + } + + bSampleConvertDither = pLAVFSettings->GetSampleConvertDithering(); + + return true; +} + +bool CFGFilterLAVAudio::Settings::SetSettings(CComQIPtr pLAVFSettings) +{ + if (!pLAVFSettings) { + return false; + } + + pLAVFSettings->SetTrayIcon(bTrayIcon); + + pLAVFSettings->SetDRC(bDRCEnabled, iDRCLevel); + + pLAVFSettings->SetDTSHDFraming(bDTSHDFraming); + + if (lav_version >= LAV_FILTERS_VERSION(0, 74, 0, 0)) { + pLAVFSettings->SetBitstreamingFallback(bBitstreamingFallback); + } + + pLAVFSettings->SetAutoAVSync(bAutoAVSync); + + pLAVFSettings->SetExpandMono(bExpandMono); + + pLAVFSettings->SetExpand61(bExpand61); + + pLAVFSettings->SetOutputStandardLayout(bOutputStandardLayout); + + pLAVFSettings->SetOutput51LegacyLayout(bOutput51Legacy); + + pLAVFSettings->SetMixingEnabled(bMixingEnabled); + + pLAVFSettings->SetMixingLayout(dwMixingLayout); + + pLAVFSettings->SetMixingFlags(dwMixingFlags); + + pLAVFSettings->SetMixingMode((LAVAudioMixingMode)dwMixingMode); + + pLAVFSettings->SetMixingLevels(dwMixingCenterLevel, dwMixingSurroundLevel, dwMixingLFELevel); + + pLAVFSettings->SetAudioDelay(bAudioDelayEnabled, iAudioDelay); + + for (int i = 0; i < Bitstream_NB; ++i) { + pLAVFSettings->SetBitstreamConfig((LAVBitstreamCodec)i, bBitstream[i]); + } + + for (int i = 0; i < SampleFormat_Bitstream; ++i) { + pLAVFSettings->SetSampleFormat((LAVAudioSampleFormat)i, bSampleFormats[i]); + } + + pLAVFSettings->SetSampleConvertDithering(bSampleConvertDither); + + // The internal LAV Audio Decoder will not be registered to handle WMA formats + // since the system decoder is preferred. However we can still enable those + // formats internally so that they are used in low-merit mode. + pLAVFSettings->SetFormatConfiguration(Codec_WMA2, TRUE); + pLAVFSettings->SetFormatConfiguration(Codec_WMAPRO, TRUE); + pLAVFSettings->SetFormatConfiguration(Codec_WMALL, TRUE); + + // Custom interface available only in patched build, will be removed after it's upstreamed + if (CComQIPtr pLAVFSettingsMPCHCCustom = pLAVFSettings) { + pLAVFSettingsMPCHCCustom->SetPropertyPageCallback(PropertyPageCallback); + } + + return true; +} diff --git a/src/mpc-hc/FGManager.cpp b/src/mpc-hc/FGManager.cpp index 79d8f2169ae..5a6dcfba1c7 100644 --- a/src/mpc-hc/FGManager.cpp +++ b/src/mpc-hc/FGManager.cpp @@ -1,3044 +1,3044 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "FGManager.h" -#include "../DeCSS/VobFile.h" -#include "../filters/Filters.h" -#include "AllocatorCommon.h" -#include "DeinterlacerFilter.h" -#include "FakeFilterMapper2.h" -#include "FileVersionInfo.h" -#include "IPinHook.h" -#include "NullRenderers.h" -#include "PathUtils.h" -#include "SyncAllocatorPresenter.h" -#include "mplayerc.h" -#include "sanear/src/Factory.h" -#include "../src/thirdparty/MpcAudioRenderer/MpcAudioRenderer.h" -#include "DSUtil.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "../src/thirdparty/LAVFilters/src/include/IURLSourceFilterLAV.h" - -#include -#include "moreuuids.h" -#include - -#if !TRACE_GRAPH_BUILD -#undef TRACE -#define TRACE(...) -#endif - -// -// CFGManager -// - -class CNullAudioRenderer; - -CFGManager::CFGManager(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) - : CUnknown(pName, pUnk) - , m_dwRegister(0) - , m_hWnd(hWnd) - , m_bIsPreview(IsPreview) - , m_bPreviewSupportsRotation(false) - , m_ignoreVideo(false) - , m_bIsCapture(false) - , m_source() - , m_transform() - , m_override() - , m_deadends() - , m_aborted(false) - , m_useragent() - , m_referrer() -{ - m_pUnkInner.CoCreateInstance(CLSID_FilterGraph, GetOwner()); - m_pFM.CoCreateInstance(CLSID_FilterMapper2); -} - -CFGManager::~CFGManager() -{ - CAutoLock cAutoLock(this); - while (!m_source.IsEmpty()) { - delete m_source.RemoveHead(); - } - while (!m_transform.IsEmpty()) { - delete m_transform.RemoveHead(); - } - while (!m_override.IsEmpty()) { - delete m_override.RemoveHead(); - } - m_pUnks.RemoveAll(); - m_pUnkInner.Release(); -} - -STDMETHODIMP CFGManager::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IFilterGraph) - QI(IGraphBuilder) - QI(IFilterGraph2) - QI(IGraphBuilder2) - QI(IGraphBuilderDeadEnd) - (m_pUnkInner && riid != IID_IUnknown && SUCCEEDED(m_pUnkInner->QueryInterface(riid, ppv))) ? S_OK : - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// - -void CFGManager::CStreamPath::Append(IBaseFilter* pBF, IPin* pPin) -{ - path_t p; - p.clsid = GetCLSID(pBF); - p.filter = GetFilterName(pBF); - p.pin = GetPinName(pPin); - AddTail(p); -} - -bool CFGManager::CStreamPath::Compare(const CStreamPath& path) -{ - POSITION pos1 = GetHeadPosition(); - POSITION pos2 = path.GetHeadPosition(); - - while (pos1 && pos2) { - const path_t& p1 = GetNext(pos1); - const path_t& p2 = path.GetNext(pos2); - - if (p1.filter != p2.filter) { - return true; - } else if (p1.pin != p2.pin) { - return false; - } - } - - return true; -} - -// - -bool CFGManager::CheckBytes(HANDLE hFile, CString chkbytes) -{ - CAtlList sl; - Explode(chkbytes, sl, ','); - - if (sl.GetCount() < 4) { - return false; - } - - ASSERT(!(sl.GetCount() & 3)); - - LARGE_INTEGER size = {0, 0}; - GetFileSizeEx(hFile, &size); - - while (sl.GetCount() >= 4) { - CString offsetstr = sl.RemoveHead(); - CString cbstr = sl.RemoveHead(); - CString maskstr = sl.RemoveHead(); - CString valstr = sl.RemoveHead(); - - long cb = _ttol(cbstr); - - if (offsetstr.IsEmpty() || cbstr.IsEmpty() - || valstr.IsEmpty() || (valstr.GetLength() & 1) - || cb * 2 != valstr.GetLength()) { - return false; - } - - LARGE_INTEGER offset; - offset.QuadPart = _ttoi64(offsetstr); - if (offset.QuadPart < 0) { - offset.QuadPart = size.QuadPart - offset.QuadPart; - } - SetFilePointerEx(hFile, offset, &offset, FILE_BEGIN); - - // LAME - while (maskstr.GetLength() < valstr.GetLength()) { - maskstr += _T('F'); - } - - CAtlArray mask, val; - CStringToBin(maskstr, mask); - CStringToBin(valstr, val); - - for (size_t i = 0; i < val.GetCount(); i++) { - BYTE b; - DWORD r; - if (!ReadFile(hFile, &b, 1, &r, nullptr) || (b & mask[i]) != val[i]) { - return false; - } - } - } - - return sl.IsEmpty(); -} - -CFGFilter* LookupFilterRegistry(const GUID& guid, CAtlList& list, UINT64 fallback_merit = MERIT64_DO_USE) -{ - POSITION pos = list.GetHeadPosition(); - CFGFilter* pFilter = nullptr; - while (pos) { - CFGFilter* pFGF = list.GetNext(pos); - if (pFGF->GetCLSID() == guid) { - pFilter = pFGF; - break; - } - } - if (pFilter) { - return DEBUG_NEW CFGFilterRegistry(guid, pFilter->GetMerit()); - } else { - return DEBUG_NEW CFGFilterRegistry(guid, fallback_merit); - } -} - -HRESULT CFGManager::EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl) -{ - // TODO: use overrides - - CheckPointer(lpcwstrFileName, E_POINTER); - - fl.RemoveAll(); - - CStringW fn = CStringW(lpcwstrFileName).TrimLeft(); - CStringW cfn = fn; - if (cfn.Left(4) == "\\\\?\\") { - cfn = cfn.Mid(4); - } - CStringW protocol = cfn.Left(cfn.Find(':') + 1).TrimRight(':').MakeLower(); - CStringW ext = CPathW(fn).GetExtension().MakeLower(); - - HANDLE hFile = INVALID_HANDLE_VALUE; - - if (protocol.GetLength() <= 1 || protocol == L"file") { - hFile = CreateFile(CString(fn), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)nullptr); - - // In case of audio CDs with extra content, the audio tracks - // cannot be accessed directly so we have to try opening it - if (hFile == INVALID_HANDLE_VALUE && ext != L".cda") { - return VFW_E_NOT_FOUND; - } - } - - if (hFile == INVALID_HANDLE_VALUE) { - // internal / protocol - - POSITION pos = m_source.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_source.GetNext(pos); - if (pFGF->m_protocols.Find(CString(protocol))) { - fl.Insert(pFGF, 0, false, false); - } - } - } else { - // internal / check bytes - - POSITION pos = m_source.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_source.GetNext(pos); - - POSITION pos2 = pFGF->m_chkbytes.GetHeadPosition(); - while (pos2) { - if (CheckBytes(hFile, pFGF->m_chkbytes.GetNext(pos2))) { - fl.Insert(pFGF, 1, false, false); - break; - } - } - } - } - - if (!ext.IsEmpty()) { - // internal / file extension - - POSITION pos = m_source.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_source.GetNext(pos); - if (pFGF->m_extensions.Find(CString(ext))) { - fl.Insert(pFGF, 2, false, false); - } - } - } - - { - // internal / the rest - - POSITION pos = m_source.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_source.GetNext(pos); - if (pFGF->m_protocols.IsEmpty() && pFGF->m_chkbytes.IsEmpty() && pFGF->m_extensions.IsEmpty()) { - fl.Insert(pFGF, 3, false, false); - } - } - } - - TCHAR buff[256]; - ULONG len; - - if (hFile == INVALID_HANDLE_VALUE) { - // protocol - - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, CString(protocol), KEY_READ)) { - CRegKey exts; - if (ERROR_SUCCESS == exts.Open(key, _T("Extensions"), KEY_READ)) { - len = _countof(buff); - if (ERROR_SUCCESS == exts.QueryStringValue(CString(ext), buff, &len)) { - fl.Insert(LookupFilterRegistry(GUIDFromCString(buff), m_override), 4); - } - } - - len = _countof(buff); - if (ERROR_SUCCESS == key.QueryStringValue(_T("Source Filter"), buff, &len)) { - fl.Insert(LookupFilterRegistry(GUIDFromCString(buff), m_override), 5); - } - } - - fl.Insert(DEBUG_NEW CFGFilterRegistry(CLSID_URLReader), 6); - } else { - // check bytes - - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Media Type"), KEY_READ)) { - FILETIME ft; - len = _countof(buff); - for (DWORD i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len, &ft); i++, len = _countof(buff)) { - GUID majortype; - if (FAILED(GUIDFromCString(buff, majortype))) { - continue; - } - - CRegKey majorkey; - if (ERROR_SUCCESS == majorkey.Open(key, buff, KEY_READ)) { - len = _countof(buff); - for (DWORD j = 0; ERROR_SUCCESS == majorkey.EnumKey(j, buff, &len, &ft); j++, len = _countof(buff)) { - GUID subtype; - if (FAILED(GUIDFromCString(buff, subtype))) { - continue; - } - - CRegKey subkey; - if (ERROR_SUCCESS == subkey.Open(majorkey, buff, KEY_READ)) { - len = _countof(buff); - if (ERROR_SUCCESS != subkey.QueryStringValue(_T("Source Filter"), buff, &len)) { - continue; - } - - GUID clsid = GUIDFromCString(buff); - TCHAR buff2[256]; - ULONG len2; - - len = _countof(buff); - len2 = sizeof(buff2); - for (DWORD k = 0, type; - clsid != GUID_NULL && ERROR_SUCCESS == RegEnumValue(subkey, k, buff2, &len2, 0, &type, (BYTE*)buff, &len); - k++, len = _countof(buff), len2 = sizeof(buff2)) { - if (CheckBytes(hFile, CString(buff))) { - CFGFilter* pFGF = LookupFilterRegistry(clsid, m_override); - pFGF->AddType(majortype, subtype); - if (pFGF->GetMerit() >= MERIT64_ABOVE_DSHOW) { - fl.Insert(pFGF, 7); - } else { - fl.Insert(pFGF, 9); - } - break; - } - } - } - } - } - } - } - } - - if (!ext.IsEmpty()) { - // file extension - - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Media Type\\Extensions\\") + CString(ext), KEY_READ)) { - len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - LONG ret = key.QueryStringValue(_T("Source Filter"), buff, &len); // QueryStringValue can return ERROR_INVALID_DATA on bogus strings (radlight mpc v1003, fixed in v1004) - if (ERROR_SUCCESS == ret || ERROR_INVALID_DATA == ret && GUIDFromCString(buff) != GUID_NULL) { - GUID clsid = GUIDFromCString(buff); - GUID majortype = GUID_NULL; - GUID subtype = GUID_NULL; - - len = _countof(buff); - if (ERROR_SUCCESS == key.QueryStringValue(_T("Media Type"), buff, &len)) { - majortype = GUIDFromCString(buff); - } - - len = _countof(buff); - if (ERROR_SUCCESS == key.QueryStringValue(_T("Subtype"), buff, &len)) { - subtype = GUIDFromCString(buff); - } - - CFGFilter* pFGF = LookupFilterRegistry(clsid, m_override); - pFGF->AddType(majortype, subtype); - fl.Insert(pFGF, 7); - } - } - - // preferred external filters - if (ext == L".avs" || ext == L".vpy") { - POSITION pos = m_override.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_override.GetNext(pos); - if (pFGF->GetMerit() >= MERIT64_ABOVE_DSHOW) { - if (pFGF->GetCLSID() == GUIDFromCString(L"{7D3BBD5A-880D-4A30-A2D1-7B8C2741AFEF}")) { // MPC Script Source - if (ext == L".avs" || ext == L".vpy") { - fl.Insert(pFGF, 0, false, false); - } - } - } - } - } - } - - if (hFile != INVALID_HANDLE_VALUE) { - CloseHandle(hFile); - - CFGFilter* pFGF = LookupFilterRegistry(CLSID_AsyncReader, m_override); - pFGF->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_NULL); - fl.Insert(pFGF, 9); - } - - return S_OK; -} - -HRESULT CFGManager::AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF) -{ - CLSID clsid = pFGF->GetCLSID(); - TRACE(_T("FGM: AddSourceFilter trying '%s'\n"), CStringFromGUID(clsid).GetString()); - - CheckPointer(lpcwstrFileName, E_POINTER); - CheckPointer(ppBF, E_POINTER); - - ASSERT(*ppBF == nullptr); - - HRESULT hr; - - CComPtr pBF; - CInterfaceList pUnks; - if (FAILED(hr = pFGF->Create(&pBF, pUnks))) { - return hr; - } - - CComQIPtr pFSF = pBF; - if (!pFSF) { - return E_NOINTERFACE; - } - - if (clsid == __uuidof(CRARFileSource) && m_entryRFS.GetLength() > 0) { - CComPtr rfs = static_cast(pBF.p); - std::wstring preselectedRarFileEntry(m_entryRFS.GetBuffer()); - rfs->SetPreselectedRarFileEntry(preselectedRarFileEntry); - } - - if (FAILED(hr = AddFilter(pBF, lpcwstrFilterName))) { - return hr; - } - - const AM_MEDIA_TYPE* pmt = nullptr; - if (clsid == GUID_LAVSplitterSource) { - CComQIPtr pSFL = pBF; - if (pSFL && (!m_useragent.IsEmpty() || !m_referrer.IsEmpty())) { - // ToDo: set strings - hr = pSFL->LoadURL(lpcwstrFileName, m_useragent, m_referrer); - if (FAILED(hr)) { - RemoveFilter(pBF); - return hr; - } - } else { - hr = pFSF->Load(lpcwstrFileName, pmt); - if (FAILED(hr)) { - RemoveFilter(pBF); - return hr; - } - } - } else { - CMediaType mt; - const CAtlList& types = pFGF->GetTypes(); - if (types.GetCount() == 2 && (types.GetHead() != GUID_NULL || types.GetTail() != GUID_NULL)) { - mt.majortype = types.GetHead(); - mt.subtype = types.GetTail(); - pmt = &mt; - } - - hr = pFSF->Load(lpcwstrFileName, pmt); - if (FAILED(hr) || m_aborted) { // sometimes looping with AviSynth - RemoveFilter(pBF); - return m_aborted ? E_ABORT : hr; - } - - BeginEnumMediaTypes(GetFirstPin(pBF, PINDIR_OUTPUT), pEMT, pmt2) { - static const GUID guid1 = - { 0x640999A0, 0xA946, 0x11D0, { 0xA5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // ASX file Parser - static const GUID guid2 = - { 0x640999A1, 0xA946, 0x11D0, { 0xA5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // ASX v.2 file Parser - static const GUID guid3 = - { 0xD51BD5AE, 0x7548, 0x11CF, { 0xA5, 0x20, 0x00, 0x80, 0xC7, 0x7E, 0xF5, 0x8A } }; // XML Playlist - - if (pmt2->subtype == guid1 || pmt2->subtype == guid2 || pmt2->subtype == guid3) { - RemoveFilter(pBF); - pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_NetShowSource); - hr = AddSourceFilter(pFGF, lpcwstrFileName, lpcwstrFilterName, ppBF); - delete pFGF; - return hr; - } - } - EndEnumMediaTypes(pmt2); - } - - *ppBF = pBF.Detach(); - - m_pUnks.AddTailList(&pUnks); - - return S_OK; -} - -// IFilterGraph - -STDMETHODIMP CFGManager::AddFilter(IBaseFilter* pFilter, LPCWSTR pName) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (FAILED(hr = CComQIPtr(m_pUnkInner)->AddFilter(pFilter, pName))) { - return hr; - } - - // TODO - hr = pFilter->JoinFilterGraph(nullptr, nullptr); - hr = pFilter->JoinFilterGraph(this, pName); - - return hr; -} - -STDMETHODIMP CFGManager::RemoveFilter(IBaseFilter* pFilter) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->RemoveFilter(pFilter); -} - -STDMETHODIMP CFGManager::EnumFilters(IEnumFilters** ppEnum) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - // Not locking here fixes a deadlock involving ReClock - //CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->EnumFilters(ppEnum); -} - -STDMETHODIMP CFGManager::FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->FindFilterByName(pName, ppFilter); -} - -STDMETHODIMP CFGManager::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - CComPtr pBF = GetFilterFromPin(pPinIn); - CLSID clsid = GetCLSID(pBF); - - // TODO: GetUpStreamFilter goes up on the first input pin only - for (CComPtr pBFUS = GetFilterFromPin(pPinOut); pBFUS; pBFUS = GetUpStreamFilter(pBFUS)) { - if (pBFUS == pBF) { - return VFW_E_CIRCULAR_GRAPH; - } - if (clsid != CLSID_Proxy && GetCLSID(pBFUS) == clsid) { - return VFW_E_CANNOT_CONNECT; - } - } - - return CComQIPtr(m_pUnkInner)->ConnectDirect(pPinOut, pPinIn, pmt); -} - -STDMETHODIMP CFGManager::Reconnect(IPin* ppin) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->Reconnect(ppin); -} - -STDMETHODIMP CFGManager::Disconnect(IPin* ppin) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->Disconnect(ppin); -} - -STDMETHODIMP CFGManager::SetDefaultSyncSource() -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->SetDefaultSyncSource(); -} - -// IGraphBuilder - -STDMETHODIMP CFGManager::Connect(IPin* pPinOut, IPin* pPinIn) -{ - return Connect(pPinOut, pPinIn, true); -} - -HRESULT CFGManager::Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPinOut, E_POINTER); - - if (m_aborted) { - return E_ABORT; - } - - HRESULT hr; - - if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT) - || pPinIn && S_OK != IsPinDirection(pPinIn, PINDIR_INPUT)) { - return VFW_E_INVALID_DIRECTION; - } - - if (S_OK == IsPinConnected(pPinOut) - || pPinIn && S_OK == IsPinConnected(pPinIn)) { - return VFW_E_ALREADY_CONNECTED; - } - - bool fDeadEnd = true; - - if (pPinIn) { - // 1. Try a direct connection between the filters, with no intermediate filters - - if (SUCCEEDED(hr = ConnectDirect(pPinOut, pPinIn, nullptr))) { - return hr; - } - } else { - // 1. Use IStreamBuilder - - if (CComQIPtr pSB = pPinOut) { - if (SUCCEEDED(hr = pSB->Render(pPinOut, this))) { - return hr; - } - - pSB->Backout(pPinOut, this); - } - } - - // 2. Try cached filters - - CComPtr pFilterPinIn = nullptr; - if (pPinIn) { - pFilterPinIn = GetFilterFromPin(pPinIn); - } - - if (CComQIPtr pGC = (IGraphBuilder2*)this) { - BeginEnumCachedFilters(pGC, pEF, pBF) { - if (pFilterPinIn && pFilterPinIn == pBF) { - continue; - } - - hr = pGC->RemoveFilterFromCache(pBF); - - // does RemoveFilterFromCache call AddFilter like AddFilterToCache calls RemoveFilter ? - - if (SUCCEEDED(hr = ConnectFilterDirect(pPinOut, pBF, nullptr))) { - if (!IsStreamEnd(pBF)) { - fDeadEnd = false; - } - - if (SUCCEEDED(hr = ConnectFilter(pBF, pPinIn))) { - return hr; - } - } - - hr = pGC->AddFilterToCache(pBF); - } - EndEnumCachedFilters; - } - - // 3. Try filters in the graph - - CComPtr pFilterPinOut = GetFilterFromPin(pPinOut); - CLSID clsid_pinout = GetCLSID(pFilterPinOut); - - { - CInterfaceList pBFs; - - BeginEnumFilters(this, pEF, pBF) { - if (pFilterPinIn && pFilterPinIn == pBF || pFilterPinOut == pBF) { - continue; - } - - // HACK: ffdshow - audio capture filter - if (clsid_pinout == GUIDFromCString(_T("{04FE9017-F873-410E-871E-AB91661A4EF7}")) - && GetCLSID(pBF) == GUIDFromCString(_T("{E30629D2-27E5-11CE-875D-00608CB78066}"))) { - continue; - } - - pBFs.AddTail(pBF); - } - EndEnumFilters; - - POSITION pos = pBFs.GetHeadPosition(); - while (pos) { - IBaseFilter* pBF = pBFs.GetNext(pos); - - if (SUCCEEDED(hr = ConnectFilterDirect(pPinOut, pBF, nullptr))) { - if (!IsStreamEnd(pBF)) { - fDeadEnd = false; - } - - if (SUCCEEDED(hr = ConnectFilter(pBF, pPinIn))) { - return hr; - } - } - - EXECUTE_ASSERT(SUCCEEDED(Disconnect(pPinOut))); - } - } - - // 4. Look up filters in the registry - - { - // workaround for Cyberlink video decoder, which can have an unwanted output pin - if (clsid_pinout == GUIDFromCString(_T("{F8FC6C1F-DE81-41A8-90FF-0316FDD439FD}"))) { - CPinInfo infoPinOut; - if (SUCCEEDED(pPinOut->QueryPinInfo(&infoPinOut))) { - if (CString(infoPinOut.achName) == L"~Encode Out") { - // ignore this pin - return S_OK; - } - } - } - - CFGFilterList fl; - - CAtlArray types; - ExtractMediaTypes(pPinOut, types); - - POSITION pos = m_transform.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_transform.GetNext(pos); - if (pFGF->GetMerit() < MERIT64_DO_USE || pFGF->CheckTypes(types, false)) { - fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true), false); - } - } - - pos = m_override.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = m_override.GetNext(pos); - if (pFGF->GetMerit() < MERIT64_DO_USE || pFGF->CheckTypes(types, false)) { - fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true), false); - } - } - - CComPtr pEM; - if (!types.IsEmpty() - && SUCCEEDED(m_pFM->EnumMatchingFilters( - &pEM, 0, FALSE, MERIT_DO_NOT_USE + 1, - TRUE, (DWORD)types.GetCount() / 2, types.GetData(), nullptr, nullptr, FALSE, - !!pPinIn, 0, nullptr, nullptr, nullptr))) { - for (CComPtr pMoniker; S_OK == pEM->Next(1, &pMoniker, nullptr); pMoniker = nullptr) { - CFGFilterRegistry* pFGF = DEBUG_NEW CFGFilterRegistry(pMoniker); - fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true)); - } - } - - // let's check whether the madVR allocator presenter is in our list - // it should be if madVR is selected as the video renderer - CFGFilter* pMadVRAllocatorPresenter = nullptr; - pos = fl.GetHeadPosition(); - while (pos) { - CFGFilter* pFGF = fl.GetNext(pos); - if (pFGF->GetCLSID() == CLSID_madVRAllocatorPresenter) { - // found it! - pMadVRAllocatorPresenter = pFGF; - break; - } - } - - pos = fl.GetHeadPosition(); - while (pos) { - if (m_aborted) { - return E_ABORT; - } - - CFGFilter* pFGF = fl.GetNext(pos); - - // avoid pointless connection attempts - CLSID candidate = pFGF->GetCLSID(); - if (clsid_pinout == candidate) { - continue; - } else if (candidate == CLSID_VSFilter) { - if (clsid_pinout == GUID_LAVAudio || clsid_pinout == __uuidof(CAudioSwitcherFilter)) { - continue; - } - } else if (candidate == CLSID_RDPDShowRedirectionFilter) { - if (clsid_pinout == __uuidof(CAudioSwitcherFilter)) { - continue; - } - } else if (candidate == GUID_LAVAudio) { - if (clsid_pinout == __uuidof(CAudioSwitcherFilter)) { - continue; - } - } - -#if 0 - // Checks if madVR is already in the graph to avoid two instances at the same time - CComPtr pBFmadVR; - FindFilterByName(_T("madVR"), &pBFmadVR); - if (pBFmadVR && (pFGF->GetName() == _T("madVR"))) { - continue; - } -#endif - - if (pMadVRAllocatorPresenter && (pFGF->GetCLSID() == CLSID_madVR)) { - // the pure madVR filter was selected (without the allocator presenter) - // subtitles, OSD etc don't work correctly without the allocator presenter - // so we prefer the allocator presenter over the pure filter - pFGF = pMadVRAllocatorPresenter; - } - - CString filtername = pFGF->GetName().GetString(); - if (filtername.IsEmpty()) { - filtername = CLSIDToString(candidate); - } - TRACE(_T("FGM: Connecting '%s'\n"), filtername); - - CComPtr pBF; - CInterfaceList pUnks; - if (FAILED(pFGF->Create(&pBF, pUnks))) { - TRACE(_T("FGM: Filter creation failed\n")); - if (!m_bIsCapture) { - // Check if selected video renderer fails to load - CLSID filter = pFGF->GetCLSID(); - if (filter == CLSID_MPCVRAllocatorPresenter || filter == CLSID_madVRAllocatorPresenter || filter == CLSID_DXRAllocatorPresenter) { - if (IDYES == AfxMessageBox(_T("The selected video renderer has failed to load.\n\nThe player will now fallback to using a basic video renderer, which has reduced performance and quality. Subtitles may also fail to load.\n\nDo you want to change settings to use the default video renderer (EVR-CP/VMR9)? (player restart required)"), MB_ICONEXCLAMATION | MB_YESNO, 0)) { - CAppSettings& s = AfxGetAppSettings(); - s.iDSVideoRendererType = IsCLSIDRegistered(CLSID_EnhancedVideoRenderer) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS; - } - } else if (filter == CLSID_EVRAllocatorPresenter || filter == CLSID_VMR9AllocatorPresenter) { - if (IDYES == AfxMessageBox(_T("The selected video renderer has failed to load.\n\nThis problem is often caused by a bug in the graphics driver. Or you may be using a generic driver which has limited capabilities. It is recommended to update the graphics driver to solve this problem. A proper driver is required for optimal video playback performance and quality.\n\nThe player will now fallback to using a basic video renderer, which has reduced performance and quality. Subtitles may also fail to load.\n\nYou can select a different renderer here:\nOptions > playback > Output\n\nDo you want to use the basic video renderer by default?"), MB_ICONEXCLAMATION | MB_YESNO, 0)) { - CAppSettings& s = AfxGetAppSettings(); - s.iDSVideoRendererType = IsCLSIDRegistered(CLSID_EnhancedVideoRenderer) ? VIDRNDT_DS_EVR : VIDRNDT_DS_VMR9WINDOWED; - s.SetSubtitleRenderer(CAppSettings::SubtitleRenderer::VS_FILTER); - // Disable DXVA in internal video decoder - CMPlayerCApp* pApp = AfxGetMyApp(); - pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), 0); - } - } - } - continue; - } - - if (FAILED(hr = AddFilter(pBF, pFGF->GetName()))) { - TRACE(_T("FGM: Adding the filter failed\n")); - pUnks.RemoveAll(); - pBF.Release(); - continue; - } - - hr = ConnectFilterDirect(pPinOut, pBF, nullptr); - /* - if (FAILED(hr)) - { - if (types.GetCount() >= 2 && types[0] == MEDIATYPE_Stream && types[1] != GUID_NULL) - { - CMediaType mt; - - mt.majortype = types[0]; - mt.subtype = types[1]; - mt.formattype = FORMAT_None; - if (FAILED(hr)) hr = ConnectFilterDirect(pPinOut, pBF, &mt); - - mt.formattype = GUID_NULL; - if (FAILED(hr)) hr = ConnectFilterDirect(pPinOut, pBF, &mt); - } - } - */ - if (SUCCEEDED(hr)) { - TRACE(_T("FGM: Filter connected to %s\n"), CLSIDToString(clsid_pinout)); - if (!IsStreamEnd(pBF)) { - fDeadEnd = false; - } - - if (m_aborted) { - return E_ABORT; - } - - if (bContinueRender) { - hr = ConnectFilter(pBF, pPinIn); - } - - if (SUCCEEDED(hr)) { - m_pUnks.AddTailList(&pUnks); - - // maybe the application should do this... - - POSITION posInterface = pUnks.GetHeadPosition(); - while (posInterface) { - if (CComQIPtr pMPC = pUnks.GetNext(posInterface)) { - pMPC->SetAspectRatioMode(AM_ARMODE_STRETCHED); - } - } - - if (CComQIPtr pARC = pBF) { - pARC->SetAspectRatioMode(VMR_ARMODE_NONE); - } - - if (CComQIPtr pARC = pBF) { - pARC->SetAspectRatioMode(VMR_ARMODE_NONE); - } - - if (CComQIPtr pMC = pBF) { - m_pUnks.AddTail(pMC); - } - - if (CComQIPtr pMB = pBF) { - m_pUnks.AddTail(pMB); - } - - if (CComQIPtr pMFVMB = pBF) { - m_pUnks.AddTail(pMFVMB); - } - - if (CComQIPtr pMFGS = pBF) { - CComPtr pMFVDC; - CComPtr pMFMB; - CComPtr pMFVP; - - if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVDC)))) { - m_pUnks.AddTail(pMFVDC); - } - - if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&pMFMB)))) { - m_pUnks.AddTail(pMFMB); - } - - if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&pMFVP)))) { - m_pUnks.AddTail(pMFVP); - } - } - - return hr; - } - } - - TRACE(_T("FGM: Failed to connect to %s\n"), CLSIDToString(clsid_pinout)); - CPinInfo infoPinOut; - if (SUCCEEDED(pPinOut->QueryPinInfo(&infoPinOut))) { - TRACE(_T("FGM: Output pin name: %s\n"), infoPinOut.achName); - } - EXECUTE_ASSERT(SUCCEEDED(RemoveFilter(pBF))); - pUnks.RemoveAll(); - pBF.Release(); - } - } - - if (fDeadEnd) { - CAutoPtr psde(DEBUG_NEW CStreamDeadEnd()); - psde->AddTailList(&m_streampath); - int skip = 0; - BeginEnumMediaTypes(pPinOut, pEM, pmt) { - if (pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_NULL) { - skip++; - } - psde->mts.AddTail(CMediaType(*pmt)); - } - EndEnumMediaTypes(pmt); - if (skip < (int)psde->mts.GetCount()) { - m_deadends.Add(psde); - } - } - - return pPinIn ? VFW_E_CANNOT_CONNECT : VFW_E_CANNOT_RENDER; -} - -STDMETHODIMP CFGManager::Render(IPin* pPinOut) -{ - CAutoLock cAutoLock(this); - - return RenderEx(pPinOut, 0, nullptr); -} - -HRESULT CFGManager::RenderRFSFileEntry(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList, CStringW entryRFS){ - this->m_entryRFS = entryRFS; - return RenderFile(lpcwstrFileName, lpcwstrPlayList); -} - -CUnknown* WINAPI CFGManager::GetMpcAudioRendererInstance(LPUNKNOWN lpunk, HRESULT* phr) { - return CreateInstance(lpunk, phr); -} - -STDMETHODIMP CFGManager::RenderFile(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList) -{ - TRACE(_T("CFGManager::RenderFile on thread: %lu\n"), GetCurrentThreadId()); - CAutoLock cAutoLock(this); - - m_streampath.RemoveAll(); - m_deadends.RemoveAll(); - - HRESULT hr; - HRESULT hrRFS = S_OK; - - CFGFilterList fl; - if (FAILED(hr = EnumSourceFilters(lpcwstrFileName, fl))) { - return hr; - } - - CAutoPtrArray deadends; - - hr = VFW_E_CANNOT_RENDER; - - POSITION pos = fl.GetHeadPosition(); - while (pos) { - CComPtr pBF; - CFGFilter* pFG = fl.GetNext(pos); - - if (SUCCEEDED(hr = AddSourceFilter(pFG, lpcwstrFileName, pFG->GetName(), &pBF))) { - m_streampath.RemoveAll(); - m_deadends.RemoveAll(); - - if (m_ignoreVideo) { - CFGFilter* pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_COMP), MERIT64_ABOVE_DSHOW + 3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } - - if (SUCCEEDED(hr = ConnectFilter(pBF, nullptr))) { - // insert null video renderer on next RenderFile call which is used for audio dubs - m_ignoreVideo = True; - TRACE(_T("CFGManager::RenderFile complete\n")); - return hr; - } - - NukeDownstream(pBF); - RemoveFilter(pBF); - - deadends.Append(m_deadends); - - if (hr == E_ABORT) { - break; - } - } else if (pFG->GetCLSID() == __uuidof(CRARFileSource) && HRESULT_FACILITY(hr) == FACILITY_ITF) { - hrRFS = hr; - } - } - - m_deadends.Copy(deadends); - - // If RFS was part of the graph, return its error code instead of the last error code. - // TODO: Improve filter error reporting to graph manager. - return hrRFS != S_OK ? hrRFS : hr; -} - -STDMETHODIMP CFGManager::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - CFGFilterList fl; - - if (FAILED(hr = EnumSourceFilters(lpcwstrFileName, fl))) { - return hr; - } - - POSITION pos = fl.GetHeadPosition(); - while (pos) { - if (SUCCEEDED(hr = AddSourceFilter(fl.GetNext(pos), lpcwstrFileName, lpcwstrFilterName, ppFilter))) { - return hr; - } - } - - return VFW_E_CANNOT_LOAD_SOURCE_FILTER; -} - -STDMETHODIMP CFGManager::SetLogFile(DWORD_PTR hFile) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->SetLogFile(hFile); -} - -STDMETHODIMP CFGManager::Abort() -{ - if (!m_pUnkInner) { - ASSERT(false); - return E_UNEXPECTED; - } - - // When a filter (renderer) in the child thread (the graph thread) calls CreateWindow() - // then that call triggers an implicit call of SendMessage to the main window. - // This is a blocking call, meaning main thread must be able to process that window message. - // So we can not request a lock here when called from main thread since that would result in a deadlock. - //CAutoLock cAutoLock(this); - - m_aborted = true; - - return CComQIPtr(m_pUnkInner)->Abort(); -} - -STDMETHODIMP CFGManager::ShouldOperationContinue() -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->ShouldOperationContinue(); -} - -// IFilterGraph2 - -STDMETHODIMP CFGManager::AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->AddSourceFilterForMoniker(pMoniker, pCtx, lpcwstrFilterName, ppFilter); -} - -STDMETHODIMP CFGManager::ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt) -{ - if (!m_pUnkInner) { - return E_UNEXPECTED; - } - - CAutoLock cAutoLock(this); - - return CComQIPtr(m_pUnkInner)->ReconnectEx(ppin, pmt); -} - -STDMETHODIMP CFGManager::RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext) -{ - CAutoLock cAutoLock(this); - - m_streampath.RemoveAll(); - m_deadends.RemoveAll(); - - if (!pPinOut || dwFlags > AM_RENDEREX_RENDERTOEXISTINGRENDERERS || pvContext) { - return E_INVALIDARG; - } - - if (dwFlags & AM_RENDEREX_RENDERTOEXISTINGRENDERERS) { - CInterfaceList pBFs; - - BeginEnumFilters(this, pEF, pBF) { - if (CComQIPtr pAMMF = pBF) { - if (pAMMF->GetMiscFlags() & AM_FILTER_MISC_FLAGS_IS_RENDERER) { - pBFs.AddTail(pBF); - } - } else { - BeginEnumPins(pBF, pEP, pPin) { - CComPtr pPinIn; - DWORD size = 1; - if (SUCCEEDED(pPin->QueryInternalConnections(&pPinIn, &size)) && size == 0) { - pBFs.AddTail(pBF); - break; - } - } - EndEnumPins; - } - } - EndEnumFilters; - - while (!pBFs.IsEmpty()) { - HRESULT hr; - if (SUCCEEDED(hr = ConnectFilter(pPinOut, pBFs.RemoveHead()))) { - return hr; - } - } - - return VFW_E_CANNOT_RENDER; - } - - return Connect(pPinOut, (IPin*)nullptr); -} - -// IGraphBuilder2 - -STDMETHODIMP CFGManager::IsPinDirection(IPin* pPin, PIN_DIRECTION dir1) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPin, E_POINTER); - - PIN_DIRECTION dir2; - if (FAILED(pPin->QueryDirection(&dir2))) { - return E_FAIL; - } - - return dir1 == dir2 ? S_OK : S_FALSE; -} - -STDMETHODIMP CFGManager::IsPinConnected(IPin* pPin) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPin, E_POINTER); - - CComPtr pPinTo; - return SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo ? S_OK : S_FALSE; -} - -STDMETHODIMP CFGManager::ConnectFilter(IBaseFilter* pBF, IPin* pPinIn) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pBF, E_POINTER); - - if (m_aborted) { - return E_ABORT; - } - - if (pPinIn && S_OK != IsPinDirection(pPinIn, PINDIR_INPUT)) { - return VFW_E_INVALID_DIRECTION; - } - - int nTotal = 0, nRendered = 0; - - const CAppSettings& s = AfxGetAppSettings(); - - BeginEnumPins(pBF, pEP, pPin) { - if (S_OK == IsPinDirection(pPin, PINDIR_OUTPUT) - && S_OK != IsPinConnected(pPin) - && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { - - CLSID clsid; - pBF->GetClassID(&clsid); - // Disable DVD subtitle mixing in EVR (CP) and Sync Renderer for Microsoft DTV-DVD Video Decoder, it corrupts DVD playback. - if (clsid == CLSID_CMPEG2VidDecoderDS) { - if (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { - if (GetPinName(pPin)[0] == '~') { - continue; - } - } - } - // No multiple pin for Internal MPEG2 Software Decoder, NVIDIA PureVideo Decoder, Sonic Cinemaster VideoDecoder - else if (clsid == CLSID_CMpeg2DecFilter - || clsid == CLSID_NvidiaVideoDecoder - || clsid == CLSID_SonicCinemasterVideoDecoder) { - if (GetPinName(pPin)[0] == '~') { - continue; - } - //TODO: enable multiple pins for the renderer, if the video decoder supports DXVA - } - - m_streampath.Append(pBF, pPin); - - HRESULT hr = Connect(pPin, pPinIn); - - if (SUCCEEDED(hr)) { - for (int i = (int)m_deadends.GetCount() - 1; i >= 0; i--) { - if (m_deadends.GetAt(i)->Compare(m_streampath)) { - m_deadends.RemoveAt(i); - } - } - nRendered++; - } - - nTotal++; - - m_streampath.RemoveTail(); - - if (SUCCEEDED(hr) && pPinIn) { - return S_OK; - } - } - } - EndEnumPins; - - return - nRendered == nTotal ? (nRendered > 0 ? S_OK : S_FALSE) : - nRendered > 0 ? VFW_S_PARTIAL_RENDER : - VFW_E_CANNOT_RENDER; -} - -STDMETHODIMP CFGManager::ConnectFilter(IPin* pPinOut, IBaseFilter* pBF) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPinOut, E_POINTER); - CheckPointer(pBF, E_POINTER); - - if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT)) { - return VFW_E_INVALID_DIRECTION; - } - - const CAppSettings& s = AfxGetAppSettings(); - - BeginEnumPins(pBF, pEP, pPin) { - if (S_OK == IsPinDirection(pPin, PINDIR_INPUT) - && S_OK != IsPinConnected(pPin) - && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { - HRESULT hr = Connect(pPinOut, pPin); - if (SUCCEEDED(hr)) { - return hr; - } - } - } - EndEnumPins; - - return VFW_E_CANNOT_CONNECT; -} - -STDMETHODIMP CFGManager::ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) -{ - CAutoLock cAutoLock(this); - - CheckPointer(pPinOut, E_POINTER); - CheckPointer(pBF, E_POINTER); - - if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT)) { - return VFW_E_INVALID_DIRECTION; - } - - const CAppSettings& s = AfxGetAppSettings(); - - BeginEnumPins(pBF, pEP, pPin) { - if (S_OK == IsPinDirection(pPin, PINDIR_INPUT) - && S_OK != IsPinConnected(pPin) - && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { - HRESULT hr = ConnectDirect(pPinOut, pPin, pmt); - if (SUCCEEDED(hr)) { - return hr; - } - } - } - EndEnumPins; - - return VFW_E_CANNOT_CONNECT; -} - -STDMETHODIMP CFGManager::NukeDownstream(IUnknown* pUnk) -{ - CAutoLock cAutoLock(this); - - if (CComQIPtr pBF = pUnk) { - BeginEnumPins(pBF, pEP, pPin) { - NukeDownstream(pPin); - } - EndEnumPins; - } else if (CComQIPtr pPin = pUnk) { - CComPtr pPinTo; - if (S_OK == IsPinDirection(pPin, PINDIR_OUTPUT) - && SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { - if (pBF = GetFilterFromPin(pPinTo)) { - if (GetCLSID(pBF) == CLSID_EnhancedVideoRenderer) { - // GetFilterFromPin() returns pointer to the Base EVR, - // but we need to remove Outer EVR from the graph. - CComPtr pOuterEVR; - if (SUCCEEDED(pBF->QueryInterface(&pOuterEVR))) { - pBF = pOuterEVR; - } - } - NukeDownstream(pBF); - Disconnect(pPinTo); - Disconnect(pPin); - RemoveFilter(pBF); - } - } - } else { - return E_INVALIDARG; - } - - return S_OK; -} - -STDMETHODIMP CFGManager::FindInterface(REFIID iid, void** ppv, BOOL bRemove) -{ - CAutoLock cAutoLock(this); - - CheckPointer(ppv, E_POINTER); - - for (POSITION pos = m_pUnks.GetHeadPosition(); pos; m_pUnks.GetNext(pos)) { - if (SUCCEEDED(m_pUnks.GetAt(pos)->QueryInterface(iid, ppv))) { - if (bRemove) { - m_pUnks.RemoveAt(pos); - } - return S_OK; - } - } - - return E_NOINTERFACE; -} - -STDMETHODIMP CFGManager::AddToROT() -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (m_dwRegister) { - return S_FALSE; - } - - CComPtr pROT; - CComPtr pMoniker; - WCHAR wsz[256]; - swprintf_s(wsz, _countof(wsz), L"FilterGraph %08p pid %08x (MPC-HC)", this, GetCurrentProcessId()); - if (SUCCEEDED(hr = GetRunningObjectTable(0, &pROT)) - && SUCCEEDED(hr = CreateItemMoniker(L"!", wsz, &pMoniker))) { - hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, (IGraphBuilder2*)this, pMoniker, &m_dwRegister); - } - - return hr; -} - -STDMETHODIMP CFGManager::RemoveFromROT() -{ - if (!m_dwRegister) { - return S_FALSE; - } - - //CAutoLock cAutoLock(this); - - HRESULT hr; - CComPtr pROT; - if (SUCCEEDED(hr = GetRunningObjectTable(0, &pROT)) - && SUCCEEDED(hr = pROT->Revoke(m_dwRegister))) { - m_dwRegister = 0; - } - - return hr; -} - -// IGraphBuilderDeadEnd - -STDMETHODIMP_(size_t) CFGManager::GetCount() -{ - CAutoLock cAutoLock(this); - - return m_deadends.GetCount(); -} - -STDMETHODIMP CFGManager::GetDeadEnd(int iIndex, CAtlList& path, CAtlList& mts) -{ - CAutoLock cAutoLock(this); - - if (iIndex < 0 || iIndex >= (int)m_deadends.GetCount()) { - return E_FAIL; - } - - path.RemoveAll(); - mts.RemoveAll(); - - POSITION pos = m_deadends[iIndex]->GetHeadPosition(); - while (pos) { - const path_t& p = m_deadends[iIndex]->GetNext(pos); - - CStringW str; - str.Format(L"%s::%s", p.filter.GetString(), p.pin.GetString()); - path.AddTail(str); - } - - mts.AddTailList(&m_deadends[iIndex]->mts); - - return S_OK; -} - -// -// Custom Filter Injection -// - -void CFGManagerCustom::InsertLAVSplitterSource(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* src = s.SrcFilters; - - CFGFilterLAV* filter; - if (IsPreview) { - filter = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER_SOURCE); - } else { - filter = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER_SOURCE); - } - CAutoPtr pFGLAVSplitterSource(static_cast (filter)); - -#if INTERNAL_SOURCEFILTER_AVI - if (src[SRC_AVI] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,41564920")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,41564958")); - pFGLAVSplitterSource->AddEnabledFormat("avi"); - } -#endif - -#if INTERNAL_SOURCEFILTER_AVS - if (src[SRC_AVS] || IsPreview) { - pFGLAVSplitterSource->m_extensions.AddTail(_T(".avs")); - pFGLAVSplitterSource->AddEnabledFormat("avisynth"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MP4 - if (src[SRC_MP4] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,66747970")); // ftyp - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,6d6f6f76")); // moov - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,6d646174")); // mdat - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,736b6970")); // skip - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,12,ffffffff00000000ffffffff,77696465027fe3706d646174")); // wide ? mdat - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("3,3,,000001")); // raw mpeg4 video - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mov")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mp4")); - pFGLAVSplitterSource->AddEnabledFormat("mp4"); - } -#endif - -#if INTERNAL_SOURCEFILTER_FLV - if (src[SRC_FLV] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,464C5601")); // FLV (v1) - pFGLAVSplitterSource->AddEnabledFormat("flv"); - } -#endif - -#if INTERNAL_SOURCEFILTER_GIF - if (src[SRC_GIF] && !IsPreview) { - pFGLAVSplitterSource->m_extensions.AddTail(_T(".gif")); - pFGLAVSplitterSource->AddEnabledFormat("gif"); - } -#endif - -#if INTERNAL_SOURCEFILTER_ASF - if (src[SRC_ASF] || IsPreview) { - pFGLAVSplitterSource->m_extensions.AddTail(_T(".wmv")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".asf")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dvr-ms")); - pFGLAVSplitterSource->AddEnabledFormat("asf"); - } -#endif - -#if INTERNAL_SOURCEFILTER_WTV - if (src[SRC_WTV] || IsPreview) { - pFGLAVSplitterSource->m_extensions.AddTail(_T(".wtv")); - pFGLAVSplitterSource->AddEnabledFormat("wtv"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MATROSKA - if (src[SRC_MATROSKA] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,1A45DFA3")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mkv")); - pFGLAVSplitterSource->AddEnabledFormat("matroska"); - } -#endif - -#if INTERNAL_SOURCEFILTER_REALMEDIA - if (src[SRC_REALMEDIA] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,2E524D46")); - pFGLAVSplitterSource->AddEnabledFormat("rm"); - } -#endif - -#if INTERNAL_SOURCEFILTER_FLIC - if (src[SRC_FLIC] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,2,,11AF")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,2,,12AF")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".fli")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".flc")); - pFGLAVSplitterSource->AddEnabledFormat("flic"); - } -#endif - -#if INTERNAL_SOURCEFILTER_FLAC - if (src[SRC_FLAC] && !IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,664C6143")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".flac")); - pFGLAVSplitterSource->AddEnabledFormat("flac"); - } -#endif - -#if INTERNAL_SOURCEFILTER_OGG - if (src[SRC_OGG] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4F676753")); - pFGLAVSplitterSource->AddEnabledFormat("ogg"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MPEG - if (src[SRC_MPEG] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,16,FFFFFFFFF100010001800001FFFFFFFF,000001BA2100010001800001000001BB")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,5,FFFFFFFFC0,000001BA40")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,54467263,1660,1,,47")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,8,fffffc00ffe00000,4156000055000000")); - pFGLAVSplitterSource->AddEnabledFormat("mpeg"); - pFGLAVSplitterSource->AddEnabledFormat("mpegraw"); - } - if (src[SRC_MPEGTS] || IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,1,,47,188,1,,47,376,1,,47")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,1,,47,196,1,,47,388,1,,47")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".ts")); // for some broken .ts - pFGLAVSplitterSource->AddEnabledFormat("mpegts"); - } - if (src[SRC_MPEG] || src[SRC_MPEGTS] || IsPreview) { - // for Blu-ray playback - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,494E4458")); // INDX (index.bdmv) - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4D4F424A")); // MOBJ (MovieObject.bdmv) - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4D504C53")); // MPLS - } -#endif - -#if INTERNAL_SOURCEFILTER_AC3 - if (src[SRC_AC3] && !IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,2,,0B77")); // AC3, E-AC3 - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,F8726FBB")); // MLP - pFGLAVSplitterSource->m_extensions.AddTail(_T(".ac3")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".eac3")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mlp")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".truehd")); - pFGLAVSplitterSource->AddEnabledFormat("ac3"); - pFGLAVSplitterSource->AddEnabledFormat("eac3"); - pFGLAVSplitterSource->AddEnabledFormat("mlp"); - pFGLAVSplitterSource->AddEnabledFormat("truehd"); - } -#endif - -#if INTERNAL_SOURCEFILTER_DTS - if (src[SRC_DTS] && !IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,7FFE8001")); // DTS - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,fE7f0180")); // DTS LE - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,8,,57415645666D7420"));// RIFFxxxxWAVEfmt_ for DTSWAV - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dts")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dtshd")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dtsma")); - pFGLAVSplitterSource->AddEnabledFormat("dts"); - pFGLAVSplitterSource->AddEnabledFormat("dtshd"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MPEGAUDIO - if (src[SRC_MPA] && !IsPreview) { - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,2,FFE0,FFE0")); - pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,10,FFFFFF00000080808080,49443300000000000000")); - pFGLAVSplitterSource->AddEnabledFormat("mp3"); - } -#endif - -#if INTERNAL_SOURCEFILTER_HTTP - if (src[SRC_HTTP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("http")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("https")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("icyx")); - pFGLAVSplitterSource->AddEnabledFormat("http"); - pFGLAVSplitterSource->AddEnabledFormat("dash"); - pFGLAVSplitterSource->AddEnabledFormat("hls"); - } -#endif - -#if INTERNAL_SOURCEFILTER_RTSP - if (src[SRC_RTSP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtsp")); - // Add transport protocol specific RTSP URL handlers - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspu")); // UDP - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspm")); // UDP multicast - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspt")); // TCP - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtsph")); // HTTP - pFGLAVSplitterSource->AddEnabledFormat("rtsp"); - } -#endif - -#if INTERNAL_SOURCEFILTER_UDP - if (src[SRC_UDP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("udp")); - pFGLAVSplitterSource->AddEnabledFormat("udp"); - } -#endif - -#if INTERNAL_SOURCEFILTER_RTP - if (src[SRC_RTP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtp")); - pFGLAVSplitterSource->AddEnabledFormat("rtp"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MMS - if (src[SRC_MMS] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("mms")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("mmsh")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("mmst")); - pFGLAVSplitterSource->AddEnabledFormat("mms"); - } -#endif - -#if INTERNAL_SOURCEFILTER_RTMP - if (src[SRC_RTMP] && !IsPreview) { - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtmp")); - pFGLAVSplitterSource->m_protocols.AddTail(_T("rtmpt")); - pFGLAVSplitterSource->AddEnabledFormat("live_flv"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MISC - // ToDo: split into separate options - if (src[SRC_MISC] || IsPreview) { - // video - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dv")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".dhav")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".m3u8")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".y4m")); - pFGLAVSplitterSource->AddEnabledFormat("dv"); - pFGLAVSplitterSource->AddEnabledFormat("dhav"); - pFGLAVSplitterSource->AddEnabledFormat("y4m"); - } - if (src[SRC_MISC] && !IsPreview) { - // raw video - pFGLAVSplitterSource->m_extensions.AddTail(_T(".264")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".265")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".h264")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".h265")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".av1")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".m4v")); - pFGLAVSplitterSource->AddEnabledFormat("av1"); - pFGLAVSplitterSource->AddEnabledFormat("m4v"); - pFGLAVSplitterSource->AddEnabledFormat("rawvideo"); - // audio - pFGLAVSplitterSource->m_extensions.AddTail(_T(".amr")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".ape")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".mpc")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".w64")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".wav")); - pFGLAVSplitterSource->m_extensions.AddTail(_T(".wv")); - pFGLAVSplitterSource->AddEnabledFormat("amr"); - pFGLAVSplitterSource->AddEnabledFormat("ape"); - pFGLAVSplitterSource->AddEnabledFormat("mpc"); - pFGLAVSplitterSource->AddEnabledFormat("mpc8"); - pFGLAVSplitterSource->AddEnabledFormat("w64"); - pFGLAVSplitterSource->AddEnabledFormat("wav"); - pFGLAVSplitterSource->AddEnabledFormat("wv"); - } -#endif - - // Always register the pipe protocol to allow handling standard input - pFGLAVSplitterSource->m_protocols.AddTail(_T("pipe")); - - // Add LAV Source Filter if needed - if (!pFGLAVSplitterSource->m_extensions.IsEmpty() - || !pFGLAVSplitterSource->m_chkbytes.IsEmpty() - || !pFGLAVSplitterSource->m_protocols.IsEmpty()) { - m_source.AddTail(pFGLAVSplitterSource.Detach()); - } -} - -void CFGManagerCustom::InsertLAVSplitter(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* src = s.SrcFilters; - - CFGFilterLAV* filterHM, * filterLM; - if (IsPreview) { - filterHM = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER, MERIT64_ABOVE_DSHOW); - filterLM = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER, MERIT64_DO_USE, true); - } else { - filterHM = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER, MERIT64_ABOVE_DSHOW); - filterLM = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER, MERIT64_DO_USE, true); - } - CAutoPtr pFGLAVSplitter(static_cast(filterHM)); - CAutoPtr pFGLAVSplitterLM(static_cast(filterLM)); - -#if INTERNAL_SOURCEFILTER_MATROSKA - if (src[SRC_MATROSKA] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Matroska); - pFGLAVSplitter->AddEnabledFormat("matroska"); - } -#endif - -#if INTERNAL_SOURCEFILTER_REALMEDIA - if (src[SRC_REALMEDIA] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_RealMedia); - pFGLAVSplitter->AddEnabledFormat("rm"); - } -#endif - -#if INTERNAL_SOURCEFILTER_AVI - if (src[SRC_AVI] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Avi); - pFGLAVSplitter->AddEnabledFormat("avi"); - } -#endif - -#if INTERNAL_SOURCEFILTER_AVS - if (src[SRC_AVS] || IsPreview) { - pFGLAVSplitter->AddEnabledFormat("avisynth"); - } -#endif - -#if INTERNAL_SOURCEFILTER_OGG - if (src[SRC_OGG] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Ogg); - pFGLAVSplitter->AddEnabledFormat("ogg"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MPEG - if (src[SRC_MPEG] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1System); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PROGRAM); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PVA); - pFGLAVSplitter->AddEnabledFormat("mpeg"); - pFGLAVSplitter->AddEnabledFormat("mpegraw"); - } - if (src[SRC_MPEGTS] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_TRANSPORT); - pFGLAVSplitter->AddEnabledFormat("mpegts"); - } -#endif - -#if INTERNAL_SOURCEFILTER_AC3 - if (src[SRC_AC3] && !IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_AC3); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_TRUEHD); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_DDPLUS); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MLP); - pFGLAVSplitter->AddEnabledFormat("ac3"); - pFGLAVSplitter->AddEnabledFormat("eac3"); - } -#endif - -#if INTERNAL_SOURCEFILTER_DTS - if (src[SRC_DTS] && !IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DTS); - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DTS_HD); - pFGLAVSplitter->AddEnabledFormat("dts"); - pFGLAVSplitter->AddEnabledFormat("dtshd"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MPEGAUDIO - if (src[SRC_MPA] && !IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio); - pFGLAVSplitter->AddEnabledFormat("mp3"); - } -#endif - -#if INTERNAL_SOURCEFILTER_MP4 - if (src[SRC_MP4] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MP4); - pFGLAVSplitter->AddEnabledFormat("mp4"); - } -#endif - -#if INTERNAL_SOURCEFILTER_FLV - if (src[SRC_FLV] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_FLV); - pFGLAVSplitter->AddEnabledFormat("flv"); - } -#endif - -#if INTERNAL_SOURCEFILTER_ASF - if (src[SRC_ASF] || IsPreview) { - pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_ASF); - pFGLAVSplitter->AddEnabledFormat("asf"); - } -#endif - - // Add LAV Splitter if needed - if (!pFGLAVSplitter->GetTypes().IsEmpty()) { - m_transform.AddTail(pFGLAVSplitter.Detach()); - } - - if (!IsPreview && pFGLAVSplitterLM) { - // Add low merit LAV Splitter - pFGLAVSplitterLM->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_NULL); - pFGLAVSplitterLM->AddEnabledFormat("*"); - // Explicitly disable all common subtitles format - pFGLAVSplitterLM->AddDisabledFormat("aqtitle"); - pFGLAVSplitterLM->AddDisabledFormat("ass"); - pFGLAVSplitterLM->AddDisabledFormat("dvbsub"); - pFGLAVSplitterLM->AddDisabledFormat("dvbtxt"); - pFGLAVSplitterLM->AddDisabledFormat("jacosub"); - pFGLAVSplitterLM->AddDisabledFormat("lrc"); - pFGLAVSplitterLM->AddDisabledFormat("microdvd"); - pFGLAVSplitterLM->AddDisabledFormat("mpl2"); - pFGLAVSplitterLM->AddDisabledFormat("mpsub"); - pFGLAVSplitterLM->AddDisabledFormat("realtext"); - pFGLAVSplitterLM->AddDisabledFormat("sami"); - pFGLAVSplitterLM->AddDisabledFormat("srt"); - pFGLAVSplitterLM->AddDisabledFormat("stl"); - pFGLAVSplitterLM->AddDisabledFormat("subviewer"); - pFGLAVSplitterLM->AddDisabledFormat("subviewer1"); - pFGLAVSplitterLM->AddDisabledFormat("sup"); - pFGLAVSplitterLM->AddDisabledFormat("vobsub"); - pFGLAVSplitterLM->AddDisabledFormat("vplayer"); - pFGLAVSplitterLM->AddDisabledFormat("webvtt"); - m_transform.AddTail(pFGLAVSplitterLM.Detach()); - } -} - -void CFGManagerCustom::InsertOtherInternalSourcefilters(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* src = s.SrcFilters; - CFGFilter* pFGF; - -#if INTERNAL_SOURCEFILTER_RFS - if (src[SRC_RFS] || IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_chkbytes.AddTail(_T("0,7,,526172211A0700")); // rar4 signature - pFGF->m_chkbytes.AddTail(_T("0,8,,526172211A070100")); // rar5 signature - pFGF->m_extensions.AddTail(_T(".rar")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_CDDA - if (src[SRC_CDDA] && !IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_extensions.AddTail(_T(".cda")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_CDXA - if (src[SRC_CDXA] || IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,43445841")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_VTS - if (src[SRC_VTS] || IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_chkbytes.AddTail(_T("0,12,,445644564944454F2D565453")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_DSM - if (src[SRC_DSM] || IsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(); - pFGF->m_chkbytes.AddTail(_T("0,4,,44534D53")); - m_source.AddTail(pFGF); - } -#endif - -#if INTERNAL_SOURCEFILTER_DSM - if (src[SRC_DSM]) { - pFGF = DEBUG_NEW CFGFilterInternal(DSMSplitterName, MERIT64_ABOVE_DSHOW); - } else { - pFGF = DEBUG_NEW CFGFilterInternal(LowMerit(DSMSplitterName), MERIT64_DO_USE); - } - pFGF->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DirectShowMedia); - pFGF->AddType(MEDIATYPE_Stream, GUID_NULL); - m_transform.AddTail(pFGF); -#endif -} - -void CFGManagerCustom::InsertLAVVideo(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* tra = s.TraFilters; - CFGFilter* pFGF; - - CAutoPtr pFGLAVVideo (IsPreview ? CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::VIDEO_DECODER, MERIT64_ABOVE_DSHOW) : CFGFilterLAV::CreateFilter(CFGFilterLAV::VIDEO_DECODER, MERIT64_ABOVE_DSHOW)); - CAutoPtr pFGLAVVideoLM(IsPreview ? CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::VIDEO_DECODER, MERIT64_DO_USE, true) : CFGFilterLAV::CreateFilter(CFGFilterLAV::VIDEO_DECODER, MERIT64_DO_USE, true)); - -#if INTERNAL_DECODER_MPEG1 - pFGF = IsPreview || tra[TRA_MPEG1] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Packet); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Payload); -#endif -#if INTERNAL_DECODER_FLV - pFGF = IsPreview || tra[TRA_FLV4] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLV1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_flv1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLV4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_flv4); -#endif -#if INTERNAL_DECODER_VP356 - pFGF = IsPreview || tra[TRA_VP356] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP30); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP31); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP40); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP50); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp50); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP60); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp60); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP61); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp61); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP62); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp62); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP6F); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp6f); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP6A); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp6a); -#endif -#if INTERNAL_DECODER_H264 - pFGF = IsPreview || tra[TRA_H264] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_X264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_x264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VSSH); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vssh); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DAVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_davc); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_PAVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_pavc); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_avc1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264_bis); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CCV1); -#endif -#if INTERNAL_DECODER_HEVC - pFGF = IsPreview || tra[TRA_HEVC] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HEVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HM10); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H265); -#endif -#if INTERNAL_DECODER_VVC - pFGF = IsPreview || tra[TRA_VVC] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VVC1); -#endif -#if INTERNAL_DECODER_AV1 - pFGF = IsPreview || tra[TRA_AV1] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AV01); -#endif -#if INTERNAL_DECODER_VC1 - pFGF = IsPreview || tra[TRA_VC1] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wvc1); -#endif -#if INTERNAL_DECODER_XVID - pFGF = IsPreview || tra[TRA_XVID] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_XVID); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_xvid); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_XVIX); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_xvix); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP4V); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp4v); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_M4S2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_m4s2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP4S); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp4s); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IV1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3iv1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IV2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3iv2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IVX); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3ivx); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_BLZ0); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_blz0); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DM4V); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dm4v); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DXGM); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dxgm); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_fmp4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HDX4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_hdx4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_LMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_lmp4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NDIG); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ndig); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_RMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_rmp4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_smp4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SEDG); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_sedg); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_UMP4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ump4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WV1F); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wv1f); -#endif -#if INTERNAL_DECODER_DIVX - pFGF = IsPreview || tra[TRA_DIVX] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIVX); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_divx); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DX50); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dx50); -#endif -#if INTERNAL_DECODER_WMV - pFGF = IsPreview || tra[TRA_WMV] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_2VMW); -#endif -#if INTERNAL_DECODER_MSMPEG4 - pFGF = IsPreview || tra[TRA_MSMPEG4] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DVX3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dvx3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP43); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp43); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_COL1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_col1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV5); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div5); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV6); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div6); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AP41); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap41); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mpg3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP42); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp42); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mpg4); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP41); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp41); -#endif -#if INTERNAL_DECODER_SVQ - pFGF = IsPreview || tra[TRA_SVQ3] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SVQ3); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SVQ1); -#endif -#if INTERNAL_DECODER_H263 - pFGF = IsPreview || tra[TRA_H263] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H263); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h263); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_S263); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_s263); -#endif -#if INTERNAL_DECODER_THEORA - pFGF = IsPreview || tra[TRA_THEORA] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_THEORA); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_theora); -#endif -#if INTERNAL_DECODER_AMVV - pFGF = IsPreview || tra[TRA_AMVV] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AMVV); -#endif -#if INTERNAL_DECODER_VP8 - pFGF = IsPreview || tra[TRA_VP8] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP80); -#endif -#if INTERNAL_DECODER_VP9 - pFGF = IsPreview || tra[TRA_VP9] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP90); -#endif -#if INTERNAL_DECODER_MJPEG - pFGF = IsPreview || tra[TRA_MJPEG] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPG); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_QTJpeg); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPA); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPB); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVRn); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_LJPG); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_JPGL); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJLS); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPA); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPB); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SP5X); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SP54); -#endif -#if INTERNAL_DECODER_INDEO - pFGF = IsPreview || tra[TRA_INDEO] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV31); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV32); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV41); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV50); -#endif -#if INTERNAL_DECODER_SCREEN - pFGF = IsPreview || tra[TRA_SCREEN] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_TSCC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_TSC2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VMNC); -#endif -#if INTERNAL_DECODER_FLIC - pFGF = IsPreview || tra[TRA_FLIC] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLIC); -#endif -#if INTERNAL_DECODER_MSVIDEO - pFGF = IsPreview || tra[TRA_MSVIDEO] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CRAM); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WHAM); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MSVC); -#endif -#if INTERNAL_DECODER_V210_V410 - pFGF = IsPreview || tra[TRA_V210_V410] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_v210); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_v410); -#endif -#if INTERNAL_DECODER_MPEG2 - pFGF = IsPreview || tra[TRA_MPEG2] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG2); -#endif -#if INTERNAL_DECODER_PRORES - pFGF = IsPreview || tra[TRA_PRORES] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apch); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apcn); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apcs); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apco); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap4h); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap4x); -#endif -#if INTERNAL_DECODER_DNXHD - pFGF = IsPreview || tra[TRA_DNXHD] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVdn); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVdh); -#endif -#if INTERNAL_DECODER_OTHERVIDEO - pFGF = IsPreview || tra[TRA_OTHERVIDEO] ? pFGLAVVideo : pFGLAVVideoLM; - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CFHD); -#endif - - // Add LAV Video if needed - if (!pFGLAVVideo->GetTypes().IsEmpty()) { - m_transform.AddTail(pFGLAVVideo.Detach()); - } - - // Add low merit LAV video - pFGLAVVideoLM->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGLAVVideoLM.Detach()); -} - -void CFGManagerCustom::InsertLAVAudio() -{ - const CAppSettings& s = AfxGetAppSettings(); - const bool* tra = s.TraFilters; - CFGFilter* pFGF; - - CAutoPtr pFGLAVAudio(CFGFilterLAV::CreateFilter(CFGFilterLAV::AUDIO_DECODER, MERIT64_ABOVE_DSHOW)); - CAutoPtr pFGLAVAudioLM(CFGFilterLAV::CreateFilter(CFGFilterLAV::AUDIO_DECODER, MERIT64_DO_USE, true)); - -#if INTERNAL_DECODER_MPEGAUDIO - pFGF = tra[TRA_MPA] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MP3); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1AudioPayload); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Payload); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Packet); - - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG2_AUDIO); -#endif - -#if INTERNAL_DECODER_AMR - pFGF = tra[TRA_AMR] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_SAMR); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AMR); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_SAWB); -#endif - -#if INTERNAL_DECODER_LPCM - pFGF = tra[TRA_LPCM] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_HDMV_LPCM_AUDIO); -#endif - -#if INTERNAL_DECODER_AC3 - pFGF = tra[TRA_AC3] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WAVE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_TRUEHD); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_DDPLUS); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MLP); -#endif - -#if INTERNAL_DECODER_DTS - pFGF = tra[TRA_DTS] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DTS_HD); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WAVE_DTS); -#endif - -#if INTERNAL_DECODER_AAC - pFGF = tra[TRA_AAC] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_AAC); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_AAC); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AAC); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_LATM_AAC); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AAC_ADTS); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MP4A); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MP4A); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MP4A); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_mp4a); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_mp4a); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_mp4a); -#endif - -#if INTERNAL_DECODER_PS2AUDIO - pFGF = tra[TRA_PS2AUD] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_PS2_PCM); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_PS2_PCM); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PS2_PCM); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_PS2_ADPCM); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_PS2_ADPCM); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PS2_ADPCM); -#endif - -#if INTERNAL_DECODER_VORBIS - pFGF = tra[TRA_VORBIS] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_Vorbis2); -#endif - -#if INTERNAL_DECODER_FLAC - pFGF = tra[TRA_FLAC] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_FLAC_FRAMED); -#endif - -#if INTERNAL_DECODER_NELLYMOSER - pFGF = tra[TRA_NELLY] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NELLYMOSER); -#endif - -#if INTERNAL_DECODER_ALAC - pFGF = tra[TRA_ALAC] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ALAC); -#endif - -#if INTERNAL_DECODER_ALS - pFGF = tra[TRA_ALS] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ALS); -#endif - -#if INTERNAL_DECODER_OPUS - pFGF = tra[TRA_OPUS] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_OPUS); -#endif - -#if INTERNAL_DECODER_WMA - pFGF = tra[TRA_WMA] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MSAUDIO1); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO2); -#endif - -#if INTERNAL_DECODER_WMAPRO - pFGF = tra[TRA_WMAPRO] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO3); -#endif - -#if INTERNAL_DECODER_WMALL - pFGF = tra[TRA_WMALL] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO_LOSSLESS); -#endif - -#if INTERNAL_DECODER_PCM - pFGF = tra[TRA_PCM] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_NONE); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_RAW); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_TWOS); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_SOWT); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_IN24); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_IN32); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_FL32); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_FL64); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IEEE_FLOAT); // only for 64-bit float PCM - /* todo: this should not depend on PCM */ - #if INTERNAL_DECODER_ADPCM - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMA4); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ADPCM_SWF); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ADPCM_AMV); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMA_WAV); - #endif -#endif - -#if INTERNAL_DECODER_G726 - pFGF = tra[TRA_G726] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_G726); -#endif - -#if INTERNAL_DECODER_G729 - pFGF = tra[TRA_G729] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_G729); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_729A); -#endif - -#if INTERNAL_DECODER_OTHERAUDIO - pFGF = tra[TRA_OTHERAUDIO] ? pFGLAVAudio : pFGLAVAudioLM; - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMC); -#endif - - // Add LAV Audio if needed - if (!pFGLAVAudio->GetTypes().IsEmpty()) { - m_transform.AddTail(pFGLAVAudio.Detach()); - } - - // Add low merit LAV Audio - pFGLAVAudioLM->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGLAVAudioLM.Detach()); -} - -void CFGManagerCustom::InsertBlockedFilters() -{ - // "Subtitle Mixer" makes an access violation around the - // 11-12th media type when enumerating them on its output. - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{00A95963-3BE5-48C0-AD9F-3356D67EA09D}")), MERIT64_DO_NOT_USE)); - - // DiracSplitter.ax is crashing MPC-HC when opening invalid files... - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{09E7F58E-71A1-419D-B0A0-E524AE1454A9}")), MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{5899CFB9-948F-4869-A999-5544ECB38BA5}")), MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{F78CF248-180E-4713-B107-B13F7B5C31E1}")), MERIT64_DO_NOT_USE)); - - // ISCR suxx - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}")), MERIT64_DO_NOT_USE)); - - // Samsung's "mpeg-4 demultiplexor" can even open matroska files, amazing... - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{99EC0C72-4D1B-411B-AB1F-D561EE049D94}")), MERIT64_DO_NOT_USE)); - - // LG Video Renderer (lgvid.ax) just crashes when trying to connect it - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{9F711C60-0668-11D0-94D4-0000C02BA972}")), MERIT64_DO_NOT_USE)); - - // palm demuxer crashes (even crashes graphedit when dropping an .ac3 onto it) - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{BE2CF8A7-08CE-4A2C-9A25-FD726A999196}")), MERIT64_DO_NOT_USE)); - - // mainconcept color space converter - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{272D77A0-A852-4851-ADA4-9091FEAD4C86}")), MERIT64_DO_NOT_USE)); - - // mainconcept mp4 demuxer - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{2A55FF12-1657-41D7-9D2D-A2CDC6978FF2}")), MERIT64_DO_NOT_USE)); - - // Accusoft PICVideo M-JPEG Codec - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{4C4CD9E1-F876-11D2-962F-00500471FDDC}")), MERIT64_DO_NOT_USE)); - - // SolveigMM MP4 Demultiplexer (smm_mp4demuxer.ax) - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{5F19B8FE-BA79-4183-B3CF-FEE4E8F801E4}")), MERIT64_DO_NOT_USE)); - - // Morgan's Stream Switcher (mmswitch.ax) - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_MorganStreamSwitcher, MERIT64_DO_NOT_USE)); - - if (AfxGetAppSettings().bBlockRDP) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_RDPDShowRedirectionFilter, MERIT64_DO_NOT_USE)); - } - - // DCDSPFilter (early versions crash mpc) - { - CRegKey key; - - TCHAR buff[256]; - ULONG len = sizeof(buff); - ZeroMemory(buff, sizeof(buff)); - - CString clsid = _T("{B38C58A0-1809-11D6-A458-EDAE78F1DF12}"); - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + clsid + _T("\\InprocServer32"), KEY_READ) - && ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len) - && FileVersionInfo::GetFileVersionNum(buff) < 0x0001000000030000ui64) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(clsid), MERIT64_DO_NOT_USE)); - } - } -} - -void CFGManagerCustom::InsertSubtitleFilters(bool IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - CFGFilter* pFGF; - - // Null text renderer - pFGF = DEBUG_NEW CFGFilterInternal(L"NullTextRenderer", IsPreview ? MERIT64_ABOVE_DSHOW : MERIT64_DO_USE); - pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_ScriptCommand, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_Subtitle, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DVD_SUBPICTURE); - pFGF->AddType(MEDIATYPE_NULL, MEDIASUBTYPE_CVD_SUBPICTURE); - pFGF->AddType(MEDIATYPE_NULL, MEDIASUBTYPE_SVCD_SUBPICTURE); - m_transform.AddTail(pFGF); - - if (IsPreview) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - } else { - // Insert preferred subtitle renderer and block others - switch (s.GetSubtitleRenderer()) { - case CAppSettings::SubtitleRenderer::INTERNAL: - if (s.fBlockVSFilter) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); - } - if (s.fBlockVSFilter || IsCLSIDRegistered(CLSID_VSFilter)) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); - } - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - break; - case CAppSettings::SubtitleRenderer::VS_FILTER: - pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_ABOVE_DSHOW); - if (pFGF) { - pFGF->AddType(MEDIASUBTYPE_NULL, MEDIASUBTYPE_NULL); - m_override.AddTail(pFGF); - } - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - break; - case CAppSettings::SubtitleRenderer::XY_SUB_FILTER: - pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_ABOVE_DSHOW); - if (pFGF) { - pFGF->AddType(MEDIASUBTYPE_NULL, MEDIASUBTYPE_NULL); - m_override.AddTail(pFGF); - } - pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_ABOVE_DSHOW); - if (pFGF) { - pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); - pFGF->AddType(MEDIATYPE_Subtitle, MEDIASUBTYPE_NULL); - m_override.AddTail(pFGF); - } - if (s.fBlockVSFilter) { - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); - } - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - break; - case CAppSettings::SubtitleRenderer::NONE: - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); - break; - } - } -} - -void CFGManagerCustom::InsertBroadcomDecoder() -{ - CFGFilter* pFGF = DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{2DE1D17E-46B1-42A8-9AEC-E20E80D9B1A9}")), MERIT64_ABOVE_DSHOW); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_X264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_x264); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VSSH); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vssh); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DAVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_davc); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_PAVC); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_pavc); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_avc1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264_bis); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CCV1); - - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WVC1); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wvc1); - - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_VIDEO); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO); - m_transform.AddHead(pFGF); -} - -// -// CFGManagerCustom -// - -CFGManagerCustom::CFGManagerCustom(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) - : CFGManager(pName, pUnk, hWnd, IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - - bool bOverrideBroadcom = false; - CFGFilter* pFGF; - m_source; - - const bool* src = s.SrcFilters; - const bool* tra = s.TraFilters; - - // Reset LAVFilters internal instances - CFGFilterLAV::ResetInternalInstances(); - - // Add internal filters - InsertLAVSplitterSource(IsPreview); - InsertLAVSplitter(IsPreview); - InsertOtherInternalSourcefilters(IsPreview); -#if HAS_VIDEO_DECODERS - InsertLAVVideo(IsPreview); -#endif -#if HAS_AUDIO_DECODERS - if (!IsPreview) { - InsertLAVAudio(); - } -#endif - InsertSubtitleFilters(IsPreview); - - // Blocked filters - InsertBlockedFilters(); - if (m_bIsPreview) { - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_RDPDShowRedirectionFilter, MERIT64_DO_NOT_USE)); - } - - // Overrides - WORD merit_low = 1; - POSITION pos = s.m_filters.GetTailPosition(); - while (pos) { - FilterOverride* fo = s.m_filters.GetPrev(pos); - - if (!fo->fDisabled && fo->name == _T("Broadcom Video Decoder")) { - bOverrideBroadcom = true; - } - if (fo->fDisabled || fo->type == FilterOverride::EXTERNAL && !PathUtils::Exists(MakeFullPath(fo->path))) { - continue; - } - - ULONGLONG merit = - fo->iLoadType == FilterOverride::BLOCK ? MERIT64_DO_NOT_USE : - fo->iLoadType == FilterOverride::PREFERRED ? (IsPreview ? MERIT64_DO_USE : MERIT64_ABOVE_DSHOW) : - MERIT64(fo->dwMerit); - - merit += merit_low++; - - pFGF = nullptr; - if (fo->type == FilterOverride::REGISTERED) { - pFGF = DEBUG_NEW CFGFilterRegistry(fo->dispname, merit); - } else if (fo->type == FilterOverride::EXTERNAL) { - pFGF = DEBUG_NEW CFGFilterFile(fo->clsid, fo->path, CStringW(fo->name), merit); - } - if (pFGF) { - pFGF->SetTypes(fo->guids); - m_override.AddTail(pFGF); - } - } - - /* Use Broadcom decoder (if installed) for VC-1, H.264 and MPEG-2 */ - if (!IsPreview && !bOverrideBroadcom) { - // ToDo: maybe remove support for this old filter? - InsertBroadcomDecoder(); - } -} - -STDMETHODIMP CFGManagerCustom::AddFilter(IBaseFilter* pBF, LPCWSTR pName) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - if (FAILED(hr = __super::AddFilter(pBF, pName))) { - return hr; - } - - CAppSettings& s = AfxGetAppSettings(); - - if (GetCLSID(pBF) == CLSID_DMOWrapperFilter) { - if (CComQIPtr pPB = pBF) { - CComVariant var(true); - pPB->Write(_T("_HIRESOUTPUT"), &var); - } - } - - if (CComQIPtr pASF = pBF) { - pASF->EnableDownSamplingTo441(s.fDownSampleTo441); - pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); - pASF->SetAudioTimeShift(s.fAudioTimeShift ? 10000i64 * s.iAudioTimeShift : 0); - pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); - } - - return hr; -} - -// -// CFGManagerPlayer -// - -CFGManagerPlayer::CFGManagerPlayer(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) - : CFGManagerCustom(pName, pUnk, hWnd, IsPreview) - , m_hWnd(hWnd) -{ - TRACE(_T("CFGManagerPlayer::CFGManagerPlayer on thread: %lu\n"), GetCurrentThreadId()); - CFGFilter* pFGF; - - const CAppSettings& s = AfxGetAppSettings(); - - /* value is chosen so that it is higher than standard renderers, but lower than important intermediate filters like VSFilter */ - UINT64 renderer_merit = MERIT64(0x800001) + 0x100; - - // Switchers - - if (s.fEnableAudioSwitcher && !m_bIsPreview) { - pFGF = DEBUG_NEW CFGFilterInternal(L"Audio Switcher", renderer_merit + 0x100); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } - - // Renderers - if (!m_bIsPreview) { - switch (s.iDSVideoRendererType) { - case VIDRNDT_DS_DEFAULT: - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VideoRendererDefault, MERIT64(0x800001))); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VideoMixingRenderer9, MERIT64(0x200003))); - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_EnhancedVideoRenderer, MERIT64(0x200002))); - break; - case VIDRNDT_DS_OVERLAYMIXER: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_OverlayMixer, StrRes(IDS_PPAGE_OUTPUT_OVERLAYMIXER), renderer_merit)); - break; - case VIDRNDT_DS_VMR9WINDOWED: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VideoMixingRenderer9, StrRes(IDS_PPAGE_OUTPUT_VMR9WINDOWED), renderer_merit)); - break; - case VIDRNDT_DS_VMR9RENDERLESS: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VMR9AllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_VMR9RENDERLESS), renderer_merit)); - break; - case VIDRNDT_DS_EVR: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, StrRes(IDS_PPAGE_OUTPUT_EVR), renderer_merit)); - break; - case VIDRNDT_DS_EVR_CUSTOM: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_EVR_CUSTOM), renderer_merit)); - break; - case VIDRNDT_DS_DXR: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_DXRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_DXR), renderer_merit)); - break; - case VIDRNDT_DS_MADVR: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_madVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_MADVR), renderer_merit)); - break; - case VIDRNDT_DS_SYNC: - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_SyncAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_SYNC), renderer_merit)); - break; - case VIDRNDT_DS_MPCVR: - if (!m_bIsCapture) { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_MPCVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_MPCVR), renderer_merit)); - } else { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, StrRes(IDS_PPAGE_OUTPUT_EVR), renderer_merit)); - } - break; - case VIDRNDT_DS_NULL_COMP: - pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_COMP), MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - break; - case VIDRNDT_DS_NULL_UNCOMP: - pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_UNCOMP), MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - break; - } - } else { - bool preview_evrcp = (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) || (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) || (s.iDSVideoRendererType == VIDRNDT_DS_MADVR) || (s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); - if (preview_evrcp && CAppSettings::IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM)) { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EVRAllocatorPresenter, L"EVRCP - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); - m_bPreviewSupportsRotation = true; - } else if (CAppSettings::IsVideoRendererAvailable(VIDRNDT_DS_EVR)) { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, L"EVR - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); - } else { - m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VideoMixingRenderer9, L"VMR9 - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); - } - } - - if (!m_bIsPreview) { - CString SelAudioRenderer = s.SelectedAudioRenderer(); - if (SelAudioRenderer == AUDRNDT_NULL_COMP) { - pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_COMP, MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - // DVD stuff - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); - m_transform.AddTail(pFGF); - } else if (SelAudioRenderer == AUDRNDT_NULL_UNCOMP) { - pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_UNCOMP, MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } else if (SelAudioRenderer == AUDRNDT_INTERNAL) { - struct SaneAudioRendererFilter : CFGFilter { - SaneAudioRendererFilter(CStringW name, UINT64 merit) : - CFGFilter(SaneAudioRenderer::Factory::GetFilterGuid(), name, merit) {} - - HRESULT Create(IBaseFilter** ppBF, CInterfaceList&) override { - return SaneAudioRenderer::Factory::CreateFilter(AfxGetAppSettings().sanear, ppBF); - } - }; - pFGF = DEBUG_NEW SaneAudioRendererFilter(AUDRNDT_SANEAR, renderer_merit + 0x50); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } else if (SelAudioRenderer == AUDRNDT_MPC) { - pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_MPC, renderer_merit); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IEEE_FLOAT); - m_transform.AddTail(pFGF); - } else if (!SelAudioRenderer.IsEmpty()) { - pFGF = DEBUG_NEW CFGFilterRegistry(SelAudioRenderer, renderer_merit); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } - } else { - pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_COMP, MERIT64_ABOVE_DSHOW + 2); - pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); - // DVD stuff - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); - pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); - pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); - m_transform.AddTail(pFGF); - } -} - -STDMETHODIMP CFGManagerPlayer::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) -{ - CAutoLock cAutoLock(this); - - CLSID pin_clsid = GetCLSID(pPinOut); - if (pin_clsid == CLSID_MPEG2Demultiplexer) { - CComQIPtr pMS = pPinOut; - REFERENCE_TIME rtDur = 0; - if (!pMS || FAILED(pMS->GetDuration(&rtDur)) || rtDur <= 0) { - return E_FAIL; - } - } else if (pin_clsid == CLSID_StillVideo || pin_clsid == CLSID_MPCImageSource) { - CComQIPtr pMS = pPinOut; - if (pMS) { - const CAppSettings& s = AfxGetAppSettings(); - if (s.iStillVideoDuration > 0) { - REFERENCE_TIME rtCur = 0; - REFERENCE_TIME rtDur = 0; - REFERENCE_TIME rtDurOverride = s.iStillVideoDuration * 10000000LL; - pMS->GetDuration(&rtDur); - if (rtDur == 0 || rtDur >= 10 * 3600 * 10000000LL) { - rtDur = rtDurOverride; - } else if (rtDur < rtDurOverride) { - rtDur = (rtDurOverride / rtDur) * rtDur; - } - // always call SetPositions() to prevent infinite repeat by the source filter - pMS->SetPositions(&rtCur, AM_SEEKING_AbsolutePositioning, &rtDur, AM_SEEKING_AbsolutePositioning); - } - } - } - - return __super::ConnectDirect(pPinOut, pPinIn, pmt); -} - -// -// CFGManagerDVD -// - -CFGManagerDVD::CFGManagerDVD(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) - : CFGManagerPlayer(pName, pUnk, hWnd, IsPreview) -{ - const CAppSettings& s = AfxGetAppSettings(); - - // elecard's decoder isn't suited for dvd playback (atm) - m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{F50B3F13-19C4-11CF-AA9A-02608C9BABA2}")), MERIT64_DO_NOT_USE)); -} - -class CResetDVD : public CDVDSession -{ -public: - CResetDVD(LPCTSTR path) { - if (Open(path)) { - if (BeginSession()) { - Authenticate(); /*GetDiscKey();*/ - EndSession(); - } - Close(); - } - } -}; - -STDMETHODIMP CFGManagerDVD::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) -{ - CAutoLock cAutoLock(this); - - HRESULT hr; - - CComPtr pBF; - if (FAILED(hr = AddSourceFilter(lpcwstrFile, lpcwstrFile, &pBF))) { - return hr; - } - - return ConnectFilter(pBF, nullptr); -} - -STDMETHODIMP CFGManagerDVD::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) -{ - CAutoLock cAutoLock(this); - - CheckPointer(lpcwstrFileName, E_POINTER); - CheckPointer(ppFilter, E_POINTER); - - CStringW fn = CStringW(lpcwstrFileName).TrimLeft(); - - GUID clsid = CLSID_DVDNavigator; - - CComPtr pBF; - if (FAILED(pBF.CoCreateInstance(clsid)) - || FAILED(AddFilter(pBF, L"DVD Navigator"))) { - return VFW_E_CANNOT_LOAD_SOURCE_FILTER; - } - - CComQIPtr pDVDC; - CComQIPtr pDVDI; - - if (!((pDVDC = pBF) && (pDVDI = pBF))) { - return E_NOINTERFACE; - } - - WCHAR buff[MAX_PATH]; - ULONG len; - if ((!fn.IsEmpty() - && FAILED(pDVDC->SetDVDDirectory(fn)) - && FAILED(pDVDC->SetDVDDirectory(fn + L"VIDEO_TS")) - && FAILED(pDVDC->SetDVDDirectory(fn + L"\\VIDEO_TS"))) - || FAILED(pDVDI->GetDVDDirectory(buff, _countof(buff), &len)) || len == 0) { - return E_INVALIDARG; - } - - pDVDC->SetOption(DVD_ResetOnStop, FALSE); - pDVDC->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); - - if (clsid == CLSID_DVDNavigator) { - CResetDVD(CString(buff)); - } - - *ppFilter = pBF.Detach(); - - return S_OK; -} - -// -// CFGManagerCapture -// - -CFGManagerCapture::CFGManagerCapture(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd) - : CFGManagerPlayer(pName, pUnk, hWnd) -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (s.bCaptureDeinterlace) { - // set merit higher than our video renderers - CFGFilter* pFGF = DEBUG_NEW CFGFilterInternal(L"Deinterlacer", MERIT64(0x800001) + 0x200); - pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); - m_transform.AddTail(pFGF); - } - - m_bIsCapture = True; -} - -// -// CFGManagerMuxer -// - -CFGManagerMuxer::CFGManagerMuxer(LPCTSTR pName, LPUNKNOWN pUnk) - : CFGManagerCustom(pName, pUnk) -{ - m_source.AddTail(DEBUG_NEW CFGFilterInternal()); -} - -// -// CFGAggregator -// - -CFGAggregator::CFGAggregator(const CLSID& clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT& hr) - : CUnknown(pName, pUnk) -{ - hr = m_pUnkInner.CoCreateInstance(clsid, GetOwner()); -} - -CFGAggregator::~CFGAggregator() -{ - m_pUnkInner.Release(); -} - -STDMETHODIMP CFGAggregator::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - m_pUnkInner && (riid != IID_IUnknown && SUCCEEDED(m_pUnkInner->QueryInterface(riid, ppv))) ? S_OK : - __super::NonDelegatingQueryInterface(riid, ppv); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "FGManager.h" +#include "../DeCSS/VobFile.h" +#include "../filters/Filters.h" +#include "AllocatorCommon.h" +#include "DeinterlacerFilter.h" +#include "FakeFilterMapper2.h" +#include "FileVersionInfo.h" +#include "IPinHook.h" +#include "NullRenderers.h" +#include "PathUtils.h" +#include "SyncAllocatorPresenter.h" +#include "mplayerc.h" +#include "sanear/src/Factory.h" +#include "../src/thirdparty/MpcAudioRenderer/MpcAudioRenderer.h" +#include "DSUtil.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "../src/thirdparty/LAVFilters/src/include/IURLSourceFilterLAV.h" + +#include +#include "moreuuids.h" +#include + +#if !TRACE_GRAPH_BUILD +#undef TRACE +#define TRACE(...) +#endif + +// +// CFGManager +// + +class CNullAudioRenderer; + +CFGManager::CFGManager(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) + : CUnknown(pName, pUnk) + , m_dwRegister(0) + , m_hWnd(hWnd) + , m_bIsPreview(IsPreview) + , m_bPreviewSupportsRotation(false) + , m_ignoreVideo(false) + , m_bIsCapture(false) + , m_source() + , m_transform() + , m_override() + , m_deadends() + , m_aborted(false) + , m_useragent() + , m_referrer() +{ + m_pUnkInner.CoCreateInstance(CLSID_FilterGraph, GetOwner()); + m_pFM.CoCreateInstance(CLSID_FilterMapper2); +} + +CFGManager::~CFGManager() +{ + CAutoLock cAutoLock(this); + while (!m_source.IsEmpty()) { + delete m_source.RemoveHead(); + } + while (!m_transform.IsEmpty()) { + delete m_transform.RemoveHead(); + } + while (!m_override.IsEmpty()) { + delete m_override.RemoveHead(); + } + m_pUnks.RemoveAll(); + m_pUnkInner.Release(); +} + +STDMETHODIMP CFGManager::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IFilterGraph) + QI(IGraphBuilder) + QI(IFilterGraph2) + QI(IGraphBuilder2) + QI(IGraphBuilderDeadEnd) + (m_pUnkInner && riid != IID_IUnknown && SUCCEEDED(m_pUnkInner->QueryInterface(riid, ppv))) ? S_OK : + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// + +void CFGManager::CStreamPath::Append(IBaseFilter* pBF, IPin* pPin) +{ + path_t p; + p.clsid = GetCLSID(pBF); + p.filter = GetFilterName(pBF); + p.pin = GetPinName(pPin); + AddTail(p); +} + +bool CFGManager::CStreamPath::Compare(const CStreamPath& path) +{ + POSITION pos1 = GetHeadPosition(); + POSITION pos2 = path.GetHeadPosition(); + + while (pos1 && pos2) { + const path_t& p1 = GetNext(pos1); + const path_t& p2 = path.GetNext(pos2); + + if (p1.filter != p2.filter) { + return true; + } else if (p1.pin != p2.pin) { + return false; + } + } + + return true; +} + +// + +bool CFGManager::CheckBytes(HANDLE hFile, CString chkbytes) +{ + CAtlList sl; + Explode(chkbytes, sl, ','); + + if (sl.GetCount() < 4) { + return false; + } + + ASSERT(!(sl.GetCount() & 3)); + + LARGE_INTEGER size = {0, 0}; + GetFileSizeEx(hFile, &size); + + while (sl.GetCount() >= 4) { + CString offsetstr = sl.RemoveHead(); + CString cbstr = sl.RemoveHead(); + CString maskstr = sl.RemoveHead(); + CString valstr = sl.RemoveHead(); + + long cb = _ttol(cbstr); + + if (offsetstr.IsEmpty() || cbstr.IsEmpty() + || valstr.IsEmpty() || (valstr.GetLength() & 1) + || cb * 2 != valstr.GetLength()) { + return false; + } + + LARGE_INTEGER offset; + offset.QuadPart = _ttoi64(offsetstr); + if (offset.QuadPart < 0) { + offset.QuadPart = size.QuadPart - offset.QuadPart; + } + SetFilePointerEx(hFile, offset, &offset, FILE_BEGIN); + + // LAME + while (maskstr.GetLength() < valstr.GetLength()) { + maskstr += _T('F'); + } + + CAtlArray mask, val; + CStringToBin(maskstr, mask); + CStringToBin(valstr, val); + + for (size_t i = 0; i < val.GetCount(); i++) { + BYTE b; + DWORD r; + if (!ReadFile(hFile, &b, 1, &r, nullptr) || (b & mask[i]) != val[i]) { + return false; + } + } + } + + return sl.IsEmpty(); +} + +CFGFilter* LookupFilterRegistry(const GUID& guid, CAtlList& list, UINT64 fallback_merit = MERIT64_DO_USE) +{ + POSITION pos = list.GetHeadPosition(); + CFGFilter* pFilter = nullptr; + while (pos) { + CFGFilter* pFGF = list.GetNext(pos); + if (pFGF->GetCLSID() == guid) { + pFilter = pFGF; + break; + } + } + if (pFilter) { + return DEBUG_NEW CFGFilterRegistry(guid, pFilter->GetMerit()); + } else { + return DEBUG_NEW CFGFilterRegistry(guid, fallback_merit); + } +} + +HRESULT CFGManager::EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl) +{ + // TODO: use overrides + + CheckPointer(lpcwstrFileName, E_POINTER); + + fl.RemoveAll(); + + CStringW fn = CStringW(lpcwstrFileName).TrimLeft(); + CStringW cfn = fn; + if (cfn.Left(4) == "\\\\?\\") { + cfn = cfn.Mid(4); + } + CStringW protocol = cfn.Left(cfn.Find(':') + 1).TrimRight(':').MakeLower(); + CStringW ext = CPathW(fn).GetExtension().MakeLower(); + + HANDLE hFile = INVALID_HANDLE_VALUE; + + if (protocol.GetLength() <= 1 || protocol == L"file") { + hFile = CreateFile(CString(fn), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)nullptr); + + // In case of audio CDs with extra content, the audio tracks + // cannot be accessed directly so we have to try opening it + if (hFile == INVALID_HANDLE_VALUE && ext != L".cda") { + return VFW_E_NOT_FOUND; + } + } + + if (hFile == INVALID_HANDLE_VALUE) { + // internal / protocol + + POSITION pos = m_source.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_source.GetNext(pos); + if (pFGF->m_protocols.Find(CString(protocol))) { + fl.Insert(pFGF, 0, false, false); + } + } + } else { + // internal / check bytes + + POSITION pos = m_source.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_source.GetNext(pos); + + POSITION pos2 = pFGF->m_chkbytes.GetHeadPosition(); + while (pos2) { + if (CheckBytes(hFile, pFGF->m_chkbytes.GetNext(pos2))) { + fl.Insert(pFGF, 1, false, false); + break; + } + } + } + } + + if (!ext.IsEmpty()) { + // internal / file extension + + POSITION pos = m_source.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_source.GetNext(pos); + if (pFGF->m_extensions.Find(CString(ext))) { + fl.Insert(pFGF, 2, false, false); + } + } + } + + { + // internal / the rest + + POSITION pos = m_source.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_source.GetNext(pos); + if (pFGF->m_protocols.IsEmpty() && pFGF->m_chkbytes.IsEmpty() && pFGF->m_extensions.IsEmpty()) { + fl.Insert(pFGF, 3, false, false); + } + } + } + + TCHAR buff[256]; + ULONG len; + + if (hFile == INVALID_HANDLE_VALUE) { + // protocol + + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, CString(protocol), KEY_READ)) { + CRegKey exts; + if (ERROR_SUCCESS == exts.Open(key, _T("Extensions"), KEY_READ)) { + len = _countof(buff); + if (ERROR_SUCCESS == exts.QueryStringValue(CString(ext), buff, &len)) { + fl.Insert(LookupFilterRegistry(GUIDFromCString(buff), m_override), 4); + } + } + + len = _countof(buff); + if (ERROR_SUCCESS == key.QueryStringValue(_T("Source Filter"), buff, &len)) { + fl.Insert(LookupFilterRegistry(GUIDFromCString(buff), m_override), 5); + } + } + + fl.Insert(DEBUG_NEW CFGFilterRegistry(CLSID_URLReader), 6); + } else { + // check bytes + + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Media Type"), KEY_READ)) { + FILETIME ft; + len = _countof(buff); + for (DWORD i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len, &ft); i++, len = _countof(buff)) { + GUID majortype; + if (FAILED(GUIDFromCString(buff, majortype))) { + continue; + } + + CRegKey majorkey; + if (ERROR_SUCCESS == majorkey.Open(key, buff, KEY_READ)) { + len = _countof(buff); + for (DWORD j = 0; ERROR_SUCCESS == majorkey.EnumKey(j, buff, &len, &ft); j++, len = _countof(buff)) { + GUID subtype; + if (FAILED(GUIDFromCString(buff, subtype))) { + continue; + } + + CRegKey subkey; + if (ERROR_SUCCESS == subkey.Open(majorkey, buff, KEY_READ)) { + len = _countof(buff); + if (ERROR_SUCCESS != subkey.QueryStringValue(_T("Source Filter"), buff, &len)) { + continue; + } + + GUID clsid = GUIDFromCString(buff); + TCHAR buff2[256]; + ULONG len2; + + len = _countof(buff); + len2 = sizeof(buff2); + for (DWORD k = 0, type; + clsid != GUID_NULL && ERROR_SUCCESS == RegEnumValue(subkey, k, buff2, &len2, 0, &type, (BYTE*)buff, &len); + k++, len = _countof(buff), len2 = sizeof(buff2)) { + if (CheckBytes(hFile, CString(buff))) { + CFGFilter* pFGF = LookupFilterRegistry(clsid, m_override); + pFGF->AddType(majortype, subtype); + if (pFGF->GetMerit() >= MERIT64_ABOVE_DSHOW) { + fl.Insert(pFGF, 7); + } else { + fl.Insert(pFGF, 9); + } + break; + } + } + } + } + } + } + } + } + + if (!ext.IsEmpty()) { + // file extension + + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Media Type\\Extensions\\") + CString(ext), KEY_READ)) { + len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + LONG ret = key.QueryStringValue(_T("Source Filter"), buff, &len); // QueryStringValue can return ERROR_INVALID_DATA on bogus strings (radlight mpc v1003, fixed in v1004) + if (ERROR_SUCCESS == ret || ERROR_INVALID_DATA == ret && GUIDFromCString(buff) != GUID_NULL) { + GUID clsid = GUIDFromCString(buff); + GUID majortype = GUID_NULL; + GUID subtype = GUID_NULL; + + len = _countof(buff); + if (ERROR_SUCCESS == key.QueryStringValue(_T("Media Type"), buff, &len)) { + majortype = GUIDFromCString(buff); + } + + len = _countof(buff); + if (ERROR_SUCCESS == key.QueryStringValue(_T("Subtype"), buff, &len)) { + subtype = GUIDFromCString(buff); + } + + CFGFilter* pFGF = LookupFilterRegistry(clsid, m_override); + pFGF->AddType(majortype, subtype); + fl.Insert(pFGF, 7); + } + } + + // preferred external filters + if (ext == L".avs" || ext == L".vpy") { + POSITION pos = m_override.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_override.GetNext(pos); + if (pFGF->GetMerit() >= MERIT64_ABOVE_DSHOW) { + if (pFGF->GetCLSID() == GUIDFromCString(L"{7D3BBD5A-880D-4A30-A2D1-7B8C2741AFEF}")) { // MPC Script Source + if (ext == L".avs" || ext == L".vpy") { + fl.Insert(pFGF, 0, false, false); + } + } + } + } + } + } + + if (hFile != INVALID_HANDLE_VALUE) { + CloseHandle(hFile); + + CFGFilter* pFGF = LookupFilterRegistry(CLSID_AsyncReader, m_override); + pFGF->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_NULL); + fl.Insert(pFGF, 9); + } + + return S_OK; +} + +HRESULT CFGManager::AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF) +{ + CLSID clsid = pFGF->GetCLSID(); + TRACE(_T("FGM: AddSourceFilter trying '%s'\n"), CStringFromGUID(clsid).GetString()); + + CheckPointer(lpcwstrFileName, E_POINTER); + CheckPointer(ppBF, E_POINTER); + + ASSERT(*ppBF == nullptr); + + HRESULT hr; + + CComPtr pBF; + CInterfaceList pUnks; + if (FAILED(hr = pFGF->Create(&pBF, pUnks))) { + return hr; + } + + CComQIPtr pFSF = pBF; + if (!pFSF) { + return E_NOINTERFACE; + } + + if (clsid == __uuidof(CRARFileSource) && m_entryRFS.GetLength() > 0) { + CComPtr rfs = static_cast(pBF.p); + std::wstring preselectedRarFileEntry(m_entryRFS.GetBuffer()); + rfs->SetPreselectedRarFileEntry(preselectedRarFileEntry); + } + + if (FAILED(hr = AddFilter(pBF, lpcwstrFilterName))) { + return hr; + } + + const AM_MEDIA_TYPE* pmt = nullptr; + if (clsid == GUID_LAVSplitterSource) { + CComQIPtr pSFL = pBF; + if (pSFL && (!m_useragent.IsEmpty() || !m_referrer.IsEmpty())) { + // ToDo: set strings + hr = pSFL->LoadURL(lpcwstrFileName, m_useragent, m_referrer); + if (FAILED(hr)) { + RemoveFilter(pBF); + return hr; + } + } else { + hr = pFSF->Load(lpcwstrFileName, pmt); + if (FAILED(hr)) { + RemoveFilter(pBF); + return hr; + } + } + } else { + CMediaType mt; + const CAtlList& types = pFGF->GetTypes(); + if (types.GetCount() == 2 && (types.GetHead() != GUID_NULL || types.GetTail() != GUID_NULL)) { + mt.majortype = types.GetHead(); + mt.subtype = types.GetTail(); + pmt = &mt; + } + + hr = pFSF->Load(lpcwstrFileName, pmt); + if (FAILED(hr) || m_aborted) { // sometimes looping with AviSynth + RemoveFilter(pBF); + return m_aborted ? E_ABORT : hr; + } + + BeginEnumMediaTypes(GetFirstPin(pBF, PINDIR_OUTPUT), pEMT, pmt2) { + static const GUID guid1 = + { 0x640999A0, 0xA946, 0x11D0, { 0xA5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // ASX file Parser + static const GUID guid2 = + { 0x640999A1, 0xA946, 0x11D0, { 0xA5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // ASX v.2 file Parser + static const GUID guid3 = + { 0xD51BD5AE, 0x7548, 0x11CF, { 0xA5, 0x20, 0x00, 0x80, 0xC7, 0x7E, 0xF5, 0x8A } }; // XML Playlist + + if (pmt2->subtype == guid1 || pmt2->subtype == guid2 || pmt2->subtype == guid3) { + RemoveFilter(pBF); + pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_NetShowSource); + hr = AddSourceFilter(pFGF, lpcwstrFileName, lpcwstrFilterName, ppBF); + delete pFGF; + return hr; + } + } + EndEnumMediaTypes(pmt2); + } + + *ppBF = pBF.Detach(); + + m_pUnks.AddTailList(&pUnks); + + return S_OK; +} + +// IFilterGraph + +STDMETHODIMP CFGManager::AddFilter(IBaseFilter* pFilter, LPCWSTR pName) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (FAILED(hr = CComQIPtr(m_pUnkInner)->AddFilter(pFilter, pName))) { + return hr; + } + + // TODO + hr = pFilter->JoinFilterGraph(nullptr, nullptr); + hr = pFilter->JoinFilterGraph(this, pName); + + return hr; +} + +STDMETHODIMP CFGManager::RemoveFilter(IBaseFilter* pFilter) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->RemoveFilter(pFilter); +} + +STDMETHODIMP CFGManager::EnumFilters(IEnumFilters** ppEnum) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + // Not locking here fixes a deadlock involving ReClock + //CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->EnumFilters(ppEnum); +} + +STDMETHODIMP CFGManager::FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->FindFilterByName(pName, ppFilter); +} + +STDMETHODIMP CFGManager::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + CComPtr pBF = GetFilterFromPin(pPinIn); + CLSID clsid = GetCLSID(pBF); + + // TODO: GetUpStreamFilter goes up on the first input pin only + for (CComPtr pBFUS = GetFilterFromPin(pPinOut); pBFUS; pBFUS = GetUpStreamFilter(pBFUS)) { + if (pBFUS == pBF) { + return VFW_E_CIRCULAR_GRAPH; + } + if (clsid != CLSID_Proxy && GetCLSID(pBFUS) == clsid) { + return VFW_E_CANNOT_CONNECT; + } + } + + return CComQIPtr(m_pUnkInner)->ConnectDirect(pPinOut, pPinIn, pmt); +} + +STDMETHODIMP CFGManager::Reconnect(IPin* ppin) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->Reconnect(ppin); +} + +STDMETHODIMP CFGManager::Disconnect(IPin* ppin) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->Disconnect(ppin); +} + +STDMETHODIMP CFGManager::SetDefaultSyncSource() +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->SetDefaultSyncSource(); +} + +// IGraphBuilder + +STDMETHODIMP CFGManager::Connect(IPin* pPinOut, IPin* pPinIn) +{ + return Connect(pPinOut, pPinIn, true); +} + +HRESULT CFGManager::Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPinOut, E_POINTER); + + if (m_aborted) { + return E_ABORT; + } + + HRESULT hr; + + if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT) + || pPinIn && S_OK != IsPinDirection(pPinIn, PINDIR_INPUT)) { + return VFW_E_INVALID_DIRECTION; + } + + if (S_OK == IsPinConnected(pPinOut) + || pPinIn && S_OK == IsPinConnected(pPinIn)) { + return VFW_E_ALREADY_CONNECTED; + } + + bool fDeadEnd = true; + + if (pPinIn) { + // 1. Try a direct connection between the filters, with no intermediate filters + + if (SUCCEEDED(hr = ConnectDirect(pPinOut, pPinIn, nullptr))) { + return hr; + } + } else { + // 1. Use IStreamBuilder + + if (CComQIPtr pSB = pPinOut) { + if (SUCCEEDED(hr = pSB->Render(pPinOut, this))) { + return hr; + } + + pSB->Backout(pPinOut, this); + } + } + + // 2. Try cached filters + + CComPtr pFilterPinIn = nullptr; + if (pPinIn) { + pFilterPinIn = GetFilterFromPin(pPinIn); + } + + if (CComQIPtr pGC = (IGraphBuilder2*)this) { + BeginEnumCachedFilters(pGC, pEF, pBF) { + if (pFilterPinIn && pFilterPinIn == pBF) { + continue; + } + + hr = pGC->RemoveFilterFromCache(pBF); + + // does RemoveFilterFromCache call AddFilter like AddFilterToCache calls RemoveFilter ? + + if (SUCCEEDED(hr = ConnectFilterDirect(pPinOut, pBF, nullptr))) { + if (!IsStreamEnd(pBF)) { + fDeadEnd = false; + } + + if (SUCCEEDED(hr = ConnectFilter(pBF, pPinIn))) { + return hr; + } + } + + hr = pGC->AddFilterToCache(pBF); + } + EndEnumCachedFilters; + } + + // 3. Try filters in the graph + + CComPtr pFilterPinOut = GetFilterFromPin(pPinOut); + CLSID clsid_pinout = GetCLSID(pFilterPinOut); + + { + CInterfaceList pBFs; + + BeginEnumFilters(this, pEF, pBF) { + if (pFilterPinIn && pFilterPinIn == pBF || pFilterPinOut == pBF) { + continue; + } + + // HACK: ffdshow - audio capture filter + if (clsid_pinout == GUIDFromCString(_T("{04FE9017-F873-410E-871E-AB91661A4EF7}")) + && GetCLSID(pBF) == GUIDFromCString(_T("{E30629D2-27E5-11CE-875D-00608CB78066}"))) { + continue; + } + + pBFs.AddTail(pBF); + } + EndEnumFilters; + + POSITION pos = pBFs.GetHeadPosition(); + while (pos) { + IBaseFilter* pBF = pBFs.GetNext(pos); + + if (SUCCEEDED(hr = ConnectFilterDirect(pPinOut, pBF, nullptr))) { + if (!IsStreamEnd(pBF)) { + fDeadEnd = false; + } + + if (SUCCEEDED(hr = ConnectFilter(pBF, pPinIn))) { + return hr; + } + } + + EXECUTE_ASSERT(SUCCEEDED(Disconnect(pPinOut))); + } + } + + // 4. Look up filters in the registry + + { + // workaround for Cyberlink video decoder, which can have an unwanted output pin + if (clsid_pinout == GUIDFromCString(_T("{F8FC6C1F-DE81-41A8-90FF-0316FDD439FD}"))) { + CPinInfo infoPinOut; + if (SUCCEEDED(pPinOut->QueryPinInfo(&infoPinOut))) { + if (CString(infoPinOut.achName) == L"~Encode Out") { + // ignore this pin + return S_OK; + } + } + } + + CFGFilterList fl; + + CAtlArray types; + ExtractMediaTypes(pPinOut, types); + + POSITION pos = m_transform.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_transform.GetNext(pos); + if (pFGF->GetMerit() < MERIT64_DO_USE || pFGF->CheckTypes(types, false)) { + fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true), false); + } + } + + pos = m_override.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = m_override.GetNext(pos); + if (pFGF->GetMerit() < MERIT64_DO_USE || pFGF->CheckTypes(types, false)) { + fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true), false); + } + } + + CComPtr pEM; + if (!types.IsEmpty() + && SUCCEEDED(m_pFM->EnumMatchingFilters( + &pEM, 0, FALSE, MERIT_DO_NOT_USE + 1, + TRUE, (DWORD)types.GetCount() / 2, types.GetData(), nullptr, nullptr, FALSE, + !!pPinIn, 0, nullptr, nullptr, nullptr))) { + for (CComPtr pMoniker; S_OK == pEM->Next(1, &pMoniker, nullptr); pMoniker = nullptr) { + CFGFilterRegistry* pFGF = DEBUG_NEW CFGFilterRegistry(pMoniker); + fl.Insert(pFGF, 0, pFGF->CheckTypes(types, true)); + } + } + + // let's check whether the madVR allocator presenter is in our list + // it should be if madVR is selected as the video renderer + CFGFilter* pMadVRAllocatorPresenter = nullptr; + pos = fl.GetHeadPosition(); + while (pos) { + CFGFilter* pFGF = fl.GetNext(pos); + if (pFGF->GetCLSID() == CLSID_madVRAllocatorPresenter) { + // found it! + pMadVRAllocatorPresenter = pFGF; + break; + } + } + + pos = fl.GetHeadPosition(); + while (pos) { + if (m_aborted) { + return E_ABORT; + } + + CFGFilter* pFGF = fl.GetNext(pos); + + // avoid pointless connection attempts + CLSID candidate = pFGF->GetCLSID(); + if (clsid_pinout == candidate) { + continue; + } else if (candidate == CLSID_VSFilter) { + if (clsid_pinout == GUID_LAVAudio || clsid_pinout == __uuidof(CAudioSwitcherFilter)) { + continue; + } + } else if (candidate == CLSID_RDPDShowRedirectionFilter) { + if (clsid_pinout == __uuidof(CAudioSwitcherFilter)) { + continue; + } + } else if (candidate == GUID_LAVAudio) { + if (clsid_pinout == __uuidof(CAudioSwitcherFilter)) { + continue; + } + } + +#if 0 + // Checks if madVR is already in the graph to avoid two instances at the same time + CComPtr pBFmadVR; + FindFilterByName(_T("madVR"), &pBFmadVR); + if (pBFmadVR && (pFGF->GetName() == _T("madVR"))) { + continue; + } +#endif + + if (pMadVRAllocatorPresenter && (pFGF->GetCLSID() == CLSID_madVR)) { + // the pure madVR filter was selected (without the allocator presenter) + // subtitles, OSD etc don't work correctly without the allocator presenter + // so we prefer the allocator presenter over the pure filter + pFGF = pMadVRAllocatorPresenter; + } + + CString filtername = pFGF->GetName().GetString(); + if (filtername.IsEmpty()) { + filtername = CLSIDToString(candidate); + } + TRACE(_T("FGM: Connecting '%s'\n"), filtername); + + CComPtr pBF; + CInterfaceList pUnks; + if (FAILED(pFGF->Create(&pBF, pUnks))) { + TRACE(_T("FGM: Filter creation failed\n")); + if (!m_bIsCapture) { + // Check if selected video renderer fails to load + CLSID filter = pFGF->GetCLSID(); + if (filter == CLSID_MPCVRAllocatorPresenter || filter == CLSID_madVRAllocatorPresenter || filter == CLSID_DXRAllocatorPresenter) { + if (IDYES == AfxMessageBox(_T("The selected video renderer has failed to load.\n\nThe player will now fallback to using a basic video renderer, which has reduced performance and quality. Subtitles may also fail to load.\n\nDo you want to change settings to use the default video renderer (EVR-CP/VMR9)? (player restart required)"), MB_ICONEXCLAMATION | MB_YESNO, 0)) { + CAppSettings& s = AfxGetAppSettings(); + s.iDSVideoRendererType = IsCLSIDRegistered(CLSID_EnhancedVideoRenderer) ? VIDRNDT_DS_EVR_CUSTOM : VIDRNDT_DS_VMR9RENDERLESS; + } + } else if (filter == CLSID_EVRAllocatorPresenter || filter == CLSID_VMR9AllocatorPresenter) { + if (IDYES == AfxMessageBox(_T("The selected video renderer has failed to load.\n\nThis problem is often caused by a bug in the graphics driver. Or you may be using a generic driver which has limited capabilities. It is recommended to update the graphics driver to solve this problem. A proper driver is required for optimal video playback performance and quality.\n\nThe player will now fallback to using a basic video renderer, which has reduced performance and quality. Subtitles may also fail to load.\n\nYou can select a different renderer here:\nOptions > playback > Output\n\nDo you want to use the basic video renderer by default?"), MB_ICONEXCLAMATION | MB_YESNO, 0)) { + CAppSettings& s = AfxGetAppSettings(); + s.iDSVideoRendererType = IsCLSIDRegistered(CLSID_EnhancedVideoRenderer) ? VIDRNDT_DS_EVR : VIDRNDT_DS_VMR9WINDOWED; + s.SetSubtitleRenderer(CAppSettings::SubtitleRenderer::VS_FILTER); + // Disable DXVA in internal video decoder + CMPlayerCApp* pApp = AfxGetMyApp(); + pApp->WriteProfileInt(IDS_R_INTERNAL_LAVVIDEO_HWACCEL, _T("HWAccel"), 0); + } + } + } + continue; + } + + if (FAILED(hr = AddFilter(pBF, pFGF->GetName()))) { + TRACE(_T("FGM: Adding the filter failed\n")); + pUnks.RemoveAll(); + pBF.Release(); + continue; + } + + hr = ConnectFilterDirect(pPinOut, pBF, nullptr); + /* + if (FAILED(hr)) + { + if (types.GetCount() >= 2 && types[0] == MEDIATYPE_Stream && types[1] != GUID_NULL) + { + CMediaType mt; + + mt.majortype = types[0]; + mt.subtype = types[1]; + mt.formattype = FORMAT_None; + if (FAILED(hr)) hr = ConnectFilterDirect(pPinOut, pBF, &mt); + + mt.formattype = GUID_NULL; + if (FAILED(hr)) hr = ConnectFilterDirect(pPinOut, pBF, &mt); + } + } + */ + if (SUCCEEDED(hr)) { + TRACE(_T("FGM: Filter connected to %s\n"), CLSIDToString(clsid_pinout)); + if (!IsStreamEnd(pBF)) { + fDeadEnd = false; + } + + if (m_aborted) { + return E_ABORT; + } + + if (bContinueRender) { + hr = ConnectFilter(pBF, pPinIn); + } + + if (SUCCEEDED(hr)) { + m_pUnks.AddTailList(&pUnks); + + // maybe the application should do this... + + POSITION posInterface = pUnks.GetHeadPosition(); + while (posInterface) { + if (CComQIPtr pMPC = pUnks.GetNext(posInterface)) { + pMPC->SetAspectRatioMode(AM_ARMODE_STRETCHED); + } + } + + if (CComQIPtr pARC = pBF) { + pARC->SetAspectRatioMode(VMR_ARMODE_NONE); + } + + if (CComQIPtr pARC = pBF) { + pARC->SetAspectRatioMode(VMR_ARMODE_NONE); + } + + if (CComQIPtr pMC = pBF) { + m_pUnks.AddTail(pMC); + } + + if (CComQIPtr pMB = pBF) { + m_pUnks.AddTail(pMB); + } + + if (CComQIPtr pMFVMB = pBF) { + m_pUnks.AddTail(pMFVMB); + } + + if (CComQIPtr pMFGS = pBF) { + CComPtr pMFVDC; + CComPtr pMFMB; + CComPtr pMFVP; + + if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pMFVDC)))) { + m_pUnks.AddTail(pMFVDC); + } + + if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&pMFMB)))) { + m_pUnks.AddTail(pMFMB); + } + + if (SUCCEEDED(pMFGS->GetService(MR_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&pMFVP)))) { + m_pUnks.AddTail(pMFVP); + } + } + + return hr; + } + } + + TRACE(_T("FGM: Failed to connect to %s\n"), CLSIDToString(clsid_pinout)); + CPinInfo infoPinOut; + if (SUCCEEDED(pPinOut->QueryPinInfo(&infoPinOut))) { + TRACE(_T("FGM: Output pin name: %s\n"), infoPinOut.achName); + } + EXECUTE_ASSERT(SUCCEEDED(RemoveFilter(pBF))); + pUnks.RemoveAll(); + pBF.Release(); + } + } + + if (fDeadEnd) { + CAutoPtr psde(DEBUG_NEW CStreamDeadEnd()); + psde->AddTailList(&m_streampath); + int skip = 0; + BeginEnumMediaTypes(pPinOut, pEM, pmt) { + if (pmt->majortype == MEDIATYPE_Stream && pmt->subtype == MEDIASUBTYPE_NULL) { + skip++; + } + psde->mts.AddTail(CMediaType(*pmt)); + } + EndEnumMediaTypes(pmt); + if (skip < (int)psde->mts.GetCount()) { + m_deadends.Add(psde); + } + } + + return pPinIn ? VFW_E_CANNOT_CONNECT : VFW_E_CANNOT_RENDER; +} + +STDMETHODIMP CFGManager::Render(IPin* pPinOut) +{ + CAutoLock cAutoLock(this); + + return RenderEx(pPinOut, 0, nullptr); +} + +HRESULT CFGManager::RenderRFSFileEntry(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList, CStringW entryRFS){ + this->m_entryRFS = entryRFS; + return RenderFile(lpcwstrFileName, lpcwstrPlayList); +} + +CUnknown* WINAPI CFGManager::GetMpcAudioRendererInstance(LPUNKNOWN lpunk, HRESULT* phr) { + return CreateInstance(lpunk, phr); +} + +STDMETHODIMP CFGManager::RenderFile(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList) +{ + TRACE(_T("CFGManager::RenderFile on thread: %lu\n"), GetCurrentThreadId()); + CAutoLock cAutoLock(this); + + m_streampath.RemoveAll(); + m_deadends.RemoveAll(); + + HRESULT hr; + HRESULT hrRFS = S_OK; + + CFGFilterList fl; + if (FAILED(hr = EnumSourceFilters(lpcwstrFileName, fl))) { + return hr; + } + + CAutoPtrArray deadends; + + hr = VFW_E_CANNOT_RENDER; + + POSITION pos = fl.GetHeadPosition(); + while (pos) { + CComPtr pBF; + CFGFilter* pFG = fl.GetNext(pos); + + if (SUCCEEDED(hr = AddSourceFilter(pFG, lpcwstrFileName, pFG->GetName(), &pBF))) { + m_streampath.RemoveAll(); + m_deadends.RemoveAll(); + + if (m_ignoreVideo) { + CFGFilter* pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_COMP), MERIT64_ABOVE_DSHOW + 3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } + + if (SUCCEEDED(hr = ConnectFilter(pBF, nullptr))) { + // insert null video renderer on next RenderFile call which is used for audio dubs + m_ignoreVideo = True; + TRACE(_T("CFGManager::RenderFile complete\n")); + return hr; + } + + NukeDownstream(pBF); + RemoveFilter(pBF); + + deadends.Append(m_deadends); + + if (hr == E_ABORT) { + break; + } + } else if (pFG->GetCLSID() == __uuidof(CRARFileSource) && HRESULT_FACILITY(hr) == FACILITY_ITF) { + hrRFS = hr; + } + } + + m_deadends.Copy(deadends); + + // If RFS was part of the graph, return its error code instead of the last error code. + // TODO: Improve filter error reporting to graph manager. + return hrRFS != S_OK ? hrRFS : hr; +} + +STDMETHODIMP CFGManager::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + CFGFilterList fl; + + if (FAILED(hr = EnumSourceFilters(lpcwstrFileName, fl))) { + return hr; + } + + POSITION pos = fl.GetHeadPosition(); + while (pos) { + if (SUCCEEDED(hr = AddSourceFilter(fl.GetNext(pos), lpcwstrFileName, lpcwstrFilterName, ppFilter))) { + return hr; + } + } + + return VFW_E_CANNOT_LOAD_SOURCE_FILTER; +} + +STDMETHODIMP CFGManager::SetLogFile(DWORD_PTR hFile) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->SetLogFile(hFile); +} + +STDMETHODIMP CFGManager::Abort() +{ + if (!m_pUnkInner) { + ASSERT(false); + return E_UNEXPECTED; + } + + // When a filter (renderer) in the child thread (the graph thread) calls CreateWindow() + // then that call triggers an implicit call of SendMessage to the main window. + // This is a blocking call, meaning main thread must be able to process that window message. + // So we can not request a lock here when called from main thread since that would result in a deadlock. + //CAutoLock cAutoLock(this); + + m_aborted = true; + + return CComQIPtr(m_pUnkInner)->Abort(); +} + +STDMETHODIMP CFGManager::ShouldOperationContinue() +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->ShouldOperationContinue(); +} + +// IFilterGraph2 + +STDMETHODIMP CFGManager::AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->AddSourceFilterForMoniker(pMoniker, pCtx, lpcwstrFilterName, ppFilter); +} + +STDMETHODIMP CFGManager::ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt) +{ + if (!m_pUnkInner) { + return E_UNEXPECTED; + } + + CAutoLock cAutoLock(this); + + return CComQIPtr(m_pUnkInner)->ReconnectEx(ppin, pmt); +} + +STDMETHODIMP CFGManager::RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext) +{ + CAutoLock cAutoLock(this); + + m_streampath.RemoveAll(); + m_deadends.RemoveAll(); + + if (!pPinOut || dwFlags > AM_RENDEREX_RENDERTOEXISTINGRENDERERS || pvContext) { + return E_INVALIDARG; + } + + if (dwFlags & AM_RENDEREX_RENDERTOEXISTINGRENDERERS) { + CInterfaceList pBFs; + + BeginEnumFilters(this, pEF, pBF) { + if (CComQIPtr pAMMF = pBF) { + if (pAMMF->GetMiscFlags() & AM_FILTER_MISC_FLAGS_IS_RENDERER) { + pBFs.AddTail(pBF); + } + } else { + BeginEnumPins(pBF, pEP, pPin) { + CComPtr pPinIn; + DWORD size = 1; + if (SUCCEEDED(pPin->QueryInternalConnections(&pPinIn, &size)) && size == 0) { + pBFs.AddTail(pBF); + break; + } + } + EndEnumPins; + } + } + EndEnumFilters; + + while (!pBFs.IsEmpty()) { + HRESULT hr; + if (SUCCEEDED(hr = ConnectFilter(pPinOut, pBFs.RemoveHead()))) { + return hr; + } + } + + return VFW_E_CANNOT_RENDER; + } + + return Connect(pPinOut, (IPin*)nullptr); +} + +// IGraphBuilder2 + +STDMETHODIMP CFGManager::IsPinDirection(IPin* pPin, PIN_DIRECTION dir1) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPin, E_POINTER); + + PIN_DIRECTION dir2; + if (FAILED(pPin->QueryDirection(&dir2))) { + return E_FAIL; + } + + return dir1 == dir2 ? S_OK : S_FALSE; +} + +STDMETHODIMP CFGManager::IsPinConnected(IPin* pPin) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPin, E_POINTER); + + CComPtr pPinTo; + return SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo ? S_OK : S_FALSE; +} + +STDMETHODIMP CFGManager::ConnectFilter(IBaseFilter* pBF, IPin* pPinIn) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pBF, E_POINTER); + + if (m_aborted) { + return E_ABORT; + } + + if (pPinIn && S_OK != IsPinDirection(pPinIn, PINDIR_INPUT)) { + return VFW_E_INVALID_DIRECTION; + } + + int nTotal = 0, nRendered = 0; + + const CAppSettings& s = AfxGetAppSettings(); + + BeginEnumPins(pBF, pEP, pPin) { + if (S_OK == IsPinDirection(pPin, PINDIR_OUTPUT) + && S_OK != IsPinConnected(pPin) + && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { + + CLSID clsid; + pBF->GetClassID(&clsid); + // Disable DVD subtitle mixing in EVR (CP) and Sync Renderer for Microsoft DTV-DVD Video Decoder, it corrupts DVD playback. + if (clsid == CLSID_CMPEG2VidDecoderDS) { + if (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { + if (GetPinName(pPin)[0] == '~') { + continue; + } + } + } + // No multiple pin for Internal MPEG2 Software Decoder, NVIDIA PureVideo Decoder, Sonic Cinemaster VideoDecoder + else if (clsid == CLSID_CMpeg2DecFilter + || clsid == CLSID_NvidiaVideoDecoder + || clsid == CLSID_SonicCinemasterVideoDecoder) { + if (GetPinName(pPin)[0] == '~') { + continue; + } + //TODO: enable multiple pins for the renderer, if the video decoder supports DXVA + } + + m_streampath.Append(pBF, pPin); + + HRESULT hr = Connect(pPin, pPinIn); + + if (SUCCEEDED(hr)) { + for (int i = (int)m_deadends.GetCount() - 1; i >= 0; i--) { + if (m_deadends.GetAt(i)->Compare(m_streampath)) { + m_deadends.RemoveAt(i); + } + } + nRendered++; + } + + nTotal++; + + m_streampath.RemoveTail(); + + if (SUCCEEDED(hr) && pPinIn) { + return S_OK; + } + } + } + EndEnumPins; + + return + nRendered == nTotal ? (nRendered > 0 ? S_OK : S_FALSE) : + nRendered > 0 ? VFW_S_PARTIAL_RENDER : + VFW_E_CANNOT_RENDER; +} + +STDMETHODIMP CFGManager::ConnectFilter(IPin* pPinOut, IBaseFilter* pBF) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPinOut, E_POINTER); + CheckPointer(pBF, E_POINTER); + + if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT)) { + return VFW_E_INVALID_DIRECTION; + } + + const CAppSettings& s = AfxGetAppSettings(); + + BeginEnumPins(pBF, pEP, pPin) { + if (S_OK == IsPinDirection(pPin, PINDIR_INPUT) + && S_OK != IsPinConnected(pPin) + && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { + HRESULT hr = Connect(pPinOut, pPin); + if (SUCCEEDED(hr)) { + return hr; + } + } + } + EndEnumPins; + + return VFW_E_CANNOT_CONNECT; +} + +STDMETHODIMP CFGManager::ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) +{ + CAutoLock cAutoLock(this); + + CheckPointer(pPinOut, E_POINTER); + CheckPointer(pBF, E_POINTER); + + if (S_OK != IsPinDirection(pPinOut, PINDIR_OUTPUT)) { + return VFW_E_INVALID_DIRECTION; + } + + const CAppSettings& s = AfxGetAppSettings(); + + BeginEnumPins(pBF, pEP, pPin) { + if (S_OK == IsPinDirection(pPin, PINDIR_INPUT) + && S_OK != IsPinConnected(pPin) + && !((s.iDSVideoRendererType != VIDRNDT_DS_EVR_CUSTOM && s.iDSVideoRendererType != VIDRNDT_DS_EVR && s.iDSVideoRendererType != VIDRNDT_DS_SYNC) && GetPinName(pPin)[0] == '~')) { + HRESULT hr = ConnectDirect(pPinOut, pPin, pmt); + if (SUCCEEDED(hr)) { + return hr; + } + } + } + EndEnumPins; + + return VFW_E_CANNOT_CONNECT; +} + +STDMETHODIMP CFGManager::NukeDownstream(IUnknown* pUnk) +{ + CAutoLock cAutoLock(this); + + if (CComQIPtr pBF = pUnk) { + BeginEnumPins(pBF, pEP, pPin) { + NukeDownstream(pPin); + } + EndEnumPins; + } else if (CComQIPtr pPin = pUnk) { + CComPtr pPinTo; + if (S_OK == IsPinDirection(pPin, PINDIR_OUTPUT) + && SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo) { + if (pBF = GetFilterFromPin(pPinTo)) { + if (GetCLSID(pBF) == CLSID_EnhancedVideoRenderer) { + // GetFilterFromPin() returns pointer to the Base EVR, + // but we need to remove Outer EVR from the graph. + CComPtr pOuterEVR; + if (SUCCEEDED(pBF->QueryInterface(&pOuterEVR))) { + pBF = pOuterEVR; + } + } + NukeDownstream(pBF); + Disconnect(pPinTo); + Disconnect(pPin); + RemoveFilter(pBF); + } + } + } else { + return E_INVALIDARG; + } + + return S_OK; +} + +STDMETHODIMP CFGManager::FindInterface(REFIID iid, void** ppv, BOOL bRemove) +{ + CAutoLock cAutoLock(this); + + CheckPointer(ppv, E_POINTER); + + for (POSITION pos = m_pUnks.GetHeadPosition(); pos; m_pUnks.GetNext(pos)) { + if (SUCCEEDED(m_pUnks.GetAt(pos)->QueryInterface(iid, ppv))) { + if (bRemove) { + m_pUnks.RemoveAt(pos); + } + return S_OK; + } + } + + return E_NOINTERFACE; +} + +STDMETHODIMP CFGManager::AddToROT() +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (m_dwRegister) { + return S_FALSE; + } + + CComPtr pROT; + CComPtr pMoniker; + WCHAR wsz[256]; + swprintf_s(wsz, _countof(wsz), L"FilterGraph %08p pid %08x (MPC-HC)", this, GetCurrentProcessId()); + if (SUCCEEDED(hr = GetRunningObjectTable(0, &pROT)) + && SUCCEEDED(hr = CreateItemMoniker(L"!", wsz, &pMoniker))) { + hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, (IGraphBuilder2*)this, pMoniker, &m_dwRegister); + } + + return hr; +} + +STDMETHODIMP CFGManager::RemoveFromROT() +{ + if (!m_dwRegister) { + return S_FALSE; + } + + //CAutoLock cAutoLock(this); + + HRESULT hr; + CComPtr pROT; + if (SUCCEEDED(hr = GetRunningObjectTable(0, &pROT)) + && SUCCEEDED(hr = pROT->Revoke(m_dwRegister))) { + m_dwRegister = 0; + } + + return hr; +} + +// IGraphBuilderDeadEnd + +STDMETHODIMP_(size_t) CFGManager::GetCount() +{ + CAutoLock cAutoLock(this); + + return m_deadends.GetCount(); +} + +STDMETHODIMP CFGManager::GetDeadEnd(int iIndex, CAtlList& path, CAtlList& mts) +{ + CAutoLock cAutoLock(this); + + if (iIndex < 0 || iIndex >= (int)m_deadends.GetCount()) { + return E_FAIL; + } + + path.RemoveAll(); + mts.RemoveAll(); + + POSITION pos = m_deadends[iIndex]->GetHeadPosition(); + while (pos) { + const path_t& p = m_deadends[iIndex]->GetNext(pos); + + CStringW str; + str.Format(L"%s::%s", p.filter.GetString(), p.pin.GetString()); + path.AddTail(str); + } + + mts.AddTailList(&m_deadends[iIndex]->mts); + + return S_OK; +} + +// +// Custom Filter Injection +// + +void CFGManagerCustom::InsertLAVSplitterSource(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* src = s.SrcFilters; + + CFGFilterLAV* filter; + if (IsPreview) { + filter = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER_SOURCE); + } else { + filter = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER_SOURCE); + } + CAutoPtr pFGLAVSplitterSource(static_cast (filter)); + +#if INTERNAL_SOURCEFILTER_AVI + if (src[SRC_AVI] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,41564920")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,41564958")); + pFGLAVSplitterSource->AddEnabledFormat("avi"); + } +#endif + +#if INTERNAL_SOURCEFILTER_AVS + if (src[SRC_AVS] || IsPreview) { + pFGLAVSplitterSource->m_extensions.AddTail(_T(".avs")); + pFGLAVSplitterSource->AddEnabledFormat("avisynth"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MP4 + if (src[SRC_MP4] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,66747970")); // ftyp + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,6d6f6f76")); // moov + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,6d646174")); // mdat + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,736b6970")); // skip + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,12,ffffffff00000000ffffffff,77696465027fe3706d646174")); // wide ? mdat + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("3,3,,000001")); // raw mpeg4 video + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mov")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mp4")); + pFGLAVSplitterSource->AddEnabledFormat("mp4"); + } +#endif + +#if INTERNAL_SOURCEFILTER_FLV + if (src[SRC_FLV] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,464C5601")); // FLV (v1) + pFGLAVSplitterSource->AddEnabledFormat("flv"); + } +#endif + +#if INTERNAL_SOURCEFILTER_GIF + if (src[SRC_GIF] && !IsPreview) { + pFGLAVSplitterSource->m_extensions.AddTail(_T(".gif")); + pFGLAVSplitterSource->AddEnabledFormat("gif"); + } +#endif + +#if INTERNAL_SOURCEFILTER_ASF + if (src[SRC_ASF] || IsPreview) { + pFGLAVSplitterSource->m_extensions.AddTail(_T(".wmv")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".asf")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dvr-ms")); + pFGLAVSplitterSource->AddEnabledFormat("asf"); + } +#endif + +#if INTERNAL_SOURCEFILTER_WTV + if (src[SRC_WTV] || IsPreview) { + pFGLAVSplitterSource->m_extensions.AddTail(_T(".wtv")); + pFGLAVSplitterSource->AddEnabledFormat("wtv"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MATROSKA + if (src[SRC_MATROSKA] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,1A45DFA3")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mkv")); + pFGLAVSplitterSource->AddEnabledFormat("matroska"); + } +#endif + +#if INTERNAL_SOURCEFILTER_REALMEDIA + if (src[SRC_REALMEDIA] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,2E524D46")); + pFGLAVSplitterSource->AddEnabledFormat("rm"); + } +#endif + +#if INTERNAL_SOURCEFILTER_FLIC + if (src[SRC_FLIC] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,2,,11AF")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,2,,12AF")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".fli")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".flc")); + pFGLAVSplitterSource->AddEnabledFormat("flic"); + } +#endif + +#if INTERNAL_SOURCEFILTER_FLAC + if (src[SRC_FLAC] && !IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,664C6143")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".flac")); + pFGLAVSplitterSource->AddEnabledFormat("flac"); + } +#endif + +#if INTERNAL_SOURCEFILTER_OGG + if (src[SRC_OGG] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4F676753")); + pFGLAVSplitterSource->AddEnabledFormat("ogg"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MPEG + if (src[SRC_MPEG] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,16,FFFFFFFFF100010001800001FFFFFFFF,000001BA2100010001800001000001BB")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,5,FFFFFFFFC0,000001BA40")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,54467263,1660,1,,47")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,8,fffffc00ffe00000,4156000055000000")); + pFGLAVSplitterSource->AddEnabledFormat("mpeg"); + pFGLAVSplitterSource->AddEnabledFormat("mpegraw"); + } + if (src[SRC_MPEGTS] || IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,1,,47,188,1,,47,376,1,,47")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,1,,47,196,1,,47,388,1,,47")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".ts")); // for some broken .ts + pFGLAVSplitterSource->AddEnabledFormat("mpegts"); + } + if (src[SRC_MPEG] || src[SRC_MPEGTS] || IsPreview) { + // for Blu-ray playback + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,494E4458")); // INDX (index.bdmv) + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4D4F424A")); // MOBJ (MovieObject.bdmv) + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,4D504C53")); // MPLS + } +#endif + +#if INTERNAL_SOURCEFILTER_AC3 + if (src[SRC_AC3] && !IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,2,,0B77")); // AC3, E-AC3 + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("4,4,,F8726FBB")); // MLP + pFGLAVSplitterSource->m_extensions.AddTail(_T(".ac3")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".eac3")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mlp")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".truehd")); + pFGLAVSplitterSource->AddEnabledFormat("ac3"); + pFGLAVSplitterSource->AddEnabledFormat("eac3"); + pFGLAVSplitterSource->AddEnabledFormat("mlp"); + pFGLAVSplitterSource->AddEnabledFormat("truehd"); + } +#endif + +#if INTERNAL_SOURCEFILTER_DTS + if (src[SRC_DTS] && !IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,7FFE8001")); // DTS + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,fE7f0180")); // DTS LE + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,4,,52494646,8,8,,57415645666D7420"));// RIFFxxxxWAVEfmt_ for DTSWAV + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dts")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dtshd")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dtsma")); + pFGLAVSplitterSource->AddEnabledFormat("dts"); + pFGLAVSplitterSource->AddEnabledFormat("dtshd"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MPEGAUDIO + if (src[SRC_MPA] && !IsPreview) { + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,2,FFE0,FFE0")); + pFGLAVSplitterSource->m_chkbytes.AddTail(_T("0,10,FFFFFF00000080808080,49443300000000000000")); + pFGLAVSplitterSource->AddEnabledFormat("mp3"); + } +#endif + +#if INTERNAL_SOURCEFILTER_HTTP + if (src[SRC_HTTP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("http")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("https")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("icyx")); + pFGLAVSplitterSource->AddEnabledFormat("http"); + pFGLAVSplitterSource->AddEnabledFormat("dash"); + pFGLAVSplitterSource->AddEnabledFormat("hls"); + } +#endif + +#if INTERNAL_SOURCEFILTER_RTSP + if (src[SRC_RTSP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtsp")); + // Add transport protocol specific RTSP URL handlers + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspu")); // UDP + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspm")); // UDP multicast + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtspt")); // TCP + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtsph")); // HTTP + pFGLAVSplitterSource->AddEnabledFormat("rtsp"); + } +#endif + +#if INTERNAL_SOURCEFILTER_UDP + if (src[SRC_UDP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("udp")); + pFGLAVSplitterSource->AddEnabledFormat("udp"); + } +#endif + +#if INTERNAL_SOURCEFILTER_RTP + if (src[SRC_RTP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtp")); + pFGLAVSplitterSource->AddEnabledFormat("rtp"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MMS + if (src[SRC_MMS] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("mms")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("mmsh")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("mmst")); + pFGLAVSplitterSource->AddEnabledFormat("mms"); + } +#endif + +#if INTERNAL_SOURCEFILTER_RTMP + if (src[SRC_RTMP] && !IsPreview) { + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtmp")); + pFGLAVSplitterSource->m_protocols.AddTail(_T("rtmpt")); + pFGLAVSplitterSource->AddEnabledFormat("live_flv"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MISC + // ToDo: split into separate options + if (src[SRC_MISC] || IsPreview) { + // video + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dv")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".dhav")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".m3u8")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".y4m")); + pFGLAVSplitterSource->AddEnabledFormat("dv"); + pFGLAVSplitterSource->AddEnabledFormat("dhav"); + pFGLAVSplitterSource->AddEnabledFormat("y4m"); + } + if (src[SRC_MISC] && !IsPreview) { + // raw video + pFGLAVSplitterSource->m_extensions.AddTail(_T(".264")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".265")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".h264")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".h265")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".av1")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".m4v")); + pFGLAVSplitterSource->AddEnabledFormat("av1"); + pFGLAVSplitterSource->AddEnabledFormat("m4v"); + pFGLAVSplitterSource->AddEnabledFormat("rawvideo"); + // audio + pFGLAVSplitterSource->m_extensions.AddTail(_T(".amr")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".ape")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".mpc")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".w64")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".wav")); + pFGLAVSplitterSource->m_extensions.AddTail(_T(".wv")); + pFGLAVSplitterSource->AddEnabledFormat("amr"); + pFGLAVSplitterSource->AddEnabledFormat("ape"); + pFGLAVSplitterSource->AddEnabledFormat("mpc"); + pFGLAVSplitterSource->AddEnabledFormat("mpc8"); + pFGLAVSplitterSource->AddEnabledFormat("w64"); + pFGLAVSplitterSource->AddEnabledFormat("wav"); + pFGLAVSplitterSource->AddEnabledFormat("wv"); + } +#endif + + // Always register the pipe protocol to allow handling standard input + pFGLAVSplitterSource->m_protocols.AddTail(_T("pipe")); + + // Add LAV Source Filter if needed + if (!pFGLAVSplitterSource->m_extensions.IsEmpty() + || !pFGLAVSplitterSource->m_chkbytes.IsEmpty() + || !pFGLAVSplitterSource->m_protocols.IsEmpty()) { + m_source.AddTail(pFGLAVSplitterSource.Detach()); + } +} + +void CFGManagerCustom::InsertLAVSplitter(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* src = s.SrcFilters; + + CFGFilterLAV* filterHM, * filterLM; + if (IsPreview) { + filterHM = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER, MERIT64_ABOVE_DSHOW); + filterLM = CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::SPLITTER, MERIT64_DO_USE, true); + } else { + filterHM = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER, MERIT64_ABOVE_DSHOW); + filterLM = CFGFilterLAV::CreateFilter(CFGFilterLAV::SPLITTER, MERIT64_DO_USE, true); + } + CAutoPtr pFGLAVSplitter(static_cast(filterHM)); + CAutoPtr pFGLAVSplitterLM(static_cast(filterLM)); + +#if INTERNAL_SOURCEFILTER_MATROSKA + if (src[SRC_MATROSKA] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Matroska); + pFGLAVSplitter->AddEnabledFormat("matroska"); + } +#endif + +#if INTERNAL_SOURCEFILTER_REALMEDIA + if (src[SRC_REALMEDIA] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_RealMedia); + pFGLAVSplitter->AddEnabledFormat("rm"); + } +#endif + +#if INTERNAL_SOURCEFILTER_AVI + if (src[SRC_AVI] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Avi); + pFGLAVSplitter->AddEnabledFormat("avi"); + } +#endif + +#if INTERNAL_SOURCEFILTER_AVS + if (src[SRC_AVS] || IsPreview) { + pFGLAVSplitter->AddEnabledFormat("avisynth"); + } +#endif + +#if INTERNAL_SOURCEFILTER_OGG + if (src[SRC_OGG] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_Ogg); + pFGLAVSplitter->AddEnabledFormat("ogg"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MPEG + if (src[SRC_MPEG] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1System); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PROGRAM); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PVA); + pFGLAVSplitter->AddEnabledFormat("mpeg"); + pFGLAVSplitter->AddEnabledFormat("mpegraw"); + } + if (src[SRC_MPEGTS] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_TRANSPORT); + pFGLAVSplitter->AddEnabledFormat("mpegts"); + } +#endif + +#if INTERNAL_SOURCEFILTER_AC3 + if (src[SRC_AC3] && !IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_AC3); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_TRUEHD); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DOLBY_DDPLUS); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MLP); + pFGLAVSplitter->AddEnabledFormat("ac3"); + pFGLAVSplitter->AddEnabledFormat("eac3"); + } +#endif + +#if INTERNAL_SOURCEFILTER_DTS + if (src[SRC_DTS] && !IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DTS); + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DTS_HD); + pFGLAVSplitter->AddEnabledFormat("dts"); + pFGLAVSplitter->AddEnabledFormat("dtshd"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MPEGAUDIO + if (src[SRC_MPA] && !IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio); + pFGLAVSplitter->AddEnabledFormat("mp3"); + } +#endif + +#if INTERNAL_SOURCEFILTER_MP4 + if (src[SRC_MP4] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_MP4); + pFGLAVSplitter->AddEnabledFormat("mp4"); + } +#endif + +#if INTERNAL_SOURCEFILTER_FLV + if (src[SRC_FLV] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_FLV); + pFGLAVSplitter->AddEnabledFormat("flv"); + } +#endif + +#if INTERNAL_SOURCEFILTER_ASF + if (src[SRC_ASF] || IsPreview) { + pFGLAVSplitter->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_ASF); + pFGLAVSplitter->AddEnabledFormat("asf"); + } +#endif + + // Add LAV Splitter if needed + if (!pFGLAVSplitter->GetTypes().IsEmpty()) { + m_transform.AddTail(pFGLAVSplitter.Detach()); + } + + if (!IsPreview && pFGLAVSplitterLM) { + // Add low merit LAV Splitter + pFGLAVSplitterLM->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_NULL); + pFGLAVSplitterLM->AddEnabledFormat("*"); + // Explicitly disable all common subtitles format + pFGLAVSplitterLM->AddDisabledFormat("aqtitle"); + pFGLAVSplitterLM->AddDisabledFormat("ass"); + pFGLAVSplitterLM->AddDisabledFormat("dvbsub"); + pFGLAVSplitterLM->AddDisabledFormat("dvbtxt"); + pFGLAVSplitterLM->AddDisabledFormat("jacosub"); + pFGLAVSplitterLM->AddDisabledFormat("lrc"); + pFGLAVSplitterLM->AddDisabledFormat("microdvd"); + pFGLAVSplitterLM->AddDisabledFormat("mpl2"); + pFGLAVSplitterLM->AddDisabledFormat("mpsub"); + pFGLAVSplitterLM->AddDisabledFormat("realtext"); + pFGLAVSplitterLM->AddDisabledFormat("sami"); + pFGLAVSplitterLM->AddDisabledFormat("srt"); + pFGLAVSplitterLM->AddDisabledFormat("stl"); + pFGLAVSplitterLM->AddDisabledFormat("subviewer"); + pFGLAVSplitterLM->AddDisabledFormat("subviewer1"); + pFGLAVSplitterLM->AddDisabledFormat("sup"); + pFGLAVSplitterLM->AddDisabledFormat("vobsub"); + pFGLAVSplitterLM->AddDisabledFormat("vplayer"); + pFGLAVSplitterLM->AddDisabledFormat("webvtt"); + m_transform.AddTail(pFGLAVSplitterLM.Detach()); + } +} + +void CFGManagerCustom::InsertOtherInternalSourcefilters(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* src = s.SrcFilters; + CFGFilter* pFGF; + +#if INTERNAL_SOURCEFILTER_RFS + if (src[SRC_RFS] || IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_chkbytes.AddTail(_T("0,7,,526172211A0700")); // rar4 signature + pFGF->m_chkbytes.AddTail(_T("0,8,,526172211A070100")); // rar5 signature + pFGF->m_extensions.AddTail(_T(".rar")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_CDDA + if (src[SRC_CDDA] && !IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_extensions.AddTail(_T(".cda")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_CDXA + if (src[SRC_CDXA] || IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_chkbytes.AddTail(_T("0,4,,52494646,8,4,,43445841")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_VTS + if (src[SRC_VTS] || IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_chkbytes.AddTail(_T("0,12,,445644564944454F2D565453")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_DSM + if (src[SRC_DSM] || IsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(); + pFGF->m_chkbytes.AddTail(_T("0,4,,44534D53")); + m_source.AddTail(pFGF); + } +#endif + +#if INTERNAL_SOURCEFILTER_DSM + if (src[SRC_DSM]) { + pFGF = DEBUG_NEW CFGFilterInternal(DSMSplitterName, MERIT64_ABOVE_DSHOW); + } else { + pFGF = DEBUG_NEW CFGFilterInternal(LowMerit(DSMSplitterName), MERIT64_DO_USE); + } + pFGF->AddType(MEDIATYPE_Stream, MEDIASUBTYPE_DirectShowMedia); + pFGF->AddType(MEDIATYPE_Stream, GUID_NULL); + m_transform.AddTail(pFGF); +#endif +} + +void CFGManagerCustom::InsertLAVVideo(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* tra = s.TraFilters; + CFGFilter* pFGF; + + CAutoPtr pFGLAVVideo (IsPreview ? CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::VIDEO_DECODER, MERIT64_ABOVE_DSHOW) : CFGFilterLAV::CreateFilter(CFGFilterLAV::VIDEO_DECODER, MERIT64_ABOVE_DSHOW)); + CAutoPtr pFGLAVVideoLM(IsPreview ? CFGFilterLAV::CreateFilterPreview(CFGFilterLAV::VIDEO_DECODER, MERIT64_DO_USE, true) : CFGFilterLAV::CreateFilter(CFGFilterLAV::VIDEO_DECODER, MERIT64_DO_USE, true)); + +#if INTERNAL_DECODER_MPEG1 + pFGF = IsPreview || tra[TRA_MPEG1] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Packet); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG1Payload); +#endif +#if INTERNAL_DECODER_FLV + pFGF = IsPreview || tra[TRA_FLV4] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLV1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_flv1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLV4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_flv4); +#endif +#if INTERNAL_DECODER_VP356 + pFGF = IsPreview || tra[TRA_VP356] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP30); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP31); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP40); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP50); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp50); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP60); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp60); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP61); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp61); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP62); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp62); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP6F); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp6f); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP6A); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vp6a); +#endif +#if INTERNAL_DECODER_H264 + pFGF = IsPreview || tra[TRA_H264] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_X264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_x264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VSSH); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vssh); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DAVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_davc); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_PAVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_pavc); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_avc1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264_bis); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CCV1); +#endif +#if INTERNAL_DECODER_HEVC + pFGF = IsPreview || tra[TRA_HEVC] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HEVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HM10); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H265); +#endif +#if INTERNAL_DECODER_VVC + pFGF = IsPreview || tra[TRA_VVC] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VVC1); +#endif +#if INTERNAL_DECODER_AV1 + pFGF = IsPreview || tra[TRA_AV1] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AV01); +#endif +#if INTERNAL_DECODER_VC1 + pFGF = IsPreview || tra[TRA_VC1] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wvc1); +#endif +#if INTERNAL_DECODER_XVID + pFGF = IsPreview || tra[TRA_XVID] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_XVID); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_xvid); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_XVIX); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_xvix); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP4V); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp4v); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_M4S2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_m4s2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP4S); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp4s); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IV1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3iv1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IV2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3iv2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3IVX); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_3ivx); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_BLZ0); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_blz0); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DM4V); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dm4v); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DXGM); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dxgm); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_fmp4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_HDX4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_hdx4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_LMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_lmp4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NDIG); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ndig); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_RMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_rmp4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_smp4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SEDG); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_sedg); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_UMP4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ump4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WV1F); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wv1f); +#endif +#if INTERNAL_DECODER_DIVX + pFGF = IsPreview || tra[TRA_DIVX] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIVX); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_divx); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DX50); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dx50); +#endif +#if INTERNAL_DECODER_WMV + pFGF = IsPreview || tra[TRA_WMV] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WMV3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wmv3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_2VMW); +#endif +#if INTERNAL_DECODER_MSMPEG4 + pFGF = IsPreview || tra[TRA_MSMPEG4] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DVX3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_dvx3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP43); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp43); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_COL1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_col1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV5); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div5); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV6); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div6); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AP41); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap41); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mpg3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP42); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp42); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mpg4); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DIV1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_div1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MP41); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_mp41); +#endif +#if INTERNAL_DECODER_SVQ + pFGF = IsPreview || tra[TRA_SVQ3] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SVQ3); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SVQ1); +#endif +#if INTERNAL_DECODER_H263 + pFGF = IsPreview || tra[TRA_H263] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H263); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h263); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_S263); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_s263); +#endif +#if INTERNAL_DECODER_THEORA + pFGF = IsPreview || tra[TRA_THEORA] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_THEORA); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_theora); +#endif +#if INTERNAL_DECODER_AMVV + pFGF = IsPreview || tra[TRA_AMVV] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AMVV); +#endif +#if INTERNAL_DECODER_VP8 + pFGF = IsPreview || tra[TRA_VP8] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP80); +#endif +#if INTERNAL_DECODER_VP9 + pFGF = IsPreview || tra[TRA_VP9] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VP90); +#endif +#if INTERNAL_DECODER_MJPEG + pFGF = IsPreview || tra[TRA_MJPEG] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPG); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_QTJpeg); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPA); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPB); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVRn); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_LJPG); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_JPGL); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJLS); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPA); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MJPB); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SP5X); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_SP54); +#endif +#if INTERNAL_DECODER_INDEO + pFGF = IsPreview || tra[TRA_INDEO] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV31); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV32); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV41); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_IV50); +#endif +#if INTERNAL_DECODER_SCREEN + pFGF = IsPreview || tra[TRA_SCREEN] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_TSCC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_TSC2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VMNC); +#endif +#if INTERNAL_DECODER_FLIC + pFGF = IsPreview || tra[TRA_FLIC] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_FLIC); +#endif +#if INTERNAL_DECODER_MSVIDEO + pFGF = IsPreview || tra[TRA_MSVIDEO] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CRAM); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WHAM); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MSVC); +#endif +#if INTERNAL_DECODER_V210_V410 + pFGF = IsPreview || tra[TRA_V210_V410] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_v210); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_v410); +#endif +#if INTERNAL_DECODER_MPEG2 + pFGF = IsPreview || tra[TRA_MPEG2] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPG2); +#endif +#if INTERNAL_DECODER_PRORES + pFGF = IsPreview || tra[TRA_PRORES] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apch); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apcn); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apcs); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_apco); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap4h); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_ap4x); +#endif +#if INTERNAL_DECODER_DNXHD + pFGF = IsPreview || tra[TRA_DNXHD] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVdn); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVdh); +#endif +#if INTERNAL_DECODER_OTHERVIDEO + pFGF = IsPreview || tra[TRA_OTHERVIDEO] ? pFGLAVVideo : pFGLAVVideoLM; + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CFHD); +#endif + + // Add LAV Video if needed + if (!pFGLAVVideo->GetTypes().IsEmpty()) { + m_transform.AddTail(pFGLAVVideo.Detach()); + } + + // Add low merit LAV video + pFGLAVVideoLM->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGLAVVideoLM.Detach()); +} + +void CFGManagerCustom::InsertLAVAudio() +{ + const CAppSettings& s = AfxGetAppSettings(); + const bool* tra = s.TraFilters; + CFGFilter* pFGF; + + CAutoPtr pFGLAVAudio(CFGFilterLAV::CreateFilter(CFGFilterLAV::AUDIO_DECODER, MERIT64_ABOVE_DSHOW)); + CAutoPtr pFGLAVAudioLM(CFGFilterLAV::CreateFilter(CFGFilterLAV::AUDIO_DECODER, MERIT64_DO_USE, true)); + +#if INTERNAL_DECODER_MPEGAUDIO + pFGF = tra[TRA_MPA] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MP3); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1AudioPayload); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Payload); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Packet); + + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG2_AUDIO); +#endif + +#if INTERNAL_DECODER_AMR + pFGF = tra[TRA_AMR] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_SAMR); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AMR); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_SAWB); +#endif + +#if INTERNAL_DECODER_LPCM + pFGF = tra[TRA_LPCM] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_HDMV_LPCM_AUDIO); +#endif + +#if INTERNAL_DECODER_AC3 + pFGF = tra[TRA_AC3] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WAVE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_TRUEHD); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_DDPLUS); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MLP); +#endif + +#if INTERNAL_DECODER_DTS + pFGF = tra[TRA_DTS] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_DTS_HD); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WAVE_DTS); +#endif + +#if INTERNAL_DECODER_AAC + pFGF = tra[TRA_AAC] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_AAC); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_AAC); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AAC); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_LATM_AAC); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_AAC_ADTS); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MP4A); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MP4A); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MP4A); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_mp4a); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_mp4a); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_mp4a); +#endif + +#if INTERNAL_DECODER_PS2AUDIO + pFGF = tra[TRA_PS2AUD] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_PS2_PCM); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_PS2_PCM); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PS2_PCM); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_PS2_ADPCM); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_PS2_ADPCM); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PS2_ADPCM); +#endif + +#if INTERNAL_DECODER_VORBIS + pFGF = tra[TRA_VORBIS] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_Vorbis2); +#endif + +#if INTERNAL_DECODER_FLAC + pFGF = tra[TRA_FLAC] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_FLAC_FRAMED); +#endif + +#if INTERNAL_DECODER_NELLYMOSER + pFGF = tra[TRA_NELLY] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NELLYMOSER); +#endif + +#if INTERNAL_DECODER_ALAC + pFGF = tra[TRA_ALAC] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ALAC); +#endif + +#if INTERNAL_DECODER_ALS + pFGF = tra[TRA_ALS] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ALS); +#endif + +#if INTERNAL_DECODER_OPUS + pFGF = tra[TRA_OPUS] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_OPUS); +#endif + +#if INTERNAL_DECODER_WMA + pFGF = tra[TRA_WMA] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_MSAUDIO1); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO2); +#endif + +#if INTERNAL_DECODER_WMAPRO + pFGF = tra[TRA_WMAPRO] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO3); +#endif + +#if INTERNAL_DECODER_WMALL + pFGF = tra[TRA_WMALL] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_WMAUDIO_LOSSLESS); +#endif + +#if INTERNAL_DECODER_PCM + pFGF = tra[TRA_PCM] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_NONE); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_RAW); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_TWOS); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_SOWT); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_IN24); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_IN32); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_FL32); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM_FL64); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IEEE_FLOAT); // only for 64-bit float PCM + /* todo: this should not depend on PCM */ + #if INTERNAL_DECODER_ADPCM + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMA4); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ADPCM_SWF); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_ADPCM_AMV); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMA_WAV); + #endif +#endif + +#if INTERNAL_DECODER_G726 + pFGF = tra[TRA_G726] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_G726); +#endif + +#if INTERNAL_DECODER_G729 + pFGF = tra[TRA_G729] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_G729); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_729A); +#endif + +#if INTERNAL_DECODER_OTHERAUDIO + pFGF = tra[TRA_OTHERAUDIO] ? pFGLAVAudio : pFGLAVAudioLM; + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IMC); +#endif + + // Add LAV Audio if needed + if (!pFGLAVAudio->GetTypes().IsEmpty()) { + m_transform.AddTail(pFGLAVAudio.Detach()); + } + + // Add low merit LAV Audio + pFGLAVAudioLM->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGLAVAudioLM.Detach()); +} + +void CFGManagerCustom::InsertBlockedFilters() +{ + // "Subtitle Mixer" makes an access violation around the + // 11-12th media type when enumerating them on its output. + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{00A95963-3BE5-48C0-AD9F-3356D67EA09D}")), MERIT64_DO_NOT_USE)); + + // DiracSplitter.ax is crashing MPC-HC when opening invalid files... + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{09E7F58E-71A1-419D-B0A0-E524AE1454A9}")), MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{5899CFB9-948F-4869-A999-5544ECB38BA5}")), MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{F78CF248-180E-4713-B107-B13F7B5C31E1}")), MERIT64_DO_NOT_USE)); + + // ISCR suxx + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}")), MERIT64_DO_NOT_USE)); + + // Samsung's "mpeg-4 demultiplexor" can even open matroska files, amazing... + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{99EC0C72-4D1B-411B-AB1F-D561EE049D94}")), MERIT64_DO_NOT_USE)); + + // LG Video Renderer (lgvid.ax) just crashes when trying to connect it + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{9F711C60-0668-11D0-94D4-0000C02BA972}")), MERIT64_DO_NOT_USE)); + + // palm demuxer crashes (even crashes graphedit when dropping an .ac3 onto it) + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{BE2CF8A7-08CE-4A2C-9A25-FD726A999196}")), MERIT64_DO_NOT_USE)); + + // mainconcept color space converter + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{272D77A0-A852-4851-ADA4-9091FEAD4C86}")), MERIT64_DO_NOT_USE)); + + // mainconcept mp4 demuxer + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{2A55FF12-1657-41D7-9D2D-A2CDC6978FF2}")), MERIT64_DO_NOT_USE)); + + // Accusoft PICVideo M-JPEG Codec + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{4C4CD9E1-F876-11D2-962F-00500471FDDC}")), MERIT64_DO_NOT_USE)); + + // SolveigMM MP4 Demultiplexer (smm_mp4demuxer.ax) + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{5F19B8FE-BA79-4183-B3CF-FEE4E8F801E4}")), MERIT64_DO_NOT_USE)); + + // Morgan's Stream Switcher (mmswitch.ax) + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_MorganStreamSwitcher, MERIT64_DO_NOT_USE)); + + if (AfxGetAppSettings().bBlockRDP) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_RDPDShowRedirectionFilter, MERIT64_DO_NOT_USE)); + } + + // DCDSPFilter (early versions crash mpc) + { + CRegKey key; + + TCHAR buff[256]; + ULONG len = sizeof(buff); + ZeroMemory(buff, sizeof(buff)); + + CString clsid = _T("{B38C58A0-1809-11D6-A458-EDAE78F1DF12}"); + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + clsid + _T("\\InprocServer32"), KEY_READ) + && ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len) + && FileVersionInfo::GetFileVersionNum(buff) < 0x0001000000030000ui64) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(clsid), MERIT64_DO_NOT_USE)); + } + } +} + +void CFGManagerCustom::InsertSubtitleFilters(bool IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + CFGFilter* pFGF; + + // Null text renderer + pFGF = DEBUG_NEW CFGFilterInternal(L"NullTextRenderer", IsPreview ? MERIT64_ABOVE_DSHOW : MERIT64_DO_USE); + pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_ScriptCommand, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_Subtitle, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DVD_SUBPICTURE); + pFGF->AddType(MEDIATYPE_NULL, MEDIASUBTYPE_CVD_SUBPICTURE); + pFGF->AddType(MEDIATYPE_NULL, MEDIASUBTYPE_SVCD_SUBPICTURE); + m_transform.AddTail(pFGF); + + if (IsPreview) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + } else { + // Insert preferred subtitle renderer and block others + switch (s.GetSubtitleRenderer()) { + case CAppSettings::SubtitleRenderer::INTERNAL: + if (s.fBlockVSFilter) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); + } + if (s.fBlockVSFilter || IsCLSIDRegistered(CLSID_VSFilter)) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); + } + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + break; + case CAppSettings::SubtitleRenderer::VS_FILTER: + pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_ABOVE_DSHOW); + if (pFGF) { + pFGF->AddType(MEDIASUBTYPE_NULL, MEDIASUBTYPE_NULL); + m_override.AddTail(pFGF); + } + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + break; + case CAppSettings::SubtitleRenderer::XY_SUB_FILTER: + pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_ABOVE_DSHOW); + if (pFGF) { + pFGF->AddType(MEDIASUBTYPE_NULL, MEDIASUBTYPE_NULL); + m_override.AddTail(pFGF); + } + pFGF = DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_ABOVE_DSHOW); + if (pFGF) { + pFGF->AddType(MEDIATYPE_Text, MEDIASUBTYPE_NULL); + pFGF->AddType(MEDIATYPE_Subtitle, MEDIASUBTYPE_NULL); + m_override.AddTail(pFGF); + } + if (s.fBlockVSFilter) { + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); + } + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + break; + case CAppSettings::SubtitleRenderer::NONE: + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VSFilter2, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_XySubFilter_AutoLoader, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter, MERIT64_DO_NOT_USE)); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_AssFilter_AutoLoader, MERIT64_DO_NOT_USE)); + break; + } + } +} + +void CFGManagerCustom::InsertBroadcomDecoder() +{ + CFGFilter* pFGF = DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{2DE1D17E-46B1-42A8-9AEC-E20E80D9B1A9}")), MERIT64_ABOVE_DSHOW); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_h264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_X264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_x264); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_VSSH); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_vssh); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_DAVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_davc); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_PAVC); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_pavc); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_AVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_avc1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_H264_bis); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_CCV1); + + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_WVC1); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_wvc1); + + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_VIDEO); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO); + m_transform.AddHead(pFGF); +} + +// +// CFGManagerCustom +// + +CFGManagerCustom::CFGManagerCustom(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) + : CFGManager(pName, pUnk, hWnd, IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + + bool bOverrideBroadcom = false; + CFGFilter* pFGF; + m_source; + + const bool* src = s.SrcFilters; + const bool* tra = s.TraFilters; + + // Reset LAVFilters internal instances + CFGFilterLAV::ResetInternalInstances(); + + // Add internal filters + InsertLAVSplitterSource(IsPreview); + InsertLAVSplitter(IsPreview); + InsertOtherInternalSourcefilters(IsPreview); +#if HAS_VIDEO_DECODERS + InsertLAVVideo(IsPreview); +#endif +#if HAS_AUDIO_DECODERS + if (!IsPreview) { + InsertLAVAudio(); + } +#endif + InsertSubtitleFilters(IsPreview); + + // Blocked filters + InsertBlockedFilters(); + if (m_bIsPreview) { + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_RDPDShowRedirectionFilter, MERIT64_DO_NOT_USE)); + } + + // Overrides + WORD merit_low = 1; + POSITION pos = s.m_filters.GetTailPosition(); + while (pos) { + FilterOverride* fo = s.m_filters.GetPrev(pos); + + if (!fo->fDisabled && fo->name == _T("Broadcom Video Decoder")) { + bOverrideBroadcom = true; + } + if (fo->fDisabled || fo->type == FilterOverride::EXTERNAL && !PathUtils::Exists(MakeFullPath(fo->path))) { + continue; + } + + ULONGLONG merit = + fo->iLoadType == FilterOverride::BLOCK ? MERIT64_DO_NOT_USE : + fo->iLoadType == FilterOverride::PREFERRED ? (IsPreview ? MERIT64_DO_USE : MERIT64_ABOVE_DSHOW) : + MERIT64(fo->dwMerit); + + merit += merit_low++; + + pFGF = nullptr; + if (fo->type == FilterOverride::REGISTERED) { + pFGF = DEBUG_NEW CFGFilterRegistry(fo->dispname, merit); + } else if (fo->type == FilterOverride::EXTERNAL) { + pFGF = DEBUG_NEW CFGFilterFile(fo->clsid, fo->path, CStringW(fo->name), merit); + } + if (pFGF) { + pFGF->SetTypes(fo->guids); + m_override.AddTail(pFGF); + } + } + + /* Use Broadcom decoder (if installed) for VC-1, H.264 and MPEG-2 */ + if (!IsPreview && !bOverrideBroadcom) { + // ToDo: maybe remove support for this old filter? + InsertBroadcomDecoder(); + } +} + +STDMETHODIMP CFGManagerCustom::AddFilter(IBaseFilter* pBF, LPCWSTR pName) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + if (FAILED(hr = __super::AddFilter(pBF, pName))) { + return hr; + } + + CAppSettings& s = AfxGetAppSettings(); + + if (GetCLSID(pBF) == CLSID_DMOWrapperFilter) { + if (CComQIPtr pPB = pBF) { + CComVariant var(true); + pPB->Write(_T("_HIRESOUTPUT"), &var); + } + } + + if (CComQIPtr pASF = pBF) { + pASF->EnableDownSamplingTo441(s.fDownSampleTo441); + pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); + pASF->SetAudioTimeShift(s.fAudioTimeShift ? 10000i64 * s.iAudioTimeShift : 0); + pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); + } + + return hr; +} + +// +// CFGManagerPlayer +// + +CFGManagerPlayer::CFGManagerPlayer(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) + : CFGManagerCustom(pName, pUnk, hWnd, IsPreview) + , m_hWnd(hWnd) +{ + TRACE(_T("CFGManagerPlayer::CFGManagerPlayer on thread: %lu\n"), GetCurrentThreadId()); + CFGFilter* pFGF; + + const CAppSettings& s = AfxGetAppSettings(); + + /* value is chosen so that it is higher than standard renderers, but lower than important intermediate filters like VSFilter */ + UINT64 renderer_merit = MERIT64(0x800001) + 0x100; + + // Switchers + + if (s.fEnableAudioSwitcher && !m_bIsPreview) { + pFGF = DEBUG_NEW CFGFilterInternal(L"Audio Switcher", renderer_merit + 0x100); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } + + // Renderers + if (!m_bIsPreview) { + switch (s.iDSVideoRendererType) { + case VIDRNDT_DS_DEFAULT: + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VideoRendererDefault, MERIT64(0x800001))); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_VideoMixingRenderer9, MERIT64(0x200003))); + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(CLSID_EnhancedVideoRenderer, MERIT64(0x200002))); + break; + case VIDRNDT_DS_OVERLAYMIXER: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_OverlayMixer, StrRes(IDS_PPAGE_OUTPUT_OVERLAYMIXER), renderer_merit)); + break; + case VIDRNDT_DS_VMR9WINDOWED: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VideoMixingRenderer9, StrRes(IDS_PPAGE_OUTPUT_VMR9WINDOWED), renderer_merit)); + break; + case VIDRNDT_DS_VMR9RENDERLESS: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VMR9AllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_VMR9RENDERLESS), renderer_merit)); + break; + case VIDRNDT_DS_EVR: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, StrRes(IDS_PPAGE_OUTPUT_EVR), renderer_merit)); + break; + case VIDRNDT_DS_EVR_CUSTOM: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_EVR_CUSTOM), renderer_merit)); + break; + case VIDRNDT_DS_DXR: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_DXRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_DXR), renderer_merit)); + break; + case VIDRNDT_DS_MADVR: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_madVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_MADVR), renderer_merit)); + break; + case VIDRNDT_DS_SYNC: + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_SyncAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_SYNC), renderer_merit)); + break; + case VIDRNDT_DS_MPCVR: + if (!m_bIsCapture) { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_MPCVRAllocatorPresenter, StrRes(IDS_PPAGE_OUTPUT_MPCVR), renderer_merit)); + } else { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, StrRes(IDS_PPAGE_OUTPUT_EVR), renderer_merit)); + } + break; + case VIDRNDT_DS_NULL_COMP: + pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_COMP), MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + break; + case VIDRNDT_DS_NULL_UNCOMP: + pFGF = DEBUG_NEW CFGFilterInternal(StrRes(IDS_PPAGE_OUTPUT_NULL_UNCOMP), MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + break; + } + } else { + bool preview_evrcp = (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) || (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) || (s.iDSVideoRendererType == VIDRNDT_DS_MADVR) || (s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); + if (preview_evrcp && CAppSettings::IsVideoRendererAvailable(VIDRNDT_DS_EVR_CUSTOM)) { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EVRAllocatorPresenter, L"EVRCP - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); + m_bPreviewSupportsRotation = true; + } else if (CAppSettings::IsVideoRendererAvailable(VIDRNDT_DS_EVR)) { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_EnhancedVideoRenderer, L"EVR - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); + } else { + m_transform.AddTail(DEBUG_NEW CFGFilterVideoRenderer(m_hWnd, CLSID_VideoMixingRenderer9, L"VMR9 - Preview Window", MERIT64_ABOVE_DSHOW + 2, true)); + } + } + + if (!m_bIsPreview) { + CString SelAudioRenderer = s.SelectedAudioRenderer(); + if (SelAudioRenderer == AUDRNDT_NULL_COMP) { + pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_COMP, MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + // DVD stuff + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); + m_transform.AddTail(pFGF); + } else if (SelAudioRenderer == AUDRNDT_NULL_UNCOMP) { + pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_UNCOMP, MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } else if (SelAudioRenderer == AUDRNDT_INTERNAL) { + struct SaneAudioRendererFilter : CFGFilter { + SaneAudioRendererFilter(CStringW name, UINT64 merit) : + CFGFilter(SaneAudioRenderer::Factory::GetFilterGuid(), name, merit) {} + + HRESULT Create(IBaseFilter** ppBF, CInterfaceList&) override { + return SaneAudioRenderer::Factory::CreateFilter(AfxGetAppSettings().sanear, ppBF); + } + }; + pFGF = DEBUG_NEW SaneAudioRendererFilter(AUDRNDT_SANEAR, renderer_merit + 0x50); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } else if (SelAudioRenderer == AUDRNDT_MPC) { + pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_MPC, renderer_merit); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_PCM); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_IEEE_FLOAT); + m_transform.AddTail(pFGF); + } else if (!SelAudioRenderer.IsEmpty()) { + pFGF = DEBUG_NEW CFGFilterRegistry(SelAudioRenderer, renderer_merit); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } + } else { + pFGF = DEBUG_NEW CFGFilterInternal(AUDRNDT_NULL_COMP, MERIT64_ABOVE_DSHOW + 2); + pFGF->AddType(MEDIATYPE_Audio, MEDIASUBTYPE_NULL); + // DVD stuff + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DOLBY_AC3); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_MPEG2_AUDIO); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DVD_LPCM_AUDIO); + pFGF->AddType(MEDIATYPE_DVD_ENCRYPTED_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PACK, MEDIASUBTYPE_DTS); + pFGF->AddType(MEDIATYPE_MPEG2_PES, MEDIASUBTYPE_DTS); + m_transform.AddTail(pFGF); + } +} + +STDMETHODIMP CFGManagerPlayer::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) +{ + CAutoLock cAutoLock(this); + + CLSID pin_clsid = GetCLSID(pPinOut); + if (pin_clsid == CLSID_MPEG2Demultiplexer) { + CComQIPtr pMS = pPinOut; + REFERENCE_TIME rtDur = 0; + if (!pMS || FAILED(pMS->GetDuration(&rtDur)) || rtDur <= 0) { + return E_FAIL; + } + } else if (pin_clsid == CLSID_StillVideo || pin_clsid == CLSID_MPCImageSource) { + CComQIPtr pMS = pPinOut; + if (pMS) { + const CAppSettings& s = AfxGetAppSettings(); + if (s.iStillVideoDuration > 0) { + REFERENCE_TIME rtCur = 0; + REFERENCE_TIME rtDur = 0; + REFERENCE_TIME rtDurOverride = s.iStillVideoDuration * 10000000LL; + pMS->GetDuration(&rtDur); + if (rtDur == 0 || rtDur >= 10 * 3600 * 10000000LL) { + rtDur = rtDurOverride; + } else if (rtDur < rtDurOverride) { + rtDur = (rtDurOverride / rtDur) * rtDur; + } + // always call SetPositions() to prevent infinite repeat by the source filter + pMS->SetPositions(&rtCur, AM_SEEKING_AbsolutePositioning, &rtDur, AM_SEEKING_AbsolutePositioning); + } + } + } + + return __super::ConnectDirect(pPinOut, pPinIn, pmt); +} + +// +// CFGManagerDVD +// + +CFGManagerDVD::CFGManagerDVD(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview) + : CFGManagerPlayer(pName, pUnk, hWnd, IsPreview) +{ + const CAppSettings& s = AfxGetAppSettings(); + + // elecard's decoder isn't suited for dvd playback (atm) + m_transform.AddTail(DEBUG_NEW CFGFilterRegistry(GUIDFromCString(_T("{F50B3F13-19C4-11CF-AA9A-02608C9BABA2}")), MERIT64_DO_NOT_USE)); +} + +class CResetDVD : public CDVDSession +{ +public: + CResetDVD(LPCTSTR path) { + if (Open(path)) { + if (BeginSession()) { + Authenticate(); /*GetDiscKey();*/ + EndSession(); + } + Close(); + } + } +}; + +STDMETHODIMP CFGManagerDVD::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) +{ + CAutoLock cAutoLock(this); + + HRESULT hr; + + CComPtr pBF; + if (FAILED(hr = AddSourceFilter(lpcwstrFile, lpcwstrFile, &pBF))) { + return hr; + } + + return ConnectFilter(pBF, nullptr); +} + +STDMETHODIMP CFGManagerDVD::AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter) +{ + CAutoLock cAutoLock(this); + + CheckPointer(lpcwstrFileName, E_POINTER); + CheckPointer(ppFilter, E_POINTER); + + CStringW fn = CStringW(lpcwstrFileName).TrimLeft(); + + GUID clsid = CLSID_DVDNavigator; + + CComPtr pBF; + if (FAILED(pBF.CoCreateInstance(clsid)) + || FAILED(AddFilter(pBF, L"DVD Navigator"))) { + return VFW_E_CANNOT_LOAD_SOURCE_FILTER; + } + + CComQIPtr pDVDC; + CComQIPtr pDVDI; + + if (!((pDVDC = pBF) && (pDVDI = pBF))) { + return E_NOINTERFACE; + } + + WCHAR buff[MAX_PATH]; + ULONG len; + if ((!fn.IsEmpty() + && FAILED(pDVDC->SetDVDDirectory(fn)) + && FAILED(pDVDC->SetDVDDirectory(fn + L"VIDEO_TS")) + && FAILED(pDVDC->SetDVDDirectory(fn + L"\\VIDEO_TS"))) + || FAILED(pDVDI->GetDVDDirectory(buff, _countof(buff), &len)) || len == 0) { + return E_INVALIDARG; + } + + pDVDC->SetOption(DVD_ResetOnStop, FALSE); + pDVDC->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); + + if (clsid == CLSID_DVDNavigator) { + CResetDVD(CString(buff)); + } + + *ppFilter = pBF.Detach(); + + return S_OK; +} + +// +// CFGManagerCapture +// + +CFGManagerCapture::CFGManagerCapture(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd) + : CFGManagerPlayer(pName, pUnk, hWnd) +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (s.bCaptureDeinterlace) { + // set merit higher than our video renderers + CFGFilter* pFGF = DEBUG_NEW CFGFilterInternal(L"Deinterlacer", MERIT64(0x800001) + 0x200); + pFGF->AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); + m_transform.AddTail(pFGF); + } + + m_bIsCapture = True; +} + +// +// CFGManagerMuxer +// + +CFGManagerMuxer::CFGManagerMuxer(LPCTSTR pName, LPUNKNOWN pUnk) + : CFGManagerCustom(pName, pUnk) +{ + m_source.AddTail(DEBUG_NEW CFGFilterInternal()); +} + +// +// CFGAggregator +// + +CFGAggregator::CFGAggregator(const CLSID& clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT& hr) + : CUnknown(pName, pUnk) +{ + hr = m_pUnkInner.CoCreateInstance(clsid, GetOwner()); +} + +CFGAggregator::~CFGAggregator() +{ + m_pUnkInner.Release(); +} + +STDMETHODIMP CFGAggregator::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + m_pUnkInner && (riid != IID_IUnknown && SUCCEEDED(m_pUnkInner->QueryInterface(riid, ppv))) ? S_OK : + __super::NonDelegatingQueryInterface(riid, ppv); +} diff --git a/src/mpc-hc/FGManager.h b/src/mpc-hc/FGManager.h index 1ec16f5d63e..2d91169a485 100644 --- a/src/mpc-hc/FGManager.h +++ b/src/mpc-hc/FGManager.h @@ -1,212 +1,212 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "FGFilter.h" -#include "FGFilterLAV.h" -#include "IGraphBuilder2.h" - -class CFGManager - : public CUnknown - , public IGraphBuilder2 - , public IGraphBuilderDeadEnd - , public CCritSec -{ -public: - struct path_t { - CLSID clsid; - CString filter, pin; - }; - - class CStreamPath : public CAtlList - { - public: - void Append(IBaseFilter* pBF, IPin* pPin); - bool Compare(const CStreamPath& path); - }; - - class CStreamDeadEnd : public CStreamPath - { - public: - CAtlList mts; - }; - -private: - CComPtr m_pUnkInner; - DWORD m_dwRegister; - - bool m_aborted; - - CStreamPath m_streampath; - CAutoPtrArray m_deadends; - -protected: - CComPtr m_pFM; - CInterfaceList m_pUnks; - CAtlList m_source, m_transform, m_override; - - BOOL m_ignoreVideo; - - CString m_useragent; - CString m_referrer; - - static bool CheckBytes(HANDLE hFile, CString chkbytes); - - HRESULT EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl); - HRESULT AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF); - HRESULT Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender); - - // IFilterGraph - - STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); - STDMETHODIMP RemoveFilter(IBaseFilter* pFilter); - STDMETHODIMP EnumFilters(IEnumFilters** ppEnum); - STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter); - STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP Reconnect(IPin* ppin); - STDMETHODIMP Disconnect(IPin* ppin); - STDMETHODIMP SetDefaultSyncSource(); - - // IGraphBuilder - - STDMETHODIMP Connect(IPin* pPinOut, IPin* pPinIn); - STDMETHODIMP Render(IPin* pPinOut); - STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); - STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - STDMETHODIMP SetLogFile(DWORD_PTR hFile); - STDMETHODIMP Abort(); - STDMETHODIMP ShouldOperationContinue(); - - // IFilterGraph2 - - STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext); - - // IGraphBuilder2 - - STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir); - STDMETHODIMP IsPinConnected(IPin* pPin); - STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn); - STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF); - STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt); - STDMETHODIMP NukeDownstream(IUnknown* pUnk); - STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove); - STDMETHODIMP AddToROT(); - STDMETHODIMP RemoveFromROT(); - - // IGraphBuilderDeadEnd - - STDMETHODIMP_(size_t) GetCount(); - STDMETHODIMP GetDeadEnd(int iIndex, CAtlList& path, CAtlList& mts); - - // - HWND m_hWnd; - bool m_bIsPreview,m_bPreviewSupportsRotation; - CStringW m_entryRFS; - bool m_bIsCapture; - -public: - CFGManager(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd = 0, bool IsPreview = false); - virtual ~CFGManager(); - HRESULT RenderRFSFileEntry(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList, CStringW entryRFS); - bool PreviewSupportsRotation() { return m_bPreviewSupportsRotation; } - static CUnknown* WINAPI GetMpcAudioRendererInstance(LPUNKNOWN lpunk, HRESULT* phr); - - void SetUserAgent(CString ua) { m_useragent = ua; }; - void SetReferrer(CString ref) { m_referrer = ref; }; - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); -}; - -class CFGManagerCustom : public CFGManager -{ -public: - // IFilterGraph - - STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); - - void InsertLAVSplitterSource(bool IsPreview = false); - void InsertLAVSplitter(bool IsPreview = false); - void InsertLAVVideo(bool IsPreview = false); - void InsertLAVAudio(); - void InsertOtherInternalSourcefilters(bool IsPreview = false); - void InsertSubtitleFilters(bool IsPreview = false); - void InsertBlockedFilters(); - void InsertBroadcomDecoder(); - -public: - CFGManagerCustom(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd = 0, bool IsPreview = false); -}; - -class CFGManagerPlayer : public CFGManagerCustom -{ -protected: - HWND m_hWnd; - - // IFilterGraph - - STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); - -public: - CFGManagerPlayer(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview = false); -}; - -class CFGManagerDVD : public CFGManagerPlayer -{ -protected: - // IGraphBuilder - - STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); - STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); - -public: - CFGManagerDVD(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview = false); -}; - -class CFGManagerCapture : public CFGManagerPlayer -{ -public: - CFGManagerCapture(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd); -}; - -class CFGManagerMuxer : public CFGManagerCustom -{ -public: - CFGManagerMuxer(LPCTSTR pName, LPUNKNOWN pUnk); -}; - -// - -class CFGAggregator : public CUnknown -{ -protected: - CComPtr m_pUnkInner; - -public: - CFGAggregator(const CLSID& clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT& hr); - virtual ~CFGAggregator(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "FGFilter.h" +#include "FGFilterLAV.h" +#include "IGraphBuilder2.h" + +class CFGManager + : public CUnknown + , public IGraphBuilder2 + , public IGraphBuilderDeadEnd + , public CCritSec +{ +public: + struct path_t { + CLSID clsid; + CString filter, pin; + }; + + class CStreamPath : public CAtlList + { + public: + void Append(IBaseFilter* pBF, IPin* pPin); + bool Compare(const CStreamPath& path); + }; + + class CStreamDeadEnd : public CStreamPath + { + public: + CAtlList mts; + }; + +private: + CComPtr m_pUnkInner; + DWORD m_dwRegister; + + bool m_aborted; + + CStreamPath m_streampath; + CAutoPtrArray m_deadends; + +protected: + CComPtr m_pFM; + CInterfaceList m_pUnks; + CAtlList m_source, m_transform, m_override; + + BOOL m_ignoreVideo; + + CString m_useragent; + CString m_referrer; + + static bool CheckBytes(HANDLE hFile, CString chkbytes); + + HRESULT EnumSourceFilters(LPCWSTR lpcwstrFileName, CFGFilterList& fl); + HRESULT AddSourceFilter(CFGFilter* pFGF, LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppBF); + HRESULT Connect(IPin* pPinOut, IPin* pPinIn, bool bContinueRender); + + // IFilterGraph + + STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); + STDMETHODIMP RemoveFilter(IBaseFilter* pFilter); + STDMETHODIMP EnumFilters(IEnumFilters** ppEnum); + STDMETHODIMP FindFilterByName(LPCWSTR pName, IBaseFilter** ppFilter); + STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP Reconnect(IPin* ppin); + STDMETHODIMP Disconnect(IPin* ppin); + STDMETHODIMP SetDefaultSyncSource(); + + // IGraphBuilder + + STDMETHODIMP Connect(IPin* pPinOut, IPin* pPinIn); + STDMETHODIMP Render(IPin* pPinOut); + STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); + STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + STDMETHODIMP SetLogFile(DWORD_PTR hFile); + STDMETHODIMP Abort(); + STDMETHODIMP ShouldOperationContinue(); + + // IFilterGraph2 + + STDMETHODIMP AddSourceFilterForMoniker(IMoniker* pMoniker, IBindCtx* pCtx, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + STDMETHODIMP ReconnectEx(IPin* ppin, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP RenderEx(IPin* pPinOut, DWORD dwFlags, DWORD* pvContext); + + // IGraphBuilder2 + + STDMETHODIMP IsPinDirection(IPin* pPin, PIN_DIRECTION dir); + STDMETHODIMP IsPinConnected(IPin* pPin); + STDMETHODIMP ConnectFilter(IBaseFilter* pBF, IPin* pPinIn); + STDMETHODIMP ConnectFilter(IPin* pPinOut, IBaseFilter* pBF); + STDMETHODIMP ConnectFilterDirect(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt); + STDMETHODIMP NukeDownstream(IUnknown* pUnk); + STDMETHODIMP FindInterface(REFIID iid, void** ppv, BOOL bRemove); + STDMETHODIMP AddToROT(); + STDMETHODIMP RemoveFromROT(); + + // IGraphBuilderDeadEnd + + STDMETHODIMP_(size_t) GetCount(); + STDMETHODIMP GetDeadEnd(int iIndex, CAtlList& path, CAtlList& mts); + + // + HWND m_hWnd; + bool m_bIsPreview,m_bPreviewSupportsRotation; + CStringW m_entryRFS; + bool m_bIsCapture; + +public: + CFGManager(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd = 0, bool IsPreview = false); + virtual ~CFGManager(); + HRESULT RenderRFSFileEntry(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrPlayList, CStringW entryRFS); + bool PreviewSupportsRotation() { return m_bPreviewSupportsRotation; } + static CUnknown* WINAPI GetMpcAudioRendererInstance(LPUNKNOWN lpunk, HRESULT* phr); + + void SetUserAgent(CString ua) { m_useragent = ua; }; + void SetReferrer(CString ref) { m_referrer = ref; }; + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); +}; + +class CFGManagerCustom : public CFGManager +{ +public: + // IFilterGraph + + STDMETHODIMP AddFilter(IBaseFilter* pFilter, LPCWSTR pName); + + void InsertLAVSplitterSource(bool IsPreview = false); + void InsertLAVSplitter(bool IsPreview = false); + void InsertLAVVideo(bool IsPreview = false); + void InsertLAVAudio(); + void InsertOtherInternalSourcefilters(bool IsPreview = false); + void InsertSubtitleFilters(bool IsPreview = false); + void InsertBlockedFilters(); + void InsertBroadcomDecoder(); + +public: + CFGManagerCustom(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd = 0, bool IsPreview = false); +}; + +class CFGManagerPlayer : public CFGManagerCustom +{ +protected: + HWND m_hWnd; + + // IFilterGraph + + STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); + +public: + CFGManagerPlayer(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview = false); +}; + +class CFGManagerDVD : public CFGManagerPlayer +{ +protected: + // IGraphBuilder + + STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); + STDMETHODIMP AddSourceFilter(LPCWSTR lpcwstrFileName, LPCWSTR lpcwstrFilterName, IBaseFilter** ppFilter); + +public: + CFGManagerDVD(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd, bool IsPreview = false); +}; + +class CFGManagerCapture : public CFGManagerPlayer +{ +public: + CFGManagerCapture(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd); +}; + +class CFGManagerMuxer : public CFGManagerCustom +{ +public: + CFGManagerMuxer(LPCTSTR pName, LPUNKNOWN pUnk); +}; + +// + +class CFGAggregator : public CUnknown +{ +protected: + CComPtr m_pUnkInner; + +public: + CFGAggregator(const CLSID& clsid, LPCTSTR pName, LPUNKNOWN pUnk, HRESULT& hr); + virtual ~CFGAggregator(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); +}; diff --git a/src/mpc-hc/FGManagerBDA.cpp b/src/mpc-hc/FGManagerBDA.cpp index 6214d4f8679..2f848165b29 100644 --- a/src/mpc-hc/FGManagerBDA.cpp +++ b/src/mpc-hc/FGManagerBDA.cpp @@ -1,1456 +1,1456 @@ -/* - * (C) 2009-2017 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 . - * - */ - -#include "stdafx.h" -#include "FGManagerBDA.h" -#include "Mpeg2SectionData.h" -#include "MainFrm.h" -#include "Logger.h" -#include -#include -#include -#include -#include -#include - -#define LOG(...) MPCHC_LOG(BDA, __VA_ARGS__) -#define CheckAndLogBDA(x, msg) hr = ##x; if (FAILED(hr)) { LOG(msg _T(": 0x%08x\n"), hr); return hr; } -#define CheckAndLogBDANoRet(x, msg) hr = ##x; if (FAILED(hr)) { LOG(msg _T(": 0x%08x\n"), hr); } - -/// Format, Video MPEG2 -static VIDEOINFOHEADER2 sMpv_fmt = { - {0, 0, 720, 576}, // rcSource - {0, 0, 0, 0}, // rcTarget - 0, // dwBitRate - 0, // dwBitErrorRate - 400000, // AvgTimePerFrame - 0, // dwInterlaceFlags - 0, // dwCopyProtectFlags - 0, // dwPictAspectRatioX - 0, // dwPictAspectRatioY - {0}, // dwControlFlag & dwReserved1 - 0, // dwReserved2 - { - // bmiHeader - sizeof(BITMAPINFOHEADER), // biSize - 720, // biWidth - 576, // biHeight - 0, // biPlanes - 0, // biBitCount - 0 // biCompression - } - // implicitly sets the others fields to 0 -}; - -/// Media type, Video MPEG2 -static const AM_MEDIA_TYPE mt_Mpv = { - MEDIATYPE_Video, // majortype - MEDIASUBTYPE_MPEG2_VIDEO, // subtype - FALSE, // bFixedSizeSamples - TRUE, // bTemporalCompression - 0, // lSampleSize - FORMAT_VideoInfo2, // formattype - nullptr, // pUnk - sizeof(sMpv_fmt), // cbFormat - (LPBYTE)& sMpv_fmt // pbFormat -}; - -/// Format, Video H264 -static VIDEOINFOHEADER2 vih2_H264 = { - {0, 0, 0, 0}, // rcSource - {0, 0, 0, 0}, // rcTarget - 0, // dwBitRate, - 0, // dwBitErrorRate - 0, // AvgTimePerFrame - 0, // dwInterlaceFlags - 0, // dwCopyProtectFlags - 0, // dwPictAspectRatioX - 0, // dwPictAspectRatioY - {0}, // dwControlFlag & dwReserved1 - 0, // dwReserved2 - { - // bmiHeader - sizeof(BITMAPINFOHEADER), // biSize - 720, // biWidth - 576, // biHeight - 1, // biPlanes - 0, // biBitCount - MAKEFOURCC('h', '2', '6', '4') // biCompression - } - // implicitly sets the others fields to 0 -}; - -/// Media type, Video H264 -static const AM_MEDIA_TYPE mt_H264 = { - MEDIATYPE_Video, // majortype - MEDIASUBTYPE_H264, // subtype - FALSE, // bFixedSizeSamples - TRUE, // bTemporalCompression - 0, // lSampleSize - FORMAT_VideoInfo2, // formattype - nullptr, // pUnk - sizeof(vih2_H264), // cbFormat - (LPBYTE)& vih2_H264 // pbFormat -}; - -/// Format, Video HEVC -static VIDEOINFOHEADER2 vih2_HEVC = { - {0, 0, 0, 0}, // rcSource - {0, 0, 0, 0}, // rcTarget - 0, // dwBitRate, - 0, // dwBitErrorRate - 0, // AvgTimePerFrame - 0, // dwInterlaceFlags - 0, // dwCopyProtectFlags - 0, // dwPictAspectRatioX - 0, // dwPictAspectRatioY - {0}, // dwControlFlag & dwReserved1 - 0, // dwReserved2 - { - // bmiHeader - sizeof(BITMAPINFOHEADER), // biSize - 720, // biWidth - 576, // biHeight - 1, // biPlanes - 0, // biBitCount - MAKEFOURCC('H', 'E', 'V', 'C') // biCompression - } - // implicitly sets the others fields to 0 -}; - -/// Media type, Video HEVC -static const AM_MEDIA_TYPE mt_HEVC = { - MEDIATYPE_Video, // majortype - MEDIASUBTYPE_HEVC, // subtype - FALSE, // bFixedSizeSamples - TRUE, // bTemporalCompression - 0, // lSampleSize - FORMAT_VideoInfo2, // formattype - nullptr, // pUnk - sizeof(vih2_HEVC), // cbFormat - (LPBYTE)& vih2_HEVC // pbFormat -}; - -// Format, Audio MPEG2 -static BYTE MPEG2AudioFormat[] = { - 0x50, 0x00, //wFormatTag - 0x02, 0x00, //nChannels - 0x80, 0xbb, 0x00, 0x00, //nSamplesPerSec - 0x00, 0x7d, 0x00, 0x00, //nAvgBytesPerSec - 0x01, 0x00, //nBlockAlign - 0x00, 0x00, //wBitsPerSample - 0x16, 0x00, //cbSize - 0x02, 0x00, //wValidBitsPerSample - 0x00, 0xe8, //wSamplesPerBlock - 0x03, 0x00, //wReserved - 0x01, 0x00, 0x01, 0x00, //dwChannelMask - 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// Format, Audio (E)AC3 -static BYTE AC3AudioFormat[] = { - 0x00, 0x20, //wFormatTag - 0x06, 0x00, //nChannels - 0x80, 0xBB, 0x00, 0x00, //nSamplesPerSec - 0xC0, 0x5D, 0x00, 0x00, //nAvgBytesPerSec - 0x00, 0x03, //nBlockAlign - 0x00, 0x00, //wBitsPerSample - 0x00, 0x00 //cbSize -}; - -// Format, Audio AAC -static BYTE AACAudioFormat[] = { - 0xFF, 0x00, //wFormatTag - 0x02, 0x00, //nChannels - 0x80, 0xBB, 0x00, 0x00, //nSamplesPerSec - 0xCE, 0x3E, 0x00, 0x00, //nAvgBytesPerSec - 0xAE, 0x02, //nBlockAlign - 0x00, 0x00, //wBitsPerSample - 0x02, 0x00, //cbSize - 0x11, 0x90 -}; - -/// Media type, Audio MPEG2 -static const AM_MEDIA_TYPE mt_Mpa = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_MPEG2_AUDIO, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(MPEG2AudioFormat), // cbFormat - MPEG2AudioFormat // pbFormat -}; - -/// Media type, Audio AC3 -static const AM_MEDIA_TYPE mt_Ac3 = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_DOLBY_AC3, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(AC3AudioFormat), // cbFormat - AC3AudioFormat, // pbFormat -}; - -/// Media type, Audio EAC3 -static const AM_MEDIA_TYPE mt_Eac3 = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_DOLBY_DDPLUS, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(AC3AudioFormat), // cbFormat - AC3AudioFormat, // pbFormat -}; - -/// Media type, Audio AAC ADTS -static const AM_MEDIA_TYPE mt_adts = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_MPEG_ADTS_AAC, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(AACAudioFormat), // cbFormat - AACAudioFormat, // pbFormat -}; - -/// Media type, Audio AAC LATM -static const AM_MEDIA_TYPE mt_latm = { - MEDIATYPE_Audio, // majortype - MEDIASUBTYPE_LATM_AAC, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_WaveFormatEx, // formattype - nullptr, // pUnk - sizeof(AACAudioFormat), // cbFormat - AACAudioFormat, // pbFormat -}; - -/// Media type, PSI -static const AM_MEDIA_TYPE mt_Psi = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_MPEG2DATA, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr // pbFormat -}; - -/// Media type, TIF -static const AM_MEDIA_TYPE mt_DVB_Tif = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_DVB_SI, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr // pbFormat -}; - -/// Media type, EPG -static const AM_MEDIA_TYPE mt_DVB_Epg = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_DVB_SI, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr, // pbFormat -}; - -/// Media type, TIF -static const AM_MEDIA_TYPE mt_ATSC_Tif = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_ATSC_SI, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr // pbFormat -}; - -/// Media type, EPG -static const AM_MEDIA_TYPE mt_ATSC_Epg = { - MEDIATYPE_MPEG2_SECTIONS, // majortype - MEDIASUBTYPE_ATSC_SI, // subtype - TRUE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - 0, // cbFormat - nullptr, // pbFormat -}; - -static const SUBTITLEINFO SubFormat = { 0, "", L"" }; - -/// Media type, subtitle -static const AM_MEDIA_TYPE mt_Subtitle = { - MEDIATYPE_Subtitle, // majortype - MEDIASUBTYPE_DVB_SUBTITLES, // subtype - FALSE, // bFixedSizeSamples - FALSE, // bTemporalCompression - 0, // lSampleSize - FORMAT_None, // formattype - nullptr, // pUnk - sizeof(SubFormat), // cbFormat - (LPBYTE)& SubFormat // pbFormat -}; - -/// CLSID for TIF -// FC772AB0-0C7F-11D3-8FF2-00A0C9224CF4 -static const CLSID CLSID_BDA_MPEG2_TIF = -{0xFC772AB0, 0x0C7F, 0x11D3, {0x8F, 0xF2, 0x00, 0xA0, 0xC9, 0x22, 0x4C, 0xF4}}; - -CFGManagerBDA::CFGManagerBDA(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd) - : CFGManagerPlayer(pName, pUnk, hWnd) -{ - LOG(_T("---------------------------------------------------------------->")); - LOG(_T("Starting session...")); - - CAppSettings& s = AfxGetAppSettings(); - m_nDVBRebuildFilterGraph = s.nDVBRebuildFilterGraph; - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - - if (pChannel) { - if (pChannel->GetVideoType() == BDA_H264) { - UpdateMediaType(&vih2_H264, pChannel); - } else if (pChannel->GetVideoType() == BDA_HEVC) { - UpdateMediaType(&vih2_HEVC, pChannel); - } else if (pChannel->GetVideoType() == BDA_MPV) { - UpdateMediaType(&sMpv_fmt, pChannel); - } - } - - tunerIsATSC = false; - BeginEnumSysDev(KSCATEGORY_BDA_NETWORK_TUNER, pMoniker) { - CComHeapPtr strName; - if (SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName)) ) { - if (s.strBDATuner == CString(strName)) { - CComPtr pPB; - pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)); - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - CString fName = CString(var.bstrVal); - if (fName.Find(_T("ATSC")) > -1) { //hack to identify an ATSC tuner. better solution might be to check the tuner capabilities, but this should be good enough - tunerIsATSC = true; - } - } - } - } - } - EndEnumSysDev; - - m_DVBStreams[BDA_MPV] = CDVBStream(L"mpv", &mt_Mpv); - m_DVBStreams[BDA_H264] = CDVBStream(L"h264", &mt_H264); - m_DVBStreams[BDA_HEVC] = CDVBStream(L"HEVC", &mt_HEVC); - m_DVBStreams[BDA_MPA] = CDVBStream(L"mpa", &mt_Mpa); - m_DVBStreams[BDA_AC3] = CDVBStream(L"ac3", &mt_Ac3); - m_DVBStreams[BDA_EAC3] = CDVBStream(L"eac3", &mt_Eac3); - m_DVBStreams[BDA_ADTS] = CDVBStream(L"adts", &mt_adts); - m_DVBStreams[BDA_LATM] = CDVBStream(L"latm", &mt_latm); - m_DVBStreams[BDA_PSI] = CDVBStream(L"psi", &mt_Psi, true, MEDIA_MPEG2_PSI); - if (tunerIsATSC) { - m_DVBStreams[BDA_TIF] = CDVBStream(L"tif", &mt_ATSC_Tif, true); - m_DVBStreams[BDA_EPG] = CDVBStream(L"epg", &mt_ATSC_Epg); - } else { - m_DVBStreams[BDA_TIF] = CDVBStream(L"tif", &mt_DVB_Tif, true); - m_DVBStreams[BDA_EPG] = CDVBStream(L"epg", &mt_DVB_Epg); - } - m_DVBStreams[BDA_SUB] = CDVBStream(L"sub", &mt_Subtitle/*, false, MEDIA_TRANSPORT_PAYLOAD*/); - - if (pChannel) { - m_nCurVideoType = pChannel->GetVideoType(); - m_nCurAudioType = pChannel->GetDefaultAudioType(); - } else { - m_nCurVideoType = BDA_MPV; - m_nCurAudioType = BDA_MPA; - } - m_fHideWindow = false; - - // Blacklist some unsupported filters (AddHead must be used to ensure higher priority): - // - audio switcher - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(__uuidof(CAudioSwitcherFilter), MERIT64_DO_NOT_USE)); - // - internal video decoder and ffdshow DXVA video decoder (cf ticket #730) - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_MPCVideoDecoder, MERIT64_DO_NOT_USE)); - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_FFDShowDXVADecoder, MERIT64_DO_NOT_USE)); - // - Microsoft DTV-DVD Audio Decoder - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_MSDVTDVDAudioDecoder, MERIT64_DO_NOT_USE)); - // - ACM Wrapper - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_ACMWrapper, MERIT64_DO_NOT_USE)); - // - ReClock - m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_ReClock, MERIT64_DO_NOT_USE)); - - LOG(_T("CFGManagerBDA object created.")); -} - -CFGManagerBDA::~CFGManagerBDA() -{ - m_DVBStreams.RemoveAll(); - LOG(_T("CFGManagerBDA object destroyed.")); - LOG(_T("<----------------------------------------------------------------\n\n")); -} - -HRESULT CFGManagerBDA::CreateKSFilterFN(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& FriendlyName) { - HRESULT hr = VFW_E_NOT_FOUND; - BeginEnumSysDev(KSCategory, pMoniker) { - CComPtr pPB; - CComVariant var; - if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB))) && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - CStringW fName = CStringW(var.bstrVal); - if (fName != FriendlyName) { - continue; - } - - hr = pMoniker->BindToObject(nullptr, nullptr, IID_PPV_ARGS(ppBF)); - if (SUCCEEDED(hr)) { - hr = AddFilter(*ppBF, fName); - } - break; - } - } - EndEnumSysDev; - - return hr; -} - - -HRESULT CFGManagerBDA::CreateKSFilter(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& DisplayName) -{ - HRESULT hr = VFW_E_NOT_FOUND; - BeginEnumSysDev(KSCategory, pMoniker) { - CComPtr pPB; - CComVariant var; - CComHeapPtr strName; - if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB))) && - SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName)) && - SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - CStringW Name = strName; - if (Name != DisplayName) { - continue; - } - - hr = pMoniker->BindToObject(nullptr, nullptr, IID_PPV_ARGS(ppBF)); - if (SUCCEEDED(hr)) { - hr = AddFilter(*ppBF, CStringW(var.bstrVal)); - } - break; - } - } - EndEnumSysDev; - - return hr; -} - -HRESULT CFGManagerBDA::SearchIBDATopology(const CComPtr& pTuner, REFIID iid, CComPtr& pUnk) -{ - CComQIPtr pTop(pTuner); - CheckPointer(pTop, E_NOINTERFACE); - - ULONG NodeTypes = 0; - ULONG NodeType[32]; - - HRESULT hr = pTop->GetNodeTypes(&NodeTypes, _countof(NodeType), NodeType); - - if (FAILED(hr)) { - return hr; - } - - for (ULONG i = 0; i < NodeTypes; i++) { - ULONG nInterfaces; - GUID aInterface[32]; - - hr = pTop->GetNodeInterfaces(NodeType[i], &nInterfaces, _countof(aInterface), aInterface); - - if (FAILED(hr)) { - continue; - } - - for (ULONG j = 0; j < nInterfaces; j++) { - if (aInterface[j] == iid) { - return pTop->GetControlNode(0, 1, NodeType[i], &pUnk); - } - } - } - - return FAILED(hr) ? hr : E_NOINTERFACE; -} - -HRESULT CFGManagerBDA::ConnectFilters(IBaseFilter* pOutFilter, IBaseFilter* pInFilter) -{ - HRESULT hr = VFW_E_CANNOT_CONNECT; - BeginEnumPins(pOutFilter, pEP, pOutPin) { - if (S_OK == IsPinDirection(pOutPin, PINDIR_OUTPUT) - && S_OK != IsPinConnected(pOutPin)) { - BeginEnumPins(pInFilter, pEP2, pInPin) { - if (S_OK == IsPinDirection(pInPin, PINDIR_INPUT) - && S_OK != IsPinConnected(pInPin)) { - hr = this->ConnectDirect(pOutPin, pInPin, nullptr); - -#if 0 && defined(_DEBUG) // Disabled by default because it can be verbose - CPinInfo infoPinIn, infoPinOut; - infoPinIn.achName[0] = infoPinOut.achName[0] = L'\0'; - CFilterInfo infoFilterIn, infoFilterOut; - infoFilterIn.achName[0] = infoFilterOut.achName[0] = L'\0'; - - pInPin->QueryPinInfo(&infoPinIn); - if (infoPinIn.pFilter) { - infoPinIn.pFilter->QueryFilterInfo(&infoFilterIn); - } - pOutPin->QueryPinInfo(&infoPinOut); - if (infoPinOut.pFilter) { - infoPinOut.pFilter->QueryFilterInfo(&infoFilterOut); - } - - TRACE(_T("%s - %s => %s - %s (hr=0x%08x)\n"), infoFilterOut.achName, infoPinOut.achName, infoFilterIn.achName, infoPinIn.achName, hr); -#endif - - if (SUCCEEDED(hr)) { - return hr; - } - } - } - EndEnumPins; - } - } - EndEnumPins; - - return hr; -} - -STDMETHODIMP CFGManagerBDA::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) -{ - HRESULT hr; - const CAppSettings& s = AfxGetAppSettings(); - CComPtr pNetwork; - CComPtr pTuner; - CComPtr pReceiver; - - LOG(_T("Creating BDA filters...")); - CheckAndLogBDA(CreateKSFilterFN(&pNetwork, KSCATEGORY_BDA_NETWORK_PROVIDER, _T("Microsoft Network Provider")), _T("Network provider creation")); - if (FAILED(hr = CreateKSFilter(&pTuner, KSCATEGORY_BDA_NETWORK_TUNER, s.strBDATuner))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CREATE_TUNER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Network tuner creation: 0x%08x\n"), hr); - LOG(_T("Network tuner creation: 0x%08x"), hr); - return hr; - } - - if (FAILED(hr = ConnectFilters(pNetwork, pTuner))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CONNECT_TUNER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Network <-> Tuner: 0x%08x\n"), hr); - LOG(_T("Network <-> Tuner: 0x%08x"), hr); - return hr; - } - m_pBDAControl = pTuner; - - if (FAILED(hr = SearchIBDATopology(pTuner, m_pBDAFreq))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, _T("IBDA_FrequencyFilter topology failed."), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - LOG(_T("IBDA_FrequencyFilter topology failed.")); - return hr; - } - m_pBDATunerStats = m_pBDAFreq; - if (FAILED(hr = SearchIBDATopology(pTuner, m_pBDADemodulator))) { - TRACE(_T("BDA: IBDA_DigitalDemodulator topology failed: 0x%08x\n"), hr); - LOG(_T("IBDA_DigitalDemodulator topology failed. Result 0x%08x"), hr); - } - m_pBDADemodStats = m_pBDADemodulator; - - if (!m_pBDATunerStats || !m_pBDADemodStats) { - if (m_pBDATunerStats) { - TRACE(_T("BDA: no statistics interface on the demodulator node --> using the statistics from the RF node only\n")); - LOG(_T("No statistics interface on the demodulator node --> using the statistics from the RF node only.")); - m_pBDADemodStats = m_pBDATunerStats; - } else if (m_pBDADemodStats) { - TRACE(_T("BDA: no statistics interface on the RF node --> using the statistics from the demodulator node only\n")); - LOG(_T("No statistics interface on the RF node --> using the statistics from the demodulator node only.")); - m_pBDATunerStats = m_pBDADemodStats; - } else { // if (!m_pBDATunerStats && !m_pBDADemodStats) - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, _T("No statistics interface available."), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Not statistics interface available\n")); - LOG(_T("Not statistics interface available.")); - return E_NOINTERFACE; - } - } - - if (SUCCEEDED(hr = SearchIBDATopology(pTuner, m_pBDAAutoDemulate))) { - if (SUCCEEDED(hr = m_pBDAAutoDemulate->put_AutoDemodulate())) { - LOG(_T("Auto Demulate is on.")); - } else { - LOG(_T("Auto Demulate could not be switched: 0x%08x."), hr); - } - } else { - LOG(_T("AutoDemulate topology not found.")); - TRACE(_T("BDA: AutoDemulate topology not found: 0x%08x\n"), hr); - } - - if (FAILED(hr = m_pDemux.CoCreateInstance(CLSID_MPEG2Demultiplexer, nullptr, CLSCTX_INPROC_SERVER))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_DEMULTIPLEXER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Microsoft demux creation: 0x%08x\n"), hr); - return hr; - } - CheckNoLog(AddFilter(m_pDemux, _T("MPEG-2 Demultiplexer"))); - if (FAILED(ConnectFilters(pTuner, m_pDemux))) { // Separate receiver is required - if (FAILED(hr = CreateKSFilter(&pReceiver, KSCATEGORY_BDA_RECEIVER_COMPONENT, s.strBDAReceiver))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CREATE_RECEIVER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Receiver creation: 0x%08x\n"), hr); - return hr; - } - if (FAILED(hr = ConnectFilters(pTuner, pReceiver))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CONNECT_TUNER_REC), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Tuner <-> Receiver: 0x%08x\n"), hr); - return hr; - } - if (FAILED(ConnectFilters(pReceiver, m_pDemux))) { - MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_DEMULTIPLEXER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); - TRACE(_T("BDA: Receiver <-> Demux: 0x%08x\n"), hr); - return hr; - } - LOG(_T("Network -> Tuner -> Receiver connected.")); - - } else { // The selected filter is performing both tuner and receiver functions - LOG(_T("Network -> Receiver connected.")); - } - - CheckNoLog(CreateMicrosoftDemux(m_pDemux)); - -#ifdef _DEBUG - LOG(_T("Filter list:")); - BeginEnumFilters(this, pEF, pBF) { - LOG(_T(" ") + GetFilterName(pBF)); - } - EndEnumFilters; - LOG(_T("Filter list end.\n")); -#endif - - return hr; -} - -STDMETHODIMP CFGManagerBDA::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) -{ - // Bypass CFGManagerPlayer limitation (IMediaSeeking for Mpeg2 demux) - return CFGManagerCustom::ConnectDirect(pPinOut, pPinIn, pmt); -} - -STDMETHODIMP CFGManagerBDA::SetChannel(int nChannelPrefNumber) -{ - HRESULT hr = E_INVALIDARG; - CAppSettings& s = AfxGetAppSettings(); - - CBDAChannel* pChannel = s.FindChannelByPref(nChannelPrefNumber); - LOG(_T("Start SetChannel %d."), nChannelPrefNumber); - if (pChannel) { - if (!((m_nCurAudioType == BDA_UNKNOWN) ^ (pChannel->GetDefaultAudioType() == BDA_UNKNOWN)) && - ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_NEVER) || - ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_WHEN_SWITCHING) && (m_nCurVideoType == pChannel->GetVideoType())) || - ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_ALWAYS) && (s.nDVBLastChannel == nChannelPrefNumber)))) { - hr = SetChannelInternal(pChannel); - } else { - s.nDVBLastChannel = nChannelPrefNumber; - return S_FALSE; - } - - if (SUCCEEDED(hr)) { - s.nDVBLastChannel = nChannelPrefNumber; - m_nCurVideoType = pChannel->GetVideoType(); - m_nCurAudioType = pChannel->GetDefaultAudioType(); - LOG(_T("SetChannel %d successful.\n"), nChannelPrefNumber); - } else { - LOG(_T("SetChannel %d failed. Result: 0x%08x.\n"), nChannelPrefNumber, hr); - } - } - return hr; -} - -STDMETHODIMP CFGManagerBDA::SetAudio(int nAudioIndex) -{ - return E_NOTIMPL; -} - -STDMETHODIMP CFGManagerBDA::SetFrequency(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) -{ - HRESULT hr; - LOG(_T("Frequency %lu, Bandwidth %lu, SymbolRate %lu"), ulFrequency, ulBandwidth, ulSymbolRate); - CheckPointer(m_pBDAControl, E_FAIL); - CheckPointer(m_pBDAFreq, E_FAIL); - - CheckAndLogBDA(m_pBDAControl->StartChanges(), _T(" SetFrequency StartChanges")); - if (ulSymbolRate != 0) { - CheckAndLogBDANoRet(m_pBDADemodulator->put_SymbolRate(&ulSymbolRate), _T(" SetFrequency put_SymbolRate")); - } - CheckAndLogBDANoRet(m_pBDAFreq->put_FrequencyMultiplier(1000), _T(" SetFrequency put_FrequencyMultiplier")); - CheckAndLogBDANoRet(m_pBDAFreq->put_Bandwidth(ulBandwidth / 1000), _T(" SetFrequency put_Bandwidth")); - CheckAndLogBDA(m_pBDAFreq->put_Frequency(ulFrequency), _T(" SetFrequency put_Frequency")); - CheckAndLogBDA(m_pBDAControl->CheckChanges(), _T(" SetFrequency CheckChanges")); - CheckAndLogBDA(m_pBDAControl->CommitChanges(), _T(" SetFrequency CommitChanges")); - - int i = 50; - ULONG pState = BDA_CHANGES_PENDING; - while (SUCCEEDED(hr = m_pBDAControl->GetChangeState(&pState)) && pState == BDA_CHANGES_PENDING && i-- > 0) { - LOG(_T("changes pending, waiting for tuner...")); - Sleep(50); - } - - if (SUCCEEDED(hr)) { - if (pState == BDA_CHANGES_PENDING) { - LOG(_T("changes pending (timeout error----)")); - hr = VFW_E_TIMEOUT; - } else { - LOG(_T("Frequency changed: %lu / %lu."), ulFrequency, ulBandwidth); -#ifdef _DEBUG - BOOLEAN bPresent; - BOOLEAN bLocked; - LONG lDbStrength; - LONG lPercentQuality; - - if (SUCCEEDED(GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { - LOG(_T("Signal stats: Strength %ld dB, Quality %ld%%"), lDbStrength, lPercentQuality); - } -#endif - } - } else { - LOG(_T("Frequency change failed. Result: 0x%08x."), hr); - } - - return hr; -} - -HRESULT CFGManagerBDA::ClearMaps() -{ - HRESULT hr = S_OK; - - if (m_DVBStreams[BDA_MPV].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_MPV].Unmap(m_DVBStreams[BDA_MPV].GetMappedPID())); - } - if (m_DVBStreams[BDA_H264].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_H264].Unmap(m_DVBStreams[BDA_H264].GetMappedPID())); - } - if (m_DVBStreams[BDA_HEVC].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_HEVC].Unmap(m_DVBStreams[BDA_HEVC].GetMappedPID())); - } - if (m_DVBStreams[BDA_MPA].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_MPA].Unmap(m_DVBStreams[BDA_MPA].GetMappedPID())); - } - if (m_DVBStreams[BDA_AC3].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_AC3].Unmap(m_DVBStreams[BDA_AC3].GetMappedPID())); - } - if (m_DVBStreams[BDA_EAC3].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_EAC3].Unmap(m_DVBStreams[BDA_EAC3].GetMappedPID())); - } - if (m_DVBStreams[BDA_ADTS].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_ADTS].Unmap(m_DVBStreams[BDA_ADTS].GetMappedPID())); - } - if (m_DVBStreams[BDA_LATM].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_LATM].Unmap(m_DVBStreams[BDA_LATM].GetMappedPID())); - } - if (m_DVBStreams[BDA_SUB].GetMappedPID()) { - CheckNoLog(m_DVBStreams[BDA_SUB].Unmap(m_DVBStreams[BDA_SUB].GetMappedPID())); - } - - return hr; -} - -STDMETHODIMP CFGManagerBDA::Scan(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd) -{ - HRESULT hr = S_OK; - - if (ulFrequency == 0 || ulBandwidth == 0) { - ClearMaps(); - } else { - CMpeg2DataParser Parser(m_DVBStreams[BDA_PSI].GetFilter()); - - LOG(_T("Scanning frequency %u.........."), ulFrequency); - - if (tunerIsATSC) { - enum DVB_SI vctType; - if (FAILED(hr = Parser.ParseMGT(vctType)) || SI_undef == vctType) { //try to read MGT to determine type of ATSC - vctType = TID_CVCT; - } - hr = Parser.ParseVCT(ulFrequency, ulBandwidth, ulSymbolRate, vctType); //ATSC - LOG(L"ParseVCT failed. Result: 0x%08x.", hr); - } else { - hr = Parser.ParseSDT(ulFrequency, ulBandwidth, ulSymbolRate); //DVB - LOG(L"ParseSDT failed. Result: 0x%08x.", hr); - } - if (!FAILED(hr)) { - if (FAILED(hr = Parser.ParsePAT())) { - LOG(_T("ParsePAT failed. Result: 0x%08x."), hr); - } else if (FAILED(hr = Parser.ParseNIT())) { - LOG(_T("ParseNIT failed. Result: 0x%08x."), hr); - } - } - - POSITION pos = Parser.Channels.GetStartPosition(); - while (pos) { - CBDAChannel& Channel = Parser.Channels.GetNextValue(pos); - if (Channel.HasName()) { - ::SendMessage(hWnd, WM_TUNER_NEW_CHANNEL, 0, (LPARAM)(LPCTSTR)Channel.ToString()); - } - } - LOG(_T("Scanning frequency %u done."), ulFrequency); - } - - return hr; -} - -STDMETHODIMP CFGManagerBDA::GetStats(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality) -{ - HRESULT hr = S_OK; - CheckPointer(m_pBDATunerStats, E_UNEXPECTED); - CheckPointer(m_pBDADemodStats, E_UNEXPECTED); - - if (FAILED(hr = m_pBDATunerStats->get_SignalPresent(&bPresent)) && FAILED(hr = m_pBDADemodStats->get_SignalPresent(&bPresent))) { - return hr; - } - if (FAILED(hr = m_pBDADemodStats->get_SignalLocked(&bLocked)) && FAILED(hr = m_pBDATunerStats->get_SignalLocked(&bLocked))) { - return hr; - } - if (FAILED(hr = m_pBDATunerStats->get_SignalStrength(&lDbStrength)) && FAILED(hr = m_pBDADemodStats->get_SignalStrength(&lDbStrength))) { - return hr; - } - if (FAILED(hr = m_pBDADemodStats->get_SignalQuality(&lPercentQuality)) && FAILED(hr = m_pBDATunerStats->get_SignalQuality(&lPercentQuality))) { - return hr; - } - - return hr; -} - -// IAMStreamSelect -STDMETHODIMP CFGManagerBDA::Count(DWORD* pcStreams) -{ - CheckPointer(pcStreams, E_POINTER); - CAppSettings& s = AfxGetAppSettings(); - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - - *pcStreams = 0; - - if (pChannel) { - int Streams = pChannel->GetAudioCount() + pChannel->GetSubtitleCount(); - *pcStreams = pChannel->GetSubtitleCount() ? Streams + 1 : Streams; - } - - return S_OK; -} - -STDMETHODIMP CFGManagerBDA::Enable(long lIndex, DWORD dwFlags) -{ - HRESULT hr = E_INVALIDARG; - CAppSettings& s = AfxGetAppSettings(); - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - - if (pChannel) { - if (lIndex >= 0 && lIndex < pChannel->GetAudioCount()) { - BDAStreamInfo* pStreamInfo = pChannel->GetAudio(lIndex); - if (pStreamInfo) { - CDVBStream* pStream = &m_DVBStreams[pStreamInfo->nType]; - if (pStream) { - if (pStream->GetMappedPID()) { - pStream->Unmap(pStream->GetMappedPID()); - } - FILTER_STATE nState = GetState(); - if (m_nCurAudioType != pStreamInfo->nType) { - if ((s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS) && (GetState() != State_Stopped)) { - ChangeState(State_Stopped); - } - SwitchStream(m_nCurAudioType, pStreamInfo->nType); - m_nCurAudioType = pStreamInfo->nType; - CheckNoLog(Flush(m_nCurVideoType, m_nCurAudioType)); - } - pStream->Map(pStreamInfo->ulPID); - ChangeState((FILTER_STATE)nState); - - hr = S_OK; - } else { - ASSERT(FALSE); - } - } else { - ASSERT(FALSE); - } - } else if (lIndex > 0 && lIndex < pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { - BDAStreamInfo* pStreamInfo = pChannel->GetSubtitle(lIndex - pChannel->GetAudioCount()); - - if (pStreamInfo) { - m_DVBStreams[BDA_SUB].Map(pStreamInfo->ulPID); - hr = S_OK; - } - } else if (lIndex > 0 && m_DVBStreams[BDA_SUB].GetMappedPID() && lIndex == pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { - m_DVBStreams[BDA_SUB].Unmap(m_DVBStreams[BDA_SUB].GetMappedPID()); - hr = S_OK; - } - } else { - ASSERT(FALSE); - } - - return hr; -} - -STDMETHODIMP CFGManagerBDA::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) -{ - HRESULT hr = E_INVALIDARG; - CAppSettings& s = AfxGetAppSettings(); - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - BDAStreamInfo* pStreamInfo = nullptr; - CDVBStream* pStream = nullptr; - CDVBStream* pCurrentStream = nullptr; - - if (pChannel) { - if (lIndex >= 0 && lIndex < pChannel->GetAudioCount()) { - pCurrentStream = &m_DVBStreams[m_nCurAudioType]; - pStreamInfo = pChannel->GetAudio(lIndex); - if (pStreamInfo) { - pStream = &m_DVBStreams[pStreamInfo->nType]; - } - if (pdwGroup) { - *pdwGroup = 1; // Audio group - } - } else if (lIndex > 0 && lIndex < pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { - pCurrentStream = &m_DVBStreams[BDA_SUB]; - pStreamInfo = pChannel->GetSubtitle(lIndex - pChannel->GetAudioCount()); - if (pStreamInfo) { - pStream = &m_DVBStreams[pStreamInfo->nType]; - } - if (pdwGroup) { - *pdwGroup = 2; // Subtitle group - } - } else if (lIndex > 0 && lIndex == pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { - pCurrentStream = &m_DVBStreams[BDA_SUB]; - - if (pCurrentStream) { - if (pdwFlags) { - *pdwFlags = (!pCurrentStream->GetMappedPID()) ? AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE : 0; - } - if (plcid) { - *plcid = (LCID)LCID_NOSUBTITLES; - } - if (pdwGroup) { - *pdwGroup = 2; // Subtitle group - } - if (ppszName) { - CStringW str; - str = _T("No subtitles"); - - *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); - if (*ppszName == nullptr) { - return E_OUTOFMEMORY; - } - wcscpy_s(*ppszName, str.GetLength() + 1, str); - } - } - - return S_OK; - } - - if (pStreamInfo && pStream && pCurrentStream) { - if (ppmt) { - const AM_MEDIA_TYPE* pMT = pStream->GetMediaType(); - if (pMT) { - *ppmt = CreateMediaType(pMT); - } else { - *ppmt = nullptr; - return E_FAIL; - } - } - if (pdwFlags) { - *pdwFlags = (pCurrentStream->GetMappedPID() == pStreamInfo->ulPID) ? AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE : 0; - } - if (plcid) { - *plcid = pStreamInfo->GetLCID(); - } - if (ppObject) { - *ppObject = nullptr; - } - if (ppUnk) { - *ppUnk = nullptr; - } - if (ppszName) { - CStringW str; - - str = StreamTypeToName(pStreamInfo->nPesType); - - if (!pStreamInfo->sLanguage.IsEmpty() && pStreamInfo->GetLCID() == 0) { - // Try to convert language code even if LCID was not found. - str += _T(" [") + ISOLang::ISO6392ToLanguage(CStringA(pStreamInfo->sLanguage)) + _T("]"); - } - - *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); - if (*ppszName == nullptr) { - return E_OUTOFMEMORY; - } - wcscpy_s(*ppszName, str.GetLength() + 1, str); - } - - hr = S_OK; - } - } - - return hr; -} - -STDMETHODIMP CFGManagerBDA::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - QI(IBDATuner) - QI(IAMStreamSelect) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -HRESULT CFGManagerBDA::CreateMicrosoftDemux(CComPtr& pMpeg2Demux) -{ - CComPtr pDemux; - HRESULT hr; - bool bAudioMPA = false; - bool bAudioAC3 = false; - bool bAudioEAC3 = false; - bool bAudioADTS = false; - bool bAudioLATM = false; - - CheckNoLog(pMpeg2Demux->QueryInterface(IID_PPV_ARGS(&pDemux))); - - LOG(_T("Receiver -> Demux connected.")); - CAppSettings& s = AfxGetAppSettings(); - CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); - if (pChannel && (m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_ALWAYS)) { - for (int i = 0; i < pChannel->GetAudioCount(); i++) { - switch ((pChannel->GetAudio(i))->nType) { - case BDA_MPA: - bAudioMPA = true; - break; - case BDA_AC3: - bAudioAC3 = true; - break; - case BDA_EAC3: - bAudioEAC3 = true; - break; - case BDA_ADTS: - bAudioADTS = true; - break; - case BDA_LATM: - bAudioLATM = true; - break; - } - } - } else { // All the possible audio filters will be present in the filter graph - bAudioMPA = true; - bAudioAC3 = true; - bAudioEAC3 = true; - bAudioADTS = true; - bAudioLATM = true; - } - - POSITION pos = m_DVBStreams.GetStartPosition(); - while (pos) { - CComPtr pPin; - BDA_STREAM_TYPE nType = m_DVBStreams.GetNextKey(pos); - CDVBStream& Stream = m_DVBStreams[nType]; - - switch (nType) { - case BDA_TIF: - case BDA_PSI: - if (!Stream.GetFindExisting() || - (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { - CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); - } - CheckNoLog(Connect(pPin, nullptr, false)); - Stream.SetPin(pPin); - LOG(_T("Filter connected to Demux for media type %d."), nType); - break; - - case BDA_MPV: - case BDA_H264: - case BDA_HEVC: - if ((nType == m_nCurVideoType) || (m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_NEVER)) { - if (!Stream.GetFindExisting() || - (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { - CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); - } - if (m_nCurVideoType == nType) { - CheckNoLog(Connect(pPin, nullptr, true)); - Stream.SetPin(pPin); - LOG(_T("Graph completed for stream type %d."), nType); - } else { - CheckNoLog(Connect(pPin, nullptr, false)); - Stream.SetPin(pPin); - LOG(_T("Filter connected to Demux for media type %d."), nType); - } - } - break; - - case BDA_MPA: - case BDA_AC3: - case BDA_EAC3: - case BDA_ADTS: - case BDA_LATM: - if ((bAudioMPA && (nType == BDA_MPA)) || (bAudioAC3 && (nType == BDA_AC3)) || - (bAudioEAC3 && (nType == BDA_EAC3)) || (bAudioADTS && (nType == BDA_ADTS)) || (bAudioLATM && (nType == BDA_LATM))) { - if (!Stream.GetFindExisting() || - (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { - CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); - } - if (m_nCurAudioType == nType) { - CheckNoLog(Connect(pPin, nullptr, true)); - Stream.SetPin(pPin); - LOG(_T("Graph completed for stream type %d."), nType); - } else { - CheckNoLog(Connect(pPin, nullptr, false)); - Stream.SetPin(pPin); - LOG(_T("Filter connected to Demux for media type %d."), nType); - } - } - break; - - case BDA_SUB: - if (!Stream.GetFindExisting() || - (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { - CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); - } - CheckNoLog(Connect(pPin, nullptr, false)); - CComPtr pPinTo; - pPin->ConnectedTo(&pPinTo); - CMainFrame* pMainFrame = dynamic_cast(AfxGetApp()->GetMainWnd()); - if (pMainFrame && SUCCEEDED(hr = pMainFrame->InsertTextPassThruFilter(pMpeg2Demux, pPin, pPinTo))) { - Stream.SetPin(pPin); - LOG(_T("Filter connected to Demux for media type %d."), nType); - } else { - LOG(_T("DVB_SUB Filter connection failed. Error 0x%08x."), hr); - } - break; - } - } - - LOG(_T("CreateMicrosoftDemux succeeded.\n")); - - return hr; -} - -HRESULT CFGManagerBDA::SetChannelInternal(CBDAChannel* pChannel) -{ - HRESULT hr = E_ABORT; - bool bRadioToTV = false; - const CAppSettings& s = AfxGetAppSettings(); - ClearMaps(); - - if (s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS && GetState() != State_Stopped) { - ChangeState(State_Stopped); - } - - if (pChannel->GetVideoPID() != 0) { - CComPtr pDemux; - m_pDemux->QueryInterface(IID_PPV_ARGS(&pDemux)); - - if (pChannel->GetVideoType() == BDA_H264) { - UpdateMediaType(&vih2_H264, pChannel); - hr = pDemux->SetOutputPinMediaType(const_cast(L"h264"), const_cast(&mt_H264)); - } else if (pChannel->GetVideoType() == BDA_HEVC) { - UpdateMediaType(&vih2_HEVC, pChannel); - hr = pDemux->SetOutputPinMediaType(const_cast(L"HEVC"), const_cast(&mt_HEVC)); - } else { - UpdateMediaType(&sMpv_fmt, pChannel); - hr = pDemux->SetOutputPinMediaType(const_cast(L"mpv"), const_cast(&mt_Mpv)); - } - if (m_nCurVideoType != pChannel->GetVideoType() || GetState() == State_Stopped) { - if (s.nDVBStopFilterGraph == DVB_STOP_FG_WHEN_SWITCHING && GetState() != State_Stopped) { - ChangeState(State_Stopped); - } - if (FAILED(hr = SwitchStream(m_nCurVideoType, pChannel->GetVideoType()))) { - LOG(_T("Video switchStream failed. Result: 0x%08x"), hr); - return hr; - } - } - - if (m_fHideWindow) { - bRadioToTV = true; - } - } else { - m_fHideWindow = true; - } - - if (m_nCurAudioType != pChannel->GetDefaultAudioType()) { - if (FAILED(hr = SwitchStream(m_nCurAudioType, pChannel->GetDefaultAudioType()))) { - LOG(_T("Audio switchStream failed. Result: 0x%08x"), hr); - return hr; - } - } - - if (GetState() == State_Stopped) { - CheckNoLog(ChangeState(State_Running)); - } - - CheckNoLog(SetFrequency(pChannel->GetFrequency(), pChannel->GetBandwidth(), pChannel->GetSymbolRate())); - - CheckNoLog(Flush(pChannel->GetVideoType(), pChannel->GetDefaultAudioType())); - - if (pChannel->GetVideoPID() != 0) { - CheckNoLog(m_DVBStreams[pChannel->GetVideoType()].Map(pChannel->GetVideoPID())); - } - - CheckNoLog(m_DVBStreams[pChannel->GetDefaultAudioType()].Map(pChannel->GetDefaultAudioPID())); - - if (pChannel->GetSubtitleCount() > 0 && pChannel->GetDefaultSubtitle() != -1 && pChannel->GetDefaultSubtitle() != pChannel->GetSubtitleCount()) { - CheckNoLog(m_DVBStreams[BDA_SUB].Map(pChannel->GetDefaultSubtitlePID())); - } - LOG(_T("Stream maps:")); - LOG(_T("Mapped PID MPEG-2: %u, Mapped PID H.264: %u, Mapped PID HEVC: %u."), - m_DVBStreams[BDA_MPV].GetMappedPID(), m_DVBStreams[BDA_H264].GetMappedPID(), m_DVBStreams[BDA_HEVC].GetMappedPID()); - LOG(_T("Mapped PID MPA: %u, Mapped PID AC3: %u, Mapped PID EAC3: %u, Mapped PID AAC-ADTS: %u, Mapped PID AAC-LATM: %u.") - , m_DVBStreams[BDA_MPA].GetMappedPID(), m_DVBStreams[BDA_AC3].GetMappedPID(), m_DVBStreams[BDA_EAC3].GetMappedPID(), m_DVBStreams[BDA_ADTS].GetMappedPID(), m_DVBStreams[BDA_LATM].GetMappedPID()); - LOG(_T("Mapped PID Subtitles: %u."), m_DVBStreams[BDA_SUB].GetMappedPID()); - - if (bRadioToTV) { - m_fHideWindow = false; - Sleep(1800); - } - - if (CMainFrame* pMainFrame = AfxGetMainFrame()) { - pMainFrame->HideVideoWindow(m_fHideWindow); - } - - return hr; -} - -HRESULT CFGManagerBDA::Flush(BDA_STREAM_TYPE nVideoType, BDA_STREAM_TYPE nAudioType) -{ - HRESULT hr = S_OK; - - CComPtr pFilterSub = m_DVBStreams[BDA_SUB].GetFilter(); - if (pFilterSub) { - CComPtr pSubPinIn = GetFirstPin(pFilterSub, PINDIR_INPUT); - hr = pSubPinIn->BeginFlush(); - hr = pSubPinIn->EndFlush(); - hr = pSubPinIn->NewSegment(0, MAXLONG, 1); - } - CComPtr pFilterAudio = m_DVBStreams[nAudioType].GetFilter(); - if (pFilterAudio) { - CComPtr pAudPinIn = GetFirstPin(pFilterAudio, PINDIR_INPUT); - hr = pAudPinIn->BeginFlush(); - hr = pAudPinIn->EndFlush(); - hr = pAudPinIn->NewSegment(0, MAXLONG, 1); - } - CComPtr pFilterVideo = m_DVBStreams[nVideoType].GetFilter(); - if (pFilterVideo) { - CComPtr pVidPinIn = GetFirstPin(pFilterVideo, PINDIR_INPUT); - hr = pVidPinIn->BeginFlush(); - hr = pVidPinIn->EndFlush(); - hr = pVidPinIn->NewSegment(0, MAXLONG, 1); - } - - return hr; -} - -HRESULT CFGManagerBDA::SwitchStream(BDA_STREAM_TYPE nOldType, BDA_STREAM_TYPE nNewType) -{ - HRESULT hr = S_OK; - CComPtr pFGOld = m_DVBStreams[nOldType].GetFilter(); - CComPtr pFGNew = m_DVBStreams[nNewType].GetFilter(); - CComPtr pOldOut = GetFirstPin(pFGOld, PINDIR_OUTPUT); - CComPtr pInPin; - if (pOldOut && pFGNew) { - pOldOut->ConnectedTo(&pInPin); - if (!pInPin) { - ASSERT(false); - return E_UNEXPECTED; - } - CComPtr pNewOut = GetFirstPin(pFGNew, PINDIR_OUTPUT); - CComPtr pNewOutDynamic; - - if (nNewType != BDA_MPV && nNewType != BDA_H264 && nNewType != BDA_HEVC && GetState() != State_Stopped) { - CComPtr pDemux; - m_pDemux->QueryInterface(IID_PPV_ARGS(&pDemux)); - - switch (nNewType) { - case BDA_MPA: - hr = pDemux->SetOutputPinMediaType(const_cast(L"mpa"), const_cast(&mt_Mpa)); - break; - case BDA_AC3: - hr = pDemux->SetOutputPinMediaType(const_cast(L"ac3"), const_cast(&mt_Ac3)); - break; - case BDA_EAC3: - hr = pDemux->SetOutputPinMediaType(const_cast(L"eac3"), const_cast(&mt_Eac3)); - break; - case BDA_ADTS: - hr = pDemux->SetOutputPinMediaType(const_cast(L"adts"), const_cast(&mt_latm)); - break; - case BDA_LATM: - hr = pDemux->SetOutputPinMediaType(const_cast(L"latm"), const_cast(&mt_latm)); - break; - } - } - - CComPtr pOldOutDynamic; - pOldOut->QueryInterface(IID_PPV_ARGS(&pOldOutDynamic)); - CComPtr pInPinDynamic; - pInPin->QueryInterface(IID_PPV_ARGS(&pInPinDynamic)); - CComPtr pOldOutControl; - if ((GetState() != State_Stopped) && pInPinDynamic && pOldOutDynamic) { // Try dynamic switch - pOldOut->QueryInterface(IID_PPV_ARGS(&pOldOutControl)); - pOldOutControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, nullptr); - CComPtr pGraph; - QueryInterface(IID_PPV_ARGS(&pGraph)); - hr = pGraph->Reconnect(pNewOut, pInPin, nullptr, nullptr, nullptr, AM_GRAPH_CONFIG_RECONNECT_DIRECTCONNECT); - pOldOutControl->Block(0, nullptr); - } else { // Dynamic pins not supported - LOG(_T("Dynamic pin interface not supported.")); - hr = Disconnect(pOldOut); - if (FAILED(hr) && (GetState() != State_Stopped)) { - ChangeState(State_Stopped); - hr = Disconnect(pOldOut); - } - if (SUCCEEDED(hr)) { - hr = Disconnect(pInPin); - if (FAILED(hr) && (GetState() != State_Stopped)) { - ChangeState(State_Stopped); - hr = Disconnect(pInPin); - } - } - if (SUCCEEDED(hr)) { - hr = ConnectDirect(pNewOut, pInPin, nullptr); - if (FAILED(hr) && (GetState() != State_Stopped)) { - ChangeState(State_Stopped); - hr = ConnectDirect(pNewOut, pInPin, nullptr); - } - if (FAILED(hr)) { - hr = E_UNEXPECTED; - } - } - } - } else { - hr = E_POINTER; - ASSERT(FALSE); - } - - LOG(_T("SwitchStream - Stream type: %d. Result: 0x%08x"), nNewType, hr); - - return hr; -} - -void CFGManagerBDA::UpdateMediaType(VIDEOINFOHEADER2* NewVideoHeader, CBDAChannel* pChannel) -{ - NewVideoHeader->AvgTimePerFrame = pChannel->GetAvgTimePerFrame(); - if ((pChannel->GetVideoFps() == BDA_FPS_25_0) || - (pChannel->GetVideoFps() == BDA_FPS_29_97) || - (pChannel->GetVideoFps() == BDA_FPS_30_0)) { - NewVideoHeader->dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_DisplayModeBobOrWeave; - } else { - NewVideoHeader->dwInterlaceFlags = 0; - } - if ((pChannel->GetVideoARx() != 0) && (pChannel->GetVideoARy() != 0)) { - NewVideoHeader->dwPictAspectRatioX = pChannel->GetVideoARx(); - NewVideoHeader->dwPictAspectRatioY = pChannel->GetVideoARy(); - } else { - NewVideoHeader->dwPictAspectRatioX = 16; - NewVideoHeader->dwPictAspectRatioY = 9; - } - - if (pChannel->GetVideoHeight()) { - NewVideoHeader->bmiHeader.biHeight = pChannel->GetVideoHeight(); - NewVideoHeader->bmiHeader.biWidth = pChannel->GetVideoWidth(); - } else { - NewVideoHeader->bmiHeader.biHeight = 576; - NewVideoHeader->bmiHeader.biWidth = 720; - } - - if (NewVideoHeader->dwPictAspectRatioX && NewVideoHeader->dwPictAspectRatioY) { - NewVideoHeader->bmiHeader.biWidth = (LONG)(NewVideoHeader->bmiHeader.biHeight * NewVideoHeader->dwPictAspectRatioX / NewVideoHeader->dwPictAspectRatioY); - } - - NewVideoHeader->rcSource.top = 0; - NewVideoHeader->rcSource.left = 0; - NewVideoHeader->rcSource.right = NewVideoHeader->bmiHeader.biWidth; - NewVideoHeader->rcSource.bottom = NewVideoHeader->bmiHeader.biHeight; - NewVideoHeader->rcTarget.top = 0; - NewVideoHeader->rcTarget.left = 0; - NewVideoHeader->rcTarget.right = 0; - NewVideoHeader->rcTarget.bottom = 0; -} - -HRESULT CFGManagerBDA::UpdatePSI(const CBDAChannel* pChannel, EventDescriptor& NowNext) -{ - HRESULT hr = S_FALSE; - CMpeg2DataParser Parser(m_DVBStreams[BDA_PSI].GetFilter()); - - if (pChannel->GetNowNextFlag()) { - hr = Parser.ParseEIT(pChannel->GetSID(), NowNext); - } - - return hr; -} - -HRESULT CFGManagerBDA::ChangeState(FILTER_STATE nRequested) -{ - HRESULT hr = S_OK; - OAFilterState nState = nRequested + 1; - - CComPtr pMC; - QueryInterface(IID_PPV_ARGS(&pMC)); - pMC->GetState(500, &nState); - if (nState != nRequested) { - CMainFrame* pMainFrame = AfxGetMainFrame(); - switch (nRequested) { - case State_Stopped: { - if (pMainFrame) { - pMainFrame->KillTimersStop(); - } - hr = pMC->Stop(); - LOG(_T("IMediaControl stop: 0x%08x."), hr); - return hr; - } - case State_Paused: { - LOG(_T("IMediaControl pause.")); - return pMC->Pause(); - } - case State_Running: { - if (SUCCEEDED(hr = pMC->Run()) && SUCCEEDED(hr = pMC->GetState(500, &nState)) && nState == State_Running && pMainFrame) { - pMainFrame->SetTimersPlay(); - } - LOG(_T("IMediaControl play: 0x%08x."), hr); - return hr; - } - } - } - return hr; -} - -FILTER_STATE CFGManagerBDA::GetState() -{ - CComPtr pMC; - OAFilterState nState; - QueryInterface(IID_PPV_ARGS(&pMC)); - pMC->GetState(500, &nState); - - return (FILTER_STATE) nState; -} +/* + * (C) 2009-2017 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 . + * + */ + +#include "stdafx.h" +#include "FGManagerBDA.h" +#include "Mpeg2SectionData.h" +#include "MainFrm.h" +#include "Logger.h" +#include +#include +#include +#include +#include +#include + +#define LOG(...) MPCHC_LOG(BDA, __VA_ARGS__) +#define CheckAndLogBDA(x, msg) hr = ##x; if (FAILED(hr)) { LOG(msg _T(": 0x%08x\n"), hr); return hr; } +#define CheckAndLogBDANoRet(x, msg) hr = ##x; if (FAILED(hr)) { LOG(msg _T(": 0x%08x\n"), hr); } + +/// Format, Video MPEG2 +static VIDEOINFOHEADER2 sMpv_fmt = { + {0, 0, 720, 576}, // rcSource + {0, 0, 0, 0}, // rcTarget + 0, // dwBitRate + 0, // dwBitErrorRate + 400000, // AvgTimePerFrame + 0, // dwInterlaceFlags + 0, // dwCopyProtectFlags + 0, // dwPictAspectRatioX + 0, // dwPictAspectRatioY + {0}, // dwControlFlag & dwReserved1 + 0, // dwReserved2 + { + // bmiHeader + sizeof(BITMAPINFOHEADER), // biSize + 720, // biWidth + 576, // biHeight + 0, // biPlanes + 0, // biBitCount + 0 // biCompression + } + // implicitly sets the others fields to 0 +}; + +/// Media type, Video MPEG2 +static const AM_MEDIA_TYPE mt_Mpv = { + MEDIATYPE_Video, // majortype + MEDIASUBTYPE_MPEG2_VIDEO, // subtype + FALSE, // bFixedSizeSamples + TRUE, // bTemporalCompression + 0, // lSampleSize + FORMAT_VideoInfo2, // formattype + nullptr, // pUnk + sizeof(sMpv_fmt), // cbFormat + (LPBYTE)& sMpv_fmt // pbFormat +}; + +/// Format, Video H264 +static VIDEOINFOHEADER2 vih2_H264 = { + {0, 0, 0, 0}, // rcSource + {0, 0, 0, 0}, // rcTarget + 0, // dwBitRate, + 0, // dwBitErrorRate + 0, // AvgTimePerFrame + 0, // dwInterlaceFlags + 0, // dwCopyProtectFlags + 0, // dwPictAspectRatioX + 0, // dwPictAspectRatioY + {0}, // dwControlFlag & dwReserved1 + 0, // dwReserved2 + { + // bmiHeader + sizeof(BITMAPINFOHEADER), // biSize + 720, // biWidth + 576, // biHeight + 1, // biPlanes + 0, // biBitCount + MAKEFOURCC('h', '2', '6', '4') // biCompression + } + // implicitly sets the others fields to 0 +}; + +/// Media type, Video H264 +static const AM_MEDIA_TYPE mt_H264 = { + MEDIATYPE_Video, // majortype + MEDIASUBTYPE_H264, // subtype + FALSE, // bFixedSizeSamples + TRUE, // bTemporalCompression + 0, // lSampleSize + FORMAT_VideoInfo2, // formattype + nullptr, // pUnk + sizeof(vih2_H264), // cbFormat + (LPBYTE)& vih2_H264 // pbFormat +}; + +/// Format, Video HEVC +static VIDEOINFOHEADER2 vih2_HEVC = { + {0, 0, 0, 0}, // rcSource + {0, 0, 0, 0}, // rcTarget + 0, // dwBitRate, + 0, // dwBitErrorRate + 0, // AvgTimePerFrame + 0, // dwInterlaceFlags + 0, // dwCopyProtectFlags + 0, // dwPictAspectRatioX + 0, // dwPictAspectRatioY + {0}, // dwControlFlag & dwReserved1 + 0, // dwReserved2 + { + // bmiHeader + sizeof(BITMAPINFOHEADER), // biSize + 720, // biWidth + 576, // biHeight + 1, // biPlanes + 0, // biBitCount + MAKEFOURCC('H', 'E', 'V', 'C') // biCompression + } + // implicitly sets the others fields to 0 +}; + +/// Media type, Video HEVC +static const AM_MEDIA_TYPE mt_HEVC = { + MEDIATYPE_Video, // majortype + MEDIASUBTYPE_HEVC, // subtype + FALSE, // bFixedSizeSamples + TRUE, // bTemporalCompression + 0, // lSampleSize + FORMAT_VideoInfo2, // formattype + nullptr, // pUnk + sizeof(vih2_HEVC), // cbFormat + (LPBYTE)& vih2_HEVC // pbFormat +}; + +// Format, Audio MPEG2 +static BYTE MPEG2AudioFormat[] = { + 0x50, 0x00, //wFormatTag + 0x02, 0x00, //nChannels + 0x80, 0xbb, 0x00, 0x00, //nSamplesPerSec + 0x00, 0x7d, 0x00, 0x00, //nAvgBytesPerSec + 0x01, 0x00, //nBlockAlign + 0x00, 0x00, //wBitsPerSample + 0x16, 0x00, //cbSize + 0x02, 0x00, //wValidBitsPerSample + 0x00, 0xe8, //wSamplesPerBlock + 0x03, 0x00, //wReserved + 0x01, 0x00, 0x01, 0x00, //dwChannelMask + 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Format, Audio (E)AC3 +static BYTE AC3AudioFormat[] = { + 0x00, 0x20, //wFormatTag + 0x06, 0x00, //nChannels + 0x80, 0xBB, 0x00, 0x00, //nSamplesPerSec + 0xC0, 0x5D, 0x00, 0x00, //nAvgBytesPerSec + 0x00, 0x03, //nBlockAlign + 0x00, 0x00, //wBitsPerSample + 0x00, 0x00 //cbSize +}; + +// Format, Audio AAC +static BYTE AACAudioFormat[] = { + 0xFF, 0x00, //wFormatTag + 0x02, 0x00, //nChannels + 0x80, 0xBB, 0x00, 0x00, //nSamplesPerSec + 0xCE, 0x3E, 0x00, 0x00, //nAvgBytesPerSec + 0xAE, 0x02, //nBlockAlign + 0x00, 0x00, //wBitsPerSample + 0x02, 0x00, //cbSize + 0x11, 0x90 +}; + +/// Media type, Audio MPEG2 +static const AM_MEDIA_TYPE mt_Mpa = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_MPEG2_AUDIO, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(MPEG2AudioFormat), // cbFormat + MPEG2AudioFormat // pbFormat +}; + +/// Media type, Audio AC3 +static const AM_MEDIA_TYPE mt_Ac3 = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_DOLBY_AC3, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(AC3AudioFormat), // cbFormat + AC3AudioFormat, // pbFormat +}; + +/// Media type, Audio EAC3 +static const AM_MEDIA_TYPE mt_Eac3 = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_DOLBY_DDPLUS, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(AC3AudioFormat), // cbFormat + AC3AudioFormat, // pbFormat +}; + +/// Media type, Audio AAC ADTS +static const AM_MEDIA_TYPE mt_adts = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_MPEG_ADTS_AAC, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(AACAudioFormat), // cbFormat + AACAudioFormat, // pbFormat +}; + +/// Media type, Audio AAC LATM +static const AM_MEDIA_TYPE mt_latm = { + MEDIATYPE_Audio, // majortype + MEDIASUBTYPE_LATM_AAC, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_WaveFormatEx, // formattype + nullptr, // pUnk + sizeof(AACAudioFormat), // cbFormat + AACAudioFormat, // pbFormat +}; + +/// Media type, PSI +static const AM_MEDIA_TYPE mt_Psi = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_MPEG2DATA, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr // pbFormat +}; + +/// Media type, TIF +static const AM_MEDIA_TYPE mt_DVB_Tif = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_DVB_SI, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr // pbFormat +}; + +/// Media type, EPG +static const AM_MEDIA_TYPE mt_DVB_Epg = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_DVB_SI, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr, // pbFormat +}; + +/// Media type, TIF +static const AM_MEDIA_TYPE mt_ATSC_Tif = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_ATSC_SI, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr // pbFormat +}; + +/// Media type, EPG +static const AM_MEDIA_TYPE mt_ATSC_Epg = { + MEDIATYPE_MPEG2_SECTIONS, // majortype + MEDIASUBTYPE_ATSC_SI, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + 0, // cbFormat + nullptr, // pbFormat +}; + +static const SUBTITLEINFO SubFormat = { 0, "", L"" }; + +/// Media type, subtitle +static const AM_MEDIA_TYPE mt_Subtitle = { + MEDIATYPE_Subtitle, // majortype + MEDIASUBTYPE_DVB_SUBTITLES, // subtype + FALSE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 0, // lSampleSize + FORMAT_None, // formattype + nullptr, // pUnk + sizeof(SubFormat), // cbFormat + (LPBYTE)& SubFormat // pbFormat +}; + +/// CLSID for TIF +// FC772AB0-0C7F-11D3-8FF2-00A0C9224CF4 +static const CLSID CLSID_BDA_MPEG2_TIF = +{0xFC772AB0, 0x0C7F, 0x11D3, {0x8F, 0xF2, 0x00, 0xA0, 0xC9, 0x22, 0x4C, 0xF4}}; + +CFGManagerBDA::CFGManagerBDA(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd) + : CFGManagerPlayer(pName, pUnk, hWnd) +{ + LOG(_T("---------------------------------------------------------------->")); + LOG(_T("Starting session...")); + + CAppSettings& s = AfxGetAppSettings(); + m_nDVBRebuildFilterGraph = s.nDVBRebuildFilterGraph; + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + + if (pChannel) { + if (pChannel->GetVideoType() == BDA_H264) { + UpdateMediaType(&vih2_H264, pChannel); + } else if (pChannel->GetVideoType() == BDA_HEVC) { + UpdateMediaType(&vih2_HEVC, pChannel); + } else if (pChannel->GetVideoType() == BDA_MPV) { + UpdateMediaType(&sMpv_fmt, pChannel); + } + } + + tunerIsATSC = false; + BeginEnumSysDev(KSCATEGORY_BDA_NETWORK_TUNER, pMoniker) { + CComHeapPtr strName; + if (SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName)) ) { + if (s.strBDATuner == CString(strName)) { + CComPtr pPB; + pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)); + CComVariant var; + if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + CString fName = CString(var.bstrVal); + if (fName.Find(_T("ATSC")) > -1) { //hack to identify an ATSC tuner. better solution might be to check the tuner capabilities, but this should be good enough + tunerIsATSC = true; + } + } + } + } + } + EndEnumSysDev; + + m_DVBStreams[BDA_MPV] = CDVBStream(L"mpv", &mt_Mpv); + m_DVBStreams[BDA_H264] = CDVBStream(L"h264", &mt_H264); + m_DVBStreams[BDA_HEVC] = CDVBStream(L"HEVC", &mt_HEVC); + m_DVBStreams[BDA_MPA] = CDVBStream(L"mpa", &mt_Mpa); + m_DVBStreams[BDA_AC3] = CDVBStream(L"ac3", &mt_Ac3); + m_DVBStreams[BDA_EAC3] = CDVBStream(L"eac3", &mt_Eac3); + m_DVBStreams[BDA_ADTS] = CDVBStream(L"adts", &mt_adts); + m_DVBStreams[BDA_LATM] = CDVBStream(L"latm", &mt_latm); + m_DVBStreams[BDA_PSI] = CDVBStream(L"psi", &mt_Psi, true, MEDIA_MPEG2_PSI); + if (tunerIsATSC) { + m_DVBStreams[BDA_TIF] = CDVBStream(L"tif", &mt_ATSC_Tif, true); + m_DVBStreams[BDA_EPG] = CDVBStream(L"epg", &mt_ATSC_Epg); + } else { + m_DVBStreams[BDA_TIF] = CDVBStream(L"tif", &mt_DVB_Tif, true); + m_DVBStreams[BDA_EPG] = CDVBStream(L"epg", &mt_DVB_Epg); + } + m_DVBStreams[BDA_SUB] = CDVBStream(L"sub", &mt_Subtitle/*, false, MEDIA_TRANSPORT_PAYLOAD*/); + + if (pChannel) { + m_nCurVideoType = pChannel->GetVideoType(); + m_nCurAudioType = pChannel->GetDefaultAudioType(); + } else { + m_nCurVideoType = BDA_MPV; + m_nCurAudioType = BDA_MPA; + } + m_fHideWindow = false; + + // Blacklist some unsupported filters (AddHead must be used to ensure higher priority): + // - audio switcher + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(__uuidof(CAudioSwitcherFilter), MERIT64_DO_NOT_USE)); + // - internal video decoder and ffdshow DXVA video decoder (cf ticket #730) + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_MPCVideoDecoder, MERIT64_DO_NOT_USE)); + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_FFDShowDXVADecoder, MERIT64_DO_NOT_USE)); + // - Microsoft DTV-DVD Audio Decoder + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_MSDVTDVDAudioDecoder, MERIT64_DO_NOT_USE)); + // - ACM Wrapper + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_ACMWrapper, MERIT64_DO_NOT_USE)); + // - ReClock + m_transform.AddHead(DEBUG_NEW CFGFilterRegistry(CLSID_ReClock, MERIT64_DO_NOT_USE)); + + LOG(_T("CFGManagerBDA object created.")); +} + +CFGManagerBDA::~CFGManagerBDA() +{ + m_DVBStreams.RemoveAll(); + LOG(_T("CFGManagerBDA object destroyed.")); + LOG(_T("<----------------------------------------------------------------\n\n")); +} + +HRESULT CFGManagerBDA::CreateKSFilterFN(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& FriendlyName) { + HRESULT hr = VFW_E_NOT_FOUND; + BeginEnumSysDev(KSCategory, pMoniker) { + CComPtr pPB; + CComVariant var; + if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB))) && SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + CStringW fName = CStringW(var.bstrVal); + if (fName != FriendlyName) { + continue; + } + + hr = pMoniker->BindToObject(nullptr, nullptr, IID_PPV_ARGS(ppBF)); + if (SUCCEEDED(hr)) { + hr = AddFilter(*ppBF, fName); + } + break; + } + } + EndEnumSysDev; + + return hr; +} + + +HRESULT CFGManagerBDA::CreateKSFilter(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& DisplayName) +{ + HRESULT hr = VFW_E_NOT_FOUND; + BeginEnumSysDev(KSCategory, pMoniker) { + CComPtr pPB; + CComVariant var; + CComHeapPtr strName; + if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB))) && + SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName)) && + SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + CStringW Name = strName; + if (Name != DisplayName) { + continue; + } + + hr = pMoniker->BindToObject(nullptr, nullptr, IID_PPV_ARGS(ppBF)); + if (SUCCEEDED(hr)) { + hr = AddFilter(*ppBF, CStringW(var.bstrVal)); + } + break; + } + } + EndEnumSysDev; + + return hr; +} + +HRESULT CFGManagerBDA::SearchIBDATopology(const CComPtr& pTuner, REFIID iid, CComPtr& pUnk) +{ + CComQIPtr pTop(pTuner); + CheckPointer(pTop, E_NOINTERFACE); + + ULONG NodeTypes = 0; + ULONG NodeType[32]; + + HRESULT hr = pTop->GetNodeTypes(&NodeTypes, _countof(NodeType), NodeType); + + if (FAILED(hr)) { + return hr; + } + + for (ULONG i = 0; i < NodeTypes; i++) { + ULONG nInterfaces; + GUID aInterface[32]; + + hr = pTop->GetNodeInterfaces(NodeType[i], &nInterfaces, _countof(aInterface), aInterface); + + if (FAILED(hr)) { + continue; + } + + for (ULONG j = 0; j < nInterfaces; j++) { + if (aInterface[j] == iid) { + return pTop->GetControlNode(0, 1, NodeType[i], &pUnk); + } + } + } + + return FAILED(hr) ? hr : E_NOINTERFACE; +} + +HRESULT CFGManagerBDA::ConnectFilters(IBaseFilter* pOutFilter, IBaseFilter* pInFilter) +{ + HRESULT hr = VFW_E_CANNOT_CONNECT; + BeginEnumPins(pOutFilter, pEP, pOutPin) { + if (S_OK == IsPinDirection(pOutPin, PINDIR_OUTPUT) + && S_OK != IsPinConnected(pOutPin)) { + BeginEnumPins(pInFilter, pEP2, pInPin) { + if (S_OK == IsPinDirection(pInPin, PINDIR_INPUT) + && S_OK != IsPinConnected(pInPin)) { + hr = this->ConnectDirect(pOutPin, pInPin, nullptr); + +#if 0 && defined(_DEBUG) // Disabled by default because it can be verbose + CPinInfo infoPinIn, infoPinOut; + infoPinIn.achName[0] = infoPinOut.achName[0] = L'\0'; + CFilterInfo infoFilterIn, infoFilterOut; + infoFilterIn.achName[0] = infoFilterOut.achName[0] = L'\0'; + + pInPin->QueryPinInfo(&infoPinIn); + if (infoPinIn.pFilter) { + infoPinIn.pFilter->QueryFilterInfo(&infoFilterIn); + } + pOutPin->QueryPinInfo(&infoPinOut); + if (infoPinOut.pFilter) { + infoPinOut.pFilter->QueryFilterInfo(&infoFilterOut); + } + + TRACE(_T("%s - %s => %s - %s (hr=0x%08x)\n"), infoFilterOut.achName, infoPinOut.achName, infoFilterIn.achName, infoPinIn.achName, hr); +#endif + + if (SUCCEEDED(hr)) { + return hr; + } + } + } + EndEnumPins; + } + } + EndEnumPins; + + return hr; +} + +STDMETHODIMP CFGManagerBDA::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList) +{ + HRESULT hr; + const CAppSettings& s = AfxGetAppSettings(); + CComPtr pNetwork; + CComPtr pTuner; + CComPtr pReceiver; + + LOG(_T("Creating BDA filters...")); + CheckAndLogBDA(CreateKSFilterFN(&pNetwork, KSCATEGORY_BDA_NETWORK_PROVIDER, _T("Microsoft Network Provider")), _T("Network provider creation")); + if (FAILED(hr = CreateKSFilter(&pTuner, KSCATEGORY_BDA_NETWORK_TUNER, s.strBDATuner))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CREATE_TUNER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Network tuner creation: 0x%08x\n"), hr); + LOG(_T("Network tuner creation: 0x%08x"), hr); + return hr; + } + + if (FAILED(hr = ConnectFilters(pNetwork, pTuner))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CONNECT_TUNER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Network <-> Tuner: 0x%08x\n"), hr); + LOG(_T("Network <-> Tuner: 0x%08x"), hr); + return hr; + } + m_pBDAControl = pTuner; + + if (FAILED(hr = SearchIBDATopology(pTuner, m_pBDAFreq))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, _T("IBDA_FrequencyFilter topology failed."), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + LOG(_T("IBDA_FrequencyFilter topology failed.")); + return hr; + } + m_pBDATunerStats = m_pBDAFreq; + if (FAILED(hr = SearchIBDATopology(pTuner, m_pBDADemodulator))) { + TRACE(_T("BDA: IBDA_DigitalDemodulator topology failed: 0x%08x\n"), hr); + LOG(_T("IBDA_DigitalDemodulator topology failed. Result 0x%08x"), hr); + } + m_pBDADemodStats = m_pBDADemodulator; + + if (!m_pBDATunerStats || !m_pBDADemodStats) { + if (m_pBDATunerStats) { + TRACE(_T("BDA: no statistics interface on the demodulator node --> using the statistics from the RF node only\n")); + LOG(_T("No statistics interface on the demodulator node --> using the statistics from the RF node only.")); + m_pBDADemodStats = m_pBDATunerStats; + } else if (m_pBDADemodStats) { + TRACE(_T("BDA: no statistics interface on the RF node --> using the statistics from the demodulator node only\n")); + LOG(_T("No statistics interface on the RF node --> using the statistics from the demodulator node only.")); + m_pBDATunerStats = m_pBDADemodStats; + } else { // if (!m_pBDATunerStats && !m_pBDADemodStats) + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, _T("No statistics interface available."), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Not statistics interface available\n")); + LOG(_T("Not statistics interface available.")); + return E_NOINTERFACE; + } + } + + if (SUCCEEDED(hr = SearchIBDATopology(pTuner, m_pBDAAutoDemulate))) { + if (SUCCEEDED(hr = m_pBDAAutoDemulate->put_AutoDemodulate())) { + LOG(_T("Auto Demulate is on.")); + } else { + LOG(_T("Auto Demulate could not be switched: 0x%08x."), hr); + } + } else { + LOG(_T("AutoDemulate topology not found.")); + TRACE(_T("BDA: AutoDemulate topology not found: 0x%08x\n"), hr); + } + + if (FAILED(hr = m_pDemux.CoCreateInstance(CLSID_MPEG2Demultiplexer, nullptr, CLSCTX_INPROC_SERVER))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_DEMULTIPLEXER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Microsoft demux creation: 0x%08x\n"), hr); + return hr; + } + CheckNoLog(AddFilter(m_pDemux, _T("MPEG-2 Demultiplexer"))); + if (FAILED(ConnectFilters(pTuner, m_pDemux))) { // Separate receiver is required + if (FAILED(hr = CreateKSFilter(&pReceiver, KSCATEGORY_BDA_RECEIVER_COMPONENT, s.strBDAReceiver))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CREATE_RECEIVER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Receiver creation: 0x%08x\n"), hr); + return hr; + } + if (FAILED(hr = ConnectFilters(pTuner, pReceiver))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_CONNECT_TUNER_REC), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Tuner <-> Receiver: 0x%08x\n"), hr); + return hr; + } + if (FAILED(ConnectFilters(pReceiver, m_pDemux))) { + MessageBox(AfxGetMyApp()->GetMainWnd()->m_hWnd, ResStr(IDS_BDA_ERROR_DEMULTIPLEXER), ResStr(IDS_BDA_ERROR), MB_ICONERROR | MB_OK); + TRACE(_T("BDA: Receiver <-> Demux: 0x%08x\n"), hr); + return hr; + } + LOG(_T("Network -> Tuner -> Receiver connected.")); + + } else { // The selected filter is performing both tuner and receiver functions + LOG(_T("Network -> Receiver connected.")); + } + + CheckNoLog(CreateMicrosoftDemux(m_pDemux)); + +#ifdef _DEBUG + LOG(_T("Filter list:")); + BeginEnumFilters(this, pEF, pBF) { + LOG(_T(" ") + GetFilterName(pBF)); + } + EndEnumFilters; + LOG(_T("Filter list end.\n")); +#endif + + return hr; +} + +STDMETHODIMP CFGManagerBDA::ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt) +{ + // Bypass CFGManagerPlayer limitation (IMediaSeeking for Mpeg2 demux) + return CFGManagerCustom::ConnectDirect(pPinOut, pPinIn, pmt); +} + +STDMETHODIMP CFGManagerBDA::SetChannel(int nChannelPrefNumber) +{ + HRESULT hr = E_INVALIDARG; + CAppSettings& s = AfxGetAppSettings(); + + CBDAChannel* pChannel = s.FindChannelByPref(nChannelPrefNumber); + LOG(_T("Start SetChannel %d."), nChannelPrefNumber); + if (pChannel) { + if (!((m_nCurAudioType == BDA_UNKNOWN) ^ (pChannel->GetDefaultAudioType() == BDA_UNKNOWN)) && + ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_NEVER) || + ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_WHEN_SWITCHING) && (m_nCurVideoType == pChannel->GetVideoType())) || + ((m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_ALWAYS) && (s.nDVBLastChannel == nChannelPrefNumber)))) { + hr = SetChannelInternal(pChannel); + } else { + s.nDVBLastChannel = nChannelPrefNumber; + return S_FALSE; + } + + if (SUCCEEDED(hr)) { + s.nDVBLastChannel = nChannelPrefNumber; + m_nCurVideoType = pChannel->GetVideoType(); + m_nCurAudioType = pChannel->GetDefaultAudioType(); + LOG(_T("SetChannel %d successful.\n"), nChannelPrefNumber); + } else { + LOG(_T("SetChannel %d failed. Result: 0x%08x.\n"), nChannelPrefNumber, hr); + } + } + return hr; +} + +STDMETHODIMP CFGManagerBDA::SetAudio(int nAudioIndex) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CFGManagerBDA::SetFrequency(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) +{ + HRESULT hr; + LOG(_T("Frequency %lu, Bandwidth %lu, SymbolRate %lu"), ulFrequency, ulBandwidth, ulSymbolRate); + CheckPointer(m_pBDAControl, E_FAIL); + CheckPointer(m_pBDAFreq, E_FAIL); + + CheckAndLogBDA(m_pBDAControl->StartChanges(), _T(" SetFrequency StartChanges")); + if (ulSymbolRate != 0) { + CheckAndLogBDANoRet(m_pBDADemodulator->put_SymbolRate(&ulSymbolRate), _T(" SetFrequency put_SymbolRate")); + } + CheckAndLogBDANoRet(m_pBDAFreq->put_FrequencyMultiplier(1000), _T(" SetFrequency put_FrequencyMultiplier")); + CheckAndLogBDANoRet(m_pBDAFreq->put_Bandwidth(ulBandwidth / 1000), _T(" SetFrequency put_Bandwidth")); + CheckAndLogBDA(m_pBDAFreq->put_Frequency(ulFrequency), _T(" SetFrequency put_Frequency")); + CheckAndLogBDA(m_pBDAControl->CheckChanges(), _T(" SetFrequency CheckChanges")); + CheckAndLogBDA(m_pBDAControl->CommitChanges(), _T(" SetFrequency CommitChanges")); + + int i = 50; + ULONG pState = BDA_CHANGES_PENDING; + while (SUCCEEDED(hr = m_pBDAControl->GetChangeState(&pState)) && pState == BDA_CHANGES_PENDING && i-- > 0) { + LOG(_T("changes pending, waiting for tuner...")); + Sleep(50); + } + + if (SUCCEEDED(hr)) { + if (pState == BDA_CHANGES_PENDING) { + LOG(_T("changes pending (timeout error----)")); + hr = VFW_E_TIMEOUT; + } else { + LOG(_T("Frequency changed: %lu / %lu."), ulFrequency, ulBandwidth); +#ifdef _DEBUG + BOOLEAN bPresent; + BOOLEAN bLocked; + LONG lDbStrength; + LONG lPercentQuality; + + if (SUCCEEDED(GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { + LOG(_T("Signal stats: Strength %ld dB, Quality %ld%%"), lDbStrength, lPercentQuality); + } +#endif + } + } else { + LOG(_T("Frequency change failed. Result: 0x%08x."), hr); + } + + return hr; +} + +HRESULT CFGManagerBDA::ClearMaps() +{ + HRESULT hr = S_OK; + + if (m_DVBStreams[BDA_MPV].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_MPV].Unmap(m_DVBStreams[BDA_MPV].GetMappedPID())); + } + if (m_DVBStreams[BDA_H264].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_H264].Unmap(m_DVBStreams[BDA_H264].GetMappedPID())); + } + if (m_DVBStreams[BDA_HEVC].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_HEVC].Unmap(m_DVBStreams[BDA_HEVC].GetMappedPID())); + } + if (m_DVBStreams[BDA_MPA].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_MPA].Unmap(m_DVBStreams[BDA_MPA].GetMappedPID())); + } + if (m_DVBStreams[BDA_AC3].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_AC3].Unmap(m_DVBStreams[BDA_AC3].GetMappedPID())); + } + if (m_DVBStreams[BDA_EAC3].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_EAC3].Unmap(m_DVBStreams[BDA_EAC3].GetMappedPID())); + } + if (m_DVBStreams[BDA_ADTS].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_ADTS].Unmap(m_DVBStreams[BDA_ADTS].GetMappedPID())); + } + if (m_DVBStreams[BDA_LATM].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_LATM].Unmap(m_DVBStreams[BDA_LATM].GetMappedPID())); + } + if (m_DVBStreams[BDA_SUB].GetMappedPID()) { + CheckNoLog(m_DVBStreams[BDA_SUB].Unmap(m_DVBStreams[BDA_SUB].GetMappedPID())); + } + + return hr; +} + +STDMETHODIMP CFGManagerBDA::Scan(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd) +{ + HRESULT hr = S_OK; + + if (ulFrequency == 0 || ulBandwidth == 0) { + ClearMaps(); + } else { + CMpeg2DataParser Parser(m_DVBStreams[BDA_PSI].GetFilter()); + + LOG(_T("Scanning frequency %u.........."), ulFrequency); + + if (tunerIsATSC) { + enum DVB_SI vctType; + if (FAILED(hr = Parser.ParseMGT(vctType)) || SI_undef == vctType) { //try to read MGT to determine type of ATSC + vctType = TID_CVCT; + } + hr = Parser.ParseVCT(ulFrequency, ulBandwidth, ulSymbolRate, vctType); //ATSC + LOG(L"ParseVCT failed. Result: 0x%08x.", hr); + } else { + hr = Parser.ParseSDT(ulFrequency, ulBandwidth, ulSymbolRate); //DVB + LOG(L"ParseSDT failed. Result: 0x%08x.", hr); + } + if (!FAILED(hr)) { + if (FAILED(hr = Parser.ParsePAT())) { + LOG(_T("ParsePAT failed. Result: 0x%08x."), hr); + } else if (FAILED(hr = Parser.ParseNIT())) { + LOG(_T("ParseNIT failed. Result: 0x%08x."), hr); + } + } + + POSITION pos = Parser.Channels.GetStartPosition(); + while (pos) { + CBDAChannel& Channel = Parser.Channels.GetNextValue(pos); + if (Channel.HasName()) { + ::SendMessage(hWnd, WM_TUNER_NEW_CHANNEL, 0, (LPARAM)(LPCTSTR)Channel.ToString()); + } + } + LOG(_T("Scanning frequency %u done."), ulFrequency); + } + + return hr; +} + +STDMETHODIMP CFGManagerBDA::GetStats(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality) +{ + HRESULT hr = S_OK; + CheckPointer(m_pBDATunerStats, E_UNEXPECTED); + CheckPointer(m_pBDADemodStats, E_UNEXPECTED); + + if (FAILED(hr = m_pBDATunerStats->get_SignalPresent(&bPresent)) && FAILED(hr = m_pBDADemodStats->get_SignalPresent(&bPresent))) { + return hr; + } + if (FAILED(hr = m_pBDADemodStats->get_SignalLocked(&bLocked)) && FAILED(hr = m_pBDATunerStats->get_SignalLocked(&bLocked))) { + return hr; + } + if (FAILED(hr = m_pBDATunerStats->get_SignalStrength(&lDbStrength)) && FAILED(hr = m_pBDADemodStats->get_SignalStrength(&lDbStrength))) { + return hr; + } + if (FAILED(hr = m_pBDADemodStats->get_SignalQuality(&lPercentQuality)) && FAILED(hr = m_pBDATunerStats->get_SignalQuality(&lPercentQuality))) { + return hr; + } + + return hr; +} + +// IAMStreamSelect +STDMETHODIMP CFGManagerBDA::Count(DWORD* pcStreams) +{ + CheckPointer(pcStreams, E_POINTER); + CAppSettings& s = AfxGetAppSettings(); + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + + *pcStreams = 0; + + if (pChannel) { + int Streams = pChannel->GetAudioCount() + pChannel->GetSubtitleCount(); + *pcStreams = pChannel->GetSubtitleCount() ? Streams + 1 : Streams; + } + + return S_OK; +} + +STDMETHODIMP CFGManagerBDA::Enable(long lIndex, DWORD dwFlags) +{ + HRESULT hr = E_INVALIDARG; + CAppSettings& s = AfxGetAppSettings(); + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + + if (pChannel) { + if (lIndex >= 0 && lIndex < pChannel->GetAudioCount()) { + BDAStreamInfo* pStreamInfo = pChannel->GetAudio(lIndex); + if (pStreamInfo) { + CDVBStream* pStream = &m_DVBStreams[pStreamInfo->nType]; + if (pStream) { + if (pStream->GetMappedPID()) { + pStream->Unmap(pStream->GetMappedPID()); + } + FILTER_STATE nState = GetState(); + if (m_nCurAudioType != pStreamInfo->nType) { + if ((s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS) && (GetState() != State_Stopped)) { + ChangeState(State_Stopped); + } + SwitchStream(m_nCurAudioType, pStreamInfo->nType); + m_nCurAudioType = pStreamInfo->nType; + CheckNoLog(Flush(m_nCurVideoType, m_nCurAudioType)); + } + pStream->Map(pStreamInfo->ulPID); + ChangeState((FILTER_STATE)nState); + + hr = S_OK; + } else { + ASSERT(FALSE); + } + } else { + ASSERT(FALSE); + } + } else if (lIndex > 0 && lIndex < pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { + BDAStreamInfo* pStreamInfo = pChannel->GetSubtitle(lIndex - pChannel->GetAudioCount()); + + if (pStreamInfo) { + m_DVBStreams[BDA_SUB].Map(pStreamInfo->ulPID); + hr = S_OK; + } + } else if (lIndex > 0 && m_DVBStreams[BDA_SUB].GetMappedPID() && lIndex == pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { + m_DVBStreams[BDA_SUB].Unmap(m_DVBStreams[BDA_SUB].GetMappedPID()); + hr = S_OK; + } + } else { + ASSERT(FALSE); + } + + return hr; +} + +STDMETHODIMP CFGManagerBDA::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) +{ + HRESULT hr = E_INVALIDARG; + CAppSettings& s = AfxGetAppSettings(); + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + BDAStreamInfo* pStreamInfo = nullptr; + CDVBStream* pStream = nullptr; + CDVBStream* pCurrentStream = nullptr; + + if (pChannel) { + if (lIndex >= 0 && lIndex < pChannel->GetAudioCount()) { + pCurrentStream = &m_DVBStreams[m_nCurAudioType]; + pStreamInfo = pChannel->GetAudio(lIndex); + if (pStreamInfo) { + pStream = &m_DVBStreams[pStreamInfo->nType]; + } + if (pdwGroup) { + *pdwGroup = 1; // Audio group + } + } else if (lIndex > 0 && lIndex < pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { + pCurrentStream = &m_DVBStreams[BDA_SUB]; + pStreamInfo = pChannel->GetSubtitle(lIndex - pChannel->GetAudioCount()); + if (pStreamInfo) { + pStream = &m_DVBStreams[pStreamInfo->nType]; + } + if (pdwGroup) { + *pdwGroup = 2; // Subtitle group + } + } else if (lIndex > 0 && lIndex == pChannel->GetAudioCount() + pChannel->GetSubtitleCount()) { + pCurrentStream = &m_DVBStreams[BDA_SUB]; + + if (pCurrentStream) { + if (pdwFlags) { + *pdwFlags = (!pCurrentStream->GetMappedPID()) ? AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE : 0; + } + if (plcid) { + *plcid = (LCID)LCID_NOSUBTITLES; + } + if (pdwGroup) { + *pdwGroup = 2; // Subtitle group + } + if (ppszName) { + CStringW str; + str = _T("No subtitles"); + + *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); + if (*ppszName == nullptr) { + return E_OUTOFMEMORY; + } + wcscpy_s(*ppszName, str.GetLength() + 1, str); + } + } + + return S_OK; + } + + if (pStreamInfo && pStream && pCurrentStream) { + if (ppmt) { + const AM_MEDIA_TYPE* pMT = pStream->GetMediaType(); + if (pMT) { + *ppmt = CreateMediaType(pMT); + } else { + *ppmt = nullptr; + return E_FAIL; + } + } + if (pdwFlags) { + *pdwFlags = (pCurrentStream->GetMappedPID() == pStreamInfo->ulPID) ? AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE : 0; + } + if (plcid) { + *plcid = pStreamInfo->GetLCID(); + } + if (ppObject) { + *ppObject = nullptr; + } + if (ppUnk) { + *ppUnk = nullptr; + } + if (ppszName) { + CStringW str; + + str = StreamTypeToName(pStreamInfo->nPesType); + + if (!pStreamInfo->sLanguage.IsEmpty() && pStreamInfo->GetLCID() == 0) { + // Try to convert language code even if LCID was not found. + str += _T(" [") + ISOLang::ISO6392ToLanguage(CStringA(pStreamInfo->sLanguage)) + _T("]"); + } + + *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); + if (*ppszName == nullptr) { + return E_OUTOFMEMORY; + } + wcscpy_s(*ppszName, str.GetLength() + 1, str); + } + + hr = S_OK; + } + } + + return hr; +} + +STDMETHODIMP CFGManagerBDA::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + QI(IBDATuner) + QI(IAMStreamSelect) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +HRESULT CFGManagerBDA::CreateMicrosoftDemux(CComPtr& pMpeg2Demux) +{ + CComPtr pDemux; + HRESULT hr; + bool bAudioMPA = false; + bool bAudioAC3 = false; + bool bAudioEAC3 = false; + bool bAudioADTS = false; + bool bAudioLATM = false; + + CheckNoLog(pMpeg2Demux->QueryInterface(IID_PPV_ARGS(&pDemux))); + + LOG(_T("Receiver -> Demux connected.")); + CAppSettings& s = AfxGetAppSettings(); + CBDAChannel* pChannel = s.FindChannelByPref(s.nDVBLastChannel); + if (pChannel && (m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_ALWAYS)) { + for (int i = 0; i < pChannel->GetAudioCount(); i++) { + switch ((pChannel->GetAudio(i))->nType) { + case BDA_MPA: + bAudioMPA = true; + break; + case BDA_AC3: + bAudioAC3 = true; + break; + case BDA_EAC3: + bAudioEAC3 = true; + break; + case BDA_ADTS: + bAudioADTS = true; + break; + case BDA_LATM: + bAudioLATM = true; + break; + } + } + } else { // All the possible audio filters will be present in the filter graph + bAudioMPA = true; + bAudioAC3 = true; + bAudioEAC3 = true; + bAudioADTS = true; + bAudioLATM = true; + } + + POSITION pos = m_DVBStreams.GetStartPosition(); + while (pos) { + CComPtr pPin; + BDA_STREAM_TYPE nType = m_DVBStreams.GetNextKey(pos); + CDVBStream& Stream = m_DVBStreams[nType]; + + switch (nType) { + case BDA_TIF: + case BDA_PSI: + if (!Stream.GetFindExisting() || + (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { + CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); + } + CheckNoLog(Connect(pPin, nullptr, false)); + Stream.SetPin(pPin); + LOG(_T("Filter connected to Demux for media type %d."), nType); + break; + + case BDA_MPV: + case BDA_H264: + case BDA_HEVC: + if ((nType == m_nCurVideoType) || (m_nDVBRebuildFilterGraph == DVB_REBUILD_FG_NEVER)) { + if (!Stream.GetFindExisting() || + (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { + CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); + } + if (m_nCurVideoType == nType) { + CheckNoLog(Connect(pPin, nullptr, true)); + Stream.SetPin(pPin); + LOG(_T("Graph completed for stream type %d."), nType); + } else { + CheckNoLog(Connect(pPin, nullptr, false)); + Stream.SetPin(pPin); + LOG(_T("Filter connected to Demux for media type %d."), nType); + } + } + break; + + case BDA_MPA: + case BDA_AC3: + case BDA_EAC3: + case BDA_ADTS: + case BDA_LATM: + if ((bAudioMPA && (nType == BDA_MPA)) || (bAudioAC3 && (nType == BDA_AC3)) || + (bAudioEAC3 && (nType == BDA_EAC3)) || (bAudioADTS && (nType == BDA_ADTS)) || (bAudioLATM && (nType == BDA_LATM))) { + if (!Stream.GetFindExisting() || + (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { + CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); + } + if (m_nCurAudioType == nType) { + CheckNoLog(Connect(pPin, nullptr, true)); + Stream.SetPin(pPin); + LOG(_T("Graph completed for stream type %d."), nType); + } else { + CheckNoLog(Connect(pPin, nullptr, false)); + Stream.SetPin(pPin); + LOG(_T("Filter connected to Demux for media type %d."), nType); + } + } + break; + + case BDA_SUB: + if (!Stream.GetFindExisting() || + (pPin = FindPin(pMpeg2Demux, PINDIR_OUTPUT, Stream.GetMediaType())) == nullptr) { + CheckNoLog(pDemux->CreateOutputPin(const_cast(Stream.GetMediaType()), const_cast(Stream.GetName()), &pPin)); + } + CheckNoLog(Connect(pPin, nullptr, false)); + CComPtr pPinTo; + pPin->ConnectedTo(&pPinTo); + CMainFrame* pMainFrame = dynamic_cast(AfxGetApp()->GetMainWnd()); + if (pMainFrame && SUCCEEDED(hr = pMainFrame->InsertTextPassThruFilter(pMpeg2Demux, pPin, pPinTo))) { + Stream.SetPin(pPin); + LOG(_T("Filter connected to Demux for media type %d."), nType); + } else { + LOG(_T("DVB_SUB Filter connection failed. Error 0x%08x."), hr); + } + break; + } + } + + LOG(_T("CreateMicrosoftDemux succeeded.\n")); + + return hr; +} + +HRESULT CFGManagerBDA::SetChannelInternal(CBDAChannel* pChannel) +{ + HRESULT hr = E_ABORT; + bool bRadioToTV = false; + const CAppSettings& s = AfxGetAppSettings(); + ClearMaps(); + + if (s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS && GetState() != State_Stopped) { + ChangeState(State_Stopped); + } + + if (pChannel->GetVideoPID() != 0) { + CComPtr pDemux; + m_pDemux->QueryInterface(IID_PPV_ARGS(&pDemux)); + + if (pChannel->GetVideoType() == BDA_H264) { + UpdateMediaType(&vih2_H264, pChannel); + hr = pDemux->SetOutputPinMediaType(const_cast(L"h264"), const_cast(&mt_H264)); + } else if (pChannel->GetVideoType() == BDA_HEVC) { + UpdateMediaType(&vih2_HEVC, pChannel); + hr = pDemux->SetOutputPinMediaType(const_cast(L"HEVC"), const_cast(&mt_HEVC)); + } else { + UpdateMediaType(&sMpv_fmt, pChannel); + hr = pDemux->SetOutputPinMediaType(const_cast(L"mpv"), const_cast(&mt_Mpv)); + } + if (m_nCurVideoType != pChannel->GetVideoType() || GetState() == State_Stopped) { + if (s.nDVBStopFilterGraph == DVB_STOP_FG_WHEN_SWITCHING && GetState() != State_Stopped) { + ChangeState(State_Stopped); + } + if (FAILED(hr = SwitchStream(m_nCurVideoType, pChannel->GetVideoType()))) { + LOG(_T("Video switchStream failed. Result: 0x%08x"), hr); + return hr; + } + } + + if (m_fHideWindow) { + bRadioToTV = true; + } + } else { + m_fHideWindow = true; + } + + if (m_nCurAudioType != pChannel->GetDefaultAudioType()) { + if (FAILED(hr = SwitchStream(m_nCurAudioType, pChannel->GetDefaultAudioType()))) { + LOG(_T("Audio switchStream failed. Result: 0x%08x"), hr); + return hr; + } + } + + if (GetState() == State_Stopped) { + CheckNoLog(ChangeState(State_Running)); + } + + CheckNoLog(SetFrequency(pChannel->GetFrequency(), pChannel->GetBandwidth(), pChannel->GetSymbolRate())); + + CheckNoLog(Flush(pChannel->GetVideoType(), pChannel->GetDefaultAudioType())); + + if (pChannel->GetVideoPID() != 0) { + CheckNoLog(m_DVBStreams[pChannel->GetVideoType()].Map(pChannel->GetVideoPID())); + } + + CheckNoLog(m_DVBStreams[pChannel->GetDefaultAudioType()].Map(pChannel->GetDefaultAudioPID())); + + if (pChannel->GetSubtitleCount() > 0 && pChannel->GetDefaultSubtitle() != -1 && pChannel->GetDefaultSubtitle() != pChannel->GetSubtitleCount()) { + CheckNoLog(m_DVBStreams[BDA_SUB].Map(pChannel->GetDefaultSubtitlePID())); + } + LOG(_T("Stream maps:")); + LOG(_T("Mapped PID MPEG-2: %u, Mapped PID H.264: %u, Mapped PID HEVC: %u."), + m_DVBStreams[BDA_MPV].GetMappedPID(), m_DVBStreams[BDA_H264].GetMappedPID(), m_DVBStreams[BDA_HEVC].GetMappedPID()); + LOG(_T("Mapped PID MPA: %u, Mapped PID AC3: %u, Mapped PID EAC3: %u, Mapped PID AAC-ADTS: %u, Mapped PID AAC-LATM: %u.") + , m_DVBStreams[BDA_MPA].GetMappedPID(), m_DVBStreams[BDA_AC3].GetMappedPID(), m_DVBStreams[BDA_EAC3].GetMappedPID(), m_DVBStreams[BDA_ADTS].GetMappedPID(), m_DVBStreams[BDA_LATM].GetMappedPID()); + LOG(_T("Mapped PID Subtitles: %u."), m_DVBStreams[BDA_SUB].GetMappedPID()); + + if (bRadioToTV) { + m_fHideWindow = false; + Sleep(1800); + } + + if (CMainFrame* pMainFrame = AfxGetMainFrame()) { + pMainFrame->HideVideoWindow(m_fHideWindow); + } + + return hr; +} + +HRESULT CFGManagerBDA::Flush(BDA_STREAM_TYPE nVideoType, BDA_STREAM_TYPE nAudioType) +{ + HRESULT hr = S_OK; + + CComPtr pFilterSub = m_DVBStreams[BDA_SUB].GetFilter(); + if (pFilterSub) { + CComPtr pSubPinIn = GetFirstPin(pFilterSub, PINDIR_INPUT); + hr = pSubPinIn->BeginFlush(); + hr = pSubPinIn->EndFlush(); + hr = pSubPinIn->NewSegment(0, MAXLONG, 1); + } + CComPtr pFilterAudio = m_DVBStreams[nAudioType].GetFilter(); + if (pFilterAudio) { + CComPtr pAudPinIn = GetFirstPin(pFilterAudio, PINDIR_INPUT); + hr = pAudPinIn->BeginFlush(); + hr = pAudPinIn->EndFlush(); + hr = pAudPinIn->NewSegment(0, MAXLONG, 1); + } + CComPtr pFilterVideo = m_DVBStreams[nVideoType].GetFilter(); + if (pFilterVideo) { + CComPtr pVidPinIn = GetFirstPin(pFilterVideo, PINDIR_INPUT); + hr = pVidPinIn->BeginFlush(); + hr = pVidPinIn->EndFlush(); + hr = pVidPinIn->NewSegment(0, MAXLONG, 1); + } + + return hr; +} + +HRESULT CFGManagerBDA::SwitchStream(BDA_STREAM_TYPE nOldType, BDA_STREAM_TYPE nNewType) +{ + HRESULT hr = S_OK; + CComPtr pFGOld = m_DVBStreams[nOldType].GetFilter(); + CComPtr pFGNew = m_DVBStreams[nNewType].GetFilter(); + CComPtr pOldOut = GetFirstPin(pFGOld, PINDIR_OUTPUT); + CComPtr pInPin; + if (pOldOut && pFGNew) { + pOldOut->ConnectedTo(&pInPin); + if (!pInPin) { + ASSERT(false); + return E_UNEXPECTED; + } + CComPtr pNewOut = GetFirstPin(pFGNew, PINDIR_OUTPUT); + CComPtr pNewOutDynamic; + + if (nNewType != BDA_MPV && nNewType != BDA_H264 && nNewType != BDA_HEVC && GetState() != State_Stopped) { + CComPtr pDemux; + m_pDemux->QueryInterface(IID_PPV_ARGS(&pDemux)); + + switch (nNewType) { + case BDA_MPA: + hr = pDemux->SetOutputPinMediaType(const_cast(L"mpa"), const_cast(&mt_Mpa)); + break; + case BDA_AC3: + hr = pDemux->SetOutputPinMediaType(const_cast(L"ac3"), const_cast(&mt_Ac3)); + break; + case BDA_EAC3: + hr = pDemux->SetOutputPinMediaType(const_cast(L"eac3"), const_cast(&mt_Eac3)); + break; + case BDA_ADTS: + hr = pDemux->SetOutputPinMediaType(const_cast(L"adts"), const_cast(&mt_latm)); + break; + case BDA_LATM: + hr = pDemux->SetOutputPinMediaType(const_cast(L"latm"), const_cast(&mt_latm)); + break; + } + } + + CComPtr pOldOutDynamic; + pOldOut->QueryInterface(IID_PPV_ARGS(&pOldOutDynamic)); + CComPtr pInPinDynamic; + pInPin->QueryInterface(IID_PPV_ARGS(&pInPinDynamic)); + CComPtr pOldOutControl; + if ((GetState() != State_Stopped) && pInPinDynamic && pOldOutDynamic) { // Try dynamic switch + pOldOut->QueryInterface(IID_PPV_ARGS(&pOldOutControl)); + pOldOutControl->Block(AM_PIN_FLOW_CONTROL_BLOCK, nullptr); + CComPtr pGraph; + QueryInterface(IID_PPV_ARGS(&pGraph)); + hr = pGraph->Reconnect(pNewOut, pInPin, nullptr, nullptr, nullptr, AM_GRAPH_CONFIG_RECONNECT_DIRECTCONNECT); + pOldOutControl->Block(0, nullptr); + } else { // Dynamic pins not supported + LOG(_T("Dynamic pin interface not supported.")); + hr = Disconnect(pOldOut); + if (FAILED(hr) && (GetState() != State_Stopped)) { + ChangeState(State_Stopped); + hr = Disconnect(pOldOut); + } + if (SUCCEEDED(hr)) { + hr = Disconnect(pInPin); + if (FAILED(hr) && (GetState() != State_Stopped)) { + ChangeState(State_Stopped); + hr = Disconnect(pInPin); + } + } + if (SUCCEEDED(hr)) { + hr = ConnectDirect(pNewOut, pInPin, nullptr); + if (FAILED(hr) && (GetState() != State_Stopped)) { + ChangeState(State_Stopped); + hr = ConnectDirect(pNewOut, pInPin, nullptr); + } + if (FAILED(hr)) { + hr = E_UNEXPECTED; + } + } + } + } else { + hr = E_POINTER; + ASSERT(FALSE); + } + + LOG(_T("SwitchStream - Stream type: %d. Result: 0x%08x"), nNewType, hr); + + return hr; +} + +void CFGManagerBDA::UpdateMediaType(VIDEOINFOHEADER2* NewVideoHeader, CBDAChannel* pChannel) +{ + NewVideoHeader->AvgTimePerFrame = pChannel->GetAvgTimePerFrame(); + if ((pChannel->GetVideoFps() == BDA_FPS_25_0) || + (pChannel->GetVideoFps() == BDA_FPS_29_97) || + (pChannel->GetVideoFps() == BDA_FPS_30_0)) { + NewVideoHeader->dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_DisplayModeBobOrWeave; + } else { + NewVideoHeader->dwInterlaceFlags = 0; + } + if ((pChannel->GetVideoARx() != 0) && (pChannel->GetVideoARy() != 0)) { + NewVideoHeader->dwPictAspectRatioX = pChannel->GetVideoARx(); + NewVideoHeader->dwPictAspectRatioY = pChannel->GetVideoARy(); + } else { + NewVideoHeader->dwPictAspectRatioX = 16; + NewVideoHeader->dwPictAspectRatioY = 9; + } + + if (pChannel->GetVideoHeight()) { + NewVideoHeader->bmiHeader.biHeight = pChannel->GetVideoHeight(); + NewVideoHeader->bmiHeader.biWidth = pChannel->GetVideoWidth(); + } else { + NewVideoHeader->bmiHeader.biHeight = 576; + NewVideoHeader->bmiHeader.biWidth = 720; + } + + if (NewVideoHeader->dwPictAspectRatioX && NewVideoHeader->dwPictAspectRatioY) { + NewVideoHeader->bmiHeader.biWidth = (LONG)(NewVideoHeader->bmiHeader.biHeight * NewVideoHeader->dwPictAspectRatioX / NewVideoHeader->dwPictAspectRatioY); + } + + NewVideoHeader->rcSource.top = 0; + NewVideoHeader->rcSource.left = 0; + NewVideoHeader->rcSource.right = NewVideoHeader->bmiHeader.biWidth; + NewVideoHeader->rcSource.bottom = NewVideoHeader->bmiHeader.biHeight; + NewVideoHeader->rcTarget.top = 0; + NewVideoHeader->rcTarget.left = 0; + NewVideoHeader->rcTarget.right = 0; + NewVideoHeader->rcTarget.bottom = 0; +} + +HRESULT CFGManagerBDA::UpdatePSI(const CBDAChannel* pChannel, EventDescriptor& NowNext) +{ + HRESULT hr = S_FALSE; + CMpeg2DataParser Parser(m_DVBStreams[BDA_PSI].GetFilter()); + + if (pChannel->GetNowNextFlag()) { + hr = Parser.ParseEIT(pChannel->GetSID(), NowNext); + } + + return hr; +} + +HRESULT CFGManagerBDA::ChangeState(FILTER_STATE nRequested) +{ + HRESULT hr = S_OK; + OAFilterState nState = nRequested + 1; + + CComPtr pMC; + QueryInterface(IID_PPV_ARGS(&pMC)); + pMC->GetState(500, &nState); + if (nState != nRequested) { + CMainFrame* pMainFrame = AfxGetMainFrame(); + switch (nRequested) { + case State_Stopped: { + if (pMainFrame) { + pMainFrame->KillTimersStop(); + } + hr = pMC->Stop(); + LOG(_T("IMediaControl stop: 0x%08x."), hr); + return hr; + } + case State_Paused: { + LOG(_T("IMediaControl pause.")); + return pMC->Pause(); + } + case State_Running: { + if (SUCCEEDED(hr = pMC->Run()) && SUCCEEDED(hr = pMC->GetState(500, &nState)) && nState == State_Running && pMainFrame) { + pMainFrame->SetTimersPlay(); + } + LOG(_T("IMediaControl play: 0x%08x."), hr); + return hr; + } + } + } + return hr; +} + +FILTER_STATE CFGManagerBDA::GetState() +{ + CComPtr pMC; + OAFilterState nState; + QueryInterface(IID_PPV_ARGS(&pMC)); + pMC->GetState(500, &nState); + + return (FILTER_STATE) nState; +} diff --git a/src/mpc-hc/FGManagerBDA.h b/src/mpc-hc/FGManagerBDA.h index b0000e1e8a4..e05895de459 100644 --- a/src/mpc-hc/FGManagerBDA.h +++ b/src/mpc-hc/FGManagerBDA.h @@ -1,178 +1,178 @@ -/* - * (C) 2009-2017 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 . - * - */ - -#pragma once - -#include "FGManager.h" -#include "DVBChannel.h" -#include - -enum DVB_RebuildFilterGraph; -typedef struct tagVIDEOINFOHEADER2 VIDEOINFOHEADER2; - -class CDVBStream -{ -public: - CDVBStream() - : m_pmt(0) - , m_bFindExisting(false) - , m_Name(L"") - , m_nMsc(MEDIA_TRANSPORT_PACKET) - , m_ulMappedPID(0) { - } - - CDVBStream(LPCWSTR strName, const AM_MEDIA_TYPE* pmt, bool bFindExisting = false, MEDIA_SAMPLE_CONTENT nMsc = MEDIA_ELEMENTARY_STREAM) - : m_pmt(pmt) - , m_bFindExisting(bFindExisting) - , m_Name(strName) - , m_nMsc(nMsc) - , m_ulMappedPID(0) { - } - - LPCWSTR GetName() const { return m_Name; }; - const AM_MEDIA_TYPE* GetMediaType() { return m_pmt; }; - bool GetFindExisting() const { return m_bFindExisting; }; - IBaseFilter* GetFilter() { return m_pFilter; }; - - void SetPin(IPin* pPin) { - CComPtr pPinOut; - PIN_INFO PinInfo; - - m_pMap = pPin; - if (m_pMap && - SUCCEEDED(pPin->ConnectedTo(&pPinOut)) && - SUCCEEDED(pPinOut->QueryPinInfo(&PinInfo))) { - m_pFilter.Attach(PinInfo.pFilter); - } - } - - HRESULT Map(ULONG ulPID) { - CheckPointer(m_pMap, E_UNEXPECTED); - ClearMaps(); - m_ulMappedPID = ulPID; - return m_pMap->MapPID(1, &ulPID, m_nMsc); - } - - HRESULT Unmap(ULONG ulPID) { - CheckPointer(m_pMap, E_UNEXPECTED); - m_ulMappedPID = 0; - return m_pMap->UnmapPID(1, &ulPID); - } - - ULONG GetMappedPID() const { return m_ulMappedPID; } - -private: - CComQIPtr m_pMap; - CComPtr m_pFilter; - const AM_MEDIA_TYPE* m_pmt; - bool m_bFindExisting; - LPCWSTR m_Name; - MEDIA_SAMPLE_CONTENT m_nMsc; - ULONG m_ulMappedPID; - - void ClearMaps() { - CComPtr pEnumMap; - - if (SUCCEEDED(m_pMap->EnumPIDMap(&pEnumMap))) { - PID_MAP maps[8]; - ULONG nbPids = 0; - ZeroMemory(maps, sizeof(maps)); - - if (pEnumMap->Next(_countof(maps), maps, &nbPids) == S_OK) { - for (ULONG i = 0; i < nbPids; i++) { - ULONG pid = maps[i].ulPID; - - m_pMap->UnmapPID(1, &pid); - } - } - } - } -}; - -class CFGManagerBDA : public CFGManagerPlayer, IBDATuner, IAMStreamSelect -{ -public: - CFGManagerBDA(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd); - ~CFGManagerBDA(); - - // IGraphBuilder - STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); - - // IFilterGraph - STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); - - // IBDATuner - STDMETHODIMP SetChannel(int nChannelPrefNumber); - STDMETHODIMP SetAudio(int nAudioIndex); - STDMETHODIMP SetFrequency(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate); - STDMETHODIMP Scan(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd); - STDMETHODIMP GetStats(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality); - - // IAMStreamSelect - STDMETHODIMP Count(DWORD* pcStreams); - STDMETHODIMP Enable(long lIndex, DWORD dwFlags); - STDMETHODIMP Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - STDMETHODIMP UpdatePSI(const CBDAChannel* pChannel, EventDescriptor& NowNext); - -private: - - CComQIPtr m_pBDAControl; - CComPtr m_pBDAFreq; - CComQIPtr m_pBDATunerStats; - CComPtr m_pBDADemodulator; - CComQIPtr m_pBDADemodStats; - CComPtr m_pBDAAutoDemulate; - DVB_RebuildFilterGraph m_nDVBRebuildFilterGraph; - CAtlMap m_DVBStreams; - bool tunerIsATSC; - - BDA_STREAM_TYPE m_nCurVideoType; - BDA_STREAM_TYPE m_nCurAudioType; - bool m_fHideWindow; - CComPtr m_pDemux; - - HRESULT CreateKSFilter(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& DisplayName); - HRESULT CreateKSFilterFN(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& FriendlyName); - HRESULT ConnectFilters(IBaseFilter* pOutFiter, IBaseFilter* pInFilter); - HRESULT CreateMicrosoftDemux(CComPtr& pMpeg2Demux); - HRESULT SetChannelInternal(CBDAChannel* pChannel); - HRESULT SwitchStream(BDA_STREAM_TYPE nOldType, BDA_STREAM_TYPE nNewType); - HRESULT ChangeState(FILTER_STATE nRequested); - HRESULT ClearMaps(); - FILTER_STATE GetState(); - void UpdateMediaType(VIDEOINFOHEADER2* NewVideoHeader, CBDAChannel* pChannel); - HRESULT Flush(BDA_STREAM_TYPE nVideoType, BDA_STREAM_TYPE nAudioType); - - template - HRESULT SearchIBDATopology(const CComPtr& pTuner, CComPtr& pItf) { - CComPtr pUnk; - HRESULT hr = SearchIBDATopology(pTuner, __uuidof(ITF), pUnk); - - if (SUCCEEDED(hr)) { - hr = pUnk.QueryInterface(&pItf); - } - return !pItf ? E_NOINTERFACE : hr; - } - - HRESULT SearchIBDATopology(const CComPtr& pTuner, REFIID iid, CComPtr& pUnk); -}; +/* + * (C) 2009-2017 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 . + * + */ + +#pragma once + +#include "FGManager.h" +#include "DVBChannel.h" +#include + +enum DVB_RebuildFilterGraph; +typedef struct tagVIDEOINFOHEADER2 VIDEOINFOHEADER2; + +class CDVBStream +{ +public: + CDVBStream() + : m_pmt(0) + , m_bFindExisting(false) + , m_Name(L"") + , m_nMsc(MEDIA_TRANSPORT_PACKET) + , m_ulMappedPID(0) { + } + + CDVBStream(LPCWSTR strName, const AM_MEDIA_TYPE* pmt, bool bFindExisting = false, MEDIA_SAMPLE_CONTENT nMsc = MEDIA_ELEMENTARY_STREAM) + : m_pmt(pmt) + , m_bFindExisting(bFindExisting) + , m_Name(strName) + , m_nMsc(nMsc) + , m_ulMappedPID(0) { + } + + LPCWSTR GetName() const { return m_Name; }; + const AM_MEDIA_TYPE* GetMediaType() { return m_pmt; }; + bool GetFindExisting() const { return m_bFindExisting; }; + IBaseFilter* GetFilter() { return m_pFilter; }; + + void SetPin(IPin* pPin) { + CComPtr pPinOut; + PIN_INFO PinInfo; + + m_pMap = pPin; + if (m_pMap && + SUCCEEDED(pPin->ConnectedTo(&pPinOut)) && + SUCCEEDED(pPinOut->QueryPinInfo(&PinInfo))) { + m_pFilter.Attach(PinInfo.pFilter); + } + } + + HRESULT Map(ULONG ulPID) { + CheckPointer(m_pMap, E_UNEXPECTED); + ClearMaps(); + m_ulMappedPID = ulPID; + return m_pMap->MapPID(1, &ulPID, m_nMsc); + } + + HRESULT Unmap(ULONG ulPID) { + CheckPointer(m_pMap, E_UNEXPECTED); + m_ulMappedPID = 0; + return m_pMap->UnmapPID(1, &ulPID); + } + + ULONG GetMappedPID() const { return m_ulMappedPID; } + +private: + CComQIPtr m_pMap; + CComPtr m_pFilter; + const AM_MEDIA_TYPE* m_pmt; + bool m_bFindExisting; + LPCWSTR m_Name; + MEDIA_SAMPLE_CONTENT m_nMsc; + ULONG m_ulMappedPID; + + void ClearMaps() { + CComPtr pEnumMap; + + if (SUCCEEDED(m_pMap->EnumPIDMap(&pEnumMap))) { + PID_MAP maps[8]; + ULONG nbPids = 0; + ZeroMemory(maps, sizeof(maps)); + + if (pEnumMap->Next(_countof(maps), maps, &nbPids) == S_OK) { + for (ULONG i = 0; i < nbPids; i++) { + ULONG pid = maps[i].ulPID; + + m_pMap->UnmapPID(1, &pid); + } + } + } + } +}; + +class CFGManagerBDA : public CFGManagerPlayer, IBDATuner, IAMStreamSelect +{ +public: + CFGManagerBDA(LPCTSTR pName, LPUNKNOWN pUnk, HWND hWnd); + ~CFGManagerBDA(); + + // IGraphBuilder + STDMETHODIMP RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList); + + // IFilterGraph + STDMETHODIMP ConnectDirect(IPin* pPinOut, IPin* pPinIn, const AM_MEDIA_TYPE* pmt); + + // IBDATuner + STDMETHODIMP SetChannel(int nChannelPrefNumber); + STDMETHODIMP SetAudio(int nAudioIndex); + STDMETHODIMP SetFrequency(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate); + STDMETHODIMP Scan(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd); + STDMETHODIMP GetStats(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality); + + // IAMStreamSelect + STDMETHODIMP Count(DWORD* pcStreams); + STDMETHODIMP Enable(long lIndex, DWORD dwFlags); + STDMETHODIMP Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + STDMETHODIMP UpdatePSI(const CBDAChannel* pChannel, EventDescriptor& NowNext); + +private: + + CComQIPtr m_pBDAControl; + CComPtr m_pBDAFreq; + CComQIPtr m_pBDATunerStats; + CComPtr m_pBDADemodulator; + CComQIPtr m_pBDADemodStats; + CComPtr m_pBDAAutoDemulate; + DVB_RebuildFilterGraph m_nDVBRebuildFilterGraph; + CAtlMap m_DVBStreams; + bool tunerIsATSC; + + BDA_STREAM_TYPE m_nCurVideoType; + BDA_STREAM_TYPE m_nCurAudioType; + bool m_fHideWindow; + CComPtr m_pDemux; + + HRESULT CreateKSFilter(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& DisplayName); + HRESULT CreateKSFilterFN(IBaseFilter** ppBF, CLSID KSCategory, const CStringW& FriendlyName); + HRESULT ConnectFilters(IBaseFilter* pOutFiter, IBaseFilter* pInFilter); + HRESULT CreateMicrosoftDemux(CComPtr& pMpeg2Demux); + HRESULT SetChannelInternal(CBDAChannel* pChannel); + HRESULT SwitchStream(BDA_STREAM_TYPE nOldType, BDA_STREAM_TYPE nNewType); + HRESULT ChangeState(FILTER_STATE nRequested); + HRESULT ClearMaps(); + FILTER_STATE GetState(); + void UpdateMediaType(VIDEOINFOHEADER2* NewVideoHeader, CBDAChannel* pChannel); + HRESULT Flush(BDA_STREAM_TYPE nVideoType, BDA_STREAM_TYPE nAudioType); + + template + HRESULT SearchIBDATopology(const CComPtr& pTuner, CComPtr& pItf) { + CComPtr pUnk; + HRESULT hr = SearchIBDATopology(pTuner, __uuidof(ITF), pUnk); + + if (SUCCEEDED(hr)) { + hr = pUnk.QueryInterface(&pItf); + } + return !pItf ? E_NOINTERFACE : hr; + } + + HRESULT SearchIBDATopology(const CComPtr& pTuner, REFIID iid, CComPtr& pUnk); +}; diff --git a/src/mpc-hc/FakeFilterMapper2.cpp b/src/mpc-hc/FakeFilterMapper2.cpp index a197be23763..f2065a39851 100644 --- a/src/mpc-hc/FakeFilterMapper2.cpp +++ b/src/mpc-hc/FakeFilterMapper2.cpp @@ -1,718 +1,718 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "FakeFilterMapper2.h" -#include "MacrovisionKicker.h" -#include "DSUtil.h" - -#include "MhookHelper.h" - - -HRESULT(__stdcall* Real_CoCreateInstance)(CONST IID& a0, - LPUNKNOWN a1, - DWORD a2, - CONST IID& a3, - LPVOID* a4) - = CoCreateInstance; - -LONG(WINAPI* Real_RegCreateKeyExA)(HKEY a0, - LPCSTR a1, - DWORD a2, - LPSTR a3, - DWORD a4, - REGSAM a5, - LPSECURITY_ATTRIBUTES a6, - PHKEY a7, - LPDWORD a8) - = RegCreateKeyExA; - -LONG(WINAPI* Real_RegCreateKeyExW)(HKEY a0, - LPCWSTR a1, - DWORD a2, - LPWSTR a3, - DWORD a4, - REGSAM a5, - LPSECURITY_ATTRIBUTES a6, - PHKEY a7, - LPDWORD a8) - = RegCreateKeyExW; - -LONG(WINAPI* Real_RegDeleteKeyA)(HKEY a0, - LPCSTR a1) - = RegDeleteKeyA; - -LONG(WINAPI* Real_RegDeleteKeyW)(HKEY a0, - LPCWSTR a1) - = RegDeleteKeyW; - -LONG(WINAPI* Real_RegDeleteValueA)(HKEY a0, - LPCSTR a1) - = RegDeleteValueA; - - -LONG(WINAPI* Real_RegDeleteValueW)(HKEY a0, - LPCWSTR a1) - = RegDeleteValueW; - -LONG(WINAPI* Real_RegEnumKeyExA)(HKEY a0, - DWORD a1, - LPSTR a2, - LPDWORD a3, - LPDWORD a4, - LPSTR a5, - LPDWORD a6, - struct _FILETIME* a7) - = RegEnumKeyExA; - -LONG(WINAPI* Real_RegEnumKeyExW)(HKEY a0, - DWORD a1, - LPWSTR a2, - LPDWORD a3, - LPDWORD a4, - LPWSTR a5, - LPDWORD a6, - struct _FILETIME* a7) - = RegEnumKeyExW; - -LONG(WINAPI* Real_RegEnumValueA)(HKEY a0, - DWORD a1, - LPSTR a2, - LPDWORD a3, - LPDWORD a4, - LPDWORD a5, - LPBYTE a6, - LPDWORD a7) - = RegEnumValueA; - -LONG(WINAPI* Real_RegEnumValueW)(HKEY a0, - DWORD a1, - LPWSTR a2, - LPDWORD a3, - LPDWORD a4, - LPDWORD a5, - LPBYTE a6, - LPDWORD a7) - = RegEnumValueW; - -LONG(WINAPI* Real_RegOpenKeyExA)(HKEY a0, - LPCSTR a1, - DWORD a2, - REGSAM a3, - PHKEY a4) - = RegOpenKeyExA; - -LONG(WINAPI* Real_RegOpenKeyExW)(HKEY a0, - LPCWSTR a1, - DWORD a2, - REGSAM a3, - PHKEY a4) - = RegOpenKeyExW; - -LONG(WINAPI* Real_RegQueryInfoKeyA)(HKEY a0, - LPSTR a1, - LPDWORD a2, - LPDWORD a3, - LPDWORD a4, - LPDWORD a5, - LPDWORD a6, - LPDWORD a7, - LPDWORD a8, - LPDWORD a9, - LPDWORD a10, - struct _FILETIME* a11) - = RegQueryInfoKeyA; - -LONG(WINAPI* Real_RegQueryInfoKeyW)(HKEY a0, - LPWSTR a1, - LPDWORD a2, - LPDWORD a3, - LPDWORD a4, - LPDWORD a5, - LPDWORD a6, - LPDWORD a7, - LPDWORD a8, - LPDWORD a9, - LPDWORD a10, - struct _FILETIME* a11) - = RegQueryInfoKeyW; - -LONG(WINAPI* Real_RegQueryValueExA)(HKEY a0, - LPCSTR a1, - LPDWORD a2, - LPDWORD a3, - LPBYTE a4, - LPDWORD a5) - = RegQueryValueExA; - -LONG(WINAPI* Real_RegQueryValueExW)(HKEY a0, - LPCWSTR a1, - LPDWORD a2, - LPDWORD a3, - LPBYTE a4, - LPDWORD a5) - = RegQueryValueExW; - -LONG(WINAPI* Real_RegSetValueExA)(HKEY a0, - LPCSTR a1, - DWORD a2, - DWORD a3, - const BYTE* a4, - DWORD a5) - = RegSetValueExA; - -LONG(WINAPI* Real_RegSetValueExW)(HKEY a0, - LPCWSTR a1, - DWORD a2, - DWORD a3, - const BYTE* a4, - DWORD a5) - = RegSetValueExW; - - -LONG(WINAPI* Real_RegCloseKey)(HKEY a0) - = RegCloseKey; - -LONG(WINAPI* Real_RegFlushKey)(HKEY a0) - = RegFlushKey; - -LONG(WINAPI* Real_RegCreateKeyA)(HKEY a0, LPCSTR a1, PHKEY a2) - = RegCreateKeyA; - -LONG(WINAPI* Real_RegCreateKeyW)(HKEY a0, LPCWSTR a1, PHKEY a2) - = RegCreateKeyW; - -LONG(WINAPI* Real_RegOpenKeyA)(HKEY a0, LPCSTR a1, PHKEY a2) - = RegOpenKeyA; - -LONG(WINAPI* Real_RegOpenKeyW)(HKEY a0, LPCWSTR a1, PHKEY a2) - = RegOpenKeyW; - -LONG(WINAPI* Real_RegQueryValueA)(HKEY a0, LPCSTR a1, LPSTR a2, PLONG a3) - = RegQueryValueA; - -LONG(WINAPI* Real_RegQueryValueW)(HKEY a0, LPCWSTR a1, LPWSTR a2, PLONG a3) - = RegQueryValueW; - -LONG(WINAPI* Real_RegSetValueW)(HKEY a0, LPCWSTR a1, DWORD a2, LPCWSTR a3, DWORD a4) - = RegSetValueW; - -LONG(WINAPI* Real_RegSetValueA)(HKEY a0, LPCSTR a1, DWORD a2, LPCSTR a3, DWORD a4) - = RegSetValueA; - - - -HRESULT WINAPI Mine_CoCreateInstance(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, - IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID FAR* ppv) -{ - if (CFilterMapper2::s_pFilterMapper2) { - CheckPointer(ppv, E_POINTER); - - if (rclsid == CLSID_FilterMapper) { - ASSERT(FALSE); - return REGDB_E_CLASSNOTREG; // sorry... - } - - if (rclsid == CLSID_FilterMapper2) { - if (pUnkOuter) { - return CLASS_E_NOAGGREGATION; - } - - if (riid == __uuidof(IUnknown)) { - CFilterMapper2::s_pFilterMapper2->AddRef(); - *ppv = (IUnknown*)CFilterMapper2::s_pFilterMapper2; - return S_OK; - } else if (riid == __uuidof(IFilterMapper2)) { - CFilterMapper2::s_pFilterMapper2->AddRef(); - *ppv = (IFilterMapper2*)CFilterMapper2::s_pFilterMapper2; - return S_OK; - } else { - return E_NOINTERFACE; - } - } - } - /* else - { - if (rclsid == CLSID_FilterMapper2) - { - CFilterMapper2* pFM2 = DEBUG_NEW CFilterMapper2(true, false, pUnkOuter); - CComPtr pUnk = (IUnknown*)pFM2; - return pUnk->QueryInterface(riid, ppv); - } - } - */ - if (!pUnkOuter) - if (rclsid == CLSID_VideoMixingRenderer || rclsid == CLSID_VideoMixingRenderer9 - || rclsid == CLSID_VideoRenderer || rclsid == CLSID_VideoRendererDefault - || rclsid == CLSID_OverlayMixer) { // || rclsid == CLSID_OverlayMixer2 - where is this declared?) - CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; - CComPtr pInner; - - if (SUCCEEDED(Real_CoCreateInstance(rclsid, pUnk, dwClsContext, IID_PPV_ARGS(&pInner)))) { - pMK->SetInner(pInner); - return pUnk->QueryInterface(riid, ppv); - } - } - - return Real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); -} - -#define FAKEHKEY (HKEY)0x12345678 - -LONG WINAPI Mine_RegCloseKey(HKEY a0) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_SUCCESS; - } - return Real_RegCloseKey(a0); -} - -LONG WINAPI Mine_RegFlushKey(HKEY a0) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_SUCCESS; - } - return Real_RegFlushKey(a0); -} - -LONG WINAPI Mine_RegCreateKeyA(HKEY a0, LPCSTR a1, PHKEY a2) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a2 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegCreateKeyA(a0, a1, a2); -} - -LONG WINAPI Mine_RegCreateKeyW(HKEY a0, LPCWSTR a1, PHKEY a2) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a2 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegCreateKeyW(a0, a1, a2); -} - -LONG WINAPI Mine_RegCreateKeyExA(HKEY a0, LPCSTR a1, DWORD a2, LPSTR a3, DWORD a4, REGSAM a5, LPSECURITY_ATTRIBUTES a6, PHKEY a7, LPDWORD a8) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a7 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegCreateKeyExA(a0, a1, a2, a3, a4, a5, a6, a7, a8); -} - -LONG WINAPI Mine_RegCreateKeyExW(HKEY a0, LPCWSTR a1, DWORD a2, LPWSTR a3, DWORD a4, REGSAM a5, LPSECURITY_ATTRIBUTES a6, PHKEY a7, LPDWORD a8) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a7 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegCreateKeyExW(a0, a1, a2, a3, a4, a5, a6, a7, a8); -} - -LONG WINAPI Mine_RegDeleteKeyA(HKEY a0, LPCSTR a1) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegDeleteKeyA(a0, a1); -} - -LONG WINAPI Mine_RegDeleteKeyW(HKEY a0, LPCWSTR a1) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegDeleteKeyW(a0, a1); -} - -LONG WINAPI Mine_RegDeleteValueA(HKEY a0, LPCSTR a1) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegDeleteValueA(a0, a1); -} - -LONG WINAPI Mine_RegDeleteValueW(HKEY a0, LPCWSTR a1) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegDeleteValueW(a0, a1); -} - -LONG WINAPI Mine_RegEnumKeyExA(HKEY a0, DWORD a1, LPSTR a2, LPDWORD a3, LPDWORD a4, LPSTR a5, LPDWORD a6, struct _FILETIME* a7) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_NO_MORE_ITEMS; - } - return Real_RegEnumKeyExA(a0, a1, a2, a3, a4, a5, a6, a7); -} - -LONG WINAPI Mine_RegEnumKeyExW(HKEY a0, DWORD a1, LPWSTR a2, LPDWORD a3, LPDWORD a4, LPWSTR a5, LPDWORD a6, struct _FILETIME* a7) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_NO_MORE_ITEMS; - } - return Real_RegEnumKeyExW(a0, a1, a2, a3, a4, a5, a6, a7); -} - -LONG WINAPI Mine_RegEnumValueA(HKEY a0, DWORD a1, LPSTR a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPBYTE a6, LPDWORD a7) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_NO_MORE_ITEMS; - } - return Real_RegEnumValueA(a0, a1, a2, a3, a4, a5, a6, a7); -} - -LONG WINAPI Mine_RegEnumValueW(HKEY a0, DWORD a1, LPWSTR a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPBYTE a6, LPDWORD a7) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_NO_MORE_ITEMS; - } - return Real_RegEnumValueW(a0, a1, a2, a3, a4, a5, a6, a7); -} - -LONG WINAPI Mine_RegOpenKeyA(HKEY a0, LPCSTR a1, PHKEY a2) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a2 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegOpenKeyA(a0, a1, a2); -} - -LONG WINAPI Mine_RegOpenKeyW(HKEY a0, LPCWSTR a1, PHKEY a2) -{ - if (CFilterMapper2::s_pFilterMapper2) { - *a2 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegOpenKeyW(a0, a1, a2); -} - -LONG WINAPI Mine_RegOpenKeyExA(HKEY a0, LPCSTR a1, DWORD a2, REGSAM a3, PHKEY a4) -{ - if (CFilterMapper2::s_pFilterMapper2 && (a3 & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { - *a4 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegOpenKeyExA(a0, a1, a2, a3, a4); -} - -LONG WINAPI Mine_RegOpenKeyExW(HKEY a0, LPCWSTR a1, DWORD a2, REGSAM a3, PHKEY a4) -{ - if (CFilterMapper2::s_pFilterMapper2 && (a3 & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { - *a4 = FAKEHKEY; - return ERROR_SUCCESS; - } - return Real_RegOpenKeyExW(a0, a1, a2, a3, a4); -} - -LONG WINAPI Mine_RegQueryInfoKeyA(HKEY a0, LPSTR a1, LPDWORD a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPDWORD a6, LPDWORD a7, LPDWORD a8, LPDWORD a9, LPDWORD a10, struct _FILETIME* a11) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_INVALID_HANDLE; - } - return Real_RegQueryInfoKeyA(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); -} - -LONG WINAPI Mine_RegQueryInfoKeyW(HKEY a0, LPWSTR a1, LPDWORD a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPDWORD a6, LPDWORD a7, LPDWORD a8, LPDWORD a9, LPDWORD a10, struct _FILETIME* a11) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - return ERROR_INVALID_HANDLE; - } - return Real_RegQueryInfoKeyW(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); -} - -LONG WINAPI Mine_RegQueryValueA(HKEY a0, LPCSTR a1, LPSTR a2, PLONG a3) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - *a3 = 0; - return ERROR_SUCCESS; - } - return Real_RegQueryValueA(a0, a1, a2, a3); -} - -LONG WINAPI Mine_RegQueryValueW(HKEY a0, LPCWSTR a1, LPWSTR a2, PLONG a3) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - *a3 = 0; - return ERROR_SUCCESS; - } - return Real_RegQueryValueW(a0, a1, a2, a3); -} - -LONG WINAPI Mine_RegQueryValueExA(HKEY a0, LPCSTR a1, LPDWORD a2, LPDWORD a3, LPBYTE a4, LPDWORD a5) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - *a5 = 0; - return ERROR_SUCCESS; - } - return Real_RegQueryValueExA(a0, a1, a2, a3, a4, a5); -} - -LONG WINAPI Mine_RegQueryValueExW(HKEY a0, LPCWSTR a1, LPDWORD a2, LPDWORD a3, LPBYTE a4, LPDWORD a5) -{ - if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { - *a5 = 0; - return ERROR_SUCCESS; - } - return Real_RegQueryValueExW(a0, a1, a2, a3, a4, a5); -} - -LONG WINAPI Mine_RegSetValueA(HKEY a0, LPCSTR a1, DWORD a2, LPCSTR a3, DWORD a4) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegSetValueA(a0, a1, a2, a3, a4); -} - -LONG WINAPI Mine_RegSetValueW(HKEY a0, LPCWSTR a1, DWORD a2, LPCWSTR a3, DWORD a4) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegSetValueW(a0, a1, a2, a3, a4); -} - -LONG WINAPI Mine_RegSetValueExA(HKEY a0, LPCSTR a1, DWORD a2, DWORD a3, const BYTE* a4, DWORD a5) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegSetValueExA(a0, a1, a2, a3, a4, a5); -} - -LONG WINAPI Mine_RegSetValueExW(HKEY a0, LPCWSTR a1, DWORD a2, DWORD a3, const BYTE* a4, DWORD a5) -{ - // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly - if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { - return ERROR_SUCCESS; - } - return Real_RegSetValueExW(a0, a1, a2, a3, a4, a5); -} - -// -// CFilterMapper2 -// - -IFilterMapper2* CFilterMapper2::s_pFilterMapper2 = nullptr; - -bool CFilterMapper2::s_bInitialized = false; - -void CFilterMapper2::Init() -{ - if (!s_bInitialized) { - // In case of error, we don't report the failure immediately since the hooks might not be needed - s_bInitialized = Mhook_SetHookEx(&Real_CoCreateInstance, Mine_CoCreateInstance) - && Mhook_SetHookEx(&Real_RegCloseKey, Mine_RegCloseKey) - && Mhook_SetHookEx(&Real_RegFlushKey, Mine_RegFlushKey) - && Mhook_SetHookEx(&Real_RegCreateKeyA, Mine_RegCreateKeyA) - && Mhook_SetHookEx(&Real_RegCreateKeyW, Mine_RegCreateKeyW) - && Mhook_SetHookEx(&Real_RegCreateKeyExA, Mine_RegCreateKeyExA) - && Mhook_SetHookEx(&Real_RegCreateKeyExW, Mine_RegCreateKeyExW) - && Mhook_SetHookEx(&Real_RegDeleteKeyA, Mine_RegDeleteKeyA) - && Mhook_SetHookEx(&Real_RegDeleteKeyW, Mine_RegDeleteKeyW) - && Mhook_SetHookEx(&Real_RegDeleteValueA, Mine_RegDeleteValueA) - && Mhook_SetHookEx(&Real_RegDeleteValueW, Mine_RegDeleteValueW) - && Mhook_SetHookEx(&Real_RegEnumKeyExA, Mine_RegEnumKeyExA) - && Mhook_SetHookEx(&Real_RegEnumKeyExW, Mine_RegEnumKeyExW) - && Mhook_SetHookEx(&Real_RegEnumValueA, Mine_RegEnumValueA) - && Mhook_SetHookEx(&Real_RegEnumValueW, Mine_RegEnumValueW) - && Mhook_SetHookEx(&Real_RegOpenKeyA, Mine_RegOpenKeyA) - && Mhook_SetHookEx(&Real_RegOpenKeyW, Mine_RegOpenKeyW) - && Mhook_SetHookEx(&Real_RegOpenKeyExA, Mine_RegOpenKeyExA) - && Mhook_SetHookEx(&Real_RegOpenKeyExW, Mine_RegOpenKeyExW) - && Mhook_SetHookEx(&Real_RegQueryInfoKeyA, Mine_RegQueryInfoKeyA) - && Mhook_SetHookEx(&Real_RegQueryInfoKeyW, Mine_RegQueryInfoKeyW) - && Mhook_SetHookEx(&Real_RegQueryValueA, Mine_RegQueryValueA) - && Mhook_SetHookEx(&Real_RegQueryValueW, Mine_RegQueryValueW) - && Mhook_SetHookEx(&Real_RegQueryValueExA, Mine_RegQueryValueExA) - && Mhook_SetHookEx(&Real_RegQueryValueExW, Mine_RegQueryValueExW) - && Mhook_SetHookEx(&Real_RegSetValueA, Mine_RegSetValueA) - && Mhook_SetHookEx(&Real_RegSetValueW, Mine_RegSetValueW) - && Mhook_SetHookEx(&Real_RegSetValueExA, Mine_RegSetValueExA) - && Mhook_SetHookEx(&Real_RegSetValueExW, Mine_RegSetValueExW); - s_bInitialized &= MH_EnableHook(MH_ALL_HOOKS) == MH_OK; - } -} - -CFilterMapper2::CFilterMapper2(bool bRefCounted, bool bAllowUnreg /*= false*/, LPUNKNOWN pUnkOuter /*= nullptr*/) - : CUnknown(NAME("CFilterMapper2"), pUnkOuter) - , m_bRefCounted(bRefCounted) - , m_bAllowUnreg(bAllowUnreg) -{ - m_cRef = bRefCounted ? 0 : 1; - - // We can't call Init() if more than one thread is running due to a custom optimization - // we use for mhook. Instead we ensure that the hooks were properly set up at startup - ENSURE(s_bInitialized); - - HRESULT hr = Real_CoCreateInstance(CLSID_FilterMapper2, (IUnknown*)(INonDelegatingUnknown*)this, - CLSCTX_ALL, IID_PPV_ARGS(&m_pFM2)); - if (FAILED(hr) || !m_pFM2) { - ASSERT(FALSE); - } -} - -CFilterMapper2::~CFilterMapper2() -{ - POSITION pos = m_filters.GetHeadPosition(); - while (pos) { - delete m_filters.GetNext(pos); - } -} - -STDMETHODIMP CFilterMapper2::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - if (riid == __uuidof(IFilterMapper2)) { - return GetInterface((IFilterMapper2*)this, ppv); - } - - HRESULT hr = m_pFM2 ? m_pFM2->QueryInterface(riid, ppv) : E_NOINTERFACE; - - return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); -} - -void CFilterMapper2::Register(CString path) -{ - // Load filter - if (HMODULE h = LoadLibraryEx(path, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH)) { - typedef HRESULT(__stdcall * PDllRegisterServer)(); - if (PDllRegisterServer fpDllRegisterServer = (PDllRegisterServer)GetProcAddress(h, "DllRegisterServer")) { - ASSERT(!CFilterMapper2::s_pFilterMapper2); - - CFilterMapper2::s_pFilterMapper2 = this; - m_path = path; - fpDllRegisterServer(); - m_path.Empty(); - CFilterMapper2::s_pFilterMapper2 = nullptr; - } - - FreeLibrary(h); - } -} - -// IFilterMapper2 - -STDMETHODIMP CFilterMapper2::CreateCategory(REFCLSID clsidCategory, DWORD dwCategoryMerit, LPCWSTR Description) -{ - if (!m_path.IsEmpty()) { - return S_OK; - } else if (CComQIPtr pFM2 = m_pFM2) { - return pFM2->CreateCategory(clsidCategory, dwCategoryMerit, Description); - } - - return E_NOTIMPL; -} - -STDMETHODIMP CFilterMapper2::UnregisterFilter(const CLSID* pclsidCategory, const OLECHAR* szInstance, REFCLSID Filter) -{ - if (!m_path.IsEmpty()) { - return S_OK; - } else if (CComQIPtr pFM2 = m_pFM2) { - return m_bAllowUnreg ? pFM2->UnregisterFilter(pclsidCategory, szInstance, Filter) : S_OK; - } - - return E_NOTIMPL; -} - -STDMETHODIMP CFilterMapper2::RegisterFilter(REFCLSID clsidFilter, LPCWSTR Name, IMoniker** ppMoniker, const CLSID* pclsidCategory, const OLECHAR* szInstance, const REGFILTER2* prf2) -{ - if (!m_path.IsEmpty()) { - if (FilterOverride* f = DEBUG_NEW FilterOverride) { - f->fDisabled = false; - f->type = FilterOverride::EXTERNAL; - f->path = m_path; - f->name = CStringW(Name); - f->clsid = clsidFilter; - f->iLoadType = FilterOverride::MERIT; - f->dwMerit = prf2->dwMerit; - - if (prf2->dwVersion == 1) { - for (ULONG i = 0; i < prf2->cPins; i++) { - const REGFILTERPINS& rgPin = prf2->rgPins[i]; - if (rgPin.bOutput) { - continue; - } - - for (UINT j = 0; j < rgPin.nMediaTypes; j++) { - if (!rgPin.lpMediaType[j].clsMajorType || !rgPin.lpMediaType[j].clsMinorType) { - break; - } - f->guids.AddTail(*rgPin.lpMediaType[j].clsMajorType); - f->guids.AddTail(*rgPin.lpMediaType[j].clsMinorType); - } - } - } else if (prf2->dwVersion == 2) { - for (ULONG i = 0; i < prf2->cPins2; i++) { - const REGFILTERPINS2& rgPin = prf2->rgPins2[i]; - if (rgPin.dwFlags & REG_PINFLAG_B_OUTPUT) { - continue; - } - - for (UINT j = 0; j < rgPin.nMediaTypes; j++) { - if (!rgPin.lpMediaType[j].clsMajorType || !rgPin.lpMediaType[j].clsMinorType) { - break; - } - f->guids.AddTail(*rgPin.lpMediaType[j].clsMajorType); - f->guids.AddTail(*rgPin.lpMediaType[j].clsMinorType); - } - } - } - - f->backup.AddTailList(&f->guids); - - m_filters.AddTail(f); - } - - return S_OK; - } else if (CComQIPtr pFM2 = m_pFM2) { - return pFM2->RegisterFilter(clsidFilter, Name, ppMoniker, pclsidCategory, szInstance, prf2); - } - - return E_NOTIMPL; -} - -STDMETHODIMP CFilterMapper2::EnumMatchingFilters(IEnumMoniker** ppEnum, DWORD dwFlags, BOOL bExactMatch, DWORD dwMerit, - BOOL bInputNeeded, DWORD cInputTypes, const GUID* pInputTypes, const REGPINMEDIUM* pMedIn, const CLSID* pPinCategoryIn, BOOL bRender, - BOOL bOutputNeeded, DWORD cOutputTypes, const GUID* pOutputTypes, const REGPINMEDIUM* pMedOut, const CLSID* pPinCategoryOut) -{ - if (CComQIPtr pFM2 = m_pFM2) { - return pFM2->EnumMatchingFilters(ppEnum, dwFlags, bExactMatch, dwMerit, - bInputNeeded, cInputTypes, pInputTypes, pMedIn, pPinCategoryIn, bRender, - bOutputNeeded, cOutputTypes, pOutputTypes, pMedOut, pPinCategoryOut); - } - - return E_NOTIMPL; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "FakeFilterMapper2.h" +#include "MacrovisionKicker.h" +#include "DSUtil.h" + +#include "MhookHelper.h" + + +HRESULT(__stdcall* Real_CoCreateInstance)(CONST IID& a0, + LPUNKNOWN a1, + DWORD a2, + CONST IID& a3, + LPVOID* a4) + = CoCreateInstance; + +LONG(WINAPI* Real_RegCreateKeyExA)(HKEY a0, + LPCSTR a1, + DWORD a2, + LPSTR a3, + DWORD a4, + REGSAM a5, + LPSECURITY_ATTRIBUTES a6, + PHKEY a7, + LPDWORD a8) + = RegCreateKeyExA; + +LONG(WINAPI* Real_RegCreateKeyExW)(HKEY a0, + LPCWSTR a1, + DWORD a2, + LPWSTR a3, + DWORD a4, + REGSAM a5, + LPSECURITY_ATTRIBUTES a6, + PHKEY a7, + LPDWORD a8) + = RegCreateKeyExW; + +LONG(WINAPI* Real_RegDeleteKeyA)(HKEY a0, + LPCSTR a1) + = RegDeleteKeyA; + +LONG(WINAPI* Real_RegDeleteKeyW)(HKEY a0, + LPCWSTR a1) + = RegDeleteKeyW; + +LONG(WINAPI* Real_RegDeleteValueA)(HKEY a0, + LPCSTR a1) + = RegDeleteValueA; + + +LONG(WINAPI* Real_RegDeleteValueW)(HKEY a0, + LPCWSTR a1) + = RegDeleteValueW; + +LONG(WINAPI* Real_RegEnumKeyExA)(HKEY a0, + DWORD a1, + LPSTR a2, + LPDWORD a3, + LPDWORD a4, + LPSTR a5, + LPDWORD a6, + struct _FILETIME* a7) + = RegEnumKeyExA; + +LONG(WINAPI* Real_RegEnumKeyExW)(HKEY a0, + DWORD a1, + LPWSTR a2, + LPDWORD a3, + LPDWORD a4, + LPWSTR a5, + LPDWORD a6, + struct _FILETIME* a7) + = RegEnumKeyExW; + +LONG(WINAPI* Real_RegEnumValueA)(HKEY a0, + DWORD a1, + LPSTR a2, + LPDWORD a3, + LPDWORD a4, + LPDWORD a5, + LPBYTE a6, + LPDWORD a7) + = RegEnumValueA; + +LONG(WINAPI* Real_RegEnumValueW)(HKEY a0, + DWORD a1, + LPWSTR a2, + LPDWORD a3, + LPDWORD a4, + LPDWORD a5, + LPBYTE a6, + LPDWORD a7) + = RegEnumValueW; + +LONG(WINAPI* Real_RegOpenKeyExA)(HKEY a0, + LPCSTR a1, + DWORD a2, + REGSAM a3, + PHKEY a4) + = RegOpenKeyExA; + +LONG(WINAPI* Real_RegOpenKeyExW)(HKEY a0, + LPCWSTR a1, + DWORD a2, + REGSAM a3, + PHKEY a4) + = RegOpenKeyExW; + +LONG(WINAPI* Real_RegQueryInfoKeyA)(HKEY a0, + LPSTR a1, + LPDWORD a2, + LPDWORD a3, + LPDWORD a4, + LPDWORD a5, + LPDWORD a6, + LPDWORD a7, + LPDWORD a8, + LPDWORD a9, + LPDWORD a10, + struct _FILETIME* a11) + = RegQueryInfoKeyA; + +LONG(WINAPI* Real_RegQueryInfoKeyW)(HKEY a0, + LPWSTR a1, + LPDWORD a2, + LPDWORD a3, + LPDWORD a4, + LPDWORD a5, + LPDWORD a6, + LPDWORD a7, + LPDWORD a8, + LPDWORD a9, + LPDWORD a10, + struct _FILETIME* a11) + = RegQueryInfoKeyW; + +LONG(WINAPI* Real_RegQueryValueExA)(HKEY a0, + LPCSTR a1, + LPDWORD a2, + LPDWORD a3, + LPBYTE a4, + LPDWORD a5) + = RegQueryValueExA; + +LONG(WINAPI* Real_RegQueryValueExW)(HKEY a0, + LPCWSTR a1, + LPDWORD a2, + LPDWORD a3, + LPBYTE a4, + LPDWORD a5) + = RegQueryValueExW; + +LONG(WINAPI* Real_RegSetValueExA)(HKEY a0, + LPCSTR a1, + DWORD a2, + DWORD a3, + const BYTE* a4, + DWORD a5) + = RegSetValueExA; + +LONG(WINAPI* Real_RegSetValueExW)(HKEY a0, + LPCWSTR a1, + DWORD a2, + DWORD a3, + const BYTE* a4, + DWORD a5) + = RegSetValueExW; + + +LONG(WINAPI* Real_RegCloseKey)(HKEY a0) + = RegCloseKey; + +LONG(WINAPI* Real_RegFlushKey)(HKEY a0) + = RegFlushKey; + +LONG(WINAPI* Real_RegCreateKeyA)(HKEY a0, LPCSTR a1, PHKEY a2) + = RegCreateKeyA; + +LONG(WINAPI* Real_RegCreateKeyW)(HKEY a0, LPCWSTR a1, PHKEY a2) + = RegCreateKeyW; + +LONG(WINAPI* Real_RegOpenKeyA)(HKEY a0, LPCSTR a1, PHKEY a2) + = RegOpenKeyA; + +LONG(WINAPI* Real_RegOpenKeyW)(HKEY a0, LPCWSTR a1, PHKEY a2) + = RegOpenKeyW; + +LONG(WINAPI* Real_RegQueryValueA)(HKEY a0, LPCSTR a1, LPSTR a2, PLONG a3) + = RegQueryValueA; + +LONG(WINAPI* Real_RegQueryValueW)(HKEY a0, LPCWSTR a1, LPWSTR a2, PLONG a3) + = RegQueryValueW; + +LONG(WINAPI* Real_RegSetValueW)(HKEY a0, LPCWSTR a1, DWORD a2, LPCWSTR a3, DWORD a4) + = RegSetValueW; + +LONG(WINAPI* Real_RegSetValueA)(HKEY a0, LPCSTR a1, DWORD a2, LPCSTR a3, DWORD a4) + = RegSetValueA; + + + +HRESULT WINAPI Mine_CoCreateInstance(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, + IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID FAR* ppv) +{ + if (CFilterMapper2::s_pFilterMapper2) { + CheckPointer(ppv, E_POINTER); + + if (rclsid == CLSID_FilterMapper) { + ASSERT(FALSE); + return REGDB_E_CLASSNOTREG; // sorry... + } + + if (rclsid == CLSID_FilterMapper2) { + if (pUnkOuter) { + return CLASS_E_NOAGGREGATION; + } + + if (riid == __uuidof(IUnknown)) { + CFilterMapper2::s_pFilterMapper2->AddRef(); + *ppv = (IUnknown*)CFilterMapper2::s_pFilterMapper2; + return S_OK; + } else if (riid == __uuidof(IFilterMapper2)) { + CFilterMapper2::s_pFilterMapper2->AddRef(); + *ppv = (IFilterMapper2*)CFilterMapper2::s_pFilterMapper2; + return S_OK; + } else { + return E_NOINTERFACE; + } + } + } + /* else + { + if (rclsid == CLSID_FilterMapper2) + { + CFilterMapper2* pFM2 = DEBUG_NEW CFilterMapper2(true, false, pUnkOuter); + CComPtr pUnk = (IUnknown*)pFM2; + return pUnk->QueryInterface(riid, ppv); + } + } + */ + if (!pUnkOuter) + if (rclsid == CLSID_VideoMixingRenderer || rclsid == CLSID_VideoMixingRenderer9 + || rclsid == CLSID_VideoRenderer || rclsid == CLSID_VideoRendererDefault + || rclsid == CLSID_OverlayMixer) { // || rclsid == CLSID_OverlayMixer2 - where is this declared?) + CMacrovisionKicker* pMK = DEBUG_NEW CMacrovisionKicker(NAME("CMacrovisionKicker"), nullptr); + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK; + CComPtr pInner; + + if (SUCCEEDED(Real_CoCreateInstance(rclsid, pUnk, dwClsContext, IID_PPV_ARGS(&pInner)))) { + pMK->SetInner(pInner); + return pUnk->QueryInterface(riid, ppv); + } + } + + return Real_CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); +} + +#define FAKEHKEY (HKEY)0x12345678 + +LONG WINAPI Mine_RegCloseKey(HKEY a0) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_SUCCESS; + } + return Real_RegCloseKey(a0); +} + +LONG WINAPI Mine_RegFlushKey(HKEY a0) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_SUCCESS; + } + return Real_RegFlushKey(a0); +} + +LONG WINAPI Mine_RegCreateKeyA(HKEY a0, LPCSTR a1, PHKEY a2) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a2 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegCreateKeyA(a0, a1, a2); +} + +LONG WINAPI Mine_RegCreateKeyW(HKEY a0, LPCWSTR a1, PHKEY a2) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a2 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegCreateKeyW(a0, a1, a2); +} + +LONG WINAPI Mine_RegCreateKeyExA(HKEY a0, LPCSTR a1, DWORD a2, LPSTR a3, DWORD a4, REGSAM a5, LPSECURITY_ATTRIBUTES a6, PHKEY a7, LPDWORD a8) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a7 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegCreateKeyExA(a0, a1, a2, a3, a4, a5, a6, a7, a8); +} + +LONG WINAPI Mine_RegCreateKeyExW(HKEY a0, LPCWSTR a1, DWORD a2, LPWSTR a3, DWORD a4, REGSAM a5, LPSECURITY_ATTRIBUTES a6, PHKEY a7, LPDWORD a8) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a7 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegCreateKeyExW(a0, a1, a2, a3, a4, a5, a6, a7, a8); +} + +LONG WINAPI Mine_RegDeleteKeyA(HKEY a0, LPCSTR a1) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegDeleteKeyA(a0, a1); +} + +LONG WINAPI Mine_RegDeleteKeyW(HKEY a0, LPCWSTR a1) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegDeleteKeyW(a0, a1); +} + +LONG WINAPI Mine_RegDeleteValueA(HKEY a0, LPCSTR a1) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegDeleteValueA(a0, a1); +} + +LONG WINAPI Mine_RegDeleteValueW(HKEY a0, LPCWSTR a1) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegDeleteValueW(a0, a1); +} + +LONG WINAPI Mine_RegEnumKeyExA(HKEY a0, DWORD a1, LPSTR a2, LPDWORD a3, LPDWORD a4, LPSTR a5, LPDWORD a6, struct _FILETIME* a7) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_NO_MORE_ITEMS; + } + return Real_RegEnumKeyExA(a0, a1, a2, a3, a4, a5, a6, a7); +} + +LONG WINAPI Mine_RegEnumKeyExW(HKEY a0, DWORD a1, LPWSTR a2, LPDWORD a3, LPDWORD a4, LPWSTR a5, LPDWORD a6, struct _FILETIME* a7) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_NO_MORE_ITEMS; + } + return Real_RegEnumKeyExW(a0, a1, a2, a3, a4, a5, a6, a7); +} + +LONG WINAPI Mine_RegEnumValueA(HKEY a0, DWORD a1, LPSTR a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPBYTE a6, LPDWORD a7) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_NO_MORE_ITEMS; + } + return Real_RegEnumValueA(a0, a1, a2, a3, a4, a5, a6, a7); +} + +LONG WINAPI Mine_RegEnumValueW(HKEY a0, DWORD a1, LPWSTR a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPBYTE a6, LPDWORD a7) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_NO_MORE_ITEMS; + } + return Real_RegEnumValueW(a0, a1, a2, a3, a4, a5, a6, a7); +} + +LONG WINAPI Mine_RegOpenKeyA(HKEY a0, LPCSTR a1, PHKEY a2) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a2 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegOpenKeyA(a0, a1, a2); +} + +LONG WINAPI Mine_RegOpenKeyW(HKEY a0, LPCWSTR a1, PHKEY a2) +{ + if (CFilterMapper2::s_pFilterMapper2) { + *a2 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegOpenKeyW(a0, a1, a2); +} + +LONG WINAPI Mine_RegOpenKeyExA(HKEY a0, LPCSTR a1, DWORD a2, REGSAM a3, PHKEY a4) +{ + if (CFilterMapper2::s_pFilterMapper2 && (a3 & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { + *a4 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegOpenKeyExA(a0, a1, a2, a3, a4); +} + +LONG WINAPI Mine_RegOpenKeyExW(HKEY a0, LPCWSTR a1, DWORD a2, REGSAM a3, PHKEY a4) +{ + if (CFilterMapper2::s_pFilterMapper2 && (a3 & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY))) { + *a4 = FAKEHKEY; + return ERROR_SUCCESS; + } + return Real_RegOpenKeyExW(a0, a1, a2, a3, a4); +} + +LONG WINAPI Mine_RegQueryInfoKeyA(HKEY a0, LPSTR a1, LPDWORD a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPDWORD a6, LPDWORD a7, LPDWORD a8, LPDWORD a9, LPDWORD a10, struct _FILETIME* a11) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_INVALID_HANDLE; + } + return Real_RegQueryInfoKeyA(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); +} + +LONG WINAPI Mine_RegQueryInfoKeyW(HKEY a0, LPWSTR a1, LPDWORD a2, LPDWORD a3, LPDWORD a4, LPDWORD a5, LPDWORD a6, LPDWORD a7, LPDWORD a8, LPDWORD a9, LPDWORD a10, struct _FILETIME* a11) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + return ERROR_INVALID_HANDLE; + } + return Real_RegQueryInfoKeyW(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); +} + +LONG WINAPI Mine_RegQueryValueA(HKEY a0, LPCSTR a1, LPSTR a2, PLONG a3) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + *a3 = 0; + return ERROR_SUCCESS; + } + return Real_RegQueryValueA(a0, a1, a2, a3); +} + +LONG WINAPI Mine_RegQueryValueW(HKEY a0, LPCWSTR a1, LPWSTR a2, PLONG a3) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + *a3 = 0; + return ERROR_SUCCESS; + } + return Real_RegQueryValueW(a0, a1, a2, a3); +} + +LONG WINAPI Mine_RegQueryValueExA(HKEY a0, LPCSTR a1, LPDWORD a2, LPDWORD a3, LPBYTE a4, LPDWORD a5) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + *a5 = 0; + return ERROR_SUCCESS; + } + return Real_RegQueryValueExA(a0, a1, a2, a3, a4, a5); +} + +LONG WINAPI Mine_RegQueryValueExW(HKEY a0, LPCWSTR a1, LPDWORD a2, LPDWORD a3, LPBYTE a4, LPDWORD a5) +{ + if (CFilterMapper2::s_pFilterMapper2 && a0 == FAKEHKEY) { + *a5 = 0; + return ERROR_SUCCESS; + } + return Real_RegQueryValueExW(a0, a1, a2, a3, a4, a5); +} + +LONG WINAPI Mine_RegSetValueA(HKEY a0, LPCSTR a1, DWORD a2, LPCSTR a3, DWORD a4) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegSetValueA(a0, a1, a2, a3, a4); +} + +LONG WINAPI Mine_RegSetValueW(HKEY a0, LPCWSTR a1, DWORD a2, LPCWSTR a3, DWORD a4) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegSetValueW(a0, a1, a2, a3, a4); +} + +LONG WINAPI Mine_RegSetValueExA(HKEY a0, LPCSTR a1, DWORD a2, DWORD a3, const BYTE* a4, DWORD a5) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegSetValueExA(a0, a1, a2, a3, a4, a5); +} + +LONG WINAPI Mine_RegSetValueExW(HKEY a0, LPCWSTR a1, DWORD a2, DWORD a3, const BYTE* a4, DWORD a5) +{ + // (INT_PTR)a0 < 0 will catch all attempts to use a predefined HKEY directly + if (CFilterMapper2::s_pFilterMapper2 && (a0 == FAKEHKEY || (INT_PTR)a0 < 0)) { + return ERROR_SUCCESS; + } + return Real_RegSetValueExW(a0, a1, a2, a3, a4, a5); +} + +// +// CFilterMapper2 +// + +IFilterMapper2* CFilterMapper2::s_pFilterMapper2 = nullptr; + +bool CFilterMapper2::s_bInitialized = false; + +void CFilterMapper2::Init() +{ + if (!s_bInitialized) { + // In case of error, we don't report the failure immediately since the hooks might not be needed + s_bInitialized = Mhook_SetHookEx(&Real_CoCreateInstance, Mine_CoCreateInstance) + && Mhook_SetHookEx(&Real_RegCloseKey, Mine_RegCloseKey) + && Mhook_SetHookEx(&Real_RegFlushKey, Mine_RegFlushKey) + && Mhook_SetHookEx(&Real_RegCreateKeyA, Mine_RegCreateKeyA) + && Mhook_SetHookEx(&Real_RegCreateKeyW, Mine_RegCreateKeyW) + && Mhook_SetHookEx(&Real_RegCreateKeyExA, Mine_RegCreateKeyExA) + && Mhook_SetHookEx(&Real_RegCreateKeyExW, Mine_RegCreateKeyExW) + && Mhook_SetHookEx(&Real_RegDeleteKeyA, Mine_RegDeleteKeyA) + && Mhook_SetHookEx(&Real_RegDeleteKeyW, Mine_RegDeleteKeyW) + && Mhook_SetHookEx(&Real_RegDeleteValueA, Mine_RegDeleteValueA) + && Mhook_SetHookEx(&Real_RegDeleteValueW, Mine_RegDeleteValueW) + && Mhook_SetHookEx(&Real_RegEnumKeyExA, Mine_RegEnumKeyExA) + && Mhook_SetHookEx(&Real_RegEnumKeyExW, Mine_RegEnumKeyExW) + && Mhook_SetHookEx(&Real_RegEnumValueA, Mine_RegEnumValueA) + && Mhook_SetHookEx(&Real_RegEnumValueW, Mine_RegEnumValueW) + && Mhook_SetHookEx(&Real_RegOpenKeyA, Mine_RegOpenKeyA) + && Mhook_SetHookEx(&Real_RegOpenKeyW, Mine_RegOpenKeyW) + && Mhook_SetHookEx(&Real_RegOpenKeyExA, Mine_RegOpenKeyExA) + && Mhook_SetHookEx(&Real_RegOpenKeyExW, Mine_RegOpenKeyExW) + && Mhook_SetHookEx(&Real_RegQueryInfoKeyA, Mine_RegQueryInfoKeyA) + && Mhook_SetHookEx(&Real_RegQueryInfoKeyW, Mine_RegQueryInfoKeyW) + && Mhook_SetHookEx(&Real_RegQueryValueA, Mine_RegQueryValueA) + && Mhook_SetHookEx(&Real_RegQueryValueW, Mine_RegQueryValueW) + && Mhook_SetHookEx(&Real_RegQueryValueExA, Mine_RegQueryValueExA) + && Mhook_SetHookEx(&Real_RegQueryValueExW, Mine_RegQueryValueExW) + && Mhook_SetHookEx(&Real_RegSetValueA, Mine_RegSetValueA) + && Mhook_SetHookEx(&Real_RegSetValueW, Mine_RegSetValueW) + && Mhook_SetHookEx(&Real_RegSetValueExA, Mine_RegSetValueExA) + && Mhook_SetHookEx(&Real_RegSetValueExW, Mine_RegSetValueExW); + s_bInitialized &= MH_EnableHook(MH_ALL_HOOKS) == MH_OK; + } +} + +CFilterMapper2::CFilterMapper2(bool bRefCounted, bool bAllowUnreg /*= false*/, LPUNKNOWN pUnkOuter /*= nullptr*/) + : CUnknown(NAME("CFilterMapper2"), pUnkOuter) + , m_bRefCounted(bRefCounted) + , m_bAllowUnreg(bAllowUnreg) +{ + m_cRef = bRefCounted ? 0 : 1; + + // We can't call Init() if more than one thread is running due to a custom optimization + // we use for mhook. Instead we ensure that the hooks were properly set up at startup + ENSURE(s_bInitialized); + + HRESULT hr = Real_CoCreateInstance(CLSID_FilterMapper2, (IUnknown*)(INonDelegatingUnknown*)this, + CLSCTX_ALL, IID_PPV_ARGS(&m_pFM2)); + if (FAILED(hr) || !m_pFM2) { + ASSERT(FALSE); + } +} + +CFilterMapper2::~CFilterMapper2() +{ + POSITION pos = m_filters.GetHeadPosition(); + while (pos) { + delete m_filters.GetNext(pos); + } +} + +STDMETHODIMP CFilterMapper2::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + if (riid == __uuidof(IFilterMapper2)) { + return GetInterface((IFilterMapper2*)this, ppv); + } + + HRESULT hr = m_pFM2 ? m_pFM2->QueryInterface(riid, ppv) : E_NOINTERFACE; + + return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv); +} + +void CFilterMapper2::Register(CString path) +{ + // Load filter + if (HMODULE h = LoadLibraryEx(path, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH)) { + typedef HRESULT(__stdcall * PDllRegisterServer)(); + if (PDllRegisterServer fpDllRegisterServer = (PDllRegisterServer)GetProcAddress(h, "DllRegisterServer")) { + ASSERT(!CFilterMapper2::s_pFilterMapper2); + + CFilterMapper2::s_pFilterMapper2 = this; + m_path = path; + fpDllRegisterServer(); + m_path.Empty(); + CFilterMapper2::s_pFilterMapper2 = nullptr; + } + + FreeLibrary(h); + } +} + +// IFilterMapper2 + +STDMETHODIMP CFilterMapper2::CreateCategory(REFCLSID clsidCategory, DWORD dwCategoryMerit, LPCWSTR Description) +{ + if (!m_path.IsEmpty()) { + return S_OK; + } else if (CComQIPtr pFM2 = m_pFM2) { + return pFM2->CreateCategory(clsidCategory, dwCategoryMerit, Description); + } + + return E_NOTIMPL; +} + +STDMETHODIMP CFilterMapper2::UnregisterFilter(const CLSID* pclsidCategory, const OLECHAR* szInstance, REFCLSID Filter) +{ + if (!m_path.IsEmpty()) { + return S_OK; + } else if (CComQIPtr pFM2 = m_pFM2) { + return m_bAllowUnreg ? pFM2->UnregisterFilter(pclsidCategory, szInstance, Filter) : S_OK; + } + + return E_NOTIMPL; +} + +STDMETHODIMP CFilterMapper2::RegisterFilter(REFCLSID clsidFilter, LPCWSTR Name, IMoniker** ppMoniker, const CLSID* pclsidCategory, const OLECHAR* szInstance, const REGFILTER2* prf2) +{ + if (!m_path.IsEmpty()) { + if (FilterOverride* f = DEBUG_NEW FilterOverride) { + f->fDisabled = false; + f->type = FilterOverride::EXTERNAL; + f->path = m_path; + f->name = CStringW(Name); + f->clsid = clsidFilter; + f->iLoadType = FilterOverride::MERIT; + f->dwMerit = prf2->dwMerit; + + if (prf2->dwVersion == 1) { + for (ULONG i = 0; i < prf2->cPins; i++) { + const REGFILTERPINS& rgPin = prf2->rgPins[i]; + if (rgPin.bOutput) { + continue; + } + + for (UINT j = 0; j < rgPin.nMediaTypes; j++) { + if (!rgPin.lpMediaType[j].clsMajorType || !rgPin.lpMediaType[j].clsMinorType) { + break; + } + f->guids.AddTail(*rgPin.lpMediaType[j].clsMajorType); + f->guids.AddTail(*rgPin.lpMediaType[j].clsMinorType); + } + } + } else if (prf2->dwVersion == 2) { + for (ULONG i = 0; i < prf2->cPins2; i++) { + const REGFILTERPINS2& rgPin = prf2->rgPins2[i]; + if (rgPin.dwFlags & REG_PINFLAG_B_OUTPUT) { + continue; + } + + for (UINT j = 0; j < rgPin.nMediaTypes; j++) { + if (!rgPin.lpMediaType[j].clsMajorType || !rgPin.lpMediaType[j].clsMinorType) { + break; + } + f->guids.AddTail(*rgPin.lpMediaType[j].clsMajorType); + f->guids.AddTail(*rgPin.lpMediaType[j].clsMinorType); + } + } + } + + f->backup.AddTailList(&f->guids); + + m_filters.AddTail(f); + } + + return S_OK; + } else if (CComQIPtr pFM2 = m_pFM2) { + return pFM2->RegisterFilter(clsidFilter, Name, ppMoniker, pclsidCategory, szInstance, prf2); + } + + return E_NOTIMPL; +} + +STDMETHODIMP CFilterMapper2::EnumMatchingFilters(IEnumMoniker** ppEnum, DWORD dwFlags, BOOL bExactMatch, DWORD dwMerit, + BOOL bInputNeeded, DWORD cInputTypes, const GUID* pInputTypes, const REGPINMEDIUM* pMedIn, const CLSID* pPinCategoryIn, BOOL bRender, + BOOL bOutputNeeded, DWORD cOutputTypes, const GUID* pOutputTypes, const REGPINMEDIUM* pMedOut, const CLSID* pPinCategoryOut) +{ + if (CComQIPtr pFM2 = m_pFM2) { + return pFM2->EnumMatchingFilters(ppEnum, dwFlags, bExactMatch, dwMerit, + bInputNeeded, cInputTypes, pInputTypes, pMedIn, pPinCategoryIn, bRender, + bOutputNeeded, cOutputTypes, pOutputTypes, pMedOut, pPinCategoryOut); + } + + return E_NOTIMPL; +} diff --git a/src/mpc-hc/FakeFilterMapper2.h b/src/mpc-hc/FakeFilterMapper2.h index 642d96d202b..70f8e2a86ed 100644 --- a/src/mpc-hc/FakeFilterMapper2.h +++ b/src/mpc-hc/FakeFilterMapper2.h @@ -1,99 +1,99 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include - - -class FilterOverride -{ -public: - bool fDisabled, fTemporary; - enum { REGISTERED, EXTERNAL } type; - // REGISTERED - CStringW dispname; - // EXTERNAL - CString path, name; - CLSID clsid; - // props - CAtlList guids, backup; - enum { PREFERRED, BLOCK, MERIT }; - int iLoadType; - DWORD dwMerit; - - FilterOverride() - : fDisabled(false) - , fTemporary(false) - , type(EXTERNAL) - , clsid(GUID_NULL) - , iLoadType(0) - , dwMerit(0) { - } - FilterOverride(FilterOverride* f) { - fDisabled = f->fDisabled; - fTemporary = f->fTemporary; - type = f->type; - dispname = f->dispname; - path = f->path; - name = f->name; - clsid = f->clsid; - guids.AddTailList(&f->guids); - backup.AddTailList(&f->backup); - iLoadType = f->iLoadType; - dwMerit = f->dwMerit; - } -}; - -class CFilterMapper2 : protected CUnknown, public IFilterMapper2 -{ - static bool s_bInitialized; - - CComPtr m_pFM2; - CString m_path; - - bool m_bRefCounted, m_bAllowUnreg; - -protected: - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IFilterMapper2 - - STDMETHODIMP CreateCategory(REFCLSID clsidCategory, DWORD dwCategoryMerit, LPCWSTR Description); - STDMETHODIMP UnregisterFilter(const CLSID* pclsidCategory, const OLECHAR* szInstance, REFCLSID Filter); - STDMETHODIMP RegisterFilter(REFCLSID clsidFilter, LPCWSTR Name, IMoniker** ppMoniker, const CLSID* pclsidCategory, const OLECHAR* szInstance, const REGFILTER2* prf2); - STDMETHODIMP EnumMatchingFilters(IEnumMoniker** ppEnum, DWORD dwFlags, BOOL bExactMatch, DWORD dwMerit, - BOOL bInputNeeded, DWORD cInputTypes, const GUID* pInputTypes, const REGPINMEDIUM* pMedIn, const CLSID* pPinCategoryIn, BOOL bRender, - BOOL bOutputNeeded, DWORD cOutputTypes, const GUID* pOutputTypes, const REGPINMEDIUM* pMedOut, const CLSID* pPinCategoryOut); - -public: - CFilterMapper2(bool bRefCounted, bool bAllowUnreg = false, LPUNKNOWN pUnkOuter = nullptr); - virtual ~CFilterMapper2(); - - void SetInner(IUnknown* pUnk) { m_pFM2 = pUnk; } - - static void Init(); - - static IFilterMapper2* s_pFilterMapper2; - CList m_filters; - void Register(CString path); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include + + +class FilterOverride +{ +public: + bool fDisabled, fTemporary; + enum { REGISTERED, EXTERNAL } type; + // REGISTERED + CStringW dispname; + // EXTERNAL + CString path, name; + CLSID clsid; + // props + CAtlList guids, backup; + enum { PREFERRED, BLOCK, MERIT }; + int iLoadType; + DWORD dwMerit; + + FilterOverride() + : fDisabled(false) + , fTemporary(false) + , type(EXTERNAL) + , clsid(GUID_NULL) + , iLoadType(0) + , dwMerit(0) { + } + FilterOverride(FilterOverride* f) { + fDisabled = f->fDisabled; + fTemporary = f->fTemporary; + type = f->type; + dispname = f->dispname; + path = f->path; + name = f->name; + clsid = f->clsid; + guids.AddTailList(&f->guids); + backup.AddTailList(&f->backup); + iLoadType = f->iLoadType; + dwMerit = f->dwMerit; + } +}; + +class CFilterMapper2 : protected CUnknown, public IFilterMapper2 +{ + static bool s_bInitialized; + + CComPtr m_pFM2; + CString m_path; + + bool m_bRefCounted, m_bAllowUnreg; + +protected: + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IFilterMapper2 + + STDMETHODIMP CreateCategory(REFCLSID clsidCategory, DWORD dwCategoryMerit, LPCWSTR Description); + STDMETHODIMP UnregisterFilter(const CLSID* pclsidCategory, const OLECHAR* szInstance, REFCLSID Filter); + STDMETHODIMP RegisterFilter(REFCLSID clsidFilter, LPCWSTR Name, IMoniker** ppMoniker, const CLSID* pclsidCategory, const OLECHAR* szInstance, const REGFILTER2* prf2); + STDMETHODIMP EnumMatchingFilters(IEnumMoniker** ppEnum, DWORD dwFlags, BOOL bExactMatch, DWORD dwMerit, + BOOL bInputNeeded, DWORD cInputTypes, const GUID* pInputTypes, const REGPINMEDIUM* pMedIn, const CLSID* pPinCategoryIn, BOOL bRender, + BOOL bOutputNeeded, DWORD cOutputTypes, const GUID* pOutputTypes, const REGPINMEDIUM* pMedOut, const CLSID* pPinCategoryOut); + +public: + CFilterMapper2(bool bRefCounted, bool bAllowUnreg = false, LPUNKNOWN pUnkOuter = nullptr); + virtual ~CFilterMapper2(); + + void SetInner(IUnknown* pUnk) { m_pFM2 = pUnk; } + + static void Init(); + + static IFilterMapper2* s_pFilterMapper2; + CList m_filters; + void Register(CString path); +}; diff --git a/src/mpc-hc/FavoriteAddDlg.cpp b/src/mpc-hc/FavoriteAddDlg.cpp index 60ddc27227d..06d1c4903e2 100644 --- a/src/mpc-hc/FavoriteAddDlg.cpp +++ b/src/mpc-hc/FavoriteAddDlg.cpp @@ -1,125 +1,125 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "FavoriteAddDlg.h" -#include "SettingsDefines.h" -#include "AppSettings.h" - -// CFavoriteAddDlg dialog - -CFavoriteAddDlg::CFavoriteAddDlg(CString shortname, CString fullname, - BOOL bEnableABMarks /*=FALSE*/, CWnd* pParent /*=nullptr*/) - : CMPCThemeResizableDialog(CFavoriteAddDlg::IDD, pParent) - , m_shortname(shortname) - , m_fullname(fullname) - , m_bEnableABMarks(bEnableABMarks) - , m_bRememberPos(TRUE) - , m_bRememberABMarks(FALSE) - , m_bRelativeDrive(FALSE) -{ -} - -CFavoriteAddDlg::~CFavoriteAddDlg() -{ -} - -void CFavoriteAddDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO1, m_namectrl); - DDX_CBString(pDX, IDC_COMBO1, m_name); - DDX_Check(pDX, IDC_CHECK1, m_bRememberPos); - DDX_Check(pDX, IDC_CHECK2, m_bRelativeDrive); - DDX_Check(pDX, IDC_CHECK3, m_bRememberABMarks); - fulfillThemeReqs(); -} - -BOOL CFavoriteAddDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - if (!m_shortname.IsEmpty()) { - m_namectrl.AddString(m_shortname); - } - - if (!m_fullname.IsEmpty()) { - m_namectrl.AddString(m_fullname); - } - - ::CorrectComboListWidth(m_namectrl); - - const CAppSettings& s = AfxGetAppSettings(); - - m_bRememberPos = s.bFavRememberPos; - m_bRelativeDrive = s.bFavRelativeDrive; - - if (m_bEnableABMarks) { - m_bRememberABMarks = s.bFavRememberABMarks; - } - GetDlgItem(IDC_CHECK3)->EnableWindow(m_bEnableABMarks); - - UpdateData(FALSE); // Update UI - - m_namectrl.SetCurSel(0); - - AddAnchor(IDC_COMBO1, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDOK, BOTTOM_RIGHT); - AddAnchor(IDCANCEL, BOTTOM_RIGHT); - - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - - -BEGIN_MESSAGE_MAP(CFavoriteAddDlg, CMPCThemeResizableDialog) - ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOk) -END_MESSAGE_MAP() - - -// CFavoriteAddDlg message handlers - -void CFavoriteAddDlg::OnUpdateOk(CCmdUI* pCmdUI) -{ - UpdateData(); // Retrieve UI values - - pCmdUI->Enable(!m_name.IsEmpty()); -} - -void CFavoriteAddDlg::OnOK() -{ - UpdateData(); // Retrieve UI values - - // Remember settings - CAppSettings& s = AfxGetAppSettings(); - - s.bFavRememberPos = !!m_bRememberPos; - s.bFavRelativeDrive = !!m_bRelativeDrive; - - if (m_bEnableABMarks) { - s.bFavRememberABMarks = !!m_bRememberABMarks; - } - - __super::OnOK(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "FavoriteAddDlg.h" +#include "SettingsDefines.h" +#include "AppSettings.h" + +// CFavoriteAddDlg dialog + +CFavoriteAddDlg::CFavoriteAddDlg(CString shortname, CString fullname, + BOOL bEnableABMarks /*=FALSE*/, CWnd* pParent /*=nullptr*/) + : CMPCThemeResizableDialog(CFavoriteAddDlg::IDD, pParent) + , m_shortname(shortname) + , m_fullname(fullname) + , m_bEnableABMarks(bEnableABMarks) + , m_bRememberPos(TRUE) + , m_bRememberABMarks(FALSE) + , m_bRelativeDrive(FALSE) +{ +} + +CFavoriteAddDlg::~CFavoriteAddDlg() +{ +} + +void CFavoriteAddDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO1, m_namectrl); + DDX_CBString(pDX, IDC_COMBO1, m_name); + DDX_Check(pDX, IDC_CHECK1, m_bRememberPos); + DDX_Check(pDX, IDC_CHECK2, m_bRelativeDrive); + DDX_Check(pDX, IDC_CHECK3, m_bRememberABMarks); + fulfillThemeReqs(); +} + +BOOL CFavoriteAddDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + if (!m_shortname.IsEmpty()) { + m_namectrl.AddString(m_shortname); + } + + if (!m_fullname.IsEmpty()) { + m_namectrl.AddString(m_fullname); + } + + ::CorrectComboListWidth(m_namectrl); + + const CAppSettings& s = AfxGetAppSettings(); + + m_bRememberPos = s.bFavRememberPos; + m_bRelativeDrive = s.bFavRelativeDrive; + + if (m_bEnableABMarks) { + m_bRememberABMarks = s.bFavRememberABMarks; + } + GetDlgItem(IDC_CHECK3)->EnableWindow(m_bEnableABMarks); + + UpdateData(FALSE); // Update UI + + m_namectrl.SetCurSel(0); + + AddAnchor(IDC_COMBO1, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDOK, BOTTOM_RIGHT); + AddAnchor(IDCANCEL, BOTTOM_RIGHT); + + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + + +BEGIN_MESSAGE_MAP(CFavoriteAddDlg, CMPCThemeResizableDialog) + ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOk) +END_MESSAGE_MAP() + + +// CFavoriteAddDlg message handlers + +void CFavoriteAddDlg::OnUpdateOk(CCmdUI* pCmdUI) +{ + UpdateData(); // Retrieve UI values + + pCmdUI->Enable(!m_name.IsEmpty()); +} + +void CFavoriteAddDlg::OnOK() +{ + UpdateData(); // Retrieve UI values + + // Remember settings + CAppSettings& s = AfxGetAppSettings(); + + s.bFavRememberPos = !!m_bRememberPos; + s.bFavRelativeDrive = !!m_bRelativeDrive; + + if (m_bEnableABMarks) { + s.bFavRememberABMarks = !!m_bRememberABMarks; + } + + __super::OnOK(); +} diff --git a/src/mpc-hc/FavoriteAddDlg.h b/src/mpc-hc/FavoriteAddDlg.h index 4dfea3e8a28..f83c98bf48b 100644 --- a/src/mpc-hc/FavoriteAddDlg.h +++ b/src/mpc-hc/FavoriteAddDlg.h @@ -1,54 +1,54 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "CMPCThemeResizableDialog.h" -#include "CMPCThemeComboBox.h" - -// CFavoriteAddDlg dialog - -class CFavoriteAddDlg : public CMPCThemeResizableDialog -{ -public: - CFavoriteAddDlg(CString shortname, CString fullname, BOOL bEnableABMarks = FALSE, CWnd* pParent = nullptr); // standard constructor - virtual ~CFavoriteAddDlg(); - - // Dialog Data - enum { IDD = IDD_FAVADD }; - - CString m_name; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual void OnOK(); - afx_msg void OnUpdateOk(CCmdUI* pCmdUI); - DECLARE_MESSAGE_MAP() - -private: - CMPCThemeComboBox m_namectrl; - CString m_shortname, m_fullname; - BOOL m_bEnableABMarks; - BOOL m_bRememberPos; - BOOL m_bRememberABMarks; - BOOL m_bRelativeDrive; -}; +/* + * (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 . + * + */ + +#pragma once + +#include "CMPCThemeResizableDialog.h" +#include "CMPCThemeComboBox.h" + +// CFavoriteAddDlg dialog + +class CFavoriteAddDlg : public CMPCThemeResizableDialog +{ +public: + CFavoriteAddDlg(CString shortname, CString fullname, BOOL bEnableABMarks = FALSE, CWnd* pParent = nullptr); // standard constructor + virtual ~CFavoriteAddDlg(); + + // Dialog Data + enum { IDD = IDD_FAVADD }; + + CString m_name; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual void OnOK(); + afx_msg void OnUpdateOk(CCmdUI* pCmdUI); + DECLARE_MESSAGE_MAP() + +private: + CMPCThemeComboBox m_namectrl; + CString m_shortname, m_fullname; + BOOL m_bEnableABMarks; + BOOL m_bRememberPos; + BOOL m_bRememberABMarks; + BOOL m_bRelativeDrive; +}; diff --git a/src/mpc-hc/FavoriteOrganizeDlg.cpp b/src/mpc-hc/FavoriteOrganizeDlg.cpp index ddaecb8bdab..8165f9a5f98 100644 --- a/src/mpc-hc/FavoriteOrganizeDlg.cpp +++ b/src/mpc-hc/FavoriteOrganizeDlg.cpp @@ -1,532 +1,532 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "FavoriteOrganizeDlg.h" -#include "mplayerc.h" -#include "MainFrm.h" -#include "CMPCTheme.h" -#undef SubclassWindow - -// CFavoriteOrganizeDlg dialog - -//IMPLEMENT_DYNAMIC(CFavoriteOrganizeDlg, CMPCThemeResizableDialog) -CFavoriteOrganizeDlg::CFavoriteOrganizeDlg(CWnd* pParent /*=nullptr*/) - : CModelessResizableDialog(CFavoriteOrganizeDlg::IDD, pParent) -{ -} - -CFavoriteOrganizeDlg::~CFavoriteOrganizeDlg() -{ -} - -void CFavoriteOrganizeDlg::SetupList(bool fSave) -{ - - int i = m_tab.GetCurSel(); - - if (fSave) { - CAtlList sl; - - for (int j = 0; j < m_list.GetItemCount(); j++) { - CAtlList args; - ExplodeEsc(m_sl[i].GetAt((POSITION)m_list.GetItemData(j)), args, _T(';')); - args.RemoveHead(); - args.AddHead(m_list.GetItemText(j, 0)); - sl.AddTail(ImplodeEsc(args, _T(';'))); - } - m_sl[i].RemoveAll(); - m_sl[i].AddTailList(&sl); - SetupList(false); //reload the list to invalide the old itemdata - } else { - m_list.SetRedraw(FALSE); - m_list.DeleteAllItems(); - - for(POSITION pos = m_sl[i].GetHeadPosition(), tmp; pos; ) { - tmp = pos; - - FileFavorite ff; - VERIFY(FileFavorite::TryParse(m_sl[i].GetNext(pos), ff)); - - int n = m_list.InsertItem(m_list.GetItemCount(), ff.Name); - m_list.SetItemData(n, (DWORD_PTR)tmp); - - CString str = ff.ToString(); - if (!str.IsEmpty()) { - m_list.SetItemText(n, 1, str); - } - } - - UpdateColumnsSizes(); - m_list.SetRedraw(TRUE); - m_list.RedrawWindow(0, 0, RDW_INVALIDATE); - } -} - -void CFavoriteOrganizeDlg::UpdateColumnsSizes() -{ - CRect r; - m_list.GetClientRect(r); - m_list.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER); - if (firstSize) { - m_list.SetColumnWidth(1, LVSCW_AUTOSIZE); //this is needed to calculate the min width, but don't keep resetting it or you get flicker - firstSize = false; - minSizeTime = m_list.GetColumnWidth(1); - } - m_list.SetColumnWidth(1, std::max(minSizeTime, r.Width() - m_list.GetColumnWidth(0))); -} - -void CFavoriteOrganizeDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Control(pDX, IDC_TAB1, m_tab); - DDX_Control(pDX, IDC_LIST2, m_list); -} - - -BEGIN_MESSAGE_MAP(CFavoriteOrganizeDlg, CModelessResizableDialog) - ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnTcnSelchangeTab1) - ON_WM_DRAWITEM() - ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST2, OnLvnItemchangedList2) - ON_BN_CLICKED(IDC_BUTTON1, OnRenameBnClicked) - ON_UPDATE_COMMAND_UI(IDC_BUTTON1, OnUpdateRenameBn) - ON_BN_CLICKED(IDC_BUTTON2, OnDeleteBnClicked) - ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateDeleteBn) - ON_BN_CLICKED(IDC_BUTTON3, OnUpBnClicked) - ON_UPDATE_COMMAND_UI(IDC_BUTTON3, OnUpdateUpBn) - ON_BN_CLICKED(IDC_BUTTON4, OnDownBnClicked) - ON_UPDATE_COMMAND_UI(IDC_BUTTON4, OnUpdateDownBn) - ON_NOTIFY(TCN_SELCHANGING, IDC_TAB1, OnTcnSelchangingTab1) - ON_BN_CLICKED(IDOK, OnBnClickedOk) - ON_WM_ACTIVATE() - ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST2, OnLvnEndlabeleditList2) - ON_NOTIFY(NM_DBLCLK, IDC_LIST2, OnPlayFavorite) - ON_NOTIFY(LVN_KEYDOWN, IDC_LIST2, OnKeyPressed) - ON_NOTIFY(LVN_GETINFOTIP, IDC_LIST2, OnLvnGetInfoTipList) - ON_WM_SIZE() -END_MESSAGE_MAP() - -void CFavoriteOrganizeDlg::OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult) { - CWnd::UpdateDialogControls(this, TRUE); //needed for modeless dialog due to no idle pump -} -// CFavoriteOrganizeDlg message handlers - -BOOL CFavoriteOrganizeDlg::OnInitDialog() -{ - __super::OnInitDialog(); - if (GetExStyle() & WS_EX_TOPMOST) { - if (auto tt = m_list.GetToolTips()) { //when dialog is topmost, tooltips appear behind the dialog? - tt->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOMOVE); - } - } - firstSize = true; - minSizeTime = 0; - m_tab.InsertItem(0, ResStr(IDS_FAVFILES)); - m_tab.InsertItem(1, ResStr(IDS_FAVDVDS)); - // m_tab.InsertItem(2, ResStr(IDS_FAVDEVICES)); - m_tab.SetCurSel(0); - - m_list.InsertColumn(0, _T("")); - m_list.InsertColumn(1, _T("")); - m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_INFOTIP); - m_list.setAdditionalStyles(LVS_EX_FULLROWSELECT); - - LoadList(); - - AddAnchor(IDC_TAB1, TOP_LEFT, BOTTOM_RIGHT); - AddAnchor(IDC_LIST2, TOP_LEFT, BOTTOM_RIGHT); - AddAnchor(IDC_BUTTON1, TOP_RIGHT); - AddAnchor(IDC_BUTTON2, TOP_RIGHT); - AddAnchor(IDC_BUTTON3, TOP_RIGHT); - AddAnchor(IDC_BUTTON4, TOP_RIGHT); - AddAnchor(IDOK, BOTTOM_RIGHT); - EnableSaveRestore(IDS_R_DLG_ORGANIZE_FAV); - fulfillThemeReqs(); - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CFavoriteOrganizeDlg::LoadList() { - const CAppSettings& s = AfxGetAppSettings(); - s.GetFav(FAV_FILE, m_sl[0]); - s.GetFav(FAV_DVD, m_sl[1]); - s.GetFav(FAV_DEVICE, m_sl[2]); - - SetupList(false); -} - -BOOL CFavoriteOrganizeDlg::PreTranslateMessage(MSG* pMsg) -{ - // Inhibit default handling for the Enter key when the list has the focus and an item is selected. - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN - && pMsg->hwnd == m_list.GetSafeHwnd() && m_list.GetSelectedCount() > 0) { - return FALSE; - } - - return __super::PreTranslateMessage(pMsg); -} - -void CFavoriteOrganizeDlg::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult) -{ - SetupList(false); - - m_list.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - - *pResult = 0; -} - -void CFavoriteOrganizeDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - if (nIDCtl != IDC_LIST2) { - return; - } - - int nItem = lpDrawItemStruct->itemID; - if (m_list.IsItemVisible(nItem)) { - CEdit* pEdit = m_list.GetEditControl(); - - CRect rcItem = lpDrawItemStruct->rcItem; - CRect rText, rTime, rectDC, rHighlight; - - m_list.GetSubItemRect(nItem, 0, LVIR_LABEL, rText); - rText.left += 2; //magic number for column 0 - m_list.GetSubItemRect(nItem, 1, LVIR_LABEL, rTime); - rTime.right -= 6; //magic number for column >0, from right - rectDC = rcItem; - rHighlight = rcItem; - rHighlight.left = rText.left; - rHighlight.right = rTime.right; - - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - int savedDC = pDC->SaveDC(); - bool isSelected = !!m_list.GetItemState(nItem, LVIS_SELECTED); - bool isEdited = pEdit && ::IsWindow(pEdit->m_hWnd) && isSelected; - - CDC dcMem; - CBitmap bmMem; - CMPCThemeUtil::initMemDC(pDC, dcMem, bmMem, rectDC); - rcItem.OffsetRect(-rectDC.TopLeft()); - rText.OffsetRect(-rectDC.TopLeft()); - rTime.OffsetRect(-rectDC.TopLeft()); - rHighlight.OffsetRect(-rectDC.TopLeft()); - - if (AppIsThemeLoaded()) { - dcMem.FillSolidRect(rcItem, CMPCTheme::ContentBGColor); - } else { - dcMem.FillSolidRect(rcItem, GetSysColor(COLOR_WINDOW)); - } - - if (isSelected) { - if (AppIsThemeLoaded()) { - dcMem.FillSolidRect(rHighlight, CMPCTheme::ContentSelectedColor); - } else { - CBrush b2; - dcMem.FillSolidRect(rHighlight, 0xf1dacc); - b2.CreateSolidBrush(0xc56a31); - dcMem.FrameRect(rHighlight, &b2); - b2.DeleteObject(); - } - } - - COLORREF textcolor; - if (AppIsThemeLoaded()) { - textcolor = CMPCTheme::TextFGColor; - } else { - textcolor = 0; - } - dcMem.SetTextColor(textcolor); - - CString str; - - if (!isEdited) { - str = m_list.GetItemText(nItem, 0); - dcMem.DrawTextW(str, rText, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX); - } - str = m_list.GetItemText(nItem, 1); - if (!str.IsEmpty()) { - dcMem.DrawTextW(str, rTime, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_RIGHT | DT_NOPREFIX); - } - if (isEdited) { //added to reduce flicker while editing. - CRect r; - pEdit->GetWindowRect(r); - m_list.ScreenToClient(r); - pDC->ExcludeClipRect(r); - } - CMPCThemeUtil::flushMemDC(pDC, dcMem, rectDC); - pDC->RestoreDC(savedDC); - } -} - -void CFavoriteOrganizeDlg::OnRenameBnClicked() -{ - if (POSITION pos = m_list.GetFirstSelectedItemPosition()) { - m_list.SetFocus(); - m_list.EditLabel(m_list.GetNextSelectedItem(pos)); - } -} - -void CFavoriteOrganizeDlg::OnUpdateRenameBn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_list.GetSelectedCount() == 1); -} - -void CFavoriteOrganizeDlg::OnLvnEndlabeleditList2(NMHDR* pNMHDR, LRESULT* pResult) -{ - NMLVDISPINFO* pDispInfo = reinterpret_cast(pNMHDR); - if (pDispInfo->item.iItem >= 0 && pDispInfo->item.pszText) { - m_list.SetItemText(pDispInfo->item.iItem, 0, pDispInfo->item.pszText); - } - UpdateColumnsSizes(); - - *pResult = 0; -} - -void CFavoriteOrganizeDlg::PlayFavorite(int nItem) -{ - switch (m_tab.GetCurSel()) { - case 0: // Files - ((CMainFrame*)GetParentFrame())->PlayFavoriteFile(m_sl[0].GetAt((POSITION)m_list.GetItemData(nItem))); - break; - case 1: // DVDs - ((CMainFrame*)GetParentFrame())->PlayFavoriteDVD(m_sl[1].GetAt((POSITION)m_list.GetItemData(nItem))); - break; - case 2: // Devices - break; - } -} - -void CFavoriteOrganizeDlg::OnPlayFavorite(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMITEMACTIVATE pItemActivate = reinterpret_cast(pNMHDR); - - if (pItemActivate->iItem >= 0) { - PlayFavorite(pItemActivate->iItem); - } -} - -void CFavoriteOrganizeDlg::OnKeyPressed(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR; - - switch (pLVKeyDow->wVKey) { - case VK_DELETE: - case VK_BACK: - OnDeleteBnClicked(); - *pResult = 1; - break; - case VK_RETURN: - if (POSITION pos = m_list.GetFirstSelectedItemPosition()) { - int nItem = m_list.GetNextSelectedItem(pos); - if (nItem >= 0 && nItem < m_list.GetItemCount()) { - PlayFavorite(nItem); - } - } - *pResult = 1; - break; - case 'A': - if (GetKeyState(VK_CONTROL) < 0) { // If the high-order bit is 1, the key is down; otherwise, it is up. - m_list.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED); - } - *pResult = 1; - break; - case 'I': - if (GetKeyState(VK_CONTROL) < 0) { // If the high-order bit is 1, the key is down; otherwise, it is up. - for (int nItem = 0; nItem < m_list.GetItemCount(); nItem++) { - m_list.SetItemState(nItem, ~m_list.GetItemState(nItem, LVIS_SELECTED), LVIS_SELECTED); - } - } - *pResult = 1; - break; - - case 'C': - if (GetKeyState(VK_CONTROL) < 0) { - if(m_tab.GetCurSel() == 0) { // Files - CopyToClipboard(); - } - } - *pResult = 1; - break; - default: - *pResult = 0; - } -} - -void CFavoriteOrganizeDlg::OnDeleteBnClicked() -{ - POSITION pos; - int nItem = -1; - - while ((pos = m_list.GetFirstSelectedItemPosition()) != nullptr) { - nItem = m_list.GetNextSelectedItem(pos); - if (nItem < 0 || nItem >= m_list.GetItemCount()) { - return; - } - - m_list.DeleteItem(nItem); - } - - nItem = std::min(nItem, m_list.GetItemCount() - 1); - m_list.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED); -} - -void CFavoriteOrganizeDlg::OnUpdateDeleteBn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_list.GetSelectedCount() > 0); -} - -void CFavoriteOrganizeDlg::MoveItem(int nItem, int offset) -{ - DWORD_PTR data = m_list.GetItemData(nItem); - CString strName = m_list.GetItemText(nItem, 0); - CString strPos = m_list.GetItemText(nItem, 1); - - m_list.DeleteItem(nItem); - - nItem += offset; - - m_list.InsertItem(nItem, strName); - m_list.SetItemData(nItem, data); - m_list.SetItemText(nItem, 1, strPos); - m_list.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED); -} - -void CFavoriteOrganizeDlg::OnUpBnClicked() -{ - POSITION pos = m_list.GetFirstSelectedItemPosition(); - - while (pos) { - int nItem = m_list.GetNextSelectedItem(pos); - if (nItem <= 0 || nItem >= m_list.GetItemCount()) { - return; - } - - MoveItem(nItem, -1); - } -} - -void CFavoriteOrganizeDlg::OnUpdateUpBn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_list.GetSelectedCount() > 0 && !m_list.GetItemState(0, LVIS_SELECTED)); -} - -void CFavoriteOrganizeDlg::OnDownBnClicked() -{ - CArray selectedItems; - POSITION pos = m_list.GetFirstSelectedItemPosition(); - - while (pos) { - int nItem = m_list.GetNextSelectedItem(pos); - if (nItem < 0 || nItem >= m_list.GetItemCount() - 1) { - return; - } - - selectedItems.Add(nItem); - } - - for (INT_PTR i = selectedItems.GetSize() - 1; i >= 0; i--) { - MoveItem(selectedItems[i], +1); - } -} - -void CFavoriteOrganizeDlg::OnUpdateDownBn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_list.GetSelectedCount() > 0 && !m_list.GetItemState(m_list.GetItemCount() - 1, LVIS_SELECTED)); -} - -void CFavoriteOrganizeDlg::OnTcnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult) -{ - SetupList(true); - - *pResult = 0; -} - -void CFavoriteOrganizeDlg::OnBnClickedOk() -{ - SetupList(true); - - CAppSettings& s = AfxGetAppSettings(); - s.SetFav(FAV_FILE, m_sl[0]); - s.SetFav(FAV_DVD, m_sl[1]); - s.SetFav(FAV_DEVICE, m_sl[2]); - - OnOK(); -} - -void CFavoriteOrganizeDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) -{ - __super::OnActivate(nState, pWndOther, bMinimized); - - if (nState == WA_ACTIVE) { - m_list.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - } -} - -void CFavoriteOrganizeDlg::OnSize(UINT nType, int cx, int cy) -{ - __super::OnSize(nType, cx, cy); - - if (IsWindow(m_list)) { - UpdateColumnsSizes(); //on first size, we need to call this, or it doesn't use the full window until a rename/resize - } -} - -void CFavoriteOrganizeDlg::OnLvnGetInfoTipList(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast(pNMHDR); - - CAtlList args; - ExplodeEsc(m_sl[m_tab.GetCurSel()].GetAt((POSITION)m_list.GetItemData(pGetInfoTip->iItem)), args, _T(';')); - CString path = args.RemoveTail(); - // Relative to drive value is always third. If less args are available that means it is not included. - int rootLength = (args.GetCount() == 3 && args.RemoveTail() != _T("0")) ? CPath(path).SkipRoot() : 0; - - StringCchCopyW(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path.Mid(rootLength)); - - *pResult = 0; -} - - -void CFavoriteOrganizeDlg::CopyToClipboard() -{ - CAtlList* pSL = &m_sl[m_tab.GetCurSel()]; - - // Iterate through selected items - CString favorites; - for(POSITION pos = m_list.GetFirstSelectedItemPosition(); pos; ) { - int iItem = m_list.GetNextSelectedItem(pos); - const CString& fav = pSL->GetAt((POSITION)m_list.GetItemData(iItem)); - CAtlList args; - ((CMainFrame*)GetParentFrame())->ParseFavoriteFile(fav, args); - - CString path = args.GetHead().Trim(); - if (!path.IsEmpty()) { - favorites.Append(path); - favorites.Append(_T("\r\n")); - } - } - - if (!favorites.IsEmpty()) { - CClipboard clipboard(this); - VERIFY(clipboard.SetText(favorites)); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "FavoriteOrganizeDlg.h" +#include "mplayerc.h" +#include "MainFrm.h" +#include "CMPCTheme.h" +#undef SubclassWindow + +// CFavoriteOrganizeDlg dialog + +//IMPLEMENT_DYNAMIC(CFavoriteOrganizeDlg, CMPCThemeResizableDialog) +CFavoriteOrganizeDlg::CFavoriteOrganizeDlg(CWnd* pParent /*=nullptr*/) + : CModelessResizableDialog(CFavoriteOrganizeDlg::IDD, pParent) +{ +} + +CFavoriteOrganizeDlg::~CFavoriteOrganizeDlg() +{ +} + +void CFavoriteOrganizeDlg::SetupList(bool fSave) +{ + + int i = m_tab.GetCurSel(); + + if (fSave) { + CAtlList sl; + + for (int j = 0; j < m_list.GetItemCount(); j++) { + CAtlList args; + ExplodeEsc(m_sl[i].GetAt((POSITION)m_list.GetItemData(j)), args, _T(';')); + args.RemoveHead(); + args.AddHead(m_list.GetItemText(j, 0)); + sl.AddTail(ImplodeEsc(args, _T(';'))); + } + m_sl[i].RemoveAll(); + m_sl[i].AddTailList(&sl); + SetupList(false); //reload the list to invalide the old itemdata + } else { + m_list.SetRedraw(FALSE); + m_list.DeleteAllItems(); + + for(POSITION pos = m_sl[i].GetHeadPosition(), tmp; pos; ) { + tmp = pos; + + FileFavorite ff; + VERIFY(FileFavorite::TryParse(m_sl[i].GetNext(pos), ff)); + + int n = m_list.InsertItem(m_list.GetItemCount(), ff.Name); + m_list.SetItemData(n, (DWORD_PTR)tmp); + + CString str = ff.ToString(); + if (!str.IsEmpty()) { + m_list.SetItemText(n, 1, str); + } + } + + UpdateColumnsSizes(); + m_list.SetRedraw(TRUE); + m_list.RedrawWindow(0, 0, RDW_INVALIDATE); + } +} + +void CFavoriteOrganizeDlg::UpdateColumnsSizes() +{ + CRect r; + m_list.GetClientRect(r); + m_list.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER); + if (firstSize) { + m_list.SetColumnWidth(1, LVSCW_AUTOSIZE); //this is needed to calculate the min width, but don't keep resetting it or you get flicker + firstSize = false; + minSizeTime = m_list.GetColumnWidth(1); + } + m_list.SetColumnWidth(1, std::max(minSizeTime, r.Width() - m_list.GetColumnWidth(0))); +} + +void CFavoriteOrganizeDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDC_TAB1, m_tab); + DDX_Control(pDX, IDC_LIST2, m_list); +} + + +BEGIN_MESSAGE_MAP(CFavoriteOrganizeDlg, CModelessResizableDialog) + ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, OnTcnSelchangeTab1) + ON_WM_DRAWITEM() + ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST2, OnLvnItemchangedList2) + ON_BN_CLICKED(IDC_BUTTON1, OnRenameBnClicked) + ON_UPDATE_COMMAND_UI(IDC_BUTTON1, OnUpdateRenameBn) + ON_BN_CLICKED(IDC_BUTTON2, OnDeleteBnClicked) + ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateDeleteBn) + ON_BN_CLICKED(IDC_BUTTON3, OnUpBnClicked) + ON_UPDATE_COMMAND_UI(IDC_BUTTON3, OnUpdateUpBn) + ON_BN_CLICKED(IDC_BUTTON4, OnDownBnClicked) + ON_UPDATE_COMMAND_UI(IDC_BUTTON4, OnUpdateDownBn) + ON_NOTIFY(TCN_SELCHANGING, IDC_TAB1, OnTcnSelchangingTab1) + ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_WM_ACTIVATE() + ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST2, OnLvnEndlabeleditList2) + ON_NOTIFY(NM_DBLCLK, IDC_LIST2, OnPlayFavorite) + ON_NOTIFY(LVN_KEYDOWN, IDC_LIST2, OnKeyPressed) + ON_NOTIFY(LVN_GETINFOTIP, IDC_LIST2, OnLvnGetInfoTipList) + ON_WM_SIZE() +END_MESSAGE_MAP() + +void CFavoriteOrganizeDlg::OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult) { + CWnd::UpdateDialogControls(this, TRUE); //needed for modeless dialog due to no idle pump +} +// CFavoriteOrganizeDlg message handlers + +BOOL CFavoriteOrganizeDlg::OnInitDialog() +{ + __super::OnInitDialog(); + if (GetExStyle() & WS_EX_TOPMOST) { + if (auto tt = m_list.GetToolTips()) { //when dialog is topmost, tooltips appear behind the dialog? + tt->SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOMOVE); + } + } + firstSize = true; + minSizeTime = 0; + m_tab.InsertItem(0, ResStr(IDS_FAVFILES)); + m_tab.InsertItem(1, ResStr(IDS_FAVDVDS)); + // m_tab.InsertItem(2, ResStr(IDS_FAVDEVICES)); + m_tab.SetCurSel(0); + + m_list.InsertColumn(0, _T("")); + m_list.InsertColumn(1, _T("")); + m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_INFOTIP); + m_list.setAdditionalStyles(LVS_EX_FULLROWSELECT); + + LoadList(); + + AddAnchor(IDC_TAB1, TOP_LEFT, BOTTOM_RIGHT); + AddAnchor(IDC_LIST2, TOP_LEFT, BOTTOM_RIGHT); + AddAnchor(IDC_BUTTON1, TOP_RIGHT); + AddAnchor(IDC_BUTTON2, TOP_RIGHT); + AddAnchor(IDC_BUTTON3, TOP_RIGHT); + AddAnchor(IDC_BUTTON4, TOP_RIGHT); + AddAnchor(IDOK, BOTTOM_RIGHT); + EnableSaveRestore(IDS_R_DLG_ORGANIZE_FAV); + fulfillThemeReqs(); + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CFavoriteOrganizeDlg::LoadList() { + const CAppSettings& s = AfxGetAppSettings(); + s.GetFav(FAV_FILE, m_sl[0]); + s.GetFav(FAV_DVD, m_sl[1]); + s.GetFav(FAV_DEVICE, m_sl[2]); + + SetupList(false); +} + +BOOL CFavoriteOrganizeDlg::PreTranslateMessage(MSG* pMsg) +{ + // Inhibit default handling for the Enter key when the list has the focus and an item is selected. + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN + && pMsg->hwnd == m_list.GetSafeHwnd() && m_list.GetSelectedCount() > 0) { + return FALSE; + } + + return __super::PreTranslateMessage(pMsg); +} + +void CFavoriteOrganizeDlg::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult) +{ + SetupList(false); + + m_list.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + + *pResult = 0; +} + +void CFavoriteOrganizeDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (nIDCtl != IDC_LIST2) { + return; + } + + int nItem = lpDrawItemStruct->itemID; + if (m_list.IsItemVisible(nItem)) { + CEdit* pEdit = m_list.GetEditControl(); + + CRect rcItem = lpDrawItemStruct->rcItem; + CRect rText, rTime, rectDC, rHighlight; + + m_list.GetSubItemRect(nItem, 0, LVIR_LABEL, rText); + rText.left += 2; //magic number for column 0 + m_list.GetSubItemRect(nItem, 1, LVIR_LABEL, rTime); + rTime.right -= 6; //magic number for column >0, from right + rectDC = rcItem; + rHighlight = rcItem; + rHighlight.left = rText.left; + rHighlight.right = rTime.right; + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + int savedDC = pDC->SaveDC(); + bool isSelected = !!m_list.GetItemState(nItem, LVIS_SELECTED); + bool isEdited = pEdit && ::IsWindow(pEdit->m_hWnd) && isSelected; + + CDC dcMem; + CBitmap bmMem; + CMPCThemeUtil::initMemDC(pDC, dcMem, bmMem, rectDC); + rcItem.OffsetRect(-rectDC.TopLeft()); + rText.OffsetRect(-rectDC.TopLeft()); + rTime.OffsetRect(-rectDC.TopLeft()); + rHighlight.OffsetRect(-rectDC.TopLeft()); + + if (AppIsThemeLoaded()) { + dcMem.FillSolidRect(rcItem, CMPCTheme::ContentBGColor); + } else { + dcMem.FillSolidRect(rcItem, GetSysColor(COLOR_WINDOW)); + } + + if (isSelected) { + if (AppIsThemeLoaded()) { + dcMem.FillSolidRect(rHighlight, CMPCTheme::ContentSelectedColor); + } else { + CBrush b2; + dcMem.FillSolidRect(rHighlight, 0xf1dacc); + b2.CreateSolidBrush(0xc56a31); + dcMem.FrameRect(rHighlight, &b2); + b2.DeleteObject(); + } + } + + COLORREF textcolor; + if (AppIsThemeLoaded()) { + textcolor = CMPCTheme::TextFGColor; + } else { + textcolor = 0; + } + dcMem.SetTextColor(textcolor); + + CString str; + + if (!isEdited) { + str = m_list.GetItemText(nItem, 0); + dcMem.DrawTextW(str, rText, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX); + } + str = m_list.GetItemText(nItem, 1); + if (!str.IsEmpty()) { + dcMem.DrawTextW(str, rTime, DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_RIGHT | DT_NOPREFIX); + } + if (isEdited) { //added to reduce flicker while editing. + CRect r; + pEdit->GetWindowRect(r); + m_list.ScreenToClient(r); + pDC->ExcludeClipRect(r); + } + CMPCThemeUtil::flushMemDC(pDC, dcMem, rectDC); + pDC->RestoreDC(savedDC); + } +} + +void CFavoriteOrganizeDlg::OnRenameBnClicked() +{ + if (POSITION pos = m_list.GetFirstSelectedItemPosition()) { + m_list.SetFocus(); + m_list.EditLabel(m_list.GetNextSelectedItem(pos)); + } +} + +void CFavoriteOrganizeDlg::OnUpdateRenameBn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_list.GetSelectedCount() == 1); +} + +void CFavoriteOrganizeDlg::OnLvnEndlabeleditList2(NMHDR* pNMHDR, LRESULT* pResult) +{ + NMLVDISPINFO* pDispInfo = reinterpret_cast(pNMHDR); + if (pDispInfo->item.iItem >= 0 && pDispInfo->item.pszText) { + m_list.SetItemText(pDispInfo->item.iItem, 0, pDispInfo->item.pszText); + } + UpdateColumnsSizes(); + + *pResult = 0; +} + +void CFavoriteOrganizeDlg::PlayFavorite(int nItem) +{ + switch (m_tab.GetCurSel()) { + case 0: // Files + ((CMainFrame*)GetParentFrame())->PlayFavoriteFile(m_sl[0].GetAt((POSITION)m_list.GetItemData(nItem))); + break; + case 1: // DVDs + ((CMainFrame*)GetParentFrame())->PlayFavoriteDVD(m_sl[1].GetAt((POSITION)m_list.GetItemData(nItem))); + break; + case 2: // Devices + break; + } +} + +void CFavoriteOrganizeDlg::OnPlayFavorite(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMITEMACTIVATE pItemActivate = reinterpret_cast(pNMHDR); + + if (pItemActivate->iItem >= 0) { + PlayFavorite(pItemActivate->iItem); + } +} + +void CFavoriteOrganizeDlg::OnKeyPressed(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR; + + switch (pLVKeyDow->wVKey) { + case VK_DELETE: + case VK_BACK: + OnDeleteBnClicked(); + *pResult = 1; + break; + case VK_RETURN: + if (POSITION pos = m_list.GetFirstSelectedItemPosition()) { + int nItem = m_list.GetNextSelectedItem(pos); + if (nItem >= 0 && nItem < m_list.GetItemCount()) { + PlayFavorite(nItem); + } + } + *pResult = 1; + break; + case 'A': + if (GetKeyState(VK_CONTROL) < 0) { // If the high-order bit is 1, the key is down; otherwise, it is up. + m_list.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED); + } + *pResult = 1; + break; + case 'I': + if (GetKeyState(VK_CONTROL) < 0) { // If the high-order bit is 1, the key is down; otherwise, it is up. + for (int nItem = 0; nItem < m_list.GetItemCount(); nItem++) { + m_list.SetItemState(nItem, ~m_list.GetItemState(nItem, LVIS_SELECTED), LVIS_SELECTED); + } + } + *pResult = 1; + break; + + case 'C': + if (GetKeyState(VK_CONTROL) < 0) { + if(m_tab.GetCurSel() == 0) { // Files + CopyToClipboard(); + } + } + *pResult = 1; + break; + default: + *pResult = 0; + } +} + +void CFavoriteOrganizeDlg::OnDeleteBnClicked() +{ + POSITION pos; + int nItem = -1; + + while ((pos = m_list.GetFirstSelectedItemPosition()) != nullptr) { + nItem = m_list.GetNextSelectedItem(pos); + if (nItem < 0 || nItem >= m_list.GetItemCount()) { + return; + } + + m_list.DeleteItem(nItem); + } + + nItem = std::min(nItem, m_list.GetItemCount() - 1); + m_list.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED); +} + +void CFavoriteOrganizeDlg::OnUpdateDeleteBn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_list.GetSelectedCount() > 0); +} + +void CFavoriteOrganizeDlg::MoveItem(int nItem, int offset) +{ + DWORD_PTR data = m_list.GetItemData(nItem); + CString strName = m_list.GetItemText(nItem, 0); + CString strPos = m_list.GetItemText(nItem, 1); + + m_list.DeleteItem(nItem); + + nItem += offset; + + m_list.InsertItem(nItem, strName); + m_list.SetItemData(nItem, data); + m_list.SetItemText(nItem, 1, strPos); + m_list.SetItemState(nItem, LVIS_SELECTED, LVIS_SELECTED); +} + +void CFavoriteOrganizeDlg::OnUpBnClicked() +{ + POSITION pos = m_list.GetFirstSelectedItemPosition(); + + while (pos) { + int nItem = m_list.GetNextSelectedItem(pos); + if (nItem <= 0 || nItem >= m_list.GetItemCount()) { + return; + } + + MoveItem(nItem, -1); + } +} + +void CFavoriteOrganizeDlg::OnUpdateUpBn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_list.GetSelectedCount() > 0 && !m_list.GetItemState(0, LVIS_SELECTED)); +} + +void CFavoriteOrganizeDlg::OnDownBnClicked() +{ + CArray selectedItems; + POSITION pos = m_list.GetFirstSelectedItemPosition(); + + while (pos) { + int nItem = m_list.GetNextSelectedItem(pos); + if (nItem < 0 || nItem >= m_list.GetItemCount() - 1) { + return; + } + + selectedItems.Add(nItem); + } + + for (INT_PTR i = selectedItems.GetSize() - 1; i >= 0; i--) { + MoveItem(selectedItems[i], +1); + } +} + +void CFavoriteOrganizeDlg::OnUpdateDownBn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_list.GetSelectedCount() > 0 && !m_list.GetItemState(m_list.GetItemCount() - 1, LVIS_SELECTED)); +} + +void CFavoriteOrganizeDlg::OnTcnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult) +{ + SetupList(true); + + *pResult = 0; +} + +void CFavoriteOrganizeDlg::OnBnClickedOk() +{ + SetupList(true); + + CAppSettings& s = AfxGetAppSettings(); + s.SetFav(FAV_FILE, m_sl[0]); + s.SetFav(FAV_DVD, m_sl[1]); + s.SetFav(FAV_DEVICE, m_sl[2]); + + OnOK(); +} + +void CFavoriteOrganizeDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) +{ + __super::OnActivate(nState, pWndOther, bMinimized); + + if (nState == WA_ACTIVE) { + m_list.SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } +} + +void CFavoriteOrganizeDlg::OnSize(UINT nType, int cx, int cy) +{ + __super::OnSize(nType, cx, cy); + + if (IsWindow(m_list)) { + UpdateColumnsSizes(); //on first size, we need to call this, or it doesn't use the full window until a rename/resize + } +} + +void CFavoriteOrganizeDlg::OnLvnGetInfoTipList(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast(pNMHDR); + + CAtlList args; + ExplodeEsc(m_sl[m_tab.GetCurSel()].GetAt((POSITION)m_list.GetItemData(pGetInfoTip->iItem)), args, _T(';')); + CString path = args.RemoveTail(); + // Relative to drive value is always third. If less args are available that means it is not included. + int rootLength = (args.GetCount() == 3 && args.RemoveTail() != _T("0")) ? CPath(path).SkipRoot() : 0; + + StringCchCopyW(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, path.Mid(rootLength)); + + *pResult = 0; +} + + +void CFavoriteOrganizeDlg::CopyToClipboard() +{ + CAtlList* pSL = &m_sl[m_tab.GetCurSel()]; + + // Iterate through selected items + CString favorites; + for(POSITION pos = m_list.GetFirstSelectedItemPosition(); pos; ) { + int iItem = m_list.GetNextSelectedItem(pos); + const CString& fav = pSL->GetAt((POSITION)m_list.GetItemData(iItem)); + CAtlList args; + ((CMainFrame*)GetParentFrame())->ParseFavoriteFile(fav, args); + + CString path = args.GetHead().Trim(); + if (!path.IsEmpty()) { + favorites.Append(path); + favorites.Append(_T("\r\n")); + } + } + + if (!favorites.IsEmpty()) { + CClipboard clipboard(this); + VERIFY(clipboard.SetText(favorites)); + } +} diff --git a/src/mpc-hc/FavoriteOrganizeDlg.h b/src/mpc-hc/FavoriteOrganizeDlg.h index b1235794cd7..00ea165aa33 100644 --- a/src/mpc-hc/FavoriteOrganizeDlg.h +++ b/src/mpc-hc/FavoriteOrganizeDlg.h @@ -1,84 +1,84 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "ModelessResizableDialog.h" -#include "CMPCThemeTabCtrl.h" -#include "CMPCThemePlayerListCtrl.h" - -// CFavoriteOrganizeDlg dialog - -class CFavoriteOrganizeDlg : public CModelessResizableDialog -{ - // DECLARE_DYNAMIC(CFavoriteOrganizeDlg) - -private: - CAtlList m_sl[3]; - -public: - CFavoriteOrganizeDlg(CWnd* pParent = nullptr); // standard constructor - virtual ~CFavoriteOrganizeDlg(); - - virtual BOOL PreTranslateMessage(MSG* pMsg); - - // Dialog Data - enum { IDD = IDD_FAVORGANIZE }; - - CMPCThemeTabCtrl m_tab; - CMPCThemePlayerListCtrl m_list; - bool firstSize=false; - int minSizeTime = 0; - void LoadList(); - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - - void SetupList(bool fSave); - - void UpdateColumnsSizes(); - void MoveItem(int nItem, int offset); - void PlayFavorite(int nItem); - void CopyToClipboard(); - - DECLARE_MESSAGE_MAP() -public: - afx_msg void OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); - afx_msg void OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnRenameBnClicked(); - afx_msg void OnUpdateRenameBn(CCmdUI* pCmdUI); - afx_msg void OnDeleteBnClicked(); - afx_msg void OnUpdateDeleteBn(CCmdUI* pCmdUI); - afx_msg void OnUpBnClicked(); - afx_msg void OnUpdateUpBn(CCmdUI* pCmdUI); - afx_msg void OnDownBnClicked(); - afx_msg void OnUpdateDownBn(CCmdUI* pCmdUI); - afx_msg void OnTcnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnBnClickedOk(); - afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); - afx_msg void OnLvnEndlabeleditList2(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnPlayFavorite(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnKeyPressed(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnLvnGetInfoTipList(NMHDR* pNMHDR, LRESULT* pResult); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "ModelessResizableDialog.h" +#include "CMPCThemeTabCtrl.h" +#include "CMPCThemePlayerListCtrl.h" + +// CFavoriteOrganizeDlg dialog + +class CFavoriteOrganizeDlg : public CModelessResizableDialog +{ + // DECLARE_DYNAMIC(CFavoriteOrganizeDlg) + +private: + CAtlList m_sl[3]; + +public: + CFavoriteOrganizeDlg(CWnd* pParent = nullptr); // standard constructor + virtual ~CFavoriteOrganizeDlg(); + + virtual BOOL PreTranslateMessage(MSG* pMsg); + + // Dialog Data + enum { IDD = IDD_FAVORGANIZE }; + + CMPCThemeTabCtrl m_tab; + CMPCThemePlayerListCtrl m_list; + bool firstSize=false; + int minSizeTime = 0; + void LoadList(); + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + + void SetupList(bool fSave); + + void UpdateColumnsSizes(); + void MoveItem(int nItem, int offset); + void PlayFavorite(int nItem); + void CopyToClipboard(); + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); + afx_msg void OnLvnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnRenameBnClicked(); + afx_msg void OnUpdateRenameBn(CCmdUI* pCmdUI); + afx_msg void OnDeleteBnClicked(); + afx_msg void OnUpdateDeleteBn(CCmdUI* pCmdUI); + afx_msg void OnUpBnClicked(); + afx_msg void OnUpdateUpBn(CCmdUI* pCmdUI); + afx_msg void OnDownBnClicked(); + afx_msg void OnUpdateDownBn(CCmdUI* pCmdUI); + afx_msg void OnTcnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnBnClickedOk(); + afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); + afx_msg void OnLvnEndlabeleditList2(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnPlayFavorite(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnKeyPressed(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnLvnGetInfoTipList(NMHDR* pNMHDR, LRESULT* pResult); +}; diff --git a/src/mpc-hc/FileAssoc.cpp b/src/mpc-hc/FileAssoc.cpp index b09c5713db9..77fe30ee093 100644 --- a/src/mpc-hc/FileAssoc.cpp +++ b/src/mpc-hc/FileAssoc.cpp @@ -1,744 +1,744 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include -#include "mplayerc.h" -#include "FileAssoc.h" -#include "resource.h" -#include "PathUtils.h" - - -// TODO: change this along with the root key for settings and the mutex name to -// avoid possible risks of conflict with the old MPC (non HC version). -#ifdef _WIN64 -#define PROGID _T("mplayerc64") -#else -#define PROGID _T("mplayerc") -#endif // _WIN64 - -CFileAssoc::IconLib::IconLib(GetIconIndexFunc fnGetIconIndex, GetIconLibVersionFunc fnGetIconLibVersion, HMODULE hLib) - : m_fnGetIconIndex(fnGetIconIndex) - , m_fnGetIconLibVersion(fnGetIconLibVersion) - , m_hLib(hLib) -{ - ASSERT(fnGetIconIndex && fnGetIconLibVersion && hLib); -} - -CFileAssoc::IconLib::~IconLib() -{ - VERIFY(FreeLibrary(m_hLib)); -} - -int CFileAssoc::IconLib::GetIconIndex(const CString& str) const -{ - return m_fnGetIconIndex(str); -} - -UINT CFileAssoc::IconLib::GetVersion() const -{ - return m_fnGetIconLibVersion(); -} - -void CFileAssoc::IconLib::SaveVersion() const -{ - AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ICON_LIB_VERSION, m_fnGetIconLibVersion()); -} - -CFileAssoc::CFileAssoc() - : m_iconLibPath(PathUtils::CombinePaths(PathUtils::GetProgramPath(), _T("mpciconlib.dll"))) - , m_strRegisteredAppName(_T("Media Player Classic")) - , m_strOldAssocKey(_T("PreviousRegistration")) - , m_strRegisteredAppKey(_T("Software\\Clients\\Media\\Media Player Classic\\Capabilities")) - , m_strRegAppFileAssocKey(_T("Software\\Clients\\Media\\Media Player Classic\\Capabilities\\FileAssociations")) - , m_strOpenCommand(_T("\"") + PathUtils::GetProgramPath(true) + _T("\" \"%1\"")) - , m_strEnqueueCommand(_T("\"") + PathUtils::GetProgramPath(true) + _T("\" /add \"%1\"")) - , m_bNoRecentDocs(false) - , m_checkIconsAssocInactiveEvent(TRUE, TRUE) // initially set, manual reset -{ - // Default manager (requires at least Vista) - VERIFY(CoCreateInstance(CLSID_ApplicationAssociationRegistration, nullptr, - CLSCTX_INPROC, IID_PPV_ARGS(&m_pAAR)) != CO_E_NOTINITIALIZED); - - m_handlers[0] = { _T("VideoFiles"), _T(" %1"), IDS_AUTOPLAY_PLAYVIDEO }; - m_handlers[1] = { _T("MusicFiles"), _T(" %1"), IDS_AUTOPLAY_PLAYMUSIC }; - m_handlers[2] = { _T("CDAudio"), _T(" %1 /cd"), IDS_AUTOPLAY_PLAYAUDIOCD }; - m_handlers[3] = { _T("DVDMovie"), _T(" %1 /dvd"), IDS_AUTOPLAY_PLAYDVDMOVIE }; -} - -CFileAssoc::~CFileAssoc() -{ - HANDLE hEvent = m_checkIconsAssocInactiveEvent; - DWORD dwEvent; - VERIFY(CoWaitForMultipleHandles(0, INFINITE, 1, &hEvent, &dwEvent) == S_OK); -} - -std::shared_ptr CFileAssoc::GetIconLib() const -{ - std::shared_ptr ret; - if (HMODULE hLib = LoadLibrary(m_iconLibPath)) { - auto fnGetIconIndex = reinterpret_cast(GetProcAddress(hLib, "GetIconIndex")); - auto fnGetIconLibVersion = reinterpret_cast(GetProcAddress(hLib, "GetIconLibVersion")); - if (fnGetIconIndex && fnGetIconLibVersion) { - ret = std::make_shared(fnGetIconIndex, fnGetIconLibVersion, hLib); - } else { - VERIFY(FreeLibrary(hLib)); - } - } - return ret; -} - -void CFileAssoc::SetNoRecentDocs(bool bNoRecentDocs, bool bUpdateAssocs /*= false*/) -{ - if (bNoRecentDocs == m_bNoRecentDocs) { - bUpdateAssocs = false; - } else { - m_bNoRecentDocs = bNoRecentDocs; - } - - CAtlList exts; - if (bUpdateAssocs && GetAssociatedExtensionsFromRegistry(exts)) { - CRegKey key; - POSITION pos = exts.GetHeadPosition(); - while (pos) { - const CString& ext = exts.GetNext(pos); - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, PROGID + ext)) { - if (m_bNoRecentDocs) { - key.SetStringValue(_T("NoRecentDocs"), _T("")); - } else { - key.DeleteValue(_T("NoRecentDocs")); - } - } - } - } -} - -bool CFileAssoc::RegisterApp() -{ - bool success = false; - - if (m_pAAR) { - CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); - - // Register MPC-HC for the windows "Default application" manager - CRegKey key; - - if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\RegisteredApplications"))) { - key.SetStringValue(_T("Media Player Classic"), m_strRegisteredAppKey); - - if (ERROR_SUCCESS == key.Create(HKEY_LOCAL_MACHINE, m_strRegisteredAppKey)) { - // ==>> TODO icon !!! - key.SetStringValue(_T("ApplicationDescription"), ResStr(IDS_APP_DESCRIPTION), REG_EXPAND_SZ); - key.SetStringValue(_T("ApplicationIcon"), appIcon, REG_EXPAND_SZ); - key.SetStringValue(_T("ApplicationName"), ResStr(IDR_MAINFRAME), REG_EXPAND_SZ); - - success = true; - } - } - } - - return success; -} - -bool CFileAssoc::Register(CString ext, CString strLabel, bool bRegister, bool bAddEnqueueContextMenu, bool bAssociatedWithIcon) -{ - CRegKey key; - CString strProgID = PROGID + ext; - - if (!bRegister) { - // On Windows 8, an app can't set itself as the default handler for a format - if (!IsWindows8OrGreater() && bRegister != IsRegistered(ext)) { - SetFileAssociation(ext, strProgID, bRegister); - } - - key.Attach(HKEY_CLASSES_ROOT); - key.RecurseDeleteKey(strProgID); - - if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, m_strRegAppFileAssocKey)) { - key.DeleteValue(ext); - } - - return true; - } else { - // Create ProgID for this file type - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID) - || ERROR_SUCCESS != key.SetStringValue(nullptr, strLabel)) { - return false; - } - - if (m_bNoRecentDocs) { - key.SetStringValue(_T("NoRecentDocs"), _T("")); - } else { - key.DeleteValue(_T("NoRecentDocs")); - } - - CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); - - // Add to playlist option - if (bAddEnqueueContextMenu) { - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, ResStr(IDS_ADD_TO_PLAYLIST)) - || ERROR_SUCCESS != key.SetStringValue(_T("Icon"), appIcon) - || ERROR_SUCCESS != key.SetStringValue(_T("MultiSelectModel"), _T("Player")) - || ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue\\command")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, m_strEnqueueCommand)) { - return false; - } - } else { - key.Close(); - key.Attach(HKEY_CLASSES_ROOT); - key.RecurseDeleteKey(strProgID + _T("\\shell\\enqueue")); - } - - // Play option - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open"))) { - return false; - } - if (ERROR_SUCCESS != key.SetStringValue(nullptr, ResStr(IDS_OPEN_WITH_MPC)) - || ERROR_SUCCESS != key.SetStringValue(_T("MultiSelectModel"), _T("Player")) - || ERROR_SUCCESS != key.SetStringValue(_T("Icon"), appIcon)) { - return false; - } - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open\\command")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, m_strOpenCommand)) { - return false; - } - - if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, m_strRegAppFileAssocKey) - || key.SetStringValue(ext, strProgID)) { - return false; - } - - if (bAssociatedWithIcon) { - if (auto iconLib = GetIconLib()) { - int iconIndex = iconLib->GetIconIndex(ext); - - /* icon_index value -1 means no icon was found in the iconlib for the file extension */ - if (iconIndex >= 0 && ExtractIcon(AfxGetApp()->m_hInstance, m_iconLibPath, iconIndex)) { - appIcon.Format(_T("\"%s\",%d"), m_iconLibPath.GetString(), iconIndex); - } - } - - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\DefaultIcon")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, appIcon)) { - return false; - } - } else { - key.Close(); - key.Attach(HKEY_CLASSES_ROOT); - key.RecurseDeleteKey(strProgID + _T("\\DefaultIcon")); - } - - // On Windows 8, an app can't set itself as the default handler for a format - if (!IsWindows8OrGreater() && bRegister != IsRegistered(ext)) { - SetFileAssociation(ext, strProgID, bRegister); - } - - return true; - } -} - -bool CFileAssoc::SetFileAssociation(CString strExt, CString strProgID, bool bRegister) -{ - CString extOldReg; - CRegKey key; - HRESULT hr = S_OK; - TCHAR buff[MAX_PATH]; - ULONG len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - - if (m_pAAR) { - // The Windows 7 way - CString strNewApp; - if (bRegister) { - // Create non existing file type - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strExt)) { - return false; - } - - CComHeapPtr pszCurrentAssociation; - // Save the application currently associated - if (SUCCEEDED(m_pAAR->QueryCurrentDefault(strExt, AT_FILEEXTENSION, AL_EFFECTIVE, &pszCurrentAssociation))) { - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID)) { - return false; - } - - key.SetStringValue(m_strOldAssocKey, pszCurrentAssociation); - } - strNewApp = m_strRegisteredAppName; - } else { - if (ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, strProgID)) { - return false; - } - - if (ERROR_SUCCESS == key.QueryStringValue(m_strOldAssocKey, buff, &len)) { - strNewApp = buff; - } - } - - hr = m_pAAR->SetAppAsDefault(strNewApp, strExt, AT_FILEEXTENSION); - } - - return SUCCEEDED(hr); -} - -bool CFileAssoc::IsRegistered(CString ext) const -{ - BOOL bIsDefault = FALSE; - CString strProgID = PROGID + ext; - - if (IsWindows8OrGreater()) { - bIsDefault = TRUE; // Check only if MPC-HC is registered as able to handle that format, not if it's the default. - } else if (m_pAAR) { - m_pAAR->QueryAppIsDefault(ext, AT_FILEEXTENSION, AL_EFFECTIVE, m_strRegisteredAppName, &bIsDefault); - } - - // Check if association is for this instance of MPC-HC - if (bIsDefault) { - CRegKey key; - TCHAR buff[MAX_PATH]; - ULONG len = _countof(buff); - - bIsDefault = FALSE; - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open\\command"), KEY_READ)) { - if (ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len)) { - bIsDefault = (m_strOpenCommand.CompareNoCase(CString(buff)) == 0); - } - } - } - - return !!bIsDefault; -} - -bool CFileAssoc::HasEnqueueContextMenuEntry(CString strExt) const -{ - CRegKey key; - CString strProgID = PROGID + strExt; - - return (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue"), KEY_READ)); -} - -bool CFileAssoc::Register(const CMediaFormatCategory& mfc, bool bRegister, bool bAddEnqueueContextMenu, bool bAssociatedWithIcon) -{ - if (!mfc.IsAssociable()) { - ASSERT(FALSE); - return false; - } - - CAtlList exts; - ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); - - CString strLabel = mfc.GetDescription(); - bool res = true; - - POSITION pos = exts.GetHeadPosition(); - while (pos) { - res &= Register(exts.GetNext(pos), strLabel, bRegister, bAddEnqueueContextMenu, bAssociatedWithIcon); - } - - return res; -} - -CFileAssoc::reg_state_t CFileAssoc::IsRegistered(const CMediaFormatCategory& mfc) const -{ - CAtlList exts; - ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); - - size_t cnt = 0; - - POSITION pos = exts.GetHeadPosition(); - while (pos) { - if (CFileAssoc::IsRegistered(exts.GetNext(pos))) { - cnt++; - } - } - - reg_state_t res; - if (cnt == 0) { - res = NOT_REGISTERED; - } else if (cnt == exts.GetCount()) { - res = ALL_REGISTERED; - } else { - res = SOME_REGISTERED; - } - - return res; -} - -CFileAssoc::reg_state_t CFileAssoc::HasAnyEnqueueContextMenuEntries(const CMediaFormatCategory& mfc) const -{ - CAtlList exts; - ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); - - size_t cnt = 0; - - POSITION pos = exts.GetHeadPosition(); - while (pos) { - if (CFileAssoc::HasEnqueueContextMenuEntry(exts.GetNext(pos))) { - cnt++; - } - } - - reg_state_t res; - if (cnt == 0) { - res = NOT_REGISTERED; - } else if (cnt == exts.GetCount()) { - res = ALL_REGISTERED; - } else { - res = SOME_REGISTERED; - } - - return res; -} - -bool CFileAssoc::RegisterFolderContextMenuEntries(bool bRegister) -{ - CRegKey key; - bool success; - - if (bRegister) { - success = false; - - CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); - - if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".enqueue"))) { - key.SetStringValue(nullptr, ResStr(IDS_ADD_TO_PLAYLIST)); - key.SetStringValue(_T("Icon"), appIcon); - - if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".enqueue\\command"))) { - key.SetStringValue(nullptr, m_strEnqueueCommand); - success = true; - } - } - - if (success && ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play"))) { - success = false; - - key.SetStringValue(nullptr, ResStr(IDS_OPEN_WITH_MPC)); - key.SetStringValue(_T("Icon"), appIcon); - - if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play\\command"))) { - key.SetStringValue(nullptr, m_strOpenCommand); - success = true; - } - } - - } else { - key.Attach(HKEY_CLASSES_ROOT); - success = (ERROR_SUCCESS == key.RecurseDeleteKey(_T("Directory\\shell\\") PROGID _T(".enqueue"))); - success &= (ERROR_SUCCESS == key.RecurseDeleteKey(_T("Directory\\shell\\") PROGID _T(".play"))); - } - - return success; -} - -bool CFileAssoc::AreRegisteredFolderContextMenuEntries() const -{ - CRegKey key; - TCHAR buff[MAX_PATH]; - ULONG len = _countof(buff); - bool registered = false; - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play\\command"), KEY_READ)) { - if (ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len)) { - registered = (m_strOpenCommand.CompareNoCase(CString(buff)) == 0); - } - } - - return registered; -} - -bool CFileAssoc::RegisterAutoPlay(autoplay_t ap, bool bRegister) -{ - CString exe = PathUtils::GetProgramPath(true); - - size_t i = (size_t)ap; - if (i >= m_handlers.size()) { - return false; - } - - CRegKey key; - - if (bRegister) { - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, _T("MediaPlayerClassic.Autorun"))) { - return false; - } - key.Close(); - - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, - _T("MediaPlayerClassic.Autorun\\Shell\\Play") + m_handlers[i].verb + _T("\\Command"))) { - return false; - } - key.SetStringValue(nullptr, _T("\"") + exe + _T("\"") + m_handlers[i].cmd); - key.Close(); - - if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\Handlers\\MPCPlay") + m_handlers[i].verb + _T("OnArrival"))) { - return false; - } - key.SetStringValue(_T("Action"), ResStr(m_handlers[i].action)); - key.SetStringValue(_T("Provider"), _T("Media Player Classic")); - key.SetStringValue(_T("InvokeProgID"), _T("MediaPlayerClassic.Autorun")); - key.SetStringValue(_T("InvokeVerb"), _T("Play") + m_handlers[i].verb); - key.SetStringValue(_T("DefaultIcon"), exe + _T(",0")); - key.Close(); - - if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"))) { - return false; - } - key.SetStringValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival"), _T("")); - key.Close(); - } else { - if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"))) { - return false; - } - key.DeleteValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival")); - key.Close(); - } - - return true; -} - -bool CFileAssoc::IsAutoPlayRegistered(autoplay_t ap) const -{ - ULONG len; - TCHAR buff[MAX_PATH]; - CString exe = PathUtils::GetProgramPath(true); - - size_t i = (size_t)ap; - if (i >= m_handlers.size()) { - return false; - } - - CRegKey key; - - if (ERROR_SUCCESS != key.Open(HKEY_LOCAL_MACHINE, - _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"), - KEY_READ)) { - return false; - } - len = _countof(buff); - if (ERROR_SUCCESS != key.QueryStringValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival"), buff, &len)) { - return false; - } - key.Close(); - - if (ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, - _T("MediaPlayerClassic.Autorun\\Shell\\Play") + m_handlers[i].verb + _T("\\Command"), - KEY_READ)) { - return false; - } - len = _countof(buff); - if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len)) { - return false; - } - if (_tcsnicmp(_T("\"") + exe, buff, exe.GetLength() + 1)) { - return false; - } - key.Close(); - - return true; -} - -bool CFileAssoc::GetAssociatedExtensions(const CMediaFormats& mf, CAtlList& exts) const -{ - exts.RemoveAll(); - - CAtlList mfcExts; - for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { - ExplodeMin(mf[i].GetExtsWithPeriod(), mfcExts, _T(' ')); - - POSITION pos = mfcExts.GetHeadPosition(); - while (pos) { - const CString ext = mfcExts.GetNext(pos); - if (IsRegistered(ext)) { - exts.AddTail(ext); - } - } - } - - return !exts.IsEmpty(); -} - -bool CFileAssoc::GetAssociatedExtensionsFromRegistry(CAtlList& exts) const -{ - exts.RemoveAll(); - - CRegKey rkHKCR(HKEY_CLASSES_ROOT); - LONG ret; - DWORD i = 0; - CString keyName, ext; - DWORD len = MAX_PATH; - - while ((ret = rkHKCR.EnumKey(i, keyName.GetBuffer(len), &len)) != ERROR_NO_MORE_ITEMS) { - if (ret == ERROR_SUCCESS) { - keyName.ReleaseBuffer(len); - - if (keyName.Find(PROGID) == 0) { - ext = keyName.Mid(_countof(PROGID) - 1); - - if (IsRegistered(ext)) { - exts.AddTail(ext); - } - } - - i++; - len = MAX_PATH; - } - } - - return !exts.IsEmpty(); -} - -bool CFileAssoc::ReAssocIcons(const CAtlList& exts) -{ - auto iconLib = GetIconLib(); - if (!iconLib) { - return false; - } - iconLib->SaveVersion(); - - const CString progPath = PathUtils::GetProgramPath(true); - - CRegKey key; - - POSITION pos = exts.GetHeadPosition(); - while (pos) { - const CString ext = exts.GetNext(pos); - const CString strProgID = PROGID + ext; - CString appIcon; - - int iconIndex = iconLib->GetIconIndex(ext); - - /* icon_index value -1 means no icon was found in the iconlib for the file extension */ - if (iconIndex >= 0 && ExtractIcon(AfxGetApp()->m_hInstance, m_iconLibPath, iconIndex)) { - appIcon.Format(_T("\"%s\",%d"), m_iconLibPath.GetString(), iconIndex); - } - - /* no icon was found for the file extension, so use MPC-HC's icon */ - if (appIcon.IsEmpty()) { - appIcon = _T("\"") + progPath + _T("\",0"); - } - - if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\DefaultIcon")) - || ERROR_SUCCESS != key.SetStringValue(nullptr, appIcon)) { - return false; - } - - key.Close(); - } - - return true; -} - -static HRESULT CALLBACK TaskDialogCallbackProc(HWND hwnd, UINT uNotification, WPARAM wParam, LPARAM lParam, LONG_PTR dwRefData) -{ - if (TDN_CREATED == uNotification) { - SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); - } - - return S_OK; -} - -void CFileAssoc::CheckIconsAssocThread() -{ - UINT nLastVersion = AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ICON_LIB_VERSION, 0); - - if (auto iconLib = GetIconLib()) { - UINT nCurrentVersion = iconLib->GetVersion(); - - CAtlList registeredExts; - - if (nCurrentVersion != nLastVersion && GetAssociatedExtensionsFromRegistry(registeredExts)) { - iconLib->SaveVersion(); - if (!IsUserAnAdmin()) { - TASKDIALOGCONFIG config; - ZeroMemory(&config, sizeof(TASKDIALOGCONFIG)); - config.cbSize = sizeof(config); - config.hInstance = AfxGetInstanceHandle(); - config.hwndParent = AfxGetApp()->GetMainWnd()->GetSafeHwnd(); - config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; - config.pszMainIcon = TD_SHIELD_ICON; - config.pszWindowTitle = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_TITLE); - config.pszMainInstruction = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_INSTR); - config.pszContent = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_CONTENT); - config.pfCallback = TaskDialogCallbackProc; - - typedef HRESULT(_stdcall * pfTaskDialogIndirect)(const TASKDIALOGCONFIG*, int*, int*, BOOL*); - - HMODULE hModule = ::LoadLibrary(_T("comctl32.dll")); - if (hModule) { - pfTaskDialogIndirect TaskDialogIndirect = (pfTaskDialogIndirect)(::GetProcAddress(hModule, "TaskDialogIndirect")); - - if (TaskDialogIndirect) { - int nButtonPressed = 0; - TaskDialogIndirect(&config, &nButtonPressed, nullptr, nullptr); - - if (IDYES == nButtonPressed) { - AfxGetMyApp()->RunAsAdministrator(PathUtils::GetProgramPath(true), _T("/iconsassoc"), true); - } - } - - ::FreeLibrary(hModule); - } - } else { - ReAssocIcons(registeredExts); - - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); - } - } - } - - m_checkIconsAssocInactiveEvent.Set(); -} - -void CFileAssoc::CheckIconsAssoc() -{ - std::lock_guard lock(m_checkIconsAssocMutex); - HANDLE hEvent = m_checkIconsAssocInactiveEvent; - DWORD dwEvent; - VERIFY(CoWaitForMultipleHandles(0, INFINITE, 1, &hEvent, &dwEvent) == S_OK); - m_checkIconsAssocInactiveEvent.Reset(); - try { - std::thread([this] { CheckIconsAssocThread(); }).detach(); - } catch (...) {} -} - -bool CFileAssoc::ShowWindowsAssocDialog() const -{ - IApplicationAssociationRegistrationUI* pAARUI; - HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI, - nullptr, - CLSCTX_INPROC, - IID_PPV_ARGS(&pAARUI)); - - bool success = (SUCCEEDED(hr) && pAARUI != nullptr); - - if (success) { - pAARUI->LaunchAdvancedAssociationUI(m_strRegisteredAppName); - pAARUI->Release(); - } - - return success; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include +#include "mplayerc.h" +#include "FileAssoc.h" +#include "resource.h" +#include "PathUtils.h" + + +// TODO: change this along with the root key for settings and the mutex name to +// avoid possible risks of conflict with the old MPC (non HC version). +#ifdef _WIN64 +#define PROGID _T("mplayerc64") +#else +#define PROGID _T("mplayerc") +#endif // _WIN64 + +CFileAssoc::IconLib::IconLib(GetIconIndexFunc fnGetIconIndex, GetIconLibVersionFunc fnGetIconLibVersion, HMODULE hLib) + : m_fnGetIconIndex(fnGetIconIndex) + , m_fnGetIconLibVersion(fnGetIconLibVersion) + , m_hLib(hLib) +{ + ASSERT(fnGetIconIndex && fnGetIconLibVersion && hLib); +} + +CFileAssoc::IconLib::~IconLib() +{ + VERIFY(FreeLibrary(m_hLib)); +} + +int CFileAssoc::IconLib::GetIconIndex(const CString& str) const +{ + return m_fnGetIconIndex(str); +} + +UINT CFileAssoc::IconLib::GetVersion() const +{ + return m_fnGetIconLibVersion(); +} + +void CFileAssoc::IconLib::SaveVersion() const +{ + AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_ICON_LIB_VERSION, m_fnGetIconLibVersion()); +} + +CFileAssoc::CFileAssoc() + : m_iconLibPath(PathUtils::CombinePaths(PathUtils::GetProgramPath(), _T("mpciconlib.dll"))) + , m_strRegisteredAppName(_T("Media Player Classic")) + , m_strOldAssocKey(_T("PreviousRegistration")) + , m_strRegisteredAppKey(_T("Software\\Clients\\Media\\Media Player Classic\\Capabilities")) + , m_strRegAppFileAssocKey(_T("Software\\Clients\\Media\\Media Player Classic\\Capabilities\\FileAssociations")) + , m_strOpenCommand(_T("\"") + PathUtils::GetProgramPath(true) + _T("\" \"%1\"")) + , m_strEnqueueCommand(_T("\"") + PathUtils::GetProgramPath(true) + _T("\" /add \"%1\"")) + , m_bNoRecentDocs(false) + , m_checkIconsAssocInactiveEvent(TRUE, TRUE) // initially set, manual reset +{ + // Default manager (requires at least Vista) + VERIFY(CoCreateInstance(CLSID_ApplicationAssociationRegistration, nullptr, + CLSCTX_INPROC, IID_PPV_ARGS(&m_pAAR)) != CO_E_NOTINITIALIZED); + + m_handlers[0] = { _T("VideoFiles"), _T(" %1"), IDS_AUTOPLAY_PLAYVIDEO }; + m_handlers[1] = { _T("MusicFiles"), _T(" %1"), IDS_AUTOPLAY_PLAYMUSIC }; + m_handlers[2] = { _T("CDAudio"), _T(" %1 /cd"), IDS_AUTOPLAY_PLAYAUDIOCD }; + m_handlers[3] = { _T("DVDMovie"), _T(" %1 /dvd"), IDS_AUTOPLAY_PLAYDVDMOVIE }; +} + +CFileAssoc::~CFileAssoc() +{ + HANDLE hEvent = m_checkIconsAssocInactiveEvent; + DWORD dwEvent; + VERIFY(CoWaitForMultipleHandles(0, INFINITE, 1, &hEvent, &dwEvent) == S_OK); +} + +std::shared_ptr CFileAssoc::GetIconLib() const +{ + std::shared_ptr ret; + if (HMODULE hLib = LoadLibrary(m_iconLibPath)) { + auto fnGetIconIndex = reinterpret_cast(GetProcAddress(hLib, "GetIconIndex")); + auto fnGetIconLibVersion = reinterpret_cast(GetProcAddress(hLib, "GetIconLibVersion")); + if (fnGetIconIndex && fnGetIconLibVersion) { + ret = std::make_shared(fnGetIconIndex, fnGetIconLibVersion, hLib); + } else { + VERIFY(FreeLibrary(hLib)); + } + } + return ret; +} + +void CFileAssoc::SetNoRecentDocs(bool bNoRecentDocs, bool bUpdateAssocs /*= false*/) +{ + if (bNoRecentDocs == m_bNoRecentDocs) { + bUpdateAssocs = false; + } else { + m_bNoRecentDocs = bNoRecentDocs; + } + + CAtlList exts; + if (bUpdateAssocs && GetAssociatedExtensionsFromRegistry(exts)) { + CRegKey key; + POSITION pos = exts.GetHeadPosition(); + while (pos) { + const CString& ext = exts.GetNext(pos); + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, PROGID + ext)) { + if (m_bNoRecentDocs) { + key.SetStringValue(_T("NoRecentDocs"), _T("")); + } else { + key.DeleteValue(_T("NoRecentDocs")); + } + } + } + } +} + +bool CFileAssoc::RegisterApp() +{ + bool success = false; + + if (m_pAAR) { + CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); + + // Register MPC-HC for the windows "Default application" manager + CRegKey key; + + if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\RegisteredApplications"))) { + key.SetStringValue(_T("Media Player Classic"), m_strRegisteredAppKey); + + if (ERROR_SUCCESS == key.Create(HKEY_LOCAL_MACHINE, m_strRegisteredAppKey)) { + // ==>> TODO icon !!! + key.SetStringValue(_T("ApplicationDescription"), ResStr(IDS_APP_DESCRIPTION), REG_EXPAND_SZ); + key.SetStringValue(_T("ApplicationIcon"), appIcon, REG_EXPAND_SZ); + key.SetStringValue(_T("ApplicationName"), ResStr(IDR_MAINFRAME), REG_EXPAND_SZ); + + success = true; + } + } + } + + return success; +} + +bool CFileAssoc::Register(CString ext, CString strLabel, bool bRegister, bool bAddEnqueueContextMenu, bool bAssociatedWithIcon) +{ + CRegKey key; + CString strProgID = PROGID + ext; + + if (!bRegister) { + // On Windows 8, an app can't set itself as the default handler for a format + if (!IsWindows8OrGreater() && bRegister != IsRegistered(ext)) { + SetFileAssociation(ext, strProgID, bRegister); + } + + key.Attach(HKEY_CLASSES_ROOT); + key.RecurseDeleteKey(strProgID); + + if (ERROR_SUCCESS == key.Open(HKEY_LOCAL_MACHINE, m_strRegAppFileAssocKey)) { + key.DeleteValue(ext); + } + + return true; + } else { + // Create ProgID for this file type + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID) + || ERROR_SUCCESS != key.SetStringValue(nullptr, strLabel)) { + return false; + } + + if (m_bNoRecentDocs) { + key.SetStringValue(_T("NoRecentDocs"), _T("")); + } else { + key.DeleteValue(_T("NoRecentDocs")); + } + + CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); + + // Add to playlist option + if (bAddEnqueueContextMenu) { + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, ResStr(IDS_ADD_TO_PLAYLIST)) + || ERROR_SUCCESS != key.SetStringValue(_T("Icon"), appIcon) + || ERROR_SUCCESS != key.SetStringValue(_T("MultiSelectModel"), _T("Player")) + || ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue\\command")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, m_strEnqueueCommand)) { + return false; + } + } else { + key.Close(); + key.Attach(HKEY_CLASSES_ROOT); + key.RecurseDeleteKey(strProgID + _T("\\shell\\enqueue")); + } + + // Play option + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open"))) { + return false; + } + if (ERROR_SUCCESS != key.SetStringValue(nullptr, ResStr(IDS_OPEN_WITH_MPC)) + || ERROR_SUCCESS != key.SetStringValue(_T("MultiSelectModel"), _T("Player")) + || ERROR_SUCCESS != key.SetStringValue(_T("Icon"), appIcon)) { + return false; + } + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open\\command")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, m_strOpenCommand)) { + return false; + } + + if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, m_strRegAppFileAssocKey) + || key.SetStringValue(ext, strProgID)) { + return false; + } + + if (bAssociatedWithIcon) { + if (auto iconLib = GetIconLib()) { + int iconIndex = iconLib->GetIconIndex(ext); + + /* icon_index value -1 means no icon was found in the iconlib for the file extension */ + if (iconIndex >= 0 && ExtractIcon(AfxGetApp()->m_hInstance, m_iconLibPath, iconIndex)) { + appIcon.Format(_T("\"%s\",%d"), m_iconLibPath.GetString(), iconIndex); + } + } + + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\DefaultIcon")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, appIcon)) { + return false; + } + } else { + key.Close(); + key.Attach(HKEY_CLASSES_ROOT); + key.RecurseDeleteKey(strProgID + _T("\\DefaultIcon")); + } + + // On Windows 8, an app can't set itself as the default handler for a format + if (!IsWindows8OrGreater() && bRegister != IsRegistered(ext)) { + SetFileAssociation(ext, strProgID, bRegister); + } + + return true; + } +} + +bool CFileAssoc::SetFileAssociation(CString strExt, CString strProgID, bool bRegister) +{ + CString extOldReg; + CRegKey key; + HRESULT hr = S_OK; + TCHAR buff[MAX_PATH]; + ULONG len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + + if (m_pAAR) { + // The Windows 7 way + CString strNewApp; + if (bRegister) { + // Create non existing file type + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strExt)) { + return false; + } + + CComHeapPtr pszCurrentAssociation; + // Save the application currently associated + if (SUCCEEDED(m_pAAR->QueryCurrentDefault(strExt, AT_FILEEXTENSION, AL_EFFECTIVE, &pszCurrentAssociation))) { + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID)) { + return false; + } + + key.SetStringValue(m_strOldAssocKey, pszCurrentAssociation); + } + strNewApp = m_strRegisteredAppName; + } else { + if (ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, strProgID)) { + return false; + } + + if (ERROR_SUCCESS == key.QueryStringValue(m_strOldAssocKey, buff, &len)) { + strNewApp = buff; + } + } + + hr = m_pAAR->SetAppAsDefault(strNewApp, strExt, AT_FILEEXTENSION); + } + + return SUCCEEDED(hr); +} + +bool CFileAssoc::IsRegistered(CString ext) const +{ + BOOL bIsDefault = FALSE; + CString strProgID = PROGID + ext; + + if (IsWindows8OrGreater()) { + bIsDefault = TRUE; // Check only if MPC-HC is registered as able to handle that format, not if it's the default. + } else if (m_pAAR) { + m_pAAR->QueryAppIsDefault(ext, AT_FILEEXTENSION, AL_EFFECTIVE, m_strRegisteredAppName, &bIsDefault); + } + + // Check if association is for this instance of MPC-HC + if (bIsDefault) { + CRegKey key; + TCHAR buff[MAX_PATH]; + ULONG len = _countof(buff); + + bIsDefault = FALSE; + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\open\\command"), KEY_READ)) { + if (ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len)) { + bIsDefault = (m_strOpenCommand.CompareNoCase(CString(buff)) == 0); + } + } + } + + return !!bIsDefault; +} + +bool CFileAssoc::HasEnqueueContextMenuEntry(CString strExt) const +{ + CRegKey key; + CString strProgID = PROGID + strExt; + + return (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, strProgID + _T("\\shell\\enqueue"), KEY_READ)); +} + +bool CFileAssoc::Register(const CMediaFormatCategory& mfc, bool bRegister, bool bAddEnqueueContextMenu, bool bAssociatedWithIcon) +{ + if (!mfc.IsAssociable()) { + ASSERT(FALSE); + return false; + } + + CAtlList exts; + ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); + + CString strLabel = mfc.GetDescription(); + bool res = true; + + POSITION pos = exts.GetHeadPosition(); + while (pos) { + res &= Register(exts.GetNext(pos), strLabel, bRegister, bAddEnqueueContextMenu, bAssociatedWithIcon); + } + + return res; +} + +CFileAssoc::reg_state_t CFileAssoc::IsRegistered(const CMediaFormatCategory& mfc) const +{ + CAtlList exts; + ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); + + size_t cnt = 0; + + POSITION pos = exts.GetHeadPosition(); + while (pos) { + if (CFileAssoc::IsRegistered(exts.GetNext(pos))) { + cnt++; + } + } + + reg_state_t res; + if (cnt == 0) { + res = NOT_REGISTERED; + } else if (cnt == exts.GetCount()) { + res = ALL_REGISTERED; + } else { + res = SOME_REGISTERED; + } + + return res; +} + +CFileAssoc::reg_state_t CFileAssoc::HasAnyEnqueueContextMenuEntries(const CMediaFormatCategory& mfc) const +{ + CAtlList exts; + ExplodeMin(mfc.GetExtsWithPeriod(), exts, ' '); + + size_t cnt = 0; + + POSITION pos = exts.GetHeadPosition(); + while (pos) { + if (CFileAssoc::HasEnqueueContextMenuEntry(exts.GetNext(pos))) { + cnt++; + } + } + + reg_state_t res; + if (cnt == 0) { + res = NOT_REGISTERED; + } else if (cnt == exts.GetCount()) { + res = ALL_REGISTERED; + } else { + res = SOME_REGISTERED; + } + + return res; +} + +bool CFileAssoc::RegisterFolderContextMenuEntries(bool bRegister) +{ + CRegKey key; + bool success; + + if (bRegister) { + success = false; + + CString appIcon = _T("\"") + PathUtils::GetProgramPath(true) + _T("\",0"); + + if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".enqueue"))) { + key.SetStringValue(nullptr, ResStr(IDS_ADD_TO_PLAYLIST)); + key.SetStringValue(_T("Icon"), appIcon); + + if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".enqueue\\command"))) { + key.SetStringValue(nullptr, m_strEnqueueCommand); + success = true; + } + } + + if (success && ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play"))) { + success = false; + + key.SetStringValue(nullptr, ResStr(IDS_OPEN_WITH_MPC)); + key.SetStringValue(_T("Icon"), appIcon); + + if (ERROR_SUCCESS == key.Create(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play\\command"))) { + key.SetStringValue(nullptr, m_strOpenCommand); + success = true; + } + } + + } else { + key.Attach(HKEY_CLASSES_ROOT); + success = (ERROR_SUCCESS == key.RecurseDeleteKey(_T("Directory\\shell\\") PROGID _T(".enqueue"))); + success &= (ERROR_SUCCESS == key.RecurseDeleteKey(_T("Directory\\shell\\") PROGID _T(".play"))); + } + + return success; +} + +bool CFileAssoc::AreRegisteredFolderContextMenuEntries() const +{ + CRegKey key; + TCHAR buff[MAX_PATH]; + ULONG len = _countof(buff); + bool registered = false; + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("Directory\\shell\\") PROGID _T(".play\\command"), KEY_READ)) { + if (ERROR_SUCCESS == key.QueryStringValue(nullptr, buff, &len)) { + registered = (m_strOpenCommand.CompareNoCase(CString(buff)) == 0); + } + } + + return registered; +} + +bool CFileAssoc::RegisterAutoPlay(autoplay_t ap, bool bRegister) +{ + CString exe = PathUtils::GetProgramPath(true); + + size_t i = (size_t)ap; + if (i >= m_handlers.size()) { + return false; + } + + CRegKey key; + + if (bRegister) { + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, _T("MediaPlayerClassic.Autorun"))) { + return false; + } + key.Close(); + + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, + _T("MediaPlayerClassic.Autorun\\Shell\\Play") + m_handlers[i].verb + _T("\\Command"))) { + return false; + } + key.SetStringValue(nullptr, _T("\"") + exe + _T("\"") + m_handlers[i].cmd); + key.Close(); + + if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\Handlers\\MPCPlay") + m_handlers[i].verb + _T("OnArrival"))) { + return false; + } + key.SetStringValue(_T("Action"), ResStr(m_handlers[i].action)); + key.SetStringValue(_T("Provider"), _T("Media Player Classic")); + key.SetStringValue(_T("InvokeProgID"), _T("MediaPlayerClassic.Autorun")); + key.SetStringValue(_T("InvokeVerb"), _T("Play") + m_handlers[i].verb); + key.SetStringValue(_T("DefaultIcon"), exe + _T(",0")); + key.Close(); + + if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"))) { + return false; + } + key.SetStringValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival"), _T("")); + key.Close(); + } else { + if (ERROR_SUCCESS != key.Create(HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"))) { + return false; + } + key.DeleteValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival")); + key.Close(); + } + + return true; +} + +bool CFileAssoc::IsAutoPlayRegistered(autoplay_t ap) const +{ + ULONG len; + TCHAR buff[MAX_PATH]; + CString exe = PathUtils::GetProgramPath(true); + + size_t i = (size_t)ap; + if (i >= m_handlers.size()) { + return false; + } + + CRegKey key; + + if (ERROR_SUCCESS != key.Open(HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\EventHandlers\\Play") + m_handlers[i].verb + _T("OnArrival"), + KEY_READ)) { + return false; + } + len = _countof(buff); + if (ERROR_SUCCESS != key.QueryStringValue(_T("MPCPlay") + m_handlers[i].verb + _T("OnArrival"), buff, &len)) { + return false; + } + key.Close(); + + if (ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, + _T("MediaPlayerClassic.Autorun\\Shell\\Play") + m_handlers[i].verb + _T("\\Command"), + KEY_READ)) { + return false; + } + len = _countof(buff); + if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len)) { + return false; + } + if (_tcsnicmp(_T("\"") + exe, buff, exe.GetLength() + 1)) { + return false; + } + key.Close(); + + return true; +} + +bool CFileAssoc::GetAssociatedExtensions(const CMediaFormats& mf, CAtlList& exts) const +{ + exts.RemoveAll(); + + CAtlList mfcExts; + for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { + ExplodeMin(mf[i].GetExtsWithPeriod(), mfcExts, _T(' ')); + + POSITION pos = mfcExts.GetHeadPosition(); + while (pos) { + const CString ext = mfcExts.GetNext(pos); + if (IsRegistered(ext)) { + exts.AddTail(ext); + } + } + } + + return !exts.IsEmpty(); +} + +bool CFileAssoc::GetAssociatedExtensionsFromRegistry(CAtlList& exts) const +{ + exts.RemoveAll(); + + CRegKey rkHKCR(HKEY_CLASSES_ROOT); + LONG ret; + DWORD i = 0; + CString keyName, ext; + DWORD len = MAX_PATH; + + while ((ret = rkHKCR.EnumKey(i, keyName.GetBuffer(len), &len)) != ERROR_NO_MORE_ITEMS) { + if (ret == ERROR_SUCCESS) { + keyName.ReleaseBuffer(len); + + if (keyName.Find(PROGID) == 0) { + ext = keyName.Mid(_countof(PROGID) - 1); + + if (IsRegistered(ext)) { + exts.AddTail(ext); + } + } + + i++; + len = MAX_PATH; + } + } + + return !exts.IsEmpty(); +} + +bool CFileAssoc::ReAssocIcons(const CAtlList& exts) +{ + auto iconLib = GetIconLib(); + if (!iconLib) { + return false; + } + iconLib->SaveVersion(); + + const CString progPath = PathUtils::GetProgramPath(true); + + CRegKey key; + + POSITION pos = exts.GetHeadPosition(); + while (pos) { + const CString ext = exts.GetNext(pos); + const CString strProgID = PROGID + ext; + CString appIcon; + + int iconIndex = iconLib->GetIconIndex(ext); + + /* icon_index value -1 means no icon was found in the iconlib for the file extension */ + if (iconIndex >= 0 && ExtractIcon(AfxGetApp()->m_hInstance, m_iconLibPath, iconIndex)) { + appIcon.Format(_T("\"%s\",%d"), m_iconLibPath.GetString(), iconIndex); + } + + /* no icon was found for the file extension, so use MPC-HC's icon */ + if (appIcon.IsEmpty()) { + appIcon = _T("\"") + progPath + _T("\",0"); + } + + if (ERROR_SUCCESS != key.Create(HKEY_CLASSES_ROOT, strProgID + _T("\\DefaultIcon")) + || ERROR_SUCCESS != key.SetStringValue(nullptr, appIcon)) { + return false; + } + + key.Close(); + } + + return true; +} + +static HRESULT CALLBACK TaskDialogCallbackProc(HWND hwnd, UINT uNotification, WPARAM wParam, LPARAM lParam, LONG_PTR dwRefData) +{ + if (TDN_CREATED == uNotification) { + SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); + } + + return S_OK; +} + +void CFileAssoc::CheckIconsAssocThread() +{ + UINT nLastVersion = AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_ICON_LIB_VERSION, 0); + + if (auto iconLib = GetIconLib()) { + UINT nCurrentVersion = iconLib->GetVersion(); + + CAtlList registeredExts; + + if (nCurrentVersion != nLastVersion && GetAssociatedExtensionsFromRegistry(registeredExts)) { + iconLib->SaveVersion(); + if (!IsUserAnAdmin()) { + TASKDIALOGCONFIG config; + ZeroMemory(&config, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(config); + config.hInstance = AfxGetInstanceHandle(); + config.hwndParent = AfxGetApp()->GetMainWnd()->GetSafeHwnd(); + config.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON; + config.pszMainIcon = TD_SHIELD_ICON; + config.pszWindowTitle = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_TITLE); + config.pszMainInstruction = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_INSTR); + config.pszContent = MAKEINTRESOURCE(IDS_ICONS_REASSOC_DLG_CONTENT); + config.pfCallback = TaskDialogCallbackProc; + + typedef HRESULT(_stdcall * pfTaskDialogIndirect)(const TASKDIALOGCONFIG*, int*, int*, BOOL*); + + HMODULE hModule = ::LoadLibrary(_T("comctl32.dll")); + if (hModule) { + pfTaskDialogIndirect TaskDialogIndirect = (pfTaskDialogIndirect)(::GetProcAddress(hModule, "TaskDialogIndirect")); + + if (TaskDialogIndirect) { + int nButtonPressed = 0; + TaskDialogIndirect(&config, &nButtonPressed, nullptr, nullptr); + + if (IDYES == nButtonPressed) { + AfxGetMyApp()->RunAsAdministrator(PathUtils::GetProgramPath(true), _T("/iconsassoc"), true); + } + } + + ::FreeLibrary(hModule); + } + } else { + ReAssocIcons(registeredExts); + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + } + } + } + + m_checkIconsAssocInactiveEvent.Set(); +} + +void CFileAssoc::CheckIconsAssoc() +{ + std::lock_guard lock(m_checkIconsAssocMutex); + HANDLE hEvent = m_checkIconsAssocInactiveEvent; + DWORD dwEvent; + VERIFY(CoWaitForMultipleHandles(0, INFINITE, 1, &hEvent, &dwEvent) == S_OK); + m_checkIconsAssocInactiveEvent.Reset(); + try { + std::thread([this] { CheckIconsAssocThread(); }).detach(); + } catch (...) {} +} + +bool CFileAssoc::ShowWindowsAssocDialog() const +{ + IApplicationAssociationRegistrationUI* pAARUI; + HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI, + nullptr, + CLSCTX_INPROC, + IID_PPV_ARGS(&pAARUI)); + + bool success = (SUCCEEDED(hr) && pAARUI != nullptr); + + if (success) { + pAARUI->LaunchAdvancedAssociationUI(m_strRegisteredAppName); + pAARUI->Release(); + } + + return success; +} diff --git a/src/mpc-hc/FileAssoc.h b/src/mpc-hc/FileAssoc.h index 0e6038ae2ef..3657bb724b0 100644 --- a/src/mpc-hc/FileAssoc.h +++ b/src/mpc-hc/FileAssoc.h @@ -1,136 +1,136 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#pragma once - -#include "MediaFormats.h" -#include - -#include -#include -#include -#include - -class CFileAssoc -{ -public: - enum reg_state_t { - NOT_REGISTERED, - SOME_REGISTERED, - ALL_REGISTERED - }; - enum autoplay_t { - AP_VIDEO, - AP_MUSIC, - AP_AUDIOCD, - AP_DVDMOVIE - }; - - class IconLib - { - public: - typedef int(*GetIconIndexFunc)(LPCTSTR); - typedef UINT(*GetIconLibVersionFunc)(); - - IconLib() = delete; - IconLib(const IconLib&) = delete; - IconLib& operator=(const IconLib&) = delete; - IconLib(GetIconIndexFunc fnGetIconIndex, GetIconLibVersionFunc fnGetIconLibVersion, HMODULE hLib); - ~IconLib(); - - int GetIconIndex(const CString& str) const; - UINT GetVersion() const; - void SaveVersion() const; - - protected: - const GetIconIndexFunc m_fnGetIconIndex; - const GetIconLibVersionFunc m_fnGetIconLibVersion; - const HMODULE m_hLib; - }; - - CFileAssoc(); - CFileAssoc(const CFileAssoc&) = delete; - CFileAssoc& operator=(const CFileAssoc&) = delete; - ~CFileAssoc(); - - std::shared_ptr GetIconLib() const; - - void SetNoRecentDocs(bool bNoRecentDocs, bool bUpdateAssocs = false); - - bool RegisterApp(); - - bool Register(CString ext, CString strLabel, bool bRegister, bool bRegisterContextMenuEntries, bool bAssociatedWithIcon); - bool IsRegistered(CString ext) const; - bool HasEnqueueContextMenuEntry(CString strExt) const; - - bool Register(const CMediaFormatCategory& mfc, bool bRegister, bool bRegisterContextMenuEntries, bool bAssociatedWithIcon); - reg_state_t IsRegistered(const CMediaFormatCategory& mfc) const; - reg_state_t HasAnyEnqueueContextMenuEntries(const CMediaFormatCategory& mfc) const; - - bool RegisterFolderContextMenuEntries(bool bRegister); - bool AreRegisteredFolderContextMenuEntries() const; - - bool RegisterAutoPlay(autoplay_t ap, bool bRegister); - bool IsAutoPlayRegistered(autoplay_t ap) const; - - bool GetAssociatedExtensions(const CMediaFormats& mf, CAtlList& exts) const; - bool GetAssociatedExtensionsFromRegistry(CAtlList& exts) const; - - bool ReAssocIcons(const CAtlList& exts); - - void CheckIconsAssoc(); - - bool ShowWindowsAssocDialog() const; - -protected: - struct Handler { - CString verb; - CString cmd; - UINT action; - - Handler() - : action(0) {} - Handler(const CString& verb, const CString& cmd, UINT action) - : verb(verb), cmd(cmd), action(action) {} - }; - - bool SetFileAssociation(CString strExt, CString strProgID, bool bRegister); - - void CheckIconsAssocThread(); - - const CString m_iconLibPath; - const CString m_strRegisteredAppName; - const CString m_strOldAssocKey; - const CString m_strRegisteredAppKey; - const CString m_strRegAppFileAssocKey; - - const CString m_strOpenCommand; - const CString m_strEnqueueCommand; - - bool m_bNoRecentDocs; - - CComPtr m_pAAR; - - std::mutex m_checkIconsAssocMutex; - ATL::CEvent m_checkIconsAssocInactiveEvent; - - std::array m_handlers; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#pragma once + +#include "MediaFormats.h" +#include + +#include +#include +#include +#include + +class CFileAssoc +{ +public: + enum reg_state_t { + NOT_REGISTERED, + SOME_REGISTERED, + ALL_REGISTERED + }; + enum autoplay_t { + AP_VIDEO, + AP_MUSIC, + AP_AUDIOCD, + AP_DVDMOVIE + }; + + class IconLib + { + public: + typedef int(*GetIconIndexFunc)(LPCTSTR); + typedef UINT(*GetIconLibVersionFunc)(); + + IconLib() = delete; + IconLib(const IconLib&) = delete; + IconLib& operator=(const IconLib&) = delete; + IconLib(GetIconIndexFunc fnGetIconIndex, GetIconLibVersionFunc fnGetIconLibVersion, HMODULE hLib); + ~IconLib(); + + int GetIconIndex(const CString& str) const; + UINT GetVersion() const; + void SaveVersion() const; + + protected: + const GetIconIndexFunc m_fnGetIconIndex; + const GetIconLibVersionFunc m_fnGetIconLibVersion; + const HMODULE m_hLib; + }; + + CFileAssoc(); + CFileAssoc(const CFileAssoc&) = delete; + CFileAssoc& operator=(const CFileAssoc&) = delete; + ~CFileAssoc(); + + std::shared_ptr GetIconLib() const; + + void SetNoRecentDocs(bool bNoRecentDocs, bool bUpdateAssocs = false); + + bool RegisterApp(); + + bool Register(CString ext, CString strLabel, bool bRegister, bool bRegisterContextMenuEntries, bool bAssociatedWithIcon); + bool IsRegistered(CString ext) const; + bool HasEnqueueContextMenuEntry(CString strExt) const; + + bool Register(const CMediaFormatCategory& mfc, bool bRegister, bool bRegisterContextMenuEntries, bool bAssociatedWithIcon); + reg_state_t IsRegistered(const CMediaFormatCategory& mfc) const; + reg_state_t HasAnyEnqueueContextMenuEntries(const CMediaFormatCategory& mfc) const; + + bool RegisterFolderContextMenuEntries(bool bRegister); + bool AreRegisteredFolderContextMenuEntries() const; + + bool RegisterAutoPlay(autoplay_t ap, bool bRegister); + bool IsAutoPlayRegistered(autoplay_t ap) const; + + bool GetAssociatedExtensions(const CMediaFormats& mf, CAtlList& exts) const; + bool GetAssociatedExtensionsFromRegistry(CAtlList& exts) const; + + bool ReAssocIcons(const CAtlList& exts); + + void CheckIconsAssoc(); + + bool ShowWindowsAssocDialog() const; + +protected: + struct Handler { + CString verb; + CString cmd; + UINT action; + + Handler() + : action(0) {} + Handler(const CString& verb, const CString& cmd, UINT action) + : verb(verb), cmd(cmd), action(action) {} + }; + + bool SetFileAssociation(CString strExt, CString strProgID, bool bRegister); + + void CheckIconsAssocThread(); + + const CString m_iconLibPath; + const CString m_strRegisteredAppName; + const CString m_strOldAssocKey; + const CString m_strRegisteredAppKey; + const CString m_strRegAppFileAssocKey; + + const CString m_strOpenCommand; + const CString m_strEnqueueCommand; + + bool m_bNoRecentDocs; + + CComPtr m_pAAR; + + std::mutex m_checkIconsAssocMutex; + ATL::CEvent m_checkIconsAssocInactiveEvent; + + std::array m_handlers; +}; diff --git a/src/mpc-hc/FilterEnum.h b/src/mpc-hc/FilterEnum.h index 081fb1d1940..5aedddc7250 100644 --- a/src/mpc-hc/FilterEnum.h +++ b/src/mpc-hc/FilterEnum.h @@ -1,274 +1,274 @@ -/* - * (C) 2010-2015, 2017 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 . - * - */ - -#pragma once - -#include "InternalFiltersConfig.h" - - -enum { - SOURCE_FILTER, - AUDIO_DECODER, - VIDEO_DECODER, - FILTER_TYPE_NB -}; - -enum SOURCE_FILTER { -#if INTERNAL_SOURCEFILTER_AC3 - SRC_AC3, -#endif -#if INTERNAL_SOURCEFILTER_ASF - SRC_ASF, -#endif -#if INTERNAL_SOURCEFILTER_AVI - SRC_AVI, -#endif -#if INTERNAL_SOURCEFILTER_AVS - SRC_AVS, -#endif -#if INTERNAL_SOURCEFILTER_DTS - SRC_DTS, -#endif -#if INTERNAL_SOURCEFILTER_FLAC - SRC_FLAC, -#endif -#if INTERNAL_SOURCEFILTER_FLIC - SRC_FLIC, -#endif -#if INTERNAL_SOURCEFILTER_FLV - SRC_FLV, -#endif -#if INTERNAL_SOURCEFILTER_GIF - SRC_GIF, -#endif -#if INTERNAL_SOURCEFILTER_HTTP - SRC_HTTP, -#endif -#if INTERNAL_SOURCEFILTER_MATROSKA - SRC_MATROSKA, -#endif -#if INTERNAL_SOURCEFILTER_MISC - SRC_MISC, -#endif -#if INTERNAL_SOURCEFILTER_MMS - SRC_MMS, -#endif -#if INTERNAL_SOURCEFILTER_MP4 - SRC_MP4, -#endif -#if INTERNAL_SOURCEFILTER_MPEGAUDIO - SRC_MPA, -#endif -#if INTERNAL_SOURCEFILTER_MPEG - SRC_MPEG, - SRC_MPEGTS, -#endif -#if INTERNAL_SOURCEFILTER_OGG - SRC_OGG, -#endif -#if INTERNAL_SOURCEFILTER_REALMEDIA - SRC_REALMEDIA, -#endif -#if INTERNAL_SOURCEFILTER_RTMP - SRC_RTMP, -#endif -#if INTERNAL_SOURCEFILTER_RTP - SRC_RTP, -#endif -#if INTERNAL_SOURCEFILTER_RTSP - SRC_RTSP, -#endif -#if INTERNAL_SOURCEFILTER_UDP - SRC_UDP, -#endif -#if INTERNAL_SOURCEFILTER_WTV - SRC_WTV, -#endif -#if INTERNAL_SOURCEFILTER_CDDA - SRC_CDDA, -#endif -#if INTERNAL_SOURCEFILTER_CDXA - SRC_CDXA, -#endif -#if INTERNAL_SOURCEFILTER_DSM - SRC_DSM, -#endif -#if INTERNAL_SOURCEFILTER_RFS - SRC_RFS, -#endif -#if INTERNAL_SOURCEFILTER_VTS - SRC_VTS, -#endif - SRC_LAST -}; - -enum DECODER { -#if INTERNAL_DECODER_MPEG1 - TRA_MPEG1, -#endif -#if INTERNAL_DECODER_MPEG2 - TRA_MPEG2, -#endif -#if INTERNAL_DECODER_REALVIDEO - TRA_RV, -#endif -#if INTERNAL_DECODER_REALAUDIO - TRA_RA, -#endif -#if INTERNAL_DECODER_MPEGAUDIO - TRA_MPA, -#endif -#if INTERNAL_DECODER_DTS - TRA_DTS, -#endif -#if INTERNAL_DECODER_LPCM - TRA_LPCM, -#endif -#if INTERNAL_DECODER_AC3 - TRA_AC3, -#endif -#if INTERNAL_DECODER_AAC - TRA_AAC, -#endif -#if INTERNAL_DECODER_ALAC - TRA_ALAC, -#endif -#if INTERNAL_DECODER_ALS - TRA_ALS, -#endif -#if INTERNAL_DECODER_PS2AUDIO - TRA_PS2AUD, -#endif -#if INTERNAL_DECODER_VORBIS - TRA_VORBIS, -#endif -#if INTERNAL_DECODER_FLAC - TRA_FLAC, -#endif -#if INTERNAL_DECODER_NELLYMOSER - TRA_NELLY, -#endif -#if INTERNAL_DECODER_AMR - TRA_AMR, -#endif -#if INTERNAL_DECODER_OPUS - TRA_OPUS, -#endif -#if INTERNAL_DECODER_WMA - TRA_WMA, -#endif -#if INTERNAL_DECODER_WMAPRO - TRA_WMAPRO, -#endif -#if INTERNAL_DECODER_WMALL - TRA_WMALL, -#endif -#if INTERNAL_DECODER_G726 - TRA_G726, -#endif -#if INTERNAL_DECODER_G729 - TRA_G729, -#endif -#if INTERNAL_DECODER_OTHERAUDIO - TRA_OTHERAUDIO, -#endif -#if INTERNAL_DECODER_PCM - TRA_PCM, -#endif -#if INTERNAL_DECODER_H264 - TRA_H264, -#endif -#if INTERNAL_DECODER_HEVC - TRA_HEVC, -#endif -#if INTERNAL_DECODER_VVC - TRA_VVC, -#endif -#if INTERNAL_DECODER_AV1 - TRA_AV1, -#endif -#if INTERNAL_DECODER_VC1 - TRA_VC1, -#endif -#if INTERNAL_DECODER_FLV - TRA_FLV4, -#endif -#if INTERNAL_DECODER_VP356 - TRA_VP356, -#endif -#if INTERNAL_DECODER_VP8 - TRA_VP8, -#endif -#if INTERNAL_DECODER_VP9 - TRA_VP9, -#endif -#if INTERNAL_DECODER_XVID - TRA_XVID, -#endif -#if INTERNAL_DECODER_DIVX - TRA_DIVX, -#endif -#if INTERNAL_DECODER_MSMPEG4 - TRA_MSMPEG4, -#endif -#if INTERNAL_DECODER_WMV - TRA_WMV, -#endif -#if INTERNAL_DECODER_SVQ - TRA_SVQ3, -#endif -#if INTERNAL_DECODER_H263 - TRA_H263, -#endif -#if INTERNAL_DECODER_THEORA - TRA_THEORA, -#endif -#if INTERNAL_DECODER_AMVV - TRA_AMVV, -#endif -#if INTERNAL_DECODER_MJPEG - TRA_MJPEG, -#endif -#if INTERNAL_DECODER_INDEO - TRA_INDEO, -#endif -#if INTERNAL_DECODER_SCREEN - TRA_SCREEN, -#endif -#if INTERNAL_DECODER_FLIC - TRA_FLIC, -#endif -#if INTERNAL_DECODER_MSVIDEO - TRA_MSVIDEO, -#endif -#if INTERNAL_DECODER_V210_V410 - TRA_V210_V410, -#endif -#if INTERNAL_DECODER_PRORES - TRA_PRORES, -#endif -#if INTERNAL_DECODER_DNXHD - TRA_DNXHD, -#endif -#if INTERNAL_DECODER_OTHERVIDEO - TRA_OTHERVIDEO, -#endif - TRA_LAST -}; +/* + * (C) 2010-2015, 2017 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 . + * + */ + +#pragma once + +#include "InternalFiltersConfig.h" + + +enum { + SOURCE_FILTER, + AUDIO_DECODER, + VIDEO_DECODER, + FILTER_TYPE_NB +}; + +enum SOURCE_FILTER { +#if INTERNAL_SOURCEFILTER_AC3 + SRC_AC3, +#endif +#if INTERNAL_SOURCEFILTER_ASF + SRC_ASF, +#endif +#if INTERNAL_SOURCEFILTER_AVI + SRC_AVI, +#endif +#if INTERNAL_SOURCEFILTER_AVS + SRC_AVS, +#endif +#if INTERNAL_SOURCEFILTER_DTS + SRC_DTS, +#endif +#if INTERNAL_SOURCEFILTER_FLAC + SRC_FLAC, +#endif +#if INTERNAL_SOURCEFILTER_FLIC + SRC_FLIC, +#endif +#if INTERNAL_SOURCEFILTER_FLV + SRC_FLV, +#endif +#if INTERNAL_SOURCEFILTER_GIF + SRC_GIF, +#endif +#if INTERNAL_SOURCEFILTER_HTTP + SRC_HTTP, +#endif +#if INTERNAL_SOURCEFILTER_MATROSKA + SRC_MATROSKA, +#endif +#if INTERNAL_SOURCEFILTER_MISC + SRC_MISC, +#endif +#if INTERNAL_SOURCEFILTER_MMS + SRC_MMS, +#endif +#if INTERNAL_SOURCEFILTER_MP4 + SRC_MP4, +#endif +#if INTERNAL_SOURCEFILTER_MPEGAUDIO + SRC_MPA, +#endif +#if INTERNAL_SOURCEFILTER_MPEG + SRC_MPEG, + SRC_MPEGTS, +#endif +#if INTERNAL_SOURCEFILTER_OGG + SRC_OGG, +#endif +#if INTERNAL_SOURCEFILTER_REALMEDIA + SRC_REALMEDIA, +#endif +#if INTERNAL_SOURCEFILTER_RTMP + SRC_RTMP, +#endif +#if INTERNAL_SOURCEFILTER_RTP + SRC_RTP, +#endif +#if INTERNAL_SOURCEFILTER_RTSP + SRC_RTSP, +#endif +#if INTERNAL_SOURCEFILTER_UDP + SRC_UDP, +#endif +#if INTERNAL_SOURCEFILTER_WTV + SRC_WTV, +#endif +#if INTERNAL_SOURCEFILTER_CDDA + SRC_CDDA, +#endif +#if INTERNAL_SOURCEFILTER_CDXA + SRC_CDXA, +#endif +#if INTERNAL_SOURCEFILTER_DSM + SRC_DSM, +#endif +#if INTERNAL_SOURCEFILTER_RFS + SRC_RFS, +#endif +#if INTERNAL_SOURCEFILTER_VTS + SRC_VTS, +#endif + SRC_LAST +}; + +enum DECODER { +#if INTERNAL_DECODER_MPEG1 + TRA_MPEG1, +#endif +#if INTERNAL_DECODER_MPEG2 + TRA_MPEG2, +#endif +#if INTERNAL_DECODER_REALVIDEO + TRA_RV, +#endif +#if INTERNAL_DECODER_REALAUDIO + TRA_RA, +#endif +#if INTERNAL_DECODER_MPEGAUDIO + TRA_MPA, +#endif +#if INTERNAL_DECODER_DTS + TRA_DTS, +#endif +#if INTERNAL_DECODER_LPCM + TRA_LPCM, +#endif +#if INTERNAL_DECODER_AC3 + TRA_AC3, +#endif +#if INTERNAL_DECODER_AAC + TRA_AAC, +#endif +#if INTERNAL_DECODER_ALAC + TRA_ALAC, +#endif +#if INTERNAL_DECODER_ALS + TRA_ALS, +#endif +#if INTERNAL_DECODER_PS2AUDIO + TRA_PS2AUD, +#endif +#if INTERNAL_DECODER_VORBIS + TRA_VORBIS, +#endif +#if INTERNAL_DECODER_FLAC + TRA_FLAC, +#endif +#if INTERNAL_DECODER_NELLYMOSER + TRA_NELLY, +#endif +#if INTERNAL_DECODER_AMR + TRA_AMR, +#endif +#if INTERNAL_DECODER_OPUS + TRA_OPUS, +#endif +#if INTERNAL_DECODER_WMA + TRA_WMA, +#endif +#if INTERNAL_DECODER_WMAPRO + TRA_WMAPRO, +#endif +#if INTERNAL_DECODER_WMALL + TRA_WMALL, +#endif +#if INTERNAL_DECODER_G726 + TRA_G726, +#endif +#if INTERNAL_DECODER_G729 + TRA_G729, +#endif +#if INTERNAL_DECODER_OTHERAUDIO + TRA_OTHERAUDIO, +#endif +#if INTERNAL_DECODER_PCM + TRA_PCM, +#endif +#if INTERNAL_DECODER_H264 + TRA_H264, +#endif +#if INTERNAL_DECODER_HEVC + TRA_HEVC, +#endif +#if INTERNAL_DECODER_VVC + TRA_VVC, +#endif +#if INTERNAL_DECODER_AV1 + TRA_AV1, +#endif +#if INTERNAL_DECODER_VC1 + TRA_VC1, +#endif +#if INTERNAL_DECODER_FLV + TRA_FLV4, +#endif +#if INTERNAL_DECODER_VP356 + TRA_VP356, +#endif +#if INTERNAL_DECODER_VP8 + TRA_VP8, +#endif +#if INTERNAL_DECODER_VP9 + TRA_VP9, +#endif +#if INTERNAL_DECODER_XVID + TRA_XVID, +#endif +#if INTERNAL_DECODER_DIVX + TRA_DIVX, +#endif +#if INTERNAL_DECODER_MSMPEG4 + TRA_MSMPEG4, +#endif +#if INTERNAL_DECODER_WMV + TRA_WMV, +#endif +#if INTERNAL_DECODER_SVQ + TRA_SVQ3, +#endif +#if INTERNAL_DECODER_H263 + TRA_H263, +#endif +#if INTERNAL_DECODER_THEORA + TRA_THEORA, +#endif +#if INTERNAL_DECODER_AMVV + TRA_AMVV, +#endif +#if INTERNAL_DECODER_MJPEG + TRA_MJPEG, +#endif +#if INTERNAL_DECODER_INDEO + TRA_INDEO, +#endif +#if INTERNAL_DECODER_SCREEN + TRA_SCREEN, +#endif +#if INTERNAL_DECODER_FLIC + TRA_FLIC, +#endif +#if INTERNAL_DECODER_MSVIDEO + TRA_MSVIDEO, +#endif +#if INTERNAL_DECODER_V210_V410 + TRA_V210_V410, +#endif +#if INTERNAL_DECODER_PRORES + TRA_PRORES, +#endif +#if INTERNAL_DECODER_DNXHD + TRA_DNXHD, +#endif +#if INTERNAL_DECODER_OTHERVIDEO + TRA_OTHERVIDEO, +#endif + TRA_LAST +}; diff --git a/src/mpc-hc/FloatEdit.cpp b/src/mpc-hc/FloatEdit.cpp index b94e2bd4331..af98e790891 100644 --- a/src/mpc-hc/FloatEdit.cpp +++ b/src/mpc-hc/FloatEdit.cpp @@ -1,181 +1,181 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015 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 . - * - */ - -#include "stdafx.h" -#include "FloatEdit.h" - - -// CFloatEdit - -IMPLEMENT_DYNAMIC(CMPCThemeFloatEdit, CMPCThemeEdit) - -bool CMPCThemeFloatEdit::GetFloat(float& f) -{ - CString s; - GetWindowText(s); - return (_stscanf_s(s, _T("%f"), &f) == 1); -} - -double CMPCThemeFloatEdit::operator = (double d) -{ - CString s; - s.Format(_T("%.4f"), d); - SetWindowText(s); - return d; -} - -CMPCThemeFloatEdit::operator double() -{ - CString s; - GetWindowText(s); - float flt; - if (swscanf_s(s, L"%f", &flt) != 1) { - flt = 0.0f; - } - flt = std::clamp(flt, m_lower, m_upper); - - return flt; -} - -void CMPCThemeFloatEdit::SetRange(float fLower, float fUpper) -{ - ASSERT(fLower < fUpper); - m_lower = fLower; - m_upper = fUpper; -} - -BEGIN_MESSAGE_MAP(CMPCThemeFloatEdit, CMPCThemeEdit) - ON_WM_CHAR() -END_MESSAGE_MAP() - -void CMPCThemeFloatEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - if (!(nChar >= '0' && nChar <= '9' || nChar == '.' || nChar == '\b' || nChar == '-')) { - return; - } - - if (nChar == '-' && m_lower >= 0) { - return; - } - - CString str; - GetWindowText(str); - - if (nChar == '.' && (str.Find('.') >= 0 || str.IsEmpty())) { - return; - } - - int nStartChar, nEndChar; - GetSel(nStartChar, nEndChar); - - if (nChar == '\b' && nStartChar <= 0) { - return; - } - - CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); -} - -// CIntEdit - -IMPLEMENT_DYNAMIC(CMPCThemeIntEdit, CMPCThemeEdit) - -BEGIN_MESSAGE_MAP(CMPCThemeIntEdit, CMPCThemeEdit) - ON_WM_CHAR() -END_MESSAGE_MAP() - -void CMPCThemeIntEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - if (!(nChar >= '0' && nChar <= '9' || nChar == '-' || nChar == '\b')) { - return; - } - - int nStartChar, nEndChar; - GetSel(nStartChar, nEndChar); - - if (nChar == '-' && nEndChar == 0) { - CString str; - GetWindowText(str); - if (!str.IsEmpty() && str[0] == '-') { - return; - } - } - - if (nChar == '-' && nStartChar != 0) { - return; - } - - CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); -} - -// CHexEdit - -IMPLEMENT_DYNAMIC(CMPCThemeHexEdit, CMPCThemeEdit) - -bool CMPCThemeHexEdit::GetDWORD(DWORD& dw) -{ - CString s; - GetWindowText(s); - return (_stscanf_s(s, _T("%lx"), &dw) == 1); -} - -DWORD CMPCThemeHexEdit::operator = (DWORD dw) -{ - CString s; - s.Format(_T("%08lx"), dw); - SetWindowText(s); - return dw; -} - -CMPCThemeHexEdit::operator DWORD() -{ - CString s; - GetWindowText(s); - DWORD dw; - return (_stscanf_s(s, _T("%lx"), &dw) == 1 ? dw : 0); -} - -BEGIN_MESSAGE_MAP(CMPCThemeHexEdit, CMPCThemeEdit) - ON_WM_CHAR() -END_MESSAGE_MAP() - -void CMPCThemeHexEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) -{ - if (!(nChar >= 'A' && nChar <= 'F' || nChar >= 'a' && nChar <= 'f' - || nChar >= '0' && nChar <= '9' || nChar == '\b')) { - return; - } - - CString str; - GetWindowText(str); - - int nStartChar, nEndChar; - GetSel(nStartChar, nEndChar); - - if (nChar == '\b' && nStartChar <= 0) { - return; - } - - if (nChar != '\b' && nEndChar - nStartChar == 0 && str.GetLength() >= 8) { - return; - } - - CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015 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 . + * + */ + +#include "stdafx.h" +#include "FloatEdit.h" + + +// CFloatEdit + +IMPLEMENT_DYNAMIC(CMPCThemeFloatEdit, CMPCThemeEdit) + +bool CMPCThemeFloatEdit::GetFloat(float& f) +{ + CString s; + GetWindowText(s); + return (_stscanf_s(s, _T("%f"), &f) == 1); +} + +double CMPCThemeFloatEdit::operator = (double d) +{ + CString s; + s.Format(_T("%.4f"), d); + SetWindowText(s); + return d; +} + +CMPCThemeFloatEdit::operator double() +{ + CString s; + GetWindowText(s); + float flt; + if (swscanf_s(s, L"%f", &flt) != 1) { + flt = 0.0f; + } + flt = std::clamp(flt, m_lower, m_upper); + + return flt; +} + +void CMPCThemeFloatEdit::SetRange(float fLower, float fUpper) +{ + ASSERT(fLower < fUpper); + m_lower = fLower; + m_upper = fUpper; +} + +BEGIN_MESSAGE_MAP(CMPCThemeFloatEdit, CMPCThemeEdit) + ON_WM_CHAR() +END_MESSAGE_MAP() + +void CMPCThemeFloatEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (!(nChar >= '0' && nChar <= '9' || nChar == '.' || nChar == '\b' || nChar == '-')) { + return; + } + + if (nChar == '-' && m_lower >= 0) { + return; + } + + CString str; + GetWindowText(str); + + if (nChar == '.' && (str.Find('.') >= 0 || str.IsEmpty())) { + return; + } + + int nStartChar, nEndChar; + GetSel(nStartChar, nEndChar); + + if (nChar == '\b' && nStartChar <= 0) { + return; + } + + CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); +} + +// CIntEdit + +IMPLEMENT_DYNAMIC(CMPCThemeIntEdit, CMPCThemeEdit) + +BEGIN_MESSAGE_MAP(CMPCThemeIntEdit, CMPCThemeEdit) + ON_WM_CHAR() +END_MESSAGE_MAP() + +void CMPCThemeIntEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (!(nChar >= '0' && nChar <= '9' || nChar == '-' || nChar == '\b')) { + return; + } + + int nStartChar, nEndChar; + GetSel(nStartChar, nEndChar); + + if (nChar == '-' && nEndChar == 0) { + CString str; + GetWindowText(str); + if (!str.IsEmpty() && str[0] == '-') { + return; + } + } + + if (nChar == '-' && nStartChar != 0) { + return; + } + + CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); +} + +// CHexEdit + +IMPLEMENT_DYNAMIC(CMPCThemeHexEdit, CMPCThemeEdit) + +bool CMPCThemeHexEdit::GetDWORD(DWORD& dw) +{ + CString s; + GetWindowText(s); + return (_stscanf_s(s, _T("%lx"), &dw) == 1); +} + +DWORD CMPCThemeHexEdit::operator = (DWORD dw) +{ + CString s; + s.Format(_T("%08lx"), dw); + SetWindowText(s); + return dw; +} + +CMPCThemeHexEdit::operator DWORD() +{ + CString s; + GetWindowText(s); + DWORD dw; + return (_stscanf_s(s, _T("%lx"), &dw) == 1 ? dw : 0); +} + +BEGIN_MESSAGE_MAP(CMPCThemeHexEdit, CMPCThemeEdit) + ON_WM_CHAR() +END_MESSAGE_MAP() + +void CMPCThemeHexEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ + if (!(nChar >= 'A' && nChar <= 'F' || nChar >= 'a' && nChar <= 'f' + || nChar >= '0' && nChar <= '9' || nChar == '\b')) { + return; + } + + CString str; + GetWindowText(str); + + int nStartChar, nEndChar; + GetSel(nStartChar, nEndChar); + + if (nChar == '\b' && nStartChar <= 0) { + return; + } + + if (nChar != '\b' && nEndChar - nStartChar == 0 && str.GetLength() >= 8) { + return; + } + + CMPCThemeEdit::OnChar(nChar, nRepCnt, nFlags); +} diff --git a/src/mpc-hc/FloatEdit.h b/src/mpc-hc/FloatEdit.h index 706fc66893a..6c41f4adaf7 100644 --- a/src/mpc-hc/FloatEdit.h +++ b/src/mpc-hc/FloatEdit.h @@ -1,70 +1,70 @@ -/* - * (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 . - * - */ - -#pragma once -#include "CMPCThemeEdit.h" -// CFloatEdit - -class CMPCThemeFloatEdit : public CMPCThemeEdit -{ - float m_lower = -1000000000.0f; - float m_upper = 1000000000.0f; - -public: - bool GetFloat(float& f); - double operator = (double d); - operator double(); - void SetRange(float fLower, float fUpper); - - DECLARE_DYNAMIC(CMPCThemeFloatEdit) - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); -}; - -// CIntEdit - -class CMPCThemeIntEdit : public CMPCThemeEdit -{ -public: - DECLARE_DYNAMIC(CMPCThemeIntEdit) - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); -}; - -// CHexEdit - -class CMPCThemeHexEdit : public CMPCThemeEdit -{ -public: - bool GetDWORD(DWORD& dw); - DWORD operator = (DWORD dw); - operator DWORD(); - - DECLARE_DYNAMIC(CMPCThemeHexEdit) - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); -}; +/* + * (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 . + * + */ + +#pragma once +#include "CMPCThemeEdit.h" +// CFloatEdit + +class CMPCThemeFloatEdit : public CMPCThemeEdit +{ + float m_lower = -1000000000.0f; + float m_upper = 1000000000.0f; + +public: + bool GetFloat(float& f); + double operator = (double d); + operator double(); + void SetRange(float fLower, float fUpper); + + DECLARE_DYNAMIC(CMPCThemeFloatEdit) + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); +}; + +// CIntEdit + +class CMPCThemeIntEdit : public CMPCThemeEdit +{ +public: + DECLARE_DYNAMIC(CMPCThemeIntEdit) + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); +}; + +// CHexEdit + +class CMPCThemeHexEdit : public CMPCThemeEdit +{ +public: + bool GetDWORD(DWORD& dw); + DWORD operator = (DWORD dw); + operator DWORD(); + + DECLARE_DYNAMIC(CMPCThemeHexEdit) + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); +}; diff --git a/src/mpc-hc/FullscreenWnd.cpp b/src/mpc-hc/FullscreenWnd.cpp index d5f6b02ddf5..c1942088c9d 100644 --- a/src/mpc-hc/FullscreenWnd.cpp +++ b/src/mpc-hc/FullscreenWnd.cpp @@ -1,103 +1,103 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "FullscreenWnd.h" -#include "MainFrm.h" - -IMPLEMENT_DYNAMIC(CFullscreenWnd, CMouseWndWithArtView) -CFullscreenWnd::CFullscreenWnd(CMainFrame* pMainFrame) - : CMouseWndWithArtView(pMainFrame, true) - , m_pMainFrame(pMainFrame) -{ -} - -bool CFullscreenWnd::IsWindow() const -{ - return !!m_hWnd; -} - -BOOL CFullscreenWnd::PreTranslateMessage(MSG* pMsg) -{ - switch (pMsg->message) { - case WM_KEYDOWN: - case WM_KEYUP: - m_pMainFrame->PostMessage(pMsg->message, pMsg->wParam, pMsg->lParam); - return TRUE; - } - - return __super::PreTranslateMessage(pMsg); -} - -BOOL CFullscreenWnd::PreCreateWindow(CREATESTRUCT& cs) -{ - cs.style &= ~WS_BORDER; - cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_NOCLOSE, - ::LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), nullptr); - - return __super::PreCreateWindow(cs); -} - -LRESULT CFullscreenWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ -#if 0 - if (message == WM_NCACTIVATE && LOWORD(wParam) == WA_INACTIVE && m_pMainFrame->IsD3DFullScreenMode()) { - return m_pMainFrame->m_pFullscreenWnd == this; - } -#endif - - return __super::WindowProc(message, wParam, lParam); -} - -BEGIN_MESSAGE_MAP(CFullscreenWnd, CMouseWnd) - ON_WM_ERASEBKGND() - ON_WM_DESTROY() -END_MESSAGE_MAP() - -BOOL CFullscreenWnd::OnEraseBkgnd(CDC* pDC) -{ - if (m_pMainFrame->m_fAudioOnly) { - return __super::OnEraseBkgnd(pDC); - } - else { - CRect r; - GetClientRect(r); - pDC->FillSolidRect(r, 0); - return FALSE; - } -} - -void CFullscreenWnd::OnDestroy() -{ - __super::OnDestroy(); - - CWnd* pMainWnd = AfxGetApp()->GetMainWnd(); - if (pMainWnd) { - pMainWnd->SetActiveWindow(); - } -} - -void CFullscreenWnd::SetCursor(LPCWSTR lpCursorName) { - m_hCursor = ::LoadCursorW(nullptr, lpCursorName); - m_bCursorVisible = true; - PostMessageW(WM_SETCURSOR, 0, 0); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "FullscreenWnd.h" +#include "MainFrm.h" + +IMPLEMENT_DYNAMIC(CFullscreenWnd, CMouseWndWithArtView) +CFullscreenWnd::CFullscreenWnd(CMainFrame* pMainFrame) + : CMouseWndWithArtView(pMainFrame, true) + , m_pMainFrame(pMainFrame) +{ +} + +bool CFullscreenWnd::IsWindow() const +{ + return !!m_hWnd; +} + +BOOL CFullscreenWnd::PreTranslateMessage(MSG* pMsg) +{ + switch (pMsg->message) { + case WM_KEYDOWN: + case WM_KEYUP: + m_pMainFrame->PostMessage(pMsg->message, pMsg->wParam, pMsg->lParam); + return TRUE; + } + + return __super::PreTranslateMessage(pMsg); +} + +BOOL CFullscreenWnd::PreCreateWindow(CREATESTRUCT& cs) +{ + cs.style &= ~WS_BORDER; + cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_NOCLOSE, + ::LoadCursor(nullptr, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), nullptr); + + return __super::PreCreateWindow(cs); +} + +LRESULT CFullscreenWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ +#if 0 + if (message == WM_NCACTIVATE && LOWORD(wParam) == WA_INACTIVE && m_pMainFrame->IsD3DFullScreenMode()) { + return m_pMainFrame->m_pFullscreenWnd == this; + } +#endif + + return __super::WindowProc(message, wParam, lParam); +} + +BEGIN_MESSAGE_MAP(CFullscreenWnd, CMouseWnd) + ON_WM_ERASEBKGND() + ON_WM_DESTROY() +END_MESSAGE_MAP() + +BOOL CFullscreenWnd::OnEraseBkgnd(CDC* pDC) +{ + if (m_pMainFrame->m_fAudioOnly) { + return __super::OnEraseBkgnd(pDC); + } + else { + CRect r; + GetClientRect(r); + pDC->FillSolidRect(r, 0); + return FALSE; + } +} + +void CFullscreenWnd::OnDestroy() +{ + __super::OnDestroy(); + + CWnd* pMainWnd = AfxGetApp()->GetMainWnd(); + if (pMainWnd) { + pMainWnd->SetActiveWindow(); + } +} + +void CFullscreenWnd::SetCursor(LPCWSTR lpCursorName) { + m_hCursor = ::LoadCursorW(nullptr, lpCursorName); + m_bCursorVisible = true; + PostMessageW(WM_SETCURSOR, 0, 0); +} diff --git a/src/mpc-hc/FullscreenWnd.h b/src/mpc-hc/FullscreenWnd.h index 0e13a9a2c0f..36a57f67813 100644 --- a/src/mpc-hc/FullscreenWnd.h +++ b/src/mpc-hc/FullscreenWnd.h @@ -1,51 +1,51 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015 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 . - * - */ - -#pragma once - -#include "MouseWndWithArtView.h" - -class CMainFrame; - -class CFullscreenWnd final : public CMouseWndWithArtView -{ - DECLARE_DYNAMIC(CFullscreenWnd) - - explicit CFullscreenWnd(CMainFrame* pMainFrame); - bool IsWindow() const; - void SetCursor(LPCWSTR lpCursorName); - -private: - CMainFrame* m_pMainFrame; - HCURSOR m_hCursor; - bool m_bCursorVisible = false; - bool m_bTrackingMouseLeave = false; - -protected: - BOOL PreCreateWindow(CREATESTRUCT& cs) override; - BOOL PreTranslateMessage(MSG* pMsg) override; - LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam) override; - - DECLARE_MESSAGE_MAP() - - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnDestroy(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015 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 . + * + */ + +#pragma once + +#include "MouseWndWithArtView.h" + +class CMainFrame; + +class CFullscreenWnd final : public CMouseWndWithArtView +{ + DECLARE_DYNAMIC(CFullscreenWnd) + + explicit CFullscreenWnd(CMainFrame* pMainFrame); + bool IsWindow() const; + void SetCursor(LPCWSTR lpCursorName); + +private: + CMainFrame* m_pMainFrame; + HCURSOR m_hCursor; + bool m_bCursorVisible = false; + bool m_bTrackingMouseLeave = false; + +protected: + BOOL PreCreateWindow(CREATESTRUCT& cs) override; + BOOL PreTranslateMessage(MSG* pMsg) override; + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam) override; + + DECLARE_MESSAGE_MAP() + + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnDestroy(); +}; diff --git a/src/mpc-hc/GoToDlg.cpp b/src/mpc-hc/GoToDlg.cpp index 506d175bca3..65cf1027aa3 100644 --- a/src/mpc-hc/GoToDlg.cpp +++ b/src/mpc-hc/GoToDlg.cpp @@ -1,195 +1,195 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "GoToDlg.h" -#include "SettingsDefines.h" -#include - -// CGoToDlg dialog - -IMPLEMENT_DYNAMIC(CGoToDlg, CMPCThemeDialog) -CGoToDlg::CGoToDlg(REFERENCE_TIME time, REFERENCE_TIME maxTime, double fps, CWnd* pParent /*=nullptr*/) - : CMPCThemeDialog(CGoToDlg::IDD, pParent) - , m_time(time) - , m_maxTime(maxTime) - , m_fps(fps) -{ - if (m_fps == 0) { - CString str = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_GOTO_FPS, _T("0")); - float fps2; - if (_stscanf_s(str, _T("%f"), &fps2) == 1) { - m_fps = fps2; - } - } -} - -CGoToDlg::~CGoToDlg() -{ -} - -void CGoToDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialog::DoDataExchange(pDX); - DDX_Text(pDX, IDC_EDIT1, m_timestr); - DDX_Text(pDX, IDC_EDIT2, m_framestr); - DDX_Control(pDX, IDC_EDIT1, m_timeedit); - DDX_Control(pDX, IDC_EDIT2, m_frameedit); - fulfillThemeReqs(); -} - -BOOL CGoToDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - bool showHours = (m_maxTime >= 3600 * 1000 * 10000i64); - - if (showHours) { - m_timeedit.EnableMask(_T("DD DD DD DDD"), _T("__:__:__.___"), L'0', _T("0123456789")); - } else { - m_timeedit.EnableMask(_T("DD DD DDD"), _T("__:__.___"), L'0', _T("0123456789")); - } - m_timeedit.EnableGetMaskedCharsOnly(false); - m_timeedit.EnableSelectByGroup(false); - - int time = (int)(m_time / 10000); - if (time >= 0) { - if (showHours) { - m_timestr.Format(_T("%02d:%02d:%02d.%03d"), - (time / (1000 * 60 * 60)) % 60, - (time / (1000 * 60)) % 60, - (time / 1000) % 60, time % 1000); - } else { - m_timestr.Format(_T("%02d:%02d.%03d"), - (time / (1000 * 60)) % 60, - (time / 1000) % 60, - time % 1000); - } - - if (m_fps > 0) { - m_framestr.Format(_T("%d, %.3f"), (int)(m_fps * m_time / 10000000 + 1.5), m_fps); - } - - UpdateData(FALSE); - - switch (AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_TIME)) { - default: - case TYPE_TIME: - m_timeedit.SetFocus(); - m_timeedit.SetSel(0, 0); - break; - case TYPE_FRAME: - m_frameedit.SetFocus(); - m_frameedit.SetSel(0, m_framestr.Find(',')); - break; - } - - } - - return FALSE; - - // return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - - -BEGIN_MESSAGE_MAP(CGoToDlg, CMPCThemeDialog) - ON_BN_CLICKED(IDC_OK1, OnParseTimeCode) - ON_BN_CLICKED(IDC_OK2, OnParseFrameCode) -END_MESSAGE_MAP() - - -// CGoToDlg message handlers - -void CGoToDlg::OnParseTimeCode() -{ - UpdateData(); - - AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_TIME); - - unsigned int hh = 0; - unsigned int mm = 0; - float ss = 0.0f; - WCHAR c; // extra character to ensure the end of string was reached - - if (((swscanf_s(m_timestr, L"%f%c", &ss, &c, 1) == 1) // ss[.ms] - || (swscanf_s(m_timestr, L"%u:%f%c", &mm, &ss, &c, 1) == 2 && ss < 60.0f) // mm:ss[.ms] - || (swscanf_s(m_timestr, L"%u:%u:%f%c", &hh, &mm, &ss, &c, 1) == 3 && mm < 60 && ss < 60.0f)) // hh:mm:ss[.ms] - && ss >= 0.0f) { - - int time = (int)(1000.0f * ((hh * 60 + mm) * 60 + ss) + 0.5f); - m_time = time * 10000i64; - - OnOK(); - } else { - AfxMessageBox(IDS_GOTO_ERROR_PARSING_TIME, MB_ICONEXCLAMATION | MB_OK, 0); - } -} - -void CGoToDlg::OnParseFrameCode() -{ - UpdateData(); - - AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_FRAME); - - int frame; - float fps; - WCHAR c1; // delimiter character - WCHAR c2; // extra character to ensure the end of string was reached - - int result = swscanf_s(m_framestr, L"%d%c%f%c", &frame, &c1, 1, &fps, &c2, 1); - if (result == 1) { - m_time = frame < 2 ? 0LL : (REFERENCE_TIME)ceil(10000000.0 * (frame - 1) / m_fps); - OnOK(); - } else if (result == 3 && c1 == L',') { - m_time = frame < 2 ? 0LL : (REFERENCE_TIME)ceil(10000000.0 * (frame - 1) / fps); - OnOK(); - } else if (result == 0 || c1 != L',') { - AfxMessageBox(IDS_GOTO_ERROR_PARSING_TEXT, MB_ICONEXCLAMATION | MB_OK, 0); - } else { - AfxMessageBox(IDS_GOTO_ERROR_PARSING_FPS, MB_ICONEXCLAMATION | MB_OK, 0); - } -} - -void CGoToDlg::OnOK() -{ - if (m_time > m_maxTime) { - AfxMessageBox(IDS_GOTO_ERROR_INVALID_TIME, MB_ICONEXCLAMATION | MB_OK, 0); - } else { - __super::OnOK(); - } -} - -BOOL CGoToDlg::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { - if (*GetFocus() == m_timeedit) { - OnParseTimeCode(); - } else if (*GetFocus() == m_frameedit) { - OnParseFrameCode(); - } - - return TRUE; - } - - return __super::PreTranslateMessage(pMsg); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "GoToDlg.h" +#include "SettingsDefines.h" +#include + +// CGoToDlg dialog + +IMPLEMENT_DYNAMIC(CGoToDlg, CMPCThemeDialog) +CGoToDlg::CGoToDlg(REFERENCE_TIME time, REFERENCE_TIME maxTime, double fps, CWnd* pParent /*=nullptr*/) + : CMPCThemeDialog(CGoToDlg::IDD, pParent) + , m_time(time) + , m_maxTime(maxTime) + , m_fps(fps) +{ + if (m_fps == 0) { + CString str = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_GOTO_FPS, _T("0")); + float fps2; + if (_stscanf_s(str, _T("%f"), &fps2) == 1) { + m_fps = fps2; + } + } +} + +CGoToDlg::~CGoToDlg() +{ +} + +void CGoToDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_EDIT1, m_timestr); + DDX_Text(pDX, IDC_EDIT2, m_framestr); + DDX_Control(pDX, IDC_EDIT1, m_timeedit); + DDX_Control(pDX, IDC_EDIT2, m_frameedit); + fulfillThemeReqs(); +} + +BOOL CGoToDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + bool showHours = (m_maxTime >= 3600 * 1000 * 10000i64); + + if (showHours) { + m_timeedit.EnableMask(_T("DD DD DD DDD"), _T("__:__:__.___"), L'0', _T("0123456789")); + } else { + m_timeedit.EnableMask(_T("DD DD DDD"), _T("__:__.___"), L'0', _T("0123456789")); + } + m_timeedit.EnableGetMaskedCharsOnly(false); + m_timeedit.EnableSelectByGroup(false); + + int time = (int)(m_time / 10000); + if (time >= 0) { + if (showHours) { + m_timestr.Format(_T("%02d:%02d:%02d.%03d"), + (time / (1000 * 60 * 60)) % 60, + (time / (1000 * 60)) % 60, + (time / 1000) % 60, time % 1000); + } else { + m_timestr.Format(_T("%02d:%02d.%03d"), + (time / (1000 * 60)) % 60, + (time / 1000) % 60, + time % 1000); + } + + if (m_fps > 0) { + m_framestr.Format(_T("%d, %.3f"), (int)(m_fps * m_time / 10000000 + 1.5), m_fps); + } + + UpdateData(FALSE); + + switch (AfxGetApp()->GetProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_TIME)) { + default: + case TYPE_TIME: + m_timeedit.SetFocus(); + m_timeedit.SetSel(0, 0); + break; + case TYPE_FRAME: + m_frameedit.SetFocus(); + m_frameedit.SetSel(0, m_framestr.Find(',')); + break; + } + + } + + return FALSE; + + // return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + + +BEGIN_MESSAGE_MAP(CGoToDlg, CMPCThemeDialog) + ON_BN_CLICKED(IDC_OK1, OnParseTimeCode) + ON_BN_CLICKED(IDC_OK2, OnParseFrameCode) +END_MESSAGE_MAP() + + +// CGoToDlg message handlers + +void CGoToDlg::OnParseTimeCode() +{ + UpdateData(); + + AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_TIME); + + unsigned int hh = 0; + unsigned int mm = 0; + float ss = 0.0f; + WCHAR c; // extra character to ensure the end of string was reached + + if (((swscanf_s(m_timestr, L"%f%c", &ss, &c, 1) == 1) // ss[.ms] + || (swscanf_s(m_timestr, L"%u:%f%c", &mm, &ss, &c, 1) == 2 && ss < 60.0f) // mm:ss[.ms] + || (swscanf_s(m_timestr, L"%u:%u:%f%c", &hh, &mm, &ss, &c, 1) == 3 && mm < 60 && ss < 60.0f)) // hh:mm:ss[.ms] + && ss >= 0.0f) { + + int time = (int)(1000.0f * ((hh * 60 + mm) * 60 + ss) + 0.5f); + m_time = time * 10000i64; + + OnOK(); + } else { + AfxMessageBox(IDS_GOTO_ERROR_PARSING_TIME, MB_ICONEXCLAMATION | MB_OK, 0); + } +} + +void CGoToDlg::OnParseFrameCode() +{ + UpdateData(); + + AfxGetApp()->WriteProfileInt(IDS_R_SETTINGS, IDS_RS_GOTO_LAST_USED, TYPE_FRAME); + + int frame; + float fps; + WCHAR c1; // delimiter character + WCHAR c2; // extra character to ensure the end of string was reached + + int result = swscanf_s(m_framestr, L"%d%c%f%c", &frame, &c1, 1, &fps, &c2, 1); + if (result == 1) { + m_time = frame < 2 ? 0LL : (REFERENCE_TIME)ceil(10000000.0 * (frame - 1) / m_fps); + OnOK(); + } else if (result == 3 && c1 == L',') { + m_time = frame < 2 ? 0LL : (REFERENCE_TIME)ceil(10000000.0 * (frame - 1) / fps); + OnOK(); + } else if (result == 0 || c1 != L',') { + AfxMessageBox(IDS_GOTO_ERROR_PARSING_TEXT, MB_ICONEXCLAMATION | MB_OK, 0); + } else { + AfxMessageBox(IDS_GOTO_ERROR_PARSING_FPS, MB_ICONEXCLAMATION | MB_OK, 0); + } +} + +void CGoToDlg::OnOK() +{ + if (m_time > m_maxTime) { + AfxMessageBox(IDS_GOTO_ERROR_INVALID_TIME, MB_ICONEXCLAMATION | MB_OK, 0); + } else { + __super::OnOK(); + } +} + +BOOL CGoToDlg::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN) { + if (*GetFocus() == m_timeedit) { + OnParseTimeCode(); + } else if (*GetFocus() == m_frameedit) { + OnParseFrameCode(); + } + + return TRUE; + } + + return __super::PreTranslateMessage(pMsg); +} diff --git a/src/mpc-hc/GoToDlg.h b/src/mpc-hc/GoToDlg.h index bd66aaa638c..e1d482e59bb 100644 --- a/src/mpc-hc/GoToDlg.h +++ b/src/mpc-hc/GoToDlg.h @@ -1,67 +1,67 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include -#include "resource.h" -#include "CMPCThemeDialog.h" -#include "CMPCThemeEdit.h" -#include "CMPCThemeMaskedEdit.h" - - -// CGoToDlg dialog - -class CGoToDlg : public CMPCThemeDialog -{ - DECLARE_DYNAMIC(CGoToDlg) - - enum { TYPE_TIME, TYPE_FRAME }; - -public: - CGoToDlg(REFERENCE_TIME time = -1, REFERENCE_TIME maxTime = -1, double fps = 0, CWnd* pParent = nullptr); // standard constructor - virtual ~CGoToDlg(); - - CString m_timestr; - CString m_framestr; - CMPCThemeMaskedEdit m_timeedit; - CMPCThemeEdit m_frameedit; - - REFERENCE_TIME m_time; - REFERENCE_TIME m_maxTime; - double m_fps; - - // Dialog Data - enum { IDD = IDD_GOTO_DLG }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual BOOL PreTranslateMessage(MSG* pMsg); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnParseTimeCode(); - afx_msg void OnParseFrameCode(); - virtual void OnOK(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include +#include "resource.h" +#include "CMPCThemeDialog.h" +#include "CMPCThemeEdit.h" +#include "CMPCThemeMaskedEdit.h" + + +// CGoToDlg dialog + +class CGoToDlg : public CMPCThemeDialog +{ + DECLARE_DYNAMIC(CGoToDlg) + + enum { TYPE_TIME, TYPE_FRAME }; + +public: + CGoToDlg(REFERENCE_TIME time = -1, REFERENCE_TIME maxTime = -1, double fps = 0, CWnd* pParent = nullptr); // standard constructor + virtual ~CGoToDlg(); + + CString m_timestr; + CString m_framestr; + CMPCThemeMaskedEdit m_timeedit; + CMPCThemeEdit m_frameedit; + + REFERENCE_TIME m_time; + REFERENCE_TIME m_maxTime; + double m_fps; + + // Dialog Data + enum { IDD = IDD_GOTO_DLG }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnParseTimeCode(); + afx_msg void OnParseFrameCode(); + virtual void OnOK(); +}; diff --git a/src/mpc-hc/GraphThread.cpp b/src/mpc-hc/GraphThread.cpp index 3933001e422..97a8110bb94 100644 --- a/src/mpc-hc/GraphThread.cpp +++ b/src/mpc-hc/GraphThread.cpp @@ -1,107 +1,107 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "MainFrm.h" -#include "GraphThread.h" -#include - -IMPLEMENT_DYNCREATE(CGraphThread, CWinThread) - -BOOL CGraphThread::InitInstance() -{ - SetThreadName(DWORD(-1), "GraphThread"); - AfxSocketInit(); - return SUCCEEDED(CoInitialize(nullptr)) ? TRUE : FALSE; -} - -int CGraphThread::ExitInstance() -{ - CoUninitialize(); - return __super::ExitInstance(); -} - -BEGIN_MESSAGE_MAP(CGraphThread, CWinThread) - ON_THREAD_MESSAGE(TM_CLOSE, OnClose) - ON_THREAD_MESSAGE(TM_DISPLAY_CHANGE, OnDisplayChange) - ON_THREAD_MESSAGE(TM_EXIT, OnExit) - ON_THREAD_MESSAGE(TM_OPEN, OnOpen) - ON_THREAD_MESSAGE(TM_RESET, OnReset) - ON_THREAD_MESSAGE(TM_TUNER_SCAN, OnTunerScan) -END_MESSAGE_MAP() - -void CGraphThread::OnClose(WPARAM wParam, LPARAM lParam) -{ - ASSERT(m_pMainFrame); - ASSERT(WaitForSingleObject(m_pMainFrame->m_evClosePrivateFinished, 0) == WAIT_TIMEOUT); - if (m_pMainFrame->GetLoadState() == MLS::CLOSING) { - m_pMainFrame->CloseMediaPrivate(); - } - VERIFY(m_pMainFrame->m_evClosePrivateFinished.Set()); -} - -void CGraphThread::OnDisplayChange(WPARAM wParam, LPARAM lParam) -{ - if (m_pMainFrame) { - m_pMainFrame->DisplayChange(); - } - if (CAMEvent* e = (CAMEvent*)lParam) { - e->Set(); - } -} - -void CGraphThread::OnExit(WPARAM wParam, LPARAM lParam) -{ - PostQuitMessage(0); - if (CAMEvent* e = (CAMEvent*)lParam) { - e->Set(); - } -} - -void CGraphThread::OnOpen(WPARAM wParam, LPARAM lParam) -{ - TRACE(_T("--> CGraphThread::OnOpen on thread: %lu\n"), GetCurrentThreadId()); - ASSERT(m_pMainFrame); - ASSERT(WaitForSingleObject(m_pMainFrame->m_evOpenPrivateFinished, 0) == WAIT_TIMEOUT); - if (m_pMainFrame->GetLoadState() == MLS::LOADING) { - CAutoPtr pOMD((OpenMediaData*)lParam); - m_pMainFrame->OpenMediaPrivate(pOMD); - } - VERIFY(m_pMainFrame->m_evOpenPrivateFinished.Set()); -} - -void CGraphThread::OnReset(WPARAM wParam, LPARAM lParam) -{ - if (m_pMainFrame) { - m_pMainFrame->ResetDevice(); - } - if (CAMEvent* e = (CAMEvent*)lParam) { - e->Set(); - } -} - -void CGraphThread::OnTunerScan(WPARAM wParam, LPARAM lParam) -{ - if (m_pMainFrame) { - CAutoPtr pTSD((TunerScanData*)lParam); - m_pMainFrame->DoTunerScan(pTSD); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "MainFrm.h" +#include "GraphThread.h" +#include + +IMPLEMENT_DYNCREATE(CGraphThread, CWinThread) + +BOOL CGraphThread::InitInstance() +{ + SetThreadName(DWORD(-1), "GraphThread"); + AfxSocketInit(); + return SUCCEEDED(CoInitialize(nullptr)) ? TRUE : FALSE; +} + +int CGraphThread::ExitInstance() +{ + CoUninitialize(); + return __super::ExitInstance(); +} + +BEGIN_MESSAGE_MAP(CGraphThread, CWinThread) + ON_THREAD_MESSAGE(TM_CLOSE, OnClose) + ON_THREAD_MESSAGE(TM_DISPLAY_CHANGE, OnDisplayChange) + ON_THREAD_MESSAGE(TM_EXIT, OnExit) + ON_THREAD_MESSAGE(TM_OPEN, OnOpen) + ON_THREAD_MESSAGE(TM_RESET, OnReset) + ON_THREAD_MESSAGE(TM_TUNER_SCAN, OnTunerScan) +END_MESSAGE_MAP() + +void CGraphThread::OnClose(WPARAM wParam, LPARAM lParam) +{ + ASSERT(m_pMainFrame); + ASSERT(WaitForSingleObject(m_pMainFrame->m_evClosePrivateFinished, 0) == WAIT_TIMEOUT); + if (m_pMainFrame->GetLoadState() == MLS::CLOSING) { + m_pMainFrame->CloseMediaPrivate(); + } + VERIFY(m_pMainFrame->m_evClosePrivateFinished.Set()); +} + +void CGraphThread::OnDisplayChange(WPARAM wParam, LPARAM lParam) +{ + if (m_pMainFrame) { + m_pMainFrame->DisplayChange(); + } + if (CAMEvent* e = (CAMEvent*)lParam) { + e->Set(); + } +} + +void CGraphThread::OnExit(WPARAM wParam, LPARAM lParam) +{ + PostQuitMessage(0); + if (CAMEvent* e = (CAMEvent*)lParam) { + e->Set(); + } +} + +void CGraphThread::OnOpen(WPARAM wParam, LPARAM lParam) +{ + TRACE(_T("--> CGraphThread::OnOpen on thread: %lu\n"), GetCurrentThreadId()); + ASSERT(m_pMainFrame); + ASSERT(WaitForSingleObject(m_pMainFrame->m_evOpenPrivateFinished, 0) == WAIT_TIMEOUT); + if (m_pMainFrame->GetLoadState() == MLS::LOADING) { + CAutoPtr pOMD((OpenMediaData*)lParam); + m_pMainFrame->OpenMediaPrivate(pOMD); + } + VERIFY(m_pMainFrame->m_evOpenPrivateFinished.Set()); +} + +void CGraphThread::OnReset(WPARAM wParam, LPARAM lParam) +{ + if (m_pMainFrame) { + m_pMainFrame->ResetDevice(); + } + if (CAMEvent* e = (CAMEvent*)lParam) { + e->Set(); + } +} + +void CGraphThread::OnTunerScan(WPARAM wParam, LPARAM lParam) +{ + if (m_pMainFrame) { + CAutoPtr pTSD((TunerScanData*)lParam); + m_pMainFrame->DoTunerScan(pTSD); + } +} diff --git a/src/mpc-hc/GraphThread.h b/src/mpc-hc/GraphThread.h index e8a2e49656a..4c87e3dcb1e 100644 --- a/src/mpc-hc/GraphThread.h +++ b/src/mpc-hc/GraphThread.h @@ -1,56 +1,56 @@ -/* - * (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 . - * - */ - -#pragma once - -class CMainFrame; - -class CGraphThread : public CWinThread -{ - DECLARE_DYNCREATE(CGraphThread); -public: - CGraphThread() : m_pMainFrame(nullptr) {} - - BOOL InitInstance(); - int ExitInstance(); - void SetMainFrame(CMainFrame* pMainFrame) { m_pMainFrame = pMainFrame; } - - enum { - TM_EXIT = WM_APP, - TM_OPEN, - TM_CLOSE, - TM_RESET, - TM_TUNER_SCAN, - TM_DISPLAY_CHANGE - }; - -protected: - DECLARE_MESSAGE_MAP() - afx_msg void OnClose(WPARAM wParam, LPARAM lParam); - afx_msg void OnDisplayChange(WPARAM wParam, LPARAM lParam); - afx_msg void OnExit(WPARAM wParam, LPARAM lParam); - afx_msg void OnOpen(WPARAM wParam, LPARAM lParam); - afx_msg void OnReset(WPARAM wParam, LPARAM lParam); - afx_msg void OnTunerScan(WPARAM wParam, LPARAM lParam); - -private: - CMainFrame* m_pMainFrame; -}; +/* + * (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 . + * + */ + +#pragma once + +class CMainFrame; + +class CGraphThread : public CWinThread +{ + DECLARE_DYNCREATE(CGraphThread); +public: + CGraphThread() : m_pMainFrame(nullptr) {} + + BOOL InitInstance(); + int ExitInstance(); + void SetMainFrame(CMainFrame* pMainFrame) { m_pMainFrame = pMainFrame; } + + enum { + TM_EXIT = WM_APP, + TM_OPEN, + TM_CLOSE, + TM_RESET, + TM_TUNER_SCAN, + TM_DISPLAY_CHANGE + }; + +protected: + DECLARE_MESSAGE_MAP() + afx_msg void OnClose(WPARAM wParam, LPARAM lParam); + afx_msg void OnDisplayChange(WPARAM wParam, LPARAM lParam); + afx_msg void OnExit(WPARAM wParam, LPARAM lParam); + afx_msg void OnOpen(WPARAM wParam, LPARAM lParam); + afx_msg void OnReset(WPARAM wParam, LPARAM lParam); + afx_msg void OnTunerScan(WPARAM wParam, LPARAM lParam); + +private: + CMainFrame* m_pMainFrame; +}; diff --git a/src/mpc-hc/IGraphBuilder2.h b/src/mpc-hc/IGraphBuilder2.h index 1f335a2da0b..7429af50b02 100644 --- a/src/mpc-hc/IGraphBuilder2.h +++ b/src/mpc-hc/IGraphBuilder2.h @@ -1,61 +1,61 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016-2017 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 . - * - */ - -#pragma once - -class CMediaType; - -interface __declspec(uuid("165BE9D6-0929-4363-9BA3-580D735AA0F6")) - IGraphBuilder2 : - public IFilterGraph2 -{ - STDMETHOD(IsPinDirection)(IPin* pPin, PIN_DIRECTION dir) PURE; - STDMETHOD(IsPinConnected)(IPin* pPin) PURE; - STDMETHOD(ConnectFilter)(IBaseFilter* pBF, IPin* pPinIn) PURE; - STDMETHOD(ConnectFilter)(IPin* pPinOut, IBaseFilter* pBF) PURE; - STDMETHOD(ConnectFilterDirect)(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) PURE; - STDMETHOD(NukeDownstream)(IUnknown* pUnk) PURE; - STDMETHOD(FindInterface)(REFIID iid, void** ppv, BOOL bRemove) PURE; - STDMETHOD(AddToROT)() PURE; - STDMETHOD(RemoveFromROT)() PURE; -}; - -// private use only -interface __declspec(uuid("43CDA93D-6A4E-4A07-BD3E-49D161073EE7")) - IGraphBuilderDeadEnd : - public IUnknown -{ - STDMETHOD_(size_t, GetCount)() PURE; - STDMETHOD(GetDeadEnd)(int iIndex, CAtlList& path, CAtlList& mts) PURE; -}; - -// private use only -interface __declspec(uuid("546E72B3-66A1-4A58-A99B-56530B3E2FFF")) - IBDATuner : - public IUnknown -{ - STDMETHOD(SetChannel)(int nChannelPrefNumber) PURE; - STDMETHOD(SetAudio)(int nAudioIndex) PURE; - STDMETHOD(SetFrequency)(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) PURE; - STDMETHOD(Scan)(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd) PURE; - STDMETHOD(GetStats)(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality) PURE; - STDMETHOD(UpdatePSI)(const class CBDAChannel* pChannel, struct EventDescriptor& NowNext) PURE; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016-2017 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 . + * + */ + +#pragma once + +class CMediaType; + +interface __declspec(uuid("165BE9D6-0929-4363-9BA3-580D735AA0F6")) + IGraphBuilder2 : + public IFilterGraph2 +{ + STDMETHOD(IsPinDirection)(IPin* pPin, PIN_DIRECTION dir) PURE; + STDMETHOD(IsPinConnected)(IPin* pPin) PURE; + STDMETHOD(ConnectFilter)(IBaseFilter* pBF, IPin* pPinIn) PURE; + STDMETHOD(ConnectFilter)(IPin* pPinOut, IBaseFilter* pBF) PURE; + STDMETHOD(ConnectFilterDirect)(IPin* pPinOut, IBaseFilter* pBF, const AM_MEDIA_TYPE* pmt) PURE; + STDMETHOD(NukeDownstream)(IUnknown* pUnk) PURE; + STDMETHOD(FindInterface)(REFIID iid, void** ppv, BOOL bRemove) PURE; + STDMETHOD(AddToROT)() PURE; + STDMETHOD(RemoveFromROT)() PURE; +}; + +// private use only +interface __declspec(uuid("43CDA93D-6A4E-4A07-BD3E-49D161073EE7")) + IGraphBuilderDeadEnd : + public IUnknown +{ + STDMETHOD_(size_t, GetCount)() PURE; + STDMETHOD(GetDeadEnd)(int iIndex, CAtlList& path, CAtlList& mts) PURE; +}; + +// private use only +interface __declspec(uuid("546E72B3-66A1-4A58-A99B-56530B3E2FFF")) + IBDATuner : + public IUnknown +{ + STDMETHOD(SetChannel)(int nChannelPrefNumber) PURE; + STDMETHOD(SetAudio)(int nAudioIndex) PURE; + STDMETHOD(SetFrequency)(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) PURE; + STDMETHOD(Scan)(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, HWND hWnd) PURE; + STDMETHOD(GetStats)(BOOLEAN& bPresent, BOOLEAN& bLocked, LONG& lDbStrength, LONG& lPercentQuality) PURE; + STDMETHOD(UpdatePSI)(const class CBDAChannel* pChannel, struct EventDescriptor& NowNext) PURE; +}; diff --git a/src/mpc-hc/Ifo.cpp b/src/mpc-hc/Ifo.cpp index 9f8dfb80a9a..d01363558a2 100644 --- a/src/mpc-hc/Ifo.cpp +++ b/src/mpc-hc/Ifo.cpp @@ -1,282 +1,282 @@ -/* - * (C) 2008-2014 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 . - * - */ - -#include "stdafx.h" -#include "Ifo.h" - - -#ifdef WORDS_BIGENDIAN -#define bswap_16(x) (x) -#define bswap_32(x) (x) -#define bswap_64(x) (x) -#else - -// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. -#define bswap_16(x) \ - ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) - -// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. -#define bswap_32(x) \ - ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ - (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) - -#define bswap_64(x) \ - (__extension__ \ - ({ union { __extension__ unsigned long long int __ll; \ - unsigned long int __l[2]; } __w, __r; \ - __w.__ll = (x); \ - __r.__l[0] = bswap_32 (__w.__l[1]); \ - __r.__l[1] = bswap_32 (__w.__l[0]); \ - __r.__ll; })) -#endif - -#ifdef WORDS_BIGENDIAN -#define be2me_16(x) (x) -#define be2me_32(x) (x) -#define be2me_64(x) (x) -#define le2me_16(x) bswap_16(x) -#define le2me_32(x) bswap_32(x) -#define le2me_64(x) bswap_64(x) -#else -#define be2me_16(x) bswap_16(x) -#define be2me_32(x) bswap_32(x) -#define be2me_64(x) bswap_64(x) -#define le2me_16(x) (x) -#define le2me_32(x) (x) -#define le2me_64(x) (x) -#endif - -#define DVD_VIDEO_LB_LEN 2048 -#define IFO_HDR_LEN 8 -#define LU_SUB_LEN 8 - -extern HANDLE(__stdcall* Real_CreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); - - -uint32_t get4bytes(const BYTE* buf) -{ - return be2me_32(*((uint32_t*)buf)); -} - - -// VMG files -#define OFF_VMGM_PGCI_UT(buf) get4bytes (buf + 0xC8) - -// VTS files -#define OFF_VTSM_PGCI_UT(buf) get4bytes (buf + 0xD0) -#define OFF_VTS_PGCIT(buf) get4bytes (buf + 0xCC) - - -CIfo::CIfo() - : m_pBuffer(nullptr) - , m_dwSize(0) - , m_pPGCI(nullptr) - , m_pPGCIT(nullptr) -{ -} - -CIfo::~CIfo() -{ - delete [] m_pBuffer; -} - -int CIfo::GetMiscPGCI(CIfo::ifo_hdr_t* hdr, int title, uint8_t** ptr) -{ - pgci_sub_t* pgci_sub; - - *ptr = (uint8_t*) hdr; - *ptr += IFO_HDR_LEN; - pgci_sub = (pgci_sub_t*) *ptr + title; - - *ptr = (uint8_t*) hdr + be2me_32(pgci_sub->start); - - return 0; -} - -void CIfo::RemovePgciUOPs(uint8_t* ptr) -{ - ifo_hdr_t* hdr = (ifo_hdr_t*) ptr; - uint16_t num; - int i; - - ptr += IFO_HDR_LEN; - num = be2me_16(hdr->num); - - for (i = 1; i <= num; i++) { - lu_sub_t* lu_sub = (lu_sub_t*) ptr; - UNREFERENCED_PARAMETER(lu_sub); - - ptr += LU_SUB_LEN; - } - - for (i = 0; i < be2me_16(hdr->num); i++) { - uint8_t* ptr2; - - if (GetMiscPGCI(hdr, i, &ptr2) >= 0) { - pgc_t* pgc = (pgc_t*) ptr2; - pgc->prohibited_ops = 0; - } - } -} - -CIfo::pgc_t* CIfo::GetFirstPGC() -{ - if (m_pBuffer) { - return (pgc_t*)(m_pBuffer + 0x0400); - } else { - return nullptr; - } -} - -CIfo::pgc_t* CIfo::GetPGCI(const int title, const ifo_hdr_t* hdr) -{ - CIfo::pgci_sub_t* pgci_sub; - uint8_t* ptr; - - ptr = (uint8_t*) hdr; - ptr += IFO_HDR_LEN; - - pgci_sub = (pgci_sub_t*) ptr + title; - - ptr = (uint8_t*) hdr + be2me_32(pgci_sub->start); - - /* jdw */ - if (ptr >= ((uint8_t*) hdr + be2me_32(hdr->len))) { - return nullptr; - } - /* /jdw */ - - return (pgc_t*) ptr; -} - -bool CIfo::IsVTS() -{ - if (m_dwSize < 12 || (strncmp((char*)m_pBuffer, "DVDVIDEO-VTS", 12) != 0)) { - return false; - } - - return true; -} - -bool CIfo::IsVMG() -{ - if (m_dwSize < 12 || (strncmp((char*)m_pBuffer, "DVDVIDEO-VMG", 12) != 0)) { - return false; - } - - return true; -} - -bool CIfo::OpenFile(LPCTSTR strFile) -{ - bool bRet = false; - - HANDLE hFile = Real_CreateFileW(strFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile != INVALID_HANDLE_VALUE) { - LARGE_INTEGER size; - // min size of the ifo file comes from dvd sector size, - // max size we allow is 8 MB (taken with reserve), - // also the file size must a multiple of dvd sector size - if (GetFileSizeEx(hFile, &size) && (size.QuadPart >= DVD_VIDEO_LB_LEN) && - (size.QuadPart <= 0x800000) && !(size.QuadPart % DVD_VIDEO_LB_LEN)) { - ASSERT(!m_pBuffer); - m_pBuffer = DEBUG_NEW BYTE [(size_t)size.QuadPart]; - if (ReadFile(hFile, m_pBuffer, (DWORD)size.QuadPart, &m_dwSize, nullptr)) { - ASSERT(!m_pPGCI); - ASSERT(!m_pPGCIT); - uint32_t sector, sectorCount = (uint32_t)size.QuadPart / DVD_VIDEO_LB_LEN; - if (IsVTS()) { - sector = OFF_VTSM_PGCI_UT(m_pBuffer); - if (sector && (sector < sectorCount)) { - m_pPGCI = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); - } else { - TRACE(_T("IFO: Missing or invalid VTSM_PGCI_UT sector\n")); - } - sector = OFF_VTS_PGCIT(m_pBuffer); - if (sector && (sector < sectorCount)) { - m_pPGCIT = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); - } else { - TRACE(_T("IFO: Missing or invalid VTS_PGCI sector\n")); - } - } else if (IsVMG()) { - sector = OFF_VMGM_PGCI_UT(m_pBuffer); - if (sector && (sector < sectorCount)) { - m_pPGCI = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); - } else { - TRACE(_T("IFO: Missing or invalid VTSM_PGCI_UT sector\n")); - } - } - bRet = (m_pPGCI != nullptr); - } - } - CloseHandle(hFile); - } else { - ASSERT(FALSE); - } - - return bRet; -} - -bool CIfo::RemoveUOPs() -{ - pgc_t* pgc; - - if (m_pPGCI) { - pgc = GetFirstPGC(); - pgc->prohibited_ops = 0; - - for (int i = 0; i < be2me_16(m_pPGCI->num); i++) { - pgc = GetPGCI(i, m_pPGCI); - if (pgc) { - RemovePgciUOPs((uint8_t*)pgc); - } - } - } - if (m_pPGCIT) { - for (int i = 0; i < be2me_16(m_pPGCIT->num); i++) { - pgc = GetPGCI(i, m_pPGCIT); - if (pgc) { - pgc->prohibited_ops = 0; - } - } - } - return true; -} - -bool CIfo::SaveFile(LPCTSTR strFile) -{ - bool bRet = false; - - if (m_pBuffer) { - HANDLE hFile = Real_CreateFileW(strFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile != INVALID_HANDLE_VALUE) { - DWORD written; - if (WriteFile(hFile, m_pBuffer, m_dwSize, &written, nullptr)) { - bRet = true; - } - CloseHandle(hFile); - } - } - - ASSERT(bRet); - - return bRet; -} +/* + * (C) 2008-2014 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 . + * + */ + +#include "stdafx.h" +#include "Ifo.h" + + +#ifdef WORDS_BIGENDIAN +#define bswap_16(x) (x) +#define bswap_32(x) (x) +#define bswap_64(x) (x) +#else + +// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. +#define bswap_16(x) \ + ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) + +// code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. +#define bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define bswap_64(x) \ + (__extension__ \ + ({ union { __extension__ unsigned long long int __ll; \ + unsigned long int __l[2]; } __w, __r; \ + __w.__ll = (x); \ + __r.__l[0] = bswap_32 (__w.__l[1]); \ + __r.__l[1] = bswap_32 (__w.__l[0]); \ + __r.__ll; })) +#endif + +#ifdef WORDS_BIGENDIAN +#define be2me_16(x) (x) +#define be2me_32(x) (x) +#define be2me_64(x) (x) +#define le2me_16(x) bswap_16(x) +#define le2me_32(x) bswap_32(x) +#define le2me_64(x) bswap_64(x) +#else +#define be2me_16(x) bswap_16(x) +#define be2me_32(x) bswap_32(x) +#define be2me_64(x) bswap_64(x) +#define le2me_16(x) (x) +#define le2me_32(x) (x) +#define le2me_64(x) (x) +#endif + +#define DVD_VIDEO_LB_LEN 2048 +#define IFO_HDR_LEN 8 +#define LU_SUB_LEN 8 + +extern HANDLE(__stdcall* Real_CreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + + +uint32_t get4bytes(const BYTE* buf) +{ + return be2me_32(*((uint32_t*)buf)); +} + + +// VMG files +#define OFF_VMGM_PGCI_UT(buf) get4bytes (buf + 0xC8) + +// VTS files +#define OFF_VTSM_PGCI_UT(buf) get4bytes (buf + 0xD0) +#define OFF_VTS_PGCIT(buf) get4bytes (buf + 0xCC) + + +CIfo::CIfo() + : m_pBuffer(nullptr) + , m_dwSize(0) + , m_pPGCI(nullptr) + , m_pPGCIT(nullptr) +{ +} + +CIfo::~CIfo() +{ + delete [] m_pBuffer; +} + +int CIfo::GetMiscPGCI(CIfo::ifo_hdr_t* hdr, int title, uint8_t** ptr) +{ + pgci_sub_t* pgci_sub; + + *ptr = (uint8_t*) hdr; + *ptr += IFO_HDR_LEN; + pgci_sub = (pgci_sub_t*) *ptr + title; + + *ptr = (uint8_t*) hdr + be2me_32(pgci_sub->start); + + return 0; +} + +void CIfo::RemovePgciUOPs(uint8_t* ptr) +{ + ifo_hdr_t* hdr = (ifo_hdr_t*) ptr; + uint16_t num; + int i; + + ptr += IFO_HDR_LEN; + num = be2me_16(hdr->num); + + for (i = 1; i <= num; i++) { + lu_sub_t* lu_sub = (lu_sub_t*) ptr; + UNREFERENCED_PARAMETER(lu_sub); + + ptr += LU_SUB_LEN; + } + + for (i = 0; i < be2me_16(hdr->num); i++) { + uint8_t* ptr2; + + if (GetMiscPGCI(hdr, i, &ptr2) >= 0) { + pgc_t* pgc = (pgc_t*) ptr2; + pgc->prohibited_ops = 0; + } + } +} + +CIfo::pgc_t* CIfo::GetFirstPGC() +{ + if (m_pBuffer) { + return (pgc_t*)(m_pBuffer + 0x0400); + } else { + return nullptr; + } +} + +CIfo::pgc_t* CIfo::GetPGCI(const int title, const ifo_hdr_t* hdr) +{ + CIfo::pgci_sub_t* pgci_sub; + uint8_t* ptr; + + ptr = (uint8_t*) hdr; + ptr += IFO_HDR_LEN; + + pgci_sub = (pgci_sub_t*) ptr + title; + + ptr = (uint8_t*) hdr + be2me_32(pgci_sub->start); + + /* jdw */ + if (ptr >= ((uint8_t*) hdr + be2me_32(hdr->len))) { + return nullptr; + } + /* /jdw */ + + return (pgc_t*) ptr; +} + +bool CIfo::IsVTS() +{ + if (m_dwSize < 12 || (strncmp((char*)m_pBuffer, "DVDVIDEO-VTS", 12) != 0)) { + return false; + } + + return true; +} + +bool CIfo::IsVMG() +{ + if (m_dwSize < 12 || (strncmp((char*)m_pBuffer, "DVDVIDEO-VMG", 12) != 0)) { + return false; + } + + return true; +} + +bool CIfo::OpenFile(LPCTSTR strFile) +{ + bool bRet = false; + + HANDLE hFile = Real_CreateFileW(strFile, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile != INVALID_HANDLE_VALUE) { + LARGE_INTEGER size; + // min size of the ifo file comes from dvd sector size, + // max size we allow is 8 MB (taken with reserve), + // also the file size must a multiple of dvd sector size + if (GetFileSizeEx(hFile, &size) && (size.QuadPart >= DVD_VIDEO_LB_LEN) && + (size.QuadPart <= 0x800000) && !(size.QuadPart % DVD_VIDEO_LB_LEN)) { + ASSERT(!m_pBuffer); + m_pBuffer = DEBUG_NEW BYTE [(size_t)size.QuadPart]; + if (ReadFile(hFile, m_pBuffer, (DWORD)size.QuadPart, &m_dwSize, nullptr)) { + ASSERT(!m_pPGCI); + ASSERT(!m_pPGCIT); + uint32_t sector, sectorCount = (uint32_t)size.QuadPart / DVD_VIDEO_LB_LEN; + if (IsVTS()) { + sector = OFF_VTSM_PGCI_UT(m_pBuffer); + if (sector && (sector < sectorCount)) { + m_pPGCI = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); + } else { + TRACE(_T("IFO: Missing or invalid VTSM_PGCI_UT sector\n")); + } + sector = OFF_VTS_PGCIT(m_pBuffer); + if (sector && (sector < sectorCount)) { + m_pPGCIT = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); + } else { + TRACE(_T("IFO: Missing or invalid VTS_PGCI sector\n")); + } + } else if (IsVMG()) { + sector = OFF_VMGM_PGCI_UT(m_pBuffer); + if (sector && (sector < sectorCount)) { + m_pPGCI = (ifo_hdr_t*)(m_pBuffer + sector * DVD_VIDEO_LB_LEN); + } else { + TRACE(_T("IFO: Missing or invalid VTSM_PGCI_UT sector\n")); + } + } + bRet = (m_pPGCI != nullptr); + } + } + CloseHandle(hFile); + } else { + ASSERT(FALSE); + } + + return bRet; +} + +bool CIfo::RemoveUOPs() +{ + pgc_t* pgc; + + if (m_pPGCI) { + pgc = GetFirstPGC(); + pgc->prohibited_ops = 0; + + for (int i = 0; i < be2me_16(m_pPGCI->num); i++) { + pgc = GetPGCI(i, m_pPGCI); + if (pgc) { + RemovePgciUOPs((uint8_t*)pgc); + } + } + } + if (m_pPGCIT) { + for (int i = 0; i < be2me_16(m_pPGCIT->num); i++) { + pgc = GetPGCI(i, m_pPGCIT); + if (pgc) { + pgc->prohibited_ops = 0; + } + } + } + return true; +} + +bool CIfo::SaveFile(LPCTSTR strFile) +{ + bool bRet = false; + + if (m_pBuffer) { + HANDLE hFile = Real_CreateFileW(strFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile != INVALID_HANDLE_VALUE) { + DWORD written; + if (WriteFile(hFile, m_pBuffer, m_dwSize, &written, nullptr)) { + bRet = true; + } + CloseHandle(hFile); + } + } + + ASSERT(bRet); + + return bRet; +} diff --git a/src/mpc-hc/Ifo.h b/src/mpc-hc/Ifo.h index fe9b5c51ee9..86e63a53262 100644 --- a/src/mpc-hc/Ifo.h +++ b/src/mpc-hc/Ifo.h @@ -1,186 +1,186 @@ -/* - * (C) 2008-2013, 2016 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 . - * - */ - -#pragma once - -#include - -#pragma pack(push, 1) - - -class CIfo -{ -public: - CIfo(); - ~CIfo(); - - bool OpenFile(LPCTSTR strFile); - bool SaveFile(LPCTSTR strFile); - bool RemoveUOPs(); - -private: - - struct pgci_sub_t { - uint16_t id : 16; // Language - uint16_t : 16; // don't know - uint32_t start : 32; // Start of unit - }; - - struct dvd_time_t { - uint8_t hour; - uint8_t minute; - uint8_t second; - uint8_t frame_u; // The two high bits are the frame rate. - }; - - typedef uint8_t command_data_t[8]; -#define COMMAND_DATA_SIZE 8 - - struct pgc_command_tbl_t { // PGC Command Table - uint16_t nr_of_pre; - uint16_t nr_of_post; - uint16_t nr_of_cell; - uint16_t tbl_len; - command_data_t* pre_commands; - command_data_t* post_commands; - command_data_t* cell_commands; - }; -#define PGC_COMMAND_TBL_SIZE 8 - - typedef uint8_t pgc_program_map_t; - - struct ifo_pgci_caddr_t { // Cell Playback Information - uint8_t chain_info : 8; // 0x5e 0xde(2 angles, no overlay), 0x5f 0x9f 0x9f 0xdf(4 angles overlay), 0x2 0xa 0x8(1 angle) - uint8_t foo; // parental control ?? - uint8_t still_time; - uint8_t cell_cmd; - - dvd_time_t playback_time; - uint32_t vobu_start; // 1st vobu start - uint32_t ilvu_end; - uint32_t vobu_last_start; - uint32_t vobu_last_end; - }; - - struct ifo_pgc_cpos_t { // Cell Position Information - uint16_t vob_id : 16; // Video Object Identifier - uint8_t foo : 8; // Unknown - uint8_t cell_id : 8; // Cell Identifier - }; - -#ifndef CLUT_T -#define CLUT_T - - struct clut_t { // CLUT == Color LookUp Table - uint8_t foo : 8; // UNKNOWN: 0x00? - uint8_t y : 8; - uint8_t cr : 8; - uint8_t cb : 8; - }; -#endif - - struct audio_status_t { // Audio Status -#if BYTE_ORDER == BIG_ENDIAN - uint8_t available : 1; - uint8_t link : 7; -#else - uint8_t link : 7; - uint8_t available : 1; -#endif - uint8_t foo : 8; // UNKNOWN - }; - - - struct subp_status_t { // Subpicture status -#if BYTE_ORDER == BIG_ENDIAN - uint8_t available : 1; - uint8_t format4_3 : 7; -#else - uint8_t format4_3 : 7; - uint8_t available : 1; -#endif - uint8_t wide : 8; - uint8_t letter : 8; - uint8_t pan : 8; - }; - - - struct pgc_t { // Program Chain Information - uint16_t zero_1; - uint8_t nr_of_programs; - uint8_t nr_of_cells; - dvd_time_t playback_time; - uint32_t prohibited_ops; // New type? - audio_status_t audio_status[8]; - subp_status_t subp_status[32]; - uint16_t next_pgc_nr; - uint16_t prev_pgc_nr; - uint16_t goup_pgc_nr; - uint8_t still_time; - uint8_t pg_playback_mode; - clut_t clut[16]; - uint16_t pgc_command_tbl_offset; - uint16_t pgc_program_map_offset; - uint16_t cell_playback_tbl_offset; - uint16_t cell_position_tbl_offset; - pgc_command_tbl_t* pgc_command_tbl; - pgc_program_map_t* pgc_program_map; - ifo_pgci_caddr_t* cell_playback_tbl; - ifo_pgc_cpos_t* cell_position_tbl; - }; -#define PGC_SIZE 236 - - struct ifo_hdr_t { - uint16_t num : 16; // number of entries - uint16_t : 16; // UNKNOWN - uint32_t len : 32; // length of table - }; - - struct lu_sub_t { -#if BYTE_ORDER == BIG_ENDIAN - uint16_t foo1 : 4; // don't know - uint8_t menu_id : 4; // 0=off, 3=root, 4=spu, - // 5=audio, 6=angle, 7=ptt -#else - uint8_t menu_id : 4; // 0=off, 3=root, 4=spu, - // 5=audio, 6=angle, 7=ptt - uint16_t foo1 : 4; // don't know -#endif - uint16_t foo2 : 8; // don't know - uint16_t bar : 16; // don't know - uint32_t start : 32; // Start of unit - }; - - - BYTE* m_pBuffer; - DWORD m_dwSize; - - ifo_hdr_t* m_pPGCI; - ifo_hdr_t* m_pPGCIT; - - bool IsVTS(); - bool IsVMG(); - - pgc_t* GetFirstPGC(); - pgc_t* GetPGCI(const int title, const ifo_hdr_t* hdr); - int GetMiscPGCI(ifo_hdr_t* hdr, int title, uint8_t** ptr); - void RemovePgciUOPs(uint8_t* ptr); -}; -#pragma pack(pop) +/* + * (C) 2008-2013, 2016 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 . + * + */ + +#pragma once + +#include + +#pragma pack(push, 1) + + +class CIfo +{ +public: + CIfo(); + ~CIfo(); + + bool OpenFile(LPCTSTR strFile); + bool SaveFile(LPCTSTR strFile); + bool RemoveUOPs(); + +private: + + struct pgci_sub_t { + uint16_t id : 16; // Language + uint16_t : 16; // don't know + uint32_t start : 32; // Start of unit + }; + + struct dvd_time_t { + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t frame_u; // The two high bits are the frame rate. + }; + + typedef uint8_t command_data_t[8]; +#define COMMAND_DATA_SIZE 8 + + struct pgc_command_tbl_t { // PGC Command Table + uint16_t nr_of_pre; + uint16_t nr_of_post; + uint16_t nr_of_cell; + uint16_t tbl_len; + command_data_t* pre_commands; + command_data_t* post_commands; + command_data_t* cell_commands; + }; +#define PGC_COMMAND_TBL_SIZE 8 + + typedef uint8_t pgc_program_map_t; + + struct ifo_pgci_caddr_t { // Cell Playback Information + uint8_t chain_info : 8; // 0x5e 0xde(2 angles, no overlay), 0x5f 0x9f 0x9f 0xdf(4 angles overlay), 0x2 0xa 0x8(1 angle) + uint8_t foo; // parental control ?? + uint8_t still_time; + uint8_t cell_cmd; + + dvd_time_t playback_time; + uint32_t vobu_start; // 1st vobu start + uint32_t ilvu_end; + uint32_t vobu_last_start; + uint32_t vobu_last_end; + }; + + struct ifo_pgc_cpos_t { // Cell Position Information + uint16_t vob_id : 16; // Video Object Identifier + uint8_t foo : 8; // Unknown + uint8_t cell_id : 8; // Cell Identifier + }; + +#ifndef CLUT_T +#define CLUT_T + + struct clut_t { // CLUT == Color LookUp Table + uint8_t foo : 8; // UNKNOWN: 0x00? + uint8_t y : 8; + uint8_t cr : 8; + uint8_t cb : 8; + }; +#endif + + struct audio_status_t { // Audio Status +#if BYTE_ORDER == BIG_ENDIAN + uint8_t available : 1; + uint8_t link : 7; +#else + uint8_t link : 7; + uint8_t available : 1; +#endif + uint8_t foo : 8; // UNKNOWN + }; + + + struct subp_status_t { // Subpicture status +#if BYTE_ORDER == BIG_ENDIAN + uint8_t available : 1; + uint8_t format4_3 : 7; +#else + uint8_t format4_3 : 7; + uint8_t available : 1; +#endif + uint8_t wide : 8; + uint8_t letter : 8; + uint8_t pan : 8; + }; + + + struct pgc_t { // Program Chain Information + uint16_t zero_1; + uint8_t nr_of_programs; + uint8_t nr_of_cells; + dvd_time_t playback_time; + uint32_t prohibited_ops; // New type? + audio_status_t audio_status[8]; + subp_status_t subp_status[32]; + uint16_t next_pgc_nr; + uint16_t prev_pgc_nr; + uint16_t goup_pgc_nr; + uint8_t still_time; + uint8_t pg_playback_mode; + clut_t clut[16]; + uint16_t pgc_command_tbl_offset; + uint16_t pgc_program_map_offset; + uint16_t cell_playback_tbl_offset; + uint16_t cell_position_tbl_offset; + pgc_command_tbl_t* pgc_command_tbl; + pgc_program_map_t* pgc_program_map; + ifo_pgci_caddr_t* cell_playback_tbl; + ifo_pgc_cpos_t* cell_position_tbl; + }; +#define PGC_SIZE 236 + + struct ifo_hdr_t { + uint16_t num : 16; // number of entries + uint16_t : 16; // UNKNOWN + uint32_t len : 32; // length of table + }; + + struct lu_sub_t { +#if BYTE_ORDER == BIG_ENDIAN + uint16_t foo1 : 4; // don't know + uint8_t menu_id : 4; // 0=off, 3=root, 4=spu, + // 5=audio, 6=angle, 7=ptt +#else + uint8_t menu_id : 4; // 0=off, 3=root, 4=spu, + // 5=audio, 6=angle, 7=ptt + uint16_t foo1 : 4; // don't know +#endif + uint16_t foo2 : 8; // don't know + uint16_t bar : 16; // don't know + uint32_t start : 32; // Start of unit + }; + + + BYTE* m_pBuffer; + DWORD m_dwSize; + + ifo_hdr_t* m_pPGCI; + ifo_hdr_t* m_pPGCIT; + + bool IsVTS(); + bool IsVMG(); + + pgc_t* GetFirstPGC(); + pgc_t* GetPGCI(const int title, const ifo_hdr_t* hdr); + int GetMiscPGCI(ifo_hdr_t* hdr, int title, uint8_t** ptr); + void RemovePgciUOPs(uint8_t* ptr); +}; +#pragma pack(pop) diff --git a/src/mpc-hc/ImageGrayer.cpp b/src/mpc-hc/ImageGrayer.cpp index 35bbeb0f1ae..a858ac58448 100644 --- a/src/mpc-hc/ImageGrayer.cpp +++ b/src/mpc-hc/ImageGrayer.cpp @@ -1,304 +1,304 @@ -/* -* (C) 2016 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 . -* -*/ - -#include "stdafx.h" -#include "ImageGrayer.h" -#include "CMPCTheme.h" - -struct HLS { - double H, L, S; - - HLS(const RGBQUAD& rgb) { - double R = rgb.rgbRed / 255.0; - double G = rgb.rgbGreen / 255.0; - double B = rgb.rgbBlue / 255.0; - double max = std::max({ R, G, B }); - double min = std::min({ R, G, B }); - - L = (max + min) / 2.0; - - if (max == min) { - S = H = 0.0; - } else { - double d = max - min; - - S = (L < 0.5) ? (d / (max + min)) : (d / (2.0 - max - min)); - - if (R == max) { - H = (G - B) / d; - } else if (G == max) { - H = 2.0 + (B - R) / d; - } else { // if (B == max) - H = 4.0 + (R - G) / d; - } - H /= 6.0; - if (H < 0.0) { - H += 1.0; - } - } - } - - RGBQUAD toRGBQUAD() { - RGBQUAD rgb; - rgb.rgbReserved = 255; - - if (S == 0.0) { - rgb.rgbRed = rgb.rgbGreen = rgb.rgbBlue = BYTE(L * 255); - } else { - auto hue2rgb = [](double p, double q, double h) { - if (h < 0.0) { - h += 1.0; - } else if (h > 1.0) { - h -= 1.0; - } - - if (h < 1.0 / 6.0) { - return p + (q - p) * 6.0 * h; - } else if (h < 0.5) { - return q; - } else if (h < 2.0 / 3.0) { - return p + (q - p) * (2.0 / 3.0 - h) * 6.0; - } - return p; - }; - - double q = (L < 0.5) ? (L * (1 + S)) : (L + S - L * S); - double p = 2 * L - q; - - rgb.rgbRed = BYTE(hue2rgb(p, q, H + 1.0 / 3.0) * 255); - rgb.rgbGreen = BYTE(hue2rgb(p, q, H) * 255); - rgb.rgbBlue = BYTE(hue2rgb(p, q, H - 1.0 / 3.0) * 255); - } - - return rgb; - } -}; - -bool ImageGrayer::Gray(const CImage& imgSource, CImage& imgDest, float brightness) -{ - // Only support 32-bit image for now - if (imgSource.GetBPP() != 32) { - return false; - } - - imgDest.Destroy(); - if (!imgDest.Create(imgSource.GetWidth(), imgSource.GetHeight(), imgSource.GetBPP())) { - return false; - } - BOOL bCopied = imgSource.BitBlt(imgDest.GetDC(), 0, 0); - imgDest.ReleaseDC(); - if (!bCopied) { - return false; - } - - auto adjustBrightness = [](BYTE c, double p) { - int cAdjusted; - if (c == 0 && p > 1.0) { - cAdjusted = std::lround((p - 1.0) * 255); - } else { - cAdjusted = std::lround(c * p); - } - - return BYTE(std::min(cAdjusted, 255)); - }; - - BYTE* bits = static_cast(imgDest.GetBits()); - for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < imgDest.GetWidth(); x++) { - HLS hls(p[x]); - hls.S = 0.0; // Make the color gray - - RGBQUAD rgb = hls.toRGBQUAD(); - - p[x].rgbRed = BYTE(adjustBrightness(rgb.rgbRed, 1.5 * brightness) * p[x].rgbReserved / 255); - p[x].rgbGreen = BYTE(adjustBrightness(rgb.rgbGreen, 1.5 * brightness) * p[x].rgbReserved / 255); - p[x].rgbBlue = BYTE(adjustBrightness(rgb.rgbBlue, 1.5 * brightness) * p[x].rgbReserved / 255); - } - } - - return true; -} - -bool ImageGrayer::UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle) -{ - // Force to 32-bit - CImage img32; - CImage const* imgSrc; - if (imgSource.GetBPP() != 32) { - if (!img32.Create(imgSource.GetWidth(), imgSource.GetHeight(), 32, CImage::createAlphaChannel)) { - return false; - } - - HDC const iDC = img32.GetDC(); - BOOL const bbResult = imgSource.BitBlt(iDC, 0, 0, SRCCOPY); - img32.ReleaseDC(); - - if (!bbResult) { - return false; - } - - BYTE* bits = static_cast(img32.GetBits()); - for (int y = 0; y < img32.GetHeight(); y++, bits += img32.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < img32.GetWidth(); x++) { - HLS hls(p[x]); - p[x].rgbReserved = 255; - } - } - imgSrc = &img32; - } else { - imgSrc = &imgSource; - } - - if (colorStyle == ImageGrayer::classicGrayscale) { - return Gray(imgSource, imgDest); - } else if (colorStyle == ImageGrayer::mpcGrayDisabled) { - if (disabled) { - return Gray(imgSource, imgDest, 0.5f); - } else { - imgDest = imgSource; - } - } else { //mpcMono - imgDest.Destroy(); - - if (!imgDest.Create(imgSrc->GetWidth(), imgSrc->GetHeight(), imgSrc->GetBPP())) { - return false; - } - BOOL bCopied = imgSrc->BitBlt(imgDest.GetDC(), 0, 0); - imgDest.ReleaseDC(); - if (!bCopied) { - return false; - } - - RGBQUAD newColor; - COLORREF themeColor; - - if (disabled) { - themeColor = CMPCTheme::ImageDisabledColor; - } else { - themeColor = CMPCTheme::TextFGColorFade; - } - newColor.rgbRed = GetRValue(themeColor); - newColor.rgbGreen = GetGValue(themeColor); - newColor.rgbBlue = GetBValue(themeColor); - newColor.rgbReserved = 0; - - - - BYTE* bits = static_cast(imgDest.GetBits()); - for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < imgDest.GetWidth(); x++) { - HLS hls(p[x]); - - RGBQUAD rgb = hls.toRGBQUAD(); - - if (p[x].rgbReserved != 0) { //ignore the transparent bits - p[x].rgbRed = newColor.rgbRed; - p[x].rgbBlue = newColor.rgbBlue; - p[x].rgbGreen = newColor.rgbGreen; - } - } - } - } - - return true; -} - -bool ImageGrayer::Colorize(const CImage& imgSrc, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90) { - // Force to 32-bit - if (imgSrc.GetBPP() != 32) { - return false; - } - - imgDest.Destroy(); - - int width = imgSrc.GetWidth(); - int height = imgSrc.GetHeight(); - - if (!imgDest.Create(width, height, imgSrc.GetBPP())) { - return false; - } - BOOL bCopied = imgSrc.BitBlt(imgDest.GetDC(), 0, 0); - imgDest.ReleaseDC(); - if (!bCopied) { - return false; - } - - RGBQUAD fgColor, bgColor; - fgColor.rgbRed = GetRValue(fg); - fgColor.rgbGreen = GetGValue(fg); - fgColor.rgbBlue = GetBValue(fg); - fgColor.rgbReserved = 0; - - bgColor.rgbRed = GetRValue(bg); - bgColor.rgbGreen = GetGValue(bg); - bgColor.rgbBlue = GetBValue(bg); - bgColor.rgbReserved = 0; - - - BYTE* bits = static_cast(imgDest.GetBits()); - for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < imgDest.GetWidth(); x++) { - HLS hls(p[x]); - - RGBQUAD rgb = hls.toRGBQUAD(); - - if (p[x].rgbReserved != 0) { //ignore the transparent bits - p[x].rgbRed = BYTE(fgColor.rgbRed * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbRed / 255); - p[x].rgbBlue = BYTE(fgColor.rgbBlue * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbBlue / 255); - p[x].rgbGreen = BYTE(fgColor.rgbGreen * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbGreen / 255); - } else { - p[x].rgbRed = bgColor.rgbRed; - p[x].rgbBlue = bgColor.rgbBlue; - p[x].rgbGreen = bgColor.rgbGreen; - } - p[x].rgbReserved = 255; - } - } - - if (rot90) { - Gdiplus::Bitmap* gdiPlusBitmap = Gdiplus::Bitmap::FromHBITMAP(imgDest.Detach(), 0); - gdiPlusBitmap->RotateFlip(Gdiplus::Rotate90FlipNone); - HBITMAP hbmp; - gdiPlusBitmap->GetHBITMAP(Gdiplus::Color::White, &hbmp); - imgDest.Attach(hbmp); - } - - return true; -} - -void ImageGrayer::PreMultiplyAlpha(CImage& imgSource) { - BYTE* bits = static_cast(imgSource.GetBits()); - for (int y = 0; y < imgSource.GetHeight(); y++, bits += imgSource.GetPitch()) { - RGBQUAD* p = reinterpret_cast(bits); - for (int x = 0; x < imgSource.GetWidth(); x++) { - HLS hls(p[x]); - - RGBQUAD rgb = hls.toRGBQUAD(); - - p[x].rgbRed = static_cast(round((float)p[x].rgbRed * p[x].rgbReserved / 255.0f)); - p[x].rgbBlue = static_cast(round((float)p[x].rgbBlue * p[x].rgbReserved / 255.0f)); - p[x].rgbGreen = static_cast(round((float)p[x].rgbGreen * p[x].rgbReserved / 255.0f)); - } - } -} +/* +* (C) 2016 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 . +* +*/ + +#include "stdafx.h" +#include "ImageGrayer.h" +#include "CMPCTheme.h" + +struct HLS { + double H, L, S; + + HLS(const RGBQUAD& rgb) { + double R = rgb.rgbRed / 255.0; + double G = rgb.rgbGreen / 255.0; + double B = rgb.rgbBlue / 255.0; + double max = std::max({ R, G, B }); + double min = std::min({ R, G, B }); + + L = (max + min) / 2.0; + + if (max == min) { + S = H = 0.0; + } else { + double d = max - min; + + S = (L < 0.5) ? (d / (max + min)) : (d / (2.0 - max - min)); + + if (R == max) { + H = (G - B) / d; + } else if (G == max) { + H = 2.0 + (B - R) / d; + } else { // if (B == max) + H = 4.0 + (R - G) / d; + } + H /= 6.0; + if (H < 0.0) { + H += 1.0; + } + } + } + + RGBQUAD toRGBQUAD() { + RGBQUAD rgb; + rgb.rgbReserved = 255; + + if (S == 0.0) { + rgb.rgbRed = rgb.rgbGreen = rgb.rgbBlue = BYTE(L * 255); + } else { + auto hue2rgb = [](double p, double q, double h) { + if (h < 0.0) { + h += 1.0; + } else if (h > 1.0) { + h -= 1.0; + } + + if (h < 1.0 / 6.0) { + return p + (q - p) * 6.0 * h; + } else if (h < 0.5) { + return q; + } else if (h < 2.0 / 3.0) { + return p + (q - p) * (2.0 / 3.0 - h) * 6.0; + } + return p; + }; + + double q = (L < 0.5) ? (L * (1 + S)) : (L + S - L * S); + double p = 2 * L - q; + + rgb.rgbRed = BYTE(hue2rgb(p, q, H + 1.0 / 3.0) * 255); + rgb.rgbGreen = BYTE(hue2rgb(p, q, H) * 255); + rgb.rgbBlue = BYTE(hue2rgb(p, q, H - 1.0 / 3.0) * 255); + } + + return rgb; + } +}; + +bool ImageGrayer::Gray(const CImage& imgSource, CImage& imgDest, float brightness) +{ + // Only support 32-bit image for now + if (imgSource.GetBPP() != 32) { + return false; + } + + imgDest.Destroy(); + if (!imgDest.Create(imgSource.GetWidth(), imgSource.GetHeight(), imgSource.GetBPP())) { + return false; + } + BOOL bCopied = imgSource.BitBlt(imgDest.GetDC(), 0, 0); + imgDest.ReleaseDC(); + if (!bCopied) { + return false; + } + + auto adjustBrightness = [](BYTE c, double p) { + int cAdjusted; + if (c == 0 && p > 1.0) { + cAdjusted = std::lround((p - 1.0) * 255); + } else { + cAdjusted = std::lround(c * p); + } + + return BYTE(std::min(cAdjusted, 255)); + }; + + BYTE* bits = static_cast(imgDest.GetBits()); + for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgDest.GetWidth(); x++) { + HLS hls(p[x]); + hls.S = 0.0; // Make the color gray + + RGBQUAD rgb = hls.toRGBQUAD(); + + p[x].rgbRed = BYTE(adjustBrightness(rgb.rgbRed, 1.5 * brightness) * p[x].rgbReserved / 255); + p[x].rgbGreen = BYTE(adjustBrightness(rgb.rgbGreen, 1.5 * brightness) * p[x].rgbReserved / 255); + p[x].rgbBlue = BYTE(adjustBrightness(rgb.rgbBlue, 1.5 * brightness) * p[x].rgbReserved / 255); + } + } + + return true; +} + +bool ImageGrayer::UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle) +{ + // Force to 32-bit + CImage img32; + CImage const* imgSrc; + if (imgSource.GetBPP() != 32) { + if (!img32.Create(imgSource.GetWidth(), imgSource.GetHeight(), 32, CImage::createAlphaChannel)) { + return false; + } + + HDC const iDC = img32.GetDC(); + BOOL const bbResult = imgSource.BitBlt(iDC, 0, 0, SRCCOPY); + img32.ReleaseDC(); + + if (!bbResult) { + return false; + } + + BYTE* bits = static_cast(img32.GetBits()); + for (int y = 0; y < img32.GetHeight(); y++, bits += img32.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < img32.GetWidth(); x++) { + HLS hls(p[x]); + p[x].rgbReserved = 255; + } + } + imgSrc = &img32; + } else { + imgSrc = &imgSource; + } + + if (colorStyle == ImageGrayer::classicGrayscale) { + return Gray(imgSource, imgDest); + } else if (colorStyle == ImageGrayer::mpcGrayDisabled) { + if (disabled) { + return Gray(imgSource, imgDest, 0.5f); + } else { + imgDest = imgSource; + } + } else { //mpcMono + imgDest.Destroy(); + + if (!imgDest.Create(imgSrc->GetWidth(), imgSrc->GetHeight(), imgSrc->GetBPP())) { + return false; + } + BOOL bCopied = imgSrc->BitBlt(imgDest.GetDC(), 0, 0); + imgDest.ReleaseDC(); + if (!bCopied) { + return false; + } + + RGBQUAD newColor; + COLORREF themeColor; + + if (disabled) { + themeColor = CMPCTheme::ImageDisabledColor; + } else { + themeColor = CMPCTheme::TextFGColorFade; + } + newColor.rgbRed = GetRValue(themeColor); + newColor.rgbGreen = GetGValue(themeColor); + newColor.rgbBlue = GetBValue(themeColor); + newColor.rgbReserved = 0; + + + + BYTE* bits = static_cast(imgDest.GetBits()); + for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgDest.GetWidth(); x++) { + HLS hls(p[x]); + + RGBQUAD rgb = hls.toRGBQUAD(); + + if (p[x].rgbReserved != 0) { //ignore the transparent bits + p[x].rgbRed = newColor.rgbRed; + p[x].rgbBlue = newColor.rgbBlue; + p[x].rgbGreen = newColor.rgbGreen; + } + } + } + } + + return true; +} + +bool ImageGrayer::Colorize(const CImage& imgSrc, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90) { + // Force to 32-bit + if (imgSrc.GetBPP() != 32) { + return false; + } + + imgDest.Destroy(); + + int width = imgSrc.GetWidth(); + int height = imgSrc.GetHeight(); + + if (!imgDest.Create(width, height, imgSrc.GetBPP())) { + return false; + } + BOOL bCopied = imgSrc.BitBlt(imgDest.GetDC(), 0, 0); + imgDest.ReleaseDC(); + if (!bCopied) { + return false; + } + + RGBQUAD fgColor, bgColor; + fgColor.rgbRed = GetRValue(fg); + fgColor.rgbGreen = GetGValue(fg); + fgColor.rgbBlue = GetBValue(fg); + fgColor.rgbReserved = 0; + + bgColor.rgbRed = GetRValue(bg); + bgColor.rgbGreen = GetGValue(bg); + bgColor.rgbBlue = GetBValue(bg); + bgColor.rgbReserved = 0; + + + BYTE* bits = static_cast(imgDest.GetBits()); + for (int y = 0; y < imgDest.GetHeight(); y++, bits += imgDest.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgDest.GetWidth(); x++) { + HLS hls(p[x]); + + RGBQUAD rgb = hls.toRGBQUAD(); + + if (p[x].rgbReserved != 0) { //ignore the transparent bits + p[x].rgbRed = BYTE(fgColor.rgbRed * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbRed / 255); + p[x].rgbBlue = BYTE(fgColor.rgbBlue * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbBlue / 255); + p[x].rgbGreen = BYTE(fgColor.rgbGreen * p[x].rgbReserved / 255 + (255 - p[x].rgbReserved) * bgColor.rgbGreen / 255); + } else { + p[x].rgbRed = bgColor.rgbRed; + p[x].rgbBlue = bgColor.rgbBlue; + p[x].rgbGreen = bgColor.rgbGreen; + } + p[x].rgbReserved = 255; + } + } + + if (rot90) { + Gdiplus::Bitmap* gdiPlusBitmap = Gdiplus::Bitmap::FromHBITMAP(imgDest.Detach(), 0); + gdiPlusBitmap->RotateFlip(Gdiplus::Rotate90FlipNone); + HBITMAP hbmp; + gdiPlusBitmap->GetHBITMAP(Gdiplus::Color::White, &hbmp); + imgDest.Attach(hbmp); + } + + return true; +} + +void ImageGrayer::PreMultiplyAlpha(CImage& imgSource) { + BYTE* bits = static_cast(imgSource.GetBits()); + for (int y = 0; y < imgSource.GetHeight(); y++, bits += imgSource.GetPitch()) { + RGBQUAD* p = reinterpret_cast(bits); + for (int x = 0; x < imgSource.GetWidth(); x++) { + HLS hls(p[x]); + + RGBQUAD rgb = hls.toRGBQUAD(); + + p[x].rgbRed = static_cast(round((float)p[x].rgbRed * p[x].rgbReserved / 255.0f)); + p[x].rgbBlue = static_cast(round((float)p[x].rgbBlue * p[x].rgbReserved / 255.0f)); + p[x].rgbGreen = static_cast(round((float)p[x].rgbGreen * p[x].rgbReserved / 255.0f)); + } + } +} diff --git a/src/mpc-hc/ImageGrayer.h b/src/mpc-hc/ImageGrayer.h index 44d643bcaf9..0ef54dbe4d3 100644 --- a/src/mpc-hc/ImageGrayer.h +++ b/src/mpc-hc/ImageGrayer.h @@ -1,35 +1,35 @@ -/* -* (C) 2016 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 . -* -*/ - -#pragma once - -namespace ImageGrayer -{ - enum mpcColorStyle { - classicGrayscale, - mpcMono, - mpcGrayDisabled, - }; - - bool Gray(const CImage& imgSource, CImage& imgDest, float brightness = 1.0f); - bool UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle); - bool Colorize(const CImage& imgSource, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90); - void PreMultiplyAlpha(CImage& imgSource); -} +/* +* (C) 2016 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 . +* +*/ + +#pragma once + +namespace ImageGrayer +{ + enum mpcColorStyle { + classicGrayscale, + mpcMono, + mpcGrayDisabled, + }; + + bool Gray(const CImage& imgSource, CImage& imgDest, float brightness = 1.0f); + bool UpdateColor(const CImage& imgSource, CImage& imgDest, bool disabled, mpcColorStyle colorStyle); + bool Colorize(const CImage& imgSource, CImage& imgDest, COLORREF fg, COLORREF bg, bool rot90); + void PreMultiplyAlpha(CImage& imgSource); +} diff --git a/src/mpc-hc/InternalFiltersConfig.h b/src/mpc-hc/InternalFiltersConfig.h index 1aae33a1906..0065fa8891b 100644 --- a/src/mpc-hc/InternalFiltersConfig.h +++ b/src/mpc-hc/InternalFiltersConfig.h @@ -1,124 +1,124 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -// For configuring which internal filters are included into the build. - -#pragma once - -#if defined(MPCHC_LITE) -#define INTERNAL_FILTERS_OTHER 0 -#else -#define INTERNAL_FILTERS_OTHER 1 -#endif -#define INTERNAL_FILTERS_LAV USE_LAVFILTERS - -// Internal source filters -#define INTERNAL_SOURCEFILTER_AC3 INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_ASF INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_AVI INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_AVS INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_DTS INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_FLAC INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_FLIC INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_FLV INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_GIF INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_HTTP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MATROSKA INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MISC INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MMS INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MP4 INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MPEG INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_MPEGAUDIO INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_OGG INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_REALMEDIA INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_RTMP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_RTP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_RTSP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_UDP INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_WTV INTERNAL_FILTERS_LAV -#define INTERNAL_SOURCEFILTER_CDDA INTERNAL_FILTERS_OTHER -#define INTERNAL_SOURCEFILTER_CDXA INTERNAL_FILTERS_OTHER -#define INTERNAL_SOURCEFILTER_DSM INTERNAL_FILTERS_OTHER -#define INTERNAL_SOURCEFILTER_RFS INTERNAL_FILTERS_OTHER -#define INTERNAL_SOURCEFILTER_VTS INTERNAL_FILTERS_OTHER - -// Internal audio decoders -#define INTERNAL_DECODER_LPCM INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_PS2AUDIO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_REALAUDIO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_PCM INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AC3 INTERNAL_FILTERS_LAV /* also E-AC3, TrueHD, MLP */ -#define INTERNAL_DECODER_DTS INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AAC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_ALAC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_ALS INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MPEGAUDIO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VORBIS INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_NELLYMOSER INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AMR INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_ADPCM INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_FLAC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_OPUS INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_WMA INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_WMAPRO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_WMALL INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_G726 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_G729 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_OTHERAUDIO INTERNAL_FILTERS_LAV - -// Internal video decoders -#define INTERNAL_DECODER_MPEG1 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MPEG2 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_REALVIDEO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_H264 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_HEVC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VVC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AV1 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VC1 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_FLV INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VP356 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_DIVX INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_XVID INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_WMV INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MSMPEG4 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_SVQ INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_H263 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_THEORA INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_AMVV INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VP8 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_VP9 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MJPEG INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_INDEO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_SCREEN INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_FLIC INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_MSVIDEO INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_V210_V410 INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_PRORES INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_DNXHD INTERNAL_FILTERS_LAV -#define INTERNAL_DECODER_OTHERVIDEO INTERNAL_FILTERS_LAV - - -// Groups -#define HAS_SOURCEFILTERS (INTERNAL_FILTERS_LAV || INTERNAL_FILTERS_OTHER) - -#define HAS_AUDIO_DECODERS INTERNAL_FILTERS_LAV - -#define HAS_VIDEO_DECODERS INTERNAL_FILTERS_LAV +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +// For configuring which internal filters are included into the build. + +#pragma once + +#if defined(MPCHC_LITE) +#define INTERNAL_FILTERS_OTHER 0 +#else +#define INTERNAL_FILTERS_OTHER 1 +#endif +#define INTERNAL_FILTERS_LAV USE_LAVFILTERS + +// Internal source filters +#define INTERNAL_SOURCEFILTER_AC3 INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_ASF INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_AVI INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_AVS INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_DTS INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_FLAC INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_FLIC INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_FLV INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_GIF INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_HTTP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MATROSKA INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MISC INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MMS INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MP4 INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MPEG INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_MPEGAUDIO INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_OGG INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_REALMEDIA INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_RTMP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_RTP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_RTSP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_UDP INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_WTV INTERNAL_FILTERS_LAV +#define INTERNAL_SOURCEFILTER_CDDA INTERNAL_FILTERS_OTHER +#define INTERNAL_SOURCEFILTER_CDXA INTERNAL_FILTERS_OTHER +#define INTERNAL_SOURCEFILTER_DSM INTERNAL_FILTERS_OTHER +#define INTERNAL_SOURCEFILTER_RFS INTERNAL_FILTERS_OTHER +#define INTERNAL_SOURCEFILTER_VTS INTERNAL_FILTERS_OTHER + +// Internal audio decoders +#define INTERNAL_DECODER_LPCM INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_PS2AUDIO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_REALAUDIO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_PCM INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AC3 INTERNAL_FILTERS_LAV /* also E-AC3, TrueHD, MLP */ +#define INTERNAL_DECODER_DTS INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AAC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_ALAC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_ALS INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MPEGAUDIO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VORBIS INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_NELLYMOSER INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AMR INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_ADPCM INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_FLAC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_OPUS INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_WMA INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_WMAPRO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_WMALL INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_G726 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_G729 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_OTHERAUDIO INTERNAL_FILTERS_LAV + +// Internal video decoders +#define INTERNAL_DECODER_MPEG1 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MPEG2 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_REALVIDEO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_H264 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_HEVC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VVC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AV1 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VC1 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_FLV INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VP356 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_DIVX INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_XVID INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_WMV INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MSMPEG4 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_SVQ INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_H263 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_THEORA INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_AMVV INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VP8 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_VP9 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MJPEG INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_INDEO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_SCREEN INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_FLIC INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_MSVIDEO INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_V210_V410 INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_PRORES INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_DNXHD INTERNAL_FILTERS_LAV +#define INTERNAL_DECODER_OTHERVIDEO INTERNAL_FILTERS_LAV + + +// Groups +#define HAS_SOURCEFILTERS (INTERNAL_FILTERS_LAV || INTERNAL_FILTERS_OTHER) + +#define HAS_AUDIO_DECODERS INTERNAL_FILTERS_LAV + +#define HAS_VIDEO_DECODERS INTERNAL_FILTERS_LAV diff --git a/src/mpc-hc/KeyProvider.cpp b/src/mpc-hc/KeyProvider.cpp index b40246cf675..3031fbe1bfc 100644 --- a/src/mpc-hc/KeyProvider.cpp +++ b/src/mpc-hc/KeyProvider.cpp @@ -1,57 +1,57 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "KeyProvider.h" -#include "DSUtil.h" - - -CKeyProvider::CKeyProvider() - : CUnknown(NAME("CKeyProvider"), nullptr) -{ -} - -CKeyProvider::~CKeyProvider() -{ -} - -STDMETHODIMP CKeyProvider::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - return - QI(IServiceProvider) - __super::NonDelegatingQueryInterface(riid, ppv); -} - -STDMETHODIMP CKeyProvider::QueryService(REFIID siid, REFIID riid, void** ppv) -{ - /* - if (siid == __uuidof(IWMReader) && riid == IID_IUnknown) - { - CComPtr punkCert; - HRESULT hr = WMCreateCertificate(&punkCert); - if (SUCCEEDED(hr)) - *ppv = (void*)punkCert.Detach(); - return hr; - } - */ - - return E_NOINTERFACE; -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "KeyProvider.h" +#include "DSUtil.h" + + +CKeyProvider::CKeyProvider() + : CUnknown(NAME("CKeyProvider"), nullptr) +{ +} + +CKeyProvider::~CKeyProvider() +{ +} + +STDMETHODIMP CKeyProvider::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + return + QI(IServiceProvider) + __super::NonDelegatingQueryInterface(riid, ppv); +} + +STDMETHODIMP CKeyProvider::QueryService(REFIID siid, REFIID riid, void** ppv) +{ + /* + if (siid == __uuidof(IWMReader) && riid == IID_IUnknown) + { + CComPtr punkCert; + HRESULT hr = WMCreateCertificate(&punkCert); + if (SUCCEEDED(hr)) + *ppv = (void*)punkCert.Detach(); + return hr; + } + */ + + return E_NOINTERFACE; +} diff --git a/src/mpc-hc/KeyProvider.h b/src/mpc-hc/KeyProvider.h index 7217b3f85e1..38fd82c43c5 100644 --- a/src/mpc-hc/KeyProvider.h +++ b/src/mpc-hc/KeyProvider.h @@ -1,42 +1,42 @@ -/* - * (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 . - * - */ - -#pragma once - -#include - - -// Declare and implement a key provider class derived from IServiceProvider. - -class CKeyProvider - : public CUnknown - , public IServiceProvider -{ -public: - CKeyProvider(); - ~CKeyProvider(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IServiceProvider - STDMETHODIMP QueryService(REFIID siid, REFIID riid, void** ppv); -}; +/* + * (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 . + * + */ + +#pragma once + +#include + + +// Declare and implement a key provider class derived from IServiceProvider. + +class CKeyProvider + : public CUnknown + , public IServiceProvider +{ +public: + CKeyProvider(); + ~CKeyProvider(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IServiceProvider + STDMETHODIMP QueryService(REFIID siid, REFIID riid, void** ppv); +}; diff --git a/src/mpc-hc/LcdSupport.cpp b/src/mpc-hc/LcdSupport.cpp index e74ffdb704c..445a90c92cb 100644 --- a/src/mpc-hc/LcdSupport.cpp +++ b/src/mpc-hc/LcdSupport.cpp @@ -1,761 +1,761 @@ -/* - * (C) 2006-2013, 2015 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include -#include // _beginthread, _endthread -#include -#include - -#include "LcdSupport.h" -#include "LCDUI/LCDUI.h" - -#include "mplayerc.h" - -#define LCD_APP_NAME "MPC-HC" -#define LCD_UPD_TIMER 40 - - -void LCD_UpdateThread(void* Control) -{ - CMPC_Lcd* ctrl = static_cast(Control); - wchar_t str[40]; - __time64_t ltime; - __time64_t otime = 0; - struct tm thetime; - _locale_t locale = _create_locale(LC_TIME, ""); - - while (ctrl->Thread_Loop) { - EnterCriticalSection(&ctrl->cs); - if (_time64(<ime) != otime) { // Retrieve the time - otime = ltime; - _localtime64_s(&thetime, <ime); - - // Format the current time structure into a string - // using %#x is the long date representation, - // appropriate to the current locale - if (_wcsftime_l(str, _countof(str), _T("%F"), (const struct tm*)&thetime, locale) && - (ltime > ctrl->nThread_tTimeout || ltime < otime)) { // message displayed, no update until timeout - ctrl->m_MonoPage.m_Text[0].SetText(str); - ctrl->m_ColorPage.m_Text[0].SetText(str); - } - - if (_wcsftime_l(str, _countof(str), _T("%X"), (const struct tm*)&thetime, locale)) { - ctrl->m_MonoPage.m_Text[1].SetText(str); - ctrl->m_ColorPage.m_Text[1].SetText(str); - } - } - ctrl->m_Connection.Update(); - LeaveCriticalSection(&ctrl->cs); - Sleep(LCD_UPD_TIMER); - } - - _free_locale(locale); - _endthread(); -} - -/****************************************************************************************************** - ****************************************** CLCDMyProgressBar ****************************************/ - -void CLCDMyProgressBar::OnDraw(CLCDGfxBase& rGfx) -{ - // draw the border - RECT r = { 0, 0, GetWidth(), GetHeight() }; - - FrameRect(rGfx.GetHDC(), &r, m_hBrush); - - // draw the progress - switch (m_eMyStyle) { - case STYLE_CURSOR: { - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)1, (float)(GetWidth() - m_nCursorWidth - 1), - m_fPos); - r.left = nCursorPos; - r.right = r.left + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - } - break; - case STYLE_FILLED_H: - case STYLE_FILLED_V: { - int nBar = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - 0.0f, (m_eMyStyle == STYLE_FILLED_H ? (float)GetWidth() : (float)GetHeight()) - 4, - m_fPos); - r.left = r.left + 2; - r.bottom = r.bottom - 2; - if (m_eMyStyle == STYLE_FILLED_H) { - r.right = nBar + 2; - r.top = r.top + 2; - } else { - r.right = r.right - 2; - r.top = r.bottom - nBar; - } - - FillRect(rGfx.GetHDC(), &r, m_hBrush); - } - break; - case STYLE_DASHED_CURSOR: { - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)1, (float)(GetWidth() - m_nCursorWidth - 1), - m_fPos); - r.left = nCursorPos; - r.right = r.left + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), m_hPen); - - ::MoveToEx(rGfx.GetHDC(), 0, (r.bottom - r.top) / 2, nullptr); - ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top) / 2); - ::SelectObject(rGfx.GetHDC(), hOldPen); - } - break; - default: - break; - } -} - -void CLCDMyProgressBar::SetProgressStyle(ePROGRESS_STYLE eStyle) -{ - m_eStyle = eStyle; - - //Convert and update the new Style type - switch (eStyle) { - case CLCDProgressBar::STYLE_CURSOR: - m_eMyStyle = STYLE_CURSOR; - break; - case CLCDProgressBar::STYLE_FILLED: - m_eMyStyle = STYLE_FILLED_H; - break; - case CLCDProgressBar::STYLE_DASHED_CURSOR: - m_eMyStyle = STYLE_DASHED_CURSOR; - break; - default: - break; - } -} - -void CLCDMyProgressBar::SetProgressStyle(eMY_PROGRESS_STYLE eMyStyle) -{ - m_eMyStyle = eMyStyle; - - //Convert and update the old Style type - switch (eMyStyle) { - case STYLE_CURSOR: - m_eStyle = CLCDProgressBar::STYLE_CURSOR; - break; - case STYLE_FILLED_V: - case STYLE_FILLED_H: - m_eStyle = CLCDProgressBar::STYLE_FILLED; - break; - case STYLE_DASHED_CURSOR: - m_eStyle = CLCDProgressBar::STYLE_DASHED_CURSOR; - break; - default: - break; - } -} - -/****************************************************************************************************** - ****************************************** CLCDMyMonoPage ****************************************/ -CLCDMyMonoPage::CLCDMyMonoPage() -{ - Initialize(); -} - -CLCDMyMonoPage::~CLCDMyMonoPage() -{ - DeleteObject(hBmp[PS_PLAY]); - DeleteObject(hBmp[PS_PAUSE]); - DeleteObject(hBmp[PS_STOP]); -} - -HRESULT CLCDMyMonoPage::Initialize() -{ - LOGFONT lf; - HFONT hFont; - unsigned int x, y; - - // max dimensions: 160 x 43 - x = 10; - y = 0; - - BYTE bPause[] = {0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF - }; - - BYTE bStop[] = {0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00 - }; - - BYTE bPlay[] = {0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F - }; - - hBmp[PS_PLAY] = CreateBitmap(56, 7, 1, 1, bPlay); - hBmp[PS_PAUSE] = CreateBitmap(14, 7, 1, 1, bPause); - hBmp[PS_STOP] = CreateBitmap(8, 7, 1, 1, bStop); - - // Initialize the text control (media) - m_Text1.Initialize(); - m_Text1.SetOrigin(x, y); - m_Text1.SetSize(160 - x, 13); - m_Text1.SetAlignment(DT_CENTER); - m_Text1.SetWordWrap(false); - m_Text1.SetText(_T("")); - m_Text1.SetStartDelay(5000); - m_Text1.SetEndDelay(2000); - m_Text1.EnableRepeat(true); - m_Text1.SetScrollDirection(SCROLL_HORZ); - m_Text1.SetSpeed(24); - - // Initialize the progressbar control (media progress) - y += 15; - m_ProgBar[1].Initialize(); - m_ProgBar[1].SetOrigin(x + 10, y); - m_ProgBar[1].SetSize(160 - x - 10, 7); - m_ProgBar[1].SetPos(0); - m_ProgBar[1].SetRange(0, 100); - m_ProgBar[1].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_H); - - // gfx - m_PlayState.Initialize(); - m_PlayState.SetOrigin(x, y); - m_PlayState.SetSize(7, 7); - m_PlayState.SetBitmap(hBmp[PS_PLAY]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(300); - m_PlayState.SetAlpha(false); - m_PlayState.SetZoomLevel(1); - - // Initialize the text control (time / mpc messages) - y += 6; - m_Text[0].Initialize(); - m_Text[0].SetOrigin(x, y); - m_Text[0].SetSize(160 - x, /*13*/25); - m_Text[0].SetAlignment(DT_CENTER); - m_Text[0].SetWordWrap(false); - m_Text[0].SetText(_T("")); - m_Text[0].SetFontPointSize(7); - hFont = m_Text[0].GetFont(); - GetObject(hFont, sizeof(LOGFONT), &lf); - wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); - m_Text[0].SetFont(lf); - - y += 10; - m_Text[1].Initialize(); - m_Text[1].SetOrigin(x, y); - m_Text[1].SetSize(160 - x, /*13*/25); - m_Text[1].SetAlignment(DT_CENTER); - m_Text[1].SetWordWrap(false); - m_Text[1].SetText(_T("")); - m_Text[1].SetFontPointSize(7); - hFont = m_Text[1].GetFont(); - GetObject(hFont, sizeof(LOGFONT), &lf); - wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); - m_Text[1].SetFont(lf); - - // Initialize the progressbar control (volume) - m_ProgBar[0].Initialize(); - m_ProgBar[0].SetOrigin(0, 0); - m_ProgBar[0].SetSize(7, 43); - m_ProgBar[0].SetPos(0); - m_ProgBar[0].SetRange(0, 100); - m_ProgBar[0].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_V); - - AddObject(&m_Text1); - AddObject(&m_Text[0]); - AddObject(&m_Text[1]); - AddObject(&m_ProgBar[0]); - AddObject(&m_ProgBar[1]); - AddObject(&m_PlayState); - - return CLCDPage::Initialize(); -} - -void CLCDMyMonoPage::OnLCDButtonUp(int nButton) -{ - switch (nButton) { - case LGLCDBUTTON_BUTTON0: { - /*LOGFONT lf; - HFONT hFont = m_Text1.GetFont(); - - GetObject(hFont, sizeof(LOGFONT), &lf); - - CFontDialog cfd(&lf); - if (cfd.DoModal() == IDOK) - { - cfd.GetCurrentFont(&lf); - m_Text1.SetFont(lf); - }*/ - break; - } - case LGLCDBUTTON_BUTTON1: - break; - case LGLCDBUTTON_BUTTON2: - break; - case LGLCDBUTTON_BUTTON3: - break; - default: - break; - } -} - -/* update play state bitmap */ -void CLCDMyMonoPage::SetPlayState(PlayState ps) -{ - switch (ps) { - case PS_PLAY: - m_PlayState.SetBitmap(hBmp[PS_PLAY]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(300); - break; - - case PS_PAUSE: - m_PlayState.SetBitmap(hBmp[PS_PAUSE]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(800); - break; - - case PS_STOP: - m_ProgBar[1].SetPos(0); - m_PlayState.SetBitmap(hBmp[PS_STOP]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(5000); // dummy, only one picture - break; - - default: - break; - } -} - -/****************************************************************************************************** - ****************************************** CLCDMyColorPage ****************************************/ -CLCDMyColorPage::CLCDMyColorPage() -{ - Initialize(); -} - -CLCDMyColorPage::~CLCDMyColorPage() -{ - DeleteObject(hBmp[PS_PLAY]); - DeleteObject(hBmp[PS_PAUSE]); - DeleteObject(hBmp[PS_STOP]); -} - -HRESULT CLCDMyColorPage::Initialize() -{ - LOGFONT lf; - HFONT hFont; - unsigned int x, y; - - // max dimensions: 320 x 240 - x = 20; - y = 0; - - BYTE bPause[] = {0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF, - 0x93, 0xFF - }; - - BYTE bStop[] = {0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00 - }; - - BYTE bPlay[] = {0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F - }; - - hBmp[PS_PLAY] = CreateBitmap(56, 7, 1, 1, bPlay); - hBmp[PS_PAUSE] = CreateBitmap(14, 7, 1, 1, bPause); - hBmp[PS_STOP] = CreateBitmap(8, 7, 1, 1, bStop); - - - // Initialize the text control (media) - m_Text1.Initialize(); - m_Text1.SetOrigin(x, y); - m_Text1.SetSize(320 - x, 26); - m_Text1.SetAlignment(DT_CENTER | DT_VCENTER); - m_Text1.SetWordWrap(false); - m_Text1.SetText(_T("")); - m_Text1.SetFontPointSize(16); - m_Text1.SetStartDelay(5000); - m_Text1.SetEndDelay(2000); - m_Text1.EnableRepeat(true); - m_Text1.SetScrollDirection(SCROLL_HORZ); - m_Text1.SetSpeed(24); - - // Initialize the progressbar control (media progress) - y += 30; - m_ProgBar[1].Initialize(); - m_ProgBar[1].SetOrigin(x + 20, y); - m_ProgBar[1].SetSize(320 - x - 20, 14); - m_ProgBar[1].SetPos(0); - m_ProgBar[1].SetRange(0, 100); - m_ProgBar[1].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_H); - - // gfx - m_PlayState.Initialize(); - m_PlayState.SetOrigin(x, y); - m_PlayState.SetSize(14, 14); - m_PlayState.SetBitmap(hBmp[PS_PLAY]); - m_PlayState.ResetUpdate(); - m_PlayState.SetZoomLevel(2); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(300); - m_PlayState.SetAlpha(false); - m_PlayState.GetSize(); - - // Initialize the text control (time / mpc messages) - y += 14; - m_Text[0].Initialize(); - m_Text[0].SetOrigin(x, y); - m_Text[0].SetSize(320 - x, /*13*/50); - m_Text[0].SetAlignment(DT_CENTER); - m_Text[0].SetWordWrap(false); - m_Text[0].SetText(_T("")); - m_Text[0].SetFontPointSize(14); - hFont = m_Text[0].GetFont(); - GetObject(hFont, sizeof(LOGFONT), &lf); - wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); - m_Text[0].SetFont(lf); - - y += 22; - m_Text[1].Initialize(); - m_Text[1].SetOrigin(x, y); - m_Text[1].SetSize(320 - x, /*13*/50); - m_Text[1].SetAlignment(DT_CENTER); - m_Text[1].SetWordWrap(false); - m_Text[1].SetText(_T("")); - m_Text[1].SetFontPointSize(14); - hFont = m_Text[1].GetFont(); - GetObject(hFont, sizeof(LOGFONT), &lf); - wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); - m_Text[1].SetFont(lf); - - // Initialize the progressbar control (volume) - m_ProgBar[0].Initialize(); - m_ProgBar[0].SetOrigin(0, 0); - m_ProgBar[0].SetSize(14, 86); - m_ProgBar[0].SetPos(0); - m_ProgBar[0].SetRange(0, 100); - m_ProgBar[0].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_V); - - AddObject(&m_Text1); - AddObject(&m_Text[0]); - AddObject(&m_Text[1]); - AddObject(&m_ProgBar[0]); - AddObject(&m_ProgBar[1]); - AddObject(&m_PlayState); - - return CLCDPage::Initialize(); -} - -void CLCDMyColorPage::OnLCDButtonUp(int nButton) -{ - switch (nButton) { - case LGLCDBUTTON_BUTTON0: { - /*LOGFONT lf; - HFONT hFont = m_Text1.GetFont(); - - GetObject(hFont, sizeof(LOGFONT), &lf); - - CFontDialog cfd(&lf); - if (cfd.DoModal() == IDOK) - { - cfd.GetCurrentFont(&lf); - m_Text1.SetFont(lf); - }*/ - break; - } - case LGLCDBUTTON_BUTTON1: - break; - case LGLCDBUTTON_BUTTON2: - break; - case LGLCDBUTTON_BUTTON3: - break; - default: - break; - } -} - -/* update play state bitmap */ -void CLCDMyColorPage::SetPlayState(PlayState ps) -{ - switch (ps) { - case PS_PLAY: - m_PlayState.SetBitmap(hBmp[PS_PLAY]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(300); - break; - - case PS_PAUSE: - m_PlayState.SetBitmap(hBmp[PS_PAUSE]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(800); - break; - - case PS_STOP: - m_ProgBar[1].SetPos(0); - m_PlayState.SetBitmap(hBmp[PS_STOP]); - m_PlayState.ResetUpdate(); - m_PlayState.SetSubpicWidth(7); - m_PlayState.SetAnimationRate(5000); // dummy, only one picture - break; - - default: - break; - } -} - -/****************************************************************************************************** - ********************************************** CMPC_Lcd *********************************************/ - -/* attach to an available lcd */ -CMPC_Lcd::CMPC_Lcd() - : hLCD_UpdateThread(nullptr) - , m_nMediaStart(0) - , m_nMediaStop(0) - , m_nVolumeStart(0) - , m_nVolumeStop(100) - , m_MonoOutput(nullptr) - , m_ColorOutput(nullptr) - , Thread_Loop(false) - , nThread_tTimeout(0) -{ - InitializeCriticalSection(&cs); - - // lcd init - ZeroMemory(&m_ConnCtx, sizeof(m_ConnCtx)); - - m_ConnCtx.appFriendlyName = _T(LCD_APP_NAME); - m_ConnCtx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BW | LGLCD_APPLET_CAP_QVGA; - m_ConnCtx.isAutostartable = FALSE; - m_ConnCtx.isPersistent = FALSE; - m_ConnCtx.onConfigure.configCallback = nullptr; // we don't have a configuration screen - m_ConnCtx.onConfigure.configContext = nullptr; - m_ConnCtx.onNotify.notificationCallback = nullptr; - m_ConnCtx.onNotify.notifyContext = nullptr; - m_ConnCtx.connection = LGLCD_INVALID_CONNECTION; // the "connection" member will be returned upon return - - const CAppSettings& s = AfxGetAppSettings(); - if (!s.fLCDSupport) { - return; - } - - if (FALSE == m_Connection.Initialize(m_ConnCtx)) { - //_tperror(_T("Initialize")); - return; - } - - m_MonoOutput = m_Connection.MonoOutput(); - m_MonoOutput->ShowPage(&m_MonoPage); - - m_ColorOutput = m_Connection.ColorOutput(); - m_ColorOutput->ShowPage(&m_ColorPage); - - SetAsForeground(TRUE); - - m_Connection.Update(); - - if (m_Connection.IsConnected()) { - Thread_Loop = true; - SetPlayState(PS_STOP); - hLCD_UpdateThread = (HANDLE) _beginthread(LCD_UpdateThread, 512 /* stack */, (void*) this /* arg */); - } -} - -/* detach from lcd */ -CMPC_Lcd::~CMPC_Lcd() -{ - if (m_Connection.IsConnected()) { - Thread_Loop = false; - WaitForSingleObject(hLCD_UpdateThread, LCD_UPD_TIMER * 2 /* timeout */); - hLCD_UpdateThread = nullptr; - } - - DeleteCriticalSection(&cs); - - m_Connection.Shutdown(); -} - -/* update title name */ -void CMPC_Lcd::SetMediaTitle(const TCHAR* text) -{ - EnterCriticalSection(&cs); - m_MonoPage.m_Text1.SetText(text); - m_MonoPage.m_ProgBar[1].SetPos(0); - m_ColorPage.m_Text1.SetText(text); - m_ColorPage.m_ProgBar[1].SetPos(0); - LeaveCriticalSection(&cs); -} - -/* set volume min/max */ -void CMPC_Lcd::SetVolumeRange(__int64 nStart, __int64 nStop) -{ - //handle 64bit integers LCDUI only supports int for Range - //Since it also supports floats for position, - //This will always work in percentage - m_nVolumeStart = nStart; - m_nVolumeStop = nStop; -} - -/* update volume */ -void CMPC_Lcd::SetVolume(__int64 nVol) -{ - //handle 64bit integers LCDUI only supports int for Range - //Since it also supports floats for position, - //This will always work in percentage - float fVol; - if (m_nVolumeStart != m_nVolumeStop) { - fVol = float(nVol - m_nVolumeStart) * 100.0f / float(m_nVolumeStop - m_nVolumeStart); - } else { - fVol = 0.0f; - ASSERT(FALSE); // This isn't supposed to happen - } - - EnterCriticalSection(&cs); - m_MonoPage.m_ProgBar[0].SetPos(fVol); - m_ColorPage.m_ProgBar[0].SetPos(fVol); - LeaveCriticalSection(&cs); -} - -/* set media min/max */ -void CMPC_Lcd::SetMediaRange(__int64 nStart, __int64 nStop) -{ - //handle 64bit integers LCDUI only supports int for Range - //Since it also supports floats for position, - //This will always work in percentage - m_nMediaStart = nStart; - m_nMediaStop = nStop; -} - -/* update media position */ -void CMPC_Lcd::SetMediaPos(__int64 nPos) -{ - //handle 64bit integers LCDUI only supports int for Range - //Since it also supports floats for position, - //This will always work in percentage - float fPos; - if (m_nMediaStart != m_nMediaStop) { - fPos = float(nPos - m_nMediaStart) * 100.0f / float(m_nMediaStop - m_nMediaStart); - } else { // The duration might be unknown - fPos = 0.0f; - } - - EnterCriticalSection(&cs); - m_MonoPage.m_ProgBar[1].SetPos(fPos); - m_ColorPage.m_ProgBar[1].SetPos(fPos); - LeaveCriticalSection(&cs); -} - -/* update status message (displayed for nTimeOut milliseconds) */ -void CMPC_Lcd::SetStatusMessage(const TCHAR* text, int nTimeOut) -{ - if (!m_Connection.IsConnected()) { - return; - } - - __time64_t ltime; - _time64(<ime); - if ((nTimeOut /= 1000) < 1) { - nTimeOut = 1; - } - - EnterCriticalSection(&cs); - nThread_tTimeout = ltime + nTimeOut; - m_MonoPage.m_Text[0].SetText(text); - m_ColorPage.m_Text[0].SetText(text); - LeaveCriticalSection(&cs); -} - -/* update play state bitmap */ -void CMPC_Lcd::SetPlayState(CMPC_Lcd::PlayState ps) -{ - if (!m_Connection.IsConnected()) { - return; - } - - EnterCriticalSection(&cs); - switch (ps) { - case PS_PLAY: - SetAsForeground(true); - break; - case PS_PAUSE: - break; - case PS_STOP: - SetAsForeground(false); - break; - default: - break; - } - - m_MonoPage.SetPlayState((CLCDMyMonoPage::PlayState)ps); - m_ColorPage.SetPlayState((CLCDMyColorPage::PlayState)ps); - - LeaveCriticalSection(&cs); -} - -HRESULT CMPC_Lcd::SetAsForeground(BOOL setAsForeground) -{ - if (nullptr != m_Connection.MonoOutput()) { - m_Connection.MonoOutput()->SetAsForeground(setAsForeground); - } - - if (nullptr != m_Connection.ColorOutput()) { - m_Connection.ColorOutput()->SetAsForeground(setAsForeground); - } - - return S_OK; -} +/* + * (C) 2006-2013, 2015 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include +#include // _beginthread, _endthread +#include +#include + +#include "LcdSupport.h" +#include "LCDUI/LCDUI.h" + +#include "mplayerc.h" + +#define LCD_APP_NAME "MPC-HC" +#define LCD_UPD_TIMER 40 + + +void LCD_UpdateThread(void* Control) +{ + CMPC_Lcd* ctrl = static_cast(Control); + wchar_t str[40]; + __time64_t ltime; + __time64_t otime = 0; + struct tm thetime; + _locale_t locale = _create_locale(LC_TIME, ""); + + while (ctrl->Thread_Loop) { + EnterCriticalSection(&ctrl->cs); + if (_time64(<ime) != otime) { // Retrieve the time + otime = ltime; + _localtime64_s(&thetime, <ime); + + // Format the current time structure into a string + // using %#x is the long date representation, + // appropriate to the current locale + if (_wcsftime_l(str, _countof(str), _T("%F"), (const struct tm*)&thetime, locale) && + (ltime > ctrl->nThread_tTimeout || ltime < otime)) { // message displayed, no update until timeout + ctrl->m_MonoPage.m_Text[0].SetText(str); + ctrl->m_ColorPage.m_Text[0].SetText(str); + } + + if (_wcsftime_l(str, _countof(str), _T("%X"), (const struct tm*)&thetime, locale)) { + ctrl->m_MonoPage.m_Text[1].SetText(str); + ctrl->m_ColorPage.m_Text[1].SetText(str); + } + } + ctrl->m_Connection.Update(); + LeaveCriticalSection(&ctrl->cs); + Sleep(LCD_UPD_TIMER); + } + + _free_locale(locale); + _endthread(); +} + +/****************************************************************************************************** + ****************************************** CLCDMyProgressBar ****************************************/ + +void CLCDMyProgressBar::OnDraw(CLCDGfxBase& rGfx) +{ + // draw the border + RECT r = { 0, 0, GetWidth(), GetHeight() }; + + FrameRect(rGfx.GetHDC(), &r, m_hBrush); + + // draw the progress + switch (m_eMyStyle) { + case STYLE_CURSOR: { + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)1, (float)(GetWidth() - m_nCursorWidth - 1), + m_fPos); + r.left = nCursorPos; + r.right = r.left + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + } + break; + case STYLE_FILLED_H: + case STYLE_FILLED_V: { + int nBar = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + 0.0f, (m_eMyStyle == STYLE_FILLED_H ? (float)GetWidth() : (float)GetHeight()) - 4, + m_fPos); + r.left = r.left + 2; + r.bottom = r.bottom - 2; + if (m_eMyStyle == STYLE_FILLED_H) { + r.right = nBar + 2; + r.top = r.top + 2; + } else { + r.right = r.right - 2; + r.top = r.bottom - nBar; + } + + FillRect(rGfx.GetHDC(), &r, m_hBrush); + } + break; + case STYLE_DASHED_CURSOR: { + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)1, (float)(GetWidth() - m_nCursorWidth - 1), + m_fPos); + r.left = nCursorPos; + r.right = r.left + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), m_hPen); + + ::MoveToEx(rGfx.GetHDC(), 0, (r.bottom - r.top) / 2, nullptr); + ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top) / 2); + ::SelectObject(rGfx.GetHDC(), hOldPen); + } + break; + default: + break; + } +} + +void CLCDMyProgressBar::SetProgressStyle(ePROGRESS_STYLE eStyle) +{ + m_eStyle = eStyle; + + //Convert and update the new Style type + switch (eStyle) { + case CLCDProgressBar::STYLE_CURSOR: + m_eMyStyle = STYLE_CURSOR; + break; + case CLCDProgressBar::STYLE_FILLED: + m_eMyStyle = STYLE_FILLED_H; + break; + case CLCDProgressBar::STYLE_DASHED_CURSOR: + m_eMyStyle = STYLE_DASHED_CURSOR; + break; + default: + break; + } +} + +void CLCDMyProgressBar::SetProgressStyle(eMY_PROGRESS_STYLE eMyStyle) +{ + m_eMyStyle = eMyStyle; + + //Convert and update the old Style type + switch (eMyStyle) { + case STYLE_CURSOR: + m_eStyle = CLCDProgressBar::STYLE_CURSOR; + break; + case STYLE_FILLED_V: + case STYLE_FILLED_H: + m_eStyle = CLCDProgressBar::STYLE_FILLED; + break; + case STYLE_DASHED_CURSOR: + m_eStyle = CLCDProgressBar::STYLE_DASHED_CURSOR; + break; + default: + break; + } +} + +/****************************************************************************************************** + ****************************************** CLCDMyMonoPage ****************************************/ +CLCDMyMonoPage::CLCDMyMonoPage() +{ + Initialize(); +} + +CLCDMyMonoPage::~CLCDMyMonoPage() +{ + DeleteObject(hBmp[PS_PLAY]); + DeleteObject(hBmp[PS_PAUSE]); + DeleteObject(hBmp[PS_STOP]); +} + +HRESULT CLCDMyMonoPage::Initialize() +{ + LOGFONT lf; + HFONT hFont; + unsigned int x, y; + + // max dimensions: 160 x 43 + x = 10; + y = 0; + + BYTE bPause[] = {0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF + }; + + BYTE bStop[] = {0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 + }; + + BYTE bPlay[] = {0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F + }; + + hBmp[PS_PLAY] = CreateBitmap(56, 7, 1, 1, bPlay); + hBmp[PS_PAUSE] = CreateBitmap(14, 7, 1, 1, bPause); + hBmp[PS_STOP] = CreateBitmap(8, 7, 1, 1, bStop); + + // Initialize the text control (media) + m_Text1.Initialize(); + m_Text1.SetOrigin(x, y); + m_Text1.SetSize(160 - x, 13); + m_Text1.SetAlignment(DT_CENTER); + m_Text1.SetWordWrap(false); + m_Text1.SetText(_T("")); + m_Text1.SetStartDelay(5000); + m_Text1.SetEndDelay(2000); + m_Text1.EnableRepeat(true); + m_Text1.SetScrollDirection(SCROLL_HORZ); + m_Text1.SetSpeed(24); + + // Initialize the progressbar control (media progress) + y += 15; + m_ProgBar[1].Initialize(); + m_ProgBar[1].SetOrigin(x + 10, y); + m_ProgBar[1].SetSize(160 - x - 10, 7); + m_ProgBar[1].SetPos(0); + m_ProgBar[1].SetRange(0, 100); + m_ProgBar[1].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_H); + + // gfx + m_PlayState.Initialize(); + m_PlayState.SetOrigin(x, y); + m_PlayState.SetSize(7, 7); + m_PlayState.SetBitmap(hBmp[PS_PLAY]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(300); + m_PlayState.SetAlpha(false); + m_PlayState.SetZoomLevel(1); + + // Initialize the text control (time / mpc messages) + y += 6; + m_Text[0].Initialize(); + m_Text[0].SetOrigin(x, y); + m_Text[0].SetSize(160 - x, /*13*/25); + m_Text[0].SetAlignment(DT_CENTER); + m_Text[0].SetWordWrap(false); + m_Text[0].SetText(_T("")); + m_Text[0].SetFontPointSize(7); + hFont = m_Text[0].GetFont(); + GetObject(hFont, sizeof(LOGFONT), &lf); + wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); + m_Text[0].SetFont(lf); + + y += 10; + m_Text[1].Initialize(); + m_Text[1].SetOrigin(x, y); + m_Text[1].SetSize(160 - x, /*13*/25); + m_Text[1].SetAlignment(DT_CENTER); + m_Text[1].SetWordWrap(false); + m_Text[1].SetText(_T("")); + m_Text[1].SetFontPointSize(7); + hFont = m_Text[1].GetFont(); + GetObject(hFont, sizeof(LOGFONT), &lf); + wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); + m_Text[1].SetFont(lf); + + // Initialize the progressbar control (volume) + m_ProgBar[0].Initialize(); + m_ProgBar[0].SetOrigin(0, 0); + m_ProgBar[0].SetSize(7, 43); + m_ProgBar[0].SetPos(0); + m_ProgBar[0].SetRange(0, 100); + m_ProgBar[0].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_V); + + AddObject(&m_Text1); + AddObject(&m_Text[0]); + AddObject(&m_Text[1]); + AddObject(&m_ProgBar[0]); + AddObject(&m_ProgBar[1]); + AddObject(&m_PlayState); + + return CLCDPage::Initialize(); +} + +void CLCDMyMonoPage::OnLCDButtonUp(int nButton) +{ + switch (nButton) { + case LGLCDBUTTON_BUTTON0: { + /*LOGFONT lf; + HFONT hFont = m_Text1.GetFont(); + + GetObject(hFont, sizeof(LOGFONT), &lf); + + CFontDialog cfd(&lf); + if (cfd.DoModal() == IDOK) + { + cfd.GetCurrentFont(&lf); + m_Text1.SetFont(lf); + }*/ + break; + } + case LGLCDBUTTON_BUTTON1: + break; + case LGLCDBUTTON_BUTTON2: + break; + case LGLCDBUTTON_BUTTON3: + break; + default: + break; + } +} + +/* update play state bitmap */ +void CLCDMyMonoPage::SetPlayState(PlayState ps) +{ + switch (ps) { + case PS_PLAY: + m_PlayState.SetBitmap(hBmp[PS_PLAY]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(300); + break; + + case PS_PAUSE: + m_PlayState.SetBitmap(hBmp[PS_PAUSE]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(800); + break; + + case PS_STOP: + m_ProgBar[1].SetPos(0); + m_PlayState.SetBitmap(hBmp[PS_STOP]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(5000); // dummy, only one picture + break; + + default: + break; + } +} + +/****************************************************************************************************** + ****************************************** CLCDMyColorPage ****************************************/ +CLCDMyColorPage::CLCDMyColorPage() +{ + Initialize(); +} + +CLCDMyColorPage::~CLCDMyColorPage() +{ + DeleteObject(hBmp[PS_PLAY]); + DeleteObject(hBmp[PS_PAUSE]); + DeleteObject(hBmp[PS_STOP]); +} + +HRESULT CLCDMyColorPage::Initialize() +{ + LOGFONT lf; + HFONT hFont; + unsigned int x, y; + + // max dimensions: 320 x 240 + x = 20; + y = 0; + + BYTE bPause[] = {0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF, + 0x93, 0xFF + }; + + BYTE bStop[] = {0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 + }; + + BYTE bPlay[] = {0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F + }; + + hBmp[PS_PLAY] = CreateBitmap(56, 7, 1, 1, bPlay); + hBmp[PS_PAUSE] = CreateBitmap(14, 7, 1, 1, bPause); + hBmp[PS_STOP] = CreateBitmap(8, 7, 1, 1, bStop); + + + // Initialize the text control (media) + m_Text1.Initialize(); + m_Text1.SetOrigin(x, y); + m_Text1.SetSize(320 - x, 26); + m_Text1.SetAlignment(DT_CENTER | DT_VCENTER); + m_Text1.SetWordWrap(false); + m_Text1.SetText(_T("")); + m_Text1.SetFontPointSize(16); + m_Text1.SetStartDelay(5000); + m_Text1.SetEndDelay(2000); + m_Text1.EnableRepeat(true); + m_Text1.SetScrollDirection(SCROLL_HORZ); + m_Text1.SetSpeed(24); + + // Initialize the progressbar control (media progress) + y += 30; + m_ProgBar[1].Initialize(); + m_ProgBar[1].SetOrigin(x + 20, y); + m_ProgBar[1].SetSize(320 - x - 20, 14); + m_ProgBar[1].SetPos(0); + m_ProgBar[1].SetRange(0, 100); + m_ProgBar[1].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_H); + + // gfx + m_PlayState.Initialize(); + m_PlayState.SetOrigin(x, y); + m_PlayState.SetSize(14, 14); + m_PlayState.SetBitmap(hBmp[PS_PLAY]); + m_PlayState.ResetUpdate(); + m_PlayState.SetZoomLevel(2); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(300); + m_PlayState.SetAlpha(false); + m_PlayState.GetSize(); + + // Initialize the text control (time / mpc messages) + y += 14; + m_Text[0].Initialize(); + m_Text[0].SetOrigin(x, y); + m_Text[0].SetSize(320 - x, /*13*/50); + m_Text[0].SetAlignment(DT_CENTER); + m_Text[0].SetWordWrap(false); + m_Text[0].SetText(_T("")); + m_Text[0].SetFontPointSize(14); + hFont = m_Text[0].GetFont(); + GetObject(hFont, sizeof(LOGFONT), &lf); + wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); + m_Text[0].SetFont(lf); + + y += 22; + m_Text[1].Initialize(); + m_Text[1].SetOrigin(x, y); + m_Text[1].SetSize(320 - x, /*13*/50); + m_Text[1].SetAlignment(DT_CENTER); + m_Text[1].SetWordWrap(false); + m_Text[1].SetText(_T("")); + m_Text[1].SetFontPointSize(14); + hFont = m_Text[1].GetFont(); + GetObject(hFont, sizeof(LOGFONT), &lf); + wcscpy_s(lf.lfFaceName, LF_FACESIZE, _T("Microsoft Sans Serif")); + m_Text[1].SetFont(lf); + + // Initialize the progressbar control (volume) + m_ProgBar[0].Initialize(); + m_ProgBar[0].SetOrigin(0, 0); + m_ProgBar[0].SetSize(14, 86); + m_ProgBar[0].SetPos(0); + m_ProgBar[0].SetRange(0, 100); + m_ProgBar[0].SetProgressStyle(CLCDMyProgressBar::STYLE_FILLED_V); + + AddObject(&m_Text1); + AddObject(&m_Text[0]); + AddObject(&m_Text[1]); + AddObject(&m_ProgBar[0]); + AddObject(&m_ProgBar[1]); + AddObject(&m_PlayState); + + return CLCDPage::Initialize(); +} + +void CLCDMyColorPage::OnLCDButtonUp(int nButton) +{ + switch (nButton) { + case LGLCDBUTTON_BUTTON0: { + /*LOGFONT lf; + HFONT hFont = m_Text1.GetFont(); + + GetObject(hFont, sizeof(LOGFONT), &lf); + + CFontDialog cfd(&lf); + if (cfd.DoModal() == IDOK) + { + cfd.GetCurrentFont(&lf); + m_Text1.SetFont(lf); + }*/ + break; + } + case LGLCDBUTTON_BUTTON1: + break; + case LGLCDBUTTON_BUTTON2: + break; + case LGLCDBUTTON_BUTTON3: + break; + default: + break; + } +} + +/* update play state bitmap */ +void CLCDMyColorPage::SetPlayState(PlayState ps) +{ + switch (ps) { + case PS_PLAY: + m_PlayState.SetBitmap(hBmp[PS_PLAY]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(300); + break; + + case PS_PAUSE: + m_PlayState.SetBitmap(hBmp[PS_PAUSE]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(800); + break; + + case PS_STOP: + m_ProgBar[1].SetPos(0); + m_PlayState.SetBitmap(hBmp[PS_STOP]); + m_PlayState.ResetUpdate(); + m_PlayState.SetSubpicWidth(7); + m_PlayState.SetAnimationRate(5000); // dummy, only one picture + break; + + default: + break; + } +} + +/****************************************************************************************************** + ********************************************** CMPC_Lcd *********************************************/ + +/* attach to an available lcd */ +CMPC_Lcd::CMPC_Lcd() + : hLCD_UpdateThread(nullptr) + , m_nMediaStart(0) + , m_nMediaStop(0) + , m_nVolumeStart(0) + , m_nVolumeStop(100) + , m_MonoOutput(nullptr) + , m_ColorOutput(nullptr) + , Thread_Loop(false) + , nThread_tTimeout(0) +{ + InitializeCriticalSection(&cs); + + // lcd init + ZeroMemory(&m_ConnCtx, sizeof(m_ConnCtx)); + + m_ConnCtx.appFriendlyName = _T(LCD_APP_NAME); + m_ConnCtx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BW | LGLCD_APPLET_CAP_QVGA; + m_ConnCtx.isAutostartable = FALSE; + m_ConnCtx.isPersistent = FALSE; + m_ConnCtx.onConfigure.configCallback = nullptr; // we don't have a configuration screen + m_ConnCtx.onConfigure.configContext = nullptr; + m_ConnCtx.onNotify.notificationCallback = nullptr; + m_ConnCtx.onNotify.notifyContext = nullptr; + m_ConnCtx.connection = LGLCD_INVALID_CONNECTION; // the "connection" member will be returned upon return + + const CAppSettings& s = AfxGetAppSettings(); + if (!s.fLCDSupport) { + return; + } + + if (FALSE == m_Connection.Initialize(m_ConnCtx)) { + //_tperror(_T("Initialize")); + return; + } + + m_MonoOutput = m_Connection.MonoOutput(); + m_MonoOutput->ShowPage(&m_MonoPage); + + m_ColorOutput = m_Connection.ColorOutput(); + m_ColorOutput->ShowPage(&m_ColorPage); + + SetAsForeground(TRUE); + + m_Connection.Update(); + + if (m_Connection.IsConnected()) { + Thread_Loop = true; + SetPlayState(PS_STOP); + hLCD_UpdateThread = (HANDLE) _beginthread(LCD_UpdateThread, 512 /* stack */, (void*) this /* arg */); + } +} + +/* detach from lcd */ +CMPC_Lcd::~CMPC_Lcd() +{ + if (m_Connection.IsConnected()) { + Thread_Loop = false; + WaitForSingleObject(hLCD_UpdateThread, LCD_UPD_TIMER * 2 /* timeout */); + hLCD_UpdateThread = nullptr; + } + + DeleteCriticalSection(&cs); + + m_Connection.Shutdown(); +} + +/* update title name */ +void CMPC_Lcd::SetMediaTitle(const TCHAR* text) +{ + EnterCriticalSection(&cs); + m_MonoPage.m_Text1.SetText(text); + m_MonoPage.m_ProgBar[1].SetPos(0); + m_ColorPage.m_Text1.SetText(text); + m_ColorPage.m_ProgBar[1].SetPos(0); + LeaveCriticalSection(&cs); +} + +/* set volume min/max */ +void CMPC_Lcd::SetVolumeRange(__int64 nStart, __int64 nStop) +{ + //handle 64bit integers LCDUI only supports int for Range + //Since it also supports floats for position, + //This will always work in percentage + m_nVolumeStart = nStart; + m_nVolumeStop = nStop; +} + +/* update volume */ +void CMPC_Lcd::SetVolume(__int64 nVol) +{ + //handle 64bit integers LCDUI only supports int for Range + //Since it also supports floats for position, + //This will always work in percentage + float fVol; + if (m_nVolumeStart != m_nVolumeStop) { + fVol = float(nVol - m_nVolumeStart) * 100.0f / float(m_nVolumeStop - m_nVolumeStart); + } else { + fVol = 0.0f; + ASSERT(FALSE); // This isn't supposed to happen + } + + EnterCriticalSection(&cs); + m_MonoPage.m_ProgBar[0].SetPos(fVol); + m_ColorPage.m_ProgBar[0].SetPos(fVol); + LeaveCriticalSection(&cs); +} + +/* set media min/max */ +void CMPC_Lcd::SetMediaRange(__int64 nStart, __int64 nStop) +{ + //handle 64bit integers LCDUI only supports int for Range + //Since it also supports floats for position, + //This will always work in percentage + m_nMediaStart = nStart; + m_nMediaStop = nStop; +} + +/* update media position */ +void CMPC_Lcd::SetMediaPos(__int64 nPos) +{ + //handle 64bit integers LCDUI only supports int for Range + //Since it also supports floats for position, + //This will always work in percentage + float fPos; + if (m_nMediaStart != m_nMediaStop) { + fPos = float(nPos - m_nMediaStart) * 100.0f / float(m_nMediaStop - m_nMediaStart); + } else { // The duration might be unknown + fPos = 0.0f; + } + + EnterCriticalSection(&cs); + m_MonoPage.m_ProgBar[1].SetPos(fPos); + m_ColorPage.m_ProgBar[1].SetPos(fPos); + LeaveCriticalSection(&cs); +} + +/* update status message (displayed for nTimeOut milliseconds) */ +void CMPC_Lcd::SetStatusMessage(const TCHAR* text, int nTimeOut) +{ + if (!m_Connection.IsConnected()) { + return; + } + + __time64_t ltime; + _time64(<ime); + if ((nTimeOut /= 1000) < 1) { + nTimeOut = 1; + } + + EnterCriticalSection(&cs); + nThread_tTimeout = ltime + nTimeOut; + m_MonoPage.m_Text[0].SetText(text); + m_ColorPage.m_Text[0].SetText(text); + LeaveCriticalSection(&cs); +} + +/* update play state bitmap */ +void CMPC_Lcd::SetPlayState(CMPC_Lcd::PlayState ps) +{ + if (!m_Connection.IsConnected()) { + return; + } + + EnterCriticalSection(&cs); + switch (ps) { + case PS_PLAY: + SetAsForeground(true); + break; + case PS_PAUSE: + break; + case PS_STOP: + SetAsForeground(false); + break; + default: + break; + } + + m_MonoPage.SetPlayState((CLCDMyMonoPage::PlayState)ps); + m_ColorPage.SetPlayState((CLCDMyColorPage::PlayState)ps); + + LeaveCriticalSection(&cs); +} + +HRESULT CMPC_Lcd::SetAsForeground(BOOL setAsForeground) +{ + if (nullptr != m_Connection.MonoOutput()) { + m_Connection.MonoOutput()->SetAsForeground(setAsForeground); + } + + if (nullptr != m_Connection.ColorOutput()) { + m_Connection.ColorOutput()->SetAsForeground(setAsForeground); + } + + return S_OK; +} diff --git a/src/mpc-hc/LcdSupport.h b/src/mpc-hc/LcdSupport.h index f7906cd6e72..c66ab24371a 100644 --- a/src/mpc-hc/LcdSupport.h +++ b/src/mpc-hc/LcdSupport.h @@ -1,136 +1,136 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2016 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 . - * - */ - -#pragma once - -#include "lglcd/lglcd.h" -#include "LCDUI/LCDUI.h" - -class CLCDMyProgressBar : public CLCDProgressBar -{ -public: - enum eMY_PROGRESS_STYLE { - STYLE_FILLED_H, - STYLE_CURSOR, - STYLE_DASHED_CURSOR, - STYLE_FILLED_V - }; - - virtual void OnDraw(CLCDGfxBase& rGfx); - virtual void SetProgressStyle(ePROGRESS_STYLE eStyle); - virtual void SetProgressStyle(eMY_PROGRESS_STYLE eMyStyle); - -protected: - eMY_PROGRESS_STYLE m_eMyStyle; -}; - -class CLCDMyMonoPage : public CLCDPage -{ -public: - enum PlayState { - PS_PLAY = 0, - PS_PAUSE = 1, - PS_STOP = 2, - PS_UNUSED = 3 - }; - - virtual HRESULT Initialize(); - virtual void OnLCDButtonUp(int nButton); - void SetPlayState(PlayState ps); - - CLCDMyMonoPage(); - ~CLCDMyMonoPage(); - - CLCDScrollingText m_Text1; - CLCDText m_Text[2]; - CLCDMyProgressBar m_ProgBar[2]; - CLCDAnimatedBitmap m_PlayState; -private: - HBITMAP hBmp[PS_UNUSED]; -}; - -class CLCDMyColorPage : public CLCDPage -{ -public: - enum PlayState { - PS_PLAY = 0, - PS_PAUSE = 1, - PS_STOP = 2, - PS_UNUSED = 3 - }; - - virtual HRESULT Initialize(); - virtual void OnLCDButtonUp(int nButton); - void SetPlayState(PlayState ps); - - CLCDMyColorPage(); - ~CLCDMyColorPage(); - - CLCDScrollingText m_Text1; - CLCDText m_Text[2]; - CLCDMyProgressBar m_ProgBar[2]; - CLCDAnimatedBitmap m_PlayState; -private: - HBITMAP hBmp[PS_UNUSED]; -}; - -class CMPC_Lcd -{ -public: - enum PlayState { - PS_PLAY = 0, - PS_PAUSE = 1, - PS_STOP = 2, - PS_UNUSED = 3 - }; - -private: - lgLcdConnectContextEx m_ConnCtx; - HANDLE hLCD_UpdateThread; - - __int64 m_nMediaStart; - __int64 m_nMediaStop; - __int64 m_nVolumeStart; - __int64 m_nVolumeStop; - - HRESULT SetAsForeground(BOOL setAsForeground); - -public: - CLCDConnection m_Connection; - CLCDOutput* m_MonoOutput; - CLCDOutput* m_ColorOutput; - CLCDMyMonoPage m_MonoPage; - CLCDMyColorPage m_ColorPage; - bool Thread_Loop; - __time64_t nThread_tTimeout; - CRITICAL_SECTION cs; - - CMPC_Lcd(); - ~CMPC_Lcd(); - - void SetMediaTitle(const TCHAR* text); - void SetMediaRange(__int64 nStart, __int64 nStop); - void SetMediaPos(__int64 nPos); - void SetVolumeRange(__int64 nStart, __int64 nStop); - void SetVolume(__int64 nVol); - void SetStatusMessage(const TCHAR* text, int nTimeOut); - void SetPlayState(PlayState ps); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2016 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 . + * + */ + +#pragma once + +#include "lglcd/lglcd.h" +#include "LCDUI/LCDUI.h" + +class CLCDMyProgressBar : public CLCDProgressBar +{ +public: + enum eMY_PROGRESS_STYLE { + STYLE_FILLED_H, + STYLE_CURSOR, + STYLE_DASHED_CURSOR, + STYLE_FILLED_V + }; + + virtual void OnDraw(CLCDGfxBase& rGfx); + virtual void SetProgressStyle(ePROGRESS_STYLE eStyle); + virtual void SetProgressStyle(eMY_PROGRESS_STYLE eMyStyle); + +protected: + eMY_PROGRESS_STYLE m_eMyStyle; +}; + +class CLCDMyMonoPage : public CLCDPage +{ +public: + enum PlayState { + PS_PLAY = 0, + PS_PAUSE = 1, + PS_STOP = 2, + PS_UNUSED = 3 + }; + + virtual HRESULT Initialize(); + virtual void OnLCDButtonUp(int nButton); + void SetPlayState(PlayState ps); + + CLCDMyMonoPage(); + ~CLCDMyMonoPage(); + + CLCDScrollingText m_Text1; + CLCDText m_Text[2]; + CLCDMyProgressBar m_ProgBar[2]; + CLCDAnimatedBitmap m_PlayState; +private: + HBITMAP hBmp[PS_UNUSED]; +}; + +class CLCDMyColorPage : public CLCDPage +{ +public: + enum PlayState { + PS_PLAY = 0, + PS_PAUSE = 1, + PS_STOP = 2, + PS_UNUSED = 3 + }; + + virtual HRESULT Initialize(); + virtual void OnLCDButtonUp(int nButton); + void SetPlayState(PlayState ps); + + CLCDMyColorPage(); + ~CLCDMyColorPage(); + + CLCDScrollingText m_Text1; + CLCDText m_Text[2]; + CLCDMyProgressBar m_ProgBar[2]; + CLCDAnimatedBitmap m_PlayState; +private: + HBITMAP hBmp[PS_UNUSED]; +}; + +class CMPC_Lcd +{ +public: + enum PlayState { + PS_PLAY = 0, + PS_PAUSE = 1, + PS_STOP = 2, + PS_UNUSED = 3 + }; + +private: + lgLcdConnectContextEx m_ConnCtx; + HANDLE hLCD_UpdateThread; + + __int64 m_nMediaStart; + __int64 m_nMediaStop; + __int64 m_nVolumeStart; + __int64 m_nVolumeStop; + + HRESULT SetAsForeground(BOOL setAsForeground); + +public: + CLCDConnection m_Connection; + CLCDOutput* m_MonoOutput; + CLCDOutput* m_ColorOutput; + CLCDMyMonoPage m_MonoPage; + CLCDMyColorPage m_ColorPage; + bool Thread_Loop; + __time64_t nThread_tTimeout; + CRITICAL_SECTION cs; + + CMPC_Lcd(); + ~CMPC_Lcd(); + + void SetMediaTitle(const TCHAR* text); + void SetMediaRange(__int64 nStart, __int64 nStop); + void SetMediaPos(__int64 nPos); + void SetVolumeRange(__int64 nStart, __int64 nStop); + void SetVolume(__int64 nVol); + void SetStatusMessage(const TCHAR* text, int nTimeOut); + void SetPlayState(PlayState ps); +}; diff --git a/src/mpc-hc/MPCPngImage.cpp b/src/mpc-hc/MPCPngImage.cpp index ca2fea78fcb..f8c34078b9a 100644 --- a/src/mpc-hc/MPCPngImage.cpp +++ b/src/mpc-hc/MPCPngImage.cpp @@ -1,114 +1,114 @@ -#include "stdafx.h" -#include "MPCPngImage.h" - - -////////////////////////////////////////////////////////////////////// -// CPngImage - -CImage* CMPCPngImage::m_pImage; - -////////////////////////////////////////////////////////////////////// -// Operations -////////////////////////////////////////////////////////////////////// - -BOOL CMPCPngImage::Load(UINT uiResID, HINSTANCE hinstRes) -{ - return Load(MAKEINTRESOURCE(uiResID), hinstRes); -} - -BOOL CMPCPngImage::Load(LPCTSTR lpszResourceName, HINSTANCE hinstRes) -{ - if (hinstRes == nullptr) { - hinstRes = AfxFindResourceHandle(lpszResourceName, _T("PNG")); - } - - HRSRC hRsrc = ::FindResource(hinstRes, lpszResourceName, _T("PNG")); - if (hRsrc == nullptr) { - // Fallback to the instance handle - hinstRes = AfxGetInstanceHandle(); - hRsrc = ::FindResource(hinstRes, lpszResourceName, _T("PNG")); - if (hRsrc == nullptr) { - return FALSE; - } - } - - HGLOBAL hGlobal = LoadResource(hinstRes, hRsrc); - if (hGlobal == nullptr) { - return FALSE; - } - - LPVOID lpBuffer = ::LockResource(hGlobal); - if (lpBuffer == nullptr) { - FreeResource(hGlobal); - return FALSE; - } - - BOOL bRes = LoadFromBuffer((LPBYTE) lpBuffer, (UINT) ::SizeofResource(hinstRes, hRsrc)); - - UnlockResource(hGlobal); - FreeResource(hGlobal); - - return bRes; -} -//******************************************************************************* -BOOL CMPCPngImage::LoadFromFile(LPCTSTR lpszPath) -{ - BOOL bRes = FALSE; - - if (m_pImage == nullptr) { - m_pImage = DEBUG_NEW CImage; - ENSURE(m_pImage != nullptr); - } - - if (m_pImage->Load(lpszPath) == S_OK) { - bRes = Attach(m_pImage->Detach()); - } - - return bRes; -} -//******************************************************************************* -BOOL CMPCPngImage::LoadFromBuffer(const LPBYTE lpBuffer, UINT uiSize) -{ - ASSERT(lpBuffer != nullptr); - - HGLOBAL hRes = ::GlobalAlloc(GMEM_MOVEABLE, uiSize); - if (hRes == nullptr) { - return FALSE; - } - - IStream* pStream = nullptr; - LPVOID lpResBuffer = ::GlobalLock(hRes); - ASSERT(lpResBuffer != nullptr); - - memcpy(lpResBuffer, lpBuffer, uiSize); - - HRESULT hResult = ::CreateStreamOnHGlobal(hRes, TRUE, &pStream); - - if (hResult != S_OK) { - ::GlobalUnlock(hRes); - ::GlobalFree(hRes); - return FALSE; - } - - if (m_pImage == nullptr) { - m_pImage = DEBUG_NEW CImage; - ENSURE(m_pImage != nullptr); - } - - m_pImage->Load(pStream); - pStream->Release(); //should free hRes due to fDeleteOnRelease=TRUE above - - BOOL bRes = Attach(m_pImage->Detach()); - - return bRes; -} - -CSize CMPCPngImage::GetSize() -{ - CSize size; - BITMAP bm; - if (GetBitmap(&bm)) { - size.SetSize(bm.bmWidth, bm.bmHeight); - } - return size; -} +#include "stdafx.h" +#include "MPCPngImage.h" + + +////////////////////////////////////////////////////////////////////// +// CPngImage + +CImage* CMPCPngImage::m_pImage; + +////////////////////////////////////////////////////////////////////// +// Operations +////////////////////////////////////////////////////////////////////// + +BOOL CMPCPngImage::Load(UINT uiResID, HINSTANCE hinstRes) +{ + return Load(MAKEINTRESOURCE(uiResID), hinstRes); +} + +BOOL CMPCPngImage::Load(LPCTSTR lpszResourceName, HINSTANCE hinstRes) +{ + if (hinstRes == nullptr) { + hinstRes = AfxFindResourceHandle(lpszResourceName, _T("PNG")); + } + + HRSRC hRsrc = ::FindResource(hinstRes, lpszResourceName, _T("PNG")); + if (hRsrc == nullptr) { + // Fallback to the instance handle + hinstRes = AfxGetInstanceHandle(); + hRsrc = ::FindResource(hinstRes, lpszResourceName, _T("PNG")); + if (hRsrc == nullptr) { + return FALSE; + } + } + + HGLOBAL hGlobal = LoadResource(hinstRes, hRsrc); + if (hGlobal == nullptr) { + return FALSE; + } + + LPVOID lpBuffer = ::LockResource(hGlobal); + if (lpBuffer == nullptr) { + FreeResource(hGlobal); + return FALSE; + } + + BOOL bRes = LoadFromBuffer((LPBYTE) lpBuffer, (UINT) ::SizeofResource(hinstRes, hRsrc)); + + UnlockResource(hGlobal); + FreeResource(hGlobal); + + return bRes; +} +//******************************************************************************* +BOOL CMPCPngImage::LoadFromFile(LPCTSTR lpszPath) +{ + BOOL bRes = FALSE; + + if (m_pImage == nullptr) { + m_pImage = DEBUG_NEW CImage; + ENSURE(m_pImage != nullptr); + } + + if (m_pImage->Load(lpszPath) == S_OK) { + bRes = Attach(m_pImage->Detach()); + } + + return bRes; +} +//******************************************************************************* +BOOL CMPCPngImage::LoadFromBuffer(const LPBYTE lpBuffer, UINT uiSize) +{ + ASSERT(lpBuffer != nullptr); + + HGLOBAL hRes = ::GlobalAlloc(GMEM_MOVEABLE, uiSize); + if (hRes == nullptr) { + return FALSE; + } + + IStream* pStream = nullptr; + LPVOID lpResBuffer = ::GlobalLock(hRes); + ASSERT(lpResBuffer != nullptr); + + memcpy(lpResBuffer, lpBuffer, uiSize); + + HRESULT hResult = ::CreateStreamOnHGlobal(hRes, TRUE, &pStream); + + if (hResult != S_OK) { + ::GlobalUnlock(hRes); + ::GlobalFree(hRes); + return FALSE; + } + + if (m_pImage == nullptr) { + m_pImage = DEBUG_NEW CImage; + ENSURE(m_pImage != nullptr); + } + + m_pImage->Load(pStream); + pStream->Release(); //should free hRes due to fDeleteOnRelease=TRUE above + + BOOL bRes = Attach(m_pImage->Detach()); + + return bRes; +} + +CSize CMPCPngImage::GetSize() +{ + CSize size; + BITMAP bm; + if (GetBitmap(&bm)) { + size.SetSize(bm.bmWidth, bm.bmHeight); + } + return size; +} diff --git a/src/mpc-hc/MPCPngImage.h b/src/mpc-hc/MPCPngImage.h index 9c041a74c4c..47448a7ff4a 100644 --- a/src/mpc-hc/MPCPngImage.h +++ b/src/mpc-hc/MPCPngImage.h @@ -1,29 +1,29 @@ -#pragma once - -#include - -class CMPCPngImage : public CBitmap -{ - // Construction/Destruction -public: - CMPCPngImage() = default; - virtual ~CMPCPngImage() = default; - - // Attributes: -protected: - static ATL::CImage* m_pImage; - - // Operations: -public: - BOOL Load(UINT uiResID, HINSTANCE hinstRes = nullptr); - BOOL Load(LPCTSTR lpszResourceName, HINSTANCE hinstRes = nullptr); - - BOOL LoadFromFile(LPCTSTR lpszPath); - BOOL LoadFromBuffer(const LPBYTE lpBuffer, UINT uiSize); - - CSize GetSize(); - - static void __stdcall CleanUp() { - SAFE_DELETE(m_pImage); - } -}; +#pragma once + +#include + +class CMPCPngImage : public CBitmap +{ + // Construction/Destruction +public: + CMPCPngImage() = default; + virtual ~CMPCPngImage() = default; + + // Attributes: +protected: + static ATL::CImage* m_pImage; + + // Operations: +public: + BOOL Load(UINT uiResID, HINSTANCE hinstRes = nullptr); + BOOL Load(LPCTSTR lpszResourceName, HINSTANCE hinstRes = nullptr); + + BOOL LoadFromFile(LPCTSTR lpszPath); + BOOL LoadFromBuffer(const LPBYTE lpBuffer, UINT uiSize); + + CSize GetSize(); + + static void __stdcall CleanUp() { + SAFE_DELETE(m_pImage); + } +}; diff --git a/src/mpc-hc/MainFrm.cpp b/src/mpc-hc/MainFrm.cpp index e4237fc5863..7f96c4c48bb 100644 --- a/src/mpc-hc/MainFrm.cpp +++ b/src/mpc-hc/MainFrm.cpp @@ -1,22182 +1,22182 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "MainFrm.h" -#include "mplayerc.h" -#include "version.h" - -#include "GraphThread.h" -#include "FGFilterLAV.h" -#include "FGManager.h" -#include "FGManagerBDA.h" -#include "ShockwaveGraph.h" -#include "TextPassThruFilter.h" -#include "FakeFilterMapper2.h" - -#include "FavoriteAddDlg.h" -#include "GoToDlg.h" -#include "MediaTypesDlg.h" -#include "OpenFileDlg.h" -#include "PnSPresetsDlg.h" -#include "SaveDlg.h" -#include "SaveImageDialog.h" -#include "SaveSubtitlesFileDialog.h" -#include "SaveThumbnailsDialog.h" -#include "OpenDirHelper.h" -#include "OpenDlg.h" -#include "TunerScanDlg.h" - -#include "ComPropertySheet.h" -#include "PPageAccelTbl.h" -#include "PPageAudioSwitcher.h" -#include "PPageFileInfoSheet.h" -#include "PPageSheet.h" -#include "PPageSubStyle.h" -#include "PPageSubtitles.h" - -#include "CoverArt.h" -#include "CrashReporter.h" -#include "KeyProvider.h" -#include "SkypeMoodMsgHandler.h" -#include "Translations.h" -#include "UpdateChecker.h" -#include "WebServer.h" -#include -#include -#include - -#include "../DeCSS/VobFile.h" -#include "../Subtitles/PGSSub.h" -#include "../Subtitles/RLECodedSubtitle.h" -#include "../Subtitles/RTS.h" -#include "../Subtitles/STS.h" -#include - -#include "../filters/InternalPropertyPage.h" -#include "../filters/PinInfoWnd.h" -#include "../filters/renderer/SyncClock/SyncClock.h" -#include "../filters/transform/BufferFilter/BufferFilter.h" - -#include -#include -#include -#include - -#include "FullscreenWnd.h" -#include "Monitors.h" - -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "YoutubeDL.h" -#include "CMPCThemeMenu.h" -#include "CMPCThemeDockBar.h" -#include "CMPCThemeMiniDockFrameWnd.h" -#include "RarEntrySelectorDialog.h" -#include "FileHandle.h" -#include "MPCFolderPickerDialog.h" - -#include "stb/stb_image.h" -#include "stb/stb_image_resize2.h" - -#include -#undef SubclassWindow - -// IID_IAMLine21Decoder -DECLARE_INTERFACE_IID_(IAMLine21Decoder_2, IAMLine21Decoder, "6E8D4A21-310C-11d0-B79A-00AA003767A7") {}; - -#define MIN_LOGO_WIDTH 400 -#define MIN_LOGO_HEIGHT 150 - -#define PREV_CHAP_THRESHOLD 2 - -static UINT s_uTaskbarRestart = RegisterWindowMessage(_T("TaskbarCreated")); -static UINT WM_NOTIFYICON = RegisterWindowMessage(_T("MYWM_NOTIFYICON")); -static UINT s_uTBBC = RegisterWindowMessage(_T("TaskbarButtonCreated")); - -CMainFrame::PlaybackRateMap CMainFrame::filePlaybackRates = { - { ID_PLAY_PLAYBACKRATE_025, .25f}, - { ID_PLAY_PLAYBACKRATE_050, .50f}, - { ID_PLAY_PLAYBACKRATE_075, .75f}, - { ID_PLAY_PLAYBACKRATE_090, .90f}, - { ID_PLAY_PLAYBACKRATE_100, 1.00f}, - { ID_PLAY_PLAYBACKRATE_110, 1.10f}, - { ID_PLAY_PLAYBACKRATE_125, 1.25f}, - { ID_PLAY_PLAYBACKRATE_150, 1.50f}, - { ID_PLAY_PLAYBACKRATE_200, 2.00f}, - { ID_PLAY_PLAYBACKRATE_300, 3.00f}, - { ID_PLAY_PLAYBACKRATE_400, 4.00f}, - { ID_PLAY_PLAYBACKRATE_600, 6.00f}, - { ID_PLAY_PLAYBACKRATE_800, 8.00f}, -}; - -CMainFrame::PlaybackRateMap CMainFrame::dvdPlaybackRates = { - { ID_PLAY_PLAYBACKRATE_025, .25f}, - { ID_PLAY_PLAYBACKRATE_050, .50f}, - { ID_PLAY_PLAYBACKRATE_100, 1.00f}, - { ID_PLAY_PLAYBACKRATE_200, 2.00f}, - { ID_PLAY_PLAYBACKRATE_400, 4.00f}, - { ID_PLAY_PLAYBACKRATE_800, 8.00f}, -}; - - -static bool EnsureDirectory(CString directory) -{ - int ret = SHCreateDirectoryEx(nullptr, directory, nullptr); - bool result = ret == ERROR_SUCCESS || ret == ERROR_ALREADY_EXISTS; - if (!result) { - AfxMessageBox(_T("Cannot create directory: ") + directory, MB_ICONEXCLAMATION | MB_OK); - } - return result; -} - -class CSubClock : public CUnknown, public ISubClock -{ - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(ISubClock) - CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - - REFERENCE_TIME m_rt; - -public: - CSubClock() : CUnknown(NAME("CSubClock"), nullptr) { - m_rt = 0; - } - - DECLARE_IUNKNOWN; - - // ISubClock - STDMETHODIMP SetTime(REFERENCE_TIME rt) { - m_rt = rt; - return S_OK; - } - STDMETHODIMP_(REFERENCE_TIME) GetTime() { - return m_rt; - } -}; - -bool FileFavorite::TryParse(const CString& fav, FileFavorite& ff) -{ - CAtlList parts; - return TryParse(fav, ff, parts); -} - -bool FileFavorite::TryParse(const CString& fav, FileFavorite& ff, CAtlList& parts) -{ - ExplodeEsc(fav, parts, _T(';')); - if (parts.IsEmpty()) { - return false; - } - - ff.Name = parts.RemoveHead(); - - if (!parts.IsEmpty()) { - // Start position and optional A-B marks "pos[:A:B]" - auto startPos = parts.RemoveHead(); - _stscanf_s(startPos, _T("%I64d:%I64d:%I64d"), &ff.Start, &ff.MarkA, &ff.MarkB); - ff.Start = std::max(ff.Start, 0ll); // Sanitize - } - if (!parts.IsEmpty()) { - _stscanf_s(parts.RemoveHead(), _T("%d"), &ff.RelativeDrive); - } - return true; -} - -CString FileFavorite::ToString() const -{ - CString str; - if (RelativeDrive) { - str = _T("[RD]"); - } - if (Start > 0) { // Start position - str.AppendFormat(_T("[%s]"), ReftimeToString2(Start).GetString()); - } - if (MarkA > 0 || MarkB > 0) { // A-B marks (only characters to save space) - CString abMarks; - if (MarkA > 0) { - abMarks = _T("A"); - } - if (MarkB > 0) { - abMarks.Append(_T("-B")); - } - str.AppendFormat(_T("[%s]"), abMarks.GetString()); - } - return str; -} - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame - -IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd) - -BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) - ON_WM_NCCREATE() - ON_WM_CREATE() - ON_WM_DESTROY() - ON_WM_CLOSE() - ON_WM_MEASUREITEM() - - ON_MESSAGE(WM_MPCVR_SWITCH_FULLSCREEN, OnMPCVRSwitchFullscreen) - - ON_REGISTERED_MESSAGE(s_uTaskbarRestart, OnTaskBarRestart) - ON_REGISTERED_MESSAGE(WM_NOTIFYICON, OnNotifyIcon) - - ON_REGISTERED_MESSAGE(s_uTBBC, OnTaskBarThumbnailsCreate) - - ON_REGISTERED_MESSAGE(SkypeMoodMsgHandler::uSkypeControlAPIAttach, OnSkypeAttach) - - ON_WM_SETFOCUS() - ON_WM_GETMINMAXINFO() - ON_WM_MOVE() - ON_WM_ENTERSIZEMOVE() - ON_WM_MOVING() - ON_WM_SIZE() - ON_WM_SIZING() - ON_WM_EXITSIZEMOVE() - ON_MESSAGE_VOID(WM_DISPLAYCHANGE, OnDisplayChange) - ON_WM_WINDOWPOSCHANGING() - - ON_MESSAGE(WM_DPICHANGED, OnDpiChanged) - - ON_WM_SYSCOMMAND() - ON_WM_ACTIVATEAPP() - ON_MESSAGE(WM_APPCOMMAND, OnAppCommand) - ON_WM_INPUT() - ON_MESSAGE(WM_HOTKEY, OnHotKey) - - ON_WM_TIMER() - - ON_MESSAGE(WM_GRAPHNOTIFY, OnGraphNotify) - ON_MESSAGE(WM_RESET_DEVICE, OnResetDevice) - ON_MESSAGE(WM_REARRANGERENDERLESS, OnRepaintRenderLess) - - ON_MESSAGE_VOID(WM_SAVESETTINGS, SaveAppSettings) - - ON_WM_NCHITTEST() - - ON_WM_HSCROLL() - - ON_WM_INITMENU() - ON_WM_INITMENUPOPUP() - ON_WM_UNINITMENUPOPUP() - - ON_WM_ENTERMENULOOP() - - ON_WM_QUERYENDSESSION() - ON_WM_ENDSESSION() - - ON_COMMAND(ID_MENU_PLAYER_SHORT, OnMenuPlayerShort) - ON_COMMAND(ID_MENU_PLAYER_LONG, OnMenuPlayerLong) - ON_COMMAND(ID_MENU_FILTERS, OnMenuFilters) - - ON_UPDATE_COMMAND_UI(IDC_PLAYERSTATUS, OnUpdatePlayerStatus) - - ON_MESSAGE(WM_POSTOPEN, OnFilePostOpenmedia) - ON_MESSAGE(WM_OPENFAILED, OnOpenMediaFailed) - ON_MESSAGE(WM_DVB_EIT_DATA_READY, OnCurrentChannelInfoUpdated) - - ON_COMMAND(ID_BOSS, OnBossKey) - - ON_COMMAND_RANGE(ID_STREAM_AUDIO_NEXT, ID_STREAM_AUDIO_PREV, OnStreamAudio) - ON_COMMAND_RANGE(ID_STREAM_SUB_NEXT, ID_STREAM_SUB_PREV, OnStreamSub) - ON_COMMAND(ID_AUDIOSHIFT_ONOFF, OnAudioShiftOnOff) - ON_COMMAND(ID_STREAM_SUB_ONOFF, OnStreamSubOnOff) - ON_COMMAND_RANGE(ID_DVD_ANGLE_NEXT, ID_DVD_ANGLE_PREV, OnDvdAngle) - ON_COMMAND_RANGE(ID_DVD_AUDIO_NEXT, ID_DVD_AUDIO_PREV, OnDvdAudio) - ON_COMMAND_RANGE(ID_DVD_SUB_NEXT, ID_DVD_SUB_PREV, OnDvdSub) - ON_COMMAND(ID_DVD_SUB_ONOFF, OnDvdSubOnOff) - - ON_COMMAND(ID_FILE_OPENQUICK, OnFileOpenQuick) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENMEDIA, OnUpdateFileOpen) - ON_COMMAND(ID_FILE_OPENMEDIA, OnFileOpenmedia) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENMEDIA, OnUpdateFileOpen) - ON_WM_COPYDATA() - ON_COMMAND(ID_FILE_OPENDVDBD, OnFileOpendvd) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENDVDBD, OnUpdateFileOpen) - ON_COMMAND(ID_FILE_OPENDEVICE, OnFileOpendevice) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENDEVICE, OnUpdateFileOpen) - ON_COMMAND_RANGE(ID_FILE_OPEN_OPTICAL_DISK_START, ID_FILE_OPEN_OPTICAL_DISK_END, OnFileOpenOpticalDisk) - ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_OPEN_OPTICAL_DISK_START, ID_FILE_OPEN_OPTICAL_DISK_END, OnUpdateFileOpen) - ON_COMMAND(ID_FILE_REOPEN, OnFileReopen) - ON_COMMAND(ID_FILE_RECYCLE, OnFileRecycle) - ON_COMMAND(ID_FILE_SAVE_COPY, OnFileSaveAs) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_COPY, OnUpdateFileSaveAs) - ON_COMMAND(ID_FILE_SAVE_IMAGE, OnFileSaveImage) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_IMAGE, OnUpdateFileSaveImage) - ON_COMMAND(ID_FILE_SAVE_IMAGE_AUTO, OnFileSaveImageAuto) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_IMAGE_AUTO, OnUpdateFileSaveImage) - ON_COMMAND(ID_CMDLINE_SAVE_THUMBNAILS, OnCmdLineSaveThumbnails) - ON_COMMAND(ID_FILE_SAVE_THUMBNAILS, OnFileSaveThumbnails) - ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_THUMBNAILS, OnUpdateFileSaveThumbnails) - ON_COMMAND(ID_FILE_SUBTITLES_LOAD, OnFileSubtitlesLoad) - ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_LOAD, OnUpdateFileSubtitlesLoad) - ON_COMMAND(ID_FILE_SUBTITLES_SAVE, OnFileSubtitlesSave) - ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_SAVE, OnUpdateFileSubtitlesSave) - //ON_COMMAND(ID_FILE_SUBTITLES_UPLOAD, OnFileSubtitlesUpload) - //ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_UPLOAD, OnUpdateFileSubtitlesUpload) - ON_COMMAND(ID_FILE_SUBTITLES_DOWNLOAD, OnFileSubtitlesDownload) - ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_DOWNLOAD, OnUpdateFileSubtitlesDownload) - ON_COMMAND(ID_FILE_PROPERTIES, OnFileProperties) - ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateFileProperties) - ON_COMMAND(ID_FILE_OPEN_LOCATION, OnFileOpenLocation) - ON_UPDATE_COMMAND_UI(ID_FILE_OPEN_LOCATION, OnUpdateFileProperties) - ON_COMMAND(ID_FILE_CLOSE_AND_RESTORE, OnFileCloseAndRestore) - ON_UPDATE_COMMAND_UI(ID_FILE_CLOSE_AND_RESTORE, OnUpdateFileClose) - ON_COMMAND(ID_FILE_CLOSEMEDIA, OnFileCloseMedia) - ON_UPDATE_COMMAND_UI(ID_FILE_CLOSEMEDIA, OnUpdateFileClose) - - ON_COMMAND(ID_VIEW_CAPTIONMENU, OnViewCaptionmenu) - ON_UPDATE_COMMAND_UI(ID_VIEW_CAPTIONMENU, OnUpdateViewCaptionmenu) - ON_COMMAND_RANGE(ID_VIEW_SEEKER, ID_VIEW_STATUS, OnViewControlBar) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_SEEKER, ID_VIEW_STATUS, OnUpdateViewControlBar) - ON_COMMAND(ID_VIEW_SUBRESYNC, OnViewSubresync) - ON_UPDATE_COMMAND_UI(ID_VIEW_SUBRESYNC, OnUpdateViewSubresync) - ON_COMMAND(ID_VIEW_PLAYLIST, OnViewPlaylist) - ON_UPDATE_COMMAND_UI(ID_VIEW_PLAYLIST, OnUpdateViewPlaylist) - ON_COMMAND(ID_PLAYLIST_TOGGLE_SHUFFLE, OnPlaylistToggleShuffle) - ON_COMMAND(ID_VIEW_EDITLISTEDITOR, OnViewEditListEditor) - ON_COMMAND(ID_EDL_IN, OnEDLIn) - ON_UPDATE_COMMAND_UI(ID_EDL_IN, OnUpdateEDLIn) - ON_COMMAND(ID_EDL_OUT, OnEDLOut) - ON_UPDATE_COMMAND_UI(ID_EDL_OUT, OnUpdateEDLOut) - ON_COMMAND(ID_EDL_NEWCLIP, OnEDLNewClip) - ON_UPDATE_COMMAND_UI(ID_EDL_NEWCLIP, OnUpdateEDLNewClip) - ON_COMMAND(ID_EDL_SAVE, OnEDLSave) - ON_UPDATE_COMMAND_UI(ID_EDL_SAVE, OnUpdateEDLSave) - ON_COMMAND(ID_VIEW_CAPTURE, OnViewCapture) - ON_UPDATE_COMMAND_UI(ID_VIEW_CAPTURE, OnUpdateViewCapture) - ON_COMMAND(ID_VIEW_DEBUGSHADERS, OnViewDebugShaders) - ON_UPDATE_COMMAND_UI(ID_VIEW_DEBUGSHADERS, OnUpdateViewDebugShaders) - ON_COMMAND(ID_VIEW_PRESETS_MINIMAL, OnViewMinimal) - ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_MINIMAL, OnUpdateViewMinimal) - ON_COMMAND(ID_VIEW_PRESETS_COMPACT, OnViewCompact) - ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_COMPACT, OnUpdateViewCompact) - ON_COMMAND(ID_VIEW_PRESETS_NORMAL, OnViewNormal) - ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_NORMAL, OnUpdateViewNormal) - ON_COMMAND(ID_VIEW_FULLSCREEN, OnViewFullscreen) - ON_COMMAND(ID_VIEW_FULLSCREEN_SECONDARY, OnViewFullscreenSecondary) - ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCREEN, OnUpdateViewFullscreen) - ON_COMMAND_RANGE(ID_VIEW_ZOOM_50, ID_VIEW_ZOOM_200, OnViewZoom) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_50, ID_VIEW_ZOOM_200, OnUpdateViewZoom) - ON_COMMAND_RANGE(ID_VIEW_ZOOM_25, ID_VIEW_ZOOM_25, OnViewZoom) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_25, ID_VIEW_ZOOM_25, OnUpdateViewZoom) - ON_COMMAND(ID_VIEW_ZOOM_AUTOFIT, OnViewZoomAutoFit) - ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_AUTOFIT, OnUpdateViewZoom) - ON_COMMAND(ID_VIEW_ZOOM_AUTOFIT_LARGER, OnViewZoomAutoFitLarger) - ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_AUTOFIT_LARGER, OnUpdateViewZoom) - ON_COMMAND_RANGE(ID_VIEW_ZOOM_SUB, ID_VIEW_ZOOM_ADD, OnViewModifySize) - ON_COMMAND_RANGE(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, OnViewDefaultVideoFrame) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, OnUpdateViewDefaultVideoFrame) - ON_COMMAND(ID_VIEW_VF_SWITCHZOOM, OnViewSwitchVideoFrame) - ON_COMMAND(ID_VIEW_VF_COMPMONDESKARDIFF, OnViewCompMonDeskARDiff) - ON_UPDATE_COMMAND_UI(ID_VIEW_VF_COMPMONDESKARDIFF, OnUpdateViewCompMonDeskARDiff) - ON_COMMAND_RANGE(ID_VIEW_RESET, ID_PANSCAN_CENTER, OnViewPanNScan) - ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_RESET, ID_PANSCAN_CENTER, OnUpdateViewPanNScan) - ON_COMMAND_RANGE(ID_PANNSCAN_PRESETS_START, ID_PANNSCAN_PRESETS_END, OnViewPanNScanPresets) - ON_UPDATE_COMMAND_UI_RANGE(ID_PANNSCAN_PRESETS_START, ID_PANNSCAN_PRESETS_END, OnUpdateViewPanNScanPresets) - ON_COMMAND_RANGE(ID_PANSCAN_ROTATEXP, ID_PANSCAN_ROTATEZM, OnViewRotate) - ON_UPDATE_COMMAND_UI_RANGE(ID_PANSCAN_ROTATEXP, ID_PANSCAN_ROTATEZM, OnUpdateViewRotate) - ON_COMMAND_RANGE(ID_PANSCAN_ROTATEZ270, ID_PANSCAN_ROTATEZ270, OnViewRotate) - ON_UPDATE_COMMAND_UI_RANGE(ID_PANSCAN_ROTATEZ270, ID_PANSCAN_ROTATEZ270, OnUpdateViewRotate) - ON_COMMAND_RANGE(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, OnViewAspectRatio) - ON_UPDATE_COMMAND_UI_RANGE(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, OnUpdateViewAspectRatio) - ON_COMMAND(ID_ASPECTRATIO_NEXT, OnViewAspectRatioNext) - ON_COMMAND_RANGE(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, OnViewOntop) - ON_UPDATE_COMMAND_UI_RANGE(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, OnUpdateViewOntop) - ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions) - - // Casimir666 - ON_UPDATE_COMMAND_UI(ID_VIEW_TEARING_TEST, OnUpdateViewTearingTest) - ON_COMMAND(ID_VIEW_TEARING_TEST, OnViewTearingTest) - ON_UPDATE_COMMAND_UI(ID_VIEW_DISPLAY_RENDERER_STATS, OnUpdateViewDisplayRendererStats) - ON_COMMAND(ID_VIEW_RESET_RENDERER_STATS, OnViewResetRendererStats) - ON_COMMAND(ID_VIEW_DISPLAY_RENDERER_STATS, OnViewDisplayRendererStats) - ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCREENGUISUPPORT, OnUpdateViewFullscreenGUISupport) - ON_UPDATE_COMMAND_UI(ID_VIEW_HIGHCOLORRESOLUTION, OnUpdateViewHighColorResolution) - ON_UPDATE_COMMAND_UI(ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION, OnUpdateViewForceInputHighColorResolution) - ON_UPDATE_COMMAND_UI(ID_VIEW_FULLFLOATINGPOINTPROCESSING, OnUpdateViewFullFloatingPointProcessing) - ON_UPDATE_COMMAND_UI(ID_VIEW_HALFFLOATINGPOINTPROCESSING, OnUpdateViewHalfFloatingPointProcessing) - ON_UPDATE_COMMAND_UI(ID_VIEW_ENABLEFRAMETIMECORRECTION, OnUpdateViewEnableFrameTimeCorrection) - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNC, OnUpdateViewVSync) - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET, OnUpdateViewVSyncOffset) - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCACCURATE, OnUpdateViewVSyncAccurate) - - ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZEVIDEO, OnUpdateViewSynchronizeVideo) - ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZEDISPLAY, OnUpdateViewSynchronizeDisplay) - ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZENEAREST, OnUpdateViewSynchronizeNearest) - - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_ENABLE, OnUpdateViewColorManagementEnable) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_AUTO, OnUpdateViewColorManagementInput) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_HDTV, OnUpdateViewColorManagementInput) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_SDTV_NTSC, OnUpdateViewColorManagementInput) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_SDTV_PAL, OnUpdateViewColorManagementInput) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_BRIGHT, OnUpdateViewColorManagementAmbientLight) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_DIM, OnUpdateViewColorManagementAmbientLight) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_DARK, OnUpdateViewColorManagementAmbientLight) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_PERCEPTUAL, OnUpdateViewColorManagementIntent) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC, OnUpdateViewColorManagementIntent) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_SATURATION, OnUpdateViewColorManagementIntent) - ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC, OnUpdateViewColorManagementIntent) - - ON_UPDATE_COMMAND_UI(ID_VIEW_EVROUTPUTRANGE_0_255, OnUpdateViewEVROutputRange) - ON_UPDATE_COMMAND_UI(ID_VIEW_EVROUTPUTRANGE_16_235, OnUpdateViewEVROutputRange) - - ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_BEFOREVSYNC, OnUpdateViewFlushGPU) - ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_AFTERPRESENT, OnUpdateViewFlushGPU) - ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_WAIT, OnUpdateViewFlushGPU) - - ON_UPDATE_COMMAND_UI(ID_VIEW_D3DFULLSCREEN, OnUpdateViewD3DFullscreen) - ON_UPDATE_COMMAND_UI(ID_VIEW_DISABLEDESKTOPCOMPOSITION, OnUpdateViewDisableDesktopComposition) - ON_UPDATE_COMMAND_UI(ID_VIEW_ALTERNATIVEVSYNC, OnUpdateViewAlternativeVSync) - - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET_INCREASE, OnUpdateViewVSyncOffsetIncrease) - ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET_DECREASE, OnUpdateViewVSyncOffsetDecrease) - ON_COMMAND(ID_VIEW_FULLSCREENGUISUPPORT, OnViewFullscreenGUISupport) - ON_COMMAND(ID_VIEW_HIGHCOLORRESOLUTION, OnViewHighColorResolution) - ON_COMMAND(ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION, OnViewForceInputHighColorResolution) - ON_COMMAND(ID_VIEW_FULLFLOATINGPOINTPROCESSING, OnViewFullFloatingPointProcessing) - ON_COMMAND(ID_VIEW_HALFFLOATINGPOINTPROCESSING, OnViewHalfFloatingPointProcessing) - ON_COMMAND(ID_VIEW_ENABLEFRAMETIMECORRECTION, OnViewEnableFrameTimeCorrection) - ON_COMMAND(ID_VIEW_VSYNC, OnViewVSync) - ON_COMMAND(ID_VIEW_VSYNCACCURATE, OnViewVSyncAccurate) - - ON_COMMAND(ID_VIEW_SYNCHRONIZEVIDEO, OnViewSynchronizeVideo) - ON_COMMAND(ID_VIEW_SYNCHRONIZEDISPLAY, OnViewSynchronizeDisplay) - ON_COMMAND(ID_VIEW_SYNCHRONIZENEAREST, OnViewSynchronizeNearest) - - ON_COMMAND(ID_VIEW_CM_ENABLE, OnViewColorManagementEnable) - ON_COMMAND(ID_VIEW_CM_INPUT_AUTO, OnViewColorManagementInputAuto) - ON_COMMAND(ID_VIEW_CM_INPUT_HDTV, OnViewColorManagementInputHDTV) - ON_COMMAND(ID_VIEW_CM_INPUT_SDTV_NTSC, OnViewColorManagementInputSDTV_NTSC) - ON_COMMAND(ID_VIEW_CM_INPUT_SDTV_PAL, OnViewColorManagementInputSDTV_PAL) - ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_BRIGHT, OnViewColorManagementAmbientLightBright) - ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_DIM, OnViewColorManagementAmbientLightDim) - ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_DARK, OnViewColorManagementAmbientLightDark) - ON_COMMAND(ID_VIEW_CM_INTENT_PERCEPTUAL, OnViewColorManagementIntentPerceptual) - ON_COMMAND(ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC, OnViewColorManagementIntentRelativeColorimetric) - ON_COMMAND(ID_VIEW_CM_INTENT_SATURATION, OnViewColorManagementIntentSaturation) - ON_COMMAND(ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC, OnViewColorManagementIntentAbsoluteColorimetric) - - ON_COMMAND(ID_VIEW_EVROUTPUTRANGE_0_255, OnViewEVROutputRange_0_255) - ON_COMMAND(ID_VIEW_EVROUTPUTRANGE_16_235, OnViewEVROutputRange_16_235) - - ON_COMMAND(ID_VIEW_FLUSHGPU_BEFOREVSYNC, OnViewFlushGPUBeforeVSync) - ON_COMMAND(ID_VIEW_FLUSHGPU_AFTERPRESENT, OnViewFlushGPUAfterVSync) - ON_COMMAND(ID_VIEW_FLUSHGPU_WAIT, OnViewFlushGPUWait) - - ON_COMMAND(ID_VIEW_D3DFULLSCREEN, OnViewD3DFullScreen) - ON_COMMAND(ID_VIEW_DISABLEDESKTOPCOMPOSITION, OnViewDisableDesktopComposition) - ON_COMMAND(ID_VIEW_ALTERNATIVEVSYNC, OnViewAlternativeVSync) - ON_COMMAND(ID_VIEW_RESET_DEFAULT, OnViewResetDefault) - ON_COMMAND(ID_VIEW_RESET_OPTIMAL, OnViewResetOptimal) - - ON_COMMAND(ID_VIEW_VSYNCOFFSET_INCREASE, OnViewVSyncOffsetIncrease) - ON_COMMAND(ID_VIEW_VSYNCOFFSET_DECREASE, OnViewVSyncOffsetDecrease) - ON_UPDATE_COMMAND_UI(ID_PRESIZE_SHADERS_TOGGLE, OnUpdateShaderToggle1) - ON_COMMAND(ID_PRESIZE_SHADERS_TOGGLE, OnShaderToggle1) - ON_UPDATE_COMMAND_UI(ID_POSTSIZE_SHADERS_TOGGLE, OnUpdateShaderToggle2) - ON_COMMAND(ID_POSTSIZE_SHADERS_TOGGLE, OnShaderToggle2) - ON_UPDATE_COMMAND_UI(ID_VIEW_OSD_DISPLAY_TIME, OnUpdateViewOSDDisplayTime) - ON_COMMAND(ID_VIEW_OSD_DISPLAY_TIME, OnViewOSDDisplayTime) - ON_UPDATE_COMMAND_UI(ID_VIEW_OSD_SHOW_FILENAME, OnUpdateViewOSDShowFileName) - ON_COMMAND(ID_VIEW_OSD_SHOW_FILENAME, OnViewOSDShowFileName) - ON_COMMAND(ID_D3DFULLSCREEN_TOGGLE, OnD3DFullscreenToggle) - ON_COMMAND_RANGE(ID_GOTO_PREV_SUB, ID_GOTO_NEXT_SUB, OnGotoSubtitle) - ON_COMMAND_RANGE(ID_SUBRESYNC_SHIFT_DOWN, ID_SUBRESYNC_SHIFT_UP, OnSubresyncShiftSub) - ON_COMMAND_RANGE(ID_SUB_DELAY_DOWN, ID_SUB_DELAY_UP, OnSubtitleDelay) - ON_COMMAND_RANGE(ID_SUB_POS_DOWN, ID_SUB_POS_UP, OnSubtitlePos) - ON_COMMAND_RANGE(ID_SUB_FONT_SIZE_DEC, ID_SUB_FONT_SIZE_INC, OnSubtitleFontSize) - - ON_COMMAND(ID_PLAY_PLAY, OnPlayPlay) - ON_COMMAND(ID_PLAY_PAUSE, OnPlayPause) - ON_COMMAND(ID_PLAY_PLAYPAUSE, OnPlayPlaypause) - ON_COMMAND(ID_PLAY_STOP, OnPlayStop) - ON_UPDATE_COMMAND_UI(ID_PLAY_PLAY, OnUpdatePlayPauseStop) - ON_UPDATE_COMMAND_UI(ID_PLAY_PAUSE, OnUpdatePlayPauseStop) - ON_UPDATE_COMMAND_UI(ID_PLAY_PLAYPAUSE, OnUpdatePlayPauseStop) - ON_UPDATE_COMMAND_UI(ID_PLAY_STOP, OnUpdatePlayPauseStop) - ON_COMMAND_RANGE(ID_PLAY_FRAMESTEP, ID_PLAY_FRAMESTEP_BACK, OnPlayFramestep) - ON_UPDATE_COMMAND_UI(ID_PLAY_FRAMESTEP, OnUpdatePlayFramestep) - ON_COMMAND_RANGE(ID_PLAY_SEEKBACKWARDSMALL, ID_PLAY_SEEKFORWARDLARGE, OnPlaySeek) - ON_COMMAND(ID_PLAY_SEEKSET, OnPlaySeekSet) - ON_COMMAND_RANGE(ID_PLAY_SEEKKEYBACKWARD, ID_PLAY_SEEKKEYFORWARD, OnPlaySeekKey) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_SEEKBACKWARDSMALL, ID_PLAY_SEEKFORWARDLARGE, OnUpdatePlaySeek) - ON_UPDATE_COMMAND_UI(ID_PLAY_SEEKSET, OnUpdatePlaySeek) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_SEEKKEYBACKWARD, ID_PLAY_SEEKKEYFORWARD, OnUpdatePlaySeek) - ON_COMMAND_RANGE(ID_PLAY_DECRATE, ID_PLAY_INCRATE, OnPlayChangeRate) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_DECRATE, ID_PLAY_INCRATE, OnUpdatePlayChangeRate) - ON_COMMAND_RANGE(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, OnPlayChangeRate) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, OnUpdatePlayChangeRate) - ON_COMMAND(ID_PLAY_RESETRATE, OnPlayResetRate) - ON_UPDATE_COMMAND_UI(ID_PLAY_RESETRATE, OnUpdatePlayResetRate) - ON_COMMAND_RANGE(ID_PLAY_INCAUDDELAY, ID_PLAY_DECAUDDELAY, OnPlayChangeAudDelay) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_INCAUDDELAY, ID_PLAY_DECAUDDELAY, OnUpdatePlayChangeAudDelay) - ON_COMMAND(ID_FILTERS_COPY_TO_CLIPBOARD, OnPlayFiltersCopyToClipboard) - ON_COMMAND_RANGE(ID_FILTERS_SUBITEM_START, ID_FILTERS_SUBITEM_END, OnPlayFilters) - ON_UPDATE_COMMAND_UI_RANGE(ID_FILTERS_SUBITEM_START, ID_FILTERS_SUBITEM_END, OnUpdatePlayFilters) - ON_COMMAND(ID_SHADERS_SELECT, OnPlayShadersSelect) - ON_COMMAND(ID_SHADERS_PRESET_NEXT, OnPlayShadersPresetNext) - ON_COMMAND(ID_SHADERS_PRESET_PREV, OnPlayShadersPresetPrev) - ON_COMMAND_RANGE(ID_SHADERS_PRESETS_START, ID_SHADERS_PRESETS_END, OnPlayShadersPresets) - ON_COMMAND_RANGE(ID_AUDIO_SUBITEM_START, ID_AUDIO_SUBITEM_END, OnPlayAudio) - ON_COMMAND_RANGE(ID_SUBTITLES_SUBITEM_START, ID_SUBTITLES_SUBITEM_END, OnPlaySubtitles) - ON_COMMAND(ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE, OnSubtitlesDefaultStyle) - ON_COMMAND_RANGE(ID_VIDEO_STREAMS_SUBITEM_START, ID_VIDEO_STREAMS_SUBITEM_END, OnPlayVideoStreams) - ON_COMMAND_RANGE(ID_FILTERSTREAMS_SUBITEM_START, ID_FILTERSTREAMS_SUBITEM_END, OnPlayFiltersStreams) - ON_COMMAND_RANGE(ID_VOLUME_UP, ID_VOLUME_MUTE, OnPlayVolume) - ON_COMMAND_RANGE(ID_VOLUME_BOOST_INC, ID_VOLUME_BOOST_MAX, OnPlayVolumeBoost) - ON_UPDATE_COMMAND_UI_RANGE(ID_VOLUME_BOOST_INC, ID_VOLUME_BOOST_MAX, OnUpdatePlayVolumeBoost) - ON_COMMAND(ID_CUSTOM_CHANNEL_MAPPING, OnCustomChannelMapping) - ON_UPDATE_COMMAND_UI(ID_CUSTOM_CHANNEL_MAPPING, OnUpdateCustomChannelMapping) - ON_COMMAND_RANGE(ID_NORMALIZE, ID_REGAIN_VOLUME, OnNormalizeRegainVolume) - ON_UPDATE_COMMAND_UI_RANGE(ID_NORMALIZE, ID_REGAIN_VOLUME, OnUpdateNormalizeRegainVolume) - ON_COMMAND_RANGE(ID_COLOR_BRIGHTNESS_INC, ID_COLOR_RESET, OnPlayColor) - ON_UPDATE_COMMAND_UI_RANGE(ID_AFTERPLAYBACK_EXIT, ID_AFTERPLAYBACK_MONITOROFF, OnUpdateAfterplayback) - ON_COMMAND_RANGE(ID_AFTERPLAYBACK_EXIT, ID_AFTERPLAYBACK_MONITOROFF, OnAfterplayback) - ON_UPDATE_COMMAND_UI_RANGE(ID_AFTERPLAYBACK_PLAYNEXT, ID_AFTERPLAYBACK_DONOTHING, OnUpdateAfterplayback) - ON_COMMAND_RANGE(ID_AFTERPLAYBACK_PLAYNEXT, ID_AFTERPLAYBACK_DONOTHING, OnAfterplayback) - ON_COMMAND_RANGE(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, OnPlayRepeat) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, OnUpdatePlayRepeat) - ON_COMMAND_RANGE(ID_PLAY_REPEAT_AB, ID_PLAY_REPEAT_AB_MARK_B, OnABRepeat) - ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_REPEAT_AB, ID_PLAY_REPEAT_AB_MARK_B, OnUpdateABRepeat) - ON_COMMAND(ID_PLAY_REPEAT_FOREVER, OnPlayRepeatForever) - ON_UPDATE_COMMAND_UI(ID_PLAY_REPEAT_FOREVER, OnUpdatePlayRepeatForever) - - ON_COMMAND_RANGE(ID_NAVIGATE_SKIPBACK, ID_NAVIGATE_SKIPFORWARD, OnNavigateSkip) - ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_SKIPBACK, ID_NAVIGATE_SKIPFORWARD, OnUpdateNavigateSkip) - ON_COMMAND_RANGE(ID_NAVIGATE_SKIPBACKFILE, ID_NAVIGATE_SKIPFORWARDFILE, OnNavigateSkipFile) - ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_SKIPBACKFILE, ID_NAVIGATE_SKIPFORWARDFILE, OnUpdateNavigateSkipFile) - ON_COMMAND(ID_NAVIGATE_GOTO, OnNavigateGoto) - ON_UPDATE_COMMAND_UI(ID_NAVIGATE_GOTO, OnUpdateNavigateGoto) - ON_COMMAND_RANGE(ID_NAVIGATE_TITLEMENU, ID_NAVIGATE_CHAPTERMENU, OnNavigateMenu) - ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_TITLEMENU, ID_NAVIGATE_CHAPTERMENU, OnUpdateNavigateMenu) - ON_COMMAND_RANGE(ID_NAVIGATE_JUMPTO_SUBITEM_START, ID_NAVIGATE_JUMPTO_SUBITEM_END, OnNavigateJumpTo) - ON_COMMAND_RANGE(ID_NAVIGATE_MENU_LEFT, ID_NAVIGATE_MENU_LEAVE, OnNavigateMenuItem) - ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_MENU_LEFT, ID_NAVIGATE_MENU_LEAVE, OnUpdateNavigateMenuItem) - - ON_COMMAND(ID_NAVIGATE_TUNERSCAN, OnTunerScan) - ON_UPDATE_COMMAND_UI(ID_NAVIGATE_TUNERSCAN, OnUpdateTunerScan) - - ON_COMMAND(ID_FAVORITES_ADD, OnFavoritesAdd) - ON_UPDATE_COMMAND_UI(ID_FAVORITES_ADD, OnUpdateFavoritesAdd) - ON_COMMAND(ID_FAVORITES_QUICKADDFAVORITE, OnFavoritesQuickAddFavorite) - ON_COMMAND(ID_FAVORITES_ORGANIZE, OnFavoritesOrganize) - ON_UPDATE_COMMAND_UI(ID_FAVORITES_ORGANIZE, OnUpdateFavoritesOrganize) - ON_COMMAND_RANGE(ID_FAVORITES_FILE_START, ID_FAVORITES_FILE_END, OnFavoritesFile) - ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_FILE_START, ID_FAVORITES_FILE_END, OnUpdateFavoritesFile) - ON_COMMAND_RANGE(ID_FAVORITES_DVD_START, ID_FAVORITES_DVD_END, OnFavoritesDVD) - ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_DVD_START, ID_FAVORITES_DVD_END, OnUpdateFavoritesDVD) - ON_COMMAND_RANGE(ID_FAVORITES_DEVICE_START, ID_FAVORITES_DEVICE_END, OnFavoritesDevice) - ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_DEVICE_START, ID_FAVORITES_DEVICE_END, OnUpdateFavoritesDevice) - - ON_COMMAND(ID_RECENT_FILES_CLEAR, OnRecentFileClear) - ON_UPDATE_COMMAND_UI(ID_RECENT_FILES_CLEAR, OnUpdateRecentFileClear) - ON_COMMAND_RANGE(ID_RECENT_FILE_START, ID_RECENT_FILE_END, OnRecentFile) - ON_UPDATE_COMMAND_UI_RANGE(ID_RECENT_FILE_START, ID_RECENT_FILE_END, OnUpdateRecentFile) - - ON_COMMAND(ID_HELP_HOMEPAGE, OnHelpHomepage) - ON_COMMAND(ID_HELP_CHECKFORUPDATE, OnHelpCheckForUpdate) - ON_COMMAND(ID_HELP_TOOLBARIMAGES, OnHelpToolbarImages) - ON_COMMAND(ID_HELP_DONATE, OnHelpDonate) - - // Open Dir incl. SubDir - ON_COMMAND(ID_FILE_OPENDIRECTORY, OnFileOpendirectory) - ON_UPDATE_COMMAND_UI(ID_FILE_OPENDIRECTORY, OnUpdateFileOpen) - ON_WM_POWERBROADCAST() - - // Navigation panel - ON_COMMAND(ID_VIEW_NAVIGATION, OnViewNavigation) - ON_UPDATE_COMMAND_UI(ID_VIEW_NAVIGATION, OnUpdateViewNavigation) - - ON_WM_WTSSESSION_CHANGE() - - ON_MESSAGE(WM_LOADSUBTITLES, OnLoadSubtitles) - ON_MESSAGE(WM_GETSUBTITLES, OnGetSubtitles) - ON_WM_DRAWITEM() - ON_WM_SETTINGCHANGE() - ON_WM_MOUSEHWHEEL() -END_MESSAGE_MAP() - -#ifdef _DEBUG -const TCHAR* GetEventString(LONG evCode) -{ -#define UNPACK_VALUE(VALUE) case VALUE: return _T(#VALUE); - switch (evCode) { - // System-defined event codes - UNPACK_VALUE(EC_COMPLETE); - UNPACK_VALUE(EC_USERABORT); - UNPACK_VALUE(EC_ERRORABORT); - //UNPACK_VALUE(EC_TIME); - UNPACK_VALUE(EC_REPAINT); - UNPACK_VALUE(EC_STREAM_ERROR_STOPPED); - UNPACK_VALUE(EC_STREAM_ERROR_STILLPLAYING); - UNPACK_VALUE(EC_ERROR_STILLPLAYING); - UNPACK_VALUE(EC_PALETTE_CHANGED); - UNPACK_VALUE(EC_VIDEO_SIZE_CHANGED); - UNPACK_VALUE(EC_QUALITY_CHANGE); - UNPACK_VALUE(EC_SHUTTING_DOWN); - UNPACK_VALUE(EC_CLOCK_CHANGED); - UNPACK_VALUE(EC_PAUSED); - UNPACK_VALUE(EC_OPENING_FILE); - UNPACK_VALUE(EC_BUFFERING_DATA); - UNPACK_VALUE(EC_FULLSCREEN_LOST); - UNPACK_VALUE(EC_ACTIVATE); - UNPACK_VALUE(EC_NEED_RESTART); - UNPACK_VALUE(EC_WINDOW_DESTROYED); - UNPACK_VALUE(EC_DISPLAY_CHANGED); - UNPACK_VALUE(EC_STARVATION); - UNPACK_VALUE(EC_OLE_EVENT); - UNPACK_VALUE(EC_NOTIFY_WINDOW); - UNPACK_VALUE(EC_STREAM_CONTROL_STOPPED); - UNPACK_VALUE(EC_STREAM_CONTROL_STARTED); - UNPACK_VALUE(EC_END_OF_SEGMENT); - UNPACK_VALUE(EC_SEGMENT_STARTED); - UNPACK_VALUE(EC_LENGTH_CHANGED); - UNPACK_VALUE(EC_DEVICE_LOST); - UNPACK_VALUE(EC_SAMPLE_NEEDED); - UNPACK_VALUE(EC_PROCESSING_LATENCY); - UNPACK_VALUE(EC_SAMPLE_LATENCY); - UNPACK_VALUE(EC_SCRUB_TIME); - UNPACK_VALUE(EC_STEP_COMPLETE); - UNPACK_VALUE(EC_TIMECODE_AVAILABLE); - UNPACK_VALUE(EC_EXTDEVICE_MODE_CHANGE); - UNPACK_VALUE(EC_STATE_CHANGE); - UNPACK_VALUE(EC_GRAPH_CHANGED); - UNPACK_VALUE(EC_CLOCK_UNSET); - UNPACK_VALUE(EC_VMR_RENDERDEVICE_SET); - UNPACK_VALUE(EC_VMR_SURFACE_FLIPPED); - UNPACK_VALUE(EC_VMR_RECONNECTION_FAILED); - UNPACK_VALUE(EC_PREPROCESS_COMPLETE); - UNPACK_VALUE(EC_CODECAPI_EVENT); - UNPACK_VALUE(EC_WMT_INDEX_EVENT); - UNPACK_VALUE(EC_WMT_EVENT); - UNPACK_VALUE(EC_BUILT); - UNPACK_VALUE(EC_UNBUILT); - UNPACK_VALUE(EC_SKIP_FRAMES); - UNPACK_VALUE(EC_PLEASE_REOPEN); - UNPACK_VALUE(EC_STATUS); - UNPACK_VALUE(EC_MARKER_HIT); - UNPACK_VALUE(EC_LOADSTATUS); - UNPACK_VALUE(EC_FILE_CLOSED); - UNPACK_VALUE(EC_ERRORABORTEX); - //UNPACK_VALUE(EC_NEW_PIN); - //UNPACK_VALUE(EC_RENDER_FINISHED); - UNPACK_VALUE(EC_EOS_SOON); - UNPACK_VALUE(EC_CONTENTPROPERTY_CHANGED); - UNPACK_VALUE(EC_BANDWIDTHCHANGE); - UNPACK_VALUE(EC_VIDEOFRAMEREADY); - // DVD-Video event codes - UNPACK_VALUE(EC_DVD_DOMAIN_CHANGE); - UNPACK_VALUE(EC_DVD_TITLE_CHANGE); - UNPACK_VALUE(EC_DVD_CHAPTER_START); - UNPACK_VALUE(EC_DVD_AUDIO_STREAM_CHANGE); - UNPACK_VALUE(EC_DVD_SUBPICTURE_STREAM_CHANGE); - UNPACK_VALUE(EC_DVD_ANGLE_CHANGE); - UNPACK_VALUE(EC_DVD_BUTTON_CHANGE); - UNPACK_VALUE(EC_DVD_VALID_UOPS_CHANGE); - UNPACK_VALUE(EC_DVD_STILL_ON); - UNPACK_VALUE(EC_DVD_STILL_OFF); - UNPACK_VALUE(EC_DVD_CURRENT_TIME); - UNPACK_VALUE(EC_DVD_ERROR); - UNPACK_VALUE(EC_DVD_WARNING); - UNPACK_VALUE(EC_DVD_CHAPTER_AUTOSTOP); - UNPACK_VALUE(EC_DVD_NO_FP_PGC); - UNPACK_VALUE(EC_DVD_PLAYBACK_RATE_CHANGE); - UNPACK_VALUE(EC_DVD_PARENTAL_LEVEL_CHANGE); - UNPACK_VALUE(EC_DVD_PLAYBACK_STOPPED); - UNPACK_VALUE(EC_DVD_ANGLES_AVAILABLE); - UNPACK_VALUE(EC_DVD_PLAYPERIOD_AUTOSTOP); - UNPACK_VALUE(EC_DVD_BUTTON_AUTO_ACTIVATED); - UNPACK_VALUE(EC_DVD_CMD_START); - UNPACK_VALUE(EC_DVD_CMD_END); - UNPACK_VALUE(EC_DVD_DISC_EJECTED); - UNPACK_VALUE(EC_DVD_DISC_INSERTED); - UNPACK_VALUE(EC_DVD_CURRENT_HMSF_TIME); - UNPACK_VALUE(EC_DVD_KARAOKE_MODE); - UNPACK_VALUE(EC_DVD_PROGRAM_CELL_CHANGE); - UNPACK_VALUE(EC_DVD_TITLE_SET_CHANGE); - UNPACK_VALUE(EC_DVD_PROGRAM_CHAIN_CHANGE); - UNPACK_VALUE(EC_DVD_VOBU_Offset); - UNPACK_VALUE(EC_DVD_VOBU_Timestamp); - UNPACK_VALUE(EC_DVD_GPRM_Change); - UNPACK_VALUE(EC_DVD_SPRM_Change); - UNPACK_VALUE(EC_DVD_BeginNavigationCommands); - UNPACK_VALUE(EC_DVD_NavigationCommand); - // Sound device error event codes - UNPACK_VALUE(EC_SNDDEV_IN_ERROR); - UNPACK_VALUE(EC_SNDDEV_OUT_ERROR); - // Custom event codes - UNPACK_VALUE(EC_BG_AUDIO_CHANGED); - UNPACK_VALUE(EC_BG_ERROR); - }; -#undef UNPACK_VALUE - return _T("UNKNOWN"); -} -#endif - -void CMainFrame::EventCallback(MpcEvent ev) -{ - const auto& s = AfxGetAppSettings(); - switch (ev) { - case MpcEvent::SHADER_SELECTION_CHANGED: - case MpcEvent::SHADER_PRERESIZE_SELECTION_CHANGED: - case MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED: - SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); - break; - case MpcEvent::DISPLAY_MODE_AUTOCHANGING: - if (GetLoadState() == MLS::LOADED && GetMediaState() == State_Running && s.autoChangeFSMode.uDelay) { - // pause if the mode is being changed during playback - OnPlayPause(); - m_bPausedForAutochangeMonitorMode = true; - } - break; - case MpcEvent::DISPLAY_MODE_AUTOCHANGED: - if (GetLoadState() == MLS::LOADED) { - if (m_bPausedForAutochangeMonitorMode && s.autoChangeFSMode.uDelay) { - // delay play if was paused due to mode change - ASSERT(GetMediaState() != State_Stopped); - const unsigned uModeChangeDelay = s.autoChangeFSMode.uDelay * 1000; - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, - std::bind(&CMainFrame::OnPlayPlay, this), uModeChangeDelay); - } else if (m_bDelaySetOutputRect) { - ASSERT(GetMediaState() == State_Stopped); - // tell OnFilePostOpenmedia() to delay entering play or paused state - m_bOpeningInAutochangedMonitorMode = true; - } - } - break; - case MpcEvent::CHANGING_UI_LANGUAGE: - UpdateUILanguage(); - break; - case MpcEvent::STREAM_POS_UPDATE_REQUEST: - OnTimer(TIMER_STREAMPOSPOLLER); - OnTimer(TIMER_STREAMPOSPOLLER2); - break; - default: - ASSERT(FALSE); - } -} - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame construction/destruction - -CMainFrame::CMainFrame() - : m_timerHider(this, TIMER_HIDER, 200) - , m_timerOneTime(this, TIMER_ONETIME_START, TIMER_ONETIME_END - TIMER_ONETIME_START + 1) - , m_bUsingDXVA(false) - , m_HWAccelType(nullptr) - , m_posFirstExtSub(nullptr) - , m_bDelaySetOutputRect(false) - , m_nJumpToSubMenusCount(0) - , m_nLoops(0) - , m_nLastSkipDirection(0) - , m_fCustomGraph(false) - , m_fShockwaveGraph(false) - , m_fFrameSteppingActive(false) - , m_nStepForwardCount(0) - , m_rtStepForwardStart(0) - , m_nVolumeBeforeFrameStepping(0) - , m_fEndOfStream(false) - , m_dwLastPause(0) - , m_dwReloadPos(0) - , m_iReloadAudioIdx(-1) - , m_iReloadSubIdx(-1) - , m_bRememberFilePos(false) - , m_dwLastRun(0) - , m_bBuffering(false) - , m_fLiveWM(false) - , m_rtDurationOverride(-1) - , m_iPlaybackMode(PM_NONE) - , m_lCurrentChapter(0) - , m_lChapterStartTime(0xFFFFFFFF) - , m_eMediaLoadState(MLS::CLOSED) - , m_CachedFilterState(-1) - , m_bSettingUpMenus(false) - , m_bOpenMediaActive(false) - , m_OpenMediaFailedCount(0) - , m_fFullScreen(false) - , m_bFullScreenWindowIsD3D(false) - , m_bFullScreenWindowIsOnSeparateDisplay(false) - , m_bNeedZoomAfterFullscreenExit(false) - , m_fStartInD3DFullscreen(false) - , m_fStartInFullscreenSeparate(false) - , m_pLastBar(nullptr) - , m_bFirstPlay(false) - , m_bOpeningInAutochangedMonitorMode(false) - , m_bPausedForAutochangeMonitorMode(false) - , m_fAudioOnly(true) - , m_iDVDDomain(DVD_DOMAIN_Stop) - , m_iDVDTitle(0) - , m_bDVDStillOn(false) - , m_dSpeedRate(1.0) - , m_ZoomX(1.0) - , m_ZoomY(1.0) - , m_PosX(0.5) - , m_PosY(0.5) - , m_AngleX(0) - , m_AngleY(0) - , m_AngleZ(0) - , m_iDefRotation(0) - , m_pGraphThread(nullptr) - , m_bOpenedThroughThread(false) - , m_evOpenPrivateFinished(FALSE, TRUE) - , m_evClosePrivateFinished(FALSE, TRUE) - , m_fOpeningAborted(false) - , m_bWasSnapped(false) - , m_wndSubtitlesDownloadDialog(this) - //, m_wndSubtitlesUploadDialog(this) - , m_wndFavoriteOrganizeDialog(this) - , m_bTrayIcon(false) - , m_fCapturing(false) - , m_controls(this) - , m_wndView(this) - , m_wndSeekBar(this) - , m_wndToolBar(this) - , m_wndInfoBar(this) - , m_wndStatsBar(this) - , m_wndStatusBar(this) - , m_wndSubresyncBar(this) - , m_wndPlaylistBar(this) - , m_wndPreView(this) - , m_wndCaptureBar(this) - , m_wndNavigationBar(this) - , m_pVideoWnd(nullptr) - , m_pOSDWnd(nullptr) - , m_pDedicatedFSVideoWnd(nullptr) - , m_OSD(this) - , m_nCurSubtitle(-1) - , m_lSubtitleShift(0) - , m_rtCurSubPos(0) - , m_bScanDlgOpened(false) - , m_bStopTunerScan(false) - , m_bLockedZoomVideoWindow(false) - , m_nLockedZoomVideoWindow(0) - , m_pActiveContextMenu(nullptr) - , m_pActiveSystemMenu(nullptr) - , m_bAltDownClean(false) - , m_bShowingFloatingMenubar(false) - , m_bAllowWindowZoom(false) - , m_dLastVideoScaleFactor(0) - , m_bExtOnTop(false) - , m_bIsBDPlay(false) - , m_bHasBDMeta(false) - , watchingDialog(themableDialogTypes::None) - , dialogHookHelper(nullptr) - , delayingFullScreen(false) - , restoringWindowRect(false) - , mediaTypesErrorDlg(nullptr) - , m_iStreamPosPollerInterval(100) - , currentAudioLang(_T("")) - , currentSubLang(_T("")) - , m_bToggleShader(false) - , m_bToggleShaderScreenSpace(false) - , m_MPLSPlaylist() - , m_sydlLastProcessURL() - , m_bUseSeekPreview(false) - , queuedSeek({0,0,false}) - , lastSeekStart(0) - , lastSeekFinish(0) - , defaultVideoAngle(0) - , m_media_trans_control() - , recentFilesMenuFromMRUSequence(-1) -{ - // Don't let CFrameWnd handle automatically the state of the menu items. - // This means that menu items without handlers won't be automatically - // disabled but it avoids some unwanted cases where programmatically - // disabled menu items are always re-enabled by CFrameWnd. - m_bAutoMenuEnable = FALSE; - - EventRouter::EventSelection receives; - receives.insert(MpcEvent::SHADER_SELECTION_CHANGED); - receives.insert(MpcEvent::SHADER_PRERESIZE_SELECTION_CHANGED); - receives.insert(MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED); - receives.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGING); - receives.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGED); - receives.insert(MpcEvent::CHANGING_UI_LANGUAGE); - receives.insert(MpcEvent::STREAM_POS_UPDATE_REQUEST); - EventRouter::EventSelection fires; - fires.insert(MpcEvent::SWITCHING_TO_FULLSCREEN); - fires.insert(MpcEvent::SWITCHED_TO_FULLSCREEN); - fires.insert(MpcEvent::SWITCHING_FROM_FULLSCREEN); - fires.insert(MpcEvent::SWITCHED_FROM_FULLSCREEN); - fires.insert(MpcEvent::SWITCHING_TO_FULLSCREEN_D3D); - fires.insert(MpcEvent::SWITCHED_TO_FULLSCREEN_D3D); - fires.insert(MpcEvent::MEDIA_LOADED); - fires.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGING); - fires.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGED); - fires.insert(MpcEvent::CONTEXT_MENU_POPUP_INITIALIZED); - fires.insert(MpcEvent::CONTEXT_MENU_POPUP_UNINITIALIZED); - fires.insert(MpcEvent::SYSTEM_MENU_POPUP_INITIALIZED); - fires.insert(MpcEvent::SYSTEM_MENU_POPUP_UNINITIALIZED); - fires.insert(MpcEvent::DPI_CHANGED); - GetEventd().Connect(m_eventc, receives, std::bind(&CMainFrame::EventCallback, this, std::placeholders::_1), fires); -} - -CMainFrame::~CMainFrame() -{ - if (defaultMPCThemeMenu != nullptr) { - delete defaultMPCThemeMenu; - } -} - -int CMainFrame::OnNcCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (IsWindows10OrGreater()) { - // Tell Windows to automatically handle scaling of non-client areas - // such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10 - const WinapiFunc - fnEnableNonClientDpiScaling = { _T("User32.dll"), "EnableNonClientDpiScaling" }; - - if (fnEnableNonClientDpiScaling) { - fnEnableNonClientDpiScaling(m_hWnd); - } - } - - return __super::OnNcCreate(lpCreateStruct); -} - -int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (__super::OnCreate(lpCreateStruct) == -1) { - return -1; - } - - CMPCThemeUtil::enableWindows10DarkFrame(this); - - if (IsWindows8Point1OrGreater()) { - m_dpi.Override(m_hWnd); - } - - const WinapiFunc - fnChangeWindowMessageFilterEx = { _T("user32.dll"), "ChangeWindowMessageFilterEx" }; - - // allow taskbar messages through UIPI - if (fnChangeWindowMessageFilterEx) { - VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, s_uTaskbarRestart, MSGFLT_ALLOW, nullptr)); - VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, s_uTBBC, MSGFLT_ALLOW, nullptr)); - VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, WM_COMMAND, MSGFLT_ALLOW, nullptr)); - } - - VERIFY(m_popupMenu.LoadMenu(IDR_POPUP)); - VERIFY(m_mainPopupMenu.LoadMenu(IDR_POPUPMAIN)); - CreateDynamicMenus(); - - // 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); - - const CAppSettings& s = AfxGetAppSettings(); - - // Create OSD Window - CreateOSDBar(); - - // Create Preview Window - if (s.fSeekPreview) { - if (m_wndPreView.CreateEx(0, AfxRegisterWndClass(0), nullptr, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CRect(0, 0, 160, 109), this, 0)) { - m_wndPreView.ShowWindow(SW_HIDE); - m_wndPreView.SetRelativeSize(AfxGetAppSettings().iSeekPreviewSize); - } else { - TRACE(_T("Failed to create Preview Window")); - } - } - - // 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 - } - - m_pDedicatedFSVideoWnd = DEBUG_NEW CFullscreenWnd(this); - - m_controls.m_toolbars[CMainFrameControls::Toolbar::SEEKBAR] = &m_wndSeekBar; - m_controls.m_toolbars[CMainFrameControls::Toolbar::CONTROLS] = &m_wndToolBar; - m_controls.m_toolbars[CMainFrameControls::Toolbar::INFO] = &m_wndInfoBar; - m_controls.m_toolbars[CMainFrameControls::Toolbar::STATS] = &m_wndStatsBar; - m_controls.m_toolbars[CMainFrameControls::Toolbar::STATUS] = &m_wndStatusBar; - - // dockable bars - - EnableDocking(CBRS_ALIGN_ANY); - - bResult = m_wndSubresyncBar.Create(this, AFX_IDW_DOCKBAR_TOP, &m_csSubLock); - if (bResult) { - m_wndSubresyncBar.SetBarStyle(m_wndSubresyncBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndSubresyncBar.EnableDocking(CBRS_ALIGN_ANY); - m_wndSubresyncBar.SetHeight(200); - m_controls.m_panels[CMainFrameControls::Panel::SUBRESYNC] = &m_wndSubresyncBar; - } - bResult = bResult && m_wndPlaylistBar.Create(this, AFX_IDW_DOCKBAR_RIGHT); - if (bResult) { - m_wndPlaylistBar.SetBarStyle(m_wndPlaylistBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndPlaylistBar.EnableDocking(CBRS_ALIGN_ANY); - m_wndPlaylistBar.SetWidth(300); - m_controls.m_panels[CMainFrameControls::Panel::PLAYLIST] = &m_wndPlaylistBar; - //m_wndPlaylistBar.LoadPlaylist(GetRecentFile()); //adipose 2019-11-12; do this later after activating the frame - } - bResult = bResult && m_wndEditListEditor.Create(this, AFX_IDW_DOCKBAR_RIGHT); - if (bResult) { - m_wndEditListEditor.SetBarStyle(m_wndEditListEditor.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndEditListEditor.EnableDocking(CBRS_ALIGN_ANY); - m_controls.m_panels[CMainFrameControls::Panel::EDL] = &m_wndEditListEditor; - m_wndEditListEditor.SetHeight(100); - } - bResult = bResult && m_wndCaptureBar.Create(this, AFX_IDW_DOCKBAR_LEFT); - if (bResult) { - m_wndCaptureBar.SetBarStyle(m_wndCaptureBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndCaptureBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); - m_controls.m_panels[CMainFrameControls::Panel::CAPTURE] = &m_wndCaptureBar; - } - bResult = bResult && m_wndNavigationBar.Create(this, AFX_IDW_DOCKBAR_LEFT); - if (bResult) { - m_wndNavigationBar.SetBarStyle(m_wndNavigationBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); - m_wndNavigationBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); - m_controls.m_panels[CMainFrameControls::Panel::NAVIGATION] = &m_wndNavigationBar; - } - if (!bResult) { - TRACE(_T("Failed to create all dockable bars\n")); - return -1; - } - - // Hide all controls initially - for (const auto& pair : m_controls.m_toolbars) { - pair.second->ShowWindow(SW_HIDE); - } - for (const auto& pair : m_controls.m_panels) { - pair.second->ShowWindow(SW_HIDE); - } - - m_dropTarget.Register(this); - - SetAlwaysOnTop(s.iOnTop); - - ShowTrayIcon(s.fTrayIcon); - - m_Lcd.SetVolumeRange(0, 100); - m_Lcd.SetVolume(std::max(1, s.nVolume)); - - m_pGraphThread = (CGraphThread*)AfxBeginThread(RUNTIME_CLASS(CGraphThread)); - - if (m_pGraphThread) { - m_pGraphThread->SetMainFrame(this); - } - - m_pSubtitlesProviders = std::make_unique(this); - m_wndSubtitlesDownloadDialog.Create(m_wndSubtitlesDownloadDialog.IDD, this, false); - //m_wndSubtitlesUploadDialog.Create(m_wndSubtitlesUploadDialog.IDD, this); - m_wndFavoriteOrganizeDialog.Create(m_wndFavoriteOrganizeDialog.IDD, this, false); - - if (s.nCmdlnWebServerPort != 0) { - if (s.nCmdlnWebServerPort > 0) { - StartWebServer(s.nCmdlnWebServerPort); - } else if (s.fEnableWebServer) { - StartWebServer(s.nWebServerPort); - } - } - - m_bToggleShader = s.bToggleShader; - m_bToggleShaderScreenSpace = s.bToggleShaderScreenSpace; - OpenSetupWindowTitle(true); - - WTSRegisterSessionNotification(); - - UpdateSkypeHandler(); - - m_popupMenu.fulfillThemeReqs(); - m_mainPopupMenu.fulfillThemeReqs(); - - if (s.bUseSMTC) { - m_media_trans_control.Init(this); - } - - return 0; -} - -void CMainFrame::CreateOSDBar() { - if (SUCCEEDED(m_OSD.Create(&m_wndView))) { - m_pOSDWnd = &m_wndView; - } -} - -bool CMainFrame::OSDBarSetPos() { - if (!m_OSD || !(::IsWindow(m_OSD.GetSafeHwnd())) || m_OSD.GetOSDType() != OSD_TYPE_GDI) { - return false; - } - const CAppSettings& s = AfxGetAppSettings(); - - if (s.iDSVideoRendererType == VIDRNDT_DS_MADVR || !m_wndView.IsWindowVisible()) { - if (m_OSD.IsWindowVisible()) { - m_OSD.ShowWindow(SW_HIDE); - } - return false; - } - - CRect r_wndView; - m_wndView.GetWindowRect(&r_wndView); - - int pos = 0; - - CRect MainWndRect; - m_wndView.GetWindowRect(&MainWndRect); - MainWndRect.right -= pos; - m_OSD.SetWndRect(MainWndRect); - if (m_OSD.IsWindowVisible()) { - ::PostMessageW(m_OSD.m_hWnd, WM_OSD_DRAW, WPARAM(0), LPARAM(0)); - } - - return false; -} - -void CMainFrame::DestroyOSDBar() { - if (m_OSD) { - m_OSD.Stop(); - m_OSD.DestroyWindow(); - } -} - -void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) -{ - if (lpMeasureItemStruct->CtlType == ODT_MENU) { - if (CMPCThemeMenu* cm = CMPCThemeMenu::getParentMenu(lpMeasureItemStruct->itemID)) { - cm->MeasureItem(lpMeasureItemStruct); - return; - } - } - - CFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct); -} - -void CMainFrame::OnDestroy() -{ - WTSUnRegisterSessionNotification(); - ShowTrayIcon(false); - m_dropTarget.Revoke(); - - if (m_pDebugShaders && IsWindow(m_pDebugShaders->m_hWnd)) { - VERIFY(m_pDebugShaders->DestroyWindow()); - } - - if (m_pGraphThread) { - CAMMsgEvent e; - m_pGraphThread->PostThreadMessage(CGraphThread::TM_EXIT, (WPARAM)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_ERROR); - } - } - - if (m_pDedicatedFSVideoWnd) { - if (m_pDedicatedFSVideoWnd->IsWindow()) { - m_pDedicatedFSVideoWnd->DestroyWindow(); - } - delete m_pDedicatedFSVideoWnd; - } - - m_wndPreView.DestroyWindow(); - - __super::OnDestroy(); -} - -void CMainFrame::OnClose() -{ - CAppSettings& s = AfxGetAppSettings(); - - s.bToggleShader = m_bToggleShader; - s.bToggleShaderScreenSpace = m_bToggleShaderScreenSpace; - s.dZoomX = m_ZoomX; - s.dZoomY = m_ZoomY; - - m_wndPlaylistBar.SavePlaylist(); - - m_controls.SaveState(); - - m_OSD.OnHide(); - - ShowWindow(SW_HIDE); - - if (GetLoadState() == MLS::LOADED || GetLoadState() == MLS::LOADING) { - CloseMedia(); - } - - m_wndPlaylistBar.ClearExternalPlaylistIfInvalid(); - - 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 - - AfxGetMyApp()->SetClosingState(); - - __super::OnClose(); -} - -LPCTSTR CMainFrame::GetRecentFile() const -{ - auto& MRU = AfxGetAppSettings().MRU; - MRU.ReadMediaHistory(); - for (int i = 0; i < MRU.GetSize(); i++) { - if (MRU[i].fns.GetCount() > 0 && !MRU[i].fns.GetHead().IsEmpty()) { - return MRU[i].fns.GetHead(); - } - } - return nullptr; -} - -LRESULT CMainFrame::OnTaskBarRestart(WPARAM, LPARAM) -{ - m_bTrayIcon = false; - ShowTrayIcon(AfxGetAppSettings().fTrayIcon); - return 0; -} - -LRESULT CMainFrame::OnNotifyIcon(WPARAM wParam, LPARAM lParam) -{ - if (HIWORD(lParam) != IDR_MAINFRAME) { - return -1; - } - - switch (LOWORD(lParam)) { - case WM_LBUTTONDOWN: - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - CreateThumbnailToolbar(); - MoveVideoWindow(); - SetForegroundWindow(); - break; - case WM_LBUTTONDBLCLK: - PostMessage(WM_COMMAND, ID_FILE_OPENMEDIA); - break; - case WM_RBUTTONDOWN: - case WM_CONTEXTMENU: { - SetForegroundWindow(); - m_mainPopupMenu.GetSubMenu(0)->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NOANIMATION, - GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam), GetModalParent()); - PostMessage(WM_NULL); - break; - } - case WM_MBUTTONDOWN: { - OnPlayPlaypause(); - break; - } - case WM_MOUSEMOVE: { - CString str; - GetWindowText(str); - SetTrayTip(str); - break; - } - default: - break; - } - - return 0; -} - -LRESULT CMainFrame::OnTaskBarThumbnailsCreate(WPARAM, LPARAM) -{ - return CreateThumbnailToolbar(); -} - -LRESULT CMainFrame::OnSkypeAttach(WPARAM wParam, LPARAM lParam) -{ - return m_pSkypeMoodMsgHandler ? m_pSkypeMoodMsgHandler->HandleAttach(wParam, lParam) : FALSE; -} - -void CMainFrame::ShowTrayIcon(bool bShow) -{ - NOTIFYICONDATA nid = { sizeof(nid), m_hWnd, IDR_MAINFRAME }; - - if (bShow) { - if (!m_bTrayIcon) { - nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; - nid.uCallbackMessage = WM_NOTIFYICON; - nid.uVersion = NOTIFYICON_VERSION_4; - nid.hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), - IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); - StringCchCopy(nid.szTip, _countof(nid.szTip), _T("MPC-HC")); - if (Shell_NotifyIcon(NIM_ADD, &nid) && Shell_NotifyIcon(NIM_SETVERSION, &nid)) { - m_bTrayIcon = true; - } - } - } else { - if (m_bTrayIcon) { - Shell_NotifyIcon(NIM_DELETE, &nid); - m_bTrayIcon = false; - if (IsIconic()) { - // if the window was minimized to tray - show it - ShowWindow(SW_RESTORE); - } - } - } -} - -void CMainFrame::SetTrayTip(const CString& str) -{ - NOTIFYICONDATA tnid; - tnid.cbSize = sizeof(NOTIFYICONDATA); - tnid.hWnd = m_hWnd; - tnid.uID = IDR_MAINFRAME; - tnid.uFlags = NIF_TIP | NIF_SHOWTIP; - StringCchCopy(tnid.szTip, _countof(tnid.szTip), str); - Shell_NotifyIcon(NIM_MODIFY, &tnid); -} - -BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) -{ - if (!__super::PreCreateWindow(cs)) { - return FALSE; - } - - cs.dwExStyle &= ~WS_EX_CLIENTEDGE; - cs.lpszClass = MPC_WND_CLASS_NAME; //AfxRegisterWndClass(nullptr); - - return TRUE; -} - -BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message == WM_KEYDOWN) { - if (pMsg->wParam == VK_ESCAPE) { - bool fEscapeNotAssigned = !AssignedToCmd(VK_ESCAPE); - - if (fEscapeNotAssigned) { - if (IsFullScreenMode()) { - OnViewFullscreen(); - if (GetLoadState() == MLS::LOADED) { - PostMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - return TRUE; - } else if (IsCaptionHidden()) { - PostMessage(WM_COMMAND, ID_VIEW_PRESETS_NORMAL); - return TRUE; - } - } - } else if (pMsg->wParam == VK_LEFT && m_pAMTuner) { - PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACK); - return TRUE; - } else if (pMsg->wParam == VK_RIGHT && m_pAMTuner) { - PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); - return TRUE; - } - } - - if ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_F10 && - m_dwMenuBarState == AFX_MBS_VISIBLE) { - // mfc doesn't hide menubar on f10, but we want to - VERIFY(SetMenuBarState(AFX_MBS_HIDDEN)); - return FALSE; - } - - if (pMsg->message == WM_KEYDOWN) { - m_bAltDownClean = false; - } - if (pMsg->message == WM_SYSKEYDOWN) { - m_bAltDownClean = (pMsg->wParam == VK_MENU); - } - if ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_MENU && - m_dwMenuBarState == AFX_MBS_HIDDEN) { - // mfc shows menubar when Ctrl->Alt->K is released in reverse order, but we don't want to - if (m_bAltDownClean) { - VERIFY(SetMenuBarState(AFX_MBS_VISIBLE)); - return FALSE; - } - return TRUE; - } - - // for compatibility with KatMouse and the like - if (pMsg->message == WM_MOUSEWHEEL && pMsg->hwnd == m_hWnd) { - pMsg->hwnd = m_wndView.m_hWnd; - return FALSE; - } - - return __super::PreTranslateMessage(pMsg); -} - -void CMainFrame::RecalcLayout(BOOL bNotify) -{ - __super::RecalcLayout(bNotify); - - CRect r; - GetWindowRect(&r); - MINMAXINFO mmi; - ZeroMemory(&mmi, sizeof(mmi)); - OnGetMinMaxInfo(&mmi); - const POINT& min = mmi.ptMinTrackSize; - if (r.Height() < min.y || r.Width() < min.x) { - r |= CRect(r.TopLeft(), CSize(min)); - MoveWindow(r); - } - OSDBarSetPos(); -} - -void CMainFrame::EnableDocking(DWORD dwDockStyle) -{ - ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY | CBRS_FLOAT_MULTI)) == 0); - - m_pFloatingFrameClass = RUNTIME_CLASS(CMPCThemeMiniDockFrameWnd); - for (int i = 0; i < 4; i++) { - if (dwDockBarMap[i][1] & dwDockStyle & CBRS_ALIGN_ANY) { - CMPCThemeDockBar* pDock = (CMPCThemeDockBar*)GetControlBar(dwDockBarMap[i][0]); - if (pDock == NULL) { - pDock = DEBUG_NEW CMPCThemeDockBar; - if (!pDock->Create(this, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD | WS_VISIBLE | - dwDockBarMap[i][1], dwDockBarMap[i][0])) { - AfxThrowResourceException(); - } - } - } - } -} - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame diagnostics - -#ifdef _DEBUG -void CMainFrame::AssertValid() const -{ - __super::AssertValid(); -} - -void CMainFrame::Dump(CDumpContext& dc) const -{ - __super::Dump(dc); -} - -#endif //_DEBUG - -typedef HIMC(WINAPI* pfnImmAssociateContext)(HWND, HIMC); -void dynImmAssociateContext(HWND hWnd, HIMC himc) { - HMODULE hImm32; - pfnImmAssociateContext pImmAssociateContext; - - hImm32 = LoadLibrary(_T("imm32.dll")); - if (NULL == hImm32) return; // No East Asian support - pImmAssociateContext = (pfnImmAssociateContext)GetProcAddress(hImm32, "ImmAssociateContext"); - if (NULL == pImmAssociateContext) { - FreeLibrary(hImm32); - return; - } - pImmAssociateContext(hWnd, himc); - FreeLibrary(hImm32); -} - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame message handlers -void CMainFrame::OnSetFocus(CWnd* pOldWnd) -{ - // forward focus to the view window - if (IsWindow(m_wndView.m_hWnd)) { - m_wndView.SetFocus(); - dynImmAssociateContext(m_wndView.m_hWnd, NULL); - } else { - dynImmAssociateContext(m_hWnd, NULL); - } -} - -BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) -{ - // let the view have first crack at the command - if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { - return TRUE; - } - - for (const auto& pair : m_controls.m_toolbars) { - if (pair.second->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { - return TRUE; - } - } - - for (const auto& pair : m_controls.m_panels) { - if (pair.second->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { - return TRUE; - } - } - - // otherwise, do default handling - return __super::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); -} - -void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI) -{ - auto setLarger = [](long & a, long b) { - a = std::max(a, b); - }; - - const long saneSize = 110; - const bool bMenuVisible = GetMenuBarVisibility() == AFX_MBV_KEEPVISIBLE || m_bShowingFloatingMenubar; - - // Begin with docked controls - lpMMI->ptMinTrackSize = CPoint(m_controls.GetDockZonesMinSize(saneSize)); - - if (bMenuVisible) { - // Ensure that menubar will fit horizontally - MENUBARINFO mbi = { sizeof(mbi) }; - GetMenuBarInfo(OBJID_MENU, 0, &mbi); - long x = GetSystemMetrics(SM_CYMENU) / 2; // free space after menu - CRect rect; - for (int i = 0; GetMenuItemRect(m_hWnd, mbi.hMenu, i, &rect); i++) { - x += rect.Width(); - } - setLarger(lpMMI->ptMinTrackSize.x, x); - } - - if (IsWindow(m_wndToolBar) && m_controls.ControlChecked(CMainFrameControls::Toolbar::CONTROLS)) { - // Ensure that Controls toolbar will fit - setLarger(lpMMI->ptMinTrackSize.x, m_wndToolBar.GetMinWidth()); - } - - // Ensure that window decorations will fit - CRect decorationsRect; - VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), bMenuVisible, GetWindowExStyle(m_hWnd))); - lpMMI->ptMinTrackSize.x += decorationsRect.Width(); - lpMMI->ptMinTrackSize.y += decorationsRect.Height(); - - // Final fence - setLarger(lpMMI->ptMinTrackSize.x, GetSystemMetrics(SM_CXMIN)); - setLarger(lpMMI->ptMinTrackSize.y, GetSystemMetrics(SM_CYMIN)); - - lpMMI->ptMaxTrackSize.x = GetSystemMetrics(SM_CXVIRTUALSCREEN) + decorationsRect.Width(); - lpMMI->ptMaxTrackSize.y = GetSystemMetrics(SM_CYVIRTUALSCREEN) - + ((GetStyle() & WS_THICKFRAME) ? GetSystemMetrics(SM_CYSIZEFRAME) : 0); - - OSDBarSetPos(); -} - -void CMainFrame::OnMove(int x, int y) -{ - __super::OnMove(x, y); - - if (m_bWasSnapped && IsZoomed()) { - m_bWasSnapped = false; - } - - WINDOWPLACEMENT wp; - GetWindowPlacement(&wp); - if (!m_bNeedZoomAfterFullscreenExit && !m_fFullScreen && IsWindowVisible() && wp.flags != WPF_RESTORETOMAXIMIZED && wp.showCmd != SW_SHOWMINIMIZED) { - GetWindowRect(AfxGetAppSettings().rcLastWindowPos); - } - - OSDBarSetPos(); -} - -void CMainFrame::OnEnterSizeMove() -{ - if (m_bWasSnapped) { - VERIFY(GetCursorPos(&m_snapStartPoint)); - GetWindowRect(m_snapStartRect); - } -} - -void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect) -{ - if (AfxGetAppSettings().fSnapToDesktopEdges) { - const CSize threshold(m_dpi.ScaleX(16), m_dpi.ScaleY(16)); - - CRect rect(pRect); - - CRect windowRect; - GetWindowRect(windowRect); - - if (windowRect.Size() != rect.Size()) { - // aero snap - return; - } - - CPoint point; - VERIFY(GetCursorPos(&point)); - - if (m_bWasSnapped) { - rect.MoveToXY(point - m_snapStartPoint + m_snapStartRect.TopLeft()); - } - - CRect areaRect; - CMonitors::GetNearestMonitor(this).GetWorkAreaRect(areaRect); - const CRect invisibleBorderSize = GetInvisibleBorderSize(); - areaRect.InflateRect(invisibleBorderSize); - - bool bSnapping = false; - - if (std::abs(rect.left - areaRect.left) < threshold.cx) { - bSnapping = true; - rect.MoveToX(areaRect.left); - } else if (std::abs(rect.right - areaRect.right) < threshold.cx) { - bSnapping = true; - rect.MoveToX(areaRect.right - rect.Width()); - } - if (std::abs(rect.top - areaRect.top) < threshold.cy) { - bSnapping = true; - rect.MoveToY(areaRect.top); - } else if (std::abs(rect.bottom - areaRect.bottom) < threshold.cy) { - bSnapping = true; - rect.MoveToY(areaRect.bottom - rect.Height()); - } - - if (!m_bWasSnapped && bSnapping) { - m_snapStartPoint = point; - m_snapStartRect = pRect; - } - - *pRect = rect; - - m_bWasSnapped = bSnapping; - } else { - m_bWasSnapped = false; - } - - __super::OnMoving(fwSide, pRect); - OSDBarSetPos(); -} - -void CMainFrame::OnSize(UINT nType, int cx, int cy) -{ - if (m_bTrayIcon && nType == SIZE_MINIMIZED) { - ShowWindow(SW_HIDE); - } else { - __super::OnSize(nType, cx, cy); - if (!m_bNeedZoomAfterFullscreenExit && IsWindowVisible() && !m_fFullScreen) { - CAppSettings& s = AfxGetAppSettings(); - if (nType != SIZE_MAXIMIZED && nType != SIZE_MINIMIZED) { - GetWindowRect(s.rcLastWindowPos); - } - s.nLastWindowType = nType; - } - } - if (nType != SIZE_MINIMIZED) { - OSDBarSetPos(); - } -} - -void CMainFrame::OnSizing(UINT nSide, LPRECT lpRect) -{ - __super::OnSizing(nSide, lpRect); - - if (m_fFullScreen) { - return; - } - - bool bCtrl = GetKeyState(VK_CONTROL) < 0; - OnSizingFixWndToVideo(nSide, lpRect, bCtrl); - OnSizingSnapToScreen(nSide, lpRect, bCtrl); -} - -void CMainFrame::OnSizingFixWndToVideo(UINT nSide, LPRECT lpRect, bool bCtrl) -{ - const auto& s = AfxGetAppSettings(); - - if (GetLoadState() != MLS::LOADED || s.iDefaultVideoSize == DVS_STRETCH || - bCtrl == s.fLimitWindowProportions || IsAeroSnapped() || (m_fAudioOnly && !m_wndView.IsCustomImgLoaded())) { - return; - } - - CSize videoSize = m_fAudioOnly ? m_wndView.GetLogoSize() : GetVideoSize(); - if (videoSize.cx == 0 || videoSize.cy == 0) { - return; - } - - CRect currentWindowRect, currentViewRect; - GetWindowRect(currentWindowRect); - m_wndView.GetWindowRect(currentViewRect); - CSize controlsSize(currentWindowRect.Width() - currentViewRect.Width(), - currentWindowRect.Height() - currentViewRect.Height()); - - const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); - const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); - if (bPanelsOnVideo) { - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetVisibleDockZones(uTop, uLeft, uRight, uBottom); - if (!bToolbarsOnVideo) { - uBottom -= m_controls.GetVisibleToolbarsHeight(); - } - controlsSize.cx -= uLeft + uRight; - controlsSize.cy -= uTop + uBottom; - } else if (bToolbarsOnVideo) { - controlsSize.cy -= m_controls.GetVisibleToolbarsHeight(); - } - - CSize newWindowSize(lpRect->right - lpRect->left, lpRect->bottom - lpRect->top); - - newWindowSize -= controlsSize; - - switch (nSide) { - case WMSZ_TOP: - case WMSZ_BOTTOM: - newWindowSize.cx = long(newWindowSize.cy * videoSize.cx / (double)videoSize.cy + 0.5); - newWindowSize.cy = long(newWindowSize.cx * videoSize.cy / (double)videoSize.cx + 0.5); - break; - case WMSZ_TOPLEFT: - case WMSZ_TOPRIGHT: - case WMSZ_BOTTOMLEFT: - case WMSZ_BOTTOMRIGHT: - case WMSZ_LEFT: - case WMSZ_RIGHT: - newWindowSize.cy = long(newWindowSize.cx * videoSize.cy / (double)videoSize.cx + 0.5); - newWindowSize.cx = long(newWindowSize.cy * videoSize.cx / (double)videoSize.cy + 0.5); - break; - } - - newWindowSize += controlsSize; - - switch (nSide) { - case WMSZ_TOPLEFT: - lpRect->left = lpRect->right - newWindowSize.cx; - lpRect->top = lpRect->bottom - newWindowSize.cy; - break; - case WMSZ_TOP: - case WMSZ_TOPRIGHT: - lpRect->right = lpRect->left + newWindowSize.cx; - lpRect->top = lpRect->bottom - newWindowSize.cy; - break; - case WMSZ_RIGHT: - case WMSZ_BOTTOM: - case WMSZ_BOTTOMRIGHT: - lpRect->right = lpRect->left + newWindowSize.cx; - lpRect->bottom = lpRect->top + newWindowSize.cy; - break; - case WMSZ_LEFT: - case WMSZ_BOTTOMLEFT: - lpRect->left = lpRect->right - newWindowSize.cx; - lpRect->bottom = lpRect->top + newWindowSize.cy; - break; - } - OSDBarSetPos(); -} - -void CMainFrame::OnSizingSnapToScreen(UINT nSide, LPRECT lpRect, bool bCtrl /*= false*/) -{ - const auto& s = AfxGetAppSettings(); - if (!s.fSnapToDesktopEdges) - return; - - CRect areaRect; - CMonitors::GetNearestMonitor(this).GetWorkAreaRect(areaRect); - const CRect invisibleBorderSize = GetInvisibleBorderSize(); - areaRect.InflateRect(invisibleBorderSize); - - CRect& rect = *reinterpret_cast(lpRect); - const CSize threshold(m_dpi.ScaleX(16), m_dpi.ScaleY(16)); - const auto SnapTo = [](LONG& val, LONG to, LONG threshold) { - return (std::abs(val - to) < threshold && val != to) ? (val = to, true) : false; - }; - - CSize videoSize = GetVideoSize(); - - if (bCtrl == s.fLimitWindowProportions || videoSize.cx == 0 || videoSize.cy == 0) { - SnapTo(rect.left, areaRect.left, threshold.cx); - SnapTo(rect.top, areaRect.top, threshold.cy); - SnapTo(rect.right, areaRect.right, threshold.cx); - SnapTo(rect.bottom, areaRect.bottom, threshold.cy); - return; - } - - const CRect rectOrig(rect); - switch (nSide) { - case WMSZ_TOPLEFT: - if (SnapTo(rect.left, areaRect.left, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_LEFT, &rect); - rect.OffsetRect(0, rectOrig.bottom - rect.bottom); - if (rect.top < areaRect.top && SnapTo(rect.top, areaRect.top, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_TOP, &rect); - rect.OffsetRect(rectOrig.right - rect.right, 0); - } - } else if (SnapTo(rect.top, areaRect.top, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_TOP, &rect); - rect.OffsetRect(rectOrig.right - rect.right, 0); - if (rect.left < areaRect.left && SnapTo(rect.left, areaRect.left, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_LEFT, &rect); - rect.OffsetRect(0, rectOrig.bottom - rect.bottom); - } - } - break; - case WMSZ_TOP: - case WMSZ_TOPRIGHT: - if (SnapTo(rect.right, areaRect.right, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); - rect.OffsetRect(0, rectOrig.bottom - rect.bottom); - if (rect.top < areaRect.top && SnapTo(rect.top, areaRect.top, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_TOP, &rect); - rect.OffsetRect(rectOrig.left - rect.left, 0); - } - } - else if (SnapTo(rect.top, areaRect.top, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_TOP, &rect); - rect.OffsetRect(rectOrig.left - rect.left, 0); - if (areaRect.right < rect.right && SnapTo(rect.right, areaRect.right, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); - rect.OffsetRect(0, rectOrig.bottom - rect.bottom); - } - } - break; - case WMSZ_RIGHT: - case WMSZ_BOTTOM: - case WMSZ_BOTTOMRIGHT: - if (SnapTo(rect.right, areaRect.right, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); - if (areaRect.bottom < rect.bottom && SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); - } - } else if (SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); - if (areaRect.right < rect.right && SnapTo(rect.right, areaRect.right, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); - } - } - break; - case WMSZ_LEFT: - case WMSZ_BOTTOMLEFT: - if (SnapTo(rect.left, areaRect.left, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_LEFT, &rect); - if (areaRect.bottom < rect.bottom && SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); - rect.OffsetRect(rectOrig.right - rect.right, 0); - } - } else if (SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { - OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); - rect.OffsetRect(rectOrig.right - rect.right, 0); - if (rect.left < areaRect.left && SnapTo(rect.left, areaRect.left, threshold.cx)) { - OnSizingFixWndToVideo(WMSZ_LEFT, &rect); - } - } - break; - } -} - -void CMainFrame::OnExitSizeMove() -{ - if (m_wndView.Dragging()) { - // HACK: windowed (not renderless) video renderers may not produce WM_MOUSEMOVE message here - UpdateControlState(CMainFrame::UPDATE_CHILDVIEW_CURSOR_HACK); - } -} - -void CMainFrame::OnDisplayChange() // untested, not sure if it's working... -{ - TRACE(_T("*** CMainFrame::OnDisplayChange()\n")); - - if (GetLoadState() == MLS::LOADED) { - if (m_pGraphThread) { - CAMMsgEvent e; - m_pGraphThread->PostThreadMessage(CGraphThread::TM_DISPLAY_CHANGE, (WPARAM)0, (LPARAM)&e); - e.WaitMsg(); - } else { - DisplayChange(); - } - } - - if (HasDedicatedFSVideoWindow()) { - MONITORINFO MonitorInfo; - HMONITOR hMonitor; - - ZeroMemory(&MonitorInfo, sizeof(MonitorInfo)); - MonitorInfo.cbSize = sizeof(MonitorInfo); - - hMonitor = MonitorFromWindow(m_pDedicatedFSVideoWnd->m_hWnd, 0); - if (GetMonitorInfo(hMonitor, &MonitorInfo)) { - CRect MonitorRect = CRect(MonitorInfo.rcMonitor); - m_pDedicatedFSVideoWnd->SetWindowPos(nullptr, - MonitorRect.left, - MonitorRect.top, - MonitorRect.Width(), - MonitorRect.Height(), - SWP_NOZORDER); - MoveVideoWindow(); - } - } -} - -void CMainFrame::OnWindowPosChanging(WINDOWPOS* lpwndpos) -{ - if (!(lpwndpos->flags & SWP_NOMOVE) && IsFullScreenMainFrame()) { - HMONITOR hm = MonitorFromPoint(CPoint(lpwndpos->x, lpwndpos->y), MONITOR_DEFAULTTONULL); - MONITORINFO mi = { sizeof(mi) }; - if (GetMonitorInfo(hm, &mi)) { - lpwndpos->flags &= ~SWP_NOSIZE; - lpwndpos->cx = mi.rcMonitor.right - mi.rcMonitor.left; - lpwndpos->cy = mi.rcMonitor.bottom - mi.rcMonitor.top; - lpwndpos->x = mi.rcMonitor.left; - lpwndpos->y = mi.rcMonitor.top; - } - } - __super::OnWindowPosChanging(lpwndpos); -} - -LRESULT CMainFrame::OnDpiChanged(WPARAM wParam, LPARAM lParam) -{ - m_dpi.Override(LOWORD(wParam), HIWORD(wParam)); - m_eventc.FireEvent(MpcEvent::DPI_CHANGED); - CMPCThemeUtil::GetMetrics(true); //force reset metrics used by util class - CMPCThemeMenu::clearDimensions(); - ReloadMenus(); - if (!restoringWindowRect) { //do not adjust for DPI if restoring saved window position - MoveWindow(reinterpret_cast(lParam)); - } - RecalcLayout(); - m_wndPreView.ScaleFont(); - return 0; -} - -void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) -{ - // Only stop screensaver if video playing; allow for audio only - if ((GetMediaState() == State_Running && !m_fEndOfStream && !m_fAudioOnly) - && (((nID & 0xFFF0) == SC_SCREENSAVE) || ((nID & 0xFFF0) == SC_MONITORPOWER))) { - TRACE(_T("SC_SCREENSAVE, nID = %u, lParam = %d\n"), nID, lParam); - return; - } - - __super::OnSysCommand(nID, lParam); -} - -void CMainFrame::OnActivateApp(BOOL bActive, DWORD dwThreadID) -{ - __super::OnActivateApp(bActive, dwThreadID); - - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW); - - if (IsFullScreenMainFrame()) { - if (bActive) { - // keep the fullscreen window on top while it's active, - // we don't want notification pop-ups to cover it - SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } else { - // don't keep the fullscreen window on top when it's not active, - // we want to be able to switch to other windows nicely - struct { - void operator()() const { - CMainFrame* pMainFrame = AfxGetMainFrame(); - if (!pMainFrame || !pMainFrame->m_fFullScreen || pMainFrame->WindowExpectedOnTop() || pMainFrame->m_bExtOnTop) { - return; - } - // place our window under the new active window - // when we can't determine that window, we try later - if (CWnd* pActiveWnd = GetForegroundWindow()) { - bool bMoved = false; - if (CWnd* pActiveRootWnd = pActiveWnd->GetAncestor(GA_ROOT)) { - const DWORD dwStyle = pActiveRootWnd->GetStyle(); - const DWORD dwExStyle = pActiveRootWnd->GetExStyle(); - if (!(dwStyle & WS_CHILD) && !(dwStyle & WS_POPUP) && !(dwExStyle & WS_EX_TOPMOST)) { - if (CWnd* pLastWnd = GetDesktopWindow()->GetTopWindow()) { - while (CWnd* pWnd = pLastWnd->GetNextWindow(GW_HWNDNEXT)) { - if (*pLastWnd == *pActiveRootWnd) { - pMainFrame->SetWindowPos( - pWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - bMoved = true; - break; - } - pLastWnd = pWnd; - } - } else { - ASSERT(FALSE); - } - } - } - if (!bMoved) { - pMainFrame->SetWindowPos( - &wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } - } else { - pMainFrame->m_timerOneTime.Subscribe( - TimerOneTimeSubscriber::PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW, *this, 1); - } - } - } placeUnder; - placeUnder(); - } - } -} - -LRESULT CMainFrame::OnAppCommand(WPARAM wParam, LPARAM lParam) -{ - UINT cmd = GET_APPCOMMAND_LPARAM(lParam); - UINT uDevice = GET_DEVICE_LPARAM(lParam); - - if (uDevice != FAPPCOMMAND_OEM && cmd != 0 - || cmd == APPCOMMAND_MEDIA_PLAY - || cmd == APPCOMMAND_MEDIA_PAUSE - || cmd == APPCOMMAND_MEDIA_CHANNEL_UP - || cmd == APPCOMMAND_MEDIA_CHANNEL_DOWN - || cmd == APPCOMMAND_MEDIA_RECORD - || cmd == APPCOMMAND_MEDIA_FAST_FORWARD - || cmd == APPCOMMAND_MEDIA_REWIND) { - const CAppSettings& s = AfxGetAppSettings(); - - BOOL fRet = FALSE; - - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - if (wc.appcmd == cmd && TRUE == SendMessage(WM_COMMAND, wc.cmd)) { - fRet = TRUE; - } - } - - if (fRet) { - return TRUE; - } - } - - return Default(); -} - -void CMainFrame::OnRawInput(UINT nInputcode, HRAWINPUT hRawInput) -{ - const CAppSettings& s = AfxGetAppSettings(); - UINT nMceCmd = AfxGetMyApp()->GetRemoteControlCode(nInputcode, hRawInput); - - switch (nMceCmd) { - case MCE_DETAILS: - case MCE_GUIDE: - case MCE_TVJUMP: - case MCE_STANDBY: - case MCE_OEM1: - case MCE_OEM2: - case MCE_MYTV: - case MCE_MYVIDEOS: - case MCE_MYPICTURES: - case MCE_MYMUSIC: - case MCE_RECORDEDTV: - case MCE_DVDANGLE: - case MCE_DVDAUDIO: - case MCE_DVDMENU: - case MCE_DVDSUBTITLE: - case MCE_RED: - case MCE_GREEN: - case MCE_YELLOW: - case MCE_BLUE: - case MCE_MEDIA_NEXTTRACK: - case MCE_MEDIA_PREVIOUSTRACK: - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - if (wc.appcmd == nMceCmd) { - SendMessage(WM_COMMAND, wc.cmd); - break; - } - } - break; - } -} - -LRESULT CMainFrame::OnHotKey(WPARAM wParam, LPARAM lParam) -{ - if (wParam == 0) { - ASSERT(false); - return FALSE; - } - - const CAppSettings& s = AfxGetAppSettings(); - BOOL fRet = FALSE; - - if (GetActiveWindow() == this || s.fGlobalMedia == TRUE) { - POSITION pos = s.wmcmds.GetHeadPosition(); - - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - if (wc.appcmd == wParam && TRUE == SendMessage(WM_COMMAND, wc.cmd)) { - fRet = TRUE; - } - } - } - - return fRet; -} - -bool g_bNoDuration = false; -bool g_bExternalSubtitleTime = false; -bool g_bExternalSubtitle = false; -double g_dRate = 1.0; - -void CMainFrame::OnTimer(UINT_PTR nIDEvent) -{ - switch (nIDEvent) { - case TIMER_WINDOW_FULLSCREEN: - if (AfxGetAppSettings().iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 - BOOL setEnabled = FALSE; - ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); - } - KillTimer(TIMER_WINDOW_FULLSCREEN); - delayingFullScreen = false; - break; - case TIMER_STREAMPOSPOLLER: - if (GetLoadState() == MLS::LOADED) { - REFERENCE_TIME rtNow = 0, rtDur = 0; - switch (GetPlaybackMode()) { - case PM_FILE: - g_bExternalSubtitleTime = false; - if (m_pGB && m_pMS) { - m_pMS->GetCurrentPosition(&rtNow); - if (!m_pGB || !m_pMS) return; // can happen very rarely due to race condition - m_pMS->GetDuration(&rtDur); - - if ((abRepeat.positionA && rtNow < abRepeat.positionA || abRepeat.positionB && rtNow >= abRepeat.positionB) && GetMediaState() != State_Stopped) { - PerformABRepeat(); - return; - } - - auto* pMRU = &AfxGetAppSettings().MRU; - if (m_bRememberFilePos && !m_fEndOfStream) { - pMRU->UpdateCurrentFilePosition(rtNow); - } - - // Casimir666 : autosave subtitle sync after play - if (m_nCurSubtitle >= 0 && m_rtCurSubPos != rtNow) { - if (m_lSubtitleShift) { - 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; - } - - m_wndStatusBar.SetStatusTimer(rtNow, rtDur, IsSubresyncBarVisible(), GetTimeFormat()); - } - break; - case PM_DVD: - 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 ? 30 / 1.001 - : 25.0; - - rtNow = HMSF2RT(Location.TimeCode, fps); - - if (abRepeat.positionB && rtNow >= abRepeat.positionB && GetMediaState() != State_Stopped) { - PerformABRepeat(); - return; - } - - DVD_HMSF_TIMECODE tcDur; - ULONG ulFlags; - if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { - rtDur = HMSF2RT(tcDur, fps); - } - if (m_pSubClock) { - m_pSubClock->SetTime(rtNow); - } - } - } - m_wndStatusBar.SetStatusTimer(rtNow, rtDur, IsSubresyncBarVisible(), GetTimeFormat()); - break; - case PM_ANALOG_CAPTURE: - g_bExternalSubtitleTime = true; - if (m_fCapturing) { - if (m_wndCaptureBar.m_capdlg.m_pMux) { - CComQIPtr pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux; - if (!pMuxMS || FAILED(pMuxMS->GetCurrentPosition(&rtNow))) { - if (m_pMS) { - m_pMS->GetCurrentPosition(&rtNow); - } - } - } - if (m_rtDurationOverride >= 0) { - rtDur = m_rtDurationOverride; - } - } - break; - case PM_DIGITAL_CAPTURE: - g_bExternalSubtitleTime = true; - m_pMS->GetCurrentPosition(&rtNow); - break; - default: - ASSERT(FALSE); - break; - } - - g_bNoDuration = rtDur <= 0; - m_wndSeekBar.Enable(!g_bNoDuration); - m_wndSeekBar.SetRange(0, rtDur); - m_wndSeekBar.SetPos(rtNow); - m_OSD.SetRange(rtDur); - m_OSD.SetPos(rtNow); - m_Lcd.SetMediaRange(0, rtDur); - m_Lcd.SetMediaPos(rtNow); - - if (m_pCAP) { - if (g_bExternalSubtitleTime) { - m_pCAP->SetTime(rtNow); - } - m_wndSubresyncBar.SetTime(rtNow); - m_wndSubresyncBar.SetFPS(m_pCAP->GetFPS()); - } - if (g_bExternalSubtitleTime && (m_iStreamPosPollerInterval > 40)) { - AdjustStreamPosPoller(true); - } - } - break; - case TIMER_STREAMPOSPOLLER2: - if (GetLoadState() == MLS::LOADED) { - switch (GetPlaybackMode()) { - case PM_FILE: - // no break - case PM_DVD: - if (AfxGetAppSettings().fShowCurrentTimeInOSD && m_OSD.CanShowMessage()) { - m_OSD.DisplayTime(m_wndStatusBar.GetStatusTimer()); - } - break; - case PM_DIGITAL_CAPTURE: { - EventDescriptor& NowNext = m_pDVBState->NowNext; - time_t tNow; - time(&tNow); - if (NowNext.duration > 0 && tNow >= NowNext.startTime && tNow <= NowNext.startTime + NowNext.duration) { - REFERENCE_TIME rtNow = REFERENCE_TIME(tNow - NowNext.startTime) * 10000000; - REFERENCE_TIME rtDur = REFERENCE_TIME(NowNext.duration) * 10000000; - m_wndStatusBar.SetStatusTimer(rtNow, rtDur, false, TIME_FORMAT_MEDIA_TIME); - if (AfxGetAppSettings().fShowCurrentTimeInOSD && m_OSD.CanShowMessage()) { - m_OSD.DisplayTime(m_wndStatusBar.GetStatusTimer()); - } - } else { - m_wndStatusBar.SetStatusTimer(ResStr(IDS_CAPTURE_LIVE)); - } - } - break; - case PM_ANALOG_CAPTURE: - if (!m_fCapturing) { - CString str(StrRes(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))) { - str.AppendFormat(_T(" (ch%ld)"), lChannel); - } - m_wndStatusBar.SetStatusTimer(str); - } - break; - default: - ASSERT(FALSE); - break; - } - } - break; - case TIMER_STATS: { - const CAppSettings& s = AfxGetAppSettings(); - if (m_wndStatsBar.IsVisible()) { - CString rate; - rate.Format(_T("%.3fx"), m_dSpeedRate); - if (m_pQP) { - CString info; - int tmp, tmp1; - - if (SUCCEEDED(m_pQP->get_AvgFrameRate(&tmp))) { // We hang here due to a lock that never gets released. - info.Format(_T("%d.%02d (%s)"), tmp / 100, tmp % 100, rate.GetString()); - } else { - info = _T("-"); - } - m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMERATE), info); - - if (SUCCEEDED(m_pQP->get_AvgSyncOffset(&tmp)) - && SUCCEEDED(m_pQP->get_DevSyncOffset(&tmp1))) { - info.Format(IDS_STATSBAR_SYNC_OFFSET_FORMAT, tmp, tmp1); - } else { - info = _T("-"); - } - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SYNC_OFFSET), info); - - if (SUCCEEDED(m_pQP->get_FramesDrawn(&tmp)) - && SUCCEEDED(m_pQP->get_FramesDroppedInRenderer(&tmp1))) { - info.Format(IDS_MAINFRM_6, tmp, tmp1); - } else { - info = _T("-"); - } - m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMES), info); - - if (SUCCEEDED(m_pQP->get_Jitter(&tmp))) { - info.Format(_T("%d ms"), tmp); - } else { - info = _T("-"); - } - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_JITTER), info); - } else { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_PLAYBACK_RATE), rate); - } - - if (m_pBI) { - CString sInfo; - - for (int i = 0, j = m_pBI->GetCount(); i < j; i++) { - int samples, size; - if (S_OK == m_pBI->GetStatus(i, samples, size) && (i < 2 || size > 0)) { // third pin is usually subs - sInfo.AppendFormat(_T("[P%d] %03d samples / %d KB "), i, samples, size / 1024); - } - } - - if (!sInfo.IsEmpty()) { - //sInfo.AppendFormat(_T("(p%lu)"), m_pBI->GetPriority()); - m_wndStatsBar.SetLine(StrRes(IDS_AG_BUFFERS), sInfo); - } - } - - { - // IBitRateInfo - CString sInfo; - BeginEnumFilters(m_pGB, pEF, pBF) { - unsigned i = 0; - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pBRI = pPin) { - DWORD nAvg = pBRI->GetAverageBitRate() / 1000; - - if (nAvg > 0) { - sInfo.AppendFormat(_T("[P%u] %lu/%lu kb/s "), i, nAvg, pBRI->GetCurrentBitRate() / 1000); - } - } - i++; - } - EndEnumPins; - - if (!sInfo.IsEmpty()) { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_BITRATE), sInfo + ResStr(IDS_STATSBAR_BITRATE_AVG_CUR)); - sInfo.Empty(); - } - } - EndEnumFilters; - } - } - - if (GetPlaybackMode() == PM_DVD) { // we also use this timer to update the info panel for DVD playback - ULONG ulAvailable, ulCurrent; - - // Location - - CString Location(_T('-')); - - 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(StrRes(IDS_INFOBAR_LOCATION), Location); - - // Video - - CString Video(_T('-')); - - 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_statusbarVideoSize.Format(_T("%dx%d"), VATR.ulSourceResolutionX, VATR.ulSourceResolutionY); - m_statusbarVideoFormat = VATR.Compression == DVD_VideoCompression_MPEG1 ? L"MPG1" : VATR.Compression == DVD_VideoCompression_MPEG2 ? L"MPG2" : L""; - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_VIDEO), Video); - - // Audio - - CString Audio(_T('-')); - - DVD_AudioAttributes AATR; - - if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulAvailable, &ulCurrent)) - && SUCCEEDED(m_pDVDI->GetAudioAttributes(ulCurrent, &AATR))) { - CString lang; - if (AATR.Language) { - GetLocaleString(AATR.Language, LOCALE_SENGLANGUAGE, lang); - currentAudioLang = lang; - } else { - lang.Format(IDS_AG_UNKNOWN, ulCurrent + 1); - currentAudioLang.Empty(); - } - - 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); - m_statusbarAudioFormat.Format(L"%s %dch", format, AATR.bNumberOfChannels); - - Audio.Format(IDS_MAINFRM_11, - lang.GetString(), - format.GetString(), - AATR.dwFrequency, - AATR.bQuantization, - AATR.bNumberOfChannels, - ResStr(AATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString()); - - m_wndStatusBar.SetStatusBitmap( - AATR.bNumberOfChannels == 1 ? IDB_AUDIOTYPE_MONO - : AATR.bNumberOfChannels >= 2 ? IDB_AUDIOTYPE_STEREO - : IDB_AUDIOTYPE_NOAUDIO); - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUDIO), Audio); - - // Subtitles - - CString Subtitles(_T('-')); - - BOOL bIsDisabled; - DVD_SubpictureAttributes SATR; - - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulAvailable, &ulCurrent, &bIsDisabled)) - && SUCCEEDED(m_pDVDI->GetSubpictureAttributes(ulCurrent, &SATR))) { - CString lang; - GetLocaleString(SATR.Language, LOCALE_SENGLANGUAGE, lang); - - 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.GetString()); - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_SUBTITLES), Subtitles); - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - if (m_pDVBState->bActive) { - CComQIPtr pTun = m_pGB; - BOOLEAN bPresent, bLocked; - LONG lDbStrength, lPercentQuality; - CString Signal; - - if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { - Signal.Format(IDS_STATSBAR_SIGNAL_FORMAT, (int)lDbStrength, lPercentQuality); - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), Signal); - } - } else { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), _T("-")); - } - } else if (GetPlaybackMode() == PM_FILE) { - OpenSetupInfoBar(false); - if (s.iTitleBarTextStyle == 1 && s.fTitleBarTextTitle) { - OpenSetupWindowTitle(); - } - MediaTransportControlSetMedia(); - SendNowPlayingToSkype(); - SendNowPlayingToApi(false); - } - - if (m_CachedFilterState == State_Running && !m_fAudioOnly) { - if (s.bPreventDisplaySleep) { - BOOL fActive = FALSE; - if (SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fActive, 0) && fActive) { - SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, nullptr, SPIF_SENDWININICHANGE); - SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, fActive, nullptr, SPIF_SENDWININICHANGE); - } - - // prevent screensaver activate, monitor sleep/turn off after playback - SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); - } - } - } - break; - case TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS: { - if (GetPlaybackMode() == PM_NONE) { - if (UnloadUnusedExternalObjects()) { - KillTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS); - } - } - } - break; - case TIMER_HIDER: - m_timerHider.NotifySubscribers(); - break; - case TIMER_DELAYEDSEEK: - KillTimer(TIMER_DELAYEDSEEK); - if (queuedSeek.seekTime > 0) { - SeekTo(queuedSeek.rtPos, queuedSeek.bShowOSD); - } - break; - default: - if (nIDEvent >= TIMER_ONETIME_START && nIDEvent <= TIMER_ONETIME_END) { - m_timerOneTime.NotifySubscribers(nIDEvent); - } else { - ASSERT(FALSE); - } - } - - __super::OnTimer(nIDEvent); -} - -void CMainFrame::DoAfterPlaybackEvent() -{ - CAppSettings& s = AfxGetAppSettings(); - bool bExitFullScreen = false; - bool bNoMoreMedia = false; - - if (s.nCLSwitches & CLSW_DONOTHING) { - // Do nothing - } else if (s.nCLSwitches & CLSW_CLOSE) { - SendMessage(WM_COMMAND, ID_FILE_EXIT); - } else if (s.nCLSwitches & CLSW_MONITOROFF) { - m_fEndOfStream = true; - bExitFullScreen = true; - SetThreadExecutionState(ES_CONTINUOUS); - SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, 2); - } else if (s.nCLSwitches & CLSW_STANDBY) { - SetPrivilege(SE_SHUTDOWN_NAME); - SetSystemPowerState(TRUE, FALSE); - SendMessage(WM_COMMAND, ID_FILE_EXIT); // Recheck if this is still needed after switching to new toolset and SetSuspendState() - } else if (s.nCLSwitches & CLSW_HIBERNATE) { - SetPrivilege(SE_SHUTDOWN_NAME); - SetSystemPowerState(FALSE, FALSE); - SendMessage(WM_COMMAND, ID_FILE_EXIT); - } else if (s.nCLSwitches & CLSW_SHUTDOWN) { - SetPrivilege(SE_SHUTDOWN_NAME); - InitiateSystemShutdownEx(nullptr, nullptr, 0, TRUE, FALSE, - SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE | SHTDN_REASON_FLAG_PLANNED); - SendMessage(WM_COMMAND, ID_FILE_EXIT); - } else if (s.nCLSwitches & CLSW_LOGOFF) { - SetPrivilege(SE_SHUTDOWN_NAME); - ExitWindowsEx(EWX_LOGOFF | EWX_FORCEIFHUNG, 0); - SendMessage(WM_COMMAND, ID_FILE_EXIT); - } else if (s.nCLSwitches & CLSW_LOCK) { - m_fEndOfStream = true; - bExitFullScreen = true; - LockWorkStation(); - } else if (s.nCLSwitches & CLSW_PLAYNEXT) { - if (!SearchInDir(true, (s.fLoopForever || m_nLoops < s.nLoops || s.bLoopFolderOnPlayNextFile))) { - m_fEndOfStream = true; - bExitFullScreen = true; - bNoMoreMedia = true; - } - } else { - // remembered after playback events - switch (s.eAfterPlayback) { - case CAppSettings::AfterPlayback::PLAY_NEXT: - if (m_wndPlaylistBar.GetCount() < 2) { // ignore global PLAY_NEXT in case of a playlist - if (!SearchInDir(true, s.bLoopFolderOnPlayNextFile)) { - SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); - } - } - break; - case CAppSettings::AfterPlayback::REWIND: - bExitFullScreen = true; - if (m_wndPlaylistBar.GetCount() > 1) { - s.nCLSwitches |= CLSW_OPEN; - PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); - } else { - SendMessage(WM_COMMAND, ID_PLAY_STOP); - } - break; - case CAppSettings::AfterPlayback::MONITOROFF: - m_fEndOfStream = true; - bExitFullScreen = true; - SetThreadExecutionState(ES_CONTINUOUS); - SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, 2); - break; - case CAppSettings::AfterPlayback::CLOSE: - SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); - break; - case CAppSettings::AfterPlayback::EXIT: - SendMessage(WM_COMMAND, ID_FILE_EXIT); - break; - default: - m_fEndOfStream = true; - bExitFullScreen = true; - break; - } - } - - if (AfxGetMyApp()->m_fClosingState) { - return; - } - - if (m_fEndOfStream) { - m_OSD.EnableShowMessage(false); - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - m_OSD.EnableShowMessage(); - if (bNoMoreMedia) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_NO_MORE_MEDIA)); - } - } - - if (bExitFullScreen && (IsFullScreenMode()) && s.fExitFullScreenAtTheEnd) { - OnViewFullscreen(); - } -} - -void CMainFrame::OnUpdateABRepeat(CCmdUI* pCmdUI) { - bool canABRepeat = GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD; - bool abRepeatActive = static_cast(abRepeat); - - switch (pCmdUI->m_nID) { - case ID_PLAY_REPEAT_AB: - pCmdUI->Enable(canABRepeat && abRepeatActive); - break; - case ID_PLAY_REPEAT_AB_MARK_A: - if (pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuItem(ID_PLAY_REPEAT_AB_MARK_A, MF_BYCOMMAND | (abRepeat.positionA ? MF_CHECKED : MF_UNCHECKED)); - } - pCmdUI->Enable(canABRepeat); - break; - case ID_PLAY_REPEAT_AB_MARK_B: - if (pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuItem(ID_PLAY_REPEAT_AB_MARK_B, MF_BYCOMMAND | (abRepeat.positionB ? MF_CHECKED : MF_UNCHECKED)); - } - pCmdUI->Enable(canABRepeat); - break; - default: - ASSERT(FALSE); - return; - } -} - - -void CMainFrame::OnABRepeat(UINT nID) { - switch (nID) { - case ID_PLAY_REPEAT_AB: - if (abRepeat) { //only support disabling from the menu - DisableABRepeat(); - } - break; - case ID_PLAY_REPEAT_AB_MARK_A: - case ID_PLAY_REPEAT_AB_MARK_B: - REFERENCE_TIME rtDur = 0; - int playmode = GetPlaybackMode(); - - bool havePos = false; - REFERENCE_TIME pos = 0; - - if (playmode == PM_FILE && m_pMS) { - m_pMS->GetDuration(&rtDur); - havePos = SUCCEEDED(m_pMS->GetCurrentPosition(&pos)); - } else if (playmode == PM_DVD && 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 ? 30 / 1.001 - : 25.0; - DVD_HMSF_TIMECODE tcDur; - ULONG ulFlags; - if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { - rtDur = HMSF2RT(tcDur, fps); - } - havePos = true; - pos = HMSF2RT(Location.TimeCode, fps); - abRepeat.dvdTitle = m_iDVDTitle; //we only support one title. so if they clear or set, we will remember the current title - } - } else { - return; - } - - if (nID == ID_PLAY_REPEAT_AB_MARK_A) { - if (abRepeat.positionA) { - abRepeat.positionA = 0; - } else if (havePos) { - abRepeat.positionA = pos; - if (abRepeat.positionA < rtDur) { - if (abRepeat.positionB && abRepeat.positionA >= abRepeat.positionB) { - abRepeat.positionB = 0; - } - } else { - abRepeat.positionA = 0; - } - } - } else if (nID == ID_PLAY_REPEAT_AB_MARK_B) { - if (abRepeat.positionB) { - abRepeat.positionB = 0; - } else if (havePos) { - abRepeat.positionB = pos; - if (abRepeat.positionB > 0 && abRepeat.positionB > abRepeat.positionA && rtDur >= abRepeat.positionB) { - if (GetMediaState() == State_Running) { - PerformABRepeat(); //we just set loop point B, so we need to repeat right now - } - } else { - abRepeat.positionB = 0; - } - } - } - - auto pMRU = &AfxGetAppSettings().MRU; - pMRU->UpdateCurrentABRepeat(abRepeat); - - m_wndSeekBar.Invalidate(); - break; - } -} - -void CMainFrame::PerformABRepeat() { - DoSeekTo(abRepeat.positionA, false); - - if (GetMediaState() == State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } -} - -void CMainFrame::DisableABRepeat() { - abRepeat = ABRepeat(); - - auto* pMRU = &AfxGetAppSettings().MRU; - pMRU->UpdateCurrentABRepeat(abRepeat); - - m_wndSeekBar.Invalidate(); -} - -bool CMainFrame::CheckABRepeat(REFERENCE_TIME& aPos, REFERENCE_TIME& bPos) { - if (GetPlaybackMode() == PM_FILE || (GetPlaybackMode() == PM_DVD && m_iDVDTitle == abRepeat.dvdTitle)) { - if (abRepeat) { - aPos = abRepeat.positionA; - bPos = abRepeat.positionB; - return true; - } - } - return false; -} - - -// -// graph event EC_COMPLETE handler -// -void CMainFrame::GraphEventComplete() -{ - CAppSettings& s = AfxGetAppSettings(); - - auto* pMRU = &s.MRU; - - - if (m_bRememberFilePos) { - pMRU->UpdateCurrentFilePosition(0, true); - } - - bool bBreak = false; - if (m_wndPlaylistBar.IsAtEnd() || s.eLoopMode == CAppSettings::LoopMode::FILE) { - ++m_nLoops; - bBreak = !!(s.nCLSwitches & CLSW_AFTERPLAYBACK_MASK); - } - - if (abRepeat) { - PerformABRepeat(); - } else if (s.fLoopForever || m_nLoops < s.nLoops) { - if (bBreak) { - DoAfterPlaybackEvent(); - } else if ((m_wndPlaylistBar.GetCount() > 1) && (s.eLoopMode == CAppSettings::LoopMode::PLAYLIST)) { - int nLoops = m_nLoops; - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARDFILE); - m_nLoops = nLoops; - } else { - if (GetMediaState() == State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } else if (m_pMS) { - REFERENCE_TIME rtDur = 0; - if ((m_pMS->GetDuration(&rtDur) == S_OK) && (rtDur >= 1000000LL) || !IsImageFile(lastOpenFile)) { // repeating still image is pointless and can cause player UI to freeze - REFERENCE_TIME rtPos = 0; - m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - if (GetMediaState() == State_Paused) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - } - } - } - } else { - DoAfterPlaybackEvent(); - } -} - -// -// our WM_GRAPHNOTIFY handler -// - -LRESULT CMainFrame::OnGraphNotify(WPARAM wParam, LPARAM lParam) -{ - CAppSettings& s = AfxGetAppSettings(); - HRESULT hr = S_OK; - - LONG evCode = 0; - LONG_PTR evParam1, evParam2; - while (!AfxGetMyApp()->m_fClosingState && m_pME && SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) { -#ifdef _DEBUG - if (evCode != EC_DVD_CURRENT_HMSF_TIME) { - TRACE(_T("--> CMainFrame::OnGraphNotify on thread: %lu; event: 0x%08x (%ws)\n"), GetCurrentThreadId(), evCode, GetEventString(evCode)); - } -#endif - CString str; - if (m_fCustomGraph) { - if (EC_BG_ERROR == evCode) { - str = CString((char*)evParam1); - } - } - hr = m_pME->FreeEventParams(evCode, evParam1, evParam2); - - switch (evCode) { - case EC_PAUSED: - if (GetLoadState() == MLS::LOADED) { - UpdateCachedMediaState(); - } - if (m_audioTrackCount > 1 && GetLoadState() == MLS::LOADED) { - CheckSelectedAudioStream(); - } - break; - case EC_COMPLETE: - UpdateCachedMediaState(); - GraphEventComplete(); - break; - case EC_ERRORABORT: - UpdateCachedMediaState(); - TRACE(_T("\thr = %08x\n"), (HRESULT)evParam1); - break; - case EC_BUFFERING_DATA: - TRACE(_T("\tBuffering data = %s\n"), evParam1 ? _T("true") : _T("false")); - m_bBuffering = !!evParam1; - break; - case EC_STEP_COMPLETE: - if (m_fFrameSteppingActive) { - m_nStepForwardCount++; - } - UpdateCachedMediaState(); - break; - case EC_DEVICE_LOST: - UpdateCachedMediaState(); - if (evParam2 == 0) { - // Device lost - if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - CComQIPtr pBF = (IUnknown*)evParam1; - if (!m_pVidCap && m_pVidCap == pBF || !m_pAudCap && m_pAudCap == pBF) { - SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); - } - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); - } - } - break; - case EC_DVD_TITLE_CHANGE: { - if (GetPlaybackMode() == PM_FILE) { - SetupChapters(); - } else if (GetPlaybackMode() == PM_DVD) { - m_iDVDTitle = (DWORD)evParam1; - - if (m_iDVDDomain == DVD_DOMAIN_Title) { - CString Domain; - Domain.Format(IDS_AG_TITLE, m_iDVDTitle); - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), Domain); - } - - SetupDVDChapters(); - } - } - break; - case EC_DVD_DOMAIN_CHANGE: { - m_iDVDDomain = (DVD_DOMAIN)evParam1; - - OpenDVDData* pDVDData = dynamic_cast(m_lastOMD.m_p); - ASSERT(pDVDData); - - CString Domain(_T('-')); - - switch (m_iDVDDomain) { - case DVD_DOMAIN_FirstPlay: - ULONGLONG llDVDGuid; - - Domain = _T("First Play"); - - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDiscID(nullptr, &llDVDGuid))) { - m_fValidDVDOpen = true; - - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("DVD Title: %lu"), s.lDVDTitle); - } - - if (s.lDVDTitle != 0) { - // Set command line position - hr = m_pDVDC->PlayTitle(s.lDVDTitle, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayTitle: 0x%08X"), hr); - m_OSD.DebugMessage(_T("DVD Chapter: %lu"), s.lDVDChapter); - } - - if (s.lDVDChapter > 1) { - hr = m_pDVDC->PlayChapterInTitle(s.lDVDTitle, s.lDVDChapter, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayChapterInTitle: 0x%08X"), hr); - } - } else { - // Trick: skip trailers with some DVDs - hr = m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("Resume: 0x%08X"), hr); - } - - // If the resume call succeeded, then we skip PlayChapterInTitle - // and PlayAtTimeInTitle. - if (hr == S_OK) { - // This might fail if the Title is not available yet? - hr = m_pDVDC->PlayAtTime(&s.DVDPosition, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayAtTime: 0x%08X"), hr); - } - } else { - if (s.fShowDebugInfo) - m_OSD.DebugMessage(_T("Timecode requested: %02d:%02d:%02d.%03d"), - s.DVDPosition.bHours, s.DVDPosition.bMinutes, - s.DVDPosition.bSeconds, s.DVDPosition.bFrames); - - // Always play chapter 1 (for now, until something else dumb happens) - hr = m_pDVDC->PlayChapterInTitle(s.lDVDTitle, 1, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayChapterInTitle: 0x%08X"), hr); - } - - // This might fail if the Title is not available yet? - hr = m_pDVDC->PlayAtTime(&s.DVDPosition, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayAtTime: 0x%08X"), hr); - } - - if (hr != S_OK) { - hr = m_pDVDC->PlayAtTimeInTitle(s.lDVDTitle, &s.DVDPosition, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayAtTimeInTitle: 0x%08X"), hr); - } - } - } // Resume - - hr = m_pDVDC->PlayAtTime(&s.DVDPosition, - DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("PlayAtTime: %d"), hr); - } - } - - m_iDVDTitle = s.lDVDTitle; - s.lDVDTitle = 0; - s.lDVDChapter = 0; - } else if (pDVDData && pDVDData->pDvdState) { - // Set position from favorite - VERIFY(SUCCEEDED(m_pDVDC->SetState(pDVDData->pDvdState, DVD_CMD_FLAG_Block, nullptr))); - // We don't want to restore the position from the favorite - // if the playback is reinitialized so we clear the saved state - pDVDData->pDvdState.Release(); - } else if (s.fKeepHistory && s.fRememberDVDPos && s.MRU.GetCurrentDVDPosition().llDVDGuid) { - // Set last remembered position (if found...) - DVD_POSITION dvdPosition = s.MRU.GetCurrentDVDPosition(); - - hr = m_pDVDC->PlayTitle(dvdPosition.lTitle, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - TRACE(_T("Failed to set remembered DVD title index, hr = 0x%08X"), hr); - } else { - m_iDVDTitle = dvdPosition.lTitle; - - if (dvdPosition.timecode.bSeconds > 0 || dvdPosition.timecode.bMinutes > 0 || dvdPosition.timecode.bHours > 0 || dvdPosition.timecode.bFrames > 0) { -#if 0 - hr = m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - TRACE(_T("Failed to set remembered DVD resume flags, hr = 0x%08X"), hr); - } -#endif -#if 0 - hr = m_pDVDC->PlayAtTimeInTitle(dvdPosition.lTitle, &dvdPosition.timecode, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); -#else - hr = m_pDVDC->PlayAtTime(&dvdPosition.timecode, DVD_CMD_FLAG_Flush, nullptr); -#endif - } - - ABRepeat tmp = s.MRU.GetCurrentABRepeat(); - if (tmp.dvdTitle == m_iDVDTitle) { - abRepeat = tmp; - m_wndSeekBar.Invalidate(); - } - } - } - - if (s.fRememberZoomLevel && !IsFullScreenMode() && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { // Hack to the normal initial zoom for DVD + DXVA ... - ZoomVideoWindow(); - } - } - break; - case DVD_DOMAIN_VideoManagerMenu: - Domain = _T("Video Manager Menu"); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - break; - case DVD_DOMAIN_VideoTitleSetMenu: - Domain = _T("Video Title Set Menu"); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - break; - case DVD_DOMAIN_Title: - Domain.Format(IDS_AG_TITLE, m_iDVDTitle); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - if (s.fKeepHistory && s.fRememberDVDPos) { - s.MRU.UpdateCurrentDVDTitle(m_iDVDTitle); - } - if (!m_fValidDVDOpen && m_pDVDC) { - m_fValidDVDOpen = true; - m_pDVDC->ShowMenu(DVD_MENU_Title, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - } - break; - case DVD_DOMAIN_Stop: - Domain.LoadString(IDS_AG_STOP); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - break; - default: - Domain = _T("-"); - if (s.fShowDebugInfo) { - m_OSD.DebugMessage(_T("%s"), Domain.GetString()); - } - break; - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), Domain); - - if (GetPlaybackMode() == PM_FILE) { - SetupChapters(); - } else if (GetPlaybackMode() == PM_DVD) { - SetupDVDChapters(); - } - -#if 0 // UOPs debug traces - if (hr == VFW_E_DVD_OPERATION_INHIBITED) { - ULONG UOPfields = 0; - pDVDI->GetCurrentUOPS(&UOPfields); - CString message; - message.Format(_T("UOP bitfield: 0x%08X; domain: %s"), UOPfields, Domain); - m_OSD.DisplayMessage(OSD_TOPLEFT, message); - } else { - m_OSD.DisplayMessage(OSD_TOPRIGHT, Domain); - } -#endif - - MoveVideoWindow(); // AR might have changed - } - break; - case EC_DVD_CURRENT_HMSF_TIME: { - s.MRU.UpdateCurrentDVDTimecode((DVD_HMSF_TIMECODE*)&evParam1); - } - break; - case EC_DVD_ERROR: { - TRACE(_T("\t%I64d %Id\n"), evParam1, evParam2); - - UINT err; - - switch (evParam1) { - case DVD_ERROR_Unexpected: - default: - err = IDS_MAINFRM_16; - break; - case DVD_ERROR_CopyProtectFail: - err = IDS_MAINFRM_17; - break; - case DVD_ERROR_InvalidDVD1_0Disc: - err = IDS_MAINFRM_18; - break; - case DVD_ERROR_InvalidDiscRegion: - err = IDS_MAINFRM_19; - break; - case DVD_ERROR_LowParentalLevel: - err = IDS_MAINFRM_20; - break; - case DVD_ERROR_MacrovisionFail: - err = IDS_MAINFRM_21; - break; - case DVD_ERROR_IncompatibleSystemAndDecoderRegions: - err = IDS_MAINFRM_22; - break; - case DVD_ERROR_IncompatibleDiscAndDecoderRegions: - err = IDS_MAINFRM_23; - break; - } - - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - - m_closingmsg.LoadString(err); - } - break; - case EC_DVD_WARNING: - TRACE(_T("\t%Id %Id\n"), evParam1, evParam2); - break; - case EC_VIDEO_SIZE_CHANGED: { - CSize size((DWORD)evParam1); - TRACE(_T("\t%ldx%ld\n"), size.cx, size.cy); - const bool bWasAudioOnly = m_fAudioOnly; - m_fAudioOnly = (size.cx <= 0 || size.cy <= 0); - OnVideoSizeChanged(bWasAudioOnly); - } - break; - case EC_LENGTH_CHANGED: { - REFERENCE_TIME rtDur = 0; - m_pMS->GetDuration(&rtDur); - m_wndPlaylistBar.SetCurTime(rtDur); - OnTimer(TIMER_STREAMPOSPOLLER); - OnTimer(TIMER_STREAMPOSPOLLER2); - LoadKeyFrames(); - if (GetPlaybackMode() == PM_FILE) { - SetupChapters(); - } else if (GetPlaybackMode() == PM_DVD) { - SetupDVDChapters(); - } - } - break; - case EC_BG_AUDIO_CHANGED: - if (m_fCustomGraph) { - int nAudioChannels = (int)evParam1; - - m_wndStatusBar.SetStatusBitmap(nAudioChannels == 1 ? IDB_AUDIOTYPE_MONO - : nAudioChannels >= 2 ? IDB_AUDIOTYPE_STEREO - : IDB_AUDIOTYPE_NOAUDIO); - } - break; - case EC_BG_ERROR: - if (m_fCustomGraph) { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - m_closingmsg = !str.IsEmpty() ? str : CString(_T("Unspecified graph error")); - m_wndPlaylistBar.SetCurValid(false); - return hr; - } - break; - case EC_DVD_PLAYBACK_RATE_CHANGE: - if (m_fCustomGraph && s.autoChangeFSMode.bEnabled && - (IsFullScreenMode()) && m_iDVDDomain == DVD_DOMAIN_Title) { - AutoChangeMonitorMode(); - } - break; - case EC_CLOCK_CHANGED: - if (m_pBA && !m_fFrameSteppingActive) { - m_pBA->put_Volume(m_wndToolBar.Volume); - } - break; - case 0xfa17: - // madVR changed graph state - UpdateCachedMediaState(); - break; - case EC_DVD_STILL_ON: - m_bDVDStillOn = true; - break; - case EC_DVD_STILL_OFF: - m_bDVDStillOn = false; - break; - case EC_DVD_BUTTON_CHANGE: - case EC_DVD_SUBPICTURE_STREAM_CHANGE: - case EC_DVD_AUDIO_STREAM_CHANGE: - case EC_DVD_ANGLE_CHANGE: - case EC_DVD_VALID_UOPS_CHANGE: - case EC_DVD_CHAPTER_START: - // no action required - break; - default: - UpdateCachedMediaState(); - TRACE(_T("Unhandled graph event\n")); - } - } - - return hr; -} - -LRESULT CMainFrame::OnResetDevice(WPARAM wParam, LPARAM lParam) -{ - m_OSD.HideMessage(true); - - OAFilterState fs = GetMediaState(); - if (fs == State_Running) { - if (!IsPlaybackCaptureMode()) { - MediaControlPause(true); - } else { - MediaControlStop(true); // Capture mode doesn't support pause - } - } - - if (m_bOpenedThroughThread) { - CAMMsgEvent e; - m_pGraphThread->PostThreadMessage(CGraphThread::TM_RESET, (WPARAM)0, (LPARAM)&e); - e.WaitMsg(); - } else { - ResetDevice(); - } - - if (fs == State_Running && m_pMC) { - MediaControlRun(); - - // When restarting DVB capture, we need to set again the channel. - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - SetChannel(AfxGetAppSettings().nDVBLastChannel); - } - } - } - - if (m_OSD.CanShowMessage()) { - m_OSD.HideMessage(false); - } - - return S_OK; -} - -LRESULT CMainFrame::OnRepaintRenderLess(WPARAM wParam, LPARAM lParam) -{ - MoveVideoWindow(); - return TRUE; -} - -void CMainFrame::SaveAppSettings() -{ - MSG msg; - if (!PeekMessage(&msg, m_hWnd, WM_SAVESETTINGS, WM_SAVESETTINGS, PM_NOREMOVE | PM_NOYIELD)) { - AfxGetAppSettings().SaveSettings(); - } -} - -LRESULT CMainFrame::OnNcHitTest(CPoint point) -{ - LRESULT nHitTest = __super::OnNcHitTest(point); - return ((IsCaptionHidden()) && nHitTest == HTCLIENT) ? HTCAPTION : nHitTest; -} - -void CMainFrame::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - // pScrollBar is null when making horizontal scroll with pen tablet - if (!pScrollBar) return; - - if (pScrollBar->IsKindOf(RUNTIME_CLASS(CVolumeCtrl))) { - OnPlayVolume(0); - } else if (pScrollBar->IsKindOf(RUNTIME_CLASS(CPlayerSeekBar)) && GetLoadState() == MLS::LOADED) { - SeekTo(m_wndSeekBar.GetPos()); - } else if (*pScrollBar == *m_pVideoWnd) { - SeekTo(m_OSD.GetPos()); - } - - __super::OnHScroll(nSBCode, nPos, pScrollBar); -} - -void CMainFrame::RestoreFocus() { - CWnd* curFocus = GetFocus(); - if (curFocus && curFocus != this) { - SetFocus(); - } -} - -void CMainFrame::OnInitMenu(CMenu* pMenu) -{ - __super::OnInitMenu(pMenu); - RestoreFocus(); - - const UINT uiMenuCount = pMenu->GetMenuItemCount(); - if (uiMenuCount == -1) { - return; - } - - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - - for (UINT i = 0; i < uiMenuCount; ++i) { -#ifdef _DEBUG - CString str; - pMenu->GetMenuString(i, str, MF_BYPOSITION); - str.Remove('&'); -#endif - UINT itemID = pMenu->GetMenuItemID(i); - if (itemID == 0xFFFFFFFF) { - mii.fMask = MIIM_ID; - pMenu->GetMenuItemInfo(i, &mii, TRUE); - itemID = mii.wID; - } - - CMPCThemeMenu* pSubMenu = nullptr; - - if (itemID == ID_FAVORITES) { - SetupFavoritesSubMenu(); - pSubMenu = &m_favoritesMenu; - }/*else if (itemID == ID_RECENT_FILES) { - SetupRecentFilesSubMenu(); - pSubMenu = &m_recentFilesMenu; - }*/ - - if (pSubMenu) { - mii.fMask = MIIM_STATE | MIIM_SUBMENU; - mii.fState = (pSubMenu->GetMenuItemCount()) > 0 ? MFS_ENABLED : MFS_DISABLED; - mii.hSubMenu = *pSubMenu; - VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pMenu, i, &mii, TRUE)); - pSubMenu->fulfillThemeReqs(); - } - } -} - -void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) { - __super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu); - - if (bSysMenu) { - m_pActiveSystemMenu = pPopupMenu; - m_eventc.FireEvent(MpcEvent::SYSTEM_MENU_POPUP_INITIALIZED); - return; - } - - UINT uiMenuCount = pPopupMenu->GetMenuItemCount(); - if (uiMenuCount == -1) { - return; - } - - MENUITEMINFO mii; - mii.cbSize = sizeof(mii); - - for (UINT i = 0; i < uiMenuCount; ++i) { -#ifdef _DEBUG - CString str; - pPopupMenu->GetMenuString(i, str, MF_BYPOSITION); - str.Remove('&'); -#endif - UINT firstSubItemID = 0; - CMenu* sm = pPopupMenu->GetSubMenu(i); - if (sm) { - firstSubItemID = sm->GetMenuItemID(0); - } - - if (firstSubItemID == ID_NAVIGATE_SKIPBACK) { // is "Navigate" submenu { - UINT fState = (GetLoadState() == MLS::LOADED - && (1/*GetPlaybackMode() == PM_DVD *//*|| (GetPlaybackMode() == PM_FILE && !m_PlayList.IsEmpty())*/)) - ? MF_ENABLED - : MF_GRAYED; - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - if (firstSubItemID == ID_VIEW_VF_HALF // is "Video Frame" submenu - || firstSubItemID == ID_VIEW_INCSIZE // is "Pan&Scan" submenu - || firstSubItemID == ID_ASPECTRATIO_START // is "Override Aspect Ratio" submenu - || firstSubItemID == ID_VIEW_ZOOM_25) { // is "Zoom" submenu - UINT fState = (GetLoadState() == MLS::LOADED && !m_fAudioOnly) - ? MF_ENABLED - : MF_GRAYED; - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - - // "File -> Subtitles" submenu - if (firstSubItemID == ID_FILE_SUBTITLES_LOAD) { - UINT fState = (GetLoadState() == MLS::LOADED && !m_fAudioOnly && m_pCAP) - ? MF_ENABLED - : MF_GRAYED; - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - - // renderer settings - if (firstSubItemID == ID_VIEW_TEARING_TEST) { - UINT fState = MF_GRAYED; - const CAppSettings& s = AfxGetAppSettings(); - if (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC || s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS) { - fState = MF_ENABLED; - } - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - - UINT itemID = pPopupMenu->GetMenuItemID(i); - if (itemID == 0xFFFFFFFF) { - mii.fMask = MIIM_ID; - VERIFY(pPopupMenu->GetMenuItemInfo(i, &mii, TRUE)); - itemID = mii.wID; - } - CMPCThemeMenu* pSubMenu = nullptr; - - // debug shaders - if (itemID == ID_VIEW_DEBUGSHADERS) { - UINT fState = MF_GRAYED; - if (GetLoadState() == MLS::LOADED && !m_fAudioOnly && m_pCAP2) { - fState = MF_ENABLED; - } - pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); - continue; - } - - if (itemID == ID_FILE_OPENDISC) { - SetupOpenCDSubMenu(); - pSubMenu = &m_openCDsMenu; - } else if (itemID == ID_FILTERS) { - SetupFiltersSubMenu(); - pSubMenu = &m_filtersMenu; - } else if (itemID == ID_AUDIOS) { - SetupAudioSubMenu(); - pSubMenu = &m_audiosMenu; - } else if (itemID == ID_SUBTITLES) { - SetupSubtitlesSubMenu(); - pSubMenu = &m_subtitlesMenu; - } else if (itemID == ID_VIDEO_STREAMS) { - CString menuStr; - menuStr.LoadString(GetPlaybackMode() == PM_DVD ? IDS_MENU_VIDEO_ANGLE : IDS_MENU_VIDEO_STREAM); - - mii.fMask = MIIM_STRING; - mii.dwTypeData = (LPTSTR)(LPCTSTR)menuStr; - VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pPopupMenu, i, &mii, TRUE)); - - SetupVideoStreamsSubMenu(); - pSubMenu = &m_videoStreamsMenu; - } else if (itemID == ID_NAVIGATE_GOTO) { - // ID_NAVIGATE_GOTO is just a marker we use to insert the appropriate submenus - SetupJumpToSubMenus(pPopupMenu, i + 1); - uiMenuCount = pPopupMenu->GetMenuItemCount(); //SetupJumpToSubMenus could actually reduce the menu count! - } else if (itemID == ID_FAVORITES) { - SetupFavoritesSubMenu(); - pSubMenu = &m_favoritesMenu; - } else if (itemID == ID_RECENT_FILES) { - SetupRecentFilesSubMenu(); - pSubMenu = &m_recentFilesMenu; - } else if (itemID == ID_SHADERS) { - if (SetupShadersSubMenu()) { - pPopupMenu->EnableMenuItem(ID_SHADERS, MF_BYPOSITION | MF_ENABLED); - } else { - pPopupMenu->EnableMenuItem(ID_SHADERS, MF_BYPOSITION | MF_GRAYED); - } - pSubMenu = &m_shadersMenu; - } - - if (pSubMenu) { - mii.fMask = MIIM_STATE | MIIM_SUBMENU; - mii.fState = (pSubMenu->GetMenuItemCount() > 0) ? MF_ENABLED : MF_GRAYED; - mii.hSubMenu = *pSubMenu; - VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pPopupMenu, i, &mii, TRUE)); - pSubMenu->fulfillThemeReqs(); - } - } - - uiMenuCount = pPopupMenu->GetMenuItemCount(); - if (uiMenuCount == -1) { - return; - } - - if (!AppIsThemeLoaded()) { //themed menus draw accelerators already, no need to append - for (UINT i = 0; i < uiMenuCount; ++i) { - UINT nID = pPopupMenu->GetMenuItemID(i); - if (nID == ID_SEPARATOR || nID == -1 - || nID >= ID_FAVORITES_FILE_START && nID <= ID_FAVORITES_FILE_END - || nID >= ID_RECENT_FILE_START && nID <= ID_RECENT_FILE_END - || nID >= ID_SUBTITLES_SUBITEM_START && nID <= ID_SUBTITLES_SUBITEM_END - || nID >= ID_NAVIGATE_JUMPTO_SUBITEM_START && nID <= ID_NAVIGATE_JUMPTO_SUBITEM_END) { - continue; - } - - CString str; - pPopupMenu->GetMenuString(i, str, MF_BYPOSITION); - int k = str.Find('\t'); - if (k > 0) { - str = str.Left(k); - } - - CString key = CPPageAccelTbl::MakeAccelShortcutLabel(nID); - if (key.IsEmpty() && k < 0) { - continue; - } - str += _T("\t") + key; - - // BUG(?): this disables menu item update ui calls for some reason... - //pPopupMenu->ModifyMenu(i, MF_BYPOSITION|MF_STRING, nID, str); - - // this works fine - mii.fMask = MIIM_STRING; - mii.dwTypeData = (LPTSTR)(LPCTSTR)str; - VERIFY(pPopupMenu->SetMenuItemInfo(i, &mii, TRUE)); - } - } - - uiMenuCount = pPopupMenu->GetMenuItemCount(); - if (uiMenuCount == -1) { - return; - } - - bool fPnSPresets = false; - - for (UINT i = 0; i < uiMenuCount; ++i) { - UINT nID = pPopupMenu->GetMenuItemID(i); - - if (nID >= ID_PANNSCAN_PRESETS_START && nID < ID_PANNSCAN_PRESETS_END) { - do { - nID = pPopupMenu->GetMenuItemID(i); - VERIFY(pPopupMenu->DeleteMenu(i, MF_BYPOSITION)); - uiMenuCount--; - } while (i < uiMenuCount && nID >= ID_PANNSCAN_PRESETS_START && nID < ID_PANNSCAN_PRESETS_END); - - nID = pPopupMenu->GetMenuItemID(i); - } - - if (nID == ID_VIEW_RESET) { - fPnSPresets = true; - } - } - - if (fPnSPresets) { - bool usetheme = AppIsThemeLoaded(); - const CAppSettings& s = AfxGetAppSettings(); - INT_PTR i = 0, j = s.m_pnspresets.GetCount(); - for (; i < j; i++) { - int k = 0; - CString label = s.m_pnspresets[i].Tokenize(_T(","), k); - VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND, ID_PANNSCAN_PRESETS_START + i, label)); - CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, (UINT)(ID_PANNSCAN_PRESETS_START + i), true); - } - //if (j > 0) - { - VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND, ID_PANNSCAN_PRESETS_START + i, ResStr(IDS_PANSCAN_EDIT))); - VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND | MF_SEPARATOR)); - if (usetheme) { - CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, (UINT)(ID_PANNSCAN_PRESETS_START + i), true); - UINT pos = CMPCThemeMenu::getPosFromID(pPopupMenu, ID_VIEW_RESET); //separator is inserted right before view_reset - CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, pos - 1); - } - } - } - - if (m_pActiveContextMenu == pPopupMenu) { - m_eventc.FireEvent(MpcEvent::CONTEXT_MENU_POPUP_INITIALIZED); - } -} - -void CMainFrame::OnUnInitMenuPopup(CMenu* pPopupMenu, UINT nFlags) -{ - __super::OnUnInitMenuPopup(pPopupMenu, nFlags); - if (m_pActiveContextMenu == pPopupMenu) { - m_pActiveContextMenu = nullptr; - m_eventc.FireEvent(MpcEvent::CONTEXT_MENU_POPUP_UNINITIALIZED); - } else if (m_pActiveSystemMenu == pPopupMenu) { - m_pActiveSystemMenu = nullptr; - SendMessage(WM_CANCELMODE); // unfocus main menu if system menu was entered with alt+space - m_eventc.FireEvent(MpcEvent::SYSTEM_MENU_POPUP_UNINITIALIZED); - } -} - -void CMainFrame::OnEnterMenuLoop(BOOL bIsTrackPopupMenu) -{ - if (!bIsTrackPopupMenu && !m_pActiveSystemMenu && GetMenuBarState() == AFX_MBS_HIDDEN) { - // mfc has problems synchronizing menu visibility with modal loop in certain situations - ASSERT(!m_pActiveContextMenu); - VERIFY(SetMenuBarState(AFX_MBS_VISIBLE)); - } - __super::OnEnterMenuLoop(bIsTrackPopupMenu); -} - -BOOL CMainFrame::OnQueryEndSession() -{ - return TRUE; -} - -void CMainFrame::OnEndSession(BOOL bEnding) -{ - // do nothing for now -} - -BOOL CMainFrame::OnMenu(CMenu* pMenu) -{ - if (!pMenu) { - return FALSE; - } - - CPoint point; - GetCursorPos(&point); - - // Do not show popup menu in D3D fullscreen it has several adverse effects. - if (IsD3DFullScreenMode()) { - CWnd* pWnd = WindowFromPoint(point); - if (pWnd && *pWnd == *m_pDedicatedFSVideoWnd) { - return FALSE; - } - } - - if (AfxGetMyApp()->m_fClosingState) { - return FALSE; //prevent crash when player closes with context menu open - } - - m_pActiveContextMenu = pMenu; - - pMenu->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NOANIMATION, point.x, point.y, this); - - return TRUE; -} - -void CMainFrame::OnMenuPlayerShort() -{ - if (!AfxGetAppSettings().bAlwaysUseShortMenu && (IsMenuHidden() || IsD3DFullScreenMode())) { - OnMenu(m_mainPopupMenu.GetSubMenu(0)); - } else { - OnMenu(m_popupMenu.GetSubMenu(0)); - } -} - -void CMainFrame::OnMenuPlayerLong() -{ - OnMenu(m_mainPopupMenu.GetSubMenu(0)); -} - -void CMainFrame::OnMenuFilters() -{ - SetupFiltersSubMenu(); - OnMenu(&m_filtersMenu); -} - -void CMainFrame::OnUpdatePlayerStatus(CCmdUI* pCmdUI) -{ - if (GetLoadState() == MLS::LOADING) { - m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_OPENING)); - if (AfxGetAppSettings().bUseEnhancedTaskBar && m_pTaskbarList) { - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_INDETERMINATE); - } - } else if (GetLoadState() == MLS::LOADED) { - if (!m_tempstatus_msg.IsEmpty()) { - m_wndStatusBar.SetStatusMessage(m_tempstatus_msg); - return; - } - CString msg; - if (m_fCapturing) { - msg.LoadString(IDS_CONTROLS_CAPTURING); - - if (m_pAMDF) { - long lDropped = 0; - m_pAMDF->GetNumDropped(&lDropped); - long lNotDropped = 0; - m_pAMDF->GetNumNotDropped(&lNotDropped); - - if ((lDropped + lNotDropped) > 0) { - msg.AppendFormat(IDS_MAINFRM_37, lDropped + lNotDropped, lDropped); - } - } - - CComPtr pPin; - if (m_pCGB && SUCCEEDED(m_pCGB->FindPin(m_wndCaptureBar.m_capdlg.m_pDst, PINDIR_INPUT, nullptr, nullptr, FALSE, 0, &pPin))) { - LONGLONG size = 0; - if (CComQIPtr pStream = pPin) { - pStream->Commit(STGC_DEFAULT); - - WIN32_FIND_DATA findFileData; - HANDLE h = FindFirstFile(m_wndCaptureBar.m_capdlg.m_file, &findFileData); - if (h != INVALID_HANDLE_VALUE) { - size = ((LONGLONG)findFileData.nFileSizeHigh << 32) | findFileData.nFileSizeLow; - - if (size < 1024i64 * 1024) { - msg.AppendFormat(IDS_MAINFRM_38, size / 1024); - } else { //if (size < 1024i64*1024*1024) - msg.AppendFormat(IDS_MAINFRM_39, size / 1024 / 1024); - } - - FindClose(h); - } - } - - ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes, TotalNumberOfFreeBytes; - if (GetDiskFreeSpaceEx( - m_wndCaptureBar.m_capdlg.m_file.Left(m_wndCaptureBar.m_capdlg.m_file.ReverseFind('\\') + 1), - &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) { - if (FreeBytesAvailable.QuadPart < 1024i64 * 1024) { - msg.AppendFormat(IDS_MAINFRM_40, FreeBytesAvailable.QuadPart / 1024); - } else { //if (FreeBytesAvailable.QuadPart < 1024i64*1024*1024) - msg.AppendFormat(IDS_MAINFRM_41, FreeBytesAvailable.QuadPart / 1024 / 1024); - } - } - - if (m_wndCaptureBar.m_capdlg.m_pMux) { - __int64 pos = 0; - CComQIPtr pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux; - if (pMuxMS && SUCCEEDED(pMuxMS->GetCurrentPosition(&pos)) && pos > 0) { - double bytepersec = 10000000.0 * size / pos; - if (bytepersec > 0) { - m_rtDurationOverride = REFERENCE_TIME(10000000.0 * (FreeBytesAvailable.QuadPart + size) / bytepersec); - } - } - } - - if (m_wndCaptureBar.m_capdlg.m_pVidBuffer - || m_wndCaptureBar.m_capdlg.m_pAudBuffer) { - int nFreeVidBuffers = 0, nFreeAudBuffers = 0; - if (CComQIPtr pVB = m_wndCaptureBar.m_capdlg.m_pVidBuffer) { - nFreeVidBuffers = pVB->GetFreeBuffers(); - } - if (CComQIPtr pAB = m_wndCaptureBar.m_capdlg.m_pAudBuffer) { - nFreeAudBuffers = pAB->GetFreeBuffers(); - } - - msg.AppendFormat(IDS_MAINFRM_42, nFreeVidBuffers, nFreeAudBuffers); - } - } - } else if (m_bBuffering) { - if (m_pAMNS) { - long BufferingProgress = 0; - if (SUCCEEDED(m_pAMNS->get_BufferingProgress(&BufferingProgress)) && BufferingProgress > 0) { - msg.Format(IDS_CONTROLS_BUFFERING, BufferingProgress); - - __int64 start = 0, stop = 0; - m_wndSeekBar.GetRange(start, stop); - m_fLiveWM = (stop == start); - } - } - } else if (m_pAMOP) { - LONGLONG t = 0, c = 0; - if (SUCCEEDED(m_pAMOP->QueryProgress(&t, &c)) && t > 0 && c < t) { - msg.Format(IDS_CONTROLS_BUFFERING, c * 100 / t); - } else { - m_pAMOP.Release(); - } - } - - if (msg.IsEmpty()) { - int msg_id = 0; - switch (m_CachedFilterState) { - case State_Stopped: - msg_id = IDS_CONTROLS_STOPPED; - break; - case State_Paused: - msg_id = IDS_CONTROLS_PAUSED; - break; - case State_Running: - msg_id = IDS_CONTROLS_PLAYING; - break; - } - if (m_fFrameSteppingActive) { - msg_id = IDS_CONTROLS_PAUSED; - } - if (msg_id) { - msg.LoadString(msg_id); - - if (m_bUsingDXVA && (msg_id == IDS_CONTROLS_PAUSED || msg_id == IDS_CONTROLS_PLAYING)) { - msg.AppendFormat(_T(" %s"), ResStr(IDS_HW_INDICATOR).GetString()); - } - } - - auto& s = AfxGetAppSettings(); - - CString videoinfo; - CString fpsinfo; - CStringW audioinfo; - if (s.bShowVideoInfoInStatusbar && (!m_statusbarVideoFormat.IsEmpty() || !m_statusbarVideoSize.IsEmpty())) { - if(!m_statusbarVideoFormat.IsEmpty()) { - videoinfo.Append(m_statusbarVideoFormat); - } - if(!m_statusbarVideoSize.IsEmpty()) { - if(!m_statusbarVideoFormat.IsEmpty()) { - videoinfo.AppendChar(_T(' ')); - } - videoinfo.Append(m_statusbarVideoSize); - } - } - if (s.bShowFPSInStatusbar && m_pCAP) { - if (m_dSpeedRate != 1.0) { - fpsinfo.Format(_T("%.2lf fps (%.2lfx)"), m_pCAP->GetFPS(), m_dSpeedRate); - } else { - fpsinfo.Format(_T("%.2lf fps"), m_pCAP->GetFPS()); - } - } - - if (s.bShowAudioFormatInStatusbar && !m_statusbarAudioFormat.IsEmpty()) { - audioinfo = m_statusbarAudioFormat; - } - - if (!videoinfo.IsEmpty() || !fpsinfo.IsEmpty()) { - CStringW tinfo = L""; - AppendWithDelimiter(tinfo, videoinfo); - AppendWithDelimiter(tinfo, fpsinfo); - msg.Append(L"\u2001[" + tinfo + L"]"); - } - - if (!audioinfo.IsEmpty()) { - msg.Append(L"\u2001[" + audioinfo); - if (s.bShowLangInStatusbar && !currentAudioLang.IsEmpty()) { - msg.Append(L" " + currentAudioLang); - } - msg.Append(L"]"); - } - - if (s.bShowLangInStatusbar) { - bool showaudiolang = audioinfo.IsEmpty() && !currentAudioLang.IsEmpty(); - if (showaudiolang || !currentSubLang.IsEmpty()) { - msg.Append(_T("\u2001[")); - if (showaudiolang) { - msg.Append(L"AUD: " + currentAudioLang); - } - if (!currentSubLang.IsEmpty()) { - if (showaudiolang) { - msg.Append(_T(", ")); - } - msg.Append(L"SUB: " + currentSubLang); - } - msg.Append(_T("]")); - } - } - if (s.bShowABMarksInStatusbar) { - if (abRepeat) { - REFERENCE_TIME actualB = abRepeat.positionB; - if (actualB == 0) { - REFERENCE_TIME start = 0; - m_wndSeekBar.GetRange(start, actualB); - } - bool showhours = (actualB >= 35995000000) || (abRepeat.positionA >= 35995000000); - CString timeMarkA = showhours ? ReftimeToString2(abRepeat.positionA) : ReftimeToString3(abRepeat.positionA); - CString timeMarkB = showhours ? ReftimeToString2(actualB) : ReftimeToString3(actualB); - msg.AppendFormat(_T("\u2001[A-B %s > %s]"), timeMarkA.GetString(), timeMarkB.GetString()); - } - } - } - - m_wndStatusBar.SetStatusMessage(msg); - } else if (GetLoadState() == MLS::CLOSING) { - m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_CLOSING)); - if (AfxGetAppSettings().bUseEnhancedTaskBar && m_pTaskbarList) { - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_INDETERMINATE); - } - } else { - m_wndStatusBar.SetStatusMessage(m_closingmsg); - } -} - -LRESULT CMainFrame::OnFilePostOpenmedia(WPARAM wParam, LPARAM lParam) -{ - if (!m_pGB) { - ASSERT(FALSE); - return 1; - } - ASSERT(GetLoadState() == MLS::LOADING); - - auto& s = AfxGetAppSettings(); - - // from this on - m_bOpenMediaActive = false; - m_OpenMediaFailedCount = 0; - m_bSettingUpMenus = true; - - SetLoadState(MLS::LOADED); - ASSERT(GetMediaStateDirect() == State_Stopped); - - // destroy invisible top-level d3dfs window if there is no video renderer - if (HasDedicatedFSVideoWindow() && !m_pMFVDC && !m_pVMRWC && !m_pVW) { - m_pDedicatedFSVideoWnd->DestroyWindow(); - if (s.IsD3DFullscreen()) { - m_fStartInD3DFullscreen = true; - } else { - m_fStartInFullscreenSeparate = true; - } - } - - // auto-change monitor mode if requested - if (s.autoChangeFSMode.bEnabled && IsFullScreenMode()) { - AutoChangeMonitorMode(); - // make sure the fullscreen window is positioned properly after the mode change, - // OnWindowPosChanging() will take care of that - if (m_bOpeningInAutochangedMonitorMode && m_fFullScreen) { - CRect rect; - GetWindowRect(rect); - MoveWindow(rect); - } - } - - // set shader selection - if (m_pCAP || m_pCAP2) { - SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); - } - - // load keyframes for fast-seek - if (wParam == PM_FILE) { - LoadKeyFrames(); - } - - // remember OpenMediaData for later use - m_lastOMD.Free(); - m_lastOMD.Attach((OpenMediaData*)lParam); - if (!m_lastOMD->title) { - ASSERT(false); - m_lastOMD->title = L""; - } - - // the media opened successfully, we don't want to jump trough it anymore - UINT lastSkipDirection = m_nLastSkipDirection; - m_nLastSkipDirection = 0; - - // let the EDL do its magic - if (s.fEnableEDLEditor && !m_lastOMD->title.IsEmpty()) { - m_wndEditListEditor.OpenFile(m_lastOMD->title); - } - - // initiate Capture panel with the new media - if (auto pDeviceData = dynamic_cast(m_lastOMD.m_p)) { - m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput); - m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel); - m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput); - } - - // current playlist item was loaded successfully - m_wndPlaylistBar.SetCurValid(true); - - // set item duration in the playlist - // TODO: GetDuration() should be refactored out of this place, to some aggregating class - REFERENCE_TIME rtDur = 0; - if (m_pMS && m_pMS->GetDuration(&rtDur) == S_OK) { - m_wndPlaylistBar.SetCurTime(rtDur); - } - - // process /pns command-line arg, then discard it - ApplyPanNScanPresetString(); - - // initiate toolbars with the new media - OpenSetupInfoBar(); - OpenSetupStatsBar(); - OpenSetupStatusBar(); - OpenSetupCaptureBar(); - - // Load cover-art - if (m_fAudioOnly || HasDedicatedFSVideoWindow()) { - UpdateControlState(CMainFrame::UPDATE_LOGO); - } - - if (s.bOpenRecPanelWhenOpeningDevice) { - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - // show navigation panel when it's available and not disabled - if (!s.fHideNavigation) { - m_wndNavigationBar.m_navdlg.UpdateElementList(); - if (!m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); - } - else { - ASSERT(FALSE); - } - } - } - else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - // show capture bar - if (!m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)) { - m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); - } - else { - ASSERT(FALSE); - } - } - } - - // we don't want to wait until timers initialize the seekbar and the time counter - OnTimer(TIMER_STREAMPOSPOLLER); - OnTimer(TIMER_STREAMPOSPOLLER2); - - if (m_AngleX != 0 || m_AngleY != 0 || m_AngleZ != 0) { - PerformFlipRotate(); - } - - bool go_fullscreen = s.fLaunchfullscreen && !m_fAudioOnly && !IsFullScreenMode() && lastSkipDirection == 0 && !(s.nCLSwitches & CLSW_THUMBNAILS); - - // auto-zoom if requested - if (IsWindowVisible() && s.fRememberZoomLevel && !IsFullScreenMode() && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { - if (go_fullscreen) { - m_bNeedZoomAfterFullscreenExit = true; - } - ZoomVideoWindow(ZOOM_DEFAULT_LEVEL, go_fullscreen); - } - - if (go_fullscreen) { - OnViewFullscreen(); - } - - // Add temporary flag to allow EC_VIDEO_SIZE_CHANGED event to stabilize window size - // for 5 seconds since playback starts - m_bAllowWindowZoom = true; - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::AUTOFIT_TIMEOUT, [this] - { m_bAllowWindowZoom = false; }, 5000); - - // update control bar areas and paint bypassing the message queue - RecalcLayout(); - UpdateWindow(); - - // the window is repositioned and repainted, video renderer rect is ready to be set - - // OnPlayPlay()/OnPlayPause() will take care of that - m_bDelaySetOutputRect = false; - - if (s.nCLSwitches & CLSW_THUMBNAILS) { - MoveVideoWindow(false, true); - MediaControlPause(true); - SendMessageW(WM_COMMAND, ID_CMDLINE_SAVE_THUMBNAILS); - m_bSettingUpMenus = false; - m_bRememberFilePos = false; - SendMessageW(WM_COMMAND, ID_FILE_EXIT); - return 0; - } - - MediaTransportControlSetMedia(); - - // start playback if requested - m_bFirstPlay = true; - const auto uModeChangeDelay = s.autoChangeFSMode.uDelay * 1000; - if (!(s.nCLSwitches & CLSW_OPEN) && (s.nLoops > 0)) { - if (m_bOpeningInAutochangedMonitorMode && uModeChangeDelay) { - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, - std::bind(&CMainFrame::OnPlayPlay, this), uModeChangeDelay); - } else { - OnPlayPlay(); - } - } else { - // OnUpdatePlayPauseStop() will decide if we can pause the media - if (m_bOpeningInAutochangedMonitorMode && uModeChangeDelay) { - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, - [this] { OnCommand(ID_PLAY_PAUSE, 0); }, uModeChangeDelay); - } else { - OnCommand(ID_PLAY_PAUSE, 0); - } - } - s.nCLSwitches &= ~CLSW_OPEN; - - // Ensure the dynamically added menu items are updated - SetupFiltersSubMenu(); - SetupAudioSubMenu(); - SetupSubtitlesSubMenu(); - SetupVideoStreamsSubMenu(); - SetupJumpToSubMenus(); - SetupRecentFilesSubMenu(); - - // notify listeners - if (GetPlaybackMode() != PM_DIGITAL_CAPTURE) { - SendNowPlayingToSkype(); - SendNowPlayingToApi(); - } - - if (CanPreviewUse() && m_wndSeekBar.IsVisible()) { - CPoint point; - GetCursorPos(&point); - - CRect rect; - m_wndSeekBar.GetWindowRect(&rect); - if (rect.PtInRect(point)) { - m_wndSeekBar.PreviewWindowShow(point); - } - } - - m_bSettingUpMenus = false; - - return 0; -} - -LRESULT CMainFrame::OnOpenMediaFailed(WPARAM wParam, LPARAM lParam) -{ - ASSERT(GetLoadState() == MLS::LOADING); - SetLoadState(MLS::FAILING); - - ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); - const auto& s = AfxGetAppSettings(); - - m_lastOMD.Free(); - m_lastOMD.Attach((OpenMediaData*)lParam); - if (!m_lastOMD->title) { - ASSERT(false); - m_lastOMD->title = L""; - } - - bool bOpenNextInPlaylist = false; - bool bAfterPlaybackEvent = false; - - m_bOpenMediaActive = false; - m_OpenMediaFailedCount++; - - m_dwReloadPos = 0; - reloadABRepeat = ABRepeat(); - m_iReloadAudioIdx = -1; - m_iReloadSubIdx = -1; - - if (wParam == PM_FILE && m_OpenMediaFailedCount < 5) { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli) && pli.m_bYoutubeDL && m_sydlLastProcessURL != pli.m_ydlSourceURL) { - OpenCurPlaylistItem(0, true); // Try to reprocess if failed first time. - return 0; - } - if (m_wndPlaylistBar.GetCount() == 1) { - if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { - bOpenNextInPlaylist = SearchInDir(false, s.bLoopFolderOnPlayNextFile); - if (!bOpenNextInPlaylist) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_FIRST_IN_FOLDER)); - } - } else if (m_nLastSkipDirection == ID_NAVIGATE_SKIPFORWARD) { - bOpenNextInPlaylist = SearchInDir(true, s.bLoopFolderOnPlayNextFile); - if (!bOpenNextInPlaylist) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_LAST_IN_FOLDER)); - } - } - } else { - m_wndPlaylistBar.SetCurValid(false); - - if (m_wndPlaylistBar.IsAtEnd()) { - m_nLoops++; - } - - if (s.fLoopForever || m_nLoops < s.nLoops) { - if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { - bOpenNextInPlaylist = m_wndPlaylistBar.SetPrev(); - } else { - bOpenNextInPlaylist = m_wndPlaylistBar.SetNext(); - } - } else { - bAfterPlaybackEvent = true; - } - } - } - - CloseMedia(bOpenNextInPlaylist); - - if (m_OpenMediaFailedCount >= 5) { - m_wndPlaylistBar.SetCurValid(false); - if (m_wndPlaylistBar.IsAtEnd()) { - m_nLoops++; - } - if (s.fLoopForever || m_nLoops < s.nLoops) { - if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { - m_wndPlaylistBar.SetPrev(); - } else { - m_wndPlaylistBar.SetNext(); - } - } - m_OpenMediaFailedCount = 0; - } - else if (bOpenNextInPlaylist) { - OpenCurPlaylistItem(); - } - else if (bAfterPlaybackEvent) { - DoAfterPlaybackEvent(); - } - - return 0; -} - -void CMainFrame::OnFilePostClosemedia(bool bNextIsQueued/* = false*/) -{ - SetPlaybackMode(PM_NONE); - SetLoadState(MLS::CLOSED); - - m_bOpenMediaActive = false; - - abRepeat = ABRepeat(); - m_kfs.clear(); - - m_nCurSubtitle = -1; - m_lSubtitleShift = 0; - - CAppSettings& s = AfxGetAppSettings(); - if (!s.fSavePnSZoom) { - m_AngleX = m_AngleY = m_AngleZ = 0; - m_ZoomX = m_ZoomY = 1.0; - m_PosX = m_PosY = 0.5; - } - - if (m_closingmsg.IsEmpty()) { - m_closingmsg.LoadString(IDS_CONTROLS_CLOSED); - } - - m_wndView.SetVideoRect(); - m_wndSeekBar.Enable(false); - m_wndSeekBar.SetRange(0, 0); - m_wndSeekBar.SetPos(0); - m_wndSeekBar.RemoveChapters(); - m_wndInfoBar.RemoveAllLines(); - m_wndStatsBar.RemoveAllLines(); - m_wndStatusBar.Clear(); - m_wndStatusBar.ShowTimer(false); - currentAudioLang.Empty(); - currentSubLang.Empty(); - m_OSD.SetRange(0); - m_OSD.SetPos(0); - m_Lcd.SetMediaRange(0, 0); - m_Lcd.SetMediaPos(0); - m_statusbarVideoFormat.Empty(); - m_statusbarVideoSize.Empty(); - - m_VidDispName.Empty(); - m_AudDispName.Empty(); - m_HWAccelType = L""; - - if (!bNextIsQueued) { - UpdateControlState(CMainFrame::UPDATE_LOGO); - RecalcLayout(); - } - - if (s.fEnableEDLEditor) { - m_wndEditListEditor.CloseFile(); - } - - if (m_controls.ControlChecked(CMainFrameControls::Panel::SUBRESYNC)) { - m_controls.ToggleControl(CMainFrameControls::Panel::SUBRESYNC); - } - - if (m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)) { - m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); - } - m_wndCaptureBar.m_capdlg.SetupVideoControls(_T(""), nullptr, nullptr, nullptr); - m_wndCaptureBar.m_capdlg.SetupAudioControls(_T(""), nullptr, CInterfaceArray()); - - if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); - } - - if (!bNextIsQueued) { - OpenSetupWindowTitle(true); - } - - SetAlwaysOnTop(s.iOnTop); - - SendNowPlayingToSkype(); - - // try to release external objects - UnloadUnusedExternalObjects(); - SetTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS, 60000, nullptr); - - if (HasDedicatedFSVideoWindow()) { - if (IsD3DFullScreenMode()) { - m_fStartInD3DFullscreen = true; - } else { - m_fStartInFullscreenSeparate = true; - } - if (!bNextIsQueued) { - m_pDedicatedFSVideoWnd->DestroyWindow(); - } - } - - UpdateWindow(); // redraw -} - -void CMainFrame::OnBossKey() -{ - // Disable animation - ANIMATIONINFO AnimationInfo; - AnimationInfo.cbSize = sizeof(ANIMATIONINFO); - ::SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - int m_WindowAnimationType = AnimationInfo.iMinAnimate; - AnimationInfo.iMinAnimate = 0; - ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - if (IsFullScreenMode()) { - SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN); - } - SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, -1); - - // Enable animation - AnimationInfo.iMinAnimate = m_WindowAnimationType; - ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); -} - -void CMainFrame::OnStreamAudio(UINT nID) -{ - nID -= ID_STREAM_AUDIO_NEXT; - - if (GetLoadState() != MLS::LOADED) { - return; - } - - DWORD cStreams = 0; - if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 1) { - for (DWORD i = 0; i < cStreams; i++) { - DWORD dwFlags = 0; - DWORD dwGroup = 0; - if (FAILED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { - return; - } - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - long stream_index = (i + (nID == 0 ? 1 : cStreams - 1)) % cStreams; - if (SUCCEEDED(m_pAudioSwitcherSS->Enable(stream_index, AMSTREAMSELECTENABLE_ENABLE))) { - LCID lcid = 0; - CComHeapPtr pszName; - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(m_pAudioSwitcherSS->Info(stream_index, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) { - m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pszName), lcid, 1)); - UpdateSelectedAudioStreamInfo(stream_index, pmt, lcid); - DeleteMediaType(pmt); - } - } - break; - } - } - } else if (GetPlaybackMode() == PM_FILE) { - OnStreamSelect(nID == 0, 1); - } else if (GetPlaybackMode() == PM_DVD) { - SendMessage(WM_COMMAND, ID_DVD_AUDIO_NEXT + nID); - } - - if (m_pBA && !m_fFrameSteppingActive) { - m_pBA->put_Volume(m_wndToolBar.Volume); - } -} - -void CMainFrame::OnStreamSub(UINT nID) -{ - nID -= ID_STREAM_SUB_NEXT; - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (!m_pSubStreams.IsEmpty()) { - AfxGetAppSettings().fEnableSubtitles = true; - SetSubtitle(nID == 0 ? 1 : -1, true, true); - SetFocus(); - } else if (GetPlaybackMode() == PM_FILE) { - OnStreamSelect(nID == 0, 2); - } else if (GetPlaybackMode() == PM_DVD) { - SendMessage(WM_COMMAND, ID_DVD_SUB_NEXT + nID); - } -} - -void CMainFrame::OnStreamSubOnOff() -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pCAP && !m_pSubStreams.IsEmpty() || m_pDVS) { - ToggleSubtitleOnOff(true); - SetFocus(); - } else if (GetPlaybackMode() == PM_DVD) { - SendMessage(WM_COMMAND, ID_DVD_SUB_ONOFF); - } -} - -void CMainFrame::OnDvdAngle(UINT nID) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pDVDI && m_pDVDC) { - ULONG ulAnglesAvailable, ulCurrentAngle; - if (SUCCEEDED(m_pDVDI->GetCurrentAngle(&ulAnglesAvailable, &ulCurrentAngle)) && ulAnglesAvailable > 1) { - ulCurrentAngle += (nID == ID_DVD_ANGLE_NEXT) ? 1 : -1; - if (ulCurrentAngle > ulAnglesAvailable) { - ulCurrentAngle = 1; - } else if (ulCurrentAngle < 1) { - ulCurrentAngle = ulAnglesAvailable; - } - m_pDVDC->SelectAngle(ulCurrentAngle, DVD_CMD_FLAG_Block, nullptr); - - CString osdMessage; - osdMessage.Format(IDS_AG_ANGLE, ulCurrentAngle); - m_OSD.DisplayMessage(OSD_TOPLEFT, osdMessage); - } - } -} - -void CMainFrame::OnDvdAudio(UINT nID) -{ - nID -= ID_DVD_AUDIO_NEXT; - - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pDVDI && m_pDVDC) { - ULONG nStreamsAvailable, nCurrentStream; - if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&nStreamsAvailable, &nCurrentStream)) && nStreamsAvailable > 1) { - DVD_AudioAttributes AATR; - UINT nNextStream = (nCurrentStream + (nID == 0 ? 1 : nStreamsAvailable - 1)) % nStreamsAvailable; - - HRESULT hr = m_pDVDC->SelectAudioStream(nNextStream, DVD_CMD_FLAG_Block, nullptr); - if (SUCCEEDED(m_pDVDI->GetAudioAttributes(nNextStream, &AATR))) { - CString lang; - CString strMessage; - if (AATR.Language) { - GetLocaleString(AATR.Language, LOCALE_SENGLANGUAGE, lang); - currentAudioLang = lang; - } else { - lang.Format(IDS_AG_UNKNOWN, nNextStream + 1); - currentAudioLang.Empty(); - } - - CString format = GetDVDAudioFormatName(AATR); - CString str; - - if (!format.IsEmpty()) { - str.Format(IDS_MAINFRM_11, - lang.GetString(), - format.GetString(), - AATR.dwFrequency, - AATR.bQuantization, - AATR.bNumberOfChannels, - ResStr(AATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString()); - if (FAILED(hr)) { - str += _T(" [") + ResStr(IDS_AG_ERROR) + _T("] "); - } - strMessage.Format(IDS_AUDIO_STREAM, str.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, strMessage); - } - } - } - } -} - -void CMainFrame::OnDvdSub(UINT nID) -{ - nID -= ID_DVD_SUB_NEXT; - - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pDVDI && m_pDVDC) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) - && ulStreamsAvailable > 1) { - //UINT nNextStream = (ulCurrentStream+(nID==0?1:ulStreamsAvailable-1))%ulStreamsAvailable; - int nNextStream; - - if (!bIsDisabled) { - nNextStream = ulCurrentStream + (nID == 0 ? 1 : -1); - } else { - nNextStream = (nID == 0 ? 0 : ulStreamsAvailable - 1); - } - - if (!bIsDisabled && ((nNextStream < 0) || ((ULONG)nNextStream >= ulStreamsAvailable))) { - m_pDVDC->SetSubpictureState(FALSE, DVD_CMD_FLAG_Block, nullptr); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_SUBTITLE_STREAM_OFF)); - } else { - HRESULT hr = m_pDVDC->SelectSubpictureStream(nNextStream, DVD_CMD_FLAG_Block, nullptr); - - DVD_SubpictureAttributes SATR; - m_pDVDC->SetSubpictureState(TRUE, DVD_CMD_FLAG_Block, nullptr); - if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(nNextStream, &SATR))) { - CString lang; - CString strMessage; - GetLocaleString(SATR.Language, LOCALE_SENGLANGUAGE, lang); - - if (FAILED(hr)) { - lang += _T(" [") + ResStr(IDS_AG_ERROR) + _T("] "); - } - strMessage.Format(IDS_SUBTITLE_STREAM, lang.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, strMessage); - } - } - } - } -} - -void CMainFrame::OnDvdSubOnOff() -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (m_pDVDI && m_pDVDC) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { - m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); - } - } -} - -// -// menu item handlers -// - -// file - -INT_PTR CMainFrame::DoFileDialogWithLastFolder(CFileDialog& fd, CStringW& lastPath) { - if (!lastPath.IsEmpty()) { - fd.m_ofn.lpstrInitialDir = lastPath; - } - INT_PTR ret = fd.DoModal(); - if (ret == IDOK) { - lastPath = GetFolderOnly(fd.m_ofn.lpstrFile); - } - return ret; -} - - -void CMainFrame::OnFileOpenQuick() -{ - if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar)) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - CString filter; - CAtlArray mask; - s.m_Formats.GetFilter(filter, mask); - - DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_ALLOWMULTISELECT | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - if (!s.fKeepHistory) { - dwFlags |= OFN_DONTADDTORECENT; - } - - COpenFileDlg fd(mask, true, nullptr, nullptr, dwFlags, filter, GetModalParent()); - if (DoFileDialogWithLastFolder(fd, s.lastQuickOpenPath) != IDOK) { - return; - } - - CAtlList fns; - - POSITION pos = fd.GetStartPosition(); - while (pos) { - fns.AddTail(fd.GetNextPathName(pos)); - } - - bool fMultipleFiles = false; - - if (fns.GetCount() > 1 - || fns.GetCount() == 1 - && (fns.GetHead()[fns.GetHead().GetLength() - 1] == '\\' - || fns.GetHead()[fns.GetHead().GetLength() - 1] == '*')) { - fMultipleFiles = true; - } - - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - SetForegroundWindow(); - - if (fns.GetCount() == 1) { - if (OpenBD(fns.GetHead())) { - return; - } - } - - m_wndPlaylistBar.Open(fns, fMultipleFiles); - - OpenCurPlaylistItem(); -} - -void CMainFrame::OnFileOpenmedia() -{ - if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar) || IsD3DFullScreenMode()) { - return; - } - - static COpenDlg dlg; - if (IsWindow(dlg.GetSafeHwnd()) && dlg.IsWindowVisible()) { - dlg.SetForegroundWindow(); - return; - } - if (dlg.DoModal() != IDOK || dlg.GetFileNames().IsEmpty()) { - return; - } - - if (!dlg.GetAppendToPlaylist()) { - CloseMediaBeforeOpen(); - } - - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - SetForegroundWindow(); - - CAtlList filenames; - - if (CanSendToYoutubeDL(dlg.GetFileNames().GetHead())) { - if (ProcessYoutubeDLURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist())) { - if (!dlg.GetAppendToPlaylist()) { - OpenCurPlaylistItem(); - } - return; - } else if (IsOnYDLWhitelist(dlg.GetFileNames().GetHead())) { - // don't bother trying to open this website URL directly - return; - } - } - - filenames.AddHeadList(&dlg.GetFileNames()); - - if (!dlg.HasMultipleFiles()) { - if (OpenBD(filenames.GetHead())) { - return; - } - } - - if (dlg.GetAppendToPlaylist()) { - m_wndPlaylistBar.Append(filenames, dlg.HasMultipleFiles()); - } else { - m_wndPlaylistBar.Open(filenames, dlg.HasMultipleFiles()); - - OpenCurPlaylistItem(); - } -} - -LRESULT CMainFrame::OnMPCVRSwitchFullscreen(WPARAM wParam, LPARAM lParam) -{ - const auto& s = AfxGetAppSettings(); - m_bIsMPCVRExclusiveMode = static_cast(wParam); - - m_OSD.Stop(); - if (m_bIsMPCVRExclusiveMode) { - TRACE(L"MPCVR exclusive full screen\n"); - bool excl_mode_controls = IsFullScreenMainFrame(); - if (excl_mode_controls && m_wndPlaylistBar.IsVisible()) { - m_wndPlaylistBar.SetHiddenDueToFullscreen(true); - } - if (s.fShowOSD || s.fShowDebugInfo) { - if (m_pVMB || m_pMFVMB) { - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, excl_mode_controls); - } - } - } else { - if (s.fShowOSD || s.fShowDebugInfo) { - m_OSD.Start(m_pOSDWnd); - OSDBarSetPos(); - } - if (m_wndPlaylistBar.IsHiddenDueToFullscreen()) { - m_wndPlaylistBar.SetHiddenDueToFullscreen(false); - } - } - - return 0; -} - -void CMainFrame::OnUpdateFileOpen(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() != MLS::LOADING); -} - -BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) -{ - if (AfxGetMyApp()->m_fClosingState) { - return FALSE; - } - - CAppSettings& s = AfxGetAppSettings(); - - if (m_pSkypeMoodMsgHandler && m_pSkypeMoodMsgHandler->HandleMessage(pWnd->GetSafeHwnd(), pCDS)) { - return TRUE; - } else if (pCDS->dwData != 0x6ABE51 || pCDS->cbData < sizeof(DWORD)) { - if (s.hMasterWnd) { - ProcessAPICommand(pCDS); - return TRUE; - } else { - return FALSE; - } - } - - if (m_bScanDlgOpened) { - return FALSE; - } - - DWORD len = *((DWORD*)pCDS->lpData); - TCHAR* pBuff = (TCHAR*)((DWORD*)pCDS->lpData + 1); - TCHAR* pBuffEnd = (TCHAR*)((BYTE*)pBuff + pCDS->cbData - sizeof(DWORD)); - - CAtlList cmdln; - - while (len-- > 0 && pBuff < pBuffEnd) { - CString str(pBuff); - pBuff += str.GetLength() + 1; - - cmdln.AddTail(str); - } - - s.ParseCommandLine(cmdln); - - if (s.nCLSwitches & CLSW_SLAVE) { - SendAPICommand(CMD_CONNECT, L"%d", PtrToInt(GetSafeHwnd())); - s.nCLSwitches &= ~CLSW_SLAVE; - } - - POSITION pos = s.slFilters.GetHeadPosition(); - while (pos) { - CString fullpath = MakeFullPath(s.slFilters.GetNext(pos)); - - CPath tmp(fullpath); - tmp.RemoveFileSpec(); - tmp.AddBackslash(); - CString path = tmp; - - WIN32_FIND_DATA fd; - ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); - HANDLE hFind = FindFirstFile(fullpath, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - continue; - } - - CFilterMapper2 fm2(false); - fm2.Register(path + fd.cFileName); - while (!fm2.m_filters.IsEmpty()) { - if (FilterOverride* f = fm2.m_filters.RemoveTail()) { - f->fTemporary = true; - - bool fFound = false; - - POSITION pos2 = s.m_filters.GetHeadPosition(); - while (pos2) { - FilterOverride* f2 = s.m_filters.GetNext(pos2); - if (f2->type == FilterOverride::EXTERNAL && !f2->path.CompareNoCase(f->path)) { - fFound = true; - break; - } - } - - if (!fFound) { - CAutoPtr p(f); - s.m_filters.AddHead(p); - } - } - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - } - - bool fSetForegroundWindow = false; - - auto applyRandomizeSwitch = [&]() { - if (s.nCLSwitches & CLSW_RANDOMIZE) { - m_wndPlaylistBar.Randomize(); - s.nCLSwitches &= ~CLSW_RANDOMIZE; - } - }; - - if ((s.nCLSwitches & CLSW_DVD) && !s.slFiles.IsEmpty()) { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - fSetForegroundWindow = true; - - CAutoPtr p(DEBUG_NEW OpenDVDData()); - if (p) { - p->path = s.slFiles.GetHead(); - p->subs.AddTailList(&s.slSubs); - } - OpenMedia(p); - s.nCLSwitches &= ~CLSW_DVD; - } else if (s.nCLSwitches & CLSW_CD) { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - fSetForegroundWindow = true; - - CAtlList sl; - - if (!s.slFiles.IsEmpty()) { - GetOpticalDiskType(s.slFiles.GetHead()[0], sl); - } else { - CString dir; - dir.ReleaseBufferSetLength(GetCurrentDirectory(2048, dir.GetBuffer(2048))); - - GetOpticalDiskType(dir[0], sl); - - for (TCHAR drive = _T('A'); sl.IsEmpty() && drive <= _T('Z'); drive++) { - GetOpticalDiskType(drive, sl); - } - } - - m_wndPlaylistBar.Open(sl, true); - applyRandomizeSwitch(); - OpenCurPlaylistItem(); - s.nCLSwitches &= ~CLSW_CD; - } else if (s.nCLSwitches & CLSW_DEVICE) { - SendMessage(WM_COMMAND, ID_FILE_OPENDEVICE); - s.nCLSwitches &= ~CLSW_DEVICE; - } else if (!s.slFiles.IsEmpty()) { - CAtlList sl; - sl.AddTailList(&s.slFiles); - - PathUtils::ParseDirs(sl); - - bool fMulti = sl.GetCount() > 1; - - if (!fMulti) { - sl.AddTailList(&s.slDubs); - } - - if (OpenBD(s.slFiles.GetHead())) { - // Nothing more to do - } else if (!fMulti && CPath(s.slFiles.GetHead() + _T("\\VIDEO_TS")).IsDirectory()) { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - fSetForegroundWindow = true; - - CAutoPtr p(DEBUG_NEW OpenDVDData()); - if (p) { - p->path = s.slFiles.GetHead(); - p->subs.AddTailList(&s.slSubs); - } - OpenMedia(p); - } else { - ULONGLONG tcnow = GetTickCount64(); - if (m_dwLastRun && ((tcnow - m_dwLastRun) < s.iRedirectOpenToAppendThreshold)) { - s.nCLSwitches |= CLSW_ADD; - } - m_dwLastRun = tcnow; - - if ((s.nCLSwitches & CLSW_ADD) && !IsPlaylistEmpty()) { - POSITION pos2 = sl.GetHeadPosition(); - while (pos2) { - CString fn = sl.GetNext(pos2); - if (!CanSendToYoutubeDL(fn) || !ProcessYoutubeDLURL(fn, true)) { - CAtlList sl2; - sl2.AddHead(fn); - m_wndPlaylistBar.Append(sl2, false, &s.slSubs); - } - } - - applyRandomizeSwitch(); - - if (s.nCLSwitches & (CLSW_OPEN | CLSW_PLAY)) { - m_wndPlaylistBar.SetLast(); - OpenCurPlaylistItem(); - } - } else { - //SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - fSetForegroundWindow = true; - - if (fMulti || sl.GetCount() == 1) { - bool first = true; - POSITION pos2 = sl.GetHeadPosition(); - while (pos2) { - CString fn = sl.GetNext(pos2); - if (!CanSendToYoutubeDL(fn) || !ProcessYoutubeDLURL(fn, !first, false)) { - CAtlList sl2; - sl2.AddHead(fn); - if (first) { - m_wndPlaylistBar.Open(sl2, false, &s.slSubs); - } else { - m_wndPlaylistBar.Append(sl2, false, &s.slSubs); - } - } - first = false; - } - } else { - // video + dub - m_wndPlaylistBar.Open(sl, false, &s.slSubs); - } - - applyRandomizeSwitch(); - if (sl.GetCount() != 1 || !IsPlaylistFile(sl.GetHead())) { //playlists already set first pos (or saved pos) - m_wndPlaylistBar.SetFirst(); - } - OpenCurPlaylistItem((s.nCLSwitches & CLSW_STARTVALID) ? s.rtStart : 0, false, s.abRepeat); - - s.nCLSwitches &= ~CLSW_STARTVALID; - s.rtStart = 0; - } - s.nCLSwitches &= ~CLSW_ADD; - } - } else if ((s.nCLSwitches & CLSW_PLAY) && !IsPlaylistEmpty()) { - OpenCurPlaylistItem(); - } else { - applyRandomizeSwitch(); - } - - if (s.nCLSwitches & CLSW_PRESET1) { - SendMessage(WM_COMMAND, ID_VIEW_PRESETS_MINIMAL); - s.nCLSwitches &= ~CLSW_PRESET1; - } else if (s.nCLSwitches & CLSW_PRESET2) { - SendMessage(WM_COMMAND, ID_VIEW_PRESETS_COMPACT); - s.nCLSwitches &= ~CLSW_PRESET2; - } else if (s.nCLSwitches & CLSW_PRESET3) { - SendMessage(WM_COMMAND, ID_VIEW_PRESETS_NORMAL); - s.nCLSwitches &= ~CLSW_PRESET3; - } - if (s.nCLSwitches & CLSW_VOLUME) { - if (IsMuted()) { - SendMessage(WM_COMMAND, ID_VOLUME_MUTE); - } - m_wndToolBar.SetVolume(s.nCmdVolume); - s.nCLSwitches &= ~CLSW_VOLUME; - } - if (s.nCLSwitches & CLSW_MUTE) { - if (!IsMuted()) { - SendMessage(WM_COMMAND, ID_VOLUME_MUTE); - } - s.nCLSwitches &= ~CLSW_MUTE; - } - - if (fSetForegroundWindow && !(s.nCLSwitches & CLSW_NOFOCUS)) { - SetForegroundWindow(); - } - - return TRUE; -} - -int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) -{ - switch (uMsg) { - case BFFM_INITIALIZED: { - //Initial directory is set here - const CAppSettings& s = AfxGetAppSettings(); - if (!s.strDVDPath.IsEmpty()) { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)s.strDVDPath); - } - break; - } - default: - break; - } - return 0; -} - -void CMainFrame::OpenDVDOrBD(CStringW path) { - if (!path.IsEmpty()) { - AfxGetAppSettings().strDVDPath = path; - if (!OpenBD(path)) { - CAutoPtr p(DEBUG_NEW OpenDVDData()); - p->path = path; - p->path.Replace(_T('/'), _T('\\')); - p->path = ForceTrailingSlash(p->path); - - OpenMedia(p); - } - } -} - -void CMainFrame::OnFileOpendvd() -{ - if ((GetLoadState() == MLS::LOADING) || IsD3DFullScreenMode()) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - CString strTitle(StrRes(IDS_MAINFRM_46)); - CString path; - - if (s.fUseDVDPath && !s.strDVDPath.IsEmpty()) { - path = s.strDVDPath; - } else { - //strDVDPath is actually used as a default to open without the dialog, - //but since it is always updated to the last path chosen, - //we can use it as the default for the dialog, too - CFolderPickerDialog fd(ForceTrailingSlash(s.strDVDPath), FOS_PATHMUSTEXIST, GetModalParent()); - fd.m_ofn.lpstrTitle = strTitle; - - if (fd.DoModal() == IDOK) { - path = fd.GetPathName(); //getfolderpath() does not work correctly for CFolderPickerDialog - } else { - return; - } - } - OpenDVDOrBD(path); -} - -void CMainFrame::OnFileOpendevice() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (GetLoadState() == MLS::LOADING) { - return; - } - - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - SetForegroundWindow(); - - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - - m_wndPlaylistBar.Empty(); - - if (s.iDefaultCaptureDevice == 0 && s.strAnalogVideo == L"dummy" && s.strAnalogAudio == L"dummy") { - // device not configured yet, open settings - ShowOptions(IDD_PPAGECAPTURE); - return; - } - - CAutoPtr p(DEBUG_NEW OpenDeviceData()); - if (p) { - p->DisplayName[0] = s.strAnalogVideo; - p->DisplayName[1] = s.strAnalogAudio; - } - OpenMedia(p); -} - -void CMainFrame::OnFileOpenOpticalDisk(UINT nID) -{ - nID -= ID_FILE_OPEN_OPTICAL_DISK_START; - - nID++; - for (TCHAR drive = _T('A'); drive <= _T('Z'); drive++) { - CAtlList sl; - - OpticalDiskType_t discType = GetOpticalDiskType(drive, sl); - switch (discType) { - case OpticalDisk_Audio: - case OpticalDisk_VideoCD: - case OpticalDisk_DVDVideo: - case OpticalDisk_BD: - nID--; - break; - default: - break; - } - - if (nID == 0) { - if (OpticalDisk_BD == discType || OpticalDisk_DVDVideo == discType) { - OpenDVDOrBD(CStringW(drive) + L":\\"); - } else { - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - SetForegroundWindow(); - - if (IsIconic()) { - ShowWindow(SW_RESTORE); - } - - m_wndPlaylistBar.Open(sl, true); - OpenCurPlaylistItem(); - } - break; - } - } -} - -void CMainFrame::OnFileRecycle() -{ - // check if a file is playing - if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_FILE) { - return; - } - - OAFilterState fs = GetMediaState(); - if (fs == State_Running) { - MediaControlPause(true); - } - - m_wndPlaylistBar.DeleteFileInPlaylist(m_wndPlaylistBar.m_pl.GetPos()); -} - -void CMainFrame::OnFileReopen() -{ - if (!m_LastOpenBDPath.IsEmpty() && OpenBD(m_LastOpenBDPath)) { - return; - } - - // save playback position - if (GetLoadState() == MLS::LOADED) { - if (m_bRememberFilePos && !m_fEndOfStream && m_dwReloadPos == 0 && m_pMS) { - auto& s = AfxGetAppSettings(); - REFERENCE_TIME rtNow = 0; - m_pMS->GetCurrentPosition(&rtNow); - m_dwReloadPos = rtNow; - s.MRU.UpdateCurrentFilePosition(rtNow, true); - } - reloadABRepeat = abRepeat; - } - - OpenCurPlaylistItem(0, true); -} - -DROPEFFECT CMainFrame::OnDropAccept(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) -{ - ClientToScreen(&point); - if (CMouse::CursorOnRootWindow(point, *this)) { - UpdateControlState(UPDATE_CONTROLS_VISIBILITY); - return (dwKeyState & MK_CONTROL) ? (DROPEFFECT_COPY | DROPEFFECT_APPEND) - : (DROPEFFECT_MOVE | DROPEFFECT_LINK | DROPEFFECT_COPY); - } - - return DROPEFFECT_NONE; -} - -bool CMainFrame::IsImageFile(CStringW fn) { - CPath path(fn); - CStringW ext(path.GetExtension()); - return IsImageFileExt(ext); -} - -bool CMainFrame::IsImageFileExt(CStringW ext) { - ext.MakeLower(); - return ( - ext == _T(".jpg") || ext == _T(".jpeg") || ext == _T(".png") || ext == _T(".gif") || ext == _T(".bmp") - || ext == _T(".tiff") || ext == _T(".jpe") || ext == _T(".tga") || ext == _T(".heic") || ext == _T(".avif") - ); -} - -bool CMainFrame::IsPlaylistFile(CStringW fn) { - CPath path(fn); - CStringW ext(path.GetExtension()); - return IsPlaylistFileExt(ext); -} - -bool CMainFrame::IsPlaylistFileExt(CStringW ext) { - return (ext == _T(".m3u") || ext == _T(".m3u8") || ext == _T(".mpcpl") || ext == _T(".pls") || ext == _T(".cue") || ext == _T(".asx")); -} - -bool CMainFrame::IsAudioOrVideoFileExt(CStringW ext) { - return IsPlayableFormatExt(ext); -} - -bool CMainFrame::IsAudioFileExt(CStringW ext) { - const CMediaFormats& mf = AfxGetAppSettings().m_Formats; - ext.MakeLower(); - return mf.FindExt(ext, true); -} - -bool CMainFrame::IsPlayableFormatExt(CStringW ext) { - const CMediaFormats& mf = AfxGetAppSettings().m_Formats; - ext.MakeLower(); - return mf.FindExt(ext); -} - -bool CMainFrame::CanSkipToExt(CStringW ext, CStringW curExt) -{ - if (IsImageFileExt(curExt)) { - return IsImageFileExt(ext); - } else { - return IsPlayableFormatExt(ext); - } -} - -BOOL IsSubtitleExtension(CString ext) -{ - return (ext == _T(".srt") || ext == _T(".ssa") || ext == _T(".ass") || ext == _T(".idx") || ext == _T(".sub") || ext == _T(".webvtt") || ext == _T(".vtt") || ext == _T(".sup") || ext == _T(".smi") || ext == _T(".psb") || ext == _T(".usf") || ext == _T(".xss") || ext == _T(".rt")|| ext == _T(".txt")); -} - -BOOL IsSubtitleFilename(CString filename) -{ - CString ext = CPath(filename).GetExtension().MakeLower(); - return IsSubtitleExtension(ext); -} - -bool CMainFrame::IsAudioFilename(CString filename) -{ - CString ext = CPath(filename).GetExtension(); - return IsAudioFileExt(ext); -} - -void CMainFrame::OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) -{ - SetForegroundWindow(); - - if (slFiles.IsEmpty()) { - return; - } - - if (slFiles.GetCount() == 1 && OpenBD(slFiles.GetHead())) { - return; - } - - PathUtils::ParseDirs(slFiles); - - bool bAppend = !!(dropEffect & DROPEFFECT_APPEND); - - // Check for subtitle files - SubtitleInput subInputSelected; - CString subfile; - BOOL onlysubs = true; - BOOL subloaded = false; - BOOL canLoadSub = !bAppend && !m_fAudioOnly && GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode(); - BOOL canLoadSubISR = canLoadSub && m_pCAP && (!m_pDVS || AfxGetAppSettings().IsISRAutoLoadEnabled()); - POSITION pos = slFiles.GetHeadPosition(); - while (pos) { - SubtitleInput subInput; - POSITION curpos = pos; - subfile = slFiles.GetNext(pos); - if (IsSubtitleFilename(subfile)) { - // remove subtitle file from list - slFiles.RemoveAt(curpos); - // try to load it - if (onlysubs && canLoadSub) { - if (canLoadSubISR && LoadSubtitle(subfile, &subInput, False)) { - if (!subInputSelected.pSubStream) { - // first one - subInputSelected = subInput; - } - subloaded = true; - } else if (m_pDVS && slFiles.IsEmpty()) { - if (SUCCEEDED(m_pDVS->put_FileName((LPWSTR)(LPCWSTR)subfile))) { - m_pDVS->put_SelectedLanguage(0); - m_pDVS->put_HideSubtitles(true); - m_pDVS->put_HideSubtitles(false); - subloaded = true; - } - } - } - } - else { - onlysubs = false; - } - } - - if (onlysubs) { - if (subInputSelected.pSubStream) { - AfxGetAppSettings().fEnableSubtitles = true; - SetSubtitle(subInputSelected); - } - if (subloaded) { - CPath fn(subfile); - fn.StripPath(); - CString statusmsg(static_cast(fn)); - SendStatusMessage(statusmsg + ResStr(IDS_SUB_LOADED_SUCCESS), 3000); - } else { - SendStatusMessage(_T("Failed to load subtitle file"), 3000); - } - return; - } - - // load http url with youtube-dl, if available - if (CanSendToYoutubeDL(slFiles.GetHead())) { - CloseMediaBeforeOpen(); - if (ProcessYoutubeDLURL(slFiles.GetHead(), bAppend)) { - if (!bAppend) { - OpenCurPlaylistItem(); - } - return; - } else if (IsOnYDLWhitelist(slFiles.GetHead())) { - // don't bother trying to open this website URL directly - return; - } - } - - // add remaining items - if (bAppend) { - m_wndPlaylistBar.Append(slFiles, true); - } else { - m_wndPlaylistBar.Open(slFiles, true); - OpenCurPlaylistItem(); - } -} - -void CMainFrame::OnFileSaveAs() -{ - CString in, out, ext; - CAppSettings& s = AfxGetAppSettings(); - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - in = pli.m_fns.GetHead(); - } else { - return; - } - - if (pli.m_bYoutubeDL || PathUtils::IsURL(in)) { - // URL - if (pli.m_bYoutubeDL) { - out = _T("%(title)s.%(ext)s"); - } else { - out = _T("choose_a_filename"); - } - } else { - out = PathUtils::StripPathOrUrl(in); - ext = CPath(out).GetExtension().MakeLower(); - if (ext == _T(".cda")) { - out = out.Left(out.GetLength() - 4) + _T(".wav"); - } else if (ext == _T(".ifo")) { - out = out.Left(out.GetLength() - 4) + _T(".vob"); - } - } - - if (!pli.m_bYoutubeDL || pli.m_ydlSourceURL.IsEmpty() || (AfxGetAppSettings().sYDLCommandLine.Find(_T("-o ")) < 0)) { - CFileDialog fd(FALSE, 0, out, - OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR, - ResStr(IDS_ALL_FILES_FILTER), GetModalParent(), 0); - if (DoFileDialogWithLastFolder(fd, s.lastFileSaveCopyPath) != IDOK || !in.CompareNoCase(fd.GetPathName())) { - return; - } else { - out = fd.GetPathName(); - } - } - - if (pli.m_bYoutubeDL && !pli.m_ydlSourceURL.IsEmpty()) { - DownloadWithYoutubeDL(pli.m_ydlSourceURL, out); - return; - } - - CPath p(out); - if (!ext.IsEmpty()) { - p.AddExtension(ext); - } - - OAFilterState fs = State_Stopped; - if (m_pMC) { - m_pMC->GetState(0, &fs); - if (fs == State_Running) { - MediaControlPause(true); - } - } - - CSaveDlg dlg(in, p); - dlg.DoModal(); - - if (m_pMC && fs == State_Running) { - MediaControlRun(); - } -} - -void CMainFrame::OnUpdateFileSaveAs(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_FILE); -} - -bool CMainFrame::GetDIB(BYTE** ppData, long& size, bool fSilent) -{ - if (!ppData) { - return false; - } - if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { - return false; - } - OAFilterState fs = GetMediaState(); - if (fs != State_Paused && fs != State_Running) { - return false; - } - - *ppData = nullptr; - size = 0; - - if (fs == State_Running && !m_pCAP) { - MediaControlPause(true); // wait for completion - } - - HRESULT hr = S_OK; - CString errmsg; - - do { - if (m_pCAP) { - hr = m_pCAP->GetDIB(nullptr, (DWORD*)&size); - if (FAILED(hr)) { - errmsg.Format(IDS_GETDIB_FAILED, hr); - break; - } - - *ppData = DEBUG_NEW BYTE[size]; - if (!(*ppData)) { - return false; - } - - hr = m_pCAP->GetDIB(*ppData, (DWORD*)&size); - if (FAILED(hr)) { - errmsg.Format(IDS_GETDIB_FAILED, hr); - break; - } - } else if (m_pMFVDC) { - // Capture with EVR - BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER)}; - BYTE* pDib; - DWORD dwSize; - REFERENCE_TIME rtImage = 0; - hr = m_pMFVDC->GetCurrentImage(&bih, &pDib, &dwSize, &rtImage); - if (FAILED(hr) || dwSize == 0) { - errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); - break; - } - - size = (long)dwSize + sizeof(BITMAPINFOHEADER); - *ppData = DEBUG_NEW BYTE[size]; - if (!(*ppData)) { - return false; - } - memcpy_s(*ppData, size, &bih, sizeof(BITMAPINFOHEADER)); - memcpy_s(*ppData + sizeof(BITMAPINFOHEADER), size - sizeof(BITMAPINFOHEADER), pDib, dwSize); - CoTaskMemFree(pDib); - } else { - hr = m_pBV->GetCurrentImage(&size, nullptr); - if (FAILED(hr) || size == 0) { - errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); - break; - } - - *ppData = DEBUG_NEW BYTE[size]; - if (!(*ppData)) { - return false; - } - - hr = m_pBV->GetCurrentImage(&size, (long*)*ppData); - if (FAILED(hr)) { - errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); - break; - } - } - } while (0); - - if (!fSilent) { - if (!errmsg.IsEmpty()) { - AfxMessageBox(errmsg, MB_OK); - } - } - - if (fs == State_Running && GetMediaState() != State_Running) { - MediaControlRun(); - } - - if (FAILED(hr)) { - SAFE_DELETE_ARRAY(*ppData); - return false; - } - - return true; -} - -void CMainFrame::SaveDIB(LPCTSTR fn, BYTE* pData, long size) -{ - CPath path(fn); - - PBITMAPINFO bi = reinterpret_cast(pData); - PBITMAPINFOHEADER bih = &bi->bmiHeader; - int bpp = bih->biBitCount; - - if (bpp != 16 && bpp != 24 && bpp != 32) { - AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); - return; - } - int w = bih->biWidth; - int h = abs(bih->biHeight); - int srcpitch = w * (bpp >> 3); - int dstpitch = (w * 3 + 3) / 4 * 4; // round w * 3 to next multiple of 4 - - BYTE* p = DEBUG_NEW BYTE[dstpitch * h]; - - const BYTE* src = pData + sizeof(*bih); - - BitBltFromRGBToRGB(w, h, p, dstpitch, 24, (BYTE*)src + srcpitch * (h - 1), -srcpitch, bpp); - - { - Gdiplus::GdiplusStartupInput gdiplusStartupInput; - ULONG_PTR gdiplusToken; - Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); - - Gdiplus::Bitmap* bm = new Gdiplus::Bitmap(w, h, dstpitch, PixelFormat24bppRGB, p); - - UINT num; // number of image encoders - UINT arraySize; // size, in bytes, of the image encoder array - - // How many encoders are there? - // How big (in bytes) is the array of all ImageCodecInfo objects? - Gdiplus::GetImageEncodersSize(&num, &arraySize); - - // Create a buffer large enough to hold the array of ImageCodecInfo - // objects that will be returned by GetImageEncoders. - Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)DEBUG_NEW BYTE[arraySize]; - - // GetImageEncoders creates an array of ImageCodecInfo objects - // and copies that array into a previously allocated buffer. - // The third argument, imageCodecInfos, is a pointer to that buffer. - Gdiplus::GetImageEncoders(num, arraySize, pImageCodecInfo); - - Gdiplus::EncoderParameters* pEncoderParameters = nullptr; - - // Find the mime type based on the extension - CString ext(path.GetExtension()); - CStringW mime; - if (ext == _T(".jpg")) { - mime = L"image/jpeg"; - - // Set the encoder parameter for jpeg quality - pEncoderParameters = DEBUG_NEW Gdiplus::EncoderParameters; - ULONG quality = AfxGetAppSettings().nJpegQuality; - - pEncoderParameters->Count = 1; - pEncoderParameters->Parameter[0].Guid = Gdiplus::EncoderQuality; - pEncoderParameters->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong; - pEncoderParameters->Parameter[0].NumberOfValues = 1; - pEncoderParameters->Parameter[0].Value = &quality; - } else if (ext == _T(".bmp")) { - mime = L"image/bmp"; - } else { - mime = L"image/png"; - } - - // Get the encoder clsid - CLSID encoderClsid = CLSID_NULL; - for (UINT i = 0; i < num && encoderClsid == CLSID_NULL; i++) { - if (wcscmp(pImageCodecInfo[i].MimeType, mime) == 0) { - encoderClsid = pImageCodecInfo[i].Clsid; - } - } - - Gdiplus::Status s = bm->Save(fn, &encoderClsid, pEncoderParameters); - - // All GDI+ objects must be destroyed before GdiplusShutdown is called - delete bm; - delete [] pImageCodecInfo; - delete pEncoderParameters; - Gdiplus::GdiplusShutdown(gdiplusToken); - delete [] p; - - if (s != Gdiplus::Ok) { - AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); - return; - } - } - - path.m_strPath.Replace(_T("\\\\"), _T("\\")); - - SendStatusMessage(m_wndStatusBar.PreparePathStatusMessage(path), 3000); -} - -HRESULT GetBasicVideoFrame(IBasicVideo* pBasicVideo, std::vector& dib) { - // IBasicVideo::GetCurrentImage() gives the original frame - - long size; - - HRESULT hr = pBasicVideo->GetCurrentImage(&size, nullptr); - if (FAILED(hr)) { - return hr; - } - if (size <= 0) { - return E_ABORT; - } - - dib.resize(size); - - hr = pBasicVideo->GetCurrentImage(&size, (long*)dib.data()); - if (FAILED(hr)) { - dib.clear(); - } - - return hr; -} - -HRESULT GetVideoDisplayControlFrame(IMFVideoDisplayControl* pVideoDisplayControl, std::vector& dib) { - // IMFVideoDisplayControl::GetCurrentImage() gives the displayed frame - - BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER) }; - BYTE* pDib; - DWORD size; - REFERENCE_TIME rtImage = 0; - - HRESULT hr = pVideoDisplayControl->GetCurrentImage(&bih, &pDib, &size, &rtImage); - if (S_OK != hr) { - return hr; - } - if (size == 0) { - return E_ABORT; - } - - dib.resize(sizeof(BITMAPINFOHEADER) + size); - - memcpy(dib.data(), &bih, sizeof(BITMAPINFOHEADER)); - memcpy(dib.data() + sizeof(BITMAPINFOHEADER), pDib, size); - CoTaskMemFree(pDib); - - return hr; -} - -HRESULT GetMadVRFrameGrabberFrame(IMadVRFrameGrabber* pMadVRFrameGrabber, std::vector& dib, bool displayed) { - LPVOID dibImage = nullptr; - HRESULT hr; - - if (displayed) { - hr = pMadVRFrameGrabber->GrabFrame(ZOOM_PLAYBACK_SIZE, 0, 0, 0, 0, 0, &dibImage, 0); - } else { - hr = pMadVRFrameGrabber->GrabFrame(ZOOM_ENCODED_SIZE, 0, 0, 0, 0, 0, &dibImage, 0); - } - - if (S_OK != hr) { - return hr; - } - if (!dibImage) { - return E_ABORT; - } - - const BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)dibImage; - - dib.resize(sizeof(BITMAPINFOHEADER) + bih->biSizeImage); - memcpy(dib.data(), dibImage, sizeof(BITMAPINFOHEADER) + bih->biSizeImage); - LocalFree(dibImage); - - return hr; -} - -HRESULT CMainFrame::GetDisplayedImage(std::vector& dib, CString& errmsg) { - errmsg.Empty(); - HRESULT hr; - - if (m_pCAP) { - LPVOID dibImage = nullptr; - hr = m_pCAP->GetDisplayedImage(&dibImage); - - if (S_OK == hr && dibImage) { - const BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)dibImage; - dib.resize(sizeof(BITMAPINFOHEADER) + bih->biSizeImage); - memcpy(dib.data(), dibImage, sizeof(BITMAPINFOHEADER) + bih->biSizeImage); - LocalFree(dibImage); - } - } - else if (m_pMFVDC) { - hr = GetVideoDisplayControlFrame(m_pMFVDC, dib); - } else if (m_pMVRFG) { - hr = GetMadVRFrameGrabberFrame(m_pMVRFG, dib, true); - } else { - hr = E_NOINTERFACE; - } - - if (FAILED(hr)) { - errmsg.Format(L"CMainFrame::GetCurrentImage() failed, 0x%08x", hr); - } - - return hr; -} - -HRESULT CMainFrame::GetCurrentFrame(std::vector& dib, CString& errmsg) { - HRESULT hr = S_OK; - errmsg.Empty(); - - OAFilterState fs = GetMediaState(); - if (m_eMediaLoadState != MLS::LOADED || m_fAudioOnly || (fs != State_Paused && fs != State_Running)) { - return E_ABORT; - } - - if (fs == State_Running && !m_pCAP) { - MediaControlPause(true); //wait for completion - } - - if (m_pCAP) { - DWORD size; - hr = m_pCAP->GetDIB(nullptr, &size); - - if (S_OK == hr) { - dib.resize(size); - hr = m_pCAP->GetDIB(dib.data(), &size); - } - - if (FAILED(hr)) { - errmsg.Format(L"ISubPicAllocatorPresenter3::GetDIB() failed, 0x%08x", hr); - } - } else if (m_pBV) { - hr = GetBasicVideoFrame(m_pBV, dib); - - if (hr == E_NOINTERFACE && m_pMFVDC) { - // hmm, EVR is not able to give the original frame, giving the displayed image - hr = GetDisplayedImage(dib, errmsg); - } else if (FAILED(hr)) { - errmsg.Format(L"IBasicVideo::GetCurrentImage() failed, 0x%08x", hr); - } - } else { - hr = E_POINTER; - errmsg.Format(L"Interface not found!"); - } - - if (fs == State_Running && GetMediaState() != State_Running) { - MediaControlRun(); - } - - return hr; -} - -HRESULT CMainFrame::GetOriginalFrame(std::vector& dib, CString& errmsg) { - HRESULT hr = S_OK; - errmsg.Empty(); - - if (m_pMVRFG) { - hr = GetMadVRFrameGrabberFrame(m_pMVRFG, dib, false); - if (FAILED(hr)) { - errmsg.Format(L"IMadVRFrameGrabber::GrabFrame() failed, 0x%08x", hr); - } - } else { - hr = GetCurrentFrame(dib, errmsg); - } - - return hr; -} - -HRESULT CMainFrame::RenderCurrentSubtitles(BYTE* pData) { - ASSERT(m_pCAP && AfxGetAppSettings().bSnapShotSubtitles && !m_pMVRFG && AfxGetAppSettings().fEnableSubtitles && AfxGetAppSettings().IsISRAutoLoadEnabled()); - CheckPointer(pData, E_FAIL); - HRESULT hr = S_FALSE; - - if (CComQIPtr pSubPicProvider = m_pCurrentSubInput.pSubStream) { - const PBITMAPINFOHEADER bih = (PBITMAPINFOHEADER)pData; - const int width = bih->biWidth; - const int height = bih->biHeight; - - REFERENCE_TIME rtNow = 0; - m_pMS->GetCurrentPosition(&rtNow); - - int delay = m_pCAP->GetSubtitleDelay(); - if (delay != 0) { - if (delay > 0 && delay * 10000LL > rtNow) { - return S_FALSE; - } else { - rtNow -= delay * 10000LL; - } - } - - int subWidth = width; - int subHeight = height; - bool needsResize = false; - if (CPGSSub* pgsSub = dynamic_cast(pSubPicProvider.p)) { - CSize sz; - if (SUCCEEDED(pgsSub->GetPresentationSegmentTextureSize(rtNow, sz))) { - subWidth = sz.cx; - subHeight = sz.cy; - needsResize = true; - } - } - - SubPicDesc spdRender; - - spdRender.type = MSP_RGB32; - spdRender.w = subWidth; - spdRender.h = abs(subHeight); - spdRender.bpp = 32; - spdRender.pitch = subWidth * 4; - spdRender.vidrect = { 0, 0, width, height }; - spdRender.bits = DEBUG_NEW BYTE[spdRender.pitch * spdRender.h]; - - CComPtr pSubPicAllocator = DEBUG_NEW CMemSubPicAllocator(spdRender.type, CSize(spdRender.w, spdRender.h)); - - CMemSubPic memSubPic(spdRender, pSubPicAllocator); - memSubPic.SetInverseAlpha(false); - memSubPic.ClearDirtyRect(); - - RECT bbox = {}; - hr = pSubPicProvider->Render(spdRender, rtNow, m_pCAP->GetFPS(), bbox); - if (needsResize) { - memSubPic.UnlockARGB(); - } - - if (S_OK == hr) { - SubPicDesc spdTarget; - spdTarget.type = MSP_RGB32; - spdTarget.w = width; - spdTarget.h = height; - spdTarget.bpp = 32; - spdTarget.pitch = -width * 4; - spdTarget.vidrect = { 0, 0, width, height }; - spdTarget.bits = (BYTE*)(bih + 1) + (width * 4) * (height - 1); - - hr = memSubPic.AlphaBlt(&spdRender.vidrect, &spdTarget.vidrect, &spdTarget); - } - } - - return hr; -} - -void CMainFrame::SaveImage(LPCWSTR fn, bool displayed, bool includeSubtitles) { - std::vector dib; - CString errmsg; - HRESULT hr; - if (displayed) { - hr = GetDisplayedImage(dib, errmsg); - } else { - hr = GetCurrentFrame(dib, errmsg); - if (includeSubtitles && m_pCAP && hr == S_OK) { - RenderCurrentSubtitles(dib.data()); - } - } - - if (hr == S_OK) { - SaveDIB(fn, dib.data(), (long)dib.size()); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_IMAGE_SAVED), 3000); - } else { - m_OSD.DisplayMessage(OSD_TOPLEFT, errmsg, 3000); - } -} - -void CMainFrame::SaveThumbnails(LPCTSTR fn) -{ - if (!m_pMC || !m_pMS || GetPlaybackMode() != PM_FILE /*&& GetPlaybackMode() != PM_DVD*/) { - return; - } - - REFERENCE_TIME rtPos = GetPos(); - REFERENCE_TIME rtDur = GetDur(); - - if (rtDur <= 0) { - AfxMessageBox(IDS_THUMBNAILS_NO_DURATION, MB_ICONWARNING | MB_OK, 0); - return; - } - - OAFilterState filterState = UpdateCachedMediaState(); - bool bWasStopped = (filterState == State_Stopped); - if (filterState != State_Paused) { - OnPlayPause(); - } - - CSize szVideoARCorrected, szVideo, szAR; - - if (m_pCAP) { - szVideo = m_pCAP->GetVideoSize(false); - szAR = m_pCAP->GetVideoSize(true); - } else if (m_pMFVDC) { - VERIFY(SUCCEEDED(m_pMFVDC->GetNativeVideoSize(&szVideo, &szAR))); - } else { - VERIFY(SUCCEEDED(m_pBV->GetVideoSize(&szVideo.cx, &szVideo.cy))); - - CComQIPtr pBV2 = m_pBV; - long lARx = 0, lARy = 0; - if (pBV2 && SUCCEEDED(pBV2->GetPreferredAspectRatio(&lARx, &lARy)) && lARx > 0 && lARy > 0) { - szAR.SetSize(lARx, lARy); - } - } - - if (szVideo.cx <= 0 || szVideo.cy <= 0) { - AfxMessageBox(IDS_THUMBNAILS_NO_FRAME_SIZE, MB_ICONWARNING | MB_OK, 0); - return; - } - - // with the overlay mixer IBasicVideo2 won't tell the new AR when changed dynamically - DVD_VideoAttributes VATR; - if (GetPlaybackMode() == PM_DVD && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { - szAR.SetSize(VATR.ulAspectX, VATR.ulAspectY); - } - - szVideoARCorrected = (szAR.cx <= 0 || szAR.cy <= 0) ? szVideo : CSize(MulDiv(szVideo.cy, szAR.cx, szAR.cy), szVideo.cy); - - const CAppSettings& s = AfxGetAppSettings(); - - int cols = std::clamp(s.iThumbCols, 1, 16); - int rows = std::clamp(s.iThumbRows, 1, 40); - - const int margin = 5; - int width = std::clamp(s.iThumbWidth, 256, 3840); - float fontscale = width / 1280.0; - int fontsize = fontscale * 16; - const int infoheight = 4 * fontsize + 6 + 2 * margin; - int height = width * szVideoARCorrected.cy / szVideoARCorrected.cx * rows / cols + infoheight; - - int dibsize = sizeof(BITMAPINFOHEADER) + width * height * 4; - - CAutoVectorPtr dib; - if (!dib.Allocate(dibsize)) { - AfxMessageBox(IDS_OUT_OF_MEMORY, MB_ICONWARNING | MB_OK, 0); - return; - } - - BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)(BYTE*)dib; - ZeroMemory(bih, sizeof(BITMAPINFOHEADER)); - bih->biSize = sizeof(BITMAPINFOHEADER); - bih->biWidth = width; - bih->biHeight = height; - bih->biPlanes = 1; - bih->biBitCount = 32; - bih->biCompression = BI_RGB; - bih->biSizeImage = width * height * 4; - memsetd(bih + 1, 0xffffff, bih->biSizeImage); - - SubPicDesc spd; - spd.w = width; - spd.h = height; - spd.bpp = 32; - spd.pitch = -width * 4; - spd.vidrect = CRect(0, 0, width, height); - spd.bits = (BYTE*)(bih + 1) + (width * 4) * (height - 1); - - bool darktheme = s.bMPCTheme && s.eModernThemeMode == CMPCTheme::ModernThemeMode::DARK; - - int gradientBase = 0xe0; - if (darktheme) { - gradientBase = 0x00; - } - // Paint the background - { - BYTE* p = (BYTE*)spd.bits; - for (int y = 0; y < spd.h; y++, p += spd.pitch) { - for (int x = 0; x < spd.w; x++) { - ((DWORD*)p)[x] = 0x010101 * (gradientBase + 0x08 * y / spd.h + 0x18 * (spd.w - x) / spd.w); - } - } - } - - CCritSec csSubLock; - RECT bbox; - CSize szThumbnail((width - margin * 2) / cols - margin * 2, (height - margin * 2 - infoheight) / rows - margin * 2); - // Ensure the thumbnails aren't ridiculously small so that the time indication can at least fit - if (szThumbnail.cx < 60 || szThumbnail.cy < 20) { - AfxMessageBox(IDS_THUMBNAIL_TOO_SMALL, MB_ICONWARNING | MB_OK, 0); - return; - } - - m_nVolumeBeforeFrameStepping = m_wndToolBar.Volume; - if (m_pBA) { - m_pBA->put_Volume(-10000); - } - - // Draw the thumbnails - std::unique_ptr thumb(new(std::nothrow) BYTE[szThumbnail.cx * szThumbnail.cy * 4]); - if (!thumb) { - return; - } - - int pics = cols * rows; - REFERENCE_TIME rtInterval = rtDur / (pics + 1LL); - for (int i = 1; i <= pics; i++) { - REFERENCE_TIME rt = rtInterval * i; - // use a keyframe if close to target time - if (rtInterval >= 100000000LL) { - REFERENCE_TIME rtMaxDiff = std::min(100000000LL, rtInterval / 10); // no more than 10 sec - rt = GetClosestKeyFrame(rt, rtMaxDiff, rtMaxDiff); - } - - DoSeekTo(rt, false); - UpdateWindow(); - - HRESULT hr = m_pFS ? m_pFS->Step(1, nullptr) : E_FAIL; - if (FAILED(hr)) { - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - AfxMessageBox(IDS_FRAME_STEP_ERROR_RENDERER, MB_ICONEXCLAMATION | MB_OK, 0); - return; - } - - bool abortloop = false; - HANDLE hGraphEvent = nullptr; - m_pME->GetEventHandle((OAEVENT*)&hGraphEvent); - while (hGraphEvent) { - DWORD res = WaitForSingleObject(hGraphEvent, 5000); - if (res == WAIT_OBJECT_0) { - LONG evCode = 0; - LONG_PTR evParam1, evParam2; - while (m_pME && SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) { - m_pME->FreeEventParams(evCode, evParam1, evParam2); - if (EC_STEP_COMPLETE == evCode) { - hGraphEvent = nullptr; - } - } - } else { - hGraphEvent = nullptr; - if (res == WAIT_TIMEOUT) { - // Likely a seek failure has occurred. For example due to an incomplete file. - REFERENCE_TIME rtCur = 0; - m_pMS->GetCurrentPosition(&rtCur); - if (rtCur >= rtDur) { - abortloop = true; - } - } - } - } - - if (abortloop) { - break; - } - - int col = (i - 1) % cols; - int row = (i - 1) / cols; - - CPoint p(2 * margin + col * (szThumbnail.cx + 2 * margin), infoheight + 2 * margin + row * (szThumbnail.cy + 2 * margin)); - CRect r(p, szThumbnail); - - CRenderedTextSubtitle rts(&csSubLock); - rts.m_SubRendererSettings.renderSSAUsingLibass = false; - rts.m_SubRendererSettings.overrideDefaultStyle = false; - rts.m_SubRendererSettings.overrideAllStyles = false; - rts.CreateDefaultStyle(0); - rts.m_storageRes = rts.m_playRes = CSize(width, height); - STSStyle* style = DEBUG_NEW STSStyle(); - style->fontName = L"Calibri"; - style->marginRect.SetRectEmpty(); - rts.AddStyle(_T("thumbs"), style); - - DVD_HMSF_TIMECODE hmsf = RT2HMS_r(rt); - CStringW str; - if (!darktheme) { - str.Format(L"{\\an7\\1c&Hffffff&\\4a&Hb0&\\bord1\\shad4\\be1}{\\p1}m %d %d l %d %d %d %d %d %d{\\p}", - r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom); - rts.Add(str, true, MS2RT(0), MS2RT(1), _T("thumbs")); // Thumbnail background - } - str.Format(L"{\\an3\\1c&Hffffff&\\3c&H000000&\\alpha&H80&\\fs%d\\b1\\bord2\\shad0\\pos(%d,%d)}%02u:%02u:%02u", - fontsize, r.right - 5, r.bottom - 3, hmsf.bHours, hmsf.bMinutes, hmsf.bSeconds); - rts.Add(str, true, MS2RT(1), MS2RT(2), _T("thumbs")); // Thumbnail time - - rts.Render(spd, 0, 25, bbox); // Draw the thumbnail background/time - - BYTE* pData = nullptr; - long size = 0; - if (!GetDIB(&pData, size)) { - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - return; - } - - BITMAPINFO* bi = (BITMAPINFO*)pData; - - if (bi->bmiHeader.biBitCount != 32) { - CString strTemp; - strTemp.Format(IDS_THUMBNAILS_INVALID_FORMAT, bi->bmiHeader.biBitCount); - AfxMessageBox(strTemp); - delete [] pData; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - return; - } - - int sw = bi->bmiHeader.biWidth; - int sh = abs(bi->bmiHeader.biHeight); - int sp = sw * 4; - const BYTE* src = pData + sizeof(bi->bmiHeader); - - stbir_resize(src, sw, sh, sp, thumb.get(), szThumbnail.cx, szThumbnail.cy, szThumbnail.cx * 4, STBIR_RGBA_PM, STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT); - - BYTE* dst = spd.bits + spd.pitch * r.top + r.left * 4; - - const BYTE* tsrc = thumb.get(); - int tsrcPitch = szThumbnail.cx * 4; - if (bi->bmiHeader.biHeight >= 0) { - tsrc += tsrcPitch * (szThumbnail.cy - 1); - tsrcPitch = -tsrcPitch; - } - for (int y = 0; y < szThumbnail.cy; y++, dst += spd.pitch, tsrc += tsrcPitch) { - memcpy(dst, tsrc, abs(tsrcPitch)); - } - - rts.Render(spd, 10000, 25, bbox); // Draw the thumbnail time - - delete [] pData; - } - - // Draw the file information - { - CRenderedTextSubtitle rts(&csSubLock); - rts.m_SubRendererSettings.renderSSAUsingLibass = false; - rts.m_SubRendererSettings.overrideDefaultStyle = false; - rts.m_SubRendererSettings.overrideAllStyles = false; - rts.CreateDefaultStyle(0); - rts.m_storageRes = rts.m_playRes = CSize(width, height); - STSStyle* style = DEBUG_NEW STSStyle(); - // Use System UI font. - CFont tempFont; - CMPCThemeUtil::getFontByType(tempFont, nullptr, CMPCThemeUtil::MessageFont); - LOGFONT lf; - if (tempFont.GetLogFont(&lf)) { - CString fontName(lf.lfFaceName); - style->fontName = fontName; - } - style->marginRect.SetRect(margin * 2, margin * 2, margin * 2, height - infoheight - margin); - rts.AddStyle(_T("thumbs"), style); - - CStringW str; - str.Format(L"{\\an9\\fs%d\\b1\\bord0\\shad0\\1c&Hffffff&}%s", infoheight - 2 * margin, L"MPC-HC"); - if (darktheme) { - str.Replace(L"\\1c&Hffffff", L"\\1c&Hc8c8c8"); - } - rts.Add(str, true, 0, 1, _T("thumbs"), _T(""), _T(""), CRect(0, 0, 0, 0), -1); - - DVD_HMSF_TIMECODE hmsf = RT2HMS_r(rtDur); - - CString title; - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_bYoutubeDL && pli.m_label && !pli.m_label.IsEmpty()) { - title = pli.m_label; - } else { - title = GetFileName(); - } - - CStringW fs; - CString curfile = m_wndPlaylistBar.GetCurFileName(); - if (!PathUtils::IsURL(curfile)) { - ExtendMaxPathLengthIfNeeded(curfile, true); - WIN32_FIND_DATA wfd; - HANDLE hFind = FindFirstFile(curfile, &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); - fs.Format(IDS_THUMBNAILS_INFO_FILESIZE, szFileSize, FormatNumber(szByteSize).GetString()); - } - } - - CStringW ar; - if (szAR.cx > 0 && szAR.cy > 0 && szAR.cx != szVideo.cx && szAR.cy != szVideo.cy) { - ar.Format(L"(%ld:%ld)", szAR.cx, szAR.cy); - } - CStringW fmt = ResStr(IDS_THUMBNAILS_INFO_HEADER); - if (darktheme) { - fmt.Replace(L"\\1c&H000000", L"\\1c&Hc8c8c8"); - } - str.Format(fmt, fontsize, - title.GetString(), fs.GetString(), szVideo.cx, szVideo.cy, ar.GetString(), hmsf.bHours, hmsf.bMinutes, hmsf.bSeconds); - rts.Add(str, true, 0, 1, _T("thumbs")); - - rts.Render(spd, 0, 25, bbox); - } - - SaveDIB(fn, (BYTE*)dib, dibsize); - - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - - if (bWasStopped) { - OnPlayStop(); - } else { - DoSeekTo(rtPos, false); - } - - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_THUMBS_SAVED), 3000); -} - -CString CMainFrame::MakeSnapshotFileName(BOOL thumbnails) -{ - CAppSettings& s = AfxGetAppSettings(); - CString prefix; - CString fn; - - ASSERT(!thumbnails || GetPlaybackMode() == PM_FILE); - - auto videoFn = GetFileName(); - auto fullName = m_wndPlaylistBar.GetCurFileName(true); - bool needsExtensionRemoval = !s.bSnapShotKeepVideoExtension; - if (IsPlaylistFile(videoFn)) { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - videoFn = pli.m_label; - needsExtensionRemoval = false; - } - } else if (needsExtensionRemoval && PathUtils::IsURL(fullName)){ - auto title = getBestTitle(); - if (!title.IsEmpty()) { - videoFn = title; - needsExtensionRemoval = false; - } - } - - - if (needsExtensionRemoval) { - int nPos = videoFn.ReverseFind('.'); - if (nPos != -1) { - videoFn = videoFn.Left(nPos); - } - } - - bool saveImagePosition, saveImageCurrentTime; - - if (m_wndSeekBar.HasDuration()) { - saveImagePosition = s.bSaveImagePosition; - saveImageCurrentTime = s.bSaveImageCurrentTime; - } else { - saveImagePosition = false; - saveImageCurrentTime = true; - } - - if (GetPlaybackMode() == PM_FILE) { - if (thumbnails) { - prefix.Format(_T("%s_thumbs"), videoFn.GetString()); - } else { - if (saveImagePosition) { - prefix.Format(_T("%s_snapshot_%s"), videoFn.GetString(), GetVidPos().GetString()); - } else { - prefix.Format(_T("%s_snapshot"), videoFn.GetString()); - } - } - } else if (GetPlaybackMode() == PM_DVD) { - if (saveImagePosition) { - prefix.Format(_T("dvd_snapshot_%s"), GetVidPos().GetString()); - } else { - prefix = _T("dvd_snapshot"); - } - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - prefix.Format(_T("%s_snapshot"), m_pDVBState->sChannelName.GetString()); - } else { - prefix = _T("snapshot"); - } - - if (!thumbnails && saveImageCurrentTime) { - CTime t = CTime::GetCurrentTime(); - fn.Format(_T("%s_[%s]%s"), PathUtils::FilterInvalidCharsFromFileName(prefix).GetString(), t.Format(_T("%Y.%m.%d_%H.%M.%S")).GetString(), s.strSnapshotExt.GetString()); - } else { - fn.Format(_T("%s%s"), PathUtils::FilterInvalidCharsFromFileName(prefix).GetString(), s.strSnapshotExt.GetString()); - } - return fn; -} - -BOOL CMainFrame::IsRendererCompatibleWithSaveImage() -{ - BOOL result = TRUE; - const CAppSettings& s = AfxGetAppSettings(); - - if (m_fShockwaveGraph) { - AfxMessageBox(IDS_SCREENSHOT_ERROR_SHOCKWAVE, MB_ICONEXCLAMATION | MB_OK, 0); - result = FALSE; - } else if (s.iDSVideoRendererType == VIDRNDT_DS_OVERLAYMIXER) { - AfxMessageBox(IDS_SCREENSHOT_ERROR_OVERLAY, MB_ICONEXCLAMATION | MB_OK, 0); - result = FALSE; - } - - return result; -} - -CString CMainFrame::GetVidPos() const -{ - CString posstr = _T(""); - if ((GetPlaybackMode() == PM_FILE) || (GetPlaybackMode() == PM_DVD)) { - __int64 start, stop, pos; - m_wndSeekBar.GetRange(start, stop); - pos = m_wndSeekBar.GetPos(); - - DVD_HMSF_TIMECODE tcNow = RT2HMSF(pos); - DVD_HMSF_TIMECODE tcDur = RT2HMSF(stop); - - if (tcDur.bHours > 0 || tcNow.bHours > 0) { - posstr.Format(_T("%02u.%02u.%02u.%03u"), tcNow.bHours, tcNow.bMinutes, tcNow.bSeconds, (pos / 10000) % 1000); - } else { - posstr.Format(_T("%02u.%02u.%03u"), tcNow.bMinutes, tcNow.bSeconds, (pos / 10000) % 1000); - } - } - - return posstr; -} - -void CMainFrame::OnFileSaveImage() -{ - CAppSettings& s = AfxGetAppSettings(); - - /* Check if a compatible renderer is being used */ - if (!IsRendererCompatibleWithSaveImage()) { - return; - } - - CPath psrc(s.strSnapshotPath); - psrc.Combine(s.strSnapshotPath.GetString(), MakeSnapshotFileName(FALSE)); - - bool subtitleOptionSupported = !m_pMVRFG && s.fEnableSubtitles && s.IsISRAutoLoadEnabled(); - - CSaveImageDialog fd(s.nJpegQuality, s.strSnapshotExt, (LPCTSTR)psrc, - _T("BMP - Windows Bitmap (*.bmp)|*.bmp|JPG - JPEG Image (*.jpg)|*.jpg|PNG - Portable Network Graphics (*.png)|*.png||"), GetModalParent(), subtitleOptionSupported); - - if (s.strSnapshotExt == _T(".bmp")) { - fd.m_pOFN->nFilterIndex = 1; - } else if (s.strSnapshotExt == _T(".jpg")) { - fd.m_pOFN->nFilterIndex = 2; - } else if (s.strSnapshotExt == _T(".png")) { - fd.m_pOFN->nFilterIndex = 3; - } - - if (fd.DoModal() != IDOK) { - return; - } - - if (fd.m_pOFN->nFilterIndex == 1) { - s.strSnapshotExt = _T(".bmp"); - } else if (fd.m_pOFN->nFilterIndex == 2) { - s.strSnapshotExt = _T(".jpg"); - s.nJpegQuality = fd.m_nJpegQuality; - } else { - fd.m_pOFN->nFilterIndex = 3; - s.strSnapshotExt = _T(".png"); - } - - CPath pdst(fd.GetPathName()); - CString ext(pdst.GetExtension().MakeLower()); - if (ext != s.strSnapshotExt) { - if (ext == _T(".bmp") || ext == _T(".jpg") || ext == _T(".png")) { - ext = s.strSnapshotExt; - } else { - ext += s.strSnapshotExt; - } - pdst.RenameExtension(ext); - } - CString path = (LPCTSTR)pdst; - pdst.RemoveFileSpec(); - s.strSnapshotPath = (LPCTSTR)pdst; - - bool includeSubtitles = subtitleOptionSupported && s.bSnapShotSubtitles; - - SaveImage(path, false, includeSubtitles); -} - -void CMainFrame::OnFileSaveImageAuto() -{ - const CAppSettings& s = AfxGetAppSettings(); - - // If path doesn't exist, Save Image instead - if (!PathUtils::IsDir(s.strSnapshotPath)) { - AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); - OnFileSaveImage(); - return; - } - - /* Check if a compatible renderer is being used */ - if (!IsRendererCompatibleWithSaveImage()) { - return; - } - - bool includeSubtitles = s.bSnapShotSubtitles && !m_pMVRFG && s.fEnableSubtitles && s.IsISRAutoLoadEnabled(); - - CString fn; - fn.Format(_T("%s\\%s"), s.strSnapshotPath.GetString(), MakeSnapshotFileName(FALSE).GetString()); - SaveImage(fn.GetString(), false, includeSubtitles); -} - -void CMainFrame::OnUpdateFileSaveImage(CCmdUI* pCmdUI) -{ - OAFilterState fs = GetMediaState(); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (fs == State_Paused || fs == State_Running)); -} - -void CMainFrame::OnCmdLineSaveThumbnails() -{ - CAppSettings& s = AfxGetAppSettings(); - - /* Check if a compatible renderer is being used */ - if (!IsRendererCompatibleWithSaveImage()) { - return; - } - - CPlaylistItem pli; - if (!m_wndPlaylistBar.GetCur(pli, true)) { - return; - } - - CPath psrc(m_wndPlaylistBar.GetCurFileName(true)); - psrc.RemoveFileSpec(); - psrc.Combine(psrc, MakeSnapshotFileName(TRUE)); - - s.iThumbRows = std::clamp(s.iThumbRows, 1, 40); - s.iThumbCols = std::clamp(s.iThumbCols, 1, 16); - s.iThumbWidth = std::clamp(s.iThumbWidth, 256, 3840); - - CString path = (LPCTSTR)psrc; - - SaveThumbnails(path); - -} - -void CMainFrame::OnFileSaveThumbnails() -{ - CAppSettings& s = AfxGetAppSettings(); - - /* Check if a compatible renderer is being used */ - if (!IsRendererCompatibleWithSaveImage()) { - return; - } - - CPath psrc(s.strSnapshotPath); - psrc.Combine(s.strSnapshotPath, MakeSnapshotFileName(TRUE)); - - CSaveThumbnailsDialog fd(s.nJpegQuality, s.iThumbRows, s.iThumbCols, s.iThumbWidth, s.strSnapshotExt, (LPCTSTR)psrc, - _T("BMP - Windows Bitmap (*.bmp)|*.bmp|JPG - JPEG Image (*.jpg)|*.jpg|PNG - Portable Network Graphics (*.png)|*.png||"), GetModalParent()); - - if (s.strSnapshotExt == _T(".bmp")) { - fd.m_pOFN->nFilterIndex = 1; - } else if (s.strSnapshotExt == _T(".jpg")) { - fd.m_pOFN->nFilterIndex = 2; - } else if (s.strSnapshotExt == _T(".png")) { - fd.m_pOFN->nFilterIndex = 3; - } - - if (fd.DoModal() != IDOK) { - return; - } - - if (fd.m_pOFN->nFilterIndex == 1) { - s.strSnapshotExt = _T(".bmp"); - } else if (fd.m_pOFN->nFilterIndex == 2) { - s.strSnapshotExt = _T(".jpg"); - s.nJpegQuality = fd.m_nJpegQuality; - } else { - fd.m_pOFN->nFilterIndex = 3; - s.strSnapshotExt = _T(".png"); - } - - s.iThumbRows = std::clamp(fd.m_rows, 1, 40); - s.iThumbCols = std::clamp(fd.m_cols, 1, 16); - s.iThumbWidth = std::clamp(fd.m_width, 256, 3840); - - CPath pdst(fd.GetPathName()); - CString ext(pdst.GetExtension().MakeLower()); - if (ext != s.strSnapshotExt) { - if (ext == _T(".bmp") || ext == _T(".jpg") || ext == _T(".png")) { - ext = s.strSnapshotExt; - } else { - ext += s.strSnapshotExt; - } - pdst.RenameExtension(ext); - } - CString path = (LPCTSTR)pdst; - pdst.RemoveFileSpec(); - s.strSnapshotPath = (LPCTSTR)pdst; - - SaveThumbnails(path); -} - -void CMainFrame::OnUpdateFileSaveThumbnails(CCmdUI* pCmdUI) -{ - OAFilterState fs = GetMediaState(); - UNREFERENCED_PARAMETER(fs); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (GetPlaybackMode() == PM_FILE /*|| GetPlaybackMode() == PM_DVD*/)); -} - -void CMainFrame::OnFileSubtitlesLoad() -{ - if (!m_pCAP && !m_pDVS) { - AfxMessageBox(IDS_CANNOT_LOAD_SUB, MB_ICONINFORMATION | MB_OK, 0); - return; - } - - DWORD dwFlags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_NOCHANGEDIR; - if (!AfxGetAppSettings().fKeepHistory) { - dwFlags |= OFN_DONTADDTORECENT; - } - CString filters; - filters.Format(_T("%s|*.srt;*.sub;*.ssa;*.ass;*.smi;*.psb;*.txt;*.idx;*.usf;*.xss;*.rt;*.sup;*.webvtt;*.vtt|%s"), - ResStr(IDS_SUBTITLE_FILES_FILTER).GetString(), ResStr(IDS_ALL_FILES_FILTER).GetString()); - - CFileDialog fd(TRUE, nullptr, nullptr, dwFlags, filters, GetModalParent()); - - OPENFILENAME& ofn = fd.GetOFN(); - // Provide a buffer big enough to hold 16 paths (which should be more than enough) - const int nBufferSize = 16 * (MAX_PATH + 1) + 1; - CString filenames; - ofn.lpstrFile = filenames.GetBuffer(nBufferSize); - ofn.nMaxFile = nBufferSize; - // Set the current file directory as default folder - CString curfile = m_wndPlaylistBar.GetCurFileName(); - if (!PathUtils::IsURL(curfile)) { - CPath defaultDir(curfile); - defaultDir.RemoveFileSpec(); - if (!defaultDir.m_strPath.IsEmpty()) { - ofn.lpstrInitialDir = defaultDir.m_strPath; - } - } - - if (fd.DoModal() == IDOK) { - bool bFirstFile = true; - POSITION pos = fd.GetStartPosition(); - while (pos) { - CString subfile = fd.GetNextPathName(pos); - if (m_pDVS) { - if (SUCCEEDED(m_pDVS->put_FileName((LPWSTR)(LPCWSTR)subfile))) { - m_pDVS->put_SelectedLanguage(0); - m_pDVS->put_HideSubtitles(true); - m_pDVS->put_HideSubtitles(false); - break; - } - } else { - SubtitleInput subInput; - if (LoadSubtitle(subfile, &subInput) && bFirstFile) { - bFirstFile = false; - // Use the subtitles file that was just added - AfxGetAppSettings().fEnableSubtitles = true; - SetSubtitle(subInput); - } - } - } - } -} - -void CMainFrame::OnUpdateFileSubtitlesLoad(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(!m_fAudioOnly && (m_pCAP || m_pDVS) && GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode()); -} - -void CMainFrame::SubtitlesSave(const TCHAR* directory, bool silent) -{ - if (lastOpenFile.IsEmpty()) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - - int i = 0; - SubtitleInput* pSubInput = GetSubtitleInput(i, true); - if (!pSubInput) { - return; - } - - CLSID clsid; - if (FAILED(pSubInput->pSubStream->GetClassID(&clsid))) { - return; - } - - CString suggestedFileName; - if (PathUtils::IsURL(lastOpenFile)) { - if (silent) { - return; - } - suggestedFileName = _T("subtitle"); - } else { - CPath path(lastOpenFile); - path.RemoveExtension(); - suggestedFileName = CString(path); - } - - if (directory && *directory) { - CPath suggestedPath(suggestedFileName); - int pos = suggestedPath.FindFileName(); - CString fileName = suggestedPath.m_strPath.Mid(pos); - CPath dirPath(directory); - if (dirPath.IsRelative()) { - dirPath = CPath(suggestedPath.m_strPath.Left(pos)) += dirPath; - } - if (EnsureDirectory(dirPath)) { - suggestedFileName = CString(dirPath += fileName); - } - else if (silent) { - return; - } - } - - bool isSaved = false; - if (clsid == __uuidof(CVobSubFile)) { - CVobSubFile* pVSF = (CVobSubFile*)(ISubStream*)pSubInput->pSubStream; - - // remember to set lpszDefExt to the first extension in the filter so that the save dialog autocompletes the extension - // and tracks attempts to overwrite in a graceful manner - if (silent) { - isSaved = pVSF->Save(suggestedFileName + _T(".idx"), m_pCAP->GetSubtitleDelay()); - } else { - CSaveSubtitlesFileDialog fd(m_pCAP->GetSubtitleDelay(), _T("idx"), suggestedFileName, - _T("VobSub (*.idx, *.sub)|*.idx;*.sub||"), GetModalParent()); - - if (fd.DoModal() == IDOK) { - CAutoLock cAutoLock(&m_csSubLock); - isSaved = pVSF->Save(fd.GetPathName(), fd.GetDelay()); - } - } - } - else if (clsid == __uuidof(CRenderedTextSubtitle)) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; - - if (s.bAddLangCodeWhenSaveSubtitles && pRTS->m_lcid && pRTS->m_lcid != LCID(-1)) { - CString str; - GetLocaleString(pRTS->m_lcid, LOCALE_SISO639LANGNAME, str); - suggestedFileName += _T('.') + str; - - if (pRTS->m_eHearingImpaired == Subtitle::HI_YES) { - suggestedFileName += _T(".hi"); - } - } - - // same thing as in the case of CVobSubFile above for lpszDefExt - if (silent) { - Subtitle::SubType type; - switch (pRTS->m_subtitleType) - { - case Subtitle::ASS: - case Subtitle::SSA: - case Subtitle::VTT: - type = Subtitle::ASS; - break; - default: - type = Subtitle::SRT; - } - - isSaved = pRTS->SaveAs( - suggestedFileName, type, m_pCAP->GetFPS(), m_pCAP->GetSubtitleDelay(), - CTextFile::DEFAULT_ENCODING, s.bSubSaveExternalStyleFile); - } else { - const std::vector types = { - Subtitle::SRT, - Subtitle::SUB, - Subtitle::SMI, - Subtitle::PSB, - Subtitle::SSA, - Subtitle::ASS - }; - - CString filter; - filter += _T("SubRip (*.srt)|*.srt|"); //1 = default - filter += _T("MicroDVD (*.sub)|*.sub|"); //2 - filter += _T("SAMI (*.smi)|*.smi|"); //3 - filter += _T("PowerDivX (*.psb)|*.psb|"); //4 - filter += _T("SubStation Alpha (*.ssa)|*.ssa|"); //5 - filter += _T("Advanced SubStation Alpha (*.ass)|*.ass|"); //6 - filter += _T("|"); - - CSaveSubtitlesFileDialog fd(pRTS->m_encoding, m_pCAP->GetSubtitleDelay(), s.bSubSaveExternalStyleFile, - _T("srt"), suggestedFileName, filter, types, GetModalParent()); - - if (pRTS->m_subtitleType == Subtitle::SSA || pRTS->m_subtitleType == Subtitle::ASS) { - fd.m_ofn.nFilterIndex = 6; //nFilterIndex is 1-based - } - - if (fd.DoModal() == IDOK) { - CAutoLock cAutoLock(&m_csSubLock); - s.bSubSaveExternalStyleFile = fd.GetSaveExternalStyleFile(); - isSaved = pRTS->SaveAs(fd.GetPathName(), types[fd.m_ofn.nFilterIndex - 1], m_pCAP->GetFPS(), fd.GetDelay(), fd.GetEncoding(), fd.GetSaveExternalStyleFile()); - } - } - } - else { - AfxMessageBox(_T("This operation is not supported.\r\nThe selected subtitles cannot be saved."), MB_ICONEXCLAMATION | MB_OK); - } - - if (isSaved && s.fKeepHistory) { - auto subPath = pSubInput->pSubStream->GetPath(); - if (!subPath.IsEmpty()) { - s.MRU.AddSubToCurrent(subPath); - } - } -} - -void CMainFrame::OnUpdateFileSubtitlesSave(CCmdUI* pCmdUI) -{ - bool bEnable = false; - - if (!m_pCurrentSubInput.pSourceFilter) { - if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { - bEnable = !pRTS->IsEmpty(); - } else if (dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { - bEnable = true; - } - } - - pCmdUI->Enable(bEnable); -} - -#if 0 -void CMainFrame::OnFileSubtitlesUpload() -{ - m_wndSubtitlesUploadDialog.ShowWindow(SW_SHOW); -} - -void CMainFrame::OnUpdateFileSubtitlesUpload(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(!m_pSubStreams.IsEmpty() && s.fEnableSubtitles); -} -#endif - -void CMainFrame::OnFileSubtitlesDownload() -{ - if (!m_fAudioOnly) { - if (m_pCAP && AfxGetAppSettings().IsISRAutoLoadEnabled()) { - m_wndSubtitlesDownloadDialog.ShowWindow(SW_SHOW); - } else { - AfxMessageBox(_T("Downloading subtitles only works when using the internal subtitle renderer."), MB_ICONINFORMATION | MB_OK, 0); - } - } -} - -void CMainFrame::OnUpdateFileSubtitlesDownload(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode() && m_pCAP && !m_fAudioOnly); -} - -void CMainFrame::OnFileProperties() -{ - CString fn; - CString ydlsrc; - if (m_pDVBState) { - fn = m_pDVBState->sChannelName; - } else { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - fn = pli.m_fns.GetHead(); - if (pli.m_bYoutubeDL) { - ydlsrc = pli.m_ydlSourceURL; - } - } - } - - ASSERT(!fn.IsEmpty()); - - CPPageFileInfoSheet fileinfo(fn, ydlsrc, this, GetModalParent()); - fileinfo.DoModal(); -} - -void CMainFrame::OnUpdateFileProperties(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() != PM_ANALOG_CAPTURE); -} - -void CMainFrame::OnFileOpenLocation() { - CString filePath = m_wndPlaylistBar.GetCurFileName(); - if (!PathUtils::IsURL(filePath)) { - ExploreToFile(filePath); - } -} - -void CMainFrame::OnFileCloseMedia() -{ - CloseMedia(); -} - -void CMainFrame::OnUpdateViewTearingTest(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC); - - pCmdUI->Enable(supported && GetLoadState() == MLS::LOADED && !m_fAudioOnly); - pCmdUI->SetCheck(supported && AfxGetMyApp()->m_Renderers.m_bTearingTest); -} - -void CMainFrame::OnViewTearingTest() -{ - AfxGetMyApp()->m_Renderers.m_bTearingTest = !AfxGetMyApp()->m_Renderers.m_bTearingTest; -} - -void CMainFrame::OnUpdateViewDisplayRendererStats(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); - - pCmdUI->Enable(supported && GetLoadState() == MLS::LOADED && !m_fAudioOnly); - pCmdUI->SetCheck(supported && AfxGetMyApp()->m_Renderers.m_iDisplayStats > 0); -} - -void CMainFrame::OnViewResetRendererStats() -{ - AfxGetMyApp()->m_Renderers.m_bResetStats = true; // Reset by "consumer" -} - -void CMainFrame::OnViewDisplayRendererStats() -{ - const CAppSettings& s = AfxGetAppSettings(); - bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); - - if (supported) { - if (m_pCAP3) { - m_pCAP3->ToggleStats(); - return; - } - - if (!AfxGetMyApp()->m_Renderers.m_iDisplayStats) { - AfxGetMyApp()->m_Renderers.m_bResetStats = true; // to reset statistics on first call ... - } - - ++AfxGetMyApp()->m_Renderers.m_iDisplayStats; - if (AfxGetMyApp()->m_Renderers.m_iDisplayStats > 3) { - AfxGetMyApp()->m_Renderers.m_iDisplayStats = 0; - } - RepaintVideo(); - } -} - -void CMainFrame::OnUpdateViewVSync(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(!supported || r.m_AdvRendSets.bVMR9VSync); -} - -void CMainFrame::OnUpdateViewVSyncOffset(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D - && r.m_AdvRendSets.bVMR9AlterativeVSync); - - pCmdUI->Enable(supported); - CString Temp; - Temp.Format(L"%d", r.m_AdvRendSets.iVMR9VSyncOffset); - pCmdUI->SetText(Temp); - CMPCThemeMenu::updateItem(pCmdUI); -} - -void CMainFrame::OnUpdateViewVSyncAccurate(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9VSyncAccurate); -} - -void CMainFrame::OnUpdateViewSynchronizeVideo(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_SYNC) && GetPlaybackMode() == PM_NONE); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeVideo); -} - -void CMainFrame::OnUpdateViewSynchronizeDisplay(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_SYNC) && GetPlaybackMode() == PM_NONE); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeDisplay); -} - -void CMainFrame::OnUpdateViewSynchronizeNearest(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_SYNC); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeNearest); -} - -void CMainFrame::OnUpdateViewColorManagementEnable(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9ColorManagementEnable); -} - -void CMainFrame::OnUpdateViewColorManagementInput(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support - && r.m_AdvRendSets.bVMR9ColorManagementEnable; - - pCmdUI->Enable(supported); - - switch (pCmdUI->m_nID) { - case ID_VIEW_CM_INPUT_AUTO: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_UNKNOWN); - break; - - case ID_VIEW_CM_INPUT_HDTV: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_HDTV); - break; - - case ID_VIEW_CM_INPUT_SDTV_NTSC: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_SDTV_NTSC); - break; - - case ID_VIEW_CM_INPUT_SDTV_PAL: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_SDTV_PAL); - break; - } -} - -void CMainFrame::OnUpdateViewColorManagementAmbientLight(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support && - r.m_AdvRendSets.bVMR9ColorManagementEnable; - - pCmdUI->Enable(supported); - - switch (pCmdUI->m_nID) { - case ID_VIEW_CM_AMBIENTLIGHT_BRIGHT: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_BRIGHT); - break; - case ID_VIEW_CM_AMBIENTLIGHT_DIM: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_DIM); - break; - case ID_VIEW_CM_AMBIENTLIGHT_DARK: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_DARK); - break; - } -} - -void CMainFrame::OnUpdateViewColorManagementIntent(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support - && r.m_AdvRendSets.bVMR9ColorManagementEnable; - - pCmdUI->Enable(supported); - - switch (pCmdUI->m_nID) { - case ID_VIEW_CM_INTENT_PERCEPTUAL: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_PERCEPTUAL); - break; - case ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC); - break; - case ID_VIEW_CM_INTENT_SATURATION: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_SATURATION); - break; - case ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC: - pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC); - break; - } -} - -void CMainFrame::OnUpdateViewEVROutputRange(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - - if (pCmdUI->m_nID == ID_VIEW_EVROUTPUTRANGE_0_255) { - pCmdUI->SetCheck(r.m_AdvRendSets.iEVROutputRange == 0); - } else if (pCmdUI->m_nID == ID_VIEW_EVROUTPUTRANGE_16_235) { - pCmdUI->SetCheck(r.m_AdvRendSets.iEVROutputRange == 1); - } -} - -void CMainFrame::OnUpdateViewFlushGPU(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - - if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_BEFOREVSYNC) { - pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUBeforeVSync); - } else if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_AFTERPRESENT) { - pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUAfterPresent); - } else if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_WAIT) { - pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUWait); - } - -} - -void CMainFrame::OnUpdateViewD3DFullscreen(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(s.fD3DFullscreen); -} - -void CMainFrame::OnUpdateViewDisableDesktopComposition(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D - && !IsWindows8OrGreater()); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(supported && r.m_AdvRendSets.bVMRDisableDesktopComposition); -} - -void CMainFrame::OnUpdateViewAlternativeVSync(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9AlterativeVSync); -} - -void CMainFrame::OnUpdateViewFullscreenGUISupport(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9FullscreenGUISupport); -} - -void CMainFrame::OnUpdateViewHighColorResolution(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM - || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_b10bitSupport; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bEVRHighColorResolution); -} - -void CMainFrame::OnUpdateViewForceInputHighColorResolution(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_b10bitSupport; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bEVRForceInputHighColorResolution); -} - -void CMainFrame::OnUpdateViewFullFloatingPointProcessing(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP32Support; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9FullFloatingPointProcessing); -} - -void CMainFrame::OnUpdateViewHalfFloatingPointProcessing(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - const CRenderersData& rd = AfxGetMyApp()->m_Renderers; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && rd.m_bFP16Support; - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing); -} - -void CMainFrame::OnUpdateViewEnableFrameTimeCorrection(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); - - pCmdUI->Enable(supported); - pCmdUI->SetCheck(r.m_AdvRendSets.bEVREnableFrameTimeCorrection); -} - -void CMainFrame::OnUpdateViewVSyncOffsetIncrease(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || (((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && r.m_AdvRendSets.bVMR9AlterativeVSync); - - pCmdUI->Enable(supported); -} - -void CMainFrame::OnUpdateViewVSyncOffsetDecrease(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - bool supported = s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || (((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS - || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) - && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) - && r.m_AdvRendSets.bVMR9AlterativeVSync); - - pCmdUI->Enable(supported); -} - -void CMainFrame::OnViewVSync() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9VSync = !r.m_AdvRendSets.bVMR9VSync; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9VSync - ? IDS_OSD_RS_VSYNC_ON : IDS_OSD_RS_VSYNC_OFF)); -} - -void CMainFrame::OnViewVSyncAccurate() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9VSyncAccurate = !r.m_AdvRendSets.bVMR9VSyncAccurate; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9VSyncAccurate - ? IDS_OSD_RS_ACCURATE_VSYNC_ON : IDS_OSD_RS_ACCURATE_VSYNC_OFF)); -} - -void CMainFrame::OnViewSynchronizeVideo() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bSynchronizeVideo = !r.m_AdvRendSets.bSynchronizeVideo; - if (r.m_AdvRendSets.bSynchronizeVideo) { - r.m_AdvRendSets.bSynchronizeDisplay = false; - r.m_AdvRendSets.bSynchronizeNearest = false; - r.m_AdvRendSets.bVMR9VSync = false; - r.m_AdvRendSets.bVMR9VSyncAccurate = false; - r.m_AdvRendSets.bVMR9AlterativeVSync = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeVideo - ? IDS_OSD_RS_SYNC_TO_DISPLAY_ON : IDS_OSD_RS_SYNC_TO_DISPLAY_ON)); -} - -void CMainFrame::OnViewSynchronizeDisplay() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bSynchronizeDisplay = !r.m_AdvRendSets.bSynchronizeDisplay; - if (r.m_AdvRendSets.bSynchronizeDisplay) { - r.m_AdvRendSets.bSynchronizeVideo = false; - r.m_AdvRendSets.bSynchronizeNearest = false; - r.m_AdvRendSets.bVMR9VSync = false; - r.m_AdvRendSets.bVMR9VSyncAccurate = false; - r.m_AdvRendSets.bVMR9AlterativeVSync = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeDisplay - ? IDS_OSD_RS_SYNC_TO_VIDEO_ON : IDS_OSD_RS_SYNC_TO_VIDEO_ON)); -} - -void CMainFrame::OnViewSynchronizeNearest() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bSynchronizeNearest = !r.m_AdvRendSets.bSynchronizeNearest; - if (r.m_AdvRendSets.bSynchronizeNearest) { - r.m_AdvRendSets.bSynchronizeVideo = false; - r.m_AdvRendSets.bSynchronizeDisplay = false; - r.m_AdvRendSets.bVMR9VSync = false; - r.m_AdvRendSets.bVMR9VSyncAccurate = false; - r.m_AdvRendSets.bVMR9AlterativeVSync = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeNearest - ? IDS_OSD_RS_PRESENT_NEAREST_ON : IDS_OSD_RS_PRESENT_NEAREST_OFF)); -} - -void CMainFrame::OnViewColorManagementEnable() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9ColorManagementEnable = !r.m_AdvRendSets.bVMR9ColorManagementEnable; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9ColorManagementEnable - ? IDS_OSD_RS_COLOR_MANAGEMENT_ON : IDS_OSD_RS_COLOR_MANAGEMENT_OFF)); -} - -void CMainFrame::OnViewColorManagementInputAuto() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_AUTO)); -} - -void CMainFrame::OnViewColorManagementInputHDTV() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_HDTV; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_HDTV)); -} - -void CMainFrame::OnViewColorManagementInputSDTV_NTSC() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_SDTV_NTSC; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_SD_NTSC)); -} - -void CMainFrame::OnViewColorManagementInputSDTV_PAL() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_SDTV_PAL; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_SD_PAL)); -} - -void CMainFrame::OnViewColorManagementAmbientLightBright() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_BRIGHT)); -} - -void CMainFrame::OnViewColorManagementAmbientLightDim() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_DIM; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_DIM)); -} - -void CMainFrame::OnViewColorManagementAmbientLightDark() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_DARK; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_DARK)); -} - -void CMainFrame::OnViewColorManagementIntentPerceptual() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_PERCEPT)); -} - -void CMainFrame::OnViewColorManagementIntentRelativeColorimetric() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_RELATIVE)); -} - -void CMainFrame::OnViewColorManagementIntentSaturation() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_SATURATION; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_SATUR)); -} - -void CMainFrame::OnViewColorManagementIntentAbsoluteColorimetric() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_ABSOLUTE)); -} - -void CMainFrame::OnViewEVROutputRange_0_255() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iEVROutputRange = 0; - CString strOSD; - strOSD.Format(IDS_OSD_RS_OUTPUT_RANGE, _T("0 - 255")); - m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); -} - -void CMainFrame::OnViewEVROutputRange_16_235() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.iEVROutputRange = 1; - CString strOSD; - strOSD.Format(IDS_OSD_RS_OUTPUT_RANGE, _T("16 - 235")); - m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); -} - -void CMainFrame::OnViewFlushGPUBeforeVSync() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMRFlushGPUBeforeVSync = !r.m_AdvRendSets.bVMRFlushGPUBeforeVSync; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUBeforeVSync - ? IDS_OSD_RS_FLUSH_BEF_VSYNC_ON : IDS_OSD_RS_FLUSH_BEF_VSYNC_OFF)); -} - -void CMainFrame::OnViewFlushGPUAfterVSync() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMRFlushGPUAfterPresent = !r.m_AdvRendSets.bVMRFlushGPUAfterPresent; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUAfterPresent - ? IDS_OSD_RS_FLUSH_AFT_PRES_ON : IDS_OSD_RS_FLUSH_AFT_PRES_OFF)); -} - -void CMainFrame::OnViewFlushGPUWait() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMRFlushGPUWait = !r.m_AdvRendSets.bVMRFlushGPUWait; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUWait - ? IDS_OSD_RS_WAIT_ON : IDS_OSD_RS_WAIT_OFF)); -} - -void CMainFrame::OnViewD3DFullScreen() -{ - CAppSettings& r = AfxGetAppSettings(); - r.fD3DFullscreen = !r.fD3DFullscreen; - r.SaveSettings(); - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.fD3DFullscreen - ? IDS_OSD_RS_D3D_FULLSCREEN_ON : IDS_OSD_RS_D3D_FULLSCREEN_OFF)); -} - -void CMainFrame::OnViewDisableDesktopComposition() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMRDisableDesktopComposition = !r.m_AdvRendSets.bVMRDisableDesktopComposition; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRDisableDesktopComposition - ? IDS_OSD_RS_NO_DESKTOP_COMP_ON : IDS_OSD_RS_NO_DESKTOP_COMP_OFF)); -} - -void CMainFrame::OnViewAlternativeVSync() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9AlterativeVSync = !r.m_AdvRendSets.bVMR9AlterativeVSync; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9AlterativeVSync - ? IDS_OSD_RS_ALT_VSYNC_ON : IDS_OSD_RS_ALT_VSYNC_OFF)); -} - -void CMainFrame::OnViewResetDefault() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.SetDefault(); - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_RESET_DEFAULT)); -} - -void CMainFrame::OnViewResetOptimal() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.SetOptimal(); - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_RESET_OPTIMAL)); -} - -void CMainFrame::OnViewFullscreenGUISupport() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9FullscreenGUISupport = !r.m_AdvRendSets.bVMR9FullscreenGUISupport; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9FullscreenGUISupport - ? IDS_OSD_RS_D3D_FS_GUI_SUPP_ON : IDS_OSD_RS_D3D_FS_GUI_SUPP_OFF)); -} - -void CMainFrame::OnViewHighColorResolution() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bEVRHighColorResolution = !r.m_AdvRendSets.bEVRHighColorResolution; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVRHighColorResolution - ? IDS_OSD_RS_10BIT_RBG_OUT_ON : IDS_OSD_RS_10BIT_RBG_OUT_OFF)); -} - -void CMainFrame::OnViewForceInputHighColorResolution() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bEVRForceInputHighColorResolution = !r.m_AdvRendSets.bEVRForceInputHighColorResolution; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVRForceInputHighColorResolution - ? IDS_OSD_RS_10BIT_RBG_IN_ON : IDS_OSD_RS_10BIT_RBG_IN_OFF)); -} - -void CMainFrame::OnViewFullFloatingPointProcessing() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - if (!r.m_AdvRendSets.bVMR9FullFloatingPointProcessing) { - if (AfxMessageBox(_T("WARNING: Full Floating Point processing can sometimes cause problems. With some videos it can cause the player to freeze, crash, or display corrupted video. This happens mostly with Intel GPUs.\n\nAre you really sure that you want to enable this setting?"), MB_YESNO) == IDNO) { - return; - } - } - r.m_AdvRendSets.bVMR9FullFloatingPointProcessing = !r.m_AdvRendSets.bVMR9FullFloatingPointProcessing; - if (r.m_AdvRendSets.bVMR9FullFloatingPointProcessing) { - r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9FullFloatingPointProcessing - ? IDS_OSD_RS_FULL_FP_PROCESS_ON : IDS_OSD_RS_FULL_FP_PROCESS_OFF)); -} - -void CMainFrame::OnViewHalfFloatingPointProcessing() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing = !r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing; - if (r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing) { - r.m_AdvRendSets.bVMR9FullFloatingPointProcessing = false; - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing - ? IDS_OSD_RS_HALF_FP_PROCESS_ON : IDS_OSD_RS_HALF_FP_PROCESS_OFF)); -} - -void CMainFrame::OnViewEnableFrameTimeCorrection() -{ - CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; - r.m_AdvRendSets.bEVREnableFrameTimeCorrection = !r.m_AdvRendSets.bEVREnableFrameTimeCorrection; - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVREnableFrameTimeCorrection - ? IDS_OSD_RS_FT_CORRECTION_ON : IDS_OSD_RS_FT_CORRECTION_OFF)); -} - -void CMainFrame::OnViewVSyncOffsetIncrease() -{ - CAppSettings& s = AfxGetAppSettings(); - CRenderersSettings& r = s.m_RenderersSettings; - CString strOSD; - if (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { - r.m_AdvRendSets.fTargetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset - 0.5; // Yeah, it should be a "-" - strOSD.Format(IDS_OSD_RS_TARGET_VSYNC_OFFSET, r.m_AdvRendSets.fTargetSyncOffset); - } else { - ++r.m_AdvRendSets.iVMR9VSyncOffset; - strOSD.Format(IDS_OSD_RS_VSYNC_OFFSET, r.m_AdvRendSets.iVMR9VSyncOffset); - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); -} - -void CMainFrame::OnViewVSyncOffsetDecrease() -{ - CAppSettings& s = AfxGetAppSettings(); - CRenderersSettings& r = s.m_RenderersSettings; - CString strOSD; - if (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { - r.m_AdvRendSets.fTargetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset + 0.5; - strOSD.Format(IDS_OSD_RS_TARGET_VSYNC_OFFSET, r.m_AdvRendSets.fTargetSyncOffset); - } else { - --r.m_AdvRendSets.iVMR9VSyncOffset; - strOSD.Format(IDS_OSD_RS_VSYNC_OFFSET, r.m_AdvRendSets.iVMR9VSyncOffset); - } - m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); -} - -void CMainFrame::OnUpdateViewOSDDisplayTime(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(s.fShowOSD && GetLoadState() != MLS::CLOSED); - pCmdUI->SetCheck(AfxGetAppSettings().fShowCurrentTimeInOSD); -} - -void CMainFrame::OnViewOSDDisplayTime() -{ - auto &showTime = AfxGetAppSettings().fShowCurrentTimeInOSD; - showTime = !showTime; - - if (!showTime) { - m_OSD.ClearTime(); - } - - OnTimer(TIMER_STREAMPOSPOLLER2); -} - -void CMainFrame::OnUpdateViewOSDShowFileName(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(s.fShowOSD && GetLoadState() != MLS::CLOSED); -} - -void CMainFrame::OnViewOSDShowFileName() -{ - CString strOSD; - switch (GetPlaybackMode()) { - case PM_FILE: - strOSD = GetFileName(); - break; - case PM_DVD: - strOSD = _T("DVD"); - if (m_pDVDI) { - CString path; - ULONG len = 0; - if (SUCCEEDED(m_pDVDI->GetDVDDirectory(path.GetBuffer(MAX_PATH), MAX_PATH, &len)) && len) { - path.ReleaseBuffer(); - if (path.Find(_T("\\VIDEO_TS")) == 2) { - strOSD.AppendFormat(_T(" - %s"), GetDriveLabel(CPath(path)).GetString()); - } else { - strOSD.AppendFormat(_T(" - %s"), path.GetString()); - } - } - } - break; - case PM_ANALOG_CAPTURE: - strOSD = GetCaptureTitle(); - break; - case PM_DIGITAL_CAPTURE: - UpdateCurrentChannelInfo(true, false); - break; - default: // Shouldn't happen - ASSERT(FALSE); - return; - } - if (!strOSD.IsEmpty()) { - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD); - } -} - -void CMainFrame::OnUpdateShaderToggle1(CCmdUI* pCmdUI) -{ - if (AfxGetAppSettings().m_Shaders.GetCurrentPreset().GetPreResize().empty()) { - pCmdUI->Enable(FALSE); - pCmdUI->SetCheck (0); - } else { - pCmdUI->Enable(TRUE); - pCmdUI->SetCheck (m_bToggleShader); - } -} - -void CMainFrame::OnUpdateShaderToggle2(CCmdUI* pCmdUI) -{ - CAppSettings& s = AfxGetAppSettings(); - - if (s.m_Shaders.GetCurrentPreset().GetPostResize().empty()) { - pCmdUI->Enable(FALSE); - pCmdUI->SetCheck(0); - } else { - pCmdUI->Enable(TRUE); - pCmdUI->SetCheck(m_bToggleShaderScreenSpace); - } -} - -void CMainFrame::OnShaderToggle1() -{ - m_bToggleShader = !m_bToggleShader; - SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); - if (m_bToggleShader) { - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_PRESIZE_SHADERS_ENABLED)); - } else { - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_PRESIZE_SHADERS_DISABLED)); - } - - if (m_pCAP) { - RepaintVideo(); - } -} - -void CMainFrame::OnShaderToggle2() -{ - m_bToggleShaderScreenSpace = !m_bToggleShaderScreenSpace; - SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); - if (m_bToggleShaderScreenSpace) { - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_POSTSIZE_SHADERS_ENABLED)); - } else { - m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_POSTSIZE_SHADERS_DISABLED)); - } - - if (m_pCAP) { - RepaintVideo(); - } -} - -void CMainFrame::OnD3DFullscreenToggle() -{ - CAppSettings& s = AfxGetAppSettings(); - CString strMsg; - - s.fD3DFullscreen = !s.fD3DFullscreen; - strMsg.LoadString(s.fD3DFullscreen ? IDS_OSD_RS_D3D_FULLSCREEN_ON : IDS_OSD_RS_D3D_FULLSCREEN_OFF); - if (GetLoadState() == MLS::CLOSED) { - m_closingmsg = strMsg; - } else { - m_OSD.DisplayMessage(OSD_TOPRIGHT, strMsg); - } -} - -void CMainFrame::OnFileCloseAndRestore() -{ - if (GetLoadState() == MLS::LOADED && IsFullScreenMode()) { - // exit fullscreen - OnViewFullscreen(); - } - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - RestoreDefaultWindowRect(); -} - -void CMainFrame::OnUpdateFileClose(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED || GetLoadState() == MLS::LOADING); -} - -// view - -void CMainFrame::SetCaptionState(MpcCaptionState eState) -{ - auto& s = AfxGetAppSettings(); - - if (eState == s.eCaptionMenuMode) { - return; - } - - const auto eOldState = s.eCaptionMenuMode; - s.eCaptionMenuMode = eState; - - if (IsFullScreenMainFrame()) { - return; - } - - DWORD dwRemove = 0, dwAdd = 0; - DWORD dwMenuFlags = GetMenuBarVisibility(); - - CRect windowRect; - - const bool bZoomed = !!IsZoomed(); - - if (!bZoomed) { - GetWindowRect(&windowRect); - CRect decorationsRect; - VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), dwMenuFlags == AFX_MBV_KEEPVISIBLE, GetWindowExStyle(m_hWnd))); - windowRect.bottom -= decorationsRect.bottom; - windowRect.right -= decorationsRect.right; - windowRect.top -= decorationsRect.top; - windowRect.left -= decorationsRect.left; - } - - const int base = MpcCaptionState::MODE_COUNT; - for (int i = eOldState; i != eState; i = (i + 1) % base) { - switch (static_cast(i)) { - case MpcCaptionState::MODE_BORDERLESS: - dwMenuFlags = AFX_MBV_KEEPVISIBLE; - dwAdd |= (WS_CAPTION | WS_THICKFRAME); - dwRemove &= ~(WS_CAPTION | WS_THICKFRAME); - break; - case MpcCaptionState::MODE_SHOWCAPTIONMENU: - dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; - break; - case MpcCaptionState::MODE_HIDEMENU: - dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; - dwAdd &= ~WS_CAPTION; - dwRemove |= WS_CAPTION; - break; - case MpcCaptionState::MODE_FRAMEONLY: - dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; - dwAdd &= ~WS_THICKFRAME; - dwRemove |= WS_THICKFRAME; - break; - default: - ASSERT(FALSE); - } - } - - UINT uFlags = SWP_NOZORDER; - if (dwRemove != dwAdd) { - uFlags |= SWP_FRAMECHANGED; - VERIFY(SetWindowLong(m_hWnd, GWL_STYLE, (GetWindowLong(m_hWnd, GWL_STYLE) | dwAdd) & ~dwRemove)); - } - - SetMenuBarVisibility(dwMenuFlags); - if (bZoomed) { - CMonitors::GetNearestMonitor(this).GetWorkAreaRect(windowRect); - } else { - VERIFY(AdjustWindowRectEx(windowRect, GetWindowStyle(m_hWnd), dwMenuFlags == AFX_MBV_KEEPVISIBLE, GetWindowExStyle(m_hWnd))); - } - - VERIFY(SetWindowPos(nullptr, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), uFlags)); - OSDBarSetPos(); -} - -void CMainFrame::OnViewCaptionmenu() -{ - const auto& s = AfxGetAppSettings(); - SetCaptionState(static_cast((s.eCaptionMenuMode + 1) % MpcCaptionState::MODE_COUNT)); -} - -void CMainFrame::OnUpdateViewCaptionmenu(CCmdUI* pCmdUI) -{ - const auto& s = AfxGetAppSettings(); - const UINT next[] = { IDS_VIEW_HIDEMENU, IDS_VIEW_FRAMEONLY, IDS_VIEW_BORDERLESS, IDS_VIEW_CAPTIONMENU }; - pCmdUI->SetText(ResStr(next[s.eCaptionMenuMode % MpcCaptionState::MODE_COUNT])); - CMPCThemeMenu::updateItem(pCmdUI); -} - -void CMainFrame::OnViewControlBar(UINT nID) -{ - nID -= ID_VIEW_SEEKER; - m_controls.ToggleControl(static_cast(nID)); -} - -void CMainFrame::OnUpdateViewControlBar(CCmdUI* pCmdUI) -{ - const UINT nID = pCmdUI->m_nID - ID_VIEW_SEEKER; - pCmdUI->SetCheck(m_controls.ControlChecked(static_cast(nID))); - if (pCmdUI->m_nID == ID_VIEW_SEEKER) { - pCmdUI->Enable(!IsPlaybackCaptureMode()); - } -} - -void CMainFrame::OnViewSubresync() -{ - m_controls.ToggleControl(CMainFrameControls::Panel::SUBRESYNC); - AdjustStreamPosPoller(true); -} - -void CMainFrame::OnUpdateViewSubresync(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::SUBRESYNC)); - bool enabled = m_pCAP && m_pCurrentSubInput.pSubStream && !IsPlaybackCaptureMode(); - if (enabled) { - CLSID clsid; - m_pCurrentSubInput.pSubStream->GetClassID(&clsid); - if (clsid == __uuidof(CRenderedTextSubtitle)) { -#if USE_LIBASS - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; - enabled = !pRTS->m_LibassContext.IsLibassActive(); -#endif - } else { - enabled = false; - } - } - pCmdUI->Enable(enabled); -} - -void CMainFrame::OnViewPlaylist() -{ - m_controls.ToggleControl(CMainFrameControls::Panel::PLAYLIST); - m_wndPlaylistBar.SetHiddenDueToFullscreen(false); -} - -void CMainFrame::OnUpdateViewPlaylist(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)); -} - -void CMainFrame::OnPlaylistToggleShuffle() { - CAppSettings& s = AfxGetAppSettings(); - s.bShufflePlaylistItems = !s.bShufflePlaylistItems; - m_wndPlaylistBar.m_pl.SetShuffle(s.bShufflePlaylistItems); -} - -void CMainFrame::OnViewEditListEditor() -{ - CAppSettings& s = AfxGetAppSettings(); - - if (s.fEnableEDLEditor || (AfxMessageBox(IDS_MB_SHOW_EDL_EDITOR, MB_ICONQUESTION | MB_YESNO, 0) == IDYES)) { - s.fEnableEDLEditor = true; - m_controls.ToggleControl(CMainFrameControls::Panel::EDL); - } -} - -void CMainFrame::OnEDLIn() -{ - if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { - REFERENCE_TIME rt; - - m_pMS->GetCurrentPosition(&rt); - m_wndEditListEditor.SetIn(rt); - } -} - -void CMainFrame::OnUpdateEDLIn(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); -} - -void CMainFrame::OnEDLOut() -{ - if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { - REFERENCE_TIME rt; - - m_pMS->GetCurrentPosition(&rt); - m_wndEditListEditor.SetOut(rt); - } -} - -void CMainFrame::OnUpdateEDLOut(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); -} - -void CMainFrame::OnEDLNewClip() -{ - if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { - REFERENCE_TIME rt; - - m_pMS->GetCurrentPosition(&rt); - m_wndEditListEditor.NewClip(rt); - } -} - -void CMainFrame::OnUpdateEDLNewClip(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); -} - -void CMainFrame::OnEDLSave() -{ - if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { - m_wndEditListEditor.Save(); - } -} - -void CMainFrame::OnUpdateEDLSave(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); -} - -// Navigation menu -void CMainFrame::OnViewNavigation() -{ - const bool bHiding = m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION); - m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); - if (!bHiding) { - m_wndNavigationBar.m_navdlg.UpdateElementList(); - } - AfxGetAppSettings().fHideNavigation = bHiding; -} - -void CMainFrame::OnUpdateViewNavigation(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_DIGITAL_CAPTURE); -} - -void CMainFrame::OnViewCapture() -{ - m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); -} - -void CMainFrame::OnUpdateViewCapture(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_ANALOG_CAPTURE); -} - -void CMainFrame::OnViewDebugShaders() -{ - auto& dlg = m_pDebugShaders; - if (dlg && !dlg->m_hWnd) { - // something has destroyed the dialog and we didn't know about it - dlg = nullptr; - } - if (!dlg) { - // dialog doesn't exist - create and show it - dlg = std::make_unique(); - dlg->ShowWindow(SW_SHOW); - } else if (dlg->IsWindowVisible()) { - if (dlg->IsIconic()) { - // dialog is visible but iconic - restore it - VERIFY(dlg->ShowWindow(SW_RESTORE)); - } else { - // dialog is visible and not iconic - destroy it - VERIFY(dlg->DestroyWindow()); - ASSERT(!dlg->m_hWnd); - dlg = nullptr; - } - } else { - // dialog is not visible - show it - VERIFY(!dlg->ShowWindow(SW_SHOW)); - } -} - -void CMainFrame::OnUpdateViewDebugShaders(CCmdUI* pCmdUI) -{ - const auto& dlg = m_pDebugShaders; - pCmdUI->SetCheck(dlg && dlg->m_hWnd && dlg->IsWindowVisible()); -} - -void CMainFrame::OnViewMinimal() -{ - SetCaptionState(MODE_BORDERLESS); - m_controls.SetToolbarsSelection(CS_NONE, true); -} - -void CMainFrame::OnUpdateViewMinimal(CCmdUI* pCmdUI) -{ -} - -void CMainFrame::OnViewCompact() -{ - SetCaptionState(MODE_FRAMEONLY); - m_controls.SetToolbarsSelection(CS_SEEKBAR, true); -} - -void CMainFrame::OnUpdateViewCompact(CCmdUI* pCmdUI) -{ -} - -void CMainFrame::OnViewNormal() -{ - SetCaptionState(MODE_SHOWCAPTIONMENU); - m_controls.SetToolbarsSelection(CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR, true); -} - -void CMainFrame::OnUpdateViewNormal(CCmdUI* pCmdUI) -{ -} - -void CMainFrame::OnViewFullscreen() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (IsD3DFullScreenMode() || (s.IsD3DFullscreen() && !m_fFullScreen && !m_fAudioOnly && m_pD3DFSC && m_pMFVDC)) { - ToggleD3DFullscreen(true); - } else { - ToggleFullscreen(true, true); - } -} - -void CMainFrame::OnViewFullscreenSecondary() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (IsD3DFullScreenMode() || (s.IsD3DFullscreen() && !m_fFullScreen && !m_fAudioOnly && m_pD3DFSC && m_pMFVDC)) { - ToggleD3DFullscreen(false); - } else { - ToggleFullscreen(true, false); - } -} - -void CMainFrame::OnUpdateViewFullscreen(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED || m_fFullScreen); - pCmdUI->SetCheck(m_fFullScreen); -} - -void CMainFrame::OnViewZoom(UINT nID) -{ - double scale = (nID == ID_VIEW_ZOOM_25) ? 0.25 : (nID == ID_VIEW_ZOOM_50) ? 0.5 : (nID == ID_VIEW_ZOOM_200) ? 2.0 : 1.0; - - ZoomVideoWindow(scale); - - CString strODSMessage; - strODSMessage.Format(IDS_OSD_ZOOM, scale * 100); - m_OSD.DisplayMessage(OSD_TOPLEFT, strODSMessage, 3000); -} - -void CMainFrame::OnUpdateViewZoom(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly); -} - -void CMainFrame::OnViewZoomAutoFit() -{ - ZoomVideoWindow(ZOOM_AUTOFIT); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_ZOOM_AUTO), 3000); -} - -void CMainFrame::OnViewZoomAutoFitLarger() -{ - ZoomVideoWindow(ZOOM_AUTOFIT_LARGER); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_ZOOM_AUTO_LARGER), 3000); -} - -void CMainFrame::OnViewModifySize(UINT nID) { - if (m_fFullScreen || !m_pVideoWnd || IsZoomed() || IsIconic() || GetLoadState() != MLS::LOADED) { - return; - } - - enum resizeMethod { - autoChoose - , byHeight - , byWidth - } usedMethod; - - const CAppSettings& s = AfxGetAppSettings(); - MINMAXINFO mmi; - CSize videoSize = GetVideoOrArtSize(mmi); - int minWidth = (int)mmi.ptMinTrackSize.x; - - int mult = (nID == ID_VIEW_ZOOM_ADD ? 1 : ID_VIEW_ZOOM_SUB ? -1 : 0); - - double videoRatio = double(videoSize.cy) / double(videoSize.cx); - - CRect videoRect, workRect, maxRect; - videoRect = m_pVideoWnd->GetVideoRect(); - double videoRectRatio = double(videoRect.Height()) / double(videoRect.Width()); - bool previouslyProportional = IsNearlyEqual(videoRectRatio, videoRatio, 0.01); - - GetWorkAreaRect(workRect); - maxRect = GetZoomWindowRect(CSize(INT_MAX, INT_MAX), true); - - CRect rect, zoomRect; - GetWindowRect(&rect); - CSize targetSize; - - auto calculateZoomWindowRect = [&](resizeMethod useMethod = autoChoose, CSize forceDimension = {0,0}) { - int newWidth = videoRect.Width(); - int newHeight = videoRect.Height(); - - if (useMethod == autoChoose) { - if (double(videoRect.Height()) / videoRect.Width() + 0.01f < videoRatio) { //wider than aspect ratio, so use height instead - useMethod = byHeight; - int growPixels = int(.02f * workRect.Height()); - newHeight = videoRect.Height() + growPixels * mult; - } else { - useMethod = byWidth; - int growPixels = int(.02f * workRect.Width()); - newWidth = std::max(videoRect.Width() + growPixels * mult, minWidth); - } - } else if (useMethod == byHeight) { - newHeight = forceDimension.cy + videoRect.Height() - rect.Height(); - } else { - newWidth = forceDimension.cx + videoRect.Width() - rect.Width(); - } - - if (useMethod == byHeight) { - double newRatio = double(newHeight) / double(videoRect.Width()); - if (s.fLimitWindowProportions || previouslyProportional || SGN(newRatio - videoRatio) != SGN(videoRectRatio - videoRatio)) { - newWidth = std::max(int(ceil(newHeight / videoRatio)), minWidth); - if (mult == 1) { - newWidth = std::max(newWidth, videoRect.Width()); - } - } - } else { - double newRatio = double(videoRect.Height()) / double(newWidth); - if (s.fLimitWindowProportions || previouslyProportional || SGN(newRatio - videoRatio) != SGN(videoRectRatio - videoRatio)) { - newHeight = int(ceil(newWidth * videoRatio)); - if (mult == 1) { - newHeight = std::max(newHeight, videoRect.Height()); - } - } - } - targetSize = rect.Size() + CSize(newWidth - videoRect.Width(), newHeight - videoRect.Height()); - usedMethod = useMethod; - return GetZoomWindowRect(targetSize, true); - }; - - zoomRect = calculateZoomWindowRect(); - - CRect newRect, work; - newRect = CRect(rect.TopLeft(), targetSize); //this will be our default - - //if old rect was constrained to a single monitor, we zoom incrementally - if (GetWorkAreaRect(work) && work.PtInRect(rect.TopLeft()) && work.PtInRect(rect.BottomRight()-CSize(1,1)) - && ((zoomRect.Height() != rect.Height() && usedMethod == byHeight) || (zoomRect.Width() != rect.Width() && usedMethod == byWidth))) { - - if (zoomRect.Width() != targetSize.cx && zoomRect.Width() == maxRect.Width()) { //we appear to have been constrained by Screen Width - if (maxRect.Width() != rect.Width()) { //if it wasn't already filling the monitor horizonally, we will do that now - newRect = calculateZoomWindowRect(byWidth, maxRect.Size()); - } - } else if (zoomRect.Height() != targetSize.cy && zoomRect.Height() == maxRect.Height()) { //we appear to have been constrained by Screen Height - if (maxRect.Height() != rect.Height()) { //if it wasn't already filling the monitor vertically, we will do that now - newRect = calculateZoomWindowRect(byHeight, maxRect.Size()); - } - } else { - newRect = zoomRect; - } - } - - MoveWindow(newRect); -} - -void CMainFrame::OnViewDefaultVideoFrame(UINT nID) -{ - AfxGetAppSettings().iDefaultVideoSize = nID - ID_VIEW_VF_HALF; - m_ZoomX = m_ZoomY = 1; - m_PosX = m_PosY = 0.5; - MoveVideoWindow(); -} - -void CMainFrame::OnUpdateViewDefaultVideoFrame(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && s.iDSVideoRendererType != VIDRNDT_DS_EVR); - - int dvs = pCmdUI->m_nID - ID_VIEW_VF_HALF; - if (s.iDefaultVideoSize == dvs && pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, pCmdUI->m_nID, MF_BYCOMMAND); - } -} - -void CMainFrame::OnViewSwitchVideoFrame() -{ - CAppSettings& s = AfxGetAppSettings(); - - int vs = s.iDefaultVideoSize; - if (vs <= DVS_DOUBLE || vs == DVS_FROMOUTSIDE) { - vs = DVS_STRETCH; - } else if (vs == DVS_FROMINSIDE) { - vs = DVS_ZOOM1; - } else if (vs == DVS_ZOOM2) { - vs = DVS_FROMOUTSIDE; - } else { - vs++; - } - switch (vs) { // TODO: Read messages from resource file - case DVS_STRETCH: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_STRETCH_TO_WINDOW)); - break; - case DVS_FROMINSIDE: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_TOUCH_WINDOW_FROM_INSIDE)); - break; - case DVS_ZOOM1: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_ZOOM1)); - break; - case DVS_ZOOM2: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_ZOOM2)); - break; - case DVS_FROMOUTSIDE: - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_TOUCH_WINDOW_FROM_OUTSIDE)); - break; - } - s.iDefaultVideoSize = vs; - m_ZoomX = m_ZoomY = 1; - m_PosX = m_PosY = 0.5; - MoveVideoWindow(); -} - -void CMainFrame::OnViewCompMonDeskARDiff() -{ - CAppSettings& s = AfxGetAppSettings(); - - s.fCompMonDeskARDiff = !s.fCompMonDeskARDiff; - OnVideoSizeChanged(); -} - -void CMainFrame::OnUpdateViewCompMonDeskARDiff(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - - pCmdUI->Enable(GetLoadState() == MLS::LOADED - && !m_fAudioOnly - && s.iDSVideoRendererType != VIDRNDT_DS_EVR - // This doesn't work with madVR due to the fact that it positions video itself. - // And it has exactly the same option built in. - && s.iDSVideoRendererType != VIDRNDT_DS_MADVR); - pCmdUI->SetCheck(s.fCompMonDeskARDiff); -} - -void CMainFrame::OnViewPanNScan(UINT nID) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - int x = 0, y = 0; - int dx = 0, dy = 0; - - switch (nID) { - case ID_VIEW_RESET: - // Subtitle overrides - ResetSubtitlePosAndSize(true); - // Pan&Scan - m_ZoomX = m_ZoomY = 1.0; - m_PosX = m_PosY = 0.5; - m_AngleX = m_AngleY = m_AngleZ = 0; - PerformFlipRotate(); - break; - case ID_VIEW_INCSIZE: - x = y = 1; - break; - case ID_VIEW_DECSIZE: - x = y = -1; - break; - case ID_VIEW_INCWIDTH: - x = 1; - break; - case ID_VIEW_DECWIDTH: - x = -1; - break; - case ID_VIEW_INCHEIGHT: - y = 1; - break; - case ID_VIEW_DECHEIGHT: - y = -1; - break; - case ID_PANSCAN_CENTER: - m_PosX = m_PosY = 0.5; - break; - case ID_PANSCAN_MOVELEFT: - dx = -1; - break; - case ID_PANSCAN_MOVERIGHT: - dx = 1; - break; - case ID_PANSCAN_MOVEUP: - dy = -1; - break; - case ID_PANSCAN_MOVEDOWN: - dy = 1; - break; - case ID_PANSCAN_MOVEUPLEFT: - dx = dy = -1; - break; - case ID_PANSCAN_MOVEUPRIGHT: - dx = 1; - dy = -1; - break; - case ID_PANSCAN_MOVEDOWNLEFT: - dx = -1; - dy = 1; - break; - case ID_PANSCAN_MOVEDOWNRIGHT: - dx = dy = 1; - break; - default: - break; - } - - if (x > 0 && m_ZoomX < 5.0) { - m_ZoomX = std::min(m_ZoomX * 1.02, 5.0); - } else if (x < 0 && m_ZoomX > 0.2) { - m_ZoomX = std::max(m_ZoomX / 1.02, 0.2); - } - - if (y > 0 && m_ZoomY < 5.0) { - m_ZoomY = std::min(m_ZoomY * 1.02, 5.0); - } else if (y < 0 && m_ZoomY > 0.2) { - m_ZoomY = std::max(m_ZoomY / 1.02, 0.2); - } - - if (dx < 0 && m_PosX > -0.5) { - m_PosX = std::max(m_PosX - 0.005 * m_ZoomX, -0.5); - } else if (dx > 0 && m_PosX < 1.5) { - m_PosX = std::min(m_PosX + 0.005 * m_ZoomX, 1.5); - } - - if (dy < 0 && m_PosY > -0.5) { - m_PosY = std::max(m_PosY - 0.005 * m_ZoomY, -0.5); - } else if (dy > 0 && m_PosY < 1.5) { - m_PosY = std::min(m_PosY + 0.005 * m_ZoomY, 1.5); - } - - MoveVideoWindow(true); -} - -void CMainFrame::OnUpdateViewPanNScan(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && AfxGetAppSettings().iDSVideoRendererType != VIDRNDT_DS_EVR); -} - -void CMainFrame::ApplyPanNScanPresetString() -{ - auto& s = AfxGetAppSettings(); - - if (s.strPnSPreset.IsEmpty()) - return; - - if (s.strPnSPreset.Find(',') != -1) { // try to set raw values - if (_stscanf_s(s.strPnSPreset, _T("%lf,%lf,%lf,%lf"), &m_PosX, &m_PosY, &m_ZoomX, &m_ZoomY) == 4) { - ValidatePanNScanParameters(); - MoveVideoWindow(); - } - } else { // try to set named preset - for (int i = 0; i < s.m_pnspresets.GetCount(); i++) { - int j = 0; - CString str = s.m_pnspresets[i]; - CString label = str.Tokenize(_T(","), j); - if (s.strPnSPreset == label) { - OnViewPanNScanPresets(i + ID_PANNSCAN_PRESETS_START); - } - } - } - - s.strPnSPreset.Empty(); -} - -void CMainFrame::OnViewPanNScanPresets(UINT nID) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - - nID -= ID_PANNSCAN_PRESETS_START; - - if ((INT_PTR)nID == s.m_pnspresets.GetCount()) { - CPnSPresetsDlg dlg; - dlg.m_pnspresets.Copy(s.m_pnspresets); - if (dlg.DoModal() == IDOK) { - s.m_pnspresets.Copy(dlg.m_pnspresets); - s.SaveSettings(); - } - return; - } - - m_PosX = 0.5; - m_PosY = 0.5; - m_ZoomX = 1.0; - m_ZoomY = 1.0; - - CString str = s.m_pnspresets[nID]; - - int i = 0, j = 0; - for (CString token = str.Tokenize(_T(","), i); !token.IsEmpty(); token = str.Tokenize(_T(","), i), j++) { - float f = 0; - if (_stscanf_s(token, _T("%f"), &f) != 1) { - continue; - } - - switch (j) { - case 0: - break; - case 1: - m_PosX = f; - break; - case 2: - m_PosY = f; - break; - case 3: - m_ZoomX = f; - break; - case 4: - m_ZoomY = f; - break; - default: - break; - } - } - - if (j != 5) { - return; - } - - ValidatePanNScanParameters(); - - MoveVideoWindow(true); -} - -void CMainFrame::ValidatePanNScanParameters() -{ - m_PosX = std::min(std::max(m_PosX, -0.5), 1.5); - m_PosY = std::min(std::max(m_PosY, -0.5), 1.5); - m_ZoomX = std::min(std::max(m_ZoomX, 0.2), 5.0); - m_ZoomY = std::min(std::max(m_ZoomY, 0.2), 5.0); -} - -void CMainFrame::OnUpdateViewPanNScanPresets(CCmdUI* pCmdUI) -{ - int nID = pCmdUI->m_nID - ID_PANNSCAN_PRESETS_START; - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && nID >= 0 && nID <= s.m_pnspresets.GetCount() && s.iDSVideoRendererType != VIDRNDT_DS_EVR); -} - -int nearest90(int angle) { - return int(float(angle) / 90 + 0.5) * 90; -} - -bool CMainFrame::PerformFlipRotate() -{ - HRESULT hr = E_NOTIMPL; - // Note: m_AngleZ is counterclockwise, so value 270 means rotated 90 degrees clockwise - if (m_pCAP3) { - bool isFlip = m_AngleX == 180; - bool isMirror = m_AngleY == 180; - int rotation = (360 - m_AngleZ + m_iDefRotation) % 360; - if (m_pMVRS) { - // MadVR: does not support mirror, instead of flip we rotate 180 degrees - hr = m_pCAP3->SetRotation(isFlip ? (rotation + 180) % 360 : rotation); - } else { - // MPCVR: instead of flip, we mirror plus rotate 180 degrees - hr = m_pCAP3->SetRotation(isFlip ? (rotation + 180) % 360 : rotation); - if (SUCCEEDED(hr)) { - // SetFlip actually mirrors instead of doing vertical flip - hr = m_pCAP3->SetFlip(isFlip || isMirror); - } - } - } else if (m_pCAP) { - // EVR-CP behavior for custom angles is ignored when choosing video size and zoom - // We get better results if we treat the closest 90 as the standard rotation, and custom rotate the remainder (<45deg) - int z = m_AngleZ; - if (m_pCAP2) { - int nZ = nearest90(z); - z = (z - nZ + 360) % 360; - Vector defAngle = Vector(0, 0, Vector::DegToRad((nZ - m_iDefRotation + 360) % 360)); - m_pCAP2->SetDefaultVideoAngle(defAngle); - } - - hr = m_pCAP->SetVideoAngle(Vector(Vector::DegToRad(m_AngleX), Vector::DegToRad(m_AngleY), Vector::DegToRad(z))); - } - - if (FAILED(hr)) { - m_AngleX = m_AngleY = m_AngleZ = 0; - return false; - } - if (m_pCAP2_preview) { //we support rotating preview - PreviewWindowHide(); - m_wndPreView.SetWindowSize(); - SetPreviewVideoPosition(); - //adipose: using defaultvideoangle instead of videoangle, as some oddity with AR shows up when using normal rotate with EVRCP. - //Since we only need to support 4 angles, this will work, but it *should* work with SetVideoAngle... - - hr = m_pCAP2_preview->SetDefaultVideoAngle(Vector(Vector::DegToRad(nearest90(m_AngleX)), Vector::DegToRad(nearest90(m_AngleY)), Vector::DegToRad(defaultVideoAngle + nearest90(m_AngleZ)))); - } - - return true; -} - -void CMainFrame::OnViewRotate(UINT nID) -{ - switch (nID) { - case ID_PANSCAN_ROTATEXP: - if (!m_pCAP3) { - m_AngleX += 2; - break; - } - [[fallthrough]]; // fall through for m_pCAP3 - case ID_PANSCAN_ROTATEXM: - if (m_AngleX >= 180) { - m_AngleX = 0; - } else { - m_AngleX = 180; - } - break; - case ID_PANSCAN_ROTATEYP: - if (!m_pCAP3) { - m_AngleY += 2; - break; - } - [[fallthrough]]; - case ID_PANSCAN_ROTATEYM: - if (m_AngleY >= 180) { - m_AngleY = 0; - } else { - m_AngleY = 180; - } - break; - case ID_PANSCAN_ROTATEZM: - if (m_AngleZ == 0 || m_AngleZ > 270) { - m_AngleZ = 270; - } else if (m_AngleZ > 180) { - m_AngleZ = 180; - } else if (m_AngleZ > 90) { - m_AngleZ = 90; - } else if (m_AngleZ > 0) { - m_AngleZ = 0; - } - break; - case ID_PANSCAN_ROTATEZP: - if (!m_pCAP3) { - m_AngleZ += 2; - break; - } - [[fallthrough]]; - case ID_PANSCAN_ROTATEZ270: - if (m_AngleZ < 90) { - m_AngleZ = 90; - } else if (m_AngleZ >= 270) { - m_AngleZ = 0; - } else if (m_AngleZ >= 180) { - m_AngleZ = 270; - } else if (m_AngleZ >= 90) { - m_AngleZ = 180; - } - break; - default: - return; - } - - m_AngleX %= 360; - m_AngleY %= 360; - if (m_AngleX == 180 && m_AngleY == 180) { - m_AngleX = m_AngleY = 0; - m_AngleZ += 180; - } - m_AngleZ %= 360; - - ASSERT(m_AngleX >= 0); - ASSERT(m_AngleY >= 0); - ASSERT(m_AngleZ >= 0); - - if (PerformFlipRotate()) { - // FIXME: do proper resizing of the window after rotate - if (!m_pMVRC) { - MoveVideoWindow(); - } - - CString info; - info.Format(_T("x: %d, y: %d, z: %d"), m_AngleX, m_AngleY, m_AngleZ); - SendStatusMessage(info, 3000); - } -} - -void CMainFrame::OnUpdateViewRotate(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (m_pCAP || m_pCAP3)); -} - -// FIXME -const static SIZE s_ar[] = {{0, 0}, {4, 3}, {5, 4}, {16, 9}, {235, 100}, {185, 100}}; - -void CMainFrame::OnViewAspectRatio(UINT nID) -{ - auto& s = AfxGetAppSettings(); - - CString info; - if (nID == ID_ASPECTRATIO_SAR) { - s.fKeepAspectRatio = false; - info.LoadString(IDS_ASPECT_RATIO_SAR); - } else { - s.fKeepAspectRatio = true; - CSize ar = s_ar[nID - ID_ASPECTRATIO_START]; - s.SetAspectRatioOverride(ar); - if (ar.cx && ar.cy) { - info.Format(IDS_MAINFRM_68, ar.cx, ar.cy); - } else { - info.LoadString(IDS_MAINFRM_69); - } - } - - SendStatusMessage(info, 3000); - m_OSD.DisplayMessage(OSD_TOPLEFT, info, 3000); - - OnVideoSizeChanged(); -} - -void CMainFrame::OnUpdateViewAspectRatio(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - - bool bSelected; - if (pCmdUI->m_nID == ID_ASPECTRATIO_SAR) { - bSelected = s.fKeepAspectRatio == false; - } else { - bSelected = s.fKeepAspectRatio == true && s.GetAspectRatioOverride() == s_ar[pCmdUI->m_nID - ID_ASPECTRATIO_START]; - } - if (bSelected && pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, pCmdUI->m_nID, MF_BYCOMMAND); - } - - pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && s.iDSVideoRendererType != VIDRNDT_DS_EVR); -} - -void CMainFrame::OnViewAspectRatioNext() -{ - static_assert(ID_ASPECTRATIO_SAR - ID_ASPECTRATIO_START == _countof(s_ar) && ID_ASPECTRATIO_SAR == ID_ASPECTRATIO_END, - "ID_ASPECTRATIO_SAR needs to be last item in the menu."); - - const auto& s = AfxGetAppSettings(); - UINT nID = ID_ASPECTRATIO_START; - if (s.fKeepAspectRatio) { - const CSize ar = s.GetAspectRatioOverride(); - for (int i = 0; i < _countof(s_ar); i++) { - if (ar == s_ar[i]) { - nID += (i + 1) % ((ID_ASPECTRATIO_END - ID_ASPECTRATIO_START) + 1); - break; - } - } - } - - OnViewAspectRatio(nID); -} - -void CMainFrame::OnViewOntop(UINT nID) -{ - nID -= ID_ONTOP_DEFAULT; - if (AfxGetAppSettings().iOnTop == (int)nID) { - nID = !nID; - } - SetAlwaysOnTop(nID); -} - -void CMainFrame::OnUpdateViewOntop(CCmdUI* pCmdUI) -{ - int onTop = pCmdUI->m_nID - ID_ONTOP_DEFAULT; - if (AfxGetAppSettings().iOnTop == onTop && pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, pCmdUI->m_nID, MF_BYCOMMAND); - } -} - -void CMainFrame::OnViewOptions() -{ - ShowOptions(); -} - -// play - -void CMainFrame::OnPlayPlay() -{ - const CAppSettings& s = AfxGetAppSettings(); - - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); - m_bOpeningInAutochangedMonitorMode = false; - m_bPausedForAutochangeMonitorMode = false; - - if (GetLoadState() == MLS::CLOSED) { - m_bFirstPlay = false; - OpenCurPlaylistItem(); - return; - } - - if (GetLoadState() == MLS::LOADING) { - return; - } - - if (GetLoadState() == MLS::LOADED) { - // If playback was previously stopped or ended, we need to reset the window size - bool bVideoWndNeedReset = GetMediaState() == State_Stopped || m_fEndOfStream; - - KillTimersStop(); - - if (GetPlaybackMode() == PM_FILE) { - if (m_fEndOfStream) { - SendMessage(WM_COMMAND, ID_PLAY_STOP); - } else { - if (!m_fAudioOnly && m_dwLastPause && m_wndSeekBar.HasDuration() && s.iReloadAfterLongPause >= 0) { - // after long pause or hibernation, reload video file to avoid playback issues on some systems (with buggy drivers) - // in case of hibernate, m_dwLastPause equals 1 - if (m_dwLastPause == 1 || s.iReloadAfterLongPause > 0 && (GetTickCount64() - m_dwLastPause >= s.iReloadAfterLongPause * 60 * 1000)) { - m_dwReloadPos = m_wndSeekBar.GetPos(); - reloadABRepeat = abRepeat; - m_iReloadAudioIdx = GetCurrentAudioTrackIdx(); - m_iReloadSubIdx = GetCurrentSubtitleTrackIdx(); - OnFileReopen(); - return; - } - } - } - if (m_pMS) { - if (FAILED(m_pMS->SetRate(m_dSpeedRate))) { - m_dSpeedRate = 1.0; - } - } - } else if (GetPlaybackMode() == PM_DVD) { - m_dSpeedRate = 1.0; - m_pDVDC->PlayForwards(m_dSpeedRate, DVD_CMD_FLAG_Block, nullptr); - m_pDVDC->Pause(FALSE); - } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - MediaControlStop(); // audio preview won't be in sync if we run it from paused state - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - bVideoWndNeedReset = false; // SetChannel deals with MoveVideoWindow - SetChannel(s.nDVBLastChannel); - } else { - ASSERT(FALSE); - } - } else { - ASSERT(FALSE); - } - - if (bVideoWndNeedReset) { - MoveVideoWindow(false, true); - } - - if (m_fFrameSteppingActive) { - m_pFS->CancelStep(); - m_fFrameSteppingActive = false; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } else { - if (m_pBA) { - m_pBA->put_Volume(m_wndToolBar.Volume); - } - } - m_nStepForwardCount = 0; - - // Restart playback - MediaControlRun(); - - SetAlwaysOnTop(s.iOnTop); - - SetTimersPlay(); - } - - m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_PLAYING), 3000); - SetPlayState(PS_PLAY); - - OnTimer(TIMER_STREAMPOSPOLLER); - - SetupEVRColorControl(); // can be configured when streaming begins - - if (m_OSD.CanShowMessage()) { - CString strOSD; - CString strPlay(StrRes(ID_PLAY_PLAY)); - int i = strPlay.Find(_T("\n")); - if (i > 0) { - strPlay.Delete(i, strPlay.GetLength() - i); - } - - if (m_bFirstPlay) { - if (GetPlaybackMode() == PM_FILE) { - if (!m_LastOpenBDPath.IsEmpty()) { - strOSD.LoadString(IDS_PLAY_BD); - } else { - strOSD = GetFileName(); - CPlaylistItem pli; - if (!strOSD.IsEmpty() && (!m_wndPlaylistBar.GetCur(pli) || !pli.m_bYoutubeDL)) { - strOSD.TrimRight('/'); - strOSD.Replace('\\', '/'); - strOSD = strOSD.Mid(strOSD.ReverseFind('/') + 1); - } - } - } else if (GetPlaybackMode() == PM_DVD) { - strOSD.LoadString(IDS_PLAY_DVD); - } - } - - if (strOSD.IsEmpty()) { - strOSD = strPlay; - } - if (GetPlaybackMode() != PM_DIGITAL_CAPTURE) { - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - } - } - - m_bFirstPlay = false; -} - -void CMainFrame::OnPlayPause() -{ - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); - m_bOpeningInAutochangedMonitorMode = false; - - if (GetLoadState() == MLS::LOADED && GetMediaState() == State_Stopped) { - MoveVideoWindow(false, true); - } - - if (GetLoadState() == MLS::LOADED) { - if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD || GetPlaybackMode() == PM_ANALOG_CAPTURE) { - if (m_fFrameSteppingActive) { - m_pFS->CancelStep(); - m_fFrameSteppingActive = false; - m_nStepForwardCount = 0; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } - MediaControlPause(true); - } else { - ASSERT(FALSE); - } - - KillTimer(TIMER_STATS); - SetAlwaysOnTop(AfxGetAppSettings().iOnTop); - } - - CString strOSD(StrRes(ID_PLAY_PAUSE)); - int i = strOSD.Find(_T("\n")); - if (i > 0) { - strOSD.Delete(i, strOSD.GetLength() - i); - } - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_PAUSED), 3000); - SetPlayState(PS_PAUSE); -} - -void CMainFrame::OnPlayPlaypause() -{ - if (GetLoadState() == MLS::LOADED) { - OAFilterState fs = GetMediaState(); - if (fs == State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } else if (fs == State_Stopped || fs == State_Paused) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - } else if (GetLoadState() == MLS::CLOSED && !IsPlaylistEmpty()) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } -} - -void CMainFrame::OnApiPause() -{ - OAFilterState fs = GetMediaState(); - if (fs == State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } -} -void CMainFrame::OnApiPlay() -{ - OAFilterState fs = GetMediaState(); - if (fs == State_Stopped || fs == State_Paused) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } -} - -void CMainFrame::OnPlayStop() -{ - OnPlayStop(false); -} - -void CMainFrame::OnPlayStop(bool is_closing) -{ - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); - m_bOpeningInAutochangedMonitorMode = false; - m_bPausedForAutochangeMonitorMode = false; - - KillTimersStop(); - - m_wndSeekBar.SetPos(0); - if (GetLoadState() == MLS::LOADED) { - if (GetPlaybackMode() == PM_FILE) { - if (!is_closing) { - LONGLONG pos = 0; - m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - MediaControlStop(true); - if (m_bUseSeekPreview) { - MediaControlStopPreview(); - } - - if (m_pAMNS && m_pFSF) { - // After pause or stop the netshow url source filter won't continue - // on the next play command, unless we cheat it by setting the file name again. - WCHAR* pFN = nullptr; - AM_MEDIA_TYPE mt; - if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { - m_pFSF->Load(pFN, nullptr); - CoTaskMemFree(pFN); - } - } - } else if (GetPlaybackMode() == PM_DVD) { - m_pDVDC->SetOption(DVD_ResetOnStop, TRUE); - MediaControlStop(true); - m_pDVDC->SetOption(DVD_ResetOnStop, FALSE); - - if (m_bUseSeekPreview && m_pDVDC_preview) { - m_pDVDC_preview->SetOption(DVD_ResetOnStop, TRUE); - MediaControlStopPreview(); - m_pDVDC_preview->SetOption(DVD_ResetOnStop, FALSE); - } - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - MediaControlStop(true); - m_pDVBState->bActive = false; - OpenSetupWindowTitle(); - m_wndStatusBar.SetStatusTimer(StrRes(IDS_CAPTURE_LIVE)); - } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - MediaControlStop(true); - } - - m_dSpeedRate = 1.0; - - if (m_fFrameSteppingActive) { - m_pFS->CancelStep(); - m_fFrameSteppingActive = false; - m_nStepForwardCount = 0; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } - m_nStepForwardCount = 0; - } else if (GetLoadState() == MLS::CLOSING) { - MediaControlStop(true); - } - - m_nLoops = 0; - - if (m_hWnd) { - MoveVideoWindow(); - - if (!is_closing && GetLoadState() == MLS::LOADED) { - __int64 start, stop; - m_wndSeekBar.GetRange(start, stop); - if (!IsPlaybackCaptureMode()) { - m_wndStatusBar.SetStatusTimer(m_wndSeekBar.GetPos(), stop, IsSubresyncBarVisible(), GetTimeFormat()); - } - - SetAlwaysOnTop(AfxGetAppSettings().iOnTop); - } - } - - if (!is_closing && !m_fEndOfStream && GetLoadState() == MLS::LOADED) { - CString strOSD(StrRes(ID_PLAY_STOP)); - int i = strOSD.Find(_T("\n")); - if (i > 0) { - strOSD.Delete(i, strOSD.GetLength() - i); - } - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_STOPPED), 3000); - } else { - m_fEndOfStream = false; - } - - SetPlayState(PS_STOP); -} - -void CMainFrame::OnUpdatePlayPauseStop(CCmdUI* pCmdUI) -{ - bool fEnable = false; - bool fCheck = false; - - if (GetLoadState() == MLS::LOADED) { - OAFilterState fs = m_fFrameSteppingActive ? State_Paused : GetMediaState(); - - fCheck = pCmdUI->m_nID == ID_PLAY_PLAY && fs == State_Running || - pCmdUI->m_nID == ID_PLAY_PAUSE && fs == State_Paused || - pCmdUI->m_nID == ID_PLAY_STOP && fs == State_Stopped || - pCmdUI->m_nID == ID_PLAY_PLAYPAUSE && (fs == State_Paused || fs == State_Running); - - if (fs >= 0) { - if (GetPlaybackMode() == PM_FILE || IsPlaybackCaptureMode()) { - fEnable = true; - - if (m_fCapturing) { - fEnable = false; - } else if (m_fLiveWM && pCmdUI->m_nID == ID_PLAY_PAUSE) { - fEnable = false; - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE && pCmdUI->m_nID == ID_PLAY_PAUSE) { - fEnable = false; // Disable pause for digital capture mode to avoid accidental playback stop. We don't support time shifting yet. - } - } else if (GetPlaybackMode() == PM_DVD) { - fEnable = m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu - && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu; - - if (fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE) { - fEnable = false; - } - } - } - } else if (GetLoadState() == MLS::CLOSED) { - fEnable = (pCmdUI->m_nID == ID_PLAY_PLAY || pCmdUI->m_nID == ID_PLAY_PLAYPAUSE) && !IsPlaylistEmpty(); - } - - pCmdUI->SetCheck(fCheck); - pCmdUI->Enable(fEnable); -} - -void CMainFrame::OnPlayFramestep(UINT nID) -{ - if (!m_pFS && !m_pMS) { - return; - } - - KillTimerDelayedSeek(); - - m_OSD.EnableShowMessage(false); - - if (m_CachedFilterState == State_Paused) { - // Double check the state, because graph may have silently gone into a running state after performing a framestep - if (UpdateCachedMediaState() != State_Paused) { - MediaControlPause(true); - } - } else { - KillTimer(TIMER_STATS); - MediaControlPause(true); - } - - if (nID == ID_PLAY_FRAMESTEP && m_pFS) { - // To support framestep back, store the initial position when - // stepping forward - if (m_nStepForwardCount == 0) { - if (GetPlaybackMode() == PM_DVD) { - OnTimer(TIMER_STREAMPOSPOLLER); - m_rtStepForwardStart = m_wndSeekBar.GetPos(); - } else { - m_pMS->GetCurrentPosition(&m_rtStepForwardStart); - } - } - - if (!m_fFrameSteppingActive) { - m_fFrameSteppingActive = true; - m_nVolumeBeforeFrameStepping = m_wndToolBar.Volume; - if (m_pBA) { - m_pBA->put_Volume(-10000); - } - } - - HRESULT hr = m_pFS->Step(1, nullptr); - if (FAILED(hr)) { - TRACE(_T("Frame step failed.\n")); - m_fFrameSteppingActive = false; - m_nStepForwardCount = 0; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } - } else if (m_pMS && (m_nStepForwardCount == 0) && (S_OK == m_pMS->IsFormatSupported(&TIME_FORMAT_FRAME))) { - if (SUCCEEDED(m_pMS->SetTimeFormat(&TIME_FORMAT_FRAME))) { - REFERENCE_TIME rtCurPos; - - if (SUCCEEDED(m_pMS->GetCurrentPosition(&rtCurPos))) { - rtCurPos += (nID == ID_PLAY_FRAMESTEP) ? 1 : -1; - - m_pMS->SetPositions(&rtCurPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - m_pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME); - } - } else { // nID == ID_PLAY_FRAMESTEP_BACK - const REFERENCE_TIME rtAvgTimePerFrame = std::llround(GetAvgTimePerFrame() * 10000000LL); - REFERENCE_TIME rtCurPos = 0; - - if (m_nStepForwardCount) { // Exit of framestep forward, calculate current position - m_pFS->CancelStep(); - rtCurPos = m_rtStepForwardStart + m_nStepForwardCount * rtAvgTimePerFrame; - m_nStepForwardCount = 0; - rtCurPos -= rtAvgTimePerFrame; - } else if (GetPlaybackMode() == PM_DVD) { - // IMediaSeeking doesn't work properly with DVD Navigator - // Unfortunately, IDvdInfo2::GetCurrentLocation is inaccurate as well and only updates position approx. once per 500ms - // Due to inaccurate start position value, framestep backwards simply doesn't work well with DVDs. - // Seeking has same accuracy problem. Best we can do is jump back 500ms to at least get to a different frame. - OnTimer(TIMER_STREAMPOSPOLLER); - rtCurPos = m_wndSeekBar.GetPos(); - rtCurPos -= 5000000LL; - } else { - m_pMS->GetCurrentPosition(&rtCurPos); - rtCurPos -= rtAvgTimePerFrame; - } - - DoSeekTo(rtCurPos, false); - } - m_OSD.EnableShowMessage(); -} - -void CMainFrame::OnUpdatePlayFramestep(CCmdUI* pCmdUI) -{ - bool fEnable = false; - - if (pCmdUI->m_nID == ID_PLAY_FRAMESTEP) { - if (!m_fAudioOnly && !m_fLiveWM && GetLoadState() == MLS::LOADED && (GetPlaybackMode() == PM_FILE || (GetPlaybackMode() == PM_DVD && m_iDVDDomain == DVD_DOMAIN_Title))) { - if (m_pFS || m_pMS && (S_OK == m_pMS->IsFormatSupported(&TIME_FORMAT_FRAME))) { - fEnable = true; - } - } - } - pCmdUI->Enable(fEnable); -} - -void CMainFrame::OnPlaySeek(UINT nID) -{ - const auto& s = AfxGetAppSettings(); - - REFERENCE_TIME rtJumpDiff = - nID == ID_PLAY_SEEKBACKWARDSMALL ? -10000i64 * s.nJumpDistS : - nID == ID_PLAY_SEEKFORWARDSMALL ? +10000i64 * s.nJumpDistS : - nID == ID_PLAY_SEEKBACKWARDMED ? -10000i64 * s.nJumpDistM : - nID == ID_PLAY_SEEKFORWARDMED ? +10000i64 * s.nJumpDistM : - nID == ID_PLAY_SEEKBACKWARDLARGE ? -10000i64 * s.nJumpDistL : - nID == ID_PLAY_SEEKFORWARDLARGE ? +10000i64 * s.nJumpDistL : - 0; - - if (rtJumpDiff == 0) { - ASSERT(FALSE); - return; - } - - if (m_fShockwaveGraph) { - // HACK: the custom graph should support frame based seeking instead - rtJumpDiff /= 10000i64 * 100; - } - - const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); - REFERENCE_TIME rtSeekTo = rtPos + rtJumpDiff; - if (rtSeekTo < 0) { - rtSeekTo = 0; - } - - if (s.bFastSeek && !m_kfs.empty()) { - REFERENCE_TIME rtMaxForwardDiff; - REFERENCE_TIME rtMaxBackwardDiff; - if (s.bAllowInaccurateFastseek && (s.nJumpDistS >= 5000 || (nID != ID_PLAY_SEEKBACKWARDSMALL) && (nID != ID_PLAY_SEEKFORWARDSMALL))) { - if (rtJumpDiff > 0) { - rtMaxForwardDiff = 200000000LL; - rtMaxBackwardDiff = rtJumpDiff / 2; - } else { - rtMaxForwardDiff = -rtJumpDiff / 2; - rtMaxBackwardDiff = 200000000LL; - } - } else { - rtMaxForwardDiff = rtMaxBackwardDiff = std::min(100000000LL, abs(rtJumpDiff) * 3 / 10); - } - rtSeekTo = GetClosestKeyFrame(rtSeekTo, rtMaxForwardDiff, rtMaxBackwardDiff); - } - - SeekTo(rtSeekTo); -} - -void CMainFrame::OnPlaySeekSet() -{ - const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); - REFERENCE_TIME rtStart, rtStop; - m_wndSeekBar.GetRange(rtStart, rtStop); - - if (abRepeat.positionA > rtStart && abRepeat.positionA < rtStop) { - rtStart = abRepeat.positionA; - } - if (rtPos != rtStart) { - SeekTo(rtStart, false); - } -} - -void CMainFrame::AdjustStreamPosPoller(bool restart) -{ - int current_value = m_iStreamPosPollerInterval; - - if (g_bExternalSubtitleTime || IsSubresyncBarVisible()) { - m_iStreamPosPollerInterval = 40; - } else { - m_iStreamPosPollerInterval = AfxGetAppSettings().nStreamPosPollerInterval; - } - - if (restart && current_value != m_iStreamPosPollerInterval) { - if (KillTimer(TIMER_STREAMPOSPOLLER)) { - SetTimer(TIMER_STREAMPOSPOLLER, m_iStreamPosPollerInterval, nullptr); - } - } -} - -void CMainFrame::SetTimersPlay() -{ - AdjustStreamPosPoller(false); - - SetTimer(TIMER_STREAMPOSPOLLER, m_iStreamPosPollerInterval, nullptr); - SetTimer(TIMER_STREAMPOSPOLLER2, 500, nullptr); - SetTimer(TIMER_STATS, 1000, nullptr); -} - -void CMainFrame::KillTimerDelayedSeek() -{ - KillTimer(TIMER_DELAYEDSEEK); - queuedSeek = { 0, 0, false }; -} - -void CMainFrame::KillTimersStop() -{ - KillTimerDelayedSeek(); - KillTimer(TIMER_STREAMPOSPOLLER2); - KillTimer(TIMER_STREAMPOSPOLLER); - KillTimer(TIMER_STATS); - m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DVBINFO_UPDATE); -} - -void CMainFrame::OnPlaySeekKey(UINT nID) -{ - if (!m_kfs.empty()) { - bool bSeekingForward = (nID == ID_PLAY_SEEKKEYFORWARD); - const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); - REFERENCE_TIME rtKeyframe; - REFERENCE_TIME rtTarget; - REFERENCE_TIME rtMin; - REFERENCE_TIME rtMax; - if (bSeekingForward) { - rtMin = rtPos + 10000LL; // at least one millisecond later - rtMax = GetDur(); - rtTarget = rtMin; - } else { - rtMin = 0; - if (GetMediaState() == State_Paused) { - rtMax = rtPos - 10000LL; - } else { - rtMax = rtPos - 5000000LL; - } - rtTarget = rtMax; - } - - if (GetKeyFrame(rtTarget, rtMin, rtMax, false, rtKeyframe)) { - SeekTo(rtKeyframe); - } - } -} - -void CMainFrame::OnUpdatePlaySeek(CCmdUI* pCmdUI) -{ - bool fEnable = false; - - if (GetLoadState() == MLS::LOADED) { - fEnable = true; - if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { - fEnable = false; - } else if (IsPlaybackCaptureMode()) { - fEnable = false; - } - } - - pCmdUI->Enable(fEnable); -} - -void CMainFrame::SetPlayingRate(double rate) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - HRESULT hr = E_FAIL; - if (GetPlaybackMode() == PM_FILE) { - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - if (m_pMS) { - hr = m_pMS->SetRate(rate); - } - } else if (GetPlaybackMode() == PM_DVD) { - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - if (rate > 0) { - hr = m_pDVDC->PlayForwards(rate, DVD_CMD_FLAG_Block, nullptr); - } else { - hr = m_pDVDC->PlayBackwards(-rate, DVD_CMD_FLAG_Block, nullptr); - } - } - if (SUCCEEDED(hr)) { - m_dSpeedRate = rate; - CString strODSMessage; - strODSMessage.Format(IDS_OSD_SPEED, rate); - m_OSD.DisplayMessage(OSD_TOPRIGHT, strODSMessage); - } -} - -void CMainFrame::OnPlayChangeRate(UINT nID) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - if (GetPlaybackMode() == PM_FILE) { - const CAppSettings& s = AfxGetAppSettings(); - double dSpeedStep = s.nSpeedStep / 100.0; - - if (nID == ID_PLAY_INCRATE) { - if (s.nSpeedStep > 0) { - if (m_dSpeedRate <= 0.05) { - double newrate = 1.0 - (95 / s.nSpeedStep) * dSpeedStep; - SetPlayingRate(newrate > 0.05 ? newrate : newrate + dSpeedStep); - } else { - SetPlayingRate(std::max(0.05, m_dSpeedRate + dSpeedStep)); - } - } else { - SetPlayingRate(std::max(0.0625, m_dSpeedRate * 2.0)); - } - } else if (nID == ID_PLAY_DECRATE) { - if (s.nSpeedStep > 0) { - SetPlayingRate(std::max(0.05, m_dSpeedRate - dSpeedStep)); - } else { - SetPlayingRate(std::max(0.0625, m_dSpeedRate / 2.0)); - } - } else if (nID > ID_PLAY_PLAYBACKRATE_START && nID < ID_PLAY_PLAYBACKRATE_END) { - if (filePlaybackRates.count(nID) != 0) { - SetPlayingRate(filePlaybackRates[nID]); - } else if (nID == ID_PLAY_PLAYBACKRATE_FPS24 || nID == ID_PLAY_PLAYBACKRATE_FPS25) { - if (m_pCAP) { - float target = (nID == ID_PLAY_PLAYBACKRATE_FPS24 ? 24.0f : 25.0f); - SetPlayingRate(target / m_pCAP->GetFPS()); - } - } - } - } else if (GetPlaybackMode() == PM_DVD) { - if (nID == ID_PLAY_INCRATE) { - if (m_dSpeedRate > 0) { - SetPlayingRate(m_dSpeedRate * 2.0); - } else if (m_dSpeedRate >= -1) { - SetPlayingRate(1); - } else { - SetPlayingRate(m_dSpeedRate / 2.0); - } - } else if (nID == ID_PLAY_DECRATE) { - if (m_dSpeedRate < 0) { - SetPlayingRate(m_dSpeedRate * 2.0); - } else if (m_dSpeedRate <= 1) { - SetPlayingRate(-1); - } else { - SetPlayingRate(m_dSpeedRate / 2.0); - } - } else if (nID > ID_PLAY_PLAYBACKRATE_START && nID < ID_PLAY_PLAYBACKRATE_END) { - if (dvdPlaybackRates.count(nID) != 0) { - SetPlayingRate(dvdPlaybackRates[nID]); - } - } - } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - - long lChannelMin = 0, lChannelMax = 0; - m_pAMTuner->ChannelMinMax(&lChannelMin, &lChannelMax); - long lChannel = 0, lVivSub = 0, lAudSub = 0; - m_pAMTuner->get_Channel(&lChannel, &lVivSub, &lAudSub); - - long lFreqOrg = 0, lFreqNew = -1; - m_pAMTuner->get_VideoFrequency(&lFreqOrg); - - //long lSignalStrength; - do { - if (nID == ID_PLAY_DECRATE) { - lChannel--; - } else if (nID == ID_PLAY_INCRATE) { - lChannel++; - } - - //if (lChannel < lChannelMin) lChannel = lChannelMax; - //if (lChannel > lChannelMax) lChannel = lChannelMin; - - if (lChannel < lChannelMin || lChannel > lChannelMax) { - break; - } - - if (FAILED(m_pAMTuner->put_Channel(lChannel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT))) { - break; - } - - long flFoundSignal; - m_pAMTuner->AutoTune(lChannel, &flFoundSignal); - - m_pAMTuner->get_VideoFrequency(&lFreqNew); - } while (FALSE); - /*SUCCEEDED(m_pAMTuner->SignalPresent(&lSignalStrength)) - && (lSignalStrength != AMTUNER_SIGNALPRESENT || lFreqNew == lFreqOrg));*/ - } else { - ASSERT(FALSE); - } -} - -void CMainFrame::OnUpdatePlayChangeRate(CCmdUI* pCmdUI) -{ - bool fEnable = false; - - if (GetLoadState() == MLS::LOADED) { - if (pCmdUI->m_nID > ID_PLAY_PLAYBACKRATE_START && pCmdUI->m_nID < ID_PLAY_PLAYBACKRATE_END && pCmdUI->m_pMenu) { - fEnable = false; - if (GetPlaybackMode() == PM_FILE) { - if (filePlaybackRates.count(pCmdUI->m_nID) != 0) { - fEnable = true; - if (filePlaybackRates[pCmdUI->m_nID] == m_dSpeedRate) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); - } - } else if (pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS24 || pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS25) { - fEnable = true; - if (m_pCAP) { - float target = (pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS24 ? 24.0f : 25.0f); - if (target / m_pCAP->GetFPS() == m_dSpeedRate) { - bool found = false; - for (auto const& [key, rate] : filePlaybackRates) { //make sure it wasn't a standard rate already - if (rate == m_dSpeedRate) { - found = true; - } - } - if (!found) { //must have used fps, as it didn't match a standard rate - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); - } - } - } - } - } else if (GetPlaybackMode() == PM_DVD) { - if (dvdPlaybackRates.count(pCmdUI->m_nID) != 0) { - fEnable = true; - if (dvdPlaybackRates[pCmdUI->m_nID] == m_dSpeedRate) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); - } - } - } - } else { - bool fInc = pCmdUI->m_nID == ID_PLAY_INCRATE; - - fEnable = true; - if (fInc && m_dSpeedRate >= 128.0) { - fEnable = false; - } else if (!fInc && GetPlaybackMode() == PM_FILE && m_dSpeedRate <= 0.05) { - fEnable = false; - } else if (!fInc && GetPlaybackMode() == PM_DVD && m_dSpeedRate <= -128.0) { - fEnable = false; - } else if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { - fEnable = false; - } else if (m_fShockwaveGraph) { - fEnable = false; - } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE && (!m_wndCaptureBar.m_capdlg.IsTunerActive() || m_fCapturing)) { - fEnable = false; - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - fEnable = false; - } else if (m_fLiveWM) { - fEnable = false; - } - } - } - - pCmdUI->Enable(fEnable); -} - -void CMainFrame::OnPlayResetRate() -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - HRESULT hr = E_FAIL; - - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - - if (GetPlaybackMode() == PM_FILE) { - hr = m_pMS->SetRate(1.0); - } else if (GetPlaybackMode() == PM_DVD) { - hr = m_pDVDC->PlayForwards(1.0, DVD_CMD_FLAG_Block, nullptr); - } - - if (SUCCEEDED(hr)) { - m_dSpeedRate = 1.0; - - CString strODSMessage; - strODSMessage.Format(IDS_OSD_SPEED, m_dSpeedRate); - m_OSD.DisplayMessage(OSD_TOPRIGHT, strODSMessage); - } -} - -void CMainFrame::OnUpdatePlayResetRate(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED); -} - -void CMainFrame::SetAudioDelay(REFERENCE_TIME rtShift) -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - pASF->SetAudioTimeShift(rtShift); - - if (GetLoadState() == MLS::LOADED) { - CString str; - str.Format(IDS_MAINFRM_70, rtShift / 10000); - SendStatusMessage(str, 3000); - m_OSD.DisplayMessage(OSD_TOPLEFT, str); - } - } -} - -void CMainFrame::SetSubtitleDelay(int delay_ms, bool relative) -{ - if (!m_pCAP && !m_pDVS) { - if (GetLoadState() == MLS::LOADED) { - SendStatusMessage(L"Delay is not supported by current subtitle renderer", 3000); - } - return; - } - - if (m_pDVS) { - int currentDelay, speedMul, speedDiv; - if (FAILED(m_pDVS->get_SubtitleTiming(¤tDelay, &speedMul, &speedDiv))) { - return; - } - if (relative) { - delay_ms += currentDelay; - } - - VERIFY(SUCCEEDED(m_pDVS->put_SubtitleTiming(delay_ms, speedMul, speedDiv))); - } - else { - ASSERT(m_pCAP != nullptr); - if (m_pSubStreams.IsEmpty()) { - SendStatusMessage(StrRes(IDS_SUBTITLES_ERROR), 3000); - return; - } - if (relative) { - delay_ms += m_pCAP->GetSubtitleDelay(); - } - - m_pCAP->SetSubtitleDelay(delay_ms); - } - - CString strSubDelay; - strSubDelay.Format(IDS_MAINFRM_139, delay_ms); - SendStatusMessage(strSubDelay, 3000); - m_OSD.DisplayMessage(OSD_TOPLEFT, strSubDelay); -} - -void CMainFrame::OnPlayChangeAudDelay(UINT nID) -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - REFERENCE_TIME rtShift = pASF->GetAudioTimeShift(); - rtShift += - nID == ID_PLAY_INCAUDDELAY ? 100000 : - nID == ID_PLAY_DECAUDDELAY ? -100000 : - 0; - - SetAudioDelay(rtShift); - } -} - -void CMainFrame::OnUpdatePlayChangeAudDelay(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(!!m_pGB /*&& !!FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)*/); -} - -void CMainFrame::OnPlayFiltersCopyToClipboard() -{ - // Don't translate that output since it's mostly for debugging purpose - CString filtersList = _T("Filters currently loaded:\r\n"); - // Skip the first two entries since they are the "Copy to clipboard" menu entry and a separator - for (int i = 2, count = m_filtersMenu.GetMenuItemCount(); i < count; i++) { - CString filterName; - m_filtersMenu.GetMenuString(i, filterName, MF_BYPOSITION); - filtersList.AppendFormat(_T(" - %s\r\n"), filterName.GetString()); - } - - CClipboard clipboard(this); - VERIFY(clipboard.SetText(filtersList)); -} - -bool CMainFrame::FilterSettingsByClassID(CLSID clsid, CWnd* parent) -{ - for (int a = 0; a < m_pparray.GetCount(); a++) { - CComQIPtr pBF2 = m_pparray[a]; - if (pBF2) { - CLSID tclsid; - pBF2->GetClassID(&tclsid); - if (tclsid == clsid) { - FilterSettings(m_pparray[a], parent); - return true; - } - } - } - return false; -} - -void CMainFrame::FilterSettings(CComPtr pUnk, CWnd* parent) { - CComPropertySheet ps(IDS_PROPSHEET_PROPERTIES); - - CComQIPtr pBF = pUnk; - CLSID clsid = GetCLSID(pBF); - CFGFilterLAV::LAVFILTER_TYPE LAVFilterType = CFGFilterLAV::INVALID; - bool bIsInternalLAV = CFGFilterLAV::IsInternalInstance(pBF, &LAVFilterType); - - if (CComQIPtr pSPP = pUnk) { - ULONG uIgnoredPage = ULONG(-1); - // If we are dealing with an internal filter, we want to ignore the "Formats" page. - if (bIsInternalLAV) { - uIgnoredPage = (LAVFilterType != CFGFilterLAV::AUDIO_DECODER) ? 1 : 2; - } - bool bIsInternalFilter = bIsInternalLAV || clsid == CLSID_MPCVR; - ps.AddPages(pSPP, bIsInternalFilter, uIgnoredPage); - } - - HRESULT hr; - CComPtr pPP = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr); - ps.AddPage(pPP, pBF); - - if (ps.GetPageCount() > 0) { - CMPCThemeComPropertyPage::SetDialogType(clsid); - ps.DoModal(); - OpenSetupStatusBar(); - - if (bIsInternalLAV) { - if (CComQIPtr pLAVFSettings = pBF) { - CFGFilterLAVSplitterBase::Settings settings; - if (settings.GetSettings(pLAVFSettings)) { // Get current settings from LAVSplitter - settings.SaveSettings(); // Save them to the registry/ini - } - } else if (CComQIPtr pLAVVideoSettings = pBF) { - CFGFilterLAVVideo::Settings settings; - if (settings.GetSettings(pLAVVideoSettings)) { // Get current settings from LAVVideo - settings.SaveSettings(); // Save them to the registry/ini - } - } else if (CComQIPtr pLAVAudioSettings = pBF) { - CFGFilterLAVAudio::Settings settings; - if (settings.GetSettings(pLAVAudioSettings)) { // Get current settings from LAVAudio - settings.SaveSettings(); // Save them to the registry/ini - } - } - } - } -} - -void CMainFrame::OnPlayFilters(UINT nID) -{ - //ShowPPage(m_spparray[nID - ID_FILTERS_SUBITEM_START], m_hWnd); - - CComPtr pUnk = m_pparray[nID - ID_FILTERS_SUBITEM_START]; - - FilterSettings(pUnk, GetModalParent()); -} - -void CMainFrame::OnUpdatePlayFilters(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(!m_fCapturing); -} - -void CMainFrame::OnPlayShadersSelect() -{ - ShowOptions(IDD_PPAGESHADERS); -} - -void CMainFrame::OnPlayShadersPresetNext() -{ - auto& s = AfxGetAppSettings(); - if (s.m_Shaders.NextPreset()) { - CString name; - if (s.m_Shaders.GetCurrentPresetName(name)) { - CString msg; - msg.Format(IDS_OSD_SHADERS_PRESET, name.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, msg); - } - } -} - -void CMainFrame::OnPlayShadersPresetPrev() -{ - auto& s = AfxGetAppSettings(); - if (s.m_Shaders.PrevPreset()) { - CString name; - if (s.m_Shaders.GetCurrentPresetName(name)) { - CString msg; - msg.Format(IDS_OSD_SHADERS_PRESET, name.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, msg); - } - } -} - -void CMainFrame::OnPlayShadersPresets(UINT nID) -{ - ASSERT((nID >= ID_SHADERS_PRESETS_START) && (nID <= ID_SHADERS_PRESETS_END)); - auto& s = AfxGetAppSettings(); - int num = (int)nID - ID_SHADERS_PRESETS_START; - auto presets = s.m_Shaders.GetPresets(); - ASSERT(num < (int)presets.size()); - for (const auto& pair : presets) { - if (num-- == 0) { - s.m_Shaders.SetCurrentPreset(pair.first); - break; - } - } -} - -int CMainFrame::UpdateSelectedAudioStreamInfo(int index, AM_MEDIA_TYPE* pmt, LCID lcid) { - int nChannels = 0; - if (index >= 0) { - m_loadedAudioTrackIndex = index; - AfxGetAppSettings().MRU.UpdateCurrentAudioTrack(index); - } - if (pmt) { - m_statusbarAudioFormat = GetShortAudioNameFromMediaType(pmt); - AppendWithDelimiter(m_statusbarAudioFormat, GetChannelStrFromMediaType(pmt, nChannels)); - } else { - m_statusbarAudioFormat.Empty(); - } - if (lcid > 0) { - GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentAudioLang); - } else { - currentAudioLang.Empty(); - } - return nChannels; -} - -int CMainFrame::GetSelectedSubtitleTrackIndex() { - int subIdx = 0; - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - CComQIPtr pSSF = subInput.pSourceFilter; - if (pSSF) { - DWORD cStreams; - if (SUCCEEDED(pSSF->Count(&cStreams))) { - for (long j = 0; j < (long)cStreams; j++) { - DWORD dwFlags, dwGroup; - if (SUCCEEDED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 2) { - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - return subIdx; - } - subIdx++; - } - } - } - } - } else { - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - return subIdx; - } else { - subIdx += subInput.pSubStream->GetStreamCount(); - } - } - } - return 0; -} - -bool CMainFrame::IsValidSubtitleStream(int i) { - if (GetSubtitleInput(i) != nullptr) { - return true; - } - - return false; -} - -// Called from GraphThread -void CMainFrame::OnPlayAudio(UINT nID) -{ - int i = (int)nID - ID_AUDIO_SUBITEM_START; - - DWORD cStreams = 0; - - if (GetPlaybackMode() == PM_DVD) { - m_pDVDC->SelectAudioStream(i, DVD_CMD_FLAG_Block, nullptr); - LCID lcid = 0; - if (SUCCEEDED(m_pDVDI->GetAudioLanguage(i, &lcid)) && lcid != 0) { - GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentAudioLang); - } else { - currentAudioLang.Empty(); - } - } else if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { - if (i == 0) { - ShowOptions(CPPageAudioSwitcher::IDD); - } else { - LONG sidx = i - 1; - if (m_iReloadAudioIdx >= 0) { - if (m_iReloadAudioIdx < cStreams) { - sidx = m_iReloadAudioIdx; - } - m_iReloadAudioIdx = -1; - } - if (sidx >= cStreams) { //invalid stream? - return; - } - if (SUCCEEDED(m_pAudioSwitcherSS->Enable(sidx, AMSTREAMSELECTENABLE_ENABLE))) { - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(m_pAudioSwitcherSS->Info(sidx, &pmt, nullptr, &lcid, nullptr, nullptr, nullptr, nullptr))) { - UpdateSelectedAudioStreamInfo(sidx, pmt, lcid); - DeleteMediaType(pmt); - } else { - UpdateSelectedAudioStreamInfo(sidx, nullptr, -1); - } - } - } - } else if (GetPlaybackMode() == PM_FILE) { - OnNavStreamSelectSubMenu(i, 1); - AfxGetAppSettings().MRU.UpdateCurrentAudioTrack(i); - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - if (CBDAChannel* pChannel = m_pDVBState->pChannel) { - OnNavStreamSelectSubMenu(i, 1); - pChannel->SetDefaultAudio(i); - } - } -} - -void CMainFrame::OnSubtitlesDefaultStyle() -{ - CAppSettings& s = AfxGetAppSettings(); - if (!m_pSubStreams.IsEmpty()) { - s.bSubtitleOverrideDefaultStyle = !s.bSubtitleOverrideDefaultStyle; - UpdateSubtitleRenderingParameters(); - RepaintVideo(); - } -} - -void CMainFrame::OnPlaySubtitles(UINT nID) -{ - CAppSettings& s = AfxGetAppSettings(); - int i = (int)nID - ID_SUBTITLES_SUBITEM_START; - - if (GetPlaybackMode() == PM_DVD) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) - && ulStreamsAvailable) { - if (i == 0) { - m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); - } else if (i <= int(ulStreamsAvailable)) { - m_pDVDC->SelectSubpictureStream(i - 1, DVD_CMD_FLAG_Block, nullptr); - m_pDVDC->SetSubpictureState(TRUE, DVD_CMD_FLAG_Block, nullptr); - } - i -= ulStreamsAvailable + 1; - } - } - - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - if (CBDAChannel* pChannel = m_pDVBState->pChannel) { - OnNavStreamSelectSubMenu(i, 2); - pChannel->SetDefaultSubtitle(i); - SetSubtitle(i); - } - } else if (!m_pSubStreams.IsEmpty()) { - // Currently the subtitles menu contains 6 items apart from the actual subtitles list when the ISR is used - i -= 6; - - if (i == -6) { - // options - ShowOptions(CPPageSubtitles::IDD); - } else if (i == -5) { - // styles - int j = 0; - SubtitleInput* pSubInput = GetSubtitleInput(j, true); - CLSID clsid; - - if (pSubInput && SUCCEEDED(pSubInput->pSubStream->GetClassID(&clsid))) { - if (clsid == __uuidof(CRenderedTextSubtitle)) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; - - CAutoPtrArray pages; - CAtlArray styles; - - POSITION pos = pRTS->m_styles.GetStartPosition(); - for (int k = 0; pos; k++) { - CString styleName; - STSStyle* style; - pRTS->m_styles.GetNextAssoc(pos, styleName, style); - - CAutoPtr page(DEBUG_NEW CPPageSubStyle(/*isStyleDialog = */ true)); - if (style->hasAnsiStyleName) { - styleName = ToUnicode(styleName, pRTS->GetCharSet(style->charSet)); - } - page->InitStyle(styleName, *style); - pages.Add(page); - styles.Add(style); - } - - CMPCThemePropertySheet dlg(IDS_SUBTITLES_STYLES_CAPTION, GetModalParent()); - for (size_t l = 0; l < pages.GetCount(); l++) { - dlg.AddPage(pages[l]); - } - - if (dlg.DoModal() == IDOK) { - { - CAutoLock cAutoLock(&m_csSubLock); - bool defaultStyleChanged = false, otherStyleChanged = false; - - for (size_t l = 0; l < pages.GetCount(); l++) { - STSStyle tmpStyle = *styles[l]; - pages[l]->GetStyle(*styles[l]); - if (pages[l]->GetStyleName() == L"Default") { - if (*styles[l] != s.subtitlesDefStyle) { - pRTS->m_bUsingPlayerDefaultStyle = false; - pRTS->SetDefaultStyle(*styles[l]); - defaultStyleChanged = true; - } - } else if (tmpStyle != *styles[l]) { - otherStyleChanged = true; - } - } - if (otherStyleChanged || defaultStyleChanged) { - if (!defaultStyleChanged) { //it will already have triggered SetStyleChanged() internally - pRTS->SetStyleChanged(); - } - pRTS->Deinit(); - InvalidateSubtitle(); - RepaintVideo(); - m_wndSubresyncBar.ReloadSubtitle(); - } - } - } - } - } - } else if (i == -4) { - // reload - ReloadSubtitle(); - } else if (i == -3) { - // hide - ToggleSubtitleOnOff(); - } else if (i == -2) { - // override default style - s.bSubtitleOverrideDefaultStyle = !s.bSubtitleOverrideDefaultStyle; - UpdateSubtitleRenderingParameters(); - RepaintVideo(); - } else if (i == -1) { - // override all styles - s.bSubtitleOverrideAllStyles = !s.bSubtitleOverrideAllStyles; - UpdateSubtitleRenderingParameters(); - RepaintVideo(); - } else if (i >= 0) { - // this is an actual item from the subtitles list - s.fEnableSubtitles = true; - SetSubtitle(i); - } - } else if (GetPlaybackMode() == PM_FILE) { - OnNavStreamSelectSubMenu(i, 2); - } -} - -void CMainFrame::OnPlayVideoStreams(UINT nID) -{ - nID -= ID_VIDEO_STREAMS_SUBITEM_START; - - if (GetPlaybackMode() == PM_FILE) { - OnNavStreamSelectSubMenu(nID, 0); - } else if (GetPlaybackMode() == PM_DVD) { - m_pDVDC->SelectAngle(nID + 1, DVD_CMD_FLAG_Block, nullptr); - - CString osdMessage; - osdMessage.Format(IDS_AG_ANGLE, nID + 1); - m_OSD.DisplayMessage(OSD_TOPLEFT, osdMessage); - } -} - -void CMainFrame::OnPlayFiltersStreams(UINT nID) -{ - nID -= ID_FILTERSTREAMS_SUBITEM_START; - CComPtr pAMSS = m_ssarray[nID]; - UINT i = nID; - - while (i > 0 && pAMSS == m_ssarray[i - 1]) { - i--; - } - - if (FAILED(pAMSS->Enable(nID - i, AMSTREAMSELECTENABLE_ENABLE))) { - MessageBeep(UINT_MAX); - } - - OpenSetupStatusBar(); -} - -void CMainFrame::OnPlayVolume(UINT nID) -{ - if (GetLoadState() == MLS::LOADED) { - CString strVolume; - m_pBA->put_Volume(m_wndToolBar.Volume); - - //strVolume.Format (L"Vol : %d dB", m_wndToolBar.Volume / 100); - if (m_wndToolBar.Volume == -10000) { - strVolume.Format(IDS_VOLUME_OSD, 0); - } else { - strVolume.Format(IDS_VOLUME_OSD, m_wndToolBar.m_volctrl.GetPos()); - } - m_OSD.DisplayMessage(OSD_TOPLEFT, strVolume); - //SendStatusMessage(strVolume, 3000); // Now the volume is displayed in three places at once. - } - - m_Lcd.SetVolume((m_wndToolBar.Volume > -10000 ? m_wndToolBar.m_volctrl.GetPos() : 1)); -} - -void CMainFrame::OnPlayVolumeBoost(UINT nID) -{ - CAppSettings& s = AfxGetAppSettings(); - - switch (nID) { - case ID_VOLUME_BOOST_INC: - s.nAudioBoost += s.nVolumeStep; - if (s.nAudioBoost > 300) { - s.nAudioBoost = 300; - } - break; - case ID_VOLUME_BOOST_DEC: - if (s.nAudioBoost > s.nVolumeStep) { - s.nAudioBoost -= s.nVolumeStep; - } else { - s.nAudioBoost = 0; - } - break; - case ID_VOLUME_BOOST_MIN: - s.nAudioBoost = 0; - break; - case ID_VOLUME_BOOST_MAX: - s.nAudioBoost = 300; - break; - } - - SetVolumeBoost(s.nAudioBoost); -} - -void CMainFrame::SetVolumeBoost(UINT nAudioBoost) -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - bool fNormalize, fNormalizeRecover; - UINT nMaxNormFactor, nBoost; - pASF->GetNormalizeBoost2(fNormalize, nMaxNormFactor, fNormalizeRecover, nBoost); - - CString strBoost; - strBoost.Format(IDS_BOOST_OSD, nAudioBoost); - pASF->SetNormalizeBoost2(fNormalize, nMaxNormFactor, fNormalizeRecover, nAudioBoost); - m_OSD.DisplayMessage(OSD_TOPLEFT, strBoost); - } -} - -void CMainFrame::OnUpdatePlayVolumeBoost(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(); -} - -void CMainFrame::OnCustomChannelMapping() -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - CAppSettings& s = AfxGetAppSettings(); - s.fCustomChannelMapping = !s.fCustomChannelMapping; - pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(s.fCustomChannelMapping ? IDS_OSD_CUSTOM_CH_MAPPING_ON : IDS_OSD_CUSTOM_CH_MAPPING_OFF)); - } -} - -void CMainFrame::OnUpdateCustomChannelMapping(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(s.fEnableAudioSwitcher); -} - -void CMainFrame::OnNormalizeRegainVolume(UINT nID) -{ - if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { - CAppSettings& s = AfxGetAppSettings(); - WORD osdMessage = 0; - - switch (nID) { - case ID_NORMALIZE: - s.fAudioNormalize = !s.fAudioNormalize; - osdMessage = s.fAudioNormalize ? IDS_OSD_NORMALIZE_ON : IDS_OSD_NORMALIZE_OFF; - break; - case ID_REGAIN_VOLUME: - s.fAudioNormalizeRecover = !s.fAudioNormalizeRecover; - osdMessage = s.fAudioNormalizeRecover ? IDS_OSD_REGAIN_VOLUME_ON : IDS_OSD_REGAIN_VOLUME_OFF; - break; - } - - pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMessage)); - } -} - -void CMainFrame::OnUpdateNormalizeRegainVolume(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable(s.fEnableAudioSwitcher); -} - -void CMainFrame::OnPlayColor(UINT nID) -{ - if (m_pVMRMC || m_pMFVP) { - CAppSettings& s = AfxGetAppSettings(); - //ColorRanges* crs = AfxGetMyApp()->ColorControls; - int& brightness = s.iBrightness; - int& contrast = s.iContrast; - int& hue = s.iHue; - int& saturation = s.iSaturation; - CString tmp, str; - switch (nID) { - case ID_COLOR_BRIGHTNESS_INC: - brightness += 2; - [[fallthrough]]; - case ID_COLOR_BRIGHTNESS_DEC: - brightness -= 1; - SetColorControl(ProcAmp_Brightness, brightness, contrast, hue, saturation); - tmp.Format(brightness ? _T("%+d") : _T("%d"), brightness); - str.Format(IDS_OSD_BRIGHTNESS, tmp.GetString()); - break; - case ID_COLOR_CONTRAST_INC: - contrast += 2; - [[fallthrough]]; - case ID_COLOR_CONTRAST_DEC: - contrast -= 1; - SetColorControl(ProcAmp_Contrast, brightness, contrast, hue, saturation); - tmp.Format(contrast ? _T("%+d") : _T("%d"), contrast); - str.Format(IDS_OSD_CONTRAST, tmp.GetString()); - break; - case ID_COLOR_HUE_INC: - hue += 2; - [[fallthrough]]; - case ID_COLOR_HUE_DEC: - hue -= 1; - SetColorControl(ProcAmp_Hue, brightness, contrast, hue, saturation); - tmp.Format(hue ? _T("%+d") : _T("%d"), hue); - str.Format(IDS_OSD_HUE, tmp.GetString()); - break; - case ID_COLOR_SATURATION_INC: - saturation += 2; - [[fallthrough]]; - case ID_COLOR_SATURATION_DEC: - saturation -= 1; - SetColorControl(ProcAmp_Saturation, brightness, contrast, hue, saturation); - tmp.Format(saturation ? _T("%+d") : _T("%d"), saturation); - str.Format(IDS_OSD_SATURATION, tmp.GetString()); - break; - case ID_COLOR_RESET: - brightness = AfxGetMyApp()->GetColorControl(ProcAmp_Brightness)->DefaultValue; - contrast = AfxGetMyApp()->GetColorControl(ProcAmp_Contrast)->DefaultValue; - hue = AfxGetMyApp()->GetColorControl(ProcAmp_Hue)->DefaultValue; - saturation = AfxGetMyApp()->GetColorControl(ProcAmp_Saturation)->DefaultValue; - SetColorControl(ProcAmp_All, brightness, contrast, hue, saturation); - str.LoadString(IDS_OSD_RESET_COLOR); - break; - } - m_OSD.DisplayMessage(OSD_TOPLEFT, str); - } else { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_NO_COLORCONTROL)); - } -} - -void CMainFrame::OnAfterplayback(UINT nID) -{ - CAppSettings& s = AfxGetAppSettings(); - WORD osdMsg = 0; - bool bDisable = false; - - auto toggleOption = [&](UINT64 nID) { - bDisable = !!(s.nCLSwitches & nID); - s.nCLSwitches &= ~CLSW_AFTERPLAYBACK_MASK | nID; - s.nCLSwitches ^= nID; - }; - - switch (nID) { - case ID_AFTERPLAYBACK_EXIT: - toggleOption(CLSW_CLOSE); - osdMsg = IDS_AFTERPLAYBACK_EXIT; - break; - case ID_AFTERPLAYBACK_STANDBY: - toggleOption(CLSW_STANDBY); - osdMsg = IDS_AFTERPLAYBACK_STANDBY; - break; - case ID_AFTERPLAYBACK_HIBERNATE: - toggleOption(CLSW_HIBERNATE); - osdMsg = IDS_AFTERPLAYBACK_HIBERNATE; - break; - case ID_AFTERPLAYBACK_SHUTDOWN: - toggleOption(CLSW_SHUTDOWN); - osdMsg = IDS_AFTERPLAYBACK_SHUTDOWN; - break; - case ID_AFTERPLAYBACK_LOGOFF: - toggleOption(CLSW_LOGOFF); - osdMsg = IDS_AFTERPLAYBACK_LOGOFF; - break; - case ID_AFTERPLAYBACK_LOCK: - toggleOption(CLSW_LOCK); - osdMsg = IDS_AFTERPLAYBACK_LOCK; - break; - case ID_AFTERPLAYBACK_MONITOROFF: - toggleOption(CLSW_MONITOROFF); - osdMsg = IDS_AFTERPLAYBACK_MONITOROFF; - break; - case ID_AFTERPLAYBACK_PLAYNEXT: - toggleOption(CLSW_PLAYNEXT); - osdMsg = IDS_AFTERPLAYBACK_PLAYNEXT; - break; - case ID_AFTERPLAYBACK_DONOTHING: - toggleOption(CLSW_DONOTHING); - osdMsg = IDS_AFTERPLAYBACK_DONOTHING; - break; - } - if (bDisable) { - switch (s.eAfterPlayback) { - case CAppSettings::AfterPlayback::PLAY_NEXT: - osdMsg = IDS_AFTERPLAYBACK_PLAYNEXT; - break; - case CAppSettings::AfterPlayback::REWIND: - osdMsg = IDS_AFTERPLAYBACK_REWIND; - break; - case CAppSettings::AfterPlayback::MONITOROFF: - osdMsg = IDS_AFTERPLAYBACK_MONITOROFF; - break; - case CAppSettings::AfterPlayback::CLOSE: - osdMsg = IDS_AFTERPLAYBACK_CLOSE; - break; - case CAppSettings::AfterPlayback::EXIT: - osdMsg = IDS_AFTERPLAYBACK_EXIT; - break; - default: - ASSERT(FALSE); - [[fallthrough]]; - case CAppSettings::AfterPlayback::DO_NOTHING: - osdMsg = IDS_AFTERPLAYBACK_DONOTHING; - break; - } - } - - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMsg)); -} - -void CMainFrame::OnUpdateAfterplayback(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - bool bChecked; - bool bRadio = false; - - switch (pCmdUI->m_nID) { - case ID_AFTERPLAYBACK_EXIT: - bChecked = !!(s.nCLSwitches & CLSW_CLOSE); - bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::EXIT; - break; - case ID_AFTERPLAYBACK_STANDBY: - bChecked = !!(s.nCLSwitches & CLSW_STANDBY); - break; - case ID_AFTERPLAYBACK_HIBERNATE: - bChecked = !!(s.nCLSwitches & CLSW_HIBERNATE); - break; - case ID_AFTERPLAYBACK_SHUTDOWN: - bChecked = !!(s.nCLSwitches & CLSW_SHUTDOWN); - break; - case ID_AFTERPLAYBACK_LOGOFF: - bChecked = !!(s.nCLSwitches & CLSW_LOGOFF); - break; - case ID_AFTERPLAYBACK_LOCK: - bChecked = !!(s.nCLSwitches & CLSW_LOCK); - break; - case ID_AFTERPLAYBACK_MONITOROFF: - bChecked = !!(s.nCLSwitches & CLSW_MONITOROFF); - bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::MONITOROFF; - break; - case ID_AFTERPLAYBACK_PLAYNEXT: - bChecked = !!(s.nCLSwitches & CLSW_PLAYNEXT); - bRadio = (s.eAfterPlayback == CAppSettings::AfterPlayback::PLAY_NEXT) && (m_wndPlaylistBar.GetCount() < 2); - break; - case ID_AFTERPLAYBACK_DONOTHING: - bChecked = !!(s.nCLSwitches & CLSW_DONOTHING); - bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::DO_NOTHING; - break; - default: - ASSERT(FALSE); - return; - } - - if (IsMenu(*pCmdUI->m_pMenu)) { - MENUITEMINFO mii, cii; - ZeroMemory(&cii, sizeof(MENUITEMINFO)); - cii.cbSize = sizeof(cii); - cii.fMask = MIIM_FTYPE; - pCmdUI->m_pMenu->GetMenuItemInfo(pCmdUI->m_nID, &cii); - - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_FTYPE | MIIM_STATE; - mii.fType = (bRadio ? MFT_RADIOCHECK : 0) | (cii.fType & MFT_OWNERDRAW); //preserve owner draw flag - mii.fState = (bRadio ? MFS_DISABLED : 0) | (bChecked || bRadio ? MFS_CHECKED : 0); - VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pCmdUI->m_pMenu, pCmdUI->m_nID, &mii)); - } -} - -void CMainFrame::OnPlayRepeat(UINT nID) -{ - CAppSettings& s = AfxGetAppSettings(); - WORD osdMsg = 0; - - switch (nID) { - case ID_PLAY_REPEAT_ONEFILE: - s.eLoopMode = CAppSettings::LoopMode::FILE; - osdMsg = IDS_PLAYLOOPMODE_FILE; - break; - case ID_PLAY_REPEAT_WHOLEPLAYLIST: - s.eLoopMode = CAppSettings::LoopMode::PLAYLIST; - osdMsg = IDS_PLAYLOOPMODE_PLAYLIST; - break; - default: - ASSERT(FALSE); - return; - } - - m_nLoops = 0; - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMsg)); -} - -void CMainFrame::OnUpdatePlayRepeat(CCmdUI* pCmdUI) -{ - CAppSettings::LoopMode loopmode; - - switch (pCmdUI->m_nID) { - case ID_PLAY_REPEAT_ONEFILE: - loopmode = CAppSettings::LoopMode::FILE; - break; - case ID_PLAY_REPEAT_WHOLEPLAYLIST: - loopmode = CAppSettings::LoopMode::PLAYLIST; - break; - default: - ASSERT(FALSE); - return; - } - if (AfxGetAppSettings().eLoopMode == loopmode && pCmdUI->m_pMenu) { - pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, pCmdUI->m_nID, MF_BYCOMMAND); - } -} - -void CMainFrame::OnPlayRepeatForever() -{ - CAppSettings& s = AfxGetAppSettings(); - - s.fLoopForever = !s.fLoopForever; - - m_nLoops = 0; - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(s.fLoopForever ? IDS_PLAYLOOP_FOREVER_ON : IDS_PLAYLOOP_FOREVER_OFF)); -} - -void CMainFrame::OnUpdatePlayRepeatForever(CCmdUI* pCmdUI) -{ - pCmdUI->SetCheck(AfxGetAppSettings().fLoopForever); -} - -bool CMainFrame::SeekToFileChapter(int iChapter, bool bRelative /*= false*/) -{ - if (GetPlaybackMode() != PM_FILE || !m_pCB) { - return false; - } - - bool ret = false; - - if (DWORD nChapters = m_pCB->ChapGetCount()) { - REFERENCE_TIME rt; - - if (bRelative) { - if (m_pMS && SUCCEEDED(m_pMS->GetCurrentPosition(&rt))) { - if (iChapter < 0) { - // Add a small threshold to jump back at least that amount of time - // This is needed when rt is near start of current chapter - rt -= PREV_CHAP_THRESHOLD * 10000000; - iChapter = 0; - iChapter = m_pCB->ChapLookupPrevious(&rt, nullptr); - // seek to start if there is no previous chapter - if (iChapter == -1 && rt >= 0) { - REFERENCE_TIME rtStart, rtStop; - m_wndSeekBar.GetRange(rtStart, rtStop); - DoSeekTo(rtStart, false); - return true; - } - } else { - iChapter = m_pCB->ChapLookupNext(&rt, nullptr); - } - } else { - return false; - } - } - - CComBSTR name; - REFERENCE_TIME rtStart, rtStop; - m_wndSeekBar.GetRange(rtStart, rtStop); - if (iChapter >= 0 && DWORD(iChapter) < nChapters && SUCCEEDED(m_pCB->ChapGet(iChapter, &rt, &name)) && rt < rtStop) { - DoSeekTo(rt, false); - SendStatusMessage(ResStr(IDS_AG_CHAPTER2) + CString(name), 3000); - ret = true; - - REFERENCE_TIME rtDur; - if (m_pMS && SUCCEEDED(m_pMS->GetDuration(&rtDur))) { - const CAppSettings& s = AfxGetAppSettings(); - CString strOSD; - REFERENCE_TIME rtShow = rt; - if (s.fRemainingTime) { - strOSD.Append(_T("-")); - rtShow = rtDur - rt; - } - if (rtDur >= 36005000000LL) { // At least 1 hour (rounded) - strOSD.AppendFormat(_T("%s / %s "), ReftimeToString2(rtShow).GetString(), ReftimeToString2(rtDur).GetString()); - } else { - strOSD.AppendFormat(_T("%s / %s "), ReftimeToString3(rtShow).GetString(), ReftimeToString3(rtDur).GetString()); - } - strOSD.AppendFormat(_T("\"%s\" (%d/%u)"), static_cast(name), iChapter + 1, nChapters); - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - } - } - } - - return ret; -} - -bool CMainFrame::SeekToDVDChapter(int iChapter, bool bRelative /*= false*/) -{ - if (GetPlaybackMode() != PM_DVD) { - return false; - } - - ULONG ulNumOfVolumes, ulVolume; - DVD_DISC_SIDE Side; - ULONG ulNumOfTitles = 0; - CheckNoLogBool(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles)); - - DVD_PLAYBACK_LOCATION2 Location; - ULONG ulNumOfChapters = 0; - ULONG uTitle = 0, uChapter = 0; - if (bRelative) { - CheckNoLogBool(m_pDVDI->GetCurrentLocation(&Location)); - - CheckNoLogBool(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters)); - - uTitle = Location.TitleNum; - uChapter = Location.ChapterNum; - - if (iChapter < 0) { - ULONG tsec = (Location.TimeCode.bHours * 3600) - + (Location.TimeCode.bMinutes * 60) - + (Location.TimeCode.bSeconds); - ULONG diff = 0; - if (m_lChapterStartTime != 0xFFFFFFFF && tsec > m_lChapterStartTime) { - diff = tsec - m_lChapterStartTime; - } - // Go the previous chapter only if more than PREV_CHAP_THRESHOLD seconds - // have passed since the beginning of the current chapter else restart it - if (diff <= PREV_CHAP_THRESHOLD) { - // If we are at the first chapter of a volume that isn't the first - // one, we skip to the last chapter of the previous volume. - if (uChapter == 1 && uTitle > 1) { - uTitle--; - CheckNoLogBool(m_pDVDI->GetNumberOfChapters(uTitle, &uChapter)); - } else if (uChapter > 1) { - uChapter--; - } - } - } else { - // If we are at the last chapter of a volume that isn't the last - // one, we skip to the first chapter of the next volume. - if (uChapter == ulNumOfChapters && uTitle < ulNumOfTitles) { - uTitle++; - uChapter = 1; - } else if (uChapter < ulNumOfChapters) { - uChapter++; - } - } - } else if (iChapter > 0) { - uChapter = ULONG(iChapter); - if (uChapter <= ulNumOfTitles) { - uTitle = uChapter; - uChapter = 1; - } else { - CheckNoLogBool(m_pDVDI->GetCurrentLocation(&Location)); - uTitle = Location.TitleNum; - uChapter -= ulNumOfTitles; - } - } - - if (uTitle && uChapter - && SUCCEEDED(m_pDVDC->PlayChapterInTitle(uTitle, uChapter, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr))) { - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location)) - && SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters))) { - CString strTitle; - strTitle.Format(IDS_AG_TITLE2, Location.TitleNum, ulNumOfTitles); - __int64 start, stop; - m_wndSeekBar.GetRange(start, stop); - - CString strOSD; - if (stop > 0) { - const CAppSettings& s = AfxGetAppSettings(); - - DVD_HMSF_TIMECODE currentHMSF = s.fRemainingTime ? RT2HMS_r(stop - HMSF2RT(Location.TimeCode)) : Location.TimeCode; - DVD_HMSF_TIMECODE stopHMSF = RT2HMS_r(stop); - strOSD.Format(_T("%s%s/%s %s, %s%02u/%02lu"), - s.fRemainingTime ? _T("- ") : _T(""), DVDtimeToString(currentHMSF, stopHMSF.bHours > 0).GetString(), DVDtimeToString(stopHMSF).GetString(), - strTitle.GetString(), ResStr(IDS_AG_CHAPTER2).GetString(), Location.ChapterNum, ulNumOfChapters); - } else { - strOSD.Format(_T("%s, %s%02u/%02lu"), strTitle.GetString(), ResStr(IDS_AG_CHAPTER2).GetString(), Location.ChapterNum, ulNumOfChapters); - } - - m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); - } - - return true; - } - - return false; -} - -// navigate -void CMainFrame::OnNavigateSkip(UINT nID) -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (GetPlaybackMode() == PM_FILE || CanSkipFromClosedFile()) { - m_nLastSkipDirection = nID; - - if (!SeekToFileChapter((nID == ID_NAVIGATE_SKIPBACK) ? -1 : 1, true)) { - if (nID == ID_NAVIGATE_SKIPBACK) { - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACKFILE); - } else if (nID == ID_NAVIGATE_SKIPFORWARD) { - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARDFILE); - } - } - } else if (GetPlaybackMode() == PM_DVD) { - m_dSpeedRate = 1.0; - - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - - SeekToDVDChapter((nID == ID_NAVIGATE_SKIPBACK) ? -1 : 1, true); - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - int nCurrentChannel = s.nDVBLastChannel; - - if (nID == ID_NAVIGATE_SKIPBACK) { - if (SUCCEEDED(SetChannel(nCurrentChannel - 1))) { - if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_wndNavigationBar.m_navdlg.UpdatePos(nCurrentChannel - 1); - } - } - } else if (nID == ID_NAVIGATE_SKIPFORWARD) { - if (SUCCEEDED(SetChannel(nCurrentChannel + 1))) { - if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_wndNavigationBar.m_navdlg.UpdatePos(nCurrentChannel + 1); - } - } - } - } - } -} - -bool CMainFrame::CanSkipFromClosedFile() { - if (GetPlaybackMode() == PM_NONE && AfxGetAppSettings().fUseSearchInFolder) { - if (m_wndPlaylistBar.GetCount() == 1) { - CPlaylistItem pli; - return m_wndPlaylistBar.GetCur(pli, true) && !PathUtils::IsURL(pli.m_fns.GetHead()); - } else if (m_wndPlaylistBar.GetCount() == 0 && !lastOpenFile.IsEmpty()) { - return !PathUtils::IsURL(lastOpenFile); - } - } - return false; -} - -void CMainFrame::OnUpdateNavigateSkip(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - - pCmdUI->Enable( - (GetLoadState() == MLS::LOADED - && ((GetPlaybackMode() == PM_DVD - && m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu - && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu) - || (GetPlaybackMode() == PM_FILE && s.fUseSearchInFolder) - || (GetPlaybackMode() == PM_FILE && !s.fUseSearchInFolder && (m_wndPlaylistBar.GetCount() > 1 || m_pCB->ChapGetCount() > 1)) - || (GetPlaybackMode() == PM_DIGITAL_CAPTURE && !m_pDVBState->bSetChannelActive))) - || (GetLoadState() == MLS::CLOSED && CanSkipFromClosedFile()) //to support skipping from broken file - ); -} - -void CMainFrame::OnNavigateSkipFile(UINT nID) -{ - if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_ANALOG_CAPTURE || CanSkipFromClosedFile()) { - if (m_wndPlaylistBar.GetCount() == 1 || CanSkipFromClosedFile()) { - CAppSettings& s = AfxGetAppSettings(); - if (GetPlaybackMode() == PM_ANALOG_CAPTURE || !s.fUseSearchInFolder) { - SendMessage(WM_COMMAND, ID_PLAY_STOP); // do not remove this, unless you want a circular call with OnPlayPlay() - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } else { - if (nID == ID_NAVIGATE_SKIPBACKFILE) { - if (!SearchInDir(false, s.bLoopFolderOnPlayNextFile)) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_FIRST_IN_FOLDER)); - } - } else if (nID == ID_NAVIGATE_SKIPFORWARDFILE) { - if (!SearchInDir(true, s.bLoopFolderOnPlayNextFile)) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_LAST_IN_FOLDER)); - } - } - } - } else { - if (nID == ID_NAVIGATE_SKIPBACKFILE) { - m_wndPlaylistBar.SetPrev(); - } else if (nID == ID_NAVIGATE_SKIPFORWARDFILE) { - m_wndPlaylistBar.SetNext(); - } - - OpenCurPlaylistItem(); - } - } -} - -void CMainFrame::OnUpdateNavigateSkipFile(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - pCmdUI->Enable( - (GetLoadState() == MLS::LOADED - && ((GetPlaybackMode() == PM_FILE && (m_wndPlaylistBar.GetCount() > 1 || s.fUseSearchInFolder)) - || (GetPlaybackMode() == PM_ANALOG_CAPTURE && !m_fCapturing && m_wndPlaylistBar.GetCount() > 1))) - || (GetLoadState() == MLS::CLOSED && CanSkipFromClosedFile()) - ); -} - -void CMainFrame::OnNavigateGoto() -{ - if ((GetLoadState() != MLS::LOADED) || IsD3DFullScreenMode()) { - return; - } - - const REFTIME atpf = GetAvgTimePerFrame(); - - REFERENCE_TIME start, dur = -1; - m_wndSeekBar.GetRange(start, dur); - CGoToDlg dlg(m_wndSeekBar.GetPos(), dur, atpf > 0.0 ? (1.0 / atpf) : 0.0); - if (IDOK != dlg.DoModal() || dlg.m_time < 0) { - return; - } - - DoSeekTo(dlg.m_time); -} - -void CMainFrame::OnUpdateNavigateGoto(CCmdUI* pCmdUI) -{ - bool fEnable = false; - - if (GetLoadState() == MLS::LOADED) { - fEnable = true; - if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { - fEnable = false; - } else if (IsPlaybackCaptureMode()) { - fEnable = false; - } - } - - pCmdUI->Enable(fEnable); -} - -void CMainFrame::OnNavigateMenu(UINT nID) -{ - nID -= ID_NAVIGATE_TITLEMENU; - - if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_DVD) { - return; - } - - m_dSpeedRate = 1.0; - - if (GetMediaState() != State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - - m_pDVDC->ShowMenu((DVD_MENU_ID)(nID + 2), DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); -} - -void CMainFrame::OnUpdateNavigateMenu(CCmdUI* pCmdUI) -{ - UINT nID = pCmdUI->m_nID - ID_NAVIGATE_TITLEMENU; - ULONG ulUOPs; - - if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_DVD - || FAILED(m_pDVDI->GetCurrentUOPS(&ulUOPs))) { - pCmdUI->Enable(FALSE); - return; - } - - pCmdUI->Enable(!(ulUOPs & (UOP_FLAG_ShowMenu_Title << nID))); -} - -void CMainFrame::OnNavigateJumpTo(UINT nID) -{ - if (nID < ID_NAVIGATE_JUMPTO_SUBITEM_START) { - return; - } - - const CAppSettings& s = AfxGetAppSettings(); - - if (GetPlaybackMode() == PM_FILE) { - int id = nID - ID_NAVIGATE_JUMPTO_SUBITEM_START; - - if (id < (int)m_MPLSPlaylist.size() && m_MPLSPlaylist.size() > 1) { - int idx = 0; - for (auto &Item : m_MPLSPlaylist) { - if (idx == id) { - m_bIsBDPlay = true; - m_wndPlaylistBar.Empty(); - CAtlList sl; - sl.AddTail(CString(Item.m_strFileName)); - m_wndPlaylistBar.Append(sl, false); - OpenCurPlaylistItem(); - return; - } - idx++; - } - } - - if (m_MPLSPlaylist.size() > 1) { - id -= (int)m_MPLSPlaylist.size(); - } - - if (m_pCB->ChapGetCount() > 1) { - if (SeekToFileChapter(id)) { - return; - } - - id -= m_pCB->ChapGetCount(); - } - - if (id >= 0 && id < m_wndPlaylistBar.GetCount() && m_wndPlaylistBar.GetSelIdx() != id) { - m_wndPlaylistBar.SetSelIdx(id); - OpenCurPlaylistItem(); - } - } else if (GetPlaybackMode() == PM_DVD) { - SeekToDVDChapter(nID - ID_NAVIGATE_JUMPTO_SUBITEM_START + 1); - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - int nChannel = nID - ID_NAVIGATE_JUMPTO_SUBITEM_START; - - if (s.nDVBLastChannel != nChannel) { - if (SUCCEEDED(SetChannel(nChannel))) { - if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { - m_wndNavigationBar.m_navdlg.UpdatePos(nChannel); - } - } - } - } - } -} - -void CMainFrame::OnNavigateMenuItem(UINT nID) -{ - nID -= ID_NAVIGATE_MENU_LEFT; - - if (GetPlaybackMode() == PM_DVD) { - switch (nID) { - case 0: - m_pDVDC->SelectRelativeButton(DVD_Relative_Left); - break; - case 1: - m_pDVDC->SelectRelativeButton(DVD_Relative_Right); - break; - case 2: - m_pDVDC->SelectRelativeButton(DVD_Relative_Upper); - break; - case 3: - m_pDVDC->SelectRelativeButton(DVD_Relative_Lower); - break; - case 4: - if (m_iDVDDomain == DVD_DOMAIN_Title || m_iDVDDomain == DVD_DOMAIN_VideoTitleSetMenu || m_iDVDDomain == DVD_DOMAIN_VideoManagerMenu) { - m_pDVDC->ActivateButton(); - } else { - OnPlayPlay(); - } - break; - case 5: - m_pDVDC->ReturnFromSubmenu(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - break; - case 6: - m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - break; - default: - break; - } - } else if (GetPlaybackMode() == PM_FILE) { - OnPlayPlay(); - } -} - -void CMainFrame::OnUpdateNavigateMenuItem(CCmdUI* pCmdUI) -{ - pCmdUI->Enable((GetLoadState() == MLS::LOADED) && ((GetPlaybackMode() == PM_DVD) || (GetPlaybackMode() == PM_FILE))); -} - -void CMainFrame::OnTunerScan() -{ - m_bScanDlgOpened = true; - CTunerScanDlg dlg(this); - dlg.DoModal(); - m_bScanDlgOpened = false; -} - -void CMainFrame::OnUpdateTunerScan(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_DIGITAL_CAPTURE); -} - -// favorites - -class CDVDStateStream : public CUnknown, public IStream -{ - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { - return - QI(IStream) - CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - - size_t m_pos; - -public: - CDVDStateStream() : CUnknown(NAME("CDVDStateStream"), nullptr) { - m_pos = 0; - } - - DECLARE_IUNKNOWN; - - CAtlArray m_data; - - // ISequentialStream - STDMETHODIMP Read(void* pv, ULONG cb, ULONG* pcbRead) { - size_t cbRead = std::min(m_data.GetCount() - m_pos, size_t(cb)); - cbRead = std::max(cbRead, size_t(0)); - if (cbRead) { - memcpy(pv, &m_data[m_pos], cbRead); - } - if (pcbRead) { - *pcbRead = (ULONG)cbRead; - } - m_pos += cbRead; - return S_OK; - } - STDMETHODIMP Write(const void* pv, ULONG cb, ULONG* pcbWritten) { - BYTE* p = (BYTE*)pv; - ULONG cbWritten = (ULONG) - 1; - while (++cbWritten < cb) { - m_data.Add(*p++); - } - if (pcbWritten) { - *pcbWritten = cbWritten; - } - return S_OK; - } - - // IStream - STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { - return E_NOTIMPL; - } - - STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize) { - return E_NOTIMPL; - } - - STDMETHODIMP CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { - return E_NOTIMPL; - } - - STDMETHODIMP Commit(DWORD grfCommitFlags) { - return E_NOTIMPL; - } - - STDMETHODIMP Revert() { - return E_NOTIMPL; - } - - STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { - return E_NOTIMPL; - } - - STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { - return E_NOTIMPL; - } - - STDMETHODIMP Stat(STATSTG* pstatstg, DWORD grfStatFlag) { - return E_NOTIMPL; - } - - STDMETHODIMP Clone(IStream** ppstm) { - return E_NOTIMPL; - } -}; - -void CMainFrame::AddFavorite(bool fDisplayMessage, bool fShowDialog) -{ - CAppSettings& s = AfxGetAppSettings(); - CAtlList args; - WORD osdMsg = 0; - const TCHAR sep = _T(';'); - - if (GetPlaybackMode() == PM_FILE) { - bool is_BD = false; - CString fn = m_wndPlaylistBar.GetCurFileNameTitle(); - if (fn.IsEmpty()) { - if (m_pFSF) { - CComHeapPtr pFN; - AM_MEDIA_TYPE mt; - if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { - fn = CStringW(pFN); - } - } - if (fn.IsEmpty()) { - return; - } - is_BD = true; - } - - CString desc = GetFileName(); - - // Name - CString name; - if (fShowDialog) { - BOOL bEnableABMarks = static_cast(abRepeat); - CFavoriteAddDlg dlg(desc, fn, bEnableABMarks); - if (dlg.DoModal() != IDOK) { - return; - } - name = dlg.m_name; - } else { - name = desc; - } - args.AddTail(name); - - // RememberPos - CString posStr = _T("0"); - if (s.bFavRememberPos) { - posStr.Format(_T("%I64d"), GetPos()); - } - // RememberABMarks - if (s.bFavRememberABMarks && abRepeat) { - posStr.AppendFormat(_T(":%I64d:%I64d"), abRepeat.positionA, abRepeat.positionB); - } - args.AddTail(posStr); - - // RelativeDrive - CString relativeDrive; - relativeDrive.Format(_T("%d"), s.bFavRelativeDrive); - - args.AddTail(relativeDrive); - - // Paths - if (is_BD) { - args.AddTail(fn); - } else { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli)) { - if (pli.m_bYoutubeDL) { - args.AddTail(pli.m_ydlSourceURL); - } else { - POSITION pos = pli.m_fns.GetHeadPosition(); - while (pos) { - args.AddTail(pli.m_fns.GetNext(pos)); - } - } - } - } - - CString str = ImplodeEsc(args, sep); - s.AddFav(FAV_FILE, str); - osdMsg = IDS_FILE_FAV_ADDED; - } else if (GetPlaybackMode() == PM_DVD) { - WCHAR path[MAX_PATH]; - ULONG len = 0; - if (SUCCEEDED(m_pDVDI->GetDVDDirectory(path, MAX_PATH, &len))) { - CString fn = path; - fn.TrimRight(_T("/\\")); - - DVD_PLAYBACK_LOCATION2 Location; - CString desc; - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location))) { - desc.Format(_T("%s - T%02u C%02u - %02u:%02u:%02u"), fn.GetString(), Location.TitleNum, Location.ChapterNum, - Location.TimeCode.bHours, Location.TimeCode.bMinutes, Location.TimeCode.bSeconds); - } else { - desc = fn; - } - // Name - CString name; - if (fShowDialog) { - CFavoriteAddDlg dlg(fn, desc); - if (dlg.DoModal() != IDOK) { - return; - } - name = dlg.m_name; - } else { - name = s.bFavRememberPos ? desc : fn; - } - args.AddTail(name); - - // RememberPos - CString pos(_T("0")); - if (s.bFavRememberPos) { - CDVDStateStream stream; - stream.AddRef(); - - CComPtr pStateData; - CComQIPtr pPersistStream; - if (SUCCEEDED(m_pDVDI->GetState(&pStateData)) - && (pPersistStream = pStateData) - && SUCCEEDED(OleSaveToStream(pPersistStream, (IStream*)&stream))) { - pos = BinToCString(stream.m_data.GetData(), stream.m_data.GetCount()); - } - } - - args.AddTail(pos); - - // Paths - args.AddTail(fn); - - CString str = ImplodeEsc(args, sep); - s.AddFav(FAV_DVD, str); - osdMsg = IDS_DVD_FAV_ADDED; - } - } // TODO: PM_ANALOG_CAPTURE and PM_DIGITAL_CAPTURE - - if (fDisplayMessage && osdMsg) { - CString osdMsgStr(StrRes(osdMsg)); - SendStatusMessage(osdMsgStr, 3000); - m_OSD.DisplayMessage(OSD_TOPLEFT, osdMsgStr, 3000); - } - if (::IsWindow(m_wndFavoriteOrganizeDialog.m_hWnd)) { - m_wndFavoriteOrganizeDialog.LoadList(); - } -} - -void CMainFrame::OnFavoritesAdd() -{ - AddFavorite(); -} - -void CMainFrame::OnUpdateFavoritesAdd(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD); -} - -void CMainFrame::OnFavoritesQuickAddFavorite() -{ - AddFavorite(true, false); -} - -void CMainFrame::OnFavoritesOrganize() -{ - m_wndFavoriteOrganizeDialog.ShowWindow(SW_SHOW); -} - -void CMainFrame::OnUpdateFavoritesOrganize(CCmdUI* pCmdUI) -{ - const CAppSettings& s = AfxGetAppSettings(); - CAtlList sl; - s.GetFav(FAV_FILE, sl); - bool enable = !sl.IsEmpty(); - - if (!enable) { - s.GetFav(FAV_DVD, sl); - enable = !sl.IsEmpty(); - } - - pCmdUI->Enable(enable); -} - -void CMainFrame::OnRecentFileClear() -{ - if (IDYES != AfxMessageBox(IDS_RECENT_FILES_QUESTION, MB_ICONQUESTION | MB_YESNO, 0)) { - return; - } - - CAppSettings& s = AfxGetAppSettings(); - s.ClearRecentFiles(); -} - -void CMainFrame::OnUpdateRecentFileClear(CCmdUI* pCmdUI) -{ - // TODO: Add your command update UI handler code here -} - -void CMainFrame::OnFavoritesFile(UINT nID) -{ - nID -= ID_FAVORITES_FILE_START; - CAtlList sl; - AfxGetAppSettings().GetFav(FAV_FILE, sl); - - if (POSITION pos = sl.FindIndex(nID)) { - PlayFavoriteFile(sl.GetAt(pos)); - } -} - -void CMainFrame::PlayFavoriteFile(const CString& fav) -{ - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - - CAtlList args; - REFERENCE_TIME rtStart = 0; - FileFavorite ff = ParseFavoriteFile(fav, args, &rtStart); - - auto firstFile = args.GetHead(); - if (!m_wndPlaylistBar.SelectFileInPlaylist(firstFile) && - (!CanSendToYoutubeDL(firstFile) || - !ProcessYoutubeDLURL(firstFile, false))) { - m_wndPlaylistBar.Open(args, false); - } - - m_wndPlaylistBar.SetCurLabel(ff.Name); - - if (GetPlaybackMode() == PM_FILE && args.GetHead() == m_lastOMD->title) { - m_pMS->SetPositions(&rtStart, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - OnPlayPlay(); - } else { - OpenCurPlaylistItem(rtStart); - } - -} - -FileFavorite CMainFrame::ParseFavoriteFile(const CString& fav, CAtlList& args, REFERENCE_TIME* prtStart) -{ - FileFavorite ff; - VERIFY(FileFavorite::TryParse(fav, ff, args)); - - abRepeat.positionA = ff.MarkA; - abRepeat.positionB = ff.MarkB; - - // Start at mark A (if set) - ff.Start = std::max(ff.Start, abRepeat.positionA); - - if (prtStart) { - *prtStart = ff.Start; - } - - // NOTE: This is just for the favorites but we could add a global settings that - // does this always when on. Could be useful when using removable devices. - // All you have to do then is plug in your 500 gb drive, full with movies and/or music, - // start MPC-HC (from the 500 gb drive) with a preloaded playlist and press play. - if (ff.RelativeDrive) { - // Get the drive MPC-HC is on and apply it to the path list - CString exePath = PathUtils::GetProgramPath(true); - - CPath exeDrive(exePath); - - if (exeDrive.StripToRoot()) { - POSITION pos = args.GetHeadPosition(); - - while (pos != nullptr) { - CString& stringPath = args.GetNext(pos); // Note the reference (!) - CPath path(stringPath); - - int rootLength = path.SkipRoot(); - - if (path.StripToRoot()) { - if (_tcsicmp(exeDrive, path) != 0) { // Do we need to replace the drive letter ? - // Replace drive letter - CString newPath(exeDrive); - - newPath += stringPath.Mid(rootLength); - - stringPath = newPath; // Note: Changes args.GetHead() - } - } - } - } - } - return ff; -} - -void CMainFrame::OnUpdateFavoritesFile(CCmdUI* pCmdUI) -{ - //UINT nID = pCmdUI->m_nID - ID_FAVORITES_FILE_START; -} - -void CMainFrame::OnRecentFile(UINT nID) -{ - CAtlList fns; - auto& MRU = AfxGetAppSettings().MRU; - RecentFileEntry r; - - // find corresponding item in MRU list, we can't directly use string from menu because it may have been shortened - nID -= ID_RECENT_FILE_START; - if (nID < MRU.GetSize()) { - r = MRU[nID]; - fns.AddHeadList(&r.fns); - } else { - ASSERT(false); - return; - } - - CloseMediaBeforeOpen(); - - if (fns.GetCount() == 1 && CanSendToYoutubeDL(r.fns.GetHead())) { - if (ProcessYoutubeDLURL(fns.GetHead(), false)) { - OpenCurPlaylistItem(); - return; - } else if (IsOnYDLWhitelist(fns.GetHead())) { - // don't bother trying to open this website URL directly - return; - } - } - - CAtlList subs; - subs.AddHeadList(&r.subs); - - if (!m_wndPlaylistBar.SelectFileInPlaylist(fns.GetHead())) { - m_wndPlaylistBar.Open(fns, false, &subs, r.title, _T(""), r.cue); - } - else { - m_wndPlaylistBar.ReplaceCurrentItem(fns, &subs, r.title, _T(""), r.cue); - } - - OpenCurPlaylistItem(); -} - -void CMainFrame::OnUpdateRecentFile(CCmdUI* pCmdUI) -{ - //UINT nID = pCmdUI->m_nID - ID_RECENT_FILE_START; -} - -void CMainFrame::OnFavoritesDVD(UINT nID) -{ - nID -= ID_FAVORITES_DVD_START; - - CAtlList sl; - AfxGetAppSettings().GetFav(FAV_DVD, sl); - - if (POSITION pos = sl.FindIndex(nID)) { - PlayFavoriteDVD(sl.GetAt(pos)); - } -} - -void CMainFrame::PlayFavoriteDVD(CString fav) -{ - CAtlList args; - CString fn; - CDVDStateStream stream; - - stream.AddRef(); - - ExplodeEsc(fav, args, _T(';'), 3); - args.RemoveHeadNoReturn(); // desc / name - CString state = args.RemoveHead(); // state - if (state != _T("0")) { - CStringToBin(state, stream.m_data); - } - fn = args.RemoveHead(); // path - - SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); - - CComPtr pDvdState; - HRESULT hr = OleLoadFromStream((IStream*)&stream, IID_PPV_ARGS(&pDvdState)); - UNREFERENCED_PARAMETER(hr); - - CAutoPtr p(DEBUG_NEW OpenDVDData()); - if (p) { - p->path = fn; - p->pDvdState = pDvdState; - } - OpenMedia(p); -} - -void CMainFrame::OnUpdateFavoritesDVD(CCmdUI* pCmdUI) -{ - //UINT nID = pCmdUI->m_nID - ID_FAVORITES_DVD_START; -} - -void CMainFrame::OnFavoritesDevice(UINT nID) -{ - //nID -= ID_FAVORITES_DEVICE_START; -} - -void CMainFrame::OnUpdateFavoritesDevice(CCmdUI* pCmdUI) -{ - //UINT nID = pCmdUI->m_nID - ID_FAVORITES_DEVICE_START; -} - -// help - -void CMainFrame::OnHelpHomepage() -{ - ShellExecute(m_hWnd, _T("open"), WEBSITE_URL, nullptr, nullptr, SW_SHOWDEFAULT); -} - -void CMainFrame::OnHelpCheckForUpdate() -{ - UpdateChecker::CheckForUpdate(); -} - -void CMainFrame::OnHelpToolbarImages() -{ - ShellExecute(m_hWnd, _T("open"), _T("https://github.com/clsid2/mpc-hc/issues/382"), nullptr, nullptr, SW_SHOWDEFAULT); -} - -void CMainFrame::OnHelpDonate() -{ - ShellExecute(m_hWnd, _T("open"), _T("https://github.com/clsid2/mpc-hc/issues/383"), nullptr, nullptr, SW_SHOWDEFAULT); -} - -////////////////////////////////// - -static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - CAtlArray* ml = (CAtlArray*)dwData; - ml->Add(hMonitor); - return TRUE; -} - -void CMainFrame::SetDefaultWindowRect(int iMonitor) -{ - const CAppSettings& s = AfxGetAppSettings(); - CRect rcLastWindowPos = s.rcLastWindowPos; - - if (s.eCaptionMenuMode != MODE_SHOWCAPTIONMENU) { - if (s.eCaptionMenuMode == MODE_FRAMEONLY) { - ModifyStyle(WS_CAPTION, 0, SWP_NOZORDER); - } else if (s.eCaptionMenuMode == MODE_BORDERLESS) { - ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0, SWP_NOZORDER); - } - SetMenuBarVisibility(AFX_MBV_DISPLAYONFOCUS); - SetWindowPos(nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - } - - CMonitors monitors; - CMonitor monitor; - if (iMonitor > 0 && iMonitor <= monitors.GetCount()) { - monitor = monitors.GetMonitor(iMonitor - 1); - } else { - monitor = CMonitors::GetNearestMonitor(this); - } - - CSize windowSize; - bool tRememberPos = s.fRememberWindowPos; - MINMAXINFO mmi; - OnGetMinMaxInfo(&mmi); - - if (s.HasFixedWindowSize()) { - windowSize = CSize(std::max(s.sizeFixedWindow.cx, mmi.ptMinTrackSize.x), std::max(s.sizeFixedWindow.cy, mmi.ptMinTrackSize.y)); - if (s.fixedWindowPosition != NO_FIXED_POSITION) { - tRememberPos = true; - CRect monitorRect; - monitor.GetWorkAreaRect(&monitorRect); - monitorRect += s.fixedWindowPosition; - rcLastWindowPos.MoveToXY(monitorRect.left, monitorRect.top); - } - } else if (s.fRememberWindowSize) { - windowSize = rcLastWindowPos.Size(); - } else { - CRect windowRect; - GetWindowRect(&windowRect); - CRect clientRect; - GetClientRect(&clientRect); - - CSize logoSize = m_wndView.GetLogoSize(); - logoSize.cx = std::max(logoSize.cx, m_dpi.ScaleX(MIN_LOGO_WIDTH)); - logoSize.cy = std::max(logoSize.cy, m_dpi.ScaleY(MIN_LOGO_HEIGHT)); - - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); - - windowSize.cx = windowRect.Width() - clientRect.Width() + logoSize.cx + uLeft + uRight; - windowSize.cy = windowRect.Height() - clientRect.Height() + logoSize.cy + uTop + uBottom; - } - - bool bRestoredWindowPosition = false; - if (tRememberPos) { - CRect windowRect(rcLastWindowPos.TopLeft(), windowSize); - if ((!iMonitor && CMonitors::IsOnScreen(windowRect)) - || (iMonitor && monitor.IsOnMonitor(windowRect))) { - restoringWindowRect = true; - MoveWindow(windowRect); - restoringWindowRect = false; - bRestoredWindowPosition = true; - } - } - - if (!bRestoredWindowPosition) { - CRect windowRect(0, 0, std::max(windowSize.cx, mmi.ptMinTrackSize.x), std::max(windowSize.cy, mmi.ptMinTrackSize.y)); - monitor.CenterRectToMonitor(windowRect, TRUE); - SetWindowPos(nullptr, windowRect.left, windowRect.top, windowSize.cx, windowSize.cy, SWP_NOZORDER | SWP_NOACTIVATE); - } - - if (s.fSavePnSZoom) { - m_ZoomX = s.dZoomX; - m_ZoomY = s.dZoomY; - } -} - -void CMainFrame::SetDefaultFullscreenState() -{ - CAppSettings& s = AfxGetAppSettings(); - - bool clGoFullscreen = !(s.nCLSwitches & (CLSW_ADD | CLSW_THUMBNAILS)) && (s.nCLSwitches & CLSW_FULLSCREEN); - - if (clGoFullscreen && !s.slFiles.IsEmpty()) { - // ignore fullscreen if all files are audio - clGoFullscreen = false; - const CMediaFormats& mf = AfxGetAppSettings().m_Formats; - POSITION pos = s.slFiles.GetHeadPosition(); - while (pos) { - CString fpath = s.slFiles.GetNext(pos); - CString ext = fpath.Mid(fpath.ReverseFind('.') + 1); - if (!mf.FindExt(ext, true)) { - clGoFullscreen = true; - break; - } - } - } - - if (clGoFullscreen) { - if (s.IsD3DFullscreen()) { - m_fStartInD3DFullscreen = true; - } else { - bool launchingFullscreenSeparateControls = false; - if (s.bFullscreenSeparateControls) { - CMonitors monitors; - CMonitor currentMonitor = monitors.GetNearestMonitor(this); - CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); - if (fullscreenMonitor.IsMonitor()) { - launchingFullscreenSeparateControls = fullscreenMonitor != currentMonitor; - } - } - - if (launchingFullscreenSeparateControls) { - m_fStartInFullscreenSeparate = true; - } else { - ToggleFullscreen(true, true); - m_bNeedZoomAfterFullscreenExit = true; - } - } - s.nCLSwitches &= ~CLSW_FULLSCREEN; - } else if (s.fRememberWindowSize && s.fRememberWindowPos && !m_fFullScreen && s.fLastFullScreen) { - // Casimir666 : if fullscreen was on, put it on back - if (s.IsD3DFullscreen()) { - m_fStartInD3DFullscreen = true; - } else { - ToggleFullscreen(true, true); - m_bNeedZoomAfterFullscreenExit = true; - } - } -} - -void CMainFrame::RestoreDefaultWindowRect() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (!m_fFullScreen && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { - CSize windowSize; - - if (s.HasFixedWindowSize()) { - windowSize = s.sizeFixedWindow; - } else if (s.fRememberWindowSize) { - windowSize = s.rcLastWindowPos.Size(); - } else { - CRect windowRect; - GetWindowRect(&windowRect); - CRect clientRect; - GetClientRect(&clientRect); - - CSize logoSize = m_wndView.GetLogoSize(); - logoSize.cx = std::max(logoSize.cx, m_dpi.ScaleX(MIN_LOGO_WIDTH)); - logoSize.cy = std::max(logoSize.cy, m_dpi.ScaleY(MIN_LOGO_HEIGHT)); - - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); - - windowSize.cx = windowRect.Width() - clientRect.Width() + logoSize.cx + uLeft + uRight; - windowSize.cy = windowRect.Height() - clientRect.Height() + logoSize.cy + uTop + uBottom; - } - - if (s.fRememberWindowPos) { - MoveWindow(CRect(s.rcLastWindowPos.TopLeft(), windowSize)); - } else { - SetWindowPos(nullptr, 0, 0, windowSize.cx, windowSize.cy, SWP_NOMOVE | SWP_NOZORDER); - CenterWindow(); - } - } -} - -CRect CMainFrame::GetInvisibleBorderSize() const -{ - CRect invisibleBorders; - - if (IsWindows10OrGreater()) { - static const WinapiFunc - fnDwmGetWindowAttribute = { _T("Dwmapi.dll"), "DwmGetWindowAttribute" }; - - if (fnDwmGetWindowAttribute) { - if (SUCCEEDED(fnDwmGetWindowAttribute(GetSafeHwnd(), DWMWA_EXTENDED_FRAME_BOUNDS, &invisibleBorders, sizeof(RECT)))) { - CRect windowRect; - GetWindowRect(windowRect); - - invisibleBorders.TopLeft() = invisibleBorders.TopLeft() - windowRect.TopLeft(); - invisibleBorders.BottomRight() = windowRect.BottomRight() - invisibleBorders.BottomRight(); - } else { - ASSERT(false); - } - } - } - - return invisibleBorders; -} - -OAFilterState CMainFrame::GetMediaStateDirect() const -{ - OAFilterState ret = -1; - if (m_eMediaLoadState == MLS::LOADED) { - m_pMC->GetState(0, &ret); - } - return ret; -} - -OAFilterState CMainFrame::GetMediaState() const -{ - OAFilterState ret = -1; - if (m_eMediaLoadState == MLS::LOADED) { - if (m_CachedFilterState != -1) { - #if DEBUG & 0 - ret = GetMediaStateDirect(); - ASSERT(ret == m_CachedFilterState || m_fFrameSteppingActive); - #endif - return m_CachedFilterState; - } else { - m_pMC->GetState(0, &ret); - } - } - return ret; -} - -OAFilterState CMainFrame::UpdateCachedMediaState() -{ - m_CachedFilterState = GetMediaStateDirect(); - return m_CachedFilterState; -} - -bool CMainFrame::MediaControlRun(bool waitforcompletion) -{ - m_dwLastPause = 0; - if (m_pMC) { - m_CachedFilterState = State_Running; - if (FAILED(m_pMC->Run())) { - // still in transition to running state - if (waitforcompletion) { - m_CachedFilterState = -1; - m_pMC->GetState(0, &m_CachedFilterState); - ASSERT(m_CachedFilterState == State_Running); - } - }; - MediaTransportControlUpdateState(State_Running); - return true; - } - return false; -} - -bool CMainFrame::MediaControlPause(bool waitforcompletion) -{ - m_dwLastPause = GetTickCount64(); - if (m_pMC) { - m_CachedFilterState = State_Paused; - if (FAILED(m_pMC->Pause())) { - // still in transition to paused state - if (waitforcompletion) { - m_CachedFilterState = -1; - m_pMC->GetState(0, &m_CachedFilterState); - ASSERT(m_CachedFilterState == State_Paused); - } - } - MediaTransportControlUpdateState(State_Paused); - return true; - } - return false; -} - -bool CMainFrame::MediaControlStop(bool waitforcompletion) -{ - m_dwLastPause = 0; - if (m_pMC) { - m_pMC->GetState(0, &m_CachedFilterState); - if (m_CachedFilterState != State_Stopped) { - if (FAILED(m_pMC->Stop())) { - ASSERT(FALSE); - m_CachedFilterState = -1; - return false; - } - if (waitforcompletion) { - m_CachedFilterState = -1; - m_pMC->GetState(0, &m_CachedFilterState); - ASSERT(m_CachedFilterState == State_Stopped); - } else { - m_CachedFilterState = State_Stopped; - } - } - MediaTransportControlUpdateState(State_Stopped); - return true; - } - return false; -} - -bool CMainFrame::MediaControlStopPreview() -{ - if (m_pMC_preview) { - OAFilterState fs = -1; - m_pMC_preview->GetState(0, &fs); - if (fs != State_Stopped) { - if (FAILED(m_pMC_preview->Stop())) { - ASSERT(FALSE); - return false; - } - m_pMC_preview->GetState(0, &fs); - ASSERT(fs == State_Stopped); - } - return true; - } - return false; -} - -void CMainFrame::SetPlaybackMode(int iNewStatus) -{ - m_iPlaybackMode = iNewStatus; -} - -CSize CMainFrame::GetVideoSizeWithRotation(bool forPreview) const -{ - CSize ret = GetVideoSize(); - if (forPreview && m_pGB_preview) { - CFGManagerPlayer* fgmPreview = static_cast(m_pGB_preview.p); - if (fgmPreview && !fgmPreview->PreviewSupportsRotation()) { - //preview cannot rotate, so we need to reverse any default rotation that swapped x/y - int rotation = ((360 - m_iDefRotation) % 360) / 90; - if (rotation == 1 || rotation == 3) { - std::swap(ret.cx, ret.cy); - } - return ret; - } - } - - if (m_pCAP && !m_pCAP3) { //videosize does not consider manual rotation - int rotation = ((360 - nearest90(m_AngleZ)) % 360) / 90; //do not add in m_iDefRotation - if (rotation == 1 || rotation == 3) { //90 degrees - std::swap(ret.cx, ret.cy); - } - } - return ret; -} - -CSize CMainFrame::GetVideoSize() const -{ - CSize ret; - if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { - return ret; - } - - const CAppSettings& s = AfxGetAppSettings(); - CSize videoSize, preferedAR; - - if (m_pCAP) { - videoSize = m_pCAP->GetVideoSize(false); - preferedAR = m_pCAP->GetVideoSize(s.fKeepAspectRatio); - } else if (m_pMFVDC) { - m_pMFVDC->GetNativeVideoSize(&videoSize, &preferedAR); // TODO : check AR !! - } else if (m_pBV) { - m_pBV->GetVideoSize(&videoSize.cx, &videoSize.cy); - - long arx = 0, ary = 0; - CComQIPtr pBV2 = m_pBV; - // FIXME: It can hang here, for few seconds (CPU goes to 100%), after the window have been moving over to another screen, - // due to GetPreferredAspectRatio, if it happens before CAudioSwitcherFilter::DeliverEndFlush, it seems. - if (pBV2 && SUCCEEDED(pBV2->GetPreferredAspectRatio(&arx, &ary)) && arx > 0 && ary > 0) { - preferedAR.SetSize(arx, ary); - } - } - if (preferedAR.cx <= 0 || preferedAR.cy <= 0) { //due to IBasicVideo2 not being found, this could still be zero for .swf - preferedAR.SetSize(videoSize.cx, videoSize.cy); - } - - if (videoSize.cx <= 0 || videoSize.cy <= 0) { - return ret; - } - - if (s.fKeepAspectRatio) { - CSize overrideAR = s.GetAspectRatioOverride(); - DVD_VideoAttributes VATR; - if ((!overrideAR.cx || !overrideAR.cy) && GetPlaybackMode() == PM_DVD - && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { - overrideAR.SetSize(VATR.ulAspectX, VATR.ulAspectY); - } - if (overrideAR.cx > 0 && overrideAR.cy > 0) { - if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", double(overrideAR.cx) / overrideAR.cy))) { - ret = m_pCAP->GetVideoSize(false); - } else { - ret = CSize(MulDiv(videoSize.cy, overrideAR.cx, overrideAR.cy), videoSize.cy); - } - } else { - if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", 0.0))) { - ret = m_pCAP->GetVideoSize(false); - } else { - ret = CSize(MulDiv(videoSize.cy, preferedAR.cx, preferedAR.cy), videoSize.cy); - } - } - } else { - CSize originalVideoSize(0, 1); - if (m_pMVRI) { - m_pMVRI->GetSize("originalVideoSize", &originalVideoSize); - } - if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", - double(originalVideoSize.cx) / originalVideoSize.cy))) { - ret = m_pCAP->GetVideoSize(false); - } else { - ret = videoSize; - } - } - - if (s.fCompMonDeskARDiff - && s.iDSVideoRendererType != VIDRNDT_DS_EVR - && s.iDSVideoRendererType != VIDRNDT_DS_MADVR) - if (HDC hDC = ::GetDC(nullptr)) { - int _HORZSIZE = GetDeviceCaps(hDC, HORZSIZE); - int _VERTSIZE = GetDeviceCaps(hDC, VERTSIZE); - int _HORZRES = GetDeviceCaps(hDC, HORZRES); - int _VERTRES = GetDeviceCaps(hDC, VERTRES); - - if (_HORZSIZE > 0 && _VERTSIZE > 0 && _HORZRES > 0 && _VERTRES > 0) { - double a = 1.0 * _HORZSIZE / _VERTSIZE; - double b = 1.0 * _HORZRES / _VERTRES; - - if (b < a) { - ret.cy = (DWORD)(1.0 * ret.cy * a / b); - } else if (a < b) { - ret.cx = (DWORD)(1.0 * ret.cx * b / a); - } - } - - ::ReleaseDC(nullptr, hDC); - } - - return ret; -} - -void CMainFrame::HidePlaylistFullScreen(bool force /* = false */) -{ - if (force || m_fFullScreen) { - CAppSettings& s = AfxGetAppSettings(); - if (s.bHidePlaylistFullScreen && m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)) { - m_wndPlaylistBar.SetHiddenDueToFullscreen(true); - ShowControlBar(&m_wndPlaylistBar, FALSE, FALSE); - } - } -} - -void CMainFrame::ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo) -{ - if (IsD3DFullScreenMode()) { - ASSERT(FALSE); - return; - } - - CAppSettings& s = AfxGetAppSettings(); - - if (delayingFullScreen) { - return; //swallow request if we are in the delay period - } - - CMonitors monitors; - CMonitor defaultMonitor = monitors.GetPrimaryMonitor(); - CMonitor currentMonitor = monitors.GetNearestMonitor(this); - CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); - if (!fullscreenMonitor.IsMonitor()) { - fullscreenMonitor = currentMonitor; - } - bool fullScreenSeparate = s.bFullscreenSeparateControls && (m_pMFVDC || m_pVMRWC || m_pVW) && fullscreenMonitor.IsMonitor() && fullscreenMonitor != currentMonitor && (s.nCS & (CS_SEEKBAR | CS_TOOLBAR)); - - const CWnd* pInsertAfter = nullptr; - CRect windowRect; - DWORD dwRemove = 0, dwAdd = 0; - - if (!fullScreenSeparate && s.iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 - BOOL setEnabled = TRUE; - ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); - } - - bool restart_osd = false; - if (!m_pMVTO) { - m_OSD.Stop(); - restart_osd = s.fShowOSD || s.fShowDebugInfo; - } - - if (fullScreenSeparate) { - if (m_fFullScreen) { - m_fFullScreen = false; - } else { - if (!m_bNeedZoomAfterFullscreenExit && !s.HasFixedWindowSize()) { - // adjust control window size to minimal - m_bNeedZoomAfterFullscreenExit = true; - ZoomVideoWindow(ZOOM_DEFAULT_LEVEL, true); - } - m_fFullScreen = true; - } - s.fLastFullScreen = false; //not really, just fullScreenSecondMonitor - - if (m_fFullScreen) { - m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN); - - // Set the fullscreen display mode - if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo) { - AutoChangeMonitorMode(); - } - - CreateFullScreenWindow(false); - if (m_pD3DFSC && s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { - m_pD3DFSC->SetD3DFullscreen(true); - } - // Assign the windowed video frame and pass it to the relevant classes. - m_pVideoWnd = m_pDedicatedFSVideoWnd; - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } else if (m_pVMRWC) { - m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); - } - if (m_pVW) { - m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); - m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); - } - m_wndView.Invalidate(); - } else { - m_eventc.FireEvent(MpcEvent::SWITCHING_FROM_FULLSCREEN); - - if (m_pD3DFSC && s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { - m_pD3DFSC->SetD3DFullscreen(false); - } - m_pVideoWnd = &m_wndView; - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } else if (m_pVMRWC) { - m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); - } - if (m_pVW) { - m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); - m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); - } - if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { - SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift - } - - // Destroy the Fullscreen window and zoom the windowed video frame - m_pDedicatedFSVideoWnd->DestroyWindow(); - if (m_bNeedZoomAfterFullscreenExit) { - m_bNeedZoomAfterFullscreenExit = false; - if (s.fRememberZoomLevel) { - ZoomVideoWindow(); - } - } - } - MoveVideoWindow(); - - if (s.bHideWindowedControls) { - m_controls.UpdateToolbarsVisibility(); - } - } else { - m_fFullScreen = !m_fFullScreen; - s.fLastFullScreen = m_fFullScreen; - - if (m_fFullScreen) { - SetCursor(nullptr); // prevents cursor flickering when our window is not under the cursor - - m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN); - - HidePlaylistFullScreen(true); - - GetWindowRect(&m_lastWindowRect); - - if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo && GetPlaybackMode() != PM_NONE) { - AutoChangeMonitorMode(); - } - - dwRemove |= WS_CAPTION | WS_THICKFRAME; - if (s.fPreventMinimize && fullscreenMonitor != defaultMonitor) { - dwRemove |= WS_MINIMIZEBOX; - } - - m_bExtOnTop = !s.iOnTop && (GetExStyle() & WS_EX_TOPMOST); - pInsertAfter = &wndTopMost; - - if (fToNearest) { - fullscreenMonitor.GetMonitorRect(windowRect); - } else { - GetDesktopWindow()->GetWindowRect(windowRect); - } - } else { - m_eventc.FireEvent(MpcEvent::SWITCHING_FROM_FULLSCREEN); - - if (m_pVideoWnd != &m_wndView) { - m_pVideoWnd = &m_wndView; - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } else if (m_pVMRWC) { - m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); - } - if (m_pVW) { - m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); - m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); - } - } - m_pDedicatedFSVideoWnd->DestroyWindow(); - - if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { - SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift - } - - windowRect = m_lastWindowRect; - if (!monitors.IsOnScreen(windowRect)) { - currentMonitor.CenterRectToMonitor(windowRect, TRUE); - } - - dwAdd |= WS_MINIMIZEBOX; - if (s.eCaptionMenuMode != MODE_BORDERLESS) { - dwAdd |= WS_THICKFRAME; - if (s.eCaptionMenuMode != MODE_FRAMEONLY) { - dwAdd |= WS_CAPTION; - } - } - - if (m_wndPlaylistBar.IsHiddenDueToFullscreen() && !m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)) { - if (s.bHideWindowedControls) { - m_wndPlaylistBar.SetHiddenDueToFullscreen(false, true); - } else { - m_wndPlaylistBar.SetHiddenDueToFullscreen(false); - m_controls.ToggleControl(CMainFrameControls::Panel::PLAYLIST); - } - } - - // If MPC-HC wasn't previously set "on top" by an external tool, - // we restore the current internal on top state. (1/2) - if (!m_bExtOnTop) { - pInsertAfter = &wndNoTopMost; - } - } - - bool bZoomVideoWindow = false; - if (m_bNeedZoomAfterFullscreenExit && !m_fFullScreen) { - bZoomVideoWindow = s.fRememberZoomLevel; - m_bNeedZoomAfterFullscreenExit = false; - } - - ModifyStyle(dwRemove, dwAdd, SWP_NOZORDER); - SetWindowPos(pInsertAfter, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), - SWP_NOSENDCHANGING | SWP_FRAMECHANGED); - - // If MPC-HC wasn't previously set "on top" by an external tool, - // we restore the current internal on top state. (2/2) - if (!m_fFullScreen && !m_bExtOnTop) { - SetAlwaysOnTop(s.iOnTop); - } - - SetMenuBarVisibility((!m_fFullScreen && s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) - ? AFX_MBV_KEEPVISIBLE : AFX_MBV_DISPLAYONFOCUS); - - UpdateControlState(UPDATE_CONTROLS_VISIBILITY); - - if (bZoomVideoWindow) { - ZoomVideoWindow(); - } - MoveVideoWindow(); - } - - if (restart_osd) { - if (m_fFullScreen && m_pCAP3 && m_pMFVMB) { // MPCVR - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); - } else { - m_OSD.Start(m_pOSDWnd); - OSDBarSetPos(); - } - } - - if (m_fFullScreen) { - m_eventc.FireEvent(MpcEvent::SWITCHED_TO_FULLSCREEN); - } else { - m_eventc.FireEvent(MpcEvent::SWITCHED_FROM_FULLSCREEN); - } - - if (!fullScreenSeparate && s.iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 - UINT_PTR timerID = 0; - timerID = SetTimer(TIMER_WINDOW_FULLSCREEN, s.iFullscreenDelay, nullptr); - if (0 == timerID) { - BOOL setEnabled = FALSE; - ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); - } else { - delayingFullScreen = true; - } - RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE); - } -} - -void CMainFrame::ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo) -{ - if (m_pD3DFSC && m_pMFVDC) { - CAppSettings& s = AfxGetAppSettings(); - - bool bIsFullscreen = false; - m_pD3DFSC->GetD3DFullscreen(&bIsFullscreen); - s.fLastFullScreen = !bIsFullscreen; - - m_OSD.Stop(); - - if (bIsFullscreen) { - // Turn off D3D Fullscreen - m_pD3DFSC->SetD3DFullscreen(false); - - // Assign the windowed video frame and pass it to the relevant classes. - m_pVideoWnd = &m_wndView; - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - - if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { - SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift - } - - // Destroy the D3D Fullscreen window and zoom the windowed video frame - m_pDedicatedFSVideoWnd->DestroyWindow(); - if (m_bNeedZoomAfterFullscreenExit) { - if (s.fRememberZoomLevel) { - ZoomVideoWindow(); - } - m_bNeedZoomAfterFullscreenExit = false; - } - - if (s.fShowOSD) { - m_OSD.Start(m_pOSDWnd); - } - MoveVideoWindow(); - RecalcLayout(); - } else { - // Set the fullscreen display mode - if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo) { - AutoChangeMonitorMode(); - } - - // Create a new D3D Fullscreen window - CreateFullScreenWindow(); - - m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN_D3D); - - // Assign the windowed video frame and pass it to the relevant classes. - m_pVideoWnd = m_pDedicatedFSVideoWnd; - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - m_wndView.Invalidate(); - - MoveVideoWindow(); - - // Turn on D3D Fullscreen - m_pD3DFSC->SetD3DFullscreen(true); - - if (s.fShowOSD || s.fShowDebugInfo) { - if (m_pVMB || m_pMFVMB) { - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); - } - } - - m_eventc.FireEvent(MpcEvent::SWITCHED_TO_FULLSCREEN_D3D); - } - } else { - ASSERT(false); - } -} - -bool CMainFrame::GetCurDispMode(const CString& displayName, DisplayMode& dm) -{ - return GetDispMode(displayName, ENUM_CURRENT_SETTINGS, dm); -} - -bool CMainFrame::GetDispMode(CString displayName, int i, DisplayMode& dm) -{ - if (displayName == _T("Current") || displayName.IsEmpty()) { - CMonitor monitor = CMonitors::GetNearestMonitor(AfxGetApp()->m_pMainWnd); - monitor.GetName(displayName); - } - - DEVMODE devmode; - devmode.dmSize = sizeof(DEVMODE); - devmode.dmDriverExtra = 0; - - dm.bValid = !!EnumDisplaySettingsExW(displayName, i, &devmode, EDS_RAWMODE); - - if (dm.bValid) { - dm.size = CSize(devmode.dmPelsWidth, devmode.dmPelsHeight); - dm.bpp = devmode.dmBitsPerPel; - dm.freq = devmode.dmDisplayFrequency; - dm.dwDisplayFlags = devmode.dmDisplayFlags; - } - - return dm.bValid; -} - -void CMainFrame::SetDispMode(CString displayName, const DisplayMode& dm, int msAudioDelay) -{ - DisplayMode dmCurrent; - if (!GetCurDispMode(displayName, dmCurrent)) { - return; - } - - CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); - if (dm.size == dmCurrent.size && dm.bpp == dmCurrent.bpp && dm.freq == dmCurrent.freq) { - if (pASF) { - pASF->SetAudioTimeShift(msAudioDelay * 10000i64); - } - return; - } - - DEVMODE dmScreenSettings; - ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings)); - dmScreenSettings.dmSize = sizeof(dmScreenSettings); - dmScreenSettings.dmPelsWidth = dm.size.cx; - dmScreenSettings.dmPelsHeight = dm.size.cy; - dmScreenSettings.dmBitsPerPel = dm.bpp; - dmScreenSettings.dmDisplayFrequency = dm.freq; - dmScreenSettings.dmDisplayFlags = dm.dwDisplayFlags; - dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; - - if (displayName == _T("Current") || displayName.IsEmpty()) { - CMonitor monitor = CMonitors::GetNearestMonitor(AfxGetApp()->m_pMainWnd); - monitor.GetName(displayName); - } - - const auto& s = AfxGetAppSettings(); - LONG ret; - - m_eventc.FireEvent(MpcEvent::DISPLAY_MODE_AUTOCHANGING); - if (AfxGetAppSettings().autoChangeFSMode.bRestoreResAfterProgExit) { - ret = ChangeDisplaySettingsExW(displayName, &dmScreenSettings, nullptr, CDS_FULLSCREEN, nullptr); - } else { - ret = ChangeDisplaySettingsExW(displayName, &dmScreenSettings, nullptr, 0, nullptr); - } - m_eventc.FireEvent(MpcEvent::DISPLAY_MODE_AUTOCHANGED); - - msAudioDelay = ret == DISP_CHANGE_SUCCESSFUL ? msAudioDelay : (s.fAudioTimeShift ? s.iAudioTimeShift : 0); - if (pASF) { - pASF->SetAudioTimeShift(msAudioDelay * 10000i64); - } -} - -void CMainFrame::AutoChangeMonitorMode() -{ - const CAppSettings& s = AfxGetAppSettings(); - if (s.autoChangeFSMode.modes.empty()) { - return; - } - - double dMediaFPS = 0.0; - - if (GetPlaybackMode() == PM_FILE) { - REFERENCE_TIME m_rtTimePerFrame = 1; - // if ExtractAvgTimePerFrame isn't executed then MediaFPS=10000000.0, - // (int)(MediaFPS + 0.5)=10000000 and SetDispMode is executed to Default. - BeginEnumFilters(m_pGB, pEF, pBF) { - BeginEnumPins(pBF, pEP, pPin) { - CMediaTypeEx mt; - PIN_DIRECTION dir; - if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_OUTPUT && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame)) { - if (m_rtTimePerFrame == 0) { - m_rtTimePerFrame = 1; - } - } - } - } - EndEnumPins; - } - EndEnumFilters; - dMediaFPS = 10000000.0 / m_rtTimePerFrame; - } else if (GetPlaybackMode() == PM_DVD) { - DVD_PLAYBACK_LOCATION2 Location; - if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) { - dMediaFPS = 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; - } - } - - for (const auto& mode : s.autoChangeFSMode.modes) { - if (mode.bChecked && dMediaFPS >= mode.dFrameRateStart && dMediaFPS <= mode.dFrameRateStop) { - SetDispMode(s.strFullScreenMonitorID, mode.dm, mode.msAudioDelay); - return; - } - } - SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift -} - -void CMainFrame::MoveVideoWindow(bool fShowStats/* = false*/, bool bSetStoppedVideoRect/* = false*/) -{ - m_dLastVideoScaleFactor = 0; - m_lastVideoSize.SetSize(0, 0); - - if (!m_bDelaySetOutputRect && GetLoadState() == MLS::LOADED && !m_fAudioOnly && IsWindowVisible()) { - CRect windowRect(0, 0, 0, 0); - CRect videoRect(0, 0, 0, 0); - - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->GetClientRect(windowRect); - } else { - m_wndView.GetClientRect(windowRect); - } - - const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); - const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); - if (bPanelsOnVideo) { - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetVisibleDockZones(uTop, uLeft, uRight, uBottom); - if (!bToolbarsOnVideo) { - uBottom -= m_controls.GetVisibleToolbarsHeight(); - } - windowRect.InflateRect(uLeft, uTop, uRight, uBottom); - } else if (bToolbarsOnVideo) { - windowRect.bottom += m_controls.GetVisibleToolbarsHeight(); - } - - int nCompensateForMenubar = m_bShowingFloatingMenubar && !IsD3DFullScreenMode() ? GetSystemMetrics(SM_CYMENU) : 0; - windowRect.bottom += nCompensateForMenubar; - - OAFilterState fs = GetMediaState(); - if (fs != State_Stopped || bSetStoppedVideoRect || m_fShockwaveGraph) { - const CSize szVideo = GetVideoSize(); - - m_dLastVideoScaleFactor = std::min((double)windowRect.Size().cx / szVideo.cx, - (double)windowRect.Size().cy / szVideo.cy); - m_lastVideoSize = szVideo; - - const double dVideoAR = double(szVideo.cx) / szVideo.cy; - - // because we don't have a way to get .swf size reliably, - // other modes don't make sense - const dvstype iDefaultVideoSize = m_fShockwaveGraph ? DVS_STRETCH : - static_cast(AfxGetAppSettings().iDefaultVideoSize); - - const double dWRWidth = windowRect.Width(); - const double dWRHeight = windowRect.Height(); - - double dVRWidth = dWRHeight * dVideoAR; - double dVRHeight; - - double madVRZoomFactor = 1.0; - - switch (iDefaultVideoSize) { - case DVS_HALF: - dVRWidth = szVideo.cx * 0.5; - dVRHeight = szVideo.cy * 0.5; - break; - case DVS_NORMAL: - dVRWidth = szVideo.cx; - dVRHeight = szVideo.cy; - break; - case DVS_DOUBLE: - dVRWidth = szVideo.cx * 2.0; - dVRHeight = szVideo.cy * 2.0; - break; - case DVS_STRETCH: - dVRWidth = dWRWidth; - dVRHeight = dWRHeight; - break; - default: - ASSERT(FALSE); - [[fallthrough]]; // Fallback to "Touch Window From Inside" if settings were corrupted. - case DVS_FROMINSIDE: - if (dWRWidth < dVRWidth) { - dVRWidth = dWRWidth; - dVRHeight = dVRWidth / dVideoAR; - } else { - dVRHeight = dWRHeight; - } - break; - case DVS_FROMOUTSIDE: - if (dWRWidth > dVRWidth) { - dVRWidth = dWRWidth; - dVRHeight = dVRWidth / dVideoAR; - } else { - dVRHeight = dWRHeight; - } - break; - case DVS_ZOOM1: - case DVS_ZOOM2: { - double scale = iDefaultVideoSize == DVS_ZOOM1 ? 1.0 / 3.0 : 2.0 / 3.0; - double minw = std::min(dWRWidth, dVRWidth); - double zoomValue = (std::max(dWRWidth, dVRWidth) - minw) * scale; - madVRZoomFactor = (minw + zoomValue) / minw; - dVRWidth = minw + zoomValue; - dVRHeight = dVRWidth / dVideoAR; - break; - } - } - - // Scale video frame - double dScaledVRWidth = m_ZoomX * dVRWidth; - double dScaledVRHeight = m_ZoomY * dVRHeight; - - auto vertAlign = AfxGetAppSettings().iVerticalAlignVideo; - double vertAlignOffset = 0; - if (vertAlign == CAppSettings::verticalAlignVideoType::ALIGN_TOP) { - vertAlignOffset = -(dWRHeight - dScaledVRHeight) / 2; - } else if (vertAlign == CAppSettings::verticalAlignVideoType::ALIGN_BOTTOM) { - vertAlignOffset = (dWRHeight - dScaledVRHeight) / 2; - } - - // Position video frame - // left and top parts are allowed to be negative - videoRect.left = lround(m_PosX * (dWRWidth * 3.0 - dScaledVRWidth) - dWRWidth); - videoRect.top = lround(m_PosY * (dWRHeight * 3.0 - dScaledVRHeight) - dWRHeight + vertAlignOffset); - // right and bottom parts are always at picture center or beyond, so never negative - videoRect.right = lround(videoRect.left + dScaledVRWidth); - videoRect.bottom = lround(videoRect.top + dScaledVRHeight); - - ASSERT(videoRect.Width() == lround(dScaledVRWidth)); - ASSERT(videoRect.Height() == lround(dScaledVRHeight)); - - if (m_pMVRC) { - static constexpr const LPCWSTR madVRModesMap[] = { - L"50%", - L"100%", - L"200%", - L"stretch", - L"touchInside", - L"touchOutside", - L"touchInside", - L"touchInside" - }; - - // workaround for rotated video with MadVR - bool swapxy = ((m_iDefRotation + m_AngleZ) / 90) & 1; - double mvr_ZoomX = swapxy ? m_ZoomY : m_ZoomX; - double mvr_ZoomY = swapxy ? m_ZoomX : m_ZoomY; - double mvr_PosX = swapxy ? m_PosY : m_PosX; - double mvr_PosY = swapxy ? m_PosX : m_PosY; - - m_pMVRC->SendCommandString("setZoomMode", const_cast(madVRModesMap[iDefaultVideoSize])); - m_pMVRC->SendCommandDouble("setZoomFactorX", madVRZoomFactor * mvr_ZoomX); - m_pMVRC->SendCommandDouble("setZoomFactorY", madVRZoomFactor * mvr_ZoomY); - m_pMVRC->SendCommandDouble("setZoomOffsetX", 2 * mvr_PosX - 1.0); - m_pMVRC->SendCommandDouble("setZoomOffsetY", 2 * mvr_PosY - 1.0); - } - - if (fShowStats) { - CString info; - info.Format(_T("Pos %.3f %.3f, Zoom %.3f %.3f, AR %.3f"), m_PosX, m_PosY, m_ZoomX, m_ZoomY, double(videoRect.Width()) / videoRect.Height()); - SendStatusMessage(info, 3000); - } - } else if (m_pMVRC) { - m_pMVRC->SendCommandString("setZoomMode", const_cast(L"autoDetect")); - } - - windowRect.top -= nCompensateForMenubar; - windowRect.bottom -= nCompensateForMenubar; - - if (m_pCAP) { - m_pCAP->SetPosition(windowRect, videoRect); - UpdateSubtitleRenderingParameters(); - } else { - if (m_pBV) { - m_pBV->SetDefaultSourcePosition(); - m_pBV->SetDestinationPosition(videoRect.left, videoRect.top, videoRect.Width(), videoRect.Height()); - } - if (m_pVW) { - m_pVW->SetWindowPosition(windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height()); - } - - if (m_pMFVDC) { - m_pMFVDC->SetVideoPosition(nullptr, &windowRect); - } - } - - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->SetVideoRect(&windowRect); - } else { - m_wndView.SetVideoRect(&windowRect); - } - } else { - m_wndView.SetVideoRect(); - } -} - -void CMainFrame::SetPreviewVideoPosition() { - if (m_bUseSeekPreview) { - CPoint point; - GetCursorPos(&point); - m_wndSeekBar.ScreenToClient(&point); - m_wndSeekBar.UpdateToolTipPosition(point); - - CRect wr; - m_wndPreView.GetVideoRect(&wr); - - const CSize ws(wr.Size()); - int w = ws.cx; - int h = ws.cy; - - const CSize arxy(GetVideoSizeWithRotation()); - { - const int dh = ws.cy; - const int dw = MulDiv(dh, arxy.cx, arxy.cy); - - int minw = dw; - int maxw = dw; - if (ws.cx < dw) { - minw = ws.cx; - } else if (ws.cx > dw) { - maxw = ws.cx; - } - - const float scale = 1 / 3.0f; - w = int(minw + (maxw - minw) * scale); - h = MulDiv(w, arxy.cy, arxy.cx); - } - - const CPoint pos(int(m_PosX * (wr.Width() * 3 - w) - wr.Width()), int(m_PosY * (wr.Height() * 3 - h) - wr.Height())); - const CRect vr(pos, CSize(w, h)); - - if (m_pMFVDC_preview) { - m_pMFVDC_preview->SetVideoPosition(nullptr, wr); - m_pMFVDC_preview->SetAspectRatioMode(MFVideoARMode_PreservePicture); - } - if (m_pVMR9C_preview) { - m_pVMR9C_preview->SetVideoPosition(nullptr, wr); - m_pVMR9C_preview->SetAspectRatioMode(VMR9ARMode_LetterBox); - } - if (m_pCAP2_preview) { - m_pCAP2_preview->SetPosition(wr, wr); - } - - if (m_pBV_preview) { - m_pBV_preview->SetDefaultSourcePosition(); - m_pBV_preview->SetDestinationPosition(vr.left, vr.top, vr.Width(), vr.Height()); - } - if (m_pVW_preview) { - m_pVW_preview->SetWindowPosition(wr.left, wr.top, wr.Width(), wr.Height()); - } - } -} - -void CMainFrame::HideVideoWindow(bool fHide) -{ - CRect wr; - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->GetClientRect(&wr); - } else if (!m_fFullScreen) { - m_wndView.GetClientRect(&wr); - } else { - GetWindowRect(&wr); - - // this code is needed to work in fullscreen on secondary monitor - CRect r; - m_wndView.GetWindowRect(&r); - wr -= r.TopLeft(); - } - - if (m_pCAP) { - if (fHide) { - CRect vr = CRect(0, 0, 0, 0); - m_pCAP->SetPosition(vr, vr); // hide - } else { - m_pCAP->SetPosition(wr, wr); // show - } - } - m_bLockedZoomVideoWindow = fHide; -} - -CSize CMainFrame::GetVideoOrArtSize(MINMAXINFO& mmi) -{ - const auto& s = AfxGetAppSettings(); - CSize videoSize; - OnGetMinMaxInfo(&mmi); - - if (m_fAudioOnly) { - videoSize = m_wndView.GetLogoSize(); - - if (videoSize.cx > videoSize.cy) { - if (videoSize.cx > s.nCoverArtSizeLimit) { - videoSize.cy = MulDiv(videoSize.cy, s.nCoverArtSizeLimit, videoSize.cx); - videoSize.cx = s.nCoverArtSizeLimit; - } - } else { - if (videoSize.cy > s.nCoverArtSizeLimit) { - videoSize.cx = MulDiv(videoSize.cx, s.nCoverArtSizeLimit, videoSize.cy); - videoSize.cy = s.nCoverArtSizeLimit; - } - } - } else { - videoSize = GetVideoSize(); - } - return videoSize; -} - -CSize CMainFrame::GetZoomWindowSize(double dScale, bool ignore_video_size) -{ - CSize ret; - - if (dScale >= 0.0 && GetLoadState() == MLS::LOADED) { - const auto& s = AfxGetAppSettings(); - MINMAXINFO mmi; - CSize videoSize = GetVideoOrArtSize(mmi); - - if (ignore_video_size || videoSize.cx <= 1 || videoSize.cy <= 1) { - videoSize.SetSize(0, 0); - } - if (videoSize.cx == 0 || m_fAudioOnly && videoSize.cy < 300) { - CRect windowRect; - GetWindowRect(windowRect); - if (windowRect.Height() < 420 && windowRect.Width() < 3800) { - // keep existing width, since it probably was intentionally made wider by user - mmi.ptMinTrackSize.x = std::max(windowRect.Width(), mmi.ptMinTrackSize.x); - if (m_fAudioOnly) { - // also keep existing height - videoSize.SetSize(0, 0); - mmi.ptMinTrackSize.y = std::max(windowRect.Height(), mmi.ptMinTrackSize.y); - } - } - - } - - CSize videoTargetSize = videoSize; - - CSize controlsSize; - const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); - const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); - if (!bPanelsOnVideo) { - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); - if (bToolbarsOnVideo) { - uBottom -= m_controls.GetToolbarsHeight(); - } - controlsSize.cx = uLeft + uRight; - controlsSize.cy = uTop + uBottom; - } else if (!bToolbarsOnVideo) { - controlsSize.cy = m_controls.GetToolbarsHeight(); - } - - CRect decorationsRect; - VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU, - GetWindowExStyle(m_hWnd))); - - CRect workRect; - CMonitors::GetNearestMonitor(this).GetWorkAreaRect(workRect); - - if (workRect.Width() && workRect.Height()) { - // account for invisible borders on Windows 10 by allowing - // the window to go out of screen a bit - if (IsWindows10OrGreater()) { - workRect.InflateRect(GetInvisibleBorderSize()); - } - - if (videoSize.cx > 0) { - // don't go larger than the current monitor working area and prevent black bars in this case - CSize videoSpaceSize = workRect.Size() - controlsSize - decorationsRect.Size(); - - // Do not adjust window size for video frame aspect ratio when video size is independent from window size - const bool bAdjustWindowAR = !(s.iDefaultVideoSize == DVS_HALF || s.iDefaultVideoSize == DVS_NORMAL || s.iDefaultVideoSize == DVS_DOUBLE); - const double videoAR = videoSize.cx / (double)videoSize.cy; - - videoTargetSize = CSize(int(videoSize.cx * dScale + 0.5), int(videoSize.cy * dScale + 0.5)); - - if (videoTargetSize.cx > videoSpaceSize.cx) { - videoTargetSize.cx = videoSpaceSize.cx; - if (bAdjustWindowAR) { - videoTargetSize.cy = std::lround(videoSpaceSize.cx / videoAR); - } - } - - if (videoTargetSize.cy > videoSpaceSize.cy) { - videoTargetSize.cy = videoSpaceSize.cy; - if (bAdjustWindowAR) { - videoTargetSize.cx = std::lround(videoSpaceSize.cy * videoAR); - } - } - } - } else { - ASSERT(FALSE); - } - - ret = videoTargetSize + controlsSize + decorationsRect.Size(); - ret.cx = std::max(ret.cx, mmi.ptMinTrackSize.x); - ret.cy = std::max(ret.cy, mmi.ptMinTrackSize.y); - } else { - ASSERT(FALSE); - } - - return ret; -} - -bool CMainFrame::GetWorkAreaRect(CRect& work) { - MONITORINFO mi = { sizeof(mi) }; - if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { - work = mi.rcWork; - // account for invisible borders on Windows 10 by allowing - // the window to go out of screen a bit - if (IsWindows10OrGreater()) { - work.InflateRect(GetInvisibleBorderSize()); - } - return true; - } - return false; -} - -CRect CMainFrame::GetZoomWindowRect(const CSize& size, bool ignoreSavedPosition /*= false*/) -{ - const auto& s = AfxGetAppSettings(); - CRect ret; - GetWindowRect(ret); - - CRect rcWork; - if (GetWorkAreaRect(rcWork)) { - CSize windowSize(size); - - // don't go larger than the current monitor working area - windowSize.cx = std::min(windowSize.cx, rcWork.Width()); - windowSize.cy = std::min(windowSize.cy, rcWork.Height()); - - // retain snapping or try not to be move the center of the window - // if we don't remember its position - if (m_bWasSnapped && ret.left == rcWork.left) { - // do nothing - } else if (m_bWasSnapped && ret.right == rcWork.right) { - ret.left = ret.right - windowSize.cx; - } else if (!s.fRememberWindowPos || ignoreSavedPosition) { - ret.left += (ret.right - ret.left) / 2 - windowSize.cx / 2; - } - if (m_bWasSnapped && ret.top == rcWork.top) { - // do nothing - } else if (m_bWasSnapped && ret.bottom == rcWork.bottom) { - ret.top = ret.bottom - windowSize.cy; - } else if (!s.fRememberWindowPos || ignoreSavedPosition) { - ret.top += (ret.bottom - ret.top) / 2 - windowSize.cy / 2; - } - - ret.right = ret.left + windowSize.cx; - ret.bottom = ret.top + windowSize.cy; - - // don't go beyond the current monitor working area - if (ret.right > rcWork.right) { - ret.OffsetRect(rcWork.right - ret.right, 0); - } - if (ret.left < rcWork.left) { - ret.OffsetRect(rcWork.left - ret.left, 0); - } - if (ret.bottom > rcWork.bottom) { - ret.OffsetRect(0, rcWork.bottom - ret.bottom); - } - if (ret.top < rcWork.top) { - ret.OffsetRect(0, rcWork.top - ret.top); - } - } else { - ASSERT(FALSE); - } - - return ret; -} - -void CMainFrame::ZoomVideoWindow(double dScale/* = ZOOM_DEFAULT_LEVEL*/, bool ignore_video_size /*= false*/) -{ - const auto& s = AfxGetAppSettings(); - - if ((GetLoadState() != MLS::LOADED) || - (m_nLockedZoomVideoWindow > 0) || m_bLockedZoomVideoWindow) { - if (m_nLockedZoomVideoWindow > 0) { - m_nLockedZoomVideoWindow--; - } - return; - } - - // Leave fullscreen when changing the zoom level - if (IsFullScreenMode()) { - OnViewFullscreen(); - } - - if (!s.HasFixedWindowSize()) { - ShowWindow(SW_SHOWNOACTIVATE); - if (dScale == (double)ZOOM_DEFAULT_LEVEL) { - if (s.fRememberWindowSize) { - return; // ignore default auto-zoom setting - } - dScale = - s.iZoomLevel == -1 ? 0.25 : - s.iZoomLevel == 0 ? 0.5 : - s.iZoomLevel == 1 ? 1.0 : - s.iZoomLevel == 2 ? 2.0 : - s.iZoomLevel == 3 ? GetZoomAutoFitScale() : -// s.iZoomLevel == 4 ? GetZoomAutoFitScale(true) : - 1.0; - } else if (dScale == (double)ZOOM_AUTOFIT) { - dScale = GetZoomAutoFitScale(); - } else if (dScale <= 0.0) { - ASSERT(FALSE); - return; - } - MoveWindow(GetZoomWindowRect(GetZoomWindowSize(dScale, ignore_video_size), !s.fRememberWindowPos)); - } -} - -double CMainFrame::GetZoomAutoFitScale() -{ - if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { - return 1.0; - } - - const CAppSettings& s = AfxGetAppSettings(); - - CSize arxy = GetVideoSize(); - - // get the work area - MONITORINFO mi; - mi.cbSize = sizeof(MONITORINFO); - HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); - GetMonitorInfo(hMonitor, &mi); - RECT& wa = mi.rcWork; - - DWORD style = GetStyle(); - CSize decorationsSize(0, 0); - - if (style & WS_CAPTION) { - // caption - decorationsSize.cy += GetSystemMetrics(SM_CYCAPTION); - // menu - if (s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) { - decorationsSize.cy += GetSystemMetrics(SM_CYMENU); - } - } - - if (style & WS_THICKFRAME) { - // vertical borders - decorationsSize.cx += 2 * ::GetSystemMetrics(SM_CXSIZEFRAME); - // horizontal borders - decorationsSize.cy += 2 * ::GetSystemMetrics(SM_CYSIZEFRAME); - - // account for invisible borders on Windows 10 - if (IsWindows10OrGreater()) { - RECT invisibleBorders = GetInvisibleBorderSize(); - - decorationsSize.cx -= (invisibleBorders.left + invisibleBorders.right); - decorationsSize.cy -= (invisibleBorders.top + invisibleBorders.bottom); - } - - if (!(style & WS_CAPTION)) { - decorationsSize.cx -= 2; - decorationsSize.cy -= 2; - } - } - - const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); - const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); - if (!bPanelsOnVideo) { - unsigned uTop, uLeft, uRight, uBottom; - m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); - if (bToolbarsOnVideo) { - uBottom -= m_controls.GetVisibleToolbarsHeight(); - } - decorationsSize.cx += uLeft + uRight; - decorationsSize.cy += uTop + uBottom; - } else if (!bToolbarsOnVideo) { - decorationsSize.cy -= m_controls.GetVisibleToolbarsHeight(); - } - - LONG width = wa.right - wa.left; - LONG height = wa.bottom - wa.top; - - double sxMin = ((double)width * s.nAutoFitFactorMin / 100 - decorationsSize.cx) / arxy.cx; - double syMin = ((double)height * s.nAutoFitFactorMin / 100 - decorationsSize.cy) / arxy.cy; - sxMin = std::min(sxMin, syMin); - // Take movie aspect ratio into consideration - // The scaling is computed so that the height is an integer value - syMin = floor(arxy.cy * floor(arxy.cx * sxMin + 0.5) / arxy.cx + 0.5) / arxy.cy; - - double sxMax = ((double)width * s.nAutoFitFactorMax / 100 - decorationsSize.cx) / arxy.cx; - double syMax = ((double)height * s.nAutoFitFactorMax / 100 - decorationsSize.cy) / arxy.cy; - sxMax = std::min(sxMax, syMax); - // Take movie aspect ratio into consideration - // The scaling is computed so that the height is an integer value - syMax = floor(arxy.cy * floor(arxy.cx * sxMax + 0.5) / arxy.cx + 0.5) / arxy.cy; - - - if (syMin < 0.0 || syMax < 0.0) { - ASSERT(FALSE); - syMin = 0.0; - syMax = 0.0; - } - - if (syMin > 1.0) { - return syMin; - } - if (syMax < 1.0) { - return syMax; - } - return 1.0; - -} - -void CMainFrame::RepaintVideo(const bool bForceRepaint/* = false*/) -{ - if (!m_bDelaySetOutputRect && (m_pCAP || m_pMFVDC)) { - OAFilterState fs = GetMediaState(); - if (fs == State_Paused || fs == State_Stopped || bForceRepaint || (m_bDVDStillOn && GetPlaybackMode() == PM_DVD)) { - if (m_pCAP) { - m_pCAP->Paint(false); - } else if (m_pMFVDC) { - m_pMFVDC->RepaintVideo(); - } - } - } -} - -ShaderC* CMainFrame::GetShader(CString path, bool bD3D11) -{ - ShaderC* pShader = nullptr; - - CString shadersDir = ShaderList::GetShadersDir(); - CString shadersDir11 = ShaderList::GetShadersDir11(); - CString tPath = path; - tPath.Replace(shadersDir, shadersDir11); - - //if the shader exists in the Shaders11 folder, use that one - if (bD3D11 && ::PathFileExistsW(tPath)) { - path = tPath; - } - - for (auto& shader : m_ShaderCache) { - if (shader.Match(path, bD3D11)) { - pShader = &shader; - break; - } - } - - if (!pShader) { - if (::PathFileExistsW(path)) { - CStdioFile file; - if (file.Open(path, CFile::modeRead | CFile::shareDenyWrite | CFile::typeText)) { - ShaderC shader; - shader.label = path; - - CString str; - file.ReadString(str); // read first string - if (str.Left(25) == L"// $MinimumShaderProfile:") { - shader.profile = str.Mid(25).Trim(); // shader version property - } else { - file.SeekToBegin(); - } - - if (shader.profile == L"ps_4_0" && !bD3D11 || shader.profile == L"ps_5_0") { - ASSERT(false); - return nullptr; - } else if (bD3D11) { - shader.profile = L"ps_4_0"; - } else if (shader.profile == L"ps_3_sw") { - shader.profile = L"ps_3_0"; - } else if (shader.profile != L"ps_2_0" - && shader.profile != L"ps_2_a" - && shader.profile != L"ps_2_b" - && shader.profile != L"ps_3_0") { - shader.profile = L"ps_3_0"; - } - - while (file.ReadString(str)) { - shader.srcdata += str + L"\n"; - } - - shader.length = file.GetLength(); - - FILETIME ftCreate, ftAccess, ftWrite; - if (GetFileTime(file.m_hFile, &ftCreate, &ftAccess, &ftWrite)) { - shader.ftwrite = ftWrite; - } - - file.Close(); - - m_ShaderCache.push_back(shader); - pShader = &m_ShaderCache.back(); - } - } - } - - return pShader; -} - -bool CMainFrame::SaveShaderFile(ShaderC* shader) -{ - CString path; - if (AfxGetMyApp()->GetAppSavePath(path)) { - path.AppendFormat(L"Shaders\\%s.hlsl", static_cast(shader->label)); - - CStdioFile file; - if (file.Open(path, CFile::modeWrite | CFile::shareExclusive | CFile::typeText)) { - file.SetLength(0); - - CString str; - str.Format(L"// $MinimumShaderProfile: %s\n", static_cast(shader->profile)); - file.WriteString(static_cast(str)); - - file.WriteString(static_cast(shader->srcdata)); - file.Close(); - - // delete out-of-date data from the cache - for (auto it = m_ShaderCache.begin(), end = m_ShaderCache.end(); it != end; ++it) { - if (it->Match(shader->label, false)) { - m_ShaderCache.erase(it); - break; - } - } - - return true; - } - } - return false; -} - -bool CMainFrame::DeleteShaderFile(LPCWSTR label) -{ - CString path; - if (AfxGetMyApp()->GetAppSavePath(path)) { - path.AppendFormat(L"Shaders\\%s.hlsl", label); - - if (!::PathFileExistsW(path) || ::DeleteFileW(path)) { - // if the file is missing or deleted successfully, then remove it from the cache - for (auto it = m_ShaderCache.begin(), end = m_ShaderCache.end(); it != end; ++it) { - if (it->Match(label, false)) { - m_ShaderCache.erase(it); - return true; - } - } - } - } - - return false; -} - -void CMainFrame::TidyShaderCache() -{ - CString appsavepath; - if (!AfxGetMyApp()->GetAppSavePath(appsavepath)) { - return; - } - - for (auto it = m_ShaderCache.cbegin(); it != m_ShaderCache.cend(); ) { - CString path(appsavepath); - path += L"Shaders\\"; - path += (*it).label + L".hlsl"; - - CFile file; - if (file.Open(path, CFile::modeRead | CFile::modeCreate | CFile::shareDenyNone)) { - ULONGLONG length = file.GetLength(); - FILETIME ftCreate = {}, ftAccess = {}, ftWrite = {}; - GetFileTime(file.m_hFile, &ftCreate, &ftAccess, &ftWrite); - - file.Close(); - - if ((*it).length == length && CompareFileTime(&(*it).ftwrite, &ftWrite) == 0) { - it++; - continue; // actual shader - } - } - - m_ShaderCache.erase(it++); // outdated shader - } -} - -void CMainFrame::SetShaders(bool bSetPreResize/* = true*/, bool bSetPostResize/* = true*/) -{ - if (GetLoadState() != MLS::LOADED) { - return; - } - - const auto& s = AfxGetAppSettings(); - bool preFailed = false, postFailed = false; - - if (m_pCAP3) { //interfaces for madVR and MPC-VR - TidyShaderCache(); - const int PShaderMode = m_pCAP3->GetPixelShaderMode(); - if (PShaderMode != 9 && PShaderMode != 11) { - return; - } - - m_pCAP3->ClearPixelShaders(TARGET_FRAME); - m_pCAP3->ClearPixelShaders(TARGET_SCREEN); - int shadercount = 0; - if (bSetPreResize) { - int preTarget; - if (s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { //for now MPC-VR does not support pre-size shaders - preTarget = TARGET_SCREEN; - } else { - preTarget = TARGET_FRAME; - } - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { - ShaderC* pShader = GetShader(shader.filePath, PShaderMode == 11); - if (pShader) { - shadercount++; - CStringW label; - label.Format(L"Shader%d", shadercount); - CStringA profile = pShader->profile; - CStringA srcdata = pShader->srcdata; - if (FAILED(m_pCAP3->AddPixelShader(preTarget, label, profile, srcdata))) { - preFailed = true; - m_pCAP3->ClearPixelShaders(preTarget); - break; - } - } - } - } - if (bSetPostResize) { - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize().ExpandMultiPassShaderList()) { - ShaderC* pShader = GetShader(shader.filePath, PShaderMode == 11); - if (pShader) { - shadercount++; - CStringW label; - label.Format(L"Shader%d", shadercount); - CStringA profile = pShader->profile; - CStringA srcdata = pShader->srcdata; - if (FAILED(m_pCAP3->AddPixelShader(TARGET_SCREEN, label, profile, srcdata))) { - postFailed = true; - m_pCAP3->ClearPixelShaders(TARGET_SCREEN); - break; - } - } - } - } - } else if (m_pCAP2) { - // When pTarget parameter of ISubPicAllocatorPresenter2::SetPixelShader2() is nullptr, - // internal video renderers select maximum available profile and madVR (the only external renderer that - // supports shader part of ISubPicAllocatorPresenter2 interface) seems to ignore it altogether. - m_pCAP2->SetPixelShader2(nullptr, nullptr, false); - if (bSetPreResize) { - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { - if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, false))) { - preFailed = true; - m_pCAP2->SetPixelShader2(nullptr, nullptr, false); - break; - } - } - } - m_pCAP2->SetPixelShader2(nullptr, nullptr, true); - if (bSetPostResize) { - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize().ExpandMultiPassShaderList()) { - if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, true))) { - postFailed = true; - m_pCAP2->SetPixelShader2(nullptr, nullptr, true); - break; - } - } - } - } else if (m_pCAP) { - // shouldn't happen, all known renderers that support ISubPicAllocatorPresenter interface - // support ISubPicAllocatorPresenter2 as well, and it takes priority - ASSERT(FALSE); - m_pCAP->SetPixelShader(nullptr, nullptr); - if (bSetPreResize) { - for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { - if (FAILED(m_pCAP->SetPixelShader(shader.GetCode(), nullptr))) { - preFailed = true; - m_pCAP->SetPixelShader(nullptr, nullptr); - break; - } - } - } - postFailed = !s.m_Shaders.GetCurrentPreset().GetPostResize().empty(); - } - - CString errMsg; - if (preFailed && postFailed) { - VERIFY(errMsg.LoadString(IDS_MAINFRM_BOTH_SHADERS_FAILED)); - } else if (preFailed) { - VERIFY(errMsg.LoadString(IDS_MAINFRM_PRE_SHADERS_FAILED)); - } else if (postFailed) { - VERIFY(errMsg.LoadString(IDS_MAINFRM_POST_SHADERS_FAILED)); - } else { - return; - } - SendStatusMessage(errMsg, 3000); -} - -void CMainFrame::SetBalance(int balance) -{ - int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channel - int balance_dB; - if (balance > -100 && balance < 100) { - balance_dB = sign * (int)(100 * 20 * log10(1 - abs(balance) / 100.0f)); - } else { - balance_dB = sign * (-10000); // -10000: only left, 10000: only right - } - - if (GetLoadState() == MLS::LOADED) { - CString strBalance, strBalanceOSD; - - m_pBA->put_Balance(balance_dB); - - if (balance == 0) { - strBalance.LoadString(IDS_BALANCE); - } else if (balance < 0) { - strBalance.Format(IDS_BALANCE_L, -balance); - } else { //if (m_nBalance > 0) - strBalance.Format(IDS_BALANCE_R, balance); - } - - strBalanceOSD.Format(IDS_BALANCE_OSD, strBalance.GetString()); - m_OSD.DisplayMessage(OSD_TOPLEFT, strBalanceOSD); - } -} - -// -// Open/Close -// - -bool PathIsOnOpticalDisc(CString path) -{ - if (path.GetLength() >= 3 && path[1] == L':' && path[2] == L'\\') { - CString drive = path.Left(3); - UINT type = GetDriveType(drive); - return type == DRIVE_CDROM && !IsDriveVirtual(drive); - } - return false; -} - -// Called from GraphThread -void CMainFrame::OpenCreateGraphObject(OpenMediaData* pOMD) -{ - ASSERT(m_pGB == nullptr); - - m_fCustomGraph = false; - m_fShockwaveGraph = false; - - const CAppSettings& s = AfxGetAppSettings(); - - m_pGB_preview = nullptr; - m_bUseSeekPreview = s.fUseSeekbarHover && s.fSeekPreview && m_wndPreView && ::IsWindow(m_wndPreView.m_hWnd) && !(s.nCLSwitches & CLSW_THUMBNAILS); - if (m_bUseSeekPreview) { -#if 1 - if (auto pOpenDVDData = dynamic_cast(pOMD)) { - // preview does not always work good with DVD even when loaded from hdd - m_bUseSeekPreview = false; - } else -#endif - if (OpenFileData* pFileData = dynamic_cast(pOMD)) { - CString fn = pFileData->fns.GetHead(); - if (fn.IsEmpty()) { - m_bUseSeekPreview = false; - } else { - CString ext = CPath(fn).GetExtension().MakeLower(); - if (((fn.Find(L"://") >= 0) || IsAudioFileExt(ext) || ext == L".avs" || PathIsOnOpticalDisc(fn))) { - // disable seek preview for: streaming data, audio files, files on optical disc - m_bUseSeekPreview = false; - } - } - } - } - - if (auto pOpenFileData = dynamic_cast(pOMD)) { - engine_t engine = s.m_Formats.GetEngine(pOpenFileData->fns.GetHead()); - - HRESULT hr = E_FAIL; - CComPtr pUnk; - - if (engine == ShockWave) { - pUnk = (IUnknown*)(INonDelegatingUnknown*)DEBUG_NEW DSObjects::CShockwaveGraph(m_pVideoWnd->m_hWnd, hr); - if (!pUnk) { - throw (UINT)IDS_AG_OUT_OF_MEMORY; - } - - if (SUCCEEDED(hr)) { - m_pGB = CComQIPtr(pUnk); - } - if (FAILED(hr) || !m_pGB) { - throw (UINT)IDS_MAINFRM_77; - } - m_fShockwaveGraph = true; - } - - m_fCustomGraph = m_fShockwaveGraph; - - if (!m_fCustomGraph) { - CFGManagerPlayer* fgm = DEBUG_NEW CFGManagerPlayer(_T("CFGManagerPlayer"), nullptr, m_pVideoWnd->m_hWnd); - if (!pOpenFileData->useragent.IsEmpty()) { - fgm->SetUserAgent(pOpenFileData->useragent); - } - if (!pOpenFileData->referrer.IsEmpty()) { - fgm->SetReferrer(pOpenFileData->referrer); - } - m_pGB = fgm; - - if (m_pGB && m_bUseSeekPreview) { - // build graph for preview - m_pGB_preview = DEBUG_NEW CFGManagerPlayer(L"CFGManagerPlayer", nullptr, m_wndPreView.GetVideoHWND(), true); - } - } - } else if (auto pOpenDVDData = dynamic_cast(pOMD)) { - m_pGB = DEBUG_NEW CFGManagerDVD(_T("CFGManagerDVD"), nullptr, m_pVideoWnd->m_hWnd); - - if (m_bUseSeekPreview) { - if (!PathIsOnOpticalDisc(pOpenDVDData->path)) { - m_pGB_preview = DEBUG_NEW CFGManagerDVD(L"CFGManagerDVD", nullptr, m_wndPreView.GetVideoHWND(), true); - } - } - } else if (auto pOpenDeviceData = dynamic_cast(pOMD)) { - if (s.iDefaultCaptureDevice == 1) { - m_pGB = DEBUG_NEW CFGManagerBDA(_T("CFGManagerBDA"), nullptr, m_pVideoWnd->m_hWnd); - } else { - m_pGB = DEBUG_NEW CFGManagerCapture(_T("CFGManagerCapture"), nullptr, m_pVideoWnd->m_hWnd); - } - } - - if (!m_pGB) { - throw (UINT)IDS_MAINFRM_80; - } - - if (!m_pGB_preview) { - m_bUseSeekPreview = false; - } - - m_pGB->AddToROT(); - - m_pMC = m_pGB; - m_pME = m_pGB; - m_pMS = m_pGB; // general - m_pVW = m_pGB; - m_pBV = m_pGB; // video - m_pBA = m_pGB; // audio - m_pFS = m_pGB; - - if (m_bUseSeekPreview) { - m_pGB_preview->AddToROT(); - - m_pMC_preview = m_pGB_preview; - //m_pME_preview = m_pGB_preview; - m_pMS_preview = m_pGB_preview; // general - m_pVW_preview = m_pGB_preview; - m_pBV_preview = m_pGB_preview; - //m_pFS_preview = m_pGB_preview; - } - - if (!(m_pMC && m_pME && m_pMS) - || !(m_pVW && m_pBV) - || !(m_pBA)) { - throw (UINT)IDS_GRAPH_INTERFACES_ERROR; - } - - if (FAILED(m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0))) { - throw (UINT)IDS_GRAPH_TARGET_WND_ERROR; - } - - m_pProv = (IUnknown*)DEBUG_NEW CKeyProvider(); - - if (CComQIPtr pObjectWithSite = m_pGB) { - pObjectWithSite->SetSite(m_pProv); - } - - m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); -} - -CWnd* CMainFrame::GetModalParent() -{ - const CAppSettings& s = AfxGetAppSettings(); - CWnd* pParentWnd = this; - if (HasDedicatedFSVideoWindow() && s.m_RenderersSettings.m_AdvRendSets.bVMR9FullscreenGUISupport) { - pParentWnd = m_pDedicatedFSVideoWnd; - } - return pParentWnd; -} - -void CMainFrame::ShowMediaTypesDialog() { - if (!m_fOpeningAborted) { - CAutoLock lck(&lockModalDialog); - CComQIPtr pGBDE = m_pGB; - if (pGBDE && pGBDE->GetCount()) { - mediaTypesErrorDlg = DEBUG_NEW CMediaTypesDlg(pGBDE, GetModalParent()); - mediaTypesErrorDlg->DoModal(); - delete mediaTypesErrorDlg; - mediaTypesErrorDlg = nullptr; - } - } -} - -void CMainFrame::ReleasePreviewGraph() -{ - if (m_pGB_preview) { - m_pCAP2_preview.Release(); - m_pMFVP_preview.Release(); - m_pMFVDC_preview.Release(); - m_pVMR9C_preview.Release(); - - //m_pFS_preview.Release(); - m_pMS_preview.Release(); - m_pBV_preview.Release(); - m_pVW_preview.Release(); - //m_pME_preview.Release(); - m_pMC_preview.Release(); - - if (m_pDVDC_preview) { - m_pDVDC_preview.Release(); - m_pDVDI_preview.Release(); - } - - m_pGB_preview->RemoveFromROT(); - m_pGB_preview.Release(); - } -} - -HRESULT CMainFrame::PreviewWindowHide() { - HRESULT hr = S_OK; - - if (!m_bUseSeekPreview) { - return E_FAIL; - } - - if (m_wndPreView.IsWindowVisible()) { - // Disable animation - ANIMATIONINFO AnimationInfo; - AnimationInfo.cbSize = sizeof(ANIMATIONINFO); - ::SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - int WindowAnimationType = AnimationInfo.iMinAnimate; - AnimationInfo.iMinAnimate = 0; - ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - - m_wndPreView.ShowWindow(SW_HIDE); - - // Enable animation - AnimationInfo.iMinAnimate = WindowAnimationType; - ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); - - if (m_pGB_preview && m_pMC_preview) { - m_pMC_preview->Pause(); - } - } - - return hr; -} - -HRESULT CMainFrame::PreviewWindowShow(REFERENCE_TIME rtCur2) { - if (!CanPreviewUse()) { - return E_FAIL; - } - - HRESULT hr = S_OK; - if (GetPlaybackMode() == PM_DVD && m_pDVDC_preview) { - DVD_PLAYBACK_LOCATION2 Loc, Loc2; - double fps = 0; - - hr = m_pDVDI->GetCurrentLocation(&Loc); - if (FAILED(hr)) { - return hr; - } - - hr = m_pDVDI_preview->GetCurrentLocation(&Loc2); - - fps = Loc.TimeCodeFlags == DVD_TC_FLAG_25fps ? 25.0 - : Loc.TimeCodeFlags == DVD_TC_FLAG_30fps ? 30.0 - : Loc.TimeCodeFlags == DVD_TC_FLAG_DropFrame ? 29.97 - : 25.0; - - DVD_HMSF_TIMECODE dvdTo = RT2HMSF(rtCur2, fps); - - if (FAILED(hr) || (Loc.TitleNum != Loc2.TitleNum)) { - hr = m_pDVDC_preview->PlayTitle(Loc.TitleNum, DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - return hr; - } - m_pDVDC_preview->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (SUCCEEDED(hr)) { - hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - return hr; - } - } else { - hr = m_pDVDC_preview->PlayChapterInTitle(Loc.TitleNum, 1, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - hr = m_pDVDC_preview->PlayAtTimeInTitle(Loc.TitleNum, &dvdTo, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - return hr; - } - } - } - } else { - hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); - if (FAILED(hr)) { - return hr; - } - } - - m_pDVDI_preview->GetCurrentLocation(&Loc2); - - m_pMC_preview->Run(); - Sleep(10); - m_pMC_preview->Pause(); - } else if (GetPlaybackMode() == PM_FILE && m_pMS_preview) { - hr = m_pMS_preview->SetPositions(&rtCur2, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } else { - return E_FAIL; - } - - if (FAILED(hr)) { - return hr; - } - - /* - if (GetPlaybackMode() == PM_FILE) { - hr = pFS2 ? pFS2->Step(2, nullptr) : E_FAIL; - if (SUCCEEDED(hr)) { - Sleep(10); - } - } - */ - - if (!m_wndPreView.IsWindowVisible()) { - m_wndPreView.SetRelativeSize(AfxGetAppSettings().iSeekPreviewSize); - m_wndPreView.ShowWindow(SW_SHOWNOACTIVATE); - m_wndPreView.SetWindowSize(); - } - - return hr; -} - -HRESULT CMainFrame::HandleMultipleEntryRar(CStringW fn) { - CRFSList file_list(true); //true = clears itself on destruction - int num_files, num_ok_files; - - CRARFileSource::ScanArchive(fn.GetBuffer(), &file_list, &num_files, &num_ok_files); - if (num_ok_files > 1) { - RarEntrySelectorDialog entrySelector(&file_list, GetModalParent()); - if (IDOK == entrySelector.DoModal()) { - CStringW entryName = entrySelector.GetCurrentEntry(); - if (entryName.GetLength() > 0) { - CComPtr fgm = static_cast(m_pGB.p); - return fgm->RenderRFSFileEntry(fn, nullptr, entryName); - } - } - return RFS_E_ABORT; //we found multiple entries but no entry selected. - } - return E_NOTIMPL; //not a multi-entry rar -} - -// Called from GraphThread -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; - } - if (bMainFile) { - // store info, this is used for skipping to next/previous file - pOFD->title = fn; - lastOpenFile = fn; - } - - CString ext = GetFileExt(fn); - if (ext == ".mpls") { - CString fnn = PathUtils::StripPathOrUrl(fn); - CString tempath(fn); - tempath.Replace(fnn, _T("")); - tempath.Replace(_T("BDMV\\PLAYLIST\\"), _T("")); - CHdmvClipInfo clipinfo; - m_bHasBDMeta = clipinfo.ReadMeta(tempath, m_BDMeta); - } - - HRESULT hr; - HRESULT rarHR = E_NOTIMPL; -#if INTERNAL_SOURCEFILTER_RFS - if (s.SrcFilters[SRC_RFS] && !PathUtils::IsURL(fn)) { - CString ext = CPath(fn).GetExtension().MakeLower(); - if (ext == L".rar") { - rarHR = HandleMultipleEntryRar(fn); - } - } -#endif - - if (E_NOTIMPL == rarHR) { - hr = m_pGB->RenderFile(fn, nullptr); - } else { - hr = rarHR; - } - - if (FAILED(hr)) { - if (bMainFile) { - if (m_pME) { - m_pME->SetNotifyWindow(NULL, 0, 0); - } - - if (s.fReportFailedPins) { - ShowMediaTypesDialog(); - } - - 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; - } - } - - if (bMainFile) { - bool bIsVideo = false; - bool isRFS = false; - CStringW entryRFS; - - // Check for supported interfaces - BeginEnumFilters(m_pGB, pEF, pBF); - bool fsf = false; - CLSID clsid = GetCLSID(pBF); - // IFileSourceFilter - if (!m_pFSF) { - m_pFSF = pBF; - if (m_pFSF) { - fsf = true; - if (!m_pAMNS) { - m_pAMNS = pBF; - } - if (!m_pSplitterSS) { - m_pSplitterSS = pBF; - } - if (m_bUseSeekPreview) { - if (clsid == CLSID_StillVideo || clsid == CLSID_MPCImageSource) { - m_bUseSeekPreview = false; - } else if (clsid == __uuidof(CRARFileSource)) { - WCHAR* pFN = nullptr; - AM_MEDIA_TYPE mt; - if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { - isRFS = true; - entryRFS = pFN; - CoTaskMemFree(pFN); - } - } - } - } - } - // IAMStreamSelect / IDirectVobSub - if (!fsf) { - if (clsid == __uuidof(CAudioSwitcherFilter)) { - m_pAudioSwitcherSS = pBF; - } else { - if (clsid == GUID_LAVSplitter) { - m_pSplitterSS = pBF; - } else { - if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { - m_pDVS = pBF; - m_pDVS2 = pBF; - } else { - if (clsid != CLSID_MPCBEAudioRenderer) { - if (CComQIPtr pTest = pBF) { - if (!m_pOtherSS[0]) { - m_pOtherSS[0] = pBF; - } else if (!m_pOtherSS[1]) { - m_pOtherSS[1] = pBF; - } else { - ASSERT(false); - } - } - } - } - } - } - } - // Others - if (!m_pLN21) { - m_pLN21 = pBF; - } - if (!m_pKFI) { - m_pKFI = pBF; - } - if (!m_pAMOP) { - m_pAMOP = pBF; - } - if (!m_pAMMC[0]) { - m_pAMMC[0] = pBF; - } else if (!m_pAMMC[1]) { - m_pAMMC[1] = pBF; - } - if (m_bUseSeekPreview && !bIsVideo && IsVideoRenderer(pBF)) { - bIsVideo = true; - } - EndEnumFilters; - - ASSERT(m_pFSF); - - if (!bIsVideo) { - m_bUseSeekPreview = false; - } - if (m_bUseSeekPreview && IsImageFile(fn)) { - // don't use preview for images - m_bUseSeekPreview = false; - } - - if (m_bUseSeekPreview) { - HRESULT previewHR; - if (isRFS) { - CComPtr fgm = static_cast(m_pGB_preview.p); - previewHR = fgm->RenderRFSFileEntry(fn, nullptr, entryRFS); - } else { - previewHR = m_pGB_preview->RenderFile(fn, nullptr); - } - - if (FAILED(previewHR)) { - m_bUseSeekPreview = false; - ReleasePreviewGraph(); - } - } - } else { // Audio DUB - // Check for supported interfaces - BeginEnumFilters(m_pGB, pEF, pBF); - CLSID clsid = GetCLSID(pBF); - if (clsid == GUID_LAVSplitter || clsid == GUID_LAVSplitterSource) { - m_pSplitterDubSS = pBF; - if (m_pSplitterSS && m_pSplitterSS == m_pSplitterDubSS) { - m_pSplitterDubSS.Release(); - } - } else if (clsid == __uuidof(CAudioSwitcherFilter)) { - if (!m_pAudioSwitcherSS) { - m_pAudioSwitcherSS = pBF; - } - } - EndEnumFilters; - } - - // We don't keep track of piped inputs since that hardly makes any sense - if (s.fKeepHistory && fn.Find(_T("pipe:")) != 0 && pOFD->bAddToRecent) { - if (bMainFile) { - auto* pMRU = &s.MRU; - RecentFileEntry r; - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - if (pli.m_bYoutubeDL && !pli.m_ydlSourceURL.IsEmpty()) { - pMRU->LoadMediaHistoryEntryFN(pli.m_ydlSourceURL, r); - } else { - pMRU->LoadMediaHistoryEntryFN(fn, r); - if (pli.m_fns.GetCount() > r.fns.GetCount()) { - r.fns.RemoveAll(); - r.fns.AddHeadList(&pli.m_fns); - } - SHAddToRecentDocs(SHARD_PATH, fn); - } - if (pli.m_cue) { - r.cue = pli.m_cue_filename; - } - if (pli.m_subs.GetCount() > r.subs.GetCount()) { - r.subs.RemoveAll(); - r.subs.AddHeadList(&pli.m_subs); - } - - if (pli.m_label.IsEmpty()) { - CString title; - for (const auto& pAMMC : m_pAMMC) { - if (pAMMC) { - CComBSTR bstr; - if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { - title = bstr.m_str; - title.Trim(); - break; - } - } - } - if (title.GetLength() >= 10 && !IsNameSimilar(title, PathUtils::StripPathOrUrl(fn))) { - r.title = title; - } - } else { - if (pli.m_bYoutubeDL || !IsNameSimilar(pli.m_label, PathUtils::StripPathOrUrl(fn))) { - if (!pli.m_bYoutubeDL || fn == pli.m_ydlSourceURL) { - r.title = pli.m_label; - } else { - CString videoName(pli.m_label); - int m = LastIndexOfCString(videoName, _T(" (")); - if (m > 0) { - videoName = pli.m_label.Left(m); - } - r.title = videoName; - } - } - } - } else { - ASSERT(false); - r.fns.AddHead(fn); - } - - pMRU->Add(r, true); - CStringW playListName; - if (s.bRememberExternalPlaylistPos && m_wndPlaylistBar.IsExternalPlayListActive(playListName)) { - s.SavePlayListPosition(playListName, m_wndPlaylistBar.GetSelIdx()); - } - } - else { - CPlaylistItem pli; - if (!m_wndPlaylistBar.GetCur(pli) || !pli.m_bYoutubeDL) { - CRecentFileList* pMRUDub = &s.MRUDub; - pMRUDub->ReadList(); - pMRUDub->Add(fn); - pMRUDub->WriteList(); - } - } - } - - bMainFile = false; - - if (m_fCustomGraph) { - break; - } - } - - if (s.fReportFailedPins) { - ShowMediaTypesDialog(); - } - - SetupChapters(); - - SetPlaybackMode(PM_FILE); -} - -void CMainFrame::SetupExternalChapters() -{ - // .XCHP (eXternal CHaPters) file format: - // - UTF-8 text file. - // - Located in same folder as the audio/video file, and has same base filename. - // - It will override chapter metadata that is embedded in the file. - // - Each line defines a chapter: timecode, optionally followed by a space and chapter title. - // - Timecode must be in this format: HH:MM:SS,ddd - - CString fn = m_wndPlaylistBar.GetCurFileName(true); - if (fn.IsEmpty() || PathUtils::IsURL(fn)) { - return; - } - - CPath cp(fn); - cp.RenameExtension(_T(".xchp")); - if (!cp.FileExists()) { - return; - } - fn = cp.m_strPath; - - CTextFile f(CTextFile::UTF8); - f.SetFallbackEncoding(CTextFile::ANSI); - - CString str; - if (!f.Open(fn) || !f.ReadString(str)) { - return; - } - - f.Seek(0, CFile::SeekPosition::begin); - - while (f.ReadString(str)) { - REFERENCE_TIME rt = 0; - CString name = ""; - - if (str.GetLength() > 11) { - int lHour = 0; - int lMinute = 0; - int lSecond = 0; - int lMillisec = 0; - if (_stscanf_s(str.Left(12), _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { - rt = ((((lHour * 60) + lMinute) * 60 + lSecond) * MILLISECONDS + lMillisec) * (UNITS / MILLISECONDS); - if (str.GetLength() > 12) { - name = str.Mid(12); - name.Trim(); - } - m_pCB->ChapAppend(rt, name); - } else { - break; - } - } else { - break; - } - } - m_pCB->ChapSort(); -} - -void CMainFrame::SetupChapters() -{ - // Release the old chapter bag and create a new one. - // Due to smart pointers the old chapter bag won't - // be deleted until all classes release it. - m_pCB.Release(); - m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); - - SetupExternalChapters(); - if (m_pCB->ChapGetCount() > 0) { - UpdateSeekbarChapterBag(); - return; - } - - // ToDo: add global pointer list for IDSMChapterBag - CInterfaceList pBFs; - BeginEnumFilters(m_pGB, pEF, pBF); - pBFs.AddTail(pBF); - EndEnumFilters; - - POSITION pos; - - pos = pBFs.GetHeadPosition(); - while (pos && !m_pCB->ChapGetCount()) { - IBaseFilter* pBF = pBFs.GetNext(pos); - - CComQIPtr pCB = pBF; - if (!pCB) { - continue; - } - - for (DWORD i = 0, cnt = pCB->ChapGetCount(); i < cnt; i++) { - REFERENCE_TIME rt; - CComBSTR name; - if (SUCCEEDED(pCB->ChapGet(i, &rt, &name))) { - m_pCB->ChapAppend(rt, name); - } - } - } - - pos = pBFs.GetHeadPosition(); - while (pos && !m_pCB->ChapGetCount()) { - IBaseFilter* pBF = pBFs.GetNext(pos); - - CComQIPtr pCI = pBF; - if (!pCI) { - continue; - } - - CHAR iso6391[3]; - ::GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, iso6391, 3); - CStringA iso6392 = ISOLang::ISO6391To6392(iso6391); - if (iso6392.GetLength() < 3) { - iso6392 = "eng"; - } - - UINT cnt = pCI->GetChapterCount(CHAPTER_ROOT_ID); - for (UINT i = 1; i <= cnt; i++) { - UINT cid = pCI->GetChapterId(CHAPTER_ROOT_ID, i); - - ChapterElement ce; - if (pCI->GetChapterInfo(cid, &ce)) { - char pl[3] = {iso6392[0], iso6392[1], iso6392[2]}; - char cc[] = " "; - CComBSTR name; - name.Attach(pCI->GetChapterStringInfo(cid, pl, cc)); - m_pCB->ChapAppend(ce.rtStart, name); - } - } - } - - pos = pBFs.GetHeadPosition(); - while (pos && !m_pCB->ChapGetCount()) { - IBaseFilter* pBF = pBFs.GetNext(pos); - - CComQIPtr pES = pBF; - if (!pES) { - continue; - } - - long MarkerCount = 0; - if (SUCCEEDED(pES->get_MarkerCount(&MarkerCount))) { - for (long i = 1; i <= MarkerCount; i++) { - double MarkerTime = 0; - if (SUCCEEDED(pES->GetMarkerTime(i, &MarkerTime))) { - CStringW name; - name.Format(IDS_AG_CHAPTER, i); - - CComBSTR bstr; - if (S_OK == pES->GetMarkerName(i, &bstr)) { - name = bstr; - } - - m_pCB->ChapAppend(REFERENCE_TIME(MarkerTime * 10000000), name); - } - } - } - } - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_cue) { - SetupCueChapters(pli.m_cue_filename); - } - - UpdateSeekbarChapterBag(); -} - -void CMainFrame::SetupCueChapters(CString fn) { - CString str; - int cue_index(-1); - - CPlaylistItem pli; - if (!m_wndPlaylistBar.GetCur(pli, true)) { - ASSERT(false); - return; - } - - CWebTextFile f(CTextFile::UTF8); - f.SetFallbackEncoding(CTextFile::ANSI); - if (!f.Open(fn) || !f.ReadString(str)) { - return; - } - f.Seek(0, CFile::SeekPosition::begin); - - CString base; - bool isurl = PathUtils::IsURL(fn); - if (isurl) { - int p = fn.Find(_T('?')); - if (p > 0) { - fn = fn.Left(p); - } - p = fn.ReverseFind(_T('/')); - if (p > 0) { - base = fn.Left(p + 1); - } - } - else { - CPath basefilepath(fn); - basefilepath.RemoveFileSpec(); - basefilepath.AddBackslash(); - base = basefilepath.m_strPath; - } - - CString title; - CString performer; - CAtlList trackl; - CueTrackMeta track; - int trackID(0); - - while (f.ReadString(str)) { - str.Trim(); - if (cue_index == -1 && str.Left(5) == _T("TITLE")) { - title = str.Mid(6).Trim(_T("\"")); - } - else if (cue_index == -1 && str.Left(9) == _T("PERFORMER")) { - performer = str.Mid(10).Trim(_T("\"")); - } - else if (str.Left(4) == _T("FILE")) { - if (str.Right(4) == _T("WAVE") || str.Right(3) == _T("MP3") || str.Right(4) == _T("AIFF")) { // We just support audio file. - cue_index++; - } - } - else if (cue_index >= 0) { - if (str.Left(5) == _T("TRACK") && str.Right(5) == _T("AUDIO")) { - CT2CA tmp(str.Mid(6, str.GetLength() - 12)); - const char* tmp2(tmp); - sscanf_s(tmp2, "%d", &trackID); - if (track.trackID != 0) { - trackl.AddTail(track); - track = CueTrackMeta(); - } - track.trackID = trackID; - } - else if (str.Left(5) == _T("TITLE")) { - track.title = str.Mid(6).Trim(_T("\"")); - } - else if (str.Left(9) == _T("PERFORMER")) { - track.performer = str.Mid(10).Trim(_T("\"")); - } - else if (str.Left(5) == _T("INDEX")) { - CT2CA tmp(str.Mid(6)); - const char* tmp2(tmp); - int i1(0), m(0), s(0), ms(0); - sscanf_s(tmp2, "%d %d:%d:%d", &i1, &m, &s, &ms); - if (i1 != 0) track.time = 10000i64 * ((m * 60 + s) * 1000 + ms); - } - } - } - - if (track.trackID != 0) { - trackl.AddTail(track); - } - - if ((cue_index == 0 && trackl.GetCount() == 1) || cue_index > 1) pli.m_cue = false; // avoid unnecessary parsing of cue again later - - if (trackl.GetCount() >= 1) { - POSITION p = trackl.GetHeadPosition(); - bool b(true); - do { - if (p == trackl.GetTailPosition()) b = false; - CueTrackMeta c(trackl.GetNext(p)); - if (cue_index == 0 || (cue_index > 0 && c.trackID == (pli.m_cue_index + 1))) { - CString label; - if (c.trackID != 0 && !c.title.IsEmpty()) { - label = c.title; - if (!c.performer.IsEmpty()) { - label += (_T(" - ") + c.performer); - } - else if (!performer.IsEmpty()) { - label += (_T(" - ") + performer); - } - } - REFERENCE_TIME time(c.time); - if (cue_index > 0) time = 0; // We don't support gap. - m_pCB->ChapAppend(time, label); - } - } while (b); - } -} - -void CMainFrame::SetupDVDChapters() -{ - // Release the old chapter bag and create a new one. - // Due to smart pointers the old chapter bag won't - // be deleted until all classes release it. - m_pCB.Release(); - m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); - - WCHAR buff[MAX_PATH]; - ULONG len, ulNumOfChapters; - DVD_PLAYBACK_LOCATION2 loc; - - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDVDDirectory(buff, _countof(buff), &len)) - && SUCCEEDED(m_pDVDI->GetCurrentLocation(&loc)) - && SUCCEEDED(m_pDVDI->GetNumberOfChapters(loc.TitleNum, &ulNumOfChapters))) { - CString path; - path.Format(L"%s\\video_ts.IFO", buff); - ULONG VTSN, TTN; - - if (CVobFile::GetTitleInfo(path, loc.TitleNum, VTSN, TTN)) { - path.Format(L"%s\\VTS_%02lu_0.IFO", buff, VTSN); - CAtlList files; - - CVobFile vob; - if (vob.Open(path, files, TTN, false)) { - int iChaptersCount = vob.GetChaptersCount(); - if (ulNumOfChapters == (ULONG)iChaptersCount) { - for (int i = 0; i < iChaptersCount; i++) { - REFERENCE_TIME rt = vob.GetChapterOffset(i); - - CStringW str; - str.Format(IDS_AG_CHAPTER, i + 1); - - m_pCB->ChapAppend(rt, str); - } - } else { - // Parser failed! - ASSERT(FALSE); - } - vob.Close(); - } - } - } - - m_pCB->ChapSort(); - - UpdateSeekbarChapterBag(); -} - -// Called from GraphThread -void CMainFrame::OpenDVD(OpenDVDData* pODD) -{ - lastOpenFile.Empty(); - - HRESULT hr = m_pGB->RenderFile(CStringW(pODD->path), nullptr); - - CAppSettings& s = AfxGetAppSettings(); - - if (s.fReportFailedPins) { - ShowMediaTypesDialog(); - } - - if (SUCCEEDED(hr) && m_bUseSeekPreview) { - if (FAILED(hr = m_pGB_preview->RenderFile(pODD->path, nullptr))) { - m_bUseSeekPreview = false; - } - } - - // Check for supported interfaces - BeginEnumFilters(m_pGB, pEF, pBF) - CLSID clsid = GetCLSID(pBF); - // DVD stuff - if (!m_pDVDC) { - m_pDVDC = pBF; - } - if (!m_pDVDI) { - m_pDVDI = pBF; - } - // IAMStreamSelect filters / IDirectVobSub - if (clsid == __uuidof(CAudioSwitcherFilter)) { - m_pAudioSwitcherSS = pBF; - } else { - if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { - m_pDVS = pBF; - m_pDVS2 = pBF; - } else { - if (clsid != CLSID_MPCBEAudioRenderer) { - if (CComQIPtr pTest = pBF) { - if (!m_pOtherSS[0]) { - m_pOtherSS[0] = pBF; - } else if (!m_pOtherSS[1]) { - m_pOtherSS[1] = pBF; - } else { - ASSERT(false); - } - } - } - } - } - // Others - if (!m_pLN21) { - m_pLN21 = pBF; - } - EndEnumFilters; - - ASSERT(m_pDVDC); - ASSERT(m_pDVDI); - - if (m_bUseSeekPreview) { - BeginEnumFilters(m_pGB_preview, pEF, pBF) { - if ((m_pDVDC_preview = pBF) && (m_pDVDI_preview = pBF)) { - break; - } - } - EndEnumFilters; - } - - if (hr == E_INVALIDARG) { - throw (UINT)IDS_MAINFRM_93; - } else if (hr == VFW_E_CANNOT_RENDER) { - throw (UINT)IDS_DVD_NAV_ALL_PINS_ERROR; - } else if (hr == VFW_S_PARTIAL_RENDER) { - throw (UINT)IDS_DVD_NAV_SOME_PINS_ERROR; - } else if (hr == E_NOINTERFACE || !m_pDVDC || !m_pDVDI) { - throw (UINT)IDS_DVD_INTERFACES_ERROR; - } else if (hr == VFW_E_CANNOT_LOAD_SOURCE_FILTER) { - throw (UINT)IDS_MAINFRM_94; - } else if (FAILED(hr)) { - throw (UINT)IDS_AG_FAILED; - } - - WCHAR buff[MAX_PATH]; - ULONG len = 0; - if (SUCCEEDED(hr = m_pDVDI->GetDVDDirectory(buff, _countof(buff), &len))) { - pODD->title = CString(CStringW(buff)).TrimRight(_T("\\")); - } - - if (s.fKeepHistory) { - ULONGLONG llDVDGuid; - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDiscID(nullptr, &llDVDGuid))) { - auto* pMRU = &s.MRU; - pMRU->Add(pODD->title, llDVDGuid); - } - SHAddToRecentDocs(SHARD_PATH, pODD->title); - } - - // TODO: resetdvd - m_pDVDC->SetOption(DVD_ResetOnStop, FALSE); - m_pDVDC->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); - - if (m_bUseSeekPreview && m_pDVDC_preview) { - m_pDVDC_preview->SetOption(DVD_ResetOnStop, FALSE); - m_pDVDC_preview->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); - } - - if (s.idMenuLang) { - m_pDVDC->SelectDefaultMenuLanguage(s.idMenuLang); - } - if (s.idAudioLang) { - m_pDVDC->SelectDefaultAudioLanguage(s.idAudioLang, DVD_AUD_EXT_NotSpecified); - } - if (s.idSubtitlesLang) { - m_pDVDC->SelectDefaultSubpictureLanguage(s.idSubtitlesLang, DVD_SP_EXT_NotSpecified); - } - - m_iDVDDomain = DVD_DOMAIN_Stop; - - SetPlaybackMode(PM_DVD); -} - -// Called from GraphThread -HRESULT CMainFrame::OpenBDAGraph() -{ - lastOpenFile.Empty(); - - HRESULT hr = m_pGB->RenderFile(L"", L""); - if (SUCCEEDED(hr)) { - SetPlaybackMode(PM_DIGITAL_CAPTURE); - m_pDVBState = std::make_unique(); - - // Check for supported interfaces - BeginEnumFilters(m_pGB, pEF, pBF); - bool fsf = false; - CLSID clsid = GetCLSID(pBF); - // IFileSourceFilter - if (!m_pFSF) { - m_pFSF = pBF; - if (m_pFSF) { - fsf = true; - if (!m_pAMNS) { - m_pAMNS = pBF; - } - } - } - // IAMStreamSelect / IDirectVobSub - if (!fsf) { - if (clsid == __uuidof(CAudioSwitcherFilter)) { - m_pAudioSwitcherSS = pBF; - } else { - if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { - m_pDVS = pBF; - m_pDVS2 = pBF; - } - } - } - // Others - if (!m_pLN21) { - m_pLN21 = pBF; - } - if (!m_pAMMC[0]) { - m_pAMMC[0] = pBF; - } else if (!m_pAMMC[1]) { - m_pAMMC[1] = pBF; - } - EndEnumFilters; - - ASSERT(m_pFSF); - - // BDA graph builder implements IAMStreamSelect - m_pSplitterSS = m_pGB; - } - return hr; -} - -// Called from GraphThread -void CMainFrame::OpenCapture(OpenDeviceData* pODD) -{ - lastOpenFile.Empty(); - - m_wndCaptureBar.InitControls(); - - CStringW vidfrname, audfrname; - CComPtr pVidCapTmp, pAudCapTmp; - - m_VidDispName = pODD->DisplayName[0]; - - if (!m_VidDispName.IsEmpty()) { - if (!CreateFilter(m_VidDispName, &pVidCapTmp, vidfrname)) { - throw (UINT)IDS_MAINFRM_96; - } - } - - m_AudDispName = pODD->DisplayName[1]; - - if (!m_AudDispName.IsEmpty()) { - if (!CreateFilter(m_AudDispName, &pAudCapTmp, audfrname)) { - throw (UINT)IDS_MAINFRM_96; - } - } - - if (!pVidCapTmp && !pAudCapTmp) { - throw (UINT)IDS_MAINFRM_98; - } - - m_pCGB = nullptr; - m_pVidCap = nullptr; - m_pAudCap = nullptr; - - if (FAILED(m_pCGB.CoCreateInstance(CLSID_CaptureGraphBuilder2))) { - throw (UINT)IDS_MAINFRM_99; - } - - HRESULT hr; - - m_pCGB->SetFiltergraph(m_pGB); - - if (pVidCapTmp) { - if (FAILED(hr = m_pGB->AddFilter(pVidCapTmp, vidfrname))) { - throw (UINT)IDS_CAPTURE_ERROR_VID_FILTER; - } - - m_pVidCap = pVidCapTmp; - - if (!pAudCapTmp) { - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap))) - && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); - } - - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Interleaved, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev))) - && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); - } - - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pVidCap, IID_PPV_ARGS(&m_pAMASC))) - && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pVidCap, IID_PPV_ARGS(&m_pAMASC)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap")); - } else { - m_pAudCap = m_pVidCap; - } - } else { - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); - } - - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); - } - } - - if (FAILED(m_pCGB->FindInterface(&LOOK_UPSTREAM_ONLY, nullptr, m_pVidCap, IID_PPV_ARGS(&m_pAMXBar)))) { - TRACE(_T("Warning: No IAMCrossbar interface was found\n")); - } - - if (FAILED(m_pCGB->FindInterface(&LOOK_UPSTREAM_ONLY, nullptr, m_pVidCap, IID_PPV_ARGS(&m_pAMTuner)))) { - TRACE(_T("Warning: No IAMTVTuner interface was found\n")); - } - // TODO: init m_pAMXBar - - if (m_pAMTuner) { // load saved channel - m_pAMTuner->put_CountryCode(AfxGetApp()->GetProfileInt(_T("Capture"), _T("Country"), 1)); - - int vchannel = pODD->vchannel; - if (vchannel < 0) { - vchannel = AfxGetApp()->GetProfileInt(_T("Capture\\") + CString(m_VidDispName), _T("Channel"), -1); - } - if (vchannel >= 0) { - OAFilterState fs = State_Stopped; - m_pMC->GetState(0, &fs); - if (fs == State_Running) { - MediaControlPause(true); - } - m_pAMTuner->put_Channel(vchannel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT); - if (fs == State_Running) { - MediaControlRun(); - } - } - } - } - - if (pAudCapTmp) { - if (FAILED(hr = m_pGB->AddFilter(pAudCapTmp, CStringW(audfrname)))) { - throw (UINT)IDS_CAPTURE_ERROR_AUD_FILTER; - } - - m_pAudCap = pAudCapTmp; - - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pAudCap, IID_PPV_ARGS(&m_pAMASC))) - && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pAudCap, IID_PPV_ARGS(&m_pAMASC)))) { - TRACE(_T("Warning: No IAMStreamConfig interface for vidcap")); - } - } - - if (!(m_pVidCap || m_pAudCap)) { - throw (UINT)IDS_MAINFRM_108; - } - - pODD->title.LoadString(IDS_CAPTURE_LIVE); - - SetPlaybackMode(PM_ANALOG_CAPTURE); -} - -// Called from GraphThread -void CMainFrame::OpenCustomizeGraph() -{ - if (GetPlaybackMode() != PM_FILE && GetPlaybackMode() != PM_DVD) { - return; - } - - CleanGraph(); - - if (GetPlaybackMode() == PM_FILE) { - if (m_pCAP && AfxGetAppSettings().IsISRAutoLoadEnabled()) { - AddTextPassThruFilter(); - } - } - - const CAppSettings& s = AfxGetAppSettings(); - const CRenderersSettings& r = s.m_RenderersSettings; - if (r.m_AdvRendSets.bSynchronizeVideo && s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { - HRESULT hr = S_OK; - m_pRefClock = DEBUG_NEW CSyncClockFilter(nullptr, &hr); - - if (SUCCEEDED(hr) && SUCCEEDED(m_pGB->AddFilter(m_pRefClock, L"SyncClock Filter"))) { - CComQIPtr refClock = m_pRefClock; - CComQIPtr mediaFilter = m_pGB; - - if (refClock && mediaFilter) { - VERIFY(SUCCEEDED(mediaFilter->SetSyncSource(refClock))); - mediaFilter = nullptr; - refClock = nullptr; - - VERIFY(SUCCEEDED(m_pRefClock->QueryInterface(IID_PPV_ARGS(&m_pSyncClock)))); - CComQIPtr pAdviser = m_pCAP; - if (pAdviser) { - VERIFY(SUCCEEDED(pAdviser->AdviseSyncClock(m_pSyncClock))); - } - } - } - } - - if (GetPlaybackMode() == PM_DVD) { - if (m_pDVS2) { - if (!m_pSubClock) { - m_pSubClock = DEBUG_NEW CSubClock; - } - m_pDVS2->AdviseSubClock(m_pSubClock); - } - } - - CleanGraph(); -} - -// Called from GraphThread -void CMainFrame::OpenSetupVideo() -{ - m_fAudioOnly = true; - - CSize vs; - - if (m_pMFVDC) { // EVR - m_fAudioOnly = false; - m_pMFVDC->GetNativeVideoSize(&vs, nullptr); - } else if (m_pCAP) { - vs = m_pCAP->GetVideoSize(false); - m_fAudioOnly = (vs.cx <= 0 || vs.cy <= 0); - } else { - if (CComQIPtr pBV = m_pGB) { - pBV->GetVideoSize(&vs.cx, &vs.cy); - - if (vs.cx > 0 && vs.cy > 0) { - m_fAudioOnly = false; - } - } - if (m_fAudioOnly && m_pVW) { - long lVisible; - if (SUCCEEDED(m_pVW->get_Visible(&lVisible))) { - m_pVW->get_Width(&vs.cx); - m_pVW->get_Height(&vs.cy); - if (vs.cx > 0 && vs.cy > 0) { - m_fAudioOnly = false; - } - } - } - } - - if (m_fShockwaveGraph) { - m_fAudioOnly = false; - } - - 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_pVideoWnd->m_hWnd); - - for (CWnd* pWnd = m_pVideoWnd->GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) { - // 1. lets WM_SETCURSOR through (not needed as of now) - // 2. allows CMouse::CursorOnWindow() to work with m_pVideoWnd - pWnd->EnableWindow(FALSE); - } - - if (m_bUseSeekPreview) { - m_pVW_preview->put_Owner((OAHWND)m_wndPreView.GetVideoHWND()); - m_pVW_preview->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); - } - - if (m_fAudioOnly) { - if (HasDedicatedFSVideoWindow() && !AfxGetAppSettings().bFullscreenSeparateControls) { //DedicateFSWindow allowed for audio - m_pDedicatedFSVideoWnd->DestroyWindow(); - } - } else { - m_statusbarVideoSize.Format(_T("%dx%d"), vs.cx, vs.cy); - UpdateDXVAStatus(); - } -} - -// Called from GraphThread -void CMainFrame::OpenSetupAudio() -{ - m_pBA->put_Volume(m_wndToolBar.Volume); - - // FIXME - int balance = AfxGetAppSettings().nBalance; - - int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channel - if (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); -} - -void CMainFrame::OpenSetupCaptureBar() -{ - if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - if (m_pVidCap && m_pAMVSCCap) { - CComQIPtr pVfwCD = m_pVidCap; - - if (!m_pAMXBar && pVfwCD) { - m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, m_pAMVSCCap, pVfwCD); - } else { - m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, m_pAMVSCCap, m_pAMXBar, m_pAMTuner); - } - } - - if (m_pAudCap && m_pAMASC) { - CInterfaceArray pAMAIM; - - BeginEnumPins(m_pAudCap, pEP, pPin) { - if (CComQIPtr pAIM = pPin) { - pAMAIM.Add(pAIM); - } - } - EndEnumPins; - - m_wndCaptureBar.m_capdlg.SetupAudioControls(m_AudDispName, m_pAMASC, pAMAIM); - } - - BuildGraphVideoAudio( - m_wndCaptureBar.m_capdlg.m_fVidPreview, false, - m_wndCaptureBar.m_capdlg.m_fAudPreview, false); - } -} - -void CMainFrame::OpenSetupInfoBar(bool bClear /*= true*/) -{ - bool bRecalcLayout = false; - - if (bClear) { - m_wndInfoBar.RemoveAllLines(); - } - - if (GetPlaybackMode() == PM_FILE) { - CComBSTR bstr; - CString title, author, copyright, rating, description; - if (m_pAMMC[0]) { - for (const auto& pAMMC : m_pAMMC) { - if (pAMMC) { - if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { - title = bstr.m_str; - title.Trim(); - } - bstr.Empty(); - if (SUCCEEDED(pAMMC->get_AuthorName(&bstr)) && bstr.Length()) { - author = bstr.m_str; - } - bstr.Empty(); - if (SUCCEEDED(pAMMC->get_Copyright(&bstr)) && bstr.Length()) { - copyright = bstr.m_str; - } - bstr.Empty(); - if (SUCCEEDED(pAMMC->get_Rating(&bstr)) && bstr.Length()) { - rating = bstr.m_str; - } - bstr.Empty(); - if (SUCCEEDED(pAMMC->get_Description(&bstr)) && bstr.Length()) { - description = bstr.m_str; - } - bstr.Empty(); - } - } - } - - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TITLE), title); - UpdateChapterInInfoBar(); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUTHOR), author); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_COPYRIGHT), copyright); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_RATING), rating); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); - } else if (GetPlaybackMode() == PM_DVD) { - CString info(_T('-')); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), info); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_LOCATION), info); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_VIDEO), info); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUDIO), info); - bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_SUBTITLES), info); - } - - if (bRecalcLayout) { - RecalcLayout(); - } -} - -void CMainFrame::UpdateChapterInInfoBar() -{ - CString chapter; - if (m_pCB) { - DWORD dwChapCount = m_pCB->ChapGetCount(); - if (dwChapCount) { - REFERENCE_TIME rtNow; - m_pMS->GetCurrentPosition(&rtNow); - - if (m_pCB) { - CComBSTR bstr; - long currentChap = m_pCB->ChapLookup(&rtNow, &bstr); - if (bstr.Length()) { - chapter.Format(_T("%s (%ld/%lu)"), bstr.m_str, std::max(0l, currentChap + 1l), dwChapCount); - } else { - chapter.Format(_T("%ld/%lu"), currentChap + 1, dwChapCount); - } - } - } - } - if (m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CHAPTER), chapter)) { - RecalcLayout(); - } -} - -void CMainFrame::OpenSetupStatsBar() -{ - m_wndStatsBar.RemoveAllLines(); - - if (GetLoadState() == MLS::LOADED) { - CString info(_T('-')); - bool bFoundIBitRateInfo = false; - - BeginEnumFilters(m_pGB, pEF, pBF) { - if (!m_pQP) { - m_pQP = pBF; - } - if (!m_pBI) { - m_pBI = pBF; - } - if (!bFoundIBitRateInfo) { - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pBRI = pPin) { - bFoundIBitRateInfo = true; - break; - } - } - EndEnumPins; - } - if (m_pQP && m_pBI && bFoundIBitRateInfo) { - break; - } - } - EndEnumFilters; - - if (m_pQP) { - m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMERATE), info); - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SYNC_OFFSET), info); - m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMES), info); - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_JITTER), info); - } else { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_PLAYBACK_RATE), info); - } - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), info); - } - if (m_pBI) { - m_wndStatsBar.SetLine(StrRes(IDS_AG_BUFFERS), info); - } - if (bFoundIBitRateInfo) { - m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_BITRATE), info); - } - } -} - -void CMainFrame::CheckSelectedAudioStream() -{ - int nChannels = 0; - int audiostreamcount = 0; - UINT audiobitmapid = IDB_AUDIOTYPE_NOAUDIO; - m_loadedAudioTrackIndex = -1; - - if (m_pAudioSwitcherSS) { - DWORD cStreams = 0; - if (SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { - LCID lcid = 0; - DWORD dwFlags, dwGroup; - AM_MEDIA_TYPE* pmt = nullptr; - for (DWORD i = 0; i < cStreams; i++) { - if (SUCCEEDED(m_pAudioSwitcherSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 1) { - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - m_loadedAudioTrackIndex = audiostreamcount; - nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - audiostreamcount++; - } - DeleteMediaType(pmt); - } - } - } - } - if (audiostreamcount == 0 && m_pSplitterSS) { - DWORD cStreams = 0; - if (SUCCEEDED(m_pSplitterSS->Count(&cStreams)) && cStreams > 0) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - for (DWORD i = 0; i < cStreams; i++) { - if (SUCCEEDED(m_pSplitterSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 1) { - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - m_loadedAudioTrackIndex = audiostreamcount; - nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - audiostreamcount++; - } - DeleteMediaType(pmt); - } - } - } - } - if (audiostreamcount == 0 && m_pSplitterDubSS) { - DWORD cStreams = 0; - if (SUCCEEDED(m_pSplitterDubSS->Count(&cStreams)) && cStreams > 0) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - for (DWORD i = 0; i < cStreams; i++) { - if (SUCCEEDED(m_pSplitterDubSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 1) { - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - m_loadedAudioTrackIndex = audiostreamcount; - nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - audiostreamcount++; - } - DeleteMediaType(pmt); - } - } - } - } - if (audiostreamcount == 0 && !m_pAudioSwitcherSS) { // Fallback - BeginEnumFilters(m_pGB, pEF, pBF) { - CComQIPtr pBA = pBF; // implemented by audio renderers - bool notrenderer = false; - - BeginEnumPins(pBF, pEP, pPin) { - if (S_OK == m_pGB->IsPinDirection(pPin, PINDIR_INPUT) && S_OK == m_pGB->IsPinConnected(pPin)) { - AM_MEDIA_TYPE mt; - if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (mt.majortype == MEDIATYPE_Audio) { - notrenderer = !pBA; - audiostreamcount = 1; - nChannels = UpdateSelectedAudioStreamInfo(-1, &mt, -1); - break; - } else if (mt.majortype == MEDIATYPE_Midi) { - notrenderer = true; - audiostreamcount = 1; - nChannels = UpdateSelectedAudioStreamInfo(-1, &mt, -1); - break; - } - } - } - } - EndEnumPins; - - if (nChannels > 0 && notrenderer) { // prefer audio decoder above renderer - break; - } - } - EndEnumFilters; - } - - if (audiostreamcount == 0) { - m_loadedAudioTrackIndex = -1; - UpdateSelectedAudioStreamInfo(-1, nullptr, -1); - } - - if (nChannels >= 2) { - audiobitmapid = IDB_AUDIOTYPE_STEREO; - } else if (nChannels == 1) { - audiobitmapid = IDB_AUDIOTYPE_MONO; - } - m_wndStatusBar.SetStatusBitmap(audiobitmapid); -} - -void CMainFrame::OpenSetupStatusBar() -{ - m_wndStatusBar.ShowTimer(true); - - if (!m_fCustomGraph) { - CString fcc; - // Find video output pin of the source filter or splitter - BeginEnumFilters(m_pGB, pEF, pBF) { - CLSID clsid = GetCLSID(pBF); - bool splitter = (clsid == GUID_LAVSplitterSource || clsid == GUID_LAVSplitter); - // only process filters that might be splitters - if (splitter || clsid != __uuidof(CAudioSwitcherFilter) && clsid != GUID_LAVVideo && clsid != GUID_LAVAudio) { - int input_pins = 0; - BeginEnumPins(pBF, pEP, pPin) { - PIN_DIRECTION dir; - CMediaTypeEx mt; - if (SUCCEEDED(pPin->QueryDirection(&dir)) && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (dir == PINDIR_OUTPUT) { - if (mt.majortype == MEDIATYPE_Video) { - GetVideoFormatNameFromMediaType(mt.subtype, fcc); - if (splitter) { - break; - } - } - } else { - input_pins++; - splitter = (mt.majortype == MEDIATYPE_Stream); - } - } - } - EndEnumPins; - - if ((input_pins == 0 || splitter) && !fcc.IsEmpty()) { - break; - } - } - } - EndEnumFilters; - - if (!fcc.IsEmpty()) { - m_statusbarVideoFormat = fcc; - } - - CheckSelectedAudioStream(); - } -} - -// Called from GraphThread -void CMainFrame::OpenSetupWindowTitle(bool reset /*= false*/) -{ - CString title(StrRes(IDR_MAINFRAME)); -#ifdef MPCHC_LITE - title += _T(" Lite"); -#endif - - CAppSettings& s = AfxGetAppSettings(); - - int i = s.iTitleBarTextStyle; - - if (!reset && (i == 0 || i == 1)) { - // There is no path in capture mode - if (IsPlaybackCaptureMode()) { - title = GetCaptureTitle(); - } else if (i == 1) { // Show filename or title - if (GetPlaybackMode() == PM_FILE) { - title = getBestTitle(s.fTitleBarTextTitle); - bool has_title = !title.IsEmpty(); - - CStringW fn = GetFileName(); - - if (has_title && !IsNameSimilar(title, fn)) s.MRU.SetCurrentTitle(title); - - if (!has_title) { - title = fn; - } - } else if (GetPlaybackMode() == PM_DVD) { - title = _T("DVD"); - CString path; - ULONG len = 0; - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDVDDirectory(path.GetBufferSetLength(MAX_PATH), MAX_PATH, &len)) && len) { - path.ReleaseBuffer(); - if (path.Find(_T("\\VIDEO_TS")) == 2) { - title.AppendFormat(_T(" - %s"), GetDriveLabel(CPath(path)).GetString()); - } - } - } - } else { // Show full path - if (GetPlaybackMode() == PM_FILE) { - title = m_wndPlaylistBar.GetCurFileNameTitle(); - } else if (GetPlaybackMode() == PM_DVD) { - title = _T("DVD"); - ULONG len = 0; - if (m_pDVDI) { - VERIFY(SUCCEEDED(m_pDVDI->GetDVDDirectory(title.GetBufferSetLength(MAX_PATH), MAX_PATH, &len))); - title.ReleaseBuffer(); - } - } - } - } - - SetWindowText(title); - m_Lcd.SetMediaTitle(title); -} - -// Called from GraphThread -int CMainFrame::SetupAudioStreams() -{ - bool bIsSplitter = false; - int desiredTrackIndex = m_loadedAudioTrackIndex; - m_loadedAudioTrackIndex = -1; - m_audioTrackCount = 0; - - CComQIPtr pSS = m_pAudioSwitcherSS; - if (!pSS) { - bIsSplitter = true; - pSS = m_pSplitterSS; - } - - DWORD cStreams = 0; - if (pSS && SUCCEEDED(pSS->Count(&cStreams))) { - if (cStreams > 1) { - const CAppSettings& s = AfxGetAppSettings(); - - CAtlArray langs; - int tPos = 0; - CString lang = s.strAudiosLanguageOrder.Tokenize(_T(",; "), tPos); - while (tPos != -1) { - lang.MakeLower(); - langs.Add(lang); - // Try to match the full language if possible - lang = ISOLang::ISO639XToLanguage(CStringA(lang)); - if (!lang.IsEmpty()) { - langs.Add(lang.MakeLower()); - } - lang = s.strAudiosLanguageOrder.Tokenize(_T(",; "), tPos); - } - - int selected = -1, id = 0; - int maxrating = -1; - for (DWORD i = 0; i < cStreams; i++) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - WCHAR* pName = nullptr; - CComPtr pObject; - if (FAILED(pSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pName, &pObject, nullptr))) { - continue; - } - CString name(pName); - CoTaskMemFree(pName); - - if (dwGroup != 1) { - ASSERT(bIsSplitter); - continue; - } - - m_audioTrackCount++; - - int rating = 0; - // If the track is controlled by a splitter and isn't selected at splitter level - if (!(dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE))) { - bool bSkipTrack; - - // If the splitter is the internal LAV Splitter and no language preferences - // have been set at splitter level, we can override its choice safely - CComQIPtr pBF = bIsSplitter ? pSS : reinterpret_cast(pObject.p); - if (pBF && CFGFilterLAV::IsInternalInstance(pBF)) { - bSkipTrack = false; - if (CComQIPtr pLAVFSettings = pBF) { - LPWSTR langPrefs = nullptr; - if (SUCCEEDED(pLAVFSettings->GetPreferredLanguages(&langPrefs)) && langPrefs && wcslen(langPrefs)) { - bSkipTrack = true; - } - CoTaskMemFree(langPrefs); - } - } else { - bSkipTrack = !s.bAllowOverridingExternalSplitterChoice; - } - - if (bSkipTrack) { - id++; - continue; - } - } else if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - // Give selected track a slightly higher rating - rating += 1; - // Get details of currently selected track - m_loadedAudioTrackIndex = m_audioTrackCount - 1; - UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - - DeleteMediaType(pmt); - - name.Trim(); - name.MakeLower(); - - for (size_t j = 0; j < langs.GetCount(); j++) { - int num = _tstoi(langs[j]) - 1; - if (num >= 0) { // this is track number - if (id != num) { - continue; // not matched - } - } else { // this is lang string - int len = langs[j].GetLength(); - if (name.Left(len) != langs[j] && name.Find(_T("[") + langs[j]) < 0) { - continue; // not matched - } - } - rating += 16 * int(langs.GetCount() - j); - break; - } - if (name.Find(_T("[default,forced]")) != -1) { // for LAV Splitter - rating += 4 + 2; - } - if (name.Find(_T("[forced]")) != -1) { - rating += 4; - } - if (name.Find(_T("[default]")) != -1) { - rating += 2; - } - - if (rating > maxrating) { - maxrating = rating; - selected = id; - } - - id++; - } - - if (desiredTrackIndex >= 0 && desiredTrackIndex < m_audioTrackCount) { - selected = desiredTrackIndex; - } - return m_audioTrackCount > 1 ? selected + !bIsSplitter : -1; - } else if (cStreams == 1) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pSS->Info(0, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { - if (dwGroup == 1 && (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE))) { - m_loadedAudioTrackIndex = 0; - m_audioTrackCount = 1; - UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); - } - DeleteMediaType(pmt); - return -1; // no need to select a specific track - } - } - } - - return -1; -} - -bool MatchSubtrackWithISOLang(CString& tname, const ISOLangT& l) -{ - int p; - - if (!l.iso6392.IsEmpty()) { - p = tname.Find(_T("[") + l.iso6392 + _T("]")); - if (p > 0) { - return true; - } - p = tname.Find(_T(".") + l.iso6392 + _T(".")); - if (p > 0) { - return true; - } - } - - if (!l.iso6391.IsEmpty()) { - p = tname.Find(_T("[") + l.iso6391 + _T("]")); - if (p > 0) { - return true; - } - p = tname.Find(_T(".") + l.iso6391 + _T(".")); - if (p > 0) { - return true; - } - p = tname.Find(_T("[") + l.iso6391 + _T("-]")); // truncated BCP47 - if (p > 0) { - return true; - } - } - - if (!l.name.IsEmpty()) { - if (l.name == _T("off")) { - return tname.Find(_T("no subtitles")) >= 0; - } - - std::list langlist; - int tPos = 0; - CString lang = l.name.Tokenize(_T(";"), tPos); - while (tPos != -1) { - lang.MakeLower().TrimLeft(); - langlist.emplace_back(lang); - lang = l.name.Tokenize(_T(";"), tPos); - } - - for (auto& substr : langlist) { - p = tname.Find(_T("\t") + substr); - if (p > 0) { - return true; - } - p = tname.Find(_T(".") + substr + _T(".")); - if (p > 0) { - return true; - } - p = tname.Find(_T("[") + substr + _T("]")); - if (p > 0) { - return true; - } - p = tname.Find(substr); - if (p == 0 || p == 3 && tname.Left(3) == _T("s: ")) { // at begin of trackname - return true; - } - } - } - - return false; -} - -// Called from GraphThread -int CMainFrame::SetupSubtitleStreams() -{ - const CAppSettings& s = AfxGetAppSettings(); - - int selected = -1; - - if (!m_pSubStreams.IsEmpty()) { - bool is_external = false; - bool externalPriority = false; - bool has_off_lang = false; - std::list> langs; - int tPos = 0; - CString lang = s.strSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); - while (tPos != -1) { - lang.MakeLower(); - ISOLangT l = ISOLangT(lang, L"", L"", 0); - - if (lang == _T("off")) { - has_off_lang = true; - } else if (lang.Find(L'-') == 2) { - // BCP 47 - } else { - l = ISOLang::ISO639XToISOLang(CStringA(lang)); - if (l.name.IsEmpty()) { // not an ISO code - l.name = lang; - } else { - l.name.MakeLower(); - } - } - - langs.emplace_back(l); - - lang = s.strSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); - } - - int i = 0; - int subcount = m_pSubStreams.GetSize(); - int maxrating = 0; - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - if (m_posFirstExtSub == pos) { - is_external = true; - externalPriority = s.fPrioritizeExternalSubtitles; - } - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - CComPtr pSubStream = subInput.pSubStream; - CComQIPtr pSSF = subInput.pSourceFilter; - - bool bAllowOverridingSplitterChoice; - // If the internal LAV Splitter has its own language preferences set, we choose not to override its choice - if (pSSF && CFGFilterLAV::IsInternalInstance(subInput.pSourceFilter)) { - bAllowOverridingSplitterChoice = true; - if (CComQIPtr pLAVFSettings = subInput.pSourceFilter) { - CComHeapPtr pLangPrefs; - LAVSubtitleMode subtitleMode = pLAVFSettings->GetSubtitleMode(); - if ((((subtitleMode == LAVSubtitleMode_Default && SUCCEEDED(pLAVFSettings->GetPreferredSubtitleLanguages(&pLangPrefs))) - || (subtitleMode == LAVSubtitleMode_Advanced && SUCCEEDED(pLAVFSettings->GetAdvancedSubtitleConfig(&pLangPrefs)))) - && pLangPrefs && wcslen(pLangPrefs)) - || subtitleMode == LAVSubtitleMode_ForcedOnly || subtitleMode == LAVSubtitleMode_NoSubs) { - bAllowOverridingSplitterChoice = false; - } - } - } else { - bAllowOverridingSplitterChoice = s.bAllowOverridingExternalSplitterChoice; - } - - int count = 0; - if (pSSF) { - DWORD cStreams; - if (SUCCEEDED(pSSF->Count(&cStreams))) { - count = (int)cStreams; - } - } else { - count = pSubStream->GetStreamCount(); - } - - for (int j = 0; j < count; j++) { - CComHeapPtr pName; - LCID lcid = 0; - int rating = 0; - if (pSSF) { - DWORD dwFlags, dwGroup = 2; - pSSF->Info(j, nullptr, &dwFlags, &lcid, &dwGroup, &pName, nullptr, nullptr); - if (dwGroup != 2) { // If the track isn't a subtitle track, we skip it - continue; - } else if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - // Give slightly higher priority to the track selected by splitter so that - // we won't override selected track in case all have the same rating. - rating += 1; - } else if (!bAllowOverridingSplitterChoice) { - // If we aren't allowed to modify the splitter choice and the current - // track isn't already selected at splitter level we need to skip it. - i++; - continue; - } - } else { - pSubStream->GetStreamInfo(j, &pName, &lcid); - } - CString name(pName); - name.Trim(); - name.MakeLower(); - - size_t k = 0; - for (const auto& l : langs) { - int num = _tstoi(l.name) - 1; - if (num >= 0) { // this is track number - if (i != num) { - k++; - continue; // not matched - } - } else { // this is lang string - if (lcid == 0 || lcid == LCID(-1) || lcid != l.lcid) { - // no LCID match, analyze track name for language match - if (!MatchSubtrackWithISOLang(name, l)) { - k++; - continue; // not matched - } - } - // LCID match - } - rating += 16 * int(langs.size() - k); - break; - } - - if (is_external) { - if (rating > 0) { - if (externalPriority) { - rating += 16 * int(langs.size() + 1); - } - } else { - if (langs.size() == 0 || name.Find(_T("\t")) == -1) { - // no preferred language or unknown sub language - if (externalPriority) { - rating += 16 * int(langs.size() + 1); - } else { - rating = 1; - } - } - } - } else { - if (s.bPreferDefaultForcedSubtitles) { - if (name.Find(_T("[default,forced]")) != -1) { // for LAV Splitter - rating += 4 + 2; - } - if (name.Find(_T("[forced]")) != -1) { - rating += 2; - } - if (name.Find(_T("[default]")) != -1) { - rating += 4; - } - } -#if 0 - if (rating == 0 && bAllowOverridingSplitterChoice && langs.size() == 0) { - // use first embedded track as fallback if there is no preferred language - rating = 1; - } -#endif - } - - if (rating > maxrating) { - maxrating = rating; - selected = i; - } - i++; - } - } - } - - if (s.IsISRAutoLoadEnabled() && !m_fAudioOnly) { - if (s.bAutoDownloadSubtitles && m_pSubStreams.IsEmpty()) { - m_pSubtitlesProviders->Search(TRUE); - } else if (m_wndSubtitlesDownloadDialog.IsWindowVisible()) { - m_pSubtitlesProviders->Search(FALSE); - } - } - - return selected; -} - -bool CMainFrame::OpenMediaPrivate(CAutoPtr pOMD) -{ - ASSERT(GetLoadState() == MLS::LOADING); - auto& s = AfxGetAppSettings(); - - m_fValidDVDOpen = false; - m_iDefRotation = 0; - - OpenFileData* pFileData = dynamic_cast(pOMD.m_p); - OpenDVDData* pDVDData = dynamic_cast(pOMD.m_p); - OpenDeviceData* pDeviceData = dynamic_cast(pOMD.m_p); - ASSERT(pFileData || pDVDData || pDeviceData); - - m_pCAP3 = nullptr; - m_pCAP2 = nullptr; - m_pCAP = nullptr; - m_pVMRWC = nullptr; - m_pVMRMC = nullptr; - m_pMFVDC = nullptr; - m_pVMB = nullptr; - m_pMFVMB = nullptr; - m_pMFVP = nullptr; - m_pMVRC = nullptr; - m_pMVRI = nullptr; - m_pMVRS = nullptr; - m_pMVRSR = nullptr; - m_pMVRFG = nullptr; - m_pMVTO = nullptr; - m_pD3DFSC = nullptr; - m_pLN21 = nullptr; - m_pCAP2_preview = nullptr; - m_pMFVDC_preview = nullptr; - m_pMFVP_preview = nullptr; - m_pVMR9C_preview = nullptr; - -#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[%u]:\n"), index); - TRACE(_T("\t%ws\n"), path.GetString()); // %ws - wide character string always - index++; - } - } - // Debug trace code - End -#endif - - CString err; - try { - auto checkAborted = [&]() { - if (m_fOpeningAborted) { - throw (UINT)IDS_AG_ABORTED; - } - }; - - OpenCreateGraphObject(pOMD); - checkAborted(); - - if (pFileData) { - OpenFile(pFileData); - } else if (pDVDData) { - 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; - } - - if (!m_pGB) { - throw (UINT)IDS_MAINFRM_88; - } - - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP2), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP3), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRWC), FALSE); // might have IVMRMixerBitmap9, but not IVMRWindowlessControl9 - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRMC), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMB), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVMB), TRUE); - - m_pMVRC = m_pCAP; - m_pMVRI = m_pCAP; - m_pMVRS = m_pCAP; - m_pMVRSR = m_pCAP; - m_pMVRFG = m_pCAP; - m_pMVTO = m_pCAP; - m_pD3DFSC = m_pCAP; - - checkAborted(); - - SetupVMR9ColorControl(); - checkAborted(); - - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVDC), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVP), TRUE); - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } - - // COMMENTED OUT: does not work at this location, need to choose the correct mode (IMFVideoProcessor::SetVideoProcessorMode) - //SetupEVRColorControl(); - - if (m_bUseSeekPreview) { - m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pMFVDC_preview), TRUE); - m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pMFVP_preview), TRUE); - m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pVMR9C_preview), TRUE); - m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pCAP2_preview), TRUE); - - RECT wr; - m_wndPreView.GetVideoRect(&wr); - if (m_pMFVDC_preview) { - m_pMFVDC_preview->SetVideoWindow(m_wndPreView.GetVideoHWND()); - m_pMFVDC_preview->SetVideoPosition(nullptr, &wr); - } - if (m_pCAP2_preview) { - m_pCAP2_preview->SetPosition(wr, wr); - } - } - - if (m_pLN21) { - m_pLN21->SetServiceState(s.fClosedCaptions ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off); - } - - checkAborted(); - - OpenCustomizeGraph(); - checkAborted(); - - OpenSetupVideo(); - checkAborted(); - - if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is used - m_OSD.Stop(); - - if (m_pMVTO) { - m_OSD.Start(m_pVideoWnd, m_pMVTO); - } else if (m_fFullScreen && !m_fAudioOnly && m_pCAP3) { // MPCVR - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); - } else if (!m_fAudioOnly && IsD3DFullScreenMode() && (m_pVMB || m_pMFVMB)) { - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); - } else { - m_OSD.Start(m_pOSDWnd); - } - } - - OpenSetupAudio(); - checkAborted(); - - if (GetPlaybackMode() == PM_FILE && pFileData) { - const CString& fn = pFileData->fns.GetHead(); - // Don't try to save file position if source isn't seekable - REFERENCE_TIME rtPos = 0; - REFERENCE_TIME rtDur = 0; - m_loadedAudioTrackIndex = -1; - m_loadedSubtitleTrackIndex = -1; - - if (m_pMS) { - m_pMS->GetDuration(&rtDur); - } - - m_bRememberFilePos = s.fKeepHistory && s.fRememberFilePos && rtDur > (s.iRememberPosForLongerThan * 10000000i64 * 60i64) && (s.bRememberPosForAudioFiles || !m_fAudioOnly); - - // Set start time but seek only after all files are loaded - if (pFileData->rtStart > 0) { // Check if an explicit start time was given - rtPos = pFileData->rtStart; - } - if (pFileData->abRepeat) { // Check if an explicit a/b repeat time was given - abRepeat = pFileData->abRepeat; - } - - if (m_dwReloadPos > 0) { - if (m_dwReloadPos < rtDur) { - rtPos = m_dwReloadPos; - } - m_dwReloadPos = 0; - } - if (reloadABRepeat) { - abRepeat = reloadABRepeat; - reloadABRepeat = ABRepeat(); - } - - auto* pMRU = &AfxGetAppSettings().MRU; - if (pMRU->rfe_array.GetCount()) { - if (!rtPos && m_bRememberFilePos) { - rtPos = pMRU->GetCurrentFilePosition(); - if (rtPos >= rtDur || rtDur - rtPos < 50000000LL) { - rtPos = 0; - } - } - if (!abRepeat && s.fKeepHistory && s.fRememberFilePos) { - abRepeat = pMRU->GetCurrentABRepeat(); - } - if (s.fKeepHistory && s.bRememberTrackSelection) { - if (m_loadedAudioTrackIndex == -1) { - m_loadedAudioTrackIndex = pMRU->GetCurrentAudioTrack(); - } - if (m_loadedSubtitleTrackIndex == -1) { - m_loadedSubtitleTrackIndex = pMRU->GetCurrentSubtitleTrack(); - } - } - } - - if (abRepeat && abRepeat.positionB > 0) { - // validate - if (abRepeat.positionB > rtDur || abRepeat.positionA >= abRepeat.positionB) { - abRepeat = ABRepeat(); - } - } - if (abRepeat) { - m_wndSeekBar.Invalidate(); - } - - if (rtPos && rtDur) { - m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - - defaultVideoAngle = 0; - if (m_pFSF && (m_pCAP2 || m_pCAP3)) { - CComQIPtr pBF = m_pFSF; - if (GetCLSID(pBF) == GUID_LAVSplitter || GetCLSID(pBF) == GUID_LAVSplitterSource) { - if (CComQIPtr pPB = pBF) { - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("rotation"), &var, nullptr)) && var.vt == VT_BSTR) { - int rotatevalue = _wtoi(var.bstrVal); - if (rotatevalue == 90 || rotatevalue == 180 || rotatevalue == 270) { - m_iDefRotation = rotatevalue; - if (m_pCAP3) { - m_pCAP3->SetRotation(rotatevalue); - } else { - m_pCAP2->SetDefaultVideoAngle(Vector(0, 0, Vector::DegToRad(360 - rotatevalue))); - } - if (m_pCAP2_preview) { - defaultVideoAngle = 360 - rotatevalue; - m_pCAP2_preview->SetDefaultVideoAngle(Vector(0, 0, Vector::DegToRad(defaultVideoAngle))); - } - } - } - var.Clear(); - } - } - } - } - checkAborted(); - - if (m_pCAP && s.IsISRAutoLoadEnabled() && !m_fAudioOnly) { - if (s.fDisableInternalSubtitles) { - m_pSubStreams.RemoveAll(); // Needs to be replaced with code that checks for forced subtitles. - } - m_posFirstExtSub = nullptr; - if (!pOMD->subs.IsEmpty()) { - POSITION pos = pOMD->subs.GetHeadPosition(); - while (pos) { - LoadSubtitle(pOMD->subs.GetNext(pos), nullptr, true); - } - } - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli) && pli.m_bYoutubeDL && !s.sYDLSubsPreference.IsEmpty()) { - POSITION pos2 = pli.m_ydl_subs.GetHeadPosition(); - while (pos2) { - CYoutubeDLInstance::YDLSubInfo ydlsub = pli.m_ydl_subs.GetNext(pos2); - if (!ydlsub.isAutomaticCaptions || s.bUseAutomaticCaptions) { - LoadSubtitle(ydlsub); - } - } - } - } - checkAborted(); - - OpenSetupWindowTitle(); - checkAborted(); - - int audstm; // offset in audio track menu, AudioSwitcher adds an "Options" entry above the audio tracks - audstm = SetupAudioStreams(); - if (audstm >= 0) { - OnPlayAudio(ID_AUDIO_SUBITEM_START + audstm); - } - checkAborted(); - - int substm; - if (m_loadedSubtitleTrackIndex >= 0 && IsValidSubtitleStream(m_loadedSubtitleTrackIndex)) { - substm = m_loadedSubtitleTrackIndex; - } else { - substm = SetupSubtitleStreams(); - } - if (substm >= 0) { - SetSubtitle(substm); - } - checkAborted(); - - // apply /dubdelay command-line switch - // TODO: that command-line switch probably needs revision - if (s.rtShift != 0) { - SetAudioDelay(s.rtShift); - s.rtShift = 0; - } - } catch (LPCTSTR msg) { - err = msg; - } catch (CString& msg) { - err = msg; - } catch (UINT msg) { - err.LoadString(msg); - } - - if (m_bUseSeekPreview && m_pMC_preview) { - m_pMC_preview->Pause(); - } - - m_closingmsg = err; - - auto getMessageArgs = [&]() { - WPARAM wp = pFileData ? PM_FILE : pDVDData ? PM_DVD : pDeviceData ? (s.iDefaultCaptureDevice == 1 ? PM_DIGITAL_CAPTURE : PM_ANALOG_CAPTURE) : PM_NONE; - ASSERT(wp != PM_NONE); - LPARAM lp = (LPARAM)pOMD.Detach(); - ASSERT(lp); - return std::make_pair(wp, lp); - }; - if (err.IsEmpty()) { - auto args = getMessageArgs(); - if (!m_bOpenedThroughThread) { - ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); - OnFilePostOpenmedia(args.first, args.second); - } else { - PostMessage(WM_POSTOPEN, args.first, args.second); - } - } else if (!m_fOpeningAborted) { - auto args = getMessageArgs(); - if (!m_bOpenedThroughThread) { - ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); - OnOpenMediaFailed(args.first, args.second); - } else { - PostMessage(WM_OPENFAILED, args.first, args.second); - } - } - - return err.IsEmpty(); -} - -void CMainFrame::CloseMediaPrivate() -{ - ASSERT(GetLoadState() == MLS::CLOSING); - - MediaControlStop(true); // needed for StreamBufferSource, because m_iMediaLoadState is always MLS::CLOSED // TODO: fix the opening for such media - m_CachedFilterState = -1; - - m_fLiveWM = false; - m_fEndOfStream = false; - m_bBuffering = false; - m_rtDurationOverride = -1; - m_bUsingDXVA = false; - m_audioTrackCount = 0; - if (m_pDVBState) { - m_pDVBState->Join(); - m_pDVBState = nullptr; - } - m_pCB.Release(); - - { - CAutoLock cAutoLock(&m_csSubLock); - m_pCurrentSubInput = SubtitleInput(nullptr); - m_pSubStreams.RemoveAll(); - m_ExternalSubstreams.clear(); - } - m_pSubClock.Release(); - - if (m_pVW && !m_pMVRS) { - m_pVW->put_Owner(NULL); - } - - m_bIsMPCVRExclusiveMode = false; - - // IMPORTANT: IVMRSurfaceAllocatorNotify/IVMRSurfaceAllocatorNotify9 has to be released before the VMR/VMR9, otherwise it will crash in Release() - m_OSD.Stop(); - m_pMVRFG.Release(); - m_pMVRSR.Release(); - m_pMVRS.Release(); - m_pMVRC.Release(); - m_pMVRI.Release(); - m_pMVTO.Release(); - m_pD3DFSC.Release(); - m_pCAP3.Release(); - m_pCAP2.Release(); - m_pCAP.Release(); - m_pVMRWC.Release(); - m_pVMRMC.Release(); - m_pVMB.Release(); - m_pMFVMB.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(); - m_pFSF.Release(); - m_pKFI.Release(); - m_pAMNS.Release(); - m_pDVS.Release(); - m_pDVS2.Release(); - for (auto& pAMMC : m_pAMMC) { - pAMMC.Release(); - } - m_pAudioSwitcherSS.Release(); - m_pSplitterSS.Release(); - m_pSplitterDubSS.Release(); - for (auto& pSS : m_pOtherSS) { - pSS.Release(); - } - - if (m_pGB) { - m_pGB->RemoveFromROT(); - m_pGB.Release(); - } - - if (m_pGB_preview) { - TRACE(_T("Stopping preview graph\n")); - MediaControlStopPreview(); - TRACE(_T("Releasing preview graph\n")); - ReleasePreviewGraph(); - } - - m_pProv.Release(); - - m_fCustomGraph = m_fShockwaveGraph = false; - - m_lastOMD.Free(); - - m_FontInstaller.UninstallFonts(); -} - -bool CMainFrame::WildcardFileSearch(CString searchstr, std::set& results, bool recurse_dirs) -{ - ExtendMaxPathLengthIfNeeded(searchstr); - - CString path = searchstr; - path.Replace('/', '\\'); - int p = path.ReverseFind('\\'); - if (p < 0) return false; - path = path.Left(p + 1); - - WIN32_FIND_DATA findData; - ZeroMemory(&findData, sizeof(WIN32_FIND_DATA)); - HANDLE h = FindFirstFile(searchstr, &findData); - if (h != INVALID_HANDLE_VALUE) { - CString search_ext = searchstr.Mid(searchstr.ReverseFind('.')).MakeLower(); - bool other_ext = (search_ext != _T(".*")); - CStringW curExt = CPath(m_wndPlaylistBar.GetCurFileName()).GetExtension().MakeLower(); - - do { - CString filename = findData.cFileName; - - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if (recurse_dirs && search_ext == L".*" && filename != L"." && filename != L"..") { - WildcardFileSearch(path + filename + L"\\*.*", results, true); - } - continue; - } - - CString ext = filename.Mid(filename.ReverseFind('.')).MakeLower(); - - if (CanSkipToExt(ext, curExt)) { - /* playlist and cue files should be ignored when searching dir for playable files */ - if (!IsPlaylistFileExt(ext)) { - results.insert(path + filename); - } - } else if (other_ext && search_ext == ext) { - results.insert(path + filename); - if (ext == _T(".rar")) { - break; - } - } - } while (FindNextFile(h, &findData)); - - FindClose(h); - } - - return results.size() > 0; -} - -bool CMainFrame::SearchInDir(bool bDirForward, bool bLoop /*= false*/) -{ - ASSERT(GetPlaybackMode() == PM_FILE || CanSkipFromClosedFile()); - - CString filename; - - auto pFileData = dynamic_cast(m_lastOMD.m_p); - if (!pFileData || !pFileData->title || pFileData->title.IsEmpty()) { - if (CanSkipFromClosedFile()) { - if (m_wndPlaylistBar.GetCount() == 1) { - filename = m_wndPlaylistBar.m_pl.GetHead().m_fns.GetHead(); - } else { - filename = lastOpenFile; - } - } else { - ASSERT(FALSE); - return false; - } - } else { - filename = pFileData->title; - } - - if (PathUtils::IsURL(filename)) { - return false; - } - - int p = filename.ReverseFind(_T('\\')); - if (p < 0) { - return false; - } - CString filemask = filename.Left(p + 1) + _T("*.*"); - std::set filelist; - if (!WildcardFileSearch(filemask, filelist, false)) { - return false; - } - - // We make sure that the currently opened file is added to the list - // even if it's of an unknown format. - auto current = filelist.insert(filename).first; - - if (filelist.size() < 2 && CPath(filename).FileExists()) { - return false; - } - - if (bDirForward) { - current++; - if (current == filelist.end()) { - if (bLoop) { - current = filelist.begin(); - } else { - return false; - } - } - } else { - if (current == filelist.begin()) { - if (bLoop) { - current = filelist.end(); - } else { - return false; - } - } - current--; - } - - CAtlList sl; - sl.AddHead(*current); - m_wndPlaylistBar.Open(sl, false); - OpenCurPlaylistItem(); - - return true; -} - -void CMainFrame::DoTunerScan(TunerScanData* pTSD) -{ - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - CComQIPtr pTun = m_pGB; - if (pTun) { - bool wasStopped = false; - if (GetMediaState() == State_Stopped) { - SetChannel(-1); - MediaControlRun(); - wasStopped = true; - } - - BOOLEAN bPresent; - BOOLEAN bLocked; - LONG lDbStrength = 0; - LONG lPercentQuality = 0; - int nOffset = pTSD->Offset ? 3 : 1; - LONG lOffsets[3] = {0, pTSD->Offset, -pTSD->Offset}; - m_bStopTunerScan = false; - pTun->Scan(0, 0, 0, NULL); // Clear maps - - for (ULONG ulFrequency = pTSD->FrequencyStart; ulFrequency <= pTSD->FrequencyStop; ulFrequency += pTSD->Bandwidth) { - bool bSucceeded = false; - for (int nOffsetPos = 0; nOffsetPos < nOffset && !bSucceeded; nOffsetPos++) { - if (SUCCEEDED(pTun->SetFrequency(ulFrequency + lOffsets[nOffsetPos], pTSD->Bandwidth, pTSD->SymbolRate))) { - Sleep(200); // Let the tuner some time to detect the signal - if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { - ::SendMessage(pTSD->Hwnd, WM_TUNER_STATS, lDbStrength, lPercentQuality); - pTun->Scan(ulFrequency + lOffsets[nOffsetPos], pTSD->Bandwidth, pTSD->SymbolRate, pTSD->Hwnd); - bSucceeded = true; - } - } - } - - int nProgress = MulDiv(ulFrequency - pTSD->FrequencyStart, 100, pTSD->FrequencyStop - pTSD->FrequencyStart); - ::SendMessage(pTSD->Hwnd, WM_TUNER_SCAN_PROGRESS, nProgress, 0); - ::SendMessage(pTSD->Hwnd, WM_TUNER_STATS, lDbStrength, lPercentQuality); - - if (m_bStopTunerScan) { - break; - } - } - - ::SendMessage(pTSD->Hwnd, WM_TUNER_SCAN_END, 0, 0); - if (wasStopped) { - SetChannel(AfxGetAppSettings().nDVBLastChannel); - MediaControlStop(); - } - } - } -} - -// Skype - -void CMainFrame::SendNowPlayingToSkype() -{ - if (!m_pSkypeMoodMsgHandler) { - return; - } - - CString msg; - - if (GetLoadState() == MLS::LOADED) { - CString title, author; - - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_TITLE), title); - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); - - if (title.IsEmpty()) { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - CString label = !pli.m_label.IsEmpty() ? pli.m_label : pli.m_fns.GetHead(); - - if (GetPlaybackMode() == PM_FILE) { - CString fn = label; - if (!pli.m_bYoutubeDL && PathUtils::IsURL(fn)) { - int i = fn.Find('?'); - if (i >= 0) { - fn = fn.Left(i); - } - } - CPath path(fn); - path.StripPath(); - path.MakePretty(); - path.RemoveExtension(); - title = (LPCTSTR)path; - author.Empty(); - } else if (IsPlaybackCaptureMode()) { - title = GetCaptureTitle(); - author.Empty(); - } else if (GetPlaybackMode() == PM_DVD) { - title = _T("DVD"); - author.Empty(); - } - } - } - - if (!author.IsEmpty()) { - msg.Format(_T("%s - %s"), author.GetString(), title.GetString()); - } else { - msg = title; - } - } - - m_pSkypeMoodMsgHandler->SendMoodMessage(msg); -} - -// dynamic menus - -void CMainFrame::CreateDynamicMenus() -{ - VERIFY(m_openCDsMenu.CreatePopupMenu()); - VERIFY(m_filtersMenu.CreatePopupMenu()); - VERIFY(m_subtitlesMenu.CreatePopupMenu()); - VERIFY(m_audiosMenu.CreatePopupMenu()); - VERIFY(m_videoStreamsMenu.CreatePopupMenu()); - VERIFY(m_chaptersMenu.CreatePopupMenu()); - VERIFY(m_titlesMenu.CreatePopupMenu()); - VERIFY(m_playlistMenu.CreatePopupMenu()); - VERIFY(m_BDPlaylistMenu.CreatePopupMenu()); - VERIFY(m_channelsMenu.CreatePopupMenu()); - VERIFY(m_favoritesMenu.CreatePopupMenu()); - VERIFY(m_shadersMenu.CreatePopupMenu()); - VERIFY(m_recentFilesMenu.CreatePopupMenu()); -} - -void CMainFrame::DestroyDynamicMenus() -{ - VERIFY(m_openCDsMenu.DestroyMenu()); - VERIFY(m_filtersMenu.DestroyMenu()); - VERIFY(m_subtitlesMenu.DestroyMenu()); - VERIFY(m_audiosMenu.DestroyMenu()); - VERIFY(m_videoStreamsMenu.DestroyMenu()); - VERIFY(m_chaptersMenu.DestroyMenu()); - VERIFY(m_titlesMenu.DestroyMenu()); - VERIFY(m_playlistMenu.DestroyMenu()); - VERIFY(m_BDPlaylistMenu.DestroyMenu()); - VERIFY(m_channelsMenu.DestroyMenu()); - VERIFY(m_favoritesMenu.DestroyMenu()); - VERIFY(m_shadersMenu.DestroyMenu()); - VERIFY(m_recentFilesMenu.DestroyMenu()); - m_nJumpToSubMenusCount = 0; -} - -void CMainFrame::SetupOpenCDSubMenu() -{ - CMenu& subMenu = m_openCDsMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (GetLoadState() == MLS::LOADING || AfxGetAppSettings().fHideCDROMsSubMenu) { - return; - } - - UINT id = ID_FILE_OPEN_OPTICAL_DISK_START; - for (TCHAR drive = _T('A'); drive <= _T('Z'); drive++) { - CAtlList files; - OpticalDiskType_t opticalDiskType = GetOpticalDiskType(drive, files); - - if (opticalDiskType != OpticalDisk_NotFound && opticalDiskType != OpticalDisk_Unknown) { - CString label = GetDriveLabel(drive); - if (label.IsEmpty()) { - switch (opticalDiskType) { - case OpticalDisk_Audio: - label = _T("Audio CD"); - break; - case OpticalDisk_VideoCD: - label = _T("(S)VCD"); - break; - case OpticalDisk_DVDVideo: - label = _T("DVD Video"); - break; - case OpticalDisk_BD: - label = _T("Blu-ray Disc"); - break; - default: - ASSERT(FALSE); - break; - } - } - - CString str; - str.Format(_T("%s (%c:)"), label.GetString(), drive); - - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, str)); - } - } -} - -void CMainFrame::SetupFiltersSubMenu() -{ - CMPCThemeMenu& subMenu = m_filtersMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - m_pparray.RemoveAll(); - m_ssarray.RemoveAll(); - - if (GetLoadState() == MLS::LOADED) { - UINT idf = 1; //used as an id, so make non-zero to start - UINT ids = ID_FILTERS_SUBITEM_START; - UINT idl = ID_FILTERSTREAMS_SUBITEM_START; - - BeginEnumFilters(m_pGB, pEF, pBF) { - CString filterName(GetFilterName(pBF)); - if (filterName.GetLength() >= 43) { - filterName = filterName.Left(40) + _T("..."); - } - - CLSID clsid = GetCLSID(pBF); - if (clsid == CLSID_AVIDec) { - CComPtr pPin = GetFirstPin(pBF); - AM_MEDIA_TYPE mt; - if (pPin && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - DWORD c = ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression; - switch (c) { - case BI_RGB: - filterName += _T(" (RGB)"); - break; - case BI_RLE4: - filterName += _T(" (RLE4)"); - break; - case BI_RLE8: - filterName += _T(" (RLE8)"); - break; - case BI_BITFIELDS: - filterName += _T(" (BITF)"); - break; - default: - filterName.AppendFormat(_T(" (%c%c%c%c)"), - (TCHAR)((c >> 0) & 0xff), - (TCHAR)((c >> 8) & 0xff), - (TCHAR)((c >> 16) & 0xff), - (TCHAR)((c >> 24) & 0xff)); - break; - } - } - } else if (clsid == CLSID_ACMWrapper) { - CComPtr pPin = GetFirstPin(pBF); - AM_MEDIA_TYPE mt; - if (pPin && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - WORD c = ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag; - filterName.AppendFormat(_T(" (0x%04x)"), (int)c); - } - } else if (clsid == __uuidof(CTextPassThruFilter) - || clsid == __uuidof(CNullTextRenderer) - || clsid == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) { // ISCR - // hide these - continue; - } - - CMenu internalSubMenu; - VERIFY(internalSubMenu.CreatePopupMenu()); - - int nPPages = 0; - - CComQIPtr pSPP = pBF; - - m_pparray.Add(pBF); - VERIFY(internalSubMenu.AppendMenu(MF_STRING | MF_ENABLED, ids, ResStr(IDS_MAINFRM_116))); - - nPPages++; - - BeginEnumPins(pBF, pEP, pPin) { - CString pinName = GetPinName(pPin); - pinName.Replace(_T("&"), _T("&&")); - - if (pSPP = pPin) { - CAUUID caGUID; - caGUID.pElems = nullptr; - if (SUCCEEDED(pSPP->GetPages(&caGUID)) && caGUID.cElems > 0) { - m_pparray.Add(pPin); - VERIFY(internalSubMenu.AppendMenu(MF_STRING | MF_ENABLED, ids + nPPages, pinName + ResStr(IDS_MAINFRM_117))); - - if (caGUID.pElems) { - CoTaskMemFree(caGUID.pElems); - } - - nPPages++; - } - } - } - EndEnumPins; - - CComQIPtr pSS = pBF; - DWORD nStreams = 0; - if (pSS && SUCCEEDED(pSS->Count(&nStreams))) { - DWORD flags = DWORD_MAX; - DWORD group = DWORD_MAX; - DWORD prevgroup = DWORD_MAX; - LCID lcid = 0; - WCHAR* wname = nullptr; - UINT uMenuFlags; - - if (nStreams > 0 && nPPages > 0) { - VERIFY(internalSubMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - } - - UINT idlstart = idl; - UINT selectedInGroup = 0; - - for (DWORD i = 0; i < nStreams; i++) { - m_ssarray.Add(pSS); - - flags = group = 0; - wname = nullptr; - if (FAILED(pSS->Info(i, nullptr, &flags, &lcid, &group, &wname, nullptr, nullptr))) { - continue; - } - - if (group != prevgroup && idl > idlstart) { - if (selectedInGroup) { - VERIFY(internalSubMenu.CheckMenuRadioItem(idlstart, idl - 1, selectedInGroup, MF_BYCOMMAND)); - selectedInGroup = 0; - } - VERIFY(internalSubMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - idlstart = idl; - } - prevgroup = group; - - uMenuFlags = MF_STRING | MF_ENABLED; - if (flags & AMSTREAMSELECTINFO_EXCLUSIVE) { - selectedInGroup = idl; - } else if (flags & AMSTREAMSELECTINFO_ENABLED) { - uMenuFlags |= MF_CHECKED; - } - - CString streamName; - if (!wname) { - streamName.LoadString(IDS_AG_UNKNOWN_STREAM); - streamName.AppendFormat(_T(" %lu"), i + 1); - } else { - streamName = wname; - streamName.Replace(_T("&"), _T("&&")); - CoTaskMemFree(wname); - } - - VERIFY(internalSubMenu.AppendMenu(uMenuFlags, idl++, streamName)); - } - if (selectedInGroup) { - VERIFY(internalSubMenu.CheckMenuRadioItem(idlstart, idl - 1, selectedInGroup, MF_BYCOMMAND)); - } - - if (nStreams == 0) { - pSS.Release(); - } - } - - if (nPPages == 1 && !pSS) { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ids, filterName)); - } else { - if (nPPages > 0 || pSS) { - UINT nFlags = MF_STRING | MF_POPUP | ((pSPP || pSS) ? MF_ENABLED : MF_GRAYED); - VERIFY(subMenu.AppendMenu(nFlags, (UINT_PTR)internalSubMenu.Detach(), filterName)); - } else { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_GRAYED, idf, filterName)); - } - } - - ids += nPPages; - idf++; - } - EndEnumFilters; - - if (subMenu.GetMenuItemCount() > 0) { - VERIFY(subMenu.InsertMenu(0, MF_STRING | MF_ENABLED | MF_BYPOSITION, ID_FILTERS_COPY_TO_CLIPBOARD, ResStr(IDS_FILTERS_COPY_TO_CLIPBOARD))); - VERIFY(subMenu.InsertMenu(1, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); - } - subMenu.fulfillThemeReqs(); - } -} - -void CMainFrame::SetupAudioSubMenu() -{ - CMenu& subMenu = m_audiosMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (GetLoadState() != MLS::LOADED) { - return; - } - - UINT id = ID_AUDIO_SUBITEM_START; - - DWORD cStreams = 0; - - if (GetPlaybackMode() == PM_DVD) { - currentAudioLang = _T(""); - ULONG ulStreamsAvailable, ulCurrentStream; - if (FAILED(m_pDVDI->GetCurrentAudio(&ulStreamsAvailable, &ulCurrentStream))) { - return; - } - - LCID DefLanguage; - DVD_AUDIO_LANG_EXT ext; - if (FAILED(m_pDVDI->GetDefaultAudioLanguage(&DefLanguage, &ext))) { - return; - } - - for (ULONG i = 0; i < ulStreamsAvailable; i++) { - LCID Language; - if (FAILED(m_pDVDI->GetAudioLanguage(i, &Language))) { - continue; - } - - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (Language == DefLanguage) { - flags |= MF_DEFAULT; - } - if (i == ulCurrentStream) { - flags |= MF_CHECKED; - if (Language) { - GetLocaleString(Language, LOCALE_SISO639LANGNAME2, currentAudioLang); - } - } - - CString str; - if (Language) { - GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); - } else { - str.Format(IDS_AG_UNKNOWN, i + 1); - } - - DVD_AudioAttributes ATR; - if (SUCCEEDED(m_pDVDI->GetAudioAttributes(i, &ATR))) { - switch (ATR.LanguageExtension) { - case DVD_AUD_EXT_NotSpecified: - default: - break; - case DVD_AUD_EXT_Captions: - str += _T(" (Captions)"); - break; - case DVD_AUD_EXT_VisuallyImpaired: - str += _T(" (Visually Impaired)"); - break; - case DVD_AUD_EXT_DirectorComments1: - str.AppendFormat(IDS_MAINFRM_121); - break; - case DVD_AUD_EXT_DirectorComments2: - str.AppendFormat(IDS_MAINFRM_122); - break; - } - - CString format = GetDVDAudioFormatName(ATR); - - if (!format.IsEmpty()) { - str.Format(IDS_MAINFRM_11, - CString(str).GetString(), - format.GetString(), - ATR.dwFrequency, - ATR.bQuantization, - ATR.bNumberOfChannels, - ResStr(ATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString() - ); - } - } - - VERIFY(AppendMenuEx(subMenu, flags, id++, str)); - } - } - // If available use the audio switcher for everything but DVDs - else if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_OPTIONS))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - - long iSel = 0; - - for (long i = 0; i < (long)cStreams; i++) { - DWORD dwFlags; - WCHAR* pName = nullptr; - if (FAILED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, nullptr, &pName, nullptr, nullptr))) { - break; - } - if (dwFlags) { - iSel = i; - } - - CString name(pName); - name.Replace(_T("&"), _T("&&")); - - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); - - CoTaskMemFree(pName); - } - VERIFY(subMenu.CheckMenuRadioItem(2, 2 + cStreams - 1, 2 + iSel, MF_BYPOSITION)); - } else if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - SetupNavStreamSelectSubMenu(subMenu, id, 1); - } -} - -void CMainFrame::SetupSubtitlesSubMenu() -{ - CMenu& subMenu = m_subtitlesMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { - return; - } - - UINT id = ID_SUBTITLES_SUBITEM_START; - - // DVD subtitles in DVD mode are never handled by the internal subtitles renderer - // but it is still possible to load external subtitles so we keep that if block - // separated from the rest - if (GetPlaybackMode() == PM_DVD) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) - && ulStreamsAvailable > 0) { - LCID DefLanguage; - DVD_SUBPICTURE_LANG_EXT ext; - if (FAILED(m_pDVDI->GetDefaultSubpictureLanguage(&DefLanguage, &ext))) { - return; - } - - VERIFY(subMenu.AppendMenu(MF_STRING | (bIsDisabled ? 0 : MF_CHECKED), id++, ResStr(IDS_DVD_SUBTITLES_ENABLE))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - - for (ULONG i = 0; i < ulStreamsAvailable; i++) { - LCID Language; - if (FAILED(m_pDVDI->GetSubpictureLanguage(i, &Language))) { - continue; - } - - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (Language == DefLanguage) { - flags |= MF_DEFAULT; - } - if (i == ulCurrentStream) { - flags |= MF_CHECKED; - } - - CString str; - if (Language) { - GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); - } else { - str.Format(IDS_AG_UNKNOWN, i + 1); - } - - DVD_SubpictureAttributes ATR; - if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(i, &ATR))) { - switch (ATR.LanguageExtension) { - case DVD_SP_EXT_NotSpecified: - default: - break; - case DVD_SP_EXT_Caption_Normal: - str += _T(""); - break; - case DVD_SP_EXT_Caption_Big: - str += _T(" (Big)"); - break; - case DVD_SP_EXT_Caption_Children: - str += _T(" (Children)"); - break; - case DVD_SP_EXT_CC_Normal: - str += _T(" (CC)"); - break; - case DVD_SP_EXT_CC_Big: - str += _T(" (CC Big)"); - break; - case DVD_SP_EXT_CC_Children: - str += _T(" (CC Children)"); - break; - case DVD_SP_EXT_Forced: - str += _T(" (Forced)"); - break; - case DVD_SP_EXT_DirectorComments_Normal: - str += _T(" (Director Comments)"); - break; - case DVD_SP_EXT_DirectorComments_Big: - str += _T(" (Director Comments, Big)"); - break; - case DVD_SP_EXT_DirectorComments_Children: - str += _T(" (Director Comments, Children)"); - break; - } - } - - VERIFY(AppendMenuEx(subMenu, flags, id++, str)); - } - } - } - - POSITION pos = m_pSubStreams.GetHeadPosition(); - - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - DWORD selected = SetupNavStreamSelectSubMenu(subMenu, id, 2); - if (selected != -1) { - SetSubtitle(selected - ID_SUBTITLES_SUBITEM_START); - } - } else if (pos) { // Internal subtitles renderer - int nItemsBeforeStart = id - ID_SUBTITLES_SUBITEM_START; - if (nItemsBeforeStart > 0) { - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - nItemsBeforeStart += 2; // Separators - } - - // Build the static menu's items - bool bTextSubtitles = false; - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_OPTIONS))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_STYLES))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_RELOAD))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_HIDE))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUB_OVERRIDE_DEFAULT_STYLE))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUB_OVERRIDE_ALL_STYLES))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - - // Build the dynamic menu's items - int i = 0, iSelected = -1; - while (pos) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - - if (CComQIPtr pSSF = subInput.pSourceFilter) { - DWORD cStreams; - if (FAILED(pSSF->Count(&cStreams))) { - continue; - } - - for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { - DWORD dwFlags, dwGroup; - CComHeapPtr pszName; - LCID lcid = 0; - if (FAILED(pSSF->Info(j, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - if (dwGroup != 2) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream - && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - iSelected = i; - } - - CString name(pszName); - /* - CString lcname = CString(name).MakeLower(); - if (lcname.Find(_T(" off")) >= 0) { - name.LoadString(IDS_AG_DISABLED); - } - */ - if (lcid != 0 && name.Find(L'\t') < 0) { - CString lcidstr; - GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); - name.Append(_T("\t") + lcidstr); - } - - name.Replace(_T("&"), _T("&&")); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); - i++; - } - } else { - CComPtr pSubStream = subInput.pSubStream; - if (!pSubStream) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - iSelected = i + pSubStream->GetStream(); - } - - for (int j = 0, cnt = pSubStream->GetStreamCount(); j < cnt; j++) { - CComHeapPtr pName; - LCID lcid = 0; - if (SUCCEEDED(pSubStream->GetStreamInfo(j, &pName, &lcid))) { - CString name(pName); - if (lcid != 0 && name.Find(L'\t') < 0) { - CString lcidstr; - GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); - name.Append(_T("\t") + lcidstr); - } - - name.Replace(_T("&"), _T("&&")); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); - } else { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_AG_UNKNOWN_STREAM))); - } - i++; - } - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - CLSID clsid; - if (SUCCEEDED(subInput.pSubStream->GetClassID(&clsid)) - && clsid == __uuidof(CRenderedTextSubtitle)) { - bTextSubtitles = true; - } - } - - // TODO: find a better way to group these entries - /*if (pos && m_pSubStreams.GetAt(pos).subStream) { - CLSID cur, next; - pSubStream->GetClassID(&cur); - m_pSubStreams.GetAt(pos).subStream->GetClassID(&next); - - if (cur != next) { - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - } - }*/ - } - - // Set the menu's items' state - const CAppSettings& s = AfxGetAppSettings(); - // Style - if (!bTextSubtitles) { - subMenu.EnableMenuItem(nItemsBeforeStart + 1, MF_BYPOSITION | MF_GRAYED); - } - // Hide - if (!s.fEnableSubtitles) { - subMenu.CheckMenuItem(nItemsBeforeStart + 4, MF_BYPOSITION | MF_CHECKED); - } - // Style overrides - if (!bTextSubtitles) { - subMenu.EnableMenuItem(nItemsBeforeStart + 5, MF_BYPOSITION | MF_GRAYED); - subMenu.EnableMenuItem(nItemsBeforeStart + 6, MF_BYPOSITION | MF_GRAYED); - } - if (s.bSubtitleOverrideDefaultStyle) { - subMenu.CheckMenuItem(nItemsBeforeStart + 5, MF_BYPOSITION | MF_CHECKED); - } - if (s.bSubtitleOverrideAllStyles) { - subMenu.CheckMenuItem(nItemsBeforeStart + 6, MF_BYPOSITION | MF_CHECKED); - } - if (iSelected >= 0) { - VERIFY(subMenu.CheckMenuRadioItem(nItemsBeforeStart + 8, nItemsBeforeStart + 8 + i - 1, nItemsBeforeStart + 8 + iSelected, MF_BYPOSITION)); - } - } else if (GetPlaybackMode() == PM_FILE) { - SetupNavStreamSelectSubMenu(subMenu, id, 2); - } -} - -void CMainFrame::SetupVideoStreamsSubMenu() -{ - CMenu& subMenu = m_videoStreamsMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (GetLoadState() != MLS::LOADED) { - return; - } - - UINT id = ID_VIDEO_STREAMS_SUBITEM_START; - - if (GetPlaybackMode() == PM_FILE) { - SetupNavStreamSelectSubMenu(subMenu, id, 0); - } else if (GetPlaybackMode() == PM_DVD) { - ULONG ulStreamsAvailable, ulCurrentStream; - if (FAILED(m_pDVDI->GetCurrentAngle(&ulStreamsAvailable, &ulCurrentStream))) { - return; - } - - if (ulStreamsAvailable < 2) { - return; // one choice is not a choice... - } - - for (ULONG i = 1; i <= ulStreamsAvailable; i++) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (i == ulCurrentStream) { - flags |= MF_CHECKED; - } - - CString str; - str.Format(IDS_AG_ANGLE, i); - - VERIFY(subMenu.AppendMenu(flags, id++, str)); - } - } -} - -void CMainFrame::SetupJumpToSubMenus(CMenu* parentMenu /*= nullptr*/, int iInsertPos /*= -1*/) -{ - const CAppSettings& s = AfxGetAppSettings(); - auto emptyMenu = [&](CMPCThemeMenu & menu) { - while (menu.RemoveMenu(0, MF_BYPOSITION)); - }; - - // Empty the submenus - emptyMenu(m_chaptersMenu); - emptyMenu(m_titlesMenu); - emptyMenu(m_playlistMenu); - emptyMenu(m_BDPlaylistMenu); - emptyMenu(m_channelsMenu); - // Remove the submenus from the "Navigate" menu - if (parentMenu && iInsertPos >= 0) { - for (; m_nJumpToSubMenusCount > 0; m_nJumpToSubMenusCount--) { - VERIFY(parentMenu->RemoveMenu(iInsertPos, MF_BYPOSITION)); - } - } - - if (GetLoadState() != MLS::LOADED) { - return; - } - - UINT id = ID_NAVIGATE_JUMPTO_SUBITEM_START, idStart, idSelected; - - auto menuStartRadioSection = [&]() { - idStart = id; - idSelected = UINT_ERROR; - }; - auto menuEndRadioSection = [&](CMenu & menu) { - if (idSelected != UINT_ERROR) { - VERIFY(menu.CheckMenuRadioItem(idStart, id - 1, idSelected, - idStart >= ID_NAVIGATE_JUMPTO_SUBITEM_START ? MF_BYCOMMAND : MF_BYPOSITION)); - } - }; - auto addSubMenuIfPossible = [&](CString subMenuName, CMenu & subMenu) { - if (parentMenu && iInsertPos >= 0) { - if (parentMenu->InsertMenu(iInsertPos + m_nJumpToSubMenusCount, MF_POPUP | MF_BYPOSITION, - (UINT_PTR)(HMENU)subMenu, subMenuName)) { - CMPCThemeMenu::fulfillThemeReqsItem(parentMenu, iInsertPos + m_nJumpToSubMenusCount); - m_nJumpToSubMenusCount++; - } else { - ASSERT(FALSE); - } - } - }; - - if (GetPlaybackMode() == PM_FILE) { - if (m_MPLSPlaylist.size() > 1) { - menuStartRadioSection(); - for (auto& Item : m_MPLSPlaylist) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - CString time = _T("[") + ReftimeToString2(Item.Duration()) + _T("]"); - CString name = PathUtils::StripPathOrUrl(Item.m_strFileName); - - if (name == m_wndPlaylistBar.m_pl.GetHead().GetLabel()) { - idSelected = id; - } - - name.Replace(_T("&"), _T("&&")); - VERIFY(m_BDPlaylistMenu.AppendMenu(flags, id++, name + '\t' + time)); - } - menuEndRadioSection(m_BDPlaylistMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_BD_PLAYLISTS), m_BDPlaylistMenu); - } - - //SetupChapters(); - if (m_pCB && m_pCB->ChapGetCount() > 1) { - REFERENCE_TIME rt = GetPos(); - DWORD j = m_pCB->ChapLookup(&rt, nullptr); - menuStartRadioSection(); - for (DWORD i = 0; i < m_pCB->ChapGetCount(); i++, id++) { - rt = 0; - CComBSTR bstr; - if (FAILED(m_pCB->ChapGet(i, &rt, &bstr))) { - continue; - } - - CString time = _T("[") + ReftimeToString2(rt) + _T("]"); - - CString name = CString(bstr); - name.Replace(_T("&"), _T("&&")); - name.Replace(_T("\t"), _T(" ")); - - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (i == j) { - idSelected = id; - } - - VERIFY(m_chaptersMenu.AppendMenu(flags, id, name + '\t' + time)); - } - menuEndRadioSection(m_chaptersMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHAPTERS), m_chaptersMenu); - } - - if (m_wndPlaylistBar.GetCount() > 1) { - menuStartRadioSection(); - POSITION pos = m_wndPlaylistBar.m_pl.GetHeadPosition(); - while (pos && id < ID_NAVIGATE_JUMPTO_SUBITEM_START + 128) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (pos == m_wndPlaylistBar.m_pl.GetPos()) { - idSelected = id; - } - CPlaylistItem& pli = m_wndPlaylistBar.m_pl.GetNext(pos); - CString name = pli.GetLabel(); - name.Replace(_T("&"), _T("&&")); - VERIFY(m_playlistMenu.AppendMenu(flags, id++, name)); - } - menuEndRadioSection(m_playlistMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_PLAYLIST), m_playlistMenu); - } - } else if (GetPlaybackMode() == PM_DVD) { - ULONG ulNumOfVolumes, ulVolume, ulNumOfTitles, ulNumOfChapters, ulUOPs; - DVD_DISC_SIDE Side; - DVD_PLAYBACK_LOCATION2 Location; - - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location)) - && SUCCEEDED(m_pDVDI->GetCurrentUOPS(&ulUOPs)) - && SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters)) - && SUCCEEDED(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles))) { - menuStartRadioSection(); - for (ULONG i = 1; i <= ulNumOfTitles; i++) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (i == Location.TitleNum) { - idSelected = id; - } - if (ulUOPs & UOP_FLAG_Play_Title) { - flags |= MF_GRAYED; - } - - CString str; - str.Format(IDS_AG_TITLE, i); - - VERIFY(m_titlesMenu.AppendMenu(flags, id++, str)); - } - menuEndRadioSection(m_titlesMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_TITLES), m_titlesMenu); - - menuStartRadioSection(); - for (ULONG i = 1; i <= ulNumOfChapters; i++) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (i == Location.ChapterNum) { - idSelected = id; - } - if (ulUOPs & UOP_FLAG_Play_Chapter) { - flags |= MF_GRAYED; - } - - CString str; - str.Format(IDS_AG_CHAPTER, i); - - VERIFY(m_chaptersMenu.AppendMenu(flags, id++, str)); - } - menuEndRadioSection(m_chaptersMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHAPTERS), m_chaptersMenu); - } - } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - menuStartRadioSection(); - for (const auto& channel : s.m_DVBChannels) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - - if (channel.GetPrefNumber() == s.nDVBLastChannel) { - idSelected = id; - } - VERIFY(m_channelsMenu.AppendMenu(flags, ID_NAVIGATE_JUMPTO_SUBITEM_START + channel.GetPrefNumber(), channel.GetName())); - id++; - } - menuEndRadioSection(m_channelsMenu); - addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHANNELS), m_channelsMenu); - } -} - -DWORD CMainFrame::SetupNavStreamSelectSubMenu(CMenu& subMenu, UINT id, DWORD dwSelGroup) -{ - bool bAddSeparator = false; - DWORD selected = -1; - bool streams_found = false; - - auto addStreamSelectFilter = [&](CComPtr pSS) { - DWORD cStreams; - if (!pSS || FAILED(pSS->Count(&cStreams))) { - return; - } - - bool bAdded = false; - for (DWORD i = 0; i < cStreams; i++) { - DWORD dwFlags, dwGroup; - CComHeapPtr pszName; - LCID lcid = 0; - if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - if (dwGroup != dwSelGroup) { - continue; - } - - CString name(pszName); - /* - CString lcname = CString(name).MakeLower(); - if (dwGroup == 2 && lcname.Find(_T(" off")) >= 0) { - name.LoadString(IDS_AG_DISABLED); - } - */ - if (dwGroup == 2 && lcid != 0 && name.Find(L'\t') < 0) { - CString lcidstr; - GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); - name.Append(_T("\t") + lcidstr); - } - - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (dwFlags) { - flags |= MF_CHECKED; - selected = id; - } - - if (bAddSeparator) { - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - bAddSeparator = false; - } - bAdded = true; - - name.Replace(_T("&"), _T("&&")); - VERIFY(subMenu.AppendMenu(flags, id++, name)); - } - - if (bAdded) { - bAddSeparator = true; - streams_found = true; - } - }; - - if (m_pSplitterSS) { - addStreamSelectFilter(m_pSplitterSS); - } - if (!streams_found && m_pOtherSS[0]) { - addStreamSelectFilter(m_pOtherSS[0]); - } - if (!streams_found && m_pOtherSS[1]) { - addStreamSelectFilter(m_pOtherSS[1]); - } - - return selected; -} - -void CMainFrame::OnNavStreamSelectSubMenu(UINT id, DWORD dwSelGroup) -{ - bool streams_found = false; - - auto processStreamSelectFilter = [&](CComPtr pSS) { - bool bSelected = false; - - DWORD cStreams; - if (SUCCEEDED(pSS->Count(&cStreams))) { - for (int i = 0, j = cStreams; i < j; i++) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - CComHeapPtr pszName; - - if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - if (dwGroup != dwSelGroup) { - continue; - } - - streams_found = true; - - if (id == 0) { - pSS->Enable(i, AMSTREAMSELECTENABLE_ENABLE); - bSelected = true; - break; - } - - id--; - } - } - - return bSelected; - }; - - if (m_pSplitterSS) { - if (processStreamSelectFilter(m_pSplitterSS)) return; - } - if (!streams_found && m_pOtherSS[0]) { - if (processStreamSelectFilter(m_pOtherSS[0])) return; - } - if (!streams_found && m_pOtherSS[1]) { - if (processStreamSelectFilter(m_pOtherSS[1])) return; - } -} - -void CMainFrame::OnStreamSelect(bool bForward, DWORD dwSelGroup) -{ - ASSERT(dwSelGroup == 1 || dwSelGroup == 2); - bool streams_found = false; - - auto processStreamSelectFilter = [&](CComPtr pSS) { - DWORD cStreams; - if (FAILED(pSS->Count(&cStreams))) { - return false; - } - - std::vector> streams; - size_t currentSel = SIZE_MAX; - for (DWORD i = 0; i < cStreams; i++) { - DWORD dwFlags, dwGroup; - LCID lcid = 0; - CComHeapPtr pszName; - - if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - if (dwGroup != dwSelGroup) { - continue; - } - - streams_found = true; - - if (dwFlags) { - currentSel = streams.size(); - } - streams.emplace_back(i, (int)streams.size(), lcid, CString(pszName)); - } - - size_t count = streams.size(); - if (count && currentSel != SIZE_MAX) { - size_t requested = (bForward ? currentSel + 1 : currentSel - 1) % count; - DWORD id; - int trackindex; - LCID lcid = 0; - CString name; - std::tie(id, trackindex, lcid, name) = streams.at(requested); - if (SUCCEEDED(pSS->Enable(id, AMSTREAMSELECTENABLE_ENABLE))) { - if (dwSelGroup == 1 || AfxGetAppSettings().fEnableSubtitles) { - m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(name, lcid, dwSelGroup)); - } - if (dwSelGroup == 1) { - AM_MEDIA_TYPE* pmt = nullptr; - if (SUCCEEDED(pSS->Info(id, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr))) { - UpdateSelectedAudioStreamInfo(trackindex, pmt, lcid); - DeleteMediaType(pmt); - } - } else { - if (lcid && AfxGetAppSettings().fEnableSubtitles) { - GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentSubLang); - } else { - currentSubLang.Empty(); - } - } - } - return true; - } - return false; - }; - - if (m_pSplitterSS) { - if (processStreamSelectFilter(m_pSplitterSS)) return; - } - if (!streams_found && m_pOtherSS[0]) { - if (processStreamSelectFilter(m_pOtherSS[0])) return; - } - if (!streams_found && m_pOtherSS[1]) { - if (processStreamSelectFilter(m_pOtherSS[1])) return; - } -} - -CString CMainFrame::GetStreamOSDString(CString name, LCID lcid, DWORD dwSelGroup) -{ - name.Replace(_T("\t"), _T(" - ")); - CString sLcid; - if (lcid && lcid != LCID(-1)) { - GetLocaleString(lcid, LOCALE_SENGLANGUAGE, sLcid); - } - if (!sLcid.IsEmpty() && CString(name).MakeLower().Find(CString(sLcid).MakeLower()) < 0) { - name += _T(" (") + sLcid + _T(")"); - } - CString strMessage; - if (dwSelGroup == 1) { - int n = 0; - if (name.Find(_T("A:")) == 0) { - n = 2; - } - strMessage.Format(IDS_AUDIO_STREAM, name.Mid(n).Trim().GetString()); - } else if (dwSelGroup == 2) { - int n = 0; - if (name.Find(_T("S:")) == 0) { - n = 2; - } - strMessage.Format(IDS_SUBTITLE_STREAM, name.Mid(n).Trim().GetString()); - } - return strMessage; -} - -void CMainFrame::SetupRecentFilesSubMenu() -{ - auto& s = AfxGetAppSettings(); - auto& MRU = s.MRU; - MRU.ReadMediaHistory(); - - if (MRU.listModifySequence == recentFilesMenuFromMRUSequence) { - return; - } - recentFilesMenuFromMRUSequence = MRU.listModifySequence; - - CMenu& subMenu = m_recentFilesMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (!s.fKeepHistory) { - return; - } - - if (MRU.GetSize() > 0) { - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_RECENT_FILES_CLEAR, ResStr(IDS_RECENT_FILES_CLEAR))); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); - UINT id = ID_RECENT_FILE_START; - for (int i = 0; i < MRU.GetSize(); i++) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - if (!MRU[i].fns.IsEmpty() && !MRU[i].fns.GetHead().IsEmpty()) { - CString p = MRU[i].cue.IsEmpty() ? MRU[i].fns.GetHead() : MRU[i].cue; - if (s.bUseTitleInRecentFileList && !MRU[i].title.IsEmpty()) { - CString title(MRU[i].title); - if (title.GetLength() > 100) { - title = title.Left(40) + _T("~~~") + title.Right(57); - } - int targetlen = 150 - title.GetLength(); - if (PathUtils::IsURL(p)) { - if (title.Right(1) == L')') { - // probably already contains shorturl - p = title; - } else { - CString shorturl = ShortenURL(p, targetlen, true); - p.Format(_T("%s (%s)"), static_cast(title), static_cast(shorturl)); - } - } else { - CString fn = PathUtils::StripPathOrUrl(p); - if (fn.GetLength() > targetlen) { // If file name is too long, cut middle part. - int l = fn.GetLength(); - fn.Format(_T("%s~~~%s"), static_cast(fn.Left(l / 2 - 2 + (l % 2))), static_cast(fn.Right(l / 2 - 1))); - } - p.Format(_T("%s (%s)"), static_cast(title), static_cast(fn)); - } - } - else { - if (PathUtils::IsURL(p)) { - p = ShortenURL(p, 150); - } - if (p.GetLength() > 150) { - p.Format(_T("%s~~~%s"), static_cast(p.Left(60)), static_cast(p.Right(87))); - } - } - p.Replace(_T("&"), _T("&&")); - VERIFY(subMenu.AppendMenu(flags, id, p)); - } else { - ASSERT(false); - } - id++; - } - } -} - -void CMainFrame::SetupFavoritesSubMenu() -{ - CMenu& subMenu = m_favoritesMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - const CAppSettings& s = AfxGetAppSettings(); - - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_FAVORITES_ADD, ResStr(IDS_FAVORITES_ADD))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_FAVORITES_ORGANIZE, ResStr(IDS_FAVORITES_ORGANIZE))); - - UINT nLastGroupStart = subMenu.GetMenuItemCount(); - UINT id = ID_FAVORITES_FILE_START; - CAtlList favs; - AfxGetAppSettings().GetFav(FAV_FILE, favs); - POSITION pos = favs.GetHeadPosition(); - - while (pos) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - - CString f_str = favs.GetNext(pos); - f_str.Replace(_T("&"), _T("&&")); - f_str.Replace(_T("\t"), _T(" ")); - - FileFavorite ff; - VERIFY(FileFavorite::TryParse(f_str, ff)); - - f_str = ff.Name; - - CString str = ff.ToString(); - if (!str.IsEmpty()) { - f_str.AppendFormat(_T("\t%s"), str.GetString()); - } - - if (!f_str.IsEmpty()) { - VERIFY(subMenu.AppendMenu(flags, id, f_str)); - } - - id++; - if (id > ID_FAVORITES_FILE_END) { - break; - } - } - - if (id > ID_FAVORITES_FILE_START) { - VERIFY(subMenu.InsertMenu(nLastGroupStart, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); - } - - nLastGroupStart = subMenu.GetMenuItemCount(); - - id = ID_FAVORITES_DVD_START; - s.GetFav(FAV_DVD, favs); - pos = favs.GetHeadPosition(); - - while (pos) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - - CString str = favs.GetNext(pos); - str.Replace(_T("&"), _T("&&")); - - CAtlList sl; - ExplodeEsc(str, sl, _T(';'), 2); - - str = sl.RemoveHead(); - - if (!sl.IsEmpty()) { - // TODO - } - - if (!str.IsEmpty()) { - VERIFY(subMenu.AppendMenu(flags, id, str)); - } - - id++; - if (id > ID_FAVORITES_DVD_END) { - break; - } - } - - if (id > ID_FAVORITES_DVD_START) { - VERIFY(subMenu.InsertMenu(nLastGroupStart, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); - } - - nLastGroupStart = subMenu.GetMenuItemCount(); - - id = ID_FAVORITES_DEVICE_START; - - s.GetFav(FAV_DEVICE, favs); - - pos = favs.GetHeadPosition(); - while (pos) { - UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; - - CString str = favs.GetNext(pos); - str.Replace(_T("&"), _T("&&")); - - CAtlList sl; - ExplodeEsc(str, sl, _T(';'), 2); - - str = sl.RemoveHead(); - - if (!str.IsEmpty()) { - VERIFY(subMenu.AppendMenu(flags, id, str)); - } - - id++; - if (id > ID_FAVORITES_DEVICE_END) { - break; - } - } -} - -bool CMainFrame::SetupShadersSubMenu() -{ - const auto& s = AfxGetAppSettings(); - - CMenu& subMenu = m_shadersMenu; - // Empty the menu - while (subMenu.RemoveMenu(0, MF_BYPOSITION)); - - if (!(s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC - || s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS || s.iDSVideoRendererType == VIDRNDT_DS_MADVR || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR)) { - return false; - } - - subMenu.AppendMenu(MF_BYCOMMAND | MF_STRING | MF_ENABLED, ID_PRESIZE_SHADERS_TOGGLE, ResStr(IDS_PRESIZE_SHADERS_TOGGLE)); - subMenu.AppendMenu(MF_BYCOMMAND | MF_STRING | MF_ENABLED, ID_POSTSIZE_SHADERS_TOGGLE, ResStr(IDS_POSTSIZE_SHADERS_TOGGLE)); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_SHADERS_SELECT, ResStr(IDS_SHADERS_SELECT))); - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_VIEW_DEBUGSHADERS, ResStr(IDS_SHADERS_DEBUG))); - - auto presets = s.m_Shaders.GetPresets(); - if (!presets.empty()) { - CString current; - bool selected = s.m_Shaders.GetCurrentPresetName(current); - VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); - UINT nID = ID_SHADERS_PRESETS_START; - for (const auto& pair : presets) { - if (nID > ID_SHADERS_PRESETS_END) { - // too many presets - ASSERT(FALSE); - break; - } - VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, nID, pair.first)); - if (selected && pair.first == current) { - VERIFY(subMenu.CheckMenuRadioItem(nID, nID, nID, MF_BYCOMMAND)); - selected = false; - } - nID++; - } - } - return true; -} - -///////////// - -void CMainFrame::SetAlwaysOnTop(int iOnTop) -{ - CAppSettings& s = AfxGetAppSettings(); - - if (!IsFullScreenMode()) { - const CWnd* pInsertAfter = nullptr; - - if (iOnTop == 0) { - // We only want to disable "On Top" once so that - // we don't interfere with other window manager - if (s.iOnTop || !alwaysOnTopZOrderInitialized) { - pInsertAfter = &wndNoTopMost; - alwaysOnTopZOrderInitialized = true; - } - } else if (iOnTop == 1) { - pInsertAfter = &wndTopMost; - } else if (iOnTop == 2) { - pInsertAfter = (GetMediaState() == State_Running) ? &wndTopMost : &wndNoTopMost; - } else { // if (iOnTop == 3) - pInsertAfter = (GetMediaState() == State_Running && !m_fAudioOnly) ? &wndTopMost : &wndNoTopMost; - } - - if (pInsertAfter) { - SetWindowPos(pInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); - } - } - - s.iOnTop = iOnTop; -} - -bool CMainFrame::WindowExpectedOnTop() { - return (AfxGetAppSettings().iOnTop == 1 || - (AfxGetAppSettings().iOnTop == 2 && GetMediaState() == State_Running) || - (AfxGetAppSettings().iOnTop == 3 && GetMediaState() == State_Running && !m_fAudioOnly)); -} - -void CMainFrame::AddTextPassThruFilter() -{ - BeginEnumFilters(m_pGB, pEF, pBF) { - if (!IsSplitter(pBF)) { - continue; - } - - BeginEnumPins(pBF, pEP, pPin) { - CComPtr pPinTo; - AM_MEDIA_TYPE mt; - if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo - && SUCCEEDED(pPin->ConnectionMediaType(&mt)) - && (mt.majortype == MEDIATYPE_Text || mt.majortype == MEDIATYPE_Subtitle)) { - InsertTextPassThruFilter(pBF, pPin, pPinTo); - } - } - EndEnumPins; - } - EndEnumFilters; -} - -HRESULT CMainFrame::InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinTo) -{ - HRESULT hr; - CComQIPtr pTPTF = DEBUG_NEW CTextPassThruFilter(this); - CStringW name; - name.Format(L"TextPassThru%p", static_cast(pTPTF)); - if (FAILED(hr = m_pGB->AddFilter(pTPTF, name))) { - return hr; - } - - OAFilterState fs = GetMediaState(); - if (fs == State_Running || fs == State_Paused) { - MediaControlStop(true); - } - - hr = pPinTo->Disconnect(); - hr = pPin->Disconnect(); - - if (FAILED(hr = m_pGB->ConnectDirect(pPin, GetFirstPin(pTPTF, PINDIR_INPUT), nullptr)) - || FAILED(hr = m_pGB->ConnectDirect(GetFirstPin(pTPTF, PINDIR_OUTPUT), pPinTo, nullptr))) { - hr = m_pGB->ConnectDirect(pPin, pPinTo, nullptr); - } else { - SubtitleInput subInput(CComQIPtr(pTPTF), pBF); - m_pSubStreams.AddTail(subInput); - } - - if (fs == State_Running) { - MediaControlRun(); - } else if (fs == State_Paused) { - MediaControlPause(); - } - - return hr; -} - -bool CMainFrame::LoadSubtitle(CString fn, SubtitleInput* pSubInput /*= nullptr*/, bool bAutoLoad /*= false*/) -{ - CAppSettings& s = AfxGetAppSettings(); - CComQIPtr pSubStream; - - if (!s.IsISRAutoLoadEnabled() && (FindFilter(CLSID_VSFilter, m_pGB) || FindFilter(CLSID_XySubFilter, m_pGB))) { - // Prevent ISR from loading if VSFilter is already in graph. - // TODO: Support VSFilter natively (see ticket #4122) - // Note that this doesn't affect ISR auto-loading if any sub renderer force loading itself into the graph. - // VSFilter like filters can be blocked when building the graph and ISR auto-loading is enabled but some - // users don't want that. - return false; - } - - if (GetPlaybackMode() == PM_FILE && !s.fDisableInternalSubtitles && !FindFilter(__uuidof(CTextPassThruFilter), m_pGB)) { - // Add TextPassThru filter if it isn't already in the graph. (i.e ISR hasn't been loaded before) - // This will load all embedded subtitle tracks when user triggers ISR (load external subtitle file) for the first time. - AddTextPassThruFilter(); - } - - CString videoName; - if (GetPlaybackMode() == PM_FILE) { - videoName = m_wndPlaylistBar.GetCurFileName(); - } - - CString ext = CPath(fn).GetExtension().MakeLower(); - - if (!pSubStream && (ext == _T(".idx") || !bAutoLoad && ext == _T(".sub"))) { - CAutoPtr pVSF(DEBUG_NEW CVobSubFile(&m_csSubLock)); - if (pVSF && pVSF->Open(fn) && pVSF->GetStreamCount() > 0) { - pSubStream = pVSF.Detach(); - } - } - - if (!pSubStream && ext != _T(".idx") && ext != _T(".sup")) { - CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); - if (pRTS) { - if (pRTS->Open(fn, DEFAULT_CHARSET, _T(""), videoName) && pRTS->GetStreamCount() > 0) { -#if USE_LIBASS - if (pRTS->m_LibassContext.IsLibassActive()) { - pRTS->m_LibassContext.SetFilterGraph(m_pGB); - } -#endif - pSubStream = pRTS.Detach(); - } - } - } - - if (!pSubStream) { - CAutoPtr pPSF(DEBUG_NEW CPGSSubFile(&m_csSubLock)); - if (pPSF && pPSF->Open(fn, _T(""), videoName) && pPSF->GetStreamCount() > 0) { - pSubStream = pPSF.Detach(); - } - } - - if (pSubStream) { - SubtitleInput subInput(pSubStream); - m_ExternalSubstreams.push_back(pSubStream); - m_pSubStreams.AddTail(subInput); - - // Temporarily load fonts from 'Fonts' folder - Begin - CString path = PathUtils::DirName(fn) + L"\\fonts\\"; - ExtendMaxPathLengthIfNeeded(path); - - if (::PathIsDirectory(path)) { - WIN32_FIND_DATA fd = {0}; - HANDLE hFind; - - hFind = FindFirstFile(path + L"*.?t?", &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - CStringW ext = GetFileExt(fd.cFileName); - if (ext == ".ttf" || ext == ".otf" || ext == ".ttc") { - m_FontInstaller.InstallTempFontFile(path + fd.cFileName); - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - } - // Temporarily load fonts from 'Fonts' folder - End - - if (!m_posFirstExtSub) { - m_posFirstExtSub = m_pSubStreams.GetTailPosition(); - } - - if (pSubInput) { - *pSubInput = subInput; - } - - if (!bAutoLoad) { - m_wndPlaylistBar.AddSubtitleToCurrent(fn); - if (s.fKeepHistory) { - s.MRU.AddSubToCurrent(fn); - } - } - } - - return !!pSubStream; -} - -bool CMainFrame::LoadSubtitle(CYoutubeDLInstance::YDLSubInfo& sub) { - CAppSettings& s = AfxGetAppSettings(); - CComQIPtr pSubStream; - CAtlList preferlist; - if (!s.sYDLSubsPreference.IsEmpty()) { - if (s.sYDLSubsPreference.Find(_T(',')) != -1) { - ExplodeMin(s.sYDLSubsPreference, preferlist, ','); - } else { - ExplodeMin(s.sYDLSubsPreference, preferlist, ' '); - } - } - if (!preferlist.IsEmpty() && !CYoutubeDLInstance::isPrefer(preferlist, sub.lang)) { - return false; - } - - if (!s.IsISRAutoLoadEnabled() && (FindFilter(CLSID_VSFilter, m_pGB) || FindFilter(CLSID_XySubFilter, m_pGB))) { - // Prevent ISR from loading if VSFilter is already in graph. - // TODO: Support VSFilter natively (see ticket #4122) - // Note that this doesn't affect ISR auto-loading if any sub renderer force loading itself into the graph. - // VSFilter like filters can be blocked when building the graph and ISR auto-loading is enabled but some - // users don't want that. - return false; - } - - if (GetPlaybackMode() == PM_FILE && !s.fDisableInternalSubtitles && !FindFilter(__uuidof(CTextPassThruFilter), m_pGB)) { - // Add TextPassThru filter if it isn't already in the graph. (i.e ISR hasn't been loaded before) - // This will load all embedded subtitle tracks when user triggers ISR (load external subtitle file) for the first time. - AddTextPassThruFilter(); - } - - CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); - if (pRTS) { - bool opened = false; - if (!sub.url.IsEmpty()) { - SubtitlesProvidersUtils::stringMap strmap{}; - DWORD dwStatusCode; - CT2CA tem(sub.url); - std::string tem2(tem); - std::string data(""); - SubtitlesProvidersUtils::StringDownload(tem2, strmap, data, true, &dwStatusCode); - if (dwStatusCode != 200) { - return false; - } - if (sub.ext.IsEmpty()) { - int m2(sub.url.ReverseFind(_T('?'))); - int m3(sub.url.ReverseFind(_T('#'))); - int m = -1; - if (m2 > -1 && m3 > -1) m = std::min(m2, m3); - else if (m2 > -1) m = m2; - else if (m3 > -1) m = m3; - CString temp(sub.url); - if (m > 0) temp = sub.url.Left(m); - m = temp.ReverseFind(_T('.')); - if (m >= 0) sub.ext = temp.Mid(m + 1); - } - CString langt = sub.isAutomaticCaptions ? sub.lang + _T("[Automatic]") : sub.lang; - opened = pRTS->Open((BYTE*)data.c_str(), (int)data.length(), DEFAULT_CHARSET, _T("YoutubeDL"), langt, sub.ext); - } else if (!sub.data.IsEmpty()) { - CString langt = sub.isAutomaticCaptions ? sub.lang + _T("[Automatic]") : sub.lang; - opened = pRTS->Open(sub.data, CTextFile::enc::UTF8, DEFAULT_CHARSET, _T("YoutubeDL"), langt, sub.ext); // Do not modify charset, Now it wroks with Unicode char. - } - if (opened && pRTS->GetStreamCount() > 0) { -#if USE_LIBASS - if (pRTS->m_LibassContext.IsLibassActive()) { - pRTS->m_LibassContext.SetFilterGraph(m_pGB); - } -#endif - pSubStream = pRTS.Detach(); - } - } - - if (pSubStream) { - SubtitleInput subInput(pSubStream); - m_ExternalSubstreams.push_back(pSubStream); - m_pSubStreams.AddTail(subInput); - - if (!m_posFirstExtSub) { - m_posFirstExtSub = m_pSubStreams.GetTailPosition(); - } - } - - return !!pSubStream; -} - -// Called from GraphThread -bool CMainFrame::SetSubtitle(int i, bool bIsOffset /*= false*/, bool bDisplayMessage /*= false*/) -{ - if (!m_pCAP) { - return false; - } - if (GetLoadState() == MLS::CLOSING) { - return false; - } - - CAppSettings& s = AfxGetAppSettings(); - - SubtitleInput* pSubInput = nullptr; - if (m_iReloadSubIdx >= 0) { - pSubInput = GetSubtitleInput(m_iReloadSubIdx); - if (pSubInput) { - i = m_iReloadSubIdx; - } - m_iReloadSubIdx = -1; - } - - if (!pSubInput) { - pSubInput = GetSubtitleInput(i, bIsOffset); - } - - bool success = false; - - if (pSubInput) { - CComHeapPtr pName; - if (CComQIPtr pSSF = pSubInput->pSourceFilter) { - DWORD dwFlags; - LCID lcid = 0; - if (FAILED(pSSF->Info(i, nullptr, &dwFlags, &lcid, nullptr, &pName, nullptr, nullptr))) { - dwFlags = 0; - } - if (lcid && s.fEnableSubtitles) { - currentSubLang = ISOLang::GetLocaleStringCompat(lcid); - } else { - currentSubLang.Empty(); - } - - // Enable the track only if it isn't already the only selected track in the group - if (!(dwFlags & AMSTREAMSELECTINFO_EXCLUSIVE)) { - pSSF->Enable(i, AMSTREAMSELECTENABLE_ENABLE); - } - i = 0; - } - { - // m_csSubLock shouldn't be locked when using IAMStreamSelect::Enable or SetSubtitle - CAutoLock cAutoLock(&m_csSubLock); - pSubInput->pSubStream->SetStream(i); - } - SetSubtitle(*pSubInput, true); - - if (!pName) { - LCID lcid = 0; - pSubInput->pSubStream->GetStreamInfo(0, &pName, &lcid); - if (lcid && s.fEnableSubtitles) { - currentSubLang = ISOLang::GetLocaleStringCompat(lcid); - } else { - currentSubLang.Empty(); - } - } - - if (bDisplayMessage && pName) { - m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pName), LCID(-1), 2)); - } - success = true; - } - - if (success && s.fKeepHistory && s.bRememberTrackSelection) { - s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); - } - return success; -} - -void CMainFrame::UpdateSubtitleColorInfo() -{ - if (!m_pCAP || !m_pCurrentSubInput.pSubStream) { - return; - } - - // store video mediatype, so colorspace information can be extracted when present - // FIXME: mediatype extended colorinfo may be absent on initial connection, call this again after first frame has been decoded? - CComQIPtr pBF = m_pCAP; - CComPtr pPin = GetFirstPin(pBF); - if (pPin) { - AM_MEDIA_TYPE mt; - if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - m_pCAP->SetVideoMediaType(CMediaType(mt)); - } - } - - CComQIPtr pSRO = m_pCAP; - - LPWSTR yuvMatrix = nullptr; - int nLen; - if (m_pMVRI) { - m_pMVRI->GetString("yuvMatrix", &yuvMatrix, &nLen); - } else if (pSRO) { - pSRO->GetString("yuvMatrix", &yuvMatrix, &nLen); - } - - int targetBlackLevel = 0, targetWhiteLevel = 255; - if (m_pMVRS) { - m_pMVRS->SettingsGetInteger(L"Black", &targetBlackLevel); - m_pMVRS->SettingsGetInteger(L"White", &targetWhiteLevel); - } else if (pSRO) { - int range = 0; - pSRO->GetInt("supportedLevels", &range); - if (range == 3) { - targetBlackLevel = 16; - targetWhiteLevel = 235; - } - } - - m_pCurrentSubInput.pSubStream->SetSourceTargetInfo(yuvMatrix, targetBlackLevel, targetWhiteLevel); - LocalFree(yuvMatrix); -} - -void CMainFrame::SetSubtitle(const SubtitleInput& subInput, bool skip_lcid /* = false */) -{ - TRACE(_T("CMainFrame::SetSubtitle\n")); - - CAppSettings& s = AfxGetAppSettings(); - ResetSubtitlePosAndSize(false); - - { - CAutoLock cAutoLock(&m_csSubLock); - - bool firstuse = !m_pCurrentSubInput.pSubStream; - - if (subInput.pSubStream) { - bool found = false; - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - if (subInput.pSubStream == m_pSubStreams.GetNext(pos).pSubStream) { - found = true; - break; - } - } - // We are trying to set a subtitles stream that isn't in the list so we abort here. - if (!found) { - return; - } - } - - if (m_pCAP && m_pCurrentSubInput.pSubStream && m_pCurrentSubInput.pSubStream != subInput.pSubStream) { - m_pCAP->SetSubPicProvider(nullptr); - } - - m_pCurrentSubInput = subInput; - - UpdateSubtitleRenderingParameters(); - - if (firstuse) { - // note: can deadlock when calling ConnectionMediaType() with MPCVR when SubPicProvider!=nullptr - UpdateSubtitleColorInfo(); - } - - if (!skip_lcid) { - LCID lcid = 0; - if (m_pCurrentSubInput.pSubStream && s.fEnableSubtitles) { - CComHeapPtr pName; - m_pCurrentSubInput.pSubStream->GetStreamInfo(0, &pName, &lcid); - } - if (lcid) { - GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentSubLang); - } else { - currentSubLang.Empty(); - } - } - - if (m_pCAP) { - g_bExternalSubtitle = (std::find(m_ExternalSubstreams.cbegin(), m_ExternalSubstreams.cend(), subInput.pSubStream) != m_ExternalSubstreams.cend()); - bool use_subresync = false; - if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { -#if USE_LIBASS - if (!pRTS->m_LibassContext.IsLibassActive()) -#endif - use_subresync = true; - } - if (use_subresync) { - m_wndSubresyncBar.SetSubtitle(subInput.pSubStream, m_pCAP->GetFPS(), g_bExternalSubtitle); - } else { - m_wndSubresyncBar.SetSubtitle(nullptr, m_pCAP->GetFPS(), g_bExternalSubtitle); - } - } - } - - if (m_pCAP && s.fEnableSubtitles) { - m_pCAP->SetSubPicProvider(CComQIPtr(subInput.pSubStream)); - } - - if (s.fKeepHistory && s.bRememberTrackSelection) { - s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); - } -} - -void CMainFrame::OnAudioShiftOnOff() -{ - AfxGetAppSettings().fAudioTimeShift = !AfxGetAppSettings().fAudioTimeShift; -} - -void CMainFrame::ToggleSubtitleOnOff(bool bDisplayMessage /*= false*/) -{ - if (m_pDVS) { - bool bHideSubtitles = false; - m_pDVS->get_HideSubtitles(&bHideSubtitles); - bHideSubtitles = !bHideSubtitles; - m_pDVS->put_HideSubtitles(bHideSubtitles); - } - if (m_pCAP && (!m_pDVS || !m_pSubStreams.IsEmpty())) { - CAppSettings& s = AfxGetAppSettings(); - s.fEnableSubtitles = !s.fEnableSubtitles; - - if (s.fEnableSubtitles) { - SetSubtitle(0, true, bDisplayMessage); - } else { - if (m_pCAP) { - m_pCAP->SetSubPicProvider(nullptr); - } - currentSubLang = ResStr(IDS_AG_DISABLED); - - if (bDisplayMessage) { - m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_SUBTITLE_STREAM_OFF)); - } - } - } -} - -void CMainFrame::ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew) -{ - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - POSITION cur = pos; - if (pSubStreamOld == m_pSubStreams.GetNext(pos).pSubStream) { - m_pSubStreams.GetAt(cur).pSubStream = pSubStreamNew; - if (m_pCurrentSubInput.pSubStream == pSubStreamOld) { - SetSubtitle(m_pSubStreams.GetAt(cur), true); - } - break; - } - } -} - -void CMainFrame::InvalidateSubtitle(DWORD_PTR nSubtitleId /*= DWORD_PTR_MAX*/, REFERENCE_TIME rtInvalidate /*= -1*/) -{ - if (m_pCAP) { - if (nSubtitleId == DWORD_PTR_MAX || nSubtitleId == (DWORD_PTR)(ISubStream*)m_pCurrentSubInput.pSubStream) { - m_pCAP->Invalidate(rtInvalidate); - } - } -} - -void CMainFrame::ReloadSubtitle() -{ - { - CAutoLock cAutoLock(&m_csSubLock); - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - m_pSubStreams.GetNext(pos).pSubStream->Reload(); - } - } - - ResetSubtitlePosAndSize(false); - - SetSubtitle(0, true); - m_wndSubresyncBar.ReloadSubtitle(); -} - -void CMainFrame::SetSubtitleTrackIdx(int index) -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (GetLoadState() == MLS::LOADED && m_pCAP) { - // Check if we want to change the enable/disable state - if (s.fEnableSubtitles != (index >= 0)) { - ToggleSubtitleOnOff(); - } - // Set the new subtitles track if needed - if (s.fEnableSubtitles) { - SetSubtitle(index); - } - } -} - -void CMainFrame::SetAudioTrackIdx(int index) -{ - if (GetLoadState() == MLS::LOADED) { - DWORD cStreams = 0; - DWORD dwFlags = AMSTREAMSELECTENABLE_ENABLE; - if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { - if ((index >= 0) && (index < ((int)cStreams))) { - m_pAudioSwitcherSS->Enable(index, dwFlags); - - m_loadedAudioTrackIndex = index; - LCID lcid = 0; - AM_MEDIA_TYPE* pmt = nullptr; - CComHeapPtr pszName; - if (SUCCEEDED(m_pAudioSwitcherSS->Info(index, &pmt, &dwFlags, &lcid, nullptr, &pszName, nullptr, nullptr))) { - m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pszName), lcid, 1)); - UpdateSelectedAudioStreamInfo(index, pmt, lcid); - DeleteMediaType(pmt); - } - } - } - // ToDo: use m_pSplitterSS - } -} - -int CMainFrame::GetCurrentAudioTrackIdx(CString *pstrName) -{ - if(pstrName) - pstrName->Empty(); - - if (GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_FILE && m_pGB) { - DWORD cStreams = 0; - if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { - for (int i = 0; i < (int)cStreams; i++) { - DWORD dwFlags = 0; - CComHeapPtr pName; - if (SUCCEEDED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, nullptr, &pName, nullptr, nullptr))) { - if (dwFlags & AMSTREAMSELECTINFO_ENABLED) { - if(pstrName) - *pstrName = pName; - ASSERT(m_loadedAudioTrackIndex == i); - return i; - } - } else { - break; - } - } - } - // ToDo: use m_pSplitterSS - } - return -1; -} - -int CMainFrame::GetCurrentSubtitleTrackIdx(CString *pstrName) -{ - if(pstrName) - pstrName->Empty(); - - if (GetLoadState() != MLS::LOADED) { - return -1; - } - - if (m_pCAP && !m_pSubStreams.IsEmpty()) { - int idx = 0; - POSITION pos = m_pSubStreams.GetHeadPosition(); - while (pos) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - if (CComQIPtr pSSF = subInput.pSourceFilter) { - DWORD cStreams; - if (FAILED(pSSF->Count(&cStreams))) { - continue; - } - for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { - DWORD dwFlags, dwGroup; - CComHeapPtr pName; - if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, &pName, nullptr, nullptr))) { - continue; - } - if (dwGroup != 2) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - if (pstrName) - *pstrName = pName; - return idx; - } - } - idx++; - } - } else { - CComPtr pSubStream = subInput.pSubStream; - if (!pSubStream) { - continue; - } - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - if (pstrName) { - CComHeapPtr pName; - pSubStream->GetStreamInfo(pSubStream->GetStream(), &pName, nullptr); - *pstrName = pName; - } - return idx + pSubStream->GetStream(); - } - idx += pSubStream->GetStreamCount(); - } - } - } else if (m_pSplitterSS) { - DWORD cStreams; - if (SUCCEEDED(m_pSplitterSS->Count(&cStreams))) { - int idx = 0; - for (int i = 0; i < (int)cStreams; i++) { - DWORD dwFlags, dwGroup; - CComHeapPtr pszName; - - if (FAILED(m_pSplitterSS->Info(i, nullptr, &dwFlags, nullptr, &dwGroup, &pszName, nullptr, nullptr))) - continue; - - if (dwGroup != 2) - continue; - - if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - if (pstrName) - *pstrName = pszName; - return idx; - } - - idx++; - } - } - } - - return -1; -} - -REFERENCE_TIME CMainFrame::GetPos() const -{ - return (GetLoadState() == MLS::LOADED ? m_wndSeekBar.GetPos() : 0); -} - -REFERENCE_TIME CMainFrame::GetDur() const -{ - __int64 start, stop; - m_wndSeekBar.GetRange(start, stop); - return (GetLoadState() == MLS::LOADED ? stop : 0); -} - -void CMainFrame::LoadKeyFrames() -{ - UINT nKFs = 0; - m_kfs.clear(); - if (m_pKFI && S_OK == m_pKFI->GetKeyFrameCount(nKFs) && nKFs > 1) { - UINT k = nKFs; - m_kfs.resize(k); - if (FAILED(m_pKFI->GetKeyFrames(&TIME_FORMAT_MEDIA_TIME, m_kfs.data(), k)) || k != nKFs) { - m_kfs.clear(); - } - } -} - -bool CMainFrame::GetKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMin, REFERENCE_TIME rtMax, bool nearest, REFERENCE_TIME& keyframetime) const -{ - ASSERT(rtTarget >= rtMin); - ASSERT(rtTarget <= rtMax); - if (!m_kfs.empty()) { - const auto cbegin = m_kfs.cbegin(); - const auto cend = m_kfs.cend(); - ASSERT(std::is_sorted(cbegin, cend)); - - auto foundkeyframe = std::lower_bound(cbegin, cend, rtTarget); - - if (foundkeyframe == cbegin) { - // first keyframe - keyframetime = *foundkeyframe; - if ((keyframetime < rtMin) || (keyframetime > rtMax)) { - keyframetime = rtTarget; - return false; - } - } else if (foundkeyframe == cend) { - // last keyframe - keyframetime = *(--foundkeyframe); - if (keyframetime < rtMin) { - keyframetime = rtTarget; - return false; - } - } else { - keyframetime = *foundkeyframe; - if (keyframetime == rtTarget) { - return true; - } - if (keyframetime > rtMax) { - // use preceding keyframe - keyframetime = *(--foundkeyframe); - if (keyframetime < rtMin) { - keyframetime = rtTarget; - return false; - } - } else { - if (nearest) { - const auto& s = AfxGetAppSettings(); - if (s.eFastSeekMethod == s.FASTSEEK_NEAREST_KEYFRAME) { - // use closest keyframe - REFERENCE_TIME prev_keyframetime = *(--foundkeyframe); - if ((prev_keyframetime >= rtMin)) { - if ((keyframetime - rtTarget) > (rtTarget - prev_keyframetime)) { - keyframetime = prev_keyframetime; - } - } - } - } - } - } - return true; - } else { - keyframetime = rtTarget; - } - return false; -} - -REFERENCE_TIME CMainFrame::GetClosestKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMaxForwardDiff, REFERENCE_TIME rtMaxBackwardDiff) const -{ - if (rtTarget < 0LL) return 0LL; - if (rtTarget > GetDur()) return rtTarget; - - REFERENCE_TIME rtKeyframe; - REFERENCE_TIME rtMin = std::max(rtTarget - rtMaxBackwardDiff, 0LL); - REFERENCE_TIME rtMax = rtTarget + rtMaxForwardDiff; - - if (GetKeyFrame(rtTarget, rtMin, rtMax, true, rtKeyframe)) { - return rtKeyframe; - } - return rtTarget; -} - -REFERENCE_TIME CMainFrame::GetClosestKeyFramePreview(REFERENCE_TIME rtTarget) const -{ - return GetClosestKeyFrame(rtTarget, 200000000LL, 200000000LL); -} - -void CMainFrame::SeekTo(REFERENCE_TIME rtPos, bool bShowOSD /*= true*/) -{ - if (m_pMS == nullptr) { - return; - } - ASSERT(lastSeekFinish >= lastSeekStart); // ToDo: remove lastSeekStart variable if no regressions show up - ULONGLONG curTime = GetTickCount64(); - ULONGLONG ticksSinceLastSeek = curTime - lastSeekFinish; - ULONGLONG mindelay = (lastSeekFinish - lastSeekStart) > 40ULL ? 100ULL : 40ULL; - //ASSERT(rtPos != queuedSeek.rtPos || queuedSeek.seekTime == 0 || (curTime < queuedSeek.seekTime + 500ULL)); - - if (ticksSinceLastSeek < mindelay) { - //TRACE(_T("Delay seek: %lu %lu\n"), rtPos, ticksSinceLastSeek); - queuedSeek = { rtPos, curTime, bShowOSD }; - SetTimer(TIMER_DELAYEDSEEK, (UINT) (mindelay * 1.25 - ticksSinceLastSeek), nullptr); - } else { - KillTimerDelayedSeek(); - lastSeekStart = curTime; - DoSeekTo(rtPos, bShowOSD); - lastSeekFinish = GetTickCount64(); - } -} - -void CMainFrame::DoSeekTo(REFERENCE_TIME rtPos, bool bShowOSD /*= true*/) -{ - //TRACE(_T("DoSeekTo: %lu\n"), rtPos); - - ASSERT(m_pMS != nullptr); - if (m_pMS == nullptr) { - return; - } - OAFilterState fs = GetMediaState(); - - if (rtPos < 0) { - rtPos = 0; - } - - if (abRepeat.positionA && rtPos < abRepeat.positionA || abRepeat.positionB && rtPos > abRepeat.positionB) { - DisableABRepeat(); - } - - if (m_fFrameSteppingActive) { - // Cancel pending frame steps - m_pFS->CancelStep(); - m_fFrameSteppingActive = false; - if (m_pBA) { - m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); - } - } - m_nStepForwardCount = 0; - - // skip seeks when duration is unknown - if (!m_wndSeekBar.HasDuration()) { - return; - } - - if (!IsPlaybackCaptureMode()) { - __int64 start, stop; - m_wndSeekBar.GetRange(start, stop); - if (rtPos > stop) { - rtPos = stop; - } - m_wndStatusBar.SetStatusTimer(rtPos, stop, IsSubresyncBarVisible(), GetTimeFormat()); - - if (bShowOSD) { - m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 1500); - } - } - - if (GetPlaybackMode() == PM_FILE) { - if (fs == State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - - //SleepEx(5000, False); // artificial slow seek for testing purposes - if (FAILED(m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning))) { - TRACE(_T("IMediaSeeking SetPositions failure\n")); - if (abRepeat.positionA && rtPos == abRepeat.positionA) { - DisableABRepeat(); - } - } - UpdateChapterInInfoBar(); - } else if (GetPlaybackMode() == PM_DVD && m_iDVDDomain == DVD_DOMAIN_Title) { - if (fs == State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - fs = State_Paused; - } - - const REFTIME refAvgTimePerFrame = GetAvgTimePerFrame(); - if (fs == State_Paused) { - // Jump one more frame back, this is needed because we don't have any other - // way to seek to specific time without running playback to refresh state. - rtPos -= std::llround(refAvgTimePerFrame * 10000000i64); - m_pFS->CancelStep(); - } - - DVD_HMSF_TIMECODE tc = RT2HMSF(rtPos, (1.0 / refAvgTimePerFrame)); - m_pDVDC->PlayAtTime(&tc, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); - - if (fs == State_Paused) { - // Do frame step to update current position in paused state - m_pFS->Step(1, nullptr); - } - } else { - ASSERT(FALSE); - } - m_fEndOfStream = false; - - OnTimer(TIMER_STREAMPOSPOLLER); - OnTimer(TIMER_STREAMPOSPOLLER2); - - SendCurrentPositionToApi(true); -} - -void CMainFrame::CleanGraph() -{ - if (!m_pGB) { - return; - } - - BeginEnumFilters(m_pGB, pEF, pBF) { - CComQIPtr pAMMF(pBF); - if (pAMMF && (pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE)) { - continue; - } - - // some capture filters forget to set AM_FILTER_MISC_FLAGS_IS_SOURCE - // or to implement the IAMFilterMiscFlags interface - if (pBF == m_pVidCap || pBF == m_pAudCap) { - continue; - } - - // XySubFilter doesn't have any pins connected when it is reading - // external subtitles - if (GetCLSID(pBF) == CLSID_XySubFilter) { - continue; - } - - if (CComQIPtr(pBF)) { - continue; - } - - int nIn, nOut, nInC, nOutC; - if (CountPins(pBF, nIn, nOut, nInC, nOutC) > 0 && (nInC + nOutC) == 0) { - TRACE(CStringW(L"Removing: ") + GetFilterName(pBF) + '\n'); - - m_pGB->RemoveFilter(pBF); - pEF->Reset(); - } - } - EndEnumFilters; -} - -#define AUDIOBUFFERLEN 500 - -static void SetLatency(IBaseFilter* pBF, int cbBuffer) -{ - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pAMBN = pPin) { - ALLOCATOR_PROPERTIES ap; - ap.cbAlign = -1; // -1 means no preference. - ap.cbBuffer = cbBuffer; - ap.cbPrefix = -1; - ap.cBuffers = -1; - pAMBN->SuggestAllocatorProperties(&ap); - } - } - EndEnumPins; -} - -HRESULT CMainFrame::BuildCapture(IPin* pPin, IBaseFilter* pBF[3], const GUID& majortype, AM_MEDIA_TYPE* pmt) -{ - IBaseFilter* pBuff = pBF[0]; - IBaseFilter* pEnc = pBF[1]; - IBaseFilter* pMux = pBF[2]; - - if (!pPin || !pMux) { - return E_FAIL; - } - - CString err; - HRESULT hr = S_OK; - CFilterInfo fi; - - if (FAILED(pMux->QueryFilterInfo(&fi)) || !fi.pGraph) { - m_pGB->AddFilter(pMux, L"Multiplexer"); - } - - CStringW prefix; - CString type; - if (majortype == MEDIATYPE_Video) { - prefix = L"Video "; - type.LoadString(IDS_CAPTURE_ERROR_VIDEO); - } else if (majortype == MEDIATYPE_Audio) { - prefix = L"Audio "; - type.LoadString(IDS_CAPTURE_ERROR_AUDIO); - } - - if (pBuff) { - hr = m_pGB->AddFilter(pBuff, prefix + L"Buffer"); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_ADD_BUFFER, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - - hr = m_pGB->ConnectFilter(pPin, pBuff); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_CONNECT_BUFF, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - - pPin = GetFirstPin(pBuff, PINDIR_OUTPUT); - } - - if (pEnc) { - hr = m_pGB->AddFilter(pEnc, prefix + L"Encoder"); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_ADD_ENCODER, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - - hr = m_pGB->ConnectFilter(pPin, pEnc); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_CONNECT_ENC, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - - pPin = GetFirstPin(pEnc, PINDIR_OUTPUT); - - if (CComQIPtr pAMSC = pPin) { - if (pmt->majortype == majortype) { - hr = pAMSC->SetFormat(pmt); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_COMPRESSION, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - } - } - - } - - //if (pMux) - { - hr = m_pGB->ConnectFilter(pPin, pMux); - if (FAILED(hr)) { - err.Format(IDS_CAPTURE_ERROR_MULTIPLEXER, type.GetString()); - MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return hr; - } - } - - CleanGraph(); - - return S_OK; -} - -bool CMainFrame::BuildToCapturePreviewPin( - IBaseFilter* pVidCap, IPin** ppVidCapPin, IPin** ppVidPrevPin, - IBaseFilter* pAudCap, IPin** ppAudCapPin, IPin** ppAudPrevPin) -{ - HRESULT hr; - *ppVidCapPin = *ppVidPrevPin = nullptr; - *ppAudCapPin = *ppAudPrevPin = nullptr; - CComPtr pDVAudPin; - - if (pVidCap) { - CComPtr pPin; - if (!pAudCap // only look for interleaved stream when we don't use any other audio capture source - && SUCCEEDED(m_pCGB->FindPin(pVidCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, TRUE, 0, &pPin))) { - CComPtr pDVSplitter; - hr = pDVSplitter.CoCreateInstance(CLSID_DVSplitter); - hr = m_pGB->AddFilter(pDVSplitter, L"DV Splitter"); - - hr = m_pCGB->RenderStream(nullptr, &MEDIATYPE_Interleaved, pPin, nullptr, pDVSplitter); - - pPin = nullptr; - hr = m_pCGB->FindPin(pDVSplitter, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Video, TRUE, 0, &pPin); - hr = m_pCGB->FindPin(pDVSplitter, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Audio, TRUE, 0, &pDVAudPin); - - CComPtr pDVDec; - hr = pDVDec.CoCreateInstance(CLSID_DVVideoCodec); - hr = m_pGB->AddFilter(pDVDec, L"DV Video Decoder"); - - hr = m_pGB->ConnectFilter(pPin, pDVDec); - - pPin = nullptr; - hr = m_pCGB->FindPin(pDVDec, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Video, TRUE, 0, &pPin); - } else if (FAILED(m_pCGB->FindPin(pVidCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, TRUE, 0, &pPin))) { - MessageBox(ResStr(IDS_CAPTURE_ERROR_VID_CAPT_PIN), ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return false; - } - - CComPtr pSmartTee; - hr = pSmartTee.CoCreateInstance(CLSID_SmartTee); - hr = m_pGB->AddFilter(pSmartTee, L"Smart Tee (video)"); - - hr = m_pGB->ConnectFilter(pPin, pSmartTee); - - hr = pSmartTee->FindPin(L"Preview", ppVidPrevPin); - hr = pSmartTee->FindPin(L"Capture", ppVidCapPin); - } - - if (pAudCap || pDVAudPin) { - CComPtr pPin; - if (pDVAudPin) { - pPin = pDVAudPin; - } else if (FAILED(m_pCGB->FindPin(pAudCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, TRUE, 0, &pPin))) { - MessageBox(ResStr(IDS_CAPTURE_ERROR_AUD_CAPT_PIN), ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); - return false; - } - - CComPtr pSmartTee; - hr = pSmartTee.CoCreateInstance(CLSID_SmartTee); - hr = m_pGB->AddFilter(pSmartTee, L"Smart Tee (audio)"); - - hr = m_pGB->ConnectFilter(pPin, pSmartTee); - - hr = pSmartTee->FindPin(L"Preview", ppAudPrevPin); - hr = pSmartTee->FindPin(L"Capture", ppAudCapPin); - } - - return true; -} - -bool CMainFrame::BuildGraphVideoAudio(int fVPreview, bool fVCapture, int fAPreview, bool fACapture) -{ - if (!m_pCGB) { - return false; - } - - OAFilterState fs = GetMediaState(); - - if (fs != State_Stopped) { - SendMessage(WM_COMMAND, ID_PLAY_STOP); - } - - HRESULT hr; - - m_pGB->NukeDownstream(m_pVidCap); - m_pGB->NukeDownstream(m_pAudCap); - - CleanGraph(); - - if (m_pAMVSCCap) { - hr = m_pAMVSCCap->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv); - } - if (m_pAMVSCPrev) { - hr = m_pAMVSCPrev->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv); - } - if (m_pAMASC) { - hr = m_pAMASC->SetFormat(&m_wndCaptureBar.m_capdlg.m_mta); - } - - CComPtr pVidBuffer = m_wndCaptureBar.m_capdlg.m_pVidBuffer; - CComPtr pAudBuffer = m_wndCaptureBar.m_capdlg.m_pAudBuffer; - CComPtr pVidEnc = m_wndCaptureBar.m_capdlg.m_pVidEnc; - CComPtr pAudEnc = m_wndCaptureBar.m_capdlg.m_pAudEnc; - CComPtr pMux = m_wndCaptureBar.m_capdlg.m_pMux; - CComPtr pDst = m_wndCaptureBar.m_capdlg.m_pDst; - CComPtr pAudMux = m_wndCaptureBar.m_capdlg.m_pAudMux; - CComPtr pAudDst = m_wndCaptureBar.m_capdlg.m_pAudDst; - - bool fFileOutput = (pMux && pDst) || (pAudMux && pAudDst); - bool fCapture = (fVCapture || fACapture); - - if (m_pAudCap) { - AM_MEDIA_TYPE* pmt = &m_wndCaptureBar.m_capdlg.m_mta; - int ms = (fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput) ? AUDIOBUFFERLEN : 60; - if (pMux != pAudMux && fACapture) { - SetLatency(m_pAudCap, -1); - } else if (pmt->pbFormat) { - SetLatency(m_pAudCap, ((WAVEFORMATEX*)pmt->pbFormat)->nAvgBytesPerSec * ms / 1000); - } - } - - CComPtr pVidCapPin, pVidPrevPin, pAudCapPin, pAudPrevPin; - BuildToCapturePreviewPin(m_pVidCap, &pVidCapPin, &pVidPrevPin, m_pAudCap, &pAudCapPin, &pAudPrevPin); - - //if (m_pVidCap) - { - bool fVidPrev = pVidPrevPin && fVPreview; - bool fVidCap = pVidCapPin && fVCapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fVidOutput; - - if (fVPreview == 2 && !fVidCap && pVidCapPin) { - pVidPrevPin = pVidCapPin; - pVidCapPin = nullptr; - } - - if (fVidPrev) { - m_pMVRS.Release(); - m_pMVRFG.Release(); - m_pMVRSR.Release(); - - m_OSD.Stop(); - m_pCAP3.Release(); - m_pCAP2.Release(); - m_pCAP.Release(); - m_pVMRWC.Release(); - m_pVMRMC.Release(); - m_pVMB.Release(); - m_pMFVMB.Release(); - m_pMFVP.Release(); - m_pMFVDC.Release(); - m_pQP.Release(); - - m_pGB->Render(pVidPrevPin); - - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP2), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP3), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRWC), FALSE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRMC), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMB), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVMB), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVDC), TRUE); - m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVP), TRUE); - m_pMVTO = m_pCAP; - m_pMVRSR = m_pCAP; - m_pMVRS = m_pCAP; - m_pMVRFG = m_pCAP; - - const CAppSettings& s = AfxGetAppSettings(); - m_pVideoWnd = &m_wndView; - - if (m_pMFVDC) { - m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); - } else if (m_pVMRWC) { - m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); - } - - if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is used - m_OSD.Stop(); - - if (m_pMVTO) { - m_OSD.Start(m_pVideoWnd, m_pMVTO); - } else if (m_fFullScreen && !m_fAudioOnly && m_pCAP3) { // MPCVR - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); - } else if (!m_fAudioOnly && IsD3DFullScreenMode() && (m_pVMB || m_pMFVMB)) { - m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); - } else { - m_OSD.Start(m_pOSDWnd); - } - } - } - - if (fVidCap) { - IBaseFilter* pBF[3] = {pVidBuffer, pVidEnc, pMux}; - HRESULT hr2 = BuildCapture(pVidCapPin, pBF, MEDIATYPE_Video, &m_wndCaptureBar.m_capdlg.m_mtcv); - UNREFERENCED_PARAMETER(hr2); - } - - m_pAMDF.Release(); - if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMDF)))) { - TRACE(_T("Warning: No IAMDroppedFrames interface for vidcap capture")); - } - } - - //if (m_pAudCap) - { - bool fAudPrev = pAudPrevPin && fAPreview; - bool fAudCap = pAudCapPin && fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput; - - if (fAPreview == 2 && !fAudCap && pAudCapPin) { - pAudPrevPin = pAudCapPin; - pAudCapPin = nullptr; - } - - if (fAudPrev) { - m_pGB->Render(pAudPrevPin); - } - - if (fAudCap) { - IBaseFilter* pBF[3] = {pAudBuffer, pAudEnc, pAudMux ? pAudMux : pMux}; - HRESULT hr2 = BuildCapture(pAudCapPin, pBF, MEDIATYPE_Audio, &m_wndCaptureBar.m_capdlg.m_mtca); - UNREFERENCED_PARAMETER(hr2); - } - } - - if ((m_pVidCap || m_pAudCap) && fCapture && fFileOutput) { - if (pMux != pDst) { - hr = m_pGB->AddFilter(pDst, L"File Writer V/A"); - hr = m_pGB->ConnectFilter(GetFirstPin(pMux, PINDIR_OUTPUT), pDst); - } - - if (CComQIPtr pCAM = pMux) { - int nIn, nOut, nInC, nOutC; - CountPins(pMux, nIn, nOut, nInC, nOutC); - pCAM->SetMasterStream(nInC - 1); - //pCAM->SetMasterStream(-1); - pCAM->SetOutputCompatibilityIndex(FALSE); - } - - if (CComQIPtr pCI = pMux) { - //if (FAILED(pCI->put_Mode(INTERLEAVE_CAPTURE))) - if (FAILED(pCI->put_Mode(INTERLEAVE_NONE_BUFFERED))) { - pCI->put_Mode(INTERLEAVE_NONE); - } - - REFERENCE_TIME rtInterleave = 10000i64 * AUDIOBUFFERLEN, rtPreroll = 0; //10000i64*500 - pCI->put_Interleaving(&rtInterleave, &rtPreroll); - } - - if (pMux != pAudMux && pAudMux != pAudDst) { - hr = m_pGB->AddFilter(pAudDst, L"File Writer A"); - hr = m_pGB->ConnectFilter(GetFirstPin(pAudMux, PINDIR_OUTPUT), pAudDst); - } - } - - REFERENCE_TIME stop = MAX_TIME; - hr = m_pCGB->ControlStream(&PIN_CATEGORY_CAPTURE, nullptr, nullptr, nullptr, &stop, 0, 0); // stop in the infinite - - CleanGraph(); - - OpenSetupVideo(); - OpenSetupAudio(); - OpenSetupStatsBar(); - OpenSetupStatusBar(); - RecalcLayout(); - - SetupVMR9ColorControl(); - - if (GetLoadState() == MLS::LOADED) { - if (fs == State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } else if (fs == State_Paused) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - } - - return true; -} - -bool CMainFrame::StartCapture() -{ - if (!m_pCGB || m_fCapturing) { - return false; - } - - if (!m_wndCaptureBar.m_capdlg.m_pMux && !m_wndCaptureBar.m_capdlg.m_pDst) { - return false; - } - - HRESULT hr; - - ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); - - // rare to see two capture filters to support IAMPushSource at the same time... - //hr = CComQIPtr(m_pGB)->SyncUsingStreamOffset(TRUE); // TODO: - - BuildGraphVideoAudio( - m_wndCaptureBar.m_capdlg.m_fVidPreview, true, - m_wndCaptureBar.m_capdlg.m_fAudPreview, true); - - hr = m_pME->CancelDefaultHandling(EC_REPAINT); - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - m_fCapturing = true; - - return true; -} - -bool CMainFrame::StopCapture() -{ - if (!m_pCGB || !m_fCapturing) { - return false; - } - - if (!m_wndCaptureBar.m_capdlg.m_pMux && !m_wndCaptureBar.m_capdlg.m_pDst) { - return false; - } - - m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_COMPLETING)); - m_fCapturing = false; - - BuildGraphVideoAudio( - m_wndCaptureBar.m_capdlg.m_fVidPreview, false, - m_wndCaptureBar.m_capdlg.m_fAudPreview, false); - - m_pME->RestoreDefaultHandling(EC_REPAINT); - - ::SetPriorityClass(::GetCurrentProcess(), AfxGetAppSettings().dwPriority); - - m_rtDurationOverride = -1; - - return true; -} - -// - -void CMainFrame::ShowOptions(int idPage/* = 0*/) -{ - // Disable the options dialog when using D3D fullscreen - if (IsD3DFullScreenMode() && !m_bFullScreenWindowIsOnSeparateDisplay) { - return; - } - - // show warning when INI file is read-only - CPath iniPath = AfxGetMyApp()->GetIniPath(); - if (PathUtils::Exists(iniPath)) { - HANDLE hFile = CreateFile(iniPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - if (hFile == INVALID_HANDLE_VALUE) { - AfxMessageBox(_T("The player settings are currently stored in an INI file located in the installation directory of the player.\n\nThe player currently does not have write access to this file, meaning any changes to the settings will not be saved.\n\nPlease remove the INI file to ensure proper functionality of the player.\n\nSettings will then be stored in the Windows Registry. You can easily backup those settings through: Options > Miscellaneous > Export"), MB_ICONWARNING, 0); - } - CloseHandle(hFile); - } - - INT_PTR iRes; - do { - CPPageSheet options(ResStr(IDS_OPTIONS_CAPTION), m_pGB, GetModalParent(), idPage); - iRes = options.DoModal(); - idPage = 0; // If we are to show the dialog again, always show the latest page - } while (iRes == CPPageSheet::APPLY_LANGUAGE_CHANGE); // check if we exited the dialog so that the language change can be applied - - switch (iRes) { - case CPPageSheet::RESET_SETTINGS: - // Request MPC-HC to close itself - SendMessage(WM_CLOSE); - // and immediately reopen - ShellExecute(nullptr, _T("open"), PathUtils::GetProgramPath(true), _T("/reset"), nullptr, SW_SHOWNORMAL); - break; - default: - ASSERT(iRes > 0 && iRes != CPPageSheet::APPLY_LANGUAGE_CHANGE); - break; - } -} - -void CMainFrame::StartWebServer(int nPort) -{ - if (!m_pWebServer) { - m_pWebServer.Attach(DEBUG_NEW CWebServer(this, nPort)); - } -} - -void CMainFrame::StopWebServer() -{ - if (m_pWebServer) { - m_pWebServer.Free(); - } -} - -void CMainFrame::SendStatusMessage(CString msg, int nTimeOut) -{ - const auto timerId = TimerOneTimeSubscriber::STATUS_ERASE; - - m_timerOneTime.Unsubscribe(timerId); - - m_tempstatus_msg.Empty(); - if (nTimeOut <= 0) { - return; - } - - m_tempstatus_msg = msg; - m_timerOneTime.Subscribe(timerId, [this] { m_tempstatus_msg.Empty(); }, nTimeOut); - - m_Lcd.SetStatusMessage(msg, nTimeOut); -} - -bool CMainFrame::CanPreviewUse() { - return (m_bUseSeekPreview && m_wndPreView && !m_fAudioOnly && m_eMediaLoadState == MLS::LOADED - && (GetPlaybackMode() == PM_DVD || GetPlaybackMode() == PM_FILE)); -} - -void CMainFrame::OpenCurPlaylistItem(REFERENCE_TIME rtStart, bool reopen /* = false */, ABRepeat abRepeat /* = ABRepeat() */) -{ - if (IsPlaylistEmpty()) { - return; - } - - CPlaylistItem pli; - if (!m_wndPlaylistBar.GetCur(pli)) { - m_wndPlaylistBar.SetFirstSelected(); - if (!m_wndPlaylistBar.GetCur(pli)) { - return; - } - } - - if (pli.m_bYoutubeDL && (reopen || pli.m_fns.GetHead() == pli.m_ydlSourceURL && m_sydlLastProcessURL != pli.m_ydlSourceURL)) { - if (ProcessYoutubeDLURL(pli.m_ydlSourceURL, false, true)) { - OpenCurPlaylistItem(rtStart, false); - return; - } - } - - CAutoPtr p(m_wndPlaylistBar.GetCurOMD(rtStart, abRepeat)); - if (p) { - OpenMedia(p); - } -} - -void CMainFrame::AddCurDevToPlaylist() -{ - if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - m_wndPlaylistBar.Append( - m_VidDispName, - m_AudDispName, - m_wndCaptureBar.m_capdlg.GetVideoInput(), - m_wndCaptureBar.m_capdlg.GetVideoChannel(), - m_wndCaptureBar.m_capdlg.GetAudioInput() - ); - } -} - -void CMainFrame::OpenMedia(CAutoPtr pOMD) -{ - auto pFileData = dynamic_cast(pOMD.m_p); - //auto pDVDData = dynamic_cast(pOMD.m_p); - auto pDeviceData = dynamic_cast(pOMD.m_p); - - // if the tuner graph is already loaded, we just change its channel - if (pDeviceData) { - if (GetLoadState() == MLS::LOADED && m_pAMTuner - && m_VidDispName == pDeviceData->DisplayName[0] && m_AudDispName == pDeviceData->DisplayName[1]) { - m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput); - m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel); - m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput); - SendNowPlayingToSkype(); - return; - } - } - - CloseMediaBeforeOpen(); - - // if the file is on some removable drive and that drive is missing, - // we yell at user before even trying to construct the graph - if (pFileData) { - CString fn = pFileData->fns.GetHead(); - int i = fn.Find(_T(":\\")); - if (i > 0) { - CString drive = fn.Left(i + 2); - UINT type = GetDriveType(drive); - CAtlList sl; - if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM && GetOpticalDiskType(drive[0], sl) != OpticalDisk_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.GetString()); - ret = AfxMessageBox(msg, MB_RETRYCANCEL); - } - } - if (ret != IDOK) { - return; - } - } - } - } - - ASSERT(!m_bOpenMediaActive); - m_bOpenMediaActive = true; - - // clear BD playlist if we are not currently opening something from it - if (!m_bIsBDPlay) { - m_MPLSPlaylist.clear(); - m_LastOpenBDPath = _T(""); - } - m_bIsBDPlay = false; - - // no need to try releasing external objects while playing - KillTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS); - - // we hereby proclaim - SetLoadState(MLS::LOADING); - - const auto& s = AfxGetAppSettings(); - - // use the graph thread only for some media types - bool bDirectShow = pFileData && !pFileData->fns.IsEmpty() && s.m_Formats.GetEngine(pFileData->fns.GetHead()) == DirectShow; - bool bUseThread = m_pGraphThread && s.fEnableWorkerThreadForOpening && (bDirectShow || !pFileData) && (s.iDefaultCaptureDevice == 1 || !pDeviceData); - bool wasMaximized = IsZoomed(); - // create d3dfs window if launching in fullscreen and d3dfs is enabled - if (s.IsD3DFullscreen() && m_fStartInD3DFullscreen) { - CreateFullScreenWindow(); - m_pVideoWnd = m_pDedicatedFSVideoWnd; - m_fStartInD3DFullscreen = false; - } else if (m_fStartInFullscreenSeparate) { - CreateFullScreenWindow(false); - m_pVideoWnd = m_pDedicatedFSVideoWnd; - m_fStartInFullscreenSeparate = false; - m_bNeedZoomAfterFullscreenExit = true; - } else { - m_pVideoWnd = &m_wndView; - } - - // activate auto-fit logic upon exiting fullscreen if - // we are opening new media in fullscreen mode - // adipose: unless we were previously maximized - if ((IsFullScreenMode()) && s.fRememberZoomLevel && !wasMaximized) { - m_bNeedZoomAfterFullscreenExit = true; - } - - // don't set video renderer output rect until the window is repositioned - m_bDelaySetOutputRect = true; - -#if 0 - // display corresponding media icon in status bar - if (pFileData) { - CString filename = m_wndPlaylistBar.GetCurFileName(); - CString ext = filename.Mid(filename.ReverseFind('.') + 1); - m_wndStatusBar.SetMediaType(ext); - } else if (pDVDData) { - m_wndStatusBar.SetMediaType(_T(".ifo")); - } else { - // TODO: Create icons for pDeviceData - m_wndStatusBar.SetMediaType(_T(".unknown")); - } -#endif - - // initiate graph creation, OpenMediaPrivate() will call OnFilePostOpenmedia() - if (bUseThread) { - VERIFY(m_evOpenPrivateFinished.Reset()); - VERIFY(m_pGraphThread->PostThreadMessage(CGraphThread::TM_OPEN, (WPARAM)0, (LPARAM)pOMD.Detach())); - m_bOpenedThroughThread = true; - } else { - OpenMediaPrivate(pOMD); - m_bOpenedThroughThread = false; - } -} - -bool CMainFrame::ResetDevice() -{ - if (m_pCAP2_preview) { - m_pCAP2_preview->ResetDevice(); - } - if (m_pCAP) { - return m_pCAP->ResetDevice(); - } - return true; -} - -bool CMainFrame::DisplayChange() -{ - if (m_pCAP2_preview) { - m_pCAP2_preview->DisplayChange(); - } - if (m_pCAP) { - return m_pCAP->DisplayChange(); - } - return true; -} - -void CMainFrame::CloseMediaBeforeOpen() -{ - if (GetLoadState() != MLS::CLOSED) { - CloseMedia(true); - } -} - -void CMainFrame::ForceCloseProcess() -{ - MessageBeep(MB_ICONEXCLAMATION); - if (CrashReporter::IsEnabled()) { - CrashReporter::Disable(); - } - TerminateProcess(GetCurrentProcess(), 0xDEADBEEF); -} - -void CMainFrame::CloseMedia(bool bNextIsQueued/* = false*/, bool bPendingFileDelete/* = false*/) -{ - TRACE(_T("CMainFrame::CloseMedia\n")); - - m_dwLastPause = 0; - - if (m_bUseSeekPreview && m_wndPreView.IsWindowVisible()) { - m_wndPreView.ShowWindow(SW_HIDE); - } - m_bUseSeekPreview = false; - m_bDVDStillOn = false; - - if (GetLoadState() == MLS::CLOSING || GetLoadState() == MLS::CLOSED) { - TRACE(_T("Ignoring duplicate close action.\n")); - return; - } - - m_media_trans_control.close(); - - if (m_bSettingUpMenus) { - SleepEx(500, false); - ASSERT(!m_bSettingUpMenus); - } - - auto& s = AfxGetAppSettings(); - bool savehistory = false; - if (GetLoadState() == MLS::LOADED) { - // abort sub search - m_pSubtitlesProviders->Abort(SubtitlesThreadType(STT_SEARCH | STT_DOWNLOAD)); - m_wndSubtitlesDownloadDialog.DoClear(); - - // save playback position - if (s.fKeepHistory && !bPendingFileDelete) { - if (m_bRememberFilePos && !m_fEndOfStream && m_dwReloadPos == 0 && m_pMS) { - REFERENCE_TIME rtNow = 0; - m_pMS->GetCurrentPosition(&rtNow); - if (rtNow > 0) { - REFERENCE_TIME rtDur = 0; - m_pMS->GetDuration(&rtDur); - if (rtNow >= rtDur || rtDur - rtNow < 50000000LL) { // at end of file - rtNow = 0; - } - } - s.MRU.UpdateCurrentFilePosition(rtNow, true); - } else if (GetPlaybackMode() == PM_DVD && m_pDVDI) { - DVD_DOMAIN DVDDomain; - if (SUCCEEDED(m_pDVDI->GetCurrentDomain(&DVDDomain))) { - if (DVDDomain == DVD_DOMAIN_Title) { - DVD_PLAYBACK_LOCATION2 Location2; - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location2))) { - DVD_POSITION dvdPosition = s.MRU.GetCurrentDVDPosition(); - if (dvdPosition.llDVDGuid) { - dvdPosition.lTitle = Location2.TitleNum; - dvdPosition.timecode = Location2.TimeCode; - } - } - } - } - } - } - - if (m_pME) { - m_pME->SetNotifyWindow(NULL, 0, 0); - } - - // save external subtitle - if (g_bExternalSubtitle && !bPendingFileDelete && - m_pCurrentSubInput.pSubStream && m_pCurrentSubInput.pSubStream->GetPath().IsEmpty()) { - const auto& s = AfxGetAppSettings(); - if (s.bAutoSaveDownloadedSubtitles) { - CString dirBuffer; - LPCTSTR dir = nullptr; - if (!s.strSubtitlePaths.IsEmpty()) { - auto start = s.strSubtitlePaths.Left(2); - if (start != _T(".") && start != _T(".;")) { - int pos = 0; - dir = dirBuffer = s.strSubtitlePaths.Tokenize(_T(";"), pos); - } - } - SubtitlesSave(dir, true); - } - } - - if (s.fKeepHistory && !bPendingFileDelete) { - savehistory = true; - } - } - - // delay showing auto-hidden controls if new media is queued - if (bNextIsQueued) { - m_controls.DelayShowNotLoaded(true); - } else { - m_controls.DelayShowNotLoaded(false); - } - - // abort if loading - bool bGraphTerminated = false; - if (GetLoadState() == MLS::LOADING) { - TRACE(_T("Media is still loading. Aborting graph.\n")); - - // tell OpenMediaPrivate() that we want to abort - m_fOpeningAborted = true; - - // close pin connection error dialog - if (mediaTypesErrorDlg) { - mediaTypesErrorDlg->SendMessage(WM_EXTERNALCLOSE, 0, 0); - // wait till error dialog has been closed - CAutoLock lck(&lockModalDialog); - } - - // abort current graph task - if (m_pGB) { - if (!m_pAMOP) { - m_pAMOP = m_pGB; - if (!m_pAMOP) { - BeginEnumFilters(m_pGB, pEF, pBF) - if (m_pAMOP = pBF) { - break; - } - EndEnumFilters; - } - } - if (m_pAMOP) { - m_pAMOP->AbortOperation(); - } - m_pGB->Abort(); // TODO: lock on graph objects somehow, this is not thread safe - } - if (m_pGB_preview) { - m_pGB_preview->Abort(); - } - - if (m_bOpenedThroughThread) { - BeginWaitCursor(); - MSG msg; - HANDLE h = m_evOpenPrivateFinished; - bool killprocess = true; - bool processmsg = true; - ULONGLONG start = GetTickCount64(); - while (processmsg && (GetTickCount64() - start < 6000ULL)) { - DWORD res = MsgWaitForMultipleObjectsEx(1, &h, 1000, QS_ALLINPUT, MWMO_INPUTAVAILABLE); - switch (res) { - case WAIT_OBJECT_0: - TRACE(_T("Graph abort successful\n")); - killprocess = false; // event has been signalled - processmsg = false; - break; - case WAIT_OBJECT_0 + 1: - // we have a message - peek and dispatch it - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - break; - case WAIT_TIMEOUT: - break; - default: // unexpected failure - processmsg = false; - break; - } - } - if (killprocess) - { - // Aborting graph failed - TRACE(_T("Failed to abort graph creation.\n")); - ForceCloseProcess(); - } - EndWaitCursor(); - } else { - // Aborting graph failed - TRACE(_T("Failed to abort graph creation.\n")); - ForceCloseProcess(); - } - - MSG msg; - // purge possible queued OnFilePostOpenmedia() - if (PeekMessage(&msg, m_hWnd, WM_POSTOPEN, WM_POSTOPEN, PM_REMOVE | PM_NOYIELD)) { - free((OpenMediaData*)msg.lParam); - } - // purge possible queued OnOpenMediaFailed() - if (PeekMessage(&msg, m_hWnd, WM_OPENFAILED, WM_OPENFAILED, PM_REMOVE | PM_NOYIELD)) { - free((OpenMediaData*)msg.lParam); - } - - // abort finished, unset the flag - m_fOpeningAborted = false; - } - - // we are on the way - m_bSettingUpMenus = true; - SetLoadState(MLS::CLOSING); - - if (m_pGB_preview) { - PreviewWindowHide(); - m_bUseSeekPreview = false; - } - - // stop the graph before destroying it - OnPlayStop(true); - - // clear any active osd messages - //m_OSD.ClearMessage(); - - // Ensure the dynamically added menu items are cleared and all references - // on objects belonging to the DirectShow graph they might hold are freed. - // Note that we need to be in closing state already when doing that - if (m_hWnd) { - SetupFiltersSubMenu(); - SetupAudioSubMenu(); - SetupSubtitlesSubMenu(); - SetupVideoStreamsSubMenu(); - SetupJumpToSubMenus(); - } - - m_bSettingUpMenus = false; - - // initiate graph destruction - if (m_pGraphThread && m_bOpenedThroughThread && !bGraphTerminated) { - // either opening or closing has to be blocked to prevent reentering them, closing is the better choice - VERIFY(m_evClosePrivateFinished.Reset()); - VERIFY(m_pGraphThread->PostThreadMessage(CGraphThread::TM_CLOSE, (WPARAM)0, (LPARAM)0)); - - HANDLE handle = m_evClosePrivateFinished; - DWORD dwWait; - ULONGLONG start = GetTickCount64(); - ULONGLONG waitdur = 10000ULL; - bool killprocess = true; - bool processmsg = true; - bool extendedwait = false; - while (processmsg) { - dwWait = MsgWaitForMultipleObjects(1, &handle, FALSE, 1000, QS_SENDMESSAGE); - switch (dwWait) { - case WAIT_OBJECT_0: - processmsg = false; // event received - killprocess = false; - break; - case WAIT_OBJECT_0 + 1: - MSG msg; - PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE); - break; - case WAIT_TIMEOUT: - break; - default: - processmsg = false; - break; - } - - if (processmsg && (GetTickCount64() - start > waitdur)) { - if (extendedwait || m_fFullScreen) { - processmsg = false; - } else { - CString msg; - if (!m_pGB && m_pGB_preview) { -#if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER && (MPC_VERSION_REV > 10) && 0 - if (CrashReporter::IsEnabled()) { - throw 1; - } -#endif - msg = L"Timeout when closing preview filter graph.\n\nClick YES to terminate player process. Click NO to wait longer (up to 15 seconds)."; - } else { - msg = L"Timeout when closing filter graph.\n\nClick YES to terminate player process. Click NO to wait longer (up to 15 seconds)."; - } - if (IDYES == AfxMessageBox(msg, MB_ICONEXCLAMATION | MB_YESNO, 0)) { - processmsg = false; - } else { - extendedwait = true; - start = GetTickCount64(); - waitdur = 15000ULL; - } - } - } - } - if (killprocess) { - TRACE(_T("Failed to close filter graph thread.\n")); - ForceCloseProcess(); - } - } else { - CloseMediaPrivate(); - } - - // graph is destroyed, update stuff - OnFilePostClosemedia(bNextIsQueued); - - if (savehistory) { - s.MRU.WriteCurrentEntry(); - } - s.MRU.current_rfe_hash.Empty(); - - TRACE(_T("Close media completed\n")); -} - -void CMainFrame::StartTunerScan(CAutoPtr pTSD) -{ - // Remove the old info during the scan - if (m_pDVBState) { - m_pDVBState->Reset(); - } - m_wndInfoBar.RemoveAllLines(); - m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); - RecalcLayout(); - OpenSetupWindowTitle(); - SendNowPlayingToSkype(); - - if (m_pGraphThread) { - m_pGraphThread->PostThreadMessage(CGraphThread::TM_TUNER_SCAN, (WPARAM)0, (LPARAM)pTSD.Detach()); - } else { - DoTunerScan(pTSD); - } -} - -void CMainFrame::StopTunerScan() -{ - m_bStopTunerScan = true; -} - -HRESULT CMainFrame::SetChannel(int nChannel) -{ - CAppSettings& s = AfxGetAppSettings(); - HRESULT hr = S_OK; - CComQIPtr pTun = m_pGB; - CBDAChannel* pChannel = s.FindChannelByPref(nChannel); - - if (s.m_DVBChannels.empty() && nChannel == INT_ERROR) { - hr = S_FALSE; // All channels have been cleared or it is the first start - } else if (pTun && pChannel && !m_pDVBState->bSetChannelActive) { - m_pDVBState->Reset(); - m_wndInfoBar.RemoveAllLines(); - m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); - RecalcLayout(); - m_pDVBState->bSetChannelActive = true; - - // Skip n intermediate ZoomVideoWindow() calls while the new size is stabilized: - switch (s.iDSVideoRendererType) { - case VIDRNDT_DS_MADVR: - if (s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS) { - m_nLockedZoomVideoWindow = 3; - } else { - m_nLockedZoomVideoWindow = 0; - } - break; - case VIDRNDT_DS_EVR_CUSTOM: - m_nLockedZoomVideoWindow = 0; - break; - default: - m_nLockedZoomVideoWindow = 0; - } - if (SUCCEEDED(hr = pTun->SetChannel(nChannel))) { - if (hr == S_FALSE) { - // Re-create all - m_nLockedZoomVideoWindow = 0; - PostMessage(WM_COMMAND, ID_FILE_OPENDEVICE); - return hr; - } - - m_pDVBState->bActive = true; - m_pDVBState->pChannel = pChannel; - m_pDVBState->sChannelName = pChannel->GetName(); - - m_wndInfoBar.SetLine(ResStr(IDS_INFOBAR_CHANNEL), m_pDVBState->sChannelName); - RecalcLayout(); - - if (s.fRememberZoomLevel && !(m_fFullScreen || IsZoomed() || IsIconic())) { - ZoomVideoWindow(); - } - MoveVideoWindow(); - - // Add temporary flag to allow EC_VIDEO_SIZE_CHANGED event to stabilize window size - // for 5 seconds since playback starts - m_bAllowWindowZoom = true; - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::AUTOFIT_TIMEOUT, [this] - { m_bAllowWindowZoom = false; }, 5000); - - UpdateCurrentChannelInfo(); - } - m_pDVBState->bSetChannelActive = false; - } else { - hr = E_FAIL; - ASSERT(FALSE); - } - - return hr; -} - -void CMainFrame::UpdateCurrentChannelInfo(bool bShowOSD /*= true*/, bool bShowInfoBar /*= false*/) -{ - const CBDAChannel* pChannel = m_pDVBState->pChannel; - CComQIPtr pTun = m_pGB; - - if (!m_pDVBState->bInfoActive && pChannel && pTun) { - if (m_pDVBState->infoData.valid()) { - m_pDVBState->bAbortInfo = true; - m_pDVBState->infoData.get(); - } - m_pDVBState->bAbortInfo = false; - m_pDVBState->bInfoActive = true; - m_pDVBState->infoData = std::async(std::launch::async, [this, pChannel, pTun, bShowOSD, bShowInfoBar] { - DVBState::EITData infoData; - infoData.hr = pTun->UpdatePSI(pChannel, infoData.NowNext); - infoData.bShowOSD = bShowOSD; - infoData.bShowInfoBar = bShowInfoBar; - if (m_pDVBState && !m_pDVBState->bAbortInfo) - { - PostMessage(WM_DVB_EIT_DATA_READY); - } - return infoData; - }); - } -} - -LRESULT CMainFrame::OnCurrentChannelInfoUpdated(WPARAM wParam, LPARAM lParam) -{ - if (!m_pDVBState->bAbortInfo && m_pDVBState->infoData.valid()) { - EventDescriptor& NowNext = m_pDVBState->NowNext; - const auto infoData = m_pDVBState->infoData.get(); - NowNext = infoData.NowNext; - - if (infoData.hr != S_FALSE) { - // Set a timer to update the infos only if channel has now/next flag - time_t tNow; - time(&tNow); - time_t tElapse = NowNext.duration - (tNow - NowNext.startTime); - if (tElapse < 0) { - tElapse = 0; - } - // We set a 15s delay to let some room for the program infos to change - tElapse += 15; - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DVBINFO_UPDATE, - [this] { UpdateCurrentChannelInfo(false, false); }, - 1000 * (UINT)tElapse); - m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(true); - } else { - m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); - } - - CString sChannelInfo = m_pDVBState->sChannelName; - m_wndInfoBar.RemoveAllLines(); - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CHANNEL), sChannelInfo); - - if (infoData.hr == S_OK) { - // EIT information parsed correctly - if (infoData.bShowOSD) { - sChannelInfo.AppendFormat(_T(" | %s (%s - %s)"), NowNext.eventName.GetString(), NowNext.strStartTime.GetString(), NowNext.strEndTime.GetString()); - } - - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TITLE), NowNext.eventName); - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TIME), NowNext.strStartTime + _T(" - ") + NowNext.strEndTime); - - if (NowNext.parentalRating >= 0) { - CString parentRating; - if (!NowNext.parentalRating) { - parentRating.LoadString(IDS_NO_PARENTAL_RATING); - } else { - parentRating.Format(IDS_PARENTAL_RATING, NowNext.parentalRating); - } - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_PARENTAL_RATING), parentRating); - } - - if (!NowNext.content.IsEmpty()) { - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CONTENT), NowNext.content); - } - - CString description = NowNext.eventDesc; - if (!NowNext.extendedDescriptorsText.IsEmpty()) { - if (!description.IsEmpty()) { - description += _T("; "); - } - description += NowNext.extendedDescriptorsText; - } - m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); - - for (const auto& item : NowNext.extendedDescriptorsItems) { - m_wndInfoBar.SetLine(item.first, item.second); - } - - if (infoData.bShowInfoBar && !m_controls.ControlChecked(CMainFrameControls::Toolbar::INFO)) { - m_controls.ToggleControl(CMainFrameControls::Toolbar::INFO); - } - } - - RecalcLayout(); - if (infoData.bShowOSD) { - m_OSD.DisplayMessage(OSD_TOPLEFT, sChannelInfo, 3500); - } - - // Update window title and skype status - OpenSetupWindowTitle(); - SendNowPlayingToSkype(); - } else { - ASSERT(FALSE); - } - - m_pDVBState->bInfoActive = false; - - return 0; -} - -// ==== Added by CASIMIR666 -void CMainFrame::SetLoadState(MLS eState) -{ - m_eMediaLoadState = eState; - SendAPICommand(CMD_STATE, L"%d", static_cast(eState)); - if (eState == MLS::LOADED) { - m_controls.DelayShowNotLoaded(false); - m_eventc.FireEvent(MpcEvent::MEDIA_LOADED); - } - UpdateControlState(UPDATE_CONTROLS_VISIBILITY); -} - -inline MLS CMainFrame::GetLoadState() const -{ - return m_eMediaLoadState; -} - -void CMainFrame::SetPlayState(MPC_PLAYSTATE iState) -{ - m_Lcd.SetPlayState((CMPC_Lcd::PlayState)iState); - SendAPICommand(CMD_PLAYMODE, L"%d", iState); - - if (m_fEndOfStream) { - SendAPICommand(CMD_NOTIFYENDOFSTREAM, L"\0"); // do not pass NULL here! - } - - if (iState == PS_PLAY) { - // Prevent sleep when playing audio and/or video, but allow screensaver when only audio - if (!m_fAudioOnly && AfxGetAppSettings().bPreventDisplaySleep) { - SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED); - } else { - SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); - } - } else { - SetThreadExecutionState(ES_CONTINUOUS); - } - - - UpdateThumbarButton(iState); -} - -bool CMainFrame::CreateFullScreenWindow(bool isD3D /* = true */) -{ - if (m_bFullScreenWindowIsD3D == isD3D && HasDedicatedFSVideoWindow()) { - return false; - } - const CAppSettings& s = AfxGetAppSettings(); - CMonitors monitors; - CMonitor monitor, currentMonitor; - - if (m_pDedicatedFSVideoWnd->IsWindow()) { - m_pDedicatedFSVideoWnd->DestroyWindow(); - } - - currentMonitor = monitors.GetNearestMonitor(this); - if (s.iMonitor == 0) { - monitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); - } - if (!monitor.IsMonitor()) { - monitor = currentMonitor; - } - - CRect monitorRect; - monitor.GetMonitorRect(monitorRect); - - m_bFullScreenWindowIsD3D = isD3D; - m_bFullScreenWindowIsOnSeparateDisplay = monitor != currentMonitor; - - // allow the mainframe to keep focus - bool ret = !!m_pDedicatedFSVideoWnd->CreateEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, _T(""), ResStr(IDS_MAINFRM_136), WS_POPUP, monitorRect, nullptr, 0); - if (ret) { - m_pDedicatedFSVideoWnd->ShowWindow(SW_SHOWNOACTIVATE); - } - return ret; -} - -bool CMainFrame::IsFrameLessWindow() const -{ - return (IsFullScreenMainFrame() || AfxGetAppSettings().eCaptionMenuMode == MODE_BORDERLESS); -} - -bool CMainFrame::IsCaptionHidden() const -{ - // If no caption, there is no menu bar. But if is no menu bar, then the caption can be. - return (!IsFullScreenMainFrame() && AfxGetAppSettings().eCaptionMenuMode > MODE_HIDEMENU); //!=MODE_SHOWCAPTIONMENU && !=MODE_HIDEMENU -} - -bool CMainFrame::IsMenuHidden() const -{ - return (!IsFullScreenMainFrame() && AfxGetAppSettings().eCaptionMenuMode != MODE_SHOWCAPTIONMENU); -} - -bool CMainFrame::IsPlaylistEmpty() const -{ - return (m_wndPlaylistBar.GetCount() == 0); -} - -bool CMainFrame::IsInteractiveVideo() const -{ - return m_fShockwaveGraph; -} - -bool CMainFrame::IsFullScreenMode() const { - return m_fFullScreen || IsD3DFullScreenMode(); -} - -bool CMainFrame::IsFullScreenMainFrame() const { - return m_fFullScreen && !HasDedicatedFSVideoWindow(); -} - -bool CMainFrame::IsFullScreenMainFrameExclusiveMPCVR() const { - return m_fFullScreen && m_bIsMPCVRExclusiveMode && !HasDedicatedFSVideoWindow(); -} - -bool CMainFrame::IsFullScreenSeparate() const { - return m_fFullScreen && HasDedicatedFSVideoWindow() && !m_bFullScreenWindowIsD3D; -} - -bool CMainFrame::HasDedicatedFSVideoWindow() const { - return m_pDedicatedFSVideoWnd && m_pDedicatedFSVideoWnd->IsWindow(); -} - -bool CMainFrame::IsD3DFullScreenMode() const -{ - return HasDedicatedFSVideoWindow() && m_bFullScreenWindowIsD3D; -}; - -bool CMainFrame::IsSubresyncBarVisible() const -{ - return !!m_wndSubresyncBar.IsWindowVisible(); -} - -void CMainFrame::SetupEVRColorControl() -{ - if (m_pMFVP) { - CMPlayerCApp* pApp = AfxGetMyApp(); - CAppSettings& s = AfxGetAppSettings(); - - if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Brightness, pApp->GetEVRColorControl(ProcAmp_Brightness)))) { - return; - } - if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Contrast, pApp->GetEVRColorControl(ProcAmp_Contrast)))) { - return; - } - if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Hue, pApp->GetEVRColorControl(ProcAmp_Hue)))) { - return; - } - if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Saturation, pApp->GetEVRColorControl(ProcAmp_Saturation)))) { - return; - } - - pApp->UpdateColorControlRange(true); - SetColorControl(ProcAmp_All, s.iBrightness, s.iContrast, s.iHue, s.iSaturation); - } -} - -// Called from GraphThread -void CMainFrame::SetupVMR9ColorControl() -{ - if (m_pVMRMC) { - CMPlayerCApp* pApp = AfxGetMyApp(); - CAppSettings& s = AfxGetAppSettings(); - - if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Brightness)))) { - return; - } - if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Contrast)))) { - return; - } - if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Hue)))) { - return; - } - if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Saturation)))) { - return; - } - - pApp->UpdateColorControlRange(false); - SetColorControl(ProcAmp_All, s.iBrightness, s.iContrast, s.iHue, s.iSaturation); - } -} - -void CMainFrame::SetColorControl(DWORD flags, int& brightness, int& contrast, int& hue, int& saturation) -{ - CMPlayerCApp* pApp = AfxGetMyApp(); - HRESULT hr = 0; - - static VMR9ProcAmpControl ClrControl; - static DXVA2_ProcAmpValues ClrValues; - - COLORPROPERTY_RANGE* cr = 0; - if (flags & ProcAmp_Brightness) { - cr = pApp->GetColorControl(ProcAmp_Brightness); - brightness = std::min(std::max(brightness, cr->MinValue), cr->MaxValue); - } - if (flags & ProcAmp_Contrast) { - cr = pApp->GetColorControl(ProcAmp_Contrast); - contrast = std::min(std::max(contrast, cr->MinValue), cr->MaxValue); - } - if (flags & ProcAmp_Hue) { - cr = pApp->GetColorControl(ProcAmp_Hue); - hue = std::min(std::max(hue, cr->MinValue), cr->MaxValue); - } - if (flags & ProcAmp_Saturation) { - cr = pApp->GetColorControl(ProcAmp_Saturation); - saturation = std::min(std::max(saturation, cr->MinValue), cr->MaxValue); - } - - if (m_pVMRMC) { - ClrControl.dwSize = sizeof(ClrControl); - ClrControl.dwFlags = flags; - ClrControl.Brightness = (float)brightness; - ClrControl.Contrast = (float)(contrast + 100) / 100; - ClrControl.Hue = (float)hue; - ClrControl.Saturation = (float)(saturation + 100) / 100; - - hr = m_pVMRMC->SetProcAmpControl(0, &ClrControl); - } else if (m_pMFVP) { - ClrValues.Brightness = IntToFixed(brightness); - ClrValues.Contrast = IntToFixed(contrast + 100, 100); - ClrValues.Hue = IntToFixed(hue); - ClrValues.Saturation = IntToFixed(saturation + 100, 100); - - hr = m_pMFVP->SetProcAmpValues(flags, &ClrValues); - - } - // Workaround: with Intel driver the minimum values of the supported range may not actually work - if (FAILED(hr)) { - if (flags & ProcAmp_Brightness) { - cr = pApp->GetColorControl(ProcAmp_Brightness); - if (brightness == cr->MinValue) { - brightness = cr->MinValue + 1; - } - } - if (flags & ProcAmp_Hue) { - cr = pApp->GetColorControl(ProcAmp_Hue); - if (hue == cr->MinValue) { - hue = cr->MinValue + 1; - } - } - } -} - -void CMainFrame::SetClosedCaptions(bool enable) -{ - if (m_pLN21) { - m_pLN21->SetServiceState(enable ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off); - } -} - -LPCTSTR CMainFrame::GetDVDAudioFormatName(const DVD_AudioAttributes& ATR) const -{ - switch (ATR.AudioFormat) { - case DVD_AudioFormat_AC3: - return _T("AC3"); - case DVD_AudioFormat_MPEG1: - case DVD_AudioFormat_MPEG1_DRC: - return _T("MPEG1"); - case DVD_AudioFormat_MPEG2: - case DVD_AudioFormat_MPEG2_DRC: - return _T("MPEG2"); - case DVD_AudioFormat_LPCM: - return _T("LPCM"); - case DVD_AudioFormat_DTS: - return _T("DTS"); - case DVD_AudioFormat_SDDS: - return _T("SDDS"); - case DVD_AudioFormat_Other: - default: - return MAKEINTRESOURCE(IDS_MAINFRM_137); - } -} - -afx_msg void CMainFrame::OnGotoSubtitle(UINT nID) -{ - if (!m_pSubStreams.IsEmpty() && !IsPlaybackCaptureMode()) { - m_rtCurSubPos = m_wndSeekBar.GetPos(); - m_lSubtitleShift = 0; - m_wndSubresyncBar.RefreshEmbeddedTextSubtitleData(); - m_nCurSubtitle = m_wndSubresyncBar.FindNearestSub(m_rtCurSubPos, (nID == ID_GOTO_NEXT_SUB)); - if (m_nCurSubtitle >= 0 && m_pMS) { - if (nID == ID_GOTO_PREV_SUB) { - OnPlayPause(); - } - m_pMS->SetPositions(&m_rtCurSubPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - } -} - -afx_msg void CMainFrame::OnSubresyncShiftSub(UINT nID) -{ - if (m_nCurSubtitle >= 0) { - long lShift = (nID == ID_SUBRESYNC_SHIFT_DOWN) ? -100 : 100; - CString strSubShift; - - if (m_wndSubresyncBar.ShiftSubtitle(m_nCurSubtitle, lShift, m_rtCurSubPos)) { - m_lSubtitleShift += lShift; - if (m_pMS) { - m_pMS->SetPositions(&m_rtCurSubPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); - } - } - - strSubShift.Format(IDS_MAINFRM_138, m_lSubtitleShift); - m_OSD.DisplayMessage(OSD_TOPLEFT, strSubShift); - } -} - -afx_msg void CMainFrame::OnSubtitleDelay(UINT nID) -{ - int nDelayStep = AfxGetAppSettings().nSubDelayStep; - - if (nID == ID_SUB_DELAY_DOWN) { - nDelayStep = -nDelayStep; - } - - SetSubtitleDelay(nDelayStep, /*relative=*/ true); -} - -afx_msg void CMainFrame::OnSubtitlePos(UINT nID) -{ - if (m_pCAP) { - CAppSettings& s = AfxGetAppSettings(); - switch (nID) { - case ID_SUB_POS_DOWN: - s.m_RenderersSettings.subPicVerticalShift += 2; - break; - case ID_SUB_POS_UP: - s.m_RenderersSettings.subPicVerticalShift -= 2; - break; - } - - if (GetMediaState() != State_Running) { - m_pCAP->Paint(false); - } - } -} - -afx_msg void CMainFrame::OnSubtitleFontSize(UINT nID) -{ - if (m_pCAP && m_pCurrentSubInput.pSubStream) { - CLSID clsid; - m_pCurrentSubInput.pSubStream->GetClassID(&clsid); - if (clsid == __uuidof(CRenderedTextSubtitle)) { - CAppSettings& s = AfxGetAppSettings(); - switch (nID) { - case ID_SUB_FONT_SIZE_DEC: - s.m_RenderersSettings.fontScaleOverride -= 0.05; - break; - case ID_SUB_FONT_SIZE_INC: - s.m_RenderersSettings.fontScaleOverride += 0.05; - break; - } - - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; - - if (pRTS->m_LibassContext.IsLibassActive()) { - // not supported by libass (yet) - if (!IsFullScreenMode()) { - AfxMessageBox(_T("Adjusting subtitle text size is not possible when using libass."), MB_ICONERROR, 0); - } - } - - { - CAutoLock cAutoLock(&m_csSubLock); - pRTS->Deinit(); - } - InvalidateSubtitle(); - - if (GetMediaState() != State_Running) { - m_pCAP->Paint(false); - } - } else { - if (!IsFullScreenMode()) { - AfxMessageBox(_T("Adjusting subtitle text size is not possible for image based subtitle formats."), MB_ICONERROR, 0); - } - } - } -} - -void CMainFrame::ResetSubtitlePosAndSize(bool repaint /* = false*/) -{ - CAppSettings& s = AfxGetAppSettings(); - bool changed = (s.m_RenderersSettings.fontScaleOverride != 1.0) || (s.m_RenderersSettings.subPicVerticalShift != 0); - - s.m_RenderersSettings.fontScaleOverride = 1.0; - s.m_RenderersSettings.subPicVerticalShift = 0; - - if (changed && repaint && m_pCAP && m_pCurrentSubInput.pSubStream) { - CLSID clsid; - m_pCurrentSubInput.pSubStream->GetClassID(&clsid); - if (clsid == __uuidof(CRenderedTextSubtitle)) { - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; - { - CAutoLock cAutoLock(&m_csSubLock); - pRTS->Deinit(); - } - InvalidateSubtitle(); - - if (GetMediaState() != State_Running) { - m_pCAP->Paint(false); - } - } - } -} - - -void CMainFrame::ProcessAPICommand(COPYDATASTRUCT* pCDS) -{ - CAtlList fns; - REFERENCE_TIME rtPos = 0; - CString fn; - - switch (pCDS->dwData) { - case CMD_OPENFILE: - fn = CString((LPCWSTR)pCDS->lpData); - if (CanSendToYoutubeDL(fn)) { - if (ProcessYoutubeDLURL(fn, false)) { - OpenCurPlaylistItem(); - return; - } else if (IsOnYDLWhitelist(fn)) { - return; - } - } - fns.AddHead(fn); - m_wndPlaylistBar.Open(fns, false); - OpenCurPlaylistItem(); - break; - case CMD_STOP: - OnPlayStop(); - break; - case CMD_CLOSEFILE: - CloseMedia(); - break; - case CMD_PLAYPAUSE: - OnPlayPlaypause(); - break; - case CMD_PLAY: - OnApiPlay(); - break; - case CMD_PAUSE: - OnApiPause(); - break; - case CMD_ADDTOPLAYLIST: - fn = CString((LPCWSTR)pCDS->lpData); - if (CanSendToYoutubeDL(fn)) { - if (ProcessYoutubeDLURL(fn, true)) { - return; - } else if (IsOnYDLWhitelist(fn)) { - return; - } - } - fns.AddHead(fn); - m_wndPlaylistBar.Append(fns, true); - break; - case CMD_STARTPLAYLIST: - OpenCurPlaylistItem(); - break; - case CMD_CLEARPLAYLIST: - m_wndPlaylistBar.Empty(); - break; - case CMD_SETPOSITION: - rtPos = 10000 * REFERENCE_TIME(_wtof((LPCWSTR)pCDS->lpData) * 1000); //with accuracy of 1 ms - // imianz: quick and dirty trick - // Pause->SeekTo->Play (in place of SeekTo only) seems to prevents in most cases - // some strange video effects on avi files (ex. locks a while and than running fast). - if (!m_fAudioOnly && GetMediaState() == State_Running) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - SeekTo(rtPos); - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } else { - SeekTo(rtPos); - } - // show current position overridden by play command - m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 2000); - break; - case CMD_SETAUDIODELAY: - rtPos = (REFERENCE_TIME)_wtol((LPCWSTR)pCDS->lpData) * 10000; - SetAudioDelay(rtPos); - break; - case CMD_SETSUBTITLEDELAY: - SetSubtitleDelay(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_SETINDEXPLAYLIST: - //m_wndPlaylistBar.SetSelIdx(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_SETAUDIOTRACK: - SetAudioTrackIdx(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_SETSUBTITLETRACK: - SetSubtitleTrackIdx(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_GETVERSION: { - CStringW buff = AfxGetMyApp()->m_strVersion; - SendAPICommand(CMD_VERSION, buff); - break; - } - case CMD_GETSUBTITLETRACKS: - SendSubtitleTracksToApi(); - break; - case CMD_GETAUDIOTRACKS: - SendAudioTracksToApi(); - break; - case CMD_GETCURRENTAUDIOTRACK: - SendAPICommand(CMD_CURRENTAUDIOTRACK, L"%d", GetCurrentAudioTrackIdx()); - break; - case CMD_GETCURRENTSUBTITLETRACK: - SendAPICommand(CMD_CURRENTSUBTITLETRACK, L"%d", GetCurrentSubtitleTrackIdx()); - break; - case CMD_GETCURRENTPOSITION: - SendCurrentPositionToApi(); - break; - case CMD_GETNOWPLAYING: - SendNowPlayingToApi(); - break; - case CMD_JUMPOFNSECONDS: - JumpOfNSeconds(_wtoi((LPCWSTR)pCDS->lpData)); - break; - case CMD_GETPLAYLIST: - SendPlaylistToApi(); - break; - case CMD_JUMPFORWARDMED: - OnPlaySeek(ID_PLAY_SEEKFORWARDMED); - break; - case CMD_JUMPBACKWARDMED: - OnPlaySeek(ID_PLAY_SEEKBACKWARDMED); - break; - case CMD_TOGGLEFULLSCREEN: - OnViewFullscreen(); - break; - case CMD_INCREASEVOLUME: - m_wndToolBar.m_volctrl.IncreaseVolume(); - break; - case CMD_DECREASEVOLUME: - m_wndToolBar.m_volctrl.DecreaseVolume(); - break; - case CMD_SHADER_TOGGLE : - OnShaderToggle1(); - break; - case CMD_CLOSEAPP: - PostMessage(WM_CLOSE); - break; - case CMD_SETSPEED: - SetPlayingRate(_wtof((LPCWSTR)pCDS->lpData)); - break; - case CMD_SETPANSCAN: - AfxGetAppSettings().strPnSPreset = (LPCWSTR)pCDS->lpData; - ApplyPanNScanPresetString(); - break; - case CMD_OSDSHOWMESSAGE: - ShowOSDCustomMessageApi((MPC_OSDDATA*)pCDS->lpData); - break; - } -} - -void CMainFrame::SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...) -{ - const CAppSettings& s = AfxGetAppSettings(); - - if (s.hMasterWnd) { - COPYDATASTRUCT CDS; - - va_list args; - va_start(args, fmt); - - int nBufferLen = _vsctprintf(fmt, args) + 1; // _vsctprintf doesn't count the null terminator - TCHAR* pBuff = DEBUG_NEW TCHAR[nBufferLen]; - _vstprintf_s(pBuff, nBufferLen, fmt, args); - - CDS.cbData = (DWORD)nBufferLen * sizeof(TCHAR); - CDS.dwData = nCommand; - CDS.lpData = (LPVOID)pBuff; - - ::SendMessage(s.hMasterWnd, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&CDS); - - va_end(args); - delete [] pBuff; - } -} - -void CMainFrame::SendNowPlayingToApi(bool sendtrackinfo) -{ - if (!AfxGetAppSettings().hMasterWnd) { - return; - } - - if (GetLoadState() == MLS::LOADED) { - CString title, author, description; - CString label; - CString strDur; - - if (GetPlaybackMode() == PM_FILE) { - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_TITLE), title); - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - label = !pli.m_label.IsEmpty() ? pli.m_label : pli.m_fns.GetHead(); - REFERENCE_TIME rtDur; - m_pMS->GetDuration(&rtDur); - strDur.Format(L"%.3f", rtDur / 10000000.0); - } - } else if (GetPlaybackMode() == PM_DVD) { - DVD_DOMAIN DVDDomain; - ULONG ulNumOfChapters = 0; - DVD_PLAYBACK_LOCATION2 Location; - - // Get current DVD Domain - if (SUCCEEDED(m_pDVDI->GetCurrentDomain(&DVDDomain))) { - switch (DVDDomain) { - case DVD_DOMAIN_Stop: - title = _T("DVD - Stopped"); - break; - case DVD_DOMAIN_FirstPlay: - title = _T("DVD - FirstPlay"); - break; - case DVD_DOMAIN_VideoManagerMenu: - title = _T("DVD - RootMenu"); - break; - case DVD_DOMAIN_VideoTitleSetMenu: - title = _T("DVD - TitleMenu"); - break; - case DVD_DOMAIN_Title: - title = _T("DVD - Title"); - break; - } - - // get title information - if (DVDDomain == DVD_DOMAIN_Title) { - // get current location (title number & chapter) - if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location))) { - // get number of chapters in current title - VERIFY(SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters))); - } - - // get total time of title - DVD_HMSF_TIMECODE tcDur; - ULONG ulFlags; - if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { - // calculate duration in seconds - strDur.Format(L"%d", tcDur.bHours * 60 * 60 + tcDur.bMinutes * 60 + tcDur.bSeconds); - } - - // build string - // DVD - xxxxx|currenttitle|numberofchapters|currentchapter|titleduration - author.Format(L"%lu", Location.TitleNum); - description.Format(L"%lu", ulNumOfChapters); - label.Format(L"%lu", Location.ChapterNum); - } - } - } - - title.Replace(L"|", L"\\|"); - author.Replace(L"|", L"\\|"); - description.Replace(L"|", L"\\|"); - label.Replace(L"|", L"\\|"); - - CStringW buff; - buff.Format(L"%s|%s|%s|%s|%s", title.GetString(), author.GetString(), description.GetString(), label.GetString(), strDur.GetString()); - - SendAPICommand(CMD_NOWPLAYING, L"%s", static_cast(buff)); - if (sendtrackinfo) { - SendSubtitleTracksToApi(); - SendAudioTracksToApi(); - } - } -} - -void CMainFrame::SendSubtitleTracksToApi() -{ - CStringW strSubs; - if (GetLoadState() == MLS::LOADED) { - if (GetPlaybackMode() == PM_DVD) { - ULONG ulStreamsAvailable, ulCurrentStream; - BOOL bIsDisabled; - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) - && ulStreamsAvailable > 0) { - LCID DefLanguage; - int i = 0, iSelected = -1; - - DVD_SUBPICTURE_LANG_EXT ext; - if (FAILED(m_pDVDI->GetDefaultSubpictureLanguage(&DefLanguage, &ext))) { - return; - } - - for (i = 0; i < ulStreamsAvailable; i++) { - LCID Language; - if (FAILED(m_pDVDI->GetSubpictureLanguage(i, &Language))) { - continue; - } - - if (i == ulCurrentStream) { - iSelected = i; - } - - CString str; - if (Language) { - GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); - } else { - str.Format(IDS_AG_UNKNOWN, i + 1); - } - - DVD_SubpictureAttributes ATR; - if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(i, &ATR))) { - switch (ATR.LanguageExtension) { - case DVD_SP_EXT_NotSpecified: - default: - break; - case DVD_SP_EXT_Caption_Normal: - str += _T(""); - break; - case DVD_SP_EXT_Caption_Big: - str += _T(" (Big)"); - break; - case DVD_SP_EXT_Caption_Children: - str += _T(" (Children)"); - break; - case DVD_SP_EXT_CC_Normal: - str += _T(" (CC)"); - break; - case DVD_SP_EXT_CC_Big: - str += _T(" (CC Big)"); - break; - case DVD_SP_EXT_CC_Children: - str += _T(" (CC Children)"); - break; - case DVD_SP_EXT_Forced: - str += _T(" (Forced)"); - break; - case DVD_SP_EXT_DirectorComments_Normal: - str += _T(" (Director Comments)"); - break; - case DVD_SP_EXT_DirectorComments_Big: - str += _T(" (Director Comments, Big)"); - break; - case DVD_SP_EXT_DirectorComments_Children: - str += _T(" (Director Comments, Children)"); - break; - } - } - if (!strSubs.IsEmpty()) { - strSubs.Append(L"|"); - } - str.Replace(L"|", L"\\|"); - strSubs.Append(str); - } - if (AfxGetAppSettings().fEnableSubtitles) { - strSubs.AppendFormat(L"|%d", iSelected); - } else { - strSubs.Append(L"|-1"); - } - } - } else { - - POSITION pos = m_pSubStreams.GetHeadPosition(); - int i = 0, iSelected = -1; - if (pos) { - while (pos) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - - if (CComQIPtr pSSF = subInput.pSourceFilter) { - DWORD cStreams; - if (FAILED(pSSF->Count(&cStreams))) { - continue; - } - - for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { - DWORD dwFlags, dwGroup; - WCHAR* pszName = nullptr; - - if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, &pszName, nullptr, nullptr)) - || !pszName) { - continue; - } - - CString name(pszName); - CoTaskMemFree(pszName); - - if (dwGroup != 2) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream - && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - iSelected = j; - } - - if (!strSubs.IsEmpty()) { - strSubs.Append(L"|"); - } - name.Replace(L"|", L"\\|"); - strSubs.Append(name); - - i++; - } - } else { - CComPtr pSubStream = subInput.pSubStream; - if (!pSubStream) { - continue; - } - - if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - iSelected = i + pSubStream->GetStream(); - } - - for (int j = 0, cnt = pSubStream->GetStreamCount(); j < cnt; j++) { - WCHAR* pName = nullptr; - if (SUCCEEDED(pSubStream->GetStreamInfo(j, &pName, nullptr))) { - CString name(pName); - CoTaskMemFree(pName); - - if (!strSubs.IsEmpty()) { - strSubs.Append(L"|"); - } - name.Replace(L"|", L"\\|"); - strSubs.Append(name); - } - i++; - } - } - - } - if (AfxGetAppSettings().fEnableSubtitles) { - strSubs.AppendFormat(L"|%d", iSelected); - } else { - strSubs.Append(L"|-1"); - } - } else { - strSubs.Append(L"-1"); - } - } - } else { - strSubs.Append(L"-2"); - } - SendAPICommand(CMD_LISTSUBTITLETRACKS, L"%s", static_cast(strSubs)); -} - -void CMainFrame::SendAudioTracksToApi() -{ - CStringW strAudios; - - if (GetLoadState() == MLS::LOADED) { - DWORD cStreams = 0; - if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { - int currentStream = -1; - for (int i = 0; i < (int)cStreams; i++) { - AM_MEDIA_TYPE* pmt = nullptr; - DWORD dwFlags = 0; - LCID lcid = 0; - DWORD dwGroup = 0; - WCHAR* pszName = nullptr; - if (FAILED(m_pAudioSwitcherSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) { - return; - } - if (dwFlags == AMSTREAMSELECTINFO_EXCLUSIVE) { - currentStream = i; - } - CString name(pszName); - if (!strAudios.IsEmpty()) { - strAudios.Append(L"|"); - } - name.Replace(L"|", L"\\|"); - strAudios.AppendFormat(L"%s", name.GetString()); - if (pmt) { - DeleteMediaType(pmt); - } - if (pszName) { - CoTaskMemFree(pszName); - } - } - strAudios.AppendFormat(L"|%d", currentStream); - - } else { - strAudios.Append(L"-1"); - } - } else { - strAudios.Append(L"-2"); - } - SendAPICommand(CMD_LISTAUDIOTRACKS, L"%s", static_cast(strAudios)); - -} - -void CMainFrame::SendPlaylistToApi() -{ - CStringW strPlaylist; - POSITION pos = m_wndPlaylistBar.m_pl.GetHeadPosition(), pos2; - - while (pos) { - CPlaylistItem& pli = m_wndPlaylistBar.m_pl.GetNext(pos); - - if (pli.m_type == CPlaylistItem::file) { - pos2 = pli.m_fns.GetHeadPosition(); - while (pos2) { - CString fn = pli.m_fns.GetNext(pos2); - if (!strPlaylist.IsEmpty()) { - strPlaylist.Append(L"|"); - } - fn.Replace(L"|", L"\\|"); - strPlaylist.AppendFormat(L"%s", fn.GetString()); - } - } - } - if (strPlaylist.IsEmpty()) { - strPlaylist.Append(L"-1"); - } else { - strPlaylist.AppendFormat(L"|%d", m_wndPlaylistBar.GetSelIdx()); - } - SendAPICommand(CMD_PLAYLIST, L"%s", static_cast(strPlaylist)); -} - -void CMainFrame::SendCurrentPositionToApi(bool fNotifySeek) -{ - if (!AfxGetAppSettings().hMasterWnd) { - return; - } - - if (GetLoadState() == MLS::LOADED) { - CStringW strPos; - - if (GetPlaybackMode() == PM_FILE) { - REFERENCE_TIME rtCur; - m_pMS->GetCurrentPosition(&rtCur); - strPos.Format(L"%.3f", rtCur / 10000000.0); - } else if (GetPlaybackMode() == PM_DVD) { - DVD_PLAYBACK_LOCATION2 Location; - // get current location while playing disc, will return 0, if at a menu - if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) { - strPos.Format(L"%d", Location.TimeCode.bHours * 60 * 60 + Location.TimeCode.bMinutes * 60 + Location.TimeCode.bSeconds); - } - } - - SendAPICommand(fNotifySeek ? CMD_NOTIFYSEEK : CMD_CURRENTPOSITION, strPos); - } -} - -void CMainFrame::ShowOSDCustomMessageApi(const MPC_OSDDATA* osdData) -{ - m_OSD.DisplayMessage((OSD_MESSAGEPOS)osdData->nMsgPos, osdData->strMsg, osdData->nDurationMS); -} - -void CMainFrame::JumpOfNSeconds(int nSeconds) -{ - if (GetLoadState() == MLS::LOADED) { - REFERENCE_TIME rtCur; - - if (GetPlaybackMode() == PM_FILE) { - m_pMS->GetCurrentPosition(&rtCur); - DVD_HMSF_TIMECODE tcCur = RT2HMSF(rtCur); - long lPosition = tcCur.bHours * 60 * 60 + tcCur.bMinutes * 60 + tcCur.bSeconds + nSeconds; - - // revert the update position to REFERENCE_TIME format - tcCur.bHours = (BYTE)(lPosition / 3600); - tcCur.bMinutes = (lPosition / 60) % 60; - tcCur.bSeconds = lPosition % 60; - rtCur = HMSF2RT(tcCur); - - // quick and dirty trick: - // pause->seekto->play seems to prevents some strange - // video effect (ex. locks for a while and than running fast) - if (!m_fAudioOnly) { - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - SeekTo(rtCur); - if (!m_fAudioOnly) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - // show current position overridden by play command - m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 2000); - } - } - } -} - -// TODO : to be finished ! -//void CMainFrame::AutoSelectTracks() -//{ -// LCID DefAudioLanguageLcid [2] = {MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT), MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT)}; -// int DefAudioLanguageIndex [2] = {-1, -1}; -// LCID DefSubtitleLanguageLcid [2] = {0, MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)}; -// int DefSubtitleLanguageIndex[2] = {-1, -1}; -// LCID Language = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT); -// -// if ((m_iMediaLoadState == MLS::LOADING) || (m_iMediaLoadState == MLS::LOADED)) -// { -// if (GetPlaybackMode() == PM_FILE) -// { -// CComQIPtr pSS = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); -// -// DWORD cStreams = 0; -// if (pSS && SUCCEEDED(pSS->Count(&cStreams))) -// { -// for (int i = 0; i < (int)cStreams; i++) -// { -// AM_MEDIA_TYPE* pmt = nullptr; -// DWORD dwFlags = 0; -// LCID lcid = 0; -// DWORD dwGroup = 0; -// WCHAR* pszName = nullptr; -// if (FAILED(pSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) -// return; -// } -// } -// -// POSITION pos = m_pSubStreams.GetHeadPosition(); -// while (pos) -// { -// CComPtr pSubStream = m_pSubStreams.GetNext(pos).subStream; -// if (!pSubStream) continue; -// -// for (int i = 0, j = pSubStream->GetStreamCount(); i < j; i++) -// { -// WCHAR* pName = nullptr; -// if (SUCCEEDED(pSubStream->GetStreamInfo(i, &pName, &Language))) -// { -// if (DefAudioLanguageLcid[0] == Language) DefSubtitleLanguageIndex[0] = i; -// if (DefSubtitleLanguageLcid[1] == Language) DefSubtitleLanguageIndex[1] = i; -// CoTaskMemFree(pName); -// } -// } -// } -// } -// else if (GetPlaybackMode() == PM_DVD) -// { -// ULONG ulStreamsAvailable, ulCurrentStream; -// BOOL bIsDisabled; -// -// if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) -// { -// for (ULONG i = 0; i < ulStreamsAvailable; i++) -// { -// DVD_SubpictureAttributes ATR; -// if (SUCCEEDED(m_pDVDI->GetSubpictureLanguage(i, &Language))) -// { -// // Auto select forced subtitle -// if ((DefAudioLanguageLcid[0] == Language) && (ATR.LanguageExtension == DVD_SP_EXT_Forced)) -// DefSubtitleLanguageIndex[0] = i; -// -// if (DefSubtitleLanguageLcid[1] == Language) DefSubtitleLanguageIndex[1] = i; -// } -// } -// } -// -// if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulStreamsAvailable, &ulCurrentStream))) -// { -// for (ULONG i = 0; i < ulStreamsAvailable; i++) -// { -// if (SUCCEEDED(m_pDVDI->GetAudioLanguage(i, &Language))) -// { -// if (DefAudioLanguageLcid[0] == Language) DefAudioLanguageIndex[0] = i; -// if (DefAudioLanguageLcid[1] == Language) DefAudioLanguageIndex[1] = i; -// } -// } -// } -// -// // Select best audio/subtitles tracks -// if (DefAudioLanguageLcid[0] != -1) -// { -// m_pDVDC->SelectAudioStream(DefAudioLanguageIndex[0], DVD_CMD_FLAG_Block, nullptr); -// if (DefSubtitleLanguageIndex[0] != -1) -// m_pDVDC->SelectSubpictureStream(DefSubtitleLanguageIndex[0], DVD_CMD_FLAG_Block, nullptr); -// } -// else if ((DefAudioLanguageLcid[1] != -1) && (DefSubtitleLanguageLcid[1] != -1)) -// { -// m_pDVDC->SelectAudioStream (DefAudioLanguageIndex[1], DVD_CMD_FLAG_Block, nullptr); -// m_pDVDC->SelectSubpictureStream (DefSubtitleLanguageIndex[1], DVD_CMD_FLAG_Block, nullptr); -// } -// } -// -// -// } -//} - -void CMainFrame::OnFileOpendirectory() -{ - if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar)) { - return; - } - - auto& s = AfxGetAppSettings(); - CString strTitle(StrRes(IDS_MAINFRM_DIR_TITLE)); - CString path; - - MPCFolderPickerDialog fd(ForceTrailingSlash(s.lastFileOpenDirPath), FOS_PATHMUSTEXIST, GetModalParent(), IDS_MAINFRM_DIR_CHECK); - fd.m_ofn.lpstrTitle = strTitle; - - if (fd.DoModal() == IDOK) { - path = fd.GetPathName(); //getfolderpath() does not work correctly for CFolderPickerDialog - } else { - return; - } - - BOOL recur = TRUE; - fd.GetCheckButtonState(IDS_MAINFRM_DIR_CHECK, recur); - COpenDirHelper::m_incl_subdir = !!recur; - - // If we got a link file that points to a directory, follow the link - if (PathUtils::IsLinkFile(path)) { - CString resolvedPath = PathUtils::ResolveLinkFile(path); - if (PathUtils::IsDir(resolvedPath)) { - path = resolvedPath; - } - } - - path = ForceTrailingSlash(path); - s.lastFileOpenDirPath = path; - - CAtlList sl; - sl.AddTail(path); - if (COpenDirHelper::m_incl_subdir) { - PathUtils::RecurseAddDir(path, sl); - } - - m_wndPlaylistBar.Open(sl, true); - OpenCurPlaylistItem(); -} - -HRESULT CMainFrame::CreateThumbnailToolbar() -{ - if (!this || !AfxGetAppSettings().bUseEnhancedTaskBar) { - return E_FAIL; - } - - if (m_pTaskbarList || SUCCEEDED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER))) { - bool bRTLLayout = false; // Assume left-to-right layout by default - // Try to locate the window used to display the task bar - if (CWnd* pTaskBarWnd = FindWindow(_T("TaskListThumbnailWnd"), nullptr)) { - bRTLLayout = !!(pTaskBarWnd->GetExStyle() & WS_EX_LAYOUTRTL); - } - - CMPCPngImage image; - if (!image.Load(IDF_WIN7_TOOLBAR)) { - return E_FAIL; - } - - CSize size = image.GetSize(); - - if (bRTLLayout) { // We don't want the buttons to be mirrored so we pre-mirror them - // Create memory DCs for the source and destination bitmaps - CDC sourceDC, destDC; - sourceDC.CreateCompatibleDC(nullptr); - destDC.CreateCompatibleDC(nullptr); - // Swap the source bitmap with an empty one - CBitmap sourceImg; - sourceImg.Attach(image.Detach()); - // Create a temporary DC - CClientDC clientDC(nullptr); - // Create the destination bitmap - image.CreateCompatibleBitmap(&clientDC, size.cx, size.cy); - // Select the bitmaps into the DCs - HGDIOBJ oldSourceDCObj = sourceDC.SelectObject(sourceImg); - HGDIOBJ oldDestDCObj = destDC.SelectObject(image); - // Actually flip the bitmap - destDC.StretchBlt(0, 0, size.cx, size.cy, - &sourceDC, size.cx, 0, -size.cx, size.cy, - SRCCOPY); - // Reselect the old objects back into their DCs - sourceDC.SelectObject(oldSourceDCObj); - destDC.SelectObject(oldDestDCObj); - - sourceDC.DeleteDC(); - destDC.DeleteDC(); - } - - CImageList imageList; - imageList.Create(size.cy, size.cy, ILC_COLOR32, size.cx / size.cy, 0); - imageList.Add(&image, nullptr); - - if (SUCCEEDED(m_pTaskbarList->ThumbBarSetImageList(m_hWnd, imageList.GetSafeHandle()))) { - THUMBBUTTON buttons[5] = {}; - - for (size_t i = 0; i < _countof(buttons); i++) { - buttons[i].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS; - buttons[i].dwFlags = THBF_DISABLED; - buttons[i].iBitmap = 0; // Will be set later - } - - // PREVIOUS - buttons[0].iId = IDTB_BUTTON3; - // STOP - buttons[1].iId = IDTB_BUTTON1; - // PLAY/PAUSE - buttons[2].iId = IDTB_BUTTON2; - // NEXT - buttons[3].iId = IDTB_BUTTON4; - // FULLSCREEN - buttons[4].iId = IDTB_BUTTON5; - - if (bRTLLayout) { // We don't want the buttons to be mirrored so we pre-mirror them - std::reverse(buttons, buttons + _countof(buttons)); - } - - if (SUCCEEDED(m_pTaskbarList->ThumbBarAddButtons(m_hWnd, _countof(buttons), buttons))) { - return UpdateThumbarButton(); - } - } - } - - return E_FAIL; -} - -HRESULT CMainFrame::UpdateThumbarButton() -{ - MPC_PLAYSTATE state = PS_STOP; - if (GetLoadState() == MLS::LOADED) { - switch (GetMediaState()) { - case State_Running: - state = PS_PLAY; - break; - case State_Paused: - state = PS_PAUSE; - break; - } - } - return UpdateThumbarButton(state); -} - -HRESULT CMainFrame::UpdateThumbarButton(MPC_PLAYSTATE iPlayState) -{ - if (!m_pTaskbarList) { - return E_FAIL; - } - - THUMBBUTTON buttons[5] = {}; - - for (size_t i = 0; i < _countof(buttons); i++) { - buttons[i].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS; - } - - buttons[0].iId = IDTB_BUTTON3; - buttons[1].iId = IDTB_BUTTON1; - buttons[2].iId = IDTB_BUTTON2; - buttons[3].iId = IDTB_BUTTON4; - buttons[4].iId = IDTB_BUTTON5; - - const CAppSettings& s = AfxGetAppSettings(); - - if (!s.bUseEnhancedTaskBar) { - m_pTaskbarList->SetOverlayIcon(m_hWnd, nullptr, L""); - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); - - for (size_t i = 0; i < _countof(buttons); i++) { - buttons[i].dwFlags = THBF_HIDDEN; - } - } else { - buttons[0].iBitmap = 0; - StringCchCopy(buttons[0].szTip, _countof(buttons[0].szTip), ResStr(IDS_AG_PREVIOUS)); - - buttons[1].iBitmap = 1; - StringCchCopy(buttons[1].szTip, _countof(buttons[1].szTip), ResStr(IDS_AG_STOP)); - - buttons[2].iBitmap = 3; - StringCchCopy(buttons[2].szTip, _countof(buttons[2].szTip), ResStr(IDS_AG_PLAYPAUSE)); - - buttons[3].iBitmap = 4; - StringCchCopy(buttons[3].szTip, _countof(buttons[3].szTip), ResStr(IDS_AG_NEXT)); - - buttons[4].iBitmap = 5; - StringCchCopy(buttons[4].szTip, _countof(buttons[4].szTip), ResStr(IDS_AG_FULLSCREEN)); - - if (GetLoadState() == MLS::LOADED) { - HICON hIcon = nullptr; - - buttons[0].dwFlags = (!s.fUseSearchInFolder && m_wndPlaylistBar.GetCount() <= 1 && (m_pCB && m_pCB->ChapGetCount() <= 1)) ? THBF_DISABLED : THBF_ENABLED; - buttons[3].dwFlags = (!s.fUseSearchInFolder && m_wndPlaylistBar.GetCount() <= 1 && (m_pCB && m_pCB->ChapGetCount() <= 1)) ? THBF_DISABLED : THBF_ENABLED; - buttons[4].dwFlags = THBF_ENABLED; - - if (iPlayState == PS_PLAY) { - buttons[1].dwFlags = THBF_ENABLED; - buttons[2].dwFlags = THBF_ENABLED; - buttons[2].iBitmap = 2; - - hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_PLAY), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); - m_pTaskbarList->SetProgressState(m_hWnd, m_wndSeekBar.HasDuration() ? TBPF_NORMAL : TBPF_NOPROGRESS); - } else if (iPlayState == PS_STOP) { - buttons[1].dwFlags = THBF_DISABLED; - buttons[2].dwFlags = THBF_ENABLED; - buttons[2].iBitmap = 3; - - hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_STOP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); - } else if (iPlayState == PS_PAUSE) { - buttons[1].dwFlags = THBF_ENABLED; - buttons[2].dwFlags = THBF_ENABLED; - buttons[2].iBitmap = 3; - - hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_PAUSE), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); - m_pTaskbarList->SetProgressState(m_hWnd, m_wndSeekBar.HasDuration() ? TBPF_PAUSED : TBPF_NOPROGRESS); - } - - if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { - buttons[0].dwFlags = THBF_DISABLED; - buttons[1].dwFlags = THBF_DISABLED; - buttons[2].dwFlags = THBF_DISABLED; - buttons[3].dwFlags = THBF_DISABLED; - } - - m_pTaskbarList->SetOverlayIcon(m_hWnd, hIcon, L""); - - if (hIcon != nullptr) { - DestroyIcon(hIcon); - } - } else { - for (size_t i = 0; i < _countof(buttons); i++) { - buttons[i].dwFlags = THBF_DISABLED; - } - - m_pTaskbarList->SetOverlayIcon(m_hWnd, nullptr, L""); - m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); - } - - UpdateThumbnailClip(); - } - - // Try to locate the window used to display the task bar to check if it is RTLed - if (CWnd* pTaskBarWnd = FindWindow(_T("TaskListThumbnailWnd"), nullptr)) { - // We don't want the buttons to be mirrored so we pre-mirror them - if (pTaskBarWnd->GetExStyle() & WS_EX_LAYOUTRTL) { - for (UINT i = 0; i < _countof(buttons); i++) { - buttons[i].iBitmap = _countof(buttons) - buttons[i].iBitmap; - } - std::reverse(buttons, buttons + _countof(buttons)); - } - } - - return m_pTaskbarList->ThumbBarUpdateButtons(m_hWnd, _countof(buttons), buttons); -} - -HRESULT CMainFrame::UpdateThumbnailClip() -{ - if (!m_pTaskbarList || !m_hWnd || !m_wndView.m_hWnd) { - return E_FAIL; - } - - const CAppSettings& s = AfxGetAppSettings(); - - CRect r; - m_wndView.GetClientRect(&r); - if (s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) { - r.OffsetRect(0, GetSystemMetrics(SM_CYMENU)); - } - - if (!s.bUseEnhancedTaskBar || (GetLoadState() != MLS::LOADED) || IsFullScreenMode() || r.Width() <= 0 || r.Height() <= 0) { - return m_pTaskbarList->SetThumbnailClip(m_hWnd, nullptr); - } - - return m_pTaskbarList->SetThumbnailClip(m_hWnd, &r); -} - -BOOL CMainFrame::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext) -{ - if (defaultMPCThemeMenu == nullptr) { - defaultMPCThemeMenu = DEBUG_NEW CMPCThemeMenu(); - } - if (lpszMenuName != NULL) { - defaultMPCThemeMenu->LoadMenu(lpszMenuName); - - if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), defaultMPCThemeMenu->m_hMenu, (LPVOID)pContext)) { - return FALSE; - } - defaultMPCThemeMenu->fulfillThemeReqs(true); - - return TRUE; - } - return FALSE; -} - -void CMainFrame::enableFileDialogHook(CMPCThemeUtil* helper) { - if (AfxGetAppSettings().bWindows10DarkThemeActive) { //hard coded behavior for windows 10 dark theme file dialogs, irrespsective of theme loaded by user (fixing windows bugs) - watchingDialog = themableDialogTypes::windowsFileDialog; - dialogHookHelper = helper; - } -} - -void CMainFrame::enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type) { - if (AppIsThemeLoaded()) { - watchingDialog = type; - dialogHookHelper = helper; - } -} - -bool CMainFrame::isSafeZone(CPoint pt) { - CRect r; - m_wndSeekBar.GetClientRect(r); - m_wndSeekBar.MapWindowPoints(this, r); - r.InflateRect(0, m_dpi.ScaleY(16)); - if (r.top < 0) r.top = 0; - - if (r.PtInRect(pt)) { - TRACE(_T("Click was inside safezone!\n")); - return true; - } - return false; -} - -LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (!m_hWnd) { - ASSERT(false); - return 0; - } - if (message == WM_ACTIVATE || message == WM_SETFOCUS) { - if (AfxGetMyApp()->m_fClosingState) { - TRACE(_T("Dropped WindowProc: message %u value %d\n"), message, LOWORD(wParam)); - return 0; - } - } - - if ((message == WM_COMMAND) && (THBN_CLICKED == HIWORD(wParam))) { - int const wmId = LOWORD(wParam); - switch (wmId) { - case IDTB_BUTTON1: - SendMessage(WM_COMMAND, ID_PLAY_STOP); - break; - case IDTB_BUTTON2: - SendMessage(WM_COMMAND, ID_PLAY_PLAYPAUSE); - break; - case IDTB_BUTTON3: - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACK); - break; - case IDTB_BUTTON4: - SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); - break; - case IDTB_BUTTON5: - WINDOWPLACEMENT wp; - GetWindowPlacement(&wp); - if (wp.showCmd == SW_SHOWMINIMIZED) { - SendMessage(WM_SYSCOMMAND, SC_RESTORE, -1); - } - SetForegroundWindow(); - SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN); - break; - default: - break; - } - return 0; - } else if (watchingDialog != themableDialogTypes::None && nullptr != dialogHookHelper && message == WM_ACTIVATE && LOWORD(wParam) == WA_INACTIVE) { - dialogHookHelper->themableDialogHandle = (HWND)lParam; - foundDialog = watchingDialog; - watchingDialog = themableDialogTypes::None; - //capture but process message normally - } else if (message == WM_GETICON && foundDialog == themableDialogTypes::windowsFileDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { - dialogHookHelper->subClassFileDialog(this); - foundDialog = themableDialogTypes::None; - } else if (message == WM_ENTERIDLE && foundDialog == themableDialogTypes::toolbarCustomizeDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { - dialogHookHelper->subClassTBCustomizeDialog(this, &m_wndToolBar); - foundDialog = themableDialogTypes::None; - } - - if (message == WM_NCLBUTTONDOWN && wParam == HTCAPTION && !m_pMVRSR) { - CPoint pt = CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - ScreenToClient(&pt); - if (isSafeZone(pt)) { - return 0; - } - } - - LRESULT ret = 0; - bool bCallOurProc = true; - if (m_pMVRSR) { - // call madVR window proc directly when the interface is available - switch (message) { - case WM_CLOSE: - break; - case WM_MOUSEMOVE: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - // CMouseWnd will call madVR window proc - break; - default: - bCallOurProc = !m_pMVRSR->ParentWindowProc(m_hWnd, message, &wParam, &lParam, &ret); - } - } - if (bCallOurProc && m_hWnd) { - ret = __super::WindowProc(message, wParam, lParam); - } - - return ret; -} - -bool CMainFrame::IsAeroSnapped() -{ - bool ret = false; - WINDOWPLACEMENT wp = { sizeof(wp) }; - if (IsWindowVisible() && !IsZoomed() && !IsIconic() && GetWindowPlacement(&wp)) { - CRect rect; - GetWindowRect(rect); - if (HMONITOR hMon = MonitorFromRect(rect, MONITOR_DEFAULTTONULL)) { - MONITORINFO mi = { sizeof(mi) }; - if (GetMonitorInfo(hMon, &mi)) { - CRect wpRect(wp.rcNormalPosition); - wpRect.OffsetRect(mi.rcWork.left - mi.rcMonitor.left, mi.rcWork.top - mi.rcMonitor.top); - ret = !!(rect != wpRect); - } else { - ASSERT(FALSE); - } - } - } - return ret; -} - -UINT CMainFrame::OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData) -{ - static BOOL bWasPausedBeforeSuspention; - - switch (nPowerEvent) { - case PBT_APMSUSPEND: // System is suspending operation. - TRACE(_T("OnPowerBroadcast - suspending\n")); // For user tracking - bWasPausedBeforeSuspention = FALSE; // Reset value - - if (GetMediaState() == State_Running) { - bWasPausedBeforeSuspention = TRUE; - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); // Pause - } - break; - case PBT_APMRESUMESUSPEND: // System is resuming operation - TRACE(_T("OnPowerBroadcast - resuming\n")); // For user tracking - - // force seek to current position when resuming playback to re-initialize the video decoder - m_dwLastPause = 1; - - // Resume if we paused before suspension. - if (bWasPausedBeforeSuspention) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); // Resume - } - break; - } - - return __super::OnPowerBroadcast(nPowerEvent, nEventData); -} - -#define NOTIFY_FOR_THIS_SESSION 0 - -void CMainFrame::OnSessionChange(UINT nSessionState, UINT nId) -{ - if (AfxGetAppSettings().bLockNoPause) { - return; - } - - static BOOL bWasPausedBeforeSessionChange; - - switch (nSessionState) { - case WTS_SESSION_LOCK: - TRACE(_T("OnSessionChange - Lock session\n")); - bWasPausedBeforeSessionChange = FALSE; - - if (GetMediaState() == State_Running && !m_fAudioOnly) { - bWasPausedBeforeSessionChange = TRUE; - SendMessage(WM_COMMAND, ID_PLAY_PAUSE); - } - break; - case WTS_SESSION_UNLOCK: - TRACE(_T("OnSessionChange - UnLock session\n")); - - if (bWasPausedBeforeSessionChange) { - SendMessage(WM_COMMAND, ID_PLAY_PLAY); - } - break; - } -} - -void CMainFrame::WTSRegisterSessionNotification() -{ - const WinapiFunc - fnWtsRegisterSessionNotification = { _T("wtsapi32.dll"), "WTSRegisterSessionNotification" }; - - if (fnWtsRegisterSessionNotification) { - fnWtsRegisterSessionNotification(m_hWnd, NOTIFY_FOR_THIS_SESSION); - } -} - -void CMainFrame::WTSUnRegisterSessionNotification() -{ - const WinapiFunc - fnWtsUnRegisterSessionNotification = { _T("wtsapi32.dll"), "WTSUnRegisterSessionNotification" }; - - if (fnWtsUnRegisterSessionNotification) { - fnWtsUnRegisterSessionNotification(m_hWnd); - } -} - -void CMainFrame::UpdateSkypeHandler() -{ - const auto& s = AfxGetAppSettings(); - if (s.bNotifySkype && !m_pSkypeMoodMsgHandler) { - m_pSkypeMoodMsgHandler.Attach(DEBUG_NEW SkypeMoodMsgHandler()); - m_pSkypeMoodMsgHandler->Connect(m_hWnd); - } else if (!s.bNotifySkype && m_pSkypeMoodMsgHandler) { - m_pSkypeMoodMsgHandler.Free(); - } -} - -void CMainFrame::UpdateSeekbarChapterBag() -{ - const auto& s = AfxGetAppSettings(); - if (s.fShowChapters && m_pCB && m_pCB->ChapGetCount() > 0) { - m_wndSeekBar.SetChapterBag(m_pCB); - m_OSD.SetChapterBag(m_pCB); - } else { - m_wndSeekBar.RemoveChapters(); - m_OSD.RemoveChapters(); - } -} - -void CMainFrame::UpdateAudioSwitcher() -{ - CAppSettings& s = AfxGetAppSettings(); - CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); - - if (pASF) { - pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); - pASF->EnableDownSamplingTo441(s.fDownSampleTo441); - pASF->SetAudioTimeShift(s.fAudioTimeShift ? 10000i64 * s.iAudioTimeShift : 0); - pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); - } -} - -void CMainFrame::LoadArtToViews(const CString& imagePath) -{ - m_wndView.LoadImg(imagePath); - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->LoadImg(imagePath); - } -} - -void CMainFrame::LoadArtToViews(std::vector buffer) -{ - m_wndView.LoadImg(buffer); - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->LoadImg(buffer); - } -} - -void CMainFrame::ClearArtFromViews() -{ - m_wndView.LoadImg(); - if (HasDedicatedFSVideoWindow()) { - m_pDedicatedFSVideoWnd->LoadImg(); - } -} - -void CMainFrame::UpdateControlState(UpdateControlTarget target) -{ - const auto& s = AfxGetAppSettings(); - switch (target) { - case UPDATE_VOLUME_STEP: - m_wndToolBar.m_volctrl.SetPageSize(s.nVolumeStep); - break; - case UPDATE_LOGO: - if (GetLoadState() == MLS::LOADED && m_fAudioOnly && s.bEnableCoverArt) { - CString filename = m_wndPlaylistBar.GetCurFileName(); - CString filename_no_ext; - CString filedir; - if (!PathUtils::IsURL(filename)) { - CPath path = CPath(filename); - if (path.FileExists()) { - path.RemoveExtension(); - filename_no_ext = path.m_strPath; - path.RemoveFileSpec(); - filedir = path.m_strPath; - } - } - - CString author; - m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); - - CComQIPtr pFilterGraph = m_pGB; - std::vector internalCover; - if (CoverArt::FindEmbedded(pFilterGraph, internalCover)) { - LoadArtToViews(internalCover); - m_currentCoverPath = filename; - m_currentCoverAuthor = author; - } else { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli) && !pli.m_cover.IsEmpty() && CPath(pli.m_cover).FileExists()) { - LoadArtToViews(pli.m_cover); - } else if (!filedir.IsEmpty() && (m_currentCoverPath != filedir || m_currentCoverAuthor != author || currentCoverIsFileArt)) { - CString img = CoverArt::FindExternal(filename_no_ext, filedir, author, currentCoverIsFileArt); - LoadArtToViews(img); - m_currentCoverPath = filedir; - m_currentCoverAuthor = author; - } else if (!m_wndView.IsCustomImgLoaded()) { - ClearArtFromViews(); - } - } - } else { - m_currentCoverPath.Empty(); - m_currentCoverAuthor.Empty(); - ClearArtFromViews(); - } - break; - case UPDATE_SKYPE: - UpdateSkypeHandler(); - break; - case UPDATE_SEEKBAR_CHAPTERS: - UpdateSeekbarChapterBag(); - break; - case UPDATE_WINDOW_TITLE: - OpenSetupWindowTitle(); - break; - case UPDATE_AUDIO_SWITCHER: - UpdateAudioSwitcher(); - break; - case UPDATE_CONTROLS_VISIBILITY: - m_controls.UpdateToolbarsVisibility(); - break; - case UPDATE_CHILDVIEW_CURSOR_HACK: - // HACK: windowed (not renderless) video renderers created in graph thread do not - // produce WM_MOUSEMOVE message when we release mouse capture on top of it, here's a workaround - m_timerOneTime.Subscribe(TimerOneTimeSubscriber::CHILDVIEW_CURSOR_HACK, std::bind(&CChildView::Invalidate, &m_wndView, FALSE), 16); - break; - default: - ASSERT(FALSE); - } -} - -void CMainFrame::ReloadMenus() { - // CMenu defaultMenu; - CMenu* oldMenu; - - // Destroy the dynamic menus before reloading the main menus - DestroyDynamicMenus(); - - // Reload the main menus - m_popupMenu.DestroyMenu(); - m_popupMenu.LoadMenu(IDR_POPUP); - m_mainPopupMenu.DestroyMenu(); - m_mainPopupMenu.LoadMenu(IDR_POPUPMAIN); - - oldMenu = GetMenu(); - defaultMPCThemeMenu = DEBUG_NEW CMPCThemeMenu(); //will have been destroyed - defaultMPCThemeMenu->LoadMenu(IDR_MAINFRAME); - if (oldMenu) { - // Attach the new menu to the window only if there was a menu before - SetMenu(defaultMPCThemeMenu); - // and then destroy the old one - oldMenu->DestroyMenu(); - delete oldMenu; - } - //we don't detach because we retain the cmenu - //m_hMenuDefault = defaultMenu.Detach(); - m_hMenuDefault = defaultMPCThemeMenu->GetSafeHmenu(); - - m_popupMenu.fulfillThemeReqs(); - m_mainPopupMenu.fulfillThemeReqs(); - defaultMPCThemeMenu->fulfillThemeReqs(true); - - // Reload the dynamic menus - CreateDynamicMenus(); -} - - -void CMainFrame::UpdateUILanguage() -{ - ReloadMenus(); - - // Reload the static bars - OpenSetupInfoBar(); - if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - UpdateCurrentChannelInfo(false, false); - } - OpenSetupStatsBar(); - - // Reload the debug shaders dialog if need be - if (m_pDebugShaders && IsWindow(m_pDebugShaders->m_hWnd)) { - BOOL bWasVisible = m_pDebugShaders->IsWindowVisible(); - VERIFY(m_pDebugShaders->DestroyWindow()); - m_pDebugShaders = std::make_unique(); - if (bWasVisible) { - m_pDebugShaders->ShowWindow(SW_SHOWNA); - // Don't steal focus from main frame - SetActiveWindow(); - } - } -} - -bool CMainFrame::OpenBD(CString Path) -{ - CHdmvClipInfo ClipInfo; - CString strPlaylistFile; - CHdmvClipInfo::HdmvPlaylist MainPlaylist; - -#if INTERNAL_SOURCEFILTER_MPEG - const CAppSettings& s = AfxGetAppSettings(); - bool InternalMpegSplitter = s.SrcFilters[SRC_MPEG] || s.SrcFilters[SRC_MPEGTS]; -#else - bool InternalMpegSplitter = false; -#endif - - m_LastOpenBDPath = Path; - - CString ext = CPath(Path).GetExtension(); - ext.MakeLower(); - - if ((CPath(Path).IsDirectory() && Path.Find(_T("\\BDMV"))) - || CPath(Path + _T("\\BDMV")).IsDirectory() - || (!ext.IsEmpty() && ext == _T(".bdmv"))) { - if (!ext.IsEmpty() && ext == _T(".bdmv")) { - Path.Replace(_T("\\BDMV\\"), _T("\\")); - CPath _Path(Path); - _Path.RemoveFileSpec(); - Path = CString(_Path); - } else if (Path.Find(_T("\\BDMV"))) { - Path.Replace(_T("\\BDMV"), _T("\\")); - } - if (SUCCEEDED(ClipInfo.FindMainMovie(Path, strPlaylistFile, MainPlaylist, m_MPLSPlaylist))) { - m_bIsBDPlay = true; - - m_bHasBDMeta = ClipInfo.ReadMeta(Path, m_BDMeta); - - if (!InternalMpegSplitter && !ext.IsEmpty() && ext == _T(".bdmv")) { - return false; - } else { - m_wndPlaylistBar.Empty(); - CAtlList sl; - - if (InternalMpegSplitter) { - sl.AddTail(CString(strPlaylistFile)); - } else { - sl.AddTail(CString(Path + _T("\\BDMV\\index.bdmv"))); - } - - m_wndPlaylistBar.Append(sl, false); - OpenCurPlaylistItem(); - return true; - } - } - } - - m_LastOpenBDPath = _T(""); - return false; -} - -// Returns the the corresponding subInput or nullptr in case of error. -// i is modified to reflect the locale index of track -SubtitleInput* CMainFrame::GetSubtitleInput(int& i, bool bIsOffset /*= false*/) -{ - // Only 1, 0 and -1 are supported offsets - if ((bIsOffset && (i < -1 || i > 1)) || (!bIsOffset && i < 0)) { - return nullptr; - } - - POSITION pos = m_pSubStreams.GetHeadPosition(); - SubtitleInput* pSubInput = nullptr, *pSubInputPrec = nullptr; - int iLocalIdx = -1, iLocalIdxPrec = -1; - bool bNextTrack = false; - - while (pos && !pSubInput) { - SubtitleInput& subInput = m_pSubStreams.GetNext(pos); - - if (CComQIPtr pSSF = subInput.pSourceFilter) { - DWORD cStreams; - if (FAILED(pSSF->Count(&cStreams))) { - continue; - } - - for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { - DWORD dwFlags, dwGroup; - - if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { - continue; - } - - if (dwGroup != 2) { - continue; - } - - if (bIsOffset) { - if (bNextTrack) { // We detected previously that the next subtitles track is the one we want to select - pSubInput = &subInput; - iLocalIdx = j; - break; - } else if (subInput.pSubStream == m_pCurrentSubInput.pSubStream - && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { - if (i == 0) { - pSubInput = &subInput; - iLocalIdx = j; - break; - } else if (i > 0) { - bNextTrack = true; // We want to the select the next subtitles track - } else { - // We want the previous subtitles track and we know which one it is - if (pSubInputPrec) { - pSubInput = pSubInputPrec; - iLocalIdx = iLocalIdxPrec; - break; - } - } - } - - pSubInputPrec = &subInput; - iLocalIdxPrec = j; - } else { - if (i == 0) { - pSubInput = &subInput; - iLocalIdx = j; - break; - } - - i--; - } - } - } else { - if (bIsOffset) { - if (bNextTrack) { // We detected previously that the next subtitles track is the one we want to select - pSubInput = &subInput; - iLocalIdx = 0; - break; - } else if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { - iLocalIdx = subInput.pSubStream->GetStream() + i; - if (iLocalIdx >= 0 && iLocalIdx < subInput.pSubStream->GetStreamCount()) { - // The subtitles track we want to select is part of this substream - pSubInput = &subInput; - } else if (i > 0) { // We want to the select the next subtitles track - bNextTrack = true; - } else { - // We want the previous subtitles track and we know which one it is - if (pSubInputPrec) { - pSubInput = pSubInputPrec; - iLocalIdx = iLocalIdxPrec; - } - } - } else { - pSubInputPrec = &subInput; - iLocalIdxPrec = subInput.pSubStream->GetStreamCount() - 1; - } - } else { - if (i < subInput.pSubStream->GetStreamCount()) { - pSubInput = &subInput; - iLocalIdx = i; - } else { - i -= subInput.pSubStream->GetStreamCount(); - } - } - } - - // Handle special cases - if (!pos && !pSubInput && bIsOffset) { - if (bNextTrack) { // The last subtitles track was selected and we want the next one - // Let's restart the loop to select the first subtitles track - pos = m_pSubStreams.GetHeadPosition(); - } else if (i < 0) { // The first subtitles track was selected and we want the previous one - pSubInput = pSubInputPrec; // We select the last track - iLocalIdx = iLocalIdxPrec; - } - } - } - - i = iLocalIdx; - - return pSubInput; -} - -CString CMainFrame::GetFileName() -{ - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true)) { - CString path(m_wndPlaylistBar.GetCurFileName(true)); - if (!pli.m_bYoutubeDL && m_pFSF) { - CComHeapPtr pFN; - if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, nullptr))) { - path = pFN; - } - } - if (PathUtils::IsURL(path)) { - path = ShortenURL(path); - } - return pli.m_bYoutubeDL ? path : PathUtils::StripPathOrUrl(path); - } - return _T(""); -} - -CString CMainFrame::GetCaptureTitle() -{ - CString title; - - title.LoadString(IDS_CAPTURE_LIVE); - if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { - CString devName = GetFriendlyName(m_VidDispName); - if (!devName.IsEmpty()) { - title.AppendFormat(_T(" | %s"), devName.GetString()); - } - } else { - CString& eventName = m_pDVBState->NowNext.eventName; - if (m_pDVBState->bActive) { - title.AppendFormat(_T(" | %s"), m_pDVBState->sChannelName.GetString()); - if (!eventName.IsEmpty()) { - title.AppendFormat(_T(" - %s"), eventName.GetString()); - } - } else { - title += _T(" | DVB"); - } - } - return title; -} - -GUID CMainFrame::GetTimeFormat() -{ - GUID ret; - if (!m_pMS || !SUCCEEDED(m_pMS->GetTimeFormat(&ret))) { - ASSERT(FALSE); - ret = TIME_FORMAT_NONE; - } - return ret; -} - -void CMainFrame::UpdateDXVAStatus() -{ - CString DXVAInfo; - // We only support getting info from LAV Video Decoder is that is what will be used 99% of the time - if (CComQIPtr pLAVVideoStatus = FindFilter(GUID_LAVVideo, m_pGB)) { - const LPCWSTR decoderName = pLAVVideoStatus->GetActiveDecoderName(); - if (decoderName == nullptr || wcscmp(decoderName, L"avcodec") == 0 || wcscmp(decoderName, L"wmv9 mft") == 0 || wcscmp(decoderName, L"msdk mvc") == 0) { - DXVAInfo = _T("H/W Decoder : None"); - } else { - m_bUsingDXVA = true; - m_HWAccelType = CFGFilterLAVVideo::GetUserFriendlyDecoderName(decoderName); - DXVAInfo.Format(_T("H/W Decoder : %s"), m_HWAccelType); - } - } else { - DXVAInfo = _T("H/W Decoder : None / Unknown"); - } - GetRenderersData()->m_strDXVAInfo = DXVAInfo; -} - -bool CMainFrame::GetDecoderType(CString& type) const -{ - if (!m_fAudioOnly) { - if (m_bUsingDXVA) { - type = m_HWAccelType; - } else { - type.LoadString(IDS_TOOLTIP_SOFTWARE_DECODING); - } - return true; - } - return false; -} - -void CMainFrame::UpdateSubtitleRenderingParameters() -{ - if (!m_pCAP) { - return; - } - - const CAppSettings& s = AfxGetAppSettings(); - if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { - bool bChangeStorageRes = false; - bool bChangePARComp = false; - double dPARCompensation = 1.0; - bool bKeepAspectRatio = s.fKeepAspectRatio; - - CSize szAspectRatio = m_pCAP->GetVideoSize(true); - CSize szVideoFrame; - if (m_pMVRI) { - // Use IMadVRInfo to get size. See http://bugs.madshi.net/view.php?id=180 - m_pMVRI->GetSize("originalVideoSize", &szVideoFrame); - bKeepAspectRatio = true; - } else { - szVideoFrame = m_pCAP->GetVideoSize(false); - } - - if (s.bSubtitleARCompensation && szAspectRatio.cx && szAspectRatio.cy && szVideoFrame.cx && szVideoFrame.cy && bKeepAspectRatio) { - if (pRTS->m_layoutRes.cx > 0) { - dPARCompensation = (double)szAspectRatio.cx * pRTS->m_layoutRes.cy / (szAspectRatio.cy * pRTS->m_layoutRes.cx); - } else { - dPARCompensation = (double)szAspectRatio.cx * szVideoFrame.cy / (szAspectRatio.cy * szVideoFrame.cx); - } - } - if (pRTS->m_dPARCompensation != dPARCompensation) { - bChangePARComp = true; - } - - if (pRTS->m_subtitleType == Subtitle::ASS || pRTS->m_subtitleType == Subtitle::SSA) { - if (szVideoFrame.cx > 0) { - if (pRTS->m_layoutRes.cx == 0 || pRTS->m_layoutRes.cy == 0) { - bChangeStorageRes = (pRTS->m_storageRes != szVideoFrame); - } else { - bChangeStorageRes = (pRTS->m_storageRes != pRTS->m_layoutRes); - } - } - } - - { - CAutoLock cAutoLock(&m_csSubLock); - if (bChangeStorageRes) { - if (pRTS->m_layoutRes.cx == 0 || pRTS->m_layoutRes.cy == 0) { - pRTS->m_storageRes = szVideoFrame; - } else { - pRTS->m_storageRes = pRTS->m_layoutRes; - } - } - if (bChangePARComp) { - pRTS->m_ePARCompensationType = CSimpleTextSubtitle::EPARCompensationType::EPCTAccurateSize_ISR; - pRTS->m_dPARCompensation = dPARCompensation; - } - - STSStyle style = s.subtitlesDefStyle; - if (pRTS->m_bUsingPlayerDefaultStyle) { - pRTS->SetDefaultStyle(style); - } else if (pRTS->GetDefaultStyle(style) && style.relativeTo == STSStyle::AUTO && s.subtitlesDefStyle.relativeTo != STSStyle::AUTO) { - style.relativeTo = s.subtitlesDefStyle.relativeTo; - pRTS->SetDefaultStyle(style); - } - pRTS->SetOverride(s.bSubtitleOverrideDefaultStyle, s.bSubtitleOverrideAllStyles, s.subtitlesDefStyle); - pRTS->SetAlignment(s.fOverridePlacement, s.nHorPos, s.nVerPos); - pRTS->SetUseFreeType(s.bUseFreeType); - pRTS->SetOpenTypeLangHint(s.strOpenTypeLangHint); - pRTS->Deinit(); - } - m_pCAP->Invalidate(); - } else if (auto pVSS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { - { - CAutoLock cAutoLock(&m_csSubLock); - pVSS->SetAlignment(s.fOverridePlacement, s.nHorPos, s.nVerPos); - } - m_pCAP->Invalidate(); - } -} - -REFTIME CMainFrame::GetAvgTimePerFrame() const -{ - REFTIME refAvgTimePerFrame = 0.0; - - if (FAILED(m_pBV->get_AvgTimePerFrame(&refAvgTimePerFrame))) { - if (m_pCAP) { - refAvgTimePerFrame = 1.0 / m_pCAP->GetFPS(); - } - - BeginEnumFilters(m_pGB, pEF, pBF) { - if (refAvgTimePerFrame > 0.0) { - break; - } - - BeginEnumPins(pBF, pEP, pPin) { - AM_MEDIA_TYPE mt; - if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { - if (mt.majortype == MEDIATYPE_Video && mt.formattype == FORMAT_VideoInfo) { - refAvgTimePerFrame = (REFTIME)((VIDEOINFOHEADER*)mt.pbFormat)->AvgTimePerFrame / 10000000i64; - break; - } else if (mt.majortype == MEDIATYPE_Video && mt.formattype == FORMAT_VideoInfo2) { - refAvgTimePerFrame = (REFTIME)((VIDEOINFOHEADER2*)mt.pbFormat)->AvgTimePerFrame / 10000000i64; - break; - } - } - } - EndEnumPins; - } - EndEnumFilters; - } - - // Double-check that the detection is correct for DVDs - DVD_VideoAttributes VATR; - if (m_pDVDI && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { - double ratio; - if (VATR.ulFrameRate == 50) { - ratio = 25.0 * refAvgTimePerFrame; - // Accept 25 or 50 fps - if (!IsNearlyEqual(ratio, 1.0, 1e-2) && !IsNearlyEqual(ratio, 2.0, 1e-2)) { - refAvgTimePerFrame = 1.0 / 25.0; - } - } else { - ratio = 29.97 * refAvgTimePerFrame; - // Accept 29,97, 59.94, 23.976 or 47.952 fps - if (!IsNearlyEqual(ratio, 1.0, 1e-2) && !IsNearlyEqual(ratio, 2.0, 1e-2) - && !IsNearlyEqual(ratio, 1.25, 1e-2) && !IsNearlyEqual(ratio, 2.5, 1e-2)) { - refAvgTimePerFrame = 1.0 / 29.97; - } - } - } - - return refAvgTimePerFrame; -} - -void CMainFrame::OnVideoSizeChanged(const bool bWasAudioOnly /*= false*/) -{ - const auto& s = AfxGetAppSettings(); - if (GetLoadState() == MLS::LOADED && - ((s.fRememberZoomLevel && (s.fLimitWindowProportions || m_bAllowWindowZoom)) || m_fAudioOnly || bWasAudioOnly) && - !(IsFullScreenMode() || IsZoomed() || IsIconic() || IsAeroSnapped())) { - CSize videoSize; - if (!m_fAudioOnly && !m_bAllowWindowZoom) { - videoSize = GetVideoSize(); - } - if (videoSize.cx && videoSize.cy) { - ZoomVideoWindow(m_dLastVideoScaleFactor * std::sqrt((static_cast(m_lastVideoSize.cx) * m_lastVideoSize.cy) - / (static_cast(videoSize.cx) * videoSize.cy))); - } else { - ZoomVideoWindow(); - } - } - MoveVideoWindow(); -} - -typedef struct { - SubtitlesInfo* pSubtitlesInfo; - BOOL bActivate; - std::string fileName; - std::string fileContents; -} SubtitlesData; - -LRESULT CMainFrame::OnLoadSubtitles(WPARAM wParam, LPARAM lParam) -{ - SubtitlesData& data = *(SubtitlesData*)lParam; - - CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); - if (pRTS) { - if (pRTS->Open(CString(data.pSubtitlesInfo->Provider()->DisplayName().c_str()), - (BYTE*)(LPCSTR)data.fileContents.c_str(), (int)data.fileContents.length(), DEFAULT_CHARSET, - UTF8To16(data.fileName.c_str()), Subtitle::HearingImpairedType(data.pSubtitlesInfo->hearingImpaired), - ISOLang::ISO6391ToLcid(data.pSubtitlesInfo->languageCode.c_str())) && pRTS->GetStreamCount() > 0) { - m_wndSubtitlesDownloadDialog.DoDownloaded(*data.pSubtitlesInfo); -#if USE_LIBASS - if (pRTS->m_LibassContext.IsLibassActive()) { - pRTS->m_LibassContext.SetFilterGraph(m_pGB); - } -#endif - SubtitleInput subElement = pRTS.Detach(); - m_pSubStreams.AddTail(subElement); - if (data.bActivate) { - m_ExternalSubstreams.push_back(subElement.pSubStream); - SetSubtitle(subElement.pSubStream); - - auto& s = AfxGetAppSettings(); - if (s.fKeepHistory && s.bRememberTrackSelection && s.bAutoSaveDownloadedSubtitles) { - s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); - } - } - return TRUE; - } - } - - return FALSE; -} - -LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) -{ - CheckPointer(lParam, FALSE); - - int n = 0; - SubtitleInput* pSubInput = GetSubtitleInput(n, true); - CheckPointer(pSubInput, FALSE); - - CLSID clsid; - if (FAILED(pSubInput->pSubStream->GetClassID(&clsid)) || clsid != __uuidof(CRenderedTextSubtitle)) { - return FALSE; - } - - CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; - // Only for external text subtitles - if (pRTS->m_path.IsEmpty()) { - return FALSE; - } - - SubtitlesInfo* pSubtitlesInfo = reinterpret_cast(lParam); - - pSubtitlesInfo->GetFileInfo(); - pSubtitlesInfo->releaseNames.emplace_back(UTF16To8(pRTS->m_name)); - if (pSubtitlesInfo->hearingImpaired == Subtitle::HI_UNKNOWN) { - pSubtitlesInfo->hearingImpaired = pRTS->m_eHearingImpaired; - } - - if (!pSubtitlesInfo->languageCode.length() && pRTS->m_lcid && pRTS->m_lcid != LCID(-1)) { - CString str; - GetLocaleString(pRTS->m_lcid, LOCALE_SISO639LANGNAME, str); - pSubtitlesInfo->languageCode = UTF16To8(str); - } - - pSubtitlesInfo->frameRate = m_pCAP->GetFPS(); - int delay = m_pCAP->GetSubtitleDelay(); - if (pRTS->m_mode == FRAME) { - delay = std::lround(delay * pSubtitlesInfo->frameRate / 1000.0); - } - - const CStringW fmt(L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n"); - CStringW content; - CAutoLock cAutoLock(&m_csSubLock); - for (int i = 0, j = int(pRTS->GetCount()), k = 0; i < j; i++) { - int t1 = (int)(RT2MS(pRTS->TranslateStart(i, pSubtitlesInfo->frameRate)) + delay); - if (t1 < 0) { - k++; - continue; - } - - int t2 = (int)(RT2MS(pRTS->TranslateEnd(i, pSubtitlesInfo->frameRate)) + delay); - - int hh1 = (t1 / 60 / 60 / 1000); - int mm1 = (t1 / 60 / 1000) % 60; - int ss1 = (t1 / 1000) % 60; - int ms1 = (t1) % 1000; - int hh2 = (t2 / 60 / 60 / 1000); - int mm2 = (t2 / 60 / 1000) % 60; - int ss2 = (t2 / 1000) % 60; - int ms2 = (t2) % 1000; - - content.AppendFormat(fmt, i - k + 1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, pRTS->GetStrW(i, false).GetString()); - } - - pSubtitlesInfo->fileContents = UTF16To8(content); - return TRUE; -} - -static const CString ydl_whitelist[] = { - _T("youtube.com/"), - _T("youtu.be/"), - _T("twitch.tv/"), - _T("twitch.com/") -}; - -static const CString ydl_blacklist[] = { - _T("googlevideo.com/videoplayback"), // already processed URL - _T("googlevideo.com/api/manifest"), - _T("@127.0.0.1:"), // local URL - _T("saunalahti.fi/") -}; - -bool CMainFrame::IsOnYDLWhitelist(CString url) { - for (int i = 0; i < _countof(ydl_whitelist); i++) { - if (url.Find(ydl_whitelist[i]) >= 0) { - return true; - } - } - return false; -} - -bool CMainFrame::CanSendToYoutubeDL(const CString url) -{ - if (url.Left(4).MakeLower() == _T("http") && AfxGetAppSettings().bUseYDL) { - // Blacklist: don't use for IP addresses - std::wcmatch regmatch; - std::wregex regexp(LR"(https?:\/\/(\d{1,3}\.){3}\d{1,3}.*)"); - if (std::regex_match(url.GetString(), regmatch, regexp)) { - return false; - } - - // Whitelist: popular supported sites - if (IsOnYDLWhitelist(url)) { - return true; - } - - // Blacklist: unsupported sites where YDL causes an error or long delay - for (int i = 0; i < _countof(ydl_blacklist); i++) { - if (url.Find(ydl_blacklist[i], 7) > 0) { - return false; - } - } - - // Blacklist: URL points to a file - CString baseurl; - int q = url.Find(_T('?')); - if (q > 0) { - baseurl = url.Left(q); - } else { - baseurl = url; - q = url.GetLength(); - } - int p = baseurl.ReverseFind(_T('.')); - if (p > 0 && (q - p <= 6)) { - CString ext = baseurl.Mid(p); - if (AfxGetAppSettings().m_Formats.FindExt(ext)) { - return false; - } - } - - return true; - } - return false; -} - -bool CMainFrame::ProcessYoutubeDLURL(CString url, bool append, bool replace) -{ - auto& s = AfxGetAppSettings(); - CAtlList streams; - CAtlList filenames; - CYoutubeDLInstance ydl; - CYoutubeDLInstance::YDLPlaylistInfo listinfo; - CString useragent; - - m_sydlLastProcessURL = url; - - m_wndStatusBar.SetStatusMessage(ResStr(IDS_CONTROLS_YOUTUBEDL)); - - if (!ydl.Run(url)) { - return false; - } - if (!ydl.GetHttpStreams(streams, listinfo, useragent)) { - return false; - } - - if (!append && !replace) { - m_wndPlaylistBar.Empty(); - } - - CString f_title; - - for (unsigned int i = 0; i < streams.GetCount(); i++) { - auto stream = streams.GetAt(streams.FindIndex(i)); - CString v_url = stream.video_url; - CString a_url = stream.audio_url; - filenames.RemoveAll(); - if (!v_url.IsEmpty() && (!s.bYDLAudioOnly || a_url.IsEmpty())) { - filenames.AddTail(v_url); - - } - if (!a_url.IsEmpty()) { - filenames.AddTail(a_url); - } - CString title = stream.title; - CString seasonid; - if (stream.season_number != -1) { - seasonid.Format(_T("S%02d"), stream.season_number); - } - CString episodeid; - if (stream.episode_number != -1) { - episodeid.Format(_T("E%02d"), stream.episode_number); - } - CString epiid; - if (!seasonid.IsEmpty() || !episodeid.IsEmpty()) { - epiid.Format(_T("%s%s. "), static_cast(seasonid), static_cast(episodeid)); - } - CString season; - if (!stream.series.IsEmpty()) { - season = stream.series; - CString t(stream.season.Left(6)); - if (!stream.season.IsEmpty() && (t.MakeLower() != _T("season") || stream.season_number == -1)) { - season += _T(" ") + stream.season; - } - season += _T(" - "); - } - else if (!stream.season.IsEmpty()) { - CString t(stream.season.Left(6)); - if (t.MakeLower() != _T("season") || stream.season_number == -1) { - season = stream.season + _T(" - "); - } - } - title.Format(_T("%s%s%s"), static_cast(epiid), static_cast(season), static_cast(title)); - if (i == 0) f_title = title; - - CString ydl_src = stream.webpage_url.IsEmpty() ? url : stream.webpage_url; - if (i == 0) m_sydlLastProcessURL = ydl_src; - - int targetlen = title.GetLength() > 100 ? 50 : 150 - title.GetLength(); - CString short_url = ShortenURL(ydl_src, targetlen, true); - - if (ydl_src == filenames.GetHead()) { - // Processed URL is same as input, can happen for DASH manifest files. Clear source URL to avoid reprocessing. - ydl_src = _T(""); - } - - if (replace) { - m_wndPlaylistBar.ReplaceCurrentItem(filenames, nullptr, title + " (" + short_url + ")", ydl_src, useragent, _T(""), &stream.subtitles); - break; - } else { - m_wndPlaylistBar.Append(filenames, false, nullptr, title + " (" + short_url + ")", ydl_src, useragent, _T(""), &stream.subtitles); - } - } - - if (s.fKeepHistory) { - auto* mru = &s.MRU; - RecentFileEntry r; - mru->LoadMediaHistoryEntryFN(m_sydlLastProcessURL, r); - if (streams.GetCount() > 1) { - auto h = streams.GetHead(); - if (!h.series.IsEmpty()) { - r.title = h.series; - if (!h.season.IsEmpty()) { - r.title += _T(" - ") + h.season; - } - } - else if (!h.season.IsEmpty()) { - r.title = h.season; - } - else if (!listinfo.title.IsEmpty()) { - if (!listinfo.uploader.IsEmpty()) r.title.Format(_T("%s - %s"), static_cast(listinfo.uploader), static_cast(listinfo.title)); - else r.title = listinfo.title; - } - else r.title = f_title; - } - else if (streams.GetCount() == 1) { - r.title = f_title; - } - mru->Add(r, false); - } - - if (!append && (!replace || m_wndPlaylistBar.GetCount() == 0)) { - m_wndPlaylistBar.SetFirst(); - } - return true; -} - -bool CMainFrame::DownloadWithYoutubeDL(CString url, CString filename) -{ - PROCESS_INFORMATION proc_info; - STARTUPINFO startup_info; - const auto& s = AfxGetAppSettings(); - - bool ytdlp = true; - CString args = _T("\"") + GetYDLExePath(&ytdlp) + _T("\" --console-title \"") + url + _T("\""); - if (!s.sYDLCommandLine.IsEmpty()) { - args.Append(_T(" ")); - args.Append(s.sYDLCommandLine); - } - if (s.bYDLAudioOnly && (s.sYDLCommandLine.Find(_T("-f ")) < 0)) { - args.Append(_T(" -f bestaudio")); - } - if (s.sYDLCommandLine.Find(_T("-o ")) < 0) { - args.Append(_T(" -o \"" + filename + "\"")); - } - - ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&startup_info, sizeof(STARTUPINFO)); - startup_info.cb = sizeof(STARTUPINFO); - - if (!CreateProcess(NULL, args.GetBuffer(), NULL, NULL, false, 0, - NULL, NULL, &startup_info, &proc_info)) { - AfxMessageBox(_T("An error occurred while attempting to run Youtube-DL"), MB_ICONERROR, 0); - return false; - } - - CloseHandle(proc_info.hProcess); - CloseHandle(proc_info.hThread); - - return true; -} - -void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) -{ - __super::OnSettingChange(uFlags, lpszSection); - if (SPI_SETNONCLIENTMETRICS == uFlags) { - CMPCThemeUtil::GetMetrics(true); - CMPCThemeMenu::clearDimensions(); - if (nullptr != defaultMPCThemeMenu) { - UpdateUILanguage(); //cheap way to rebuild menus--we want to do this to force them to re-measure - } - RecalcLayout(); - } -} - -BOOL CMainFrame::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) { - if (m_bUseSeekPreview && m_wndPreView.IsWindowVisible()) { - - int seek = - nFlags == MK_SHIFT ? 10 : - nFlags == MK_CONTROL ? 1 : 5; - - zDelta > 0 ? SetCursorPos(point.x + seek, point.y) : - zDelta < 0 ? SetCursorPos(point.x - seek, point.y) : SetCursorPos(point.x, point.y); - - return 0; - } - return __super::OnMouseWheel(nFlags, zDelta, point); -} - -void CMainFrame::OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt) { - if (m_wndView && m_wndView.OnMouseHWheelImpl(nFlags, zDelta, pt)) { - //HWHEEL is sent to active window, so we have to manually pass it to CMouseWnd to trap hotkeys - return; - } - __super::OnMouseHWheel(nFlags, zDelta, pt); -} - -CHdmvClipInfo::BDMVMeta CMainFrame::GetBDMVMeta() -{ - return m_BDMeta.GetHead(); -} - -BOOL CMainFrame::AppendMenuEx(CMenu& menu, UINT nFlags, UINT nIDNewItem, CString& text) -{ - text.Replace(_T("&"), _T("&&")); - auto bResult = menu.AppendMenu(nFlags, nIDNewItem, text.GetString()); - if (bResult && (nFlags & MF_DEFAULT)) { - bResult = menu.SetDefaultItem(nIDNewItem); - } - return bResult; -} - -CString CMainFrame::getBestTitle(bool fTitleBarTextTitle) { - CString title; - if (fTitleBarTextTitle && m_pAMMC[0]) { - for (const auto& pAMMC : m_pAMMC) { - if (pAMMC) { - CComBSTR bstr; - if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { - title = bstr.m_str; - title.Trim(); - if (!title.IsEmpty()) { - return title; - } - } - } - } - } - - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_label && !pli.m_label.IsEmpty()) { - if (fTitleBarTextTitle || pli.m_bYoutubeDL) { - title = pli.m_label; - return title; - } - } - - CStringW ext = GetFileExt(GetFileName()); - if (ext == ".mpls" && m_bHasBDMeta) { - title = GetBDMVMeta().title; - return title; - } else if (ext != ".mpls") { - m_bHasBDMeta = false; - m_BDMeta.RemoveAll(); - } - - return L""; -} - -void CMainFrame::MediaTransportControlSetMedia() { - if (m_media_trans_control.smtc_updater && m_media_trans_control.smtc_controls) { - TRACE(_T("CMainFrame::MediaTransportControlSetMedia()\n")); - HRESULT ret = S_OK; - bool have_secondary_title = false; - - CString title = getBestTitle(); - if (title.IsEmpty()) { - title = GetFileName(); - } - - CString author; - if (m_pAMMC[0]) { - for (const auto& pAMMC : m_pAMMC) { - if (pAMMC) { - CComBSTR bstr; - if (SUCCEEDED(pAMMC->get_AuthorName(&bstr)) && bstr.Length()) { - author = bstr.m_str; - author.Trim(); - } - } - } - } - - // Set media details - if (m_fAudioOnly) { - ret = m_media_trans_control.smtc_updater->put_Type(ABI::Windows::Media::MediaPlaybackType_Music); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: put_Type error %ld\n"), ret); - return; - } - - CComPtr pMusicDisplayProperties; - ret = m_media_trans_control.smtc_updater->get_MusicProperties(&pMusicDisplayProperties); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: get_MusicProperties error %ld\n"), ret); - return; - } - - if (!title.IsEmpty()) { - HSTRING ttitle; - if (WindowsCreateString(title.GetString(), title.GetLength(), &ttitle) == S_OK) { - ret = pMusicDisplayProperties->put_Title(ttitle); - ASSERT(ret == S_OK); - } - } - if (!author.IsEmpty()) { - HSTRING temp; - if (WindowsCreateString(author.GetString(), author.GetLength(), &temp) == S_OK) { - ret = pMusicDisplayProperties->put_Artist(temp); - ASSERT(ret == S_OK); - } - } - } else { - ret = m_media_trans_control.smtc_updater->put_Type(ABI::Windows::Media::MediaPlaybackType_Video); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: put_Type error %ld\n"), ret); - return; - } - - CComPtr pVideoDisplayProperties; - ret = m_media_trans_control.smtc_updater->get_VideoProperties(&pVideoDisplayProperties); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: get_VideoProperties error %ld\n"), ret); - return; - } - - if (!title.IsEmpty()) { - HSTRING ttitle; - if (WindowsCreateString(title.GetString(), title.GetLength(), &ttitle) == S_OK) { - ret = pVideoDisplayProperties->put_Title(ttitle); - ASSERT(ret == S_OK); - } - } - CString chapter; - if (m_pCB) { - DWORD dwChapCount = m_pCB->ChapGetCount(); - if (dwChapCount) { - REFERENCE_TIME rtNow; - m_pMS->GetCurrentPosition(&rtNow); - - CComBSTR bstr; - long currentChap = m_pCB->ChapLookup(&rtNow, &bstr); - if (bstr.Length()) { - chapter.Format(_T("%s (%ld/%lu)"), bstr.m_str, std::max(0l, currentChap + 1l), dwChapCount); - } else { - chapter.Format(_T("%ld/%lu"), currentChap + 1, dwChapCount); - } - } - } - if (!chapter.IsEmpty() && chapter != title) { - HSTRING temp; - if (WindowsCreateString(chapter.GetString(), chapter.GetLength(), &temp) == S_OK) { - ret = pVideoDisplayProperties->put_Subtitle(temp); - ASSERT(ret == S_OK); - have_secondary_title = true; - } - } - if (!have_secondary_title && !author.IsEmpty() && author != title) { - HSTRING temp; - if (WindowsCreateString(author.GetString(), author.GetLength(), &temp) == S_OK) { - ret = pVideoDisplayProperties->put_Subtitle(temp); - ASSERT(ret == S_OK); - have_secondary_title = true; - } - } - } - - // Thumbnail - CComQIPtr pFilterGraph = m_pGB; - std::vector internalCover; - if (CoverArt::FindEmbedded(pFilterGraph, internalCover)) { - m_media_trans_control.loadThumbnail(internalCover.data(), internalCover.size()); - } else { - CPlaylistItem pli; - if (m_wndPlaylistBar.GetCur(pli) && !pli.m_cover.IsEmpty()) { - m_media_trans_control.loadThumbnail(pli.m_cover); - } else { - CString filename = m_wndPlaylistBar.GetCurFileName(); - CString filename_no_ext; - CString filedir; - if (!PathUtils::IsURL(filename)) { - CPath path = CPath(filename); - if (path.FileExists()) { - path.RemoveExtension(); - filename_no_ext = path.m_strPath; - path.RemoveFileSpec(); - filedir = path.m_strPath; - bool is_file_art = false; - CString img = CoverArt::FindExternal(filename_no_ext, filedir, author, is_file_art); - if (!img.IsEmpty()) { - if (m_fAudioOnly || is_file_art) { - m_media_trans_control.loadThumbnail(img); - } - } - } - } - } - } - - // Update data and status - ret = m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus::MediaPlaybackStatus_Playing); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: put_PlaybackStatus error %ld\n"), ret); - return; - } - ret = m_media_trans_control.smtc_updater->Update(); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: Update error %ld\n"), ret); - return; - } - // Enable - ret = m_media_trans_control.smtc_controls->put_IsEnabled(true); - if (ret != S_OK) { - TRACE(_T("MediaTransControls: put_IsEnabled error %ld\n"), ret); - return; - } - } -} - -void CMainFrame::MediaTransportControlUpdateState(OAFilterState state) { - if (m_media_trans_control.smtc_controls) { - if (state == State_Running) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Playing); - else if (state == State_Paused) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Paused); - else if (state == State_Stopped) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Stopped); - else m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Changing); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "MainFrm.h" +#include "mplayerc.h" +#include "version.h" + +#include "GraphThread.h" +#include "FGFilterLAV.h" +#include "FGManager.h" +#include "FGManagerBDA.h" +#include "ShockwaveGraph.h" +#include "TextPassThruFilter.h" +#include "FakeFilterMapper2.h" + +#include "FavoriteAddDlg.h" +#include "GoToDlg.h" +#include "MediaTypesDlg.h" +#include "OpenFileDlg.h" +#include "PnSPresetsDlg.h" +#include "SaveDlg.h" +#include "SaveImageDialog.h" +#include "SaveSubtitlesFileDialog.h" +#include "SaveThumbnailsDialog.h" +#include "OpenDirHelper.h" +#include "OpenDlg.h" +#include "TunerScanDlg.h" + +#include "ComPropertySheet.h" +#include "PPageAccelTbl.h" +#include "PPageAudioSwitcher.h" +#include "PPageFileInfoSheet.h" +#include "PPageSheet.h" +#include "PPageSubStyle.h" +#include "PPageSubtitles.h" + +#include "CoverArt.h" +#include "CrashReporter.h" +#include "KeyProvider.h" +#include "SkypeMoodMsgHandler.h" +#include "Translations.h" +#include "UpdateChecker.h" +#include "WebServer.h" +#include +#include +#include + +#include "../DeCSS/VobFile.h" +#include "../Subtitles/PGSSub.h" +#include "../Subtitles/RLECodedSubtitle.h" +#include "../Subtitles/RTS.h" +#include "../Subtitles/STS.h" +#include + +#include "../filters/InternalPropertyPage.h" +#include "../filters/PinInfoWnd.h" +#include "../filters/renderer/SyncClock/SyncClock.h" +#include "../filters/transform/BufferFilter/BufferFilter.h" + +#include +#include +#include +#include + +#include "FullscreenWnd.h" +#include "Monitors.h" + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "YoutubeDL.h" +#include "CMPCThemeMenu.h" +#include "CMPCThemeDockBar.h" +#include "CMPCThemeMiniDockFrameWnd.h" +#include "RarEntrySelectorDialog.h" +#include "FileHandle.h" +#include "MPCFolderPickerDialog.h" + +#include "stb/stb_image.h" +#include "stb/stb_image_resize2.h" + +#include +#undef SubclassWindow + +// IID_IAMLine21Decoder +DECLARE_INTERFACE_IID_(IAMLine21Decoder_2, IAMLine21Decoder, "6E8D4A21-310C-11d0-B79A-00AA003767A7") {}; + +#define MIN_LOGO_WIDTH 400 +#define MIN_LOGO_HEIGHT 150 + +#define PREV_CHAP_THRESHOLD 2 + +static UINT s_uTaskbarRestart = RegisterWindowMessage(_T("TaskbarCreated")); +static UINT WM_NOTIFYICON = RegisterWindowMessage(_T("MYWM_NOTIFYICON")); +static UINT s_uTBBC = RegisterWindowMessage(_T("TaskbarButtonCreated")); + +CMainFrame::PlaybackRateMap CMainFrame::filePlaybackRates = { + { ID_PLAY_PLAYBACKRATE_025, .25f}, + { ID_PLAY_PLAYBACKRATE_050, .50f}, + { ID_PLAY_PLAYBACKRATE_075, .75f}, + { ID_PLAY_PLAYBACKRATE_090, .90f}, + { ID_PLAY_PLAYBACKRATE_100, 1.00f}, + { ID_PLAY_PLAYBACKRATE_110, 1.10f}, + { ID_PLAY_PLAYBACKRATE_125, 1.25f}, + { ID_PLAY_PLAYBACKRATE_150, 1.50f}, + { ID_PLAY_PLAYBACKRATE_200, 2.00f}, + { ID_PLAY_PLAYBACKRATE_300, 3.00f}, + { ID_PLAY_PLAYBACKRATE_400, 4.00f}, + { ID_PLAY_PLAYBACKRATE_600, 6.00f}, + { ID_PLAY_PLAYBACKRATE_800, 8.00f}, +}; + +CMainFrame::PlaybackRateMap CMainFrame::dvdPlaybackRates = { + { ID_PLAY_PLAYBACKRATE_025, .25f}, + { ID_PLAY_PLAYBACKRATE_050, .50f}, + { ID_PLAY_PLAYBACKRATE_100, 1.00f}, + { ID_PLAY_PLAYBACKRATE_200, 2.00f}, + { ID_PLAY_PLAYBACKRATE_400, 4.00f}, + { ID_PLAY_PLAYBACKRATE_800, 8.00f}, +}; + + +static bool EnsureDirectory(CString directory) +{ + int ret = SHCreateDirectoryEx(nullptr, directory, nullptr); + bool result = ret == ERROR_SUCCESS || ret == ERROR_ALREADY_EXISTS; + if (!result) { + AfxMessageBox(_T("Cannot create directory: ") + directory, MB_ICONEXCLAMATION | MB_OK); + } + return result; +} + +class CSubClock : public CUnknown, public ISubClock +{ + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(ISubClock) + CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + + REFERENCE_TIME m_rt; + +public: + CSubClock() : CUnknown(NAME("CSubClock"), nullptr) { + m_rt = 0; + } + + DECLARE_IUNKNOWN; + + // ISubClock + STDMETHODIMP SetTime(REFERENCE_TIME rt) { + m_rt = rt; + return S_OK; + } + STDMETHODIMP_(REFERENCE_TIME) GetTime() { + return m_rt; + } +}; + +bool FileFavorite::TryParse(const CString& fav, FileFavorite& ff) +{ + CAtlList parts; + return TryParse(fav, ff, parts); +} + +bool FileFavorite::TryParse(const CString& fav, FileFavorite& ff, CAtlList& parts) +{ + ExplodeEsc(fav, parts, _T(';')); + if (parts.IsEmpty()) { + return false; + } + + ff.Name = parts.RemoveHead(); + + if (!parts.IsEmpty()) { + // Start position and optional A-B marks "pos[:A:B]" + auto startPos = parts.RemoveHead(); + _stscanf_s(startPos, _T("%I64d:%I64d:%I64d"), &ff.Start, &ff.MarkA, &ff.MarkB); + ff.Start = std::max(ff.Start, 0ll); // Sanitize + } + if (!parts.IsEmpty()) { + _stscanf_s(parts.RemoveHead(), _T("%d"), &ff.RelativeDrive); + } + return true; +} + +CString FileFavorite::ToString() const +{ + CString str; + if (RelativeDrive) { + str = _T("[RD]"); + } + if (Start > 0) { // Start position + str.AppendFormat(_T("[%s]"), ReftimeToString2(Start).GetString()); + } + if (MarkA > 0 || MarkB > 0) { // A-B marks (only characters to save space) + CString abMarks; + if (MarkA > 0) { + abMarks = _T("A"); + } + if (MarkB > 0) { + abMarks.Append(_T("-B")); + } + str.AppendFormat(_T("[%s]"), abMarks.GetString()); + } + return str; +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame + +IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd) + +BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) + ON_WM_NCCREATE() + ON_WM_CREATE() + ON_WM_DESTROY() + ON_WM_CLOSE() + ON_WM_MEASUREITEM() + + ON_MESSAGE(WM_MPCVR_SWITCH_FULLSCREEN, OnMPCVRSwitchFullscreen) + + ON_REGISTERED_MESSAGE(s_uTaskbarRestart, OnTaskBarRestart) + ON_REGISTERED_MESSAGE(WM_NOTIFYICON, OnNotifyIcon) + + ON_REGISTERED_MESSAGE(s_uTBBC, OnTaskBarThumbnailsCreate) + + ON_REGISTERED_MESSAGE(SkypeMoodMsgHandler::uSkypeControlAPIAttach, OnSkypeAttach) + + ON_WM_SETFOCUS() + ON_WM_GETMINMAXINFO() + ON_WM_MOVE() + ON_WM_ENTERSIZEMOVE() + ON_WM_MOVING() + ON_WM_SIZE() + ON_WM_SIZING() + ON_WM_EXITSIZEMOVE() + ON_MESSAGE_VOID(WM_DISPLAYCHANGE, OnDisplayChange) + ON_WM_WINDOWPOSCHANGING() + + ON_MESSAGE(WM_DPICHANGED, OnDpiChanged) + + ON_WM_SYSCOMMAND() + ON_WM_ACTIVATEAPP() + ON_MESSAGE(WM_APPCOMMAND, OnAppCommand) + ON_WM_INPUT() + ON_MESSAGE(WM_HOTKEY, OnHotKey) + + ON_WM_TIMER() + + ON_MESSAGE(WM_GRAPHNOTIFY, OnGraphNotify) + ON_MESSAGE(WM_RESET_DEVICE, OnResetDevice) + ON_MESSAGE(WM_REARRANGERENDERLESS, OnRepaintRenderLess) + + ON_MESSAGE_VOID(WM_SAVESETTINGS, SaveAppSettings) + + ON_WM_NCHITTEST() + + ON_WM_HSCROLL() + + ON_WM_INITMENU() + ON_WM_INITMENUPOPUP() + ON_WM_UNINITMENUPOPUP() + + ON_WM_ENTERMENULOOP() + + ON_WM_QUERYENDSESSION() + ON_WM_ENDSESSION() + + ON_COMMAND(ID_MENU_PLAYER_SHORT, OnMenuPlayerShort) + ON_COMMAND(ID_MENU_PLAYER_LONG, OnMenuPlayerLong) + ON_COMMAND(ID_MENU_FILTERS, OnMenuFilters) + + ON_UPDATE_COMMAND_UI(IDC_PLAYERSTATUS, OnUpdatePlayerStatus) + + ON_MESSAGE(WM_POSTOPEN, OnFilePostOpenmedia) + ON_MESSAGE(WM_OPENFAILED, OnOpenMediaFailed) + ON_MESSAGE(WM_DVB_EIT_DATA_READY, OnCurrentChannelInfoUpdated) + + ON_COMMAND(ID_BOSS, OnBossKey) + + ON_COMMAND_RANGE(ID_STREAM_AUDIO_NEXT, ID_STREAM_AUDIO_PREV, OnStreamAudio) + ON_COMMAND_RANGE(ID_STREAM_SUB_NEXT, ID_STREAM_SUB_PREV, OnStreamSub) + ON_COMMAND(ID_AUDIOSHIFT_ONOFF, OnAudioShiftOnOff) + ON_COMMAND(ID_STREAM_SUB_ONOFF, OnStreamSubOnOff) + ON_COMMAND_RANGE(ID_DVD_ANGLE_NEXT, ID_DVD_ANGLE_PREV, OnDvdAngle) + ON_COMMAND_RANGE(ID_DVD_AUDIO_NEXT, ID_DVD_AUDIO_PREV, OnDvdAudio) + ON_COMMAND_RANGE(ID_DVD_SUB_NEXT, ID_DVD_SUB_PREV, OnDvdSub) + ON_COMMAND(ID_DVD_SUB_ONOFF, OnDvdSubOnOff) + + ON_COMMAND(ID_FILE_OPENQUICK, OnFileOpenQuick) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENMEDIA, OnUpdateFileOpen) + ON_COMMAND(ID_FILE_OPENMEDIA, OnFileOpenmedia) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENMEDIA, OnUpdateFileOpen) + ON_WM_COPYDATA() + ON_COMMAND(ID_FILE_OPENDVDBD, OnFileOpendvd) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENDVDBD, OnUpdateFileOpen) + ON_COMMAND(ID_FILE_OPENDEVICE, OnFileOpendevice) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENDEVICE, OnUpdateFileOpen) + ON_COMMAND_RANGE(ID_FILE_OPEN_OPTICAL_DISK_START, ID_FILE_OPEN_OPTICAL_DISK_END, OnFileOpenOpticalDisk) + ON_UPDATE_COMMAND_UI_RANGE(ID_FILE_OPEN_OPTICAL_DISK_START, ID_FILE_OPEN_OPTICAL_DISK_END, OnUpdateFileOpen) + ON_COMMAND(ID_FILE_REOPEN, OnFileReopen) + ON_COMMAND(ID_FILE_RECYCLE, OnFileRecycle) + ON_COMMAND(ID_FILE_SAVE_COPY, OnFileSaveAs) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_COPY, OnUpdateFileSaveAs) + ON_COMMAND(ID_FILE_SAVE_IMAGE, OnFileSaveImage) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_IMAGE, OnUpdateFileSaveImage) + ON_COMMAND(ID_FILE_SAVE_IMAGE_AUTO, OnFileSaveImageAuto) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_IMAGE_AUTO, OnUpdateFileSaveImage) + ON_COMMAND(ID_CMDLINE_SAVE_THUMBNAILS, OnCmdLineSaveThumbnails) + ON_COMMAND(ID_FILE_SAVE_THUMBNAILS, OnFileSaveThumbnails) + ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_THUMBNAILS, OnUpdateFileSaveThumbnails) + ON_COMMAND(ID_FILE_SUBTITLES_LOAD, OnFileSubtitlesLoad) + ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_LOAD, OnUpdateFileSubtitlesLoad) + ON_COMMAND(ID_FILE_SUBTITLES_SAVE, OnFileSubtitlesSave) + ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_SAVE, OnUpdateFileSubtitlesSave) + //ON_COMMAND(ID_FILE_SUBTITLES_UPLOAD, OnFileSubtitlesUpload) + //ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_UPLOAD, OnUpdateFileSubtitlesUpload) + ON_COMMAND(ID_FILE_SUBTITLES_DOWNLOAD, OnFileSubtitlesDownload) + ON_UPDATE_COMMAND_UI(ID_FILE_SUBTITLES_DOWNLOAD, OnUpdateFileSubtitlesDownload) + ON_COMMAND(ID_FILE_PROPERTIES, OnFileProperties) + ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateFileProperties) + ON_COMMAND(ID_FILE_OPEN_LOCATION, OnFileOpenLocation) + ON_UPDATE_COMMAND_UI(ID_FILE_OPEN_LOCATION, OnUpdateFileProperties) + ON_COMMAND(ID_FILE_CLOSE_AND_RESTORE, OnFileCloseAndRestore) + ON_UPDATE_COMMAND_UI(ID_FILE_CLOSE_AND_RESTORE, OnUpdateFileClose) + ON_COMMAND(ID_FILE_CLOSEMEDIA, OnFileCloseMedia) + ON_UPDATE_COMMAND_UI(ID_FILE_CLOSEMEDIA, OnUpdateFileClose) + + ON_COMMAND(ID_VIEW_CAPTIONMENU, OnViewCaptionmenu) + ON_UPDATE_COMMAND_UI(ID_VIEW_CAPTIONMENU, OnUpdateViewCaptionmenu) + ON_COMMAND_RANGE(ID_VIEW_SEEKER, ID_VIEW_STATUS, OnViewControlBar) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_SEEKER, ID_VIEW_STATUS, OnUpdateViewControlBar) + ON_COMMAND(ID_VIEW_SUBRESYNC, OnViewSubresync) + ON_UPDATE_COMMAND_UI(ID_VIEW_SUBRESYNC, OnUpdateViewSubresync) + ON_COMMAND(ID_VIEW_PLAYLIST, OnViewPlaylist) + ON_UPDATE_COMMAND_UI(ID_VIEW_PLAYLIST, OnUpdateViewPlaylist) + ON_COMMAND(ID_PLAYLIST_TOGGLE_SHUFFLE, OnPlaylistToggleShuffle) + ON_COMMAND(ID_VIEW_EDITLISTEDITOR, OnViewEditListEditor) + ON_COMMAND(ID_EDL_IN, OnEDLIn) + ON_UPDATE_COMMAND_UI(ID_EDL_IN, OnUpdateEDLIn) + ON_COMMAND(ID_EDL_OUT, OnEDLOut) + ON_UPDATE_COMMAND_UI(ID_EDL_OUT, OnUpdateEDLOut) + ON_COMMAND(ID_EDL_NEWCLIP, OnEDLNewClip) + ON_UPDATE_COMMAND_UI(ID_EDL_NEWCLIP, OnUpdateEDLNewClip) + ON_COMMAND(ID_EDL_SAVE, OnEDLSave) + ON_UPDATE_COMMAND_UI(ID_EDL_SAVE, OnUpdateEDLSave) + ON_COMMAND(ID_VIEW_CAPTURE, OnViewCapture) + ON_UPDATE_COMMAND_UI(ID_VIEW_CAPTURE, OnUpdateViewCapture) + ON_COMMAND(ID_VIEW_DEBUGSHADERS, OnViewDebugShaders) + ON_UPDATE_COMMAND_UI(ID_VIEW_DEBUGSHADERS, OnUpdateViewDebugShaders) + ON_COMMAND(ID_VIEW_PRESETS_MINIMAL, OnViewMinimal) + ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_MINIMAL, OnUpdateViewMinimal) + ON_COMMAND(ID_VIEW_PRESETS_COMPACT, OnViewCompact) + ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_COMPACT, OnUpdateViewCompact) + ON_COMMAND(ID_VIEW_PRESETS_NORMAL, OnViewNormal) + ON_UPDATE_COMMAND_UI(ID_VIEW_PRESETS_NORMAL, OnUpdateViewNormal) + ON_COMMAND(ID_VIEW_FULLSCREEN, OnViewFullscreen) + ON_COMMAND(ID_VIEW_FULLSCREEN_SECONDARY, OnViewFullscreenSecondary) + ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCREEN, OnUpdateViewFullscreen) + ON_COMMAND_RANGE(ID_VIEW_ZOOM_50, ID_VIEW_ZOOM_200, OnViewZoom) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_50, ID_VIEW_ZOOM_200, OnUpdateViewZoom) + ON_COMMAND_RANGE(ID_VIEW_ZOOM_25, ID_VIEW_ZOOM_25, OnViewZoom) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM_25, ID_VIEW_ZOOM_25, OnUpdateViewZoom) + ON_COMMAND(ID_VIEW_ZOOM_AUTOFIT, OnViewZoomAutoFit) + ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_AUTOFIT, OnUpdateViewZoom) + ON_COMMAND(ID_VIEW_ZOOM_AUTOFIT_LARGER, OnViewZoomAutoFitLarger) + ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_AUTOFIT_LARGER, OnUpdateViewZoom) + ON_COMMAND_RANGE(ID_VIEW_ZOOM_SUB, ID_VIEW_ZOOM_ADD, OnViewModifySize) + ON_COMMAND_RANGE(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, OnViewDefaultVideoFrame) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, OnUpdateViewDefaultVideoFrame) + ON_COMMAND(ID_VIEW_VF_SWITCHZOOM, OnViewSwitchVideoFrame) + ON_COMMAND(ID_VIEW_VF_COMPMONDESKARDIFF, OnViewCompMonDeskARDiff) + ON_UPDATE_COMMAND_UI(ID_VIEW_VF_COMPMONDESKARDIFF, OnUpdateViewCompMonDeskARDiff) + ON_COMMAND_RANGE(ID_VIEW_RESET, ID_PANSCAN_CENTER, OnViewPanNScan) + ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_RESET, ID_PANSCAN_CENTER, OnUpdateViewPanNScan) + ON_COMMAND_RANGE(ID_PANNSCAN_PRESETS_START, ID_PANNSCAN_PRESETS_END, OnViewPanNScanPresets) + ON_UPDATE_COMMAND_UI_RANGE(ID_PANNSCAN_PRESETS_START, ID_PANNSCAN_PRESETS_END, OnUpdateViewPanNScanPresets) + ON_COMMAND_RANGE(ID_PANSCAN_ROTATEXP, ID_PANSCAN_ROTATEZM, OnViewRotate) + ON_UPDATE_COMMAND_UI_RANGE(ID_PANSCAN_ROTATEXP, ID_PANSCAN_ROTATEZM, OnUpdateViewRotate) + ON_COMMAND_RANGE(ID_PANSCAN_ROTATEZ270, ID_PANSCAN_ROTATEZ270, OnViewRotate) + ON_UPDATE_COMMAND_UI_RANGE(ID_PANSCAN_ROTATEZ270, ID_PANSCAN_ROTATEZ270, OnUpdateViewRotate) + ON_COMMAND_RANGE(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, OnViewAspectRatio) + ON_UPDATE_COMMAND_UI_RANGE(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, OnUpdateViewAspectRatio) + ON_COMMAND(ID_ASPECTRATIO_NEXT, OnViewAspectRatioNext) + ON_COMMAND_RANGE(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, OnViewOntop) + ON_UPDATE_COMMAND_UI_RANGE(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, OnUpdateViewOntop) + ON_COMMAND(ID_VIEW_OPTIONS, OnViewOptions) + + // Casimir666 + ON_UPDATE_COMMAND_UI(ID_VIEW_TEARING_TEST, OnUpdateViewTearingTest) + ON_COMMAND(ID_VIEW_TEARING_TEST, OnViewTearingTest) + ON_UPDATE_COMMAND_UI(ID_VIEW_DISPLAY_RENDERER_STATS, OnUpdateViewDisplayRendererStats) + ON_COMMAND(ID_VIEW_RESET_RENDERER_STATS, OnViewResetRendererStats) + ON_COMMAND(ID_VIEW_DISPLAY_RENDERER_STATS, OnViewDisplayRendererStats) + ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCREENGUISUPPORT, OnUpdateViewFullscreenGUISupport) + ON_UPDATE_COMMAND_UI(ID_VIEW_HIGHCOLORRESOLUTION, OnUpdateViewHighColorResolution) + ON_UPDATE_COMMAND_UI(ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION, OnUpdateViewForceInputHighColorResolution) + ON_UPDATE_COMMAND_UI(ID_VIEW_FULLFLOATINGPOINTPROCESSING, OnUpdateViewFullFloatingPointProcessing) + ON_UPDATE_COMMAND_UI(ID_VIEW_HALFFLOATINGPOINTPROCESSING, OnUpdateViewHalfFloatingPointProcessing) + ON_UPDATE_COMMAND_UI(ID_VIEW_ENABLEFRAMETIMECORRECTION, OnUpdateViewEnableFrameTimeCorrection) + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNC, OnUpdateViewVSync) + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET, OnUpdateViewVSyncOffset) + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCACCURATE, OnUpdateViewVSyncAccurate) + + ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZEVIDEO, OnUpdateViewSynchronizeVideo) + ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZEDISPLAY, OnUpdateViewSynchronizeDisplay) + ON_UPDATE_COMMAND_UI(ID_VIEW_SYNCHRONIZENEAREST, OnUpdateViewSynchronizeNearest) + + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_ENABLE, OnUpdateViewColorManagementEnable) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_AUTO, OnUpdateViewColorManagementInput) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_HDTV, OnUpdateViewColorManagementInput) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_SDTV_NTSC, OnUpdateViewColorManagementInput) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INPUT_SDTV_PAL, OnUpdateViewColorManagementInput) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_BRIGHT, OnUpdateViewColorManagementAmbientLight) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_DIM, OnUpdateViewColorManagementAmbientLight) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_AMBIENTLIGHT_DARK, OnUpdateViewColorManagementAmbientLight) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_PERCEPTUAL, OnUpdateViewColorManagementIntent) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC, OnUpdateViewColorManagementIntent) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_SATURATION, OnUpdateViewColorManagementIntent) + ON_UPDATE_COMMAND_UI(ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC, OnUpdateViewColorManagementIntent) + + ON_UPDATE_COMMAND_UI(ID_VIEW_EVROUTPUTRANGE_0_255, OnUpdateViewEVROutputRange) + ON_UPDATE_COMMAND_UI(ID_VIEW_EVROUTPUTRANGE_16_235, OnUpdateViewEVROutputRange) + + ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_BEFOREVSYNC, OnUpdateViewFlushGPU) + ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_AFTERPRESENT, OnUpdateViewFlushGPU) + ON_UPDATE_COMMAND_UI(ID_VIEW_FLUSHGPU_WAIT, OnUpdateViewFlushGPU) + + ON_UPDATE_COMMAND_UI(ID_VIEW_D3DFULLSCREEN, OnUpdateViewD3DFullscreen) + ON_UPDATE_COMMAND_UI(ID_VIEW_DISABLEDESKTOPCOMPOSITION, OnUpdateViewDisableDesktopComposition) + ON_UPDATE_COMMAND_UI(ID_VIEW_ALTERNATIVEVSYNC, OnUpdateViewAlternativeVSync) + + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET_INCREASE, OnUpdateViewVSyncOffsetIncrease) + ON_UPDATE_COMMAND_UI(ID_VIEW_VSYNCOFFSET_DECREASE, OnUpdateViewVSyncOffsetDecrease) + ON_COMMAND(ID_VIEW_FULLSCREENGUISUPPORT, OnViewFullscreenGUISupport) + ON_COMMAND(ID_VIEW_HIGHCOLORRESOLUTION, OnViewHighColorResolution) + ON_COMMAND(ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION, OnViewForceInputHighColorResolution) + ON_COMMAND(ID_VIEW_FULLFLOATINGPOINTPROCESSING, OnViewFullFloatingPointProcessing) + ON_COMMAND(ID_VIEW_HALFFLOATINGPOINTPROCESSING, OnViewHalfFloatingPointProcessing) + ON_COMMAND(ID_VIEW_ENABLEFRAMETIMECORRECTION, OnViewEnableFrameTimeCorrection) + ON_COMMAND(ID_VIEW_VSYNC, OnViewVSync) + ON_COMMAND(ID_VIEW_VSYNCACCURATE, OnViewVSyncAccurate) + + ON_COMMAND(ID_VIEW_SYNCHRONIZEVIDEO, OnViewSynchronizeVideo) + ON_COMMAND(ID_VIEW_SYNCHRONIZEDISPLAY, OnViewSynchronizeDisplay) + ON_COMMAND(ID_VIEW_SYNCHRONIZENEAREST, OnViewSynchronizeNearest) + + ON_COMMAND(ID_VIEW_CM_ENABLE, OnViewColorManagementEnable) + ON_COMMAND(ID_VIEW_CM_INPUT_AUTO, OnViewColorManagementInputAuto) + ON_COMMAND(ID_VIEW_CM_INPUT_HDTV, OnViewColorManagementInputHDTV) + ON_COMMAND(ID_VIEW_CM_INPUT_SDTV_NTSC, OnViewColorManagementInputSDTV_NTSC) + ON_COMMAND(ID_VIEW_CM_INPUT_SDTV_PAL, OnViewColorManagementInputSDTV_PAL) + ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_BRIGHT, OnViewColorManagementAmbientLightBright) + ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_DIM, OnViewColorManagementAmbientLightDim) + ON_COMMAND(ID_VIEW_CM_AMBIENTLIGHT_DARK, OnViewColorManagementAmbientLightDark) + ON_COMMAND(ID_VIEW_CM_INTENT_PERCEPTUAL, OnViewColorManagementIntentPerceptual) + ON_COMMAND(ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC, OnViewColorManagementIntentRelativeColorimetric) + ON_COMMAND(ID_VIEW_CM_INTENT_SATURATION, OnViewColorManagementIntentSaturation) + ON_COMMAND(ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC, OnViewColorManagementIntentAbsoluteColorimetric) + + ON_COMMAND(ID_VIEW_EVROUTPUTRANGE_0_255, OnViewEVROutputRange_0_255) + ON_COMMAND(ID_VIEW_EVROUTPUTRANGE_16_235, OnViewEVROutputRange_16_235) + + ON_COMMAND(ID_VIEW_FLUSHGPU_BEFOREVSYNC, OnViewFlushGPUBeforeVSync) + ON_COMMAND(ID_VIEW_FLUSHGPU_AFTERPRESENT, OnViewFlushGPUAfterVSync) + ON_COMMAND(ID_VIEW_FLUSHGPU_WAIT, OnViewFlushGPUWait) + + ON_COMMAND(ID_VIEW_D3DFULLSCREEN, OnViewD3DFullScreen) + ON_COMMAND(ID_VIEW_DISABLEDESKTOPCOMPOSITION, OnViewDisableDesktopComposition) + ON_COMMAND(ID_VIEW_ALTERNATIVEVSYNC, OnViewAlternativeVSync) + ON_COMMAND(ID_VIEW_RESET_DEFAULT, OnViewResetDefault) + ON_COMMAND(ID_VIEW_RESET_OPTIMAL, OnViewResetOptimal) + + ON_COMMAND(ID_VIEW_VSYNCOFFSET_INCREASE, OnViewVSyncOffsetIncrease) + ON_COMMAND(ID_VIEW_VSYNCOFFSET_DECREASE, OnViewVSyncOffsetDecrease) + ON_UPDATE_COMMAND_UI(ID_PRESIZE_SHADERS_TOGGLE, OnUpdateShaderToggle1) + ON_COMMAND(ID_PRESIZE_SHADERS_TOGGLE, OnShaderToggle1) + ON_UPDATE_COMMAND_UI(ID_POSTSIZE_SHADERS_TOGGLE, OnUpdateShaderToggle2) + ON_COMMAND(ID_POSTSIZE_SHADERS_TOGGLE, OnShaderToggle2) + ON_UPDATE_COMMAND_UI(ID_VIEW_OSD_DISPLAY_TIME, OnUpdateViewOSDDisplayTime) + ON_COMMAND(ID_VIEW_OSD_DISPLAY_TIME, OnViewOSDDisplayTime) + ON_UPDATE_COMMAND_UI(ID_VIEW_OSD_SHOW_FILENAME, OnUpdateViewOSDShowFileName) + ON_COMMAND(ID_VIEW_OSD_SHOW_FILENAME, OnViewOSDShowFileName) + ON_COMMAND(ID_D3DFULLSCREEN_TOGGLE, OnD3DFullscreenToggle) + ON_COMMAND_RANGE(ID_GOTO_PREV_SUB, ID_GOTO_NEXT_SUB, OnGotoSubtitle) + ON_COMMAND_RANGE(ID_SUBRESYNC_SHIFT_DOWN, ID_SUBRESYNC_SHIFT_UP, OnSubresyncShiftSub) + ON_COMMAND_RANGE(ID_SUB_DELAY_DOWN, ID_SUB_DELAY_UP, OnSubtitleDelay) + ON_COMMAND_RANGE(ID_SUB_POS_DOWN, ID_SUB_POS_UP, OnSubtitlePos) + ON_COMMAND_RANGE(ID_SUB_FONT_SIZE_DEC, ID_SUB_FONT_SIZE_INC, OnSubtitleFontSize) + + ON_COMMAND(ID_PLAY_PLAY, OnPlayPlay) + ON_COMMAND(ID_PLAY_PAUSE, OnPlayPause) + ON_COMMAND(ID_PLAY_PLAYPAUSE, OnPlayPlaypause) + ON_COMMAND(ID_PLAY_STOP, OnPlayStop) + ON_UPDATE_COMMAND_UI(ID_PLAY_PLAY, OnUpdatePlayPauseStop) + ON_UPDATE_COMMAND_UI(ID_PLAY_PAUSE, OnUpdatePlayPauseStop) + ON_UPDATE_COMMAND_UI(ID_PLAY_PLAYPAUSE, OnUpdatePlayPauseStop) + ON_UPDATE_COMMAND_UI(ID_PLAY_STOP, OnUpdatePlayPauseStop) + ON_COMMAND_RANGE(ID_PLAY_FRAMESTEP, ID_PLAY_FRAMESTEP_BACK, OnPlayFramestep) + ON_UPDATE_COMMAND_UI(ID_PLAY_FRAMESTEP, OnUpdatePlayFramestep) + ON_COMMAND_RANGE(ID_PLAY_SEEKBACKWARDSMALL, ID_PLAY_SEEKFORWARDLARGE, OnPlaySeek) + ON_COMMAND(ID_PLAY_SEEKSET, OnPlaySeekSet) + ON_COMMAND_RANGE(ID_PLAY_SEEKKEYBACKWARD, ID_PLAY_SEEKKEYFORWARD, OnPlaySeekKey) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_SEEKBACKWARDSMALL, ID_PLAY_SEEKFORWARDLARGE, OnUpdatePlaySeek) + ON_UPDATE_COMMAND_UI(ID_PLAY_SEEKSET, OnUpdatePlaySeek) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_SEEKKEYBACKWARD, ID_PLAY_SEEKKEYFORWARD, OnUpdatePlaySeek) + ON_COMMAND_RANGE(ID_PLAY_DECRATE, ID_PLAY_INCRATE, OnPlayChangeRate) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_DECRATE, ID_PLAY_INCRATE, OnUpdatePlayChangeRate) + ON_COMMAND_RANGE(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, OnPlayChangeRate) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, OnUpdatePlayChangeRate) + ON_COMMAND(ID_PLAY_RESETRATE, OnPlayResetRate) + ON_UPDATE_COMMAND_UI(ID_PLAY_RESETRATE, OnUpdatePlayResetRate) + ON_COMMAND_RANGE(ID_PLAY_INCAUDDELAY, ID_PLAY_DECAUDDELAY, OnPlayChangeAudDelay) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_INCAUDDELAY, ID_PLAY_DECAUDDELAY, OnUpdatePlayChangeAudDelay) + ON_COMMAND(ID_FILTERS_COPY_TO_CLIPBOARD, OnPlayFiltersCopyToClipboard) + ON_COMMAND_RANGE(ID_FILTERS_SUBITEM_START, ID_FILTERS_SUBITEM_END, OnPlayFilters) + ON_UPDATE_COMMAND_UI_RANGE(ID_FILTERS_SUBITEM_START, ID_FILTERS_SUBITEM_END, OnUpdatePlayFilters) + ON_COMMAND(ID_SHADERS_SELECT, OnPlayShadersSelect) + ON_COMMAND(ID_SHADERS_PRESET_NEXT, OnPlayShadersPresetNext) + ON_COMMAND(ID_SHADERS_PRESET_PREV, OnPlayShadersPresetPrev) + ON_COMMAND_RANGE(ID_SHADERS_PRESETS_START, ID_SHADERS_PRESETS_END, OnPlayShadersPresets) + ON_COMMAND_RANGE(ID_AUDIO_SUBITEM_START, ID_AUDIO_SUBITEM_END, OnPlayAudio) + ON_COMMAND_RANGE(ID_SUBTITLES_SUBITEM_START, ID_SUBTITLES_SUBITEM_END, OnPlaySubtitles) + ON_COMMAND(ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE, OnSubtitlesDefaultStyle) + ON_COMMAND_RANGE(ID_VIDEO_STREAMS_SUBITEM_START, ID_VIDEO_STREAMS_SUBITEM_END, OnPlayVideoStreams) + ON_COMMAND_RANGE(ID_FILTERSTREAMS_SUBITEM_START, ID_FILTERSTREAMS_SUBITEM_END, OnPlayFiltersStreams) + ON_COMMAND_RANGE(ID_VOLUME_UP, ID_VOLUME_MUTE, OnPlayVolume) + ON_COMMAND_RANGE(ID_VOLUME_BOOST_INC, ID_VOLUME_BOOST_MAX, OnPlayVolumeBoost) + ON_UPDATE_COMMAND_UI_RANGE(ID_VOLUME_BOOST_INC, ID_VOLUME_BOOST_MAX, OnUpdatePlayVolumeBoost) + ON_COMMAND(ID_CUSTOM_CHANNEL_MAPPING, OnCustomChannelMapping) + ON_UPDATE_COMMAND_UI(ID_CUSTOM_CHANNEL_MAPPING, OnUpdateCustomChannelMapping) + ON_COMMAND_RANGE(ID_NORMALIZE, ID_REGAIN_VOLUME, OnNormalizeRegainVolume) + ON_UPDATE_COMMAND_UI_RANGE(ID_NORMALIZE, ID_REGAIN_VOLUME, OnUpdateNormalizeRegainVolume) + ON_COMMAND_RANGE(ID_COLOR_BRIGHTNESS_INC, ID_COLOR_RESET, OnPlayColor) + ON_UPDATE_COMMAND_UI_RANGE(ID_AFTERPLAYBACK_EXIT, ID_AFTERPLAYBACK_MONITOROFF, OnUpdateAfterplayback) + ON_COMMAND_RANGE(ID_AFTERPLAYBACK_EXIT, ID_AFTERPLAYBACK_MONITOROFF, OnAfterplayback) + ON_UPDATE_COMMAND_UI_RANGE(ID_AFTERPLAYBACK_PLAYNEXT, ID_AFTERPLAYBACK_DONOTHING, OnUpdateAfterplayback) + ON_COMMAND_RANGE(ID_AFTERPLAYBACK_PLAYNEXT, ID_AFTERPLAYBACK_DONOTHING, OnAfterplayback) + ON_COMMAND_RANGE(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, OnPlayRepeat) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, OnUpdatePlayRepeat) + ON_COMMAND_RANGE(ID_PLAY_REPEAT_AB, ID_PLAY_REPEAT_AB_MARK_B, OnABRepeat) + ON_UPDATE_COMMAND_UI_RANGE(ID_PLAY_REPEAT_AB, ID_PLAY_REPEAT_AB_MARK_B, OnUpdateABRepeat) + ON_COMMAND(ID_PLAY_REPEAT_FOREVER, OnPlayRepeatForever) + ON_UPDATE_COMMAND_UI(ID_PLAY_REPEAT_FOREVER, OnUpdatePlayRepeatForever) + + ON_COMMAND_RANGE(ID_NAVIGATE_SKIPBACK, ID_NAVIGATE_SKIPFORWARD, OnNavigateSkip) + ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_SKIPBACK, ID_NAVIGATE_SKIPFORWARD, OnUpdateNavigateSkip) + ON_COMMAND_RANGE(ID_NAVIGATE_SKIPBACKFILE, ID_NAVIGATE_SKIPFORWARDFILE, OnNavigateSkipFile) + ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_SKIPBACKFILE, ID_NAVIGATE_SKIPFORWARDFILE, OnUpdateNavigateSkipFile) + ON_COMMAND(ID_NAVIGATE_GOTO, OnNavigateGoto) + ON_UPDATE_COMMAND_UI(ID_NAVIGATE_GOTO, OnUpdateNavigateGoto) + ON_COMMAND_RANGE(ID_NAVIGATE_TITLEMENU, ID_NAVIGATE_CHAPTERMENU, OnNavigateMenu) + ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_TITLEMENU, ID_NAVIGATE_CHAPTERMENU, OnUpdateNavigateMenu) + ON_COMMAND_RANGE(ID_NAVIGATE_JUMPTO_SUBITEM_START, ID_NAVIGATE_JUMPTO_SUBITEM_END, OnNavigateJumpTo) + ON_COMMAND_RANGE(ID_NAVIGATE_MENU_LEFT, ID_NAVIGATE_MENU_LEAVE, OnNavigateMenuItem) + ON_UPDATE_COMMAND_UI_RANGE(ID_NAVIGATE_MENU_LEFT, ID_NAVIGATE_MENU_LEAVE, OnUpdateNavigateMenuItem) + + ON_COMMAND(ID_NAVIGATE_TUNERSCAN, OnTunerScan) + ON_UPDATE_COMMAND_UI(ID_NAVIGATE_TUNERSCAN, OnUpdateTunerScan) + + ON_COMMAND(ID_FAVORITES_ADD, OnFavoritesAdd) + ON_UPDATE_COMMAND_UI(ID_FAVORITES_ADD, OnUpdateFavoritesAdd) + ON_COMMAND(ID_FAVORITES_QUICKADDFAVORITE, OnFavoritesQuickAddFavorite) + ON_COMMAND(ID_FAVORITES_ORGANIZE, OnFavoritesOrganize) + ON_UPDATE_COMMAND_UI(ID_FAVORITES_ORGANIZE, OnUpdateFavoritesOrganize) + ON_COMMAND_RANGE(ID_FAVORITES_FILE_START, ID_FAVORITES_FILE_END, OnFavoritesFile) + ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_FILE_START, ID_FAVORITES_FILE_END, OnUpdateFavoritesFile) + ON_COMMAND_RANGE(ID_FAVORITES_DVD_START, ID_FAVORITES_DVD_END, OnFavoritesDVD) + ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_DVD_START, ID_FAVORITES_DVD_END, OnUpdateFavoritesDVD) + ON_COMMAND_RANGE(ID_FAVORITES_DEVICE_START, ID_FAVORITES_DEVICE_END, OnFavoritesDevice) + ON_UPDATE_COMMAND_UI_RANGE(ID_FAVORITES_DEVICE_START, ID_FAVORITES_DEVICE_END, OnUpdateFavoritesDevice) + + ON_COMMAND(ID_RECENT_FILES_CLEAR, OnRecentFileClear) + ON_UPDATE_COMMAND_UI(ID_RECENT_FILES_CLEAR, OnUpdateRecentFileClear) + ON_COMMAND_RANGE(ID_RECENT_FILE_START, ID_RECENT_FILE_END, OnRecentFile) + ON_UPDATE_COMMAND_UI_RANGE(ID_RECENT_FILE_START, ID_RECENT_FILE_END, OnUpdateRecentFile) + + ON_COMMAND(ID_HELP_HOMEPAGE, OnHelpHomepage) + ON_COMMAND(ID_HELP_CHECKFORUPDATE, OnHelpCheckForUpdate) + ON_COMMAND(ID_HELP_TOOLBARIMAGES, OnHelpToolbarImages) + ON_COMMAND(ID_HELP_DONATE, OnHelpDonate) + + // Open Dir incl. SubDir + ON_COMMAND(ID_FILE_OPENDIRECTORY, OnFileOpendirectory) + ON_UPDATE_COMMAND_UI(ID_FILE_OPENDIRECTORY, OnUpdateFileOpen) + ON_WM_POWERBROADCAST() + + // Navigation panel + ON_COMMAND(ID_VIEW_NAVIGATION, OnViewNavigation) + ON_UPDATE_COMMAND_UI(ID_VIEW_NAVIGATION, OnUpdateViewNavigation) + + ON_WM_WTSSESSION_CHANGE() + + ON_MESSAGE(WM_LOADSUBTITLES, OnLoadSubtitles) + ON_MESSAGE(WM_GETSUBTITLES, OnGetSubtitles) + ON_WM_DRAWITEM() + ON_WM_SETTINGCHANGE() + ON_WM_MOUSEHWHEEL() +END_MESSAGE_MAP() + +#ifdef _DEBUG +const TCHAR* GetEventString(LONG evCode) +{ +#define UNPACK_VALUE(VALUE) case VALUE: return _T(#VALUE); + switch (evCode) { + // System-defined event codes + UNPACK_VALUE(EC_COMPLETE); + UNPACK_VALUE(EC_USERABORT); + UNPACK_VALUE(EC_ERRORABORT); + //UNPACK_VALUE(EC_TIME); + UNPACK_VALUE(EC_REPAINT); + UNPACK_VALUE(EC_STREAM_ERROR_STOPPED); + UNPACK_VALUE(EC_STREAM_ERROR_STILLPLAYING); + UNPACK_VALUE(EC_ERROR_STILLPLAYING); + UNPACK_VALUE(EC_PALETTE_CHANGED); + UNPACK_VALUE(EC_VIDEO_SIZE_CHANGED); + UNPACK_VALUE(EC_QUALITY_CHANGE); + UNPACK_VALUE(EC_SHUTTING_DOWN); + UNPACK_VALUE(EC_CLOCK_CHANGED); + UNPACK_VALUE(EC_PAUSED); + UNPACK_VALUE(EC_OPENING_FILE); + UNPACK_VALUE(EC_BUFFERING_DATA); + UNPACK_VALUE(EC_FULLSCREEN_LOST); + UNPACK_VALUE(EC_ACTIVATE); + UNPACK_VALUE(EC_NEED_RESTART); + UNPACK_VALUE(EC_WINDOW_DESTROYED); + UNPACK_VALUE(EC_DISPLAY_CHANGED); + UNPACK_VALUE(EC_STARVATION); + UNPACK_VALUE(EC_OLE_EVENT); + UNPACK_VALUE(EC_NOTIFY_WINDOW); + UNPACK_VALUE(EC_STREAM_CONTROL_STOPPED); + UNPACK_VALUE(EC_STREAM_CONTROL_STARTED); + UNPACK_VALUE(EC_END_OF_SEGMENT); + UNPACK_VALUE(EC_SEGMENT_STARTED); + UNPACK_VALUE(EC_LENGTH_CHANGED); + UNPACK_VALUE(EC_DEVICE_LOST); + UNPACK_VALUE(EC_SAMPLE_NEEDED); + UNPACK_VALUE(EC_PROCESSING_LATENCY); + UNPACK_VALUE(EC_SAMPLE_LATENCY); + UNPACK_VALUE(EC_SCRUB_TIME); + UNPACK_VALUE(EC_STEP_COMPLETE); + UNPACK_VALUE(EC_TIMECODE_AVAILABLE); + UNPACK_VALUE(EC_EXTDEVICE_MODE_CHANGE); + UNPACK_VALUE(EC_STATE_CHANGE); + UNPACK_VALUE(EC_GRAPH_CHANGED); + UNPACK_VALUE(EC_CLOCK_UNSET); + UNPACK_VALUE(EC_VMR_RENDERDEVICE_SET); + UNPACK_VALUE(EC_VMR_SURFACE_FLIPPED); + UNPACK_VALUE(EC_VMR_RECONNECTION_FAILED); + UNPACK_VALUE(EC_PREPROCESS_COMPLETE); + UNPACK_VALUE(EC_CODECAPI_EVENT); + UNPACK_VALUE(EC_WMT_INDEX_EVENT); + UNPACK_VALUE(EC_WMT_EVENT); + UNPACK_VALUE(EC_BUILT); + UNPACK_VALUE(EC_UNBUILT); + UNPACK_VALUE(EC_SKIP_FRAMES); + UNPACK_VALUE(EC_PLEASE_REOPEN); + UNPACK_VALUE(EC_STATUS); + UNPACK_VALUE(EC_MARKER_HIT); + UNPACK_VALUE(EC_LOADSTATUS); + UNPACK_VALUE(EC_FILE_CLOSED); + UNPACK_VALUE(EC_ERRORABORTEX); + //UNPACK_VALUE(EC_NEW_PIN); + //UNPACK_VALUE(EC_RENDER_FINISHED); + UNPACK_VALUE(EC_EOS_SOON); + UNPACK_VALUE(EC_CONTENTPROPERTY_CHANGED); + UNPACK_VALUE(EC_BANDWIDTHCHANGE); + UNPACK_VALUE(EC_VIDEOFRAMEREADY); + // DVD-Video event codes + UNPACK_VALUE(EC_DVD_DOMAIN_CHANGE); + UNPACK_VALUE(EC_DVD_TITLE_CHANGE); + UNPACK_VALUE(EC_DVD_CHAPTER_START); + UNPACK_VALUE(EC_DVD_AUDIO_STREAM_CHANGE); + UNPACK_VALUE(EC_DVD_SUBPICTURE_STREAM_CHANGE); + UNPACK_VALUE(EC_DVD_ANGLE_CHANGE); + UNPACK_VALUE(EC_DVD_BUTTON_CHANGE); + UNPACK_VALUE(EC_DVD_VALID_UOPS_CHANGE); + UNPACK_VALUE(EC_DVD_STILL_ON); + UNPACK_VALUE(EC_DVD_STILL_OFF); + UNPACK_VALUE(EC_DVD_CURRENT_TIME); + UNPACK_VALUE(EC_DVD_ERROR); + UNPACK_VALUE(EC_DVD_WARNING); + UNPACK_VALUE(EC_DVD_CHAPTER_AUTOSTOP); + UNPACK_VALUE(EC_DVD_NO_FP_PGC); + UNPACK_VALUE(EC_DVD_PLAYBACK_RATE_CHANGE); + UNPACK_VALUE(EC_DVD_PARENTAL_LEVEL_CHANGE); + UNPACK_VALUE(EC_DVD_PLAYBACK_STOPPED); + UNPACK_VALUE(EC_DVD_ANGLES_AVAILABLE); + UNPACK_VALUE(EC_DVD_PLAYPERIOD_AUTOSTOP); + UNPACK_VALUE(EC_DVD_BUTTON_AUTO_ACTIVATED); + UNPACK_VALUE(EC_DVD_CMD_START); + UNPACK_VALUE(EC_DVD_CMD_END); + UNPACK_VALUE(EC_DVD_DISC_EJECTED); + UNPACK_VALUE(EC_DVD_DISC_INSERTED); + UNPACK_VALUE(EC_DVD_CURRENT_HMSF_TIME); + UNPACK_VALUE(EC_DVD_KARAOKE_MODE); + UNPACK_VALUE(EC_DVD_PROGRAM_CELL_CHANGE); + UNPACK_VALUE(EC_DVD_TITLE_SET_CHANGE); + UNPACK_VALUE(EC_DVD_PROGRAM_CHAIN_CHANGE); + UNPACK_VALUE(EC_DVD_VOBU_Offset); + UNPACK_VALUE(EC_DVD_VOBU_Timestamp); + UNPACK_VALUE(EC_DVD_GPRM_Change); + UNPACK_VALUE(EC_DVD_SPRM_Change); + UNPACK_VALUE(EC_DVD_BeginNavigationCommands); + UNPACK_VALUE(EC_DVD_NavigationCommand); + // Sound device error event codes + UNPACK_VALUE(EC_SNDDEV_IN_ERROR); + UNPACK_VALUE(EC_SNDDEV_OUT_ERROR); + // Custom event codes + UNPACK_VALUE(EC_BG_AUDIO_CHANGED); + UNPACK_VALUE(EC_BG_ERROR); + }; +#undef UNPACK_VALUE + return _T("UNKNOWN"); +} +#endif + +void CMainFrame::EventCallback(MpcEvent ev) +{ + const auto& s = AfxGetAppSettings(); + switch (ev) { + case MpcEvent::SHADER_SELECTION_CHANGED: + case MpcEvent::SHADER_PRERESIZE_SELECTION_CHANGED: + case MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED: + SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); + break; + case MpcEvent::DISPLAY_MODE_AUTOCHANGING: + if (GetLoadState() == MLS::LOADED && GetMediaState() == State_Running && s.autoChangeFSMode.uDelay) { + // pause if the mode is being changed during playback + OnPlayPause(); + m_bPausedForAutochangeMonitorMode = true; + } + break; + case MpcEvent::DISPLAY_MODE_AUTOCHANGED: + if (GetLoadState() == MLS::LOADED) { + if (m_bPausedForAutochangeMonitorMode && s.autoChangeFSMode.uDelay) { + // delay play if was paused due to mode change + ASSERT(GetMediaState() != State_Stopped); + const unsigned uModeChangeDelay = s.autoChangeFSMode.uDelay * 1000; + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, + std::bind(&CMainFrame::OnPlayPlay, this), uModeChangeDelay); + } else if (m_bDelaySetOutputRect) { + ASSERT(GetMediaState() == State_Stopped); + // tell OnFilePostOpenmedia() to delay entering play or paused state + m_bOpeningInAutochangedMonitorMode = true; + } + } + break; + case MpcEvent::CHANGING_UI_LANGUAGE: + UpdateUILanguage(); + break; + case MpcEvent::STREAM_POS_UPDATE_REQUEST: + OnTimer(TIMER_STREAMPOSPOLLER); + OnTimer(TIMER_STREAMPOSPOLLER2); + break; + default: + ASSERT(FALSE); + } +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame construction/destruction + +CMainFrame::CMainFrame() + : m_timerHider(this, TIMER_HIDER, 200) + , m_timerOneTime(this, TIMER_ONETIME_START, TIMER_ONETIME_END - TIMER_ONETIME_START + 1) + , m_bUsingDXVA(false) + , m_HWAccelType(nullptr) + , m_posFirstExtSub(nullptr) + , m_bDelaySetOutputRect(false) + , m_nJumpToSubMenusCount(0) + , m_nLoops(0) + , m_nLastSkipDirection(0) + , m_fCustomGraph(false) + , m_fShockwaveGraph(false) + , m_fFrameSteppingActive(false) + , m_nStepForwardCount(0) + , m_rtStepForwardStart(0) + , m_nVolumeBeforeFrameStepping(0) + , m_fEndOfStream(false) + , m_dwLastPause(0) + , m_dwReloadPos(0) + , m_iReloadAudioIdx(-1) + , m_iReloadSubIdx(-1) + , m_bRememberFilePos(false) + , m_dwLastRun(0) + , m_bBuffering(false) + , m_fLiveWM(false) + , m_rtDurationOverride(-1) + , m_iPlaybackMode(PM_NONE) + , m_lCurrentChapter(0) + , m_lChapterStartTime(0xFFFFFFFF) + , m_eMediaLoadState(MLS::CLOSED) + , m_CachedFilterState(-1) + , m_bSettingUpMenus(false) + , m_bOpenMediaActive(false) + , m_OpenMediaFailedCount(0) + , m_fFullScreen(false) + , m_bFullScreenWindowIsD3D(false) + , m_bFullScreenWindowIsOnSeparateDisplay(false) + , m_bNeedZoomAfterFullscreenExit(false) + , m_fStartInD3DFullscreen(false) + , m_fStartInFullscreenSeparate(false) + , m_pLastBar(nullptr) + , m_bFirstPlay(false) + , m_bOpeningInAutochangedMonitorMode(false) + , m_bPausedForAutochangeMonitorMode(false) + , m_fAudioOnly(true) + , m_iDVDDomain(DVD_DOMAIN_Stop) + , m_iDVDTitle(0) + , m_bDVDStillOn(false) + , m_dSpeedRate(1.0) + , m_ZoomX(1.0) + , m_ZoomY(1.0) + , m_PosX(0.5) + , m_PosY(0.5) + , m_AngleX(0) + , m_AngleY(0) + , m_AngleZ(0) + , m_iDefRotation(0) + , m_pGraphThread(nullptr) + , m_bOpenedThroughThread(false) + , m_evOpenPrivateFinished(FALSE, TRUE) + , m_evClosePrivateFinished(FALSE, TRUE) + , m_fOpeningAborted(false) + , m_bWasSnapped(false) + , m_wndSubtitlesDownloadDialog(this) + //, m_wndSubtitlesUploadDialog(this) + , m_wndFavoriteOrganizeDialog(this) + , m_bTrayIcon(false) + , m_fCapturing(false) + , m_controls(this) + , m_wndView(this) + , m_wndSeekBar(this) + , m_wndToolBar(this) + , m_wndInfoBar(this) + , m_wndStatsBar(this) + , m_wndStatusBar(this) + , m_wndSubresyncBar(this) + , m_wndPlaylistBar(this) + , m_wndPreView(this) + , m_wndCaptureBar(this) + , m_wndNavigationBar(this) + , m_pVideoWnd(nullptr) + , m_pOSDWnd(nullptr) + , m_pDedicatedFSVideoWnd(nullptr) + , m_OSD(this) + , m_nCurSubtitle(-1) + , m_lSubtitleShift(0) + , m_rtCurSubPos(0) + , m_bScanDlgOpened(false) + , m_bStopTunerScan(false) + , m_bLockedZoomVideoWindow(false) + , m_nLockedZoomVideoWindow(0) + , m_pActiveContextMenu(nullptr) + , m_pActiveSystemMenu(nullptr) + , m_bAltDownClean(false) + , m_bShowingFloatingMenubar(false) + , m_bAllowWindowZoom(false) + , m_dLastVideoScaleFactor(0) + , m_bExtOnTop(false) + , m_bIsBDPlay(false) + , m_bHasBDMeta(false) + , watchingDialog(themableDialogTypes::None) + , dialogHookHelper(nullptr) + , delayingFullScreen(false) + , restoringWindowRect(false) + , mediaTypesErrorDlg(nullptr) + , m_iStreamPosPollerInterval(100) + , currentAudioLang(_T("")) + , currentSubLang(_T("")) + , m_bToggleShader(false) + , m_bToggleShaderScreenSpace(false) + , m_MPLSPlaylist() + , m_sydlLastProcessURL() + , m_bUseSeekPreview(false) + , queuedSeek({0,0,false}) + , lastSeekStart(0) + , lastSeekFinish(0) + , defaultVideoAngle(0) + , m_media_trans_control() + , recentFilesMenuFromMRUSequence(-1) +{ + // Don't let CFrameWnd handle automatically the state of the menu items. + // This means that menu items without handlers won't be automatically + // disabled but it avoids some unwanted cases where programmatically + // disabled menu items are always re-enabled by CFrameWnd. + m_bAutoMenuEnable = FALSE; + + EventRouter::EventSelection receives; + receives.insert(MpcEvent::SHADER_SELECTION_CHANGED); + receives.insert(MpcEvent::SHADER_PRERESIZE_SELECTION_CHANGED); + receives.insert(MpcEvent::SHADER_POSTRESIZE_SELECTION_CHANGED); + receives.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGING); + receives.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGED); + receives.insert(MpcEvent::CHANGING_UI_LANGUAGE); + receives.insert(MpcEvent::STREAM_POS_UPDATE_REQUEST); + EventRouter::EventSelection fires; + fires.insert(MpcEvent::SWITCHING_TO_FULLSCREEN); + fires.insert(MpcEvent::SWITCHED_TO_FULLSCREEN); + fires.insert(MpcEvent::SWITCHING_FROM_FULLSCREEN); + fires.insert(MpcEvent::SWITCHED_FROM_FULLSCREEN); + fires.insert(MpcEvent::SWITCHING_TO_FULLSCREEN_D3D); + fires.insert(MpcEvent::SWITCHED_TO_FULLSCREEN_D3D); + fires.insert(MpcEvent::MEDIA_LOADED); + fires.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGING); + fires.insert(MpcEvent::DISPLAY_MODE_AUTOCHANGED); + fires.insert(MpcEvent::CONTEXT_MENU_POPUP_INITIALIZED); + fires.insert(MpcEvent::CONTEXT_MENU_POPUP_UNINITIALIZED); + fires.insert(MpcEvent::SYSTEM_MENU_POPUP_INITIALIZED); + fires.insert(MpcEvent::SYSTEM_MENU_POPUP_UNINITIALIZED); + fires.insert(MpcEvent::DPI_CHANGED); + GetEventd().Connect(m_eventc, receives, std::bind(&CMainFrame::EventCallback, this, std::placeholders::_1), fires); +} + +CMainFrame::~CMainFrame() +{ + if (defaultMPCThemeMenu != nullptr) { + delete defaultMPCThemeMenu; + } +} + +int CMainFrame::OnNcCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (IsWindows10OrGreater()) { + // Tell Windows to automatically handle scaling of non-client areas + // such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10 + const WinapiFunc + fnEnableNonClientDpiScaling = { _T("User32.dll"), "EnableNonClientDpiScaling" }; + + if (fnEnableNonClientDpiScaling) { + fnEnableNonClientDpiScaling(m_hWnd); + } + } + + return __super::OnNcCreate(lpCreateStruct); +} + +int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (__super::OnCreate(lpCreateStruct) == -1) { + return -1; + } + + CMPCThemeUtil::enableWindows10DarkFrame(this); + + if (IsWindows8Point1OrGreater()) { + m_dpi.Override(m_hWnd); + } + + const WinapiFunc + fnChangeWindowMessageFilterEx = { _T("user32.dll"), "ChangeWindowMessageFilterEx" }; + + // allow taskbar messages through UIPI + if (fnChangeWindowMessageFilterEx) { + VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, s_uTaskbarRestart, MSGFLT_ALLOW, nullptr)); + VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, s_uTBBC, MSGFLT_ALLOW, nullptr)); + VERIFY(fnChangeWindowMessageFilterEx(m_hWnd, WM_COMMAND, MSGFLT_ALLOW, nullptr)); + } + + VERIFY(m_popupMenu.LoadMenu(IDR_POPUP)); + VERIFY(m_mainPopupMenu.LoadMenu(IDR_POPUPMAIN)); + CreateDynamicMenus(); + + // 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); + + const CAppSettings& s = AfxGetAppSettings(); + + // Create OSD Window + CreateOSDBar(); + + // Create Preview Window + if (s.fSeekPreview) { + if (m_wndPreView.CreateEx(0, AfxRegisterWndClass(0), nullptr, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CRect(0, 0, 160, 109), this, 0)) { + m_wndPreView.ShowWindow(SW_HIDE); + m_wndPreView.SetRelativeSize(AfxGetAppSettings().iSeekPreviewSize); + } else { + TRACE(_T("Failed to create Preview Window")); + } + } + + // 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 + } + + m_pDedicatedFSVideoWnd = DEBUG_NEW CFullscreenWnd(this); + + m_controls.m_toolbars[CMainFrameControls::Toolbar::SEEKBAR] = &m_wndSeekBar; + m_controls.m_toolbars[CMainFrameControls::Toolbar::CONTROLS] = &m_wndToolBar; + m_controls.m_toolbars[CMainFrameControls::Toolbar::INFO] = &m_wndInfoBar; + m_controls.m_toolbars[CMainFrameControls::Toolbar::STATS] = &m_wndStatsBar; + m_controls.m_toolbars[CMainFrameControls::Toolbar::STATUS] = &m_wndStatusBar; + + // dockable bars + + EnableDocking(CBRS_ALIGN_ANY); + + bResult = m_wndSubresyncBar.Create(this, AFX_IDW_DOCKBAR_TOP, &m_csSubLock); + if (bResult) { + m_wndSubresyncBar.SetBarStyle(m_wndSubresyncBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndSubresyncBar.EnableDocking(CBRS_ALIGN_ANY); + m_wndSubresyncBar.SetHeight(200); + m_controls.m_panels[CMainFrameControls::Panel::SUBRESYNC] = &m_wndSubresyncBar; + } + bResult = bResult && m_wndPlaylistBar.Create(this, AFX_IDW_DOCKBAR_RIGHT); + if (bResult) { + m_wndPlaylistBar.SetBarStyle(m_wndPlaylistBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndPlaylistBar.EnableDocking(CBRS_ALIGN_ANY); + m_wndPlaylistBar.SetWidth(300); + m_controls.m_panels[CMainFrameControls::Panel::PLAYLIST] = &m_wndPlaylistBar; + //m_wndPlaylistBar.LoadPlaylist(GetRecentFile()); //adipose 2019-11-12; do this later after activating the frame + } + bResult = bResult && m_wndEditListEditor.Create(this, AFX_IDW_DOCKBAR_RIGHT); + if (bResult) { + m_wndEditListEditor.SetBarStyle(m_wndEditListEditor.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndEditListEditor.EnableDocking(CBRS_ALIGN_ANY); + m_controls.m_panels[CMainFrameControls::Panel::EDL] = &m_wndEditListEditor; + m_wndEditListEditor.SetHeight(100); + } + bResult = bResult && m_wndCaptureBar.Create(this, AFX_IDW_DOCKBAR_LEFT); + if (bResult) { + m_wndCaptureBar.SetBarStyle(m_wndCaptureBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndCaptureBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); + m_controls.m_panels[CMainFrameControls::Panel::CAPTURE] = &m_wndCaptureBar; + } + bResult = bResult && m_wndNavigationBar.Create(this, AFX_IDW_DOCKBAR_LEFT); + if (bResult) { + m_wndNavigationBar.SetBarStyle(m_wndNavigationBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + m_wndNavigationBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); + m_controls.m_panels[CMainFrameControls::Panel::NAVIGATION] = &m_wndNavigationBar; + } + if (!bResult) { + TRACE(_T("Failed to create all dockable bars\n")); + return -1; + } + + // Hide all controls initially + for (const auto& pair : m_controls.m_toolbars) { + pair.second->ShowWindow(SW_HIDE); + } + for (const auto& pair : m_controls.m_panels) { + pair.second->ShowWindow(SW_HIDE); + } + + m_dropTarget.Register(this); + + SetAlwaysOnTop(s.iOnTop); + + ShowTrayIcon(s.fTrayIcon); + + m_Lcd.SetVolumeRange(0, 100); + m_Lcd.SetVolume(std::max(1, s.nVolume)); + + m_pGraphThread = (CGraphThread*)AfxBeginThread(RUNTIME_CLASS(CGraphThread)); + + if (m_pGraphThread) { + m_pGraphThread->SetMainFrame(this); + } + + m_pSubtitlesProviders = std::make_unique(this); + m_wndSubtitlesDownloadDialog.Create(m_wndSubtitlesDownloadDialog.IDD, this, false); + //m_wndSubtitlesUploadDialog.Create(m_wndSubtitlesUploadDialog.IDD, this); + m_wndFavoriteOrganizeDialog.Create(m_wndFavoriteOrganizeDialog.IDD, this, false); + + if (s.nCmdlnWebServerPort != 0) { + if (s.nCmdlnWebServerPort > 0) { + StartWebServer(s.nCmdlnWebServerPort); + } else if (s.fEnableWebServer) { + StartWebServer(s.nWebServerPort); + } + } + + m_bToggleShader = s.bToggleShader; + m_bToggleShaderScreenSpace = s.bToggleShaderScreenSpace; + OpenSetupWindowTitle(true); + + WTSRegisterSessionNotification(); + + UpdateSkypeHandler(); + + m_popupMenu.fulfillThemeReqs(); + m_mainPopupMenu.fulfillThemeReqs(); + + if (s.bUseSMTC) { + m_media_trans_control.Init(this); + } + + return 0; +} + +void CMainFrame::CreateOSDBar() { + if (SUCCEEDED(m_OSD.Create(&m_wndView))) { + m_pOSDWnd = &m_wndView; + } +} + +bool CMainFrame::OSDBarSetPos() { + if (!m_OSD || !(::IsWindow(m_OSD.GetSafeHwnd())) || m_OSD.GetOSDType() != OSD_TYPE_GDI) { + return false; + } + const CAppSettings& s = AfxGetAppSettings(); + + if (s.iDSVideoRendererType == VIDRNDT_DS_MADVR || !m_wndView.IsWindowVisible()) { + if (m_OSD.IsWindowVisible()) { + m_OSD.ShowWindow(SW_HIDE); + } + return false; + } + + CRect r_wndView; + m_wndView.GetWindowRect(&r_wndView); + + int pos = 0; + + CRect MainWndRect; + m_wndView.GetWindowRect(&MainWndRect); + MainWndRect.right -= pos; + m_OSD.SetWndRect(MainWndRect); + if (m_OSD.IsWindowVisible()) { + ::PostMessageW(m_OSD.m_hWnd, WM_OSD_DRAW, WPARAM(0), LPARAM(0)); + } + + return false; +} + +void CMainFrame::DestroyOSDBar() { + if (m_OSD) { + m_OSD.Stop(); + m_OSD.DestroyWindow(); + } +} + +void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) +{ + if (lpMeasureItemStruct->CtlType == ODT_MENU) { + if (CMPCThemeMenu* cm = CMPCThemeMenu::getParentMenu(lpMeasureItemStruct->itemID)) { + cm->MeasureItem(lpMeasureItemStruct); + return; + } + } + + CFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct); +} + +void CMainFrame::OnDestroy() +{ + WTSUnRegisterSessionNotification(); + ShowTrayIcon(false); + m_dropTarget.Revoke(); + + if (m_pDebugShaders && IsWindow(m_pDebugShaders->m_hWnd)) { + VERIFY(m_pDebugShaders->DestroyWindow()); + } + + if (m_pGraphThread) { + CAMMsgEvent e; + m_pGraphThread->PostThreadMessage(CGraphThread::TM_EXIT, (WPARAM)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_ERROR); + } + } + + if (m_pDedicatedFSVideoWnd) { + if (m_pDedicatedFSVideoWnd->IsWindow()) { + m_pDedicatedFSVideoWnd->DestroyWindow(); + } + delete m_pDedicatedFSVideoWnd; + } + + m_wndPreView.DestroyWindow(); + + __super::OnDestroy(); +} + +void CMainFrame::OnClose() +{ + CAppSettings& s = AfxGetAppSettings(); + + s.bToggleShader = m_bToggleShader; + s.bToggleShaderScreenSpace = m_bToggleShaderScreenSpace; + s.dZoomX = m_ZoomX; + s.dZoomY = m_ZoomY; + + m_wndPlaylistBar.SavePlaylist(); + + m_controls.SaveState(); + + m_OSD.OnHide(); + + ShowWindow(SW_HIDE); + + if (GetLoadState() == MLS::LOADED || GetLoadState() == MLS::LOADING) { + CloseMedia(); + } + + m_wndPlaylistBar.ClearExternalPlaylistIfInvalid(); + + 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 + + AfxGetMyApp()->SetClosingState(); + + __super::OnClose(); +} + +LPCTSTR CMainFrame::GetRecentFile() const +{ + auto& MRU = AfxGetAppSettings().MRU; + MRU.ReadMediaHistory(); + for (int i = 0; i < MRU.GetSize(); i++) { + if (MRU[i].fns.GetCount() > 0 && !MRU[i].fns.GetHead().IsEmpty()) { + return MRU[i].fns.GetHead(); + } + } + return nullptr; +} + +LRESULT CMainFrame::OnTaskBarRestart(WPARAM, LPARAM) +{ + m_bTrayIcon = false; + ShowTrayIcon(AfxGetAppSettings().fTrayIcon); + return 0; +} + +LRESULT CMainFrame::OnNotifyIcon(WPARAM wParam, LPARAM lParam) +{ + if (HIWORD(lParam) != IDR_MAINFRAME) { + return -1; + } + + switch (LOWORD(lParam)) { + case WM_LBUTTONDOWN: + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + CreateThumbnailToolbar(); + MoveVideoWindow(); + SetForegroundWindow(); + break; + case WM_LBUTTONDBLCLK: + PostMessage(WM_COMMAND, ID_FILE_OPENMEDIA); + break; + case WM_RBUTTONDOWN: + case WM_CONTEXTMENU: { + SetForegroundWindow(); + m_mainPopupMenu.GetSubMenu(0)->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NOANIMATION, + GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam), GetModalParent()); + PostMessage(WM_NULL); + break; + } + case WM_MBUTTONDOWN: { + OnPlayPlaypause(); + break; + } + case WM_MOUSEMOVE: { + CString str; + GetWindowText(str); + SetTrayTip(str); + break; + } + default: + break; + } + + return 0; +} + +LRESULT CMainFrame::OnTaskBarThumbnailsCreate(WPARAM, LPARAM) +{ + return CreateThumbnailToolbar(); +} + +LRESULT CMainFrame::OnSkypeAttach(WPARAM wParam, LPARAM lParam) +{ + return m_pSkypeMoodMsgHandler ? m_pSkypeMoodMsgHandler->HandleAttach(wParam, lParam) : FALSE; +} + +void CMainFrame::ShowTrayIcon(bool bShow) +{ + NOTIFYICONDATA nid = { sizeof(nid), m_hWnd, IDR_MAINFRAME }; + + if (bShow) { + if (!m_bTrayIcon) { + nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; + nid.uCallbackMessage = WM_NOTIFYICON; + nid.uVersion = NOTIFYICON_VERSION_4; + nid.hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), + IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + StringCchCopy(nid.szTip, _countof(nid.szTip), _T("MPC-HC")); + if (Shell_NotifyIcon(NIM_ADD, &nid) && Shell_NotifyIcon(NIM_SETVERSION, &nid)) { + m_bTrayIcon = true; + } + } + } else { + if (m_bTrayIcon) { + Shell_NotifyIcon(NIM_DELETE, &nid); + m_bTrayIcon = false; + if (IsIconic()) { + // if the window was minimized to tray - show it + ShowWindow(SW_RESTORE); + } + } + } +} + +void CMainFrame::SetTrayTip(const CString& str) +{ + NOTIFYICONDATA tnid; + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = m_hWnd; + tnid.uID = IDR_MAINFRAME; + tnid.uFlags = NIF_TIP | NIF_SHOWTIP; + StringCchCopy(tnid.szTip, _countof(tnid.szTip), str); + Shell_NotifyIcon(NIM_MODIFY, &tnid); +} + +BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) +{ + if (!__super::PreCreateWindow(cs)) { + return FALSE; + } + + cs.dwExStyle &= ~WS_EX_CLIENTEDGE; + cs.lpszClass = MPC_WND_CLASS_NAME; //AfxRegisterWndClass(nullptr); + + return TRUE; +} + +BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->message == WM_KEYDOWN) { + if (pMsg->wParam == VK_ESCAPE) { + bool fEscapeNotAssigned = !AssignedToCmd(VK_ESCAPE); + + if (fEscapeNotAssigned) { + if (IsFullScreenMode()) { + OnViewFullscreen(); + if (GetLoadState() == MLS::LOADED) { + PostMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + return TRUE; + } else if (IsCaptionHidden()) { + PostMessage(WM_COMMAND, ID_VIEW_PRESETS_NORMAL); + return TRUE; + } + } + } else if (pMsg->wParam == VK_LEFT && m_pAMTuner) { + PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACK); + return TRUE; + } else if (pMsg->wParam == VK_RIGHT && m_pAMTuner) { + PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); + return TRUE; + } + } + + if ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_F10 && + m_dwMenuBarState == AFX_MBS_VISIBLE) { + // mfc doesn't hide menubar on f10, but we want to + VERIFY(SetMenuBarState(AFX_MBS_HIDDEN)); + return FALSE; + } + + if (pMsg->message == WM_KEYDOWN) { + m_bAltDownClean = false; + } + if (pMsg->message == WM_SYSKEYDOWN) { + m_bAltDownClean = (pMsg->wParam == VK_MENU); + } + if ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_MENU && + m_dwMenuBarState == AFX_MBS_HIDDEN) { + // mfc shows menubar when Ctrl->Alt->K is released in reverse order, but we don't want to + if (m_bAltDownClean) { + VERIFY(SetMenuBarState(AFX_MBS_VISIBLE)); + return FALSE; + } + return TRUE; + } + + // for compatibility with KatMouse and the like + if (pMsg->message == WM_MOUSEWHEEL && pMsg->hwnd == m_hWnd) { + pMsg->hwnd = m_wndView.m_hWnd; + return FALSE; + } + + return __super::PreTranslateMessage(pMsg); +} + +void CMainFrame::RecalcLayout(BOOL bNotify) +{ + __super::RecalcLayout(bNotify); + + CRect r; + GetWindowRect(&r); + MINMAXINFO mmi; + ZeroMemory(&mmi, sizeof(mmi)); + OnGetMinMaxInfo(&mmi); + const POINT& min = mmi.ptMinTrackSize; + if (r.Height() < min.y || r.Width() < min.x) { + r |= CRect(r.TopLeft(), CSize(min)); + MoveWindow(r); + } + OSDBarSetPos(); +} + +void CMainFrame::EnableDocking(DWORD dwDockStyle) +{ + ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY | CBRS_FLOAT_MULTI)) == 0); + + m_pFloatingFrameClass = RUNTIME_CLASS(CMPCThemeMiniDockFrameWnd); + for (int i = 0; i < 4; i++) { + if (dwDockBarMap[i][1] & dwDockStyle & CBRS_ALIGN_ANY) { + CMPCThemeDockBar* pDock = (CMPCThemeDockBar*)GetControlBar(dwDockBarMap[i][0]); + if (pDock == NULL) { + pDock = DEBUG_NEW CMPCThemeDockBar; + if (!pDock->Create(this, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD | WS_VISIBLE | + dwDockBarMap[i][1], dwDockBarMap[i][0])) { + AfxThrowResourceException(); + } + } + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame diagnostics + +#ifdef _DEBUG +void CMainFrame::AssertValid() const +{ + __super::AssertValid(); +} + +void CMainFrame::Dump(CDumpContext& dc) const +{ + __super::Dump(dc); +} + +#endif //_DEBUG + +typedef HIMC(WINAPI* pfnImmAssociateContext)(HWND, HIMC); +void dynImmAssociateContext(HWND hWnd, HIMC himc) { + HMODULE hImm32; + pfnImmAssociateContext pImmAssociateContext; + + hImm32 = LoadLibrary(_T("imm32.dll")); + if (NULL == hImm32) return; // No East Asian support + pImmAssociateContext = (pfnImmAssociateContext)GetProcAddress(hImm32, "ImmAssociateContext"); + if (NULL == pImmAssociateContext) { + FreeLibrary(hImm32); + return; + } + pImmAssociateContext(hWnd, himc); + FreeLibrary(hImm32); +} + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame message handlers +void CMainFrame::OnSetFocus(CWnd* pOldWnd) +{ + // forward focus to the view window + if (IsWindow(m_wndView.m_hWnd)) { + m_wndView.SetFocus(); + dynImmAssociateContext(m_wndView.m_hWnd, NULL); + } else { + dynImmAssociateContext(m_hWnd, NULL); + } +} + +BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) +{ + // let the view have first crack at the command + if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + + for (const auto& pair : m_controls.m_toolbars) { + if (pair.second->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + } + + for (const auto& pair : m_controls.m_panels) { + if (pair.second->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) { + return TRUE; + } + } + + // otherwise, do default handling + return __super::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpMMI) +{ + auto setLarger = [](long & a, long b) { + a = std::max(a, b); + }; + + const long saneSize = 110; + const bool bMenuVisible = GetMenuBarVisibility() == AFX_MBV_KEEPVISIBLE || m_bShowingFloatingMenubar; + + // Begin with docked controls + lpMMI->ptMinTrackSize = CPoint(m_controls.GetDockZonesMinSize(saneSize)); + + if (bMenuVisible) { + // Ensure that menubar will fit horizontally + MENUBARINFO mbi = { sizeof(mbi) }; + GetMenuBarInfo(OBJID_MENU, 0, &mbi); + long x = GetSystemMetrics(SM_CYMENU) / 2; // free space after menu + CRect rect; + for (int i = 0; GetMenuItemRect(m_hWnd, mbi.hMenu, i, &rect); i++) { + x += rect.Width(); + } + setLarger(lpMMI->ptMinTrackSize.x, x); + } + + if (IsWindow(m_wndToolBar) && m_controls.ControlChecked(CMainFrameControls::Toolbar::CONTROLS)) { + // Ensure that Controls toolbar will fit + setLarger(lpMMI->ptMinTrackSize.x, m_wndToolBar.GetMinWidth()); + } + + // Ensure that window decorations will fit + CRect decorationsRect; + VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), bMenuVisible, GetWindowExStyle(m_hWnd))); + lpMMI->ptMinTrackSize.x += decorationsRect.Width(); + lpMMI->ptMinTrackSize.y += decorationsRect.Height(); + + // Final fence + setLarger(lpMMI->ptMinTrackSize.x, GetSystemMetrics(SM_CXMIN)); + setLarger(lpMMI->ptMinTrackSize.y, GetSystemMetrics(SM_CYMIN)); + + lpMMI->ptMaxTrackSize.x = GetSystemMetrics(SM_CXVIRTUALSCREEN) + decorationsRect.Width(); + lpMMI->ptMaxTrackSize.y = GetSystemMetrics(SM_CYVIRTUALSCREEN) + + ((GetStyle() & WS_THICKFRAME) ? GetSystemMetrics(SM_CYSIZEFRAME) : 0); + + OSDBarSetPos(); +} + +void CMainFrame::OnMove(int x, int y) +{ + __super::OnMove(x, y); + + if (m_bWasSnapped && IsZoomed()) { + m_bWasSnapped = false; + } + + WINDOWPLACEMENT wp; + GetWindowPlacement(&wp); + if (!m_bNeedZoomAfterFullscreenExit && !m_fFullScreen && IsWindowVisible() && wp.flags != WPF_RESTORETOMAXIMIZED && wp.showCmd != SW_SHOWMINIMIZED) { + GetWindowRect(AfxGetAppSettings().rcLastWindowPos); + } + + OSDBarSetPos(); +} + +void CMainFrame::OnEnterSizeMove() +{ + if (m_bWasSnapped) { + VERIFY(GetCursorPos(&m_snapStartPoint)); + GetWindowRect(m_snapStartRect); + } +} + +void CMainFrame::OnMoving(UINT fwSide, LPRECT pRect) +{ + if (AfxGetAppSettings().fSnapToDesktopEdges) { + const CSize threshold(m_dpi.ScaleX(16), m_dpi.ScaleY(16)); + + CRect rect(pRect); + + CRect windowRect; + GetWindowRect(windowRect); + + if (windowRect.Size() != rect.Size()) { + // aero snap + return; + } + + CPoint point; + VERIFY(GetCursorPos(&point)); + + if (m_bWasSnapped) { + rect.MoveToXY(point - m_snapStartPoint + m_snapStartRect.TopLeft()); + } + + CRect areaRect; + CMonitors::GetNearestMonitor(this).GetWorkAreaRect(areaRect); + const CRect invisibleBorderSize = GetInvisibleBorderSize(); + areaRect.InflateRect(invisibleBorderSize); + + bool bSnapping = false; + + if (std::abs(rect.left - areaRect.left) < threshold.cx) { + bSnapping = true; + rect.MoveToX(areaRect.left); + } else if (std::abs(rect.right - areaRect.right) < threshold.cx) { + bSnapping = true; + rect.MoveToX(areaRect.right - rect.Width()); + } + if (std::abs(rect.top - areaRect.top) < threshold.cy) { + bSnapping = true; + rect.MoveToY(areaRect.top); + } else if (std::abs(rect.bottom - areaRect.bottom) < threshold.cy) { + bSnapping = true; + rect.MoveToY(areaRect.bottom - rect.Height()); + } + + if (!m_bWasSnapped && bSnapping) { + m_snapStartPoint = point; + m_snapStartRect = pRect; + } + + *pRect = rect; + + m_bWasSnapped = bSnapping; + } else { + m_bWasSnapped = false; + } + + __super::OnMoving(fwSide, pRect); + OSDBarSetPos(); +} + +void CMainFrame::OnSize(UINT nType, int cx, int cy) +{ + if (m_bTrayIcon && nType == SIZE_MINIMIZED) { + ShowWindow(SW_HIDE); + } else { + __super::OnSize(nType, cx, cy); + if (!m_bNeedZoomAfterFullscreenExit && IsWindowVisible() && !m_fFullScreen) { + CAppSettings& s = AfxGetAppSettings(); + if (nType != SIZE_MAXIMIZED && nType != SIZE_MINIMIZED) { + GetWindowRect(s.rcLastWindowPos); + } + s.nLastWindowType = nType; + } + } + if (nType != SIZE_MINIMIZED) { + OSDBarSetPos(); + } +} + +void CMainFrame::OnSizing(UINT nSide, LPRECT lpRect) +{ + __super::OnSizing(nSide, lpRect); + + if (m_fFullScreen) { + return; + } + + bool bCtrl = GetKeyState(VK_CONTROL) < 0; + OnSizingFixWndToVideo(nSide, lpRect, bCtrl); + OnSizingSnapToScreen(nSide, lpRect, bCtrl); +} + +void CMainFrame::OnSizingFixWndToVideo(UINT nSide, LPRECT lpRect, bool bCtrl) +{ + const auto& s = AfxGetAppSettings(); + + if (GetLoadState() != MLS::LOADED || s.iDefaultVideoSize == DVS_STRETCH || + bCtrl == s.fLimitWindowProportions || IsAeroSnapped() || (m_fAudioOnly && !m_wndView.IsCustomImgLoaded())) { + return; + } + + CSize videoSize = m_fAudioOnly ? m_wndView.GetLogoSize() : GetVideoSize(); + if (videoSize.cx == 0 || videoSize.cy == 0) { + return; + } + + CRect currentWindowRect, currentViewRect; + GetWindowRect(currentWindowRect); + m_wndView.GetWindowRect(currentViewRect); + CSize controlsSize(currentWindowRect.Width() - currentViewRect.Width(), + currentWindowRect.Height() - currentViewRect.Height()); + + const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); + const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); + if (bPanelsOnVideo) { + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetVisibleDockZones(uTop, uLeft, uRight, uBottom); + if (!bToolbarsOnVideo) { + uBottom -= m_controls.GetVisibleToolbarsHeight(); + } + controlsSize.cx -= uLeft + uRight; + controlsSize.cy -= uTop + uBottom; + } else if (bToolbarsOnVideo) { + controlsSize.cy -= m_controls.GetVisibleToolbarsHeight(); + } + + CSize newWindowSize(lpRect->right - lpRect->left, lpRect->bottom - lpRect->top); + + newWindowSize -= controlsSize; + + switch (nSide) { + case WMSZ_TOP: + case WMSZ_BOTTOM: + newWindowSize.cx = long(newWindowSize.cy * videoSize.cx / (double)videoSize.cy + 0.5); + newWindowSize.cy = long(newWindowSize.cx * videoSize.cy / (double)videoSize.cx + 0.5); + break; + case WMSZ_TOPLEFT: + case WMSZ_TOPRIGHT: + case WMSZ_BOTTOMLEFT: + case WMSZ_BOTTOMRIGHT: + case WMSZ_LEFT: + case WMSZ_RIGHT: + newWindowSize.cy = long(newWindowSize.cx * videoSize.cy / (double)videoSize.cx + 0.5); + newWindowSize.cx = long(newWindowSize.cy * videoSize.cx / (double)videoSize.cy + 0.5); + break; + } + + newWindowSize += controlsSize; + + switch (nSide) { + case WMSZ_TOPLEFT: + lpRect->left = lpRect->right - newWindowSize.cx; + lpRect->top = lpRect->bottom - newWindowSize.cy; + break; + case WMSZ_TOP: + case WMSZ_TOPRIGHT: + lpRect->right = lpRect->left + newWindowSize.cx; + lpRect->top = lpRect->bottom - newWindowSize.cy; + break; + case WMSZ_RIGHT: + case WMSZ_BOTTOM: + case WMSZ_BOTTOMRIGHT: + lpRect->right = lpRect->left + newWindowSize.cx; + lpRect->bottom = lpRect->top + newWindowSize.cy; + break; + case WMSZ_LEFT: + case WMSZ_BOTTOMLEFT: + lpRect->left = lpRect->right - newWindowSize.cx; + lpRect->bottom = lpRect->top + newWindowSize.cy; + break; + } + OSDBarSetPos(); +} + +void CMainFrame::OnSizingSnapToScreen(UINT nSide, LPRECT lpRect, bool bCtrl /*= false*/) +{ + const auto& s = AfxGetAppSettings(); + if (!s.fSnapToDesktopEdges) + return; + + CRect areaRect; + CMonitors::GetNearestMonitor(this).GetWorkAreaRect(areaRect); + const CRect invisibleBorderSize = GetInvisibleBorderSize(); + areaRect.InflateRect(invisibleBorderSize); + + CRect& rect = *reinterpret_cast(lpRect); + const CSize threshold(m_dpi.ScaleX(16), m_dpi.ScaleY(16)); + const auto SnapTo = [](LONG& val, LONG to, LONG threshold) { + return (std::abs(val - to) < threshold && val != to) ? (val = to, true) : false; + }; + + CSize videoSize = GetVideoSize(); + + if (bCtrl == s.fLimitWindowProportions || videoSize.cx == 0 || videoSize.cy == 0) { + SnapTo(rect.left, areaRect.left, threshold.cx); + SnapTo(rect.top, areaRect.top, threshold.cy); + SnapTo(rect.right, areaRect.right, threshold.cx); + SnapTo(rect.bottom, areaRect.bottom, threshold.cy); + return; + } + + const CRect rectOrig(rect); + switch (nSide) { + case WMSZ_TOPLEFT: + if (SnapTo(rect.left, areaRect.left, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_LEFT, &rect); + rect.OffsetRect(0, rectOrig.bottom - rect.bottom); + if (rect.top < areaRect.top && SnapTo(rect.top, areaRect.top, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_TOP, &rect); + rect.OffsetRect(rectOrig.right - rect.right, 0); + } + } else if (SnapTo(rect.top, areaRect.top, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_TOP, &rect); + rect.OffsetRect(rectOrig.right - rect.right, 0); + if (rect.left < areaRect.left && SnapTo(rect.left, areaRect.left, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_LEFT, &rect); + rect.OffsetRect(0, rectOrig.bottom - rect.bottom); + } + } + break; + case WMSZ_TOP: + case WMSZ_TOPRIGHT: + if (SnapTo(rect.right, areaRect.right, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); + rect.OffsetRect(0, rectOrig.bottom - rect.bottom); + if (rect.top < areaRect.top && SnapTo(rect.top, areaRect.top, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_TOP, &rect); + rect.OffsetRect(rectOrig.left - rect.left, 0); + } + } + else if (SnapTo(rect.top, areaRect.top, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_TOP, &rect); + rect.OffsetRect(rectOrig.left - rect.left, 0); + if (areaRect.right < rect.right && SnapTo(rect.right, areaRect.right, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); + rect.OffsetRect(0, rectOrig.bottom - rect.bottom); + } + } + break; + case WMSZ_RIGHT: + case WMSZ_BOTTOM: + case WMSZ_BOTTOMRIGHT: + if (SnapTo(rect.right, areaRect.right, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); + if (areaRect.bottom < rect.bottom && SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); + } + } else if (SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); + if (areaRect.right < rect.right && SnapTo(rect.right, areaRect.right, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_RIGHT, &rect); + } + } + break; + case WMSZ_LEFT: + case WMSZ_BOTTOMLEFT: + if (SnapTo(rect.left, areaRect.left, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_LEFT, &rect); + if (areaRect.bottom < rect.bottom && SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); + rect.OffsetRect(rectOrig.right - rect.right, 0); + } + } else if (SnapTo(rect.bottom, areaRect.bottom, threshold.cy)) { + OnSizingFixWndToVideo(WMSZ_BOTTOM, &rect); + rect.OffsetRect(rectOrig.right - rect.right, 0); + if (rect.left < areaRect.left && SnapTo(rect.left, areaRect.left, threshold.cx)) { + OnSizingFixWndToVideo(WMSZ_LEFT, &rect); + } + } + break; + } +} + +void CMainFrame::OnExitSizeMove() +{ + if (m_wndView.Dragging()) { + // HACK: windowed (not renderless) video renderers may not produce WM_MOUSEMOVE message here + UpdateControlState(CMainFrame::UPDATE_CHILDVIEW_CURSOR_HACK); + } +} + +void CMainFrame::OnDisplayChange() // untested, not sure if it's working... +{ + TRACE(_T("*** CMainFrame::OnDisplayChange()\n")); + + if (GetLoadState() == MLS::LOADED) { + if (m_pGraphThread) { + CAMMsgEvent e; + m_pGraphThread->PostThreadMessage(CGraphThread::TM_DISPLAY_CHANGE, (WPARAM)0, (LPARAM)&e); + e.WaitMsg(); + } else { + DisplayChange(); + } + } + + if (HasDedicatedFSVideoWindow()) { + MONITORINFO MonitorInfo; + HMONITOR hMonitor; + + ZeroMemory(&MonitorInfo, sizeof(MonitorInfo)); + MonitorInfo.cbSize = sizeof(MonitorInfo); + + hMonitor = MonitorFromWindow(m_pDedicatedFSVideoWnd->m_hWnd, 0); + if (GetMonitorInfo(hMonitor, &MonitorInfo)) { + CRect MonitorRect = CRect(MonitorInfo.rcMonitor); + m_pDedicatedFSVideoWnd->SetWindowPos(nullptr, + MonitorRect.left, + MonitorRect.top, + MonitorRect.Width(), + MonitorRect.Height(), + SWP_NOZORDER); + MoveVideoWindow(); + } + } +} + +void CMainFrame::OnWindowPosChanging(WINDOWPOS* lpwndpos) +{ + if (!(lpwndpos->flags & SWP_NOMOVE) && IsFullScreenMainFrame()) { + HMONITOR hm = MonitorFromPoint(CPoint(lpwndpos->x, lpwndpos->y), MONITOR_DEFAULTTONULL); + MONITORINFO mi = { sizeof(mi) }; + if (GetMonitorInfo(hm, &mi)) { + lpwndpos->flags &= ~SWP_NOSIZE; + lpwndpos->cx = mi.rcMonitor.right - mi.rcMonitor.left; + lpwndpos->cy = mi.rcMonitor.bottom - mi.rcMonitor.top; + lpwndpos->x = mi.rcMonitor.left; + lpwndpos->y = mi.rcMonitor.top; + } + } + __super::OnWindowPosChanging(lpwndpos); +} + +LRESULT CMainFrame::OnDpiChanged(WPARAM wParam, LPARAM lParam) +{ + m_dpi.Override(LOWORD(wParam), HIWORD(wParam)); + m_eventc.FireEvent(MpcEvent::DPI_CHANGED); + CMPCThemeUtil::GetMetrics(true); //force reset metrics used by util class + CMPCThemeMenu::clearDimensions(); + ReloadMenus(); + if (!restoringWindowRect) { //do not adjust for DPI if restoring saved window position + MoveWindow(reinterpret_cast(lParam)); + } + RecalcLayout(); + m_wndPreView.ScaleFont(); + return 0; +} + +void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) +{ + // Only stop screensaver if video playing; allow for audio only + if ((GetMediaState() == State_Running && !m_fEndOfStream && !m_fAudioOnly) + && (((nID & 0xFFF0) == SC_SCREENSAVE) || ((nID & 0xFFF0) == SC_MONITORPOWER))) { + TRACE(_T("SC_SCREENSAVE, nID = %u, lParam = %d\n"), nID, lParam); + return; + } + + __super::OnSysCommand(nID, lParam); +} + +void CMainFrame::OnActivateApp(BOOL bActive, DWORD dwThreadID) +{ + __super::OnActivateApp(bActive, dwThreadID); + + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW); + + if (IsFullScreenMainFrame()) { + if (bActive) { + // keep the fullscreen window on top while it's active, + // we don't want notification pop-ups to cover it + SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } else { + // don't keep the fullscreen window on top when it's not active, + // we want to be able to switch to other windows nicely + struct { + void operator()() const { + CMainFrame* pMainFrame = AfxGetMainFrame(); + if (!pMainFrame || !pMainFrame->m_fFullScreen || pMainFrame->WindowExpectedOnTop() || pMainFrame->m_bExtOnTop) { + return; + } + // place our window under the new active window + // when we can't determine that window, we try later + if (CWnd* pActiveWnd = GetForegroundWindow()) { + bool bMoved = false; + if (CWnd* pActiveRootWnd = pActiveWnd->GetAncestor(GA_ROOT)) { + const DWORD dwStyle = pActiveRootWnd->GetStyle(); + const DWORD dwExStyle = pActiveRootWnd->GetExStyle(); + if (!(dwStyle & WS_CHILD) && !(dwStyle & WS_POPUP) && !(dwExStyle & WS_EX_TOPMOST)) { + if (CWnd* pLastWnd = GetDesktopWindow()->GetTopWindow()) { + while (CWnd* pWnd = pLastWnd->GetNextWindow(GW_HWNDNEXT)) { + if (*pLastWnd == *pActiveRootWnd) { + pMainFrame->SetWindowPos( + pWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + bMoved = true; + break; + } + pLastWnd = pWnd; + } + } else { + ASSERT(FALSE); + } + } + } + if (!bMoved) { + pMainFrame->SetWindowPos( + &wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + } else { + pMainFrame->m_timerOneTime.Subscribe( + TimerOneTimeSubscriber::PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW, *this, 1); + } + } + } placeUnder; + placeUnder(); + } + } +} + +LRESULT CMainFrame::OnAppCommand(WPARAM wParam, LPARAM lParam) +{ + UINT cmd = GET_APPCOMMAND_LPARAM(lParam); + UINT uDevice = GET_DEVICE_LPARAM(lParam); + + if (uDevice != FAPPCOMMAND_OEM && cmd != 0 + || cmd == APPCOMMAND_MEDIA_PLAY + || cmd == APPCOMMAND_MEDIA_PAUSE + || cmd == APPCOMMAND_MEDIA_CHANNEL_UP + || cmd == APPCOMMAND_MEDIA_CHANNEL_DOWN + || cmd == APPCOMMAND_MEDIA_RECORD + || cmd == APPCOMMAND_MEDIA_FAST_FORWARD + || cmd == APPCOMMAND_MEDIA_REWIND) { + const CAppSettings& s = AfxGetAppSettings(); + + BOOL fRet = FALSE; + + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + if (wc.appcmd == cmd && TRUE == SendMessage(WM_COMMAND, wc.cmd)) { + fRet = TRUE; + } + } + + if (fRet) { + return TRUE; + } + } + + return Default(); +} + +void CMainFrame::OnRawInput(UINT nInputcode, HRAWINPUT hRawInput) +{ + const CAppSettings& s = AfxGetAppSettings(); + UINT nMceCmd = AfxGetMyApp()->GetRemoteControlCode(nInputcode, hRawInput); + + switch (nMceCmd) { + case MCE_DETAILS: + case MCE_GUIDE: + case MCE_TVJUMP: + case MCE_STANDBY: + case MCE_OEM1: + case MCE_OEM2: + case MCE_MYTV: + case MCE_MYVIDEOS: + case MCE_MYPICTURES: + case MCE_MYMUSIC: + case MCE_RECORDEDTV: + case MCE_DVDANGLE: + case MCE_DVDAUDIO: + case MCE_DVDMENU: + case MCE_DVDSUBTITLE: + case MCE_RED: + case MCE_GREEN: + case MCE_YELLOW: + case MCE_BLUE: + case MCE_MEDIA_NEXTTRACK: + case MCE_MEDIA_PREVIOUSTRACK: + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + if (wc.appcmd == nMceCmd) { + SendMessage(WM_COMMAND, wc.cmd); + break; + } + } + break; + } +} + +LRESULT CMainFrame::OnHotKey(WPARAM wParam, LPARAM lParam) +{ + if (wParam == 0) { + ASSERT(false); + return FALSE; + } + + const CAppSettings& s = AfxGetAppSettings(); + BOOL fRet = FALSE; + + if (GetActiveWindow() == this || s.fGlobalMedia == TRUE) { + POSITION pos = s.wmcmds.GetHeadPosition(); + + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + if (wc.appcmd == wParam && TRUE == SendMessage(WM_COMMAND, wc.cmd)) { + fRet = TRUE; + } + } + } + + return fRet; +} + +bool g_bNoDuration = false; +bool g_bExternalSubtitleTime = false; +bool g_bExternalSubtitle = false; +double g_dRate = 1.0; + +void CMainFrame::OnTimer(UINT_PTR nIDEvent) +{ + switch (nIDEvent) { + case TIMER_WINDOW_FULLSCREEN: + if (AfxGetAppSettings().iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 + BOOL setEnabled = FALSE; + ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); + } + KillTimer(TIMER_WINDOW_FULLSCREEN); + delayingFullScreen = false; + break; + case TIMER_STREAMPOSPOLLER: + if (GetLoadState() == MLS::LOADED) { + REFERENCE_TIME rtNow = 0, rtDur = 0; + switch (GetPlaybackMode()) { + case PM_FILE: + g_bExternalSubtitleTime = false; + if (m_pGB && m_pMS) { + m_pMS->GetCurrentPosition(&rtNow); + if (!m_pGB || !m_pMS) return; // can happen very rarely due to race condition + m_pMS->GetDuration(&rtDur); + + if ((abRepeat.positionA && rtNow < abRepeat.positionA || abRepeat.positionB && rtNow >= abRepeat.positionB) && GetMediaState() != State_Stopped) { + PerformABRepeat(); + return; + } + + auto* pMRU = &AfxGetAppSettings().MRU; + if (m_bRememberFilePos && !m_fEndOfStream) { + pMRU->UpdateCurrentFilePosition(rtNow); + } + + // Casimir666 : autosave subtitle sync after play + if (m_nCurSubtitle >= 0 && m_rtCurSubPos != rtNow) { + if (m_lSubtitleShift) { + 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; + } + + m_wndStatusBar.SetStatusTimer(rtNow, rtDur, IsSubresyncBarVisible(), GetTimeFormat()); + } + break; + case PM_DVD: + 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 ? 30 / 1.001 + : 25.0; + + rtNow = HMSF2RT(Location.TimeCode, fps); + + if (abRepeat.positionB && rtNow >= abRepeat.positionB && GetMediaState() != State_Stopped) { + PerformABRepeat(); + return; + } + + DVD_HMSF_TIMECODE tcDur; + ULONG ulFlags; + if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { + rtDur = HMSF2RT(tcDur, fps); + } + if (m_pSubClock) { + m_pSubClock->SetTime(rtNow); + } + } + } + m_wndStatusBar.SetStatusTimer(rtNow, rtDur, IsSubresyncBarVisible(), GetTimeFormat()); + break; + case PM_ANALOG_CAPTURE: + g_bExternalSubtitleTime = true; + if (m_fCapturing) { + if (m_wndCaptureBar.m_capdlg.m_pMux) { + CComQIPtr pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux; + if (!pMuxMS || FAILED(pMuxMS->GetCurrentPosition(&rtNow))) { + if (m_pMS) { + m_pMS->GetCurrentPosition(&rtNow); + } + } + } + if (m_rtDurationOverride >= 0) { + rtDur = m_rtDurationOverride; + } + } + break; + case PM_DIGITAL_CAPTURE: + g_bExternalSubtitleTime = true; + m_pMS->GetCurrentPosition(&rtNow); + break; + default: + ASSERT(FALSE); + break; + } + + g_bNoDuration = rtDur <= 0; + m_wndSeekBar.Enable(!g_bNoDuration); + m_wndSeekBar.SetRange(0, rtDur); + m_wndSeekBar.SetPos(rtNow); + m_OSD.SetRange(rtDur); + m_OSD.SetPos(rtNow); + m_Lcd.SetMediaRange(0, rtDur); + m_Lcd.SetMediaPos(rtNow); + + if (m_pCAP) { + if (g_bExternalSubtitleTime) { + m_pCAP->SetTime(rtNow); + } + m_wndSubresyncBar.SetTime(rtNow); + m_wndSubresyncBar.SetFPS(m_pCAP->GetFPS()); + } + if (g_bExternalSubtitleTime && (m_iStreamPosPollerInterval > 40)) { + AdjustStreamPosPoller(true); + } + } + break; + case TIMER_STREAMPOSPOLLER2: + if (GetLoadState() == MLS::LOADED) { + switch (GetPlaybackMode()) { + case PM_FILE: + // no break + case PM_DVD: + if (AfxGetAppSettings().fShowCurrentTimeInOSD && m_OSD.CanShowMessage()) { + m_OSD.DisplayTime(m_wndStatusBar.GetStatusTimer()); + } + break; + case PM_DIGITAL_CAPTURE: { + EventDescriptor& NowNext = m_pDVBState->NowNext; + time_t tNow; + time(&tNow); + if (NowNext.duration > 0 && tNow >= NowNext.startTime && tNow <= NowNext.startTime + NowNext.duration) { + REFERENCE_TIME rtNow = REFERENCE_TIME(tNow - NowNext.startTime) * 10000000; + REFERENCE_TIME rtDur = REFERENCE_TIME(NowNext.duration) * 10000000; + m_wndStatusBar.SetStatusTimer(rtNow, rtDur, false, TIME_FORMAT_MEDIA_TIME); + if (AfxGetAppSettings().fShowCurrentTimeInOSD && m_OSD.CanShowMessage()) { + m_OSD.DisplayTime(m_wndStatusBar.GetStatusTimer()); + } + } else { + m_wndStatusBar.SetStatusTimer(ResStr(IDS_CAPTURE_LIVE)); + } + } + break; + case PM_ANALOG_CAPTURE: + if (!m_fCapturing) { + CString str(StrRes(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))) { + str.AppendFormat(_T(" (ch%ld)"), lChannel); + } + m_wndStatusBar.SetStatusTimer(str); + } + break; + default: + ASSERT(FALSE); + break; + } + } + break; + case TIMER_STATS: { + const CAppSettings& s = AfxGetAppSettings(); + if (m_wndStatsBar.IsVisible()) { + CString rate; + rate.Format(_T("%.3fx"), m_dSpeedRate); + if (m_pQP) { + CString info; + int tmp, tmp1; + + if (SUCCEEDED(m_pQP->get_AvgFrameRate(&tmp))) { // We hang here due to a lock that never gets released. + info.Format(_T("%d.%02d (%s)"), tmp / 100, tmp % 100, rate.GetString()); + } else { + info = _T("-"); + } + m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMERATE), info); + + if (SUCCEEDED(m_pQP->get_AvgSyncOffset(&tmp)) + && SUCCEEDED(m_pQP->get_DevSyncOffset(&tmp1))) { + info.Format(IDS_STATSBAR_SYNC_OFFSET_FORMAT, tmp, tmp1); + } else { + info = _T("-"); + } + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SYNC_OFFSET), info); + + if (SUCCEEDED(m_pQP->get_FramesDrawn(&tmp)) + && SUCCEEDED(m_pQP->get_FramesDroppedInRenderer(&tmp1))) { + info.Format(IDS_MAINFRM_6, tmp, tmp1); + } else { + info = _T("-"); + } + m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMES), info); + + if (SUCCEEDED(m_pQP->get_Jitter(&tmp))) { + info.Format(_T("%d ms"), tmp); + } else { + info = _T("-"); + } + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_JITTER), info); + } else { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_PLAYBACK_RATE), rate); + } + + if (m_pBI) { + CString sInfo; + + for (int i = 0, j = m_pBI->GetCount(); i < j; i++) { + int samples, size; + if (S_OK == m_pBI->GetStatus(i, samples, size) && (i < 2 || size > 0)) { // third pin is usually subs + sInfo.AppendFormat(_T("[P%d] %03d samples / %d KB "), i, samples, size / 1024); + } + } + + if (!sInfo.IsEmpty()) { + //sInfo.AppendFormat(_T("(p%lu)"), m_pBI->GetPriority()); + m_wndStatsBar.SetLine(StrRes(IDS_AG_BUFFERS), sInfo); + } + } + + { + // IBitRateInfo + CString sInfo; + BeginEnumFilters(m_pGB, pEF, pBF) { + unsigned i = 0; + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pBRI = pPin) { + DWORD nAvg = pBRI->GetAverageBitRate() / 1000; + + if (nAvg > 0) { + sInfo.AppendFormat(_T("[P%u] %lu/%lu kb/s "), i, nAvg, pBRI->GetCurrentBitRate() / 1000); + } + } + i++; + } + EndEnumPins; + + if (!sInfo.IsEmpty()) { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_BITRATE), sInfo + ResStr(IDS_STATSBAR_BITRATE_AVG_CUR)); + sInfo.Empty(); + } + } + EndEnumFilters; + } + } + + if (GetPlaybackMode() == PM_DVD) { // we also use this timer to update the info panel for DVD playback + ULONG ulAvailable, ulCurrent; + + // Location + + CString Location(_T('-')); + + 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(StrRes(IDS_INFOBAR_LOCATION), Location); + + // Video + + CString Video(_T('-')); + + 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_statusbarVideoSize.Format(_T("%dx%d"), VATR.ulSourceResolutionX, VATR.ulSourceResolutionY); + m_statusbarVideoFormat = VATR.Compression == DVD_VideoCompression_MPEG1 ? L"MPG1" : VATR.Compression == DVD_VideoCompression_MPEG2 ? L"MPG2" : L""; + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_VIDEO), Video); + + // Audio + + CString Audio(_T('-')); + + DVD_AudioAttributes AATR; + + if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulAvailable, &ulCurrent)) + && SUCCEEDED(m_pDVDI->GetAudioAttributes(ulCurrent, &AATR))) { + CString lang; + if (AATR.Language) { + GetLocaleString(AATR.Language, LOCALE_SENGLANGUAGE, lang); + currentAudioLang = lang; + } else { + lang.Format(IDS_AG_UNKNOWN, ulCurrent + 1); + currentAudioLang.Empty(); + } + + 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); + m_statusbarAudioFormat.Format(L"%s %dch", format, AATR.bNumberOfChannels); + + Audio.Format(IDS_MAINFRM_11, + lang.GetString(), + format.GetString(), + AATR.dwFrequency, + AATR.bQuantization, + AATR.bNumberOfChannels, + ResStr(AATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString()); + + m_wndStatusBar.SetStatusBitmap( + AATR.bNumberOfChannels == 1 ? IDB_AUDIOTYPE_MONO + : AATR.bNumberOfChannels >= 2 ? IDB_AUDIOTYPE_STEREO + : IDB_AUDIOTYPE_NOAUDIO); + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUDIO), Audio); + + // Subtitles + + CString Subtitles(_T('-')); + + BOOL bIsDisabled; + DVD_SubpictureAttributes SATR; + + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulAvailable, &ulCurrent, &bIsDisabled)) + && SUCCEEDED(m_pDVDI->GetSubpictureAttributes(ulCurrent, &SATR))) { + CString lang; + GetLocaleString(SATR.Language, LOCALE_SENGLANGUAGE, lang); + + 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.GetString()); + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_SUBTITLES), Subtitles); + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + if (m_pDVBState->bActive) { + CComQIPtr pTun = m_pGB; + BOOLEAN bPresent, bLocked; + LONG lDbStrength, lPercentQuality; + CString Signal; + + if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { + Signal.Format(IDS_STATSBAR_SIGNAL_FORMAT, (int)lDbStrength, lPercentQuality); + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), Signal); + } + } else { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), _T("-")); + } + } else if (GetPlaybackMode() == PM_FILE) { + OpenSetupInfoBar(false); + if (s.iTitleBarTextStyle == 1 && s.fTitleBarTextTitle) { + OpenSetupWindowTitle(); + } + MediaTransportControlSetMedia(); + SendNowPlayingToSkype(); + SendNowPlayingToApi(false); + } + + if (m_CachedFilterState == State_Running && !m_fAudioOnly) { + if (s.bPreventDisplaySleep) { + BOOL fActive = FALSE; + if (SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fActive, 0) && fActive) { + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, nullptr, SPIF_SENDWININICHANGE); + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, fActive, nullptr, SPIF_SENDWININICHANGE); + } + + // prevent screensaver activate, monitor sleep/turn off after playback + SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); + } + } + } + break; + case TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS: { + if (GetPlaybackMode() == PM_NONE) { + if (UnloadUnusedExternalObjects()) { + KillTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS); + } + } + } + break; + case TIMER_HIDER: + m_timerHider.NotifySubscribers(); + break; + case TIMER_DELAYEDSEEK: + KillTimer(TIMER_DELAYEDSEEK); + if (queuedSeek.seekTime > 0) { + SeekTo(queuedSeek.rtPos, queuedSeek.bShowOSD); + } + break; + default: + if (nIDEvent >= TIMER_ONETIME_START && nIDEvent <= TIMER_ONETIME_END) { + m_timerOneTime.NotifySubscribers(nIDEvent); + } else { + ASSERT(FALSE); + } + } + + __super::OnTimer(nIDEvent); +} + +void CMainFrame::DoAfterPlaybackEvent() +{ + CAppSettings& s = AfxGetAppSettings(); + bool bExitFullScreen = false; + bool bNoMoreMedia = false; + + if (s.nCLSwitches & CLSW_DONOTHING) { + // Do nothing + } else if (s.nCLSwitches & CLSW_CLOSE) { + SendMessage(WM_COMMAND, ID_FILE_EXIT); + } else if (s.nCLSwitches & CLSW_MONITOROFF) { + m_fEndOfStream = true; + bExitFullScreen = true; + SetThreadExecutionState(ES_CONTINUOUS); + SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, 2); + } else if (s.nCLSwitches & CLSW_STANDBY) { + SetPrivilege(SE_SHUTDOWN_NAME); + SetSystemPowerState(TRUE, FALSE); + SendMessage(WM_COMMAND, ID_FILE_EXIT); // Recheck if this is still needed after switching to new toolset and SetSuspendState() + } else if (s.nCLSwitches & CLSW_HIBERNATE) { + SetPrivilege(SE_SHUTDOWN_NAME); + SetSystemPowerState(FALSE, FALSE); + SendMessage(WM_COMMAND, ID_FILE_EXIT); + } else if (s.nCLSwitches & CLSW_SHUTDOWN) { + SetPrivilege(SE_SHUTDOWN_NAME); + InitiateSystemShutdownEx(nullptr, nullptr, 0, TRUE, FALSE, + SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE | SHTDN_REASON_FLAG_PLANNED); + SendMessage(WM_COMMAND, ID_FILE_EXIT); + } else if (s.nCLSwitches & CLSW_LOGOFF) { + SetPrivilege(SE_SHUTDOWN_NAME); + ExitWindowsEx(EWX_LOGOFF | EWX_FORCEIFHUNG, 0); + SendMessage(WM_COMMAND, ID_FILE_EXIT); + } else if (s.nCLSwitches & CLSW_LOCK) { + m_fEndOfStream = true; + bExitFullScreen = true; + LockWorkStation(); + } else if (s.nCLSwitches & CLSW_PLAYNEXT) { + if (!SearchInDir(true, (s.fLoopForever || m_nLoops < s.nLoops || s.bLoopFolderOnPlayNextFile))) { + m_fEndOfStream = true; + bExitFullScreen = true; + bNoMoreMedia = true; + } + } else { + // remembered after playback events + switch (s.eAfterPlayback) { + case CAppSettings::AfterPlayback::PLAY_NEXT: + if (m_wndPlaylistBar.GetCount() < 2) { // ignore global PLAY_NEXT in case of a playlist + if (!SearchInDir(true, s.bLoopFolderOnPlayNextFile)) { + SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); + } + } + break; + case CAppSettings::AfterPlayback::REWIND: + bExitFullScreen = true; + if (m_wndPlaylistBar.GetCount() > 1) { + s.nCLSwitches |= CLSW_OPEN; + PostMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); + } else { + SendMessage(WM_COMMAND, ID_PLAY_STOP); + } + break; + case CAppSettings::AfterPlayback::MONITOROFF: + m_fEndOfStream = true; + bExitFullScreen = true; + SetThreadExecutionState(ES_CONTINUOUS); + SendMessage(WM_SYSCOMMAND, SC_MONITORPOWER, 2); + break; + case CAppSettings::AfterPlayback::CLOSE: + SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); + break; + case CAppSettings::AfterPlayback::EXIT: + SendMessage(WM_COMMAND, ID_FILE_EXIT); + break; + default: + m_fEndOfStream = true; + bExitFullScreen = true; + break; + } + } + + if (AfxGetMyApp()->m_fClosingState) { + return; + } + + if (m_fEndOfStream) { + m_OSD.EnableShowMessage(false); + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + m_OSD.EnableShowMessage(); + if (bNoMoreMedia) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_NO_MORE_MEDIA)); + } + } + + if (bExitFullScreen && (IsFullScreenMode()) && s.fExitFullScreenAtTheEnd) { + OnViewFullscreen(); + } +} + +void CMainFrame::OnUpdateABRepeat(CCmdUI* pCmdUI) { + bool canABRepeat = GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD; + bool abRepeatActive = static_cast(abRepeat); + + switch (pCmdUI->m_nID) { + case ID_PLAY_REPEAT_AB: + pCmdUI->Enable(canABRepeat && abRepeatActive); + break; + case ID_PLAY_REPEAT_AB_MARK_A: + if (pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuItem(ID_PLAY_REPEAT_AB_MARK_A, MF_BYCOMMAND | (abRepeat.positionA ? MF_CHECKED : MF_UNCHECKED)); + } + pCmdUI->Enable(canABRepeat); + break; + case ID_PLAY_REPEAT_AB_MARK_B: + if (pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuItem(ID_PLAY_REPEAT_AB_MARK_B, MF_BYCOMMAND | (abRepeat.positionB ? MF_CHECKED : MF_UNCHECKED)); + } + pCmdUI->Enable(canABRepeat); + break; + default: + ASSERT(FALSE); + return; + } +} + + +void CMainFrame::OnABRepeat(UINT nID) { + switch (nID) { + case ID_PLAY_REPEAT_AB: + if (abRepeat) { //only support disabling from the menu + DisableABRepeat(); + } + break; + case ID_PLAY_REPEAT_AB_MARK_A: + case ID_PLAY_REPEAT_AB_MARK_B: + REFERENCE_TIME rtDur = 0; + int playmode = GetPlaybackMode(); + + bool havePos = false; + REFERENCE_TIME pos = 0; + + if (playmode == PM_FILE && m_pMS) { + m_pMS->GetDuration(&rtDur); + havePos = SUCCEEDED(m_pMS->GetCurrentPosition(&pos)); + } else if (playmode == PM_DVD && 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 ? 30 / 1.001 + : 25.0; + DVD_HMSF_TIMECODE tcDur; + ULONG ulFlags; + if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { + rtDur = HMSF2RT(tcDur, fps); + } + havePos = true; + pos = HMSF2RT(Location.TimeCode, fps); + abRepeat.dvdTitle = m_iDVDTitle; //we only support one title. so if they clear or set, we will remember the current title + } + } else { + return; + } + + if (nID == ID_PLAY_REPEAT_AB_MARK_A) { + if (abRepeat.positionA) { + abRepeat.positionA = 0; + } else if (havePos) { + abRepeat.positionA = pos; + if (abRepeat.positionA < rtDur) { + if (abRepeat.positionB && abRepeat.positionA >= abRepeat.positionB) { + abRepeat.positionB = 0; + } + } else { + abRepeat.positionA = 0; + } + } + } else if (nID == ID_PLAY_REPEAT_AB_MARK_B) { + if (abRepeat.positionB) { + abRepeat.positionB = 0; + } else if (havePos) { + abRepeat.positionB = pos; + if (abRepeat.positionB > 0 && abRepeat.positionB > abRepeat.positionA && rtDur >= abRepeat.positionB) { + if (GetMediaState() == State_Running) { + PerformABRepeat(); //we just set loop point B, so we need to repeat right now + } + } else { + abRepeat.positionB = 0; + } + } + } + + auto pMRU = &AfxGetAppSettings().MRU; + pMRU->UpdateCurrentABRepeat(abRepeat); + + m_wndSeekBar.Invalidate(); + break; + } +} + +void CMainFrame::PerformABRepeat() { + DoSeekTo(abRepeat.positionA, false); + + if (GetMediaState() == State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } +} + +void CMainFrame::DisableABRepeat() { + abRepeat = ABRepeat(); + + auto* pMRU = &AfxGetAppSettings().MRU; + pMRU->UpdateCurrentABRepeat(abRepeat); + + m_wndSeekBar.Invalidate(); +} + +bool CMainFrame::CheckABRepeat(REFERENCE_TIME& aPos, REFERENCE_TIME& bPos) { + if (GetPlaybackMode() == PM_FILE || (GetPlaybackMode() == PM_DVD && m_iDVDTitle == abRepeat.dvdTitle)) { + if (abRepeat) { + aPos = abRepeat.positionA; + bPos = abRepeat.positionB; + return true; + } + } + return false; +} + + +// +// graph event EC_COMPLETE handler +// +void CMainFrame::GraphEventComplete() +{ + CAppSettings& s = AfxGetAppSettings(); + + auto* pMRU = &s.MRU; + + + if (m_bRememberFilePos) { + pMRU->UpdateCurrentFilePosition(0, true); + } + + bool bBreak = false; + if (m_wndPlaylistBar.IsAtEnd() || s.eLoopMode == CAppSettings::LoopMode::FILE) { + ++m_nLoops; + bBreak = !!(s.nCLSwitches & CLSW_AFTERPLAYBACK_MASK); + } + + if (abRepeat) { + PerformABRepeat(); + } else if (s.fLoopForever || m_nLoops < s.nLoops) { + if (bBreak) { + DoAfterPlaybackEvent(); + } else if ((m_wndPlaylistBar.GetCount() > 1) && (s.eLoopMode == CAppSettings::LoopMode::PLAYLIST)) { + int nLoops = m_nLoops; + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARDFILE); + m_nLoops = nLoops; + } else { + if (GetMediaState() == State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } else if (m_pMS) { + REFERENCE_TIME rtDur = 0; + if ((m_pMS->GetDuration(&rtDur) == S_OK) && (rtDur >= 1000000LL) || !IsImageFile(lastOpenFile)) { // repeating still image is pointless and can cause player UI to freeze + REFERENCE_TIME rtPos = 0; + m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + if (GetMediaState() == State_Paused) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + } + } + } + } else { + DoAfterPlaybackEvent(); + } +} + +// +// our WM_GRAPHNOTIFY handler +// + +LRESULT CMainFrame::OnGraphNotify(WPARAM wParam, LPARAM lParam) +{ + CAppSettings& s = AfxGetAppSettings(); + HRESULT hr = S_OK; + + LONG evCode = 0; + LONG_PTR evParam1, evParam2; + while (!AfxGetMyApp()->m_fClosingState && m_pME && SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) { +#ifdef _DEBUG + if (evCode != EC_DVD_CURRENT_HMSF_TIME) { + TRACE(_T("--> CMainFrame::OnGraphNotify on thread: %lu; event: 0x%08x (%ws)\n"), GetCurrentThreadId(), evCode, GetEventString(evCode)); + } +#endif + CString str; + if (m_fCustomGraph) { + if (EC_BG_ERROR == evCode) { + str = CString((char*)evParam1); + } + } + hr = m_pME->FreeEventParams(evCode, evParam1, evParam2); + + switch (evCode) { + case EC_PAUSED: + if (GetLoadState() == MLS::LOADED) { + UpdateCachedMediaState(); + } + if (m_audioTrackCount > 1 && GetLoadState() == MLS::LOADED) { + CheckSelectedAudioStream(); + } + break; + case EC_COMPLETE: + UpdateCachedMediaState(); + GraphEventComplete(); + break; + case EC_ERRORABORT: + UpdateCachedMediaState(); + TRACE(_T("\thr = %08x\n"), (HRESULT)evParam1); + break; + case EC_BUFFERING_DATA: + TRACE(_T("\tBuffering data = %s\n"), evParam1 ? _T("true") : _T("false")); + m_bBuffering = !!evParam1; + break; + case EC_STEP_COMPLETE: + if (m_fFrameSteppingActive) { + m_nStepForwardCount++; + } + UpdateCachedMediaState(); + break; + case EC_DEVICE_LOST: + UpdateCachedMediaState(); + if (evParam2 == 0) { + // Device lost + if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + CComQIPtr pBF = (IUnknown*)evParam1; + if (!m_pVidCap && m_pVidCap == pBF || !m_pAudCap && m_pAudCap == pBF) { + SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); + } + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + SendMessage(WM_COMMAND, ID_FILE_CLOSE_AND_RESTORE); + } + } + break; + case EC_DVD_TITLE_CHANGE: { + if (GetPlaybackMode() == PM_FILE) { + SetupChapters(); + } else if (GetPlaybackMode() == PM_DVD) { + m_iDVDTitle = (DWORD)evParam1; + + if (m_iDVDDomain == DVD_DOMAIN_Title) { + CString Domain; + Domain.Format(IDS_AG_TITLE, m_iDVDTitle); + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), Domain); + } + + SetupDVDChapters(); + } + } + break; + case EC_DVD_DOMAIN_CHANGE: { + m_iDVDDomain = (DVD_DOMAIN)evParam1; + + OpenDVDData* pDVDData = dynamic_cast(m_lastOMD.m_p); + ASSERT(pDVDData); + + CString Domain(_T('-')); + + switch (m_iDVDDomain) { + case DVD_DOMAIN_FirstPlay: + ULONGLONG llDVDGuid; + + Domain = _T("First Play"); + + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDiscID(nullptr, &llDVDGuid))) { + m_fValidDVDOpen = true; + + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("DVD Title: %lu"), s.lDVDTitle); + } + + if (s.lDVDTitle != 0) { + // Set command line position + hr = m_pDVDC->PlayTitle(s.lDVDTitle, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayTitle: 0x%08X"), hr); + m_OSD.DebugMessage(_T("DVD Chapter: %lu"), s.lDVDChapter); + } + + if (s.lDVDChapter > 1) { + hr = m_pDVDC->PlayChapterInTitle(s.lDVDTitle, s.lDVDChapter, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayChapterInTitle: 0x%08X"), hr); + } + } else { + // Trick: skip trailers with some DVDs + hr = m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("Resume: 0x%08X"), hr); + } + + // If the resume call succeeded, then we skip PlayChapterInTitle + // and PlayAtTimeInTitle. + if (hr == S_OK) { + // This might fail if the Title is not available yet? + hr = m_pDVDC->PlayAtTime(&s.DVDPosition, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayAtTime: 0x%08X"), hr); + } + } else { + if (s.fShowDebugInfo) + m_OSD.DebugMessage(_T("Timecode requested: %02d:%02d:%02d.%03d"), + s.DVDPosition.bHours, s.DVDPosition.bMinutes, + s.DVDPosition.bSeconds, s.DVDPosition.bFrames); + + // Always play chapter 1 (for now, until something else dumb happens) + hr = m_pDVDC->PlayChapterInTitle(s.lDVDTitle, 1, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayChapterInTitle: 0x%08X"), hr); + } + + // This might fail if the Title is not available yet? + hr = m_pDVDC->PlayAtTime(&s.DVDPosition, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayAtTime: 0x%08X"), hr); + } + + if (hr != S_OK) { + hr = m_pDVDC->PlayAtTimeInTitle(s.lDVDTitle, &s.DVDPosition, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayAtTimeInTitle: 0x%08X"), hr); + } + } + } // Resume + + hr = m_pDVDC->PlayAtTime(&s.DVDPosition, + DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("PlayAtTime: %d"), hr); + } + } + + m_iDVDTitle = s.lDVDTitle; + s.lDVDTitle = 0; + s.lDVDChapter = 0; + } else if (pDVDData && pDVDData->pDvdState) { + // Set position from favorite + VERIFY(SUCCEEDED(m_pDVDC->SetState(pDVDData->pDvdState, DVD_CMD_FLAG_Block, nullptr))); + // We don't want to restore the position from the favorite + // if the playback is reinitialized so we clear the saved state + pDVDData->pDvdState.Release(); + } else if (s.fKeepHistory && s.fRememberDVDPos && s.MRU.GetCurrentDVDPosition().llDVDGuid) { + // Set last remembered position (if found...) + DVD_POSITION dvdPosition = s.MRU.GetCurrentDVDPosition(); + + hr = m_pDVDC->PlayTitle(dvdPosition.lTitle, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + TRACE(_T("Failed to set remembered DVD title index, hr = 0x%08X"), hr); + } else { + m_iDVDTitle = dvdPosition.lTitle; + + if (dvdPosition.timecode.bSeconds > 0 || dvdPosition.timecode.bMinutes > 0 || dvdPosition.timecode.bHours > 0 || dvdPosition.timecode.bFrames > 0) { +#if 0 + hr = m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + TRACE(_T("Failed to set remembered DVD resume flags, hr = 0x%08X"), hr); + } +#endif +#if 0 + hr = m_pDVDC->PlayAtTimeInTitle(dvdPosition.lTitle, &dvdPosition.timecode, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); +#else + hr = m_pDVDC->PlayAtTime(&dvdPosition.timecode, DVD_CMD_FLAG_Flush, nullptr); +#endif + } + + ABRepeat tmp = s.MRU.GetCurrentABRepeat(); + if (tmp.dvdTitle == m_iDVDTitle) { + abRepeat = tmp; + m_wndSeekBar.Invalidate(); + } + } + } + + if (s.fRememberZoomLevel && !IsFullScreenMode() && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { // Hack to the normal initial zoom for DVD + DXVA ... + ZoomVideoWindow(); + } + } + break; + case DVD_DOMAIN_VideoManagerMenu: + Domain = _T("Video Manager Menu"); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + break; + case DVD_DOMAIN_VideoTitleSetMenu: + Domain = _T("Video Title Set Menu"); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + break; + case DVD_DOMAIN_Title: + Domain.Format(IDS_AG_TITLE, m_iDVDTitle); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + if (s.fKeepHistory && s.fRememberDVDPos) { + s.MRU.UpdateCurrentDVDTitle(m_iDVDTitle); + } + if (!m_fValidDVDOpen && m_pDVDC) { + m_fValidDVDOpen = true; + m_pDVDC->ShowMenu(DVD_MENU_Title, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + } + break; + case DVD_DOMAIN_Stop: + Domain.LoadString(IDS_AG_STOP); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + break; + default: + Domain = _T("-"); + if (s.fShowDebugInfo) { + m_OSD.DebugMessage(_T("%s"), Domain.GetString()); + } + break; + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), Domain); + + if (GetPlaybackMode() == PM_FILE) { + SetupChapters(); + } else if (GetPlaybackMode() == PM_DVD) { + SetupDVDChapters(); + } + +#if 0 // UOPs debug traces + if (hr == VFW_E_DVD_OPERATION_INHIBITED) { + ULONG UOPfields = 0; + pDVDI->GetCurrentUOPS(&UOPfields); + CString message; + message.Format(_T("UOP bitfield: 0x%08X; domain: %s"), UOPfields, Domain); + m_OSD.DisplayMessage(OSD_TOPLEFT, message); + } else { + m_OSD.DisplayMessage(OSD_TOPRIGHT, Domain); + } +#endif + + MoveVideoWindow(); // AR might have changed + } + break; + case EC_DVD_CURRENT_HMSF_TIME: { + s.MRU.UpdateCurrentDVDTimecode((DVD_HMSF_TIMECODE*)&evParam1); + } + break; + case EC_DVD_ERROR: { + TRACE(_T("\t%I64d %Id\n"), evParam1, evParam2); + + UINT err; + + switch (evParam1) { + case DVD_ERROR_Unexpected: + default: + err = IDS_MAINFRM_16; + break; + case DVD_ERROR_CopyProtectFail: + err = IDS_MAINFRM_17; + break; + case DVD_ERROR_InvalidDVD1_0Disc: + err = IDS_MAINFRM_18; + break; + case DVD_ERROR_InvalidDiscRegion: + err = IDS_MAINFRM_19; + break; + case DVD_ERROR_LowParentalLevel: + err = IDS_MAINFRM_20; + break; + case DVD_ERROR_MacrovisionFail: + err = IDS_MAINFRM_21; + break; + case DVD_ERROR_IncompatibleSystemAndDecoderRegions: + err = IDS_MAINFRM_22; + break; + case DVD_ERROR_IncompatibleDiscAndDecoderRegions: + err = IDS_MAINFRM_23; + break; + } + + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + m_closingmsg.LoadString(err); + } + break; + case EC_DVD_WARNING: + TRACE(_T("\t%Id %Id\n"), evParam1, evParam2); + break; + case EC_VIDEO_SIZE_CHANGED: { + CSize size((DWORD)evParam1); + TRACE(_T("\t%ldx%ld\n"), size.cx, size.cy); + const bool bWasAudioOnly = m_fAudioOnly; + m_fAudioOnly = (size.cx <= 0 || size.cy <= 0); + OnVideoSizeChanged(bWasAudioOnly); + } + break; + case EC_LENGTH_CHANGED: { + REFERENCE_TIME rtDur = 0; + m_pMS->GetDuration(&rtDur); + m_wndPlaylistBar.SetCurTime(rtDur); + OnTimer(TIMER_STREAMPOSPOLLER); + OnTimer(TIMER_STREAMPOSPOLLER2); + LoadKeyFrames(); + if (GetPlaybackMode() == PM_FILE) { + SetupChapters(); + } else if (GetPlaybackMode() == PM_DVD) { + SetupDVDChapters(); + } + } + break; + case EC_BG_AUDIO_CHANGED: + if (m_fCustomGraph) { + int nAudioChannels = (int)evParam1; + + m_wndStatusBar.SetStatusBitmap(nAudioChannels == 1 ? IDB_AUDIOTYPE_MONO + : nAudioChannels >= 2 ? IDB_AUDIOTYPE_STEREO + : IDB_AUDIOTYPE_NOAUDIO); + } + break; + case EC_BG_ERROR: + if (m_fCustomGraph) { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + m_closingmsg = !str.IsEmpty() ? str : CString(_T("Unspecified graph error")); + m_wndPlaylistBar.SetCurValid(false); + return hr; + } + break; + case EC_DVD_PLAYBACK_RATE_CHANGE: + if (m_fCustomGraph && s.autoChangeFSMode.bEnabled && + (IsFullScreenMode()) && m_iDVDDomain == DVD_DOMAIN_Title) { + AutoChangeMonitorMode(); + } + break; + case EC_CLOCK_CHANGED: + if (m_pBA && !m_fFrameSteppingActive) { + m_pBA->put_Volume(m_wndToolBar.Volume); + } + break; + case 0xfa17: + // madVR changed graph state + UpdateCachedMediaState(); + break; + case EC_DVD_STILL_ON: + m_bDVDStillOn = true; + break; + case EC_DVD_STILL_OFF: + m_bDVDStillOn = false; + break; + case EC_DVD_BUTTON_CHANGE: + case EC_DVD_SUBPICTURE_STREAM_CHANGE: + case EC_DVD_AUDIO_STREAM_CHANGE: + case EC_DVD_ANGLE_CHANGE: + case EC_DVD_VALID_UOPS_CHANGE: + case EC_DVD_CHAPTER_START: + // no action required + break; + default: + UpdateCachedMediaState(); + TRACE(_T("Unhandled graph event\n")); + } + } + + return hr; +} + +LRESULT CMainFrame::OnResetDevice(WPARAM wParam, LPARAM lParam) +{ + m_OSD.HideMessage(true); + + OAFilterState fs = GetMediaState(); + if (fs == State_Running) { + if (!IsPlaybackCaptureMode()) { + MediaControlPause(true); + } else { + MediaControlStop(true); // Capture mode doesn't support pause + } + } + + if (m_bOpenedThroughThread) { + CAMMsgEvent e; + m_pGraphThread->PostThreadMessage(CGraphThread::TM_RESET, (WPARAM)0, (LPARAM)&e); + e.WaitMsg(); + } else { + ResetDevice(); + } + + if (fs == State_Running && m_pMC) { + MediaControlRun(); + + // When restarting DVB capture, we need to set again the channel. + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + SetChannel(AfxGetAppSettings().nDVBLastChannel); + } + } + } + + if (m_OSD.CanShowMessage()) { + m_OSD.HideMessage(false); + } + + return S_OK; +} + +LRESULT CMainFrame::OnRepaintRenderLess(WPARAM wParam, LPARAM lParam) +{ + MoveVideoWindow(); + return TRUE; +} + +void CMainFrame::SaveAppSettings() +{ + MSG msg; + if (!PeekMessage(&msg, m_hWnd, WM_SAVESETTINGS, WM_SAVESETTINGS, PM_NOREMOVE | PM_NOYIELD)) { + AfxGetAppSettings().SaveSettings(); + } +} + +LRESULT CMainFrame::OnNcHitTest(CPoint point) +{ + LRESULT nHitTest = __super::OnNcHitTest(point); + return ((IsCaptionHidden()) && nHitTest == HTCLIENT) ? HTCAPTION : nHitTest; +} + +void CMainFrame::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + // pScrollBar is null when making horizontal scroll with pen tablet + if (!pScrollBar) return; + + if (pScrollBar->IsKindOf(RUNTIME_CLASS(CVolumeCtrl))) { + OnPlayVolume(0); + } else if (pScrollBar->IsKindOf(RUNTIME_CLASS(CPlayerSeekBar)) && GetLoadState() == MLS::LOADED) { + SeekTo(m_wndSeekBar.GetPos()); + } else if (*pScrollBar == *m_pVideoWnd) { + SeekTo(m_OSD.GetPos()); + } + + __super::OnHScroll(nSBCode, nPos, pScrollBar); +} + +void CMainFrame::RestoreFocus() { + CWnd* curFocus = GetFocus(); + if (curFocus && curFocus != this) { + SetFocus(); + } +} + +void CMainFrame::OnInitMenu(CMenu* pMenu) +{ + __super::OnInitMenu(pMenu); + RestoreFocus(); + + const UINT uiMenuCount = pMenu->GetMenuItemCount(); + if (uiMenuCount == -1) { + return; + } + + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + + for (UINT i = 0; i < uiMenuCount; ++i) { +#ifdef _DEBUG + CString str; + pMenu->GetMenuString(i, str, MF_BYPOSITION); + str.Remove('&'); +#endif + UINT itemID = pMenu->GetMenuItemID(i); + if (itemID == 0xFFFFFFFF) { + mii.fMask = MIIM_ID; + pMenu->GetMenuItemInfo(i, &mii, TRUE); + itemID = mii.wID; + } + + CMPCThemeMenu* pSubMenu = nullptr; + + if (itemID == ID_FAVORITES) { + SetupFavoritesSubMenu(); + pSubMenu = &m_favoritesMenu; + }/*else if (itemID == ID_RECENT_FILES) { + SetupRecentFilesSubMenu(); + pSubMenu = &m_recentFilesMenu; + }*/ + + if (pSubMenu) { + mii.fMask = MIIM_STATE | MIIM_SUBMENU; + mii.fState = (pSubMenu->GetMenuItemCount()) > 0 ? MFS_ENABLED : MFS_DISABLED; + mii.hSubMenu = *pSubMenu; + VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pMenu, i, &mii, TRUE)); + pSubMenu->fulfillThemeReqs(); + } + } +} + +void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) { + __super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu); + + if (bSysMenu) { + m_pActiveSystemMenu = pPopupMenu; + m_eventc.FireEvent(MpcEvent::SYSTEM_MENU_POPUP_INITIALIZED); + return; + } + + UINT uiMenuCount = pPopupMenu->GetMenuItemCount(); + if (uiMenuCount == -1) { + return; + } + + MENUITEMINFO mii; + mii.cbSize = sizeof(mii); + + for (UINT i = 0; i < uiMenuCount; ++i) { +#ifdef _DEBUG + CString str; + pPopupMenu->GetMenuString(i, str, MF_BYPOSITION); + str.Remove('&'); +#endif + UINT firstSubItemID = 0; + CMenu* sm = pPopupMenu->GetSubMenu(i); + if (sm) { + firstSubItemID = sm->GetMenuItemID(0); + } + + if (firstSubItemID == ID_NAVIGATE_SKIPBACK) { // is "Navigate" submenu { + UINT fState = (GetLoadState() == MLS::LOADED + && (1/*GetPlaybackMode() == PM_DVD *//*|| (GetPlaybackMode() == PM_FILE && !m_PlayList.IsEmpty())*/)) + ? MF_ENABLED + : MF_GRAYED; + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + if (firstSubItemID == ID_VIEW_VF_HALF // is "Video Frame" submenu + || firstSubItemID == ID_VIEW_INCSIZE // is "Pan&Scan" submenu + || firstSubItemID == ID_ASPECTRATIO_START // is "Override Aspect Ratio" submenu + || firstSubItemID == ID_VIEW_ZOOM_25) { // is "Zoom" submenu + UINT fState = (GetLoadState() == MLS::LOADED && !m_fAudioOnly) + ? MF_ENABLED + : MF_GRAYED; + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + + // "File -> Subtitles" submenu + if (firstSubItemID == ID_FILE_SUBTITLES_LOAD) { + UINT fState = (GetLoadState() == MLS::LOADED && !m_fAudioOnly && m_pCAP) + ? MF_ENABLED + : MF_GRAYED; + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + + // renderer settings + if (firstSubItemID == ID_VIEW_TEARING_TEST) { + UINT fState = MF_GRAYED; + const CAppSettings& s = AfxGetAppSettings(); + if (s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC || s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS) { + fState = MF_ENABLED; + } + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + + UINT itemID = pPopupMenu->GetMenuItemID(i); + if (itemID == 0xFFFFFFFF) { + mii.fMask = MIIM_ID; + VERIFY(pPopupMenu->GetMenuItemInfo(i, &mii, TRUE)); + itemID = mii.wID; + } + CMPCThemeMenu* pSubMenu = nullptr; + + // debug shaders + if (itemID == ID_VIEW_DEBUGSHADERS) { + UINT fState = MF_GRAYED; + if (GetLoadState() == MLS::LOADED && !m_fAudioOnly && m_pCAP2) { + fState = MF_ENABLED; + } + pPopupMenu->EnableMenuItem(i, MF_BYPOSITION | fState); + continue; + } + + if (itemID == ID_FILE_OPENDISC) { + SetupOpenCDSubMenu(); + pSubMenu = &m_openCDsMenu; + } else if (itemID == ID_FILTERS) { + SetupFiltersSubMenu(); + pSubMenu = &m_filtersMenu; + } else if (itemID == ID_AUDIOS) { + SetupAudioSubMenu(); + pSubMenu = &m_audiosMenu; + } else if (itemID == ID_SUBTITLES) { + SetupSubtitlesSubMenu(); + pSubMenu = &m_subtitlesMenu; + } else if (itemID == ID_VIDEO_STREAMS) { + CString menuStr; + menuStr.LoadString(GetPlaybackMode() == PM_DVD ? IDS_MENU_VIDEO_ANGLE : IDS_MENU_VIDEO_STREAM); + + mii.fMask = MIIM_STRING; + mii.dwTypeData = (LPTSTR)(LPCTSTR)menuStr; + VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pPopupMenu, i, &mii, TRUE)); + + SetupVideoStreamsSubMenu(); + pSubMenu = &m_videoStreamsMenu; + } else if (itemID == ID_NAVIGATE_GOTO) { + // ID_NAVIGATE_GOTO is just a marker we use to insert the appropriate submenus + SetupJumpToSubMenus(pPopupMenu, i + 1); + uiMenuCount = pPopupMenu->GetMenuItemCount(); //SetupJumpToSubMenus could actually reduce the menu count! + } else if (itemID == ID_FAVORITES) { + SetupFavoritesSubMenu(); + pSubMenu = &m_favoritesMenu; + } else if (itemID == ID_RECENT_FILES) { + SetupRecentFilesSubMenu(); + pSubMenu = &m_recentFilesMenu; + } else if (itemID == ID_SHADERS) { + if (SetupShadersSubMenu()) { + pPopupMenu->EnableMenuItem(ID_SHADERS, MF_BYPOSITION | MF_ENABLED); + } else { + pPopupMenu->EnableMenuItem(ID_SHADERS, MF_BYPOSITION | MF_GRAYED); + } + pSubMenu = &m_shadersMenu; + } + + if (pSubMenu) { + mii.fMask = MIIM_STATE | MIIM_SUBMENU; + mii.fState = (pSubMenu->GetMenuItemCount() > 0) ? MF_ENABLED : MF_GRAYED; + mii.hSubMenu = *pSubMenu; + VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pPopupMenu, i, &mii, TRUE)); + pSubMenu->fulfillThemeReqs(); + } + } + + uiMenuCount = pPopupMenu->GetMenuItemCount(); + if (uiMenuCount == -1) { + return; + } + + if (!AppIsThemeLoaded()) { //themed menus draw accelerators already, no need to append + for (UINT i = 0; i < uiMenuCount; ++i) { + UINT nID = pPopupMenu->GetMenuItemID(i); + if (nID == ID_SEPARATOR || nID == -1 + || nID >= ID_FAVORITES_FILE_START && nID <= ID_FAVORITES_FILE_END + || nID >= ID_RECENT_FILE_START && nID <= ID_RECENT_FILE_END + || nID >= ID_SUBTITLES_SUBITEM_START && nID <= ID_SUBTITLES_SUBITEM_END + || nID >= ID_NAVIGATE_JUMPTO_SUBITEM_START && nID <= ID_NAVIGATE_JUMPTO_SUBITEM_END) { + continue; + } + + CString str; + pPopupMenu->GetMenuString(i, str, MF_BYPOSITION); + int k = str.Find('\t'); + if (k > 0) { + str = str.Left(k); + } + + CString key = CPPageAccelTbl::MakeAccelShortcutLabel(nID); + if (key.IsEmpty() && k < 0) { + continue; + } + str += _T("\t") + key; + + // BUG(?): this disables menu item update ui calls for some reason... + //pPopupMenu->ModifyMenu(i, MF_BYPOSITION|MF_STRING, nID, str); + + // this works fine + mii.fMask = MIIM_STRING; + mii.dwTypeData = (LPTSTR)(LPCTSTR)str; + VERIFY(pPopupMenu->SetMenuItemInfo(i, &mii, TRUE)); + } + } + + uiMenuCount = pPopupMenu->GetMenuItemCount(); + if (uiMenuCount == -1) { + return; + } + + bool fPnSPresets = false; + + for (UINT i = 0; i < uiMenuCount; ++i) { + UINT nID = pPopupMenu->GetMenuItemID(i); + + if (nID >= ID_PANNSCAN_PRESETS_START && nID < ID_PANNSCAN_PRESETS_END) { + do { + nID = pPopupMenu->GetMenuItemID(i); + VERIFY(pPopupMenu->DeleteMenu(i, MF_BYPOSITION)); + uiMenuCount--; + } while (i < uiMenuCount && nID >= ID_PANNSCAN_PRESETS_START && nID < ID_PANNSCAN_PRESETS_END); + + nID = pPopupMenu->GetMenuItemID(i); + } + + if (nID == ID_VIEW_RESET) { + fPnSPresets = true; + } + } + + if (fPnSPresets) { + bool usetheme = AppIsThemeLoaded(); + const CAppSettings& s = AfxGetAppSettings(); + INT_PTR i = 0, j = s.m_pnspresets.GetCount(); + for (; i < j; i++) { + int k = 0; + CString label = s.m_pnspresets[i].Tokenize(_T(","), k); + VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND, ID_PANNSCAN_PRESETS_START + i, label)); + CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, (UINT)(ID_PANNSCAN_PRESETS_START + i), true); + } + //if (j > 0) + { + VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND, ID_PANNSCAN_PRESETS_START + i, ResStr(IDS_PANSCAN_EDIT))); + VERIFY(pPopupMenu->InsertMenu(ID_VIEW_RESET, MF_BYCOMMAND | MF_SEPARATOR)); + if (usetheme) { + CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, (UINT)(ID_PANNSCAN_PRESETS_START + i), true); + UINT pos = CMPCThemeMenu::getPosFromID(pPopupMenu, ID_VIEW_RESET); //separator is inserted right before view_reset + CMPCThemeMenu::fulfillThemeReqsItem(pPopupMenu, pos - 1); + } + } + } + + if (m_pActiveContextMenu == pPopupMenu) { + m_eventc.FireEvent(MpcEvent::CONTEXT_MENU_POPUP_INITIALIZED); + } +} + +void CMainFrame::OnUnInitMenuPopup(CMenu* pPopupMenu, UINT nFlags) +{ + __super::OnUnInitMenuPopup(pPopupMenu, nFlags); + if (m_pActiveContextMenu == pPopupMenu) { + m_pActiveContextMenu = nullptr; + m_eventc.FireEvent(MpcEvent::CONTEXT_MENU_POPUP_UNINITIALIZED); + } else if (m_pActiveSystemMenu == pPopupMenu) { + m_pActiveSystemMenu = nullptr; + SendMessage(WM_CANCELMODE); // unfocus main menu if system menu was entered with alt+space + m_eventc.FireEvent(MpcEvent::SYSTEM_MENU_POPUP_UNINITIALIZED); + } +} + +void CMainFrame::OnEnterMenuLoop(BOOL bIsTrackPopupMenu) +{ + if (!bIsTrackPopupMenu && !m_pActiveSystemMenu && GetMenuBarState() == AFX_MBS_HIDDEN) { + // mfc has problems synchronizing menu visibility with modal loop in certain situations + ASSERT(!m_pActiveContextMenu); + VERIFY(SetMenuBarState(AFX_MBS_VISIBLE)); + } + __super::OnEnterMenuLoop(bIsTrackPopupMenu); +} + +BOOL CMainFrame::OnQueryEndSession() +{ + return TRUE; +} + +void CMainFrame::OnEndSession(BOOL bEnding) +{ + // do nothing for now +} + +BOOL CMainFrame::OnMenu(CMenu* pMenu) +{ + if (!pMenu) { + return FALSE; + } + + CPoint point; + GetCursorPos(&point); + + // Do not show popup menu in D3D fullscreen it has several adverse effects. + if (IsD3DFullScreenMode()) { + CWnd* pWnd = WindowFromPoint(point); + if (pWnd && *pWnd == *m_pDedicatedFSVideoWnd) { + return FALSE; + } + } + + if (AfxGetMyApp()->m_fClosingState) { + return FALSE; //prevent crash when player closes with context menu open + } + + m_pActiveContextMenu = pMenu; + + pMenu->TrackPopupMenu(TPM_RIGHTBUTTON | TPM_NOANIMATION, point.x, point.y, this); + + return TRUE; +} + +void CMainFrame::OnMenuPlayerShort() +{ + if (!AfxGetAppSettings().bAlwaysUseShortMenu && (IsMenuHidden() || IsD3DFullScreenMode())) { + OnMenu(m_mainPopupMenu.GetSubMenu(0)); + } else { + OnMenu(m_popupMenu.GetSubMenu(0)); + } +} + +void CMainFrame::OnMenuPlayerLong() +{ + OnMenu(m_mainPopupMenu.GetSubMenu(0)); +} + +void CMainFrame::OnMenuFilters() +{ + SetupFiltersSubMenu(); + OnMenu(&m_filtersMenu); +} + +void CMainFrame::OnUpdatePlayerStatus(CCmdUI* pCmdUI) +{ + if (GetLoadState() == MLS::LOADING) { + m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_OPENING)); + if (AfxGetAppSettings().bUseEnhancedTaskBar && m_pTaskbarList) { + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_INDETERMINATE); + } + } else if (GetLoadState() == MLS::LOADED) { + if (!m_tempstatus_msg.IsEmpty()) { + m_wndStatusBar.SetStatusMessage(m_tempstatus_msg); + return; + } + CString msg; + if (m_fCapturing) { + msg.LoadString(IDS_CONTROLS_CAPTURING); + + if (m_pAMDF) { + long lDropped = 0; + m_pAMDF->GetNumDropped(&lDropped); + long lNotDropped = 0; + m_pAMDF->GetNumNotDropped(&lNotDropped); + + if ((lDropped + lNotDropped) > 0) { + msg.AppendFormat(IDS_MAINFRM_37, lDropped + lNotDropped, lDropped); + } + } + + CComPtr pPin; + if (m_pCGB && SUCCEEDED(m_pCGB->FindPin(m_wndCaptureBar.m_capdlg.m_pDst, PINDIR_INPUT, nullptr, nullptr, FALSE, 0, &pPin))) { + LONGLONG size = 0; + if (CComQIPtr pStream = pPin) { + pStream->Commit(STGC_DEFAULT); + + WIN32_FIND_DATA findFileData; + HANDLE h = FindFirstFile(m_wndCaptureBar.m_capdlg.m_file, &findFileData); + if (h != INVALID_HANDLE_VALUE) { + size = ((LONGLONG)findFileData.nFileSizeHigh << 32) | findFileData.nFileSizeLow; + + if (size < 1024i64 * 1024) { + msg.AppendFormat(IDS_MAINFRM_38, size / 1024); + } else { //if (size < 1024i64*1024*1024) + msg.AppendFormat(IDS_MAINFRM_39, size / 1024 / 1024); + } + + FindClose(h); + } + } + + ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes, TotalNumberOfFreeBytes; + if (GetDiskFreeSpaceEx( + m_wndCaptureBar.m_capdlg.m_file.Left(m_wndCaptureBar.m_capdlg.m_file.ReverseFind('\\') + 1), + &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) { + if (FreeBytesAvailable.QuadPart < 1024i64 * 1024) { + msg.AppendFormat(IDS_MAINFRM_40, FreeBytesAvailable.QuadPart / 1024); + } else { //if (FreeBytesAvailable.QuadPart < 1024i64*1024*1024) + msg.AppendFormat(IDS_MAINFRM_41, FreeBytesAvailable.QuadPart / 1024 / 1024); + } + } + + if (m_wndCaptureBar.m_capdlg.m_pMux) { + __int64 pos = 0; + CComQIPtr pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux; + if (pMuxMS && SUCCEEDED(pMuxMS->GetCurrentPosition(&pos)) && pos > 0) { + double bytepersec = 10000000.0 * size / pos; + if (bytepersec > 0) { + m_rtDurationOverride = REFERENCE_TIME(10000000.0 * (FreeBytesAvailable.QuadPart + size) / bytepersec); + } + } + } + + if (m_wndCaptureBar.m_capdlg.m_pVidBuffer + || m_wndCaptureBar.m_capdlg.m_pAudBuffer) { + int nFreeVidBuffers = 0, nFreeAudBuffers = 0; + if (CComQIPtr pVB = m_wndCaptureBar.m_capdlg.m_pVidBuffer) { + nFreeVidBuffers = pVB->GetFreeBuffers(); + } + if (CComQIPtr pAB = m_wndCaptureBar.m_capdlg.m_pAudBuffer) { + nFreeAudBuffers = pAB->GetFreeBuffers(); + } + + msg.AppendFormat(IDS_MAINFRM_42, nFreeVidBuffers, nFreeAudBuffers); + } + } + } else if (m_bBuffering) { + if (m_pAMNS) { + long BufferingProgress = 0; + if (SUCCEEDED(m_pAMNS->get_BufferingProgress(&BufferingProgress)) && BufferingProgress > 0) { + msg.Format(IDS_CONTROLS_BUFFERING, BufferingProgress); + + __int64 start = 0, stop = 0; + m_wndSeekBar.GetRange(start, stop); + m_fLiveWM = (stop == start); + } + } + } else if (m_pAMOP) { + LONGLONG t = 0, c = 0; + if (SUCCEEDED(m_pAMOP->QueryProgress(&t, &c)) && t > 0 && c < t) { + msg.Format(IDS_CONTROLS_BUFFERING, c * 100 / t); + } else { + m_pAMOP.Release(); + } + } + + if (msg.IsEmpty()) { + int msg_id = 0; + switch (m_CachedFilterState) { + case State_Stopped: + msg_id = IDS_CONTROLS_STOPPED; + break; + case State_Paused: + msg_id = IDS_CONTROLS_PAUSED; + break; + case State_Running: + msg_id = IDS_CONTROLS_PLAYING; + break; + } + if (m_fFrameSteppingActive) { + msg_id = IDS_CONTROLS_PAUSED; + } + if (msg_id) { + msg.LoadString(msg_id); + + if (m_bUsingDXVA && (msg_id == IDS_CONTROLS_PAUSED || msg_id == IDS_CONTROLS_PLAYING)) { + msg.AppendFormat(_T(" %s"), ResStr(IDS_HW_INDICATOR).GetString()); + } + } + + auto& s = AfxGetAppSettings(); + + CString videoinfo; + CString fpsinfo; + CStringW audioinfo; + if (s.bShowVideoInfoInStatusbar && (!m_statusbarVideoFormat.IsEmpty() || !m_statusbarVideoSize.IsEmpty())) { + if(!m_statusbarVideoFormat.IsEmpty()) { + videoinfo.Append(m_statusbarVideoFormat); + } + if(!m_statusbarVideoSize.IsEmpty()) { + if(!m_statusbarVideoFormat.IsEmpty()) { + videoinfo.AppendChar(_T(' ')); + } + videoinfo.Append(m_statusbarVideoSize); + } + } + if (s.bShowFPSInStatusbar && m_pCAP) { + if (m_dSpeedRate != 1.0) { + fpsinfo.Format(_T("%.2lf fps (%.2lfx)"), m_pCAP->GetFPS(), m_dSpeedRate); + } else { + fpsinfo.Format(_T("%.2lf fps"), m_pCAP->GetFPS()); + } + } + + if (s.bShowAudioFormatInStatusbar && !m_statusbarAudioFormat.IsEmpty()) { + audioinfo = m_statusbarAudioFormat; + } + + if (!videoinfo.IsEmpty() || !fpsinfo.IsEmpty()) { + CStringW tinfo = L""; + AppendWithDelimiter(tinfo, videoinfo); + AppendWithDelimiter(tinfo, fpsinfo); + msg.Append(L"\u2001[" + tinfo + L"]"); + } + + if (!audioinfo.IsEmpty()) { + msg.Append(L"\u2001[" + audioinfo); + if (s.bShowLangInStatusbar && !currentAudioLang.IsEmpty()) { + msg.Append(L" " + currentAudioLang); + } + msg.Append(L"]"); + } + + if (s.bShowLangInStatusbar) { + bool showaudiolang = audioinfo.IsEmpty() && !currentAudioLang.IsEmpty(); + if (showaudiolang || !currentSubLang.IsEmpty()) { + msg.Append(_T("\u2001[")); + if (showaudiolang) { + msg.Append(L"AUD: " + currentAudioLang); + } + if (!currentSubLang.IsEmpty()) { + if (showaudiolang) { + msg.Append(_T(", ")); + } + msg.Append(L"SUB: " + currentSubLang); + } + msg.Append(_T("]")); + } + } + if (s.bShowABMarksInStatusbar) { + if (abRepeat) { + REFERENCE_TIME actualB = abRepeat.positionB; + if (actualB == 0) { + REFERENCE_TIME start = 0; + m_wndSeekBar.GetRange(start, actualB); + } + bool showhours = (actualB >= 35995000000) || (abRepeat.positionA >= 35995000000); + CString timeMarkA = showhours ? ReftimeToString2(abRepeat.positionA) : ReftimeToString3(abRepeat.positionA); + CString timeMarkB = showhours ? ReftimeToString2(actualB) : ReftimeToString3(actualB); + msg.AppendFormat(_T("\u2001[A-B %s > %s]"), timeMarkA.GetString(), timeMarkB.GetString()); + } + } + } + + m_wndStatusBar.SetStatusMessage(msg); + } else if (GetLoadState() == MLS::CLOSING) { + m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_CLOSING)); + if (AfxGetAppSettings().bUseEnhancedTaskBar && m_pTaskbarList) { + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_INDETERMINATE); + } + } else { + m_wndStatusBar.SetStatusMessage(m_closingmsg); + } +} + +LRESULT CMainFrame::OnFilePostOpenmedia(WPARAM wParam, LPARAM lParam) +{ + if (!m_pGB) { + ASSERT(FALSE); + return 1; + } + ASSERT(GetLoadState() == MLS::LOADING); + + auto& s = AfxGetAppSettings(); + + // from this on + m_bOpenMediaActive = false; + m_OpenMediaFailedCount = 0; + m_bSettingUpMenus = true; + + SetLoadState(MLS::LOADED); + ASSERT(GetMediaStateDirect() == State_Stopped); + + // destroy invisible top-level d3dfs window if there is no video renderer + if (HasDedicatedFSVideoWindow() && !m_pMFVDC && !m_pVMRWC && !m_pVW) { + m_pDedicatedFSVideoWnd->DestroyWindow(); + if (s.IsD3DFullscreen()) { + m_fStartInD3DFullscreen = true; + } else { + m_fStartInFullscreenSeparate = true; + } + } + + // auto-change monitor mode if requested + if (s.autoChangeFSMode.bEnabled && IsFullScreenMode()) { + AutoChangeMonitorMode(); + // make sure the fullscreen window is positioned properly after the mode change, + // OnWindowPosChanging() will take care of that + if (m_bOpeningInAutochangedMonitorMode && m_fFullScreen) { + CRect rect; + GetWindowRect(rect); + MoveWindow(rect); + } + } + + // set shader selection + if (m_pCAP || m_pCAP2) { + SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); + } + + // load keyframes for fast-seek + if (wParam == PM_FILE) { + LoadKeyFrames(); + } + + // remember OpenMediaData for later use + m_lastOMD.Free(); + m_lastOMD.Attach((OpenMediaData*)lParam); + if (!m_lastOMD->title) { + ASSERT(false); + m_lastOMD->title = L""; + } + + // the media opened successfully, we don't want to jump trough it anymore + UINT lastSkipDirection = m_nLastSkipDirection; + m_nLastSkipDirection = 0; + + // let the EDL do its magic + if (s.fEnableEDLEditor && !m_lastOMD->title.IsEmpty()) { + m_wndEditListEditor.OpenFile(m_lastOMD->title); + } + + // initiate Capture panel with the new media + if (auto pDeviceData = dynamic_cast(m_lastOMD.m_p)) { + m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput); + m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel); + m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput); + } + + // current playlist item was loaded successfully + m_wndPlaylistBar.SetCurValid(true); + + // set item duration in the playlist + // TODO: GetDuration() should be refactored out of this place, to some aggregating class + REFERENCE_TIME rtDur = 0; + if (m_pMS && m_pMS->GetDuration(&rtDur) == S_OK) { + m_wndPlaylistBar.SetCurTime(rtDur); + } + + // process /pns command-line arg, then discard it + ApplyPanNScanPresetString(); + + // initiate toolbars with the new media + OpenSetupInfoBar(); + OpenSetupStatsBar(); + OpenSetupStatusBar(); + OpenSetupCaptureBar(); + + // Load cover-art + if (m_fAudioOnly || HasDedicatedFSVideoWindow()) { + UpdateControlState(CMainFrame::UPDATE_LOGO); + } + + if (s.bOpenRecPanelWhenOpeningDevice) { + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + // show navigation panel when it's available and not disabled + if (!s.fHideNavigation) { + m_wndNavigationBar.m_navdlg.UpdateElementList(); + if (!m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); + } + else { + ASSERT(FALSE); + } + } + } + else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + // show capture bar + if (!m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)) { + m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); + } + else { + ASSERT(FALSE); + } + } + } + + // we don't want to wait until timers initialize the seekbar and the time counter + OnTimer(TIMER_STREAMPOSPOLLER); + OnTimer(TIMER_STREAMPOSPOLLER2); + + if (m_AngleX != 0 || m_AngleY != 0 || m_AngleZ != 0) { + PerformFlipRotate(); + } + + bool go_fullscreen = s.fLaunchfullscreen && !m_fAudioOnly && !IsFullScreenMode() && lastSkipDirection == 0 && !(s.nCLSwitches & CLSW_THUMBNAILS); + + // auto-zoom if requested + if (IsWindowVisible() && s.fRememberZoomLevel && !IsFullScreenMode() && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { + if (go_fullscreen) { + m_bNeedZoomAfterFullscreenExit = true; + } + ZoomVideoWindow(ZOOM_DEFAULT_LEVEL, go_fullscreen); + } + + if (go_fullscreen) { + OnViewFullscreen(); + } + + // Add temporary flag to allow EC_VIDEO_SIZE_CHANGED event to stabilize window size + // for 5 seconds since playback starts + m_bAllowWindowZoom = true; + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::AUTOFIT_TIMEOUT, [this] + { m_bAllowWindowZoom = false; }, 5000); + + // update control bar areas and paint bypassing the message queue + RecalcLayout(); + UpdateWindow(); + + // the window is repositioned and repainted, video renderer rect is ready to be set - + // OnPlayPlay()/OnPlayPause() will take care of that + m_bDelaySetOutputRect = false; + + if (s.nCLSwitches & CLSW_THUMBNAILS) { + MoveVideoWindow(false, true); + MediaControlPause(true); + SendMessageW(WM_COMMAND, ID_CMDLINE_SAVE_THUMBNAILS); + m_bSettingUpMenus = false; + m_bRememberFilePos = false; + SendMessageW(WM_COMMAND, ID_FILE_EXIT); + return 0; + } + + MediaTransportControlSetMedia(); + + // start playback if requested + m_bFirstPlay = true; + const auto uModeChangeDelay = s.autoChangeFSMode.uDelay * 1000; + if (!(s.nCLSwitches & CLSW_OPEN) && (s.nLoops > 0)) { + if (m_bOpeningInAutochangedMonitorMode && uModeChangeDelay) { + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, + std::bind(&CMainFrame::OnPlayPlay, this), uModeChangeDelay); + } else { + OnPlayPlay(); + } + } else { + // OnUpdatePlayPauseStop() will decide if we can pause the media + if (m_bOpeningInAutochangedMonitorMode && uModeChangeDelay) { + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, + [this] { OnCommand(ID_PLAY_PAUSE, 0); }, uModeChangeDelay); + } else { + OnCommand(ID_PLAY_PAUSE, 0); + } + } + s.nCLSwitches &= ~CLSW_OPEN; + + // Ensure the dynamically added menu items are updated + SetupFiltersSubMenu(); + SetupAudioSubMenu(); + SetupSubtitlesSubMenu(); + SetupVideoStreamsSubMenu(); + SetupJumpToSubMenus(); + SetupRecentFilesSubMenu(); + + // notify listeners + if (GetPlaybackMode() != PM_DIGITAL_CAPTURE) { + SendNowPlayingToSkype(); + SendNowPlayingToApi(); + } + + if (CanPreviewUse() && m_wndSeekBar.IsVisible()) { + CPoint point; + GetCursorPos(&point); + + CRect rect; + m_wndSeekBar.GetWindowRect(&rect); + if (rect.PtInRect(point)) { + m_wndSeekBar.PreviewWindowShow(point); + } + } + + m_bSettingUpMenus = false; + + return 0; +} + +LRESULT CMainFrame::OnOpenMediaFailed(WPARAM wParam, LPARAM lParam) +{ + ASSERT(GetLoadState() == MLS::LOADING); + SetLoadState(MLS::FAILING); + + ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); + const auto& s = AfxGetAppSettings(); + + m_lastOMD.Free(); + m_lastOMD.Attach((OpenMediaData*)lParam); + if (!m_lastOMD->title) { + ASSERT(false); + m_lastOMD->title = L""; + } + + bool bOpenNextInPlaylist = false; + bool bAfterPlaybackEvent = false; + + m_bOpenMediaActive = false; + m_OpenMediaFailedCount++; + + m_dwReloadPos = 0; + reloadABRepeat = ABRepeat(); + m_iReloadAudioIdx = -1; + m_iReloadSubIdx = -1; + + if (wParam == PM_FILE && m_OpenMediaFailedCount < 5) { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli) && pli.m_bYoutubeDL && m_sydlLastProcessURL != pli.m_ydlSourceURL) { + OpenCurPlaylistItem(0, true); // Try to reprocess if failed first time. + return 0; + } + if (m_wndPlaylistBar.GetCount() == 1) { + if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { + bOpenNextInPlaylist = SearchInDir(false, s.bLoopFolderOnPlayNextFile); + if (!bOpenNextInPlaylist) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_FIRST_IN_FOLDER)); + } + } else if (m_nLastSkipDirection == ID_NAVIGATE_SKIPFORWARD) { + bOpenNextInPlaylist = SearchInDir(true, s.bLoopFolderOnPlayNextFile); + if (!bOpenNextInPlaylist) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_LAST_IN_FOLDER)); + } + } + } else { + m_wndPlaylistBar.SetCurValid(false); + + if (m_wndPlaylistBar.IsAtEnd()) { + m_nLoops++; + } + + if (s.fLoopForever || m_nLoops < s.nLoops) { + if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { + bOpenNextInPlaylist = m_wndPlaylistBar.SetPrev(); + } else { + bOpenNextInPlaylist = m_wndPlaylistBar.SetNext(); + } + } else { + bAfterPlaybackEvent = true; + } + } + } + + CloseMedia(bOpenNextInPlaylist); + + if (m_OpenMediaFailedCount >= 5) { + m_wndPlaylistBar.SetCurValid(false); + if (m_wndPlaylistBar.IsAtEnd()) { + m_nLoops++; + } + if (s.fLoopForever || m_nLoops < s.nLoops) { + if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) { + m_wndPlaylistBar.SetPrev(); + } else { + m_wndPlaylistBar.SetNext(); + } + } + m_OpenMediaFailedCount = 0; + } + else if (bOpenNextInPlaylist) { + OpenCurPlaylistItem(); + } + else if (bAfterPlaybackEvent) { + DoAfterPlaybackEvent(); + } + + return 0; +} + +void CMainFrame::OnFilePostClosemedia(bool bNextIsQueued/* = false*/) +{ + SetPlaybackMode(PM_NONE); + SetLoadState(MLS::CLOSED); + + m_bOpenMediaActive = false; + + abRepeat = ABRepeat(); + m_kfs.clear(); + + m_nCurSubtitle = -1; + m_lSubtitleShift = 0; + + CAppSettings& s = AfxGetAppSettings(); + if (!s.fSavePnSZoom) { + m_AngleX = m_AngleY = m_AngleZ = 0; + m_ZoomX = m_ZoomY = 1.0; + m_PosX = m_PosY = 0.5; + } + + if (m_closingmsg.IsEmpty()) { + m_closingmsg.LoadString(IDS_CONTROLS_CLOSED); + } + + m_wndView.SetVideoRect(); + m_wndSeekBar.Enable(false); + m_wndSeekBar.SetRange(0, 0); + m_wndSeekBar.SetPos(0); + m_wndSeekBar.RemoveChapters(); + m_wndInfoBar.RemoveAllLines(); + m_wndStatsBar.RemoveAllLines(); + m_wndStatusBar.Clear(); + m_wndStatusBar.ShowTimer(false); + currentAudioLang.Empty(); + currentSubLang.Empty(); + m_OSD.SetRange(0); + m_OSD.SetPos(0); + m_Lcd.SetMediaRange(0, 0); + m_Lcd.SetMediaPos(0); + m_statusbarVideoFormat.Empty(); + m_statusbarVideoSize.Empty(); + + m_VidDispName.Empty(); + m_AudDispName.Empty(); + m_HWAccelType = L""; + + if (!bNextIsQueued) { + UpdateControlState(CMainFrame::UPDATE_LOGO); + RecalcLayout(); + } + + if (s.fEnableEDLEditor) { + m_wndEditListEditor.CloseFile(); + } + + if (m_controls.ControlChecked(CMainFrameControls::Panel::SUBRESYNC)) { + m_controls.ToggleControl(CMainFrameControls::Panel::SUBRESYNC); + } + + if (m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)) { + m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); + } + m_wndCaptureBar.m_capdlg.SetupVideoControls(_T(""), nullptr, nullptr, nullptr); + m_wndCaptureBar.m_capdlg.SetupAudioControls(_T(""), nullptr, CInterfaceArray()); + + if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); + } + + if (!bNextIsQueued) { + OpenSetupWindowTitle(true); + } + + SetAlwaysOnTop(s.iOnTop); + + SendNowPlayingToSkype(); + + // try to release external objects + UnloadUnusedExternalObjects(); + SetTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS, 60000, nullptr); + + if (HasDedicatedFSVideoWindow()) { + if (IsD3DFullScreenMode()) { + m_fStartInD3DFullscreen = true; + } else { + m_fStartInFullscreenSeparate = true; + } + if (!bNextIsQueued) { + m_pDedicatedFSVideoWnd->DestroyWindow(); + } + } + + UpdateWindow(); // redraw +} + +void CMainFrame::OnBossKey() +{ + // Disable animation + ANIMATIONINFO AnimationInfo; + AnimationInfo.cbSize = sizeof(ANIMATIONINFO); + ::SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + int m_WindowAnimationType = AnimationInfo.iMinAnimate; + AnimationInfo.iMinAnimate = 0; + ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + if (IsFullScreenMode()) { + SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN); + } + SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, -1); + + // Enable animation + AnimationInfo.iMinAnimate = m_WindowAnimationType; + ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); +} + +void CMainFrame::OnStreamAudio(UINT nID) +{ + nID -= ID_STREAM_AUDIO_NEXT; + + if (GetLoadState() != MLS::LOADED) { + return; + } + + DWORD cStreams = 0; + if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 1) { + for (DWORD i = 0; i < cStreams; i++) { + DWORD dwFlags = 0; + DWORD dwGroup = 0; + if (FAILED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { + return; + } + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + long stream_index = (i + (nID == 0 ? 1 : cStreams - 1)) % cStreams; + if (SUCCEEDED(m_pAudioSwitcherSS->Enable(stream_index, AMSTREAMSELECTENABLE_ENABLE))) { + LCID lcid = 0; + CComHeapPtr pszName; + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(m_pAudioSwitcherSS->Info(stream_index, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) { + m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pszName), lcid, 1)); + UpdateSelectedAudioStreamInfo(stream_index, pmt, lcid); + DeleteMediaType(pmt); + } + } + break; + } + } + } else if (GetPlaybackMode() == PM_FILE) { + OnStreamSelect(nID == 0, 1); + } else if (GetPlaybackMode() == PM_DVD) { + SendMessage(WM_COMMAND, ID_DVD_AUDIO_NEXT + nID); + } + + if (m_pBA && !m_fFrameSteppingActive) { + m_pBA->put_Volume(m_wndToolBar.Volume); + } +} + +void CMainFrame::OnStreamSub(UINT nID) +{ + nID -= ID_STREAM_SUB_NEXT; + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (!m_pSubStreams.IsEmpty()) { + AfxGetAppSettings().fEnableSubtitles = true; + SetSubtitle(nID == 0 ? 1 : -1, true, true); + SetFocus(); + } else if (GetPlaybackMode() == PM_FILE) { + OnStreamSelect(nID == 0, 2); + } else if (GetPlaybackMode() == PM_DVD) { + SendMessage(WM_COMMAND, ID_DVD_SUB_NEXT + nID); + } +} + +void CMainFrame::OnStreamSubOnOff() +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pCAP && !m_pSubStreams.IsEmpty() || m_pDVS) { + ToggleSubtitleOnOff(true); + SetFocus(); + } else if (GetPlaybackMode() == PM_DVD) { + SendMessage(WM_COMMAND, ID_DVD_SUB_ONOFF); + } +} + +void CMainFrame::OnDvdAngle(UINT nID) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pDVDI && m_pDVDC) { + ULONG ulAnglesAvailable, ulCurrentAngle; + if (SUCCEEDED(m_pDVDI->GetCurrentAngle(&ulAnglesAvailable, &ulCurrentAngle)) && ulAnglesAvailable > 1) { + ulCurrentAngle += (nID == ID_DVD_ANGLE_NEXT) ? 1 : -1; + if (ulCurrentAngle > ulAnglesAvailable) { + ulCurrentAngle = 1; + } else if (ulCurrentAngle < 1) { + ulCurrentAngle = ulAnglesAvailable; + } + m_pDVDC->SelectAngle(ulCurrentAngle, DVD_CMD_FLAG_Block, nullptr); + + CString osdMessage; + osdMessage.Format(IDS_AG_ANGLE, ulCurrentAngle); + m_OSD.DisplayMessage(OSD_TOPLEFT, osdMessage); + } + } +} + +void CMainFrame::OnDvdAudio(UINT nID) +{ + nID -= ID_DVD_AUDIO_NEXT; + + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pDVDI && m_pDVDC) { + ULONG nStreamsAvailable, nCurrentStream; + if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&nStreamsAvailable, &nCurrentStream)) && nStreamsAvailable > 1) { + DVD_AudioAttributes AATR; + UINT nNextStream = (nCurrentStream + (nID == 0 ? 1 : nStreamsAvailable - 1)) % nStreamsAvailable; + + HRESULT hr = m_pDVDC->SelectAudioStream(nNextStream, DVD_CMD_FLAG_Block, nullptr); + if (SUCCEEDED(m_pDVDI->GetAudioAttributes(nNextStream, &AATR))) { + CString lang; + CString strMessage; + if (AATR.Language) { + GetLocaleString(AATR.Language, LOCALE_SENGLANGUAGE, lang); + currentAudioLang = lang; + } else { + lang.Format(IDS_AG_UNKNOWN, nNextStream + 1); + currentAudioLang.Empty(); + } + + CString format = GetDVDAudioFormatName(AATR); + CString str; + + if (!format.IsEmpty()) { + str.Format(IDS_MAINFRM_11, + lang.GetString(), + format.GetString(), + AATR.dwFrequency, + AATR.bQuantization, + AATR.bNumberOfChannels, + ResStr(AATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString()); + if (FAILED(hr)) { + str += _T(" [") + ResStr(IDS_AG_ERROR) + _T("] "); + } + strMessage.Format(IDS_AUDIO_STREAM, str.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, strMessage); + } + } + } + } +} + +void CMainFrame::OnDvdSub(UINT nID) +{ + nID -= ID_DVD_SUB_NEXT; + + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pDVDI && m_pDVDC) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) + && ulStreamsAvailable > 1) { + //UINT nNextStream = (ulCurrentStream+(nID==0?1:ulStreamsAvailable-1))%ulStreamsAvailable; + int nNextStream; + + if (!bIsDisabled) { + nNextStream = ulCurrentStream + (nID == 0 ? 1 : -1); + } else { + nNextStream = (nID == 0 ? 0 : ulStreamsAvailable - 1); + } + + if (!bIsDisabled && ((nNextStream < 0) || ((ULONG)nNextStream >= ulStreamsAvailable))) { + m_pDVDC->SetSubpictureState(FALSE, DVD_CMD_FLAG_Block, nullptr); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_SUBTITLE_STREAM_OFF)); + } else { + HRESULT hr = m_pDVDC->SelectSubpictureStream(nNextStream, DVD_CMD_FLAG_Block, nullptr); + + DVD_SubpictureAttributes SATR; + m_pDVDC->SetSubpictureState(TRUE, DVD_CMD_FLAG_Block, nullptr); + if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(nNextStream, &SATR))) { + CString lang; + CString strMessage; + GetLocaleString(SATR.Language, LOCALE_SENGLANGUAGE, lang); + + if (FAILED(hr)) { + lang += _T(" [") + ResStr(IDS_AG_ERROR) + _T("] "); + } + strMessage.Format(IDS_SUBTITLE_STREAM, lang.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, strMessage); + } + } + } + } +} + +void CMainFrame::OnDvdSubOnOff() +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (m_pDVDI && m_pDVDC) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) { + m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); + } + } +} + +// +// menu item handlers +// + +// file + +INT_PTR CMainFrame::DoFileDialogWithLastFolder(CFileDialog& fd, CStringW& lastPath) { + if (!lastPath.IsEmpty()) { + fd.m_ofn.lpstrInitialDir = lastPath; + } + INT_PTR ret = fd.DoModal(); + if (ret == IDOK) { + lastPath = GetFolderOnly(fd.m_ofn.lpstrFile); + } + return ret; +} + + +void CMainFrame::OnFileOpenQuick() +{ + if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar)) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + CString filter; + CAtlArray mask; + s.m_Formats.GetFilter(filter, mask); + + DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_ALLOWMULTISELECT | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + if (!s.fKeepHistory) { + dwFlags |= OFN_DONTADDTORECENT; + } + + COpenFileDlg fd(mask, true, nullptr, nullptr, dwFlags, filter, GetModalParent()); + if (DoFileDialogWithLastFolder(fd, s.lastQuickOpenPath) != IDOK) { + return; + } + + CAtlList fns; + + POSITION pos = fd.GetStartPosition(); + while (pos) { + fns.AddTail(fd.GetNextPathName(pos)); + } + + bool fMultipleFiles = false; + + if (fns.GetCount() > 1 + || fns.GetCount() == 1 + && (fns.GetHead()[fns.GetHead().GetLength() - 1] == '\\' + || fns.GetHead()[fns.GetHead().GetLength() - 1] == '*')) { + fMultipleFiles = true; + } + + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + SetForegroundWindow(); + + if (fns.GetCount() == 1) { + if (OpenBD(fns.GetHead())) { + return; + } + } + + m_wndPlaylistBar.Open(fns, fMultipleFiles); + + OpenCurPlaylistItem(); +} + +void CMainFrame::OnFileOpenmedia() +{ + if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar) || IsD3DFullScreenMode()) { + return; + } + + static COpenDlg dlg; + if (IsWindow(dlg.GetSafeHwnd()) && dlg.IsWindowVisible()) { + dlg.SetForegroundWindow(); + return; + } + if (dlg.DoModal() != IDOK || dlg.GetFileNames().IsEmpty()) { + return; + } + + if (!dlg.GetAppendToPlaylist()) { + CloseMediaBeforeOpen(); + } + + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + SetForegroundWindow(); + + CAtlList filenames; + + if (CanSendToYoutubeDL(dlg.GetFileNames().GetHead())) { + if (ProcessYoutubeDLURL(dlg.GetFileNames().GetHead(), dlg.GetAppendToPlaylist())) { + if (!dlg.GetAppendToPlaylist()) { + OpenCurPlaylistItem(); + } + return; + } else if (IsOnYDLWhitelist(dlg.GetFileNames().GetHead())) { + // don't bother trying to open this website URL directly + return; + } + } + + filenames.AddHeadList(&dlg.GetFileNames()); + + if (!dlg.HasMultipleFiles()) { + if (OpenBD(filenames.GetHead())) { + return; + } + } + + if (dlg.GetAppendToPlaylist()) { + m_wndPlaylistBar.Append(filenames, dlg.HasMultipleFiles()); + } else { + m_wndPlaylistBar.Open(filenames, dlg.HasMultipleFiles()); + + OpenCurPlaylistItem(); + } +} + +LRESULT CMainFrame::OnMPCVRSwitchFullscreen(WPARAM wParam, LPARAM lParam) +{ + const auto& s = AfxGetAppSettings(); + m_bIsMPCVRExclusiveMode = static_cast(wParam); + + m_OSD.Stop(); + if (m_bIsMPCVRExclusiveMode) { + TRACE(L"MPCVR exclusive full screen\n"); + bool excl_mode_controls = IsFullScreenMainFrame(); + if (excl_mode_controls && m_wndPlaylistBar.IsVisible()) { + m_wndPlaylistBar.SetHiddenDueToFullscreen(true); + } + if (s.fShowOSD || s.fShowDebugInfo) { + if (m_pVMB || m_pMFVMB) { + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, excl_mode_controls); + } + } + } else { + if (s.fShowOSD || s.fShowDebugInfo) { + m_OSD.Start(m_pOSDWnd); + OSDBarSetPos(); + } + if (m_wndPlaylistBar.IsHiddenDueToFullscreen()) { + m_wndPlaylistBar.SetHiddenDueToFullscreen(false); + } + } + + return 0; +} + +void CMainFrame::OnUpdateFileOpen(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() != MLS::LOADING); +} + +BOOL CMainFrame::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCDS) +{ + if (AfxGetMyApp()->m_fClosingState) { + return FALSE; + } + + CAppSettings& s = AfxGetAppSettings(); + + if (m_pSkypeMoodMsgHandler && m_pSkypeMoodMsgHandler->HandleMessage(pWnd->GetSafeHwnd(), pCDS)) { + return TRUE; + } else if (pCDS->dwData != 0x6ABE51 || pCDS->cbData < sizeof(DWORD)) { + if (s.hMasterWnd) { + ProcessAPICommand(pCDS); + return TRUE; + } else { + return FALSE; + } + } + + if (m_bScanDlgOpened) { + return FALSE; + } + + DWORD len = *((DWORD*)pCDS->lpData); + TCHAR* pBuff = (TCHAR*)((DWORD*)pCDS->lpData + 1); + TCHAR* pBuffEnd = (TCHAR*)((BYTE*)pBuff + pCDS->cbData - sizeof(DWORD)); + + CAtlList cmdln; + + while (len-- > 0 && pBuff < pBuffEnd) { + CString str(pBuff); + pBuff += str.GetLength() + 1; + + cmdln.AddTail(str); + } + + s.ParseCommandLine(cmdln); + + if (s.nCLSwitches & CLSW_SLAVE) { + SendAPICommand(CMD_CONNECT, L"%d", PtrToInt(GetSafeHwnd())); + s.nCLSwitches &= ~CLSW_SLAVE; + } + + POSITION pos = s.slFilters.GetHeadPosition(); + while (pos) { + CString fullpath = MakeFullPath(s.slFilters.GetNext(pos)); + + CPath tmp(fullpath); + tmp.RemoveFileSpec(); + tmp.AddBackslash(); + CString path = tmp; + + WIN32_FIND_DATA fd; + ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); + HANDLE hFind = FindFirstFile(fullpath, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + continue; + } + + CFilterMapper2 fm2(false); + fm2.Register(path + fd.cFileName); + while (!fm2.m_filters.IsEmpty()) { + if (FilterOverride* f = fm2.m_filters.RemoveTail()) { + f->fTemporary = true; + + bool fFound = false; + + POSITION pos2 = s.m_filters.GetHeadPosition(); + while (pos2) { + FilterOverride* f2 = s.m_filters.GetNext(pos2); + if (f2->type == FilterOverride::EXTERNAL && !f2->path.CompareNoCase(f->path)) { + fFound = true; + break; + } + } + + if (!fFound) { + CAutoPtr p(f); + s.m_filters.AddHead(p); + } + } + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + } + + bool fSetForegroundWindow = false; + + auto applyRandomizeSwitch = [&]() { + if (s.nCLSwitches & CLSW_RANDOMIZE) { + m_wndPlaylistBar.Randomize(); + s.nCLSwitches &= ~CLSW_RANDOMIZE; + } + }; + + if ((s.nCLSwitches & CLSW_DVD) && !s.slFiles.IsEmpty()) { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + fSetForegroundWindow = true; + + CAutoPtr p(DEBUG_NEW OpenDVDData()); + if (p) { + p->path = s.slFiles.GetHead(); + p->subs.AddTailList(&s.slSubs); + } + OpenMedia(p); + s.nCLSwitches &= ~CLSW_DVD; + } else if (s.nCLSwitches & CLSW_CD) { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + fSetForegroundWindow = true; + + CAtlList sl; + + if (!s.slFiles.IsEmpty()) { + GetOpticalDiskType(s.slFiles.GetHead()[0], sl); + } else { + CString dir; + dir.ReleaseBufferSetLength(GetCurrentDirectory(2048, dir.GetBuffer(2048))); + + GetOpticalDiskType(dir[0], sl); + + for (TCHAR drive = _T('A'); sl.IsEmpty() && drive <= _T('Z'); drive++) { + GetOpticalDiskType(drive, sl); + } + } + + m_wndPlaylistBar.Open(sl, true); + applyRandomizeSwitch(); + OpenCurPlaylistItem(); + s.nCLSwitches &= ~CLSW_CD; + } else if (s.nCLSwitches & CLSW_DEVICE) { + SendMessage(WM_COMMAND, ID_FILE_OPENDEVICE); + s.nCLSwitches &= ~CLSW_DEVICE; + } else if (!s.slFiles.IsEmpty()) { + CAtlList sl; + sl.AddTailList(&s.slFiles); + + PathUtils::ParseDirs(sl); + + bool fMulti = sl.GetCount() > 1; + + if (!fMulti) { + sl.AddTailList(&s.slDubs); + } + + if (OpenBD(s.slFiles.GetHead())) { + // Nothing more to do + } else if (!fMulti && CPath(s.slFiles.GetHead() + _T("\\VIDEO_TS")).IsDirectory()) { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + fSetForegroundWindow = true; + + CAutoPtr p(DEBUG_NEW OpenDVDData()); + if (p) { + p->path = s.slFiles.GetHead(); + p->subs.AddTailList(&s.slSubs); + } + OpenMedia(p); + } else { + ULONGLONG tcnow = GetTickCount64(); + if (m_dwLastRun && ((tcnow - m_dwLastRun) < s.iRedirectOpenToAppendThreshold)) { + s.nCLSwitches |= CLSW_ADD; + } + m_dwLastRun = tcnow; + + if ((s.nCLSwitches & CLSW_ADD) && !IsPlaylistEmpty()) { + POSITION pos2 = sl.GetHeadPosition(); + while (pos2) { + CString fn = sl.GetNext(pos2); + if (!CanSendToYoutubeDL(fn) || !ProcessYoutubeDLURL(fn, true)) { + CAtlList sl2; + sl2.AddHead(fn); + m_wndPlaylistBar.Append(sl2, false, &s.slSubs); + } + } + + applyRandomizeSwitch(); + + if (s.nCLSwitches & (CLSW_OPEN | CLSW_PLAY)) { + m_wndPlaylistBar.SetLast(); + OpenCurPlaylistItem(); + } + } else { + //SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + fSetForegroundWindow = true; + + if (fMulti || sl.GetCount() == 1) { + bool first = true; + POSITION pos2 = sl.GetHeadPosition(); + while (pos2) { + CString fn = sl.GetNext(pos2); + if (!CanSendToYoutubeDL(fn) || !ProcessYoutubeDLURL(fn, !first, false)) { + CAtlList sl2; + sl2.AddHead(fn); + if (first) { + m_wndPlaylistBar.Open(sl2, false, &s.slSubs); + } else { + m_wndPlaylistBar.Append(sl2, false, &s.slSubs); + } + } + first = false; + } + } else { + // video + dub + m_wndPlaylistBar.Open(sl, false, &s.slSubs); + } + + applyRandomizeSwitch(); + if (sl.GetCount() != 1 || !IsPlaylistFile(sl.GetHead())) { //playlists already set first pos (or saved pos) + m_wndPlaylistBar.SetFirst(); + } + OpenCurPlaylistItem((s.nCLSwitches & CLSW_STARTVALID) ? s.rtStart : 0, false, s.abRepeat); + + s.nCLSwitches &= ~CLSW_STARTVALID; + s.rtStart = 0; + } + s.nCLSwitches &= ~CLSW_ADD; + } + } else if ((s.nCLSwitches & CLSW_PLAY) && !IsPlaylistEmpty()) { + OpenCurPlaylistItem(); + } else { + applyRandomizeSwitch(); + } + + if (s.nCLSwitches & CLSW_PRESET1) { + SendMessage(WM_COMMAND, ID_VIEW_PRESETS_MINIMAL); + s.nCLSwitches &= ~CLSW_PRESET1; + } else if (s.nCLSwitches & CLSW_PRESET2) { + SendMessage(WM_COMMAND, ID_VIEW_PRESETS_COMPACT); + s.nCLSwitches &= ~CLSW_PRESET2; + } else if (s.nCLSwitches & CLSW_PRESET3) { + SendMessage(WM_COMMAND, ID_VIEW_PRESETS_NORMAL); + s.nCLSwitches &= ~CLSW_PRESET3; + } + if (s.nCLSwitches & CLSW_VOLUME) { + if (IsMuted()) { + SendMessage(WM_COMMAND, ID_VOLUME_MUTE); + } + m_wndToolBar.SetVolume(s.nCmdVolume); + s.nCLSwitches &= ~CLSW_VOLUME; + } + if (s.nCLSwitches & CLSW_MUTE) { + if (!IsMuted()) { + SendMessage(WM_COMMAND, ID_VOLUME_MUTE); + } + s.nCLSwitches &= ~CLSW_MUTE; + } + + if (fSetForegroundWindow && !(s.nCLSwitches & CLSW_NOFOCUS)) { + SetForegroundWindow(); + } + + return TRUE; +} + +int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) +{ + switch (uMsg) { + case BFFM_INITIALIZED: { + //Initial directory is set here + const CAppSettings& s = AfxGetAppSettings(); + if (!s.strDVDPath.IsEmpty()) { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)s.strDVDPath); + } + break; + } + default: + break; + } + return 0; +} + +void CMainFrame::OpenDVDOrBD(CStringW path) { + if (!path.IsEmpty()) { + AfxGetAppSettings().strDVDPath = path; + if (!OpenBD(path)) { + CAutoPtr p(DEBUG_NEW OpenDVDData()); + p->path = path; + p->path.Replace(_T('/'), _T('\\')); + p->path = ForceTrailingSlash(p->path); + + OpenMedia(p); + } + } +} + +void CMainFrame::OnFileOpendvd() +{ + if ((GetLoadState() == MLS::LOADING) || IsD3DFullScreenMode()) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + CString strTitle(StrRes(IDS_MAINFRM_46)); + CString path; + + if (s.fUseDVDPath && !s.strDVDPath.IsEmpty()) { + path = s.strDVDPath; + } else { + //strDVDPath is actually used as a default to open without the dialog, + //but since it is always updated to the last path chosen, + //we can use it as the default for the dialog, too + CFolderPickerDialog fd(ForceTrailingSlash(s.strDVDPath), FOS_PATHMUSTEXIST, GetModalParent()); + fd.m_ofn.lpstrTitle = strTitle; + + if (fd.DoModal() == IDOK) { + path = fd.GetPathName(); //getfolderpath() does not work correctly for CFolderPickerDialog + } else { + return; + } + } + OpenDVDOrBD(path); +} + +void CMainFrame::OnFileOpendevice() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (GetLoadState() == MLS::LOADING) { + return; + } + + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + SetForegroundWindow(); + + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + + m_wndPlaylistBar.Empty(); + + if (s.iDefaultCaptureDevice == 0 && s.strAnalogVideo == L"dummy" && s.strAnalogAudio == L"dummy") { + // device not configured yet, open settings + ShowOptions(IDD_PPAGECAPTURE); + return; + } + + CAutoPtr p(DEBUG_NEW OpenDeviceData()); + if (p) { + p->DisplayName[0] = s.strAnalogVideo; + p->DisplayName[1] = s.strAnalogAudio; + } + OpenMedia(p); +} + +void CMainFrame::OnFileOpenOpticalDisk(UINT nID) +{ + nID -= ID_FILE_OPEN_OPTICAL_DISK_START; + + nID++; + for (TCHAR drive = _T('A'); drive <= _T('Z'); drive++) { + CAtlList sl; + + OpticalDiskType_t discType = GetOpticalDiskType(drive, sl); + switch (discType) { + case OpticalDisk_Audio: + case OpticalDisk_VideoCD: + case OpticalDisk_DVDVideo: + case OpticalDisk_BD: + nID--; + break; + default: + break; + } + + if (nID == 0) { + if (OpticalDisk_BD == discType || OpticalDisk_DVDVideo == discType) { + OpenDVDOrBD(CStringW(drive) + L":\\"); + } else { + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + SetForegroundWindow(); + + if (IsIconic()) { + ShowWindow(SW_RESTORE); + } + + m_wndPlaylistBar.Open(sl, true); + OpenCurPlaylistItem(); + } + break; + } + } +} + +void CMainFrame::OnFileRecycle() +{ + // check if a file is playing + if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_FILE) { + return; + } + + OAFilterState fs = GetMediaState(); + if (fs == State_Running) { + MediaControlPause(true); + } + + m_wndPlaylistBar.DeleteFileInPlaylist(m_wndPlaylistBar.m_pl.GetPos()); +} + +void CMainFrame::OnFileReopen() +{ + if (!m_LastOpenBDPath.IsEmpty() && OpenBD(m_LastOpenBDPath)) { + return; + } + + // save playback position + if (GetLoadState() == MLS::LOADED) { + if (m_bRememberFilePos && !m_fEndOfStream && m_dwReloadPos == 0 && m_pMS) { + auto& s = AfxGetAppSettings(); + REFERENCE_TIME rtNow = 0; + m_pMS->GetCurrentPosition(&rtNow); + m_dwReloadPos = rtNow; + s.MRU.UpdateCurrentFilePosition(rtNow, true); + } + reloadABRepeat = abRepeat; + } + + OpenCurPlaylistItem(0, true); +} + +DROPEFFECT CMainFrame::OnDropAccept(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) +{ + ClientToScreen(&point); + if (CMouse::CursorOnRootWindow(point, *this)) { + UpdateControlState(UPDATE_CONTROLS_VISIBILITY); + return (dwKeyState & MK_CONTROL) ? (DROPEFFECT_COPY | DROPEFFECT_APPEND) + : (DROPEFFECT_MOVE | DROPEFFECT_LINK | DROPEFFECT_COPY); + } + + return DROPEFFECT_NONE; +} + +bool CMainFrame::IsImageFile(CStringW fn) { + CPath path(fn); + CStringW ext(path.GetExtension()); + return IsImageFileExt(ext); +} + +bool CMainFrame::IsImageFileExt(CStringW ext) { + ext.MakeLower(); + return ( + ext == _T(".jpg") || ext == _T(".jpeg") || ext == _T(".png") || ext == _T(".gif") || ext == _T(".bmp") + || ext == _T(".tiff") || ext == _T(".jpe") || ext == _T(".tga") || ext == _T(".heic") || ext == _T(".avif") + ); +} + +bool CMainFrame::IsPlaylistFile(CStringW fn) { + CPath path(fn); + CStringW ext(path.GetExtension()); + return IsPlaylistFileExt(ext); +} + +bool CMainFrame::IsPlaylistFileExt(CStringW ext) { + return (ext == _T(".m3u") || ext == _T(".m3u8") || ext == _T(".mpcpl") || ext == _T(".pls") || ext == _T(".cue") || ext == _T(".asx")); +} + +bool CMainFrame::IsAudioOrVideoFileExt(CStringW ext) { + return IsPlayableFormatExt(ext); +} + +bool CMainFrame::IsAudioFileExt(CStringW ext) { + const CMediaFormats& mf = AfxGetAppSettings().m_Formats; + ext.MakeLower(); + return mf.FindExt(ext, true); +} + +bool CMainFrame::IsPlayableFormatExt(CStringW ext) { + const CMediaFormats& mf = AfxGetAppSettings().m_Formats; + ext.MakeLower(); + return mf.FindExt(ext); +} + +bool CMainFrame::CanSkipToExt(CStringW ext, CStringW curExt) +{ + if (IsImageFileExt(curExt)) { + return IsImageFileExt(ext); + } else { + return IsPlayableFormatExt(ext); + } +} + +BOOL IsSubtitleExtension(CString ext) +{ + return (ext == _T(".srt") || ext == _T(".ssa") || ext == _T(".ass") || ext == _T(".idx") || ext == _T(".sub") || ext == _T(".webvtt") || ext == _T(".vtt") || ext == _T(".sup") || ext == _T(".smi") || ext == _T(".psb") || ext == _T(".usf") || ext == _T(".xss") || ext == _T(".rt")|| ext == _T(".txt")); +} + +BOOL IsSubtitleFilename(CString filename) +{ + CString ext = CPath(filename).GetExtension().MakeLower(); + return IsSubtitleExtension(ext); +} + +bool CMainFrame::IsAudioFilename(CString filename) +{ + CString ext = CPath(filename).GetExtension(); + return IsAudioFileExt(ext); +} + +void CMainFrame::OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) +{ + SetForegroundWindow(); + + if (slFiles.IsEmpty()) { + return; + } + + if (slFiles.GetCount() == 1 && OpenBD(slFiles.GetHead())) { + return; + } + + PathUtils::ParseDirs(slFiles); + + bool bAppend = !!(dropEffect & DROPEFFECT_APPEND); + + // Check for subtitle files + SubtitleInput subInputSelected; + CString subfile; + BOOL onlysubs = true; + BOOL subloaded = false; + BOOL canLoadSub = !bAppend && !m_fAudioOnly && GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode(); + BOOL canLoadSubISR = canLoadSub && m_pCAP && (!m_pDVS || AfxGetAppSettings().IsISRAutoLoadEnabled()); + POSITION pos = slFiles.GetHeadPosition(); + while (pos) { + SubtitleInput subInput; + POSITION curpos = pos; + subfile = slFiles.GetNext(pos); + if (IsSubtitleFilename(subfile)) { + // remove subtitle file from list + slFiles.RemoveAt(curpos); + // try to load it + if (onlysubs && canLoadSub) { + if (canLoadSubISR && LoadSubtitle(subfile, &subInput, False)) { + if (!subInputSelected.pSubStream) { + // first one + subInputSelected = subInput; + } + subloaded = true; + } else if (m_pDVS && slFiles.IsEmpty()) { + if (SUCCEEDED(m_pDVS->put_FileName((LPWSTR)(LPCWSTR)subfile))) { + m_pDVS->put_SelectedLanguage(0); + m_pDVS->put_HideSubtitles(true); + m_pDVS->put_HideSubtitles(false); + subloaded = true; + } + } + } + } + else { + onlysubs = false; + } + } + + if (onlysubs) { + if (subInputSelected.pSubStream) { + AfxGetAppSettings().fEnableSubtitles = true; + SetSubtitle(subInputSelected); + } + if (subloaded) { + CPath fn(subfile); + fn.StripPath(); + CString statusmsg(static_cast(fn)); + SendStatusMessage(statusmsg + ResStr(IDS_SUB_LOADED_SUCCESS), 3000); + } else { + SendStatusMessage(_T("Failed to load subtitle file"), 3000); + } + return; + } + + // load http url with youtube-dl, if available + if (CanSendToYoutubeDL(slFiles.GetHead())) { + CloseMediaBeforeOpen(); + if (ProcessYoutubeDLURL(slFiles.GetHead(), bAppend)) { + if (!bAppend) { + OpenCurPlaylistItem(); + } + return; + } else if (IsOnYDLWhitelist(slFiles.GetHead())) { + // don't bother trying to open this website URL directly + return; + } + } + + // add remaining items + if (bAppend) { + m_wndPlaylistBar.Append(slFiles, true); + } else { + m_wndPlaylistBar.Open(slFiles, true); + OpenCurPlaylistItem(); + } +} + +void CMainFrame::OnFileSaveAs() +{ + CString in, out, ext; + CAppSettings& s = AfxGetAppSettings(); + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + in = pli.m_fns.GetHead(); + } else { + return; + } + + if (pli.m_bYoutubeDL || PathUtils::IsURL(in)) { + // URL + if (pli.m_bYoutubeDL) { + out = _T("%(title)s.%(ext)s"); + } else { + out = _T("choose_a_filename"); + } + } else { + out = PathUtils::StripPathOrUrl(in); + ext = CPath(out).GetExtension().MakeLower(); + if (ext == _T(".cda")) { + out = out.Left(out.GetLength() - 4) + _T(".wav"); + } else if (ext == _T(".ifo")) { + out = out.Left(out.GetLength() - 4) + _T(".vob"); + } + } + + if (!pli.m_bYoutubeDL || pli.m_ydlSourceURL.IsEmpty() || (AfxGetAppSettings().sYDLCommandLine.Find(_T("-o ")) < 0)) { + CFileDialog fd(FALSE, 0, out, + OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR, + ResStr(IDS_ALL_FILES_FILTER), GetModalParent(), 0); + if (DoFileDialogWithLastFolder(fd, s.lastFileSaveCopyPath) != IDOK || !in.CompareNoCase(fd.GetPathName())) { + return; + } else { + out = fd.GetPathName(); + } + } + + if (pli.m_bYoutubeDL && !pli.m_ydlSourceURL.IsEmpty()) { + DownloadWithYoutubeDL(pli.m_ydlSourceURL, out); + return; + } + + CPath p(out); + if (!ext.IsEmpty()) { + p.AddExtension(ext); + } + + OAFilterState fs = State_Stopped; + if (m_pMC) { + m_pMC->GetState(0, &fs); + if (fs == State_Running) { + MediaControlPause(true); + } + } + + CSaveDlg dlg(in, p); + dlg.DoModal(); + + if (m_pMC && fs == State_Running) { + MediaControlRun(); + } +} + +void CMainFrame::OnUpdateFileSaveAs(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_FILE); +} + +bool CMainFrame::GetDIB(BYTE** ppData, long& size, bool fSilent) +{ + if (!ppData) { + return false; + } + if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { + return false; + } + OAFilterState fs = GetMediaState(); + if (fs != State_Paused && fs != State_Running) { + return false; + } + + *ppData = nullptr; + size = 0; + + if (fs == State_Running && !m_pCAP) { + MediaControlPause(true); // wait for completion + } + + HRESULT hr = S_OK; + CString errmsg; + + do { + if (m_pCAP) { + hr = m_pCAP->GetDIB(nullptr, (DWORD*)&size); + if (FAILED(hr)) { + errmsg.Format(IDS_GETDIB_FAILED, hr); + break; + } + + *ppData = DEBUG_NEW BYTE[size]; + if (!(*ppData)) { + return false; + } + + hr = m_pCAP->GetDIB(*ppData, (DWORD*)&size); + if (FAILED(hr)) { + errmsg.Format(IDS_GETDIB_FAILED, hr); + break; + } + } else if (m_pMFVDC) { + // Capture with EVR + BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER)}; + BYTE* pDib; + DWORD dwSize; + REFERENCE_TIME rtImage = 0; + hr = m_pMFVDC->GetCurrentImage(&bih, &pDib, &dwSize, &rtImage); + if (FAILED(hr) || dwSize == 0) { + errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); + break; + } + + size = (long)dwSize + sizeof(BITMAPINFOHEADER); + *ppData = DEBUG_NEW BYTE[size]; + if (!(*ppData)) { + return false; + } + memcpy_s(*ppData, size, &bih, sizeof(BITMAPINFOHEADER)); + memcpy_s(*ppData + sizeof(BITMAPINFOHEADER), size - sizeof(BITMAPINFOHEADER), pDib, dwSize); + CoTaskMemFree(pDib); + } else { + hr = m_pBV->GetCurrentImage(&size, nullptr); + if (FAILED(hr) || size == 0) { + errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); + break; + } + + *ppData = DEBUG_NEW BYTE[size]; + if (!(*ppData)) { + return false; + } + + hr = m_pBV->GetCurrentImage(&size, (long*)*ppData); + if (FAILED(hr)) { + errmsg.Format(IDS_GETCURRENTIMAGE_FAILED, hr); + break; + } + } + } while (0); + + if (!fSilent) { + if (!errmsg.IsEmpty()) { + AfxMessageBox(errmsg, MB_OK); + } + } + + if (fs == State_Running && GetMediaState() != State_Running) { + MediaControlRun(); + } + + if (FAILED(hr)) { + SAFE_DELETE_ARRAY(*ppData); + return false; + } + + return true; +} + +void CMainFrame::SaveDIB(LPCTSTR fn, BYTE* pData, long size) +{ + CPath path(fn); + + PBITMAPINFO bi = reinterpret_cast(pData); + PBITMAPINFOHEADER bih = &bi->bmiHeader; + int bpp = bih->biBitCount; + + if (bpp != 16 && bpp != 24 && bpp != 32) { + AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); + return; + } + int w = bih->biWidth; + int h = abs(bih->biHeight); + int srcpitch = w * (bpp >> 3); + int dstpitch = (w * 3 + 3) / 4 * 4; // round w * 3 to next multiple of 4 + + BYTE* p = DEBUG_NEW BYTE[dstpitch * h]; + + const BYTE* src = pData + sizeof(*bih); + + BitBltFromRGBToRGB(w, h, p, dstpitch, 24, (BYTE*)src + srcpitch * (h - 1), -srcpitch, bpp); + + { + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + ULONG_PTR gdiplusToken; + Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); + + Gdiplus::Bitmap* bm = new Gdiplus::Bitmap(w, h, dstpitch, PixelFormat24bppRGB, p); + + UINT num; // number of image encoders + UINT arraySize; // size, in bytes, of the image encoder array + + // How many encoders are there? + // How big (in bytes) is the array of all ImageCodecInfo objects? + Gdiplus::GetImageEncodersSize(&num, &arraySize); + + // Create a buffer large enough to hold the array of ImageCodecInfo + // objects that will be returned by GetImageEncoders. + Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)DEBUG_NEW BYTE[arraySize]; + + // GetImageEncoders creates an array of ImageCodecInfo objects + // and copies that array into a previously allocated buffer. + // The third argument, imageCodecInfos, is a pointer to that buffer. + Gdiplus::GetImageEncoders(num, arraySize, pImageCodecInfo); + + Gdiplus::EncoderParameters* pEncoderParameters = nullptr; + + // Find the mime type based on the extension + CString ext(path.GetExtension()); + CStringW mime; + if (ext == _T(".jpg")) { + mime = L"image/jpeg"; + + // Set the encoder parameter for jpeg quality + pEncoderParameters = DEBUG_NEW Gdiplus::EncoderParameters; + ULONG quality = AfxGetAppSettings().nJpegQuality; + + pEncoderParameters->Count = 1; + pEncoderParameters->Parameter[0].Guid = Gdiplus::EncoderQuality; + pEncoderParameters->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong; + pEncoderParameters->Parameter[0].NumberOfValues = 1; + pEncoderParameters->Parameter[0].Value = &quality; + } else if (ext == _T(".bmp")) { + mime = L"image/bmp"; + } else { + mime = L"image/png"; + } + + // Get the encoder clsid + CLSID encoderClsid = CLSID_NULL; + for (UINT i = 0; i < num && encoderClsid == CLSID_NULL; i++) { + if (wcscmp(pImageCodecInfo[i].MimeType, mime) == 0) { + encoderClsid = pImageCodecInfo[i].Clsid; + } + } + + Gdiplus::Status s = bm->Save(fn, &encoderClsid, pEncoderParameters); + + // All GDI+ objects must be destroyed before GdiplusShutdown is called + delete bm; + delete [] pImageCodecInfo; + delete pEncoderParameters; + Gdiplus::GdiplusShutdown(gdiplusToken); + delete [] p; + + if (s != Gdiplus::Ok) { + AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); + return; + } + } + + path.m_strPath.Replace(_T("\\\\"), _T("\\")); + + SendStatusMessage(m_wndStatusBar.PreparePathStatusMessage(path), 3000); +} + +HRESULT GetBasicVideoFrame(IBasicVideo* pBasicVideo, std::vector& dib) { + // IBasicVideo::GetCurrentImage() gives the original frame + + long size; + + HRESULT hr = pBasicVideo->GetCurrentImage(&size, nullptr); + if (FAILED(hr)) { + return hr; + } + if (size <= 0) { + return E_ABORT; + } + + dib.resize(size); + + hr = pBasicVideo->GetCurrentImage(&size, (long*)dib.data()); + if (FAILED(hr)) { + dib.clear(); + } + + return hr; +} + +HRESULT GetVideoDisplayControlFrame(IMFVideoDisplayControl* pVideoDisplayControl, std::vector& dib) { + // IMFVideoDisplayControl::GetCurrentImage() gives the displayed frame + + BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER) }; + BYTE* pDib; + DWORD size; + REFERENCE_TIME rtImage = 0; + + HRESULT hr = pVideoDisplayControl->GetCurrentImage(&bih, &pDib, &size, &rtImage); + if (S_OK != hr) { + return hr; + } + if (size == 0) { + return E_ABORT; + } + + dib.resize(sizeof(BITMAPINFOHEADER) + size); + + memcpy(dib.data(), &bih, sizeof(BITMAPINFOHEADER)); + memcpy(dib.data() + sizeof(BITMAPINFOHEADER), pDib, size); + CoTaskMemFree(pDib); + + return hr; +} + +HRESULT GetMadVRFrameGrabberFrame(IMadVRFrameGrabber* pMadVRFrameGrabber, std::vector& dib, bool displayed) { + LPVOID dibImage = nullptr; + HRESULT hr; + + if (displayed) { + hr = pMadVRFrameGrabber->GrabFrame(ZOOM_PLAYBACK_SIZE, 0, 0, 0, 0, 0, &dibImage, 0); + } else { + hr = pMadVRFrameGrabber->GrabFrame(ZOOM_ENCODED_SIZE, 0, 0, 0, 0, 0, &dibImage, 0); + } + + if (S_OK != hr) { + return hr; + } + if (!dibImage) { + return E_ABORT; + } + + const BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)dibImage; + + dib.resize(sizeof(BITMAPINFOHEADER) + bih->biSizeImage); + memcpy(dib.data(), dibImage, sizeof(BITMAPINFOHEADER) + bih->biSizeImage); + LocalFree(dibImage); + + return hr; +} + +HRESULT CMainFrame::GetDisplayedImage(std::vector& dib, CString& errmsg) { + errmsg.Empty(); + HRESULT hr; + + if (m_pCAP) { + LPVOID dibImage = nullptr; + hr = m_pCAP->GetDisplayedImage(&dibImage); + + if (S_OK == hr && dibImage) { + const BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)dibImage; + dib.resize(sizeof(BITMAPINFOHEADER) + bih->biSizeImage); + memcpy(dib.data(), dibImage, sizeof(BITMAPINFOHEADER) + bih->biSizeImage); + LocalFree(dibImage); + } + } + else if (m_pMFVDC) { + hr = GetVideoDisplayControlFrame(m_pMFVDC, dib); + } else if (m_pMVRFG) { + hr = GetMadVRFrameGrabberFrame(m_pMVRFG, dib, true); + } else { + hr = E_NOINTERFACE; + } + + if (FAILED(hr)) { + errmsg.Format(L"CMainFrame::GetCurrentImage() failed, 0x%08x", hr); + } + + return hr; +} + +HRESULT CMainFrame::GetCurrentFrame(std::vector& dib, CString& errmsg) { + HRESULT hr = S_OK; + errmsg.Empty(); + + OAFilterState fs = GetMediaState(); + if (m_eMediaLoadState != MLS::LOADED || m_fAudioOnly || (fs != State_Paused && fs != State_Running)) { + return E_ABORT; + } + + if (fs == State_Running && !m_pCAP) { + MediaControlPause(true); //wait for completion + } + + if (m_pCAP) { + DWORD size; + hr = m_pCAP->GetDIB(nullptr, &size); + + if (S_OK == hr) { + dib.resize(size); + hr = m_pCAP->GetDIB(dib.data(), &size); + } + + if (FAILED(hr)) { + errmsg.Format(L"ISubPicAllocatorPresenter3::GetDIB() failed, 0x%08x", hr); + } + } else if (m_pBV) { + hr = GetBasicVideoFrame(m_pBV, dib); + + if (hr == E_NOINTERFACE && m_pMFVDC) { + // hmm, EVR is not able to give the original frame, giving the displayed image + hr = GetDisplayedImage(dib, errmsg); + } else if (FAILED(hr)) { + errmsg.Format(L"IBasicVideo::GetCurrentImage() failed, 0x%08x", hr); + } + } else { + hr = E_POINTER; + errmsg.Format(L"Interface not found!"); + } + + if (fs == State_Running && GetMediaState() != State_Running) { + MediaControlRun(); + } + + return hr; +} + +HRESULT CMainFrame::GetOriginalFrame(std::vector& dib, CString& errmsg) { + HRESULT hr = S_OK; + errmsg.Empty(); + + if (m_pMVRFG) { + hr = GetMadVRFrameGrabberFrame(m_pMVRFG, dib, false); + if (FAILED(hr)) { + errmsg.Format(L"IMadVRFrameGrabber::GrabFrame() failed, 0x%08x", hr); + } + } else { + hr = GetCurrentFrame(dib, errmsg); + } + + return hr; +} + +HRESULT CMainFrame::RenderCurrentSubtitles(BYTE* pData) { + ASSERT(m_pCAP && AfxGetAppSettings().bSnapShotSubtitles && !m_pMVRFG && AfxGetAppSettings().fEnableSubtitles && AfxGetAppSettings().IsISRAutoLoadEnabled()); + CheckPointer(pData, E_FAIL); + HRESULT hr = S_FALSE; + + if (CComQIPtr pSubPicProvider = m_pCurrentSubInput.pSubStream) { + const PBITMAPINFOHEADER bih = (PBITMAPINFOHEADER)pData; + const int width = bih->biWidth; + const int height = bih->biHeight; + + REFERENCE_TIME rtNow = 0; + m_pMS->GetCurrentPosition(&rtNow); + + int delay = m_pCAP->GetSubtitleDelay(); + if (delay != 0) { + if (delay > 0 && delay * 10000LL > rtNow) { + return S_FALSE; + } else { + rtNow -= delay * 10000LL; + } + } + + int subWidth = width; + int subHeight = height; + bool needsResize = false; + if (CPGSSub* pgsSub = dynamic_cast(pSubPicProvider.p)) { + CSize sz; + if (SUCCEEDED(pgsSub->GetPresentationSegmentTextureSize(rtNow, sz))) { + subWidth = sz.cx; + subHeight = sz.cy; + needsResize = true; + } + } + + SubPicDesc spdRender; + + spdRender.type = MSP_RGB32; + spdRender.w = subWidth; + spdRender.h = abs(subHeight); + spdRender.bpp = 32; + spdRender.pitch = subWidth * 4; + spdRender.vidrect = { 0, 0, width, height }; + spdRender.bits = DEBUG_NEW BYTE[spdRender.pitch * spdRender.h]; + + CComPtr pSubPicAllocator = DEBUG_NEW CMemSubPicAllocator(spdRender.type, CSize(spdRender.w, spdRender.h)); + + CMemSubPic memSubPic(spdRender, pSubPicAllocator); + memSubPic.SetInverseAlpha(false); + memSubPic.ClearDirtyRect(); + + RECT bbox = {}; + hr = pSubPicProvider->Render(spdRender, rtNow, m_pCAP->GetFPS(), bbox); + if (needsResize) { + memSubPic.UnlockARGB(); + } + + if (S_OK == hr) { + SubPicDesc spdTarget; + spdTarget.type = MSP_RGB32; + spdTarget.w = width; + spdTarget.h = height; + spdTarget.bpp = 32; + spdTarget.pitch = -width * 4; + spdTarget.vidrect = { 0, 0, width, height }; + spdTarget.bits = (BYTE*)(bih + 1) + (width * 4) * (height - 1); + + hr = memSubPic.AlphaBlt(&spdRender.vidrect, &spdTarget.vidrect, &spdTarget); + } + } + + return hr; +} + +void CMainFrame::SaveImage(LPCWSTR fn, bool displayed, bool includeSubtitles) { + std::vector dib; + CString errmsg; + HRESULT hr; + if (displayed) { + hr = GetDisplayedImage(dib, errmsg); + } else { + hr = GetCurrentFrame(dib, errmsg); + if (includeSubtitles && m_pCAP && hr == S_OK) { + RenderCurrentSubtitles(dib.data()); + } + } + + if (hr == S_OK) { + SaveDIB(fn, dib.data(), (long)dib.size()); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_IMAGE_SAVED), 3000); + } else { + m_OSD.DisplayMessage(OSD_TOPLEFT, errmsg, 3000); + } +} + +void CMainFrame::SaveThumbnails(LPCTSTR fn) +{ + if (!m_pMC || !m_pMS || GetPlaybackMode() != PM_FILE /*&& GetPlaybackMode() != PM_DVD*/) { + return; + } + + REFERENCE_TIME rtPos = GetPos(); + REFERENCE_TIME rtDur = GetDur(); + + if (rtDur <= 0) { + AfxMessageBox(IDS_THUMBNAILS_NO_DURATION, MB_ICONWARNING | MB_OK, 0); + return; + } + + OAFilterState filterState = UpdateCachedMediaState(); + bool bWasStopped = (filterState == State_Stopped); + if (filterState != State_Paused) { + OnPlayPause(); + } + + CSize szVideoARCorrected, szVideo, szAR; + + if (m_pCAP) { + szVideo = m_pCAP->GetVideoSize(false); + szAR = m_pCAP->GetVideoSize(true); + } else if (m_pMFVDC) { + VERIFY(SUCCEEDED(m_pMFVDC->GetNativeVideoSize(&szVideo, &szAR))); + } else { + VERIFY(SUCCEEDED(m_pBV->GetVideoSize(&szVideo.cx, &szVideo.cy))); + + CComQIPtr pBV2 = m_pBV; + long lARx = 0, lARy = 0; + if (pBV2 && SUCCEEDED(pBV2->GetPreferredAspectRatio(&lARx, &lARy)) && lARx > 0 && lARy > 0) { + szAR.SetSize(lARx, lARy); + } + } + + if (szVideo.cx <= 0 || szVideo.cy <= 0) { + AfxMessageBox(IDS_THUMBNAILS_NO_FRAME_SIZE, MB_ICONWARNING | MB_OK, 0); + return; + } + + // with the overlay mixer IBasicVideo2 won't tell the new AR when changed dynamically + DVD_VideoAttributes VATR; + if (GetPlaybackMode() == PM_DVD && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { + szAR.SetSize(VATR.ulAspectX, VATR.ulAspectY); + } + + szVideoARCorrected = (szAR.cx <= 0 || szAR.cy <= 0) ? szVideo : CSize(MulDiv(szVideo.cy, szAR.cx, szAR.cy), szVideo.cy); + + const CAppSettings& s = AfxGetAppSettings(); + + int cols = std::clamp(s.iThumbCols, 1, 16); + int rows = std::clamp(s.iThumbRows, 1, 40); + + const int margin = 5; + int width = std::clamp(s.iThumbWidth, 256, 3840); + float fontscale = width / 1280.0; + int fontsize = fontscale * 16; + const int infoheight = 4 * fontsize + 6 + 2 * margin; + int height = width * szVideoARCorrected.cy / szVideoARCorrected.cx * rows / cols + infoheight; + + int dibsize = sizeof(BITMAPINFOHEADER) + width * height * 4; + + CAutoVectorPtr dib; + if (!dib.Allocate(dibsize)) { + AfxMessageBox(IDS_OUT_OF_MEMORY, MB_ICONWARNING | MB_OK, 0); + return; + } + + BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)(BYTE*)dib; + ZeroMemory(bih, sizeof(BITMAPINFOHEADER)); + bih->biSize = sizeof(BITMAPINFOHEADER); + bih->biWidth = width; + bih->biHeight = height; + bih->biPlanes = 1; + bih->biBitCount = 32; + bih->biCompression = BI_RGB; + bih->biSizeImage = width * height * 4; + memsetd(bih + 1, 0xffffff, bih->biSizeImage); + + SubPicDesc spd; + spd.w = width; + spd.h = height; + spd.bpp = 32; + spd.pitch = -width * 4; + spd.vidrect = CRect(0, 0, width, height); + spd.bits = (BYTE*)(bih + 1) + (width * 4) * (height - 1); + + bool darktheme = s.bMPCTheme && s.eModernThemeMode == CMPCTheme::ModernThemeMode::DARK; + + int gradientBase = 0xe0; + if (darktheme) { + gradientBase = 0x00; + } + // Paint the background + { + BYTE* p = (BYTE*)spd.bits; + for (int y = 0; y < spd.h; y++, p += spd.pitch) { + for (int x = 0; x < spd.w; x++) { + ((DWORD*)p)[x] = 0x010101 * (gradientBase + 0x08 * y / spd.h + 0x18 * (spd.w - x) / spd.w); + } + } + } + + CCritSec csSubLock; + RECT bbox; + CSize szThumbnail((width - margin * 2) / cols - margin * 2, (height - margin * 2 - infoheight) / rows - margin * 2); + // Ensure the thumbnails aren't ridiculously small so that the time indication can at least fit + if (szThumbnail.cx < 60 || szThumbnail.cy < 20) { + AfxMessageBox(IDS_THUMBNAIL_TOO_SMALL, MB_ICONWARNING | MB_OK, 0); + return; + } + + m_nVolumeBeforeFrameStepping = m_wndToolBar.Volume; + if (m_pBA) { + m_pBA->put_Volume(-10000); + } + + // Draw the thumbnails + std::unique_ptr thumb(new(std::nothrow) BYTE[szThumbnail.cx * szThumbnail.cy * 4]); + if (!thumb) { + return; + } + + int pics = cols * rows; + REFERENCE_TIME rtInterval = rtDur / (pics + 1LL); + for (int i = 1; i <= pics; i++) { + REFERENCE_TIME rt = rtInterval * i; + // use a keyframe if close to target time + if (rtInterval >= 100000000LL) { + REFERENCE_TIME rtMaxDiff = std::min(100000000LL, rtInterval / 10); // no more than 10 sec + rt = GetClosestKeyFrame(rt, rtMaxDiff, rtMaxDiff); + } + + DoSeekTo(rt, false); + UpdateWindow(); + + HRESULT hr = m_pFS ? m_pFS->Step(1, nullptr) : E_FAIL; + if (FAILED(hr)) { + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + AfxMessageBox(IDS_FRAME_STEP_ERROR_RENDERER, MB_ICONEXCLAMATION | MB_OK, 0); + return; + } + + bool abortloop = false; + HANDLE hGraphEvent = nullptr; + m_pME->GetEventHandle((OAEVENT*)&hGraphEvent); + while (hGraphEvent) { + DWORD res = WaitForSingleObject(hGraphEvent, 5000); + if (res == WAIT_OBJECT_0) { + LONG evCode = 0; + LONG_PTR evParam1, evParam2; + while (m_pME && SUCCEEDED(m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0))) { + m_pME->FreeEventParams(evCode, evParam1, evParam2); + if (EC_STEP_COMPLETE == evCode) { + hGraphEvent = nullptr; + } + } + } else { + hGraphEvent = nullptr; + if (res == WAIT_TIMEOUT) { + // Likely a seek failure has occurred. For example due to an incomplete file. + REFERENCE_TIME rtCur = 0; + m_pMS->GetCurrentPosition(&rtCur); + if (rtCur >= rtDur) { + abortloop = true; + } + } + } + } + + if (abortloop) { + break; + } + + int col = (i - 1) % cols; + int row = (i - 1) / cols; + + CPoint p(2 * margin + col * (szThumbnail.cx + 2 * margin), infoheight + 2 * margin + row * (szThumbnail.cy + 2 * margin)); + CRect r(p, szThumbnail); + + CRenderedTextSubtitle rts(&csSubLock); + rts.m_SubRendererSettings.renderSSAUsingLibass = false; + rts.m_SubRendererSettings.overrideDefaultStyle = false; + rts.m_SubRendererSettings.overrideAllStyles = false; + rts.CreateDefaultStyle(0); + rts.m_storageRes = rts.m_playRes = CSize(width, height); + STSStyle* style = DEBUG_NEW STSStyle(); + style->fontName = L"Calibri"; + style->marginRect.SetRectEmpty(); + rts.AddStyle(_T("thumbs"), style); + + DVD_HMSF_TIMECODE hmsf = RT2HMS_r(rt); + CStringW str; + if (!darktheme) { + str.Format(L"{\\an7\\1c&Hffffff&\\4a&Hb0&\\bord1\\shad4\\be1}{\\p1}m %d %d l %d %d %d %d %d %d{\\p}", + r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom); + rts.Add(str, true, MS2RT(0), MS2RT(1), _T("thumbs")); // Thumbnail background + } + str.Format(L"{\\an3\\1c&Hffffff&\\3c&H000000&\\alpha&H80&\\fs%d\\b1\\bord2\\shad0\\pos(%d,%d)}%02u:%02u:%02u", + fontsize, r.right - 5, r.bottom - 3, hmsf.bHours, hmsf.bMinutes, hmsf.bSeconds); + rts.Add(str, true, MS2RT(1), MS2RT(2), _T("thumbs")); // Thumbnail time + + rts.Render(spd, 0, 25, bbox); // Draw the thumbnail background/time + + BYTE* pData = nullptr; + long size = 0; + if (!GetDIB(&pData, size)) { + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + return; + } + + BITMAPINFO* bi = (BITMAPINFO*)pData; + + if (bi->bmiHeader.biBitCount != 32) { + CString strTemp; + strTemp.Format(IDS_THUMBNAILS_INVALID_FORMAT, bi->bmiHeader.biBitCount); + AfxMessageBox(strTemp); + delete [] pData; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + return; + } + + int sw = bi->bmiHeader.biWidth; + int sh = abs(bi->bmiHeader.biHeight); + int sp = sw * 4; + const BYTE* src = pData + sizeof(bi->bmiHeader); + + stbir_resize(src, sw, sh, sp, thumb.get(), szThumbnail.cx, szThumbnail.cy, szThumbnail.cx * 4, STBIR_RGBA_PM, STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT); + + BYTE* dst = spd.bits + spd.pitch * r.top + r.left * 4; + + const BYTE* tsrc = thumb.get(); + int tsrcPitch = szThumbnail.cx * 4; + if (bi->bmiHeader.biHeight >= 0) { + tsrc += tsrcPitch * (szThumbnail.cy - 1); + tsrcPitch = -tsrcPitch; + } + for (int y = 0; y < szThumbnail.cy; y++, dst += spd.pitch, tsrc += tsrcPitch) { + memcpy(dst, tsrc, abs(tsrcPitch)); + } + + rts.Render(spd, 10000, 25, bbox); // Draw the thumbnail time + + delete [] pData; + } + + // Draw the file information + { + CRenderedTextSubtitle rts(&csSubLock); + rts.m_SubRendererSettings.renderSSAUsingLibass = false; + rts.m_SubRendererSettings.overrideDefaultStyle = false; + rts.m_SubRendererSettings.overrideAllStyles = false; + rts.CreateDefaultStyle(0); + rts.m_storageRes = rts.m_playRes = CSize(width, height); + STSStyle* style = DEBUG_NEW STSStyle(); + // Use System UI font. + CFont tempFont; + CMPCThemeUtil::getFontByType(tempFont, nullptr, CMPCThemeUtil::MessageFont); + LOGFONT lf; + if (tempFont.GetLogFont(&lf)) { + CString fontName(lf.lfFaceName); + style->fontName = fontName; + } + style->marginRect.SetRect(margin * 2, margin * 2, margin * 2, height - infoheight - margin); + rts.AddStyle(_T("thumbs"), style); + + CStringW str; + str.Format(L"{\\an9\\fs%d\\b1\\bord0\\shad0\\1c&Hffffff&}%s", infoheight - 2 * margin, L"MPC-HC"); + if (darktheme) { + str.Replace(L"\\1c&Hffffff", L"\\1c&Hc8c8c8"); + } + rts.Add(str, true, 0, 1, _T("thumbs"), _T(""), _T(""), CRect(0, 0, 0, 0), -1); + + DVD_HMSF_TIMECODE hmsf = RT2HMS_r(rtDur); + + CString title; + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_bYoutubeDL && pli.m_label && !pli.m_label.IsEmpty()) { + title = pli.m_label; + } else { + title = GetFileName(); + } + + CStringW fs; + CString curfile = m_wndPlaylistBar.GetCurFileName(); + if (!PathUtils::IsURL(curfile)) { + ExtendMaxPathLengthIfNeeded(curfile, true); + WIN32_FIND_DATA wfd; + HANDLE hFind = FindFirstFile(curfile, &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); + fs.Format(IDS_THUMBNAILS_INFO_FILESIZE, szFileSize, FormatNumber(szByteSize).GetString()); + } + } + + CStringW ar; + if (szAR.cx > 0 && szAR.cy > 0 && szAR.cx != szVideo.cx && szAR.cy != szVideo.cy) { + ar.Format(L"(%ld:%ld)", szAR.cx, szAR.cy); + } + CStringW fmt = ResStr(IDS_THUMBNAILS_INFO_HEADER); + if (darktheme) { + fmt.Replace(L"\\1c&H000000", L"\\1c&Hc8c8c8"); + } + str.Format(fmt, fontsize, + title.GetString(), fs.GetString(), szVideo.cx, szVideo.cy, ar.GetString(), hmsf.bHours, hmsf.bMinutes, hmsf.bSeconds); + rts.Add(str, true, 0, 1, _T("thumbs")); + + rts.Render(spd, 0, 25, bbox); + } + + SaveDIB(fn, (BYTE*)dib, dibsize); + + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + + if (bWasStopped) { + OnPlayStop(); + } else { + DoSeekTo(rtPos, false); + } + + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_THUMBS_SAVED), 3000); +} + +CString CMainFrame::MakeSnapshotFileName(BOOL thumbnails) +{ + CAppSettings& s = AfxGetAppSettings(); + CString prefix; + CString fn; + + ASSERT(!thumbnails || GetPlaybackMode() == PM_FILE); + + auto videoFn = GetFileName(); + auto fullName = m_wndPlaylistBar.GetCurFileName(true); + bool needsExtensionRemoval = !s.bSnapShotKeepVideoExtension; + if (IsPlaylistFile(videoFn)) { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + videoFn = pli.m_label; + needsExtensionRemoval = false; + } + } else if (needsExtensionRemoval && PathUtils::IsURL(fullName)){ + auto title = getBestTitle(); + if (!title.IsEmpty()) { + videoFn = title; + needsExtensionRemoval = false; + } + } + + + if (needsExtensionRemoval) { + int nPos = videoFn.ReverseFind('.'); + if (nPos != -1) { + videoFn = videoFn.Left(nPos); + } + } + + bool saveImagePosition, saveImageCurrentTime; + + if (m_wndSeekBar.HasDuration()) { + saveImagePosition = s.bSaveImagePosition; + saveImageCurrentTime = s.bSaveImageCurrentTime; + } else { + saveImagePosition = false; + saveImageCurrentTime = true; + } + + if (GetPlaybackMode() == PM_FILE) { + if (thumbnails) { + prefix.Format(_T("%s_thumbs"), videoFn.GetString()); + } else { + if (saveImagePosition) { + prefix.Format(_T("%s_snapshot_%s"), videoFn.GetString(), GetVidPos().GetString()); + } else { + prefix.Format(_T("%s_snapshot"), videoFn.GetString()); + } + } + } else if (GetPlaybackMode() == PM_DVD) { + if (saveImagePosition) { + prefix.Format(_T("dvd_snapshot_%s"), GetVidPos().GetString()); + } else { + prefix = _T("dvd_snapshot"); + } + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + prefix.Format(_T("%s_snapshot"), m_pDVBState->sChannelName.GetString()); + } else { + prefix = _T("snapshot"); + } + + if (!thumbnails && saveImageCurrentTime) { + CTime t = CTime::GetCurrentTime(); + fn.Format(_T("%s_[%s]%s"), PathUtils::FilterInvalidCharsFromFileName(prefix).GetString(), t.Format(_T("%Y.%m.%d_%H.%M.%S")).GetString(), s.strSnapshotExt.GetString()); + } else { + fn.Format(_T("%s%s"), PathUtils::FilterInvalidCharsFromFileName(prefix).GetString(), s.strSnapshotExt.GetString()); + } + return fn; +} + +BOOL CMainFrame::IsRendererCompatibleWithSaveImage() +{ + BOOL result = TRUE; + const CAppSettings& s = AfxGetAppSettings(); + + if (m_fShockwaveGraph) { + AfxMessageBox(IDS_SCREENSHOT_ERROR_SHOCKWAVE, MB_ICONEXCLAMATION | MB_OK, 0); + result = FALSE; + } else if (s.iDSVideoRendererType == VIDRNDT_DS_OVERLAYMIXER) { + AfxMessageBox(IDS_SCREENSHOT_ERROR_OVERLAY, MB_ICONEXCLAMATION | MB_OK, 0); + result = FALSE; + } + + return result; +} + +CString CMainFrame::GetVidPos() const +{ + CString posstr = _T(""); + if ((GetPlaybackMode() == PM_FILE) || (GetPlaybackMode() == PM_DVD)) { + __int64 start, stop, pos; + m_wndSeekBar.GetRange(start, stop); + pos = m_wndSeekBar.GetPos(); + + DVD_HMSF_TIMECODE tcNow = RT2HMSF(pos); + DVD_HMSF_TIMECODE tcDur = RT2HMSF(stop); + + if (tcDur.bHours > 0 || tcNow.bHours > 0) { + posstr.Format(_T("%02u.%02u.%02u.%03u"), tcNow.bHours, tcNow.bMinutes, tcNow.bSeconds, (pos / 10000) % 1000); + } else { + posstr.Format(_T("%02u.%02u.%03u"), tcNow.bMinutes, tcNow.bSeconds, (pos / 10000) % 1000); + } + } + + return posstr; +} + +void CMainFrame::OnFileSaveImage() +{ + CAppSettings& s = AfxGetAppSettings(); + + /* Check if a compatible renderer is being used */ + if (!IsRendererCompatibleWithSaveImage()) { + return; + } + + CPath psrc(s.strSnapshotPath); + psrc.Combine(s.strSnapshotPath.GetString(), MakeSnapshotFileName(FALSE)); + + bool subtitleOptionSupported = !m_pMVRFG && s.fEnableSubtitles && s.IsISRAutoLoadEnabled(); + + CSaveImageDialog fd(s.nJpegQuality, s.strSnapshotExt, (LPCTSTR)psrc, + _T("BMP - Windows Bitmap (*.bmp)|*.bmp|JPG - JPEG Image (*.jpg)|*.jpg|PNG - Portable Network Graphics (*.png)|*.png||"), GetModalParent(), subtitleOptionSupported); + + if (s.strSnapshotExt == _T(".bmp")) { + fd.m_pOFN->nFilterIndex = 1; + } else if (s.strSnapshotExt == _T(".jpg")) { + fd.m_pOFN->nFilterIndex = 2; + } else if (s.strSnapshotExt == _T(".png")) { + fd.m_pOFN->nFilterIndex = 3; + } + + if (fd.DoModal() != IDOK) { + return; + } + + if (fd.m_pOFN->nFilterIndex == 1) { + s.strSnapshotExt = _T(".bmp"); + } else if (fd.m_pOFN->nFilterIndex == 2) { + s.strSnapshotExt = _T(".jpg"); + s.nJpegQuality = fd.m_nJpegQuality; + } else { + fd.m_pOFN->nFilterIndex = 3; + s.strSnapshotExt = _T(".png"); + } + + CPath pdst(fd.GetPathName()); + CString ext(pdst.GetExtension().MakeLower()); + if (ext != s.strSnapshotExt) { + if (ext == _T(".bmp") || ext == _T(".jpg") || ext == _T(".png")) { + ext = s.strSnapshotExt; + } else { + ext += s.strSnapshotExt; + } + pdst.RenameExtension(ext); + } + CString path = (LPCTSTR)pdst; + pdst.RemoveFileSpec(); + s.strSnapshotPath = (LPCTSTR)pdst; + + bool includeSubtitles = subtitleOptionSupported && s.bSnapShotSubtitles; + + SaveImage(path, false, includeSubtitles); +} + +void CMainFrame::OnFileSaveImageAuto() +{ + const CAppSettings& s = AfxGetAppSettings(); + + // If path doesn't exist, Save Image instead + if (!PathUtils::IsDir(s.strSnapshotPath)) { + AfxMessageBox(IDS_SCREENSHOT_ERROR, MB_ICONWARNING | MB_OK, 0); + OnFileSaveImage(); + return; + } + + /* Check if a compatible renderer is being used */ + if (!IsRendererCompatibleWithSaveImage()) { + return; + } + + bool includeSubtitles = s.bSnapShotSubtitles && !m_pMVRFG && s.fEnableSubtitles && s.IsISRAutoLoadEnabled(); + + CString fn; + fn.Format(_T("%s\\%s"), s.strSnapshotPath.GetString(), MakeSnapshotFileName(FALSE).GetString()); + SaveImage(fn.GetString(), false, includeSubtitles); +} + +void CMainFrame::OnUpdateFileSaveImage(CCmdUI* pCmdUI) +{ + OAFilterState fs = GetMediaState(); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (fs == State_Paused || fs == State_Running)); +} + +void CMainFrame::OnCmdLineSaveThumbnails() +{ + CAppSettings& s = AfxGetAppSettings(); + + /* Check if a compatible renderer is being used */ + if (!IsRendererCompatibleWithSaveImage()) { + return; + } + + CPlaylistItem pli; + if (!m_wndPlaylistBar.GetCur(pli, true)) { + return; + } + + CPath psrc(m_wndPlaylistBar.GetCurFileName(true)); + psrc.RemoveFileSpec(); + psrc.Combine(psrc, MakeSnapshotFileName(TRUE)); + + s.iThumbRows = std::clamp(s.iThumbRows, 1, 40); + s.iThumbCols = std::clamp(s.iThumbCols, 1, 16); + s.iThumbWidth = std::clamp(s.iThumbWidth, 256, 3840); + + CString path = (LPCTSTR)psrc; + + SaveThumbnails(path); + +} + +void CMainFrame::OnFileSaveThumbnails() +{ + CAppSettings& s = AfxGetAppSettings(); + + /* Check if a compatible renderer is being used */ + if (!IsRendererCompatibleWithSaveImage()) { + return; + } + + CPath psrc(s.strSnapshotPath); + psrc.Combine(s.strSnapshotPath, MakeSnapshotFileName(TRUE)); + + CSaveThumbnailsDialog fd(s.nJpegQuality, s.iThumbRows, s.iThumbCols, s.iThumbWidth, s.strSnapshotExt, (LPCTSTR)psrc, + _T("BMP - Windows Bitmap (*.bmp)|*.bmp|JPG - JPEG Image (*.jpg)|*.jpg|PNG - Portable Network Graphics (*.png)|*.png||"), GetModalParent()); + + if (s.strSnapshotExt == _T(".bmp")) { + fd.m_pOFN->nFilterIndex = 1; + } else if (s.strSnapshotExt == _T(".jpg")) { + fd.m_pOFN->nFilterIndex = 2; + } else if (s.strSnapshotExt == _T(".png")) { + fd.m_pOFN->nFilterIndex = 3; + } + + if (fd.DoModal() != IDOK) { + return; + } + + if (fd.m_pOFN->nFilterIndex == 1) { + s.strSnapshotExt = _T(".bmp"); + } else if (fd.m_pOFN->nFilterIndex == 2) { + s.strSnapshotExt = _T(".jpg"); + s.nJpegQuality = fd.m_nJpegQuality; + } else { + fd.m_pOFN->nFilterIndex = 3; + s.strSnapshotExt = _T(".png"); + } + + s.iThumbRows = std::clamp(fd.m_rows, 1, 40); + s.iThumbCols = std::clamp(fd.m_cols, 1, 16); + s.iThumbWidth = std::clamp(fd.m_width, 256, 3840); + + CPath pdst(fd.GetPathName()); + CString ext(pdst.GetExtension().MakeLower()); + if (ext != s.strSnapshotExt) { + if (ext == _T(".bmp") || ext == _T(".jpg") || ext == _T(".png")) { + ext = s.strSnapshotExt; + } else { + ext += s.strSnapshotExt; + } + pdst.RenameExtension(ext); + } + CString path = (LPCTSTR)pdst; + pdst.RemoveFileSpec(); + s.strSnapshotPath = (LPCTSTR)pdst; + + SaveThumbnails(path); +} + +void CMainFrame::OnUpdateFileSaveThumbnails(CCmdUI* pCmdUI) +{ + OAFilterState fs = GetMediaState(); + UNREFERENCED_PARAMETER(fs); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (GetPlaybackMode() == PM_FILE /*|| GetPlaybackMode() == PM_DVD*/)); +} + +void CMainFrame::OnFileSubtitlesLoad() +{ + if (!m_pCAP && !m_pDVS) { + AfxMessageBox(IDS_CANNOT_LOAD_SUB, MB_ICONINFORMATION | MB_OK, 0); + return; + } + + DWORD dwFlags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING | OFN_NOCHANGEDIR; + if (!AfxGetAppSettings().fKeepHistory) { + dwFlags |= OFN_DONTADDTORECENT; + } + CString filters; + filters.Format(_T("%s|*.srt;*.sub;*.ssa;*.ass;*.smi;*.psb;*.txt;*.idx;*.usf;*.xss;*.rt;*.sup;*.webvtt;*.vtt|%s"), + ResStr(IDS_SUBTITLE_FILES_FILTER).GetString(), ResStr(IDS_ALL_FILES_FILTER).GetString()); + + CFileDialog fd(TRUE, nullptr, nullptr, dwFlags, filters, GetModalParent()); + + OPENFILENAME& ofn = fd.GetOFN(); + // Provide a buffer big enough to hold 16 paths (which should be more than enough) + const int nBufferSize = 16 * (MAX_PATH + 1) + 1; + CString filenames; + ofn.lpstrFile = filenames.GetBuffer(nBufferSize); + ofn.nMaxFile = nBufferSize; + // Set the current file directory as default folder + CString curfile = m_wndPlaylistBar.GetCurFileName(); + if (!PathUtils::IsURL(curfile)) { + CPath defaultDir(curfile); + defaultDir.RemoveFileSpec(); + if (!defaultDir.m_strPath.IsEmpty()) { + ofn.lpstrInitialDir = defaultDir.m_strPath; + } + } + + if (fd.DoModal() == IDOK) { + bool bFirstFile = true; + POSITION pos = fd.GetStartPosition(); + while (pos) { + CString subfile = fd.GetNextPathName(pos); + if (m_pDVS) { + if (SUCCEEDED(m_pDVS->put_FileName((LPWSTR)(LPCWSTR)subfile))) { + m_pDVS->put_SelectedLanguage(0); + m_pDVS->put_HideSubtitles(true); + m_pDVS->put_HideSubtitles(false); + break; + } + } else { + SubtitleInput subInput; + if (LoadSubtitle(subfile, &subInput) && bFirstFile) { + bFirstFile = false; + // Use the subtitles file that was just added + AfxGetAppSettings().fEnableSubtitles = true; + SetSubtitle(subInput); + } + } + } + } +} + +void CMainFrame::OnUpdateFileSubtitlesLoad(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(!m_fAudioOnly && (m_pCAP || m_pDVS) && GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode()); +} + +void CMainFrame::SubtitlesSave(const TCHAR* directory, bool silent) +{ + if (lastOpenFile.IsEmpty()) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + + int i = 0; + SubtitleInput* pSubInput = GetSubtitleInput(i, true); + if (!pSubInput) { + return; + } + + CLSID clsid; + if (FAILED(pSubInput->pSubStream->GetClassID(&clsid))) { + return; + } + + CString suggestedFileName; + if (PathUtils::IsURL(lastOpenFile)) { + if (silent) { + return; + } + suggestedFileName = _T("subtitle"); + } else { + CPath path(lastOpenFile); + path.RemoveExtension(); + suggestedFileName = CString(path); + } + + if (directory && *directory) { + CPath suggestedPath(suggestedFileName); + int pos = suggestedPath.FindFileName(); + CString fileName = suggestedPath.m_strPath.Mid(pos); + CPath dirPath(directory); + if (dirPath.IsRelative()) { + dirPath = CPath(suggestedPath.m_strPath.Left(pos)) += dirPath; + } + if (EnsureDirectory(dirPath)) { + suggestedFileName = CString(dirPath += fileName); + } + else if (silent) { + return; + } + } + + bool isSaved = false; + if (clsid == __uuidof(CVobSubFile)) { + CVobSubFile* pVSF = (CVobSubFile*)(ISubStream*)pSubInput->pSubStream; + + // remember to set lpszDefExt to the first extension in the filter so that the save dialog autocompletes the extension + // and tracks attempts to overwrite in a graceful manner + if (silent) { + isSaved = pVSF->Save(suggestedFileName + _T(".idx"), m_pCAP->GetSubtitleDelay()); + } else { + CSaveSubtitlesFileDialog fd(m_pCAP->GetSubtitleDelay(), _T("idx"), suggestedFileName, + _T("VobSub (*.idx, *.sub)|*.idx;*.sub||"), GetModalParent()); + + if (fd.DoModal() == IDOK) { + CAutoLock cAutoLock(&m_csSubLock); + isSaved = pVSF->Save(fd.GetPathName(), fd.GetDelay()); + } + } + } + else if (clsid == __uuidof(CRenderedTextSubtitle)) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; + + if (s.bAddLangCodeWhenSaveSubtitles && pRTS->m_lcid && pRTS->m_lcid != LCID(-1)) { + CString str; + GetLocaleString(pRTS->m_lcid, LOCALE_SISO639LANGNAME, str); + suggestedFileName += _T('.') + str; + + if (pRTS->m_eHearingImpaired == Subtitle::HI_YES) { + suggestedFileName += _T(".hi"); + } + } + + // same thing as in the case of CVobSubFile above for lpszDefExt + if (silent) { + Subtitle::SubType type; + switch (pRTS->m_subtitleType) + { + case Subtitle::ASS: + case Subtitle::SSA: + case Subtitle::VTT: + type = Subtitle::ASS; + break; + default: + type = Subtitle::SRT; + } + + isSaved = pRTS->SaveAs( + suggestedFileName, type, m_pCAP->GetFPS(), m_pCAP->GetSubtitleDelay(), + CTextFile::DEFAULT_ENCODING, s.bSubSaveExternalStyleFile); + } else { + const std::vector types = { + Subtitle::SRT, + Subtitle::SUB, + Subtitle::SMI, + Subtitle::PSB, + Subtitle::SSA, + Subtitle::ASS + }; + + CString filter; + filter += _T("SubRip (*.srt)|*.srt|"); //1 = default + filter += _T("MicroDVD (*.sub)|*.sub|"); //2 + filter += _T("SAMI (*.smi)|*.smi|"); //3 + filter += _T("PowerDivX (*.psb)|*.psb|"); //4 + filter += _T("SubStation Alpha (*.ssa)|*.ssa|"); //5 + filter += _T("Advanced SubStation Alpha (*.ass)|*.ass|"); //6 + filter += _T("|"); + + CSaveSubtitlesFileDialog fd(pRTS->m_encoding, m_pCAP->GetSubtitleDelay(), s.bSubSaveExternalStyleFile, + _T("srt"), suggestedFileName, filter, types, GetModalParent()); + + if (pRTS->m_subtitleType == Subtitle::SSA || pRTS->m_subtitleType == Subtitle::ASS) { + fd.m_ofn.nFilterIndex = 6; //nFilterIndex is 1-based + } + + if (fd.DoModal() == IDOK) { + CAutoLock cAutoLock(&m_csSubLock); + s.bSubSaveExternalStyleFile = fd.GetSaveExternalStyleFile(); + isSaved = pRTS->SaveAs(fd.GetPathName(), types[fd.m_ofn.nFilterIndex - 1], m_pCAP->GetFPS(), fd.GetDelay(), fd.GetEncoding(), fd.GetSaveExternalStyleFile()); + } + } + } + else { + AfxMessageBox(_T("This operation is not supported.\r\nThe selected subtitles cannot be saved."), MB_ICONEXCLAMATION | MB_OK); + } + + if (isSaved && s.fKeepHistory) { + auto subPath = pSubInput->pSubStream->GetPath(); + if (!subPath.IsEmpty()) { + s.MRU.AddSubToCurrent(subPath); + } + } +} + +void CMainFrame::OnUpdateFileSubtitlesSave(CCmdUI* pCmdUI) +{ + bool bEnable = false; + + if (!m_pCurrentSubInput.pSourceFilter) { + if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { + bEnable = !pRTS->IsEmpty(); + } else if (dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { + bEnable = true; + } + } + + pCmdUI->Enable(bEnable); +} + +#if 0 +void CMainFrame::OnFileSubtitlesUpload() +{ + m_wndSubtitlesUploadDialog.ShowWindow(SW_SHOW); +} + +void CMainFrame::OnUpdateFileSubtitlesUpload(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(!m_pSubStreams.IsEmpty() && s.fEnableSubtitles); +} +#endif + +void CMainFrame::OnFileSubtitlesDownload() +{ + if (!m_fAudioOnly) { + if (m_pCAP && AfxGetAppSettings().IsISRAutoLoadEnabled()) { + m_wndSubtitlesDownloadDialog.ShowWindow(SW_SHOW); + } else { + AfxMessageBox(_T("Downloading subtitles only works when using the internal subtitle renderer."), MB_ICONINFORMATION | MB_OK, 0); + } + } +} + +void CMainFrame::OnUpdateFileSubtitlesDownload(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !IsPlaybackCaptureMode() && m_pCAP && !m_fAudioOnly); +} + +void CMainFrame::OnFileProperties() +{ + CString fn; + CString ydlsrc; + if (m_pDVBState) { + fn = m_pDVBState->sChannelName; + } else { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + fn = pli.m_fns.GetHead(); + if (pli.m_bYoutubeDL) { + ydlsrc = pli.m_ydlSourceURL; + } + } + } + + ASSERT(!fn.IsEmpty()); + + CPPageFileInfoSheet fileinfo(fn, ydlsrc, this, GetModalParent()); + fileinfo.DoModal(); +} + +void CMainFrame::OnUpdateFileProperties(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() != PM_ANALOG_CAPTURE); +} + +void CMainFrame::OnFileOpenLocation() { + CString filePath = m_wndPlaylistBar.GetCurFileName(); + if (!PathUtils::IsURL(filePath)) { + ExploreToFile(filePath); + } +} + +void CMainFrame::OnFileCloseMedia() +{ + CloseMedia(); +} + +void CMainFrame::OnUpdateViewTearingTest(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC); + + pCmdUI->Enable(supported && GetLoadState() == MLS::LOADED && !m_fAudioOnly); + pCmdUI->SetCheck(supported && AfxGetMyApp()->m_Renderers.m_bTearingTest); +} + +void CMainFrame::OnViewTearingTest() +{ + AfxGetMyApp()->m_Renderers.m_bTearingTest = !AfxGetMyApp()->m_Renderers.m_bTearingTest; +} + +void CMainFrame::OnUpdateViewDisplayRendererStats(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); + + pCmdUI->Enable(supported && GetLoadState() == MLS::LOADED && !m_fAudioOnly); + pCmdUI->SetCheck(supported && AfxGetMyApp()->m_Renderers.m_iDisplayStats > 0); +} + +void CMainFrame::OnViewResetRendererStats() +{ + AfxGetMyApp()->m_Renderers.m_bResetStats = true; // Reset by "consumer" +} + +void CMainFrame::OnViewDisplayRendererStats() +{ + const CAppSettings& s = AfxGetAppSettings(); + bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR); + + if (supported) { + if (m_pCAP3) { + m_pCAP3->ToggleStats(); + return; + } + + if (!AfxGetMyApp()->m_Renderers.m_iDisplayStats) { + AfxGetMyApp()->m_Renderers.m_bResetStats = true; // to reset statistics on first call ... + } + + ++AfxGetMyApp()->m_Renderers.m_iDisplayStats; + if (AfxGetMyApp()->m_Renderers.m_iDisplayStats > 3) { + AfxGetMyApp()->m_Renderers.m_iDisplayStats = 0; + } + RepaintVideo(); + } +} + +void CMainFrame::OnUpdateViewVSync(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(!supported || r.m_AdvRendSets.bVMR9VSync); +} + +void CMainFrame::OnUpdateViewVSyncOffset(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D + && r.m_AdvRendSets.bVMR9AlterativeVSync); + + pCmdUI->Enable(supported); + CString Temp; + Temp.Format(L"%d", r.m_AdvRendSets.iVMR9VSyncOffset); + pCmdUI->SetText(Temp); + CMPCThemeMenu::updateItem(pCmdUI); +} + +void CMainFrame::OnUpdateViewVSyncAccurate(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9VSyncAccurate); +} + +void CMainFrame::OnUpdateViewSynchronizeVideo(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_SYNC) && GetPlaybackMode() == PM_NONE); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeVideo); +} + +void CMainFrame::OnUpdateViewSynchronizeDisplay(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_SYNC) && GetPlaybackMode() == PM_NONE); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeDisplay); +} + +void CMainFrame::OnUpdateViewSynchronizeNearest(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = (s.iDSVideoRendererType == VIDRNDT_DS_SYNC); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bSynchronizeNearest); +} + +void CMainFrame::OnUpdateViewColorManagementEnable(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9ColorManagementEnable); +} + +void CMainFrame::OnUpdateViewColorManagementInput(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support + && r.m_AdvRendSets.bVMR9ColorManagementEnable; + + pCmdUI->Enable(supported); + + switch (pCmdUI->m_nID) { + case ID_VIEW_CM_INPUT_AUTO: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_UNKNOWN); + break; + + case ID_VIEW_CM_INPUT_HDTV: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_HDTV); + break; + + case ID_VIEW_CM_INPUT_SDTV_NTSC: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_SDTV_NTSC); + break; + + case ID_VIEW_CM_INPUT_SDTV_PAL: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementInput == VIDEO_SYSTEM_SDTV_PAL); + break; + } +} + +void CMainFrame::OnUpdateViewColorManagementAmbientLight(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support && + r.m_AdvRendSets.bVMR9ColorManagementEnable; + + pCmdUI->Enable(supported); + + switch (pCmdUI->m_nID) { + case ID_VIEW_CM_AMBIENTLIGHT_BRIGHT: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_BRIGHT); + break; + case ID_VIEW_CM_AMBIENTLIGHT_DIM: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_DIM); + break; + case ID_VIEW_CM_AMBIENTLIGHT_DARK: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementAmbientLight == AMBIENT_LIGHT_DARK); + break; + } +} + +void CMainFrame::OnUpdateViewColorManagementIntent(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support + && r.m_AdvRendSets.bVMR9ColorManagementEnable; + + pCmdUI->Enable(supported); + + switch (pCmdUI->m_nID) { + case ID_VIEW_CM_INTENT_PERCEPTUAL: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_PERCEPTUAL); + break; + case ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC); + break; + case ID_VIEW_CM_INTENT_SATURATION: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_SATURATION); + break; + case ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC: + pCmdUI->SetCheck(r.m_AdvRendSets.iVMR9ColorManagementIntent == COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC); + break; + } +} + +void CMainFrame::OnUpdateViewEVROutputRange(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + + if (pCmdUI->m_nID == ID_VIEW_EVROUTPUTRANGE_0_255) { + pCmdUI->SetCheck(r.m_AdvRendSets.iEVROutputRange == 0); + } else if (pCmdUI->m_nID == ID_VIEW_EVROUTPUTRANGE_16_235) { + pCmdUI->SetCheck(r.m_AdvRendSets.iEVROutputRange == 1); + } +} + +void CMainFrame::OnUpdateViewFlushGPU(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + + if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_BEFOREVSYNC) { + pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUBeforeVSync); + } else if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_AFTERPRESENT) { + pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUAfterPresent); + } else if (pCmdUI->m_nID == ID_VIEW_FLUSHGPU_WAIT) { + pCmdUI->SetCheck(r.m_AdvRendSets.bVMRFlushGPUWait); + } + +} + +void CMainFrame::OnUpdateViewD3DFullscreen(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(s.fD3DFullscreen); +} + +void CMainFrame::OnUpdateViewDisableDesktopComposition(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D + && !IsWindows8OrGreater()); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(supported && r.m_AdvRendSets.bVMRDisableDesktopComposition); +} + +void CMainFrame::OnUpdateViewAlternativeVSync(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9AlterativeVSync); +} + +void CMainFrame::OnUpdateViewFullscreenGUISupport(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9FullscreenGUISupport); +} + +void CMainFrame::OnUpdateViewHighColorResolution(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM + || s.iDSVideoRendererType == VIDRNDT_DS_SYNC) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_b10bitSupport; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bEVRHighColorResolution); +} + +void CMainFrame::OnUpdateViewForceInputHighColorResolution(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_b10bitSupport; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bEVRForceInputHighColorResolution); +} + +void CMainFrame::OnUpdateViewFullFloatingPointProcessing(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP32Support; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9FullFloatingPointProcessing); +} + +void CMainFrame::OnUpdateViewHalfFloatingPointProcessing(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + const CRenderersData& rd = AfxGetMyApp()->m_Renderers; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && rd.m_bFP16Support; + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing); +} + +void CMainFrame::OnUpdateViewEnableFrameTimeCorrection(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = ((s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D); + + pCmdUI->Enable(supported); + pCmdUI->SetCheck(r.m_AdvRendSets.bEVREnableFrameTimeCorrection); +} + +void CMainFrame::OnUpdateViewVSyncOffsetIncrease(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || (((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && r.m_AdvRendSets.bVMR9AlterativeVSync); + + pCmdUI->Enable(supported); +} + +void CMainFrame::OnUpdateViewVSyncOffsetDecrease(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + bool supported = s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || (((s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS + || s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM) + && r.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D) + && r.m_AdvRendSets.bVMR9AlterativeVSync); + + pCmdUI->Enable(supported); +} + +void CMainFrame::OnViewVSync() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9VSync = !r.m_AdvRendSets.bVMR9VSync; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9VSync + ? IDS_OSD_RS_VSYNC_ON : IDS_OSD_RS_VSYNC_OFF)); +} + +void CMainFrame::OnViewVSyncAccurate() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9VSyncAccurate = !r.m_AdvRendSets.bVMR9VSyncAccurate; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9VSyncAccurate + ? IDS_OSD_RS_ACCURATE_VSYNC_ON : IDS_OSD_RS_ACCURATE_VSYNC_OFF)); +} + +void CMainFrame::OnViewSynchronizeVideo() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bSynchronizeVideo = !r.m_AdvRendSets.bSynchronizeVideo; + if (r.m_AdvRendSets.bSynchronizeVideo) { + r.m_AdvRendSets.bSynchronizeDisplay = false; + r.m_AdvRendSets.bSynchronizeNearest = false; + r.m_AdvRendSets.bVMR9VSync = false; + r.m_AdvRendSets.bVMR9VSyncAccurate = false; + r.m_AdvRendSets.bVMR9AlterativeVSync = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeVideo + ? IDS_OSD_RS_SYNC_TO_DISPLAY_ON : IDS_OSD_RS_SYNC_TO_DISPLAY_ON)); +} + +void CMainFrame::OnViewSynchronizeDisplay() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bSynchronizeDisplay = !r.m_AdvRendSets.bSynchronizeDisplay; + if (r.m_AdvRendSets.bSynchronizeDisplay) { + r.m_AdvRendSets.bSynchronizeVideo = false; + r.m_AdvRendSets.bSynchronizeNearest = false; + r.m_AdvRendSets.bVMR9VSync = false; + r.m_AdvRendSets.bVMR9VSyncAccurate = false; + r.m_AdvRendSets.bVMR9AlterativeVSync = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeDisplay + ? IDS_OSD_RS_SYNC_TO_VIDEO_ON : IDS_OSD_RS_SYNC_TO_VIDEO_ON)); +} + +void CMainFrame::OnViewSynchronizeNearest() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bSynchronizeNearest = !r.m_AdvRendSets.bSynchronizeNearest; + if (r.m_AdvRendSets.bSynchronizeNearest) { + r.m_AdvRendSets.bSynchronizeVideo = false; + r.m_AdvRendSets.bSynchronizeDisplay = false; + r.m_AdvRendSets.bVMR9VSync = false; + r.m_AdvRendSets.bVMR9VSyncAccurate = false; + r.m_AdvRendSets.bVMR9AlterativeVSync = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bSynchronizeNearest + ? IDS_OSD_RS_PRESENT_NEAREST_ON : IDS_OSD_RS_PRESENT_NEAREST_OFF)); +} + +void CMainFrame::OnViewColorManagementEnable() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9ColorManagementEnable = !r.m_AdvRendSets.bVMR9ColorManagementEnable; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9ColorManagementEnable + ? IDS_OSD_RS_COLOR_MANAGEMENT_ON : IDS_OSD_RS_COLOR_MANAGEMENT_OFF)); +} + +void CMainFrame::OnViewColorManagementInputAuto() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_UNKNOWN; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_AUTO)); +} + +void CMainFrame::OnViewColorManagementInputHDTV() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_HDTV; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_HDTV)); +} + +void CMainFrame::OnViewColorManagementInputSDTV_NTSC() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_SDTV_NTSC; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_SD_NTSC)); +} + +void CMainFrame::OnViewColorManagementInputSDTV_PAL() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementInput = VIDEO_SYSTEM_SDTV_PAL; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_INPUT_TYPE_SD_PAL)); +} + +void CMainFrame::OnViewColorManagementAmbientLightBright() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_BRIGHT; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_BRIGHT)); +} + +void CMainFrame::OnViewColorManagementAmbientLightDim() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_DIM; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_DIM)); +} + +void CMainFrame::OnViewColorManagementAmbientLightDark() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementAmbientLight = AMBIENT_LIGHT_DARK; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_AMBIENT_LIGHT_DARK)); +} + +void CMainFrame::OnViewColorManagementIntentPerceptual() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_PERCEPTUAL; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_PERCEPT)); +} + +void CMainFrame::OnViewColorManagementIntentRelativeColorimetric() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_RELATIVE)); +} + +void CMainFrame::OnViewColorManagementIntentSaturation() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_SATURATION; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_SATUR)); +} + +void CMainFrame::OnViewColorManagementIntentAbsoluteColorimetric() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iVMR9ColorManagementIntent = COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_REND_INTENT_ABSOLUTE)); +} + +void CMainFrame::OnViewEVROutputRange_0_255() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iEVROutputRange = 0; + CString strOSD; + strOSD.Format(IDS_OSD_RS_OUTPUT_RANGE, _T("0 - 255")); + m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); +} + +void CMainFrame::OnViewEVROutputRange_16_235() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.iEVROutputRange = 1; + CString strOSD; + strOSD.Format(IDS_OSD_RS_OUTPUT_RANGE, _T("16 - 235")); + m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); +} + +void CMainFrame::OnViewFlushGPUBeforeVSync() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMRFlushGPUBeforeVSync = !r.m_AdvRendSets.bVMRFlushGPUBeforeVSync; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUBeforeVSync + ? IDS_OSD_RS_FLUSH_BEF_VSYNC_ON : IDS_OSD_RS_FLUSH_BEF_VSYNC_OFF)); +} + +void CMainFrame::OnViewFlushGPUAfterVSync() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMRFlushGPUAfterPresent = !r.m_AdvRendSets.bVMRFlushGPUAfterPresent; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUAfterPresent + ? IDS_OSD_RS_FLUSH_AFT_PRES_ON : IDS_OSD_RS_FLUSH_AFT_PRES_OFF)); +} + +void CMainFrame::OnViewFlushGPUWait() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMRFlushGPUWait = !r.m_AdvRendSets.bVMRFlushGPUWait; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRFlushGPUWait + ? IDS_OSD_RS_WAIT_ON : IDS_OSD_RS_WAIT_OFF)); +} + +void CMainFrame::OnViewD3DFullScreen() +{ + CAppSettings& r = AfxGetAppSettings(); + r.fD3DFullscreen = !r.fD3DFullscreen; + r.SaveSettings(); + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.fD3DFullscreen + ? IDS_OSD_RS_D3D_FULLSCREEN_ON : IDS_OSD_RS_D3D_FULLSCREEN_OFF)); +} + +void CMainFrame::OnViewDisableDesktopComposition() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMRDisableDesktopComposition = !r.m_AdvRendSets.bVMRDisableDesktopComposition; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMRDisableDesktopComposition + ? IDS_OSD_RS_NO_DESKTOP_COMP_ON : IDS_OSD_RS_NO_DESKTOP_COMP_OFF)); +} + +void CMainFrame::OnViewAlternativeVSync() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9AlterativeVSync = !r.m_AdvRendSets.bVMR9AlterativeVSync; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9AlterativeVSync + ? IDS_OSD_RS_ALT_VSYNC_ON : IDS_OSD_RS_ALT_VSYNC_OFF)); +} + +void CMainFrame::OnViewResetDefault() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.SetDefault(); + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_RESET_DEFAULT)); +} + +void CMainFrame::OnViewResetOptimal() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.SetOptimal(); + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_OSD_RS_RESET_OPTIMAL)); +} + +void CMainFrame::OnViewFullscreenGUISupport() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9FullscreenGUISupport = !r.m_AdvRendSets.bVMR9FullscreenGUISupport; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9FullscreenGUISupport + ? IDS_OSD_RS_D3D_FS_GUI_SUPP_ON : IDS_OSD_RS_D3D_FS_GUI_SUPP_OFF)); +} + +void CMainFrame::OnViewHighColorResolution() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bEVRHighColorResolution = !r.m_AdvRendSets.bEVRHighColorResolution; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVRHighColorResolution + ? IDS_OSD_RS_10BIT_RBG_OUT_ON : IDS_OSD_RS_10BIT_RBG_OUT_OFF)); +} + +void CMainFrame::OnViewForceInputHighColorResolution() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bEVRForceInputHighColorResolution = !r.m_AdvRendSets.bEVRForceInputHighColorResolution; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVRForceInputHighColorResolution + ? IDS_OSD_RS_10BIT_RBG_IN_ON : IDS_OSD_RS_10BIT_RBG_IN_OFF)); +} + +void CMainFrame::OnViewFullFloatingPointProcessing() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + if (!r.m_AdvRendSets.bVMR9FullFloatingPointProcessing) { + if (AfxMessageBox(_T("WARNING: Full Floating Point processing can sometimes cause problems. With some videos it can cause the player to freeze, crash, or display corrupted video. This happens mostly with Intel GPUs.\n\nAre you really sure that you want to enable this setting?"), MB_YESNO) == IDNO) { + return; + } + } + r.m_AdvRendSets.bVMR9FullFloatingPointProcessing = !r.m_AdvRendSets.bVMR9FullFloatingPointProcessing; + if (r.m_AdvRendSets.bVMR9FullFloatingPointProcessing) { + r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9FullFloatingPointProcessing + ? IDS_OSD_RS_FULL_FP_PROCESS_ON : IDS_OSD_RS_FULL_FP_PROCESS_OFF)); +} + +void CMainFrame::OnViewHalfFloatingPointProcessing() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing = !r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing; + if (r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing) { + r.m_AdvRendSets.bVMR9FullFloatingPointProcessing = false; + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bVMR9HalfFloatingPointProcessing + ? IDS_OSD_RS_HALF_FP_PROCESS_ON : IDS_OSD_RS_HALF_FP_PROCESS_OFF)); +} + +void CMainFrame::OnViewEnableFrameTimeCorrection() +{ + CRenderersSettings& r = AfxGetAppSettings().m_RenderersSettings; + r.m_AdvRendSets.bEVREnableFrameTimeCorrection = !r.m_AdvRendSets.bEVREnableFrameTimeCorrection; + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(r.m_AdvRendSets.bEVREnableFrameTimeCorrection + ? IDS_OSD_RS_FT_CORRECTION_ON : IDS_OSD_RS_FT_CORRECTION_OFF)); +} + +void CMainFrame::OnViewVSyncOffsetIncrease() +{ + CAppSettings& s = AfxGetAppSettings(); + CRenderersSettings& r = s.m_RenderersSettings; + CString strOSD; + if (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { + r.m_AdvRendSets.fTargetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset - 0.5; // Yeah, it should be a "-" + strOSD.Format(IDS_OSD_RS_TARGET_VSYNC_OFFSET, r.m_AdvRendSets.fTargetSyncOffset); + } else { + ++r.m_AdvRendSets.iVMR9VSyncOffset; + strOSD.Format(IDS_OSD_RS_VSYNC_OFFSET, r.m_AdvRendSets.iVMR9VSyncOffset); + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); +} + +void CMainFrame::OnViewVSyncOffsetDecrease() +{ + CAppSettings& s = AfxGetAppSettings(); + CRenderersSettings& r = s.m_RenderersSettings; + CString strOSD; + if (s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { + r.m_AdvRendSets.fTargetSyncOffset = r.m_AdvRendSets.fTargetSyncOffset + 0.5; + strOSD.Format(IDS_OSD_RS_TARGET_VSYNC_OFFSET, r.m_AdvRendSets.fTargetSyncOffset); + } else { + --r.m_AdvRendSets.iVMR9VSyncOffset; + strOSD.Format(IDS_OSD_RS_VSYNC_OFFSET, r.m_AdvRendSets.iVMR9VSyncOffset); + } + m_OSD.DisplayMessage(OSD_TOPRIGHT, strOSD); +} + +void CMainFrame::OnUpdateViewOSDDisplayTime(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(s.fShowOSD && GetLoadState() != MLS::CLOSED); + pCmdUI->SetCheck(AfxGetAppSettings().fShowCurrentTimeInOSD); +} + +void CMainFrame::OnViewOSDDisplayTime() +{ + auto &showTime = AfxGetAppSettings().fShowCurrentTimeInOSD; + showTime = !showTime; + + if (!showTime) { + m_OSD.ClearTime(); + } + + OnTimer(TIMER_STREAMPOSPOLLER2); +} + +void CMainFrame::OnUpdateViewOSDShowFileName(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(s.fShowOSD && GetLoadState() != MLS::CLOSED); +} + +void CMainFrame::OnViewOSDShowFileName() +{ + CString strOSD; + switch (GetPlaybackMode()) { + case PM_FILE: + strOSD = GetFileName(); + break; + case PM_DVD: + strOSD = _T("DVD"); + if (m_pDVDI) { + CString path; + ULONG len = 0; + if (SUCCEEDED(m_pDVDI->GetDVDDirectory(path.GetBuffer(MAX_PATH), MAX_PATH, &len)) && len) { + path.ReleaseBuffer(); + if (path.Find(_T("\\VIDEO_TS")) == 2) { + strOSD.AppendFormat(_T(" - %s"), GetDriveLabel(CPath(path)).GetString()); + } else { + strOSD.AppendFormat(_T(" - %s"), path.GetString()); + } + } + } + break; + case PM_ANALOG_CAPTURE: + strOSD = GetCaptureTitle(); + break; + case PM_DIGITAL_CAPTURE: + UpdateCurrentChannelInfo(true, false); + break; + default: // Shouldn't happen + ASSERT(FALSE); + return; + } + if (!strOSD.IsEmpty()) { + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD); + } +} + +void CMainFrame::OnUpdateShaderToggle1(CCmdUI* pCmdUI) +{ + if (AfxGetAppSettings().m_Shaders.GetCurrentPreset().GetPreResize().empty()) { + pCmdUI->Enable(FALSE); + pCmdUI->SetCheck (0); + } else { + pCmdUI->Enable(TRUE); + pCmdUI->SetCheck (m_bToggleShader); + } +} + +void CMainFrame::OnUpdateShaderToggle2(CCmdUI* pCmdUI) +{ + CAppSettings& s = AfxGetAppSettings(); + + if (s.m_Shaders.GetCurrentPreset().GetPostResize().empty()) { + pCmdUI->Enable(FALSE); + pCmdUI->SetCheck(0); + } else { + pCmdUI->Enable(TRUE); + pCmdUI->SetCheck(m_bToggleShaderScreenSpace); + } +} + +void CMainFrame::OnShaderToggle1() +{ + m_bToggleShader = !m_bToggleShader; + SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); + if (m_bToggleShader) { + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_PRESIZE_SHADERS_ENABLED)); + } else { + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_PRESIZE_SHADERS_DISABLED)); + } + + if (m_pCAP) { + RepaintVideo(); + } +} + +void CMainFrame::OnShaderToggle2() +{ + m_bToggleShaderScreenSpace = !m_bToggleShaderScreenSpace; + SetShaders(m_bToggleShader, m_bToggleShaderScreenSpace); + if (m_bToggleShaderScreenSpace) { + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_POSTSIZE_SHADERS_ENABLED)); + } else { + m_OSD.DisplayMessage(OSD_TOPRIGHT, ResStr(IDS_POSTSIZE_SHADERS_DISABLED)); + } + + if (m_pCAP) { + RepaintVideo(); + } +} + +void CMainFrame::OnD3DFullscreenToggle() +{ + CAppSettings& s = AfxGetAppSettings(); + CString strMsg; + + s.fD3DFullscreen = !s.fD3DFullscreen; + strMsg.LoadString(s.fD3DFullscreen ? IDS_OSD_RS_D3D_FULLSCREEN_ON : IDS_OSD_RS_D3D_FULLSCREEN_OFF); + if (GetLoadState() == MLS::CLOSED) { + m_closingmsg = strMsg; + } else { + m_OSD.DisplayMessage(OSD_TOPRIGHT, strMsg); + } +} + +void CMainFrame::OnFileCloseAndRestore() +{ + if (GetLoadState() == MLS::LOADED && IsFullScreenMode()) { + // exit fullscreen + OnViewFullscreen(); + } + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + RestoreDefaultWindowRect(); +} + +void CMainFrame::OnUpdateFileClose(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED || GetLoadState() == MLS::LOADING); +} + +// view + +void CMainFrame::SetCaptionState(MpcCaptionState eState) +{ + auto& s = AfxGetAppSettings(); + + if (eState == s.eCaptionMenuMode) { + return; + } + + const auto eOldState = s.eCaptionMenuMode; + s.eCaptionMenuMode = eState; + + if (IsFullScreenMainFrame()) { + return; + } + + DWORD dwRemove = 0, dwAdd = 0; + DWORD dwMenuFlags = GetMenuBarVisibility(); + + CRect windowRect; + + const bool bZoomed = !!IsZoomed(); + + if (!bZoomed) { + GetWindowRect(&windowRect); + CRect decorationsRect; + VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), dwMenuFlags == AFX_MBV_KEEPVISIBLE, GetWindowExStyle(m_hWnd))); + windowRect.bottom -= decorationsRect.bottom; + windowRect.right -= decorationsRect.right; + windowRect.top -= decorationsRect.top; + windowRect.left -= decorationsRect.left; + } + + const int base = MpcCaptionState::MODE_COUNT; + for (int i = eOldState; i != eState; i = (i + 1) % base) { + switch (static_cast(i)) { + case MpcCaptionState::MODE_BORDERLESS: + dwMenuFlags = AFX_MBV_KEEPVISIBLE; + dwAdd |= (WS_CAPTION | WS_THICKFRAME); + dwRemove &= ~(WS_CAPTION | WS_THICKFRAME); + break; + case MpcCaptionState::MODE_SHOWCAPTIONMENU: + dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; + break; + case MpcCaptionState::MODE_HIDEMENU: + dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; + dwAdd &= ~WS_CAPTION; + dwRemove |= WS_CAPTION; + break; + case MpcCaptionState::MODE_FRAMEONLY: + dwMenuFlags = AFX_MBV_DISPLAYONFOCUS; + dwAdd &= ~WS_THICKFRAME; + dwRemove |= WS_THICKFRAME; + break; + default: + ASSERT(FALSE); + } + } + + UINT uFlags = SWP_NOZORDER; + if (dwRemove != dwAdd) { + uFlags |= SWP_FRAMECHANGED; + VERIFY(SetWindowLong(m_hWnd, GWL_STYLE, (GetWindowLong(m_hWnd, GWL_STYLE) | dwAdd) & ~dwRemove)); + } + + SetMenuBarVisibility(dwMenuFlags); + if (bZoomed) { + CMonitors::GetNearestMonitor(this).GetWorkAreaRect(windowRect); + } else { + VERIFY(AdjustWindowRectEx(windowRect, GetWindowStyle(m_hWnd), dwMenuFlags == AFX_MBV_KEEPVISIBLE, GetWindowExStyle(m_hWnd))); + } + + VERIFY(SetWindowPos(nullptr, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), uFlags)); + OSDBarSetPos(); +} + +void CMainFrame::OnViewCaptionmenu() +{ + const auto& s = AfxGetAppSettings(); + SetCaptionState(static_cast((s.eCaptionMenuMode + 1) % MpcCaptionState::MODE_COUNT)); +} + +void CMainFrame::OnUpdateViewCaptionmenu(CCmdUI* pCmdUI) +{ + const auto& s = AfxGetAppSettings(); + const UINT next[] = { IDS_VIEW_HIDEMENU, IDS_VIEW_FRAMEONLY, IDS_VIEW_BORDERLESS, IDS_VIEW_CAPTIONMENU }; + pCmdUI->SetText(ResStr(next[s.eCaptionMenuMode % MpcCaptionState::MODE_COUNT])); + CMPCThemeMenu::updateItem(pCmdUI); +} + +void CMainFrame::OnViewControlBar(UINT nID) +{ + nID -= ID_VIEW_SEEKER; + m_controls.ToggleControl(static_cast(nID)); +} + +void CMainFrame::OnUpdateViewControlBar(CCmdUI* pCmdUI) +{ + const UINT nID = pCmdUI->m_nID - ID_VIEW_SEEKER; + pCmdUI->SetCheck(m_controls.ControlChecked(static_cast(nID))); + if (pCmdUI->m_nID == ID_VIEW_SEEKER) { + pCmdUI->Enable(!IsPlaybackCaptureMode()); + } +} + +void CMainFrame::OnViewSubresync() +{ + m_controls.ToggleControl(CMainFrameControls::Panel::SUBRESYNC); + AdjustStreamPosPoller(true); +} + +void CMainFrame::OnUpdateViewSubresync(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::SUBRESYNC)); + bool enabled = m_pCAP && m_pCurrentSubInput.pSubStream && !IsPlaybackCaptureMode(); + if (enabled) { + CLSID clsid; + m_pCurrentSubInput.pSubStream->GetClassID(&clsid); + if (clsid == __uuidof(CRenderedTextSubtitle)) { +#if USE_LIBASS + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; + enabled = !pRTS->m_LibassContext.IsLibassActive(); +#endif + } else { + enabled = false; + } + } + pCmdUI->Enable(enabled); +} + +void CMainFrame::OnViewPlaylist() +{ + m_controls.ToggleControl(CMainFrameControls::Panel::PLAYLIST); + m_wndPlaylistBar.SetHiddenDueToFullscreen(false); +} + +void CMainFrame::OnUpdateViewPlaylist(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)); +} + +void CMainFrame::OnPlaylistToggleShuffle() { + CAppSettings& s = AfxGetAppSettings(); + s.bShufflePlaylistItems = !s.bShufflePlaylistItems; + m_wndPlaylistBar.m_pl.SetShuffle(s.bShufflePlaylistItems); +} + +void CMainFrame::OnViewEditListEditor() +{ + CAppSettings& s = AfxGetAppSettings(); + + if (s.fEnableEDLEditor || (AfxMessageBox(IDS_MB_SHOW_EDL_EDITOR, MB_ICONQUESTION | MB_YESNO, 0) == IDYES)) { + s.fEnableEDLEditor = true; + m_controls.ToggleControl(CMainFrameControls::Panel::EDL); + } +} + +void CMainFrame::OnEDLIn() +{ + if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { + REFERENCE_TIME rt; + + m_pMS->GetCurrentPosition(&rt); + m_wndEditListEditor.SetIn(rt); + } +} + +void CMainFrame::OnUpdateEDLIn(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); +} + +void CMainFrame::OnEDLOut() +{ + if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { + REFERENCE_TIME rt; + + m_pMS->GetCurrentPosition(&rt); + m_wndEditListEditor.SetOut(rt); + } +} + +void CMainFrame::OnUpdateEDLOut(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); +} + +void CMainFrame::OnEDLNewClip() +{ + if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { + REFERENCE_TIME rt; + + m_pMS->GetCurrentPosition(&rt); + m_wndEditListEditor.NewClip(rt); + } +} + +void CMainFrame::OnUpdateEDLNewClip(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); +} + +void CMainFrame::OnEDLSave() +{ + if (AfxGetAppSettings().fEnableEDLEditor && (GetLoadState() == MLS::LOADED) && (GetPlaybackMode() == PM_FILE)) { + m_wndEditListEditor.Save(); + } +} + +void CMainFrame::OnUpdateEDLSave(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(m_controls.ControlChecked(CMainFrameControls::Panel::EDL)); +} + +// Navigation menu +void CMainFrame::OnViewNavigation() +{ + const bool bHiding = m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION); + m_controls.ToggleControl(CMainFrameControls::Panel::NAVIGATION); + if (!bHiding) { + m_wndNavigationBar.m_navdlg.UpdateElementList(); + } + AfxGetAppSettings().fHideNavigation = bHiding; +} + +void CMainFrame::OnUpdateViewNavigation(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_DIGITAL_CAPTURE); +} + +void CMainFrame::OnViewCapture() +{ + m_controls.ToggleControl(CMainFrameControls::Panel::CAPTURE); +} + +void CMainFrame::OnUpdateViewCapture(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(m_controls.ControlChecked(CMainFrameControls::Panel::CAPTURE)); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_ANALOG_CAPTURE); +} + +void CMainFrame::OnViewDebugShaders() +{ + auto& dlg = m_pDebugShaders; + if (dlg && !dlg->m_hWnd) { + // something has destroyed the dialog and we didn't know about it + dlg = nullptr; + } + if (!dlg) { + // dialog doesn't exist - create and show it + dlg = std::make_unique(); + dlg->ShowWindow(SW_SHOW); + } else if (dlg->IsWindowVisible()) { + if (dlg->IsIconic()) { + // dialog is visible but iconic - restore it + VERIFY(dlg->ShowWindow(SW_RESTORE)); + } else { + // dialog is visible and not iconic - destroy it + VERIFY(dlg->DestroyWindow()); + ASSERT(!dlg->m_hWnd); + dlg = nullptr; + } + } else { + // dialog is not visible - show it + VERIFY(!dlg->ShowWindow(SW_SHOW)); + } +} + +void CMainFrame::OnUpdateViewDebugShaders(CCmdUI* pCmdUI) +{ + const auto& dlg = m_pDebugShaders; + pCmdUI->SetCheck(dlg && dlg->m_hWnd && dlg->IsWindowVisible()); +} + +void CMainFrame::OnViewMinimal() +{ + SetCaptionState(MODE_BORDERLESS); + m_controls.SetToolbarsSelection(CS_NONE, true); +} + +void CMainFrame::OnUpdateViewMinimal(CCmdUI* pCmdUI) +{ +} + +void CMainFrame::OnViewCompact() +{ + SetCaptionState(MODE_FRAMEONLY); + m_controls.SetToolbarsSelection(CS_SEEKBAR, true); +} + +void CMainFrame::OnUpdateViewCompact(CCmdUI* pCmdUI) +{ +} + +void CMainFrame::OnViewNormal() +{ + SetCaptionState(MODE_SHOWCAPTIONMENU); + m_controls.SetToolbarsSelection(CS_SEEKBAR | CS_TOOLBAR | CS_STATUSBAR, true); +} + +void CMainFrame::OnUpdateViewNormal(CCmdUI* pCmdUI) +{ +} + +void CMainFrame::OnViewFullscreen() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (IsD3DFullScreenMode() || (s.IsD3DFullscreen() && !m_fFullScreen && !m_fAudioOnly && m_pD3DFSC && m_pMFVDC)) { + ToggleD3DFullscreen(true); + } else { + ToggleFullscreen(true, true); + } +} + +void CMainFrame::OnViewFullscreenSecondary() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (IsD3DFullScreenMode() || (s.IsD3DFullscreen() && !m_fFullScreen && !m_fAudioOnly && m_pD3DFSC && m_pMFVDC)) { + ToggleD3DFullscreen(false); + } else { + ToggleFullscreen(true, false); + } +} + +void CMainFrame::OnUpdateViewFullscreen(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED || m_fFullScreen); + pCmdUI->SetCheck(m_fFullScreen); +} + +void CMainFrame::OnViewZoom(UINT nID) +{ + double scale = (nID == ID_VIEW_ZOOM_25) ? 0.25 : (nID == ID_VIEW_ZOOM_50) ? 0.5 : (nID == ID_VIEW_ZOOM_200) ? 2.0 : 1.0; + + ZoomVideoWindow(scale); + + CString strODSMessage; + strODSMessage.Format(IDS_OSD_ZOOM, scale * 100); + m_OSD.DisplayMessage(OSD_TOPLEFT, strODSMessage, 3000); +} + +void CMainFrame::OnUpdateViewZoom(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly); +} + +void CMainFrame::OnViewZoomAutoFit() +{ + ZoomVideoWindow(ZOOM_AUTOFIT); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_ZOOM_AUTO), 3000); +} + +void CMainFrame::OnViewZoomAutoFitLarger() +{ + ZoomVideoWindow(ZOOM_AUTOFIT_LARGER); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_ZOOM_AUTO_LARGER), 3000); +} + +void CMainFrame::OnViewModifySize(UINT nID) { + if (m_fFullScreen || !m_pVideoWnd || IsZoomed() || IsIconic() || GetLoadState() != MLS::LOADED) { + return; + } + + enum resizeMethod { + autoChoose + , byHeight + , byWidth + } usedMethod; + + const CAppSettings& s = AfxGetAppSettings(); + MINMAXINFO mmi; + CSize videoSize = GetVideoOrArtSize(mmi); + int minWidth = (int)mmi.ptMinTrackSize.x; + + int mult = (nID == ID_VIEW_ZOOM_ADD ? 1 : ID_VIEW_ZOOM_SUB ? -1 : 0); + + double videoRatio = double(videoSize.cy) / double(videoSize.cx); + + CRect videoRect, workRect, maxRect; + videoRect = m_pVideoWnd->GetVideoRect(); + double videoRectRatio = double(videoRect.Height()) / double(videoRect.Width()); + bool previouslyProportional = IsNearlyEqual(videoRectRatio, videoRatio, 0.01); + + GetWorkAreaRect(workRect); + maxRect = GetZoomWindowRect(CSize(INT_MAX, INT_MAX), true); + + CRect rect, zoomRect; + GetWindowRect(&rect); + CSize targetSize; + + auto calculateZoomWindowRect = [&](resizeMethod useMethod = autoChoose, CSize forceDimension = {0,0}) { + int newWidth = videoRect.Width(); + int newHeight = videoRect.Height(); + + if (useMethod == autoChoose) { + if (double(videoRect.Height()) / videoRect.Width() + 0.01f < videoRatio) { //wider than aspect ratio, so use height instead + useMethod = byHeight; + int growPixels = int(.02f * workRect.Height()); + newHeight = videoRect.Height() + growPixels * mult; + } else { + useMethod = byWidth; + int growPixels = int(.02f * workRect.Width()); + newWidth = std::max(videoRect.Width() + growPixels * mult, minWidth); + } + } else if (useMethod == byHeight) { + newHeight = forceDimension.cy + videoRect.Height() - rect.Height(); + } else { + newWidth = forceDimension.cx + videoRect.Width() - rect.Width(); + } + + if (useMethod == byHeight) { + double newRatio = double(newHeight) / double(videoRect.Width()); + if (s.fLimitWindowProportions || previouslyProportional || SGN(newRatio - videoRatio) != SGN(videoRectRatio - videoRatio)) { + newWidth = std::max(int(ceil(newHeight / videoRatio)), minWidth); + if (mult == 1) { + newWidth = std::max(newWidth, videoRect.Width()); + } + } + } else { + double newRatio = double(videoRect.Height()) / double(newWidth); + if (s.fLimitWindowProportions || previouslyProportional || SGN(newRatio - videoRatio) != SGN(videoRectRatio - videoRatio)) { + newHeight = int(ceil(newWidth * videoRatio)); + if (mult == 1) { + newHeight = std::max(newHeight, videoRect.Height()); + } + } + } + targetSize = rect.Size() + CSize(newWidth - videoRect.Width(), newHeight - videoRect.Height()); + usedMethod = useMethod; + return GetZoomWindowRect(targetSize, true); + }; + + zoomRect = calculateZoomWindowRect(); + + CRect newRect, work; + newRect = CRect(rect.TopLeft(), targetSize); //this will be our default + + //if old rect was constrained to a single monitor, we zoom incrementally + if (GetWorkAreaRect(work) && work.PtInRect(rect.TopLeft()) && work.PtInRect(rect.BottomRight()-CSize(1,1)) + && ((zoomRect.Height() != rect.Height() && usedMethod == byHeight) || (zoomRect.Width() != rect.Width() && usedMethod == byWidth))) { + + if (zoomRect.Width() != targetSize.cx && zoomRect.Width() == maxRect.Width()) { //we appear to have been constrained by Screen Width + if (maxRect.Width() != rect.Width()) { //if it wasn't already filling the monitor horizonally, we will do that now + newRect = calculateZoomWindowRect(byWidth, maxRect.Size()); + } + } else if (zoomRect.Height() != targetSize.cy && zoomRect.Height() == maxRect.Height()) { //we appear to have been constrained by Screen Height + if (maxRect.Height() != rect.Height()) { //if it wasn't already filling the monitor vertically, we will do that now + newRect = calculateZoomWindowRect(byHeight, maxRect.Size()); + } + } else { + newRect = zoomRect; + } + } + + MoveWindow(newRect); +} + +void CMainFrame::OnViewDefaultVideoFrame(UINT nID) +{ + AfxGetAppSettings().iDefaultVideoSize = nID - ID_VIEW_VF_HALF; + m_ZoomX = m_ZoomY = 1; + m_PosX = m_PosY = 0.5; + MoveVideoWindow(); +} + +void CMainFrame::OnUpdateViewDefaultVideoFrame(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && s.iDSVideoRendererType != VIDRNDT_DS_EVR); + + int dvs = pCmdUI->m_nID - ID_VIEW_VF_HALF; + if (s.iDefaultVideoSize == dvs && pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_VIEW_VF_HALF, ID_VIEW_VF_ZOOM2, pCmdUI->m_nID, MF_BYCOMMAND); + } +} + +void CMainFrame::OnViewSwitchVideoFrame() +{ + CAppSettings& s = AfxGetAppSettings(); + + int vs = s.iDefaultVideoSize; + if (vs <= DVS_DOUBLE || vs == DVS_FROMOUTSIDE) { + vs = DVS_STRETCH; + } else if (vs == DVS_FROMINSIDE) { + vs = DVS_ZOOM1; + } else if (vs == DVS_ZOOM2) { + vs = DVS_FROMOUTSIDE; + } else { + vs++; + } + switch (vs) { // TODO: Read messages from resource file + case DVS_STRETCH: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_STRETCH_TO_WINDOW)); + break; + case DVS_FROMINSIDE: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_TOUCH_WINDOW_FROM_INSIDE)); + break; + case DVS_ZOOM1: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_ZOOM1)); + break; + case DVS_ZOOM2: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_ZOOM2)); + break; + case DVS_FROMOUTSIDE: + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_TOUCH_WINDOW_FROM_OUTSIDE)); + break; + } + s.iDefaultVideoSize = vs; + m_ZoomX = m_ZoomY = 1; + m_PosX = m_PosY = 0.5; + MoveVideoWindow(); +} + +void CMainFrame::OnViewCompMonDeskARDiff() +{ + CAppSettings& s = AfxGetAppSettings(); + + s.fCompMonDeskARDiff = !s.fCompMonDeskARDiff; + OnVideoSizeChanged(); +} + +void CMainFrame::OnUpdateViewCompMonDeskARDiff(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + + pCmdUI->Enable(GetLoadState() == MLS::LOADED + && !m_fAudioOnly + && s.iDSVideoRendererType != VIDRNDT_DS_EVR + // This doesn't work with madVR due to the fact that it positions video itself. + // And it has exactly the same option built in. + && s.iDSVideoRendererType != VIDRNDT_DS_MADVR); + pCmdUI->SetCheck(s.fCompMonDeskARDiff); +} + +void CMainFrame::OnViewPanNScan(UINT nID) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + int x = 0, y = 0; + int dx = 0, dy = 0; + + switch (nID) { + case ID_VIEW_RESET: + // Subtitle overrides + ResetSubtitlePosAndSize(true); + // Pan&Scan + m_ZoomX = m_ZoomY = 1.0; + m_PosX = m_PosY = 0.5; + m_AngleX = m_AngleY = m_AngleZ = 0; + PerformFlipRotate(); + break; + case ID_VIEW_INCSIZE: + x = y = 1; + break; + case ID_VIEW_DECSIZE: + x = y = -1; + break; + case ID_VIEW_INCWIDTH: + x = 1; + break; + case ID_VIEW_DECWIDTH: + x = -1; + break; + case ID_VIEW_INCHEIGHT: + y = 1; + break; + case ID_VIEW_DECHEIGHT: + y = -1; + break; + case ID_PANSCAN_CENTER: + m_PosX = m_PosY = 0.5; + break; + case ID_PANSCAN_MOVELEFT: + dx = -1; + break; + case ID_PANSCAN_MOVERIGHT: + dx = 1; + break; + case ID_PANSCAN_MOVEUP: + dy = -1; + break; + case ID_PANSCAN_MOVEDOWN: + dy = 1; + break; + case ID_PANSCAN_MOVEUPLEFT: + dx = dy = -1; + break; + case ID_PANSCAN_MOVEUPRIGHT: + dx = 1; + dy = -1; + break; + case ID_PANSCAN_MOVEDOWNLEFT: + dx = -1; + dy = 1; + break; + case ID_PANSCAN_MOVEDOWNRIGHT: + dx = dy = 1; + break; + default: + break; + } + + if (x > 0 && m_ZoomX < 5.0) { + m_ZoomX = std::min(m_ZoomX * 1.02, 5.0); + } else if (x < 0 && m_ZoomX > 0.2) { + m_ZoomX = std::max(m_ZoomX / 1.02, 0.2); + } + + if (y > 0 && m_ZoomY < 5.0) { + m_ZoomY = std::min(m_ZoomY * 1.02, 5.0); + } else if (y < 0 && m_ZoomY > 0.2) { + m_ZoomY = std::max(m_ZoomY / 1.02, 0.2); + } + + if (dx < 0 && m_PosX > -0.5) { + m_PosX = std::max(m_PosX - 0.005 * m_ZoomX, -0.5); + } else if (dx > 0 && m_PosX < 1.5) { + m_PosX = std::min(m_PosX + 0.005 * m_ZoomX, 1.5); + } + + if (dy < 0 && m_PosY > -0.5) { + m_PosY = std::max(m_PosY - 0.005 * m_ZoomY, -0.5); + } else if (dy > 0 && m_PosY < 1.5) { + m_PosY = std::min(m_PosY + 0.005 * m_ZoomY, 1.5); + } + + MoveVideoWindow(true); +} + +void CMainFrame::OnUpdateViewPanNScan(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && AfxGetAppSettings().iDSVideoRendererType != VIDRNDT_DS_EVR); +} + +void CMainFrame::ApplyPanNScanPresetString() +{ + auto& s = AfxGetAppSettings(); + + if (s.strPnSPreset.IsEmpty()) + return; + + if (s.strPnSPreset.Find(',') != -1) { // try to set raw values + if (_stscanf_s(s.strPnSPreset, _T("%lf,%lf,%lf,%lf"), &m_PosX, &m_PosY, &m_ZoomX, &m_ZoomY) == 4) { + ValidatePanNScanParameters(); + MoveVideoWindow(); + } + } else { // try to set named preset + for (int i = 0; i < s.m_pnspresets.GetCount(); i++) { + int j = 0; + CString str = s.m_pnspresets[i]; + CString label = str.Tokenize(_T(","), j); + if (s.strPnSPreset == label) { + OnViewPanNScanPresets(i + ID_PANNSCAN_PRESETS_START); + } + } + } + + s.strPnSPreset.Empty(); +} + +void CMainFrame::OnViewPanNScanPresets(UINT nID) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + + nID -= ID_PANNSCAN_PRESETS_START; + + if ((INT_PTR)nID == s.m_pnspresets.GetCount()) { + CPnSPresetsDlg dlg; + dlg.m_pnspresets.Copy(s.m_pnspresets); + if (dlg.DoModal() == IDOK) { + s.m_pnspresets.Copy(dlg.m_pnspresets); + s.SaveSettings(); + } + return; + } + + m_PosX = 0.5; + m_PosY = 0.5; + m_ZoomX = 1.0; + m_ZoomY = 1.0; + + CString str = s.m_pnspresets[nID]; + + int i = 0, j = 0; + for (CString token = str.Tokenize(_T(","), i); !token.IsEmpty(); token = str.Tokenize(_T(","), i), j++) { + float f = 0; + if (_stscanf_s(token, _T("%f"), &f) != 1) { + continue; + } + + switch (j) { + case 0: + break; + case 1: + m_PosX = f; + break; + case 2: + m_PosY = f; + break; + case 3: + m_ZoomX = f; + break; + case 4: + m_ZoomY = f; + break; + default: + break; + } + } + + if (j != 5) { + return; + } + + ValidatePanNScanParameters(); + + MoveVideoWindow(true); +} + +void CMainFrame::ValidatePanNScanParameters() +{ + m_PosX = std::min(std::max(m_PosX, -0.5), 1.5); + m_PosY = std::min(std::max(m_PosY, -0.5), 1.5); + m_ZoomX = std::min(std::max(m_ZoomX, 0.2), 5.0); + m_ZoomY = std::min(std::max(m_ZoomY, 0.2), 5.0); +} + +void CMainFrame::OnUpdateViewPanNScanPresets(CCmdUI* pCmdUI) +{ + int nID = pCmdUI->m_nID - ID_PANNSCAN_PRESETS_START; + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && nID >= 0 && nID <= s.m_pnspresets.GetCount() && s.iDSVideoRendererType != VIDRNDT_DS_EVR); +} + +int nearest90(int angle) { + return int(float(angle) / 90 + 0.5) * 90; +} + +bool CMainFrame::PerformFlipRotate() +{ + HRESULT hr = E_NOTIMPL; + // Note: m_AngleZ is counterclockwise, so value 270 means rotated 90 degrees clockwise + if (m_pCAP3) { + bool isFlip = m_AngleX == 180; + bool isMirror = m_AngleY == 180; + int rotation = (360 - m_AngleZ + m_iDefRotation) % 360; + if (m_pMVRS) { + // MadVR: does not support mirror, instead of flip we rotate 180 degrees + hr = m_pCAP3->SetRotation(isFlip ? (rotation + 180) % 360 : rotation); + } else { + // MPCVR: instead of flip, we mirror plus rotate 180 degrees + hr = m_pCAP3->SetRotation(isFlip ? (rotation + 180) % 360 : rotation); + if (SUCCEEDED(hr)) { + // SetFlip actually mirrors instead of doing vertical flip + hr = m_pCAP3->SetFlip(isFlip || isMirror); + } + } + } else if (m_pCAP) { + // EVR-CP behavior for custom angles is ignored when choosing video size and zoom + // We get better results if we treat the closest 90 as the standard rotation, and custom rotate the remainder (<45deg) + int z = m_AngleZ; + if (m_pCAP2) { + int nZ = nearest90(z); + z = (z - nZ + 360) % 360; + Vector defAngle = Vector(0, 0, Vector::DegToRad((nZ - m_iDefRotation + 360) % 360)); + m_pCAP2->SetDefaultVideoAngle(defAngle); + } + + hr = m_pCAP->SetVideoAngle(Vector(Vector::DegToRad(m_AngleX), Vector::DegToRad(m_AngleY), Vector::DegToRad(z))); + } + + if (FAILED(hr)) { + m_AngleX = m_AngleY = m_AngleZ = 0; + return false; + } + if (m_pCAP2_preview) { //we support rotating preview + PreviewWindowHide(); + m_wndPreView.SetWindowSize(); + SetPreviewVideoPosition(); + //adipose: using defaultvideoangle instead of videoangle, as some oddity with AR shows up when using normal rotate with EVRCP. + //Since we only need to support 4 angles, this will work, but it *should* work with SetVideoAngle... + + hr = m_pCAP2_preview->SetDefaultVideoAngle(Vector(Vector::DegToRad(nearest90(m_AngleX)), Vector::DegToRad(nearest90(m_AngleY)), Vector::DegToRad(defaultVideoAngle + nearest90(m_AngleZ)))); + } + + return true; +} + +void CMainFrame::OnViewRotate(UINT nID) +{ + switch (nID) { + case ID_PANSCAN_ROTATEXP: + if (!m_pCAP3) { + m_AngleX += 2; + break; + } + [[fallthrough]]; // fall through for m_pCAP3 + case ID_PANSCAN_ROTATEXM: + if (m_AngleX >= 180) { + m_AngleX = 0; + } else { + m_AngleX = 180; + } + break; + case ID_PANSCAN_ROTATEYP: + if (!m_pCAP3) { + m_AngleY += 2; + break; + } + [[fallthrough]]; + case ID_PANSCAN_ROTATEYM: + if (m_AngleY >= 180) { + m_AngleY = 0; + } else { + m_AngleY = 180; + } + break; + case ID_PANSCAN_ROTATEZM: + if (m_AngleZ == 0 || m_AngleZ > 270) { + m_AngleZ = 270; + } else if (m_AngleZ > 180) { + m_AngleZ = 180; + } else if (m_AngleZ > 90) { + m_AngleZ = 90; + } else if (m_AngleZ > 0) { + m_AngleZ = 0; + } + break; + case ID_PANSCAN_ROTATEZP: + if (!m_pCAP3) { + m_AngleZ += 2; + break; + } + [[fallthrough]]; + case ID_PANSCAN_ROTATEZ270: + if (m_AngleZ < 90) { + m_AngleZ = 90; + } else if (m_AngleZ >= 270) { + m_AngleZ = 0; + } else if (m_AngleZ >= 180) { + m_AngleZ = 270; + } else if (m_AngleZ >= 90) { + m_AngleZ = 180; + } + break; + default: + return; + } + + m_AngleX %= 360; + m_AngleY %= 360; + if (m_AngleX == 180 && m_AngleY == 180) { + m_AngleX = m_AngleY = 0; + m_AngleZ += 180; + } + m_AngleZ %= 360; + + ASSERT(m_AngleX >= 0); + ASSERT(m_AngleY >= 0); + ASSERT(m_AngleZ >= 0); + + if (PerformFlipRotate()) { + // FIXME: do proper resizing of the window after rotate + if (!m_pMVRC) { + MoveVideoWindow(); + } + + CString info; + info.Format(_T("x: %d, y: %d, z: %d"), m_AngleX, m_AngleY, m_AngleZ); + SendStatusMessage(info, 3000); + } +} + +void CMainFrame::OnUpdateViewRotate(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && (m_pCAP || m_pCAP3)); +} + +// FIXME +const static SIZE s_ar[] = {{0, 0}, {4, 3}, {5, 4}, {16, 9}, {235, 100}, {185, 100}}; + +void CMainFrame::OnViewAspectRatio(UINT nID) +{ + auto& s = AfxGetAppSettings(); + + CString info; + if (nID == ID_ASPECTRATIO_SAR) { + s.fKeepAspectRatio = false; + info.LoadString(IDS_ASPECT_RATIO_SAR); + } else { + s.fKeepAspectRatio = true; + CSize ar = s_ar[nID - ID_ASPECTRATIO_START]; + s.SetAspectRatioOverride(ar); + if (ar.cx && ar.cy) { + info.Format(IDS_MAINFRM_68, ar.cx, ar.cy); + } else { + info.LoadString(IDS_MAINFRM_69); + } + } + + SendStatusMessage(info, 3000); + m_OSD.DisplayMessage(OSD_TOPLEFT, info, 3000); + + OnVideoSizeChanged(); +} + +void CMainFrame::OnUpdateViewAspectRatio(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + + bool bSelected; + if (pCmdUI->m_nID == ID_ASPECTRATIO_SAR) { + bSelected = s.fKeepAspectRatio == false; + } else { + bSelected = s.fKeepAspectRatio == true && s.GetAspectRatioOverride() == s_ar[pCmdUI->m_nID - ID_ASPECTRATIO_START]; + } + if (bSelected && pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_ASPECTRATIO_START, ID_ASPECTRATIO_END, pCmdUI->m_nID, MF_BYCOMMAND); + } + + pCmdUI->Enable(GetLoadState() == MLS::LOADED && !m_fAudioOnly && s.iDSVideoRendererType != VIDRNDT_DS_EVR); +} + +void CMainFrame::OnViewAspectRatioNext() +{ + static_assert(ID_ASPECTRATIO_SAR - ID_ASPECTRATIO_START == _countof(s_ar) && ID_ASPECTRATIO_SAR == ID_ASPECTRATIO_END, + "ID_ASPECTRATIO_SAR needs to be last item in the menu."); + + const auto& s = AfxGetAppSettings(); + UINT nID = ID_ASPECTRATIO_START; + if (s.fKeepAspectRatio) { + const CSize ar = s.GetAspectRatioOverride(); + for (int i = 0; i < _countof(s_ar); i++) { + if (ar == s_ar[i]) { + nID += (i + 1) % ((ID_ASPECTRATIO_END - ID_ASPECTRATIO_START) + 1); + break; + } + } + } + + OnViewAspectRatio(nID); +} + +void CMainFrame::OnViewOntop(UINT nID) +{ + nID -= ID_ONTOP_DEFAULT; + if (AfxGetAppSettings().iOnTop == (int)nID) { + nID = !nID; + } + SetAlwaysOnTop(nID); +} + +void CMainFrame::OnUpdateViewOntop(CCmdUI* pCmdUI) +{ + int onTop = pCmdUI->m_nID - ID_ONTOP_DEFAULT; + if (AfxGetAppSettings().iOnTop == onTop && pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_ONTOP_DEFAULT, ID_ONTOP_WHILEPLAYINGVIDEO, pCmdUI->m_nID, MF_BYCOMMAND); + } +} + +void CMainFrame::OnViewOptions() +{ + ShowOptions(); +} + +// play + +void CMainFrame::OnPlayPlay() +{ + const CAppSettings& s = AfxGetAppSettings(); + + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); + m_bOpeningInAutochangedMonitorMode = false; + m_bPausedForAutochangeMonitorMode = false; + + if (GetLoadState() == MLS::CLOSED) { + m_bFirstPlay = false; + OpenCurPlaylistItem(); + return; + } + + if (GetLoadState() == MLS::LOADING) { + return; + } + + if (GetLoadState() == MLS::LOADED) { + // If playback was previously stopped or ended, we need to reset the window size + bool bVideoWndNeedReset = GetMediaState() == State_Stopped || m_fEndOfStream; + + KillTimersStop(); + + if (GetPlaybackMode() == PM_FILE) { + if (m_fEndOfStream) { + SendMessage(WM_COMMAND, ID_PLAY_STOP); + } else { + if (!m_fAudioOnly && m_dwLastPause && m_wndSeekBar.HasDuration() && s.iReloadAfterLongPause >= 0) { + // after long pause or hibernation, reload video file to avoid playback issues on some systems (with buggy drivers) + // in case of hibernate, m_dwLastPause equals 1 + if (m_dwLastPause == 1 || s.iReloadAfterLongPause > 0 && (GetTickCount64() - m_dwLastPause >= s.iReloadAfterLongPause * 60 * 1000)) { + m_dwReloadPos = m_wndSeekBar.GetPos(); + reloadABRepeat = abRepeat; + m_iReloadAudioIdx = GetCurrentAudioTrackIdx(); + m_iReloadSubIdx = GetCurrentSubtitleTrackIdx(); + OnFileReopen(); + return; + } + } + } + if (m_pMS) { + if (FAILED(m_pMS->SetRate(m_dSpeedRate))) { + m_dSpeedRate = 1.0; + } + } + } else if (GetPlaybackMode() == PM_DVD) { + m_dSpeedRate = 1.0; + m_pDVDC->PlayForwards(m_dSpeedRate, DVD_CMD_FLAG_Block, nullptr); + m_pDVDC->Pause(FALSE); + } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + MediaControlStop(); // audio preview won't be in sync if we run it from paused state + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + bVideoWndNeedReset = false; // SetChannel deals with MoveVideoWindow + SetChannel(s.nDVBLastChannel); + } else { + ASSERT(FALSE); + } + } else { + ASSERT(FALSE); + } + + if (bVideoWndNeedReset) { + MoveVideoWindow(false, true); + } + + if (m_fFrameSteppingActive) { + m_pFS->CancelStep(); + m_fFrameSteppingActive = false; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } else { + if (m_pBA) { + m_pBA->put_Volume(m_wndToolBar.Volume); + } + } + m_nStepForwardCount = 0; + + // Restart playback + MediaControlRun(); + + SetAlwaysOnTop(s.iOnTop); + + SetTimersPlay(); + } + + m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_PLAYING), 3000); + SetPlayState(PS_PLAY); + + OnTimer(TIMER_STREAMPOSPOLLER); + + SetupEVRColorControl(); // can be configured when streaming begins + + if (m_OSD.CanShowMessage()) { + CString strOSD; + CString strPlay(StrRes(ID_PLAY_PLAY)); + int i = strPlay.Find(_T("\n")); + if (i > 0) { + strPlay.Delete(i, strPlay.GetLength() - i); + } + + if (m_bFirstPlay) { + if (GetPlaybackMode() == PM_FILE) { + if (!m_LastOpenBDPath.IsEmpty()) { + strOSD.LoadString(IDS_PLAY_BD); + } else { + strOSD = GetFileName(); + CPlaylistItem pli; + if (!strOSD.IsEmpty() && (!m_wndPlaylistBar.GetCur(pli) || !pli.m_bYoutubeDL)) { + strOSD.TrimRight('/'); + strOSD.Replace('\\', '/'); + strOSD = strOSD.Mid(strOSD.ReverseFind('/') + 1); + } + } + } else if (GetPlaybackMode() == PM_DVD) { + strOSD.LoadString(IDS_PLAY_DVD); + } + } + + if (strOSD.IsEmpty()) { + strOSD = strPlay; + } + if (GetPlaybackMode() != PM_DIGITAL_CAPTURE) { + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + } + } + + m_bFirstPlay = false; +} + +void CMainFrame::OnPlayPause() +{ + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); + m_bOpeningInAutochangedMonitorMode = false; + + if (GetLoadState() == MLS::LOADED && GetMediaState() == State_Stopped) { + MoveVideoWindow(false, true); + } + + if (GetLoadState() == MLS::LOADED) { + if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD || GetPlaybackMode() == PM_ANALOG_CAPTURE) { + if (m_fFrameSteppingActive) { + m_pFS->CancelStep(); + m_fFrameSteppingActive = false; + m_nStepForwardCount = 0; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } + MediaControlPause(true); + } else { + ASSERT(FALSE); + } + + KillTimer(TIMER_STATS); + SetAlwaysOnTop(AfxGetAppSettings().iOnTop); + } + + CString strOSD(StrRes(ID_PLAY_PAUSE)); + int i = strOSD.Find(_T("\n")); + if (i > 0) { + strOSD.Delete(i, strOSD.GetLength() - i); + } + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_PAUSED), 3000); + SetPlayState(PS_PAUSE); +} + +void CMainFrame::OnPlayPlaypause() +{ + if (GetLoadState() == MLS::LOADED) { + OAFilterState fs = GetMediaState(); + if (fs == State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } else if (fs == State_Stopped || fs == State_Paused) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + } else if (GetLoadState() == MLS::CLOSED && !IsPlaylistEmpty()) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } +} + +void CMainFrame::OnApiPause() +{ + OAFilterState fs = GetMediaState(); + if (fs == State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } +} +void CMainFrame::OnApiPlay() +{ + OAFilterState fs = GetMediaState(); + if (fs == State_Stopped || fs == State_Paused) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } +} + +void CMainFrame::OnPlayStop() +{ + OnPlayStop(false); +} + +void CMainFrame::OnPlayStop(bool is_closing) +{ + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE); + m_bOpeningInAutochangedMonitorMode = false; + m_bPausedForAutochangeMonitorMode = false; + + KillTimersStop(); + + m_wndSeekBar.SetPos(0); + if (GetLoadState() == MLS::LOADED) { + if (GetPlaybackMode() == PM_FILE) { + if (!is_closing) { + LONGLONG pos = 0; + m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + MediaControlStop(true); + if (m_bUseSeekPreview) { + MediaControlStopPreview(); + } + + if (m_pAMNS && m_pFSF) { + // After pause or stop the netshow url source filter won't continue + // on the next play command, unless we cheat it by setting the file name again. + WCHAR* pFN = nullptr; + AM_MEDIA_TYPE mt; + if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { + m_pFSF->Load(pFN, nullptr); + CoTaskMemFree(pFN); + } + } + } else if (GetPlaybackMode() == PM_DVD) { + m_pDVDC->SetOption(DVD_ResetOnStop, TRUE); + MediaControlStop(true); + m_pDVDC->SetOption(DVD_ResetOnStop, FALSE); + + if (m_bUseSeekPreview && m_pDVDC_preview) { + m_pDVDC_preview->SetOption(DVD_ResetOnStop, TRUE); + MediaControlStopPreview(); + m_pDVDC_preview->SetOption(DVD_ResetOnStop, FALSE); + } + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + MediaControlStop(true); + m_pDVBState->bActive = false; + OpenSetupWindowTitle(); + m_wndStatusBar.SetStatusTimer(StrRes(IDS_CAPTURE_LIVE)); + } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + MediaControlStop(true); + } + + m_dSpeedRate = 1.0; + + if (m_fFrameSteppingActive) { + m_pFS->CancelStep(); + m_fFrameSteppingActive = false; + m_nStepForwardCount = 0; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } + m_nStepForwardCount = 0; + } else if (GetLoadState() == MLS::CLOSING) { + MediaControlStop(true); + } + + m_nLoops = 0; + + if (m_hWnd) { + MoveVideoWindow(); + + if (!is_closing && GetLoadState() == MLS::LOADED) { + __int64 start, stop; + m_wndSeekBar.GetRange(start, stop); + if (!IsPlaybackCaptureMode()) { + m_wndStatusBar.SetStatusTimer(m_wndSeekBar.GetPos(), stop, IsSubresyncBarVisible(), GetTimeFormat()); + } + + SetAlwaysOnTop(AfxGetAppSettings().iOnTop); + } + } + + if (!is_closing && !m_fEndOfStream && GetLoadState() == MLS::LOADED) { + CString strOSD(StrRes(ID_PLAY_STOP)); + int i = strOSD.Find(_T("\n")); + if (i > 0) { + strOSD.Delete(i, strOSD.GetLength() - i); + } + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + m_Lcd.SetStatusMessage(ResStr(IDS_CONTROLS_STOPPED), 3000); + } else { + m_fEndOfStream = false; + } + + SetPlayState(PS_STOP); +} + +void CMainFrame::OnUpdatePlayPauseStop(CCmdUI* pCmdUI) +{ + bool fEnable = false; + bool fCheck = false; + + if (GetLoadState() == MLS::LOADED) { + OAFilterState fs = m_fFrameSteppingActive ? State_Paused : GetMediaState(); + + fCheck = pCmdUI->m_nID == ID_PLAY_PLAY && fs == State_Running || + pCmdUI->m_nID == ID_PLAY_PAUSE && fs == State_Paused || + pCmdUI->m_nID == ID_PLAY_STOP && fs == State_Stopped || + pCmdUI->m_nID == ID_PLAY_PLAYPAUSE && (fs == State_Paused || fs == State_Running); + + if (fs >= 0) { + if (GetPlaybackMode() == PM_FILE || IsPlaybackCaptureMode()) { + fEnable = true; + + if (m_fCapturing) { + fEnable = false; + } else if (m_fLiveWM && pCmdUI->m_nID == ID_PLAY_PAUSE) { + fEnable = false; + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE && pCmdUI->m_nID == ID_PLAY_PAUSE) { + fEnable = false; // Disable pause for digital capture mode to avoid accidental playback stop. We don't support time shifting yet. + } + } else if (GetPlaybackMode() == PM_DVD) { + fEnable = m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu + && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu; + + if (fs == State_Stopped && pCmdUI->m_nID == ID_PLAY_PAUSE) { + fEnable = false; + } + } + } + } else if (GetLoadState() == MLS::CLOSED) { + fEnable = (pCmdUI->m_nID == ID_PLAY_PLAY || pCmdUI->m_nID == ID_PLAY_PLAYPAUSE) && !IsPlaylistEmpty(); + } + + pCmdUI->SetCheck(fCheck); + pCmdUI->Enable(fEnable); +} + +void CMainFrame::OnPlayFramestep(UINT nID) +{ + if (!m_pFS && !m_pMS) { + return; + } + + KillTimerDelayedSeek(); + + m_OSD.EnableShowMessage(false); + + if (m_CachedFilterState == State_Paused) { + // Double check the state, because graph may have silently gone into a running state after performing a framestep + if (UpdateCachedMediaState() != State_Paused) { + MediaControlPause(true); + } + } else { + KillTimer(TIMER_STATS); + MediaControlPause(true); + } + + if (nID == ID_PLAY_FRAMESTEP && m_pFS) { + // To support framestep back, store the initial position when + // stepping forward + if (m_nStepForwardCount == 0) { + if (GetPlaybackMode() == PM_DVD) { + OnTimer(TIMER_STREAMPOSPOLLER); + m_rtStepForwardStart = m_wndSeekBar.GetPos(); + } else { + m_pMS->GetCurrentPosition(&m_rtStepForwardStart); + } + } + + if (!m_fFrameSteppingActive) { + m_fFrameSteppingActive = true; + m_nVolumeBeforeFrameStepping = m_wndToolBar.Volume; + if (m_pBA) { + m_pBA->put_Volume(-10000); + } + } + + HRESULT hr = m_pFS->Step(1, nullptr); + if (FAILED(hr)) { + TRACE(_T("Frame step failed.\n")); + m_fFrameSteppingActive = false; + m_nStepForwardCount = 0; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } + } else if (m_pMS && (m_nStepForwardCount == 0) && (S_OK == m_pMS->IsFormatSupported(&TIME_FORMAT_FRAME))) { + if (SUCCEEDED(m_pMS->SetTimeFormat(&TIME_FORMAT_FRAME))) { + REFERENCE_TIME rtCurPos; + + if (SUCCEEDED(m_pMS->GetCurrentPosition(&rtCurPos))) { + rtCurPos += (nID == ID_PLAY_FRAMESTEP) ? 1 : -1; + + m_pMS->SetPositions(&rtCurPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + m_pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME); + } + } else { // nID == ID_PLAY_FRAMESTEP_BACK + const REFERENCE_TIME rtAvgTimePerFrame = std::llround(GetAvgTimePerFrame() * 10000000LL); + REFERENCE_TIME rtCurPos = 0; + + if (m_nStepForwardCount) { // Exit of framestep forward, calculate current position + m_pFS->CancelStep(); + rtCurPos = m_rtStepForwardStart + m_nStepForwardCount * rtAvgTimePerFrame; + m_nStepForwardCount = 0; + rtCurPos -= rtAvgTimePerFrame; + } else if (GetPlaybackMode() == PM_DVD) { + // IMediaSeeking doesn't work properly with DVD Navigator + // Unfortunately, IDvdInfo2::GetCurrentLocation is inaccurate as well and only updates position approx. once per 500ms + // Due to inaccurate start position value, framestep backwards simply doesn't work well with DVDs. + // Seeking has same accuracy problem. Best we can do is jump back 500ms to at least get to a different frame. + OnTimer(TIMER_STREAMPOSPOLLER); + rtCurPos = m_wndSeekBar.GetPos(); + rtCurPos -= 5000000LL; + } else { + m_pMS->GetCurrentPosition(&rtCurPos); + rtCurPos -= rtAvgTimePerFrame; + } + + DoSeekTo(rtCurPos, false); + } + m_OSD.EnableShowMessage(); +} + +void CMainFrame::OnUpdatePlayFramestep(CCmdUI* pCmdUI) +{ + bool fEnable = false; + + if (pCmdUI->m_nID == ID_PLAY_FRAMESTEP) { + if (!m_fAudioOnly && !m_fLiveWM && GetLoadState() == MLS::LOADED && (GetPlaybackMode() == PM_FILE || (GetPlaybackMode() == PM_DVD && m_iDVDDomain == DVD_DOMAIN_Title))) { + if (m_pFS || m_pMS && (S_OK == m_pMS->IsFormatSupported(&TIME_FORMAT_FRAME))) { + fEnable = true; + } + } + } + pCmdUI->Enable(fEnable); +} + +void CMainFrame::OnPlaySeek(UINT nID) +{ + const auto& s = AfxGetAppSettings(); + + REFERENCE_TIME rtJumpDiff = + nID == ID_PLAY_SEEKBACKWARDSMALL ? -10000i64 * s.nJumpDistS : + nID == ID_PLAY_SEEKFORWARDSMALL ? +10000i64 * s.nJumpDistS : + nID == ID_PLAY_SEEKBACKWARDMED ? -10000i64 * s.nJumpDistM : + nID == ID_PLAY_SEEKFORWARDMED ? +10000i64 * s.nJumpDistM : + nID == ID_PLAY_SEEKBACKWARDLARGE ? -10000i64 * s.nJumpDistL : + nID == ID_PLAY_SEEKFORWARDLARGE ? +10000i64 * s.nJumpDistL : + 0; + + if (rtJumpDiff == 0) { + ASSERT(FALSE); + return; + } + + if (m_fShockwaveGraph) { + // HACK: the custom graph should support frame based seeking instead + rtJumpDiff /= 10000i64 * 100; + } + + const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); + REFERENCE_TIME rtSeekTo = rtPos + rtJumpDiff; + if (rtSeekTo < 0) { + rtSeekTo = 0; + } + + if (s.bFastSeek && !m_kfs.empty()) { + REFERENCE_TIME rtMaxForwardDiff; + REFERENCE_TIME rtMaxBackwardDiff; + if (s.bAllowInaccurateFastseek && (s.nJumpDistS >= 5000 || (nID != ID_PLAY_SEEKBACKWARDSMALL) && (nID != ID_PLAY_SEEKFORWARDSMALL))) { + if (rtJumpDiff > 0) { + rtMaxForwardDiff = 200000000LL; + rtMaxBackwardDiff = rtJumpDiff / 2; + } else { + rtMaxForwardDiff = -rtJumpDiff / 2; + rtMaxBackwardDiff = 200000000LL; + } + } else { + rtMaxForwardDiff = rtMaxBackwardDiff = std::min(100000000LL, abs(rtJumpDiff) * 3 / 10); + } + rtSeekTo = GetClosestKeyFrame(rtSeekTo, rtMaxForwardDiff, rtMaxBackwardDiff); + } + + SeekTo(rtSeekTo); +} + +void CMainFrame::OnPlaySeekSet() +{ + const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); + REFERENCE_TIME rtStart, rtStop; + m_wndSeekBar.GetRange(rtStart, rtStop); + + if (abRepeat.positionA > rtStart && abRepeat.positionA < rtStop) { + rtStart = abRepeat.positionA; + } + if (rtPos != rtStart) { + SeekTo(rtStart, false); + } +} + +void CMainFrame::AdjustStreamPosPoller(bool restart) +{ + int current_value = m_iStreamPosPollerInterval; + + if (g_bExternalSubtitleTime || IsSubresyncBarVisible()) { + m_iStreamPosPollerInterval = 40; + } else { + m_iStreamPosPollerInterval = AfxGetAppSettings().nStreamPosPollerInterval; + } + + if (restart && current_value != m_iStreamPosPollerInterval) { + if (KillTimer(TIMER_STREAMPOSPOLLER)) { + SetTimer(TIMER_STREAMPOSPOLLER, m_iStreamPosPollerInterval, nullptr); + } + } +} + +void CMainFrame::SetTimersPlay() +{ + AdjustStreamPosPoller(false); + + SetTimer(TIMER_STREAMPOSPOLLER, m_iStreamPosPollerInterval, nullptr); + SetTimer(TIMER_STREAMPOSPOLLER2, 500, nullptr); + SetTimer(TIMER_STATS, 1000, nullptr); +} + +void CMainFrame::KillTimerDelayedSeek() +{ + KillTimer(TIMER_DELAYEDSEEK); + queuedSeek = { 0, 0, false }; +} + +void CMainFrame::KillTimersStop() +{ + KillTimerDelayedSeek(); + KillTimer(TIMER_STREAMPOSPOLLER2); + KillTimer(TIMER_STREAMPOSPOLLER); + KillTimer(TIMER_STATS); + m_timerOneTime.Unsubscribe(TimerOneTimeSubscriber::DVBINFO_UPDATE); +} + +void CMainFrame::OnPlaySeekKey(UINT nID) +{ + if (!m_kfs.empty()) { + bool bSeekingForward = (nID == ID_PLAY_SEEKKEYFORWARD); + const REFERENCE_TIME rtPos = m_wndSeekBar.GetPos(); + REFERENCE_TIME rtKeyframe; + REFERENCE_TIME rtTarget; + REFERENCE_TIME rtMin; + REFERENCE_TIME rtMax; + if (bSeekingForward) { + rtMin = rtPos + 10000LL; // at least one millisecond later + rtMax = GetDur(); + rtTarget = rtMin; + } else { + rtMin = 0; + if (GetMediaState() == State_Paused) { + rtMax = rtPos - 10000LL; + } else { + rtMax = rtPos - 5000000LL; + } + rtTarget = rtMax; + } + + if (GetKeyFrame(rtTarget, rtMin, rtMax, false, rtKeyframe)) { + SeekTo(rtKeyframe); + } + } +} + +void CMainFrame::OnUpdatePlaySeek(CCmdUI* pCmdUI) +{ + bool fEnable = false; + + if (GetLoadState() == MLS::LOADED) { + fEnable = true; + if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { + fEnable = false; + } else if (IsPlaybackCaptureMode()) { + fEnable = false; + } + } + + pCmdUI->Enable(fEnable); +} + +void CMainFrame::SetPlayingRate(double rate) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + HRESULT hr = E_FAIL; + if (GetPlaybackMode() == PM_FILE) { + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + if (m_pMS) { + hr = m_pMS->SetRate(rate); + } + } else if (GetPlaybackMode() == PM_DVD) { + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + if (rate > 0) { + hr = m_pDVDC->PlayForwards(rate, DVD_CMD_FLAG_Block, nullptr); + } else { + hr = m_pDVDC->PlayBackwards(-rate, DVD_CMD_FLAG_Block, nullptr); + } + } + if (SUCCEEDED(hr)) { + m_dSpeedRate = rate; + CString strODSMessage; + strODSMessage.Format(IDS_OSD_SPEED, rate); + m_OSD.DisplayMessage(OSD_TOPRIGHT, strODSMessage); + } +} + +void CMainFrame::OnPlayChangeRate(UINT nID) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + if (GetPlaybackMode() == PM_FILE) { + const CAppSettings& s = AfxGetAppSettings(); + double dSpeedStep = s.nSpeedStep / 100.0; + + if (nID == ID_PLAY_INCRATE) { + if (s.nSpeedStep > 0) { + if (m_dSpeedRate <= 0.05) { + double newrate = 1.0 - (95 / s.nSpeedStep) * dSpeedStep; + SetPlayingRate(newrate > 0.05 ? newrate : newrate + dSpeedStep); + } else { + SetPlayingRate(std::max(0.05, m_dSpeedRate + dSpeedStep)); + } + } else { + SetPlayingRate(std::max(0.0625, m_dSpeedRate * 2.0)); + } + } else if (nID == ID_PLAY_DECRATE) { + if (s.nSpeedStep > 0) { + SetPlayingRate(std::max(0.05, m_dSpeedRate - dSpeedStep)); + } else { + SetPlayingRate(std::max(0.0625, m_dSpeedRate / 2.0)); + } + } else if (nID > ID_PLAY_PLAYBACKRATE_START && nID < ID_PLAY_PLAYBACKRATE_END) { + if (filePlaybackRates.count(nID) != 0) { + SetPlayingRate(filePlaybackRates[nID]); + } else if (nID == ID_PLAY_PLAYBACKRATE_FPS24 || nID == ID_PLAY_PLAYBACKRATE_FPS25) { + if (m_pCAP) { + float target = (nID == ID_PLAY_PLAYBACKRATE_FPS24 ? 24.0f : 25.0f); + SetPlayingRate(target / m_pCAP->GetFPS()); + } + } + } + } else if (GetPlaybackMode() == PM_DVD) { + if (nID == ID_PLAY_INCRATE) { + if (m_dSpeedRate > 0) { + SetPlayingRate(m_dSpeedRate * 2.0); + } else if (m_dSpeedRate >= -1) { + SetPlayingRate(1); + } else { + SetPlayingRate(m_dSpeedRate / 2.0); + } + } else if (nID == ID_PLAY_DECRATE) { + if (m_dSpeedRate < 0) { + SetPlayingRate(m_dSpeedRate * 2.0); + } else if (m_dSpeedRate <= 1) { + SetPlayingRate(-1); + } else { + SetPlayingRate(m_dSpeedRate / 2.0); + } + } else if (nID > ID_PLAY_PLAYBACKRATE_START && nID < ID_PLAY_PLAYBACKRATE_END) { + if (dvdPlaybackRates.count(nID) != 0) { + SetPlayingRate(dvdPlaybackRates[nID]); + } + } + } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + + long lChannelMin = 0, lChannelMax = 0; + m_pAMTuner->ChannelMinMax(&lChannelMin, &lChannelMax); + long lChannel = 0, lVivSub = 0, lAudSub = 0; + m_pAMTuner->get_Channel(&lChannel, &lVivSub, &lAudSub); + + long lFreqOrg = 0, lFreqNew = -1; + m_pAMTuner->get_VideoFrequency(&lFreqOrg); + + //long lSignalStrength; + do { + if (nID == ID_PLAY_DECRATE) { + lChannel--; + } else if (nID == ID_PLAY_INCRATE) { + lChannel++; + } + + //if (lChannel < lChannelMin) lChannel = lChannelMax; + //if (lChannel > lChannelMax) lChannel = lChannelMin; + + if (lChannel < lChannelMin || lChannel > lChannelMax) { + break; + } + + if (FAILED(m_pAMTuner->put_Channel(lChannel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT))) { + break; + } + + long flFoundSignal; + m_pAMTuner->AutoTune(lChannel, &flFoundSignal); + + m_pAMTuner->get_VideoFrequency(&lFreqNew); + } while (FALSE); + /*SUCCEEDED(m_pAMTuner->SignalPresent(&lSignalStrength)) + && (lSignalStrength != AMTUNER_SIGNALPRESENT || lFreqNew == lFreqOrg));*/ + } else { + ASSERT(FALSE); + } +} + +void CMainFrame::OnUpdatePlayChangeRate(CCmdUI* pCmdUI) +{ + bool fEnable = false; + + if (GetLoadState() == MLS::LOADED) { + if (pCmdUI->m_nID > ID_PLAY_PLAYBACKRATE_START && pCmdUI->m_nID < ID_PLAY_PLAYBACKRATE_END && pCmdUI->m_pMenu) { + fEnable = false; + if (GetPlaybackMode() == PM_FILE) { + if (filePlaybackRates.count(pCmdUI->m_nID) != 0) { + fEnable = true; + if (filePlaybackRates[pCmdUI->m_nID] == m_dSpeedRate) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); + } + } else if (pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS24 || pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS25) { + fEnable = true; + if (m_pCAP) { + float target = (pCmdUI->m_nID == ID_PLAY_PLAYBACKRATE_FPS24 ? 24.0f : 25.0f); + if (target / m_pCAP->GetFPS() == m_dSpeedRate) { + bool found = false; + for (auto const& [key, rate] : filePlaybackRates) { //make sure it wasn't a standard rate already + if (rate == m_dSpeedRate) { + found = true; + } + } + if (!found) { //must have used fps, as it didn't match a standard rate + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); + } + } + } + } + } else if (GetPlaybackMode() == PM_DVD) { + if (dvdPlaybackRates.count(pCmdUI->m_nID) != 0) { + fEnable = true; + if (dvdPlaybackRates[pCmdUI->m_nID] == m_dSpeedRate) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_PLAYBACKRATE_START, ID_PLAY_PLAYBACKRATE_END, pCmdUI->m_nID, MF_BYCOMMAND); + } + } + } + } else { + bool fInc = pCmdUI->m_nID == ID_PLAY_INCRATE; + + fEnable = true; + if (fInc && m_dSpeedRate >= 128.0) { + fEnable = false; + } else if (!fInc && GetPlaybackMode() == PM_FILE && m_dSpeedRate <= 0.05) { + fEnable = false; + } else if (!fInc && GetPlaybackMode() == PM_DVD && m_dSpeedRate <= -128.0) { + fEnable = false; + } else if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { + fEnable = false; + } else if (m_fShockwaveGraph) { + fEnable = false; + } else if (GetPlaybackMode() == PM_ANALOG_CAPTURE && (!m_wndCaptureBar.m_capdlg.IsTunerActive() || m_fCapturing)) { + fEnable = false; + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + fEnable = false; + } else if (m_fLiveWM) { + fEnable = false; + } + } + } + + pCmdUI->Enable(fEnable); +} + +void CMainFrame::OnPlayResetRate() +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + HRESULT hr = E_FAIL; + + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + + if (GetPlaybackMode() == PM_FILE) { + hr = m_pMS->SetRate(1.0); + } else if (GetPlaybackMode() == PM_DVD) { + hr = m_pDVDC->PlayForwards(1.0, DVD_CMD_FLAG_Block, nullptr); + } + + if (SUCCEEDED(hr)) { + m_dSpeedRate = 1.0; + + CString strODSMessage; + strODSMessage.Format(IDS_OSD_SPEED, m_dSpeedRate); + m_OSD.DisplayMessage(OSD_TOPRIGHT, strODSMessage); + } +} + +void CMainFrame::OnUpdatePlayResetRate(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED); +} + +void CMainFrame::SetAudioDelay(REFERENCE_TIME rtShift) +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + pASF->SetAudioTimeShift(rtShift); + + if (GetLoadState() == MLS::LOADED) { + CString str; + str.Format(IDS_MAINFRM_70, rtShift / 10000); + SendStatusMessage(str, 3000); + m_OSD.DisplayMessage(OSD_TOPLEFT, str); + } + } +} + +void CMainFrame::SetSubtitleDelay(int delay_ms, bool relative) +{ + if (!m_pCAP && !m_pDVS) { + if (GetLoadState() == MLS::LOADED) { + SendStatusMessage(L"Delay is not supported by current subtitle renderer", 3000); + } + return; + } + + if (m_pDVS) { + int currentDelay, speedMul, speedDiv; + if (FAILED(m_pDVS->get_SubtitleTiming(¤tDelay, &speedMul, &speedDiv))) { + return; + } + if (relative) { + delay_ms += currentDelay; + } + + VERIFY(SUCCEEDED(m_pDVS->put_SubtitleTiming(delay_ms, speedMul, speedDiv))); + } + else { + ASSERT(m_pCAP != nullptr); + if (m_pSubStreams.IsEmpty()) { + SendStatusMessage(StrRes(IDS_SUBTITLES_ERROR), 3000); + return; + } + if (relative) { + delay_ms += m_pCAP->GetSubtitleDelay(); + } + + m_pCAP->SetSubtitleDelay(delay_ms); + } + + CString strSubDelay; + strSubDelay.Format(IDS_MAINFRM_139, delay_ms); + SendStatusMessage(strSubDelay, 3000); + m_OSD.DisplayMessage(OSD_TOPLEFT, strSubDelay); +} + +void CMainFrame::OnPlayChangeAudDelay(UINT nID) +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + REFERENCE_TIME rtShift = pASF->GetAudioTimeShift(); + rtShift += + nID == ID_PLAY_INCAUDDELAY ? 100000 : + nID == ID_PLAY_DECAUDDELAY ? -100000 : + 0; + + SetAudioDelay(rtShift); + } +} + +void CMainFrame::OnUpdatePlayChangeAudDelay(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(!!m_pGB /*&& !!FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)*/); +} + +void CMainFrame::OnPlayFiltersCopyToClipboard() +{ + // Don't translate that output since it's mostly for debugging purpose + CString filtersList = _T("Filters currently loaded:\r\n"); + // Skip the first two entries since they are the "Copy to clipboard" menu entry and a separator + for (int i = 2, count = m_filtersMenu.GetMenuItemCount(); i < count; i++) { + CString filterName; + m_filtersMenu.GetMenuString(i, filterName, MF_BYPOSITION); + filtersList.AppendFormat(_T(" - %s\r\n"), filterName.GetString()); + } + + CClipboard clipboard(this); + VERIFY(clipboard.SetText(filtersList)); +} + +bool CMainFrame::FilterSettingsByClassID(CLSID clsid, CWnd* parent) +{ + for (int a = 0; a < m_pparray.GetCount(); a++) { + CComQIPtr pBF2 = m_pparray[a]; + if (pBF2) { + CLSID tclsid; + pBF2->GetClassID(&tclsid); + if (tclsid == clsid) { + FilterSettings(m_pparray[a], parent); + return true; + } + } + } + return false; +} + +void CMainFrame::FilterSettings(CComPtr pUnk, CWnd* parent) { + CComPropertySheet ps(IDS_PROPSHEET_PROPERTIES); + + CComQIPtr pBF = pUnk; + CLSID clsid = GetCLSID(pBF); + CFGFilterLAV::LAVFILTER_TYPE LAVFilterType = CFGFilterLAV::INVALID; + bool bIsInternalLAV = CFGFilterLAV::IsInternalInstance(pBF, &LAVFilterType); + + if (CComQIPtr pSPP = pUnk) { + ULONG uIgnoredPage = ULONG(-1); + // If we are dealing with an internal filter, we want to ignore the "Formats" page. + if (bIsInternalLAV) { + uIgnoredPage = (LAVFilterType != CFGFilterLAV::AUDIO_DECODER) ? 1 : 2; + } + bool bIsInternalFilter = bIsInternalLAV || clsid == CLSID_MPCVR; + ps.AddPages(pSPP, bIsInternalFilter, uIgnoredPage); + } + + HRESULT hr; + CComPtr pPP = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr); + ps.AddPage(pPP, pBF); + + if (ps.GetPageCount() > 0) { + CMPCThemeComPropertyPage::SetDialogType(clsid); + ps.DoModal(); + OpenSetupStatusBar(); + + if (bIsInternalLAV) { + if (CComQIPtr pLAVFSettings = pBF) { + CFGFilterLAVSplitterBase::Settings settings; + if (settings.GetSettings(pLAVFSettings)) { // Get current settings from LAVSplitter + settings.SaveSettings(); // Save them to the registry/ini + } + } else if (CComQIPtr pLAVVideoSettings = pBF) { + CFGFilterLAVVideo::Settings settings; + if (settings.GetSettings(pLAVVideoSettings)) { // Get current settings from LAVVideo + settings.SaveSettings(); // Save them to the registry/ini + } + } else if (CComQIPtr pLAVAudioSettings = pBF) { + CFGFilterLAVAudio::Settings settings; + if (settings.GetSettings(pLAVAudioSettings)) { // Get current settings from LAVAudio + settings.SaveSettings(); // Save them to the registry/ini + } + } + } + } +} + +void CMainFrame::OnPlayFilters(UINT nID) +{ + //ShowPPage(m_spparray[nID - ID_FILTERS_SUBITEM_START], m_hWnd); + + CComPtr pUnk = m_pparray[nID - ID_FILTERS_SUBITEM_START]; + + FilterSettings(pUnk, GetModalParent()); +} + +void CMainFrame::OnUpdatePlayFilters(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(!m_fCapturing); +} + +void CMainFrame::OnPlayShadersSelect() +{ + ShowOptions(IDD_PPAGESHADERS); +} + +void CMainFrame::OnPlayShadersPresetNext() +{ + auto& s = AfxGetAppSettings(); + if (s.m_Shaders.NextPreset()) { + CString name; + if (s.m_Shaders.GetCurrentPresetName(name)) { + CString msg; + msg.Format(IDS_OSD_SHADERS_PRESET, name.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, msg); + } + } +} + +void CMainFrame::OnPlayShadersPresetPrev() +{ + auto& s = AfxGetAppSettings(); + if (s.m_Shaders.PrevPreset()) { + CString name; + if (s.m_Shaders.GetCurrentPresetName(name)) { + CString msg; + msg.Format(IDS_OSD_SHADERS_PRESET, name.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, msg); + } + } +} + +void CMainFrame::OnPlayShadersPresets(UINT nID) +{ + ASSERT((nID >= ID_SHADERS_PRESETS_START) && (nID <= ID_SHADERS_PRESETS_END)); + auto& s = AfxGetAppSettings(); + int num = (int)nID - ID_SHADERS_PRESETS_START; + auto presets = s.m_Shaders.GetPresets(); + ASSERT(num < (int)presets.size()); + for (const auto& pair : presets) { + if (num-- == 0) { + s.m_Shaders.SetCurrentPreset(pair.first); + break; + } + } +} + +int CMainFrame::UpdateSelectedAudioStreamInfo(int index, AM_MEDIA_TYPE* pmt, LCID lcid) { + int nChannels = 0; + if (index >= 0) { + m_loadedAudioTrackIndex = index; + AfxGetAppSettings().MRU.UpdateCurrentAudioTrack(index); + } + if (pmt) { + m_statusbarAudioFormat = GetShortAudioNameFromMediaType(pmt); + AppendWithDelimiter(m_statusbarAudioFormat, GetChannelStrFromMediaType(pmt, nChannels)); + } else { + m_statusbarAudioFormat.Empty(); + } + if (lcid > 0) { + GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentAudioLang); + } else { + currentAudioLang.Empty(); + } + return nChannels; +} + +int CMainFrame::GetSelectedSubtitleTrackIndex() { + int subIdx = 0; + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + CComQIPtr pSSF = subInput.pSourceFilter; + if (pSSF) { + DWORD cStreams; + if (SUCCEEDED(pSSF->Count(&cStreams))) { + for (long j = 0; j < (long)cStreams; j++) { + DWORD dwFlags, dwGroup; + if (SUCCEEDED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 2) { + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + return subIdx; + } + subIdx++; + } + } + } + } + } else { + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + return subIdx; + } else { + subIdx += subInput.pSubStream->GetStreamCount(); + } + } + } + return 0; +} + +bool CMainFrame::IsValidSubtitleStream(int i) { + if (GetSubtitleInput(i) != nullptr) { + return true; + } + + return false; +} + +// Called from GraphThread +void CMainFrame::OnPlayAudio(UINT nID) +{ + int i = (int)nID - ID_AUDIO_SUBITEM_START; + + DWORD cStreams = 0; + + if (GetPlaybackMode() == PM_DVD) { + m_pDVDC->SelectAudioStream(i, DVD_CMD_FLAG_Block, nullptr); + LCID lcid = 0; + if (SUCCEEDED(m_pDVDI->GetAudioLanguage(i, &lcid)) && lcid != 0) { + GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentAudioLang); + } else { + currentAudioLang.Empty(); + } + } else if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { + if (i == 0) { + ShowOptions(CPPageAudioSwitcher::IDD); + } else { + LONG sidx = i - 1; + if (m_iReloadAudioIdx >= 0) { + if (m_iReloadAudioIdx < cStreams) { + sidx = m_iReloadAudioIdx; + } + m_iReloadAudioIdx = -1; + } + if (sidx >= cStreams) { //invalid stream? + return; + } + if (SUCCEEDED(m_pAudioSwitcherSS->Enable(sidx, AMSTREAMSELECTENABLE_ENABLE))) { + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(m_pAudioSwitcherSS->Info(sidx, &pmt, nullptr, &lcid, nullptr, nullptr, nullptr, nullptr))) { + UpdateSelectedAudioStreamInfo(sidx, pmt, lcid); + DeleteMediaType(pmt); + } else { + UpdateSelectedAudioStreamInfo(sidx, nullptr, -1); + } + } + } + } else if (GetPlaybackMode() == PM_FILE) { + OnNavStreamSelectSubMenu(i, 1); + AfxGetAppSettings().MRU.UpdateCurrentAudioTrack(i); + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + if (CBDAChannel* pChannel = m_pDVBState->pChannel) { + OnNavStreamSelectSubMenu(i, 1); + pChannel->SetDefaultAudio(i); + } + } +} + +void CMainFrame::OnSubtitlesDefaultStyle() +{ + CAppSettings& s = AfxGetAppSettings(); + if (!m_pSubStreams.IsEmpty()) { + s.bSubtitleOverrideDefaultStyle = !s.bSubtitleOverrideDefaultStyle; + UpdateSubtitleRenderingParameters(); + RepaintVideo(); + } +} + +void CMainFrame::OnPlaySubtitles(UINT nID) +{ + CAppSettings& s = AfxGetAppSettings(); + int i = (int)nID - ID_SUBTITLES_SUBITEM_START; + + if (GetPlaybackMode() == PM_DVD) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) + && ulStreamsAvailable) { + if (i == 0) { + m_pDVDC->SetSubpictureState(bIsDisabled, DVD_CMD_FLAG_Block, nullptr); + } else if (i <= int(ulStreamsAvailable)) { + m_pDVDC->SelectSubpictureStream(i - 1, DVD_CMD_FLAG_Block, nullptr); + m_pDVDC->SetSubpictureState(TRUE, DVD_CMD_FLAG_Block, nullptr); + } + i -= ulStreamsAvailable + 1; + } + } + + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + if (CBDAChannel* pChannel = m_pDVBState->pChannel) { + OnNavStreamSelectSubMenu(i, 2); + pChannel->SetDefaultSubtitle(i); + SetSubtitle(i); + } + } else if (!m_pSubStreams.IsEmpty()) { + // Currently the subtitles menu contains 6 items apart from the actual subtitles list when the ISR is used + i -= 6; + + if (i == -6) { + // options + ShowOptions(CPPageSubtitles::IDD); + } else if (i == -5) { + // styles + int j = 0; + SubtitleInput* pSubInput = GetSubtitleInput(j, true); + CLSID clsid; + + if (pSubInput && SUCCEEDED(pSubInput->pSubStream->GetClassID(&clsid))) { + if (clsid == __uuidof(CRenderedTextSubtitle)) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; + + CAutoPtrArray pages; + CAtlArray styles; + + POSITION pos = pRTS->m_styles.GetStartPosition(); + for (int k = 0; pos; k++) { + CString styleName; + STSStyle* style; + pRTS->m_styles.GetNextAssoc(pos, styleName, style); + + CAutoPtr page(DEBUG_NEW CPPageSubStyle(/*isStyleDialog = */ true)); + if (style->hasAnsiStyleName) { + styleName = ToUnicode(styleName, pRTS->GetCharSet(style->charSet)); + } + page->InitStyle(styleName, *style); + pages.Add(page); + styles.Add(style); + } + + CMPCThemePropertySheet dlg(IDS_SUBTITLES_STYLES_CAPTION, GetModalParent()); + for (size_t l = 0; l < pages.GetCount(); l++) { + dlg.AddPage(pages[l]); + } + + if (dlg.DoModal() == IDOK) { + { + CAutoLock cAutoLock(&m_csSubLock); + bool defaultStyleChanged = false, otherStyleChanged = false; + + for (size_t l = 0; l < pages.GetCount(); l++) { + STSStyle tmpStyle = *styles[l]; + pages[l]->GetStyle(*styles[l]); + if (pages[l]->GetStyleName() == L"Default") { + if (*styles[l] != s.subtitlesDefStyle) { + pRTS->m_bUsingPlayerDefaultStyle = false; + pRTS->SetDefaultStyle(*styles[l]); + defaultStyleChanged = true; + } + } else if (tmpStyle != *styles[l]) { + otherStyleChanged = true; + } + } + if (otherStyleChanged || defaultStyleChanged) { + if (!defaultStyleChanged) { //it will already have triggered SetStyleChanged() internally + pRTS->SetStyleChanged(); + } + pRTS->Deinit(); + InvalidateSubtitle(); + RepaintVideo(); + m_wndSubresyncBar.ReloadSubtitle(); + } + } + } + } + } + } else if (i == -4) { + // reload + ReloadSubtitle(); + } else if (i == -3) { + // hide + ToggleSubtitleOnOff(); + } else if (i == -2) { + // override default style + s.bSubtitleOverrideDefaultStyle = !s.bSubtitleOverrideDefaultStyle; + UpdateSubtitleRenderingParameters(); + RepaintVideo(); + } else if (i == -1) { + // override all styles + s.bSubtitleOverrideAllStyles = !s.bSubtitleOverrideAllStyles; + UpdateSubtitleRenderingParameters(); + RepaintVideo(); + } else if (i >= 0) { + // this is an actual item from the subtitles list + s.fEnableSubtitles = true; + SetSubtitle(i); + } + } else if (GetPlaybackMode() == PM_FILE) { + OnNavStreamSelectSubMenu(i, 2); + } +} + +void CMainFrame::OnPlayVideoStreams(UINT nID) +{ + nID -= ID_VIDEO_STREAMS_SUBITEM_START; + + if (GetPlaybackMode() == PM_FILE) { + OnNavStreamSelectSubMenu(nID, 0); + } else if (GetPlaybackMode() == PM_DVD) { + m_pDVDC->SelectAngle(nID + 1, DVD_CMD_FLAG_Block, nullptr); + + CString osdMessage; + osdMessage.Format(IDS_AG_ANGLE, nID + 1); + m_OSD.DisplayMessage(OSD_TOPLEFT, osdMessage); + } +} + +void CMainFrame::OnPlayFiltersStreams(UINT nID) +{ + nID -= ID_FILTERSTREAMS_SUBITEM_START; + CComPtr pAMSS = m_ssarray[nID]; + UINT i = nID; + + while (i > 0 && pAMSS == m_ssarray[i - 1]) { + i--; + } + + if (FAILED(pAMSS->Enable(nID - i, AMSTREAMSELECTENABLE_ENABLE))) { + MessageBeep(UINT_MAX); + } + + OpenSetupStatusBar(); +} + +void CMainFrame::OnPlayVolume(UINT nID) +{ + if (GetLoadState() == MLS::LOADED) { + CString strVolume; + m_pBA->put_Volume(m_wndToolBar.Volume); + + //strVolume.Format (L"Vol : %d dB", m_wndToolBar.Volume / 100); + if (m_wndToolBar.Volume == -10000) { + strVolume.Format(IDS_VOLUME_OSD, 0); + } else { + strVolume.Format(IDS_VOLUME_OSD, m_wndToolBar.m_volctrl.GetPos()); + } + m_OSD.DisplayMessage(OSD_TOPLEFT, strVolume); + //SendStatusMessage(strVolume, 3000); // Now the volume is displayed in three places at once. + } + + m_Lcd.SetVolume((m_wndToolBar.Volume > -10000 ? m_wndToolBar.m_volctrl.GetPos() : 1)); +} + +void CMainFrame::OnPlayVolumeBoost(UINT nID) +{ + CAppSettings& s = AfxGetAppSettings(); + + switch (nID) { + case ID_VOLUME_BOOST_INC: + s.nAudioBoost += s.nVolumeStep; + if (s.nAudioBoost > 300) { + s.nAudioBoost = 300; + } + break; + case ID_VOLUME_BOOST_DEC: + if (s.nAudioBoost > s.nVolumeStep) { + s.nAudioBoost -= s.nVolumeStep; + } else { + s.nAudioBoost = 0; + } + break; + case ID_VOLUME_BOOST_MIN: + s.nAudioBoost = 0; + break; + case ID_VOLUME_BOOST_MAX: + s.nAudioBoost = 300; + break; + } + + SetVolumeBoost(s.nAudioBoost); +} + +void CMainFrame::SetVolumeBoost(UINT nAudioBoost) +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + bool fNormalize, fNormalizeRecover; + UINT nMaxNormFactor, nBoost; + pASF->GetNormalizeBoost2(fNormalize, nMaxNormFactor, fNormalizeRecover, nBoost); + + CString strBoost; + strBoost.Format(IDS_BOOST_OSD, nAudioBoost); + pASF->SetNormalizeBoost2(fNormalize, nMaxNormFactor, fNormalizeRecover, nAudioBoost); + m_OSD.DisplayMessage(OSD_TOPLEFT, strBoost); + } +} + +void CMainFrame::OnUpdatePlayVolumeBoost(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(); +} + +void CMainFrame::OnCustomChannelMapping() +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + CAppSettings& s = AfxGetAppSettings(); + s.fCustomChannelMapping = !s.fCustomChannelMapping; + pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(s.fCustomChannelMapping ? IDS_OSD_CUSTOM_CH_MAPPING_ON : IDS_OSD_CUSTOM_CH_MAPPING_OFF)); + } +} + +void CMainFrame::OnUpdateCustomChannelMapping(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(s.fEnableAudioSwitcher); +} + +void CMainFrame::OnNormalizeRegainVolume(UINT nID) +{ + if (CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB)) { + CAppSettings& s = AfxGetAppSettings(); + WORD osdMessage = 0; + + switch (nID) { + case ID_NORMALIZE: + s.fAudioNormalize = !s.fAudioNormalize; + osdMessage = s.fAudioNormalize ? IDS_OSD_NORMALIZE_ON : IDS_OSD_NORMALIZE_OFF; + break; + case ID_REGAIN_VOLUME: + s.fAudioNormalizeRecover = !s.fAudioNormalizeRecover; + osdMessage = s.fAudioNormalizeRecover ? IDS_OSD_REGAIN_VOLUME_ON : IDS_OSD_REGAIN_VOLUME_OFF; + break; + } + + pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMessage)); + } +} + +void CMainFrame::OnUpdateNormalizeRegainVolume(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable(s.fEnableAudioSwitcher); +} + +void CMainFrame::OnPlayColor(UINT nID) +{ + if (m_pVMRMC || m_pMFVP) { + CAppSettings& s = AfxGetAppSettings(); + //ColorRanges* crs = AfxGetMyApp()->ColorControls; + int& brightness = s.iBrightness; + int& contrast = s.iContrast; + int& hue = s.iHue; + int& saturation = s.iSaturation; + CString tmp, str; + switch (nID) { + case ID_COLOR_BRIGHTNESS_INC: + brightness += 2; + [[fallthrough]]; + case ID_COLOR_BRIGHTNESS_DEC: + brightness -= 1; + SetColorControl(ProcAmp_Brightness, brightness, contrast, hue, saturation); + tmp.Format(brightness ? _T("%+d") : _T("%d"), brightness); + str.Format(IDS_OSD_BRIGHTNESS, tmp.GetString()); + break; + case ID_COLOR_CONTRAST_INC: + contrast += 2; + [[fallthrough]]; + case ID_COLOR_CONTRAST_DEC: + contrast -= 1; + SetColorControl(ProcAmp_Contrast, brightness, contrast, hue, saturation); + tmp.Format(contrast ? _T("%+d") : _T("%d"), contrast); + str.Format(IDS_OSD_CONTRAST, tmp.GetString()); + break; + case ID_COLOR_HUE_INC: + hue += 2; + [[fallthrough]]; + case ID_COLOR_HUE_DEC: + hue -= 1; + SetColorControl(ProcAmp_Hue, brightness, contrast, hue, saturation); + tmp.Format(hue ? _T("%+d") : _T("%d"), hue); + str.Format(IDS_OSD_HUE, tmp.GetString()); + break; + case ID_COLOR_SATURATION_INC: + saturation += 2; + [[fallthrough]]; + case ID_COLOR_SATURATION_DEC: + saturation -= 1; + SetColorControl(ProcAmp_Saturation, brightness, contrast, hue, saturation); + tmp.Format(saturation ? _T("%+d") : _T("%d"), saturation); + str.Format(IDS_OSD_SATURATION, tmp.GetString()); + break; + case ID_COLOR_RESET: + brightness = AfxGetMyApp()->GetColorControl(ProcAmp_Brightness)->DefaultValue; + contrast = AfxGetMyApp()->GetColorControl(ProcAmp_Contrast)->DefaultValue; + hue = AfxGetMyApp()->GetColorControl(ProcAmp_Hue)->DefaultValue; + saturation = AfxGetMyApp()->GetColorControl(ProcAmp_Saturation)->DefaultValue; + SetColorControl(ProcAmp_All, brightness, contrast, hue, saturation); + str.LoadString(IDS_OSD_RESET_COLOR); + break; + } + m_OSD.DisplayMessage(OSD_TOPLEFT, str); + } else { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_OSD_NO_COLORCONTROL)); + } +} + +void CMainFrame::OnAfterplayback(UINT nID) +{ + CAppSettings& s = AfxGetAppSettings(); + WORD osdMsg = 0; + bool bDisable = false; + + auto toggleOption = [&](UINT64 nID) { + bDisable = !!(s.nCLSwitches & nID); + s.nCLSwitches &= ~CLSW_AFTERPLAYBACK_MASK | nID; + s.nCLSwitches ^= nID; + }; + + switch (nID) { + case ID_AFTERPLAYBACK_EXIT: + toggleOption(CLSW_CLOSE); + osdMsg = IDS_AFTERPLAYBACK_EXIT; + break; + case ID_AFTERPLAYBACK_STANDBY: + toggleOption(CLSW_STANDBY); + osdMsg = IDS_AFTERPLAYBACK_STANDBY; + break; + case ID_AFTERPLAYBACK_HIBERNATE: + toggleOption(CLSW_HIBERNATE); + osdMsg = IDS_AFTERPLAYBACK_HIBERNATE; + break; + case ID_AFTERPLAYBACK_SHUTDOWN: + toggleOption(CLSW_SHUTDOWN); + osdMsg = IDS_AFTERPLAYBACK_SHUTDOWN; + break; + case ID_AFTERPLAYBACK_LOGOFF: + toggleOption(CLSW_LOGOFF); + osdMsg = IDS_AFTERPLAYBACK_LOGOFF; + break; + case ID_AFTERPLAYBACK_LOCK: + toggleOption(CLSW_LOCK); + osdMsg = IDS_AFTERPLAYBACK_LOCK; + break; + case ID_AFTERPLAYBACK_MONITOROFF: + toggleOption(CLSW_MONITOROFF); + osdMsg = IDS_AFTERPLAYBACK_MONITOROFF; + break; + case ID_AFTERPLAYBACK_PLAYNEXT: + toggleOption(CLSW_PLAYNEXT); + osdMsg = IDS_AFTERPLAYBACK_PLAYNEXT; + break; + case ID_AFTERPLAYBACK_DONOTHING: + toggleOption(CLSW_DONOTHING); + osdMsg = IDS_AFTERPLAYBACK_DONOTHING; + break; + } + if (bDisable) { + switch (s.eAfterPlayback) { + case CAppSettings::AfterPlayback::PLAY_NEXT: + osdMsg = IDS_AFTERPLAYBACK_PLAYNEXT; + break; + case CAppSettings::AfterPlayback::REWIND: + osdMsg = IDS_AFTERPLAYBACK_REWIND; + break; + case CAppSettings::AfterPlayback::MONITOROFF: + osdMsg = IDS_AFTERPLAYBACK_MONITOROFF; + break; + case CAppSettings::AfterPlayback::CLOSE: + osdMsg = IDS_AFTERPLAYBACK_CLOSE; + break; + case CAppSettings::AfterPlayback::EXIT: + osdMsg = IDS_AFTERPLAYBACK_EXIT; + break; + default: + ASSERT(FALSE); + [[fallthrough]]; + case CAppSettings::AfterPlayback::DO_NOTHING: + osdMsg = IDS_AFTERPLAYBACK_DONOTHING; + break; + } + } + + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMsg)); +} + +void CMainFrame::OnUpdateAfterplayback(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + bool bChecked; + bool bRadio = false; + + switch (pCmdUI->m_nID) { + case ID_AFTERPLAYBACK_EXIT: + bChecked = !!(s.nCLSwitches & CLSW_CLOSE); + bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::EXIT; + break; + case ID_AFTERPLAYBACK_STANDBY: + bChecked = !!(s.nCLSwitches & CLSW_STANDBY); + break; + case ID_AFTERPLAYBACK_HIBERNATE: + bChecked = !!(s.nCLSwitches & CLSW_HIBERNATE); + break; + case ID_AFTERPLAYBACK_SHUTDOWN: + bChecked = !!(s.nCLSwitches & CLSW_SHUTDOWN); + break; + case ID_AFTERPLAYBACK_LOGOFF: + bChecked = !!(s.nCLSwitches & CLSW_LOGOFF); + break; + case ID_AFTERPLAYBACK_LOCK: + bChecked = !!(s.nCLSwitches & CLSW_LOCK); + break; + case ID_AFTERPLAYBACK_MONITOROFF: + bChecked = !!(s.nCLSwitches & CLSW_MONITOROFF); + bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::MONITOROFF; + break; + case ID_AFTERPLAYBACK_PLAYNEXT: + bChecked = !!(s.nCLSwitches & CLSW_PLAYNEXT); + bRadio = (s.eAfterPlayback == CAppSettings::AfterPlayback::PLAY_NEXT) && (m_wndPlaylistBar.GetCount() < 2); + break; + case ID_AFTERPLAYBACK_DONOTHING: + bChecked = !!(s.nCLSwitches & CLSW_DONOTHING); + bRadio = s.eAfterPlayback == CAppSettings::AfterPlayback::DO_NOTHING; + break; + default: + ASSERT(FALSE); + return; + } + + if (IsMenu(*pCmdUI->m_pMenu)) { + MENUITEMINFO mii, cii; + ZeroMemory(&cii, sizeof(MENUITEMINFO)); + cii.cbSize = sizeof(cii); + cii.fMask = MIIM_FTYPE; + pCmdUI->m_pMenu->GetMenuItemInfo(pCmdUI->m_nID, &cii); + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE | MIIM_STATE; + mii.fType = (bRadio ? MFT_RADIOCHECK : 0) | (cii.fType & MFT_OWNERDRAW); //preserve owner draw flag + mii.fState = (bRadio ? MFS_DISABLED : 0) | (bChecked || bRadio ? MFS_CHECKED : 0); + VERIFY(CMPCThemeMenu::SetThemedMenuItemInfo(pCmdUI->m_pMenu, pCmdUI->m_nID, &mii)); + } +} + +void CMainFrame::OnPlayRepeat(UINT nID) +{ + CAppSettings& s = AfxGetAppSettings(); + WORD osdMsg = 0; + + switch (nID) { + case ID_PLAY_REPEAT_ONEFILE: + s.eLoopMode = CAppSettings::LoopMode::FILE; + osdMsg = IDS_PLAYLOOPMODE_FILE; + break; + case ID_PLAY_REPEAT_WHOLEPLAYLIST: + s.eLoopMode = CAppSettings::LoopMode::PLAYLIST; + osdMsg = IDS_PLAYLOOPMODE_PLAYLIST; + break; + default: + ASSERT(FALSE); + return; + } + + m_nLoops = 0; + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(osdMsg)); +} + +void CMainFrame::OnUpdatePlayRepeat(CCmdUI* pCmdUI) +{ + CAppSettings::LoopMode loopmode; + + switch (pCmdUI->m_nID) { + case ID_PLAY_REPEAT_ONEFILE: + loopmode = CAppSettings::LoopMode::FILE; + break; + case ID_PLAY_REPEAT_WHOLEPLAYLIST: + loopmode = CAppSettings::LoopMode::PLAYLIST; + break; + default: + ASSERT(FALSE); + return; + } + if (AfxGetAppSettings().eLoopMode == loopmode && pCmdUI->m_pMenu) { + pCmdUI->m_pMenu->CheckMenuRadioItem(ID_PLAY_REPEAT_ONEFILE, ID_PLAY_REPEAT_WHOLEPLAYLIST, pCmdUI->m_nID, MF_BYCOMMAND); + } +} + +void CMainFrame::OnPlayRepeatForever() +{ + CAppSettings& s = AfxGetAppSettings(); + + s.fLoopForever = !s.fLoopForever; + + m_nLoops = 0; + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(s.fLoopForever ? IDS_PLAYLOOP_FOREVER_ON : IDS_PLAYLOOP_FOREVER_OFF)); +} + +void CMainFrame::OnUpdatePlayRepeatForever(CCmdUI* pCmdUI) +{ + pCmdUI->SetCheck(AfxGetAppSettings().fLoopForever); +} + +bool CMainFrame::SeekToFileChapter(int iChapter, bool bRelative /*= false*/) +{ + if (GetPlaybackMode() != PM_FILE || !m_pCB) { + return false; + } + + bool ret = false; + + if (DWORD nChapters = m_pCB->ChapGetCount()) { + REFERENCE_TIME rt; + + if (bRelative) { + if (m_pMS && SUCCEEDED(m_pMS->GetCurrentPosition(&rt))) { + if (iChapter < 0) { + // Add a small threshold to jump back at least that amount of time + // This is needed when rt is near start of current chapter + rt -= PREV_CHAP_THRESHOLD * 10000000; + iChapter = 0; + iChapter = m_pCB->ChapLookupPrevious(&rt, nullptr); + // seek to start if there is no previous chapter + if (iChapter == -1 && rt >= 0) { + REFERENCE_TIME rtStart, rtStop; + m_wndSeekBar.GetRange(rtStart, rtStop); + DoSeekTo(rtStart, false); + return true; + } + } else { + iChapter = m_pCB->ChapLookupNext(&rt, nullptr); + } + } else { + return false; + } + } + + CComBSTR name; + REFERENCE_TIME rtStart, rtStop; + m_wndSeekBar.GetRange(rtStart, rtStop); + if (iChapter >= 0 && DWORD(iChapter) < nChapters && SUCCEEDED(m_pCB->ChapGet(iChapter, &rt, &name)) && rt < rtStop) { + DoSeekTo(rt, false); + SendStatusMessage(ResStr(IDS_AG_CHAPTER2) + CString(name), 3000); + ret = true; + + REFERENCE_TIME rtDur; + if (m_pMS && SUCCEEDED(m_pMS->GetDuration(&rtDur))) { + const CAppSettings& s = AfxGetAppSettings(); + CString strOSD; + REFERENCE_TIME rtShow = rt; + if (s.fRemainingTime) { + strOSD.Append(_T("-")); + rtShow = rtDur - rt; + } + if (rtDur >= 36005000000LL) { // At least 1 hour (rounded) + strOSD.AppendFormat(_T("%s / %s "), ReftimeToString2(rtShow).GetString(), ReftimeToString2(rtDur).GetString()); + } else { + strOSD.AppendFormat(_T("%s / %s "), ReftimeToString3(rtShow).GetString(), ReftimeToString3(rtDur).GetString()); + } + strOSD.AppendFormat(_T("\"%s\" (%d/%u)"), static_cast(name), iChapter + 1, nChapters); + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + } + } + } + + return ret; +} + +bool CMainFrame::SeekToDVDChapter(int iChapter, bool bRelative /*= false*/) +{ + if (GetPlaybackMode() != PM_DVD) { + return false; + } + + ULONG ulNumOfVolumes, ulVolume; + DVD_DISC_SIDE Side; + ULONG ulNumOfTitles = 0; + CheckNoLogBool(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles)); + + DVD_PLAYBACK_LOCATION2 Location; + ULONG ulNumOfChapters = 0; + ULONG uTitle = 0, uChapter = 0; + if (bRelative) { + CheckNoLogBool(m_pDVDI->GetCurrentLocation(&Location)); + + CheckNoLogBool(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters)); + + uTitle = Location.TitleNum; + uChapter = Location.ChapterNum; + + if (iChapter < 0) { + ULONG tsec = (Location.TimeCode.bHours * 3600) + + (Location.TimeCode.bMinutes * 60) + + (Location.TimeCode.bSeconds); + ULONG diff = 0; + if (m_lChapterStartTime != 0xFFFFFFFF && tsec > m_lChapterStartTime) { + diff = tsec - m_lChapterStartTime; + } + // Go the previous chapter only if more than PREV_CHAP_THRESHOLD seconds + // have passed since the beginning of the current chapter else restart it + if (diff <= PREV_CHAP_THRESHOLD) { + // If we are at the first chapter of a volume that isn't the first + // one, we skip to the last chapter of the previous volume. + if (uChapter == 1 && uTitle > 1) { + uTitle--; + CheckNoLogBool(m_pDVDI->GetNumberOfChapters(uTitle, &uChapter)); + } else if (uChapter > 1) { + uChapter--; + } + } + } else { + // If we are at the last chapter of a volume that isn't the last + // one, we skip to the first chapter of the next volume. + if (uChapter == ulNumOfChapters && uTitle < ulNumOfTitles) { + uTitle++; + uChapter = 1; + } else if (uChapter < ulNumOfChapters) { + uChapter++; + } + } + } else if (iChapter > 0) { + uChapter = ULONG(iChapter); + if (uChapter <= ulNumOfTitles) { + uTitle = uChapter; + uChapter = 1; + } else { + CheckNoLogBool(m_pDVDI->GetCurrentLocation(&Location)); + uTitle = Location.TitleNum; + uChapter -= ulNumOfTitles; + } + } + + if (uTitle && uChapter + && SUCCEEDED(m_pDVDC->PlayChapterInTitle(uTitle, uChapter, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr))) { + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location)) + && SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters))) { + CString strTitle; + strTitle.Format(IDS_AG_TITLE2, Location.TitleNum, ulNumOfTitles); + __int64 start, stop; + m_wndSeekBar.GetRange(start, stop); + + CString strOSD; + if (stop > 0) { + const CAppSettings& s = AfxGetAppSettings(); + + DVD_HMSF_TIMECODE currentHMSF = s.fRemainingTime ? RT2HMS_r(stop - HMSF2RT(Location.TimeCode)) : Location.TimeCode; + DVD_HMSF_TIMECODE stopHMSF = RT2HMS_r(stop); + strOSD.Format(_T("%s%s/%s %s, %s%02u/%02lu"), + s.fRemainingTime ? _T("- ") : _T(""), DVDtimeToString(currentHMSF, stopHMSF.bHours > 0).GetString(), DVDtimeToString(stopHMSF).GetString(), + strTitle.GetString(), ResStr(IDS_AG_CHAPTER2).GetString(), Location.ChapterNum, ulNumOfChapters); + } else { + strOSD.Format(_T("%s, %s%02u/%02lu"), strTitle.GetString(), ResStr(IDS_AG_CHAPTER2).GetString(), Location.ChapterNum, ulNumOfChapters); + } + + m_OSD.DisplayMessage(OSD_TOPLEFT, strOSD, 3000); + } + + return true; + } + + return false; +} + +// navigate +void CMainFrame::OnNavigateSkip(UINT nID) +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (GetPlaybackMode() == PM_FILE || CanSkipFromClosedFile()) { + m_nLastSkipDirection = nID; + + if (!SeekToFileChapter((nID == ID_NAVIGATE_SKIPBACK) ? -1 : 1, true)) { + if (nID == ID_NAVIGATE_SKIPBACK) { + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACKFILE); + } else if (nID == ID_NAVIGATE_SKIPFORWARD) { + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARDFILE); + } + } + } else if (GetPlaybackMode() == PM_DVD) { + m_dSpeedRate = 1.0; + + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + + SeekToDVDChapter((nID == ID_NAVIGATE_SKIPBACK) ? -1 : 1, true); + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + int nCurrentChannel = s.nDVBLastChannel; + + if (nID == ID_NAVIGATE_SKIPBACK) { + if (SUCCEEDED(SetChannel(nCurrentChannel - 1))) { + if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_wndNavigationBar.m_navdlg.UpdatePos(nCurrentChannel - 1); + } + } + } else if (nID == ID_NAVIGATE_SKIPFORWARD) { + if (SUCCEEDED(SetChannel(nCurrentChannel + 1))) { + if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_wndNavigationBar.m_navdlg.UpdatePos(nCurrentChannel + 1); + } + } + } + } + } +} + +bool CMainFrame::CanSkipFromClosedFile() { + if (GetPlaybackMode() == PM_NONE && AfxGetAppSettings().fUseSearchInFolder) { + if (m_wndPlaylistBar.GetCount() == 1) { + CPlaylistItem pli; + return m_wndPlaylistBar.GetCur(pli, true) && !PathUtils::IsURL(pli.m_fns.GetHead()); + } else if (m_wndPlaylistBar.GetCount() == 0 && !lastOpenFile.IsEmpty()) { + return !PathUtils::IsURL(lastOpenFile); + } + } + return false; +} + +void CMainFrame::OnUpdateNavigateSkip(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + + pCmdUI->Enable( + (GetLoadState() == MLS::LOADED + && ((GetPlaybackMode() == PM_DVD + && m_iDVDDomain != DVD_DOMAIN_VideoManagerMenu + && m_iDVDDomain != DVD_DOMAIN_VideoTitleSetMenu) + || (GetPlaybackMode() == PM_FILE && s.fUseSearchInFolder) + || (GetPlaybackMode() == PM_FILE && !s.fUseSearchInFolder && (m_wndPlaylistBar.GetCount() > 1 || m_pCB->ChapGetCount() > 1)) + || (GetPlaybackMode() == PM_DIGITAL_CAPTURE && !m_pDVBState->bSetChannelActive))) + || (GetLoadState() == MLS::CLOSED && CanSkipFromClosedFile()) //to support skipping from broken file + ); +} + +void CMainFrame::OnNavigateSkipFile(UINT nID) +{ + if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_ANALOG_CAPTURE || CanSkipFromClosedFile()) { + if (m_wndPlaylistBar.GetCount() == 1 || CanSkipFromClosedFile()) { + CAppSettings& s = AfxGetAppSettings(); + if (GetPlaybackMode() == PM_ANALOG_CAPTURE || !s.fUseSearchInFolder) { + SendMessage(WM_COMMAND, ID_PLAY_STOP); // do not remove this, unless you want a circular call with OnPlayPlay() + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } else { + if (nID == ID_NAVIGATE_SKIPBACKFILE) { + if (!SearchInDir(false, s.bLoopFolderOnPlayNextFile)) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_FIRST_IN_FOLDER)); + } + } else if (nID == ID_NAVIGATE_SKIPFORWARDFILE) { + if (!SearchInDir(true, s.bLoopFolderOnPlayNextFile)) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_LAST_IN_FOLDER)); + } + } + } + } else { + if (nID == ID_NAVIGATE_SKIPBACKFILE) { + m_wndPlaylistBar.SetPrev(); + } else if (nID == ID_NAVIGATE_SKIPFORWARDFILE) { + m_wndPlaylistBar.SetNext(); + } + + OpenCurPlaylistItem(); + } + } +} + +void CMainFrame::OnUpdateNavigateSkipFile(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + pCmdUI->Enable( + (GetLoadState() == MLS::LOADED + && ((GetPlaybackMode() == PM_FILE && (m_wndPlaylistBar.GetCount() > 1 || s.fUseSearchInFolder)) + || (GetPlaybackMode() == PM_ANALOG_CAPTURE && !m_fCapturing && m_wndPlaylistBar.GetCount() > 1))) + || (GetLoadState() == MLS::CLOSED && CanSkipFromClosedFile()) + ); +} + +void CMainFrame::OnNavigateGoto() +{ + if ((GetLoadState() != MLS::LOADED) || IsD3DFullScreenMode()) { + return; + } + + const REFTIME atpf = GetAvgTimePerFrame(); + + REFERENCE_TIME start, dur = -1; + m_wndSeekBar.GetRange(start, dur); + CGoToDlg dlg(m_wndSeekBar.GetPos(), dur, atpf > 0.0 ? (1.0 / atpf) : 0.0); + if (IDOK != dlg.DoModal() || dlg.m_time < 0) { + return; + } + + DoSeekTo(dlg.m_time); +} + +void CMainFrame::OnUpdateNavigateGoto(CCmdUI* pCmdUI) +{ + bool fEnable = false; + + if (GetLoadState() == MLS::LOADED) { + fEnable = true; + if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { + fEnable = false; + } else if (IsPlaybackCaptureMode()) { + fEnable = false; + } + } + + pCmdUI->Enable(fEnable); +} + +void CMainFrame::OnNavigateMenu(UINT nID) +{ + nID -= ID_NAVIGATE_TITLEMENU; + + if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_DVD) { + return; + } + + m_dSpeedRate = 1.0; + + if (GetMediaState() != State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + + m_pDVDC->ShowMenu((DVD_MENU_ID)(nID + 2), DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); +} + +void CMainFrame::OnUpdateNavigateMenu(CCmdUI* pCmdUI) +{ + UINT nID = pCmdUI->m_nID - ID_NAVIGATE_TITLEMENU; + ULONG ulUOPs; + + if (GetLoadState() != MLS::LOADED || GetPlaybackMode() != PM_DVD + || FAILED(m_pDVDI->GetCurrentUOPS(&ulUOPs))) { + pCmdUI->Enable(FALSE); + return; + } + + pCmdUI->Enable(!(ulUOPs & (UOP_FLAG_ShowMenu_Title << nID))); +} + +void CMainFrame::OnNavigateJumpTo(UINT nID) +{ + if (nID < ID_NAVIGATE_JUMPTO_SUBITEM_START) { + return; + } + + const CAppSettings& s = AfxGetAppSettings(); + + if (GetPlaybackMode() == PM_FILE) { + int id = nID - ID_NAVIGATE_JUMPTO_SUBITEM_START; + + if (id < (int)m_MPLSPlaylist.size() && m_MPLSPlaylist.size() > 1) { + int idx = 0; + for (auto &Item : m_MPLSPlaylist) { + if (idx == id) { + m_bIsBDPlay = true; + m_wndPlaylistBar.Empty(); + CAtlList sl; + sl.AddTail(CString(Item.m_strFileName)); + m_wndPlaylistBar.Append(sl, false); + OpenCurPlaylistItem(); + return; + } + idx++; + } + } + + if (m_MPLSPlaylist.size() > 1) { + id -= (int)m_MPLSPlaylist.size(); + } + + if (m_pCB->ChapGetCount() > 1) { + if (SeekToFileChapter(id)) { + return; + } + + id -= m_pCB->ChapGetCount(); + } + + if (id >= 0 && id < m_wndPlaylistBar.GetCount() && m_wndPlaylistBar.GetSelIdx() != id) { + m_wndPlaylistBar.SetSelIdx(id); + OpenCurPlaylistItem(); + } + } else if (GetPlaybackMode() == PM_DVD) { + SeekToDVDChapter(nID - ID_NAVIGATE_JUMPTO_SUBITEM_START + 1); + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + int nChannel = nID - ID_NAVIGATE_JUMPTO_SUBITEM_START; + + if (s.nDVBLastChannel != nChannel) { + if (SUCCEEDED(SetChannel(nChannel))) { + if (m_controls.ControlChecked(CMainFrameControls::Panel::NAVIGATION)) { + m_wndNavigationBar.m_navdlg.UpdatePos(nChannel); + } + } + } + } + } +} + +void CMainFrame::OnNavigateMenuItem(UINT nID) +{ + nID -= ID_NAVIGATE_MENU_LEFT; + + if (GetPlaybackMode() == PM_DVD) { + switch (nID) { + case 0: + m_pDVDC->SelectRelativeButton(DVD_Relative_Left); + break; + case 1: + m_pDVDC->SelectRelativeButton(DVD_Relative_Right); + break; + case 2: + m_pDVDC->SelectRelativeButton(DVD_Relative_Upper); + break; + case 3: + m_pDVDC->SelectRelativeButton(DVD_Relative_Lower); + break; + case 4: + if (m_iDVDDomain == DVD_DOMAIN_Title || m_iDVDDomain == DVD_DOMAIN_VideoTitleSetMenu || m_iDVDDomain == DVD_DOMAIN_VideoManagerMenu) { + m_pDVDC->ActivateButton(); + } else { + OnPlayPlay(); + } + break; + case 5: + m_pDVDC->ReturnFromSubmenu(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + break; + case 6: + m_pDVDC->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + break; + default: + break; + } + } else if (GetPlaybackMode() == PM_FILE) { + OnPlayPlay(); + } +} + +void CMainFrame::OnUpdateNavigateMenuItem(CCmdUI* pCmdUI) +{ + pCmdUI->Enable((GetLoadState() == MLS::LOADED) && ((GetPlaybackMode() == PM_DVD) || (GetPlaybackMode() == PM_FILE))); +} + +void CMainFrame::OnTunerScan() +{ + m_bScanDlgOpened = true; + CTunerScanDlg dlg(this); + dlg.DoModal(); + m_bScanDlgOpened = false; +} + +void CMainFrame::OnUpdateTunerScan(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_DIGITAL_CAPTURE); +} + +// favorites + +class CDVDStateStream : public CUnknown, public IStream +{ + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) { + return + QI(IStream) + CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + + size_t m_pos; + +public: + CDVDStateStream() : CUnknown(NAME("CDVDStateStream"), nullptr) { + m_pos = 0; + } + + DECLARE_IUNKNOWN; + + CAtlArray m_data; + + // ISequentialStream + STDMETHODIMP Read(void* pv, ULONG cb, ULONG* pcbRead) { + size_t cbRead = std::min(m_data.GetCount() - m_pos, size_t(cb)); + cbRead = std::max(cbRead, size_t(0)); + if (cbRead) { + memcpy(pv, &m_data[m_pos], cbRead); + } + if (pcbRead) { + *pcbRead = (ULONG)cbRead; + } + m_pos += cbRead; + return S_OK; + } + STDMETHODIMP Write(const void* pv, ULONG cb, ULONG* pcbWritten) { + BYTE* p = (BYTE*)pv; + ULONG cbWritten = (ULONG) - 1; + while (++cbWritten < cb) { + m_data.Add(*p++); + } + if (pcbWritten) { + *pcbWritten = cbWritten; + } + return S_OK; + } + + // IStream + STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { + return E_NOTIMPL; + } + + STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize) { + return E_NOTIMPL; + } + + STDMETHODIMP CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { + return E_NOTIMPL; + } + + STDMETHODIMP Commit(DWORD grfCommitFlags) { + return E_NOTIMPL; + } + + STDMETHODIMP Revert() { + return E_NOTIMPL; + } + + STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { + return E_NOTIMPL; + } + + STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { + return E_NOTIMPL; + } + + STDMETHODIMP Stat(STATSTG* pstatstg, DWORD grfStatFlag) { + return E_NOTIMPL; + } + + STDMETHODIMP Clone(IStream** ppstm) { + return E_NOTIMPL; + } +}; + +void CMainFrame::AddFavorite(bool fDisplayMessage, bool fShowDialog) +{ + CAppSettings& s = AfxGetAppSettings(); + CAtlList args; + WORD osdMsg = 0; + const TCHAR sep = _T(';'); + + if (GetPlaybackMode() == PM_FILE) { + bool is_BD = false; + CString fn = m_wndPlaylistBar.GetCurFileNameTitle(); + if (fn.IsEmpty()) { + if (m_pFSF) { + CComHeapPtr pFN; + AM_MEDIA_TYPE mt; + if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { + fn = CStringW(pFN); + } + } + if (fn.IsEmpty()) { + return; + } + is_BD = true; + } + + CString desc = GetFileName(); + + // Name + CString name; + if (fShowDialog) { + BOOL bEnableABMarks = static_cast(abRepeat); + CFavoriteAddDlg dlg(desc, fn, bEnableABMarks); + if (dlg.DoModal() != IDOK) { + return; + } + name = dlg.m_name; + } else { + name = desc; + } + args.AddTail(name); + + // RememberPos + CString posStr = _T("0"); + if (s.bFavRememberPos) { + posStr.Format(_T("%I64d"), GetPos()); + } + // RememberABMarks + if (s.bFavRememberABMarks && abRepeat) { + posStr.AppendFormat(_T(":%I64d:%I64d"), abRepeat.positionA, abRepeat.positionB); + } + args.AddTail(posStr); + + // RelativeDrive + CString relativeDrive; + relativeDrive.Format(_T("%d"), s.bFavRelativeDrive); + + args.AddTail(relativeDrive); + + // Paths + if (is_BD) { + args.AddTail(fn); + } else { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli)) { + if (pli.m_bYoutubeDL) { + args.AddTail(pli.m_ydlSourceURL); + } else { + POSITION pos = pli.m_fns.GetHeadPosition(); + while (pos) { + args.AddTail(pli.m_fns.GetNext(pos)); + } + } + } + } + + CString str = ImplodeEsc(args, sep); + s.AddFav(FAV_FILE, str); + osdMsg = IDS_FILE_FAV_ADDED; + } else if (GetPlaybackMode() == PM_DVD) { + WCHAR path[MAX_PATH]; + ULONG len = 0; + if (SUCCEEDED(m_pDVDI->GetDVDDirectory(path, MAX_PATH, &len))) { + CString fn = path; + fn.TrimRight(_T("/\\")); + + DVD_PLAYBACK_LOCATION2 Location; + CString desc; + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location))) { + desc.Format(_T("%s - T%02u C%02u - %02u:%02u:%02u"), fn.GetString(), Location.TitleNum, Location.ChapterNum, + Location.TimeCode.bHours, Location.TimeCode.bMinutes, Location.TimeCode.bSeconds); + } else { + desc = fn; + } + // Name + CString name; + if (fShowDialog) { + CFavoriteAddDlg dlg(fn, desc); + if (dlg.DoModal() != IDOK) { + return; + } + name = dlg.m_name; + } else { + name = s.bFavRememberPos ? desc : fn; + } + args.AddTail(name); + + // RememberPos + CString pos(_T("0")); + if (s.bFavRememberPos) { + CDVDStateStream stream; + stream.AddRef(); + + CComPtr pStateData; + CComQIPtr pPersistStream; + if (SUCCEEDED(m_pDVDI->GetState(&pStateData)) + && (pPersistStream = pStateData) + && SUCCEEDED(OleSaveToStream(pPersistStream, (IStream*)&stream))) { + pos = BinToCString(stream.m_data.GetData(), stream.m_data.GetCount()); + } + } + + args.AddTail(pos); + + // Paths + args.AddTail(fn); + + CString str = ImplodeEsc(args, sep); + s.AddFav(FAV_DVD, str); + osdMsg = IDS_DVD_FAV_ADDED; + } + } // TODO: PM_ANALOG_CAPTURE and PM_DIGITAL_CAPTURE + + if (fDisplayMessage && osdMsg) { + CString osdMsgStr(StrRes(osdMsg)); + SendStatusMessage(osdMsgStr, 3000); + m_OSD.DisplayMessage(OSD_TOPLEFT, osdMsgStr, 3000); + } + if (::IsWindow(m_wndFavoriteOrganizeDialog.m_hWnd)) { + m_wndFavoriteOrganizeDialog.LoadList(); + } +} + +void CMainFrame::OnFavoritesAdd() +{ + AddFavorite(); +} + +void CMainFrame::OnUpdateFavoritesAdd(CCmdUI* pCmdUI) +{ + pCmdUI->Enable(GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DVD); +} + +void CMainFrame::OnFavoritesQuickAddFavorite() +{ + AddFavorite(true, false); +} + +void CMainFrame::OnFavoritesOrganize() +{ + m_wndFavoriteOrganizeDialog.ShowWindow(SW_SHOW); +} + +void CMainFrame::OnUpdateFavoritesOrganize(CCmdUI* pCmdUI) +{ + const CAppSettings& s = AfxGetAppSettings(); + CAtlList sl; + s.GetFav(FAV_FILE, sl); + bool enable = !sl.IsEmpty(); + + if (!enable) { + s.GetFav(FAV_DVD, sl); + enable = !sl.IsEmpty(); + } + + pCmdUI->Enable(enable); +} + +void CMainFrame::OnRecentFileClear() +{ + if (IDYES != AfxMessageBox(IDS_RECENT_FILES_QUESTION, MB_ICONQUESTION | MB_YESNO, 0)) { + return; + } + + CAppSettings& s = AfxGetAppSettings(); + s.ClearRecentFiles(); +} + +void CMainFrame::OnUpdateRecentFileClear(CCmdUI* pCmdUI) +{ + // TODO: Add your command update UI handler code here +} + +void CMainFrame::OnFavoritesFile(UINT nID) +{ + nID -= ID_FAVORITES_FILE_START; + CAtlList sl; + AfxGetAppSettings().GetFav(FAV_FILE, sl); + + if (POSITION pos = sl.FindIndex(nID)) { + PlayFavoriteFile(sl.GetAt(pos)); + } +} + +void CMainFrame::PlayFavoriteFile(const CString& fav) +{ + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + CAtlList args; + REFERENCE_TIME rtStart = 0; + FileFavorite ff = ParseFavoriteFile(fav, args, &rtStart); + + auto firstFile = args.GetHead(); + if (!m_wndPlaylistBar.SelectFileInPlaylist(firstFile) && + (!CanSendToYoutubeDL(firstFile) || + !ProcessYoutubeDLURL(firstFile, false))) { + m_wndPlaylistBar.Open(args, false); + } + + m_wndPlaylistBar.SetCurLabel(ff.Name); + + if (GetPlaybackMode() == PM_FILE && args.GetHead() == m_lastOMD->title) { + m_pMS->SetPositions(&rtStart, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + OnPlayPlay(); + } else { + OpenCurPlaylistItem(rtStart); + } + +} + +FileFavorite CMainFrame::ParseFavoriteFile(const CString& fav, CAtlList& args, REFERENCE_TIME* prtStart) +{ + FileFavorite ff; + VERIFY(FileFavorite::TryParse(fav, ff, args)); + + abRepeat.positionA = ff.MarkA; + abRepeat.positionB = ff.MarkB; + + // Start at mark A (if set) + ff.Start = std::max(ff.Start, abRepeat.positionA); + + if (prtStart) { + *prtStart = ff.Start; + } + + // NOTE: This is just for the favorites but we could add a global settings that + // does this always when on. Could be useful when using removable devices. + // All you have to do then is plug in your 500 gb drive, full with movies and/or music, + // start MPC-HC (from the 500 gb drive) with a preloaded playlist and press play. + if (ff.RelativeDrive) { + // Get the drive MPC-HC is on and apply it to the path list + CString exePath = PathUtils::GetProgramPath(true); + + CPath exeDrive(exePath); + + if (exeDrive.StripToRoot()) { + POSITION pos = args.GetHeadPosition(); + + while (pos != nullptr) { + CString& stringPath = args.GetNext(pos); // Note the reference (!) + CPath path(stringPath); + + int rootLength = path.SkipRoot(); + + if (path.StripToRoot()) { + if (_tcsicmp(exeDrive, path) != 0) { // Do we need to replace the drive letter ? + // Replace drive letter + CString newPath(exeDrive); + + newPath += stringPath.Mid(rootLength); + + stringPath = newPath; // Note: Changes args.GetHead() + } + } + } + } + } + return ff; +} + +void CMainFrame::OnUpdateFavoritesFile(CCmdUI* pCmdUI) +{ + //UINT nID = pCmdUI->m_nID - ID_FAVORITES_FILE_START; +} + +void CMainFrame::OnRecentFile(UINT nID) +{ + CAtlList fns; + auto& MRU = AfxGetAppSettings().MRU; + RecentFileEntry r; + + // find corresponding item in MRU list, we can't directly use string from menu because it may have been shortened + nID -= ID_RECENT_FILE_START; + if (nID < MRU.GetSize()) { + r = MRU[nID]; + fns.AddHeadList(&r.fns); + } else { + ASSERT(false); + return; + } + + CloseMediaBeforeOpen(); + + if (fns.GetCount() == 1 && CanSendToYoutubeDL(r.fns.GetHead())) { + if (ProcessYoutubeDLURL(fns.GetHead(), false)) { + OpenCurPlaylistItem(); + return; + } else if (IsOnYDLWhitelist(fns.GetHead())) { + // don't bother trying to open this website URL directly + return; + } + } + + CAtlList subs; + subs.AddHeadList(&r.subs); + + if (!m_wndPlaylistBar.SelectFileInPlaylist(fns.GetHead())) { + m_wndPlaylistBar.Open(fns, false, &subs, r.title, _T(""), r.cue); + } + else { + m_wndPlaylistBar.ReplaceCurrentItem(fns, &subs, r.title, _T(""), r.cue); + } + + OpenCurPlaylistItem(); +} + +void CMainFrame::OnUpdateRecentFile(CCmdUI* pCmdUI) +{ + //UINT nID = pCmdUI->m_nID - ID_RECENT_FILE_START; +} + +void CMainFrame::OnFavoritesDVD(UINT nID) +{ + nID -= ID_FAVORITES_DVD_START; + + CAtlList sl; + AfxGetAppSettings().GetFav(FAV_DVD, sl); + + if (POSITION pos = sl.FindIndex(nID)) { + PlayFavoriteDVD(sl.GetAt(pos)); + } +} + +void CMainFrame::PlayFavoriteDVD(CString fav) +{ + CAtlList args; + CString fn; + CDVDStateStream stream; + + stream.AddRef(); + + ExplodeEsc(fav, args, _T(';'), 3); + args.RemoveHeadNoReturn(); // desc / name + CString state = args.RemoveHead(); // state + if (state != _T("0")) { + CStringToBin(state, stream.m_data); + } + fn = args.RemoveHead(); // path + + SendMessage(WM_COMMAND, ID_FILE_CLOSEMEDIA); + + CComPtr pDvdState; + HRESULT hr = OleLoadFromStream((IStream*)&stream, IID_PPV_ARGS(&pDvdState)); + UNREFERENCED_PARAMETER(hr); + + CAutoPtr p(DEBUG_NEW OpenDVDData()); + if (p) { + p->path = fn; + p->pDvdState = pDvdState; + } + OpenMedia(p); +} + +void CMainFrame::OnUpdateFavoritesDVD(CCmdUI* pCmdUI) +{ + //UINT nID = pCmdUI->m_nID - ID_FAVORITES_DVD_START; +} + +void CMainFrame::OnFavoritesDevice(UINT nID) +{ + //nID -= ID_FAVORITES_DEVICE_START; +} + +void CMainFrame::OnUpdateFavoritesDevice(CCmdUI* pCmdUI) +{ + //UINT nID = pCmdUI->m_nID - ID_FAVORITES_DEVICE_START; +} + +// help + +void CMainFrame::OnHelpHomepage() +{ + ShellExecute(m_hWnd, _T("open"), WEBSITE_URL, nullptr, nullptr, SW_SHOWDEFAULT); +} + +void CMainFrame::OnHelpCheckForUpdate() +{ + UpdateChecker::CheckForUpdate(); +} + +void CMainFrame::OnHelpToolbarImages() +{ + ShellExecute(m_hWnd, _T("open"), _T("https://github.com/clsid2/mpc-hc/issues/382"), nullptr, nullptr, SW_SHOWDEFAULT); +} + +void CMainFrame::OnHelpDonate() +{ + ShellExecute(m_hWnd, _T("open"), _T("https://github.com/clsid2/mpc-hc/issues/383"), nullptr, nullptr, SW_SHOWDEFAULT); +} + +////////////////////////////////// + +static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + CAtlArray* ml = (CAtlArray*)dwData; + ml->Add(hMonitor); + return TRUE; +} + +void CMainFrame::SetDefaultWindowRect(int iMonitor) +{ + const CAppSettings& s = AfxGetAppSettings(); + CRect rcLastWindowPos = s.rcLastWindowPos; + + if (s.eCaptionMenuMode != MODE_SHOWCAPTIONMENU) { + if (s.eCaptionMenuMode == MODE_FRAMEONLY) { + ModifyStyle(WS_CAPTION, 0, SWP_NOZORDER); + } else if (s.eCaptionMenuMode == MODE_BORDERLESS) { + ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0, SWP_NOZORDER); + } + SetMenuBarVisibility(AFX_MBV_DISPLAYONFOCUS); + SetWindowPos(nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } + + CMonitors monitors; + CMonitor monitor; + if (iMonitor > 0 && iMonitor <= monitors.GetCount()) { + monitor = monitors.GetMonitor(iMonitor - 1); + } else { + monitor = CMonitors::GetNearestMonitor(this); + } + + CSize windowSize; + bool tRememberPos = s.fRememberWindowPos; + MINMAXINFO mmi; + OnGetMinMaxInfo(&mmi); + + if (s.HasFixedWindowSize()) { + windowSize = CSize(std::max(s.sizeFixedWindow.cx, mmi.ptMinTrackSize.x), std::max(s.sizeFixedWindow.cy, mmi.ptMinTrackSize.y)); + if (s.fixedWindowPosition != NO_FIXED_POSITION) { + tRememberPos = true; + CRect monitorRect; + monitor.GetWorkAreaRect(&monitorRect); + monitorRect += s.fixedWindowPosition; + rcLastWindowPos.MoveToXY(monitorRect.left, monitorRect.top); + } + } else if (s.fRememberWindowSize) { + windowSize = rcLastWindowPos.Size(); + } else { + CRect windowRect; + GetWindowRect(&windowRect); + CRect clientRect; + GetClientRect(&clientRect); + + CSize logoSize = m_wndView.GetLogoSize(); + logoSize.cx = std::max(logoSize.cx, m_dpi.ScaleX(MIN_LOGO_WIDTH)); + logoSize.cy = std::max(logoSize.cy, m_dpi.ScaleY(MIN_LOGO_HEIGHT)); + + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); + + windowSize.cx = windowRect.Width() - clientRect.Width() + logoSize.cx + uLeft + uRight; + windowSize.cy = windowRect.Height() - clientRect.Height() + logoSize.cy + uTop + uBottom; + } + + bool bRestoredWindowPosition = false; + if (tRememberPos) { + CRect windowRect(rcLastWindowPos.TopLeft(), windowSize); + if ((!iMonitor && CMonitors::IsOnScreen(windowRect)) + || (iMonitor && monitor.IsOnMonitor(windowRect))) { + restoringWindowRect = true; + MoveWindow(windowRect); + restoringWindowRect = false; + bRestoredWindowPosition = true; + } + } + + if (!bRestoredWindowPosition) { + CRect windowRect(0, 0, std::max(windowSize.cx, mmi.ptMinTrackSize.x), std::max(windowSize.cy, mmi.ptMinTrackSize.y)); + monitor.CenterRectToMonitor(windowRect, TRUE); + SetWindowPos(nullptr, windowRect.left, windowRect.top, windowSize.cx, windowSize.cy, SWP_NOZORDER | SWP_NOACTIVATE); + } + + if (s.fSavePnSZoom) { + m_ZoomX = s.dZoomX; + m_ZoomY = s.dZoomY; + } +} + +void CMainFrame::SetDefaultFullscreenState() +{ + CAppSettings& s = AfxGetAppSettings(); + + bool clGoFullscreen = !(s.nCLSwitches & (CLSW_ADD | CLSW_THUMBNAILS)) && (s.nCLSwitches & CLSW_FULLSCREEN); + + if (clGoFullscreen && !s.slFiles.IsEmpty()) { + // ignore fullscreen if all files are audio + clGoFullscreen = false; + const CMediaFormats& mf = AfxGetAppSettings().m_Formats; + POSITION pos = s.slFiles.GetHeadPosition(); + while (pos) { + CString fpath = s.slFiles.GetNext(pos); + CString ext = fpath.Mid(fpath.ReverseFind('.') + 1); + if (!mf.FindExt(ext, true)) { + clGoFullscreen = true; + break; + } + } + } + + if (clGoFullscreen) { + if (s.IsD3DFullscreen()) { + m_fStartInD3DFullscreen = true; + } else { + bool launchingFullscreenSeparateControls = false; + if (s.bFullscreenSeparateControls) { + CMonitors monitors; + CMonitor currentMonitor = monitors.GetNearestMonitor(this); + CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); + if (fullscreenMonitor.IsMonitor()) { + launchingFullscreenSeparateControls = fullscreenMonitor != currentMonitor; + } + } + + if (launchingFullscreenSeparateControls) { + m_fStartInFullscreenSeparate = true; + } else { + ToggleFullscreen(true, true); + m_bNeedZoomAfterFullscreenExit = true; + } + } + s.nCLSwitches &= ~CLSW_FULLSCREEN; + } else if (s.fRememberWindowSize && s.fRememberWindowPos && !m_fFullScreen && s.fLastFullScreen) { + // Casimir666 : if fullscreen was on, put it on back + if (s.IsD3DFullscreen()) { + m_fStartInD3DFullscreen = true; + } else { + ToggleFullscreen(true, true); + m_bNeedZoomAfterFullscreenExit = true; + } + } +} + +void CMainFrame::RestoreDefaultWindowRect() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (!m_fFullScreen && !IsZoomed() && !IsIconic() && !IsAeroSnapped()) { + CSize windowSize; + + if (s.HasFixedWindowSize()) { + windowSize = s.sizeFixedWindow; + } else if (s.fRememberWindowSize) { + windowSize = s.rcLastWindowPos.Size(); + } else { + CRect windowRect; + GetWindowRect(&windowRect); + CRect clientRect; + GetClientRect(&clientRect); + + CSize logoSize = m_wndView.GetLogoSize(); + logoSize.cx = std::max(logoSize.cx, m_dpi.ScaleX(MIN_LOGO_WIDTH)); + logoSize.cy = std::max(logoSize.cy, m_dpi.ScaleY(MIN_LOGO_HEIGHT)); + + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); + + windowSize.cx = windowRect.Width() - clientRect.Width() + logoSize.cx + uLeft + uRight; + windowSize.cy = windowRect.Height() - clientRect.Height() + logoSize.cy + uTop + uBottom; + } + + if (s.fRememberWindowPos) { + MoveWindow(CRect(s.rcLastWindowPos.TopLeft(), windowSize)); + } else { + SetWindowPos(nullptr, 0, 0, windowSize.cx, windowSize.cy, SWP_NOMOVE | SWP_NOZORDER); + CenterWindow(); + } + } +} + +CRect CMainFrame::GetInvisibleBorderSize() const +{ + CRect invisibleBorders; + + if (IsWindows10OrGreater()) { + static const WinapiFunc + fnDwmGetWindowAttribute = { _T("Dwmapi.dll"), "DwmGetWindowAttribute" }; + + if (fnDwmGetWindowAttribute) { + if (SUCCEEDED(fnDwmGetWindowAttribute(GetSafeHwnd(), DWMWA_EXTENDED_FRAME_BOUNDS, &invisibleBorders, sizeof(RECT)))) { + CRect windowRect; + GetWindowRect(windowRect); + + invisibleBorders.TopLeft() = invisibleBorders.TopLeft() - windowRect.TopLeft(); + invisibleBorders.BottomRight() = windowRect.BottomRight() - invisibleBorders.BottomRight(); + } else { + ASSERT(false); + } + } + } + + return invisibleBorders; +} + +OAFilterState CMainFrame::GetMediaStateDirect() const +{ + OAFilterState ret = -1; + if (m_eMediaLoadState == MLS::LOADED) { + m_pMC->GetState(0, &ret); + } + return ret; +} + +OAFilterState CMainFrame::GetMediaState() const +{ + OAFilterState ret = -1; + if (m_eMediaLoadState == MLS::LOADED) { + if (m_CachedFilterState != -1) { + #if DEBUG & 0 + ret = GetMediaStateDirect(); + ASSERT(ret == m_CachedFilterState || m_fFrameSteppingActive); + #endif + return m_CachedFilterState; + } else { + m_pMC->GetState(0, &ret); + } + } + return ret; +} + +OAFilterState CMainFrame::UpdateCachedMediaState() +{ + m_CachedFilterState = GetMediaStateDirect(); + return m_CachedFilterState; +} + +bool CMainFrame::MediaControlRun(bool waitforcompletion) +{ + m_dwLastPause = 0; + if (m_pMC) { + m_CachedFilterState = State_Running; + if (FAILED(m_pMC->Run())) { + // still in transition to running state + if (waitforcompletion) { + m_CachedFilterState = -1; + m_pMC->GetState(0, &m_CachedFilterState); + ASSERT(m_CachedFilterState == State_Running); + } + }; + MediaTransportControlUpdateState(State_Running); + return true; + } + return false; +} + +bool CMainFrame::MediaControlPause(bool waitforcompletion) +{ + m_dwLastPause = GetTickCount64(); + if (m_pMC) { + m_CachedFilterState = State_Paused; + if (FAILED(m_pMC->Pause())) { + // still in transition to paused state + if (waitforcompletion) { + m_CachedFilterState = -1; + m_pMC->GetState(0, &m_CachedFilterState); + ASSERT(m_CachedFilterState == State_Paused); + } + } + MediaTransportControlUpdateState(State_Paused); + return true; + } + return false; +} + +bool CMainFrame::MediaControlStop(bool waitforcompletion) +{ + m_dwLastPause = 0; + if (m_pMC) { + m_pMC->GetState(0, &m_CachedFilterState); + if (m_CachedFilterState != State_Stopped) { + if (FAILED(m_pMC->Stop())) { + ASSERT(FALSE); + m_CachedFilterState = -1; + return false; + } + if (waitforcompletion) { + m_CachedFilterState = -1; + m_pMC->GetState(0, &m_CachedFilterState); + ASSERT(m_CachedFilterState == State_Stopped); + } else { + m_CachedFilterState = State_Stopped; + } + } + MediaTransportControlUpdateState(State_Stopped); + return true; + } + return false; +} + +bool CMainFrame::MediaControlStopPreview() +{ + if (m_pMC_preview) { + OAFilterState fs = -1; + m_pMC_preview->GetState(0, &fs); + if (fs != State_Stopped) { + if (FAILED(m_pMC_preview->Stop())) { + ASSERT(FALSE); + return false; + } + m_pMC_preview->GetState(0, &fs); + ASSERT(fs == State_Stopped); + } + return true; + } + return false; +} + +void CMainFrame::SetPlaybackMode(int iNewStatus) +{ + m_iPlaybackMode = iNewStatus; +} + +CSize CMainFrame::GetVideoSizeWithRotation(bool forPreview) const +{ + CSize ret = GetVideoSize(); + if (forPreview && m_pGB_preview) { + CFGManagerPlayer* fgmPreview = static_cast(m_pGB_preview.p); + if (fgmPreview && !fgmPreview->PreviewSupportsRotation()) { + //preview cannot rotate, so we need to reverse any default rotation that swapped x/y + int rotation = ((360 - m_iDefRotation) % 360) / 90; + if (rotation == 1 || rotation == 3) { + std::swap(ret.cx, ret.cy); + } + return ret; + } + } + + if (m_pCAP && !m_pCAP3) { //videosize does not consider manual rotation + int rotation = ((360 - nearest90(m_AngleZ)) % 360) / 90; //do not add in m_iDefRotation + if (rotation == 1 || rotation == 3) { //90 degrees + std::swap(ret.cx, ret.cy); + } + } + return ret; +} + +CSize CMainFrame::GetVideoSize() const +{ + CSize ret; + if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { + return ret; + } + + const CAppSettings& s = AfxGetAppSettings(); + CSize videoSize, preferedAR; + + if (m_pCAP) { + videoSize = m_pCAP->GetVideoSize(false); + preferedAR = m_pCAP->GetVideoSize(s.fKeepAspectRatio); + } else if (m_pMFVDC) { + m_pMFVDC->GetNativeVideoSize(&videoSize, &preferedAR); // TODO : check AR !! + } else if (m_pBV) { + m_pBV->GetVideoSize(&videoSize.cx, &videoSize.cy); + + long arx = 0, ary = 0; + CComQIPtr pBV2 = m_pBV; + // FIXME: It can hang here, for few seconds (CPU goes to 100%), after the window have been moving over to another screen, + // due to GetPreferredAspectRatio, if it happens before CAudioSwitcherFilter::DeliverEndFlush, it seems. + if (pBV2 && SUCCEEDED(pBV2->GetPreferredAspectRatio(&arx, &ary)) && arx > 0 && ary > 0) { + preferedAR.SetSize(arx, ary); + } + } + if (preferedAR.cx <= 0 || preferedAR.cy <= 0) { //due to IBasicVideo2 not being found, this could still be zero for .swf + preferedAR.SetSize(videoSize.cx, videoSize.cy); + } + + if (videoSize.cx <= 0 || videoSize.cy <= 0) { + return ret; + } + + if (s.fKeepAspectRatio) { + CSize overrideAR = s.GetAspectRatioOverride(); + DVD_VideoAttributes VATR; + if ((!overrideAR.cx || !overrideAR.cy) && GetPlaybackMode() == PM_DVD + && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { + overrideAR.SetSize(VATR.ulAspectX, VATR.ulAspectY); + } + if (overrideAR.cx > 0 && overrideAR.cy > 0) { + if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", double(overrideAR.cx) / overrideAR.cy))) { + ret = m_pCAP->GetVideoSize(false); + } else { + ret = CSize(MulDiv(videoSize.cy, overrideAR.cx, overrideAR.cy), videoSize.cy); + } + } else { + if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", 0.0))) { + ret = m_pCAP->GetVideoSize(false); + } else { + ret = CSize(MulDiv(videoSize.cy, preferedAR.cx, preferedAR.cy), videoSize.cy); + } + } + } else { + CSize originalVideoSize(0, 1); + if (m_pMVRI) { + m_pMVRI->GetSize("originalVideoSize", &originalVideoSize); + } + if (m_pMVRC && SUCCEEDED(m_pMVRC->SendCommandDouble("setArOverride", + double(originalVideoSize.cx) / originalVideoSize.cy))) { + ret = m_pCAP->GetVideoSize(false); + } else { + ret = videoSize; + } + } + + if (s.fCompMonDeskARDiff + && s.iDSVideoRendererType != VIDRNDT_DS_EVR + && s.iDSVideoRendererType != VIDRNDT_DS_MADVR) + if (HDC hDC = ::GetDC(nullptr)) { + int _HORZSIZE = GetDeviceCaps(hDC, HORZSIZE); + int _VERTSIZE = GetDeviceCaps(hDC, VERTSIZE); + int _HORZRES = GetDeviceCaps(hDC, HORZRES); + int _VERTRES = GetDeviceCaps(hDC, VERTRES); + + if (_HORZSIZE > 0 && _VERTSIZE > 0 && _HORZRES > 0 && _VERTRES > 0) { + double a = 1.0 * _HORZSIZE / _VERTSIZE; + double b = 1.0 * _HORZRES / _VERTRES; + + if (b < a) { + ret.cy = (DWORD)(1.0 * ret.cy * a / b); + } else if (a < b) { + ret.cx = (DWORD)(1.0 * ret.cx * b / a); + } + } + + ::ReleaseDC(nullptr, hDC); + } + + return ret; +} + +void CMainFrame::HidePlaylistFullScreen(bool force /* = false */) +{ + if (force || m_fFullScreen) { + CAppSettings& s = AfxGetAppSettings(); + if (s.bHidePlaylistFullScreen && m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)) { + m_wndPlaylistBar.SetHiddenDueToFullscreen(true); + ShowControlBar(&m_wndPlaylistBar, FALSE, FALSE); + } + } +} + +void CMainFrame::ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo) +{ + if (IsD3DFullScreenMode()) { + ASSERT(FALSE); + return; + } + + CAppSettings& s = AfxGetAppSettings(); + + if (delayingFullScreen) { + return; //swallow request if we are in the delay period + } + + CMonitors monitors; + CMonitor defaultMonitor = monitors.GetPrimaryMonitor(); + CMonitor currentMonitor = monitors.GetNearestMonitor(this); + CMonitor fullscreenMonitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); + if (!fullscreenMonitor.IsMonitor()) { + fullscreenMonitor = currentMonitor; + } + bool fullScreenSeparate = s.bFullscreenSeparateControls && (m_pMFVDC || m_pVMRWC || m_pVW) && fullscreenMonitor.IsMonitor() && fullscreenMonitor != currentMonitor && (s.nCS & (CS_SEEKBAR | CS_TOOLBAR)); + + const CWnd* pInsertAfter = nullptr; + CRect windowRect; + DWORD dwRemove = 0, dwAdd = 0; + + if (!fullScreenSeparate && s.iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 + BOOL setEnabled = TRUE; + ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); + } + + bool restart_osd = false; + if (!m_pMVTO) { + m_OSD.Stop(); + restart_osd = s.fShowOSD || s.fShowDebugInfo; + } + + if (fullScreenSeparate) { + if (m_fFullScreen) { + m_fFullScreen = false; + } else { + if (!m_bNeedZoomAfterFullscreenExit && !s.HasFixedWindowSize()) { + // adjust control window size to minimal + m_bNeedZoomAfterFullscreenExit = true; + ZoomVideoWindow(ZOOM_DEFAULT_LEVEL, true); + } + m_fFullScreen = true; + } + s.fLastFullScreen = false; //not really, just fullScreenSecondMonitor + + if (m_fFullScreen) { + m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN); + + // Set the fullscreen display mode + if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo) { + AutoChangeMonitorMode(); + } + + CreateFullScreenWindow(false); + if (m_pD3DFSC && s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { + m_pD3DFSC->SetD3DFullscreen(true); + } + // Assign the windowed video frame and pass it to the relevant classes. + m_pVideoWnd = m_pDedicatedFSVideoWnd; + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } else if (m_pVMRWC) { + m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); + } + if (m_pVW) { + m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); + m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); + } + m_wndView.Invalidate(); + } else { + m_eventc.FireEvent(MpcEvent::SWITCHING_FROM_FULLSCREEN); + + if (m_pD3DFSC && s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { + m_pD3DFSC->SetD3DFullscreen(false); + } + m_pVideoWnd = &m_wndView; + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } else if (m_pVMRWC) { + m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); + } + if (m_pVW) { + m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); + m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); + } + if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { + SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift + } + + // Destroy the Fullscreen window and zoom the windowed video frame + m_pDedicatedFSVideoWnd->DestroyWindow(); + if (m_bNeedZoomAfterFullscreenExit) { + m_bNeedZoomAfterFullscreenExit = false; + if (s.fRememberZoomLevel) { + ZoomVideoWindow(); + } + } + } + MoveVideoWindow(); + + if (s.bHideWindowedControls) { + m_controls.UpdateToolbarsVisibility(); + } + } else { + m_fFullScreen = !m_fFullScreen; + s.fLastFullScreen = m_fFullScreen; + + if (m_fFullScreen) { + SetCursor(nullptr); // prevents cursor flickering when our window is not under the cursor + + m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN); + + HidePlaylistFullScreen(true); + + GetWindowRect(&m_lastWindowRect); + + if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo && GetPlaybackMode() != PM_NONE) { + AutoChangeMonitorMode(); + } + + dwRemove |= WS_CAPTION | WS_THICKFRAME; + if (s.fPreventMinimize && fullscreenMonitor != defaultMonitor) { + dwRemove |= WS_MINIMIZEBOX; + } + + m_bExtOnTop = !s.iOnTop && (GetExStyle() & WS_EX_TOPMOST); + pInsertAfter = &wndTopMost; + + if (fToNearest) { + fullscreenMonitor.GetMonitorRect(windowRect); + } else { + GetDesktopWindow()->GetWindowRect(windowRect); + } + } else { + m_eventc.FireEvent(MpcEvent::SWITCHING_FROM_FULLSCREEN); + + if (m_pVideoWnd != &m_wndView) { + m_pVideoWnd = &m_wndView; + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } else if (m_pVMRWC) { + m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); + } + if (m_pVW) { + m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd); + m_pVW->put_MessageDrain((OAHWND)m_pVideoWnd->m_hWnd); + } + } + m_pDedicatedFSVideoWnd->DestroyWindow(); + + if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { + SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift + } + + windowRect = m_lastWindowRect; + if (!monitors.IsOnScreen(windowRect)) { + currentMonitor.CenterRectToMonitor(windowRect, TRUE); + } + + dwAdd |= WS_MINIMIZEBOX; + if (s.eCaptionMenuMode != MODE_BORDERLESS) { + dwAdd |= WS_THICKFRAME; + if (s.eCaptionMenuMode != MODE_FRAMEONLY) { + dwAdd |= WS_CAPTION; + } + } + + if (m_wndPlaylistBar.IsHiddenDueToFullscreen() && !m_controls.ControlChecked(CMainFrameControls::Panel::PLAYLIST)) { + if (s.bHideWindowedControls) { + m_wndPlaylistBar.SetHiddenDueToFullscreen(false, true); + } else { + m_wndPlaylistBar.SetHiddenDueToFullscreen(false); + m_controls.ToggleControl(CMainFrameControls::Panel::PLAYLIST); + } + } + + // If MPC-HC wasn't previously set "on top" by an external tool, + // we restore the current internal on top state. (1/2) + if (!m_bExtOnTop) { + pInsertAfter = &wndNoTopMost; + } + } + + bool bZoomVideoWindow = false; + if (m_bNeedZoomAfterFullscreenExit && !m_fFullScreen) { + bZoomVideoWindow = s.fRememberZoomLevel; + m_bNeedZoomAfterFullscreenExit = false; + } + + ModifyStyle(dwRemove, dwAdd, SWP_NOZORDER); + SetWindowPos(pInsertAfter, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), + SWP_NOSENDCHANGING | SWP_FRAMECHANGED); + + // If MPC-HC wasn't previously set "on top" by an external tool, + // we restore the current internal on top state. (2/2) + if (!m_fFullScreen && !m_bExtOnTop) { + SetAlwaysOnTop(s.iOnTop); + } + + SetMenuBarVisibility((!m_fFullScreen && s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) + ? AFX_MBV_KEEPVISIBLE : AFX_MBV_DISPLAYONFOCUS); + + UpdateControlState(UPDATE_CONTROLS_VISIBILITY); + + if (bZoomVideoWindow) { + ZoomVideoWindow(); + } + MoveVideoWindow(); + } + + if (restart_osd) { + if (m_fFullScreen && m_pCAP3 && m_pMFVMB) { // MPCVR + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); + } else { + m_OSD.Start(m_pOSDWnd); + OSDBarSetPos(); + } + } + + if (m_fFullScreen) { + m_eventc.FireEvent(MpcEvent::SWITCHED_TO_FULLSCREEN); + } else { + m_eventc.FireEvent(MpcEvent::SWITCHED_FROM_FULLSCREEN); + } + + if (!fullScreenSeparate && s.iFullscreenDelay > 0 && IsWindows8OrGreater()) {//DWMWA_CLOAK not supported on 7 + UINT_PTR timerID = 0; + timerID = SetTimer(TIMER_WINDOW_FULLSCREEN, s.iFullscreenDelay, nullptr); + if (0 == timerID) { + BOOL setEnabled = FALSE; + ::DwmSetWindowAttribute(m_hWnd, DWMWA_CLOAK, &setEnabled, sizeof(setEnabled)); + } else { + delayingFullScreen = true; + } + RedrawWindow(nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE); + } +} + +void CMainFrame::ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo) +{ + if (m_pD3DFSC && m_pMFVDC) { + CAppSettings& s = AfxGetAppSettings(); + + bool bIsFullscreen = false; + m_pD3DFSC->GetD3DFullscreen(&bIsFullscreen); + s.fLastFullScreen = !bIsFullscreen; + + m_OSD.Stop(); + + if (bIsFullscreen) { + // Turn off D3D Fullscreen + m_pD3DFSC->SetD3DFullscreen(false); + + // Assign the windowed video frame and pass it to the relevant classes. + m_pVideoWnd = &m_wndView; + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + + if (s.autoChangeFSMode.bEnabled && s.autoChangeFSMode.bApplyDefaultModeAtFSExit && !s.autoChangeFSMode.modes.empty() && s.autoChangeFSMode.modes[0].bChecked) { + SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift + } + + // Destroy the D3D Fullscreen window and zoom the windowed video frame + m_pDedicatedFSVideoWnd->DestroyWindow(); + if (m_bNeedZoomAfterFullscreenExit) { + if (s.fRememberZoomLevel) { + ZoomVideoWindow(); + } + m_bNeedZoomAfterFullscreenExit = false; + } + + if (s.fShowOSD) { + m_OSD.Start(m_pOSDWnd); + } + MoveVideoWindow(); + RecalcLayout(); + } else { + // Set the fullscreen display mode + if (s.autoChangeFSMode.bEnabled && fSwitchScreenResWhenHasTo) { + AutoChangeMonitorMode(); + } + + // Create a new D3D Fullscreen window + CreateFullScreenWindow(); + + m_eventc.FireEvent(MpcEvent::SWITCHING_TO_FULLSCREEN_D3D); + + // Assign the windowed video frame and pass it to the relevant classes. + m_pVideoWnd = m_pDedicatedFSVideoWnd; + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + m_wndView.Invalidate(); + + MoveVideoWindow(); + + // Turn on D3D Fullscreen + m_pD3DFSC->SetD3DFullscreen(true); + + if (s.fShowOSD || s.fShowDebugInfo) { + if (m_pVMB || m_pMFVMB) { + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); + } + } + + m_eventc.FireEvent(MpcEvent::SWITCHED_TO_FULLSCREEN_D3D); + } + } else { + ASSERT(false); + } +} + +bool CMainFrame::GetCurDispMode(const CString& displayName, DisplayMode& dm) +{ + return GetDispMode(displayName, ENUM_CURRENT_SETTINGS, dm); +} + +bool CMainFrame::GetDispMode(CString displayName, int i, DisplayMode& dm) +{ + if (displayName == _T("Current") || displayName.IsEmpty()) { + CMonitor monitor = CMonitors::GetNearestMonitor(AfxGetApp()->m_pMainWnd); + monitor.GetName(displayName); + } + + DEVMODE devmode; + devmode.dmSize = sizeof(DEVMODE); + devmode.dmDriverExtra = 0; + + dm.bValid = !!EnumDisplaySettingsExW(displayName, i, &devmode, EDS_RAWMODE); + + if (dm.bValid) { + dm.size = CSize(devmode.dmPelsWidth, devmode.dmPelsHeight); + dm.bpp = devmode.dmBitsPerPel; + dm.freq = devmode.dmDisplayFrequency; + dm.dwDisplayFlags = devmode.dmDisplayFlags; + } + + return dm.bValid; +} + +void CMainFrame::SetDispMode(CString displayName, const DisplayMode& dm, int msAudioDelay) +{ + DisplayMode dmCurrent; + if (!GetCurDispMode(displayName, dmCurrent)) { + return; + } + + CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); + if (dm.size == dmCurrent.size && dm.bpp == dmCurrent.bpp && dm.freq == dmCurrent.freq) { + if (pASF) { + pASF->SetAudioTimeShift(msAudioDelay * 10000i64); + } + return; + } + + DEVMODE dmScreenSettings; + ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings)); + dmScreenSettings.dmSize = sizeof(dmScreenSettings); + dmScreenSettings.dmPelsWidth = dm.size.cx; + dmScreenSettings.dmPelsHeight = dm.size.cy; + dmScreenSettings.dmBitsPerPel = dm.bpp; + dmScreenSettings.dmDisplayFrequency = dm.freq; + dmScreenSettings.dmDisplayFlags = dm.dwDisplayFlags; + dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; + + if (displayName == _T("Current") || displayName.IsEmpty()) { + CMonitor monitor = CMonitors::GetNearestMonitor(AfxGetApp()->m_pMainWnd); + monitor.GetName(displayName); + } + + const auto& s = AfxGetAppSettings(); + LONG ret; + + m_eventc.FireEvent(MpcEvent::DISPLAY_MODE_AUTOCHANGING); + if (AfxGetAppSettings().autoChangeFSMode.bRestoreResAfterProgExit) { + ret = ChangeDisplaySettingsExW(displayName, &dmScreenSettings, nullptr, CDS_FULLSCREEN, nullptr); + } else { + ret = ChangeDisplaySettingsExW(displayName, &dmScreenSettings, nullptr, 0, nullptr); + } + m_eventc.FireEvent(MpcEvent::DISPLAY_MODE_AUTOCHANGED); + + msAudioDelay = ret == DISP_CHANGE_SUCCESSFUL ? msAudioDelay : (s.fAudioTimeShift ? s.iAudioTimeShift : 0); + if (pASF) { + pASF->SetAudioTimeShift(msAudioDelay * 10000i64); + } +} + +void CMainFrame::AutoChangeMonitorMode() +{ + const CAppSettings& s = AfxGetAppSettings(); + if (s.autoChangeFSMode.modes.empty()) { + return; + } + + double dMediaFPS = 0.0; + + if (GetPlaybackMode() == PM_FILE) { + REFERENCE_TIME m_rtTimePerFrame = 1; + // if ExtractAvgTimePerFrame isn't executed then MediaFPS=10000000.0, + // (int)(MediaFPS + 0.5)=10000000 and SetDispMode is executed to Default. + BeginEnumFilters(m_pGB, pEF, pBF) { + BeginEnumPins(pBF, pEP, pPin) { + CMediaTypeEx mt; + PIN_DIRECTION dir; + if (SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_OUTPUT && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (ExtractAvgTimePerFrame(&mt, m_rtTimePerFrame)) { + if (m_rtTimePerFrame == 0) { + m_rtTimePerFrame = 1; + } + } + } + } + EndEnumPins; + } + EndEnumFilters; + dMediaFPS = 10000000.0 / m_rtTimePerFrame; + } else if (GetPlaybackMode() == PM_DVD) { + DVD_PLAYBACK_LOCATION2 Location; + if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) { + dMediaFPS = 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; + } + } + + for (const auto& mode : s.autoChangeFSMode.modes) { + if (mode.bChecked && dMediaFPS >= mode.dFrameRateStart && dMediaFPS <= mode.dFrameRateStop) { + SetDispMode(s.strFullScreenMonitorID, mode.dm, mode.msAudioDelay); + return; + } + } + SetDispMode(s.strFullScreenMonitorID, s.autoChangeFSMode.modes[0].dm, s.fAudioTimeShift ? s.iAudioTimeShift : 0); // Restore default time shift +} + +void CMainFrame::MoveVideoWindow(bool fShowStats/* = false*/, bool bSetStoppedVideoRect/* = false*/) +{ + m_dLastVideoScaleFactor = 0; + m_lastVideoSize.SetSize(0, 0); + + if (!m_bDelaySetOutputRect && GetLoadState() == MLS::LOADED && !m_fAudioOnly && IsWindowVisible()) { + CRect windowRect(0, 0, 0, 0); + CRect videoRect(0, 0, 0, 0); + + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->GetClientRect(windowRect); + } else { + m_wndView.GetClientRect(windowRect); + } + + const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); + const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); + if (bPanelsOnVideo) { + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetVisibleDockZones(uTop, uLeft, uRight, uBottom); + if (!bToolbarsOnVideo) { + uBottom -= m_controls.GetVisibleToolbarsHeight(); + } + windowRect.InflateRect(uLeft, uTop, uRight, uBottom); + } else if (bToolbarsOnVideo) { + windowRect.bottom += m_controls.GetVisibleToolbarsHeight(); + } + + int nCompensateForMenubar = m_bShowingFloatingMenubar && !IsD3DFullScreenMode() ? GetSystemMetrics(SM_CYMENU) : 0; + windowRect.bottom += nCompensateForMenubar; + + OAFilterState fs = GetMediaState(); + if (fs != State_Stopped || bSetStoppedVideoRect || m_fShockwaveGraph) { + const CSize szVideo = GetVideoSize(); + + m_dLastVideoScaleFactor = std::min((double)windowRect.Size().cx / szVideo.cx, + (double)windowRect.Size().cy / szVideo.cy); + m_lastVideoSize = szVideo; + + const double dVideoAR = double(szVideo.cx) / szVideo.cy; + + // because we don't have a way to get .swf size reliably, + // other modes don't make sense + const dvstype iDefaultVideoSize = m_fShockwaveGraph ? DVS_STRETCH : + static_cast(AfxGetAppSettings().iDefaultVideoSize); + + const double dWRWidth = windowRect.Width(); + const double dWRHeight = windowRect.Height(); + + double dVRWidth = dWRHeight * dVideoAR; + double dVRHeight; + + double madVRZoomFactor = 1.0; + + switch (iDefaultVideoSize) { + case DVS_HALF: + dVRWidth = szVideo.cx * 0.5; + dVRHeight = szVideo.cy * 0.5; + break; + case DVS_NORMAL: + dVRWidth = szVideo.cx; + dVRHeight = szVideo.cy; + break; + case DVS_DOUBLE: + dVRWidth = szVideo.cx * 2.0; + dVRHeight = szVideo.cy * 2.0; + break; + case DVS_STRETCH: + dVRWidth = dWRWidth; + dVRHeight = dWRHeight; + break; + default: + ASSERT(FALSE); + [[fallthrough]]; // Fallback to "Touch Window From Inside" if settings were corrupted. + case DVS_FROMINSIDE: + if (dWRWidth < dVRWidth) { + dVRWidth = dWRWidth; + dVRHeight = dVRWidth / dVideoAR; + } else { + dVRHeight = dWRHeight; + } + break; + case DVS_FROMOUTSIDE: + if (dWRWidth > dVRWidth) { + dVRWidth = dWRWidth; + dVRHeight = dVRWidth / dVideoAR; + } else { + dVRHeight = dWRHeight; + } + break; + case DVS_ZOOM1: + case DVS_ZOOM2: { + double scale = iDefaultVideoSize == DVS_ZOOM1 ? 1.0 / 3.0 : 2.0 / 3.0; + double minw = std::min(dWRWidth, dVRWidth); + double zoomValue = (std::max(dWRWidth, dVRWidth) - minw) * scale; + madVRZoomFactor = (minw + zoomValue) / minw; + dVRWidth = minw + zoomValue; + dVRHeight = dVRWidth / dVideoAR; + break; + } + } + + // Scale video frame + double dScaledVRWidth = m_ZoomX * dVRWidth; + double dScaledVRHeight = m_ZoomY * dVRHeight; + + auto vertAlign = AfxGetAppSettings().iVerticalAlignVideo; + double vertAlignOffset = 0; + if (vertAlign == CAppSettings::verticalAlignVideoType::ALIGN_TOP) { + vertAlignOffset = -(dWRHeight - dScaledVRHeight) / 2; + } else if (vertAlign == CAppSettings::verticalAlignVideoType::ALIGN_BOTTOM) { + vertAlignOffset = (dWRHeight - dScaledVRHeight) / 2; + } + + // Position video frame + // left and top parts are allowed to be negative + videoRect.left = lround(m_PosX * (dWRWidth * 3.0 - dScaledVRWidth) - dWRWidth); + videoRect.top = lround(m_PosY * (dWRHeight * 3.0 - dScaledVRHeight) - dWRHeight + vertAlignOffset); + // right and bottom parts are always at picture center or beyond, so never negative + videoRect.right = lround(videoRect.left + dScaledVRWidth); + videoRect.bottom = lround(videoRect.top + dScaledVRHeight); + + ASSERT(videoRect.Width() == lround(dScaledVRWidth)); + ASSERT(videoRect.Height() == lround(dScaledVRHeight)); + + if (m_pMVRC) { + static constexpr const LPCWSTR madVRModesMap[] = { + L"50%", + L"100%", + L"200%", + L"stretch", + L"touchInside", + L"touchOutside", + L"touchInside", + L"touchInside" + }; + + // workaround for rotated video with MadVR + bool swapxy = ((m_iDefRotation + m_AngleZ) / 90) & 1; + double mvr_ZoomX = swapxy ? m_ZoomY : m_ZoomX; + double mvr_ZoomY = swapxy ? m_ZoomX : m_ZoomY; + double mvr_PosX = swapxy ? m_PosY : m_PosX; + double mvr_PosY = swapxy ? m_PosX : m_PosY; + + m_pMVRC->SendCommandString("setZoomMode", const_cast(madVRModesMap[iDefaultVideoSize])); + m_pMVRC->SendCommandDouble("setZoomFactorX", madVRZoomFactor * mvr_ZoomX); + m_pMVRC->SendCommandDouble("setZoomFactorY", madVRZoomFactor * mvr_ZoomY); + m_pMVRC->SendCommandDouble("setZoomOffsetX", 2 * mvr_PosX - 1.0); + m_pMVRC->SendCommandDouble("setZoomOffsetY", 2 * mvr_PosY - 1.0); + } + + if (fShowStats) { + CString info; + info.Format(_T("Pos %.3f %.3f, Zoom %.3f %.3f, AR %.3f"), m_PosX, m_PosY, m_ZoomX, m_ZoomY, double(videoRect.Width()) / videoRect.Height()); + SendStatusMessage(info, 3000); + } + } else if (m_pMVRC) { + m_pMVRC->SendCommandString("setZoomMode", const_cast(L"autoDetect")); + } + + windowRect.top -= nCompensateForMenubar; + windowRect.bottom -= nCompensateForMenubar; + + if (m_pCAP) { + m_pCAP->SetPosition(windowRect, videoRect); + UpdateSubtitleRenderingParameters(); + } else { + if (m_pBV) { + m_pBV->SetDefaultSourcePosition(); + m_pBV->SetDestinationPosition(videoRect.left, videoRect.top, videoRect.Width(), videoRect.Height()); + } + if (m_pVW) { + m_pVW->SetWindowPosition(windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height()); + } + + if (m_pMFVDC) { + m_pMFVDC->SetVideoPosition(nullptr, &windowRect); + } + } + + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->SetVideoRect(&windowRect); + } else { + m_wndView.SetVideoRect(&windowRect); + } + } else { + m_wndView.SetVideoRect(); + } +} + +void CMainFrame::SetPreviewVideoPosition() { + if (m_bUseSeekPreview) { + CPoint point; + GetCursorPos(&point); + m_wndSeekBar.ScreenToClient(&point); + m_wndSeekBar.UpdateToolTipPosition(point); + + CRect wr; + m_wndPreView.GetVideoRect(&wr); + + const CSize ws(wr.Size()); + int w = ws.cx; + int h = ws.cy; + + const CSize arxy(GetVideoSizeWithRotation()); + { + const int dh = ws.cy; + const int dw = MulDiv(dh, arxy.cx, arxy.cy); + + int minw = dw; + int maxw = dw; + if (ws.cx < dw) { + minw = ws.cx; + } else if (ws.cx > dw) { + maxw = ws.cx; + } + + const float scale = 1 / 3.0f; + w = int(minw + (maxw - minw) * scale); + h = MulDiv(w, arxy.cy, arxy.cx); + } + + const CPoint pos(int(m_PosX * (wr.Width() * 3 - w) - wr.Width()), int(m_PosY * (wr.Height() * 3 - h) - wr.Height())); + const CRect vr(pos, CSize(w, h)); + + if (m_pMFVDC_preview) { + m_pMFVDC_preview->SetVideoPosition(nullptr, wr); + m_pMFVDC_preview->SetAspectRatioMode(MFVideoARMode_PreservePicture); + } + if (m_pVMR9C_preview) { + m_pVMR9C_preview->SetVideoPosition(nullptr, wr); + m_pVMR9C_preview->SetAspectRatioMode(VMR9ARMode_LetterBox); + } + if (m_pCAP2_preview) { + m_pCAP2_preview->SetPosition(wr, wr); + } + + if (m_pBV_preview) { + m_pBV_preview->SetDefaultSourcePosition(); + m_pBV_preview->SetDestinationPosition(vr.left, vr.top, vr.Width(), vr.Height()); + } + if (m_pVW_preview) { + m_pVW_preview->SetWindowPosition(wr.left, wr.top, wr.Width(), wr.Height()); + } + } +} + +void CMainFrame::HideVideoWindow(bool fHide) +{ + CRect wr; + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->GetClientRect(&wr); + } else if (!m_fFullScreen) { + m_wndView.GetClientRect(&wr); + } else { + GetWindowRect(&wr); + + // this code is needed to work in fullscreen on secondary monitor + CRect r; + m_wndView.GetWindowRect(&r); + wr -= r.TopLeft(); + } + + if (m_pCAP) { + if (fHide) { + CRect vr = CRect(0, 0, 0, 0); + m_pCAP->SetPosition(vr, vr); // hide + } else { + m_pCAP->SetPosition(wr, wr); // show + } + } + m_bLockedZoomVideoWindow = fHide; +} + +CSize CMainFrame::GetVideoOrArtSize(MINMAXINFO& mmi) +{ + const auto& s = AfxGetAppSettings(); + CSize videoSize; + OnGetMinMaxInfo(&mmi); + + if (m_fAudioOnly) { + videoSize = m_wndView.GetLogoSize(); + + if (videoSize.cx > videoSize.cy) { + if (videoSize.cx > s.nCoverArtSizeLimit) { + videoSize.cy = MulDiv(videoSize.cy, s.nCoverArtSizeLimit, videoSize.cx); + videoSize.cx = s.nCoverArtSizeLimit; + } + } else { + if (videoSize.cy > s.nCoverArtSizeLimit) { + videoSize.cx = MulDiv(videoSize.cx, s.nCoverArtSizeLimit, videoSize.cy); + videoSize.cy = s.nCoverArtSizeLimit; + } + } + } else { + videoSize = GetVideoSize(); + } + return videoSize; +} + +CSize CMainFrame::GetZoomWindowSize(double dScale, bool ignore_video_size) +{ + CSize ret; + + if (dScale >= 0.0 && GetLoadState() == MLS::LOADED) { + const auto& s = AfxGetAppSettings(); + MINMAXINFO mmi; + CSize videoSize = GetVideoOrArtSize(mmi); + + if (ignore_video_size || videoSize.cx <= 1 || videoSize.cy <= 1) { + videoSize.SetSize(0, 0); + } + if (videoSize.cx == 0 || m_fAudioOnly && videoSize.cy < 300) { + CRect windowRect; + GetWindowRect(windowRect); + if (windowRect.Height() < 420 && windowRect.Width() < 3800) { + // keep existing width, since it probably was intentionally made wider by user + mmi.ptMinTrackSize.x = std::max(windowRect.Width(), mmi.ptMinTrackSize.x); + if (m_fAudioOnly) { + // also keep existing height + videoSize.SetSize(0, 0); + mmi.ptMinTrackSize.y = std::max(windowRect.Height(), mmi.ptMinTrackSize.y); + } + } + + } + + CSize videoTargetSize = videoSize; + + CSize controlsSize; + const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); + const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); + if (!bPanelsOnVideo) { + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); + if (bToolbarsOnVideo) { + uBottom -= m_controls.GetToolbarsHeight(); + } + controlsSize.cx = uLeft + uRight; + controlsSize.cy = uTop + uBottom; + } else if (!bToolbarsOnVideo) { + controlsSize.cy = m_controls.GetToolbarsHeight(); + } + + CRect decorationsRect; + VERIFY(AdjustWindowRectEx(decorationsRect, GetWindowStyle(m_hWnd), s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU, + GetWindowExStyle(m_hWnd))); + + CRect workRect; + CMonitors::GetNearestMonitor(this).GetWorkAreaRect(workRect); + + if (workRect.Width() && workRect.Height()) { + // account for invisible borders on Windows 10 by allowing + // the window to go out of screen a bit + if (IsWindows10OrGreater()) { + workRect.InflateRect(GetInvisibleBorderSize()); + } + + if (videoSize.cx > 0) { + // don't go larger than the current monitor working area and prevent black bars in this case + CSize videoSpaceSize = workRect.Size() - controlsSize - decorationsRect.Size(); + + // Do not adjust window size for video frame aspect ratio when video size is independent from window size + const bool bAdjustWindowAR = !(s.iDefaultVideoSize == DVS_HALF || s.iDefaultVideoSize == DVS_NORMAL || s.iDefaultVideoSize == DVS_DOUBLE); + const double videoAR = videoSize.cx / (double)videoSize.cy; + + videoTargetSize = CSize(int(videoSize.cx * dScale + 0.5), int(videoSize.cy * dScale + 0.5)); + + if (videoTargetSize.cx > videoSpaceSize.cx) { + videoTargetSize.cx = videoSpaceSize.cx; + if (bAdjustWindowAR) { + videoTargetSize.cy = std::lround(videoSpaceSize.cx / videoAR); + } + } + + if (videoTargetSize.cy > videoSpaceSize.cy) { + videoTargetSize.cy = videoSpaceSize.cy; + if (bAdjustWindowAR) { + videoTargetSize.cx = std::lround(videoSpaceSize.cy * videoAR); + } + } + } + } else { + ASSERT(FALSE); + } + + ret = videoTargetSize + controlsSize + decorationsRect.Size(); + ret.cx = std::max(ret.cx, mmi.ptMinTrackSize.x); + ret.cy = std::max(ret.cy, mmi.ptMinTrackSize.y); + } else { + ASSERT(FALSE); + } + + return ret; +} + +bool CMainFrame::GetWorkAreaRect(CRect& work) { + MONITORINFO mi = { sizeof(mi) }; + if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { + work = mi.rcWork; + // account for invisible borders on Windows 10 by allowing + // the window to go out of screen a bit + if (IsWindows10OrGreater()) { + work.InflateRect(GetInvisibleBorderSize()); + } + return true; + } + return false; +} + +CRect CMainFrame::GetZoomWindowRect(const CSize& size, bool ignoreSavedPosition /*= false*/) +{ + const auto& s = AfxGetAppSettings(); + CRect ret; + GetWindowRect(ret); + + CRect rcWork; + if (GetWorkAreaRect(rcWork)) { + CSize windowSize(size); + + // don't go larger than the current monitor working area + windowSize.cx = std::min(windowSize.cx, rcWork.Width()); + windowSize.cy = std::min(windowSize.cy, rcWork.Height()); + + // retain snapping or try not to be move the center of the window + // if we don't remember its position + if (m_bWasSnapped && ret.left == rcWork.left) { + // do nothing + } else if (m_bWasSnapped && ret.right == rcWork.right) { + ret.left = ret.right - windowSize.cx; + } else if (!s.fRememberWindowPos || ignoreSavedPosition) { + ret.left += (ret.right - ret.left) / 2 - windowSize.cx / 2; + } + if (m_bWasSnapped && ret.top == rcWork.top) { + // do nothing + } else if (m_bWasSnapped && ret.bottom == rcWork.bottom) { + ret.top = ret.bottom - windowSize.cy; + } else if (!s.fRememberWindowPos || ignoreSavedPosition) { + ret.top += (ret.bottom - ret.top) / 2 - windowSize.cy / 2; + } + + ret.right = ret.left + windowSize.cx; + ret.bottom = ret.top + windowSize.cy; + + // don't go beyond the current monitor working area + if (ret.right > rcWork.right) { + ret.OffsetRect(rcWork.right - ret.right, 0); + } + if (ret.left < rcWork.left) { + ret.OffsetRect(rcWork.left - ret.left, 0); + } + if (ret.bottom > rcWork.bottom) { + ret.OffsetRect(0, rcWork.bottom - ret.bottom); + } + if (ret.top < rcWork.top) { + ret.OffsetRect(0, rcWork.top - ret.top); + } + } else { + ASSERT(FALSE); + } + + return ret; +} + +void CMainFrame::ZoomVideoWindow(double dScale/* = ZOOM_DEFAULT_LEVEL*/, bool ignore_video_size /*= false*/) +{ + const auto& s = AfxGetAppSettings(); + + if ((GetLoadState() != MLS::LOADED) || + (m_nLockedZoomVideoWindow > 0) || m_bLockedZoomVideoWindow) { + if (m_nLockedZoomVideoWindow > 0) { + m_nLockedZoomVideoWindow--; + } + return; + } + + // Leave fullscreen when changing the zoom level + if (IsFullScreenMode()) { + OnViewFullscreen(); + } + + if (!s.HasFixedWindowSize()) { + ShowWindow(SW_SHOWNOACTIVATE); + if (dScale == (double)ZOOM_DEFAULT_LEVEL) { + if (s.fRememberWindowSize) { + return; // ignore default auto-zoom setting + } + dScale = + s.iZoomLevel == -1 ? 0.25 : + s.iZoomLevel == 0 ? 0.5 : + s.iZoomLevel == 1 ? 1.0 : + s.iZoomLevel == 2 ? 2.0 : + s.iZoomLevel == 3 ? GetZoomAutoFitScale() : +// s.iZoomLevel == 4 ? GetZoomAutoFitScale(true) : + 1.0; + } else if (dScale == (double)ZOOM_AUTOFIT) { + dScale = GetZoomAutoFitScale(); + } else if (dScale <= 0.0) { + ASSERT(FALSE); + return; + } + MoveWindow(GetZoomWindowRect(GetZoomWindowSize(dScale, ignore_video_size), !s.fRememberWindowPos)); + } +} + +double CMainFrame::GetZoomAutoFitScale() +{ + if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { + return 1.0; + } + + const CAppSettings& s = AfxGetAppSettings(); + + CSize arxy = GetVideoSize(); + + // get the work area + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST); + GetMonitorInfo(hMonitor, &mi); + RECT& wa = mi.rcWork; + + DWORD style = GetStyle(); + CSize decorationsSize(0, 0); + + if (style & WS_CAPTION) { + // caption + decorationsSize.cy += GetSystemMetrics(SM_CYCAPTION); + // menu + if (s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) { + decorationsSize.cy += GetSystemMetrics(SM_CYMENU); + } + } + + if (style & WS_THICKFRAME) { + // vertical borders + decorationsSize.cx += 2 * ::GetSystemMetrics(SM_CXSIZEFRAME); + // horizontal borders + decorationsSize.cy += 2 * ::GetSystemMetrics(SM_CYSIZEFRAME); + + // account for invisible borders on Windows 10 + if (IsWindows10OrGreater()) { + RECT invisibleBorders = GetInvisibleBorderSize(); + + decorationsSize.cx -= (invisibleBorders.left + invisibleBorders.right); + decorationsSize.cy -= (invisibleBorders.top + invisibleBorders.bottom); + } + + if (!(style & WS_CAPTION)) { + decorationsSize.cx -= 2; + decorationsSize.cy -= 2; + } + } + + const bool bToolbarsOnVideo = m_controls.ToolbarsCoverVideo(); + const bool bPanelsOnVideo = m_controls.PanelsCoverVideo(); + if (!bPanelsOnVideo) { + unsigned uTop, uLeft, uRight, uBottom; + m_controls.GetDockZones(uTop, uLeft, uRight, uBottom); + if (bToolbarsOnVideo) { + uBottom -= m_controls.GetVisibleToolbarsHeight(); + } + decorationsSize.cx += uLeft + uRight; + decorationsSize.cy += uTop + uBottom; + } else if (!bToolbarsOnVideo) { + decorationsSize.cy -= m_controls.GetVisibleToolbarsHeight(); + } + + LONG width = wa.right - wa.left; + LONG height = wa.bottom - wa.top; + + double sxMin = ((double)width * s.nAutoFitFactorMin / 100 - decorationsSize.cx) / arxy.cx; + double syMin = ((double)height * s.nAutoFitFactorMin / 100 - decorationsSize.cy) / arxy.cy; + sxMin = std::min(sxMin, syMin); + // Take movie aspect ratio into consideration + // The scaling is computed so that the height is an integer value + syMin = floor(arxy.cy * floor(arxy.cx * sxMin + 0.5) / arxy.cx + 0.5) / arxy.cy; + + double sxMax = ((double)width * s.nAutoFitFactorMax / 100 - decorationsSize.cx) / arxy.cx; + double syMax = ((double)height * s.nAutoFitFactorMax / 100 - decorationsSize.cy) / arxy.cy; + sxMax = std::min(sxMax, syMax); + // Take movie aspect ratio into consideration + // The scaling is computed so that the height is an integer value + syMax = floor(arxy.cy * floor(arxy.cx * sxMax + 0.5) / arxy.cx + 0.5) / arxy.cy; + + + if (syMin < 0.0 || syMax < 0.0) { + ASSERT(FALSE); + syMin = 0.0; + syMax = 0.0; + } + + if (syMin > 1.0) { + return syMin; + } + if (syMax < 1.0) { + return syMax; + } + return 1.0; + +} + +void CMainFrame::RepaintVideo(const bool bForceRepaint/* = false*/) +{ + if (!m_bDelaySetOutputRect && (m_pCAP || m_pMFVDC)) { + OAFilterState fs = GetMediaState(); + if (fs == State_Paused || fs == State_Stopped || bForceRepaint || (m_bDVDStillOn && GetPlaybackMode() == PM_DVD)) { + if (m_pCAP) { + m_pCAP->Paint(false); + } else if (m_pMFVDC) { + m_pMFVDC->RepaintVideo(); + } + } + } +} + +ShaderC* CMainFrame::GetShader(CString path, bool bD3D11) +{ + ShaderC* pShader = nullptr; + + CString shadersDir = ShaderList::GetShadersDir(); + CString shadersDir11 = ShaderList::GetShadersDir11(); + CString tPath = path; + tPath.Replace(shadersDir, shadersDir11); + + //if the shader exists in the Shaders11 folder, use that one + if (bD3D11 && ::PathFileExistsW(tPath)) { + path = tPath; + } + + for (auto& shader : m_ShaderCache) { + if (shader.Match(path, bD3D11)) { + pShader = &shader; + break; + } + } + + if (!pShader) { + if (::PathFileExistsW(path)) { + CStdioFile file; + if (file.Open(path, CFile::modeRead | CFile::shareDenyWrite | CFile::typeText)) { + ShaderC shader; + shader.label = path; + + CString str; + file.ReadString(str); // read first string + if (str.Left(25) == L"// $MinimumShaderProfile:") { + shader.profile = str.Mid(25).Trim(); // shader version property + } else { + file.SeekToBegin(); + } + + if (shader.profile == L"ps_4_0" && !bD3D11 || shader.profile == L"ps_5_0") { + ASSERT(false); + return nullptr; + } else if (bD3D11) { + shader.profile = L"ps_4_0"; + } else if (shader.profile == L"ps_3_sw") { + shader.profile = L"ps_3_0"; + } else if (shader.profile != L"ps_2_0" + && shader.profile != L"ps_2_a" + && shader.profile != L"ps_2_b" + && shader.profile != L"ps_3_0") { + shader.profile = L"ps_3_0"; + } + + while (file.ReadString(str)) { + shader.srcdata += str + L"\n"; + } + + shader.length = file.GetLength(); + + FILETIME ftCreate, ftAccess, ftWrite; + if (GetFileTime(file.m_hFile, &ftCreate, &ftAccess, &ftWrite)) { + shader.ftwrite = ftWrite; + } + + file.Close(); + + m_ShaderCache.push_back(shader); + pShader = &m_ShaderCache.back(); + } + } + } + + return pShader; +} + +bool CMainFrame::SaveShaderFile(ShaderC* shader) +{ + CString path; + if (AfxGetMyApp()->GetAppSavePath(path)) { + path.AppendFormat(L"Shaders\\%s.hlsl", static_cast(shader->label)); + + CStdioFile file; + if (file.Open(path, CFile::modeWrite | CFile::shareExclusive | CFile::typeText)) { + file.SetLength(0); + + CString str; + str.Format(L"// $MinimumShaderProfile: %s\n", static_cast(shader->profile)); + file.WriteString(static_cast(str)); + + file.WriteString(static_cast(shader->srcdata)); + file.Close(); + + // delete out-of-date data from the cache + for (auto it = m_ShaderCache.begin(), end = m_ShaderCache.end(); it != end; ++it) { + if (it->Match(shader->label, false)) { + m_ShaderCache.erase(it); + break; + } + } + + return true; + } + } + return false; +} + +bool CMainFrame::DeleteShaderFile(LPCWSTR label) +{ + CString path; + if (AfxGetMyApp()->GetAppSavePath(path)) { + path.AppendFormat(L"Shaders\\%s.hlsl", label); + + if (!::PathFileExistsW(path) || ::DeleteFileW(path)) { + // if the file is missing or deleted successfully, then remove it from the cache + for (auto it = m_ShaderCache.begin(), end = m_ShaderCache.end(); it != end; ++it) { + if (it->Match(label, false)) { + m_ShaderCache.erase(it); + return true; + } + } + } + } + + return false; +} + +void CMainFrame::TidyShaderCache() +{ + CString appsavepath; + if (!AfxGetMyApp()->GetAppSavePath(appsavepath)) { + return; + } + + for (auto it = m_ShaderCache.cbegin(); it != m_ShaderCache.cend(); ) { + CString path(appsavepath); + path += L"Shaders\\"; + path += (*it).label + L".hlsl"; + + CFile file; + if (file.Open(path, CFile::modeRead | CFile::modeCreate | CFile::shareDenyNone)) { + ULONGLONG length = file.GetLength(); + FILETIME ftCreate = {}, ftAccess = {}, ftWrite = {}; + GetFileTime(file.m_hFile, &ftCreate, &ftAccess, &ftWrite); + + file.Close(); + + if ((*it).length == length && CompareFileTime(&(*it).ftwrite, &ftWrite) == 0) { + it++; + continue; // actual shader + } + } + + m_ShaderCache.erase(it++); // outdated shader + } +} + +void CMainFrame::SetShaders(bool bSetPreResize/* = true*/, bool bSetPostResize/* = true*/) +{ + if (GetLoadState() != MLS::LOADED) { + return; + } + + const auto& s = AfxGetAppSettings(); + bool preFailed = false, postFailed = false; + + if (m_pCAP3) { //interfaces for madVR and MPC-VR + TidyShaderCache(); + const int PShaderMode = m_pCAP3->GetPixelShaderMode(); + if (PShaderMode != 9 && PShaderMode != 11) { + return; + } + + m_pCAP3->ClearPixelShaders(TARGET_FRAME); + m_pCAP3->ClearPixelShaders(TARGET_SCREEN); + int shadercount = 0; + if (bSetPreResize) { + int preTarget; + if (s.iDSVideoRendererType == VIDRNDT_DS_MPCVR) { //for now MPC-VR does not support pre-size shaders + preTarget = TARGET_SCREEN; + } else { + preTarget = TARGET_FRAME; + } + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { + ShaderC* pShader = GetShader(shader.filePath, PShaderMode == 11); + if (pShader) { + shadercount++; + CStringW label; + label.Format(L"Shader%d", shadercount); + CStringA profile = pShader->profile; + CStringA srcdata = pShader->srcdata; + if (FAILED(m_pCAP3->AddPixelShader(preTarget, label, profile, srcdata))) { + preFailed = true; + m_pCAP3->ClearPixelShaders(preTarget); + break; + } + } + } + } + if (bSetPostResize) { + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize().ExpandMultiPassShaderList()) { + ShaderC* pShader = GetShader(shader.filePath, PShaderMode == 11); + if (pShader) { + shadercount++; + CStringW label; + label.Format(L"Shader%d", shadercount); + CStringA profile = pShader->profile; + CStringA srcdata = pShader->srcdata; + if (FAILED(m_pCAP3->AddPixelShader(TARGET_SCREEN, label, profile, srcdata))) { + postFailed = true; + m_pCAP3->ClearPixelShaders(TARGET_SCREEN); + break; + } + } + } + } + } else if (m_pCAP2) { + // When pTarget parameter of ISubPicAllocatorPresenter2::SetPixelShader2() is nullptr, + // internal video renderers select maximum available profile and madVR (the only external renderer that + // supports shader part of ISubPicAllocatorPresenter2 interface) seems to ignore it altogether. + m_pCAP2->SetPixelShader2(nullptr, nullptr, false); + if (bSetPreResize) { + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { + if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, false))) { + preFailed = true; + m_pCAP2->SetPixelShader2(nullptr, nullptr, false); + break; + } + } + } + m_pCAP2->SetPixelShader2(nullptr, nullptr, true); + if (bSetPostResize) { + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPostResize().ExpandMultiPassShaderList()) { + if (FAILED(m_pCAP2->SetPixelShader2(shader.GetCode(), nullptr, true))) { + postFailed = true; + m_pCAP2->SetPixelShader2(nullptr, nullptr, true); + break; + } + } + } + } else if (m_pCAP) { + // shouldn't happen, all known renderers that support ISubPicAllocatorPresenter interface + // support ISubPicAllocatorPresenter2 as well, and it takes priority + ASSERT(FALSE); + m_pCAP->SetPixelShader(nullptr, nullptr); + if (bSetPreResize) { + for (const auto& shader : s.m_Shaders.GetCurrentPreset().GetPreResize().ExpandMultiPassShaderList()) { + if (FAILED(m_pCAP->SetPixelShader(shader.GetCode(), nullptr))) { + preFailed = true; + m_pCAP->SetPixelShader(nullptr, nullptr); + break; + } + } + } + postFailed = !s.m_Shaders.GetCurrentPreset().GetPostResize().empty(); + } + + CString errMsg; + if (preFailed && postFailed) { + VERIFY(errMsg.LoadString(IDS_MAINFRM_BOTH_SHADERS_FAILED)); + } else if (preFailed) { + VERIFY(errMsg.LoadString(IDS_MAINFRM_PRE_SHADERS_FAILED)); + } else if (postFailed) { + VERIFY(errMsg.LoadString(IDS_MAINFRM_POST_SHADERS_FAILED)); + } else { + return; + } + SendStatusMessage(errMsg, 3000); +} + +void CMainFrame::SetBalance(int balance) +{ + int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channel + int balance_dB; + if (balance > -100 && balance < 100) { + balance_dB = sign * (int)(100 * 20 * log10(1 - abs(balance) / 100.0f)); + } else { + balance_dB = sign * (-10000); // -10000: only left, 10000: only right + } + + if (GetLoadState() == MLS::LOADED) { + CString strBalance, strBalanceOSD; + + m_pBA->put_Balance(balance_dB); + + if (balance == 0) { + strBalance.LoadString(IDS_BALANCE); + } else if (balance < 0) { + strBalance.Format(IDS_BALANCE_L, -balance); + } else { //if (m_nBalance > 0) + strBalance.Format(IDS_BALANCE_R, balance); + } + + strBalanceOSD.Format(IDS_BALANCE_OSD, strBalance.GetString()); + m_OSD.DisplayMessage(OSD_TOPLEFT, strBalanceOSD); + } +} + +// +// Open/Close +// + +bool PathIsOnOpticalDisc(CString path) +{ + if (path.GetLength() >= 3 && path[1] == L':' && path[2] == L'\\') { + CString drive = path.Left(3); + UINT type = GetDriveType(drive); + return type == DRIVE_CDROM && !IsDriveVirtual(drive); + } + return false; +} + +// Called from GraphThread +void CMainFrame::OpenCreateGraphObject(OpenMediaData* pOMD) +{ + ASSERT(m_pGB == nullptr); + + m_fCustomGraph = false; + m_fShockwaveGraph = false; + + const CAppSettings& s = AfxGetAppSettings(); + + m_pGB_preview = nullptr; + m_bUseSeekPreview = s.fUseSeekbarHover && s.fSeekPreview && m_wndPreView && ::IsWindow(m_wndPreView.m_hWnd) && !(s.nCLSwitches & CLSW_THUMBNAILS); + if (m_bUseSeekPreview) { +#if 1 + if (auto pOpenDVDData = dynamic_cast(pOMD)) { + // preview does not always work good with DVD even when loaded from hdd + m_bUseSeekPreview = false; + } else +#endif + if (OpenFileData* pFileData = dynamic_cast(pOMD)) { + CString fn = pFileData->fns.GetHead(); + if (fn.IsEmpty()) { + m_bUseSeekPreview = false; + } else { + CString ext = CPath(fn).GetExtension().MakeLower(); + if (((fn.Find(L"://") >= 0) || IsAudioFileExt(ext) || ext == L".avs" || PathIsOnOpticalDisc(fn))) { + // disable seek preview for: streaming data, audio files, files on optical disc + m_bUseSeekPreview = false; + } + } + } + } + + if (auto pOpenFileData = dynamic_cast(pOMD)) { + engine_t engine = s.m_Formats.GetEngine(pOpenFileData->fns.GetHead()); + + HRESULT hr = E_FAIL; + CComPtr pUnk; + + if (engine == ShockWave) { + pUnk = (IUnknown*)(INonDelegatingUnknown*)DEBUG_NEW DSObjects::CShockwaveGraph(m_pVideoWnd->m_hWnd, hr); + if (!pUnk) { + throw (UINT)IDS_AG_OUT_OF_MEMORY; + } + + if (SUCCEEDED(hr)) { + m_pGB = CComQIPtr(pUnk); + } + if (FAILED(hr) || !m_pGB) { + throw (UINT)IDS_MAINFRM_77; + } + m_fShockwaveGraph = true; + } + + m_fCustomGraph = m_fShockwaveGraph; + + if (!m_fCustomGraph) { + CFGManagerPlayer* fgm = DEBUG_NEW CFGManagerPlayer(_T("CFGManagerPlayer"), nullptr, m_pVideoWnd->m_hWnd); + if (!pOpenFileData->useragent.IsEmpty()) { + fgm->SetUserAgent(pOpenFileData->useragent); + } + if (!pOpenFileData->referrer.IsEmpty()) { + fgm->SetReferrer(pOpenFileData->referrer); + } + m_pGB = fgm; + + if (m_pGB && m_bUseSeekPreview) { + // build graph for preview + m_pGB_preview = DEBUG_NEW CFGManagerPlayer(L"CFGManagerPlayer", nullptr, m_wndPreView.GetVideoHWND(), true); + } + } + } else if (auto pOpenDVDData = dynamic_cast(pOMD)) { + m_pGB = DEBUG_NEW CFGManagerDVD(_T("CFGManagerDVD"), nullptr, m_pVideoWnd->m_hWnd); + + if (m_bUseSeekPreview) { + if (!PathIsOnOpticalDisc(pOpenDVDData->path)) { + m_pGB_preview = DEBUG_NEW CFGManagerDVD(L"CFGManagerDVD", nullptr, m_wndPreView.GetVideoHWND(), true); + } + } + } else if (auto pOpenDeviceData = dynamic_cast(pOMD)) { + if (s.iDefaultCaptureDevice == 1) { + m_pGB = DEBUG_NEW CFGManagerBDA(_T("CFGManagerBDA"), nullptr, m_pVideoWnd->m_hWnd); + } else { + m_pGB = DEBUG_NEW CFGManagerCapture(_T("CFGManagerCapture"), nullptr, m_pVideoWnd->m_hWnd); + } + } + + if (!m_pGB) { + throw (UINT)IDS_MAINFRM_80; + } + + if (!m_pGB_preview) { + m_bUseSeekPreview = false; + } + + m_pGB->AddToROT(); + + m_pMC = m_pGB; + m_pME = m_pGB; + m_pMS = m_pGB; // general + m_pVW = m_pGB; + m_pBV = m_pGB; // video + m_pBA = m_pGB; // audio + m_pFS = m_pGB; + + if (m_bUseSeekPreview) { + m_pGB_preview->AddToROT(); + + m_pMC_preview = m_pGB_preview; + //m_pME_preview = m_pGB_preview; + m_pMS_preview = m_pGB_preview; // general + m_pVW_preview = m_pGB_preview; + m_pBV_preview = m_pGB_preview; + //m_pFS_preview = m_pGB_preview; + } + + if (!(m_pMC && m_pME && m_pMS) + || !(m_pVW && m_pBV) + || !(m_pBA)) { + throw (UINT)IDS_GRAPH_INTERFACES_ERROR; + } + + if (FAILED(m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0))) { + throw (UINT)IDS_GRAPH_TARGET_WND_ERROR; + } + + m_pProv = (IUnknown*)DEBUG_NEW CKeyProvider(); + + if (CComQIPtr pObjectWithSite = m_pGB) { + pObjectWithSite->SetSite(m_pProv); + } + + m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); +} + +CWnd* CMainFrame::GetModalParent() +{ + const CAppSettings& s = AfxGetAppSettings(); + CWnd* pParentWnd = this; + if (HasDedicatedFSVideoWindow() && s.m_RenderersSettings.m_AdvRendSets.bVMR9FullscreenGUISupport) { + pParentWnd = m_pDedicatedFSVideoWnd; + } + return pParentWnd; +} + +void CMainFrame::ShowMediaTypesDialog() { + if (!m_fOpeningAborted) { + CAutoLock lck(&lockModalDialog); + CComQIPtr pGBDE = m_pGB; + if (pGBDE && pGBDE->GetCount()) { + mediaTypesErrorDlg = DEBUG_NEW CMediaTypesDlg(pGBDE, GetModalParent()); + mediaTypesErrorDlg->DoModal(); + delete mediaTypesErrorDlg; + mediaTypesErrorDlg = nullptr; + } + } +} + +void CMainFrame::ReleasePreviewGraph() +{ + if (m_pGB_preview) { + m_pCAP2_preview.Release(); + m_pMFVP_preview.Release(); + m_pMFVDC_preview.Release(); + m_pVMR9C_preview.Release(); + + //m_pFS_preview.Release(); + m_pMS_preview.Release(); + m_pBV_preview.Release(); + m_pVW_preview.Release(); + //m_pME_preview.Release(); + m_pMC_preview.Release(); + + if (m_pDVDC_preview) { + m_pDVDC_preview.Release(); + m_pDVDI_preview.Release(); + } + + m_pGB_preview->RemoveFromROT(); + m_pGB_preview.Release(); + } +} + +HRESULT CMainFrame::PreviewWindowHide() { + HRESULT hr = S_OK; + + if (!m_bUseSeekPreview) { + return E_FAIL; + } + + if (m_wndPreView.IsWindowVisible()) { + // Disable animation + ANIMATIONINFO AnimationInfo; + AnimationInfo.cbSize = sizeof(ANIMATIONINFO); + ::SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + int WindowAnimationType = AnimationInfo.iMinAnimate; + AnimationInfo.iMinAnimate = 0; + ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + + m_wndPreView.ShowWindow(SW_HIDE); + + // Enable animation + AnimationInfo.iMinAnimate = WindowAnimationType; + ::SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, 0); + + if (m_pGB_preview && m_pMC_preview) { + m_pMC_preview->Pause(); + } + } + + return hr; +} + +HRESULT CMainFrame::PreviewWindowShow(REFERENCE_TIME rtCur2) { + if (!CanPreviewUse()) { + return E_FAIL; + } + + HRESULT hr = S_OK; + if (GetPlaybackMode() == PM_DVD && m_pDVDC_preview) { + DVD_PLAYBACK_LOCATION2 Loc, Loc2; + double fps = 0; + + hr = m_pDVDI->GetCurrentLocation(&Loc); + if (FAILED(hr)) { + return hr; + } + + hr = m_pDVDI_preview->GetCurrentLocation(&Loc2); + + fps = Loc.TimeCodeFlags == DVD_TC_FLAG_25fps ? 25.0 + : Loc.TimeCodeFlags == DVD_TC_FLAG_30fps ? 30.0 + : Loc.TimeCodeFlags == DVD_TC_FLAG_DropFrame ? 29.97 + : 25.0; + + DVD_HMSF_TIMECODE dvdTo = RT2HMSF(rtCur2, fps); + + if (FAILED(hr) || (Loc.TitleNum != Loc2.TitleNum)) { + hr = m_pDVDC_preview->PlayTitle(Loc.TitleNum, DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + return hr; + } + m_pDVDC_preview->Resume(DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (SUCCEEDED(hr)) { + hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + return hr; + } + } else { + hr = m_pDVDC_preview->PlayChapterInTitle(Loc.TitleNum, 1, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + hr = m_pDVDC_preview->PlayAtTimeInTitle(Loc.TitleNum, &dvdTo, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + return hr; + } + } + } + } else { + hr = m_pDVDC_preview->PlayAtTime(&dvdTo, DVD_CMD_FLAG_Flush, nullptr); + if (FAILED(hr)) { + return hr; + } + } + + m_pDVDI_preview->GetCurrentLocation(&Loc2); + + m_pMC_preview->Run(); + Sleep(10); + m_pMC_preview->Pause(); + } else if (GetPlaybackMode() == PM_FILE && m_pMS_preview) { + hr = m_pMS_preview->SetPositions(&rtCur2, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } else { + return E_FAIL; + } + + if (FAILED(hr)) { + return hr; + } + + /* + if (GetPlaybackMode() == PM_FILE) { + hr = pFS2 ? pFS2->Step(2, nullptr) : E_FAIL; + if (SUCCEEDED(hr)) { + Sleep(10); + } + } + */ + + if (!m_wndPreView.IsWindowVisible()) { + m_wndPreView.SetRelativeSize(AfxGetAppSettings().iSeekPreviewSize); + m_wndPreView.ShowWindow(SW_SHOWNOACTIVATE); + m_wndPreView.SetWindowSize(); + } + + return hr; +} + +HRESULT CMainFrame::HandleMultipleEntryRar(CStringW fn) { + CRFSList file_list(true); //true = clears itself on destruction + int num_files, num_ok_files; + + CRARFileSource::ScanArchive(fn.GetBuffer(), &file_list, &num_files, &num_ok_files); + if (num_ok_files > 1) { + RarEntrySelectorDialog entrySelector(&file_list, GetModalParent()); + if (IDOK == entrySelector.DoModal()) { + CStringW entryName = entrySelector.GetCurrentEntry(); + if (entryName.GetLength() > 0) { + CComPtr fgm = static_cast(m_pGB.p); + return fgm->RenderRFSFileEntry(fn, nullptr, entryName); + } + } + return RFS_E_ABORT; //we found multiple entries but no entry selected. + } + return E_NOTIMPL; //not a multi-entry rar +} + +// Called from GraphThread +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; + } + if (bMainFile) { + // store info, this is used for skipping to next/previous file + pOFD->title = fn; + lastOpenFile = fn; + } + + CString ext = GetFileExt(fn); + if (ext == ".mpls") { + CString fnn = PathUtils::StripPathOrUrl(fn); + CString tempath(fn); + tempath.Replace(fnn, _T("")); + tempath.Replace(_T("BDMV\\PLAYLIST\\"), _T("")); + CHdmvClipInfo clipinfo; + m_bHasBDMeta = clipinfo.ReadMeta(tempath, m_BDMeta); + } + + HRESULT hr; + HRESULT rarHR = E_NOTIMPL; +#if INTERNAL_SOURCEFILTER_RFS + if (s.SrcFilters[SRC_RFS] && !PathUtils::IsURL(fn)) { + CString ext = CPath(fn).GetExtension().MakeLower(); + if (ext == L".rar") { + rarHR = HandleMultipleEntryRar(fn); + } + } +#endif + + if (E_NOTIMPL == rarHR) { + hr = m_pGB->RenderFile(fn, nullptr); + } else { + hr = rarHR; + } + + if (FAILED(hr)) { + if (bMainFile) { + if (m_pME) { + m_pME->SetNotifyWindow(NULL, 0, 0); + } + + if (s.fReportFailedPins) { + ShowMediaTypesDialog(); + } + + 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; + } + } + + if (bMainFile) { + bool bIsVideo = false; + bool isRFS = false; + CStringW entryRFS; + + // Check for supported interfaces + BeginEnumFilters(m_pGB, pEF, pBF); + bool fsf = false; + CLSID clsid = GetCLSID(pBF); + // IFileSourceFilter + if (!m_pFSF) { + m_pFSF = pBF; + if (m_pFSF) { + fsf = true; + if (!m_pAMNS) { + m_pAMNS = pBF; + } + if (!m_pSplitterSS) { + m_pSplitterSS = pBF; + } + if (m_bUseSeekPreview) { + if (clsid == CLSID_StillVideo || clsid == CLSID_MPCImageSource) { + m_bUseSeekPreview = false; + } else if (clsid == __uuidof(CRARFileSource)) { + WCHAR* pFN = nullptr; + AM_MEDIA_TYPE mt; + if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) { + isRFS = true; + entryRFS = pFN; + CoTaskMemFree(pFN); + } + } + } + } + } + // IAMStreamSelect / IDirectVobSub + if (!fsf) { + if (clsid == __uuidof(CAudioSwitcherFilter)) { + m_pAudioSwitcherSS = pBF; + } else { + if (clsid == GUID_LAVSplitter) { + m_pSplitterSS = pBF; + } else { + if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { + m_pDVS = pBF; + m_pDVS2 = pBF; + } else { + if (clsid != CLSID_MPCBEAudioRenderer) { + if (CComQIPtr pTest = pBF) { + if (!m_pOtherSS[0]) { + m_pOtherSS[0] = pBF; + } else if (!m_pOtherSS[1]) { + m_pOtherSS[1] = pBF; + } else { + ASSERT(false); + } + } + } + } + } + } + } + // Others + if (!m_pLN21) { + m_pLN21 = pBF; + } + if (!m_pKFI) { + m_pKFI = pBF; + } + if (!m_pAMOP) { + m_pAMOP = pBF; + } + if (!m_pAMMC[0]) { + m_pAMMC[0] = pBF; + } else if (!m_pAMMC[1]) { + m_pAMMC[1] = pBF; + } + if (m_bUseSeekPreview && !bIsVideo && IsVideoRenderer(pBF)) { + bIsVideo = true; + } + EndEnumFilters; + + ASSERT(m_pFSF); + + if (!bIsVideo) { + m_bUseSeekPreview = false; + } + if (m_bUseSeekPreview && IsImageFile(fn)) { + // don't use preview for images + m_bUseSeekPreview = false; + } + + if (m_bUseSeekPreview) { + HRESULT previewHR; + if (isRFS) { + CComPtr fgm = static_cast(m_pGB_preview.p); + previewHR = fgm->RenderRFSFileEntry(fn, nullptr, entryRFS); + } else { + previewHR = m_pGB_preview->RenderFile(fn, nullptr); + } + + if (FAILED(previewHR)) { + m_bUseSeekPreview = false; + ReleasePreviewGraph(); + } + } + } else { // Audio DUB + // Check for supported interfaces + BeginEnumFilters(m_pGB, pEF, pBF); + CLSID clsid = GetCLSID(pBF); + if (clsid == GUID_LAVSplitter || clsid == GUID_LAVSplitterSource) { + m_pSplitterDubSS = pBF; + if (m_pSplitterSS && m_pSplitterSS == m_pSplitterDubSS) { + m_pSplitterDubSS.Release(); + } + } else if (clsid == __uuidof(CAudioSwitcherFilter)) { + if (!m_pAudioSwitcherSS) { + m_pAudioSwitcherSS = pBF; + } + } + EndEnumFilters; + } + + // We don't keep track of piped inputs since that hardly makes any sense + if (s.fKeepHistory && fn.Find(_T("pipe:")) != 0 && pOFD->bAddToRecent) { + if (bMainFile) { + auto* pMRU = &s.MRU; + RecentFileEntry r; + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + if (pli.m_bYoutubeDL && !pli.m_ydlSourceURL.IsEmpty()) { + pMRU->LoadMediaHistoryEntryFN(pli.m_ydlSourceURL, r); + } else { + pMRU->LoadMediaHistoryEntryFN(fn, r); + if (pli.m_fns.GetCount() > r.fns.GetCount()) { + r.fns.RemoveAll(); + r.fns.AddHeadList(&pli.m_fns); + } + SHAddToRecentDocs(SHARD_PATH, fn); + } + if (pli.m_cue) { + r.cue = pli.m_cue_filename; + } + if (pli.m_subs.GetCount() > r.subs.GetCount()) { + r.subs.RemoveAll(); + r.subs.AddHeadList(&pli.m_subs); + } + + if (pli.m_label.IsEmpty()) { + CString title; + for (const auto& pAMMC : m_pAMMC) { + if (pAMMC) { + CComBSTR bstr; + if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { + title = bstr.m_str; + title.Trim(); + break; + } + } + } + if (title.GetLength() >= 10 && !IsNameSimilar(title, PathUtils::StripPathOrUrl(fn))) { + r.title = title; + } + } else { + if (pli.m_bYoutubeDL || !IsNameSimilar(pli.m_label, PathUtils::StripPathOrUrl(fn))) { + if (!pli.m_bYoutubeDL || fn == pli.m_ydlSourceURL) { + r.title = pli.m_label; + } else { + CString videoName(pli.m_label); + int m = LastIndexOfCString(videoName, _T(" (")); + if (m > 0) { + videoName = pli.m_label.Left(m); + } + r.title = videoName; + } + } + } + } else { + ASSERT(false); + r.fns.AddHead(fn); + } + + pMRU->Add(r, true); + CStringW playListName; + if (s.bRememberExternalPlaylistPos && m_wndPlaylistBar.IsExternalPlayListActive(playListName)) { + s.SavePlayListPosition(playListName, m_wndPlaylistBar.GetSelIdx()); + } + } + else { + CPlaylistItem pli; + if (!m_wndPlaylistBar.GetCur(pli) || !pli.m_bYoutubeDL) { + CRecentFileList* pMRUDub = &s.MRUDub; + pMRUDub->ReadList(); + pMRUDub->Add(fn); + pMRUDub->WriteList(); + } + } + } + + bMainFile = false; + + if (m_fCustomGraph) { + break; + } + } + + if (s.fReportFailedPins) { + ShowMediaTypesDialog(); + } + + SetupChapters(); + + SetPlaybackMode(PM_FILE); +} + +void CMainFrame::SetupExternalChapters() +{ + // .XCHP (eXternal CHaPters) file format: + // - UTF-8 text file. + // - Located in same folder as the audio/video file, and has same base filename. + // - It will override chapter metadata that is embedded in the file. + // - Each line defines a chapter: timecode, optionally followed by a space and chapter title. + // - Timecode must be in this format: HH:MM:SS,ddd + + CString fn = m_wndPlaylistBar.GetCurFileName(true); + if (fn.IsEmpty() || PathUtils::IsURL(fn)) { + return; + } + + CPath cp(fn); + cp.RenameExtension(_T(".xchp")); + if (!cp.FileExists()) { + return; + } + fn = cp.m_strPath; + + CTextFile f(CTextFile::UTF8); + f.SetFallbackEncoding(CTextFile::ANSI); + + CString str; + if (!f.Open(fn) || !f.ReadString(str)) { + return; + } + + f.Seek(0, CFile::SeekPosition::begin); + + while (f.ReadString(str)) { + REFERENCE_TIME rt = 0; + CString name = ""; + + if (str.GetLength() > 11) { + int lHour = 0; + int lMinute = 0; + int lSecond = 0; + int lMillisec = 0; + if (_stscanf_s(str.Left(12), _T("%02d:%02d:%02d,%03d"), &lHour, &lMinute, &lSecond, &lMillisec) == 4) { + rt = ((((lHour * 60) + lMinute) * 60 + lSecond) * MILLISECONDS + lMillisec) * (UNITS / MILLISECONDS); + if (str.GetLength() > 12) { + name = str.Mid(12); + name.Trim(); + } + m_pCB->ChapAppend(rt, name); + } else { + break; + } + } else { + break; + } + } + m_pCB->ChapSort(); +} + +void CMainFrame::SetupChapters() +{ + // Release the old chapter bag and create a new one. + // Due to smart pointers the old chapter bag won't + // be deleted until all classes release it. + m_pCB.Release(); + m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); + + SetupExternalChapters(); + if (m_pCB->ChapGetCount() > 0) { + UpdateSeekbarChapterBag(); + return; + } + + // ToDo: add global pointer list for IDSMChapterBag + CInterfaceList pBFs; + BeginEnumFilters(m_pGB, pEF, pBF); + pBFs.AddTail(pBF); + EndEnumFilters; + + POSITION pos; + + pos = pBFs.GetHeadPosition(); + while (pos && !m_pCB->ChapGetCount()) { + IBaseFilter* pBF = pBFs.GetNext(pos); + + CComQIPtr pCB = pBF; + if (!pCB) { + continue; + } + + for (DWORD i = 0, cnt = pCB->ChapGetCount(); i < cnt; i++) { + REFERENCE_TIME rt; + CComBSTR name; + if (SUCCEEDED(pCB->ChapGet(i, &rt, &name))) { + m_pCB->ChapAppend(rt, name); + } + } + } + + pos = pBFs.GetHeadPosition(); + while (pos && !m_pCB->ChapGetCount()) { + IBaseFilter* pBF = pBFs.GetNext(pos); + + CComQIPtr pCI = pBF; + if (!pCI) { + continue; + } + + CHAR iso6391[3]; + ::GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, iso6391, 3); + CStringA iso6392 = ISOLang::ISO6391To6392(iso6391); + if (iso6392.GetLength() < 3) { + iso6392 = "eng"; + } + + UINT cnt = pCI->GetChapterCount(CHAPTER_ROOT_ID); + for (UINT i = 1; i <= cnt; i++) { + UINT cid = pCI->GetChapterId(CHAPTER_ROOT_ID, i); + + ChapterElement ce; + if (pCI->GetChapterInfo(cid, &ce)) { + char pl[3] = {iso6392[0], iso6392[1], iso6392[2]}; + char cc[] = " "; + CComBSTR name; + name.Attach(pCI->GetChapterStringInfo(cid, pl, cc)); + m_pCB->ChapAppend(ce.rtStart, name); + } + } + } + + pos = pBFs.GetHeadPosition(); + while (pos && !m_pCB->ChapGetCount()) { + IBaseFilter* pBF = pBFs.GetNext(pos); + + CComQIPtr pES = pBF; + if (!pES) { + continue; + } + + long MarkerCount = 0; + if (SUCCEEDED(pES->get_MarkerCount(&MarkerCount))) { + for (long i = 1; i <= MarkerCount; i++) { + double MarkerTime = 0; + if (SUCCEEDED(pES->GetMarkerTime(i, &MarkerTime))) { + CStringW name; + name.Format(IDS_AG_CHAPTER, i); + + CComBSTR bstr; + if (S_OK == pES->GetMarkerName(i, &bstr)) { + name = bstr; + } + + m_pCB->ChapAppend(REFERENCE_TIME(MarkerTime * 10000000), name); + } + } + } + } + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_cue) { + SetupCueChapters(pli.m_cue_filename); + } + + UpdateSeekbarChapterBag(); +} + +void CMainFrame::SetupCueChapters(CString fn) { + CString str; + int cue_index(-1); + + CPlaylistItem pli; + if (!m_wndPlaylistBar.GetCur(pli, true)) { + ASSERT(false); + return; + } + + CWebTextFile f(CTextFile::UTF8); + f.SetFallbackEncoding(CTextFile::ANSI); + if (!f.Open(fn) || !f.ReadString(str)) { + return; + } + f.Seek(0, CFile::SeekPosition::begin); + + CString base; + bool isurl = PathUtils::IsURL(fn); + if (isurl) { + int p = fn.Find(_T('?')); + if (p > 0) { + fn = fn.Left(p); + } + p = fn.ReverseFind(_T('/')); + if (p > 0) { + base = fn.Left(p + 1); + } + } + else { + CPath basefilepath(fn); + basefilepath.RemoveFileSpec(); + basefilepath.AddBackslash(); + base = basefilepath.m_strPath; + } + + CString title; + CString performer; + CAtlList trackl; + CueTrackMeta track; + int trackID(0); + + while (f.ReadString(str)) { + str.Trim(); + if (cue_index == -1 && str.Left(5) == _T("TITLE")) { + title = str.Mid(6).Trim(_T("\"")); + } + else if (cue_index == -1 && str.Left(9) == _T("PERFORMER")) { + performer = str.Mid(10).Trim(_T("\"")); + } + else if (str.Left(4) == _T("FILE")) { + if (str.Right(4) == _T("WAVE") || str.Right(3) == _T("MP3") || str.Right(4) == _T("AIFF")) { // We just support audio file. + cue_index++; + } + } + else if (cue_index >= 0) { + if (str.Left(5) == _T("TRACK") && str.Right(5) == _T("AUDIO")) { + CT2CA tmp(str.Mid(6, str.GetLength() - 12)); + const char* tmp2(tmp); + sscanf_s(tmp2, "%d", &trackID); + if (track.trackID != 0) { + trackl.AddTail(track); + track = CueTrackMeta(); + } + track.trackID = trackID; + } + else if (str.Left(5) == _T("TITLE")) { + track.title = str.Mid(6).Trim(_T("\"")); + } + else if (str.Left(9) == _T("PERFORMER")) { + track.performer = str.Mid(10).Trim(_T("\"")); + } + else if (str.Left(5) == _T("INDEX")) { + CT2CA tmp(str.Mid(6)); + const char* tmp2(tmp); + int i1(0), m(0), s(0), ms(0); + sscanf_s(tmp2, "%d %d:%d:%d", &i1, &m, &s, &ms); + if (i1 != 0) track.time = 10000i64 * ((m * 60 + s) * 1000 + ms); + } + } + } + + if (track.trackID != 0) { + trackl.AddTail(track); + } + + if ((cue_index == 0 && trackl.GetCount() == 1) || cue_index > 1) pli.m_cue = false; // avoid unnecessary parsing of cue again later + + if (trackl.GetCount() >= 1) { + POSITION p = trackl.GetHeadPosition(); + bool b(true); + do { + if (p == trackl.GetTailPosition()) b = false; + CueTrackMeta c(trackl.GetNext(p)); + if (cue_index == 0 || (cue_index > 0 && c.trackID == (pli.m_cue_index + 1))) { + CString label; + if (c.trackID != 0 && !c.title.IsEmpty()) { + label = c.title; + if (!c.performer.IsEmpty()) { + label += (_T(" - ") + c.performer); + } + else if (!performer.IsEmpty()) { + label += (_T(" - ") + performer); + } + } + REFERENCE_TIME time(c.time); + if (cue_index > 0) time = 0; // We don't support gap. + m_pCB->ChapAppend(time, label); + } + } while (b); + } +} + +void CMainFrame::SetupDVDChapters() +{ + // Release the old chapter bag and create a new one. + // Due to smart pointers the old chapter bag won't + // be deleted until all classes release it. + m_pCB.Release(); + m_pCB = DEBUG_NEW CDSMChapterBag(nullptr, nullptr); + + WCHAR buff[MAX_PATH]; + ULONG len, ulNumOfChapters; + DVD_PLAYBACK_LOCATION2 loc; + + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDVDDirectory(buff, _countof(buff), &len)) + && SUCCEEDED(m_pDVDI->GetCurrentLocation(&loc)) + && SUCCEEDED(m_pDVDI->GetNumberOfChapters(loc.TitleNum, &ulNumOfChapters))) { + CString path; + path.Format(L"%s\\video_ts.IFO", buff); + ULONG VTSN, TTN; + + if (CVobFile::GetTitleInfo(path, loc.TitleNum, VTSN, TTN)) { + path.Format(L"%s\\VTS_%02lu_0.IFO", buff, VTSN); + CAtlList files; + + CVobFile vob; + if (vob.Open(path, files, TTN, false)) { + int iChaptersCount = vob.GetChaptersCount(); + if (ulNumOfChapters == (ULONG)iChaptersCount) { + for (int i = 0; i < iChaptersCount; i++) { + REFERENCE_TIME rt = vob.GetChapterOffset(i); + + CStringW str; + str.Format(IDS_AG_CHAPTER, i + 1); + + m_pCB->ChapAppend(rt, str); + } + } else { + // Parser failed! + ASSERT(FALSE); + } + vob.Close(); + } + } + } + + m_pCB->ChapSort(); + + UpdateSeekbarChapterBag(); +} + +// Called from GraphThread +void CMainFrame::OpenDVD(OpenDVDData* pODD) +{ + lastOpenFile.Empty(); + + HRESULT hr = m_pGB->RenderFile(CStringW(pODD->path), nullptr); + + CAppSettings& s = AfxGetAppSettings(); + + if (s.fReportFailedPins) { + ShowMediaTypesDialog(); + } + + if (SUCCEEDED(hr) && m_bUseSeekPreview) { + if (FAILED(hr = m_pGB_preview->RenderFile(pODD->path, nullptr))) { + m_bUseSeekPreview = false; + } + } + + // Check for supported interfaces + BeginEnumFilters(m_pGB, pEF, pBF) + CLSID clsid = GetCLSID(pBF); + // DVD stuff + if (!m_pDVDC) { + m_pDVDC = pBF; + } + if (!m_pDVDI) { + m_pDVDI = pBF; + } + // IAMStreamSelect filters / IDirectVobSub + if (clsid == __uuidof(CAudioSwitcherFilter)) { + m_pAudioSwitcherSS = pBF; + } else { + if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { + m_pDVS = pBF; + m_pDVS2 = pBF; + } else { + if (clsid != CLSID_MPCBEAudioRenderer) { + if (CComQIPtr pTest = pBF) { + if (!m_pOtherSS[0]) { + m_pOtherSS[0] = pBF; + } else if (!m_pOtherSS[1]) { + m_pOtherSS[1] = pBF; + } else { + ASSERT(false); + } + } + } + } + } + // Others + if (!m_pLN21) { + m_pLN21 = pBF; + } + EndEnumFilters; + + ASSERT(m_pDVDC); + ASSERT(m_pDVDI); + + if (m_bUseSeekPreview) { + BeginEnumFilters(m_pGB_preview, pEF, pBF) { + if ((m_pDVDC_preview = pBF) && (m_pDVDI_preview = pBF)) { + break; + } + } + EndEnumFilters; + } + + if (hr == E_INVALIDARG) { + throw (UINT)IDS_MAINFRM_93; + } else if (hr == VFW_E_CANNOT_RENDER) { + throw (UINT)IDS_DVD_NAV_ALL_PINS_ERROR; + } else if (hr == VFW_S_PARTIAL_RENDER) { + throw (UINT)IDS_DVD_NAV_SOME_PINS_ERROR; + } else if (hr == E_NOINTERFACE || !m_pDVDC || !m_pDVDI) { + throw (UINT)IDS_DVD_INTERFACES_ERROR; + } else if (hr == VFW_E_CANNOT_LOAD_SOURCE_FILTER) { + throw (UINT)IDS_MAINFRM_94; + } else if (FAILED(hr)) { + throw (UINT)IDS_AG_FAILED; + } + + WCHAR buff[MAX_PATH]; + ULONG len = 0; + if (SUCCEEDED(hr = m_pDVDI->GetDVDDirectory(buff, _countof(buff), &len))) { + pODD->title = CString(CStringW(buff)).TrimRight(_T("\\")); + } + + if (s.fKeepHistory) { + ULONGLONG llDVDGuid; + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDiscID(nullptr, &llDVDGuid))) { + auto* pMRU = &s.MRU; + pMRU->Add(pODD->title, llDVDGuid); + } + SHAddToRecentDocs(SHARD_PATH, pODD->title); + } + + // TODO: resetdvd + m_pDVDC->SetOption(DVD_ResetOnStop, FALSE); + m_pDVDC->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); + + if (m_bUseSeekPreview && m_pDVDC_preview) { + m_pDVDC_preview->SetOption(DVD_ResetOnStop, FALSE); + m_pDVDC_preview->SetOption(DVD_HMSF_TimeCodeEvents, TRUE); + } + + if (s.idMenuLang) { + m_pDVDC->SelectDefaultMenuLanguage(s.idMenuLang); + } + if (s.idAudioLang) { + m_pDVDC->SelectDefaultAudioLanguage(s.idAudioLang, DVD_AUD_EXT_NotSpecified); + } + if (s.idSubtitlesLang) { + m_pDVDC->SelectDefaultSubpictureLanguage(s.idSubtitlesLang, DVD_SP_EXT_NotSpecified); + } + + m_iDVDDomain = DVD_DOMAIN_Stop; + + SetPlaybackMode(PM_DVD); +} + +// Called from GraphThread +HRESULT CMainFrame::OpenBDAGraph() +{ + lastOpenFile.Empty(); + + HRESULT hr = m_pGB->RenderFile(L"", L""); + if (SUCCEEDED(hr)) { + SetPlaybackMode(PM_DIGITAL_CAPTURE); + m_pDVBState = std::make_unique(); + + // Check for supported interfaces + BeginEnumFilters(m_pGB, pEF, pBF); + bool fsf = false; + CLSID clsid = GetCLSID(pBF); + // IFileSourceFilter + if (!m_pFSF) { + m_pFSF = pBF; + if (m_pFSF) { + fsf = true; + if (!m_pAMNS) { + m_pAMNS = pBF; + } + } + } + // IAMStreamSelect / IDirectVobSub + if (!fsf) { + if (clsid == __uuidof(CAudioSwitcherFilter)) { + m_pAudioSwitcherSS = pBF; + } else { + if (clsid == CLSID_VSFilter || clsid == CLSID_XySubFilter) { + m_pDVS = pBF; + m_pDVS2 = pBF; + } + } + } + // Others + if (!m_pLN21) { + m_pLN21 = pBF; + } + if (!m_pAMMC[0]) { + m_pAMMC[0] = pBF; + } else if (!m_pAMMC[1]) { + m_pAMMC[1] = pBF; + } + EndEnumFilters; + + ASSERT(m_pFSF); + + // BDA graph builder implements IAMStreamSelect + m_pSplitterSS = m_pGB; + } + return hr; +} + +// Called from GraphThread +void CMainFrame::OpenCapture(OpenDeviceData* pODD) +{ + lastOpenFile.Empty(); + + m_wndCaptureBar.InitControls(); + + CStringW vidfrname, audfrname; + CComPtr pVidCapTmp, pAudCapTmp; + + m_VidDispName = pODD->DisplayName[0]; + + if (!m_VidDispName.IsEmpty()) { + if (!CreateFilter(m_VidDispName, &pVidCapTmp, vidfrname)) { + throw (UINT)IDS_MAINFRM_96; + } + } + + m_AudDispName = pODD->DisplayName[1]; + + if (!m_AudDispName.IsEmpty()) { + if (!CreateFilter(m_AudDispName, &pAudCapTmp, audfrname)) { + throw (UINT)IDS_MAINFRM_96; + } + } + + if (!pVidCapTmp && !pAudCapTmp) { + throw (UINT)IDS_MAINFRM_98; + } + + m_pCGB = nullptr; + m_pVidCap = nullptr; + m_pAudCap = nullptr; + + if (FAILED(m_pCGB.CoCreateInstance(CLSID_CaptureGraphBuilder2))) { + throw (UINT)IDS_MAINFRM_99; + } + + HRESULT hr; + + m_pCGB->SetFiltergraph(m_pGB); + + if (pVidCapTmp) { + if (FAILED(hr = m_pGB->AddFilter(pVidCapTmp, vidfrname))) { + throw (UINT)IDS_CAPTURE_ERROR_VID_FILTER; + } + + m_pVidCap = pVidCapTmp; + + if (!pAudCapTmp) { + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap))) + && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); + } + + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Interleaved, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev))) + && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); + } + + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pVidCap, IID_PPV_ARGS(&m_pAMASC))) + && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pVidCap, IID_PPV_ARGS(&m_pAMASC)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap")); + } else { + m_pAudCap = m_pVidCap; + } + } else { + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCCap)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); + } + + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMVSCPrev)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap capture")); + } + } + + if (FAILED(m_pCGB->FindInterface(&LOOK_UPSTREAM_ONLY, nullptr, m_pVidCap, IID_PPV_ARGS(&m_pAMXBar)))) { + TRACE(_T("Warning: No IAMCrossbar interface was found\n")); + } + + if (FAILED(m_pCGB->FindInterface(&LOOK_UPSTREAM_ONLY, nullptr, m_pVidCap, IID_PPV_ARGS(&m_pAMTuner)))) { + TRACE(_T("Warning: No IAMTVTuner interface was found\n")); + } + // TODO: init m_pAMXBar + + if (m_pAMTuner) { // load saved channel + m_pAMTuner->put_CountryCode(AfxGetApp()->GetProfileInt(_T("Capture"), _T("Country"), 1)); + + int vchannel = pODD->vchannel; + if (vchannel < 0) { + vchannel = AfxGetApp()->GetProfileInt(_T("Capture\\") + CString(m_VidDispName), _T("Channel"), -1); + } + if (vchannel >= 0) { + OAFilterState fs = State_Stopped; + m_pMC->GetState(0, &fs); + if (fs == State_Running) { + MediaControlPause(true); + } + m_pAMTuner->put_Channel(vchannel, AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT); + if (fs == State_Running) { + MediaControlRun(); + } + } + } + } + + if (pAudCapTmp) { + if (FAILED(hr = m_pGB->AddFilter(pAudCapTmp, CStringW(audfrname)))) { + throw (UINT)IDS_CAPTURE_ERROR_AUD_FILTER; + } + + m_pAudCap = pAudCapTmp; + + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pAudCap, IID_PPV_ARGS(&m_pAMASC))) + && FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pAudCap, IID_PPV_ARGS(&m_pAMASC)))) { + TRACE(_T("Warning: No IAMStreamConfig interface for vidcap")); + } + } + + if (!(m_pVidCap || m_pAudCap)) { + throw (UINT)IDS_MAINFRM_108; + } + + pODD->title.LoadString(IDS_CAPTURE_LIVE); + + SetPlaybackMode(PM_ANALOG_CAPTURE); +} + +// Called from GraphThread +void CMainFrame::OpenCustomizeGraph() +{ + if (GetPlaybackMode() != PM_FILE && GetPlaybackMode() != PM_DVD) { + return; + } + + CleanGraph(); + + if (GetPlaybackMode() == PM_FILE) { + if (m_pCAP && AfxGetAppSettings().IsISRAutoLoadEnabled()) { + AddTextPassThruFilter(); + } + } + + const CAppSettings& s = AfxGetAppSettings(); + const CRenderersSettings& r = s.m_RenderersSettings; + if (r.m_AdvRendSets.bSynchronizeVideo && s.iDSVideoRendererType == VIDRNDT_DS_SYNC) { + HRESULT hr = S_OK; + m_pRefClock = DEBUG_NEW CSyncClockFilter(nullptr, &hr); + + if (SUCCEEDED(hr) && SUCCEEDED(m_pGB->AddFilter(m_pRefClock, L"SyncClock Filter"))) { + CComQIPtr refClock = m_pRefClock; + CComQIPtr mediaFilter = m_pGB; + + if (refClock && mediaFilter) { + VERIFY(SUCCEEDED(mediaFilter->SetSyncSource(refClock))); + mediaFilter = nullptr; + refClock = nullptr; + + VERIFY(SUCCEEDED(m_pRefClock->QueryInterface(IID_PPV_ARGS(&m_pSyncClock)))); + CComQIPtr pAdviser = m_pCAP; + if (pAdviser) { + VERIFY(SUCCEEDED(pAdviser->AdviseSyncClock(m_pSyncClock))); + } + } + } + } + + if (GetPlaybackMode() == PM_DVD) { + if (m_pDVS2) { + if (!m_pSubClock) { + m_pSubClock = DEBUG_NEW CSubClock; + } + m_pDVS2->AdviseSubClock(m_pSubClock); + } + } + + CleanGraph(); +} + +// Called from GraphThread +void CMainFrame::OpenSetupVideo() +{ + m_fAudioOnly = true; + + CSize vs; + + if (m_pMFVDC) { // EVR + m_fAudioOnly = false; + m_pMFVDC->GetNativeVideoSize(&vs, nullptr); + } else if (m_pCAP) { + vs = m_pCAP->GetVideoSize(false); + m_fAudioOnly = (vs.cx <= 0 || vs.cy <= 0); + } else { + if (CComQIPtr pBV = m_pGB) { + pBV->GetVideoSize(&vs.cx, &vs.cy); + + if (vs.cx > 0 && vs.cy > 0) { + m_fAudioOnly = false; + } + } + if (m_fAudioOnly && m_pVW) { + long lVisible; + if (SUCCEEDED(m_pVW->get_Visible(&lVisible))) { + m_pVW->get_Width(&vs.cx); + m_pVW->get_Height(&vs.cy); + if (vs.cx > 0 && vs.cy > 0) { + m_fAudioOnly = false; + } + } + } + } + + if (m_fShockwaveGraph) { + m_fAudioOnly = false; + } + + 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_pVideoWnd->m_hWnd); + + for (CWnd* pWnd = m_pVideoWnd->GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) { + // 1. lets WM_SETCURSOR through (not needed as of now) + // 2. allows CMouse::CursorOnWindow() to work with m_pVideoWnd + pWnd->EnableWindow(FALSE); + } + + if (m_bUseSeekPreview) { + m_pVW_preview->put_Owner((OAHWND)m_wndPreView.GetVideoHWND()); + m_pVW_preview->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); + } + + if (m_fAudioOnly) { + if (HasDedicatedFSVideoWindow() && !AfxGetAppSettings().bFullscreenSeparateControls) { //DedicateFSWindow allowed for audio + m_pDedicatedFSVideoWnd->DestroyWindow(); + } + } else { + m_statusbarVideoSize.Format(_T("%dx%d"), vs.cx, vs.cy); + UpdateDXVAStatus(); + } +} + +// Called from GraphThread +void CMainFrame::OpenSetupAudio() +{ + m_pBA->put_Volume(m_wndToolBar.Volume); + + // FIXME + int balance = AfxGetAppSettings().nBalance; + + int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channel + if (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); +} + +void CMainFrame::OpenSetupCaptureBar() +{ + if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + if (m_pVidCap && m_pAMVSCCap) { + CComQIPtr pVfwCD = m_pVidCap; + + if (!m_pAMXBar && pVfwCD) { + m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, m_pAMVSCCap, pVfwCD); + } else { + m_wndCaptureBar.m_capdlg.SetupVideoControls(m_VidDispName, m_pAMVSCCap, m_pAMXBar, m_pAMTuner); + } + } + + if (m_pAudCap && m_pAMASC) { + CInterfaceArray pAMAIM; + + BeginEnumPins(m_pAudCap, pEP, pPin) { + if (CComQIPtr pAIM = pPin) { + pAMAIM.Add(pAIM); + } + } + EndEnumPins; + + m_wndCaptureBar.m_capdlg.SetupAudioControls(m_AudDispName, m_pAMASC, pAMAIM); + } + + BuildGraphVideoAudio( + m_wndCaptureBar.m_capdlg.m_fVidPreview, false, + m_wndCaptureBar.m_capdlg.m_fAudPreview, false); + } +} + +void CMainFrame::OpenSetupInfoBar(bool bClear /*= true*/) +{ + bool bRecalcLayout = false; + + if (bClear) { + m_wndInfoBar.RemoveAllLines(); + } + + if (GetPlaybackMode() == PM_FILE) { + CComBSTR bstr; + CString title, author, copyright, rating, description; + if (m_pAMMC[0]) { + for (const auto& pAMMC : m_pAMMC) { + if (pAMMC) { + if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { + title = bstr.m_str; + title.Trim(); + } + bstr.Empty(); + if (SUCCEEDED(pAMMC->get_AuthorName(&bstr)) && bstr.Length()) { + author = bstr.m_str; + } + bstr.Empty(); + if (SUCCEEDED(pAMMC->get_Copyright(&bstr)) && bstr.Length()) { + copyright = bstr.m_str; + } + bstr.Empty(); + if (SUCCEEDED(pAMMC->get_Rating(&bstr)) && bstr.Length()) { + rating = bstr.m_str; + } + bstr.Empty(); + if (SUCCEEDED(pAMMC->get_Description(&bstr)) && bstr.Length()) { + description = bstr.m_str; + } + bstr.Empty(); + } + } + } + + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TITLE), title); + UpdateChapterInInfoBar(); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUTHOR), author); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_COPYRIGHT), copyright); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_RATING), rating); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); + } else if (GetPlaybackMode() == PM_DVD) { + CString info(_T('-')); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DOMAIN), info); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_LOCATION), info); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_VIDEO), info); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_AUDIO), info); + bRecalcLayout |= m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_SUBTITLES), info); + } + + if (bRecalcLayout) { + RecalcLayout(); + } +} + +void CMainFrame::UpdateChapterInInfoBar() +{ + CString chapter; + if (m_pCB) { + DWORD dwChapCount = m_pCB->ChapGetCount(); + if (dwChapCount) { + REFERENCE_TIME rtNow; + m_pMS->GetCurrentPosition(&rtNow); + + if (m_pCB) { + CComBSTR bstr; + long currentChap = m_pCB->ChapLookup(&rtNow, &bstr); + if (bstr.Length()) { + chapter.Format(_T("%s (%ld/%lu)"), bstr.m_str, std::max(0l, currentChap + 1l), dwChapCount); + } else { + chapter.Format(_T("%ld/%lu"), currentChap + 1, dwChapCount); + } + } + } + } + if (m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CHAPTER), chapter)) { + RecalcLayout(); + } +} + +void CMainFrame::OpenSetupStatsBar() +{ + m_wndStatsBar.RemoveAllLines(); + + if (GetLoadState() == MLS::LOADED) { + CString info(_T('-')); + bool bFoundIBitRateInfo = false; + + BeginEnumFilters(m_pGB, pEF, pBF) { + if (!m_pQP) { + m_pQP = pBF; + } + if (!m_pBI) { + m_pBI = pBF; + } + if (!bFoundIBitRateInfo) { + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pBRI = pPin) { + bFoundIBitRateInfo = true; + break; + } + } + EndEnumPins; + } + if (m_pQP && m_pBI && bFoundIBitRateInfo) { + break; + } + } + EndEnumFilters; + + if (m_pQP) { + m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMERATE), info); + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SYNC_OFFSET), info); + m_wndStatsBar.SetLine(StrRes(IDS_AG_FRAMES), info); + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_JITTER), info); + } else { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_PLAYBACK_RATE), info); + } + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_SIGNAL), info); + } + if (m_pBI) { + m_wndStatsBar.SetLine(StrRes(IDS_AG_BUFFERS), info); + } + if (bFoundIBitRateInfo) { + m_wndStatsBar.SetLine(StrRes(IDS_STATSBAR_BITRATE), info); + } + } +} + +void CMainFrame::CheckSelectedAudioStream() +{ + int nChannels = 0; + int audiostreamcount = 0; + UINT audiobitmapid = IDB_AUDIOTYPE_NOAUDIO; + m_loadedAudioTrackIndex = -1; + + if (m_pAudioSwitcherSS) { + DWORD cStreams = 0; + if (SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { + LCID lcid = 0; + DWORD dwFlags, dwGroup; + AM_MEDIA_TYPE* pmt = nullptr; + for (DWORD i = 0; i < cStreams; i++) { + if (SUCCEEDED(m_pAudioSwitcherSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 1) { + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + m_loadedAudioTrackIndex = audiostreamcount; + nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + audiostreamcount++; + } + DeleteMediaType(pmt); + } + } + } + } + if (audiostreamcount == 0 && m_pSplitterSS) { + DWORD cStreams = 0; + if (SUCCEEDED(m_pSplitterSS->Count(&cStreams)) && cStreams > 0) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + for (DWORD i = 0; i < cStreams; i++) { + if (SUCCEEDED(m_pSplitterSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 1) { + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + m_loadedAudioTrackIndex = audiostreamcount; + nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + audiostreamcount++; + } + DeleteMediaType(pmt); + } + } + } + } + if (audiostreamcount == 0 && m_pSplitterDubSS) { + DWORD cStreams = 0; + if (SUCCEEDED(m_pSplitterDubSS->Count(&cStreams)) && cStreams > 0) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + for (DWORD i = 0; i < cStreams; i++) { + if (SUCCEEDED(m_pSplitterDubSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 1) { + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + m_loadedAudioTrackIndex = audiostreamcount; + nChannels = UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + audiostreamcount++; + } + DeleteMediaType(pmt); + } + } + } + } + if (audiostreamcount == 0 && !m_pAudioSwitcherSS) { // Fallback + BeginEnumFilters(m_pGB, pEF, pBF) { + CComQIPtr pBA = pBF; // implemented by audio renderers + bool notrenderer = false; + + BeginEnumPins(pBF, pEP, pPin) { + if (S_OK == m_pGB->IsPinDirection(pPin, PINDIR_INPUT) && S_OK == m_pGB->IsPinConnected(pPin)) { + AM_MEDIA_TYPE mt; + if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (mt.majortype == MEDIATYPE_Audio) { + notrenderer = !pBA; + audiostreamcount = 1; + nChannels = UpdateSelectedAudioStreamInfo(-1, &mt, -1); + break; + } else if (mt.majortype == MEDIATYPE_Midi) { + notrenderer = true; + audiostreamcount = 1; + nChannels = UpdateSelectedAudioStreamInfo(-1, &mt, -1); + break; + } + } + } + } + EndEnumPins; + + if (nChannels > 0 && notrenderer) { // prefer audio decoder above renderer + break; + } + } + EndEnumFilters; + } + + if (audiostreamcount == 0) { + m_loadedAudioTrackIndex = -1; + UpdateSelectedAudioStreamInfo(-1, nullptr, -1); + } + + if (nChannels >= 2) { + audiobitmapid = IDB_AUDIOTYPE_STEREO; + } else if (nChannels == 1) { + audiobitmapid = IDB_AUDIOTYPE_MONO; + } + m_wndStatusBar.SetStatusBitmap(audiobitmapid); +} + +void CMainFrame::OpenSetupStatusBar() +{ + m_wndStatusBar.ShowTimer(true); + + if (!m_fCustomGraph) { + CString fcc; + // Find video output pin of the source filter or splitter + BeginEnumFilters(m_pGB, pEF, pBF) { + CLSID clsid = GetCLSID(pBF); + bool splitter = (clsid == GUID_LAVSplitterSource || clsid == GUID_LAVSplitter); + // only process filters that might be splitters + if (splitter || clsid != __uuidof(CAudioSwitcherFilter) && clsid != GUID_LAVVideo && clsid != GUID_LAVAudio) { + int input_pins = 0; + BeginEnumPins(pBF, pEP, pPin) { + PIN_DIRECTION dir; + CMediaTypeEx mt; + if (SUCCEEDED(pPin->QueryDirection(&dir)) && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (dir == PINDIR_OUTPUT) { + if (mt.majortype == MEDIATYPE_Video) { + GetVideoFormatNameFromMediaType(mt.subtype, fcc); + if (splitter) { + break; + } + } + } else { + input_pins++; + splitter = (mt.majortype == MEDIATYPE_Stream); + } + } + } + EndEnumPins; + + if ((input_pins == 0 || splitter) && !fcc.IsEmpty()) { + break; + } + } + } + EndEnumFilters; + + if (!fcc.IsEmpty()) { + m_statusbarVideoFormat = fcc; + } + + CheckSelectedAudioStream(); + } +} + +// Called from GraphThread +void CMainFrame::OpenSetupWindowTitle(bool reset /*= false*/) +{ + CString title(StrRes(IDR_MAINFRAME)); +#ifdef MPCHC_LITE + title += _T(" Lite"); +#endif + + CAppSettings& s = AfxGetAppSettings(); + + int i = s.iTitleBarTextStyle; + + if (!reset && (i == 0 || i == 1)) { + // There is no path in capture mode + if (IsPlaybackCaptureMode()) { + title = GetCaptureTitle(); + } else if (i == 1) { // Show filename or title + if (GetPlaybackMode() == PM_FILE) { + title = getBestTitle(s.fTitleBarTextTitle); + bool has_title = !title.IsEmpty(); + + CStringW fn = GetFileName(); + + if (has_title && !IsNameSimilar(title, fn)) s.MRU.SetCurrentTitle(title); + + if (!has_title) { + title = fn; + } + } else if (GetPlaybackMode() == PM_DVD) { + title = _T("DVD"); + CString path; + ULONG len = 0; + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetDVDDirectory(path.GetBufferSetLength(MAX_PATH), MAX_PATH, &len)) && len) { + path.ReleaseBuffer(); + if (path.Find(_T("\\VIDEO_TS")) == 2) { + title.AppendFormat(_T(" - %s"), GetDriveLabel(CPath(path)).GetString()); + } + } + } + } else { // Show full path + if (GetPlaybackMode() == PM_FILE) { + title = m_wndPlaylistBar.GetCurFileNameTitle(); + } else if (GetPlaybackMode() == PM_DVD) { + title = _T("DVD"); + ULONG len = 0; + if (m_pDVDI) { + VERIFY(SUCCEEDED(m_pDVDI->GetDVDDirectory(title.GetBufferSetLength(MAX_PATH), MAX_PATH, &len))); + title.ReleaseBuffer(); + } + } + } + } + + SetWindowText(title); + m_Lcd.SetMediaTitle(title); +} + +// Called from GraphThread +int CMainFrame::SetupAudioStreams() +{ + bool bIsSplitter = false; + int desiredTrackIndex = m_loadedAudioTrackIndex; + m_loadedAudioTrackIndex = -1; + m_audioTrackCount = 0; + + CComQIPtr pSS = m_pAudioSwitcherSS; + if (!pSS) { + bIsSplitter = true; + pSS = m_pSplitterSS; + } + + DWORD cStreams = 0; + if (pSS && SUCCEEDED(pSS->Count(&cStreams))) { + if (cStreams > 1) { + const CAppSettings& s = AfxGetAppSettings(); + + CAtlArray langs; + int tPos = 0; + CString lang = s.strAudiosLanguageOrder.Tokenize(_T(",; "), tPos); + while (tPos != -1) { + lang.MakeLower(); + langs.Add(lang); + // Try to match the full language if possible + lang = ISOLang::ISO639XToLanguage(CStringA(lang)); + if (!lang.IsEmpty()) { + langs.Add(lang.MakeLower()); + } + lang = s.strAudiosLanguageOrder.Tokenize(_T(",; "), tPos); + } + + int selected = -1, id = 0; + int maxrating = -1; + for (DWORD i = 0; i < cStreams; i++) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + WCHAR* pName = nullptr; + CComPtr pObject; + if (FAILED(pSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pName, &pObject, nullptr))) { + continue; + } + CString name(pName); + CoTaskMemFree(pName); + + if (dwGroup != 1) { + ASSERT(bIsSplitter); + continue; + } + + m_audioTrackCount++; + + int rating = 0; + // If the track is controlled by a splitter and isn't selected at splitter level + if (!(dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE))) { + bool bSkipTrack; + + // If the splitter is the internal LAV Splitter and no language preferences + // have been set at splitter level, we can override its choice safely + CComQIPtr pBF = bIsSplitter ? pSS : reinterpret_cast(pObject.p); + if (pBF && CFGFilterLAV::IsInternalInstance(pBF)) { + bSkipTrack = false; + if (CComQIPtr pLAVFSettings = pBF) { + LPWSTR langPrefs = nullptr; + if (SUCCEEDED(pLAVFSettings->GetPreferredLanguages(&langPrefs)) && langPrefs && wcslen(langPrefs)) { + bSkipTrack = true; + } + CoTaskMemFree(langPrefs); + } + } else { + bSkipTrack = !s.bAllowOverridingExternalSplitterChoice; + } + + if (bSkipTrack) { + id++; + continue; + } + } else if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + // Give selected track a slightly higher rating + rating += 1; + // Get details of currently selected track + m_loadedAudioTrackIndex = m_audioTrackCount - 1; + UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + + DeleteMediaType(pmt); + + name.Trim(); + name.MakeLower(); + + for (size_t j = 0; j < langs.GetCount(); j++) { + int num = _tstoi(langs[j]) - 1; + if (num >= 0) { // this is track number + if (id != num) { + continue; // not matched + } + } else { // this is lang string + int len = langs[j].GetLength(); + if (name.Left(len) != langs[j] && name.Find(_T("[") + langs[j]) < 0) { + continue; // not matched + } + } + rating += 16 * int(langs.GetCount() - j); + break; + } + if (name.Find(_T("[default,forced]")) != -1) { // for LAV Splitter + rating += 4 + 2; + } + if (name.Find(_T("[forced]")) != -1) { + rating += 4; + } + if (name.Find(_T("[default]")) != -1) { + rating += 2; + } + + if (rating > maxrating) { + maxrating = rating; + selected = id; + } + + id++; + } + + if (desiredTrackIndex >= 0 && desiredTrackIndex < m_audioTrackCount) { + selected = desiredTrackIndex; + } + return m_audioTrackCount > 1 ? selected + !bIsSplitter : -1; + } else if (cStreams == 1) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pSS->Info(0, &pmt, &dwFlags, &lcid, &dwGroup, nullptr, nullptr, nullptr))) { + if (dwGroup == 1 && (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE))) { + m_loadedAudioTrackIndex = 0; + m_audioTrackCount = 1; + UpdateSelectedAudioStreamInfo(m_loadedAudioTrackIndex, pmt, lcid); + } + DeleteMediaType(pmt); + return -1; // no need to select a specific track + } + } + } + + return -1; +} + +bool MatchSubtrackWithISOLang(CString& tname, const ISOLangT& l) +{ + int p; + + if (!l.iso6392.IsEmpty()) { + p = tname.Find(_T("[") + l.iso6392 + _T("]")); + if (p > 0) { + return true; + } + p = tname.Find(_T(".") + l.iso6392 + _T(".")); + if (p > 0) { + return true; + } + } + + if (!l.iso6391.IsEmpty()) { + p = tname.Find(_T("[") + l.iso6391 + _T("]")); + if (p > 0) { + return true; + } + p = tname.Find(_T(".") + l.iso6391 + _T(".")); + if (p > 0) { + return true; + } + p = tname.Find(_T("[") + l.iso6391 + _T("-]")); // truncated BCP47 + if (p > 0) { + return true; + } + } + + if (!l.name.IsEmpty()) { + if (l.name == _T("off")) { + return tname.Find(_T("no subtitles")) >= 0; + } + + std::list langlist; + int tPos = 0; + CString lang = l.name.Tokenize(_T(";"), tPos); + while (tPos != -1) { + lang.MakeLower().TrimLeft(); + langlist.emplace_back(lang); + lang = l.name.Tokenize(_T(";"), tPos); + } + + for (auto& substr : langlist) { + p = tname.Find(_T("\t") + substr); + if (p > 0) { + return true; + } + p = tname.Find(_T(".") + substr + _T(".")); + if (p > 0) { + return true; + } + p = tname.Find(_T("[") + substr + _T("]")); + if (p > 0) { + return true; + } + p = tname.Find(substr); + if (p == 0 || p == 3 && tname.Left(3) == _T("s: ")) { // at begin of trackname + return true; + } + } + } + + return false; +} + +// Called from GraphThread +int CMainFrame::SetupSubtitleStreams() +{ + const CAppSettings& s = AfxGetAppSettings(); + + int selected = -1; + + if (!m_pSubStreams.IsEmpty()) { + bool is_external = false; + bool externalPriority = false; + bool has_off_lang = false; + std::list> langs; + int tPos = 0; + CString lang = s.strSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); + while (tPos != -1) { + lang.MakeLower(); + ISOLangT l = ISOLangT(lang, L"", L"", 0); + + if (lang == _T("off")) { + has_off_lang = true; + } else if (lang.Find(L'-') == 2) { + // BCP 47 + } else { + l = ISOLang::ISO639XToISOLang(CStringA(lang)); + if (l.name.IsEmpty()) { // not an ISO code + l.name = lang; + } else { + l.name.MakeLower(); + } + } + + langs.emplace_back(l); + + lang = s.strSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); + } + + int i = 0; + int subcount = m_pSubStreams.GetSize(); + int maxrating = 0; + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + if (m_posFirstExtSub == pos) { + is_external = true; + externalPriority = s.fPrioritizeExternalSubtitles; + } + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + CComPtr pSubStream = subInput.pSubStream; + CComQIPtr pSSF = subInput.pSourceFilter; + + bool bAllowOverridingSplitterChoice; + // If the internal LAV Splitter has its own language preferences set, we choose not to override its choice + if (pSSF && CFGFilterLAV::IsInternalInstance(subInput.pSourceFilter)) { + bAllowOverridingSplitterChoice = true; + if (CComQIPtr pLAVFSettings = subInput.pSourceFilter) { + CComHeapPtr pLangPrefs; + LAVSubtitleMode subtitleMode = pLAVFSettings->GetSubtitleMode(); + if ((((subtitleMode == LAVSubtitleMode_Default && SUCCEEDED(pLAVFSettings->GetPreferredSubtitleLanguages(&pLangPrefs))) + || (subtitleMode == LAVSubtitleMode_Advanced && SUCCEEDED(pLAVFSettings->GetAdvancedSubtitleConfig(&pLangPrefs)))) + && pLangPrefs && wcslen(pLangPrefs)) + || subtitleMode == LAVSubtitleMode_ForcedOnly || subtitleMode == LAVSubtitleMode_NoSubs) { + bAllowOverridingSplitterChoice = false; + } + } + } else { + bAllowOverridingSplitterChoice = s.bAllowOverridingExternalSplitterChoice; + } + + int count = 0; + if (pSSF) { + DWORD cStreams; + if (SUCCEEDED(pSSF->Count(&cStreams))) { + count = (int)cStreams; + } + } else { + count = pSubStream->GetStreamCount(); + } + + for (int j = 0; j < count; j++) { + CComHeapPtr pName; + LCID lcid = 0; + int rating = 0; + if (pSSF) { + DWORD dwFlags, dwGroup = 2; + pSSF->Info(j, nullptr, &dwFlags, &lcid, &dwGroup, &pName, nullptr, nullptr); + if (dwGroup != 2) { // If the track isn't a subtitle track, we skip it + continue; + } else if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + // Give slightly higher priority to the track selected by splitter so that + // we won't override selected track in case all have the same rating. + rating += 1; + } else if (!bAllowOverridingSplitterChoice) { + // If we aren't allowed to modify the splitter choice and the current + // track isn't already selected at splitter level we need to skip it. + i++; + continue; + } + } else { + pSubStream->GetStreamInfo(j, &pName, &lcid); + } + CString name(pName); + name.Trim(); + name.MakeLower(); + + size_t k = 0; + for (const auto& l : langs) { + int num = _tstoi(l.name) - 1; + if (num >= 0) { // this is track number + if (i != num) { + k++; + continue; // not matched + } + } else { // this is lang string + if (lcid == 0 || lcid == LCID(-1) || lcid != l.lcid) { + // no LCID match, analyze track name for language match + if (!MatchSubtrackWithISOLang(name, l)) { + k++; + continue; // not matched + } + } + // LCID match + } + rating += 16 * int(langs.size() - k); + break; + } + + if (is_external) { + if (rating > 0) { + if (externalPriority) { + rating += 16 * int(langs.size() + 1); + } + } else { + if (langs.size() == 0 || name.Find(_T("\t")) == -1) { + // no preferred language or unknown sub language + if (externalPriority) { + rating += 16 * int(langs.size() + 1); + } else { + rating = 1; + } + } + } + } else { + if (s.bPreferDefaultForcedSubtitles) { + if (name.Find(_T("[default,forced]")) != -1) { // for LAV Splitter + rating += 4 + 2; + } + if (name.Find(_T("[forced]")) != -1) { + rating += 2; + } + if (name.Find(_T("[default]")) != -1) { + rating += 4; + } + } +#if 0 + if (rating == 0 && bAllowOverridingSplitterChoice && langs.size() == 0) { + // use first embedded track as fallback if there is no preferred language + rating = 1; + } +#endif + } + + if (rating > maxrating) { + maxrating = rating; + selected = i; + } + i++; + } + } + } + + if (s.IsISRAutoLoadEnabled() && !m_fAudioOnly) { + if (s.bAutoDownloadSubtitles && m_pSubStreams.IsEmpty()) { + m_pSubtitlesProviders->Search(TRUE); + } else if (m_wndSubtitlesDownloadDialog.IsWindowVisible()) { + m_pSubtitlesProviders->Search(FALSE); + } + } + + return selected; +} + +bool CMainFrame::OpenMediaPrivate(CAutoPtr pOMD) +{ + ASSERT(GetLoadState() == MLS::LOADING); + auto& s = AfxGetAppSettings(); + + m_fValidDVDOpen = false; + m_iDefRotation = 0; + + OpenFileData* pFileData = dynamic_cast(pOMD.m_p); + OpenDVDData* pDVDData = dynamic_cast(pOMD.m_p); + OpenDeviceData* pDeviceData = dynamic_cast(pOMD.m_p); + ASSERT(pFileData || pDVDData || pDeviceData); + + m_pCAP3 = nullptr; + m_pCAP2 = nullptr; + m_pCAP = nullptr; + m_pVMRWC = nullptr; + m_pVMRMC = nullptr; + m_pMFVDC = nullptr; + m_pVMB = nullptr; + m_pMFVMB = nullptr; + m_pMFVP = nullptr; + m_pMVRC = nullptr; + m_pMVRI = nullptr; + m_pMVRS = nullptr; + m_pMVRSR = nullptr; + m_pMVRFG = nullptr; + m_pMVTO = nullptr; + m_pD3DFSC = nullptr; + m_pLN21 = nullptr; + m_pCAP2_preview = nullptr; + m_pMFVDC_preview = nullptr; + m_pMFVP_preview = nullptr; + m_pVMR9C_preview = nullptr; + +#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[%u]:\n"), index); + TRACE(_T("\t%ws\n"), path.GetString()); // %ws - wide character string always + index++; + } + } + // Debug trace code - End +#endif + + CString err; + try { + auto checkAborted = [&]() { + if (m_fOpeningAborted) { + throw (UINT)IDS_AG_ABORTED; + } + }; + + OpenCreateGraphObject(pOMD); + checkAborted(); + + if (pFileData) { + OpenFile(pFileData); + } else if (pDVDData) { + 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; + } + + if (!m_pGB) { + throw (UINT)IDS_MAINFRM_88; + } + + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP2), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP3), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRWC), FALSE); // might have IVMRMixerBitmap9, but not IVMRWindowlessControl9 + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRMC), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMB), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVMB), TRUE); + + m_pMVRC = m_pCAP; + m_pMVRI = m_pCAP; + m_pMVRS = m_pCAP; + m_pMVRSR = m_pCAP; + m_pMVRFG = m_pCAP; + m_pMVTO = m_pCAP; + m_pD3DFSC = m_pCAP; + + checkAborted(); + + SetupVMR9ColorControl(); + checkAborted(); + + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVDC), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVP), TRUE); + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } + + // COMMENTED OUT: does not work at this location, need to choose the correct mode (IMFVideoProcessor::SetVideoProcessorMode) + //SetupEVRColorControl(); + + if (m_bUseSeekPreview) { + m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pMFVDC_preview), TRUE); + m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pMFVP_preview), TRUE); + m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pVMR9C_preview), TRUE); + m_pGB_preview->FindInterface(IID_PPV_ARGS(&m_pCAP2_preview), TRUE); + + RECT wr; + m_wndPreView.GetVideoRect(&wr); + if (m_pMFVDC_preview) { + m_pMFVDC_preview->SetVideoWindow(m_wndPreView.GetVideoHWND()); + m_pMFVDC_preview->SetVideoPosition(nullptr, &wr); + } + if (m_pCAP2_preview) { + m_pCAP2_preview->SetPosition(wr, wr); + } + } + + if (m_pLN21) { + m_pLN21->SetServiceState(s.fClosedCaptions ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off); + } + + checkAborted(); + + OpenCustomizeGraph(); + checkAborted(); + + OpenSetupVideo(); + checkAborted(); + + if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is used + m_OSD.Stop(); + + if (m_pMVTO) { + m_OSD.Start(m_pVideoWnd, m_pMVTO); + } else if (m_fFullScreen && !m_fAudioOnly && m_pCAP3) { // MPCVR + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); + } else if (!m_fAudioOnly && IsD3DFullScreenMode() && (m_pVMB || m_pMFVMB)) { + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); + } else { + m_OSD.Start(m_pOSDWnd); + } + } + + OpenSetupAudio(); + checkAborted(); + + if (GetPlaybackMode() == PM_FILE && pFileData) { + const CString& fn = pFileData->fns.GetHead(); + // Don't try to save file position if source isn't seekable + REFERENCE_TIME rtPos = 0; + REFERENCE_TIME rtDur = 0; + m_loadedAudioTrackIndex = -1; + m_loadedSubtitleTrackIndex = -1; + + if (m_pMS) { + m_pMS->GetDuration(&rtDur); + } + + m_bRememberFilePos = s.fKeepHistory && s.fRememberFilePos && rtDur > (s.iRememberPosForLongerThan * 10000000i64 * 60i64) && (s.bRememberPosForAudioFiles || !m_fAudioOnly); + + // Set start time but seek only after all files are loaded + if (pFileData->rtStart > 0) { // Check if an explicit start time was given + rtPos = pFileData->rtStart; + } + if (pFileData->abRepeat) { // Check if an explicit a/b repeat time was given + abRepeat = pFileData->abRepeat; + } + + if (m_dwReloadPos > 0) { + if (m_dwReloadPos < rtDur) { + rtPos = m_dwReloadPos; + } + m_dwReloadPos = 0; + } + if (reloadABRepeat) { + abRepeat = reloadABRepeat; + reloadABRepeat = ABRepeat(); + } + + auto* pMRU = &AfxGetAppSettings().MRU; + if (pMRU->rfe_array.GetCount()) { + if (!rtPos && m_bRememberFilePos) { + rtPos = pMRU->GetCurrentFilePosition(); + if (rtPos >= rtDur || rtDur - rtPos < 50000000LL) { + rtPos = 0; + } + } + if (!abRepeat && s.fKeepHistory && s.fRememberFilePos) { + abRepeat = pMRU->GetCurrentABRepeat(); + } + if (s.fKeepHistory && s.bRememberTrackSelection) { + if (m_loadedAudioTrackIndex == -1) { + m_loadedAudioTrackIndex = pMRU->GetCurrentAudioTrack(); + } + if (m_loadedSubtitleTrackIndex == -1) { + m_loadedSubtitleTrackIndex = pMRU->GetCurrentSubtitleTrack(); + } + } + } + + if (abRepeat && abRepeat.positionB > 0) { + // validate + if (abRepeat.positionB > rtDur || abRepeat.positionA >= abRepeat.positionB) { + abRepeat = ABRepeat(); + } + } + if (abRepeat) { + m_wndSeekBar.Invalidate(); + } + + if (rtPos && rtDur) { + m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + + defaultVideoAngle = 0; + if (m_pFSF && (m_pCAP2 || m_pCAP3)) { + CComQIPtr pBF = m_pFSF; + if (GetCLSID(pBF) == GUID_LAVSplitter || GetCLSID(pBF) == GUID_LAVSplitterSource) { + if (CComQIPtr pPB = pBF) { + CComVariant var; + if (SUCCEEDED(pPB->Read(_T("rotation"), &var, nullptr)) && var.vt == VT_BSTR) { + int rotatevalue = _wtoi(var.bstrVal); + if (rotatevalue == 90 || rotatevalue == 180 || rotatevalue == 270) { + m_iDefRotation = rotatevalue; + if (m_pCAP3) { + m_pCAP3->SetRotation(rotatevalue); + } else { + m_pCAP2->SetDefaultVideoAngle(Vector(0, 0, Vector::DegToRad(360 - rotatevalue))); + } + if (m_pCAP2_preview) { + defaultVideoAngle = 360 - rotatevalue; + m_pCAP2_preview->SetDefaultVideoAngle(Vector(0, 0, Vector::DegToRad(defaultVideoAngle))); + } + } + } + var.Clear(); + } + } + } + } + checkAborted(); + + if (m_pCAP && s.IsISRAutoLoadEnabled() && !m_fAudioOnly) { + if (s.fDisableInternalSubtitles) { + m_pSubStreams.RemoveAll(); // Needs to be replaced with code that checks for forced subtitles. + } + m_posFirstExtSub = nullptr; + if (!pOMD->subs.IsEmpty()) { + POSITION pos = pOMD->subs.GetHeadPosition(); + while (pos) { + LoadSubtitle(pOMD->subs.GetNext(pos), nullptr, true); + } + } + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli) && pli.m_bYoutubeDL && !s.sYDLSubsPreference.IsEmpty()) { + POSITION pos2 = pli.m_ydl_subs.GetHeadPosition(); + while (pos2) { + CYoutubeDLInstance::YDLSubInfo ydlsub = pli.m_ydl_subs.GetNext(pos2); + if (!ydlsub.isAutomaticCaptions || s.bUseAutomaticCaptions) { + LoadSubtitle(ydlsub); + } + } + } + } + checkAborted(); + + OpenSetupWindowTitle(); + checkAborted(); + + int audstm; // offset in audio track menu, AudioSwitcher adds an "Options" entry above the audio tracks + audstm = SetupAudioStreams(); + if (audstm >= 0) { + OnPlayAudio(ID_AUDIO_SUBITEM_START + audstm); + } + checkAborted(); + + int substm; + if (m_loadedSubtitleTrackIndex >= 0 && IsValidSubtitleStream(m_loadedSubtitleTrackIndex)) { + substm = m_loadedSubtitleTrackIndex; + } else { + substm = SetupSubtitleStreams(); + } + if (substm >= 0) { + SetSubtitle(substm); + } + checkAborted(); + + // apply /dubdelay command-line switch + // TODO: that command-line switch probably needs revision + if (s.rtShift != 0) { + SetAudioDelay(s.rtShift); + s.rtShift = 0; + } + } catch (LPCTSTR msg) { + err = msg; + } catch (CString& msg) { + err = msg; + } catch (UINT msg) { + err.LoadString(msg); + } + + if (m_bUseSeekPreview && m_pMC_preview) { + m_pMC_preview->Pause(); + } + + m_closingmsg = err; + + auto getMessageArgs = [&]() { + WPARAM wp = pFileData ? PM_FILE : pDVDData ? PM_DVD : pDeviceData ? (s.iDefaultCaptureDevice == 1 ? PM_DIGITAL_CAPTURE : PM_ANALOG_CAPTURE) : PM_NONE; + ASSERT(wp != PM_NONE); + LPARAM lp = (LPARAM)pOMD.Detach(); + ASSERT(lp); + return std::make_pair(wp, lp); + }; + if (err.IsEmpty()) { + auto args = getMessageArgs(); + if (!m_bOpenedThroughThread) { + ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); + OnFilePostOpenmedia(args.first, args.second); + } else { + PostMessage(WM_POSTOPEN, args.first, args.second); + } + } else if (!m_fOpeningAborted) { + auto args = getMessageArgs(); + if (!m_bOpenedThroughThread) { + ASSERT(GetCurrentThreadId() == AfxGetApp()->m_nThreadID); + OnOpenMediaFailed(args.first, args.second); + } else { + PostMessage(WM_OPENFAILED, args.first, args.second); + } + } + + return err.IsEmpty(); +} + +void CMainFrame::CloseMediaPrivate() +{ + ASSERT(GetLoadState() == MLS::CLOSING); + + MediaControlStop(true); // needed for StreamBufferSource, because m_iMediaLoadState is always MLS::CLOSED // TODO: fix the opening for such media + m_CachedFilterState = -1; + + m_fLiveWM = false; + m_fEndOfStream = false; + m_bBuffering = false; + m_rtDurationOverride = -1; + m_bUsingDXVA = false; + m_audioTrackCount = 0; + if (m_pDVBState) { + m_pDVBState->Join(); + m_pDVBState = nullptr; + } + m_pCB.Release(); + + { + CAutoLock cAutoLock(&m_csSubLock); + m_pCurrentSubInput = SubtitleInput(nullptr); + m_pSubStreams.RemoveAll(); + m_ExternalSubstreams.clear(); + } + m_pSubClock.Release(); + + if (m_pVW && !m_pMVRS) { + m_pVW->put_Owner(NULL); + } + + m_bIsMPCVRExclusiveMode = false; + + // IMPORTANT: IVMRSurfaceAllocatorNotify/IVMRSurfaceAllocatorNotify9 has to be released before the VMR/VMR9, otherwise it will crash in Release() + m_OSD.Stop(); + m_pMVRFG.Release(); + m_pMVRSR.Release(); + m_pMVRS.Release(); + m_pMVRC.Release(); + m_pMVRI.Release(); + m_pMVTO.Release(); + m_pD3DFSC.Release(); + m_pCAP3.Release(); + m_pCAP2.Release(); + m_pCAP.Release(); + m_pVMRWC.Release(); + m_pVMRMC.Release(); + m_pVMB.Release(); + m_pMFVMB.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(); + m_pFSF.Release(); + m_pKFI.Release(); + m_pAMNS.Release(); + m_pDVS.Release(); + m_pDVS2.Release(); + for (auto& pAMMC : m_pAMMC) { + pAMMC.Release(); + } + m_pAudioSwitcherSS.Release(); + m_pSplitterSS.Release(); + m_pSplitterDubSS.Release(); + for (auto& pSS : m_pOtherSS) { + pSS.Release(); + } + + if (m_pGB) { + m_pGB->RemoveFromROT(); + m_pGB.Release(); + } + + if (m_pGB_preview) { + TRACE(_T("Stopping preview graph\n")); + MediaControlStopPreview(); + TRACE(_T("Releasing preview graph\n")); + ReleasePreviewGraph(); + } + + m_pProv.Release(); + + m_fCustomGraph = m_fShockwaveGraph = false; + + m_lastOMD.Free(); + + m_FontInstaller.UninstallFonts(); +} + +bool CMainFrame::WildcardFileSearch(CString searchstr, std::set& results, bool recurse_dirs) +{ + ExtendMaxPathLengthIfNeeded(searchstr); + + CString path = searchstr; + path.Replace('/', '\\'); + int p = path.ReverseFind('\\'); + if (p < 0) return false; + path = path.Left(p + 1); + + WIN32_FIND_DATA findData; + ZeroMemory(&findData, sizeof(WIN32_FIND_DATA)); + HANDLE h = FindFirstFile(searchstr, &findData); + if (h != INVALID_HANDLE_VALUE) { + CString search_ext = searchstr.Mid(searchstr.ReverseFind('.')).MakeLower(); + bool other_ext = (search_ext != _T(".*")); + CStringW curExt = CPath(m_wndPlaylistBar.GetCurFileName()).GetExtension().MakeLower(); + + do { + CString filename = findData.cFileName; + + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (recurse_dirs && search_ext == L".*" && filename != L"." && filename != L"..") { + WildcardFileSearch(path + filename + L"\\*.*", results, true); + } + continue; + } + + CString ext = filename.Mid(filename.ReverseFind('.')).MakeLower(); + + if (CanSkipToExt(ext, curExt)) { + /* playlist and cue files should be ignored when searching dir for playable files */ + if (!IsPlaylistFileExt(ext)) { + results.insert(path + filename); + } + } else if (other_ext && search_ext == ext) { + results.insert(path + filename); + if (ext == _T(".rar")) { + break; + } + } + } while (FindNextFile(h, &findData)); + + FindClose(h); + } + + return results.size() > 0; +} + +bool CMainFrame::SearchInDir(bool bDirForward, bool bLoop /*= false*/) +{ + ASSERT(GetPlaybackMode() == PM_FILE || CanSkipFromClosedFile()); + + CString filename; + + auto pFileData = dynamic_cast(m_lastOMD.m_p); + if (!pFileData || !pFileData->title || pFileData->title.IsEmpty()) { + if (CanSkipFromClosedFile()) { + if (m_wndPlaylistBar.GetCount() == 1) { + filename = m_wndPlaylistBar.m_pl.GetHead().m_fns.GetHead(); + } else { + filename = lastOpenFile; + } + } else { + ASSERT(FALSE); + return false; + } + } else { + filename = pFileData->title; + } + + if (PathUtils::IsURL(filename)) { + return false; + } + + int p = filename.ReverseFind(_T('\\')); + if (p < 0) { + return false; + } + CString filemask = filename.Left(p + 1) + _T("*.*"); + std::set filelist; + if (!WildcardFileSearch(filemask, filelist, false)) { + return false; + } + + // We make sure that the currently opened file is added to the list + // even if it's of an unknown format. + auto current = filelist.insert(filename).first; + + if (filelist.size() < 2 && CPath(filename).FileExists()) { + return false; + } + + if (bDirForward) { + current++; + if (current == filelist.end()) { + if (bLoop) { + current = filelist.begin(); + } else { + return false; + } + } + } else { + if (current == filelist.begin()) { + if (bLoop) { + current = filelist.end(); + } else { + return false; + } + } + current--; + } + + CAtlList sl; + sl.AddHead(*current); + m_wndPlaylistBar.Open(sl, false); + OpenCurPlaylistItem(); + + return true; +} + +void CMainFrame::DoTunerScan(TunerScanData* pTSD) +{ + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + CComQIPtr pTun = m_pGB; + if (pTun) { + bool wasStopped = false; + if (GetMediaState() == State_Stopped) { + SetChannel(-1); + MediaControlRun(); + wasStopped = true; + } + + BOOLEAN bPresent; + BOOLEAN bLocked; + LONG lDbStrength = 0; + LONG lPercentQuality = 0; + int nOffset = pTSD->Offset ? 3 : 1; + LONG lOffsets[3] = {0, pTSD->Offset, -pTSD->Offset}; + m_bStopTunerScan = false; + pTun->Scan(0, 0, 0, NULL); // Clear maps + + for (ULONG ulFrequency = pTSD->FrequencyStart; ulFrequency <= pTSD->FrequencyStop; ulFrequency += pTSD->Bandwidth) { + bool bSucceeded = false; + for (int nOffsetPos = 0; nOffsetPos < nOffset && !bSucceeded; nOffsetPos++) { + if (SUCCEEDED(pTun->SetFrequency(ulFrequency + lOffsets[nOffsetPos], pTSD->Bandwidth, pTSD->SymbolRate))) { + Sleep(200); // Let the tuner some time to detect the signal + if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) { + ::SendMessage(pTSD->Hwnd, WM_TUNER_STATS, lDbStrength, lPercentQuality); + pTun->Scan(ulFrequency + lOffsets[nOffsetPos], pTSD->Bandwidth, pTSD->SymbolRate, pTSD->Hwnd); + bSucceeded = true; + } + } + } + + int nProgress = MulDiv(ulFrequency - pTSD->FrequencyStart, 100, pTSD->FrequencyStop - pTSD->FrequencyStart); + ::SendMessage(pTSD->Hwnd, WM_TUNER_SCAN_PROGRESS, nProgress, 0); + ::SendMessage(pTSD->Hwnd, WM_TUNER_STATS, lDbStrength, lPercentQuality); + + if (m_bStopTunerScan) { + break; + } + } + + ::SendMessage(pTSD->Hwnd, WM_TUNER_SCAN_END, 0, 0); + if (wasStopped) { + SetChannel(AfxGetAppSettings().nDVBLastChannel); + MediaControlStop(); + } + } + } +} + +// Skype + +void CMainFrame::SendNowPlayingToSkype() +{ + if (!m_pSkypeMoodMsgHandler) { + return; + } + + CString msg; + + if (GetLoadState() == MLS::LOADED) { + CString title, author; + + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_TITLE), title); + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); + + if (title.IsEmpty()) { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + CString label = !pli.m_label.IsEmpty() ? pli.m_label : pli.m_fns.GetHead(); + + if (GetPlaybackMode() == PM_FILE) { + CString fn = label; + if (!pli.m_bYoutubeDL && PathUtils::IsURL(fn)) { + int i = fn.Find('?'); + if (i >= 0) { + fn = fn.Left(i); + } + } + CPath path(fn); + path.StripPath(); + path.MakePretty(); + path.RemoveExtension(); + title = (LPCTSTR)path; + author.Empty(); + } else if (IsPlaybackCaptureMode()) { + title = GetCaptureTitle(); + author.Empty(); + } else if (GetPlaybackMode() == PM_DVD) { + title = _T("DVD"); + author.Empty(); + } + } + } + + if (!author.IsEmpty()) { + msg.Format(_T("%s - %s"), author.GetString(), title.GetString()); + } else { + msg = title; + } + } + + m_pSkypeMoodMsgHandler->SendMoodMessage(msg); +} + +// dynamic menus + +void CMainFrame::CreateDynamicMenus() +{ + VERIFY(m_openCDsMenu.CreatePopupMenu()); + VERIFY(m_filtersMenu.CreatePopupMenu()); + VERIFY(m_subtitlesMenu.CreatePopupMenu()); + VERIFY(m_audiosMenu.CreatePopupMenu()); + VERIFY(m_videoStreamsMenu.CreatePopupMenu()); + VERIFY(m_chaptersMenu.CreatePopupMenu()); + VERIFY(m_titlesMenu.CreatePopupMenu()); + VERIFY(m_playlistMenu.CreatePopupMenu()); + VERIFY(m_BDPlaylistMenu.CreatePopupMenu()); + VERIFY(m_channelsMenu.CreatePopupMenu()); + VERIFY(m_favoritesMenu.CreatePopupMenu()); + VERIFY(m_shadersMenu.CreatePopupMenu()); + VERIFY(m_recentFilesMenu.CreatePopupMenu()); +} + +void CMainFrame::DestroyDynamicMenus() +{ + VERIFY(m_openCDsMenu.DestroyMenu()); + VERIFY(m_filtersMenu.DestroyMenu()); + VERIFY(m_subtitlesMenu.DestroyMenu()); + VERIFY(m_audiosMenu.DestroyMenu()); + VERIFY(m_videoStreamsMenu.DestroyMenu()); + VERIFY(m_chaptersMenu.DestroyMenu()); + VERIFY(m_titlesMenu.DestroyMenu()); + VERIFY(m_playlistMenu.DestroyMenu()); + VERIFY(m_BDPlaylistMenu.DestroyMenu()); + VERIFY(m_channelsMenu.DestroyMenu()); + VERIFY(m_favoritesMenu.DestroyMenu()); + VERIFY(m_shadersMenu.DestroyMenu()); + VERIFY(m_recentFilesMenu.DestroyMenu()); + m_nJumpToSubMenusCount = 0; +} + +void CMainFrame::SetupOpenCDSubMenu() +{ + CMenu& subMenu = m_openCDsMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (GetLoadState() == MLS::LOADING || AfxGetAppSettings().fHideCDROMsSubMenu) { + return; + } + + UINT id = ID_FILE_OPEN_OPTICAL_DISK_START; + for (TCHAR drive = _T('A'); drive <= _T('Z'); drive++) { + CAtlList files; + OpticalDiskType_t opticalDiskType = GetOpticalDiskType(drive, files); + + if (opticalDiskType != OpticalDisk_NotFound && opticalDiskType != OpticalDisk_Unknown) { + CString label = GetDriveLabel(drive); + if (label.IsEmpty()) { + switch (opticalDiskType) { + case OpticalDisk_Audio: + label = _T("Audio CD"); + break; + case OpticalDisk_VideoCD: + label = _T("(S)VCD"); + break; + case OpticalDisk_DVDVideo: + label = _T("DVD Video"); + break; + case OpticalDisk_BD: + label = _T("Blu-ray Disc"); + break; + default: + ASSERT(FALSE); + break; + } + } + + CString str; + str.Format(_T("%s (%c:)"), label.GetString(), drive); + + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, str)); + } + } +} + +void CMainFrame::SetupFiltersSubMenu() +{ + CMPCThemeMenu& subMenu = m_filtersMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + m_pparray.RemoveAll(); + m_ssarray.RemoveAll(); + + if (GetLoadState() == MLS::LOADED) { + UINT idf = 1; //used as an id, so make non-zero to start + UINT ids = ID_FILTERS_SUBITEM_START; + UINT idl = ID_FILTERSTREAMS_SUBITEM_START; + + BeginEnumFilters(m_pGB, pEF, pBF) { + CString filterName(GetFilterName(pBF)); + if (filterName.GetLength() >= 43) { + filterName = filterName.Left(40) + _T("..."); + } + + CLSID clsid = GetCLSID(pBF); + if (clsid == CLSID_AVIDec) { + CComPtr pPin = GetFirstPin(pBF); + AM_MEDIA_TYPE mt; + if (pPin && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + DWORD c = ((VIDEOINFOHEADER*)mt.pbFormat)->bmiHeader.biCompression; + switch (c) { + case BI_RGB: + filterName += _T(" (RGB)"); + break; + case BI_RLE4: + filterName += _T(" (RLE4)"); + break; + case BI_RLE8: + filterName += _T(" (RLE8)"); + break; + case BI_BITFIELDS: + filterName += _T(" (BITF)"); + break; + default: + filterName.AppendFormat(_T(" (%c%c%c%c)"), + (TCHAR)((c >> 0) & 0xff), + (TCHAR)((c >> 8) & 0xff), + (TCHAR)((c >> 16) & 0xff), + (TCHAR)((c >> 24) & 0xff)); + break; + } + } + } else if (clsid == CLSID_ACMWrapper) { + CComPtr pPin = GetFirstPin(pBF); + AM_MEDIA_TYPE mt; + if (pPin && SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + WORD c = ((WAVEFORMATEX*)mt.pbFormat)->wFormatTag; + filterName.AppendFormat(_T(" (0x%04x)"), (int)c); + } + } else if (clsid == __uuidof(CTextPassThruFilter) + || clsid == __uuidof(CNullTextRenderer) + || clsid == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) { // ISCR + // hide these + continue; + } + + CMenu internalSubMenu; + VERIFY(internalSubMenu.CreatePopupMenu()); + + int nPPages = 0; + + CComQIPtr pSPP = pBF; + + m_pparray.Add(pBF); + VERIFY(internalSubMenu.AppendMenu(MF_STRING | MF_ENABLED, ids, ResStr(IDS_MAINFRM_116))); + + nPPages++; + + BeginEnumPins(pBF, pEP, pPin) { + CString pinName = GetPinName(pPin); + pinName.Replace(_T("&"), _T("&&")); + + if (pSPP = pPin) { + CAUUID caGUID; + caGUID.pElems = nullptr; + if (SUCCEEDED(pSPP->GetPages(&caGUID)) && caGUID.cElems > 0) { + m_pparray.Add(pPin); + VERIFY(internalSubMenu.AppendMenu(MF_STRING | MF_ENABLED, ids + nPPages, pinName + ResStr(IDS_MAINFRM_117))); + + if (caGUID.pElems) { + CoTaskMemFree(caGUID.pElems); + } + + nPPages++; + } + } + } + EndEnumPins; + + CComQIPtr pSS = pBF; + DWORD nStreams = 0; + if (pSS && SUCCEEDED(pSS->Count(&nStreams))) { + DWORD flags = DWORD_MAX; + DWORD group = DWORD_MAX; + DWORD prevgroup = DWORD_MAX; + LCID lcid = 0; + WCHAR* wname = nullptr; + UINT uMenuFlags; + + if (nStreams > 0 && nPPages > 0) { + VERIFY(internalSubMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + } + + UINT idlstart = idl; + UINT selectedInGroup = 0; + + for (DWORD i = 0; i < nStreams; i++) { + m_ssarray.Add(pSS); + + flags = group = 0; + wname = nullptr; + if (FAILED(pSS->Info(i, nullptr, &flags, &lcid, &group, &wname, nullptr, nullptr))) { + continue; + } + + if (group != prevgroup && idl > idlstart) { + if (selectedInGroup) { + VERIFY(internalSubMenu.CheckMenuRadioItem(idlstart, idl - 1, selectedInGroup, MF_BYCOMMAND)); + selectedInGroup = 0; + } + VERIFY(internalSubMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + idlstart = idl; + } + prevgroup = group; + + uMenuFlags = MF_STRING | MF_ENABLED; + if (flags & AMSTREAMSELECTINFO_EXCLUSIVE) { + selectedInGroup = idl; + } else if (flags & AMSTREAMSELECTINFO_ENABLED) { + uMenuFlags |= MF_CHECKED; + } + + CString streamName; + if (!wname) { + streamName.LoadString(IDS_AG_UNKNOWN_STREAM); + streamName.AppendFormat(_T(" %lu"), i + 1); + } else { + streamName = wname; + streamName.Replace(_T("&"), _T("&&")); + CoTaskMemFree(wname); + } + + VERIFY(internalSubMenu.AppendMenu(uMenuFlags, idl++, streamName)); + } + if (selectedInGroup) { + VERIFY(internalSubMenu.CheckMenuRadioItem(idlstart, idl - 1, selectedInGroup, MF_BYCOMMAND)); + } + + if (nStreams == 0) { + pSS.Release(); + } + } + + if (nPPages == 1 && !pSS) { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ids, filterName)); + } else { + if (nPPages > 0 || pSS) { + UINT nFlags = MF_STRING | MF_POPUP | ((pSPP || pSS) ? MF_ENABLED : MF_GRAYED); + VERIFY(subMenu.AppendMenu(nFlags, (UINT_PTR)internalSubMenu.Detach(), filterName)); + } else { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_GRAYED, idf, filterName)); + } + } + + ids += nPPages; + idf++; + } + EndEnumFilters; + + if (subMenu.GetMenuItemCount() > 0) { + VERIFY(subMenu.InsertMenu(0, MF_STRING | MF_ENABLED | MF_BYPOSITION, ID_FILTERS_COPY_TO_CLIPBOARD, ResStr(IDS_FILTERS_COPY_TO_CLIPBOARD))); + VERIFY(subMenu.InsertMenu(1, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); + } + subMenu.fulfillThemeReqs(); + } +} + +void CMainFrame::SetupAudioSubMenu() +{ + CMenu& subMenu = m_audiosMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (GetLoadState() != MLS::LOADED) { + return; + } + + UINT id = ID_AUDIO_SUBITEM_START; + + DWORD cStreams = 0; + + if (GetPlaybackMode() == PM_DVD) { + currentAudioLang = _T(""); + ULONG ulStreamsAvailable, ulCurrentStream; + if (FAILED(m_pDVDI->GetCurrentAudio(&ulStreamsAvailable, &ulCurrentStream))) { + return; + } + + LCID DefLanguage; + DVD_AUDIO_LANG_EXT ext; + if (FAILED(m_pDVDI->GetDefaultAudioLanguage(&DefLanguage, &ext))) { + return; + } + + for (ULONG i = 0; i < ulStreamsAvailable; i++) { + LCID Language; + if (FAILED(m_pDVDI->GetAudioLanguage(i, &Language))) { + continue; + } + + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (Language == DefLanguage) { + flags |= MF_DEFAULT; + } + if (i == ulCurrentStream) { + flags |= MF_CHECKED; + if (Language) { + GetLocaleString(Language, LOCALE_SISO639LANGNAME2, currentAudioLang); + } + } + + CString str; + if (Language) { + GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); + } else { + str.Format(IDS_AG_UNKNOWN, i + 1); + } + + DVD_AudioAttributes ATR; + if (SUCCEEDED(m_pDVDI->GetAudioAttributes(i, &ATR))) { + switch (ATR.LanguageExtension) { + case DVD_AUD_EXT_NotSpecified: + default: + break; + case DVD_AUD_EXT_Captions: + str += _T(" (Captions)"); + break; + case DVD_AUD_EXT_VisuallyImpaired: + str += _T(" (Visually Impaired)"); + break; + case DVD_AUD_EXT_DirectorComments1: + str.AppendFormat(IDS_MAINFRM_121); + break; + case DVD_AUD_EXT_DirectorComments2: + str.AppendFormat(IDS_MAINFRM_122); + break; + } + + CString format = GetDVDAudioFormatName(ATR); + + if (!format.IsEmpty()) { + str.Format(IDS_MAINFRM_11, + CString(str).GetString(), + format.GetString(), + ATR.dwFrequency, + ATR.bQuantization, + ATR.bNumberOfChannels, + ResStr(ATR.bNumberOfChannels > 1 ? IDS_MAINFRM_13 : IDS_MAINFRM_12).GetString() + ); + } + } + + VERIFY(AppendMenuEx(subMenu, flags, id++, str)); + } + } + // If available use the audio switcher for everything but DVDs + else if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams)) && cStreams > 0) { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_OPTIONS))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + + long iSel = 0; + + for (long i = 0; i < (long)cStreams; i++) { + DWORD dwFlags; + WCHAR* pName = nullptr; + if (FAILED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, nullptr, &pName, nullptr, nullptr))) { + break; + } + if (dwFlags) { + iSel = i; + } + + CString name(pName); + name.Replace(_T("&"), _T("&&")); + + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); + + CoTaskMemFree(pName); + } + VERIFY(subMenu.CheckMenuRadioItem(2, 2 + cStreams - 1, 2 + iSel, MF_BYPOSITION)); + } else if (GetPlaybackMode() == PM_FILE || GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + SetupNavStreamSelectSubMenu(subMenu, id, 1); + } +} + +void CMainFrame::SetupSubtitlesSubMenu() +{ + CMenu& subMenu = m_subtitlesMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (GetLoadState() != MLS::LOADED || m_fAudioOnly) { + return; + } + + UINT id = ID_SUBTITLES_SUBITEM_START; + + // DVD subtitles in DVD mode are never handled by the internal subtitles renderer + // but it is still possible to load external subtitles so we keep that if block + // separated from the rest + if (GetPlaybackMode() == PM_DVD) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) + && ulStreamsAvailable > 0) { + LCID DefLanguage; + DVD_SUBPICTURE_LANG_EXT ext; + if (FAILED(m_pDVDI->GetDefaultSubpictureLanguage(&DefLanguage, &ext))) { + return; + } + + VERIFY(subMenu.AppendMenu(MF_STRING | (bIsDisabled ? 0 : MF_CHECKED), id++, ResStr(IDS_DVD_SUBTITLES_ENABLE))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + + for (ULONG i = 0; i < ulStreamsAvailable; i++) { + LCID Language; + if (FAILED(m_pDVDI->GetSubpictureLanguage(i, &Language))) { + continue; + } + + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (Language == DefLanguage) { + flags |= MF_DEFAULT; + } + if (i == ulCurrentStream) { + flags |= MF_CHECKED; + } + + CString str; + if (Language) { + GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); + } else { + str.Format(IDS_AG_UNKNOWN, i + 1); + } + + DVD_SubpictureAttributes ATR; + if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(i, &ATR))) { + switch (ATR.LanguageExtension) { + case DVD_SP_EXT_NotSpecified: + default: + break; + case DVD_SP_EXT_Caption_Normal: + str += _T(""); + break; + case DVD_SP_EXT_Caption_Big: + str += _T(" (Big)"); + break; + case DVD_SP_EXT_Caption_Children: + str += _T(" (Children)"); + break; + case DVD_SP_EXT_CC_Normal: + str += _T(" (CC)"); + break; + case DVD_SP_EXT_CC_Big: + str += _T(" (CC Big)"); + break; + case DVD_SP_EXT_CC_Children: + str += _T(" (CC Children)"); + break; + case DVD_SP_EXT_Forced: + str += _T(" (Forced)"); + break; + case DVD_SP_EXT_DirectorComments_Normal: + str += _T(" (Director Comments)"); + break; + case DVD_SP_EXT_DirectorComments_Big: + str += _T(" (Director Comments, Big)"); + break; + case DVD_SP_EXT_DirectorComments_Children: + str += _T(" (Director Comments, Children)"); + break; + } + } + + VERIFY(AppendMenuEx(subMenu, flags, id++, str)); + } + } + } + + POSITION pos = m_pSubStreams.GetHeadPosition(); + + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + DWORD selected = SetupNavStreamSelectSubMenu(subMenu, id, 2); + if (selected != -1) { + SetSubtitle(selected - ID_SUBTITLES_SUBITEM_START); + } + } else if (pos) { // Internal subtitles renderer + int nItemsBeforeStart = id - ID_SUBTITLES_SUBITEM_START; + if (nItemsBeforeStart > 0) { + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + nItemsBeforeStart += 2; // Separators + } + + // Build the static menu's items + bool bTextSubtitles = false; + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_OPTIONS))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_STYLES))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_RELOAD))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUBTITLES_HIDE))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUB_OVERRIDE_DEFAULT_STYLE))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_SUB_OVERRIDE_ALL_STYLES))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + + // Build the dynamic menu's items + int i = 0, iSelected = -1; + while (pos) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + + if (CComQIPtr pSSF = subInput.pSourceFilter) { + DWORD cStreams; + if (FAILED(pSSF->Count(&cStreams))) { + continue; + } + + for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { + DWORD dwFlags, dwGroup; + CComHeapPtr pszName; + LCID lcid = 0; + if (FAILED(pSSF->Info(j, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + if (dwGroup != 2) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream + && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + iSelected = i; + } + + CString name(pszName); + /* + CString lcname = CString(name).MakeLower(); + if (lcname.Find(_T(" off")) >= 0) { + name.LoadString(IDS_AG_DISABLED); + } + */ + if (lcid != 0 && name.Find(L'\t') < 0) { + CString lcidstr; + GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); + name.Append(_T("\t") + lcidstr); + } + + name.Replace(_T("&"), _T("&&")); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); + i++; + } + } else { + CComPtr pSubStream = subInput.pSubStream; + if (!pSubStream) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + iSelected = i + pSubStream->GetStream(); + } + + for (int j = 0, cnt = pSubStream->GetStreamCount(); j < cnt; j++) { + CComHeapPtr pName; + LCID lcid = 0; + if (SUCCEEDED(pSubStream->GetStreamInfo(j, &pName, &lcid))) { + CString name(pName); + if (lcid != 0 && name.Find(L'\t') < 0) { + CString lcidstr; + GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); + name.Append(_T("\t") + lcidstr); + } + + name.Replace(_T("&"), _T("&&")); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, name)); + } else { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, id++, ResStr(IDS_AG_UNKNOWN_STREAM))); + } + i++; + } + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + CLSID clsid; + if (SUCCEEDED(subInput.pSubStream->GetClassID(&clsid)) + && clsid == __uuidof(CRenderedTextSubtitle)) { + bTextSubtitles = true; + } + } + + // TODO: find a better way to group these entries + /*if (pos && m_pSubStreams.GetAt(pos).subStream) { + CLSID cur, next; + pSubStream->GetClassID(&cur); + m_pSubStreams.GetAt(pos).subStream->GetClassID(&next); + + if (cur != next) { + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + } + }*/ + } + + // Set the menu's items' state + const CAppSettings& s = AfxGetAppSettings(); + // Style + if (!bTextSubtitles) { + subMenu.EnableMenuItem(nItemsBeforeStart + 1, MF_BYPOSITION | MF_GRAYED); + } + // Hide + if (!s.fEnableSubtitles) { + subMenu.CheckMenuItem(nItemsBeforeStart + 4, MF_BYPOSITION | MF_CHECKED); + } + // Style overrides + if (!bTextSubtitles) { + subMenu.EnableMenuItem(nItemsBeforeStart + 5, MF_BYPOSITION | MF_GRAYED); + subMenu.EnableMenuItem(nItemsBeforeStart + 6, MF_BYPOSITION | MF_GRAYED); + } + if (s.bSubtitleOverrideDefaultStyle) { + subMenu.CheckMenuItem(nItemsBeforeStart + 5, MF_BYPOSITION | MF_CHECKED); + } + if (s.bSubtitleOverrideAllStyles) { + subMenu.CheckMenuItem(nItemsBeforeStart + 6, MF_BYPOSITION | MF_CHECKED); + } + if (iSelected >= 0) { + VERIFY(subMenu.CheckMenuRadioItem(nItemsBeforeStart + 8, nItemsBeforeStart + 8 + i - 1, nItemsBeforeStart + 8 + iSelected, MF_BYPOSITION)); + } + } else if (GetPlaybackMode() == PM_FILE) { + SetupNavStreamSelectSubMenu(subMenu, id, 2); + } +} + +void CMainFrame::SetupVideoStreamsSubMenu() +{ + CMenu& subMenu = m_videoStreamsMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (GetLoadState() != MLS::LOADED) { + return; + } + + UINT id = ID_VIDEO_STREAMS_SUBITEM_START; + + if (GetPlaybackMode() == PM_FILE) { + SetupNavStreamSelectSubMenu(subMenu, id, 0); + } else if (GetPlaybackMode() == PM_DVD) { + ULONG ulStreamsAvailable, ulCurrentStream; + if (FAILED(m_pDVDI->GetCurrentAngle(&ulStreamsAvailable, &ulCurrentStream))) { + return; + } + + if (ulStreamsAvailable < 2) { + return; // one choice is not a choice... + } + + for (ULONG i = 1; i <= ulStreamsAvailable; i++) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (i == ulCurrentStream) { + flags |= MF_CHECKED; + } + + CString str; + str.Format(IDS_AG_ANGLE, i); + + VERIFY(subMenu.AppendMenu(flags, id++, str)); + } + } +} + +void CMainFrame::SetupJumpToSubMenus(CMenu* parentMenu /*= nullptr*/, int iInsertPos /*= -1*/) +{ + const CAppSettings& s = AfxGetAppSettings(); + auto emptyMenu = [&](CMPCThemeMenu & menu) { + while (menu.RemoveMenu(0, MF_BYPOSITION)); + }; + + // Empty the submenus + emptyMenu(m_chaptersMenu); + emptyMenu(m_titlesMenu); + emptyMenu(m_playlistMenu); + emptyMenu(m_BDPlaylistMenu); + emptyMenu(m_channelsMenu); + // Remove the submenus from the "Navigate" menu + if (parentMenu && iInsertPos >= 0) { + for (; m_nJumpToSubMenusCount > 0; m_nJumpToSubMenusCount--) { + VERIFY(parentMenu->RemoveMenu(iInsertPos, MF_BYPOSITION)); + } + } + + if (GetLoadState() != MLS::LOADED) { + return; + } + + UINT id = ID_NAVIGATE_JUMPTO_SUBITEM_START, idStart, idSelected; + + auto menuStartRadioSection = [&]() { + idStart = id; + idSelected = UINT_ERROR; + }; + auto menuEndRadioSection = [&](CMenu & menu) { + if (idSelected != UINT_ERROR) { + VERIFY(menu.CheckMenuRadioItem(idStart, id - 1, idSelected, + idStart >= ID_NAVIGATE_JUMPTO_SUBITEM_START ? MF_BYCOMMAND : MF_BYPOSITION)); + } + }; + auto addSubMenuIfPossible = [&](CString subMenuName, CMenu & subMenu) { + if (parentMenu && iInsertPos >= 0) { + if (parentMenu->InsertMenu(iInsertPos + m_nJumpToSubMenusCount, MF_POPUP | MF_BYPOSITION, + (UINT_PTR)(HMENU)subMenu, subMenuName)) { + CMPCThemeMenu::fulfillThemeReqsItem(parentMenu, iInsertPos + m_nJumpToSubMenusCount); + m_nJumpToSubMenusCount++; + } else { + ASSERT(FALSE); + } + } + }; + + if (GetPlaybackMode() == PM_FILE) { + if (m_MPLSPlaylist.size() > 1) { + menuStartRadioSection(); + for (auto& Item : m_MPLSPlaylist) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + CString time = _T("[") + ReftimeToString2(Item.Duration()) + _T("]"); + CString name = PathUtils::StripPathOrUrl(Item.m_strFileName); + + if (name == m_wndPlaylistBar.m_pl.GetHead().GetLabel()) { + idSelected = id; + } + + name.Replace(_T("&"), _T("&&")); + VERIFY(m_BDPlaylistMenu.AppendMenu(flags, id++, name + '\t' + time)); + } + menuEndRadioSection(m_BDPlaylistMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_BD_PLAYLISTS), m_BDPlaylistMenu); + } + + //SetupChapters(); + if (m_pCB && m_pCB->ChapGetCount() > 1) { + REFERENCE_TIME rt = GetPos(); + DWORD j = m_pCB->ChapLookup(&rt, nullptr); + menuStartRadioSection(); + for (DWORD i = 0; i < m_pCB->ChapGetCount(); i++, id++) { + rt = 0; + CComBSTR bstr; + if (FAILED(m_pCB->ChapGet(i, &rt, &bstr))) { + continue; + } + + CString time = _T("[") + ReftimeToString2(rt) + _T("]"); + + CString name = CString(bstr); + name.Replace(_T("&"), _T("&&")); + name.Replace(_T("\t"), _T(" ")); + + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (i == j) { + idSelected = id; + } + + VERIFY(m_chaptersMenu.AppendMenu(flags, id, name + '\t' + time)); + } + menuEndRadioSection(m_chaptersMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHAPTERS), m_chaptersMenu); + } + + if (m_wndPlaylistBar.GetCount() > 1) { + menuStartRadioSection(); + POSITION pos = m_wndPlaylistBar.m_pl.GetHeadPosition(); + while (pos && id < ID_NAVIGATE_JUMPTO_SUBITEM_START + 128) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (pos == m_wndPlaylistBar.m_pl.GetPos()) { + idSelected = id; + } + CPlaylistItem& pli = m_wndPlaylistBar.m_pl.GetNext(pos); + CString name = pli.GetLabel(); + name.Replace(_T("&"), _T("&&")); + VERIFY(m_playlistMenu.AppendMenu(flags, id++, name)); + } + menuEndRadioSection(m_playlistMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_PLAYLIST), m_playlistMenu); + } + } else if (GetPlaybackMode() == PM_DVD) { + ULONG ulNumOfVolumes, ulVolume, ulNumOfTitles, ulNumOfChapters, ulUOPs; + DVD_DISC_SIDE Side; + DVD_PLAYBACK_LOCATION2 Location; + + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location)) + && SUCCEEDED(m_pDVDI->GetCurrentUOPS(&ulUOPs)) + && SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters)) + && SUCCEEDED(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles))) { + menuStartRadioSection(); + for (ULONG i = 1; i <= ulNumOfTitles; i++) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (i == Location.TitleNum) { + idSelected = id; + } + if (ulUOPs & UOP_FLAG_Play_Title) { + flags |= MF_GRAYED; + } + + CString str; + str.Format(IDS_AG_TITLE, i); + + VERIFY(m_titlesMenu.AppendMenu(flags, id++, str)); + } + menuEndRadioSection(m_titlesMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_TITLES), m_titlesMenu); + + menuStartRadioSection(); + for (ULONG i = 1; i <= ulNumOfChapters; i++) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (i == Location.ChapterNum) { + idSelected = id; + } + if (ulUOPs & UOP_FLAG_Play_Chapter) { + flags |= MF_GRAYED; + } + + CString str; + str.Format(IDS_AG_CHAPTER, i); + + VERIFY(m_chaptersMenu.AppendMenu(flags, id++, str)); + } + menuEndRadioSection(m_chaptersMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHAPTERS), m_chaptersMenu); + } + } else if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + menuStartRadioSection(); + for (const auto& channel : s.m_DVBChannels) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + + if (channel.GetPrefNumber() == s.nDVBLastChannel) { + idSelected = id; + } + VERIFY(m_channelsMenu.AppendMenu(flags, ID_NAVIGATE_JUMPTO_SUBITEM_START + channel.GetPrefNumber(), channel.GetName())); + id++; + } + menuEndRadioSection(m_channelsMenu); + addSubMenuIfPossible(StrRes(IDS_NAVIGATE_CHANNELS), m_channelsMenu); + } +} + +DWORD CMainFrame::SetupNavStreamSelectSubMenu(CMenu& subMenu, UINT id, DWORD dwSelGroup) +{ + bool bAddSeparator = false; + DWORD selected = -1; + bool streams_found = false; + + auto addStreamSelectFilter = [&](CComPtr pSS) { + DWORD cStreams; + if (!pSS || FAILED(pSS->Count(&cStreams))) { + return; + } + + bool bAdded = false; + for (DWORD i = 0; i < cStreams; i++) { + DWORD dwFlags, dwGroup; + CComHeapPtr pszName; + LCID lcid = 0; + if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + if (dwGroup != dwSelGroup) { + continue; + } + + CString name(pszName); + /* + CString lcname = CString(name).MakeLower(); + if (dwGroup == 2 && lcname.Find(_T(" off")) >= 0) { + name.LoadString(IDS_AG_DISABLED); + } + */ + if (dwGroup == 2 && lcid != 0 && name.Find(L'\t') < 0) { + CString lcidstr; + GetLocaleString(lcid, LOCALE_SENGLANGUAGE, lcidstr); + name.Append(_T("\t") + lcidstr); + } + + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (dwFlags) { + flags |= MF_CHECKED; + selected = id; + } + + if (bAddSeparator) { + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + bAddSeparator = false; + } + bAdded = true; + + name.Replace(_T("&"), _T("&&")); + VERIFY(subMenu.AppendMenu(flags, id++, name)); + } + + if (bAdded) { + bAddSeparator = true; + streams_found = true; + } + }; + + if (m_pSplitterSS) { + addStreamSelectFilter(m_pSplitterSS); + } + if (!streams_found && m_pOtherSS[0]) { + addStreamSelectFilter(m_pOtherSS[0]); + } + if (!streams_found && m_pOtherSS[1]) { + addStreamSelectFilter(m_pOtherSS[1]); + } + + return selected; +} + +void CMainFrame::OnNavStreamSelectSubMenu(UINT id, DWORD dwSelGroup) +{ + bool streams_found = false; + + auto processStreamSelectFilter = [&](CComPtr pSS) { + bool bSelected = false; + + DWORD cStreams; + if (SUCCEEDED(pSS->Count(&cStreams))) { + for (int i = 0, j = cStreams; i < j; i++) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + CComHeapPtr pszName; + + if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + if (dwGroup != dwSelGroup) { + continue; + } + + streams_found = true; + + if (id == 0) { + pSS->Enable(i, AMSTREAMSELECTENABLE_ENABLE); + bSelected = true; + break; + } + + id--; + } + } + + return bSelected; + }; + + if (m_pSplitterSS) { + if (processStreamSelectFilter(m_pSplitterSS)) return; + } + if (!streams_found && m_pOtherSS[0]) { + if (processStreamSelectFilter(m_pOtherSS[0])) return; + } + if (!streams_found && m_pOtherSS[1]) { + if (processStreamSelectFilter(m_pOtherSS[1])) return; + } +} + +void CMainFrame::OnStreamSelect(bool bForward, DWORD dwSelGroup) +{ + ASSERT(dwSelGroup == 1 || dwSelGroup == 2); + bool streams_found = false; + + auto processStreamSelectFilter = [&](CComPtr pSS) { + DWORD cStreams; + if (FAILED(pSS->Count(&cStreams))) { + return false; + } + + std::vector> streams; + size_t currentSel = SIZE_MAX; + for (DWORD i = 0; i < cStreams; i++) { + DWORD dwFlags, dwGroup; + LCID lcid = 0; + CComHeapPtr pszName; + + if (FAILED(pSS->Info(i, nullptr, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + if (dwGroup != dwSelGroup) { + continue; + } + + streams_found = true; + + if (dwFlags) { + currentSel = streams.size(); + } + streams.emplace_back(i, (int)streams.size(), lcid, CString(pszName)); + } + + size_t count = streams.size(); + if (count && currentSel != SIZE_MAX) { + size_t requested = (bForward ? currentSel + 1 : currentSel - 1) % count; + DWORD id; + int trackindex; + LCID lcid = 0; + CString name; + std::tie(id, trackindex, lcid, name) = streams.at(requested); + if (SUCCEEDED(pSS->Enable(id, AMSTREAMSELECTENABLE_ENABLE))) { + if (dwSelGroup == 1 || AfxGetAppSettings().fEnableSubtitles) { + m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(name, lcid, dwSelGroup)); + } + if (dwSelGroup == 1) { + AM_MEDIA_TYPE* pmt = nullptr; + if (SUCCEEDED(pSS->Info(id, &pmt, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr))) { + UpdateSelectedAudioStreamInfo(trackindex, pmt, lcid); + DeleteMediaType(pmt); + } + } else { + if (lcid && AfxGetAppSettings().fEnableSubtitles) { + GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentSubLang); + } else { + currentSubLang.Empty(); + } + } + } + return true; + } + return false; + }; + + if (m_pSplitterSS) { + if (processStreamSelectFilter(m_pSplitterSS)) return; + } + if (!streams_found && m_pOtherSS[0]) { + if (processStreamSelectFilter(m_pOtherSS[0])) return; + } + if (!streams_found && m_pOtherSS[1]) { + if (processStreamSelectFilter(m_pOtherSS[1])) return; + } +} + +CString CMainFrame::GetStreamOSDString(CString name, LCID lcid, DWORD dwSelGroup) +{ + name.Replace(_T("\t"), _T(" - ")); + CString sLcid; + if (lcid && lcid != LCID(-1)) { + GetLocaleString(lcid, LOCALE_SENGLANGUAGE, sLcid); + } + if (!sLcid.IsEmpty() && CString(name).MakeLower().Find(CString(sLcid).MakeLower()) < 0) { + name += _T(" (") + sLcid + _T(")"); + } + CString strMessage; + if (dwSelGroup == 1) { + int n = 0; + if (name.Find(_T("A:")) == 0) { + n = 2; + } + strMessage.Format(IDS_AUDIO_STREAM, name.Mid(n).Trim().GetString()); + } else if (dwSelGroup == 2) { + int n = 0; + if (name.Find(_T("S:")) == 0) { + n = 2; + } + strMessage.Format(IDS_SUBTITLE_STREAM, name.Mid(n).Trim().GetString()); + } + return strMessage; +} + +void CMainFrame::SetupRecentFilesSubMenu() +{ + auto& s = AfxGetAppSettings(); + auto& MRU = s.MRU; + MRU.ReadMediaHistory(); + + if (MRU.listModifySequence == recentFilesMenuFromMRUSequence) { + return; + } + recentFilesMenuFromMRUSequence = MRU.listModifySequence; + + CMenu& subMenu = m_recentFilesMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (!s.fKeepHistory) { + return; + } + + if (MRU.GetSize() > 0) { + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_RECENT_FILES_CLEAR, ResStr(IDS_RECENT_FILES_CLEAR))); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR | MF_ENABLED)); + UINT id = ID_RECENT_FILE_START; + for (int i = 0; i < MRU.GetSize(); i++) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + if (!MRU[i].fns.IsEmpty() && !MRU[i].fns.GetHead().IsEmpty()) { + CString p = MRU[i].cue.IsEmpty() ? MRU[i].fns.GetHead() : MRU[i].cue; + if (s.bUseTitleInRecentFileList && !MRU[i].title.IsEmpty()) { + CString title(MRU[i].title); + if (title.GetLength() > 100) { + title = title.Left(40) + _T("~~~") + title.Right(57); + } + int targetlen = 150 - title.GetLength(); + if (PathUtils::IsURL(p)) { + if (title.Right(1) == L')') { + // probably already contains shorturl + p = title; + } else { + CString shorturl = ShortenURL(p, targetlen, true); + p.Format(_T("%s (%s)"), static_cast(title), static_cast(shorturl)); + } + } else { + CString fn = PathUtils::StripPathOrUrl(p); + if (fn.GetLength() > targetlen) { // If file name is too long, cut middle part. + int l = fn.GetLength(); + fn.Format(_T("%s~~~%s"), static_cast(fn.Left(l / 2 - 2 + (l % 2))), static_cast(fn.Right(l / 2 - 1))); + } + p.Format(_T("%s (%s)"), static_cast(title), static_cast(fn)); + } + } + else { + if (PathUtils::IsURL(p)) { + p = ShortenURL(p, 150); + } + if (p.GetLength() > 150) { + p.Format(_T("%s~~~%s"), static_cast(p.Left(60)), static_cast(p.Right(87))); + } + } + p.Replace(_T("&"), _T("&&")); + VERIFY(subMenu.AppendMenu(flags, id, p)); + } else { + ASSERT(false); + } + id++; + } + } +} + +void CMainFrame::SetupFavoritesSubMenu() +{ + CMenu& subMenu = m_favoritesMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + const CAppSettings& s = AfxGetAppSettings(); + + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_FAVORITES_ADD, ResStr(IDS_FAVORITES_ADD))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_FAVORITES_ORGANIZE, ResStr(IDS_FAVORITES_ORGANIZE))); + + UINT nLastGroupStart = subMenu.GetMenuItemCount(); + UINT id = ID_FAVORITES_FILE_START; + CAtlList favs; + AfxGetAppSettings().GetFav(FAV_FILE, favs); + POSITION pos = favs.GetHeadPosition(); + + while (pos) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + + CString f_str = favs.GetNext(pos); + f_str.Replace(_T("&"), _T("&&")); + f_str.Replace(_T("\t"), _T(" ")); + + FileFavorite ff; + VERIFY(FileFavorite::TryParse(f_str, ff)); + + f_str = ff.Name; + + CString str = ff.ToString(); + if (!str.IsEmpty()) { + f_str.AppendFormat(_T("\t%s"), str.GetString()); + } + + if (!f_str.IsEmpty()) { + VERIFY(subMenu.AppendMenu(flags, id, f_str)); + } + + id++; + if (id > ID_FAVORITES_FILE_END) { + break; + } + } + + if (id > ID_FAVORITES_FILE_START) { + VERIFY(subMenu.InsertMenu(nLastGroupStart, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); + } + + nLastGroupStart = subMenu.GetMenuItemCount(); + + id = ID_FAVORITES_DVD_START; + s.GetFav(FAV_DVD, favs); + pos = favs.GetHeadPosition(); + + while (pos) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + + CString str = favs.GetNext(pos); + str.Replace(_T("&"), _T("&&")); + + CAtlList sl; + ExplodeEsc(str, sl, _T(';'), 2); + + str = sl.RemoveHead(); + + if (!sl.IsEmpty()) { + // TODO + } + + if (!str.IsEmpty()) { + VERIFY(subMenu.AppendMenu(flags, id, str)); + } + + id++; + if (id > ID_FAVORITES_DVD_END) { + break; + } + } + + if (id > ID_FAVORITES_DVD_START) { + VERIFY(subMenu.InsertMenu(nLastGroupStart, MF_SEPARATOR | MF_ENABLED | MF_BYPOSITION)); + } + + nLastGroupStart = subMenu.GetMenuItemCount(); + + id = ID_FAVORITES_DEVICE_START; + + s.GetFav(FAV_DEVICE, favs); + + pos = favs.GetHeadPosition(); + while (pos) { + UINT flags = MF_BYCOMMAND | MF_STRING | MF_ENABLED; + + CString str = favs.GetNext(pos); + str.Replace(_T("&"), _T("&&")); + + CAtlList sl; + ExplodeEsc(str, sl, _T(';'), 2); + + str = sl.RemoveHead(); + + if (!str.IsEmpty()) { + VERIFY(subMenu.AppendMenu(flags, id, str)); + } + + id++; + if (id > ID_FAVORITES_DEVICE_END) { + break; + } + } +} + +bool CMainFrame::SetupShadersSubMenu() +{ + const auto& s = AfxGetAppSettings(); + + CMenu& subMenu = m_shadersMenu; + // Empty the menu + while (subMenu.RemoveMenu(0, MF_BYPOSITION)); + + if (!(s.iDSVideoRendererType == VIDRNDT_DS_EVR_CUSTOM || s.iDSVideoRendererType == VIDRNDT_DS_SYNC + || s.iDSVideoRendererType == VIDRNDT_DS_VMR9RENDERLESS || s.iDSVideoRendererType == VIDRNDT_DS_MADVR || s.iDSVideoRendererType == VIDRNDT_DS_MPCVR)) { + return false; + } + + subMenu.AppendMenu(MF_BYCOMMAND | MF_STRING | MF_ENABLED, ID_PRESIZE_SHADERS_TOGGLE, ResStr(IDS_PRESIZE_SHADERS_TOGGLE)); + subMenu.AppendMenu(MF_BYCOMMAND | MF_STRING | MF_ENABLED, ID_POSTSIZE_SHADERS_TOGGLE, ResStr(IDS_POSTSIZE_SHADERS_TOGGLE)); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_SHADERS_SELECT, ResStr(IDS_SHADERS_SELECT))); + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, ID_VIEW_DEBUGSHADERS, ResStr(IDS_SHADERS_DEBUG))); + + auto presets = s.m_Shaders.GetPresets(); + if (!presets.empty()) { + CString current; + bool selected = s.m_Shaders.GetCurrentPresetName(current); + VERIFY(subMenu.AppendMenu(MF_SEPARATOR)); + UINT nID = ID_SHADERS_PRESETS_START; + for (const auto& pair : presets) { + if (nID > ID_SHADERS_PRESETS_END) { + // too many presets + ASSERT(FALSE); + break; + } + VERIFY(subMenu.AppendMenu(MF_STRING | MF_ENABLED, nID, pair.first)); + if (selected && pair.first == current) { + VERIFY(subMenu.CheckMenuRadioItem(nID, nID, nID, MF_BYCOMMAND)); + selected = false; + } + nID++; + } + } + return true; +} + +///////////// + +void CMainFrame::SetAlwaysOnTop(int iOnTop) +{ + CAppSettings& s = AfxGetAppSettings(); + + if (!IsFullScreenMode()) { + const CWnd* pInsertAfter = nullptr; + + if (iOnTop == 0) { + // We only want to disable "On Top" once so that + // we don't interfere with other window manager + if (s.iOnTop || !alwaysOnTopZOrderInitialized) { + pInsertAfter = &wndNoTopMost; + alwaysOnTopZOrderInitialized = true; + } + } else if (iOnTop == 1) { + pInsertAfter = &wndTopMost; + } else if (iOnTop == 2) { + pInsertAfter = (GetMediaState() == State_Running) ? &wndTopMost : &wndNoTopMost; + } else { // if (iOnTop == 3) + pInsertAfter = (GetMediaState() == State_Running && !m_fAudioOnly) ? &wndTopMost : &wndNoTopMost; + } + + if (pInsertAfter) { + SetWindowPos(pInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + + s.iOnTop = iOnTop; +} + +bool CMainFrame::WindowExpectedOnTop() { + return (AfxGetAppSettings().iOnTop == 1 || + (AfxGetAppSettings().iOnTop == 2 && GetMediaState() == State_Running) || + (AfxGetAppSettings().iOnTop == 3 && GetMediaState() == State_Running && !m_fAudioOnly)); +} + +void CMainFrame::AddTextPassThruFilter() +{ + BeginEnumFilters(m_pGB, pEF, pBF) { + if (!IsSplitter(pBF)) { + continue; + } + + BeginEnumPins(pBF, pEP, pPin) { + CComPtr pPinTo; + AM_MEDIA_TYPE mt; + if (SUCCEEDED(pPin->ConnectedTo(&pPinTo)) && pPinTo + && SUCCEEDED(pPin->ConnectionMediaType(&mt)) + && (mt.majortype == MEDIATYPE_Text || mt.majortype == MEDIATYPE_Subtitle)) { + InsertTextPassThruFilter(pBF, pPin, pPinTo); + } + } + EndEnumPins; + } + EndEnumFilters; +} + +HRESULT CMainFrame::InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinTo) +{ + HRESULT hr; + CComQIPtr pTPTF = DEBUG_NEW CTextPassThruFilter(this); + CStringW name; + name.Format(L"TextPassThru%p", static_cast(pTPTF)); + if (FAILED(hr = m_pGB->AddFilter(pTPTF, name))) { + return hr; + } + + OAFilterState fs = GetMediaState(); + if (fs == State_Running || fs == State_Paused) { + MediaControlStop(true); + } + + hr = pPinTo->Disconnect(); + hr = pPin->Disconnect(); + + if (FAILED(hr = m_pGB->ConnectDirect(pPin, GetFirstPin(pTPTF, PINDIR_INPUT), nullptr)) + || FAILED(hr = m_pGB->ConnectDirect(GetFirstPin(pTPTF, PINDIR_OUTPUT), pPinTo, nullptr))) { + hr = m_pGB->ConnectDirect(pPin, pPinTo, nullptr); + } else { + SubtitleInput subInput(CComQIPtr(pTPTF), pBF); + m_pSubStreams.AddTail(subInput); + } + + if (fs == State_Running) { + MediaControlRun(); + } else if (fs == State_Paused) { + MediaControlPause(); + } + + return hr; +} + +bool CMainFrame::LoadSubtitle(CString fn, SubtitleInput* pSubInput /*= nullptr*/, bool bAutoLoad /*= false*/) +{ + CAppSettings& s = AfxGetAppSettings(); + CComQIPtr pSubStream; + + if (!s.IsISRAutoLoadEnabled() && (FindFilter(CLSID_VSFilter, m_pGB) || FindFilter(CLSID_XySubFilter, m_pGB))) { + // Prevent ISR from loading if VSFilter is already in graph. + // TODO: Support VSFilter natively (see ticket #4122) + // Note that this doesn't affect ISR auto-loading if any sub renderer force loading itself into the graph. + // VSFilter like filters can be blocked when building the graph and ISR auto-loading is enabled but some + // users don't want that. + return false; + } + + if (GetPlaybackMode() == PM_FILE && !s.fDisableInternalSubtitles && !FindFilter(__uuidof(CTextPassThruFilter), m_pGB)) { + // Add TextPassThru filter if it isn't already in the graph. (i.e ISR hasn't been loaded before) + // This will load all embedded subtitle tracks when user triggers ISR (load external subtitle file) for the first time. + AddTextPassThruFilter(); + } + + CString videoName; + if (GetPlaybackMode() == PM_FILE) { + videoName = m_wndPlaylistBar.GetCurFileName(); + } + + CString ext = CPath(fn).GetExtension().MakeLower(); + + if (!pSubStream && (ext == _T(".idx") || !bAutoLoad && ext == _T(".sub"))) { + CAutoPtr pVSF(DEBUG_NEW CVobSubFile(&m_csSubLock)); + if (pVSF && pVSF->Open(fn) && pVSF->GetStreamCount() > 0) { + pSubStream = pVSF.Detach(); + } + } + + if (!pSubStream && ext != _T(".idx") && ext != _T(".sup")) { + CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); + if (pRTS) { + if (pRTS->Open(fn, DEFAULT_CHARSET, _T(""), videoName) && pRTS->GetStreamCount() > 0) { +#if USE_LIBASS + if (pRTS->m_LibassContext.IsLibassActive()) { + pRTS->m_LibassContext.SetFilterGraph(m_pGB); + } +#endif + pSubStream = pRTS.Detach(); + } + } + } + + if (!pSubStream) { + CAutoPtr pPSF(DEBUG_NEW CPGSSubFile(&m_csSubLock)); + if (pPSF && pPSF->Open(fn, _T(""), videoName) && pPSF->GetStreamCount() > 0) { + pSubStream = pPSF.Detach(); + } + } + + if (pSubStream) { + SubtitleInput subInput(pSubStream); + m_ExternalSubstreams.push_back(pSubStream); + m_pSubStreams.AddTail(subInput); + + // Temporarily load fonts from 'Fonts' folder - Begin + CString path = PathUtils::DirName(fn) + L"\\fonts\\"; + ExtendMaxPathLengthIfNeeded(path); + + if (::PathIsDirectory(path)) { + WIN32_FIND_DATA fd = {0}; + HANDLE hFind; + + hFind = FindFirstFile(path + L"*.?t?", &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + CStringW ext = GetFileExt(fd.cFileName); + if (ext == ".ttf" || ext == ".otf" || ext == ".ttc") { + m_FontInstaller.InstallTempFontFile(path + fd.cFileName); + } + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + } + // Temporarily load fonts from 'Fonts' folder - End + + if (!m_posFirstExtSub) { + m_posFirstExtSub = m_pSubStreams.GetTailPosition(); + } + + if (pSubInput) { + *pSubInput = subInput; + } + + if (!bAutoLoad) { + m_wndPlaylistBar.AddSubtitleToCurrent(fn); + if (s.fKeepHistory) { + s.MRU.AddSubToCurrent(fn); + } + } + } + + return !!pSubStream; +} + +bool CMainFrame::LoadSubtitle(CYoutubeDLInstance::YDLSubInfo& sub) { + CAppSettings& s = AfxGetAppSettings(); + CComQIPtr pSubStream; + CAtlList preferlist; + if (!s.sYDLSubsPreference.IsEmpty()) { + if (s.sYDLSubsPreference.Find(_T(',')) != -1) { + ExplodeMin(s.sYDLSubsPreference, preferlist, ','); + } else { + ExplodeMin(s.sYDLSubsPreference, preferlist, ' '); + } + } + if (!preferlist.IsEmpty() && !CYoutubeDLInstance::isPrefer(preferlist, sub.lang)) { + return false; + } + + if (!s.IsISRAutoLoadEnabled() && (FindFilter(CLSID_VSFilter, m_pGB) || FindFilter(CLSID_XySubFilter, m_pGB))) { + // Prevent ISR from loading if VSFilter is already in graph. + // TODO: Support VSFilter natively (see ticket #4122) + // Note that this doesn't affect ISR auto-loading if any sub renderer force loading itself into the graph. + // VSFilter like filters can be blocked when building the graph and ISR auto-loading is enabled but some + // users don't want that. + return false; + } + + if (GetPlaybackMode() == PM_FILE && !s.fDisableInternalSubtitles && !FindFilter(__uuidof(CTextPassThruFilter), m_pGB)) { + // Add TextPassThru filter if it isn't already in the graph. (i.e ISR hasn't been loaded before) + // This will load all embedded subtitle tracks when user triggers ISR (load external subtitle file) for the first time. + AddTextPassThruFilter(); + } + + CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); + if (pRTS) { + bool opened = false; + if (!sub.url.IsEmpty()) { + SubtitlesProvidersUtils::stringMap strmap{}; + DWORD dwStatusCode; + CT2CA tem(sub.url); + std::string tem2(tem); + std::string data(""); + SubtitlesProvidersUtils::StringDownload(tem2, strmap, data, true, &dwStatusCode); + if (dwStatusCode != 200) { + return false; + } + if (sub.ext.IsEmpty()) { + int m2(sub.url.ReverseFind(_T('?'))); + int m3(sub.url.ReverseFind(_T('#'))); + int m = -1; + if (m2 > -1 && m3 > -1) m = std::min(m2, m3); + else if (m2 > -1) m = m2; + else if (m3 > -1) m = m3; + CString temp(sub.url); + if (m > 0) temp = sub.url.Left(m); + m = temp.ReverseFind(_T('.')); + if (m >= 0) sub.ext = temp.Mid(m + 1); + } + CString langt = sub.isAutomaticCaptions ? sub.lang + _T("[Automatic]") : sub.lang; + opened = pRTS->Open((BYTE*)data.c_str(), (int)data.length(), DEFAULT_CHARSET, _T("YoutubeDL"), langt, sub.ext); + } else if (!sub.data.IsEmpty()) { + CString langt = sub.isAutomaticCaptions ? sub.lang + _T("[Automatic]") : sub.lang; + opened = pRTS->Open(sub.data, CTextFile::enc::UTF8, DEFAULT_CHARSET, _T("YoutubeDL"), langt, sub.ext); // Do not modify charset, Now it wroks with Unicode char. + } + if (opened && pRTS->GetStreamCount() > 0) { +#if USE_LIBASS + if (pRTS->m_LibassContext.IsLibassActive()) { + pRTS->m_LibassContext.SetFilterGraph(m_pGB); + } +#endif + pSubStream = pRTS.Detach(); + } + } + + if (pSubStream) { + SubtitleInput subInput(pSubStream); + m_ExternalSubstreams.push_back(pSubStream); + m_pSubStreams.AddTail(subInput); + + if (!m_posFirstExtSub) { + m_posFirstExtSub = m_pSubStreams.GetTailPosition(); + } + } + + return !!pSubStream; +} + +// Called from GraphThread +bool CMainFrame::SetSubtitle(int i, bool bIsOffset /*= false*/, bool bDisplayMessage /*= false*/) +{ + if (!m_pCAP) { + return false; + } + if (GetLoadState() == MLS::CLOSING) { + return false; + } + + CAppSettings& s = AfxGetAppSettings(); + + SubtitleInput* pSubInput = nullptr; + if (m_iReloadSubIdx >= 0) { + pSubInput = GetSubtitleInput(m_iReloadSubIdx); + if (pSubInput) { + i = m_iReloadSubIdx; + } + m_iReloadSubIdx = -1; + } + + if (!pSubInput) { + pSubInput = GetSubtitleInput(i, bIsOffset); + } + + bool success = false; + + if (pSubInput) { + CComHeapPtr pName; + if (CComQIPtr pSSF = pSubInput->pSourceFilter) { + DWORD dwFlags; + LCID lcid = 0; + if (FAILED(pSSF->Info(i, nullptr, &dwFlags, &lcid, nullptr, &pName, nullptr, nullptr))) { + dwFlags = 0; + } + if (lcid && s.fEnableSubtitles) { + currentSubLang = ISOLang::GetLocaleStringCompat(lcid); + } else { + currentSubLang.Empty(); + } + + // Enable the track only if it isn't already the only selected track in the group + if (!(dwFlags & AMSTREAMSELECTINFO_EXCLUSIVE)) { + pSSF->Enable(i, AMSTREAMSELECTENABLE_ENABLE); + } + i = 0; + } + { + // m_csSubLock shouldn't be locked when using IAMStreamSelect::Enable or SetSubtitle + CAutoLock cAutoLock(&m_csSubLock); + pSubInput->pSubStream->SetStream(i); + } + SetSubtitle(*pSubInput, true); + + if (!pName) { + LCID lcid = 0; + pSubInput->pSubStream->GetStreamInfo(0, &pName, &lcid); + if (lcid && s.fEnableSubtitles) { + currentSubLang = ISOLang::GetLocaleStringCompat(lcid); + } else { + currentSubLang.Empty(); + } + } + + if (bDisplayMessage && pName) { + m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pName), LCID(-1), 2)); + } + success = true; + } + + if (success && s.fKeepHistory && s.bRememberTrackSelection) { + s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); + } + return success; +} + +void CMainFrame::UpdateSubtitleColorInfo() +{ + if (!m_pCAP || !m_pCurrentSubInput.pSubStream) { + return; + } + + // store video mediatype, so colorspace information can be extracted when present + // FIXME: mediatype extended colorinfo may be absent on initial connection, call this again after first frame has been decoded? + CComQIPtr pBF = m_pCAP; + CComPtr pPin = GetFirstPin(pBF); + if (pPin) { + AM_MEDIA_TYPE mt; + if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + m_pCAP->SetVideoMediaType(CMediaType(mt)); + } + } + + CComQIPtr pSRO = m_pCAP; + + LPWSTR yuvMatrix = nullptr; + int nLen; + if (m_pMVRI) { + m_pMVRI->GetString("yuvMatrix", &yuvMatrix, &nLen); + } else if (pSRO) { + pSRO->GetString("yuvMatrix", &yuvMatrix, &nLen); + } + + int targetBlackLevel = 0, targetWhiteLevel = 255; + if (m_pMVRS) { + m_pMVRS->SettingsGetInteger(L"Black", &targetBlackLevel); + m_pMVRS->SettingsGetInteger(L"White", &targetWhiteLevel); + } else if (pSRO) { + int range = 0; + pSRO->GetInt("supportedLevels", &range); + if (range == 3) { + targetBlackLevel = 16; + targetWhiteLevel = 235; + } + } + + m_pCurrentSubInput.pSubStream->SetSourceTargetInfo(yuvMatrix, targetBlackLevel, targetWhiteLevel); + LocalFree(yuvMatrix); +} + +void CMainFrame::SetSubtitle(const SubtitleInput& subInput, bool skip_lcid /* = false */) +{ + TRACE(_T("CMainFrame::SetSubtitle\n")); + + CAppSettings& s = AfxGetAppSettings(); + ResetSubtitlePosAndSize(false); + + { + CAutoLock cAutoLock(&m_csSubLock); + + bool firstuse = !m_pCurrentSubInput.pSubStream; + + if (subInput.pSubStream) { + bool found = false; + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + if (subInput.pSubStream == m_pSubStreams.GetNext(pos).pSubStream) { + found = true; + break; + } + } + // We are trying to set a subtitles stream that isn't in the list so we abort here. + if (!found) { + return; + } + } + + if (m_pCAP && m_pCurrentSubInput.pSubStream && m_pCurrentSubInput.pSubStream != subInput.pSubStream) { + m_pCAP->SetSubPicProvider(nullptr); + } + + m_pCurrentSubInput = subInput; + + UpdateSubtitleRenderingParameters(); + + if (firstuse) { + // note: can deadlock when calling ConnectionMediaType() with MPCVR when SubPicProvider!=nullptr + UpdateSubtitleColorInfo(); + } + + if (!skip_lcid) { + LCID lcid = 0; + if (m_pCurrentSubInput.pSubStream && s.fEnableSubtitles) { + CComHeapPtr pName; + m_pCurrentSubInput.pSubStream->GetStreamInfo(0, &pName, &lcid); + } + if (lcid) { + GetLocaleString(lcid, LOCALE_SISO639LANGNAME2, currentSubLang); + } else { + currentSubLang.Empty(); + } + } + + if (m_pCAP) { + g_bExternalSubtitle = (std::find(m_ExternalSubstreams.cbegin(), m_ExternalSubstreams.cend(), subInput.pSubStream) != m_ExternalSubstreams.cend()); + bool use_subresync = false; + if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { +#if USE_LIBASS + if (!pRTS->m_LibassContext.IsLibassActive()) +#endif + use_subresync = true; + } + if (use_subresync) { + m_wndSubresyncBar.SetSubtitle(subInput.pSubStream, m_pCAP->GetFPS(), g_bExternalSubtitle); + } else { + m_wndSubresyncBar.SetSubtitle(nullptr, m_pCAP->GetFPS(), g_bExternalSubtitle); + } + } + } + + if (m_pCAP && s.fEnableSubtitles) { + m_pCAP->SetSubPicProvider(CComQIPtr(subInput.pSubStream)); + } + + if (s.fKeepHistory && s.bRememberTrackSelection) { + s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); + } +} + +void CMainFrame::OnAudioShiftOnOff() +{ + AfxGetAppSettings().fAudioTimeShift = !AfxGetAppSettings().fAudioTimeShift; +} + +void CMainFrame::ToggleSubtitleOnOff(bool bDisplayMessage /*= false*/) +{ + if (m_pDVS) { + bool bHideSubtitles = false; + m_pDVS->get_HideSubtitles(&bHideSubtitles); + bHideSubtitles = !bHideSubtitles; + m_pDVS->put_HideSubtitles(bHideSubtitles); + } + if (m_pCAP && (!m_pDVS || !m_pSubStreams.IsEmpty())) { + CAppSettings& s = AfxGetAppSettings(); + s.fEnableSubtitles = !s.fEnableSubtitles; + + if (s.fEnableSubtitles) { + SetSubtitle(0, true, bDisplayMessage); + } else { + if (m_pCAP) { + m_pCAP->SetSubPicProvider(nullptr); + } + currentSubLang = ResStr(IDS_AG_DISABLED); + + if (bDisplayMessage) { + m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_SUBTITLE_STREAM_OFF)); + } + } + } +} + +void CMainFrame::ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew) +{ + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + POSITION cur = pos; + if (pSubStreamOld == m_pSubStreams.GetNext(pos).pSubStream) { + m_pSubStreams.GetAt(cur).pSubStream = pSubStreamNew; + if (m_pCurrentSubInput.pSubStream == pSubStreamOld) { + SetSubtitle(m_pSubStreams.GetAt(cur), true); + } + break; + } + } +} + +void CMainFrame::InvalidateSubtitle(DWORD_PTR nSubtitleId /*= DWORD_PTR_MAX*/, REFERENCE_TIME rtInvalidate /*= -1*/) +{ + if (m_pCAP) { + if (nSubtitleId == DWORD_PTR_MAX || nSubtitleId == (DWORD_PTR)(ISubStream*)m_pCurrentSubInput.pSubStream) { + m_pCAP->Invalidate(rtInvalidate); + } + } +} + +void CMainFrame::ReloadSubtitle() +{ + { + CAutoLock cAutoLock(&m_csSubLock); + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + m_pSubStreams.GetNext(pos).pSubStream->Reload(); + } + } + + ResetSubtitlePosAndSize(false); + + SetSubtitle(0, true); + m_wndSubresyncBar.ReloadSubtitle(); +} + +void CMainFrame::SetSubtitleTrackIdx(int index) +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (GetLoadState() == MLS::LOADED && m_pCAP) { + // Check if we want to change the enable/disable state + if (s.fEnableSubtitles != (index >= 0)) { + ToggleSubtitleOnOff(); + } + // Set the new subtitles track if needed + if (s.fEnableSubtitles) { + SetSubtitle(index); + } + } +} + +void CMainFrame::SetAudioTrackIdx(int index) +{ + if (GetLoadState() == MLS::LOADED) { + DWORD cStreams = 0; + DWORD dwFlags = AMSTREAMSELECTENABLE_ENABLE; + if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { + if ((index >= 0) && (index < ((int)cStreams))) { + m_pAudioSwitcherSS->Enable(index, dwFlags); + + m_loadedAudioTrackIndex = index; + LCID lcid = 0; + AM_MEDIA_TYPE* pmt = nullptr; + CComHeapPtr pszName; + if (SUCCEEDED(m_pAudioSwitcherSS->Info(index, &pmt, &dwFlags, &lcid, nullptr, &pszName, nullptr, nullptr))) { + m_OSD.DisplayMessage(OSD_TOPLEFT, GetStreamOSDString(CString(pszName), lcid, 1)); + UpdateSelectedAudioStreamInfo(index, pmt, lcid); + DeleteMediaType(pmt); + } + } + } + // ToDo: use m_pSplitterSS + } +} + +int CMainFrame::GetCurrentAudioTrackIdx(CString *pstrName) +{ + if(pstrName) + pstrName->Empty(); + + if (GetLoadState() == MLS::LOADED && GetPlaybackMode() == PM_FILE && m_pGB) { + DWORD cStreams = 0; + if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { + for (int i = 0; i < (int)cStreams; i++) { + DWORD dwFlags = 0; + CComHeapPtr pName; + if (SUCCEEDED(m_pAudioSwitcherSS->Info(i, nullptr, &dwFlags, nullptr, nullptr, &pName, nullptr, nullptr))) { + if (dwFlags & AMSTREAMSELECTINFO_ENABLED) { + if(pstrName) + *pstrName = pName; + ASSERT(m_loadedAudioTrackIndex == i); + return i; + } + } else { + break; + } + } + } + // ToDo: use m_pSplitterSS + } + return -1; +} + +int CMainFrame::GetCurrentSubtitleTrackIdx(CString *pstrName) +{ + if(pstrName) + pstrName->Empty(); + + if (GetLoadState() != MLS::LOADED) { + return -1; + } + + if (m_pCAP && !m_pSubStreams.IsEmpty()) { + int idx = 0; + POSITION pos = m_pSubStreams.GetHeadPosition(); + while (pos) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + if (CComQIPtr pSSF = subInput.pSourceFilter) { + DWORD cStreams; + if (FAILED(pSSF->Count(&cStreams))) { + continue; + } + for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { + DWORD dwFlags, dwGroup; + CComHeapPtr pName; + if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, &pName, nullptr, nullptr))) { + continue; + } + if (dwGroup != 2) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + if (pstrName) + *pstrName = pName; + return idx; + } + } + idx++; + } + } else { + CComPtr pSubStream = subInput.pSubStream; + if (!pSubStream) { + continue; + } + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + if (pstrName) { + CComHeapPtr pName; + pSubStream->GetStreamInfo(pSubStream->GetStream(), &pName, nullptr); + *pstrName = pName; + } + return idx + pSubStream->GetStream(); + } + idx += pSubStream->GetStreamCount(); + } + } + } else if (m_pSplitterSS) { + DWORD cStreams; + if (SUCCEEDED(m_pSplitterSS->Count(&cStreams))) { + int idx = 0; + for (int i = 0; i < (int)cStreams; i++) { + DWORD dwFlags, dwGroup; + CComHeapPtr pszName; + + if (FAILED(m_pSplitterSS->Info(i, nullptr, &dwFlags, nullptr, &dwGroup, &pszName, nullptr, nullptr))) + continue; + + if (dwGroup != 2) + continue; + + if (dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + if (pstrName) + *pstrName = pszName; + return idx; + } + + idx++; + } + } + } + + return -1; +} + +REFERENCE_TIME CMainFrame::GetPos() const +{ + return (GetLoadState() == MLS::LOADED ? m_wndSeekBar.GetPos() : 0); +} + +REFERENCE_TIME CMainFrame::GetDur() const +{ + __int64 start, stop; + m_wndSeekBar.GetRange(start, stop); + return (GetLoadState() == MLS::LOADED ? stop : 0); +} + +void CMainFrame::LoadKeyFrames() +{ + UINT nKFs = 0; + m_kfs.clear(); + if (m_pKFI && S_OK == m_pKFI->GetKeyFrameCount(nKFs) && nKFs > 1) { + UINT k = nKFs; + m_kfs.resize(k); + if (FAILED(m_pKFI->GetKeyFrames(&TIME_FORMAT_MEDIA_TIME, m_kfs.data(), k)) || k != nKFs) { + m_kfs.clear(); + } + } +} + +bool CMainFrame::GetKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMin, REFERENCE_TIME rtMax, bool nearest, REFERENCE_TIME& keyframetime) const +{ + ASSERT(rtTarget >= rtMin); + ASSERT(rtTarget <= rtMax); + if (!m_kfs.empty()) { + const auto cbegin = m_kfs.cbegin(); + const auto cend = m_kfs.cend(); + ASSERT(std::is_sorted(cbegin, cend)); + + auto foundkeyframe = std::lower_bound(cbegin, cend, rtTarget); + + if (foundkeyframe == cbegin) { + // first keyframe + keyframetime = *foundkeyframe; + if ((keyframetime < rtMin) || (keyframetime > rtMax)) { + keyframetime = rtTarget; + return false; + } + } else if (foundkeyframe == cend) { + // last keyframe + keyframetime = *(--foundkeyframe); + if (keyframetime < rtMin) { + keyframetime = rtTarget; + return false; + } + } else { + keyframetime = *foundkeyframe; + if (keyframetime == rtTarget) { + return true; + } + if (keyframetime > rtMax) { + // use preceding keyframe + keyframetime = *(--foundkeyframe); + if (keyframetime < rtMin) { + keyframetime = rtTarget; + return false; + } + } else { + if (nearest) { + const auto& s = AfxGetAppSettings(); + if (s.eFastSeekMethod == s.FASTSEEK_NEAREST_KEYFRAME) { + // use closest keyframe + REFERENCE_TIME prev_keyframetime = *(--foundkeyframe); + if ((prev_keyframetime >= rtMin)) { + if ((keyframetime - rtTarget) > (rtTarget - prev_keyframetime)) { + keyframetime = prev_keyframetime; + } + } + } + } + } + } + return true; + } else { + keyframetime = rtTarget; + } + return false; +} + +REFERENCE_TIME CMainFrame::GetClosestKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMaxForwardDiff, REFERENCE_TIME rtMaxBackwardDiff) const +{ + if (rtTarget < 0LL) return 0LL; + if (rtTarget > GetDur()) return rtTarget; + + REFERENCE_TIME rtKeyframe; + REFERENCE_TIME rtMin = std::max(rtTarget - rtMaxBackwardDiff, 0LL); + REFERENCE_TIME rtMax = rtTarget + rtMaxForwardDiff; + + if (GetKeyFrame(rtTarget, rtMin, rtMax, true, rtKeyframe)) { + return rtKeyframe; + } + return rtTarget; +} + +REFERENCE_TIME CMainFrame::GetClosestKeyFramePreview(REFERENCE_TIME rtTarget) const +{ + return GetClosestKeyFrame(rtTarget, 200000000LL, 200000000LL); +} + +void CMainFrame::SeekTo(REFERENCE_TIME rtPos, bool bShowOSD /*= true*/) +{ + if (m_pMS == nullptr) { + return; + } + ASSERT(lastSeekFinish >= lastSeekStart); // ToDo: remove lastSeekStart variable if no regressions show up + ULONGLONG curTime = GetTickCount64(); + ULONGLONG ticksSinceLastSeek = curTime - lastSeekFinish; + ULONGLONG mindelay = (lastSeekFinish - lastSeekStart) > 40ULL ? 100ULL : 40ULL; + //ASSERT(rtPos != queuedSeek.rtPos || queuedSeek.seekTime == 0 || (curTime < queuedSeek.seekTime + 500ULL)); + + if (ticksSinceLastSeek < mindelay) { + //TRACE(_T("Delay seek: %lu %lu\n"), rtPos, ticksSinceLastSeek); + queuedSeek = { rtPos, curTime, bShowOSD }; + SetTimer(TIMER_DELAYEDSEEK, (UINT) (mindelay * 1.25 - ticksSinceLastSeek), nullptr); + } else { + KillTimerDelayedSeek(); + lastSeekStart = curTime; + DoSeekTo(rtPos, bShowOSD); + lastSeekFinish = GetTickCount64(); + } +} + +void CMainFrame::DoSeekTo(REFERENCE_TIME rtPos, bool bShowOSD /*= true*/) +{ + //TRACE(_T("DoSeekTo: %lu\n"), rtPos); + + ASSERT(m_pMS != nullptr); + if (m_pMS == nullptr) { + return; + } + OAFilterState fs = GetMediaState(); + + if (rtPos < 0) { + rtPos = 0; + } + + if (abRepeat.positionA && rtPos < abRepeat.positionA || abRepeat.positionB && rtPos > abRepeat.positionB) { + DisableABRepeat(); + } + + if (m_fFrameSteppingActive) { + // Cancel pending frame steps + m_pFS->CancelStep(); + m_fFrameSteppingActive = false; + if (m_pBA) { + m_pBA->put_Volume(m_nVolumeBeforeFrameStepping); + } + } + m_nStepForwardCount = 0; + + // skip seeks when duration is unknown + if (!m_wndSeekBar.HasDuration()) { + return; + } + + if (!IsPlaybackCaptureMode()) { + __int64 start, stop; + m_wndSeekBar.GetRange(start, stop); + if (rtPos > stop) { + rtPos = stop; + } + m_wndStatusBar.SetStatusTimer(rtPos, stop, IsSubresyncBarVisible(), GetTimeFormat()); + + if (bShowOSD) { + m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 1500); + } + } + + if (GetPlaybackMode() == PM_FILE) { + if (fs == State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + + //SleepEx(5000, False); // artificial slow seek for testing purposes + if (FAILED(m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning))) { + TRACE(_T("IMediaSeeking SetPositions failure\n")); + if (abRepeat.positionA && rtPos == abRepeat.positionA) { + DisableABRepeat(); + } + } + UpdateChapterInInfoBar(); + } else if (GetPlaybackMode() == PM_DVD && m_iDVDDomain == DVD_DOMAIN_Title) { + if (fs == State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + fs = State_Paused; + } + + const REFTIME refAvgTimePerFrame = GetAvgTimePerFrame(); + if (fs == State_Paused) { + // Jump one more frame back, this is needed because we don't have any other + // way to seek to specific time without running playback to refresh state. + rtPos -= std::llround(refAvgTimePerFrame * 10000000i64); + m_pFS->CancelStep(); + } + + DVD_HMSF_TIMECODE tc = RT2HMSF(rtPos, (1.0 / refAvgTimePerFrame)); + m_pDVDC->PlayAtTime(&tc, DVD_CMD_FLAG_Block | DVD_CMD_FLAG_Flush, nullptr); + + if (fs == State_Paused) { + // Do frame step to update current position in paused state + m_pFS->Step(1, nullptr); + } + } else { + ASSERT(FALSE); + } + m_fEndOfStream = false; + + OnTimer(TIMER_STREAMPOSPOLLER); + OnTimer(TIMER_STREAMPOSPOLLER2); + + SendCurrentPositionToApi(true); +} + +void CMainFrame::CleanGraph() +{ + if (!m_pGB) { + return; + } + + BeginEnumFilters(m_pGB, pEF, pBF) { + CComQIPtr pAMMF(pBF); + if (pAMMF && (pAMMF->GetMiscFlags()&AM_FILTER_MISC_FLAGS_IS_SOURCE)) { + continue; + } + + // some capture filters forget to set AM_FILTER_MISC_FLAGS_IS_SOURCE + // or to implement the IAMFilterMiscFlags interface + if (pBF == m_pVidCap || pBF == m_pAudCap) { + continue; + } + + // XySubFilter doesn't have any pins connected when it is reading + // external subtitles + if (GetCLSID(pBF) == CLSID_XySubFilter) { + continue; + } + + if (CComQIPtr(pBF)) { + continue; + } + + int nIn, nOut, nInC, nOutC; + if (CountPins(pBF, nIn, nOut, nInC, nOutC) > 0 && (nInC + nOutC) == 0) { + TRACE(CStringW(L"Removing: ") + GetFilterName(pBF) + '\n'); + + m_pGB->RemoveFilter(pBF); + pEF->Reset(); + } + } + EndEnumFilters; +} + +#define AUDIOBUFFERLEN 500 + +static void SetLatency(IBaseFilter* pBF, int cbBuffer) +{ + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pAMBN = pPin) { + ALLOCATOR_PROPERTIES ap; + ap.cbAlign = -1; // -1 means no preference. + ap.cbBuffer = cbBuffer; + ap.cbPrefix = -1; + ap.cBuffers = -1; + pAMBN->SuggestAllocatorProperties(&ap); + } + } + EndEnumPins; +} + +HRESULT CMainFrame::BuildCapture(IPin* pPin, IBaseFilter* pBF[3], const GUID& majortype, AM_MEDIA_TYPE* pmt) +{ + IBaseFilter* pBuff = pBF[0]; + IBaseFilter* pEnc = pBF[1]; + IBaseFilter* pMux = pBF[2]; + + if (!pPin || !pMux) { + return E_FAIL; + } + + CString err; + HRESULT hr = S_OK; + CFilterInfo fi; + + if (FAILED(pMux->QueryFilterInfo(&fi)) || !fi.pGraph) { + m_pGB->AddFilter(pMux, L"Multiplexer"); + } + + CStringW prefix; + CString type; + if (majortype == MEDIATYPE_Video) { + prefix = L"Video "; + type.LoadString(IDS_CAPTURE_ERROR_VIDEO); + } else if (majortype == MEDIATYPE_Audio) { + prefix = L"Audio "; + type.LoadString(IDS_CAPTURE_ERROR_AUDIO); + } + + if (pBuff) { + hr = m_pGB->AddFilter(pBuff, prefix + L"Buffer"); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_ADD_BUFFER, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + + hr = m_pGB->ConnectFilter(pPin, pBuff); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_CONNECT_BUFF, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + + pPin = GetFirstPin(pBuff, PINDIR_OUTPUT); + } + + if (pEnc) { + hr = m_pGB->AddFilter(pEnc, prefix + L"Encoder"); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_ADD_ENCODER, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + + hr = m_pGB->ConnectFilter(pPin, pEnc); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_CONNECT_ENC, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + + pPin = GetFirstPin(pEnc, PINDIR_OUTPUT); + + if (CComQIPtr pAMSC = pPin) { + if (pmt->majortype == majortype) { + hr = pAMSC->SetFormat(pmt); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_COMPRESSION, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + } + } + + } + + //if (pMux) + { + hr = m_pGB->ConnectFilter(pPin, pMux); + if (FAILED(hr)) { + err.Format(IDS_CAPTURE_ERROR_MULTIPLEXER, type.GetString()); + MessageBox(err, ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return hr; + } + } + + CleanGraph(); + + return S_OK; +} + +bool CMainFrame::BuildToCapturePreviewPin( + IBaseFilter* pVidCap, IPin** ppVidCapPin, IPin** ppVidPrevPin, + IBaseFilter* pAudCap, IPin** ppAudCapPin, IPin** ppAudPrevPin) +{ + HRESULT hr; + *ppVidCapPin = *ppVidPrevPin = nullptr; + *ppAudCapPin = *ppAudPrevPin = nullptr; + CComPtr pDVAudPin; + + if (pVidCap) { + CComPtr pPin; + if (!pAudCap // only look for interleaved stream when we don't use any other audio capture source + && SUCCEEDED(m_pCGB->FindPin(pVidCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, TRUE, 0, &pPin))) { + CComPtr pDVSplitter; + hr = pDVSplitter.CoCreateInstance(CLSID_DVSplitter); + hr = m_pGB->AddFilter(pDVSplitter, L"DV Splitter"); + + hr = m_pCGB->RenderStream(nullptr, &MEDIATYPE_Interleaved, pPin, nullptr, pDVSplitter); + + pPin = nullptr; + hr = m_pCGB->FindPin(pDVSplitter, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Video, TRUE, 0, &pPin); + hr = m_pCGB->FindPin(pDVSplitter, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Audio, TRUE, 0, &pDVAudPin); + + CComPtr pDVDec; + hr = pDVDec.CoCreateInstance(CLSID_DVVideoCodec); + hr = m_pGB->AddFilter(pDVDec, L"DV Video Decoder"); + + hr = m_pGB->ConnectFilter(pPin, pDVDec); + + pPin = nullptr; + hr = m_pCGB->FindPin(pDVDec, PINDIR_OUTPUT, nullptr, &MEDIATYPE_Video, TRUE, 0, &pPin); + } else if (FAILED(m_pCGB->FindPin(pVidCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, TRUE, 0, &pPin))) { + MessageBox(ResStr(IDS_CAPTURE_ERROR_VID_CAPT_PIN), ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return false; + } + + CComPtr pSmartTee; + hr = pSmartTee.CoCreateInstance(CLSID_SmartTee); + hr = m_pGB->AddFilter(pSmartTee, L"Smart Tee (video)"); + + hr = m_pGB->ConnectFilter(pPin, pSmartTee); + + hr = pSmartTee->FindPin(L"Preview", ppVidPrevPin); + hr = pSmartTee->FindPin(L"Capture", ppVidCapPin); + } + + if (pAudCap || pDVAudPin) { + CComPtr pPin; + if (pDVAudPin) { + pPin = pDVAudPin; + } else if (FAILED(m_pCGB->FindPin(pAudCap, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, TRUE, 0, &pPin))) { + MessageBox(ResStr(IDS_CAPTURE_ERROR_AUD_CAPT_PIN), ResStr(IDS_CAPTURE_ERROR), MB_ICONERROR | MB_OK); + return false; + } + + CComPtr pSmartTee; + hr = pSmartTee.CoCreateInstance(CLSID_SmartTee); + hr = m_pGB->AddFilter(pSmartTee, L"Smart Tee (audio)"); + + hr = m_pGB->ConnectFilter(pPin, pSmartTee); + + hr = pSmartTee->FindPin(L"Preview", ppAudPrevPin); + hr = pSmartTee->FindPin(L"Capture", ppAudCapPin); + } + + return true; +} + +bool CMainFrame::BuildGraphVideoAudio(int fVPreview, bool fVCapture, int fAPreview, bool fACapture) +{ + if (!m_pCGB) { + return false; + } + + OAFilterState fs = GetMediaState(); + + if (fs != State_Stopped) { + SendMessage(WM_COMMAND, ID_PLAY_STOP); + } + + HRESULT hr; + + m_pGB->NukeDownstream(m_pVidCap); + m_pGB->NukeDownstream(m_pAudCap); + + CleanGraph(); + + if (m_pAMVSCCap) { + hr = m_pAMVSCCap->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv); + } + if (m_pAMVSCPrev) { + hr = m_pAMVSCPrev->SetFormat(&m_wndCaptureBar.m_capdlg.m_mtv); + } + if (m_pAMASC) { + hr = m_pAMASC->SetFormat(&m_wndCaptureBar.m_capdlg.m_mta); + } + + CComPtr pVidBuffer = m_wndCaptureBar.m_capdlg.m_pVidBuffer; + CComPtr pAudBuffer = m_wndCaptureBar.m_capdlg.m_pAudBuffer; + CComPtr pVidEnc = m_wndCaptureBar.m_capdlg.m_pVidEnc; + CComPtr pAudEnc = m_wndCaptureBar.m_capdlg.m_pAudEnc; + CComPtr pMux = m_wndCaptureBar.m_capdlg.m_pMux; + CComPtr pDst = m_wndCaptureBar.m_capdlg.m_pDst; + CComPtr pAudMux = m_wndCaptureBar.m_capdlg.m_pAudMux; + CComPtr pAudDst = m_wndCaptureBar.m_capdlg.m_pAudDst; + + bool fFileOutput = (pMux && pDst) || (pAudMux && pAudDst); + bool fCapture = (fVCapture || fACapture); + + if (m_pAudCap) { + AM_MEDIA_TYPE* pmt = &m_wndCaptureBar.m_capdlg.m_mta; + int ms = (fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput) ? AUDIOBUFFERLEN : 60; + if (pMux != pAudMux && fACapture) { + SetLatency(m_pAudCap, -1); + } else if (pmt->pbFormat) { + SetLatency(m_pAudCap, ((WAVEFORMATEX*)pmt->pbFormat)->nAvgBytesPerSec * ms / 1000); + } + } + + CComPtr pVidCapPin, pVidPrevPin, pAudCapPin, pAudPrevPin; + BuildToCapturePreviewPin(m_pVidCap, &pVidCapPin, &pVidPrevPin, m_pAudCap, &pAudCapPin, &pAudPrevPin); + + //if (m_pVidCap) + { + bool fVidPrev = pVidPrevPin && fVPreview; + bool fVidCap = pVidCapPin && fVCapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fVidOutput; + + if (fVPreview == 2 && !fVidCap && pVidCapPin) { + pVidPrevPin = pVidCapPin; + pVidCapPin = nullptr; + } + + if (fVidPrev) { + m_pMVRS.Release(); + m_pMVRFG.Release(); + m_pMVRSR.Release(); + + m_OSD.Stop(); + m_pCAP3.Release(); + m_pCAP2.Release(); + m_pCAP.Release(); + m_pVMRWC.Release(); + m_pVMRMC.Release(); + m_pVMB.Release(); + m_pMFVMB.Release(); + m_pMFVP.Release(); + m_pMFVDC.Release(); + m_pQP.Release(); + + m_pGB->Render(pVidPrevPin); + + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP2), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pCAP3), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRWC), FALSE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMRMC), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pVMB), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVMB), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVDC), TRUE); + m_pGB->FindInterface(IID_PPV_ARGS(&m_pMFVP), TRUE); + m_pMVTO = m_pCAP; + m_pMVRSR = m_pCAP; + m_pMVRS = m_pCAP; + m_pMVRFG = m_pCAP; + + const CAppSettings& s = AfxGetAppSettings(); + m_pVideoWnd = &m_wndView; + + if (m_pMFVDC) { + m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd); + } else if (m_pVMRWC) { + m_pVMRWC->SetVideoClippingWindow(m_pVideoWnd->m_hWnd); + } + + if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is used + m_OSD.Stop(); + + if (m_pMVTO) { + m_OSD.Start(m_pVideoWnd, m_pMVTO); + } else if (m_fFullScreen && !m_fAudioOnly && m_pCAP3) { // MPCVR + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, false); + } else if (!m_fAudioOnly && IsD3DFullScreenMode() && (m_pVMB || m_pMFVMB)) { + m_OSD.Start(m_pVideoWnd, m_pVMB, m_pMFVMB, true); + } else { + m_OSD.Start(m_pOSDWnd); + } + } + } + + if (fVidCap) { + IBaseFilter* pBF[3] = {pVidBuffer, pVidEnc, pMux}; + HRESULT hr2 = BuildCapture(pVidCapPin, pBF, MEDIATYPE_Video, &m_wndCaptureBar.m_capdlg.m_mtcv); + UNREFERENCED_PARAMETER(hr2); + } + + m_pAMDF.Release(); + if (FAILED(m_pCGB->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pVidCap, IID_PPV_ARGS(&m_pAMDF)))) { + TRACE(_T("Warning: No IAMDroppedFrames interface for vidcap capture")); + } + } + + //if (m_pAudCap) + { + bool fAudPrev = pAudPrevPin && fAPreview; + bool fAudCap = pAudCapPin && fACapture && fFileOutput && m_wndCaptureBar.m_capdlg.m_fAudOutput; + + if (fAPreview == 2 && !fAudCap && pAudCapPin) { + pAudPrevPin = pAudCapPin; + pAudCapPin = nullptr; + } + + if (fAudPrev) { + m_pGB->Render(pAudPrevPin); + } + + if (fAudCap) { + IBaseFilter* pBF[3] = {pAudBuffer, pAudEnc, pAudMux ? pAudMux : pMux}; + HRESULT hr2 = BuildCapture(pAudCapPin, pBF, MEDIATYPE_Audio, &m_wndCaptureBar.m_capdlg.m_mtca); + UNREFERENCED_PARAMETER(hr2); + } + } + + if ((m_pVidCap || m_pAudCap) && fCapture && fFileOutput) { + if (pMux != pDst) { + hr = m_pGB->AddFilter(pDst, L"File Writer V/A"); + hr = m_pGB->ConnectFilter(GetFirstPin(pMux, PINDIR_OUTPUT), pDst); + } + + if (CComQIPtr pCAM = pMux) { + int nIn, nOut, nInC, nOutC; + CountPins(pMux, nIn, nOut, nInC, nOutC); + pCAM->SetMasterStream(nInC - 1); + //pCAM->SetMasterStream(-1); + pCAM->SetOutputCompatibilityIndex(FALSE); + } + + if (CComQIPtr pCI = pMux) { + //if (FAILED(pCI->put_Mode(INTERLEAVE_CAPTURE))) + if (FAILED(pCI->put_Mode(INTERLEAVE_NONE_BUFFERED))) { + pCI->put_Mode(INTERLEAVE_NONE); + } + + REFERENCE_TIME rtInterleave = 10000i64 * AUDIOBUFFERLEN, rtPreroll = 0; //10000i64*500 + pCI->put_Interleaving(&rtInterleave, &rtPreroll); + } + + if (pMux != pAudMux && pAudMux != pAudDst) { + hr = m_pGB->AddFilter(pAudDst, L"File Writer A"); + hr = m_pGB->ConnectFilter(GetFirstPin(pAudMux, PINDIR_OUTPUT), pAudDst); + } + } + + REFERENCE_TIME stop = MAX_TIME; + hr = m_pCGB->ControlStream(&PIN_CATEGORY_CAPTURE, nullptr, nullptr, nullptr, &stop, 0, 0); // stop in the infinite + + CleanGraph(); + + OpenSetupVideo(); + OpenSetupAudio(); + OpenSetupStatsBar(); + OpenSetupStatusBar(); + RecalcLayout(); + + SetupVMR9ColorControl(); + + if (GetLoadState() == MLS::LOADED) { + if (fs == State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } else if (fs == State_Paused) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + } + + return true; +} + +bool CMainFrame::StartCapture() +{ + if (!m_pCGB || m_fCapturing) { + return false; + } + + if (!m_wndCaptureBar.m_capdlg.m_pMux && !m_wndCaptureBar.m_capdlg.m_pDst) { + return false; + } + + HRESULT hr; + + ::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS); + + // rare to see two capture filters to support IAMPushSource at the same time... + //hr = CComQIPtr(m_pGB)->SyncUsingStreamOffset(TRUE); // TODO: + + BuildGraphVideoAudio( + m_wndCaptureBar.m_capdlg.m_fVidPreview, true, + m_wndCaptureBar.m_capdlg.m_fAudPreview, true); + + hr = m_pME->CancelDefaultHandling(EC_REPAINT); + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + m_fCapturing = true; + + return true; +} + +bool CMainFrame::StopCapture() +{ + if (!m_pCGB || !m_fCapturing) { + return false; + } + + if (!m_wndCaptureBar.m_capdlg.m_pMux && !m_wndCaptureBar.m_capdlg.m_pDst) { + return false; + } + + m_wndStatusBar.SetStatusMessage(StrRes(IDS_CONTROLS_COMPLETING)); + m_fCapturing = false; + + BuildGraphVideoAudio( + m_wndCaptureBar.m_capdlg.m_fVidPreview, false, + m_wndCaptureBar.m_capdlg.m_fAudPreview, false); + + m_pME->RestoreDefaultHandling(EC_REPAINT); + + ::SetPriorityClass(::GetCurrentProcess(), AfxGetAppSettings().dwPriority); + + m_rtDurationOverride = -1; + + return true; +} + +// + +void CMainFrame::ShowOptions(int idPage/* = 0*/) +{ + // Disable the options dialog when using D3D fullscreen + if (IsD3DFullScreenMode() && !m_bFullScreenWindowIsOnSeparateDisplay) { + return; + } + + // show warning when INI file is read-only + CPath iniPath = AfxGetMyApp()->GetIniPath(); + if (PathUtils::Exists(iniPath)) { + HANDLE hFile = CreateFile(iniPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + AfxMessageBox(_T("The player settings are currently stored in an INI file located in the installation directory of the player.\n\nThe player currently does not have write access to this file, meaning any changes to the settings will not be saved.\n\nPlease remove the INI file to ensure proper functionality of the player.\n\nSettings will then be stored in the Windows Registry. You can easily backup those settings through: Options > Miscellaneous > Export"), MB_ICONWARNING, 0); + } + CloseHandle(hFile); + } + + INT_PTR iRes; + do { + CPPageSheet options(ResStr(IDS_OPTIONS_CAPTION), m_pGB, GetModalParent(), idPage); + iRes = options.DoModal(); + idPage = 0; // If we are to show the dialog again, always show the latest page + } while (iRes == CPPageSheet::APPLY_LANGUAGE_CHANGE); // check if we exited the dialog so that the language change can be applied + + switch (iRes) { + case CPPageSheet::RESET_SETTINGS: + // Request MPC-HC to close itself + SendMessage(WM_CLOSE); + // and immediately reopen + ShellExecute(nullptr, _T("open"), PathUtils::GetProgramPath(true), _T("/reset"), nullptr, SW_SHOWNORMAL); + break; + default: + ASSERT(iRes > 0 && iRes != CPPageSheet::APPLY_LANGUAGE_CHANGE); + break; + } +} + +void CMainFrame::StartWebServer(int nPort) +{ + if (!m_pWebServer) { + m_pWebServer.Attach(DEBUG_NEW CWebServer(this, nPort)); + } +} + +void CMainFrame::StopWebServer() +{ + if (m_pWebServer) { + m_pWebServer.Free(); + } +} + +void CMainFrame::SendStatusMessage(CString msg, int nTimeOut) +{ + const auto timerId = TimerOneTimeSubscriber::STATUS_ERASE; + + m_timerOneTime.Unsubscribe(timerId); + + m_tempstatus_msg.Empty(); + if (nTimeOut <= 0) { + return; + } + + m_tempstatus_msg = msg; + m_timerOneTime.Subscribe(timerId, [this] { m_tempstatus_msg.Empty(); }, nTimeOut); + + m_Lcd.SetStatusMessage(msg, nTimeOut); +} + +bool CMainFrame::CanPreviewUse() { + return (m_bUseSeekPreview && m_wndPreView && !m_fAudioOnly && m_eMediaLoadState == MLS::LOADED + && (GetPlaybackMode() == PM_DVD || GetPlaybackMode() == PM_FILE)); +} + +void CMainFrame::OpenCurPlaylistItem(REFERENCE_TIME rtStart, bool reopen /* = false */, ABRepeat abRepeat /* = ABRepeat() */) +{ + if (IsPlaylistEmpty()) { + return; + } + + CPlaylistItem pli; + if (!m_wndPlaylistBar.GetCur(pli)) { + m_wndPlaylistBar.SetFirstSelected(); + if (!m_wndPlaylistBar.GetCur(pli)) { + return; + } + } + + if (pli.m_bYoutubeDL && (reopen || pli.m_fns.GetHead() == pli.m_ydlSourceURL && m_sydlLastProcessURL != pli.m_ydlSourceURL)) { + if (ProcessYoutubeDLURL(pli.m_ydlSourceURL, false, true)) { + OpenCurPlaylistItem(rtStart, false); + return; + } + } + + CAutoPtr p(m_wndPlaylistBar.GetCurOMD(rtStart, abRepeat)); + if (p) { + OpenMedia(p); + } +} + +void CMainFrame::AddCurDevToPlaylist() +{ + if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + m_wndPlaylistBar.Append( + m_VidDispName, + m_AudDispName, + m_wndCaptureBar.m_capdlg.GetVideoInput(), + m_wndCaptureBar.m_capdlg.GetVideoChannel(), + m_wndCaptureBar.m_capdlg.GetAudioInput() + ); + } +} + +void CMainFrame::OpenMedia(CAutoPtr pOMD) +{ + auto pFileData = dynamic_cast(pOMD.m_p); + //auto pDVDData = dynamic_cast(pOMD.m_p); + auto pDeviceData = dynamic_cast(pOMD.m_p); + + // if the tuner graph is already loaded, we just change its channel + if (pDeviceData) { + if (GetLoadState() == MLS::LOADED && m_pAMTuner + && m_VidDispName == pDeviceData->DisplayName[0] && m_AudDispName == pDeviceData->DisplayName[1]) { + m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput); + m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel); + m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput); + SendNowPlayingToSkype(); + return; + } + } + + CloseMediaBeforeOpen(); + + // if the file is on some removable drive and that drive is missing, + // we yell at user before even trying to construct the graph + if (pFileData) { + CString fn = pFileData->fns.GetHead(); + int i = fn.Find(_T(":\\")); + if (i > 0) { + CString drive = fn.Left(i + 2); + UINT type = GetDriveType(drive); + CAtlList sl; + if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM && GetOpticalDiskType(drive[0], sl) != OpticalDisk_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.GetString()); + ret = AfxMessageBox(msg, MB_RETRYCANCEL); + } + } + if (ret != IDOK) { + return; + } + } + } + } + + ASSERT(!m_bOpenMediaActive); + m_bOpenMediaActive = true; + + // clear BD playlist if we are not currently opening something from it + if (!m_bIsBDPlay) { + m_MPLSPlaylist.clear(); + m_LastOpenBDPath = _T(""); + } + m_bIsBDPlay = false; + + // no need to try releasing external objects while playing + KillTimer(TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS); + + // we hereby proclaim + SetLoadState(MLS::LOADING); + + const auto& s = AfxGetAppSettings(); + + // use the graph thread only for some media types + bool bDirectShow = pFileData && !pFileData->fns.IsEmpty() && s.m_Formats.GetEngine(pFileData->fns.GetHead()) == DirectShow; + bool bUseThread = m_pGraphThread && s.fEnableWorkerThreadForOpening && (bDirectShow || !pFileData) && (s.iDefaultCaptureDevice == 1 || !pDeviceData); + bool wasMaximized = IsZoomed(); + // create d3dfs window if launching in fullscreen and d3dfs is enabled + if (s.IsD3DFullscreen() && m_fStartInD3DFullscreen) { + CreateFullScreenWindow(); + m_pVideoWnd = m_pDedicatedFSVideoWnd; + m_fStartInD3DFullscreen = false; + } else if (m_fStartInFullscreenSeparate) { + CreateFullScreenWindow(false); + m_pVideoWnd = m_pDedicatedFSVideoWnd; + m_fStartInFullscreenSeparate = false; + m_bNeedZoomAfterFullscreenExit = true; + } else { + m_pVideoWnd = &m_wndView; + } + + // activate auto-fit logic upon exiting fullscreen if + // we are opening new media in fullscreen mode + // adipose: unless we were previously maximized + if ((IsFullScreenMode()) && s.fRememberZoomLevel && !wasMaximized) { + m_bNeedZoomAfterFullscreenExit = true; + } + + // don't set video renderer output rect until the window is repositioned + m_bDelaySetOutputRect = true; + +#if 0 + // display corresponding media icon in status bar + if (pFileData) { + CString filename = m_wndPlaylistBar.GetCurFileName(); + CString ext = filename.Mid(filename.ReverseFind('.') + 1); + m_wndStatusBar.SetMediaType(ext); + } else if (pDVDData) { + m_wndStatusBar.SetMediaType(_T(".ifo")); + } else { + // TODO: Create icons for pDeviceData + m_wndStatusBar.SetMediaType(_T(".unknown")); + } +#endif + + // initiate graph creation, OpenMediaPrivate() will call OnFilePostOpenmedia() + if (bUseThread) { + VERIFY(m_evOpenPrivateFinished.Reset()); + VERIFY(m_pGraphThread->PostThreadMessage(CGraphThread::TM_OPEN, (WPARAM)0, (LPARAM)pOMD.Detach())); + m_bOpenedThroughThread = true; + } else { + OpenMediaPrivate(pOMD); + m_bOpenedThroughThread = false; + } +} + +bool CMainFrame::ResetDevice() +{ + if (m_pCAP2_preview) { + m_pCAP2_preview->ResetDevice(); + } + if (m_pCAP) { + return m_pCAP->ResetDevice(); + } + return true; +} + +bool CMainFrame::DisplayChange() +{ + if (m_pCAP2_preview) { + m_pCAP2_preview->DisplayChange(); + } + if (m_pCAP) { + return m_pCAP->DisplayChange(); + } + return true; +} + +void CMainFrame::CloseMediaBeforeOpen() +{ + if (GetLoadState() != MLS::CLOSED) { + CloseMedia(true); + } +} + +void CMainFrame::ForceCloseProcess() +{ + MessageBeep(MB_ICONEXCLAMATION); + if (CrashReporter::IsEnabled()) { + CrashReporter::Disable(); + } + TerminateProcess(GetCurrentProcess(), 0xDEADBEEF); +} + +void CMainFrame::CloseMedia(bool bNextIsQueued/* = false*/, bool bPendingFileDelete/* = false*/) +{ + TRACE(_T("CMainFrame::CloseMedia\n")); + + m_dwLastPause = 0; + + if (m_bUseSeekPreview && m_wndPreView.IsWindowVisible()) { + m_wndPreView.ShowWindow(SW_HIDE); + } + m_bUseSeekPreview = false; + m_bDVDStillOn = false; + + if (GetLoadState() == MLS::CLOSING || GetLoadState() == MLS::CLOSED) { + TRACE(_T("Ignoring duplicate close action.\n")); + return; + } + + m_media_trans_control.close(); + + if (m_bSettingUpMenus) { + SleepEx(500, false); + ASSERT(!m_bSettingUpMenus); + } + + auto& s = AfxGetAppSettings(); + bool savehistory = false; + if (GetLoadState() == MLS::LOADED) { + // abort sub search + m_pSubtitlesProviders->Abort(SubtitlesThreadType(STT_SEARCH | STT_DOWNLOAD)); + m_wndSubtitlesDownloadDialog.DoClear(); + + // save playback position + if (s.fKeepHistory && !bPendingFileDelete) { + if (m_bRememberFilePos && !m_fEndOfStream && m_dwReloadPos == 0 && m_pMS) { + REFERENCE_TIME rtNow = 0; + m_pMS->GetCurrentPosition(&rtNow); + if (rtNow > 0) { + REFERENCE_TIME rtDur = 0; + m_pMS->GetDuration(&rtDur); + if (rtNow >= rtDur || rtDur - rtNow < 50000000LL) { // at end of file + rtNow = 0; + } + } + s.MRU.UpdateCurrentFilePosition(rtNow, true); + } else if (GetPlaybackMode() == PM_DVD && m_pDVDI) { + DVD_DOMAIN DVDDomain; + if (SUCCEEDED(m_pDVDI->GetCurrentDomain(&DVDDomain))) { + if (DVDDomain == DVD_DOMAIN_Title) { + DVD_PLAYBACK_LOCATION2 Location2; + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location2))) { + DVD_POSITION dvdPosition = s.MRU.GetCurrentDVDPosition(); + if (dvdPosition.llDVDGuid) { + dvdPosition.lTitle = Location2.TitleNum; + dvdPosition.timecode = Location2.TimeCode; + } + } + } + } + } + } + + if (m_pME) { + m_pME->SetNotifyWindow(NULL, 0, 0); + } + + // save external subtitle + if (g_bExternalSubtitle && !bPendingFileDelete && + m_pCurrentSubInput.pSubStream && m_pCurrentSubInput.pSubStream->GetPath().IsEmpty()) { + const auto& s = AfxGetAppSettings(); + if (s.bAutoSaveDownloadedSubtitles) { + CString dirBuffer; + LPCTSTR dir = nullptr; + if (!s.strSubtitlePaths.IsEmpty()) { + auto start = s.strSubtitlePaths.Left(2); + if (start != _T(".") && start != _T(".;")) { + int pos = 0; + dir = dirBuffer = s.strSubtitlePaths.Tokenize(_T(";"), pos); + } + } + SubtitlesSave(dir, true); + } + } + + if (s.fKeepHistory && !bPendingFileDelete) { + savehistory = true; + } + } + + // delay showing auto-hidden controls if new media is queued + if (bNextIsQueued) { + m_controls.DelayShowNotLoaded(true); + } else { + m_controls.DelayShowNotLoaded(false); + } + + // abort if loading + bool bGraphTerminated = false; + if (GetLoadState() == MLS::LOADING) { + TRACE(_T("Media is still loading. Aborting graph.\n")); + + // tell OpenMediaPrivate() that we want to abort + m_fOpeningAborted = true; + + // close pin connection error dialog + if (mediaTypesErrorDlg) { + mediaTypesErrorDlg->SendMessage(WM_EXTERNALCLOSE, 0, 0); + // wait till error dialog has been closed + CAutoLock lck(&lockModalDialog); + } + + // abort current graph task + if (m_pGB) { + if (!m_pAMOP) { + m_pAMOP = m_pGB; + if (!m_pAMOP) { + BeginEnumFilters(m_pGB, pEF, pBF) + if (m_pAMOP = pBF) { + break; + } + EndEnumFilters; + } + } + if (m_pAMOP) { + m_pAMOP->AbortOperation(); + } + m_pGB->Abort(); // TODO: lock on graph objects somehow, this is not thread safe + } + if (m_pGB_preview) { + m_pGB_preview->Abort(); + } + + if (m_bOpenedThroughThread) { + BeginWaitCursor(); + MSG msg; + HANDLE h = m_evOpenPrivateFinished; + bool killprocess = true; + bool processmsg = true; + ULONGLONG start = GetTickCount64(); + while (processmsg && (GetTickCount64() - start < 6000ULL)) { + DWORD res = MsgWaitForMultipleObjectsEx(1, &h, 1000, QS_ALLINPUT, MWMO_INPUTAVAILABLE); + switch (res) { + case WAIT_OBJECT_0: + TRACE(_T("Graph abort successful\n")); + killprocess = false; // event has been signalled + processmsg = false; + break; + case WAIT_OBJECT_0 + 1: + // we have a message - peek and dispatch it + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + break; + case WAIT_TIMEOUT: + break; + default: // unexpected failure + processmsg = false; + break; + } + } + if (killprocess) + { + // Aborting graph failed + TRACE(_T("Failed to abort graph creation.\n")); + ForceCloseProcess(); + } + EndWaitCursor(); + } else { + // Aborting graph failed + TRACE(_T("Failed to abort graph creation.\n")); + ForceCloseProcess(); + } + + MSG msg; + // purge possible queued OnFilePostOpenmedia() + if (PeekMessage(&msg, m_hWnd, WM_POSTOPEN, WM_POSTOPEN, PM_REMOVE | PM_NOYIELD)) { + free((OpenMediaData*)msg.lParam); + } + // purge possible queued OnOpenMediaFailed() + if (PeekMessage(&msg, m_hWnd, WM_OPENFAILED, WM_OPENFAILED, PM_REMOVE | PM_NOYIELD)) { + free((OpenMediaData*)msg.lParam); + } + + // abort finished, unset the flag + m_fOpeningAborted = false; + } + + // we are on the way + m_bSettingUpMenus = true; + SetLoadState(MLS::CLOSING); + + if (m_pGB_preview) { + PreviewWindowHide(); + m_bUseSeekPreview = false; + } + + // stop the graph before destroying it + OnPlayStop(true); + + // clear any active osd messages + //m_OSD.ClearMessage(); + + // Ensure the dynamically added menu items are cleared and all references + // on objects belonging to the DirectShow graph they might hold are freed. + // Note that we need to be in closing state already when doing that + if (m_hWnd) { + SetupFiltersSubMenu(); + SetupAudioSubMenu(); + SetupSubtitlesSubMenu(); + SetupVideoStreamsSubMenu(); + SetupJumpToSubMenus(); + } + + m_bSettingUpMenus = false; + + // initiate graph destruction + if (m_pGraphThread && m_bOpenedThroughThread && !bGraphTerminated) { + // either opening or closing has to be blocked to prevent reentering them, closing is the better choice + VERIFY(m_evClosePrivateFinished.Reset()); + VERIFY(m_pGraphThread->PostThreadMessage(CGraphThread::TM_CLOSE, (WPARAM)0, (LPARAM)0)); + + HANDLE handle = m_evClosePrivateFinished; + DWORD dwWait; + ULONGLONG start = GetTickCount64(); + ULONGLONG waitdur = 10000ULL; + bool killprocess = true; + bool processmsg = true; + bool extendedwait = false; + while (processmsg) { + dwWait = MsgWaitForMultipleObjects(1, &handle, FALSE, 1000, QS_SENDMESSAGE); + switch (dwWait) { + case WAIT_OBJECT_0: + processmsg = false; // event received + killprocess = false; + break; + case WAIT_OBJECT_0 + 1: + MSG msg; + PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE); + break; + case WAIT_TIMEOUT: + break; + default: + processmsg = false; + break; + } + + if (processmsg && (GetTickCount64() - start > waitdur)) { + if (extendedwait || m_fFullScreen) { + processmsg = false; + } else { + CString msg; + if (!m_pGB && m_pGB_preview) { +#if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER && (MPC_VERSION_REV > 10) && 0 + if (CrashReporter::IsEnabled()) { + throw 1; + } +#endif + msg = L"Timeout when closing preview filter graph.\n\nClick YES to terminate player process. Click NO to wait longer (up to 15 seconds)."; + } else { + msg = L"Timeout when closing filter graph.\n\nClick YES to terminate player process. Click NO to wait longer (up to 15 seconds)."; + } + if (IDYES == AfxMessageBox(msg, MB_ICONEXCLAMATION | MB_YESNO, 0)) { + processmsg = false; + } else { + extendedwait = true; + start = GetTickCount64(); + waitdur = 15000ULL; + } + } + } + } + if (killprocess) { + TRACE(_T("Failed to close filter graph thread.\n")); + ForceCloseProcess(); + } + } else { + CloseMediaPrivate(); + } + + // graph is destroyed, update stuff + OnFilePostClosemedia(bNextIsQueued); + + if (savehistory) { + s.MRU.WriteCurrentEntry(); + } + s.MRU.current_rfe_hash.Empty(); + + TRACE(_T("Close media completed\n")); +} + +void CMainFrame::StartTunerScan(CAutoPtr pTSD) +{ + // Remove the old info during the scan + if (m_pDVBState) { + m_pDVBState->Reset(); + } + m_wndInfoBar.RemoveAllLines(); + m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); + RecalcLayout(); + OpenSetupWindowTitle(); + SendNowPlayingToSkype(); + + if (m_pGraphThread) { + m_pGraphThread->PostThreadMessage(CGraphThread::TM_TUNER_SCAN, (WPARAM)0, (LPARAM)pTSD.Detach()); + } else { + DoTunerScan(pTSD); + } +} + +void CMainFrame::StopTunerScan() +{ + m_bStopTunerScan = true; +} + +HRESULT CMainFrame::SetChannel(int nChannel) +{ + CAppSettings& s = AfxGetAppSettings(); + HRESULT hr = S_OK; + CComQIPtr pTun = m_pGB; + CBDAChannel* pChannel = s.FindChannelByPref(nChannel); + + if (s.m_DVBChannels.empty() && nChannel == INT_ERROR) { + hr = S_FALSE; // All channels have been cleared or it is the first start + } else if (pTun && pChannel && !m_pDVBState->bSetChannelActive) { + m_pDVBState->Reset(); + m_wndInfoBar.RemoveAllLines(); + m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); + RecalcLayout(); + m_pDVBState->bSetChannelActive = true; + + // Skip n intermediate ZoomVideoWindow() calls while the new size is stabilized: + switch (s.iDSVideoRendererType) { + case VIDRNDT_DS_MADVR: + if (s.nDVBStopFilterGraph == DVB_STOP_FG_ALWAYS) { + m_nLockedZoomVideoWindow = 3; + } else { + m_nLockedZoomVideoWindow = 0; + } + break; + case VIDRNDT_DS_EVR_CUSTOM: + m_nLockedZoomVideoWindow = 0; + break; + default: + m_nLockedZoomVideoWindow = 0; + } + if (SUCCEEDED(hr = pTun->SetChannel(nChannel))) { + if (hr == S_FALSE) { + // Re-create all + m_nLockedZoomVideoWindow = 0; + PostMessage(WM_COMMAND, ID_FILE_OPENDEVICE); + return hr; + } + + m_pDVBState->bActive = true; + m_pDVBState->pChannel = pChannel; + m_pDVBState->sChannelName = pChannel->GetName(); + + m_wndInfoBar.SetLine(ResStr(IDS_INFOBAR_CHANNEL), m_pDVBState->sChannelName); + RecalcLayout(); + + if (s.fRememberZoomLevel && !(m_fFullScreen || IsZoomed() || IsIconic())) { + ZoomVideoWindow(); + } + MoveVideoWindow(); + + // Add temporary flag to allow EC_VIDEO_SIZE_CHANGED event to stabilize window size + // for 5 seconds since playback starts + m_bAllowWindowZoom = true; + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::AUTOFIT_TIMEOUT, [this] + { m_bAllowWindowZoom = false; }, 5000); + + UpdateCurrentChannelInfo(); + } + m_pDVBState->bSetChannelActive = false; + } else { + hr = E_FAIL; + ASSERT(FALSE); + } + + return hr; +} + +void CMainFrame::UpdateCurrentChannelInfo(bool bShowOSD /*= true*/, bool bShowInfoBar /*= false*/) +{ + const CBDAChannel* pChannel = m_pDVBState->pChannel; + CComQIPtr pTun = m_pGB; + + if (!m_pDVBState->bInfoActive && pChannel && pTun) { + if (m_pDVBState->infoData.valid()) { + m_pDVBState->bAbortInfo = true; + m_pDVBState->infoData.get(); + } + m_pDVBState->bAbortInfo = false; + m_pDVBState->bInfoActive = true; + m_pDVBState->infoData = std::async(std::launch::async, [this, pChannel, pTun, bShowOSD, bShowInfoBar] { + DVBState::EITData infoData; + infoData.hr = pTun->UpdatePSI(pChannel, infoData.NowNext); + infoData.bShowOSD = bShowOSD; + infoData.bShowInfoBar = bShowInfoBar; + if (m_pDVBState && !m_pDVBState->bAbortInfo) + { + PostMessage(WM_DVB_EIT_DATA_READY); + } + return infoData; + }); + } +} + +LRESULT CMainFrame::OnCurrentChannelInfoUpdated(WPARAM wParam, LPARAM lParam) +{ + if (!m_pDVBState->bAbortInfo && m_pDVBState->infoData.valid()) { + EventDescriptor& NowNext = m_pDVBState->NowNext; + const auto infoData = m_pDVBState->infoData.get(); + NowNext = infoData.NowNext; + + if (infoData.hr != S_FALSE) { + // Set a timer to update the infos only if channel has now/next flag + time_t tNow; + time(&tNow); + time_t tElapse = NowNext.duration - (tNow - NowNext.startTime); + if (tElapse < 0) { + tElapse = 0; + } + // We set a 15s delay to let some room for the program infos to change + tElapse += 15; + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::DVBINFO_UPDATE, + [this] { UpdateCurrentChannelInfo(false, false); }, + 1000 * (UINT)tElapse); + m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(true); + } else { + m_wndNavigationBar.m_navdlg.SetChannelInfoAvailable(false); + } + + CString sChannelInfo = m_pDVBState->sChannelName; + m_wndInfoBar.RemoveAllLines(); + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CHANNEL), sChannelInfo); + + if (infoData.hr == S_OK) { + // EIT information parsed correctly + if (infoData.bShowOSD) { + sChannelInfo.AppendFormat(_T(" | %s (%s - %s)"), NowNext.eventName.GetString(), NowNext.strStartTime.GetString(), NowNext.strEndTime.GetString()); + } + + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TITLE), NowNext.eventName); + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_TIME), NowNext.strStartTime + _T(" - ") + NowNext.strEndTime); + + if (NowNext.parentalRating >= 0) { + CString parentRating; + if (!NowNext.parentalRating) { + parentRating.LoadString(IDS_NO_PARENTAL_RATING); + } else { + parentRating.Format(IDS_PARENTAL_RATING, NowNext.parentalRating); + } + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_PARENTAL_RATING), parentRating); + } + + if (!NowNext.content.IsEmpty()) { + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_CONTENT), NowNext.content); + } + + CString description = NowNext.eventDesc; + if (!NowNext.extendedDescriptorsText.IsEmpty()) { + if (!description.IsEmpty()) { + description += _T("; "); + } + description += NowNext.extendedDescriptorsText; + } + m_wndInfoBar.SetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); + + for (const auto& item : NowNext.extendedDescriptorsItems) { + m_wndInfoBar.SetLine(item.first, item.second); + } + + if (infoData.bShowInfoBar && !m_controls.ControlChecked(CMainFrameControls::Toolbar::INFO)) { + m_controls.ToggleControl(CMainFrameControls::Toolbar::INFO); + } + } + + RecalcLayout(); + if (infoData.bShowOSD) { + m_OSD.DisplayMessage(OSD_TOPLEFT, sChannelInfo, 3500); + } + + // Update window title and skype status + OpenSetupWindowTitle(); + SendNowPlayingToSkype(); + } else { + ASSERT(FALSE); + } + + m_pDVBState->bInfoActive = false; + + return 0; +} + +// ==== Added by CASIMIR666 +void CMainFrame::SetLoadState(MLS eState) +{ + m_eMediaLoadState = eState; + SendAPICommand(CMD_STATE, L"%d", static_cast(eState)); + if (eState == MLS::LOADED) { + m_controls.DelayShowNotLoaded(false); + m_eventc.FireEvent(MpcEvent::MEDIA_LOADED); + } + UpdateControlState(UPDATE_CONTROLS_VISIBILITY); +} + +inline MLS CMainFrame::GetLoadState() const +{ + return m_eMediaLoadState; +} + +void CMainFrame::SetPlayState(MPC_PLAYSTATE iState) +{ + m_Lcd.SetPlayState((CMPC_Lcd::PlayState)iState); + SendAPICommand(CMD_PLAYMODE, L"%d", iState); + + if (m_fEndOfStream) { + SendAPICommand(CMD_NOTIFYENDOFSTREAM, L"\0"); // do not pass NULL here! + } + + if (iState == PS_PLAY) { + // Prevent sleep when playing audio and/or video, but allow screensaver when only audio + if (!m_fAudioOnly && AfxGetAppSettings().bPreventDisplaySleep) { + SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED); + } else { + SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); + } + } else { + SetThreadExecutionState(ES_CONTINUOUS); + } + + + UpdateThumbarButton(iState); +} + +bool CMainFrame::CreateFullScreenWindow(bool isD3D /* = true */) +{ + if (m_bFullScreenWindowIsD3D == isD3D && HasDedicatedFSVideoWindow()) { + return false; + } + const CAppSettings& s = AfxGetAppSettings(); + CMonitors monitors; + CMonitor monitor, currentMonitor; + + if (m_pDedicatedFSVideoWnd->IsWindow()) { + m_pDedicatedFSVideoWnd->DestroyWindow(); + } + + currentMonitor = monitors.GetNearestMonitor(this); + if (s.iMonitor == 0) { + monitor = monitors.GetMonitor(s.strFullScreenMonitorID, s.strFullScreenMonitorDeviceName); + } + if (!monitor.IsMonitor()) { + monitor = currentMonitor; + } + + CRect monitorRect; + monitor.GetMonitorRect(monitorRect); + + m_bFullScreenWindowIsD3D = isD3D; + m_bFullScreenWindowIsOnSeparateDisplay = monitor != currentMonitor; + + // allow the mainframe to keep focus + bool ret = !!m_pDedicatedFSVideoWnd->CreateEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, _T(""), ResStr(IDS_MAINFRM_136), WS_POPUP, monitorRect, nullptr, 0); + if (ret) { + m_pDedicatedFSVideoWnd->ShowWindow(SW_SHOWNOACTIVATE); + } + return ret; +} + +bool CMainFrame::IsFrameLessWindow() const +{ + return (IsFullScreenMainFrame() || AfxGetAppSettings().eCaptionMenuMode == MODE_BORDERLESS); +} + +bool CMainFrame::IsCaptionHidden() const +{ + // If no caption, there is no menu bar. But if is no menu bar, then the caption can be. + return (!IsFullScreenMainFrame() && AfxGetAppSettings().eCaptionMenuMode > MODE_HIDEMENU); //!=MODE_SHOWCAPTIONMENU && !=MODE_HIDEMENU +} + +bool CMainFrame::IsMenuHidden() const +{ + return (!IsFullScreenMainFrame() && AfxGetAppSettings().eCaptionMenuMode != MODE_SHOWCAPTIONMENU); +} + +bool CMainFrame::IsPlaylistEmpty() const +{ + return (m_wndPlaylistBar.GetCount() == 0); +} + +bool CMainFrame::IsInteractiveVideo() const +{ + return m_fShockwaveGraph; +} + +bool CMainFrame::IsFullScreenMode() const { + return m_fFullScreen || IsD3DFullScreenMode(); +} + +bool CMainFrame::IsFullScreenMainFrame() const { + return m_fFullScreen && !HasDedicatedFSVideoWindow(); +} + +bool CMainFrame::IsFullScreenMainFrameExclusiveMPCVR() const { + return m_fFullScreen && m_bIsMPCVRExclusiveMode && !HasDedicatedFSVideoWindow(); +} + +bool CMainFrame::IsFullScreenSeparate() const { + return m_fFullScreen && HasDedicatedFSVideoWindow() && !m_bFullScreenWindowIsD3D; +} + +bool CMainFrame::HasDedicatedFSVideoWindow() const { + return m_pDedicatedFSVideoWnd && m_pDedicatedFSVideoWnd->IsWindow(); +} + +bool CMainFrame::IsD3DFullScreenMode() const +{ + return HasDedicatedFSVideoWindow() && m_bFullScreenWindowIsD3D; +}; + +bool CMainFrame::IsSubresyncBarVisible() const +{ + return !!m_wndSubresyncBar.IsWindowVisible(); +} + +void CMainFrame::SetupEVRColorControl() +{ + if (m_pMFVP) { + CMPlayerCApp* pApp = AfxGetMyApp(); + CAppSettings& s = AfxGetAppSettings(); + + if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Brightness, pApp->GetEVRColorControl(ProcAmp_Brightness)))) { + return; + } + if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Contrast, pApp->GetEVRColorControl(ProcAmp_Contrast)))) { + return; + } + if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Hue, pApp->GetEVRColorControl(ProcAmp_Hue)))) { + return; + } + if (FAILED(m_pMFVP->GetProcAmpRange(DXVA2_ProcAmp_Saturation, pApp->GetEVRColorControl(ProcAmp_Saturation)))) { + return; + } + + pApp->UpdateColorControlRange(true); + SetColorControl(ProcAmp_All, s.iBrightness, s.iContrast, s.iHue, s.iSaturation); + } +} + +// Called from GraphThread +void CMainFrame::SetupVMR9ColorControl() +{ + if (m_pVMRMC) { + CMPlayerCApp* pApp = AfxGetMyApp(); + CAppSettings& s = AfxGetAppSettings(); + + if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Brightness)))) { + return; + } + if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Contrast)))) { + return; + } + if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Hue)))) { + return; + } + if (FAILED(m_pVMRMC->GetProcAmpControlRange(0, pApp->GetVMR9ColorControl(ProcAmp_Saturation)))) { + return; + } + + pApp->UpdateColorControlRange(false); + SetColorControl(ProcAmp_All, s.iBrightness, s.iContrast, s.iHue, s.iSaturation); + } +} + +void CMainFrame::SetColorControl(DWORD flags, int& brightness, int& contrast, int& hue, int& saturation) +{ + CMPlayerCApp* pApp = AfxGetMyApp(); + HRESULT hr = 0; + + static VMR9ProcAmpControl ClrControl; + static DXVA2_ProcAmpValues ClrValues; + + COLORPROPERTY_RANGE* cr = 0; + if (flags & ProcAmp_Brightness) { + cr = pApp->GetColorControl(ProcAmp_Brightness); + brightness = std::min(std::max(brightness, cr->MinValue), cr->MaxValue); + } + if (flags & ProcAmp_Contrast) { + cr = pApp->GetColorControl(ProcAmp_Contrast); + contrast = std::min(std::max(contrast, cr->MinValue), cr->MaxValue); + } + if (flags & ProcAmp_Hue) { + cr = pApp->GetColorControl(ProcAmp_Hue); + hue = std::min(std::max(hue, cr->MinValue), cr->MaxValue); + } + if (flags & ProcAmp_Saturation) { + cr = pApp->GetColorControl(ProcAmp_Saturation); + saturation = std::min(std::max(saturation, cr->MinValue), cr->MaxValue); + } + + if (m_pVMRMC) { + ClrControl.dwSize = sizeof(ClrControl); + ClrControl.dwFlags = flags; + ClrControl.Brightness = (float)brightness; + ClrControl.Contrast = (float)(contrast + 100) / 100; + ClrControl.Hue = (float)hue; + ClrControl.Saturation = (float)(saturation + 100) / 100; + + hr = m_pVMRMC->SetProcAmpControl(0, &ClrControl); + } else if (m_pMFVP) { + ClrValues.Brightness = IntToFixed(brightness); + ClrValues.Contrast = IntToFixed(contrast + 100, 100); + ClrValues.Hue = IntToFixed(hue); + ClrValues.Saturation = IntToFixed(saturation + 100, 100); + + hr = m_pMFVP->SetProcAmpValues(flags, &ClrValues); + + } + // Workaround: with Intel driver the minimum values of the supported range may not actually work + if (FAILED(hr)) { + if (flags & ProcAmp_Brightness) { + cr = pApp->GetColorControl(ProcAmp_Brightness); + if (brightness == cr->MinValue) { + brightness = cr->MinValue + 1; + } + } + if (flags & ProcAmp_Hue) { + cr = pApp->GetColorControl(ProcAmp_Hue); + if (hue == cr->MinValue) { + hue = cr->MinValue + 1; + } + } + } +} + +void CMainFrame::SetClosedCaptions(bool enable) +{ + if (m_pLN21) { + m_pLN21->SetServiceState(enable ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off); + } +} + +LPCTSTR CMainFrame::GetDVDAudioFormatName(const DVD_AudioAttributes& ATR) const +{ + switch (ATR.AudioFormat) { + case DVD_AudioFormat_AC3: + return _T("AC3"); + case DVD_AudioFormat_MPEG1: + case DVD_AudioFormat_MPEG1_DRC: + return _T("MPEG1"); + case DVD_AudioFormat_MPEG2: + case DVD_AudioFormat_MPEG2_DRC: + return _T("MPEG2"); + case DVD_AudioFormat_LPCM: + return _T("LPCM"); + case DVD_AudioFormat_DTS: + return _T("DTS"); + case DVD_AudioFormat_SDDS: + return _T("SDDS"); + case DVD_AudioFormat_Other: + default: + return MAKEINTRESOURCE(IDS_MAINFRM_137); + } +} + +afx_msg void CMainFrame::OnGotoSubtitle(UINT nID) +{ + if (!m_pSubStreams.IsEmpty() && !IsPlaybackCaptureMode()) { + m_rtCurSubPos = m_wndSeekBar.GetPos(); + m_lSubtitleShift = 0; + m_wndSubresyncBar.RefreshEmbeddedTextSubtitleData(); + m_nCurSubtitle = m_wndSubresyncBar.FindNearestSub(m_rtCurSubPos, (nID == ID_GOTO_NEXT_SUB)); + if (m_nCurSubtitle >= 0 && m_pMS) { + if (nID == ID_GOTO_PREV_SUB) { + OnPlayPause(); + } + m_pMS->SetPositions(&m_rtCurSubPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + } +} + +afx_msg void CMainFrame::OnSubresyncShiftSub(UINT nID) +{ + if (m_nCurSubtitle >= 0) { + long lShift = (nID == ID_SUBRESYNC_SHIFT_DOWN) ? -100 : 100; + CString strSubShift; + + if (m_wndSubresyncBar.ShiftSubtitle(m_nCurSubtitle, lShift, m_rtCurSubPos)) { + m_lSubtitleShift += lShift; + if (m_pMS) { + m_pMS->SetPositions(&m_rtCurSubPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning); + } + } + + strSubShift.Format(IDS_MAINFRM_138, m_lSubtitleShift); + m_OSD.DisplayMessage(OSD_TOPLEFT, strSubShift); + } +} + +afx_msg void CMainFrame::OnSubtitleDelay(UINT nID) +{ + int nDelayStep = AfxGetAppSettings().nSubDelayStep; + + if (nID == ID_SUB_DELAY_DOWN) { + nDelayStep = -nDelayStep; + } + + SetSubtitleDelay(nDelayStep, /*relative=*/ true); +} + +afx_msg void CMainFrame::OnSubtitlePos(UINT nID) +{ + if (m_pCAP) { + CAppSettings& s = AfxGetAppSettings(); + switch (nID) { + case ID_SUB_POS_DOWN: + s.m_RenderersSettings.subPicVerticalShift += 2; + break; + case ID_SUB_POS_UP: + s.m_RenderersSettings.subPicVerticalShift -= 2; + break; + } + + if (GetMediaState() != State_Running) { + m_pCAP->Paint(false); + } + } +} + +afx_msg void CMainFrame::OnSubtitleFontSize(UINT nID) +{ + if (m_pCAP && m_pCurrentSubInput.pSubStream) { + CLSID clsid; + m_pCurrentSubInput.pSubStream->GetClassID(&clsid); + if (clsid == __uuidof(CRenderedTextSubtitle)) { + CAppSettings& s = AfxGetAppSettings(); + switch (nID) { + case ID_SUB_FONT_SIZE_DEC: + s.m_RenderersSettings.fontScaleOverride -= 0.05; + break; + case ID_SUB_FONT_SIZE_INC: + s.m_RenderersSettings.fontScaleOverride += 0.05; + break; + } + + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; + + if (pRTS->m_LibassContext.IsLibassActive()) { + // not supported by libass (yet) + if (!IsFullScreenMode()) { + AfxMessageBox(_T("Adjusting subtitle text size is not possible when using libass."), MB_ICONERROR, 0); + } + } + + { + CAutoLock cAutoLock(&m_csSubLock); + pRTS->Deinit(); + } + InvalidateSubtitle(); + + if (GetMediaState() != State_Running) { + m_pCAP->Paint(false); + } + } else { + if (!IsFullScreenMode()) { + AfxMessageBox(_T("Adjusting subtitle text size is not possible for image based subtitle formats."), MB_ICONERROR, 0); + } + } + } +} + +void CMainFrame::ResetSubtitlePosAndSize(bool repaint /* = false*/) +{ + CAppSettings& s = AfxGetAppSettings(); + bool changed = (s.m_RenderersSettings.fontScaleOverride != 1.0) || (s.m_RenderersSettings.subPicVerticalShift != 0); + + s.m_RenderersSettings.fontScaleOverride = 1.0; + s.m_RenderersSettings.subPicVerticalShift = 0; + + if (changed && repaint && m_pCAP && m_pCurrentSubInput.pSubStream) { + CLSID clsid; + m_pCurrentSubInput.pSubStream->GetClassID(&clsid); + if (clsid == __uuidof(CRenderedTextSubtitle)) { + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pCurrentSubInput.pSubStream; + { + CAutoLock cAutoLock(&m_csSubLock); + pRTS->Deinit(); + } + InvalidateSubtitle(); + + if (GetMediaState() != State_Running) { + m_pCAP->Paint(false); + } + } + } +} + + +void CMainFrame::ProcessAPICommand(COPYDATASTRUCT* pCDS) +{ + CAtlList fns; + REFERENCE_TIME rtPos = 0; + CString fn; + + switch (pCDS->dwData) { + case CMD_OPENFILE: + fn = CString((LPCWSTR)pCDS->lpData); + if (CanSendToYoutubeDL(fn)) { + if (ProcessYoutubeDLURL(fn, false)) { + OpenCurPlaylistItem(); + return; + } else if (IsOnYDLWhitelist(fn)) { + return; + } + } + fns.AddHead(fn); + m_wndPlaylistBar.Open(fns, false); + OpenCurPlaylistItem(); + break; + case CMD_STOP: + OnPlayStop(); + break; + case CMD_CLOSEFILE: + CloseMedia(); + break; + case CMD_PLAYPAUSE: + OnPlayPlaypause(); + break; + case CMD_PLAY: + OnApiPlay(); + break; + case CMD_PAUSE: + OnApiPause(); + break; + case CMD_ADDTOPLAYLIST: + fn = CString((LPCWSTR)pCDS->lpData); + if (CanSendToYoutubeDL(fn)) { + if (ProcessYoutubeDLURL(fn, true)) { + return; + } else if (IsOnYDLWhitelist(fn)) { + return; + } + } + fns.AddHead(fn); + m_wndPlaylistBar.Append(fns, true); + break; + case CMD_STARTPLAYLIST: + OpenCurPlaylistItem(); + break; + case CMD_CLEARPLAYLIST: + m_wndPlaylistBar.Empty(); + break; + case CMD_SETPOSITION: + rtPos = 10000 * REFERENCE_TIME(_wtof((LPCWSTR)pCDS->lpData) * 1000); //with accuracy of 1 ms + // imianz: quick and dirty trick + // Pause->SeekTo->Play (in place of SeekTo only) seems to prevents in most cases + // some strange video effects on avi files (ex. locks a while and than running fast). + if (!m_fAudioOnly && GetMediaState() == State_Running) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + SeekTo(rtPos); + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } else { + SeekTo(rtPos); + } + // show current position overridden by play command + m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 2000); + break; + case CMD_SETAUDIODELAY: + rtPos = (REFERENCE_TIME)_wtol((LPCWSTR)pCDS->lpData) * 10000; + SetAudioDelay(rtPos); + break; + case CMD_SETSUBTITLEDELAY: + SetSubtitleDelay(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_SETINDEXPLAYLIST: + //m_wndPlaylistBar.SetSelIdx(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_SETAUDIOTRACK: + SetAudioTrackIdx(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_SETSUBTITLETRACK: + SetSubtitleTrackIdx(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_GETVERSION: { + CStringW buff = AfxGetMyApp()->m_strVersion; + SendAPICommand(CMD_VERSION, buff); + break; + } + case CMD_GETSUBTITLETRACKS: + SendSubtitleTracksToApi(); + break; + case CMD_GETAUDIOTRACKS: + SendAudioTracksToApi(); + break; + case CMD_GETCURRENTAUDIOTRACK: + SendAPICommand(CMD_CURRENTAUDIOTRACK, L"%d", GetCurrentAudioTrackIdx()); + break; + case CMD_GETCURRENTSUBTITLETRACK: + SendAPICommand(CMD_CURRENTSUBTITLETRACK, L"%d", GetCurrentSubtitleTrackIdx()); + break; + case CMD_GETCURRENTPOSITION: + SendCurrentPositionToApi(); + break; + case CMD_GETNOWPLAYING: + SendNowPlayingToApi(); + break; + case CMD_JUMPOFNSECONDS: + JumpOfNSeconds(_wtoi((LPCWSTR)pCDS->lpData)); + break; + case CMD_GETPLAYLIST: + SendPlaylistToApi(); + break; + case CMD_JUMPFORWARDMED: + OnPlaySeek(ID_PLAY_SEEKFORWARDMED); + break; + case CMD_JUMPBACKWARDMED: + OnPlaySeek(ID_PLAY_SEEKBACKWARDMED); + break; + case CMD_TOGGLEFULLSCREEN: + OnViewFullscreen(); + break; + case CMD_INCREASEVOLUME: + m_wndToolBar.m_volctrl.IncreaseVolume(); + break; + case CMD_DECREASEVOLUME: + m_wndToolBar.m_volctrl.DecreaseVolume(); + break; + case CMD_SHADER_TOGGLE : + OnShaderToggle1(); + break; + case CMD_CLOSEAPP: + PostMessage(WM_CLOSE); + break; + case CMD_SETSPEED: + SetPlayingRate(_wtof((LPCWSTR)pCDS->lpData)); + break; + case CMD_SETPANSCAN: + AfxGetAppSettings().strPnSPreset = (LPCWSTR)pCDS->lpData; + ApplyPanNScanPresetString(); + break; + case CMD_OSDSHOWMESSAGE: + ShowOSDCustomMessageApi((MPC_OSDDATA*)pCDS->lpData); + break; + } +} + +void CMainFrame::SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...) +{ + const CAppSettings& s = AfxGetAppSettings(); + + if (s.hMasterWnd) { + COPYDATASTRUCT CDS; + + va_list args; + va_start(args, fmt); + + int nBufferLen = _vsctprintf(fmt, args) + 1; // _vsctprintf doesn't count the null terminator + TCHAR* pBuff = DEBUG_NEW TCHAR[nBufferLen]; + _vstprintf_s(pBuff, nBufferLen, fmt, args); + + CDS.cbData = (DWORD)nBufferLen * sizeof(TCHAR); + CDS.dwData = nCommand; + CDS.lpData = (LPVOID)pBuff; + + ::SendMessage(s.hMasterWnd, WM_COPYDATA, (WPARAM)GetSafeHwnd(), (LPARAM)&CDS); + + va_end(args); + delete [] pBuff; + } +} + +void CMainFrame::SendNowPlayingToApi(bool sendtrackinfo) +{ + if (!AfxGetAppSettings().hMasterWnd) { + return; + } + + if (GetLoadState() == MLS::LOADED) { + CString title, author, description; + CString label; + CString strDur; + + if (GetPlaybackMode() == PM_FILE) { + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_TITLE), title); + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_DESCRIPTION), description); + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + label = !pli.m_label.IsEmpty() ? pli.m_label : pli.m_fns.GetHead(); + REFERENCE_TIME rtDur; + m_pMS->GetDuration(&rtDur); + strDur.Format(L"%.3f", rtDur / 10000000.0); + } + } else if (GetPlaybackMode() == PM_DVD) { + DVD_DOMAIN DVDDomain; + ULONG ulNumOfChapters = 0; + DVD_PLAYBACK_LOCATION2 Location; + + // Get current DVD Domain + if (SUCCEEDED(m_pDVDI->GetCurrentDomain(&DVDDomain))) { + switch (DVDDomain) { + case DVD_DOMAIN_Stop: + title = _T("DVD - Stopped"); + break; + case DVD_DOMAIN_FirstPlay: + title = _T("DVD - FirstPlay"); + break; + case DVD_DOMAIN_VideoManagerMenu: + title = _T("DVD - RootMenu"); + break; + case DVD_DOMAIN_VideoTitleSetMenu: + title = _T("DVD - TitleMenu"); + break; + case DVD_DOMAIN_Title: + title = _T("DVD - Title"); + break; + } + + // get title information + if (DVDDomain == DVD_DOMAIN_Title) { + // get current location (title number & chapter) + if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&Location))) { + // get number of chapters in current title + VERIFY(SUCCEEDED(m_pDVDI->GetNumberOfChapters(Location.TitleNum, &ulNumOfChapters))); + } + + // get total time of title + DVD_HMSF_TIMECODE tcDur; + ULONG ulFlags; + if (SUCCEEDED(m_pDVDI->GetTotalTitleTime(&tcDur, &ulFlags))) { + // calculate duration in seconds + strDur.Format(L"%d", tcDur.bHours * 60 * 60 + tcDur.bMinutes * 60 + tcDur.bSeconds); + } + + // build string + // DVD - xxxxx|currenttitle|numberofchapters|currentchapter|titleduration + author.Format(L"%lu", Location.TitleNum); + description.Format(L"%lu", ulNumOfChapters); + label.Format(L"%lu", Location.ChapterNum); + } + } + } + + title.Replace(L"|", L"\\|"); + author.Replace(L"|", L"\\|"); + description.Replace(L"|", L"\\|"); + label.Replace(L"|", L"\\|"); + + CStringW buff; + buff.Format(L"%s|%s|%s|%s|%s", title.GetString(), author.GetString(), description.GetString(), label.GetString(), strDur.GetString()); + + SendAPICommand(CMD_NOWPLAYING, L"%s", static_cast(buff)); + if (sendtrackinfo) { + SendSubtitleTracksToApi(); + SendAudioTracksToApi(); + } + } +} + +void CMainFrame::SendSubtitleTracksToApi() +{ + CStringW strSubs; + if (GetLoadState() == MLS::LOADED) { + if (GetPlaybackMode() == PM_DVD) { + ULONG ulStreamsAvailable, ulCurrentStream; + BOOL bIsDisabled; + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled)) + && ulStreamsAvailable > 0) { + LCID DefLanguage; + int i = 0, iSelected = -1; + + DVD_SUBPICTURE_LANG_EXT ext; + if (FAILED(m_pDVDI->GetDefaultSubpictureLanguage(&DefLanguage, &ext))) { + return; + } + + for (i = 0; i < ulStreamsAvailable; i++) { + LCID Language; + if (FAILED(m_pDVDI->GetSubpictureLanguage(i, &Language))) { + continue; + } + + if (i == ulCurrentStream) { + iSelected = i; + } + + CString str; + if (Language) { + GetLocaleString(Language, LOCALE_SENGLANGUAGE, str); + } else { + str.Format(IDS_AG_UNKNOWN, i + 1); + } + + DVD_SubpictureAttributes ATR; + if (SUCCEEDED(m_pDVDI->GetSubpictureAttributes(i, &ATR))) { + switch (ATR.LanguageExtension) { + case DVD_SP_EXT_NotSpecified: + default: + break; + case DVD_SP_EXT_Caption_Normal: + str += _T(""); + break; + case DVD_SP_EXT_Caption_Big: + str += _T(" (Big)"); + break; + case DVD_SP_EXT_Caption_Children: + str += _T(" (Children)"); + break; + case DVD_SP_EXT_CC_Normal: + str += _T(" (CC)"); + break; + case DVD_SP_EXT_CC_Big: + str += _T(" (CC Big)"); + break; + case DVD_SP_EXT_CC_Children: + str += _T(" (CC Children)"); + break; + case DVD_SP_EXT_Forced: + str += _T(" (Forced)"); + break; + case DVD_SP_EXT_DirectorComments_Normal: + str += _T(" (Director Comments)"); + break; + case DVD_SP_EXT_DirectorComments_Big: + str += _T(" (Director Comments, Big)"); + break; + case DVD_SP_EXT_DirectorComments_Children: + str += _T(" (Director Comments, Children)"); + break; + } + } + if (!strSubs.IsEmpty()) { + strSubs.Append(L"|"); + } + str.Replace(L"|", L"\\|"); + strSubs.Append(str); + } + if (AfxGetAppSettings().fEnableSubtitles) { + strSubs.AppendFormat(L"|%d", iSelected); + } else { + strSubs.Append(L"|-1"); + } + } + } else { + + POSITION pos = m_pSubStreams.GetHeadPosition(); + int i = 0, iSelected = -1; + if (pos) { + while (pos) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + + if (CComQIPtr pSSF = subInput.pSourceFilter) { + DWORD cStreams; + if (FAILED(pSSF->Count(&cStreams))) { + continue; + } + + for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { + DWORD dwFlags, dwGroup; + WCHAR* pszName = nullptr; + + if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, &pszName, nullptr, nullptr)) + || !pszName) { + continue; + } + + CString name(pszName); + CoTaskMemFree(pszName); + + if (dwGroup != 2) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream + && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + iSelected = j; + } + + if (!strSubs.IsEmpty()) { + strSubs.Append(L"|"); + } + name.Replace(L"|", L"\\|"); + strSubs.Append(name); + + i++; + } + } else { + CComPtr pSubStream = subInput.pSubStream; + if (!pSubStream) { + continue; + } + + if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + iSelected = i + pSubStream->GetStream(); + } + + for (int j = 0, cnt = pSubStream->GetStreamCount(); j < cnt; j++) { + WCHAR* pName = nullptr; + if (SUCCEEDED(pSubStream->GetStreamInfo(j, &pName, nullptr))) { + CString name(pName); + CoTaskMemFree(pName); + + if (!strSubs.IsEmpty()) { + strSubs.Append(L"|"); + } + name.Replace(L"|", L"\\|"); + strSubs.Append(name); + } + i++; + } + } + + } + if (AfxGetAppSettings().fEnableSubtitles) { + strSubs.AppendFormat(L"|%d", iSelected); + } else { + strSubs.Append(L"|-1"); + } + } else { + strSubs.Append(L"-1"); + } + } + } else { + strSubs.Append(L"-2"); + } + SendAPICommand(CMD_LISTSUBTITLETRACKS, L"%s", static_cast(strSubs)); +} + +void CMainFrame::SendAudioTracksToApi() +{ + CStringW strAudios; + + if (GetLoadState() == MLS::LOADED) { + DWORD cStreams = 0; + if (m_pAudioSwitcherSS && SUCCEEDED(m_pAudioSwitcherSS->Count(&cStreams))) { + int currentStream = -1; + for (int i = 0; i < (int)cStreams; i++) { + AM_MEDIA_TYPE* pmt = nullptr; + DWORD dwFlags = 0; + LCID lcid = 0; + DWORD dwGroup = 0; + WCHAR* pszName = nullptr; + if (FAILED(m_pAudioSwitcherSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) { + return; + } + if (dwFlags == AMSTREAMSELECTINFO_EXCLUSIVE) { + currentStream = i; + } + CString name(pszName); + if (!strAudios.IsEmpty()) { + strAudios.Append(L"|"); + } + name.Replace(L"|", L"\\|"); + strAudios.AppendFormat(L"%s", name.GetString()); + if (pmt) { + DeleteMediaType(pmt); + } + if (pszName) { + CoTaskMemFree(pszName); + } + } + strAudios.AppendFormat(L"|%d", currentStream); + + } else { + strAudios.Append(L"-1"); + } + } else { + strAudios.Append(L"-2"); + } + SendAPICommand(CMD_LISTAUDIOTRACKS, L"%s", static_cast(strAudios)); + +} + +void CMainFrame::SendPlaylistToApi() +{ + CStringW strPlaylist; + POSITION pos = m_wndPlaylistBar.m_pl.GetHeadPosition(), pos2; + + while (pos) { + CPlaylistItem& pli = m_wndPlaylistBar.m_pl.GetNext(pos); + + if (pli.m_type == CPlaylistItem::file) { + pos2 = pli.m_fns.GetHeadPosition(); + while (pos2) { + CString fn = pli.m_fns.GetNext(pos2); + if (!strPlaylist.IsEmpty()) { + strPlaylist.Append(L"|"); + } + fn.Replace(L"|", L"\\|"); + strPlaylist.AppendFormat(L"%s", fn.GetString()); + } + } + } + if (strPlaylist.IsEmpty()) { + strPlaylist.Append(L"-1"); + } else { + strPlaylist.AppendFormat(L"|%d", m_wndPlaylistBar.GetSelIdx()); + } + SendAPICommand(CMD_PLAYLIST, L"%s", static_cast(strPlaylist)); +} + +void CMainFrame::SendCurrentPositionToApi(bool fNotifySeek) +{ + if (!AfxGetAppSettings().hMasterWnd) { + return; + } + + if (GetLoadState() == MLS::LOADED) { + CStringW strPos; + + if (GetPlaybackMode() == PM_FILE) { + REFERENCE_TIME rtCur; + m_pMS->GetCurrentPosition(&rtCur); + strPos.Format(L"%.3f", rtCur / 10000000.0); + } else if (GetPlaybackMode() == PM_DVD) { + DVD_PLAYBACK_LOCATION2 Location; + // get current location while playing disc, will return 0, if at a menu + if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) { + strPos.Format(L"%d", Location.TimeCode.bHours * 60 * 60 + Location.TimeCode.bMinutes * 60 + Location.TimeCode.bSeconds); + } + } + + SendAPICommand(fNotifySeek ? CMD_NOTIFYSEEK : CMD_CURRENTPOSITION, strPos); + } +} + +void CMainFrame::ShowOSDCustomMessageApi(const MPC_OSDDATA* osdData) +{ + m_OSD.DisplayMessage((OSD_MESSAGEPOS)osdData->nMsgPos, osdData->strMsg, osdData->nDurationMS); +} + +void CMainFrame::JumpOfNSeconds(int nSeconds) +{ + if (GetLoadState() == MLS::LOADED) { + REFERENCE_TIME rtCur; + + if (GetPlaybackMode() == PM_FILE) { + m_pMS->GetCurrentPosition(&rtCur); + DVD_HMSF_TIMECODE tcCur = RT2HMSF(rtCur); + long lPosition = tcCur.bHours * 60 * 60 + tcCur.bMinutes * 60 + tcCur.bSeconds + nSeconds; + + // revert the update position to REFERENCE_TIME format + tcCur.bHours = (BYTE)(lPosition / 3600); + tcCur.bMinutes = (lPosition / 60) % 60; + tcCur.bSeconds = lPosition % 60; + rtCur = HMSF2RT(tcCur); + + // quick and dirty trick: + // pause->seekto->play seems to prevents some strange + // video effect (ex. locks for a while and than running fast) + if (!m_fAudioOnly) { + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + SeekTo(rtCur); + if (!m_fAudioOnly) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + // show current position overridden by play command + m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer(), 2000); + } + } + } +} + +// TODO : to be finished ! +//void CMainFrame::AutoSelectTracks() +//{ +// LCID DefAudioLanguageLcid [2] = {MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT), MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT)}; +// int DefAudioLanguageIndex [2] = {-1, -1}; +// LCID DefSubtitleLanguageLcid [2] = {0, MAKELCID( MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT)}; +// int DefSubtitleLanguageIndex[2] = {-1, -1}; +// LCID Language = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT); +// +// if ((m_iMediaLoadState == MLS::LOADING) || (m_iMediaLoadState == MLS::LOADED)) +// { +// if (GetPlaybackMode() == PM_FILE) +// { +// CComQIPtr pSS = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); +// +// DWORD cStreams = 0; +// if (pSS && SUCCEEDED(pSS->Count(&cStreams))) +// { +// for (int i = 0; i < (int)cStreams; i++) +// { +// AM_MEDIA_TYPE* pmt = nullptr; +// DWORD dwFlags = 0; +// LCID lcid = 0; +// DWORD dwGroup = 0; +// WCHAR* pszName = nullptr; +// if (FAILED(pSS->Info(i, &pmt, &dwFlags, &lcid, &dwGroup, &pszName, nullptr, nullptr))) +// return; +// } +// } +// +// POSITION pos = m_pSubStreams.GetHeadPosition(); +// while (pos) +// { +// CComPtr pSubStream = m_pSubStreams.GetNext(pos).subStream; +// if (!pSubStream) continue; +// +// for (int i = 0, j = pSubStream->GetStreamCount(); i < j; i++) +// { +// WCHAR* pName = nullptr; +// if (SUCCEEDED(pSubStream->GetStreamInfo(i, &pName, &Language))) +// { +// if (DefAudioLanguageLcid[0] == Language) DefSubtitleLanguageIndex[0] = i; +// if (DefSubtitleLanguageLcid[1] == Language) DefSubtitleLanguageIndex[1] = i; +// CoTaskMemFree(pName); +// } +// } +// } +// } +// else if (GetPlaybackMode() == PM_DVD) +// { +// ULONG ulStreamsAvailable, ulCurrentStream; +// BOOL bIsDisabled; +// +// if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulStreamsAvailable, &ulCurrentStream, &bIsDisabled))) +// { +// for (ULONG i = 0; i < ulStreamsAvailable; i++) +// { +// DVD_SubpictureAttributes ATR; +// if (SUCCEEDED(m_pDVDI->GetSubpictureLanguage(i, &Language))) +// { +// // Auto select forced subtitle +// if ((DefAudioLanguageLcid[0] == Language) && (ATR.LanguageExtension == DVD_SP_EXT_Forced)) +// DefSubtitleLanguageIndex[0] = i; +// +// if (DefSubtitleLanguageLcid[1] == Language) DefSubtitleLanguageIndex[1] = i; +// } +// } +// } +// +// if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulStreamsAvailable, &ulCurrentStream))) +// { +// for (ULONG i = 0; i < ulStreamsAvailable; i++) +// { +// if (SUCCEEDED(m_pDVDI->GetAudioLanguage(i, &Language))) +// { +// if (DefAudioLanguageLcid[0] == Language) DefAudioLanguageIndex[0] = i; +// if (DefAudioLanguageLcid[1] == Language) DefAudioLanguageIndex[1] = i; +// } +// } +// } +// +// // Select best audio/subtitles tracks +// if (DefAudioLanguageLcid[0] != -1) +// { +// m_pDVDC->SelectAudioStream(DefAudioLanguageIndex[0], DVD_CMD_FLAG_Block, nullptr); +// if (DefSubtitleLanguageIndex[0] != -1) +// m_pDVDC->SelectSubpictureStream(DefSubtitleLanguageIndex[0], DVD_CMD_FLAG_Block, nullptr); +// } +// else if ((DefAudioLanguageLcid[1] != -1) && (DefSubtitleLanguageLcid[1] != -1)) +// { +// m_pDVDC->SelectAudioStream (DefAudioLanguageIndex[1], DVD_CMD_FLAG_Block, nullptr); +// m_pDVDC->SelectSubpictureStream (DefSubtitleLanguageIndex[1], DVD_CMD_FLAG_Block, nullptr); +// } +// } +// +// +// } +//} + +void CMainFrame::OnFileOpendirectory() +{ + if (GetLoadState() == MLS::LOADING || !IsWindow(m_wndPlaylistBar)) { + return; + } + + auto& s = AfxGetAppSettings(); + CString strTitle(StrRes(IDS_MAINFRM_DIR_TITLE)); + CString path; + + MPCFolderPickerDialog fd(ForceTrailingSlash(s.lastFileOpenDirPath), FOS_PATHMUSTEXIST, GetModalParent(), IDS_MAINFRM_DIR_CHECK); + fd.m_ofn.lpstrTitle = strTitle; + + if (fd.DoModal() == IDOK) { + path = fd.GetPathName(); //getfolderpath() does not work correctly for CFolderPickerDialog + } else { + return; + } + + BOOL recur = TRUE; + fd.GetCheckButtonState(IDS_MAINFRM_DIR_CHECK, recur); + COpenDirHelper::m_incl_subdir = !!recur; + + // If we got a link file that points to a directory, follow the link + if (PathUtils::IsLinkFile(path)) { + CString resolvedPath = PathUtils::ResolveLinkFile(path); + if (PathUtils::IsDir(resolvedPath)) { + path = resolvedPath; + } + } + + path = ForceTrailingSlash(path); + s.lastFileOpenDirPath = path; + + CAtlList sl; + sl.AddTail(path); + if (COpenDirHelper::m_incl_subdir) { + PathUtils::RecurseAddDir(path, sl); + } + + m_wndPlaylistBar.Open(sl, true); + OpenCurPlaylistItem(); +} + +HRESULT CMainFrame::CreateThumbnailToolbar() +{ + if (!this || !AfxGetAppSettings().bUseEnhancedTaskBar) { + return E_FAIL; + } + + if (m_pTaskbarList || SUCCEEDED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER))) { + bool bRTLLayout = false; // Assume left-to-right layout by default + // Try to locate the window used to display the task bar + if (CWnd* pTaskBarWnd = FindWindow(_T("TaskListThumbnailWnd"), nullptr)) { + bRTLLayout = !!(pTaskBarWnd->GetExStyle() & WS_EX_LAYOUTRTL); + } + + CMPCPngImage image; + if (!image.Load(IDF_WIN7_TOOLBAR)) { + return E_FAIL; + } + + CSize size = image.GetSize(); + + if (bRTLLayout) { // We don't want the buttons to be mirrored so we pre-mirror them + // Create memory DCs for the source and destination bitmaps + CDC sourceDC, destDC; + sourceDC.CreateCompatibleDC(nullptr); + destDC.CreateCompatibleDC(nullptr); + // Swap the source bitmap with an empty one + CBitmap sourceImg; + sourceImg.Attach(image.Detach()); + // Create a temporary DC + CClientDC clientDC(nullptr); + // Create the destination bitmap + image.CreateCompatibleBitmap(&clientDC, size.cx, size.cy); + // Select the bitmaps into the DCs + HGDIOBJ oldSourceDCObj = sourceDC.SelectObject(sourceImg); + HGDIOBJ oldDestDCObj = destDC.SelectObject(image); + // Actually flip the bitmap + destDC.StretchBlt(0, 0, size.cx, size.cy, + &sourceDC, size.cx, 0, -size.cx, size.cy, + SRCCOPY); + // Reselect the old objects back into their DCs + sourceDC.SelectObject(oldSourceDCObj); + destDC.SelectObject(oldDestDCObj); + + sourceDC.DeleteDC(); + destDC.DeleteDC(); + } + + CImageList imageList; + imageList.Create(size.cy, size.cy, ILC_COLOR32, size.cx / size.cy, 0); + imageList.Add(&image, nullptr); + + if (SUCCEEDED(m_pTaskbarList->ThumbBarSetImageList(m_hWnd, imageList.GetSafeHandle()))) { + THUMBBUTTON buttons[5] = {}; + + for (size_t i = 0; i < _countof(buttons); i++) { + buttons[i].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS; + buttons[i].dwFlags = THBF_DISABLED; + buttons[i].iBitmap = 0; // Will be set later + } + + // PREVIOUS + buttons[0].iId = IDTB_BUTTON3; + // STOP + buttons[1].iId = IDTB_BUTTON1; + // PLAY/PAUSE + buttons[2].iId = IDTB_BUTTON2; + // NEXT + buttons[3].iId = IDTB_BUTTON4; + // FULLSCREEN + buttons[4].iId = IDTB_BUTTON5; + + if (bRTLLayout) { // We don't want the buttons to be mirrored so we pre-mirror them + std::reverse(buttons, buttons + _countof(buttons)); + } + + if (SUCCEEDED(m_pTaskbarList->ThumbBarAddButtons(m_hWnd, _countof(buttons), buttons))) { + return UpdateThumbarButton(); + } + } + } + + return E_FAIL; +} + +HRESULT CMainFrame::UpdateThumbarButton() +{ + MPC_PLAYSTATE state = PS_STOP; + if (GetLoadState() == MLS::LOADED) { + switch (GetMediaState()) { + case State_Running: + state = PS_PLAY; + break; + case State_Paused: + state = PS_PAUSE; + break; + } + } + return UpdateThumbarButton(state); +} + +HRESULT CMainFrame::UpdateThumbarButton(MPC_PLAYSTATE iPlayState) +{ + if (!m_pTaskbarList) { + return E_FAIL; + } + + THUMBBUTTON buttons[5] = {}; + + for (size_t i = 0; i < _countof(buttons); i++) { + buttons[i].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS; + } + + buttons[0].iId = IDTB_BUTTON3; + buttons[1].iId = IDTB_BUTTON1; + buttons[2].iId = IDTB_BUTTON2; + buttons[3].iId = IDTB_BUTTON4; + buttons[4].iId = IDTB_BUTTON5; + + const CAppSettings& s = AfxGetAppSettings(); + + if (!s.bUseEnhancedTaskBar) { + m_pTaskbarList->SetOverlayIcon(m_hWnd, nullptr, L""); + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); + + for (size_t i = 0; i < _countof(buttons); i++) { + buttons[i].dwFlags = THBF_HIDDEN; + } + } else { + buttons[0].iBitmap = 0; + StringCchCopy(buttons[0].szTip, _countof(buttons[0].szTip), ResStr(IDS_AG_PREVIOUS)); + + buttons[1].iBitmap = 1; + StringCchCopy(buttons[1].szTip, _countof(buttons[1].szTip), ResStr(IDS_AG_STOP)); + + buttons[2].iBitmap = 3; + StringCchCopy(buttons[2].szTip, _countof(buttons[2].szTip), ResStr(IDS_AG_PLAYPAUSE)); + + buttons[3].iBitmap = 4; + StringCchCopy(buttons[3].szTip, _countof(buttons[3].szTip), ResStr(IDS_AG_NEXT)); + + buttons[4].iBitmap = 5; + StringCchCopy(buttons[4].szTip, _countof(buttons[4].szTip), ResStr(IDS_AG_FULLSCREEN)); + + if (GetLoadState() == MLS::LOADED) { + HICON hIcon = nullptr; + + buttons[0].dwFlags = (!s.fUseSearchInFolder && m_wndPlaylistBar.GetCount() <= 1 && (m_pCB && m_pCB->ChapGetCount() <= 1)) ? THBF_DISABLED : THBF_ENABLED; + buttons[3].dwFlags = (!s.fUseSearchInFolder && m_wndPlaylistBar.GetCount() <= 1 && (m_pCB && m_pCB->ChapGetCount() <= 1)) ? THBF_DISABLED : THBF_ENABLED; + buttons[4].dwFlags = THBF_ENABLED; + + if (iPlayState == PS_PLAY) { + buttons[1].dwFlags = THBF_ENABLED; + buttons[2].dwFlags = THBF_ENABLED; + buttons[2].iBitmap = 2; + + hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_PLAY), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + m_pTaskbarList->SetProgressState(m_hWnd, m_wndSeekBar.HasDuration() ? TBPF_NORMAL : TBPF_NOPROGRESS); + } else if (iPlayState == PS_STOP) { + buttons[1].dwFlags = THBF_DISABLED; + buttons[2].dwFlags = THBF_ENABLED; + buttons[2].iBitmap = 3; + + hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_STOP), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); + } else if (iPlayState == PS_PAUSE) { + buttons[1].dwFlags = THBF_ENABLED; + buttons[2].dwFlags = THBF_ENABLED; + buttons[2].iBitmap = 3; + + hIcon = (HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_TB_PAUSE), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); + m_pTaskbarList->SetProgressState(m_hWnd, m_wndSeekBar.HasDuration() ? TBPF_PAUSED : TBPF_NOPROGRESS); + } + + if (GetPlaybackMode() == PM_DVD && m_iDVDDomain != DVD_DOMAIN_Title) { + buttons[0].dwFlags = THBF_DISABLED; + buttons[1].dwFlags = THBF_DISABLED; + buttons[2].dwFlags = THBF_DISABLED; + buttons[3].dwFlags = THBF_DISABLED; + } + + m_pTaskbarList->SetOverlayIcon(m_hWnd, hIcon, L""); + + if (hIcon != nullptr) { + DestroyIcon(hIcon); + } + } else { + for (size_t i = 0; i < _countof(buttons); i++) { + buttons[i].dwFlags = THBF_DISABLED; + } + + m_pTaskbarList->SetOverlayIcon(m_hWnd, nullptr, L""); + m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS); + } + + UpdateThumbnailClip(); + } + + // Try to locate the window used to display the task bar to check if it is RTLed + if (CWnd* pTaskBarWnd = FindWindow(_T("TaskListThumbnailWnd"), nullptr)) { + // We don't want the buttons to be mirrored so we pre-mirror them + if (pTaskBarWnd->GetExStyle() & WS_EX_LAYOUTRTL) { + for (UINT i = 0; i < _countof(buttons); i++) { + buttons[i].iBitmap = _countof(buttons) - buttons[i].iBitmap; + } + std::reverse(buttons, buttons + _countof(buttons)); + } + } + + return m_pTaskbarList->ThumbBarUpdateButtons(m_hWnd, _countof(buttons), buttons); +} + +HRESULT CMainFrame::UpdateThumbnailClip() +{ + if (!m_pTaskbarList || !m_hWnd || !m_wndView.m_hWnd) { + return E_FAIL; + } + + const CAppSettings& s = AfxGetAppSettings(); + + CRect r; + m_wndView.GetClientRect(&r); + if (s.eCaptionMenuMode == MODE_SHOWCAPTIONMENU) { + r.OffsetRect(0, GetSystemMetrics(SM_CYMENU)); + } + + if (!s.bUseEnhancedTaskBar || (GetLoadState() != MLS::LOADED) || IsFullScreenMode() || r.Width() <= 0 || r.Height() <= 0) { + return m_pTaskbarList->SetThumbnailClip(m_hWnd, nullptr); + } + + return m_pTaskbarList->SetThumbnailClip(m_hWnd, &r); +} + +BOOL CMainFrame::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, LPCTSTR lpszMenuName, DWORD dwExStyle, CCreateContext* pContext) +{ + if (defaultMPCThemeMenu == nullptr) { + defaultMPCThemeMenu = DEBUG_NEW CMPCThemeMenu(); + } + if (lpszMenuName != NULL) { + defaultMPCThemeMenu->LoadMenu(lpszMenuName); + + if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), defaultMPCThemeMenu->m_hMenu, (LPVOID)pContext)) { + return FALSE; + } + defaultMPCThemeMenu->fulfillThemeReqs(true); + + return TRUE; + } + return FALSE; +} + +void CMainFrame::enableFileDialogHook(CMPCThemeUtil* helper) { + if (AfxGetAppSettings().bWindows10DarkThemeActive) { //hard coded behavior for windows 10 dark theme file dialogs, irrespsective of theme loaded by user (fixing windows bugs) + watchingDialog = themableDialogTypes::windowsFileDialog; + dialogHookHelper = helper; + } +} + +void CMainFrame::enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type) { + if (AppIsThemeLoaded()) { + watchingDialog = type; + dialogHookHelper = helper; + } +} + +bool CMainFrame::isSafeZone(CPoint pt) { + CRect r; + m_wndSeekBar.GetClientRect(r); + m_wndSeekBar.MapWindowPoints(this, r); + r.InflateRect(0, m_dpi.ScaleY(16)); + if (r.top < 0) r.top = 0; + + if (r.PtInRect(pt)) { + TRACE(_T("Click was inside safezone!\n")); + return true; + } + return false; +} + +LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (!m_hWnd) { + ASSERT(false); + return 0; + } + if (message == WM_ACTIVATE || message == WM_SETFOCUS) { + if (AfxGetMyApp()->m_fClosingState) { + TRACE(_T("Dropped WindowProc: message %u value %d\n"), message, LOWORD(wParam)); + return 0; + } + } + + if ((message == WM_COMMAND) && (THBN_CLICKED == HIWORD(wParam))) { + int const wmId = LOWORD(wParam); + switch (wmId) { + case IDTB_BUTTON1: + SendMessage(WM_COMMAND, ID_PLAY_STOP); + break; + case IDTB_BUTTON2: + SendMessage(WM_COMMAND, ID_PLAY_PLAYPAUSE); + break; + case IDTB_BUTTON3: + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPBACK); + break; + case IDTB_BUTTON4: + SendMessage(WM_COMMAND, ID_NAVIGATE_SKIPFORWARD); + break; + case IDTB_BUTTON5: + WINDOWPLACEMENT wp; + GetWindowPlacement(&wp); + if (wp.showCmd == SW_SHOWMINIMIZED) { + SendMessage(WM_SYSCOMMAND, SC_RESTORE, -1); + } + SetForegroundWindow(); + SendMessage(WM_COMMAND, ID_VIEW_FULLSCREEN); + break; + default: + break; + } + return 0; + } else if (watchingDialog != themableDialogTypes::None && nullptr != dialogHookHelper && message == WM_ACTIVATE && LOWORD(wParam) == WA_INACTIVE) { + dialogHookHelper->themableDialogHandle = (HWND)lParam; + foundDialog = watchingDialog; + watchingDialog = themableDialogTypes::None; + //capture but process message normally + } else if (message == WM_GETICON && foundDialog == themableDialogTypes::windowsFileDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { + dialogHookHelper->subClassFileDialog(this); + foundDialog = themableDialogTypes::None; + } else if (message == WM_ENTERIDLE && foundDialog == themableDialogTypes::toolbarCustomizeDialog && nullptr != dialogHookHelper && nullptr != dialogHookHelper->themableDialogHandle) { + dialogHookHelper->subClassTBCustomizeDialog(this, &m_wndToolBar); + foundDialog = themableDialogTypes::None; + } + + if (message == WM_NCLBUTTONDOWN && wParam == HTCAPTION && !m_pMVRSR) { + CPoint pt = CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + ScreenToClient(&pt); + if (isSafeZone(pt)) { + return 0; + } + } + + LRESULT ret = 0; + bool bCallOurProc = true; + if (m_pMVRSR) { + // call madVR window proc directly when the interface is available + switch (message) { + case WM_CLOSE: + break; + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + // CMouseWnd will call madVR window proc + break; + default: + bCallOurProc = !m_pMVRSR->ParentWindowProc(m_hWnd, message, &wParam, &lParam, &ret); + } + } + if (bCallOurProc && m_hWnd) { + ret = __super::WindowProc(message, wParam, lParam); + } + + return ret; +} + +bool CMainFrame::IsAeroSnapped() +{ + bool ret = false; + WINDOWPLACEMENT wp = { sizeof(wp) }; + if (IsWindowVisible() && !IsZoomed() && !IsIconic() && GetWindowPlacement(&wp)) { + CRect rect; + GetWindowRect(rect); + if (HMONITOR hMon = MonitorFromRect(rect, MONITOR_DEFAULTTONULL)) { + MONITORINFO mi = { sizeof(mi) }; + if (GetMonitorInfo(hMon, &mi)) { + CRect wpRect(wp.rcNormalPosition); + wpRect.OffsetRect(mi.rcWork.left - mi.rcMonitor.left, mi.rcWork.top - mi.rcMonitor.top); + ret = !!(rect != wpRect); + } else { + ASSERT(FALSE); + } + } + } + return ret; +} + +UINT CMainFrame::OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData) +{ + static BOOL bWasPausedBeforeSuspention; + + switch (nPowerEvent) { + case PBT_APMSUSPEND: // System is suspending operation. + TRACE(_T("OnPowerBroadcast - suspending\n")); // For user tracking + bWasPausedBeforeSuspention = FALSE; // Reset value + + if (GetMediaState() == State_Running) { + bWasPausedBeforeSuspention = TRUE; + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); // Pause + } + break; + case PBT_APMRESUMESUSPEND: // System is resuming operation + TRACE(_T("OnPowerBroadcast - resuming\n")); // For user tracking + + // force seek to current position when resuming playback to re-initialize the video decoder + m_dwLastPause = 1; + + // Resume if we paused before suspension. + if (bWasPausedBeforeSuspention) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); // Resume + } + break; + } + + return __super::OnPowerBroadcast(nPowerEvent, nEventData); +} + +#define NOTIFY_FOR_THIS_SESSION 0 + +void CMainFrame::OnSessionChange(UINT nSessionState, UINT nId) +{ + if (AfxGetAppSettings().bLockNoPause) { + return; + } + + static BOOL bWasPausedBeforeSessionChange; + + switch (nSessionState) { + case WTS_SESSION_LOCK: + TRACE(_T("OnSessionChange - Lock session\n")); + bWasPausedBeforeSessionChange = FALSE; + + if (GetMediaState() == State_Running && !m_fAudioOnly) { + bWasPausedBeforeSessionChange = TRUE; + SendMessage(WM_COMMAND, ID_PLAY_PAUSE); + } + break; + case WTS_SESSION_UNLOCK: + TRACE(_T("OnSessionChange - UnLock session\n")); + + if (bWasPausedBeforeSessionChange) { + SendMessage(WM_COMMAND, ID_PLAY_PLAY); + } + break; + } +} + +void CMainFrame::WTSRegisterSessionNotification() +{ + const WinapiFunc + fnWtsRegisterSessionNotification = { _T("wtsapi32.dll"), "WTSRegisterSessionNotification" }; + + if (fnWtsRegisterSessionNotification) { + fnWtsRegisterSessionNotification(m_hWnd, NOTIFY_FOR_THIS_SESSION); + } +} + +void CMainFrame::WTSUnRegisterSessionNotification() +{ + const WinapiFunc + fnWtsUnRegisterSessionNotification = { _T("wtsapi32.dll"), "WTSUnRegisterSessionNotification" }; + + if (fnWtsUnRegisterSessionNotification) { + fnWtsUnRegisterSessionNotification(m_hWnd); + } +} + +void CMainFrame::UpdateSkypeHandler() +{ + const auto& s = AfxGetAppSettings(); + if (s.bNotifySkype && !m_pSkypeMoodMsgHandler) { + m_pSkypeMoodMsgHandler.Attach(DEBUG_NEW SkypeMoodMsgHandler()); + m_pSkypeMoodMsgHandler->Connect(m_hWnd); + } else if (!s.bNotifySkype && m_pSkypeMoodMsgHandler) { + m_pSkypeMoodMsgHandler.Free(); + } +} + +void CMainFrame::UpdateSeekbarChapterBag() +{ + const auto& s = AfxGetAppSettings(); + if (s.fShowChapters && m_pCB && m_pCB->ChapGetCount() > 0) { + m_wndSeekBar.SetChapterBag(m_pCB); + m_OSD.SetChapterBag(m_pCB); + } else { + m_wndSeekBar.RemoveChapters(); + m_OSD.RemoveChapters(); + } +} + +void CMainFrame::UpdateAudioSwitcher() +{ + CAppSettings& s = AfxGetAppSettings(); + CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), m_pGB); + + if (pASF) { + pASF->SetSpeakerConfig(s.fCustomChannelMapping, s.pSpeakerToChannelMap); + pASF->EnableDownSamplingTo441(s.fDownSampleTo441); + pASF->SetAudioTimeShift(s.fAudioTimeShift ? 10000i64 * s.iAudioTimeShift : 0); + pASF->SetNormalizeBoost2(s.fAudioNormalize, s.nAudioMaxNormFactor, s.fAudioNormalizeRecover, s.nAudioBoost); + } +} + +void CMainFrame::LoadArtToViews(const CString& imagePath) +{ + m_wndView.LoadImg(imagePath); + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->LoadImg(imagePath); + } +} + +void CMainFrame::LoadArtToViews(std::vector buffer) +{ + m_wndView.LoadImg(buffer); + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->LoadImg(buffer); + } +} + +void CMainFrame::ClearArtFromViews() +{ + m_wndView.LoadImg(); + if (HasDedicatedFSVideoWindow()) { + m_pDedicatedFSVideoWnd->LoadImg(); + } +} + +void CMainFrame::UpdateControlState(UpdateControlTarget target) +{ + const auto& s = AfxGetAppSettings(); + switch (target) { + case UPDATE_VOLUME_STEP: + m_wndToolBar.m_volctrl.SetPageSize(s.nVolumeStep); + break; + case UPDATE_LOGO: + if (GetLoadState() == MLS::LOADED && m_fAudioOnly && s.bEnableCoverArt) { + CString filename = m_wndPlaylistBar.GetCurFileName(); + CString filename_no_ext; + CString filedir; + if (!PathUtils::IsURL(filename)) { + CPath path = CPath(filename); + if (path.FileExists()) { + path.RemoveExtension(); + filename_no_ext = path.m_strPath; + path.RemoveFileSpec(); + filedir = path.m_strPath; + } + } + + CString author; + m_wndInfoBar.GetLine(StrRes(IDS_INFOBAR_AUTHOR), author); + + CComQIPtr pFilterGraph = m_pGB; + std::vector internalCover; + if (CoverArt::FindEmbedded(pFilterGraph, internalCover)) { + LoadArtToViews(internalCover); + m_currentCoverPath = filename; + m_currentCoverAuthor = author; + } else { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli) && !pli.m_cover.IsEmpty() && CPath(pli.m_cover).FileExists()) { + LoadArtToViews(pli.m_cover); + } else if (!filedir.IsEmpty() && (m_currentCoverPath != filedir || m_currentCoverAuthor != author || currentCoverIsFileArt)) { + CString img = CoverArt::FindExternal(filename_no_ext, filedir, author, currentCoverIsFileArt); + LoadArtToViews(img); + m_currentCoverPath = filedir; + m_currentCoverAuthor = author; + } else if (!m_wndView.IsCustomImgLoaded()) { + ClearArtFromViews(); + } + } + } else { + m_currentCoverPath.Empty(); + m_currentCoverAuthor.Empty(); + ClearArtFromViews(); + } + break; + case UPDATE_SKYPE: + UpdateSkypeHandler(); + break; + case UPDATE_SEEKBAR_CHAPTERS: + UpdateSeekbarChapterBag(); + break; + case UPDATE_WINDOW_TITLE: + OpenSetupWindowTitle(); + break; + case UPDATE_AUDIO_SWITCHER: + UpdateAudioSwitcher(); + break; + case UPDATE_CONTROLS_VISIBILITY: + m_controls.UpdateToolbarsVisibility(); + break; + case UPDATE_CHILDVIEW_CURSOR_HACK: + // HACK: windowed (not renderless) video renderers created in graph thread do not + // produce WM_MOUSEMOVE message when we release mouse capture on top of it, here's a workaround + m_timerOneTime.Subscribe(TimerOneTimeSubscriber::CHILDVIEW_CURSOR_HACK, std::bind(&CChildView::Invalidate, &m_wndView, FALSE), 16); + break; + default: + ASSERT(FALSE); + } +} + +void CMainFrame::ReloadMenus() { + // CMenu defaultMenu; + CMenu* oldMenu; + + // Destroy the dynamic menus before reloading the main menus + DestroyDynamicMenus(); + + // Reload the main menus + m_popupMenu.DestroyMenu(); + m_popupMenu.LoadMenu(IDR_POPUP); + m_mainPopupMenu.DestroyMenu(); + m_mainPopupMenu.LoadMenu(IDR_POPUPMAIN); + + oldMenu = GetMenu(); + defaultMPCThemeMenu = DEBUG_NEW CMPCThemeMenu(); //will have been destroyed + defaultMPCThemeMenu->LoadMenu(IDR_MAINFRAME); + if (oldMenu) { + // Attach the new menu to the window only if there was a menu before + SetMenu(defaultMPCThemeMenu); + // and then destroy the old one + oldMenu->DestroyMenu(); + delete oldMenu; + } + //we don't detach because we retain the cmenu + //m_hMenuDefault = defaultMenu.Detach(); + m_hMenuDefault = defaultMPCThemeMenu->GetSafeHmenu(); + + m_popupMenu.fulfillThemeReqs(); + m_mainPopupMenu.fulfillThemeReqs(); + defaultMPCThemeMenu->fulfillThemeReqs(true); + + // Reload the dynamic menus + CreateDynamicMenus(); +} + + +void CMainFrame::UpdateUILanguage() +{ + ReloadMenus(); + + // Reload the static bars + OpenSetupInfoBar(); + if (GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + UpdateCurrentChannelInfo(false, false); + } + OpenSetupStatsBar(); + + // Reload the debug shaders dialog if need be + if (m_pDebugShaders && IsWindow(m_pDebugShaders->m_hWnd)) { + BOOL bWasVisible = m_pDebugShaders->IsWindowVisible(); + VERIFY(m_pDebugShaders->DestroyWindow()); + m_pDebugShaders = std::make_unique(); + if (bWasVisible) { + m_pDebugShaders->ShowWindow(SW_SHOWNA); + // Don't steal focus from main frame + SetActiveWindow(); + } + } +} + +bool CMainFrame::OpenBD(CString Path) +{ + CHdmvClipInfo ClipInfo; + CString strPlaylistFile; + CHdmvClipInfo::HdmvPlaylist MainPlaylist; + +#if INTERNAL_SOURCEFILTER_MPEG + const CAppSettings& s = AfxGetAppSettings(); + bool InternalMpegSplitter = s.SrcFilters[SRC_MPEG] || s.SrcFilters[SRC_MPEGTS]; +#else + bool InternalMpegSplitter = false; +#endif + + m_LastOpenBDPath = Path; + + CString ext = CPath(Path).GetExtension(); + ext.MakeLower(); + + if ((CPath(Path).IsDirectory() && Path.Find(_T("\\BDMV"))) + || CPath(Path + _T("\\BDMV")).IsDirectory() + || (!ext.IsEmpty() && ext == _T(".bdmv"))) { + if (!ext.IsEmpty() && ext == _T(".bdmv")) { + Path.Replace(_T("\\BDMV\\"), _T("\\")); + CPath _Path(Path); + _Path.RemoveFileSpec(); + Path = CString(_Path); + } else if (Path.Find(_T("\\BDMV"))) { + Path.Replace(_T("\\BDMV"), _T("\\")); + } + if (SUCCEEDED(ClipInfo.FindMainMovie(Path, strPlaylistFile, MainPlaylist, m_MPLSPlaylist))) { + m_bIsBDPlay = true; + + m_bHasBDMeta = ClipInfo.ReadMeta(Path, m_BDMeta); + + if (!InternalMpegSplitter && !ext.IsEmpty() && ext == _T(".bdmv")) { + return false; + } else { + m_wndPlaylistBar.Empty(); + CAtlList sl; + + if (InternalMpegSplitter) { + sl.AddTail(CString(strPlaylistFile)); + } else { + sl.AddTail(CString(Path + _T("\\BDMV\\index.bdmv"))); + } + + m_wndPlaylistBar.Append(sl, false); + OpenCurPlaylistItem(); + return true; + } + } + } + + m_LastOpenBDPath = _T(""); + return false; +} + +// Returns the the corresponding subInput or nullptr in case of error. +// i is modified to reflect the locale index of track +SubtitleInput* CMainFrame::GetSubtitleInput(int& i, bool bIsOffset /*= false*/) +{ + // Only 1, 0 and -1 are supported offsets + if ((bIsOffset && (i < -1 || i > 1)) || (!bIsOffset && i < 0)) { + return nullptr; + } + + POSITION pos = m_pSubStreams.GetHeadPosition(); + SubtitleInput* pSubInput = nullptr, *pSubInputPrec = nullptr; + int iLocalIdx = -1, iLocalIdxPrec = -1; + bool bNextTrack = false; + + while (pos && !pSubInput) { + SubtitleInput& subInput = m_pSubStreams.GetNext(pos); + + if (CComQIPtr pSSF = subInput.pSourceFilter) { + DWORD cStreams; + if (FAILED(pSSF->Count(&cStreams))) { + continue; + } + + for (int j = 0, cnt = (int)cStreams; j < cnt; j++) { + DWORD dwFlags, dwGroup; + + if (FAILED(pSSF->Info(j, nullptr, &dwFlags, nullptr, &dwGroup, nullptr, nullptr, nullptr))) { + continue; + } + + if (dwGroup != 2) { + continue; + } + + if (bIsOffset) { + if (bNextTrack) { // We detected previously that the next subtitles track is the one we want to select + pSubInput = &subInput; + iLocalIdx = j; + break; + } else if (subInput.pSubStream == m_pCurrentSubInput.pSubStream + && dwFlags & (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE)) { + if (i == 0) { + pSubInput = &subInput; + iLocalIdx = j; + break; + } else if (i > 0) { + bNextTrack = true; // We want to the select the next subtitles track + } else { + // We want the previous subtitles track and we know which one it is + if (pSubInputPrec) { + pSubInput = pSubInputPrec; + iLocalIdx = iLocalIdxPrec; + break; + } + } + } + + pSubInputPrec = &subInput; + iLocalIdxPrec = j; + } else { + if (i == 0) { + pSubInput = &subInput; + iLocalIdx = j; + break; + } + + i--; + } + } + } else { + if (bIsOffset) { + if (bNextTrack) { // We detected previously that the next subtitles track is the one we want to select + pSubInput = &subInput; + iLocalIdx = 0; + break; + } else if (subInput.pSubStream == m_pCurrentSubInput.pSubStream) { + iLocalIdx = subInput.pSubStream->GetStream() + i; + if (iLocalIdx >= 0 && iLocalIdx < subInput.pSubStream->GetStreamCount()) { + // The subtitles track we want to select is part of this substream + pSubInput = &subInput; + } else if (i > 0) { // We want to the select the next subtitles track + bNextTrack = true; + } else { + // We want the previous subtitles track and we know which one it is + if (pSubInputPrec) { + pSubInput = pSubInputPrec; + iLocalIdx = iLocalIdxPrec; + } + } + } else { + pSubInputPrec = &subInput; + iLocalIdxPrec = subInput.pSubStream->GetStreamCount() - 1; + } + } else { + if (i < subInput.pSubStream->GetStreamCount()) { + pSubInput = &subInput; + iLocalIdx = i; + } else { + i -= subInput.pSubStream->GetStreamCount(); + } + } + } + + // Handle special cases + if (!pos && !pSubInput && bIsOffset) { + if (bNextTrack) { // The last subtitles track was selected and we want the next one + // Let's restart the loop to select the first subtitles track + pos = m_pSubStreams.GetHeadPosition(); + } else if (i < 0) { // The first subtitles track was selected and we want the previous one + pSubInput = pSubInputPrec; // We select the last track + iLocalIdx = iLocalIdxPrec; + } + } + } + + i = iLocalIdx; + + return pSubInput; +} + +CString CMainFrame::GetFileName() +{ + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true)) { + CString path(m_wndPlaylistBar.GetCurFileName(true)); + if (!pli.m_bYoutubeDL && m_pFSF) { + CComHeapPtr pFN; + if (SUCCEEDED(m_pFSF->GetCurFile(&pFN, nullptr))) { + path = pFN; + } + } + if (PathUtils::IsURL(path)) { + path = ShortenURL(path); + } + return pli.m_bYoutubeDL ? path : PathUtils::StripPathOrUrl(path); + } + return _T(""); +} + +CString CMainFrame::GetCaptureTitle() +{ + CString title; + + title.LoadString(IDS_CAPTURE_LIVE); + if (GetPlaybackMode() == PM_ANALOG_CAPTURE) { + CString devName = GetFriendlyName(m_VidDispName); + if (!devName.IsEmpty()) { + title.AppendFormat(_T(" | %s"), devName.GetString()); + } + } else { + CString& eventName = m_pDVBState->NowNext.eventName; + if (m_pDVBState->bActive) { + title.AppendFormat(_T(" | %s"), m_pDVBState->sChannelName.GetString()); + if (!eventName.IsEmpty()) { + title.AppendFormat(_T(" - %s"), eventName.GetString()); + } + } else { + title += _T(" | DVB"); + } + } + return title; +} + +GUID CMainFrame::GetTimeFormat() +{ + GUID ret; + if (!m_pMS || !SUCCEEDED(m_pMS->GetTimeFormat(&ret))) { + ASSERT(FALSE); + ret = TIME_FORMAT_NONE; + } + return ret; +} + +void CMainFrame::UpdateDXVAStatus() +{ + CString DXVAInfo; + // We only support getting info from LAV Video Decoder is that is what will be used 99% of the time + if (CComQIPtr pLAVVideoStatus = FindFilter(GUID_LAVVideo, m_pGB)) { + const LPCWSTR decoderName = pLAVVideoStatus->GetActiveDecoderName(); + if (decoderName == nullptr || wcscmp(decoderName, L"avcodec") == 0 || wcscmp(decoderName, L"wmv9 mft") == 0 || wcscmp(decoderName, L"msdk mvc") == 0) { + DXVAInfo = _T("H/W Decoder : None"); + } else { + m_bUsingDXVA = true; + m_HWAccelType = CFGFilterLAVVideo::GetUserFriendlyDecoderName(decoderName); + DXVAInfo.Format(_T("H/W Decoder : %s"), m_HWAccelType); + } + } else { + DXVAInfo = _T("H/W Decoder : None / Unknown"); + } + GetRenderersData()->m_strDXVAInfo = DXVAInfo; +} + +bool CMainFrame::GetDecoderType(CString& type) const +{ + if (!m_fAudioOnly) { + if (m_bUsingDXVA) { + type = m_HWAccelType; + } else { + type.LoadString(IDS_TOOLTIP_SOFTWARE_DECODING); + } + return true; + } + return false; +} + +void CMainFrame::UpdateSubtitleRenderingParameters() +{ + if (!m_pCAP) { + return; + } + + const CAppSettings& s = AfxGetAppSettings(); + if (auto pRTS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { + bool bChangeStorageRes = false; + bool bChangePARComp = false; + double dPARCompensation = 1.0; + bool bKeepAspectRatio = s.fKeepAspectRatio; + + CSize szAspectRatio = m_pCAP->GetVideoSize(true); + CSize szVideoFrame; + if (m_pMVRI) { + // Use IMadVRInfo to get size. See http://bugs.madshi.net/view.php?id=180 + m_pMVRI->GetSize("originalVideoSize", &szVideoFrame); + bKeepAspectRatio = true; + } else { + szVideoFrame = m_pCAP->GetVideoSize(false); + } + + if (s.bSubtitleARCompensation && szAspectRatio.cx && szAspectRatio.cy && szVideoFrame.cx && szVideoFrame.cy && bKeepAspectRatio) { + if (pRTS->m_layoutRes.cx > 0) { + dPARCompensation = (double)szAspectRatio.cx * pRTS->m_layoutRes.cy / (szAspectRatio.cy * pRTS->m_layoutRes.cx); + } else { + dPARCompensation = (double)szAspectRatio.cx * szVideoFrame.cy / (szAspectRatio.cy * szVideoFrame.cx); + } + } + if (pRTS->m_dPARCompensation != dPARCompensation) { + bChangePARComp = true; + } + + if (pRTS->m_subtitleType == Subtitle::ASS || pRTS->m_subtitleType == Subtitle::SSA) { + if (szVideoFrame.cx > 0) { + if (pRTS->m_layoutRes.cx == 0 || pRTS->m_layoutRes.cy == 0) { + bChangeStorageRes = (pRTS->m_storageRes != szVideoFrame); + } else { + bChangeStorageRes = (pRTS->m_storageRes != pRTS->m_layoutRes); + } + } + } + + { + CAutoLock cAutoLock(&m_csSubLock); + if (bChangeStorageRes) { + if (pRTS->m_layoutRes.cx == 0 || pRTS->m_layoutRes.cy == 0) { + pRTS->m_storageRes = szVideoFrame; + } else { + pRTS->m_storageRes = pRTS->m_layoutRes; + } + } + if (bChangePARComp) { + pRTS->m_ePARCompensationType = CSimpleTextSubtitle::EPARCompensationType::EPCTAccurateSize_ISR; + pRTS->m_dPARCompensation = dPARCompensation; + } + + STSStyle style = s.subtitlesDefStyle; + if (pRTS->m_bUsingPlayerDefaultStyle) { + pRTS->SetDefaultStyle(style); + } else if (pRTS->GetDefaultStyle(style) && style.relativeTo == STSStyle::AUTO && s.subtitlesDefStyle.relativeTo != STSStyle::AUTO) { + style.relativeTo = s.subtitlesDefStyle.relativeTo; + pRTS->SetDefaultStyle(style); + } + pRTS->SetOverride(s.bSubtitleOverrideDefaultStyle, s.bSubtitleOverrideAllStyles, s.subtitlesDefStyle); + pRTS->SetAlignment(s.fOverridePlacement, s.nHorPos, s.nVerPos); + pRTS->SetUseFreeType(s.bUseFreeType); + pRTS->SetOpenTypeLangHint(s.strOpenTypeLangHint); + pRTS->Deinit(); + } + m_pCAP->Invalidate(); + } else if (auto pVSS = dynamic_cast((ISubStream*)m_pCurrentSubInput.pSubStream)) { + { + CAutoLock cAutoLock(&m_csSubLock); + pVSS->SetAlignment(s.fOverridePlacement, s.nHorPos, s.nVerPos); + } + m_pCAP->Invalidate(); + } +} + +REFTIME CMainFrame::GetAvgTimePerFrame() const +{ + REFTIME refAvgTimePerFrame = 0.0; + + if (FAILED(m_pBV->get_AvgTimePerFrame(&refAvgTimePerFrame))) { + if (m_pCAP) { + refAvgTimePerFrame = 1.0 / m_pCAP->GetFPS(); + } + + BeginEnumFilters(m_pGB, pEF, pBF) { + if (refAvgTimePerFrame > 0.0) { + break; + } + + BeginEnumPins(pBF, pEP, pPin) { + AM_MEDIA_TYPE mt; + if (SUCCEEDED(pPin->ConnectionMediaType(&mt))) { + if (mt.majortype == MEDIATYPE_Video && mt.formattype == FORMAT_VideoInfo) { + refAvgTimePerFrame = (REFTIME)((VIDEOINFOHEADER*)mt.pbFormat)->AvgTimePerFrame / 10000000i64; + break; + } else if (mt.majortype == MEDIATYPE_Video && mt.formattype == FORMAT_VideoInfo2) { + refAvgTimePerFrame = (REFTIME)((VIDEOINFOHEADER2*)mt.pbFormat)->AvgTimePerFrame / 10000000i64; + break; + } + } + } + EndEnumPins; + } + EndEnumFilters; + } + + // Double-check that the detection is correct for DVDs + DVD_VideoAttributes VATR; + if (m_pDVDI && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) { + double ratio; + if (VATR.ulFrameRate == 50) { + ratio = 25.0 * refAvgTimePerFrame; + // Accept 25 or 50 fps + if (!IsNearlyEqual(ratio, 1.0, 1e-2) && !IsNearlyEqual(ratio, 2.0, 1e-2)) { + refAvgTimePerFrame = 1.0 / 25.0; + } + } else { + ratio = 29.97 * refAvgTimePerFrame; + // Accept 29,97, 59.94, 23.976 or 47.952 fps + if (!IsNearlyEqual(ratio, 1.0, 1e-2) && !IsNearlyEqual(ratio, 2.0, 1e-2) + && !IsNearlyEqual(ratio, 1.25, 1e-2) && !IsNearlyEqual(ratio, 2.5, 1e-2)) { + refAvgTimePerFrame = 1.0 / 29.97; + } + } + } + + return refAvgTimePerFrame; +} + +void CMainFrame::OnVideoSizeChanged(const bool bWasAudioOnly /*= false*/) +{ + const auto& s = AfxGetAppSettings(); + if (GetLoadState() == MLS::LOADED && + ((s.fRememberZoomLevel && (s.fLimitWindowProportions || m_bAllowWindowZoom)) || m_fAudioOnly || bWasAudioOnly) && + !(IsFullScreenMode() || IsZoomed() || IsIconic() || IsAeroSnapped())) { + CSize videoSize; + if (!m_fAudioOnly && !m_bAllowWindowZoom) { + videoSize = GetVideoSize(); + } + if (videoSize.cx && videoSize.cy) { + ZoomVideoWindow(m_dLastVideoScaleFactor * std::sqrt((static_cast(m_lastVideoSize.cx) * m_lastVideoSize.cy) + / (static_cast(videoSize.cx) * videoSize.cy))); + } else { + ZoomVideoWindow(); + } + } + MoveVideoWindow(); +} + +typedef struct { + SubtitlesInfo* pSubtitlesInfo; + BOOL bActivate; + std::string fileName; + std::string fileContents; +} SubtitlesData; + +LRESULT CMainFrame::OnLoadSubtitles(WPARAM wParam, LPARAM lParam) +{ + SubtitlesData& data = *(SubtitlesData*)lParam; + + CAutoPtr pRTS(DEBUG_NEW CRenderedTextSubtitle(&m_csSubLock)); + if (pRTS) { + if (pRTS->Open(CString(data.pSubtitlesInfo->Provider()->DisplayName().c_str()), + (BYTE*)(LPCSTR)data.fileContents.c_str(), (int)data.fileContents.length(), DEFAULT_CHARSET, + UTF8To16(data.fileName.c_str()), Subtitle::HearingImpairedType(data.pSubtitlesInfo->hearingImpaired), + ISOLang::ISO6391ToLcid(data.pSubtitlesInfo->languageCode.c_str())) && pRTS->GetStreamCount() > 0) { + m_wndSubtitlesDownloadDialog.DoDownloaded(*data.pSubtitlesInfo); +#if USE_LIBASS + if (pRTS->m_LibassContext.IsLibassActive()) { + pRTS->m_LibassContext.SetFilterGraph(m_pGB); + } +#endif + SubtitleInput subElement = pRTS.Detach(); + m_pSubStreams.AddTail(subElement); + if (data.bActivate) { + m_ExternalSubstreams.push_back(subElement.pSubStream); + SetSubtitle(subElement.pSubStream); + + auto& s = AfxGetAppSettings(); + if (s.fKeepHistory && s.bRememberTrackSelection && s.bAutoSaveDownloadedSubtitles) { + s.MRU.UpdateCurrentSubtitleTrack(GetSelectedSubtitleTrackIndex()); + } + } + return TRUE; + } + } + + return FALSE; +} + +LRESULT CMainFrame::OnGetSubtitles(WPARAM, LPARAM lParam) +{ + CheckPointer(lParam, FALSE); + + int n = 0; + SubtitleInput* pSubInput = GetSubtitleInput(n, true); + CheckPointer(pSubInput, FALSE); + + CLSID clsid; + if (FAILED(pSubInput->pSubStream->GetClassID(&clsid)) || clsid != __uuidof(CRenderedTextSubtitle)) { + return FALSE; + } + + CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubInput->pSubStream; + // Only for external text subtitles + if (pRTS->m_path.IsEmpty()) { + return FALSE; + } + + SubtitlesInfo* pSubtitlesInfo = reinterpret_cast(lParam); + + pSubtitlesInfo->GetFileInfo(); + pSubtitlesInfo->releaseNames.emplace_back(UTF16To8(pRTS->m_name)); + if (pSubtitlesInfo->hearingImpaired == Subtitle::HI_UNKNOWN) { + pSubtitlesInfo->hearingImpaired = pRTS->m_eHearingImpaired; + } + + if (!pSubtitlesInfo->languageCode.length() && pRTS->m_lcid && pRTS->m_lcid != LCID(-1)) { + CString str; + GetLocaleString(pRTS->m_lcid, LOCALE_SISO639LANGNAME, str); + pSubtitlesInfo->languageCode = UTF16To8(str); + } + + pSubtitlesInfo->frameRate = m_pCAP->GetFPS(); + int delay = m_pCAP->GetSubtitleDelay(); + if (pRTS->m_mode == FRAME) { + delay = std::lround(delay * pSubtitlesInfo->frameRate / 1000.0); + } + + const CStringW fmt(L"%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n%s\n\n"); + CStringW content; + CAutoLock cAutoLock(&m_csSubLock); + for (int i = 0, j = int(pRTS->GetCount()), k = 0; i < j; i++) { + int t1 = (int)(RT2MS(pRTS->TranslateStart(i, pSubtitlesInfo->frameRate)) + delay); + if (t1 < 0) { + k++; + continue; + } + + int t2 = (int)(RT2MS(pRTS->TranslateEnd(i, pSubtitlesInfo->frameRate)) + delay); + + int hh1 = (t1 / 60 / 60 / 1000); + int mm1 = (t1 / 60 / 1000) % 60; + int ss1 = (t1 / 1000) % 60; + int ms1 = (t1) % 1000; + int hh2 = (t2 / 60 / 60 / 1000); + int mm2 = (t2 / 60 / 1000) % 60; + int ss2 = (t2 / 1000) % 60; + int ms2 = (t2) % 1000; + + content.AppendFormat(fmt, i - k + 1, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, pRTS->GetStrW(i, false).GetString()); + } + + pSubtitlesInfo->fileContents = UTF16To8(content); + return TRUE; +} + +static const CString ydl_whitelist[] = { + _T("youtube.com/"), + _T("youtu.be/"), + _T("twitch.tv/"), + _T("twitch.com/") +}; + +static const CString ydl_blacklist[] = { + _T("googlevideo.com/videoplayback"), // already processed URL + _T("googlevideo.com/api/manifest"), + _T("@127.0.0.1:"), // local URL + _T("saunalahti.fi/") +}; + +bool CMainFrame::IsOnYDLWhitelist(CString url) { + for (int i = 0; i < _countof(ydl_whitelist); i++) { + if (url.Find(ydl_whitelist[i]) >= 0) { + return true; + } + } + return false; +} + +bool CMainFrame::CanSendToYoutubeDL(const CString url) +{ + if (url.Left(4).MakeLower() == _T("http") && AfxGetAppSettings().bUseYDL) { + // Blacklist: don't use for IP addresses + std::wcmatch regmatch; + std::wregex regexp(LR"(https?:\/\/(\d{1,3}\.){3}\d{1,3}.*)"); + if (std::regex_match(url.GetString(), regmatch, regexp)) { + return false; + } + + // Whitelist: popular supported sites + if (IsOnYDLWhitelist(url)) { + return true; + } + + // Blacklist: unsupported sites where YDL causes an error or long delay + for (int i = 0; i < _countof(ydl_blacklist); i++) { + if (url.Find(ydl_blacklist[i], 7) > 0) { + return false; + } + } + + // Blacklist: URL points to a file + CString baseurl; + int q = url.Find(_T('?')); + if (q > 0) { + baseurl = url.Left(q); + } else { + baseurl = url; + q = url.GetLength(); + } + int p = baseurl.ReverseFind(_T('.')); + if (p > 0 && (q - p <= 6)) { + CString ext = baseurl.Mid(p); + if (AfxGetAppSettings().m_Formats.FindExt(ext)) { + return false; + } + } + + return true; + } + return false; +} + +bool CMainFrame::ProcessYoutubeDLURL(CString url, bool append, bool replace) +{ + auto& s = AfxGetAppSettings(); + CAtlList streams; + CAtlList filenames; + CYoutubeDLInstance ydl; + CYoutubeDLInstance::YDLPlaylistInfo listinfo; + CString useragent; + + m_sydlLastProcessURL = url; + + m_wndStatusBar.SetStatusMessage(ResStr(IDS_CONTROLS_YOUTUBEDL)); + + if (!ydl.Run(url)) { + return false; + } + if (!ydl.GetHttpStreams(streams, listinfo, useragent)) { + return false; + } + + if (!append && !replace) { + m_wndPlaylistBar.Empty(); + } + + CString f_title; + + for (unsigned int i = 0; i < streams.GetCount(); i++) { + auto stream = streams.GetAt(streams.FindIndex(i)); + CString v_url = stream.video_url; + CString a_url = stream.audio_url; + filenames.RemoveAll(); + if (!v_url.IsEmpty() && (!s.bYDLAudioOnly || a_url.IsEmpty())) { + filenames.AddTail(v_url); + + } + if (!a_url.IsEmpty()) { + filenames.AddTail(a_url); + } + CString title = stream.title; + CString seasonid; + if (stream.season_number != -1) { + seasonid.Format(_T("S%02d"), stream.season_number); + } + CString episodeid; + if (stream.episode_number != -1) { + episodeid.Format(_T("E%02d"), stream.episode_number); + } + CString epiid; + if (!seasonid.IsEmpty() || !episodeid.IsEmpty()) { + epiid.Format(_T("%s%s. "), static_cast(seasonid), static_cast(episodeid)); + } + CString season; + if (!stream.series.IsEmpty()) { + season = stream.series; + CString t(stream.season.Left(6)); + if (!stream.season.IsEmpty() && (t.MakeLower() != _T("season") || stream.season_number == -1)) { + season += _T(" ") + stream.season; + } + season += _T(" - "); + } + else if (!stream.season.IsEmpty()) { + CString t(stream.season.Left(6)); + if (t.MakeLower() != _T("season") || stream.season_number == -1) { + season = stream.season + _T(" - "); + } + } + title.Format(_T("%s%s%s"), static_cast(epiid), static_cast(season), static_cast(title)); + if (i == 0) f_title = title; + + CString ydl_src = stream.webpage_url.IsEmpty() ? url : stream.webpage_url; + if (i == 0) m_sydlLastProcessURL = ydl_src; + + int targetlen = title.GetLength() > 100 ? 50 : 150 - title.GetLength(); + CString short_url = ShortenURL(ydl_src, targetlen, true); + + if (ydl_src == filenames.GetHead()) { + // Processed URL is same as input, can happen for DASH manifest files. Clear source URL to avoid reprocessing. + ydl_src = _T(""); + } + + if (replace) { + m_wndPlaylistBar.ReplaceCurrentItem(filenames, nullptr, title + " (" + short_url + ")", ydl_src, useragent, _T(""), &stream.subtitles); + break; + } else { + m_wndPlaylistBar.Append(filenames, false, nullptr, title + " (" + short_url + ")", ydl_src, useragent, _T(""), &stream.subtitles); + } + } + + if (s.fKeepHistory) { + auto* mru = &s.MRU; + RecentFileEntry r; + mru->LoadMediaHistoryEntryFN(m_sydlLastProcessURL, r); + if (streams.GetCount() > 1) { + auto h = streams.GetHead(); + if (!h.series.IsEmpty()) { + r.title = h.series; + if (!h.season.IsEmpty()) { + r.title += _T(" - ") + h.season; + } + } + else if (!h.season.IsEmpty()) { + r.title = h.season; + } + else if (!listinfo.title.IsEmpty()) { + if (!listinfo.uploader.IsEmpty()) r.title.Format(_T("%s - %s"), static_cast(listinfo.uploader), static_cast(listinfo.title)); + else r.title = listinfo.title; + } + else r.title = f_title; + } + else if (streams.GetCount() == 1) { + r.title = f_title; + } + mru->Add(r, false); + } + + if (!append && (!replace || m_wndPlaylistBar.GetCount() == 0)) { + m_wndPlaylistBar.SetFirst(); + } + return true; +} + +bool CMainFrame::DownloadWithYoutubeDL(CString url, CString filename) +{ + PROCESS_INFORMATION proc_info; + STARTUPINFO startup_info; + const auto& s = AfxGetAppSettings(); + + bool ytdlp = true; + CString args = _T("\"") + GetYDLExePath(&ytdlp) + _T("\" --console-title \"") + url + _T("\""); + if (!s.sYDLCommandLine.IsEmpty()) { + args.Append(_T(" ")); + args.Append(s.sYDLCommandLine); + } + if (s.bYDLAudioOnly && (s.sYDLCommandLine.Find(_T("-f ")) < 0)) { + args.Append(_T(" -f bestaudio")); + } + if (s.sYDLCommandLine.Find(_T("-o ")) < 0) { + args.Append(_T(" -o \"" + filename + "\"")); + } + + ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&startup_info, sizeof(STARTUPINFO)); + startup_info.cb = sizeof(STARTUPINFO); + + if (!CreateProcess(NULL, args.GetBuffer(), NULL, NULL, false, 0, + NULL, NULL, &startup_info, &proc_info)) { + AfxMessageBox(_T("An error occurred while attempting to run Youtube-DL"), MB_ICONERROR, 0); + return false; + } + + CloseHandle(proc_info.hProcess); + CloseHandle(proc_info.hThread); + + return true; +} + +void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) +{ + __super::OnSettingChange(uFlags, lpszSection); + if (SPI_SETNONCLIENTMETRICS == uFlags) { + CMPCThemeUtil::GetMetrics(true); + CMPCThemeMenu::clearDimensions(); + if (nullptr != defaultMPCThemeMenu) { + UpdateUILanguage(); //cheap way to rebuild menus--we want to do this to force them to re-measure + } + RecalcLayout(); + } +} + +BOOL CMainFrame::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) { + if (m_bUseSeekPreview && m_wndPreView.IsWindowVisible()) { + + int seek = + nFlags == MK_SHIFT ? 10 : + nFlags == MK_CONTROL ? 1 : 5; + + zDelta > 0 ? SetCursorPos(point.x + seek, point.y) : + zDelta < 0 ? SetCursorPos(point.x - seek, point.y) : SetCursorPos(point.x, point.y); + + return 0; + } + return __super::OnMouseWheel(nFlags, zDelta, point); +} + +void CMainFrame::OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt) { + if (m_wndView && m_wndView.OnMouseHWheelImpl(nFlags, zDelta, pt)) { + //HWHEEL is sent to active window, so we have to manually pass it to CMouseWnd to trap hotkeys + return; + } + __super::OnMouseHWheel(nFlags, zDelta, pt); +} + +CHdmvClipInfo::BDMVMeta CMainFrame::GetBDMVMeta() +{ + return m_BDMeta.GetHead(); +} + +BOOL CMainFrame::AppendMenuEx(CMenu& menu, UINT nFlags, UINT nIDNewItem, CString& text) +{ + text.Replace(_T("&"), _T("&&")); + auto bResult = menu.AppendMenu(nFlags, nIDNewItem, text.GetString()); + if (bResult && (nFlags & MF_DEFAULT)) { + bResult = menu.SetDefaultItem(nIDNewItem); + } + return bResult; +} + +CString CMainFrame::getBestTitle(bool fTitleBarTextTitle) { + CString title; + if (fTitleBarTextTitle && m_pAMMC[0]) { + for (const auto& pAMMC : m_pAMMC) { + if (pAMMC) { + CComBSTR bstr; + if (SUCCEEDED(pAMMC->get_Title(&bstr)) && bstr.Length()) { + title = bstr.m_str; + title.Trim(); + if (!title.IsEmpty()) { + return title; + } + } + } + } + } + + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli, true) && pli.m_label && !pli.m_label.IsEmpty()) { + if (fTitleBarTextTitle || pli.m_bYoutubeDL) { + title = pli.m_label; + return title; + } + } + + CStringW ext = GetFileExt(GetFileName()); + if (ext == ".mpls" && m_bHasBDMeta) { + title = GetBDMVMeta().title; + return title; + } else if (ext != ".mpls") { + m_bHasBDMeta = false; + m_BDMeta.RemoveAll(); + } + + return L""; +} + +void CMainFrame::MediaTransportControlSetMedia() { + if (m_media_trans_control.smtc_updater && m_media_trans_control.smtc_controls) { + TRACE(_T("CMainFrame::MediaTransportControlSetMedia()\n")); + HRESULT ret = S_OK; + bool have_secondary_title = false; + + CString title = getBestTitle(); + if (title.IsEmpty()) { + title = GetFileName(); + } + + CString author; + if (m_pAMMC[0]) { + for (const auto& pAMMC : m_pAMMC) { + if (pAMMC) { + CComBSTR bstr; + if (SUCCEEDED(pAMMC->get_AuthorName(&bstr)) && bstr.Length()) { + author = bstr.m_str; + author.Trim(); + } + } + } + } + + // Set media details + if (m_fAudioOnly) { + ret = m_media_trans_control.smtc_updater->put_Type(ABI::Windows::Media::MediaPlaybackType_Music); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: put_Type error %ld\n"), ret); + return; + } + + CComPtr pMusicDisplayProperties; + ret = m_media_trans_control.smtc_updater->get_MusicProperties(&pMusicDisplayProperties); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: get_MusicProperties error %ld\n"), ret); + return; + } + + if (!title.IsEmpty()) { + HSTRING ttitle; + if (WindowsCreateString(title.GetString(), title.GetLength(), &ttitle) == S_OK) { + ret = pMusicDisplayProperties->put_Title(ttitle); + ASSERT(ret == S_OK); + } + } + if (!author.IsEmpty()) { + HSTRING temp; + if (WindowsCreateString(author.GetString(), author.GetLength(), &temp) == S_OK) { + ret = pMusicDisplayProperties->put_Artist(temp); + ASSERT(ret == S_OK); + } + } + } else { + ret = m_media_trans_control.smtc_updater->put_Type(ABI::Windows::Media::MediaPlaybackType_Video); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: put_Type error %ld\n"), ret); + return; + } + + CComPtr pVideoDisplayProperties; + ret = m_media_trans_control.smtc_updater->get_VideoProperties(&pVideoDisplayProperties); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: get_VideoProperties error %ld\n"), ret); + return; + } + + if (!title.IsEmpty()) { + HSTRING ttitle; + if (WindowsCreateString(title.GetString(), title.GetLength(), &ttitle) == S_OK) { + ret = pVideoDisplayProperties->put_Title(ttitle); + ASSERT(ret == S_OK); + } + } + CString chapter; + if (m_pCB) { + DWORD dwChapCount = m_pCB->ChapGetCount(); + if (dwChapCount) { + REFERENCE_TIME rtNow; + m_pMS->GetCurrentPosition(&rtNow); + + CComBSTR bstr; + long currentChap = m_pCB->ChapLookup(&rtNow, &bstr); + if (bstr.Length()) { + chapter.Format(_T("%s (%ld/%lu)"), bstr.m_str, std::max(0l, currentChap + 1l), dwChapCount); + } else { + chapter.Format(_T("%ld/%lu"), currentChap + 1, dwChapCount); + } + } + } + if (!chapter.IsEmpty() && chapter != title) { + HSTRING temp; + if (WindowsCreateString(chapter.GetString(), chapter.GetLength(), &temp) == S_OK) { + ret = pVideoDisplayProperties->put_Subtitle(temp); + ASSERT(ret == S_OK); + have_secondary_title = true; + } + } + if (!have_secondary_title && !author.IsEmpty() && author != title) { + HSTRING temp; + if (WindowsCreateString(author.GetString(), author.GetLength(), &temp) == S_OK) { + ret = pVideoDisplayProperties->put_Subtitle(temp); + ASSERT(ret == S_OK); + have_secondary_title = true; + } + } + } + + // Thumbnail + CComQIPtr pFilterGraph = m_pGB; + std::vector internalCover; + if (CoverArt::FindEmbedded(pFilterGraph, internalCover)) { + m_media_trans_control.loadThumbnail(internalCover.data(), internalCover.size()); + } else { + CPlaylistItem pli; + if (m_wndPlaylistBar.GetCur(pli) && !pli.m_cover.IsEmpty()) { + m_media_trans_control.loadThumbnail(pli.m_cover); + } else { + CString filename = m_wndPlaylistBar.GetCurFileName(); + CString filename_no_ext; + CString filedir; + if (!PathUtils::IsURL(filename)) { + CPath path = CPath(filename); + if (path.FileExists()) { + path.RemoveExtension(); + filename_no_ext = path.m_strPath; + path.RemoveFileSpec(); + filedir = path.m_strPath; + bool is_file_art = false; + CString img = CoverArt::FindExternal(filename_no_ext, filedir, author, is_file_art); + if (!img.IsEmpty()) { + if (m_fAudioOnly || is_file_art) { + m_media_trans_control.loadThumbnail(img); + } + } + } + } + } + } + + // Update data and status + ret = m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus::MediaPlaybackStatus_Playing); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: put_PlaybackStatus error %ld\n"), ret); + return; + } + ret = m_media_trans_control.smtc_updater->Update(); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: Update error %ld\n"), ret); + return; + } + // Enable + ret = m_media_trans_control.smtc_controls->put_IsEnabled(true); + if (ret != S_OK) { + TRACE(_T("MediaTransControls: put_IsEnabled error %ld\n"), ret); + return; + } + } +} + +void CMainFrame::MediaTransportControlUpdateState(OAFilterState state) { + if (m_media_trans_control.smtc_controls) { + if (state == State_Running) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Playing); + else if (state == State_Paused) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Paused); + else if (state == State_Stopped) m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Stopped); + else m_media_trans_control.smtc_controls->put_PlaybackStatus(ABI::Windows::Media::MediaPlaybackStatus_Changing); + } +} diff --git a/src/mpc-hc/MainFrm.h b/src/mpc-hc/MainFrm.h index 12edc275077..7cfa0d91ac6 100644 --- a/src/mpc-hc/MainFrm.h +++ b/src/mpc-hc/MainFrm.h @@ -1,1411 +1,1411 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#include "ChildView.h" -#include "DVBChannel.h" -#include "DebugShadersDlg.h" -#include "DropTarget.h" -#include "EditListEditor.h" -#include "IBufferInfo.h" -#include "IKeyFrameInfo.h" -#include "MainFrmControls.h" -#include "MouseTouch.h" -#include "MpcApi.h" -#include "PlayerCaptureBar.h" -#include "PlayerInfoBar.h" -#include "PlayerNavigationBar.h" -#include "PlayerPlaylistBar.h" -#include "PlayerSeekBar.h" -#include "PlayerStatusBar.h" -#include "PlayerSubresyncBar.h" -#include "PlayerPreView.h" -#include "PlayerToolBar.h" -#include "SubtitleDlDlg.h" -#include "TimerWrappers.h" -#include "OSD.h" -#include "CMPCThemeMenu.h" -#include "../SubPic/MemSubPic.h" -#include -#include -#include "../DSUtil/FontInstaller.h" -#include "AppSettings.h" -#include "../filters/transform/VSFilter/IDirectVobSub.h" -#include "MediaTransControls.h" -#include "FavoriteOrganizeDlg.h" -#include "AllocatorCommon.h" - -class CDebugShadersDlg; -class CFullscreenWnd; -class SkypeMoodMsgHandler; -struct DisplayMode; -enum MpcCaptionState; -class CMediaTypesDlg; - -interface IDSMChapterBag; -interface IGraphBuilder2; -interface IMFVideoDisplayControl; -interface IMFVideoProcessor; -interface IMadVRCommand; -interface IMadVRInfo; -interface IMadVRFrameGrabber; -interface IMadVRSettings; -interface IMadVRSubclassReplacement; -interface ISubClock; -interface ISubPicAllocatorPresenter2; -interface ISubPicAllocatorPresenter; -interface ISubStream; -interface ISyncClock; -DECLARE_INTERFACE_IID(IAMLine21Decoder_2, "6E8D4A21-310C-11d0-B79A-00AA003767A7"); - -enum class MLS { - CLOSED, - LOADING, - LOADED, - CLOSING, - FAILING, -}; - -enum { - PM_NONE, - PM_FILE, - PM_DVD, - PM_ANALOG_CAPTURE, - PM_DIGITAL_CAPTURE -}; - -class OpenMediaData -{ -public: - // OpenMediaData() {} - virtual ~OpenMediaData() {} // one virtual funct is needed to enable rtti - CString title; - CAtlList subs; -}; - -class OpenFileData : public OpenMediaData -{ -public: - OpenFileData() : rtStart(0), bAddToRecent(true) {} - CAtlList fns; - REFERENCE_TIME rtStart; - ABRepeat abRepeat; - bool bAddToRecent; - CString useragent; - CString referrer; -}; - -class OpenDVDData : public OpenMediaData -{ -public: - // OpenDVDData() {} - CString path; - CComPtr pDvdState; -}; - -class OpenDeviceData : public OpenMediaData -{ -public: - OpenDeviceData() { - vinput = vchannel = ainput = -1; - } - CStringW DisplayName[2]; - int vinput, vchannel, ainput; -}; - -class TunerScanData -{ -public: - ULONG FrequencyStart; - ULONG FrequencyStop; - ULONG Bandwidth; - ULONG SymbolRate; - LONG Offset; - HWND Hwnd; -}; - -struct SeekToCommand { - REFERENCE_TIME rtPos; - ULONGLONG seekTime; - bool bShowOSD; -}; - -struct SubtitleInput { - CComQIPtr pSubStream; - CComPtr pSourceFilter; - - SubtitleInput() {}; - SubtitleInput(CComQIPtr pSubStream) : pSubStream(pSubStream) {}; - SubtitleInput(CComQIPtr pSubStream, CComPtr pSourceFilter) - : pSubStream(pSubStream), pSourceFilter(pSourceFilter) {}; -}; - -struct FileFavorite { - CString Name; - REFERENCE_TIME Start; - REFERENCE_TIME MarkA; - REFERENCE_TIME MarkB; - BOOL RelativeDrive; - - FileFavorite() { - Start = MarkA = MarkB = 0; - RelativeDrive = FALSE; - } - - static bool TryParse(const CString& fav, FileFavorite& ff); - static bool TryParse(const CString& fav, FileFavorite& ff, CAtlList& parts); - - CString ToString() const; -}; - -///////////////////////////////////////////////////////////////////////////// -// CMainFrame - -class CMainFrame : public CFrameWnd, public CDropClient -{ -public: - - DpiHelper m_dpi; - - enum class TimerHiderSubscriber { - TOOLBARS_HIDER, - CURSOR_HIDER, - CURSOR_HIDER_D3DFS, - }; - OnDemandTimer m_timerHider; - - enum class TimerOneTimeSubscriber { - TOOLBARS_DELAY_NOTLOADED, - CHILDVIEW_CURSOR_HACK, - DELAY_IDLE, - ACTIVE_SHADER_FILES_CHANGE_COOLDOWN, - DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, - DVBINFO_UPDATE, - STATUS_ERASE, - PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW, - AUTOFIT_TIMEOUT - }; - OneTimeTimerPool m_timerOneTime; - -private: - EventClient m_eventc; - void EventCallback(MpcEvent ev); - - CMainFrameMouseHook m_mouseHook; - - enum { - TIMER_STREAMPOSPOLLER = 1, - TIMER_STREAMPOSPOLLER2, - TIMER_STATS, - TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS, - TIMER_HIDER, - TIMER_WINDOW_FULLSCREEN, - TIMER_DELAYEDSEEK, - TIMER_ONETIME_START, - TIMER_ONETIME_END = TIMER_ONETIME_START + 127, - }; - enum { - SEEK_DIRECTION_NONE, - SEEK_DIRECTION_BACKWARD, - SEEK_DIRECTION_FORWARD - }; - enum { - ZOOM_DEFAULT_LEVEL = 0, - ZOOM_AUTOFIT = -1, - ZOOM_AUTOFIT_LARGER = -2 - }; - - - typedef std::map PlaybackRateMap; - static PlaybackRateMap filePlaybackRates; - static PlaybackRateMap dvdPlaybackRates; - - friend class CPPageFileInfoSheet; - friend class CPPageLogo; - friend class CMouse; - friend class CPlayerSeekBar; // for accessing m_controls.ControlChecked() - friend class CChildView; // for accessing m_controls.DelayShowNotLoaded() - friend class CFullscreenWnd; // for accessing m_controls.DelayShowNotLoaded() - friend class CMouseWndWithArtView; // for accessing m_controls.DelayShowNotLoaded() - friend class SubtitlesProvider; - - // TODO: wrap these graph objects into a class to make it look cleaner - - CComPtr m_pGB; - CComQIPtr m_pMC; - CComQIPtr m_pME; - CComQIPtr m_pVW; - CComQIPtr m_pBV; - CComQIPtr m_pBA; - CComQIPtr m_pMS; - CComQIPtr m_pFS; - CComQIPtr m_pFSF; - CComQIPtr m_pKFI; - CComQIPtr m_pQP; - CComQIPtr m_pBI; - CComQIPtr m_pAMOP; - CComQIPtr m_pAMMC[2]; - CComQIPtr m_pAMNS; - CComQIPtr m_pAudioSwitcherSS; - CComQIPtr m_pSplitterSS; - CComQIPtr m_pSplitterDubSS; - CComQIPtr m_pOtherSS[2]; - // SmarkSeek - CComPtr m_pGB_preview; - CComQIPtr m_pMC_preview; - //CComQIPtr m_pME_preview; - CComQIPtr m_pMS_preview; - CComQIPtr m_pVW_preview; - CComQIPtr m_pBV_preview; - //CComQIPtr m_pFS_preview; - CComQIPtr m_pDVDC_preview; - CComQIPtr m_pDVDI_preview; // VtX: usually not necessary but may sometimes be necessary. - CComPtr m_pMFVDC_preview; - CComPtr m_pVMR9C_preview; - CComPtr m_pMFVP_preview; - CComPtr m_pCAP2_preview; - int defaultVideoAngle; - // - CComPtr m_pVMRMC; - CComPtr m_pMFVDC; - CComPtr m_pMFVP; - CComPtr m_pVMB; - CComPtr m_pMFVMB; - CComPtr m_pVMRWC; - - CComPtr m_pCAP; - CComPtr m_pCAP2; - CComPtr m_pCAP3; - - CComPtr m_pMVRS; - CComPtr m_pMVRSR; - CComPtr m_pMVRC; - CComPtr m_pMVRI; - CComPtr m_pMVRFG; - CComPtr m_pMVTO; - - CComPtr m_pD3DFSC; - - CComQIPtr m_pDVDC; - CComQIPtr m_pDVDI; - CComPtr m_pLN21; - - CComPtr m_pCGB; - CStringW m_VidDispName, m_AudDispName; - CComPtr m_pVidCap, m_pAudCap; - CComPtr m_pAMVCCap, m_pAMVCPrev; - CComPtr m_pAMVSCCap, m_pAMVSCPrev, m_pAMASC; - CComPtr m_pAMXBar; - CComPtr m_pAMTuner; - CComPtr m_pAMDF; - - CComPtr m_pProv; - - CComQIPtr m_pDVS; - CComQIPtr m_pDVS2; - - bool m_bUsingDXVA; - LPCTSTR m_HWAccelType; - void UpdateDXVAStatus(); - - void SetVolumeBoost(UINT nAudioBoost); - void SetBalance(int balance); - - // temp fonts loader - CFontInstaller m_FontInstaller; - - // subtitles - - CCritSec m_csSubLock; - CCritSec m_csSubtitleManagementLock; - - CList m_pSubStreams; - std::list m_ExternalSubstreams; - POSITION m_posFirstExtSub; - SubtitleInput m_pCurrentSubInput; - - // StatusBar message text parts - CString currentAudioLang; - CString currentSubLang; - CString m_statusbarVideoFormat; - CString m_statusbarAudioFormat; - CString m_statusbarVideoSize; - - SubtitleInput* GetSubtitleInput(int& i, bool bIsOffset = false); - int UpdateSelectedAudioStreamInfo(int index, AM_MEDIA_TYPE* pmt, LCID lcid); - bool IsValidSubtitleStream(int i); - int GetSelectedSubtitleTrackIndex(); - - friend class CTextPassThruFilter; - - // windowing - - bool m_bDelaySetOutputRect; - - CRect m_lastWindowRect; - - void SetDefaultWindowRect(int iMonitor = 0); - void SetDefaultFullscreenState(); - void RestoreDefaultWindowRect(); - CRect GetInvisibleBorderSize() const; - CSize GetVideoOrArtSize(MINMAXINFO& mmi); - CSize GetZoomWindowSize(double dScale, bool ignore_video_size = false); - bool GetWorkAreaRect(CRect& work); - CRect GetZoomWindowRect(const CSize& size, bool ignoreSavedPosition = false); - void ZoomVideoWindow(double dScale = ZOOM_DEFAULT_LEVEL, bool ignore_video_size = false); - double GetZoomAutoFitScale(); - - bool alwaysOnTopZOrderInitialized = false; - void SetAlwaysOnTop(int iOnTop); - bool WindowExpectedOnTop(); - - // dynamic menus - - void CreateDynamicMenus(); - void DestroyDynamicMenus(); - void SetupOpenCDSubMenu(); - void SetupFiltersSubMenu(); - void SetupAudioSubMenu(); - void SetupSubtitlesSubMenu(); - void SetupVideoStreamsSubMenu(); - void SetupJumpToSubMenus(CMenu* parentMenu = nullptr, int iInsertPos = -1); - void SetupFavoritesSubMenu(); - bool SetupShadersSubMenu(); - void SetupRecentFilesSubMenu(); - - DWORD SetupNavStreamSelectSubMenu(CMenu& subMenu, UINT id, DWORD dwSelGroup); - void OnNavStreamSelectSubMenu(UINT id, DWORD dwSelGroup); - void OnStreamSelect(bool forward, DWORD dwSelGroup); - static CString GetStreamOSDString(CString name, LCID lcid, DWORD dwSelGroup); - - void CreateOSDBar(); - bool OSDBarSetPos(); - void DestroyOSDBar(); - - CMPCThemeMenu m_mainPopupMenu, m_popupMenu; - CMPCThemeMenu m_openCDsMenu; - CMPCThemeMenu m_filtersMenu, m_subtitlesMenu, m_audiosMenu, m_videoStreamsMenu; - CMPCThemeMenu m_chaptersMenu, m_titlesMenu, m_playlistMenu, m_BDPlaylistMenu, m_channelsMenu; - CMPCThemeMenu m_favoritesMenu; - CMPCThemeMenu m_shadersMenu; - CMPCThemeMenu m_recentFilesMenu; - int recentFilesMenuFromMRUSequence; - - UINT m_nJumpToSubMenusCount; - - CInterfaceArray m_pparray; - CInterfaceArray m_ssarray; - - // chapters (file mode) - CComPtr m_pCB; - void SetupChapters(); - void SetupCueChapters(CString fn); - - // chapters (DVD mode) - void SetupDVDChapters(); - - bool SeekToFileChapter(int iChapter, bool bRelative = false); - bool SeekToDVDChapter(int iChapter, bool bRelative = false); - - void AddTextPassThruFilter(); - - int m_nLoops; - ABRepeat abRepeat, reloadABRepeat; - UINT m_nLastSkipDirection; - - int m_iStreamPosPollerInterval; - - bool m_fCustomGraph; - bool m_fShockwaveGraph; - - CComPtr m_pSubClock; - - bool m_fFrameSteppingActive; - int m_nStepForwardCount; - REFERENCE_TIME m_rtStepForwardStart; - int m_nVolumeBeforeFrameStepping; - - bool m_fEndOfStream; - ULONGLONG m_dwLastPause; - ULONGLONG m_dwReloadPos; - int m_iReloadAudioIdx; - int m_iReloadSubIdx; - - bool m_bRememberFilePos; - - ULONGLONG m_dwLastRun; - - bool m_bBuffering; - - bool m_fLiveWM; - - bool delayingFullScreen; - - bool m_bIsMPCVRExclusiveMode = false; - - void SendStatusMessage(CString msg, int nTimeOut); - CString m_tempstatus_msg, m_closingmsg; - - REFERENCE_TIME m_rtDurationOverride; - - void CleanGraph(); - - void ShowOptions(int idPage = 0); - - HRESULT GetDisplayedImage(std::vector& dib, CString& errmsg); - HRESULT GetCurrentFrame(std::vector& dib, CString& errmsg); - HRESULT GetOriginalFrame(std::vector& dib, CString& errmsg); - HRESULT RenderCurrentSubtitles(BYTE* pData); - bool GetDIB(BYTE** ppData, long& size, bool fSilent = false); - void SaveDIB(LPCTSTR fn, BYTE* pData, long size); - CString MakeSnapshotFileName(BOOL thumbnails); - BOOL IsRendererCompatibleWithSaveImage(); - void SaveImage(LPCTSTR fn, bool displayed, bool includeSubtitles); - void SaveThumbnails(LPCTSTR fn); - - // - - friend class CWebClientSocket; - friend class CWebServer; - CAutoPtr m_pWebServer; - int m_iPlaybackMode; - ULONG m_lCurrentChapter; - ULONG m_lChapterStartTime; - - CString m_currentCoverAuthor; - CString m_currentCoverPath; - bool currentCoverIsFileArt = false; - - CAutoPtr m_pSkypeMoodMsgHandler; - void SendNowPlayingToSkype(); - - MLS m_eMediaLoadState; - OAFilterState m_CachedFilterState; - - bool m_bSettingUpMenus; - bool m_bOpenMediaActive; - int m_OpenMediaFailedCount; - - REFTIME GetAvgTimePerFrame() const; - void OnVideoSizeChanged(const bool bWasAudioOnly = false); - - CDropTarget m_dropTarget; - void OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) override; - DROPEFFECT OnDropAccept(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) override; - -public: - void StartWebServer(int nPort); - void StopWebServer(); - - int GetPlaybackMode() const { - return m_iPlaybackMode; - } - bool IsPlaybackCaptureMode() const { - return GetPlaybackMode() == PM_ANALOG_CAPTURE || GetPlaybackMode() == PM_DIGITAL_CAPTURE; - } - void SetPlaybackMode(int iNewStatus); - bool IsMuted() { - return m_wndToolBar.GetVolume() == -10000; - } - int GetVolume() { - return m_wndToolBar.m_volctrl.GetPos(); - } - double GetPlayingRate() const { - return m_dSpeedRate; - } - -public: - CMainFrame(); - DECLARE_DYNAMIC(CMainFrame) - - // Attributes -public: - bool m_fFullScreen; - bool m_bNeedZoomAfterFullscreenExit; - bool m_fStartInD3DFullscreen; - bool m_fStartInFullscreenSeparate; - bool m_bFullScreenWindowIsD3D; - bool m_bFullScreenWindowIsOnSeparateDisplay; - - CComPtr m_pRefClock; // Adjustable reference clock. GothSync - CComPtr m_pSyncClock; - - bool IsFrameLessWindow() const; - bool IsCaptionHidden() const; - bool IsMenuHidden() const; - bool IsPlaylistEmpty() const; - bool IsInteractiveVideo() const; - bool IsFullScreenMode() const; - bool IsFullScreenMainFrame() const; - bool IsFullScreenMainFrameExclusiveMPCVR() const; - bool IsFullScreenSeparate() const; - bool HasDedicatedFSVideoWindow() const; - bool IsD3DFullScreenMode() const; - bool IsSubresyncBarVisible() const; - - CControlBar* m_pLastBar; - -protected: - bool m_bUseSeekPreview; - bool m_bFirstPlay; - bool m_bOpeningInAutochangedMonitorMode; - bool m_bPausedForAutochangeMonitorMode; - bool restoringWindowRect; - - bool m_fAudioOnly; - bool m_fValidDVDOpen; - CString m_LastOpenBDPath; - CAutoPtr m_lastOMD; - - DVD_DOMAIN m_iDVDDomain; - DWORD m_iDVDTitle; - bool m_bDVDStillOn; - int m_loadedAudioTrackIndex = -1; - int m_loadedSubtitleTrackIndex = -1; - int m_audioTrackCount = 0; - - double m_dSpeedRate; - double m_ZoomX, m_ZoomY, m_PosX, m_PosY; - int m_AngleX, m_AngleY, m_AngleZ; - int m_iDefRotation; - - void ForceCloseProcess(); - - // Operations - bool OpenMediaPrivate(CAutoPtr pOMD); - void CloseMediaPrivate(); - void DoTunerScan(TunerScanData* pTSD); - - CWnd* GetModalParent(); - - CCritSec lockModalDialog; - CMediaTypesDlg* mediaTypesErrorDlg; - void ShowMediaTypesDialog(); - - void OpenCreateGraphObject(OpenMediaData* pOMD); - void OpenFile(OpenFileData* pOFD); - void OpenDVD(OpenDVDData* pODD); - void OpenCapture(OpenDeviceData* pODD); - HRESULT OpenBDAGraph(); - void OpenCustomizeGraph(); - void OpenSetupVideo(); - void OpenSetupAudio(); - void OpenSetupInfoBar(bool bClear = true); - void UpdateChapterInInfoBar(); - void OpenSetupStatsBar(); - void CheckSelectedAudioStream(); - void OpenSetupStatusBar(); - void OpenSetupCaptureBar(); - void OpenSetupWindowTitle(bool reset = false); - -public: - static bool GetCurDispMode(const CString& displayName, DisplayMode& dm); - static bool GetDispMode(CString displayName, int i, DisplayMode& dm); - -protected: - void SetDispMode(CString displayName, const DisplayMode& dm, int msAudioDelay); - void AutoChangeMonitorMode(); - - void GraphEventComplete(); - - friend class CGraphThread; - CGraphThread* m_pGraphThread; - bool m_bOpenedThroughThread; - ATL::CEvent m_evOpenPrivateFinished; - ATL::CEvent m_evClosePrivateFinished; - - void LoadKeyFrames(); - std::vector m_kfs; - - bool m_fOpeningAborted; - bool m_bWasSnapped; - -protected: - friend class CSubtitleDlDlg; - CSubtitleDlDlg m_wndSubtitlesDownloadDialog; - CFavoriteOrganizeDlg m_wndFavoriteOrganizeDialog; - friend class CPPageSubMisc; - - friend class SubtitlesProviders; - std::unique_ptr m_pSubtitlesProviders; - friend struct SubtitlesInfo; - friend class SubtitlesTask; - friend class SubtitlesThread; - -public: - void OpenCurPlaylistItem(REFERENCE_TIME rtStart = 0, bool reopen = false, ABRepeat abRepeat = ABRepeat()); - void OpenMedia(CAutoPtr pOMD); - void PlayFavoriteFile(const CString& fav); - void PlayFavoriteDVD(CString fav); - FileFavorite ParseFavoriteFile(const CString& fav, CAtlList& args, REFERENCE_TIME* prtStart = nullptr); - bool ResetDevice(); - bool DisplayChange(); - void CloseMediaBeforeOpen(); - void CloseMedia(bool bNextIsQueued = false, bool bPendingFileDelete = false); - void StartTunerScan(CAutoPtr pTSD); - void StopTunerScan(); - HRESULT SetChannel(int nChannel); - - void AddCurDevToPlaylist(); - - bool m_bTrayIcon; - void ShowTrayIcon(bool bShow); - void SetTrayTip(const CString& str); - - CSize GetVideoSize() const; - CSize GetVideoSizeWithRotation(bool forPreview = false) const; - void HidePlaylistFullScreen(bool force = false); - void ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo); - void ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo); - void MoveVideoWindow(bool fShowStats = false, bool bSetStoppedVideoRect = false); - void SetPreviewVideoPosition(); - - void RepaintVideo(const bool bForceRepaint = false); - void HideVideoWindow(bool fHide); - - OAFilterState GetMediaStateDirect() const; - OAFilterState GetMediaState() const; - OAFilterState CMainFrame::UpdateCachedMediaState(); - bool MediaControlRun(bool waitforcompletion = false); - bool MediaControlPause(bool waitforcompletion = false); - bool MediaControlStop(bool waitforcompletion = false); - bool MediaControlStopPreview(); - - REFERENCE_TIME GetPos() const; - REFERENCE_TIME GetDur() const; - bool GetKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMin, REFERENCE_TIME rtMax, bool nearest, REFERENCE_TIME& keyframetime) const; - REFERENCE_TIME GetClosestKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMaxForwardDiff, REFERENCE_TIME rtMaxBackwardDiff) const; - REFERENCE_TIME GetClosestKeyFramePreview(REFERENCE_TIME rtTarget) const; - void SeekTo(REFERENCE_TIME rt, bool bShowOSD = true); - void DoSeekTo(REFERENCE_TIME rt, bool bShowOSD = true); - SeekToCommand queuedSeek; - ULONGLONG lastSeekStart; - ULONGLONG lastSeekFinish; - void SetPlayingRate(double rate); - - int SetupAudioStreams(); - int SetupSubtitleStreams(); - - bool LoadSubtitle(CString fn, SubtitleInput* pSubInput = nullptr, bool bAutoLoad = false); - bool LoadSubtitle(CYoutubeDLInstance::YDLSubInfo& sub); - bool SetSubtitle(int i, bool bIsOffset = false, bool bDisplayMessage = false); - void SetSubtitle(const SubtitleInput& subInput, bool skip_lcid = false); - void UpdateSubtitleColorInfo(); - void ToggleSubtitleOnOff(bool bDisplayMessage = false); - void ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew); - void InvalidateSubtitle(DWORD_PTR nSubtitleId = DWORD_PTR_MAX, REFERENCE_TIME rtInvalidate = -1); - void ReloadSubtitle(); - void UpdateSubtitleRenderingParameters(); - HRESULT InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinto); - - void SetAudioTrackIdx(int index); - void SetSubtitleTrackIdx(int index); - int GetCurrentAudioTrackIdx(CString *pstrName = nullptr); - int GetCurrentSubtitleTrackIdx(CString *pstrName = nullptr); - - void AddFavorite(bool fDisplayMessage = false, bool fShowDialog = true); - - CString GetFileName(); - CString GetCaptureTitle(); - - // shaders - void SetShaders(bool bSetPreResize = true, bool bSetPostResize = true); - - bool m_bToggleShader; - bool m_bToggleShaderScreenSpace; - std::list m_ShaderCache; - ShaderC* GetShader(CString path, bool bD3D11); - bool SaveShaderFile(ShaderC* shader); - bool DeleteShaderFile(LPCWSTR label); - void TidyShaderCache(); - - // 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(); - - void DoAfterPlaybackEvent(); - bool SearchInDir(bool bDirForward, bool bLoop = false); - bool WildcardFileSearch(CString searchstr, std::set& results, bool recurse_dirs); - CString lastOpenFile; - bool CanSkipFromClosedFile(); - - 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); - void EnableDocking(DWORD dwDockStyle); - - // DVB capture - void UpdateCurrentChannelInfo(bool bShowOSD = true, bool bShowInfoBar = false); - LRESULT OnCurrentChannelInfoUpdated(WPARAM wParam, LPARAM lParam); - - bool CheckABRepeat(REFERENCE_TIME& aPos, REFERENCE_TIME& bPos); - void PerformABRepeat(); - void DisableABRepeat(); - - struct DVBState { - struct EITData { - HRESULT hr = E_FAIL; - EventDescriptor NowNext; - bool bShowOSD = true; - bool bShowInfoBar = false; - }; - - CString sChannelName; // Current channel name - CBDAChannel* pChannel = nullptr; // Pointer to current channel object - EventDescriptor NowNext; // Current channel EIT - bool bActive = false; // True when channel is active - bool bSetChannelActive = false; // True when channel change is in progress - bool bInfoActive = false; // True when EIT data update is in progress - bool bAbortInfo = true; // True when aborting current EIT update - std::future infoData; - - void Reset() { - sChannelName.Empty(); - pChannel = nullptr; - NowNext = EventDescriptor(); - bActive = false; - bSetChannelActive = false; - bInfoActive = false; - bAbortInfo = true; - } - - void Join() { - if (infoData.valid()) { - bAbortInfo = true; - infoData.wait(); - } - } - - ~DVBState() { - bAbortInfo = true; - } - }; - - std::unique_ptr m_pDVBState = nullptr; - - // Implementation -public: - virtual ~CMainFrame(); -#ifdef _DEBUG - virtual void AssertValid() const; - virtual void Dump(CDumpContext& dc) const; -#endif - -protected: // control bar embedded members - friend class CMainFrameControls; - friend class CPPageToolBar; - CMainFrameControls m_controls; - friend class CPlayerBar; // it notifies m_controls of panel re-dock - - CChildView m_wndView; - - CPlayerSeekBar m_wndSeekBar; - CPlayerToolBar m_wndToolBar; - CPlayerInfoBar m_wndInfoBar; - CPlayerInfoBar m_wndStatsBar; - CPlayerStatusBar m_wndStatusBar; - - CPlayerSubresyncBar m_wndSubresyncBar; - CPlayerPlaylistBar m_wndPlaylistBar; - CPlayerCaptureBar m_wndCaptureBar; - CPlayerNavigationBar m_wndNavigationBar; - CEditListEditor m_wndEditListEditor; - - std::unique_ptr m_pDebugShaders; - - LPCTSTR GetRecentFile() const; - - friend class CPPagePlayback; // TODO - friend class CPPageAudioSwitcher; // TODO - friend class CMPlayerCApp; // TODO - - // Generated message map functions - - DECLARE_MESSAGE_MAP() - -public: - afx_msg int OnNcCreate(LPCREATESTRUCT lpCreateStruct); - 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 OnEnterSizeMove(); - afx_msg void OnMoving(UINT fwSide, LPRECT pRect); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnSizing(UINT nSide, LPRECT lpRect); - afx_msg void OnExitSizeMove(); - afx_msg void OnDisplayChange(); - afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); - - LRESULT OnDpiChanged(WPARAM wParam, LPARAM lParam); - - 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 void SaveAppSettings(); - - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - - void RestoreFocus(); - - afx_msg void OnInitMenu(CMenu* pMenu); - afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); - afx_msg void OnUnInitMenuPopup(CMenu* pPopupMenu, UINT nFlags); - afx_msg void OnEnterMenuLoop(BOOL bIsTrackPopupMenu); - - afx_msg BOOL OnQueryEndSession(); - afx_msg void OnEndSession(BOOL bEnding); - - BOOL OnMenu(CMenu* pMenu); - afx_msg void OnMenuPlayerShort(); - afx_msg void OnMenuPlayerLong(); - afx_msg void OnMenuFilters(); - - afx_msg void OnUpdatePlayerStatus(CCmdUI* pCmdUI); - - afx_msg LRESULT OnFilePostOpenmedia(WPARAM wParam, LPARAM lparam); - afx_msg LRESULT OnOpenMediaFailed(WPARAM wParam, LPARAM lParam); - void OnFilePostClosemedia(bool bNextIsQueued = false); - - afx_msg void OnBossKey(); - - afx_msg void OnStreamAudio(UINT nID); - afx_msg void OnStreamSub(UINT nID); - afx_msg void OnStreamSubOnOff(); - afx_msg void OnAudioShiftOnOff(); - afx_msg void OnDvdAngle(UINT nID); - afx_msg void OnDvdAudio(UINT nID); - afx_msg void OnDvdSub(UINT nID); - afx_msg void OnDvdSubOnOff(); - - afx_msg LRESULT OnLoadSubtitles(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnGetSubtitles(WPARAM, LPARAM lParam); - - // menu item handlers - - INT_PTR DoFileDialogWithLastFolder(CFileDialog& fd, CStringW& lastPath); - void OpenDVDOrBD(CStringW path); - - 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 OnFileOpenOpticalDisk(UINT nID); - afx_msg void OnFileReopen(); - afx_msg void OnFileRecycle(); - afx_msg void OnFileSaveAs(); - afx_msg void OnUpdateFileSaveAs(CCmdUI* pCmdUI); - afx_msg void OnFileSaveImage(); - afx_msg void OnFileSaveImageAuto(); - afx_msg void OnUpdateFileSaveImage(CCmdUI* pCmdUI); - afx_msg void OnCmdLineSaveThumbnails(); - afx_msg void OnFileSaveThumbnails(); - afx_msg void OnUpdateFileSaveThumbnails(CCmdUI* pCmdUI); - afx_msg void OnFileSubtitlesLoad(); - afx_msg void OnUpdateFileSubtitlesLoad(CCmdUI* pCmdUI); - afx_msg void OnFileSubtitlesSave() { SubtitlesSave(); } - afx_msg void OnUpdateFileSubtitlesSave(CCmdUI* pCmdUI); - //afx_msg void OnFileSubtitlesUpload(); - //afx_msg void OnUpdateFileSubtitlesUpload(CCmdUI* pCmdUI); - afx_msg void OnFileSubtitlesDownload(); - afx_msg void OnUpdateFileSubtitlesDownload(CCmdUI* pCmdUI); - afx_msg void OnFileProperties(); - afx_msg void OnUpdateFileProperties(CCmdUI* pCmdUI); - afx_msg void OnFileOpenLocation(); - afx_msg void OnFileCloseAndRestore(); - afx_msg void OnFileCloseMedia(); // no menu item - afx_msg void OnUpdateFileClose(CCmdUI* pCmdUI); - - void SetCaptionState(MpcCaptionState eState); - afx_msg void OnViewCaptionmenu(); - - afx_msg void OnViewNavigation(); - afx_msg void OnUpdateViewCaptionmenu(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewNavigation(CCmdUI* pCmdUI); - afx_msg void OnViewControlBar(UINT nID); - afx_msg void OnUpdateViewControlBar(CCmdUI* pCmdUI); - afx_msg void OnViewSubresync(); - afx_msg void OnUpdateViewSubresync(CCmdUI* pCmdUI); - afx_msg void OnViewPlaylist(); - afx_msg void OnPlaylistToggleShuffle(); - afx_msg void OnUpdateViewPlaylist(CCmdUI* pCmdUI); - afx_msg void OnViewEditListEditor(); - afx_msg void OnEDLIn(); - afx_msg void OnUpdateEDLIn(CCmdUI* pCmdUI); - afx_msg void OnEDLOut(); - afx_msg void OnUpdateEDLOut(CCmdUI* pCmdUI); - afx_msg void OnEDLNewClip(); - afx_msg void OnUpdateEDLNewClip(CCmdUI* pCmdUI); - afx_msg void OnEDLSave(); - afx_msg void OnUpdateEDLSave(CCmdUI* pCmdUI); - afx_msg void OnViewCapture(); - afx_msg void OnUpdateViewCapture(CCmdUI* pCmdUI); - afx_msg void OnViewDebugShaders(); - afx_msg void OnUpdateViewDebugShaders(CCmdUI* pCmdUI); - afx_msg void OnViewMinimal(); - afx_msg void OnUpdateViewMinimal(CCmdUI* pCmdUI); - afx_msg void OnViewCompact(); - afx_msg void OnUpdateViewCompact(CCmdUI* pCmdUI); - afx_msg void OnViewNormal(); - afx_msg void OnUpdateViewNormal(CCmdUI* pCmdUI); - afx_msg void OnViewFullscreen(); - afx_msg void OnViewFullscreenSecondary(); - afx_msg void OnUpdateViewFullscreen(CCmdUI* pCmdUI); - afx_msg void OnViewZoom(UINT nID); - afx_msg void OnUpdateViewZoom(CCmdUI* pCmdUI); - afx_msg void OnViewZoomAutoFit(); - afx_msg void OnViewZoomAutoFitLarger(); - afx_msg void OnViewModifySize(UINT nID); - afx_msg void OnViewDefaultVideoFrame(UINT nID); - afx_msg void OnUpdateViewDefaultVideoFrame(CCmdUI* pCmdUI); - afx_msg void OnViewSwitchVideoFrame(); - afx_msg void OnUpdateViewSwitchVideoFrame(CCmdUI* pCmdUI); - afx_msg void OnViewCompMonDeskARDiff(); - afx_msg void OnUpdateViewCompMonDeskARDiff(CCmdUI* pCmdUI); - afx_msg void OnViewPanNScan(UINT nID); - afx_msg void OnUpdateViewPanNScan(CCmdUI* pCmdUI); - afx_msg void OnViewPanNScanPresets(UINT nID); - afx_msg void OnUpdateViewPanNScanPresets(CCmdUI* pCmdUI); - afx_msg void OnViewRotate(UINT nID); - afx_msg void OnUpdateViewRotate(CCmdUI* pCmdUI); - afx_msg void OnViewAspectRatio(UINT nID); - afx_msg void OnUpdateViewAspectRatio(CCmdUI* pCmdUI); - afx_msg void OnViewAspectRatioNext(); - afx_msg void OnViewOntop(UINT nID); - afx_msg void OnUpdateViewOntop(CCmdUI* pCmdUI); - afx_msg void OnViewOptions(); - afx_msg void OnUpdateViewTearingTest(CCmdUI* pCmdUI); - afx_msg void OnViewTearingTest(); - afx_msg void OnUpdateViewDisplayRendererStats(CCmdUI* pCmdUI); - afx_msg void OnViewResetRendererStats(); - afx_msg void OnViewDisplayRendererStats(); - afx_msg void OnUpdateViewVSync(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewVSyncOffset(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewVSyncAccurate(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewFlushGPU(CCmdUI* pCmdUI); - - afx_msg void OnUpdateViewSynchronizeVideo(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewSynchronizeDisplay(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewSynchronizeNearest(CCmdUI* pCmdUI); - - afx_msg void OnUpdateViewD3DFullscreen(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewDisableDesktopComposition(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewAlternativeVSync(CCmdUI* pCmdUI); - - afx_msg void OnUpdateViewColorManagementEnable(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewColorManagementInput(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewColorManagementAmbientLight(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewColorManagementIntent(CCmdUI* pCmdUI); - - afx_msg void OnUpdateViewEVROutputRange(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewFullscreenGUISupport(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewHighColorResolution(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewForceInputHighColorResolution(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewFullFloatingPointProcessing(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewHalfFloatingPointProcessing(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewEnableFrameTimeCorrection(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewVSyncOffsetIncrease(CCmdUI* pCmdUI); - afx_msg void OnUpdateViewVSyncOffsetDecrease(CCmdUI* pCmdUI); - afx_msg void OnViewVSync(); - afx_msg void OnViewVSyncAccurate(); - - afx_msg void OnViewSynchronizeVideo(); - afx_msg void OnViewSynchronizeDisplay(); - afx_msg void OnViewSynchronizeNearest(); - - afx_msg void OnViewColorManagementEnable(); - afx_msg void OnViewColorManagementInputAuto(); - afx_msg void OnViewColorManagementInputHDTV(); - afx_msg void OnViewColorManagementInputSDTV_NTSC(); - afx_msg void OnViewColorManagementInputSDTV_PAL(); - afx_msg void OnViewColorManagementAmbientLightBright(); - afx_msg void OnViewColorManagementAmbientLightDim(); - afx_msg void OnViewColorManagementAmbientLightDark(); - afx_msg void OnViewColorManagementIntentPerceptual(); - afx_msg void OnViewColorManagementIntentRelativeColorimetric(); - afx_msg void OnViewColorManagementIntentSaturation(); - afx_msg void OnViewColorManagementIntentAbsoluteColorimetric(); - - afx_msg void OnViewEVROutputRange_0_255(); - afx_msg void OnViewEVROutputRange_16_235(); - - afx_msg void OnViewFlushGPUBeforeVSync(); - afx_msg void OnViewFlushGPUAfterVSync(); - afx_msg void OnViewFlushGPUWait(); - - afx_msg void OnViewD3DFullScreen(); - afx_msg void OnViewDisableDesktopComposition(); - afx_msg void OnViewAlternativeVSync(); - afx_msg void OnViewResetDefault(); - afx_msg void OnViewResetOptimal(); - - afx_msg void OnViewFullscreenGUISupport(); - afx_msg void OnViewHighColorResolution(); - afx_msg void OnViewForceInputHighColorResolution(); - afx_msg void OnViewFullFloatingPointProcessing(); - afx_msg void OnViewHalfFloatingPointProcessing(); - afx_msg void OnViewEnableFrameTimeCorrection(); - afx_msg void OnViewVSyncOffsetIncrease(); - afx_msg void OnViewVSyncOffsetDecrease(); - afx_msg void OnUpdateShaderToggle1(CCmdUI* pCmdUI); - afx_msg void OnUpdateShaderToggle2(CCmdUI* pCmdUI); - afx_msg void OnShaderToggle1(); - afx_msg void OnShaderToggle2(); - afx_msg void OnUpdateViewOSDDisplayTime(CCmdUI* pCmdUI); - afx_msg void OnViewOSDDisplayTime(); - afx_msg void OnUpdateViewOSDShowFileName(CCmdUI* pCmdUI); - afx_msg void OnViewOSDShowFileName(); - afx_msg void OnD3DFullscreenToggle(); - afx_msg void OnGotoSubtitle(UINT nID); - afx_msg void OnSubresyncShiftSub(UINT nID); - afx_msg void OnSubtitleDelay(UINT nID); - afx_msg void OnSubtitlePos(UINT nID); - afx_msg void OnSubtitleFontSize(UINT nID); - - afx_msg void OnPlayPlay(); - afx_msg void OnPlayPause(); - afx_msg void OnPlayPlaypause(); - afx_msg void OnApiPlay(); - afx_msg void OnApiPause(); - afx_msg void OnPlayStop(); - void OnPlayStop(bool is_closing); - afx_msg void OnUpdatePlayPauseStop(CCmdUI* pCmdUI); - afx_msg void OnPlayFramestep(UINT nID); - afx_msg void OnUpdatePlayFramestep(CCmdUI* pCmdUI); - afx_msg void OnPlaySeek(UINT nID); - afx_msg void OnPlaySeekSet(); - afx_msg void OnPlaySeekKey(UINT nID); // no menu item - afx_msg void OnUpdatePlaySeek(CCmdUI* pCmdUI); - afx_msg void OnPlayChangeRate(UINT nID); - afx_msg void OnUpdatePlayChangeRate(CCmdUI* pCmdUI); - afx_msg void OnPlayResetRate(); - afx_msg void OnUpdatePlayResetRate(CCmdUI* pCmdUI); - afx_msg void OnPlayChangeAudDelay(UINT nID); - afx_msg void OnUpdatePlayChangeAudDelay(CCmdUI* pCmdUI); - afx_msg void OnPlayFiltersCopyToClipboard(); - afx_msg void OnPlayFilters(UINT nID); - afx_msg void OnUpdatePlayFilters(CCmdUI* pCmdUI); - afx_msg void OnPlayShadersSelect(); - afx_msg void OnPlayShadersPresetNext(); - afx_msg void OnPlayShadersPresetPrev(); - afx_msg void OnPlayShadersPresets(UINT nID); - afx_msg void OnPlayAudio(UINT nID); - afx_msg void OnSubtitlesDefaultStyle(); - afx_msg void OnPlaySubtitles(UINT nID); - afx_msg void OnPlayVideoStreams(UINT nID); - afx_msg void OnPlayFiltersStreams(UINT nID); - afx_msg void OnPlayVolume(UINT nID); - afx_msg void OnPlayVolumeBoost(UINT nID); - afx_msg void OnUpdatePlayVolumeBoost(CCmdUI* pCmdUI); - afx_msg void OnCustomChannelMapping(); - afx_msg void OnUpdateCustomChannelMapping(CCmdUI* pCmdUI); - afx_msg void OnNormalizeRegainVolume(UINT nID); - afx_msg void OnUpdateNormalizeRegainVolume(CCmdUI* pCmdUI); - afx_msg void OnPlayColor(UINT nID); - afx_msg void OnAfterplayback(UINT nID); - afx_msg void OnUpdateAfterplayback(CCmdUI* pCmdUI); - afx_msg void OnPlayRepeat(UINT nID); - afx_msg void OnUpdatePlayRepeat(CCmdUI* pCmdUI); - afx_msg void OnABRepeat(UINT nID); - afx_msg void OnUpdateABRepeat(CCmdUI* pCmdUI); - afx_msg void OnPlayRepeatForever(); - afx_msg void OnUpdatePlayRepeatForever(CCmdUI* pCmdUI); - - afx_msg void OnNavigateSkip(UINT nID); - afx_msg void OnUpdateNavigateSkip(CCmdUI* pCmdUI); - afx_msg void OnNavigateSkipFile(UINT nID); - afx_msg void OnUpdateNavigateSkipFile(CCmdUI* pCmdUI); - afx_msg void OnNavigateGoto(); - afx_msg void OnUpdateNavigateGoto(CCmdUI* pCmdUI); - afx_msg void OnNavigateMenu(UINT nID); - afx_msg void OnUpdateNavigateMenu(CCmdUI* pCmdUI); - afx_msg void OnNavigateJumpTo(UINT nID); - afx_msg void OnNavigateMenuItem(UINT nID); - afx_msg void OnUpdateNavigateMenuItem(CCmdUI* pCmdUI); - afx_msg void OnTunerScan(); - afx_msg void OnUpdateTunerScan(CCmdUI* pCmdUI); - - afx_msg void OnFavoritesAdd(); - afx_msg void OnUpdateFavoritesAdd(CCmdUI* pCmdUI); - afx_msg void OnFavoritesQuickAddFavorite(); - afx_msg void OnFavoritesOrganize(); - afx_msg void OnUpdateFavoritesOrganize(CCmdUI* pCmdUI); - afx_msg void OnFavoritesFile(UINT nID); - afx_msg void OnUpdateFavoritesFile(CCmdUI* pCmdUI); - afx_msg void OnFavoritesDVD(UINT nID); - afx_msg void OnUpdateFavoritesDVD(CCmdUI* pCmdUI); - afx_msg void OnFavoritesDevice(UINT nID); - afx_msg void OnUpdateFavoritesDevice(CCmdUI* pCmdUI); - afx_msg void OnRecentFileClear(); - afx_msg void OnUpdateRecentFileClear(CCmdUI* pCmdUI); - afx_msg void OnRecentFile(UINT nID); - afx_msg void OnUpdateRecentFile(CCmdUI* pCmdUI); - - afx_msg void OnHelpHomepage(); - afx_msg void OnHelpCheckForUpdate(); - afx_msg void OnHelpToolbarImages(); - afx_msg void OnHelpDonate(); - - afx_msg void OnClose(); - - bool FilterSettingsByClassID(CLSID clsid, CWnd* parent); - void FilterSettings(CComPtr pUnk, CWnd* parent); - - LRESULT OnMPCVRSwitchFullscreen(WPARAM wParam, LPARAM lParam); - - CMPC_Lcd m_Lcd; - - CMouseWndWithArtView* m_pVideoWnd; // Current Video (main display screen or 2nd) - CWnd* m_pOSDWnd; - CPreView m_wndPreView; // SeekPreview - - - void ReleasePreviewGraph(); - HRESULT PreviewWindowHide(); - HRESULT PreviewWindowShow(REFERENCE_TIME rtCur2); - HRESULT HandleMultipleEntryRar(CStringW fn); - bool CanPreviewUse(); - - CFullscreenWnd* m_pDedicatedFSVideoWnd; - COSD m_OSD; - int m_nCurSubtitle; - long m_lSubtitleShift; - REFERENCE_TIME m_rtCurSubPos; - bool m_bScanDlgOpened; - bool m_bStopTunerScan; - bool m_bLockedZoomVideoWindow; - int m_nLockedZoomVideoWindow; - - void SetLoadState(MLS eState); - MLS GetLoadState() const; - void SetPlayState(MPC_PLAYSTATE iState); - bool CreateFullScreenWindow(bool isD3D=true); - 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, bool relative = false); - //void AutoSelectTracks(); - void SetTimersPlay(); - void KillTimerDelayedSeek(); - void KillTimersStop(); - void AdjustStreamPosPoller(bool restart); - void ResetSubtitlePosAndSize(bool repaint = false); - - // MPC API functions - void ProcessAPICommand(COPYDATASTRUCT* pCDS); - void SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...); - void SendNowPlayingToApi(bool sendtrackinfo = true); - void SendSubtitleTracksToApi(); - void SendAudioTracksToApi(); - void SendPlaylistToApi(); - afx_msg void OnFileOpendirectory(); - - void SendCurrentPositionToApi(bool fNotifySeek = false); - void ShowOSDCustomMessageApi(const MPC_OSDDATA* osdData); - void JumpOfNSeconds(int seconds); - - CString GetVidPos() const; - - CComPtr m_pTaskbarList; - HRESULT CreateThumbnailToolbar(); - HRESULT UpdateThumbarButton(); - HRESULT UpdateThumbarButton(MPC_PLAYSTATE iPlayState); - HRESULT UpdateThumbnailClip(); - BOOL Create(LPCTSTR lpszClassName, - LPCTSTR lpszWindowName, - DWORD dwStyle = WS_OVERLAPPEDWINDOW, - const RECT& rect = rectDefault, - CWnd* pParentWnd = NULL, // != NULL for popups - LPCTSTR lpszMenuName = NULL, - DWORD dwExStyle = 0, - CCreateContext* pContext = NULL); - CMPCThemeMenu* defaultMPCThemeMenu = nullptr; - - bool isSafeZone(CPoint pt); - -protected: - afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); - // GDI+ - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - void WTSRegisterSessionNotification(); - void WTSUnRegisterSessionNotification(); - - CMenu* m_pActiveContextMenu; - CMenu* m_pActiveSystemMenu; - - void UpdateSkypeHandler(); - void UpdateSeekbarChapterBag(); - void UpdateAudioSwitcher(); - - void LoadArtToViews(const CString& imagePath); - void LoadArtToViews(std::vector buffer); - void ClearArtFromViews(); - - void UpdateUILanguage(); - - bool PerformFlipRotate(); - - bool m_bAltDownClean; - bool m_bShowingFloatingMenubar; - virtual void OnShowMenuBar() override { - m_bShowingFloatingMenubar = (GetMenuBarVisibility() != AFX_MBV_KEEPVISIBLE); - }; - virtual void OnHideMenuBar() override { - m_bShowingFloatingMenubar = false; - }; - virtual void SetMenuBarVisibility(DWORD dwStyle) override { - __super::SetMenuBarVisibility(dwStyle); - if (dwStyle & AFX_MBV_KEEPVISIBLE) { - m_bShowingFloatingMenubar = false; - } - }; - - bool IsAeroSnapped(); - - CPoint m_snapStartPoint; - CRect m_snapStartRect; - - bool m_bAllowWindowZoom; - double m_dLastVideoScaleFactor; - CSize m_lastVideoSize; - - bool m_bExtOnTop; // 'true' if the "on top" flag was set by an external tool - - CString m_sydlLastProcessURL; - - bool IsImageFile(CStringW fn); - bool IsPlayableFormatExt(CStringW ext); - bool IsAudioFileExt(CStringW ext); - bool IsImageFileExt(CStringW ext); - bool IsPlaylistFile(CStringW fn); - bool IsPlaylistFileExt(CStringW ext); - bool IsAudioOrVideoFileExt(CStringW ext); - bool CanSkipToExt(CStringW ext, CStringW curExt); - bool IsAudioFilename(CString filename); - - - // Handles MF_DEFAULT and escapes '&' - static BOOL AppendMenuEx(CMenu& menu, UINT nFlags, UINT nIDNewItem, CString& text); - - void SubtitlesSave(const TCHAR* directory = nullptr, bool silent = false); - - void OnSizingFixWndToVideo(UINT nSide, LPRECT lpRect, bool bCtrl = false); - void OnSizingSnapToScreen(UINT nSide, LPRECT lpRect, bool bCtrl = false); - -public: - afx_msg UINT OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData); - afx_msg void OnSessionChange(UINT nSessionState, UINT nId); - - enum UpdateControlTarget { - UPDATE_VOLUME_STEP, - UPDATE_LOGO, - UPDATE_SKYPE, - UPDATE_SEEKBAR_CHAPTERS, - UPDATE_WINDOW_TITLE, - UPDATE_AUDIO_SWITCHER, - UPDATE_CONTROLS_VISIBILITY, - UPDATE_CHILDVIEW_CURSOR_HACK, - }; - - void UpdateControlState(UpdateControlTarget target); - - void ReloadMenus(); - - // TODO: refactor it outside of MainFrm - GUID GetTimeFormat(); - - CHdmvClipInfo::HdmvPlaylist m_MPLSPlaylist; - bool m_bIsBDPlay; - bool OpenBD(CString Path); - bool m_bHasBDMeta; - CAtlList m_BDMeta; - CHdmvClipInfo::BDMVMeta GetBDMVMeta(); - - bool GetDecoderType(CString& type) const; - - static bool IsOnYDLWhitelist(const CString url); - - bool CanSendToYoutubeDL(const CString url); - bool ProcessYoutubeDLURL(CString url, bool append, bool replace = false); - bool DownloadWithYoutubeDL(CString url, CString filename); - - /** - * @brief Get title of file - * @param fTitleBarTextTitle - * @return - */ - CString getBestTitle(bool fTitleBarTextTitle = true); - MediaTransControls m_media_trans_control; - - void MediaTransportControlSetMedia(); - void MediaTransportControlUpdateState(OAFilterState state); - - enum themableDialogTypes { - None, - windowsFileDialog, - toolbarCustomizeDialog - }; - void enableFileDialogHook(CMPCThemeUtil* helper); - void enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type); -private: - themableDialogTypes watchingDialog, foundDialog; - CMPCThemeUtil* dialogHookHelper; - -public: - afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); - afx_msg void OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt); -private: - void SetupExternalChapters(); - void ApplyPanNScanPresetString(); - void ValidatePanNScanParameters(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#include "ChildView.h" +#include "DVBChannel.h" +#include "DebugShadersDlg.h" +#include "DropTarget.h" +#include "EditListEditor.h" +#include "IBufferInfo.h" +#include "IKeyFrameInfo.h" +#include "MainFrmControls.h" +#include "MouseTouch.h" +#include "MpcApi.h" +#include "PlayerCaptureBar.h" +#include "PlayerInfoBar.h" +#include "PlayerNavigationBar.h" +#include "PlayerPlaylistBar.h" +#include "PlayerSeekBar.h" +#include "PlayerStatusBar.h" +#include "PlayerSubresyncBar.h" +#include "PlayerPreView.h" +#include "PlayerToolBar.h" +#include "SubtitleDlDlg.h" +#include "TimerWrappers.h" +#include "OSD.h" +#include "CMPCThemeMenu.h" +#include "../SubPic/MemSubPic.h" +#include +#include +#include "../DSUtil/FontInstaller.h" +#include "AppSettings.h" +#include "../filters/transform/VSFilter/IDirectVobSub.h" +#include "MediaTransControls.h" +#include "FavoriteOrganizeDlg.h" +#include "AllocatorCommon.h" + +class CDebugShadersDlg; +class CFullscreenWnd; +class SkypeMoodMsgHandler; +struct DisplayMode; +enum MpcCaptionState; +class CMediaTypesDlg; + +interface IDSMChapterBag; +interface IGraphBuilder2; +interface IMFVideoDisplayControl; +interface IMFVideoProcessor; +interface IMadVRCommand; +interface IMadVRInfo; +interface IMadVRFrameGrabber; +interface IMadVRSettings; +interface IMadVRSubclassReplacement; +interface ISubClock; +interface ISubPicAllocatorPresenter2; +interface ISubPicAllocatorPresenter; +interface ISubStream; +interface ISyncClock; +DECLARE_INTERFACE_IID(IAMLine21Decoder_2, "6E8D4A21-310C-11d0-B79A-00AA003767A7"); + +enum class MLS { + CLOSED, + LOADING, + LOADED, + CLOSING, + FAILING, +}; + +enum { + PM_NONE, + PM_FILE, + PM_DVD, + PM_ANALOG_CAPTURE, + PM_DIGITAL_CAPTURE +}; + +class OpenMediaData +{ +public: + // OpenMediaData() {} + virtual ~OpenMediaData() {} // one virtual funct is needed to enable rtti + CString title; + CAtlList subs; +}; + +class OpenFileData : public OpenMediaData +{ +public: + OpenFileData() : rtStart(0), bAddToRecent(true) {} + CAtlList fns; + REFERENCE_TIME rtStart; + ABRepeat abRepeat; + bool bAddToRecent; + CString useragent; + CString referrer; +}; + +class OpenDVDData : public OpenMediaData +{ +public: + // OpenDVDData() {} + CString path; + CComPtr pDvdState; +}; + +class OpenDeviceData : public OpenMediaData +{ +public: + OpenDeviceData() { + vinput = vchannel = ainput = -1; + } + CStringW DisplayName[2]; + int vinput, vchannel, ainput; +}; + +class TunerScanData +{ +public: + ULONG FrequencyStart; + ULONG FrequencyStop; + ULONG Bandwidth; + ULONG SymbolRate; + LONG Offset; + HWND Hwnd; +}; + +struct SeekToCommand { + REFERENCE_TIME rtPos; + ULONGLONG seekTime; + bool bShowOSD; +}; + +struct SubtitleInput { + CComQIPtr pSubStream; + CComPtr pSourceFilter; + + SubtitleInput() {}; + SubtitleInput(CComQIPtr pSubStream) : pSubStream(pSubStream) {}; + SubtitleInput(CComQIPtr pSubStream, CComPtr pSourceFilter) + : pSubStream(pSubStream), pSourceFilter(pSourceFilter) {}; +}; + +struct FileFavorite { + CString Name; + REFERENCE_TIME Start; + REFERENCE_TIME MarkA; + REFERENCE_TIME MarkB; + BOOL RelativeDrive; + + FileFavorite() { + Start = MarkA = MarkB = 0; + RelativeDrive = FALSE; + } + + static bool TryParse(const CString& fav, FileFavorite& ff); + static bool TryParse(const CString& fav, FileFavorite& ff, CAtlList& parts); + + CString ToString() const; +}; + +///////////////////////////////////////////////////////////////////////////// +// CMainFrame + +class CMainFrame : public CFrameWnd, public CDropClient +{ +public: + + DpiHelper m_dpi; + + enum class TimerHiderSubscriber { + TOOLBARS_HIDER, + CURSOR_HIDER, + CURSOR_HIDER_D3DFS, + }; + OnDemandTimer m_timerHider; + + enum class TimerOneTimeSubscriber { + TOOLBARS_DELAY_NOTLOADED, + CHILDVIEW_CURSOR_HACK, + DELAY_IDLE, + ACTIVE_SHADER_FILES_CHANGE_COOLDOWN, + DELAY_PLAYPAUSE_AFTER_AUTOCHANGE_MODE, + DVBINFO_UPDATE, + STATUS_ERASE, + PLACE_FULLSCREEN_UNDER_ACTIVE_WINDOW, + AUTOFIT_TIMEOUT + }; + OneTimeTimerPool m_timerOneTime; + +private: + EventClient m_eventc; + void EventCallback(MpcEvent ev); + + CMainFrameMouseHook m_mouseHook; + + enum { + TIMER_STREAMPOSPOLLER = 1, + TIMER_STREAMPOSPOLLER2, + TIMER_STATS, + TIMER_UNLOAD_UNUSED_EXTERNAL_OBJECTS, + TIMER_HIDER, + TIMER_WINDOW_FULLSCREEN, + TIMER_DELAYEDSEEK, + TIMER_ONETIME_START, + TIMER_ONETIME_END = TIMER_ONETIME_START + 127, + }; + enum { + SEEK_DIRECTION_NONE, + SEEK_DIRECTION_BACKWARD, + SEEK_DIRECTION_FORWARD + }; + enum { + ZOOM_DEFAULT_LEVEL = 0, + ZOOM_AUTOFIT = -1, + ZOOM_AUTOFIT_LARGER = -2 + }; + + + typedef std::map PlaybackRateMap; + static PlaybackRateMap filePlaybackRates; + static PlaybackRateMap dvdPlaybackRates; + + friend class CPPageFileInfoSheet; + friend class CPPageLogo; + friend class CMouse; + friend class CPlayerSeekBar; // for accessing m_controls.ControlChecked() + friend class CChildView; // for accessing m_controls.DelayShowNotLoaded() + friend class CFullscreenWnd; // for accessing m_controls.DelayShowNotLoaded() + friend class CMouseWndWithArtView; // for accessing m_controls.DelayShowNotLoaded() + friend class SubtitlesProvider; + + // TODO: wrap these graph objects into a class to make it look cleaner + + CComPtr m_pGB; + CComQIPtr m_pMC; + CComQIPtr m_pME; + CComQIPtr m_pVW; + CComQIPtr m_pBV; + CComQIPtr m_pBA; + CComQIPtr m_pMS; + CComQIPtr m_pFS; + CComQIPtr m_pFSF; + CComQIPtr m_pKFI; + CComQIPtr m_pQP; + CComQIPtr m_pBI; + CComQIPtr m_pAMOP; + CComQIPtr m_pAMMC[2]; + CComQIPtr m_pAMNS; + CComQIPtr m_pAudioSwitcherSS; + CComQIPtr m_pSplitterSS; + CComQIPtr m_pSplitterDubSS; + CComQIPtr m_pOtherSS[2]; + // SmarkSeek + CComPtr m_pGB_preview; + CComQIPtr m_pMC_preview; + //CComQIPtr m_pME_preview; + CComQIPtr m_pMS_preview; + CComQIPtr m_pVW_preview; + CComQIPtr m_pBV_preview; + //CComQIPtr m_pFS_preview; + CComQIPtr m_pDVDC_preview; + CComQIPtr m_pDVDI_preview; // VtX: usually not necessary but may sometimes be necessary. + CComPtr m_pMFVDC_preview; + CComPtr m_pVMR9C_preview; + CComPtr m_pMFVP_preview; + CComPtr m_pCAP2_preview; + int defaultVideoAngle; + // + CComPtr m_pVMRMC; + CComPtr m_pMFVDC; + CComPtr m_pMFVP; + CComPtr m_pVMB; + CComPtr m_pMFVMB; + CComPtr m_pVMRWC; + + CComPtr m_pCAP; + CComPtr m_pCAP2; + CComPtr m_pCAP3; + + CComPtr m_pMVRS; + CComPtr m_pMVRSR; + CComPtr m_pMVRC; + CComPtr m_pMVRI; + CComPtr m_pMVRFG; + CComPtr m_pMVTO; + + CComPtr m_pD3DFSC; + + CComQIPtr m_pDVDC; + CComQIPtr m_pDVDI; + CComPtr m_pLN21; + + CComPtr m_pCGB; + CStringW m_VidDispName, m_AudDispName; + CComPtr m_pVidCap, m_pAudCap; + CComPtr m_pAMVCCap, m_pAMVCPrev; + CComPtr m_pAMVSCCap, m_pAMVSCPrev, m_pAMASC; + CComPtr m_pAMXBar; + CComPtr m_pAMTuner; + CComPtr m_pAMDF; + + CComPtr m_pProv; + + CComQIPtr m_pDVS; + CComQIPtr m_pDVS2; + + bool m_bUsingDXVA; + LPCTSTR m_HWAccelType; + void UpdateDXVAStatus(); + + void SetVolumeBoost(UINT nAudioBoost); + void SetBalance(int balance); + + // temp fonts loader + CFontInstaller m_FontInstaller; + + // subtitles + + CCritSec m_csSubLock; + CCritSec m_csSubtitleManagementLock; + + CList m_pSubStreams; + std::list m_ExternalSubstreams; + POSITION m_posFirstExtSub; + SubtitleInput m_pCurrentSubInput; + + // StatusBar message text parts + CString currentAudioLang; + CString currentSubLang; + CString m_statusbarVideoFormat; + CString m_statusbarAudioFormat; + CString m_statusbarVideoSize; + + SubtitleInput* GetSubtitleInput(int& i, bool bIsOffset = false); + int UpdateSelectedAudioStreamInfo(int index, AM_MEDIA_TYPE* pmt, LCID lcid); + bool IsValidSubtitleStream(int i); + int GetSelectedSubtitleTrackIndex(); + + friend class CTextPassThruFilter; + + // windowing + + bool m_bDelaySetOutputRect; + + CRect m_lastWindowRect; + + void SetDefaultWindowRect(int iMonitor = 0); + void SetDefaultFullscreenState(); + void RestoreDefaultWindowRect(); + CRect GetInvisibleBorderSize() const; + CSize GetVideoOrArtSize(MINMAXINFO& mmi); + CSize GetZoomWindowSize(double dScale, bool ignore_video_size = false); + bool GetWorkAreaRect(CRect& work); + CRect GetZoomWindowRect(const CSize& size, bool ignoreSavedPosition = false); + void ZoomVideoWindow(double dScale = ZOOM_DEFAULT_LEVEL, bool ignore_video_size = false); + double GetZoomAutoFitScale(); + + bool alwaysOnTopZOrderInitialized = false; + void SetAlwaysOnTop(int iOnTop); + bool WindowExpectedOnTop(); + + // dynamic menus + + void CreateDynamicMenus(); + void DestroyDynamicMenus(); + void SetupOpenCDSubMenu(); + void SetupFiltersSubMenu(); + void SetupAudioSubMenu(); + void SetupSubtitlesSubMenu(); + void SetupVideoStreamsSubMenu(); + void SetupJumpToSubMenus(CMenu* parentMenu = nullptr, int iInsertPos = -1); + void SetupFavoritesSubMenu(); + bool SetupShadersSubMenu(); + void SetupRecentFilesSubMenu(); + + DWORD SetupNavStreamSelectSubMenu(CMenu& subMenu, UINT id, DWORD dwSelGroup); + void OnNavStreamSelectSubMenu(UINT id, DWORD dwSelGroup); + void OnStreamSelect(bool forward, DWORD dwSelGroup); + static CString GetStreamOSDString(CString name, LCID lcid, DWORD dwSelGroup); + + void CreateOSDBar(); + bool OSDBarSetPos(); + void DestroyOSDBar(); + + CMPCThemeMenu m_mainPopupMenu, m_popupMenu; + CMPCThemeMenu m_openCDsMenu; + CMPCThemeMenu m_filtersMenu, m_subtitlesMenu, m_audiosMenu, m_videoStreamsMenu; + CMPCThemeMenu m_chaptersMenu, m_titlesMenu, m_playlistMenu, m_BDPlaylistMenu, m_channelsMenu; + CMPCThemeMenu m_favoritesMenu; + CMPCThemeMenu m_shadersMenu; + CMPCThemeMenu m_recentFilesMenu; + int recentFilesMenuFromMRUSequence; + + UINT m_nJumpToSubMenusCount; + + CInterfaceArray m_pparray; + CInterfaceArray m_ssarray; + + // chapters (file mode) + CComPtr m_pCB; + void SetupChapters(); + void SetupCueChapters(CString fn); + + // chapters (DVD mode) + void SetupDVDChapters(); + + bool SeekToFileChapter(int iChapter, bool bRelative = false); + bool SeekToDVDChapter(int iChapter, bool bRelative = false); + + void AddTextPassThruFilter(); + + int m_nLoops; + ABRepeat abRepeat, reloadABRepeat; + UINT m_nLastSkipDirection; + + int m_iStreamPosPollerInterval; + + bool m_fCustomGraph; + bool m_fShockwaveGraph; + + CComPtr m_pSubClock; + + bool m_fFrameSteppingActive; + int m_nStepForwardCount; + REFERENCE_TIME m_rtStepForwardStart; + int m_nVolumeBeforeFrameStepping; + + bool m_fEndOfStream; + ULONGLONG m_dwLastPause; + ULONGLONG m_dwReloadPos; + int m_iReloadAudioIdx; + int m_iReloadSubIdx; + + bool m_bRememberFilePos; + + ULONGLONG m_dwLastRun; + + bool m_bBuffering; + + bool m_fLiveWM; + + bool delayingFullScreen; + + bool m_bIsMPCVRExclusiveMode = false; + + void SendStatusMessage(CString msg, int nTimeOut); + CString m_tempstatus_msg, m_closingmsg; + + REFERENCE_TIME m_rtDurationOverride; + + void CleanGraph(); + + void ShowOptions(int idPage = 0); + + HRESULT GetDisplayedImage(std::vector& dib, CString& errmsg); + HRESULT GetCurrentFrame(std::vector& dib, CString& errmsg); + HRESULT GetOriginalFrame(std::vector& dib, CString& errmsg); + HRESULT RenderCurrentSubtitles(BYTE* pData); + bool GetDIB(BYTE** ppData, long& size, bool fSilent = false); + void SaveDIB(LPCTSTR fn, BYTE* pData, long size); + CString MakeSnapshotFileName(BOOL thumbnails); + BOOL IsRendererCompatibleWithSaveImage(); + void SaveImage(LPCTSTR fn, bool displayed, bool includeSubtitles); + void SaveThumbnails(LPCTSTR fn); + + // + + friend class CWebClientSocket; + friend class CWebServer; + CAutoPtr m_pWebServer; + int m_iPlaybackMode; + ULONG m_lCurrentChapter; + ULONG m_lChapterStartTime; + + CString m_currentCoverAuthor; + CString m_currentCoverPath; + bool currentCoverIsFileArt = false; + + CAutoPtr m_pSkypeMoodMsgHandler; + void SendNowPlayingToSkype(); + + MLS m_eMediaLoadState; + OAFilterState m_CachedFilterState; + + bool m_bSettingUpMenus; + bool m_bOpenMediaActive; + int m_OpenMediaFailedCount; + + REFTIME GetAvgTimePerFrame() const; + void OnVideoSizeChanged(const bool bWasAudioOnly = false); + + CDropTarget m_dropTarget; + void OnDropFiles(CAtlList& slFiles, DROPEFFECT dropEffect) override; + DROPEFFECT OnDropAccept(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) override; + +public: + void StartWebServer(int nPort); + void StopWebServer(); + + int GetPlaybackMode() const { + return m_iPlaybackMode; + } + bool IsPlaybackCaptureMode() const { + return GetPlaybackMode() == PM_ANALOG_CAPTURE || GetPlaybackMode() == PM_DIGITAL_CAPTURE; + } + void SetPlaybackMode(int iNewStatus); + bool IsMuted() { + return m_wndToolBar.GetVolume() == -10000; + } + int GetVolume() { + return m_wndToolBar.m_volctrl.GetPos(); + } + double GetPlayingRate() const { + return m_dSpeedRate; + } + +public: + CMainFrame(); + DECLARE_DYNAMIC(CMainFrame) + + // Attributes +public: + bool m_fFullScreen; + bool m_bNeedZoomAfterFullscreenExit; + bool m_fStartInD3DFullscreen; + bool m_fStartInFullscreenSeparate; + bool m_bFullScreenWindowIsD3D; + bool m_bFullScreenWindowIsOnSeparateDisplay; + + CComPtr m_pRefClock; // Adjustable reference clock. GothSync + CComPtr m_pSyncClock; + + bool IsFrameLessWindow() const; + bool IsCaptionHidden() const; + bool IsMenuHidden() const; + bool IsPlaylistEmpty() const; + bool IsInteractiveVideo() const; + bool IsFullScreenMode() const; + bool IsFullScreenMainFrame() const; + bool IsFullScreenMainFrameExclusiveMPCVR() const; + bool IsFullScreenSeparate() const; + bool HasDedicatedFSVideoWindow() const; + bool IsD3DFullScreenMode() const; + bool IsSubresyncBarVisible() const; + + CControlBar* m_pLastBar; + +protected: + bool m_bUseSeekPreview; + bool m_bFirstPlay; + bool m_bOpeningInAutochangedMonitorMode; + bool m_bPausedForAutochangeMonitorMode; + bool restoringWindowRect; + + bool m_fAudioOnly; + bool m_fValidDVDOpen; + CString m_LastOpenBDPath; + CAutoPtr m_lastOMD; + + DVD_DOMAIN m_iDVDDomain; + DWORD m_iDVDTitle; + bool m_bDVDStillOn; + int m_loadedAudioTrackIndex = -1; + int m_loadedSubtitleTrackIndex = -1; + int m_audioTrackCount = 0; + + double m_dSpeedRate; + double m_ZoomX, m_ZoomY, m_PosX, m_PosY; + int m_AngleX, m_AngleY, m_AngleZ; + int m_iDefRotation; + + void ForceCloseProcess(); + + // Operations + bool OpenMediaPrivate(CAutoPtr pOMD); + void CloseMediaPrivate(); + void DoTunerScan(TunerScanData* pTSD); + + CWnd* GetModalParent(); + + CCritSec lockModalDialog; + CMediaTypesDlg* mediaTypesErrorDlg; + void ShowMediaTypesDialog(); + + void OpenCreateGraphObject(OpenMediaData* pOMD); + void OpenFile(OpenFileData* pOFD); + void OpenDVD(OpenDVDData* pODD); + void OpenCapture(OpenDeviceData* pODD); + HRESULT OpenBDAGraph(); + void OpenCustomizeGraph(); + void OpenSetupVideo(); + void OpenSetupAudio(); + void OpenSetupInfoBar(bool bClear = true); + void UpdateChapterInInfoBar(); + void OpenSetupStatsBar(); + void CheckSelectedAudioStream(); + void OpenSetupStatusBar(); + void OpenSetupCaptureBar(); + void OpenSetupWindowTitle(bool reset = false); + +public: + static bool GetCurDispMode(const CString& displayName, DisplayMode& dm); + static bool GetDispMode(CString displayName, int i, DisplayMode& dm); + +protected: + void SetDispMode(CString displayName, const DisplayMode& dm, int msAudioDelay); + void AutoChangeMonitorMode(); + + void GraphEventComplete(); + + friend class CGraphThread; + CGraphThread* m_pGraphThread; + bool m_bOpenedThroughThread; + ATL::CEvent m_evOpenPrivateFinished; + ATL::CEvent m_evClosePrivateFinished; + + void LoadKeyFrames(); + std::vector m_kfs; + + bool m_fOpeningAborted; + bool m_bWasSnapped; + +protected: + friend class CSubtitleDlDlg; + CSubtitleDlDlg m_wndSubtitlesDownloadDialog; + CFavoriteOrganizeDlg m_wndFavoriteOrganizeDialog; + friend class CPPageSubMisc; + + friend class SubtitlesProviders; + std::unique_ptr m_pSubtitlesProviders; + friend struct SubtitlesInfo; + friend class SubtitlesTask; + friend class SubtitlesThread; + +public: + void OpenCurPlaylistItem(REFERENCE_TIME rtStart = 0, bool reopen = false, ABRepeat abRepeat = ABRepeat()); + void OpenMedia(CAutoPtr pOMD); + void PlayFavoriteFile(const CString& fav); + void PlayFavoriteDVD(CString fav); + FileFavorite ParseFavoriteFile(const CString& fav, CAtlList& args, REFERENCE_TIME* prtStart = nullptr); + bool ResetDevice(); + bool DisplayChange(); + void CloseMediaBeforeOpen(); + void CloseMedia(bool bNextIsQueued = false, bool bPendingFileDelete = false); + void StartTunerScan(CAutoPtr pTSD); + void StopTunerScan(); + HRESULT SetChannel(int nChannel); + + void AddCurDevToPlaylist(); + + bool m_bTrayIcon; + void ShowTrayIcon(bool bShow); + void SetTrayTip(const CString& str); + + CSize GetVideoSize() const; + CSize GetVideoSizeWithRotation(bool forPreview = false) const; + void HidePlaylistFullScreen(bool force = false); + void ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo); + void ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo); + void MoveVideoWindow(bool fShowStats = false, bool bSetStoppedVideoRect = false); + void SetPreviewVideoPosition(); + + void RepaintVideo(const bool bForceRepaint = false); + void HideVideoWindow(bool fHide); + + OAFilterState GetMediaStateDirect() const; + OAFilterState GetMediaState() const; + OAFilterState CMainFrame::UpdateCachedMediaState(); + bool MediaControlRun(bool waitforcompletion = false); + bool MediaControlPause(bool waitforcompletion = false); + bool MediaControlStop(bool waitforcompletion = false); + bool MediaControlStopPreview(); + + REFERENCE_TIME GetPos() const; + REFERENCE_TIME GetDur() const; + bool GetKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMin, REFERENCE_TIME rtMax, bool nearest, REFERENCE_TIME& keyframetime) const; + REFERENCE_TIME GetClosestKeyFrame(REFERENCE_TIME rtTarget, REFERENCE_TIME rtMaxForwardDiff, REFERENCE_TIME rtMaxBackwardDiff) const; + REFERENCE_TIME GetClosestKeyFramePreview(REFERENCE_TIME rtTarget) const; + void SeekTo(REFERENCE_TIME rt, bool bShowOSD = true); + void DoSeekTo(REFERENCE_TIME rt, bool bShowOSD = true); + SeekToCommand queuedSeek; + ULONGLONG lastSeekStart; + ULONGLONG lastSeekFinish; + void SetPlayingRate(double rate); + + int SetupAudioStreams(); + int SetupSubtitleStreams(); + + bool LoadSubtitle(CString fn, SubtitleInput* pSubInput = nullptr, bool bAutoLoad = false); + bool LoadSubtitle(CYoutubeDLInstance::YDLSubInfo& sub); + bool SetSubtitle(int i, bool bIsOffset = false, bool bDisplayMessage = false); + void SetSubtitle(const SubtitleInput& subInput, bool skip_lcid = false); + void UpdateSubtitleColorInfo(); + void ToggleSubtitleOnOff(bool bDisplayMessage = false); + void ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew); + void InvalidateSubtitle(DWORD_PTR nSubtitleId = DWORD_PTR_MAX, REFERENCE_TIME rtInvalidate = -1); + void ReloadSubtitle(); + void UpdateSubtitleRenderingParameters(); + HRESULT InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinto); + + void SetAudioTrackIdx(int index); + void SetSubtitleTrackIdx(int index); + int GetCurrentAudioTrackIdx(CString *pstrName = nullptr); + int GetCurrentSubtitleTrackIdx(CString *pstrName = nullptr); + + void AddFavorite(bool fDisplayMessage = false, bool fShowDialog = true); + + CString GetFileName(); + CString GetCaptureTitle(); + + // shaders + void SetShaders(bool bSetPreResize = true, bool bSetPostResize = true); + + bool m_bToggleShader; + bool m_bToggleShaderScreenSpace; + std::list m_ShaderCache; + ShaderC* GetShader(CString path, bool bD3D11); + bool SaveShaderFile(ShaderC* shader); + bool DeleteShaderFile(LPCWSTR label); + void TidyShaderCache(); + + // 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(); + + void DoAfterPlaybackEvent(); + bool SearchInDir(bool bDirForward, bool bLoop = false); + bool WildcardFileSearch(CString searchstr, std::set& results, bool recurse_dirs); + CString lastOpenFile; + bool CanSkipFromClosedFile(); + + 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); + void EnableDocking(DWORD dwDockStyle); + + // DVB capture + void UpdateCurrentChannelInfo(bool bShowOSD = true, bool bShowInfoBar = false); + LRESULT OnCurrentChannelInfoUpdated(WPARAM wParam, LPARAM lParam); + + bool CheckABRepeat(REFERENCE_TIME& aPos, REFERENCE_TIME& bPos); + void PerformABRepeat(); + void DisableABRepeat(); + + struct DVBState { + struct EITData { + HRESULT hr = E_FAIL; + EventDescriptor NowNext; + bool bShowOSD = true; + bool bShowInfoBar = false; + }; + + CString sChannelName; // Current channel name + CBDAChannel* pChannel = nullptr; // Pointer to current channel object + EventDescriptor NowNext; // Current channel EIT + bool bActive = false; // True when channel is active + bool bSetChannelActive = false; // True when channel change is in progress + bool bInfoActive = false; // True when EIT data update is in progress + bool bAbortInfo = true; // True when aborting current EIT update + std::future infoData; + + void Reset() { + sChannelName.Empty(); + pChannel = nullptr; + NowNext = EventDescriptor(); + bActive = false; + bSetChannelActive = false; + bInfoActive = false; + bAbortInfo = true; + } + + void Join() { + if (infoData.valid()) { + bAbortInfo = true; + infoData.wait(); + } + } + + ~DVBState() { + bAbortInfo = true; + } + }; + + std::unique_ptr m_pDVBState = nullptr; + + // Implementation +public: + virtual ~CMainFrame(); +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +protected: // control bar embedded members + friend class CMainFrameControls; + friend class CPPageToolBar; + CMainFrameControls m_controls; + friend class CPlayerBar; // it notifies m_controls of panel re-dock + + CChildView m_wndView; + + CPlayerSeekBar m_wndSeekBar; + CPlayerToolBar m_wndToolBar; + CPlayerInfoBar m_wndInfoBar; + CPlayerInfoBar m_wndStatsBar; + CPlayerStatusBar m_wndStatusBar; + + CPlayerSubresyncBar m_wndSubresyncBar; + CPlayerPlaylistBar m_wndPlaylistBar; + CPlayerCaptureBar m_wndCaptureBar; + CPlayerNavigationBar m_wndNavigationBar; + CEditListEditor m_wndEditListEditor; + + std::unique_ptr m_pDebugShaders; + + LPCTSTR GetRecentFile() const; + + friend class CPPagePlayback; // TODO + friend class CPPageAudioSwitcher; // TODO + friend class CMPlayerCApp; // TODO + + // Generated message map functions + + DECLARE_MESSAGE_MAP() + +public: + afx_msg int OnNcCreate(LPCREATESTRUCT lpCreateStruct); + 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 OnEnterSizeMove(); + afx_msg void OnMoving(UINT fwSide, LPRECT pRect); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnSizing(UINT nSide, LPRECT lpRect); + afx_msg void OnExitSizeMove(); + afx_msg void OnDisplayChange(); + afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos); + + LRESULT OnDpiChanged(WPARAM wParam, LPARAM lParam); + + 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 void SaveAppSettings(); + + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + + void RestoreFocus(); + + afx_msg void OnInitMenu(CMenu* pMenu); + afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); + afx_msg void OnUnInitMenuPopup(CMenu* pPopupMenu, UINT nFlags); + afx_msg void OnEnterMenuLoop(BOOL bIsTrackPopupMenu); + + afx_msg BOOL OnQueryEndSession(); + afx_msg void OnEndSession(BOOL bEnding); + + BOOL OnMenu(CMenu* pMenu); + afx_msg void OnMenuPlayerShort(); + afx_msg void OnMenuPlayerLong(); + afx_msg void OnMenuFilters(); + + afx_msg void OnUpdatePlayerStatus(CCmdUI* pCmdUI); + + afx_msg LRESULT OnFilePostOpenmedia(WPARAM wParam, LPARAM lparam); + afx_msg LRESULT OnOpenMediaFailed(WPARAM wParam, LPARAM lParam); + void OnFilePostClosemedia(bool bNextIsQueued = false); + + afx_msg void OnBossKey(); + + afx_msg void OnStreamAudio(UINT nID); + afx_msg void OnStreamSub(UINT nID); + afx_msg void OnStreamSubOnOff(); + afx_msg void OnAudioShiftOnOff(); + afx_msg void OnDvdAngle(UINT nID); + afx_msg void OnDvdAudio(UINT nID); + afx_msg void OnDvdSub(UINT nID); + afx_msg void OnDvdSubOnOff(); + + afx_msg LRESULT OnLoadSubtitles(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnGetSubtitles(WPARAM, LPARAM lParam); + + // menu item handlers + + INT_PTR DoFileDialogWithLastFolder(CFileDialog& fd, CStringW& lastPath); + void OpenDVDOrBD(CStringW path); + + 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 OnFileOpenOpticalDisk(UINT nID); + afx_msg void OnFileReopen(); + afx_msg void OnFileRecycle(); + afx_msg void OnFileSaveAs(); + afx_msg void OnUpdateFileSaveAs(CCmdUI* pCmdUI); + afx_msg void OnFileSaveImage(); + afx_msg void OnFileSaveImageAuto(); + afx_msg void OnUpdateFileSaveImage(CCmdUI* pCmdUI); + afx_msg void OnCmdLineSaveThumbnails(); + afx_msg void OnFileSaveThumbnails(); + afx_msg void OnUpdateFileSaveThumbnails(CCmdUI* pCmdUI); + afx_msg void OnFileSubtitlesLoad(); + afx_msg void OnUpdateFileSubtitlesLoad(CCmdUI* pCmdUI); + afx_msg void OnFileSubtitlesSave() { SubtitlesSave(); } + afx_msg void OnUpdateFileSubtitlesSave(CCmdUI* pCmdUI); + //afx_msg void OnFileSubtitlesUpload(); + //afx_msg void OnUpdateFileSubtitlesUpload(CCmdUI* pCmdUI); + afx_msg void OnFileSubtitlesDownload(); + afx_msg void OnUpdateFileSubtitlesDownload(CCmdUI* pCmdUI); + afx_msg void OnFileProperties(); + afx_msg void OnUpdateFileProperties(CCmdUI* pCmdUI); + afx_msg void OnFileOpenLocation(); + afx_msg void OnFileCloseAndRestore(); + afx_msg void OnFileCloseMedia(); // no menu item + afx_msg void OnUpdateFileClose(CCmdUI* pCmdUI); + + void SetCaptionState(MpcCaptionState eState); + afx_msg void OnViewCaptionmenu(); + + afx_msg void OnViewNavigation(); + afx_msg void OnUpdateViewCaptionmenu(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewNavigation(CCmdUI* pCmdUI); + afx_msg void OnViewControlBar(UINT nID); + afx_msg void OnUpdateViewControlBar(CCmdUI* pCmdUI); + afx_msg void OnViewSubresync(); + afx_msg void OnUpdateViewSubresync(CCmdUI* pCmdUI); + afx_msg void OnViewPlaylist(); + afx_msg void OnPlaylistToggleShuffle(); + afx_msg void OnUpdateViewPlaylist(CCmdUI* pCmdUI); + afx_msg void OnViewEditListEditor(); + afx_msg void OnEDLIn(); + afx_msg void OnUpdateEDLIn(CCmdUI* pCmdUI); + afx_msg void OnEDLOut(); + afx_msg void OnUpdateEDLOut(CCmdUI* pCmdUI); + afx_msg void OnEDLNewClip(); + afx_msg void OnUpdateEDLNewClip(CCmdUI* pCmdUI); + afx_msg void OnEDLSave(); + afx_msg void OnUpdateEDLSave(CCmdUI* pCmdUI); + afx_msg void OnViewCapture(); + afx_msg void OnUpdateViewCapture(CCmdUI* pCmdUI); + afx_msg void OnViewDebugShaders(); + afx_msg void OnUpdateViewDebugShaders(CCmdUI* pCmdUI); + afx_msg void OnViewMinimal(); + afx_msg void OnUpdateViewMinimal(CCmdUI* pCmdUI); + afx_msg void OnViewCompact(); + afx_msg void OnUpdateViewCompact(CCmdUI* pCmdUI); + afx_msg void OnViewNormal(); + afx_msg void OnUpdateViewNormal(CCmdUI* pCmdUI); + afx_msg void OnViewFullscreen(); + afx_msg void OnViewFullscreenSecondary(); + afx_msg void OnUpdateViewFullscreen(CCmdUI* pCmdUI); + afx_msg void OnViewZoom(UINT nID); + afx_msg void OnUpdateViewZoom(CCmdUI* pCmdUI); + afx_msg void OnViewZoomAutoFit(); + afx_msg void OnViewZoomAutoFitLarger(); + afx_msg void OnViewModifySize(UINT nID); + afx_msg void OnViewDefaultVideoFrame(UINT nID); + afx_msg void OnUpdateViewDefaultVideoFrame(CCmdUI* pCmdUI); + afx_msg void OnViewSwitchVideoFrame(); + afx_msg void OnUpdateViewSwitchVideoFrame(CCmdUI* pCmdUI); + afx_msg void OnViewCompMonDeskARDiff(); + afx_msg void OnUpdateViewCompMonDeskARDiff(CCmdUI* pCmdUI); + afx_msg void OnViewPanNScan(UINT nID); + afx_msg void OnUpdateViewPanNScan(CCmdUI* pCmdUI); + afx_msg void OnViewPanNScanPresets(UINT nID); + afx_msg void OnUpdateViewPanNScanPresets(CCmdUI* pCmdUI); + afx_msg void OnViewRotate(UINT nID); + afx_msg void OnUpdateViewRotate(CCmdUI* pCmdUI); + afx_msg void OnViewAspectRatio(UINT nID); + afx_msg void OnUpdateViewAspectRatio(CCmdUI* pCmdUI); + afx_msg void OnViewAspectRatioNext(); + afx_msg void OnViewOntop(UINT nID); + afx_msg void OnUpdateViewOntop(CCmdUI* pCmdUI); + afx_msg void OnViewOptions(); + afx_msg void OnUpdateViewTearingTest(CCmdUI* pCmdUI); + afx_msg void OnViewTearingTest(); + afx_msg void OnUpdateViewDisplayRendererStats(CCmdUI* pCmdUI); + afx_msg void OnViewResetRendererStats(); + afx_msg void OnViewDisplayRendererStats(); + afx_msg void OnUpdateViewVSync(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewVSyncOffset(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewVSyncAccurate(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewFlushGPU(CCmdUI* pCmdUI); + + afx_msg void OnUpdateViewSynchronizeVideo(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewSynchronizeDisplay(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewSynchronizeNearest(CCmdUI* pCmdUI); + + afx_msg void OnUpdateViewD3DFullscreen(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewDisableDesktopComposition(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewAlternativeVSync(CCmdUI* pCmdUI); + + afx_msg void OnUpdateViewColorManagementEnable(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewColorManagementInput(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewColorManagementAmbientLight(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewColorManagementIntent(CCmdUI* pCmdUI); + + afx_msg void OnUpdateViewEVROutputRange(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewFullscreenGUISupport(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewHighColorResolution(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewForceInputHighColorResolution(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewFullFloatingPointProcessing(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewHalfFloatingPointProcessing(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewEnableFrameTimeCorrection(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewVSyncOffsetIncrease(CCmdUI* pCmdUI); + afx_msg void OnUpdateViewVSyncOffsetDecrease(CCmdUI* pCmdUI); + afx_msg void OnViewVSync(); + afx_msg void OnViewVSyncAccurate(); + + afx_msg void OnViewSynchronizeVideo(); + afx_msg void OnViewSynchronizeDisplay(); + afx_msg void OnViewSynchronizeNearest(); + + afx_msg void OnViewColorManagementEnable(); + afx_msg void OnViewColorManagementInputAuto(); + afx_msg void OnViewColorManagementInputHDTV(); + afx_msg void OnViewColorManagementInputSDTV_NTSC(); + afx_msg void OnViewColorManagementInputSDTV_PAL(); + afx_msg void OnViewColorManagementAmbientLightBright(); + afx_msg void OnViewColorManagementAmbientLightDim(); + afx_msg void OnViewColorManagementAmbientLightDark(); + afx_msg void OnViewColorManagementIntentPerceptual(); + afx_msg void OnViewColorManagementIntentRelativeColorimetric(); + afx_msg void OnViewColorManagementIntentSaturation(); + afx_msg void OnViewColorManagementIntentAbsoluteColorimetric(); + + afx_msg void OnViewEVROutputRange_0_255(); + afx_msg void OnViewEVROutputRange_16_235(); + + afx_msg void OnViewFlushGPUBeforeVSync(); + afx_msg void OnViewFlushGPUAfterVSync(); + afx_msg void OnViewFlushGPUWait(); + + afx_msg void OnViewD3DFullScreen(); + afx_msg void OnViewDisableDesktopComposition(); + afx_msg void OnViewAlternativeVSync(); + afx_msg void OnViewResetDefault(); + afx_msg void OnViewResetOptimal(); + + afx_msg void OnViewFullscreenGUISupport(); + afx_msg void OnViewHighColorResolution(); + afx_msg void OnViewForceInputHighColorResolution(); + afx_msg void OnViewFullFloatingPointProcessing(); + afx_msg void OnViewHalfFloatingPointProcessing(); + afx_msg void OnViewEnableFrameTimeCorrection(); + afx_msg void OnViewVSyncOffsetIncrease(); + afx_msg void OnViewVSyncOffsetDecrease(); + afx_msg void OnUpdateShaderToggle1(CCmdUI* pCmdUI); + afx_msg void OnUpdateShaderToggle2(CCmdUI* pCmdUI); + afx_msg void OnShaderToggle1(); + afx_msg void OnShaderToggle2(); + afx_msg void OnUpdateViewOSDDisplayTime(CCmdUI* pCmdUI); + afx_msg void OnViewOSDDisplayTime(); + afx_msg void OnUpdateViewOSDShowFileName(CCmdUI* pCmdUI); + afx_msg void OnViewOSDShowFileName(); + afx_msg void OnD3DFullscreenToggle(); + afx_msg void OnGotoSubtitle(UINT nID); + afx_msg void OnSubresyncShiftSub(UINT nID); + afx_msg void OnSubtitleDelay(UINT nID); + afx_msg void OnSubtitlePos(UINT nID); + afx_msg void OnSubtitleFontSize(UINT nID); + + afx_msg void OnPlayPlay(); + afx_msg void OnPlayPause(); + afx_msg void OnPlayPlaypause(); + afx_msg void OnApiPlay(); + afx_msg void OnApiPause(); + afx_msg void OnPlayStop(); + void OnPlayStop(bool is_closing); + afx_msg void OnUpdatePlayPauseStop(CCmdUI* pCmdUI); + afx_msg void OnPlayFramestep(UINT nID); + afx_msg void OnUpdatePlayFramestep(CCmdUI* pCmdUI); + afx_msg void OnPlaySeek(UINT nID); + afx_msg void OnPlaySeekSet(); + afx_msg void OnPlaySeekKey(UINT nID); // no menu item + afx_msg void OnUpdatePlaySeek(CCmdUI* pCmdUI); + afx_msg void OnPlayChangeRate(UINT nID); + afx_msg void OnUpdatePlayChangeRate(CCmdUI* pCmdUI); + afx_msg void OnPlayResetRate(); + afx_msg void OnUpdatePlayResetRate(CCmdUI* pCmdUI); + afx_msg void OnPlayChangeAudDelay(UINT nID); + afx_msg void OnUpdatePlayChangeAudDelay(CCmdUI* pCmdUI); + afx_msg void OnPlayFiltersCopyToClipboard(); + afx_msg void OnPlayFilters(UINT nID); + afx_msg void OnUpdatePlayFilters(CCmdUI* pCmdUI); + afx_msg void OnPlayShadersSelect(); + afx_msg void OnPlayShadersPresetNext(); + afx_msg void OnPlayShadersPresetPrev(); + afx_msg void OnPlayShadersPresets(UINT nID); + afx_msg void OnPlayAudio(UINT nID); + afx_msg void OnSubtitlesDefaultStyle(); + afx_msg void OnPlaySubtitles(UINT nID); + afx_msg void OnPlayVideoStreams(UINT nID); + afx_msg void OnPlayFiltersStreams(UINT nID); + afx_msg void OnPlayVolume(UINT nID); + afx_msg void OnPlayVolumeBoost(UINT nID); + afx_msg void OnUpdatePlayVolumeBoost(CCmdUI* pCmdUI); + afx_msg void OnCustomChannelMapping(); + afx_msg void OnUpdateCustomChannelMapping(CCmdUI* pCmdUI); + afx_msg void OnNormalizeRegainVolume(UINT nID); + afx_msg void OnUpdateNormalizeRegainVolume(CCmdUI* pCmdUI); + afx_msg void OnPlayColor(UINT nID); + afx_msg void OnAfterplayback(UINT nID); + afx_msg void OnUpdateAfterplayback(CCmdUI* pCmdUI); + afx_msg void OnPlayRepeat(UINT nID); + afx_msg void OnUpdatePlayRepeat(CCmdUI* pCmdUI); + afx_msg void OnABRepeat(UINT nID); + afx_msg void OnUpdateABRepeat(CCmdUI* pCmdUI); + afx_msg void OnPlayRepeatForever(); + afx_msg void OnUpdatePlayRepeatForever(CCmdUI* pCmdUI); + + afx_msg void OnNavigateSkip(UINT nID); + afx_msg void OnUpdateNavigateSkip(CCmdUI* pCmdUI); + afx_msg void OnNavigateSkipFile(UINT nID); + afx_msg void OnUpdateNavigateSkipFile(CCmdUI* pCmdUI); + afx_msg void OnNavigateGoto(); + afx_msg void OnUpdateNavigateGoto(CCmdUI* pCmdUI); + afx_msg void OnNavigateMenu(UINT nID); + afx_msg void OnUpdateNavigateMenu(CCmdUI* pCmdUI); + afx_msg void OnNavigateJumpTo(UINT nID); + afx_msg void OnNavigateMenuItem(UINT nID); + afx_msg void OnUpdateNavigateMenuItem(CCmdUI* pCmdUI); + afx_msg void OnTunerScan(); + afx_msg void OnUpdateTunerScan(CCmdUI* pCmdUI); + + afx_msg void OnFavoritesAdd(); + afx_msg void OnUpdateFavoritesAdd(CCmdUI* pCmdUI); + afx_msg void OnFavoritesQuickAddFavorite(); + afx_msg void OnFavoritesOrganize(); + afx_msg void OnUpdateFavoritesOrganize(CCmdUI* pCmdUI); + afx_msg void OnFavoritesFile(UINT nID); + afx_msg void OnUpdateFavoritesFile(CCmdUI* pCmdUI); + afx_msg void OnFavoritesDVD(UINT nID); + afx_msg void OnUpdateFavoritesDVD(CCmdUI* pCmdUI); + afx_msg void OnFavoritesDevice(UINT nID); + afx_msg void OnUpdateFavoritesDevice(CCmdUI* pCmdUI); + afx_msg void OnRecentFileClear(); + afx_msg void OnUpdateRecentFileClear(CCmdUI* pCmdUI); + afx_msg void OnRecentFile(UINT nID); + afx_msg void OnUpdateRecentFile(CCmdUI* pCmdUI); + + afx_msg void OnHelpHomepage(); + afx_msg void OnHelpCheckForUpdate(); + afx_msg void OnHelpToolbarImages(); + afx_msg void OnHelpDonate(); + + afx_msg void OnClose(); + + bool FilterSettingsByClassID(CLSID clsid, CWnd* parent); + void FilterSettings(CComPtr pUnk, CWnd* parent); + + LRESULT OnMPCVRSwitchFullscreen(WPARAM wParam, LPARAM lParam); + + CMPC_Lcd m_Lcd; + + CMouseWndWithArtView* m_pVideoWnd; // Current Video (main display screen or 2nd) + CWnd* m_pOSDWnd; + CPreView m_wndPreView; // SeekPreview + + + void ReleasePreviewGraph(); + HRESULT PreviewWindowHide(); + HRESULT PreviewWindowShow(REFERENCE_TIME rtCur2); + HRESULT HandleMultipleEntryRar(CStringW fn); + bool CanPreviewUse(); + + CFullscreenWnd* m_pDedicatedFSVideoWnd; + COSD m_OSD; + int m_nCurSubtitle; + long m_lSubtitleShift; + REFERENCE_TIME m_rtCurSubPos; + bool m_bScanDlgOpened; + bool m_bStopTunerScan; + bool m_bLockedZoomVideoWindow; + int m_nLockedZoomVideoWindow; + + void SetLoadState(MLS eState); + MLS GetLoadState() const; + void SetPlayState(MPC_PLAYSTATE iState); + bool CreateFullScreenWindow(bool isD3D=true); + 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, bool relative = false); + //void AutoSelectTracks(); + void SetTimersPlay(); + void KillTimerDelayedSeek(); + void KillTimersStop(); + void AdjustStreamPosPoller(bool restart); + void ResetSubtitlePosAndSize(bool repaint = false); + + // MPC API functions + void ProcessAPICommand(COPYDATASTRUCT* pCDS); + void SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...); + void SendNowPlayingToApi(bool sendtrackinfo = true); + void SendSubtitleTracksToApi(); + void SendAudioTracksToApi(); + void SendPlaylistToApi(); + afx_msg void OnFileOpendirectory(); + + void SendCurrentPositionToApi(bool fNotifySeek = false); + void ShowOSDCustomMessageApi(const MPC_OSDDATA* osdData); + void JumpOfNSeconds(int seconds); + + CString GetVidPos() const; + + CComPtr m_pTaskbarList; + HRESULT CreateThumbnailToolbar(); + HRESULT UpdateThumbarButton(); + HRESULT UpdateThumbarButton(MPC_PLAYSTATE iPlayState); + HRESULT UpdateThumbnailClip(); + BOOL Create(LPCTSTR lpszClassName, + LPCTSTR lpszWindowName, + DWORD dwStyle = WS_OVERLAPPEDWINDOW, + const RECT& rect = rectDefault, + CWnd* pParentWnd = NULL, // != NULL for popups + LPCTSTR lpszMenuName = NULL, + DWORD dwExStyle = 0, + CCreateContext* pContext = NULL); + CMPCThemeMenu* defaultMPCThemeMenu = nullptr; + + bool isSafeZone(CPoint pt); + +protected: + afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct); + // GDI+ + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + void WTSRegisterSessionNotification(); + void WTSUnRegisterSessionNotification(); + + CMenu* m_pActiveContextMenu; + CMenu* m_pActiveSystemMenu; + + void UpdateSkypeHandler(); + void UpdateSeekbarChapterBag(); + void UpdateAudioSwitcher(); + + void LoadArtToViews(const CString& imagePath); + void LoadArtToViews(std::vector buffer); + void ClearArtFromViews(); + + void UpdateUILanguage(); + + bool PerformFlipRotate(); + + bool m_bAltDownClean; + bool m_bShowingFloatingMenubar; + virtual void OnShowMenuBar() override { + m_bShowingFloatingMenubar = (GetMenuBarVisibility() != AFX_MBV_KEEPVISIBLE); + }; + virtual void OnHideMenuBar() override { + m_bShowingFloatingMenubar = false; + }; + virtual void SetMenuBarVisibility(DWORD dwStyle) override { + __super::SetMenuBarVisibility(dwStyle); + if (dwStyle & AFX_MBV_KEEPVISIBLE) { + m_bShowingFloatingMenubar = false; + } + }; + + bool IsAeroSnapped(); + + CPoint m_snapStartPoint; + CRect m_snapStartRect; + + bool m_bAllowWindowZoom; + double m_dLastVideoScaleFactor; + CSize m_lastVideoSize; + + bool m_bExtOnTop; // 'true' if the "on top" flag was set by an external tool + + CString m_sydlLastProcessURL; + + bool IsImageFile(CStringW fn); + bool IsPlayableFormatExt(CStringW ext); + bool IsAudioFileExt(CStringW ext); + bool IsImageFileExt(CStringW ext); + bool IsPlaylistFile(CStringW fn); + bool IsPlaylistFileExt(CStringW ext); + bool IsAudioOrVideoFileExt(CStringW ext); + bool CanSkipToExt(CStringW ext, CStringW curExt); + bool IsAudioFilename(CString filename); + + + // Handles MF_DEFAULT and escapes '&' + static BOOL AppendMenuEx(CMenu& menu, UINT nFlags, UINT nIDNewItem, CString& text); + + void SubtitlesSave(const TCHAR* directory = nullptr, bool silent = false); + + void OnSizingFixWndToVideo(UINT nSide, LPRECT lpRect, bool bCtrl = false); + void OnSizingSnapToScreen(UINT nSide, LPRECT lpRect, bool bCtrl = false); + +public: + afx_msg UINT OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData); + afx_msg void OnSessionChange(UINT nSessionState, UINT nId); + + enum UpdateControlTarget { + UPDATE_VOLUME_STEP, + UPDATE_LOGO, + UPDATE_SKYPE, + UPDATE_SEEKBAR_CHAPTERS, + UPDATE_WINDOW_TITLE, + UPDATE_AUDIO_SWITCHER, + UPDATE_CONTROLS_VISIBILITY, + UPDATE_CHILDVIEW_CURSOR_HACK, + }; + + void UpdateControlState(UpdateControlTarget target); + + void ReloadMenus(); + + // TODO: refactor it outside of MainFrm + GUID GetTimeFormat(); + + CHdmvClipInfo::HdmvPlaylist m_MPLSPlaylist; + bool m_bIsBDPlay; + bool OpenBD(CString Path); + bool m_bHasBDMeta; + CAtlList m_BDMeta; + CHdmvClipInfo::BDMVMeta GetBDMVMeta(); + + bool GetDecoderType(CString& type) const; + + static bool IsOnYDLWhitelist(const CString url); + + bool CanSendToYoutubeDL(const CString url); + bool ProcessYoutubeDLURL(CString url, bool append, bool replace = false); + bool DownloadWithYoutubeDL(CString url, CString filename); + + /** + * @brief Get title of file + * @param fTitleBarTextTitle + * @return + */ + CString getBestTitle(bool fTitleBarTextTitle = true); + MediaTransControls m_media_trans_control; + + void MediaTransportControlSetMedia(); + void MediaTransportControlUpdateState(OAFilterState state); + + enum themableDialogTypes { + None, + windowsFileDialog, + toolbarCustomizeDialog + }; + void enableFileDialogHook(CMPCThemeUtil* helper); + void enableDialogHook(CMPCThemeUtil* helper, themableDialogTypes type); +private: + themableDialogTypes watchingDialog, foundDialog; + CMPCThemeUtil* dialogHookHelper; + +public: + afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); + afx_msg void OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt); +private: + void SetupExternalChapters(); + void ApplyPanNScanPresetString(); + void ValidatePanNScanParameters(); +}; diff --git a/src/mpc-hc/MediaFormats.cpp b/src/mpc-hc/MediaFormats.cpp index 3e2ca5c81a4..d6b87ba7e94 100644 --- a/src/mpc-hc/MediaFormats.cpp +++ b/src/mpc-hc/MediaFormats.cpp @@ -1,343 +1,343 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "MediaFormats.h" -#include "resource.h" - -// -// CMediaFormatCategory -// - -CMediaFormatCategory::CMediaFormatCategory() - : m_fAudioOnly(false) - , m_fAssociable(true) -{ -} - -CMediaFormatCategory::CMediaFormatCategory(CString label, CString description, CAtlList& exts, bool fAudioOnly, bool fAssociable) -{ - m_label = label; - m_description = description; - m_exts.AddTailList(&exts); - m_backupexts.AddTailList(&m_exts); - m_fAudioOnly = fAudioOnly; - m_fAssociable = fAssociable; -} - -CMediaFormatCategory::CMediaFormatCategory(CString label, CString description, CString exts, bool fAudioOnly, bool fAssociable) -{ - m_label = label; - m_description = description; - ExplodeMin(exts, m_exts, ' '); - POSITION pos = m_exts.GetHeadPosition(); - while (pos) { - m_exts.GetNext(pos).TrimLeft(_T('.')); - } - - m_backupexts.AddTailList(&m_exts); - m_fAudioOnly = fAudioOnly; - m_fAssociable = fAssociable; -} - -CMediaFormatCategory::~CMediaFormatCategory() -{ -} - -void CMediaFormatCategory::UpdateData(bool fSave) -{ - if (fSave) { - AfxGetApp()->WriteProfileString(_T("FileFormats2"), m_label, GetExts()); - } else { - SetExts(AfxGetApp()->GetProfileString(_T("FileFormats2"), m_label, GetExts())); - } -} - -CMediaFormatCategory::CMediaFormatCategory(const CMediaFormatCategory& mfc) -{ - *this = mfc; -} - -CMediaFormatCategory& CMediaFormatCategory::operator = (const CMediaFormatCategory& mfc) -{ - if (this != &mfc) { - m_label = mfc.m_label; - m_description = mfc.m_description; - m_exts.RemoveAll(); - m_exts.AddTailList(&mfc.m_exts); - m_backupexts.RemoveAll(); - m_backupexts.AddTailList(&mfc.m_backupexts); - m_fAudioOnly = mfc.m_fAudioOnly; - m_fAssociable = mfc.m_fAssociable; - } - return *this; -} - -void CMediaFormatCategory::RestoreDefaultExts() -{ - m_exts.RemoveAll(); - m_exts.AddTailList(&m_backupexts); -} - -void CMediaFormatCategory::SetExts(CAtlList& exts) -{ - m_exts.RemoveAll(); - m_exts.AddTailList(&exts); -} - -void CMediaFormatCategory::SetExts(CString exts) -{ - exts.Remove(_T('.')); - m_exts.RemoveAll(); - ExplodeMin(exts, m_exts, ' '); -} - -CString CMediaFormatCategory::GetFilter() const -{ - CString filter; - POSITION pos = m_exts.GetHeadPosition(); - while (pos) { - filter += _T("*.") + m_exts.GetNext(pos) + _T(";"); - } - filter.TrimRight(_T(';')); - return filter; -} - -CString CMediaFormatCategory::GetExts() const -{ - return Implode(m_exts, ' '); -} - -CString CMediaFormatCategory::GetExtsWithPeriod() const -{ - CString exts; - POSITION pos = m_exts.GetHeadPosition(); - while (pos) { - exts += _T(".") + m_exts.GetNext(pos) + _T(" "); - } - exts.TrimRight(_T(' ')); - return exts; -} - -CString CMediaFormatCategory::GetBackupExtsWithPeriod() const -{ - CString exts; - POSITION pos = m_backupexts.GetHeadPosition(); - while (pos) { - exts += _T(".") + m_backupexts.GetNext(pos) + _T(" "); - } - exts.TrimRight(_T(' ')); - return exts; -} - -// -// CMediaFormats -// - -CMediaFormats::CMediaFormats() -{ -} - -CMediaFormats::~CMediaFormats() -{ -} - -void CMediaFormats::UpdateData(bool fSave) -{ - if (fSave) { - AfxGetApp()->WriteProfileString(_T("FileFormats2"), nullptr, nullptr); - } else { - RemoveAll(); - -#define ADDFMT(f) Add(CMediaFormatCategory##f) - - ADDFMT((_T("avi"), StrRes(IDS_MFMT_AVI), _T("avi"))); - ADDFMT((_T("mpeg"), StrRes(IDS_MFMT_MPEG), _T("mpg mpeg mpe m1v m2v mpv2 mp2v pva evo m2p"))); - ADDFMT((_T("mpegts"), StrRes(IDS_MFMT_MPEGTS), _T("ts tp trp m2t m2ts mts rec ssif"))); - ADDFMT((_T("dvdvideo"), StrRes(IDS_MFMT_DVDVIDEO), _T("vob ifo"))); - ADDFMT((_T("mkv"), StrRes(IDS_MFMT_MKV), _T("mkv mk3d"))); - ADDFMT((_T("webm"), StrRes(IDS_MFMT_WEBM), _T("webm"))); - ADDFMT((_T("mp4"), StrRes(IDS_MFMT_MP4), _T("mp4 m4v mp4v mpv4 hdmov"))); - ADDFMT((_T("mov"), StrRes(IDS_MFMT_MOV), _T("mov"))); - ADDFMT((_T("3gp"), StrRes(IDS_MFMT_3GP), _T("3gp 3gpp 3g2 3gp2"))); - ADDFMT((_T("flv"), StrRes(IDS_MFMT_FLV), _T("flv f4v"))); - ADDFMT((_T("ogm"), StrRes(IDS_MFMT_OGM), _T("ogm ogv"))); - ADDFMT((_T("rm"), StrRes(IDS_MFMT_RM), _T("rm rmvb"))); - ADDFMT((_T("rt"), StrRes(IDS_MFMT_RT), _T("rt ram rpm rmm rp smi smil"))); - ADDFMT((_T("wmv"), StrRes(IDS_MFMT_WMV), _T("wmv wmp wm asf"))); - ADDFMT((_T("bink"), StrRes(IDS_MFMT_BINK), _T("smk bik"))); - ADDFMT((_T("flic"), StrRes(IDS_MFMT_FLIC), _T("fli flc flic"))); - ADDFMT((_T("dsm"), StrRes(IDS_MFMT_DSM), _T("dsm dsv dsa dss"))); - ADDFMT((_T("ivf"), StrRes(IDS_MFMT_IVF), _T("ivf"))); - ADDFMT((_T("other"), StrRes(IDS_MFMT_OTHER), _T("divx amv mxf dv dav"))); - ADDFMT((_T("bdpls"), StrRes(IDS_MFMT_BDPLS), _T("mpls bdmv"))); - ADDFMT((_T("3ga"), StrRes(IDS_MFMT_3GA), _T("3ga"), true)); - ADDFMT((_T("ac3"), StrRes(IDS_MFMT_AC3), _T("ac3"), true)); - ADDFMT((_T("dts"), StrRes(IDS_MFMT_DTS), _T("dts dtshd dtsma"), true)); - ADDFMT((_T("aiff"), StrRes(IDS_MFMT_AIFF), _T("aif aifc aiff"), true)); - ADDFMT((_T("alac"), StrRes(IDS_MFMT_ALAC), _T("alac"), true)); - ADDFMT((_T("amr"), StrRes(IDS_MFMT_AMR), _T("amr"), true)); - ADDFMT((_T("ape"), StrRes(IDS_MFMT_APE), _T("ape apl"), true)); - ADDFMT((_T("au"), StrRes(IDS_MFMT_AU), _T("au snd"), true)); - ADDFMT((_T("audiocd"), StrRes(IDS_MFMT_CDA), _T("cda"), true)); - ADDFMT((_T("flac"), StrRes(IDS_MFMT_FLAC), _T("flac"), true)); - ADDFMT((_T("m4a"), StrRes(IDS_MFMT_M4A), _T("m4a m4b m4r aac"), true)); - ADDFMT((_T("midi"), StrRes(IDS_MFMT_MIDI), _T("mid midi rmi"), true)); - ADDFMT((_T("mka"), StrRes(IDS_MFMT_MKA), _T("mka"), true)); - ADDFMT((_T("mp3"), StrRes(IDS_MFMT_MP3), _T("mp3"), true)); - ADDFMT((_T("mpa"), StrRes(IDS_MFMT_MPA), _T("mpa mp2 m1a m2a"), true)); - ADDFMT((_T("mpc"), StrRes(IDS_MFMT_MPC), _T("mpc"), true)); - ADDFMT((_T("ofr"), StrRes(IDS_MFMT_OFR), _T("ofr ofs"), true)); - ADDFMT((_T("ogg"), StrRes(IDS_MFMT_OGG), _T("ogg oga"), true)); - ADDFMT((_T("opus"), StrRes(IDS_MFMT_OPUS), _T("opus"), true)); - ADDFMT((_T("ra"), StrRes(IDS_MFMT_RA), _T("ra"), true)); - ADDFMT((_T("tak"), StrRes(IDS_MFMT_TAK), _T("tak"), true)); - ADDFMT((_T("tta"), StrRes(IDS_MFMT_TTA), _T("tta"), true)); - ADDFMT((_T("wav"), StrRes(IDS_MFMT_WAV), _T("wav"), true)); - ADDFMT((_T("wma"), StrRes(IDS_MFMT_WMA), _T("wma"), true)); - ADDFMT((_T("wavpack"), StrRes(IDS_MFMT_WV), _T("wv"), true)); - ADDFMT((_T("weba"), _T("WebA"), _T("weba"), true)); - ADDFMT((_T("other_audio"), StrRes(IDS_MFMT_OTHER_AUDIO), _T("aob mlp thd mpl spx caf dsf eac3"), true)); - ADDFMT((_T("pls"), StrRes(IDS_MFMT_PLS), _T("asx m3u m3u8 pls wvx wax wmx mpcpl"))); - ADDFMT((_T("cue"), _T("Cue sheet"), _T("cue"))); - ADDFMT((_T("swf"), StrRes(IDS_MFMT_SWF), _T("swf"))); - ADDFMT((_T("rar"), StrRes(IDS_MFMT_RAR), _T("rar"), false, false)); - ADDFMT((_T("avs"), StrRes(IDS_MFMT_AVS), _T("avs"), false, false)); -#undef ADDFMT - } - - for (size_t i = 0; i < GetCount(); i++) { - GetAt(i).UpdateData(fSave); - } -} - -bool CMediaFormats::IsUsingEngine(CString path, engine_t e) const -{ - return (GetEngine(path) == e); -} - -engine_t CMediaFormats::GetEngine(CString path) const -{ - CString ext = CPath(path.Trim()).GetExtension().MakeLower(); - if (ext == _T(".swf")) { - return ShockWave; - } - return DirectShow; -} - -bool CMediaFormats::FindExt(CString ext, bool fAudioOnly, bool fAssociableOnly) const -{ - return (FindMediaByExt(ext, fAudioOnly, fAssociableOnly) != nullptr); -} - -const CMediaFormatCategory* CMediaFormats::FindMediaByExt(CString ext, bool fAudioOnly, bool fAssociableOnly) const -{ - ext.TrimLeft(_T('.')); - - if (!ext.IsEmpty()) { - for (size_t i = 0; i < GetCount(); i++) { - const CMediaFormatCategory& mfc = GetAt(i); - if ((!fAudioOnly || mfc.IsAudioOnly()) && (!fAssociableOnly || mfc.IsAssociable()) && mfc.FindExt(ext)) { - return &mfc; - } - } - } - - return nullptr; -} - -void CMediaFormats::GetFilter(CString& filter, CAtlArray& mask) const -{ - CString strTemp; - - filter.AppendFormat(IsExtHidden() ? _T("%s|") : _T("%s (*.avi;*.mp4;*.mkv;...)|"), ResStr(IDS_AG_MEDIAFILES).GetString()); - mask.Add(_T("")); - - for (size_t i = 0; i < GetCount(); i++) { - strTemp = GetAt(i).GetFilter() + _T(";"); - mask[0] += strTemp; - filter += strTemp; - } - mask[0].TrimRight(_T(';')); - filter.TrimRight(_T(';')); - filter += _T("|"); - - for (size_t i = 0; i < GetCount(); i++) { - const CMediaFormatCategory& mfc = GetAt(i); - filter += mfc.GetDescription() + _T("|" + GetAt(i).GetFilter() + _T("|")); - mask.Add(mfc.GetFilter()); - } - - filter.AppendFormat(IDS_AG_ALLFILES); - mask.Add(_T("*.*")); - - filter += _T("|"); -} - -void CMediaFormats::GetAudioFilter(CString& filter, CAtlArray& mask) const -{ - CString strTemp; - - filter.AppendFormat(IsExtHidden() ? _T("%s|") : _T("%s (*.mp3;*.aac;*.wav;...)|"), ResStr(IDS_AG_AUDIOFILES).GetString()); - mask.Add(_T("")); - - for (size_t i = 0; i < GetCount(); i++) { - const CMediaFormatCategory& mfc = GetAt(i); - if (!mfc.IsAudioOnly()) { - continue; - } - strTemp = GetAt(i).GetFilter() + _T(";"); - mask[0] += strTemp; - filter += strTemp; - } - - mask[0].TrimRight(_T(';')); - filter.TrimRight(_T(';')); - filter += _T("|"); - - for (size_t i = 0; i < GetCount(); i++) { - const CMediaFormatCategory& mfc = GetAt(i); - if (!mfc.IsAudioOnly()) { - continue; - } - filter += mfc.GetDescription() + _T("|") + GetAt(i).GetFilter() + _T("|"); - mask.Add(mfc.GetFilter()); - } - - filter.AppendFormat(IDS_AG_ALLFILES); - mask.Add(_T("*.*")); - - filter += _T("|"); -} - -bool CMediaFormats::IsExtHidden() -{ - CRegKey key; - if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), KEY_READ)) { - DWORD value; - if (ERROR_SUCCESS == key.QueryDWORDValue(_T("HideFileExt"), value)) { - return !!value; - } - } - return false; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "MediaFormats.h" +#include "resource.h" + +// +// CMediaFormatCategory +// + +CMediaFormatCategory::CMediaFormatCategory() + : m_fAudioOnly(false) + , m_fAssociable(true) +{ +} + +CMediaFormatCategory::CMediaFormatCategory(CString label, CString description, CAtlList& exts, bool fAudioOnly, bool fAssociable) +{ + m_label = label; + m_description = description; + m_exts.AddTailList(&exts); + m_backupexts.AddTailList(&m_exts); + m_fAudioOnly = fAudioOnly; + m_fAssociable = fAssociable; +} + +CMediaFormatCategory::CMediaFormatCategory(CString label, CString description, CString exts, bool fAudioOnly, bool fAssociable) +{ + m_label = label; + m_description = description; + ExplodeMin(exts, m_exts, ' '); + POSITION pos = m_exts.GetHeadPosition(); + while (pos) { + m_exts.GetNext(pos).TrimLeft(_T('.')); + } + + m_backupexts.AddTailList(&m_exts); + m_fAudioOnly = fAudioOnly; + m_fAssociable = fAssociable; +} + +CMediaFormatCategory::~CMediaFormatCategory() +{ +} + +void CMediaFormatCategory::UpdateData(bool fSave) +{ + if (fSave) { + AfxGetApp()->WriteProfileString(_T("FileFormats2"), m_label, GetExts()); + } else { + SetExts(AfxGetApp()->GetProfileString(_T("FileFormats2"), m_label, GetExts())); + } +} + +CMediaFormatCategory::CMediaFormatCategory(const CMediaFormatCategory& mfc) +{ + *this = mfc; +} + +CMediaFormatCategory& CMediaFormatCategory::operator = (const CMediaFormatCategory& mfc) +{ + if (this != &mfc) { + m_label = mfc.m_label; + m_description = mfc.m_description; + m_exts.RemoveAll(); + m_exts.AddTailList(&mfc.m_exts); + m_backupexts.RemoveAll(); + m_backupexts.AddTailList(&mfc.m_backupexts); + m_fAudioOnly = mfc.m_fAudioOnly; + m_fAssociable = mfc.m_fAssociable; + } + return *this; +} + +void CMediaFormatCategory::RestoreDefaultExts() +{ + m_exts.RemoveAll(); + m_exts.AddTailList(&m_backupexts); +} + +void CMediaFormatCategory::SetExts(CAtlList& exts) +{ + m_exts.RemoveAll(); + m_exts.AddTailList(&exts); +} + +void CMediaFormatCategory::SetExts(CString exts) +{ + exts.Remove(_T('.')); + m_exts.RemoveAll(); + ExplodeMin(exts, m_exts, ' '); +} + +CString CMediaFormatCategory::GetFilter() const +{ + CString filter; + POSITION pos = m_exts.GetHeadPosition(); + while (pos) { + filter += _T("*.") + m_exts.GetNext(pos) + _T(";"); + } + filter.TrimRight(_T(';')); + return filter; +} + +CString CMediaFormatCategory::GetExts() const +{ + return Implode(m_exts, ' '); +} + +CString CMediaFormatCategory::GetExtsWithPeriod() const +{ + CString exts; + POSITION pos = m_exts.GetHeadPosition(); + while (pos) { + exts += _T(".") + m_exts.GetNext(pos) + _T(" "); + } + exts.TrimRight(_T(' ')); + return exts; +} + +CString CMediaFormatCategory::GetBackupExtsWithPeriod() const +{ + CString exts; + POSITION pos = m_backupexts.GetHeadPosition(); + while (pos) { + exts += _T(".") + m_backupexts.GetNext(pos) + _T(" "); + } + exts.TrimRight(_T(' ')); + return exts; +} + +// +// CMediaFormats +// + +CMediaFormats::CMediaFormats() +{ +} + +CMediaFormats::~CMediaFormats() +{ +} + +void CMediaFormats::UpdateData(bool fSave) +{ + if (fSave) { + AfxGetApp()->WriteProfileString(_T("FileFormats2"), nullptr, nullptr); + } else { + RemoveAll(); + +#define ADDFMT(f) Add(CMediaFormatCategory##f) + + ADDFMT((_T("avi"), StrRes(IDS_MFMT_AVI), _T("avi"))); + ADDFMT((_T("mpeg"), StrRes(IDS_MFMT_MPEG), _T("mpg mpeg mpe m1v m2v mpv2 mp2v pva evo m2p"))); + ADDFMT((_T("mpegts"), StrRes(IDS_MFMT_MPEGTS), _T("ts tp trp m2t m2ts mts rec ssif"))); + ADDFMT((_T("dvdvideo"), StrRes(IDS_MFMT_DVDVIDEO), _T("vob ifo"))); + ADDFMT((_T("mkv"), StrRes(IDS_MFMT_MKV), _T("mkv mk3d"))); + ADDFMT((_T("webm"), StrRes(IDS_MFMT_WEBM), _T("webm"))); + ADDFMT((_T("mp4"), StrRes(IDS_MFMT_MP4), _T("mp4 m4v mp4v mpv4 hdmov"))); + ADDFMT((_T("mov"), StrRes(IDS_MFMT_MOV), _T("mov"))); + ADDFMT((_T("3gp"), StrRes(IDS_MFMT_3GP), _T("3gp 3gpp 3g2 3gp2"))); + ADDFMT((_T("flv"), StrRes(IDS_MFMT_FLV), _T("flv f4v"))); + ADDFMT((_T("ogm"), StrRes(IDS_MFMT_OGM), _T("ogm ogv"))); + ADDFMT((_T("rm"), StrRes(IDS_MFMT_RM), _T("rm rmvb"))); + ADDFMT((_T("rt"), StrRes(IDS_MFMT_RT), _T("rt ram rpm rmm rp smi smil"))); + ADDFMT((_T("wmv"), StrRes(IDS_MFMT_WMV), _T("wmv wmp wm asf"))); + ADDFMT((_T("bink"), StrRes(IDS_MFMT_BINK), _T("smk bik"))); + ADDFMT((_T("flic"), StrRes(IDS_MFMT_FLIC), _T("fli flc flic"))); + ADDFMT((_T("dsm"), StrRes(IDS_MFMT_DSM), _T("dsm dsv dsa dss"))); + ADDFMT((_T("ivf"), StrRes(IDS_MFMT_IVF), _T("ivf"))); + ADDFMT((_T("other"), StrRes(IDS_MFMT_OTHER), _T("divx amv mxf dv dav"))); + ADDFMT((_T("bdpls"), StrRes(IDS_MFMT_BDPLS), _T("mpls bdmv"))); + ADDFMT((_T("3ga"), StrRes(IDS_MFMT_3GA), _T("3ga"), true)); + ADDFMT((_T("ac3"), StrRes(IDS_MFMT_AC3), _T("ac3"), true)); + ADDFMT((_T("dts"), StrRes(IDS_MFMT_DTS), _T("dts dtshd dtsma"), true)); + ADDFMT((_T("aiff"), StrRes(IDS_MFMT_AIFF), _T("aif aifc aiff"), true)); + ADDFMT((_T("alac"), StrRes(IDS_MFMT_ALAC), _T("alac"), true)); + ADDFMT((_T("amr"), StrRes(IDS_MFMT_AMR), _T("amr"), true)); + ADDFMT((_T("ape"), StrRes(IDS_MFMT_APE), _T("ape apl"), true)); + ADDFMT((_T("au"), StrRes(IDS_MFMT_AU), _T("au snd"), true)); + ADDFMT((_T("audiocd"), StrRes(IDS_MFMT_CDA), _T("cda"), true)); + ADDFMT((_T("flac"), StrRes(IDS_MFMT_FLAC), _T("flac"), true)); + ADDFMT((_T("m4a"), StrRes(IDS_MFMT_M4A), _T("m4a m4b m4r aac"), true)); + ADDFMT((_T("midi"), StrRes(IDS_MFMT_MIDI), _T("mid midi rmi"), true)); + ADDFMT((_T("mka"), StrRes(IDS_MFMT_MKA), _T("mka"), true)); + ADDFMT((_T("mp3"), StrRes(IDS_MFMT_MP3), _T("mp3"), true)); + ADDFMT((_T("mpa"), StrRes(IDS_MFMT_MPA), _T("mpa mp2 m1a m2a"), true)); + ADDFMT((_T("mpc"), StrRes(IDS_MFMT_MPC), _T("mpc"), true)); + ADDFMT((_T("ofr"), StrRes(IDS_MFMT_OFR), _T("ofr ofs"), true)); + ADDFMT((_T("ogg"), StrRes(IDS_MFMT_OGG), _T("ogg oga"), true)); + ADDFMT((_T("opus"), StrRes(IDS_MFMT_OPUS), _T("opus"), true)); + ADDFMT((_T("ra"), StrRes(IDS_MFMT_RA), _T("ra"), true)); + ADDFMT((_T("tak"), StrRes(IDS_MFMT_TAK), _T("tak"), true)); + ADDFMT((_T("tta"), StrRes(IDS_MFMT_TTA), _T("tta"), true)); + ADDFMT((_T("wav"), StrRes(IDS_MFMT_WAV), _T("wav"), true)); + ADDFMT((_T("wma"), StrRes(IDS_MFMT_WMA), _T("wma"), true)); + ADDFMT((_T("wavpack"), StrRes(IDS_MFMT_WV), _T("wv"), true)); + ADDFMT((_T("weba"), _T("WebA"), _T("weba"), true)); + ADDFMT((_T("other_audio"), StrRes(IDS_MFMT_OTHER_AUDIO), _T("aob mlp thd mpl spx caf dsf eac3"), true)); + ADDFMT((_T("pls"), StrRes(IDS_MFMT_PLS), _T("asx m3u m3u8 pls wvx wax wmx mpcpl"))); + ADDFMT((_T("cue"), _T("Cue sheet"), _T("cue"))); + ADDFMT((_T("swf"), StrRes(IDS_MFMT_SWF), _T("swf"))); + ADDFMT((_T("rar"), StrRes(IDS_MFMT_RAR), _T("rar"), false, false)); + ADDFMT((_T("avs"), StrRes(IDS_MFMT_AVS), _T("avs"), false, false)); +#undef ADDFMT + } + + for (size_t i = 0; i < GetCount(); i++) { + GetAt(i).UpdateData(fSave); + } +} + +bool CMediaFormats::IsUsingEngine(CString path, engine_t e) const +{ + return (GetEngine(path) == e); +} + +engine_t CMediaFormats::GetEngine(CString path) const +{ + CString ext = CPath(path.Trim()).GetExtension().MakeLower(); + if (ext == _T(".swf")) { + return ShockWave; + } + return DirectShow; +} + +bool CMediaFormats::FindExt(CString ext, bool fAudioOnly, bool fAssociableOnly) const +{ + return (FindMediaByExt(ext, fAudioOnly, fAssociableOnly) != nullptr); +} + +const CMediaFormatCategory* CMediaFormats::FindMediaByExt(CString ext, bool fAudioOnly, bool fAssociableOnly) const +{ + ext.TrimLeft(_T('.')); + + if (!ext.IsEmpty()) { + for (size_t i = 0; i < GetCount(); i++) { + const CMediaFormatCategory& mfc = GetAt(i); + if ((!fAudioOnly || mfc.IsAudioOnly()) && (!fAssociableOnly || mfc.IsAssociable()) && mfc.FindExt(ext)) { + return &mfc; + } + } + } + + return nullptr; +} + +void CMediaFormats::GetFilter(CString& filter, CAtlArray& mask) const +{ + CString strTemp; + + filter.AppendFormat(IsExtHidden() ? _T("%s|") : _T("%s (*.avi;*.mp4;*.mkv;...)|"), ResStr(IDS_AG_MEDIAFILES).GetString()); + mask.Add(_T("")); + + for (size_t i = 0; i < GetCount(); i++) { + strTemp = GetAt(i).GetFilter() + _T(";"); + mask[0] += strTemp; + filter += strTemp; + } + mask[0].TrimRight(_T(';')); + filter.TrimRight(_T(';')); + filter += _T("|"); + + for (size_t i = 0; i < GetCount(); i++) { + const CMediaFormatCategory& mfc = GetAt(i); + filter += mfc.GetDescription() + _T("|" + GetAt(i).GetFilter() + _T("|")); + mask.Add(mfc.GetFilter()); + } + + filter.AppendFormat(IDS_AG_ALLFILES); + mask.Add(_T("*.*")); + + filter += _T("|"); +} + +void CMediaFormats::GetAudioFilter(CString& filter, CAtlArray& mask) const +{ + CString strTemp; + + filter.AppendFormat(IsExtHidden() ? _T("%s|") : _T("%s (*.mp3;*.aac;*.wav;...)|"), ResStr(IDS_AG_AUDIOFILES).GetString()); + mask.Add(_T("")); + + for (size_t i = 0; i < GetCount(); i++) { + const CMediaFormatCategory& mfc = GetAt(i); + if (!mfc.IsAudioOnly()) { + continue; + } + strTemp = GetAt(i).GetFilter() + _T(";"); + mask[0] += strTemp; + filter += strTemp; + } + + mask[0].TrimRight(_T(';')); + filter.TrimRight(_T(';')); + filter += _T("|"); + + for (size_t i = 0; i < GetCount(); i++) { + const CMediaFormatCategory& mfc = GetAt(i); + if (!mfc.IsAudioOnly()) { + continue; + } + filter += mfc.GetDescription() + _T("|") + GetAt(i).GetFilter() + _T("|"); + mask.Add(mfc.GetFilter()); + } + + filter.AppendFormat(IDS_AG_ALLFILES); + mask.Add(_T("*.*")); + + filter += _T("|"); +} + +bool CMediaFormats::IsExtHidden() +{ + CRegKey key; + if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), KEY_READ)) { + DWORD value; + if (ERROR_SUCCESS == key.QueryDWORDValue(_T("HideFileExt"), value)) { + return !!value; + } + } + return false; +} diff --git a/src/mpc-hc/MediaFormats.h b/src/mpc-hc/MediaFormats.h index 3087987e1e4..83629319f3f 100644 --- a/src/mpc-hc/MediaFormats.h +++ b/src/mpc-hc/MediaFormats.h @@ -1,91 +1,91 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "BaseGraph.h" - - -class CMediaFormatCategory -{ -protected: - CString m_label, m_description; - CAtlList m_exts, m_backupexts; - bool m_fAudioOnly; - bool m_fAssociable; - -public: - CMediaFormatCategory(); - CMediaFormatCategory(CString label, CString description, CAtlList& exts, bool fAudioOnly = false, bool fAssociable = true); - CMediaFormatCategory(CString label, CString description, CString exts, bool fAudioOnly = false, bool fAssociable = true); - virtual ~CMediaFormatCategory(); - - void UpdateData(bool fSave); - - CMediaFormatCategory(const CMediaFormatCategory& mfc); - CMediaFormatCategory& operator = (const CMediaFormatCategory& mfc); - - void RestoreDefaultExts(); - void SetExts(CAtlList& exts); - void SetExts(CString exts); - - bool FindExt(CString ext) const { - return m_exts.Find(ext.TrimLeft(_T('.')).MakeLower()) != nullptr; - } - - CString GetLabel() const { return m_label; } - - CString GetDescription() const { return m_description; } - CString GetFilter() const; - CString GetExts() const; - CString GetExtsWithPeriod() const; - CString GetBackupExtsWithPeriod() const; - bool IsAudioOnly() const { return m_fAudioOnly; } - bool IsAssociable() const { return m_fAssociable; } - bool IsVideoOnly() const { return !m_fAudioOnly && m_label != _T("pls") && m_label != _T("cue") && m_label != _T("swf"); } -}; - -class CMediaFormats : public CAtlArray -{ -public: - CMediaFormats(); - virtual ~CMediaFormats(); - - //CMediaFormats(const CMediaFormats& mf) { *this = mf; } - CMediaFormats& operator=(const CMediaFormats& mf) { - Copy(mf); - return *this; - } - - void UpdateData(bool fSave); - - bool IsUsingEngine(CString path, engine_t e) const; - engine_t GetEngine(CString path) const; - - bool FindExt(CString ext, bool fAudioOnly = false, bool fAssociableOnly = true) const; - const CMediaFormatCategory* FindMediaByExt(CString ext, bool fAudioOnly = false, bool fAssociableOnly = true) const; - - void GetFilter(CString& filter, CAtlArray& mask) const; - void GetAudioFilter(CString& filter, CAtlArray& mask) const; - - static bool IsExtHidden(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "BaseGraph.h" + + +class CMediaFormatCategory +{ +protected: + CString m_label, m_description; + CAtlList m_exts, m_backupexts; + bool m_fAudioOnly; + bool m_fAssociable; + +public: + CMediaFormatCategory(); + CMediaFormatCategory(CString label, CString description, CAtlList& exts, bool fAudioOnly = false, bool fAssociable = true); + CMediaFormatCategory(CString label, CString description, CString exts, bool fAudioOnly = false, bool fAssociable = true); + virtual ~CMediaFormatCategory(); + + void UpdateData(bool fSave); + + CMediaFormatCategory(const CMediaFormatCategory& mfc); + CMediaFormatCategory& operator = (const CMediaFormatCategory& mfc); + + void RestoreDefaultExts(); + void SetExts(CAtlList& exts); + void SetExts(CString exts); + + bool FindExt(CString ext) const { + return m_exts.Find(ext.TrimLeft(_T('.')).MakeLower()) != nullptr; + } + + CString GetLabel() const { return m_label; } + + CString GetDescription() const { return m_description; } + CString GetFilter() const; + CString GetExts() const; + CString GetExtsWithPeriod() const; + CString GetBackupExtsWithPeriod() const; + bool IsAudioOnly() const { return m_fAudioOnly; } + bool IsAssociable() const { return m_fAssociable; } + bool IsVideoOnly() const { return !m_fAudioOnly && m_label != _T("pls") && m_label != _T("cue") && m_label != _T("swf"); } +}; + +class CMediaFormats : public CAtlArray +{ +public: + CMediaFormats(); + virtual ~CMediaFormats(); + + //CMediaFormats(const CMediaFormats& mf) { *this = mf; } + CMediaFormats& operator=(const CMediaFormats& mf) { + Copy(mf); + return *this; + } + + void UpdateData(bool fSave); + + bool IsUsingEngine(CString path, engine_t e) const; + engine_t GetEngine(CString path) const; + + bool FindExt(CString ext, bool fAudioOnly = false, bool fAssociableOnly = true) const; + const CMediaFormatCategory* FindMediaByExt(CString ext, bool fAudioOnly = false, bool fAssociableOnly = true) const; + + void GetFilter(CString& filter, CAtlArray& mask) const; + void GetAudioFilter(CString& filter, CAtlArray& mask) const; + + static bool IsExtHidden(); +}; diff --git a/src/mpc-hc/MediaTypesDlg.cpp b/src/mpc-hc/MediaTypesDlg.cpp index bbb1c1fecd4..c49971c5934 100644 --- a/src/mpc-hc/MediaTypesDlg.cpp +++ b/src/mpc-hc/MediaTypesDlg.cpp @@ -1,158 +1,158 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "MediaTypesDlg.h" -#include "DSUtil.h" -#include "moreuuids.h" - - -// CMediaTypesDlg dialog - -//IMPLEMENT_DYNAMIC(CMediaTypesDlg, CResizableDialog) -CMediaTypesDlg::CMediaTypesDlg(IGraphBuilderDeadEnd* pGBDE, CWnd* pParent /*=nullptr*/) - : CMPCThemeResizableDialog(CMediaTypesDlg::IDD, pParent) - , m_pGBDE(pGBDE) - , m_type(UNKNOWN) - , m_subtype(GUID_NULL) -{ -} - -CMediaTypesDlg::~CMediaTypesDlg() -{ -} - -void CMediaTypesDlg::DoDataExchange(CDataExchange* pDX) -{ - CResizableDialog::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO1, m_pins); - DDX_Control(pDX, IDC_EDIT1, m_report); -} - -void CMediaTypesDlg::AddLine(CString str) -{ - str.Replace(_T("\n"), _T("\r\n")); - int len = m_report.GetWindowTextLength(); - m_report.SetSel(len, len, TRUE); - m_report.ReplaceSel(str); -} - -void CMediaTypesDlg::AddMediaType(const AM_MEDIA_TYPE* pmt) -{ - m_subtype = pmt->subtype; - if (pmt->majortype == MEDIATYPE_Video) { - m_type = VIDEO; - } else if (pmt->majortype == MEDIATYPE_Audio) { - m_type = AUDIO; - } else { - m_type = UNKNOWN; - } - - CAtlList sl; - CMediaTypeEx(*pmt).Dump(sl); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - AddLine(sl.GetNext(pos) + '\n'); - } -} - -BEGIN_MESSAGE_MAP(CMediaTypesDlg, CMPCThemeResizableDialog) - ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelchangeCombo1) - ON_MESSAGE(WM_EXTERNALCLOSE, OnExternalClose) -END_MESSAGE_MAP() - - -// CMediaTypesDlg message handlers - -BOOL CMediaTypesDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - CAtlList path; - CAtlList mts; - - for (int i = 0; S_OK == m_pGBDE->GetDeadEnd(i, path, mts); i++) { - if (!path.GetCount()) { - continue; - } - m_pins.SetItemData(m_pins.AddString(CString(path.GetTail())), (DWORD_PTR)i); - } - - m_pins.SetCurSel(0); - OnCbnSelchangeCombo1(); - - AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_STATIC2, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_COMBO1, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_EDIT1, TOP_LEFT, BOTTOM_RIGHT); - AddAnchor(IDOK, BOTTOM_RIGHT); - - SetMinTrackSize(CSize(300, 200)); - fulfillThemeReqs(); - - //DWORD threadID = GetWindowThreadProcessId(m_hWnd,nullptr); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CMediaTypesDlg::OnCbnSelchangeCombo1() -{ - m_report.SetWindowText(_T("")); - - int i = m_pins.GetCurSel(); - if (i < 0) { - return; - } - - CAtlList path; - CAtlList mts; - - if (FAILED(m_pGBDE->GetDeadEnd(i, path, mts)) || !path.GetCount()) { - return; - } - - POSITION pos = path.GetHeadPosition(); - while (pos) { - AddLine(CString(path.GetNext(pos)) + _T("\n")); - if (!pos) { - AddLine(_T("\n")); - } - } - - pos = mts.GetHeadPosition(); - for (int j = 0; pos; j++) { - CString str; - str.Format(_T("Media Type %d:\n"), j); - AddLine(str); - AddLine(_T("--------------------------\n")); - AddMediaType(&mts.GetNext(pos)); - AddLine(); - } - - m_report.SetSel(0, 0); -} - -LRESULT CMediaTypesDlg::OnExternalClose(WPARAM wParam, LPARAM lParam) { - EndDialog(IDCANCEL); - return LRESULT(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "MediaTypesDlg.h" +#include "DSUtil.h" +#include "moreuuids.h" + + +// CMediaTypesDlg dialog + +//IMPLEMENT_DYNAMIC(CMediaTypesDlg, CResizableDialog) +CMediaTypesDlg::CMediaTypesDlg(IGraphBuilderDeadEnd* pGBDE, CWnd* pParent /*=nullptr*/) + : CMPCThemeResizableDialog(CMediaTypesDlg::IDD, pParent) + , m_pGBDE(pGBDE) + , m_type(UNKNOWN) + , m_subtype(GUID_NULL) +{ +} + +CMediaTypesDlg::~CMediaTypesDlg() +{ +} + +void CMediaTypesDlg::DoDataExchange(CDataExchange* pDX) +{ + CResizableDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO1, m_pins); + DDX_Control(pDX, IDC_EDIT1, m_report); +} + +void CMediaTypesDlg::AddLine(CString str) +{ + str.Replace(_T("\n"), _T("\r\n")); + int len = m_report.GetWindowTextLength(); + m_report.SetSel(len, len, TRUE); + m_report.ReplaceSel(str); +} + +void CMediaTypesDlg::AddMediaType(const AM_MEDIA_TYPE* pmt) +{ + m_subtype = pmt->subtype; + if (pmt->majortype == MEDIATYPE_Video) { + m_type = VIDEO; + } else if (pmt->majortype == MEDIATYPE_Audio) { + m_type = AUDIO; + } else { + m_type = UNKNOWN; + } + + CAtlList sl; + CMediaTypeEx(*pmt).Dump(sl); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + AddLine(sl.GetNext(pos) + '\n'); + } +} + +BEGIN_MESSAGE_MAP(CMediaTypesDlg, CMPCThemeResizableDialog) + ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelchangeCombo1) + ON_MESSAGE(WM_EXTERNALCLOSE, OnExternalClose) +END_MESSAGE_MAP() + + +// CMediaTypesDlg message handlers + +BOOL CMediaTypesDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + CAtlList path; + CAtlList mts; + + for (int i = 0; S_OK == m_pGBDE->GetDeadEnd(i, path, mts); i++) { + if (!path.GetCount()) { + continue; + } + m_pins.SetItemData(m_pins.AddString(CString(path.GetTail())), (DWORD_PTR)i); + } + + m_pins.SetCurSel(0); + OnCbnSelchangeCombo1(); + + AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_STATIC2, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_COMBO1, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_EDIT1, TOP_LEFT, BOTTOM_RIGHT); + AddAnchor(IDOK, BOTTOM_RIGHT); + + SetMinTrackSize(CSize(300, 200)); + fulfillThemeReqs(); + + //DWORD threadID = GetWindowThreadProcessId(m_hWnd,nullptr); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CMediaTypesDlg::OnCbnSelchangeCombo1() +{ + m_report.SetWindowText(_T("")); + + int i = m_pins.GetCurSel(); + if (i < 0) { + return; + } + + CAtlList path; + CAtlList mts; + + if (FAILED(m_pGBDE->GetDeadEnd(i, path, mts)) || !path.GetCount()) { + return; + } + + POSITION pos = path.GetHeadPosition(); + while (pos) { + AddLine(CString(path.GetNext(pos)) + _T("\n")); + if (!pos) { + AddLine(_T("\n")); + } + } + + pos = mts.GetHeadPosition(); + for (int j = 0; pos; j++) { + CString str; + str.Format(_T("Media Type %d:\n"), j); + AddLine(str); + AddLine(_T("--------------------------\n")); + AddMediaType(&mts.GetNext(pos)); + AddLine(); + } + + m_report.SetSel(0, 0); +} + +LRESULT CMediaTypesDlg::OnExternalClose(WPARAM wParam, LPARAM lParam) { + EndDialog(IDCANCEL); + return LRESULT(); +} diff --git a/src/mpc-hc/MediaTypesDlg.h b/src/mpc-hc/MediaTypesDlg.h index 4f81e06ded0..db0dd3c3208 100644 --- a/src/mpc-hc/MediaTypesDlg.h +++ b/src/mpc-hc/MediaTypesDlg.h @@ -1,64 +1,64 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include -#include "IGraphBuilder2.h" -#include "CMPCThemeResizableDialog.h" -#include "CMPCThemeEdit.h" -#include "CMPCThemeComboBox.h" - - -#define WM_EXTERNALCLOSE WM_APP + 0x100 - -// CMediaTypesDlg dialog - -class CMediaTypesDlg : public CMPCThemeResizableDialog -{ - // DECLARE_DYNAMIC(CMediaTypesDlg) - -private: - CComPtr m_pGBDE; - enum { UNKNOWN, VIDEO, AUDIO } m_type; - GUID m_subtype; - void AddLine(CString str = _T("\n")); - void AddMediaType(const AM_MEDIA_TYPE* pmt); - -public: - CMediaTypesDlg(IGraphBuilderDeadEnd* pGBDE, CWnd* pParent = nullptr); // standard constructor - virtual ~CMediaTypesDlg(); - - // Dialog Data - enum { IDD = IDD_MEDIATYPES_DLG }; - CMPCThemeComboBox m_pins; - CMPCThemeEdit m_report; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - - DECLARE_MESSAGE_MAP() -public: - afx_msg void OnCbnSelchangeCombo1(); - afx_msg LRESULT OnExternalClose(WPARAM wParam, LPARAM lParam); -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include +#include "IGraphBuilder2.h" +#include "CMPCThemeResizableDialog.h" +#include "CMPCThemeEdit.h" +#include "CMPCThemeComboBox.h" + + +#define WM_EXTERNALCLOSE WM_APP + 0x100 + +// CMediaTypesDlg dialog + +class CMediaTypesDlg : public CMPCThemeResizableDialog +{ + // DECLARE_DYNAMIC(CMediaTypesDlg) + +private: + CComPtr m_pGBDE; + enum { UNKNOWN, VIDEO, AUDIO } m_type; + GUID m_subtype; + void AddLine(CString str = _T("\n")); + void AddMediaType(const AM_MEDIA_TYPE* pmt); + +public: + CMediaTypesDlg(IGraphBuilderDeadEnd* pGBDE, CWnd* pParent = nullptr); // standard constructor + virtual ~CMediaTypesDlg(); + + // Dialog Data + enum { IDD = IDD_MEDIATYPES_DLG }; + CMPCThemeComboBox m_pins; + CMPCThemeEdit m_report; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnCbnSelchangeCombo1(); + afx_msg LRESULT OnExternalClose(WPARAM wParam, LPARAM lParam); +}; diff --git a/src/mpc-hc/Monitors.cpp b/src/mpc-hc/Monitors.cpp index 927ad7402fc..93c5ed14e97 100644 --- a/src/mpc-hc/Monitors.cpp +++ b/src/mpc-hc/Monitors.cpp @@ -1,246 +1,246 @@ -/* - * Author: Donald Kackman - * Email: don@itsEngineering.com - * Copyright 2002, Donald Kackman - * - * 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 . - * - */ - -#include "stdafx.h" -#include "Monitors.h" - - -// CMonitors - -CMonitors::CMonitors() -{ - // WARNING : GetSystemMetrics(SM_CMONITORS) return only visible display monitors, and EnumDisplayMonitors - // enumerate visible and pseudo invisible monitors !!! - // m_MonitorArray.SetSize( GetMonitorCount() ); - - ADDMONITOR addMonitor; - addMonitor.pMonitors = &m_MonitorArray; - addMonitor.currentIndex = 0; - - ::EnumDisplayMonitors(nullptr, nullptr, AddMonitorsCallBack, (LPARAM)&addMonitor); -} - -CMonitors::~CMonitors() -{ - for (int i = 0; i < m_MonitorArray.GetSize(); i++) { - delete m_MonitorArray.GetAt(i); - } -} - - -// CMonitors member functions - -BOOL CALLBACK CMonitors::AddMonitorsCallBack(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - LPADDMONITOR pAddMonitor = (LPADDMONITOR)dwData; - - CMonitor* pMonitor = DEBUG_NEW CMonitor; - pMonitor->Attach(hMonitor); - - pAddMonitor->pMonitors->Add(pMonitor); - pAddMonitor->currentIndex++; - - return TRUE; -} -// -// returns the primary monitor -CMonitor CMonitors::GetPrimaryMonitor() -{ - //the primary monitor always has its origin at 0,0 - HMONITOR hMonitor = ::MonitorFromPoint(CPoint(0, 0), MONITOR_DEFAULTTOPRIMARY); - ASSERT(IsMonitor(hMonitor)); - - CMonitor monitor; - monitor.Attach(hMonitor); - ASSERT(monitor.IsPrimaryMonitor()); - - return monitor; -} - -CMonitor CMonitors::GetMonitor(CStringW displayName) -{ - CMonitor monitor; - if (displayName != _T("Current")) { - for (int i = 0; i < GetCount(); i++) { - monitor = GetMonitor(i); - if (!monitor.IsMonitor()) { - continue; - } - CStringW str; - monitor.GetName(str); - if (displayName == str) { - break; - } - monitor.Detach(); - } - } - return monitor; -} - -CMonitor CMonitors::GetMonitor(CStringW displayName, CStringW deviceName) -{ - if (deviceName.IsEmpty()) { - return GetMonitor(displayName); - } - - CMonitor monitor; - if (displayName != _T("Current")) { - int best = -1; - for (int i = 0; i < GetCount(); i++) { - monitor = GetMonitor(i); - if (!monitor.IsMonitor()) { - continue; - } - CStringW displayName2, deviceName2; - monitor.GetNames(displayName2, deviceName2); - if (deviceName == deviceName2) { - if (displayName == displayName2) { - // exact match - best = -1; - break; - } else { - // there might be a better match in case of duplicate device names - if (best == -1) { - best = i; - } - } - } - monitor.Detach(); - } - if (best >= 0) { - monitor = GetMonitor(best); - } - } - return monitor; -} - -// -// is the given handle a valid monitor handle -BOOL CMonitors::IsMonitor(const HMONITOR hMonitor) -{ - if (hMonitor == nullptr) { - return FALSE; - } - - MATCHMONITOR match; - match.target = hMonitor; - match.foundMatch = FALSE; - - ::EnumDisplayMonitors(nullptr, nullptr, FindMatchingMonitorHandle, (LPARAM)&match); - - return match.foundMatch; -} - -//this is the callback method that gets called via IsMontior -BOOL CALLBACK CMonitors::FindMatchingMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -{ - LPMATCHMONITOR pMatch = (LPMATCHMONITOR)dwData; - - if (hMonitor == pMatch->target) { - //found a monitor with the same handle we are looking for - pMatch->foundMatch = TRUE; - return FALSE; //stop enumerating - } - - //haven't found a match yet - pMatch->foundMatch = FALSE; - return TRUE; //keep enumerating -} - -BOOL CMonitors::AllMonitorsShareDisplayFormat() -{ - return ::GetSystemMetrics(SM_SAMEDISPLAYFORMAT); -} - -// -// the number of monitors on the system -int CMonitors::GetMonitorCount() -{ - return ::GetSystemMetrics(SM_CMONITORS); -} - -CMonitor CMonitors::GetMonitor(const int index) const -{ - ASSERT(index >= 0 && index < m_MonitorArray.GetCount()); - - CMonitor* pMonitor = static_cast(m_MonitorArray.GetAt(index)); - - return *pMonitor; -} - -// -// returns the rectangle that is the union of all active monitors -void CMonitors::GetVirtualDesktopRect(LPRECT lprc) -{ - ::SetRect(lprc, - ::GetSystemMetrics(SM_XVIRTUALSCREEN), - ::GetSystemMetrics(SM_YVIRTUALSCREEN), - ::GetSystemMetrics(SM_CXVIRTUALSCREEN), - ::GetSystemMetrics(SM_CYVIRTUALSCREEN)); - -} - -// -// these methods determine whether the given item is -// visible on any monitor -BOOL CMonitors::IsOnScreen(const LPRECT lprc) -{ - return ::MonitorFromRect(lprc, MONITOR_DEFAULTTONULL) != nullptr; -} - -BOOL CMonitors::IsOnScreen(const POINT& pt) -{ - return ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) != nullptr; -} - -BOOL CMonitors::IsOnScreen(const CWnd* pWnd) -{ - return ::MonitorFromWindow(pWnd->GetSafeHwnd(), MONITOR_DEFAULTTONULL) != nullptr; -} - -CMonitor CMonitors::GetNearestMonitor(const LPRECT lprc) -{ - CMonitor monitor; - monitor.Attach(::MonitorFromRect(lprc, MONITOR_DEFAULTTONEAREST)); - - return monitor; - -} - -CMonitor CMonitors::GetNearestMonitor(const POINT& pt) -{ - CMonitor monitor; - monitor.Attach(::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST)); - - return monitor; -} - -CMonitor CMonitors::GetNearestMonitor(const CWnd* pWnd) -{ - ASSERT(pWnd); - ASSERT(::IsWindow(pWnd->m_hWnd)); - - CMonitor monitor; - monitor.Attach(::MonitorFromWindow(pWnd->GetSafeHwnd(), MONITOR_DEFAULTTONEAREST)); - - return monitor; -} +/* + * Author: Donald Kackman + * Email: don@itsEngineering.com + * Copyright 2002, Donald Kackman + * + * 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 . + * + */ + +#include "stdafx.h" +#include "Monitors.h" + + +// CMonitors + +CMonitors::CMonitors() +{ + // WARNING : GetSystemMetrics(SM_CMONITORS) return only visible display monitors, and EnumDisplayMonitors + // enumerate visible and pseudo invisible monitors !!! + // m_MonitorArray.SetSize( GetMonitorCount() ); + + ADDMONITOR addMonitor; + addMonitor.pMonitors = &m_MonitorArray; + addMonitor.currentIndex = 0; + + ::EnumDisplayMonitors(nullptr, nullptr, AddMonitorsCallBack, (LPARAM)&addMonitor); +} + +CMonitors::~CMonitors() +{ + for (int i = 0; i < m_MonitorArray.GetSize(); i++) { + delete m_MonitorArray.GetAt(i); + } +} + + +// CMonitors member functions + +BOOL CALLBACK CMonitors::AddMonitorsCallBack(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + LPADDMONITOR pAddMonitor = (LPADDMONITOR)dwData; + + CMonitor* pMonitor = DEBUG_NEW CMonitor; + pMonitor->Attach(hMonitor); + + pAddMonitor->pMonitors->Add(pMonitor); + pAddMonitor->currentIndex++; + + return TRUE; +} +// +// returns the primary monitor +CMonitor CMonitors::GetPrimaryMonitor() +{ + //the primary monitor always has its origin at 0,0 + HMONITOR hMonitor = ::MonitorFromPoint(CPoint(0, 0), MONITOR_DEFAULTTOPRIMARY); + ASSERT(IsMonitor(hMonitor)); + + CMonitor monitor; + monitor.Attach(hMonitor); + ASSERT(monitor.IsPrimaryMonitor()); + + return monitor; +} + +CMonitor CMonitors::GetMonitor(CStringW displayName) +{ + CMonitor monitor; + if (displayName != _T("Current")) { + for (int i = 0; i < GetCount(); i++) { + monitor = GetMonitor(i); + if (!monitor.IsMonitor()) { + continue; + } + CStringW str; + monitor.GetName(str); + if (displayName == str) { + break; + } + monitor.Detach(); + } + } + return monitor; +} + +CMonitor CMonitors::GetMonitor(CStringW displayName, CStringW deviceName) +{ + if (deviceName.IsEmpty()) { + return GetMonitor(displayName); + } + + CMonitor monitor; + if (displayName != _T("Current")) { + int best = -1; + for (int i = 0; i < GetCount(); i++) { + monitor = GetMonitor(i); + if (!monitor.IsMonitor()) { + continue; + } + CStringW displayName2, deviceName2; + monitor.GetNames(displayName2, deviceName2); + if (deviceName == deviceName2) { + if (displayName == displayName2) { + // exact match + best = -1; + break; + } else { + // there might be a better match in case of duplicate device names + if (best == -1) { + best = i; + } + } + } + monitor.Detach(); + } + if (best >= 0) { + monitor = GetMonitor(best); + } + } + return monitor; +} + +// +// is the given handle a valid monitor handle +BOOL CMonitors::IsMonitor(const HMONITOR hMonitor) +{ + if (hMonitor == nullptr) { + return FALSE; + } + + MATCHMONITOR match; + match.target = hMonitor; + match.foundMatch = FALSE; + + ::EnumDisplayMonitors(nullptr, nullptr, FindMatchingMonitorHandle, (LPARAM)&match); + + return match.foundMatch; +} + +//this is the callback method that gets called via IsMontior +BOOL CALLBACK CMonitors::FindMatchingMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) +{ + LPMATCHMONITOR pMatch = (LPMATCHMONITOR)dwData; + + if (hMonitor == pMatch->target) { + //found a monitor with the same handle we are looking for + pMatch->foundMatch = TRUE; + return FALSE; //stop enumerating + } + + //haven't found a match yet + pMatch->foundMatch = FALSE; + return TRUE; //keep enumerating +} + +BOOL CMonitors::AllMonitorsShareDisplayFormat() +{ + return ::GetSystemMetrics(SM_SAMEDISPLAYFORMAT); +} + +// +// the number of monitors on the system +int CMonitors::GetMonitorCount() +{ + return ::GetSystemMetrics(SM_CMONITORS); +} + +CMonitor CMonitors::GetMonitor(const int index) const +{ + ASSERT(index >= 0 && index < m_MonitorArray.GetCount()); + + CMonitor* pMonitor = static_cast(m_MonitorArray.GetAt(index)); + + return *pMonitor; +} + +// +// returns the rectangle that is the union of all active monitors +void CMonitors::GetVirtualDesktopRect(LPRECT lprc) +{ + ::SetRect(lprc, + ::GetSystemMetrics(SM_XVIRTUALSCREEN), + ::GetSystemMetrics(SM_YVIRTUALSCREEN), + ::GetSystemMetrics(SM_CXVIRTUALSCREEN), + ::GetSystemMetrics(SM_CYVIRTUALSCREEN)); + +} + +// +// these methods determine whether the given item is +// visible on any monitor +BOOL CMonitors::IsOnScreen(const LPRECT lprc) +{ + return ::MonitorFromRect(lprc, MONITOR_DEFAULTTONULL) != nullptr; +} + +BOOL CMonitors::IsOnScreen(const POINT& pt) +{ + return ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) != nullptr; +} + +BOOL CMonitors::IsOnScreen(const CWnd* pWnd) +{ + return ::MonitorFromWindow(pWnd->GetSafeHwnd(), MONITOR_DEFAULTTONULL) != nullptr; +} + +CMonitor CMonitors::GetNearestMonitor(const LPRECT lprc) +{ + CMonitor monitor; + monitor.Attach(::MonitorFromRect(lprc, MONITOR_DEFAULTTONEAREST)); + + return monitor; + +} + +CMonitor CMonitors::GetNearestMonitor(const POINT& pt) +{ + CMonitor monitor; + monitor.Attach(::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST)); + + return monitor; +} + +CMonitor CMonitors::GetNearestMonitor(const CWnd* pWnd) +{ + ASSERT(pWnd); + ASSERT(::IsWindow(pWnd->m_hWnd)); + + CMonitor monitor; + monitor.Attach(::MonitorFromWindow(pWnd->GetSafeHwnd(), MONITOR_DEFAULTTONEAREST)); + + return monitor; +} diff --git a/src/mpc-hc/Monitors.h b/src/mpc-hc/Monitors.h index f374853d37e..7a69af5c010 100644 --- a/src/mpc-hc/Monitors.h +++ b/src/mpc-hc/Monitors.h @@ -1,90 +1,90 @@ -/* - * Author: Donald Kackman - * Email: don@itsEngineering.com - * Copyright 2002, Donald Kackman - * - * 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 . - * - */ - -#pragma once - -#include "MultiMonitor.h" - -// CMonitors command target - -class CMonitors : public CObject -{ -public: - CMonitors(); - virtual ~CMonitors(); - - CMonitor GetMonitor(const int index) const; - - - int GetCount() const { - return (int)m_MonitorArray.GetCount(); - } - - //static members - static CMonitor GetNearestMonitor(const LPRECT lprc); - static CMonitor GetNearestMonitor(const POINT& pt); - static CMonitor GetNearestMonitor(const CWnd* pWnd); - - static BOOL IsOnScreen(const POINT& pt); - static BOOL IsOnScreen(const CWnd* pWnd); - static BOOL IsOnScreen(const LPRECT lprc); - - static void GetVirtualDesktopRect(LPRECT lprc); - - static BOOL IsMonitor(const HMONITOR hMonitor); - - static CMonitor GetPrimaryMonitor(); - CMonitor GetMonitor(CStringW displayName); - CMonitor GetMonitor(CStringW displayName, CStringW deviceName); - static BOOL AllMonitorsShareDisplayFormat(); - - static int GetMonitorCount(); - -private: - CObArray m_MonitorArray; - - typedef struct tagMATCHMONITOR { - HMONITOR target; - BOOL foundMatch; - } MATCHMONITOR, *LPMATCHMONITOR; - - static BOOL CALLBACK FindMatchingMonitorHandle( - HMONITOR hMonitor, // handle to display monitor - HDC hdcMonitor, // handle to monitor DC - LPRECT lprcMonitor, // monitor intersection rectangle - LPARAM dwData // data - ); - - - typedef struct tagADDMONITOR { - CObArray* pMonitors; - int currentIndex; - } ADDMONITOR, *LPADDMONITOR; - - static BOOL CALLBACK AddMonitorsCallBack( - HMONITOR hMonitor, // handle to display monitor - HDC hdcMonitor, // handle to monitor DC - LPRECT lprcMonitor, // monitor intersection rectangle - LPARAM dwData // data - ); - -}; +/* + * Author: Donald Kackman + * Email: don@itsEngineering.com + * Copyright 2002, Donald Kackman + * + * 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 . + * + */ + +#pragma once + +#include "MultiMonitor.h" + +// CMonitors command target + +class CMonitors : public CObject +{ +public: + CMonitors(); + virtual ~CMonitors(); + + CMonitor GetMonitor(const int index) const; + + + int GetCount() const { + return (int)m_MonitorArray.GetCount(); + } + + //static members + static CMonitor GetNearestMonitor(const LPRECT lprc); + static CMonitor GetNearestMonitor(const POINT& pt); + static CMonitor GetNearestMonitor(const CWnd* pWnd); + + static BOOL IsOnScreen(const POINT& pt); + static BOOL IsOnScreen(const CWnd* pWnd); + static BOOL IsOnScreen(const LPRECT lprc); + + static void GetVirtualDesktopRect(LPRECT lprc); + + static BOOL IsMonitor(const HMONITOR hMonitor); + + static CMonitor GetPrimaryMonitor(); + CMonitor GetMonitor(CStringW displayName); + CMonitor GetMonitor(CStringW displayName, CStringW deviceName); + static BOOL AllMonitorsShareDisplayFormat(); + + static int GetMonitorCount(); + +private: + CObArray m_MonitorArray; + + typedef struct tagMATCHMONITOR { + HMONITOR target; + BOOL foundMatch; + } MATCHMONITOR, *LPMATCHMONITOR; + + static BOOL CALLBACK FindMatchingMonitorHandle( + HMONITOR hMonitor, // handle to display monitor + HDC hdcMonitor, // handle to monitor DC + LPRECT lprcMonitor, // monitor intersection rectangle + LPARAM dwData // data + ); + + + typedef struct tagADDMONITOR { + CObArray* pMonitors; + int currentIndex; + } ADDMONITOR, *LPADDMONITOR; + + static BOOL CALLBACK AddMonitorsCallBack( + HMONITOR hMonitor, // handle to display monitor + HDC hdcMonitor, // handle to monitor DC + LPRECT lprcMonitor, // monitor intersection rectangle + LPARAM dwData // data + ); + +}; diff --git a/src/mpc-hc/MpcApi.h b/src/mpc-hc/MpcApi.h index 4adb929c4a9..4b4b0e917a7 100644 --- a/src/mpc-hc/MpcApi.h +++ b/src/mpc-hc/MpcApi.h @@ -1,286 +1,286 @@ -/* - * (C) 2006-2015 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 . - * - */ - - -/* -This file defines commands used for "MPC-HC" API. To send commands -to MPC-HC and receive playback notifications, first launch MPC-HC with the /slave command line -argument followed by a HWnd handle used to receive notification: - -..\bin\mpc-hc /slave 125421 - -After startup, MPC-HC sends a WM_COPYDATA message to host with COPYDATASTRUCT struct filled with: - - dwData : CMD_CONNECT - - lpData : Unicode string containing MPC-HC's main window handle - -To control MPC-HC, send WM_COPYDATA messages to Hwnd provided on connection. All messages should be -formatted as null-terminated Unicode strings. For commands or notifications with multiple parameters, -values are separated by |. -If a string contains a |, it will be escaped with a \ so a \| is not a separator. - -Ex: When a file is opened, MPC-HC sends to host the "now playing" notification: - - dwData : CMD_NOWPLAYING - - lpData : title|author|description|filename|duration - -Ex: When a DVD is playing, use CMD_GETNOWPLAYING to get: - - dwData : CMD_NOWPLAYING - - lpData : dvddomain|titlenumber|numberofchapters|currentchapter|titleduration - dvddomains: DVD - Stopped, DVD - FirstPlay, DVD - RootMenu, DVD - TitleMenu, DVD - Title -*/ - -#pragma once - -typedef enum MPC_LOADSTATE { - MLS_CLOSED, - MLS_LOADING, - MLS_LOADED, - MLS_CLOSING, - MLS_FAILING, -} MPC_LOADSTATE; - - -typedef enum MPC_PLAYSTATE { - PS_PLAY = 0, - PS_PAUSE = 1, - PS_STOP = 2, - PS_UNUSED = 3 -} MPC_PLAYSTATE; - - -struct MPC_OSDDATA { - int nMsgPos; // screen position constant (see OSD_MESSAGEPOS constants) - int nDurationMS; // duration in milliseconds - TCHAR strMsg[128]; // message to display in OSD -}; - -// MPC_OSDDATA. nMsgPos constants (for host side programming): -/* -typedef enum { - OSD_NOMESSAGE, - OSD_TOPLEFT, - OSD_TOPRIGHT -} OSD_MESSAGEPOS; -*/ - - -typedef enum MPCAPI_COMMAND : - unsigned int { - // ==== Commands from MPC-HC to host - - // Send after connection - // Parameter 1: MPC-HC window handle (command should be sent to this HWnd) - CMD_CONNECT = 0x50000000, - - // Send when opening or closing file - // Parameter 1: current state (see MPC_LOADSTATE enum) - CMD_STATE = 0x50000001, - - // Send when playing, pausing or closing file - // Parameter 1: current play mode (see MPC_PLAYSTATE enum) - CMD_PLAYMODE = 0x50000002, - - // Send after opening a new file - // Parameter 1: title - // Parameter 2: author - // Parameter 3: description - // Parameter 4: complete filename (path included) - // Parameter 5: duration in seconds - CMD_NOWPLAYING = 0x50000003, - - // List of subtitle tracks - // Parameter 1: Subtitle track name 0 - // Parameter 2: Subtitle track name 1 - // ... - // Parameter n: Active subtitle track, -1 if subtitles are disabled - // - // if no subtitle track present, returns -1 - // if no file loaded, returns -2 - CMD_LISTSUBTITLETRACKS = 0x50000004, - - // List of audio tracks - // Parameter 1: Audio track name 0 - // Parameter 2: Audio track name 1 - // ... - // Parameter n: Active audio track - // - // if no audio track is present, returns -1 - // if no file is loaded, returns -2 - CMD_LISTAUDIOTRACKS = 0x50000005, - - // Send index of currently selected audio track - CMD_CURRENTAUDIOTRACK = 0x5000000C, - - // Send index of currently selected subtitle track - CMD_CURRENTSUBTITLETRACK = 0x5000000D, - - // Send current playback position in response - // of CMD_GETCURRENTPOSITION. - // Parameter 1: current position in seconds - CMD_CURRENTPOSITION = 0x50000007, - - // Send the current playback position after a jump. - // (Automatically sent after a seek event). - // Parameter 1: new playback position (in seconds). - CMD_NOTIFYSEEK = 0x50000008, - - // Notify the end of current playback - // (Automatically sent). - // Parameter 1: none. - CMD_NOTIFYENDOFSTREAM = 0x50000009, - - // Send version str - // Parameter 1: MPC-HC's version - CMD_VERSION = 0x5000000A, - - // List of files in the playlist - // Parameter 1: file path 0 - // Parameter 2: file path 1 - // ... - // Parameter n: active file, -1 if no active file - CMD_PLAYLIST = 0x50000006, - - // Send information about MPC-HC closing - CMD_DISCONNECT = 0x5000000B, - - // ==== Commands from host to MPC-HC - - // Open new file - // Parameter 1: file path - CMD_OPENFILE = 0xA0000000, - - // Stop playback, but keep file / playlist - CMD_STOP = 0xA0000001, - - // Stop playback and close file / playlist - CMD_CLOSEFILE = 0xA0000002, - - // Pause or restart playback - CMD_PLAYPAUSE = 0xA0000003, - - // Unpause playback - CMD_PLAY = 0xA0000004, - - // Pause playback - CMD_PAUSE = 0xA0000005, - - // Add a new file to playlist (did not start playing) - // Parameter 1: file path - CMD_ADDTOPLAYLIST = 0xA0001000, - - // Remove all files from playlist - CMD_CLEARPLAYLIST = 0xA0001001, - - // Start playing playlist - CMD_STARTPLAYLIST = 0xA0001002, - - CMD_REMOVEFROMPLAYLIST = 0xA0001003, // TODO - - // Cue current file to specific position - // Parameter 1: new position in seconds - CMD_SETPOSITION = 0xA0002000, - - // Set the audio delay - // Parameter 1: new audio delay in ms - CMD_SETAUDIODELAY = 0xA0002001, - - // Set the subtitle delay - // Parameter 1: new subtitle delay in ms - CMD_SETSUBTITLEDELAY = 0xA0002002, - - // Set the active file in the playlist - // Parameter 1: index of the active file, -1 for no file selected - // DOESN'T WORK - CMD_SETINDEXPLAYLIST = 0xA0002003, - - // Set the audio track - // Parameter 1: index of the audio track - CMD_SETAUDIOTRACK = 0xA0002004, - - // Set the subtitle track - // Parameter 1: index of the subtitle track, -1 for disabling subtitles - CMD_SETSUBTITLETRACK = 0xA0002005, - - // Ask for a list of the subtitles tracks of the file - // return a CMD_LISTSUBTITLETRACKS - CMD_GETSUBTITLETRACKS = 0xA0003000, - - // Ask for the current playback position, - // see CMD_CURRENTPOSITION. - // Parameter 1: current position in seconds - CMD_GETCURRENTPOSITION = 0xA0003004, - - // Jump forward/backward of N seconds, - // Parameter 1: seconds (negative values for backward) - CMD_JUMPOFNSECONDS = 0xA0003005, - - // Ask slave for version - CMD_GETVERSION = 0xA0003006, - - // Ask for a list of the audio tracks of the file - // return a CMD_LISTAUDIOTRACKS - CMD_GETAUDIOTRACKS = 0xA0003001, - - // Ask for the properties of the current loaded file - // return a CMD_NOWPLAYING - CMD_GETNOWPLAYING = 0xA0003002, - - // Ask for the current playlist - // return a CMD_PLAYLIST - CMD_GETPLAYLIST = 0xA0003003, - - // Ask for the index of the currently selected audio track - // return a CMD_CURRENTAUDIOTRACK - CMD_GETCURRENTAUDIOTRACK = 0xA0003007, - - // Ask for the index of the currently selected subtitle track - // return a CMD_CURRENTSUBTITLETRACK - CMD_GETCURRENTSUBTITLETRACK = 0xA0003008, - - // Toggle FullScreen - CMD_TOGGLEFULLSCREEN = 0xA0004000, - - // Jump forward(medium) - CMD_JUMPFORWARDMED = 0xA0004001, - - // Jump backward(medium) - CMD_JUMPBACKWARDMED = 0xA0004002, - - // Increase Volume - CMD_INCREASEVOLUME = 0xA0004003, - - // Decrease volume - CMD_DECREASEVOLUME = 0xA0004004, - - // Toggle shader - CMD_SHADER_TOGGLE = 0xA0004005, - - // Close App - CMD_CLOSEAPP = 0xA0004006, - - // Set playing rate - CMD_SETSPEED = 0xA0004008, - - // Set Pan & Scan - CMD_SETPANSCAN = 0xA0004009, - - // Show host defined OSD message string - CMD_OSDSHOWMESSAGE = 0xA0005000 - -} MPCAPI_COMMAND; +/* + * (C) 2006-2015 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 . + * + */ + + +/* +This file defines commands used for "MPC-HC" API. To send commands +to MPC-HC and receive playback notifications, first launch MPC-HC with the /slave command line +argument followed by a HWnd handle used to receive notification: + +..\bin\mpc-hc /slave 125421 + +After startup, MPC-HC sends a WM_COPYDATA message to host with COPYDATASTRUCT struct filled with: + - dwData : CMD_CONNECT + - lpData : Unicode string containing MPC-HC's main window handle + +To control MPC-HC, send WM_COPYDATA messages to Hwnd provided on connection. All messages should be +formatted as null-terminated Unicode strings. For commands or notifications with multiple parameters, +values are separated by |. +If a string contains a |, it will be escaped with a \ so a \| is not a separator. + +Ex: When a file is opened, MPC-HC sends to host the "now playing" notification: + - dwData : CMD_NOWPLAYING + - lpData : title|author|description|filename|duration + +Ex: When a DVD is playing, use CMD_GETNOWPLAYING to get: + - dwData : CMD_NOWPLAYING + - lpData : dvddomain|titlenumber|numberofchapters|currentchapter|titleduration + dvddomains: DVD - Stopped, DVD - FirstPlay, DVD - RootMenu, DVD - TitleMenu, DVD - Title +*/ + +#pragma once + +typedef enum MPC_LOADSTATE { + MLS_CLOSED, + MLS_LOADING, + MLS_LOADED, + MLS_CLOSING, + MLS_FAILING, +} MPC_LOADSTATE; + + +typedef enum MPC_PLAYSTATE { + PS_PLAY = 0, + PS_PAUSE = 1, + PS_STOP = 2, + PS_UNUSED = 3 +} MPC_PLAYSTATE; + + +struct MPC_OSDDATA { + int nMsgPos; // screen position constant (see OSD_MESSAGEPOS constants) + int nDurationMS; // duration in milliseconds + TCHAR strMsg[128]; // message to display in OSD +}; + +// MPC_OSDDATA. nMsgPos constants (for host side programming): +/* +typedef enum { + OSD_NOMESSAGE, + OSD_TOPLEFT, + OSD_TOPRIGHT +} OSD_MESSAGEPOS; +*/ + + +typedef enum MPCAPI_COMMAND : + unsigned int { + // ==== Commands from MPC-HC to host + + // Send after connection + // Parameter 1: MPC-HC window handle (command should be sent to this HWnd) + CMD_CONNECT = 0x50000000, + + // Send when opening or closing file + // Parameter 1: current state (see MPC_LOADSTATE enum) + CMD_STATE = 0x50000001, + + // Send when playing, pausing or closing file + // Parameter 1: current play mode (see MPC_PLAYSTATE enum) + CMD_PLAYMODE = 0x50000002, + + // Send after opening a new file + // Parameter 1: title + // Parameter 2: author + // Parameter 3: description + // Parameter 4: complete filename (path included) + // Parameter 5: duration in seconds + CMD_NOWPLAYING = 0x50000003, + + // List of subtitle tracks + // Parameter 1: Subtitle track name 0 + // Parameter 2: Subtitle track name 1 + // ... + // Parameter n: Active subtitle track, -1 if subtitles are disabled + // + // if no subtitle track present, returns -1 + // if no file loaded, returns -2 + CMD_LISTSUBTITLETRACKS = 0x50000004, + + // List of audio tracks + // Parameter 1: Audio track name 0 + // Parameter 2: Audio track name 1 + // ... + // Parameter n: Active audio track + // + // if no audio track is present, returns -1 + // if no file is loaded, returns -2 + CMD_LISTAUDIOTRACKS = 0x50000005, + + // Send index of currently selected audio track + CMD_CURRENTAUDIOTRACK = 0x5000000C, + + // Send index of currently selected subtitle track + CMD_CURRENTSUBTITLETRACK = 0x5000000D, + + // Send current playback position in response + // of CMD_GETCURRENTPOSITION. + // Parameter 1: current position in seconds + CMD_CURRENTPOSITION = 0x50000007, + + // Send the current playback position after a jump. + // (Automatically sent after a seek event). + // Parameter 1: new playback position (in seconds). + CMD_NOTIFYSEEK = 0x50000008, + + // Notify the end of current playback + // (Automatically sent). + // Parameter 1: none. + CMD_NOTIFYENDOFSTREAM = 0x50000009, + + // Send version str + // Parameter 1: MPC-HC's version + CMD_VERSION = 0x5000000A, + + // List of files in the playlist + // Parameter 1: file path 0 + // Parameter 2: file path 1 + // ... + // Parameter n: active file, -1 if no active file + CMD_PLAYLIST = 0x50000006, + + // Send information about MPC-HC closing + CMD_DISCONNECT = 0x5000000B, + + // ==== Commands from host to MPC-HC + + // Open new file + // Parameter 1: file path + CMD_OPENFILE = 0xA0000000, + + // Stop playback, but keep file / playlist + CMD_STOP = 0xA0000001, + + // Stop playback and close file / playlist + CMD_CLOSEFILE = 0xA0000002, + + // Pause or restart playback + CMD_PLAYPAUSE = 0xA0000003, + + // Unpause playback + CMD_PLAY = 0xA0000004, + + // Pause playback + CMD_PAUSE = 0xA0000005, + + // Add a new file to playlist (did not start playing) + // Parameter 1: file path + CMD_ADDTOPLAYLIST = 0xA0001000, + + // Remove all files from playlist + CMD_CLEARPLAYLIST = 0xA0001001, + + // Start playing playlist + CMD_STARTPLAYLIST = 0xA0001002, + + CMD_REMOVEFROMPLAYLIST = 0xA0001003, // TODO + + // Cue current file to specific position + // Parameter 1: new position in seconds + CMD_SETPOSITION = 0xA0002000, + + // Set the audio delay + // Parameter 1: new audio delay in ms + CMD_SETAUDIODELAY = 0xA0002001, + + // Set the subtitle delay + // Parameter 1: new subtitle delay in ms + CMD_SETSUBTITLEDELAY = 0xA0002002, + + // Set the active file in the playlist + // Parameter 1: index of the active file, -1 for no file selected + // DOESN'T WORK + CMD_SETINDEXPLAYLIST = 0xA0002003, + + // Set the audio track + // Parameter 1: index of the audio track + CMD_SETAUDIOTRACK = 0xA0002004, + + // Set the subtitle track + // Parameter 1: index of the subtitle track, -1 for disabling subtitles + CMD_SETSUBTITLETRACK = 0xA0002005, + + // Ask for a list of the subtitles tracks of the file + // return a CMD_LISTSUBTITLETRACKS + CMD_GETSUBTITLETRACKS = 0xA0003000, + + // Ask for the current playback position, + // see CMD_CURRENTPOSITION. + // Parameter 1: current position in seconds + CMD_GETCURRENTPOSITION = 0xA0003004, + + // Jump forward/backward of N seconds, + // Parameter 1: seconds (negative values for backward) + CMD_JUMPOFNSECONDS = 0xA0003005, + + // Ask slave for version + CMD_GETVERSION = 0xA0003006, + + // Ask for a list of the audio tracks of the file + // return a CMD_LISTAUDIOTRACKS + CMD_GETAUDIOTRACKS = 0xA0003001, + + // Ask for the properties of the current loaded file + // return a CMD_NOWPLAYING + CMD_GETNOWPLAYING = 0xA0003002, + + // Ask for the current playlist + // return a CMD_PLAYLIST + CMD_GETPLAYLIST = 0xA0003003, + + // Ask for the index of the currently selected audio track + // return a CMD_CURRENTAUDIOTRACK + CMD_GETCURRENTAUDIOTRACK = 0xA0003007, + + // Ask for the index of the currently selected subtitle track + // return a CMD_CURRENTSUBTITLETRACK + CMD_GETCURRENTSUBTITLETRACK = 0xA0003008, + + // Toggle FullScreen + CMD_TOGGLEFULLSCREEN = 0xA0004000, + + // Jump forward(medium) + CMD_JUMPFORWARDMED = 0xA0004001, + + // Jump backward(medium) + CMD_JUMPBACKWARDMED = 0xA0004002, + + // Increase Volume + CMD_INCREASEVOLUME = 0xA0004003, + + // Decrease volume + CMD_DECREASEVOLUME = 0xA0004004, + + // Toggle shader + CMD_SHADER_TOGGLE = 0xA0004005, + + // Close App + CMD_CLOSEAPP = 0xA0004006, + + // Set playing rate + CMD_SETSPEED = 0xA0004008, + + // Set Pan & Scan + CMD_SETPANSCAN = 0xA0004009, + + // Show host defined OSD message string + CMD_OSDSHOWMESSAGE = 0xA0005000 + +} MPCAPI_COMMAND; diff --git a/src/mpc-hc/Mpeg2SectionData.cpp b/src/mpc-hc/Mpeg2SectionData.cpp index 777a05ebb03..0d1f8946432 100644 --- a/src/mpc-hc/Mpeg2SectionData.cpp +++ b/src/mpc-hc/Mpeg2SectionData.cpp @@ -1,879 +1,879 @@ -/* - * (C) 2009-2017 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 . - * - */ - -#include "stdafx.h" -#include "BaseClasses/streams.h" -#include - -#include "GolombBuffer.h" -#include "Mpeg2SectionData.h" -#include "FreeviewEPGDecode.h" -#include "resource.h" -#include "Logger.h" - -#define BeginEnumDescriptors(gb, nType, nLength) \ -{ \ - BYTE DescBuffer[256]; \ - size_t nLimit = (size_t)gb.BitRead(12) + gb.GetPos(); \ - while (gb.GetPos() < nLimit) { \ - MPEG2_DESCRIPTOR nType = (MPEG2_DESCRIPTOR)gb.BitRead(8); \ - WORD nLength = (WORD)gb.BitRead(8); - -#define SkipDescriptor(gb, nType, nLength) \ - gb.ReadBuffer(DescBuffer, nLength); \ - BDA_LOG(_T("Skipped descriptor : 0x%02x"), nType); \ - UNREFERENCED_PARAMETER(nType); - -#define EndEnumDescriptors }} - -#define BeginEnumDescriptorsATSC(gb, nType, nLength, bits) \ -{ \ - BYTE DescBuffer[256]; \ - size_t nLimit = (size_t)gb.BitRead(bits) + gb.GetPos(); \ - while (gb.GetPos() < nLimit) { \ - MPEG2_DESCRIPTOR nType = (MPEG2_DESCRIPTOR)gb.BitRead(8); \ - WORD nLength = (WORD)gb.BitRead(8); - - -void UTF16BE2LE(BYTE* in, int len) { - for (int i = 0; i < len; i+=2) { - BYTE in0 = in[i]; - in[i] = in[i+1]; - in[i+1] = in0; - } - in[len] = 0; - in[len + 1] = 0; -} - -CMpeg2DataParser::CMpeg2DataParser(IBaseFilter* pFilter) -{ - m_pData = pFilter; - - ZeroMemory(&m_Filter, sizeof(m_Filter)); - m_Filter.bVersionNumber = 1; - m_Filter.wFilterSize = MPEG2_FILTER_VERSION_1_SIZE; - m_Filter.fSpecifySectionNumber = TRUE; -} - -CStringW CMpeg2DataParser::ConvertString(BYTE* pBuffer, size_t uLength) -{ - static const UINT16 codepages[0x20] = { - 20269, // 00 - Default ISO/IEC 6937 - 28595, // 01 - ISO 8859-5 Cyrillic - 28596, // 02 - ISO 8859-6 Arabic - 28597, // 03 - ISO 8859-7 Greek - 28598, // 04 - ISO 8859-8 Hebrew - 28599, // 05 - ISO 8859-9 Latin 5 - 28591, // 06 - ??? - ISO/IEC 8859-10 - Latin alphabet No. 6 - 28591, // 07 - ??? - ISO/IEC 8859-11 - Latin/Thai (draft only) - 28591, // 08 - reserved - 28603, // 09 - ISO 8859-13 - Estonian - 28591, // 0a - ??? - ISO/IEC 8859-14 - Latin alphabet No. 8 (Celtic) - 28605, // 0b - ISO 8859-15 Latin 9 - 28591, // 0c - reserved - 28591, // 0d - reserved - 28591, // 0e - reserved - 28591, // 0f - reserved - 0, // 10 - See codepages10 array - 28591, // 11 - ??? - ISO/IEC 10646 - Basic Multilingual Plane (BMP) - 28591, // 12 - ??? - KSX1001-2004 - Korean Character Set - 20936, // 13 - Chinese Simplified (GB2312-80) - 950, // 14 - Chinese Traditional (Big5) - 65001, // 15 - UTF-8 encoding of ISO/IEC 10646 - Basic Multilingual Plane (BMP) - 28591, // 16 - reserved - 28591, // 17 - reserved - 28591, // 18 - reserved - 28591, // 19 - reserved - 28591, // 1a - reserved - 28591, // 1b - reserved - 28591, // 1c - reserved - 28591, // 1d - reserved - 28591, // 1e - reserved - 28591 // 1f - TODO! - }; - - static const UINT16 codepages10[0x10] = { - 28591, // 00 - reserved - 28591, // 01 - ISO 8859-1 Western European - 28592, // 02 - ISO 8859-2 Central European - 28593, // 03 - ISO 8859-3 Latin 3 - 28594, // 04 - ISO 8859-4 Baltic - 28595, // 05 - ISO 8859-5 Cyrillic - 28596, // 06 - ISO 8859-6 Arabic - 28597, // 07 - ISO 8859-7 Greek - 28598, // 08 - ISO 8859-8 Hebrew - 28599, // 09 - ISO 8859-9 Turkish - 28591, // 0a - ??? - ISO/IEC 8859-10 - 28591, // 0b - ??? - ISO/IEC 8859-11 - 28591, // 0c - ??? - ISO/IEC 8859-12 - 28603, // 0d - ISO 8859-13 Estonian - 28591, // 0e - ??? - ISO/IEC 8859-14 - 28605, // 0f - ISO 8859-15 Latin 9 - - // 0x10 to 0xFF - reserved for future use - }; - - CStringW strResult; - if (uLength > 0) { - UINT cp = CP_ACP; - int nDestSize; - - if (pBuffer[0] == 0x10) { - pBuffer++; - uLength--; - if (pBuffer[0] == 0x00) { - cp = codepages10[pBuffer[1]]; - } else { // if (pBuffer[0] > 0x00) - // reserved for future use, use default codepage - cp = codepages[0]; - } - pBuffer += 2; - uLength -= 2; - } else if (pBuffer[0] < 0x20) { - cp = codepages[pBuffer[0]]; - pBuffer++; - uLength--; - } else { // No code page indication, use the default - cp = codepages[0]; - } - - // Work around a bug in MS MultiByteToWideChar with ISO/IEC 6937 and take care of the Euro symbol special case (step 1/2)... - CArray euroSymbolPos; - if (cp == 20269) { - BYTE tmp; - for (size_t i = 0; i < uLength - 1; i++) { - if (pBuffer[i] >= 0xC1 && pBuffer[i] <= 0xCF && pBuffer[i] != 0xC9 && pBuffer[i] != 0xCC) { - // Swap the current char with the next one - tmp = pBuffer[i]; - pBuffer[i] = pBuffer[i + 1]; - pBuffer[++i] = tmp; - } else if (pBuffer[i] == 0xA4) { // was added as 0xA4 in the DVB spec - euroSymbolPos.Add(i); - } - } - // Handle last symbol if it's a - if (pBuffer[uLength - 1] == 0xA4) { - euroSymbolPos.Add(uLength - 1); - } - } - - nDestSize = MultiByteToWideChar(cp, MB_PRECOMPOSED, (LPCSTR)pBuffer, (int)uLength, nullptr, 0); - if (nDestSize > 0) { - LPWSTR strResultBuff = strResult.GetBuffer(nDestSize); - MultiByteToWideChar(cp, MB_PRECOMPOSED, (LPCSTR)pBuffer, (int)uLength, strResultBuff, nDestSize); - - // Work around a bug in MS MultiByteToWideChar with ISO/IEC 6937 and take care of the Euro symbol special case (step 2/2)... - if (cp == 20269) { - for (size_t i = 0, len = (size_t)nDestSize; i < len; i++) { - switch (strResultBuff[i]) { - case 0x60: // grave accent - strResultBuff[i] = 0x0300; - break; - case 0xb4: // acute accent - strResultBuff[i] = 0x0301; - break; - case 0x5e: // circumflex accent - strResultBuff[i] = 0x0302; - break; - case 0x7e: // tilde - strResultBuff[i] = 0x0303; - break; - case 0xaf: // macron - strResultBuff[i] = 0x0304; - break; - case 0xf8f8: // dot - strResultBuff[i] = 0x0307; - break; - } - } - - for (INT_PTR i = 0, len = euroSymbolPos.GetCount(); i < len; i++) { - strResultBuff[euroSymbolPos[i]] = _T(''); - } - } - - // Some strings seems to be null-terminated, we need to take that into account. - while (nDestSize > 0 && strResultBuff[nDestSize - 1] == L'\0') { - nDestSize--; - } - - strResult.ReleaseBuffer(nDestSize); - } - } - - return strResult; -} - -BDA_STREAM_TYPE CMpeg2DataParser::ConvertToDVBType(PES_STREAM_TYPE nType) -{ - switch (nType) { - case VIDEO_STREAM_MPEG1: - case VIDEO_STREAM_MPEG2: - return BDA_MPV; - case AUDIO_STREAM_MPEG1: - case AUDIO_STREAM_MPEG2: - return BDA_MPA; - case VIDEO_STREAM_H264: - return BDA_H264; - case VIDEO_STREAM_HEVC: - return BDA_HEVC; - case AUDIO_STREAM_AC3: - return BDA_AC3; - case AUDIO_STREAM_AC3_PLUS: - return BDA_EAC3; - case AUDIO_STREAM_AAC: - return BDA_ADTS; - case AUDIO_STREAM_AAC_LATM: - return BDA_LATM; - case SUBTITLE_STREAM: - return BDA_SUBTITLE; - } - - return BDA_UNKNOWN; -} - -HRESULT CMpeg2DataParser::ParseSIHeader(CGolombBuffer& gb, DVB_SI SIType, WORD& wSectionLength, WORD& wTSID) -{ - if (gb.BitRead(8) != SIType) { - return ERROR_INVALID_DATA; // table_id - } - gb.BitRead(1); // section_syntax_indicator - gb.BitRead(1); // reserved_future_use - gb.BitRead(2); // reserved - wSectionLength = (WORD)gb.BitRead(12); // section_length - wTSID = (WORD)gb.BitRead(16); // transport_stream_id - gb.BitRead(2); // reserved - gb.BitRead(5); // version_number - gb.BitRead(1); // current_next_indicator - gb.BitRead(8); // section_number - gb.BitRead(8); // last_section_number - - return S_OK; -} - -HRESULT CMpeg2DataParser::ParseSDT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) -{ - HRESULT hr; - CComPtr pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wONID; - WORD wSectionLength; - WORD serviceType = 0; - - CheckNoLog(m_pData->GetSection(PID_SDT, SI_SDT, &m_Filter, 15000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - // service_description_section() - CheckNoLog(ParseSIHeader(gb, SI_SDT, wSectionLength, wTSID)); - - wONID = (WORD)gb.BitRead(16); // original_network_id - gb.BitRead(8); // reserved_future_use - - while (gb.GetSize() - gb.GetPos() > 4) { - CBDAChannel Channel; - Channel.SetFrequency(ulFrequency); - Channel.SetBandwidth(ulBandwidth); - Channel.SetSymbolRate(ulSymbolRate); - Channel.SetTSID(wTSID); - Channel.SetONID(wONID); - Channel.SetSID((ULONG)gb.BitRead(16)); // service_id uimsbf - gb.BitRead(6); // reserved_future_use bslbf - gb.BitRead(1); // EIT_schedule_flag bslbf - Channel.SetNowNextFlag(!!gb.BitRead(1)); // EIT_present_following_flag bslbf - gb.BitRead(3); // running_status uimsbf - Channel.SetEncrypted(!!gb.BitRead(1)); // free_CA_mode bslbf - - // Descriptors: - BeginEnumDescriptors(gb, nType, nLength) { - switch (nType) { - case DT_SERVICE: - serviceType = (WORD)gb.BitRead(8); // service_type - nLength = (WORD)gb.BitRead(8); // service_provider_name_length - gb.ReadBuffer(DescBuffer, nLength); // service_provider_name - - nLength = (WORD)gb.BitRead(8); // service_name_length - gb.ReadBuffer(DescBuffer, nLength); // service_name - DescBuffer[nLength] = 0; - Channel.SetName(ConvertString(DescBuffer, nLength)); - BDA_LOG(_T("%-20s %lu"), Channel.GetName(), Channel.GetSID()); - break; - default: - SkipDescriptor(gb, nType, nLength); // descriptor() - break; - } - } - EndEnumDescriptors; - - - if (!Channels.Lookup(Channel.GetSID())) { - switch (serviceType) { - case DIGITAL_TV: - case DIGITAL_RADIO: - case AVC_DIGITAL_RADIO: - case MPEG2_HD_DIGITAL_TV: - case AVC_SD_TV: - case AVC_HD_TV: - case HEVC_TV: - Channels[Channel.GetSID()] = Channel; - break; - default: - BDA_LOG(_T("DVB: Skipping not supported service: %-20s %lu"), Channel.GetName(), Channel.GetSID()); - break; - } - } - } - - return S_OK; -} - -//supports Master Guide Table; see ATSC A/65:2013 -HRESULT CMpeg2DataParser::ParseMGT(enum DVB_SI &vctType) -{ - vctType = SI_undef; - HRESULT hr; - CComPtr pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - - hr = m_pData->GetSection(PID_PSIP, TID_MGT, &m_Filter, 15000, &pSectionList); - CheckNoLog(hr); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - CheckNoLog(ParseSIHeader(gb, TID_MGT, wSectionLength, wTSID)); - gb.BitRead(8); - uint16_t num_tables = gb.BitRead(16); - - for (uint8_t i = 0; i < num_tables; i++) { - uint16_t table_type = gb.BitRead(16); //table_type - - gb.BitRead(3); //reserved - uint16_t table_type_PID = gb.BitRead(13); //table_type_PID - if (table_type_PID == PID_PSIP) { //expect to find TVCT table with PID_PSIP id - if (table_type == TT_TVCT_C0 || table_type == TT_TVCT_C1) { - vctType = (DVB_SI)TID_TVCT; - } else if (table_type == TT_CVCT_C0 || table_type == TT_CVCT_C1) { - vctType = (DVB_SI)TID_CVCT; - } - } - gb.BitRead(3); //reserved - gb.BitRead(5); //table_type_version_number - gb.BitRead(32); //number_bytes - gb.BitRead(4); //reserved - - BeginEnumDescriptorsATSC(gb, nType, nLength, 12) { // for (i=0;i pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - WORD serviceType = 0; - - hr = m_pData->GetSection(PID_PSIP, vctType, &m_Filter, 15000, &pSectionList); - CheckNoLog(hr); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - CheckNoLog(ParseSIHeader(gb, vctType, wSectionLength, wTSID)); - gb.BitRead(8); //protocol_version - uint8_t num_channels = gb.BitRead(8); - - const int SHORT_NAME_LEN = 7*2; - BYTE short_name[SHORT_NAME_LEN+2]; - - for (uint8_t i = 0; i < num_channels; i++) { - gb.ReadBuffer(short_name, SHORT_NAME_LEN); //short_name - UTF16BE2LE(short_name, SHORT_NAME_LEN); - CStringW shortName((wchar_t*)short_name); - gb.BitRead(4); //reserved - uint16_t major_channel_number = gb.BitRead(10); //major_channel_number - uint16_t minor_channel_number = gb.BitRead(10); //minor_channel_number - gb.BitRead(8); //modulation_mode - gb.BitRead(32); //carrier_frequency - uint16_t channel_TSID=gb.BitRead(16); //channel_TSID - uint16_t program_number=gb.BitRead(16); //program_number - gb.BitRead(2); //ETM_location - gb.BitRead(1); //access_controlled - gb.BitRead(1); //hidden - gb.BitRead(2); //TVCT: reserved(1), CVCT: path_select(1) / out_of_band(1) - gb.BitRead(1); //hide_guide - gb.BitRead(3); //reserved - serviceType = gb.BitRead(6); //service_type - uint16_t source_id=gb.BitRead(16); //source_id - gb.BitRead(6); //reserved - BeginEnumDescriptorsATSC(gb, nType, nLength, 10) { // for (i=0;i pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - - CheckNoLog(m_pData->GetSection(PID_PAT, SI_PAT, &m_Filter, 15000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - // program_association_section() - CheckNoLog(ParseSIHeader(gb, SI_PAT, wSectionLength, wTSID)); - while (gb.GetSize() - gb.GetPos() > 4) { - WORD program_number = (WORD)gb.BitRead(16); // program_number - gb.BitRead(3); // reserved - if (program_number == 0) { - gb.BitRead(13); // network_PID - } else { - WORD program_map_PID = (WORD)gb.BitRead(13); // program_map_PID - if (Channels.Lookup(program_number)) { - Channels [program_number].SetPMT(program_map_PID); - ParsePMT(Channels [program_number]); - } - } - } - - return S_OK; -} - -HRESULT CMpeg2DataParser::ParsePMT(CBDAChannel& Channel) -{ - HRESULT hr; - CComPtr pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - - Channel.SetVideoFps(BDA_FPS_NONE); - Channel.SetVideoChroma(BDA_Chroma_NONE); - - CheckNoLog(m_pData->GetSection((PID)Channel.GetPMT(), SI_PMT, &m_Filter, 15000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - // TS_program_map_section() - CheckNoLog(ParseSIHeader(gb, SI_PMT, wSectionLength, wTSID)); - - gb.BitRead(3); // reserved - Channel.SetPCR((ULONG)gb.BitRead(13)); // PCR_PID - gb.BitRead(4); // reserved - BeginEnumDescriptors(gb, nType, nLength) { // for (i=0;i 4) { - PES_STREAM_TYPE pes_stream_type; - BDA_STREAM_TYPE dvb_stream_type; - WORD wPID; - CString strLanguage; - - pes_stream_type = (PES_STREAM_TYPE)gb.BitRead(8); // stream_type - gb.BitRead(3); // reserved - wPID = (WORD)gb.BitRead(13); // elementary_PID - gb.BitRead(4); // reserved - - BeginEnumDescriptors(gb, nType, nLength) { // ES_info_length - switch (nType) { - case DT_ISO_639_LANGUAGE: - gb.ReadBuffer(DescBuffer, nLength); - strLanguage = ConvertString(DescBuffer, 3); - break; - case DT_AC3_AUDIO: - pes_stream_type = AUDIO_STREAM_AC3; - SkipDescriptor(gb, nType, nLength); - break; - case DT_EXTENDED_AC3_AUDIO: - pes_stream_type = AUDIO_STREAM_AC3_PLUS; - SkipDescriptor(gb, nType, nLength); - break; - case DT_AAC_AUDIO: - pes_stream_type = AUDIO_STREAM_AAC_LATM; - SkipDescriptor(gb, nType, nLength); - break; - case DT_SUBTITLING: - gb.ReadBuffer(DescBuffer, nLength); - strLanguage = ConvertString(DescBuffer, 3); - pes_stream_type = SUBTITLE_STREAM; - break; - case DT_VIDEO_STREAM: { - gb.BitRead(1); // multiple_frame_rate_flag - Channel.SetVideoFps((BDA_FPS_TYPE) gb.BitRead(4)); - UINT MPEG_1_only_flag = (UINT) gb.BitRead(1); - gb.BitRead(1); // constrained_parameter_flag - gb.BitRead(1); // still_picture_flag - if (!MPEG_1_only_flag) { - gb.BitRead(8); // profile_and_level_indicator - Channel.SetVideoChroma((BDA_CHROMA_TYPE) gb.BitRead(2)); - gb.BitRead(1); // frame_rate_extension_flag - gb.BitRead(5); // Reserved - } - } - break; - case DT_TARGET_BACKGROUND_GRID: - Channel.SetVideoWidth((ULONG) gb.BitRead(14)); - Channel.SetVideoHeight((ULONG) gb.BitRead(14)); - Channel.SetVideoAR((BDA_AspectRatio_TYPE) gb.BitRead(4)); - break; - default: - SkipDescriptor(gb, nType, nLength); - break; - } - } - EndEnumDescriptors; - if ((dvb_stream_type = ConvertToDVBType(pes_stream_type)) != BDA_UNKNOWN) { - Channel.AddStreamInfo(wPID, dvb_stream_type, pes_stream_type, strLanguage); - } - } - if ((Channel.GetVideoType() == BDA_MPV) && (Channel.GetVideoPID())) { - if (Channel.GetVideoFps() == BDA_FPS_NONE) { - Channel.SetVideoFps(BDA_FPS_25_0); - } - if ((Channel.GetVideoWidth() == 0) && (Channel.GetVideoHeight() == 0)) { - Channel.SetVideoWidth(720); - Channel.SetVideoHeight(576); - } - } else if ((Channel.GetVideoType() == BDA_H264 || Channel.GetVideoType() == BDA_HEVC) && (Channel.GetVideoPID())) { - if (Channel.GetVideoFps() == BDA_FPS_NONE) { - Channel.SetVideoFps(BDA_FPS_25_0); - } - } - - - return S_OK; -} - -HRESULT CMpeg2DataParser::SetTime(CGolombBuffer& gb, EventDescriptor& NowNext) -{ - wchar_t descBuffer[6]; - time_t tNow, tTime; - tm tmTime; - long timezone; - - // init tm structures - time(&tNow); - gmtime_s(&tmTime, &tNow); - _tzset(); - _get_timezone(&timezone); // The difference in seconds between UTC and local time. - - // Start time: - tmTime.tm_hour = (int)(gb.BitRead(4) * 10); - tmTime.tm_hour += (int)gb.BitRead(4); - tmTime.tm_min = (int)(gb.BitRead(4) * 10); - tmTime.tm_min += (int)gb.BitRead(4); - tmTime.tm_sec = (int)(gb.BitRead(4) * 10); - tmTime.tm_sec += (int)gb.BitRead(4); - // Convert to time_t - // mktime() expect tm struct to be local time and since we are feeding it with GMT - // we need to compensate for timezone offset. Note that we don't compensate for DST. - // That is because tm_isdst is set to 0 (GMT) and in this case mktime() won't add any offset. - NowNext.startTime = tTime = mktime(&tmTime) - timezone; - while (tNow < tTime) { - // If current time is less than even start time it is likely that event started the day before. - // We go one day back - NowNext.startTime = tTime -= 86400; - } - - localtime_s(&tmTime, &tTime); - wcsftime(descBuffer, 6, L"%H:%M", &tmTime); - descBuffer[5] = '\0'; - NowNext.strStartTime = descBuffer; - - // Duration: - NowNext.duration = (time_t)(36000 * gb.BitRead(4)); - NowNext.duration += (time_t)(3600 * gb.BitRead(4)); - NowNext.duration += (time_t)(600 * gb.BitRead(4)); - NowNext.duration += (time_t)(60 * gb.BitRead(4)); - NowNext.duration += (time_t)(10 * gb.BitRead(4)); - NowNext.duration += (time_t)gb.BitRead(4); - - tTime += NowNext.duration; - localtime_s(&tmTime, &tTime); - wcsftime(descBuffer, 6, L"%H:%M", &tmTime); - descBuffer[5] = '\0'; - NowNext.strEndTime = descBuffer; - - return S_OK; -} - -HRESULT CMpeg2DataParser::ParseEIT(ULONG ulSID, EventDescriptor& NowNext) -{ - HRESULT hr = S_OK; - DWORD dwLength; - PSECTION data; - ULONG ulGetSID; - EventInformationSection InfoEvent; - NowNext = EventDescriptor(); - - do { - CComPtr pSectionList; - CheckNoLog(m_pData->GetSection(PID_EIT, SI_EIT_act, nullptr, 5000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - InfoEvent.TableID = (UINT8)gb.BitRead(8); - InfoEvent.SectionSyntaxIndicator = (WORD)gb.BitRead(1); - gb.BitRead(3); - InfoEvent.SectionLength = (WORD)gb.BitRead(12); - ulGetSID = (ULONG)gb.BitRead(8); - ulGetSID += 0x100 * (ULONG)gb.BitRead(8); - InfoEvent.ServiceId = ulGetSID; // This is really strange, ServiceID should be uimsbf ??? - if (InfoEvent.ServiceId == ulSID) { - gb.BitRead(2); - InfoEvent.VersionNumber = (UINT8)gb.BitRead(5); - InfoEvent.CurrentNextIndicator = (UINT8)gb.BitRead(1); - if (InfoEvent.CurrentNextIndicator == 1) { - InfoEvent.SectionNumber = (UINT8)gb.BitRead(8); - InfoEvent.LastSectionNumber = (UINT8)gb.BitRead(8); - InfoEvent.TransportStreamID = (WORD)gb.BitRead(16); - InfoEvent.OriginalNetworkID = (WORD)gb.BitRead(16); - InfoEvent.SegmentLastSectionNumber = (UINT8)gb.BitRead(8); - InfoEvent.LastTableID = (UINT8)gb.BitRead(8); - - // Info event - InfoEvent.EventID = (WORD)gb.BitRead(16); - InfoEvent.StartDate = (WORD)gb.BitRead(16); - SetTime(gb, NowNext); - - InfoEvent.RunninStatus = (WORD)gb.BitRead(3); - InfoEvent.FreeCAMode = (WORD)gb.BitRead(1); - if (InfoEvent.RunninStatus == 4) { - UINT8 nLen; - UINT8 itemsLength; - - // Descriptors: - BeginEnumDescriptors(gb, nType, nLength) { - switch (nType) { - case DT_SHORT_EVENT: - gb.BitRead(24); // ISO_639_language_code - - nLen = (UINT8)gb.BitRead(8); // event_name_length - gb.ReadBuffer(DescBuffer, nLen); - if (IsFreeviewEPG(InfoEvent.OriginalNetworkID, DescBuffer, nLen)) { - NowNext.eventName = DecodeFreeviewEPG(DescBuffer, nLen); - } else { - NowNext.eventName = ConvertString(DescBuffer, nLen); - } - - nLen = (UINT8)gb.BitRead(8); // text_length - gb.ReadBuffer(DescBuffer, nLen); - if (IsFreeviewEPG(InfoEvent.OriginalNetworkID, DescBuffer, nLen)) { - NowNext.eventDesc = DecodeFreeviewEPG(DescBuffer, nLen); - } else { - NowNext.eventDesc = ConvertString(DescBuffer, nLen); - } - break; - case DT_EXTENDED_EVENT: - gb.BitRead(4); // descriptor_number - gb.BitRead(4); // last_descriptor_number - gb.BitRead(24); // ISO_639_language_code - - itemsLength = (UINT8)gb.BitRead(8); // length_of_items - while (itemsLength > 0) { - nLen = (UINT8)gb.BitRead(8); // item_description_length - gb.ReadBuffer(DescBuffer, nLen); - CString itemDesc = ConvertString(DescBuffer, nLen); - itemsLength -= nLen + 1; - - nLen = (UINT8)gb.BitRead(8); // item_length - gb.ReadBuffer(DescBuffer, nLen); - CString itemText = ConvertString(DescBuffer, nLen); - itemsLength -= nLen + 1; - NowNext.extendedDescriptorsItems.emplace_back(itemDesc, itemText); - } - - nLen = (UINT8)gb.BitRead(8); // text_length - if (nLen > 0) { - gb.ReadBuffer(DescBuffer, nLen); - NowNext.extendedDescriptorsText += ConvertString(DescBuffer, nLen); - } - break; - case DT_PARENTAL_RATING: { - ASSERT(nLength % 4 == 0); - int rating = -1; - while (nLength >= 4) { - gb.BitRead(24); // ISO 3166 country_code - rating = (int)gb.BitRead(8); // rating - nLength -= 4; - } - if (rating >= 0 && rating <= 0x0f) { - if (rating > 0) { // 0x00 undefined - rating += 3; // 0x01 to 0x0F minimum age = rating + 3 years - } - NowNext.parentalRating = rating; - } - } - break; - case DT_CONTENT: - ASSERT(nLength % 2 == 0); - while (nLength >= 2) { - BYTE content = (BYTE)gb.BitRead(4); // content_nibble_level_1 - gb.BitRead(4); // content_nibble_level_2 - gb.BitRead(8); // user_byte - if (1 <= content && content <= 10) { - if (!NowNext.content.IsEmpty()) { - NowNext.content.Append(_T(", ")); - } - - static UINT contents[] = { - IDS_CONTENT_MOVIE_DRAMA, - IDS_CONTENT_NEWS_CURRENTAFFAIRS, - IDS_CONTENT_SHOW_GAMESHOW, - IDS_CONTENT_SPORTS, - IDS_CONTENT_CHILDREN_YOUTH_PROG, - IDS_CONTENT_MUSIC_BALLET_DANCE, - IDS_CONTENT_MUSIC_ART_CULTURE, - IDS_CONTENT_SOCIAL_POLITICAL_ECO, - IDS_CONTENT_EDUCATION_SCIENCE, - IDS_CONTENT_LEISURE - }; - - NowNext.content.AppendFormat(contents[content - 1]); - } - nLength -= 2; - } - break; - default: - SkipDescriptor(gb, nType, nLength); - break; - } - } - EndEnumDescriptors; - } - } - } - m_Filter.SectionNumber++; - } while ((InfoEvent.ServiceId != ulSID || InfoEvent.RunninStatus != 4) && m_Filter.SectionNumber <= 22); - - if (m_Filter.SectionNumber > 22 || InfoEvent.CurrentNextIndicator != 1) { - NowNext = EventDescriptor(); - hr = E_FAIL; - } - - return hr; -} - -HRESULT CMpeg2DataParser::ParseNIT() -{ - HRESULT hr; - CComPtr pSectionList; - DWORD dwLength; - PSECTION data; - WORD wTSID; - WORD wSectionLength; - - CheckNoLog(m_pData->GetSection(PID_NIT, SI_NIT, &m_Filter, 15000, &pSectionList)); - CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); - - CGolombBuffer gb((BYTE*)data, dwLength); - - // network_information_section() - CheckNoLog(ParseSIHeader(gb, SI_NIT, wSectionLength, wTSID)); - - gb.BitRead(4); // reserved_future_use - BeginEnumDescriptors(gb, nType, nLength) { // for (i=0;i 4) { - WORD transport_stream_id = (WORD)gb.BitRead(16); // transport_stream_id - UNREFERENCED_PARAMETER(transport_stream_id); - WORD original_network_id = (WORD)gb.BitRead(16); // original_network_id - UNREFERENCED_PARAMETER(original_network_id); - gb.BitRead(4); // reserved_future_use - BeginEnumDescriptors(gb, nType, nLength) { - switch (nType) { - case DT_LOGICAL_CHANNEL: - for (int i = 0; i < nLength / 4; i++) { - WORD service_id = (WORD)gb.BitRead(16); - gb.BitRead(6); - WORD logical_channel_number = (WORD)gb.BitRead(10); - if (Channels.Lookup(service_id)) { - Channels[service_id].SetOriginNumber(logical_channel_number); - BDA_LOG(_T("NIT association : %d -> %s"), logical_channel_number, Channels[service_id].ToString().GetString()); - } - } - break; - default: - SkipDescriptor(gb, nType, nLength); - break; - } - } - EndEnumDescriptors; - } - - return S_OK; -} +/* + * (C) 2009-2017 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 . + * + */ + +#include "stdafx.h" +#include "BaseClasses/streams.h" +#include + +#include "GolombBuffer.h" +#include "Mpeg2SectionData.h" +#include "FreeviewEPGDecode.h" +#include "resource.h" +#include "Logger.h" + +#define BeginEnumDescriptors(gb, nType, nLength) \ +{ \ + BYTE DescBuffer[256]; \ + size_t nLimit = (size_t)gb.BitRead(12) + gb.GetPos(); \ + while (gb.GetPos() < nLimit) { \ + MPEG2_DESCRIPTOR nType = (MPEG2_DESCRIPTOR)gb.BitRead(8); \ + WORD nLength = (WORD)gb.BitRead(8); + +#define SkipDescriptor(gb, nType, nLength) \ + gb.ReadBuffer(DescBuffer, nLength); \ + BDA_LOG(_T("Skipped descriptor : 0x%02x"), nType); \ + UNREFERENCED_PARAMETER(nType); + +#define EndEnumDescriptors }} + +#define BeginEnumDescriptorsATSC(gb, nType, nLength, bits) \ +{ \ + BYTE DescBuffer[256]; \ + size_t nLimit = (size_t)gb.BitRead(bits) + gb.GetPos(); \ + while (gb.GetPos() < nLimit) { \ + MPEG2_DESCRIPTOR nType = (MPEG2_DESCRIPTOR)gb.BitRead(8); \ + WORD nLength = (WORD)gb.BitRead(8); + + +void UTF16BE2LE(BYTE* in, int len) { + for (int i = 0; i < len; i+=2) { + BYTE in0 = in[i]; + in[i] = in[i+1]; + in[i+1] = in0; + } + in[len] = 0; + in[len + 1] = 0; +} + +CMpeg2DataParser::CMpeg2DataParser(IBaseFilter* pFilter) +{ + m_pData = pFilter; + + ZeroMemory(&m_Filter, sizeof(m_Filter)); + m_Filter.bVersionNumber = 1; + m_Filter.wFilterSize = MPEG2_FILTER_VERSION_1_SIZE; + m_Filter.fSpecifySectionNumber = TRUE; +} + +CStringW CMpeg2DataParser::ConvertString(BYTE* pBuffer, size_t uLength) +{ + static const UINT16 codepages[0x20] = { + 20269, // 00 - Default ISO/IEC 6937 + 28595, // 01 - ISO 8859-5 Cyrillic + 28596, // 02 - ISO 8859-6 Arabic + 28597, // 03 - ISO 8859-7 Greek + 28598, // 04 - ISO 8859-8 Hebrew + 28599, // 05 - ISO 8859-9 Latin 5 + 28591, // 06 - ??? - ISO/IEC 8859-10 - Latin alphabet No. 6 + 28591, // 07 - ??? - ISO/IEC 8859-11 - Latin/Thai (draft only) + 28591, // 08 - reserved + 28603, // 09 - ISO 8859-13 - Estonian + 28591, // 0a - ??? - ISO/IEC 8859-14 - Latin alphabet No. 8 (Celtic) + 28605, // 0b - ISO 8859-15 Latin 9 + 28591, // 0c - reserved + 28591, // 0d - reserved + 28591, // 0e - reserved + 28591, // 0f - reserved + 0, // 10 - See codepages10 array + 28591, // 11 - ??? - ISO/IEC 10646 - Basic Multilingual Plane (BMP) + 28591, // 12 - ??? - KSX1001-2004 - Korean Character Set + 20936, // 13 - Chinese Simplified (GB2312-80) + 950, // 14 - Chinese Traditional (Big5) + 65001, // 15 - UTF-8 encoding of ISO/IEC 10646 - Basic Multilingual Plane (BMP) + 28591, // 16 - reserved + 28591, // 17 - reserved + 28591, // 18 - reserved + 28591, // 19 - reserved + 28591, // 1a - reserved + 28591, // 1b - reserved + 28591, // 1c - reserved + 28591, // 1d - reserved + 28591, // 1e - reserved + 28591 // 1f - TODO! + }; + + static const UINT16 codepages10[0x10] = { + 28591, // 00 - reserved + 28591, // 01 - ISO 8859-1 Western European + 28592, // 02 - ISO 8859-2 Central European + 28593, // 03 - ISO 8859-3 Latin 3 + 28594, // 04 - ISO 8859-4 Baltic + 28595, // 05 - ISO 8859-5 Cyrillic + 28596, // 06 - ISO 8859-6 Arabic + 28597, // 07 - ISO 8859-7 Greek + 28598, // 08 - ISO 8859-8 Hebrew + 28599, // 09 - ISO 8859-9 Turkish + 28591, // 0a - ??? - ISO/IEC 8859-10 + 28591, // 0b - ??? - ISO/IEC 8859-11 + 28591, // 0c - ??? - ISO/IEC 8859-12 + 28603, // 0d - ISO 8859-13 Estonian + 28591, // 0e - ??? - ISO/IEC 8859-14 + 28605, // 0f - ISO 8859-15 Latin 9 + + // 0x10 to 0xFF - reserved for future use + }; + + CStringW strResult; + if (uLength > 0) { + UINT cp = CP_ACP; + int nDestSize; + + if (pBuffer[0] == 0x10) { + pBuffer++; + uLength--; + if (pBuffer[0] == 0x00) { + cp = codepages10[pBuffer[1]]; + } else { // if (pBuffer[0] > 0x00) + // reserved for future use, use default codepage + cp = codepages[0]; + } + pBuffer += 2; + uLength -= 2; + } else if (pBuffer[0] < 0x20) { + cp = codepages[pBuffer[0]]; + pBuffer++; + uLength--; + } else { // No code page indication, use the default + cp = codepages[0]; + } + + // Work around a bug in MS MultiByteToWideChar with ISO/IEC 6937 and take care of the Euro symbol special case (step 1/2)... + CArray euroSymbolPos; + if (cp == 20269) { + BYTE tmp; + for (size_t i = 0; i < uLength - 1; i++) { + if (pBuffer[i] >= 0xC1 && pBuffer[i] <= 0xCF && pBuffer[i] != 0xC9 && pBuffer[i] != 0xCC) { + // Swap the current char with the next one + tmp = pBuffer[i]; + pBuffer[i] = pBuffer[i + 1]; + pBuffer[++i] = tmp; + } else if (pBuffer[i] == 0xA4) { // was added as 0xA4 in the DVB spec + euroSymbolPos.Add(i); + } + } + // Handle last symbol if it's a + if (pBuffer[uLength - 1] == 0xA4) { + euroSymbolPos.Add(uLength - 1); + } + } + + nDestSize = MultiByteToWideChar(cp, MB_PRECOMPOSED, (LPCSTR)pBuffer, (int)uLength, nullptr, 0); + if (nDestSize > 0) { + LPWSTR strResultBuff = strResult.GetBuffer(nDestSize); + MultiByteToWideChar(cp, MB_PRECOMPOSED, (LPCSTR)pBuffer, (int)uLength, strResultBuff, nDestSize); + + // Work around a bug in MS MultiByteToWideChar with ISO/IEC 6937 and take care of the Euro symbol special case (step 2/2)... + if (cp == 20269) { + for (size_t i = 0, len = (size_t)nDestSize; i < len; i++) { + switch (strResultBuff[i]) { + case 0x60: // grave accent + strResultBuff[i] = 0x0300; + break; + case 0xb4: // acute accent + strResultBuff[i] = 0x0301; + break; + case 0x5e: // circumflex accent + strResultBuff[i] = 0x0302; + break; + case 0x7e: // tilde + strResultBuff[i] = 0x0303; + break; + case 0xaf: // macron + strResultBuff[i] = 0x0304; + break; + case 0xf8f8: // dot + strResultBuff[i] = 0x0307; + break; + } + } + + for (INT_PTR i = 0, len = euroSymbolPos.GetCount(); i < len; i++) { + strResultBuff[euroSymbolPos[i]] = _T(''); + } + } + + // Some strings seems to be null-terminated, we need to take that into account. + while (nDestSize > 0 && strResultBuff[nDestSize - 1] == L'\0') { + nDestSize--; + } + + strResult.ReleaseBuffer(nDestSize); + } + } + + return strResult; +} + +BDA_STREAM_TYPE CMpeg2DataParser::ConvertToDVBType(PES_STREAM_TYPE nType) +{ + switch (nType) { + case VIDEO_STREAM_MPEG1: + case VIDEO_STREAM_MPEG2: + return BDA_MPV; + case AUDIO_STREAM_MPEG1: + case AUDIO_STREAM_MPEG2: + return BDA_MPA; + case VIDEO_STREAM_H264: + return BDA_H264; + case VIDEO_STREAM_HEVC: + return BDA_HEVC; + case AUDIO_STREAM_AC3: + return BDA_AC3; + case AUDIO_STREAM_AC3_PLUS: + return BDA_EAC3; + case AUDIO_STREAM_AAC: + return BDA_ADTS; + case AUDIO_STREAM_AAC_LATM: + return BDA_LATM; + case SUBTITLE_STREAM: + return BDA_SUBTITLE; + } + + return BDA_UNKNOWN; +} + +HRESULT CMpeg2DataParser::ParseSIHeader(CGolombBuffer& gb, DVB_SI SIType, WORD& wSectionLength, WORD& wTSID) +{ + if (gb.BitRead(8) != SIType) { + return ERROR_INVALID_DATA; // table_id + } + gb.BitRead(1); // section_syntax_indicator + gb.BitRead(1); // reserved_future_use + gb.BitRead(2); // reserved + wSectionLength = (WORD)gb.BitRead(12); // section_length + wTSID = (WORD)gb.BitRead(16); // transport_stream_id + gb.BitRead(2); // reserved + gb.BitRead(5); // version_number + gb.BitRead(1); // current_next_indicator + gb.BitRead(8); // section_number + gb.BitRead(8); // last_section_number + + return S_OK; +} + +HRESULT CMpeg2DataParser::ParseSDT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate) +{ + HRESULT hr; + CComPtr pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wONID; + WORD wSectionLength; + WORD serviceType = 0; + + CheckNoLog(m_pData->GetSection(PID_SDT, SI_SDT, &m_Filter, 15000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + // service_description_section() + CheckNoLog(ParseSIHeader(gb, SI_SDT, wSectionLength, wTSID)); + + wONID = (WORD)gb.BitRead(16); // original_network_id + gb.BitRead(8); // reserved_future_use + + while (gb.GetSize() - gb.GetPos() > 4) { + CBDAChannel Channel; + Channel.SetFrequency(ulFrequency); + Channel.SetBandwidth(ulBandwidth); + Channel.SetSymbolRate(ulSymbolRate); + Channel.SetTSID(wTSID); + Channel.SetONID(wONID); + Channel.SetSID((ULONG)gb.BitRead(16)); // service_id uimsbf + gb.BitRead(6); // reserved_future_use bslbf + gb.BitRead(1); // EIT_schedule_flag bslbf + Channel.SetNowNextFlag(!!gb.BitRead(1)); // EIT_present_following_flag bslbf + gb.BitRead(3); // running_status uimsbf + Channel.SetEncrypted(!!gb.BitRead(1)); // free_CA_mode bslbf + + // Descriptors: + BeginEnumDescriptors(gb, nType, nLength) { + switch (nType) { + case DT_SERVICE: + serviceType = (WORD)gb.BitRead(8); // service_type + nLength = (WORD)gb.BitRead(8); // service_provider_name_length + gb.ReadBuffer(DescBuffer, nLength); // service_provider_name + + nLength = (WORD)gb.BitRead(8); // service_name_length + gb.ReadBuffer(DescBuffer, nLength); // service_name + DescBuffer[nLength] = 0; + Channel.SetName(ConvertString(DescBuffer, nLength)); + BDA_LOG(_T("%-20s %lu"), Channel.GetName(), Channel.GetSID()); + break; + default: + SkipDescriptor(gb, nType, nLength); // descriptor() + break; + } + } + EndEnumDescriptors; + + + if (!Channels.Lookup(Channel.GetSID())) { + switch (serviceType) { + case DIGITAL_TV: + case DIGITAL_RADIO: + case AVC_DIGITAL_RADIO: + case MPEG2_HD_DIGITAL_TV: + case AVC_SD_TV: + case AVC_HD_TV: + case HEVC_TV: + Channels[Channel.GetSID()] = Channel; + break; + default: + BDA_LOG(_T("DVB: Skipping not supported service: %-20s %lu"), Channel.GetName(), Channel.GetSID()); + break; + } + } + } + + return S_OK; +} + +//supports Master Guide Table; see ATSC A/65:2013 +HRESULT CMpeg2DataParser::ParseMGT(enum DVB_SI &vctType) +{ + vctType = SI_undef; + HRESULT hr; + CComPtr pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + + hr = m_pData->GetSection(PID_PSIP, TID_MGT, &m_Filter, 15000, &pSectionList); + CheckNoLog(hr); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + CheckNoLog(ParseSIHeader(gb, TID_MGT, wSectionLength, wTSID)); + gb.BitRead(8); + uint16_t num_tables = gb.BitRead(16); + + for (uint8_t i = 0; i < num_tables; i++) { + uint16_t table_type = gb.BitRead(16); //table_type + + gb.BitRead(3); //reserved + uint16_t table_type_PID = gb.BitRead(13); //table_type_PID + if (table_type_PID == PID_PSIP) { //expect to find TVCT table with PID_PSIP id + if (table_type == TT_TVCT_C0 || table_type == TT_TVCT_C1) { + vctType = (DVB_SI)TID_TVCT; + } else if (table_type == TT_CVCT_C0 || table_type == TT_CVCT_C1) { + vctType = (DVB_SI)TID_CVCT; + } + } + gb.BitRead(3); //reserved + gb.BitRead(5); //table_type_version_number + gb.BitRead(32); //number_bytes + gb.BitRead(4); //reserved + + BeginEnumDescriptorsATSC(gb, nType, nLength, 12) { // for (i=0;i pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + WORD serviceType = 0; + + hr = m_pData->GetSection(PID_PSIP, vctType, &m_Filter, 15000, &pSectionList); + CheckNoLog(hr); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + CheckNoLog(ParseSIHeader(gb, vctType, wSectionLength, wTSID)); + gb.BitRead(8); //protocol_version + uint8_t num_channels = gb.BitRead(8); + + const int SHORT_NAME_LEN = 7*2; + BYTE short_name[SHORT_NAME_LEN+2]; + + for (uint8_t i = 0; i < num_channels; i++) { + gb.ReadBuffer(short_name, SHORT_NAME_LEN); //short_name + UTF16BE2LE(short_name, SHORT_NAME_LEN); + CStringW shortName((wchar_t*)short_name); + gb.BitRead(4); //reserved + uint16_t major_channel_number = gb.BitRead(10); //major_channel_number + uint16_t minor_channel_number = gb.BitRead(10); //minor_channel_number + gb.BitRead(8); //modulation_mode + gb.BitRead(32); //carrier_frequency + uint16_t channel_TSID=gb.BitRead(16); //channel_TSID + uint16_t program_number=gb.BitRead(16); //program_number + gb.BitRead(2); //ETM_location + gb.BitRead(1); //access_controlled + gb.BitRead(1); //hidden + gb.BitRead(2); //TVCT: reserved(1), CVCT: path_select(1) / out_of_band(1) + gb.BitRead(1); //hide_guide + gb.BitRead(3); //reserved + serviceType = gb.BitRead(6); //service_type + uint16_t source_id=gb.BitRead(16); //source_id + gb.BitRead(6); //reserved + BeginEnumDescriptorsATSC(gb, nType, nLength, 10) { // for (i=0;i pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + + CheckNoLog(m_pData->GetSection(PID_PAT, SI_PAT, &m_Filter, 15000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + // program_association_section() + CheckNoLog(ParseSIHeader(gb, SI_PAT, wSectionLength, wTSID)); + while (gb.GetSize() - gb.GetPos() > 4) { + WORD program_number = (WORD)gb.BitRead(16); // program_number + gb.BitRead(3); // reserved + if (program_number == 0) { + gb.BitRead(13); // network_PID + } else { + WORD program_map_PID = (WORD)gb.BitRead(13); // program_map_PID + if (Channels.Lookup(program_number)) { + Channels [program_number].SetPMT(program_map_PID); + ParsePMT(Channels [program_number]); + } + } + } + + return S_OK; +} + +HRESULT CMpeg2DataParser::ParsePMT(CBDAChannel& Channel) +{ + HRESULT hr; + CComPtr pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + + Channel.SetVideoFps(BDA_FPS_NONE); + Channel.SetVideoChroma(BDA_Chroma_NONE); + + CheckNoLog(m_pData->GetSection((PID)Channel.GetPMT(), SI_PMT, &m_Filter, 15000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + // TS_program_map_section() + CheckNoLog(ParseSIHeader(gb, SI_PMT, wSectionLength, wTSID)); + + gb.BitRead(3); // reserved + Channel.SetPCR((ULONG)gb.BitRead(13)); // PCR_PID + gb.BitRead(4); // reserved + BeginEnumDescriptors(gb, nType, nLength) { // for (i=0;i 4) { + PES_STREAM_TYPE pes_stream_type; + BDA_STREAM_TYPE dvb_stream_type; + WORD wPID; + CString strLanguage; + + pes_stream_type = (PES_STREAM_TYPE)gb.BitRead(8); // stream_type + gb.BitRead(3); // reserved + wPID = (WORD)gb.BitRead(13); // elementary_PID + gb.BitRead(4); // reserved + + BeginEnumDescriptors(gb, nType, nLength) { // ES_info_length + switch (nType) { + case DT_ISO_639_LANGUAGE: + gb.ReadBuffer(DescBuffer, nLength); + strLanguage = ConvertString(DescBuffer, 3); + break; + case DT_AC3_AUDIO: + pes_stream_type = AUDIO_STREAM_AC3; + SkipDescriptor(gb, nType, nLength); + break; + case DT_EXTENDED_AC3_AUDIO: + pes_stream_type = AUDIO_STREAM_AC3_PLUS; + SkipDescriptor(gb, nType, nLength); + break; + case DT_AAC_AUDIO: + pes_stream_type = AUDIO_STREAM_AAC_LATM; + SkipDescriptor(gb, nType, nLength); + break; + case DT_SUBTITLING: + gb.ReadBuffer(DescBuffer, nLength); + strLanguage = ConvertString(DescBuffer, 3); + pes_stream_type = SUBTITLE_STREAM; + break; + case DT_VIDEO_STREAM: { + gb.BitRead(1); // multiple_frame_rate_flag + Channel.SetVideoFps((BDA_FPS_TYPE) gb.BitRead(4)); + UINT MPEG_1_only_flag = (UINT) gb.BitRead(1); + gb.BitRead(1); // constrained_parameter_flag + gb.BitRead(1); // still_picture_flag + if (!MPEG_1_only_flag) { + gb.BitRead(8); // profile_and_level_indicator + Channel.SetVideoChroma((BDA_CHROMA_TYPE) gb.BitRead(2)); + gb.BitRead(1); // frame_rate_extension_flag + gb.BitRead(5); // Reserved + } + } + break; + case DT_TARGET_BACKGROUND_GRID: + Channel.SetVideoWidth((ULONG) gb.BitRead(14)); + Channel.SetVideoHeight((ULONG) gb.BitRead(14)); + Channel.SetVideoAR((BDA_AspectRatio_TYPE) gb.BitRead(4)); + break; + default: + SkipDescriptor(gb, nType, nLength); + break; + } + } + EndEnumDescriptors; + if ((dvb_stream_type = ConvertToDVBType(pes_stream_type)) != BDA_UNKNOWN) { + Channel.AddStreamInfo(wPID, dvb_stream_type, pes_stream_type, strLanguage); + } + } + if ((Channel.GetVideoType() == BDA_MPV) && (Channel.GetVideoPID())) { + if (Channel.GetVideoFps() == BDA_FPS_NONE) { + Channel.SetVideoFps(BDA_FPS_25_0); + } + if ((Channel.GetVideoWidth() == 0) && (Channel.GetVideoHeight() == 0)) { + Channel.SetVideoWidth(720); + Channel.SetVideoHeight(576); + } + } else if ((Channel.GetVideoType() == BDA_H264 || Channel.GetVideoType() == BDA_HEVC) && (Channel.GetVideoPID())) { + if (Channel.GetVideoFps() == BDA_FPS_NONE) { + Channel.SetVideoFps(BDA_FPS_25_0); + } + } + + + return S_OK; +} + +HRESULT CMpeg2DataParser::SetTime(CGolombBuffer& gb, EventDescriptor& NowNext) +{ + wchar_t descBuffer[6]; + time_t tNow, tTime; + tm tmTime; + long timezone; + + // init tm structures + time(&tNow); + gmtime_s(&tmTime, &tNow); + _tzset(); + _get_timezone(&timezone); // The difference in seconds between UTC and local time. + + // Start time: + tmTime.tm_hour = (int)(gb.BitRead(4) * 10); + tmTime.tm_hour += (int)gb.BitRead(4); + tmTime.tm_min = (int)(gb.BitRead(4) * 10); + tmTime.tm_min += (int)gb.BitRead(4); + tmTime.tm_sec = (int)(gb.BitRead(4) * 10); + tmTime.tm_sec += (int)gb.BitRead(4); + // Convert to time_t + // mktime() expect tm struct to be local time and since we are feeding it with GMT + // we need to compensate for timezone offset. Note that we don't compensate for DST. + // That is because tm_isdst is set to 0 (GMT) and in this case mktime() won't add any offset. + NowNext.startTime = tTime = mktime(&tmTime) - timezone; + while (tNow < tTime) { + // If current time is less than even start time it is likely that event started the day before. + // We go one day back + NowNext.startTime = tTime -= 86400; + } + + localtime_s(&tmTime, &tTime); + wcsftime(descBuffer, 6, L"%H:%M", &tmTime); + descBuffer[5] = '\0'; + NowNext.strStartTime = descBuffer; + + // Duration: + NowNext.duration = (time_t)(36000 * gb.BitRead(4)); + NowNext.duration += (time_t)(3600 * gb.BitRead(4)); + NowNext.duration += (time_t)(600 * gb.BitRead(4)); + NowNext.duration += (time_t)(60 * gb.BitRead(4)); + NowNext.duration += (time_t)(10 * gb.BitRead(4)); + NowNext.duration += (time_t)gb.BitRead(4); + + tTime += NowNext.duration; + localtime_s(&tmTime, &tTime); + wcsftime(descBuffer, 6, L"%H:%M", &tmTime); + descBuffer[5] = '\0'; + NowNext.strEndTime = descBuffer; + + return S_OK; +} + +HRESULT CMpeg2DataParser::ParseEIT(ULONG ulSID, EventDescriptor& NowNext) +{ + HRESULT hr = S_OK; + DWORD dwLength; + PSECTION data; + ULONG ulGetSID; + EventInformationSection InfoEvent; + NowNext = EventDescriptor(); + + do { + CComPtr pSectionList; + CheckNoLog(m_pData->GetSection(PID_EIT, SI_EIT_act, nullptr, 5000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + InfoEvent.TableID = (UINT8)gb.BitRead(8); + InfoEvent.SectionSyntaxIndicator = (WORD)gb.BitRead(1); + gb.BitRead(3); + InfoEvent.SectionLength = (WORD)gb.BitRead(12); + ulGetSID = (ULONG)gb.BitRead(8); + ulGetSID += 0x100 * (ULONG)gb.BitRead(8); + InfoEvent.ServiceId = ulGetSID; // This is really strange, ServiceID should be uimsbf ??? + if (InfoEvent.ServiceId == ulSID) { + gb.BitRead(2); + InfoEvent.VersionNumber = (UINT8)gb.BitRead(5); + InfoEvent.CurrentNextIndicator = (UINT8)gb.BitRead(1); + if (InfoEvent.CurrentNextIndicator == 1) { + InfoEvent.SectionNumber = (UINT8)gb.BitRead(8); + InfoEvent.LastSectionNumber = (UINT8)gb.BitRead(8); + InfoEvent.TransportStreamID = (WORD)gb.BitRead(16); + InfoEvent.OriginalNetworkID = (WORD)gb.BitRead(16); + InfoEvent.SegmentLastSectionNumber = (UINT8)gb.BitRead(8); + InfoEvent.LastTableID = (UINT8)gb.BitRead(8); + + // Info event + InfoEvent.EventID = (WORD)gb.BitRead(16); + InfoEvent.StartDate = (WORD)gb.BitRead(16); + SetTime(gb, NowNext); + + InfoEvent.RunninStatus = (WORD)gb.BitRead(3); + InfoEvent.FreeCAMode = (WORD)gb.BitRead(1); + if (InfoEvent.RunninStatus == 4) { + UINT8 nLen; + UINT8 itemsLength; + + // Descriptors: + BeginEnumDescriptors(gb, nType, nLength) { + switch (nType) { + case DT_SHORT_EVENT: + gb.BitRead(24); // ISO_639_language_code + + nLen = (UINT8)gb.BitRead(8); // event_name_length + gb.ReadBuffer(DescBuffer, nLen); + if (IsFreeviewEPG(InfoEvent.OriginalNetworkID, DescBuffer, nLen)) { + NowNext.eventName = DecodeFreeviewEPG(DescBuffer, nLen); + } else { + NowNext.eventName = ConvertString(DescBuffer, nLen); + } + + nLen = (UINT8)gb.BitRead(8); // text_length + gb.ReadBuffer(DescBuffer, nLen); + if (IsFreeviewEPG(InfoEvent.OriginalNetworkID, DescBuffer, nLen)) { + NowNext.eventDesc = DecodeFreeviewEPG(DescBuffer, nLen); + } else { + NowNext.eventDesc = ConvertString(DescBuffer, nLen); + } + break; + case DT_EXTENDED_EVENT: + gb.BitRead(4); // descriptor_number + gb.BitRead(4); // last_descriptor_number + gb.BitRead(24); // ISO_639_language_code + + itemsLength = (UINT8)gb.BitRead(8); // length_of_items + while (itemsLength > 0) { + nLen = (UINT8)gb.BitRead(8); // item_description_length + gb.ReadBuffer(DescBuffer, nLen); + CString itemDesc = ConvertString(DescBuffer, nLen); + itemsLength -= nLen + 1; + + nLen = (UINT8)gb.BitRead(8); // item_length + gb.ReadBuffer(DescBuffer, nLen); + CString itemText = ConvertString(DescBuffer, nLen); + itemsLength -= nLen + 1; + NowNext.extendedDescriptorsItems.emplace_back(itemDesc, itemText); + } + + nLen = (UINT8)gb.BitRead(8); // text_length + if (nLen > 0) { + gb.ReadBuffer(DescBuffer, nLen); + NowNext.extendedDescriptorsText += ConvertString(DescBuffer, nLen); + } + break; + case DT_PARENTAL_RATING: { + ASSERT(nLength % 4 == 0); + int rating = -1; + while (nLength >= 4) { + gb.BitRead(24); // ISO 3166 country_code + rating = (int)gb.BitRead(8); // rating + nLength -= 4; + } + if (rating >= 0 && rating <= 0x0f) { + if (rating > 0) { // 0x00 undefined + rating += 3; // 0x01 to 0x0F minimum age = rating + 3 years + } + NowNext.parentalRating = rating; + } + } + break; + case DT_CONTENT: + ASSERT(nLength % 2 == 0); + while (nLength >= 2) { + BYTE content = (BYTE)gb.BitRead(4); // content_nibble_level_1 + gb.BitRead(4); // content_nibble_level_2 + gb.BitRead(8); // user_byte + if (1 <= content && content <= 10) { + if (!NowNext.content.IsEmpty()) { + NowNext.content.Append(_T(", ")); + } + + static UINT contents[] = { + IDS_CONTENT_MOVIE_DRAMA, + IDS_CONTENT_NEWS_CURRENTAFFAIRS, + IDS_CONTENT_SHOW_GAMESHOW, + IDS_CONTENT_SPORTS, + IDS_CONTENT_CHILDREN_YOUTH_PROG, + IDS_CONTENT_MUSIC_BALLET_DANCE, + IDS_CONTENT_MUSIC_ART_CULTURE, + IDS_CONTENT_SOCIAL_POLITICAL_ECO, + IDS_CONTENT_EDUCATION_SCIENCE, + IDS_CONTENT_LEISURE + }; + + NowNext.content.AppendFormat(contents[content - 1]); + } + nLength -= 2; + } + break; + default: + SkipDescriptor(gb, nType, nLength); + break; + } + } + EndEnumDescriptors; + } + } + } + m_Filter.SectionNumber++; + } while ((InfoEvent.ServiceId != ulSID || InfoEvent.RunninStatus != 4) && m_Filter.SectionNumber <= 22); + + if (m_Filter.SectionNumber > 22 || InfoEvent.CurrentNextIndicator != 1) { + NowNext = EventDescriptor(); + hr = E_FAIL; + } + + return hr; +} + +HRESULT CMpeg2DataParser::ParseNIT() +{ + HRESULT hr; + CComPtr pSectionList; + DWORD dwLength; + PSECTION data; + WORD wTSID; + WORD wSectionLength; + + CheckNoLog(m_pData->GetSection(PID_NIT, SI_NIT, &m_Filter, 15000, &pSectionList)); + CheckNoLog(pSectionList->GetSectionData(0, &dwLength, &data)); + + CGolombBuffer gb((BYTE*)data, dwLength); + + // network_information_section() + CheckNoLog(ParseSIHeader(gb, SI_NIT, wSectionLength, wTSID)); + + gb.BitRead(4); // reserved_future_use + BeginEnumDescriptors(gb, nType, nLength) { // for (i=0;i 4) { + WORD transport_stream_id = (WORD)gb.BitRead(16); // transport_stream_id + UNREFERENCED_PARAMETER(transport_stream_id); + WORD original_network_id = (WORD)gb.BitRead(16); // original_network_id + UNREFERENCED_PARAMETER(original_network_id); + gb.BitRead(4); // reserved_future_use + BeginEnumDescriptors(gb, nType, nLength) { + switch (nType) { + case DT_LOGICAL_CHANNEL: + for (int i = 0; i < nLength / 4; i++) { + WORD service_id = (WORD)gb.BitRead(16); + gb.BitRead(6); + WORD logical_channel_number = (WORD)gb.BitRead(10); + if (Channels.Lookup(service_id)) { + Channels[service_id].SetOriginNumber(logical_channel_number); + BDA_LOG(_T("NIT association : %d -> %s"), logical_channel_number, Channels[service_id].ToString().GetString()); + } + } + break; + default: + SkipDescriptor(gb, nType, nLength); + break; + } + } + EndEnumDescriptors; + } + + return S_OK; +} diff --git a/src/mpc-hc/Mpeg2SectionData.h b/src/mpc-hc/Mpeg2SectionData.h index 5544dad852e..860afdf4c67 100644 --- a/src/mpc-hc/Mpeg2SectionData.h +++ b/src/mpc-hc/Mpeg2SectionData.h @@ -1,94 +1,94 @@ -/* - * (C) 2009-2013, 2016 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 . - * - */ - -#pragma once - -#include "DVBChannel.h" -#include -#include - -class CGolombBuffer; - -#pragma pack(push, 1) -struct SI_HEADER { - UINT8 TableID; - WORD SectionSyntaxIndicator : 1; - WORD Reserved1 : 3; - WORD SectionLength : 12; - WORD BouquetID; - UINT8 Reserved2 : 1; - UINT8 VersionNumber : 5; - UINT8 CurrentNextIndicator : 1; - UINT8 SectionNumber; - UINT8 LastSectionNumber; -}; - -struct EventInformationSection { - UINT8 TableID; - WORD SectionSyntaxIndicator : 1; - WORD Reserved1 : 3; - WORD SectionLength : 12; - ULONG ServiceId; - UINT8 Reserved2 : 2; - UINT8 VersionNumber : 5; - UINT8 CurrentNextIndicator : 1; - UINT8 SectionNumber; - UINT8 LastSectionNumber; - WORD TransportStreamID; - WORD OriginalNetworkID; - UINT8 SegmentLastSectionNumber; - UINT8 LastTableID; - WORD EventID; - WORD StartDate; - UINT8 StartTime[6]; - UINT8 Duration[6]; - WORD RunninStatus : 3; - WORD FreeCAMode : 1; - WORD DescriptorsLoopLength : 12; - -}; - -class CMpeg2DataParser -{ -public: - CMpeg2DataParser(IBaseFilter* pFilter); - - HRESULT ParseSDT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate); - HRESULT ParseVCT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, enum DVB_SI vctType); - HRESULT ParseMGT(enum DVB_SI &vctType); - HRESULT ParsePAT(); - HRESULT ParseNIT(); - HRESULT ParseEIT(ULONG ulSID, EventDescriptor& NowNext); - HRESULT ParsePMT(CBDAChannel& Channel); - - static CStringW ConvertString(BYTE* pBuffer, size_t uLength); - - CAtlMap Channels; - -private: - CComQIPtr m_pData; - MPEG2_FILTER m_Filter; - - - BDA_STREAM_TYPE ConvertToDVBType(PES_STREAM_TYPE nType); - HRESULT ParseSIHeader(CGolombBuffer& gb, DVB_SI SIType, WORD& wSectionLength, WORD& wTSID); - HRESULT SetTime(CGolombBuffer& gb, EventDescriptor& NowNext); -}; -#pragma pack(pop) +/* + * (C) 2009-2013, 2016 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 . + * + */ + +#pragma once + +#include "DVBChannel.h" +#include +#include + +class CGolombBuffer; + +#pragma pack(push, 1) +struct SI_HEADER { + UINT8 TableID; + WORD SectionSyntaxIndicator : 1; + WORD Reserved1 : 3; + WORD SectionLength : 12; + WORD BouquetID; + UINT8 Reserved2 : 1; + UINT8 VersionNumber : 5; + UINT8 CurrentNextIndicator : 1; + UINT8 SectionNumber; + UINT8 LastSectionNumber; +}; + +struct EventInformationSection { + UINT8 TableID; + WORD SectionSyntaxIndicator : 1; + WORD Reserved1 : 3; + WORD SectionLength : 12; + ULONG ServiceId; + UINT8 Reserved2 : 2; + UINT8 VersionNumber : 5; + UINT8 CurrentNextIndicator : 1; + UINT8 SectionNumber; + UINT8 LastSectionNumber; + WORD TransportStreamID; + WORD OriginalNetworkID; + UINT8 SegmentLastSectionNumber; + UINT8 LastTableID; + WORD EventID; + WORD StartDate; + UINT8 StartTime[6]; + UINT8 Duration[6]; + WORD RunninStatus : 3; + WORD FreeCAMode : 1; + WORD DescriptorsLoopLength : 12; + +}; + +class CMpeg2DataParser +{ +public: + CMpeg2DataParser(IBaseFilter* pFilter); + + HRESULT ParseSDT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate); + HRESULT ParseVCT(ULONG ulFrequency, ULONG ulBandwidth, ULONG ulSymbolRate, enum DVB_SI vctType); + HRESULT ParseMGT(enum DVB_SI &vctType); + HRESULT ParsePAT(); + HRESULT ParseNIT(); + HRESULT ParseEIT(ULONG ulSID, EventDescriptor& NowNext); + HRESULT ParsePMT(CBDAChannel& Channel); + + static CStringW ConvertString(BYTE* pBuffer, size_t uLength); + + CAtlMap Channels; + +private: + CComQIPtr m_pData; + MPEG2_FILTER m_Filter; + + + BDA_STREAM_TYPE ConvertToDVBType(PES_STREAM_TYPE nType); + HRESULT ParseSIHeader(CGolombBuffer& gb, DVB_SI SIType, WORD& wSectionLength, WORD& wTSID); + HRESULT SetTime(CGolombBuffer& gb, EventDescriptor& NowNext); +}; +#pragma pack(pop) diff --git a/src/mpc-hc/MultiMonitor.cpp b/src/mpc-hc/MultiMonitor.cpp index 2a62da0f590..d6d3010a77f 100644 --- a/src/mpc-hc/MultiMonitor.cpp +++ b/src/mpc-hc/MultiMonitor.cpp @@ -1,263 +1,263 @@ -/* - * Author: Donald Kackman - * Email: don@itsEngineering.com - * Copyright 2002, Donald Kackman - * - * 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 . - * - */ - -#include "stdafx.h" -#include "MultiMonitor.h" -#include "Monitors.h" - -// CMonitor - -// constucts a monitor class not attached to any handle -CMonitor::CMonitor() : m_hMonitor(nullptr) -{ -} - -// copy constructor -CMonitor::CMonitor(const CMonitor& monitor) -{ - m_hMonitor = (HMONITOR)monitor; -} - -CMonitor::~CMonitor() -{ -} - -void CMonitor::Attach(const HMONITOR hMonitor) -{ - ASSERT(CMonitors::IsMonitor(hMonitor)); - - m_hMonitor = hMonitor; -} - -HMONITOR CMonitor::Detach() -{ - HMONITOR hMonitor = m_hMonitor; - m_hMonitor = nullptr; - return hMonitor; -} - -// creates an HDC for the monitor -// it is up to the client to call DeleteDC -// -// for normal multimonitor drawing it is not necessary to get a -// dc for each monitor. Windows takes care of drawing correctly -// on all monitors -// -// Only very exacting applications would need a DC for each monitor -HDC CMonitor::CreateDC() const -{ - ASSERT(IsMonitor()); - - CString name; - GetName(name); - - //create a dc for this display - HDC hdc = ::CreateDC(name, name, nullptr, nullptr); - ASSERT(hdc != nullptr); - - //set the viewport based on the monitor rect's relation to the primary monitor - CRect rect; - GetMonitorRect(&rect); - - ::SetViewportOrgEx(hdc, -rect.left, -rect.top, nullptr); - ::SetViewportExtEx(hdc, rect.Width(), rect.Height(), nullptr); - - return hdc; -} - -int CMonitor::GetBitsPerPixel() const -{ - HDC hdc = CreateDC(); - int ret = ::GetDeviceCaps(hdc, BITSPIXEL) * ::GetDeviceCaps(hdc, PLANES); - VERIFY(::DeleteDC(hdc)); - - return ret; -} - -void CMonitor::GetName(CString& displayName) const -{ - ASSERT(IsMonitor()); - - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - - displayName = mi.szDevice; -} - -void CMonitor::GetNames(CString& displayName, CString& deviceName) const -{ - ASSERT(IsMonitor()); - - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - - displayName = mi.szDevice; - - DISPLAY_DEVICE displayDevice = { sizeof(displayDevice) }; - if (EnumDisplayDevices(displayName, 0, &displayDevice, 0)) { - deviceName = displayDevice.DeviceString; - } else { - deviceName = L""; - } -} - -// -// these methods return true if any part of the item intersects the monitor rect -BOOL CMonitor::IsOnMonitor(const POINT& pt) const -{ - CRect rect; - GetMonitorRect(rect); - - return rect.PtInRect(pt); -} - -BOOL CMonitor::IsOnMonitor(const CWnd* pWnd) const -{ - CRect rect; - GetMonitorRect(rect); - - ASSERT(::IsWindow(pWnd->GetSafeHwnd())); - CRect wndRect; - pWnd->GetWindowRect(&wndRect); - - return rect.IntersectRect(rect, wndRect); -} - -BOOL CMonitor::IsOnMonitor(const LPRECT lprc) const -{ - CRect rect; - GetMonitorRect(rect); - - return rect.IntersectRect(rect, lprc); -} - -void CMonitor::GetMonitorRect(LPRECT lprc) const -{ - ASSERT(IsMonitor()); - - MONITORINFO mi; - RECT rc; - - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - rc = mi.rcMonitor; - - ::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom); -} - -// -// the work area does not include the start bar -void CMonitor::GetWorkAreaRect(LPRECT lprc) const -{ - ASSERT(IsMonitor()); - - MONITORINFO mi; - RECT rc; - - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - rc = mi.rcWork; - - ::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom); -} - -//these two center methods are adapted from David Campbell's -//MSJ article (see comment at the top of the header file) -void CMonitor::CenterRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect) const -{ - int w = lprc->right - lprc->left; - int h = lprc->bottom - lprc->top; - - CRect rect; - if (UseWorkAreaRect) { - GetWorkAreaRect(&rect); - } else { - GetMonitorRect(&rect); - } - - // MPC-HC custom code start - // Added rounding to get exactly the same rect as the CWnd::CenterWindow method returns. - lprc->left = std::lround(rect.left + (rect.Width() - w) / 2.0); - lprc->top = std::lround(rect.top + (rect.Height() - h) / 2.0); - // MPC-HC custom code end - lprc->right = lprc->left + w; - lprc->bottom = lprc->top + h; -} - -void CMonitor::CenterWindowToMonitor(CWnd* const pWnd, const BOOL UseWorkAreaRect) const -{ - ASSERT(IsMonitor()); - ASSERT(pWnd); - ASSERT(::IsWindow(pWnd->m_hWnd)); - - CRect rect; - pWnd->GetWindowRect(&rect); - CenterRectToMonitor(&rect, UseWorkAreaRect); - // MPC-HC custom code start - // Check if we are a child window and modify the coordinates accordingly - if (pWnd->GetStyle() & WS_CHILD) { - pWnd->GetParent()->ScreenToClient(&rect); - } - // MPC-HC custom code end - pWnd->SetWindowPos(nullptr, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); -} - -void CMonitor::ClipRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect) const -{ - int w = lprc->right - lprc->left; - int h = lprc->bottom - lprc->top; - - CRect rect; - if (UseWorkAreaRect) { - GetWorkAreaRect(&rect); - } else { - GetMonitorRect(&rect); - } - - lprc->left = std::max(rect.left, std::min(rect.right - w, lprc->left)); - lprc->top = std::max(rect.top, std::min(rect.bottom - h, lprc->top)); - lprc->right = lprc->left + w; - lprc->bottom = lprc->top + h; -} - -// -// is the instance the primary monitor -BOOL CMonitor::IsPrimaryMonitor() const -{ - ASSERT(IsMonitor()); - - MONITORINFO mi; - - mi.cbSize = sizeof(mi); - ::GetMonitorInfo(m_hMonitor, &mi); - - return mi.dwFlags == MONITORINFOF_PRIMARY; -} - -// -// is the instance currently attached to a valid monitor handle -BOOL CMonitor::IsMonitor() const -{ - return CMonitors::IsMonitor(m_hMonitor); -} +/* + * Author: Donald Kackman + * Email: don@itsEngineering.com + * Copyright 2002, Donald Kackman + * + * 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 . + * + */ + +#include "stdafx.h" +#include "MultiMonitor.h" +#include "Monitors.h" + +// CMonitor + +// constucts a monitor class not attached to any handle +CMonitor::CMonitor() : m_hMonitor(nullptr) +{ +} + +// copy constructor +CMonitor::CMonitor(const CMonitor& monitor) +{ + m_hMonitor = (HMONITOR)monitor; +} + +CMonitor::~CMonitor() +{ +} + +void CMonitor::Attach(const HMONITOR hMonitor) +{ + ASSERT(CMonitors::IsMonitor(hMonitor)); + + m_hMonitor = hMonitor; +} + +HMONITOR CMonitor::Detach() +{ + HMONITOR hMonitor = m_hMonitor; + m_hMonitor = nullptr; + return hMonitor; +} + +// creates an HDC for the monitor +// it is up to the client to call DeleteDC +// +// for normal multimonitor drawing it is not necessary to get a +// dc for each monitor. Windows takes care of drawing correctly +// on all monitors +// +// Only very exacting applications would need a DC for each monitor +HDC CMonitor::CreateDC() const +{ + ASSERT(IsMonitor()); + + CString name; + GetName(name); + + //create a dc for this display + HDC hdc = ::CreateDC(name, name, nullptr, nullptr); + ASSERT(hdc != nullptr); + + //set the viewport based on the monitor rect's relation to the primary monitor + CRect rect; + GetMonitorRect(&rect); + + ::SetViewportOrgEx(hdc, -rect.left, -rect.top, nullptr); + ::SetViewportExtEx(hdc, rect.Width(), rect.Height(), nullptr); + + return hdc; +} + +int CMonitor::GetBitsPerPixel() const +{ + HDC hdc = CreateDC(); + int ret = ::GetDeviceCaps(hdc, BITSPIXEL) * ::GetDeviceCaps(hdc, PLANES); + VERIFY(::DeleteDC(hdc)); + + return ret; +} + +void CMonitor::GetName(CString& displayName) const +{ + ASSERT(IsMonitor()); + + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + + displayName = mi.szDevice; +} + +void CMonitor::GetNames(CString& displayName, CString& deviceName) const +{ + ASSERT(IsMonitor()); + + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + + displayName = mi.szDevice; + + DISPLAY_DEVICE displayDevice = { sizeof(displayDevice) }; + if (EnumDisplayDevices(displayName, 0, &displayDevice, 0)) { + deviceName = displayDevice.DeviceString; + } else { + deviceName = L""; + } +} + +// +// these methods return true if any part of the item intersects the monitor rect +BOOL CMonitor::IsOnMonitor(const POINT& pt) const +{ + CRect rect; + GetMonitorRect(rect); + + return rect.PtInRect(pt); +} + +BOOL CMonitor::IsOnMonitor(const CWnd* pWnd) const +{ + CRect rect; + GetMonitorRect(rect); + + ASSERT(::IsWindow(pWnd->GetSafeHwnd())); + CRect wndRect; + pWnd->GetWindowRect(&wndRect); + + return rect.IntersectRect(rect, wndRect); +} + +BOOL CMonitor::IsOnMonitor(const LPRECT lprc) const +{ + CRect rect; + GetMonitorRect(rect); + + return rect.IntersectRect(rect, lprc); +} + +void CMonitor::GetMonitorRect(LPRECT lprc) const +{ + ASSERT(IsMonitor()); + + MONITORINFO mi; + RECT rc; + + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + rc = mi.rcMonitor; + + ::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom); +} + +// +// the work area does not include the start bar +void CMonitor::GetWorkAreaRect(LPRECT lprc) const +{ + ASSERT(IsMonitor()); + + MONITORINFO mi; + RECT rc; + + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + rc = mi.rcWork; + + ::SetRect(lprc, rc.left, rc.top, rc.right, rc.bottom); +} + +//these two center methods are adapted from David Campbell's +//MSJ article (see comment at the top of the header file) +void CMonitor::CenterRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect) const +{ + int w = lprc->right - lprc->left; + int h = lprc->bottom - lprc->top; + + CRect rect; + if (UseWorkAreaRect) { + GetWorkAreaRect(&rect); + } else { + GetMonitorRect(&rect); + } + + // MPC-HC custom code start + // Added rounding to get exactly the same rect as the CWnd::CenterWindow method returns. + lprc->left = std::lround(rect.left + (rect.Width() - w) / 2.0); + lprc->top = std::lround(rect.top + (rect.Height() - h) / 2.0); + // MPC-HC custom code end + lprc->right = lprc->left + w; + lprc->bottom = lprc->top + h; +} + +void CMonitor::CenterWindowToMonitor(CWnd* const pWnd, const BOOL UseWorkAreaRect) const +{ + ASSERT(IsMonitor()); + ASSERT(pWnd); + ASSERT(::IsWindow(pWnd->m_hWnd)); + + CRect rect; + pWnd->GetWindowRect(&rect); + CenterRectToMonitor(&rect, UseWorkAreaRect); + // MPC-HC custom code start + // Check if we are a child window and modify the coordinates accordingly + if (pWnd->GetStyle() & WS_CHILD) { + pWnd->GetParent()->ScreenToClient(&rect); + } + // MPC-HC custom code end + pWnd->SetWindowPos(nullptr, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); +} + +void CMonitor::ClipRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect) const +{ + int w = lprc->right - lprc->left; + int h = lprc->bottom - lprc->top; + + CRect rect; + if (UseWorkAreaRect) { + GetWorkAreaRect(&rect); + } else { + GetMonitorRect(&rect); + } + + lprc->left = std::max(rect.left, std::min(rect.right - w, lprc->left)); + lprc->top = std::max(rect.top, std::min(rect.bottom - h, lprc->top)); + lprc->right = lprc->left + w; + lprc->bottom = lprc->top + h; +} + +// +// is the instance the primary monitor +BOOL CMonitor::IsPrimaryMonitor() const +{ + ASSERT(IsMonitor()); + + MONITORINFO mi; + + mi.cbSize = sizeof(mi); + ::GetMonitorInfo(m_hMonitor, &mi); + + return mi.dwFlags == MONITORINFOF_PRIMARY; +} + +// +// is the instance currently attached to a valid monitor handle +BOOL CMonitor::IsMonitor() const +{ + return CMonitors::IsMonitor(m_hMonitor); +} diff --git a/src/mpc-hc/MultiMonitor.h b/src/mpc-hc/MultiMonitor.h index 434875b24ca..c43ebbc20c7 100644 --- a/src/mpc-hc/MultiMonitor.h +++ b/src/mpc-hc/MultiMonitor.h @@ -1,89 +1,89 @@ -/* - * Author: Donald Kackman - * Email: don@itsEngineering.com - * Copyright 2002, Donald Kackman - * - * 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 . - * - */ - -/* - * David Campbell's article - * How to Exploit Multiple Monitor Support in Memphis and Windows NT 5.0 - * is very helpful for multimonitor api calls - * http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0697/monitor/monitor.htm&nav=/msj/0697/newnav.htm -*/ - -// CMonitor - -#pragma once - -class CMonitor : public CObject -{ -public: - //construction destruction - CMonitor(); - CMonitor(const CMonitor& monitor); - virtual ~CMonitor(); - - //operations - void Attach(const HMONITOR hMonitor); - HMONITOR Detach(); - - void ClipRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect = FALSE) const; - void CenterRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect = FALSE) const; - void CenterWindowToMonitor(CWnd* const pWnd, const BOOL UseWorkAreaRect = FALSE) const; - - HDC CreateDC() const; - - //properties - void GetMonitorRect(LPRECT lprc) const; - void GetWorkAreaRect(LPRECT lprc) const; - - void GetName(CString& displayName) const; - void GetNames(CString& displayName, CString& deviceName) const; - - int GetBitsPerPixel() const; - - BOOL IsOnMonitor(const POINT& pt) const; - BOOL IsOnMonitor(const CWnd* pWnd) const; - BOOL IsOnMonitor(const LPRECT lprc) const; - - BOOL IsPrimaryMonitor() const; - BOOL IsMonitor() const; - - //operators - operator HMONITOR() const { - return this == nullptr ? nullptr : m_hMonitor; - } - - BOOL operator ==(const CMonitor& monitor) const { - return m_hMonitor == (HMONITOR)monitor; - } - - BOOL operator !=(const CMonitor& monitor) const { - return !(*this == monitor); - } - - CMonitor& operator =(const CMonitor& monitor) { - m_hMonitor = (HMONITOR)monitor; - return *this; - } - -private: - HMONITOR m_hMonitor; - -}; +/* + * Author: Donald Kackman + * Email: don@itsEngineering.com + * Copyright 2002, Donald Kackman + * + * 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 . + * + */ + +/* + * David Campbell's article + * How to Exploit Multiple Monitor Support in Memphis and Windows NT 5.0 + * is very helpful for multimonitor api calls + * http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0697/monitor/monitor.htm&nav=/msj/0697/newnav.htm +*/ + +// CMonitor + +#pragma once + +class CMonitor : public CObject +{ +public: + //construction destruction + CMonitor(); + CMonitor(const CMonitor& monitor); + virtual ~CMonitor(); + + //operations + void Attach(const HMONITOR hMonitor); + HMONITOR Detach(); + + void ClipRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect = FALSE) const; + void CenterRectToMonitor(LPRECT lprc, const BOOL UseWorkAreaRect = FALSE) const; + void CenterWindowToMonitor(CWnd* const pWnd, const BOOL UseWorkAreaRect = FALSE) const; + + HDC CreateDC() const; + + //properties + void GetMonitorRect(LPRECT lprc) const; + void GetWorkAreaRect(LPRECT lprc) const; + + void GetName(CString& displayName) const; + void GetNames(CString& displayName, CString& deviceName) const; + + int GetBitsPerPixel() const; + + BOOL IsOnMonitor(const POINT& pt) const; + BOOL IsOnMonitor(const CWnd* pWnd) const; + BOOL IsOnMonitor(const LPRECT lprc) const; + + BOOL IsPrimaryMonitor() const; + BOOL IsMonitor() const; + + //operators + operator HMONITOR() const { + return this == nullptr ? nullptr : m_hMonitor; + } + + BOOL operator ==(const CMonitor& monitor) const { + return m_hMonitor == (HMONITOR)monitor; + } + + BOOL operator !=(const CMonitor& monitor) const { + return !(*this == monitor); + } + + CMonitor& operator =(const CMonitor& monitor) { + m_hMonitor = (HMONITOR)monitor; + return *this; + } + +private: + HMONITOR m_hMonitor; + +}; diff --git a/src/mpc-hc/OpenDirHelper.cpp b/src/mpc-hc/OpenDirHelper.cpp index 1cfd265e02b..5b18a31cc12 100644 --- a/src/mpc-hc/OpenDirHelper.cpp +++ b/src/mpc-hc/OpenDirHelper.cpp @@ -1,113 +1,113 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include "MainFrm.h" -#include "OpenDirHelper.h" -#include "PathUtils.h" - - -WNDPROC COpenDirHelper::CBProc; -bool COpenDirHelper::m_incl_subdir; -CString COpenDirHelper::strLastOpenDir; - -void COpenDirHelper::SetFont(HWND hwnd, LPCTSTR FontName, int FontSize) -{ - HFONT hf, hfOld; - LOGFONT lf; - ZeroMemory(&lf, sizeof(LOGFONT)); - HDC hdc = GetDC(hwnd); - - GetObject(GetWindowFont(hwnd), sizeof(lf), &lf); - lf.lfWeight = FW_REGULAR; - lf.lfHeight = (LONG)FontSize; - _tcscpy_s(lf.lfFaceName, FontName); - hf = CreateFontIndirect(&lf); - SetBkMode(hdc, OPAQUE); - - hfOld = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); // get old font - SendMessage(hwnd, WM_SETFONT, (WPARAM)hf, TRUE); // set new font - - if (!hfOld && (hfOld != hf)) { - DeleteObject(hfOld); // if the old font is not system font or the same as newfont, release it. - } - ReleaseDC(hwnd, hdc); -} - -// Subclass procedure -LRESULT APIENTRY COpenDirHelper::CheckBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (uMsg == WM_LBUTTONUP) { - if ((SendMessage(hwnd, BM_GETCHECK, 0, 0)) == 1) { - m_incl_subdir = FALSE; - } else { - m_incl_subdir = TRUE; - } - } - return CallWindowProc(CBProc, hwnd, uMsg, wParam, lParam); -} - -int CALLBACK COpenDirHelper::BrowseCallbackProcDIR(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) -{ - // Initialization callback message - if (uMsg == BFFM_INITIALIZED) { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)strLastOpenDir); - - HWND checkbox; - RECT ListViewRect; - RECT Dialog; - RECT ClientArea; - RECT ButtonRect; - - checkbox = CreateWindowEx(0, _T("BUTTON"), ResStr(IDS_MAINFRM_DIR_CHECK), - WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | BS_AUTOCHECKBOX | BS_MULTILINE, - 0, 100, 100, 50, hwnd, 0, AfxGetApp()->m_hInstance, nullptr); - - HWND ListView = FindWindowEx(hwnd, nullptr, _T("SysTreeView32"), nullptr); - - HWND id_ok = GetDlgItem(hwnd, IDOK); - HWND id_cancel = GetDlgItem(hwnd, IDCANCEL); - - GetWindowRect(hwnd, &Dialog); - MoveWindow(hwnd, Dialog.left, Dialog.top, Dialog.right - Dialog.left + 50, Dialog.bottom - Dialog.top + 70, TRUE); - GetWindowRect(hwnd, &Dialog); - - GetClientRect(hwnd, &ClientArea); - - GetWindowRect(ListView, &ListViewRect); - MoveWindow(ListView, ListViewRect.left - Dialog.left - 3, ListViewRect.top - Dialog.top - 75, ListViewRect.right - ListViewRect.left + 49, ListViewRect.bottom - ListViewRect.top + 115, TRUE); - GetWindowRect(ListView, &ListViewRect); - - GetWindowRect(id_ok, &ButtonRect); - MoveWindow(id_ok, ButtonRect.left - Dialog.left + 49, ButtonRect.top - Dialog.top + 40, ButtonRect.right - ButtonRect.left, ButtonRect.bottom - ButtonRect.top, TRUE); - - GetWindowRect(id_cancel, &ButtonRect); - MoveWindow(id_cancel, ButtonRect.left - Dialog.left + 49, ButtonRect.top - Dialog.top + 40, ButtonRect.right - ButtonRect.left, ButtonRect.bottom - ButtonRect.top, TRUE); - - SetWindowPos(checkbox, HWND_BOTTOM, ListViewRect.left - Dialog.left - 3, ClientArea.bottom - 35, 180, 27, SWP_SHOWWINDOW); - SetFont(checkbox, _T("Tahoma"), 13); - - CBProc = (WNDPROC)SetWindowLongPtr(checkbox, GWLP_WNDPROC, (LONG_PTR)CheckBoxSubclassProc); - SendMessage(checkbox, BM_SETCHECK, (WPARAM)m_incl_subdir, 0); - } - - return 0; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include "MainFrm.h" +#include "OpenDirHelper.h" +#include "PathUtils.h" + + +WNDPROC COpenDirHelper::CBProc; +bool COpenDirHelper::m_incl_subdir; +CString COpenDirHelper::strLastOpenDir; + +void COpenDirHelper::SetFont(HWND hwnd, LPCTSTR FontName, int FontSize) +{ + HFONT hf, hfOld; + LOGFONT lf; + ZeroMemory(&lf, sizeof(LOGFONT)); + HDC hdc = GetDC(hwnd); + + GetObject(GetWindowFont(hwnd), sizeof(lf), &lf); + lf.lfWeight = FW_REGULAR; + lf.lfHeight = (LONG)FontSize; + _tcscpy_s(lf.lfFaceName, FontName); + hf = CreateFontIndirect(&lf); + SetBkMode(hdc, OPAQUE); + + hfOld = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); // get old font + SendMessage(hwnd, WM_SETFONT, (WPARAM)hf, TRUE); // set new font + + if (!hfOld && (hfOld != hf)) { + DeleteObject(hfOld); // if the old font is not system font or the same as newfont, release it. + } + ReleaseDC(hwnd, hdc); +} + +// Subclass procedure +LRESULT APIENTRY COpenDirHelper::CheckBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (uMsg == WM_LBUTTONUP) { + if ((SendMessage(hwnd, BM_GETCHECK, 0, 0)) == 1) { + m_incl_subdir = FALSE; + } else { + m_incl_subdir = TRUE; + } + } + return CallWindowProc(CBProc, hwnd, uMsg, wParam, lParam); +} + +int CALLBACK COpenDirHelper::BrowseCallbackProcDIR(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) +{ + // Initialization callback message + if (uMsg == BFFM_INITIALIZED) { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(LPCTSTR)strLastOpenDir); + + HWND checkbox; + RECT ListViewRect; + RECT Dialog; + RECT ClientArea; + RECT ButtonRect; + + checkbox = CreateWindowEx(0, _T("BUTTON"), ResStr(IDS_MAINFRM_DIR_CHECK), + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | BS_AUTOCHECKBOX | BS_MULTILINE, + 0, 100, 100, 50, hwnd, 0, AfxGetApp()->m_hInstance, nullptr); + + HWND ListView = FindWindowEx(hwnd, nullptr, _T("SysTreeView32"), nullptr); + + HWND id_ok = GetDlgItem(hwnd, IDOK); + HWND id_cancel = GetDlgItem(hwnd, IDCANCEL); + + GetWindowRect(hwnd, &Dialog); + MoveWindow(hwnd, Dialog.left, Dialog.top, Dialog.right - Dialog.left + 50, Dialog.bottom - Dialog.top + 70, TRUE); + GetWindowRect(hwnd, &Dialog); + + GetClientRect(hwnd, &ClientArea); + + GetWindowRect(ListView, &ListViewRect); + MoveWindow(ListView, ListViewRect.left - Dialog.left - 3, ListViewRect.top - Dialog.top - 75, ListViewRect.right - ListViewRect.left + 49, ListViewRect.bottom - ListViewRect.top + 115, TRUE); + GetWindowRect(ListView, &ListViewRect); + + GetWindowRect(id_ok, &ButtonRect); + MoveWindow(id_ok, ButtonRect.left - Dialog.left + 49, ButtonRect.top - Dialog.top + 40, ButtonRect.right - ButtonRect.left, ButtonRect.bottom - ButtonRect.top, TRUE); + + GetWindowRect(id_cancel, &ButtonRect); + MoveWindow(id_cancel, ButtonRect.left - Dialog.left + 49, ButtonRect.top - Dialog.top + 40, ButtonRect.right - ButtonRect.left, ButtonRect.bottom - ButtonRect.top, TRUE); + + SetWindowPos(checkbox, HWND_BOTTOM, ListViewRect.left - Dialog.left - 3, ClientArea.bottom - 35, 180, 27, SWP_SHOWWINDOW); + SetFont(checkbox, _T("Tahoma"), 13); + + CBProc = (WNDPROC)SetWindowLongPtr(checkbox, GWLP_WNDPROC, (LONG_PTR)CheckBoxSubclassProc); + SendMessage(checkbox, BM_SETCHECK, (WPARAM)m_incl_subdir, 0); + } + + return 0; +} diff --git a/src/mpc-hc/OpenDirHelper.h b/src/mpc-hc/OpenDirHelper.h index ec40aec7a2d..85311ff42fe 100644 --- a/src/mpc-hc/OpenDirHelper.h +++ b/src/mpc-hc/OpenDirHelper.h @@ -1,36 +1,36 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2015, 2017 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 . - * - */ - -#pragma once - -class COpenDirHelper -{ -public: - static WNDPROC CBProc; - static bool m_incl_subdir; - static CString strLastOpenDir; - - static void SetFont(HWND hwnd, LPCTSTR FontName, int FontSize); - // Subclass procedure - static LRESULT APIENTRY CheckBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - - static int CALLBACK BrowseCallbackProcDIR(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2015, 2017 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 . + * + */ + +#pragma once + +class COpenDirHelper +{ +public: + static WNDPROC CBProc; + static bool m_incl_subdir; + static CString strLastOpenDir; + + static void SetFont(HWND hwnd, LPCTSTR FontName, int FontSize); + // Subclass procedure + static LRESULT APIENTRY CheckBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + static int CALLBACK BrowseCallbackProcDIR(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData); +}; diff --git a/src/mpc-hc/OpenDlg.cpp b/src/mpc-hc/OpenDlg.cpp index 332b03216b1..c27a7f28843 100644 --- a/src/mpc-hc/OpenDlg.cpp +++ b/src/mpc-hc/OpenDlg.cpp @@ -1,237 +1,237 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#include "stdafx.h" -#include -#include "mplayerc.h" -#include "PathUtils.h" -#include "OpenDlg.h" -#include "OpenFileDlg.h" - - -// COpenDlg dialog - -//IMPLEMENT_DYNAMIC(COpenDlg, CMPCThemeResizableDialog) -COpenDlg::COpenDlg(CWnd* pParent /*=nullptr*/) - : CMPCThemeResizableDialog(COpenDlg::IDD, pParent) - , m_bAppendToPlaylist(FALSE) - , m_bMultipleFiles(false) -{ -} - -COpenDlg::~COpenDlg() -{ -} - -void COpenDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Control(pDX, IDR_MAINFRAME, m_icon); - DDX_Control(pDX, IDC_COMBO1, m_cbMRU); - DDX_CBString(pDX, IDC_COMBO1, m_path); - DDX_Control(pDX, IDC_COMBO2, m_cbMRUDub); - DDX_CBString(pDX, IDC_COMBO2, m_pathDub); - DDX_Control(pDX, IDC_STATIC1, m_labelDub); - DDX_Check(pDX, IDC_CHECK1, m_bAppendToPlaylist); - fulfillThemeReqs(); -} - - -BEGIN_MESSAGE_MAP(COpenDlg, CMPCThemeResizableDialog) - ON_BN_CLICKED(IDC_BUTTON1, OnBrowseFile) - ON_BN_CLICKED(IDC_BUTTON2, OnBrowseDubFile) - ON_BN_CLICKED(IDOK, OnOk) - ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateDub) - ON_UPDATE_COMMAND_UI(IDC_COMBO2, OnUpdateDub) - ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateDub) - ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOk) -END_MESSAGE_MAP() - - -// COpenDlg message handlers - -BOOL COpenDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - m_icon.SetIcon((HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED)); - - CAppSettings& s = AfxGetAppSettings(); - - auto& MRU = s.MRU; - MRU.ReadMediaHistory(); - m_cbMRU.ResetContent(); - for (int i = 0; i < MRU.GetSize(); i++) { - if (MRU[i].fns.GetCount() >0 && !MRU[i].fns.GetHead().IsEmpty()) { - m_cbMRU.AddString(MRU[i].fns.GetHead()); - } - } - CorrectComboListWidth(m_cbMRU); - - CRecentFileList& MRUDub = s.MRUDub; - MRUDub.ReadList(); - m_cbMRUDub.ResetContent(); - for (int i = 0; i < MRUDub.GetSize(); i++) { - if (!MRUDub[i].IsEmpty()) { - m_cbMRUDub.AddString(MRUDub[i]); - } - } - CorrectComboListWidth(m_cbMRUDub); - - if (m_cbMRU.GetCount() > 0) { - m_cbMRU.SetCurSel(0); - } - - m_fns.RemoveAll(); - m_path.Empty(); - m_pathDub.Empty(); - m_bMultipleFiles = false; - m_bAppendToPlaylist = FALSE; - - AddAnchor(m_cbMRU, TOP_LEFT, TOP_RIGHT); - AddAnchor(m_cbMRUDub, TOP_LEFT, TOP_RIGHT); - AddAnchor(IDC_BUTTON1, TOP_RIGHT); - AddAnchor(IDC_BUTTON2, TOP_RIGHT); - AddAnchor(IDOK, TOP_RIGHT); - AddAnchor(IDCANCEL, TOP_RIGHT); - AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); - - CRect r; - GetWindowRect(r); - CSize size = r.Size(); - SetMinTrackSize(size); - size.cx = 1000; - SetMaxTrackSize(size); - - fulfillThemeReqs(); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -static CString GetFileName(CString str) -{ - CPath p = str; - p.StripPath(); - return (LPCTSTR)p; -} - -void COpenDlg::OnBrowseFile() -{ - UpdateData(); - - CAppSettings& s = AfxGetAppSettings(); - - CString filter; - CAtlArray mask; - s.m_Formats.GetFilter(filter, mask); - - DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR; - if (!s.fKeepHistory) { - dwFlags |= OFN_DONTADDTORECENT; - } - - COpenFileDlg fd(mask, true, nullptr, m_path, dwFlags, filter, this); - if (m_path.IsEmpty() && s.fKeepHistory && !s.lastQuickOpenPath.IsEmpty()) { - fd.m_ofn.lpstrInitialDir = s.lastQuickOpenPath; - } - if (fd.DoModal() != IDOK) { - return; - } - - m_fns.RemoveAll(); - - POSITION pos = fd.GetStartPosition(); - while (pos) { - m_fns.AddTail(fd.GetNextPathName(pos)); - } - - if (!m_fns.IsEmpty()) { - if (s.fKeepHistory) { - s.lastQuickOpenPath = PathUtils::DirName(m_fns.GetHead()); - } - - if (m_fns.GetCount() > 1) { - m_bMultipleFiles = true; - EndDialog(IDOK); - return; - } else if (m_fns.GetHead()[m_fns.GetHead().GetLength() - 1] == '\\' || m_fns.GetHead()[m_fns.GetHead().GetLength() - 1] == '*') { - m_bMultipleFiles = true; - EndDialog(IDOK); - return; - } - } - - m_cbMRU.SetWindowText(fd.GetPathName()); -} - -void COpenDlg::OnBrowseDubFile() -{ - UpdateData(); - - const CAppSettings& s = AfxGetAppSettings(); - - CString filter; - CAtlArray mask; - s.m_Formats.GetAudioFilter(filter, mask); - - DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR; - if (!s.fKeepHistory) { - dwFlags |= OFN_DONTADDTORECENT; - } - - COpenFileDlg fd(mask, false, nullptr, m_pathDub, dwFlags, filter, this); - if (m_pathDub.IsEmpty() && s.fKeepHistory && !s.lastQuickOpenPath.IsEmpty()) { - fd.m_ofn.lpstrInitialDir = s.lastQuickOpenPath; - } - if (fd.DoModal() != IDOK) { - return; - } - - m_cbMRUDub.SetWindowText(fd.GetPathName()); -} - -void COpenDlg::OnOk() -{ - UpdateData(); - - m_fns.RemoveAll(); - m_fns.AddTail(PathUtils::Unquote(m_path)); - if (m_cbMRUDub.IsWindowEnabled() && !m_pathDub.IsEmpty()) { - m_fns.AddTail(PathUtils::Unquote(m_pathDub)); - } - - m_bMultipleFiles = false; - - OnOK(); -} - -void COpenDlg::OnUpdateDub(CCmdUI* pCmdUI) -{ - UpdateData(); - pCmdUI->Enable(AfxGetAppSettings().m_Formats.GetEngine(m_path) == DirectShow); -} - -void COpenDlg::OnUpdateOk(CCmdUI* pCmdUI) -{ - UpdateData(); - pCmdUI->Enable(!m_path.IsEmpty() || !m_pathDub.IsEmpty()); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#include "stdafx.h" +#include +#include "mplayerc.h" +#include "PathUtils.h" +#include "OpenDlg.h" +#include "OpenFileDlg.h" + + +// COpenDlg dialog + +//IMPLEMENT_DYNAMIC(COpenDlg, CMPCThemeResizableDialog) +COpenDlg::COpenDlg(CWnd* pParent /*=nullptr*/) + : CMPCThemeResizableDialog(COpenDlg::IDD, pParent) + , m_bAppendToPlaylist(FALSE) + , m_bMultipleFiles(false) +{ +} + +COpenDlg::~COpenDlg() +{ +} + +void COpenDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDR_MAINFRAME, m_icon); + DDX_Control(pDX, IDC_COMBO1, m_cbMRU); + DDX_CBString(pDX, IDC_COMBO1, m_path); + DDX_Control(pDX, IDC_COMBO2, m_cbMRUDub); + DDX_CBString(pDX, IDC_COMBO2, m_pathDub); + DDX_Control(pDX, IDC_STATIC1, m_labelDub); + DDX_Check(pDX, IDC_CHECK1, m_bAppendToPlaylist); + fulfillThemeReqs(); +} + + +BEGIN_MESSAGE_MAP(COpenDlg, CMPCThemeResizableDialog) + ON_BN_CLICKED(IDC_BUTTON1, OnBrowseFile) + ON_BN_CLICKED(IDC_BUTTON2, OnBrowseDubFile) + ON_BN_CLICKED(IDOK, OnOk) + ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateDub) + ON_UPDATE_COMMAND_UI(IDC_COMBO2, OnUpdateDub) + ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateDub) + ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOk) +END_MESSAGE_MAP() + + +// COpenDlg message handlers + +BOOL COpenDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + m_icon.SetIcon((HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED)); + + CAppSettings& s = AfxGetAppSettings(); + + auto& MRU = s.MRU; + MRU.ReadMediaHistory(); + m_cbMRU.ResetContent(); + for (int i = 0; i < MRU.GetSize(); i++) { + if (MRU[i].fns.GetCount() >0 && !MRU[i].fns.GetHead().IsEmpty()) { + m_cbMRU.AddString(MRU[i].fns.GetHead()); + } + } + CorrectComboListWidth(m_cbMRU); + + CRecentFileList& MRUDub = s.MRUDub; + MRUDub.ReadList(); + m_cbMRUDub.ResetContent(); + for (int i = 0; i < MRUDub.GetSize(); i++) { + if (!MRUDub[i].IsEmpty()) { + m_cbMRUDub.AddString(MRUDub[i]); + } + } + CorrectComboListWidth(m_cbMRUDub); + + if (m_cbMRU.GetCount() > 0) { + m_cbMRU.SetCurSel(0); + } + + m_fns.RemoveAll(); + m_path.Empty(); + m_pathDub.Empty(); + m_bMultipleFiles = false; + m_bAppendToPlaylist = FALSE; + + AddAnchor(m_cbMRU, TOP_LEFT, TOP_RIGHT); + AddAnchor(m_cbMRUDub, TOP_LEFT, TOP_RIGHT); + AddAnchor(IDC_BUTTON1, TOP_RIGHT); + AddAnchor(IDC_BUTTON2, TOP_RIGHT); + AddAnchor(IDOK, TOP_RIGHT); + AddAnchor(IDCANCEL, TOP_RIGHT); + AddAnchor(IDC_STATIC1, TOP_LEFT, TOP_RIGHT); + + CRect r; + GetWindowRect(r); + CSize size = r.Size(); + SetMinTrackSize(size); + size.cx = 1000; + SetMaxTrackSize(size); + + fulfillThemeReqs(); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +static CString GetFileName(CString str) +{ + CPath p = str; + p.StripPath(); + return (LPCTSTR)p; +} + +void COpenDlg::OnBrowseFile() +{ + UpdateData(); + + CAppSettings& s = AfxGetAppSettings(); + + CString filter; + CAtlArray mask; + s.m_Formats.GetFilter(filter, mask); + + DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR; + if (!s.fKeepHistory) { + dwFlags |= OFN_DONTADDTORECENT; + } + + COpenFileDlg fd(mask, true, nullptr, m_path, dwFlags, filter, this); + if (m_path.IsEmpty() && s.fKeepHistory && !s.lastQuickOpenPath.IsEmpty()) { + fd.m_ofn.lpstrInitialDir = s.lastQuickOpenPath; + } + if (fd.DoModal() != IDOK) { + return; + } + + m_fns.RemoveAll(); + + POSITION pos = fd.GetStartPosition(); + while (pos) { + m_fns.AddTail(fd.GetNextPathName(pos)); + } + + if (!m_fns.IsEmpty()) { + if (s.fKeepHistory) { + s.lastQuickOpenPath = PathUtils::DirName(m_fns.GetHead()); + } + + if (m_fns.GetCount() > 1) { + m_bMultipleFiles = true; + EndDialog(IDOK); + return; + } else if (m_fns.GetHead()[m_fns.GetHead().GetLength() - 1] == '\\' || m_fns.GetHead()[m_fns.GetHead().GetLength() - 1] == '*') { + m_bMultipleFiles = true; + EndDialog(IDOK); + return; + } + } + + m_cbMRU.SetWindowText(fd.GetPathName()); +} + +void COpenDlg::OnBrowseDubFile() +{ + UpdateData(); + + const CAppSettings& s = AfxGetAppSettings(); + + CString filter; + CAtlArray mask; + s.m_Formats.GetAudioFilter(filter, mask); + + DWORD dwFlags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ENABLEINCLUDENOTIFY | OFN_NOCHANGEDIR; + if (!s.fKeepHistory) { + dwFlags |= OFN_DONTADDTORECENT; + } + + COpenFileDlg fd(mask, false, nullptr, m_pathDub, dwFlags, filter, this); + if (m_pathDub.IsEmpty() && s.fKeepHistory && !s.lastQuickOpenPath.IsEmpty()) { + fd.m_ofn.lpstrInitialDir = s.lastQuickOpenPath; + } + if (fd.DoModal() != IDOK) { + return; + } + + m_cbMRUDub.SetWindowText(fd.GetPathName()); +} + +void COpenDlg::OnOk() +{ + UpdateData(); + + m_fns.RemoveAll(); + m_fns.AddTail(PathUtils::Unquote(m_path)); + if (m_cbMRUDub.IsWindowEnabled() && !m_pathDub.IsEmpty()) { + m_fns.AddTail(PathUtils::Unquote(m_pathDub)); + } + + m_bMultipleFiles = false; + + OnOK(); +} + +void COpenDlg::OnUpdateDub(CCmdUI* pCmdUI) +{ + UpdateData(); + pCmdUI->Enable(AfxGetAppSettings().m_Formats.GetEngine(m_path) == DirectShow); +} + +void COpenDlg::OnUpdateOk(CCmdUI* pCmdUI) +{ + UpdateData(); + pCmdUI->Enable(!m_path.IsEmpty() || !m_pathDub.IsEmpty()); +} diff --git a/src/mpc-hc/OpenDlg.h b/src/mpc-hc/OpenDlg.h index 07902266c95..b1ecd01168f 100644 --- a/src/mpc-hc/OpenDlg.h +++ b/src/mpc-hc/OpenDlg.h @@ -1,68 +1,68 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "resource.h" -#include "CMPCThemeResizableDialog.h" -#include "CMPCThemeStatic.h" -#include "CMPCThemeComboBox.h" - -// COpenDlg dialog - -class COpenDlg : public CMPCThemeResizableDialog -{ - // DECLARE_DYNAMIC(COpenDlg) -private: - CStatic m_icon; - CMPCThemeComboBox m_cbMRU; - CString m_path; - CMPCThemeComboBox m_cbMRUDub; - CString m_pathDub; - CMPCThemeStatic m_labelDub; - BOOL m_bAppendToPlaylist; - - bool m_bMultipleFiles; - CAtlList m_fns; - -public: - COpenDlg(CWnd* pParent = nullptr); - virtual ~COpenDlg(); - - // Dialog Data - enum { IDD = IDD_OPEN_DLG }; - - const CAtlList& GetFileNames() const { return m_fns; } - bool HasMultipleFiles() const { return m_bMultipleFiles; } - bool GetAppendToPlaylist() const { return !!m_bAppendToPlaylist; } - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - - DECLARE_MESSAGE_MAP() - - afx_msg void OnBrowseFile(); - afx_msg void OnBrowseDubFile(); - afx_msg void OnOk(); - afx_msg void OnUpdateDub(CCmdUI* pCmdUI); - afx_msg void OnUpdateOk(CCmdUI* pCmdUI); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "resource.h" +#include "CMPCThemeResizableDialog.h" +#include "CMPCThemeStatic.h" +#include "CMPCThemeComboBox.h" + +// COpenDlg dialog + +class COpenDlg : public CMPCThemeResizableDialog +{ + // DECLARE_DYNAMIC(COpenDlg) +private: + CStatic m_icon; + CMPCThemeComboBox m_cbMRU; + CString m_path; + CMPCThemeComboBox m_cbMRUDub; + CString m_pathDub; + CMPCThemeStatic m_labelDub; + BOOL m_bAppendToPlaylist; + + bool m_bMultipleFiles; + CAtlList m_fns; + +public: + COpenDlg(CWnd* pParent = nullptr); + virtual ~COpenDlg(); + + // Dialog Data + enum { IDD = IDD_OPEN_DLG }; + + const CAtlList& GetFileNames() const { return m_fns; } + bool HasMultipleFiles() const { return m_bMultipleFiles; } + bool GetAppendToPlaylist() const { return !!m_bAppendToPlaylist; } + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnBrowseFile(); + afx_msg void OnBrowseDubFile(); + afx_msg void OnOk(); + afx_msg void OnUpdateDub(CCmdUI* pCmdUI); + afx_msg void OnUpdateOk(CCmdUI* pCmdUI); +}; diff --git a/src/mpc-hc/OpenFileDlg.cpp b/src/mpc-hc/OpenFileDlg.cpp index 910119038a2..f7bdc68cd10 100644 --- a/src/mpc-hc/OpenFileDlg.cpp +++ b/src/mpc-hc/OpenFileDlg.cpp @@ -1,237 +1,237 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015, 2017 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 . - * - */ - -#include "stdafx.h" -#include -#include -#include "OpenFileDlg.h" - -#define __DUMMY__ _T("*.*") - -bool COpenFileDlg::m_fAllowDirSelection = false; -WNDPROC COpenFileDlg::m_wndProc = nullptr; - - -// COpenFileDlg - -IMPLEMENT_DYNAMIC(COpenFileDlg, CFileDialog) -COpenFileDlg::COpenFileDlg(CAtlArray& mask, bool fAllowDirSelection, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, - DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) - : CFileDialog(TRUE, lpszDefExt, lpszFileName, dwFlags | OFN_NOVALIDATE, lpszFilter, pParentWnd, 0) - , m_mask(mask) -{ - m_defaultDir = lpszFileName; - m_defaultDir.RemoveFileSpec(); - - m_fAllowDirSelection = fAllowDirSelection; - m_pOFN->lpstrInitialDir = m_defaultDir.FileExists() ? (LPCTSTR)m_defaultDir : nullptr; - - m_buff = DEBUG_NEW TCHAR[10000]; - m_buff[0] = 0; - m_pOFN->lpstrFile = m_buff; - m_pOFN->nMaxFile = 10000; -} - -COpenFileDlg::~COpenFileDlg() -{ - delete [] m_buff; -} - -BEGIN_MESSAGE_MAP(COpenFileDlg, CFileDialog) - ON_WM_DESTROY() -END_MESSAGE_MAP() - - -// COpenFileDlg message handlers - -LRESULT CALLBACK COpenFileDlg::WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK - && m_fAllowDirSelection) { - CAutoVectorPtr path; - // MAX_PATH should be bigger for multiple selection, but we are only interested if it's zero length - // note: allocating MAX_PATH only will cause a buffer overrun for too long strings, and will result in a silent app disappearing crash, 100% reproducible - if (path.Allocate(MAX_PATH + 1) && ::GetDlgItemText(hwnd, cmb13, (TCHAR*)path, MAX_PATH) == 0) { - ::SendMessage(hwnd, CDM_SETCONTROLTEXT, edt1, (LPARAM)__DUMMY__); - } - } - - return CallWindowProc(COpenFileDlg::m_wndProc, hwnd, message, wParam, lParam); -} - -BOOL COpenFileDlg::OnInitDialog() -{ - CFileDialog::OnInitDialog(); - - m_wndProc = (WNDPROC)SetWindowLongPtr(GetParent()->m_hWnd, GWLP_WNDPROC, (LONG_PTR)WindowProcNew); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void COpenFileDlg::OnDestroy() -{ - int i = GetPathName().Find(__DUMMY__); - if (i >= 0) { - m_pOFN->lpstrFile[i] = m_pOFN->lpstrFile[i + 1] = 0; - } - - CFileDialog::OnDestroy(); -} - -BOOL COpenFileDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) -{ - ASSERT(pResult != nullptr); - - OFNOTIFY* pNotify = (OFNOTIFY*)lParam; - // allow message map to override - if (__super::OnNotify(wParam, lParam, pResult)) { - ASSERT(pNotify->hdr.code != CDN_INCLUDEITEM); - return TRUE; - } - - switch (pNotify->hdr.code) { - case CDN_INCLUDEITEM: - if (OnIncludeItem((OFNOTIFYEX*)lParam, pResult)) { - return TRUE; - } - break; - } - - return FALSE; // not handled -} - -BOOL COpenFileDlg::OnIncludeItem(OFNOTIFYEX* pOFNEx, LRESULT* pResult) -{ - CString fn; - if (!SHGetPathFromIDList((PIDLIST_ABSOLUTE)pOFNEx->pidl, fn.GetBuffer(MAX_PATH))) { - fn.ReleaseBuffer(0); - IShellFolder* psf = (IShellFolder*)pOFNEx->psf; - PCUITEMID_CHILD pidl = (PCUITEMID_CHILD)pOFNEx->pidl; - STRRET s; - CComHeapPtr fnTmp; - if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &s)) - && SUCCEEDED(StrRetToStr(&s, pidl, &fnTmp))) { - fn = fnTmp; - } - } else { - fn.ReleaseBuffer(); - } - - /* - WIN32_FILE_ATTRIBUTE_DATA fad; - if (GetFileAttributesEx(fn, GetFileExInfoStandard, &fad) - && (fad.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) - return FALSE; - */ - int i = fn.ReverseFind('.'), j = fn.ReverseFind('\\'); - if (i < 0 || i < j) { - return FALSE; - } - - CString mask = m_mask[pOFNEx->lpOFN->nFilterIndex - 1] + _T(";"); - CString ext = fn.Mid(i).MakeLower() + _T(";"); - - *pResult = mask.Find(ext) >= 0 || mask.Find(_T("*.*")) >= 0; - - return TRUE; -} - -// override CFileDialog::GetNextPathName() and increase max path length -CString COpenFileDlg::GetNextPathName(POSITION& pos) const -{ - BOOL bExplorer = m_ofn.Flags & OFN_EXPLORER; - TCHAR chDelimiter; - if (bExplorer) - chDelimiter = '\0'; - else - chDelimiter = ' '; - - LPTSTR lpsz = (LPTSTR)pos; - if (lpsz == m_ofn.lpstrFile) // first time - { - if ((m_ofn.Flags & OFN_ALLOWMULTISELECT) == 0) - { - pos = NULL; - return m_ofn.lpstrFile; - } - - // find char pos after first Delimiter - while (*lpsz != chDelimiter && *lpsz != '\0') - lpsz = _tcsinc(lpsz); - lpsz = _tcsinc(lpsz); - - // if single selection then return only selection - if (*lpsz == 0) - { - pos = NULL; - return m_ofn.lpstrFile; - } - } - - CString strBasePath = m_ofn.lpstrFile; - if (!bExplorer) - { - LPTSTR lpszPath = m_ofn.lpstrFile; - while (*lpszPath != chDelimiter) - lpszPath = _tcsinc(lpszPath); - strBasePath = strBasePath.Left(int(lpszPath - m_ofn.lpstrFile)); - } - - LPTSTR lpszFileName = lpsz; - CString strFileName = lpsz; - - // find char pos at next Delimiter - while (*lpsz != chDelimiter && *lpsz != '\0') - lpsz = _tcsinc(lpsz); - - if (!bExplorer && *lpsz == '\0') - pos = NULL; - else - { - if (!bExplorer) - strFileName = strFileName.Left(int(lpsz - lpszFileName)); - - lpsz = _tcsinc(lpsz); - if (*lpsz == '\0') // if double terminated then done - pos = NULL; - else - pos = (POSITION)lpsz; - } - - TCHAR strDrive[_MAX_DRIVE], strDir[4 * _MAX_DIR], strName[4 * _MAX_FNAME], strExt[_MAX_EXT]; - Checked::tsplitpath_s(strFileName, strDrive, _MAX_DRIVE, strDir, 4 * _MAX_DIR, strName, 4 * _MAX_FNAME, strExt, _MAX_EXT); - TCHAR strPath[4 * _MAX_PATH]; - if (*strDrive || *strDir) - { - Checked::tcscpy_s(strPath, _countof(strPath), strFileName); - } else - { - if ((strBasePath.GetLength() != 3) || (strBasePath[1] != ':') || (strBasePath[2] != '\\')) - { - strBasePath += _T("\\"); - } - Checked::tsplitpath_s(strBasePath, strDrive, _MAX_DRIVE, strDir, 4 * _MAX_DIR, NULL, 0, NULL, 0); - Checked::tmakepath_s(strPath, 4 * _MAX_PATH, strDrive, strDir, strName, strExt); - } - - return strPath; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015, 2017 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 . + * + */ + +#include "stdafx.h" +#include +#include +#include "OpenFileDlg.h" + +#define __DUMMY__ _T("*.*") + +bool COpenFileDlg::m_fAllowDirSelection = false; +WNDPROC COpenFileDlg::m_wndProc = nullptr; + + +// COpenFileDlg + +IMPLEMENT_DYNAMIC(COpenFileDlg, CFileDialog) +COpenFileDlg::COpenFileDlg(CAtlArray& mask, bool fAllowDirSelection, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, + DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) + : CFileDialog(TRUE, lpszDefExt, lpszFileName, dwFlags | OFN_NOVALIDATE, lpszFilter, pParentWnd, 0) + , m_mask(mask) +{ + m_defaultDir = lpszFileName; + m_defaultDir.RemoveFileSpec(); + + m_fAllowDirSelection = fAllowDirSelection; + m_pOFN->lpstrInitialDir = m_defaultDir.FileExists() ? (LPCTSTR)m_defaultDir : nullptr; + + m_buff = DEBUG_NEW TCHAR[10000]; + m_buff[0] = 0; + m_pOFN->lpstrFile = m_buff; + m_pOFN->nMaxFile = 10000; +} + +COpenFileDlg::~COpenFileDlg() +{ + delete [] m_buff; +} + +BEGIN_MESSAGE_MAP(COpenFileDlg, CFileDialog) + ON_WM_DESTROY() +END_MESSAGE_MAP() + + +// COpenFileDlg message handlers + +LRESULT CALLBACK COpenFileDlg::WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK + && m_fAllowDirSelection) { + CAutoVectorPtr path; + // MAX_PATH should be bigger for multiple selection, but we are only interested if it's zero length + // note: allocating MAX_PATH only will cause a buffer overrun for too long strings, and will result in a silent app disappearing crash, 100% reproducible + if (path.Allocate(MAX_PATH + 1) && ::GetDlgItemText(hwnd, cmb13, (TCHAR*)path, MAX_PATH) == 0) { + ::SendMessage(hwnd, CDM_SETCONTROLTEXT, edt1, (LPARAM)__DUMMY__); + } + } + + return CallWindowProc(COpenFileDlg::m_wndProc, hwnd, message, wParam, lParam); +} + +BOOL COpenFileDlg::OnInitDialog() +{ + CFileDialog::OnInitDialog(); + + m_wndProc = (WNDPROC)SetWindowLongPtr(GetParent()->m_hWnd, GWLP_WNDPROC, (LONG_PTR)WindowProcNew); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void COpenFileDlg::OnDestroy() +{ + int i = GetPathName().Find(__DUMMY__); + if (i >= 0) { + m_pOFN->lpstrFile[i] = m_pOFN->lpstrFile[i + 1] = 0; + } + + CFileDialog::OnDestroy(); +} + +BOOL COpenFileDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) +{ + ASSERT(pResult != nullptr); + + OFNOTIFY* pNotify = (OFNOTIFY*)lParam; + // allow message map to override + if (__super::OnNotify(wParam, lParam, pResult)) { + ASSERT(pNotify->hdr.code != CDN_INCLUDEITEM); + return TRUE; + } + + switch (pNotify->hdr.code) { + case CDN_INCLUDEITEM: + if (OnIncludeItem((OFNOTIFYEX*)lParam, pResult)) { + return TRUE; + } + break; + } + + return FALSE; // not handled +} + +BOOL COpenFileDlg::OnIncludeItem(OFNOTIFYEX* pOFNEx, LRESULT* pResult) +{ + CString fn; + if (!SHGetPathFromIDList((PIDLIST_ABSOLUTE)pOFNEx->pidl, fn.GetBuffer(MAX_PATH))) { + fn.ReleaseBuffer(0); + IShellFolder* psf = (IShellFolder*)pOFNEx->psf; + PCUITEMID_CHILD pidl = (PCUITEMID_CHILD)pOFNEx->pidl; + STRRET s; + CComHeapPtr fnTmp; + if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_FORPARSING, &s)) + && SUCCEEDED(StrRetToStr(&s, pidl, &fnTmp))) { + fn = fnTmp; + } + } else { + fn.ReleaseBuffer(); + } + + /* + WIN32_FILE_ATTRIBUTE_DATA fad; + if (GetFileAttributesEx(fn, GetFileExInfoStandard, &fad) + && (fad.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) + return FALSE; + */ + int i = fn.ReverseFind('.'), j = fn.ReverseFind('\\'); + if (i < 0 || i < j) { + return FALSE; + } + + CString mask = m_mask[pOFNEx->lpOFN->nFilterIndex - 1] + _T(";"); + CString ext = fn.Mid(i).MakeLower() + _T(";"); + + *pResult = mask.Find(ext) >= 0 || mask.Find(_T("*.*")) >= 0; + + return TRUE; +} + +// override CFileDialog::GetNextPathName() and increase max path length +CString COpenFileDlg::GetNextPathName(POSITION& pos) const +{ + BOOL bExplorer = m_ofn.Flags & OFN_EXPLORER; + TCHAR chDelimiter; + if (bExplorer) + chDelimiter = '\0'; + else + chDelimiter = ' '; + + LPTSTR lpsz = (LPTSTR)pos; + if (lpsz == m_ofn.lpstrFile) // first time + { + if ((m_ofn.Flags & OFN_ALLOWMULTISELECT) == 0) + { + pos = NULL; + return m_ofn.lpstrFile; + } + + // find char pos after first Delimiter + while (*lpsz != chDelimiter && *lpsz != '\0') + lpsz = _tcsinc(lpsz); + lpsz = _tcsinc(lpsz); + + // if single selection then return only selection + if (*lpsz == 0) + { + pos = NULL; + return m_ofn.lpstrFile; + } + } + + CString strBasePath = m_ofn.lpstrFile; + if (!bExplorer) + { + LPTSTR lpszPath = m_ofn.lpstrFile; + while (*lpszPath != chDelimiter) + lpszPath = _tcsinc(lpszPath); + strBasePath = strBasePath.Left(int(lpszPath - m_ofn.lpstrFile)); + } + + LPTSTR lpszFileName = lpsz; + CString strFileName = lpsz; + + // find char pos at next Delimiter + while (*lpsz != chDelimiter && *lpsz != '\0') + lpsz = _tcsinc(lpsz); + + if (!bExplorer && *lpsz == '\0') + pos = NULL; + else + { + if (!bExplorer) + strFileName = strFileName.Left(int(lpsz - lpszFileName)); + + lpsz = _tcsinc(lpsz); + if (*lpsz == '\0') // if double terminated then done + pos = NULL; + else + pos = (POSITION)lpsz; + } + + TCHAR strDrive[_MAX_DRIVE], strDir[4 * _MAX_DIR], strName[4 * _MAX_FNAME], strExt[_MAX_EXT]; + Checked::tsplitpath_s(strFileName, strDrive, _MAX_DRIVE, strDir, 4 * _MAX_DIR, strName, 4 * _MAX_FNAME, strExt, _MAX_EXT); + TCHAR strPath[4 * _MAX_PATH]; + if (*strDrive || *strDir) + { + Checked::tcscpy_s(strPath, _countof(strPath), strFileName); + } else + { + if ((strBasePath.GetLength() != 3) || (strBasePath[1] != ':') || (strBasePath[2] != '\\')) + { + strBasePath += _T("\\"); + } + Checked::tsplitpath_s(strBasePath, strDrive, _MAX_DRIVE, strDir, 4 * _MAX_DIR, NULL, 0, NULL, 0); + Checked::tmakepath_s(strPath, 4 * _MAX_PATH, strDrive, strDir, strName, strExt); + } + + return strPath; +} diff --git a/src/mpc-hc/OpenFileDlg.h b/src/mpc-hc/OpenFileDlg.h index f9cb428e381..4b4d7089eb4 100644 --- a/src/mpc-hc/OpenFileDlg.h +++ b/src/mpc-hc/OpenFileDlg.h @@ -1,62 +1,62 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include - - -// COpenFileDlg - -class COpenFileDlg : public CFileDialog -{ - DECLARE_DYNAMIC(COpenFileDlg) - -private: - TCHAR* m_buff; - CAtlArray& m_mask; - CPath m_defaultDir; - -public: - COpenFileDlg(CAtlArray& mask, bool fAllowDirSelection, - LPCTSTR lpszDefExt = nullptr, - LPCTSTR lpszFileName = nullptr, - DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, - LPCTSTR lpszFilter = nullptr, - CWnd* pParentWnd = nullptr); - virtual ~COpenFileDlg(); - - static bool m_fAllowDirSelection; - static WNDPROC m_wndProc; - static LRESULT CALLBACK WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - - virtual BOOL OnInitDialog(); - -protected: - DECLARE_MESSAGE_MAP() - virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); - virtual BOOL OnIncludeItem(OFNOTIFYEX* pOFNEx, LRESULT* pResult); - -public: - afx_msg void OnDestroy(); - CString GetNextPathName(POSITION& pos) const; -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include + + +// COpenFileDlg + +class COpenFileDlg : public CFileDialog +{ + DECLARE_DYNAMIC(COpenFileDlg) + +private: + TCHAR* m_buff; + CAtlArray& m_mask; + CPath m_defaultDir; + +public: + COpenFileDlg(CAtlArray& mask, bool fAllowDirSelection, + LPCTSTR lpszDefExt = nullptr, + LPCTSTR lpszFileName = nullptr, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + LPCTSTR lpszFilter = nullptr, + CWnd* pParentWnd = nullptr); + virtual ~COpenFileDlg(); + + static bool m_fAllowDirSelection; + static WNDPROC m_wndProc; + static LRESULT CALLBACK WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + + virtual BOOL OnInitDialog(); + +protected: + DECLARE_MESSAGE_MAP() + virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); + virtual BOOL OnIncludeItem(OFNOTIFYEX* pOFNEx, LRESULT* pResult); + +public: + afx_msg void OnDestroy(); + CString GetNextPathName(POSITION& pos) const; +}; diff --git a/src/mpc-hc/PPageAccelTbl.cpp b/src/mpc-hc/PPageAccelTbl.cpp index 42b65b29966..486babd6eb9 100644 --- a/src/mpc-hc/PPageAccelTbl.cpp +++ b/src/mpc-hc/PPageAccelTbl.cpp @@ -1,1452 +1,1452 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "PPageAccelTbl.h" -#include "AppSettings.h" - -#define DUP_KEY (1<<12) -#define DUP_APPCMD (1<<13) -#define DUP_RMCMD (1<<14) -#define MASK_DUP (DUP_KEY|DUP_APPCMD|DUP_RMCMD) - -struct APP_COMMAND { - UINT appcmd; - LPCTSTR cmdname; -}; - -static constexpr APP_COMMAND g_CommandList[] = { - {0, _T("")}, - {APPCOMMAND_MEDIA_PLAY_PAUSE, _T("MEDIA_PLAY_PAUSE")}, - {APPCOMMAND_MEDIA_PLAY, _T("MEDIA_PLAY")}, - {APPCOMMAND_MEDIA_PAUSE, _T("MEDIA_PAUSE")}, - {APPCOMMAND_MEDIA_STOP, _T("MEDIA_STOP")}, - {APPCOMMAND_MEDIA_NEXTTRACK, _T("MEDIA_NEXTTRACK")}, - {APPCOMMAND_MEDIA_PREVIOUSTRACK, _T("MEDIA_PREVIOUSTRACK")}, - {APPCOMMAND_MEDIA_FAST_FORWARD, _T("MEDIA_FAST_FORWARD")}, - {APPCOMMAND_MEDIA_REWIND, _T("MEDIA_REWIND")}, - {APPCOMMAND_MEDIA_CHANNEL_UP, _T("MEDIA_CHANNEL_UP")}, - {APPCOMMAND_MEDIA_CHANNEL_DOWN, _T("MEDIA_CHANNEL_DOWN")}, - {APPCOMMAND_MEDIA_RECORD, _T("MEDIA_RECORD")}, - {APPCOMMAND_VOLUME_DOWN, _T("VOLUME_DOWN")}, - {APPCOMMAND_VOLUME_UP, _T("VOLUME_UP")}, - {APPCOMMAND_VOLUME_MUTE, _T("VOLUME_MUTE")}, - {APPCOMMAND_LAUNCH_MEDIA_SELECT, _T("LAUNCH_MEDIA_SELECT")}, - /* - {APPCOMMAND_BROWSER_BACKWARD, _T("BROWSER_BACKWARD")}, - {APPCOMMAND_BROWSER_FORWARD, _T("BROWSER_FORWARD")}, - {APPCOMMAND_BROWSER_REFRESH, _T("BROWSER_REFRESH")}, - {APPCOMMAND_BROWSER_STOP, _T("BROWSER_STOP")}, - {APPCOMMAND_BROWSER_SEARCH, _T("BROWSER_SEARCH")}, - {APPCOMMAND_BROWSER_FAVORITES, _T("BROWSER_FAVORITES")}, - {APPCOMMAND_BROWSER_HOME, _T("BROWSER_HOME")}, - */ - {APPCOMMAND_LAUNCH_APP1, _T("LAUNCH_APP1")}, - {APPCOMMAND_LAUNCH_APP2, _T("LAUNCH_APP2")}, - {APPCOMMAND_OPEN, _T("OPEN")}, - {APPCOMMAND_CLOSE, _T("CLOSE")}, - {APPCOMMAND_DELETE, _T("DELETE")}, - {MCE_DETAILS, _T("MCE_DETAILS")}, - {MCE_GUIDE, _T("MCE_GUIDE")}, - {MCE_TVJUMP, _T("MCE_TVJUMP")}, - {MCE_STANDBY, _T("MCE_STANDBY")}, - {MCE_OEM1, _T("MCE_OEM1")}, - {MCE_OEM2, _T("MCE_OEM2")}, - {MCE_MYTV, _T("MCE_MYTV")}, - {MCE_MYVIDEOS, _T("MCE_MYVIDEOS")}, - {MCE_MYPICTURES, _T("MCE_MYPICTURES")}, - {MCE_MYMUSIC, _T("MCE_MYMUSIC")}, - {MCE_RECORDEDTV, _T("MCE_RECORDEDTV")}, - {MCE_DVDANGLE, _T("MCE_DVDANGLE")}, - {MCE_DVDAUDIO, _T("MCE_DVDAUDIO")}, - {MCE_DVDMENU, _T("MCE_DVDMENU")}, - {MCE_DVDSUBTITLE, _T("MCE_DVDSUBTITLE")}, - {MCE_RED, _T("MCE_RED")}, - {MCE_GREEN, _T("MCE_GREEN")}, - {MCE_YELLOW, _T("MCE_YELLOW")}, - {MCE_BLUE, _T("MCE_BLUE")}, - {MCE_MEDIA_NEXTTRACK, _T("MCE_MEDIA_NEXTTRACK")}, - {MCE_MEDIA_PREVIOUSTRACK, _T("MCE_MEDIA_PREVIOUSTRACK")} -}; - -// CPPageAccelTbl dialog - -IMPLEMENT_DYNAMIC(CPPageAccelTbl, CMPCThemePPageBase) -CPPageAccelTbl::CPPageAccelTbl() - : CMPCThemePPageBase(CPPageAccelTbl::IDD, CPPageAccelTbl::IDD) - , m_counter(0) - , m_list(0) - , m_fWinLirc(FALSE) - , m_WinLircLink(_T("http://winlirc.sourceforge.net/")) - , m_fUIce(FALSE) - , m_UIceLink(L"https://web.archive.org/web/20160609195532/http://www.mediatexx.com/") // home site no longer works - , m_nStatusTimerID(0) - , filterTimerID(0) - , sortDirection(HDF_SORTUP) - , m_fGlobalMedia(FALSE) -{ -} - -CPPageAccelTbl::~CPPageAccelTbl() -{ -} - -BOOL CPPageAccelTbl::PreTranslateMessage(MSG* pMsg) -{ - if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN - && (pMsg->hwnd == m_WinLircEdit.m_hWnd || pMsg->hwnd == m_UIceEdit.m_hWnd)) { - OnApply(); - return TRUE; - } - - return __super::PreTranslateMessage(pMsg); -} - -void CPPageAccelTbl::UpdateKeyDupFlags() -{ - for (int row = 0; row < m_list.GetItemCount(); row++) { - auto itemData = (ITEMDATA*)m_list.GetItemData(row); - const wmcmd& wc = m_wmcmds.GetAt(itemData->index); - - itemData->flag &= ~DUP_KEY; - - if (wc.key) { - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; m_wmcmds.GetNext(pos)) { - if (itemData->index == pos) { continue; } - - if (wc.key == m_wmcmds.GetAt(pos).key && (wc.fVirt & (FCONTROL | FALT | FSHIFT)) == (m_wmcmds.GetAt(pos).fVirt & (FCONTROL | FALT | FSHIFT))) { - itemData->flag |= DUP_KEY; - break; - } - } - } - } -} - -void CPPageAccelTbl::UpdateAppcmdDupFlags() -{ - for (int row = 0; row < m_list.GetItemCount(); row++) { - auto itemData = (ITEMDATA*)m_list.GetItemData(row); - const wmcmd& wc = m_wmcmds.GetAt(itemData->index); - - itemData->flag &= ~DUP_APPCMD; - - if (wc.appcmd) { - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; m_wmcmds.GetNext(pos)) { - if (itemData->index == pos) { continue; } - - if (wc.appcmd == m_wmcmds.GetAt(pos).appcmd) { - itemData->flag |= DUP_APPCMD; - break; - } - } - } - } -} - -void CPPageAccelTbl::UpdateRmcmdDupFlags() -{ - for (int row = 0; row < m_list.GetItemCount(); row++) { - auto itemData = (ITEMDATA*)m_list.GetItemData(row); - const wmcmd& wc = m_wmcmds.GetAt(itemData->index); - - itemData->flag &= ~DUP_RMCMD; - - if (wc.rmcmd.GetLength()) { - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; m_wmcmds.GetNext(pos)) { - if (itemData->index == pos) { continue; } - - if (wc.rmcmd.CompareNoCase(m_wmcmds.GetAt(pos).rmcmd) == 0) { - itemData->flag |= DUP_RMCMD; - break; - } - } - } - } -} - -void CPPageAccelTbl::UpdateAllDupFlags() -{ - UpdateKeyDupFlags(); - UpdateAppcmdDupFlags(); - UpdateRmcmdDupFlags(); -} - -void CPPageAccelTbl::SetupList(bool allowResize) -{ - for (int row = 0; row < m_list.GetItemCount(); row++) { - wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(row))->index); - - CString hotkey; - HotkeyModToString(wc.key, wc.fVirt, hotkey); - m_list.SetItemText(row, COL_KEY, hotkey); - - CString id; - id.Format(_T("%u"), wc.cmd); - m_list.SetItemText(row, COL_ID, id); - - m_list.SetItemText(row, COL_APPCMD, MakeAppCommandLabel(wc.appcmd)); - - m_list.SetItemText(row, COL_RMCMD, CString(wc.rmcmd)); - - CString repcnt; - repcnt.Format(_T("%d"), wc.rmrepcnt); - m_list.SetItemText(row, COL_RMREPCNT, repcnt); - } - - UpdateAllDupFlags(); - - if (allowResize) { - for (int nCol = COL_CMD; nCol <= COL_RMREPCNT; nCol++) { - m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE); - int contentSize = m_list.GetColumnWidth(nCol); - m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE_USEHEADER); - if (contentSize > m_list.GetColumnWidth(nCol)) { - m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE); - } - } - for (int nCol = COL_CMD; nCol <= COL_RMREPCNT; nCol++) { - int contentSize = m_list.GetColumnWidth(nCol); - m_list.SetColumnWidth(nCol, contentSize); - } - } -} - -CString CPPageAccelTbl::MakeAccelModLabel(BYTE fVirt) -{ - CString str; - if (fVirt & FCONTROL) { - if (!str.IsEmpty()) { - str += _T(" + "); - } - str += _T("Ctrl"); - } - if (fVirt & FALT) { - if (!str.IsEmpty()) { - str += _T(" + "); - } - str += _T("Alt"); - } - if (fVirt & FSHIFT) { - if (!str.IsEmpty()) { - str += _T(" + "); - } - str += _T("Shift"); - } - if (str.IsEmpty()) { - str.LoadString(IDS_AG_NONE); - } - return str; -} - -CString CPPageAccelTbl::MakeAccelShortcutLabel(UINT id) -{ - CList& wmcmds = AfxGetAppSettings().wmcmds; - POSITION pos = wmcmds.GetHeadPosition(); - while (pos) { - ACCEL& a = wmcmds.GetNext(pos); - if (a.cmd == id) { - return (MakeAccelShortcutLabel(a)); - } - } - - return _T(""); -} - -CString CPPageAccelTbl::MakeAccelShortcutLabel(const ACCEL& a) -{ - if (!a.key) { - return _T(""); - } - - // Reference page for Virtual-Key Codes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.100%29.aspx - CString str; - - switch (a.key) { - case VK_LBUTTON: - str = _T("LBtn"); - break; - case VK_RBUTTON: - str = _T("RBtn"); - break; - case VK_CANCEL: - str = _T("Cancel"); - break; - case VK_MBUTTON: - str = _T("MBtn"); - break; - case VK_XBUTTON1: - str = _T("X1Btn"); - break; - case VK_XBUTTON2: - str = _T("X2Btn"); - break; - case VK_BACK: - str = _T("Back"); - break; - case VK_TAB: - str = _T("Tab"); - break; - case VK_CLEAR: - str = _T("Clear"); - break; - case VK_RETURN: - str = _T("Enter"); - break; - case VK_SHIFT: - str = _T("Shift"); - break; - case VK_CONTROL: - str = _T("Ctrl"); - break; - case VK_MENU: - str = _T("Alt"); - break; - case VK_PAUSE: - str = _T("Pause"); - break; - case VK_CAPITAL: - str = _T("Capital"); - break; - // case VK_KANA: str = _T("Kana"); break; - // case VK_HANGEUL: str = _T("Hangeul"); break; - case VK_HANGUL: - str = _T("Hangul"); - break; - case VK_JUNJA: - str = _T("Junja"); - break; - case VK_FINAL: - str = _T("Final"); - break; - // case VK_HANJA: str = _T("Hanja"); break; - case VK_KANJI: - str = _T("Kanji"); - break; - case VK_ESCAPE: - str = _T("Escape"); - break; - case VK_CONVERT: - str = _T("Convert"); - break; - case VK_NONCONVERT: - str = _T("Non Convert"); - break; - case VK_ACCEPT: - str = _T("Accept"); - break; - case VK_MODECHANGE: - str = _T("Mode Change"); - break; - case VK_SPACE: - str = _T("Space"); - break; - case VK_PRIOR: - str = _T("PgUp"); - break; - case VK_NEXT: - str = _T("PgDn"); - break; - case VK_END: - str = _T("End"); - break; - case VK_HOME: - str = _T("Home"); - break; - case VK_LEFT: - str = _T("Left"); - break; - case VK_UP: - str = _T("Up"); - break; - case VK_RIGHT: - str = _T("Right"); - break; - case VK_DOWN: - str = _T("Down"); - break; - case VK_SELECT: - str = _T("Select"); - break; - case VK_PRINT: - str = _T("Print"); - break; - case VK_EXECUTE: - str = _T("Execute"); - break; - case VK_SNAPSHOT: - str = _T("Snapshot"); - break; - case VK_INSERT: - str = _T("Insert"); - break; - case VK_DELETE: - str = _T("Delete"); - break; - case VK_HELP: - str = _T("Help"); - break; - case VK_LWIN: - str = _T("LWin"); - break; - case VK_RWIN: - str = _T("RWin"); - break; - case VK_APPS: - str = _T("Apps"); - break; - case VK_SLEEP: - str = _T("Sleep"); - break; - case VK_NUMPAD0: - str = _T("Numpad 0"); - break; - case VK_NUMPAD1: - str = _T("Numpad 1"); - break; - case VK_NUMPAD2: - str = _T("Numpad 2"); - break; - case VK_NUMPAD3: - str = _T("Numpad 3"); - break; - case VK_NUMPAD4: - str = _T("Numpad 4"); - break; - case VK_NUMPAD5: - str = _T("Numpad 5"); - break; - case VK_NUMPAD6: - str = _T("Numpad 6"); - break; - case VK_NUMPAD7: - str = _T("Numpad 7"); - break; - case VK_NUMPAD8: - str = _T("Numpad 8"); - break; - case VK_NUMPAD9: - str = _T("Numpad 9"); - break; - case VK_MULTIPLY: - str = _T("Multiply"); - break; - case VK_ADD: - str = _T("Add"); - break; - case VK_SEPARATOR: - str = _T("Separator"); - break; - case VK_SUBTRACT: - str = _T("Subtract"); - break; - case VK_DECIMAL: - str = _T("Decimal"); - break; - case VK_DIVIDE: - str = _T("Divide"); - break; - case VK_F1: - str = _T("F1"); - break; - case VK_F2: - str = _T("F2"); - break; - case VK_F3: - str = _T("F3"); - break; - case VK_F4: - str = _T("F4"); - break; - case VK_F5: - str = _T("F5"); - break; - case VK_F6: - str = _T("F6"); - break; - case VK_F7: - str = _T("F7"); - break; - case VK_F8: - str = _T("F8"); - break; - case VK_F9: - str = _T("F9"); - break; - case VK_F10: - str = _T("F10"); - break; - case VK_F11: - str = _T("F11"); - break; - case VK_F12: - str = _T("F12"); - break; - case VK_F13: - str = _T("F13"); - break; - case VK_F14: - str = _T("F14"); - break; - case VK_F15: - str = _T("F15"); - break; - case VK_F16: - str = _T("F16"); - break; - case VK_F17: - str = _T("F17"); - break; - case VK_F18: - str = _T("F18"); - break; - case VK_F19: - str = _T("F19"); - break; - case VK_F20: - str = _T("F20"); - break; - case VK_F21: - str = _T("F21"); - break; - case VK_F22: - str = _T("F22"); - break; - case VK_F23: - str = _T("F23"); - break; - case VK_F24: - str = _T("F24"); - break; - case VK_NUMLOCK: - str = _T("Numlock"); - break; - case VK_SCROLL: - str = _T("Scroll"); - break; - // case VK_OEM_NEC_EQUAL: str = _T("OEM NEC Equal"); break; - case VK_OEM_FJ_JISHO: - str = _T("OEM FJ Jisho"); - break; - case VK_OEM_FJ_MASSHOU: - str = _T("OEM FJ Msshou"); - break; - case VK_OEM_FJ_TOUROKU: - str = _T("OEM FJ Touroku"); - break; - case VK_OEM_FJ_LOYA: - str = _T("OEM FJ Loya"); - break; - case VK_OEM_FJ_ROYA: - str = _T("OEM FJ Roya"); - break; - case VK_LSHIFT: - str = _T("LShift"); - break; - case VK_RSHIFT: - str = _T("RShift"); - break; - case VK_LCONTROL: - str = _T("LCtrl"); - break; - case VK_RCONTROL: - str = _T("RCtrl"); - break; - case VK_LMENU: - str = _T("LAlt"); - break; - case VK_RMENU: - str = _T("RAlt"); - break; - case VK_BROWSER_BACK: - str = _T("Browser Back"); - break; - case VK_BROWSER_FORWARD: - str = _T("Browser Forward"); - break; - case VK_BROWSER_REFRESH: - str = _T("Browser Refresh"); - break; - case VK_BROWSER_STOP: - str = _T("Browser Stop"); - break; - case VK_BROWSER_SEARCH: - str = _T("Browser Search"); - break; - case VK_BROWSER_FAVORITES: - str = _T("Browser Favorites"); - break; - case VK_BROWSER_HOME: - str = _T("Browser Home"); - break; - case VK_VOLUME_MUTE: - str = _T("Volume Mute"); - break; - case VK_VOLUME_DOWN: - str = _T("Volume Down"); - break; - case VK_VOLUME_UP: - str = _T("Volume Up"); - break; - case VK_MEDIA_NEXT_TRACK: - str = _T("Media Next Track"); - break; - case VK_MEDIA_PREV_TRACK: - str = _T("Media Prev Track"); - break; - case VK_MEDIA_STOP: - str = _T("Media Stop"); - break; - case VK_MEDIA_PLAY_PAUSE: - str = _T("Media Play/Pause"); - break; - case VK_LAUNCH_MAIL: - str = _T("Launch Mail"); - break; - case VK_LAUNCH_MEDIA_SELECT: - str = _T("Launch Media Select"); - break; - case VK_LAUNCH_APP1: - str = _T("Launch App1"); - break; - case VK_LAUNCH_APP2: - str = _T("Launch App2"); - break; - case VK_OEM_1: - str = _T("OEM 1"); - break; - case VK_OEM_PLUS: - str = _T("Plus"); - break; - case VK_OEM_COMMA: - str = _T("Comma"); - break; - case VK_OEM_MINUS: - str = _T("Minus"); - break; - case VK_OEM_PERIOD: - str = _T("Period"); - break; - case VK_OEM_2: - str = _T("OEM 2"); - break; - case VK_OEM_3: - str = _T("`"); - break; - case VK_OEM_4: - str = _T("["); - break; - case VK_OEM_5: - str = _T("OEM 5"); - break; - case VK_OEM_6: - str = _T("]"); - break; - case VK_OEM_7: - str = _T("OEM 7"); - break; - case VK_OEM_8: - str = _T("OEM 8"); - break; - case VK_OEM_AX: - str = _T("OEM AX"); - break; - case VK_OEM_102: - str = _T("OEM 102"); - break; - case VK_ICO_HELP: - str = _T("ICO Help"); - break; - case VK_ICO_00: - str = _T("ICO 00"); - break; - case VK_PROCESSKEY: - str = _T("Process Key"); - break; - case VK_ICO_CLEAR: - str = _T("ICO Clear"); - break; - case VK_PACKET: - str = _T("Packet"); - break; - case VK_OEM_RESET: - str = _T("OEM Reset"); - break; - case VK_OEM_JUMP: - str = _T("OEM Jump"); - break; - case VK_OEM_PA1: - str = _T("OEM PA1"); - break; - case VK_OEM_PA2: - str = _T("OEM PA2"); - break; - case VK_OEM_PA3: - str = _T("OEM PA3"); - break; - case VK_OEM_WSCTRL: - str = _T("OEM WSCtrl"); - break; - case VK_OEM_CUSEL: - str = _T("OEM CUSEL"); - break; - case VK_OEM_ATTN: - str = _T("OEM ATTN"); - break; - case VK_OEM_FINISH: - str = _T("OEM Finish"); - break; - case VK_OEM_COPY: - str = _T("OEM Copy"); - break; - case VK_OEM_AUTO: - str = _T("OEM Auto"); - break; - case VK_OEM_ENLW: - str = _T("OEM ENLW"); - break; - case VK_OEM_BACKTAB: - str = _T("OEM Backtab"); - break; - case VK_ATTN: - str = _T("ATTN"); - break; - case VK_CRSEL: - str = _T("CRSEL"); - break; - case VK_EXSEL: - str = _T("EXSEL"); - break; - case VK_EREOF: - str = _T("EREOF"); - break; - case VK_PLAY: - str = _T("Play"); - break; - case VK_ZOOM: - str = _T("Zoom"); - break; - case VK_NONAME: - str = _T("Noname"); - break; - case VK_PA1: - str = _T("PA1"); - break; - case VK_OEM_CLEAR: - str = _T("OEM Clear"); - break; - case 0x07: - case 0x0E: - case 0x0F: - case 0x16: - case 0x1A: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - str.Format(_T("Undefined (0x%02x)"), (TCHAR)a.key); - break; - case 0x0A: - case 0x0B: - case 0x5E: - case 0xB8: - case 0xB9: - case 0xC1: - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xE0: - str.Format(_T("Reserved (0x%02x)"), (TCHAR)a.key); - break; - case 0x88: - case 0x89: - case 0x8A: - case 0x8B: - case 0x8C: - case 0x8D: - case 0x8E: - case 0x8F: - case 0x97: - case 0x98: - case 0x99: - case 0x9A: - case 0x9B: - case 0x9C: - case 0x9D: - case 0x9E: - case 0x9F: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xE8: - str.Format(_T("Unassigned (0x%02x)"), (TCHAR)a.key); - break; - case 0xFF: - str = _T("Multimedia keys"); - break; - default: - str.Format(_T("%c"), (TCHAR)a.key); - break; - } - - if (a.fVirt & (FCONTROL | FALT | FSHIFT)) { - str = MakeAccelModLabel(a.fVirt) + _T(" + ") + str; - } - - str.Replace(_T(" + "), _T("+")); - - return str; -} - -CString CPPageAccelTbl::MakeAppCommandLabel(UINT id) -{ - for (int i = 0; i < _countof(g_CommandList); i++) { - if (g_CommandList[i].appcmd == id) { - return CString(g_CommandList[i].cmdname); - } - } - return id == 0 ? _T("") : _T("Invalid"); -} - -void CPPageAccelTbl::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Text(pDX, IDC_EDIT1, m_WinLircAddr); - DDX_Control(pDX, IDC_EDIT1, m_WinLircEdit); - DDX_Control(pDX, IDC_STATICLINK, m_WinLircLink); - DDX_Check(pDX, IDC_CHECK1, m_fWinLirc); - DDX_Text(pDX, IDC_EDIT2, m_UIceAddr); - DDX_Control(pDX, IDC_EDIT2, m_UIceEdit); - DDX_Control(pDX, IDC_EDIT3, filterEdit); - DDX_Control(pDX, IDC_STATICLINK2, m_UIceLink); - DDX_Check(pDX, IDC_CHECK9, m_fUIce); - DDX_Check(pDX, IDC_CHECK2, m_fGlobalMedia); -} - -BEGIN_MESSAGE_MAP(CPPageAccelTbl, CPPageBase) - ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_LIST1, OnBeginListLabelEdit) - ON_NOTIFY(LVN_DOLABELEDIT, IDC_LIST1, OnDoListLabelEdit) - ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST1, OnEndListLabelEdit) - ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnListColumnClick) - ON_EN_CHANGE(IDC_EDIT3, OnChangeFilterEdit) - ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSelectAll) - ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedReset) - ON_WM_TIMER() - ON_WM_CTLCOLOR() - ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST1, OnCustomdrawList) -END_MESSAGE_MAP() - -// CPPageAccelTbl message handlers - -static 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)) { - CPlayerListCtrl* pList = (CPlayerListCtrl*)CWnd::FromHandle(control); - - for (int i = 0, j = pList->GetItemCount(); i < j; i++) { - pList->SetItemState(i, LVIS_SELECTED, LVIS_SELECTED); - } - - return 0; - } - } - - return CallWindowProc(OldControlProc, control, message, wParam, lParam); // call control's own windowproc -} - -BOOL CPPageAccelTbl::OnInitDialog() -{ - __super::OnInitDialog(); - - CAppSettings& s = AfxGetAppSettings(); - - m_wmcmds.RemoveAll(); - m_wmcmds.AddTail(&s.wmcmds); - m_fWinLirc = s.fWinLirc; - m_WinLircAddr = s.strWinLircAddr; - m_fUIce = s.fUIce; - m_UIceAddr = s.strUIceAddr; - m_fGlobalMedia = s.fGlobalMedia; - - CString text; - text.Format(IDS_STRING_COLON, _T("WinLIRC")); - m_WinLircLink.SetWindowText(text); - text.Format(IDS_STRING_COLON, _T("uICE")); - m_UIceLink.SetWindowText(text); - - UpdateData(FALSE); - - CRect r; - GetDlgItem(IDC_PLACEHOLDER)->GetWindowRect(r); - ScreenToClient(r); - - m_list.CreateEx( - WS_EX_CLIENTEDGE, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | LVS_REPORT | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS, - r, this, IDC_LIST1); - - //m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES ); - m_list.setAdditionalStyles(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES); - m_list.setColorInterface(this); - - //this list was created dynamically but lives in a dialog. if we don't inherit the parent font, - //it will be scaled by text zoom settings, which looks bad in an unscaled dialog - CFont* curDialogFont = GetFont(); - if (curDialogFont && curDialogFont->m_hObject) { - m_list.SetFont(curDialogFont); - } - - for (int i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++) { - m_list.DeleteColumn(0); - } - m_list.InsertColumn(COL_CMD, ResStr(IDS_AG_COMMAND), LVCFMT_LEFT, 80); - m_list.InsertColumn(COL_KEY, ResStr(IDS_AG_KEY), LVCFMT_LEFT, 80); - m_list.InsertColumn(COL_ID, _T("ID"), LVCFMT_LEFT, 40); - m_list.InsertColumn(COL_APPCMD, ResStr(IDS_AG_APP_COMMAND), LVCFMT_LEFT, 120); - m_list.InsertColumn(COL_RMCMD, _T("RemoteCmd"), LVCFMT_LEFT, 80); - m_list.InsertColumn(COL_RMREPCNT, _T("RepCnt"), LVCFMT_CENTER, 60); - - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; m_wmcmds.GetNext(pos)) { - int row = m_list.InsertItem(m_list.GetItemCount(), m_wmcmds.GetAt(pos).GetName(), COL_CMD); - auto itemData = std::make_unique(); - itemData->index = pos; - m_list.SetItemData(row, (DWORD_PTR)itemData.get()); - m_pItemsData.push_back(std::move(itemData)); - } - - SetupList(); - - m_list.SetColumnWidth(COL_CMD, LVSCW_AUTOSIZE); - m_list.SetColumnWidth(COL_KEY, LVSCW_AUTOSIZE); - m_list.SetColumnWidth(COL_ID, LVSCW_AUTOSIZE_USEHEADER); - - // subclass the keylist control - OldControlProc = (WNDPROC)SetWindowLongPtr(m_list.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 -} - -BOOL CPPageAccelTbl::OnApply() -{ - AfxGetMyApp()->UnregisterHotkeys(); - UpdateData(); - - CAppSettings& s = AfxGetAppSettings(); - - s.wmcmds.RemoveAll(); - s.wmcmds.AddTail(&m_wmcmds); - - if (s.hAccel) { - DestroyAcceleratorTable(s.hAccel); - } - - CAtlArray pAccel; - pAccel.SetCount(ACCEL_LIST_SIZE); - int accel_count = 0; - POSITION pos = m_wmcmds.GetHeadPosition(); - for (int i = 0; pos; i++) { - ACCEL x = m_wmcmds.GetNext(pos); - if (x.key > 0) { - pAccel[accel_count] = x; - accel_count++; - } - } - s.hAccel = CreateAcceleratorTable(pAccel.GetData(), accel_count); - - CFrameWnd* parent = GetParentFrame(); - if (parent) { - parent->m_hAccelTable = s.hAccel; - } - - s.fWinLirc = !!m_fWinLirc; - s.strWinLircAddr = m_WinLircAddr; - if (s.fWinLirc) { - s.WinLircClient.Connect(m_WinLircAddr); - } - s.fUIce = !!m_fUIce; - s.strUIceAddr = m_UIceAddr; - if (s.fUIce) { - s.UIceClient.Connect(m_UIceAddr); - } - s.fGlobalMedia = !!m_fGlobalMedia; - - AfxGetMyApp()->RegisterHotkeys(); - - return __super::OnApply(); -} - -void CPPageAccelTbl::OnBnClickedSelectAll() -{ - m_list.SetFocus(); - - for (int i = 0, j = m_list.GetItemCount(); i < j; i++) { - m_list.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED); - } -} - -void CPPageAccelTbl::OnBnClickedReset() -{ - m_list.SetFocus(); - - POSITION pos = m_list.GetFirstSelectedItemPosition(); - if (!pos) { - return; - } - - while (pos) { - int ni = m_list.GetNextSelectedItem(pos); - POSITION pi = ((ITEMDATA*)m_list.GetItemData(ni))->index; - wmcmd& wc = m_wmcmds.GetAt(pi); - wc.Restore(); - } - - SetupList(); - - SetModified(); -} - -void CPPageAccelTbl::OnChangeFilterEdit() -{ - KillTimer(filterTimerID); - filterTimerID = SetTimer(2, 100, NULL); -} - -void CPPageAccelTbl::FilterList() -{ - CString filter; - filterEdit.GetWindowText(filter); - LANGID langid = AfxGetAppSettings().language; - filter = NormalizeUnicodeStrForSearch(filter, langid); - - m_list.SetRedraw(false); - m_list.DeleteAllItems(); - m_pItemsData.clear(); - - POSITION pos = m_wmcmds.GetHeadPosition(); - for (; pos; ) { - CString hotkey, id, name, sname; - - wmcmd& wc = m_wmcmds.GetAt(pos); - - HotkeyModToString(wc.key, wc.fVirt, hotkey); - id.Format(_T("%u"), wc.cmd); - sname = wc.GetName(); - - sname = NormalizeUnicodeStrForSearch(sname, langid); - id = NormalizeUnicodeStrForSearch(id, langid); - hotkey = NormalizeUnicodeStrForSearch(hotkey, langid); - - if (filter.IsEmpty() || sname.Find(filter) != -1 || hotkey.Find(filter) != -1 || id.Find(filter) != -1) { - int row = m_list.InsertItem(m_list.GetItemCount(), wc.GetName(), COL_CMD); - auto itemData = std::make_unique(); - itemData->index = pos; - m_list.SetItemData(row, (DWORD_PTR)itemData.get()); - m_pItemsData.push_back(std::move(itemData)); - } - m_wmcmds.GetNext(pos); - } - SetupList(false); - m_list.SetRedraw(true); - m_list.RedrawWindow(); -} - -void CPPageAccelTbl::GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) { - auto itemData = (ITEMDATA*)m_list.GetItemData(nItem); - auto dup = itemData->flag; - if (iSubItem == COL_CMD && dup - || iSubItem == COL_KEY && (dup & DUP_KEY) - || iSubItem == COL_APPCMD && (dup & DUP_APPCMD) - || iSubItem == COL_RMCMD && (dup & DUP_RMCMD)) { - if (AppIsThemeLoaded()) { - clrTextBk = CMPCTheme::ListCtrlErrorColor; - overrideSelectedBG = true; - } else { - clrTextBk = RGB(255, 130, 120); - } - } else { - if (AppIsThemeLoaded()) { - clrTextBk = CMPCTheme::ContentBGColor; - } else { - clrTextBk = GetSysColor(COLOR_WINDOW); - } - } -} - -void CPPageAccelTbl::GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) { - horzGridColor = CMPCTheme::ListCtrlGridColor; - vertGridColor = CMPCTheme::ListCtrlGridColor; -} - -void CPPageAccelTbl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult) { - NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); - *pResult = CDRF_DODEFAULT; - - if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage) { - *pResult = CDRF_NOTIFYITEMDRAW; - } else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage) { - *pResult = CDRF_NOTIFYSUBITEMDRAW; - } else if ((CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage) { - bool ignore; - GetCustomTextColors(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, pLVCD->clrText, pLVCD->clrTextBk, ignore); - *pResult = CDRF_DODEFAULT; - } -} - -void CPPageAccelTbl::OnBeginListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (pItem->iItem < 0) { - return; - } - - if (pItem->iSubItem == COL_KEY || pItem->iSubItem == COL_APPCMD || pItem->iSubItem == COL_RMCMD || pItem->iSubItem == COL_RMREPCNT) { - *pResult = TRUE; - } -} - -static BYTE s_mods[] = {0, FALT, FCONTROL, FSHIFT, FCONTROL | FALT, FCONTROL | FSHIFT, FALT | FSHIFT, FCONTROL | FALT | FSHIFT}; - -void CPPageAccelTbl::OnDoListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - if (pItem->iItem < 0) { - *pResult = FALSE; - return; - } - - *pResult = TRUE; - - - wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(pItem->iItem))->index); - - CAtlList sl; - int nSel = -1; - - auto createHotkey = [&](auto virt, auto key) { - m_list.ShowInPlaceWinHotkey(pItem->iItem, pItem->iSubItem); - CWinHotkeyCtrl* pWinHotkey = (CWinHotkeyCtrl*)m_list.GetDlgItem(IDC_WINHOTKEY1); - UINT cod = 0, mod = 0; - if (virt & FALT) { - mod |= MOD_ALT; - } - if (virt & FCONTROL) { - mod |= MOD_CONTROL; - } - if (virt & FSHIFT) { - mod |= MOD_SHIFT; - } - cod = key; - pWinHotkey->SetWinHotkey(cod, mod); - }; - - switch (pItem->iSubItem) { - case COL_KEY: - createHotkey(wc.fVirt, wc.key); - break; - case COL_APPCMD: - for (int i = 0; i < _countof(g_CommandList); i++) { - sl.AddTail(g_CommandList[i].cmdname); - if (wc.appcmd == g_CommandList[i].appcmd) { - nSel = i; - } - } - - m_list.ShowInPlaceComboBox(pItem->iItem, pItem->iSubItem, sl, nSel); - break; - case COL_RMCMD: - m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem); - break; - case COL_RMREPCNT: - m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem); - break; - default: - *pResult = FALSE; - break; - } -} - -int CPPageAccelTbl::CompareFunc(LPARAM lParam1, LPARAM lParam2) -{ - int result; - - CString strItem1 = m_list.GetItemText(static_cast(lParam1), sortColumn); - CString strItem2 = m_list.GetItemText(static_cast(lParam2), sortColumn); - if (sortColumn == COL_ID || sortColumn == COL_RMREPCNT) { - wmcmd& wc1 = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(static_cast(lParam1)))->index); - wmcmd& wc2 = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(static_cast(lParam2)))->index); - - result = wc1.cmd == wc2.cmd ? 0 : (wc1.cmd < wc2.cmd ? -1 : 1); - } else { - result = strItem1.Compare(strItem2); - } - - if (sortDirection == HDF_SORTUP) { - return result; - } else { - return -result; - } -} - -static int CALLBACK StaticCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) -{ - CPPageAccelTbl* ppAccelTbl = (CPPageAccelTbl*)lParamSort; - return ppAccelTbl->CompareFunc(lParam1, lParam2); -} - -void CPPageAccelTbl::UpdateHeaderSort(int column, int sort) -{ - CHeaderCtrl* hdr = m_list.GetHeaderCtrl(); - HDITEMW hItem = { 0 }; - hItem.mask = HDI_FORMAT; - if (hdr->GetItem(column, &hItem)) { - if (sort == HDF_SORTUP) { - hItem.fmt |= HDF_SORTUP; - hItem.fmt &= ~HDF_SORTDOWN; - } else if (sort == HDF_SORTDOWN) { - hItem.fmt |= HDF_SORTDOWN; - hItem.fmt &= ~HDF_SORTUP; - } else { //no sort - hItem.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); - } - hdr->SetItem(column, &hItem); - } -} - -void CPPageAccelTbl::OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult) -{ - NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; - int colToSort = pNMListView->iSubItem; - if (colToSort == sortColumn) { - sortDirection = sortDirection == HDF_SORTUP ? HDF_SORTDOWN : HDF_SORTUP; - } else { - if (sortColumn != -1) { - UpdateHeaderSort(sortColumn, 0); //clear old sort - } - sortColumn = colToSort; - sortDirection = HDF_SORTUP; - } - m_list.SortItemsEx(StaticCompareFunc, (LPARAM)this); - UpdateHeaderSort(sortColumn, sortDirection); -} - -void CPPageAccelTbl::OnEndListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) -{ - LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; - LV_ITEM* pItem = &pDispInfo->item; - - *pResult = FALSE; - - if (!m_list.m_fInPlaceDirty) { - return; - } - - if (pItem->iItem < 0) { - return; - } - wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(pItem->iItem))->index); - - auto updateHotkey = [&](auto &virt, auto &key) { - UINT cod, mod; - CWinHotkeyCtrl* pWinHotkey = (CWinHotkeyCtrl*)m_list.GetDlgItem(IDC_WINHOTKEY1); - pWinHotkey->GetWinHotkey(&cod, &mod); - ASSERT(cod < WORD_MAX); - key = (WORD)cod; - virt = FVIRTKEY; - if (mod & MOD_ALT) { - virt |= FALT; - } - if (mod & MOD_CONTROL) { - virt |= FCONTROL; - } - if (mod & MOD_SHIFT) { - virt |= FSHIFT; - } - - CString str; - HotkeyToString(key, mod, str); - m_list.SetItemText(pItem->iItem, pItem->iSubItem, str); - - *pResult = TRUE; - UpdateKeyDupFlags(); - }; - - WORD discard; - switch (pItem->iSubItem) { - case COL_KEY: - updateHotkey(wc.fVirt, wc.key); - break; - case COL_APPCMD: { - ptrdiff_t i = pItem->lParam; - if (i >= 0 && i < _countof(g_CommandList)) { - wc.appcmd = g_CommandList[i].appcmd; - m_list.SetItemText(pItem->iItem, COL_APPCMD, pItem->pszText); - *pResult = TRUE; - UpdateAppcmdDupFlags(); - } - } - break; - case COL_RMCMD: { - CString cmd = pItem->pszText; - cmd.Trim(); - cmd.Replace(_T(' '), ('_')); - m_list.SetItemText(pItem->iItem, pItem->iSubItem, cmd); - wc.rmcmd = cmd; - *pResult = TRUE; - UpdateRmcmdDupFlags(); - break; - } - case COL_RMREPCNT: - CString str = pItem->pszText; - wc.rmrepcnt = _tcstol(str.Trim(), nullptr, 10); - str.Format(_T("%d"), wc.rmrepcnt); - m_list.SetItemText(pItem->iItem, pItem->iSubItem, str); - *pResult = TRUE; - break; - } - - if (*pResult) { - m_list.RedrawWindow(); - SetModified(); - } -} - -void CPPageAccelTbl::OnTimer(UINT_PTR nIDEvent) -{ - if (nIDEvent == m_nStatusTimerID) { - UpdateData(); - - CAppSettings& s = AfxGetAppSettings(); - - if (m_fWinLirc) { - CString addr; - m_WinLircEdit.GetWindowText(addr); - s.WinLircClient.Connect(addr); - } - - m_WinLircEdit.Invalidate(); - - if (m_fUIce) { - CString addr; - m_UIceEdit.GetWindowText(addr); - s.UIceClient.Connect(addr); - } - - m_UIceEdit.Invalidate(); - - m_counter++; - } else if (nIDEvent == filterTimerID) { - KillTimer(filterTimerID); - FilterList(); - } else { - __super::OnTimer(nIDEvent); - } -} - -HBRUSH CPPageAccelTbl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) -{ - HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); - - const CAppSettings& s = AfxGetAppSettings(); - if (AppIsThemeLoaded()) { - return hbr; //should have already been handled inside themed ctlcolor - } - int status = -1; - - if (*pWnd == m_WinLircEdit) { - status = s.WinLircClient.GetStatus(); - } else if (*pWnd == m_UIceEdit) { - status = s.UIceClient.GetStatus(); - } - - if (status == 0 || status == 2 && (m_counter & 1)) { - pDC->SetTextColor(0x0000ff); - } else if (status == 1) { - pDC->SetTextColor(0x008000); - } - - return hbr; -} - -BOOL CPPageAccelTbl::OnSetActive() -{ - m_nStatusTimerID = SetTimer(1, 1000, nullptr); - - return CPPageBase::OnSetActive(); -} - -BOOL CPPageAccelTbl::OnKillActive() -{ - KillTimer(m_nStatusTimerID); - m_nStatusTimerID = 0; - - return CPPageBase::OnKillActive(); -} - -void CPPageAccelTbl::OnCancel() -{ - CAppSettings& s = AfxGetAppSettings(); - - if (!s.fWinLirc) { - s.WinLircClient.DisConnect(); - } - if (!s.fUIce) { - s.UIceClient.DisConnect(); - } - - __super::OnCancel(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "PPageAccelTbl.h" +#include "AppSettings.h" + +#define DUP_KEY (1<<12) +#define DUP_APPCMD (1<<13) +#define DUP_RMCMD (1<<14) +#define MASK_DUP (DUP_KEY|DUP_APPCMD|DUP_RMCMD) + +struct APP_COMMAND { + UINT appcmd; + LPCTSTR cmdname; +}; + +static constexpr APP_COMMAND g_CommandList[] = { + {0, _T("")}, + {APPCOMMAND_MEDIA_PLAY_PAUSE, _T("MEDIA_PLAY_PAUSE")}, + {APPCOMMAND_MEDIA_PLAY, _T("MEDIA_PLAY")}, + {APPCOMMAND_MEDIA_PAUSE, _T("MEDIA_PAUSE")}, + {APPCOMMAND_MEDIA_STOP, _T("MEDIA_STOP")}, + {APPCOMMAND_MEDIA_NEXTTRACK, _T("MEDIA_NEXTTRACK")}, + {APPCOMMAND_MEDIA_PREVIOUSTRACK, _T("MEDIA_PREVIOUSTRACK")}, + {APPCOMMAND_MEDIA_FAST_FORWARD, _T("MEDIA_FAST_FORWARD")}, + {APPCOMMAND_MEDIA_REWIND, _T("MEDIA_REWIND")}, + {APPCOMMAND_MEDIA_CHANNEL_UP, _T("MEDIA_CHANNEL_UP")}, + {APPCOMMAND_MEDIA_CHANNEL_DOWN, _T("MEDIA_CHANNEL_DOWN")}, + {APPCOMMAND_MEDIA_RECORD, _T("MEDIA_RECORD")}, + {APPCOMMAND_VOLUME_DOWN, _T("VOLUME_DOWN")}, + {APPCOMMAND_VOLUME_UP, _T("VOLUME_UP")}, + {APPCOMMAND_VOLUME_MUTE, _T("VOLUME_MUTE")}, + {APPCOMMAND_LAUNCH_MEDIA_SELECT, _T("LAUNCH_MEDIA_SELECT")}, + /* + {APPCOMMAND_BROWSER_BACKWARD, _T("BROWSER_BACKWARD")}, + {APPCOMMAND_BROWSER_FORWARD, _T("BROWSER_FORWARD")}, + {APPCOMMAND_BROWSER_REFRESH, _T("BROWSER_REFRESH")}, + {APPCOMMAND_BROWSER_STOP, _T("BROWSER_STOP")}, + {APPCOMMAND_BROWSER_SEARCH, _T("BROWSER_SEARCH")}, + {APPCOMMAND_BROWSER_FAVORITES, _T("BROWSER_FAVORITES")}, + {APPCOMMAND_BROWSER_HOME, _T("BROWSER_HOME")}, + */ + {APPCOMMAND_LAUNCH_APP1, _T("LAUNCH_APP1")}, + {APPCOMMAND_LAUNCH_APP2, _T("LAUNCH_APP2")}, + {APPCOMMAND_OPEN, _T("OPEN")}, + {APPCOMMAND_CLOSE, _T("CLOSE")}, + {APPCOMMAND_DELETE, _T("DELETE")}, + {MCE_DETAILS, _T("MCE_DETAILS")}, + {MCE_GUIDE, _T("MCE_GUIDE")}, + {MCE_TVJUMP, _T("MCE_TVJUMP")}, + {MCE_STANDBY, _T("MCE_STANDBY")}, + {MCE_OEM1, _T("MCE_OEM1")}, + {MCE_OEM2, _T("MCE_OEM2")}, + {MCE_MYTV, _T("MCE_MYTV")}, + {MCE_MYVIDEOS, _T("MCE_MYVIDEOS")}, + {MCE_MYPICTURES, _T("MCE_MYPICTURES")}, + {MCE_MYMUSIC, _T("MCE_MYMUSIC")}, + {MCE_RECORDEDTV, _T("MCE_RECORDEDTV")}, + {MCE_DVDANGLE, _T("MCE_DVDANGLE")}, + {MCE_DVDAUDIO, _T("MCE_DVDAUDIO")}, + {MCE_DVDMENU, _T("MCE_DVDMENU")}, + {MCE_DVDSUBTITLE, _T("MCE_DVDSUBTITLE")}, + {MCE_RED, _T("MCE_RED")}, + {MCE_GREEN, _T("MCE_GREEN")}, + {MCE_YELLOW, _T("MCE_YELLOW")}, + {MCE_BLUE, _T("MCE_BLUE")}, + {MCE_MEDIA_NEXTTRACK, _T("MCE_MEDIA_NEXTTRACK")}, + {MCE_MEDIA_PREVIOUSTRACK, _T("MCE_MEDIA_PREVIOUSTRACK")} +}; + +// CPPageAccelTbl dialog + +IMPLEMENT_DYNAMIC(CPPageAccelTbl, CMPCThemePPageBase) +CPPageAccelTbl::CPPageAccelTbl() + : CMPCThemePPageBase(CPPageAccelTbl::IDD, CPPageAccelTbl::IDD) + , m_counter(0) + , m_list(0) + , m_fWinLirc(FALSE) + , m_WinLircLink(_T("http://winlirc.sourceforge.net/")) + , m_fUIce(FALSE) + , m_UIceLink(L"https://web.archive.org/web/20160609195532/http://www.mediatexx.com/") // home site no longer works + , m_nStatusTimerID(0) + , filterTimerID(0) + , sortDirection(HDF_SORTUP) + , m_fGlobalMedia(FALSE) +{ +} + +CPPageAccelTbl::~CPPageAccelTbl() +{ +} + +BOOL CPPageAccelTbl::PreTranslateMessage(MSG* pMsg) +{ + if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN + && (pMsg->hwnd == m_WinLircEdit.m_hWnd || pMsg->hwnd == m_UIceEdit.m_hWnd)) { + OnApply(); + return TRUE; + } + + return __super::PreTranslateMessage(pMsg); +} + +void CPPageAccelTbl::UpdateKeyDupFlags() +{ + for (int row = 0; row < m_list.GetItemCount(); row++) { + auto itemData = (ITEMDATA*)m_list.GetItemData(row); + const wmcmd& wc = m_wmcmds.GetAt(itemData->index); + + itemData->flag &= ~DUP_KEY; + + if (wc.key) { + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; m_wmcmds.GetNext(pos)) { + if (itemData->index == pos) { continue; } + + if (wc.key == m_wmcmds.GetAt(pos).key && (wc.fVirt & (FCONTROL | FALT | FSHIFT)) == (m_wmcmds.GetAt(pos).fVirt & (FCONTROL | FALT | FSHIFT))) { + itemData->flag |= DUP_KEY; + break; + } + } + } + } +} + +void CPPageAccelTbl::UpdateAppcmdDupFlags() +{ + for (int row = 0; row < m_list.GetItemCount(); row++) { + auto itemData = (ITEMDATA*)m_list.GetItemData(row); + const wmcmd& wc = m_wmcmds.GetAt(itemData->index); + + itemData->flag &= ~DUP_APPCMD; + + if (wc.appcmd) { + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; m_wmcmds.GetNext(pos)) { + if (itemData->index == pos) { continue; } + + if (wc.appcmd == m_wmcmds.GetAt(pos).appcmd) { + itemData->flag |= DUP_APPCMD; + break; + } + } + } + } +} + +void CPPageAccelTbl::UpdateRmcmdDupFlags() +{ + for (int row = 0; row < m_list.GetItemCount(); row++) { + auto itemData = (ITEMDATA*)m_list.GetItemData(row); + const wmcmd& wc = m_wmcmds.GetAt(itemData->index); + + itemData->flag &= ~DUP_RMCMD; + + if (wc.rmcmd.GetLength()) { + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; m_wmcmds.GetNext(pos)) { + if (itemData->index == pos) { continue; } + + if (wc.rmcmd.CompareNoCase(m_wmcmds.GetAt(pos).rmcmd) == 0) { + itemData->flag |= DUP_RMCMD; + break; + } + } + } + } +} + +void CPPageAccelTbl::UpdateAllDupFlags() +{ + UpdateKeyDupFlags(); + UpdateAppcmdDupFlags(); + UpdateRmcmdDupFlags(); +} + +void CPPageAccelTbl::SetupList(bool allowResize) +{ + for (int row = 0; row < m_list.GetItemCount(); row++) { + wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(row))->index); + + CString hotkey; + HotkeyModToString(wc.key, wc.fVirt, hotkey); + m_list.SetItemText(row, COL_KEY, hotkey); + + CString id; + id.Format(_T("%u"), wc.cmd); + m_list.SetItemText(row, COL_ID, id); + + m_list.SetItemText(row, COL_APPCMD, MakeAppCommandLabel(wc.appcmd)); + + m_list.SetItemText(row, COL_RMCMD, CString(wc.rmcmd)); + + CString repcnt; + repcnt.Format(_T("%d"), wc.rmrepcnt); + m_list.SetItemText(row, COL_RMREPCNT, repcnt); + } + + UpdateAllDupFlags(); + + if (allowResize) { + for (int nCol = COL_CMD; nCol <= COL_RMREPCNT; nCol++) { + m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE); + int contentSize = m_list.GetColumnWidth(nCol); + m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE_USEHEADER); + if (contentSize > m_list.GetColumnWidth(nCol)) { + m_list.SetColumnWidth(nCol, LVSCW_AUTOSIZE); + } + } + for (int nCol = COL_CMD; nCol <= COL_RMREPCNT; nCol++) { + int contentSize = m_list.GetColumnWidth(nCol); + m_list.SetColumnWidth(nCol, contentSize); + } + } +} + +CString CPPageAccelTbl::MakeAccelModLabel(BYTE fVirt) +{ + CString str; + if (fVirt & FCONTROL) { + if (!str.IsEmpty()) { + str += _T(" + "); + } + str += _T("Ctrl"); + } + if (fVirt & FALT) { + if (!str.IsEmpty()) { + str += _T(" + "); + } + str += _T("Alt"); + } + if (fVirt & FSHIFT) { + if (!str.IsEmpty()) { + str += _T(" + "); + } + str += _T("Shift"); + } + if (str.IsEmpty()) { + str.LoadString(IDS_AG_NONE); + } + return str; +} + +CString CPPageAccelTbl::MakeAccelShortcutLabel(UINT id) +{ + CList& wmcmds = AfxGetAppSettings().wmcmds; + POSITION pos = wmcmds.GetHeadPosition(); + while (pos) { + ACCEL& a = wmcmds.GetNext(pos); + if (a.cmd == id) { + return (MakeAccelShortcutLabel(a)); + } + } + + return _T(""); +} + +CString CPPageAccelTbl::MakeAccelShortcutLabel(const ACCEL& a) +{ + if (!a.key) { + return _T(""); + } + + // Reference page for Virtual-Key Codes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.100%29.aspx + CString str; + + switch (a.key) { + case VK_LBUTTON: + str = _T("LBtn"); + break; + case VK_RBUTTON: + str = _T("RBtn"); + break; + case VK_CANCEL: + str = _T("Cancel"); + break; + case VK_MBUTTON: + str = _T("MBtn"); + break; + case VK_XBUTTON1: + str = _T("X1Btn"); + break; + case VK_XBUTTON2: + str = _T("X2Btn"); + break; + case VK_BACK: + str = _T("Back"); + break; + case VK_TAB: + str = _T("Tab"); + break; + case VK_CLEAR: + str = _T("Clear"); + break; + case VK_RETURN: + str = _T("Enter"); + break; + case VK_SHIFT: + str = _T("Shift"); + break; + case VK_CONTROL: + str = _T("Ctrl"); + break; + case VK_MENU: + str = _T("Alt"); + break; + case VK_PAUSE: + str = _T("Pause"); + break; + case VK_CAPITAL: + str = _T("Capital"); + break; + // case VK_KANA: str = _T("Kana"); break; + // case VK_HANGEUL: str = _T("Hangeul"); break; + case VK_HANGUL: + str = _T("Hangul"); + break; + case VK_JUNJA: + str = _T("Junja"); + break; + case VK_FINAL: + str = _T("Final"); + break; + // case VK_HANJA: str = _T("Hanja"); break; + case VK_KANJI: + str = _T("Kanji"); + break; + case VK_ESCAPE: + str = _T("Escape"); + break; + case VK_CONVERT: + str = _T("Convert"); + break; + case VK_NONCONVERT: + str = _T("Non Convert"); + break; + case VK_ACCEPT: + str = _T("Accept"); + break; + case VK_MODECHANGE: + str = _T("Mode Change"); + break; + case VK_SPACE: + str = _T("Space"); + break; + case VK_PRIOR: + str = _T("PgUp"); + break; + case VK_NEXT: + str = _T("PgDn"); + break; + case VK_END: + str = _T("End"); + break; + case VK_HOME: + str = _T("Home"); + break; + case VK_LEFT: + str = _T("Left"); + break; + case VK_UP: + str = _T("Up"); + break; + case VK_RIGHT: + str = _T("Right"); + break; + case VK_DOWN: + str = _T("Down"); + break; + case VK_SELECT: + str = _T("Select"); + break; + case VK_PRINT: + str = _T("Print"); + break; + case VK_EXECUTE: + str = _T("Execute"); + break; + case VK_SNAPSHOT: + str = _T("Snapshot"); + break; + case VK_INSERT: + str = _T("Insert"); + break; + case VK_DELETE: + str = _T("Delete"); + break; + case VK_HELP: + str = _T("Help"); + break; + case VK_LWIN: + str = _T("LWin"); + break; + case VK_RWIN: + str = _T("RWin"); + break; + case VK_APPS: + str = _T("Apps"); + break; + case VK_SLEEP: + str = _T("Sleep"); + break; + case VK_NUMPAD0: + str = _T("Numpad 0"); + break; + case VK_NUMPAD1: + str = _T("Numpad 1"); + break; + case VK_NUMPAD2: + str = _T("Numpad 2"); + break; + case VK_NUMPAD3: + str = _T("Numpad 3"); + break; + case VK_NUMPAD4: + str = _T("Numpad 4"); + break; + case VK_NUMPAD5: + str = _T("Numpad 5"); + break; + case VK_NUMPAD6: + str = _T("Numpad 6"); + break; + case VK_NUMPAD7: + str = _T("Numpad 7"); + break; + case VK_NUMPAD8: + str = _T("Numpad 8"); + break; + case VK_NUMPAD9: + str = _T("Numpad 9"); + break; + case VK_MULTIPLY: + str = _T("Multiply"); + break; + case VK_ADD: + str = _T("Add"); + break; + case VK_SEPARATOR: + str = _T("Separator"); + break; + case VK_SUBTRACT: + str = _T("Subtract"); + break; + case VK_DECIMAL: + str = _T("Decimal"); + break; + case VK_DIVIDE: + str = _T("Divide"); + break; + case VK_F1: + str = _T("F1"); + break; + case VK_F2: + str = _T("F2"); + break; + case VK_F3: + str = _T("F3"); + break; + case VK_F4: + str = _T("F4"); + break; + case VK_F5: + str = _T("F5"); + break; + case VK_F6: + str = _T("F6"); + break; + case VK_F7: + str = _T("F7"); + break; + case VK_F8: + str = _T("F8"); + break; + case VK_F9: + str = _T("F9"); + break; + case VK_F10: + str = _T("F10"); + break; + case VK_F11: + str = _T("F11"); + break; + case VK_F12: + str = _T("F12"); + break; + case VK_F13: + str = _T("F13"); + break; + case VK_F14: + str = _T("F14"); + break; + case VK_F15: + str = _T("F15"); + break; + case VK_F16: + str = _T("F16"); + break; + case VK_F17: + str = _T("F17"); + break; + case VK_F18: + str = _T("F18"); + break; + case VK_F19: + str = _T("F19"); + break; + case VK_F20: + str = _T("F20"); + break; + case VK_F21: + str = _T("F21"); + break; + case VK_F22: + str = _T("F22"); + break; + case VK_F23: + str = _T("F23"); + break; + case VK_F24: + str = _T("F24"); + break; + case VK_NUMLOCK: + str = _T("Numlock"); + break; + case VK_SCROLL: + str = _T("Scroll"); + break; + // case VK_OEM_NEC_EQUAL: str = _T("OEM NEC Equal"); break; + case VK_OEM_FJ_JISHO: + str = _T("OEM FJ Jisho"); + break; + case VK_OEM_FJ_MASSHOU: + str = _T("OEM FJ Msshou"); + break; + case VK_OEM_FJ_TOUROKU: + str = _T("OEM FJ Touroku"); + break; + case VK_OEM_FJ_LOYA: + str = _T("OEM FJ Loya"); + break; + case VK_OEM_FJ_ROYA: + str = _T("OEM FJ Roya"); + break; + case VK_LSHIFT: + str = _T("LShift"); + break; + case VK_RSHIFT: + str = _T("RShift"); + break; + case VK_LCONTROL: + str = _T("LCtrl"); + break; + case VK_RCONTROL: + str = _T("RCtrl"); + break; + case VK_LMENU: + str = _T("LAlt"); + break; + case VK_RMENU: + str = _T("RAlt"); + break; + case VK_BROWSER_BACK: + str = _T("Browser Back"); + break; + case VK_BROWSER_FORWARD: + str = _T("Browser Forward"); + break; + case VK_BROWSER_REFRESH: + str = _T("Browser Refresh"); + break; + case VK_BROWSER_STOP: + str = _T("Browser Stop"); + break; + case VK_BROWSER_SEARCH: + str = _T("Browser Search"); + break; + case VK_BROWSER_FAVORITES: + str = _T("Browser Favorites"); + break; + case VK_BROWSER_HOME: + str = _T("Browser Home"); + break; + case VK_VOLUME_MUTE: + str = _T("Volume Mute"); + break; + case VK_VOLUME_DOWN: + str = _T("Volume Down"); + break; + case VK_VOLUME_UP: + str = _T("Volume Up"); + break; + case VK_MEDIA_NEXT_TRACK: + str = _T("Media Next Track"); + break; + case VK_MEDIA_PREV_TRACK: + str = _T("Media Prev Track"); + break; + case VK_MEDIA_STOP: + str = _T("Media Stop"); + break; + case VK_MEDIA_PLAY_PAUSE: + str = _T("Media Play/Pause"); + break; + case VK_LAUNCH_MAIL: + str = _T("Launch Mail"); + break; + case VK_LAUNCH_MEDIA_SELECT: + str = _T("Launch Media Select"); + break; + case VK_LAUNCH_APP1: + str = _T("Launch App1"); + break; + case VK_LAUNCH_APP2: + str = _T("Launch App2"); + break; + case VK_OEM_1: + str = _T("OEM 1"); + break; + case VK_OEM_PLUS: + str = _T("Plus"); + break; + case VK_OEM_COMMA: + str = _T("Comma"); + break; + case VK_OEM_MINUS: + str = _T("Minus"); + break; + case VK_OEM_PERIOD: + str = _T("Period"); + break; + case VK_OEM_2: + str = _T("OEM 2"); + break; + case VK_OEM_3: + str = _T("`"); + break; + case VK_OEM_4: + str = _T("["); + break; + case VK_OEM_5: + str = _T("OEM 5"); + break; + case VK_OEM_6: + str = _T("]"); + break; + case VK_OEM_7: + str = _T("OEM 7"); + break; + case VK_OEM_8: + str = _T("OEM 8"); + break; + case VK_OEM_AX: + str = _T("OEM AX"); + break; + case VK_OEM_102: + str = _T("OEM 102"); + break; + case VK_ICO_HELP: + str = _T("ICO Help"); + break; + case VK_ICO_00: + str = _T("ICO 00"); + break; + case VK_PROCESSKEY: + str = _T("Process Key"); + break; + case VK_ICO_CLEAR: + str = _T("ICO Clear"); + break; + case VK_PACKET: + str = _T("Packet"); + break; + case VK_OEM_RESET: + str = _T("OEM Reset"); + break; + case VK_OEM_JUMP: + str = _T("OEM Jump"); + break; + case VK_OEM_PA1: + str = _T("OEM PA1"); + break; + case VK_OEM_PA2: + str = _T("OEM PA2"); + break; + case VK_OEM_PA3: + str = _T("OEM PA3"); + break; + case VK_OEM_WSCTRL: + str = _T("OEM WSCtrl"); + break; + case VK_OEM_CUSEL: + str = _T("OEM CUSEL"); + break; + case VK_OEM_ATTN: + str = _T("OEM ATTN"); + break; + case VK_OEM_FINISH: + str = _T("OEM Finish"); + break; + case VK_OEM_COPY: + str = _T("OEM Copy"); + break; + case VK_OEM_AUTO: + str = _T("OEM Auto"); + break; + case VK_OEM_ENLW: + str = _T("OEM ENLW"); + break; + case VK_OEM_BACKTAB: + str = _T("OEM Backtab"); + break; + case VK_ATTN: + str = _T("ATTN"); + break; + case VK_CRSEL: + str = _T("CRSEL"); + break; + case VK_EXSEL: + str = _T("EXSEL"); + break; + case VK_EREOF: + str = _T("EREOF"); + break; + case VK_PLAY: + str = _T("Play"); + break; + case VK_ZOOM: + str = _T("Zoom"); + break; + case VK_NONAME: + str = _T("Noname"); + break; + case VK_PA1: + str = _T("PA1"); + break; + case VK_OEM_CLEAR: + str = _T("OEM Clear"); + break; + case 0x07: + case 0x0E: + case 0x0F: + case 0x16: + case 0x1A: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + str.Format(_T("Undefined (0x%02x)"), (TCHAR)a.key); + break; + case 0x0A: + case 0x0B: + case 0x5E: + case 0xB8: + case 0xB9: + case 0xC1: + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xE0: + str.Format(_T("Reserved (0x%02x)"), (TCHAR)a.key); + break; + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xE8: + str.Format(_T("Unassigned (0x%02x)"), (TCHAR)a.key); + break; + case 0xFF: + str = _T("Multimedia keys"); + break; + default: + str.Format(_T("%c"), (TCHAR)a.key); + break; + } + + if (a.fVirt & (FCONTROL | FALT | FSHIFT)) { + str = MakeAccelModLabel(a.fVirt) + _T(" + ") + str; + } + + str.Replace(_T(" + "), _T("+")); + + return str; +} + +CString CPPageAccelTbl::MakeAppCommandLabel(UINT id) +{ + for (int i = 0; i < _countof(g_CommandList); i++) { + if (g_CommandList[i].appcmd == id) { + return CString(g_CommandList[i].cmdname); + } + } + return id == 0 ? _T("") : _T("Invalid"); +} + +void CPPageAccelTbl::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Text(pDX, IDC_EDIT1, m_WinLircAddr); + DDX_Control(pDX, IDC_EDIT1, m_WinLircEdit); + DDX_Control(pDX, IDC_STATICLINK, m_WinLircLink); + DDX_Check(pDX, IDC_CHECK1, m_fWinLirc); + DDX_Text(pDX, IDC_EDIT2, m_UIceAddr); + DDX_Control(pDX, IDC_EDIT2, m_UIceEdit); + DDX_Control(pDX, IDC_EDIT3, filterEdit); + DDX_Control(pDX, IDC_STATICLINK2, m_UIceLink); + DDX_Check(pDX, IDC_CHECK9, m_fUIce); + DDX_Check(pDX, IDC_CHECK2, m_fGlobalMedia); +} + +BEGIN_MESSAGE_MAP(CPPageAccelTbl, CPPageBase) + ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_LIST1, OnBeginListLabelEdit) + ON_NOTIFY(LVN_DOLABELEDIT, IDC_LIST1, OnDoListLabelEdit) + ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST1, OnEndListLabelEdit) + ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnListColumnClick) + ON_EN_CHANGE(IDC_EDIT3, OnChangeFilterEdit) + ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSelectAll) + ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedReset) + ON_WM_TIMER() + ON_WM_CTLCOLOR() + ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST1, OnCustomdrawList) +END_MESSAGE_MAP() + +// CPPageAccelTbl message handlers + +static 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)) { + CPlayerListCtrl* pList = (CPlayerListCtrl*)CWnd::FromHandle(control); + + for (int i = 0, j = pList->GetItemCount(); i < j; i++) { + pList->SetItemState(i, LVIS_SELECTED, LVIS_SELECTED); + } + + return 0; + } + } + + return CallWindowProc(OldControlProc, control, message, wParam, lParam); // call control's own windowproc +} + +BOOL CPPageAccelTbl::OnInitDialog() +{ + __super::OnInitDialog(); + + CAppSettings& s = AfxGetAppSettings(); + + m_wmcmds.RemoveAll(); + m_wmcmds.AddTail(&s.wmcmds); + m_fWinLirc = s.fWinLirc; + m_WinLircAddr = s.strWinLircAddr; + m_fUIce = s.fUIce; + m_UIceAddr = s.strUIceAddr; + m_fGlobalMedia = s.fGlobalMedia; + + CString text; + text.Format(IDS_STRING_COLON, _T("WinLIRC")); + m_WinLircLink.SetWindowText(text); + text.Format(IDS_STRING_COLON, _T("uICE")); + m_UIceLink.SetWindowText(text); + + UpdateData(FALSE); + + CRect r; + GetDlgItem(IDC_PLACEHOLDER)->GetWindowRect(r); + ScreenToClient(r); + + m_list.CreateEx( + WS_EX_CLIENTEDGE, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | LVS_REPORT | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS, + r, this, IDC_LIST1); + + //m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES ); + m_list.setAdditionalStyles(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES); + m_list.setColorInterface(this); + + //this list was created dynamically but lives in a dialog. if we don't inherit the parent font, + //it will be scaled by text zoom settings, which looks bad in an unscaled dialog + CFont* curDialogFont = GetFont(); + if (curDialogFont && curDialogFont->m_hObject) { + m_list.SetFont(curDialogFont); + } + + for (int i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++) { + m_list.DeleteColumn(0); + } + m_list.InsertColumn(COL_CMD, ResStr(IDS_AG_COMMAND), LVCFMT_LEFT, 80); + m_list.InsertColumn(COL_KEY, ResStr(IDS_AG_KEY), LVCFMT_LEFT, 80); + m_list.InsertColumn(COL_ID, _T("ID"), LVCFMT_LEFT, 40); + m_list.InsertColumn(COL_APPCMD, ResStr(IDS_AG_APP_COMMAND), LVCFMT_LEFT, 120); + m_list.InsertColumn(COL_RMCMD, _T("RemoteCmd"), LVCFMT_LEFT, 80); + m_list.InsertColumn(COL_RMREPCNT, _T("RepCnt"), LVCFMT_CENTER, 60); + + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; m_wmcmds.GetNext(pos)) { + int row = m_list.InsertItem(m_list.GetItemCount(), m_wmcmds.GetAt(pos).GetName(), COL_CMD); + auto itemData = std::make_unique(); + itemData->index = pos; + m_list.SetItemData(row, (DWORD_PTR)itemData.get()); + m_pItemsData.push_back(std::move(itemData)); + } + + SetupList(); + + m_list.SetColumnWidth(COL_CMD, LVSCW_AUTOSIZE); + m_list.SetColumnWidth(COL_KEY, LVSCW_AUTOSIZE); + m_list.SetColumnWidth(COL_ID, LVSCW_AUTOSIZE_USEHEADER); + + // subclass the keylist control + OldControlProc = (WNDPROC)SetWindowLongPtr(m_list.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 +} + +BOOL CPPageAccelTbl::OnApply() +{ + AfxGetMyApp()->UnregisterHotkeys(); + UpdateData(); + + CAppSettings& s = AfxGetAppSettings(); + + s.wmcmds.RemoveAll(); + s.wmcmds.AddTail(&m_wmcmds); + + if (s.hAccel) { + DestroyAcceleratorTable(s.hAccel); + } + + CAtlArray pAccel; + pAccel.SetCount(ACCEL_LIST_SIZE); + int accel_count = 0; + POSITION pos = m_wmcmds.GetHeadPosition(); + for (int i = 0; pos; i++) { + ACCEL x = m_wmcmds.GetNext(pos); + if (x.key > 0) { + pAccel[accel_count] = x; + accel_count++; + } + } + s.hAccel = CreateAcceleratorTable(pAccel.GetData(), accel_count); + + CFrameWnd* parent = GetParentFrame(); + if (parent) { + parent->m_hAccelTable = s.hAccel; + } + + s.fWinLirc = !!m_fWinLirc; + s.strWinLircAddr = m_WinLircAddr; + if (s.fWinLirc) { + s.WinLircClient.Connect(m_WinLircAddr); + } + s.fUIce = !!m_fUIce; + s.strUIceAddr = m_UIceAddr; + if (s.fUIce) { + s.UIceClient.Connect(m_UIceAddr); + } + s.fGlobalMedia = !!m_fGlobalMedia; + + AfxGetMyApp()->RegisterHotkeys(); + + return __super::OnApply(); +} + +void CPPageAccelTbl::OnBnClickedSelectAll() +{ + m_list.SetFocus(); + + for (int i = 0, j = m_list.GetItemCount(); i < j; i++) { + m_list.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED); + } +} + +void CPPageAccelTbl::OnBnClickedReset() +{ + m_list.SetFocus(); + + POSITION pos = m_list.GetFirstSelectedItemPosition(); + if (!pos) { + return; + } + + while (pos) { + int ni = m_list.GetNextSelectedItem(pos); + POSITION pi = ((ITEMDATA*)m_list.GetItemData(ni))->index; + wmcmd& wc = m_wmcmds.GetAt(pi); + wc.Restore(); + } + + SetupList(); + + SetModified(); +} + +void CPPageAccelTbl::OnChangeFilterEdit() +{ + KillTimer(filterTimerID); + filterTimerID = SetTimer(2, 100, NULL); +} + +void CPPageAccelTbl::FilterList() +{ + CString filter; + filterEdit.GetWindowText(filter); + LANGID langid = AfxGetAppSettings().language; + filter = NormalizeUnicodeStrForSearch(filter, langid); + + m_list.SetRedraw(false); + m_list.DeleteAllItems(); + m_pItemsData.clear(); + + POSITION pos = m_wmcmds.GetHeadPosition(); + for (; pos; ) { + CString hotkey, id, name, sname; + + wmcmd& wc = m_wmcmds.GetAt(pos); + + HotkeyModToString(wc.key, wc.fVirt, hotkey); + id.Format(_T("%u"), wc.cmd); + sname = wc.GetName(); + + sname = NormalizeUnicodeStrForSearch(sname, langid); + id = NormalizeUnicodeStrForSearch(id, langid); + hotkey = NormalizeUnicodeStrForSearch(hotkey, langid); + + if (filter.IsEmpty() || sname.Find(filter) != -1 || hotkey.Find(filter) != -1 || id.Find(filter) != -1) { + int row = m_list.InsertItem(m_list.GetItemCount(), wc.GetName(), COL_CMD); + auto itemData = std::make_unique(); + itemData->index = pos; + m_list.SetItemData(row, (DWORD_PTR)itemData.get()); + m_pItemsData.push_back(std::move(itemData)); + } + m_wmcmds.GetNext(pos); + } + SetupList(false); + m_list.SetRedraw(true); + m_list.RedrawWindow(); +} + +void CPPageAccelTbl::GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG) { + auto itemData = (ITEMDATA*)m_list.GetItemData(nItem); + auto dup = itemData->flag; + if (iSubItem == COL_CMD && dup + || iSubItem == COL_KEY && (dup & DUP_KEY) + || iSubItem == COL_APPCMD && (dup & DUP_APPCMD) + || iSubItem == COL_RMCMD && (dup & DUP_RMCMD)) { + if (AppIsThemeLoaded()) { + clrTextBk = CMPCTheme::ListCtrlErrorColor; + overrideSelectedBG = true; + } else { + clrTextBk = RGB(255, 130, 120); + } + } else { + if (AppIsThemeLoaded()) { + clrTextBk = CMPCTheme::ContentBGColor; + } else { + clrTextBk = GetSysColor(COLOR_WINDOW); + } + } +} + +void CPPageAccelTbl::GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) { + horzGridColor = CMPCTheme::ListCtrlGridColor; + vertGridColor = CMPCTheme::ListCtrlGridColor; +} + +void CPPageAccelTbl::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult) { + NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR); + *pResult = CDRF_DODEFAULT; + + if (CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage) { + *pResult = CDRF_NOTIFYITEMDRAW; + } else if (CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage) { + *pResult = CDRF_NOTIFYSUBITEMDRAW; + } else if ((CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage) { + bool ignore; + GetCustomTextColors(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, pLVCD->clrText, pLVCD->clrTextBk, ignore); + *pResult = CDRF_DODEFAULT; + } +} + +void CPPageAccelTbl::OnBeginListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (pItem->iItem < 0) { + return; + } + + if (pItem->iSubItem == COL_KEY || pItem->iSubItem == COL_APPCMD || pItem->iSubItem == COL_RMCMD || pItem->iSubItem == COL_RMREPCNT) { + *pResult = TRUE; + } +} + +static BYTE s_mods[] = {0, FALT, FCONTROL, FSHIFT, FCONTROL | FALT, FCONTROL | FSHIFT, FALT | FSHIFT, FCONTROL | FALT | FSHIFT}; + +void CPPageAccelTbl::OnDoListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + if (pItem->iItem < 0) { + *pResult = FALSE; + return; + } + + *pResult = TRUE; + + + wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(pItem->iItem))->index); + + CAtlList sl; + int nSel = -1; + + auto createHotkey = [&](auto virt, auto key) { + m_list.ShowInPlaceWinHotkey(pItem->iItem, pItem->iSubItem); + CWinHotkeyCtrl* pWinHotkey = (CWinHotkeyCtrl*)m_list.GetDlgItem(IDC_WINHOTKEY1); + UINT cod = 0, mod = 0; + if (virt & FALT) { + mod |= MOD_ALT; + } + if (virt & FCONTROL) { + mod |= MOD_CONTROL; + } + if (virt & FSHIFT) { + mod |= MOD_SHIFT; + } + cod = key; + pWinHotkey->SetWinHotkey(cod, mod); + }; + + switch (pItem->iSubItem) { + case COL_KEY: + createHotkey(wc.fVirt, wc.key); + break; + case COL_APPCMD: + for (int i = 0; i < _countof(g_CommandList); i++) { + sl.AddTail(g_CommandList[i].cmdname); + if (wc.appcmd == g_CommandList[i].appcmd) { + nSel = i; + } + } + + m_list.ShowInPlaceComboBox(pItem->iItem, pItem->iSubItem, sl, nSel); + break; + case COL_RMCMD: + m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem); + break; + case COL_RMREPCNT: + m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem); + break; + default: + *pResult = FALSE; + break; + } +} + +int CPPageAccelTbl::CompareFunc(LPARAM lParam1, LPARAM lParam2) +{ + int result; + + CString strItem1 = m_list.GetItemText(static_cast(lParam1), sortColumn); + CString strItem2 = m_list.GetItemText(static_cast(lParam2), sortColumn); + if (sortColumn == COL_ID || sortColumn == COL_RMREPCNT) { + wmcmd& wc1 = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(static_cast(lParam1)))->index); + wmcmd& wc2 = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(static_cast(lParam2)))->index); + + result = wc1.cmd == wc2.cmd ? 0 : (wc1.cmd < wc2.cmd ? -1 : 1); + } else { + result = strItem1.Compare(strItem2); + } + + if (sortDirection == HDF_SORTUP) { + return result; + } else { + return -result; + } +} + +static int CALLBACK StaticCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + CPPageAccelTbl* ppAccelTbl = (CPPageAccelTbl*)lParamSort; + return ppAccelTbl->CompareFunc(lParam1, lParam2); +} + +void CPPageAccelTbl::UpdateHeaderSort(int column, int sort) +{ + CHeaderCtrl* hdr = m_list.GetHeaderCtrl(); + HDITEMW hItem = { 0 }; + hItem.mask = HDI_FORMAT; + if (hdr->GetItem(column, &hItem)) { + if (sort == HDF_SORTUP) { + hItem.fmt |= HDF_SORTUP; + hItem.fmt &= ~HDF_SORTDOWN; + } else if (sort == HDF_SORTDOWN) { + hItem.fmt |= HDF_SORTDOWN; + hItem.fmt &= ~HDF_SORTUP; + } else { //no sort + hItem.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN); + } + hdr->SetItem(column, &hItem); + } +} + +void CPPageAccelTbl::OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; + int colToSort = pNMListView->iSubItem; + if (colToSort == sortColumn) { + sortDirection = sortDirection == HDF_SORTUP ? HDF_SORTDOWN : HDF_SORTUP; + } else { + if (sortColumn != -1) { + UpdateHeaderSort(sortColumn, 0); //clear old sort + } + sortColumn = colToSort; + sortDirection = HDF_SORTUP; + } + m_list.SortItemsEx(StaticCompareFunc, (LPARAM)this); + UpdateHeaderSort(sortColumn, sortDirection); +} + +void CPPageAccelTbl::OnEndListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) +{ + LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; + LV_ITEM* pItem = &pDispInfo->item; + + *pResult = FALSE; + + if (!m_list.m_fInPlaceDirty) { + return; + } + + if (pItem->iItem < 0) { + return; + } + wmcmd& wc = m_wmcmds.GetAt(((ITEMDATA*)m_list.GetItemData(pItem->iItem))->index); + + auto updateHotkey = [&](auto &virt, auto &key) { + UINT cod, mod; + CWinHotkeyCtrl* pWinHotkey = (CWinHotkeyCtrl*)m_list.GetDlgItem(IDC_WINHOTKEY1); + pWinHotkey->GetWinHotkey(&cod, &mod); + ASSERT(cod < WORD_MAX); + key = (WORD)cod; + virt = FVIRTKEY; + if (mod & MOD_ALT) { + virt |= FALT; + } + if (mod & MOD_CONTROL) { + virt |= FCONTROL; + } + if (mod & MOD_SHIFT) { + virt |= FSHIFT; + } + + CString str; + HotkeyToString(key, mod, str); + m_list.SetItemText(pItem->iItem, pItem->iSubItem, str); + + *pResult = TRUE; + UpdateKeyDupFlags(); + }; + + WORD discard; + switch (pItem->iSubItem) { + case COL_KEY: + updateHotkey(wc.fVirt, wc.key); + break; + case COL_APPCMD: { + ptrdiff_t i = pItem->lParam; + if (i >= 0 && i < _countof(g_CommandList)) { + wc.appcmd = g_CommandList[i].appcmd; + m_list.SetItemText(pItem->iItem, COL_APPCMD, pItem->pszText); + *pResult = TRUE; + UpdateAppcmdDupFlags(); + } + } + break; + case COL_RMCMD: { + CString cmd = pItem->pszText; + cmd.Trim(); + cmd.Replace(_T(' '), ('_')); + m_list.SetItemText(pItem->iItem, pItem->iSubItem, cmd); + wc.rmcmd = cmd; + *pResult = TRUE; + UpdateRmcmdDupFlags(); + break; + } + case COL_RMREPCNT: + CString str = pItem->pszText; + wc.rmrepcnt = _tcstol(str.Trim(), nullptr, 10); + str.Format(_T("%d"), wc.rmrepcnt); + m_list.SetItemText(pItem->iItem, pItem->iSubItem, str); + *pResult = TRUE; + break; + } + + if (*pResult) { + m_list.RedrawWindow(); + SetModified(); + } +} + +void CPPageAccelTbl::OnTimer(UINT_PTR nIDEvent) +{ + if (nIDEvent == m_nStatusTimerID) { + UpdateData(); + + CAppSettings& s = AfxGetAppSettings(); + + if (m_fWinLirc) { + CString addr; + m_WinLircEdit.GetWindowText(addr); + s.WinLircClient.Connect(addr); + } + + m_WinLircEdit.Invalidate(); + + if (m_fUIce) { + CString addr; + m_UIceEdit.GetWindowText(addr); + s.UIceClient.Connect(addr); + } + + m_UIceEdit.Invalidate(); + + m_counter++; + } else if (nIDEvent == filterTimerID) { + KillTimer(filterTimerID); + FilterList(); + } else { + __super::OnTimer(nIDEvent); + } +} + +HBRUSH CPPageAccelTbl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) +{ + HBRUSH hbr = __super::OnCtlColor(pDC, pWnd, nCtlColor); + + const CAppSettings& s = AfxGetAppSettings(); + if (AppIsThemeLoaded()) { + return hbr; //should have already been handled inside themed ctlcolor + } + int status = -1; + + if (*pWnd == m_WinLircEdit) { + status = s.WinLircClient.GetStatus(); + } else if (*pWnd == m_UIceEdit) { + status = s.UIceClient.GetStatus(); + } + + if (status == 0 || status == 2 && (m_counter & 1)) { + pDC->SetTextColor(0x0000ff); + } else if (status == 1) { + pDC->SetTextColor(0x008000); + } + + return hbr; +} + +BOOL CPPageAccelTbl::OnSetActive() +{ + m_nStatusTimerID = SetTimer(1, 1000, nullptr); + + return CPPageBase::OnSetActive(); +} + +BOOL CPPageAccelTbl::OnKillActive() +{ + KillTimer(m_nStatusTimerID); + m_nStatusTimerID = 0; + + return CPPageBase::OnKillActive(); +} + +void CPPageAccelTbl::OnCancel() +{ + CAppSettings& s = AfxGetAppSettings(); + + if (!s.fWinLirc) { + s.WinLircClient.DisConnect(); + } + if (!s.fUIce) { + s.UIceClient.DisConnect(); + } + + __super::OnCancel(); +} diff --git a/src/mpc-hc/PPageAccelTbl.h b/src/mpc-hc/PPageAccelTbl.h index b2dbc11ed7f..28a6ce5d0f1 100644 --- a/src/mpc-hc/PPageAccelTbl.h +++ b/src/mpc-hc/PPageAccelTbl.h @@ -1,125 +1,125 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 see Authors.txt - * - * This film_liste 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 . - * - */ - -#pragma once - -#include "PPageBase.h" -#include "PlayerListCtrl.h" -#include "StaticLink.h" -#include "WinHotkeyCtrl.h" -#include "vkCodes.h" -#include "CMPCThemePPageBase.h" -#include "CMPCThemeStaticLink.h" -#include "CMPCThemeEdit.h" - -// CPPageAccelTbl dialog - -class CPPageAccelTbl : public CMPCThemePPageBase - , public CMPCThemeListCtrlCustomInterface -{ -private: - enum { - COL_CMD, - COL_KEY, - COL_ID, - COL_APPCMD, - COL_RMCMD, - COL_RMREPCNT - }; - - enum { APPCOMMAND_LAST = APPCOMMAND_DWM_FLIP3D }; - - CList m_wmcmds; - - void UpdateKeyDupFlags(); - void UpdateAppcmdDupFlags(); - void UpdateRmcmdDupFlags(); - void UpdateAllDupFlags(); - - int m_counter; - struct ITEMDATA - { - POSITION index = 0; - DWORD flag = 0; - }; - std::vector> m_pItemsData; - - CPlayerListCtrl m_list; - int sortColumn = -1; - int sortDirection; - BOOL m_fWinLirc; - CString m_WinLircAddr; - CMPCThemeEdit m_WinLircEdit; - CMPCThemeStaticLink m_WinLircLink; - BOOL m_fUIce; - CString m_UIceAddr; - CMPCThemeEdit m_UIceEdit; - CMPCThemeEdit filterEdit; - CMPCThemeStaticLink m_UIceLink; - UINT_PTR m_nStatusTimerID, filterTimerID; - BOOL m_fGlobalMedia; - - static CString MakeAccelModLabel(BYTE fVirt); - static CString MakeAccelShortcutLabel(const ACCEL& a); - static CString MakeAppCommandLabel(UINT id); - - void SetupList(bool allowResize = true); - -public: - DECLARE_DYNAMIC(CPPageAccelTbl) - - CPPageAccelTbl(); - virtual ~CPPageAccelTbl(); - - // Dialog Data - enum { IDD = IDD_PPAGEACCELTBL }; - - static CString MakeAccelShortcutLabel(UINT id); - int CompareFunc(LPARAM lParam1, LPARAM lParam2); - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual BOOL OnApply(); - virtual BOOL PreTranslateMessage(MSG* pMsg); - virtual BOOL OnSetActive(); - virtual BOOL OnKillActive(); - void UpdateHeaderSort(int column, int sort); - void FilterList(); - virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG); - virtual void DoCustomPrePaint() {} - virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor); - - DECLARE_MESSAGE_MAP() - - afx_msg void OnBeginListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDoListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnEndListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnBnClickedSelectAll(); - afx_msg void OnBnClickedReset(); - afx_msg void OnChangeFilterEdit(); - afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); - afx_msg void OnTimer(UINT_PTR nIDEvent); - afx_msg void OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult); - - virtual void OnCancel(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 see Authors.txt + * + * This film_liste 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 . + * + */ + +#pragma once + +#include "PPageBase.h" +#include "PlayerListCtrl.h" +#include "StaticLink.h" +#include "WinHotkeyCtrl.h" +#include "vkCodes.h" +#include "CMPCThemePPageBase.h" +#include "CMPCThemeStaticLink.h" +#include "CMPCThemeEdit.h" + +// CPPageAccelTbl dialog + +class CPPageAccelTbl : public CMPCThemePPageBase + , public CMPCThemeListCtrlCustomInterface +{ +private: + enum { + COL_CMD, + COL_KEY, + COL_ID, + COL_APPCMD, + COL_RMCMD, + COL_RMREPCNT + }; + + enum { APPCOMMAND_LAST = APPCOMMAND_DWM_FLIP3D }; + + CList m_wmcmds; + + void UpdateKeyDupFlags(); + void UpdateAppcmdDupFlags(); + void UpdateRmcmdDupFlags(); + void UpdateAllDupFlags(); + + int m_counter; + struct ITEMDATA + { + POSITION index = 0; + DWORD flag = 0; + }; + std::vector> m_pItemsData; + + CPlayerListCtrl m_list; + int sortColumn = -1; + int sortDirection; + BOOL m_fWinLirc; + CString m_WinLircAddr; + CMPCThemeEdit m_WinLircEdit; + CMPCThemeStaticLink m_WinLircLink; + BOOL m_fUIce; + CString m_UIceAddr; + CMPCThemeEdit m_UIceEdit; + CMPCThemeEdit filterEdit; + CMPCThemeStaticLink m_UIceLink; + UINT_PTR m_nStatusTimerID, filterTimerID; + BOOL m_fGlobalMedia; + + static CString MakeAccelModLabel(BYTE fVirt); + static CString MakeAccelShortcutLabel(const ACCEL& a); + static CString MakeAppCommandLabel(UINT id); + + void SetupList(bool allowResize = true); + +public: + DECLARE_DYNAMIC(CPPageAccelTbl) + + CPPageAccelTbl(); + virtual ~CPPageAccelTbl(); + + // Dialog Data + enum { IDD = IDD_PPAGEACCELTBL }; + + static CString MakeAccelShortcutLabel(UINT id); + int CompareFunc(LPARAM lParam1, LPARAM lParam2); + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual BOOL OnApply(); + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL OnSetActive(); + virtual BOOL OnKillActive(); + void UpdateHeaderSort(int column, int sort); + void FilterList(); + virtual void GetCustomTextColors(INT_PTR nItem, int iSubItem, COLORREF& clrText, COLORREF& clrTextBk, bool& overrideSelectedBG); + virtual void DoCustomPrePaint() {} + virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnBeginListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDoListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnListColumnClick(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnEndListLabelEdit(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnBnClickedSelectAll(); + afx_msg void OnBnClickedReset(); + afx_msg void OnChangeFilterEdit(); + afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); + afx_msg void OnTimer(UINT_PTR nIDEvent); + afx_msg void OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult); + + virtual void OnCancel(); +}; diff --git a/src/mpc-hc/PPageAudioSwitcher.cpp b/src/mpc-hc/PPageAudioSwitcher.cpp index 95596a25bc8..6f61ecb24ed 100644 --- a/src/mpc-hc/PPageAudioSwitcher.cpp +++ b/src/mpc-hc/PPageAudioSwitcher.cpp @@ -1,440 +1,440 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include -#include "mplayerc.h" -#include "MainFrm.h" -#include "PPageAudioSwitcher.h" -#include "CMPCTheme.h" -#include "CMPCThemeHeaderCtrl.h" - - -// CPPageAudioSwitcher dialog - -#pragma warning(push) -#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized -IMPLEMENT_DYNAMIC(CPPageAudioSwitcher, CMPCThemePPageBase) -CPPageAudioSwitcher::CPPageAudioSwitcher(IFilterGraph* pFG) -#if 1 - : CMPCThemePPageBase(CPPageAudioSwitcher::IDD, CPPageAudioSwitcher::IDD) -#else - : CMPCThemePPageBase(CPPageAudioSwitcher::IDD, IDS_AUDIOSWITCHER) -#endif - , m_pSpeakerToChannelMap() - , m_dwChannelMask(0) - , m_fEnableAudioSwitcher(FALSE) - , m_fAudioNormalize(FALSE) - , m_nAudioMaxNormFactor(400) - , m_fAudioNormalizeRecover(FALSE) - , m_AudioBoostPos(0) - , m_fDownSampleTo441(FALSE) - , m_fCustomChannelMapping(FALSE) - , m_nChannels(0) - , m_tAudioTimeShift(0) - , m_fAudioTimeShift(FALSE) -{ - CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), pFG); - - if (pASF) { - pASF->GetInputSpeakerConfig(&m_dwChannelMask); - m_nChannels = pASF->GetNumberOfInputChannels(); - } -} -#pragma warning(pop) - -CPPageAudioSwitcher::~CPPageAudioSwitcher() -{ -} - -void CPPageAudioSwitcher::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); - DDX_Check(pDX, IDC_CHECK5, m_fAudioNormalize); - DDX_Text(pDX, IDC_EDIT3, m_nAudioMaxNormFactor); - DDX_Control(pDX, IDC_SPIN3, m_AudioMaxNormFactorSpin); - DDX_Check(pDX, IDC_CHECK6, m_fAudioNormalizeRecover); - DDX_Slider(pDX, IDC_SLIDER1, m_AudioBoostPos); - DDX_Control(pDX, IDC_SLIDER1, m_AudioBoostCtrl); - DDX_Check(pDX, IDC_CHECK3, m_fDownSampleTo441); - DDX_Check(pDX, IDC_CHECK1, m_fCustomChannelMapping); - DDX_Control(pDX, IDC_EDIT1, m_nChannelsCtrl); - DDX_Text(pDX, IDC_EDIT1, m_nChannels); - if (m_nChannels > AS_MAX_CHANNELS) { - m_nChannels = AS_MAX_CHANNELS; - SetDlgItemText(IDC_EDIT1, L"18"); - } - DDX_Control(pDX, IDC_SPIN1, m_nChannelsSpinCtrl); - DDX_Control(pDX, IDC_LIST1, m_list); - DDX_Check(pDX, IDC_CHECK2, m_fEnableAudioSwitcher); - DDX_Control(pDX, IDC_CHECK3, m_fDownSampleTo441Ctrl); - DDX_Control(pDX, IDC_CHECK1, m_fCustomChannelMappingCtrl); - DDX_Control(pDX, IDC_EDIT2, m_tAudioTimeShiftCtrl); - DDX_Control(pDX, IDC_SPIN2, m_tAudioTimeShiftSpin); - DDX_Text(pDX, IDC_EDIT2, m_tAudioTimeShift); - DDX_Check(pDX, IDC_CHECK4, m_fAudioTimeShift); - DDX_Control(pDX, IDC_CHECK4, m_fAudioTimeShiftCtrl); -} - -BEGIN_MESSAGE_MAP(CPPageAudioSwitcher, CMPCThemePPageBase) - ON_NOTIFY(NM_CLICK, IDC_LIST1, OnNMClickList1) - ON_WM_DRAWITEM() - ON_EN_CHANGE(IDC_EDIT1, OnEnChangeEdit1) - ON_UPDATE_COMMAND_UI(IDC_STATIC6, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_SLIDER1, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_CHECK5, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_STATIC4, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_STATIC5, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_CHECK6, OnUpdateNormalize) - ON_UPDATE_COMMAND_UI(IDC_EDIT2, OnUpdateTimeShift) - ON_UPDATE_COMMAND_UI(IDC_SPIN2, OnUpdateTimeShift) - ON_UPDATE_COMMAND_UI(IDC_CHECK3, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_CHECK4, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_CHECK1, OnUpdateAudioSwitcher) - ON_UPDATE_COMMAND_UI(IDC_EDIT1, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_SPIN1, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_LIST1, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_STATIC2, OnUpdateChannelMapping) - ON_UPDATE_COMMAND_UI(IDC_STATIC3, OnUpdateChannelMapping) - ON_WM_HSCROLL() - ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) -END_MESSAGE_MAP() - - -// CPPageAudioSwitcher message handlers - -BOOL CPPageAudioSwitcher::OnInitDialog() -{ - __super::OnInitDialog(); - - const CAppSettings& s = AfxGetAppSettings(); - - m_fEnableAudioSwitcher = s.fEnableAudioSwitcher; - m_fAudioNormalize = s.fAudioNormalize; - m_nAudioMaxNormFactor = s.nAudioMaxNormFactor; - m_AudioMaxNormFactorSpin.SetRange32(100, 1000); - m_fAudioNormalizeRecover = s.fAudioNormalizeRecover; - m_AudioBoostCtrl.SetRange(0, 300); - m_AudioBoostCtrl.SetPageSize(10); - m_AudioBoostPos = s.nAudioBoost; - m_fDownSampleTo441 = s.fDownSampleTo441; - m_fAudioTimeShift = s.fAudioTimeShift; - m_tAudioTimeShift = s.iAudioTimeShift; - m_tAudioTimeShiftSpin.SetRange32(-1000 * 60 * 60 * 24, 1000 * 60 * 60 * 24); - m_fCustomChannelMapping = s.fCustomChannelMapping; - memcpy(m_pSpeakerToChannelMap, s.pSpeakerToChannelMap, sizeof(s.pSpeakerToChannelMap)); - - m_nChannels = std::clamp(s.nSpeakerChannels, 1, AS_MAX_CHANNELS); - m_nChannelsSpinCtrl.SetRange(1, AS_MAX_CHANNELS); - - m_list.setAdditionalStyles(0); //cleans up styles if necessary for mpc theme - m_list.InsertColumn(0, _T(""), LVCFMT_LEFT, 100); - m_list.InsertItem(0, _T("")); - m_list.InsertItem(1, ResStr(IDS_FRONT_LEFT)); - m_list.InsertItem(2, ResStr(IDS_FRONT_RIGHT)); - m_list.InsertItem(3, ResStr(IDS_FRONT_CENTER)); - m_list.InsertItem(4, ResStr(IDS_LOW_FREQUENCY)); - m_list.InsertItem(5, ResStr(IDS_BACK_LEFT)); - m_list.InsertItem(6, ResStr(IDS_BACK_RIGHT)); - m_list.InsertItem(7, ResStr(IDS_FRONT_LEFT_OF_CENTER)); - m_list.InsertItem(8, ResStr(IDS_FRONT_RIGHT_OF_CENTER)); - m_list.InsertItem(9, ResStr(IDS_BACK_CENTER)); - m_list.InsertItem(10, ResStr(IDS_SIDE_LEFT)); - m_list.InsertItem(11, ResStr(IDS_SIDE_RIGHT)); - m_list.InsertItem(12, ResStr(IDS_TOP_CENTER)); - m_list.InsertItem(13, ResStr(IDS_TOP_FRONT_LEFT)); - m_list.InsertItem(14, ResStr(IDS_TOP_FRONT_CENTER)); - m_list.InsertItem(15, ResStr(IDS_TOP_FRONT_RIGHT)); - m_list.InsertItem(16, ResStr(IDS_TOP_BACK_LEFT)); - m_list.InsertItem(17, ResStr(IDS_TOP_BACK_CENTER)); - m_list.InsertItem(18, ResStr(IDS_TOP_BACK_RIGHT)); - m_list.SetColumnWidth(0, LVSCW_AUTOSIZE); - - for (int i = 1; i <= AS_MAX_CHANNELS; i++) { - m_list.InsertColumn(i, _T(""), LVCFMT_CENTER, 16); - CString n; - n.Format(_T("%d"), i); - m_list.SetItemText(0, i, n); - // m_list.SetColumnWidth(i, LVSCW_AUTOSIZE); - // m_list.SetColumnWidth(i, m_list.GetColumnWidth(i)*8/10); - } - - EnableThemedDialogTooltips(this); - m_tooltip.Create(this); - m_tooltip.Activate(TRUE); - - CorrectComboBoxHeaderWidth(GetDlgItem(IDC_CHECK5)); - - UpdateData(FALSE); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -BOOL CPPageAudioSwitcher::OnApply() -{ - UpdateData(); - - CAppSettings& s = AfxGetAppSettings(); - - s.fEnableAudioSwitcher = !!m_fEnableAudioSwitcher; - s.fAudioNormalize = !!m_fAudioNormalize; - if (m_nAudioMaxNormFactor > 1000) { - m_nAudioMaxNormFactor = 1000; - } else if (m_nAudioMaxNormFactor < 100) { - m_nAudioMaxNormFactor = 100; - } - s.nAudioMaxNormFactor = m_nAudioMaxNormFactor; - s.fAudioNormalizeRecover = !!m_fAudioNormalizeRecover; - s.nAudioBoost = m_AudioBoostPos; - s.fDownSampleTo441 = !!m_fDownSampleTo441; - s.fAudioTimeShift = !!m_fAudioTimeShift; - s.iAudioTimeShift = m_tAudioTimeShift; - s.fCustomChannelMapping = !!m_fCustomChannelMapping; - memcpy(s.pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); - s.nSpeakerChannels = std::clamp(m_nChannels, 1, AS_MAX_CHANNELS); - - // There is no main frame when the option dialog is displayed stand-alone - if (CMainFrame* pMainFrame = AfxGetMainFrame()) { - pMainFrame->UpdateControlState(CMainFrame::UPDATE_AUDIO_SWITCHER); - } - - return __super::OnApply(); -} - -void CPPageAudioSwitcher::OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pNMHDR; - - if (lpnmlv->iItem > 0 && lpnmlv->iSubItem > 0 && lpnmlv->iSubItem <= m_nChannels) { - UpdateData(); - m_pSpeakerToChannelMap[m_nChannels - 1][lpnmlv->iItem - 1] ^= 1 << (lpnmlv->iSubItem - 1); - m_list.RedrawItems(lpnmlv->iItem, lpnmlv->iItem); - SetModified(); - - if (GetKeyState(VK_SHIFT) & 0x8000) { - OnApply(); - } - } - - *pResult = 0; -} - -void CPPageAudioSwitcher::OnEnChangeEdit1() -{ - if (IsWindow(m_list.m_hWnd)) { - UpdateData(); - m_list.Invalidate(); - SetModified(); - } -} - -void CPPageAudioSwitcher::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) -{ - if (nIDCtl != IDC_LIST1) { - return; - } - - // if (lpDrawItemStruct->itemID == 0) - // UpdateData(); - - CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); - - pDC->SetBkMode(TRANSPARENT); - - COLORREF frameClr, textClr, textDisabledClr, textNAClr; - COLORREF oldBkColor = pDC->GetBkColor(); - if (AppNeedsThemedControls()) { - frameClr = CMPCTheme::AudioSwitcherGridColor; - textClr = CMPCTheme::TextFGColor; - textDisabledClr = CMPCTheme::ContentTextDisabledFGColorFade; - textNAClr = CMPCTheme::ContentTextDisabledFGColorFade2; - pDC->SetBkColor(CMPCTheme::ContentBGColor); - CRect bgRect = lpDrawItemStruct->rcItem; - pDC->FillSolidRect(bgRect, CMPCTheme::ContentBGColor); - } else { - frameClr = 0xe0e0e0; - textClr = 0; - textDisabledClr = 0xb0b0b0; - textNAClr = 0xe0e0e0; - } - - CPen p(PS_INSIDEFRAME, 1, frameClr); - CPen* old = pDC->SelectObject(&p); - - pDC->MoveTo(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - 1); - pDC->LineTo(lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom - 1); - - CHeaderCtrl* pHeader = m_list.GetHeaderCtrl(); - int nColumnCount = pHeader->GetItemCount(); - - for (int i = 0; i < nColumnCount; i++) { - CRect r, rb; - m_list.GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_BOUNDS, rb); - m_list.GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_LABEL, r); - - pDC->MoveTo(r.right - 1, r.top); - pDC->LineTo(r.right - 1, r.bottom - 1); - - CSize s = pDC->GetTextExtent(m_list.GetItemText(lpDrawItemStruct->itemID, i)); - - if (i == 0) { - r.left = rb.left; - - if (lpDrawItemStruct->itemID == 0) { - pDC->MoveTo(0, 0); - pDC->LineTo(r.right, r.bottom - 1); - } else { - pDC->SetTextColor(m_list.IsWindowEnabled() ? textClr : textDisabledClr); - pDC->TextOut(r.left + 1, (r.top + r.bottom - s.cy) / 2, m_list.GetItemText(lpDrawItemStruct->itemID, i)); - } - } else { - pDC->SetTextColor(i > m_nChannels ? textNAClr : (!m_list.IsWindowEnabled() ? textDisabledClr : textClr)); - - if (lpDrawItemStruct->itemID == 0) { - pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, m_list.GetItemText(lpDrawItemStruct->itemID, i)); - } else { - if (m_dwChannelMask & (1 << (lpDrawItemStruct->itemID - 1))) { - int nBitsSet = 0; - - for (int j = 1; j <= (1 << (lpDrawItemStruct->itemID - 1)); j <<= 1) { - if (m_dwChannelMask & j) { - nBitsSet++; - } - } - - if (nBitsSet == i) { - COLORREF tmp = pDC->GetTextColor(); - - pDC->SetTextColor(textNAClr); - CFont f; - f.CreatePointFont(MulDiv(100, 96, pDC->GetDeviceCaps(LOGPIXELSX)), _T("Marlett")); - CFont* old2 = pDC->SelectObject(&f); - UNREFERENCED_PARAMETER(old2); - s = pDC->GetTextExtent(_T("g")); - pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, _T("g")); - - pDC->SetTextColor(tmp); - } - } - - if (m_pSpeakerToChannelMap[m_nChannels - 1][lpDrawItemStruct->itemID - 1] & (1 << (i - 1))) { - CFont f; - f.CreatePointFont(MulDiv(100, 96, pDC->GetDeviceCaps(LOGPIXELSX)), _T("Marlett")); - CFont* old2 = pDC->SelectObject(&f); - s = pDC->GetTextExtent(_T("a")); - pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, _T("a")); - pDC->SelectObject(old2); - } - } - } - } - - pDC->SetBkColor(oldBkColor); - pDC->SelectObject(old); -} - -void CPPageAudioSwitcher::OnUpdateAudioSwitcher(CCmdUI* pCmdUI) -{ - // UpdateData(); - pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/); -} - -void CPPageAudioSwitcher::OnUpdateNormalize(CCmdUI* pCmdUI) -{ - // UpdateData(); - pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ - && IsDlgButtonChecked(IDC_CHECK5)/*m_fNormalize*/); -} - -void CPPageAudioSwitcher::OnUpdateTimeShift(CCmdUI* pCmdUI) -{ - // UpdateData(); - pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ - && IsDlgButtonChecked(IDC_CHECK4)/*m_fAudioTimeShift)*/); -} - -void CPPageAudioSwitcher::OnUpdateChannelMapping(CCmdUI* pCmdUI) -{ - // UpdateData(); - pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ - && IsDlgButtonChecked(IDC_CHECK1)/*m_fCustomChannelMapping*/); -} - -void CPPageAudioSwitcher::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) -{ - if (*pScrollBar == m_AudioBoostCtrl) { - UpdateData(); - ((CMainFrame*)GetParentFrame())->SetVolumeBoost(m_AudioBoostPos); // nice shortcut... - } - RedrawDialogTooltipIfVisible(); //if the scroll is caused by a wheel or arrows, the default tooltip may be active due to hover, in which case, we want to update - - SetModified(); - - __super::OnHScroll(nSBCode, nPos, pScrollBar); -} - -BOOL CPPageAudioSwitcher::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) -{ - TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR; - - UINT_PTR nID = pNMHDR->idFrom; - if (pTTT->uFlags & TTF_IDISHWND) { - nID = ::GetDlgCtrlID((HWND)nID); - } - - bool bRet = false; - - static CString strTipText; - - switch (nID) { - case IDC_SLIDER1: - strTipText.Format(IDS_BOOST, m_AudioBoostCtrl.GetPos()); - bRet = true; - break; - case IDC_EDIT2: - case IDC_SPIN2: - strTipText.LoadString(IDS_TIME_SHIFT_TOOLTIP); - bRet = true; - break; - } - - if (bRet) { - pTTT->lpszText = (LPWSTR)(LPCWSTR)strTipText; - PlaceThemedDialogTooltip(nID); - } - - return bRet; -} - -void CPPageAudioSwitcher::OnCancel() -{ - const CAppSettings& s = AfxGetAppSettings(); - - if ((UINT)m_AudioBoostPos != s.nAudioBoost) { - ((CMainFrame*)GetParentFrame())->SetVolumeBoost(s.nAudioBoost); - } - - __super::OnCancel(); -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include +#include "mplayerc.h" +#include "MainFrm.h" +#include "PPageAudioSwitcher.h" +#include "CMPCTheme.h" +#include "CMPCThemeHeaderCtrl.h" + + +// CPPageAudioSwitcher dialog + +#pragma warning(push) +#pragma warning(disable: 4351) // new behavior: elements of array 'array' will be default initialized +IMPLEMENT_DYNAMIC(CPPageAudioSwitcher, CMPCThemePPageBase) +CPPageAudioSwitcher::CPPageAudioSwitcher(IFilterGraph* pFG) +#if 1 + : CMPCThemePPageBase(CPPageAudioSwitcher::IDD, CPPageAudioSwitcher::IDD) +#else + : CMPCThemePPageBase(CPPageAudioSwitcher::IDD, IDS_AUDIOSWITCHER) +#endif + , m_pSpeakerToChannelMap() + , m_dwChannelMask(0) + , m_fEnableAudioSwitcher(FALSE) + , m_fAudioNormalize(FALSE) + , m_nAudioMaxNormFactor(400) + , m_fAudioNormalizeRecover(FALSE) + , m_AudioBoostPos(0) + , m_fDownSampleTo441(FALSE) + , m_fCustomChannelMapping(FALSE) + , m_nChannels(0) + , m_tAudioTimeShift(0) + , m_fAudioTimeShift(FALSE) +{ + CComQIPtr pASF = FindFilter(__uuidof(CAudioSwitcherFilter), pFG); + + if (pASF) { + pASF->GetInputSpeakerConfig(&m_dwChannelMask); + m_nChannels = pASF->GetNumberOfInputChannels(); + } +} +#pragma warning(pop) + +CPPageAudioSwitcher::~CPPageAudioSwitcher() +{ +} + +void CPPageAudioSwitcher::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Check(pDX, IDC_CHECK5, m_fAudioNormalize); + DDX_Text(pDX, IDC_EDIT3, m_nAudioMaxNormFactor); + DDX_Control(pDX, IDC_SPIN3, m_AudioMaxNormFactorSpin); + DDX_Check(pDX, IDC_CHECK6, m_fAudioNormalizeRecover); + DDX_Slider(pDX, IDC_SLIDER1, m_AudioBoostPos); + DDX_Control(pDX, IDC_SLIDER1, m_AudioBoostCtrl); + DDX_Check(pDX, IDC_CHECK3, m_fDownSampleTo441); + DDX_Check(pDX, IDC_CHECK1, m_fCustomChannelMapping); + DDX_Control(pDX, IDC_EDIT1, m_nChannelsCtrl); + DDX_Text(pDX, IDC_EDIT1, m_nChannels); + if (m_nChannels > AS_MAX_CHANNELS) { + m_nChannels = AS_MAX_CHANNELS; + SetDlgItemText(IDC_EDIT1, L"18"); + } + DDX_Control(pDX, IDC_SPIN1, m_nChannelsSpinCtrl); + DDX_Control(pDX, IDC_LIST1, m_list); + DDX_Check(pDX, IDC_CHECK2, m_fEnableAudioSwitcher); + DDX_Control(pDX, IDC_CHECK3, m_fDownSampleTo441Ctrl); + DDX_Control(pDX, IDC_CHECK1, m_fCustomChannelMappingCtrl); + DDX_Control(pDX, IDC_EDIT2, m_tAudioTimeShiftCtrl); + DDX_Control(pDX, IDC_SPIN2, m_tAudioTimeShiftSpin); + DDX_Text(pDX, IDC_EDIT2, m_tAudioTimeShift); + DDX_Check(pDX, IDC_CHECK4, m_fAudioTimeShift); + DDX_Control(pDX, IDC_CHECK4, m_fAudioTimeShiftCtrl); +} + +BEGIN_MESSAGE_MAP(CPPageAudioSwitcher, CMPCThemePPageBase) + ON_NOTIFY(NM_CLICK, IDC_LIST1, OnNMClickList1) + ON_WM_DRAWITEM() + ON_EN_CHANGE(IDC_EDIT1, OnEnChangeEdit1) + ON_UPDATE_COMMAND_UI(IDC_STATIC6, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_SLIDER1, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_CHECK5, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_STATIC4, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_STATIC5, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_CHECK6, OnUpdateNormalize) + ON_UPDATE_COMMAND_UI(IDC_EDIT2, OnUpdateTimeShift) + ON_UPDATE_COMMAND_UI(IDC_SPIN2, OnUpdateTimeShift) + ON_UPDATE_COMMAND_UI(IDC_CHECK3, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_CHECK4, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_CHECK1, OnUpdateAudioSwitcher) + ON_UPDATE_COMMAND_UI(IDC_EDIT1, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_SPIN1, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_LIST1, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_STATIC2, OnUpdateChannelMapping) + ON_UPDATE_COMMAND_UI(IDC_STATIC3, OnUpdateChannelMapping) + ON_WM_HSCROLL() + ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) +END_MESSAGE_MAP() + + +// CPPageAudioSwitcher message handlers + +BOOL CPPageAudioSwitcher::OnInitDialog() +{ + __super::OnInitDialog(); + + const CAppSettings& s = AfxGetAppSettings(); + + m_fEnableAudioSwitcher = s.fEnableAudioSwitcher; + m_fAudioNormalize = s.fAudioNormalize; + m_nAudioMaxNormFactor = s.nAudioMaxNormFactor; + m_AudioMaxNormFactorSpin.SetRange32(100, 1000); + m_fAudioNormalizeRecover = s.fAudioNormalizeRecover; + m_AudioBoostCtrl.SetRange(0, 300); + m_AudioBoostCtrl.SetPageSize(10); + m_AudioBoostPos = s.nAudioBoost; + m_fDownSampleTo441 = s.fDownSampleTo441; + m_fAudioTimeShift = s.fAudioTimeShift; + m_tAudioTimeShift = s.iAudioTimeShift; + m_tAudioTimeShiftSpin.SetRange32(-1000 * 60 * 60 * 24, 1000 * 60 * 60 * 24); + m_fCustomChannelMapping = s.fCustomChannelMapping; + memcpy(m_pSpeakerToChannelMap, s.pSpeakerToChannelMap, sizeof(s.pSpeakerToChannelMap)); + + m_nChannels = std::clamp(s.nSpeakerChannels, 1, AS_MAX_CHANNELS); + m_nChannelsSpinCtrl.SetRange(1, AS_MAX_CHANNELS); + + m_list.setAdditionalStyles(0); //cleans up styles if necessary for mpc theme + m_list.InsertColumn(0, _T(""), LVCFMT_LEFT, 100); + m_list.InsertItem(0, _T("")); + m_list.InsertItem(1, ResStr(IDS_FRONT_LEFT)); + m_list.InsertItem(2, ResStr(IDS_FRONT_RIGHT)); + m_list.InsertItem(3, ResStr(IDS_FRONT_CENTER)); + m_list.InsertItem(4, ResStr(IDS_LOW_FREQUENCY)); + m_list.InsertItem(5, ResStr(IDS_BACK_LEFT)); + m_list.InsertItem(6, ResStr(IDS_BACK_RIGHT)); + m_list.InsertItem(7, ResStr(IDS_FRONT_LEFT_OF_CENTER)); + m_list.InsertItem(8, ResStr(IDS_FRONT_RIGHT_OF_CENTER)); + m_list.InsertItem(9, ResStr(IDS_BACK_CENTER)); + m_list.InsertItem(10, ResStr(IDS_SIDE_LEFT)); + m_list.InsertItem(11, ResStr(IDS_SIDE_RIGHT)); + m_list.InsertItem(12, ResStr(IDS_TOP_CENTER)); + m_list.InsertItem(13, ResStr(IDS_TOP_FRONT_LEFT)); + m_list.InsertItem(14, ResStr(IDS_TOP_FRONT_CENTER)); + m_list.InsertItem(15, ResStr(IDS_TOP_FRONT_RIGHT)); + m_list.InsertItem(16, ResStr(IDS_TOP_BACK_LEFT)); + m_list.InsertItem(17, ResStr(IDS_TOP_BACK_CENTER)); + m_list.InsertItem(18, ResStr(IDS_TOP_BACK_RIGHT)); + m_list.SetColumnWidth(0, LVSCW_AUTOSIZE); + + for (int i = 1; i <= AS_MAX_CHANNELS; i++) { + m_list.InsertColumn(i, _T(""), LVCFMT_CENTER, 16); + CString n; + n.Format(_T("%d"), i); + m_list.SetItemText(0, i, n); + // m_list.SetColumnWidth(i, LVSCW_AUTOSIZE); + // m_list.SetColumnWidth(i, m_list.GetColumnWidth(i)*8/10); + } + + EnableThemedDialogTooltips(this); + m_tooltip.Create(this); + m_tooltip.Activate(TRUE); + + CorrectComboBoxHeaderWidth(GetDlgItem(IDC_CHECK5)); + + UpdateData(FALSE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +BOOL CPPageAudioSwitcher::OnApply() +{ + UpdateData(); + + CAppSettings& s = AfxGetAppSettings(); + + s.fEnableAudioSwitcher = !!m_fEnableAudioSwitcher; + s.fAudioNormalize = !!m_fAudioNormalize; + if (m_nAudioMaxNormFactor > 1000) { + m_nAudioMaxNormFactor = 1000; + } else if (m_nAudioMaxNormFactor < 100) { + m_nAudioMaxNormFactor = 100; + } + s.nAudioMaxNormFactor = m_nAudioMaxNormFactor; + s.fAudioNormalizeRecover = !!m_fAudioNormalizeRecover; + s.nAudioBoost = m_AudioBoostPos; + s.fDownSampleTo441 = !!m_fDownSampleTo441; + s.fAudioTimeShift = !!m_fAudioTimeShift; + s.iAudioTimeShift = m_tAudioTimeShift; + s.fCustomChannelMapping = !!m_fCustomChannelMapping; + memcpy(s.pSpeakerToChannelMap, m_pSpeakerToChannelMap, sizeof(m_pSpeakerToChannelMap)); + s.nSpeakerChannels = std::clamp(m_nChannels, 1, AS_MAX_CHANNELS); + + // There is no main frame when the option dialog is displayed stand-alone + if (CMainFrame* pMainFrame = AfxGetMainFrame()) { + pMainFrame->UpdateControlState(CMainFrame::UPDATE_AUDIO_SWITCHER); + } + + return __super::OnApply(); +} + +void CPPageAudioSwitcher::OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pNMHDR; + + if (lpnmlv->iItem > 0 && lpnmlv->iSubItem > 0 && lpnmlv->iSubItem <= m_nChannels) { + UpdateData(); + m_pSpeakerToChannelMap[m_nChannels - 1][lpnmlv->iItem - 1] ^= 1 << (lpnmlv->iSubItem - 1); + m_list.RedrawItems(lpnmlv->iItem, lpnmlv->iItem); + SetModified(); + + if (GetKeyState(VK_SHIFT) & 0x8000) { + OnApply(); + } + } + + *pResult = 0; +} + +void CPPageAudioSwitcher::OnEnChangeEdit1() +{ + if (IsWindow(m_list.m_hWnd)) { + UpdateData(); + m_list.Invalidate(); + SetModified(); + } +} + +void CPPageAudioSwitcher::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) +{ + if (nIDCtl != IDC_LIST1) { + return; + } + + // if (lpDrawItemStruct->itemID == 0) + // UpdateData(); + + CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); + + pDC->SetBkMode(TRANSPARENT); + + COLORREF frameClr, textClr, textDisabledClr, textNAClr; + COLORREF oldBkColor = pDC->GetBkColor(); + if (AppNeedsThemedControls()) { + frameClr = CMPCTheme::AudioSwitcherGridColor; + textClr = CMPCTheme::TextFGColor; + textDisabledClr = CMPCTheme::ContentTextDisabledFGColorFade; + textNAClr = CMPCTheme::ContentTextDisabledFGColorFade2; + pDC->SetBkColor(CMPCTheme::ContentBGColor); + CRect bgRect = lpDrawItemStruct->rcItem; + pDC->FillSolidRect(bgRect, CMPCTheme::ContentBGColor); + } else { + frameClr = 0xe0e0e0; + textClr = 0; + textDisabledClr = 0xb0b0b0; + textNAClr = 0xe0e0e0; + } + + CPen p(PS_INSIDEFRAME, 1, frameClr); + CPen* old = pDC->SelectObject(&p); + + pDC->MoveTo(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - 1); + pDC->LineTo(lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom - 1); + + CHeaderCtrl* pHeader = m_list.GetHeaderCtrl(); + int nColumnCount = pHeader->GetItemCount(); + + for (int i = 0; i < nColumnCount; i++) { + CRect r, rb; + m_list.GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_BOUNDS, rb); + m_list.GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_LABEL, r); + + pDC->MoveTo(r.right - 1, r.top); + pDC->LineTo(r.right - 1, r.bottom - 1); + + CSize s = pDC->GetTextExtent(m_list.GetItemText(lpDrawItemStruct->itemID, i)); + + if (i == 0) { + r.left = rb.left; + + if (lpDrawItemStruct->itemID == 0) { + pDC->MoveTo(0, 0); + pDC->LineTo(r.right, r.bottom - 1); + } else { + pDC->SetTextColor(m_list.IsWindowEnabled() ? textClr : textDisabledClr); + pDC->TextOut(r.left + 1, (r.top + r.bottom - s.cy) / 2, m_list.GetItemText(lpDrawItemStruct->itemID, i)); + } + } else { + pDC->SetTextColor(i > m_nChannels ? textNAClr : (!m_list.IsWindowEnabled() ? textDisabledClr : textClr)); + + if (lpDrawItemStruct->itemID == 0) { + pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, m_list.GetItemText(lpDrawItemStruct->itemID, i)); + } else { + if (m_dwChannelMask & (1 << (lpDrawItemStruct->itemID - 1))) { + int nBitsSet = 0; + + for (int j = 1; j <= (1 << (lpDrawItemStruct->itemID - 1)); j <<= 1) { + if (m_dwChannelMask & j) { + nBitsSet++; + } + } + + if (nBitsSet == i) { + COLORREF tmp = pDC->GetTextColor(); + + pDC->SetTextColor(textNAClr); + CFont f; + f.CreatePointFont(MulDiv(100, 96, pDC->GetDeviceCaps(LOGPIXELSX)), _T("Marlett")); + CFont* old2 = pDC->SelectObject(&f); + UNREFERENCED_PARAMETER(old2); + s = pDC->GetTextExtent(_T("g")); + pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, _T("g")); + + pDC->SetTextColor(tmp); + } + } + + if (m_pSpeakerToChannelMap[m_nChannels - 1][lpDrawItemStruct->itemID - 1] & (1 << (i - 1))) { + CFont f; + f.CreatePointFont(MulDiv(100, 96, pDC->GetDeviceCaps(LOGPIXELSX)), _T("Marlett")); + CFont* old2 = pDC->SelectObject(&f); + s = pDC->GetTextExtent(_T("a")); + pDC->TextOut((r.left + r.right - s.cx) / 2, (r.top + r.bottom - s.cy) / 2, _T("a")); + pDC->SelectObject(old2); + } + } + } + } + + pDC->SetBkColor(oldBkColor); + pDC->SelectObject(old); +} + +void CPPageAudioSwitcher::OnUpdateAudioSwitcher(CCmdUI* pCmdUI) +{ + // UpdateData(); + pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/); +} + +void CPPageAudioSwitcher::OnUpdateNormalize(CCmdUI* pCmdUI) +{ + // UpdateData(); + pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ + && IsDlgButtonChecked(IDC_CHECK5)/*m_fNormalize*/); +} + +void CPPageAudioSwitcher::OnUpdateTimeShift(CCmdUI* pCmdUI) +{ + // UpdateData(); + pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ + && IsDlgButtonChecked(IDC_CHECK4)/*m_fAudioTimeShift)*/); +} + +void CPPageAudioSwitcher::OnUpdateChannelMapping(CCmdUI* pCmdUI) +{ + // UpdateData(); + pCmdUI->Enable(IsDlgButtonChecked(IDC_CHECK2)/*m_fEnableAudioSwitcher*/ + && IsDlgButtonChecked(IDC_CHECK1)/*m_fCustomChannelMapping*/); +} + +void CPPageAudioSwitcher::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + if (*pScrollBar == m_AudioBoostCtrl) { + UpdateData(); + ((CMainFrame*)GetParentFrame())->SetVolumeBoost(m_AudioBoostPos); // nice shortcut... + } + RedrawDialogTooltipIfVisible(); //if the scroll is caused by a wheel or arrows, the default tooltip may be active due to hover, in which case, we want to update + + SetModified(); + + __super::OnHScroll(nSBCode, nPos, pScrollBar); +} + +BOOL CPPageAudioSwitcher::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) +{ + TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR; + + UINT_PTR nID = pNMHDR->idFrom; + if (pTTT->uFlags & TTF_IDISHWND) { + nID = ::GetDlgCtrlID((HWND)nID); + } + + bool bRet = false; + + static CString strTipText; + + switch (nID) { + case IDC_SLIDER1: + strTipText.Format(IDS_BOOST, m_AudioBoostCtrl.GetPos()); + bRet = true; + break; + case IDC_EDIT2: + case IDC_SPIN2: + strTipText.LoadString(IDS_TIME_SHIFT_TOOLTIP); + bRet = true; + break; + } + + if (bRet) { + pTTT->lpszText = (LPWSTR)(LPCWSTR)strTipText; + PlaceThemedDialogTooltip(nID); + } + + return bRet; +} + +void CPPageAudioSwitcher::OnCancel() +{ + const CAppSettings& s = AfxGetAppSettings(); + + if ((UINT)m_AudioBoostPos != s.nAudioBoost) { + ((CMainFrame*)GetParentFrame())->SetVolumeBoost(s.nAudioBoost); + } + + __super::OnCancel(); +} diff --git a/src/mpc-hc/PPageAudioSwitcher.h b/src/mpc-hc/PPageAudioSwitcher.h index 36c3649ab14..a5bec944bfe 100644 --- a/src/mpc-hc/PPageAudioSwitcher.h +++ b/src/mpc-hc/PPageAudioSwitcher.h @@ -1,94 +1,94 @@ -/* - * (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 . - * - */ - -#pragma once - -#include "CMPCThemePPageBase.h" -#include "FloatEdit.h" -#include "../filters/switcher/AudioSwitcher/AudioSwitcher.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeSliderCtrl.h" -#include "CMPCThemeEdit.h" -#include "CMPCThemeSpinButtonCtrl.h" -#include "CMPCThemePlayerListCtrl.h" - - - - -// CPPageAudioSwitcher dialog - -class CPPageAudioSwitcher : public CMPCThemePPageBase -{ - DECLARE_DYNAMIC(CPPageAudioSwitcher) - -private: - DWORD m_pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]; - DWORD m_dwChannelMask; - - BOOL m_fEnableAudioSwitcher; - BOOL m_fAudioNormalize; - UINT m_nAudioMaxNormFactor; - CMPCThemeSpinButtonCtrl m_AudioMaxNormFactorSpin; - BOOL m_fAudioNormalizeRecover; - int m_AudioBoostPos; - CMPCThemeSliderCtrl m_AudioBoostCtrl; - BOOL m_fDownSampleTo441; - CMPCThemeRadioOrCheck m_fDownSampleTo441Ctrl; - BOOL m_fCustomChannelMapping; - CMPCThemeRadioOrCheck m_fCustomChannelMappingCtrl; - CMPCThemeEdit m_nChannelsCtrl; - int m_nChannels; - CMPCThemeSpinButtonCtrl m_nChannelsSpinCtrl; - CMPCThemePlayerListCtrl m_list; - int m_tAudioTimeShift; - CMPCThemeRadioOrCheck m_fAudioTimeShiftCtrl; - CMPCThemeIntEdit m_tAudioTimeShiftCtrl; - CMPCThemeSpinButtonCtrl m_tAudioTimeShiftSpin; - BOOL m_fAudioTimeShift; - - // tooltip for slidercontrol - CToolTipCtrl m_tooltip; -public: - CPPageAudioSwitcher(IFilterGraph* pFG); - virtual ~CPPageAudioSwitcher(); - - // Dialog Data - enum { IDD = IDD_PPAGEAUDIOSWITCHER }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual BOOL OnApply(); - - DECLARE_MESSAGE_MAP() - - afx_msg void OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); - afx_msg void OnEnChangeEdit1(); - afx_msg void OnUpdateAudioSwitcher(CCmdUI* pCmdUI); - afx_msg void OnUpdateNormalize(CCmdUI* pCmdUI); - afx_msg void OnUpdateTimeShift(CCmdUI* pCmdUI); - afx_msg void OnUpdateChannelMapping(CCmdUI* pCmdUI); - - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); - virtual void OnCancel(); -}; +/* + * (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 . + * + */ + +#pragma once + +#include "CMPCThemePPageBase.h" +#include "FloatEdit.h" +#include "../filters/switcher/AudioSwitcher/AudioSwitcher.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeSliderCtrl.h" +#include "CMPCThemeEdit.h" +#include "CMPCThemeSpinButtonCtrl.h" +#include "CMPCThemePlayerListCtrl.h" + + + + +// CPPageAudioSwitcher dialog + +class CPPageAudioSwitcher : public CMPCThemePPageBase +{ + DECLARE_DYNAMIC(CPPageAudioSwitcher) + +private: + DWORD m_pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS]; + DWORD m_dwChannelMask; + + BOOL m_fEnableAudioSwitcher; + BOOL m_fAudioNormalize; + UINT m_nAudioMaxNormFactor; + CMPCThemeSpinButtonCtrl m_AudioMaxNormFactorSpin; + BOOL m_fAudioNormalizeRecover; + int m_AudioBoostPos; + CMPCThemeSliderCtrl m_AudioBoostCtrl; + BOOL m_fDownSampleTo441; + CMPCThemeRadioOrCheck m_fDownSampleTo441Ctrl; + BOOL m_fCustomChannelMapping; + CMPCThemeRadioOrCheck m_fCustomChannelMappingCtrl; + CMPCThemeEdit m_nChannelsCtrl; + int m_nChannels; + CMPCThemeSpinButtonCtrl m_nChannelsSpinCtrl; + CMPCThemePlayerListCtrl m_list; + int m_tAudioTimeShift; + CMPCThemeRadioOrCheck m_fAudioTimeShiftCtrl; + CMPCThemeIntEdit m_tAudioTimeShiftCtrl; + CMPCThemeSpinButtonCtrl m_tAudioTimeShiftSpin; + BOOL m_fAudioTimeShift; + + // tooltip for slidercontrol + CToolTipCtrl m_tooltip; +public: + CPPageAudioSwitcher(IFilterGraph* pFG); + virtual ~CPPageAudioSwitcher(); + + // Dialog Data + enum { IDD = IDD_PPAGEAUDIOSWITCHER }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual BOOL OnApply(); + + DECLARE_MESSAGE_MAP() + + afx_msg void OnNMClickList1(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct); + afx_msg void OnEnChangeEdit1(); + afx_msg void OnUpdateAudioSwitcher(CCmdUI* pCmdUI); + afx_msg void OnUpdateNormalize(CCmdUI* pCmdUI); + afx_msg void OnUpdateTimeShift(CCmdUI* pCmdUI); + afx_msg void OnUpdateChannelMapping(CCmdUI* pCmdUI); + + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); + virtual void OnCancel(); +}; diff --git a/src/mpc-hc/PPageBase.cpp b/src/mpc-hc/PPageBase.cpp index 777278fee36..b7e316e15f0 100644 --- a/src/mpc-hc/PPageBase.cpp +++ b/src/mpc-hc/PPageBase.cpp @@ -1,191 +1,191 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2016 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 . - * - */ - -#include "stdafx.h" -#include "MainFrm.h" -#include "mplayerc.h" -#include "PPageBase.h" -#include "SettingsDefines.h" -#include "ComPropertySheet.h" - - -// CPPageBase dialog - -IMPLEMENT_DYNAMIC(CPPageBase, CCmdUIPropertyPage) -CPPageBase::CPPageBase(UINT nIDTemplate, UINT nIDCaption) - : CCmdUIPropertyPage(nIDTemplate, nIDCaption) -{ -} - -CPPageBase::~CPPageBase() -{ -} - -void CPPageBase::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange(pDX); -} - -bool CPPageBase::FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT) -{ - bool bNeedTooltip = false; - - CDC* pDC = comboBox.GetDC(); - CFont* pFont = comboBox.GetFont(); - CFont* pOldFont = pDC->SelectObject(pFont); - - TEXTMETRIC tm; - pDC->GetTextMetrics(&tm); - - CRect comboBoxRect; - comboBox.GetWindowRect(comboBoxRect); - comboBoxRect.right -= GetSystemMetrics(SM_CXVSCROLL) + 2 * GetSystemMetrics(SM_CXEDGE); - - int i = comboBox.GetCurSel(); - CString str; - comboBox.GetLBText(i, str); - CSize textSize; - textSize = pDC->GetTextExtent(str); - pDC->SelectObject(pOldFont); - comboBox.ReleaseDC(pDC); - textSize.cx += tm.tmAveCharWidth; - - if (textSize.cx > comboBoxRect.Width()) { - bNeedTooltip = true; - if (str.GetLength() > _countof(pTTT->szText) - 1) { - str.Truncate(_countof(pTTT->szText) - 1); - } - _tcscpy_s(pTTT->szText, str); - pTTT->hinst = nullptr; - } - - return bNeedTooltip; -} - -void CPPageBase::CreateToolTip() -{ - m_wndToolTip.Create(this, TTS_NOPREFIX); - m_wndToolTip.Activate(TRUE); - m_wndToolTip.SetMaxTipWidth(300); - m_wndToolTip.SetDelayTime(TTDT_AUTOPOP, 10000); - for (CWnd* pChild = GetWindow(GW_CHILD); pChild; pChild = pChild->GetWindow(GW_HWNDNEXT)) { - CString strToolTip; - if (strToolTip.LoadString(pChild->GetDlgCtrlID())) { - m_wndToolTip.AddTool(pChild, strToolTip); - } - } -} - -void CPPageBase::SetButtonIcon(UINT nIDButton, IconDef iconDef) -{ - if (!m_buttonIcons.count(iconDef)) { - CImage img; - if (iconDef.svgTargetWidth) { - SVGImage::LoadIconDef(iconDef, img); - } else { - img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); - } - CImageList& imageList = m_buttonIcons[iconDef]; - imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 1, 0); - imageList.Add(CBitmap::FromHandle(img), nullptr); - } - - BUTTON_IMAGELIST buttonImageList; - buttonImageList.himl = m_buttonIcons[iconDef]; - buttonImageList.margin = { 0, 0, 0, 0 }; - buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; - static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); -} - -BOOL CPPageBase::PreTranslateMessage(MSG* pMsg) -{ - if (IsWindow(m_wndToolTip)) - if (pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST) { - MSG msg; - memcpy(&msg, pMsg, sizeof(MSG)); - for (HWND hWndParent = ::GetParent(msg.hwnd); - hWndParent && hWndParent != m_hWnd; - hWndParent = ::GetParent(hWndParent)) { - msg.hwnd = hWndParent; - } - - if (msg.hwnd) { - m_wndToolTip.RelayEvent(&msg); - } - } - - return __super::PreTranslateMessage(pMsg); -} - -BEGIN_MESSAGE_MAP(CPPageBase, CCmdUIPropertyPage) - ON_WM_DESTROY() -END_MESSAGE_MAP() - - -// CPPageBase message handlers - -BOOL CPPageBase::OnSetActive() -{ - ASSERT(IS_INTRESOURCE(m_pPSP->pszTemplate)); - AfxGetAppSettings().nLastUsedPage = (WORD)(ULONG_PTR)m_pPSP->pszTemplate; - SetRedraw(false); //adipose: disable redraw due to CPropertyPage::OnSetActive forcing ddx, which causes "optimized" redraw of comboboxes without consulting subclass paint method - BOOL ret = __super::OnSetActive(); - SetRedraw(true); //adipose: reenable redraw. no regressions observed by enabling after ddx - return ret; -} - -BOOL CPPageBase::OnApply() -{ - // There is no main frame when the option dialog is displayed stand-alone - if (CMainFrame* pMainFrame = AfxGetMainFrame()) { - pMainFrame->PostMessage(WM_SAVESETTINGS); - } - return __super::OnApply(); -} - -void CPPageBase::OnDestroy() -{ - __super::OnDestroy(); - m_wndToolTip.DestroyWindow(); -} - -void CPPageBase::ShowPPage(CUnknown* (WINAPI* CreateInstance)(LPUNKNOWN lpunk, HRESULT* phr)) { - if (!CreateInstance) { - return; - } - - HRESULT hr; - CUnknown* pObj = CreateInstance(nullptr, &hr); - - if (!pObj) { - return; - } - - CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pObj; - - if (SUCCEEDED(hr)) { - if (CComQIPtr pSPP = pUnk) { - CComPropertySheet ps(ResStr(IDS_PROPSHEET_PROPERTIES), this); - ps.AddPages(pSPP); - ps.DoModal(); - } - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2016 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 . + * + */ + +#include "stdafx.h" +#include "MainFrm.h" +#include "mplayerc.h" +#include "PPageBase.h" +#include "SettingsDefines.h" +#include "ComPropertySheet.h" + + +// CPPageBase dialog + +IMPLEMENT_DYNAMIC(CPPageBase, CCmdUIPropertyPage) +CPPageBase::CPPageBase(UINT nIDTemplate, UINT nIDCaption) + : CCmdUIPropertyPage(nIDTemplate, nIDCaption) +{ +} + +CPPageBase::~CPPageBase() +{ +} + +void CPPageBase::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); +} + +bool CPPageBase::FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT) +{ + bool bNeedTooltip = false; + + CDC* pDC = comboBox.GetDC(); + CFont* pFont = comboBox.GetFont(); + CFont* pOldFont = pDC->SelectObject(pFont); + + TEXTMETRIC tm; + pDC->GetTextMetrics(&tm); + + CRect comboBoxRect; + comboBox.GetWindowRect(comboBoxRect); + comboBoxRect.right -= GetSystemMetrics(SM_CXVSCROLL) + 2 * GetSystemMetrics(SM_CXEDGE); + + int i = comboBox.GetCurSel(); + CString str; + comboBox.GetLBText(i, str); + CSize textSize; + textSize = pDC->GetTextExtent(str); + pDC->SelectObject(pOldFont); + comboBox.ReleaseDC(pDC); + textSize.cx += tm.tmAveCharWidth; + + if (textSize.cx > comboBoxRect.Width()) { + bNeedTooltip = true; + if (str.GetLength() > _countof(pTTT->szText) - 1) { + str.Truncate(_countof(pTTT->szText) - 1); + } + _tcscpy_s(pTTT->szText, str); + pTTT->hinst = nullptr; + } + + return bNeedTooltip; +} + +void CPPageBase::CreateToolTip() +{ + m_wndToolTip.Create(this, TTS_NOPREFIX); + m_wndToolTip.Activate(TRUE); + m_wndToolTip.SetMaxTipWidth(300); + m_wndToolTip.SetDelayTime(TTDT_AUTOPOP, 10000); + for (CWnd* pChild = GetWindow(GW_CHILD); pChild; pChild = pChild->GetWindow(GW_HWNDNEXT)) { + CString strToolTip; + if (strToolTip.LoadString(pChild->GetDlgCtrlID())) { + m_wndToolTip.AddTool(pChild, strToolTip); + } + } +} + +void CPPageBase::SetButtonIcon(UINT nIDButton, IconDef iconDef) +{ + if (!m_buttonIcons.count(iconDef)) { + CImage img; + if (iconDef.svgTargetWidth) { + SVGImage::LoadIconDef(iconDef, img); + } else { + img.LoadFromResource(AfxGetInstanceHandle(), iconDef.nIDIcon); + } + CImageList& imageList = m_buttonIcons[iconDef]; + imageList.Create(img.GetWidth(), img.GetHeight(), ILC_COLOR32, 1, 0); + imageList.Add(CBitmap::FromHandle(img), nullptr); + } + + BUTTON_IMAGELIST buttonImageList; + buttonImageList.himl = m_buttonIcons[iconDef]; + buttonImageList.margin = { 0, 0, 0, 0 }; + buttonImageList.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER; + static_cast(GetDlgItem(nIDButton))->SetImageList(&buttonImageList); +} + +BOOL CPPageBase::PreTranslateMessage(MSG* pMsg) +{ + if (IsWindow(m_wndToolTip)) + if (pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST) { + MSG msg; + memcpy(&msg, pMsg, sizeof(MSG)); + for (HWND hWndParent = ::GetParent(msg.hwnd); + hWndParent && hWndParent != m_hWnd; + hWndParent = ::GetParent(hWndParent)) { + msg.hwnd = hWndParent; + } + + if (msg.hwnd) { + m_wndToolTip.RelayEvent(&msg); + } + } + + return __super::PreTranslateMessage(pMsg); +} + +BEGIN_MESSAGE_MAP(CPPageBase, CCmdUIPropertyPage) + ON_WM_DESTROY() +END_MESSAGE_MAP() + + +// CPPageBase message handlers + +BOOL CPPageBase::OnSetActive() +{ + ASSERT(IS_INTRESOURCE(m_pPSP->pszTemplate)); + AfxGetAppSettings().nLastUsedPage = (WORD)(ULONG_PTR)m_pPSP->pszTemplate; + SetRedraw(false); //adipose: disable redraw due to CPropertyPage::OnSetActive forcing ddx, which causes "optimized" redraw of comboboxes without consulting subclass paint method + BOOL ret = __super::OnSetActive(); + SetRedraw(true); //adipose: reenable redraw. no regressions observed by enabling after ddx + return ret; +} + +BOOL CPPageBase::OnApply() +{ + // There is no main frame when the option dialog is displayed stand-alone + if (CMainFrame* pMainFrame = AfxGetMainFrame()) { + pMainFrame->PostMessage(WM_SAVESETTINGS); + } + return __super::OnApply(); +} + +void CPPageBase::OnDestroy() +{ + __super::OnDestroy(); + m_wndToolTip.DestroyWindow(); +} + +void CPPageBase::ShowPPage(CUnknown* (WINAPI* CreateInstance)(LPUNKNOWN lpunk, HRESULT* phr)) { + if (!CreateInstance) { + return; + } + + HRESULT hr; + CUnknown* pObj = CreateInstance(nullptr, &hr); + + if (!pObj) { + return; + } + + CComPtr pUnk = (IUnknown*)(INonDelegatingUnknown*)pObj; + + if (SUCCEEDED(hr)) { + if (CComQIPtr pSPP = pUnk) { + CComPropertySheet ps(ResStr(IDS_PROPSHEET_PROPERTIES), this); + ps.AddPages(pSPP); + ps.DoModal(); + } + } +} diff --git a/src/mpc-hc/PPageBase.h b/src/mpc-hc/PPageBase.h index 9471ed5f04b..89f0450efa2 100644 --- a/src/mpc-hc/PPageBase.h +++ b/src/mpc-hc/PPageBase.h @@ -1,61 +1,61 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include "ResizableLib/ResizableDialog.h" -#include "CMPCThemeToolTipCtrl.h" -#include "SVGImage.h" - -// CPPageBase dialog -using namespace SVGImage; -class CPPageBase : public CCmdUIPropertyPage -{ - DECLARE_DYNAMIC(CPPageBase) - -protected: - CMPCThemeToolTipCtrl m_wndToolTip; - std::map m_buttonIcons; - - static bool FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT); - - void CreateToolTip(); - - void SetButtonIcon(UINT nIDButton, IconDef iconDef); - -public: - CPPageBase(UINT nIDTemplate, UINT nIDCaption = 0); - virtual ~CPPageBase(); - - // Dialog Data - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL PreTranslateMessage(MSG* pMsg); - virtual BOOL OnSetActive(); - virtual BOOL OnApply(); - void ShowPPage(CUnknown* (__stdcall* CreateInstance)(LPUNKNOWN lpunk, HRESULT* phr)); - - DECLARE_MESSAGE_MAP() - -public: - afx_msg void OnDestroy(); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include "ResizableLib/ResizableDialog.h" +#include "CMPCThemeToolTipCtrl.h" +#include "SVGImage.h" + +// CPPageBase dialog +using namespace SVGImage; +class CPPageBase : public CCmdUIPropertyPage +{ + DECLARE_DYNAMIC(CPPageBase) + +protected: + CMPCThemeToolTipCtrl m_wndToolTip; + std::map m_buttonIcons; + + static bool FillComboToolTip(CComboBox& comboBox, TOOLTIPTEXT* pTTT); + + void CreateToolTip(); + + void SetButtonIcon(UINT nIDButton, IconDef iconDef); + +public: + CPPageBase(UINT nIDTemplate, UINT nIDCaption = 0); + virtual ~CPPageBase(); + + // Dialog Data + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual BOOL OnSetActive(); + virtual BOOL OnApply(); + void ShowPPage(CUnknown* (__stdcall* CreateInstance)(LPUNKNOWN lpunk, HRESULT* phr)); + + DECLARE_MESSAGE_MAP() + +public: + afx_msg void OnDestroy(); +}; diff --git a/src/mpc-hc/PPageCapture.cpp b/src/mpc-hc/PPageCapture.cpp index e6a01dd32e8..584710b6726 100644 --- a/src/mpc-hc/PPageCapture.cpp +++ b/src/mpc-hc/PPageCapture.cpp @@ -1,730 +1,730 @@ -/* - * (C) 2009-2015, 2017 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 . - * - */ - -// PPageCapture.cpp : implementation file -// - -#include "stdafx.h" -#include -#include -#include -#include -#include - -#include "mplayerc.h" -#include "PPageCapture.h" -#include "DSUtil.h" - - -struct cc_t { - long code; - AnalogVideoStandard standard; - const TCHAR* str; -} static constexpr s_countrycodes[] = { - {1, AnalogVideo_NTSC_M, _T("USA")}, - /* - {1, AnalogVideo_NTSC_M, _T("Anguilla")}, - {1, AnalogVideo_NTSC_M, _T("Antigua")}, - {1, AnalogVideo_NTSC_M, _T("Bahamas")}, - {1, AnalogVideo_NTSC_M, _T("Barbados")}, - {1, AnalogVideo_NTSC_M, _T("Bermuda")}, - {1, AnalogVideo_NTSC_M, _T("British Virgin Islands")}, - {1, AnalogVideo_NTSC_M, _T("Canada")}, - {1, AnalogVideo_NTSC_M, _T("Cayman Islands")}, - {1, AnalogVideo_NTSC_M, _T("Dominica")}, - {1, AnalogVideo_NTSC_M, _T("Dominican Republic")}, - {1, AnalogVideo_NTSC_M, _T("Grenada")}, - {1, AnalogVideo_NTSC_M, _T("Jamaica")}, - {1, AnalogVideo_NTSC_M, _T("Montserrat")}, - {1, AnalogVideo_NTSC_M, _T("Nevis")}, - {1, AnalogVideo_NTSC_M, _T("St. Kitts")}, - {1, AnalogVideo_NTSC_M, _T("St. Vincent and the Grenadines")}, - {1, AnalogVideo_NTSC_M, _T("Trinidad and Tobago")}, - {1, AnalogVideo_NTSC_M, _T("Turks and Caicos Islands")}, - {1, AnalogVideo_NTSC_M, _T("Barbuda")}, - {1, AnalogVideo_NTSC_M, _T("Puerto Rico")}, - {1, AnalogVideo_NTSC_M, _T("Saint Lucia")}, - {1, AnalogVideo_NTSC_M, _T("United States Virgin Islands")}, - */ - {2, AnalogVideo_NTSC_M, _T("Canada")}, - {7, AnalogVideo_SECAM_D, _T("Russia")}, - /* - {7, AnalogVideo_SECAM_D, _T("Kazakhstan")}, - {7, AnalogVideo_SECAM_D, _T("Kyrgyzstan")}, - {7, AnalogVideo_SECAM_D, _T("Tajikistan")}, - {7, AnalogVideo_SECAM_D, _T("Turkmenistan")}, - {7, AnalogVideo_SECAM_D, _T("Uzbekistan")}, - */ - {20, AnalogVideo_SECAM_B, _T("Egypt")}, - {27, AnalogVideo_PAL_I, _T("South Africa")}, - {30, AnalogVideo_SECAM_B, _T("Greece")}, - {31, AnalogVideo_PAL_B, _T("Netherlands")}, - {32, AnalogVideo_PAL_B, _T("Belgium")}, - {33, AnalogVideo_SECAM_L, _T("France")}, - {34, AnalogVideo_PAL_B, _T("Spain")}, - {36, AnalogVideo_SECAM_D, _T("Hungary")}, - {39, AnalogVideo_PAL_B, _T("Italy")}, - // {39, AnalogVideo_PAL_B, _T("Vatican City")}, - {40, AnalogVideo_PAL_D, _T("Romania")}, - {41, AnalogVideo_PAL_B, _T("Switzerland")}, - // {41, AnalogVideo_PAL_B, _T("Liechtenstein")}, - {43, AnalogVideo_PAL_B, _T("Austria")}, - {44, AnalogVideo_PAL_I, _T("United Kingdom")}, - {45, AnalogVideo_PAL_B, _T("Denmark")}, - {46, AnalogVideo_PAL_B, _T("Sweden")}, - {47, AnalogVideo_PAL_B, _T("Norway")}, - {48, AnalogVideo_PAL_B, _T("Poland")}, - {49, AnalogVideo_PAL_B, _T("Germany")}, - {51, AnalogVideo_NTSC_M, _T("Peru")}, - {52, AnalogVideo_NTSC_M, _T("Mexico")}, - {53, AnalogVideo_NTSC_M, _T("Cuba")}, - // {53, AnalogVideo_NTSC_M, _T("Guantanamo Bay")}, - {54, AnalogVideo_PAL_N, _T("Argentina")}, - {55, AnalogVideo_PAL_M, _T("Brazil")}, - {56, AnalogVideo_NTSC_M, _T("Chile")}, - {57, AnalogVideo_NTSC_M, _T("Colombia")}, - {58, AnalogVideo_NTSC_M, _T("Bolivarian Republic of Venezuela")}, - {60, AnalogVideo_PAL_B, _T("Malaysia")}, - {61, AnalogVideo_PAL_B, _T("Australia")}, - // {61, AnalogVideo_NTSC_M, _T("Cocos-Keeling Islands")}, - {62, AnalogVideo_PAL_B, _T("Indonesia")}, - {63, AnalogVideo_NTSC_M, _T("Philippines")}, - {64, AnalogVideo_PAL_B, _T("New Zealand")}, - {65, AnalogVideo_PAL_B, _T("Singapore")}, - {66, AnalogVideo_PAL_B, _T("Thailand")}, - {81, AnalogVideo_NTSC_M_J, _T("Japan")}, - {82, AnalogVideo_NTSC_M, _T("Korea (South)")}, - {84, AnalogVideo_NTSC_M, _T("Vietnam")}, - {86, AnalogVideo_PAL_D, _T("China")}, - {90, AnalogVideo_PAL_B, _T("Turkey")}, - {91, AnalogVideo_PAL_B, _T("India")}, - {92, AnalogVideo_PAL_B, _T("Pakistan")}, - {93, AnalogVideo_PAL_B, _T("Afghanistan")}, - {94, AnalogVideo_PAL_B, _T("Sri Lanka")}, - {95, AnalogVideo_NTSC_M, _T("Myanmar")}, - {98, AnalogVideo_SECAM_B, _T("Iran")}, - {212, AnalogVideo_SECAM_B, _T("Morocco")}, - {213, AnalogVideo_PAL_B, _T("Algeria")}, - {216, AnalogVideo_SECAM_B, _T("Tunisia")}, - {218, AnalogVideo_SECAM_B, _T("Libya")}, - {220, AnalogVideo_SECAM_K, _T("Gambia")}, - {221, AnalogVideo_SECAM_K, _T("Senegal Republic")}, - {222, AnalogVideo_SECAM_B, _T("Mauritania")}, - {223, AnalogVideo_SECAM_K, _T("Mali")}, - {224, AnalogVideo_SECAM_K, _T("Guinea")}, - {225, AnalogVideo_SECAM_K, _T("Cote D'Ivoire")}, - {226, AnalogVideo_SECAM_K, _T("Burkina Faso")}, - {227, AnalogVideo_SECAM_K, _T("Niger")}, - {228, AnalogVideo_SECAM_K, _T("Togo")}, - {229, AnalogVideo_SECAM_K, _T("Benin")}, - {230, AnalogVideo_SECAM_B, _T("Mauritius")}, - {231, AnalogVideo_PAL_B, _T("Liberia")}, - {232, AnalogVideo_PAL_B, _T("Sierra Leone")}, - {233, AnalogVideo_PAL_B, _T("Ghana")}, - {234, AnalogVideo_PAL_B, _T("Nigeria")}, - {235, AnalogVideo_PAL_B, _T("Chad")}, - {236, AnalogVideo_PAL_B, _T("Central African Republic")}, - {237, AnalogVideo_PAL_B, _T("Cameroon")}, - {238, AnalogVideo_NTSC_M, _T("Cape Verde Islands")}, - {239, AnalogVideo_PAL_B, _T("Sao Tome and Principe")}, - {240, AnalogVideo_SECAM_B, _T("Equatorial Guinea")}, - {241, AnalogVideo_SECAM_K, _T("Gabon")}, - {242, AnalogVideo_SECAM_D, _T("Congo")}, - {243, AnalogVideo_SECAM_K, _T("Congo(DRC)")}, - {244, AnalogVideo_PAL_I, _T("Angola")}, - {245, AnalogVideo_NTSC_M, _T("Guinea-Bissau")}, - {246, AnalogVideo_NTSC_M, _T("Diego Garcia")}, - {247, AnalogVideo_NTSC_M, _T("Ascension Island")}, - {248, AnalogVideo_PAL_B, _T("Seychelle Islands")}, - {249, AnalogVideo_PAL_B, _T("Sudan")}, - {250, AnalogVideo_PAL_B, _T("Rwanda")}, - {251, AnalogVideo_PAL_B, _T("Ethiopia")}, - {252, AnalogVideo_PAL_B, _T("Somalia")}, - {253, AnalogVideo_SECAM_K, _T("Djibouti")}, - {254, AnalogVideo_PAL_B, _T("Kenya")}, - {255, AnalogVideo_PAL_B, _T("Tanzania")}, - {256, AnalogVideo_PAL_B, _T("Uganda")}, - {257, AnalogVideo_SECAM_K, _T("Burundi")}, - {258, AnalogVideo_PAL_B, _T("Mozambique")}, - {260, AnalogVideo_PAL_B, _T("Zambia")}, - {261, AnalogVideo_SECAM_K, _T("Madagascar")}, - {262, AnalogVideo_SECAM_K, _T("Reunion Island")}, - {263, AnalogVideo_PAL_B, _T("Zimbabwe")}, - {264, AnalogVideo_PAL_I, _T("Namibia")}, - {265, AnalogVideo_NTSC_M, _T("Malawi")}, - {266, AnalogVideo_PAL_I, _T("Lesotho")}, - {267, AnalogVideo_SECAM_K, _T("Botswana")}, - {268, AnalogVideo_PAL_B, _T("Swaziland")}, - {269, AnalogVideo_SECAM_K, _T("Mayotte Island")}, - // {269, AnalogVideo_NTSC_M, _T("Comoros")}, - {290, AnalogVideo_NTSC_M, _T("St. Helena")}, - {291, AnalogVideo_NTSC_M, _T("Eritrea")}, - {297, AnalogVideo_NTSC_M, _T("Aruba")}, - {298, AnalogVideo_PAL_B, _T("Faroe Islands")}, - {299, AnalogVideo_NTSC_M, _T("Greenland")}, - {350, AnalogVideo_PAL_B, _T("Gibraltar")}, - {351, AnalogVideo_PAL_B, _T("Portugal")}, - {352, AnalogVideo_PAL_B, _T("Luxembourg")}, - {353, AnalogVideo_PAL_I, _T("Ireland")}, - {354, AnalogVideo_PAL_B, _T("Iceland")}, - {355, AnalogVideo_PAL_B, _T("Albania")}, - {356, AnalogVideo_PAL_B, _T("Malta")}, - {357, AnalogVideo_PAL_B, _T("Cyprus")}, - {358, AnalogVideo_PAL_B, _T("Finland")}, - {359, AnalogVideo_SECAM_D, _T("Bulgaria")}, - {370, AnalogVideo_PAL_B, _T("Lithuania")}, - {371, AnalogVideo_SECAM_D, _T("Latvia")}, - {372, AnalogVideo_PAL_B, _T("Estonia")}, - {373, AnalogVideo_SECAM_D, _T("Moldova")}, - {374, AnalogVideo_SECAM_D, _T("Armenia")}, - {375, AnalogVideo_SECAM_D, _T("Belarus")}, - {376, AnalogVideo_NTSC_M, _T("Andorra")}, - {377, AnalogVideo_SECAM_G, _T("Monaco")}, - {378, AnalogVideo_PAL_B, _T("San Marino")}, - {380, AnalogVideo_SECAM_D, _T("Ukraine")}, - {381, AnalogVideo_PAL_B, _T("Serbia")}, - {385, AnalogVideo_PAL_B, _T("Croatia")}, - {386, AnalogVideo_PAL_B, _T("Slovenia")}, - {387, AnalogVideo_PAL_B, _T("Bosnia and Herzegovina")}, - {389, AnalogVideo_PAL_B, _T("F.Y.R.O.M. (Former Yugoslav Republic of Macedonia)")}, - {420, AnalogVideo_PAL_D, _T("Czech Republic")}, - {421, AnalogVideo_PAL_B, _T("Slovak Republic")}, - {500, AnalogVideo_PAL_I, _T("Falkland Islands (Islas Malvinas)")}, - {501, AnalogVideo_NTSC_M, _T("Belize")}, - {502, AnalogVideo_NTSC_M, _T("Guatemala")}, - {503, AnalogVideo_NTSC_M, _T("El Salvador")}, - {504, AnalogVideo_NTSC_M, _T("Honduras")}, - {505, AnalogVideo_NTSC_M, _T("Nicaragua")}, - {506, AnalogVideo_NTSC_M, _T("Costa Rica")}, - {507, AnalogVideo_NTSC_M, _T("Panama")}, - {508, AnalogVideo_SECAM_K, _T("St. Pierre and Miquelon")}, - {509, AnalogVideo_NTSC_M, _T("Haiti")}, - {590, AnalogVideo_SECAM_K, _T("Guadeloupe")}, - // {590, AnalogVideo_NTSC_M, _T("French Antilles")}, - {591, AnalogVideo_PAL_N, _T("Bolivia")}, - {592, AnalogVideo_SECAM_K, _T("Guyana")}, - {593, AnalogVideo_NTSC_M, _T("Ecuador")}, - {594, AnalogVideo_SECAM_K, _T("French Guiana")}, - {595, AnalogVideo_PAL_N, _T("Paraguay")}, - {596, AnalogVideo_SECAM_K, _T("Martinique")}, - {597, AnalogVideo_NTSC_M, _T("Suriname")}, - {598, AnalogVideo_PAL_N, _T("Uruguay")}, - {599, AnalogVideo_NTSC_M, _T("Netherlands Antilles")}, - {670, AnalogVideo_NTSC_M, _T("Saipan Island")}, - // {670, AnalogVideo_NTSC_M, _T("Rota Island")}, - // {670, AnalogVideo_NTSC_M, _T("Tinian Island")}, - {671, AnalogVideo_NTSC_M, _T("Guam")}, - // {672, AnalogVideo_NTSC_M, _T("Christmas Island")}, - // {672, AnalogVideo_NTSC_M, _T("Australian Antarctic Territory")}, - // {672, AnalogVideo_PAL_B, _T("Norfolk Island")}, - {673, AnalogVideo_PAL_B, _T("Brunei")}, - {674, AnalogVideo_NTSC_M, _T("Nauru")}, - {675, AnalogVideo_PAL_B, _T("Papua New Guinea")}, - {676, AnalogVideo_NTSC_M, _T("Tonga")}, - {677, AnalogVideo_NTSC_M, _T("Solomon Islands")}, - {678, AnalogVideo_NTSC_M, _T("Vanuatu")}, - {679, AnalogVideo_NTSC_M, _T("Fiji Islands")}, - {680, AnalogVideo_NTSC_M, _T("Palau")}, - {681, AnalogVideo_SECAM_K, _T("Wallis and Futuna Islands")}, - {682, AnalogVideo_PAL_B, _T("Cook Islands")}, - {683, AnalogVideo_NTSC_M, _T("Niue")}, - {684, AnalogVideo_NTSC_M, _T("Territory of American Samoa")}, - {685, AnalogVideo_PAL_B, _T("Samoa")}, - {686, AnalogVideo_PAL_B, _T("Kiribati Republic")}, - {687, AnalogVideo_SECAM_K, _T("New Caledonia")}, - {688, AnalogVideo_NTSC_M, _T("Tuvalu")}, - {689, AnalogVideo_SECAM_K, _T("French Polynesia")}, - {690, AnalogVideo_NTSC_M, _T("Tokelau")}, - {691, AnalogVideo_NTSC_M, _T("Micronesia")}, - {692, AnalogVideo_NTSC_M, _T("Marshall Islands")}, - {850, AnalogVideo_SECAM_D, _T("Korea (North)")}, - {852, AnalogVideo_PAL_I, _T("Hong Kong SAR")}, - {853, AnalogVideo_PAL_I, _T("Macao SAR")}, - {855, AnalogVideo_PAL_B, _T("Cambodia")}, - {856, AnalogVideo_PAL_B, _T("Laos")}, - {871, AnalogVideo_NTSC_M, _T("INMARSAT (Atlantic-East)")}, - {872, AnalogVideo_NTSC_M, _T("INMARSAT (Pacific)")}, - {873, AnalogVideo_NTSC_M, _T("INMARSAT (Indian)")}, - {874, AnalogVideo_NTSC_M, _T("INMARSAT (Atlantic-West)")}, - {880, AnalogVideo_PAL_B, _T("Bangladesh")}, - {886, AnalogVideo_NTSC_M, _T("Taiwan")}, - {960, AnalogVideo_PAL_B, _T("Maldives")}, - {961, AnalogVideo_SECAM_B, _T("Lebanon")}, - {962, AnalogVideo_PAL_B, _T("Jordan")}, - {963, AnalogVideo_SECAM_B, _T("Syria")}, - {964, AnalogVideo_SECAM_B, _T("Iraq")}, - {965, AnalogVideo_PAL_B, _T("Kuwait")}, - {966, AnalogVideo_SECAM_B, _T("Saudi Arabia")}, - {967, AnalogVideo_PAL_B, _T("Yemen")}, - {968, AnalogVideo_PAL_B, _T("Oman")}, - {971, AnalogVideo_PAL_B, _T("United Arab Emirates")}, - {972, AnalogVideo_PAL_B, _T("Israel")}, - {973, AnalogVideo_PAL_B, _T("Bahrain")}, - {974, AnalogVideo_PAL_B, _T("Qatar")}, - {975, AnalogVideo_NTSC_M, _T("Bhutan")}, - {976, AnalogVideo_SECAM_D, _T("Mongolia")}, - {977, AnalogVideo_PAL_B, _T("Nepal")}, - {994, AnalogVideo_SECAM_D, _T("Azerbaijan")}, - {995, AnalogVideo_SECAM_D, _T("Georgia")} -}; - - -// CPPageCapture dialog - -IMPLEMENT_DYNAMIC(CPPageCapture, CMPCThemePPageBase) - -CPPageCapture::CPPageCapture() - : CMPCThemePPageBase(CPPageCapture::IDD, CPPageCapture::IDD) - , m_iDefaultDevice(0) -{ -} - -CPPageCapture::~CPPageCapture() -{ -} - -void CPPageCapture::DoDataExchange(CDataExchange* pDX) -{ - CMPCThemePPageBase::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO1, m_cbAnalogVideo); - DDX_Control(pDX, IDC_COMBO2, m_cbAnalogAudio); - DDX_Control(pDX, IDC_COMBO9, m_cbAnalogCountry); - DDX_Control(pDX, IDC_COMBO4, m_cbDigitalNetworkProvider); - DDX_Control(pDX, IDC_COMBO5, m_cbDigitalTuner); - DDX_Control(pDX, IDC_COMBO3, m_cbDigitalReceiver); - DDX_Radio(pDX, IDC_RADIO1, m_iDefaultDevice); - DDX_Control(pDX, IDC_COMBO6, m_cbRebuildFilterGraph); - DDX_Control(pDX, IDC_COMBO7, m_cbStopFilterGraph); -} - -BEGIN_MESSAGE_MAP(CPPageCapture, CMPCThemePPageBase) - ON_UPDATE_COMMAND_UI(IDC_COMBO1, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_COMBO2, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_COMBO9, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_STATIC1, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_STATIC2, OnUpdateAnalog) - ON_UPDATE_COMMAND_UI(IDC_STATIC3, OnUpdateAnalog) - //ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_COMBO5, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_STATIC4, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_STATIC5, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_COMBO3, OnUpdateDigitalReciver) - ON_UPDATE_COMMAND_UI(IDC_STATIC6, OnUpdateDigitalReciver) - ON_UPDATE_COMMAND_UI(IDC_COMBO6, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_COMBO7, OnUpdateDigitalStopFilterGraph) - ON_UPDATE_COMMAND_UI(IDC_CHECK1, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_PPAGECAPTURE_ST10, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_PPAGECAPTURE_ST11, OnUpdateDigital) - ON_UPDATE_COMMAND_UI(IDC_PPAGECAPTURE_ST12, OnUpdateDigitalStopFilterGraph) - ON_UPDATE_COMMAND_UI(IDC_PPAGECAPTURE_DESC1, OnUpdateDigital) - ON_CBN_SELCHANGE(IDC_COMBO6, OnSelChangeRebuildFilterGraph) - ON_CBN_SELCHANGE(IDC_COMBO7, OnSelChangeStopFilterGraph) - ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) -END_MESSAGE_MAP() - -// CPPageCapture message handlers - -BOOL CPPageCapture::OnInitDialog() -{ - __super::OnInitDialog(); - - SetHandCursor(m_hWnd, IDC_COMBO1); - - const CAppSettings& s = AfxGetAppSettings(); - - FindAnalogDevices(); - FindDigitalDevices(); - - if (m_cbAnalogVideo.GetCount() && m_cbDigitalTuner.GetCount()) { - m_iDefaultDevice = s.iDefaultCaptureDevice; - } else if (m_cbAnalogVideo.GetCount()) { - m_iDefaultDevice = 0; - GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE); - } else if (m_cbDigitalTuner.GetCount()) { - m_iDefaultDevice = 1; - GetDlgItem(IDC_RADIO1)->EnableWindow(FALSE); - } else { - m_iDefaultDevice = s.iDefaultCaptureDevice; - GetDlgItem(IDC_RADIO2)->EnableWindow(FALSE); - GetDlgItem(IDC_RADIO1)->EnableWindow(FALSE); - } - - //we don't offer other providers anymore, but in case someone wants to know what is being used, we leave this here, disabled and defaulted - //note this setting is not used anywhere and Network Provider is hard-coded elsewhere in the code - m_cbDigitalNetworkProvider.AddString(_T("Microsoft Network Provider")); - m_cbDigitalNetworkProvider.SetCurSel(0); - GetDlgItem(IDC_COMBO4)->EnableWindow(FALSE); - - m_cbRebuildFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_FG0)); - m_cbRebuildFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_FG1)); - m_cbRebuildFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_FG2)); - m_cbRebuildFilterGraph.SetCurSel(s.nDVBRebuildFilterGraph); - CorrectComboListWidth(m_cbRebuildFilterGraph); - - m_cbStopFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_SFG0)); - m_cbStopFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_SFG1)); - m_cbStopFilterGraph.AddString(ResStr(IDS_PPAGE_CAPTURE_SFG2)); - m_cbStopFilterGraph.SetCurSel(s.nDVBStopFilterGraph); - CorrectComboListWidth(m_cbStopFilterGraph); - - OnSelChangeRebuildFilterGraph(); - OnSelChangeStopFilterGraph(); - - UpdateData(FALSE); - - SaveFoundDevices(); // Save (new) devices to ensure that comboboxes reflect actual settings. - - AdjustDynamicWidgets(); - EnableThemedDialogTooltips(this); - - return TRUE; -} - -BOOL CPPageCapture::OnApply() -{ - UpdateData(); - SaveFoundDevices(); - return __super::OnApply(); -} - -void CPPageCapture::OnUpdateAnalog(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(IsDlgButtonChecked(IDC_RADIO1) && m_cbAnalogVideo.GetCount()); -} - -void CPPageCapture::OnUpdateDigital(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(IsDlgButtonChecked(IDC_RADIO2) && m_cbDigitalTuner.GetCount()); -} - -void CPPageCapture::OnUpdateDigitalReciver(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(IsDlgButtonChecked(IDC_RADIO2) && m_cbDigitalReceiver.GetCount()); -} - -void CPPageCapture::OnUpdateDigitalStopFilterGraph(CCmdUI* pCmdUI) -{ - pCmdUI->Enable(IsDlgButtonChecked(IDC_RADIO2) && m_cbDigitalTuner.GetCount() && - (m_cbRebuildFilterGraph.GetCurSel() != 2)); -} - -void CPPageCapture::OnSelChangeRebuildFilterGraph() -{ - if (m_cbRebuildFilterGraph.GetCurSel() == 0) { - GetDlgItem(IDC_PPAGECAPTURE_DESC1)->SetWindowText(ResStr(IDS_PPAGE_CAPTURE_FGDESC0)); - } else if (m_cbRebuildFilterGraph.GetCurSel() == 1) { - GetDlgItem(IDC_PPAGECAPTURE_DESC1)->SetWindowText(ResStr(IDS_PPAGE_CAPTURE_FGDESC1)); - } else if (m_cbRebuildFilterGraph.GetCurSel() == 2) { - GetDlgItem(IDC_PPAGECAPTURE_DESC1)->SetWindowText(ResStr(IDS_PPAGE_CAPTURE_FGDESC2)); - } else { - GetDlgItem(IDC_PPAGECAPTURE_DESC1)->SetWindowText(_T("")); - } - SetModified(); -} - - -void CPPageCapture::OnSelChangeStopFilterGraph() -{ - SetModified(); -} - -BOOL CPPageCapture::OnToolTipNotify(UINT id, NMHDR* pNMH, LRESULT* pResult) -{ - LPTOOLTIPTEXT pTTT = reinterpret_cast(pNMH); - - UINT_PTR nID = pNMH->idFrom; - if (pTTT->uFlags & TTF_IDISHWND) { - nID = ::GetDlgCtrlID((HWND)nID); - } - - BOOL bRet = FALSE; - - switch (nID) { - case IDC_COMBO1: - bRet = FillComboToolTip(m_cbAnalogVideo, pTTT); - break; - case IDC_COMBO2: - bRet = FillComboToolTip(m_cbAnalogAudio, pTTT); - break; - case IDC_COMBO9: - bRet = FillComboToolTip(m_cbAnalogCountry, pTTT); - break; -/* - case IDC_COMBO4: - bRet = FillComboToolTip(m_cbDigitalNetworkProvider, pTTT); - break; -*/ - case IDC_COMBO5: - bRet = FillComboToolTip(m_cbDigitalTuner, pTTT); - break; - case IDC_COMBO3: - bRet = FillComboToolTip(m_cbDigitalReceiver, pTTT); - break; - case IDC_COMBO6: - bRet = FillComboToolTip(m_cbRebuildFilterGraph, pTTT); - break; - case IDC_COMBO7: - bRet = FillComboToolTip(m_cbStopFilterGraph, pTTT); - break; - } - - if (bRet) { - PlaceThemedDialogTooltip(nID); - } - - return bRet; -} - - -void CPPageCapture::FindAnalogDevices() -{ - const CAppSettings& s = AfxGetAppSettings(); - int iSel = 0; - - // List video devices - BeginEnumSysDev(CLSID_VideoInputDeviceCategory, pMoniker) { - CComPtr pPB; - pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)); - - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - int i = m_cbAnalogVideo.AddString(CString(var.bstrVal)); - CComHeapPtr strName; - if (SUCCEEDED(pMoniker->GetDisplayName(nullptr, nullptr, &strName))) { - m_vidnames.Add(CString(strName)); - if (s.strAnalogVideo == CString(strName)) { - iSel = i; - } - } - } - } - EndEnumSysDev; - - if (m_cbAnalogVideo.GetCount()) { - m_cbAnalogVideo.SetCurSel(iSel); - } else { - return; - } - - // List audio devices - iSel = 0; - { - int i = m_cbAnalogAudio.AddString(_T("

Create(SubtitlesProviders* pOwner) { \ - return std::make_shared

(pOwner); \ - } \ -private: \ - virtual std::string Name() const override { return #P; } \ - virtual std::string DisplayName() const override { return N; } \ - virtual std::string Url() const override { return U; } \ - virtual const std::set& Languages() const override; \ - virtual bool Flags(DWORD dwFlags) const override { return (dwFlags & (F)) == dwFlags; } \ - virtual int Icon() const override { return I; } \ -private: \ - virtual SRESULT Search(const SubtitlesInfo& pFileInfo) override; \ - virtual SRESULT Download(SubtitlesInfo& pSubtitlesInfo) override; -#define DEFINE_SUBTITLESPROVIDER_END \ -}; - -#if 0 -DEFINE_SUBTITLESPROVIDER_BEGIN(OpenSubtitles, "OpenSubtitles.org", "https://api.opensubtitles.org", IDI_OPENSUBTITLES, SPF_LOGIN | SPF_HASH | SPF_UPLOAD) -void Initialize() override; -bool NeedLogin() override; -SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; -SRESULT LogOut() override; -SRESULT Hash(SubtitlesInfo& pFileInfo) override; -SRESULT Upload(const SubtitlesInfo& pSubtitlesInfo) override; -std::unique_ptr xmlrpc; -XmlRpcValue token; -DEFINE_SUBTITLESPROVIDER_END -#endif - -DEFINE_SUBTITLESPROVIDER_BEGIN(OpenSubtitles2, "OpenSubtitles.com", "https://www.opensubtitles.com", IDI_OPENSUBTITLES, SPF_LOGIN | SPF_HASH) -void Initialize() override; -bool NeedLogin() override; -SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; -SRESULT LogOut() override; -SRESULT Hash(SubtitlesInfo& pFileInfo) override; - -struct Response { - DWORD code; - std::string text; -}; - -bool CallAPI(CHttpFile* httpFile, CString& headers, std::string& body, Response& response); -bool CallAPI(CHttpFile* httpFile, CString& headers, Response& response); -bool CallAPIResponse(CHttpFile* httpFile, Response& response); -bool GetOptionalValue(const rapidjson::Value& node, const char* path, std::string& result); -bool GetOptionalValue(const rapidjson::Value& node, const char* path, int& result); -bool GetOptionalValue(const rapidjson::Value& node, const char* path, double& result); - -CString token; -static constexpr TCHAR* APIKEY = _T("s2GJfwwPNA74kkeXudFAdiHIqTDjgrmq"); -DEFINE_SUBTITLESPROVIDER_END - -DEFINE_SUBTITLESPROVIDER_BEGIN(podnapisi, "Podnapisi", "https://www.podnapisi.net", IDI_PODNAPISI, SPF_SEARCH) -SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; -SRESULT Hash(SubtitlesInfo& pFileInfo) override; -DEFINE_SUBTITLESPROVIDER_END - -DEFINE_SUBTITLESPROVIDER_BEGIN(Napisy24, "Napisy24", "https://napisy24.pl/", IDI_N24, SPF_HASH | SPF_SEARCH) -SRESULT Hash(SubtitlesInfo& pFileInfo) override; -DEFINE_SUBTITLESPROVIDER_END - -static const struct { - const char* code; - const char* name; -} podnapisi_languages[] = { - { /* 0*/ "", "" }, { /* 1*/ "sl", "Slovenian" }, { /* 2*/ "en", "English" }, - { /* 3*/ "no", "Norwegian" }, { /* 4*/ "ko", "Korean" }, { /* 5*/ "de", "German" }, - { /* 6*/ "is", "Icelandic" }, { /* 7*/ "cs", "Czech" }, { /* 8*/ "fr", "French" }, - { /* 9*/ "it", "Italian" }, { /*10*/ "bs", "Bosnian" }, { /*11*/ "ja", "Japanese" }, - { /*12*/ "ar", "Arabic" }, { /*13*/ "ro", "Romanian" }, { /*14*/ "es", "Argentino" }, - { /*15*/ "hu", "Hungarian" }, { /*16*/ "el", "Greek" }, { /*17*/ "zh", "Chinese" }, - { /*18*/ "", "" }, { /*19*/ "lt", "Lithuanian" }, { /*20*/ "et", "Estonian" }, - { /*21*/ "lv", "Latvian" }, { /*22*/ "he", "Hebrew" }, { /*23*/ "nl", "Dutch" }, - { /*24*/ "da", "Danish" }, { /*25*/ "sv", "Swedish" }, { /*26*/ "pl", "Polish" }, - { /*27*/ "ru", "Russian" }, { /*28*/ "es", "Spanish" }, { /*29*/ "sq", "Albanian" }, - { /*30*/ "tr", "Turkish" }, { /*31*/ "fi", "Finnish" }, { /*32*/ "pt", "Portuguese" }, - { /*33*/ "bg", "Bulgarian" }, { /*34*/ "", "" }, { /*35*/ "mk", "Macedonian" }, - { /*36*/ "sr", "Serbian" }, { /*37*/ "sk", "Slovak" }, { /*38*/ "hr", "Croatian" }, - { /*39*/ "", "" }, { /*40*/ "zh", "Mandarin" }, { /*41*/ "", "" }, - { /*42*/ "hi", "Hindi" }, { /*43*/ "", "" }, { /*44*/ "th", "Thai" }, - { /*45*/ "", "" }, { /*46*/ "uk", "Ukrainian" }, { /*47*/ "sr", "Serbian (Cyrillic)" }, - { /*48*/ "pb", "Brazilian" }, { /*49*/ "ga", "Irish" }, { /*50*/ "be", "Belarus" }, - { /*51*/ "vi", "Vietnamese" }, { /*52*/ "fa", "Farsi" }, { /*53*/ "ca", "Catalan" }, - { /*54*/ "id", "Indonesian" }, { /*55*/ "ms", "Malay" }, { /*56*/ "si", "Sinhala" }, - { /*57*/ "kl", "Greenlandic" }, { /*58*/ "kk", "Kazakh" }, { /*59*/ "bn", "Bengali" }, -}; +/* + * (C) 2016-2017 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 . + * + */ + +#pragma once + +#include "SubtitlesProviders.h" +#include "VersionInfo.h" +#include "rapidjson/include/rapidjson/document.h" +#include "XmlRpc4Win/TimXmlRpc.h" + +#define DEFINE_SUBTITLESPROVIDER_BEGIN(P, N, U, I, F) \ +class P final : public SubtitlesProvider { \ +public: \ + P(SubtitlesProviders* pOwner) \ + : SubtitlesProvider(pOwner) { \ + Initialize(); \ + } \ + ~P() { Uninitialize(); } \ + P(P const&) = delete; \ + P& operator=(P const&) = delete; \ + static std::shared_ptr

Create(SubtitlesProviders* pOwner) { \ + return std::make_shared

(pOwner); \ + } \ +private: \ + virtual std::string Name() const override { return #P; } \ + virtual std::string DisplayName() const override { return N; } \ + virtual std::string Url() const override { return U; } \ + virtual const std::set& Languages() const override; \ + virtual bool Flags(DWORD dwFlags) const override { return (dwFlags & (F)) == dwFlags; } \ + virtual int Icon() const override { return I; } \ +private: \ + virtual SRESULT Search(const SubtitlesInfo& pFileInfo) override; \ + virtual SRESULT Download(SubtitlesInfo& pSubtitlesInfo) override; +#define DEFINE_SUBTITLESPROVIDER_END \ +}; + +#if 0 +DEFINE_SUBTITLESPROVIDER_BEGIN(OpenSubtitles, "OpenSubtitles.org", "https://api.opensubtitles.org", IDI_OPENSUBTITLES, SPF_LOGIN | SPF_HASH | SPF_UPLOAD) +void Initialize() override; +bool NeedLogin() override; +SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; +SRESULT LogOut() override; +SRESULT Hash(SubtitlesInfo& pFileInfo) override; +SRESULT Upload(const SubtitlesInfo& pSubtitlesInfo) override; +std::unique_ptr xmlrpc; +XmlRpcValue token; +DEFINE_SUBTITLESPROVIDER_END +#endif + +DEFINE_SUBTITLESPROVIDER_BEGIN(OpenSubtitles2, "OpenSubtitles.com", "https://www.opensubtitles.com", IDI_OPENSUBTITLES, SPF_LOGIN | SPF_HASH) +void Initialize() override; +bool NeedLogin() override; +SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; +SRESULT LogOut() override; +SRESULT Hash(SubtitlesInfo& pFileInfo) override; + +struct Response { + DWORD code; + std::string text; +}; + +bool CallAPI(CHttpFile* httpFile, CString& headers, std::string& body, Response& response); +bool CallAPI(CHttpFile* httpFile, CString& headers, Response& response); +bool CallAPIResponse(CHttpFile* httpFile, Response& response); +bool GetOptionalValue(const rapidjson::Value& node, const char* path, std::string& result); +bool GetOptionalValue(const rapidjson::Value& node, const char* path, int& result); +bool GetOptionalValue(const rapidjson::Value& node, const char* path, double& result); + +CString token; +static constexpr TCHAR* APIKEY = _T("s2GJfwwPNA74kkeXudFAdiHIqTDjgrmq"); +DEFINE_SUBTITLESPROVIDER_END + +DEFINE_SUBTITLESPROVIDER_BEGIN(podnapisi, "Podnapisi", "https://www.podnapisi.net", IDI_PODNAPISI, SPF_SEARCH) +SRESULT Login(const std::string& sUserName, const std::string& sPassword) override; +SRESULT Hash(SubtitlesInfo& pFileInfo) override; +DEFINE_SUBTITLESPROVIDER_END + +DEFINE_SUBTITLESPROVIDER_BEGIN(Napisy24, "Napisy24", "https://napisy24.pl/", IDI_N24, SPF_HASH | SPF_SEARCH) +SRESULT Hash(SubtitlesInfo& pFileInfo) override; +DEFINE_SUBTITLESPROVIDER_END + +static const struct { + const char* code; + const char* name; +} podnapisi_languages[] = { + { /* 0*/ "", "" }, { /* 1*/ "sl", "Slovenian" }, { /* 2*/ "en", "English" }, + { /* 3*/ "no", "Norwegian" }, { /* 4*/ "ko", "Korean" }, { /* 5*/ "de", "German" }, + { /* 6*/ "is", "Icelandic" }, { /* 7*/ "cs", "Czech" }, { /* 8*/ "fr", "French" }, + { /* 9*/ "it", "Italian" }, { /*10*/ "bs", "Bosnian" }, { /*11*/ "ja", "Japanese" }, + { /*12*/ "ar", "Arabic" }, { /*13*/ "ro", "Romanian" }, { /*14*/ "es", "Argentino" }, + { /*15*/ "hu", "Hungarian" }, { /*16*/ "el", "Greek" }, { /*17*/ "zh", "Chinese" }, + { /*18*/ "", "" }, { /*19*/ "lt", "Lithuanian" }, { /*20*/ "et", "Estonian" }, + { /*21*/ "lv", "Latvian" }, { /*22*/ "he", "Hebrew" }, { /*23*/ "nl", "Dutch" }, + { /*24*/ "da", "Danish" }, { /*25*/ "sv", "Swedish" }, { /*26*/ "pl", "Polish" }, + { /*27*/ "ru", "Russian" }, { /*28*/ "es", "Spanish" }, { /*29*/ "sq", "Albanian" }, + { /*30*/ "tr", "Turkish" }, { /*31*/ "fi", "Finnish" }, { /*32*/ "pt", "Portuguese" }, + { /*33*/ "bg", "Bulgarian" }, { /*34*/ "", "" }, { /*35*/ "mk", "Macedonian" }, + { /*36*/ "sr", "Serbian" }, { /*37*/ "sk", "Slovak" }, { /*38*/ "hr", "Croatian" }, + { /*39*/ "", "" }, { /*40*/ "zh", "Mandarin" }, { /*41*/ "", "" }, + { /*42*/ "hi", "Hindi" }, { /*43*/ "", "" }, { /*44*/ "th", "Thai" }, + { /*45*/ "", "" }, { /*46*/ "uk", "Ukrainian" }, { /*47*/ "sr", "Serbian (Cyrillic)" }, + { /*48*/ "pb", "Brazilian" }, { /*49*/ "ga", "Irish" }, { /*50*/ "be", "Belarus" }, + { /*51*/ "vi", "Vietnamese" }, { /*52*/ "fa", "Farsi" }, { /*53*/ "ca", "Catalan" }, + { /*54*/ "id", "Indonesian" }, { /*55*/ "ms", "Malay" }, { /*56*/ "si", "Sinhala" }, + { /*57*/ "kl", "Greenlandic" }, { /*58*/ "kk", "Kazakh" }, { /*59*/ "bn", "Bengali" }, +}; diff --git a/src/mpc-hc/SubtitlesProviders.h b/src/mpc-hc/SubtitlesProviders.h index 4d20b19ad1b..872902768ae 100644 --- a/src/mpc-hc/SubtitlesProviders.h +++ b/src/mpc-hc/SubtitlesProviders.h @@ -1,443 +1,443 @@ -/* - * (C) 2016-2017 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 . - * - */ - -#pragma once - -#include "SubtitlesProvidersUtils.h" -#include "../Subtitles/SubtitleHelpers.h" -#include "base64/base64.h" -#include "VersionInfo.h" - -class CMainFrame; -struct SubtitlesInfo; -class SubtitlesThread; -class SubtitlesTask; -class SubtitlesProvider; -class SubtitlesProviders; - -using SubtitlesList = std::list; - -enum SubtitlesProviderFlags { - SPF_SEARCH = 0x00000000, - SPF_LOGIN = 0x00000001, - SPF_HASH = 0x00000002, -}; - -enum SubtitlesProviderLogin { - SPL_UNDEFINED = 0x00000000, - SPL_FAILED = 0x00000001, - SPL_ANONYMOUS = 0x00000002, - SPL_REGISTERED = 0x00000004, -}; - -enum SRESULT { - SR_UNDEFINED, - SR_SUCCEEDED, - SR_FAILED, - SR_ABORTED, - // Specific to search only - SR_TOOMANY, -}; - -enum SubtitlesThreadType { - STT_UNDEFINED = 0x00000000, - STT_SEARCH = 0x00000001, - STT_DOWNLOAD = 0x00000002, - STT_MANUALSEARCH = 0x00000008 -}; - - -struct SubtitlesInfo { - SubtitlesInfo() - : fileProvider(nullptr) - , uid(UINT_ERROR) - , score(0ul) - , fileSize(ULONGLONG_ERROR) - , year(INT_ERROR) - , seasonNumber(INT_ERROR) - , episodeNumber(INT_ERROR) - , discNumber(INT_ERROR) - , hearingImpaired(Subtitle::HI_UNKNOWN) - , discCount(INT_ERROR) - , downloadCount(INT_ERROR) - , corrected(0) - , frameRate(-1.0) - , framesNumber(INT_ERROR) - , lengthMs(ULONGLONG_ERROR) {} - bool operator<(const SubtitlesInfo& rhs) const { return score > rhs.score; } - HRESULT GetFileInfo(const std::string& sFileName = std::string()); - void Download(bool bActivate); - void OpenUrl() const; - std::shared_ptr Provider() const { return fileProvider; } - void Provider(std::shared_ptr pProvider) { fileProvider = pProvider; } - DWORD Score() const { return score; } - void Set(std::shared_ptr pProvider, BYTE nLanguage, BYTE nHearingImpaired, SHORT nScore) { - static UINT i(0); - // run twice to check whether i has reached MAXUINT32 which is invalid - if (uid == UINT_ERROR) { - uid = ++i; - if (uid == UINT_ERROR) { - uid = ++i; - } - } - fileProvider = pProvider; - score = MAKELONG(nScore + 0x10, MAKEWORD(nHearingImpaired, nLanguage)); - } - - std::string DisplayTitle() const { - std::string _title(title); - if (!title2.empty()) { - _title.append(": " + title2); - } - if (year != -1) { - _title.append(" (" + std::to_string(year) + ")"); - } - return _title; - } - - std::string NormalizeString(std::string sTitle) const { - // remove ' and ' from string and replace '!?&:\' with ' ' to get more accurate results - sTitle = std::regex_replace(sTitle, std::regex(" and ", SubtitlesProvidersUtils::RegexFlags), " "); - sTitle = std::regex_replace(sTitle, std::regex(" *[!?&:] *", SubtitlesProvidersUtils::RegexFlags), " "); - sTitle = std::regex_replace(sTitle, std::regex("'", SubtitlesProvidersUtils::RegexFlags), ""); - - return sTitle; - } - - std::string NormalizeTitle() const { return NormalizeString(title); } - UINT UID() const { return uid; } - -private: - std::shared_ptr fileProvider; - UINT uid; - DWORD score; -public: - // file properties - std::wstring filePathW; - std::string filePath; - std::string fileName; - std::string fileExtension; - ULONGLONG fileSize; - std::string fileContents; - std::string fileHash; - CComQIPtr pAsyncReader; - - // file name properties - std::string title; - std::string country; - int year; - std::string episode; - int seasonNumber; - int episodeNumber; - std::string title2; - std::string resolution; - std::string format; - std::string audioCodec; - std::string videoCodec; - std::string releaseGroup; - int discNumber; - - // subtitles properties - std::string id; - std::string imdbid; - std::string languageCode; - std::string languageName; - std::string url; - std::list releaseNames; - int hearingImpaired; - int discCount; - int downloadCount; - int corrected; - - // video properties - double frameRate; - int framesNumber; - ULONGLONG lengthMs; - - CString manualSearchString; -}; - - -class CWinThreadProc -{ -public: - CWinThreadProc() : m_pThread(nullptr), m_bAbort(false) {} - virtual ~CWinThreadProc() = default; - - operator CWinThread* () const { return m_pThread; } - - bool IsThreadRunning() const { return m_pThread != nullptr; } - volatile bool& IsThreadAborting() { return m_bAbort; } - - CWinThread* CreateThread() { - if (!IsThreadRunning()) { - m_pThread = AfxBeginThread(_ThreadProc, this); - } - return m_pThread; - } - void AbortThread() { - if (IsThreadRunning()) { - m_bAbort = true; - } - } - void WaitThread() const { - if (IsThreadRunning()) { - ::WaitForSingleObjectEx(*m_pThread, INFINITE, TRUE); - } - } - -private: - static UINT _ThreadProc(LPVOID pThreadParams) { - CWinThreadProc* pThread = static_cast(pThreadParams); - pThread->ThreadProc(); - return 0; - } - virtual void ThreadProc() PURE; - - CWinThread* m_pThread; - volatile bool m_bAbort; -}; - - -class SubtitlesThread final : public CWinThreadProc -{ - friend class SubtitlesProvider; - friend class SubtitlesTask; -public: - SubtitlesThread(SubtitlesTask* pTask, const SubtitlesInfo& pFileInfo, std::shared_ptr pProvider) - : m_pTask(pTask) - , m_pFileInfo(pFileInfo) - { m_pFileInfo.Provider(pProvider); } - -private: - void Set(SubtitlesInfo& pSubtitlesInfo); - - void ThreadProc() override; - void Search(); - void Download(SubtitlesInfo& pFileInfo, BOOL bActivate); - void Download(); - - void CheckAbortAndThrow() { - if (IsThreadAborting()) { - throw E_ABORT; - } - } - - SubtitlesTask* m_pTask; - SubtitlesInfo m_pFileInfo; - SubtitlesList m_pSubtitlesList; -}; - - -class SubtitlesTask final : public CWinThreadProc -{ - friend class SubtitlesThread; -public: - // Search - SubtitlesTask(CMainFrame* pMainFrame, bool bAutoDownload, const std::list& sLanguages); - SubtitlesTask(CMainFrame* pMainFrame, bool bAutoDownload, const std::list& sLanguages, CString manualSearch); - // Download - SubtitlesTask(CMainFrame* pMainFrame, SubtitlesInfo& pSubtitlesInfo, bool bActivate); - - SubtitlesThreadType Type() const { return m_nType; }; - BYTE GetLangPriority(const std::string& sLanguage) { - return m_LangPriority.count(sLanguage) ? m_LangPriority[sLanguage] : 0; - } - - void InsertThread(SubtitlesThread* pThread) { - CAutoLock cAutoLock(&m_csThreads); - m_pThreads.push_back(pThread); - } - - void RemoveThread(SubtitlesThread* pThread) { - { - CAutoLock cAutoLock(&m_csThreads); - m_pThreads.remove(pThread); - } - delete pThread; - } - - void Abort() { - if(!this) return; - CAutoLock cAutoLock(&m_csThreads); - for (auto& iter : m_pThreads) { - iter->AbortThread(); - } - AbortThread(); - } - -private: - void ThreadProc() override; - - CMainFrame* m_pMainFrame; - std::list m_pThreads; - CCritSec m_csThreads; - CCritSec m_csDownload; - - SubtitlesInfo m_pFileInfo; - bool m_bActivate; - SubtitlesThreadType m_nType; - bool m_bAutoDownload; - std::unordered_map m_AutoDownload; - std::unordered_map m_LangPriority; - - CString manualSearch; -}; - -class SubtitlesProvider -{ -public: - SubtitlesProvider(SubtitlesProviders* pOwner); - virtual ~SubtitlesProvider() = default; - -public: // implemented - virtual std::string Name() const PURE; - virtual std::string DisplayName() const PURE; - virtual std::string Url() const PURE; - virtual const std::set& Languages() const PURE; - virtual bool Flags(DWORD dwFlags) const PURE; - virtual int Icon() const PURE; - virtual SRESULT Search(const SubtitlesInfo& pFileInfo) PURE; - virtual SRESULT Download(SubtitlesInfo& pSubtitlesInfo) PURE; - -protected: // overridden - virtual void Initialize() {} - virtual void Uninitialize() { LogOut(); } -public: // overridden - virtual bool NeedLogin() { return !(m_nLoggedIn & (SPL_REGISTERED | SPL_ANONYMOUS)); } - virtual SRESULT Login(const std::string&, const std::string&) { return SR_UNDEFINED; } - virtual SRESULT LogOut() { - m_nLoggedIn = SPL_UNDEFINED; - return SR_SUCCEEDED; - } - virtual SRESULT Hash(SubtitlesInfo&) { return SR_UNDEFINED; } - virtual std::string UserAgent() const { - return SubtitlesProvidersUtils::StringFormat("MPC-HC v%u.%u.%u", - VersionInfo::GetMajorNumber(), - VersionInfo::GetMinorNumber(), - VersionInfo::GetPatchNumber()); - } - - bool LoginInternal(); - void OpenUrl() const; - size_t Index() const; - static bool CheckInternetConnection(); - static bool CheckLanguage(const std::string& sLanguageCode); - std::list GetLanguagesIntersection() const; - std::list GetLanguagesIntersection(std::list&& userSelectedLangauges) const; - bool SupportsUserSelectedLanguages() const; - SRESULT DownloadInternal(std::string url, std::string referer, std::string& data) const; - static void Set(SubtitlesInfo& pSubtitlesInfo); - static bool IsAborting(); - - BOOL Enabled(SubtitlesProviderFlags nFlag) { return m_bSearch; } - void Enabled(SubtitlesProviderFlags nFlag, BOOL bEnabled) { - m_bSearch = bEnabled; - } - std::string UserName() const { return m_sUserName; }; - void UserName(std::string sUserName) { m_sUserName = sUserName; }; - std::string Password(bool bDecrypt = true) { - return bDecrypt - ? SubtitlesProvidersUtils::StringDecrypt(Base64::decode(m_sPassword), SubtitlesProvidersUtils::StringGenerateUniqueKey()) - : m_sPassword; - }; - void Password(LPCSTR sPassword, bool bEncrypt = true) { - m_sPassword = bEncrypt - ? Base64::encode(SubtitlesProvidersUtils::StringEncrypt(sPassword, SubtitlesProvidersUtils::StringGenerateUniqueKey())) - : sPassword; - }; - SubtitlesProviders& Providers() const { return *m_pOwner; } - int GetIconIndex() const { return m_nIconIndex; } - void SetIconIndex(int nIconIndex) { m_nIconIndex = nIconIndex; } - -private: - BOOL m_bSearch; - std::string m_sUserName; - std::string m_sPassword; - SubtitlesProviders* m_pOwner; - int m_nIconIndex; -protected: - SubtitlesProviderLogin m_nLoggedIn; -}; - -class SubtitlesProviders final -{ -public: - explicit SubtitlesProviders(CMainFrame* pMainFrame); - ~SubtitlesProviders(); - SubtitlesProviders(SubtitlesProviders const&) = delete; - SubtitlesProviders& operator=(SubtitlesProviders const&) = delete; - -private: - void RegisterProviders(); - template - void Register(SubtitlesProviders* pOwner) { - m_pProviders.push_back(T::Create(pOwner)); - auto& provider = m_pProviders.back(); - HICON hIcon = ::LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(provider->Icon())); - provider->SetIconIndex(m_himl.Add(hIcon)); - DestroyIcon(hIcon); - } - -public: - const std::vector>& Providers() const { - return m_pProviders; - }; - static BOOL SubtitlesProviders::CheckInternetConnection(); - - void ReadSettings(); - std::string WriteSettings(); - - void Search(bool bAutoDownload); - void ManualSearch(bool bAutoDownload, CString manualSearch); - void Download(SubtitlesInfo& pSubtitlesInfo, bool bActivate); - void Abort(SubtitlesThreadType nType); - - void InsertTask(SubtitlesTask* pTask) { - CAutoLock cAutoLock(&m_csTasks); - m_pTasks.push_back(pTask); - } - - void RemoveTask(SubtitlesTask* pTask) { - CAutoLock cAutoLock(&m_csTasks); - if(!m_pTasks.empty()) { - m_pTasks.remove(pTask); - } - } - - void MoveUp(size_t nIndex) { - std::iter_swap(m_pProviders.begin() + nIndex, m_pProviders.begin() + nIndex - 1); - } - - void MoveDown(size_t nIndex) { - std::iter_swap(m_pProviders.begin() + nIndex, m_pProviders.begin() + nIndex + 1); - } - - CImageList& GetImageList() { return m_himl; } - -private: - CMainFrame* m_pMainFrame; - - std::vector> m_pProviders; - - CCritSec m_csTasks; - std::list m_pTasks; - CImageList m_himl; -}; +/* + * (C) 2016-2017 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 . + * + */ + +#pragma once + +#include "SubtitlesProvidersUtils.h" +#include "../Subtitles/SubtitleHelpers.h" +#include "base64/base64.h" +#include "VersionInfo.h" + +class CMainFrame; +struct SubtitlesInfo; +class SubtitlesThread; +class SubtitlesTask; +class SubtitlesProvider; +class SubtitlesProviders; + +using SubtitlesList = std::list; + +enum SubtitlesProviderFlags { + SPF_SEARCH = 0x00000000, + SPF_LOGIN = 0x00000001, + SPF_HASH = 0x00000002, +}; + +enum SubtitlesProviderLogin { + SPL_UNDEFINED = 0x00000000, + SPL_FAILED = 0x00000001, + SPL_ANONYMOUS = 0x00000002, + SPL_REGISTERED = 0x00000004, +}; + +enum SRESULT { + SR_UNDEFINED, + SR_SUCCEEDED, + SR_FAILED, + SR_ABORTED, + // Specific to search only + SR_TOOMANY, +}; + +enum SubtitlesThreadType { + STT_UNDEFINED = 0x00000000, + STT_SEARCH = 0x00000001, + STT_DOWNLOAD = 0x00000002, + STT_MANUALSEARCH = 0x00000008 +}; + + +struct SubtitlesInfo { + SubtitlesInfo() + : fileProvider(nullptr) + , uid(UINT_ERROR) + , score(0ul) + , fileSize(ULONGLONG_ERROR) + , year(INT_ERROR) + , seasonNumber(INT_ERROR) + , episodeNumber(INT_ERROR) + , discNumber(INT_ERROR) + , hearingImpaired(Subtitle::HI_UNKNOWN) + , discCount(INT_ERROR) + , downloadCount(INT_ERROR) + , corrected(0) + , frameRate(-1.0) + , framesNumber(INT_ERROR) + , lengthMs(ULONGLONG_ERROR) {} + bool operator<(const SubtitlesInfo& rhs) const { return score > rhs.score; } + HRESULT GetFileInfo(const std::string& sFileName = std::string()); + void Download(bool bActivate); + void OpenUrl() const; + std::shared_ptr Provider() const { return fileProvider; } + void Provider(std::shared_ptr pProvider) { fileProvider = pProvider; } + DWORD Score() const { return score; } + void Set(std::shared_ptr pProvider, BYTE nLanguage, BYTE nHearingImpaired, SHORT nScore) { + static UINT i(0); + // run twice to check whether i has reached MAXUINT32 which is invalid + if (uid == UINT_ERROR) { + uid = ++i; + if (uid == UINT_ERROR) { + uid = ++i; + } + } + fileProvider = pProvider; + score = MAKELONG(nScore + 0x10, MAKEWORD(nHearingImpaired, nLanguage)); + } + + std::string DisplayTitle() const { + std::string _title(title); + if (!title2.empty()) { + _title.append(": " + title2); + } + if (year != -1) { + _title.append(" (" + std::to_string(year) + ")"); + } + return _title; + } + + std::string NormalizeString(std::string sTitle) const { + // remove ' and ' from string and replace '!?&:\' with ' ' to get more accurate results + sTitle = std::regex_replace(sTitle, std::regex(" and ", SubtitlesProvidersUtils::RegexFlags), " "); + sTitle = std::regex_replace(sTitle, std::regex(" *[!?&:] *", SubtitlesProvidersUtils::RegexFlags), " "); + sTitle = std::regex_replace(sTitle, std::regex("'", SubtitlesProvidersUtils::RegexFlags), ""); + + return sTitle; + } + + std::string NormalizeTitle() const { return NormalizeString(title); } + UINT UID() const { return uid; } + +private: + std::shared_ptr fileProvider; + UINT uid; + DWORD score; +public: + // file properties + std::wstring filePathW; + std::string filePath; + std::string fileName; + std::string fileExtension; + ULONGLONG fileSize; + std::string fileContents; + std::string fileHash; + CComQIPtr pAsyncReader; + + // file name properties + std::string title; + std::string country; + int year; + std::string episode; + int seasonNumber; + int episodeNumber; + std::string title2; + std::string resolution; + std::string format; + std::string audioCodec; + std::string videoCodec; + std::string releaseGroup; + int discNumber; + + // subtitles properties + std::string id; + std::string imdbid; + std::string languageCode; + std::string languageName; + std::string url; + std::list releaseNames; + int hearingImpaired; + int discCount; + int downloadCount; + int corrected; + + // video properties + double frameRate; + int framesNumber; + ULONGLONG lengthMs; + + CString manualSearchString; +}; + + +class CWinThreadProc +{ +public: + CWinThreadProc() : m_pThread(nullptr), m_bAbort(false) {} + virtual ~CWinThreadProc() = default; + + operator CWinThread* () const { return m_pThread; } + + bool IsThreadRunning() const { return m_pThread != nullptr; } + volatile bool& IsThreadAborting() { return m_bAbort; } + + CWinThread* CreateThread() { + if (!IsThreadRunning()) { + m_pThread = AfxBeginThread(_ThreadProc, this); + } + return m_pThread; + } + void AbortThread() { + if (IsThreadRunning()) { + m_bAbort = true; + } + } + void WaitThread() const { + if (IsThreadRunning()) { + ::WaitForSingleObjectEx(*m_pThread, INFINITE, TRUE); + } + } + +private: + static UINT _ThreadProc(LPVOID pThreadParams) { + CWinThreadProc* pThread = static_cast(pThreadParams); + pThread->ThreadProc(); + return 0; + } + virtual void ThreadProc() PURE; + + CWinThread* m_pThread; + volatile bool m_bAbort; +}; + + +class SubtitlesThread final : public CWinThreadProc +{ + friend class SubtitlesProvider; + friend class SubtitlesTask; +public: + SubtitlesThread(SubtitlesTask* pTask, const SubtitlesInfo& pFileInfo, std::shared_ptr pProvider) + : m_pTask(pTask) + , m_pFileInfo(pFileInfo) + { m_pFileInfo.Provider(pProvider); } + +private: + void Set(SubtitlesInfo& pSubtitlesInfo); + + void ThreadProc() override; + void Search(); + void Download(SubtitlesInfo& pFileInfo, BOOL bActivate); + void Download(); + + void CheckAbortAndThrow() { + if (IsThreadAborting()) { + throw E_ABORT; + } + } + + SubtitlesTask* m_pTask; + SubtitlesInfo m_pFileInfo; + SubtitlesList m_pSubtitlesList; +}; + + +class SubtitlesTask final : public CWinThreadProc +{ + friend class SubtitlesThread; +public: + // Search + SubtitlesTask(CMainFrame* pMainFrame, bool bAutoDownload, const std::list& sLanguages); + SubtitlesTask(CMainFrame* pMainFrame, bool bAutoDownload, const std::list& sLanguages, CString manualSearch); + // Download + SubtitlesTask(CMainFrame* pMainFrame, SubtitlesInfo& pSubtitlesInfo, bool bActivate); + + SubtitlesThreadType Type() const { return m_nType; }; + BYTE GetLangPriority(const std::string& sLanguage) { + return m_LangPriority.count(sLanguage) ? m_LangPriority[sLanguage] : 0; + } + + void InsertThread(SubtitlesThread* pThread) { + CAutoLock cAutoLock(&m_csThreads); + m_pThreads.push_back(pThread); + } + + void RemoveThread(SubtitlesThread* pThread) { + { + CAutoLock cAutoLock(&m_csThreads); + m_pThreads.remove(pThread); + } + delete pThread; + } + + void Abort() { + if(!this) return; + CAutoLock cAutoLock(&m_csThreads); + for (auto& iter : m_pThreads) { + iter->AbortThread(); + } + AbortThread(); + } + +private: + void ThreadProc() override; + + CMainFrame* m_pMainFrame; + std::list m_pThreads; + CCritSec m_csThreads; + CCritSec m_csDownload; + + SubtitlesInfo m_pFileInfo; + bool m_bActivate; + SubtitlesThreadType m_nType; + bool m_bAutoDownload; + std::unordered_map m_AutoDownload; + std::unordered_map m_LangPriority; + + CString manualSearch; +}; + +class SubtitlesProvider +{ +public: + SubtitlesProvider(SubtitlesProviders* pOwner); + virtual ~SubtitlesProvider() = default; + +public: // implemented + virtual std::string Name() const PURE; + virtual std::string DisplayName() const PURE; + virtual std::string Url() const PURE; + virtual const std::set& Languages() const PURE; + virtual bool Flags(DWORD dwFlags) const PURE; + virtual int Icon() const PURE; + virtual SRESULT Search(const SubtitlesInfo& pFileInfo) PURE; + virtual SRESULT Download(SubtitlesInfo& pSubtitlesInfo) PURE; + +protected: // overridden + virtual void Initialize() {} + virtual void Uninitialize() { LogOut(); } +public: // overridden + virtual bool NeedLogin() { return !(m_nLoggedIn & (SPL_REGISTERED | SPL_ANONYMOUS)); } + virtual SRESULT Login(const std::string&, const std::string&) { return SR_UNDEFINED; } + virtual SRESULT LogOut() { + m_nLoggedIn = SPL_UNDEFINED; + return SR_SUCCEEDED; + } + virtual SRESULT Hash(SubtitlesInfo&) { return SR_UNDEFINED; } + virtual std::string UserAgent() const { + return SubtitlesProvidersUtils::StringFormat("MPC-HC v%u.%u.%u", + VersionInfo::GetMajorNumber(), + VersionInfo::GetMinorNumber(), + VersionInfo::GetPatchNumber()); + } + + bool LoginInternal(); + void OpenUrl() const; + size_t Index() const; + static bool CheckInternetConnection(); + static bool CheckLanguage(const std::string& sLanguageCode); + std::list GetLanguagesIntersection() const; + std::list GetLanguagesIntersection(std::list&& userSelectedLangauges) const; + bool SupportsUserSelectedLanguages() const; + SRESULT DownloadInternal(std::string url, std::string referer, std::string& data) const; + static void Set(SubtitlesInfo& pSubtitlesInfo); + static bool IsAborting(); + + BOOL Enabled(SubtitlesProviderFlags nFlag) { return m_bSearch; } + void Enabled(SubtitlesProviderFlags nFlag, BOOL bEnabled) { + m_bSearch = bEnabled; + } + std::string UserName() const { return m_sUserName; }; + void UserName(std::string sUserName) { m_sUserName = sUserName; }; + std::string Password(bool bDecrypt = true) { + return bDecrypt + ? SubtitlesProvidersUtils::StringDecrypt(Base64::decode(m_sPassword), SubtitlesProvidersUtils::StringGenerateUniqueKey()) + : m_sPassword; + }; + void Password(LPCSTR sPassword, bool bEncrypt = true) { + m_sPassword = bEncrypt + ? Base64::encode(SubtitlesProvidersUtils::StringEncrypt(sPassword, SubtitlesProvidersUtils::StringGenerateUniqueKey())) + : sPassword; + }; + SubtitlesProviders& Providers() const { return *m_pOwner; } + int GetIconIndex() const { return m_nIconIndex; } + void SetIconIndex(int nIconIndex) { m_nIconIndex = nIconIndex; } + +private: + BOOL m_bSearch; + std::string m_sUserName; + std::string m_sPassword; + SubtitlesProviders* m_pOwner; + int m_nIconIndex; +protected: + SubtitlesProviderLogin m_nLoggedIn; +}; + +class SubtitlesProviders final +{ +public: + explicit SubtitlesProviders(CMainFrame* pMainFrame); + ~SubtitlesProviders(); + SubtitlesProviders(SubtitlesProviders const&) = delete; + SubtitlesProviders& operator=(SubtitlesProviders const&) = delete; + +private: + void RegisterProviders(); + template + void Register(SubtitlesProviders* pOwner) { + m_pProviders.push_back(T::Create(pOwner)); + auto& provider = m_pProviders.back(); + HICON hIcon = ::LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(provider->Icon())); + provider->SetIconIndex(m_himl.Add(hIcon)); + DestroyIcon(hIcon); + } + +public: + const std::vector>& Providers() const { + return m_pProviders; + }; + static BOOL SubtitlesProviders::CheckInternetConnection(); + + void ReadSettings(); + std::string WriteSettings(); + + void Search(bool bAutoDownload); + void ManualSearch(bool bAutoDownload, CString manualSearch); + void Download(SubtitlesInfo& pSubtitlesInfo, bool bActivate); + void Abort(SubtitlesThreadType nType); + + void InsertTask(SubtitlesTask* pTask) { + CAutoLock cAutoLock(&m_csTasks); + m_pTasks.push_back(pTask); + } + + void RemoveTask(SubtitlesTask* pTask) { + CAutoLock cAutoLock(&m_csTasks); + if(!m_pTasks.empty()) { + m_pTasks.remove(pTask); + } + } + + void MoveUp(size_t nIndex) { + std::iter_swap(m_pProviders.begin() + nIndex, m_pProviders.begin() + nIndex - 1); + } + + void MoveDown(size_t nIndex) { + std::iter_swap(m_pProviders.begin() + nIndex, m_pProviders.begin() + nIndex + 1); + } + + CImageList& GetImageList() { return m_himl; } + +private: + CMainFrame* m_pMainFrame; + + std::vector> m_pProviders; + + CCritSec m_csTasks; + std::list m_pTasks; + CImageList m_himl; +}; diff --git a/src/mpc-hc/TextPassThruFilter.cpp b/src/mpc-hc/TextPassThruFilter.cpp index 16361a29367..184f6c45eca 100644 --- a/src/mpc-hc/TextPassThruFilter.cpp +++ b/src/mpc-hc/TextPassThruFilter.cpp @@ -1,255 +1,255 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2013, 2016 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 . - * - */ - -#include "stdafx.h" -#include -#include "mplayerc.h" -#include "MainFrm.h" -#include "TextPassThruFilter.h" -#include "moreuuids.h" -#include "DSUtil.h" -#include "../Subtitles/SubtitleInputPin.h" - -// -// CTextPassThruInputPin -// - -class CTextPassThruInputPin : public CSubtitleInputPin -{ - CTextPassThruFilter* m_pTPTFilter; - CComPtr m_pSubStreamOld; - -protected: - void AddSubStream(ISubStream* pSubStream) { - if (m_pSubStreamOld) { - if (pSubStream) { - m_pTPTFilter->m_pMainFrame->ReplaceSubtitle(m_pSubStreamOld, pSubStream); - } - m_pSubStreamOld = nullptr; - } - } - - void RemoveSubStream(ISubStream* pSubStream) { - m_pSubStreamOld = pSubStream; - } - - void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) { - m_pTPTFilter->m_pMainFrame->InvalidateSubtitle((DWORD_PTR)pSubStream, rtStart); - } - -public: - CTextPassThruInputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); - STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - STDMETHODIMP Receive(IMediaSample* pSample); - STDMETHODIMP EndOfStream(); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - - HRESULT CompleteConnect(IPin* pReceivePin); -}; - -// -// CTextPassThruOutputPin -// - -class CTextPassThruOutputPin : public CBaseOutputPin -{ - CTextPassThruFilter* m_pTPTFilter; - -public: - CTextPassThruOutputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, HRESULT* phr); - - HRESULT CheckMediaType(const CMediaType* mtOut); - HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); - HRESULT GetMediaType(int iPosition, CMediaType* pmt); - STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) { - return S_OK; - } -}; - -/////////// - -CTextPassThruInputPin::CTextPassThruInputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr) - : CSubtitleInputPin(pTPTFilter, pLock, pSubLock, phr) - , m_pTPTFilter(pTPTFilter) -{ -} - -STDMETHODIMP CTextPassThruInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - HRESULT hr = __super::NewSegment(tStart, tStop, dRate); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->DeliverNewSegment(tStart, tStop, dRate); -} - -STDMETHODIMP CTextPassThruInputPin::Receive(IMediaSample* pSample) -{ - HRESULT hr = __super::Receive(pSample); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->Deliver(pSample); -} - -STDMETHODIMP CTextPassThruInputPin::EndOfStream() -{ - HRESULT hr = __super::EndOfStream(); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->DeliverEndOfStream(); -} - -STDMETHODIMP CTextPassThruInputPin::BeginFlush() -{ - HRESULT hr = __super::BeginFlush(); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->DeliverBeginFlush(); -} - -STDMETHODIMP CTextPassThruInputPin::EndFlush() -{ - HRESULT hr = __super::EndFlush(); - if (FAILED(hr)) { - return hr; - } - return m_pTPTFilter->m_pOutput->DeliverEndFlush(); -} - -HRESULT CTextPassThruInputPin::CompleteConnect(IPin* pReceivePin) -{ - HRESULT hr = __super::CompleteConnect(pReceivePin); - if (FAILED(hr) || !m_pTPTFilter->m_pOutput->IsConnected()) { - return hr; - } - return m_pTPTFilter->ReconnectPin(m_pTPTFilter->m_pOutput, &m_mt); -} - -// - -CTextPassThruOutputPin::CTextPassThruOutputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, HRESULT* phr) - : CBaseOutputPin(NAME(""), pTPTFilter, pLock, phr, L"Out") - , m_pTPTFilter(pTPTFilter) -{ -} - -HRESULT CTextPassThruOutputPin::CheckMediaType(const CMediaType* mtOut) -{ - CMediaType mt; - return S_OK == m_pTPTFilter->m_pInput->ConnectionMediaType(&mt) && mt == *mtOut - ? S_OK - : E_FAIL; -} - -HRESULT CTextPassThruOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) -{ - if (m_pTPTFilter->m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - CComPtr pAllocatorIn; - m_pTPTFilter->m_pInput->GetAllocator(&pAllocatorIn); - if (!pAllocatorIn) { - return E_UNEXPECTED; - } - - pAllocatorIn->GetProperties(pProperties); - - HRESULT hr; - ALLOCATOR_PROPERTIES Actual; - if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { - return hr; - } - - return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer - ? E_FAIL - : NOERROR); -} - -HRESULT CTextPassThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt) -{ - if (m_pTPTFilter->m_pInput->IsConnected() == FALSE) { - return E_UNEXPECTED; - } - - if (iPosition < 0) { - return E_INVALIDARG; - } - if (iPosition > 0) { - return VFW_S_NO_MORE_ITEMS; - } - - m_pTPTFilter->m_pInput->ConnectionMediaType(pmt); - - return S_OK; -} - -// -// CTextPassThruFilter -// - -CTextPassThruFilter::CTextPassThruFilter(CMainFrame* pMainFrame) - : CBaseFilter(NAME("CTextPassThruFilter"), nullptr, this, __uuidof(this)) - , m_pMainFrame(pMainFrame) -{ - HRESULT hr; - m_pInput = DEBUG_NEW CTextPassThruInputPin(this, this, &m_pMainFrame->m_csSubLock, &hr); - m_pOutput = DEBUG_NEW CTextPassThruOutputPin(this, this, &hr); -} - -CTextPassThruFilter::~CTextPassThruFilter() -{ - delete m_pInput; - m_pInput = nullptr; - delete m_pOutput; - m_pOutput = nullptr; -} - -STDMETHODIMP CTextPassThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - if (m_pInput && riid == __uuidof(ISubStream)) { - if (CComPtr pSubStream = m_pInput->GetSubStream()) { - *ppv = pSubStream.Detach(); - return S_OK; - } - } - - return __super::NonDelegatingQueryInterface(riid, ppv); -} - -int CTextPassThruFilter::GetPinCount() -{ - return 2; -} - -CBasePin* CTextPassThruFilter::GetPin(int n) -{ - if (n == 0) { - return m_pInput; - } else if (n == 1) { - return m_pOutput; - } - return nullptr; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2013, 2016 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 . + * + */ + +#include "stdafx.h" +#include +#include "mplayerc.h" +#include "MainFrm.h" +#include "TextPassThruFilter.h" +#include "moreuuids.h" +#include "DSUtil.h" +#include "../Subtitles/SubtitleInputPin.h" + +// +// CTextPassThruInputPin +// + +class CTextPassThruInputPin : public CSubtitleInputPin +{ + CTextPassThruFilter* m_pTPTFilter; + CComPtr m_pSubStreamOld; + +protected: + void AddSubStream(ISubStream* pSubStream) { + if (m_pSubStreamOld) { + if (pSubStream) { + m_pTPTFilter->m_pMainFrame->ReplaceSubtitle(m_pSubStreamOld, pSubStream); + } + m_pSubStreamOld = nullptr; + } + } + + void RemoveSubStream(ISubStream* pSubStream) { + m_pSubStreamOld = pSubStream; + } + + void InvalidateSubtitle(REFERENCE_TIME rtStart, ISubStream* pSubStream) { + m_pTPTFilter->m_pMainFrame->InvalidateSubtitle((DWORD_PTR)pSubStream, rtStart); + } + +public: + CTextPassThruInputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr); + STDMETHODIMP NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + STDMETHODIMP Receive(IMediaSample* pSample); + STDMETHODIMP EndOfStream(); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + + HRESULT CompleteConnect(IPin* pReceivePin); +}; + +// +// CTextPassThruOutputPin +// + +class CTextPassThruOutputPin : public CBaseOutputPin +{ + CTextPassThruFilter* m_pTPTFilter; + +public: + CTextPassThruOutputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, HRESULT* phr); + + HRESULT CheckMediaType(const CMediaType* mtOut); + HRESULT DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties); + HRESULT GetMediaType(int iPosition, CMediaType* pmt); + STDMETHODIMP Notify(IBaseFilter* pSender, Quality q) { + return S_OK; + } +}; + +/////////// + +CTextPassThruInputPin::CTextPassThruInputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr) + : CSubtitleInputPin(pTPTFilter, pLock, pSubLock, phr) + , m_pTPTFilter(pTPTFilter) +{ +} + +STDMETHODIMP CTextPassThruInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + HRESULT hr = __super::NewSegment(tStart, tStop, dRate); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->DeliverNewSegment(tStart, tStop, dRate); +} + +STDMETHODIMP CTextPassThruInputPin::Receive(IMediaSample* pSample) +{ + HRESULT hr = __super::Receive(pSample); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->Deliver(pSample); +} + +STDMETHODIMP CTextPassThruInputPin::EndOfStream() +{ + HRESULT hr = __super::EndOfStream(); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->DeliverEndOfStream(); +} + +STDMETHODIMP CTextPassThruInputPin::BeginFlush() +{ + HRESULT hr = __super::BeginFlush(); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->DeliverBeginFlush(); +} + +STDMETHODIMP CTextPassThruInputPin::EndFlush() +{ + HRESULT hr = __super::EndFlush(); + if (FAILED(hr)) { + return hr; + } + return m_pTPTFilter->m_pOutput->DeliverEndFlush(); +} + +HRESULT CTextPassThruInputPin::CompleteConnect(IPin* pReceivePin) +{ + HRESULT hr = __super::CompleteConnect(pReceivePin); + if (FAILED(hr) || !m_pTPTFilter->m_pOutput->IsConnected()) { + return hr; + } + return m_pTPTFilter->ReconnectPin(m_pTPTFilter->m_pOutput, &m_mt); +} + +// + +CTextPassThruOutputPin::CTextPassThruOutputPin(CTextPassThruFilter* pTPTFilter, CCritSec* pLock, HRESULT* phr) + : CBaseOutputPin(NAME(""), pTPTFilter, pLock, phr, L"Out") + , m_pTPTFilter(pTPTFilter) +{ +} + +HRESULT CTextPassThruOutputPin::CheckMediaType(const CMediaType* mtOut) +{ + CMediaType mt; + return S_OK == m_pTPTFilter->m_pInput->ConnectionMediaType(&mt) && mt == *mtOut + ? S_OK + : E_FAIL; +} + +HRESULT CTextPassThruOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties) +{ + if (m_pTPTFilter->m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + CComPtr pAllocatorIn; + m_pTPTFilter->m_pInput->GetAllocator(&pAllocatorIn); + if (!pAllocatorIn) { + return E_UNEXPECTED; + } + + pAllocatorIn->GetProperties(pProperties); + + HRESULT hr; + ALLOCATOR_PROPERTIES Actual; + if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) { + return hr; + } + + return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer + ? E_FAIL + : NOERROR); +} + +HRESULT CTextPassThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt) +{ + if (m_pTPTFilter->m_pInput->IsConnected() == FALSE) { + return E_UNEXPECTED; + } + + if (iPosition < 0) { + return E_INVALIDARG; + } + if (iPosition > 0) { + return VFW_S_NO_MORE_ITEMS; + } + + m_pTPTFilter->m_pInput->ConnectionMediaType(pmt); + + return S_OK; +} + +// +// CTextPassThruFilter +// + +CTextPassThruFilter::CTextPassThruFilter(CMainFrame* pMainFrame) + : CBaseFilter(NAME("CTextPassThruFilter"), nullptr, this, __uuidof(this)) + , m_pMainFrame(pMainFrame) +{ + HRESULT hr; + m_pInput = DEBUG_NEW CTextPassThruInputPin(this, this, &m_pMainFrame->m_csSubLock, &hr); + m_pOutput = DEBUG_NEW CTextPassThruOutputPin(this, this, &hr); +} + +CTextPassThruFilter::~CTextPassThruFilter() +{ + delete m_pInput; + m_pInput = nullptr; + delete m_pOutput; + m_pOutput = nullptr; +} + +STDMETHODIMP CTextPassThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + if (m_pInput && riid == __uuidof(ISubStream)) { + if (CComPtr pSubStream = m_pInput->GetSubStream()) { + *ppv = pSubStream.Detach(); + return S_OK; + } + } + + return __super::NonDelegatingQueryInterface(riid, ppv); +} + +int CTextPassThruFilter::GetPinCount() +{ + return 2; +} + +CBasePin* CTextPassThruFilter::GetPin(int n) +{ + if (n == 0) { + return m_pInput; + } else if (n == 1) { + return m_pOutput; + } + return nullptr; +} diff --git a/src/mpc-hc/TextPassThruFilter.h b/src/mpc-hc/TextPassThruFilter.h index 7304989c2a2..78758659b82 100644 --- a/src/mpc-hc/TextPassThruFilter.h +++ b/src/mpc-hc/TextPassThruFilter.h @@ -1,46 +1,46 @@ -/* - * (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 . - * - */ - -#pragma once - -class CTextPassThruInputPin; - -class __declspec(uuid("E2BA9B7B-B65D-4804-ACB2-89C3E55511DB")) - CTextPassThruFilter : public CBaseFilter, public CCritSec -{ - friend class CTextPassThruInputPin; - friend class CTextPassThruOutputPin; - - CTextPassThruInputPin* m_pInput; - CTextPassThruOutputPin* m_pOutput; - - CMainFrame* m_pMainFrame; - -public: - CTextPassThruFilter(CMainFrame* pMainFrame); - virtual ~CTextPassThruFilter(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - int GetPinCount(); - CBasePin* GetPin(int n); -}; +/* + * (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 . + * + */ + +#pragma once + +class CTextPassThruInputPin; + +class __declspec(uuid("E2BA9B7B-B65D-4804-ACB2-89C3E55511DB")) + CTextPassThruFilter : public CBaseFilter, public CCritSec +{ + friend class CTextPassThruInputPin; + friend class CTextPassThruOutputPin; + + CTextPassThruInputPin* m_pInput; + CTextPassThruOutputPin* m_pOutput; + + CMainFrame* m_pMainFrame; + +public: + CTextPassThruFilter(CMainFrame* pMainFrame); + virtual ~CTextPassThruFilter(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + int GetPinCount(); + CBasePin* GetPin(int n); +}; diff --git a/src/mpc-hc/TunerScanDlg.cpp b/src/mpc-hc/TunerScanDlg.cpp index dd915300f32..da7360c5957 100644 --- a/src/mpc-hc/TunerScanDlg.cpp +++ b/src/mpc-hc/TunerScanDlg.cpp @@ -1,317 +1,317 @@ -/* - * (C) 2009-2017 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 . - * - */ - -// TunerScanDlg.cpp : implementation file -// - -#include "stdafx.h" -#include "mplayerc.h" -#include "MainFrm.h" -#include "TunerScanDlg.h" -#include "DVBChannel.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" - - -enum TSC_COLUMN { - TSCC_NUMBER, - TSCC_NAME, - TSCC_FREQUENCY, - TSCC_ENCRYPTED, - TSCC_VIDEO_FORMAT, - TSCC_VIDEO_FPS, - TSCC_VIDEO_RES, - TSCC_VIDEO_AR, - TSCC_CHANNEL -}; - -// CTunerScanDlg dialog - -IMPLEMENT_DYNAMIC(CTunerScanDlg, CMPCThemeDialog) - -CTunerScanDlg::CTunerScanDlg(CMainFrame* pMainFrame) - : CMPCThemeDialog(CTunerScanDlg::IDD, pMainFrame) - , m_pMainFrame(pMainFrame) - , m_bInProgress(false) -{ - const CAppSettings& s = AfxGetAppSettings(); - - m_ulFrequencyStart = s.iBDAScanFreqStart; - m_ulFrequencyEnd = s.iBDAScanFreqEnd; - m_ulBandwidth = s.iBDABandwidth * 1000; - m_ulSymbolRate = s.iBDASymbolRate; - m_bUseOffset = s.fBDAUseOffset; - m_lOffset = s.iBDAOffset; - m_bIgnoreEncryptedChannels = s.fBDAIgnoreEncryptedChannels; -} - -CTunerScanDlg::~CTunerScanDlg() -{ -} - -BOOL CTunerScanDlg::OnInitDialog() -{ - CMPCThemeDialog::OnInitDialog(); - - m_OffsetEditBox.EnableWindow(m_bUseOffset); - - m_ChannelList.InsertColumn(TSCC_NUMBER, ResStr(IDS_DVB_CHANNEL_NUMBER), LVCFMT_LEFT, 35); - m_ChannelList.InsertColumn(TSCC_NAME, ResStr(IDS_DVB_CHANNEL_NAME), LVCFMT_LEFT, 190); - m_ChannelList.InsertColumn(TSCC_FREQUENCY, ResStr(IDS_DVB_CHANNEL_FREQUENCY), LVCFMT_LEFT, 65); - m_ChannelList.InsertColumn(TSCC_ENCRYPTED, ResStr(IDS_DVB_CHANNEL_ENCRYPTION), LVCFMT_CENTER, 55); - m_ChannelList.InsertColumn(TSCC_VIDEO_FORMAT, ResStr(IDS_DVB_CHANNEL_FORMAT), LVCFMT_CENTER, 55); - m_ChannelList.InsertColumn(TSCC_VIDEO_FPS, ResStr(IDS_DVB_CHANNEL_FPS), LVCFMT_CENTER, 50); - m_ChannelList.InsertColumn(TSCC_VIDEO_RES, ResStr(IDS_DVB_CHANNEL_RESOLUTION), LVCFMT_CENTER, 70); - m_ChannelList.InsertColumn(TSCC_VIDEO_AR, ResStr(IDS_DVB_CHANNEL_ASPECT_RATIO), LVCFMT_CENTER, 50); - m_ChannelList.InsertColumn(TSCC_CHANNEL, _T("Channel"), LVCFMT_LEFT, 0); - - m_Progress.SetRange(0, 100); - CMPCThemeUtil::fulfillThemeReqs(&m_Progress); - m_Strength.SetRange(0, 100); - CMPCThemeUtil::fulfillThemeReqs(&m_Strength); - m_Quality.SetRange(0, 100); - CMPCThemeUtil::fulfillThemeReqs(&m_Quality); - - m_btnSave.EnableWindow(FALSE); - - return TRUE; -} - -void CTunerScanDlg::DoDataExchange(CDataExchange* pDX) -{ - CMPCThemeDialog::DoDataExchange(pDX); - DDX_Text(pDX, IDC_FREQ_START, m_ulFrequencyStart); - DDX_Text(pDX, IDC_FREQ_END, m_ulFrequencyEnd); - DDX_Text(pDX, IDC_BANDWIDTH, m_ulBandwidth); - DDX_Text(pDX, IDC_SYMBOLRATE, m_ulSymbolRate); - DDX_Text(pDX, IDC_OFFSET, m_lOffset); - DDX_Check(pDX, IDC_CHECK_OFFSET, m_bUseOffset); - DDX_Check(pDX, IDC_CHECK_IGNORE_ENCRYPTED, m_bIgnoreEncryptedChannels); - DDX_Control(pDX, IDC_PROGRESS, m_Progress); - DDX_Control(pDX, IDC_STRENGTH, m_Strength); - DDX_Control(pDX, IDC_QUALITY, m_Quality); - DDX_Control(pDX, IDC_CHANNEL_LIST, m_ChannelList); - DDX_Control(pDX, ID_START, m_btnStart); - DDX_Control(pDX, ID_SAVE, m_btnSave); - DDX_Control(pDX, IDCANCEL, m_btnCancel); - DDX_Control(pDX, IDC_OFFSET, m_OffsetEditBox); - fulfillThemeReqs(); -} - -BEGIN_MESSAGE_MAP(CTunerScanDlg, CMPCThemeDialog) - ON_MESSAGE(WM_TUNER_SCAN_PROGRESS, OnScanProgress) - ON_MESSAGE(WM_TUNER_SCAN_END, OnScanEnd) - ON_MESSAGE(WM_TUNER_STATS, OnStats) - ON_MESSAGE(WM_TUNER_NEW_CHANNEL, OnNewChannel) - ON_BN_CLICKED(ID_SAVE, &CTunerScanDlg::OnBnClickedSave) - ON_BN_CLICKED(ID_START, &CTunerScanDlg::OnBnClickedStart) - ON_BN_CLICKED(IDCANCEL, &CTunerScanDlg::OnBnClickedCancel) - ON_BN_CLICKED(IDC_CHECK_OFFSET, &CTunerScanDlg::OnBnClickedCheckOffset) -END_MESSAGE_MAP() - -// CTunerScanDlg message handlers - -void CTunerScanDlg::OnBnClickedSave() -{ - auto& DVBChannels = AfxGetAppSettings().m_DVBChannels; - const size_t maxChannelsNum = ID_NAVIGATE_JUMPTO_SUBITEM_END - ID_NAVIGATE_JUMPTO_SUBITEM_START + 1; - - for (int i = 0; i < m_ChannelList.GetItemCount(); i++) { - try { - CBDAChannel channel(m_ChannelList.GetItemText(i, TSCC_CHANNEL)); - auto it = std::find(std::begin(DVBChannels), std::end(DVBChannels), channel); - if (it != DVBChannels.end()) { - // replace existing channel - channel.SetPrefNumber(it->GetPrefNumber()); - *it = channel; - } else { - // add new channel to the end - const size_t size = DVBChannels.size(); - if (size < maxChannelsNum) { - channel.SetPrefNumber((int)size); - DVBChannels.push_back(channel); - } else { - // Just to be safe. We have 600 channels limit, but we never know what user might load there. - CString msg; - msg.Format(_T("Unable to add new channel \"%s\" to the list. Channels list is full. Please notify developers about the problem."), channel.GetName()); - AfxMessageBox(msg, MB_OK | MB_ICONERROR); - } - } - } catch (CException* e) { - // The tokenisation can fail if the input string was invalid - TRACE(_T("Failed to parse a DVB channel from string \"%s\""), m_ChannelList.GetItemText(i, TSCC_CHANNEL).GetString()); - ASSERT(FALSE); - e->Delete(); - } - } - m_pMainFrame->SetChannel(0); - - OnOK(); -} - -void CTunerScanDlg::OnBnClickedStart() -{ - if (!m_bInProgress) { - UpdateData(true); - CAutoPtr pTSD(DEBUG_NEW TunerScanData); - pTSD->Hwnd = m_hWnd; - pTSD->FrequencyStart = m_ulFrequencyStart; - pTSD->FrequencyStop = m_ulFrequencyEnd; - pTSD->Bandwidth = m_ulBandwidth; - pTSD->SymbolRate = m_ulSymbolRate; - pTSD->Offset = m_bUseOffset ? m_lOffset : 0; - SaveScanSettings(); - - m_ChannelList.DeleteAllItems(); - m_pMainFrame->StartTunerScan(pTSD); - - SetProgress(true); - } else { - m_pMainFrame->StopTunerScan(); - } -} - -void CTunerScanDlg::OnBnClickedCancel() -{ - if (m_bInProgress) { - m_pMainFrame->StopTunerScan(); - } - m_pMainFrame->SetChannel(AfxGetAppSettings().nDVBLastChannel); - - OnCancel(); -} - -void CTunerScanDlg::OnBnClickedCheckOffset() -{ - UpdateData(true); - m_OffsetEditBox.EnableWindow(m_bUseOffset); -} - -LRESULT CTunerScanDlg::OnScanProgress(WPARAM wParam, LPARAM lParam) -{ - m_Progress.SetPos(static_cast(wParam)); - return TRUE; -} - -LRESULT CTunerScanDlg::OnScanEnd(WPARAM wParam, LPARAM lParam) -{ - SetProgress(false); - return TRUE; -} - -LRESULT CTunerScanDlg::OnStats(WPARAM wParam, LPARAM lParam) -{ - m_Strength.SetPos((int)wParam); - m_Quality.SetPos((int)lParam); - return TRUE; -} - -LRESULT CTunerScanDlg::OnNewChannel(WPARAM wParam, LPARAM lParam) -{ - try { - CBDAChannel channel((LPCTSTR)lParam); - if (!m_bIgnoreEncryptedChannels || !channel.IsEncrypted()) { - CString strTemp; - int nItem, nChannelNumber; - - if (channel.GetOriginNumber() != 0) { // LCN is available - nChannelNumber = channel.GetOriginNumber(); - // Insert new channel so that channels are sorted by their logical number - for (nItem = 0; nItem < m_ChannelList.GetItemCount(); nItem++) { - if ((int)m_ChannelList.GetItemData(nItem) > nChannelNumber || (int)m_ChannelList.GetItemData(nItem) == 0) { - break; - } - } - } else { - nChannelNumber = 0; - nItem = m_ChannelList.GetItemCount(); - } - - strTemp.Format(_T("%d"), nChannelNumber); - nItem = m_ChannelList.InsertItem(nItem, strTemp); - - m_ChannelList.SetItemData(nItem, channel.GetOriginNumber()); - - m_ChannelList.SetItemText(nItem, TSCC_NAME, channel.GetName()); - - strTemp.Format(_T("%lu"), channel.GetFrequency()); - m_ChannelList.SetItemText(nItem, TSCC_FREQUENCY, strTemp); - - m_ChannelList.SetItemText(nItem, TSCC_ENCRYPTED, ResStr(channel.IsEncrypted() ? IDS_YES : IDS_NO)); - if (channel.GetVideoType() == BDA_H264) { - strTemp = _T("H.264"); - } else if (channel.GetVideoType() == BDA_HEVC) { - strTemp = _T("HEVC"); - } else if (channel.GetVideoPID()) { - strTemp = _T("MPEG-2"); - } else { - strTemp = _T("-"); - } - m_ChannelList.SetItemText(nItem, TSCC_VIDEO_FORMAT, strTemp); - strTemp = channel.GetVideoFpsDesc(); - m_ChannelList.SetItemText(nItem, TSCC_VIDEO_FPS, strTemp); - if (channel.GetVideoWidth() || channel.GetVideoHeight()) { - strTemp.Format(_T("%lux%lu"), channel.GetVideoWidth(), channel.GetVideoHeight()); - } else { - strTemp = _T("-"); - } - m_ChannelList.SetItemText(nItem, TSCC_VIDEO_RES, strTemp); - strTemp.Format(_T("%lu/%lu"), channel.GetVideoARy(), channel.GetVideoARx()); - m_ChannelList.SetItemText(nItem, TSCC_VIDEO_AR, strTemp); - m_ChannelList.SetItemText(nItem, TSCC_CHANNEL, (LPCTSTR) lParam); - } - } catch (CException* e) { - // The tokenisation can fail if the input string was invalid - TRACE(_T("Failed to parse a DVB channel from string \"%s\""), (LPCTSTR)lParam); - ASSERT(FALSE); - e->Delete(); - return FALSE; - } - - return TRUE; -} - -void CTunerScanDlg::SetProgress(bool bState) -{ - if (bState) { - m_btnStart.SetWindowTextW(ResStr(IDS_DVB_CHANNEL_STOP_SCAN)); - m_btnSave.EnableWindow(FALSE); - } else { - m_btnStart.SetWindowTextW(ResStr(IDS_DVB_CHANNEL_START_SCAN)); - m_Progress.SetPos(0); - m_btnSave.EnableWindow(TRUE); - } - - m_bInProgress = bState; -} - -void CTunerScanDlg::SaveScanSettings() -{ - CAppSettings& s = AfxGetAppSettings(); - - s.iBDAScanFreqStart = m_ulFrequencyStart; - s.iBDAScanFreqEnd = m_ulFrequencyEnd; - div_t bdw = div(m_ulBandwidth, 1000); - s.iBDABandwidth = bdw.quot; - s.iBDASymbolRate = m_ulSymbolRate; - s.fBDAUseOffset = !!m_bUseOffset; - s.iBDAOffset = m_lOffset; - s.fBDAIgnoreEncryptedChannels = !!m_bIgnoreEncryptedChannels; -} +/* + * (C) 2009-2017 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 . + * + */ + +// TunerScanDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "mplayerc.h" +#include "MainFrm.h" +#include "TunerScanDlg.h" +#include "DVBChannel.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" + + +enum TSC_COLUMN { + TSCC_NUMBER, + TSCC_NAME, + TSCC_FREQUENCY, + TSCC_ENCRYPTED, + TSCC_VIDEO_FORMAT, + TSCC_VIDEO_FPS, + TSCC_VIDEO_RES, + TSCC_VIDEO_AR, + TSCC_CHANNEL +}; + +// CTunerScanDlg dialog + +IMPLEMENT_DYNAMIC(CTunerScanDlg, CMPCThemeDialog) + +CTunerScanDlg::CTunerScanDlg(CMainFrame* pMainFrame) + : CMPCThemeDialog(CTunerScanDlg::IDD, pMainFrame) + , m_pMainFrame(pMainFrame) + , m_bInProgress(false) +{ + const CAppSettings& s = AfxGetAppSettings(); + + m_ulFrequencyStart = s.iBDAScanFreqStart; + m_ulFrequencyEnd = s.iBDAScanFreqEnd; + m_ulBandwidth = s.iBDABandwidth * 1000; + m_ulSymbolRate = s.iBDASymbolRate; + m_bUseOffset = s.fBDAUseOffset; + m_lOffset = s.iBDAOffset; + m_bIgnoreEncryptedChannels = s.fBDAIgnoreEncryptedChannels; +} + +CTunerScanDlg::~CTunerScanDlg() +{ +} + +BOOL CTunerScanDlg::OnInitDialog() +{ + CMPCThemeDialog::OnInitDialog(); + + m_OffsetEditBox.EnableWindow(m_bUseOffset); + + m_ChannelList.InsertColumn(TSCC_NUMBER, ResStr(IDS_DVB_CHANNEL_NUMBER), LVCFMT_LEFT, 35); + m_ChannelList.InsertColumn(TSCC_NAME, ResStr(IDS_DVB_CHANNEL_NAME), LVCFMT_LEFT, 190); + m_ChannelList.InsertColumn(TSCC_FREQUENCY, ResStr(IDS_DVB_CHANNEL_FREQUENCY), LVCFMT_LEFT, 65); + m_ChannelList.InsertColumn(TSCC_ENCRYPTED, ResStr(IDS_DVB_CHANNEL_ENCRYPTION), LVCFMT_CENTER, 55); + m_ChannelList.InsertColumn(TSCC_VIDEO_FORMAT, ResStr(IDS_DVB_CHANNEL_FORMAT), LVCFMT_CENTER, 55); + m_ChannelList.InsertColumn(TSCC_VIDEO_FPS, ResStr(IDS_DVB_CHANNEL_FPS), LVCFMT_CENTER, 50); + m_ChannelList.InsertColumn(TSCC_VIDEO_RES, ResStr(IDS_DVB_CHANNEL_RESOLUTION), LVCFMT_CENTER, 70); + m_ChannelList.InsertColumn(TSCC_VIDEO_AR, ResStr(IDS_DVB_CHANNEL_ASPECT_RATIO), LVCFMT_CENTER, 50); + m_ChannelList.InsertColumn(TSCC_CHANNEL, _T("Channel"), LVCFMT_LEFT, 0); + + m_Progress.SetRange(0, 100); + CMPCThemeUtil::fulfillThemeReqs(&m_Progress); + m_Strength.SetRange(0, 100); + CMPCThemeUtil::fulfillThemeReqs(&m_Strength); + m_Quality.SetRange(0, 100); + CMPCThemeUtil::fulfillThemeReqs(&m_Quality); + + m_btnSave.EnableWindow(FALSE); + + return TRUE; +} + +void CTunerScanDlg::DoDataExchange(CDataExchange* pDX) +{ + CMPCThemeDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_FREQ_START, m_ulFrequencyStart); + DDX_Text(pDX, IDC_FREQ_END, m_ulFrequencyEnd); + DDX_Text(pDX, IDC_BANDWIDTH, m_ulBandwidth); + DDX_Text(pDX, IDC_SYMBOLRATE, m_ulSymbolRate); + DDX_Text(pDX, IDC_OFFSET, m_lOffset); + DDX_Check(pDX, IDC_CHECK_OFFSET, m_bUseOffset); + DDX_Check(pDX, IDC_CHECK_IGNORE_ENCRYPTED, m_bIgnoreEncryptedChannels); + DDX_Control(pDX, IDC_PROGRESS, m_Progress); + DDX_Control(pDX, IDC_STRENGTH, m_Strength); + DDX_Control(pDX, IDC_QUALITY, m_Quality); + DDX_Control(pDX, IDC_CHANNEL_LIST, m_ChannelList); + DDX_Control(pDX, ID_START, m_btnStart); + DDX_Control(pDX, ID_SAVE, m_btnSave); + DDX_Control(pDX, IDCANCEL, m_btnCancel); + DDX_Control(pDX, IDC_OFFSET, m_OffsetEditBox); + fulfillThemeReqs(); +} + +BEGIN_MESSAGE_MAP(CTunerScanDlg, CMPCThemeDialog) + ON_MESSAGE(WM_TUNER_SCAN_PROGRESS, OnScanProgress) + ON_MESSAGE(WM_TUNER_SCAN_END, OnScanEnd) + ON_MESSAGE(WM_TUNER_STATS, OnStats) + ON_MESSAGE(WM_TUNER_NEW_CHANNEL, OnNewChannel) + ON_BN_CLICKED(ID_SAVE, &CTunerScanDlg::OnBnClickedSave) + ON_BN_CLICKED(ID_START, &CTunerScanDlg::OnBnClickedStart) + ON_BN_CLICKED(IDCANCEL, &CTunerScanDlg::OnBnClickedCancel) + ON_BN_CLICKED(IDC_CHECK_OFFSET, &CTunerScanDlg::OnBnClickedCheckOffset) +END_MESSAGE_MAP() + +// CTunerScanDlg message handlers + +void CTunerScanDlg::OnBnClickedSave() +{ + auto& DVBChannels = AfxGetAppSettings().m_DVBChannels; + const size_t maxChannelsNum = ID_NAVIGATE_JUMPTO_SUBITEM_END - ID_NAVIGATE_JUMPTO_SUBITEM_START + 1; + + for (int i = 0; i < m_ChannelList.GetItemCount(); i++) { + try { + CBDAChannel channel(m_ChannelList.GetItemText(i, TSCC_CHANNEL)); + auto it = std::find(std::begin(DVBChannels), std::end(DVBChannels), channel); + if (it != DVBChannels.end()) { + // replace existing channel + channel.SetPrefNumber(it->GetPrefNumber()); + *it = channel; + } else { + // add new channel to the end + const size_t size = DVBChannels.size(); + if (size < maxChannelsNum) { + channel.SetPrefNumber((int)size); + DVBChannels.push_back(channel); + } else { + // Just to be safe. We have 600 channels limit, but we never know what user might load there. + CString msg; + msg.Format(_T("Unable to add new channel \"%s\" to the list. Channels list is full. Please notify developers about the problem."), channel.GetName()); + AfxMessageBox(msg, MB_OK | MB_ICONERROR); + } + } + } catch (CException* e) { + // The tokenisation can fail if the input string was invalid + TRACE(_T("Failed to parse a DVB channel from string \"%s\""), m_ChannelList.GetItemText(i, TSCC_CHANNEL).GetString()); + ASSERT(FALSE); + e->Delete(); + } + } + m_pMainFrame->SetChannel(0); + + OnOK(); +} + +void CTunerScanDlg::OnBnClickedStart() +{ + if (!m_bInProgress) { + UpdateData(true); + CAutoPtr pTSD(DEBUG_NEW TunerScanData); + pTSD->Hwnd = m_hWnd; + pTSD->FrequencyStart = m_ulFrequencyStart; + pTSD->FrequencyStop = m_ulFrequencyEnd; + pTSD->Bandwidth = m_ulBandwidth; + pTSD->SymbolRate = m_ulSymbolRate; + pTSD->Offset = m_bUseOffset ? m_lOffset : 0; + SaveScanSettings(); + + m_ChannelList.DeleteAllItems(); + m_pMainFrame->StartTunerScan(pTSD); + + SetProgress(true); + } else { + m_pMainFrame->StopTunerScan(); + } +} + +void CTunerScanDlg::OnBnClickedCancel() +{ + if (m_bInProgress) { + m_pMainFrame->StopTunerScan(); + } + m_pMainFrame->SetChannel(AfxGetAppSettings().nDVBLastChannel); + + OnCancel(); +} + +void CTunerScanDlg::OnBnClickedCheckOffset() +{ + UpdateData(true); + m_OffsetEditBox.EnableWindow(m_bUseOffset); +} + +LRESULT CTunerScanDlg::OnScanProgress(WPARAM wParam, LPARAM lParam) +{ + m_Progress.SetPos(static_cast(wParam)); + return TRUE; +} + +LRESULT CTunerScanDlg::OnScanEnd(WPARAM wParam, LPARAM lParam) +{ + SetProgress(false); + return TRUE; +} + +LRESULT CTunerScanDlg::OnStats(WPARAM wParam, LPARAM lParam) +{ + m_Strength.SetPos((int)wParam); + m_Quality.SetPos((int)lParam); + return TRUE; +} + +LRESULT CTunerScanDlg::OnNewChannel(WPARAM wParam, LPARAM lParam) +{ + try { + CBDAChannel channel((LPCTSTR)lParam); + if (!m_bIgnoreEncryptedChannels || !channel.IsEncrypted()) { + CString strTemp; + int nItem, nChannelNumber; + + if (channel.GetOriginNumber() != 0) { // LCN is available + nChannelNumber = channel.GetOriginNumber(); + // Insert new channel so that channels are sorted by their logical number + for (nItem = 0; nItem < m_ChannelList.GetItemCount(); nItem++) { + if ((int)m_ChannelList.GetItemData(nItem) > nChannelNumber || (int)m_ChannelList.GetItemData(nItem) == 0) { + break; + } + } + } else { + nChannelNumber = 0; + nItem = m_ChannelList.GetItemCount(); + } + + strTemp.Format(_T("%d"), nChannelNumber); + nItem = m_ChannelList.InsertItem(nItem, strTemp); + + m_ChannelList.SetItemData(nItem, channel.GetOriginNumber()); + + m_ChannelList.SetItemText(nItem, TSCC_NAME, channel.GetName()); + + strTemp.Format(_T("%lu"), channel.GetFrequency()); + m_ChannelList.SetItemText(nItem, TSCC_FREQUENCY, strTemp); + + m_ChannelList.SetItemText(nItem, TSCC_ENCRYPTED, ResStr(channel.IsEncrypted() ? IDS_YES : IDS_NO)); + if (channel.GetVideoType() == BDA_H264) { + strTemp = _T("H.264"); + } else if (channel.GetVideoType() == BDA_HEVC) { + strTemp = _T("HEVC"); + } else if (channel.GetVideoPID()) { + strTemp = _T("MPEG-2"); + } else { + strTemp = _T("-"); + } + m_ChannelList.SetItemText(nItem, TSCC_VIDEO_FORMAT, strTemp); + strTemp = channel.GetVideoFpsDesc(); + m_ChannelList.SetItemText(nItem, TSCC_VIDEO_FPS, strTemp); + if (channel.GetVideoWidth() || channel.GetVideoHeight()) { + strTemp.Format(_T("%lux%lu"), channel.GetVideoWidth(), channel.GetVideoHeight()); + } else { + strTemp = _T("-"); + } + m_ChannelList.SetItemText(nItem, TSCC_VIDEO_RES, strTemp); + strTemp.Format(_T("%lu/%lu"), channel.GetVideoARy(), channel.GetVideoARx()); + m_ChannelList.SetItemText(nItem, TSCC_VIDEO_AR, strTemp); + m_ChannelList.SetItemText(nItem, TSCC_CHANNEL, (LPCTSTR) lParam); + } + } catch (CException* e) { + // The tokenisation can fail if the input string was invalid + TRACE(_T("Failed to parse a DVB channel from string \"%s\""), (LPCTSTR)lParam); + ASSERT(FALSE); + e->Delete(); + return FALSE; + } + + return TRUE; +} + +void CTunerScanDlg::SetProgress(bool bState) +{ + if (bState) { + m_btnStart.SetWindowTextW(ResStr(IDS_DVB_CHANNEL_STOP_SCAN)); + m_btnSave.EnableWindow(FALSE); + } else { + m_btnStart.SetWindowTextW(ResStr(IDS_DVB_CHANNEL_START_SCAN)); + m_Progress.SetPos(0); + m_btnSave.EnableWindow(TRUE); + } + + m_bInProgress = bState; +} + +void CTunerScanDlg::SaveScanSettings() +{ + CAppSettings& s = AfxGetAppSettings(); + + s.iBDAScanFreqStart = m_ulFrequencyStart; + s.iBDAScanFreqEnd = m_ulFrequencyEnd; + div_t bdw = div(m_ulBandwidth, 1000); + s.iBDABandwidth = bdw.quot; + s.iBDASymbolRate = m_ulSymbolRate; + s.fBDAUseOffset = !!m_bUseOffset; + s.iBDAOffset = m_lOffset; + s.fBDAIgnoreEncryptedChannels = !!m_bIgnoreEncryptedChannels; +} diff --git a/src/mpc-hc/TunerScanDlg.h b/src/mpc-hc/TunerScanDlg.h index 08a649b5d45..8363f8bfb6e 100644 --- a/src/mpc-hc/TunerScanDlg.h +++ b/src/mpc-hc/TunerScanDlg.h @@ -1,80 +1,80 @@ -/* - * (C) 2009-2014 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 . - * - */ - -#pragma once - -#include -#include -#include "CMPCThemeDialog.h" -#include "CMPCThemeEdit.h" -#include "CMPCThemePlayerListCtrl.h" -#include "CMPCThemeButton.h" - - -// CTunerScanDlg dialog - -class CTunerScanDlg : public CMPCThemeDialog -{ - CMainFrame* m_pMainFrame; - - DECLARE_DYNAMIC(CTunerScanDlg) - -public: - CTunerScanDlg(CMainFrame* pMainFrame); // standard constructor - virtual ~CTunerScanDlg(); - - // Dialog Data - enum { IDD = IDD_TUNER_SCAN }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - void SetProgress(bool bState); - void SaveScanSettings(); - - DECLARE_MESSAGE_MAP() -public: - ULONG m_ulFrequencyStart; - ULONG m_ulFrequencyEnd; - ULONG m_ulBandwidth; - ULONG m_ulSymbolRate; - LONG m_lOffset; - CMPCThemeEdit m_OffsetEditBox; - BOOL m_bUseOffset; - BOOL m_bIgnoreEncryptedChannels; - CProgressCtrl m_Progress; - CProgressCtrl m_Strength; - CProgressCtrl m_Quality; - CMPCThemePlayerListCtrl m_ChannelList; - bool m_bInProgress; - - afx_msg LRESULT OnScanProgress(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnScanEnd(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnStats(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnNewChannel(WPARAM wParam, LPARAM lParam); - - afx_msg void OnBnClickedCheckOffset(); - afx_msg void OnBnClickedSave(); - afx_msg void OnBnClickedStart(); - afx_msg void OnBnClickedCancel(); - virtual BOOL OnInitDialog(); - CMPCThemeButton m_btnStart; - CMPCThemeButton m_btnSave; - CMPCThemeButton m_btnCancel; -}; +/* + * (C) 2009-2014 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 . + * + */ + +#pragma once + +#include +#include +#include "CMPCThemeDialog.h" +#include "CMPCThemeEdit.h" +#include "CMPCThemePlayerListCtrl.h" +#include "CMPCThemeButton.h" + + +// CTunerScanDlg dialog + +class CTunerScanDlg : public CMPCThemeDialog +{ + CMainFrame* m_pMainFrame; + + DECLARE_DYNAMIC(CTunerScanDlg) + +public: + CTunerScanDlg(CMainFrame* pMainFrame); // standard constructor + virtual ~CTunerScanDlg(); + + // Dialog Data + enum { IDD = IDD_TUNER_SCAN }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + void SetProgress(bool bState); + void SaveScanSettings(); + + DECLARE_MESSAGE_MAP() +public: + ULONG m_ulFrequencyStart; + ULONG m_ulFrequencyEnd; + ULONG m_ulBandwidth; + ULONG m_ulSymbolRate; + LONG m_lOffset; + CMPCThemeEdit m_OffsetEditBox; + BOOL m_bUseOffset; + BOOL m_bIgnoreEncryptedChannels; + CProgressCtrl m_Progress; + CProgressCtrl m_Strength; + CProgressCtrl m_Quality; + CMPCThemePlayerListCtrl m_ChannelList; + bool m_bInProgress; + + afx_msg LRESULT OnScanProgress(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnScanEnd(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnStats(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnNewChannel(WPARAM wParam, LPARAM lParam); + + afx_msg void OnBnClickedCheckOffset(); + afx_msg void OnBnClickedSave(); + afx_msg void OnBnClickedStart(); + afx_msg void OnBnClickedCancel(); + virtual BOOL OnInitDialog(); + CMPCThemeButton m_btnStart; + CMPCThemeButton m_btnSave; + CMPCThemeButton m_btnCancel; +}; diff --git a/src/mpc-hc/UpdateChecker.cpp b/src/mpc-hc/UpdateChecker.cpp index 7d963fbc0f8..1ce0e123928 100644 --- a/src/mpc-hc/UpdateChecker.cpp +++ b/src/mpc-hc/UpdateChecker.cpp @@ -1,288 +1,288 @@ -/* - * (C) 2012-2014, 2017 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 . - * - */ - - -#include "stdafx.h" -#include "mpc-hc_config.h" -#include "VersionInfo.h" -#include "UpdateChecker.h" -#include "UpdateCheckerDlg.h" -#include "SettingsDefines.h" -#include "mplayerc.h" -#include "AppSettings.h" - -#include - -const Version UpdateChecker::MPC_HC_VERSION = { - VersionInfo::GetMajorNumber(), - VersionInfo::GetMinorNumber(), - VersionInfo::GetPatchNumber(), - VersionInfo::GetRevisionNumber() -}; -const LPCTSTR UpdateChecker::MPC_HC_UPDATE_URL = UPDATE_URL; - -bool UpdateChecker::bIsCheckingForUpdate = false; -CCritSec UpdateChecker::csIsCheckingForUpdate; - -UpdateChecker::UpdateChecker(CString versionFileURL) - : versionFileURL(versionFileURL) - , latestVersion() -{ -} - -UpdateChecker::~UpdateChecker() -{ -} - -Update_Status UpdateChecker::IsUpdateAvailable(const Version& currentVersion) -{ - Update_Status update_status = IsUpdateAvailable(currentVersion, false); - if (update_status == UPDATER_ERROR) update_status = IsUpdateAvailable(currentVersion, true); - return update_status; -} - -Update_Status UpdateChecker::IsUpdateAvailable(const Version& currentVersion, bool useBackupURL) -{ - Update_Status updateAvailable = UPDATER_LATEST_STABLE; - - try { - CInternetSession internet; - -#pragma warning(push) -#pragma warning(disable: 4996) - OSVERSIONINFOEX osVersion = { sizeof(OSVERSIONINFOEX) }; - GetVersionEx(reinterpret_cast(&osVersion)); -#pragma warning(pop) - CString osVersionStr; - osVersionStr.Format(_T("Windows %1u.%1u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion); - -#if !defined(_WIN64) - // 32-bit programs run on both 32-bit and 64-bit Windows - // so must sniff - BOOL f64 = FALSE; - if (IsWow64Process(GetCurrentProcess(), &f64) && f64) -#endif - { - osVersionStr += _T(" x64"); - } - - CString headersFmt = _T("User-Agent: MPC-HC"); - if (VersionInfo::Is64Bit()) { - headersFmt += _T(" (64-bit)"); - } -#ifdef MPCHC_LITE - headersFmt += _T(" Lite"); -#endif - headersFmt += _T(" (%s)/"); - headersFmt += VersionInfo::GetFullVersionString(); - headersFmt += _T("\r\n"); - - CString headers; - headers.Format(headersFmt, osVersionStr.GetString()); - - CString fileURL; - if (useBackupURL) fileURL = BACKUP_UPDATE_URL; - else fileURL = versionFileURL; - - CHttpFile* versionFile = (CHttpFile*) internet.OpenURL(fileURL, - 1, - INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, - headers, - DWORD(-1)); - - if (versionFile) { - CString latestVersionStr; - char buffer[101]; - UINT br = 0; - - while ((br = versionFile->Read(buffer, 50)) > 0) { - buffer[br] = '\0'; - latestVersionStr += buffer; - } - - if (!ParseVersion(latestVersionStr, latestVersion)) { - updateAvailable = UPDATER_ERROR; - } else { - time_t lastCheck = time(nullptr); - AfxGetApp()->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_UPDATER_LAST_CHECK, (LPBYTE)&lastCheck, sizeof(time_t)); - - int comp = CompareVersion(currentVersion, latestVersion); - - if (comp < 0) { - CString ignoredVersionStr = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_UPDATER_IGNORE_VERSION, _T("0.0.0.0")); - Version ignoredVersion; - bool ignored = false; - - if (ParseVersion(ignoredVersionStr, ignoredVersion)) { - ignored = (CompareVersion(ignoredVersion, latestVersion) >= 0); - } - - updateAvailable = ignored ? UPDATER_UPDATE_AVAILABLE_IGNORED : UPDATER_UPDATE_AVAILABLE; - } else if (comp > 0) { - updateAvailable = UPDATER_NEWER_VERSION; - } - } - - versionFile->Close(); // Close() isn't called by the destructor - delete versionFile; - } else { - updateAvailable = UPDATER_ERROR; - } - } catch (CInternetException* pEx) { - updateAvailable = UPDATER_ERROR; - pEx->Delete(); - } - - return updateAvailable; -} - -Update_Status UpdateChecker::IsUpdateAvailable() -{ - return IsUpdateAvailable(MPC_HC_VERSION); -} - -void UpdateChecker::IgnoreLatestVersion() -{ - CString ignoredVersionStr; - ignoredVersionStr.Format(_T("%u.%u.%u.%u"), latestVersion.major, latestVersion.minor, latestVersion.patch, latestVersion.revision); - - AfxGetApp()->WriteProfileString(IDS_R_SETTINGS, IDS_RS_UPDATER_IGNORE_VERSION, ignoredVersionStr); -} - -bool UpdateChecker::ParseVersion(const CString& versionStr, Version& version) -{ - bool success = false; - - if (!versionStr.IsEmpty()) { - UINT v[4]; - int curPos = 0; - UINT i = 0; - CString resToken = versionStr.Tokenize(_T("."), curPos); - - success = !resToken.IsEmpty(); - - while (!resToken.IsEmpty() && i < _countof(v) && success) { - if (1 != _stscanf_s(resToken, _T("%u"), v + i)) { - success = false; - } - - resToken = versionStr.Tokenize(_T("."), curPos); - i++; - } - - success = success && (i == _countof(v)); - - if (success) { - version.major = v[0]; - version.minor = v[1]; - version.patch = v[2]; - version.revision = v[3]; - } - } - - return success; -} - -int UpdateChecker::CompareVersion(const Version& v1, const Version& v2) -{ - if (v1.major > v2.major) { - return 1; - } else if (v1.major < v2.major) { - return -1; - } else if (v1.minor > v2.minor) { - return 1; - } else if (v1.minor < v2.minor) { - return -1; - } else if (v1.patch > v2.patch) { - return 1; - } else if (v1.patch < v2.patch) { - return -1; - } else if (v1.revision > v2.revision) { - return 1; - } else if (v1.revision < v2.revision) { - return -1; - } else { - return 0; - } -} - -bool UpdateChecker::IsAutoUpdateEnabled() -{ - int& status = AfxGetAppSettings().nUpdaterAutoCheck; - - if (status == AUTOUPDATE_UNKNOWN) { // First run - status = (AfxMessageBox(IDS_UPDATE_CONFIG_AUTO_CHECK, MB_ICONQUESTION | MB_YESNO, 0) == IDYES) ? AUTOUPDATE_ENABLE : AUTOUPDATE_DISABLE; - } - - return (status == AUTOUPDATE_ENABLE); -} - -bool UpdateChecker::IsTimeToAutoUpdate() -{ - time_t* lastCheck = nullptr; - UINT nRead; - - if (!AfxGetApp()->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_UPDATER_LAST_CHECK, (LPBYTE*)&lastCheck, &nRead) || nRead != sizeof(time_t)) { - if (lastCheck) { - delete [] lastCheck; - } - - return true; - } - - bool isTimeToAutoUpdate = (time(nullptr) >= *lastCheck + AfxGetAppSettings().nUpdaterDelay * 24 * 3600); - - delete [] lastCheck; - - return isTimeToAutoUpdate; -} - -static UINT RunCheckForUpdateThread(LPVOID pParam) -{ - bool autoCheck = !!pParam; - - if (!autoCheck || UpdateChecker::IsTimeToAutoUpdate()) { - UpdateChecker updateChecker(UpdateChecker::MPC_HC_UPDATE_URL); - - Update_Status status = updateChecker.IsUpdateAvailable(); - - if (!autoCheck || status == UPDATER_UPDATE_AVAILABLE) { - UpdateCheckerDlg dlg(status, updateChecker.GetLatestVersion()); - - if (dlg.DoModal() == IDC_UPDATE_IGNORE_BUTTON) { - updateChecker.IgnoreLatestVersion(); - } - } - } - - UpdateChecker::bIsCheckingForUpdate = false; - - return 0; -} - -void UpdateChecker::CheckForUpdate(bool autoCheck /*= false*/) -{ - CAutoLock lock(&csIsCheckingForUpdate); - - if (!bIsCheckingForUpdate) { - bIsCheckingForUpdate = true; - AfxBeginThread(RunCheckForUpdateThread, (LPVOID)autoCheck); - } -} +/* + * (C) 2012-2014, 2017 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 . + * + */ + + +#include "stdafx.h" +#include "mpc-hc_config.h" +#include "VersionInfo.h" +#include "UpdateChecker.h" +#include "UpdateCheckerDlg.h" +#include "SettingsDefines.h" +#include "mplayerc.h" +#include "AppSettings.h" + +#include + +const Version UpdateChecker::MPC_HC_VERSION = { + VersionInfo::GetMajorNumber(), + VersionInfo::GetMinorNumber(), + VersionInfo::GetPatchNumber(), + VersionInfo::GetRevisionNumber() +}; +const LPCTSTR UpdateChecker::MPC_HC_UPDATE_URL = UPDATE_URL; + +bool UpdateChecker::bIsCheckingForUpdate = false; +CCritSec UpdateChecker::csIsCheckingForUpdate; + +UpdateChecker::UpdateChecker(CString versionFileURL) + : versionFileURL(versionFileURL) + , latestVersion() +{ +} + +UpdateChecker::~UpdateChecker() +{ +} + +Update_Status UpdateChecker::IsUpdateAvailable(const Version& currentVersion) +{ + Update_Status update_status = IsUpdateAvailable(currentVersion, false); + if (update_status == UPDATER_ERROR) update_status = IsUpdateAvailable(currentVersion, true); + return update_status; +} + +Update_Status UpdateChecker::IsUpdateAvailable(const Version& currentVersion, bool useBackupURL) +{ + Update_Status updateAvailable = UPDATER_LATEST_STABLE; + + try { + CInternetSession internet; + +#pragma warning(push) +#pragma warning(disable: 4996) + OSVERSIONINFOEX osVersion = { sizeof(OSVERSIONINFOEX) }; + GetVersionEx(reinterpret_cast(&osVersion)); +#pragma warning(pop) + CString osVersionStr; + osVersionStr.Format(_T("Windows %1u.%1u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion); + +#if !defined(_WIN64) + // 32-bit programs run on both 32-bit and 64-bit Windows + // so must sniff + BOOL f64 = FALSE; + if (IsWow64Process(GetCurrentProcess(), &f64) && f64) +#endif + { + osVersionStr += _T(" x64"); + } + + CString headersFmt = _T("User-Agent: MPC-HC"); + if (VersionInfo::Is64Bit()) { + headersFmt += _T(" (64-bit)"); + } +#ifdef MPCHC_LITE + headersFmt += _T(" Lite"); +#endif + headersFmt += _T(" (%s)/"); + headersFmt += VersionInfo::GetFullVersionString(); + headersFmt += _T("\r\n"); + + CString headers; + headers.Format(headersFmt, osVersionStr.GetString()); + + CString fileURL; + if (useBackupURL) fileURL = BACKUP_UPDATE_URL; + else fileURL = versionFileURL; + + CHttpFile* versionFile = (CHttpFile*) internet.OpenURL(fileURL, + 1, + INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, + headers, + DWORD(-1)); + + if (versionFile) { + CString latestVersionStr; + char buffer[101]; + UINT br = 0; + + while ((br = versionFile->Read(buffer, 50)) > 0) { + buffer[br] = '\0'; + latestVersionStr += buffer; + } + + if (!ParseVersion(latestVersionStr, latestVersion)) { + updateAvailable = UPDATER_ERROR; + } else { + time_t lastCheck = time(nullptr); + AfxGetApp()->WriteProfileBinary(IDS_R_SETTINGS, IDS_RS_UPDATER_LAST_CHECK, (LPBYTE)&lastCheck, sizeof(time_t)); + + int comp = CompareVersion(currentVersion, latestVersion); + + if (comp < 0) { + CString ignoredVersionStr = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_UPDATER_IGNORE_VERSION, _T("0.0.0.0")); + Version ignoredVersion; + bool ignored = false; + + if (ParseVersion(ignoredVersionStr, ignoredVersion)) { + ignored = (CompareVersion(ignoredVersion, latestVersion) >= 0); + } + + updateAvailable = ignored ? UPDATER_UPDATE_AVAILABLE_IGNORED : UPDATER_UPDATE_AVAILABLE; + } else if (comp > 0) { + updateAvailable = UPDATER_NEWER_VERSION; + } + } + + versionFile->Close(); // Close() isn't called by the destructor + delete versionFile; + } else { + updateAvailable = UPDATER_ERROR; + } + } catch (CInternetException* pEx) { + updateAvailable = UPDATER_ERROR; + pEx->Delete(); + } + + return updateAvailable; +} + +Update_Status UpdateChecker::IsUpdateAvailable() +{ + return IsUpdateAvailable(MPC_HC_VERSION); +} + +void UpdateChecker::IgnoreLatestVersion() +{ + CString ignoredVersionStr; + ignoredVersionStr.Format(_T("%u.%u.%u.%u"), latestVersion.major, latestVersion.minor, latestVersion.patch, latestVersion.revision); + + AfxGetApp()->WriteProfileString(IDS_R_SETTINGS, IDS_RS_UPDATER_IGNORE_VERSION, ignoredVersionStr); +} + +bool UpdateChecker::ParseVersion(const CString& versionStr, Version& version) +{ + bool success = false; + + if (!versionStr.IsEmpty()) { + UINT v[4]; + int curPos = 0; + UINT i = 0; + CString resToken = versionStr.Tokenize(_T("."), curPos); + + success = !resToken.IsEmpty(); + + while (!resToken.IsEmpty() && i < _countof(v) && success) { + if (1 != _stscanf_s(resToken, _T("%u"), v + i)) { + success = false; + } + + resToken = versionStr.Tokenize(_T("."), curPos); + i++; + } + + success = success && (i == _countof(v)); + + if (success) { + version.major = v[0]; + version.minor = v[1]; + version.patch = v[2]; + version.revision = v[3]; + } + } + + return success; +} + +int UpdateChecker::CompareVersion(const Version& v1, const Version& v2) +{ + if (v1.major > v2.major) { + return 1; + } else if (v1.major < v2.major) { + return -1; + } else if (v1.minor > v2.minor) { + return 1; + } else if (v1.minor < v2.minor) { + return -1; + } else if (v1.patch > v2.patch) { + return 1; + } else if (v1.patch < v2.patch) { + return -1; + } else if (v1.revision > v2.revision) { + return 1; + } else if (v1.revision < v2.revision) { + return -1; + } else { + return 0; + } +} + +bool UpdateChecker::IsAutoUpdateEnabled() +{ + int& status = AfxGetAppSettings().nUpdaterAutoCheck; + + if (status == AUTOUPDATE_UNKNOWN) { // First run + status = (AfxMessageBox(IDS_UPDATE_CONFIG_AUTO_CHECK, MB_ICONQUESTION | MB_YESNO, 0) == IDYES) ? AUTOUPDATE_ENABLE : AUTOUPDATE_DISABLE; + } + + return (status == AUTOUPDATE_ENABLE); +} + +bool UpdateChecker::IsTimeToAutoUpdate() +{ + time_t* lastCheck = nullptr; + UINT nRead; + + if (!AfxGetApp()->GetProfileBinary(IDS_R_SETTINGS, IDS_RS_UPDATER_LAST_CHECK, (LPBYTE*)&lastCheck, &nRead) || nRead != sizeof(time_t)) { + if (lastCheck) { + delete [] lastCheck; + } + + return true; + } + + bool isTimeToAutoUpdate = (time(nullptr) >= *lastCheck + AfxGetAppSettings().nUpdaterDelay * 24 * 3600); + + delete [] lastCheck; + + return isTimeToAutoUpdate; +} + +static UINT RunCheckForUpdateThread(LPVOID pParam) +{ + bool autoCheck = !!pParam; + + if (!autoCheck || UpdateChecker::IsTimeToAutoUpdate()) { + UpdateChecker updateChecker(UpdateChecker::MPC_HC_UPDATE_URL); + + Update_Status status = updateChecker.IsUpdateAvailable(); + + if (!autoCheck || status == UPDATER_UPDATE_AVAILABLE) { + UpdateCheckerDlg dlg(status, updateChecker.GetLatestVersion()); + + if (dlg.DoModal() == IDC_UPDATE_IGNORE_BUTTON) { + updateChecker.IgnoreLatestVersion(); + } + } + } + + UpdateChecker::bIsCheckingForUpdate = false; + + return 0; +} + +void UpdateChecker::CheckForUpdate(bool autoCheck /*= false*/) +{ + CAutoLock lock(&csIsCheckingForUpdate); + + if (!bIsCheckingForUpdate) { + bIsCheckingForUpdate = true; + AfxBeginThread(RunCheckForUpdateThread, (LPVOID)autoCheck); + } +} diff --git a/src/mpc-hc/UpdateChecker.h b/src/mpc-hc/UpdateChecker.h index f0e4f10672e..fc10d8abf3f 100644 --- a/src/mpc-hc/UpdateChecker.h +++ b/src/mpc-hc/UpdateChecker.h @@ -1,87 +1,87 @@ -/* - * (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 . - * - */ - -#pragma once - -#include - -struct Version { - UINT major; - UINT minor; - UINT patch; - UINT revision; - - CString ToString() const { - CString versionStr; - - versionStr.Format(_T("%u.%u.%u"), major, minor, patch); - if (revision) { - versionStr.AppendFormat(_T(".%u"), revision); - } - - return versionStr; - } -}; - -enum Update_Status { - UPDATER_ERROR = -1, - UPDATER_LATEST_STABLE, - UPDATER_NEWER_VERSION, - UPDATER_UPDATE_AVAILABLE, - UPDATER_UPDATE_AVAILABLE_IGNORED -}; - -enum AutoUpdate_Status { - AUTOUPDATE_UNKNOWN = -1, - AUTOUPDATE_DISABLE, - AUTOUPDATE_ENABLE -}; - -class UpdateChecker -{ -public: - static const Version MPC_HC_VERSION; - static const LPCTSTR MPC_HC_UPDATE_URL; - - UpdateChecker(CString versionFileURL); - ~UpdateChecker(); - - Update_Status IsUpdateAvailable(const Version& currentVersion, bool useBackupURL); - Update_Status IsUpdateAvailable(const Version& currentVersion); - Update_Status IsUpdateAvailable(); - const Version& GetLatestVersion() const { return latestVersion; }; - void IgnoreLatestVersion(); - - static bool IsAutoUpdateEnabled(); - static bool IsTimeToAutoUpdate(); - static void CheckForUpdate(bool autoCheck = false); - -private: - static bool bIsCheckingForUpdate; - static CCritSec csIsCheckingForUpdate; - - CString versionFileURL; - Version latestVersion; - - static bool ParseVersion(const CString& versionStr, Version& version); - static int CompareVersion(const Version& v1, const Version& v2); - - friend static UINT RunCheckForUpdateThread(LPVOID pParam); -}; +/* + * (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 . + * + */ + +#pragma once + +#include + +struct Version { + UINT major; + UINT minor; + UINT patch; + UINT revision; + + CString ToString() const { + CString versionStr; + + versionStr.Format(_T("%u.%u.%u"), major, minor, patch); + if (revision) { + versionStr.AppendFormat(_T(".%u"), revision); + } + + return versionStr; + } +}; + +enum Update_Status { + UPDATER_ERROR = -1, + UPDATER_LATEST_STABLE, + UPDATER_NEWER_VERSION, + UPDATER_UPDATE_AVAILABLE, + UPDATER_UPDATE_AVAILABLE_IGNORED +}; + +enum AutoUpdate_Status { + AUTOUPDATE_UNKNOWN = -1, + AUTOUPDATE_DISABLE, + AUTOUPDATE_ENABLE +}; + +class UpdateChecker +{ +public: + static const Version MPC_HC_VERSION; + static const LPCTSTR MPC_HC_UPDATE_URL; + + UpdateChecker(CString versionFileURL); + ~UpdateChecker(); + + Update_Status IsUpdateAvailable(const Version& currentVersion, bool useBackupURL); + Update_Status IsUpdateAvailable(const Version& currentVersion); + Update_Status IsUpdateAvailable(); + const Version& GetLatestVersion() const { return latestVersion; }; + void IgnoreLatestVersion(); + + static bool IsAutoUpdateEnabled(); + static bool IsTimeToAutoUpdate(); + static void CheckForUpdate(bool autoCheck = false); + +private: + static bool bIsCheckingForUpdate; + static CCritSec csIsCheckingForUpdate; + + CString versionFileURL; + Version latestVersion; + + static bool ParseVersion(const CString& versionStr, Version& version); + static int CompareVersion(const Version& v1, const Version& v2); + + friend static UINT RunCheckForUpdateThread(LPVOID pParam); +}; diff --git a/src/mpc-hc/UpdateCheckerDlg.cpp b/src/mpc-hc/UpdateCheckerDlg.cpp index babbd78069a..ebff3b40ab6 100644 --- a/src/mpc-hc/UpdateCheckerDlg.cpp +++ b/src/mpc-hc/UpdateCheckerDlg.cpp @@ -1,132 +1,132 @@ -/* - * (C) 2012-2013, 2017 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 . - * - */ - - -#include -#include "stdafx.h" -#include "UpdateCheckerDlg.h" -#include "mpc-hc_config.h" - -IMPLEMENT_DYNAMIC(UpdateCheckerDlg, CMPCThemeDialog) - -UpdateCheckerDlg::UpdateCheckerDlg(Update_Status updateStatus, const Version& latestVersion, CWnd* pParent /*=nullptr*/) - : CMPCThemeDialog(UpdateCheckerDlg::IDD, pParent) - , m_updateStatus(updateStatus) -{ - switch (updateStatus) { - case UPDATER_UPDATE_AVAILABLE: - case UPDATER_UPDATE_AVAILABLE_IGNORED: - m_text.Format(IDS_NEW_UPDATE_AVAILABLE, - latestVersion.ToString().GetString(), - UpdateChecker::MPC_HC_VERSION.ToString().GetString()); - break; - case UPDATER_LATEST_STABLE: - m_text.LoadString(IDS_USING_LATEST_STABLE); - break; - case UPDATER_NEWER_VERSION: - m_text.Format(IDS_USING_NEWER_VERSION, - UpdateChecker::MPC_HC_VERSION.ToString().GetString(), - latestVersion.ToString().GetString()); - break; - case UPDATER_ERROR: - m_text.LoadString(IDS_UPDATE_ERROR); - break; - default: - ASSERT(0); // should never happen - } -} - -UpdateCheckerDlg::~UpdateCheckerDlg() -{ -} - -void UpdateCheckerDlg::DoDataExchange(CDataExchange* pDX) -{ - CMPCThemeDialog::DoDataExchange(pDX); - DDX_Text(pDX, IDC_UPDATE_DLG_TEXT, m_text); - DDX_Control(pDX, IDC_UPDATE_ICON, m_icon); - DDX_Control(pDX, IDC_UPDATE_DL_BUTTON, m_dlButton); - DDX_Control(pDX, IDC_UPDATE_LATER_BUTTON, m_laterButton); - DDX_Control(pDX, IDC_UPDATE_IGNORE_BUTTON, m_ignoreButton); - fulfillThemeReqs(); -} - - -BEGIN_MESSAGE_MAP(UpdateCheckerDlg, CMPCThemeDialog) - ON_BN_CLICKED(IDC_UPDATE_DL_BUTTON, OnOpenDownloadPage) - ON_BN_CLICKED(IDC_UPDATE_LATER_BUTTON, OnUpdateLater) - ON_BN_CLICKED(IDC_UPDATE_IGNORE_BUTTON, OnIgnoreUpdate) -END_MESSAGE_MAP() - -BOOL UpdateCheckerDlg::OnInitDialog() -{ - BOOL ret = __super::OnInitDialog(); - - switch (m_updateStatus) { - case UPDATER_UPDATE_AVAILABLE: - case UPDATER_UPDATE_AVAILABLE_IGNORED: - m_icon.SetIcon(LoadIcon(nullptr, IDI_QUESTION)); - break; - case UPDATER_LATEST_STABLE: - case UPDATER_NEWER_VERSION: - case UPDATER_ERROR: { - m_icon.SetIcon(LoadIcon(nullptr, (m_updateStatus == UPDATER_ERROR) ? IDI_WARNING : IDI_INFORMATION)); - m_dlButton.ShowWindow(SW_HIDE); - m_laterButton.ShowWindow(SW_HIDE); - m_ignoreButton.SetWindowText(ResStr(IDS_UPDATE_CLOSE)); - - CRect buttonRect, windowRect; - m_ignoreButton.GetWindowRect(&buttonRect); - ScreenToClient(&buttonRect); - // Reduce the button width - buttonRect.left += 30; - // Center the button - GetWindowRect(&windowRect); - buttonRect.MoveToX((windowRect.Width() - buttonRect.Width()) / 2); - m_ignoreButton.MoveWindow(&buttonRect); - - // Change the default button - SetDefID(IDC_UPDATE_IGNORE_BUTTON); - ret = FALSE; // Focus has been set explicitly - } - break; - default: - ASSERT(0); // should never happen - } - - return ret; -} - -void UpdateCheckerDlg::OnOpenDownloadPage() -{ - ShellExecute(nullptr, _T("open"), DOWNLOAD_URL, nullptr, nullptr, SW_SHOWNORMAL); - - EndDialog(IDC_UPDATE_DL_BUTTON); -} - -void UpdateCheckerDlg::OnUpdateLater() -{ - EndDialog(IDC_UPDATE_LATER_BUTTON); -} - -void UpdateCheckerDlg::OnIgnoreUpdate() -{ - EndDialog((m_updateStatus == UPDATER_UPDATE_AVAILABLE) ? IDC_UPDATE_IGNORE_BUTTON : 0); -} +/* + * (C) 2012-2013, 2017 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 . + * + */ + + +#include +#include "stdafx.h" +#include "UpdateCheckerDlg.h" +#include "mpc-hc_config.h" + +IMPLEMENT_DYNAMIC(UpdateCheckerDlg, CMPCThemeDialog) + +UpdateCheckerDlg::UpdateCheckerDlg(Update_Status updateStatus, const Version& latestVersion, CWnd* pParent /*=nullptr*/) + : CMPCThemeDialog(UpdateCheckerDlg::IDD, pParent) + , m_updateStatus(updateStatus) +{ + switch (updateStatus) { + case UPDATER_UPDATE_AVAILABLE: + case UPDATER_UPDATE_AVAILABLE_IGNORED: + m_text.Format(IDS_NEW_UPDATE_AVAILABLE, + latestVersion.ToString().GetString(), + UpdateChecker::MPC_HC_VERSION.ToString().GetString()); + break; + case UPDATER_LATEST_STABLE: + m_text.LoadString(IDS_USING_LATEST_STABLE); + break; + case UPDATER_NEWER_VERSION: + m_text.Format(IDS_USING_NEWER_VERSION, + UpdateChecker::MPC_HC_VERSION.ToString().GetString(), + latestVersion.ToString().GetString()); + break; + case UPDATER_ERROR: + m_text.LoadString(IDS_UPDATE_ERROR); + break; + default: + ASSERT(0); // should never happen + } +} + +UpdateCheckerDlg::~UpdateCheckerDlg() +{ +} + +void UpdateCheckerDlg::DoDataExchange(CDataExchange* pDX) +{ + CMPCThemeDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_UPDATE_DLG_TEXT, m_text); + DDX_Control(pDX, IDC_UPDATE_ICON, m_icon); + DDX_Control(pDX, IDC_UPDATE_DL_BUTTON, m_dlButton); + DDX_Control(pDX, IDC_UPDATE_LATER_BUTTON, m_laterButton); + DDX_Control(pDX, IDC_UPDATE_IGNORE_BUTTON, m_ignoreButton); + fulfillThemeReqs(); +} + + +BEGIN_MESSAGE_MAP(UpdateCheckerDlg, CMPCThemeDialog) + ON_BN_CLICKED(IDC_UPDATE_DL_BUTTON, OnOpenDownloadPage) + ON_BN_CLICKED(IDC_UPDATE_LATER_BUTTON, OnUpdateLater) + ON_BN_CLICKED(IDC_UPDATE_IGNORE_BUTTON, OnIgnoreUpdate) +END_MESSAGE_MAP() + +BOOL UpdateCheckerDlg::OnInitDialog() +{ + BOOL ret = __super::OnInitDialog(); + + switch (m_updateStatus) { + case UPDATER_UPDATE_AVAILABLE: + case UPDATER_UPDATE_AVAILABLE_IGNORED: + m_icon.SetIcon(LoadIcon(nullptr, IDI_QUESTION)); + break; + case UPDATER_LATEST_STABLE: + case UPDATER_NEWER_VERSION: + case UPDATER_ERROR: { + m_icon.SetIcon(LoadIcon(nullptr, (m_updateStatus == UPDATER_ERROR) ? IDI_WARNING : IDI_INFORMATION)); + m_dlButton.ShowWindow(SW_HIDE); + m_laterButton.ShowWindow(SW_HIDE); + m_ignoreButton.SetWindowText(ResStr(IDS_UPDATE_CLOSE)); + + CRect buttonRect, windowRect; + m_ignoreButton.GetWindowRect(&buttonRect); + ScreenToClient(&buttonRect); + // Reduce the button width + buttonRect.left += 30; + // Center the button + GetWindowRect(&windowRect); + buttonRect.MoveToX((windowRect.Width() - buttonRect.Width()) / 2); + m_ignoreButton.MoveWindow(&buttonRect); + + // Change the default button + SetDefID(IDC_UPDATE_IGNORE_BUTTON); + ret = FALSE; // Focus has been set explicitly + } + break; + default: + ASSERT(0); // should never happen + } + + return ret; +} + +void UpdateCheckerDlg::OnOpenDownloadPage() +{ + ShellExecute(nullptr, _T("open"), DOWNLOAD_URL, nullptr, nullptr, SW_SHOWNORMAL); + + EndDialog(IDC_UPDATE_DL_BUTTON); +} + +void UpdateCheckerDlg::OnUpdateLater() +{ + EndDialog(IDC_UPDATE_LATER_BUTTON); +} + +void UpdateCheckerDlg::OnIgnoreUpdate() +{ + EndDialog((m_updateStatus == UPDATER_UPDATE_AVAILABLE) ? IDC_UPDATE_IGNORE_BUTTON : 0); +} diff --git a/src/mpc-hc/UpdateCheckerDlg.h b/src/mpc-hc/UpdateCheckerDlg.h index 2013504985c..9ffd583ec94 100644 --- a/src/mpc-hc/UpdateCheckerDlg.h +++ b/src/mpc-hc/UpdateCheckerDlg.h @@ -1,54 +1,54 @@ -/* - * (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 . - * - */ - -#pragma once - -#include -#include "resource.h" -#include "UpdateChecker.h" -#include "CMPCThemeDialog.h" -#include "CMPCThemeButton.h" - -class UpdateCheckerDlg : public CMPCThemeDialog -{ - DECLARE_DYNAMIC(UpdateCheckerDlg) - -public: - UpdateCheckerDlg(Update_Status updateStatus, const Version& latestVersion, CWnd* pParent = nullptr); - virtual ~UpdateCheckerDlg(); - - enum { IDD = IDD_UPDATE_DIALOG }; - -protected: - virtual void DoDataExchange(CDataExchange* pDX); - afx_msg virtual BOOL OnInitDialog(); - afx_msg void OnOpenDownloadPage(); - afx_msg void OnUpdateLater(); - afx_msg void OnIgnoreUpdate(); - - DECLARE_MESSAGE_MAP() -private: - Update_Status m_updateStatus; - CString m_text; - CStatic m_icon; - CMPCThemeButton m_dlButton; - CMPCThemeButton m_laterButton; - CMPCThemeButton m_ignoreButton; -}; +/* + * (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 . + * + */ + +#pragma once + +#include +#include "resource.h" +#include "UpdateChecker.h" +#include "CMPCThemeDialog.h" +#include "CMPCThemeButton.h" + +class UpdateCheckerDlg : public CMPCThemeDialog +{ + DECLARE_DYNAMIC(UpdateCheckerDlg) + +public: + UpdateCheckerDlg(Update_Status updateStatus, const Version& latestVersion, CWnd* pParent = nullptr); + virtual ~UpdateCheckerDlg(); + + enum { IDD = IDD_UPDATE_DIALOG }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); + afx_msg virtual BOOL OnInitDialog(); + afx_msg void OnOpenDownloadPage(); + afx_msg void OnUpdateLater(); + afx_msg void OnIgnoreUpdate(); + + DECLARE_MESSAGE_MAP() +private: + Update_Status m_updateStatus; + CString m_text; + CStatic m_icon; + CMPCThemeButton m_dlButton; + CMPCThemeButton m_laterButton; + CMPCThemeButton m_ignoreButton; +}; diff --git a/src/mpc-hc/VMROSD.cpp b/src/mpc-hc/VMROSD.cpp index e7b1562986b..fbba5b7bc36 100644 --- a/src/mpc-hc/VMROSD.cpp +++ b/src/mpc-hc/VMROSD.cpp @@ -1,662 +1,662 @@ -/* - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "VMROSD.h" -#include "mplayerc.h" -#include "DSMPropertyBag.h" -#include "MainFrm.h" -#include -#include "CMPCTheme.h" - -#define SEEKBAR_HEIGHT 60 -#define SLIDER_BAR_MARGIN 10 -#define SLIDER_BAR_HEIGHT 10 -#define SLIDER_CURSOR_HEIGHT 30 -#define SLIDER_CURSOR_WIDTH 15 -#define SLIDER_CHAP_WIDTH 4 -#define SLIDER_CHAP_HEIGHT 10 - - -CVMROSD::CVMROSD(CMainFrame* pMainFrame) - : m_pVMB(nullptr) - , m_pMFVMB(nullptr) - , m_pMVTO(nullptr) - , m_pCB(nullptr) - , m_pMainFrame(pMainFrame) - , m_pWnd(nullptr) - , m_iFontSize(0) - , m_bCursorMoving(false) - , m_bShowSeekBar(false) - , m_bSeekBarVisible(false) - , m_llSeekMin(0) - , m_llSeekMax(0) - , m_llSeekPos(0) - , m_bShowMessage(true) - , m_nMessagePos(OSD_NOMESSAGE) - , timerExpires(GetTickCount()) -{ - m_colors[OSD_TRANSPARENT] = RGB(0, 0, 0); - if (AppIsThemeLoaded()) { - m_colors[OSD_BACKGROUND] = CMPCTheme::ContentBGColor; - m_colors[OSD_BORDER] = CMPCTheme::WindowBorderColorDim; - m_colors[OSD_TEXT] = CMPCTheme::TextFGColor; - m_colors[OSD_BAR] = CMPCTheme::ScrollBGColor; - m_colors[OSD_CURSOR] = CMPCTheme::ScrollThumbColor; - m_colors[OSD_DEBUGCLR] = CMPCTheme::DebugColorRed; - - for (int a = OSD_TRANSPARENT + 1; a < std::size(m_colors); a++) { - if (m_colors[a] == 0) { //we cannot permit any standard color to be transparent=RGB(0,0,0) - m_colors[a] = RGB(1,1,1); - } - } - } else { - m_colors[OSD_BACKGROUND] = RGB(32, 40, 48); - m_colors[OSD_BORDER] = RGB(48, 56, 62); - m_colors[OSD_TEXT] = RGB(224, 224, 224); - m_colors[OSD_BAR] = RGB(64, 72, 80); - m_colors[OSD_CURSOR] = RGB(192, 200, 208); - m_colors[OSD_DEBUGCLR] = RGB(128, 136, 144); - } - - m_penBorder.CreatePen(PS_SOLID, 1, m_colors[OSD_BORDER]); - m_penCursor.CreatePen(PS_SOLID, 4, m_colors[OSD_CURSOR]); - m_brushBack.CreateSolidBrush(m_colors[OSD_BACKGROUND]); - m_brushBar.CreateSolidBrush(m_colors[OSD_BAR]); - m_brushChapter.CreateSolidBrush(m_colors[OSD_CURSOR]); - m_debugBrushBack.CreateSolidBrush(m_colors[OSD_DEBUGCLR]); - m_debugPenBorder.CreatePen(PS_SOLID, 1, m_colors[OSD_BORDER]); - - ZeroMemory(&m_bitmapInfo, sizeof(m_bitmapInfo)); - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - ZeroMemory(&m_MFVideoAlphaBitmap, sizeof(m_MFVideoAlphaBitmap)); -} - -CVMROSD::~CVMROSD() -{ - Stop(); - m_memDC.DeleteDC(); - m_penBorder.DeleteObject(); - m_penCursor.DeleteObject(); - m_brushBack.DeleteObject(); - m_brushBar.DeleteObject(); - m_brushChapter.DeleteObject(); - m_debugBrushBack.DeleteObject(); - m_debugPenBorder.DeleteObject(); -} - -void CVMROSD::SetSize(const CRect& wndRect, const CRect& videoRect) -{ - if (m_pWnd && (m_pVMB || m_pMFVMB)) { - if (m_bSeekBarVisible) { - m_bCursorMoving = false; - m_bSeekBarVisible = false; - Invalidate(); - } - - // Vanilla VMR9/EVR renderers draw the OSD relative to the video frame - const CAppSettings& s = AfxGetAppSettings(); - m_rectWnd = (s.iDSVideoRendererType != VIDRNDT_DS_VMR9WINDOWED - && s.iDSVideoRendererType != VIDRNDT_DS_EVR) ? wndRect : videoRect; - m_rectWnd.MoveToXY(0, 0); - - m_rectSeekBar.left = m_rectWnd.left; - m_rectSeekBar.right = m_rectWnd.right; - m_rectSeekBar.top = m_rectWnd.bottom - SEEKBAR_HEIGHT; - m_rectSeekBar.bottom = m_rectSeekBar.top + SEEKBAR_HEIGHT; - - UpdateBitmap(); - } -} - -void CVMROSD::UpdateBitmap() -{ - CAutoLock lock(&m_csLock); - CWindowDC dc(m_pWnd); - - m_memDC.DeleteDC(); - ZeroMemory(&m_bitmapInfo, sizeof(m_bitmapInfo)); - - if (m_memDC.CreateCompatibleDC(&dc)) { - BITMAPINFO bmi; - HBITMAP hbmpRender; - - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = m_rectWnd.Width(); - bmi.bmiHeader.biHeight = - m_rectWnd.Height(); // top-down - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - - hbmpRender = CreateDIBSection(m_memDC, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0); - m_memDC.SelectObject(hbmpRender); - - if (::GetObject(hbmpRender, sizeof(BITMAP), &m_bitmapInfo) != 0) { - // Configure the VMR's bitmap structure - if (m_pVMB) { - ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); - m_VMR9AlphaBitmap.dwFlags = VMRBITMAP_HDC | VMRBITMAP_SRCCOLORKEY; - m_VMR9AlphaBitmap.hdc = m_memDC; - m_VMR9AlphaBitmap.rSrc = m_rectWnd; - m_VMR9AlphaBitmap.rDest.left = 0; - m_VMR9AlphaBitmap.rDest.top = 0; - m_VMR9AlphaBitmap.rDest.right = 1.0; - m_VMR9AlphaBitmap.rDest.bottom = 1.0; - m_VMR9AlphaBitmap.fAlpha = 1.0; - m_VMR9AlphaBitmap.clrSrcKey = m_colors[OSD_TRANSPARENT]; - } else if (m_pMFVMB) { - ZeroMemory(&m_MFVideoAlphaBitmap, sizeof(m_MFVideoAlphaBitmap)); - m_MFVideoAlphaBitmap.params.dwFlags = MFVideoAlphaBitmap_SrcColorKey; - m_MFVideoAlphaBitmap.params.clrSrcKey = m_colors[OSD_TRANSPARENT]; - m_MFVideoAlphaBitmap.params.rcSrc = m_rectWnd; - m_MFVideoAlphaBitmap.params.nrcDest.right = 1; - m_MFVideoAlphaBitmap.params.nrcDest.bottom = 1; - m_MFVideoAlphaBitmap.GetBitmapFromDC = TRUE; - m_MFVideoAlphaBitmap.bitmap.hdc = m_memDC; - } - m_memDC.SetTextColor(m_colors[OSD_TEXT]); - m_memDC.SetBkMode(TRANSPARENT); - } - - if (m_mainFont.GetSafeHandle()) { - m_memDC.SelectObject(m_mainFont); - } - - DeleteObject(hbmpRender); - } -} - -void CVMROSD::Start(CWnd* pWnd, IVMRMixerBitmap9* pVMB, bool bShowSeekBar) -{ - m_pVMB = pVMB; - m_pMFVMB = nullptr; - m_pMVTO = nullptr; - m_pWnd = pWnd; - m_bShowSeekBar = bShowSeekBar; - UpdateBitmap(); -} - -void CVMROSD::Start(CWnd* pWnd, IMFVideoMixerBitmap* pMFVMB, bool bShowSeekBar) -{ - m_pMFVMB = pMFVMB; - m_pVMB = nullptr; - m_pMVTO = nullptr; - m_pWnd = pWnd; - m_bShowSeekBar = bShowSeekBar; - UpdateBitmap(); -} - -void CVMROSD::Start(CWnd* pWnd, IMadVRTextOsd* pMVTO) -{ - m_pMFVMB = nullptr; - m_pVMB = nullptr; - m_pMVTO = pMVTO; - m_pWnd = pWnd; -} - -void CVMROSD::Stop() -{ - m_pVMB.Release(); - m_pMFVMB.Release(); - m_pMVTO.Release(); - if (m_pWnd) { - m_pWnd->KillTimer((UINT_PTR)this); - m_pWnd = nullptr; - } -} - -void CVMROSD::SetVideoWindow(CWnd* pWnd) -{ - CAutoLock lock(&m_csLock); - - if (m_pWnd) { - m_pWnd->KillTimer((UINT_PTR)this); - } - m_pWnd = pWnd; - m_pWnd->SetTimer((UINT_PTR)this, 1000, TimerFunc); - UpdateBitmap(); -} - -void CVMROSD::DrawRect(const CRect* rect, CBrush* pBrush, CPen* pPen) -{ - if (pPen) { - m_memDC.SelectObject(pPen); - } else { - m_memDC.SelectStockObject(NULL_PEN); - } - - if (pBrush) { - m_memDC.SelectObject(pBrush); - } else { - m_memDC.SelectStockObject(HOLLOW_BRUSH); - } - - m_memDC.Rectangle(rect); -} - -void CVMROSD::DrawSlider(CRect* rect, __int64 llMin, __int64 llMax, __int64 llPos) -{ - m_rectBar.left = rect->left + SLIDER_BAR_MARGIN; - m_rectBar.right = rect->right - SLIDER_BAR_MARGIN; - m_rectBar.top = rect->top + (rect->Height() - SLIDER_BAR_HEIGHT) / 2; - m_rectBar.bottom = m_rectBar.top + SLIDER_BAR_HEIGHT; - - if (llMax == llMin) { - m_rectCursor.left = m_rectBar.left; - } else { - m_rectCursor.left = m_rectBar.left + (long)(m_rectBar.Width() * llPos / (llMax - llMin)); - } - m_rectCursor.left -= SLIDER_CURSOR_WIDTH / 2; - m_rectCursor.right = m_rectCursor.left + SLIDER_CURSOR_WIDTH; - m_rectCursor.top = rect->top + (rect->Height() - SLIDER_CURSOR_HEIGHT) / 2; - m_rectCursor.bottom = m_rectCursor.top + SLIDER_CURSOR_HEIGHT; - - DrawRect(rect, &m_brushBack, &m_penBorder); - DrawRect(&m_rectBar, &m_brushBar); - - if (m_pCB && m_pCB->ChapGetCount() > 1 && llMax != llMin) { - REFERENCE_TIME rt; - for (DWORD i = 0; i < m_pCB->ChapGetCount(); ++i) { - if (SUCCEEDED(m_pCB->ChapGet(i, &rt, nullptr))) { - __int64 pos = m_rectBar.Width() * rt / (llMax - llMin); - if (pos < 0) { - continue; - } - - CRect r; - r.left = m_rectBar.left + (LONG)pos - SLIDER_CHAP_WIDTH / 2; - r.top = rect->top + (rect->Height() - SLIDER_CHAP_HEIGHT) / 2; - r.right = r.left + SLIDER_CHAP_WIDTH; - r.bottom = r.top + SLIDER_CHAP_HEIGHT; - - DrawRect(&r, &m_brushChapter); - } - } - } - - DrawRect(&m_rectCursor, nullptr, &m_penCursor); -} - -void CVMROSD::DrawMessage() -{ - if (!m_bitmapInfo.bmWidth || !m_bitmapInfo.bmHeight || !m_bitmapInfo.bmBitsPixel) { - return; - } - if (m_nMessagePos != OSD_NOMESSAGE) { - CRect rectRestrictedWnd(m_rectWnd); - rectRestrictedWnd.DeflateRect(10, 10); - CRect rectText; - CRect rectOSD; - - DWORD uFormat = DT_SINGLELINE | DT_NOPREFIX; - m_memDC.DrawText(m_strMessage, &rectText, uFormat | DT_CALCRECT); - rectText.InflateRect(10, 5); - - rectOSD = rectText; - switch (m_nMessagePos) { - case OSD_TOPLEFT: - rectOSD.MoveToXY(10, 10); - break; - case OSD_TOPRIGHT: - default: - rectOSD.MoveToXY(m_rectWnd.Width() - rectText.Width() - 10, 10); - break; - } - rectOSD &= rectRestrictedWnd; - - DrawRect(&rectOSD, &m_brushBack, &m_penBorder); - uFormat |= DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS; - rectOSD.DeflateRect(10, 5); - m_memDC.DrawText(m_strMessage, &rectOSD, uFormat); - } -} - -void CVMROSD::DrawDebug() -{ - if (!m_debugMessages.IsEmpty()) { - CString msg, tmp; - POSITION pos; - pos = m_debugMessages.GetHeadPosition(); - msg.Format(_T("%s"), m_debugMessages.GetNext(pos).GetString()); - - while (pos) { - tmp = m_debugMessages.GetNext(pos); - if (!tmp.IsEmpty()) { - msg.AppendFormat(_T("\r\n%s"), tmp.GetString()); - } - } - - CRect rectText(0, 0, 0, 0); - CRect rectMessages; - m_memDC.DrawText(msg, &rectText, DT_CALCRECT); - rectText.InflateRect(20, 10); - - int l, r, t, b; - l = (m_rectWnd.Width() >> 1) - (rectText.Width() >> 1) - 10; - r = (m_rectWnd.Width() >> 1) + (rectText.Width() >> 1) + 10; - t = (m_rectWnd.Height() >> 1) - (rectText.Height() >> 1) - 10; - b = (m_rectWnd.Height() >> 1) + (rectText.Height() >> 1) + 10; - rectMessages = CRect(l, t, r, b); - DrawRect(&rectMessages, &m_debugBrushBack, &m_debugPenBorder); - m_memDC.DrawText(msg, &rectMessages, DT_CENTER | DT_VCENTER); - } -} - -void CVMROSD::Invalidate() -{ - CAutoLock lock(&m_csLock); - if (!m_bitmapInfo.bmWidth || !m_bitmapInfo.bmHeight || !m_bitmapInfo.bmBitsPixel) { - return; - } - memsetd(m_bitmapInfo.bmBits, 0xff000000, m_bitmapInfo.bmWidth * m_bitmapInfo.bmHeight * (m_bitmapInfo.bmBitsPixel / 8)); - - if (m_bSeekBarVisible) { - DrawSlider(&m_rectSeekBar, m_llSeekMin, m_llSeekMax, m_llSeekPos); - } - DrawMessage(); - DrawDebug(); - - if (m_pVMB) { - m_VMR9AlphaBitmap.dwFlags &= ~VMRBITMAP_DISABLE; - m_pVMB->SetAlphaBitmap(&m_VMR9AlphaBitmap); - } else if (m_pMFVMB) { - m_pMFVMB->SetAlphaBitmap(&m_MFVideoAlphaBitmap); - } - - m_pMainFrame->RepaintVideo(); -} - -void CVMROSD::UpdateSeekBarPos(CPoint point) -{ - m_llSeekPos = (point.x - m_rectBar.left) * (m_llSeekMax - m_llSeekMin) / (m_rectBar.Width() - SLIDER_CURSOR_WIDTH); - m_llSeekPos = std::max(m_llSeekPos, m_llSeekMin); - m_llSeekPos = std::min(m_llSeekPos, m_llSeekMax); - - const CAppSettings& s = AfxGetAppSettings(); - if (s.bFastSeek ^ (GetKeyState(VK_SHIFT) < 0)) { - REFERENCE_TIME rtMaxDiff = s.bAllowInaccurateFastseek ? 200000000LL : std::min(100000000LL, m_llSeekMax / 30); - m_llSeekPos = m_pMainFrame->GetClosestKeyFrame(m_llSeekPos, rtMaxDiff, rtMaxDiff); - } - - if (m_pWnd) { - AfxGetApp()->GetMainWnd()->PostMessage(WM_HSCROLL, (WPARAM)0, reinterpret_cast(m_pWnd->m_hWnd)); - } -} - -bool CVMROSD::OnMouseMove(UINT nFlags, CPoint point) -{ - bool bRet = false; - - if (m_pVMB || m_pMFVMB) { - if (m_bCursorMoving) { - bRet = true; - UpdateSeekBarPos(point); - Invalidate(); - } else if (m_bShowSeekBar && m_rectSeekBar.PtInRect(point)) { - bRet = true; - if (!m_bSeekBarVisible) { - m_bSeekBarVisible = true; - Invalidate(); - } - } else if (m_bSeekBarVisible) { - OnMouseLeave(); - } - } - - return bRet; -} - -void CVMROSD::OnMouseLeave() -{ - const bool bHideSeekbar = (m_pVMB || m_pMFVMB) && m_bSeekBarVisible; - m_bCursorMoving = false; - m_bSeekBarVisible = false; - - if (bHideSeekbar) { - // Add new timer for removing any messages - if (m_pWnd) { - m_pWnd->KillTimer((UINT_PTR)this); - m_pWnd->SetTimer((UINT_PTR)this, 1000, TimerFunc); - } - Invalidate(); - } -} - -bool CVMROSD::OnLButtonDown(UINT nFlags, CPoint point) -{ - bool bRet = false; - if (m_pVMB || m_pMFVMB) { - if (m_rectCursor.PtInRect(point)) { - m_bCursorMoving = true; - bRet = true; - if (m_pWnd) { - ASSERT(dynamic_cast(m_pWnd)); - m_pWnd->SetCapture(); - } - } else if (m_rectSeekBar.PtInRect(point)) { - bRet = true; - UpdateSeekBarPos(point); - Invalidate(); - } - } - - return bRet; -} - -bool CVMROSD::OnLButtonUp(UINT nFlags, CPoint point) -{ - bool bRet = false; - - if (m_pVMB || m_pMFVMB) { - m_bCursorMoving = false; - - bRet = (m_rectCursor.PtInRect(point) || m_rectSeekBar.PtInRect(point)); - } - return bRet; -} - -__int64 CVMROSD::GetPos() const -{ - return m_llSeekPos; -} - -void CVMROSD::SetPos(__int64 pos) -{ - m_llSeekPos = pos; - if (m_bSeekBarVisible) { - Invalidate(); - } -} - -void CVMROSD::SetRange(__int64 start, __int64 stop) -{ - m_llSeekMin = start; - m_llSeekMax = stop; -} - -void CVMROSD::GetRange(__int64& start, __int64& stop) -{ - start = m_llSeekMin; - stop = m_llSeekMax; -} - -void CVMROSD::TimerFunc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime) -{ - CVMROSD* pVMROSD = (CVMROSD*)nIDEvent; - if (pVMROSD) { - if (!pVMROSD->currentTime.IsEmpty()) { - pVMROSD->DisplayTime(pVMROSD->currentTime); - } else { - pVMROSD->ClearMessage(); - } - } - KillTimer(hWnd, nIDEvent); -} - -void CVMROSD::ClearTime() -{ - currentTime = L""; - if (timerExpires == timerExpiresForTime) { - ClearMessage(); - } -} - -void CVMROSD::ClearMessage(bool hide) -{ - CAutoLock lock(&m_csLock); - if (m_bSeekBarVisible) { - return; - } - - if (!hide) { - m_nMessagePos = OSD_NOMESSAGE; - } - - if (m_pVMB) { - DWORD dwBackup = (m_VMR9AlphaBitmap.dwFlags | VMRBITMAP_DISABLE); - m_VMR9AlphaBitmap.dwFlags = VMRBITMAP_DISABLE; - m_pVMB->SetAlphaBitmap(&m_VMR9AlphaBitmap); - m_VMR9AlphaBitmap.dwFlags = dwBackup; - } else if (m_pMFVMB) { - m_pMFVMB->ClearAlphaBitmap(); - } else if (m_pMVTO) { - m_pMVTO->OsdClearMessage(); - } - - m_pMainFrame->RepaintVideo(); -} - -void CVMROSD::DisplayTime(LPCTSTR strTime) -{ - currentTime = strTime; - if (timerExpires < GetTickCount() || timerExpires == timerExpiresForTime) { - DisplayMessage(OSD_TOPLEFT, strTime, 1000); - timerExpiresForTime = timerExpires; - } -} - - -void CVMROSD::DisplayMessage(OSD_MESSAGEPOS nPos, LPCTSTR strMsg, int nDuration, int iFontSize, CString fontName) -{ - if (!m_bShowMessage) { - return; - } - - if (m_pVMB || m_pMFVMB) { - if (nPos != OSD_DEBUG) { - m_nMessagePos = nPos; - m_strMessage = strMsg; - } else { - m_debugMessages.AddTail(strMsg); - if (m_debugMessages.GetCount() > 20) { - m_debugMessages.RemoveHead(); - } - nDuration = -1; - } - - int iOldFontSize = m_iFontSize; - CString oldFontName = m_fontName; - const CAppSettings& s = AfxGetAppSettings(); - - if (iFontSize == 0) { - m_iFontSize = s.nOSDSize; - } else { - m_iFontSize = iFontSize; - } - if (m_iFontSize < 10 || m_iFontSize > 50) { - m_iFontSize = 20; - } - if (fontName.IsEmpty()) { - m_fontName = s.strOSDFont; - } else { - m_fontName = fontName; - } - - if (iOldFontSize != m_iFontSize || oldFontName != m_fontName) { - if (m_mainFont.GetSafeHandle()) { - m_mainFont.DeleteObject(); - } - - m_mainFont.CreatePointFont(m_iFontSize * 10, m_fontName); - m_memDC.SelectObject(m_mainFont); - } - - if (m_pWnd) { - m_pWnd->KillTimer((UINT_PTR)this); - if (nDuration != -1) { - timerExpires = GetTickCount() + nDuration; - m_pWnd->SetTimer((UINT_PTR)this, nDuration, TimerFunc); - } - } - Invalidate(); - } else if (m_pMVTO) { - m_pMVTO->OsdDisplayMessage(strMsg, nDuration); - } -} - -void CVMROSD::DebugMessage(LPCTSTR format, ...) -{ - CString msg; - va_list argList; - va_start(argList, format); - msg.FormatV(format, argList); - va_end(argList); - - DisplayMessage(OSD_DEBUG, msg); -} - -void CVMROSD::HideMessage(bool hide) -{ - if (m_pVMB || m_pMFVMB) { - if (hide) { - ClearMessage(true); - } else { - Invalidate(); - } - } -} - -void CVMROSD::EnableShowMessage(bool enabled) -{ - m_bShowMessage = enabled; -} - -bool CVMROSD::CanShowMessage() -{ - return m_bShowMessage && (m_pVMB || m_pMFVMB || m_pMVTO); -} - -void CVMROSD::EnableShowSeekBar(bool enabled) -{ - m_bShowSeekBar = enabled; -} - -void CVMROSD::SetChapterBag(IDSMChapterBag* pCB) -{ - CAutoLock lock(&m_csLock); - m_pCB = pCB; - Invalidate(); -} - -void CVMROSD::RemoveChapters() -{ - SetChapterBag(nullptr); -} +/* + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "VMROSD.h" +#include "mplayerc.h" +#include "DSMPropertyBag.h" +#include "MainFrm.h" +#include +#include "CMPCTheme.h" + +#define SEEKBAR_HEIGHT 60 +#define SLIDER_BAR_MARGIN 10 +#define SLIDER_BAR_HEIGHT 10 +#define SLIDER_CURSOR_HEIGHT 30 +#define SLIDER_CURSOR_WIDTH 15 +#define SLIDER_CHAP_WIDTH 4 +#define SLIDER_CHAP_HEIGHT 10 + + +CVMROSD::CVMROSD(CMainFrame* pMainFrame) + : m_pVMB(nullptr) + , m_pMFVMB(nullptr) + , m_pMVTO(nullptr) + , m_pCB(nullptr) + , m_pMainFrame(pMainFrame) + , m_pWnd(nullptr) + , m_iFontSize(0) + , m_bCursorMoving(false) + , m_bShowSeekBar(false) + , m_bSeekBarVisible(false) + , m_llSeekMin(0) + , m_llSeekMax(0) + , m_llSeekPos(0) + , m_bShowMessage(true) + , m_nMessagePos(OSD_NOMESSAGE) + , timerExpires(GetTickCount()) +{ + m_colors[OSD_TRANSPARENT] = RGB(0, 0, 0); + if (AppIsThemeLoaded()) { + m_colors[OSD_BACKGROUND] = CMPCTheme::ContentBGColor; + m_colors[OSD_BORDER] = CMPCTheme::WindowBorderColorDim; + m_colors[OSD_TEXT] = CMPCTheme::TextFGColor; + m_colors[OSD_BAR] = CMPCTheme::ScrollBGColor; + m_colors[OSD_CURSOR] = CMPCTheme::ScrollThumbColor; + m_colors[OSD_DEBUGCLR] = CMPCTheme::DebugColorRed; + + for (int a = OSD_TRANSPARENT + 1; a < std::size(m_colors); a++) { + if (m_colors[a] == 0) { //we cannot permit any standard color to be transparent=RGB(0,0,0) + m_colors[a] = RGB(1,1,1); + } + } + } else { + m_colors[OSD_BACKGROUND] = RGB(32, 40, 48); + m_colors[OSD_BORDER] = RGB(48, 56, 62); + m_colors[OSD_TEXT] = RGB(224, 224, 224); + m_colors[OSD_BAR] = RGB(64, 72, 80); + m_colors[OSD_CURSOR] = RGB(192, 200, 208); + m_colors[OSD_DEBUGCLR] = RGB(128, 136, 144); + } + + m_penBorder.CreatePen(PS_SOLID, 1, m_colors[OSD_BORDER]); + m_penCursor.CreatePen(PS_SOLID, 4, m_colors[OSD_CURSOR]); + m_brushBack.CreateSolidBrush(m_colors[OSD_BACKGROUND]); + m_brushBar.CreateSolidBrush(m_colors[OSD_BAR]); + m_brushChapter.CreateSolidBrush(m_colors[OSD_CURSOR]); + m_debugBrushBack.CreateSolidBrush(m_colors[OSD_DEBUGCLR]); + m_debugPenBorder.CreatePen(PS_SOLID, 1, m_colors[OSD_BORDER]); + + ZeroMemory(&m_bitmapInfo, sizeof(m_bitmapInfo)); + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + ZeroMemory(&m_MFVideoAlphaBitmap, sizeof(m_MFVideoAlphaBitmap)); +} + +CVMROSD::~CVMROSD() +{ + Stop(); + m_memDC.DeleteDC(); + m_penBorder.DeleteObject(); + m_penCursor.DeleteObject(); + m_brushBack.DeleteObject(); + m_brushBar.DeleteObject(); + m_brushChapter.DeleteObject(); + m_debugBrushBack.DeleteObject(); + m_debugPenBorder.DeleteObject(); +} + +void CVMROSD::SetSize(const CRect& wndRect, const CRect& videoRect) +{ + if (m_pWnd && (m_pVMB || m_pMFVMB)) { + if (m_bSeekBarVisible) { + m_bCursorMoving = false; + m_bSeekBarVisible = false; + Invalidate(); + } + + // Vanilla VMR9/EVR renderers draw the OSD relative to the video frame + const CAppSettings& s = AfxGetAppSettings(); + m_rectWnd = (s.iDSVideoRendererType != VIDRNDT_DS_VMR9WINDOWED + && s.iDSVideoRendererType != VIDRNDT_DS_EVR) ? wndRect : videoRect; + m_rectWnd.MoveToXY(0, 0); + + m_rectSeekBar.left = m_rectWnd.left; + m_rectSeekBar.right = m_rectWnd.right; + m_rectSeekBar.top = m_rectWnd.bottom - SEEKBAR_HEIGHT; + m_rectSeekBar.bottom = m_rectSeekBar.top + SEEKBAR_HEIGHT; + + UpdateBitmap(); + } +} + +void CVMROSD::UpdateBitmap() +{ + CAutoLock lock(&m_csLock); + CWindowDC dc(m_pWnd); + + m_memDC.DeleteDC(); + ZeroMemory(&m_bitmapInfo, sizeof(m_bitmapInfo)); + + if (m_memDC.CreateCompatibleDC(&dc)) { + BITMAPINFO bmi; + HBITMAP hbmpRender; + + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = m_rectWnd.Width(); + bmi.bmiHeader.biHeight = - m_rectWnd.Height(); // top-down + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + hbmpRender = CreateDIBSection(m_memDC, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0); + m_memDC.SelectObject(hbmpRender); + + if (::GetObject(hbmpRender, sizeof(BITMAP), &m_bitmapInfo) != 0) { + // Configure the VMR's bitmap structure + if (m_pVMB) { + ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap)); + m_VMR9AlphaBitmap.dwFlags = VMRBITMAP_HDC | VMRBITMAP_SRCCOLORKEY; + m_VMR9AlphaBitmap.hdc = m_memDC; + m_VMR9AlphaBitmap.rSrc = m_rectWnd; + m_VMR9AlphaBitmap.rDest.left = 0; + m_VMR9AlphaBitmap.rDest.top = 0; + m_VMR9AlphaBitmap.rDest.right = 1.0; + m_VMR9AlphaBitmap.rDest.bottom = 1.0; + m_VMR9AlphaBitmap.fAlpha = 1.0; + m_VMR9AlphaBitmap.clrSrcKey = m_colors[OSD_TRANSPARENT]; + } else if (m_pMFVMB) { + ZeroMemory(&m_MFVideoAlphaBitmap, sizeof(m_MFVideoAlphaBitmap)); + m_MFVideoAlphaBitmap.params.dwFlags = MFVideoAlphaBitmap_SrcColorKey; + m_MFVideoAlphaBitmap.params.clrSrcKey = m_colors[OSD_TRANSPARENT]; + m_MFVideoAlphaBitmap.params.rcSrc = m_rectWnd; + m_MFVideoAlphaBitmap.params.nrcDest.right = 1; + m_MFVideoAlphaBitmap.params.nrcDest.bottom = 1; + m_MFVideoAlphaBitmap.GetBitmapFromDC = TRUE; + m_MFVideoAlphaBitmap.bitmap.hdc = m_memDC; + } + m_memDC.SetTextColor(m_colors[OSD_TEXT]); + m_memDC.SetBkMode(TRANSPARENT); + } + + if (m_mainFont.GetSafeHandle()) { + m_memDC.SelectObject(m_mainFont); + } + + DeleteObject(hbmpRender); + } +} + +void CVMROSD::Start(CWnd* pWnd, IVMRMixerBitmap9* pVMB, bool bShowSeekBar) +{ + m_pVMB = pVMB; + m_pMFVMB = nullptr; + m_pMVTO = nullptr; + m_pWnd = pWnd; + m_bShowSeekBar = bShowSeekBar; + UpdateBitmap(); +} + +void CVMROSD::Start(CWnd* pWnd, IMFVideoMixerBitmap* pMFVMB, bool bShowSeekBar) +{ + m_pMFVMB = pMFVMB; + m_pVMB = nullptr; + m_pMVTO = nullptr; + m_pWnd = pWnd; + m_bShowSeekBar = bShowSeekBar; + UpdateBitmap(); +} + +void CVMROSD::Start(CWnd* pWnd, IMadVRTextOsd* pMVTO) +{ + m_pMFVMB = nullptr; + m_pVMB = nullptr; + m_pMVTO = pMVTO; + m_pWnd = pWnd; +} + +void CVMROSD::Stop() +{ + m_pVMB.Release(); + m_pMFVMB.Release(); + m_pMVTO.Release(); + if (m_pWnd) { + m_pWnd->KillTimer((UINT_PTR)this); + m_pWnd = nullptr; + } +} + +void CVMROSD::SetVideoWindow(CWnd* pWnd) +{ + CAutoLock lock(&m_csLock); + + if (m_pWnd) { + m_pWnd->KillTimer((UINT_PTR)this); + } + m_pWnd = pWnd; + m_pWnd->SetTimer((UINT_PTR)this, 1000, TimerFunc); + UpdateBitmap(); +} + +void CVMROSD::DrawRect(const CRect* rect, CBrush* pBrush, CPen* pPen) +{ + if (pPen) { + m_memDC.SelectObject(pPen); + } else { + m_memDC.SelectStockObject(NULL_PEN); + } + + if (pBrush) { + m_memDC.SelectObject(pBrush); + } else { + m_memDC.SelectStockObject(HOLLOW_BRUSH); + } + + m_memDC.Rectangle(rect); +} + +void CVMROSD::DrawSlider(CRect* rect, __int64 llMin, __int64 llMax, __int64 llPos) +{ + m_rectBar.left = rect->left + SLIDER_BAR_MARGIN; + m_rectBar.right = rect->right - SLIDER_BAR_MARGIN; + m_rectBar.top = rect->top + (rect->Height() - SLIDER_BAR_HEIGHT) / 2; + m_rectBar.bottom = m_rectBar.top + SLIDER_BAR_HEIGHT; + + if (llMax == llMin) { + m_rectCursor.left = m_rectBar.left; + } else { + m_rectCursor.left = m_rectBar.left + (long)(m_rectBar.Width() * llPos / (llMax - llMin)); + } + m_rectCursor.left -= SLIDER_CURSOR_WIDTH / 2; + m_rectCursor.right = m_rectCursor.left + SLIDER_CURSOR_WIDTH; + m_rectCursor.top = rect->top + (rect->Height() - SLIDER_CURSOR_HEIGHT) / 2; + m_rectCursor.bottom = m_rectCursor.top + SLIDER_CURSOR_HEIGHT; + + DrawRect(rect, &m_brushBack, &m_penBorder); + DrawRect(&m_rectBar, &m_brushBar); + + if (m_pCB && m_pCB->ChapGetCount() > 1 && llMax != llMin) { + REFERENCE_TIME rt; + for (DWORD i = 0; i < m_pCB->ChapGetCount(); ++i) { + if (SUCCEEDED(m_pCB->ChapGet(i, &rt, nullptr))) { + __int64 pos = m_rectBar.Width() * rt / (llMax - llMin); + if (pos < 0) { + continue; + } + + CRect r; + r.left = m_rectBar.left + (LONG)pos - SLIDER_CHAP_WIDTH / 2; + r.top = rect->top + (rect->Height() - SLIDER_CHAP_HEIGHT) / 2; + r.right = r.left + SLIDER_CHAP_WIDTH; + r.bottom = r.top + SLIDER_CHAP_HEIGHT; + + DrawRect(&r, &m_brushChapter); + } + } + } + + DrawRect(&m_rectCursor, nullptr, &m_penCursor); +} + +void CVMROSD::DrawMessage() +{ + if (!m_bitmapInfo.bmWidth || !m_bitmapInfo.bmHeight || !m_bitmapInfo.bmBitsPixel) { + return; + } + if (m_nMessagePos != OSD_NOMESSAGE) { + CRect rectRestrictedWnd(m_rectWnd); + rectRestrictedWnd.DeflateRect(10, 10); + CRect rectText; + CRect rectOSD; + + DWORD uFormat = DT_SINGLELINE | DT_NOPREFIX; + m_memDC.DrawText(m_strMessage, &rectText, uFormat | DT_CALCRECT); + rectText.InflateRect(10, 5); + + rectOSD = rectText; + switch (m_nMessagePos) { + case OSD_TOPLEFT: + rectOSD.MoveToXY(10, 10); + break; + case OSD_TOPRIGHT: + default: + rectOSD.MoveToXY(m_rectWnd.Width() - rectText.Width() - 10, 10); + break; + } + rectOSD &= rectRestrictedWnd; + + DrawRect(&rectOSD, &m_brushBack, &m_penBorder); + uFormat |= DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS; + rectOSD.DeflateRect(10, 5); + m_memDC.DrawText(m_strMessage, &rectOSD, uFormat); + } +} + +void CVMROSD::DrawDebug() +{ + if (!m_debugMessages.IsEmpty()) { + CString msg, tmp; + POSITION pos; + pos = m_debugMessages.GetHeadPosition(); + msg.Format(_T("%s"), m_debugMessages.GetNext(pos).GetString()); + + while (pos) { + tmp = m_debugMessages.GetNext(pos); + if (!tmp.IsEmpty()) { + msg.AppendFormat(_T("\r\n%s"), tmp.GetString()); + } + } + + CRect rectText(0, 0, 0, 0); + CRect rectMessages; + m_memDC.DrawText(msg, &rectText, DT_CALCRECT); + rectText.InflateRect(20, 10); + + int l, r, t, b; + l = (m_rectWnd.Width() >> 1) - (rectText.Width() >> 1) - 10; + r = (m_rectWnd.Width() >> 1) + (rectText.Width() >> 1) + 10; + t = (m_rectWnd.Height() >> 1) - (rectText.Height() >> 1) - 10; + b = (m_rectWnd.Height() >> 1) + (rectText.Height() >> 1) + 10; + rectMessages = CRect(l, t, r, b); + DrawRect(&rectMessages, &m_debugBrushBack, &m_debugPenBorder); + m_memDC.DrawText(msg, &rectMessages, DT_CENTER | DT_VCENTER); + } +} + +void CVMROSD::Invalidate() +{ + CAutoLock lock(&m_csLock); + if (!m_bitmapInfo.bmWidth || !m_bitmapInfo.bmHeight || !m_bitmapInfo.bmBitsPixel) { + return; + } + memsetd(m_bitmapInfo.bmBits, 0xff000000, m_bitmapInfo.bmWidth * m_bitmapInfo.bmHeight * (m_bitmapInfo.bmBitsPixel / 8)); + + if (m_bSeekBarVisible) { + DrawSlider(&m_rectSeekBar, m_llSeekMin, m_llSeekMax, m_llSeekPos); + } + DrawMessage(); + DrawDebug(); + + if (m_pVMB) { + m_VMR9AlphaBitmap.dwFlags &= ~VMRBITMAP_DISABLE; + m_pVMB->SetAlphaBitmap(&m_VMR9AlphaBitmap); + } else if (m_pMFVMB) { + m_pMFVMB->SetAlphaBitmap(&m_MFVideoAlphaBitmap); + } + + m_pMainFrame->RepaintVideo(); +} + +void CVMROSD::UpdateSeekBarPos(CPoint point) +{ + m_llSeekPos = (point.x - m_rectBar.left) * (m_llSeekMax - m_llSeekMin) / (m_rectBar.Width() - SLIDER_CURSOR_WIDTH); + m_llSeekPos = std::max(m_llSeekPos, m_llSeekMin); + m_llSeekPos = std::min(m_llSeekPos, m_llSeekMax); + + const CAppSettings& s = AfxGetAppSettings(); + if (s.bFastSeek ^ (GetKeyState(VK_SHIFT) < 0)) { + REFERENCE_TIME rtMaxDiff = s.bAllowInaccurateFastseek ? 200000000LL : std::min(100000000LL, m_llSeekMax / 30); + m_llSeekPos = m_pMainFrame->GetClosestKeyFrame(m_llSeekPos, rtMaxDiff, rtMaxDiff); + } + + if (m_pWnd) { + AfxGetApp()->GetMainWnd()->PostMessage(WM_HSCROLL, (WPARAM)0, reinterpret_cast(m_pWnd->m_hWnd)); + } +} + +bool CVMROSD::OnMouseMove(UINT nFlags, CPoint point) +{ + bool bRet = false; + + if (m_pVMB || m_pMFVMB) { + if (m_bCursorMoving) { + bRet = true; + UpdateSeekBarPos(point); + Invalidate(); + } else if (m_bShowSeekBar && m_rectSeekBar.PtInRect(point)) { + bRet = true; + if (!m_bSeekBarVisible) { + m_bSeekBarVisible = true; + Invalidate(); + } + } else if (m_bSeekBarVisible) { + OnMouseLeave(); + } + } + + return bRet; +} + +void CVMROSD::OnMouseLeave() +{ + const bool bHideSeekbar = (m_pVMB || m_pMFVMB) && m_bSeekBarVisible; + m_bCursorMoving = false; + m_bSeekBarVisible = false; + + if (bHideSeekbar) { + // Add new timer for removing any messages + if (m_pWnd) { + m_pWnd->KillTimer((UINT_PTR)this); + m_pWnd->SetTimer((UINT_PTR)this, 1000, TimerFunc); + } + Invalidate(); + } +} + +bool CVMROSD::OnLButtonDown(UINT nFlags, CPoint point) +{ + bool bRet = false; + if (m_pVMB || m_pMFVMB) { + if (m_rectCursor.PtInRect(point)) { + m_bCursorMoving = true; + bRet = true; + if (m_pWnd) { + ASSERT(dynamic_cast(m_pWnd)); + m_pWnd->SetCapture(); + } + } else if (m_rectSeekBar.PtInRect(point)) { + bRet = true; + UpdateSeekBarPos(point); + Invalidate(); + } + } + + return bRet; +} + +bool CVMROSD::OnLButtonUp(UINT nFlags, CPoint point) +{ + bool bRet = false; + + if (m_pVMB || m_pMFVMB) { + m_bCursorMoving = false; + + bRet = (m_rectCursor.PtInRect(point) || m_rectSeekBar.PtInRect(point)); + } + return bRet; +} + +__int64 CVMROSD::GetPos() const +{ + return m_llSeekPos; +} + +void CVMROSD::SetPos(__int64 pos) +{ + m_llSeekPos = pos; + if (m_bSeekBarVisible) { + Invalidate(); + } +} + +void CVMROSD::SetRange(__int64 start, __int64 stop) +{ + m_llSeekMin = start; + m_llSeekMax = stop; +} + +void CVMROSD::GetRange(__int64& start, __int64& stop) +{ + start = m_llSeekMin; + stop = m_llSeekMax; +} + +void CVMROSD::TimerFunc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime) +{ + CVMROSD* pVMROSD = (CVMROSD*)nIDEvent; + if (pVMROSD) { + if (!pVMROSD->currentTime.IsEmpty()) { + pVMROSD->DisplayTime(pVMROSD->currentTime); + } else { + pVMROSD->ClearMessage(); + } + } + KillTimer(hWnd, nIDEvent); +} + +void CVMROSD::ClearTime() +{ + currentTime = L""; + if (timerExpires == timerExpiresForTime) { + ClearMessage(); + } +} + +void CVMROSD::ClearMessage(bool hide) +{ + CAutoLock lock(&m_csLock); + if (m_bSeekBarVisible) { + return; + } + + if (!hide) { + m_nMessagePos = OSD_NOMESSAGE; + } + + if (m_pVMB) { + DWORD dwBackup = (m_VMR9AlphaBitmap.dwFlags | VMRBITMAP_DISABLE); + m_VMR9AlphaBitmap.dwFlags = VMRBITMAP_DISABLE; + m_pVMB->SetAlphaBitmap(&m_VMR9AlphaBitmap); + m_VMR9AlphaBitmap.dwFlags = dwBackup; + } else if (m_pMFVMB) { + m_pMFVMB->ClearAlphaBitmap(); + } else if (m_pMVTO) { + m_pMVTO->OsdClearMessage(); + } + + m_pMainFrame->RepaintVideo(); +} + +void CVMROSD::DisplayTime(LPCTSTR strTime) +{ + currentTime = strTime; + if (timerExpires < GetTickCount() || timerExpires == timerExpiresForTime) { + DisplayMessage(OSD_TOPLEFT, strTime, 1000); + timerExpiresForTime = timerExpires; + } +} + + +void CVMROSD::DisplayMessage(OSD_MESSAGEPOS nPos, LPCTSTR strMsg, int nDuration, int iFontSize, CString fontName) +{ + if (!m_bShowMessage) { + return; + } + + if (m_pVMB || m_pMFVMB) { + if (nPos != OSD_DEBUG) { + m_nMessagePos = nPos; + m_strMessage = strMsg; + } else { + m_debugMessages.AddTail(strMsg); + if (m_debugMessages.GetCount() > 20) { + m_debugMessages.RemoveHead(); + } + nDuration = -1; + } + + int iOldFontSize = m_iFontSize; + CString oldFontName = m_fontName; + const CAppSettings& s = AfxGetAppSettings(); + + if (iFontSize == 0) { + m_iFontSize = s.nOSDSize; + } else { + m_iFontSize = iFontSize; + } + if (m_iFontSize < 10 || m_iFontSize > 50) { + m_iFontSize = 20; + } + if (fontName.IsEmpty()) { + m_fontName = s.strOSDFont; + } else { + m_fontName = fontName; + } + + if (iOldFontSize != m_iFontSize || oldFontName != m_fontName) { + if (m_mainFont.GetSafeHandle()) { + m_mainFont.DeleteObject(); + } + + m_mainFont.CreatePointFont(m_iFontSize * 10, m_fontName); + m_memDC.SelectObject(m_mainFont); + } + + if (m_pWnd) { + m_pWnd->KillTimer((UINT_PTR)this); + if (nDuration != -1) { + timerExpires = GetTickCount() + nDuration; + m_pWnd->SetTimer((UINT_PTR)this, nDuration, TimerFunc); + } + } + Invalidate(); + } else if (m_pMVTO) { + m_pMVTO->OsdDisplayMessage(strMsg, nDuration); + } +} + +void CVMROSD::DebugMessage(LPCTSTR format, ...) +{ + CString msg; + va_list argList; + va_start(argList, format); + msg.FormatV(format, argList); + va_end(argList); + + DisplayMessage(OSD_DEBUG, msg); +} + +void CVMROSD::HideMessage(bool hide) +{ + if (m_pVMB || m_pMFVMB) { + if (hide) { + ClearMessage(true); + } else { + Invalidate(); + } + } +} + +void CVMROSD::EnableShowMessage(bool enabled) +{ + m_bShowMessage = enabled; +} + +bool CVMROSD::CanShowMessage() +{ + return m_bShowMessage && (m_pVMB || m_pMFVMB || m_pMVTO); +} + +void CVMROSD::EnableShowSeekBar(bool enabled) +{ + m_bShowSeekBar = enabled; +} + +void CVMROSD::SetChapterBag(IDSMChapterBag* pCB) +{ + CAutoLock lock(&m_csLock); + m_pCB = pCB; + Invalidate(); +} + +void CVMROSD::RemoveChapters() +{ + SetChapterBag(nullptr); +} diff --git a/src/mpc-hc/VMROSD.h b/src/mpc-hc/VMROSD.h index fdcdb57a361..a85015afa5a 100644 --- a/src/mpc-hc/VMROSD.h +++ b/src/mpc-hc/VMROSD.h @@ -1,144 +1,144 @@ -/* - * (C) 2006-2014, 2016 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 . - * - */ - -#pragma once - -#include -#include - - -enum OSD_COLORS { - OSD_TRANSPARENT, - OSD_BACKGROUND, - OSD_BORDER, - OSD_TEXT, - OSD_BAR, - OSD_CURSOR, - OSD_DEBUGCLR, - OSD_LAST -}; - -enum OSD_MESSAGEPOS { - OSD_NOMESSAGE, - OSD_TOPLEFT, - OSD_TOPRIGHT, - OSD_DEBUG -}; - -interface IMadVRTextOsd; -interface IDSMChapterBag; -class CMainFrame; - -class CVMROSD -{ -public: - CVMROSD(CMainFrame* pMainFrame); - ~CVMROSD(); - - void Start(CWnd* pWnd, IVMRMixerBitmap9* pVMB, bool bShowSeekBar); - void Start(CWnd* pWnd, IMFVideoMixerBitmap* pVMB, bool bShowSeekBar); - void Start(CWnd* pWnd, IMadVRTextOsd* pMVTO); - void Stop(); - - void DisplayTime(LPCTSTR strTime); - void DisplayMessage(OSD_MESSAGEPOS nPos, LPCTSTR strMsg, int nDuration = 5000, int iFontSize = 0, CString fontName = _T("")); - void DebugMessage(LPCTSTR format, ...); - void ClearTime(); - void ClearMessage(bool hide = false); - void HideMessage(bool hide); - void EnableShowMessage(bool enabled = true); - bool CanShowMessage(); - - __int64 GetPos() const; - void SetPos(__int64 pos); - void SetRange(__int64 start, __int64 stop); - void GetRange(__int64& start, __int64& stop); - - void SetSize(const CRect& wndRect, const CRect& videoRect); - bool OnMouseMove(UINT nFlags, CPoint point); - void OnMouseLeave(); - bool OnLButtonDown(UINT nFlags, CPoint point); - bool OnLButtonUp(UINT nFlags, CPoint point); - - void EnableShowSeekBar(bool enabled = true); - void SetVideoWindow(CWnd* pWnd); - - void SetChapterBag(IDSMChapterBag* pCB); - void RemoveChapters(); -private: - CComPtr m_pVMB; - CComPtr m_pMFVMB; - CComPtr m_pMVTO; - CComPtr m_pCB; - - CMainFrame* m_pMainFrame; - CWnd* m_pWnd; - - CCritSec m_csLock; - CDC m_memDC; - VMR9AlphaBitmap m_VMR9AlphaBitmap; - MFVideoAlphaBitmap m_MFVideoAlphaBitmap; - BITMAP m_bitmapInfo; - - CFont m_mainFont; - CPen m_penBorder; - CPen m_penCursor; - CBrush m_brushBack; - CBrush m_brushBar; - CBrush m_brushChapter; - CPen m_debugPenBorder; - CBrush m_debugBrushBack; - int m_iFontSize; - CString m_fontName; - - CStringW currentTime; - DWORD timerExpires, timerExpiresForTime; - - CRect m_rectWnd; - COLORREF m_colors[OSD_LAST]; - - // Seekbar - CRect m_rectSeekBar; - CRect m_rectCursor; - CRect m_rectBar; - bool m_bCursorMoving; - bool m_bShowSeekBar; - bool m_bSeekBarVisible; - __int64 m_llSeekMin; - __int64 m_llSeekMax; - __int64 m_llSeekPos; - - bool m_bShowMessage; - - // Messages - CString m_strMessage; - OSD_MESSAGEPOS m_nMessagePos; - CList m_debugMessages; - - void UpdateBitmap(); - void UpdateSeekBarPos(CPoint point); - void DrawSlider(CRect* rect, __int64 llMin, __int64 llMax, __int64 llPos); - void DrawRect(const CRect* rect, CBrush* pBrush = nullptr, CPen* pPen = nullptr); - void Invalidate(); - void DrawMessage(); - void DrawDebug(); - - static void CALLBACK TimerFunc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime); -}; +/* + * (C) 2006-2014, 2016 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 . + * + */ + +#pragma once + +#include +#include + + +enum OSD_COLORS { + OSD_TRANSPARENT, + OSD_BACKGROUND, + OSD_BORDER, + OSD_TEXT, + OSD_BAR, + OSD_CURSOR, + OSD_DEBUGCLR, + OSD_LAST +}; + +enum OSD_MESSAGEPOS { + OSD_NOMESSAGE, + OSD_TOPLEFT, + OSD_TOPRIGHT, + OSD_DEBUG +}; + +interface IMadVRTextOsd; +interface IDSMChapterBag; +class CMainFrame; + +class CVMROSD +{ +public: + CVMROSD(CMainFrame* pMainFrame); + ~CVMROSD(); + + void Start(CWnd* pWnd, IVMRMixerBitmap9* pVMB, bool bShowSeekBar); + void Start(CWnd* pWnd, IMFVideoMixerBitmap* pVMB, bool bShowSeekBar); + void Start(CWnd* pWnd, IMadVRTextOsd* pMVTO); + void Stop(); + + void DisplayTime(LPCTSTR strTime); + void DisplayMessage(OSD_MESSAGEPOS nPos, LPCTSTR strMsg, int nDuration = 5000, int iFontSize = 0, CString fontName = _T("")); + void DebugMessage(LPCTSTR format, ...); + void ClearTime(); + void ClearMessage(bool hide = false); + void HideMessage(bool hide); + void EnableShowMessage(bool enabled = true); + bool CanShowMessage(); + + __int64 GetPos() const; + void SetPos(__int64 pos); + void SetRange(__int64 start, __int64 stop); + void GetRange(__int64& start, __int64& stop); + + void SetSize(const CRect& wndRect, const CRect& videoRect); + bool OnMouseMove(UINT nFlags, CPoint point); + void OnMouseLeave(); + bool OnLButtonDown(UINT nFlags, CPoint point); + bool OnLButtonUp(UINT nFlags, CPoint point); + + void EnableShowSeekBar(bool enabled = true); + void SetVideoWindow(CWnd* pWnd); + + void SetChapterBag(IDSMChapterBag* pCB); + void RemoveChapters(); +private: + CComPtr m_pVMB; + CComPtr m_pMFVMB; + CComPtr m_pMVTO; + CComPtr m_pCB; + + CMainFrame* m_pMainFrame; + CWnd* m_pWnd; + + CCritSec m_csLock; + CDC m_memDC; + VMR9AlphaBitmap m_VMR9AlphaBitmap; + MFVideoAlphaBitmap m_MFVideoAlphaBitmap; + BITMAP m_bitmapInfo; + + CFont m_mainFont; + CPen m_penBorder; + CPen m_penCursor; + CBrush m_brushBack; + CBrush m_brushBar; + CBrush m_brushChapter; + CPen m_debugPenBorder; + CBrush m_debugBrushBack; + int m_iFontSize; + CString m_fontName; + + CStringW currentTime; + DWORD timerExpires, timerExpiresForTime; + + CRect m_rectWnd; + COLORREF m_colors[OSD_LAST]; + + // Seekbar + CRect m_rectSeekBar; + CRect m_rectCursor; + CRect m_rectBar; + bool m_bCursorMoving; + bool m_bShowSeekBar; + bool m_bSeekBarVisible; + __int64 m_llSeekMin; + __int64 m_llSeekMax; + __int64 m_llSeekPos; + + bool m_bShowMessage; + + // Messages + CString m_strMessage; + OSD_MESSAGEPOS m_nMessagePos; + CList m_debugMessages; + + void UpdateBitmap(); + void UpdateSeekBarPos(CPoint point); + void DrawSlider(CRect* rect, __int64 llMin, __int64 llMax, __int64 llPos); + void DrawRect(const CRect* rect, CBrush* pBrush = nullptr, CPen* pPen = nullptr); + void Invalidate(); + void DrawMessage(); + void DrawDebug(); + + static void CALLBACK TimerFunc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime); +}; diff --git a/src/mpc-hc/VolumeCtrl.cpp b/src/mpc-hc/VolumeCtrl.cpp index aeac5905d58..c1ba6d4f994 100644 --- a/src/mpc-hc/VolumeCtrl.cpp +++ b/src/mpc-hc/VolumeCtrl.cpp @@ -1,498 +1,498 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2016 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "VolumeCtrl.h" -#include "AppSettings.h" -#include "CMPCTheme.h" -#include "CMPCThemeUtil.h" -#include "MainFrm.h" -#undef SubclassWindow - - -// CVolumeCtrl - -IMPLEMENT_DYNAMIC(CVolumeCtrl, CSliderCtrl) -CVolumeCtrl::CVolumeCtrl(bool fSelfDrawn) - : m_fSelfDrawn(fSelfDrawn) - , m_bDrag(false) - , m_bHover(false) - , modernStyle(AfxGetAppSettings().bMPCTheme) -{ -} - -CVolumeCtrl::~CVolumeCtrl() -{ -} - -bool CVolumeCtrl::Create(CWnd* pParentWnd) -{ - DWORD tooltipStyle = AppIsThemeLoaded() ? 0 : TBS_TOOLTIPS; - if (!CSliderCtrl::Create(WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_HORZ | tooltipStyle, CRect(0, 0, 0, 0), pParentWnd, IDC_SLIDER1)) { - return false; - } - - const CAppSettings& s = AfxGetAppSettings(); - EnableToolTips(TRUE); - SetRange(0, 100); - SetPos(s.nVolume); - SetPageSize(s.nVolumeStep); - SetLineSize(0); - - if (AppIsThemeLoaded()) { - CToolTipCtrl* pTip = GetToolTips(); - if (NULL != pTip) { - themedToolTip.SubclassWindow(pTip->m_hWnd); - } - } - - return true; -} - -void CVolumeCtrl::SetPosInternal(int pos) -{ - SetPos(pos); - GetParent()->PostMessage(WM_HSCROLL, MAKEWPARAM(static_cast(pos), SB_THUMBPOSITION), reinterpret_cast(m_hWnd)); // this will be reflected back on us - POINT p; - ::GetCursorPos(&p); - ScreenToClient(&p); - checkHover(p); -} - -void CVolumeCtrl::IncreaseVolume() -{ - // align volume up to step. recommend using steps 1, 2, 5 and 10 - SetPosInternal(GetPos() + GetPageSize() - GetPos() % GetPageSize()); - -} - -void CVolumeCtrl::DecreaseVolume() -{ - // align volume down to step. recommend using steps 1, 2, 5 and 10 - int m = GetPos() % GetPageSize(); - SetPosInternal(GetPos() - (m ? m : GetPageSize())); -} - -BEGIN_MESSAGE_MAP(CVolumeCtrl, CSliderCtrl) - ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw) - ON_WM_LBUTTONDOWN() - ON_WM_SETFOCUS() - ON_WM_HSCROLL_REFLECT() - ON_WM_SETCURSOR() - ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) - ON_WM_MOUSEWHEEL() - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONUP() - ON_WM_MOUSELEAVE() - ON_WM_PAINT() - ON_WM_ERASEBKGND() -END_MESSAGE_MAP() - -// CVolumeCtrl message handlers - -void CVolumeCtrl::getCustomChannelRect(LPRECT rc) -{ - if (AppIsThemeLoaded()) { - CRect channelRect; - GetClientRect(channelRect); - CopyRect(rc, CRect(channelRect.left, channelRect.top, channelRect.right - AfxGetMainFrame()->m_dpi.ScaleFloorX(2), channelRect.bottom)); - } else { - CRect channelRect; - GetChannelRect(channelRect); - CRect thumbRect; - GetThumbRect(thumbRect); - - CopyRect(rc, CRect(channelRect.left, thumbRect.top + 2, channelRect.right - 2, thumbRect.bottom - 2)); - } -} - -void CVolumeCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) -{ - LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); - - LRESULT lr = CDRF_DODEFAULT; - - bool usetheme = AppIsThemeLoaded(); - - if (m_fSelfDrawn) - switch (pNMCD->dwDrawStage) { - case CDDS_PREPAINT: - lr = CDRF_NOTIFYITEMDRAW; - break; - - case CDDS_ITEMPREPAINT: - - if (pNMCD->dwItemSpec == TBCD_CHANNEL) { - CDC dc; - dc.Attach(pNMCD->hdc); - - if (usetheme) { - CRect rect; - GetClientRect(rect); - dc.FillSolidRect(&rect, CMPCTheme::PlayerBGColor); - } - - getCustomChannelRect(&pNMCD->rc); - - if (usetheme) { - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - CRect r(pNMCD->rc); - r.DeflateRect(0, dpiWindow.ScaleFloorY(6), 0, dpiWindow.ScaleFloorY(6)); - dc.FillSolidRect(r, CMPCTheme::ScrollBGColor); - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - } else { - CPen shadow; - CPen light; - shadow.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); - light.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT)); - CPen* old = dc.SelectObject(&light); - dc.MoveTo(pNMCD->rc.right, pNMCD->rc.top); - dc.LineTo(pNMCD->rc.right, pNMCD->rc.bottom); - dc.LineTo(pNMCD->rc.left, pNMCD->rc.bottom); - dc.SelectObject(&shadow); - dc.LineTo(pNMCD->rc.right, pNMCD->rc.top); - dc.SelectObject(old); - shadow.DeleteObject(); - light.DeleteObject(); - } - - dc.Detach(); - lr = CDRF_SKIPDEFAULT; - } else if (pNMCD->dwItemSpec == TBCD_THUMB) { - CDC dc; - dc.Attach(pNMCD->hdc); - pNMCD->rc.bottom--; - CRect r(pNMCD->rc); - r.DeflateRect(0, 0, 1, 0); - - COLORREF shadow = GetSysColor(COLOR_3DSHADOW); - COLORREF light = GetSysColor(COLOR_3DHILIGHT); - if (usetheme) { - CBrush fb; - if (m_bDrag) { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbDragColor); - } else if (m_bHover) { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbHoverColor); - } else { - dc.FillSolidRect(r, CMPCTheme::ScrollThumbColor); - } - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dc.FrameRect(r, &fb); - fb.DeleteObject(); - } else { - dc.Draw3dRect(&r, light, 0); - r.DeflateRect(0, 0, 1, 1); - dc.Draw3dRect(&r, light, shadow); - r.DeflateRect(1, 1, 1, 1); - dc.FillSolidRect(&r, GetSysColor(COLOR_BTNFACE)); - dc.SetPixel(r.left + 7, r.top - 1, GetSysColor(COLOR_BTNFACE)); - } - - dc.Detach(); - lr = CDRF_SKIPDEFAULT; - } - - break; - }; - - pNMCD->uItemState &= ~CDIS_FOCUS; - - *pResult = lr; -} - -void CVolumeCtrl::OnLButtonDown(UINT nFlags, CPoint point) -{ - CRect r; - GetChannelRect(&r); - - if (r.left >= r.right) { - return; - } - - int start, stop; - GetRange(start, stop); - - if (!(AppIsThemeLoaded() && modernStyle)) { - r.left += 3; - r.right -= 4; - } - - if (point.x < r.left) { - SetPosInternal(start); - } else if (point.x >= r.right) { - SetPosInternal(stop); - } else { - int w = r.right - r.left; - if (start < stop) { - if (!(AppIsThemeLoaded() && modernStyle)) { - SetPosInternal(start + ((stop - start) * (point.x - r.left) + (w / 2)) / w); - } else { - SetPosInternal(start + lround((stop - start) * float(point.x - r.left) / w)); - } - } - } - m_bDrag = true; - if (AppIsThemeLoaded() && modernStyle) { - if (themedToolTip.m_hWnd) { - TOOLINFO ti = { sizeof(TOOLINFO) }; - ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_ABSOLUTE; - ti.hwnd = m_hWnd; - ti.uId = (UINT_PTR)m_hWnd; - ti.hinst = AfxGetInstanceHandle(); - ti.lpszText = LPSTR_TEXTCALLBACK; - - themedToolTip.SendMessage(TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti); - } - - updateModernVolCtrl(point); - SetCapture(); - } else { - invalidateThumb(); - CSliderCtrl::OnLButtonDown(nFlags, point); - } -} - -void CVolumeCtrl::OnSetFocus(CWnd* pOldWnd) -{ - CSliderCtrl::OnSetFocus(pOldWnd); - - AfxGetMainWnd()->SetFocus(); // don't focus on us, parents will take care of our positioning -} - -void CVolumeCtrl::HScroll(UINT nSBCode, UINT nPos) -{ - auto &s = AfxGetAppSettings(); - auto oldVolume = s.nVolume; - s.nVolume = GetPos(); - - CFrameWnd* pFrame = GetParentFrame(); - if (pFrame && pFrame != GetParent()) { - pFrame->PostMessage(WM_HSCROLL, MAKEWPARAM(static_cast(nPos), static_cast(nSBCode)), reinterpret_cast(m_hWnd)); - if (s.nVolume != oldVolume) { - CRect r; - getCustomChannelRect(r); - InvalidateRect(r); //needed to redraw the volume text - } - } -} - -BOOL CVolumeCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) -{ - ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_HAND)); - return TRUE; -} - -BOOL CVolumeCtrl::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) -{ - TOOLTIPTEXT* pTTT = reinterpret_cast(pNMHDR); - CString str; - str.Format(IDS_VOLUME, GetPos()); - _tcscpy_s(pTTT->szText, str); - pTTT->hinst = nullptr; - - *pResult = 0; - - return TRUE; -} - -BOOL CVolumeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) -{ - if (zDelta > 0) { - IncreaseVolume(); - } else if (zDelta < 0) { - DecreaseVolume(); - } else { - return FALSE; - } - return TRUE; -} - -void CVolumeCtrl::invalidateThumb() -{ - if (!(AppIsThemeLoaded() && modernStyle)) { - SetRangeMax(100, TRUE); - } -} - - -void CVolumeCtrl::checkHover(CPoint point) -{ - CRect thumbRect; - GetThumbRect(thumbRect); - bool oldHover = m_bHover; - m_bHover = false; - if (thumbRect.PtInRect(point)) { - m_bHover = true; - } - - if (m_bHover != oldHover) { - invalidateThumb(); - } -} - -void CVolumeCtrl::updateModernVolCtrl(CPoint point) -{ - //CSliderCtrl::OnMouseMove yields bad results due to assumption of thumb width - //we must do all position calculation ourselves, and send correct position to tooltip - - CRect r; - GetChannelRect(&r); - - int start, stop; - GetRange(start, stop); - int useX; - if (point.x < r.left) { - SetPosInternal(start); - useX = r.left; - } else if (point.x >= r.right) { - SetPosInternal(stop); - useX = r.right; - } else { - int w = r.right - r.left; - if (start < stop) { - SetPosInternal(start + lround((stop - start) * float(point.x - r.left) / w)); - } - useX = point.x; - } - POINT p = { useX, point.y }; - ClientToScreen(&p); - CRect ttRect; - if (themedToolTip.m_hWnd) { - CRect cr = r; - ClientToScreen(cr); - themedToolTip.GetWindowRect(ttRect); - p.y = cr.top - ttRect.Height(); - themedToolTip.SendMessage(TTM_TRACKPOSITION, 0, MAKELPARAM(p.x, p.y)); - } - - RECT ur; - getCustomChannelRect(&ur); - RedrawWindow(&ur, nullptr, RDW_INVALIDATE); //we must redraw the whole channel with the modern volume ctrl. by default only areas where thumb has been are invalidated -} - - -void CVolumeCtrl::OnMouseMove(UINT nFlags, CPoint point) -{ - checkHover(point); - - if (AppIsThemeLoaded() && modernStyle && m_bDrag) { - updateModernVolCtrl(point); - } else { - CSliderCtrl::OnMouseMove(nFlags, point); - } -} - - -void CVolumeCtrl::OnLButtonUp(UINT nFlags, CPoint point) -{ - if (AppIsThemeLoaded() && modernStyle) { - if (m_bDrag) { - ReleaseCapture(); - } - m_bDrag = false; - if (themedToolTip.m_hWnd) { - themedToolTip.SendMessage(TTM_TRACKACTIVATE, FALSE, 0); - } - } else { - m_bDrag = false; - invalidateThumb(); - checkHover(point); - CSliderCtrl::OnLButtonUp(nFlags, point); - } -} - - -void CVolumeCtrl::OnMouseLeave() -{ - checkHover(CPoint(-1 - 1)); - CSliderCtrl::OnMouseLeave(); -} - - -void CVolumeCtrl::OnPaint() { - if (m_fSelfDrawn && AppIsThemeLoaded() && modernStyle) { - DpiHelper dpiWindow; - dpiWindow.Override(GetSafeHwnd()); - - CPaintDC dc(this); - CRect r, cr; - GetClientRect(cr); - - CDC dcMem; - CBitmap bmMem; - CRect memRect = { 0, 0, cr.right, cr.bottom }; - CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, memRect); - - dcMem.FillSolidRect(&memRect, CMPCTheme::PlayerBGColor); - getCustomChannelRect(r); - //r.DeflateRect(0, dpiWindow.ScaleFloorY(3), 0, dpiWindow.ScaleFloorY(2)); - r.OffsetRect(-cr.TopLeft()); - - CRect filledRect, unfilledRect; - filledRect = r; - filledRect.right = r.left + lround(r.Width() * float(GetPos()) / 100); - dcMem.FillSolidRect(&filledRect, CMPCTheme::ScrollProgressColor); - - if (filledRect.right < r.right) { //do not fill bg if already full - unfilledRect = r; - unfilledRect.left = filledRect.right; - dcMem.FillSolidRect(&unfilledRect, CMPCTheme::ScrollBGColor); - } - - CBrush fb; - fb.CreateSolidBrush(CMPCTheme::NoBorderColor); - dcMem.FrameRect(r, &fb); - fb.DeleteObject(); - - dcMem.SetTextColor(CMPCTheme::TextFGColor); - CFont f; - LOGFONT lf = { 0 }; - lf.lfHeight = r.Height(); - lf.lfQuality = CLEARTYPE_QUALITY; - wcscpy_s(lf.lfFaceName, L"Calibri"); - f.CreateFontIndirectW(&lf); - CFont* oldFont = (CFont*)dcMem.SelectObject(&f); - int oldMode = dcMem.SetBkMode(TRANSPARENT); - CStringW str; - str.Format(IDS_VOLUME, GetPos()); - dcMem.DrawTextW(str, r, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX); - dcMem.SelectObject(oldFont); - dcMem.SetBkMode(oldMode); - - CMPCThemeUtil::flushMemDC(&dc, dcMem, memRect); - } else { - __super::OnPaint(); //can trigger OnNMCustomdraw - } -} - -BOOL CVolumeCtrl::OnEraseBkgnd(CDC* pDC) { - if (m_fSelfDrawn && AppIsThemeLoaded() && modernStyle) { - return TRUE; - } else { - return CSliderCtrl::OnEraseBkgnd(pDC); - } -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2016 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "VolumeCtrl.h" +#include "AppSettings.h" +#include "CMPCTheme.h" +#include "CMPCThemeUtil.h" +#include "MainFrm.h" +#undef SubclassWindow + + +// CVolumeCtrl + +IMPLEMENT_DYNAMIC(CVolumeCtrl, CSliderCtrl) +CVolumeCtrl::CVolumeCtrl(bool fSelfDrawn) + : m_fSelfDrawn(fSelfDrawn) + , m_bDrag(false) + , m_bHover(false) + , modernStyle(AfxGetAppSettings().bMPCTheme) +{ +} + +CVolumeCtrl::~CVolumeCtrl() +{ +} + +bool CVolumeCtrl::Create(CWnd* pParentWnd) +{ + DWORD tooltipStyle = AppIsThemeLoaded() ? 0 : TBS_TOOLTIPS; + if (!CSliderCtrl::Create(WS_CHILD | WS_VISIBLE | TBS_NOTICKS | TBS_HORZ | tooltipStyle, CRect(0, 0, 0, 0), pParentWnd, IDC_SLIDER1)) { + return false; + } + + const CAppSettings& s = AfxGetAppSettings(); + EnableToolTips(TRUE); + SetRange(0, 100); + SetPos(s.nVolume); + SetPageSize(s.nVolumeStep); + SetLineSize(0); + + if (AppIsThemeLoaded()) { + CToolTipCtrl* pTip = GetToolTips(); + if (NULL != pTip) { + themedToolTip.SubclassWindow(pTip->m_hWnd); + } + } + + return true; +} + +void CVolumeCtrl::SetPosInternal(int pos) +{ + SetPos(pos); + GetParent()->PostMessage(WM_HSCROLL, MAKEWPARAM(static_cast(pos), SB_THUMBPOSITION), reinterpret_cast(m_hWnd)); // this will be reflected back on us + POINT p; + ::GetCursorPos(&p); + ScreenToClient(&p); + checkHover(p); +} + +void CVolumeCtrl::IncreaseVolume() +{ + // align volume up to step. recommend using steps 1, 2, 5 and 10 + SetPosInternal(GetPos() + GetPageSize() - GetPos() % GetPageSize()); + +} + +void CVolumeCtrl::DecreaseVolume() +{ + // align volume down to step. recommend using steps 1, 2, 5 and 10 + int m = GetPos() % GetPageSize(); + SetPosInternal(GetPos() - (m ? m : GetPageSize())); +} + +BEGIN_MESSAGE_MAP(CVolumeCtrl, CSliderCtrl) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw) + ON_WM_LBUTTONDOWN() + ON_WM_SETFOCUS() + ON_WM_HSCROLL_REFLECT() + ON_WM_SETCURSOR() + ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify) + ON_WM_MOUSEWHEEL() + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONUP() + ON_WM_MOUSELEAVE() + ON_WM_PAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +// CVolumeCtrl message handlers + +void CVolumeCtrl::getCustomChannelRect(LPRECT rc) +{ + if (AppIsThemeLoaded()) { + CRect channelRect; + GetClientRect(channelRect); + CopyRect(rc, CRect(channelRect.left, channelRect.top, channelRect.right - AfxGetMainFrame()->m_dpi.ScaleFloorX(2), channelRect.bottom)); + } else { + CRect channelRect; + GetChannelRect(channelRect); + CRect thumbRect; + GetThumbRect(thumbRect); + + CopyRect(rc, CRect(channelRect.left, thumbRect.top + 2, channelRect.right - 2, thumbRect.bottom - 2)); + } +} + +void CVolumeCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR); + + LRESULT lr = CDRF_DODEFAULT; + + bool usetheme = AppIsThemeLoaded(); + + if (m_fSelfDrawn) + switch (pNMCD->dwDrawStage) { + case CDDS_PREPAINT: + lr = CDRF_NOTIFYITEMDRAW; + break; + + case CDDS_ITEMPREPAINT: + + if (pNMCD->dwItemSpec == TBCD_CHANNEL) { + CDC dc; + dc.Attach(pNMCD->hdc); + + if (usetheme) { + CRect rect; + GetClientRect(rect); + dc.FillSolidRect(&rect, CMPCTheme::PlayerBGColor); + } + + getCustomChannelRect(&pNMCD->rc); + + if (usetheme) { + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + CRect r(pNMCD->rc); + r.DeflateRect(0, dpiWindow.ScaleFloorY(6), 0, dpiWindow.ScaleFloorY(6)); + dc.FillSolidRect(r, CMPCTheme::ScrollBGColor); + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + } else { + CPen shadow; + CPen light; + shadow.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); + light.CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT)); + CPen* old = dc.SelectObject(&light); + dc.MoveTo(pNMCD->rc.right, pNMCD->rc.top); + dc.LineTo(pNMCD->rc.right, pNMCD->rc.bottom); + dc.LineTo(pNMCD->rc.left, pNMCD->rc.bottom); + dc.SelectObject(&shadow); + dc.LineTo(pNMCD->rc.right, pNMCD->rc.top); + dc.SelectObject(old); + shadow.DeleteObject(); + light.DeleteObject(); + } + + dc.Detach(); + lr = CDRF_SKIPDEFAULT; + } else if (pNMCD->dwItemSpec == TBCD_THUMB) { + CDC dc; + dc.Attach(pNMCD->hdc); + pNMCD->rc.bottom--; + CRect r(pNMCD->rc); + r.DeflateRect(0, 0, 1, 0); + + COLORREF shadow = GetSysColor(COLOR_3DSHADOW); + COLORREF light = GetSysColor(COLOR_3DHILIGHT); + if (usetheme) { + CBrush fb; + if (m_bDrag) { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbDragColor); + } else if (m_bHover) { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbHoverColor); + } else { + dc.FillSolidRect(r, CMPCTheme::ScrollThumbColor); + } + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dc.FrameRect(r, &fb); + fb.DeleteObject(); + } else { + dc.Draw3dRect(&r, light, 0); + r.DeflateRect(0, 0, 1, 1); + dc.Draw3dRect(&r, light, shadow); + r.DeflateRect(1, 1, 1, 1); + dc.FillSolidRect(&r, GetSysColor(COLOR_BTNFACE)); + dc.SetPixel(r.left + 7, r.top - 1, GetSysColor(COLOR_BTNFACE)); + } + + dc.Detach(); + lr = CDRF_SKIPDEFAULT; + } + + break; + }; + + pNMCD->uItemState &= ~CDIS_FOCUS; + + *pResult = lr; +} + +void CVolumeCtrl::OnLButtonDown(UINT nFlags, CPoint point) +{ + CRect r; + GetChannelRect(&r); + + if (r.left >= r.right) { + return; + } + + int start, stop; + GetRange(start, stop); + + if (!(AppIsThemeLoaded() && modernStyle)) { + r.left += 3; + r.right -= 4; + } + + if (point.x < r.left) { + SetPosInternal(start); + } else if (point.x >= r.right) { + SetPosInternal(stop); + } else { + int w = r.right - r.left; + if (start < stop) { + if (!(AppIsThemeLoaded() && modernStyle)) { + SetPosInternal(start + ((stop - start) * (point.x - r.left) + (w / 2)) / w); + } else { + SetPosInternal(start + lround((stop - start) * float(point.x - r.left) / w)); + } + } + } + m_bDrag = true; + if (AppIsThemeLoaded() && modernStyle) { + if (themedToolTip.m_hWnd) { + TOOLINFO ti = { sizeof(TOOLINFO) }; + ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_ABSOLUTE; + ti.hwnd = m_hWnd; + ti.uId = (UINT_PTR)m_hWnd; + ti.hinst = AfxGetInstanceHandle(); + ti.lpszText = LPSTR_TEXTCALLBACK; + + themedToolTip.SendMessage(TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti); + } + + updateModernVolCtrl(point); + SetCapture(); + } else { + invalidateThumb(); + CSliderCtrl::OnLButtonDown(nFlags, point); + } +} + +void CVolumeCtrl::OnSetFocus(CWnd* pOldWnd) +{ + CSliderCtrl::OnSetFocus(pOldWnd); + + AfxGetMainWnd()->SetFocus(); // don't focus on us, parents will take care of our positioning +} + +void CVolumeCtrl::HScroll(UINT nSBCode, UINT nPos) +{ + auto &s = AfxGetAppSettings(); + auto oldVolume = s.nVolume; + s.nVolume = GetPos(); + + CFrameWnd* pFrame = GetParentFrame(); + if (pFrame && pFrame != GetParent()) { + pFrame->PostMessage(WM_HSCROLL, MAKEWPARAM(static_cast(nPos), static_cast(nSBCode)), reinterpret_cast(m_hWnd)); + if (s.nVolume != oldVolume) { + CRect r; + getCustomChannelRect(r); + InvalidateRect(r); //needed to redraw the volume text + } + } +} + +BOOL CVolumeCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_HAND)); + return TRUE; +} + +BOOL CVolumeCtrl::OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult) +{ + TOOLTIPTEXT* pTTT = reinterpret_cast(pNMHDR); + CString str; + str.Format(IDS_VOLUME, GetPos()); + _tcscpy_s(pTTT->szText, str); + pTTT->hinst = nullptr; + + *pResult = 0; + + return TRUE; +} + +BOOL CVolumeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint point) +{ + if (zDelta > 0) { + IncreaseVolume(); + } else if (zDelta < 0) { + DecreaseVolume(); + } else { + return FALSE; + } + return TRUE; +} + +void CVolumeCtrl::invalidateThumb() +{ + if (!(AppIsThemeLoaded() && modernStyle)) { + SetRangeMax(100, TRUE); + } +} + + +void CVolumeCtrl::checkHover(CPoint point) +{ + CRect thumbRect; + GetThumbRect(thumbRect); + bool oldHover = m_bHover; + m_bHover = false; + if (thumbRect.PtInRect(point)) { + m_bHover = true; + } + + if (m_bHover != oldHover) { + invalidateThumb(); + } +} + +void CVolumeCtrl::updateModernVolCtrl(CPoint point) +{ + //CSliderCtrl::OnMouseMove yields bad results due to assumption of thumb width + //we must do all position calculation ourselves, and send correct position to tooltip + + CRect r; + GetChannelRect(&r); + + int start, stop; + GetRange(start, stop); + int useX; + if (point.x < r.left) { + SetPosInternal(start); + useX = r.left; + } else if (point.x >= r.right) { + SetPosInternal(stop); + useX = r.right; + } else { + int w = r.right - r.left; + if (start < stop) { + SetPosInternal(start + lround((stop - start) * float(point.x - r.left) / w)); + } + useX = point.x; + } + POINT p = { useX, point.y }; + ClientToScreen(&p); + CRect ttRect; + if (themedToolTip.m_hWnd) { + CRect cr = r; + ClientToScreen(cr); + themedToolTip.GetWindowRect(ttRect); + p.y = cr.top - ttRect.Height(); + themedToolTip.SendMessage(TTM_TRACKPOSITION, 0, MAKELPARAM(p.x, p.y)); + } + + RECT ur; + getCustomChannelRect(&ur); + RedrawWindow(&ur, nullptr, RDW_INVALIDATE); //we must redraw the whole channel with the modern volume ctrl. by default only areas where thumb has been are invalidated +} + + +void CVolumeCtrl::OnMouseMove(UINT nFlags, CPoint point) +{ + checkHover(point); + + if (AppIsThemeLoaded() && modernStyle && m_bDrag) { + updateModernVolCtrl(point); + } else { + CSliderCtrl::OnMouseMove(nFlags, point); + } +} + + +void CVolumeCtrl::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (AppIsThemeLoaded() && modernStyle) { + if (m_bDrag) { + ReleaseCapture(); + } + m_bDrag = false; + if (themedToolTip.m_hWnd) { + themedToolTip.SendMessage(TTM_TRACKACTIVATE, FALSE, 0); + } + } else { + m_bDrag = false; + invalidateThumb(); + checkHover(point); + CSliderCtrl::OnLButtonUp(nFlags, point); + } +} + + +void CVolumeCtrl::OnMouseLeave() +{ + checkHover(CPoint(-1 - 1)); + CSliderCtrl::OnMouseLeave(); +} + + +void CVolumeCtrl::OnPaint() { + if (m_fSelfDrawn && AppIsThemeLoaded() && modernStyle) { + DpiHelper dpiWindow; + dpiWindow.Override(GetSafeHwnd()); + + CPaintDC dc(this); + CRect r, cr; + GetClientRect(cr); + + CDC dcMem; + CBitmap bmMem; + CRect memRect = { 0, 0, cr.right, cr.bottom }; + CMPCThemeUtil::initMemDC(&dc, dcMem, bmMem, memRect); + + dcMem.FillSolidRect(&memRect, CMPCTheme::PlayerBGColor); + getCustomChannelRect(r); + //r.DeflateRect(0, dpiWindow.ScaleFloorY(3), 0, dpiWindow.ScaleFloorY(2)); + r.OffsetRect(-cr.TopLeft()); + + CRect filledRect, unfilledRect; + filledRect = r; + filledRect.right = r.left + lround(r.Width() * float(GetPos()) / 100); + dcMem.FillSolidRect(&filledRect, CMPCTheme::ScrollProgressColor); + + if (filledRect.right < r.right) { //do not fill bg if already full + unfilledRect = r; + unfilledRect.left = filledRect.right; + dcMem.FillSolidRect(&unfilledRect, CMPCTheme::ScrollBGColor); + } + + CBrush fb; + fb.CreateSolidBrush(CMPCTheme::NoBorderColor); + dcMem.FrameRect(r, &fb); + fb.DeleteObject(); + + dcMem.SetTextColor(CMPCTheme::TextFGColor); + CFont f; + LOGFONT lf = { 0 }; + lf.lfHeight = r.Height(); + lf.lfQuality = CLEARTYPE_QUALITY; + wcscpy_s(lf.lfFaceName, L"Calibri"); + f.CreateFontIndirectW(&lf); + CFont* oldFont = (CFont*)dcMem.SelectObject(&f); + int oldMode = dcMem.SetBkMode(TRANSPARENT); + CStringW str; + str.Format(IDS_VOLUME, GetPos()); + dcMem.DrawTextW(str, r, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX); + dcMem.SelectObject(oldFont); + dcMem.SetBkMode(oldMode); + + CMPCThemeUtil::flushMemDC(&dc, dcMem, memRect); + } else { + __super::OnPaint(); //can trigger OnNMCustomdraw + } +} + +BOOL CVolumeCtrl::OnEraseBkgnd(CDC* pDC) { + if (m_fSelfDrawn && AppIsThemeLoaded() && modernStyle) { + return TRUE; + } else { + return CSliderCtrl::OnEraseBkgnd(pDC); + } +} diff --git a/src/mpc-hc/VolumeCtrl.h b/src/mpc-hc/VolumeCtrl.h index 8cb18a11f51..40b35e7e68c 100644 --- a/src/mpc-hc/VolumeCtrl.h +++ b/src/mpc-hc/VolumeCtrl.h @@ -1,66 +1,66 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2012, 2015 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 . - * - */ - -#pragma once -#include "CMPCThemeToolTipCtrl.h" - -// CVolumeCtrl - -class CVolumeCtrl : public CSliderCtrl -{ - DECLARE_DYNAMIC(CVolumeCtrl) - -private: - bool m_fSelfDrawn; - -public: - CVolumeCtrl(bool fSelfDrawn = true); - virtual ~CVolumeCtrl(); - - bool Create(CWnd* pParentWnd); - void IncreaseVolume(), DecreaseVolume(); - void SetPosInternal(int pos); - -protected: - afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); - void getCustomChannelRect(LPRECT rc); - void updateModernVolCtrl(CPoint point); - bool m_bDrag, m_bHover; - bool modernStyle; - CMPCThemeToolTipCtrl themedToolTip; - - DECLARE_MESSAGE_MAP() - -public: - afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnSetFocus(CWnd* pOldWnd); - afx_msg void HScroll(UINT nSBCode, UINT nPos); - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint point); - void invalidateThumb(); - void checkHover(CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnMouseLeave(); - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2012, 2015 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 . + * + */ + +#pragma once +#include "CMPCThemeToolTipCtrl.h" + +// CVolumeCtrl + +class CVolumeCtrl : public CSliderCtrl +{ + DECLARE_DYNAMIC(CVolumeCtrl) + +private: + bool m_fSelfDrawn; + +public: + CVolumeCtrl(bool fSelfDrawn = true); + virtual ~CVolumeCtrl(); + + bool Create(CWnd* pParentWnd); + void IncreaseVolume(), DecreaseVolume(); + void SetPosInternal(int pos); + +protected: + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + void getCustomChannelRect(LPRECT rc); + void updateModernVolCtrl(CPoint point); + bool m_bDrag, m_bHover; + bool modernStyle; + CMPCThemeToolTipCtrl themedToolTip; + + DECLARE_MESSAGE_MAP() + +public: + afx_msg BOOL OnToolTipNotify(UINT id, NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void HScroll(UINT nSBCode, UINT nPos); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint point); + void invalidateThumb(); + void checkHover(CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseLeave(); + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); +}; diff --git a/src/mpc-hc/WebClientSocket.cpp b/src/mpc-hc/WebClientSocket.cpp index 5ca0f60c495..eea682390ab 100644 --- a/src/mpc-hc/WebClientSocket.cpp +++ b/src/mpc-hc/WebClientSocket.cpp @@ -1,1018 +1,1018 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "resource.h" -#include "MainFrm.h" -#include "../Subtitles/TextFile.h" -#include "WebServer.h" -#include "WebClientSocket.h" -#include "text.h" -#include "PathUtils.h" - -#define MAX_HEADER_SIZE 512 * 1024 -#define MAX_DATA_SIZE 2 * 1024 * 1024 - -CWebClientSocket::CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame) - : m_pWebServer(pWebServer) - , m_pMainFrame(pMainFrame) - , m_buffLen(0) - , m_buffMaxLen(2048) - , m_buffLenProcessed(0) - , m_parsingState(PARSING_HEADER) - , m_dataLen(0) -{ - m_buff = DEBUG_NEW char[m_buffMaxLen]; -} - -CWebClientSocket::~CWebClientSocket() -{ - delete [] m_buff; -} - -bool CWebClientSocket::SetCookie(CStringA name, CString value, __time64_t expire, CString path, CString domain) -{ - if (name.IsEmpty()) { - return false; - } - if (value.IsEmpty()) { - m_cookie.RemoveKey(name); - return true; - } - - m_cookie[name] = value; - - m_cookieattribs[name].path = path; - m_cookieattribs[name].domain = domain; - - if (expire >= 0) { - CTime t(expire); - SYSTEMTIME st; - t.GetAsSystemTime(st); - CStringA str; - SystemTimeToHttpDate(st, str); - m_cookieattribs[name].expire = str; - } - - return true; -} - -void CWebClientSocket::Clear() -{ - m_buffLen = 0; - m_buffLenProcessed = 0; - - m_parsingState = PARSING_HEADER; - - m_dataLen = 0; - - m_hdrlines.RemoveAll(); - m_data.Empty(); - - m_cmd.Empty(); - m_path.Empty(); - m_ver.Empty(); - m_get.RemoveAll(); - m_post.RemoveAll(); - m_cookie.RemoveAll(); - m_request.RemoveAll(); -} - -void CWebClientSocket::HandleRequest() -{ - // remember new cookies - - CStringA cookie; - if (m_hdrlines.Lookup("cookie", cookie)) { - CAtlList sl; - Explode(cookie, sl, ';'); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - CAtlList sl2; - Explode(sl.GetNext(pos), sl2, '=', 2); - if (sl2.GetCount() == 2) { - m_cookie[sl2.GetHead()] = UTF8To16(sl2.GetTail()); - } else { - m_cookie[sl2.GetHead()].Empty(); - } - } - } - - // start new session - - if (!m_cookie.Lookup("MPCSESSIONID", m_sessid)) { - srand((unsigned int)time(nullptr)); - m_sessid.Format(_T("%08x"), rand() * 0x12345678); - SetCookie("MPCSESSIONID", m_sessid); - } else { - // TODO: load session - } - - CStringA reshdr, resbody; - - if (m_cmd == "GET" || m_cmd == "HEAD" || m_cmd == "POST") { - int i = m_path.Find('?'); - if (i >= 0) { - m_query = m_path.Mid(i + 1); - m_path.Truncate(i); - } - m_path = UrlDecode(m_path); - - if (!m_query.IsEmpty()) { - int j = m_query.Find('#'); - if (j >= 0) { - m_query.Truncate(j); - } - - CAtlList sl; - Explode(m_query, sl, '&'); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - CAtlList sl2; - Explode(sl.GetNext(pos), sl2, '=', 2); - if (sl2.GetCount() == 2) { - m_get[sl2.GetHead()] = UTF8To16(UrlDecode(sl2.GetTail())); - } else { - m_get[sl2.GetHead()] = _T(""); - } - } - } - - // m_request <-- m_get+m_post+m_cookie - { - CStringA key; - CString value; - POSITION pos; - pos = m_get.GetStartPosition(); - while (pos) { - m_get.GetNextAssoc(pos, key, value); - m_request[key] = value; - } - pos = m_post.GetStartPosition(); - while (pos) { - m_post.GetNextAssoc(pos, key, value); - m_request[key] = value; - } - pos = m_cookie.GetStartPosition(); - while (pos) { - m_cookie.GetNextAssoc(pos, key, value); - m_request[key] = value; - } - } - - m_pWebServer->OnRequest(this, reshdr, resbody); - } else { - reshdr = "HTTP/1.0 400 Bad Request\r\n"; - } - - if (!reshdr.IsEmpty()) { - // cookies - { - POSITION pos = m_cookie.GetStartPosition(); - while (pos) { - CStringA key; - CString value; - m_cookie.GetNextAssoc(pos, key, value); - reshdr += "Set-Cookie: " + key + "=" + TToA(value); - POSITION pos2 = m_cookieattribs.GetStartPosition(); - while (pos2) { - cookie_attribs attribs; - m_cookieattribs.GetNextAssoc(pos2, key, attribs); - if (!attribs.path.IsEmpty()) { - reshdr += "; path=" + attribs.path; - } - if (!attribs.expire.IsEmpty()) { - reshdr += "; expire=" + attribs.expire; - } - if (!attribs.domain.IsEmpty()) { - reshdr += "; domain=" + attribs.domain; - } - } - reshdr += "\r\n"; - } - } - - reshdr += - "Access-Control-Allow-Origin: *\r\n" - "Server: MPC-HC WebServer\r\n" - "Connection: close\r\n" - "\r\n"; - - Send(reshdr, reshdr.GetLength()); - - if (m_cmd != "HEAD" && reshdr.Find("HTTP/1.0 200 OK") == 0 && !resbody.IsEmpty()) { - Send(resbody, resbody.GetLength()); - } - - CStringA connection = "close"; - m_hdrlines.Lookup("connection", connection); - - Clear(); - - // TODO - // if (connection == _T("close")) - OnClose(0); - } -} - -void CWebClientSocket::ParseHeader(const char* headerEnd) -{ - char* start = m_buff, *end; - - // Parse the request type - end = strchr(start, ' '); - if (!end) { - ASSERT(false); - return; - } - m_cmd.SetString(start, int(end - start)); - m_cmd.MakeUpper(); - start = end + 1; - end = strchr(start, ' '); - if (!end) { - ASSERT(false); - return; - } - m_path.SetString(start, int(end - start)); - start = end + 1; - end = strstr(start, "\r\n"); - m_ver.SetString(start, int(end - start)); - m_ver.MakeUpper(); - - CStringA key, val; - start = end + 2; - while (start < headerEnd) { - // Parse the header fields - end = strchr(start, ':'); - key.SetString(start, int(end - start)); - start = end + 1; - end = strstr(start, "\r\n"); - val.SetString(start, int(end - start)); - start = end + 2; - - m_hdrlines[key.MakeLower()] = val; - } - - if (m_cmd == "POST") { - CStringA str; - if (m_hdrlines.Lookup("content-length", str)) { - m_dataLen = strtol(str, nullptr, 10); - } - } - m_parsingState = (m_dataLen > 0) ? PARSING_POST_DATA : PARSING_DONE; -} - -void CWebClientSocket::ParsePostData() -{ - char* start = m_buff, *end; - char* endData = m_buff + m_buffLen; - CStringA key, val; - - while (start < endData) { - end = strchr(start, '='); - if (!end) { - break; - } - key.SetString(start, int(end - start)); - start = end + 1; - end = strchr(start, '&'); - if (!end) { - end = endData; - } - val.SetString(start, int(end - start)); - start = end + 1; - - m_post[key.MakeLower()] = UTF8To16(UrlDecode(val)); - } - - m_parsingState = PARSING_DONE; -} -// - -void CWebClientSocket::OnReceive(int nErrorCode) -{ - if (nErrorCode == 0 && m_parsingState != PARSING_DONE) { - if (m_buffMaxLen - m_buffLen <= 1) { - char* buff = (char*)realloc(m_buff, 2 * m_buffMaxLen * sizeof(char)); - if (buff) { - m_buff = buff; - m_buffMaxLen *= 2; - } else { - ASSERT(0); - } - } - - int nRead = Receive(m_buff + m_buffLen, m_buffMaxLen - m_buffLen - 1); - if (nRead > 0) { - m_buffLen += nRead; - m_buff[m_buffLen] = '\0'; - - switch (m_parsingState) { - case PARSING_HEADER: { - // Search the header end - char* headerEnd = strstr(m_buff + m_buffLenProcessed, "\r\n\r\n"); - - if (headerEnd) { - ParseHeader(headerEnd); - if (m_dataLen > MAX_DATA_SIZE) { - // Refuse the connection if someone tries to send - // more than MAX_DATA_SIZE of size. - OnClose(0); - return; - } - - headerEnd += 4; - m_buffLen = std::max(int(m_buff + m_buffLen - headerEnd), 0); - if (m_buffLen > 0) { - memcpy(m_buff, headerEnd, m_buffLen + 1); - if (m_buffLen >= m_dataLen) { - ParsePostData(); - } - } - } else if (m_buffLen > MAX_HEADER_SIZE) { - // If we got more than MAX_HEADER_SIZE of data without finding - // the end of the header we close the connection. - OnClose(0); - return; - } else { - // Start next search from current end of the file - m_buffLenProcessed += nRead; - } - } - break; - case PARSING_POST_DATA: { - if (m_buffLen >= m_dataLen) { - ParsePostData(); - } - } - break; - } - - if (m_parsingState == PARSING_DONE) { - HandleRequest(); - } - } - } -} - -void CWebClientSocket::OnClose(int nErrorCode) -{ - // TODO: save session - m_pWebServer->OnClose(this); - __super::OnClose(nErrorCode); -} - -//////////////////// - -bool CWebClientSocket::OnCommand(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString arg; - if (m_request.Lookup("wm_command", arg)) { - int id = _ttol(arg); - - if (id > 0) { - if (id == ID_FILE_EXIT) { - m_pMainFrame->PostMessage(WM_COMMAND, id); - } else { - m_pMainFrame->SendMessage(WM_COMMAND, id); - } - } else { - if (arg == _T(CMD_SETPOS) && m_request.Lookup("position", arg)) { - int h, m, s, ms = 0; - TCHAR c; - if (_stscanf_s(arg, _T("%d%c%d%c%d%c%d"), &h, &c, 1, &m, &c, 1, &s, &c, 1, &ms) >= 5) { - REFERENCE_TIME rtPos = 10000i64 * (((h * 60 + m) * 60 + s) * 1000 + ms); - m_pMainFrame->SeekTo(rtPos); - for (int retries = 20; retries-- > 0; Sleep(50)) { - if (abs((int)((rtPos - m_pMainFrame->GetPos()) / 10000)) < 100) { - break; - } - } - } - } else if (arg == _T(CMD_SETPOS) && m_request.Lookup("percent", arg)) { - float percent = 0; - if (_stscanf_s(arg, _T("%f"), &percent) == 1) { - m_pMainFrame->SeekTo((REFERENCE_TIME)(percent / 100 * m_pMainFrame->GetDur())); - } - } else if (arg == _T(CMD_SETVOLUME) && m_request.Lookup("volume", arg)) { - int volume = _tcstol(arg, nullptr, 10); - m_pMainFrame->m_wndToolBar.Volume = std::min(std::max(volume, 0), 100); - m_pMainFrame->OnPlayVolume(0); - } - } - } - - CStringA ref; - if (!m_hdrlines.Lookup("referer", ref)) { - return true; - } - - hdr = - "HTTP/1.0 302 Found\r\n" - "Location: " + ref + "\r\n"; - - return true; -} - -bool CWebClientSocket::OnIndex(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CStringA wmcoptions; - - // generate page - - const CAppSettings& s = AfxGetAppSettings(); - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - CStringA str; - str.Format("%u", wc.cmd); - CStringA valueName(UTF8(wc.GetName())); - valueName.Replace("&", "&"); - wmcoptions += "\r\n"; - } - - m_pWebServer->LoadPage(IDR_HTML_INDEX, body, AToT(m_path)); - body.Replace("[wmcoptions]", wmcoptions); - - return true; -} - -bool CWebClientSocket::OnInfo(CStringA& hdr, CStringA& body, CStringA& mime) -{ - m_pWebServer->LoadPage(IDR_HTML_INFO, body, AToT(m_path)); - body.Replace("[version]", UTF8(AfxGetMyApp()->m_strVersion)); - body.Replace("[file]", UTF8(m_pMainFrame->GetFileName())); - body.Replace("[position]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); - body.Replace("[duration]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); - body.Replace("[size]", UTF8(GetSize())); - return true; -} - -bool CWebClientSocket::OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CAtlList rootdrives; - for (TCHAR drive[] = _T("A:"); drive[0] <= _T('Z'); drive[0]++) { - if (GetDriveType(drive) != DRIVE_NO_ROOT_DIR) { - rootdrives.AddTail(CStringA(drive) + '\\'); - } - } - // process GET - - CString path; - CFileStatus fs; - if (m_get.Lookup("path", path)) { - if (!PathUtils::IsURL(path) && CFileGetStatus(path, fs) && !(fs.m_attribute & CFile::directory)) { - // TODO: make a new message for just opening files, this is a bit overkill now... - - CAtlList cmdln; - - cmdln.AddTail(path); - - CString focus; - if (m_get.Lookup("focus", focus) && !focus.CompareNoCase(_T("no"))) { - cmdln.AddTail(_T("/nofocus")); - } - - int len = 0; - - POSITION pos = cmdln.GetHeadPosition(); - while (pos) { - CString& str = cmdln.GetNext(pos); - len += (str.GetLength() + 1) * sizeof(TCHAR); - } - - CAutoVectorPtr buff; - if (buff.Allocate(4 + len)) { - BYTE* p = buff; - *(DWORD*)p = (DWORD)cmdln.GetCount(); - p += sizeof(DWORD); - - pos = cmdln.GetHeadPosition(); - while (pos) { - CString& str = cmdln.GetNext(pos); - len = (str.GetLength() + 1) * sizeof(TCHAR); - memcpy(p, (LPCTSTR)str, len); - p += len; - } - - COPYDATASTRUCT cds; - cds.dwData = 0x6ABE51; - cds.cbData = DWORD(p - buff); - cds.lpData = (void*)(BYTE*)buff; - m_pMainFrame->SendMessage(WM_COPYDATA, (WPARAM)nullptr, (LPARAM)&cds); - } - - CPath p(path); - p.RemoveFileSpec(); - path = (LPCTSTR)p; - } - } else { - path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); - - if (!PathUtils::IsURL(path) && CFileGetStatus(path, fs) && !(fs.m_attribute & CFile::directory)) { - CPath p(path); - p.RemoveFileSpec(); - path = (LPCTSTR)p; - } - } - - if (PathUtils::IsURL(path)) { - path.Empty(); - } - - if (!path.IsEmpty() && CFileGetStatus(path, fs) && (fs.m_attribute & CFile::directory) - || path.Find(_T("\\")) == 0) { // FIXME - CPath p(path); - p.Canonicalize(); - p.MakePretty(); - p.AddBackslash(); - path = (LPCTSTR)p; - } - - CStringA files; - - if (path.IsEmpty()) { - POSITION pos = rootdrives.GetHeadPosition(); - while (pos) { - CStringA& drive = rootdrives.GetNext(pos); - - files += "\r\n"; - files += - "" + drive + "\r\n" - "Directory\r\n" - " \r\n" - " \r\n"; - files += "\r\n"; - } - - path = _T("Root"); - } else { - CString parent; - - if (path.GetLength() > 3) { - CPath p(path + ".."); - p.Canonicalize(); - p.AddBackslash(); - parent = (LPCTSTR)p; - } - - files += "\r\n"; - files += - "..\r\n" - "Directory\r\n" - " \r\n" - " \r\n"; - files += "\r\n"; - - WIN32_FIND_DATA fd; - ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); - - HANDLE hFind = FindFirstFile(path + "*.*", &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || fd.cFileName[0] == '.') { - continue; - } - - CString fullpath = path + fd.cFileName; - - files += "\r\n"; - files += - "" + UTF8(fd.cFileName) + "\r\n" - "Directory\r\n" - " \r\n" - "" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "\r\n"; - files += "\r\n"; - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - - hFind = FindFirstFile(path + "*.*", &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - continue; - } - - CString fullpath = path + fd.cFileName; - TCHAR* ext = _tcsrchr(fd.cFileName, '.'); - if (ext != nullptr) { - ext++; - } - - CStringA size; - size.Format("%I64uK", ((UINT64)fd.nFileSizeHigh << 22) | (fd.nFileSizeLow >> 10)); - - CString type(_T(" ")); - LoadType(fullpath, type); - - if (ext != nullptr) { - files += "\r\n"; - } else { - files += "\r\n"; - } - files += - "" + UTF8(fd.cFileName) + "\r\n" - "" + UTF8(type) + "\r\n" - "" + size + "\r\n" - "" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "\r\n"; - files += "\r\n"; - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } - } - - m_pWebServer->LoadPage(IDR_HTML_BROWSER, body, AToT(m_path)); - body.Replace("[currentdir]", HtmlSpecialChars(UTF8(path))); - body.Replace("[currentfiles]", files); - - return true; -} - -bool CWebClientSocket::OnControls(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); - CString dir; - - if (!path.IsEmpty() && !PathUtils::IsURL(path)) { - CPath p(path); - p.RemoveFileSpec(); - dir = (LPCTSTR)p; - } - - OAFilterState fs = m_pMainFrame->GetMediaState(); - CString state; - state.Format(_T("%d"), fs); - CString statestring; - switch (fs) { - case State_Stopped: - statestring.LoadString(IDS_CONTROLS_STOPPED); - break; - case State_Paused: - statestring.LoadString(IDS_CONTROLS_PAUSED); - break; - case State_Running: - statestring.LoadString(IDS_CONTROLS_PLAYING); - break; - default: - statestring = _T("N/A"); - break; - } - - CString volumelevel, muted; - volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos()); - muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0); - - CString reloadtime(_T("0")); // TODO - - m_pWebServer->LoadPage(IDR_HTML_CONTROLS, body, AToT(m_path)); - body.Replace("[filepatharg]", UTF8Arg(path)); - body.Replace("[filepath]", UTF8(path)); - body.Replace("[filedirarg]", UTF8Arg(dir)); - body.Replace("[filedir]", UTF8(dir)); - body.Replace("[state]", UTF8(state)); - body.Replace("[statestring]", UTF8(statestring)); - body.Replace("[position]", UTF8(NumToCString(std::lround(m_pMainFrame->GetPos() / 10000i64)))); - body.Replace("[positionstring]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); - body.Replace("[duration]", UTF8(NumToCString(std::lround(m_pMainFrame->GetDur() / 10000i64)))); - body.Replace("[durationstring]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); - body.Replace("[volumelevel]", UTF8(volumelevel)); - body.Replace("[muted]", UTF8(muted)); - body.Replace("[playbackrate]", UTF8(NumToCString(m_pMainFrame->GetPlayingRate()))); - body.Replace("[reloadtime]", UTF8(reloadtime)); - - return true; -} - -bool CWebClientSocket::OnVariables(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); - CString dir; - CString strName; - - if (!path.IsEmpty() && !PathUtils::IsURL(path)) { - CPath p(path); - p.RemoveFileSpec(); - dir = (LPCTSTR)p; - } - - OAFilterState fs = m_pMainFrame->GetMediaState(); - CString state; - state.Format(_T("%d"), fs); - CString statestring; - switch (fs) { - case State_Stopped: - statestring.LoadString(IDS_CONTROLS_STOPPED); - break; - case State_Paused: - statestring.LoadString(IDS_CONTROLS_PAUSED); - break; - case State_Running: - statestring.LoadString(IDS_CONTROLS_PLAYING); - break; - default: - statestring = _T("N/A"); - break; - } - - CString volumelevel, muted; - volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos()); - muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0); - - CString reloadtime(_T("0")); // TODO - - m_pWebServer->LoadPage(IDR_HTML_VARIABLES, body, AToT(m_path)); - body.Replace("[file]", UTF8(m_pMainFrame->GetFileName())); - body.Replace("[filepatharg]", UTF8Arg(path)); - body.Replace("[filepath]", UTF8(path)); - body.Replace("[filedirarg]", UTF8Arg(dir)); - body.Replace("[filedir]", UTF8(dir)); - body.Replace("[state]", UTF8(state)); - body.Replace("[statestring]", UTF8(statestring)); - body.Replace("[position]", UTF8(NumToCString(std::lround(m_pMainFrame->GetPos() / 10000i64)))); - body.Replace("[positionstring]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); - body.Replace("[duration]", UTF8(NumToCString(std::lround(m_pMainFrame->GetDur() / 10000i64)))); - body.Replace("[durationstring]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); - body.Replace("[volumelevel]", UTF8(volumelevel)); - body.Replace("[muted]", UTF8(muted)); - body.Replace("[playbackrate]", UTF8(NumToCString(m_pMainFrame->GetPlayingRate()))); - body.Replace("[size]", UTF8(GetSize())); - body.Replace("[reloadtime]", UTF8(reloadtime)); - body.Replace("[version]", UTF8(AfxGetMyApp()->m_strVersion)); - m_pMainFrame->GetCurrentAudioTrackIdx(&strName); - body.Replace("[audiotrack]", UTF8(strName)); - m_pMainFrame->GetCurrentSubtitleTrackIdx(&strName); - body.Replace("[subtitletrack]", UTF8(strName)); - - return true; -} - -bool CWebClientSocket::OnStatus(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString title; - m_pMainFrame->GetWindowText(title); - - CPath file(m_pMainFrame->m_wndPlaylistBar.GetCurFileName()); - - CString status; - OAFilterState fs = m_pMainFrame->GetMediaState(); - switch (fs) { - case State_Stopped: - status.LoadString(IDS_CONTROLS_STOPPED); - break; - case State_Paused: - status.LoadString(IDS_CONTROLS_PAUSED); - break; - case State_Running: - status.LoadString(IDS_CONTROLS_PLAYING); - break; - default: - status = _T("N/A"); - break; - } - - REFERENCE_TIME pos = m_pMainFrame->GetPos(); - REFERENCE_TIME dur = m_pMainFrame->GetDur(); - - title.Replace(_T("'"), _T("\\'")); - status.Replace(_T("'"), _T("\\'")); - - body.Format("OnStatus(\"%s\", \"%s\", %ld, \"%s\", %ld, \"%s\", %d, %d, \"%s\")", // , \"%s\" - UTF8(title).GetString(), UTF8(status).GetString(), - std::lround(pos / 10000i64), UTF8(ReftimeToString2(pos)).GetString(), - std::lround(dur / 10000i64), UTF8(ReftimeToString2(dur)).GetString(), - m_pMainFrame->IsMuted(), m_pMainFrame->GetVolume(), - UTF8(file).GetString()/*, UTF8(dir)*/); - - return true; -} - -bool CWebClientSocket::OnError404(CStringA& hdr, CStringA& body, CStringA& mime) -{ - m_pWebServer->LoadPage(IDR_HTML_404, body, AToT(m_path)); - return true; -} - -bool CWebClientSocket::OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime) -{ - m_pWebServer->LoadPage(IDR_HTML_PLAYER, body, AToT(m_path)); - if (AfxGetAppSettings().bWebUIEnablePreview) { - body.Replace("[preview]", - "\"snapshot\""); - } else { - body.Replace("[preview]", UTF8(StrRes(IDS_WEBUI_DISABLED_PREVIEW_MSG))); - } - return true; -} - -bool CWebClientSocket::OnSnapshotJpeg(CStringA& hdr, CStringA& body, CStringA& mime) -{ - // TODO: add quality control and return logo when nothing is loaded - - bool bRet = false; - - BYTE* pData = nullptr; - long size = 0; - if (!AfxGetAppSettings().bWebUIEnablePreview) { - hdr = "HTTP/1.0 403 Forbidden\r\n"; - bRet = true; - } else if (m_pMainFrame->GetDIB(&pData, size, true)) { - PBITMAPINFO bi = reinterpret_cast(pData); - PBITMAPINFOHEADER bih = &bi->bmiHeader; - - int bpp = bih->biBitCount; - if (bpp != 16 && bpp != 24 && bpp != 32) { - return false; - } - int w = bih->biWidth; - int h = abs(bih->biHeight); - BYTE* p = DEBUG_NEW BYTE[w * h * 4]; - - const BYTE* src = pData + sizeof(*bih); - - int srcpitch = w * (bpp >> 3); - int dstpitch = w * 4; - - BitBltFromRGBToRGB(w, h, p, dstpitch, 32, (BYTE*)src + srcpitch * (h - 1), -srcpitch, bpp); - - { - CBitmap bmp; - bmp.CreateBitmap(w, h, bih->biPlanes, bpp, p); - delete [] p; - - CImage img; - img.Attach(bmp); - IStream* pStream = nullptr; - CByteArray ba; - if (SUCCEEDED(CreateStreamOnHGlobal(nullptr, TRUE, &pStream))) { - if (SUCCEEDED(img.Save(pStream, Gdiplus::ImageFormatJPEG))) { - ULARGE_INTEGER ulnSize; - LARGE_INTEGER lnOffset; - lnOffset.QuadPart = 0; - if (SUCCEEDED(pStream->Seek(lnOffset, STREAM_SEEK_END, &ulnSize))) { - if (SUCCEEDED(pStream->Seek(lnOffset, STREAM_SEEK_SET, 0))) { - ULONG ulBytesRead; - ba.SetSize((INT_PTR)ulnSize.QuadPart); - pStream->Read(ba.GetData(), (ULONG)ulnSize.QuadPart, &ulBytesRead); - } - } - } - } - - pStream->Release(); - delete [] pData; - - hdr += - "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" - "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" - "Pragma: no-cache\r\n"; - body = CStringA((char*)ba.GetData(), (int)ba.GetCount()); - mime = "image/jpeg"; - bRet = true; - } - } - - return bRet; -} - -bool CWebClientSocket::OnViewRes(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString id; - if (!m_get.Lookup("id", id)) { - return false; - } - - uintptr_t key = 0; - if (1 != _stscanf_s(id, _T("%Ix"), &key) || key == 0) { - return false; - } - - CAutoLock cAutoLock(&CDSMResource::m_csResources); - - CDSMResource* res = nullptr; - if (!CDSMResource::m_resources.Lookup(key, res) || !res) { - return false; - } - - body = CStringA((const char*)res->data.GetData(), (int)res->data.GetCount()); - mime = res->mime; - - return true; -} - -static CStringA GetChannelsJSON(const std::vector& channels) -{ - // begin the JSON object with the "channels" array inside - CStringA jsonChannels = "{ \"channels\" : ["; - - for (auto it = channels.begin(); it != channels.end();) { - // fill the array with individual channel objects - jsonChannels += it->ToJSON(); - if (++it == channels.end()) { - break; - } - jsonChannels += ","; - } - - // terminate the array and the object, and return. - jsonChannels += "] }"; - return jsonChannels; -} - -bool CWebClientSocket::OnDVBChannels(CStringA& hdr, CStringA& body, CStringA& mime) -{ - if (m_pMainFrame->GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - mime = "application/json"; - body = GetChannelsJSON(AfxGetAppSettings().m_DVBChannels); - } else { - // if we're not currently running the capture, report the service as - // unavailable and return. - hdr = "HTTP/1.0 503 Service Unavailable\r\n"; - } - - // the request is always "handled", successfully or not. - return true; -} - -bool CWebClientSocket::OnDVBSetChannel(CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString requestParam; - int channelIdx; - if (m_pMainFrame->GetPlaybackMode() == PM_DIGITAL_CAPTURE) { - // the 'idx' GET parameter should contain a valid integer of the - // channel to switch to. - if (m_get.Lookup("idx", requestParam) - && _stscanf_s(requestParam, _T("%d"), &channelIdx) == 1 - && channelIdx >= 0) { - if (AfxGetAppSettings().FindChannelByPref(channelIdx)) { - m_pMainFrame->SendMessage(WM_COMMAND, channelIdx + ID_NAVIGATE_JUMPTO_SUBITEM_START); - } else { - // Return a 404 if requested channel number was not found. - hdr = "HTTP/1.0 404 Not Found\r\n"; - } - } else { - // invalid parameters. - hdr = "HTTP/1.0 400 Bad Request\r\n"; - } - } else { - // not running the capture - don't report channels. - hdr = "HTTP/1.0 503 Service Unavailable\r\n"; - } - return true; -} - -CString CWebClientSocket::GetSize() const -{ - CString sizeString; - LONGLONG size = 0; - - if (CComQIPtr pBF = m_pMainFrame->m_pFSF) { - BeginEnumPins(pBF, pEP, pPin) { - if (CComQIPtr pAR = pPin) { - LONGLONG total, available; - if (SUCCEEDED(pAR->Length(&total, &available))) { - size = total; - break; - } - } - } - EndEnumPins; - } - - if (size == 0) { - WIN32_FIND_DATA wfd; - HANDLE hFind = FindFirstFile(m_pMainFrame->m_wndPlaylistBar.GetCurFileName(), &wfd); - if (hFind != INVALID_HANDLE_VALUE) { - FindClose(hFind); - size = (LONGLONG(wfd.nFileSizeHigh) << 32) | wfd.nFileSizeLow; - } - } - - const int MAX_FILE_SIZE_BUFFER = 65; - TCHAR szFileSize[MAX_FILE_SIZE_BUFFER]; - StrFormatByteSizeW(size, szFileSize, MAX_FILE_SIZE_BUFFER); - sizeString.Format(L"%s", szFileSize); - - return sizeString; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "resource.h" +#include "MainFrm.h" +#include "../Subtitles/TextFile.h" +#include "WebServer.h" +#include "WebClientSocket.h" +#include "text.h" +#include "PathUtils.h" + +#define MAX_HEADER_SIZE 512 * 1024 +#define MAX_DATA_SIZE 2 * 1024 * 1024 + +CWebClientSocket::CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame) + : m_pWebServer(pWebServer) + , m_pMainFrame(pMainFrame) + , m_buffLen(0) + , m_buffMaxLen(2048) + , m_buffLenProcessed(0) + , m_parsingState(PARSING_HEADER) + , m_dataLen(0) +{ + m_buff = DEBUG_NEW char[m_buffMaxLen]; +} + +CWebClientSocket::~CWebClientSocket() +{ + delete [] m_buff; +} + +bool CWebClientSocket::SetCookie(CStringA name, CString value, __time64_t expire, CString path, CString domain) +{ + if (name.IsEmpty()) { + return false; + } + if (value.IsEmpty()) { + m_cookie.RemoveKey(name); + return true; + } + + m_cookie[name] = value; + + m_cookieattribs[name].path = path; + m_cookieattribs[name].domain = domain; + + if (expire >= 0) { + CTime t(expire); + SYSTEMTIME st; + t.GetAsSystemTime(st); + CStringA str; + SystemTimeToHttpDate(st, str); + m_cookieattribs[name].expire = str; + } + + return true; +} + +void CWebClientSocket::Clear() +{ + m_buffLen = 0; + m_buffLenProcessed = 0; + + m_parsingState = PARSING_HEADER; + + m_dataLen = 0; + + m_hdrlines.RemoveAll(); + m_data.Empty(); + + m_cmd.Empty(); + m_path.Empty(); + m_ver.Empty(); + m_get.RemoveAll(); + m_post.RemoveAll(); + m_cookie.RemoveAll(); + m_request.RemoveAll(); +} + +void CWebClientSocket::HandleRequest() +{ + // remember new cookies + + CStringA cookie; + if (m_hdrlines.Lookup("cookie", cookie)) { + CAtlList sl; + Explode(cookie, sl, ';'); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + CAtlList sl2; + Explode(sl.GetNext(pos), sl2, '=', 2); + if (sl2.GetCount() == 2) { + m_cookie[sl2.GetHead()] = UTF8To16(sl2.GetTail()); + } else { + m_cookie[sl2.GetHead()].Empty(); + } + } + } + + // start new session + + if (!m_cookie.Lookup("MPCSESSIONID", m_sessid)) { + srand((unsigned int)time(nullptr)); + m_sessid.Format(_T("%08x"), rand() * 0x12345678); + SetCookie("MPCSESSIONID", m_sessid); + } else { + // TODO: load session + } + + CStringA reshdr, resbody; + + if (m_cmd == "GET" || m_cmd == "HEAD" || m_cmd == "POST") { + int i = m_path.Find('?'); + if (i >= 0) { + m_query = m_path.Mid(i + 1); + m_path.Truncate(i); + } + m_path = UrlDecode(m_path); + + if (!m_query.IsEmpty()) { + int j = m_query.Find('#'); + if (j >= 0) { + m_query.Truncate(j); + } + + CAtlList sl; + Explode(m_query, sl, '&'); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + CAtlList sl2; + Explode(sl.GetNext(pos), sl2, '=', 2); + if (sl2.GetCount() == 2) { + m_get[sl2.GetHead()] = UTF8To16(UrlDecode(sl2.GetTail())); + } else { + m_get[sl2.GetHead()] = _T(""); + } + } + } + + // m_request <-- m_get+m_post+m_cookie + { + CStringA key; + CString value; + POSITION pos; + pos = m_get.GetStartPosition(); + while (pos) { + m_get.GetNextAssoc(pos, key, value); + m_request[key] = value; + } + pos = m_post.GetStartPosition(); + while (pos) { + m_post.GetNextAssoc(pos, key, value); + m_request[key] = value; + } + pos = m_cookie.GetStartPosition(); + while (pos) { + m_cookie.GetNextAssoc(pos, key, value); + m_request[key] = value; + } + } + + m_pWebServer->OnRequest(this, reshdr, resbody); + } else { + reshdr = "HTTP/1.0 400 Bad Request\r\n"; + } + + if (!reshdr.IsEmpty()) { + // cookies + { + POSITION pos = m_cookie.GetStartPosition(); + while (pos) { + CStringA key; + CString value; + m_cookie.GetNextAssoc(pos, key, value); + reshdr += "Set-Cookie: " + key + "=" + TToA(value); + POSITION pos2 = m_cookieattribs.GetStartPosition(); + while (pos2) { + cookie_attribs attribs; + m_cookieattribs.GetNextAssoc(pos2, key, attribs); + if (!attribs.path.IsEmpty()) { + reshdr += "; path=" + attribs.path; + } + if (!attribs.expire.IsEmpty()) { + reshdr += "; expire=" + attribs.expire; + } + if (!attribs.domain.IsEmpty()) { + reshdr += "; domain=" + attribs.domain; + } + } + reshdr += "\r\n"; + } + } + + reshdr += + "Access-Control-Allow-Origin: *\r\n" + "Server: MPC-HC WebServer\r\n" + "Connection: close\r\n" + "\r\n"; + + Send(reshdr, reshdr.GetLength()); + + if (m_cmd != "HEAD" && reshdr.Find("HTTP/1.0 200 OK") == 0 && !resbody.IsEmpty()) { + Send(resbody, resbody.GetLength()); + } + + CStringA connection = "close"; + m_hdrlines.Lookup("connection", connection); + + Clear(); + + // TODO + // if (connection == _T("close")) + OnClose(0); + } +} + +void CWebClientSocket::ParseHeader(const char* headerEnd) +{ + char* start = m_buff, *end; + + // Parse the request type + end = strchr(start, ' '); + if (!end) { + ASSERT(false); + return; + } + m_cmd.SetString(start, int(end - start)); + m_cmd.MakeUpper(); + start = end + 1; + end = strchr(start, ' '); + if (!end) { + ASSERT(false); + return; + } + m_path.SetString(start, int(end - start)); + start = end + 1; + end = strstr(start, "\r\n"); + m_ver.SetString(start, int(end - start)); + m_ver.MakeUpper(); + + CStringA key, val; + start = end + 2; + while (start < headerEnd) { + // Parse the header fields + end = strchr(start, ':'); + key.SetString(start, int(end - start)); + start = end + 1; + end = strstr(start, "\r\n"); + val.SetString(start, int(end - start)); + start = end + 2; + + m_hdrlines[key.MakeLower()] = val; + } + + if (m_cmd == "POST") { + CStringA str; + if (m_hdrlines.Lookup("content-length", str)) { + m_dataLen = strtol(str, nullptr, 10); + } + } + m_parsingState = (m_dataLen > 0) ? PARSING_POST_DATA : PARSING_DONE; +} + +void CWebClientSocket::ParsePostData() +{ + char* start = m_buff, *end; + char* endData = m_buff + m_buffLen; + CStringA key, val; + + while (start < endData) { + end = strchr(start, '='); + if (!end) { + break; + } + key.SetString(start, int(end - start)); + start = end + 1; + end = strchr(start, '&'); + if (!end) { + end = endData; + } + val.SetString(start, int(end - start)); + start = end + 1; + + m_post[key.MakeLower()] = UTF8To16(UrlDecode(val)); + } + + m_parsingState = PARSING_DONE; +} +// + +void CWebClientSocket::OnReceive(int nErrorCode) +{ + if (nErrorCode == 0 && m_parsingState != PARSING_DONE) { + if (m_buffMaxLen - m_buffLen <= 1) { + char* buff = (char*)realloc(m_buff, 2 * m_buffMaxLen * sizeof(char)); + if (buff) { + m_buff = buff; + m_buffMaxLen *= 2; + } else { + ASSERT(0); + } + } + + int nRead = Receive(m_buff + m_buffLen, m_buffMaxLen - m_buffLen - 1); + if (nRead > 0) { + m_buffLen += nRead; + m_buff[m_buffLen] = '\0'; + + switch (m_parsingState) { + case PARSING_HEADER: { + // Search the header end + char* headerEnd = strstr(m_buff + m_buffLenProcessed, "\r\n\r\n"); + + if (headerEnd) { + ParseHeader(headerEnd); + if (m_dataLen > MAX_DATA_SIZE) { + // Refuse the connection if someone tries to send + // more than MAX_DATA_SIZE of size. + OnClose(0); + return; + } + + headerEnd += 4; + m_buffLen = std::max(int(m_buff + m_buffLen - headerEnd), 0); + if (m_buffLen > 0) { + memcpy(m_buff, headerEnd, m_buffLen + 1); + if (m_buffLen >= m_dataLen) { + ParsePostData(); + } + } + } else if (m_buffLen > MAX_HEADER_SIZE) { + // If we got more than MAX_HEADER_SIZE of data without finding + // the end of the header we close the connection. + OnClose(0); + return; + } else { + // Start next search from current end of the file + m_buffLenProcessed += nRead; + } + } + break; + case PARSING_POST_DATA: { + if (m_buffLen >= m_dataLen) { + ParsePostData(); + } + } + break; + } + + if (m_parsingState == PARSING_DONE) { + HandleRequest(); + } + } + } +} + +void CWebClientSocket::OnClose(int nErrorCode) +{ + // TODO: save session + m_pWebServer->OnClose(this); + __super::OnClose(nErrorCode); +} + +//////////////////// + +bool CWebClientSocket::OnCommand(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString arg; + if (m_request.Lookup("wm_command", arg)) { + int id = _ttol(arg); + + if (id > 0) { + if (id == ID_FILE_EXIT) { + m_pMainFrame->PostMessage(WM_COMMAND, id); + } else { + m_pMainFrame->SendMessage(WM_COMMAND, id); + } + } else { + if (arg == _T(CMD_SETPOS) && m_request.Lookup("position", arg)) { + int h, m, s, ms = 0; + TCHAR c; + if (_stscanf_s(arg, _T("%d%c%d%c%d%c%d"), &h, &c, 1, &m, &c, 1, &s, &c, 1, &ms) >= 5) { + REFERENCE_TIME rtPos = 10000i64 * (((h * 60 + m) * 60 + s) * 1000 + ms); + m_pMainFrame->SeekTo(rtPos); + for (int retries = 20; retries-- > 0; Sleep(50)) { + if (abs((int)((rtPos - m_pMainFrame->GetPos()) / 10000)) < 100) { + break; + } + } + } + } else if (arg == _T(CMD_SETPOS) && m_request.Lookup("percent", arg)) { + float percent = 0; + if (_stscanf_s(arg, _T("%f"), &percent) == 1) { + m_pMainFrame->SeekTo((REFERENCE_TIME)(percent / 100 * m_pMainFrame->GetDur())); + } + } else if (arg == _T(CMD_SETVOLUME) && m_request.Lookup("volume", arg)) { + int volume = _tcstol(arg, nullptr, 10); + m_pMainFrame->m_wndToolBar.Volume = std::min(std::max(volume, 0), 100); + m_pMainFrame->OnPlayVolume(0); + } + } + } + + CStringA ref; + if (!m_hdrlines.Lookup("referer", ref)) { + return true; + } + + hdr = + "HTTP/1.0 302 Found\r\n" + "Location: " + ref + "\r\n"; + + return true; +} + +bool CWebClientSocket::OnIndex(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CStringA wmcoptions; + + // generate page + + const CAppSettings& s = AfxGetAppSettings(); + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + CStringA str; + str.Format("%u", wc.cmd); + CStringA valueName(UTF8(wc.GetName())); + valueName.Replace("&", "&"); + wmcoptions += "\r\n"; + } + + m_pWebServer->LoadPage(IDR_HTML_INDEX, body, AToT(m_path)); + body.Replace("[wmcoptions]", wmcoptions); + + return true; +} + +bool CWebClientSocket::OnInfo(CStringA& hdr, CStringA& body, CStringA& mime) +{ + m_pWebServer->LoadPage(IDR_HTML_INFO, body, AToT(m_path)); + body.Replace("[version]", UTF8(AfxGetMyApp()->m_strVersion)); + body.Replace("[file]", UTF8(m_pMainFrame->GetFileName())); + body.Replace("[position]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); + body.Replace("[duration]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); + body.Replace("[size]", UTF8(GetSize())); + return true; +} + +bool CWebClientSocket::OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CAtlList rootdrives; + for (TCHAR drive[] = _T("A:"); drive[0] <= _T('Z'); drive[0]++) { + if (GetDriveType(drive) != DRIVE_NO_ROOT_DIR) { + rootdrives.AddTail(CStringA(drive) + '\\'); + } + } + // process GET + + CString path; + CFileStatus fs; + if (m_get.Lookup("path", path)) { + if (!PathUtils::IsURL(path) && CFileGetStatus(path, fs) && !(fs.m_attribute & CFile::directory)) { + // TODO: make a new message for just opening files, this is a bit overkill now... + + CAtlList cmdln; + + cmdln.AddTail(path); + + CString focus; + if (m_get.Lookup("focus", focus) && !focus.CompareNoCase(_T("no"))) { + cmdln.AddTail(_T("/nofocus")); + } + + int len = 0; + + POSITION pos = cmdln.GetHeadPosition(); + while (pos) { + CString& str = cmdln.GetNext(pos); + len += (str.GetLength() + 1) * sizeof(TCHAR); + } + + CAutoVectorPtr buff; + if (buff.Allocate(4 + len)) { + BYTE* p = buff; + *(DWORD*)p = (DWORD)cmdln.GetCount(); + p += sizeof(DWORD); + + pos = cmdln.GetHeadPosition(); + while (pos) { + CString& str = cmdln.GetNext(pos); + len = (str.GetLength() + 1) * sizeof(TCHAR); + memcpy(p, (LPCTSTR)str, len); + p += len; + } + + COPYDATASTRUCT cds; + cds.dwData = 0x6ABE51; + cds.cbData = DWORD(p - buff); + cds.lpData = (void*)(BYTE*)buff; + m_pMainFrame->SendMessage(WM_COPYDATA, (WPARAM)nullptr, (LPARAM)&cds); + } + + CPath p(path); + p.RemoveFileSpec(); + path = (LPCTSTR)p; + } + } else { + path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); + + if (!PathUtils::IsURL(path) && CFileGetStatus(path, fs) && !(fs.m_attribute & CFile::directory)) { + CPath p(path); + p.RemoveFileSpec(); + path = (LPCTSTR)p; + } + } + + if (PathUtils::IsURL(path)) { + path.Empty(); + } + + if (!path.IsEmpty() && CFileGetStatus(path, fs) && (fs.m_attribute & CFile::directory) + || path.Find(_T("\\")) == 0) { // FIXME + CPath p(path); + p.Canonicalize(); + p.MakePretty(); + p.AddBackslash(); + path = (LPCTSTR)p; + } + + CStringA files; + + if (path.IsEmpty()) { + POSITION pos = rootdrives.GetHeadPosition(); + while (pos) { + CStringA& drive = rootdrives.GetNext(pos); + + files += "\r\n"; + files += + "" + drive + "\r\n" + "Directory\r\n" + " \r\n" + " \r\n"; + files += "\r\n"; + } + + path = _T("Root"); + } else { + CString parent; + + if (path.GetLength() > 3) { + CPath p(path + ".."); + p.Canonicalize(); + p.AddBackslash(); + parent = (LPCTSTR)p; + } + + files += "\r\n"; + files += + "..\r\n" + "Directory\r\n" + " \r\n" + " \r\n"; + files += "\r\n"; + + WIN32_FIND_DATA fd; + ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); + + HANDLE hFind = FindFirstFile(path + "*.*", &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || fd.cFileName[0] == '.') { + continue; + } + + CString fullpath = path + fd.cFileName; + + files += "\r\n"; + files += + "" + UTF8(fd.cFileName) + "\r\n" + "Directory\r\n" + " \r\n" + "" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "\r\n"; + files += "\r\n"; + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + + hFind = FindFirstFile(path + "*.*", &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + continue; + } + + CString fullpath = path + fd.cFileName; + TCHAR* ext = _tcsrchr(fd.cFileName, '.'); + if (ext != nullptr) { + ext++; + } + + CStringA size; + size.Format("%I64uK", ((UINT64)fd.nFileSizeHigh << 22) | (fd.nFileSizeLow >> 10)); + + CString type(_T(" ")); + LoadType(fullpath, type); + + if (ext != nullptr) { + files += "\r\n"; + } else { + files += "\r\n"; + } + files += + "" + UTF8(fd.cFileName) + "\r\n" + "" + UTF8(type) + "\r\n" + "" + size + "\r\n" + "" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "\r\n"; + files += "\r\n"; + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } + } + + m_pWebServer->LoadPage(IDR_HTML_BROWSER, body, AToT(m_path)); + body.Replace("[currentdir]", HtmlSpecialChars(UTF8(path))); + body.Replace("[currentfiles]", files); + + return true; +} + +bool CWebClientSocket::OnControls(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); + CString dir; + + if (!path.IsEmpty() && !PathUtils::IsURL(path)) { + CPath p(path); + p.RemoveFileSpec(); + dir = (LPCTSTR)p; + } + + OAFilterState fs = m_pMainFrame->GetMediaState(); + CString state; + state.Format(_T("%d"), fs); + CString statestring; + switch (fs) { + case State_Stopped: + statestring.LoadString(IDS_CONTROLS_STOPPED); + break; + case State_Paused: + statestring.LoadString(IDS_CONTROLS_PAUSED); + break; + case State_Running: + statestring.LoadString(IDS_CONTROLS_PLAYING); + break; + default: + statestring = _T("N/A"); + break; + } + + CString volumelevel, muted; + volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos()); + muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0); + + CString reloadtime(_T("0")); // TODO + + m_pWebServer->LoadPage(IDR_HTML_CONTROLS, body, AToT(m_path)); + body.Replace("[filepatharg]", UTF8Arg(path)); + body.Replace("[filepath]", UTF8(path)); + body.Replace("[filedirarg]", UTF8Arg(dir)); + body.Replace("[filedir]", UTF8(dir)); + body.Replace("[state]", UTF8(state)); + body.Replace("[statestring]", UTF8(statestring)); + body.Replace("[position]", UTF8(NumToCString(std::lround(m_pMainFrame->GetPos() / 10000i64)))); + body.Replace("[positionstring]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); + body.Replace("[duration]", UTF8(NumToCString(std::lround(m_pMainFrame->GetDur() / 10000i64)))); + body.Replace("[durationstring]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); + body.Replace("[volumelevel]", UTF8(volumelevel)); + body.Replace("[muted]", UTF8(muted)); + body.Replace("[playbackrate]", UTF8(NumToCString(m_pMainFrame->GetPlayingRate()))); + body.Replace("[reloadtime]", UTF8(reloadtime)); + + return true; +} + +bool CWebClientSocket::OnVariables(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString path = m_pMainFrame->m_wndPlaylistBar.GetCurFileName(); + CString dir; + CString strName; + + if (!path.IsEmpty() && !PathUtils::IsURL(path)) { + CPath p(path); + p.RemoveFileSpec(); + dir = (LPCTSTR)p; + } + + OAFilterState fs = m_pMainFrame->GetMediaState(); + CString state; + state.Format(_T("%d"), fs); + CString statestring; + switch (fs) { + case State_Stopped: + statestring.LoadString(IDS_CONTROLS_STOPPED); + break; + case State_Paused: + statestring.LoadString(IDS_CONTROLS_PAUSED); + break; + case State_Running: + statestring.LoadString(IDS_CONTROLS_PLAYING); + break; + default: + statestring = _T("N/A"); + break; + } + + CString volumelevel, muted; + volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos()); + muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0); + + CString reloadtime(_T("0")); // TODO + + m_pWebServer->LoadPage(IDR_HTML_VARIABLES, body, AToT(m_path)); + body.Replace("[file]", UTF8(m_pMainFrame->GetFileName())); + body.Replace("[filepatharg]", UTF8Arg(path)); + body.Replace("[filepath]", UTF8(path)); + body.Replace("[filedirarg]", UTF8Arg(dir)); + body.Replace("[filedir]", UTF8(dir)); + body.Replace("[state]", UTF8(state)); + body.Replace("[statestring]", UTF8(statestring)); + body.Replace("[position]", UTF8(NumToCString(std::lround(m_pMainFrame->GetPos() / 10000i64)))); + body.Replace("[positionstring]", UTF8(ReftimeToString2(m_pMainFrame->GetPos()))); + body.Replace("[duration]", UTF8(NumToCString(std::lround(m_pMainFrame->GetDur() / 10000i64)))); + body.Replace("[durationstring]", UTF8(ReftimeToString2(m_pMainFrame->GetDur()))); + body.Replace("[volumelevel]", UTF8(volumelevel)); + body.Replace("[muted]", UTF8(muted)); + body.Replace("[playbackrate]", UTF8(NumToCString(m_pMainFrame->GetPlayingRate()))); + body.Replace("[size]", UTF8(GetSize())); + body.Replace("[reloadtime]", UTF8(reloadtime)); + body.Replace("[version]", UTF8(AfxGetMyApp()->m_strVersion)); + m_pMainFrame->GetCurrentAudioTrackIdx(&strName); + body.Replace("[audiotrack]", UTF8(strName)); + m_pMainFrame->GetCurrentSubtitleTrackIdx(&strName); + body.Replace("[subtitletrack]", UTF8(strName)); + + return true; +} + +bool CWebClientSocket::OnStatus(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString title; + m_pMainFrame->GetWindowText(title); + + CPath file(m_pMainFrame->m_wndPlaylistBar.GetCurFileName()); + + CString status; + OAFilterState fs = m_pMainFrame->GetMediaState(); + switch (fs) { + case State_Stopped: + status.LoadString(IDS_CONTROLS_STOPPED); + break; + case State_Paused: + status.LoadString(IDS_CONTROLS_PAUSED); + break; + case State_Running: + status.LoadString(IDS_CONTROLS_PLAYING); + break; + default: + status = _T("N/A"); + break; + } + + REFERENCE_TIME pos = m_pMainFrame->GetPos(); + REFERENCE_TIME dur = m_pMainFrame->GetDur(); + + title.Replace(_T("'"), _T("\\'")); + status.Replace(_T("'"), _T("\\'")); + + body.Format("OnStatus(\"%s\", \"%s\", %ld, \"%s\", %ld, \"%s\", %d, %d, \"%s\")", // , \"%s\" + UTF8(title).GetString(), UTF8(status).GetString(), + std::lround(pos / 10000i64), UTF8(ReftimeToString2(pos)).GetString(), + std::lround(dur / 10000i64), UTF8(ReftimeToString2(dur)).GetString(), + m_pMainFrame->IsMuted(), m_pMainFrame->GetVolume(), + UTF8(file).GetString()/*, UTF8(dir)*/); + + return true; +} + +bool CWebClientSocket::OnError404(CStringA& hdr, CStringA& body, CStringA& mime) +{ + m_pWebServer->LoadPage(IDR_HTML_404, body, AToT(m_path)); + return true; +} + +bool CWebClientSocket::OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime) +{ + m_pWebServer->LoadPage(IDR_HTML_PLAYER, body, AToT(m_path)); + if (AfxGetAppSettings().bWebUIEnablePreview) { + body.Replace("[preview]", + "\"snapshot\""); + } else { + body.Replace("[preview]", UTF8(StrRes(IDS_WEBUI_DISABLED_PREVIEW_MSG))); + } + return true; +} + +bool CWebClientSocket::OnSnapshotJpeg(CStringA& hdr, CStringA& body, CStringA& mime) +{ + // TODO: add quality control and return logo when nothing is loaded + + bool bRet = false; + + BYTE* pData = nullptr; + long size = 0; + if (!AfxGetAppSettings().bWebUIEnablePreview) { + hdr = "HTTP/1.0 403 Forbidden\r\n"; + bRet = true; + } else if (m_pMainFrame->GetDIB(&pData, size, true)) { + PBITMAPINFO bi = reinterpret_cast(pData); + PBITMAPINFOHEADER bih = &bi->bmiHeader; + + int bpp = bih->biBitCount; + if (bpp != 16 && bpp != 24 && bpp != 32) { + return false; + } + int w = bih->biWidth; + int h = abs(bih->biHeight); + BYTE* p = DEBUG_NEW BYTE[w * h * 4]; + + const BYTE* src = pData + sizeof(*bih); + + int srcpitch = w * (bpp >> 3); + int dstpitch = w * 4; + + BitBltFromRGBToRGB(w, h, p, dstpitch, 32, (BYTE*)src + srcpitch * (h - 1), -srcpitch, bpp); + + { + CBitmap bmp; + bmp.CreateBitmap(w, h, bih->biPlanes, bpp, p); + delete [] p; + + CImage img; + img.Attach(bmp); + IStream* pStream = nullptr; + CByteArray ba; + if (SUCCEEDED(CreateStreamOnHGlobal(nullptr, TRUE, &pStream))) { + if (SUCCEEDED(img.Save(pStream, Gdiplus::ImageFormatJPEG))) { + ULARGE_INTEGER ulnSize; + LARGE_INTEGER lnOffset; + lnOffset.QuadPart = 0; + if (SUCCEEDED(pStream->Seek(lnOffset, STREAM_SEEK_END, &ulnSize))) { + if (SUCCEEDED(pStream->Seek(lnOffset, STREAM_SEEK_SET, 0))) { + ULONG ulBytesRead; + ba.SetSize((INT_PTR)ulnSize.QuadPart); + pStream->Read(ba.GetData(), (ULONG)ulnSize.QuadPart, &ulBytesRead); + } + } + } + } + + pStream->Release(); + delete [] pData; + + hdr += + "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" + "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" + "Pragma: no-cache\r\n"; + body = CStringA((char*)ba.GetData(), (int)ba.GetCount()); + mime = "image/jpeg"; + bRet = true; + } + } + + return bRet; +} + +bool CWebClientSocket::OnViewRes(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString id; + if (!m_get.Lookup("id", id)) { + return false; + } + + uintptr_t key = 0; + if (1 != _stscanf_s(id, _T("%Ix"), &key) || key == 0) { + return false; + } + + CAutoLock cAutoLock(&CDSMResource::m_csResources); + + CDSMResource* res = nullptr; + if (!CDSMResource::m_resources.Lookup(key, res) || !res) { + return false; + } + + body = CStringA((const char*)res->data.GetData(), (int)res->data.GetCount()); + mime = res->mime; + + return true; +} + +static CStringA GetChannelsJSON(const std::vector& channels) +{ + // begin the JSON object with the "channels" array inside + CStringA jsonChannels = "{ \"channels\" : ["; + + for (auto it = channels.begin(); it != channels.end();) { + // fill the array with individual channel objects + jsonChannels += it->ToJSON(); + if (++it == channels.end()) { + break; + } + jsonChannels += ","; + } + + // terminate the array and the object, and return. + jsonChannels += "] }"; + return jsonChannels; +} + +bool CWebClientSocket::OnDVBChannels(CStringA& hdr, CStringA& body, CStringA& mime) +{ + if (m_pMainFrame->GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + mime = "application/json"; + body = GetChannelsJSON(AfxGetAppSettings().m_DVBChannels); + } else { + // if we're not currently running the capture, report the service as + // unavailable and return. + hdr = "HTTP/1.0 503 Service Unavailable\r\n"; + } + + // the request is always "handled", successfully or not. + return true; +} + +bool CWebClientSocket::OnDVBSetChannel(CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString requestParam; + int channelIdx; + if (m_pMainFrame->GetPlaybackMode() == PM_DIGITAL_CAPTURE) { + // the 'idx' GET parameter should contain a valid integer of the + // channel to switch to. + if (m_get.Lookup("idx", requestParam) + && _stscanf_s(requestParam, _T("%d"), &channelIdx) == 1 + && channelIdx >= 0) { + if (AfxGetAppSettings().FindChannelByPref(channelIdx)) { + m_pMainFrame->SendMessage(WM_COMMAND, channelIdx + ID_NAVIGATE_JUMPTO_SUBITEM_START); + } else { + // Return a 404 if requested channel number was not found. + hdr = "HTTP/1.0 404 Not Found\r\n"; + } + } else { + // invalid parameters. + hdr = "HTTP/1.0 400 Bad Request\r\n"; + } + } else { + // not running the capture - don't report channels. + hdr = "HTTP/1.0 503 Service Unavailable\r\n"; + } + return true; +} + +CString CWebClientSocket::GetSize() const +{ + CString sizeString; + LONGLONG size = 0; + + if (CComQIPtr pBF = m_pMainFrame->m_pFSF) { + BeginEnumPins(pBF, pEP, pPin) { + if (CComQIPtr pAR = pPin) { + LONGLONG total, available; + if (SUCCEEDED(pAR->Length(&total, &available))) { + size = total; + break; + } + } + } + EndEnumPins; + } + + if (size == 0) { + WIN32_FIND_DATA wfd; + HANDLE hFind = FindFirstFile(m_pMainFrame->m_wndPlaylistBar.GetCurFileName(), &wfd); + if (hFind != INVALID_HANDLE_VALUE) { + FindClose(hFind); + size = (LONGLONG(wfd.nFileSizeHigh) << 32) | wfd.nFileSizeLow; + } + } + + const int MAX_FILE_SIZE_BUFFER = 65; + TCHAR szFileSize[MAX_FILE_SIZE_BUFFER]; + StrFormatByteSizeW(size, szFileSize, MAX_FILE_SIZE_BUFFER); + sizeString.Format(L"%s", szFileSize); + + return sizeString; +} diff --git a/src/mpc-hc/WebClientSocket.h b/src/mpc-hc/WebClientSocket.h index e7c7e8338a7..eccd24be3bf 100644 --- a/src/mpc-hc/WebClientSocket.h +++ b/src/mpc-hc/WebClientSocket.h @@ -1,85 +1,85 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2015 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 . - * - */ - -#pragma once - -class CWebServer; - -class CWebClientSocket : public CAsyncSocket -{ - CWebServer* m_pWebServer; - CMainFrame* m_pMainFrame; - - char* m_buff; - int m_buffLen, m_buffMaxLen, m_buffLenProcessed; - - enum PARSING_STATE { - PARSING_HEADER, - PARSING_POST_DATA, - PARSING_DONE - }; - PARSING_STATE m_parsingState; - int m_dataLen; - - struct cookie_attribs { - CString path, expire, domain; - }; - CAtlStringMap m_cookieattribs; - - void Clear(); - void HandleRequest(); - void ParseHeader(const char* headerEnd); - void ParsePostData(); - -protected: - void OnReceive(int nErrorCode); - void OnClose(int nErrorCode); - -public: - CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame); - virtual ~CWebClientSocket(); - - bool SetCookie(CStringA name, CString value = _T(""), __time64_t expire = -1, CString path = _T("/"), CString domain = _T("")); - - CString m_sessid; - CStringA m_cmd, m_path, m_query, m_ver; - CStringA m_data; - CAtlStringMap m_hdrlines; - CAtlStringMap m_get, m_post, m_cookie; - CAtlStringMap m_request; - - bool OnCommand(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnIndex(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnInfo(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnControls(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnVariables(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnStatus(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnError404(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnSnapshotJpeg(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnViewRes(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnDVBChannels(CStringA& hdr, CStringA& body, CStringA& mime); - bool OnDVBSetChannel(CStringA& hdr, CStringA& body, CStringA& mime); - -private: - CString GetSize() const; -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2015 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 . + * + */ + +#pragma once + +class CWebServer; + +class CWebClientSocket : public CAsyncSocket +{ + CWebServer* m_pWebServer; + CMainFrame* m_pMainFrame; + + char* m_buff; + int m_buffLen, m_buffMaxLen, m_buffLenProcessed; + + enum PARSING_STATE { + PARSING_HEADER, + PARSING_POST_DATA, + PARSING_DONE + }; + PARSING_STATE m_parsingState; + int m_dataLen; + + struct cookie_attribs { + CString path, expire, domain; + }; + CAtlStringMap m_cookieattribs; + + void Clear(); + void HandleRequest(); + void ParseHeader(const char* headerEnd); + void ParsePostData(); + +protected: + void OnReceive(int nErrorCode); + void OnClose(int nErrorCode); + +public: + CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame); + virtual ~CWebClientSocket(); + + bool SetCookie(CStringA name, CString value = _T(""), __time64_t expire = -1, CString path = _T("/"), CString domain = _T("")); + + CString m_sessid; + CStringA m_cmd, m_path, m_query, m_ver; + CStringA m_data; + CAtlStringMap m_hdrlines; + CAtlStringMap m_get, m_post, m_cookie; + CAtlStringMap m_request; + + bool OnCommand(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnIndex(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnInfo(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnControls(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnVariables(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnStatus(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnError404(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnSnapshotJpeg(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnViewRes(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnDVBChannels(CStringA& hdr, CStringA& body, CStringA& mime); + bool OnDVBSetChannel(CStringA& hdr, CStringA& body, CStringA& mime); + +private: + CString GetSize() const; +}; diff --git a/src/mpc-hc/WebServer.cpp b/src/mpc-hc/WebServer.cpp index b6d2ffb9ee5..3fe88be4ff7 100644 --- a/src/mpc-hc/WebServer.cpp +++ b/src/mpc-hc/WebServer.cpp @@ -1,715 +1,715 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "resource.h" -#include "MainFrm.h" -#include -#include "zlib/zlib.h" -#include "WebServerSocket.h" -#include "WebClientSocket.h" -#include "WebServer.h" -#include "VersionInfo.h" -#include "PathUtils.h" - - -CAtlStringMap CWebServer::m_internalpages; -CAtlStringMap CWebServer::m_downloads; -CAtlStringMap CWebServer::m_mimes; - -CWebServer::CWebServer(CMainFrame* pMainFrame, int nPort) - : m_pMainFrame(pMainFrame) - , m_nPort(nPort) -{ - m_webroot = CPath(PathUtils::GetProgramPath()); - const CAppSettings& s = AfxGetAppSettings(); - - CString WebRoot = s.strWebRoot; - WebRoot.Replace('/', '\\'); - WebRoot.Trim(); - CPath p(WebRoot); - if (WebRoot.Find(_T(":\\")) < 0 && WebRoot.Find(_T("\\\\")) < 0) { - m_webroot.Append(WebRoot); - } else { - m_webroot = p; - } - m_webroot.Canonicalize(); - m_webroot.MakePretty(); - if (!m_webroot.IsDirectory()) { - m_webroot = CPath(); - } - - CAtlList sl; - Explode(s.strWebServerCGI, sl, ';'); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - CAtlList sl2; - CString ext = Explode(sl.GetNext(pos), sl2, '=', 2); - if (sl2.GetCount() < 2) { - continue; - } - m_cgi[ext] = sl2.GetTail(); - } - - m_ThreadId = 0; - m_hThread = ::CreateThread(nullptr, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId); -} - -CWebServer::~CWebServer() -{ - if (m_hThread != nullptr) { - PostThreadMessage(m_ThreadId, WM_QUIT, (WPARAM)0, (LPARAM)0); - if (WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT) { - TerminateThread(m_hThread, 0xDEAD); - } - EXECUTE_ASSERT(CloseHandle(m_hThread)); - } -} - -void CWebServer::Init() -{ - m_internalpages["/"] = &CWebClientSocket::OnIndex; - m_internalpages["/404.html"] = &CWebClientSocket::OnError404; - m_internalpages["/browser.html"] = &CWebClientSocket::OnBrowser; - m_internalpages["/command.html"] = &CWebClientSocket::OnCommand; - m_internalpages["/controls.html"] = &CWebClientSocket::OnControls; - m_internalpages["/index.html"] = &CWebClientSocket::OnIndex; - m_internalpages["/info.html"] = &CWebClientSocket::OnInfo; - m_internalpages["/player.html"] = &CWebClientSocket::OnPlayer; - m_internalpages["/snapshot.jpg"] = &CWebClientSocket::OnSnapshotJpeg; - m_internalpages["/status.html"] = &CWebClientSocket::OnStatus; - m_internalpages["/variables.html"] = &CWebClientSocket::OnVariables; - m_internalpages["/viewres.html"] = &CWebClientSocket::OnViewRes; - m_internalpages["/dvb/channels.json"] = &CWebClientSocket::OnDVBChannels; - m_internalpages["/dvb/setchannel"] = &CWebClientSocket::OnDVBSetChannel; - - m_downloads["/default.css"] = IDF_DEFAULT_CSS; - m_downloads["/favicon.ico"] = IDF_FAVICON; - m_downloads["/img/1pix.png"] = IDF_1PIX_PNG; - m_downloads["/img/bottomside.png"] = IDF_BOTTOMSIDE_PNG; - m_downloads["/img/controlback.png"] = IDF_CONTROLBACK_PNG; - m_downloads["/img/controlbuttondecrate.png"] = IDF_CONTROLBUTTONDECRATE_PNG; - m_downloads["/img/controlbuttonincrate.png"] = IDF_CONTROLBUTTONINCRATE_PNG; - m_downloads["/img/controlbuttonpause.png"] = IDF_CONTROLBUTTONPAUSE_PNG; - m_downloads["/img/controlbuttonplay.png"] = IDF_CONTROLBUTTONPLAY_PNG; - m_downloads["/img/controlbuttonskipback.png"] = IDF_CONTROLBUTTONSKIPBACK_PNG; - m_downloads["/img/controlbuttonskipforward.png"] = IDF_CONTROLBUTTONSKIPFORWARD_PNG; - m_downloads["/img/controlbuttonstep.png"] = IDF_CONTROLBUTTONSTEP_PNG; - m_downloads["/img/controlbuttonstop.png"] = IDF_CONTROLBUTTONSTOP_PNG; - m_downloads["/img/controlvolumebar.png"] = IDF_CONTROLVOLUMEBAR_PNG; - m_downloads["/img/controlvolumegrip.png"] = IDF_CONTROLVOLUMEGRIP_PNG; - m_downloads["/img/controlvolumeoff.png"] = IDF_CONTROLVOLUMEOFF_PNG; - m_downloads["/img/controlvolumeon.png"] = IDF_CONTROLVOLUMEON_PNG; - m_downloads["/img/headerback.png"] = IDF_HEADERBACK_PNG; - m_downloads["/img/headerclose.png"] = IDF_HEADERCLOSE_PNG; - m_downloads["/img/headericon.png"] = IDF_HEADERICON_PNG; - m_downloads["/img/leftbottomside.png"] = IDF_LEFTBOTTOMSIDE_PNG; - m_downloads["/img/leftside.png"] = IDF_LEFTSIDE_PNG; - m_downloads["/img/rightbottomside.png"] = IDF_RIGHTBOTTOMSIDE_PNG; - m_downloads["/img/rightside.png"] = IDF_RIGHTSIDE_PNG; - m_downloads["/img/seekbargrip.png"] = IDF_SEEKBARGRIP_PNG; - m_downloads["/img/seekbarleft.png"] = IDF_SEEKBARLEFT_PNG; - m_downloads["/img/seekbarmid.png"] = IDF_SEEKBARMID_PNG; - m_downloads["/img/seekbarright.png"] = IDF_SEEKBARRIGHT_PNG; - m_downloads["/img/sliderback.png"] = IDF_SLIDERBACK_PNG; - m_downloads["/img/slidergrip.png"] = IDF_SLIDERGRIP_PNG; - m_downloads["/img/vbg.png"] = IDF_VBR_PNG; - m_downloads["/img/vbs.png"] = IDF_VBS_PNG; - m_downloads["/javascript.js"] = IDF_JAVASCRIPT; - -#if 0 - CRegKey key; - CString str(_T("MIME\\Database\\Content Type")); - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, str, KEY_READ)) { - TCHAR buff[256]; - DWORD len = _countof(buff); - for (int i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len); i++, len = _countof(buff)) { - CRegKey mime; - TCHAR ext[64]; - ULONG len2 = _countof(ext); - if (ERROR_SUCCESS == mime.Open(HKEY_CLASSES_ROOT, str + _T("\\") + buff, KEY_READ) - && ERROR_SUCCESS == mime.QueryStringValue(_T("Extension"), ext, &len2)) { - m_mimes[CStringA(ext).MakeLower()] = CStringA(buff).MakeLower(); - } - } - } -#endif - - m_mimes[".bmp"] = "image/bmp"; - m_mimes[".css"] = "text/css"; - m_mimes[".gif"] = "image/gif"; - m_mimes[".htm"] = "text/html"; - m_mimes[".html"] = "text/html"; - m_mimes[".jpeg"] = "image/jpeg"; - m_mimes[".jpg"] = "image/jpeg"; - m_mimes[".js"] = "text/javascript"; - m_mimes[".json"] = "text/plain"; - m_mimes[".png"] = "image/png"; - m_mimes[".txt"] = "text/plain"; - m_mimes[".ico"] = "image/x-icon"; -} - -DWORD WINAPI CWebServer::StaticThreadProc(LPVOID lpParam) -{ - SetThreadName(DWORD(-1), "WebServer Thread"); - return ((CWebServer*)lpParam)->ThreadProc(); -} - -DWORD CWebServer::ThreadProc() -{ - if (!AfxSocketInit(nullptr)) { - return DWORD_ERROR; - } - - CWebServerSocket s(this, m_nPort); - - MSG msg; - while ((int)GetMessage(&msg, nullptr, 0, 0) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - return 0; -} - -static void PutFileContents(LPCTSTR fn, const CStringA& data) -{ - FILE* f = nullptr; - if (!_tfopen_s(&f, fn, _T("wb"))) { - fwrite((LPCSTR)data, 1, data.GetLength(), f); - fclose(f); - } -} - -void CWebServer::Deploy(CString dir) -{ - CStringA data; - if (LoadResource(IDR_HTML_INDEX, data, RT_HTML)) { - PutFileContents(dir + _T("index.html"), data); - } - if (LoadResource(IDR_HTML_INFO, data, RT_HTML)) { - PutFileContents(dir + _T("info.html"), data); - } - if (LoadResource(IDR_HTML_BROWSER, data, RT_HTML)) { - PutFileContents(dir + _T("browser.html"), data); - } - if (LoadResource(IDR_HTML_CONTROLS, data, RT_HTML)) { - PutFileContents(dir + _T("controls.html"), data); - } - if (LoadResource(IDR_HTML_VARIABLES, data, RT_HTML)) { - PutFileContents(dir + _T("variables.html"), data); - } - if (LoadResource(IDR_HTML_404, data, RT_HTML)) { - PutFileContents(dir + _T("404.html"), data); - } - if (LoadResource(IDR_HTML_PLAYER, data, RT_HTML)) { - PutFileContents(dir + _T("player.html"), data); - } - - // Create the needed folder - CreateDirectory(dir + _T("img"), nullptr); - - POSITION pos = m_downloads.GetStartPosition(); - while (pos) { - CStringA fn; - UINT id; - m_downloads.GetNextAssoc(pos, fn, id); - if (LoadResource(id, data, _T("FILE")) || LoadResource(id, data, _T("PNG"))) { - PutFileContents(dir + AToT(fn), data); - } - } -} - -bool CWebServer::ToLocalPath(CString& path, CString& redir) -{ - if (!path.IsEmpty() && m_webroot.IsDirectory()) { - CString str = path; - str.Replace('/', '\\'); - str.TrimLeft('\\'); - - CPath p; - p.Combine(m_webroot, str); - p.Canonicalize(); - - if (p.IsDirectory()) { - CAtlList sl; - Explode(AfxGetAppSettings().strWebDefIndex, sl, ';'); - POSITION pos = sl.GetHeadPosition(); - while (pos) { - str = sl.GetNext(pos); - CPath p2 = p; - p2.Append(str); - if (p2.FileExists()) { - p = p2; - redir = path; - if (redir.GetAt(redir.GetLength() - 1) != '/') { - redir += _T('/'); - } - redir += str; - break; - } - } - } - - if (_tcslen(p) > _tcslen(m_webroot) && p.FileExists()) { - path = (LPCTSTR)p; - return true; - } - } - - return false; -} - -bool CWebServer::LoadPage(UINT resid, CStringA& str, CString path) -{ - CString redir; - if (ToLocalPath(path, redir)) { - FILE* f = nullptr; - if (!_tfopen_s(&f, path, _T("rb"))) { - fseek(f, 0, 2); - char* buff = str.GetBufferSetLength(ftell(f)); - fseek(f, 0, 0); - int len = (int)fread(buff, 1, str.GetLength(), f); - fclose(f); - return len == str.GetLength(); - } - } - - return LoadResource(resid, str, RT_HTML); -} - -void CWebServer::OnAccept(CWebServerSocket* pServer) -{ - CAutoPtr p(DEBUG_NEW CWebClientSocket(this, m_pMainFrame)); - if (pServer->Accept(*p)) { - CString name; - UINT port; - if (AfxGetAppSettings().fWebServerLocalhostOnly && p->GetPeerName(name, port) && name != _T("127.0.0.1")) { - p->Close(); - return; - } - - m_clients.AddTail(p); - } -} - -void CWebServer::OnClose(const CWebClientSocket* pClient) -{ - POSITION pos = m_clients.GetHeadPosition(); - while (pos) { - POSITION cur = pos; - if (m_clients.GetNext(pos) == pClient) { - m_clients.RemoveAt(cur); - break; - } - } -} - -void CWebServer::OnRequest(CWebClientSocket* pClient, CStringA& hdr, CStringA& body) -{ - const CAppSettings& s = AfxGetAppSettings(); - - CPath p(AToT(pClient->m_path)); - CStringA ext = p.GetExtension().MakeLower(); - CStringA mime; - if (ext.IsEmpty()) { - mime = "text/html"; - } else { - if (!m_mimes.Lookup(ext, mime)) { - mime = "none"; - } - } - - hdr = "HTTP/1.0 200 OK\r\n"; - - bool fHandled = false, fCGI = false; - - if (m_webroot.IsDirectory()) { - CStringA tmphdr; - fHandled = fCGI = CallCGI(pClient, tmphdr, body, mime); - - if (fHandled) { - tmphdr.Replace("\r\n", "\n"); - CAtlList hdrlines; - ExplodeMin(tmphdr, hdrlines, '\n'); - POSITION pos = hdrlines.GetHeadPosition(); - while (pos) { - POSITION cur = pos; - CAtlList sl; - CStringA key = Explode(hdrlines.GetNext(pos), sl, ':', 2); - if (sl.GetCount() < 2) { - continue; - } - key.Trim().MakeLower(); - if (key == "content-type") { - mime = sl.GetTail().Trim(); - hdrlines.RemoveAt(cur); - } else if (key == "content-length") { - hdrlines.RemoveAt(cur); - } - } - tmphdr = Implode(hdrlines, "\r\n"); - hdr += tmphdr + "\r\n"; - } - } - - RequestHandler rh = nullptr; - if (!fHandled && m_internalpages.Lookup(pClient->m_path, rh) && (pClient->*rh)(hdr, body, mime)) { - if (mime.IsEmpty()) { - mime = "text/html"; - } - - CString redir; - if (pClient->m_get.Lookup("redir", redir) - || pClient->m_post.Lookup("redir", redir)) { - if (redir.IsEmpty()) { - redir = '/'; - } - - hdr = - "HTTP/1.0 302 Found\r\n" - "Location: " + CStringA(redir) + "\r\n"; - return; - } - - fHandled = true; - } - - if (!fHandled && m_webroot.IsDirectory()) { - fHandled = LoadPage(0, body, UTF8To16(pClient->m_path)); - } - - UINT resid; - if (!fHandled && m_downloads.Lookup(pClient->m_path, resid) - && (LoadResource(resid, body, _T("FILE")) || LoadResource(resid, body, _T("PNG")))) { - if (mime.IsEmpty()) { - mime = "application/octet-stream"; - } - fHandled = true; - } - - if (!fHandled) { - hdr = mime == "text/html" - ? "HTTP/1.0 301 Moved Permanently\r\n" "Location: /404.html\r\n" - : "HTTP/1.0 404 Not Found\r\n"; - return; - } - - /* Don't cache html, js and css files */ - if ((mime == "text/html" || mime == "text/javascript" || mime == "text/css") && !fCGI) { - if (mime == "text/html") { - hdr += - "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" - "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" - "Pragma: no-cache\r\n"; - - CStringA debug; - if (s.fWebServerPrintDebugInfo) { - debug += "


\r\n";
-
-                CStringA key;
-                POSITION pos;
-
-                {
-                    CStringA value;
-
-                    pos = pClient->m_hdrlines.GetStartPosition();
-                    while (pos) {
-                        pClient->m_hdrlines.GetNextAssoc(pos, key, value);
-                        debug += "HEADER[" + key + "] = " + value + "\r\n";
-                    }
-                }
-                debug += "cmd: " + pClient->m_cmd + "\r\n";
-                debug += "path: " + pClient->m_path + "\r\n";
-                debug += "ver: " + pClient->m_ver + "\r\n";
-
-                {
-                    CString value;
-
-                    pos = pClient->m_get.GetStartPosition();
-                    while (pos) {
-                        pClient->m_get.GetNextAssoc(pos, key, value);
-                        debug += "GET[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
-                    }
-                    pos = pClient->m_post.GetStartPosition();
-                    while (pos) {
-                        pClient->m_post.GetNextAssoc(pos, key, value);
-                        debug += "POST[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
-                    }
-                    pos = pClient->m_cookie.GetStartPosition();
-                    while (pos) {
-                        pClient->m_cookie.GetNextAssoc(pos, key, value);
-                        debug += "COOKIE[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
-                    }
-                    pos = pClient->m_request.GetStartPosition();
-                    while (pos) {
-                        pClient->m_request.GetNextAssoc(pos, key, value);
-                        debug += "REQUEST[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
-                    }
-                }
-                debug += "
"; - } - body.Replace("[debug]", debug); - } - - body.Replace("[browserpath]", "/browser.html"); - body.Replace("[commandpath]", "/command.html"); - body.Replace("[controlspath]", "/controls.html"); - body.Replace("[indexpath]", "/index.html"); - body.Replace("[path]", pClient->m_path); - body.Replace("[setposcommand]", CMD_SETPOS); - body.Replace("[setvolumecommand]", CMD_SETVOLUME); - body.Replace("[wmcname]", "wm_command"); - // TODO: add more general tags to replace - } - - // gzip - if (s.fWebServerUseCompression && !body.IsEmpty() - && hdr.Find("Content-Encoding:") < 0 && ext != ".png" && ext != ".jpeg" && ext != ".gif") - do { - CStringA accept_encoding; - pClient->m_hdrlines.Lookup("accept-encoding", accept_encoding); - accept_encoding.MakeLower(); - CAtlList sl; - ExplodeMin(accept_encoding, sl, ','); - if (!sl.Find("gzip")) { - break; - } - - // Allocate deflate state - z_stream strm; - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); - if (ret != Z_OK) { - ASSERT(0); - break; - } - - int gzippedBuffLen = body.GetLength(); - BYTE* gzippedBuff = DEBUG_NEW BYTE[gzippedBuffLen]; - - // Compress - strm.avail_in = body.GetLength(); - strm.next_in = (Bytef*)(LPCSTR)body; - - strm.avail_out = gzippedBuffLen; - strm.next_out = gzippedBuff; - - ret = deflate(&strm, Z_FINISH); - if (ret != Z_STREAM_END || strm.avail_in != 0) { - ASSERT(0); - deflateEnd(&strm); - delete [] gzippedBuff; - break; - } - gzippedBuffLen -= strm.avail_out; - memcpy(body.GetBufferSetLength(gzippedBuffLen), gzippedBuff, gzippedBuffLen); - - // Clean up - deflateEnd(&strm); - delete [] gzippedBuff; - - hdr += "Content-Encoding: gzip\r\n"; - } while (0); - - CStringA content; - content.Format( - "Content-Type: %s\r\n" - "Content-Length: %d\r\n", - mime.GetString(), body.GetLength()); - hdr += content; -} - -static DWORD WINAPI KillCGI(LPVOID lParam) -{ - HANDLE hProcess = (HANDLE)lParam; - if (WaitForSingleObject(hProcess, 30000) == WAIT_TIMEOUT) { - TerminateProcess(hProcess, 0); - } - return 0; -} - -bool CWebServer::CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime) -{ - CString path = pClient->m_path, redir = path; - if (!ToLocalPath(path, redir)) { - return false; - } - CString ext = CPath(path).GetExtension().MakeLower(); - CPath dir(path); - dir.RemoveFileSpec(); - - CString cgi; - if (!m_cgi.Lookup(ext, cgi) || !CPath(cgi).FileExists()) { - return false; - } - - HANDLE hProcess = GetCurrentProcess(); - HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup = nullptr; - HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup = nullptr; - - SECURITY_ATTRIBUTES saAttr; - ZeroMemory(&saAttr, sizeof(saAttr)); - saAttr.nLength = sizeof(saAttr); - saAttr.bInheritHandle = TRUE; - - if (CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { - BOOL fSuccess = DuplicateHandle(hProcess, hChildStdoutRd, hProcess, &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS); - UNREFERENCED_PARAMETER(fSuccess); - CloseHandle(hChildStdoutRd); - } - - if (CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { - BOOL fSuccess = DuplicateHandle(hProcess, hChildStdinWr, hProcess, &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS); - UNREFERENCED_PARAMETER(fSuccess); - CloseHandle(hChildStdinWr); - } - - STARTUPINFO siStartInfo; - ZeroMemory(&siStartInfo, sizeof(siStartInfo)); - siStartInfo.cb = sizeof(siStartInfo); - siStartInfo.hStdError = hChildStdoutWr; - siStartInfo.hStdOutput = hChildStdoutWr; - siStartInfo.hStdInput = hChildStdinRd; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - siStartInfo.wShowWindow = SW_HIDE; - - PROCESS_INFORMATION piProcInfo; - ZeroMemory(&piProcInfo, sizeof(piProcInfo)); - - CStringA envstr; - - LPVOID lpvEnv = GetEnvironmentStrings(); - if (lpvEnv) { - CAtlList env; - for (LPTSTR lpszVariable = (LPTSTR)lpvEnv; *lpszVariable; lpszVariable += _tcslen(lpszVariable) + 1) { - if (lpszVariable != (LPTSTR)lpvEnv) { - env.AddTail(lpszVariable); - } - } - - env.AddTail(_T("GATEWAY_INTERFACE=CGI/1.1")); - env.AddTail(_T("SERVER_SOFTWARE=MPC-HC/") + VersionInfo::GetVersionString()); - env.AddTail(_T("SERVER_PROTOCOL=") + AToT(pClient->m_ver)); - env.AddTail(_T("REQUEST_METHOD=") + AToT(pClient->m_cmd)); - env.AddTail(_T("PATH_INFO=") + redir); - env.AddTail(_T("PATH_TRANSLATED=") + path); - env.AddTail(_T("SCRIPT_NAME=") + redir); - env.AddTail(_T("QUERY_STRING=") + AToT(pClient->m_query)); - - { - CStringA str; - if (pClient->m_hdrlines.Lookup("content-type", str)) { - env.AddTail(_T("CONTENT_TYPE=") + AToT(str)); - } - if (pClient->m_hdrlines.Lookup("content-length", str)) { - env.AddTail(_T("CONTENT_LENGTH=") + AToT(str)); - } - } - - POSITION pos = pClient->m_hdrlines.GetStartPosition(); - while (pos) { - CString key = pClient->m_hdrlines.GetKeyAt(pos); - CString value = pClient->m_hdrlines.GetNextValue(pos); - key.Replace(_T("-"), _T("_")); - key.MakeUpper(); - env.AddTail(_T("HTTP_") + key + _T("=") + value); - } - - CString str, name; - UINT port; - - if (pClient->GetPeerName(name, port)) { - str.Format(_T("%u"), port); - env.AddTail(_T("REMOTE_ADDR=") + name); - env.AddTail(_T("REMOTE_HOST=") + name); - env.AddTail(_T("REMOTE_PORT=") + str); - } - - if (pClient->GetSockName(name, port)) { - str.Format(_T("%u"), port); - env.AddTail(_T("SERVER_NAME=") + name); - env.AddTail(_T("SERVER_PORT=") + str); - } - - env.AddTail(_T("\0")); - - str = Implode(env, '\0'); - envstr = CStringA(str, str.GetLength()); - - FreeEnvironmentStrings((LPTSTR)lpvEnv); - } - - TCHAR* cmdln = DEBUG_NEW TCHAR[32768]; - _sntprintf_s(cmdln, 32768, 32768, _T("\"%s\" \"%s\""), cgi.GetString(), path.GetString()); - - if (hChildStdinRd && hChildStdoutWr) - if (CreateProcess( - nullptr, cmdln, nullptr, nullptr, TRUE, 0, - envstr.GetLength() ? (LPVOID)(LPCSTR)envstr : nullptr, - dir, &siStartInfo, &piProcInfo)) { - DWORD ThreadId; - VERIFY(CreateThread(nullptr, 0, KillCGI, (LPVOID)piProcInfo.hProcess, 0, &ThreadId)); - - static const int BUFFSIZE = 1024; - DWORD dwRead, dwWritten = 0; - - int i = 0, len = pClient->m_data.GetLength(); - for (; i < len; i += dwWritten) { - if (!WriteFile(hChildStdinWrDup, (LPCSTR)pClient->m_data + i, std::min(len - i, BUFFSIZE), &dwWritten, nullptr)) { - break; - } - } - - CloseHandle(hChildStdinWrDup); - CloseHandle(hChildStdoutWr); - - body.Empty(); - - CStringA buff; - while (i == len && ReadFile(hChildStdoutRdDup, buff.GetBuffer(BUFFSIZE), BUFFSIZE, &dwRead, nullptr) && dwRead) { - buff.ReleaseBufferSetLength(dwRead); - body += buff; - } - - int hdrend = body.Find("\r\n\r\n"); - if (hdrend >= 0) { - hdr = body.Left(hdrend + 2); - body = body.Mid(hdrend + 4); - } - - CloseHandle(hChildStdinRd); - CloseHandle(hChildStdoutRdDup); - - CloseHandle(piProcInfo.hProcess); - CloseHandle(piProcInfo.hThread); - } else { - body = "CGI Error"; - } - - delete [] cmdln; - - return true; -} +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "resource.h" +#include "MainFrm.h" +#include +#include "zlib/zlib.h" +#include "WebServerSocket.h" +#include "WebClientSocket.h" +#include "WebServer.h" +#include "VersionInfo.h" +#include "PathUtils.h" + + +CAtlStringMap CWebServer::m_internalpages; +CAtlStringMap CWebServer::m_downloads; +CAtlStringMap CWebServer::m_mimes; + +CWebServer::CWebServer(CMainFrame* pMainFrame, int nPort) + : m_pMainFrame(pMainFrame) + , m_nPort(nPort) +{ + m_webroot = CPath(PathUtils::GetProgramPath()); + const CAppSettings& s = AfxGetAppSettings(); + + CString WebRoot = s.strWebRoot; + WebRoot.Replace('/', '\\'); + WebRoot.Trim(); + CPath p(WebRoot); + if (WebRoot.Find(_T(":\\")) < 0 && WebRoot.Find(_T("\\\\")) < 0) { + m_webroot.Append(WebRoot); + } else { + m_webroot = p; + } + m_webroot.Canonicalize(); + m_webroot.MakePretty(); + if (!m_webroot.IsDirectory()) { + m_webroot = CPath(); + } + + CAtlList sl; + Explode(s.strWebServerCGI, sl, ';'); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + CAtlList sl2; + CString ext = Explode(sl.GetNext(pos), sl2, '=', 2); + if (sl2.GetCount() < 2) { + continue; + } + m_cgi[ext] = sl2.GetTail(); + } + + m_ThreadId = 0; + m_hThread = ::CreateThread(nullptr, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId); +} + +CWebServer::~CWebServer() +{ + if (m_hThread != nullptr) { + PostThreadMessage(m_ThreadId, WM_QUIT, (WPARAM)0, (LPARAM)0); + if (WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT) { + TerminateThread(m_hThread, 0xDEAD); + } + EXECUTE_ASSERT(CloseHandle(m_hThread)); + } +} + +void CWebServer::Init() +{ + m_internalpages["/"] = &CWebClientSocket::OnIndex; + m_internalpages["/404.html"] = &CWebClientSocket::OnError404; + m_internalpages["/browser.html"] = &CWebClientSocket::OnBrowser; + m_internalpages["/command.html"] = &CWebClientSocket::OnCommand; + m_internalpages["/controls.html"] = &CWebClientSocket::OnControls; + m_internalpages["/index.html"] = &CWebClientSocket::OnIndex; + m_internalpages["/info.html"] = &CWebClientSocket::OnInfo; + m_internalpages["/player.html"] = &CWebClientSocket::OnPlayer; + m_internalpages["/snapshot.jpg"] = &CWebClientSocket::OnSnapshotJpeg; + m_internalpages["/status.html"] = &CWebClientSocket::OnStatus; + m_internalpages["/variables.html"] = &CWebClientSocket::OnVariables; + m_internalpages["/viewres.html"] = &CWebClientSocket::OnViewRes; + m_internalpages["/dvb/channels.json"] = &CWebClientSocket::OnDVBChannels; + m_internalpages["/dvb/setchannel"] = &CWebClientSocket::OnDVBSetChannel; + + m_downloads["/default.css"] = IDF_DEFAULT_CSS; + m_downloads["/favicon.ico"] = IDF_FAVICON; + m_downloads["/img/1pix.png"] = IDF_1PIX_PNG; + m_downloads["/img/bottomside.png"] = IDF_BOTTOMSIDE_PNG; + m_downloads["/img/controlback.png"] = IDF_CONTROLBACK_PNG; + m_downloads["/img/controlbuttondecrate.png"] = IDF_CONTROLBUTTONDECRATE_PNG; + m_downloads["/img/controlbuttonincrate.png"] = IDF_CONTROLBUTTONINCRATE_PNG; + m_downloads["/img/controlbuttonpause.png"] = IDF_CONTROLBUTTONPAUSE_PNG; + m_downloads["/img/controlbuttonplay.png"] = IDF_CONTROLBUTTONPLAY_PNG; + m_downloads["/img/controlbuttonskipback.png"] = IDF_CONTROLBUTTONSKIPBACK_PNG; + m_downloads["/img/controlbuttonskipforward.png"] = IDF_CONTROLBUTTONSKIPFORWARD_PNG; + m_downloads["/img/controlbuttonstep.png"] = IDF_CONTROLBUTTONSTEP_PNG; + m_downloads["/img/controlbuttonstop.png"] = IDF_CONTROLBUTTONSTOP_PNG; + m_downloads["/img/controlvolumebar.png"] = IDF_CONTROLVOLUMEBAR_PNG; + m_downloads["/img/controlvolumegrip.png"] = IDF_CONTROLVOLUMEGRIP_PNG; + m_downloads["/img/controlvolumeoff.png"] = IDF_CONTROLVOLUMEOFF_PNG; + m_downloads["/img/controlvolumeon.png"] = IDF_CONTROLVOLUMEON_PNG; + m_downloads["/img/headerback.png"] = IDF_HEADERBACK_PNG; + m_downloads["/img/headerclose.png"] = IDF_HEADERCLOSE_PNG; + m_downloads["/img/headericon.png"] = IDF_HEADERICON_PNG; + m_downloads["/img/leftbottomside.png"] = IDF_LEFTBOTTOMSIDE_PNG; + m_downloads["/img/leftside.png"] = IDF_LEFTSIDE_PNG; + m_downloads["/img/rightbottomside.png"] = IDF_RIGHTBOTTOMSIDE_PNG; + m_downloads["/img/rightside.png"] = IDF_RIGHTSIDE_PNG; + m_downloads["/img/seekbargrip.png"] = IDF_SEEKBARGRIP_PNG; + m_downloads["/img/seekbarleft.png"] = IDF_SEEKBARLEFT_PNG; + m_downloads["/img/seekbarmid.png"] = IDF_SEEKBARMID_PNG; + m_downloads["/img/seekbarright.png"] = IDF_SEEKBARRIGHT_PNG; + m_downloads["/img/sliderback.png"] = IDF_SLIDERBACK_PNG; + m_downloads["/img/slidergrip.png"] = IDF_SLIDERGRIP_PNG; + m_downloads["/img/vbg.png"] = IDF_VBR_PNG; + m_downloads["/img/vbs.png"] = IDF_VBS_PNG; + m_downloads["/javascript.js"] = IDF_JAVASCRIPT; + +#if 0 + CRegKey key; + CString str(_T("MIME\\Database\\Content Type")); + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, str, KEY_READ)) { + TCHAR buff[256]; + DWORD len = _countof(buff); + for (int i = 0; ERROR_SUCCESS == key.EnumKey(i, buff, &len); i++, len = _countof(buff)) { + CRegKey mime; + TCHAR ext[64]; + ULONG len2 = _countof(ext); + if (ERROR_SUCCESS == mime.Open(HKEY_CLASSES_ROOT, str + _T("\\") + buff, KEY_READ) + && ERROR_SUCCESS == mime.QueryStringValue(_T("Extension"), ext, &len2)) { + m_mimes[CStringA(ext).MakeLower()] = CStringA(buff).MakeLower(); + } + } + } +#endif + + m_mimes[".bmp"] = "image/bmp"; + m_mimes[".css"] = "text/css"; + m_mimes[".gif"] = "image/gif"; + m_mimes[".htm"] = "text/html"; + m_mimes[".html"] = "text/html"; + m_mimes[".jpeg"] = "image/jpeg"; + m_mimes[".jpg"] = "image/jpeg"; + m_mimes[".js"] = "text/javascript"; + m_mimes[".json"] = "text/plain"; + m_mimes[".png"] = "image/png"; + m_mimes[".txt"] = "text/plain"; + m_mimes[".ico"] = "image/x-icon"; +} + +DWORD WINAPI CWebServer::StaticThreadProc(LPVOID lpParam) +{ + SetThreadName(DWORD(-1), "WebServer Thread"); + return ((CWebServer*)lpParam)->ThreadProc(); +} + +DWORD CWebServer::ThreadProc() +{ + if (!AfxSocketInit(nullptr)) { + return DWORD_ERROR; + } + + CWebServerSocket s(this, m_nPort); + + MSG msg; + while ((int)GetMessage(&msg, nullptr, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; +} + +static void PutFileContents(LPCTSTR fn, const CStringA& data) +{ + FILE* f = nullptr; + if (!_tfopen_s(&f, fn, _T("wb"))) { + fwrite((LPCSTR)data, 1, data.GetLength(), f); + fclose(f); + } +} + +void CWebServer::Deploy(CString dir) +{ + CStringA data; + if (LoadResource(IDR_HTML_INDEX, data, RT_HTML)) { + PutFileContents(dir + _T("index.html"), data); + } + if (LoadResource(IDR_HTML_INFO, data, RT_HTML)) { + PutFileContents(dir + _T("info.html"), data); + } + if (LoadResource(IDR_HTML_BROWSER, data, RT_HTML)) { + PutFileContents(dir + _T("browser.html"), data); + } + if (LoadResource(IDR_HTML_CONTROLS, data, RT_HTML)) { + PutFileContents(dir + _T("controls.html"), data); + } + if (LoadResource(IDR_HTML_VARIABLES, data, RT_HTML)) { + PutFileContents(dir + _T("variables.html"), data); + } + if (LoadResource(IDR_HTML_404, data, RT_HTML)) { + PutFileContents(dir + _T("404.html"), data); + } + if (LoadResource(IDR_HTML_PLAYER, data, RT_HTML)) { + PutFileContents(dir + _T("player.html"), data); + } + + // Create the needed folder + CreateDirectory(dir + _T("img"), nullptr); + + POSITION pos = m_downloads.GetStartPosition(); + while (pos) { + CStringA fn; + UINT id; + m_downloads.GetNextAssoc(pos, fn, id); + if (LoadResource(id, data, _T("FILE")) || LoadResource(id, data, _T("PNG"))) { + PutFileContents(dir + AToT(fn), data); + } + } +} + +bool CWebServer::ToLocalPath(CString& path, CString& redir) +{ + if (!path.IsEmpty() && m_webroot.IsDirectory()) { + CString str = path; + str.Replace('/', '\\'); + str.TrimLeft('\\'); + + CPath p; + p.Combine(m_webroot, str); + p.Canonicalize(); + + if (p.IsDirectory()) { + CAtlList sl; + Explode(AfxGetAppSettings().strWebDefIndex, sl, ';'); + POSITION pos = sl.GetHeadPosition(); + while (pos) { + str = sl.GetNext(pos); + CPath p2 = p; + p2.Append(str); + if (p2.FileExists()) { + p = p2; + redir = path; + if (redir.GetAt(redir.GetLength() - 1) != '/') { + redir += _T('/'); + } + redir += str; + break; + } + } + } + + if (_tcslen(p) > _tcslen(m_webroot) && p.FileExists()) { + path = (LPCTSTR)p; + return true; + } + } + + return false; +} + +bool CWebServer::LoadPage(UINT resid, CStringA& str, CString path) +{ + CString redir; + if (ToLocalPath(path, redir)) { + FILE* f = nullptr; + if (!_tfopen_s(&f, path, _T("rb"))) { + fseek(f, 0, 2); + char* buff = str.GetBufferSetLength(ftell(f)); + fseek(f, 0, 0); + int len = (int)fread(buff, 1, str.GetLength(), f); + fclose(f); + return len == str.GetLength(); + } + } + + return LoadResource(resid, str, RT_HTML); +} + +void CWebServer::OnAccept(CWebServerSocket* pServer) +{ + CAutoPtr p(DEBUG_NEW CWebClientSocket(this, m_pMainFrame)); + if (pServer->Accept(*p)) { + CString name; + UINT port; + if (AfxGetAppSettings().fWebServerLocalhostOnly && p->GetPeerName(name, port) && name != _T("127.0.0.1")) { + p->Close(); + return; + } + + m_clients.AddTail(p); + } +} + +void CWebServer::OnClose(const CWebClientSocket* pClient) +{ + POSITION pos = m_clients.GetHeadPosition(); + while (pos) { + POSITION cur = pos; + if (m_clients.GetNext(pos) == pClient) { + m_clients.RemoveAt(cur); + break; + } + } +} + +void CWebServer::OnRequest(CWebClientSocket* pClient, CStringA& hdr, CStringA& body) +{ + const CAppSettings& s = AfxGetAppSettings(); + + CPath p(AToT(pClient->m_path)); + CStringA ext = p.GetExtension().MakeLower(); + CStringA mime; + if (ext.IsEmpty()) { + mime = "text/html"; + } else { + if (!m_mimes.Lookup(ext, mime)) { + mime = "none"; + } + } + + hdr = "HTTP/1.0 200 OK\r\n"; + + bool fHandled = false, fCGI = false; + + if (m_webroot.IsDirectory()) { + CStringA tmphdr; + fHandled = fCGI = CallCGI(pClient, tmphdr, body, mime); + + if (fHandled) { + tmphdr.Replace("\r\n", "\n"); + CAtlList hdrlines; + ExplodeMin(tmphdr, hdrlines, '\n'); + POSITION pos = hdrlines.GetHeadPosition(); + while (pos) { + POSITION cur = pos; + CAtlList sl; + CStringA key = Explode(hdrlines.GetNext(pos), sl, ':', 2); + if (sl.GetCount() < 2) { + continue; + } + key.Trim().MakeLower(); + if (key == "content-type") { + mime = sl.GetTail().Trim(); + hdrlines.RemoveAt(cur); + } else if (key == "content-length") { + hdrlines.RemoveAt(cur); + } + } + tmphdr = Implode(hdrlines, "\r\n"); + hdr += tmphdr + "\r\n"; + } + } + + RequestHandler rh = nullptr; + if (!fHandled && m_internalpages.Lookup(pClient->m_path, rh) && (pClient->*rh)(hdr, body, mime)) { + if (mime.IsEmpty()) { + mime = "text/html"; + } + + CString redir; + if (pClient->m_get.Lookup("redir", redir) + || pClient->m_post.Lookup("redir", redir)) { + if (redir.IsEmpty()) { + redir = '/'; + } + + hdr = + "HTTP/1.0 302 Found\r\n" + "Location: " + CStringA(redir) + "\r\n"; + return; + } + + fHandled = true; + } + + if (!fHandled && m_webroot.IsDirectory()) { + fHandled = LoadPage(0, body, UTF8To16(pClient->m_path)); + } + + UINT resid; + if (!fHandled && m_downloads.Lookup(pClient->m_path, resid) + && (LoadResource(resid, body, _T("FILE")) || LoadResource(resid, body, _T("PNG")))) { + if (mime.IsEmpty()) { + mime = "application/octet-stream"; + } + fHandled = true; + } + + if (!fHandled) { + hdr = mime == "text/html" + ? "HTTP/1.0 301 Moved Permanently\r\n" "Location: /404.html\r\n" + : "HTTP/1.0 404 Not Found\r\n"; + return; + } + + /* Don't cache html, js and css files */ + if ((mime == "text/html" || mime == "text/javascript" || mime == "text/css") && !fCGI) { + if (mime == "text/html") { + hdr += + "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" + "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" + "Pragma: no-cache\r\n"; + + CStringA debug; + if (s.fWebServerPrintDebugInfo) { + debug += "

\r\n";
+
+                CStringA key;
+                POSITION pos;
+
+                {
+                    CStringA value;
+
+                    pos = pClient->m_hdrlines.GetStartPosition();
+                    while (pos) {
+                        pClient->m_hdrlines.GetNextAssoc(pos, key, value);
+                        debug += "HEADER[" + key + "] = " + value + "\r\n";
+                    }
+                }
+                debug += "cmd: " + pClient->m_cmd + "\r\n";
+                debug += "path: " + pClient->m_path + "\r\n";
+                debug += "ver: " + pClient->m_ver + "\r\n";
+
+                {
+                    CString value;
+
+                    pos = pClient->m_get.GetStartPosition();
+                    while (pos) {
+                        pClient->m_get.GetNextAssoc(pos, key, value);
+                        debug += "GET[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
+                    }
+                    pos = pClient->m_post.GetStartPosition();
+                    while (pos) {
+                        pClient->m_post.GetNextAssoc(pos, key, value);
+                        debug += "POST[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
+                    }
+                    pos = pClient->m_cookie.GetStartPosition();
+                    while (pos) {
+                        pClient->m_cookie.GetNextAssoc(pos, key, value);
+                        debug += "COOKIE[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
+                    }
+                    pos = pClient->m_request.GetStartPosition();
+                    while (pos) {
+                        pClient->m_request.GetNextAssoc(pos, key, value);
+                        debug += "REQUEST[" + HtmlSpecialChars(key) + "] = " + HtmlSpecialChars(UTF8(value)) + "\r\n";
+                    }
+                }
+                debug += "
"; + } + body.Replace("[debug]", debug); + } + + body.Replace("[browserpath]", "/browser.html"); + body.Replace("[commandpath]", "/command.html"); + body.Replace("[controlspath]", "/controls.html"); + body.Replace("[indexpath]", "/index.html"); + body.Replace("[path]", pClient->m_path); + body.Replace("[setposcommand]", CMD_SETPOS); + body.Replace("[setvolumecommand]", CMD_SETVOLUME); + body.Replace("[wmcname]", "wm_command"); + // TODO: add more general tags to replace + } + + // gzip + if (s.fWebServerUseCompression && !body.IsEmpty() + && hdr.Find("Content-Encoding:") < 0 && ext != ".png" && ext != ".jpeg" && ext != ".gif") + do { + CStringA accept_encoding; + pClient->m_hdrlines.Lookup("accept-encoding", accept_encoding); + accept_encoding.MakeLower(); + CAtlList sl; + ExplodeMin(accept_encoding, sl, ','); + if (!sl.Find("gzip")) { + break; + } + + // Allocate deflate state + z_stream strm; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) { + ASSERT(0); + break; + } + + int gzippedBuffLen = body.GetLength(); + BYTE* gzippedBuff = DEBUG_NEW BYTE[gzippedBuffLen]; + + // Compress + strm.avail_in = body.GetLength(); + strm.next_in = (Bytef*)(LPCSTR)body; + + strm.avail_out = gzippedBuffLen; + strm.next_out = gzippedBuff; + + ret = deflate(&strm, Z_FINISH); + if (ret != Z_STREAM_END || strm.avail_in != 0) { + ASSERT(0); + deflateEnd(&strm); + delete [] gzippedBuff; + break; + } + gzippedBuffLen -= strm.avail_out; + memcpy(body.GetBufferSetLength(gzippedBuffLen), gzippedBuff, gzippedBuffLen); + + // Clean up + deflateEnd(&strm); + delete [] gzippedBuff; + + hdr += "Content-Encoding: gzip\r\n"; + } while (0); + + CStringA content; + content.Format( + "Content-Type: %s\r\n" + "Content-Length: %d\r\n", + mime.GetString(), body.GetLength()); + hdr += content; +} + +static DWORD WINAPI KillCGI(LPVOID lParam) +{ + HANDLE hProcess = (HANDLE)lParam; + if (WaitForSingleObject(hProcess, 30000) == WAIT_TIMEOUT) { + TerminateProcess(hProcess, 0); + } + return 0; +} + +bool CWebServer::CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime) +{ + CString path = pClient->m_path, redir = path; + if (!ToLocalPath(path, redir)) { + return false; + } + CString ext = CPath(path).GetExtension().MakeLower(); + CPath dir(path); + dir.RemoveFileSpec(); + + CString cgi; + if (!m_cgi.Lookup(ext, cgi) || !CPath(cgi).FileExists()) { + return false; + } + + HANDLE hProcess = GetCurrentProcess(); + HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup = nullptr; + HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup = nullptr; + + SECURITY_ATTRIBUTES saAttr; + ZeroMemory(&saAttr, sizeof(saAttr)); + saAttr.nLength = sizeof(saAttr); + saAttr.bInheritHandle = TRUE; + + if (CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { + BOOL fSuccess = DuplicateHandle(hProcess, hChildStdoutRd, hProcess, &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS); + UNREFERENCED_PARAMETER(fSuccess); + CloseHandle(hChildStdoutRd); + } + + if (CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { + BOOL fSuccess = DuplicateHandle(hProcess, hChildStdinWr, hProcess, &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS); + UNREFERENCED_PARAMETER(fSuccess); + CloseHandle(hChildStdinWr); + } + + STARTUPINFO siStartInfo; + ZeroMemory(&siStartInfo, sizeof(siStartInfo)); + siStartInfo.cb = sizeof(siStartInfo); + siStartInfo.hStdError = hChildStdoutWr; + siStartInfo.hStdOutput = hChildStdoutWr; + siStartInfo.hStdInput = hChildStdinRd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION piProcInfo; + ZeroMemory(&piProcInfo, sizeof(piProcInfo)); + + CStringA envstr; + + LPVOID lpvEnv = GetEnvironmentStrings(); + if (lpvEnv) { + CAtlList env; + for (LPTSTR lpszVariable = (LPTSTR)lpvEnv; *lpszVariable; lpszVariable += _tcslen(lpszVariable) + 1) { + if (lpszVariable != (LPTSTR)lpvEnv) { + env.AddTail(lpszVariable); + } + } + + env.AddTail(_T("GATEWAY_INTERFACE=CGI/1.1")); + env.AddTail(_T("SERVER_SOFTWARE=MPC-HC/") + VersionInfo::GetVersionString()); + env.AddTail(_T("SERVER_PROTOCOL=") + AToT(pClient->m_ver)); + env.AddTail(_T("REQUEST_METHOD=") + AToT(pClient->m_cmd)); + env.AddTail(_T("PATH_INFO=") + redir); + env.AddTail(_T("PATH_TRANSLATED=") + path); + env.AddTail(_T("SCRIPT_NAME=") + redir); + env.AddTail(_T("QUERY_STRING=") + AToT(pClient->m_query)); + + { + CStringA str; + if (pClient->m_hdrlines.Lookup("content-type", str)) { + env.AddTail(_T("CONTENT_TYPE=") + AToT(str)); + } + if (pClient->m_hdrlines.Lookup("content-length", str)) { + env.AddTail(_T("CONTENT_LENGTH=") + AToT(str)); + } + } + + POSITION pos = pClient->m_hdrlines.GetStartPosition(); + while (pos) { + CString key = pClient->m_hdrlines.GetKeyAt(pos); + CString value = pClient->m_hdrlines.GetNextValue(pos); + key.Replace(_T("-"), _T("_")); + key.MakeUpper(); + env.AddTail(_T("HTTP_") + key + _T("=") + value); + } + + CString str, name; + UINT port; + + if (pClient->GetPeerName(name, port)) { + str.Format(_T("%u"), port); + env.AddTail(_T("REMOTE_ADDR=") + name); + env.AddTail(_T("REMOTE_HOST=") + name); + env.AddTail(_T("REMOTE_PORT=") + str); + } + + if (pClient->GetSockName(name, port)) { + str.Format(_T("%u"), port); + env.AddTail(_T("SERVER_NAME=") + name); + env.AddTail(_T("SERVER_PORT=") + str); + } + + env.AddTail(_T("\0")); + + str = Implode(env, '\0'); + envstr = CStringA(str, str.GetLength()); + + FreeEnvironmentStrings((LPTSTR)lpvEnv); + } + + TCHAR* cmdln = DEBUG_NEW TCHAR[32768]; + _sntprintf_s(cmdln, 32768, 32768, _T("\"%s\" \"%s\""), cgi.GetString(), path.GetString()); + + if (hChildStdinRd && hChildStdoutWr) + if (CreateProcess( + nullptr, cmdln, nullptr, nullptr, TRUE, 0, + envstr.GetLength() ? (LPVOID)(LPCSTR)envstr : nullptr, + dir, &siStartInfo, &piProcInfo)) { + DWORD ThreadId; + VERIFY(CreateThread(nullptr, 0, KillCGI, (LPVOID)piProcInfo.hProcess, 0, &ThreadId)); + + static const int BUFFSIZE = 1024; + DWORD dwRead, dwWritten = 0; + + int i = 0, len = pClient->m_data.GetLength(); + for (; i < len; i += dwWritten) { + if (!WriteFile(hChildStdinWrDup, (LPCSTR)pClient->m_data + i, std::min(len - i, BUFFSIZE), &dwWritten, nullptr)) { + break; + } + } + + CloseHandle(hChildStdinWrDup); + CloseHandle(hChildStdoutWr); + + body.Empty(); + + CStringA buff; + while (i == len && ReadFile(hChildStdoutRdDup, buff.GetBuffer(BUFFSIZE), BUFFSIZE, &dwRead, nullptr) && dwRead) { + buff.ReleaseBufferSetLength(dwRead); + body += buff; + } + + int hdrend = body.Find("\r\n\r\n"); + if (hdrend >= 0) { + hdr = body.Left(hdrend + 2); + body = body.Mid(hdrend + 4); + } + + CloseHandle(hChildStdinRd); + CloseHandle(hChildStdoutRdDup); + + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + } else { + body = "CGI Error"; + } + + delete [] cmdln; + + return true; +} diff --git a/src/mpc-hc/WebServer.h b/src/mpc-hc/WebServer.h index 68e40093975..8b7854b38e9 100644 --- a/src/mpc-hc/WebServer.h +++ b/src/mpc-hc/WebServer.h @@ -1,73 +1,73 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014 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 . - * - */ - -#pragma once - -#include -#include -#include - -#define UTF8(str) UTF16To8(TToW(str)) -#define UTF8Arg(str) UrlEncode(UTF8(str)) -#define CMD_SETPOS "-1" -#define CMD_SETVOLUME "-2" - - -class CWebServerSocket; -class CWebClientSocket; -class CMainFrame; - -class CWebServer -{ - CMainFrame* m_pMainFrame; - int m_nPort; - - DWORD ThreadProc(); - static DWORD WINAPI StaticThreadProc(LPVOID lpParam); - DWORD m_ThreadId; - HANDLE m_hThread; - - CAutoPtrList m_clients; - - typedef bool (CWebClientSocket::*RequestHandler)(CStringA& hdr, CStringA& body, CStringA& mime); - static CAtlStringMap m_internalpages; - static CAtlStringMap m_downloads; - static CAtlStringMap m_mimes; - CPath m_webroot; - - CAtlStringMap<> m_cgi; - bool CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime); - -public: - CWebServer(CMainFrame* pMainFrame, int nPort = 13579); - virtual ~CWebServer(); - - static void Init(); - - static void Deploy(CString dir); - - bool ToLocalPath(CString& path, CString& redir); - bool LoadPage(UINT resid, CStringA& str, CString path = _T("")); - - void OnAccept(CWebServerSocket* pServer); - void OnClose(const CWebClientSocket* pClient); - void OnRequest(CWebClientSocket* pClient, CStringA& reshdr, CStringA& resbody); -}; +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014 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 . + * + */ + +#pragma once + +#include +#include +#include + +#define UTF8(str) UTF16To8(TToW(str)) +#define UTF8Arg(str) UrlEncode(UTF8(str)) +#define CMD_SETPOS "-1" +#define CMD_SETVOLUME "-2" + + +class CWebServerSocket; +class CWebClientSocket; +class CMainFrame; + +class CWebServer +{ + CMainFrame* m_pMainFrame; + int m_nPort; + + DWORD ThreadProc(); + static DWORD WINAPI StaticThreadProc(LPVOID lpParam); + DWORD m_ThreadId; + HANDLE m_hThread; + + CAutoPtrList m_clients; + + typedef bool (CWebClientSocket::*RequestHandler)(CStringA& hdr, CStringA& body, CStringA& mime); + static CAtlStringMap m_internalpages; + static CAtlStringMap m_downloads; + static CAtlStringMap m_mimes; + CPath m_webroot; + + CAtlStringMap<> m_cgi; + bool CallCGI(CWebClientSocket* pClient, CStringA& hdr, CStringA& body, CStringA& mime); + +public: + CWebServer(CMainFrame* pMainFrame, int nPort = 13579); + virtual ~CWebServer(); + + static void Init(); + + static void Deploy(CString dir); + + bool ToLocalPath(CString& path, CString& redir); + bool LoadPage(UINT resid, CStringA& str, CString path = _T("")); + + void OnAccept(CWebServerSocket* pServer); + void OnClose(const CWebClientSocket* pClient); + void OnRequest(CWebClientSocket* pClient, CStringA& reshdr, CStringA& resbody); +}; diff --git a/src/mpc-hc/WebServerSocket.cpp b/src/mpc-hc/WebServerSocket.cpp index 274370f3cee..6a73fea73a8 100644 --- a/src/mpc-hc/WebServerSocket.cpp +++ b/src/mpc-hc/WebServerSocket.cpp @@ -1,45 +1,45 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" -#include "WebServer.h" -#include "WebServerSocket.h" - - -CWebServerSocket::CWebServerSocket(CWebServer* pWebServer, int port) - : m_pWebServer(pWebServer) -{ - Create(port); - Listen(); -} - -CWebServerSocket::~CWebServerSocket() -{ -} - -void CWebServerSocket::OnAccept(int nErrorCode) -{ - if (nErrorCode == 0 && m_pWebServer) { - m_pWebServer->OnAccept(this); - } - - __super::OnAccept(nErrorCode); -} +/* + * (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 . + * + */ + +#include "stdafx.h" +#include "WebServer.h" +#include "WebServerSocket.h" + + +CWebServerSocket::CWebServerSocket(CWebServer* pWebServer, int port) + : m_pWebServer(pWebServer) +{ + Create(port); + Listen(); +} + +CWebServerSocket::~CWebServerSocket() +{ +} + +void CWebServerSocket::OnAccept(int nErrorCode) +{ + if (nErrorCode == 0 && m_pWebServer) { + m_pWebServer->OnAccept(this); + } + + __super::OnAccept(nErrorCode); +} diff --git a/src/mpc-hc/WebServerSocket.h b/src/mpc-hc/WebServerSocket.h index d4185924d7b..f1248bb76e6 100644 --- a/src/mpc-hc/WebServerSocket.h +++ b/src/mpc-hc/WebServerSocket.h @@ -1,36 +1,36 @@ -/* - * (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 . - * - */ - -#pragma once - -class CWebServer; - -class CWebServerSocket : public CAsyncSocket -{ - CWebServer* m_pWebServer; - -protected: - void OnAccept(int nErrorCode); - -public: - CWebServerSocket(CWebServer* pWebServer, int port = 13579); - virtual ~CWebServerSocket(); -}; +/* + * (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 . + * + */ + +#pragma once + +class CWebServer; + +class CWebServerSocket : public CAsyncSocket +{ + CWebServer* m_pWebServer; + +protected: + void OnAccept(int nErrorCode); + +public: + CWebServerSocket(CWebServer* pWebServer, int port = 13579); + virtual ~CWebServerSocket(); +}; diff --git a/src/mpc-hc/WinHotkeyCtrl.cpp b/src/mpc-hc/WinHotkeyCtrl.cpp index 3c4620edac6..134d4030aa5 100644 --- a/src/mpc-hc/WinHotkeyCtrl.cpp +++ b/src/mpc-hc/WinHotkeyCtrl.cpp @@ -1,317 +1,317 @@ -/* - * (C) 2011-2014 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 . - * - */ - -#include "stdafx.h" -#include "resource.h" -#include "WinHotkeyCtrl.h" -#include "vkCodes.h" -#include "mplayerc.h" -#include "CMPCThemeButton.h" -#include "CMPCThemeMenu.h" - -#define WM_KEY (WM_USER + 444) - -// CWinHotkeyCtrl - -HHOOK CWinHotkeyCtrl::sm_hhookKb = nullptr; -CWinHotkeyCtrl* CWinHotkeyCtrl::sm_pwhcFocus = nullptr; - - -IMPLEMENT_DYNAMIC(CWinHotkeyCtrl, CEdit) -CWinHotkeyCtrl::CWinHotkeyCtrl() - : m_vkCode(0) - , m_vkCode_def(0) - , m_fModSet(0) - , m_fModRel(0) - , m_fModSet_def(0) - , m_fIsPressed(FALSE) - , isMouseModifier(false) -{ -} - -CWinHotkeyCtrl::~CWinHotkeyCtrl() -{ -} - -BEGIN_MESSAGE_MAP(CWinHotkeyCtrl, CEditWithButton) - ON_MESSAGE(WM_KEY, OnKey) - ON_WM_CHAR() - ON_WM_SETCURSOR() - ON_WM_SETFOCUS() - ON_WM_KILLFOCUS() - ON_WM_CONTEXTMENU() - ON_WM_DESTROY() - ON_MESSAGE(EDIT_BUTTON_LEFTCLICKED, OnLeftClick) -END_MESSAGE_MAP() - -// CWinHotkeyCtrl - -void CWinHotkeyCtrl::PreSubclassWindow() -{ - CEditWithButton::PreSubclassWindow(); - UpdateText(); -} - -LRESULT CALLBACK CWinHotkeyCtrl::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = 1; - - if (nCode == HC_ACTION && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN || - wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && sm_pwhcFocus) { - sm_pwhcFocus->PostMessage(WM_KEY, ((PKBDLLHOOKSTRUCT)lParam)->vkCode, (wParam & 1)); - } - return lResult; -} - -BOOL CWinHotkeyCtrl::InstallKbHook() -{ - if (sm_pwhcFocus && sm_hhookKb) { - sm_pwhcFocus->UninstallKbHook(); - } - sm_pwhcFocus = this; - - sm_hhookKb = ::SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)LowLevelKeyboardProc, GetModuleHandle(nullptr), 0); - - return (sm_hhookKb != nullptr); -} - -BOOL CWinHotkeyCtrl::UninstallKbHook() -{ - BOOL fOk = FALSE; - if (sm_hhookKb) { - fOk = ::UnhookWindowsHookEx(sm_hhookKb); - sm_hhookKb = nullptr; - } - sm_pwhcFocus = nullptr; - return fOk; -} - - -void CWinHotkeyCtrl::UpdateText() -{ - CString sText; - if (isMouseModifier) { - HotkeyToString(0, m_fModSet, sText); - } else { - HotkeyToString(m_vkCode, m_fModSet, sText); - } - SetWindowText((LPCTSTR)sText); - SetSel(0x8fffffff, 0x8fffffff, FALSE); -} - -DWORD CWinHotkeyCtrl::GetWinHotkey() -{ - return MAKEWORD(m_vkCode, m_fModSet); -} - -BOOL CWinHotkeyCtrl::GetWinHotkey(UINT* pvkCode, UINT* pfModifiers) -{ - *pvkCode = m_vkCode; - *pfModifiers = m_fModSet; - return (m_vkCode != 0); -} - -void CWinHotkeyCtrl::SetWinHotkey(DWORD dwHk) -{ - SetWinHotkey(LOBYTE(LOWORD(dwHk)), HIBYTE(LOWORD(dwHk))); -} - -void CWinHotkeyCtrl::SetWinHotkey(UINT vkCode, UINT fModifiers) -{ - m_vkCode = m_vkCode_def = vkCode; - m_fModSet = m_fModSet_def = m_fModRel = fModifiers; - m_fIsPressed = FALSE; - - UpdateText(); -} - -void CWinHotkeyCtrl::DrawButton(CRect rectButton) -{ - if (AppIsThemeLoaded()) { - CWindowDC dc(this); - bool disabled = 0 != (GetStyle() & (ES_READONLY | WS_DISABLED)); - bool selected = GetButtonThemeState() == PBS_PRESSED; - bool highlighted = GetButtonThemeState() == PBS_HOT; - CFont* pOldFont = dc.SelectObject(GetFont()); - CMPCThemeButton::drawButtonBase(&dc, rectButton, GetButtonText(), selected, highlighted, false, disabled, true, false); - dc.SelectObject(pOldFont); - } else { - __super::DrawButton(rectButton); - } -} - -LRESULT CWinHotkeyCtrl::OnKey(WPARAM wParam, LPARAM lParam) -{ - DWORD fMod = 0; - BOOL fRedraw = TRUE; - - switch (wParam) { - case VK_CONTROL: - case VK_LCONTROL: - case VK_RCONTROL: - fMod = MOD_CONTROL; - break; - case VK_MENU: - case VK_LMENU: - case VK_RMENU: - fMod = MOD_ALT; - break; - case VK_SHIFT: - case VK_LSHIFT: - case VK_RSHIFT: - fMod = MOD_SHIFT; - break; - } - - if (fMod) { // modifier - if (!lParam) { // press - if (!m_fIsPressed && m_vkCode) { - m_fModSet = m_fModRel = 0; - m_vkCode = 0; - } - m_fModRel &= ~fMod; - } else if (m_fModSet & fMod) { // release - m_fModRel |= fMod; - } - - if (m_fIsPressed || !m_vkCode) { - if (!lParam) { // press - if (!(m_fModSet & fMod)) { // new modifier - m_fModSet |= fMod; - } else { - fRedraw = FALSE; - } - } else { - m_fModSet &= ~fMod; - } - } - } else { // another key - if (wParam == VK_DELETE && m_fModSet == (MOD_CONTROL | MOD_ALT) // skip "Ctrl+Alt+Del" - || wParam == VK_LWIN || wParam == VK_RWIN // skip "Win" - || wParam == VK_SNAPSHOT // skip "PrintScreen" - || wParam == VK_ESCAPE && (m_fModSet == MOD_CONTROL || m_fModSet == MOD_ALT) // skip "Ctrl+Esc", "Alt+Esc" - || wParam == VK_TAB && m_fModSet == MOD_ALT) { // skip "Alt+Tab" - m_fModSet = m_fModRel = 0; - m_vkCode = 0; - m_fIsPressed = FALSE; - } else if (wParam == m_vkCode && lParam) { - m_fIsPressed = FALSE; - fRedraw = FALSE; - } else { - if (!m_fIsPressed && !lParam) { // pressed a another key - if (m_fModRel & m_fModSet) { - m_fModSet = m_fModRel = 0; - } - m_vkCode = (UINT)wParam; - m_fIsPressed = TRUE; - } - } - } - if (fRedraw) { - UpdateText(); - } - - return 0L; -} - -LRESULT CWinHotkeyCtrl::OnLeftClick(WPARAM wParam, LPARAM lParam) -{ - CRect r; - CPoint pt; - CEditWithButton::GetWindowRect(r); - CRect rectButton = GetButtonRect(r); - pt = rectButton.BottomRight(); - pt.x = pt.x - (rectButton.Width()); - OnContextMenu(this, pt); - return 0; -} - -// CWinHotkeyCtrl message handlers - -void CWinHotkeyCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) -{ -} - -BOOL CWinHotkeyCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) -{ - return FALSE; -} - -void CWinHotkeyCtrl::OnSetFocus(CWnd* pOldWnd) -{ - InstallKbHook(); - CEditWithButton::OnSetFocus(pOldWnd); -} - -void CWinHotkeyCtrl::OnKillFocus(CWnd* pNewWnd) -{ - UninstallKbHook(); - CEditWithButton::OnKillFocus(pNewWnd); -} - -void CWinHotkeyCtrl::OnContextMenu(CWnd*, CPoint pt) -{ - CMPCThemeMenu menu; - menu.CreatePopupMenu(); - UINT cod = 0, mod = 0; - menu.AppendMenu(MF_STRING, 1, ResStr(IDS_APPLY)); - menu.AppendMenu(MF_STRING, 2, ResStr(IDS_CLEAR)); - menu.AppendMenu(MF_STRING, 3, ResStr(IDS_CANCEL)); - if (AppNeedsThemedControls()) { - menu.fulfillThemeReqs(); - } - - UINT uMenuID = menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_VERPOSANIMATION | TPM_NONOTIFY | TPM_RETURNCMD, - pt.x, pt.y, this, nullptr); - - if (uMenuID) { - switch (uMenuID) { - case 1: - GetWinHotkey(&cod, &mod); - if (cod == 0 || m_vkCode == 0) { - mod = m_fModSet = m_fModRel = 0; - } - SetWinHotkey(cod, mod); - m_fIsPressed = FALSE; - break; - case 2: - m_fModSet = m_fModRel = 0; - m_vkCode = 0; - m_fIsPressed = FALSE; - break; - case 3: - m_fModSet = m_fModRel = m_fModSet_def; - m_vkCode = m_vkCode_def; - m_fIsPressed = FALSE; - break; - } - UpdateText(); - GetParent() ->SetFocus(); - } - -} - -void CWinHotkeyCtrl::OnDestroy() -{ - if (sm_pwhcFocus == this) { - sm_pwhcFocus->UninstallKbHook(); - } - CEditWithButton::OnDestroy(); -} +/* + * (C) 2011-2014 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 . + * + */ + +#include "stdafx.h" +#include "resource.h" +#include "WinHotkeyCtrl.h" +#include "vkCodes.h" +#include "mplayerc.h" +#include "CMPCThemeButton.h" +#include "CMPCThemeMenu.h" + +#define WM_KEY (WM_USER + 444) + +// CWinHotkeyCtrl + +HHOOK CWinHotkeyCtrl::sm_hhookKb = nullptr; +CWinHotkeyCtrl* CWinHotkeyCtrl::sm_pwhcFocus = nullptr; + + +IMPLEMENT_DYNAMIC(CWinHotkeyCtrl, CEdit) +CWinHotkeyCtrl::CWinHotkeyCtrl() + : m_vkCode(0) + , m_vkCode_def(0) + , m_fModSet(0) + , m_fModRel(0) + , m_fModSet_def(0) + , m_fIsPressed(FALSE) + , isMouseModifier(false) +{ +} + +CWinHotkeyCtrl::~CWinHotkeyCtrl() +{ +} + +BEGIN_MESSAGE_MAP(CWinHotkeyCtrl, CEditWithButton) + ON_MESSAGE(WM_KEY, OnKey) + ON_WM_CHAR() + ON_WM_SETCURSOR() + ON_WM_SETFOCUS() + ON_WM_KILLFOCUS() + ON_WM_CONTEXTMENU() + ON_WM_DESTROY() + ON_MESSAGE(EDIT_BUTTON_LEFTCLICKED, OnLeftClick) +END_MESSAGE_MAP() + +// CWinHotkeyCtrl + +void CWinHotkeyCtrl::PreSubclassWindow() +{ + CEditWithButton::PreSubclassWindow(); + UpdateText(); +} + +LRESULT CALLBACK CWinHotkeyCtrl::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = 1; + + if (nCode == HC_ACTION && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN || + wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && sm_pwhcFocus) { + sm_pwhcFocus->PostMessage(WM_KEY, ((PKBDLLHOOKSTRUCT)lParam)->vkCode, (wParam & 1)); + } + return lResult; +} + +BOOL CWinHotkeyCtrl::InstallKbHook() +{ + if (sm_pwhcFocus && sm_hhookKb) { + sm_pwhcFocus->UninstallKbHook(); + } + sm_pwhcFocus = this; + + sm_hhookKb = ::SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)LowLevelKeyboardProc, GetModuleHandle(nullptr), 0); + + return (sm_hhookKb != nullptr); +} + +BOOL CWinHotkeyCtrl::UninstallKbHook() +{ + BOOL fOk = FALSE; + if (sm_hhookKb) { + fOk = ::UnhookWindowsHookEx(sm_hhookKb); + sm_hhookKb = nullptr; + } + sm_pwhcFocus = nullptr; + return fOk; +} + + +void CWinHotkeyCtrl::UpdateText() +{ + CString sText; + if (isMouseModifier) { + HotkeyToString(0, m_fModSet, sText); + } else { + HotkeyToString(m_vkCode, m_fModSet, sText); + } + SetWindowText((LPCTSTR)sText); + SetSel(0x8fffffff, 0x8fffffff, FALSE); +} + +DWORD CWinHotkeyCtrl::GetWinHotkey() +{ + return MAKEWORD(m_vkCode, m_fModSet); +} + +BOOL CWinHotkeyCtrl::GetWinHotkey(UINT* pvkCode, UINT* pfModifiers) +{ + *pvkCode = m_vkCode; + *pfModifiers = m_fModSet; + return (m_vkCode != 0); +} + +void CWinHotkeyCtrl::SetWinHotkey(DWORD dwHk) +{ + SetWinHotkey(LOBYTE(LOWORD(dwHk)), HIBYTE(LOWORD(dwHk))); +} + +void CWinHotkeyCtrl::SetWinHotkey(UINT vkCode, UINT fModifiers) +{ + m_vkCode = m_vkCode_def = vkCode; + m_fModSet = m_fModSet_def = m_fModRel = fModifiers; + m_fIsPressed = FALSE; + + UpdateText(); +} + +void CWinHotkeyCtrl::DrawButton(CRect rectButton) +{ + if (AppIsThemeLoaded()) { + CWindowDC dc(this); + bool disabled = 0 != (GetStyle() & (ES_READONLY | WS_DISABLED)); + bool selected = GetButtonThemeState() == PBS_PRESSED; + bool highlighted = GetButtonThemeState() == PBS_HOT; + CFont* pOldFont = dc.SelectObject(GetFont()); + CMPCThemeButton::drawButtonBase(&dc, rectButton, GetButtonText(), selected, highlighted, false, disabled, true, false); + dc.SelectObject(pOldFont); + } else { + __super::DrawButton(rectButton); + } +} + +LRESULT CWinHotkeyCtrl::OnKey(WPARAM wParam, LPARAM lParam) +{ + DWORD fMod = 0; + BOOL fRedraw = TRUE; + + switch (wParam) { + case VK_CONTROL: + case VK_LCONTROL: + case VK_RCONTROL: + fMod = MOD_CONTROL; + break; + case VK_MENU: + case VK_LMENU: + case VK_RMENU: + fMod = MOD_ALT; + break; + case VK_SHIFT: + case VK_LSHIFT: + case VK_RSHIFT: + fMod = MOD_SHIFT; + break; + } + + if (fMod) { // modifier + if (!lParam) { // press + if (!m_fIsPressed && m_vkCode) { + m_fModSet = m_fModRel = 0; + m_vkCode = 0; + } + m_fModRel &= ~fMod; + } else if (m_fModSet & fMod) { // release + m_fModRel |= fMod; + } + + if (m_fIsPressed || !m_vkCode) { + if (!lParam) { // press + if (!(m_fModSet & fMod)) { // new modifier + m_fModSet |= fMod; + } else { + fRedraw = FALSE; + } + } else { + m_fModSet &= ~fMod; + } + } + } else { // another key + if (wParam == VK_DELETE && m_fModSet == (MOD_CONTROL | MOD_ALT) // skip "Ctrl+Alt+Del" + || wParam == VK_LWIN || wParam == VK_RWIN // skip "Win" + || wParam == VK_SNAPSHOT // skip "PrintScreen" + || wParam == VK_ESCAPE && (m_fModSet == MOD_CONTROL || m_fModSet == MOD_ALT) // skip "Ctrl+Esc", "Alt+Esc" + || wParam == VK_TAB && m_fModSet == MOD_ALT) { // skip "Alt+Tab" + m_fModSet = m_fModRel = 0; + m_vkCode = 0; + m_fIsPressed = FALSE; + } else if (wParam == m_vkCode && lParam) { + m_fIsPressed = FALSE; + fRedraw = FALSE; + } else { + if (!m_fIsPressed && !lParam) { // pressed a another key + if (m_fModRel & m_fModSet) { + m_fModSet = m_fModRel = 0; + } + m_vkCode = (UINT)wParam; + m_fIsPressed = TRUE; + } + } + } + if (fRedraw) { + UpdateText(); + } + + return 0L; +} + +LRESULT CWinHotkeyCtrl::OnLeftClick(WPARAM wParam, LPARAM lParam) +{ + CRect r; + CPoint pt; + CEditWithButton::GetWindowRect(r); + CRect rectButton = GetButtonRect(r); + pt = rectButton.BottomRight(); + pt.x = pt.x - (rectButton.Width()); + OnContextMenu(this, pt); + return 0; +} + +// CWinHotkeyCtrl message handlers + +void CWinHotkeyCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +{ +} + +BOOL CWinHotkeyCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +{ + return FALSE; +} + +void CWinHotkeyCtrl::OnSetFocus(CWnd* pOldWnd) +{ + InstallKbHook(); + CEditWithButton::OnSetFocus(pOldWnd); +} + +void CWinHotkeyCtrl::OnKillFocus(CWnd* pNewWnd) +{ + UninstallKbHook(); + CEditWithButton::OnKillFocus(pNewWnd); +} + +void CWinHotkeyCtrl::OnContextMenu(CWnd*, CPoint pt) +{ + CMPCThemeMenu menu; + menu.CreatePopupMenu(); + UINT cod = 0, mod = 0; + menu.AppendMenu(MF_STRING, 1, ResStr(IDS_APPLY)); + menu.AppendMenu(MF_STRING, 2, ResStr(IDS_CLEAR)); + menu.AppendMenu(MF_STRING, 3, ResStr(IDS_CANCEL)); + if (AppNeedsThemedControls()) { + menu.fulfillThemeReqs(); + } + + UINT uMenuID = menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_VERPOSANIMATION | TPM_NONOTIFY | TPM_RETURNCMD, + pt.x, pt.y, this, nullptr); + + if (uMenuID) { + switch (uMenuID) { + case 1: + GetWinHotkey(&cod, &mod); + if (cod == 0 || m_vkCode == 0) { + mod = m_fModSet = m_fModRel = 0; + } + SetWinHotkey(cod, mod); + m_fIsPressed = FALSE; + break; + case 2: + m_fModSet = m_fModRel = 0; + m_vkCode = 0; + m_fIsPressed = FALSE; + break; + case 3: + m_fModSet = m_fModRel = m_fModSet_def; + m_vkCode = m_vkCode_def; + m_fIsPressed = FALSE; + break; + } + UpdateText(); + GetParent() ->SetFocus(); + } + +} + +void CWinHotkeyCtrl::OnDestroy() +{ + if (sm_pwhcFocus == this) { + sm_pwhcFocus->UninstallKbHook(); + } + CEditWithButton::OnDestroy(); +} diff --git a/src/mpc-hc/WinHotkeyCtrl.h b/src/mpc-hc/WinHotkeyCtrl.h index 2147ff33cde..6609a14c154 100644 --- a/src/mpc-hc/WinHotkeyCtrl.h +++ b/src/mpc-hc/WinHotkeyCtrl.h @@ -1,72 +1,72 @@ -/* - * (C) 2011-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 . - * - */ - -#pragma once - -#include "EditWithButton.h" - -// CWinHotkeyCtrl - -class CWinHotkeyCtrl : public CEditWithButton -{ - DECLARE_DYNAMIC(CWinHotkeyCtrl) - -public: - CWinHotkeyCtrl(); - virtual ~CWinHotkeyCtrl(); - - void UpdateText(); - DWORD GetWinHotkey(); - BOOL GetWinHotkey(UINT* pvkCode, UINT* pfModifiers); - void SetWinHotkey(DWORD dwHk); - void SetWinHotkey(UINT vkCode, UINT fModifiers); - virtual void DrawButton(CRect rectButton); - void SetIsMouseModifier(bool _isMouseModifier) { isMouseModifier = _isMouseModifier; }; - -private: - static HHOOK sm_hhookKb; - static CWinHotkeyCtrl* sm_pwhcFocus; - bool isMouseModifier; - - UINT m_vkCode, m_vkCode_def; - DWORD m_fModSet, m_fModRel, m_fModSet_def; - BOOL m_fIsPressed; - -private: - BOOL InstallKbHook(); - BOOL UninstallKbHook(); - - static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); - - afx_msg LRESULT OnKey(WPARAM wParam, LPARAM lParam); - -protected: - DECLARE_MESSAGE_MAP() -public: - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); - afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); - afx_msg void OnSetFocus(CWnd* pOldWnd); - afx_msg void OnKillFocus(CWnd* pNewWnd); - afx_msg void OnContextMenu(CWnd*, CPoint pt); - afx_msg void OnDestroy(); - afx_msg LRESULT OnLeftClick(WPARAM wParam, LPARAM lParam); -protected: - virtual void PreSubclassWindow(); -}; +/* + * (C) 2011-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 . + * + */ + +#pragma once + +#include "EditWithButton.h" + +// CWinHotkeyCtrl + +class CWinHotkeyCtrl : public CEditWithButton +{ + DECLARE_DYNAMIC(CWinHotkeyCtrl) + +public: + CWinHotkeyCtrl(); + virtual ~CWinHotkeyCtrl(); + + void UpdateText(); + DWORD GetWinHotkey(); + BOOL GetWinHotkey(UINT* pvkCode, UINT* pfModifiers); + void SetWinHotkey(DWORD dwHk); + void SetWinHotkey(UINT vkCode, UINT fModifiers); + virtual void DrawButton(CRect rectButton); + void SetIsMouseModifier(bool _isMouseModifier) { isMouseModifier = _isMouseModifier; }; + +private: + static HHOOK sm_hhookKb; + static CWinHotkeyCtrl* sm_pwhcFocus; + bool isMouseModifier; + + UINT m_vkCode, m_vkCode_def; + DWORD m_fModSet, m_fModRel, m_fModSet_def; + BOOL m_fIsPressed; + +private: + BOOL InstallKbHook(); + BOOL UninstallKbHook(); + + static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); + + afx_msg LRESULT OnKey(WPARAM wParam, LPARAM lParam); + +protected: + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnKillFocus(CWnd* pNewWnd); + afx_msg void OnContextMenu(CWnd*, CPoint pt); + afx_msg void OnDestroy(); + afx_msg LRESULT OnLeftClick(WPARAM wParam, LPARAM lParam); +protected: + virtual void PreSubclassWindow(); +}; diff --git a/src/mpc-hc/mpc-hc.vcxproj b/src/mpc-hc/mpc-hc.vcxproj index 8641c298138..b1b0de618f7 100644 --- a/src/mpc-hc/mpc-hc.vcxproj +++ b/src/mpc-hc/mpc-hc.vcxproj @@ -1,843 +1,843 @@ - - - - - Debug Lite - Win32 - - - Debug Lite - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release Lite - Win32 - - - Release Lite - x64 - - - Release - Win32 - - - Release - x64 - - - - mpc-hc - {8CE7E5D0-C821-47AC-A247-28EC95B34670} - mpc-hc - MFCProj - - - - - Application - Static - Unicode - - - - - - - - - - - $(SolutionDir)bin\mpc-hc_x86_$(Configuration)\ - $(SolutionDir)bin\mpc-hc_x86_$(Configuration)\ - $(SolutionDir)bin\mpc-hc_x64_$(Configuration)\ - $(SolutionDir)bin\mpc-hc_x64_$(Configuration)\ - $(SolutionDir)bin\mpc-hc_x86\ - $(SolutionDir)bin\mpc-hc_x86 Lite\ - $(SolutionDir)bin\mpc-hc_x64\ - $(SolutionDir)bin\mpc-hc_x64 Lite\ - $(ProjectName)64 - - - - ..\..\include;%(AdditionalIncludeDirectories) - - - crypt32.lib;delayimp.lib;dsound.lib;dxguid.lib;GdiPlus.lib;Psapi.lib;SetupAPI.lib;UxTheme.lib;Vfw32.lib;Winmm.lib;dwmapi.lib;strmiids.lib;Uuid.Lib;Version.lib;Bcrypt.lib;RuntimeObject.lib;%(AdditionalDependencies) - psapi.dll;api-ms-win-shcore-stream-winrt-l1-1-0.dll;api-ms-win-core-winrt-l1-1-0.dll;api-ms-win-core-winrt-string-l1-1-0.dll;%(DelayLoadDLLs) - true - - - ..\..\include;..\DSUtil;..\filters\renderer\VideoRenderers;..\thirdparty;..\thirdparty\AudioTools;..\thirdparty\MediaInfo\library\Source;..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) - - - $(ProjectDir)res\mpc-hc.exe.manifest %(AdditionalManifestFiles) - false - - - - - $(SolutionDir)lib64;$(SolutionDir)src\thirdparty\LAVFilters\src\thirdparty\64\lib;%(AdditionalLibraryDirectories) - - - - - $(SolutionDir)lib;$(SolutionDir)src\thirdparty\LAVFilters\src\thirdparty\32\lib;%(AdditionalLibraryDirectories) - - - - - $(SolutionDir)bin\lib\Release_$(Platform);%(AdditionalLibraryDirectories) - msvcrt.lib;vcruntime.lib;ucrt.lib - - - 26812 - NDEBUG;%(PreprocessorDefinitions) - USE_DRDUMP_CRASH_REPORTER=1;%(PreprocessorDefinitions) - - - - - 26812 - - - $(SolutionDir)bin\lib\Debug_$(Platform);%(AdditionalLibraryDirectories) - - - - - AudioSwitcher.lib;BaseClasses.lib;BaseMuxer.lib;BufferFilter.lib;CmdUI.lib;DeCSS.lib;DSMMuxer.lib;DSUtil.lib;Filters.lib;kasumi.lib;LCDUI.lib;lcms2.lib;MatroskaMuxer.lib;ResizableLib.lib;sizecbar.lib;StreamDriveThru.lib;SubPic.lib;Subtitles.lib;SubtitleSource.lib;SyncClock.lib;system.lib;TreePropSheet.lib;unrar.lib;VideoRenderers.lib;WavDest.lib;zlib.lib;minhook.lib;tinyxml2.lib;RARFileSource.lib;MpcAudioRenderer.lib;AudioTools.lib;ffmpeg.lib;freetype2.lib;%(AdditionalDependencies) - - - MPCHC_LITE;%(PreprocessorDefinitions) - - - false - - - - - RARFileSource.res;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ICO - - - ICO - - - ICO - - - ICO - - - - true - - - true - - - true - - - true - - - true - - - true - - - BMP - - - RC2 - - - RC2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {981574ae-5a5e-4f27-bdf1-1b841e374cff} - - - {1a2dfd1a-3c6c-44d1-909d-294af646b575} - - - {fc70988b-1ae5-4381-866d-4f405e28ac42} - - - {1b6de4c0-9d27-4150-a327-e7f3b492b5f0} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {273b3149-3192-4b75-a791-470320b90812} - - - {db5f93b2-54d0-4474-a588-d259be36c832} - - - {65361c7c-83d6-42e4-870c-4dc85ae641fe} - - - {67827491-8162-4039-9132-f934abc836a0} - - - {eb202b68-8029-4985-b914-e94b44d2e230} - - - {37768b3f-89bc-4c16-b2a8-767c5da84c3f} - - - {1e91f58c-0bae-4021-8087-d1864d8ec066} - - - {ae399b7e-2b2c-4a96-9016-c5c74b0a2fa0} - - - {9f31d122-e84d-485a-a58d-09dad01a56ce} - - - {543d40e9-8ca6-4e4b-9936-90cba562b268} - - - {4d3b4ff4-535a-4201-ab7d-9aec1e737a95} - - - {664e726b-eeee-403a-ac15-345d9c9e1375} - - - {0b63409d-674d-47f8-a84e-87dbb7783189} - - - {fb565a7a-50dc-4a0d-852d-5e7f74dab82c} - - - {f50e74c2-5be7-4c9b-b1e7-6ca19cfad34e} - - - {8f998497-9c51-4faa-83e4-1d85b22cba13} - - - {d8db3e7e-d50e-4ec3-a9b9-dad18f5fe466} - - - {9dcfd02a-16a0-4766-bc18-66163e21929d} - - - {f6b06383-3ffd-403b-9867-4aa82a20aa83} - - - {d514ea4d-eafb-47a9-a437-a582ca571251} - - - {5e56335f-0fb1-4eea-b240-d8dc5e0608e4} - - - {0fd9bf8f-2397-4e23-b41e-e4624f35d646} - false - true - false - true - false - - - {438286b7-a9f4-411d-bcc5-948c40e37d8f} - - - {dbf1e8f7-5b7d-4cbf-842a-b7e0c02520dc} - - - {78b079bd-9fc7-4b9e-b4a6-96da0f00248b} - - - {08091723-a142-478b-a092-20741ba8fae2} - - - {9db795b7-e8bd-4846-82a5-c6d2577b1aaf} - - - {acf5c64b-78aa-4730-91a2-24f4910fbad9} - - - {19677dfd-c020-434d-9cb1-d0f105e72770} - - - {1704ea01-6b21-4362-9f1f-44d25cf2e0d7} - - - {85763f39-23df-4c04-b7df-7fbe3e7cf336} - - - {cfe70273-7a79-4815-af95-1e02e2675e37} - - - {d0620ef4-1313-40d5-9069-a82f6fe26994} - - - {2b7f22d7-1750-47c5-8709-1a3688b62499} - - - {bb2b61af-734a-4dad-9326-07f4f9ea088f} - false - true - false - true - false - - - {4c7a1953-cbc4-42d5-a12f-bb512c64b547} - false - true - false - true - false - - - {7cbde5a1-9cbb-4139-93f5-09d8dba4427f} - false - true - false - true - false - - - {e02f0c35-fb01-4059-90f9-9ac19dc22fba} - - - {da8461c4-7683-4360-9372-2a9e0f1795c2} - - - {0d252872-7542-4232-8d02-53f9182aee15} - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - {f3d02050-f39a-4103-8343-09285359a495} - false - true - false - true - false - - - {2fcd4b66-9cf9-4c8f-bc70-37cd20002d49} - - - {03208025-d5c2-426a-b0fa-251d4338f30c} - - - {476b97b4-f079-4a44-af89-52ca30c35e28} - - - {4cc7ae86-3e0a-430a-bff4-bf00204cafb0} - - - {61e6eb4d-2f1a-443b-94b0-e8200b26e99f} - - - {ab494732-ef6d-44d0-bcf8-80ff04858d10} - - - {303B855A-137D-45E9-AF6D-B7241C6E66D6} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug Lite + Win32 + + + Debug Lite + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Lite + Win32 + + + Release Lite + x64 + + + Release + Win32 + + + Release + x64 + + + + mpc-hc + {8CE7E5D0-C821-47AC-A247-28EC95B34670} + mpc-hc + MFCProj + + + + + Application + Static + Unicode + + + + + + + + + + + $(SolutionDir)bin\mpc-hc_x86_$(Configuration)\ + $(SolutionDir)bin\mpc-hc_x86_$(Configuration)\ + $(SolutionDir)bin\mpc-hc_x64_$(Configuration)\ + $(SolutionDir)bin\mpc-hc_x64_$(Configuration)\ + $(SolutionDir)bin\mpc-hc_x86\ + $(SolutionDir)bin\mpc-hc_x86 Lite\ + $(SolutionDir)bin\mpc-hc_x64\ + $(SolutionDir)bin\mpc-hc_x64 Lite\ + $(ProjectName)64 + + + + ..\..\include;%(AdditionalIncludeDirectories) + + + crypt32.lib;delayimp.lib;dsound.lib;dxguid.lib;GdiPlus.lib;Psapi.lib;SetupAPI.lib;UxTheme.lib;Vfw32.lib;Winmm.lib;dwmapi.lib;strmiids.lib;Uuid.Lib;Version.lib;Bcrypt.lib;RuntimeObject.lib;%(AdditionalDependencies) + psapi.dll;api-ms-win-shcore-stream-winrt-l1-1-0.dll;api-ms-win-core-winrt-l1-1-0.dll;api-ms-win-core-winrt-string-l1-1-0.dll;%(DelayLoadDLLs) + true + + + ..\..\include;..\DSUtil;..\filters\renderer\VideoRenderers;..\thirdparty;..\thirdparty\AudioTools;..\thirdparty\MediaInfo\library\Source;..\thirdparty\freetype2\freetype2\include;%(AdditionalIncludeDirectories) + + + $(ProjectDir)res\mpc-hc.exe.manifest %(AdditionalManifestFiles) + false + + + + + $(SolutionDir)lib64;$(SolutionDir)src\thirdparty\LAVFilters\src\thirdparty\64\lib;%(AdditionalLibraryDirectories) + + + + + $(SolutionDir)lib;$(SolutionDir)src\thirdparty\LAVFilters\src\thirdparty\32\lib;%(AdditionalLibraryDirectories) + + + + + $(SolutionDir)bin\lib\Release_$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;vcruntime.lib;ucrt.lib + + + 26812 + NDEBUG;%(PreprocessorDefinitions) + USE_DRDUMP_CRASH_REPORTER=1;%(PreprocessorDefinitions) + + + + + 26812 + + + $(SolutionDir)bin\lib\Debug_$(Platform);%(AdditionalLibraryDirectories) + + + + + AudioSwitcher.lib;BaseClasses.lib;BaseMuxer.lib;BufferFilter.lib;CmdUI.lib;DeCSS.lib;DSMMuxer.lib;DSUtil.lib;Filters.lib;kasumi.lib;LCDUI.lib;lcms2.lib;MatroskaMuxer.lib;ResizableLib.lib;sizecbar.lib;StreamDriveThru.lib;SubPic.lib;Subtitles.lib;SubtitleSource.lib;SyncClock.lib;system.lib;TreePropSheet.lib;unrar.lib;VideoRenderers.lib;WavDest.lib;zlib.lib;minhook.lib;tinyxml2.lib;RARFileSource.lib;MpcAudioRenderer.lib;AudioTools.lib;ffmpeg.lib;freetype2.lib;%(AdditionalDependencies) + + + MPCHC_LITE;%(PreprocessorDefinitions) + + + false + + + + + RARFileSource.res;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICO + + + ICO + + + ICO + + + ICO + + + + true + + + true + + + true + + + true + + + true + + + true + + + BMP + + + RC2 + + + RC2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {981574ae-5a5e-4f27-bdf1-1b841e374cff} + + + {1a2dfd1a-3c6c-44d1-909d-294af646b575} + + + {fc70988b-1ae5-4381-866d-4f405e28ac42} + + + {1b6de4c0-9d27-4150-a327-e7f3b492b5f0} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {273b3149-3192-4b75-a791-470320b90812} + + + {db5f93b2-54d0-4474-a588-d259be36c832} + + + {65361c7c-83d6-42e4-870c-4dc85ae641fe} + + + {67827491-8162-4039-9132-f934abc836a0} + + + {eb202b68-8029-4985-b914-e94b44d2e230} + + + {37768b3f-89bc-4c16-b2a8-767c5da84c3f} + + + {1e91f58c-0bae-4021-8087-d1864d8ec066} + + + {ae399b7e-2b2c-4a96-9016-c5c74b0a2fa0} + + + {9f31d122-e84d-485a-a58d-09dad01a56ce} + + + {543d40e9-8ca6-4e4b-9936-90cba562b268} + + + {4d3b4ff4-535a-4201-ab7d-9aec1e737a95} + + + {664e726b-eeee-403a-ac15-345d9c9e1375} + + + {0b63409d-674d-47f8-a84e-87dbb7783189} + + + {fb565a7a-50dc-4a0d-852d-5e7f74dab82c} + + + {f50e74c2-5be7-4c9b-b1e7-6ca19cfad34e} + + + {8f998497-9c51-4faa-83e4-1d85b22cba13} + + + {d8db3e7e-d50e-4ec3-a9b9-dad18f5fe466} + + + {9dcfd02a-16a0-4766-bc18-66163e21929d} + + + {f6b06383-3ffd-403b-9867-4aa82a20aa83} + + + {d514ea4d-eafb-47a9-a437-a582ca571251} + + + {5e56335f-0fb1-4eea-b240-d8dc5e0608e4} + + + {0fd9bf8f-2397-4e23-b41e-e4624f35d646} + false + true + false + true + false + + + {438286b7-a9f4-411d-bcc5-948c40e37d8f} + + + {dbf1e8f7-5b7d-4cbf-842a-b7e0c02520dc} + + + {78b079bd-9fc7-4b9e-b4a6-96da0f00248b} + + + {08091723-a142-478b-a092-20741ba8fae2} + + + {9db795b7-e8bd-4846-82a5-c6d2577b1aaf} + + + {acf5c64b-78aa-4730-91a2-24f4910fbad9} + + + {19677dfd-c020-434d-9cb1-d0f105e72770} + + + {1704ea01-6b21-4362-9f1f-44d25cf2e0d7} + + + {85763f39-23df-4c04-b7df-7fbe3e7cf336} + + + {cfe70273-7a79-4815-af95-1e02e2675e37} + + + {d0620ef4-1313-40d5-9069-a82f6fe26994} + + + {2b7f22d7-1750-47c5-8709-1a3688b62499} + + + {bb2b61af-734a-4dad-9326-07f4f9ea088f} + false + true + false + true + false + + + {4c7a1953-cbc4-42d5-a12f-bb512c64b547} + false + true + false + true + false + + + {7cbde5a1-9cbb-4139-93f5-09d8dba4427f} + false + true + false + true + false + + + {e02f0c35-fb01-4059-90f9-9ac19dc22fba} + + + {da8461c4-7683-4360-9372-2a9e0f1795c2} + + + {0d252872-7542-4232-8d02-53f9182aee15} + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + {f3d02050-f39a-4103-8343-09285359a495} + false + true + false + true + false + + + {2fcd4b66-9cf9-4c8f-bc70-37cd20002d49} + + + {03208025-d5c2-426a-b0fa-251d4338f30c} + + + {476b97b4-f079-4a44-af89-52ca30c35e28} + + + {4cc7ae86-3e0a-430a-bff4-bf00204cafb0} + + + {61e6eb4d-2f1a-443b-94b0-e8200b26e99f} + + + {ab494732-ef6d-44d0-bcf8-80ff04858d10} + + + {303B855A-137D-45E9-AF6D-B7241C6E66D6} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/mpc-hc/mpc-hc.vcxproj.filters b/src/mpc-hc/mpc-hc.vcxproj.filters index b1cb82c3350..0eed9ce49c5 100644 --- a/src/mpc-hc/mpc-hc.vcxproj.filters +++ b/src/mpc-hc/mpc-hc.vcxproj.filters @@ -1,1477 +1,1477 @@ - - - - - {43c75f5f-5e94-4d15-8f45-b39b7c36bd62} - - - {77a009db-eea1-41f2-8671-661a4843634e} - - - {36ad4cd9-ded8-4c35-8a6d-1ffb3ddc2684} - - - {ad577ec8-11b8-4fcf-8b57-72f6cdabf032} - - - {cf28b89c-1840-4771-ad84-96c85e9958b5} - - - {cea104bc-b14e-42eb-9bf9-2201c523f77d} - - - {ff5c37c3-46a0-4f57-b30e-02d892b73a00} - - - {b48234f3-b7a0-4dc2-b23b-f4c33349aab1} - - - {bd4abfc8-fc90-4a1d-adc4-7800f1ad7d31} - - - {aa019fb8-debd-45de-af25-ab3d5e22a7f3} - - - {c65b298e-e9cf-447f-a27a-1d30b7bd7d81} - - - {6c92dae3-76cc-449a-aa1d-f6d72742e757} - - - {ee8489ea-968c-44c9-ae3a-35eb518513d2} - ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe - - - {26bd0b2a-4fea-4c63-b05b-f28243ac8d95} - - - {85c6230e-fa6b-497b-8d98-d4a066c86f48} - - - {662236d7-ad89-4026-bb57-bb27667da2e6} - - - {631eb474-a93b-4b48-a054-9758e8a1f959} - - - {361375c5-889a-4432-90ba-83741194f7d1} - - - {ef61c989-5105-4782-9fed-e8a56be95a46} - - - {4a9b9989-f6a5-499e-9611-c7bfe024b7a3} - - - {3e62affc-727b-4af9-95eb-76f4eb63918c} - - - {d7f40587-25b5-46f1-90bb-6751caca4922} - - - {c80b5d75-ba77-444e-98a0-c5af5d89a88c} - - - {acb8c198-52e0-46e0-9e15-8991856fcb18} - - - {0453474a-2716-4c52-b5f4-cf6bd9e31ed0} - - - {1d73f7db-64e8-4bc8-b0ca-72847253f467} - - - {20afe682-61a3-4123-9012-4c918a03f482} - - - {3161f4ab-a606-4c27-9c63-d360ba1ffdc4} - - - {1cb607bd-a0b1-4e2b-b73f-54332475cb25} - - - {f0d8891c-1071-47c7-97bd-2ce27c366246} - - - - - Player Config - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Custom Controls - - - Modal Dialogs - - - Custom Controls - - - Custom Controls - - - DVB - - - Modal Dialogs - - - Modal Dialogs - - - Graph - - - Graph - - - Graph - - - Graph - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Toolbars - - - Toolbars - - - Property Dialogs\LAV Filters Options - - - Property Dialogs\LAV Filters Options - - - Graph\Shockwave Flash - - - Player Config - - - Custom Controls - - - DVB - - - Helpers - - - Integration\Logitech LCD - - - Player Config - - - Modal Dialogs - - - Helpers - - - Helpers - - - DVB - - - Helpers - - - Helpers - - - Panels - - - Toolbars - - - Custom Controls - - - Toolbars - - - Modal Dialogs - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\File Properties - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Player Config - - - Graph\Shockwave Flash - - - Integration\Skype - - - Custom Controls - - - Custom Controls - - - Subtitles - - - Subtitles - - - Subtitles - - - Subtitles - - - Player Config - - - Modal Dialogs - - - Modal Dialogs - - - Build Info - - - Helpers - - - Custom Controls - - - Integration\Web - - - Integration\Web - - - Integration\Web - - - Custom Controls - - - Graph - - - Graph - - - - Graph - - - Graph - - - Graph - - - Graph - - - - - - - - - - Main View - - - Main View - - - Main View - - - Main View - - - Panels - - - Panels - - - Panels - - - Panels - - - Panels - - - Panels - - - Helpers - - - Crash Reporter - - - Property Dialogs\Player Options\Pages - - - Helpers - - - Subtitles - - - Helpers - - - Helpers - - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme\thirdparty - - - MPCTheme\thirdparty - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - - MPCTheme - - - Toolbars - - - Main View - - - Modal Dialogs - - - Main View - - - Property Dialogs\Player Options\Pages - - - MPCTheme - - - Helpers - - - MPCTheme - - - MPCTheme - - - - Main View - - - Helpers - - - Property Dialogs\Player Options\Pages - - - Modal Dialogs - - - Modal Dialogs - - - Property Dialogs\Player Options\Pages - - - - - Player Config - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Custom Controls - - - Modal Dialogs - - - Custom Controls - - - Custom Controls - - - DVB - - - Modal Dialogs - - - Modal Dialogs - - - Graph - - - Graph - - - Graph - - - Graph - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Toolbars - - - Toolbars - - - Property Dialogs\LAV Filters Options - - - Property Dialogs\LAV Filters Options - - - Graph\Shockwave Flash - - - Player Config - - - Custom Controls - - - DVB - - - Helpers - - - Player Config - - - Integration\Logitech LCD - - - Player Config - - - Modal Dialogs - - - Helpers - - - Integration - - - Helpers - - - DVB - - - Helpers - - - Helpers - - - Panels - - - Toolbars - - - Custom Controls - - - Toolbars - - - Modal Dialogs - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\File Properties - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\File Properties\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Property Dialogs\Player Options\Pages - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Modal Dialogs - - - Player Config - - - Player Config - - - Graph\Shockwave Flash - - - Integration\Skype - - - Custom Controls - - - Custom Controls - - - Helpers - - - Subtitles - - - Subtitles - - - Subtitles - - - Subtitles - - - Helpers - - - Player Config - - - Modal Dialogs - - - Modal Dialogs - - - Build Info - - - Helpers - - - Custom Controls - - - Integration\Web - - - Integration\Web - - - Integration\Web - - - Custom Controls - - - Graph - - - Graph - - - - Graph - - - Graph - - - Graph - - - Graph - - - Graph - - - Graph - - - - - - - - - - - Main View - - - Main View - - - Main View - - - Main View - - - Build Info - - - Panels - - - Panels - - - Panels - - - Panels - - - Panels - - - Panels - - - Helpers - - - Helpers - - - Crash Reporter - - - Property Dialogs\Player Options\Pages - - - Helpers - - - Subtitles - - - Helpers - - - Helpers - - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme\thirdparty - - - MPCTheme\thirdparty - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - - MPCTheme - - - Toolbars - - - Main View - - - Modal Dialogs - - - Main View - - - - Property Dialogs\Player Options\Pages - - - MPCTheme - - - MPCTheme - - - MPCTheme - - - - Main View - - - Helpers - - - Property Dialogs\Player Options\Pages - - - Modal Dialogs - - - Modal Dialogs - - - Property Dialogs\Player Options\Pages - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files\shaders - - - Resource Files\shaders - - - Resource Files\shaders - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files\web\img - - - Resource Files - - - - - Resource Files - - - - - Resource Files - - - - - Resource Files - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - MPCTheme\resources - - - - - - - - - - - Resource Files - - - Resource Files - - - Resource Files - - + + + + + {43c75f5f-5e94-4d15-8f45-b39b7c36bd62} + + + {77a009db-eea1-41f2-8671-661a4843634e} + + + {36ad4cd9-ded8-4c35-8a6d-1ffb3ddc2684} + + + {ad577ec8-11b8-4fcf-8b57-72f6cdabf032} + + + {cf28b89c-1840-4771-ad84-96c85e9958b5} + + + {cea104bc-b14e-42eb-9bf9-2201c523f77d} + + + {ff5c37c3-46a0-4f57-b30e-02d892b73a00} + + + {b48234f3-b7a0-4dc2-b23b-f4c33349aab1} + + + {bd4abfc8-fc90-4a1d-adc4-7800f1ad7d31} + + + {aa019fb8-debd-45de-af25-ab3d5e22a7f3} + + + {c65b298e-e9cf-447f-a27a-1d30b7bd7d81} + + + {6c92dae3-76cc-449a-aa1d-f6d72742e757} + + + {ee8489ea-968c-44c9-ae3a-35eb518513d2} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {26bd0b2a-4fea-4c63-b05b-f28243ac8d95} + + + {85c6230e-fa6b-497b-8d98-d4a066c86f48} + + + {662236d7-ad89-4026-bb57-bb27667da2e6} + + + {631eb474-a93b-4b48-a054-9758e8a1f959} + + + {361375c5-889a-4432-90ba-83741194f7d1} + + + {ef61c989-5105-4782-9fed-e8a56be95a46} + + + {4a9b9989-f6a5-499e-9611-c7bfe024b7a3} + + + {3e62affc-727b-4af9-95eb-76f4eb63918c} + + + {d7f40587-25b5-46f1-90bb-6751caca4922} + + + {c80b5d75-ba77-444e-98a0-c5af5d89a88c} + + + {acb8c198-52e0-46e0-9e15-8991856fcb18} + + + {0453474a-2716-4c52-b5f4-cf6bd9e31ed0} + + + {1d73f7db-64e8-4bc8-b0ca-72847253f467} + + + {20afe682-61a3-4123-9012-4c918a03f482} + + + {3161f4ab-a606-4c27-9c63-d360ba1ffdc4} + + + {1cb607bd-a0b1-4e2b-b73f-54332475cb25} + + + {f0d8891c-1071-47c7-97bd-2ce27c366246} + + + + + Player Config + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Custom Controls + + + Modal Dialogs + + + Custom Controls + + + Custom Controls + + + DVB + + + Modal Dialogs + + + Modal Dialogs + + + Graph + + + Graph + + + Graph + + + Graph + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Toolbars + + + Toolbars + + + Property Dialogs\LAV Filters Options + + + Property Dialogs\LAV Filters Options + + + Graph\Shockwave Flash + + + Player Config + + + Custom Controls + + + DVB + + + Helpers + + + Integration\Logitech LCD + + + Player Config + + + Modal Dialogs + + + Helpers + + + Helpers + + + DVB + + + Helpers + + + Helpers + + + Panels + + + Toolbars + + + Custom Controls + + + Toolbars + + + Modal Dialogs + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\File Properties + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Player Config + + + Graph\Shockwave Flash + + + Integration\Skype + + + Custom Controls + + + Custom Controls + + + Subtitles + + + Subtitles + + + Subtitles + + + Subtitles + + + Player Config + + + Modal Dialogs + + + Modal Dialogs + + + Build Info + + + Helpers + + + Custom Controls + + + Integration\Web + + + Integration\Web + + + Integration\Web + + + Custom Controls + + + Graph + + + Graph + + + + Graph + + + Graph + + + Graph + + + Graph + + + + + + + + + + Main View + + + Main View + + + Main View + + + Main View + + + Panels + + + Panels + + + Panels + + + Panels + + + Panels + + + Panels + + + Helpers + + + Crash Reporter + + + Property Dialogs\Player Options\Pages + + + Helpers + + + Subtitles + + + Helpers + + + Helpers + + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme\thirdparty + + + MPCTheme\thirdparty + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + + MPCTheme + + + Toolbars + + + Main View + + + Modal Dialogs + + + Main View + + + Property Dialogs\Player Options\Pages + + + MPCTheme + + + Helpers + + + MPCTheme + + + MPCTheme + + + + Main View + + + Helpers + + + Property Dialogs\Player Options\Pages + + + Modal Dialogs + + + Modal Dialogs + + + Property Dialogs\Player Options\Pages + + + + + Player Config + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Custom Controls + + + Modal Dialogs + + + Custom Controls + + + Custom Controls + + + DVB + + + Modal Dialogs + + + Modal Dialogs + + + Graph + + + Graph + + + Graph + + + Graph + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Toolbars + + + Toolbars + + + Property Dialogs\LAV Filters Options + + + Property Dialogs\LAV Filters Options + + + Graph\Shockwave Flash + + + Player Config + + + Custom Controls + + + DVB + + + Helpers + + + Player Config + + + Integration\Logitech LCD + + + Player Config + + + Modal Dialogs + + + Helpers + + + Integration + + + Helpers + + + DVB + + + Helpers + + + Helpers + + + Panels + + + Toolbars + + + Custom Controls + + + Toolbars + + + Modal Dialogs + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\File Properties + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\File Properties\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Property Dialogs\Player Options\Pages + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Modal Dialogs + + + Player Config + + + Player Config + + + Graph\Shockwave Flash + + + Integration\Skype + + + Custom Controls + + + Custom Controls + + + Helpers + + + Subtitles + + + Subtitles + + + Subtitles + + + Subtitles + + + Helpers + + + Player Config + + + Modal Dialogs + + + Modal Dialogs + + + Build Info + + + Helpers + + + Custom Controls + + + Integration\Web + + + Integration\Web + + + Integration\Web + + + Custom Controls + + + Graph + + + Graph + + + + Graph + + + Graph + + + Graph + + + Graph + + + Graph + + + Graph + + + + + + + + + + + Main View + + + Main View + + + Main View + + + Main View + + + Build Info + + + Panels + + + Panels + + + Panels + + + Panels + + + Panels + + + Panels + + + Helpers + + + Helpers + + + Crash Reporter + + + Property Dialogs\Player Options\Pages + + + Helpers + + + Subtitles + + + Helpers + + + Helpers + + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme\thirdparty + + + MPCTheme\thirdparty + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + + MPCTheme + + + Toolbars + + + Main View + + + Modal Dialogs + + + Main View + + + + Property Dialogs\Player Options\Pages + + + MPCTheme + + + MPCTheme + + + MPCTheme + + + + Main View + + + Helpers + + + Property Dialogs\Player Options\Pages + + + Modal Dialogs + + + Modal Dialogs + + + Property Dialogs\Player Options\Pages + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files\shaders + + + Resource Files\shaders + + + Resource Files\shaders + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files\web\img + + + Resource Files + + + + + Resource Files + + + + + Resource Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + MPCTheme\resources + + + + + + + + + + + Resource Files + + + Resource Files + + + Resource Files + + \ No newline at end of file diff --git a/src/mpc-hc/mpciconlib/mpciconlib.cpp b/src/mpc-hc/mpciconlib/mpciconlib.cpp index 3ece30da1f3..579eee56e7d 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.cpp +++ b/src/mpc-hc/mpciconlib/mpciconlib.cpp @@ -1,273 +1,273 @@ -/* - * (C) 2008-2013, 2015 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 . - * - */ - -#include -#include - -#include "mpciconlib.h" - -int main() -{ - return 0; -} - -extern "C" __declspec(dllexport) UINT GetIconLibVersion() -{ - return ICON_LIB_VERSION; -} - -extern "C" __declspec(dllexport) int GetIconIndex(LPCTSTR ext) -{ - int iconIndex = IDI_NONE; - - if (_tcsicmp(ext, _T(".3g2")) == 0) { - iconIndex = IDI_MOV_ICON; - } else if (_tcsicmp(ext, _T(".3ga")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".3gp")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".3gp2")) == 0) { - iconIndex = IDI_MOV_ICON; - } else if (_tcsicmp(ext, _T(".3gpp")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".aac")) == 0) { - iconIndex = IDI_AAC_ICON; - } else if (_tcsicmp(ext, _T(".ac3")) == 0) { - iconIndex = IDI_AC3_ICON; - } else if (_tcsicmp(ext, _T(".aif")) == 0) { - iconIndex = IDI_AIFF_ICON; - } else if (_tcsicmp(ext, _T(".aifc")) == 0) { - iconIndex = IDI_AIFF_ICON; - } else if (_tcsicmp(ext, _T(".aiff")) == 0) { - iconIndex = IDI_AIFF_ICON; - } else if (_tcsicmp(ext, _T(".alac")) == 0) { - iconIndex = IDI_ALAC_ICON; - } else if (_tcsicmp(ext, _T(".amr")) == 0) { - iconIndex = IDI_AMR_ICON; - } else if (_tcsicmp(ext, _T(".amv")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".aob")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".ape")) == 0) { - iconIndex = IDI_APE_ICON; - } else if (_tcsicmp(ext, _T(".apl")) == 0) { - iconIndex = IDI_APE_ICON; - } else if (_tcsicmp(ext, _T(".asf")) == 0) { - iconIndex = IDI_WMV_ICON; - } else if (_tcsicmp(ext, _T(".asx")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".au")) == 0) { - iconIndex = IDI_AU_ICON; - } else if (_tcsicmp(ext, _T(".avi")) == 0) { - iconIndex = IDI_AVI_ICON; - } else if (_tcsicmp(ext, _T(".bdmv")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".bik")) == 0) { - iconIndex = IDI_BINK_ICON; - } else if (_tcsicmp(ext, _T(".cda")) == 0) { - iconIndex = IDI_CDA_ICON; - } else if (_tcsicmp(ext, _T(".divx")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".dsa")) == 0) { - iconIndex = IDI_DSM_ICON; - } else if (_tcsicmp(ext, _T(".dsm")) == 0) { - iconIndex = IDI_DSM_ICON; - } else if (_tcsicmp(ext, _T(".dss")) == 0) { - iconIndex = IDI_DSM_ICON; - } else if (_tcsicmp(ext, _T(".dsv")) == 0) { - iconIndex = IDI_DSM_ICON; - } else if (_tcsicmp(ext, _T(".dts")) == 0) { - iconIndex = IDI_DTS_ICON; - } else if (_tcsicmp(ext, _T(".dtshd")) == 0) { - iconIndex = IDI_DTS_ICON; - } else if (_tcsicmp(ext, _T(".dtsma")) == 0) { - iconIndex = IDI_DTS_ICON; - } else if (_tcsicmp(ext, _T(".evo")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".f4v")) == 0) { - iconIndex = IDI_FLV_ICON; - } else if (_tcsicmp(ext, _T(".flac")) == 0) { - iconIndex = IDI_FLAC_ICON; - } else if (_tcsicmp(ext, _T(".flc")) == 0) { - iconIndex = IDI_FLIC_ICON; - } else if (_tcsicmp(ext, _T(".fli")) == 0) { - iconIndex = IDI_FLIC_ICON; - } else if (_tcsicmp(ext, _T(".flic")) == 0) { - iconIndex = IDI_FLIC_ICON; - } else if (_tcsicmp(ext, _T(".flv")) == 0) { - iconIndex = IDI_FLV_ICON; - } else if (_tcsicmp(ext, _T(".hdmov")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".iflv")) == 0) { - iconIndex = IDI_FLV_ICON; - } else if (_tcsicmp(ext, _T(".ifo")) == 0) { - iconIndex = IDI_IFO_ICON; - } else if (_tcsicmp(ext, _T(".ivf")) == 0) { - iconIndex = IDI_IVF_ICON; - } else if (_tcsicmp(ext, _T(".m1a")) == 0) { - iconIndex = IDI_MPA_ICON; - } else if (_tcsicmp(ext, _T(".m1v")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".m2a")) == 0) { - iconIndex = IDI_MPA_ICON; - } else if (_tcsicmp(ext, _T(".m2p")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".m2t")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".m2ts")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".m2v")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".m3u")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".m3u8")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".m4a")) == 0) { - iconIndex = IDI_AAC_ICON; - } else if (_tcsicmp(ext, _T(".m4b")) == 0) { - iconIndex = IDI_AAC_ICON; - } else if (_tcsicmp(ext, _T(".m4r")) == 0) { - iconIndex = IDI_AAC_ICON; - } else if (_tcsicmp(ext, _T(".m4v")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".mid")) == 0) { - iconIndex = IDI_MIDI_ICON; - } else if (_tcsicmp(ext, _T(".midi")) == 0) { - iconIndex = IDI_MIDI_ICON; - } else if (_tcsicmp(ext, _T(".mka")) == 0) { - iconIndex = IDI_MKA_ICON; - } else if (_tcsicmp(ext, _T(".mkv")) == 0) { - iconIndex = IDI_MKV_ICON; - } else if (_tcsicmp(ext, _T(".mlp")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".mov")) == 0) { - iconIndex = IDI_MOV_ICON; - } else if (_tcsicmp(ext, _T(".mp2")) == 0) { - iconIndex = IDI_MPA_ICON; - } else if (_tcsicmp(ext, _T(".mp2v")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mp3")) == 0) { - iconIndex = IDI_MP3_ICON; - } else if (_tcsicmp(ext, _T(".mp4")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".mp4v")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".mpa")) == 0) { - iconIndex = IDI_MPA_ICON; - } else if (_tcsicmp(ext, _T(".mpc")) == 0) { - iconIndex = IDI_MPC_ICON; - } else if (_tcsicmp(ext, _T(".mpcpl")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".cue")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".mpe")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mpeg")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mpg")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mpls")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".mpv2")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".mpv4")) == 0) { - iconIndex = IDI_MP4_ICON; - } else if (_tcsicmp(ext, _T(".mts")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".ofr")) == 0) { - iconIndex = IDI_OFR_ICON; - } else if (_tcsicmp(ext, _T(".ofs")) == 0) { - iconIndex = IDI_OFR_ICON; - } else if (_tcsicmp(ext, _T(".oga")) == 0) { - iconIndex = IDI_OGG_ICON; - } else if (_tcsicmp(ext, _T(".ogg")) == 0) { - iconIndex = IDI_OGG_ICON; - } else if (_tcsicmp(ext, _T(".ogm")) == 0) { - iconIndex = IDI_OGM_ICON; - } else if (_tcsicmp(ext, _T(".ogv")) == 0) { - iconIndex = IDI_OGM_ICON; - } else if (_tcsicmp(ext, _T(".opus")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".pls")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".pva")) == 0) { - iconIndex = IDI_MPEG_ICON; - } else if (_tcsicmp(ext, _T(".ra")) == 0) { - iconIndex = IDI_RA_ICON; - } else if (_tcsicmp(ext, _T(".ram")) == 0) { - iconIndex = IDI_RM_ICON; - } else if (_tcsicmp(ext, _T(".rm")) == 0) { - iconIndex = IDI_RM_ICON; - } else if (_tcsicmp(ext, _T(".rmi")) == 0) { - iconIndex = IDI_MIDI_ICON; - } else if (_tcsicmp(ext, _T(".rmm")) == 0) { - iconIndex = IDI_RM_ICON; - } else if (_tcsicmp(ext, _T(".rmvb")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".rp")) == 0) { - iconIndex = IDI_RT_ICON; - } else if (_tcsicmp(ext, _T(".rt")) == 0) { - iconIndex = IDI_RT_ICON; - } else if (_tcsicmp(ext, _T(".smil")) == 0) { - iconIndex = IDI_RT_ICON; - } else if (_tcsicmp(ext, _T(".smk")) == 0) { - iconIndex = IDI_SMK_ICON; - } else if (_tcsicmp(ext, _T(".snd")) == 0) { - iconIndex = IDI_AU_ICON; - } else if (_tcsicmp(ext, _T(".swf")) == 0) { - iconIndex = IDI_SWF_ICON; - } else if (_tcsicmp(ext, _T(".tp")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".trp")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".ts")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".rec")) == 0) { - iconIndex = IDI_TS_ICON; - } else if (_tcsicmp(ext, _T(".tak")) == 0) { - iconIndex = IDI_OTHER_ICON; - } else if (_tcsicmp(ext, _T(".tta")) == 0) { - iconIndex = IDI_TTA_ICON; - } else if (_tcsicmp(ext, _T(".vob")) == 0) { - iconIndex = IDI_VOB_ICON; - } else if (_tcsicmp(ext, _T(".wav")) == 0) { - iconIndex = IDI_WAV_ICON; - } else if (_tcsicmp(ext, _T(".wax")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".webm")) == 0) { - iconIndex = IDI_WEBM_ICON; - } else if (_tcsicmp(ext, _T(".wm")) == 0) { - iconIndex = IDI_WMV_ICON; - } else if (_tcsicmp(ext, _T(".wma")) == 0) { - iconIndex = IDI_WMA_ICON; - } else if (_tcsicmp(ext, _T(".wmp")) == 0) { - iconIndex = IDI_WMV_ICON; - } else if (_tcsicmp(ext, _T(".wmv")) == 0) { - iconIndex = IDI_WMV_ICON; - } else if (_tcsicmp(ext, _T(".wmx")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } else if (_tcsicmp(ext, _T(".wv")) == 0) { - iconIndex = IDI_WV_ICON; - } else if (_tcsicmp(ext, _T(".wvx")) == 0) { - iconIndex = IDI_PLAYLIST_ICON; - } - - return iconIndex; -} +/* + * (C) 2008-2013, 2015 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 . + * + */ + +#include +#include + +#include "mpciconlib.h" + +int main() +{ + return 0; +} + +extern "C" __declspec(dllexport) UINT GetIconLibVersion() +{ + return ICON_LIB_VERSION; +} + +extern "C" __declspec(dllexport) int GetIconIndex(LPCTSTR ext) +{ + int iconIndex = IDI_NONE; + + if (_tcsicmp(ext, _T(".3g2")) == 0) { + iconIndex = IDI_MOV_ICON; + } else if (_tcsicmp(ext, _T(".3ga")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".3gp")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".3gp2")) == 0) { + iconIndex = IDI_MOV_ICON; + } else if (_tcsicmp(ext, _T(".3gpp")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".aac")) == 0) { + iconIndex = IDI_AAC_ICON; + } else if (_tcsicmp(ext, _T(".ac3")) == 0) { + iconIndex = IDI_AC3_ICON; + } else if (_tcsicmp(ext, _T(".aif")) == 0) { + iconIndex = IDI_AIFF_ICON; + } else if (_tcsicmp(ext, _T(".aifc")) == 0) { + iconIndex = IDI_AIFF_ICON; + } else if (_tcsicmp(ext, _T(".aiff")) == 0) { + iconIndex = IDI_AIFF_ICON; + } else if (_tcsicmp(ext, _T(".alac")) == 0) { + iconIndex = IDI_ALAC_ICON; + } else if (_tcsicmp(ext, _T(".amr")) == 0) { + iconIndex = IDI_AMR_ICON; + } else if (_tcsicmp(ext, _T(".amv")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".aob")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".ape")) == 0) { + iconIndex = IDI_APE_ICON; + } else if (_tcsicmp(ext, _T(".apl")) == 0) { + iconIndex = IDI_APE_ICON; + } else if (_tcsicmp(ext, _T(".asf")) == 0) { + iconIndex = IDI_WMV_ICON; + } else if (_tcsicmp(ext, _T(".asx")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".au")) == 0) { + iconIndex = IDI_AU_ICON; + } else if (_tcsicmp(ext, _T(".avi")) == 0) { + iconIndex = IDI_AVI_ICON; + } else if (_tcsicmp(ext, _T(".bdmv")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".bik")) == 0) { + iconIndex = IDI_BINK_ICON; + } else if (_tcsicmp(ext, _T(".cda")) == 0) { + iconIndex = IDI_CDA_ICON; + } else if (_tcsicmp(ext, _T(".divx")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".dsa")) == 0) { + iconIndex = IDI_DSM_ICON; + } else if (_tcsicmp(ext, _T(".dsm")) == 0) { + iconIndex = IDI_DSM_ICON; + } else if (_tcsicmp(ext, _T(".dss")) == 0) { + iconIndex = IDI_DSM_ICON; + } else if (_tcsicmp(ext, _T(".dsv")) == 0) { + iconIndex = IDI_DSM_ICON; + } else if (_tcsicmp(ext, _T(".dts")) == 0) { + iconIndex = IDI_DTS_ICON; + } else if (_tcsicmp(ext, _T(".dtshd")) == 0) { + iconIndex = IDI_DTS_ICON; + } else if (_tcsicmp(ext, _T(".dtsma")) == 0) { + iconIndex = IDI_DTS_ICON; + } else if (_tcsicmp(ext, _T(".evo")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".f4v")) == 0) { + iconIndex = IDI_FLV_ICON; + } else if (_tcsicmp(ext, _T(".flac")) == 0) { + iconIndex = IDI_FLAC_ICON; + } else if (_tcsicmp(ext, _T(".flc")) == 0) { + iconIndex = IDI_FLIC_ICON; + } else if (_tcsicmp(ext, _T(".fli")) == 0) { + iconIndex = IDI_FLIC_ICON; + } else if (_tcsicmp(ext, _T(".flic")) == 0) { + iconIndex = IDI_FLIC_ICON; + } else if (_tcsicmp(ext, _T(".flv")) == 0) { + iconIndex = IDI_FLV_ICON; + } else if (_tcsicmp(ext, _T(".hdmov")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".iflv")) == 0) { + iconIndex = IDI_FLV_ICON; + } else if (_tcsicmp(ext, _T(".ifo")) == 0) { + iconIndex = IDI_IFO_ICON; + } else if (_tcsicmp(ext, _T(".ivf")) == 0) { + iconIndex = IDI_IVF_ICON; + } else if (_tcsicmp(ext, _T(".m1a")) == 0) { + iconIndex = IDI_MPA_ICON; + } else if (_tcsicmp(ext, _T(".m1v")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".m2a")) == 0) { + iconIndex = IDI_MPA_ICON; + } else if (_tcsicmp(ext, _T(".m2p")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".m2t")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".m2ts")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".m2v")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".m3u")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".m3u8")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".m4a")) == 0) { + iconIndex = IDI_AAC_ICON; + } else if (_tcsicmp(ext, _T(".m4b")) == 0) { + iconIndex = IDI_AAC_ICON; + } else if (_tcsicmp(ext, _T(".m4r")) == 0) { + iconIndex = IDI_AAC_ICON; + } else if (_tcsicmp(ext, _T(".m4v")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".mid")) == 0) { + iconIndex = IDI_MIDI_ICON; + } else if (_tcsicmp(ext, _T(".midi")) == 0) { + iconIndex = IDI_MIDI_ICON; + } else if (_tcsicmp(ext, _T(".mka")) == 0) { + iconIndex = IDI_MKA_ICON; + } else if (_tcsicmp(ext, _T(".mkv")) == 0) { + iconIndex = IDI_MKV_ICON; + } else if (_tcsicmp(ext, _T(".mlp")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".mov")) == 0) { + iconIndex = IDI_MOV_ICON; + } else if (_tcsicmp(ext, _T(".mp2")) == 0) { + iconIndex = IDI_MPA_ICON; + } else if (_tcsicmp(ext, _T(".mp2v")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mp3")) == 0) { + iconIndex = IDI_MP3_ICON; + } else if (_tcsicmp(ext, _T(".mp4")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".mp4v")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".mpa")) == 0) { + iconIndex = IDI_MPA_ICON; + } else if (_tcsicmp(ext, _T(".mpc")) == 0) { + iconIndex = IDI_MPC_ICON; + } else if (_tcsicmp(ext, _T(".mpcpl")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".cue")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".mpe")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mpeg")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mpg")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mpls")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".mpv2")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".mpv4")) == 0) { + iconIndex = IDI_MP4_ICON; + } else if (_tcsicmp(ext, _T(".mts")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".ofr")) == 0) { + iconIndex = IDI_OFR_ICON; + } else if (_tcsicmp(ext, _T(".ofs")) == 0) { + iconIndex = IDI_OFR_ICON; + } else if (_tcsicmp(ext, _T(".oga")) == 0) { + iconIndex = IDI_OGG_ICON; + } else if (_tcsicmp(ext, _T(".ogg")) == 0) { + iconIndex = IDI_OGG_ICON; + } else if (_tcsicmp(ext, _T(".ogm")) == 0) { + iconIndex = IDI_OGM_ICON; + } else if (_tcsicmp(ext, _T(".ogv")) == 0) { + iconIndex = IDI_OGM_ICON; + } else if (_tcsicmp(ext, _T(".opus")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".pls")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".pva")) == 0) { + iconIndex = IDI_MPEG_ICON; + } else if (_tcsicmp(ext, _T(".ra")) == 0) { + iconIndex = IDI_RA_ICON; + } else if (_tcsicmp(ext, _T(".ram")) == 0) { + iconIndex = IDI_RM_ICON; + } else if (_tcsicmp(ext, _T(".rm")) == 0) { + iconIndex = IDI_RM_ICON; + } else if (_tcsicmp(ext, _T(".rmi")) == 0) { + iconIndex = IDI_MIDI_ICON; + } else if (_tcsicmp(ext, _T(".rmm")) == 0) { + iconIndex = IDI_RM_ICON; + } else if (_tcsicmp(ext, _T(".rmvb")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".rp")) == 0) { + iconIndex = IDI_RT_ICON; + } else if (_tcsicmp(ext, _T(".rt")) == 0) { + iconIndex = IDI_RT_ICON; + } else if (_tcsicmp(ext, _T(".smil")) == 0) { + iconIndex = IDI_RT_ICON; + } else if (_tcsicmp(ext, _T(".smk")) == 0) { + iconIndex = IDI_SMK_ICON; + } else if (_tcsicmp(ext, _T(".snd")) == 0) { + iconIndex = IDI_AU_ICON; + } else if (_tcsicmp(ext, _T(".swf")) == 0) { + iconIndex = IDI_SWF_ICON; + } else if (_tcsicmp(ext, _T(".tp")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".trp")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".ts")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".rec")) == 0) { + iconIndex = IDI_TS_ICON; + } else if (_tcsicmp(ext, _T(".tak")) == 0) { + iconIndex = IDI_OTHER_ICON; + } else if (_tcsicmp(ext, _T(".tta")) == 0) { + iconIndex = IDI_TTA_ICON; + } else if (_tcsicmp(ext, _T(".vob")) == 0) { + iconIndex = IDI_VOB_ICON; + } else if (_tcsicmp(ext, _T(".wav")) == 0) { + iconIndex = IDI_WAV_ICON; + } else if (_tcsicmp(ext, _T(".wax")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".webm")) == 0) { + iconIndex = IDI_WEBM_ICON; + } else if (_tcsicmp(ext, _T(".wm")) == 0) { + iconIndex = IDI_WMV_ICON; + } else if (_tcsicmp(ext, _T(".wma")) == 0) { + iconIndex = IDI_WMA_ICON; + } else if (_tcsicmp(ext, _T(".wmp")) == 0) { + iconIndex = IDI_WMV_ICON; + } else if (_tcsicmp(ext, _T(".wmv")) == 0) { + iconIndex = IDI_WMV_ICON; + } else if (_tcsicmp(ext, _T(".wmx")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } else if (_tcsicmp(ext, _T(".wv")) == 0) { + iconIndex = IDI_WV_ICON; + } else if (_tcsicmp(ext, _T(".wvx")) == 0) { + iconIndex = IDI_PLAYLIST_ICON; + } + + return iconIndex; +} diff --git a/src/mpc-hc/mpciconlib/mpciconlib.h b/src/mpc-hc/mpciconlib/mpciconlib.h index dd311863084..3fa71694287 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.h +++ b/src/mpc-hc/mpciconlib/mpciconlib.h @@ -1,86 +1,86 @@ -/* - * (C) 2008-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 . - * - */ - -/* The version number of the icon library. Should be incremented when the indexes are changed. */ -#define ICON_LIB_VERSION 3 - -/* The values below correspond to the icon indexes. - * The order should be exactly the same as in the mpciconlib.rc file. - * There should be no gaps in the numbering. So be careful - * when adding/removing icons. - */ - -#define IDI_NONE -1 -#define IDI_OTHER_ICON 0 -#define IDI_AAC_ICON 1 -#define IDI_AC3_ICON 2 -#define IDI_AIFF_ICON 3 -#define IDI_ALAC_ICON 4 -#define IDI_AMR_ICON 5 -#define IDI_APE_ICON 6 -#define IDI_AU_ICON 7 -#define IDI_AVI_ICON 8 -#define IDI_BINK_ICON 9 -#define IDI_CDA_ICON 10 -#define IDI_DSM_ICON 11 -#define IDI_DTS_ICON 12 -#define IDI_FLAC_ICON 13 -#define IDI_FLIC_ICON 14 -#define IDI_FLV_ICON 15 -#define IDI_IFO_ICON 16 -#define IDI_IVF_ICON 17 -#define IDI_MIDI_ICON 18 -#define IDI_MKA_ICON 19 -#define IDI_MKV_ICON 20 -#define IDI_MOV_ICON 21 -#define IDI_MP3_ICON 22 -#define IDI_MP4_ICON 23 -#define IDI_MPA_ICON 24 -#define IDI_MPC_ICON 25 -#define IDI_MPEG_ICON 26 -#define IDI_OFR_ICON 27 -#define IDI_OGG_ICON 28 -#define IDI_OGM_ICON 29 -#define IDI_PLAYLIST_ICON 30 -#define IDI_RA_ICON 31 -#define IDI_RM_ICON 32 -#define IDI_RT_ICON 33 -#define IDI_SMK_ICON 34 -#define IDI_SWF_ICON 35 -#define IDI_TS_ICON 36 -#define IDI_TTA_ICON 37 -#define IDI_VOB_ICON 38 -#define IDI_WAV_ICON 39 -#define IDI_WEBM_ICON 40 -#define IDI_WMA_ICON 41 -#define IDI_WMV_ICON 42 -#define IDI_WV_ICON 43 - - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 44 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +/* + * (C) 2008-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 . + * + */ + +/* The version number of the icon library. Should be incremented when the indexes are changed. */ +#define ICON_LIB_VERSION 3 + +/* The values below correspond to the icon indexes. + * The order should be exactly the same as in the mpciconlib.rc file. + * There should be no gaps in the numbering. So be careful + * when adding/removing icons. + */ + +#define IDI_NONE -1 +#define IDI_OTHER_ICON 0 +#define IDI_AAC_ICON 1 +#define IDI_AC3_ICON 2 +#define IDI_AIFF_ICON 3 +#define IDI_ALAC_ICON 4 +#define IDI_AMR_ICON 5 +#define IDI_APE_ICON 6 +#define IDI_AU_ICON 7 +#define IDI_AVI_ICON 8 +#define IDI_BINK_ICON 9 +#define IDI_CDA_ICON 10 +#define IDI_DSM_ICON 11 +#define IDI_DTS_ICON 12 +#define IDI_FLAC_ICON 13 +#define IDI_FLIC_ICON 14 +#define IDI_FLV_ICON 15 +#define IDI_IFO_ICON 16 +#define IDI_IVF_ICON 17 +#define IDI_MIDI_ICON 18 +#define IDI_MKA_ICON 19 +#define IDI_MKV_ICON 20 +#define IDI_MOV_ICON 21 +#define IDI_MP3_ICON 22 +#define IDI_MP4_ICON 23 +#define IDI_MPA_ICON 24 +#define IDI_MPC_ICON 25 +#define IDI_MPEG_ICON 26 +#define IDI_OFR_ICON 27 +#define IDI_OGG_ICON 28 +#define IDI_OGM_ICON 29 +#define IDI_PLAYLIST_ICON 30 +#define IDI_RA_ICON 31 +#define IDI_RM_ICON 32 +#define IDI_RT_ICON 33 +#define IDI_SMK_ICON 34 +#define IDI_SWF_ICON 35 +#define IDI_TS_ICON 36 +#define IDI_TTA_ICON 37 +#define IDI_VOB_ICON 38 +#define IDI_WAV_ICON 39 +#define IDI_WEBM_ICON 40 +#define IDI_WMA_ICON 41 +#define IDI_WMV_ICON 42 +#define IDI_WV_ICON 43 + + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 44 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/mpc-hc/mpciconlib/mpciconlib.rc b/src/mpc-hc/mpciconlib/mpciconlib.rc index 54305aff3a8..a7202b8a94b 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.rc +++ b/src/mpc-hc/mpciconlib/mpciconlib.rc @@ -1,154 +1,154 @@ -// Microsoft Visual C++ generated resource script. -// -#include "mpciconlib.h" -#include "version.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "mpciconlib.h\0" - "version.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// The icons should have the exact same order as in "mpciconlib.h" ! -IDI_OTHER_ICON ICON "icons\\other.ico" -IDI_AAC_ICON ICON "icons\\aac.ico" -IDI_AC3_ICON ICON "icons\\ac3.ico" -IDI_AIFF_ICON ICON "icons\\aiff.ico" -IDI_ALAC_ICON ICON "icons\\alac.ico" -IDI_AMR_ICON ICON "icons\\amr.ico" -IDI_APE_ICON ICON "icons\\ape.ico" -IDI_AU_ICON ICON "icons\\au.ico" -IDI_AVI_ICON ICON "icons\\avi.ico" -IDI_BINK_ICON ICON "icons\\bink.ico" -IDI_CDA_ICON ICON "icons\\cda.ico" -IDI_DSM_ICON ICON "icons\\dsm.ico" -IDI_DTS_ICON ICON "icons\\dts.ico" -IDI_FLAC_ICON ICON "icons\\flac.ico" -IDI_FLIC_ICON ICON "icons\\flic.ico" -IDI_FLV_ICON ICON "icons\\flv.ico" -IDI_IFO_ICON ICON "icons\\ifo.ico" -IDI_IVF_ICON ICON "icons\\ivf.ico" -IDI_MIDI_ICON ICON "icons\\midi.ico" -IDI_MKA_ICON ICON "icons\\mka.ico" -IDI_MKV_ICON ICON "icons\\mkv.ico" -IDI_MOV_ICON ICON "icons\\mov.ico" -IDI_MP3_ICON ICON "icons\\mp3.ico" -IDI_MP4_ICON ICON "icons\\mp4.ico" -IDI_MPA_ICON ICON "icons\\mpa.ico" -IDI_MPC_ICON ICON "icons\\mpc.ico" -IDI_MPEG_ICON ICON "icons\\mpeg.ico" -IDI_OFR_ICON ICON "icons\\ofr.ico" -IDI_OGG_ICON ICON "icons\\ogg.ico" -IDI_OGM_ICON ICON "icons\\ogm.ico" -IDI_PLAYLIST_ICON ICON "icons\\playlist.ico" -IDI_RA_ICON ICON "icons\\ra.ico" -IDI_RM_ICON ICON "icons\\rm.ico" -IDI_RT_ICON ICON "icons\\rt.ico" -IDI_SMK_ICON ICON "icons\\smk.ico" -IDI_SWF_ICON ICON "icons\\swf.ico" -IDI_TS_ICON ICON "icons\\ts.ico" -IDI_TTA_ICON ICON "icons\\tta.ico" -IDI_VOB_ICON ICON "icons\\vob.ico" -IDI_WAV_ICON ICON "icons\\wav.ico" -IDI_WEBM_ICON ICON "icons\\webm.ico" -IDI_WMA_ICON ICON "icons\\wma.ico" -IDI_WMV_ICON ICON "icons\\wmv.ico" -IDI_WV_ICON ICON "icons\\wv.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION MPC_VERSION_NUM - PRODUCTVERSION MPC_VERSION_NUM - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "MPC-HC Icon Library" - VALUE "CompanyName", MPC_COMP_NAME_STR - VALUE "FileDescription", "MPC-HC Icon Library" - VALUE "FileVersion", MPC_VERSION_STR - VALUE "InternalName", "mpciconlib" - VALUE "LegalCopyright", MPC_COPYRIGHT_STR - VALUE "OriginalFilename", "mpciconlib.dll" - VALUE "ProductName", "MPC-HC Icon Library" - VALUE "ProductVersion", MPC_VERSION_STR - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "mpciconlib.h" +#include "version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "mpciconlib.h\0" + "version.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// The icons should have the exact same order as in "mpciconlib.h" ! +IDI_OTHER_ICON ICON "icons\\other.ico" +IDI_AAC_ICON ICON "icons\\aac.ico" +IDI_AC3_ICON ICON "icons\\ac3.ico" +IDI_AIFF_ICON ICON "icons\\aiff.ico" +IDI_ALAC_ICON ICON "icons\\alac.ico" +IDI_AMR_ICON ICON "icons\\amr.ico" +IDI_APE_ICON ICON "icons\\ape.ico" +IDI_AU_ICON ICON "icons\\au.ico" +IDI_AVI_ICON ICON "icons\\avi.ico" +IDI_BINK_ICON ICON "icons\\bink.ico" +IDI_CDA_ICON ICON "icons\\cda.ico" +IDI_DSM_ICON ICON "icons\\dsm.ico" +IDI_DTS_ICON ICON "icons\\dts.ico" +IDI_FLAC_ICON ICON "icons\\flac.ico" +IDI_FLIC_ICON ICON "icons\\flic.ico" +IDI_FLV_ICON ICON "icons\\flv.ico" +IDI_IFO_ICON ICON "icons\\ifo.ico" +IDI_IVF_ICON ICON "icons\\ivf.ico" +IDI_MIDI_ICON ICON "icons\\midi.ico" +IDI_MKA_ICON ICON "icons\\mka.ico" +IDI_MKV_ICON ICON "icons\\mkv.ico" +IDI_MOV_ICON ICON "icons\\mov.ico" +IDI_MP3_ICON ICON "icons\\mp3.ico" +IDI_MP4_ICON ICON "icons\\mp4.ico" +IDI_MPA_ICON ICON "icons\\mpa.ico" +IDI_MPC_ICON ICON "icons\\mpc.ico" +IDI_MPEG_ICON ICON "icons\\mpeg.ico" +IDI_OFR_ICON ICON "icons\\ofr.ico" +IDI_OGG_ICON ICON "icons\\ogg.ico" +IDI_OGM_ICON ICON "icons\\ogm.ico" +IDI_PLAYLIST_ICON ICON "icons\\playlist.ico" +IDI_RA_ICON ICON "icons\\ra.ico" +IDI_RM_ICON ICON "icons\\rm.ico" +IDI_RT_ICON ICON "icons\\rt.ico" +IDI_SMK_ICON ICON "icons\\smk.ico" +IDI_SWF_ICON ICON "icons\\swf.ico" +IDI_TS_ICON ICON "icons\\ts.ico" +IDI_TTA_ICON ICON "icons\\tta.ico" +IDI_VOB_ICON ICON "icons\\vob.ico" +IDI_WAV_ICON ICON "icons\\wav.ico" +IDI_WEBM_ICON ICON "icons\\webm.ico" +IDI_WMA_ICON ICON "icons\\wma.ico" +IDI_WMV_ICON ICON "icons\\wmv.ico" +IDI_WV_ICON ICON "icons\\wv.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MPC_VERSION_NUM + PRODUCTVERSION MPC_VERSION_NUM + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "MPC-HC Icon Library" + VALUE "CompanyName", MPC_COMP_NAME_STR + VALUE "FileDescription", "MPC-HC Icon Library" + VALUE "FileVersion", MPC_VERSION_STR + VALUE "InternalName", "mpciconlib" + VALUE "LegalCopyright", MPC_COPYRIGHT_STR + VALUE "OriginalFilename", "mpciconlib.dll" + VALUE "ProductName", "MPC-HC Icon Library" + VALUE "ProductVersion", MPC_VERSION_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/mpc-hc/mpciconlib/mpciconlib.vcxproj b/src/mpc-hc/mpciconlib/mpciconlib.vcxproj index f719902895f..8008b02eaa8 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.vcxproj +++ b/src/mpc-hc/mpciconlib/mpciconlib.vcxproj @@ -1,114 +1,114 @@ - - - - - Release - Win32 - - - Release - x64 - - - - {86251DC4-9298-424C-AE6C-07844F79C0B5} - mpciconlib - Win32Proj - mpciconlib - - - - - DynamicLibrary - Unicode - - - - - - - - - - - $(SolutionDir)bin\mpc-hc_x86\ - $(SolutionDir)bin\mpc-hc_x64\ - - - $(SolutionDir)bin15\mpc-hc_x86\ - $(SolutionDir)bin15\mpc-hc_x64\ - - - - NotUsing - - - true - $(IntDir)$(TargetName).pdb - libucrt.lib;%(AdditionalDependencies) - - - ..\..\..\include - NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Release + Win32 + + + Release + x64 + + + + {86251DC4-9298-424C-AE6C-07844F79C0B5} + mpciconlib + Win32Proj + mpciconlib + + + + + DynamicLibrary + Unicode + + + + + + + + + + + $(SolutionDir)bin\mpc-hc_x86\ + $(SolutionDir)bin\mpc-hc_x64\ + + + $(SolutionDir)bin15\mpc-hc_x86\ + $(SolutionDir)bin15\mpc-hc_x64\ + + + + NotUsing + + + true + $(IntDir)$(TargetName).pdb + libucrt.lib;%(AdditionalDependencies) + + + ..\..\..\include + NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/mpc-hc/mpciconlib/mpciconlib.vcxproj.filters b/src/mpc-hc/mpciconlib/mpciconlib.vcxproj.filters index cdd171fb8e6..c00c5c34b70 100644 --- a/src/mpc-hc/mpciconlib/mpciconlib.vcxproj.filters +++ b/src/mpc-hc/mpciconlib/mpciconlib.vcxproj.filters @@ -1,172 +1,172 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - {a30fae36-ef1d-4888-83c4-6ef86520877d} - - - - - Source Files - - - - - Header Files - - - Header Files - - - - - Resource Files - - - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - - Resource Files\icons - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {a30fae36-ef1d-4888-83c4-6ef86520877d} + + + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + + Resource Files\icons + + \ No newline at end of file diff --git a/src/mpc-hc/mpcresources/mpcresources.vcxproj b/src/mpc-hc/mpcresources/mpcresources.vcxproj index afea46cf0df..2ee18f37681 100644 --- a/src/mpc-hc/mpcresources/mpcresources.vcxproj +++ b/src/mpc-hc/mpcresources/mpcresources.vcxproj @@ -1,596 +1,596 @@ - - - - - Release Arabic - Win32 - - - Release Arabic - x64 - - - Release Armenian - Win32 - - - Release Armenian - x64 - - - Release Basque - Win32 - - - Release Basque - x64 - - - Release Belarusian - Win32 - - - Release Belarusian - x64 - - - Release Bengali - Win32 - - - Release Bengali - x64 - - - Release Bosnian - Win32 - - - Release Bosnian - x64 - - - Release Bulgarian - Win32 - - - Release Bulgarian - x64 - - - Release Catalan - Win32 - - - Release Catalan - x64 - - - Release Chinese Simplified - Win32 - - - Release Chinese Simplified - x64 - - - Release Chinese Traditional - Win32 - - - Release Chinese Traditional - x64 - - - Release Croatian - Win32 - - - Release Croatian - x64 - - - Release Czech - Win32 - - - Release Czech - x64 - - - Release Danish - Win32 - - - Release Danish - x64 - - - Release Dutch - Win32 - - - Release Dutch - x64 - - - Release English (British) - Win32 - - - Release English (British) - x64 - - - Release Finnish - Win32 - - - Release Finnish - x64 - - - Release French - Win32 - - - Release French - x64 - - - Release Galician - Win32 - - - Release Galician - x64 - - - Release German - Win32 - - - Release German - x64 - - - Release Greek - Win32 - - - Release Greek - x64 - - - Release Hebrew - Win32 - - - Release Hebrew - x64 - - - Release Hungarian - Win32 - - - Release Hungarian - x64 - - - Release Indonesian - Win32 - - - Release Indonesian - x64 - - - Release Italian - Win32 - - - Release Italian - x64 - - - Release Japanese - Win32 - - - Release Japanese - x64 - - - Release Korean - Win32 - - - Release Korean - x64 - - - Release Lithuanian - Win32 - - - Release Lithuanian - x64 - - - Release Malay - Win32 - - - Release Malay - x64 - - - Release Polish - Win32 - - - Release Polish - x64 - - - Release Portuguese (Brazil) - Win32 - - - Release Portuguese (Brazil) - x64 - - - Release Portuguese (Portugal) - Win32 - - - Release Portuguese (Portugal) - x64 - - - Release Punjabi - Win32 - - - Release Punjabi - x64 - - - Release Romanian - Win32 - - - Release Romanian - x64 - - - Release Russian - Win32 - - - Release Russian - x64 - - - Release Serbian - Win32 - - - Release Serbian - x64 - - - Release Slovak - Win32 - - - Release Slovak - x64 - - - Release Slovenian - Win32 - - - Release Slovenian - x64 - - - Release Spanish - Win32 - - - Release Spanish - x64 - - - Release Swedish - Win32 - - - Release Swedish - x64 - - - Release Tatar - Win32 - - - Release Tatar - x64 - - - Release Thai - Win32 - - - Release Thai - x64 - - - Release Turkish - Win32 - - - Release Turkish - x64 - - - Release Ukrainian - Win32 - - - Release Ukrainian - x64 - - - Release Vietnamese - Win32 - - - Release Vietnamese - x64 - - - - {A57CBE1A-3703-4237-950A-FC5F594FDB43} - mpcresources - Win32Proj - mpcresources - - - - - DynamicLibrary - Unicode - - - - - - - - - - - $(SolutionDir)bin\mpc-hc_x86\Lang\ - $(SolutionDir)bin\mpc-hc_x64\Lang\ - $(SolutionDir)bin\obj\Release_$(Platform)\$(ProjectName)\$(Configuration)\ - $(ProjectName).ar - $(ProjectName).hy - $(ProjectName).eu - $(ProjectName).be - $(ProjectName).bn - $(ProjectName).bs_BA - $(ProjectName).bg - $(ProjectName).ca - $(ProjectName).zh_CN - $(ProjectName).zh_TW - $(ProjectName).hr - $(ProjectName).cs - $(ProjectName).da - $(ProjectName).nl - $(ProjectName).en_GB - $(ProjectName).fi - $(ProjectName).fr - $(ProjectName).gl - $(ProjectName).de - $(ProjectName).el - $(ProjectName).he - $(ProjectName).hu - $(ProjectName).id - $(ProjectName).it - $(ProjectName).ja - $(ProjectName).ko - $(ProjectName).lt - $(ProjectName).ms_MY - $(ProjectName).pl - $(ProjectName).pt_BR - $(ProjectName).pt_PT - $(ProjectName).pa - $(ProjectName).ro - $(ProjectName).ru - $(ProjectName).sr - $(ProjectName).sk - $(ProjectName).sl - $(ProjectName).es - $(ProjectName).sv - $(ProjectName).tt - $(ProjectName).th_TH - $(ProjectName).tr - $(ProjectName).uk - $(ProjectName).vi - - - $(SolutionDir)bin15\mpc-hc_x86\Lang\ - $(SolutionDir)bin15\mpc-hc_x64\Lang\ - $(SolutionDir)bin15\obj\Release_$(Platform)\$(ProjectName)\$(Configuration)\ - - - - false - - - Default - false - true - true - - - ..\..\..\include;..;%(AdditionalIncludeDirectories) - NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) - - - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - - - - - - - {904017f7-ee7a-49b6-a000-0d2fe5d5809a} - false - - - - - - + + + + + Release Arabic + Win32 + + + Release Arabic + x64 + + + Release Armenian + Win32 + + + Release Armenian + x64 + + + Release Basque + Win32 + + + Release Basque + x64 + + + Release Belarusian + Win32 + + + Release Belarusian + x64 + + + Release Bengali + Win32 + + + Release Bengali + x64 + + + Release Bosnian + Win32 + + + Release Bosnian + x64 + + + Release Bulgarian + Win32 + + + Release Bulgarian + x64 + + + Release Catalan + Win32 + + + Release Catalan + x64 + + + Release Chinese Simplified + Win32 + + + Release Chinese Simplified + x64 + + + Release Chinese Traditional + Win32 + + + Release Chinese Traditional + x64 + + + Release Croatian + Win32 + + + Release Croatian + x64 + + + Release Czech + Win32 + + + Release Czech + x64 + + + Release Danish + Win32 + + + Release Danish + x64 + + + Release Dutch + Win32 + + + Release Dutch + x64 + + + Release English (British) + Win32 + + + Release English (British) + x64 + + + Release Finnish + Win32 + + + Release Finnish + x64 + + + Release French + Win32 + + + Release French + x64 + + + Release Galician + Win32 + + + Release Galician + x64 + + + Release German + Win32 + + + Release German + x64 + + + Release Greek + Win32 + + + Release Greek + x64 + + + Release Hebrew + Win32 + + + Release Hebrew + x64 + + + Release Hungarian + Win32 + + + Release Hungarian + x64 + + + Release Indonesian + Win32 + + + Release Indonesian + x64 + + + Release Italian + Win32 + + + Release Italian + x64 + + + Release Japanese + Win32 + + + Release Japanese + x64 + + + Release Korean + Win32 + + + Release Korean + x64 + + + Release Lithuanian + Win32 + + + Release Lithuanian + x64 + + + Release Malay + Win32 + + + Release Malay + x64 + + + Release Polish + Win32 + + + Release Polish + x64 + + + Release Portuguese (Brazil) + Win32 + + + Release Portuguese (Brazil) + x64 + + + Release Portuguese (Portugal) + Win32 + + + Release Portuguese (Portugal) + x64 + + + Release Punjabi + Win32 + + + Release Punjabi + x64 + + + Release Romanian + Win32 + + + Release Romanian + x64 + + + Release Russian + Win32 + + + Release Russian + x64 + + + Release Serbian + Win32 + + + Release Serbian + x64 + + + Release Slovak + Win32 + + + Release Slovak + x64 + + + Release Slovenian + Win32 + + + Release Slovenian + x64 + + + Release Spanish + Win32 + + + Release Spanish + x64 + + + Release Swedish + Win32 + + + Release Swedish + x64 + + + Release Tatar + Win32 + + + Release Tatar + x64 + + + Release Thai + Win32 + + + Release Thai + x64 + + + Release Turkish + Win32 + + + Release Turkish + x64 + + + Release Ukrainian + Win32 + + + Release Ukrainian + x64 + + + Release Vietnamese + Win32 + + + Release Vietnamese + x64 + + + + {A57CBE1A-3703-4237-950A-FC5F594FDB43} + mpcresources + Win32Proj + mpcresources + + + + + DynamicLibrary + Unicode + + + + + + + + + + + $(SolutionDir)bin\mpc-hc_x86\Lang\ + $(SolutionDir)bin\mpc-hc_x64\Lang\ + $(SolutionDir)bin\obj\Release_$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName).ar + $(ProjectName).hy + $(ProjectName).eu + $(ProjectName).be + $(ProjectName).bn + $(ProjectName).bs_BA + $(ProjectName).bg + $(ProjectName).ca + $(ProjectName).zh_CN + $(ProjectName).zh_TW + $(ProjectName).hr + $(ProjectName).cs + $(ProjectName).da + $(ProjectName).nl + $(ProjectName).en_GB + $(ProjectName).fi + $(ProjectName).fr + $(ProjectName).gl + $(ProjectName).de + $(ProjectName).el + $(ProjectName).he + $(ProjectName).hu + $(ProjectName).id + $(ProjectName).it + $(ProjectName).ja + $(ProjectName).ko + $(ProjectName).lt + $(ProjectName).ms_MY + $(ProjectName).pl + $(ProjectName).pt_BR + $(ProjectName).pt_PT + $(ProjectName).pa + $(ProjectName).ro + $(ProjectName).ru + $(ProjectName).sr + $(ProjectName).sk + $(ProjectName).sl + $(ProjectName).es + $(ProjectName).sv + $(ProjectName).tt + $(ProjectName).th_TH + $(ProjectName).tr + $(ProjectName).uk + $(ProjectName).vi + + + $(SolutionDir)bin15\mpc-hc_x86\Lang\ + $(SolutionDir)bin15\mpc-hc_x64\Lang\ + $(SolutionDir)bin15\obj\Release_$(Platform)\$(ProjectName)\$(Configuration)\ + + + + false + + + Default + false + true + true + + + ..\..\..\include;..;%(AdditionalIncludeDirectories) + NO_VERSION_REV_NEEDED;%(PreprocessorDefinitions) + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + + + {904017f7-ee7a-49b6-a000-0d2fe5d5809a} + false + + + + + + diff --git a/src/mpc-hc/mpcresources/mpcresources.vcxproj.filters b/src/mpc-hc/mpcresources/mpcresources.vcxproj.filters index 1ce5258f723..ab875c6db94 100644 --- a/src/mpc-hc/mpcresources/mpcresources.vcxproj.filters +++ b/src/mpc-hc/mpcresources/mpcresources.vcxproj.filters @@ -1,160 +1,160 @@ - - - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - Resource Files - - - - - Header Files - - - Header Files - - - - - Resource Files - - - + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + diff --git a/src/mpc-hc/mplayerc.cpp b/src/mpc-hc/mplayerc.cpp index 0a7b0cbd2f0..88de0955d8d 100644 --- a/src/mpc-hc/mplayerc.cpp +++ b/src/mpc-hc/mplayerc.cpp @@ -1,2825 +1,2825 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2018 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 . - * - */ - -#include "stdafx.h" -#include "mplayerc.h" -#include "AboutDlg.h" -#include "CmdLineHelpDlg.h" -#include "CrashReporter.h" -#include "DSUtil.h" -#include "FakeFilterMapper2.h" -#include "FileAssoc.h" -#include "FileVersionInfo.h" -#include "Ifo.h" -#include "MainFrm.h" -#include "MhookHelper.h" -#include "PPageFormats.h" -#include "PPageSheet.h" -#include "PathUtils.h" -#include "Struct.h" -#include "UpdateChecker.h" -#include "WebServer.h" -#include "WinAPIUtils.h" -#include "mpc-hc_config.h" -#include "winddk/ntddcdvd.h" -#include -#include -#include -#include -#include "ExceptionHandler.h" -#include "FGFilterLAV.h" -#include "CMPCThemeMsgBox.h" -#include "version.h" -#include "psapi.h" - -HICON LoadIcon(CString fn, bool bSmallIcon, DpiHelper* pDpiHelper/* = nullptr*/) -{ - if (fn.IsEmpty()) { - return nullptr; - } - - CString ext = fn.Left(fn.Find(_T("://")) + 1).TrimRight(':'); - if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) { - ext = _T(".") + fn.Mid(fn.ReverseFind('.') + 1); - } - - CSize size(bSmallIcon ? GetSystemMetrics(SM_CXSMICON) : GetSystemMetrics(SM_CXICON), - bSmallIcon ? GetSystemMetrics(SM_CYSMICON) : GetSystemMetrics(SM_CYICON)); - - if (pDpiHelper) { - size.cx = pDpiHelper->ScaleSystemToOverrideX(size.cx); - size.cy = pDpiHelper->ScaleSystemToOverrideY(size.cy); - } - - typedef HRESULT(WINAPI * LIWSD)(HINSTANCE, PCWSTR, int, int, HICON*); - auto loadIcon = [&size](PCWSTR pszName) { - LIWSD pLIWSD = (LIWSD)GetProcAddress(GetModuleHandle(_T("comctl32.dll")), "LoadIconWithScaleDown"); - HICON ret = nullptr; - if (pLIWSD) { - pLIWSD(AfxGetInstanceHandle(), pszName, size.cx, size.cy, &ret); - } else { - ret = (HICON)LoadImage(AfxGetInstanceHandle(), pszName, IMAGE_ICON, size.cx, size.cy, 0); - } - return ret; - }; - - if (!ext.CompareNoCase(_T(".ifo"))) { - if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_DVD))) { - return hIcon; - } - } - - if (!ext.CompareNoCase(_T(".cda"))) { - if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_AUDIOCD))) { - return hIcon; - } - } - - if (!ext.CompareNoCase(_T(".unknown"))) { - if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_UNKNOWN))) { - return hIcon; - } - } - - do { - CRegKey key; - TCHAR buff[256]; - ULONG len; - - auto openRegKey = [&](HKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValueName) { - if (ERROR_SUCCESS == key.Open(hKeyParent, lpszKeyName, KEY_READ)) { - len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - CString progId; - - if (ERROR_SUCCESS == key.QueryStringValue(lpszValueName, buff, &len) && !(progId = buff).Trim().IsEmpty()) { - return (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, progId + _T("\\DefaultIcon"), KEY_READ)); - } - } - return false; - }; - - if (!openRegKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\") + ext + _T("\\UserChoice"), _T("Progid")) - && !openRegKey(HKEY_CLASSES_ROOT, ext, nullptr) - && ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, ext + _T("\\DefaultIcon"), KEY_READ)) { - break; - } - - CString icon; - len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len) || (icon = buff).Trim().IsEmpty()) { - break; - } - - int i = icon.ReverseFind(','); - if (i < 0) { - break; - } - - int id = 0; - if (_stscanf_s(icon.Mid(i + 1), _T("%d"), &id) != 1) { - break; - } - - icon = icon.Left(i); - icon.Trim(_T(" \\\"")); - - HICON hIcon = nullptr; - UINT cnt = bSmallIcon - ? ExtractIconEx(icon, id, nullptr, &hIcon, 1) - : ExtractIconEx(icon, id, &hIcon, nullptr, 1); - if (hIcon && cnt == 1) { - return hIcon; - } - } while (0); - - return loadIcon(MAKEINTRESOURCE(IDI_UNKNOWN)); -} - -bool LoadType(CString fn, CString& type) -{ - bool found = false; - - if (!fn.IsEmpty()) { - CString ext = fn.Left(fn.Find(_T("://")) + 1).TrimRight(':'); - if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) { - ext = _T(".") + fn.Mid(fn.ReverseFind('.') + 1); - } - - // Try MPC-HC's internal formats list - const CMediaFormatCategory* mfc = AfxGetAppSettings().m_Formats.FindMediaByExt(ext); - - if (mfc != nullptr) { - found = true; - type = mfc->GetDescription(); - } else { // Fallback to registry - CRegKey key; - TCHAR buff[256]; - ULONG len; - - CString tmp = _T(""); - CString mplayerc_ext = _T("mplayerc") + ext; - - if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, mplayerc_ext)) { - tmp = mplayerc_ext; - } - - if (!tmp.IsEmpty() || ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, ext)) { - found = true; - - if (tmp.IsEmpty()) { - tmp = ext; - } - - while (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, tmp)) { - len = _countof(buff); - ZeroMemory(buff, sizeof(buff)); - - if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len)) { - break; - } - - CString str(buff); - str.Trim(); - - if (str.IsEmpty() || str == tmp) { - break; - } - - tmp = str; - } - - type = tmp; - } - } - } - - return found; -} - -bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype) -{ - str.Empty(); - HRSRC hrsrc = FindResource(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(resid), restype); - if (!hrsrc) { - return false; - } - HGLOBAL hGlobal = LoadResource(AfxGetApp()->m_hInstance, hrsrc); - if (!hGlobal) { - return false; - } - DWORD size = SizeofResource(AfxGetApp()->m_hInstance, hrsrc); - if (!size) { - return false; - } - memcpy(str.GetBufferSetLength(size), LockResource(hGlobal), size); - return true; -} - -static bool FindRedir(const CUrl& src,const CString& body, CAtlList& urls, const std::vector& res) -{ - bool bDetectHLS = false; - for (const auto re : res) { - std::wcmatch mc; - - for (LPCTSTR s = body; std::regex_search(s, mc, re); s += mc.position() + mc.length()) { - CString url = mc[mc.size() - 1].str().c_str(); - url.Trim(); - - if (url.CompareNoCase(_T("asf path")) == 0) { - continue; - } - if (url.Find(_T("EXTM3U")) == 0 || url.Find(_T("#EXTINF")) == 0) { - bDetectHLS = true; - continue; - } - // Detect HTTP Live Streaming and let the source filter handle that - if (bDetectHLS - && (url.Find(_T("EXT-X-STREAM-INF:")) != -1 - || url.Find(_T("EXT-X-TARGETDURATION:")) != -1 - || url.Find(_T("EXT-X-MEDIA-SEQUENCE:")) != -1)) { - urls.RemoveAll(); - break; - } - - CUrl dst; - dst.CrackUrl(CString(url)); - if (_tcsicmp(src.GetSchemeName(), dst.GetSchemeName()) - || _tcsicmp(src.GetHostName(), dst.GetHostName()) - || _tcsicmp(src.GetUrlPath(), dst.GetUrlPath())) { - urls.AddTail(url); - } else { - // recursive - urls.RemoveAll(); - break; - } - } - } - - return !urls.IsEmpty(); -} - -static bool FindRedir(const CString& fn, CAtlList& fns, const std::vector& res) -{ - CString body; - - CTextFile f(CTextFile::UTF8); - if (f.Open(fn)) { - int i = 0; - for (CString tmp; i < 10000 && f.ReadString(tmp); body += tmp + '\n', ++i) { - ; - } - } - - CString dir = fn.Left(std::max(fn.ReverseFind('/'), fn.ReverseFind('\\')) + 1); // "ReverseFindOneOf" - - for (const auto re : res) { - std::wcmatch mc; - - for (LPCTSTR s = body; std::regex_search(s, mc, re); s += mc.position() + mc.length()) { - CString fn2 = mc[mc.size() - 1].str().c_str(); - fn2.Trim(); - - if (!fn2.CompareNoCase(_T("asf path"))) { - continue; - } - if (fn2.Find(_T("EXTM3U")) == 0 || fn2.Find(_T("#EXTINF")) == 0) { - continue; - } - - if (fn2.Find(_T(":")) < 0 && fn2.Find(_T("\\\\")) != 0 && fn2.Find(_T("//")) != 0) { - CPath p; - p.Combine(dir, fn2); - fn2 = (LPCTSTR)p; - } - - if (!fn2.CompareNoCase(fn)) { - continue; - } - - fns.AddTail(fn2); - } - } - - return !fns.IsEmpty(); -} - - -CString GetContentType(CString fn, CAtlList* redir) -{ - fn.Trim(); - if (fn.IsEmpty()) { - return ""; - } - - CUrl url; - CString content, body; - BOOL url_fail = false; - BOOL ishttp = false; - BOOL parsefile = false; - BOOL isurl = PathUtils::IsURL(fn); - - // Get content type based on the URI scheme - if (isurl) { - url.CrackUrl(fn); - - if (_tcsicmp(url.GetSchemeName(), _T("pnm")) == 0) { - return "audio/x-pn-realaudio"; - } - if (_tcsicmp(url.GetSchemeName(), _T("mms")) == 0) { - return "video/x-ms-asf"; - } - if (_tcsicmp(url.GetSchemeName(), _T("http")) == 0 || _tcsicmp(url.GetSchemeName(), _T("https")) == 0) { - ishttp = true; - } else { - return ""; - } - } - - CString ext = CPath(fn).GetExtension().MakeLower(); - int p = ext.FindOneOf(_T("?#")); - if (p > 0) { - ext = ext.Left(p); - } - - // no further analysis needed if known audio/video extension and points directly to a file - if (!ext.IsEmpty()) { - if (ext == _T(".mp4") || ext == _T(".m4v") || ext == _T(".mov") || ext == _T(".mkv") || ext == _T(".webm") || ext == _T(".avi") || ext == _T(".wmv") || ext == _T(".mpg") || ext == _T(".mpeg") || ext == _T(".flv") || ext == _T(".ogm") || ext == _T(".m2ts") || ext == _T(".ts")) { - content = _T("video"); - } else if (ext == _T(".mp3") || ext == _T(".m4a") || ext == _T(".aac") || ext == _T(".flac") || ext == _T(".mka") || ext == _T(".ogg") || ext == _T(".opus")) { - content = _T("audio"); - } else if (ext == _T(".mpcpl")) { - content = _T("application/x-mpc-playlist"); - } else if (ext == _T(".m3u") || ext == _T(".m3u8")) { - content = _T("audio/x-mpegurl"); - } else if (ext == _T(".bdmv")) { - content = _T("application/x-bdmv-playlist"); - } else if (ext == _T(".cue")) { - content = _T("application/x-cue-sheet"); - } else if (ext == _T(".swf")) { - content = _T("application/x-shockwave-flash"); - } - - if (!content.IsEmpty()) { - return content; - } - } - - // Get content type by getting the header response from server - if (ishttp) { - CInternetSession internet; - internet.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 5000); - CString headers = _T("User-Agent: MPC-HC"); - CHttpFile* httpFile = NULL; - try { - httpFile = (CHttpFile*)internet.OpenURL(fn, - 1, - INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, - headers, - DWORD(-1)); - } - catch (CInternetException* pEx) - { - pEx->Delete(); - url_fail = true; // Timeout has most likely occured, server unreachable - return content; - } - - if (httpFile) { - //CString strContentType; - //httpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS, strContentType); // Check also HTTP_QUERY_RAW_HEADERS_CRLF - //DWORD dw = 8192; // Arbitrary 8192 char length for Url (should handle most cases) - //CString urlredirect; // Retrieve the new Url in case we encountered an HTTP redirection (HTTP 302 code) - //httpFile->QueryOption(INTERNET_OPTION_URL, urlredirect.GetBuffer(8192), &dw); - DWORD dwStatus; - httpFile->QueryInfoStatusCode(dwStatus); - switch (dwStatus) { - case HTTP_STATUS_OK: // 200 request completed - case HTTP_STATUS_CREATED: // 201 object created, reason = new URI - case HTTP_STATUS_ACCEPTED: // 202 async completion (TBS) - case HTTP_STATUS_PARTIAL: // 203 partial completion - case HTTP_STATUS_NO_CONTENT: // 204 no info to return - case HTTP_STATUS_RESET_CONTENT: // 205 request completed, but clear form - case HTTP_STATUS_PARTIAL_CONTENT: // 206 partial GET furfilled - case HTTP_STATUS_AMBIGUOUS: // 300 server couldn't decide what to return - case HTTP_STATUS_MOVED: // 301 object permanently moved - case HTTP_STATUS_REDIRECT: // 302 object temporarily moved - case HTTP_STATUS_REDIRECT_METHOD: // 303 redirection w/ new access method - case HTTP_STATUS_NOT_MODIFIED: // 304 if-modified-since was not modified - case HTTP_STATUS_USE_PROXY: // 305 redirection to proxy, location header specifies proxy to use - case HTTP_STATUS_REDIRECT_KEEP_VERB: // 307 HTTP/1.1: keep same verb - case 308/*HTTP_STATUS_PERMANENT_REDIRECT*/: // 308 Object permanently moved keep verb - break; - default: - //CString strStatus; - //httpFile->QueryInfo(HTTP_QUERY_STATUS_TEXT, strStatus); // Status String - eg OK, Not Found - url_fail = true; - } - - if (url_fail) { - httpFile->Close(); // Close() isn't called by the destructor - delete httpFile; - return content; - } - - if (content.IsEmpty()) { - httpFile->QueryInfo(HTTP_QUERY_CONTENT_TYPE, content); // Content-Type - eg text/html - } - - long contentsize = 0; - CString contentlength = _T(""); - if (httpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, contentlength)) { - contentsize = _ttol(contentlength); - } - - // Partial download of response body to further identify content types - if (content.IsEmpty() && contentsize < 256*1024) { - UINT br = 0; - char buffer[513] = ""; - while (body.GetLength() < 256) { - br = httpFile->Read(buffer, 256); - if (br == 0) { - break; - } - buffer[br] = '\0'; - body += buffer; - } - if (body.GetLength() >= 8) { - BOOL exit = false; - if (!wcsncmp((LPCWSTR)body, _T(".ra"), 3)) { - content = _T("audio/x-pn-realaudio"); - exit = true; - } else if (!wcsncmp((LPCWSTR)body, _T(".RMF"), 4)) { - content = _T("audio/x-pn-realaudio"); - exit = true; - } - - if (exit) { - httpFile->Close(); - delete httpFile; - return content; - } - } - } - // Download larger piece of response body in case it's a playlist - if (redir && contentsize < 256*1024 && (content == _T("audio/x-scpls") || content == _T("audio/scpls") - || content == _T("video/x-ms-asf") || content == _T("text/plain") - || content == _T("application/octet-stream") || content == _T("application/pls+xml"))) { - UINT br = 0; - char buffer[513] = ""; - while (body.GetLength() < 64 * 1024) { // should be enough for a playlist... - br = httpFile->Read(buffer, 256); - if (br == 0) { - break; - } - buffer[br] = '\0'; - body += buffer; - } - } - - httpFile->Close(); - delete httpFile; - } - } - - // If content type is empty, plain text or octet-stream (weird server!) GUESS by extension if it exists..... - if (content.IsEmpty() || content == _T("text/plain") || content == _T("application/octet-stream")) { - if (ext == _T(".pls")) { - content = _T("audio/x-scpls"); - parsefile = true; - } else if (ext == _T(".asx")) { - content = _T("video/x-ms-asf"); - parsefile = true; - } else if (ext == _T(".ram")) { - content = _T("audio/x-pn-realaudio"); - parsefile = true; - } - } - - if (redir && !content.IsEmpty() && (isurl && !body.IsEmpty() || !isurl && parsefile)) { - std::vector res; - const std::wregex::flag_type reFlags = std::wregex::icase | std::wregex::optimize; - - if (content == _T("video/x-ms-asf")) { - // ...://..."/> - res.emplace_back(_T("[a-zA-Z]+://[^\n\">]*"), reFlags); - // Ref#n= ...://...\n - res.emplace_back(_T("Ref\\d+\\s*=\\s*[\"]*([a-zA-Z]+://[^\n\"]+)"), reFlags); - } - else if (content == _T("audio/x-scpls") || content == _T("audio/scpls") || content == _T("application/pls+xml")) { - // File1=...\n - res.emplace_back(_T("file\\d+\\s*=\\s*[\"]*([^\n\"]+)"), reFlags); - } - else if (content == _T("audio/x-pn-realaudio")) { - // rtsp://... - res.emplace_back(_T("rtsp://[^\n]+"), reFlags); - // http://... - res.emplace_back(_T("http://[^\n]+"), reFlags); - } - - if (res.size()) { - if (isurl) { - FindRedir(url, body, *redir, res); - } else { - FindRedir(fn, *redir, res); - } - } - } - - return content; -} - -WORD AssignedToCmd(UINT keyValue) -{ - if (keyValue == 0) { - ASSERT(false); - return 0; - } - - WORD assignTo = 0; - const CAppSettings& s = AfxGetAppSettings(); - - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos && !assignTo) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - - if (wc.key == keyValue) { - assignTo = wc.cmd; - } - } - - return assignTo; -} - -std::map GetAudioDeviceList() { - std::map devicelist; - BeginEnumSysDev(CLSID_AudioRendererCategory, pMoniker) { - CComHeapPtr olestr; - if (FAILED(pMoniker->GetDisplayName(0, 0, &olestr))) { - continue; - } - CStringW dispname(olestr); - CStringW friendlyname; - CComPtr pPB; - if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)))) { - CComVariant var; - if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { - CStringW frname(var.bstrVal); - var.Clear(); - friendlyname = frname; - } - } else { - friendlyname = dispname; - } - devicelist.emplace(friendlyname, dispname); - } - EndEnumSysDev; - - return devicelist; -} - -void SetAudioRenderer(int AudioDevNo) -{ - CStringArray dispnames; - AfxGetMyApp()->m_AudioRendererDisplayName_CL = _T(""); - dispnames.Add(_T("")); - dispnames.Add(AUDRNDT_INTERNAL); - dispnames.Add(AUDRNDT_MPC); - int devcount = 3; - - std::map devicelist = GetAudioDeviceList(); - - for (auto it = devicelist.cbegin(); it != devicelist.cend(); it++) { - dispnames.Add((*it).second); - devcount++; - } - - dispnames.Add(AUDRNDT_NULL_COMP); - dispnames.Add(AUDRNDT_NULL_UNCOMP); - devcount += 2; - - if (AudioDevNo >= 1 && AudioDevNo <= devcount) { - AfxGetMyApp()->m_AudioRendererDisplayName_CL = dispnames[AudioDevNo - 1]; - } -} - -void SetHandCursor(HWND m_hWnd, UINT nID) -{ - SetClassLongPtr(GetDlgItem(m_hWnd, nID), GCLP_HCURSOR, (LONG_PTR)AfxGetApp()->LoadStandardCursor(IDC_HAND)); -} - -// CMPlayerCApp - -CMPlayerCApp::CMPlayerCApp() - : m_hNTDLL(nullptr) - , m_bDelayingIdle(false) - , m_bProfileInitialized(false) - , m_bQueuedProfileFlush(false) - , m_dwProfileLastAccessTick(0) - , m_fClosingState(false) - , m_bThemeLoaded(false) -{ - m_strVersion = FileVersionInfo::GetFileVersionStr(PathUtils::GetProgramPath(true)); - - ZeroMemory(&m_ColorControl, sizeof(m_ColorControl)); - ResetColorControlRange(); - - ZeroMemory(&m_VMR9ColorControl, sizeof(m_VMR9ColorControl)); - m_VMR9ColorControl[0].dwSize = sizeof(VMR9ProcAmpControlRange); - m_VMR9ColorControl[0].dwProperty = ProcAmpControl9_Brightness; - m_VMR9ColorControl[1].dwSize = sizeof(VMR9ProcAmpControlRange); - m_VMR9ColorControl[1].dwProperty = ProcAmpControl9_Contrast; - m_VMR9ColorControl[2].dwSize = sizeof(VMR9ProcAmpControlRange); - m_VMR9ColorControl[2].dwProperty = ProcAmpControl9_Hue; - m_VMR9ColorControl[3].dwSize = sizeof(VMR9ProcAmpControlRange); - m_VMR9ColorControl[3].dwProperty = ProcAmpControl9_Saturation; - - ZeroMemory(&m_EVRColorControl, sizeof(m_EVRColorControl)); - - GetRemoteControlCode = GetRemoteControlCodeMicrosoft; -} - -CMPlayerCApp::~CMPlayerCApp() -{ - if (m_hNTDLL) { - FreeLibrary(m_hNTDLL); - } - // Wait for any pending I/O operations to be canceled - while (WAIT_IO_COMPLETION == SleepEx(0, TRUE)); -} - -int CMPlayerCApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, - UINT nIDPrompt) -{ - if (AppIsThemeLoaded()) { - CWnd* pParentWnd = CWnd::GetActiveWindow(); - if (pParentWnd == NULL) { - pParentWnd = GetMainWnd(); - if (pParentWnd == NULL) { - return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt); - } else { - pParentWnd = pParentWnd->GetLastActivePopup(); - } - } - - CMPCThemeMsgBox dlgMessage(pParentWnd, lpszPrompt, _T(""), nType, - nIDPrompt); - - return (int)dlgMessage.DoModal(); - } else { - return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt); - } -} - -void CMPlayerCApp::DelayedIdle() -{ - m_bDelayingIdle = false; -} - -BOOL CMPlayerCApp::IsIdleMessage(MSG* pMsg) -{ - BOOL ret = __super::IsIdleMessage(pMsg); - if (ret && pMsg->message == WM_MOUSEMOVE) { - if (m_bDelayingIdle) { - ret = FALSE; - } else { - auto pMainFrm = AfxGetMainFrame(); - if (pMainFrm && m_pMainWnd) { - const unsigned uTimeout = 100; - // delay next WM_MOUSEMOVE initiated idle for uTimeout ms - // if there will be no WM_MOUSEMOVE messages, WM_TIMER will initiate the idle - pMainFrm->m_timerOneTime.Subscribe( - CMainFrame::TimerOneTimeSubscriber::DELAY_IDLE, std::bind(&CMPlayerCApp::DelayedIdle, this), uTimeout); - m_bDelayingIdle = true; - } - } - } - return ret; -} - -BOOL CMPlayerCApp::OnIdle(LONG lCount) -{ - BOOL ret = __super::OnIdle(lCount); - - if (!ret) { - FlushProfile(false); - } - - return ret; -} - -BOOL CMPlayerCApp::PumpMessage() -{ - return MsgWaitForMultipleObjectsEx(0, nullptr, INFINITE, QS_ALLINPUT, - MWMO_INPUTAVAILABLE | MWMO_ALERTABLE) == WAIT_IO_COMPLETION ? TRUE : __super::PumpMessage(); -} - -void CMPlayerCApp::ShowCmdlnSwitches() const -{ - CString cmdLine; - - if ((m_s->nCLSwitches & CLSW_UNRECOGNIZEDSWITCH) && __argc > 0) { - cmdLine = __targv[0]; - for (int i = 1; i < __argc; i++) { - cmdLine.AppendFormat(_T(" %s"), __targv[i]); - } - } - - CmdLineHelpDlg dlg(cmdLine); - dlg.DoModal(); -} - -CMPlayerCApp theApp; // The one and only CMPlayerCApp object - -HWND g_hWnd = nullptr; - -bool CMPlayerCApp::StoreSettingsToIni() -{ - std::lock_guard lock(m_profileMutex); - - CString ini = GetIniPath(); - free((void*)m_pszRegistryKey); - m_pszRegistryKey = nullptr; - free((void*)m_pszProfileName); - m_pszProfileName = _tcsdup(ini); - - return true; -} - -bool CMPlayerCApp::StoreSettingsToRegistry() -{ - std::lock_guard lock(m_profileMutex); - - free((void*)m_pszRegistryKey); - m_pszRegistryKey = nullptr; - - SetRegistryKey(_T("MPC-HC")); - - return true; -} - -CString CMPlayerCApp::GetIniPath() const -{ - CString path = PathUtils::GetProgramPath(true); - path = path.Left(path.ReverseFind('.') + 1) + _T("ini"); - return path; -} - -bool CMPlayerCApp::IsIniValid() const -{ - return PathUtils::Exists(GetIniPath()); -} - -bool CMPlayerCApp::GetAppSavePath(CString& path) -{ - if (IsIniValid()) { // If settings ini file found, store stuff in the same folder as the exe file - path = PathUtils::GetProgramPath(); - } else { - return GetAppDataPath(path); - } - - return true; -} - -bool CMPlayerCApp::GetAppDataPath(CString& path) -{ - path.Empty(); - - HRESULT hr = SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, 0, path.GetBuffer(MAX_PATH)); - path.ReleaseBuffer(); - if (FAILED(hr)) { - return false; - } - CPath p; - p.Combine(path, _T("MPC-HC")); - path = (LPCTSTR)p; - - return true; -} - -bool CMPlayerCApp::ChangeSettingsLocation(bool useIni) -{ - std::lock_guard lock(m_profileMutex); - - bool success; - - // Load favorites so that they can be correctly saved to the new location - CAtlList filesFav, DVDsFav, devicesFav; - m_s->GetFav(FAV_FILE, filesFav); - m_s->GetFav(FAV_DVD, DVDsFav); - m_s->GetFav(FAV_DEVICE, devicesFav); - - if (useIni) { - success = StoreSettingsToIni(); - // No need to delete old mpc-hc.ini, - // as it will be overwritten during CAppSettings::SaveSettings() - } else { - success = StoreSettingsToRegistry(); - _tremove(GetIniPath()); - } - - // Save favorites to the new location - m_s->SetFav(FAV_FILE, filesFav); - m_s->SetFav(FAV_DVD, DVDsFav); - m_s->SetFav(FAV_DEVICE, devicesFav); - - // Save external filters to the new location - m_s->SaveExternalFilters(); - - // Write settings immediately - m_s->SaveSettings(true); - - return success; -} - -bool CMPlayerCApp::ExportSettings(CString savePath, CString subKey) -{ - bool success = false; - m_s->SaveSettings(); - - if (IsIniValid()) { - success = !!CopyFile(GetIniPath(), savePath, FALSE); - } else { - CString regKey; - if (subKey.IsEmpty()) { - regKey.Format(_T("Software\\%s\\%s"), m_pszRegistryKey, m_pszProfileName); - } else { - regKey.Format(_T("Software\\%s\\%s\\%s"), m_pszRegistryKey, m_pszProfileName, subKey.GetString()); - } - - FILE* fStream; - errno_t error = _tfopen_s(&fStream, savePath, _T("wt,ccs=UNICODE")); - CStdioFile file(fStream); - file.WriteString(_T("Windows Registry Editor Version 5.00\n\n")); - - success = !error && ExportRegistryKey(file, HKEY_CURRENT_USER, regKey); - - file.Close(); - if (!success && !error) { - DeleteFile(savePath); - } - } - - return success; -} - -void CMPlayerCApp::InitProfile() -{ - std::lock_guard lock(m_profileMutex); - - if (!m_pszRegistryKey) { - // Don't reread mpc-hc.ini if the cache needs to be flushed or it was accessed recently - if (m_bProfileInitialized && (m_bQueuedProfileFlush || GetTickCount64() - m_dwProfileLastAccessTick < 100ULL)) { - m_dwProfileLastAccessTick = GetTickCount64(); - return; - } - - m_bProfileInitialized = true; - m_dwProfileLastAccessTick = GetTickCount64(); - - ASSERT(m_pszProfileName); - if (!PathUtils::Exists(m_pszProfileName)) { - return; - } - - FILE* fp; - int fpStatus; - do { // Open mpc-hc.ini in UNICODE mode, retry if it is already being used by another process - fp = _tfsopen(m_pszProfileName, _T("r, ccs=UNICODE"), _SH_SECURE); - if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { - break; - } - Sleep(100); - } while (true); - if (!fp) { - ASSERT(FALSE); - return; - } - if (_ftell_nolock(fp) == 0L) { - // No BOM was consumed, assume mpc-hc.ini is ANSI encoded - fpStatus = fclose(fp); - ASSERT(fpStatus == 0); - do { // Reopen mpc-hc.ini in ANSI mode, retry if it is already being used by another process - fp = _tfsopen(m_pszProfileName, _T("r"), _SH_SECURE); - if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { - break; - } - Sleep(100); - } while (true); - if (!fp) { - ASSERT(FALSE); - return; - } - } - - CStdioFile file(fp); - - ASSERT(!m_bQueuedProfileFlush); - m_ProfileMap.clear(); - - CString line, section, var, val; - while (file.ReadString(line)) { - // Parse mpc-hc.ini file, this parser: - // - doesn't trim whitespaces - // - doesn't remove quotation marks - // - omits keys with empty names - // - omits unnamed sections - int pos = 0; - if (line[0] == _T('[')) { - pos = line.Find(_T(']')); - if (pos == -1) { - continue; - } - section = line.Mid(1, pos - 1); - } else if (line[0] != _T(';')) { - pos = line.Find(_T('=')); - if (pos == -1) { - continue; - } - var = line.Mid(0, pos); - val = line.Mid(pos + 1); - if (!section.IsEmpty() && !var.IsEmpty()) { - m_ProfileMap[section][var] = val; - } - } - } - fpStatus = fclose(fp); - ASSERT(fpStatus == 0); - - m_dwProfileLastAccessTick = GetTickCount64(); - } -} - -void CMPlayerCApp::FlushProfile(bool bForce/* = true*/) -{ - std::lock_guard lock(m_profileMutex); - - if (!m_pszRegistryKey) { - if (!bForce && !m_bQueuedProfileFlush) { - return; - } - - m_bQueuedProfileFlush = false; - - ASSERT(m_bProfileInitialized); - ASSERT(m_pszProfileName); - - FILE* fp; - int fpStatus; - do { // Open mpc-hc.ini, retry if it is already being used by another process - fp = _tfsopen(m_pszProfileName, _T("w, ccs=UTF-8"), _SH_SECURE); - if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { - break; - } - Sleep(100); - } while (true); - if (!fp) { - ASSERT(FALSE); - return; - } - CStdioFile file(fp); - CString line; - try { - file.WriteString(_T("; MPC-HC\n")); - for (auto it1 = m_ProfileMap.begin(); it1 != m_ProfileMap.end(); ++it1) { - line.Format(_T("[%s]\n"), it1->first.GetString()); - file.WriteString(line); - for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) { - line.Format(_T("%s=%s\n"), it2->first.GetString(), it2->second.GetString()); - file.WriteString(line); - } - } - } catch (CFileException& e) { - // Fail silently if disk is full - UNREFERENCED_PARAMETER(e); - ASSERT(FALSE); - } - fpStatus = fclose(fp); - ASSERT(fpStatus == 0); - } -} - -BOOL CMPlayerCApp::GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes) -{ - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - return CWinAppEx::GetProfileBinary(lpszSection, lpszEntry, ppData, pBytes); - } else { - if (!lpszSection || !lpszEntry || !ppData || !pBytes) { - ASSERT(FALSE); - return FALSE; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - CString valueStr; - - InitProfile(); - auto it1 = m_ProfileMap.find(sectionStr); - if (it1 != m_ProfileMap.end()) { - auto it2 = it1->second.find(keyStr); - if (it2 != it1->second.end()) { - valueStr = it2->second; - } - } - if (valueStr.IsEmpty()) { - return FALSE; - } - int length = valueStr.GetLength(); - // Encoding: each 4-bit sequence is coded in one character, from 'A' for 0x0 to 'P' for 0xf - if (length % 2) { - ASSERT(FALSE); - return FALSE; - } - for (int i = 0; i < length; i++) { - if (valueStr[i] < 'A' || valueStr[i] > 'P') { - ASSERT(FALSE); - return FALSE; - } - } - *pBytes = length / 2; - *ppData = new (std::nothrow) BYTE[*pBytes]; - if (!(*ppData)) { - ASSERT(FALSE); - return FALSE; - } - for (UINT i = 0; i < *pBytes; i++) { - (*ppData)[i] = BYTE((valueStr[i * 2] - 'A') | ((valueStr[i * 2 + 1] - 'A') << 4)); - } - return TRUE; - } -} - -UINT CMPlayerCApp::GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) -{ - std::lock_guard lock(m_profileMutex); - - int res = nDefault; - if (m_pszRegistryKey) { - res = CWinAppEx::GetProfileInt(lpszSection, lpszEntry, nDefault); - } else { - if (!lpszSection || !lpszEntry) { - ASSERT(FALSE); - return res; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return res; - } - - InitProfile(); - auto it1 = m_ProfileMap.find(sectionStr); - if (it1 != m_ProfileMap.end()) { - auto it2 = it1->second.find(keyStr); - if (it2 != it1->second.end()) { - res = _ttoi(it2->second); - } - } - } - return res; -} - -std::list CMPlayerCApp::GetSectionSubKeys(LPCWSTR lpszSection) { - std::lock_guard lock(m_profileMutex); - - std::list keys; - - if (m_pszRegistryKey) { - WCHAR achKey[MAX_REGKEY_LEN]; // buffer for subkey name - DWORD cbName; // size of name string - DWORD cSubKeys = 0; // number of subkeys - - if (HKEY hAppKey = GetAppRegistryKey()) { - HKEY hSectionKey; - if (ERROR_SUCCESS == RegOpenKeyExW(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey)) { - RegQueryInfoKeyW(hSectionKey, NULL, NULL, NULL, &cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - - if (cSubKeys) { - for (DWORD i = 0; i < cSubKeys; i++) { - cbName = MAX_REGKEY_LEN; - if (ERROR_SUCCESS == RegEnumKeyExW(hSectionKey, i, achKey, &cbName, NULL, NULL, NULL, NULL)){ - keys.push_back(achKey); - } - } - } - } - } - } else { - if (!lpszSection) { - ASSERT(FALSE); - return keys; - } - CStringW sectionStr(lpszSection); - if (sectionStr.IsEmpty()) { - ASSERT(FALSE); - return keys; - } - InitProfile(); - auto it1 = m_ProfileMap.begin(); - while (it1 != m_ProfileMap.end()) { - if (it1->first.Find(sectionStr + L"\\") == 0) { - CStringW subKey = it1->first.Mid(sectionStr.GetLength() + 1); - if (subKey.Find(L"\\") == -1) { - keys.push_back(subKey); - } - } - it1++; - } - - } - return keys; -} - - -CString CMPlayerCApp::GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault) -{ - std::lock_guard lock(m_profileMutex); - - CString res; - if (m_pszRegistryKey) { - res = CWinAppEx::GetProfileString(lpszSection, lpszEntry, lpszDefault); - } else { - if (!lpszSection || !lpszEntry) { - ASSERT(FALSE); - return res; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return res; - } - if (lpszDefault) { - res = lpszDefault; - } - - InitProfile(); - auto it1 = m_ProfileMap.find(sectionStr); - if (it1 != m_ProfileMap.end()) { - auto it2 = it1->second.find(keyStr); - if (it2 != it1->second.end()) { - res = it2->second; - } - } - } - return res; -} - -BOOL CMPlayerCApp::WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes) -{ - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - return CWinAppEx::WriteProfileBinary(lpszSection, lpszEntry, pData, nBytes); - } else { - if (!lpszSection || !lpszEntry || !pData || !nBytes) { - ASSERT(FALSE); - return FALSE; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - CString valueStr; - - TCHAR* buffer = valueStr.GetBufferSetLength(nBytes * 2); - // Encoding: each 4-bit sequence is coded in one character, from 'A' for 0x0 to 'P' for 0xf - for (UINT i = 0; i < nBytes; i++) { - buffer[i * 2] = 'A' + (pData[i] & 0xf); - buffer[i * 2 + 1] = 'A' + (pData[i] >> 4 & 0xf); - } - valueStr.ReleaseBufferSetLength(nBytes * 2); - - InitProfile(); - CString& old = m_ProfileMap[sectionStr][keyStr]; - if (old != valueStr) { - old = valueStr; - m_bQueuedProfileFlush = true; - } - return TRUE; - } -} - -LONG CMPlayerCApp::RemoveProfileKey(LPCWSTR lpszSection, LPCWSTR lpszEntry) { - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - if (HKEY hAppKey = GetAppRegistryKey()) { - HKEY hSectionKey; - if (ERROR_SUCCESS == RegOpenKeyEx(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey)) { - return CWinAppEx::DelRegTree(hSectionKey, lpszEntry); - } - } - } else { - if (!lpszSection || !lpszEntry) { - ASSERT(FALSE); - return 1; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return 1; - } - - InitProfile(); - auto it1 = m_ProfileMap.find(sectionStr + L"\\" + keyStr); - if (it1 != m_ProfileMap.end()) { - m_ProfileMap.erase(it1); - m_bQueuedProfileFlush = true; - } - } - return 0; -} - -BOOL CMPlayerCApp::WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) -{ - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - return CWinAppEx::WriteProfileInt(lpszSection, lpszEntry, nValue); - } else { - if (!lpszSection || !lpszEntry) { - ASSERT(FALSE); - return FALSE; - } - CString sectionStr(lpszSection); - CString keyStr(lpszEntry); - if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - CString valueStr; - valueStr.Format(_T("%d"), nValue); - - InitProfile(); - CString& old = m_ProfileMap[sectionStr][keyStr]; - if (old != valueStr) { - old = valueStr; - m_bQueuedProfileFlush = true; - } - return TRUE; - } -} - -BOOL CMPlayerCApp::WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) -{ - std::lock_guard lock(m_profileMutex); - - if (m_pszRegistryKey) { - return CWinAppEx::WriteProfileString(lpszSection, lpszEntry, lpszValue); - } else { - if (!lpszSection) { - ASSERT(FALSE); - return FALSE; - } - CString sectionStr(lpszSection); - if (sectionStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - CString keyStr(lpszEntry); - if (lpszEntry && keyStr.IsEmpty()) { - ASSERT(FALSE); - return FALSE; - } - - InitProfile(); - - // Mimic CWinAppEx::WriteProfileString() behavior - if (lpszEntry) { - if (lpszValue) { - CString& old = m_ProfileMap[sectionStr][keyStr]; - if (old != lpszValue) { - old = lpszValue; - m_bQueuedProfileFlush = true; - } - } else { // Delete key - auto it = m_ProfileMap.find(sectionStr); - if (it != m_ProfileMap.end()) { - if (it->second.erase(keyStr)) { - m_bQueuedProfileFlush = true; - } - } - } - } else { // Delete section - if (m_ProfileMap.erase(sectionStr)) { - m_bQueuedProfileFlush = true; - } - } - return TRUE; - } -} - -bool CMPlayerCApp::HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry) -{ - std::lock_guard lock(m_profileMutex); - - bool ret = false; - if (m_pszRegistryKey) { - if (HKEY hAppKey = GetAppRegistryKey()) { - HKEY hSectionKey; - if (RegOpenKeyEx(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey) == ERROR_SUCCESS) { - LONG lResult = RegQueryValueEx(hSectionKey, lpszEntry, nullptr, nullptr, nullptr, nullptr); - ret = (lResult == ERROR_SUCCESS); - VERIFY(RegCloseKey(hSectionKey) == ERROR_SUCCESS); - } - VERIFY(RegCloseKey(hAppKey) == ERROR_SUCCESS); - } else { - ASSERT(FALSE); - } - } else { - InitProfile(); - auto it1 = m_ProfileMap.find(lpszSection); - if (it1 != m_ProfileMap.end()) { - auto& sectionMap = it1->second; - auto it2 = sectionMap.find(lpszEntry); - ret = (it2 != sectionMap.end()); - } - } - return ret; -} - -std::vector CMPlayerCApp::GetProfileVectorInt(CString strSection, CString strKey) { - std::vector vData; - UINT uSize = theApp.GetProfileInt(strSection, strKey + _T("Size"), 0); - UINT uSizeRead = 0; - BYTE* temp = nullptr; - theApp.GetProfileBinary(strSection, strKey, &temp, &uSizeRead); - if (uSizeRead == uSize) { - vData.resize(uSizeRead / sizeof(int), 0); - memcpy(vData.data(), temp, uSizeRead); - } - delete[] temp; - temp = nullptr; - return vData; -} - - -void CMPlayerCApp::WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData) { - UINT uSize = static_cast(sizeof(int) * vData.size()); - theApp.WriteProfileBinary( - strSection, - strKey, - (LPBYTE)vData.data(), - uSize - ); - theApp.WriteProfileInt(strSection, strKey + _T("Size"), uSize); -} - -void CMPlayerCApp::PreProcessCommandLine() -{ - m_cmdln.RemoveAll(); - - for (int i = 1; i < __argc; i++) { - m_cmdln.AddTail(CString(__targv[i]).Trim(_T(" \""))); - } -} - -bool CMPlayerCApp::SendCommandLine(HWND hWnd) -{ - if (m_cmdln.IsEmpty()) { - return false; - } - - int bufflen = sizeof(DWORD); - - POSITION pos = m_cmdln.GetHeadPosition(); - while (pos) { - bufflen += (m_cmdln.GetNext(pos).GetLength() + 1) * sizeof(TCHAR); - } - - CAutoVectorPtr buff; - if (!buff.Allocate(bufflen)) { - return FALSE; - } - - BYTE* p = buff; - - *(DWORD*)p = (DWORD)m_cmdln.GetCount(); - p += sizeof(DWORD); - - pos = m_cmdln.GetHeadPosition(); - while (pos) { - const CString& s = m_cmdln.GetNext(pos); - int len = (s.GetLength() + 1) * sizeof(TCHAR); - memcpy(p, s, len); - p += len; - } - - COPYDATASTRUCT cds; - cds.dwData = 0x6ABE51; - cds.cbData = bufflen; - cds.lpData = (void*)(BYTE*)buff; - - return !!SendMessageTimeoutW(hWnd, WM_COPYDATA, (WPARAM)nullptr, (LPARAM)&cds, SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 5000, nullptr); -} - -// CMPlayerCApp initialization - -// This hook prevents the program from reporting that a debugger is attached -BOOL(WINAPI* Real_IsDebuggerPresent)() = IsDebuggerPresent; -BOOL WINAPI Mine_IsDebuggerPresent() -{ - TRACE(_T("Oops, somebody was trying to be naughty! (called IsDebuggerPresent)\n")); - return FALSE; -} - -// This hook prevents the program from reporting that a debugger is attached -NTSTATUS(WINAPI* Real_NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG) = nullptr; -NTSTATUS WINAPI Mine_NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength) -{ - NTSTATUS nRet; - - nRet = Real_NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength); - - if (ProcessInformationClass == ProcessBasicInformation) { - PROCESS_BASIC_INFORMATION* pbi = (PROCESS_BASIC_INFORMATION*)ProcessInformation; - PEB_NT* pPEB = (PEB_NT*)pbi->PebBaseAddress; - PEB_NT PEB; - - ReadProcessMemory(ProcessHandle, pPEB, &PEB, sizeof(PEB), nullptr); - PEB.BeingDebugged = FALSE; - WriteProcessMemory(ProcessHandle, pPEB, &PEB, sizeof(PEB), nullptr); - } else if (ProcessInformationClass == 7) { // ProcessDebugPort - BOOL* pDebugPort = (BOOL*)ProcessInformation; - *pDebugPort = FALSE; - } - - return nRet; -} - -#define USE_DLL_BLOCKLIST 1 - -#if USE_DLL_BLOCKLIST -#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) - -typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT; - -typedef enum _SECTION_INFORMATION_CLASS { - SectionBasicInformation = 0, - SectionImageInformation -} SECTION_INFORMATION_CLASS; - -typedef struct _SECTION_BASIC_INFORMATION { - PVOID BaseAddress; - ULONG Attributes; - LARGE_INTEGER Size; -} SECTION_BASIC_INFORMATION; - -typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtMapViewOfSection)(HANDLE, HANDLE, PVOID, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT, ULONG, ULONG); -typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtUnmapViewOfSection)(HANDLE, PVOID); -typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); -typedef DWORD(STDMETHODCALLTYPE* pfn_GetMappedFileNameW)(HANDLE, LPVOID, LPWSTR, DWORD); - -static pfn_NtMapViewOfSection Real_NtMapViewOfSection = nullptr; -static pfn_NtUnmapViewOfSection Real_NtUnmapViewOfSection = nullptr; -static pfn_NtQuerySection Real_NtQuerySection = nullptr; -static pfn_GetMappedFileNameW Real_GetMappedFileNameW = nullptr; - -typedef struct { - // DLL name, lower case, with backslash as prefix - const wchar_t* name; - size_t name_len; -} blocked_module_t; - -// list of modules that can cause crashes or other unwanted behavior -static blocked_module_t moduleblocklist[] = { -#if WIN64 - // Logitech codec - {_T("\\lvcod64.dll"), 12}, - // ProxyCodec64 - {_T("\\pxc0.dll"), 9}, -#else - {_T("\\mlc.dll"), 8}, -#endif - // Lame - {_T("\\lameacm.acm"), 12}, - // ffdshow vfw - {_T("\\ff_vfw.dll"), 11}, -#if WIN64 - // Trusteer Rapport - {_T("\\rooksbas_x64.dll"), 17}, - {_T("\\rooksdol_x64.dll"), 17}, - {_T("\\rapportgh_x64.dll"), 18}, -#endif - // ASUS GamerOSD - {_T("\\atkdx11disp.dll"), 16}, - // ASUS GPU TWEAK II OSD - {_T("\\gtii-osd64.dll"), 15}, - {_T("\\gtii-osd64-vk.dll"), 18}, - // Nahimic Audio - {L"\\nahimicmsidevprops.dll", 23}, - {L"\\nahimicmsiosd.dll", 18}, - // LoiLoGameRecorder - {_T("\\loilocap.dll"), 13}, - // Other - {_T("\\tortoiseoverlays.dll"), 21}, -#if WIN64 - // Sizer - {_T("\\hook64.dll"), 11}, -#endif -}; - -bool IsBlockedModule(wchar_t* modulename) -{ - size_t mod_name_len = wcslen(modulename); - - //TRACE(L"Checking module blocklist: %s\n", modulename); - - for (size_t i = 0; i < _countof(moduleblocklist); i++) { - blocked_module_t* b = &moduleblocklist[i]; - if (mod_name_len > b->name_len) { - wchar_t* dll_ptr = modulename + mod_name_len - b->name_len; - if (_wcsicmp(dll_ptr, b->name) == 0) { - //AfxMessageBox(modulename); - TRACE(L"Blocked module load: %s\n", modulename); - return true; - } - } - } - - return false; -} - -NTSTATUS STDMETHODCALLTYPE Mine_NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, - PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) -{ - NTSTATUS ret = Real_NtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); - - // Verify map and process - if (ret < 0 || ProcessHandle != GetCurrentProcess()) - return ret; - - // Fetch section information - SIZE_T wrote = 0; - SECTION_BASIC_INFORMATION section_information; - if (Real_NtQuerySection(SectionHandle, SectionBasicInformation, §ion_information, sizeof(section_information), &wrote) < 0) - return ret; - - // Verify fetch was successful - if (wrote != sizeof(section_information)) - return ret; - - // We're not interested in non-image maps - if (!(section_information.Attributes & SEC_IMAGE)) - return ret; - - // Get the actual filename if possible - wchar_t fileName[MAX_PATH]; - // ToDo: switch to PSAPI_VERSION=2 and directly use K32GetMappedFileNameW ? - if (Real_GetMappedFileNameW(ProcessHandle, *BaseAddress, fileName, _countof(fileName)) == 0) - return ret; - - if (IsBlockedModule(fileName)) { - Real_NtUnmapViewOfSection(ProcessHandle, BaseAddress); - ret = STATUS_UNSUCCESSFUL; - } - - return ret; -} -#endif - -static LONG Mine_ChangeDisplaySettingsEx(LONG ret, DWORD dwFlags, LPVOID lParam) -{ - if (dwFlags & CDS_VIDEOPARAMETERS) { - VIDEOPARAMETERS* vp = (VIDEOPARAMETERS*)lParam; - - if (vp->Guid == GUIDFromCString(_T("{02C62061-1097-11d1-920F-00A024DF156E}")) - && (vp->dwFlags & VP_FLAGS_COPYPROTECT)) { - if (vp->dwCommand == VP_COMMAND_GET) { - if ((vp->dwTVStandard & VP_TV_STANDARD_WIN_VGA) - && vp->dwTVStandard != VP_TV_STANDARD_WIN_VGA) { - TRACE(_T("Ooops, tv-out enabled? macrovision checks suck...")); - vp->dwTVStandard = VP_TV_STANDARD_WIN_VGA; - } - } else if (vp->dwCommand == VP_COMMAND_SET) { - TRACE(_T("Ooops, as I already told ya, no need for any macrovision bs here")); - return 0; - } - } - } - - return ret; -} - -// These two hooks prevent the program from requesting Macrovision checks -LONG(WINAPI* Real_ChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID) = ChangeDisplaySettingsExA; -LONG(WINAPI* Real_ChangeDisplaySettingsExW)(LPCWSTR, LPDEVMODEW, HWND, DWORD, LPVOID) = ChangeDisplaySettingsExW; -LONG WINAPI Mine_ChangeDisplaySettingsExA(LPCSTR lpszDeviceName, LPDEVMODEA lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam) -{ - return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExA(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam); -} -LONG WINAPI Mine_ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, LPDEVMODEW lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam) -{ - return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam); -} - -// This hook forces files to open even if they are currently being written -HANDLE(WINAPI* Real_CreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileA; -HANDLE WINAPI Mine_CreateFileA(LPCSTR p1, DWORD p2, DWORD p3, LPSECURITY_ATTRIBUTES p4, DWORD p5, DWORD p6, HANDLE p7) -{ - p3 |= FILE_SHARE_WRITE; - - return Real_CreateFileA(p1, p2, p3, p4, p5, p6, p7); -} - -static BOOL CreateFakeVideoTS(LPCWSTR strIFOPath, LPWSTR strFakeFile, size_t nFakeFileSize) -{ - BOOL bRet = FALSE; - WCHAR szTempPath[MAX_PATH]; - WCHAR strFileName[MAX_PATH]; - WCHAR strExt[_MAX_EXT]; - CIfo Ifo; - - if (!GetTempPathW(MAX_PATH, szTempPath)) { - return FALSE; - } - - _wsplitpath_s(strIFOPath, nullptr, 0, nullptr, 0, strFileName, _countof(strFileName), strExt, _countof(strExt)); - _snwprintf_s(strFakeFile, nFakeFileSize, _TRUNCATE, L"%sMPC%s%s", szTempPath, strFileName, strExt); - - if (Ifo.OpenFile(strIFOPath) && Ifo.RemoveUOPs() && Ifo.SaveFile(strFakeFile)) { - bRet = TRUE; - } - - return bRet; -} - -// This hook forces files to open even if they are currently being written and hijacks -// IFO file opening so that a modified IFO with no forbidden operations is opened instead. -HANDLE(WINAPI* Real_CreateFileW)(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileW; -HANDLE WINAPI Mine_CreateFileW(LPCWSTR p1, DWORD p2, DWORD p3, LPSECURITY_ATTRIBUTES p4, DWORD p5, DWORD p6, HANDLE p7) -{ - HANDLE hFile = INVALID_HANDLE_VALUE; - size_t nLen = wcslen(p1); - - p3 |= FILE_SHARE_WRITE; - - if (nLen >= 4 && _wcsicmp(p1 + nLen - 4, L".ifo") == 0) { - WCHAR strFakeFile[MAX_PATH]; - if (CreateFakeVideoTS(p1, strFakeFile, _countof(strFakeFile))) { - hFile = Real_CreateFileW(strFakeFile, p2, p3, p4, p5, p6, p7); - } - } - - if (hFile == INVALID_HANDLE_VALUE) { - hFile = Real_CreateFileW(p1, p2, p3, p4, p5, p6, p7); - } - - return hFile; -} - -// This hooks disables the DVD version check -BOOL(WINAPI* Real_DeviceIoControl)(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED) = DeviceIoControl; -BOOL WINAPI Mine_DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) -{ - BOOL ret = Real_DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); - if (IOCTL_DVD_GET_REGION == dwIoControlCode && lpOutBuffer && nOutBufferSize == sizeof(DVD_REGION)) { - DVD_REGION* pDVDRegion = (DVD_REGION*)lpOutBuffer; - - if (pDVDRegion->RegionData > 0) { - UCHAR disc_regions = ~pDVDRegion->RegionData; - if ((disc_regions & pDVDRegion->SystemRegion) == 0) { - if (disc_regions & 1) pDVDRegion->SystemRegion = 1; - else if (disc_regions & 2) pDVDRegion->SystemRegion = 2; - else if (disc_regions & 4) pDVDRegion->SystemRegion = 4; - else if (disc_regions & 8) pDVDRegion->SystemRegion = 8; - else if (disc_regions & 16) pDVDRegion->SystemRegion = 16; - else if (disc_regions & 32) pDVDRegion->SystemRegion = 32; - else if (disc_regions & 128) pDVDRegion->SystemRegion = 128; - ret = true; - } - } else if (pDVDRegion->SystemRegion == 0) { - pDVDRegion->SystemRegion = 1; - ret = true; - } - } - return ret; -} - -MMRESULT(WINAPI* Real_mixerSetControlDetails)(HMIXEROBJ, LPMIXERCONTROLDETAILS, DWORD) = mixerSetControlDetails; -MMRESULT WINAPI Mine_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) -{ - if (fdwDetails == (MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)) { - return MMSYSERR_NOERROR; // don't touch the mixer, kthx - } - return Real_mixerSetControlDetails(hmxobj, pmxcd, fdwDetails); -} - -BOOL (WINAPI* Real_LockWindowUpdate)(HWND) = LockWindowUpdate; -BOOL WINAPI Mine_LockWindowUpdate(HWND hWndLock) -{ - // TODO: Check if needed on Windows 8+ - if (hWndLock == ::GetDesktopWindow()) { - // locking the desktop window with aero active locks the entire compositor, - // unfortunately MFC does that (when dragging CControlBar) and we want to prevent it - return FALSE; - } else { - return Real_LockWindowUpdate(hWndLock); - } -} - -BOOL RegQueryBoolValue(HKEY hKeyRoot, LPCWSTR lpSubKey, LPCWSTR lpValuename, BOOL defaultvalue) { - BOOL result = defaultvalue; - HKEY hKeyOpen; - DWORD rv = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKeyOpen); - if (rv == ERROR_SUCCESS) { - DWORD data; - DWORD dwBufferSize = sizeof(DWORD); - rv = RegQueryValueEx(hKeyOpen, lpValuename, NULL, NULL, reinterpret_cast(&data), &dwBufferSize); - if (rv == ERROR_SUCCESS) { - result = (data > 0); - } - RegCloseKey(hKeyOpen); - } - return result; -} - -#if USE_DRDUMP_CRASH_REPORTER -void DisableCrashReporter() -{ - if (CrashReporter::IsEnabled()) { - CrashReporter::Disable(); - MPCExceptionHandler::Enable(); - } -} -#endif - -BOOL CMPlayerCApp::InitInstance() -{ - // Remove the working directory from the search path to work around the DLL preloading vulnerability - SetDllDirectory(_T("")); - - // At this point we have not hooked this function yet so we get the real result - if (!IsDebuggerPresent()) { -#if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER - if (RegQueryBoolValue(HKEY_CURRENT_USER, _T("Software\\MPC-HC\\MPC-HC\\Settings"), _T("EnableCrashReporter"), true)) { - CrashReporter::Enable(); - if (!CrashReporter::IsEnabled()) { - MPCExceptionHandler::Enable(); - } - } else { - MPCExceptionHandler::Enable(); - } -#else - MPCExceptionHandler::Enable(); -#endif - } - - if (!HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0)) { - TRACE(_T("Failed to enable \"terminate on corruption\" heap option, error %u\n"), GetLastError()); - ASSERT(FALSE); - } - - bool bHookingSuccessful = MH_Initialize() == MH_OK; - -#ifndef _DEBUG - bHookingSuccessful &= !!Mhook_SetHookEx(&Real_IsDebuggerPresent, Mine_IsDebuggerPresent); -#endif - - m_hNTDLL = LoadLibrary(_T("ntdll.dll")); -#if 0 -#ifndef _DEBUG // Disable NtQueryInformationProcess in debug (prevent VS debugger to stop on crash address) - if (m_hNTDLL) { - Real_NtQueryInformationProcess = (decltype(Real_NtQueryInformationProcess))GetProcAddress(m_hNTDLL, "NtQueryInformationProcess"); - - if (Real_NtQueryInformationProcess) { - bHookingSuccessful &= !!Mhook_SetHookEx(&Real_NtQueryInformationProcess, Mine_NtQueryInformationProcess); - } - } -#endif -#endif - - bHookingSuccessful &= !!Mhook_SetHookEx(&Real_CreateFileW, Mine_CreateFileW); - bHookingSuccessful &= !!Mhook_SetHookEx(&Real_DeviceIoControl, Mine_DeviceIoControl); - - bHookingSuccessful &= MH_EnableHook(MH_ALL_HOOKS) == MH_OK; - - if (!bHookingSuccessful) { - AfxMessageBox(IDS_HOOKS_FAILED); - } - -#if USE_DLL_BLOCKLIST - if (m_hNTDLL) { - Real_NtMapViewOfSection = (pfn_NtMapViewOfSection)GetProcAddress(m_hNTDLL, "NtMapViewOfSection"); - Real_NtUnmapViewOfSection = (pfn_NtUnmapViewOfSection)GetProcAddress(m_hNTDLL, "NtUnmapViewOfSection"); - Real_NtQuerySection = (pfn_NtQuerySection)GetProcAddress(m_hNTDLL, "NtQuerySection"); - Real_GetMappedFileNameW = (pfn_GetMappedFileNameW)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "K32GetMappedFileNameW"); - if (Real_NtMapViewOfSection && Real_NtUnmapViewOfSection && Real_NtQuerySection && Real_GetMappedFileNameW) { - VERIFY(Mhook_SetHookEx(&Real_NtMapViewOfSection, Mine_NtMapViewOfSection)); - } - } -#endif - - // If those hooks fail it's annoying but try to run anyway without reporting any error in release mode - VERIFY(Mhook_SetHookEx(&Real_ChangeDisplaySettingsExA, Mine_ChangeDisplaySettingsExA)); - VERIFY(Mhook_SetHookEx(&Real_ChangeDisplaySettingsExW, Mine_ChangeDisplaySettingsExW)); - VERIFY(Mhook_SetHookEx(&Real_CreateFileA, Mine_CreateFileA)); // The internal splitter uses the right share mode anyway so this is no big deal - VERIFY(Mhook_SetHookEx(&Real_LockWindowUpdate, Mine_LockWindowUpdate)); - VERIFY(Mhook_SetHookEx(&Real_mixerSetControlDetails, Mine_mixerSetControlDetails)); - MH_EnableHook(MH_ALL_HOOKS); - - CFilterMapper2::Init(); - - if (FAILED(OleInitialize(nullptr))) { - AfxMessageBox(_T("OleInitialize failed!")); - return FALSE; - } - - m_s = std::make_unique(); - - // Be careful if you move that code: IDR_MAINFRAME icon can only be loaded from the executable, - // LoadIcon can't be used after the language DLL has been set as the main resource. - HICON icon = LoadIcon(IDR_MAINFRAME); - - WNDCLASS wndcls; - ZeroMemory(&wndcls, sizeof(WNDCLASS)); - wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; - wndcls.lpfnWndProc = ::DefWindowProc; - wndcls.hInstance = AfxGetInstanceHandle(); - wndcls.hIcon = icon; - wndcls.hCursor = LoadCursor(IDC_ARROW); - wndcls.hbrBackground = 0;//(HBRUSH)(COLOR_WINDOW + 1); // no bkg brush, the view and the bars should always fill the whole client area - wndcls.lpszMenuName = nullptr; - wndcls.lpszClassName = MPC_WND_CLASS_NAME; - - if (!AfxRegisterClass(&wndcls)) { - AfxMessageBox(_T("MainFrm class registration failed!")); - return FALSE; - } - - if (!AfxSocketInit(nullptr)) { - AfxMessageBox(_T("AfxSocketInit failed!")); - return FALSE; - } - - PreProcessCommandLine(); - - if (IsIniValid()) { - StoreSettingsToIni(); - } else { - StoreSettingsToRegistry(); - } - - m_s->ParseCommandLine(m_cmdln); - - VERIFY(SetCurrentDirectory(PathUtils::GetProgramPath())); - - if (m_s->nCLSwitches & (CLSW_HELP | CLSW_UNRECOGNIZEDSWITCH)) { // show commandline help window - m_s->LoadSettings(); - ShowCmdlnSwitches(); - return FALSE; - } - - if (m_s->nCLSwitches & CLSW_RESET) { // reset settings - // We want the other instances to be closed before resetting the settings. - HWND hWnd = FindWindow(MPC_WND_CLASS_NAME, nullptr); - - while (hWnd) { - Sleep(500); - - hWnd = FindWindow(MPC_WND_CLASS_NAME, nullptr); - - if (hWnd && MessageBox(nullptr, ResStr(IDS_RESET_SETTINGS_MUTEX), ResStr(IDS_RESET_SETTINGS), MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDCANCEL) { - return FALSE; - } - } - - // If the profile was already cached, it should be cleared here - ASSERT(!m_bProfileInitialized); - - // Remove the settings - if (IsIniValid()) { - FILE* fp; - do { // Open mpc-hc.ini, retry if it is already being used by another process - fp = _tfsopen(m_pszProfileName, _T("w"), _SH_SECURE); - if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { - break; - } - Sleep(100); - } while (true); - if (fp) { - // Close without writing anything, it should produce empty file - VERIFY(fclose(fp) == 0); - } else { - ASSERT(FALSE); - } - } else { - CRegKey key; - // Clear settings - key.Attach(GetAppRegistryKey()); - VERIFY(key.RecurseDeleteKey(_T("")) == ERROR_SUCCESS); - VERIFY(key.Close() == ERROR_SUCCESS); - // Set ExePath value to prevent settings migration - key.Attach(GetAppRegistryKey()); - VERIFY(key.SetStringValue(_T("ExePath"), PathUtils::GetProgramPath(true)) == ERROR_SUCCESS); - VERIFY(key.Close() == ERROR_SUCCESS); - } - - // Remove the current playlist if it exists - CString strSavePath; - if (GetAppSavePath(strSavePath)) { - CPath playlistPath; - playlistPath.Combine(strSavePath, _T("default.mpcpl")); - - if (playlistPath.FileExists()) { - try { - CFile::Remove(playlistPath); - } catch (...) {} - } - } - } - - if ((m_s->nCLSwitches & CLSW_CLOSE) && m_s->slFiles.IsEmpty()) { // "/close" switch and empty file list - return FALSE; - } - - if (m_s->nCLSwitches & (CLSW_REGEXTVID | CLSW_REGEXTAUD | CLSW_REGEXTPL)) { // register file types - m_s->fileAssoc.RegisterApp(); - - CMediaFormats& mf = m_s->m_Formats; - mf.UpdateData(false); - - bool bAudioOnly; - - auto iconLib = m_s->fileAssoc.GetIconLib(); - if (iconLib) { - iconLib->SaveVersion(); - } - - for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { - bool bPlaylist = !mf[i].GetLabel().CompareNoCase(_T("pls")); - - if (bPlaylist && !(m_s->nCLSwitches & CLSW_REGEXTPL)) { - continue; - } - - bAudioOnly = mf[i].IsAudioOnly(); - - if (((m_s->nCLSwitches & CLSW_REGEXTVID) && !bAudioOnly) || - ((m_s->nCLSwitches & CLSW_REGEXTAUD) && bAudioOnly) || - ((m_s->nCLSwitches & CLSW_REGEXTPL) && bPlaylist)) { - m_s->fileAssoc.Register(mf[i], true, false, true); - } - } - - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); - - return FALSE; - } - - if (m_s->nCLSwitches & CLSW_UNREGEXT) { // unregistered file types - CMediaFormats& mf = m_s->m_Formats; - mf.UpdateData(false); - - for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { - m_s->fileAssoc.Register(mf[i], false, false, false); - } - - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); - - return FALSE; - } - - if (m_s->nCLSwitches & CLSW_ICONSASSOC) { - CMediaFormats& mf = m_s->m_Formats; - mf.UpdateData(false); - - CAtlList registeredExts; - m_s->fileAssoc.GetAssociatedExtensionsFromRegistry(registeredExts); - - m_s->fileAssoc.ReAssocIcons(registeredExts); - - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); - - return FALSE; - } - - // Enable to open options with administrator privilege (for Vista UAC) - if (m_s->nCLSwitches & CLSW_ADMINOPTION) { - m_s->LoadSettings(); // read all settings. long time but not critical at this point - - switch (m_s->iAdminOption) { - case CPPageFormats::IDD: { - CPPageSheet options(ResStr(IDS_OPTIONS_CAPTION), nullptr, nullptr, m_s->iAdminOption); - options.LockPage(); - options.DoModal(); - } - break; - - default: - ASSERT(FALSE); - } - return FALSE; - } - - if (m_s->nCLSwitches & (CLSW_CONFIGLAVSPLITTER | CLSW_CONFIGLAVAUDIO | CLSW_CONFIGLAVVIDEO)) { - m_s->LoadSettings(); - if (m_s->nCLSwitches & CLSW_CONFIGLAVSPLITTER) { - CFGFilterLAVSplitter::ShowPropertyPages(NULL); - } - if (m_s->nCLSwitches & CLSW_CONFIGLAVAUDIO) { - CFGFilterLAVAudio::ShowPropertyPages(NULL); - } - if (m_s->nCLSwitches & CLSW_CONFIGLAVVIDEO) { - CFGFilterLAVVideo::ShowPropertyPages(NULL); - } - return FALSE; - } - - m_mutexOneInstance.Create(nullptr, TRUE, MPC_WND_CLASS_NAME); - - if (GetLastError() == ERROR_ALREADY_EXISTS) { - if ((m_s->nCLSwitches & CLSW_ADD) || !(m_s->GetAllowMultiInst() || m_s->nCLSwitches & CLSW_NEW || m_cmdln.IsEmpty())) { - DWORD res = WaitForSingleObject(m_mutexOneInstance.m_h, 5000); - if (res == WAIT_OBJECT_0 || res == WAIT_ABANDONED) { - HWND hWnd = ::FindWindow(MPC_WND_CLASS_NAME, nullptr); - if (hWnd) { - DWORD dwProcessId = 0; - if (GetWindowThreadProcessId(hWnd, &dwProcessId) && dwProcessId) { - VERIFY(AllowSetForegroundWindow(dwProcessId)); - } else { - ASSERT(FALSE); - } - if (!(m_s->nCLSwitches & CLSW_MINIMIZED) && IsIconic(hWnd) && - (!(m_s->nCLSwitches & CLSW_ADD) || m_s->nCLSwitches & CLSW_PLAY) //do not restore when adding to playlist of minimized player, unless also playing - ) { - ShowWindow(hWnd, SW_RESTORE); - } - if (SendCommandLine(hWnd)) { - m_mutexOneInstance.Close(); - return FALSE; - } - } - } - if ((m_s->nCLSwitches & CLSW_ADD)) { - ASSERT(FALSE); - return FALSE; // don't open new instance if SendCommandLine() failed - } - } - } - - if (!IsIniValid()) { - CRegKey key; - if (ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, _T("Software\\MPC-HC\\MPC-HC"))) { - if (RegQueryValueEx(key, _T("ExePath"), 0, nullptr, nullptr, nullptr) != ERROR_SUCCESS) { // First launch - // Move registry settings from the old to the new location - CRegKey oldKey; - if (ERROR_SUCCESS == oldKey.Open(HKEY_CURRENT_USER, _T("Software\\Gabest\\Media Player Classic"), KEY_READ)) { - SHCopyKey(oldKey, _T(""), key, 0); - } - } - - key.SetStringValue(_T("ExePath"), PathUtils::GetProgramPath(true)); - } - } - - m_s->UpdateSettings(); // update settings - m_s->LoadSettings(); // read settings - - #if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER - if (!m_s->bEnableCrashReporter) { - DisableCrashReporter(); - } - #endif - - m_AudioRendererDisplayName_CL = _T(""); - - if (!__super::InitInstance()) { - AfxMessageBox(_T("InitInstance failed!")); - return FALSE; - } - - AfxEnableControlContainer(); - - CMainFrame* pFrame; - try { - pFrame = DEBUG_NEW CMainFrame; - if (!pFrame || !pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, nullptr, nullptr)) { - MessageBox(nullptr, ResStr(IDS_FRAME_INIT_FAILED), m_pszAppName, MB_ICONERROR | MB_OK); - return FALSE; - } - } catch (...) { - return FALSE; - } - - m_pMainWnd = pFrame; - pFrame->m_controls.LoadState(); - CPoint borderAdjustDirection; - pFrame->SetDefaultWindowRect((m_s->nCLSwitches & CLSW_MONITOR) ? m_s->iMonitor : 0); - if (!m_s->slFiles.IsEmpty()) { - pFrame->m_controls.DelayShowNotLoaded(true); - } - pFrame->SetDefaultFullscreenState(); - pFrame->UpdateControlState(CMainFrame::UPDATE_CONTROLS_VISIBILITY); - pFrame->SetIcon(icon, TRUE); - - bool bRestoreLastWindowType = (m_s->fRememberWindowSize || m_s->fRememberWindowPos) && !m_s->fLastFullScreen && !m_s->fLaunchfullscreen; - bool bMinimized = (m_s->nCLSwitches & CLSW_MINIMIZED) || (bRestoreLastWindowType && m_s->nLastWindowType == SIZE_MINIMIZED); - bool bMaximized = bRestoreLastWindowType && m_s->nLastWindowType == SIZE_MAXIMIZED; - - if (bMinimized) { - m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWMINNOACTIVE : SW_SHOWMINIMIZED; - } else if (bMaximized) { - // Show maximized without focus is not supported nor make sense. - m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWNOACTIVATE : SW_SHOWMAXIMIZED; - } else { - m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL; - } - - pFrame->ActivateFrame(m_nCmdShow); - - if (AfxGetAppSettings().HasFixedWindowSize() && IsWindows8OrGreater()) {//make adjustments for drop shadow frame - CRect rect, frame; - pFrame->GetWindowRect(&rect); - CRect diff = pFrame->GetInvisibleBorderSize(); - if (!diff.IsRectNull()) { - rect.InflateRect(diff); - pFrame->SetWindowPos(nullptr, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER | SWP_NOACTIVATE); - } - } - - /* adipose 2019-11-12: - LoadPlayList this used to be performed inside OnCreate, - but due to all toolbars being hidden, EnsureVisible does not correctly - scroll to the current file in the playlist. We call after activating - the frame to fix this issue. - */ - pFrame->m_wndPlaylistBar.LoadPlaylist(pFrame->GetRecentFile()); - - pFrame->UpdateWindow(); - - - if (bMinimized && bMaximized) { - WINDOWPLACEMENT wp; - GetWindowPlacement(*pFrame, &wp); - wp.flags = WPF_RESTORETOMAXIMIZED; - SetWindowPlacement(*pFrame, &wp); - } - - pFrame->m_hAccelTable = m_s->hAccel; - m_s->WinLircClient.SetHWND(m_pMainWnd->m_hWnd); - if (m_s->fWinLirc) { - m_s->WinLircClient.Connect(m_s->strWinLircAddr); - } - m_s->UIceClient.SetHWND(m_pMainWnd->m_hWnd); - if (m_s->fUIce) { - m_s->UIceClient.Connect(m_s->strUIceAddr); - } - - if (UpdateChecker::IsAutoUpdateEnabled()) { - UpdateChecker::CheckForUpdate(true); - } - - if (!m_pMainWnd) return false; - - SendCommandLine(m_pMainWnd->m_hWnd); - RegisterHotkeys(); - - // set HIGH I/O Priority for better playback performance - if (m_hNTDLL) { - typedef NTSTATUS(WINAPI * FUNC_NTSETINFORMATIONPROCESS)(HANDLE, ULONG, PVOID, ULONG); - FUNC_NTSETINFORMATIONPROCESS NtSetInformationProcess = (FUNC_NTSETINFORMATIONPROCESS)GetProcAddress(m_hNTDLL, "NtSetInformationProcess"); - - if (NtSetInformationProcess && SetPrivilege(SE_INC_BASE_PRIORITY_NAME)) { - ULONG IoPriority = 3; - ULONG ProcessIoPriority = 0x21; - NTSTATUS NtStatus = NtSetInformationProcess(GetCurrentProcess(), ProcessIoPriority, &IoPriority, sizeof(ULONG)); - TRACE(_T("Set I/O Priority - %d\n"), NtStatus); - UNREFERENCED_PARAMETER(NtStatus); - } - } - - m_mutexOneInstance.Release(); - - CWebServer::Init(); - - if (m_s->fAssociatedWithIcons) { - m_s->fileAssoc.CheckIconsAssoc(); - } - - return TRUE; -} - -UINT CMPlayerCApp::GetRemoteControlCodeMicrosoft(UINT nInputcode, HRAWINPUT hRawInput) -{ - UINT dwSize = 0; - UINT nMceCmd = 0; - - // Support for MCE remote control - UINT ret = GetRawInputData(hRawInput, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); - if (ret == 0 && dwSize > 0) { - BYTE* pRawBuffer = DEBUG_NEW BYTE[dwSize]; - if (GetRawInputData(hRawInput, RID_INPUT, pRawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) != -1) { - RAWINPUT* raw = (RAWINPUT*)pRawBuffer; - if (raw->header.dwType == RIM_TYPEHID && raw->data.hid.dwSizeHid >= 3) { - nMceCmd = 0x10000 + (raw->data.hid.bRawData[1] | raw->data.hid.bRawData[2] << 8); - } - } - delete [] pRawBuffer; - } - - return nMceCmd; -} - -UINT CMPlayerCApp::GetRemoteControlCodeSRM7500(UINT nInputcode, HRAWINPUT hRawInput) -{ - UINT dwSize = 0; - UINT nMceCmd = 0; - - UINT ret = GetRawInputData(hRawInput, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); - if (ret == 0 && dwSize > 21) { - BYTE* pRawBuffer = DEBUG_NEW BYTE[dwSize]; - if (GetRawInputData(hRawInput, RID_INPUT, pRawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) != -1) { - RAWINPUT* raw = (RAWINPUT*)pRawBuffer; - - // data.hid.bRawData[21] set to one when key is pressed - if (raw->header.dwType == RIM_TYPEHID && raw->data.hid.dwSizeHid >= 22 && raw->data.hid.bRawData[21] == 1) { - // data.hid.bRawData[21] has keycode - switch (raw->data.hid.bRawData[20]) { - case 0x0033: - nMceCmd = MCE_DETAILS; - break; - case 0x0022: - nMceCmd = MCE_GUIDE; - break; - case 0x0036: - nMceCmd = MCE_MYTV; - break; - case 0x0026: - nMceCmd = MCE_RECORDEDTV; - break; - case 0x0005: - nMceCmd = MCE_RED; - break; - case 0x0002: - nMceCmd = MCE_GREEN; - break; - case 0x0045: - nMceCmd = MCE_YELLOW; - break; - case 0x0046: - nMceCmd = MCE_BLUE; - break; - case 0x000A: - nMceCmd = MCE_MEDIA_PREVIOUSTRACK; - break; - case 0x004A: - nMceCmd = MCE_MEDIA_NEXTTRACK; - break; - } - } - } - delete [] pRawBuffer; - } - - return nMceCmd; -} - -void CMPlayerCApp::RegisterHotkeys() -{ - CAutoVectorPtr inputDeviceList; - UINT nInputDeviceCount = 0, nErrCode; - RID_DEVICE_INFO deviceInfo; - RAWINPUTDEVICE MCEInputDevice[] = { - // usUsagePage usUsage dwFlags hwndTarget - { 0xFFBC, 0x88, 0, nullptr}, - { 0x000C, 0x01, 0, nullptr}, - { 0x000C, 0x80, 0, nullptr} - }; - - // Register MCE Remote Control raw input - for (unsigned int i = 0; i < _countof(MCEInputDevice); i++) { - MCEInputDevice[i].hwndTarget = m_pMainWnd->m_hWnd; - } - - // Get the size of the device list - nErrCode = GetRawInputDeviceList(nullptr, &nInputDeviceCount, sizeof(RAWINPUTDEVICELIST)); - inputDeviceList.Attach(DEBUG_NEW RAWINPUTDEVICELIST[nInputDeviceCount]); - if (nErrCode == UINT(-1) || !nInputDeviceCount || !inputDeviceList) { - ASSERT(nErrCode != UINT(-1)); - return; - } - - nErrCode = GetRawInputDeviceList(inputDeviceList, &nInputDeviceCount, sizeof(RAWINPUTDEVICELIST)); - if (nErrCode == UINT(-1)) { - ASSERT(FALSE); - return; - } - - for (UINT i = 0; i < nInputDeviceCount; i++) { - UINT nTemp = deviceInfo.cbSize = sizeof(deviceInfo); - - if (GetRawInputDeviceInfo(inputDeviceList[i].hDevice, RIDI_DEVICEINFO, &deviceInfo, &nTemp) > 0) { - if (deviceInfo.hid.dwVendorId == 0x00000471 && // Philips HID vendor id - deviceInfo.hid.dwProductId == 0x00000617) { // IEEE802.15.4 RF Dongle (SRM 7500) - MCEInputDevice[0].usUsagePage = deviceInfo.hid.usUsagePage; - MCEInputDevice[0].usUsage = deviceInfo.hid.usUsage; - GetRemoteControlCode = GetRemoteControlCodeSRM7500; - } - } - } - - RegisterRawInputDevices(MCEInputDevice, _countof(MCEInputDevice), sizeof(RAWINPUTDEVICE)); - - if (m_s->fGlobalMedia) { - POSITION pos = m_s->wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = m_s->wmcmds.GetNext(pos); - if (wc.appcmd != 0) { - UINT vkappcmd = GetVKFromAppCommand(wc.appcmd); - if (vkappcmd > 0) { - RegisterHotKey(m_pMainWnd->m_hWnd, wc.appcmd, 0, vkappcmd); - } - } - } - } -} - -void CMPlayerCApp::UnregisterHotkeys() -{ - if (m_s->fGlobalMedia) { - POSITION pos = m_s->wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = m_s->wmcmds.GetNext(pos); - if (wc.appcmd != 0) { - UnregisterHotKey(m_pMainWnd->m_hWnd, wc.appcmd); - } - } - } -} - -UINT CMPlayerCApp::GetVKFromAppCommand(UINT nAppCommand) -{ - // Note: Only a subset of AppCommands have a VirtualKey - switch (nAppCommand) { - case APPCOMMAND_MEDIA_PLAY_PAUSE: - return VK_MEDIA_PLAY_PAUSE; - case APPCOMMAND_MEDIA_STOP: - return VK_MEDIA_STOP; - case APPCOMMAND_MEDIA_NEXTTRACK: - return VK_MEDIA_NEXT_TRACK; - case APPCOMMAND_MEDIA_PREVIOUSTRACK: - return VK_MEDIA_PREV_TRACK; - case APPCOMMAND_VOLUME_DOWN: - return VK_VOLUME_DOWN; - case APPCOMMAND_VOLUME_UP: - return VK_VOLUME_UP; - case APPCOMMAND_VOLUME_MUTE: - return VK_VOLUME_MUTE; - case APPCOMMAND_LAUNCH_MEDIA_SELECT: - return VK_LAUNCH_MEDIA_SELECT; - case APPCOMMAND_BROWSER_BACKWARD: - return VK_BROWSER_BACK; - case APPCOMMAND_BROWSER_FORWARD: - return VK_BROWSER_FORWARD; - case APPCOMMAND_BROWSER_REFRESH: - return VK_BROWSER_REFRESH; - case APPCOMMAND_BROWSER_STOP: - return VK_BROWSER_STOP; - case APPCOMMAND_BROWSER_SEARCH: - return VK_BROWSER_SEARCH; - case APPCOMMAND_BROWSER_FAVORITES: - return VK_BROWSER_FAVORITES; - case APPCOMMAND_BROWSER_HOME: - return VK_BROWSER_HOME; - case APPCOMMAND_LAUNCH_APP1: - return VK_LAUNCH_APP1; - case APPCOMMAND_LAUNCH_APP2: - return VK_LAUNCH_APP2; - } - - return 0; -} - -int CMPlayerCApp::ExitInstance() -{ - // We might be exiting before m_s is initialized. - if (m_s) { - m_s->SaveSettings(); - m_s = nullptr; - } - - CMPCPngImage::CleanUp(); - - MH_Uninitialize(); - - OleUninitialize(); - - return CWinAppEx::ExitInstance(); -} - -BOOL CMPlayerCApp::SaveAllModified() -{ - // CWinApp::SaveAllModified - // Called by the framework to save all documents - // when the application's main frame window is to be closed, - // or through a WM_QUERYENDSESSION message. - if (m_s && !m_fClosingState) { - if (auto pMainFrame = AfxFindMainFrame()) { - if (pMainFrame->GetLoadState() != MLS::CLOSED) { - pMainFrame->CloseMedia(); - } - } - } - - return TRUE; -} - -// CMPlayerCApp message handlers - -BEGIN_MESSAGE_MAP(CMPlayerCApp, CWinAppEx) - ON_COMMAND(ID_HELP_ABOUT, OnAppAbout) - ON_COMMAND(ID_FILE_EXIT, OnFileExit) - ON_COMMAND(ID_HELP_SHOWCOMMANDLINESWITCHES, OnHelpShowcommandlineswitches) -END_MESSAGE_MAP() - -void CMPlayerCApp::OnAppAbout() -{ - CAboutDlg aboutDlg; - aboutDlg.DoModal(); -} - -void CMPlayerCApp::SetClosingState() -{ - m_fClosingState = true; -#if USE_DRDUMP_CRASH_REPORTER & (MPC_VERSION_REV < 20) - DisableCrashReporter(); -#endif -} - -void CMPlayerCApp::OnFileExit() -{ - OnAppExit(); -} - -void CMPlayerCApp::OnHelpShowcommandlineswitches() -{ - ShowCmdlnSwitches(); -} - -// CRemoteCtrlClient - -CRemoteCtrlClient::CRemoteCtrlClient() - : m_pWnd(nullptr) - , m_nStatus(DISCONNECTED) -{ -} - -void CRemoteCtrlClient::SetHWND(HWND hWnd) -{ - CAutoLock cAutoLock(&m_csLock); - - m_pWnd = CWnd::FromHandle(hWnd); -} - -void CRemoteCtrlClient::Connect(CString addr) -{ - CAutoLock cAutoLock(&m_csLock); - - if (m_nStatus == CONNECTING && m_addr == addr) { - TRACE(_T("CRemoteCtrlClient (Connect): already connecting to %s\n"), addr.GetString()); - return; - } - - if (m_nStatus == CONNECTED && m_addr == addr) { - TRACE(_T("CRemoteCtrlClient (Connect): already connected to %s\n"), addr.GetString()); - return; - } - - m_nStatus = CONNECTING; - - TRACE(_T("CRemoteCtrlClient (Connect): connecting to %s\n"), addr.GetString()); - - Close(); - - Create(); - - CString ip = addr.Left(addr.Find(':') + 1).TrimRight(':'); - int port = _tcstol(addr.Mid(addr.Find(':') + 1), nullptr, 10); - - __super::Connect(ip, port); - - m_addr = addr; -} - -void CRemoteCtrlClient::DisConnect() -{ - CAutoLock cAutoLock(&m_csLock); - - ShutDown(2); - Close(); -} - -void CRemoteCtrlClient::OnConnect(int nErrorCode) -{ - CAutoLock cAutoLock(&m_csLock); - - m_nStatus = (nErrorCode == 0 ? CONNECTED : DISCONNECTED); - - TRACE(_T("CRemoteCtrlClient (OnConnect): %d\n"), nErrorCode); -} - -void CRemoteCtrlClient::OnClose(int nErrorCode) -{ - CAutoLock cAutoLock(&m_csLock); - - if (m_hSocket != INVALID_SOCKET && m_nStatus == CONNECTED) { - TRACE(_T("CRemoteCtrlClient (OnClose): connection lost\n")); - } - - m_nStatus = DISCONNECTED; - - TRACE(_T("CRemoteCtrlClient (OnClose): %d\n"), nErrorCode); -} - -void CRemoteCtrlClient::OnReceive(int nErrorCode) -{ - if (nErrorCode != 0 || !m_pWnd) { - return; - } - - CStringA str; - int ret = Receive(str.GetBuffer(256), 255, 0); - if (ret <= 0) { - return; - } - str.ReleaseBuffer(ret); - - TRACE(_T("CRemoteCtrlClient (OnReceive): %S\n"), str.GetString()); - - OnCommand(str); - - __super::OnReceive(nErrorCode); -} - -void CRemoteCtrlClient::ExecuteCommand(CStringA cmd, int repcnt) -{ - cmd.Trim(); - if (cmd.IsEmpty()) { - return; - } - cmd.Replace(' ', '_'); - - const CAppSettings& s = AfxGetAppSettings(); - - POSITION pos = s.wmcmds.GetHeadPosition(); - while (pos) { - const wmcmd& wc = s.wmcmds.GetNext(pos); - if ((repcnt == 0 && wc.rmrepcnt == 0 || wc.rmrepcnt > 0 && (repcnt % wc.rmrepcnt) == 0) - && (wc.rmcmd.CompareNoCase(cmd) == 0 || wc.cmd == (WORD)strtol(cmd, nullptr, 10))) { - CAutoLock cAutoLock(&m_csLock); - TRACE(_T("CRemoteCtrlClient (calling command): %s\n"), wc.GetName().GetString()); - m_pWnd->SendMessage(WM_COMMAND, wc.cmd); - break; - } - } -} - -// CWinLircClient - -CWinLircClient::CWinLircClient() -{ -} - -void CWinLircClient::OnCommand(CStringA str) -{ - TRACE(_T("CWinLircClient (OnCommand): %S\n"), str.GetString()); - - int i = 0, j = 0, repcnt = 0; - for (CStringA token = str.Tokenize(" ", i); - !token.IsEmpty(); - token = str.Tokenize(" ", i), j++) { - if (j == 1) { - repcnt = strtol(token, nullptr, 16); - } else if (j == 2) { - ExecuteCommand(token, repcnt); - } - } -} - -// CUIceClient - -CUIceClient::CUIceClient() -{ -} - -void CUIceClient::OnCommand(CStringA str) -{ - TRACE(_T("CUIceClient (OnCommand): %S\n"), str.GetString()); - - CStringA cmd; - int i = 0, j = 0; - for (CStringA token = str.Tokenize("|", i); - !token.IsEmpty(); - token = str.Tokenize("|", i), j++) { - if (j == 0) { - cmd = token; - } else if (j == 1) { - ExecuteCommand(cmd, strtol(token, nullptr, 16)); - } - } -} - -// CMPlayerCApp continuation - -COLORPROPERTY_RANGE* CMPlayerCApp::GetColorControl(ControlType nFlag) -{ - switch (nFlag) { - case ProcAmp_Brightness: - return &m_ColorControl[0]; - case ProcAmp_Contrast: - return &m_ColorControl[1]; - case ProcAmp_Hue: - return &m_ColorControl[2]; - case ProcAmp_Saturation: - return &m_ColorControl[3]; - } - return nullptr; -} - -void CMPlayerCApp::ResetColorControlRange() -{ - m_ColorControl[0].dwProperty = ProcAmp_Brightness; - m_ColorControl[0].MinValue = -100; - m_ColorControl[0].MaxValue = 100; - m_ColorControl[0].DefaultValue = 0; - m_ColorControl[0].StepSize = 1; - m_ColorControl[1].dwProperty = ProcAmp_Contrast; - m_ColorControl[1].MinValue = -100; - m_ColorControl[1].MaxValue = 100; - m_ColorControl[1].DefaultValue = 0; - m_ColorControl[1].StepSize = 1; - m_ColorControl[2].dwProperty = ProcAmp_Hue; - m_ColorControl[2].MinValue = -180; - m_ColorControl[2].MaxValue = 180; - m_ColorControl[2].DefaultValue = 0; - m_ColorControl[2].StepSize = 1; - m_ColorControl[3].dwProperty = ProcAmp_Saturation; - m_ColorControl[3].MinValue = -100; - m_ColorControl[3].MaxValue = 100; - m_ColorControl[3].DefaultValue = 0; - m_ColorControl[3].StepSize = 1; -} - -void CMPlayerCApp::UpdateColorControlRange(bool isEVR) -{ - if (isEVR) { - // Brightness - m_ColorControl[0].MinValue = FixedToInt(m_EVRColorControl[0].MinValue); - m_ColorControl[0].MaxValue = FixedToInt(m_EVRColorControl[0].MaxValue); - m_ColorControl[0].DefaultValue = FixedToInt(m_EVRColorControl[0].DefaultValue); - m_ColorControl[0].StepSize = std::max(1, FixedToInt(m_EVRColorControl[0].StepSize)); - // Contrast - m_ColorControl[1].MinValue = FixedToInt(m_EVRColorControl[1].MinValue, 100) - 100; - m_ColorControl[1].MaxValue = FixedToInt(m_EVRColorControl[1].MaxValue, 100) - 100; - m_ColorControl[1].DefaultValue = FixedToInt(m_EVRColorControl[1].DefaultValue, 100) - 100; - m_ColorControl[1].StepSize = std::max(1, FixedToInt(m_EVRColorControl[1].StepSize, 100)); - // Hue - m_ColorControl[2].MinValue = FixedToInt(m_EVRColorControl[2].MinValue); - m_ColorControl[2].MaxValue = FixedToInt(m_EVRColorControl[2].MaxValue); - m_ColorControl[2].DefaultValue = FixedToInt(m_EVRColorControl[2].DefaultValue); - m_ColorControl[2].StepSize = std::max(1, FixedToInt(m_EVRColorControl[2].StepSize)); - // Saturation - m_ColorControl[3].MinValue = FixedToInt(m_EVRColorControl[3].MinValue, 100) - 100; - m_ColorControl[3].MaxValue = FixedToInt(m_EVRColorControl[3].MaxValue, 100) - 100; - m_ColorControl[3].DefaultValue = FixedToInt(m_EVRColorControl[3].DefaultValue, 100) - 100; - m_ColorControl[3].StepSize = std::max(1, FixedToInt(m_EVRColorControl[3].StepSize, 100)); - } else { - // Brightness - m_ColorControl[0].MinValue = (int)floor(m_VMR9ColorControl[0].MinValue + 0.5); - m_ColorControl[0].MaxValue = (int)floor(m_VMR9ColorControl[0].MaxValue + 0.5); - m_ColorControl[0].DefaultValue = (int)floor(m_VMR9ColorControl[0].DefaultValue + 0.5); - m_ColorControl[0].StepSize = std::max(1, (int)(m_VMR9ColorControl[0].StepSize + 0.5)); - // Contrast - if (*(int*)&m_VMR9ColorControl[1].MinValue == 1036830720) { - m_VMR9ColorControl[1].MinValue = 0.11f; //fix NVIDIA bug - } - m_ColorControl[1].MinValue = (int)floor(m_VMR9ColorControl[1].MinValue * 100 + 0.5) - 100; - m_ColorControl[1].MaxValue = (int)floor(m_VMR9ColorControl[1].MaxValue * 100 + 0.5) - 100; - m_ColorControl[1].DefaultValue = (int)floor(m_VMR9ColorControl[1].DefaultValue * 100 + 0.5) - 100; - m_ColorControl[1].StepSize = std::max(1, (int)(m_VMR9ColorControl[1].StepSize * 100 + 0.5)); - // Hue - m_ColorControl[2].MinValue = (int)floor(m_VMR9ColorControl[2].MinValue + 0.5); - m_ColorControl[2].MaxValue = (int)floor(m_VMR9ColorControl[2].MaxValue + 0.5); - m_ColorControl[2].DefaultValue = (int)floor(m_VMR9ColorControl[2].DefaultValue + 0.5); - m_ColorControl[2].StepSize = std::max(1, (int)(m_VMR9ColorControl[2].StepSize + 0.5)); - // Saturation - m_ColorControl[3].MinValue = (int)floor(m_VMR9ColorControl[3].MinValue * 100 + 0.5) - 100; - m_ColorControl[3].MaxValue = (int)floor(m_VMR9ColorControl[3].MaxValue * 100 + 0.5) - 100; - m_ColorControl[3].DefaultValue = (int)floor(m_VMR9ColorControl[3].DefaultValue * 100 + 0.5) - 100; - m_ColorControl[3].StepSize = std::max(1, (int)(m_VMR9ColorControl[3].StepSize * 100 + 0.5)); - } - - // Brightness - if (m_ColorControl[0].MinValue < -100) { - m_ColorControl[0].MinValue = -100; - } - if (m_ColorControl[0].MaxValue > 100) { - m_ColorControl[0].MaxValue = 100; - } - // Contrast - if (m_ColorControl[1].MinValue == m_ColorControl[1].MaxValue) { // when ProcAmp is unsupported - m_ColorControl[1].MinValue = m_ColorControl[1].MaxValue = m_ColorControl[1].DefaultValue = 0; - } - if (m_ColorControl[1].MinValue < -100) { - m_ColorControl[1].MinValue = -100; - } - if (m_ColorControl[1].MaxValue > 100) { - m_ColorControl[1].MaxValue = 100; - } - // Hue - if (m_ColorControl[2].MinValue < -180) { - m_ColorControl[2].MinValue = -180; - } - if (m_ColorControl[2].MaxValue > 180) { - m_ColorControl[2].MaxValue = 180; - } - // Saturation - if (m_ColorControl[3].MinValue == m_ColorControl[3].MaxValue) { // when ProcAmp is unsupported - m_ColorControl[3].MinValue = m_ColorControl[3].MaxValue = m_ColorControl[3].DefaultValue = 0; - } - if (m_ColorControl[3].MinValue < -100) { - m_ColorControl[3].MinValue = -100; - } - if (m_ColorControl[3].MaxValue > 100) { - m_ColorControl[3].MaxValue = 100; - } -} - -VMR9ProcAmpControlRange* CMPlayerCApp::GetVMR9ColorControl(ControlType nFlag) -{ - switch (nFlag) { - case ProcAmp_Brightness: - return &m_VMR9ColorControl[0]; - case ProcAmp_Contrast: - return &m_VMR9ColorControl[1]; - case ProcAmp_Hue: - return &m_VMR9ColorControl[2]; - case ProcAmp_Saturation: - return &m_VMR9ColorControl[3]; - } - return nullptr; -} - -DXVA2_ValueRange* CMPlayerCApp::GetEVRColorControl(ControlType nFlag) -{ - switch (nFlag) { - case ProcAmp_Brightness: - return &m_EVRColorControl[0]; - case ProcAmp_Contrast: - return &m_EVRColorControl[1]; - case ProcAmp_Hue: - return &m_EVRColorControl[2]; - case ProcAmp_Saturation: - return &m_EVRColorControl[3]; - } - return nullptr; -} - -void CMPlayerCApp::RunAsAdministrator(LPCTSTR strCommand, LPCTSTR strArgs, bool bWaitProcess) -{ - SHELLEXECUTEINFO execinfo; - ZeroMemory(&execinfo, sizeof(execinfo)); - execinfo.lpFile = strCommand; - execinfo.cbSize = sizeof(execinfo); - execinfo.lpVerb = _T("runas"); - execinfo.fMask = SEE_MASK_NOCLOSEPROCESS; - execinfo.nShow = SW_SHOWDEFAULT; - execinfo.lpParameters = strArgs; - - ShellExecuteEx(&execinfo); - - if (bWaitProcess) { - WaitForSingleObject(execinfo.hProcess, INFINITE); - } -} - +/* + * (C) 2003-2006 Gabest + * (C) 2006-2018 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 . + * + */ + +#include "stdafx.h" +#include "mplayerc.h" +#include "AboutDlg.h" +#include "CmdLineHelpDlg.h" +#include "CrashReporter.h" +#include "DSUtil.h" +#include "FakeFilterMapper2.h" +#include "FileAssoc.h" +#include "FileVersionInfo.h" +#include "Ifo.h" +#include "MainFrm.h" +#include "MhookHelper.h" +#include "PPageFormats.h" +#include "PPageSheet.h" +#include "PathUtils.h" +#include "Struct.h" +#include "UpdateChecker.h" +#include "WebServer.h" +#include "WinAPIUtils.h" +#include "mpc-hc_config.h" +#include "winddk/ntddcdvd.h" +#include +#include +#include +#include +#include "ExceptionHandler.h" +#include "FGFilterLAV.h" +#include "CMPCThemeMsgBox.h" +#include "version.h" +#include "psapi.h" + +HICON LoadIcon(CString fn, bool bSmallIcon, DpiHelper* pDpiHelper/* = nullptr*/) +{ + if (fn.IsEmpty()) { + return nullptr; + } + + CString ext = fn.Left(fn.Find(_T("://")) + 1).TrimRight(':'); + if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) { + ext = _T(".") + fn.Mid(fn.ReverseFind('.') + 1); + } + + CSize size(bSmallIcon ? GetSystemMetrics(SM_CXSMICON) : GetSystemMetrics(SM_CXICON), + bSmallIcon ? GetSystemMetrics(SM_CYSMICON) : GetSystemMetrics(SM_CYICON)); + + if (pDpiHelper) { + size.cx = pDpiHelper->ScaleSystemToOverrideX(size.cx); + size.cy = pDpiHelper->ScaleSystemToOverrideY(size.cy); + } + + typedef HRESULT(WINAPI * LIWSD)(HINSTANCE, PCWSTR, int, int, HICON*); + auto loadIcon = [&size](PCWSTR pszName) { + LIWSD pLIWSD = (LIWSD)GetProcAddress(GetModuleHandle(_T("comctl32.dll")), "LoadIconWithScaleDown"); + HICON ret = nullptr; + if (pLIWSD) { + pLIWSD(AfxGetInstanceHandle(), pszName, size.cx, size.cy, &ret); + } else { + ret = (HICON)LoadImage(AfxGetInstanceHandle(), pszName, IMAGE_ICON, size.cx, size.cy, 0); + } + return ret; + }; + + if (!ext.CompareNoCase(_T(".ifo"))) { + if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_DVD))) { + return hIcon; + } + } + + if (!ext.CompareNoCase(_T(".cda"))) { + if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_AUDIOCD))) { + return hIcon; + } + } + + if (!ext.CompareNoCase(_T(".unknown"))) { + if (HICON hIcon = loadIcon(MAKEINTRESOURCE(IDI_UNKNOWN))) { + return hIcon; + } + } + + do { + CRegKey key; + TCHAR buff[256]; + ULONG len; + + auto openRegKey = [&](HKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValueName) { + if (ERROR_SUCCESS == key.Open(hKeyParent, lpszKeyName, KEY_READ)) { + len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + CString progId; + + if (ERROR_SUCCESS == key.QueryStringValue(lpszValueName, buff, &len) && !(progId = buff).Trim().IsEmpty()) { + return (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, progId + _T("\\DefaultIcon"), KEY_READ)); + } + } + return false; + }; + + if (!openRegKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\") + ext + _T("\\UserChoice"), _T("Progid")) + && !openRegKey(HKEY_CLASSES_ROOT, ext, nullptr) + && ERROR_SUCCESS != key.Open(HKEY_CLASSES_ROOT, ext + _T("\\DefaultIcon"), KEY_READ)) { + break; + } + + CString icon; + len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len) || (icon = buff).Trim().IsEmpty()) { + break; + } + + int i = icon.ReverseFind(','); + if (i < 0) { + break; + } + + int id = 0; + if (_stscanf_s(icon.Mid(i + 1), _T("%d"), &id) != 1) { + break; + } + + icon = icon.Left(i); + icon.Trim(_T(" \\\"")); + + HICON hIcon = nullptr; + UINT cnt = bSmallIcon + ? ExtractIconEx(icon, id, nullptr, &hIcon, 1) + : ExtractIconEx(icon, id, &hIcon, nullptr, 1); + if (hIcon && cnt == 1) { + return hIcon; + } + } while (0); + + return loadIcon(MAKEINTRESOURCE(IDI_UNKNOWN)); +} + +bool LoadType(CString fn, CString& type) +{ + bool found = false; + + if (!fn.IsEmpty()) { + CString ext = fn.Left(fn.Find(_T("://")) + 1).TrimRight(':'); + if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) { + ext = _T(".") + fn.Mid(fn.ReverseFind('.') + 1); + } + + // Try MPC-HC's internal formats list + const CMediaFormatCategory* mfc = AfxGetAppSettings().m_Formats.FindMediaByExt(ext); + + if (mfc != nullptr) { + found = true; + type = mfc->GetDescription(); + } else { // Fallback to registry + CRegKey key; + TCHAR buff[256]; + ULONG len; + + CString tmp = _T(""); + CString mplayerc_ext = _T("mplayerc") + ext; + + if (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, mplayerc_ext)) { + tmp = mplayerc_ext; + } + + if (!tmp.IsEmpty() || ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, ext)) { + found = true; + + if (tmp.IsEmpty()) { + tmp = ext; + } + + while (ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, tmp)) { + len = _countof(buff); + ZeroMemory(buff, sizeof(buff)); + + if (ERROR_SUCCESS != key.QueryStringValue(nullptr, buff, &len)) { + break; + } + + CString str(buff); + str.Trim(); + + if (str.IsEmpty() || str == tmp) { + break; + } + + tmp = str; + } + + type = tmp; + } + } + } + + return found; +} + +bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype) +{ + str.Empty(); + HRSRC hrsrc = FindResource(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(resid), restype); + if (!hrsrc) { + return false; + } + HGLOBAL hGlobal = LoadResource(AfxGetApp()->m_hInstance, hrsrc); + if (!hGlobal) { + return false; + } + DWORD size = SizeofResource(AfxGetApp()->m_hInstance, hrsrc); + if (!size) { + return false; + } + memcpy(str.GetBufferSetLength(size), LockResource(hGlobal), size); + return true; +} + +static bool FindRedir(const CUrl& src,const CString& body, CAtlList& urls, const std::vector& res) +{ + bool bDetectHLS = false; + for (const auto re : res) { + std::wcmatch mc; + + for (LPCTSTR s = body; std::regex_search(s, mc, re); s += mc.position() + mc.length()) { + CString url = mc[mc.size() - 1].str().c_str(); + url.Trim(); + + if (url.CompareNoCase(_T("asf path")) == 0) { + continue; + } + if (url.Find(_T("EXTM3U")) == 0 || url.Find(_T("#EXTINF")) == 0) { + bDetectHLS = true; + continue; + } + // Detect HTTP Live Streaming and let the source filter handle that + if (bDetectHLS + && (url.Find(_T("EXT-X-STREAM-INF:")) != -1 + || url.Find(_T("EXT-X-TARGETDURATION:")) != -1 + || url.Find(_T("EXT-X-MEDIA-SEQUENCE:")) != -1)) { + urls.RemoveAll(); + break; + } + + CUrl dst; + dst.CrackUrl(CString(url)); + if (_tcsicmp(src.GetSchemeName(), dst.GetSchemeName()) + || _tcsicmp(src.GetHostName(), dst.GetHostName()) + || _tcsicmp(src.GetUrlPath(), dst.GetUrlPath())) { + urls.AddTail(url); + } else { + // recursive + urls.RemoveAll(); + break; + } + } + } + + return !urls.IsEmpty(); +} + +static bool FindRedir(const CString& fn, CAtlList& fns, const std::vector& res) +{ + CString body; + + CTextFile f(CTextFile::UTF8); + if (f.Open(fn)) { + int i = 0; + for (CString tmp; i < 10000 && f.ReadString(tmp); body += tmp + '\n', ++i) { + ; + } + } + + CString dir = fn.Left(std::max(fn.ReverseFind('/'), fn.ReverseFind('\\')) + 1); // "ReverseFindOneOf" + + for (const auto re : res) { + std::wcmatch mc; + + for (LPCTSTR s = body; std::regex_search(s, mc, re); s += mc.position() + mc.length()) { + CString fn2 = mc[mc.size() - 1].str().c_str(); + fn2.Trim(); + + if (!fn2.CompareNoCase(_T("asf path"))) { + continue; + } + if (fn2.Find(_T("EXTM3U")) == 0 || fn2.Find(_T("#EXTINF")) == 0) { + continue; + } + + if (fn2.Find(_T(":")) < 0 && fn2.Find(_T("\\\\")) != 0 && fn2.Find(_T("//")) != 0) { + CPath p; + p.Combine(dir, fn2); + fn2 = (LPCTSTR)p; + } + + if (!fn2.CompareNoCase(fn)) { + continue; + } + + fns.AddTail(fn2); + } + } + + return !fns.IsEmpty(); +} + + +CString GetContentType(CString fn, CAtlList* redir) +{ + fn.Trim(); + if (fn.IsEmpty()) { + return ""; + } + + CUrl url; + CString content, body; + BOOL url_fail = false; + BOOL ishttp = false; + BOOL parsefile = false; + BOOL isurl = PathUtils::IsURL(fn); + + // Get content type based on the URI scheme + if (isurl) { + url.CrackUrl(fn); + + if (_tcsicmp(url.GetSchemeName(), _T("pnm")) == 0) { + return "audio/x-pn-realaudio"; + } + if (_tcsicmp(url.GetSchemeName(), _T("mms")) == 0) { + return "video/x-ms-asf"; + } + if (_tcsicmp(url.GetSchemeName(), _T("http")) == 0 || _tcsicmp(url.GetSchemeName(), _T("https")) == 0) { + ishttp = true; + } else { + return ""; + } + } + + CString ext = CPath(fn).GetExtension().MakeLower(); + int p = ext.FindOneOf(_T("?#")); + if (p > 0) { + ext = ext.Left(p); + } + + // no further analysis needed if known audio/video extension and points directly to a file + if (!ext.IsEmpty()) { + if (ext == _T(".mp4") || ext == _T(".m4v") || ext == _T(".mov") || ext == _T(".mkv") || ext == _T(".webm") || ext == _T(".avi") || ext == _T(".wmv") || ext == _T(".mpg") || ext == _T(".mpeg") || ext == _T(".flv") || ext == _T(".ogm") || ext == _T(".m2ts") || ext == _T(".ts")) { + content = _T("video"); + } else if (ext == _T(".mp3") || ext == _T(".m4a") || ext == _T(".aac") || ext == _T(".flac") || ext == _T(".mka") || ext == _T(".ogg") || ext == _T(".opus")) { + content = _T("audio"); + } else if (ext == _T(".mpcpl")) { + content = _T("application/x-mpc-playlist"); + } else if (ext == _T(".m3u") || ext == _T(".m3u8")) { + content = _T("audio/x-mpegurl"); + } else if (ext == _T(".bdmv")) { + content = _T("application/x-bdmv-playlist"); + } else if (ext == _T(".cue")) { + content = _T("application/x-cue-sheet"); + } else if (ext == _T(".swf")) { + content = _T("application/x-shockwave-flash"); + } + + if (!content.IsEmpty()) { + return content; + } + } + + // Get content type by getting the header response from server + if (ishttp) { + CInternetSession internet; + internet.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 5000); + CString headers = _T("User-Agent: MPC-HC"); + CHttpFile* httpFile = NULL; + try { + httpFile = (CHttpFile*)internet.OpenURL(fn, + 1, + INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, + headers, + DWORD(-1)); + } + catch (CInternetException* pEx) + { + pEx->Delete(); + url_fail = true; // Timeout has most likely occured, server unreachable + return content; + } + + if (httpFile) { + //CString strContentType; + //httpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS, strContentType); // Check also HTTP_QUERY_RAW_HEADERS_CRLF + //DWORD dw = 8192; // Arbitrary 8192 char length for Url (should handle most cases) + //CString urlredirect; // Retrieve the new Url in case we encountered an HTTP redirection (HTTP 302 code) + //httpFile->QueryOption(INTERNET_OPTION_URL, urlredirect.GetBuffer(8192), &dw); + DWORD dwStatus; + httpFile->QueryInfoStatusCode(dwStatus); + switch (dwStatus) { + case HTTP_STATUS_OK: // 200 request completed + case HTTP_STATUS_CREATED: // 201 object created, reason = new URI + case HTTP_STATUS_ACCEPTED: // 202 async completion (TBS) + case HTTP_STATUS_PARTIAL: // 203 partial completion + case HTTP_STATUS_NO_CONTENT: // 204 no info to return + case HTTP_STATUS_RESET_CONTENT: // 205 request completed, but clear form + case HTTP_STATUS_PARTIAL_CONTENT: // 206 partial GET furfilled + case HTTP_STATUS_AMBIGUOUS: // 300 server couldn't decide what to return + case HTTP_STATUS_MOVED: // 301 object permanently moved + case HTTP_STATUS_REDIRECT: // 302 object temporarily moved + case HTTP_STATUS_REDIRECT_METHOD: // 303 redirection w/ new access method + case HTTP_STATUS_NOT_MODIFIED: // 304 if-modified-since was not modified + case HTTP_STATUS_USE_PROXY: // 305 redirection to proxy, location header specifies proxy to use + case HTTP_STATUS_REDIRECT_KEEP_VERB: // 307 HTTP/1.1: keep same verb + case 308/*HTTP_STATUS_PERMANENT_REDIRECT*/: // 308 Object permanently moved keep verb + break; + default: + //CString strStatus; + //httpFile->QueryInfo(HTTP_QUERY_STATUS_TEXT, strStatus); // Status String - eg OK, Not Found + url_fail = true; + } + + if (url_fail) { + httpFile->Close(); // Close() isn't called by the destructor + delete httpFile; + return content; + } + + if (content.IsEmpty()) { + httpFile->QueryInfo(HTTP_QUERY_CONTENT_TYPE, content); // Content-Type - eg text/html + } + + long contentsize = 0; + CString contentlength = _T(""); + if (httpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, contentlength)) { + contentsize = _ttol(contentlength); + } + + // Partial download of response body to further identify content types + if (content.IsEmpty() && contentsize < 256*1024) { + UINT br = 0; + char buffer[513] = ""; + while (body.GetLength() < 256) { + br = httpFile->Read(buffer, 256); + if (br == 0) { + break; + } + buffer[br] = '\0'; + body += buffer; + } + if (body.GetLength() >= 8) { + BOOL exit = false; + if (!wcsncmp((LPCWSTR)body, _T(".ra"), 3)) { + content = _T("audio/x-pn-realaudio"); + exit = true; + } else if (!wcsncmp((LPCWSTR)body, _T(".RMF"), 4)) { + content = _T("audio/x-pn-realaudio"); + exit = true; + } + + if (exit) { + httpFile->Close(); + delete httpFile; + return content; + } + } + } + // Download larger piece of response body in case it's a playlist + if (redir && contentsize < 256*1024 && (content == _T("audio/x-scpls") || content == _T("audio/scpls") + || content == _T("video/x-ms-asf") || content == _T("text/plain") + || content == _T("application/octet-stream") || content == _T("application/pls+xml"))) { + UINT br = 0; + char buffer[513] = ""; + while (body.GetLength() < 64 * 1024) { // should be enough for a playlist... + br = httpFile->Read(buffer, 256); + if (br == 0) { + break; + } + buffer[br] = '\0'; + body += buffer; + } + } + + httpFile->Close(); + delete httpFile; + } + } + + // If content type is empty, plain text or octet-stream (weird server!) GUESS by extension if it exists..... + if (content.IsEmpty() || content == _T("text/plain") || content == _T("application/octet-stream")) { + if (ext == _T(".pls")) { + content = _T("audio/x-scpls"); + parsefile = true; + } else if (ext == _T(".asx")) { + content = _T("video/x-ms-asf"); + parsefile = true; + } else if (ext == _T(".ram")) { + content = _T("audio/x-pn-realaudio"); + parsefile = true; + } + } + + if (redir && !content.IsEmpty() && (isurl && !body.IsEmpty() || !isurl && parsefile)) { + std::vector res; + const std::wregex::flag_type reFlags = std::wregex::icase | std::wregex::optimize; + + if (content == _T("video/x-ms-asf")) { + // ...://..."/> + res.emplace_back(_T("[a-zA-Z]+://[^\n\">]*"), reFlags); + // Ref#n= ...://...\n + res.emplace_back(_T("Ref\\d+\\s*=\\s*[\"]*([a-zA-Z]+://[^\n\"]+)"), reFlags); + } + else if (content == _T("audio/x-scpls") || content == _T("audio/scpls") || content == _T("application/pls+xml")) { + // File1=...\n + res.emplace_back(_T("file\\d+\\s*=\\s*[\"]*([^\n\"]+)"), reFlags); + } + else if (content == _T("audio/x-pn-realaudio")) { + // rtsp://... + res.emplace_back(_T("rtsp://[^\n]+"), reFlags); + // http://... + res.emplace_back(_T("http://[^\n]+"), reFlags); + } + + if (res.size()) { + if (isurl) { + FindRedir(url, body, *redir, res); + } else { + FindRedir(fn, *redir, res); + } + } + } + + return content; +} + +WORD AssignedToCmd(UINT keyValue) +{ + if (keyValue == 0) { + ASSERT(false); + return 0; + } + + WORD assignTo = 0; + const CAppSettings& s = AfxGetAppSettings(); + + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos && !assignTo) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + + if (wc.key == keyValue) { + assignTo = wc.cmd; + } + } + + return assignTo; +} + +std::map GetAudioDeviceList() { + std::map devicelist; + BeginEnumSysDev(CLSID_AudioRendererCategory, pMoniker) { + CComHeapPtr olestr; + if (FAILED(pMoniker->GetDisplayName(0, 0, &olestr))) { + continue; + } + CStringW dispname(olestr); + CStringW friendlyname; + CComPtr pPB; + if (SUCCEEDED(pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPB)))) { + CComVariant var; + if (SUCCEEDED(pPB->Read(_T("FriendlyName"), &var, nullptr))) { + CStringW frname(var.bstrVal); + var.Clear(); + friendlyname = frname; + } + } else { + friendlyname = dispname; + } + devicelist.emplace(friendlyname, dispname); + } + EndEnumSysDev; + + return devicelist; +} + +void SetAudioRenderer(int AudioDevNo) +{ + CStringArray dispnames; + AfxGetMyApp()->m_AudioRendererDisplayName_CL = _T(""); + dispnames.Add(_T("")); + dispnames.Add(AUDRNDT_INTERNAL); + dispnames.Add(AUDRNDT_MPC); + int devcount = 3; + + std::map devicelist = GetAudioDeviceList(); + + for (auto it = devicelist.cbegin(); it != devicelist.cend(); it++) { + dispnames.Add((*it).second); + devcount++; + } + + dispnames.Add(AUDRNDT_NULL_COMP); + dispnames.Add(AUDRNDT_NULL_UNCOMP); + devcount += 2; + + if (AudioDevNo >= 1 && AudioDevNo <= devcount) { + AfxGetMyApp()->m_AudioRendererDisplayName_CL = dispnames[AudioDevNo - 1]; + } +} + +void SetHandCursor(HWND m_hWnd, UINT nID) +{ + SetClassLongPtr(GetDlgItem(m_hWnd, nID), GCLP_HCURSOR, (LONG_PTR)AfxGetApp()->LoadStandardCursor(IDC_HAND)); +} + +// CMPlayerCApp + +CMPlayerCApp::CMPlayerCApp() + : m_hNTDLL(nullptr) + , m_bDelayingIdle(false) + , m_bProfileInitialized(false) + , m_bQueuedProfileFlush(false) + , m_dwProfileLastAccessTick(0) + , m_fClosingState(false) + , m_bThemeLoaded(false) +{ + m_strVersion = FileVersionInfo::GetFileVersionStr(PathUtils::GetProgramPath(true)); + + ZeroMemory(&m_ColorControl, sizeof(m_ColorControl)); + ResetColorControlRange(); + + ZeroMemory(&m_VMR9ColorControl, sizeof(m_VMR9ColorControl)); + m_VMR9ColorControl[0].dwSize = sizeof(VMR9ProcAmpControlRange); + m_VMR9ColorControl[0].dwProperty = ProcAmpControl9_Brightness; + m_VMR9ColorControl[1].dwSize = sizeof(VMR9ProcAmpControlRange); + m_VMR9ColorControl[1].dwProperty = ProcAmpControl9_Contrast; + m_VMR9ColorControl[2].dwSize = sizeof(VMR9ProcAmpControlRange); + m_VMR9ColorControl[2].dwProperty = ProcAmpControl9_Hue; + m_VMR9ColorControl[3].dwSize = sizeof(VMR9ProcAmpControlRange); + m_VMR9ColorControl[3].dwProperty = ProcAmpControl9_Saturation; + + ZeroMemory(&m_EVRColorControl, sizeof(m_EVRColorControl)); + + GetRemoteControlCode = GetRemoteControlCodeMicrosoft; +} + +CMPlayerCApp::~CMPlayerCApp() +{ + if (m_hNTDLL) { + FreeLibrary(m_hNTDLL); + } + // Wait for any pending I/O operations to be canceled + while (WAIT_IO_COMPLETION == SleepEx(0, TRUE)); +} + +int CMPlayerCApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, + UINT nIDPrompt) +{ + if (AppIsThemeLoaded()) { + CWnd* pParentWnd = CWnd::GetActiveWindow(); + if (pParentWnd == NULL) { + pParentWnd = GetMainWnd(); + if (pParentWnd == NULL) { + return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt); + } else { + pParentWnd = pParentWnd->GetLastActivePopup(); + } + } + + CMPCThemeMsgBox dlgMessage(pParentWnd, lpszPrompt, _T(""), nType, + nIDPrompt); + + return (int)dlgMessage.DoModal(); + } else { + return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt); + } +} + +void CMPlayerCApp::DelayedIdle() +{ + m_bDelayingIdle = false; +} + +BOOL CMPlayerCApp::IsIdleMessage(MSG* pMsg) +{ + BOOL ret = __super::IsIdleMessage(pMsg); + if (ret && pMsg->message == WM_MOUSEMOVE) { + if (m_bDelayingIdle) { + ret = FALSE; + } else { + auto pMainFrm = AfxGetMainFrame(); + if (pMainFrm && m_pMainWnd) { + const unsigned uTimeout = 100; + // delay next WM_MOUSEMOVE initiated idle for uTimeout ms + // if there will be no WM_MOUSEMOVE messages, WM_TIMER will initiate the idle + pMainFrm->m_timerOneTime.Subscribe( + CMainFrame::TimerOneTimeSubscriber::DELAY_IDLE, std::bind(&CMPlayerCApp::DelayedIdle, this), uTimeout); + m_bDelayingIdle = true; + } + } + } + return ret; +} + +BOOL CMPlayerCApp::OnIdle(LONG lCount) +{ + BOOL ret = __super::OnIdle(lCount); + + if (!ret) { + FlushProfile(false); + } + + return ret; +} + +BOOL CMPlayerCApp::PumpMessage() +{ + return MsgWaitForMultipleObjectsEx(0, nullptr, INFINITE, QS_ALLINPUT, + MWMO_INPUTAVAILABLE | MWMO_ALERTABLE) == WAIT_IO_COMPLETION ? TRUE : __super::PumpMessage(); +} + +void CMPlayerCApp::ShowCmdlnSwitches() const +{ + CString cmdLine; + + if ((m_s->nCLSwitches & CLSW_UNRECOGNIZEDSWITCH) && __argc > 0) { + cmdLine = __targv[0]; + for (int i = 1; i < __argc; i++) { + cmdLine.AppendFormat(_T(" %s"), __targv[i]); + } + } + + CmdLineHelpDlg dlg(cmdLine); + dlg.DoModal(); +} + +CMPlayerCApp theApp; // The one and only CMPlayerCApp object + +HWND g_hWnd = nullptr; + +bool CMPlayerCApp::StoreSettingsToIni() +{ + std::lock_guard lock(m_profileMutex); + + CString ini = GetIniPath(); + free((void*)m_pszRegistryKey); + m_pszRegistryKey = nullptr; + free((void*)m_pszProfileName); + m_pszProfileName = _tcsdup(ini); + + return true; +} + +bool CMPlayerCApp::StoreSettingsToRegistry() +{ + std::lock_guard lock(m_profileMutex); + + free((void*)m_pszRegistryKey); + m_pszRegistryKey = nullptr; + + SetRegistryKey(_T("MPC-HC")); + + return true; +} + +CString CMPlayerCApp::GetIniPath() const +{ + CString path = PathUtils::GetProgramPath(true); + path = path.Left(path.ReverseFind('.') + 1) + _T("ini"); + return path; +} + +bool CMPlayerCApp::IsIniValid() const +{ + return PathUtils::Exists(GetIniPath()); +} + +bool CMPlayerCApp::GetAppSavePath(CString& path) +{ + if (IsIniValid()) { // If settings ini file found, store stuff in the same folder as the exe file + path = PathUtils::GetProgramPath(); + } else { + return GetAppDataPath(path); + } + + return true; +} + +bool CMPlayerCApp::GetAppDataPath(CString& path) +{ + path.Empty(); + + HRESULT hr = SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, 0, path.GetBuffer(MAX_PATH)); + path.ReleaseBuffer(); + if (FAILED(hr)) { + return false; + } + CPath p; + p.Combine(path, _T("MPC-HC")); + path = (LPCTSTR)p; + + return true; +} + +bool CMPlayerCApp::ChangeSettingsLocation(bool useIni) +{ + std::lock_guard lock(m_profileMutex); + + bool success; + + // Load favorites so that they can be correctly saved to the new location + CAtlList filesFav, DVDsFav, devicesFav; + m_s->GetFav(FAV_FILE, filesFav); + m_s->GetFav(FAV_DVD, DVDsFav); + m_s->GetFav(FAV_DEVICE, devicesFav); + + if (useIni) { + success = StoreSettingsToIni(); + // No need to delete old mpc-hc.ini, + // as it will be overwritten during CAppSettings::SaveSettings() + } else { + success = StoreSettingsToRegistry(); + _tremove(GetIniPath()); + } + + // Save favorites to the new location + m_s->SetFav(FAV_FILE, filesFav); + m_s->SetFav(FAV_DVD, DVDsFav); + m_s->SetFav(FAV_DEVICE, devicesFav); + + // Save external filters to the new location + m_s->SaveExternalFilters(); + + // Write settings immediately + m_s->SaveSettings(true); + + return success; +} + +bool CMPlayerCApp::ExportSettings(CString savePath, CString subKey) +{ + bool success = false; + m_s->SaveSettings(); + + if (IsIniValid()) { + success = !!CopyFile(GetIniPath(), savePath, FALSE); + } else { + CString regKey; + if (subKey.IsEmpty()) { + regKey.Format(_T("Software\\%s\\%s"), m_pszRegistryKey, m_pszProfileName); + } else { + regKey.Format(_T("Software\\%s\\%s\\%s"), m_pszRegistryKey, m_pszProfileName, subKey.GetString()); + } + + FILE* fStream; + errno_t error = _tfopen_s(&fStream, savePath, _T("wt,ccs=UNICODE")); + CStdioFile file(fStream); + file.WriteString(_T("Windows Registry Editor Version 5.00\n\n")); + + success = !error && ExportRegistryKey(file, HKEY_CURRENT_USER, regKey); + + file.Close(); + if (!success && !error) { + DeleteFile(savePath); + } + } + + return success; +} + +void CMPlayerCApp::InitProfile() +{ + std::lock_guard lock(m_profileMutex); + + if (!m_pszRegistryKey) { + // Don't reread mpc-hc.ini if the cache needs to be flushed or it was accessed recently + if (m_bProfileInitialized && (m_bQueuedProfileFlush || GetTickCount64() - m_dwProfileLastAccessTick < 100ULL)) { + m_dwProfileLastAccessTick = GetTickCount64(); + return; + } + + m_bProfileInitialized = true; + m_dwProfileLastAccessTick = GetTickCount64(); + + ASSERT(m_pszProfileName); + if (!PathUtils::Exists(m_pszProfileName)) { + return; + } + + FILE* fp; + int fpStatus; + do { // Open mpc-hc.ini in UNICODE mode, retry if it is already being used by another process + fp = _tfsopen(m_pszProfileName, _T("r, ccs=UNICODE"), _SH_SECURE); + if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { + break; + } + Sleep(100); + } while (true); + if (!fp) { + ASSERT(FALSE); + return; + } + if (_ftell_nolock(fp) == 0L) { + // No BOM was consumed, assume mpc-hc.ini is ANSI encoded + fpStatus = fclose(fp); + ASSERT(fpStatus == 0); + do { // Reopen mpc-hc.ini in ANSI mode, retry if it is already being used by another process + fp = _tfsopen(m_pszProfileName, _T("r"), _SH_SECURE); + if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { + break; + } + Sleep(100); + } while (true); + if (!fp) { + ASSERT(FALSE); + return; + } + } + + CStdioFile file(fp); + + ASSERT(!m_bQueuedProfileFlush); + m_ProfileMap.clear(); + + CString line, section, var, val; + while (file.ReadString(line)) { + // Parse mpc-hc.ini file, this parser: + // - doesn't trim whitespaces + // - doesn't remove quotation marks + // - omits keys with empty names + // - omits unnamed sections + int pos = 0; + if (line[0] == _T('[')) { + pos = line.Find(_T(']')); + if (pos == -1) { + continue; + } + section = line.Mid(1, pos - 1); + } else if (line[0] != _T(';')) { + pos = line.Find(_T('=')); + if (pos == -1) { + continue; + } + var = line.Mid(0, pos); + val = line.Mid(pos + 1); + if (!section.IsEmpty() && !var.IsEmpty()) { + m_ProfileMap[section][var] = val; + } + } + } + fpStatus = fclose(fp); + ASSERT(fpStatus == 0); + + m_dwProfileLastAccessTick = GetTickCount64(); + } +} + +void CMPlayerCApp::FlushProfile(bool bForce/* = true*/) +{ + std::lock_guard lock(m_profileMutex); + + if (!m_pszRegistryKey) { + if (!bForce && !m_bQueuedProfileFlush) { + return; + } + + m_bQueuedProfileFlush = false; + + ASSERT(m_bProfileInitialized); + ASSERT(m_pszProfileName); + + FILE* fp; + int fpStatus; + do { // Open mpc-hc.ini, retry if it is already being used by another process + fp = _tfsopen(m_pszProfileName, _T("w, ccs=UTF-8"), _SH_SECURE); + if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { + break; + } + Sleep(100); + } while (true); + if (!fp) { + ASSERT(FALSE); + return; + } + CStdioFile file(fp); + CString line; + try { + file.WriteString(_T("; MPC-HC\n")); + for (auto it1 = m_ProfileMap.begin(); it1 != m_ProfileMap.end(); ++it1) { + line.Format(_T("[%s]\n"), it1->first.GetString()); + file.WriteString(line); + for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) { + line.Format(_T("%s=%s\n"), it2->first.GetString(), it2->second.GetString()); + file.WriteString(line); + } + } + } catch (CFileException& e) { + // Fail silently if disk is full + UNREFERENCED_PARAMETER(e); + ASSERT(FALSE); + } + fpStatus = fclose(fp); + ASSERT(fpStatus == 0); + } +} + +BOOL CMPlayerCApp::GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes) +{ + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + return CWinAppEx::GetProfileBinary(lpszSection, lpszEntry, ppData, pBytes); + } else { + if (!lpszSection || !lpszEntry || !ppData || !pBytes) { + ASSERT(FALSE); + return FALSE; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + CString valueStr; + + InitProfile(); + auto it1 = m_ProfileMap.find(sectionStr); + if (it1 != m_ProfileMap.end()) { + auto it2 = it1->second.find(keyStr); + if (it2 != it1->second.end()) { + valueStr = it2->second; + } + } + if (valueStr.IsEmpty()) { + return FALSE; + } + int length = valueStr.GetLength(); + // Encoding: each 4-bit sequence is coded in one character, from 'A' for 0x0 to 'P' for 0xf + if (length % 2) { + ASSERT(FALSE); + return FALSE; + } + for (int i = 0; i < length; i++) { + if (valueStr[i] < 'A' || valueStr[i] > 'P') { + ASSERT(FALSE); + return FALSE; + } + } + *pBytes = length / 2; + *ppData = new (std::nothrow) BYTE[*pBytes]; + if (!(*ppData)) { + ASSERT(FALSE); + return FALSE; + } + for (UINT i = 0; i < *pBytes; i++) { + (*ppData)[i] = BYTE((valueStr[i * 2] - 'A') | ((valueStr[i * 2 + 1] - 'A') << 4)); + } + return TRUE; + } +} + +UINT CMPlayerCApp::GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) +{ + std::lock_guard lock(m_profileMutex); + + int res = nDefault; + if (m_pszRegistryKey) { + res = CWinAppEx::GetProfileInt(lpszSection, lpszEntry, nDefault); + } else { + if (!lpszSection || !lpszEntry) { + ASSERT(FALSE); + return res; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return res; + } + + InitProfile(); + auto it1 = m_ProfileMap.find(sectionStr); + if (it1 != m_ProfileMap.end()) { + auto it2 = it1->second.find(keyStr); + if (it2 != it1->second.end()) { + res = _ttoi(it2->second); + } + } + } + return res; +} + +std::list CMPlayerCApp::GetSectionSubKeys(LPCWSTR lpszSection) { + std::lock_guard lock(m_profileMutex); + + std::list keys; + + if (m_pszRegistryKey) { + WCHAR achKey[MAX_REGKEY_LEN]; // buffer for subkey name + DWORD cbName; // size of name string + DWORD cSubKeys = 0; // number of subkeys + + if (HKEY hAppKey = GetAppRegistryKey()) { + HKEY hSectionKey; + if (ERROR_SUCCESS == RegOpenKeyExW(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey)) { + RegQueryInfoKeyW(hSectionKey, NULL, NULL, NULL, &cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + if (cSubKeys) { + for (DWORD i = 0; i < cSubKeys; i++) { + cbName = MAX_REGKEY_LEN; + if (ERROR_SUCCESS == RegEnumKeyExW(hSectionKey, i, achKey, &cbName, NULL, NULL, NULL, NULL)){ + keys.push_back(achKey); + } + } + } + } + } + } else { + if (!lpszSection) { + ASSERT(FALSE); + return keys; + } + CStringW sectionStr(lpszSection); + if (sectionStr.IsEmpty()) { + ASSERT(FALSE); + return keys; + } + InitProfile(); + auto it1 = m_ProfileMap.begin(); + while (it1 != m_ProfileMap.end()) { + if (it1->first.Find(sectionStr + L"\\") == 0) { + CStringW subKey = it1->first.Mid(sectionStr.GetLength() + 1); + if (subKey.Find(L"\\") == -1) { + keys.push_back(subKey); + } + } + it1++; + } + + } + return keys; +} + + +CString CMPlayerCApp::GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault) +{ + std::lock_guard lock(m_profileMutex); + + CString res; + if (m_pszRegistryKey) { + res = CWinAppEx::GetProfileString(lpszSection, lpszEntry, lpszDefault); + } else { + if (!lpszSection || !lpszEntry) { + ASSERT(FALSE); + return res; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return res; + } + if (lpszDefault) { + res = lpszDefault; + } + + InitProfile(); + auto it1 = m_ProfileMap.find(sectionStr); + if (it1 != m_ProfileMap.end()) { + auto it2 = it1->second.find(keyStr); + if (it2 != it1->second.end()) { + res = it2->second; + } + } + } + return res; +} + +BOOL CMPlayerCApp::WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes) +{ + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + return CWinAppEx::WriteProfileBinary(lpszSection, lpszEntry, pData, nBytes); + } else { + if (!lpszSection || !lpszEntry || !pData || !nBytes) { + ASSERT(FALSE); + return FALSE; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + CString valueStr; + + TCHAR* buffer = valueStr.GetBufferSetLength(nBytes * 2); + // Encoding: each 4-bit sequence is coded in one character, from 'A' for 0x0 to 'P' for 0xf + for (UINT i = 0; i < nBytes; i++) { + buffer[i * 2] = 'A' + (pData[i] & 0xf); + buffer[i * 2 + 1] = 'A' + (pData[i] >> 4 & 0xf); + } + valueStr.ReleaseBufferSetLength(nBytes * 2); + + InitProfile(); + CString& old = m_ProfileMap[sectionStr][keyStr]; + if (old != valueStr) { + old = valueStr; + m_bQueuedProfileFlush = true; + } + return TRUE; + } +} + +LONG CMPlayerCApp::RemoveProfileKey(LPCWSTR lpszSection, LPCWSTR lpszEntry) { + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + if (HKEY hAppKey = GetAppRegistryKey()) { + HKEY hSectionKey; + if (ERROR_SUCCESS == RegOpenKeyEx(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey)) { + return CWinAppEx::DelRegTree(hSectionKey, lpszEntry); + } + } + } else { + if (!lpszSection || !lpszEntry) { + ASSERT(FALSE); + return 1; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return 1; + } + + InitProfile(); + auto it1 = m_ProfileMap.find(sectionStr + L"\\" + keyStr); + if (it1 != m_ProfileMap.end()) { + m_ProfileMap.erase(it1); + m_bQueuedProfileFlush = true; + } + } + return 0; +} + +BOOL CMPlayerCApp::WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) +{ + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + return CWinAppEx::WriteProfileInt(lpszSection, lpszEntry, nValue); + } else { + if (!lpszSection || !lpszEntry) { + ASSERT(FALSE); + return FALSE; + } + CString sectionStr(lpszSection); + CString keyStr(lpszEntry); + if (sectionStr.IsEmpty() || keyStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + CString valueStr; + valueStr.Format(_T("%d"), nValue); + + InitProfile(); + CString& old = m_ProfileMap[sectionStr][keyStr]; + if (old != valueStr) { + old = valueStr; + m_bQueuedProfileFlush = true; + } + return TRUE; + } +} + +BOOL CMPlayerCApp::WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) +{ + std::lock_guard lock(m_profileMutex); + + if (m_pszRegistryKey) { + return CWinAppEx::WriteProfileString(lpszSection, lpszEntry, lpszValue); + } else { + if (!lpszSection) { + ASSERT(FALSE); + return FALSE; + } + CString sectionStr(lpszSection); + if (sectionStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + CString keyStr(lpszEntry); + if (lpszEntry && keyStr.IsEmpty()) { + ASSERT(FALSE); + return FALSE; + } + + InitProfile(); + + // Mimic CWinAppEx::WriteProfileString() behavior + if (lpszEntry) { + if (lpszValue) { + CString& old = m_ProfileMap[sectionStr][keyStr]; + if (old != lpszValue) { + old = lpszValue; + m_bQueuedProfileFlush = true; + } + } else { // Delete key + auto it = m_ProfileMap.find(sectionStr); + if (it != m_ProfileMap.end()) { + if (it->second.erase(keyStr)) { + m_bQueuedProfileFlush = true; + } + } + } + } else { // Delete section + if (m_ProfileMap.erase(sectionStr)) { + m_bQueuedProfileFlush = true; + } + } + return TRUE; + } +} + +bool CMPlayerCApp::HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry) +{ + std::lock_guard lock(m_profileMutex); + + bool ret = false; + if (m_pszRegistryKey) { + if (HKEY hAppKey = GetAppRegistryKey()) { + HKEY hSectionKey; + if (RegOpenKeyEx(hAppKey, lpszSection, 0, KEY_READ, &hSectionKey) == ERROR_SUCCESS) { + LONG lResult = RegQueryValueEx(hSectionKey, lpszEntry, nullptr, nullptr, nullptr, nullptr); + ret = (lResult == ERROR_SUCCESS); + VERIFY(RegCloseKey(hSectionKey) == ERROR_SUCCESS); + } + VERIFY(RegCloseKey(hAppKey) == ERROR_SUCCESS); + } else { + ASSERT(FALSE); + } + } else { + InitProfile(); + auto it1 = m_ProfileMap.find(lpszSection); + if (it1 != m_ProfileMap.end()) { + auto& sectionMap = it1->second; + auto it2 = sectionMap.find(lpszEntry); + ret = (it2 != sectionMap.end()); + } + } + return ret; +} + +std::vector CMPlayerCApp::GetProfileVectorInt(CString strSection, CString strKey) { + std::vector vData; + UINT uSize = theApp.GetProfileInt(strSection, strKey + _T("Size"), 0); + UINT uSizeRead = 0; + BYTE* temp = nullptr; + theApp.GetProfileBinary(strSection, strKey, &temp, &uSizeRead); + if (uSizeRead == uSize) { + vData.resize(uSizeRead / sizeof(int), 0); + memcpy(vData.data(), temp, uSizeRead); + } + delete[] temp; + temp = nullptr; + return vData; +} + + +void CMPlayerCApp::WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData) { + UINT uSize = static_cast(sizeof(int) * vData.size()); + theApp.WriteProfileBinary( + strSection, + strKey, + (LPBYTE)vData.data(), + uSize + ); + theApp.WriteProfileInt(strSection, strKey + _T("Size"), uSize); +} + +void CMPlayerCApp::PreProcessCommandLine() +{ + m_cmdln.RemoveAll(); + + for (int i = 1; i < __argc; i++) { + m_cmdln.AddTail(CString(__targv[i]).Trim(_T(" \""))); + } +} + +bool CMPlayerCApp::SendCommandLine(HWND hWnd) +{ + if (m_cmdln.IsEmpty()) { + return false; + } + + int bufflen = sizeof(DWORD); + + POSITION pos = m_cmdln.GetHeadPosition(); + while (pos) { + bufflen += (m_cmdln.GetNext(pos).GetLength() + 1) * sizeof(TCHAR); + } + + CAutoVectorPtr buff; + if (!buff.Allocate(bufflen)) { + return FALSE; + } + + BYTE* p = buff; + + *(DWORD*)p = (DWORD)m_cmdln.GetCount(); + p += sizeof(DWORD); + + pos = m_cmdln.GetHeadPosition(); + while (pos) { + const CString& s = m_cmdln.GetNext(pos); + int len = (s.GetLength() + 1) * sizeof(TCHAR); + memcpy(p, s, len); + p += len; + } + + COPYDATASTRUCT cds; + cds.dwData = 0x6ABE51; + cds.cbData = bufflen; + cds.lpData = (void*)(BYTE*)buff; + + return !!SendMessageTimeoutW(hWnd, WM_COPYDATA, (WPARAM)nullptr, (LPARAM)&cds, SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 5000, nullptr); +} + +// CMPlayerCApp initialization + +// This hook prevents the program from reporting that a debugger is attached +BOOL(WINAPI* Real_IsDebuggerPresent)() = IsDebuggerPresent; +BOOL WINAPI Mine_IsDebuggerPresent() +{ + TRACE(_T("Oops, somebody was trying to be naughty! (called IsDebuggerPresent)\n")); + return FALSE; +} + +// This hook prevents the program from reporting that a debugger is attached +NTSTATUS(WINAPI* Real_NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG) = nullptr; +NTSTATUS WINAPI Mine_NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength) +{ + NTSTATUS nRet; + + nRet = Real_NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength); + + if (ProcessInformationClass == ProcessBasicInformation) { + PROCESS_BASIC_INFORMATION* pbi = (PROCESS_BASIC_INFORMATION*)ProcessInformation; + PEB_NT* pPEB = (PEB_NT*)pbi->PebBaseAddress; + PEB_NT PEB; + + ReadProcessMemory(ProcessHandle, pPEB, &PEB, sizeof(PEB), nullptr); + PEB.BeingDebugged = FALSE; + WriteProcessMemory(ProcessHandle, pPEB, &PEB, sizeof(PEB), nullptr); + } else if (ProcessInformationClass == 7) { // ProcessDebugPort + BOOL* pDebugPort = (BOOL*)ProcessInformation; + *pDebugPort = FALSE; + } + + return nRet; +} + +#define USE_DLL_BLOCKLIST 1 + +#if USE_DLL_BLOCKLIST +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) + +typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 } SECTION_INHERIT; + +typedef enum _SECTION_INFORMATION_CLASS { + SectionBasicInformation = 0, + SectionImageInformation +} SECTION_INFORMATION_CLASS; + +typedef struct _SECTION_BASIC_INFORMATION { + PVOID BaseAddress; + ULONG Attributes; + LARGE_INTEGER Size; +} SECTION_BASIC_INFORMATION; + +typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtMapViewOfSection)(HANDLE, HANDLE, PVOID, ULONG_PTR, SIZE_T, PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT, ULONG, ULONG); +typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtUnmapViewOfSection)(HANDLE, PVOID); +typedef NTSTATUS(STDMETHODCALLTYPE* pfn_NtQuerySection)(HANDLE, SECTION_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); +typedef DWORD(STDMETHODCALLTYPE* pfn_GetMappedFileNameW)(HANDLE, LPVOID, LPWSTR, DWORD); + +static pfn_NtMapViewOfSection Real_NtMapViewOfSection = nullptr; +static pfn_NtUnmapViewOfSection Real_NtUnmapViewOfSection = nullptr; +static pfn_NtQuerySection Real_NtQuerySection = nullptr; +static pfn_GetMappedFileNameW Real_GetMappedFileNameW = nullptr; + +typedef struct { + // DLL name, lower case, with backslash as prefix + const wchar_t* name; + size_t name_len; +} blocked_module_t; + +// list of modules that can cause crashes or other unwanted behavior +static blocked_module_t moduleblocklist[] = { +#if WIN64 + // Logitech codec + {_T("\\lvcod64.dll"), 12}, + // ProxyCodec64 + {_T("\\pxc0.dll"), 9}, +#else + {_T("\\mlc.dll"), 8}, +#endif + // Lame + {_T("\\lameacm.acm"), 12}, + // ffdshow vfw + {_T("\\ff_vfw.dll"), 11}, +#if WIN64 + // Trusteer Rapport + {_T("\\rooksbas_x64.dll"), 17}, + {_T("\\rooksdol_x64.dll"), 17}, + {_T("\\rapportgh_x64.dll"), 18}, +#endif + // ASUS GamerOSD + {_T("\\atkdx11disp.dll"), 16}, + // ASUS GPU TWEAK II OSD + {_T("\\gtii-osd64.dll"), 15}, + {_T("\\gtii-osd64-vk.dll"), 18}, + // Nahimic Audio + {L"\\nahimicmsidevprops.dll", 23}, + {L"\\nahimicmsiosd.dll", 18}, + // LoiLoGameRecorder + {_T("\\loilocap.dll"), 13}, + // Other + {_T("\\tortoiseoverlays.dll"), 21}, +#if WIN64 + // Sizer + {_T("\\hook64.dll"), 11}, +#endif +}; + +bool IsBlockedModule(wchar_t* modulename) +{ + size_t mod_name_len = wcslen(modulename); + + //TRACE(L"Checking module blocklist: %s\n", modulename); + + for (size_t i = 0; i < _countof(moduleblocklist); i++) { + blocked_module_t* b = &moduleblocklist[i]; + if (mod_name_len > b->name_len) { + wchar_t* dll_ptr = modulename + mod_name_len - b->name_len; + if (_wcsicmp(dll_ptr, b->name) == 0) { + //AfxMessageBox(modulename); + TRACE(L"Blocked module load: %s\n", modulename); + return true; + } + } + } + + return false; +} + +NTSTATUS STDMETHODCALLTYPE Mine_NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, + PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) +{ + NTSTATUS ret = Real_NtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); + + // Verify map and process + if (ret < 0 || ProcessHandle != GetCurrentProcess()) + return ret; + + // Fetch section information + SIZE_T wrote = 0; + SECTION_BASIC_INFORMATION section_information; + if (Real_NtQuerySection(SectionHandle, SectionBasicInformation, §ion_information, sizeof(section_information), &wrote) < 0) + return ret; + + // Verify fetch was successful + if (wrote != sizeof(section_information)) + return ret; + + // We're not interested in non-image maps + if (!(section_information.Attributes & SEC_IMAGE)) + return ret; + + // Get the actual filename if possible + wchar_t fileName[MAX_PATH]; + // ToDo: switch to PSAPI_VERSION=2 and directly use K32GetMappedFileNameW ? + if (Real_GetMappedFileNameW(ProcessHandle, *BaseAddress, fileName, _countof(fileName)) == 0) + return ret; + + if (IsBlockedModule(fileName)) { + Real_NtUnmapViewOfSection(ProcessHandle, BaseAddress); + ret = STATUS_UNSUCCESSFUL; + } + + return ret; +} +#endif + +static LONG Mine_ChangeDisplaySettingsEx(LONG ret, DWORD dwFlags, LPVOID lParam) +{ + if (dwFlags & CDS_VIDEOPARAMETERS) { + VIDEOPARAMETERS* vp = (VIDEOPARAMETERS*)lParam; + + if (vp->Guid == GUIDFromCString(_T("{02C62061-1097-11d1-920F-00A024DF156E}")) + && (vp->dwFlags & VP_FLAGS_COPYPROTECT)) { + if (vp->dwCommand == VP_COMMAND_GET) { + if ((vp->dwTVStandard & VP_TV_STANDARD_WIN_VGA) + && vp->dwTVStandard != VP_TV_STANDARD_WIN_VGA) { + TRACE(_T("Ooops, tv-out enabled? macrovision checks suck...")); + vp->dwTVStandard = VP_TV_STANDARD_WIN_VGA; + } + } else if (vp->dwCommand == VP_COMMAND_SET) { + TRACE(_T("Ooops, as I already told ya, no need for any macrovision bs here")); + return 0; + } + } + } + + return ret; +} + +// These two hooks prevent the program from requesting Macrovision checks +LONG(WINAPI* Real_ChangeDisplaySettingsExA)(LPCSTR, LPDEVMODEA, HWND, DWORD, LPVOID) = ChangeDisplaySettingsExA; +LONG(WINAPI* Real_ChangeDisplaySettingsExW)(LPCWSTR, LPDEVMODEW, HWND, DWORD, LPVOID) = ChangeDisplaySettingsExW; +LONG WINAPI Mine_ChangeDisplaySettingsExA(LPCSTR lpszDeviceName, LPDEVMODEA lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam) +{ + return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExA(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam); +} +LONG WINAPI Mine_ChangeDisplaySettingsExW(LPCWSTR lpszDeviceName, LPDEVMODEW lpDevMode, HWND hwnd, DWORD dwFlags, LPVOID lParam) +{ + return Mine_ChangeDisplaySettingsEx(Real_ChangeDisplaySettingsExW(lpszDeviceName, lpDevMode, hwnd, dwFlags, lParam), dwFlags, lParam); +} + +// This hook forces files to open even if they are currently being written +HANDLE(WINAPI* Real_CreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileA; +HANDLE WINAPI Mine_CreateFileA(LPCSTR p1, DWORD p2, DWORD p3, LPSECURITY_ATTRIBUTES p4, DWORD p5, DWORD p6, HANDLE p7) +{ + p3 |= FILE_SHARE_WRITE; + + return Real_CreateFileA(p1, p2, p3, p4, p5, p6, p7); +} + +static BOOL CreateFakeVideoTS(LPCWSTR strIFOPath, LPWSTR strFakeFile, size_t nFakeFileSize) +{ + BOOL bRet = FALSE; + WCHAR szTempPath[MAX_PATH]; + WCHAR strFileName[MAX_PATH]; + WCHAR strExt[_MAX_EXT]; + CIfo Ifo; + + if (!GetTempPathW(MAX_PATH, szTempPath)) { + return FALSE; + } + + _wsplitpath_s(strIFOPath, nullptr, 0, nullptr, 0, strFileName, _countof(strFileName), strExt, _countof(strExt)); + _snwprintf_s(strFakeFile, nFakeFileSize, _TRUNCATE, L"%sMPC%s%s", szTempPath, strFileName, strExt); + + if (Ifo.OpenFile(strIFOPath) && Ifo.RemoveUOPs() && Ifo.SaveFile(strFakeFile)) { + bRet = TRUE; + } + + return bRet; +} + +// This hook forces files to open even if they are currently being written and hijacks +// IFO file opening so that a modified IFO with no forbidden operations is opened instead. +HANDLE(WINAPI* Real_CreateFileW)(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileW; +HANDLE WINAPI Mine_CreateFileW(LPCWSTR p1, DWORD p2, DWORD p3, LPSECURITY_ATTRIBUTES p4, DWORD p5, DWORD p6, HANDLE p7) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + size_t nLen = wcslen(p1); + + p3 |= FILE_SHARE_WRITE; + + if (nLen >= 4 && _wcsicmp(p1 + nLen - 4, L".ifo") == 0) { + WCHAR strFakeFile[MAX_PATH]; + if (CreateFakeVideoTS(p1, strFakeFile, _countof(strFakeFile))) { + hFile = Real_CreateFileW(strFakeFile, p2, p3, p4, p5, p6, p7); + } + } + + if (hFile == INVALID_HANDLE_VALUE) { + hFile = Real_CreateFileW(p1, p2, p3, p4, p5, p6, p7); + } + + return hFile; +} + +// This hooks disables the DVD version check +BOOL(WINAPI* Real_DeviceIoControl)(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED) = DeviceIoControl; +BOOL WINAPI Mine_DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) +{ + BOOL ret = Real_DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + if (IOCTL_DVD_GET_REGION == dwIoControlCode && lpOutBuffer && nOutBufferSize == sizeof(DVD_REGION)) { + DVD_REGION* pDVDRegion = (DVD_REGION*)lpOutBuffer; + + if (pDVDRegion->RegionData > 0) { + UCHAR disc_regions = ~pDVDRegion->RegionData; + if ((disc_regions & pDVDRegion->SystemRegion) == 0) { + if (disc_regions & 1) pDVDRegion->SystemRegion = 1; + else if (disc_regions & 2) pDVDRegion->SystemRegion = 2; + else if (disc_regions & 4) pDVDRegion->SystemRegion = 4; + else if (disc_regions & 8) pDVDRegion->SystemRegion = 8; + else if (disc_regions & 16) pDVDRegion->SystemRegion = 16; + else if (disc_regions & 32) pDVDRegion->SystemRegion = 32; + else if (disc_regions & 128) pDVDRegion->SystemRegion = 128; + ret = true; + } + } else if (pDVDRegion->SystemRegion == 0) { + pDVDRegion->SystemRegion = 1; + ret = true; + } + } + return ret; +} + +MMRESULT(WINAPI* Real_mixerSetControlDetails)(HMIXEROBJ, LPMIXERCONTROLDETAILS, DWORD) = mixerSetControlDetails; +MMRESULT WINAPI Mine_mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails) +{ + if (fdwDetails == (MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)) { + return MMSYSERR_NOERROR; // don't touch the mixer, kthx + } + return Real_mixerSetControlDetails(hmxobj, pmxcd, fdwDetails); +} + +BOOL (WINAPI* Real_LockWindowUpdate)(HWND) = LockWindowUpdate; +BOOL WINAPI Mine_LockWindowUpdate(HWND hWndLock) +{ + // TODO: Check if needed on Windows 8+ + if (hWndLock == ::GetDesktopWindow()) { + // locking the desktop window with aero active locks the entire compositor, + // unfortunately MFC does that (when dragging CControlBar) and we want to prevent it + return FALSE; + } else { + return Real_LockWindowUpdate(hWndLock); + } +} + +BOOL RegQueryBoolValue(HKEY hKeyRoot, LPCWSTR lpSubKey, LPCWSTR lpValuename, BOOL defaultvalue) { + BOOL result = defaultvalue; + HKEY hKeyOpen; + DWORD rv = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKeyOpen); + if (rv == ERROR_SUCCESS) { + DWORD data; + DWORD dwBufferSize = sizeof(DWORD); + rv = RegQueryValueEx(hKeyOpen, lpValuename, NULL, NULL, reinterpret_cast(&data), &dwBufferSize); + if (rv == ERROR_SUCCESS) { + result = (data > 0); + } + RegCloseKey(hKeyOpen); + } + return result; +} + +#if USE_DRDUMP_CRASH_REPORTER +void DisableCrashReporter() +{ + if (CrashReporter::IsEnabled()) { + CrashReporter::Disable(); + MPCExceptionHandler::Enable(); + } +} +#endif + +BOOL CMPlayerCApp::InitInstance() +{ + // Remove the working directory from the search path to work around the DLL preloading vulnerability + SetDllDirectory(_T("")); + + // At this point we have not hooked this function yet so we get the real result + if (!IsDebuggerPresent()) { +#if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER + if (RegQueryBoolValue(HKEY_CURRENT_USER, _T("Software\\MPC-HC\\MPC-HC\\Settings"), _T("EnableCrashReporter"), true)) { + CrashReporter::Enable(); + if (!CrashReporter::IsEnabled()) { + MPCExceptionHandler::Enable(); + } + } else { + MPCExceptionHandler::Enable(); + } +#else + MPCExceptionHandler::Enable(); +#endif + } + + if (!HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0)) { + TRACE(_T("Failed to enable \"terminate on corruption\" heap option, error %u\n"), GetLastError()); + ASSERT(FALSE); + } + + bool bHookingSuccessful = MH_Initialize() == MH_OK; + +#ifndef _DEBUG + bHookingSuccessful &= !!Mhook_SetHookEx(&Real_IsDebuggerPresent, Mine_IsDebuggerPresent); +#endif + + m_hNTDLL = LoadLibrary(_T("ntdll.dll")); +#if 0 +#ifndef _DEBUG // Disable NtQueryInformationProcess in debug (prevent VS debugger to stop on crash address) + if (m_hNTDLL) { + Real_NtQueryInformationProcess = (decltype(Real_NtQueryInformationProcess))GetProcAddress(m_hNTDLL, "NtQueryInformationProcess"); + + if (Real_NtQueryInformationProcess) { + bHookingSuccessful &= !!Mhook_SetHookEx(&Real_NtQueryInformationProcess, Mine_NtQueryInformationProcess); + } + } +#endif +#endif + + bHookingSuccessful &= !!Mhook_SetHookEx(&Real_CreateFileW, Mine_CreateFileW); + bHookingSuccessful &= !!Mhook_SetHookEx(&Real_DeviceIoControl, Mine_DeviceIoControl); + + bHookingSuccessful &= MH_EnableHook(MH_ALL_HOOKS) == MH_OK; + + if (!bHookingSuccessful) { + AfxMessageBox(IDS_HOOKS_FAILED); + } + +#if USE_DLL_BLOCKLIST + if (m_hNTDLL) { + Real_NtMapViewOfSection = (pfn_NtMapViewOfSection)GetProcAddress(m_hNTDLL, "NtMapViewOfSection"); + Real_NtUnmapViewOfSection = (pfn_NtUnmapViewOfSection)GetProcAddress(m_hNTDLL, "NtUnmapViewOfSection"); + Real_NtQuerySection = (pfn_NtQuerySection)GetProcAddress(m_hNTDLL, "NtQuerySection"); + Real_GetMappedFileNameW = (pfn_GetMappedFileNameW)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "K32GetMappedFileNameW"); + if (Real_NtMapViewOfSection && Real_NtUnmapViewOfSection && Real_NtQuerySection && Real_GetMappedFileNameW) { + VERIFY(Mhook_SetHookEx(&Real_NtMapViewOfSection, Mine_NtMapViewOfSection)); + } + } +#endif + + // If those hooks fail it's annoying but try to run anyway without reporting any error in release mode + VERIFY(Mhook_SetHookEx(&Real_ChangeDisplaySettingsExA, Mine_ChangeDisplaySettingsExA)); + VERIFY(Mhook_SetHookEx(&Real_ChangeDisplaySettingsExW, Mine_ChangeDisplaySettingsExW)); + VERIFY(Mhook_SetHookEx(&Real_CreateFileA, Mine_CreateFileA)); // The internal splitter uses the right share mode anyway so this is no big deal + VERIFY(Mhook_SetHookEx(&Real_LockWindowUpdate, Mine_LockWindowUpdate)); + VERIFY(Mhook_SetHookEx(&Real_mixerSetControlDetails, Mine_mixerSetControlDetails)); + MH_EnableHook(MH_ALL_HOOKS); + + CFilterMapper2::Init(); + + if (FAILED(OleInitialize(nullptr))) { + AfxMessageBox(_T("OleInitialize failed!")); + return FALSE; + } + + m_s = std::make_unique(); + + // Be careful if you move that code: IDR_MAINFRAME icon can only be loaded from the executable, + // LoadIcon can't be used after the language DLL has been set as the main resource. + HICON icon = LoadIcon(IDR_MAINFRAME); + + WNDCLASS wndcls; + ZeroMemory(&wndcls, sizeof(WNDCLASS)); + wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wndcls.lpfnWndProc = ::DefWindowProc; + wndcls.hInstance = AfxGetInstanceHandle(); + wndcls.hIcon = icon; + wndcls.hCursor = LoadCursor(IDC_ARROW); + wndcls.hbrBackground = 0;//(HBRUSH)(COLOR_WINDOW + 1); // no bkg brush, the view and the bars should always fill the whole client area + wndcls.lpszMenuName = nullptr; + wndcls.lpszClassName = MPC_WND_CLASS_NAME; + + if (!AfxRegisterClass(&wndcls)) { + AfxMessageBox(_T("MainFrm class registration failed!")); + return FALSE; + } + + if (!AfxSocketInit(nullptr)) { + AfxMessageBox(_T("AfxSocketInit failed!")); + return FALSE; + } + + PreProcessCommandLine(); + + if (IsIniValid()) { + StoreSettingsToIni(); + } else { + StoreSettingsToRegistry(); + } + + m_s->ParseCommandLine(m_cmdln); + + VERIFY(SetCurrentDirectory(PathUtils::GetProgramPath())); + + if (m_s->nCLSwitches & (CLSW_HELP | CLSW_UNRECOGNIZEDSWITCH)) { // show commandline help window + m_s->LoadSettings(); + ShowCmdlnSwitches(); + return FALSE; + } + + if (m_s->nCLSwitches & CLSW_RESET) { // reset settings + // We want the other instances to be closed before resetting the settings. + HWND hWnd = FindWindow(MPC_WND_CLASS_NAME, nullptr); + + while (hWnd) { + Sleep(500); + + hWnd = FindWindow(MPC_WND_CLASS_NAME, nullptr); + + if (hWnd && MessageBox(nullptr, ResStr(IDS_RESET_SETTINGS_MUTEX), ResStr(IDS_RESET_SETTINGS), MB_ICONEXCLAMATION | MB_RETRYCANCEL) == IDCANCEL) { + return FALSE; + } + } + + // If the profile was already cached, it should be cleared here + ASSERT(!m_bProfileInitialized); + + // Remove the settings + if (IsIniValid()) { + FILE* fp; + do { // Open mpc-hc.ini, retry if it is already being used by another process + fp = _tfsopen(m_pszProfileName, _T("w"), _SH_SECURE); + if (fp || (GetLastError() != ERROR_SHARING_VIOLATION)) { + break; + } + Sleep(100); + } while (true); + if (fp) { + // Close without writing anything, it should produce empty file + VERIFY(fclose(fp) == 0); + } else { + ASSERT(FALSE); + } + } else { + CRegKey key; + // Clear settings + key.Attach(GetAppRegistryKey()); + VERIFY(key.RecurseDeleteKey(_T("")) == ERROR_SUCCESS); + VERIFY(key.Close() == ERROR_SUCCESS); + // Set ExePath value to prevent settings migration + key.Attach(GetAppRegistryKey()); + VERIFY(key.SetStringValue(_T("ExePath"), PathUtils::GetProgramPath(true)) == ERROR_SUCCESS); + VERIFY(key.Close() == ERROR_SUCCESS); + } + + // Remove the current playlist if it exists + CString strSavePath; + if (GetAppSavePath(strSavePath)) { + CPath playlistPath; + playlistPath.Combine(strSavePath, _T("default.mpcpl")); + + if (playlistPath.FileExists()) { + try { + CFile::Remove(playlistPath); + } catch (...) {} + } + } + } + + if ((m_s->nCLSwitches & CLSW_CLOSE) && m_s->slFiles.IsEmpty()) { // "/close" switch and empty file list + return FALSE; + } + + if (m_s->nCLSwitches & (CLSW_REGEXTVID | CLSW_REGEXTAUD | CLSW_REGEXTPL)) { // register file types + m_s->fileAssoc.RegisterApp(); + + CMediaFormats& mf = m_s->m_Formats; + mf.UpdateData(false); + + bool bAudioOnly; + + auto iconLib = m_s->fileAssoc.GetIconLib(); + if (iconLib) { + iconLib->SaveVersion(); + } + + for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { + bool bPlaylist = !mf[i].GetLabel().CompareNoCase(_T("pls")); + + if (bPlaylist && !(m_s->nCLSwitches & CLSW_REGEXTPL)) { + continue; + } + + bAudioOnly = mf[i].IsAudioOnly(); + + if (((m_s->nCLSwitches & CLSW_REGEXTVID) && !bAudioOnly) || + ((m_s->nCLSwitches & CLSW_REGEXTAUD) && bAudioOnly) || + ((m_s->nCLSwitches & CLSW_REGEXTPL) && bPlaylist)) { + m_s->fileAssoc.Register(mf[i], true, false, true); + } + } + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + + return FALSE; + } + + if (m_s->nCLSwitches & CLSW_UNREGEXT) { // unregistered file types + CMediaFormats& mf = m_s->m_Formats; + mf.UpdateData(false); + + for (size_t i = 0, cnt = mf.GetCount(); i < cnt; i++) { + m_s->fileAssoc.Register(mf[i], false, false, false); + } + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + + return FALSE; + } + + if (m_s->nCLSwitches & CLSW_ICONSASSOC) { + CMediaFormats& mf = m_s->m_Formats; + mf.UpdateData(false); + + CAtlList registeredExts; + m_s->fileAssoc.GetAssociatedExtensionsFromRegistry(registeredExts); + + m_s->fileAssoc.ReAssocIcons(registeredExts); + + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + + return FALSE; + } + + // Enable to open options with administrator privilege (for Vista UAC) + if (m_s->nCLSwitches & CLSW_ADMINOPTION) { + m_s->LoadSettings(); // read all settings. long time but not critical at this point + + switch (m_s->iAdminOption) { + case CPPageFormats::IDD: { + CPPageSheet options(ResStr(IDS_OPTIONS_CAPTION), nullptr, nullptr, m_s->iAdminOption); + options.LockPage(); + options.DoModal(); + } + break; + + default: + ASSERT(FALSE); + } + return FALSE; + } + + if (m_s->nCLSwitches & (CLSW_CONFIGLAVSPLITTER | CLSW_CONFIGLAVAUDIO | CLSW_CONFIGLAVVIDEO)) { + m_s->LoadSettings(); + if (m_s->nCLSwitches & CLSW_CONFIGLAVSPLITTER) { + CFGFilterLAVSplitter::ShowPropertyPages(NULL); + } + if (m_s->nCLSwitches & CLSW_CONFIGLAVAUDIO) { + CFGFilterLAVAudio::ShowPropertyPages(NULL); + } + if (m_s->nCLSwitches & CLSW_CONFIGLAVVIDEO) { + CFGFilterLAVVideo::ShowPropertyPages(NULL); + } + return FALSE; + } + + m_mutexOneInstance.Create(nullptr, TRUE, MPC_WND_CLASS_NAME); + + if (GetLastError() == ERROR_ALREADY_EXISTS) { + if ((m_s->nCLSwitches & CLSW_ADD) || !(m_s->GetAllowMultiInst() || m_s->nCLSwitches & CLSW_NEW || m_cmdln.IsEmpty())) { + DWORD res = WaitForSingleObject(m_mutexOneInstance.m_h, 5000); + if (res == WAIT_OBJECT_0 || res == WAIT_ABANDONED) { + HWND hWnd = ::FindWindow(MPC_WND_CLASS_NAME, nullptr); + if (hWnd) { + DWORD dwProcessId = 0; + if (GetWindowThreadProcessId(hWnd, &dwProcessId) && dwProcessId) { + VERIFY(AllowSetForegroundWindow(dwProcessId)); + } else { + ASSERT(FALSE); + } + if (!(m_s->nCLSwitches & CLSW_MINIMIZED) && IsIconic(hWnd) && + (!(m_s->nCLSwitches & CLSW_ADD) || m_s->nCLSwitches & CLSW_PLAY) //do not restore when adding to playlist of minimized player, unless also playing + ) { + ShowWindow(hWnd, SW_RESTORE); + } + if (SendCommandLine(hWnd)) { + m_mutexOneInstance.Close(); + return FALSE; + } + } + } + if ((m_s->nCLSwitches & CLSW_ADD)) { + ASSERT(FALSE); + return FALSE; // don't open new instance if SendCommandLine() failed + } + } + } + + if (!IsIniValid()) { + CRegKey key; + if (ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, _T("Software\\MPC-HC\\MPC-HC"))) { + if (RegQueryValueEx(key, _T("ExePath"), 0, nullptr, nullptr, nullptr) != ERROR_SUCCESS) { // First launch + // Move registry settings from the old to the new location + CRegKey oldKey; + if (ERROR_SUCCESS == oldKey.Open(HKEY_CURRENT_USER, _T("Software\\Gabest\\Media Player Classic"), KEY_READ)) { + SHCopyKey(oldKey, _T(""), key, 0); + } + } + + key.SetStringValue(_T("ExePath"), PathUtils::GetProgramPath(true)); + } + } + + m_s->UpdateSettings(); // update settings + m_s->LoadSettings(); // read settings + + #if !defined(_DEBUG) && USE_DRDUMP_CRASH_REPORTER + if (!m_s->bEnableCrashReporter) { + DisableCrashReporter(); + } + #endif + + m_AudioRendererDisplayName_CL = _T(""); + + if (!__super::InitInstance()) { + AfxMessageBox(_T("InitInstance failed!")); + return FALSE; + } + + AfxEnableControlContainer(); + + CMainFrame* pFrame; + try { + pFrame = DEBUG_NEW CMainFrame; + if (!pFrame || !pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, nullptr, nullptr)) { + MessageBox(nullptr, ResStr(IDS_FRAME_INIT_FAILED), m_pszAppName, MB_ICONERROR | MB_OK); + return FALSE; + } + } catch (...) { + return FALSE; + } + + m_pMainWnd = pFrame; + pFrame->m_controls.LoadState(); + CPoint borderAdjustDirection; + pFrame->SetDefaultWindowRect((m_s->nCLSwitches & CLSW_MONITOR) ? m_s->iMonitor : 0); + if (!m_s->slFiles.IsEmpty()) { + pFrame->m_controls.DelayShowNotLoaded(true); + } + pFrame->SetDefaultFullscreenState(); + pFrame->UpdateControlState(CMainFrame::UPDATE_CONTROLS_VISIBILITY); + pFrame->SetIcon(icon, TRUE); + + bool bRestoreLastWindowType = (m_s->fRememberWindowSize || m_s->fRememberWindowPos) && !m_s->fLastFullScreen && !m_s->fLaunchfullscreen; + bool bMinimized = (m_s->nCLSwitches & CLSW_MINIMIZED) || (bRestoreLastWindowType && m_s->nLastWindowType == SIZE_MINIMIZED); + bool bMaximized = bRestoreLastWindowType && m_s->nLastWindowType == SIZE_MAXIMIZED; + + if (bMinimized) { + m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWMINNOACTIVE : SW_SHOWMINIMIZED; + } else if (bMaximized) { + // Show maximized without focus is not supported nor make sense. + m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWNOACTIVATE : SW_SHOWMAXIMIZED; + } else { + m_nCmdShow = (m_s->nCLSwitches & CLSW_NOFOCUS) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL; + } + + pFrame->ActivateFrame(m_nCmdShow); + + if (AfxGetAppSettings().HasFixedWindowSize() && IsWindows8OrGreater()) {//make adjustments for drop shadow frame + CRect rect, frame; + pFrame->GetWindowRect(&rect); + CRect diff = pFrame->GetInvisibleBorderSize(); + if (!diff.IsRectNull()) { + rect.InflateRect(diff); + pFrame->SetWindowPos(nullptr, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER | SWP_NOACTIVATE); + } + } + + /* adipose 2019-11-12: + LoadPlayList this used to be performed inside OnCreate, + but due to all toolbars being hidden, EnsureVisible does not correctly + scroll to the current file in the playlist. We call after activating + the frame to fix this issue. + */ + pFrame->m_wndPlaylistBar.LoadPlaylist(pFrame->GetRecentFile()); + + pFrame->UpdateWindow(); + + + if (bMinimized && bMaximized) { + WINDOWPLACEMENT wp; + GetWindowPlacement(*pFrame, &wp); + wp.flags = WPF_RESTORETOMAXIMIZED; + SetWindowPlacement(*pFrame, &wp); + } + + pFrame->m_hAccelTable = m_s->hAccel; + m_s->WinLircClient.SetHWND(m_pMainWnd->m_hWnd); + if (m_s->fWinLirc) { + m_s->WinLircClient.Connect(m_s->strWinLircAddr); + } + m_s->UIceClient.SetHWND(m_pMainWnd->m_hWnd); + if (m_s->fUIce) { + m_s->UIceClient.Connect(m_s->strUIceAddr); + } + + if (UpdateChecker::IsAutoUpdateEnabled()) { + UpdateChecker::CheckForUpdate(true); + } + + if (!m_pMainWnd) return false; + + SendCommandLine(m_pMainWnd->m_hWnd); + RegisterHotkeys(); + + // set HIGH I/O Priority for better playback performance + if (m_hNTDLL) { + typedef NTSTATUS(WINAPI * FUNC_NTSETINFORMATIONPROCESS)(HANDLE, ULONG, PVOID, ULONG); + FUNC_NTSETINFORMATIONPROCESS NtSetInformationProcess = (FUNC_NTSETINFORMATIONPROCESS)GetProcAddress(m_hNTDLL, "NtSetInformationProcess"); + + if (NtSetInformationProcess && SetPrivilege(SE_INC_BASE_PRIORITY_NAME)) { + ULONG IoPriority = 3; + ULONG ProcessIoPriority = 0x21; + NTSTATUS NtStatus = NtSetInformationProcess(GetCurrentProcess(), ProcessIoPriority, &IoPriority, sizeof(ULONG)); + TRACE(_T("Set I/O Priority - %d\n"), NtStatus); + UNREFERENCED_PARAMETER(NtStatus); + } + } + + m_mutexOneInstance.Release(); + + CWebServer::Init(); + + if (m_s->fAssociatedWithIcons) { + m_s->fileAssoc.CheckIconsAssoc(); + } + + return TRUE; +} + +UINT CMPlayerCApp::GetRemoteControlCodeMicrosoft(UINT nInputcode, HRAWINPUT hRawInput) +{ + UINT dwSize = 0; + UINT nMceCmd = 0; + + // Support for MCE remote control + UINT ret = GetRawInputData(hRawInput, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); + if (ret == 0 && dwSize > 0) { + BYTE* pRawBuffer = DEBUG_NEW BYTE[dwSize]; + if (GetRawInputData(hRawInput, RID_INPUT, pRawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) != -1) { + RAWINPUT* raw = (RAWINPUT*)pRawBuffer; + if (raw->header.dwType == RIM_TYPEHID && raw->data.hid.dwSizeHid >= 3) { + nMceCmd = 0x10000 + (raw->data.hid.bRawData[1] | raw->data.hid.bRawData[2] << 8); + } + } + delete [] pRawBuffer; + } + + return nMceCmd; +} + +UINT CMPlayerCApp::GetRemoteControlCodeSRM7500(UINT nInputcode, HRAWINPUT hRawInput) +{ + UINT dwSize = 0; + UINT nMceCmd = 0; + + UINT ret = GetRawInputData(hRawInput, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER)); + if (ret == 0 && dwSize > 21) { + BYTE* pRawBuffer = DEBUG_NEW BYTE[dwSize]; + if (GetRawInputData(hRawInput, RID_INPUT, pRawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) != -1) { + RAWINPUT* raw = (RAWINPUT*)pRawBuffer; + + // data.hid.bRawData[21] set to one when key is pressed + if (raw->header.dwType == RIM_TYPEHID && raw->data.hid.dwSizeHid >= 22 && raw->data.hid.bRawData[21] == 1) { + // data.hid.bRawData[21] has keycode + switch (raw->data.hid.bRawData[20]) { + case 0x0033: + nMceCmd = MCE_DETAILS; + break; + case 0x0022: + nMceCmd = MCE_GUIDE; + break; + case 0x0036: + nMceCmd = MCE_MYTV; + break; + case 0x0026: + nMceCmd = MCE_RECORDEDTV; + break; + case 0x0005: + nMceCmd = MCE_RED; + break; + case 0x0002: + nMceCmd = MCE_GREEN; + break; + case 0x0045: + nMceCmd = MCE_YELLOW; + break; + case 0x0046: + nMceCmd = MCE_BLUE; + break; + case 0x000A: + nMceCmd = MCE_MEDIA_PREVIOUSTRACK; + break; + case 0x004A: + nMceCmd = MCE_MEDIA_NEXTTRACK; + break; + } + } + } + delete [] pRawBuffer; + } + + return nMceCmd; +} + +void CMPlayerCApp::RegisterHotkeys() +{ + CAutoVectorPtr inputDeviceList; + UINT nInputDeviceCount = 0, nErrCode; + RID_DEVICE_INFO deviceInfo; + RAWINPUTDEVICE MCEInputDevice[] = { + // usUsagePage usUsage dwFlags hwndTarget + { 0xFFBC, 0x88, 0, nullptr}, + { 0x000C, 0x01, 0, nullptr}, + { 0x000C, 0x80, 0, nullptr} + }; + + // Register MCE Remote Control raw input + for (unsigned int i = 0; i < _countof(MCEInputDevice); i++) { + MCEInputDevice[i].hwndTarget = m_pMainWnd->m_hWnd; + } + + // Get the size of the device list + nErrCode = GetRawInputDeviceList(nullptr, &nInputDeviceCount, sizeof(RAWINPUTDEVICELIST)); + inputDeviceList.Attach(DEBUG_NEW RAWINPUTDEVICELIST[nInputDeviceCount]); + if (nErrCode == UINT(-1) || !nInputDeviceCount || !inputDeviceList) { + ASSERT(nErrCode != UINT(-1)); + return; + } + + nErrCode = GetRawInputDeviceList(inputDeviceList, &nInputDeviceCount, sizeof(RAWINPUTDEVICELIST)); + if (nErrCode == UINT(-1)) { + ASSERT(FALSE); + return; + } + + for (UINT i = 0; i < nInputDeviceCount; i++) { + UINT nTemp = deviceInfo.cbSize = sizeof(deviceInfo); + + if (GetRawInputDeviceInfo(inputDeviceList[i].hDevice, RIDI_DEVICEINFO, &deviceInfo, &nTemp) > 0) { + if (deviceInfo.hid.dwVendorId == 0x00000471 && // Philips HID vendor id + deviceInfo.hid.dwProductId == 0x00000617) { // IEEE802.15.4 RF Dongle (SRM 7500) + MCEInputDevice[0].usUsagePage = deviceInfo.hid.usUsagePage; + MCEInputDevice[0].usUsage = deviceInfo.hid.usUsage; + GetRemoteControlCode = GetRemoteControlCodeSRM7500; + } + } + } + + RegisterRawInputDevices(MCEInputDevice, _countof(MCEInputDevice), sizeof(RAWINPUTDEVICE)); + + if (m_s->fGlobalMedia) { + POSITION pos = m_s->wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = m_s->wmcmds.GetNext(pos); + if (wc.appcmd != 0) { + UINT vkappcmd = GetVKFromAppCommand(wc.appcmd); + if (vkappcmd > 0) { + RegisterHotKey(m_pMainWnd->m_hWnd, wc.appcmd, 0, vkappcmd); + } + } + } + } +} + +void CMPlayerCApp::UnregisterHotkeys() +{ + if (m_s->fGlobalMedia) { + POSITION pos = m_s->wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = m_s->wmcmds.GetNext(pos); + if (wc.appcmd != 0) { + UnregisterHotKey(m_pMainWnd->m_hWnd, wc.appcmd); + } + } + } +} + +UINT CMPlayerCApp::GetVKFromAppCommand(UINT nAppCommand) +{ + // Note: Only a subset of AppCommands have a VirtualKey + switch (nAppCommand) { + case APPCOMMAND_MEDIA_PLAY_PAUSE: + return VK_MEDIA_PLAY_PAUSE; + case APPCOMMAND_MEDIA_STOP: + return VK_MEDIA_STOP; + case APPCOMMAND_MEDIA_NEXTTRACK: + return VK_MEDIA_NEXT_TRACK; + case APPCOMMAND_MEDIA_PREVIOUSTRACK: + return VK_MEDIA_PREV_TRACK; + case APPCOMMAND_VOLUME_DOWN: + return VK_VOLUME_DOWN; + case APPCOMMAND_VOLUME_UP: + return VK_VOLUME_UP; + case APPCOMMAND_VOLUME_MUTE: + return VK_VOLUME_MUTE; + case APPCOMMAND_LAUNCH_MEDIA_SELECT: + return VK_LAUNCH_MEDIA_SELECT; + case APPCOMMAND_BROWSER_BACKWARD: + return VK_BROWSER_BACK; + case APPCOMMAND_BROWSER_FORWARD: + return VK_BROWSER_FORWARD; + case APPCOMMAND_BROWSER_REFRESH: + return VK_BROWSER_REFRESH; + case APPCOMMAND_BROWSER_STOP: + return VK_BROWSER_STOP; + case APPCOMMAND_BROWSER_SEARCH: + return VK_BROWSER_SEARCH; + case APPCOMMAND_BROWSER_FAVORITES: + return VK_BROWSER_FAVORITES; + case APPCOMMAND_BROWSER_HOME: + return VK_BROWSER_HOME; + case APPCOMMAND_LAUNCH_APP1: + return VK_LAUNCH_APP1; + case APPCOMMAND_LAUNCH_APP2: + return VK_LAUNCH_APP2; + } + + return 0; +} + +int CMPlayerCApp::ExitInstance() +{ + // We might be exiting before m_s is initialized. + if (m_s) { + m_s->SaveSettings(); + m_s = nullptr; + } + + CMPCPngImage::CleanUp(); + + MH_Uninitialize(); + + OleUninitialize(); + + return CWinAppEx::ExitInstance(); +} + +BOOL CMPlayerCApp::SaveAllModified() +{ + // CWinApp::SaveAllModified + // Called by the framework to save all documents + // when the application's main frame window is to be closed, + // or through a WM_QUERYENDSESSION message. + if (m_s && !m_fClosingState) { + if (auto pMainFrame = AfxFindMainFrame()) { + if (pMainFrame->GetLoadState() != MLS::CLOSED) { + pMainFrame->CloseMedia(); + } + } + } + + return TRUE; +} + +// CMPlayerCApp message handlers + +BEGIN_MESSAGE_MAP(CMPlayerCApp, CWinAppEx) + ON_COMMAND(ID_HELP_ABOUT, OnAppAbout) + ON_COMMAND(ID_FILE_EXIT, OnFileExit) + ON_COMMAND(ID_HELP_SHOWCOMMANDLINESWITCHES, OnHelpShowcommandlineswitches) +END_MESSAGE_MAP() + +void CMPlayerCApp::OnAppAbout() +{ + CAboutDlg aboutDlg; + aboutDlg.DoModal(); +} + +void CMPlayerCApp::SetClosingState() +{ + m_fClosingState = true; +#if USE_DRDUMP_CRASH_REPORTER & (MPC_VERSION_REV < 20) + DisableCrashReporter(); +#endif +} + +void CMPlayerCApp::OnFileExit() +{ + OnAppExit(); +} + +void CMPlayerCApp::OnHelpShowcommandlineswitches() +{ + ShowCmdlnSwitches(); +} + +// CRemoteCtrlClient + +CRemoteCtrlClient::CRemoteCtrlClient() + : m_pWnd(nullptr) + , m_nStatus(DISCONNECTED) +{ +} + +void CRemoteCtrlClient::SetHWND(HWND hWnd) +{ + CAutoLock cAutoLock(&m_csLock); + + m_pWnd = CWnd::FromHandle(hWnd); +} + +void CRemoteCtrlClient::Connect(CString addr) +{ + CAutoLock cAutoLock(&m_csLock); + + if (m_nStatus == CONNECTING && m_addr == addr) { + TRACE(_T("CRemoteCtrlClient (Connect): already connecting to %s\n"), addr.GetString()); + return; + } + + if (m_nStatus == CONNECTED && m_addr == addr) { + TRACE(_T("CRemoteCtrlClient (Connect): already connected to %s\n"), addr.GetString()); + return; + } + + m_nStatus = CONNECTING; + + TRACE(_T("CRemoteCtrlClient (Connect): connecting to %s\n"), addr.GetString()); + + Close(); + + Create(); + + CString ip = addr.Left(addr.Find(':') + 1).TrimRight(':'); + int port = _tcstol(addr.Mid(addr.Find(':') + 1), nullptr, 10); + + __super::Connect(ip, port); + + m_addr = addr; +} + +void CRemoteCtrlClient::DisConnect() +{ + CAutoLock cAutoLock(&m_csLock); + + ShutDown(2); + Close(); +} + +void CRemoteCtrlClient::OnConnect(int nErrorCode) +{ + CAutoLock cAutoLock(&m_csLock); + + m_nStatus = (nErrorCode == 0 ? CONNECTED : DISCONNECTED); + + TRACE(_T("CRemoteCtrlClient (OnConnect): %d\n"), nErrorCode); +} + +void CRemoteCtrlClient::OnClose(int nErrorCode) +{ + CAutoLock cAutoLock(&m_csLock); + + if (m_hSocket != INVALID_SOCKET && m_nStatus == CONNECTED) { + TRACE(_T("CRemoteCtrlClient (OnClose): connection lost\n")); + } + + m_nStatus = DISCONNECTED; + + TRACE(_T("CRemoteCtrlClient (OnClose): %d\n"), nErrorCode); +} + +void CRemoteCtrlClient::OnReceive(int nErrorCode) +{ + if (nErrorCode != 0 || !m_pWnd) { + return; + } + + CStringA str; + int ret = Receive(str.GetBuffer(256), 255, 0); + if (ret <= 0) { + return; + } + str.ReleaseBuffer(ret); + + TRACE(_T("CRemoteCtrlClient (OnReceive): %S\n"), str.GetString()); + + OnCommand(str); + + __super::OnReceive(nErrorCode); +} + +void CRemoteCtrlClient::ExecuteCommand(CStringA cmd, int repcnt) +{ + cmd.Trim(); + if (cmd.IsEmpty()) { + return; + } + cmd.Replace(' ', '_'); + + const CAppSettings& s = AfxGetAppSettings(); + + POSITION pos = s.wmcmds.GetHeadPosition(); + while (pos) { + const wmcmd& wc = s.wmcmds.GetNext(pos); + if ((repcnt == 0 && wc.rmrepcnt == 0 || wc.rmrepcnt > 0 && (repcnt % wc.rmrepcnt) == 0) + && (wc.rmcmd.CompareNoCase(cmd) == 0 || wc.cmd == (WORD)strtol(cmd, nullptr, 10))) { + CAutoLock cAutoLock(&m_csLock); + TRACE(_T("CRemoteCtrlClient (calling command): %s\n"), wc.GetName().GetString()); + m_pWnd->SendMessage(WM_COMMAND, wc.cmd); + break; + } + } +} + +// CWinLircClient + +CWinLircClient::CWinLircClient() +{ +} + +void CWinLircClient::OnCommand(CStringA str) +{ + TRACE(_T("CWinLircClient (OnCommand): %S\n"), str.GetString()); + + int i = 0, j = 0, repcnt = 0; + for (CStringA token = str.Tokenize(" ", i); + !token.IsEmpty(); + token = str.Tokenize(" ", i), j++) { + if (j == 1) { + repcnt = strtol(token, nullptr, 16); + } else if (j == 2) { + ExecuteCommand(token, repcnt); + } + } +} + +// CUIceClient + +CUIceClient::CUIceClient() +{ +} + +void CUIceClient::OnCommand(CStringA str) +{ + TRACE(_T("CUIceClient (OnCommand): %S\n"), str.GetString()); + + CStringA cmd; + int i = 0, j = 0; + for (CStringA token = str.Tokenize("|", i); + !token.IsEmpty(); + token = str.Tokenize("|", i), j++) { + if (j == 0) { + cmd = token; + } else if (j == 1) { + ExecuteCommand(cmd, strtol(token, nullptr, 16)); + } + } +} + +// CMPlayerCApp continuation + +COLORPROPERTY_RANGE* CMPlayerCApp::GetColorControl(ControlType nFlag) +{ + switch (nFlag) { + case ProcAmp_Brightness: + return &m_ColorControl[0]; + case ProcAmp_Contrast: + return &m_ColorControl[1]; + case ProcAmp_Hue: + return &m_ColorControl[2]; + case ProcAmp_Saturation: + return &m_ColorControl[3]; + } + return nullptr; +} + +void CMPlayerCApp::ResetColorControlRange() +{ + m_ColorControl[0].dwProperty = ProcAmp_Brightness; + m_ColorControl[0].MinValue = -100; + m_ColorControl[0].MaxValue = 100; + m_ColorControl[0].DefaultValue = 0; + m_ColorControl[0].StepSize = 1; + m_ColorControl[1].dwProperty = ProcAmp_Contrast; + m_ColorControl[1].MinValue = -100; + m_ColorControl[1].MaxValue = 100; + m_ColorControl[1].DefaultValue = 0; + m_ColorControl[1].StepSize = 1; + m_ColorControl[2].dwProperty = ProcAmp_Hue; + m_ColorControl[2].MinValue = -180; + m_ColorControl[2].MaxValue = 180; + m_ColorControl[2].DefaultValue = 0; + m_ColorControl[2].StepSize = 1; + m_ColorControl[3].dwProperty = ProcAmp_Saturation; + m_ColorControl[3].MinValue = -100; + m_ColorControl[3].MaxValue = 100; + m_ColorControl[3].DefaultValue = 0; + m_ColorControl[3].StepSize = 1; +} + +void CMPlayerCApp::UpdateColorControlRange(bool isEVR) +{ + if (isEVR) { + // Brightness + m_ColorControl[0].MinValue = FixedToInt(m_EVRColorControl[0].MinValue); + m_ColorControl[0].MaxValue = FixedToInt(m_EVRColorControl[0].MaxValue); + m_ColorControl[0].DefaultValue = FixedToInt(m_EVRColorControl[0].DefaultValue); + m_ColorControl[0].StepSize = std::max(1, FixedToInt(m_EVRColorControl[0].StepSize)); + // Contrast + m_ColorControl[1].MinValue = FixedToInt(m_EVRColorControl[1].MinValue, 100) - 100; + m_ColorControl[1].MaxValue = FixedToInt(m_EVRColorControl[1].MaxValue, 100) - 100; + m_ColorControl[1].DefaultValue = FixedToInt(m_EVRColorControl[1].DefaultValue, 100) - 100; + m_ColorControl[1].StepSize = std::max(1, FixedToInt(m_EVRColorControl[1].StepSize, 100)); + // Hue + m_ColorControl[2].MinValue = FixedToInt(m_EVRColorControl[2].MinValue); + m_ColorControl[2].MaxValue = FixedToInt(m_EVRColorControl[2].MaxValue); + m_ColorControl[2].DefaultValue = FixedToInt(m_EVRColorControl[2].DefaultValue); + m_ColorControl[2].StepSize = std::max(1, FixedToInt(m_EVRColorControl[2].StepSize)); + // Saturation + m_ColorControl[3].MinValue = FixedToInt(m_EVRColorControl[3].MinValue, 100) - 100; + m_ColorControl[3].MaxValue = FixedToInt(m_EVRColorControl[3].MaxValue, 100) - 100; + m_ColorControl[3].DefaultValue = FixedToInt(m_EVRColorControl[3].DefaultValue, 100) - 100; + m_ColorControl[3].StepSize = std::max(1, FixedToInt(m_EVRColorControl[3].StepSize, 100)); + } else { + // Brightness + m_ColorControl[0].MinValue = (int)floor(m_VMR9ColorControl[0].MinValue + 0.5); + m_ColorControl[0].MaxValue = (int)floor(m_VMR9ColorControl[0].MaxValue + 0.5); + m_ColorControl[0].DefaultValue = (int)floor(m_VMR9ColorControl[0].DefaultValue + 0.5); + m_ColorControl[0].StepSize = std::max(1, (int)(m_VMR9ColorControl[0].StepSize + 0.5)); + // Contrast + if (*(int*)&m_VMR9ColorControl[1].MinValue == 1036830720) { + m_VMR9ColorControl[1].MinValue = 0.11f; //fix NVIDIA bug + } + m_ColorControl[1].MinValue = (int)floor(m_VMR9ColorControl[1].MinValue * 100 + 0.5) - 100; + m_ColorControl[1].MaxValue = (int)floor(m_VMR9ColorControl[1].MaxValue * 100 + 0.5) - 100; + m_ColorControl[1].DefaultValue = (int)floor(m_VMR9ColorControl[1].DefaultValue * 100 + 0.5) - 100; + m_ColorControl[1].StepSize = std::max(1, (int)(m_VMR9ColorControl[1].StepSize * 100 + 0.5)); + // Hue + m_ColorControl[2].MinValue = (int)floor(m_VMR9ColorControl[2].MinValue + 0.5); + m_ColorControl[2].MaxValue = (int)floor(m_VMR9ColorControl[2].MaxValue + 0.5); + m_ColorControl[2].DefaultValue = (int)floor(m_VMR9ColorControl[2].DefaultValue + 0.5); + m_ColorControl[2].StepSize = std::max(1, (int)(m_VMR9ColorControl[2].StepSize + 0.5)); + // Saturation + m_ColorControl[3].MinValue = (int)floor(m_VMR9ColorControl[3].MinValue * 100 + 0.5) - 100; + m_ColorControl[3].MaxValue = (int)floor(m_VMR9ColorControl[3].MaxValue * 100 + 0.5) - 100; + m_ColorControl[3].DefaultValue = (int)floor(m_VMR9ColorControl[3].DefaultValue * 100 + 0.5) - 100; + m_ColorControl[3].StepSize = std::max(1, (int)(m_VMR9ColorControl[3].StepSize * 100 + 0.5)); + } + + // Brightness + if (m_ColorControl[0].MinValue < -100) { + m_ColorControl[0].MinValue = -100; + } + if (m_ColorControl[0].MaxValue > 100) { + m_ColorControl[0].MaxValue = 100; + } + // Contrast + if (m_ColorControl[1].MinValue == m_ColorControl[1].MaxValue) { // when ProcAmp is unsupported + m_ColorControl[1].MinValue = m_ColorControl[1].MaxValue = m_ColorControl[1].DefaultValue = 0; + } + if (m_ColorControl[1].MinValue < -100) { + m_ColorControl[1].MinValue = -100; + } + if (m_ColorControl[1].MaxValue > 100) { + m_ColorControl[1].MaxValue = 100; + } + // Hue + if (m_ColorControl[2].MinValue < -180) { + m_ColorControl[2].MinValue = -180; + } + if (m_ColorControl[2].MaxValue > 180) { + m_ColorControl[2].MaxValue = 180; + } + // Saturation + if (m_ColorControl[3].MinValue == m_ColorControl[3].MaxValue) { // when ProcAmp is unsupported + m_ColorControl[3].MinValue = m_ColorControl[3].MaxValue = m_ColorControl[3].DefaultValue = 0; + } + if (m_ColorControl[3].MinValue < -100) { + m_ColorControl[3].MinValue = -100; + } + if (m_ColorControl[3].MaxValue > 100) { + m_ColorControl[3].MaxValue = 100; + } +} + +VMR9ProcAmpControlRange* CMPlayerCApp::GetVMR9ColorControl(ControlType nFlag) +{ + switch (nFlag) { + case ProcAmp_Brightness: + return &m_VMR9ColorControl[0]; + case ProcAmp_Contrast: + return &m_VMR9ColorControl[1]; + case ProcAmp_Hue: + return &m_VMR9ColorControl[2]; + case ProcAmp_Saturation: + return &m_VMR9ColorControl[3]; + } + return nullptr; +} + +DXVA2_ValueRange* CMPlayerCApp::GetEVRColorControl(ControlType nFlag) +{ + switch (nFlag) { + case ProcAmp_Brightness: + return &m_EVRColorControl[0]; + case ProcAmp_Contrast: + return &m_EVRColorControl[1]; + case ProcAmp_Hue: + return &m_EVRColorControl[2]; + case ProcAmp_Saturation: + return &m_EVRColorControl[3]; + } + return nullptr; +} + +void CMPlayerCApp::RunAsAdministrator(LPCTSTR strCommand, LPCTSTR strArgs, bool bWaitProcess) +{ + SHELLEXECUTEINFO execinfo; + ZeroMemory(&execinfo, sizeof(execinfo)); + execinfo.lpFile = strCommand; + execinfo.cbSize = sizeof(execinfo); + execinfo.lpVerb = _T("runas"); + execinfo.fMask = SEE_MASK_NOCLOSEPROCESS; + execinfo.nShow = SW_SHOWDEFAULT; + execinfo.lpParameters = strArgs; + + ShellExecuteEx(&execinfo); + + if (bWaitProcess) { + WaitForSingleObject(execinfo.hProcess, INFINITE); + } +} + diff --git a/src/mpc-hc/mplayerc.h b/src/mpc-hc/mplayerc.h index 30bb8e671fc..8ec7937dc75 100644 --- a/src/mpc-hc/mplayerc.h +++ b/src/mpc-hc/mplayerc.h @@ -1,234 +1,234 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2017 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 . - * - */ - -#pragma once - -#ifndef __AFXWIN_H__ -#error include 'stdafx.h' before including this file for PCH -#endif - -#include "EventDispatcher.h" -#include "DpiHelper.h" -#include "AppSettings.h" -#include "../filters/renderer/VideoRenderers/RenderersSettings.h" -#include "resource.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#define MPC_WND_CLASS_NAME L"MediaPlayerClassicW" - -// define the default logo we use -#define DEF_LOGO IDF_LOGO3 - -#define MIN_MODERN_SEEKBAR_HEIGHT 8 -#define DEF_MODERN_SEEKBAR_HEIGHT 16 -#define MAX_MODERN_SEEKBAR_HEIGHT 64 - -#define MIN_TOOLBAR_HEIGHT 16 -#define DEF_TOOLBAR_HEIGHT 24 -#define MAX_TOOLBAR_HEIGHT 128 - - -#define MIN_FULLSCREEN_DELAY 0 -#define MAX_FULLSCREEN_DELAY 500 -#define MAX_REGKEY_LEN 255 - -extern HICON LoadIcon(CString fn, bool bSmallIcon, DpiHelper* pDpiHelper = nullptr); -extern bool LoadType(CString fn, CString& type); -extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); -extern CString GetContentType(CString fn, CAtlList* redir = nullptr); -extern WORD AssignedToCmd(UINT keyValue); -extern std::map GetAudioDeviceList(); -extern void SetAudioRenderer(int AudioDevNo); -extern void SetHandCursor(HWND m_hWnd, UINT nID); - -__inline DXVA2_Fixed32 IntToFixed(__in const int _int_, __in const short divisor = 1) -{ - // special converter that is resistant to MS bugs - DXVA2_Fixed32 _fixed_; - _fixed_.Value = SHORT(_int_ / divisor); - _fixed_.Fraction = USHORT((_int_ % divisor * 0x10000 + divisor / 2) / divisor); - return _fixed_; -} - -__inline int FixedToInt(__in const DXVA2_Fixed32& _fixed_, __in const short factor = 1) -{ - // special converter that is resistant to MS bugs - return (int)_fixed_.Value * factor + ((int)_fixed_.Fraction * factor + 0x8000) / 0x10000; -} - -enum { - WM_GRAPHNOTIFY = WM_RESET_DEVICE + 1, - WM_POSTOPEN, - WM_OPENFAILED, - WM_SAVESETTINGS, - WM_TUNER_SCAN_PROGRESS, - WM_TUNER_SCAN_END, - WM_TUNER_STATS, - WM_TUNER_NEW_CHANNEL, - WM_DVB_EIT_DATA_READY, - WM_LOADSUBTITLES, - WM_GETSUBTITLES, - WM_OSD_HIDE, - WM_OSD_DRAW, - WM_MPCVR_SWITCH_FULLSCREEN = WM_APP + 4096, -}; - -enum ControlType { - ProcAmp_Brightness = 0x1, - ProcAmp_Contrast = 0x2, - ProcAmp_Hue = 0x4, - ProcAmp_Saturation = 0x8, - ProcAmp_All = ProcAmp_Brightness | ProcAmp_Contrast | ProcAmp_Hue | ProcAmp_Saturation -}; - -struct COLORPROPERTY_RANGE { - DWORD dwProperty; - int MinValue; - int MaxValue; - int DefaultValue; - int StepSize; -}; - -class CAppSettings; - -class CMPlayerCApp : public CWinAppEx -{ - HMODULE m_hNTDLL; - - ATL::CMutex m_mutexOneInstance; - - CAtlList m_cmdln; - void PreProcessCommandLine(); - bool SendCommandLine(HWND hWnd); - UINT GetVKFromAppCommand(UINT nAppCommand); - - COLORPROPERTY_RANGE m_ColorControl[4]; - VMR9ProcAmpControlRange m_VMR9ColorControl[4]; - DXVA2_ValueRange m_EVRColorControl[4]; - - static UINT GetRemoteControlCodeMicrosoft(UINT nInputcode, HRAWINPUT hRawInput); - static UINT GetRemoteControlCodeSRM7500(UINT nInputcode, HRAWINPUT hRawInput); - - bool m_bDelayingIdle; - void DelayedIdle(); - virtual BOOL IsIdleMessage(MSG* pMsg) override; - virtual BOOL OnIdle(LONG lCount) override; - virtual BOOL PumpMessage() override; - -public: - CMPlayerCApp(); - ~CMPlayerCApp(); - - int DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT nIDPrompt); - - EventRouter m_eventd; - - void ShowCmdlnSwitches() const; - - bool StoreSettingsToIni(); - bool StoreSettingsToRegistry(); - CString GetIniPath() const; - bool IsIniValid() const; - bool ChangeSettingsLocation(bool useIni); - bool ExportSettings(CString savePath, CString subKey = _T("")); - -private: - std::map, CStringUtils::IgnoreCaseLess> m_ProfileMap; - bool m_bProfileInitialized; - bool m_bQueuedProfileFlush; - void InitProfile(); - std::recursive_mutex m_profileMutex; - ULONGLONG m_dwProfileLastAccessTick; - -public: - void FlushProfile(bool bForce = true); - virtual BOOL GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes) override; - virtual UINT GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) override; - - std::list GetSectionSubKeys(LPCWSTR lpszSection); - virtual CString GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = nullptr) override; - virtual BOOL WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes) override; - virtual LONG RemoveProfileKey(LPCWSTR lpszSection, LPCWSTR lpszEntry); - virtual BOOL WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) override; - virtual BOOL WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) override; - bool HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry); - std::vector GetProfileVectorInt(CString strSection, CString strKey); - void WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData); - - bool GetAppSavePath(CString& path); - bool GetAppDataPath(CString& path); - - bool m_fClosingState; - bool m_bThemeLoaded; - CRenderersData m_Renderers; - CString m_strVersion; - CString m_AudioRendererDisplayName_CL; - - std::unique_ptr m_s; - - typedef UINT(*PTR_GetRemoteControlCode)(UINT nInputcode, HRAWINPUT hRawInput); - - PTR_GetRemoteControlCode GetRemoteControlCode; - COLORPROPERTY_RANGE* GetColorControl(ControlType nFlag); - void ResetColorControlRange(); - void UpdateColorControlRange(bool isEVR); - VMR9ProcAmpControlRange* GetVMR9ColorControl(ControlType nFlag); - DXVA2_ValueRange* GetEVRColorControl(ControlType nFlag); - - static void RunAsAdministrator(LPCTSTR strCommand, LPCTSTR strArgs, bool bWaitProcess); - - void RegisterHotkeys(); - void UnregisterHotkeys(); - -public: - virtual BOOL InitInstance() override; - virtual int ExitInstance() override; - virtual BOOL SaveAllModified() override; - -public: - void SetClosingState(); - -public: - DECLARE_MESSAGE_MAP() - afx_msg void OnAppAbout(); - afx_msg void OnFileExit(); - afx_msg void OnHelpShowcommandlineswitches(); -}; - -#define AfxGetAppSettings() (*static_cast(AfxGetApp())->m_s.get()) -#define AfxGetMyApp() static_cast(AfxGetApp()) - -#define GetEventd() AfxGetMyApp()->m_eventd - -#define AppIsThemeLoaded() (static_cast(AfxGetApp())->m_bThemeLoaded) -#define AppNeedsThemedControls() (AppIsThemeLoaded() && CMPCTheme::drawThemedControls) - -#define AfxGetMainFrame() static_cast(AfxGetMainWnd()) -#define AfxFindMainFrame() dynamic_cast(AfxGetMainWnd()) +/* + * (C) 2003-2006 Gabest + * (C) 2006-2017 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 . + * + */ + +#pragma once + +#ifndef __AFXWIN_H__ +#error include 'stdafx.h' before including this file for PCH +#endif + +#include "EventDispatcher.h" +#include "DpiHelper.h" +#include "AppSettings.h" +#include "../filters/renderer/VideoRenderers/RenderersSettings.h" +#include "resource.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MPC_WND_CLASS_NAME L"MediaPlayerClassicW" + +// define the default logo we use +#define DEF_LOGO IDF_LOGO3 + +#define MIN_MODERN_SEEKBAR_HEIGHT 8 +#define DEF_MODERN_SEEKBAR_HEIGHT 16 +#define MAX_MODERN_SEEKBAR_HEIGHT 64 + +#define MIN_TOOLBAR_HEIGHT 16 +#define DEF_TOOLBAR_HEIGHT 24 +#define MAX_TOOLBAR_HEIGHT 128 + + +#define MIN_FULLSCREEN_DELAY 0 +#define MAX_FULLSCREEN_DELAY 500 +#define MAX_REGKEY_LEN 255 + +extern HICON LoadIcon(CString fn, bool bSmallIcon, DpiHelper* pDpiHelper = nullptr); +extern bool LoadType(CString fn, CString& type); +extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype); +extern CString GetContentType(CString fn, CAtlList* redir = nullptr); +extern WORD AssignedToCmd(UINT keyValue); +extern std::map GetAudioDeviceList(); +extern void SetAudioRenderer(int AudioDevNo); +extern void SetHandCursor(HWND m_hWnd, UINT nID); + +__inline DXVA2_Fixed32 IntToFixed(__in const int _int_, __in const short divisor = 1) +{ + // special converter that is resistant to MS bugs + DXVA2_Fixed32 _fixed_; + _fixed_.Value = SHORT(_int_ / divisor); + _fixed_.Fraction = USHORT((_int_ % divisor * 0x10000 + divisor / 2) / divisor); + return _fixed_; +} + +__inline int FixedToInt(__in const DXVA2_Fixed32& _fixed_, __in const short factor = 1) +{ + // special converter that is resistant to MS bugs + return (int)_fixed_.Value * factor + ((int)_fixed_.Fraction * factor + 0x8000) / 0x10000; +} + +enum { + WM_GRAPHNOTIFY = WM_RESET_DEVICE + 1, + WM_POSTOPEN, + WM_OPENFAILED, + WM_SAVESETTINGS, + WM_TUNER_SCAN_PROGRESS, + WM_TUNER_SCAN_END, + WM_TUNER_STATS, + WM_TUNER_NEW_CHANNEL, + WM_DVB_EIT_DATA_READY, + WM_LOADSUBTITLES, + WM_GETSUBTITLES, + WM_OSD_HIDE, + WM_OSD_DRAW, + WM_MPCVR_SWITCH_FULLSCREEN = WM_APP + 4096, +}; + +enum ControlType { + ProcAmp_Brightness = 0x1, + ProcAmp_Contrast = 0x2, + ProcAmp_Hue = 0x4, + ProcAmp_Saturation = 0x8, + ProcAmp_All = ProcAmp_Brightness | ProcAmp_Contrast | ProcAmp_Hue | ProcAmp_Saturation +}; + +struct COLORPROPERTY_RANGE { + DWORD dwProperty; + int MinValue; + int MaxValue; + int DefaultValue; + int StepSize; +}; + +class CAppSettings; + +class CMPlayerCApp : public CWinAppEx +{ + HMODULE m_hNTDLL; + + ATL::CMutex m_mutexOneInstance; + + CAtlList m_cmdln; + void PreProcessCommandLine(); + bool SendCommandLine(HWND hWnd); + UINT GetVKFromAppCommand(UINT nAppCommand); + + COLORPROPERTY_RANGE m_ColorControl[4]; + VMR9ProcAmpControlRange m_VMR9ColorControl[4]; + DXVA2_ValueRange m_EVRColorControl[4]; + + static UINT GetRemoteControlCodeMicrosoft(UINT nInputcode, HRAWINPUT hRawInput); + static UINT GetRemoteControlCodeSRM7500(UINT nInputcode, HRAWINPUT hRawInput); + + bool m_bDelayingIdle; + void DelayedIdle(); + virtual BOOL IsIdleMessage(MSG* pMsg) override; + virtual BOOL OnIdle(LONG lCount) override; + virtual BOOL PumpMessage() override; + +public: + CMPlayerCApp(); + ~CMPlayerCApp(); + + int DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT nIDPrompt); + + EventRouter m_eventd; + + void ShowCmdlnSwitches() const; + + bool StoreSettingsToIni(); + bool StoreSettingsToRegistry(); + CString GetIniPath() const; + bool IsIniValid() const; + bool ChangeSettingsLocation(bool useIni); + bool ExportSettings(CString savePath, CString subKey = _T("")); + +private: + std::map, CStringUtils::IgnoreCaseLess> m_ProfileMap; + bool m_bProfileInitialized; + bool m_bQueuedProfileFlush; + void InitProfile(); + std::recursive_mutex m_profileMutex; + ULONGLONG m_dwProfileLastAccessTick; + +public: + void FlushProfile(bool bForce = true); + virtual BOOL GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes) override; + virtual UINT GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) override; + + std::list GetSectionSubKeys(LPCWSTR lpszSection); + virtual CString GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = nullptr) override; + virtual BOOL WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes) override; + virtual LONG RemoveProfileKey(LPCWSTR lpszSection, LPCWSTR lpszEntry); + virtual BOOL WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) override; + virtual BOOL WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) override; + bool HasProfileEntry(LPCTSTR lpszSection, LPCTSTR lpszEntry); + std::vector GetProfileVectorInt(CString strSection, CString strKey); + void WriteProfileVectorInt(CString strSection, CString strKey, std::vector vData); + + bool GetAppSavePath(CString& path); + bool GetAppDataPath(CString& path); + + bool m_fClosingState; + bool m_bThemeLoaded; + CRenderersData m_Renderers; + CString m_strVersion; + CString m_AudioRendererDisplayName_CL; + + std::unique_ptr m_s; + + typedef UINT(*PTR_GetRemoteControlCode)(UINT nInputcode, HRAWINPUT hRawInput); + + PTR_GetRemoteControlCode GetRemoteControlCode; + COLORPROPERTY_RANGE* GetColorControl(ControlType nFlag); + void ResetColorControlRange(); + void UpdateColorControlRange(bool isEVR); + VMR9ProcAmpControlRange* GetVMR9ColorControl(ControlType nFlag); + DXVA2_ValueRange* GetEVRColorControl(ControlType nFlag); + + static void RunAsAdministrator(LPCTSTR strCommand, LPCTSTR strArgs, bool bWaitProcess); + + void RegisterHotkeys(); + void UnregisterHotkeys(); + +public: + virtual BOOL InitInstance() override; + virtual int ExitInstance() override; + virtual BOOL SaveAllModified() override; + +public: + void SetClosingState(); + +public: + DECLARE_MESSAGE_MAP() + afx_msg void OnAppAbout(); + afx_msg void OnFileExit(); + afx_msg void OnHelpShowcommandlineswitches(); +}; + +#define AfxGetAppSettings() (*static_cast(AfxGetApp())->m_s.get()) +#define AfxGetMyApp() static_cast(AfxGetApp()) + +#define GetEventd() AfxGetMyApp()->m_eventd + +#define AppIsThemeLoaded() (static_cast(AfxGetApp())->m_bThemeLoaded) +#define AppNeedsThemedControls() (AppIsThemeLoaded() && CMPCTheme::drawThemedControls) + +#define AfxGetMainFrame() static_cast(AfxGetMainWnd()) +#define AfxFindMainFrame() dynamic_cast(AfxGetMainWnd()) diff --git a/src/mpc-hc/res/mpc-hc.exe.manifest.conf b/src/mpc-hc/res/mpc-hc.exe.manifest.conf index 80eb1e293ce..09930765368 100644 --- a/src/mpc-hc/res/mpc-hc.exe.manifest.conf +++ b/src/mpc-hc/res/mpc-hc.exe.manifest.conf @@ -1,45 +1,45 @@ - - - - MPC-HC - - - - - - - - - - - - - - - - - - - - - - - - True/PM - PerMonitorV2, PerMonitor - true - - + + + + MPC-HC + + + + + + + + + + + + + + + + + + + + + + + + True/PM + PerMonitorV2, PerMonitor + true + + \ No newline at end of file diff --git a/src/mpc-hc/res/shaders/empty.psh b/src/mpc-hc/res/shaders/empty.psh index 8578320e26e..dc2fa90b3e7 100644 --- a/src/mpc-hc/res/shaders/empty.psh +++ b/src/mpc-hc/res/shaders/empty.psh @@ -1,17 +1,17 @@ -sampler s0 : register(s0); -float4 p0 : register(c0); -float4 p1 : register(c1); - -#define width (p0[0]) -#define height (p0[1]) -#define counter (p0[2]) -#define clock (p0[3]) -#define one_over_width (p1[0]) -#define one_over_height (p1[1]) -#define PI acos(-1) - -float4 main(float2 tex : TEXCOORD0) : COLOR { - float4 c0 = tex2D(s0, tex); - - return c0; -} +sampler s0 : register(s0); +float4 p0 : register(c0); +float4 p1 : register(c1); + +#define width (p0[0]) +#define height (p0[1]) +#define counter (p0[2]) +#define clock (p0[3]) +#define one_over_width (p1[0]) +#define one_over_height (p1[1]) +#define PI acos(-1) + +float4 main(float2 tex : TEXCOORD0) : COLOR { + float4 c0 = tex2D(s0, tex); + + return c0; +} diff --git a/src/mpc-hc/res/shaders/final.psh b/src/mpc-hc/res/shaders/final.psh index 1070d4cac0d..c39b5078ea6 100644 --- a/src/mpc-hc/res/shaders/final.psh +++ b/src/mpc-hc/res/shaders/final.psh @@ -1,29 +1,29 @@ -#define LUT3D_ENABLED (_LUT3D_ENABLED_VALUE_) - -sampler image : register(s0); - -sampler ditherMatrix : register(s1); -float2 ditherMatrixCoordScale : register(c0); - -// Maximum quantized integer value -static const float QUANTIZATION = _QUANTIZATION_VALUE_; - -#if LUT3D_ENABLED -sampler lut3D : register(s2); -static const float LUT3D_SIZE = _LUT3D_SIZE_VALUE_; - -// 3D LUT texture coordinate scale and offset required for correct linear interpolation -static const float LUT3D_SCALE = (LUT3D_SIZE - 1.0f) / LUT3D_SIZE; -static const float LUT3D_OFFSET = 1.0f / (2.0f * LUT3D_SIZE); -#endif - -float4 main(float2 imageCoord : TEXCOORD0) : COLOR { - float4 pixel = tex2D(image, imageCoord); - -#if LUT3D_ENABLED - pixel = tex3D(lut3D, pixel.rgb * LUT3D_SCALE + LUT3D_OFFSET); -#endif - - float4 ditherValue = tex2D(ditherMatrix, imageCoord * ditherMatrixCoordScale); - return floor(pixel * QUANTIZATION + ditherValue) / QUANTIZATION; -} +#define LUT3D_ENABLED (_LUT3D_ENABLED_VALUE_) + +sampler image : register(s0); + +sampler ditherMatrix : register(s1); +float2 ditherMatrixCoordScale : register(c0); + +// Maximum quantized integer value +static const float QUANTIZATION = _QUANTIZATION_VALUE_; + +#if LUT3D_ENABLED +sampler lut3D : register(s2); +static const float LUT3D_SIZE = _LUT3D_SIZE_VALUE_; + +// 3D LUT texture coordinate scale and offset required for correct linear interpolation +static const float LUT3D_SCALE = (LUT3D_SIZE - 1.0f) / LUT3D_SIZE; +static const float LUT3D_OFFSET = 1.0f / (2.0f * LUT3D_SIZE); +#endif + +float4 main(float2 imageCoord : TEXCOORD0) : COLOR { + float4 pixel = tex2D(image, imageCoord); + +#if LUT3D_ENABLED + pixel = tex3D(lut3D, pixel.rgb * LUT3D_SCALE + LUT3D_OFFSET); +#endif + + float4 ditherValue = tex2D(ditherMatrix, imageCoord * ditherMatrixCoordScale); + return floor(pixel * QUANTIZATION + ditherValue) / QUANTIZATION; +} diff --git a/src/mpc-hc/res/shaders/resizer.psh b/src/mpc-hc/res/shaders/resizer.psh index 9a45f678dbf..180bce84cd0 100644 --- a/src/mpc-hc/res/shaders/resizer.psh +++ b/src/mpc-hc/res/shaders/resizer.psh @@ -1,115 +1,115 @@ -sampler s0 : register(s0); -sampler s1 : register(s1); -sampler s2 : register(s2); -sampler s3 : register(s3); -sampler s4 : register(s4); - -float4 dxdy05 : register(c0); -float2 dxdy : register(c1); -float2 dx : register(c2); -float2 dy : register(c3); - -#define A _The_Value_Of_A_Is_Set_Here_ - -// none of the resizers here can be used for 1:1 mapping! -// tex * size won't be 0, 1, 2, 3, ... as you might expect, but something like 0, 0.999, 2.001, 2.999, ... -// this means when the fractional part becomes 0.999 we will be interpolating with the wrong value!!! - -struct PS_INPUT { - float2 t0 : TEXCOORD0; - float2 t1 : TEXCOORD1; - float2 t2 : TEXCOORD2; - float2 t3 : TEXCOORD3; - float2 t4 : TEXCOORD4; -}; - -float4 main_bilinear(PS_INPUT input) : COLOR { - float2 PixelPos = input.t0; - float2 dd = frac(PixelPos); - float2 ExactPixel = PixelPos - dd; - float2 samplePos = ExactPixel * dxdy + dxdy05; - - float4 c = lerp( - lerp(tex2D(s0, samplePos), tex2D(s0, samplePos + dx), dd.x), - lerp(tex2D(s0, samplePos + dy), tex2D(s0, samplePos + dxdy), dd.x), - dd.y); - - return c; -} - -static float4x4 tco = { - 0, A, -2 * A, A, - 1, 0, -A - 3, A + 2, - 0, -A, 2 * A + 3, -A - 2, - 0, 0, A, -A -}; - -float4 taps(float t) -{ - return mul(tco, float4(1, t, t * t, t * t * t)); -} - -float4 SampleX(float4 tx, float2 t0) -{ - return - mul(tx, - float4x4( - tex2D(s0, t0 - dx), - tex2D(s0, t0), - tex2D(s0, t0 + dx), - tex2D(s0, t0 + dx + dx) - ) - ); -} - -float4 SampleY(float4 tx, float4 ty, float2 t0) -{ - return - mul(ty, - float4x4( - SampleX(tx, t0 - dy), - SampleX(tx, t0), - SampleX(tx, t0 + dy), - SampleX(tx, t0 + dy + dy) - ) - ); -} - -float4 main_bicubic1pass(PS_INPUT input) : COLOR { - float2 PixelPos = input.t0; - float2 dd = frac(PixelPos); - float2 ExactPixel = PixelPos - dd; - float2 samplePos = ExactPixel * dxdy + dxdy05; - return SampleY(taps(dd.x), taps(dd.y), samplePos); -} - -float4 Sample(float4 t, float2 samplePos, float2 sampleD) -{ - return - mul(t, - float4x4( - tex2D(s0, samplePos - sampleD), - tex2D(s0, samplePos), - tex2D(s0, samplePos + sampleD), - tex2D(s0, samplePos + sampleD + sampleD) - ) - ); -} - -float4 main_bicubic2pass_pass1(PS_INPUT input) : COLOR { - float2 PixelPos = input.t0; - float2 dd = frac(PixelPos); - float2 ExactPixel = PixelPos - dd; - float2 samplePos = ExactPixel * dxdy + dxdy05; - - return Sample(taps(dd.x), samplePos, dx); -} - -float4 main_bicubic2pass_pass2(PS_INPUT input) : COLOR { - float2 PixelPos = input.t0; - float2 dd = frac(PixelPos); - float2 ExactPixel = PixelPos - dd; - float2 samplePos = ExactPixel * dxdy + dxdy05; - - return Sample(taps(dd.y), samplePos, dy); -} +sampler s0 : register(s0); +sampler s1 : register(s1); +sampler s2 : register(s2); +sampler s3 : register(s3); +sampler s4 : register(s4); + +float4 dxdy05 : register(c0); +float2 dxdy : register(c1); +float2 dx : register(c2); +float2 dy : register(c3); + +#define A _The_Value_Of_A_Is_Set_Here_ + +// none of the resizers here can be used for 1:1 mapping! +// tex * size won't be 0, 1, 2, 3, ... as you might expect, but something like 0, 0.999, 2.001, 2.999, ... +// this means when the fractional part becomes 0.999 we will be interpolating with the wrong value!!! + +struct PS_INPUT { + float2 t0 : TEXCOORD0; + float2 t1 : TEXCOORD1; + float2 t2 : TEXCOORD2; + float2 t3 : TEXCOORD3; + float2 t4 : TEXCOORD4; +}; + +float4 main_bilinear(PS_INPUT input) : COLOR { + float2 PixelPos = input.t0; + float2 dd = frac(PixelPos); + float2 ExactPixel = PixelPos - dd; + float2 samplePos = ExactPixel * dxdy + dxdy05; + + float4 c = lerp( + lerp(tex2D(s0, samplePos), tex2D(s0, samplePos + dx), dd.x), + lerp(tex2D(s0, samplePos + dy), tex2D(s0, samplePos + dxdy), dd.x), + dd.y); + + return c; +} + +static float4x4 tco = { + 0, A, -2 * A, A, + 1, 0, -A - 3, A + 2, + 0, -A, 2 * A + 3, -A - 2, + 0, 0, A, -A +}; + +float4 taps(float t) +{ + return mul(tco, float4(1, t, t * t, t * t * t)); +} + +float4 SampleX(float4 tx, float2 t0) +{ + return + mul(tx, + float4x4( + tex2D(s0, t0 - dx), + tex2D(s0, t0), + tex2D(s0, t0 + dx), + tex2D(s0, t0 + dx + dx) + ) + ); +} + +float4 SampleY(float4 tx, float4 ty, float2 t0) +{ + return + mul(ty, + float4x4( + SampleX(tx, t0 - dy), + SampleX(tx, t0), + SampleX(tx, t0 + dy), + SampleX(tx, t0 + dy + dy) + ) + ); +} + +float4 main_bicubic1pass(PS_INPUT input) : COLOR { + float2 PixelPos = input.t0; + float2 dd = frac(PixelPos); + float2 ExactPixel = PixelPos - dd; + float2 samplePos = ExactPixel * dxdy + dxdy05; + return SampleY(taps(dd.x), taps(dd.y), samplePos); +} + +float4 Sample(float4 t, float2 samplePos, float2 sampleD) +{ + return + mul(t, + float4x4( + tex2D(s0, samplePos - sampleD), + tex2D(s0, samplePos), + tex2D(s0, samplePos + sampleD), + tex2D(s0, samplePos + sampleD + sampleD) + ) + ); +} + +float4 main_bicubic2pass_pass1(PS_INPUT input) : COLOR { + float2 PixelPos = input.t0; + float2 dd = frac(PixelPos); + float2 ExactPixel = PixelPos - dd; + float2 samplePos = ExactPixel * dxdy + dxdy05; + + return Sample(taps(dd.x), samplePos, dx); +} + +float4 main_bicubic2pass_pass2(PS_INPUT input) : COLOR { + float2 PixelPos = input.t0; + float2 dd = frac(PixelPos); + float2 ExactPixel = PixelPos - dd; + float2 samplePos = ExactPixel * dxdy + dxdy05; + + return Sample(taps(dd.y), samplePos, dy); +} diff --git a/src/mpc-hc/res/web/404.html b/src/mpc-hc/res/web/404.html index b5f8769984c..805f6ecc58d 100644 --- a/src/mpc-hc/res/web/404.html +++ b/src/mpc-hc/res/web/404.html @@ -1,14 +1,14 @@ - - - - - MPC-HC WebServer - Page Not Found - - - - -

Page Not Found

-

Sorry, but the page you were trying to view does not exist.

-[debug] - - + + + + + MPC-HC WebServer - Page Not Found + + + + +

Page Not Found

+

Sorry, but the page you were trying to view does not exist.

+[debug] + + diff --git a/src/mpc-hc/res/web/browser.html b/src/mpc-hc/res/web/browser.html index f78ff0620c7..22da98397c9 100644 --- a/src/mpc-hc/res/web/browser.html +++ b/src/mpc-hc/res/web/browser.html @@ -1,33 +1,33 @@ - - - - - MPC-HC WebServer - File Browser - - - - -
- - - - -
- Location: [currentdir] -
-
-   -
- - - - - - - - [currentfiles] -
NameTypeSizeDate Modified
-
-[debug] - - + + + + + MPC-HC WebServer - File Browser + + + + +
+ + + + +
+ Location: [currentdir] +
+
+   +
+ + + + + + + + [currentfiles] +
NameTypeSizeDate Modified
+
+[debug] + + diff --git a/src/mpc-hc/res/web/controls.html b/src/mpc-hc/res/web/controls.html index 2cbd44e5d0e..a31b8edf5a5 100644 --- a/src/mpc-hc/res/web/controls.html +++ b/src/mpc-hc/res/web/controls.html @@ -1,1204 +1,1204 @@ - - - - - MPC-HC WebServer - Controls - - - - - - -
- File Info - - - - - - - - - - -
- Loaded file: - [filepath] - Browse... -
Status: [statestring] - - - - - - -
[positionstring]/[durationstring]
-
- - -
- -
-
-
-
-
-
- - Goto control - - - - - - - - -
- - - - - - -
1pixslidergrip1pix
-
- - - - - - -
-
-
-
-
- - - - - -
Playback control - - - - - - - - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
-
 Seek - - - - - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
-
-
-
- - - - - - - - - -
Volume control - - - - - - - - - - -
-
- - -
-
- - - - - -
- - - - - - -
1pixvbs1pix
-
- -
-
- - -
- - -
-
-
- - -
-
-
 Playlist - - - - - -
-
- - -
-
-
- - -
-
-
 Panic Button - - - - -
-
- - -
-
-
 Audio Delay - - - - - -
-
- - -
-
-
- - -
-
-
-
-
-
- - - - - -
Pan&Scan Move - - - - - - - - - - - - - - - - -
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
 Pan&Scan Size - - - - - - - - - - - - - -
  - - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
-
-
-
- - - - - - -
Video Frame - - - - - - - - - - - - - -
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
DVD Menu Controler - - - - - - - - - - - - - - - -
  - - - - -
-
- - -
-
-
 
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
 Misc - - - - - - - - - - - - - - - -
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
- - - - -
-
- - -
-
-
-
-
-
-
- - - - - - -
Zoom control - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
 Fullscreen control - - - - - -
-
- - -
-
-
- - -
-
-
-
-
-
- - - - - - -
Player views - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
Detachable Controls - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
-
-
- - - - -
Generic Audio/Subtitles - - - - - - - - -
-
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
-
-
-
-
- - - - - - -
Subtitles - - - - - -
-
- - -
-
-
- - -
-
-
 DVD Angles/Audio/Subtitles - - - - - - - - - - - -
-
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
  -
- - -
-
-
- - -
-
-
-
-
-
- - - - - - -
DVD Menus - - - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
 MPC-HC's Menus - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
-
-
-
- Always On Top - - - - - - - -
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-[debug] - - + + + + + MPC-HC WebServer - Controls + + + + + + +
+ File Info + + + + + + + + + + +
+ Loaded file: + [filepath] + Browse... +
Status: [statestring] + + + + + + +
[positionstring]/[durationstring]
+
+ + +
+ +
+
+
+
+
+
+ + Goto control + + + + + + + + +
+ + + + + + +
1pixslidergrip1pix
+
+ + + + + + +
+
+
+
+
+ + + + + +
Playback control + + + + + + + + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
+
 Seek + + + + + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + + + + +
Volume control + + + + + + + + + + +
+
+ + +
+
+ + + + + +
+ + + + + + +
1pixvbs1pix
+
+ +
+
+ + +
+ + +
+
+
+ + +
+
+
 Playlist + + + + + +
+
+ + +
+
+
+ + +
+
+
 Panic Button + + + + +
+
+ + +
+
+
 Audio Delay + + + + + +
+
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + +
Pan&Scan Move + + + + + + + + + + + + + + + + +
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
 Pan&Scan Size + + + + + + + + + + + + + +
  + + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
+
+
+
+ + + + + + +
Video Frame + + + + + + + + + + + + + +
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
DVD Menu Controler + + + + + + + + + + + + + + + +
  + + + + +
+
+ + +
+
+
 
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
 Misc + + + + + + + + + + + + + + + +
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+ + + + +
+
+ + +
+
+
+
+
+
+
+ + + + + + +
Zoom control + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
 Fullscreen control + + + + + +
+
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + +
Player views + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
Detachable Controls + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+
+
+ + + + +
Generic Audio/Subtitles + + + + + + + + +
+
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + +
Subtitles + + + + + +
+
+ + +
+
+
+ + +
+
+
 DVD Angles/Audio/Subtitles + + + + + + + + + + + +
+
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
  +
+ + +
+
+
+ + +
+
+
+
+
+
+ + + + + + +
DVD Menus + + + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
 MPC-HC's Menus + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+
+
+
+ Always On Top + + + + + + + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+[debug] + + diff --git a/src/mpc-hc/res/web/default.css b/src/mpc-hc/res/web/default.css index e88faed5f49..f004c480380 100644 --- a/src/mpc-hc/res/web/default.css +++ b/src/mpc-hc/res/web/default.css @@ -1,350 +1,350 @@ -/*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ -progress,sub,sup{vertical-align:baseline} -button,hr,input,select{overflow:visible} -[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0} -html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} -body{margin:0} -article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block} -audio,canvas,progress,video{display:inline-block} -audio:not([controls]){display:none;height:0} -[hidden],template{display:none} -a{background-color:transparent} -a:active,a:hover{outline-width:0} -abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted} -b,strong{font-weight:bolder} -dfn{font-style:italic} -h1{font-size:2em;margin:.67em 0} -mark{background-color:#ff0;color:#000} -small{font-size:80%} -sub,sup{font-size:75%;line-height:0;position:relative} -sub{bottom:-.25em} -sup{top:-.5em} -img{border-style:none} -svg:not(:root){overflow:hidden} -code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em} -figure{margin:1em 40px} -hr{box-sizing:content-box;height:0} -button,input,select,textarea{font:inherit;margin:0} -optgroup{font-weight:700} -button,select{text-transform:none} -[type=button],[type=reset],[type=submit],button{cursor:pointer} -[disabled]{cursor:default} -[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button} -button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} -button:-moz-focusring,input:-moz-focusring{outline:ButtonText dotted 1px} -fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} -legend{color:inherit;display:table;max-width:100%;white-space:normal} -textarea{overflow:auto} -[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto} -[type=search]{-webkit-appearance:textfield} -[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none} -/* END OF normalize.css v4.0.0 */ - - -/* common */ -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -body { - font: 14px Arial, Verdana, Helvetica, Sans-Serif; -} - -img { - margin: 0; - padding: 0; -} - -.text-center { - text-align: center; -} - -.text-right { - text-align: right; -} - -.browser-warning { - background-color: red; - padding: 10px; -} - - -/* browser.html */ -.browser-table { - border-collapse: collapse; - width: 100%; -} - -.browser-table, -.browser-table th, -.browser-table td { - border: 2px solid black; - padding: 4px; -} - -.browser-table th { - font-weight: bold; - white-space: nowrap; -} - -.browser-table th:first-child { - width: 100%; -} - -.dirname { - font-weight: bold; -} - - - -/* controls.html */ -td, -th { - padding: 0; -} -#slider { - background: url(img/sliderback.png) no-repeat; - width: 515px; - height: 20px; -} - -#slider img { - cursor: pointer; -} - -#v { - background: url(img/vbg.png) no-repeat; - width: 110px; - height: 20px; - cursor: pointer; -} - -#v img { - cursor: pointer; -} - -#muted { - min-width: 29px; -} - -.nobr { - white-space: nowrap; -} - -form input { - min-width: 20px; - min-height: 24px; - vertical-align: middle; -} - - - -/* player.html */ -#player { - margin: 0 auto; -} - -#player, -#player table, -#player td, -#player th { - border-collapse: separate; - border-spacing: 0; - padding: 0; -} - -#player td { - font: 13px Sans-Serif; -} - -#header td { - height: 30px; -} - -#headerIcon { - background: url(img/headericon.png) no-repeat; - width: 22px; -} - -#headerBack { - background: url(img/headerback.png) repeat-x; - color: white; - font-weight: bold !important; -} - -#headerClose { - background: url(img/headerclose.png) no-repeat; - width: 28px; -} - -#durstr, -#posstr, -#status, -#title { - display: inline; -} - -#menu td { - font-size: 12px; - padding: 2px 6px; -} - -#menu-help { - width: 100%; -} - -#controlbar, -#menu { - background-color: #ECE6D4; - width: 100%; -} - -#statusbar { - padding: 4px 2px 1px 2px !important; - width: 100%; -} - -#statusbar td { - font-size: 12px; -} - -#statusbar, -#video { - background-color: black; - color: white; -} - -#video { - cursor: pointer; -} - -#snapshot { - margin-bottom: -4px; -} - -#controlbar { - background: url(img/controlback.png) repeat-x; - height: 28px; -} - -#controlbuttonplay { - background: url(img/controlbuttonplay.png) no-repeat; - width: 25px; - height: 28px; - cursor: pointer; -} - -#controlbuttonpause { - background: url(img/controlbuttonpause.png) no-repeat; - width: 23px; - height: 28px; - cursor: pointer; -} - -#controlbuttonstop { - background: url(img/controlbuttonstop.png) no-repeat; - width: 25px; - height: 28px; - cursor: pointer; -} - -#controlbuttonskipback { - background: url(img/controlbuttonskipback.png) no-repeat; - width: 24px; - height: 28px; - cursor: pointer; -} - -#controlbuttondecrate { - background: url(img/controlbuttondecrate.png) no-repeat; - width: 22px; - height: 28px; - cursor: pointer; -} - -#controlbuttonincrate { - background: url(img/controlbuttonincrate.png) no-repeat; - width: 23px; - height: 28px; - cursor: pointer; -} - -#controlbuttonskipforward { - background: url(img/controlbuttonskipforward.png) no-repeat; - width: 28px; - height: 28px; - cursor: pointer; -} - -#controlbuttonstep { - background: url(img/controlbuttonstep.png) no-repeat; - width: 31px; - height: 28px; - cursor: pointer; -} - -#controlvolumemute { - background: url(img/controlvolumeon.png) no-repeat; - width: 28px; - height: 28px; - cursor: pointer; -} - -#controlvolumebar { - background: url(img/controlvolumebar.png) no-repeat; - width: 55px; - height: 28px; - cursor: pointer; -} - -#seekbar { - background: url(img/seekbarmid.png) repeat-x; - margin-top: 1px; - width: 100%; - cursor: pointer; -} - -#seekbar td { - font-size: 0; -} - -#leftside { - background: url(img/leftside.png) repeat-y; - width: 4px; -} - -#rightside { - background: url(img/rightside.png) repeat-y; - width: 4px; -} - -#leftbottomside { - background: url(img/leftbottomside.png) repeat-x; - width: 4px; - height: 4px; -} - -#bottomside { - background: url(img/bottomside.png) repeat-x; - height: 4px; -} - -#rightbottomside { - background: url(img/rightbottomside.png) repeat-x; - width: 4px; - height: 4px; -} - -#center, -#header { - width: 100%; -} +/*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ +progress,sub,sup{vertical-align:baseline} +button,hr,input,select{overflow:visible} +[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0} +html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} +body{margin:0} +article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block} +audio,canvas,progress,video{display:inline-block} +audio:not([controls]){display:none;height:0} +[hidden],template{display:none} +a{background-color:transparent} +a:active,a:hover{outline-width:0} +abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted} +b,strong{font-weight:bolder} +dfn{font-style:italic} +h1{font-size:2em;margin:.67em 0} +mark{background-color:#ff0;color:#000} +small{font-size:80%} +sub,sup{font-size:75%;line-height:0;position:relative} +sub{bottom:-.25em} +sup{top:-.5em} +img{border-style:none} +svg:not(:root){overflow:hidden} +code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em} +figure{margin:1em 40px} +hr{box-sizing:content-box;height:0} +button,input,select,textarea{font:inherit;margin:0} +optgroup{font-weight:700} +button,select{text-transform:none} +[type=button],[type=reset],[type=submit],button{cursor:pointer} +[disabled]{cursor:default} +[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button} +button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} +button:-moz-focusring,input:-moz-focusring{outline:ButtonText dotted 1px} +fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} +legend{color:inherit;display:table;max-width:100%;white-space:normal} +textarea{overflow:auto} +[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto} +[type=search]{-webkit-appearance:textfield} +[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none} +/* END OF normalize.css v4.0.0 */ + + +/* common */ +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +body { + font: 14px Arial, Verdana, Helvetica, Sans-Serif; +} + +img { + margin: 0; + padding: 0; +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.browser-warning { + background-color: red; + padding: 10px; +} + + +/* browser.html */ +.browser-table { + border-collapse: collapse; + width: 100%; +} + +.browser-table, +.browser-table th, +.browser-table td { + border: 2px solid black; + padding: 4px; +} + +.browser-table th { + font-weight: bold; + white-space: nowrap; +} + +.browser-table th:first-child { + width: 100%; +} + +.dirname { + font-weight: bold; +} + + + +/* controls.html */ +td, +th { + padding: 0; +} +#slider { + background: url(img/sliderback.png) no-repeat; + width: 515px; + height: 20px; +} + +#slider img { + cursor: pointer; +} + +#v { + background: url(img/vbg.png) no-repeat; + width: 110px; + height: 20px; + cursor: pointer; +} + +#v img { + cursor: pointer; +} + +#muted { + min-width: 29px; +} + +.nobr { + white-space: nowrap; +} + +form input { + min-width: 20px; + min-height: 24px; + vertical-align: middle; +} + + + +/* player.html */ +#player { + margin: 0 auto; +} + +#player, +#player table, +#player td, +#player th { + border-collapse: separate; + border-spacing: 0; + padding: 0; +} + +#player td { + font: 13px Sans-Serif; +} + +#header td { + height: 30px; +} + +#headerIcon { + background: url(img/headericon.png) no-repeat; + width: 22px; +} + +#headerBack { + background: url(img/headerback.png) repeat-x; + color: white; + font-weight: bold !important; +} + +#headerClose { + background: url(img/headerclose.png) no-repeat; + width: 28px; +} + +#durstr, +#posstr, +#status, +#title { + display: inline; +} + +#menu td { + font-size: 12px; + padding: 2px 6px; +} + +#menu-help { + width: 100%; +} + +#controlbar, +#menu { + background-color: #ECE6D4; + width: 100%; +} + +#statusbar { + padding: 4px 2px 1px 2px !important; + width: 100%; +} + +#statusbar td { + font-size: 12px; +} + +#statusbar, +#video { + background-color: black; + color: white; +} + +#video { + cursor: pointer; +} + +#snapshot { + margin-bottom: -4px; +} + +#controlbar { + background: url(img/controlback.png) repeat-x; + height: 28px; +} + +#controlbuttonplay { + background: url(img/controlbuttonplay.png) no-repeat; + width: 25px; + height: 28px; + cursor: pointer; +} + +#controlbuttonpause { + background: url(img/controlbuttonpause.png) no-repeat; + width: 23px; + height: 28px; + cursor: pointer; +} + +#controlbuttonstop { + background: url(img/controlbuttonstop.png) no-repeat; + width: 25px; + height: 28px; + cursor: pointer; +} + +#controlbuttonskipback { + background: url(img/controlbuttonskipback.png) no-repeat; + width: 24px; + height: 28px; + cursor: pointer; +} + +#controlbuttondecrate { + background: url(img/controlbuttondecrate.png) no-repeat; + width: 22px; + height: 28px; + cursor: pointer; +} + +#controlbuttonincrate { + background: url(img/controlbuttonincrate.png) no-repeat; + width: 23px; + height: 28px; + cursor: pointer; +} + +#controlbuttonskipforward { + background: url(img/controlbuttonskipforward.png) no-repeat; + width: 28px; + height: 28px; + cursor: pointer; +} + +#controlbuttonstep { + background: url(img/controlbuttonstep.png) no-repeat; + width: 31px; + height: 28px; + cursor: pointer; +} + +#controlvolumemute { + background: url(img/controlvolumeon.png) no-repeat; + width: 28px; + height: 28px; + cursor: pointer; +} + +#controlvolumebar { + background: url(img/controlvolumebar.png) no-repeat; + width: 55px; + height: 28px; + cursor: pointer; +} + +#seekbar { + background: url(img/seekbarmid.png) repeat-x; + margin-top: 1px; + width: 100%; + cursor: pointer; +} + +#seekbar td { + font-size: 0; +} + +#leftside { + background: url(img/leftside.png) repeat-y; + width: 4px; +} + +#rightside { + background: url(img/rightside.png) repeat-y; + width: 4px; +} + +#leftbottomside { + background: url(img/leftbottomside.png) repeat-x; + width: 4px; + height: 4px; +} + +#bottomside { + background: url(img/bottomside.png) repeat-x; + height: 4px; +} + +#rightbottomside { + background: url(img/rightbottomside.png) repeat-x; + width: 4px; + height: 4px; +} + +#center, +#header { + width: 100%; +} diff --git a/src/mpc-hc/res/web/index.html b/src/mpc-hc/res/web/index.html index 2d3980ca4a0..b1a43c005fd 100644 --- a/src/mpc-hc/res/web/index.html +++ b/src/mpc-hc/res/web/index.html @@ -1,25 +1,25 @@ - - - - - MPC-HC WebServer - - - - -

Demo page; submit patches if you want this page updated.

-

And if you are already here, why don't you try sending a few commands to MPC-HC, just to see if it works :)

-
-
- - -
-
-

File browser

-

The media player interface made by chobits

-

MPC-HC in the browser

-

Info page

-

Variables page

-[debug] - - + + + + + MPC-HC WebServer + + + + +

Demo page; submit patches if you want this page updated.

+

And if you are already here, why don't you try sending a few commands to MPC-HC, just to see if it works :)

+
+
+ + +
+
+

File browser

+

The media player interface made by chobits

+

MPC-HC in the browser

+

Info page

+

Variables page

+[debug] + + diff --git a/src/mpc-hc/res/web/info.html b/src/mpc-hc/res/web/info.html index 81ea463e77c..7653385b80f 100644 --- a/src/mpc-hc/res/web/info.html +++ b/src/mpc-hc/res/web/info.html @@ -1,14 +1,14 @@ - - - - - MPC-HC WebServer - Info - - - - - -

« MPC-HC v[version] • [file] • [position]/[duration] • [size] »

-[debug] - - + + + + + MPC-HC WebServer - Info + + + + + +

« MPC-HC v[version] • [file] • [position]/[duration] • [size] »

+[debug] + + diff --git a/src/mpc-hc/res/web/javascript.js b/src/mpc-hc/res/web/javascript.js index 508b23909cd..0b65eab1fe9 100644 --- a/src/mpc-hc/res/web/javascript.js +++ b/src/mpc-hc/res/web/javascript.js @@ -1,574 +1,574 @@ -/* jshint browser:true, camelcase:true, curly:true, es3:true, eqeqeq:true, - immed:true, indent:4, latedef:true, quotmark:double, strict:true, undef:true, - unused:true */ - -/* global ActiveXObject */ -/* exported controlsInit, positionUpdate, onLoadSnapshot, onAbortErrorSnapshot, - onCommand, playerInit */ - - -var filePath; -var curPos; -var len; -var state; -var pbr; -var eta; -var volume; -var muted; // 1 no sound -var startTime = new Date().getTime(); -var sliderSize = 500; -var sliderButtonWidth = 15; -var vsb = 10; -var vss = 100; -var vs; -var sc = 0; -var rdirt; -var Live; -var re; -var sas; -var cpf; -var cp; -var s; -var m; -var sb1; -var sb2; -var sb3; -var vs1; -var vs2; -var vs3; -var etaup = false; -var httpRequestStatus; - - -// common functions -function getById(id) { - "use strict"; - return document.getElementById(id); -} - -function getOffsetX(m) { - "use strict"; - var x = m.offsetLeft; - while (m.offsetParent) { - x += (m = m.offsetParent).offsetLeft; - } - return x; -} - - -// controls.html -function timeSyntax(ts) { - "use strict"; - var b = ""; - for (var a = 0, len = ts.length; a < len; a++) { - switch (ts.charAt(a)) { - case "0": - b += "0"; - break; - case "1": - b += "1"; - break; - case "2": - b += "2"; - break; - case "3": - b += "3"; - break; - case "4": - b += "4"; - break; - case "5": - b += "5"; - break; - case "6": - b += "6"; - break; - case "7": - b += "7"; - break; - case "8": - b += "8"; - break; - case "9": - b += "9"; - break; - case ".": - b += "."; - break; - case ":": - b += ":"; - break; - default: - break; - } - } - return b; -} - -function parseTime(y) { - "use strict"; - var ts = timeSyntax(y); - var t = 0; - var p1 = ts.indexOf("."); - var p2 = ts.indexOf(":"); - var p3 = ts.indexOf(":", p2 + 1); - var p4 = ts.indexOf(":", p3 + 1); - - if (p4 !== -1 || (p1 !== -1 && p2 !== -1 && p2 > p1) || (p1 !== -1 && p3 !== -1 && p3 > p1)) { - return -2000; - } - if (p1 === -1) { - p1 = ts.length + 1; - } else { - p1 = p1; - } - if (p2 === -1) { - t = parseFloat((ts + " ").substring(0, p1 + 4)); - } - if (p2 !== -1 && p3 === -1) { - t = parseInt(ts.substring(0, p2), 10) * 60 + parseFloat("0" + (ts + " ").substring(p2 + 1, p1 + 4)); - } - if (p2 !== -1 && p3 !== -1) { - t = parseInt(ts.substring(0, p2), 10) * 3600 + parseInt(ts.substring(p2 + 1, p3), 10) * 60 + parseFloat("0" + (ts + " ").substring(p3 + 1, p1 + 4)); - } - return t; -} - -function update(a, b) { - "use strict"; - if (a === -2000) { - return false; - } - if (b) { - if (a > len && !Live) { - curPos = len; - } else { - curPos = a < 0 ? 0 : a; - } - m = curPos * sliderSize / len; - } else { - if (a > sliderSize) { - m = sliderSize; - } else { - m = a < 0 ? 0 : a; - } - curPos = m * len / sliderSize; - } - if (m > sb1.width) { - sb3.width = sliderSize - Math.floor(m); - sb1.width = m; - } else { - sb1.width = m; - sb3.width = sliderSize - sb1.width; - } - return true; -} - -function pad(number, len) { - "use strict"; - var str = String(number); - while (str.length < len) { - str = "0" + str; - } - return str; -} - -function secondsToTS(a, b) { - "use strict"; - var a1 = Math.floor(a / 3600000); - var a2 = Math.floor(a / 60000) % 60; - var a3 = Math.floor(a / 1000) % 60; - var a4 = Math.floor(a) % 1000; - var a1s = pad(a1.toString(), 2); - var a2s = pad(a2.toString(), 2); - var a3s = pad(a3.toString(), 2); - var a4s = pad(a4.toString(), 3); - - switch (b) { - case 1: - return a1s; - case 2: - return a2s; - case 3: - return a3s; - case 4: - return a4s; - case 5: - case 6: - case 7: - return a1s + ":" + a2s + ":" + a3s; - default: - return ((a1 > 0 ? (a1s + ":") : "") + a2s + ":" + a3s); - } -} - -function postForm(wmc, ext, extv) { - "use strict"; - getById("fwmc").value = wmc; - getById("fextra").value = extv; - getById("fextra").name = ext; - getById("ef").submit(); - return true; -} - -function autoplay(a) { - "use strict"; - if (etaup && re.checked === true) { - etaup = false; - setTimeout(function () { - etaup = true; - if (re.checked === true) { - postForm(0, "null", 0); - } - }, 5000); - } - setTimeout(autoplay, rdirt); - var ct = new Date().getTime(); - var cap = pbr * (ct - startTime); - if (cap > len && !Live) { - if (re.checked === true) { - setTimeout(function () { - window.location = window.location; - }, 5000); - } - } - cap = ((cap > len && !Live) ? len : (cap < 0 ? 0 : cap)); - if (sas.checked === true || a === true) { - update(cap, true); - cpf.value = secondsToTS(cap, 5); - } - var gg = " " + secondsToTS(cap, 5) + " "; - cp.innerHTML = gg; - return true; -} - -function sliderClick(e) { - "use strict"; - update((window.event ? window.event.clientX - 3 : e.clientX) + document.body.scrollLeft - getOffsetX(s) - Math.floor(sliderButtonWidth / 2) + sc, false); - cpf.value = secondsToTS(curPos, 5); - sas.checked = false; - return true; -} - -function volumeUpdate(a, b) { - "use strict"; - if (b) { - if (a > 100) { - volume = 100; - } else { - volume = a < 0 ? 0 : a; - } - m = volume * vss / 100; - } else { - if (a > vss) { - m = vss; - } else { - m = a < 0 ? 0 : a; - } - volume = m * 100 / vss; - } - volume = Math.ceil(volume); - vs1.width = m; - vs3.width = vss - vs1.width; - return true; -} - -function volSliderClick(e) { - "use strict"; - var ret = volumeUpdate((window.event ? window.event.clientX - 3 : e.clientX) + document.body.scrollLeft - getOffsetX(vs) - Math.floor(vsb / 2) + sc, false); - return ret; -} - - -if (eta === 0) { - if (state < 0 && filePath.length > 0) { - eta = 2; - } else { - eta = 120; - } -} - -function controlsInit(_filePath, _curPos, _length, _state, _pbr, _eta, _volume, _muted) { - "use strict"; - filePath = decodeURIComponent(_filePath); - curPos = _curPos; - len = _length; - state = _state; - pbr = _pbr; - eta = _eta; - volume = _volume; - muted = _muted; - - if (eta > 0) { - setTimeout(function () { - etaup = true; - if (re.checked === true) { - postForm(0, "null", 0); - } - }, 1000 * eta); - } - Live = len < 1; - startTime -= curPos; - rdirt = len * pbr / sliderSize; - rdirt = Math.floor(rdirt > 1000 ? 1000 : (rdirt < 300 ? 300 : rdirt)); - cpf = getById("pos"); - cp = getById("time"); - sas = getById("SliderAutoScroll"); - re = getById("reloadenabled"); - s = getById("slider"); - sb1 = getById("c1"); - sb2 = getById("c2"); - sb3 = getById("c3"); - vs = getById("v"); - vs1 = getById("v1"); - vs2 = getById("v2"); - vs3 = getById("v3"); - - if (muted === 1) { - getById("muted").innerHTML = "M"; - } - vs2.title = volume; - sb2.title = secondsToTS(curPos, 5); - s.height = sb1.height = sb2.height = sb3.height = vs.height = vs1.height = vs2.height = vs3.height = 20; - s.width = sliderSize + (sb2.width = sliderButtonWidth); - vs.width = vss + (vs2.width = vsb); - sb1.onclick = sb2.onclick = sb3.onclick = sliderClick; - vs1.onclick = vs2.onclick = vs3.onclick = volSliderClick; - sas.checked = true; - cp.innerHTML = cpf.value = secondsToTS(curPos, 5); - if (state === 2 && pbr !== 0) { - autoplay(); - } - volumeUpdate(volume, true); - return update(curPos, true); -} - -function positionUpdate() { - "use strict"; - if (event.keyCode < 46 || event.keyCode > 58 || event.keyCode === 47) { - return false; - } - setTimeout(function () { - update(parseFloat(parseTime(cpf.value)), true); - }, 1); - return true; -} - - -// player.html -function getXMLHTTP() { - "use strict"; - try { - return new ActiveXObject("Msxml2.XMLHTTP"); - } catch (e) { - try { - return new ActiveXObject("Microsoft.XMLHTTP"); - } catch (err) {} - } - if (typeof XMLHttpRequest !== "undefined") { - return new XMLHttpRequest(); - } - return null; -} - -function makeRequest(req) { - "use strict"; - var httpRequest = getXMLHTTP(); - try { - httpRequest.open("GET", req, true); - httpRequest.send(null); - } catch (e) {} -} - -function onStatus (title, status, pos, posStr, dur, durStr, muted, volume) { - "use strict"; - var maxTitle = 70; - var timestr; - var el; - - if (dur > 0 && posStr && durStr) { - timestr = posStr + " / " + durStr; - } else { - timestr = " "; - } - - if (title.length > maxTitle) { - title = title.substr(0, maxTitle - 3) + "…"; - } - if (!dur || dur === 0) { - dur = 1; - } - - el = getById("title"); - if (el) { - el.innerHTML = title; - } - - var sbpercent = Math.floor(100 * pos / dur); - el = getById("seekbarchleft"); - if (el) { - el.width = sbpercent > 0 ? sbpercent + "%" : "1px"; - } - - el = getById("seekbarchright"); - if (el) { - el.width = sbpercent < 100 ? (100 - sbpercent) + "%" : "1px"; - } - - el = getById("seekbargrip"); - if (el) { - el.title = posStr; - } - - el = getById("status"); - if (el && el.innerHTML !== status) { - el.innerHTML = status; - } - - el = getById("timer"); - if (el && el.innerHTML !== timestr) { - el.innerHTML = timestr; - } - - el = getById("controlvolumemute"); - if (el) { - var url = "url(img/controlvolume" + (muted ? "off" : "on") + ".png)"; - if (el.style.backgroundImage !== url) { - el.style.backgroundImage = url; - } - } - - el = getById("controlvolumegrip"); - if (el) { - el.title = volume; - volume = (getById("controlvolumebar").offsetWidth - el.offsetWidth) * volume / 100; - el.style.position = "relative"; - el.style.top = "2px"; - el.style.left = Math.floor(volume) + "px"; - } -} - -function onReadyStateChange() { - "use strict"; - var statusRegExp = /OnStatus\("(.*)", "(.*)", (\d+), "(.*)", (\d+), "(.*)", (\d+), (\d+), "(.*)"\)/; - - if (httpRequestStatus && httpRequestStatus.readyState === 4 && httpRequestStatus.responseText) { - if (httpRequestStatus.responseText.charAt(0) !== "<") { - var params = statusRegExp.exec(httpRequestStatus.responseText); - onStatus(params[1], params[2], parseInt(params[3], 10), params[4], parseInt(params[5], 10), params[6], parseInt(params[7], 10), parseInt(params[8], 10), params[9]); - } else { - alert(httpRequestStatus.responseText); - } - httpRequestStatus = null; - } -} - -function statusLoop() { - "use strict"; - - if (!httpRequestStatus || httpRequestStatus.readyState === 0) { - httpRequestStatus = getXMLHTTP(); - try { - httpRequestStatus.open("GET", "status.html", true); - httpRequestStatus.onreadystatechange = onReadyStateChange; - httpRequestStatus.send(null); - } catch (e) {} - } - setTimeout(statusLoop, 500); -} - -var snapshotCounter = 0; - -function loadSnapshot() { - "use strict"; - var img = getById("snapshot"); - if (img) { - img.src = "snapshot.jpg?" + snapshotCounter++; - } -} - -function onLoadSnapshot() { - "use strict"; - setTimeout(loadSnapshot, 500); -} - -function onAbortErrorSnapshot() { - "use strict"; - setTimeout(loadSnapshot, 5000); -} - -function onSeek(e) { - "use strict"; - var left = 0; - var right = 0; - var percent; - var sb; - - sb = getById("seekbarchleft"); - if (sb) { - left = getOffsetX(sb); - } - - sb = getById("seekbarchright"); - if (sb) { - right = getOffsetX(sb) + sb.offsetWidth; - } - - sb = getById("seekbargrip"); - if (sb) { - left += sb.offsetWidth / 2; - right -= sb.offsetWidth / 2; - } - if (left > 0 && left < right) { - percent = 100 * ((window.event ? window.event.clientX : e.clientX) - left) / (right - left); - if (percent < 0) { - percent = 0; - } else if (percent > 100) { - percent = 100; - } - makeRequest("command.html?wm_command=[setposcommand]&percent=" + percent); - } -} - -function onVolume(e) { - "use strict"; - var left = 0; - var right = 0; - var percent; - var cv = getById("controlvolumebar"); - - if (cv) { - left = getOffsetX(cv) + 3; - right = getOffsetX(cv) + cv.offsetWidth - 3; - } - if (left > 0 && left < right) { - percent = 100 * ((window.event ? window.event.clientX : e.clientX) - left) / (right - left); - if (percent < 0) { - percent = 0; - } else if (percent > 100) { - percent = 100; - } - makeRequest("command.html?wm_command=[setvolumecommand]&volume=" + percent); - } -} - -function onCommand(id) { - "use strict"; - makeRequest("command.html?wm_command=" + id); -} - -function playerInit() { - "use strict"; - statusLoop(); - loadSnapshot(); - - var el = getById("seekbar"); - if (el) { - el.onclick = onSeek; - } - - el = getById("controlvolumebar"); - if (el) { - el.onclick = onVolume; - } -} +/* jshint browser:true, camelcase:true, curly:true, es3:true, eqeqeq:true, + immed:true, indent:4, latedef:true, quotmark:double, strict:true, undef:true, + unused:true */ + +/* global ActiveXObject */ +/* exported controlsInit, positionUpdate, onLoadSnapshot, onAbortErrorSnapshot, + onCommand, playerInit */ + + +var filePath; +var curPos; +var len; +var state; +var pbr; +var eta; +var volume; +var muted; // 1 no sound +var startTime = new Date().getTime(); +var sliderSize = 500; +var sliderButtonWidth = 15; +var vsb = 10; +var vss = 100; +var vs; +var sc = 0; +var rdirt; +var Live; +var re; +var sas; +var cpf; +var cp; +var s; +var m; +var sb1; +var sb2; +var sb3; +var vs1; +var vs2; +var vs3; +var etaup = false; +var httpRequestStatus; + + +// common functions +function getById(id) { + "use strict"; + return document.getElementById(id); +} + +function getOffsetX(m) { + "use strict"; + var x = m.offsetLeft; + while (m.offsetParent) { + x += (m = m.offsetParent).offsetLeft; + } + return x; +} + + +// controls.html +function timeSyntax(ts) { + "use strict"; + var b = ""; + for (var a = 0, len = ts.length; a < len; a++) { + switch (ts.charAt(a)) { + case "0": + b += "0"; + break; + case "1": + b += "1"; + break; + case "2": + b += "2"; + break; + case "3": + b += "3"; + break; + case "4": + b += "4"; + break; + case "5": + b += "5"; + break; + case "6": + b += "6"; + break; + case "7": + b += "7"; + break; + case "8": + b += "8"; + break; + case "9": + b += "9"; + break; + case ".": + b += "."; + break; + case ":": + b += ":"; + break; + default: + break; + } + } + return b; +} + +function parseTime(y) { + "use strict"; + var ts = timeSyntax(y); + var t = 0; + var p1 = ts.indexOf("."); + var p2 = ts.indexOf(":"); + var p3 = ts.indexOf(":", p2 + 1); + var p4 = ts.indexOf(":", p3 + 1); + + if (p4 !== -1 || (p1 !== -1 && p2 !== -1 && p2 > p1) || (p1 !== -1 && p3 !== -1 && p3 > p1)) { + return -2000; + } + if (p1 === -1) { + p1 = ts.length + 1; + } else { + p1 = p1; + } + if (p2 === -1) { + t = parseFloat((ts + " ").substring(0, p1 + 4)); + } + if (p2 !== -1 && p3 === -1) { + t = parseInt(ts.substring(0, p2), 10) * 60 + parseFloat("0" + (ts + " ").substring(p2 + 1, p1 + 4)); + } + if (p2 !== -1 && p3 !== -1) { + t = parseInt(ts.substring(0, p2), 10) * 3600 + parseInt(ts.substring(p2 + 1, p3), 10) * 60 + parseFloat("0" + (ts + " ").substring(p3 + 1, p1 + 4)); + } + return t; +} + +function update(a, b) { + "use strict"; + if (a === -2000) { + return false; + } + if (b) { + if (a > len && !Live) { + curPos = len; + } else { + curPos = a < 0 ? 0 : a; + } + m = curPos * sliderSize / len; + } else { + if (a > sliderSize) { + m = sliderSize; + } else { + m = a < 0 ? 0 : a; + } + curPos = m * len / sliderSize; + } + if (m > sb1.width) { + sb3.width = sliderSize - Math.floor(m); + sb1.width = m; + } else { + sb1.width = m; + sb3.width = sliderSize - sb1.width; + } + return true; +} + +function pad(number, len) { + "use strict"; + var str = String(number); + while (str.length < len) { + str = "0" + str; + } + return str; +} + +function secondsToTS(a, b) { + "use strict"; + var a1 = Math.floor(a / 3600000); + var a2 = Math.floor(a / 60000) % 60; + var a3 = Math.floor(a / 1000) % 60; + var a4 = Math.floor(a) % 1000; + var a1s = pad(a1.toString(), 2); + var a2s = pad(a2.toString(), 2); + var a3s = pad(a3.toString(), 2); + var a4s = pad(a4.toString(), 3); + + switch (b) { + case 1: + return a1s; + case 2: + return a2s; + case 3: + return a3s; + case 4: + return a4s; + case 5: + case 6: + case 7: + return a1s + ":" + a2s + ":" + a3s; + default: + return ((a1 > 0 ? (a1s + ":") : "") + a2s + ":" + a3s); + } +} + +function postForm(wmc, ext, extv) { + "use strict"; + getById("fwmc").value = wmc; + getById("fextra").value = extv; + getById("fextra").name = ext; + getById("ef").submit(); + return true; +} + +function autoplay(a) { + "use strict"; + if (etaup && re.checked === true) { + etaup = false; + setTimeout(function () { + etaup = true; + if (re.checked === true) { + postForm(0, "null", 0); + } + }, 5000); + } + setTimeout(autoplay, rdirt); + var ct = new Date().getTime(); + var cap = pbr * (ct - startTime); + if (cap > len && !Live) { + if (re.checked === true) { + setTimeout(function () { + window.location = window.location; + }, 5000); + } + } + cap = ((cap > len && !Live) ? len : (cap < 0 ? 0 : cap)); + if (sas.checked === true || a === true) { + update(cap, true); + cpf.value = secondsToTS(cap, 5); + } + var gg = " " + secondsToTS(cap, 5) + " "; + cp.innerHTML = gg; + return true; +} + +function sliderClick(e) { + "use strict"; + update((window.event ? window.event.clientX - 3 : e.clientX) + document.body.scrollLeft - getOffsetX(s) - Math.floor(sliderButtonWidth / 2) + sc, false); + cpf.value = secondsToTS(curPos, 5); + sas.checked = false; + return true; +} + +function volumeUpdate(a, b) { + "use strict"; + if (b) { + if (a > 100) { + volume = 100; + } else { + volume = a < 0 ? 0 : a; + } + m = volume * vss / 100; + } else { + if (a > vss) { + m = vss; + } else { + m = a < 0 ? 0 : a; + } + volume = m * 100 / vss; + } + volume = Math.ceil(volume); + vs1.width = m; + vs3.width = vss - vs1.width; + return true; +} + +function volSliderClick(e) { + "use strict"; + var ret = volumeUpdate((window.event ? window.event.clientX - 3 : e.clientX) + document.body.scrollLeft - getOffsetX(vs) - Math.floor(vsb / 2) + sc, false); + return ret; +} + + +if (eta === 0) { + if (state < 0 && filePath.length > 0) { + eta = 2; + } else { + eta = 120; + } +} + +function controlsInit(_filePath, _curPos, _length, _state, _pbr, _eta, _volume, _muted) { + "use strict"; + filePath = decodeURIComponent(_filePath); + curPos = _curPos; + len = _length; + state = _state; + pbr = _pbr; + eta = _eta; + volume = _volume; + muted = _muted; + + if (eta > 0) { + setTimeout(function () { + etaup = true; + if (re.checked === true) { + postForm(0, "null", 0); + } + }, 1000 * eta); + } + Live = len < 1; + startTime -= curPos; + rdirt = len * pbr / sliderSize; + rdirt = Math.floor(rdirt > 1000 ? 1000 : (rdirt < 300 ? 300 : rdirt)); + cpf = getById("pos"); + cp = getById("time"); + sas = getById("SliderAutoScroll"); + re = getById("reloadenabled"); + s = getById("slider"); + sb1 = getById("c1"); + sb2 = getById("c2"); + sb3 = getById("c3"); + vs = getById("v"); + vs1 = getById("v1"); + vs2 = getById("v2"); + vs3 = getById("v3"); + + if (muted === 1) { + getById("muted").innerHTML = "M"; + } + vs2.title = volume; + sb2.title = secondsToTS(curPos, 5); + s.height = sb1.height = sb2.height = sb3.height = vs.height = vs1.height = vs2.height = vs3.height = 20; + s.width = sliderSize + (sb2.width = sliderButtonWidth); + vs.width = vss + (vs2.width = vsb); + sb1.onclick = sb2.onclick = sb3.onclick = sliderClick; + vs1.onclick = vs2.onclick = vs3.onclick = volSliderClick; + sas.checked = true; + cp.innerHTML = cpf.value = secondsToTS(curPos, 5); + if (state === 2 && pbr !== 0) { + autoplay(); + } + volumeUpdate(volume, true); + return update(curPos, true); +} + +function positionUpdate() { + "use strict"; + if (event.keyCode < 46 || event.keyCode > 58 || event.keyCode === 47) { + return false; + } + setTimeout(function () { + update(parseFloat(parseTime(cpf.value)), true); + }, 1); + return true; +} + + +// player.html +function getXMLHTTP() { + "use strict"; + try { + return new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) { + try { + return new ActiveXObject("Microsoft.XMLHTTP"); + } catch (err) {} + } + if (typeof XMLHttpRequest !== "undefined") { + return new XMLHttpRequest(); + } + return null; +} + +function makeRequest(req) { + "use strict"; + var httpRequest = getXMLHTTP(); + try { + httpRequest.open("GET", req, true); + httpRequest.send(null); + } catch (e) {} +} + +function onStatus (title, status, pos, posStr, dur, durStr, muted, volume) { + "use strict"; + var maxTitle = 70; + var timestr; + var el; + + if (dur > 0 && posStr && durStr) { + timestr = posStr + " / " + durStr; + } else { + timestr = " "; + } + + if (title.length > maxTitle) { + title = title.substr(0, maxTitle - 3) + "…"; + } + if (!dur || dur === 0) { + dur = 1; + } + + el = getById("title"); + if (el) { + el.innerHTML = title; + } + + var sbpercent = Math.floor(100 * pos / dur); + el = getById("seekbarchleft"); + if (el) { + el.width = sbpercent > 0 ? sbpercent + "%" : "1px"; + } + + el = getById("seekbarchright"); + if (el) { + el.width = sbpercent < 100 ? (100 - sbpercent) + "%" : "1px"; + } + + el = getById("seekbargrip"); + if (el) { + el.title = posStr; + } + + el = getById("status"); + if (el && el.innerHTML !== status) { + el.innerHTML = status; + } + + el = getById("timer"); + if (el && el.innerHTML !== timestr) { + el.innerHTML = timestr; + } + + el = getById("controlvolumemute"); + if (el) { + var url = "url(img/controlvolume" + (muted ? "off" : "on") + ".png)"; + if (el.style.backgroundImage !== url) { + el.style.backgroundImage = url; + } + } + + el = getById("controlvolumegrip"); + if (el) { + el.title = volume; + volume = (getById("controlvolumebar").offsetWidth - el.offsetWidth) * volume / 100; + el.style.position = "relative"; + el.style.top = "2px"; + el.style.left = Math.floor(volume) + "px"; + } +} + +function onReadyStateChange() { + "use strict"; + var statusRegExp = /OnStatus\("(.*)", "(.*)", (\d+), "(.*)", (\d+), "(.*)", (\d+), (\d+), "(.*)"\)/; + + if (httpRequestStatus && httpRequestStatus.readyState === 4 && httpRequestStatus.responseText) { + if (httpRequestStatus.responseText.charAt(0) !== "<") { + var params = statusRegExp.exec(httpRequestStatus.responseText); + onStatus(params[1], params[2], parseInt(params[3], 10), params[4], parseInt(params[5], 10), params[6], parseInt(params[7], 10), parseInt(params[8], 10), params[9]); + } else { + alert(httpRequestStatus.responseText); + } + httpRequestStatus = null; + } +} + +function statusLoop() { + "use strict"; + + if (!httpRequestStatus || httpRequestStatus.readyState === 0) { + httpRequestStatus = getXMLHTTP(); + try { + httpRequestStatus.open("GET", "status.html", true); + httpRequestStatus.onreadystatechange = onReadyStateChange; + httpRequestStatus.send(null); + } catch (e) {} + } + setTimeout(statusLoop, 500); +} + +var snapshotCounter = 0; + +function loadSnapshot() { + "use strict"; + var img = getById("snapshot"); + if (img) { + img.src = "snapshot.jpg?" + snapshotCounter++; + } +} + +function onLoadSnapshot() { + "use strict"; + setTimeout(loadSnapshot, 500); +} + +function onAbortErrorSnapshot() { + "use strict"; + setTimeout(loadSnapshot, 5000); +} + +function onSeek(e) { + "use strict"; + var left = 0; + var right = 0; + var percent; + var sb; + + sb = getById("seekbarchleft"); + if (sb) { + left = getOffsetX(sb); + } + + sb = getById("seekbarchright"); + if (sb) { + right = getOffsetX(sb) + sb.offsetWidth; + } + + sb = getById("seekbargrip"); + if (sb) { + left += sb.offsetWidth / 2; + right -= sb.offsetWidth / 2; + } + if (left > 0 && left < right) { + percent = 100 * ((window.event ? window.event.clientX : e.clientX) - left) / (right - left); + if (percent < 0) { + percent = 0; + } else if (percent > 100) { + percent = 100; + } + makeRequest("command.html?wm_command=[setposcommand]&percent=" + percent); + } +} + +function onVolume(e) { + "use strict"; + var left = 0; + var right = 0; + var percent; + var cv = getById("controlvolumebar"); + + if (cv) { + left = getOffsetX(cv) + 3; + right = getOffsetX(cv) + cv.offsetWidth - 3; + } + if (left > 0 && left < right) { + percent = 100 * ((window.event ? window.event.clientX : e.clientX) - left) / (right - left); + if (percent < 0) { + percent = 0; + } else if (percent > 100) { + percent = 100; + } + makeRequest("command.html?wm_command=[setvolumecommand]&volume=" + percent); + } +} + +function onCommand(id) { + "use strict"; + makeRequest("command.html?wm_command=" + id); +} + +function playerInit() { + "use strict"; + statusLoop(); + loadSnapshot(); + + var el = getById("seekbar"); + if (el) { + el.onclick = onSeek; + } + + el = getById("controlvolumebar"); + if (el) { + el.onclick = onVolume; + } +} diff --git a/src/mpc-hc/res/web/player.html b/src/mpc-hc/res/web/player.html index 1216e91026e..dc306314e17 100644 --- a/src/mpc-hc/res/web/player.html +++ b/src/mpc-hc/res/web/player.html @@ -1,109 +1,109 @@ - - - - - MPC-HC WebServer - Player - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - - -
- - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- [preview] -
- - - - - - - - -
seekbarleftseekbargripseekbarright
-
- - - - - - - - - - - - - - -
  - control volume grip -
-
- - - - - -
 
-
-
-
-[debug] - - + + + + + MPC-HC WebServer - Player + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ [preview] +
+ + + + + + + + +
seekbarleftseekbargripseekbarright
+
+ + + + + + + + + + + + + + +
  + control volume grip +
+
+ + + + + +
 
+
+
+
+[debug] + + diff --git a/src/mpc-hc/res/web/variables.html b/src/mpc-hc/res/web/variables.html index 36cddffe29c..a831d33acf4 100644 --- a/src/mpc-hc/res/web/variables.html +++ b/src/mpc-hc/res/web/variables.html @@ -1,31 +1,31 @@ - - - - - MPC-HC WebServer - Variables - - - - -

[file]

-

[filepatharg]

-

[filepath]

-

[filedirarg]

-

[filedir]

-

[state]

-

[statestring]

-

[position]

-

[positionstring]

-

[duration]

-

[durationstring]

-

[volumelevel]

-

[muted]

-

[playbackrate]

-

[size]

-

[reloadtime]

-

[version]

-

[audiotrack]

-

[subtitletrack]

-[debug] - - + + + + + MPC-HC WebServer - Variables + + + + +

[file]

+

[filepatharg]

+

[filepath]

+

[filedirarg]

+

[filedir]

+

[state]

+

[statestring]

+

[position]

+

[positionstring]

+

[duration]

+

[durationstring]

+

[volumelevel]

+

[muted]

+

[playbackrate]

+

[size]

+

[reloadtime]

+

[version]

+

[audiotrack]

+

[subtitletrack]

+[debug] + + diff --git a/src/mpc-hc/resource.h b/src/mpc-hc/resource.h index f7b1fd1de46..0cd406fd264 100644 --- a/src/mpc-hc/resource.h +++ b/src/mpc-hc/resource.h @@ -1,1770 +1,1770 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by mpc-hc.rc -// -#define IDR_MAINFRAME 128 -#define IDR_POPUP 130 -#define IDR_POPUPMAIN 133 -#define IDB_PLAYERTOOLBAR 201 -#define IDB_AUDIOTYPE_NOAUDIO 202 -#define IDB_AUDIOTYPE_MONO 203 -#define IDB_AUDIOTYPE_STEREO 204 -#define IDB_CHECKBOX 205 -#define IDF_LOGO0 206 -#define IDF_LOGO1 207 -#define IDF_LOGO2 208 -#define IDF_LOGO3 209 -#define IDF_TICKCROSS 210 -#define IDB_STREAMTYPES 215 -#define IDB_SHADER_UP 216 -#define IDB_SHADER_DOWN 217 -#define IDB_SHADER_DEL 218 -#define IDB_CHECK_ALL 219 -#define IDB_UNCHECK_ALL 220 -#define IDB_CHECK_AUDIO 221 -#define IDB_CHECK_VIDEO 222 -#define IDI_SINGLE 300 -#define IDI_MULTI 301 -#define IDI_DVD 302 -#define IDI_AUDIOCD 303 -#define IDI_UNKNOWN 304 -#define IDR_AVI_FILECOPY 400 -#define IDR_HTML_INFO 500 -#define IDR_HTML_INDEX 501 -#define IDR_HTML_404 502 -#define IDR_HTML_BROWSER 503 -#define IDR_HTML_CONTROLS 504 -#define IDR_HTML_PLAYER 505 -#define IDF_DEFAULT_CSS 506 -#define IDF_VBR_PNG 507 -#define IDF_VBS_PNG 508 -#define IDF_SLIDERGRIP_PNG 509 -#define IDF_1PIX_PNG 510 -#define IDF_SLIDERBACK_PNG 511 -#define IDF_HEADERICON_PNG 512 -#define IDF_HEADERBACK_PNG 513 -#define IDF_HEADERCLOSE_PNG 514 -#define IDF_LEFTSIDE_PNG 515 -#define IDF_RIGHTSIDE_PNG 516 -#define IDF_BOTTOMSIDE_PNG 517 -#define IDF_LEFTBOTTOMSIDE_PNG 518 -#define IDF_RIGHTBOTTOMSIDE_PNG 519 -#define IDF_SEEKBARLEFT_PNG 520 -#define IDF_SEEKBARMID_PNG 521 -#define IDF_SEEKBARRIGHT_PNG 522 -#define IDF_SEEKBARGRIP_PNG 523 -#define IDF_CONTROLBACK_PNG 524 -#define IDF_CONTROLBUTTONPLAY_PNG 525 -#define IDF_CONTROLBUTTONPAUSE_PNG 526 -#define IDF_CONTROLBUTTONSTOP_PNG 527 -#define IDF_CONTROLBUTTONSKIPBACK_PNG 528 -#define IDF_CONTROLBUTTONDECRATE_PNG 529 -#define IDF_CONTROLBUTTONINCRATE_PNG 530 -#define IDF_CONTROLBUTTONSKIPFORWARD_PNG 531 -#define IDF_CONTROLBUTTONSTEP_PNG 532 -#define IDF_CONTROLVOLUMEON_PNG 533 -#define IDF_CONTROLVOLUMEOFF_PNG 534 -#define IDF_CONTROLVOLUMEBAR_PNG 535 -#define IDF_CONTROLVOLUMEGRIP_PNG 536 -#define IDR_HTML_VARIABLES 537 -#define IDF_JAVASCRIPT 538 -#define IDF_FAVICON 539 -#define IDF_SHADER_RESIZER 700 -#define IDF_SHADER_EMPTY 701 -#define IDF_SHADER_FINAL 702 -#define IDF_SVG_TOOLBAR 703 -#define IDF_SVG_BUTTONS 704 -#define IDF_SVG_ARROW 705 -#define ID_FILE_OPENMEDIA 800 -#define ID_FILE_OPENDVDBD 801 -#define ID_FILE_OPENDEVICE 802 -#define ID_FILE_CLOSEMEDIA 803 -#define ID_FILE_CLOSE_AND_RESTORE 804 -#define ID_FILE_SAVE_COPY 805 -#define ID_FILE_SAVE_IMAGE 806 -#define ID_FILE_SAVE_IMAGE_AUTO 807 -#define ID_FILE_SAVE_THUMBNAILS 808 -#define ID_FILE_SUBTITLES_LOAD 809 -#define ID_FILE_SUBTITLES_SAVE 810 -#define ID_FILE_SUBTITLES_DOWNLOAD 812 -#define ID_VIEW_ZOOM_25 813 -#define ID_FILE_PROPERTIES 814 -#define ID_VIEW_OPTIONS 815 -#define ID_FILE_EXIT 816 -#define ID_VIEW_CAPTIONMENU 817 -#define ID_VIEW_SEEKER 818 -#define ID_VIEW_CONTROLS 819 -#define ID_VIEW_INFORMATION 820 -#define ID_VIEW_STATISTICS 821 -#define ID_VIEW_STATUS 822 -#define ID_VIEW_SUBRESYNC 823 -#define ID_VIEW_PLAYLIST 824 -#define ID_VIEW_CAPTURE 825 -#define ID_VIEW_DEBUGSHADERS 826 -#define ID_VIEW_PRESETS_MINIMAL 827 -#define ID_VIEW_PRESETS_COMPACT 828 -#define ID_VIEW_PRESETS_NORMAL 829 -#define ID_VIEW_FULLSCREEN 830 -#define ID_VIEW_FULLSCREEN_SECONDARY 831 -#define ID_VIEW_ZOOM_50 832 -#define ID_VIEW_ZOOM_100 833 -#define ID_VIEW_ZOOM_200 834 -#define ID_VIEW_VF_HALF 835 -#define ID_VIEW_VF_NORMAL 836 -#define ID_VIEW_VF_DOUBLE 837 -#define ID_VIEW_VF_STRETCH 838 -#define ID_VIEW_VF_FROMINSIDE 839 -#define ID_VIEW_VF_FROMOUTSIDE 840 -#define ID_VIEW_VF_ZOOM1 841 -#define ID_VIEW_VF_ZOOM2 842 -#define ID_VIEW_VF_SWITCHZOOM 843 -#define ID_VIEW_VF_COMPMONDESKARDIFF 845 -#define ID_VIEW_EDITLISTEDITOR 846 -#define ID_EDL_IN 847 -#define ID_EDL_OUT 848 -#define ID_EDL_NEWCLIP 849 -#define ID_ASPECTRATIO_START 850 -#define ID_ASPECTRATIO_DAR 850 -#define ID_ASPECTRATIO_4_3 851 -#define ID_ASPECTRATIO_5_4 852 -#define ID_ASPECTRATIO_16_9 853 -#define ID_ASPECTRATIO_235_100 854 -#define ID_ASPECTRATIO_185_100 855 -#define ID_ASPECTRATIO_SAR 856 -#define ID_ASPECTRATIO_END 856 -#define ID_ASPECTRATIO_NEXT 859 -#define ID_EDL_SAVE 860 -#define ID_VIEW_RESET 861 -#define ID_VIEW_INCSIZE 862 -#define ID_VIEW_DECSIZE 863 -#define ID_VIEW_INCWIDTH 864 -#define ID_VIEW_DECWIDTH 865 -#define ID_VIEW_INCHEIGHT 866 -#define ID_VIEW_DECHEIGHT 867 -#define ID_PANSCAN_MOVELEFT 868 -#define ID_PANSCAN_MOVERIGHT 869 -#define ID_PANSCAN_MOVEUP 870 -#define ID_PANSCAN_MOVEDOWN 871 -#define ID_PANSCAN_MOVEUPLEFT 872 -#define ID_PANSCAN_MOVEUPRIGHT 873 -#define ID_PANSCAN_MOVEDOWNLEFT 874 -#define ID_PANSCAN_MOVEDOWNRIGHT 875 -#define ID_PANSCAN_CENTER 876 -#define ID_PANSCAN_ROTATEXP 877 -#define ID_PANSCAN_ROTATEXM 878 -#define ID_PANSCAN_ROTATEYP 879 -#define ID_PANSCAN_ROTATEYM 880 -#define ID_PANSCAN_ROTATEZP 881 -#define ID_PANSCAN_ROTATEZM 882 -#define ID_ONTOP_DEFAULT 883 -#define ID_ONTOP_ALWAYS 884 -#define ID_ONTOP_WHILEPLAYING 885 -#define ID_ONTOP_WHILEPLAYINGVIDEO 886 -#define ID_PLAY_PLAY 887 -#define ID_PLAY_PAUSE 888 -#define ID_PLAY_PLAYPAUSE 889 -#define IDS_SHADERNOTES 889 -#define ID_PLAY_STOP 890 -#define ID_PLAY_FRAMESTEP 891 -#define ID_PLAY_FRAMESTEP_BACK 892 -#define ID_NAVIGATE_GOTO 893 -#define ID_PLAY_DECRATE 894 -#define ID_PLAY_INCRATE 895 -#define ID_PLAY_RESETRATE 896 -#define ID_PLAY_SEEKKEYBACKWARD 897 -#define ID_PLAY_SEEKKEYFORWARD 898 -#define ID_PLAY_SEEKBACKWARDSMALL 899 -#define ID_PLAY_SEEKFORWARDSMALL 900 -#define ID_PLAY_SEEKBACKWARDMED 901 -#define ID_PLAY_SEEKFORWARDMED 902 -#define ID_PLAY_SEEKBACKWARDLARGE 903 -#define ID_PLAY_SEEKFORWARDLARGE 904 -#define ID_PLAY_INCAUDDELAY 905 -#define ID_PLAY_DECAUDDELAY 906 -#define ID_VOLUME_UP 907 -#define ID_VOLUME_DOWN 908 -#define ID_VOLUME_MUTE 909 -#define ID_VOLUME_MUTE_OFF 910 -#define ID_VOLUME_MUTE_DISABLED 911 -#define ID_AFTERPLAYBACK_EXIT 912 -#define ID_AFTERPLAYBACK_STANDBY 913 -#define ID_AFTERPLAYBACK_HIBERNATE 914 -#define ID_AFTERPLAYBACK_SHUTDOWN 915 -#define ID_AFTERPLAYBACK_LOGOFF 916 -#define ID_AFTERPLAYBACK_LOCK 917 -#define ID_AFTERPLAYBACK_MONITOROFF 918 -#define ID_NAVIGATE_SKIPBACKFILE 919 -#define ID_NAVIGATE_SKIPFORWARDFILE 920 -#define ID_NAVIGATE_SKIPBACK 921 -#define ID_NAVIGATE_SKIPFORWARD 922 -#define ID_NAVIGATE_TITLEMENU 923 -#define ID_NAVIGATE_ROOTMENU 924 -#define ID_NAVIGATE_SUBPICTUREMENU 925 -#define ID_NAVIGATE_AUDIOMENU 926 -#define ID_NAVIGATE_ANGLEMENU 927 -#define ID_NAVIGATE_CHAPTERMENU 928 -#define ID_NAVIGATE_MENU_LEFT 929 -#define ID_NAVIGATE_MENU_RIGHT 930 -#define ID_NAVIGATE_MENU_UP 931 -#define ID_NAVIGATE_MENU_DOWN 932 -#define ID_NAVIGATE_MENU_ACTIVATE 933 -#define ID_NAVIGATE_MENU_BACK 934 -#define ID_NAVIGATE_MENU_LEAVE 935 -#define ID_FAVORITES 936 -#define ID_FAVORITES_ORGANIZE 937 -#define ID_FAVORITES_ADD 938 -#define ID_HELP_HOMEPAGE 939 -#define ID_HELP_DONATE 940 -#define ID_HELP_SHOWCOMMANDLINESWITCHES 941 -#define ID_HELP_TOOLBARIMAGES 942 -#define ID_HELP_ABOUT 943 -#define ID_BOSS 944 -#define ID_DUMMYSEPARATOR 945 -#define ID_BUTTONSEP 946 -#define ID_AFTERPLAYBACK_PLAYNEXT 947 -#define ID_AFTERPLAYBACK_DONOTHING 948 -#define ID_MENU_PLAYER_SHORT 949 -#define ID_MENU_PLAYER_LONG 950 -#define ID_MENU_FILTERS 951 -#define ID_STREAM_AUDIO_NEXT 952 -#define ID_STREAM_AUDIO_PREV 953 -#define ID_STREAM_SUB_NEXT 954 -#define ID_STREAM_SUB_PREV 955 -#define ID_STREAM_SUB_ONOFF 956 -#define ID_AUDIOSHIFT_ONOFF 960 -#define ID_DVD_ANGLE_NEXT 961 -#define ID_DVD_ANGLE_PREV 962 -#define ID_DVD_AUDIO_NEXT 963 -#define ID_DVD_AUDIO_PREV 964 -#define ID_DVD_SUB_NEXT 965 -#define ID_DVD_SUB_PREV 966 -#define ID_DVD_SUB_ONOFF 967 -#define ID_VIEW_ZOOM_AUTOFIT 968 -#define ID_FILE_OPENQUICK 969 -#define ID_VOLUME_BOOST_INC 970 -#define ID_VOLUME_BOOST_DEC 971 -#define ID_VOLUME_BOOST_MIN 972 -#define ID_VOLUME_BOOST_MAX 973 -#define ID_NAVIGATE_TUNERSCAN 974 -#define ID_FAVORITES_QUICKADDFAVORITE 975 -#define ID_FILE_REOPEN 976 -#define ID_FILTERS 977 -#define ID_AUDIOS 978 -#define ID_SUBTITLES 979 -#define ID_VIDEO_STREAMS 980 -#define ID_COLOR_BRIGHTNESS_INC 984 -#define ID_COLOR_BRIGHTNESS_DEC 985 -#define ID_COLOR_CONTRAST_INC 986 -#define ID_COLOR_CONTRAST_DEC 987 -#define ID_COLOR_HUE_INC 988 -#define ID_COLOR_HUE_DEC 989 -#define ID_COLOR_SATURATION_INC 990 -#define ID_COLOR_SATURATION_DEC 991 -#define ID_COLOR_RESET 992 -#define ID_CUSTOM_CHANNEL_MAPPING 993 -#define ID_NORMALIZE 994 -#define ID_REGAIN_VOLUME 995 -#define ID_PLAY_SEEKSET 996 -#define ID_PANSCAN_ROTATEZ270 997 -#define ID_PRESIZE_SHADERS_TOGGLE 998 -#define ID_POSTSIZE_SHADERS_TOGGLE 999 -#define ID_FILTERS_COPY_TO_CLIPBOARD 1999 -#define ID_FILTERS_SUBITEM_START 2000 -#define ID_FILTERS_SUBITEM_END 2099 -#define ID_FILTERSTREAMS_SUBITEM_START 2100 -#define ID_FILTERSTREAMS_SUBITEM_END 2199 -#define ID_AUDIO_SUBITEM_START 2200 -#define ID_AUDIO_SUBITEM_END 2299 -#define ID_SUBTITLES_SUBITEM_START 2300 -#define ID_SUBTITLES_SUBITEM_END 2399 -#define ID_VIDEO_STREAMS_SUBITEM_START 2400 -#define ID_VIDEO_STREAMS_SUBITEM_END 2499 -#define ID_FAVORITES_FILE_START 2800 -#define ID_FAVORITES_FILE_END 3799 -#define ID_FAVORITES_DVD_START 3800 -#define ID_FAVORITES_DVD_END 3899 -#define ID_FAVORITES_DEVICE_START 3900 -#define ID_FAVORITES_DEVICE_END 3999 -#define ID_FILE_OPEN_OPTICAL_DISK_START 4000 -#define ID_FILE_OPEN_OPTICAL_DISK_END 4099 -#define ID_PANNSCAN_PRESETS_START 4100 -#define ID_PANNSCAN_PRESETS_END 4199 -#define ID_SHADERS_SELECT 4200 -#define ID_SHADERS_PRESETS_START 4201 -#define ID_SHADERS_PRESETS_END 4299 -#define ID_NAVIGATE_JUMPTO_SUBITEM_START 4300 -#define ID_NAVIGATE_JUMPTO_SUBITEM_END 4899 -#define ID_VIEW_ZOOM_AUTOFIT_LARGER 4900 -#define ID_PLAY_PLAYBACKRATE_START 5000 -#define ID_PLAY_PLAYBACKRATE_025 5001 -#define ID_PLAY_PLAYBACKRATE_050 5002 -#define ID_PLAY_PLAYBACKRATE_075 5003 -#define ID_PLAY_PLAYBACKRATE_090 5004 -#define ID_PLAY_PLAYBACKRATE_100 5005 -#define ID_PLAY_PLAYBACKRATE_110 5006 -#define ID_PLAY_PLAYBACKRATE_125 5007 -#define ID_PLAY_PLAYBACKRATE_150 5008 -#define ID_PLAY_PLAYBACKRATE_200 5009 -#define ID_PLAY_PLAYBACKRATE_300 5010 -#define ID_PLAY_PLAYBACKRATE_400 5011 -#define ID_PLAY_PLAYBACKRATE_600 5012 -#define ID_PLAY_PLAYBACKRATE_800 5013 -#define ID_PLAY_PLAYBACKRATE_FPS24 5020 -#define ID_PLAY_PLAYBACKRATE_FPS25 5021 -#define ID_PLAY_PLAYBACKRATE_END 5029 -#define ID_PLAYLIST_TOGGLE_SHUFFLE 5030 -#define ID_CMDLINE_SAVE_THUMBNAILS 5031 -#define ID_MOUSE_ADD_CMD 5032 -#define IDS_FILTER_SETTINGS_CAPTION 7000 -#define IDD_OPEN_DLG 10000 -#define IDD_MEDIATYPES_DLG 10002 -#define IDD_SAVE_DLG 10004 -#define IDD_SUBTITLEDL_DLG 10005 -#define IDD_FILEPROPDETAILS 10010 -#define IDD_FILEPROPCLIP 10011 -#define IDD_PNSPRESET_DLG 10015 -#define IDD_GOTO_DLG 10016 -#define IDD_FAVADD 10017 -#define IDD_FAVORGANIZE 10018 -#define IDD_ABOUTBOX 10019 -#define IDD_PLAYERINFOBAR 10020 -#define IDD_PLAYERSTATUSBAR 10021 -#define IDD_PLAYERSEEKBAR 10022 -#define IDD_PPAGEPLAYBACK 10023 -#define IDD_PPAGEPLAYER 10024 -#define IDD_PPAGEDVD 10025 -#define IDD_PPAGESUBTITLES 10026 -#define IDD_PPAGEFORMATS 10027 -#define IDD_PPAGETWEAKS 10028 -#define IDD_PPAGEAUDIOSWITCHER 10029 -#define IDD_PPAGEEXTERNALFILTERS 10030 -#define IDD_PPAGESHADERS 10031 -#define IDD_PPAGEACCELTBL 10032 -#define IDD_PPAGESUBSTYLE 10033 -#define IDD_PPAGEINTERNALFILTERS 10036 -#define IDD_PPAGELOGO 10037 -#define IDD_PPAGETHEME 10038 -#define IDD_PPAGEOUTPUT 10039 -#define IDD_PPAGEWEBSERVER 10040 -#define IDD_CAPTURE_DLG 10045 -#define IDD_ADDREGFILTER 10046 -#define IDD_SELECTMEDIATYPE 10047 -#define IDD_COMPROPERTYPAGE 10048 -#define IDD_FILEPROPRES 10049 -#define IDD_PPAGEMISC 10052 -#define IDD_FILEMEDIAINFO 10053 -#define IDD_PPAGECAPTURE 10054 -#define IDD_PPAGESYNC 10055 -#define IDD_PPAGEFULLSCREEN 10056 -#define IDD_RFS_FILELIST_EXT 10057 -#define IDD_PPAGEAUDIORENDERER 10058 -#define IDD_PPAGEMOUSE 10059 -#define IDC_COMBO1 11000 -#define IDC_COMBO2 11001 -#define IDC_COMBO3 11002 -#define IDC_COMBO4 11003 -#define IDC_COMBO5 11004 -#define IDC_COMBO6 11005 -#define IDC_COMBO7 11006 -#define IDC_COMBO8 11007 -#define IDC_COMBO9 11008 -#define IDC_COMBO10 11009 -#define IDC_COMBO11 11010 -#define IDC_COMBO12 11011 -#define IDC_COMBO14 11013 -#define IDC_SLIDER1 11020 -#define IDC_SLIDER2 11021 -#define IDC_SLIDER3 11022 -#define IDC_SLIDER4 11023 -#define IDC_SLI_BRIGHTNESS 11025 -#define IDC_SLI_HUE 11026 -#define IDC_SLI_SATURATION 11027 -#define IDC_RADIO1 11040 -#define IDC_RADIO2 11041 -#define IDC_RADIO3 11042 -#define IDC_RADIO4 11043 -#define IDC_RADIO5 11044 -#define IDC_RADIO6 11045 -#define IDC_RADIO7 11046 -#define IDC_RADIO8 11047 -#define IDC_RADIO9 11048 -#define IDC_RADIO10 11049 -#define IDC_RADIO11 11050 -#define IDC_EDIT1 11060 -#define IDC_EDIT3 11061 -#define IDC_EDIT2 11062 -#define IDC_EDIT4 11063 -#define IDC_EDIT5 11064 -#define IDC_EDIT6 11065 -#define IDC_EDIT7 11066 -#define IDC_EDIT8 11067 -#define IDC_EDIT9 11068 -#define IDC_EDIT10 11069 -#define IDC_WINHOTKEY1 11070 -#define IDC_CHECK1 11080 -#define IDC_CHECK2 11081 -#define IDC_CHECK3 11082 -#define IDC_CHECK4 11083 -#define IDC_CHECK5 11084 -#define IDC_CHECK6 11085 -#define IDC_CHECK7 11086 -#define IDC_CHECK8 11087 -#define IDC_CHECK9 11088 -#define IDC_CHECK10 11089 -#define IDC_CHECK11 11090 -#define IDC_CHECK12 11091 -#define IDC_CHECK13 11092 -#define IDC_CHECK14 11093 -#define IDC_SPIN1 11100 -#define IDC_SPIN2 11101 -#define IDC_SPIN3 11102 -#define IDC_SPIN4 11103 -#define IDC_SPIN5 11104 -#define IDC_SPIN6 11105 -#define IDC_SPIN7 11106 -#define IDC_SPIN8 11107 -#define IDC_SPIN9 11108 -#define IDC_SPIN10 11109 -#define IDC_BUTTON1 11120 -#define IDC_BUTTON2 11121 -#define IDC_BUTTON3 11122 -#define IDC_BUTTON4 11123 -#define IDC_BUTTON5 11124 -#define IDC_BUTTON6 11125 -#define IDC_BUTTON7 11126 -#define IDC_BUTTON8 11127 -#define IDC_BUTTON9 11128 -#define IDC_BUTTON10 11129 -#define IDC_BUTTON11 11130 -#define IDC_BUTTON12 11131 -#define IDC_BUTTON13 11132 -#define IDC_RESET_SETTINGS 11133 -#define IDC_EXPORT_SETTINGS 11134 -#define IDC_TREE1 11140 -#define IDC_LIST1 11160 -#define IDC_LIST2 11161 -#define IDC_LIST3 11162 -#define IDC_TAB1 11200 -#define IDC_ANIMATE1 11220 -#define IDC_PROGRESS1 11240 -#define IDC_STATIC1 11260 -#define IDC_STATIC2 11261 -#define IDC_STATIC3 11262 -#define IDC_STATIC4 11263 -#define IDC_STATIC5 11264 -#define IDC_STATIC6 11265 -#define IDC_STATIC7 11266 -#define IDC_STATIC8 11267 -#define IDC_STATIC9 11268 -#define IDC_STATIC10 11269 -#define IDC_STATIC11 11270 -#define IDC_DVDPATH 12000 -#define IDC_SUBRESYNCLIST 12001 -#define IDC_PLAYLIST 12002 -#define IDC_COLORPRI 12003 -#define IDC_COLORSEC 12004 -#define IDC_COLOROUTL 12005 -#define IDC_COLORSHAD 12006 -#define IDC_STATICLINK 12007 -#define IDC_STATICLINK2 12008 -#define IDC_DEFAULTICON 12009 -#define IDC_PLACEHOLDER 12010 -#define IDC_REPORT 12011 -#define IDC_FROMTO 12012 -#define IDC_STATIC_BALANCE 12013 -#define IDC_LOGOPREVIEW 12014 -#define IDC_LOGOFILENAME 12016 -#define IDC_AUTHOR 12018 -#define IDC_CHECK_RELATIVETO 12019 -#define IDC_CHECK_NO_SUB_ANIM 12021 -#define IDC_SUBPIC_TO_BUFFER 12022 -#define IDC_BUTTON_EXT_SET 12023 -#define IDC_OK1 12024 -#define IDC_OK2 12025 -#define IDC_PLAYERSTATUS 12026 -#define IDC_PLAYERTIME 12027 -#define IDC_EDITLIST 12028 -#define IDC_CHECK_SUB_AR_COMPENSATION 12029 -#define IDC_CHECK_ALLOW_DROPPING_SUBPIC 12030 -#define IDC_DSSYSDEF 12100 -#define IDC_DSOVERLAYMIXER 12102 -#define IDC_DSVMR9WIN 12104 -#define IDC_DSVMR9REN 12106 -#define IDC_DSDXR 12107 -#define IDC_DSNULL_COMP 12108 -#define IDC_DSNULL_UNCOMP 12109 -#define IDC_DSEVR_CUSTOM 12111 -#define IDC_DSMADVR 12112 -#define IDC_DSSYNC 12113 -#define IDC_REGULARSURF 12127 -#define IDC_TEXTURESURF2D 12128 -#define IDC_TEXTURESURF3D 12129 -#define IDC_DX9RESIZER_COMBO 12130 -#define IDC_DSVMR9LOADMIXER 12131 -#define IDC_DX_SURFACE 12133 -#define IDC_BUTTON_MI 12136 -#define IDC_MIEDIT 12137 -#define IDC_LISTCHANNELS 12138 -#define IDC_STATUSBAR 12139 -#define IDC_PPAGECAPTURE_DESC1 12140 -#define IDC_DSMPCVR 12141 -#define IDS_SRC_VTS 14002 -#define IDS_SRC_RFS 14003 -#define IDS_INTERNAL_LAVF 14004 -#define IDS_INTERNAL_LAVF_WMV 14005 -#define IDS_AG_OPEN_FILE_LOCATION 14006 -#define IDS_AG_OPENDIRECTORY 14007 -#define IDS_PLAYLIST_OPEN 14114 -#define IDS_PLAYLIST_ADD 14115 -#define IDS_PLAYLIST_REMOVE 14116 -#define IDS_PLAYLIST_CLEAR 14117 -#define IDS_PLAYLIST_COPYTOCLIPBOARD 14118 -#define IDS_PLAYLIST_SAVE 14119 -#define IDS_PLAYLIST_SAVEAS 14120 -#define IDS_PLAYLIST_SORTBYLABEL 14121 -#define IDS_PLAYLIST_SORTBYPATH 14122 -#define IDS_PLAYLIST_RANDOMIZE 14123 -#define IDS_PLAYLIST_RESTORE 14124 -#define IDS_SUBRESYNC_SEPARATOR 14125 -#define IDS_SUBRESYNC_DELETE 14126 -#define IDS_SUBRESYNC_DUPLICATE 14127 -#define IDS_SUBRESYNC_RESET 14128 -#define IDS_SUBRESYNC_ORIGINAL 14129 -#define IDS_SUBRESYNC_CURRENT 14130 -#define IDS_SUBRESYNC_EDIT 14131 -#define IDS_SUBRESYNC_YES 14132 -#define IDS_SUBRESYNC_NO 14133 -#define IDS_SUBRESYNC_DECREASE 14134 -#define IDS_SUBRESYNC_INCREASE 14135 -#define IDS_OPTIONS_CAPTION 14136 -#define IDS_SHADERS_SELECT 14137 -#define IDS_SHADERS_DEBUG 14138 -#define IDS_FAVORITES_ADD 14153 -#define IDS_FAVORITES_ORGANIZE 14154 -#define IDS_PLAYLIST_SHUFFLE 14155 -#define IDS_PLAYLIST_SHOWFOLDER 14156 -#define IDS_CONTROLS_CLOSING 14157 -#define IDS_CONTROLS_PLAYING 14158 -#define IDS_CONTROLS_PAUSED 14159 -#define IDS_CONTROLS_STOPPED 14160 -#define IDS_CONTROLS_BUFFERING 14161 -#define IDS_CONTROLS_CAPTURING 14162 -#define IDS_CONTROLS_OPENING 14163 -#define IDS_CONTROLS_CLOSED 14164 -#define IDS_SUBTITLES_OPTIONS 14165 -#define IDS_SUBTITLES_STYLES 14166 -#define IDS_SUBTITLES_RELOAD 14167 -#define IDS_SUBTITLES_HIDE 14168 -#define IDS_PANSCAN_EDIT 14169 -#define IDS_INFOBAR_TITLE 14170 -#define IDS_INFOBAR_AUTHOR 14171 -#define IDS_INFOBAR_COPYRIGHT 14172 -#define IDS_INFOBAR_RATING 14173 -#define IDS_INFOBAR_DESCRIPTION 14174 -#define IDS_INFOBAR_DOMAIN 14175 -#define IDS_INFOBAR_LOCATION 14176 -#define IDS_INFOBAR_VIDEO 14177 -#define IDS_INFOBAR_AUDIO 14178 -#define IDS_INFOBAR_SUBTITLES 14179 -#define IDS_INFOBAR_CHAPTER 14180 -#define IDS_CONTROLS_COMPLETING 14181 -#define IDS_AUTOPLAY_PLAYVIDEO 14182 -#define IDS_AUTOPLAY_PLAYMUSIC 14183 -#define IDS_AUTOPLAY_PLAYAUDIOCD 14184 -#define IDS_AUTOPLAY_PLAYDVDMOVIE 14185 -#define IDS_PROPSHEET_PROPERTIES 14186 -#define IDS_PLAY_LOOPMODE_FILE 14187 -#define IDS_SUB_OVERRIDE_DEFAULT_STYLE 14188 -#define IDS_PLAY_LOOPMODE_PLAYLIST 14189 -#define IDS_FAVFILES 14190 -#define IDS_FAVDVDS 14191 -#define IDS_INFOBAR_CHANNEL 14192 -#define IDS_INFOBAR_TIME 14193 -#define IDS_STATSBAR_SYNC_OFFSET 14194 -#define IDS_STATSBAR_SYNC_OFFSET_FORMAT 14195 -#define IDS_STATSBAR_JITTER 14196 -#define IDS_STATSBAR_BITRATE 14197 -#define IDS_STATSBAR_BITRATE_AVG_CUR 14198 -#define IDS_STATSBAR_SIGNAL 14199 -#define IDS_STATSBAR_SIGNAL_FORMAT 14200 -#define IDS_SUBTITLES_STYLES_CAPTION 14201 -#define IDS_TEXT_SUB_RENDERING_TARGET 14202 -#define IDS_PLAYLOOPMODE_PLAYLIST 14203 -#define IDS_PLAYLOOPMODE_FILE 14204 -#define IDS_PLAYLOOP_FOREVER_ON 14205 -#define IDS_PLAYLOOP_FOREVER_OFF 14206 -#define IDS_PLAYLOOP_FOREVER 14207 -#define IDS_PLAYLOOPMODE_AB 14208 -#define IDS_PLAY_LOOPMODE_AB 14209 -#define IDS_PLAYLOOPMODE_AB_MARK_A 14210 -#define IDS_PLAYLOOPMODE_AB_MARK_B 14211 -#define IDS_SNAPSHOT_SUBTITLES 14212 -#define IDS_THEMEMODE_DARK 14213 -#define IDS_THEMEMODE_LIGHT 14214 -#define IDS_THEMEMODE_WINDOWS 14215 -#define IDS_SUB_OVERRIDE_ALL_STYLES 14216 -#define IDD_TUNER_SCAN 20002 -#define IDS_OSD_DISPLAY_RENDERER_STATS 20003 -#define IDD_PPAGELOGO2 20003 -#define IDS_OSD_RESET_RENDERER_STATS 20004 -#define IDD_NAVIGATION_DLG 20005 -#define IDD_PPAGESUBMISC 20006 -#define IDS_VIEW_BORDERLESS 20007 -#define IDS_VIEW_FRAMEONLY 20008 -#define IDS_VIEW_CAPTIONMENU 20009 -#define IDS_VIEW_HIDEMENU 20010 -#define IDD_UPDATE_DIALOG 20011 -#define IDF_WIN7_TOOLBAR 20012 -#define IDD_DEBUGSHADERS_DLG 20013 -#define IDD_PPAGEADVANCED 20014 -#define IDD_CMD_LINE_HELP 20016 -#define IDD_CRASH_REPORTER 20017 -#define IDD_PPAGEDPICALC 20018 -#define IDD_RAR_ENTRY_SELECTOR 20019 -#define IDD_ADDCOMMAND_DLG 20020 -#define IDD_PPAGETOOLBAR 20021 -#define IDB_DT_CB_96 20050 -#define IDB_DT_CB_120 20051 -#define IDB_DT_CB_144 20052 -#define IDB_DT_CB_192 20053 -#define IDB_DT_RADIO_96 20054 -#define IDB_DT_RADIO_120 20055 -#define IDB_DT_RADIO_144 20056 -#define IDB_DT_RADIO_129 20057 -#define IDB_DT_RADIO_192 20057 -#define IDS_MESSAGEBOX_CANCEL 20059 -#define IDS_MESSAGEBOX_ABORT 20060 -#define IDS_MESSAGEBOX_RETRY 20061 -#define IDS_MESSAGEBOX_IGNORE 20062 -#define IDS_MESSAGEBOX_OK 20063 -#define IDS_MESSAGEBOX_CONTINUE 20064 -#define IDS_AG_TOGGLE_DEFAULT_SUBTITLE_STYLE 20065 -#define ID_FILE_OPEN_LOCATION 20066 -#define IDB_NOIMAGE 20067 -#define IDB_GRIPPER_168 20070 -#define IDB_GRIPPER_144 20071 -#define IDB_GRIPPER_192 20073 -#define IDB_GRIPPER_96 20074 -#define IDB_PNG1 20075 -#define IDB_GRIPPER_120 20075 -#define IDI_OPENSUBTITLES 21001 -#define IDI_PODNAPISI 21002 -#define IDI_N24 21006 -#define IDC_FULLSCREEN_MONITOR_CHECK 22002 -#define IDC_SLI_CONTRAST 22003 -#define IDC_RESET 22004 -#define IDC_DVD_POS 22005 -#define IDC_FILE_POS 22006 -#define IDC_EVR_BUFFERS 22010 -#define IDC_VERSION 22011 -#define IDC_SHOW_OSD 22013 -#define IDC_EVR_BUFFERS_TXT 22014 -#define IDC_LAVFILTERS_VERSION 22016 -#define IDC_DSVMR9ALTERNATIVEVSYNC 22017 -#define IDC_HOMEPAGE_LINK 22018 -#define IDC_QUALITY 22019 -#define IDC_PROGRESS 22020 -#define IDC_FREQ_START 22021 -#define IDC_BANDWIDTH 22022 -#define IDC_FREQ_END 22023 -#define IDC_CHANNEL_LIST 22024 -#define ID_START 22025 -#define IDC_SYMBOLRATE 22026 -#define ID_SAVE 22030 -#define IDC_STRENGTH 22031 -#define IDC_SYNCVIDEO 22032 -#define IDC_SYNCDISPLAY 22033 -#define IDC_CYCLEDELTA 22034 -#define IDC_LINEDELTA 22035 -#define IDC_COLUMNDELTA 22036 -#define IDC_TARGETSYNCOFFSET 22037 -#define IDC_CONTROLLIMIT 22038 -#define IDC_SYNCNEAREST 22040 -#define IDC_D3D9DEVICE 22041 -#define IDC_NAVIGATION_SCAN 22043 -#define IDC_D3D9DEVICE_COMBO 22045 -#define IDC_NAVIGATION_INFO 22046 -#define IDC_NAVIGATION_FILTERSTATIONS 22047 -#define IDC_CHECK_OFFSET 22048 -#define IDC_OFFSET 22049 -#define IDC_CHECK_IGNORE_ENCRYPTED 22050 -#define IDC_UPDATE_DLG_TEXT 22051 -#define IDC_UPDATE_ICON 22052 -#define IDC_UPDATE_DL_BUTTON 22053 -#define IDC_UPDATE_LATER_BUTTON 22054 -#define IDC_UPDATE_IGNORE_BUTTON 22055 -#define IDC_AUTHORS_LINK 22056 -#define IDC_CHECK_LCD 22059 -#define IDC_VIDRND_COMBO 22060 -#define IDC_AUDRND_COMBO 22063 -#define IDC_VIDRND_DXVA_SUPPORT 22064 -#define IDC_VIDRND_SHADER_SUPPORT 22065 -#define IDC_VIDRND_SUBTITLE_SUPPORT 22066 -#define IDC_VIDRND_SAVEIMAGE_SUPPORT 22067 -#define IDC_VIDRND_ROTATION_SUPPORT 22068 -#define IDC_VOLUMESTEP 22073 -#define IDC_VOLUMESTEP_SPIN 22074 -#define IDC_SPEEDSTEP 22075 -#define IDC_SPEEDSTEP_SPIN 22076 -#define IDC_EXPORT_KEYS 22077 -#define IDC_PPAGECAPTURE_ST10 22078 -#define IDC_PPAGECAPTURE_ST11 22079 -#define IDC_PPAGECAPTURE_ST12 22080 -#define IDC_FASTSEEK_CHECK 22081 -#define IDC_ASSOCIATE_ALL_FORMATS 22082 -#define IDC_ASSOCIATE_VIDEO_FORMATS 22083 -#define IDC_ASSOCIATE_AUDIO_FORMATS 22084 -#define IDC_CLEAR_ALL_ASSOCIATIONS 22085 -#define IDC_SEEK_PREVIEW 22086 -#define IDC_CHECK_AUTOSAVE_ONLINE_SUBTITLE 22087 -#define IDC_STATIC21 22088 -#define IDC_STATIC22 22089 -#define IDC_STATIC23 22090 -#define IDC_STATIC_LIBASS 22091 -#define IDC_MODERNSEEKBARHEIGHT 22092 -#define IDC_MODERNSEEKBARHEIGHT_SPIN 22093 -#define ID_SUB_DELAY_DOWN 24000 -#define ID_SUB_DELAY_UP 24001 -#define IDS_MPLAYERC_104 24002 -#define IDS_MPLAYERC_105 24003 -#define IDS_FILE_SAVE_THUMBNAILS 24005 -#define ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION 24028 -#define ID_VIEW_FULLFLOATINGPOINTPROCESSING 24029 -#define ID_VIEW_CM_ENABLE 24030 -#define ID_VIEW_CM_INPUT_AUTO 24031 -#define ID_VIEW_CM_INPUT_HDTV 24032 -#define ID_VIEW_CM_INPUT_SDTV_NTSC 24033 -#define ID_VIEW_CM_INPUT_SDTV_PAL 24034 -#define ID_VIEW_CM_AMBIENTLIGHT_BRIGHT 24035 -#define ID_VIEW_CM_AMBIENTLIGHT_DIM 24037 -#define ID_VIEW_CM_AMBIENTLIGHT_DARK 24038 -#define ID_VIEW_CM_INTENT_PERCEPTUAL 24039 -#define ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC 24040 -#define ID_VIEW_CM_INTENT_SATURATION 24041 -#define ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC 24042 -#define ID_VIEW_HALFFLOATINGPOINTPROCESSING 24043 -#define ID_FILE_RECYCLE 24044 -#define ID_VIEW_MPCTHEME 24045 -#define PLAYER_PLAYLIST_UPDATE_SCROLLBAR 24048 -#define IDF_LOGO4 24050 -#define ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE 24051 -#define ID_SUB_POS_DOWN 24052 -#define ID_SUB_POS_UP 24053 -#define ID_SUB_FONT_SIZE_DEC 24054 -#define ID_SUB_FONT_SIZE_INC 24055 -#define IDS_SUB_POS_DOWN 24056 -#define IDS_SUB_POS_UP 24057 -#define IDS_SUB_FONT_SIZE_DEC 24058 -#define IDS_SUB_FONT_SIZE_INC 24059 -#define ID_VIEW_TEARING_TEST 32769 -#define ID_FILE_OPENDISC 32774 -#define ID_SHADERS 32775 -#define ID_VIEW_OSD_SHOW_FILENAME 32777 -#define ID_VIEW_OSD_DISPLAY_TIME 32778 -#define ID_D3DFULLSCREEN_TOGGLE 32779 -#define ID_GOTO_PREV_SUB 32780 -#define ID_GOTO_NEXT_SUB 32781 -#define ID_SUBRESYNC_SHIFT_DOWN 32782 -#define ID_SUBRESYNC_SHIFT_UP 32783 -#define ID_VIEW_DISPLAY_RENDERER_STATS 32784 -#define ID_VIEW_RESET_RENDERER_STATS 32785 -#define IDS_AG_CLOSE 32830 -#define IDS_AG_NONE 32832 -#define IDS_AG_COMMAND 32833 -#define IDS_AG_KEY 32834 -#define IDS_AG_MOUSE 32836 -#define IDS_AG_APP_COMMAND 32838 -#define IDS_AG_MEDIAFILES 32871 -#define IDS_AG_ALLFILES 32872 -#define IDS_AG_AUDIOFILES 32873 -#define IDS_AG_NOT_KNOWN 32876 -#define IDS_MPLAYERC_0 32877 -#define IDS_AG_OPEN_FILE 32878 -#define IDS_AG_OPEN_DVD 32879 -#define IDS_AG_OPEN_DEVICE 32880 -#define IDS_AG_SAVE_AS 32881 -#define IDS_AG_SAVE_IMAGE 32882 -#define IDS_MPLAYERC_6 32883 -#define IDS_OSD_IMAGE_SAVED 32884 -#define IDS_AG_LOAD_SUBTITLES 32885 -#define IDS_AG_SAVE_SUBTITLES 32886 -#define IDS_AG_PROPERTIES 32887 -#define IDS_AG_EXIT 32888 -#define IDS_AG_PLAYPAUSE 32889 -#define IDS_AG_PLAY 32890 -#define IDS_AG_STOP 32891 -#define IDS_AG_FRAMESTEP 32892 -#define IDS_MPLAYERC_16 32893 -#define IDS_AG_GO_TO 32894 -#define IDS_AG_INCREASE_RATE 32895 -#define IDS_AG_DECREASE_RATE 32896 -#define IDS_AG_RESET_RATE 32897 -#define IDS_MPLAYERC_21 32898 -#define IDS_MPLAYERC_22 32899 -#define IDS_MPLAYERC_23 32900 -#define IDS_MPLAYERC_24 32901 -#define IDS_MPLAYERC_25 32902 -#define IDS_MPLAYERC_26 32903 -#define IDS_MPLAYERC_27 32904 -#define IDS_MPLAYERC_28 32905 -#define IDS_MPLAYERC_29 32906 -#define IDS_MPLAYERC_30 32907 -#define IDS_AG_NEXT 32908 -#define IDS_AG_PREVIOUS 32909 -#define IDS_AG_NEXT_FILE 32910 -#define IDS_AG_PREVIOUS_FILE 32911 -#define IDS_AG_VIEW_MINIMAL 32912 -#define IDS_AG_VIEW_COMPACT 32913 -#define IDS_AG_VIEW_NORMAL 32914 -#define IDS_AG_FULLSCREEN 32915 -#define IDS_MPLAYERC_39 32916 -#define IDS_AG_ZOOM_AUTO_FIT 32917 -#define IDS_AG_VIDFRM_HALF 32918 -#define IDS_AG_VIDFRM_NORMAL 32919 -#define IDS_AG_VIDFRM_DOUBLE 32920 -#define IDS_AG_ALWAYS_ON_TOP 32921 -#define IDS_AG_PNS_INC_SIZE 32922 -#define IDS_AG_PNS_INC_WIDTH 32923 -#define IDS_MPLAYERC_47 32924 -#define IDS_AG_PNS_DEC_SIZE 32925 -#define IDS_AG_PNS_DEC_WIDTH 32926 -#define IDS_MPLAYERC_50 32927 -#define IDS_AG_PNS_CENTER 32928 -#define IDS_AG_PNS_LEFT 32929 -#define IDS_AG_PNS_RIGHT 32930 -#define IDS_AG_PNS_UP 32931 -#define IDS_AG_PNS_DOWN 32932 -#define IDS_AG_PNS_UPLEFT 32933 -#define IDS_AG_PNS_UPRIGHT 32934 -#define IDS_AG_PNS_DOWNLEFT 32935 -#define IDS_MPLAYERC_59 32936 -#define IDS_AG_VOLUME_UP 32937 -#define IDS_AG_VOLUME_DOWN 32938 -#define IDS_AG_VOLUME_MUTE 32939 -#define IDS_MPLAYERC_63 32940 -#define IDS_AG_DVD_ROOT_MENU 32941 -#define IDS_MPLAYERC_65 32942 -#define IDS_MPLAYERC_66 32943 -#define IDS_MPLAYERC_67 32944 -#define IDS_MPLAYERC_68 32945 -#define IDS_AG_DVD_MENU_LEFT 32946 -#define IDS_MPLAYERC_70 32947 -#define IDS_AG_DVD_MENU_UP 32948 -#define IDS_AG_DVD_MENU_DOWN 32949 -#define IDS_MPLAYERC_73 32950 -#define IDS_AG_DVD_MENU_BACK 32951 -#define IDS_MPLAYERC_75 32952 -#define IDS_AG_BOSS_KEY 32953 -#define IDS_MPLAYERC_77 32954 -#define IDS_MPLAYERC_78 32955 -#define IDS_AG_FILTERS_MENU 32956 -#define IDS_AG_OPTIONS 32957 -#define IDS_AG_NEXT_AUDIO 32958 -#define IDS_AG_PREV_AUDIO 32959 -#define IDS_AG_NEXT_SUBTITLE 32960 -#define IDS_AG_PREV_SUBTITLE 32961 -#define IDS_MPLAYERC_85 32962 -#define IDS_MPLAYERC_86 32963 -#define IDS_MPLAYERC_91 32968 -#define IDS_MPLAYERC_92 32969 -#define IDS_MPLAYERC_93 32970 -#define IDS_MPLAYERC_94 32971 -#define IDS_MPLAYERC_95 32972 -#define IDS_MPLAYERC_96 32973 -#define IDS_MPLAYERC_97 32974 -#define IDS_OSD_DISPLAY_CURRENT_TIME 32975 -#define IDS_MPLAYERC_99 32976 -#define IDS_MPLAYERC_100 32977 -#define IDS_MPLAYERC_101 32978 -#define IDS_MPLAYERC_102 32979 -#define IDS_MPLAYERC_103 32980 -#define IDS_AG_SEEKSET 32982 -#define IDS_OSD_SHOW_FILENAME 32983 -#define IDS_PLAY_DVD 32984 -#define IDS_PLAY_BD 32985 -#define IDS_PPAGEWEBSERVER_0 32996 -#define IDS_MAINFRM_2 33014 -#define IDS_AG_SUBTITLES_SAVED 33015 -#define IDS_MAINFRM_4 33016 -#define IDS_AG_FRAMERATE 33017 -#define IDS_MAINFRM_6 33018 -#define IDS_AG_FRAMES 33019 -#define IDS_AG_BUFFERS 33020 -#define IDS_MAINFRM_9 33021 -#define IDS_MAINFRM_10 33022 -#define IDS_MAINFRM_11 33023 -#define IDS_AG_TITLE 33024 -#define IDS_MAINFRM_16 33025 -#define IDS_MAINFRM_17 33026 -#define IDS_MAINFRM_18 33027 -#define IDS_MAINFRM_19 33028 -#define IDS_MAINFRM_20 33029 -#define IDS_MAINFRM_21 33030 -#define IDS_MAINFRM_22 33031 -#define IDS_MAINFRM_23 33032 -#define IDS_AG_ASPECT_RATIO 33045 -#define IDS_MAINFRM_37 33046 -#define IDS_MAINFRM_38 33047 -#define IDS_MAINFRM_39 33048 -#define IDS_MAINFRM_40 33049 -#define IDS_MAINFRM_41 33050 -#define IDS_MAINFRM_42 33051 -#define IDS_AG_ERROR 33052 -#define IDS_SUBTITLE_STREAM_OFF 33053 -#define IDS_SUBTITLE_STREAM 33054 -#define IDS_MAINFRM_46 33055 -#define IDS_SUB_LOADED_SUCCESS 33056 -#define IDS_ALL_FILES_FILTER 33057 -#define IDS_GETDIB_FAILED 33058 -#define IDS_GETCURRENTIMAGE_FAILED 33059 -#define IDS_SCREENSHOT_ERROR 33060 -#define IDS_THUMBNAILS_NO_DURATION 33061 -#define IDS_THUMBNAILS_NO_FRAME_SIZE 33062 -#define IDS_OUT_OF_MEMORY 33063 -#define IDS_THUMBNAILS_INVALID_FORMAT 33064 -#define IDS_THUMBNAILS_INFO_FILESIZE 33065 -#define IDS_THUMBNAILS_INFO_HEADER 33066 -#define IDS_THUMBNAIL_TOO_SMALL 33067 -#define IDS_CANNOT_LOAD_SUB 33068 -#define IDS_SUBTITLE_FILES_FILTER 33069 -#define IDS_MAINFRM_68 33075 -#define IDS_MAINFRM_69 33076 -#define IDS_MAINFRM_70 33077 -#define IDS_AG_CHAPTER 33078 -#define IDS_AG_OUT_OF_MEMORY 33081 -#define IDS_MAINFRM_77 33082 -#define IDS_MAINFRM_80 33084 -#define IDS_MAINFRM_81 33085 -#define IDS_MAINFRM_82 33086 -#define IDS_MAINFRM_83 33087 -#define IDS_MAINFRM_84 33088 -#define IDS_MAINFRM_86 33089 -#define IDS_MAINFRM_87 33090 -#define IDS_MAINFRM_88 33091 -#define IDS_MAINFRM_89 33092 -#define IDS_MAINFRM_90 33093 -#define IDS_MAINFRM_91 33094 -#define IDS_MAINFRM_92 33095 -#define IDS_MAINFRM_93 33096 -#define IDS_MAINFRM_94 33097 -#define IDS_AG_FAILED 33098 -#define IDS_MAINFRM_96 33099 -#define IDS_MAINFRM_98 33100 -#define IDS_MAINFRM_99 33101 -#define IDS_MAINFRM_108 33106 -#define IDS_AG_SOUND 33107 -#define IDS_MAINFRM_114 33108 -#define IDS_AG_ABORTED 33109 -#define IDS_MAINFRM_116 33110 -#define IDS_MAINFRM_117 33111 -#define IDS_AG_UNKNOWN_STREAM 33112 -#define IDS_AG_UNKNOWN 33113 -#define IDS_AG_VSYNC 33114 -#define IDS_MAINFRM_121 33115 -#define IDS_MAINFRM_122 33116 -#define IDS_DVD_SUBTITLES_ENABLE 33117 -#define IDS_AG_ANGLE 33118 -#define IDS_AG_VSYNCOFFSET_INCREASE 33119 -#define IDS_AG_DISABLED 33120 -#define IDS_AG_VSYNCOFFSET_DECREASE 33121 -#define IDS_MAINFRM_136 33126 -#define IDS_MAINFRM_137 33127 -#define IDS_MAINFRM_138 33128 -#define IDS_VOLUME_BOOST_INC 33129 -#define IDS_VOLUME_BOOST_DEC 33130 -#define IDS_VOLUME_BOOST_MIN 33131 -#define IDS_VOLUME_BOOST_MAX 33132 -#define IDS_USAGE 33133 -#define IDS_UNKNOWN_SWITCH 33134 -#define IDS_ADD_TO_PLAYLIST 33161 -#define IDS_OPEN_WITH_MPC 33162 -#define IDS_CANNOT_CHANGE_FORMAT 33163 -#define IDS_APP_DESCRIPTION 33164 -#define IDS_MAINFRM_12 33165 -#define IDS_MAINFRM_13 33166 -#define IDS_D3DFS_WARNING 33190 -#define IDS_MAINFRM_139 33191 -#define IDS_AG_TITLE2 33192 -#define IDS_REALVIDEO_INCOMPATIBLE 33193 -#define IDS_THUMB_ROWNUMBER 33195 -#define IDS_THUMB_COLNUMBER 33196 -#define IDS_THUMB_IMAGE_WIDTH 33197 -#define IDS_AG_CHAPTER2 33201 -#define IDS_VOLUME_OSD 33202 -#define IDS_BOOST_OSD 33203 -#define IDS_BALANCE_OSD 33204 -#define IDS_FULLSCREENMONITOR_CURRENT 33205 -#define ID_FILE_OPENDIRECTORY 33208 -#define IDS_MAINFRM_DIR_TITLE 33209 -#define IDS_MAINFRM_DIR_CHECK 33210 -#define IDS_AG_PAUSE 33212 -#define IDS_AG_TOGGLE_CAPTION 33213 -#define IDS_AG_TOGGLE_SEEKER 33214 -#define IDS_AG_TOGGLE_CONTROLS 33215 -#define IDS_AG_TOGGLE_INFO 33216 -#define IDS_AG_TOGGLE_STATS 33217 -#define IDS_AG_TOGGLE_STATUS 33218 -#define IDS_AG_TOGGLE_SUBRESYNC 33219 -#define IDS_AG_TOGGLE_PLAYLIST 33220 -#define IDS_AG_TOGGLE_CAPTURE 33221 -#define IDS_AG_TOGGLE_DEBUGSHADERS 33222 -#define IDS_AG_ZOOM_50 33223 -#define IDS_AG_ZOOM_100 33224 -#define IDS_AG_ZOOM_200 33225 -#define IDS_AG_NEXT_AR_PRESET 33226 -#define IDS_AG_VIDFRM_STRETCH 33227 -#define IDS_AG_VIDFRM_INSIDE 33228 -#define IDS_AG_VIDFRM_OUTSIDE 33229 -#define IDS_AG_PNS_RESET 33230 -#define IDS_AG_PNS_ROTATEX_P 33231 -#define IDS_AG_PNS_ROTATEX_M 33232 -#define IDS_AG_PNS_ROTATEY_P 33233 -#define IDS_AG_PNS_ROTATEY_M 33234 -#define IDS_AG_PNS_ROTATEZ_P 33235 -#define IDS_AG_PNS_ROTATEZ_M 33236 -#define IDS_AG_TEARING_TEST 33237 -#define IDS_SCALE_16_9 33239 -#define IDS_SCALE_WIDESCREEN 33240 -#define IDS_SCALE_ULTRAWIDE 33241 -#define IDS_PLAYLIST_HIDEFS 33242 -#define ID_VIEW_VSYNC 33243 -#define ID_VIEW_VSYNCOFFSET 33245 -#define ID_VIEW_VSYNCOFFSET_DECREASE 33246 -#define ID_VIEW_VSYNCOFFSET_INCREASE 33247 -#define IDS_AG_TOGGLE_NAVIGATION 33248 -#define ID_VIEW_VSYNCACCURATE 33260 -#define IDS_AG_VSYNCACCURATE 33261 -#define ID_VIEW_FULLSCREENGUISUPPORT 33263 -#define ID_VIEW_HIGHCOLORRESOLUTION 33264 -#define ID_VIEW_ENABLEFRAMETIMECORRECTION 33265 -#define ID_VIEW_EVROUTPUTRANGE 33269 -#define ID_VIEW_EVROUTPUTRANGE_0_255 33273 -#define ID_VIEW_EVROUTPUTRANGE_16_235 33274 -#define IDS_AG_ENABLEFRAMETIMECORRECTION 33275 -#define IDS_AG_TOGGLE_EDITLISTEDITOR 33277 -#define IDS_AG_EDL_IN 33278 -#define IDS_AG_EDL_OUT 33279 -#define IDS_AG_EDL_NEW_CLIP 33280 -#define ID_RECENT_FILES 33281 -#define ID_RECENT_FILES_CLEAR 33282 -#define IDS_RECENT_FILES_CLEAR 33283 -#define IDS_RECENT_FILES_QUESTION 33284 -#define ID_VIEW_FLUSHGPU_BEFOREVSYNC 33286 -#define ID_VIEW_FLUSHGPU_AFTERPRESENT 33287 -#define ID_VIEW_FLUSHGPU_WAIT 33288 -#define ID_VIEW_D3DFULLSCREEN 33289 -#define ID_VIEW_DISABLEDESKTOPCOMPOSITION 33290 -#define ID_VIEW_ALTERNATIVEVSYNC 33291 -#define ID_VIEW_RESET_DEFAULT 33292 -#define ID_VIEW_RESET_OPTIMAL 33293 -#define IDS_AG_EDL_SAVE 33294 -#define IDC_RESETDEVICE 33400 -#define IDS_NAVIGATE_TUNERSCAN 33401 -#define IDS_SUBTITLES_ERROR 33402 -#define IDC_CHECK_ENHANCED_TASKBAR 33403 -#define IDC_CACHESHADERS 33404 -#define ID_VIEW_SYNCHRONIZEVIDEO 33408 -#define ID_VIEW_SYNCHRONIZEDISPLAY 33409 -#define ID_VIEW_SYNCHRONIZENEAREST 33410 -#define ID_VIEW_NAVIGATION 33415 -#define IDS_AG_VIDFRM_ZOOM1 33419 -#define IDS_AG_VIDFRM_ZOOM2 33420 -#define IDS_AG_VIDFRM_SWITCHZOOM 33422 -#define IDS_ENABLE_ALL_FILTERS 33423 -#define IDS_DISABLE_ALL_FILTERS 33424 -#define IDS_ENABLE_AUDIO_FILTERS 33425 -#define IDS_DISABLE_AUDIO_FILTERS 33426 -#define IDS_ENABLE_VIDEO_FILTERS 33427 -#define IDS_DISABLE_VIDEO_FILTERS 33428 -#define IDS_STRETCH_TO_WINDOW 33429 -#define IDS_TOUCH_WINDOW_FROM_INSIDE 33430 -#define IDS_ZOOM1 33431 -#define IDS_ZOOM2 33432 -#define IDS_TOUCH_WINDOW_FROM_OUTSIDE 33433 -#define IDS_AUDIO_STREAM 33434 -#define IDS_AG_REOPEN 33435 -#define IDS_TIME_TOOLTIP_ABOVE 33440 -#define IDS_TIME_TOOLTIP_BELOW 33441 -#define IDS_VIDEO_STREAM 33442 -#define IDS_APPLY 33443 -#define IDS_CLEAR 33444 -#define IDS_CANCEL 33445 -#define IDS_THUMB_THUMBNAILS 33446 -#define IDS_THUMB_PIXELS 33447 -#define IDS_TEXTFILE_ENC 33448 -#define ID_PLAY_REPEAT_FOREVER 33449 -#define ID_PLAY_REPEAT_ONEFILE 33450 -#define ID_PLAY_REPEAT_WHOLEPLAYLIST 33451 -#define IDS_AG_ZOOM_25 33452 -#define ID_PLAY_REPEAT_AB 33453 -#define IDS_AG_MOUSE_MODIFIER 33453 -#define ID_PLAY_REPEAT_AB_MARK_A 33454 -#define ID_PLAY_REPEAT_AB_MARK_B 33455 -#define ID_VIEW_ZOOM_SUB 33456 -#define ID_VIEW_ZOOM_ADD 33457 -#define IDS_AG_ZOOM_ADD 33458 -#define IDS_AG_ZOOM_SUB 33459 -#define IDS_SEEKBAR_HOVER_PREVIEW 33460 -#define IDS_SEEKBAR_HOVER_TOOLTIP 33461 -#define ID_RECENT_FILE_START 34000 -#define ID_RECENT_FILE_END 34999 -#define IDS_MFMT_AVI 39001 -#define IDS_MFMT_MPEG 39002 -#define IDS_MFMT_MPEGTS 39003 -#define IDS_MFMT_DVDVIDEO 39004 -#define IDS_MFMT_MKV 39005 -#define IDS_MFMT_WEBM 39006 -#define IDS_MFMT_MP4 39007 -#define IDS_MFMT_MOV 39008 -#define IDS_MFMT_3GP 39009 -#define IDS_MFMT_3GA 39010 -#define IDS_MFMT_FLV 39011 -#define IDS_MFMT_OGM 39012 -#define IDS_MFMT_RM 39013 -#define IDS_MFMT_RT 39014 -#define IDS_MFMT_WMV 39015 -#define IDS_MFMT_BINK 39018 -#define IDS_MFMT_FLIC 39019 -#define IDS_MFMT_DSM 39020 -#define IDS_MFMT_IVF 39021 -#define IDS_MFMT_AVS 39022 -#define IDS_MFMT_OTHER 39401 -#define IDS_MFMT_SWF 39403 -#define IDS_MFMT_OTHER_AUDIO 39404 -#define IDS_MFMT_AC3 39501 -#define IDS_MFMT_AIFF 39502 -#define IDS_MFMT_ALAC 39503 -#define IDS_MFMT_AMR 39504 -#define IDS_MFMT_APE 39505 -#define IDS_MFMT_AU 39506 -#define IDS_MFMT_CDA 39507 -#define IDS_MFMT_FLAC 39508 -#define IDS_MFMT_M4A 39509 -#define IDS_MFMT_MIDI 39510 -#define IDS_MFMT_MKA 39511 -#define IDS_MFMT_MP3 39512 -#define IDS_MFMT_MPA 39513 -#define IDS_MFMT_MPC 39514 -#define IDS_MFMT_OFR 39515 -#define IDS_MFMT_OGG 39516 -#define IDS_MFMT_RA 39517 -#define IDS_MFMT_TAK 39518 -#define IDS_MFMT_TTA 39519 -#define IDS_MFMT_WAV 39520 -#define IDS_MFMT_WMA 39521 -#define IDS_MFMT_WV 39522 -#define IDS_MFMT_OPUS 39523 -#define IDS_MFMT_DTS 39524 -#define IDS_MFMT_PLS 39901 -#define IDS_MFMT_BDPLS 39902 -#define IDS_MFMT_RAR 39903 -#define IDTB_BUTTON1 40001 -#define IDTB_BUTTON2 40002 -#define IDTB_BUTTON3 40003 -#define IDTB_BUTTON4 40004 -#define IDTB_BUTTON5 40005 -#define IDR_TB_PLAY 41001 -#define IDR_TB_PAUSE 41002 -#define IDR_TB_STOP 41003 -#define IDS_FRONT_LEFT 41006 -#define IDS_FRONT_RIGHT 41007 -#define IDS_FRONT_CENTER 41008 -#define IDS_LOW_FREQUENCY 41009 -#define IDS_BACK_LEFT 41010 -#define IDS_BACK_RIGHT 41011 -#define IDS_FRONT_LEFT_OF_CENTER 41012 -#define IDS_FRONT_RIGHT_OF_CENTER 41013 -#define IDS_BACK_CENTER 41014 -#define IDS_SIDE_LEFT 41015 -#define IDS_SIDE_RIGHT 41016 -#define IDS_TOP_CENTER 41017 -#define IDS_TOP_FRONT_LEFT 41018 -#define IDS_TOP_FRONT_CENTER 41019 -#define IDS_TOP_FRONT_RIGHT 41020 -#define IDS_TOP_BACK_LEFT 41021 -#define IDS_TOP_BACK_CENTER 41022 -#define IDS_TOP_BACK_RIGHT 41023 -#define IDS_LOGO_AUTHOR 41024 -#define IDC_RESTORERESCHECK 41025 -#define IDS_NO_MORE_MEDIA 41026 -#define IDS_FIRST_IN_FOLDER 41027 -#define IDS_LAST_IN_FOLDER 41028 -#define IDS_FAVORITES_QUICKADDFAVORITE 41105 -#define IDS_DVB_CHANNEL_NUMBER 41109 -#define IDS_DVB_CHANNEL_NAME 41110 -#define IDS_DVB_CHANNEL_FREQUENCY 41111 -#define IDS_DVB_CHANNEL_ENCRYPTION 41112 -#define IDS_YES 41113 -#define IDS_NO 41114 -#define IDS_DVB_CHANNEL_START_SCAN 41115 -#define IDS_DVB_CHANNEL_STOP_SCAN 41116 -#define IDS_DVB_TVNAV_SEERADIO 41117 -#define IDS_DVB_TVNAV_SEETV 41118 -#define IDS_DVB_CHANNEL_FORMAT 41119 -#define IDS_DVB_CHANNEL_FPS 41120 -#define IDS_DVB_CHANNEL_RESOLUTION 41121 -#define IDS_DVB_CHANNEL_ASPECT_RATIO 41122 -#define IDS_OSD_RS_VSYNC_ON 41200 -#define IDS_OSD_RS_VSYNC_OFF 41201 -#define IDS_OSD_RS_ACCURATE_VSYNC_ON 41202 -#define IDS_OSD_RS_ACCURATE_VSYNC_OFF 41203 -#define IDS_OSD_RS_SYNC_TO_DISPLAY_ON 41204 -#define IDS_OSD_RS_SYNC_TO_DISPLAY_OFF 41205 -#define IDS_OSD_RS_SYNC_TO_VIDEO_ON 41206 -#define IDS_OSD_RS_SYNC_TO_VIDEO_OFF 41207 -#define IDS_OSD_RS_PRESENT_NEAREST_ON 41208 -#define IDS_OSD_RS_PRESENT_NEAREST_OFF 41209 -#define IDS_OSD_RS_COLOR_MANAGEMENT_ON 41210 -#define IDS_OSD_RS_COLOR_MANAGEMENT_OFF 41211 -#define IDS_OSD_RS_INPUT_TYPE_AUTO 41212 -#define IDS_OSD_RS_INPUT_TYPE_HDTV 41213 -#define IDS_OSD_RS_INPUT_TYPE_SD_NTSC 41214 -#define IDS_OSD_RS_INPUT_TYPE_SD_PAL 41215 -#define IDS_OSD_RS_AMBIENT_LIGHT_BRIGHT 41216 -#define IDS_OSD_RS_AMBIENT_LIGHT_DIM 41217 -#define IDS_OSD_RS_AMBIENT_LIGHT_DARK 41218 -#define IDS_OSD_RS_REND_INTENT_PERCEPT 41219 -#define IDS_OSD_RS_REND_INTENT_RELATIVE 41220 -#define IDS_OSD_RS_REND_INTENT_SATUR 41221 -#define IDS_OSD_RS_REND_INTENT_ABSOLUTE 41222 -#define IDS_OSD_RS_OUTPUT_RANGE 41223 -#define IDS_OSD_RS_FLUSH_BEF_VSYNC_ON 41224 -#define IDS_OSD_RS_FLUSH_BEF_VSYNC_OFF 41225 -#define IDS_OSD_RS_FLUSH_AFT_PRES_ON 41226 -#define IDS_OSD_RS_FLUSH_AFT_PRES_OFF 41227 -#define IDS_OSD_RS_WAIT_ON 41228 -#define IDS_OSD_RS_WAIT_OFF 41229 -#define IDS_OSD_RS_D3D_FULLSCREEN_ON 41230 -#define IDS_OSD_RS_D3D_FULLSCREEN_OFF 41231 -#define IDS_OSD_RS_NO_DESKTOP_COMP_ON 41232 -#define IDS_OSD_RS_NO_DESKTOP_COMP_OFF 41233 -#define IDS_OSD_RS_ALT_VSYNC_ON 41234 -#define IDS_OSD_RS_ALT_VSYNC_OFF 41235 -#define IDS_OSD_RS_RESET_DEFAULT 41236 -#define IDS_OSD_RS_RESET_OPTIMAL 41237 -#define IDS_OSD_RS_D3D_FS_GUI_SUPP_ON 41238 -#define IDS_OSD_RS_D3D_FS_GUI_SUPP_OFF 41239 -#define IDS_OSD_RS_10BIT_RBG_OUT_ON 41240 -#define IDS_OSD_RS_10BIT_RBG_OUT_OFF 41241 -#define IDS_OSD_RS_10BIT_RBG_IN_ON 41242 -#define IDS_OSD_RS_10BIT_RBG_IN_OFF 41243 -#define IDS_OSD_RS_FULL_FP_PROCESS_ON 41244 -#define IDS_OSD_RS_FULL_FP_PROCESS_OFF 41245 -#define IDS_OSD_RS_HALF_FP_PROCESS_ON 41246 -#define IDS_OSD_RS_HALF_FP_PROCESS_OFF 41247 -#define IDS_OSD_RS_FT_CORRECTION_ON 41248 -#define IDS_OSD_RS_FT_CORRECTION_OFF 41249 -#define IDS_OSD_RS_TARGET_VSYNC_OFFSET 41250 -#define IDS_OSD_RS_VSYNC_OFFSET 41251 -#define IDS_OSD_SPEED 41252 -#define IDS_OSD_THUMBS_SAVED 41253 -#define IDS_MENU_VIDEO_STREAM 41254 -#define IDS_MENU_VIDEO_ANGLE 41255 -#define IDS_RESET_SETTINGS 41256 -#define IDS_RESET_SETTINGS_WARNING 41257 -#define IDS_RESET_SETTINGS_MUTEX 41258 -#define IDS_EXPORT_SETTINGS 41259 -#define IDS_EXPORT_SETTINGS_WARNING 41260 -#define IDS_EXPORT_SETTINGS_SUCCESS 41261 -#define IDS_EXPORT_SETTINGS_FAILED 41262 -#define IDS_BDA_ERROR 41263 -#define IDS_BDA_ERROR_CREATE_TUNER 41264 -#define IDS_BDA_ERROR_CREATE_RECEIVER 41265 -#define IDS_BDA_ERROR_CONNECT_NW_TUNER 41266 -#define IDS_BDA_ERROR_CONNECT_TUNER_REC 41267 -#define IDS_BDA_ERROR_CONNECT_TUNER 41268 -#define IDS_BDA_ERROR_DEMULTIPLEXER 41269 -#define IDS_GOTO_ERROR_PARSING_TIME 41270 -#define IDS_GOTO_ERROR_PARSING_TEXT 41271 -#define IDS_GOTO_ERROR_PARSING_FPS 41272 -#define IDS_FRAME_STEP_ERROR_RENDERER 41273 -#define IDS_SCREENSHOT_ERROR_SHOCKWAVE 41276 -#define IDS_SCREENSHOT_ERROR_OVERLAY 41277 -#define IDS_SUBDL_DLG_CONNECT_ERROR 41278 -#define IDS_MB_SHOW_EDL_EDITOR 41279 -#define IDS_CAPTURE_ERROR 41280 -#define IDS_CAPTURE_ERROR_VIDEO 41281 -#define IDS_CAPTURE_ERROR_AUDIO 41282 -#define IDS_CAPTURE_ERROR_ADD_BUFFER 41283 -#define IDS_CAPTURE_ERROR_CONNECT_BUFF 41284 -#define IDS_CAPTURE_ERROR_ADD_ENCODER 41285 -#define IDS_CAPTURE_ERROR_CONNECT_ENC 41286 -#define IDS_CAPTURE_ERROR_COMPRESSION 41287 -#define IDS_CAPTURE_ERROR_MULTIPLEXER 41288 -#define IDS_CAPTURE_ERROR_VID_CAPT_PIN 41289 -#define IDS_CAPTURE_ERROR_AUD_CAPT_PIN 41290 -#define IDS_CAPTURE_ERROR_OUT_FILE 41291 -#define IDS_CAPTURE_ERROR_AUD_OUT_FILE 41292 -#define IDS_SUBRESYNC_TIME_FORMAT 41293 -#define IDS_EXTERNAL_FILTERS_ERROR_MT 41294 -#define IDS_WEBSERVER_ERROR_TEST 41295 -#define IDS_AFTERPLAYBACK_EXIT 41296 -#define IDS_AFTERPLAYBACK_STANDBY 41297 -#define IDS_AFTERPLAYBACK_HIBERNATE 41298 -#define IDS_AFTERPLAYBACK_SHUTDOWN 41299 -#define IDS_AFTERPLAYBACK_LOGOFF 41300 -#define IDS_AFTERPLAYBACK_LOCK 41301 -#define IDS_AFTERPLAYBACK_MONITOROFF 41302 -#define IDS_AFTERPLAYBACK_PLAYNEXT 41303 -#define IDS_AFTERPLAYBACK_DONOTHING 41304 -#define IDS_OSD_BRIGHTNESS 41305 -#define IDS_OSD_CONTRAST 41306 -#define IDS_OSD_HUE 41307 -#define IDS_OSD_SATURATION 41308 -#define IDS_OSD_RESET_COLOR 41309 -#define IDS_OSD_NO_COLORCONTROL 41310 -#define IDS_BRIGHTNESS_INC 41311 -#define IDS_BRIGHTNESS_DEC 41312 -#define IDS_CONTRAST_INC 41313 -#define IDS_CONTRAST_DEC 41314 -#define IDS_HUE_INC 41315 -#define IDS_HUE_DEC 41316 -#define IDS_SATURATION_INC 41317 -#define IDS_SATURATION_DEC 41318 -#define IDS_RESET_COLOR 41319 -#define ID_HELP_CHECKFORUPDATE 41321 -#define IDS_USING_LATEST_STABLE 41322 -#define IDS_USING_NEWER_VERSION 41323 -#define IDS_NEW_UPDATE_AVAILABLE 41324 -#define IDS_UPDATE_ERROR 41325 -#define IDS_UPDATE_CLOSE 41326 -#define IDS_OSD_ZOOM 41327 -#define IDS_OSD_ZOOM_AUTO 41328 -#define IDS_CUSTOM_CHANNEL_MAPPING 41329 -#define IDS_OSD_CUSTOM_CH_MAPPING_ON 41330 -#define IDS_OSD_CUSTOM_CH_MAPPING_OFF 41331 -#define IDS_NORMALIZE 41332 -#define IDS_OSD_NORMALIZE_ON 41333 -#define IDS_OSD_NORMALIZE_OFF 41334 -#define IDS_REGAIN_VOLUME 41335 -#define IDS_OSD_REGAIN_VOLUME_ON 41336 -#define IDS_OSD_REGAIN_VOLUME_OFF 41337 -#define IDS_SIZE_UNIT_BYTES 41338 -#define IDS_SIZE_UNIT_K 41339 -#define IDS_SIZE_UNIT_M 41340 -#define IDS_SIZE_UNIT_G 41341 -#define IDS_SPEED_UNIT_K 41342 -#define IDS_SPEED_UNIT_M 41343 -#define IDS_SPEED_UNIT_G 41344 -#define IDS_FILE_FAV_ADDED 41345 -#define IDS_DVD_FAV_ADDED 41346 -#define IDS_CAPTURE_SETTINGS 41347 -#define IDS_NAVIGATION_BAR 41348 -#define IDS_SUBRESYNC_CAPTION 41350 -#define IDS_SUBRESYNC_CLN_TIME 41351 -#define IDS_SUBRESYNC_CLN_END 41352 -#define IDS_SUBRESYNC_CLN_PREVIEW 41353 -#define IDS_SUBRESYNC_CLN_VOB_ID 41354 -#define IDS_SUBRESYNC_CLN_CELL_ID 41355 -#define IDS_SUBRESYNC_CLN_FORCED 41356 -#define IDS_SUBRESYNC_CLN_TEXT 41357 -#define IDS_SUBRESYNC_CLN_STYLE 41358 -#define IDS_SUBRESYNC_CLN_FONT 41359 -#define IDS_SUBRESYNC_CLN_CHARSET 41360 -#define IDS_SUBRESYNC_CLN_UNICODE 41361 -#define IDS_SUBRESYNC_CLN_LAYER 41362 -#define IDS_SUBRESYNC_CLN_ACTOR 41363 -#define IDS_SUBRESYNC_CLN_EFFECT 41364 -#define IDS_PLAYLIST_CAPTION 41365 -#define IDS_PPAGE_FS_CLN_ON_OFF 41366 -#define IDS_PPAGE_FS_CLN_FROM_FPS 41367 -#define IDS_PPAGE_FS_CLN_TO_FPS 41368 -#define IDS_PPAGE_FS_CLN_DISPLAY_MODE 41369 -#define IDS_PPAGE_FS_DEFAULT 41370 -#define IDS_PPAGE_FS_OTHER 41371 -#define IDS_PPAGE_OUTPUT_SYS_DEF 41372 -#define IDS_GRAPH_INTERFACES_ERROR 41373 -#define IDS_GRAPH_TARGET_WND_ERROR 41374 -#define IDS_DVD_NAV_ALL_PINS_ERROR 41375 -#define IDS_DVD_NAV_SOME_PINS_ERROR 41376 -#define IDS_DVD_INTERFACES_ERROR 41377 -#define IDS_CAPTURE_LIVE 41378 -#define IDS_CAPTURE_ERROR_VID_FILTER 41379 -#define IDS_CAPTURE_ERROR_AUD_FILTER 41380 -#define IDS_CAPTURE_ERROR_DEVICE 41381 -#define IDS_INVALID_PARAMS_ERROR 41382 -#define IDS_EDIT_LIST_EDITOR 41383 -#define IDS_GOTO_ERROR_INVALID_TIME 41384 -#define IDS_MISSING_ICONS_LIB 41386 -#define IDS_SUBDL_DLG_FILENAME_COL 41387 -#define IDS_SUBDL_DLG_LANGUAGE_COL 41388 -#define IDS_SUBDL_DLG_FORMAT_COL 41389 -#define IDS_SUBDL_DLG_DISC_COL 41390 -#define IDS_SUBDL_DLG_TITLES_COL 41391 -#define IDS_SUBDL_DLG_DOWNLOADING 41392 -#define IDS_SUBDL_DLG_PARSING 41393 -#define IDS_SUBDL_DLG_NOT_FOUND 41394 -#define IDS_SUBDL_DLG_SUBS_AVAIL 41395 -#define IDS_UPDATE_CONFIG_AUTO_CHECK 41396 -#define IDS_ZOOM_50 41397 -#define IDS_ZOOM_100 41398 -#define IDS_ZOOM_200 41399 -#define IDS_ZOOM_AUTOFIT 41400 -#define IDS_ZOOM_AUTOFIT_LARGER 41401 -#define IDS_AG_ZOOM_AUTO_FIT_LARGER 41402 -#define IDS_OSD_ZOOM_AUTO_LARGER 41403 -#define IDS_TOOLTIP_EXPLORE_TO_FILE 41404 -#define IDS_TOOLTIP_REMAINING_TIME 41405 -#define IDS_UPDATE_DELAY_ERROR_TITLE 41406 -#define IDS_UPDATE_DELAY_ERROR_MSG 41407 -#define IDS_AUDIOSWITCHER 41408 -#define IDS_ICONS_REASSOC_DLG_TITLE 41409 -#define IDS_ICONS_REASSOC_DLG_INSTR 41410 -#define IDS_ICONS_REASSOC_DLG_CONTENT 41411 -#define IDS_PPAGE_OUTPUT_OLDRENDERER 41412 -#define IDS_PPAGE_OUTPUT_OVERLAYMIXER 41413 -#define IDS_ZOOM_25 41414 -#define IDS_PPAGE_OUTPUT_VMR9WINDOWED 41415 -#define IDS_PPAGE_OUTPUT_VMR9RENDERLESS 41417 -#define IDS_PPAGE_OUTPUT_EVR 41418 -#define IDS_PPAGE_OUTPUT_EVR_CUSTOM 41419 -#define IDS_PPAGE_OUTPUT_DXR 41420 -#define IDS_PPAGE_OUTPUT_NULL_COMP 41421 -#define IDS_PPAGE_OUTPUT_NULL_UNCOMP 41422 -#define IDS_PPAGE_OUTPUT_MADVR 41423 -#define IDS_PPAGE_OUTPUT_SYNC 41424 -#define IDS_PPAGE_OUTPUT_AUD_MPC_REND 41425 -#define IDS_PPAGE_OUTPUT_SURF_OFFSCREEN 41427 -#define IDS_PPAGE_OUTPUT_SURF_2D 41428 -#define IDS_PPAGE_OUTPUT_SURF_3D 41429 -#define IDS_PPAGE_OUTPUT_RESIZE_NN 41430 -#define IDS_PPAGE_OUTPUT_RESIZER_BILIN 41431 -#define IDS_PPAGE_OUTPUT_RESIZER_BIL_PS 41432 -#define IDS_PPAGE_OUTPUT_RESIZER_BICUB1 41433 -#define IDS_PPAGE_OUTPUT_RESIZER_BICUB2 41434 -#define IDS_PPAGE_OUTPUT_RESIZER_BICUB3 41435 -#define IDS_PPAGE_OUTPUT_UNAVAILABLE 41436 -#define IDS_PPAGE_OUTPUT_UNAVAILABLEMSG 41437 -#define IDS_PPAGE_OUTPUT_AUD_NULL_COMP 41438 -#define IDS_PPAGE_OUTPUT_AUD_NULL_UNCOMP 41439 -#define IDS_PPAGE_OUTPUT_AUD_INTERNAL_REND 41440 -#define IDS_EMB_RESOURCES_VIEWER_NAME 41441 -#define IDS_EMB_RESOURCES_VIEWER_TYPE 41442 -#define IDS_EMB_RESOURCES_VIEWER_INFO 41443 -#define IDS_SUBTITLES_DOWNLOAD 41444 -#define IDS_SUBTITLES_UPLOAD 41445 -#define IDS_SUBFILE_DELAY 41448 -#define IDS_SPEEDSTEP_AUTO 41449 -#define IDS_EXPORT_SETTINGS_NO_KEYS 41450 -#define IDS_RFS_NO_FILES 41451 -#define IDS_RFS_COMPRESSED 41452 -#define IDS_RFS_ENCRYPTED 41453 -#define IDS_RFS_MISSING_VOLS 41454 -#define IDS_OSD_D3DFS_REMINDER 41455 -#define IDS_LANG_PREF_EXAMPLE 41456 -#define IDS_OVERRIDE_EXT_SPLITTER_CHOICE 41457 -#define IDC_SPLITTER_CONF 41458 -#define IDC_VIDEO_DEC_CONF 41459 -#define IDC_AUDIO_DEC_CONF 41460 -#define IDS_NAVIGATE_BD_PLAYLISTS 41461 -#define IDS_NAVIGATE_PLAYLIST 41462 -#define IDS_NAVIGATE_CHAPTERS 41463 -#define IDS_NAVIGATE_TITLES 41464 -#define IDS_NAVIGATE_CHANNELS 41465 -#define IDS_PPAGE_OUTPUT_MPCVR 41466 -#define IDS_PPAGE_OUTPUT_VMR7 41467 -#define IDS_MOUSE_CLICK_MIDDLE 41702 -#define IDS_MOUSE_CLICK_X1 41703 -#define IDS_MOUSE_CLICK_X2 41704 -#define IDS_MOUSE_WHEEL_UP 41705 -#define IDS_MOUSE_WHEEL_DOWN 41706 -#define IDS_MOUSE_WHEEL_LEFT 41707 -#define IDS_MOUSE_WHEEL_RIGHT 41708 -#define IDS_MOUSE_ACTION 41710 -#define IDS_MOUSE_COMMAND 41711 -#define IDS_MOUSE_RIGHT_BUTTON 41712 -#define IDS_PPAGE_CAPTURE_FG0 57345 -#define IDS_PPAGE_CAPTURE_FG1 57346 -#define IDS_PPAGE_CAPTURE_FG2 57347 -#define IDS_PPAGE_CAPTURE_FGDESC0 57348 -#define IDS_PPAGE_CAPTURE_FGDESC1 57349 -#define IDS_PPAGE_CAPTURE_FGDESC2 57350 -#define IDS_PPAGE_CAPTURE_SFG0 57351 -#define IDS_PPAGE_CAPTURE_SFG1 57352 -#define IDS_PPAGE_CAPTURE_SFG2 57353 -#define IDS_INFOBAR_PARENTAL_RATING 57354 -#define IDS_PARENTAL_RATING 57355 -#define IDS_NO_PARENTAL_RATING 57356 -#define IDS_INFOBAR_CONTENT 57357 -#define IDS_CONTENT_MOVIE_DRAMA 57358 -#define IDS_CONTENT_NEWS_CURRENTAFFAIRS 57359 -#define IDS_CONTENT_SHOW_GAMESHOW 57360 -#define IDS_CONTENT_SPORTS 57361 -#define IDS_CONTENT_CHILDREN_YOUTH_PROG 57362 -#define IDS_CONTENT_MUSIC_BALLET_DANCE 57363 -#define IDS_CONTENT_MUSIC_ART_CULTURE 57364 -#define IDS_CONTENT_SOCIAL_POLITICAL_ECO 57365 -#define IDS_CONTENT_LEISURE 57366 -#define IDS_FILE_RECYCLE 57367 -#define IDS_AG_SAVE_COPY 57368 -#define IDS_FASTSEEK_LATEST 57369 -#define IDS_FASTSEEK_NEAREST 57370 -#define IDS_HOOKS_FAILED 57371 -#define IDS_PPAGEFULLSCREEN_SHOWNEVER 57372 -#define IDS_PPAGEFULLSCREEN_SHOWMOVED 57373 -#define IDS_PPAGEFULLSCREEN_SHOHHOVERED 57374 -#define IDS_MAINFRM_PRE_SHADERS_FAILED 57375 -#define IDS_MAINFRM_POST_SHADERS_FAILED 57376 -#define IDS_MAINFRM_BOTH_SHADERS_FAILED 57377 -#define IDS_DEBUGSHADERS_FIRSTRUN_MSG 57378 -#define IDS_SHADER_DLL_ERR_0 57379 -#define IDS_SHADER_DLL_ERR_1 57380 -#define IDS_OSD_SHADERS_PRESET 57381 -#define ID_SHADERS_PRESET_NEXT 57382 -#define IDS_AG_SHADERS_PRESET_NEXT 57383 -#define ID_SHADERS_PRESET_PREV 57384 -#define IDS_AG_SHADERS_PRESET_PREV 57385 -#define IDS_STRING_COLON 57386 -#define IDS_RECORD_START 57387 -#define IDS_RECORD_STOP 57388 -#define IDS_BALANCE 57389 -#define IDS_BALANCE_L 57390 -#define IDS_BALANCE_R 57391 -#define IDS_VOLUME 57392 -#define IDS_BOOST 57393 -#define IDS_PLAYLIST_ADDFOLDER 57394 -#define IDS_HW_INDICATOR 57395 -#define IDS_TOOLTIP_SOFTWARE_DECODING 57396 -#define IDS_STATSBAR_PLAYBACK_RATE 57397 -#define IDS_FILTERS_COPY_TO_CLIPBOARD 57398 -#define IDS_CREDENTIALS_SERVER 57399 -#define IDS_CREDENTIALS_CONNECT 57400 -#define IDS_SUB_SAVE_EXTERNAL_STYLE_FILE 57401 -#define IDS_CONTENT_EDUCATION_SCIENCE 57402 -#define IDS_PPAGEADVANCED_HIDE_WINDOWED 57403 -#define IDS_PPAGEADVANCED_BLOCK_VSFILTER 57404 -#define IDS_PPAGEADVANCED_COL_NAME 57405 -#define IDS_PPAGEADVANCED_COL_VALUE 57406 -#define IDS_PPAGEADVANCED_RECENT_FILES_NUMBER 57407 -#define IDS_PPAGEADVANCED_FILE_POS_LONGER 57408 -#define IDS_PPAGEADVANCED_FILE_POS_AUDIO 57409 -#define IDS_AFTER_PLAYBACK_DO_NOTHING 57410 -#define IDS_AFTER_PLAYBACK_PLAY_NEXT 57411 -#define IDS_AFTER_PLAYBACK_REWIND 57412 -#define IDS_AFTER_PLAYBACK_CLOSE 57413 -#define IDS_AFTER_PLAYBACK_EXIT 57414 -#define IDS_AFTER_PLAYBACK_MONITOROFF 57415 -#define IDS_IMAGE_JPEG_QUALITY 57416 -#define IDS_IMAGE_QUALITY 57417 -#define IDS_PPAGEADVANCED_COVER_SIZE_LIMIT 57418 -#define IDS_SUBTITLE_DELAY_STEP_TOOLTIP 57419 -#define IDS_HOTKEY_NOT_DEFINED 57420 -#define IDS_NAVIGATION_WATCH 57421 -#define IDS_NAVIGATION_MOVE_UP 57422 -#define IDS_NAVIGATION_MOVE_DOWN 57423 -#define IDS_NAVIGATION_SORT 57424 -#define IDS_NAVIGATION_REMOVE_ALL 57425 -#define IDS_REMOVE_CHANNELS_QUESTION 57426 -#define IDS_MEDIAINFO_NO_INFO_AVAILABLE 57427 -#define IDS_MEDIAINFO_ANALYSIS_IN_PROGRESS 57428 -#define IDS_ASPECT_RATIO_FMT 57429 -#define IDS_PPAGEADVANCED_LOGGER 57430 -#define IDS_TIMER_REMAINING_TIME 57431 -#define IDS_TIMER_HIGH_PRECISION 57432 -#define IDS_AFTERPLAYBACK_REWIND 57433 -#define IDS_AFTERPLAYBACK_CLOSE 57434 -#define IDS_FRAME_INIT_FAILED 57435 -#define IDS_TIME_SHIFT_TOOLTIP 57436 -#define IDS_WEBUI_DISABLED_PREVIEW_MSG 57437 -#define IDS_WEBUI_PREVIEW_WARNING 57438 -#define IDS_SUBTITLE_RENDERER_INTERNAL 57439 -#define IDS_SUBTITLE_RENDERER_VS_FILTER 57440 -#define IDS_SUBTITLE_RENDERER_XY_SUB_FILTER 57441 -#define IDS_SUBDL_DLG_PROVIDER_COL 57442 -#define IDS_SUBDL_DLG_HI_COL 57443 -#define IDS_SUBDL_DLG_DOWNLOADS_COL 57444 -#define IDS_SUBDL_DLG_SCORE_COL 57445 -#define IDS_SUBDL_DLG_FAILED 57446 -#define IDS_SUBDL_DLG_ABORTED 57447 -#define IDS_SUBDL_DLG_FOUND 57448 -#define IDS_SUBDL_DLG_NOTFOUND 57449 -#define IDS_SUBDL_DLG_TITLE 57450 -#define IDS_SUBDL_DLG_SEARCHING 57451 -#define IDS_SUBDL_DLG_ABORTING 57452 -#define IDS_SUBUL_DLG_USERNAME_COL 57453 -#define IDS_SUBUL_DLG_STATUS_COL 57454 -#define IDS_SUBUL_DLG_STATUS_READY 57455 -#define IDS_SUBUL_DLG_STATUS_NOTIMPLEMENTED 57456 -#define IDS_SUBUL_DLG_STATUS_UPLOADING 57457 -#define IDS_SUBUL_DLG_STATUS_UPLOADED 57458 -#define IDS_SUBUL_DLG_STATUS_FAILED 57459 -#define IDS_SUBUL_DLG_STATUS_ABORTED 57460 -#define IDS_SUBUL_DLG_STATUS_ALREADYEXISTS 57461 -#define IDS_SUBUL_DLG_UPLOADING 57462 -#define IDS_SUBUL_DLG_UPLOADED 57463 -#define IDS_SUBUL_DLG_ABORTED 57464 -#define IDS_SUBUL_DLG_FAILED 57465 -#define IDS_SUBMENU_DOWNLOAD 57466 -#define IDS_SUBMENU_SETUP 57467 -#define IDS_SUBMENU_RESET 57468 -#define IDS_SUBMENU_MOVEUP 57469 -#define IDS_SUBMENU_MOVEDOWN 57470 -#define IDS_SUBMENU_OPENURL 57471 -#define IDS_SUBPP_DLG_LANGUAGES_COL 57472 -#define IDS_SUBPP_DLG_LANGUAGES_ERROR 57473 -#define IDS_SUB_CREDENTIALS_TITLE 57474 -#define IDS_SUB_CREDENTIALS_MSG 57475 -#define IDS_ASPECT_RATIO_SAR 57476 -#define IDS_SUBDL_DLG_DOWNLOADED 57477 -#define IDS_SUBUL_DLG_TITLE 57478 -#define IDS_SUBUL_DLG_CONFIRM 57479 -#define IDS_SUBPP_DLG_FETCHING_LANGUAGES 57480 -#define IDS_SUB_CREDENTIALS_ERROR 57481 -#define IDS_SUB_AUTODL_IGNORE_TOOLTIP 57482 -#define IDS_CMD_PATHNAME 57483 -#define IDS_CMD_DUB 57484 -#define IDS_CMD_DUBDELAY 57485 -#define IDS_CMD_D3DFS 57486 -#define IDS_CMD_SUB 57487 -#define IDS_CMD_FILTER 57488 -#define IDS_CMD_DVD 57489 -#define IDS_CMD_DVDPOS_TC 57490 -#define IDS_CMD_DVDPOS_TIME 57491 -#define IDS_CMD_CD 57492 -#define IDS_CMD_DEVICE 57493 -#define IDS_CMD_OPEN 57494 -#define IDS_CMD_PLAY 57495 -#define IDS_CMD_CLOSE 57496 -#define IDS_CMD_SHUTDOWN 57497 -#define IDS_CMD_STANDBY 57498 -#define IDS_CMD_HIBERNATE 57499 -#define IDS_CMD_LOGOFF 57500 -#define IDS_CMD_LOCK 57501 -#define IDS_CMD_MONITOROFF 57502 -#define IDS_CMD_PLAYNEXT 57503 -#define IDS_CMD_FULLSCREEN 57504 -#define IDS_CMD_MINIMIZED 57505 -#define IDS_CMD_NEW 57506 -#define IDS_CMD_ADD 57507 -#define IDS_CMD_RANDOMIZE 57508 -#define IDS_CMD_REGVID 57509 -#define IDS_CMD_REGAUD 57510 -#define IDS_CMD_REGPL 57511 -#define IDS_CMD_REGALL 57512 -#define IDS_CMD_UNREGALL 57513 -#define IDS_CMD_START 57514 -#define IDS_CMD_STARTPOS 57515 -#define IDS_CMD_FIXEDSIZE 57516 -#define IDS_CMD_MONITOR 57517 -#define IDS_CMD_AUDIORENDERER 57518 -#define IDS_CMD_SHADERPRESET 57519 -#define IDS_CMD_PNS 57520 -#define IDS_CMD_ICONASSOC 57521 -#define IDS_CMD_NOFOCUS 57522 -#define IDS_CMD_WEBPORT 57523 -#define IDS_CMD_DEBUG 57524 -#define IDS_CMD_NOCRASHREPORTER 57525 -#define IDS_CMD_SLAVE 57526 -#define IDS_CMD_HWGPU 57527 -#define IDS_CMD_RESET 57528 -#define IDS_CMD_HELP 57529 -#define IDS_PPAGEADVANCED_SCORE 57530 -#define IDS_PPAGE_FS_CLN_AUDIO_DELAY 57531 -#define IDS_PPAGEADVANCED_DEFAULTTOOLBARSIZE 57532 -#define IDS_PPAGEADVANCED_USE_LEGACY_TOOLBAR 57533 -#define IDS_SUBMENU_COPYURL 57535 -#define IDS_CMD_VIEWPRESET 57536 -#define IDS_CMD_MUTE 57537 -#define IDS_CMD_VOLUME 57538 -#define IDS_YOUTUBEDL_NOT_FOUND 57539 -#define IDS_CONTROLS_YOUTUBEDL 57540 -#define IDS_VERTICAL_ALIGN_VIDEO_TOP 57541 -#define IDS_VERTICAL_ALIGN_VIDEO_MIDDLE 57542 -#define IDS_VERTICAL_ALIGN_VIDEO_BOTTOM 57543 -#define IDS_PPAGEADVANCED_USE_YDL 57544 -#define IDS_PPAGEADVANCED_YDL_MAX_HEIGHT 57545 -#define IDS_PPAGEADVANCED_YDL_VIDEO_FORMAT 57546 -#define IDS_PPAGEADVANCED_YDL_AUDIO_ONLY 57547 -#define IDS_PPAGEADVANCED_YDL_COMMAND_LINE 57548 -#define IDS_PPAGEADVANCED_SAVEIMAGE_POSITION 57549 -#define IDS_PPAGEADVANCED_SAVEIMAGE_CURRENTTIME 57550 -#define IDS_PPAGEADVANCED_ALLOW_INACCURATE_FASTSEEK 57551 -#define IDS_PPAGEADVANCED_LOOP_FOLDER_NEXT_FILE 57552 -#define IDS_PPAGEADVANCED_MODERNSEEKBAR 57553 -#define IDS_PPAGEADVANCED_MODERNSEEKBARHEIGHT 57554 -#define IDS_PPAGEADVANCED_FULLSCREEN_DELAY 57555 -#define IDS_PPAGEADVANCED_SNAPSHOTSUBTITLES 57556 -#define IDS_PPAGEADVANCED_SNAPSHOTKEEPVIDEOEXTENSION 57557 -#define IDS_PPAGEADVANCED_CRASHREPORTER 57558 -#define IDS_PRESIZE_SHADERS_ENABLED 57559 -#define IDS_PRESIZE_SHADERS_DISABLED 57560 -#define IDS_PRESIZE_SHADERS_TOGGLE 57561 -#define IDS_AG_PRESIZE_SHADERS_TOGGLE 57562 -#define IDS_POSTSIZE_SHADERS_ENABLED 57563 -#define IDS_POSTSIZE_SHADERS_DISABLED 57564 -#define IDS_POSTSIZE_SHADERS_TOGGLE 57565 -#define IDS_AG_POSTSIZE_SHADERS_TOGGLE 57566 -#define IDS_PPAGEADVANCED_TIME_REFRESH_INTERVAL 57567 -#define IDS_PPAGEADVANCED_SHOW_LANG_STATUSBAR 57568 -#define IDS_PPAGEADVANCED_SHOW_FPS_STATUSBAR 57569 -#define IDS_PPAGEADVANCED_ADD_LANGCODE_WHEN_SAVE_SUBTITLES 57570 -#define IDS_PPAGEADVANCED_USE_TITLE_IN_RECENT_FILE_LIST 57571 -#define IDS_PPAGEADVANCED_SHOW_ABMARKS_STATUSBAR 57572 -#define IDS_PPAGEADVANCED_SHOW_VIDEOINFO_STATUSBAR 57573 -#define IDS_PPAGEADVANCED_OPEN_REC_PANEL_WHEN_OPENING_DEVICE 57621 -#define IDS_PPAGEADVANCED_ALWAYS_USE_SHORT_MENU 57622 -#define IDS_PPAGEADVANCED_FULLSCREEN_SEPARATE_CONTROLS 57623 -#define IDS_PPAGEADVANCED_BLOCKRDP 57624 -#define IDS_PPAGEADVANCED_YDL_EXEPATH 57625 -#define IDS_PPAGEADVANCED_YDL_SUBS_PREFERENCE 57626 -#define IDS_PPAGEADVANCED_USE_AUTOMATIC_CAPTIONS 57627 -#define IDS_PPAGEADVANCED_USE_SMTC 57628 -#define IDS_PPAGEADVANCED_LOCK_NOPAUSE 57629 -#define IDS_PPAGEADVANCED_RELOAD_AFTER_LONG_PAUSE 57630 -#define IDS_PPAGEADVANCED_REDIRECT_OPEN_TO_APPEND_THRESHOLD 57631 -#define IDS_SUBTITLE_RENDERER_NONE 57632 -#define IDS_PPAGEADVANCED_MOUSE_LEFTUP_DELAY 57633 -#define IDS_PPAGEADVANCED_USE_FREETYPE 57634 -#define IDS_PPAGEADVANCED_USE_MEDIAINFO_LOAD_FILE_DURATION 57635 -#define IDS_TIMER_SHOW_PERCENTAGE 57636 -#define IDS_SUBDL_DLG_FAILED_DL 57637 -#define IDS_PPAGEADVANCED_FILEPOS_PLAYLIST 57638 -#define IDS_PPAGEADVANCED_FILEPOS_TRACK_SELECTION 57639 -#define IDS_PPAGEADVANCED_YDL_AUDIO_FORMAT 57640 -#define IDS_PPAGEADVANCED_PREVENT_DISPLAY_SLEEP 57641 -#define IDS_PPAGEADVANCED_STILL_VIDEO_DURATION 57642 -#define IDS_PPAGEADVANCED_CAPTURE_DEINTERLACE 57643 -#define IDS_PLAYLIST_TOGGLE_SHUFFLE 57644 -#define IDS_AUDIOSHIFT_ONOFF 57645 -#define IDS_SAVEDIALOG_INCLUDE_SUBS 57646 -#define IDS_PPAGEADVANCED_PAUSE_WHILE_DRAGGING_SEEKBAR 57647 -#define IDS_CMD_THUMBNAILS 57648 -#define IDS_PPAGEADVANCED_CONFIRM_FILE_DELETE 57649 -#define IDS_PPAGEADVANCED_LIBASS_FOR_SRT 57650 -#define IDS_CMD_AB_START 57651 -#define IDS_CMD_AB_END 57652 -#define IDS_ARS_WASAPI_MODE 57700 -#define IDS_ARS_EXCLUSIVE 57701 -#define IDS_ARS_SHARED 57702 -#define IDS_ARS_BITEXACT_OUTPUT 57703 -#define IDS_ARS_SYSTEM_LAYOUT_CHANNELS 57704 -#define IDS_ARS_SOUND_DEVICE 57705 -#define IDS_ARS_RELEASE_DEVICE_IDLE 57706 -#define IDS_ARS_CROSSFEED 57707 -#define IDS_ARS_DEVICE_PERIOD 57708 -#define IDS_ARS_ALT_CHECK_FORMAT 57709 -#define IDS_ARS_STATUS 57710 -#define IDS_ARS_DEVICE 57711 -#define IDS_ARS_MODE 57712 -#define IDS_ARS_INPUT 57713 -#define IDS_ARS_OUTPUT 57714 -#define IDS_ARS_FORMAT 57715 -#define IDS_ARS_SAMPLERATE 57716 -#define IDS_ARS_CHANNELS 57717 -#define IDS_ARS_WASAPI_METHOD 57718 -#define IDS_ARS_DUMMY_CHANNELS 57719 -#define IDS_ARS_TIP_BITEXACT_OUTPUT 57720 -#define IDS_ARS_TIP_ALT_CHECK_FORMAT 57721 -#define IDS_FILTER_RESET_SETTINGS 57722 -#define IDS_AG_DEFAULT 57723 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 20077 -#define _APS_NEXT_COMMAND_VALUE 33462 -#define _APS_NEXT_CONTROL_VALUE 22094 -#define _APS_NEXT_SYMED_VALUE 24052 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by mpc-hc.rc +// +#define IDR_MAINFRAME 128 +#define IDR_POPUP 130 +#define IDR_POPUPMAIN 133 +#define IDB_PLAYERTOOLBAR 201 +#define IDB_AUDIOTYPE_NOAUDIO 202 +#define IDB_AUDIOTYPE_MONO 203 +#define IDB_AUDIOTYPE_STEREO 204 +#define IDB_CHECKBOX 205 +#define IDF_LOGO0 206 +#define IDF_LOGO1 207 +#define IDF_LOGO2 208 +#define IDF_LOGO3 209 +#define IDF_TICKCROSS 210 +#define IDB_STREAMTYPES 215 +#define IDB_SHADER_UP 216 +#define IDB_SHADER_DOWN 217 +#define IDB_SHADER_DEL 218 +#define IDB_CHECK_ALL 219 +#define IDB_UNCHECK_ALL 220 +#define IDB_CHECK_AUDIO 221 +#define IDB_CHECK_VIDEO 222 +#define IDI_SINGLE 300 +#define IDI_MULTI 301 +#define IDI_DVD 302 +#define IDI_AUDIOCD 303 +#define IDI_UNKNOWN 304 +#define IDR_AVI_FILECOPY 400 +#define IDR_HTML_INFO 500 +#define IDR_HTML_INDEX 501 +#define IDR_HTML_404 502 +#define IDR_HTML_BROWSER 503 +#define IDR_HTML_CONTROLS 504 +#define IDR_HTML_PLAYER 505 +#define IDF_DEFAULT_CSS 506 +#define IDF_VBR_PNG 507 +#define IDF_VBS_PNG 508 +#define IDF_SLIDERGRIP_PNG 509 +#define IDF_1PIX_PNG 510 +#define IDF_SLIDERBACK_PNG 511 +#define IDF_HEADERICON_PNG 512 +#define IDF_HEADERBACK_PNG 513 +#define IDF_HEADERCLOSE_PNG 514 +#define IDF_LEFTSIDE_PNG 515 +#define IDF_RIGHTSIDE_PNG 516 +#define IDF_BOTTOMSIDE_PNG 517 +#define IDF_LEFTBOTTOMSIDE_PNG 518 +#define IDF_RIGHTBOTTOMSIDE_PNG 519 +#define IDF_SEEKBARLEFT_PNG 520 +#define IDF_SEEKBARMID_PNG 521 +#define IDF_SEEKBARRIGHT_PNG 522 +#define IDF_SEEKBARGRIP_PNG 523 +#define IDF_CONTROLBACK_PNG 524 +#define IDF_CONTROLBUTTONPLAY_PNG 525 +#define IDF_CONTROLBUTTONPAUSE_PNG 526 +#define IDF_CONTROLBUTTONSTOP_PNG 527 +#define IDF_CONTROLBUTTONSKIPBACK_PNG 528 +#define IDF_CONTROLBUTTONDECRATE_PNG 529 +#define IDF_CONTROLBUTTONINCRATE_PNG 530 +#define IDF_CONTROLBUTTONSKIPFORWARD_PNG 531 +#define IDF_CONTROLBUTTONSTEP_PNG 532 +#define IDF_CONTROLVOLUMEON_PNG 533 +#define IDF_CONTROLVOLUMEOFF_PNG 534 +#define IDF_CONTROLVOLUMEBAR_PNG 535 +#define IDF_CONTROLVOLUMEGRIP_PNG 536 +#define IDR_HTML_VARIABLES 537 +#define IDF_JAVASCRIPT 538 +#define IDF_FAVICON 539 +#define IDF_SHADER_RESIZER 700 +#define IDF_SHADER_EMPTY 701 +#define IDF_SHADER_FINAL 702 +#define IDF_SVG_TOOLBAR 703 +#define IDF_SVG_BUTTONS 704 +#define IDF_SVG_ARROW 705 +#define ID_FILE_OPENMEDIA 800 +#define ID_FILE_OPENDVDBD 801 +#define ID_FILE_OPENDEVICE 802 +#define ID_FILE_CLOSEMEDIA 803 +#define ID_FILE_CLOSE_AND_RESTORE 804 +#define ID_FILE_SAVE_COPY 805 +#define ID_FILE_SAVE_IMAGE 806 +#define ID_FILE_SAVE_IMAGE_AUTO 807 +#define ID_FILE_SAVE_THUMBNAILS 808 +#define ID_FILE_SUBTITLES_LOAD 809 +#define ID_FILE_SUBTITLES_SAVE 810 +#define ID_FILE_SUBTITLES_DOWNLOAD 812 +#define ID_VIEW_ZOOM_25 813 +#define ID_FILE_PROPERTIES 814 +#define ID_VIEW_OPTIONS 815 +#define ID_FILE_EXIT 816 +#define ID_VIEW_CAPTIONMENU 817 +#define ID_VIEW_SEEKER 818 +#define ID_VIEW_CONTROLS 819 +#define ID_VIEW_INFORMATION 820 +#define ID_VIEW_STATISTICS 821 +#define ID_VIEW_STATUS 822 +#define ID_VIEW_SUBRESYNC 823 +#define ID_VIEW_PLAYLIST 824 +#define ID_VIEW_CAPTURE 825 +#define ID_VIEW_DEBUGSHADERS 826 +#define ID_VIEW_PRESETS_MINIMAL 827 +#define ID_VIEW_PRESETS_COMPACT 828 +#define ID_VIEW_PRESETS_NORMAL 829 +#define ID_VIEW_FULLSCREEN 830 +#define ID_VIEW_FULLSCREEN_SECONDARY 831 +#define ID_VIEW_ZOOM_50 832 +#define ID_VIEW_ZOOM_100 833 +#define ID_VIEW_ZOOM_200 834 +#define ID_VIEW_VF_HALF 835 +#define ID_VIEW_VF_NORMAL 836 +#define ID_VIEW_VF_DOUBLE 837 +#define ID_VIEW_VF_STRETCH 838 +#define ID_VIEW_VF_FROMINSIDE 839 +#define ID_VIEW_VF_FROMOUTSIDE 840 +#define ID_VIEW_VF_ZOOM1 841 +#define ID_VIEW_VF_ZOOM2 842 +#define ID_VIEW_VF_SWITCHZOOM 843 +#define ID_VIEW_VF_COMPMONDESKARDIFF 845 +#define ID_VIEW_EDITLISTEDITOR 846 +#define ID_EDL_IN 847 +#define ID_EDL_OUT 848 +#define ID_EDL_NEWCLIP 849 +#define ID_ASPECTRATIO_START 850 +#define ID_ASPECTRATIO_DAR 850 +#define ID_ASPECTRATIO_4_3 851 +#define ID_ASPECTRATIO_5_4 852 +#define ID_ASPECTRATIO_16_9 853 +#define ID_ASPECTRATIO_235_100 854 +#define ID_ASPECTRATIO_185_100 855 +#define ID_ASPECTRATIO_SAR 856 +#define ID_ASPECTRATIO_END 856 +#define ID_ASPECTRATIO_NEXT 859 +#define ID_EDL_SAVE 860 +#define ID_VIEW_RESET 861 +#define ID_VIEW_INCSIZE 862 +#define ID_VIEW_DECSIZE 863 +#define ID_VIEW_INCWIDTH 864 +#define ID_VIEW_DECWIDTH 865 +#define ID_VIEW_INCHEIGHT 866 +#define ID_VIEW_DECHEIGHT 867 +#define ID_PANSCAN_MOVELEFT 868 +#define ID_PANSCAN_MOVERIGHT 869 +#define ID_PANSCAN_MOVEUP 870 +#define ID_PANSCAN_MOVEDOWN 871 +#define ID_PANSCAN_MOVEUPLEFT 872 +#define ID_PANSCAN_MOVEUPRIGHT 873 +#define ID_PANSCAN_MOVEDOWNLEFT 874 +#define ID_PANSCAN_MOVEDOWNRIGHT 875 +#define ID_PANSCAN_CENTER 876 +#define ID_PANSCAN_ROTATEXP 877 +#define ID_PANSCAN_ROTATEXM 878 +#define ID_PANSCAN_ROTATEYP 879 +#define ID_PANSCAN_ROTATEYM 880 +#define ID_PANSCAN_ROTATEZP 881 +#define ID_PANSCAN_ROTATEZM 882 +#define ID_ONTOP_DEFAULT 883 +#define ID_ONTOP_ALWAYS 884 +#define ID_ONTOP_WHILEPLAYING 885 +#define ID_ONTOP_WHILEPLAYINGVIDEO 886 +#define ID_PLAY_PLAY 887 +#define ID_PLAY_PAUSE 888 +#define ID_PLAY_PLAYPAUSE 889 +#define IDS_SHADERNOTES 889 +#define ID_PLAY_STOP 890 +#define ID_PLAY_FRAMESTEP 891 +#define ID_PLAY_FRAMESTEP_BACK 892 +#define ID_NAVIGATE_GOTO 893 +#define ID_PLAY_DECRATE 894 +#define ID_PLAY_INCRATE 895 +#define ID_PLAY_RESETRATE 896 +#define ID_PLAY_SEEKKEYBACKWARD 897 +#define ID_PLAY_SEEKKEYFORWARD 898 +#define ID_PLAY_SEEKBACKWARDSMALL 899 +#define ID_PLAY_SEEKFORWARDSMALL 900 +#define ID_PLAY_SEEKBACKWARDMED 901 +#define ID_PLAY_SEEKFORWARDMED 902 +#define ID_PLAY_SEEKBACKWARDLARGE 903 +#define ID_PLAY_SEEKFORWARDLARGE 904 +#define ID_PLAY_INCAUDDELAY 905 +#define ID_PLAY_DECAUDDELAY 906 +#define ID_VOLUME_UP 907 +#define ID_VOLUME_DOWN 908 +#define ID_VOLUME_MUTE 909 +#define ID_VOLUME_MUTE_OFF 910 +#define ID_VOLUME_MUTE_DISABLED 911 +#define ID_AFTERPLAYBACK_EXIT 912 +#define ID_AFTERPLAYBACK_STANDBY 913 +#define ID_AFTERPLAYBACK_HIBERNATE 914 +#define ID_AFTERPLAYBACK_SHUTDOWN 915 +#define ID_AFTERPLAYBACK_LOGOFF 916 +#define ID_AFTERPLAYBACK_LOCK 917 +#define ID_AFTERPLAYBACK_MONITOROFF 918 +#define ID_NAVIGATE_SKIPBACKFILE 919 +#define ID_NAVIGATE_SKIPFORWARDFILE 920 +#define ID_NAVIGATE_SKIPBACK 921 +#define ID_NAVIGATE_SKIPFORWARD 922 +#define ID_NAVIGATE_TITLEMENU 923 +#define ID_NAVIGATE_ROOTMENU 924 +#define ID_NAVIGATE_SUBPICTUREMENU 925 +#define ID_NAVIGATE_AUDIOMENU 926 +#define ID_NAVIGATE_ANGLEMENU 927 +#define ID_NAVIGATE_CHAPTERMENU 928 +#define ID_NAVIGATE_MENU_LEFT 929 +#define ID_NAVIGATE_MENU_RIGHT 930 +#define ID_NAVIGATE_MENU_UP 931 +#define ID_NAVIGATE_MENU_DOWN 932 +#define ID_NAVIGATE_MENU_ACTIVATE 933 +#define ID_NAVIGATE_MENU_BACK 934 +#define ID_NAVIGATE_MENU_LEAVE 935 +#define ID_FAVORITES 936 +#define ID_FAVORITES_ORGANIZE 937 +#define ID_FAVORITES_ADD 938 +#define ID_HELP_HOMEPAGE 939 +#define ID_HELP_DONATE 940 +#define ID_HELP_SHOWCOMMANDLINESWITCHES 941 +#define ID_HELP_TOOLBARIMAGES 942 +#define ID_HELP_ABOUT 943 +#define ID_BOSS 944 +#define ID_DUMMYSEPARATOR 945 +#define ID_BUTTONSEP 946 +#define ID_AFTERPLAYBACK_PLAYNEXT 947 +#define ID_AFTERPLAYBACK_DONOTHING 948 +#define ID_MENU_PLAYER_SHORT 949 +#define ID_MENU_PLAYER_LONG 950 +#define ID_MENU_FILTERS 951 +#define ID_STREAM_AUDIO_NEXT 952 +#define ID_STREAM_AUDIO_PREV 953 +#define ID_STREAM_SUB_NEXT 954 +#define ID_STREAM_SUB_PREV 955 +#define ID_STREAM_SUB_ONOFF 956 +#define ID_AUDIOSHIFT_ONOFF 960 +#define ID_DVD_ANGLE_NEXT 961 +#define ID_DVD_ANGLE_PREV 962 +#define ID_DVD_AUDIO_NEXT 963 +#define ID_DVD_AUDIO_PREV 964 +#define ID_DVD_SUB_NEXT 965 +#define ID_DVD_SUB_PREV 966 +#define ID_DVD_SUB_ONOFF 967 +#define ID_VIEW_ZOOM_AUTOFIT 968 +#define ID_FILE_OPENQUICK 969 +#define ID_VOLUME_BOOST_INC 970 +#define ID_VOLUME_BOOST_DEC 971 +#define ID_VOLUME_BOOST_MIN 972 +#define ID_VOLUME_BOOST_MAX 973 +#define ID_NAVIGATE_TUNERSCAN 974 +#define ID_FAVORITES_QUICKADDFAVORITE 975 +#define ID_FILE_REOPEN 976 +#define ID_FILTERS 977 +#define ID_AUDIOS 978 +#define ID_SUBTITLES 979 +#define ID_VIDEO_STREAMS 980 +#define ID_COLOR_BRIGHTNESS_INC 984 +#define ID_COLOR_BRIGHTNESS_DEC 985 +#define ID_COLOR_CONTRAST_INC 986 +#define ID_COLOR_CONTRAST_DEC 987 +#define ID_COLOR_HUE_INC 988 +#define ID_COLOR_HUE_DEC 989 +#define ID_COLOR_SATURATION_INC 990 +#define ID_COLOR_SATURATION_DEC 991 +#define ID_COLOR_RESET 992 +#define ID_CUSTOM_CHANNEL_MAPPING 993 +#define ID_NORMALIZE 994 +#define ID_REGAIN_VOLUME 995 +#define ID_PLAY_SEEKSET 996 +#define ID_PANSCAN_ROTATEZ270 997 +#define ID_PRESIZE_SHADERS_TOGGLE 998 +#define ID_POSTSIZE_SHADERS_TOGGLE 999 +#define ID_FILTERS_COPY_TO_CLIPBOARD 1999 +#define ID_FILTERS_SUBITEM_START 2000 +#define ID_FILTERS_SUBITEM_END 2099 +#define ID_FILTERSTREAMS_SUBITEM_START 2100 +#define ID_FILTERSTREAMS_SUBITEM_END 2199 +#define ID_AUDIO_SUBITEM_START 2200 +#define ID_AUDIO_SUBITEM_END 2299 +#define ID_SUBTITLES_SUBITEM_START 2300 +#define ID_SUBTITLES_SUBITEM_END 2399 +#define ID_VIDEO_STREAMS_SUBITEM_START 2400 +#define ID_VIDEO_STREAMS_SUBITEM_END 2499 +#define ID_FAVORITES_FILE_START 2800 +#define ID_FAVORITES_FILE_END 3799 +#define ID_FAVORITES_DVD_START 3800 +#define ID_FAVORITES_DVD_END 3899 +#define ID_FAVORITES_DEVICE_START 3900 +#define ID_FAVORITES_DEVICE_END 3999 +#define ID_FILE_OPEN_OPTICAL_DISK_START 4000 +#define ID_FILE_OPEN_OPTICAL_DISK_END 4099 +#define ID_PANNSCAN_PRESETS_START 4100 +#define ID_PANNSCAN_PRESETS_END 4199 +#define ID_SHADERS_SELECT 4200 +#define ID_SHADERS_PRESETS_START 4201 +#define ID_SHADERS_PRESETS_END 4299 +#define ID_NAVIGATE_JUMPTO_SUBITEM_START 4300 +#define ID_NAVIGATE_JUMPTO_SUBITEM_END 4899 +#define ID_VIEW_ZOOM_AUTOFIT_LARGER 4900 +#define ID_PLAY_PLAYBACKRATE_START 5000 +#define ID_PLAY_PLAYBACKRATE_025 5001 +#define ID_PLAY_PLAYBACKRATE_050 5002 +#define ID_PLAY_PLAYBACKRATE_075 5003 +#define ID_PLAY_PLAYBACKRATE_090 5004 +#define ID_PLAY_PLAYBACKRATE_100 5005 +#define ID_PLAY_PLAYBACKRATE_110 5006 +#define ID_PLAY_PLAYBACKRATE_125 5007 +#define ID_PLAY_PLAYBACKRATE_150 5008 +#define ID_PLAY_PLAYBACKRATE_200 5009 +#define ID_PLAY_PLAYBACKRATE_300 5010 +#define ID_PLAY_PLAYBACKRATE_400 5011 +#define ID_PLAY_PLAYBACKRATE_600 5012 +#define ID_PLAY_PLAYBACKRATE_800 5013 +#define ID_PLAY_PLAYBACKRATE_FPS24 5020 +#define ID_PLAY_PLAYBACKRATE_FPS25 5021 +#define ID_PLAY_PLAYBACKRATE_END 5029 +#define ID_PLAYLIST_TOGGLE_SHUFFLE 5030 +#define ID_CMDLINE_SAVE_THUMBNAILS 5031 +#define ID_MOUSE_ADD_CMD 5032 +#define IDS_FILTER_SETTINGS_CAPTION 7000 +#define IDD_OPEN_DLG 10000 +#define IDD_MEDIATYPES_DLG 10002 +#define IDD_SAVE_DLG 10004 +#define IDD_SUBTITLEDL_DLG 10005 +#define IDD_FILEPROPDETAILS 10010 +#define IDD_FILEPROPCLIP 10011 +#define IDD_PNSPRESET_DLG 10015 +#define IDD_GOTO_DLG 10016 +#define IDD_FAVADD 10017 +#define IDD_FAVORGANIZE 10018 +#define IDD_ABOUTBOX 10019 +#define IDD_PLAYERINFOBAR 10020 +#define IDD_PLAYERSTATUSBAR 10021 +#define IDD_PLAYERSEEKBAR 10022 +#define IDD_PPAGEPLAYBACK 10023 +#define IDD_PPAGEPLAYER 10024 +#define IDD_PPAGEDVD 10025 +#define IDD_PPAGESUBTITLES 10026 +#define IDD_PPAGEFORMATS 10027 +#define IDD_PPAGETWEAKS 10028 +#define IDD_PPAGEAUDIOSWITCHER 10029 +#define IDD_PPAGEEXTERNALFILTERS 10030 +#define IDD_PPAGESHADERS 10031 +#define IDD_PPAGEACCELTBL 10032 +#define IDD_PPAGESUBSTYLE 10033 +#define IDD_PPAGEINTERNALFILTERS 10036 +#define IDD_PPAGELOGO 10037 +#define IDD_PPAGETHEME 10038 +#define IDD_PPAGEOUTPUT 10039 +#define IDD_PPAGEWEBSERVER 10040 +#define IDD_CAPTURE_DLG 10045 +#define IDD_ADDREGFILTER 10046 +#define IDD_SELECTMEDIATYPE 10047 +#define IDD_COMPROPERTYPAGE 10048 +#define IDD_FILEPROPRES 10049 +#define IDD_PPAGEMISC 10052 +#define IDD_FILEMEDIAINFO 10053 +#define IDD_PPAGECAPTURE 10054 +#define IDD_PPAGESYNC 10055 +#define IDD_PPAGEFULLSCREEN 10056 +#define IDD_RFS_FILELIST_EXT 10057 +#define IDD_PPAGEAUDIORENDERER 10058 +#define IDD_PPAGEMOUSE 10059 +#define IDC_COMBO1 11000 +#define IDC_COMBO2 11001 +#define IDC_COMBO3 11002 +#define IDC_COMBO4 11003 +#define IDC_COMBO5 11004 +#define IDC_COMBO6 11005 +#define IDC_COMBO7 11006 +#define IDC_COMBO8 11007 +#define IDC_COMBO9 11008 +#define IDC_COMBO10 11009 +#define IDC_COMBO11 11010 +#define IDC_COMBO12 11011 +#define IDC_COMBO14 11013 +#define IDC_SLIDER1 11020 +#define IDC_SLIDER2 11021 +#define IDC_SLIDER3 11022 +#define IDC_SLIDER4 11023 +#define IDC_SLI_BRIGHTNESS 11025 +#define IDC_SLI_HUE 11026 +#define IDC_SLI_SATURATION 11027 +#define IDC_RADIO1 11040 +#define IDC_RADIO2 11041 +#define IDC_RADIO3 11042 +#define IDC_RADIO4 11043 +#define IDC_RADIO5 11044 +#define IDC_RADIO6 11045 +#define IDC_RADIO7 11046 +#define IDC_RADIO8 11047 +#define IDC_RADIO9 11048 +#define IDC_RADIO10 11049 +#define IDC_RADIO11 11050 +#define IDC_EDIT1 11060 +#define IDC_EDIT3 11061 +#define IDC_EDIT2 11062 +#define IDC_EDIT4 11063 +#define IDC_EDIT5 11064 +#define IDC_EDIT6 11065 +#define IDC_EDIT7 11066 +#define IDC_EDIT8 11067 +#define IDC_EDIT9 11068 +#define IDC_EDIT10 11069 +#define IDC_WINHOTKEY1 11070 +#define IDC_CHECK1 11080 +#define IDC_CHECK2 11081 +#define IDC_CHECK3 11082 +#define IDC_CHECK4 11083 +#define IDC_CHECK5 11084 +#define IDC_CHECK6 11085 +#define IDC_CHECK7 11086 +#define IDC_CHECK8 11087 +#define IDC_CHECK9 11088 +#define IDC_CHECK10 11089 +#define IDC_CHECK11 11090 +#define IDC_CHECK12 11091 +#define IDC_CHECK13 11092 +#define IDC_CHECK14 11093 +#define IDC_SPIN1 11100 +#define IDC_SPIN2 11101 +#define IDC_SPIN3 11102 +#define IDC_SPIN4 11103 +#define IDC_SPIN5 11104 +#define IDC_SPIN6 11105 +#define IDC_SPIN7 11106 +#define IDC_SPIN8 11107 +#define IDC_SPIN9 11108 +#define IDC_SPIN10 11109 +#define IDC_BUTTON1 11120 +#define IDC_BUTTON2 11121 +#define IDC_BUTTON3 11122 +#define IDC_BUTTON4 11123 +#define IDC_BUTTON5 11124 +#define IDC_BUTTON6 11125 +#define IDC_BUTTON7 11126 +#define IDC_BUTTON8 11127 +#define IDC_BUTTON9 11128 +#define IDC_BUTTON10 11129 +#define IDC_BUTTON11 11130 +#define IDC_BUTTON12 11131 +#define IDC_BUTTON13 11132 +#define IDC_RESET_SETTINGS 11133 +#define IDC_EXPORT_SETTINGS 11134 +#define IDC_TREE1 11140 +#define IDC_LIST1 11160 +#define IDC_LIST2 11161 +#define IDC_LIST3 11162 +#define IDC_TAB1 11200 +#define IDC_ANIMATE1 11220 +#define IDC_PROGRESS1 11240 +#define IDC_STATIC1 11260 +#define IDC_STATIC2 11261 +#define IDC_STATIC3 11262 +#define IDC_STATIC4 11263 +#define IDC_STATIC5 11264 +#define IDC_STATIC6 11265 +#define IDC_STATIC7 11266 +#define IDC_STATIC8 11267 +#define IDC_STATIC9 11268 +#define IDC_STATIC10 11269 +#define IDC_STATIC11 11270 +#define IDC_DVDPATH 12000 +#define IDC_SUBRESYNCLIST 12001 +#define IDC_PLAYLIST 12002 +#define IDC_COLORPRI 12003 +#define IDC_COLORSEC 12004 +#define IDC_COLOROUTL 12005 +#define IDC_COLORSHAD 12006 +#define IDC_STATICLINK 12007 +#define IDC_STATICLINK2 12008 +#define IDC_DEFAULTICON 12009 +#define IDC_PLACEHOLDER 12010 +#define IDC_REPORT 12011 +#define IDC_FROMTO 12012 +#define IDC_STATIC_BALANCE 12013 +#define IDC_LOGOPREVIEW 12014 +#define IDC_LOGOFILENAME 12016 +#define IDC_AUTHOR 12018 +#define IDC_CHECK_RELATIVETO 12019 +#define IDC_CHECK_NO_SUB_ANIM 12021 +#define IDC_SUBPIC_TO_BUFFER 12022 +#define IDC_BUTTON_EXT_SET 12023 +#define IDC_OK1 12024 +#define IDC_OK2 12025 +#define IDC_PLAYERSTATUS 12026 +#define IDC_PLAYERTIME 12027 +#define IDC_EDITLIST 12028 +#define IDC_CHECK_SUB_AR_COMPENSATION 12029 +#define IDC_CHECK_ALLOW_DROPPING_SUBPIC 12030 +#define IDC_DSSYSDEF 12100 +#define IDC_DSOVERLAYMIXER 12102 +#define IDC_DSVMR9WIN 12104 +#define IDC_DSVMR9REN 12106 +#define IDC_DSDXR 12107 +#define IDC_DSNULL_COMP 12108 +#define IDC_DSNULL_UNCOMP 12109 +#define IDC_DSEVR_CUSTOM 12111 +#define IDC_DSMADVR 12112 +#define IDC_DSSYNC 12113 +#define IDC_REGULARSURF 12127 +#define IDC_TEXTURESURF2D 12128 +#define IDC_TEXTURESURF3D 12129 +#define IDC_DX9RESIZER_COMBO 12130 +#define IDC_DSVMR9LOADMIXER 12131 +#define IDC_DX_SURFACE 12133 +#define IDC_BUTTON_MI 12136 +#define IDC_MIEDIT 12137 +#define IDC_LISTCHANNELS 12138 +#define IDC_STATUSBAR 12139 +#define IDC_PPAGECAPTURE_DESC1 12140 +#define IDC_DSMPCVR 12141 +#define IDS_SRC_VTS 14002 +#define IDS_SRC_RFS 14003 +#define IDS_INTERNAL_LAVF 14004 +#define IDS_INTERNAL_LAVF_WMV 14005 +#define IDS_AG_OPEN_FILE_LOCATION 14006 +#define IDS_AG_OPENDIRECTORY 14007 +#define IDS_PLAYLIST_OPEN 14114 +#define IDS_PLAYLIST_ADD 14115 +#define IDS_PLAYLIST_REMOVE 14116 +#define IDS_PLAYLIST_CLEAR 14117 +#define IDS_PLAYLIST_COPYTOCLIPBOARD 14118 +#define IDS_PLAYLIST_SAVE 14119 +#define IDS_PLAYLIST_SAVEAS 14120 +#define IDS_PLAYLIST_SORTBYLABEL 14121 +#define IDS_PLAYLIST_SORTBYPATH 14122 +#define IDS_PLAYLIST_RANDOMIZE 14123 +#define IDS_PLAYLIST_RESTORE 14124 +#define IDS_SUBRESYNC_SEPARATOR 14125 +#define IDS_SUBRESYNC_DELETE 14126 +#define IDS_SUBRESYNC_DUPLICATE 14127 +#define IDS_SUBRESYNC_RESET 14128 +#define IDS_SUBRESYNC_ORIGINAL 14129 +#define IDS_SUBRESYNC_CURRENT 14130 +#define IDS_SUBRESYNC_EDIT 14131 +#define IDS_SUBRESYNC_YES 14132 +#define IDS_SUBRESYNC_NO 14133 +#define IDS_SUBRESYNC_DECREASE 14134 +#define IDS_SUBRESYNC_INCREASE 14135 +#define IDS_OPTIONS_CAPTION 14136 +#define IDS_SHADERS_SELECT 14137 +#define IDS_SHADERS_DEBUG 14138 +#define IDS_FAVORITES_ADD 14153 +#define IDS_FAVORITES_ORGANIZE 14154 +#define IDS_PLAYLIST_SHUFFLE 14155 +#define IDS_PLAYLIST_SHOWFOLDER 14156 +#define IDS_CONTROLS_CLOSING 14157 +#define IDS_CONTROLS_PLAYING 14158 +#define IDS_CONTROLS_PAUSED 14159 +#define IDS_CONTROLS_STOPPED 14160 +#define IDS_CONTROLS_BUFFERING 14161 +#define IDS_CONTROLS_CAPTURING 14162 +#define IDS_CONTROLS_OPENING 14163 +#define IDS_CONTROLS_CLOSED 14164 +#define IDS_SUBTITLES_OPTIONS 14165 +#define IDS_SUBTITLES_STYLES 14166 +#define IDS_SUBTITLES_RELOAD 14167 +#define IDS_SUBTITLES_HIDE 14168 +#define IDS_PANSCAN_EDIT 14169 +#define IDS_INFOBAR_TITLE 14170 +#define IDS_INFOBAR_AUTHOR 14171 +#define IDS_INFOBAR_COPYRIGHT 14172 +#define IDS_INFOBAR_RATING 14173 +#define IDS_INFOBAR_DESCRIPTION 14174 +#define IDS_INFOBAR_DOMAIN 14175 +#define IDS_INFOBAR_LOCATION 14176 +#define IDS_INFOBAR_VIDEO 14177 +#define IDS_INFOBAR_AUDIO 14178 +#define IDS_INFOBAR_SUBTITLES 14179 +#define IDS_INFOBAR_CHAPTER 14180 +#define IDS_CONTROLS_COMPLETING 14181 +#define IDS_AUTOPLAY_PLAYVIDEO 14182 +#define IDS_AUTOPLAY_PLAYMUSIC 14183 +#define IDS_AUTOPLAY_PLAYAUDIOCD 14184 +#define IDS_AUTOPLAY_PLAYDVDMOVIE 14185 +#define IDS_PROPSHEET_PROPERTIES 14186 +#define IDS_PLAY_LOOPMODE_FILE 14187 +#define IDS_SUB_OVERRIDE_DEFAULT_STYLE 14188 +#define IDS_PLAY_LOOPMODE_PLAYLIST 14189 +#define IDS_FAVFILES 14190 +#define IDS_FAVDVDS 14191 +#define IDS_INFOBAR_CHANNEL 14192 +#define IDS_INFOBAR_TIME 14193 +#define IDS_STATSBAR_SYNC_OFFSET 14194 +#define IDS_STATSBAR_SYNC_OFFSET_FORMAT 14195 +#define IDS_STATSBAR_JITTER 14196 +#define IDS_STATSBAR_BITRATE 14197 +#define IDS_STATSBAR_BITRATE_AVG_CUR 14198 +#define IDS_STATSBAR_SIGNAL 14199 +#define IDS_STATSBAR_SIGNAL_FORMAT 14200 +#define IDS_SUBTITLES_STYLES_CAPTION 14201 +#define IDS_TEXT_SUB_RENDERING_TARGET 14202 +#define IDS_PLAYLOOPMODE_PLAYLIST 14203 +#define IDS_PLAYLOOPMODE_FILE 14204 +#define IDS_PLAYLOOP_FOREVER_ON 14205 +#define IDS_PLAYLOOP_FOREVER_OFF 14206 +#define IDS_PLAYLOOP_FOREVER 14207 +#define IDS_PLAYLOOPMODE_AB 14208 +#define IDS_PLAY_LOOPMODE_AB 14209 +#define IDS_PLAYLOOPMODE_AB_MARK_A 14210 +#define IDS_PLAYLOOPMODE_AB_MARK_B 14211 +#define IDS_SNAPSHOT_SUBTITLES 14212 +#define IDS_THEMEMODE_DARK 14213 +#define IDS_THEMEMODE_LIGHT 14214 +#define IDS_THEMEMODE_WINDOWS 14215 +#define IDS_SUB_OVERRIDE_ALL_STYLES 14216 +#define IDD_TUNER_SCAN 20002 +#define IDS_OSD_DISPLAY_RENDERER_STATS 20003 +#define IDD_PPAGELOGO2 20003 +#define IDS_OSD_RESET_RENDERER_STATS 20004 +#define IDD_NAVIGATION_DLG 20005 +#define IDD_PPAGESUBMISC 20006 +#define IDS_VIEW_BORDERLESS 20007 +#define IDS_VIEW_FRAMEONLY 20008 +#define IDS_VIEW_CAPTIONMENU 20009 +#define IDS_VIEW_HIDEMENU 20010 +#define IDD_UPDATE_DIALOG 20011 +#define IDF_WIN7_TOOLBAR 20012 +#define IDD_DEBUGSHADERS_DLG 20013 +#define IDD_PPAGEADVANCED 20014 +#define IDD_CMD_LINE_HELP 20016 +#define IDD_CRASH_REPORTER 20017 +#define IDD_PPAGEDPICALC 20018 +#define IDD_RAR_ENTRY_SELECTOR 20019 +#define IDD_ADDCOMMAND_DLG 20020 +#define IDD_PPAGETOOLBAR 20021 +#define IDB_DT_CB_96 20050 +#define IDB_DT_CB_120 20051 +#define IDB_DT_CB_144 20052 +#define IDB_DT_CB_192 20053 +#define IDB_DT_RADIO_96 20054 +#define IDB_DT_RADIO_120 20055 +#define IDB_DT_RADIO_144 20056 +#define IDB_DT_RADIO_129 20057 +#define IDB_DT_RADIO_192 20057 +#define IDS_MESSAGEBOX_CANCEL 20059 +#define IDS_MESSAGEBOX_ABORT 20060 +#define IDS_MESSAGEBOX_RETRY 20061 +#define IDS_MESSAGEBOX_IGNORE 20062 +#define IDS_MESSAGEBOX_OK 20063 +#define IDS_MESSAGEBOX_CONTINUE 20064 +#define IDS_AG_TOGGLE_DEFAULT_SUBTITLE_STYLE 20065 +#define ID_FILE_OPEN_LOCATION 20066 +#define IDB_NOIMAGE 20067 +#define IDB_GRIPPER_168 20070 +#define IDB_GRIPPER_144 20071 +#define IDB_GRIPPER_192 20073 +#define IDB_GRIPPER_96 20074 +#define IDB_PNG1 20075 +#define IDB_GRIPPER_120 20075 +#define IDI_OPENSUBTITLES 21001 +#define IDI_PODNAPISI 21002 +#define IDI_N24 21006 +#define IDC_FULLSCREEN_MONITOR_CHECK 22002 +#define IDC_SLI_CONTRAST 22003 +#define IDC_RESET 22004 +#define IDC_DVD_POS 22005 +#define IDC_FILE_POS 22006 +#define IDC_EVR_BUFFERS 22010 +#define IDC_VERSION 22011 +#define IDC_SHOW_OSD 22013 +#define IDC_EVR_BUFFERS_TXT 22014 +#define IDC_LAVFILTERS_VERSION 22016 +#define IDC_DSVMR9ALTERNATIVEVSYNC 22017 +#define IDC_HOMEPAGE_LINK 22018 +#define IDC_QUALITY 22019 +#define IDC_PROGRESS 22020 +#define IDC_FREQ_START 22021 +#define IDC_BANDWIDTH 22022 +#define IDC_FREQ_END 22023 +#define IDC_CHANNEL_LIST 22024 +#define ID_START 22025 +#define IDC_SYMBOLRATE 22026 +#define ID_SAVE 22030 +#define IDC_STRENGTH 22031 +#define IDC_SYNCVIDEO 22032 +#define IDC_SYNCDISPLAY 22033 +#define IDC_CYCLEDELTA 22034 +#define IDC_LINEDELTA 22035 +#define IDC_COLUMNDELTA 22036 +#define IDC_TARGETSYNCOFFSET 22037 +#define IDC_CONTROLLIMIT 22038 +#define IDC_SYNCNEAREST 22040 +#define IDC_D3D9DEVICE 22041 +#define IDC_NAVIGATION_SCAN 22043 +#define IDC_D3D9DEVICE_COMBO 22045 +#define IDC_NAVIGATION_INFO 22046 +#define IDC_NAVIGATION_FILTERSTATIONS 22047 +#define IDC_CHECK_OFFSET 22048 +#define IDC_OFFSET 22049 +#define IDC_CHECK_IGNORE_ENCRYPTED 22050 +#define IDC_UPDATE_DLG_TEXT 22051 +#define IDC_UPDATE_ICON 22052 +#define IDC_UPDATE_DL_BUTTON 22053 +#define IDC_UPDATE_LATER_BUTTON 22054 +#define IDC_UPDATE_IGNORE_BUTTON 22055 +#define IDC_AUTHORS_LINK 22056 +#define IDC_CHECK_LCD 22059 +#define IDC_VIDRND_COMBO 22060 +#define IDC_AUDRND_COMBO 22063 +#define IDC_VIDRND_DXVA_SUPPORT 22064 +#define IDC_VIDRND_SHADER_SUPPORT 22065 +#define IDC_VIDRND_SUBTITLE_SUPPORT 22066 +#define IDC_VIDRND_SAVEIMAGE_SUPPORT 22067 +#define IDC_VIDRND_ROTATION_SUPPORT 22068 +#define IDC_VOLUMESTEP 22073 +#define IDC_VOLUMESTEP_SPIN 22074 +#define IDC_SPEEDSTEP 22075 +#define IDC_SPEEDSTEP_SPIN 22076 +#define IDC_EXPORT_KEYS 22077 +#define IDC_PPAGECAPTURE_ST10 22078 +#define IDC_PPAGECAPTURE_ST11 22079 +#define IDC_PPAGECAPTURE_ST12 22080 +#define IDC_FASTSEEK_CHECK 22081 +#define IDC_ASSOCIATE_ALL_FORMATS 22082 +#define IDC_ASSOCIATE_VIDEO_FORMATS 22083 +#define IDC_ASSOCIATE_AUDIO_FORMATS 22084 +#define IDC_CLEAR_ALL_ASSOCIATIONS 22085 +#define IDC_SEEK_PREVIEW 22086 +#define IDC_CHECK_AUTOSAVE_ONLINE_SUBTITLE 22087 +#define IDC_STATIC21 22088 +#define IDC_STATIC22 22089 +#define IDC_STATIC23 22090 +#define IDC_STATIC_LIBASS 22091 +#define IDC_MODERNSEEKBARHEIGHT 22092 +#define IDC_MODERNSEEKBARHEIGHT_SPIN 22093 +#define ID_SUB_DELAY_DOWN 24000 +#define ID_SUB_DELAY_UP 24001 +#define IDS_MPLAYERC_104 24002 +#define IDS_MPLAYERC_105 24003 +#define IDS_FILE_SAVE_THUMBNAILS 24005 +#define ID_VIEW_FORCEINPUTHIGHCOLORRESOLUTION 24028 +#define ID_VIEW_FULLFLOATINGPOINTPROCESSING 24029 +#define ID_VIEW_CM_ENABLE 24030 +#define ID_VIEW_CM_INPUT_AUTO 24031 +#define ID_VIEW_CM_INPUT_HDTV 24032 +#define ID_VIEW_CM_INPUT_SDTV_NTSC 24033 +#define ID_VIEW_CM_INPUT_SDTV_PAL 24034 +#define ID_VIEW_CM_AMBIENTLIGHT_BRIGHT 24035 +#define ID_VIEW_CM_AMBIENTLIGHT_DIM 24037 +#define ID_VIEW_CM_AMBIENTLIGHT_DARK 24038 +#define ID_VIEW_CM_INTENT_PERCEPTUAL 24039 +#define ID_VIEW_CM_INTENT_RELATIVECOLORIMETRIC 24040 +#define ID_VIEW_CM_INTENT_SATURATION 24041 +#define ID_VIEW_CM_INTENT_ABSOLUTECOLORIMETRIC 24042 +#define ID_VIEW_HALFFLOATINGPOINTPROCESSING 24043 +#define ID_FILE_RECYCLE 24044 +#define ID_VIEW_MPCTHEME 24045 +#define PLAYER_PLAYLIST_UPDATE_SCROLLBAR 24048 +#define IDF_LOGO4 24050 +#define ID_SUBTITLES_OVERRIDE_DEFAULT_STYLE 24051 +#define ID_SUB_POS_DOWN 24052 +#define ID_SUB_POS_UP 24053 +#define ID_SUB_FONT_SIZE_DEC 24054 +#define ID_SUB_FONT_SIZE_INC 24055 +#define IDS_SUB_POS_DOWN 24056 +#define IDS_SUB_POS_UP 24057 +#define IDS_SUB_FONT_SIZE_DEC 24058 +#define IDS_SUB_FONT_SIZE_INC 24059 +#define ID_VIEW_TEARING_TEST 32769 +#define ID_FILE_OPENDISC 32774 +#define ID_SHADERS 32775 +#define ID_VIEW_OSD_SHOW_FILENAME 32777 +#define ID_VIEW_OSD_DISPLAY_TIME 32778 +#define ID_D3DFULLSCREEN_TOGGLE 32779 +#define ID_GOTO_PREV_SUB 32780 +#define ID_GOTO_NEXT_SUB 32781 +#define ID_SUBRESYNC_SHIFT_DOWN 32782 +#define ID_SUBRESYNC_SHIFT_UP 32783 +#define ID_VIEW_DISPLAY_RENDERER_STATS 32784 +#define ID_VIEW_RESET_RENDERER_STATS 32785 +#define IDS_AG_CLOSE 32830 +#define IDS_AG_NONE 32832 +#define IDS_AG_COMMAND 32833 +#define IDS_AG_KEY 32834 +#define IDS_AG_MOUSE 32836 +#define IDS_AG_APP_COMMAND 32838 +#define IDS_AG_MEDIAFILES 32871 +#define IDS_AG_ALLFILES 32872 +#define IDS_AG_AUDIOFILES 32873 +#define IDS_AG_NOT_KNOWN 32876 +#define IDS_MPLAYERC_0 32877 +#define IDS_AG_OPEN_FILE 32878 +#define IDS_AG_OPEN_DVD 32879 +#define IDS_AG_OPEN_DEVICE 32880 +#define IDS_AG_SAVE_AS 32881 +#define IDS_AG_SAVE_IMAGE 32882 +#define IDS_MPLAYERC_6 32883 +#define IDS_OSD_IMAGE_SAVED 32884 +#define IDS_AG_LOAD_SUBTITLES 32885 +#define IDS_AG_SAVE_SUBTITLES 32886 +#define IDS_AG_PROPERTIES 32887 +#define IDS_AG_EXIT 32888 +#define IDS_AG_PLAYPAUSE 32889 +#define IDS_AG_PLAY 32890 +#define IDS_AG_STOP 32891 +#define IDS_AG_FRAMESTEP 32892 +#define IDS_MPLAYERC_16 32893 +#define IDS_AG_GO_TO 32894 +#define IDS_AG_INCREASE_RATE 32895 +#define IDS_AG_DECREASE_RATE 32896 +#define IDS_AG_RESET_RATE 32897 +#define IDS_MPLAYERC_21 32898 +#define IDS_MPLAYERC_22 32899 +#define IDS_MPLAYERC_23 32900 +#define IDS_MPLAYERC_24 32901 +#define IDS_MPLAYERC_25 32902 +#define IDS_MPLAYERC_26 32903 +#define IDS_MPLAYERC_27 32904 +#define IDS_MPLAYERC_28 32905 +#define IDS_MPLAYERC_29 32906 +#define IDS_MPLAYERC_30 32907 +#define IDS_AG_NEXT 32908 +#define IDS_AG_PREVIOUS 32909 +#define IDS_AG_NEXT_FILE 32910 +#define IDS_AG_PREVIOUS_FILE 32911 +#define IDS_AG_VIEW_MINIMAL 32912 +#define IDS_AG_VIEW_COMPACT 32913 +#define IDS_AG_VIEW_NORMAL 32914 +#define IDS_AG_FULLSCREEN 32915 +#define IDS_MPLAYERC_39 32916 +#define IDS_AG_ZOOM_AUTO_FIT 32917 +#define IDS_AG_VIDFRM_HALF 32918 +#define IDS_AG_VIDFRM_NORMAL 32919 +#define IDS_AG_VIDFRM_DOUBLE 32920 +#define IDS_AG_ALWAYS_ON_TOP 32921 +#define IDS_AG_PNS_INC_SIZE 32922 +#define IDS_AG_PNS_INC_WIDTH 32923 +#define IDS_MPLAYERC_47 32924 +#define IDS_AG_PNS_DEC_SIZE 32925 +#define IDS_AG_PNS_DEC_WIDTH 32926 +#define IDS_MPLAYERC_50 32927 +#define IDS_AG_PNS_CENTER 32928 +#define IDS_AG_PNS_LEFT 32929 +#define IDS_AG_PNS_RIGHT 32930 +#define IDS_AG_PNS_UP 32931 +#define IDS_AG_PNS_DOWN 32932 +#define IDS_AG_PNS_UPLEFT 32933 +#define IDS_AG_PNS_UPRIGHT 32934 +#define IDS_AG_PNS_DOWNLEFT 32935 +#define IDS_MPLAYERC_59 32936 +#define IDS_AG_VOLUME_UP 32937 +#define IDS_AG_VOLUME_DOWN 32938 +#define IDS_AG_VOLUME_MUTE 32939 +#define IDS_MPLAYERC_63 32940 +#define IDS_AG_DVD_ROOT_MENU 32941 +#define IDS_MPLAYERC_65 32942 +#define IDS_MPLAYERC_66 32943 +#define IDS_MPLAYERC_67 32944 +#define IDS_MPLAYERC_68 32945 +#define IDS_AG_DVD_MENU_LEFT 32946 +#define IDS_MPLAYERC_70 32947 +#define IDS_AG_DVD_MENU_UP 32948 +#define IDS_AG_DVD_MENU_DOWN 32949 +#define IDS_MPLAYERC_73 32950 +#define IDS_AG_DVD_MENU_BACK 32951 +#define IDS_MPLAYERC_75 32952 +#define IDS_AG_BOSS_KEY 32953 +#define IDS_MPLAYERC_77 32954 +#define IDS_MPLAYERC_78 32955 +#define IDS_AG_FILTERS_MENU 32956 +#define IDS_AG_OPTIONS 32957 +#define IDS_AG_NEXT_AUDIO 32958 +#define IDS_AG_PREV_AUDIO 32959 +#define IDS_AG_NEXT_SUBTITLE 32960 +#define IDS_AG_PREV_SUBTITLE 32961 +#define IDS_MPLAYERC_85 32962 +#define IDS_MPLAYERC_86 32963 +#define IDS_MPLAYERC_91 32968 +#define IDS_MPLAYERC_92 32969 +#define IDS_MPLAYERC_93 32970 +#define IDS_MPLAYERC_94 32971 +#define IDS_MPLAYERC_95 32972 +#define IDS_MPLAYERC_96 32973 +#define IDS_MPLAYERC_97 32974 +#define IDS_OSD_DISPLAY_CURRENT_TIME 32975 +#define IDS_MPLAYERC_99 32976 +#define IDS_MPLAYERC_100 32977 +#define IDS_MPLAYERC_101 32978 +#define IDS_MPLAYERC_102 32979 +#define IDS_MPLAYERC_103 32980 +#define IDS_AG_SEEKSET 32982 +#define IDS_OSD_SHOW_FILENAME 32983 +#define IDS_PLAY_DVD 32984 +#define IDS_PLAY_BD 32985 +#define IDS_PPAGEWEBSERVER_0 32996 +#define IDS_MAINFRM_2 33014 +#define IDS_AG_SUBTITLES_SAVED 33015 +#define IDS_MAINFRM_4 33016 +#define IDS_AG_FRAMERATE 33017 +#define IDS_MAINFRM_6 33018 +#define IDS_AG_FRAMES 33019 +#define IDS_AG_BUFFERS 33020 +#define IDS_MAINFRM_9 33021 +#define IDS_MAINFRM_10 33022 +#define IDS_MAINFRM_11 33023 +#define IDS_AG_TITLE 33024 +#define IDS_MAINFRM_16 33025 +#define IDS_MAINFRM_17 33026 +#define IDS_MAINFRM_18 33027 +#define IDS_MAINFRM_19 33028 +#define IDS_MAINFRM_20 33029 +#define IDS_MAINFRM_21 33030 +#define IDS_MAINFRM_22 33031 +#define IDS_MAINFRM_23 33032 +#define IDS_AG_ASPECT_RATIO 33045 +#define IDS_MAINFRM_37 33046 +#define IDS_MAINFRM_38 33047 +#define IDS_MAINFRM_39 33048 +#define IDS_MAINFRM_40 33049 +#define IDS_MAINFRM_41 33050 +#define IDS_MAINFRM_42 33051 +#define IDS_AG_ERROR 33052 +#define IDS_SUBTITLE_STREAM_OFF 33053 +#define IDS_SUBTITLE_STREAM 33054 +#define IDS_MAINFRM_46 33055 +#define IDS_SUB_LOADED_SUCCESS 33056 +#define IDS_ALL_FILES_FILTER 33057 +#define IDS_GETDIB_FAILED 33058 +#define IDS_GETCURRENTIMAGE_FAILED 33059 +#define IDS_SCREENSHOT_ERROR 33060 +#define IDS_THUMBNAILS_NO_DURATION 33061 +#define IDS_THUMBNAILS_NO_FRAME_SIZE 33062 +#define IDS_OUT_OF_MEMORY 33063 +#define IDS_THUMBNAILS_INVALID_FORMAT 33064 +#define IDS_THUMBNAILS_INFO_FILESIZE 33065 +#define IDS_THUMBNAILS_INFO_HEADER 33066 +#define IDS_THUMBNAIL_TOO_SMALL 33067 +#define IDS_CANNOT_LOAD_SUB 33068 +#define IDS_SUBTITLE_FILES_FILTER 33069 +#define IDS_MAINFRM_68 33075 +#define IDS_MAINFRM_69 33076 +#define IDS_MAINFRM_70 33077 +#define IDS_AG_CHAPTER 33078 +#define IDS_AG_OUT_OF_MEMORY 33081 +#define IDS_MAINFRM_77 33082 +#define IDS_MAINFRM_80 33084 +#define IDS_MAINFRM_81 33085 +#define IDS_MAINFRM_82 33086 +#define IDS_MAINFRM_83 33087 +#define IDS_MAINFRM_84 33088 +#define IDS_MAINFRM_86 33089 +#define IDS_MAINFRM_87 33090 +#define IDS_MAINFRM_88 33091 +#define IDS_MAINFRM_89 33092 +#define IDS_MAINFRM_90 33093 +#define IDS_MAINFRM_91 33094 +#define IDS_MAINFRM_92 33095 +#define IDS_MAINFRM_93 33096 +#define IDS_MAINFRM_94 33097 +#define IDS_AG_FAILED 33098 +#define IDS_MAINFRM_96 33099 +#define IDS_MAINFRM_98 33100 +#define IDS_MAINFRM_99 33101 +#define IDS_MAINFRM_108 33106 +#define IDS_AG_SOUND 33107 +#define IDS_MAINFRM_114 33108 +#define IDS_AG_ABORTED 33109 +#define IDS_MAINFRM_116 33110 +#define IDS_MAINFRM_117 33111 +#define IDS_AG_UNKNOWN_STREAM 33112 +#define IDS_AG_UNKNOWN 33113 +#define IDS_AG_VSYNC 33114 +#define IDS_MAINFRM_121 33115 +#define IDS_MAINFRM_122 33116 +#define IDS_DVD_SUBTITLES_ENABLE 33117 +#define IDS_AG_ANGLE 33118 +#define IDS_AG_VSYNCOFFSET_INCREASE 33119 +#define IDS_AG_DISABLED 33120 +#define IDS_AG_VSYNCOFFSET_DECREASE 33121 +#define IDS_MAINFRM_136 33126 +#define IDS_MAINFRM_137 33127 +#define IDS_MAINFRM_138 33128 +#define IDS_VOLUME_BOOST_INC 33129 +#define IDS_VOLUME_BOOST_DEC 33130 +#define IDS_VOLUME_BOOST_MIN 33131 +#define IDS_VOLUME_BOOST_MAX 33132 +#define IDS_USAGE 33133 +#define IDS_UNKNOWN_SWITCH 33134 +#define IDS_ADD_TO_PLAYLIST 33161 +#define IDS_OPEN_WITH_MPC 33162 +#define IDS_CANNOT_CHANGE_FORMAT 33163 +#define IDS_APP_DESCRIPTION 33164 +#define IDS_MAINFRM_12 33165 +#define IDS_MAINFRM_13 33166 +#define IDS_D3DFS_WARNING 33190 +#define IDS_MAINFRM_139 33191 +#define IDS_AG_TITLE2 33192 +#define IDS_REALVIDEO_INCOMPATIBLE 33193 +#define IDS_THUMB_ROWNUMBER 33195 +#define IDS_THUMB_COLNUMBER 33196 +#define IDS_THUMB_IMAGE_WIDTH 33197 +#define IDS_AG_CHAPTER2 33201 +#define IDS_VOLUME_OSD 33202 +#define IDS_BOOST_OSD 33203 +#define IDS_BALANCE_OSD 33204 +#define IDS_FULLSCREENMONITOR_CURRENT 33205 +#define ID_FILE_OPENDIRECTORY 33208 +#define IDS_MAINFRM_DIR_TITLE 33209 +#define IDS_MAINFRM_DIR_CHECK 33210 +#define IDS_AG_PAUSE 33212 +#define IDS_AG_TOGGLE_CAPTION 33213 +#define IDS_AG_TOGGLE_SEEKER 33214 +#define IDS_AG_TOGGLE_CONTROLS 33215 +#define IDS_AG_TOGGLE_INFO 33216 +#define IDS_AG_TOGGLE_STATS 33217 +#define IDS_AG_TOGGLE_STATUS 33218 +#define IDS_AG_TOGGLE_SUBRESYNC 33219 +#define IDS_AG_TOGGLE_PLAYLIST 33220 +#define IDS_AG_TOGGLE_CAPTURE 33221 +#define IDS_AG_TOGGLE_DEBUGSHADERS 33222 +#define IDS_AG_ZOOM_50 33223 +#define IDS_AG_ZOOM_100 33224 +#define IDS_AG_ZOOM_200 33225 +#define IDS_AG_NEXT_AR_PRESET 33226 +#define IDS_AG_VIDFRM_STRETCH 33227 +#define IDS_AG_VIDFRM_INSIDE 33228 +#define IDS_AG_VIDFRM_OUTSIDE 33229 +#define IDS_AG_PNS_RESET 33230 +#define IDS_AG_PNS_ROTATEX_P 33231 +#define IDS_AG_PNS_ROTATEX_M 33232 +#define IDS_AG_PNS_ROTATEY_P 33233 +#define IDS_AG_PNS_ROTATEY_M 33234 +#define IDS_AG_PNS_ROTATEZ_P 33235 +#define IDS_AG_PNS_ROTATEZ_M 33236 +#define IDS_AG_TEARING_TEST 33237 +#define IDS_SCALE_16_9 33239 +#define IDS_SCALE_WIDESCREEN 33240 +#define IDS_SCALE_ULTRAWIDE 33241 +#define IDS_PLAYLIST_HIDEFS 33242 +#define ID_VIEW_VSYNC 33243 +#define ID_VIEW_VSYNCOFFSET 33245 +#define ID_VIEW_VSYNCOFFSET_DECREASE 33246 +#define ID_VIEW_VSYNCOFFSET_INCREASE 33247 +#define IDS_AG_TOGGLE_NAVIGATION 33248 +#define ID_VIEW_VSYNCACCURATE 33260 +#define IDS_AG_VSYNCACCURATE 33261 +#define ID_VIEW_FULLSCREENGUISUPPORT 33263 +#define ID_VIEW_HIGHCOLORRESOLUTION 33264 +#define ID_VIEW_ENABLEFRAMETIMECORRECTION 33265 +#define ID_VIEW_EVROUTPUTRANGE 33269 +#define ID_VIEW_EVROUTPUTRANGE_0_255 33273 +#define ID_VIEW_EVROUTPUTRANGE_16_235 33274 +#define IDS_AG_ENABLEFRAMETIMECORRECTION 33275 +#define IDS_AG_TOGGLE_EDITLISTEDITOR 33277 +#define IDS_AG_EDL_IN 33278 +#define IDS_AG_EDL_OUT 33279 +#define IDS_AG_EDL_NEW_CLIP 33280 +#define ID_RECENT_FILES 33281 +#define ID_RECENT_FILES_CLEAR 33282 +#define IDS_RECENT_FILES_CLEAR 33283 +#define IDS_RECENT_FILES_QUESTION 33284 +#define ID_VIEW_FLUSHGPU_BEFOREVSYNC 33286 +#define ID_VIEW_FLUSHGPU_AFTERPRESENT 33287 +#define ID_VIEW_FLUSHGPU_WAIT 33288 +#define ID_VIEW_D3DFULLSCREEN 33289 +#define ID_VIEW_DISABLEDESKTOPCOMPOSITION 33290 +#define ID_VIEW_ALTERNATIVEVSYNC 33291 +#define ID_VIEW_RESET_DEFAULT 33292 +#define ID_VIEW_RESET_OPTIMAL 33293 +#define IDS_AG_EDL_SAVE 33294 +#define IDC_RESETDEVICE 33400 +#define IDS_NAVIGATE_TUNERSCAN 33401 +#define IDS_SUBTITLES_ERROR 33402 +#define IDC_CHECK_ENHANCED_TASKBAR 33403 +#define IDC_CACHESHADERS 33404 +#define ID_VIEW_SYNCHRONIZEVIDEO 33408 +#define ID_VIEW_SYNCHRONIZEDISPLAY 33409 +#define ID_VIEW_SYNCHRONIZENEAREST 33410 +#define ID_VIEW_NAVIGATION 33415 +#define IDS_AG_VIDFRM_ZOOM1 33419 +#define IDS_AG_VIDFRM_ZOOM2 33420 +#define IDS_AG_VIDFRM_SWITCHZOOM 33422 +#define IDS_ENABLE_ALL_FILTERS 33423 +#define IDS_DISABLE_ALL_FILTERS 33424 +#define IDS_ENABLE_AUDIO_FILTERS 33425 +#define IDS_DISABLE_AUDIO_FILTERS 33426 +#define IDS_ENABLE_VIDEO_FILTERS 33427 +#define IDS_DISABLE_VIDEO_FILTERS 33428 +#define IDS_STRETCH_TO_WINDOW 33429 +#define IDS_TOUCH_WINDOW_FROM_INSIDE 33430 +#define IDS_ZOOM1 33431 +#define IDS_ZOOM2 33432 +#define IDS_TOUCH_WINDOW_FROM_OUTSIDE 33433 +#define IDS_AUDIO_STREAM 33434 +#define IDS_AG_REOPEN 33435 +#define IDS_TIME_TOOLTIP_ABOVE 33440 +#define IDS_TIME_TOOLTIP_BELOW 33441 +#define IDS_VIDEO_STREAM 33442 +#define IDS_APPLY 33443 +#define IDS_CLEAR 33444 +#define IDS_CANCEL 33445 +#define IDS_THUMB_THUMBNAILS 33446 +#define IDS_THUMB_PIXELS 33447 +#define IDS_TEXTFILE_ENC 33448 +#define ID_PLAY_REPEAT_FOREVER 33449 +#define ID_PLAY_REPEAT_ONEFILE 33450 +#define ID_PLAY_REPEAT_WHOLEPLAYLIST 33451 +#define IDS_AG_ZOOM_25 33452 +#define ID_PLAY_REPEAT_AB 33453 +#define IDS_AG_MOUSE_MODIFIER 33453 +#define ID_PLAY_REPEAT_AB_MARK_A 33454 +#define ID_PLAY_REPEAT_AB_MARK_B 33455 +#define ID_VIEW_ZOOM_SUB 33456 +#define ID_VIEW_ZOOM_ADD 33457 +#define IDS_AG_ZOOM_ADD 33458 +#define IDS_AG_ZOOM_SUB 33459 +#define IDS_SEEKBAR_HOVER_PREVIEW 33460 +#define IDS_SEEKBAR_HOVER_TOOLTIP 33461 +#define ID_RECENT_FILE_START 34000 +#define ID_RECENT_FILE_END 34999 +#define IDS_MFMT_AVI 39001 +#define IDS_MFMT_MPEG 39002 +#define IDS_MFMT_MPEGTS 39003 +#define IDS_MFMT_DVDVIDEO 39004 +#define IDS_MFMT_MKV 39005 +#define IDS_MFMT_WEBM 39006 +#define IDS_MFMT_MP4 39007 +#define IDS_MFMT_MOV 39008 +#define IDS_MFMT_3GP 39009 +#define IDS_MFMT_3GA 39010 +#define IDS_MFMT_FLV 39011 +#define IDS_MFMT_OGM 39012 +#define IDS_MFMT_RM 39013 +#define IDS_MFMT_RT 39014 +#define IDS_MFMT_WMV 39015 +#define IDS_MFMT_BINK 39018 +#define IDS_MFMT_FLIC 39019 +#define IDS_MFMT_DSM 39020 +#define IDS_MFMT_IVF 39021 +#define IDS_MFMT_AVS 39022 +#define IDS_MFMT_OTHER 39401 +#define IDS_MFMT_SWF 39403 +#define IDS_MFMT_OTHER_AUDIO 39404 +#define IDS_MFMT_AC3 39501 +#define IDS_MFMT_AIFF 39502 +#define IDS_MFMT_ALAC 39503 +#define IDS_MFMT_AMR 39504 +#define IDS_MFMT_APE 39505 +#define IDS_MFMT_AU 39506 +#define IDS_MFMT_CDA 39507 +#define IDS_MFMT_FLAC 39508 +#define IDS_MFMT_M4A 39509 +#define IDS_MFMT_MIDI 39510 +#define IDS_MFMT_MKA 39511 +#define IDS_MFMT_MP3 39512 +#define IDS_MFMT_MPA 39513 +#define IDS_MFMT_MPC 39514 +#define IDS_MFMT_OFR 39515 +#define IDS_MFMT_OGG 39516 +#define IDS_MFMT_RA 39517 +#define IDS_MFMT_TAK 39518 +#define IDS_MFMT_TTA 39519 +#define IDS_MFMT_WAV 39520 +#define IDS_MFMT_WMA 39521 +#define IDS_MFMT_WV 39522 +#define IDS_MFMT_OPUS 39523 +#define IDS_MFMT_DTS 39524 +#define IDS_MFMT_PLS 39901 +#define IDS_MFMT_BDPLS 39902 +#define IDS_MFMT_RAR 39903 +#define IDTB_BUTTON1 40001 +#define IDTB_BUTTON2 40002 +#define IDTB_BUTTON3 40003 +#define IDTB_BUTTON4 40004 +#define IDTB_BUTTON5 40005 +#define IDR_TB_PLAY 41001 +#define IDR_TB_PAUSE 41002 +#define IDR_TB_STOP 41003 +#define IDS_FRONT_LEFT 41006 +#define IDS_FRONT_RIGHT 41007 +#define IDS_FRONT_CENTER 41008 +#define IDS_LOW_FREQUENCY 41009 +#define IDS_BACK_LEFT 41010 +#define IDS_BACK_RIGHT 41011 +#define IDS_FRONT_LEFT_OF_CENTER 41012 +#define IDS_FRONT_RIGHT_OF_CENTER 41013 +#define IDS_BACK_CENTER 41014 +#define IDS_SIDE_LEFT 41015 +#define IDS_SIDE_RIGHT 41016 +#define IDS_TOP_CENTER 41017 +#define IDS_TOP_FRONT_LEFT 41018 +#define IDS_TOP_FRONT_CENTER 41019 +#define IDS_TOP_FRONT_RIGHT 41020 +#define IDS_TOP_BACK_LEFT 41021 +#define IDS_TOP_BACK_CENTER 41022 +#define IDS_TOP_BACK_RIGHT 41023 +#define IDS_LOGO_AUTHOR 41024 +#define IDC_RESTORERESCHECK 41025 +#define IDS_NO_MORE_MEDIA 41026 +#define IDS_FIRST_IN_FOLDER 41027 +#define IDS_LAST_IN_FOLDER 41028 +#define IDS_FAVORITES_QUICKADDFAVORITE 41105 +#define IDS_DVB_CHANNEL_NUMBER 41109 +#define IDS_DVB_CHANNEL_NAME 41110 +#define IDS_DVB_CHANNEL_FREQUENCY 41111 +#define IDS_DVB_CHANNEL_ENCRYPTION 41112 +#define IDS_YES 41113 +#define IDS_NO 41114 +#define IDS_DVB_CHANNEL_START_SCAN 41115 +#define IDS_DVB_CHANNEL_STOP_SCAN 41116 +#define IDS_DVB_TVNAV_SEERADIO 41117 +#define IDS_DVB_TVNAV_SEETV 41118 +#define IDS_DVB_CHANNEL_FORMAT 41119 +#define IDS_DVB_CHANNEL_FPS 41120 +#define IDS_DVB_CHANNEL_RESOLUTION 41121 +#define IDS_DVB_CHANNEL_ASPECT_RATIO 41122 +#define IDS_OSD_RS_VSYNC_ON 41200 +#define IDS_OSD_RS_VSYNC_OFF 41201 +#define IDS_OSD_RS_ACCURATE_VSYNC_ON 41202 +#define IDS_OSD_RS_ACCURATE_VSYNC_OFF 41203 +#define IDS_OSD_RS_SYNC_TO_DISPLAY_ON 41204 +#define IDS_OSD_RS_SYNC_TO_DISPLAY_OFF 41205 +#define IDS_OSD_RS_SYNC_TO_VIDEO_ON 41206 +#define IDS_OSD_RS_SYNC_TO_VIDEO_OFF 41207 +#define IDS_OSD_RS_PRESENT_NEAREST_ON 41208 +#define IDS_OSD_RS_PRESENT_NEAREST_OFF 41209 +#define IDS_OSD_RS_COLOR_MANAGEMENT_ON 41210 +#define IDS_OSD_RS_COLOR_MANAGEMENT_OFF 41211 +#define IDS_OSD_RS_INPUT_TYPE_AUTO 41212 +#define IDS_OSD_RS_INPUT_TYPE_HDTV 41213 +#define IDS_OSD_RS_INPUT_TYPE_SD_NTSC 41214 +#define IDS_OSD_RS_INPUT_TYPE_SD_PAL 41215 +#define IDS_OSD_RS_AMBIENT_LIGHT_BRIGHT 41216 +#define IDS_OSD_RS_AMBIENT_LIGHT_DIM 41217 +#define IDS_OSD_RS_AMBIENT_LIGHT_DARK 41218 +#define IDS_OSD_RS_REND_INTENT_PERCEPT 41219 +#define IDS_OSD_RS_REND_INTENT_RELATIVE 41220 +#define IDS_OSD_RS_REND_INTENT_SATUR 41221 +#define IDS_OSD_RS_REND_INTENT_ABSOLUTE 41222 +#define IDS_OSD_RS_OUTPUT_RANGE 41223 +#define IDS_OSD_RS_FLUSH_BEF_VSYNC_ON 41224 +#define IDS_OSD_RS_FLUSH_BEF_VSYNC_OFF 41225 +#define IDS_OSD_RS_FLUSH_AFT_PRES_ON 41226 +#define IDS_OSD_RS_FLUSH_AFT_PRES_OFF 41227 +#define IDS_OSD_RS_WAIT_ON 41228 +#define IDS_OSD_RS_WAIT_OFF 41229 +#define IDS_OSD_RS_D3D_FULLSCREEN_ON 41230 +#define IDS_OSD_RS_D3D_FULLSCREEN_OFF 41231 +#define IDS_OSD_RS_NO_DESKTOP_COMP_ON 41232 +#define IDS_OSD_RS_NO_DESKTOP_COMP_OFF 41233 +#define IDS_OSD_RS_ALT_VSYNC_ON 41234 +#define IDS_OSD_RS_ALT_VSYNC_OFF 41235 +#define IDS_OSD_RS_RESET_DEFAULT 41236 +#define IDS_OSD_RS_RESET_OPTIMAL 41237 +#define IDS_OSD_RS_D3D_FS_GUI_SUPP_ON 41238 +#define IDS_OSD_RS_D3D_FS_GUI_SUPP_OFF 41239 +#define IDS_OSD_RS_10BIT_RBG_OUT_ON 41240 +#define IDS_OSD_RS_10BIT_RBG_OUT_OFF 41241 +#define IDS_OSD_RS_10BIT_RBG_IN_ON 41242 +#define IDS_OSD_RS_10BIT_RBG_IN_OFF 41243 +#define IDS_OSD_RS_FULL_FP_PROCESS_ON 41244 +#define IDS_OSD_RS_FULL_FP_PROCESS_OFF 41245 +#define IDS_OSD_RS_HALF_FP_PROCESS_ON 41246 +#define IDS_OSD_RS_HALF_FP_PROCESS_OFF 41247 +#define IDS_OSD_RS_FT_CORRECTION_ON 41248 +#define IDS_OSD_RS_FT_CORRECTION_OFF 41249 +#define IDS_OSD_RS_TARGET_VSYNC_OFFSET 41250 +#define IDS_OSD_RS_VSYNC_OFFSET 41251 +#define IDS_OSD_SPEED 41252 +#define IDS_OSD_THUMBS_SAVED 41253 +#define IDS_MENU_VIDEO_STREAM 41254 +#define IDS_MENU_VIDEO_ANGLE 41255 +#define IDS_RESET_SETTINGS 41256 +#define IDS_RESET_SETTINGS_WARNING 41257 +#define IDS_RESET_SETTINGS_MUTEX 41258 +#define IDS_EXPORT_SETTINGS 41259 +#define IDS_EXPORT_SETTINGS_WARNING 41260 +#define IDS_EXPORT_SETTINGS_SUCCESS 41261 +#define IDS_EXPORT_SETTINGS_FAILED 41262 +#define IDS_BDA_ERROR 41263 +#define IDS_BDA_ERROR_CREATE_TUNER 41264 +#define IDS_BDA_ERROR_CREATE_RECEIVER 41265 +#define IDS_BDA_ERROR_CONNECT_NW_TUNER 41266 +#define IDS_BDA_ERROR_CONNECT_TUNER_REC 41267 +#define IDS_BDA_ERROR_CONNECT_TUNER 41268 +#define IDS_BDA_ERROR_DEMULTIPLEXER 41269 +#define IDS_GOTO_ERROR_PARSING_TIME 41270 +#define IDS_GOTO_ERROR_PARSING_TEXT 41271 +#define IDS_GOTO_ERROR_PARSING_FPS 41272 +#define IDS_FRAME_STEP_ERROR_RENDERER 41273 +#define IDS_SCREENSHOT_ERROR_SHOCKWAVE 41276 +#define IDS_SCREENSHOT_ERROR_OVERLAY 41277 +#define IDS_SUBDL_DLG_CONNECT_ERROR 41278 +#define IDS_MB_SHOW_EDL_EDITOR 41279 +#define IDS_CAPTURE_ERROR 41280 +#define IDS_CAPTURE_ERROR_VIDEO 41281 +#define IDS_CAPTURE_ERROR_AUDIO 41282 +#define IDS_CAPTURE_ERROR_ADD_BUFFER 41283 +#define IDS_CAPTURE_ERROR_CONNECT_BUFF 41284 +#define IDS_CAPTURE_ERROR_ADD_ENCODER 41285 +#define IDS_CAPTURE_ERROR_CONNECT_ENC 41286 +#define IDS_CAPTURE_ERROR_COMPRESSION 41287 +#define IDS_CAPTURE_ERROR_MULTIPLEXER 41288 +#define IDS_CAPTURE_ERROR_VID_CAPT_PIN 41289 +#define IDS_CAPTURE_ERROR_AUD_CAPT_PIN 41290 +#define IDS_CAPTURE_ERROR_OUT_FILE 41291 +#define IDS_CAPTURE_ERROR_AUD_OUT_FILE 41292 +#define IDS_SUBRESYNC_TIME_FORMAT 41293 +#define IDS_EXTERNAL_FILTERS_ERROR_MT 41294 +#define IDS_WEBSERVER_ERROR_TEST 41295 +#define IDS_AFTERPLAYBACK_EXIT 41296 +#define IDS_AFTERPLAYBACK_STANDBY 41297 +#define IDS_AFTERPLAYBACK_HIBERNATE 41298 +#define IDS_AFTERPLAYBACK_SHUTDOWN 41299 +#define IDS_AFTERPLAYBACK_LOGOFF 41300 +#define IDS_AFTERPLAYBACK_LOCK 41301 +#define IDS_AFTERPLAYBACK_MONITOROFF 41302 +#define IDS_AFTERPLAYBACK_PLAYNEXT 41303 +#define IDS_AFTERPLAYBACK_DONOTHING 41304 +#define IDS_OSD_BRIGHTNESS 41305 +#define IDS_OSD_CONTRAST 41306 +#define IDS_OSD_HUE 41307 +#define IDS_OSD_SATURATION 41308 +#define IDS_OSD_RESET_COLOR 41309 +#define IDS_OSD_NO_COLORCONTROL 41310 +#define IDS_BRIGHTNESS_INC 41311 +#define IDS_BRIGHTNESS_DEC 41312 +#define IDS_CONTRAST_INC 41313 +#define IDS_CONTRAST_DEC 41314 +#define IDS_HUE_INC 41315 +#define IDS_HUE_DEC 41316 +#define IDS_SATURATION_INC 41317 +#define IDS_SATURATION_DEC 41318 +#define IDS_RESET_COLOR 41319 +#define ID_HELP_CHECKFORUPDATE 41321 +#define IDS_USING_LATEST_STABLE 41322 +#define IDS_USING_NEWER_VERSION 41323 +#define IDS_NEW_UPDATE_AVAILABLE 41324 +#define IDS_UPDATE_ERROR 41325 +#define IDS_UPDATE_CLOSE 41326 +#define IDS_OSD_ZOOM 41327 +#define IDS_OSD_ZOOM_AUTO 41328 +#define IDS_CUSTOM_CHANNEL_MAPPING 41329 +#define IDS_OSD_CUSTOM_CH_MAPPING_ON 41330 +#define IDS_OSD_CUSTOM_CH_MAPPING_OFF 41331 +#define IDS_NORMALIZE 41332 +#define IDS_OSD_NORMALIZE_ON 41333 +#define IDS_OSD_NORMALIZE_OFF 41334 +#define IDS_REGAIN_VOLUME 41335 +#define IDS_OSD_REGAIN_VOLUME_ON 41336 +#define IDS_OSD_REGAIN_VOLUME_OFF 41337 +#define IDS_SIZE_UNIT_BYTES 41338 +#define IDS_SIZE_UNIT_K 41339 +#define IDS_SIZE_UNIT_M 41340 +#define IDS_SIZE_UNIT_G 41341 +#define IDS_SPEED_UNIT_K 41342 +#define IDS_SPEED_UNIT_M 41343 +#define IDS_SPEED_UNIT_G 41344 +#define IDS_FILE_FAV_ADDED 41345 +#define IDS_DVD_FAV_ADDED 41346 +#define IDS_CAPTURE_SETTINGS 41347 +#define IDS_NAVIGATION_BAR 41348 +#define IDS_SUBRESYNC_CAPTION 41350 +#define IDS_SUBRESYNC_CLN_TIME 41351 +#define IDS_SUBRESYNC_CLN_END 41352 +#define IDS_SUBRESYNC_CLN_PREVIEW 41353 +#define IDS_SUBRESYNC_CLN_VOB_ID 41354 +#define IDS_SUBRESYNC_CLN_CELL_ID 41355 +#define IDS_SUBRESYNC_CLN_FORCED 41356 +#define IDS_SUBRESYNC_CLN_TEXT 41357 +#define IDS_SUBRESYNC_CLN_STYLE 41358 +#define IDS_SUBRESYNC_CLN_FONT 41359 +#define IDS_SUBRESYNC_CLN_CHARSET 41360 +#define IDS_SUBRESYNC_CLN_UNICODE 41361 +#define IDS_SUBRESYNC_CLN_LAYER 41362 +#define IDS_SUBRESYNC_CLN_ACTOR 41363 +#define IDS_SUBRESYNC_CLN_EFFECT 41364 +#define IDS_PLAYLIST_CAPTION 41365 +#define IDS_PPAGE_FS_CLN_ON_OFF 41366 +#define IDS_PPAGE_FS_CLN_FROM_FPS 41367 +#define IDS_PPAGE_FS_CLN_TO_FPS 41368 +#define IDS_PPAGE_FS_CLN_DISPLAY_MODE 41369 +#define IDS_PPAGE_FS_DEFAULT 41370 +#define IDS_PPAGE_FS_OTHER 41371 +#define IDS_PPAGE_OUTPUT_SYS_DEF 41372 +#define IDS_GRAPH_INTERFACES_ERROR 41373 +#define IDS_GRAPH_TARGET_WND_ERROR 41374 +#define IDS_DVD_NAV_ALL_PINS_ERROR 41375 +#define IDS_DVD_NAV_SOME_PINS_ERROR 41376 +#define IDS_DVD_INTERFACES_ERROR 41377 +#define IDS_CAPTURE_LIVE 41378 +#define IDS_CAPTURE_ERROR_VID_FILTER 41379 +#define IDS_CAPTURE_ERROR_AUD_FILTER 41380 +#define IDS_CAPTURE_ERROR_DEVICE 41381 +#define IDS_INVALID_PARAMS_ERROR 41382 +#define IDS_EDIT_LIST_EDITOR 41383 +#define IDS_GOTO_ERROR_INVALID_TIME 41384 +#define IDS_MISSING_ICONS_LIB 41386 +#define IDS_SUBDL_DLG_FILENAME_COL 41387 +#define IDS_SUBDL_DLG_LANGUAGE_COL 41388 +#define IDS_SUBDL_DLG_FORMAT_COL 41389 +#define IDS_SUBDL_DLG_DISC_COL 41390 +#define IDS_SUBDL_DLG_TITLES_COL 41391 +#define IDS_SUBDL_DLG_DOWNLOADING 41392 +#define IDS_SUBDL_DLG_PARSING 41393 +#define IDS_SUBDL_DLG_NOT_FOUND 41394 +#define IDS_SUBDL_DLG_SUBS_AVAIL 41395 +#define IDS_UPDATE_CONFIG_AUTO_CHECK 41396 +#define IDS_ZOOM_50 41397 +#define IDS_ZOOM_100 41398 +#define IDS_ZOOM_200 41399 +#define IDS_ZOOM_AUTOFIT 41400 +#define IDS_ZOOM_AUTOFIT_LARGER 41401 +#define IDS_AG_ZOOM_AUTO_FIT_LARGER 41402 +#define IDS_OSD_ZOOM_AUTO_LARGER 41403 +#define IDS_TOOLTIP_EXPLORE_TO_FILE 41404 +#define IDS_TOOLTIP_REMAINING_TIME 41405 +#define IDS_UPDATE_DELAY_ERROR_TITLE 41406 +#define IDS_UPDATE_DELAY_ERROR_MSG 41407 +#define IDS_AUDIOSWITCHER 41408 +#define IDS_ICONS_REASSOC_DLG_TITLE 41409 +#define IDS_ICONS_REASSOC_DLG_INSTR 41410 +#define IDS_ICONS_REASSOC_DLG_CONTENT 41411 +#define IDS_PPAGE_OUTPUT_OLDRENDERER 41412 +#define IDS_PPAGE_OUTPUT_OVERLAYMIXER 41413 +#define IDS_ZOOM_25 41414 +#define IDS_PPAGE_OUTPUT_VMR9WINDOWED 41415 +#define IDS_PPAGE_OUTPUT_VMR9RENDERLESS 41417 +#define IDS_PPAGE_OUTPUT_EVR 41418 +#define IDS_PPAGE_OUTPUT_EVR_CUSTOM 41419 +#define IDS_PPAGE_OUTPUT_DXR 41420 +#define IDS_PPAGE_OUTPUT_NULL_COMP 41421 +#define IDS_PPAGE_OUTPUT_NULL_UNCOMP 41422 +#define IDS_PPAGE_OUTPUT_MADVR 41423 +#define IDS_PPAGE_OUTPUT_SYNC 41424 +#define IDS_PPAGE_OUTPUT_AUD_MPC_REND 41425 +#define IDS_PPAGE_OUTPUT_SURF_OFFSCREEN 41427 +#define IDS_PPAGE_OUTPUT_SURF_2D 41428 +#define IDS_PPAGE_OUTPUT_SURF_3D 41429 +#define IDS_PPAGE_OUTPUT_RESIZE_NN 41430 +#define IDS_PPAGE_OUTPUT_RESIZER_BILIN 41431 +#define IDS_PPAGE_OUTPUT_RESIZER_BIL_PS 41432 +#define IDS_PPAGE_OUTPUT_RESIZER_BICUB1 41433 +#define IDS_PPAGE_OUTPUT_RESIZER_BICUB2 41434 +#define IDS_PPAGE_OUTPUT_RESIZER_BICUB3 41435 +#define IDS_PPAGE_OUTPUT_UNAVAILABLE 41436 +#define IDS_PPAGE_OUTPUT_UNAVAILABLEMSG 41437 +#define IDS_PPAGE_OUTPUT_AUD_NULL_COMP 41438 +#define IDS_PPAGE_OUTPUT_AUD_NULL_UNCOMP 41439 +#define IDS_PPAGE_OUTPUT_AUD_INTERNAL_REND 41440 +#define IDS_EMB_RESOURCES_VIEWER_NAME 41441 +#define IDS_EMB_RESOURCES_VIEWER_TYPE 41442 +#define IDS_EMB_RESOURCES_VIEWER_INFO 41443 +#define IDS_SUBTITLES_DOWNLOAD 41444 +#define IDS_SUBTITLES_UPLOAD 41445 +#define IDS_SUBFILE_DELAY 41448 +#define IDS_SPEEDSTEP_AUTO 41449 +#define IDS_EXPORT_SETTINGS_NO_KEYS 41450 +#define IDS_RFS_NO_FILES 41451 +#define IDS_RFS_COMPRESSED 41452 +#define IDS_RFS_ENCRYPTED 41453 +#define IDS_RFS_MISSING_VOLS 41454 +#define IDS_OSD_D3DFS_REMINDER 41455 +#define IDS_LANG_PREF_EXAMPLE 41456 +#define IDS_OVERRIDE_EXT_SPLITTER_CHOICE 41457 +#define IDC_SPLITTER_CONF 41458 +#define IDC_VIDEO_DEC_CONF 41459 +#define IDC_AUDIO_DEC_CONF 41460 +#define IDS_NAVIGATE_BD_PLAYLISTS 41461 +#define IDS_NAVIGATE_PLAYLIST 41462 +#define IDS_NAVIGATE_CHAPTERS 41463 +#define IDS_NAVIGATE_TITLES 41464 +#define IDS_NAVIGATE_CHANNELS 41465 +#define IDS_PPAGE_OUTPUT_MPCVR 41466 +#define IDS_PPAGE_OUTPUT_VMR7 41467 +#define IDS_MOUSE_CLICK_MIDDLE 41702 +#define IDS_MOUSE_CLICK_X1 41703 +#define IDS_MOUSE_CLICK_X2 41704 +#define IDS_MOUSE_WHEEL_UP 41705 +#define IDS_MOUSE_WHEEL_DOWN 41706 +#define IDS_MOUSE_WHEEL_LEFT 41707 +#define IDS_MOUSE_WHEEL_RIGHT 41708 +#define IDS_MOUSE_ACTION 41710 +#define IDS_MOUSE_COMMAND 41711 +#define IDS_MOUSE_RIGHT_BUTTON 41712 +#define IDS_PPAGE_CAPTURE_FG0 57345 +#define IDS_PPAGE_CAPTURE_FG1 57346 +#define IDS_PPAGE_CAPTURE_FG2 57347 +#define IDS_PPAGE_CAPTURE_FGDESC0 57348 +#define IDS_PPAGE_CAPTURE_FGDESC1 57349 +#define IDS_PPAGE_CAPTURE_FGDESC2 57350 +#define IDS_PPAGE_CAPTURE_SFG0 57351 +#define IDS_PPAGE_CAPTURE_SFG1 57352 +#define IDS_PPAGE_CAPTURE_SFG2 57353 +#define IDS_INFOBAR_PARENTAL_RATING 57354 +#define IDS_PARENTAL_RATING 57355 +#define IDS_NO_PARENTAL_RATING 57356 +#define IDS_INFOBAR_CONTENT 57357 +#define IDS_CONTENT_MOVIE_DRAMA 57358 +#define IDS_CONTENT_NEWS_CURRENTAFFAIRS 57359 +#define IDS_CONTENT_SHOW_GAMESHOW 57360 +#define IDS_CONTENT_SPORTS 57361 +#define IDS_CONTENT_CHILDREN_YOUTH_PROG 57362 +#define IDS_CONTENT_MUSIC_BALLET_DANCE 57363 +#define IDS_CONTENT_MUSIC_ART_CULTURE 57364 +#define IDS_CONTENT_SOCIAL_POLITICAL_ECO 57365 +#define IDS_CONTENT_LEISURE 57366 +#define IDS_FILE_RECYCLE 57367 +#define IDS_AG_SAVE_COPY 57368 +#define IDS_FASTSEEK_LATEST 57369 +#define IDS_FASTSEEK_NEAREST 57370 +#define IDS_HOOKS_FAILED 57371 +#define IDS_PPAGEFULLSCREEN_SHOWNEVER 57372 +#define IDS_PPAGEFULLSCREEN_SHOWMOVED 57373 +#define IDS_PPAGEFULLSCREEN_SHOHHOVERED 57374 +#define IDS_MAINFRM_PRE_SHADERS_FAILED 57375 +#define IDS_MAINFRM_POST_SHADERS_FAILED 57376 +#define IDS_MAINFRM_BOTH_SHADERS_FAILED 57377 +#define IDS_DEBUGSHADERS_FIRSTRUN_MSG 57378 +#define IDS_SHADER_DLL_ERR_0 57379 +#define IDS_SHADER_DLL_ERR_1 57380 +#define IDS_OSD_SHADERS_PRESET 57381 +#define ID_SHADERS_PRESET_NEXT 57382 +#define IDS_AG_SHADERS_PRESET_NEXT 57383 +#define ID_SHADERS_PRESET_PREV 57384 +#define IDS_AG_SHADERS_PRESET_PREV 57385 +#define IDS_STRING_COLON 57386 +#define IDS_RECORD_START 57387 +#define IDS_RECORD_STOP 57388 +#define IDS_BALANCE 57389 +#define IDS_BALANCE_L 57390 +#define IDS_BALANCE_R 57391 +#define IDS_VOLUME 57392 +#define IDS_BOOST 57393 +#define IDS_PLAYLIST_ADDFOLDER 57394 +#define IDS_HW_INDICATOR 57395 +#define IDS_TOOLTIP_SOFTWARE_DECODING 57396 +#define IDS_STATSBAR_PLAYBACK_RATE 57397 +#define IDS_FILTERS_COPY_TO_CLIPBOARD 57398 +#define IDS_CREDENTIALS_SERVER 57399 +#define IDS_CREDENTIALS_CONNECT 57400 +#define IDS_SUB_SAVE_EXTERNAL_STYLE_FILE 57401 +#define IDS_CONTENT_EDUCATION_SCIENCE 57402 +#define IDS_PPAGEADVANCED_HIDE_WINDOWED 57403 +#define IDS_PPAGEADVANCED_BLOCK_VSFILTER 57404 +#define IDS_PPAGEADVANCED_COL_NAME 57405 +#define IDS_PPAGEADVANCED_COL_VALUE 57406 +#define IDS_PPAGEADVANCED_RECENT_FILES_NUMBER 57407 +#define IDS_PPAGEADVANCED_FILE_POS_LONGER 57408 +#define IDS_PPAGEADVANCED_FILE_POS_AUDIO 57409 +#define IDS_AFTER_PLAYBACK_DO_NOTHING 57410 +#define IDS_AFTER_PLAYBACK_PLAY_NEXT 57411 +#define IDS_AFTER_PLAYBACK_REWIND 57412 +#define IDS_AFTER_PLAYBACK_CLOSE 57413 +#define IDS_AFTER_PLAYBACK_EXIT 57414 +#define IDS_AFTER_PLAYBACK_MONITOROFF 57415 +#define IDS_IMAGE_JPEG_QUALITY 57416 +#define IDS_IMAGE_QUALITY 57417 +#define IDS_PPAGEADVANCED_COVER_SIZE_LIMIT 57418 +#define IDS_SUBTITLE_DELAY_STEP_TOOLTIP 57419 +#define IDS_HOTKEY_NOT_DEFINED 57420 +#define IDS_NAVIGATION_WATCH 57421 +#define IDS_NAVIGATION_MOVE_UP 57422 +#define IDS_NAVIGATION_MOVE_DOWN 57423 +#define IDS_NAVIGATION_SORT 57424 +#define IDS_NAVIGATION_REMOVE_ALL 57425 +#define IDS_REMOVE_CHANNELS_QUESTION 57426 +#define IDS_MEDIAINFO_NO_INFO_AVAILABLE 57427 +#define IDS_MEDIAINFO_ANALYSIS_IN_PROGRESS 57428 +#define IDS_ASPECT_RATIO_FMT 57429 +#define IDS_PPAGEADVANCED_LOGGER 57430 +#define IDS_TIMER_REMAINING_TIME 57431 +#define IDS_TIMER_HIGH_PRECISION 57432 +#define IDS_AFTERPLAYBACK_REWIND 57433 +#define IDS_AFTERPLAYBACK_CLOSE 57434 +#define IDS_FRAME_INIT_FAILED 57435 +#define IDS_TIME_SHIFT_TOOLTIP 57436 +#define IDS_WEBUI_DISABLED_PREVIEW_MSG 57437 +#define IDS_WEBUI_PREVIEW_WARNING 57438 +#define IDS_SUBTITLE_RENDERER_INTERNAL 57439 +#define IDS_SUBTITLE_RENDERER_VS_FILTER 57440 +#define IDS_SUBTITLE_RENDERER_XY_SUB_FILTER 57441 +#define IDS_SUBDL_DLG_PROVIDER_COL 57442 +#define IDS_SUBDL_DLG_HI_COL 57443 +#define IDS_SUBDL_DLG_DOWNLOADS_COL 57444 +#define IDS_SUBDL_DLG_SCORE_COL 57445 +#define IDS_SUBDL_DLG_FAILED 57446 +#define IDS_SUBDL_DLG_ABORTED 57447 +#define IDS_SUBDL_DLG_FOUND 57448 +#define IDS_SUBDL_DLG_NOTFOUND 57449 +#define IDS_SUBDL_DLG_TITLE 57450 +#define IDS_SUBDL_DLG_SEARCHING 57451 +#define IDS_SUBDL_DLG_ABORTING 57452 +#define IDS_SUBUL_DLG_USERNAME_COL 57453 +#define IDS_SUBUL_DLG_STATUS_COL 57454 +#define IDS_SUBUL_DLG_STATUS_READY 57455 +#define IDS_SUBUL_DLG_STATUS_NOTIMPLEMENTED 57456 +#define IDS_SUBUL_DLG_STATUS_UPLOADING 57457 +#define IDS_SUBUL_DLG_STATUS_UPLOADED 57458 +#define IDS_SUBUL_DLG_STATUS_FAILED 57459 +#define IDS_SUBUL_DLG_STATUS_ABORTED 57460 +#define IDS_SUBUL_DLG_STATUS_ALREADYEXISTS 57461 +#define IDS_SUBUL_DLG_UPLOADING 57462 +#define IDS_SUBUL_DLG_UPLOADED 57463 +#define IDS_SUBUL_DLG_ABORTED 57464 +#define IDS_SUBUL_DLG_FAILED 57465 +#define IDS_SUBMENU_DOWNLOAD 57466 +#define IDS_SUBMENU_SETUP 57467 +#define IDS_SUBMENU_RESET 57468 +#define IDS_SUBMENU_MOVEUP 57469 +#define IDS_SUBMENU_MOVEDOWN 57470 +#define IDS_SUBMENU_OPENURL 57471 +#define IDS_SUBPP_DLG_LANGUAGES_COL 57472 +#define IDS_SUBPP_DLG_LANGUAGES_ERROR 57473 +#define IDS_SUB_CREDENTIALS_TITLE 57474 +#define IDS_SUB_CREDENTIALS_MSG 57475 +#define IDS_ASPECT_RATIO_SAR 57476 +#define IDS_SUBDL_DLG_DOWNLOADED 57477 +#define IDS_SUBUL_DLG_TITLE 57478 +#define IDS_SUBUL_DLG_CONFIRM 57479 +#define IDS_SUBPP_DLG_FETCHING_LANGUAGES 57480 +#define IDS_SUB_CREDENTIALS_ERROR 57481 +#define IDS_SUB_AUTODL_IGNORE_TOOLTIP 57482 +#define IDS_CMD_PATHNAME 57483 +#define IDS_CMD_DUB 57484 +#define IDS_CMD_DUBDELAY 57485 +#define IDS_CMD_D3DFS 57486 +#define IDS_CMD_SUB 57487 +#define IDS_CMD_FILTER 57488 +#define IDS_CMD_DVD 57489 +#define IDS_CMD_DVDPOS_TC 57490 +#define IDS_CMD_DVDPOS_TIME 57491 +#define IDS_CMD_CD 57492 +#define IDS_CMD_DEVICE 57493 +#define IDS_CMD_OPEN 57494 +#define IDS_CMD_PLAY 57495 +#define IDS_CMD_CLOSE 57496 +#define IDS_CMD_SHUTDOWN 57497 +#define IDS_CMD_STANDBY 57498 +#define IDS_CMD_HIBERNATE 57499 +#define IDS_CMD_LOGOFF 57500 +#define IDS_CMD_LOCK 57501 +#define IDS_CMD_MONITOROFF 57502 +#define IDS_CMD_PLAYNEXT 57503 +#define IDS_CMD_FULLSCREEN 57504 +#define IDS_CMD_MINIMIZED 57505 +#define IDS_CMD_NEW 57506 +#define IDS_CMD_ADD 57507 +#define IDS_CMD_RANDOMIZE 57508 +#define IDS_CMD_REGVID 57509 +#define IDS_CMD_REGAUD 57510 +#define IDS_CMD_REGPL 57511 +#define IDS_CMD_REGALL 57512 +#define IDS_CMD_UNREGALL 57513 +#define IDS_CMD_START 57514 +#define IDS_CMD_STARTPOS 57515 +#define IDS_CMD_FIXEDSIZE 57516 +#define IDS_CMD_MONITOR 57517 +#define IDS_CMD_AUDIORENDERER 57518 +#define IDS_CMD_SHADERPRESET 57519 +#define IDS_CMD_PNS 57520 +#define IDS_CMD_ICONASSOC 57521 +#define IDS_CMD_NOFOCUS 57522 +#define IDS_CMD_WEBPORT 57523 +#define IDS_CMD_DEBUG 57524 +#define IDS_CMD_NOCRASHREPORTER 57525 +#define IDS_CMD_SLAVE 57526 +#define IDS_CMD_HWGPU 57527 +#define IDS_CMD_RESET 57528 +#define IDS_CMD_HELP 57529 +#define IDS_PPAGEADVANCED_SCORE 57530 +#define IDS_PPAGE_FS_CLN_AUDIO_DELAY 57531 +#define IDS_PPAGEADVANCED_DEFAULTTOOLBARSIZE 57532 +#define IDS_PPAGEADVANCED_USE_LEGACY_TOOLBAR 57533 +#define IDS_SUBMENU_COPYURL 57535 +#define IDS_CMD_VIEWPRESET 57536 +#define IDS_CMD_MUTE 57537 +#define IDS_CMD_VOLUME 57538 +#define IDS_YOUTUBEDL_NOT_FOUND 57539 +#define IDS_CONTROLS_YOUTUBEDL 57540 +#define IDS_VERTICAL_ALIGN_VIDEO_TOP 57541 +#define IDS_VERTICAL_ALIGN_VIDEO_MIDDLE 57542 +#define IDS_VERTICAL_ALIGN_VIDEO_BOTTOM 57543 +#define IDS_PPAGEADVANCED_USE_YDL 57544 +#define IDS_PPAGEADVANCED_YDL_MAX_HEIGHT 57545 +#define IDS_PPAGEADVANCED_YDL_VIDEO_FORMAT 57546 +#define IDS_PPAGEADVANCED_YDL_AUDIO_ONLY 57547 +#define IDS_PPAGEADVANCED_YDL_COMMAND_LINE 57548 +#define IDS_PPAGEADVANCED_SAVEIMAGE_POSITION 57549 +#define IDS_PPAGEADVANCED_SAVEIMAGE_CURRENTTIME 57550 +#define IDS_PPAGEADVANCED_ALLOW_INACCURATE_FASTSEEK 57551 +#define IDS_PPAGEADVANCED_LOOP_FOLDER_NEXT_FILE 57552 +#define IDS_PPAGEADVANCED_MODERNSEEKBAR 57553 +#define IDS_PPAGEADVANCED_MODERNSEEKBARHEIGHT 57554 +#define IDS_PPAGEADVANCED_FULLSCREEN_DELAY 57555 +#define IDS_PPAGEADVANCED_SNAPSHOTSUBTITLES 57556 +#define IDS_PPAGEADVANCED_SNAPSHOTKEEPVIDEOEXTENSION 57557 +#define IDS_PPAGEADVANCED_CRASHREPORTER 57558 +#define IDS_PRESIZE_SHADERS_ENABLED 57559 +#define IDS_PRESIZE_SHADERS_DISABLED 57560 +#define IDS_PRESIZE_SHADERS_TOGGLE 57561 +#define IDS_AG_PRESIZE_SHADERS_TOGGLE 57562 +#define IDS_POSTSIZE_SHADERS_ENABLED 57563 +#define IDS_POSTSIZE_SHADERS_DISABLED 57564 +#define IDS_POSTSIZE_SHADERS_TOGGLE 57565 +#define IDS_AG_POSTSIZE_SHADERS_TOGGLE 57566 +#define IDS_PPAGEADVANCED_TIME_REFRESH_INTERVAL 57567 +#define IDS_PPAGEADVANCED_SHOW_LANG_STATUSBAR 57568 +#define IDS_PPAGEADVANCED_SHOW_FPS_STATUSBAR 57569 +#define IDS_PPAGEADVANCED_ADD_LANGCODE_WHEN_SAVE_SUBTITLES 57570 +#define IDS_PPAGEADVANCED_USE_TITLE_IN_RECENT_FILE_LIST 57571 +#define IDS_PPAGEADVANCED_SHOW_ABMARKS_STATUSBAR 57572 +#define IDS_PPAGEADVANCED_SHOW_VIDEOINFO_STATUSBAR 57573 +#define IDS_PPAGEADVANCED_OPEN_REC_PANEL_WHEN_OPENING_DEVICE 57621 +#define IDS_PPAGEADVANCED_ALWAYS_USE_SHORT_MENU 57622 +#define IDS_PPAGEADVANCED_FULLSCREEN_SEPARATE_CONTROLS 57623 +#define IDS_PPAGEADVANCED_BLOCKRDP 57624 +#define IDS_PPAGEADVANCED_YDL_EXEPATH 57625 +#define IDS_PPAGEADVANCED_YDL_SUBS_PREFERENCE 57626 +#define IDS_PPAGEADVANCED_USE_AUTOMATIC_CAPTIONS 57627 +#define IDS_PPAGEADVANCED_USE_SMTC 57628 +#define IDS_PPAGEADVANCED_LOCK_NOPAUSE 57629 +#define IDS_PPAGEADVANCED_RELOAD_AFTER_LONG_PAUSE 57630 +#define IDS_PPAGEADVANCED_REDIRECT_OPEN_TO_APPEND_THRESHOLD 57631 +#define IDS_SUBTITLE_RENDERER_NONE 57632 +#define IDS_PPAGEADVANCED_MOUSE_LEFTUP_DELAY 57633 +#define IDS_PPAGEADVANCED_USE_FREETYPE 57634 +#define IDS_PPAGEADVANCED_USE_MEDIAINFO_LOAD_FILE_DURATION 57635 +#define IDS_TIMER_SHOW_PERCENTAGE 57636 +#define IDS_SUBDL_DLG_FAILED_DL 57637 +#define IDS_PPAGEADVANCED_FILEPOS_PLAYLIST 57638 +#define IDS_PPAGEADVANCED_FILEPOS_TRACK_SELECTION 57639 +#define IDS_PPAGEADVANCED_YDL_AUDIO_FORMAT 57640 +#define IDS_PPAGEADVANCED_PREVENT_DISPLAY_SLEEP 57641 +#define IDS_PPAGEADVANCED_STILL_VIDEO_DURATION 57642 +#define IDS_PPAGEADVANCED_CAPTURE_DEINTERLACE 57643 +#define IDS_PLAYLIST_TOGGLE_SHUFFLE 57644 +#define IDS_AUDIOSHIFT_ONOFF 57645 +#define IDS_SAVEDIALOG_INCLUDE_SUBS 57646 +#define IDS_PPAGEADVANCED_PAUSE_WHILE_DRAGGING_SEEKBAR 57647 +#define IDS_CMD_THUMBNAILS 57648 +#define IDS_PPAGEADVANCED_CONFIRM_FILE_DELETE 57649 +#define IDS_PPAGEADVANCED_LIBASS_FOR_SRT 57650 +#define IDS_CMD_AB_START 57651 +#define IDS_CMD_AB_END 57652 +#define IDS_ARS_WASAPI_MODE 57700 +#define IDS_ARS_EXCLUSIVE 57701 +#define IDS_ARS_SHARED 57702 +#define IDS_ARS_BITEXACT_OUTPUT 57703 +#define IDS_ARS_SYSTEM_LAYOUT_CHANNELS 57704 +#define IDS_ARS_SOUND_DEVICE 57705 +#define IDS_ARS_RELEASE_DEVICE_IDLE 57706 +#define IDS_ARS_CROSSFEED 57707 +#define IDS_ARS_DEVICE_PERIOD 57708 +#define IDS_ARS_ALT_CHECK_FORMAT 57709 +#define IDS_ARS_STATUS 57710 +#define IDS_ARS_DEVICE 57711 +#define IDS_ARS_MODE 57712 +#define IDS_ARS_INPUT 57713 +#define IDS_ARS_OUTPUT 57714 +#define IDS_ARS_FORMAT 57715 +#define IDS_ARS_SAMPLERATE 57716 +#define IDS_ARS_CHANNELS 57717 +#define IDS_ARS_WASAPI_METHOD 57718 +#define IDS_ARS_DUMMY_CHANNELS 57719 +#define IDS_ARS_TIP_BITEXACT_OUTPUT 57720 +#define IDS_ARS_TIP_ALT_CHECK_FORMAT 57721 +#define IDS_FILTER_RESET_SETTINGS 57722 +#define IDS_AG_DEFAULT 57723 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 20077 +#define _APS_NEXT_COMMAND_VALUE 33462 +#define _APS_NEXT_CONTROL_VALUE 22094 +#define _APS_NEXT_SYMED_VALUE 24052 +#endif +#endif diff --git a/src/mpc-hc/stdafx.cpp b/src/mpc-hc/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/mpc-hc/stdafx.cpp +++ b/src/mpc-hc/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/mpc-hc/stdafx.h b/src/mpc-hc/stdafx.h index a090be11bbe..dd818264290 100644 --- a/src/mpc-hc/stdafx.h +++ b/src/mpc-hc/stdafx.h @@ -1,89 +1,89 @@ -/* - * (C) 2003-2006 Gabest - * (C) 2006-2014, 2017 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 . - * - */ - -#pragma once - -#define GDIPVER 0x0110 - -#include -#include // MFC core and standard components -#include // MFC extensions -#include // MFC Automation classes -#include // MFC support for Internet Explorer 4 Common Controls -#include -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Workaround compilation errors when including GDI+ with NOMINMAX defined -namespace Gdiplus -{ - using std::min; - using std::max; -}; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "sizecbar/scbarg.h" -#include "ResizableLib/ResizableDialog.h" -#include "BaseClasses/streams.h" - -#include "LcdSupport.h" - -template -class CAtlStringMap : public CAtlMap> {}; - -#define CheckAndLog(x, msg) hr = ##x; if (FAILED(hr)) { TRACE(msg _T(": 0x%08x\n"), hr); return hr; } -#define CheckNoLog(x) hr = ##x; if (FAILED(hr)) { return hr; } -#define CheckNoLogBool(x) if (FAILED(x)) { return false; } - - - -#include "DSUtil.h" -#include "mpc-hc_config.h" -#include "resource.h" +/* + * (C) 2003-2006 Gabest + * (C) 2006-2014, 2017 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 . + * + */ + +#pragma once + +#define GDIPVER 0x0110 + +#include +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // MFC support for Internet Explorer 4 Common Controls +#include +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Workaround compilation errors when including GDI+ with NOMINMAX defined +namespace Gdiplus +{ + using std::min; + using std::max; +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sizecbar/scbarg.h" +#include "ResizableLib/ResizableDialog.h" +#include "BaseClasses/streams.h" + +#include "LcdSupport.h" + +template +class CAtlStringMap : public CAtlMap> {}; + +#define CheckAndLog(x, msg) hr = ##x; if (FAILED(hr)) { TRACE(msg _T(": 0x%08x\n"), hr); return hr; } +#define CheckNoLog(x) hr = ##x; if (FAILED(hr)) { return hr; } +#define CheckNoLogBool(x) if (FAILED(x)) { return false; } + + + +#include "DSUtil.h" +#include "mpc-hc_config.h" +#include "resource.h" diff --git a/src/mpc-hc/vkCodes.cpp b/src/mpc-hc/vkCodes.cpp index ec4d7fd9b65..e4370a3ffb1 100644 --- a/src/mpc-hc/vkCodes.cpp +++ b/src/mpc-hc/vkCodes.cpp @@ -1,337 +1,337 @@ -/* - * (C) 2011-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 . - * - */ - - -#include "stdafx.h" -#include "vkCodes.h" - -PCTSTR GetKeyName(UINT vkCode) -{ - ASSERT(vkCode < 256); - vkCode &= 0xff; - - static PCTSTR s_pszKeys[256] = { - _T("Unused"), - _T("Left mouse button"), - _T("Right mouse button"), - _T("Control-break"), - _T("Middle mouse button"), - _T("X1 mouse button"), - _T("X2 mouse button"), - _T("Undefined"), - _T("Backspace"), - _T("Tab"), - _T("Unknown"), - _T("Unknown"), - _T("Clear"), - _T("Enter"), - _T("Unknown"), - _T("Unknown"), - _T("Shift"), - _T("Control"), - _T("Alt"), - _T("Pause"), - _T("Caps Lock"), - _T("IME Kana mode"), - _T("Unknown"), - _T("IME Junja mode"), - _T("IME final mode"), - _T("IME Hanja mode"), - _T("Unknown"), - _T("Esc"), - _T("IME convert"), - _T("IME nonconvert"), - _T("IME accept"), - _T("IME mode change"), - _T("Space"), - _T("Page Up"), - _T("Page Down"), - _T("End"), - _T("Home"), - _T("Left Arrow"), - _T("Up Arrow"), - _T("Right Arrow"), - _T("Down Arrow"), - _T("Select"), - _T("Print"), - _T("Execute"), - _T("Print Screen"), - _T("Ins"), - _T("Del"), - _T("Help"), - _T("0"), - _T("1"), - _T("2"), - _T("3"), - _T("4"), - _T("5"), - _T("6"), - _T("7"), - _T("8"), - _T("9"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("A"), - _T("B"), - _T("C"), - _T("D"), - _T("E"), - _T("F"), - _T("G"), - _T("H"), - _T("I"), - _T("J"), - _T("K"), - _T("L"), - _T("M"), - _T("N"), - _T("O"), - _T("P"), - _T("Q"), - _T("R"), - _T("S"), - _T("T"), - _T("U"), - _T("V"), - _T("W"), - _T("X"), - _T("Y"), - _T("Z"), - _T("Left Win"), - _T("Right Win"), - _T("App"), - _T("Unknown"), - _T("Sleep"), - _T("Num 0"), - _T("Num 1"), - _T("Num 2"), - _T("Num 3"), - _T("Num 4"), - _T("Num 5"), - _T("Num 6"), - _T("Num 7"), - _T("Num 8"), - _T("Num 9"), - _T("Mul"), - _T("Add"), - _T("Separator"), - _T("Sub"), - _T("Decimal"), - _T("Div"), - _T("F1"), - _T("F2"), - _T("F3"), - _T("F4"), - _T("F5"), - _T("F6"), - _T("F7"), - _T("F8"), - _T("F9"), - _T("F10"), - _T("F11"), - _T("F12"), - _T("F13"), - _T("F14"), - _T("F15"), - _T("F16"), - _T("F17"), - _T("F18"), - _T("F19"), - _T("F20"), - _T("F21"), - _T("F22"), - _T("F23"), - _T("F24"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Num Lock"), - _T("Scroll Lock"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Left Shift"), - _T("Right Shift"), - _T("Left Control"), - _T("Right Control"), - _T("Left Alt"), - _T("Right Alt"), - _T("Browser Back"), - _T("Browser Forward"), - _T("Browser Refresh"), - _T("Browser Stop"), - _T("Browser Search"), - _T("Browser Favorites"), - _T("Browser Home"), - _T("Volume Mute"), - _T("Volume Down"), - _T("Volume Up"), - _T("Next Track"), - _T("Previous Track"), - _T("Stop Media"), - _T("Play/Pause Media"), - _T("Start Mail"), - _T("Select Media"), - _T("Start App 1"), - _T("Start App 2"), - _T("Unknown"), - _T("Unknown"), - _T(";"), - _T("="), - _T(","), - _T("_"), - _T("."), - _T("/"), - _T("`"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("Unknown"), - _T("["), - _T("\\"), - _T("]"), - _T("'"), - _T("OEM"), - _T("Unknown"), - _T("OEM"), - _T("<> or \\|"), - _T("OEM"), - _T("OEM"), - _T("IME Process key"), - _T("OEM"), - _T("VK_PACKET"), - _T("Unknown"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("OEM"), - _T("Attn"), - _T("CrSel"), - _T("ExSel"), - _T("Erase EOF"), - _T("Play"), - _T("Zoom"), - _T("Unknown"), - _T("PA1"), - _T("Clear"), - _T("Unknown") - }; - - return s_pszKeys[vkCode]; -} - -//----------------------------------------------------------------- - -BOOL HotkeyToString(UINT vkCode, UINT fModifiers, CString& s) -{ - - s.Empty(); - if (fModifiers & MOD_CONTROL) { - s += _T("Ctrl + "); - } - if (fModifiers & MOD_ALT) { - s += _T("Alt + "); - } - if (fModifiers & MOD_SHIFT) { - s += _T("Shift + "); - } - if (vkCode) { - s += GetKeyName(vkCode); - } - - return !s.IsEmpty(); -} - -BOOL HotkeyModToString(UINT vkCode, BYTE fModifiers, CString& s) -{ - s.Empty(); - - if (fModifiers & FCONTROL) { - s += _T("Ctrl + "); - } - if (fModifiers & FALT) { - s += _T("Alt + "); - } - if (fModifiers & FSHIFT) { - s += _T("Shift + "); - } - if (vkCode) { - s += GetKeyName(vkCode); - } - - return !s.IsEmpty(); -} - -BOOL HotkeyToString(DWORD dwHk, CString& s) -{ - return HotkeyToString(LOBYTE(LOWORD(dwHk)), HIBYTE(LOWORD(dwHk)), s); -} +/* + * (C) 2011-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 . + * + */ + + +#include "stdafx.h" +#include "vkCodes.h" + +PCTSTR GetKeyName(UINT vkCode) +{ + ASSERT(vkCode < 256); + vkCode &= 0xff; + + static PCTSTR s_pszKeys[256] = { + _T("Unused"), + _T("Left mouse button"), + _T("Right mouse button"), + _T("Control-break"), + _T("Middle mouse button"), + _T("X1 mouse button"), + _T("X2 mouse button"), + _T("Undefined"), + _T("Backspace"), + _T("Tab"), + _T("Unknown"), + _T("Unknown"), + _T("Clear"), + _T("Enter"), + _T("Unknown"), + _T("Unknown"), + _T("Shift"), + _T("Control"), + _T("Alt"), + _T("Pause"), + _T("Caps Lock"), + _T("IME Kana mode"), + _T("Unknown"), + _T("IME Junja mode"), + _T("IME final mode"), + _T("IME Hanja mode"), + _T("Unknown"), + _T("Esc"), + _T("IME convert"), + _T("IME nonconvert"), + _T("IME accept"), + _T("IME mode change"), + _T("Space"), + _T("Page Up"), + _T("Page Down"), + _T("End"), + _T("Home"), + _T("Left Arrow"), + _T("Up Arrow"), + _T("Right Arrow"), + _T("Down Arrow"), + _T("Select"), + _T("Print"), + _T("Execute"), + _T("Print Screen"), + _T("Ins"), + _T("Del"), + _T("Help"), + _T("0"), + _T("1"), + _T("2"), + _T("3"), + _T("4"), + _T("5"), + _T("6"), + _T("7"), + _T("8"), + _T("9"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("A"), + _T("B"), + _T("C"), + _T("D"), + _T("E"), + _T("F"), + _T("G"), + _T("H"), + _T("I"), + _T("J"), + _T("K"), + _T("L"), + _T("M"), + _T("N"), + _T("O"), + _T("P"), + _T("Q"), + _T("R"), + _T("S"), + _T("T"), + _T("U"), + _T("V"), + _T("W"), + _T("X"), + _T("Y"), + _T("Z"), + _T("Left Win"), + _T("Right Win"), + _T("App"), + _T("Unknown"), + _T("Sleep"), + _T("Num 0"), + _T("Num 1"), + _T("Num 2"), + _T("Num 3"), + _T("Num 4"), + _T("Num 5"), + _T("Num 6"), + _T("Num 7"), + _T("Num 8"), + _T("Num 9"), + _T("Mul"), + _T("Add"), + _T("Separator"), + _T("Sub"), + _T("Decimal"), + _T("Div"), + _T("F1"), + _T("F2"), + _T("F3"), + _T("F4"), + _T("F5"), + _T("F6"), + _T("F7"), + _T("F8"), + _T("F9"), + _T("F10"), + _T("F11"), + _T("F12"), + _T("F13"), + _T("F14"), + _T("F15"), + _T("F16"), + _T("F17"), + _T("F18"), + _T("F19"), + _T("F20"), + _T("F21"), + _T("F22"), + _T("F23"), + _T("F24"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Num Lock"), + _T("Scroll Lock"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Left Shift"), + _T("Right Shift"), + _T("Left Control"), + _T("Right Control"), + _T("Left Alt"), + _T("Right Alt"), + _T("Browser Back"), + _T("Browser Forward"), + _T("Browser Refresh"), + _T("Browser Stop"), + _T("Browser Search"), + _T("Browser Favorites"), + _T("Browser Home"), + _T("Volume Mute"), + _T("Volume Down"), + _T("Volume Up"), + _T("Next Track"), + _T("Previous Track"), + _T("Stop Media"), + _T("Play/Pause Media"), + _T("Start Mail"), + _T("Select Media"), + _T("Start App 1"), + _T("Start App 2"), + _T("Unknown"), + _T("Unknown"), + _T(";"), + _T("="), + _T(","), + _T("_"), + _T("."), + _T("/"), + _T("`"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("Unknown"), + _T("["), + _T("\\"), + _T("]"), + _T("'"), + _T("OEM"), + _T("Unknown"), + _T("OEM"), + _T("<> or \\|"), + _T("OEM"), + _T("OEM"), + _T("IME Process key"), + _T("OEM"), + _T("VK_PACKET"), + _T("Unknown"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("OEM"), + _T("Attn"), + _T("CrSel"), + _T("ExSel"), + _T("Erase EOF"), + _T("Play"), + _T("Zoom"), + _T("Unknown"), + _T("PA1"), + _T("Clear"), + _T("Unknown") + }; + + return s_pszKeys[vkCode]; +} + +//----------------------------------------------------------------- + +BOOL HotkeyToString(UINT vkCode, UINT fModifiers, CString& s) +{ + + s.Empty(); + if (fModifiers & MOD_CONTROL) { + s += _T("Ctrl + "); + } + if (fModifiers & MOD_ALT) { + s += _T("Alt + "); + } + if (fModifiers & MOD_SHIFT) { + s += _T("Shift + "); + } + if (vkCode) { + s += GetKeyName(vkCode); + } + + return !s.IsEmpty(); +} + +BOOL HotkeyModToString(UINT vkCode, BYTE fModifiers, CString& s) +{ + s.Empty(); + + if (fModifiers & FCONTROL) { + s += _T("Ctrl + "); + } + if (fModifiers & FALT) { + s += _T("Alt + "); + } + if (fModifiers & FSHIFT) { + s += _T("Shift + "); + } + if (vkCode) { + s += GetKeyName(vkCode); + } + + return !s.IsEmpty(); +} + +BOOL HotkeyToString(DWORD dwHk, CString& s) +{ + return HotkeyToString(LOBYTE(LOWORD(dwHk)), HIBYTE(LOWORD(dwHk)), s); +} diff --git a/src/mpc-hc/vkCodes.h b/src/mpc-hc/vkCodes.h index 216b80dd1c3..4562c736015 100644 --- a/src/mpc-hc/vkCodes.h +++ b/src/mpc-hc/vkCodes.h @@ -1,26 +1,26 @@ -/* - * (C) 2011-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 . - * - */ - -#pragma once - -PCTSTR GetKeyName(UINT); -BOOL HotkeyToString(UINT, UINT, CString&); -BOOL HotkeyModToString(UINT, BYTE, CString&); -BOOL HotkeyToString(DWORD, CString&); +/* + * (C) 2011-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 . + * + */ + +#pragma once + +PCTSTR GetKeyName(UINT); +BOOL HotkeyToString(UINT, UINT, CString&); +BOOL HotkeyModToString(UINT, BYTE, CString&); +BOOL HotkeyToString(DWORD, CString&); diff --git a/src/thirdparty/AsyncReader/AsyncReader.vcxproj b/src/thirdparty/AsyncReader/AsyncReader.vcxproj index 508bbbb0df4..4451075cc30 100644 --- a/src/thirdparty/AsyncReader/AsyncReader.vcxproj +++ b/src/thirdparty/AsyncReader/AsyncReader.vcxproj @@ -1,68 +1,68 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {9F31D122-E84D-485A-A58D-09DAD01A56CE} - AsyncReader - Win32Proj - AsyncReader - - - - - StaticLibrary - Unicode - - - - - - - - - - - - - ..\..\..\..\include;..;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - - - - - - - Create - - - - - - - - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {9F31D122-E84D-485A-A58D-09DAD01A56CE} + AsyncReader + Win32Proj + AsyncReader + + + + + StaticLibrary + Unicode + + + + + + + + + + + + + ..\..\..\..\include;..;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + + + + + + + Create + + + + + + + + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + + + \ No newline at end of file diff --git a/src/thirdparty/AsyncReader/AsyncReader.vcxproj.filters b/src/thirdparty/AsyncReader/AsyncReader.vcxproj.filters index 3ba609ca8d8..1d92fb5a700 100644 --- a/src/thirdparty/AsyncReader/AsyncReader.vcxproj.filters +++ b/src/thirdparty/AsyncReader/AsyncReader.vcxproj.filters @@ -1,35 +1,35 @@ - - - - - {fa80e2e7-af1c-4fe8-8023-725cf9d0c9e8} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {f27d6e75-1d82-4d17-adcd-a9d38cc032c5} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - + + + + + {fa80e2e7-af1c-4fe8-8023-725cf9d0c9e8} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {f27d6e75-1d82-4d17-adcd-a9d38cc032c5} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/AsyncReader/asyncio.cpp b/src/thirdparty/AsyncReader/asyncio.cpp index 3503b6e3111..ada6e48158f 100644 --- a/src/thirdparty/AsyncReader/asyncio.cpp +++ b/src/thirdparty/AsyncReader/asyncio.cpp @@ -1,709 +1,709 @@ -//------------------------------------------------------------------------------ -// File: AsyncIo.cpp -// -// Desc: DirectShow sample code - base library with I/O functionality. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "stdafx.h" -#include "BaseClasses/streams.h" -#include "asyncio.h" - -// --- CAsyncRequest --- - - -// implementation of CAsyncRequest representing a single -// outstanding request. All the i/o for this object is done -// in the Complete method. - - -// init the params for this request. -// Read is not issued until the complete call -HRESULT -CAsyncRequest::Request( - CAsyncIo *pIo, - CAsyncStream *pStream, - LONGLONG llPos, - LONG lLength, - BOOL bAligned, - BYTE* pBuffer, - LPVOID pContext, // filter's context - DWORD_PTR dwUser) // downstream filter's context -{ - m_pIo = pIo; - m_pStream = pStream; - m_llPos = llPos; - m_lLength = lLength; - m_bAligned = bAligned; - m_pBuffer = pBuffer; - m_pContext = pContext; - m_dwUser = dwUser; - m_hr = VFW_E_TIMEOUT; // not done yet - - return S_OK; -} - - -// issue the i/o if not overlapped, and block until i/o complete. -// returns error code of file i/o -// -// -HRESULT -CAsyncRequest::Complete() -{ - m_pStream->Lock(); - - m_hr = m_pStream->SetPointer(m_llPos); - if(S_OK == m_hr) - { - DWORD dwActual; - - m_hr = m_pStream->Read(m_pBuffer, m_lLength, m_bAligned, &dwActual); - if(m_hr == OLE_S_FIRST) - { - if(m_pContext) - { - IMediaSample *pSample = reinterpret_cast(m_pContext); - pSample->SetDiscontinuity(TRUE); - m_hr = S_OK; - } - } - - if(FAILED(m_hr)) - { - } - else if(dwActual != (DWORD)m_lLength) - { - // tell caller size changed - probably because of EOF - m_lLength = (LONG) dwActual; - m_hr = S_FALSE; - } - else - { - m_hr = S_OK; - } - } - - m_pStream->Unlock(); - return m_hr; -} - - -// --- CAsyncIo --- - -// note - all events created manual reset - -CAsyncIo::CAsyncIo(CAsyncStream *pStream) - : m_pStream(pStream), - m_bFlushing(FALSE), - m_listWork(NAME("Work list")), - m_listDone(NAME("Done list")), - m_evWork(TRUE), - m_evDone(TRUE), - m_cItemsOut(0), - m_bWaiting(FALSE), - m_evStop(TRUE), - m_hThread(NULL) -{ - -} - - -CAsyncIo::~CAsyncIo() -{ - // move everything to the done list - BeginFlush(); - - // shutdown worker thread - CloseThread(); - - // empty the done list - POSITION pos = m_listDone.GetHeadPosition(); - while(pos) - { - CAsyncRequest* pRequest = m_listDone.GetNext(pos); - delete pRequest; - } - - m_listDone.RemoveAll(); -} - - -// ready for async activity - call this before calling Request. -// -// start the worker thread if we need to -// -// !!! use overlapped i/o if possible -HRESULT -CAsyncIo::AsyncActive(void) -{ - return StartThread(); -} - -// call this when no more async activity will happen before -// the next AsyncActive call -// -// stop the worker thread if active -HRESULT -CAsyncIo::AsyncInactive(void) -{ - return CloseThread(); -} - - -// add a request to the queue. -HRESULT -CAsyncIo::Request( - LONGLONG llPos, - LONG lLength, - BOOL bAligned, - BYTE * pBuffer, - LPVOID pContext, - DWORD_PTR dwUser) -{ - if(bAligned) - { - if(!IsAligned(llPos) || - !IsAligned(lLength) || - !IsAligned((LONG_PTR) pBuffer)) - { - return VFW_E_BADALIGN; - } - } - - CAsyncRequest* pRequest = new CAsyncRequest; - if (!pRequest) - return E_OUTOFMEMORY; - - HRESULT hr = pRequest->Request(this, - m_pStream, - llPos, - lLength, - bAligned, - pBuffer, - pContext, - dwUser); - if(SUCCEEDED(hr)) - { - // might fail if flushing - hr = PutWorkItem(pRequest); - } - - if(FAILED(hr)) - { - delete pRequest; - } - - return hr; -} - - -// wait for the next request to complete -HRESULT -CAsyncIo::WaitForNext( - DWORD dwTimeout, - LPVOID * ppContext, - DWORD_PTR * pdwUser, - LONG * pcbActual) -{ - CheckPointer(ppContext,E_POINTER); - CheckPointer(pdwUser,E_POINTER); - CheckPointer(pcbActual,E_POINTER); - - // some errors find a sample, others don't. Ensure that - // *ppContext is NULL if no sample found - *ppContext = NULL; - - // wait until the event is set, but since we are not - // holding the critsec when waiting, we may need to re-wait - for(;;) - { - if(!m_evDone.Wait(dwTimeout)) - { - // timeout occurred - return VFW_E_TIMEOUT; - } - - // get next event from list - CAsyncRequest* pRequest = GetDoneItem(); - if(pRequest) - { - // found a completed request - - // check if ok - HRESULT hr = pRequest->GetHResult(); - if(hr == S_FALSE) - { - // this means the actual length was less than - // requested - may be ok if he aligned the end of file - if((pRequest->GetActualLength() + - pRequest->GetStart()) == Size()) - { - hr = S_OK; - } - else - { - // it was an actual read error - hr = E_FAIL; - } - } - - // return actual bytes read - *pcbActual = pRequest->GetActualLength(); - - // return his context - *ppContext = pRequest->GetContext(); - *pdwUser = pRequest->GetUser(); - - delete pRequest; - return hr; - } - else - { - // Hold the critical section while checking the list state - CAutoLock lck(&m_csLists); - if(m_bFlushing && !m_bWaiting) - { - // can't block as we are between BeginFlush and EndFlush - - // but note that if m_bWaiting is set, then there are some - // items not yet complete that we should block for. - - return VFW_E_WRONG_STATE; - } - } - - // done item was grabbed between completion and - // us locking m_csLists. - } -} - - -// perform a synchronous read request on this thread. -// Need to hold m_csFile while doing this (done in request object) -HRESULT -CAsyncIo::SyncReadAligned( - LONGLONG llPos, - LONG lLength, - BYTE * pBuffer, - LONG * pcbActual, - PVOID pvContext) -{ - CheckPointer(pcbActual,E_POINTER); - - if(!IsAligned(llPos) || - !IsAligned(lLength) || - !IsAligned((LONG_PTR) pBuffer)) - { - return VFW_E_BADALIGN; - } - - CAsyncRequest request; - - HRESULT hr = request.Request(this, - m_pStream, - llPos, - lLength, - TRUE, - pBuffer, - pvContext, - 0); - if(FAILED(hr)) - return hr; - - hr = request.Complete(); - - // return actual data length - *pcbActual = request.GetActualLength(); - return hr; -} - - -HRESULT -CAsyncIo::Length(LONGLONG *pllTotal, LONGLONG *pllAvailable) -{ - CheckPointer(pllTotal,E_POINTER); - - *pllTotal = m_pStream->Size(pllAvailable); - return S_OK; -} - - -// cancel all items on the worklist onto the done list -// and refuse further requests or further WaitForNext calls -// until the end flush -// -// WaitForNext must return with NULL only if there are no successful requests. -// So Flush does the following: -// 1. set m_bFlushing ensures no more requests succeed -// 2. move all items from work list to the done list. -// 3. If there are any outstanding requests, then we need to release the -// critsec to allow them to complete. The m_bWaiting as well as ensuring -// that we are signalled when they are all done is also used to indicate -// to WaitForNext that it should continue to block. -// 4. Once all outstanding requests are complete, we force m_evDone set and -// m_bFlushing set and m_bWaiting false. This ensures that WaitForNext will -// not block when the done list is empty. -HRESULT -CAsyncIo::BeginFlush() -{ - // hold the lock while emptying the work list - { - CAutoLock lock(&m_csLists); - - // prevent further requests being queued. - // Also WaitForNext will refuse to block if this is set - // unless m_bWaiting is also set which it will be when we release - // the critsec if there are any outstanding). - m_bFlushing = TRUE; - - CAsyncRequest * preq; - while((preq = GetWorkItem()) != 0) - { - preq->Cancel(); - PutDoneItem(preq); - } - - // now wait for any outstanding requests to complete - if(m_cItemsOut > 0) - { - // can be only one person waiting - ASSERT(!m_bWaiting); - - // this tells the completion routine that we need to be - // signalled via m_evAllDone when all outstanding items are - // done. It also tells WaitForNext to continue blocking. - m_bWaiting = TRUE; - } - else - { - // all done - - // force m_evDone set so that even if list is empty, - // WaitForNext will not block - // don't do this until we are sure that all - // requests are on the done list. - m_evDone.Set(); - return S_OK; - } - } - - ASSERT(m_bWaiting); - - // wait without holding critsec - for(;;) - { - m_evAllDone.Wait(); - { - // hold critsec to check - CAutoLock lock(&m_csLists); - - if(m_cItemsOut == 0) - { - // now we are sure that all outstanding requests are on - // the done list and no more will be accepted - m_bWaiting = FALSE; - - // force m_evDone set so that even if list is empty, - // WaitForNext will not block - // don't do this until we are sure that all - // requests are on the done list. - m_evDone.Set(); - - return S_OK; - } - } - } -} - - -// end a flushing state -HRESULT -CAsyncIo::EndFlush() -{ - CAutoLock lock(&m_csLists); - - m_bFlushing = FALSE; - - ASSERT(!m_bWaiting); - - // m_evDone might have been set by BeginFlush - ensure it is - // set IFF m_listDone is non-empty - if(m_listDone.GetCount() > 0) - { - m_evDone.Set(); - } - else - { - m_evDone.Reset(); - } - - return S_OK; -} - - -// start the thread -HRESULT -CAsyncIo::StartThread(void) -{ - if(m_hThread) - { - return S_OK; - } - - // clear the stop event before starting - m_evStop.Reset(); - - DWORD dwThreadID; - m_hThread = CreateThread(NULL, - 0, - InitialThreadProc, - this, - 0, - &dwThreadID); - if(!m_hThread) - { - DWORD dwErr = GetLastError(); - return HRESULT_FROM_WIN32(dwErr); - } - - return S_OK; -} - - -// stop the thread and close the handle -HRESULT -CAsyncIo::CloseThread(void) -{ - // signal the thread-exit object - m_evStop.Set(); - - if(m_hThread) - { - WaitForSingleObject(m_hThread, INFINITE); - CloseHandle(m_hThread); - m_hThread = NULL; - } - - return S_OK; -} - - -// manage the list of requests. hold m_csLists and ensure -// that the (manual reset) event hevList is set when things on -// the list but reset when the list is empty. -// returns null if list empty -CAsyncRequest* -CAsyncIo::GetWorkItem() -{ - CAutoLock lck(&m_csLists); - CAsyncRequest * preq = m_listWork.RemoveHead(); - - // force event set correctly - if(m_listWork.GetCount() == 0) - { - m_evWork.Reset(); - } - - return preq; -} - - -// get an item from the done list -CAsyncRequest* -CAsyncIo::GetDoneItem() -{ - CAutoLock lock(&m_csLists); - CAsyncRequest * preq = m_listDone.RemoveHead(); - - // force event set correctly if list now empty - // or we're in the final stages of flushing - // Note that during flushing the way it's supposed to work is that - // everything is shoved on the Done list then the application is - // supposed to pull until it gets nothing more - // - // Thus we should not set m_evDone unconditionally until everything - // has moved to the done list which means we must wait until - // cItemsOut is 0 (which is guaranteed by m_bWaiting being TRUE). - - if(m_listDone.GetCount() == 0 && - (!m_bFlushing || m_bWaiting)) - { - m_evDone.Reset(); - } - - return preq; -} - - -// put an item on the work list - fail if bFlushing -HRESULT -CAsyncIo::PutWorkItem(CAsyncRequest* pRequest) -{ - CAutoLock lock(&m_csLists); - HRESULT hr; - - if(m_bFlushing) - { - hr = VFW_E_WRONG_STATE; - } - else if(m_listWork.AddTail(pRequest)) - { - // event should now be in a set state - force this - m_evWork.Set(); - - // start the thread now if not already started - hr = StartThread(); - - } - else - { - hr = E_OUTOFMEMORY; - } - - return(hr); -} - - -// put an item on the done list - ok to do this when -// flushing -HRESULT -CAsyncIo::PutDoneItem(CAsyncRequest* pRequest) -{ - ASSERT(CritCheckIn(&m_csLists)); - - if(m_listDone.AddTail(pRequest)) - { - // event should now be in a set state - force this - m_evDone.Set(); - return S_OK; - } - else - { - return E_OUTOFMEMORY; - } -} - - -// called on thread to process any active requests -void -CAsyncIo::ProcessRequests(void) -{ - // lock to get the item and increment the outstanding count - CAsyncRequest * preq = NULL; - - for(;;) - { - { - CAutoLock lock(&m_csLists); - - preq = GetWorkItem(); - if(preq == NULL) - { - // done - return; - } - - // one more item not on the done or work list - m_cItemsOut++; - - // release critsec - } - - preq->Complete(); - - // regain critsec to replace on done list - { - CAutoLock l(&m_csLists); - - PutDoneItem(preq); - - if(--m_cItemsOut == 0) - { - if(m_bWaiting) - m_evAllDone.Set(); - } - } - } -} - - -// the thread proc - assumes that DWORD thread param is the -// this pointer -DWORD -CAsyncIo::ThreadProc(void) -{ - HANDLE ahev[] = {m_evStop, m_evWork}; - - for(;;) - { - DWORD dw = WaitForMultipleObjects(2, - ahev, - FALSE, - INFINITE); - if(dw == WAIT_OBJECT_0+1) - { - // requests need processing - ProcessRequests(); - } - else - { - // any error or stop event - we should exit - return 0; - } - } -} - - -// perform a synchronous read request on this thread. -// may not be aligned - so we will have to buffer. -HRESULT -CAsyncIo::SyncRead( - LONGLONG llPos, - LONG lLength, - BYTE * pBuffer) -{ - if(IsAligned(llPos) && - IsAligned(lLength) && - IsAligned((LONG_PTR) pBuffer)) - { - LONG cbUnused; - return SyncReadAligned(llPos, lLength, pBuffer, &cbUnused, NULL); - } - - // not aligned with requirements - use buffered file handle. - //!!! might want to fix this to buffer the data ourselves? - - CAsyncRequest request; - - HRESULT hr = request.Request(this, - m_pStream, - llPos, - lLength, - FALSE, - pBuffer, - NULL, - 0); - - if(FAILED(hr)) - { - return hr; - } - - return request.Complete(); -} - - -// Return the alignment -HRESULT -CAsyncIo::Alignment(LONG *pAlignment) -{ - CheckPointer(pAlignment,E_POINTER); - - *pAlignment = Alignment(); - return S_OK; -} - - +//------------------------------------------------------------------------------ +// File: AsyncIo.cpp +// +// Desc: DirectShow sample code - base library with I/O functionality. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "stdafx.h" +#include "BaseClasses/streams.h" +#include "asyncio.h" + +// --- CAsyncRequest --- + + +// implementation of CAsyncRequest representing a single +// outstanding request. All the i/o for this object is done +// in the Complete method. + + +// init the params for this request. +// Read is not issued until the complete call +HRESULT +CAsyncRequest::Request( + CAsyncIo *pIo, + CAsyncStream *pStream, + LONGLONG llPos, + LONG lLength, + BOOL bAligned, + BYTE* pBuffer, + LPVOID pContext, // filter's context + DWORD_PTR dwUser) // downstream filter's context +{ + m_pIo = pIo; + m_pStream = pStream; + m_llPos = llPos; + m_lLength = lLength; + m_bAligned = bAligned; + m_pBuffer = pBuffer; + m_pContext = pContext; + m_dwUser = dwUser; + m_hr = VFW_E_TIMEOUT; // not done yet + + return S_OK; +} + + +// issue the i/o if not overlapped, and block until i/o complete. +// returns error code of file i/o +// +// +HRESULT +CAsyncRequest::Complete() +{ + m_pStream->Lock(); + + m_hr = m_pStream->SetPointer(m_llPos); + if(S_OK == m_hr) + { + DWORD dwActual; + + m_hr = m_pStream->Read(m_pBuffer, m_lLength, m_bAligned, &dwActual); + if(m_hr == OLE_S_FIRST) + { + if(m_pContext) + { + IMediaSample *pSample = reinterpret_cast(m_pContext); + pSample->SetDiscontinuity(TRUE); + m_hr = S_OK; + } + } + + if(FAILED(m_hr)) + { + } + else if(dwActual != (DWORD)m_lLength) + { + // tell caller size changed - probably because of EOF + m_lLength = (LONG) dwActual; + m_hr = S_FALSE; + } + else + { + m_hr = S_OK; + } + } + + m_pStream->Unlock(); + return m_hr; +} + + +// --- CAsyncIo --- + +// note - all events created manual reset + +CAsyncIo::CAsyncIo(CAsyncStream *pStream) + : m_pStream(pStream), + m_bFlushing(FALSE), + m_listWork(NAME("Work list")), + m_listDone(NAME("Done list")), + m_evWork(TRUE), + m_evDone(TRUE), + m_cItemsOut(0), + m_bWaiting(FALSE), + m_evStop(TRUE), + m_hThread(NULL) +{ + +} + + +CAsyncIo::~CAsyncIo() +{ + // move everything to the done list + BeginFlush(); + + // shutdown worker thread + CloseThread(); + + // empty the done list + POSITION pos = m_listDone.GetHeadPosition(); + while(pos) + { + CAsyncRequest* pRequest = m_listDone.GetNext(pos); + delete pRequest; + } + + m_listDone.RemoveAll(); +} + + +// ready for async activity - call this before calling Request. +// +// start the worker thread if we need to +// +// !!! use overlapped i/o if possible +HRESULT +CAsyncIo::AsyncActive(void) +{ + return StartThread(); +} + +// call this when no more async activity will happen before +// the next AsyncActive call +// +// stop the worker thread if active +HRESULT +CAsyncIo::AsyncInactive(void) +{ + return CloseThread(); +} + + +// add a request to the queue. +HRESULT +CAsyncIo::Request( + LONGLONG llPos, + LONG lLength, + BOOL bAligned, + BYTE * pBuffer, + LPVOID pContext, + DWORD_PTR dwUser) +{ + if(bAligned) + { + if(!IsAligned(llPos) || + !IsAligned(lLength) || + !IsAligned((LONG_PTR) pBuffer)) + { + return VFW_E_BADALIGN; + } + } + + CAsyncRequest* pRequest = new CAsyncRequest; + if (!pRequest) + return E_OUTOFMEMORY; + + HRESULT hr = pRequest->Request(this, + m_pStream, + llPos, + lLength, + bAligned, + pBuffer, + pContext, + dwUser); + if(SUCCEEDED(hr)) + { + // might fail if flushing + hr = PutWorkItem(pRequest); + } + + if(FAILED(hr)) + { + delete pRequest; + } + + return hr; +} + + +// wait for the next request to complete +HRESULT +CAsyncIo::WaitForNext( + DWORD dwTimeout, + LPVOID * ppContext, + DWORD_PTR * pdwUser, + LONG * pcbActual) +{ + CheckPointer(ppContext,E_POINTER); + CheckPointer(pdwUser,E_POINTER); + CheckPointer(pcbActual,E_POINTER); + + // some errors find a sample, others don't. Ensure that + // *ppContext is NULL if no sample found + *ppContext = NULL; + + // wait until the event is set, but since we are not + // holding the critsec when waiting, we may need to re-wait + for(;;) + { + if(!m_evDone.Wait(dwTimeout)) + { + // timeout occurred + return VFW_E_TIMEOUT; + } + + // get next event from list + CAsyncRequest* pRequest = GetDoneItem(); + if(pRequest) + { + // found a completed request + + // check if ok + HRESULT hr = pRequest->GetHResult(); + if(hr == S_FALSE) + { + // this means the actual length was less than + // requested - may be ok if he aligned the end of file + if((pRequest->GetActualLength() + + pRequest->GetStart()) == Size()) + { + hr = S_OK; + } + else + { + // it was an actual read error + hr = E_FAIL; + } + } + + // return actual bytes read + *pcbActual = pRequest->GetActualLength(); + + // return his context + *ppContext = pRequest->GetContext(); + *pdwUser = pRequest->GetUser(); + + delete pRequest; + return hr; + } + else + { + // Hold the critical section while checking the list state + CAutoLock lck(&m_csLists); + if(m_bFlushing && !m_bWaiting) + { + // can't block as we are between BeginFlush and EndFlush + + // but note that if m_bWaiting is set, then there are some + // items not yet complete that we should block for. + + return VFW_E_WRONG_STATE; + } + } + + // done item was grabbed between completion and + // us locking m_csLists. + } +} + + +// perform a synchronous read request on this thread. +// Need to hold m_csFile while doing this (done in request object) +HRESULT +CAsyncIo::SyncReadAligned( + LONGLONG llPos, + LONG lLength, + BYTE * pBuffer, + LONG * pcbActual, + PVOID pvContext) +{ + CheckPointer(pcbActual,E_POINTER); + + if(!IsAligned(llPos) || + !IsAligned(lLength) || + !IsAligned((LONG_PTR) pBuffer)) + { + return VFW_E_BADALIGN; + } + + CAsyncRequest request; + + HRESULT hr = request.Request(this, + m_pStream, + llPos, + lLength, + TRUE, + pBuffer, + pvContext, + 0); + if(FAILED(hr)) + return hr; + + hr = request.Complete(); + + // return actual data length + *pcbActual = request.GetActualLength(); + return hr; +} + + +HRESULT +CAsyncIo::Length(LONGLONG *pllTotal, LONGLONG *pllAvailable) +{ + CheckPointer(pllTotal,E_POINTER); + + *pllTotal = m_pStream->Size(pllAvailable); + return S_OK; +} + + +// cancel all items on the worklist onto the done list +// and refuse further requests or further WaitForNext calls +// until the end flush +// +// WaitForNext must return with NULL only if there are no successful requests. +// So Flush does the following: +// 1. set m_bFlushing ensures no more requests succeed +// 2. move all items from work list to the done list. +// 3. If there are any outstanding requests, then we need to release the +// critsec to allow them to complete. The m_bWaiting as well as ensuring +// that we are signalled when they are all done is also used to indicate +// to WaitForNext that it should continue to block. +// 4. Once all outstanding requests are complete, we force m_evDone set and +// m_bFlushing set and m_bWaiting false. This ensures that WaitForNext will +// not block when the done list is empty. +HRESULT +CAsyncIo::BeginFlush() +{ + // hold the lock while emptying the work list + { + CAutoLock lock(&m_csLists); + + // prevent further requests being queued. + // Also WaitForNext will refuse to block if this is set + // unless m_bWaiting is also set which it will be when we release + // the critsec if there are any outstanding). + m_bFlushing = TRUE; + + CAsyncRequest * preq; + while((preq = GetWorkItem()) != 0) + { + preq->Cancel(); + PutDoneItem(preq); + } + + // now wait for any outstanding requests to complete + if(m_cItemsOut > 0) + { + // can be only one person waiting + ASSERT(!m_bWaiting); + + // this tells the completion routine that we need to be + // signalled via m_evAllDone when all outstanding items are + // done. It also tells WaitForNext to continue blocking. + m_bWaiting = TRUE; + } + else + { + // all done + + // force m_evDone set so that even if list is empty, + // WaitForNext will not block + // don't do this until we are sure that all + // requests are on the done list. + m_evDone.Set(); + return S_OK; + } + } + + ASSERT(m_bWaiting); + + // wait without holding critsec + for(;;) + { + m_evAllDone.Wait(); + { + // hold critsec to check + CAutoLock lock(&m_csLists); + + if(m_cItemsOut == 0) + { + // now we are sure that all outstanding requests are on + // the done list and no more will be accepted + m_bWaiting = FALSE; + + // force m_evDone set so that even if list is empty, + // WaitForNext will not block + // don't do this until we are sure that all + // requests are on the done list. + m_evDone.Set(); + + return S_OK; + } + } + } +} + + +// end a flushing state +HRESULT +CAsyncIo::EndFlush() +{ + CAutoLock lock(&m_csLists); + + m_bFlushing = FALSE; + + ASSERT(!m_bWaiting); + + // m_evDone might have been set by BeginFlush - ensure it is + // set IFF m_listDone is non-empty + if(m_listDone.GetCount() > 0) + { + m_evDone.Set(); + } + else + { + m_evDone.Reset(); + } + + return S_OK; +} + + +// start the thread +HRESULT +CAsyncIo::StartThread(void) +{ + if(m_hThread) + { + return S_OK; + } + + // clear the stop event before starting + m_evStop.Reset(); + + DWORD dwThreadID; + m_hThread = CreateThread(NULL, + 0, + InitialThreadProc, + this, + 0, + &dwThreadID); + if(!m_hThread) + { + DWORD dwErr = GetLastError(); + return HRESULT_FROM_WIN32(dwErr); + } + + return S_OK; +} + + +// stop the thread and close the handle +HRESULT +CAsyncIo::CloseThread(void) +{ + // signal the thread-exit object + m_evStop.Set(); + + if(m_hThread) + { + WaitForSingleObject(m_hThread, INFINITE); + CloseHandle(m_hThread); + m_hThread = NULL; + } + + return S_OK; +} + + +// manage the list of requests. hold m_csLists and ensure +// that the (manual reset) event hevList is set when things on +// the list but reset when the list is empty. +// returns null if list empty +CAsyncRequest* +CAsyncIo::GetWorkItem() +{ + CAutoLock lck(&m_csLists); + CAsyncRequest * preq = m_listWork.RemoveHead(); + + // force event set correctly + if(m_listWork.GetCount() == 0) + { + m_evWork.Reset(); + } + + return preq; +} + + +// get an item from the done list +CAsyncRequest* +CAsyncIo::GetDoneItem() +{ + CAutoLock lock(&m_csLists); + CAsyncRequest * preq = m_listDone.RemoveHead(); + + // force event set correctly if list now empty + // or we're in the final stages of flushing + // Note that during flushing the way it's supposed to work is that + // everything is shoved on the Done list then the application is + // supposed to pull until it gets nothing more + // + // Thus we should not set m_evDone unconditionally until everything + // has moved to the done list which means we must wait until + // cItemsOut is 0 (which is guaranteed by m_bWaiting being TRUE). + + if(m_listDone.GetCount() == 0 && + (!m_bFlushing || m_bWaiting)) + { + m_evDone.Reset(); + } + + return preq; +} + + +// put an item on the work list - fail if bFlushing +HRESULT +CAsyncIo::PutWorkItem(CAsyncRequest* pRequest) +{ + CAutoLock lock(&m_csLists); + HRESULT hr; + + if(m_bFlushing) + { + hr = VFW_E_WRONG_STATE; + } + else if(m_listWork.AddTail(pRequest)) + { + // event should now be in a set state - force this + m_evWork.Set(); + + // start the thread now if not already started + hr = StartThread(); + + } + else + { + hr = E_OUTOFMEMORY; + } + + return(hr); +} + + +// put an item on the done list - ok to do this when +// flushing +HRESULT +CAsyncIo::PutDoneItem(CAsyncRequest* pRequest) +{ + ASSERT(CritCheckIn(&m_csLists)); + + if(m_listDone.AddTail(pRequest)) + { + // event should now be in a set state - force this + m_evDone.Set(); + return S_OK; + } + else + { + return E_OUTOFMEMORY; + } +} + + +// called on thread to process any active requests +void +CAsyncIo::ProcessRequests(void) +{ + // lock to get the item and increment the outstanding count + CAsyncRequest * preq = NULL; + + for(;;) + { + { + CAutoLock lock(&m_csLists); + + preq = GetWorkItem(); + if(preq == NULL) + { + // done + return; + } + + // one more item not on the done or work list + m_cItemsOut++; + + // release critsec + } + + preq->Complete(); + + // regain critsec to replace on done list + { + CAutoLock l(&m_csLists); + + PutDoneItem(preq); + + if(--m_cItemsOut == 0) + { + if(m_bWaiting) + m_evAllDone.Set(); + } + } + } +} + + +// the thread proc - assumes that DWORD thread param is the +// this pointer +DWORD +CAsyncIo::ThreadProc(void) +{ + HANDLE ahev[] = {m_evStop, m_evWork}; + + for(;;) + { + DWORD dw = WaitForMultipleObjects(2, + ahev, + FALSE, + INFINITE); + if(dw == WAIT_OBJECT_0+1) + { + // requests need processing + ProcessRequests(); + } + else + { + // any error or stop event - we should exit + return 0; + } + } +} + + +// perform a synchronous read request on this thread. +// may not be aligned - so we will have to buffer. +HRESULT +CAsyncIo::SyncRead( + LONGLONG llPos, + LONG lLength, + BYTE * pBuffer) +{ + if(IsAligned(llPos) && + IsAligned(lLength) && + IsAligned((LONG_PTR) pBuffer)) + { + LONG cbUnused; + return SyncReadAligned(llPos, lLength, pBuffer, &cbUnused, NULL); + } + + // not aligned with requirements - use buffered file handle. + //!!! might want to fix this to buffer the data ourselves? + + CAsyncRequest request; + + HRESULT hr = request.Request(this, + m_pStream, + llPos, + lLength, + FALSE, + pBuffer, + NULL, + 0); + + if(FAILED(hr)) + { + return hr; + } + + return request.Complete(); +} + + +// Return the alignment +HRESULT +CAsyncIo::Alignment(LONG *pAlignment) +{ + CheckPointer(pAlignment,E_POINTER); + + *pAlignment = Alignment(); + return S_OK; +} + + diff --git a/src/thirdparty/AsyncReader/asyncio.h b/src/thirdparty/AsyncReader/asyncio.h index 8fc56200284..7cdc58de91e 100644 --- a/src/thirdparty/AsyncReader/asyncio.h +++ b/src/thirdparty/AsyncReader/asyncio.h @@ -1,280 +1,280 @@ -//------------------------------------------------------------------------------ -// File: AsyncIo.h -// -// Desc: DirectShow sample code - base library for I/O functionality. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __ASYNCIO_H__ -#define __ASYNCIO_H__ - -// -// definition of CAsyncFile object that performs file access. It provides -// asynchronous, unbuffered, aligned reads from a file, using a worker thread -// on win95 and potentially overlapped i/o if available. - -// !!! Need to use real overlapped i/o if available -// currently only uses worker thread, not overlapped i/o - - -class CAsyncIo; -class CAsyncStream; - -// -// Model the stream we read from based on a file-like interface -// -class CAsyncStream -{ -public: - virtual ~CAsyncStream() {}; - virtual HRESULT SetPointer(LONGLONG llPos) = 0; - virtual HRESULT Read(PBYTE pbBuffer, - DWORD dwBytesToRead, - BOOL bAlign, - LPDWORD pdwBytesRead) = 0; - - virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0; - virtual DWORD Alignment() = 0; - virtual void Lock() = 0; - virtual void Unlock() = 0; - //virtual void SetStopHandle(HANDLE hevStop) {} -}; - -// represents a single request and performs the i/o. Can be called on either -// worker thread or app thread, but must hold pcsFile across file accesses. -// (ie across SetFilePointer/ReadFile pairs) -class CAsyncRequest -{ - CAsyncIo *m_pIo; - CAsyncStream *m_pStream; - LONGLONG m_llPos; - BOOL m_bAligned; - LONG m_lLength; - BYTE* m_pBuffer; - LPVOID m_pContext; - DWORD_PTR m_dwUser; - HRESULT m_hr; - -public: - // init the params for this request. Issue the i/o - // if overlapped i/o is possible. - HRESULT Request( - CAsyncIo *pIo, - CAsyncStream *pStream, - LONGLONG llPos, - LONG lLength, - BOOL bAligned, - BYTE* pBuffer, - LPVOID pContext, // filter's context - DWORD_PTR dwUser); // downstream filter's context - - // issue the i/o if not overlapped, and block until i/o complete. - // returns error code of file i/o - HRESULT Complete(); - - // cancels the i/o. blocks until i/o is no longer pending - HRESULT Cancel() - { - return S_OK; - }; - - // accessor functions - LPVOID GetContext() - { - return m_pContext; - }; - - DWORD_PTR GetUser() - { - return m_dwUser; - }; - - HRESULT GetHResult() { - return m_hr; - }; - - // we set m_lLength to the actual length - LONG GetActualLength() { - return m_lLength; - }; - - LONGLONG GetStart() { - return m_llPos; - }; -}; - - -typedef CGenericList CRequestList; - -// this class needs a worker thread, but the ones defined in classes\base -// are not suitable (they assume you have one message sent or posted per -// request, whereas here for efficiency we want just to set an event when -// there is work on the queue). -// -// we create CAsyncRequest objects and queue them on m_listWork. The worker -// thread pulls them off, completes them and puts them on m_listDone. -// The events m_evWork and m_evDone are set when the corresponding lists are -// not empty. -// -// Synchronous requests are done on the caller thread. These should be -// synchronised by the caller, but to make sure we hold m_csFile across -// the SetFilePointer/ReadFile code. -// -// Flush by calling BeginFlush. This rejects all further requests (by -// setting m_bFlushing within m_csLists), cancels all requests and moves them -// to the done list, and sets m_evDone to ensure that no WaitForNext operations -// will block. Call EndFlush to cancel this state. -// -// we support unaligned calls to SyncRead. This is done by opening the file -// twice if we are using unbuffered i/o (m_dwAlign > 1). -// !!!fix this to buffer on top of existing file handle? -class CAsyncIo -{ - - CCritSec m_csReader; - CAsyncStream *m_pStream; - - CCritSec m_csLists; // locks access to the list and events - BOOL m_bFlushing; // true if between BeginFlush/EndFlush - - CRequestList m_listWork; - CRequestList m_listDone; - - CAMEvent m_evWork; // set when list is not empty - CAMEvent m_evDone; - - // for correct flush behaviour: all protected by m_csLists - LONG m_cItemsOut; // nr of items not on listDone or listWork - BOOL m_bWaiting; // TRUE if someone waiting for m_evAllDone - CAMEvent m_evAllDone; // signal when m_cItemsOut goes to 0 if m_cWaiting - - - CAMEvent m_evStop; // set when thread should exit - HANDLE m_hThread; - - LONGLONG Size() { - ASSERT(m_pStream != NULL); - return m_pStream->Size(); - }; - - // start the thread - HRESULT StartThread(void); - - // stop the thread and close the handle - HRESULT CloseThread(void); - - // manage the list of requests. hold m_csLists and ensure - // that the (manual reset) event hevList is set when things on - // the list but reset when the list is empty. - // returns null if list empty - CAsyncRequest* GetWorkItem(); - - // get an item from the done list - CAsyncRequest* GetDoneItem(); - - // put an item on the work list - HRESULT PutWorkItem(CAsyncRequest* pRequest); - - // put an item on the done list - HRESULT PutDoneItem(CAsyncRequest* pRequest); - - // called on thread to process any active requests - void ProcessRequests(void); - - // initial static thread proc calls ThreadProc with DWORD - // param as this - static DWORD WINAPI InitialThreadProc(LPVOID pv) { - CAsyncIo * pThis = (CAsyncIo*) pv; - return pThis->ThreadProc(); - }; - - DWORD ThreadProc(void); - -public: - - CAsyncIo(CAsyncStream *pStream); - ~CAsyncIo(); - - // open the file - HRESULT Open(LPCTSTR pName); - - // ready for async activity - call this before - // calling Request - HRESULT AsyncActive(void); - - // call this when no more async activity will happen before - // the next AsyncActive call - HRESULT AsyncInactive(void); - - // queue a requested read. must be aligned. - HRESULT Request( - LONGLONG llPos, - LONG lLength, - BOOL bAligned, - BYTE* pBuffer, - LPVOID pContext, - DWORD_PTR dwUser); - - // wait for the next read to complete - HRESULT WaitForNext( - DWORD dwTimeout, - LPVOID *ppContext, - DWORD_PTR * pdwUser, - LONG * pcbActual); - - // perform a read of an already aligned buffer - HRESULT SyncReadAligned( - LONGLONG llPos, - LONG lLength, - BYTE* pBuffer, - LONG* pcbActual, - PVOID pvContext); - - // perform a synchronous read. will be buffered - // if not aligned. - HRESULT SyncRead( - LONGLONG llPos, - LONG lLength, - BYTE* pBuffer); - - // return length - HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable); - - // all Reader positions, read lengths and memory locations must - // be aligned to this. - HRESULT Alignment(LONG* pl); - - HRESULT BeginFlush(); - HRESULT EndFlush(); - - LONG Alignment() - { - return m_pStream->Alignment(); - }; - - BOOL IsAligned(LONG_PTR l) - { - // LONG_PTR is long on 32-bit or __int64 on 64-bit. - if ( (static_cast(l & 0xffffffff) & (Alignment() -1)) == 0 ) - { - return TRUE; - } - else - { - return FALSE; - } - }; - -#ifndef _WIN64 - BOOL IsAligned(LONGLONG ll) { - return IsAligned( (LONG) (ll & 0xffffffff)); - }; -#endif - - // Accessor - HANDLE StopEvent() const { return m_evDone; } -}; - -#endif // __ASYNCIO_H__ +//------------------------------------------------------------------------------ +// File: AsyncIo.h +// +// Desc: DirectShow sample code - base library for I/O functionality. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __ASYNCIO_H__ +#define __ASYNCIO_H__ + +// +// definition of CAsyncFile object that performs file access. It provides +// asynchronous, unbuffered, aligned reads from a file, using a worker thread +// on win95 and potentially overlapped i/o if available. + +// !!! Need to use real overlapped i/o if available +// currently only uses worker thread, not overlapped i/o + + +class CAsyncIo; +class CAsyncStream; + +// +// Model the stream we read from based on a file-like interface +// +class CAsyncStream +{ +public: + virtual ~CAsyncStream() {}; + virtual HRESULT SetPointer(LONGLONG llPos) = 0; + virtual HRESULT Read(PBYTE pbBuffer, + DWORD dwBytesToRead, + BOOL bAlign, + LPDWORD pdwBytesRead) = 0; + + virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0; + virtual DWORD Alignment() = 0; + virtual void Lock() = 0; + virtual void Unlock() = 0; + //virtual void SetStopHandle(HANDLE hevStop) {} +}; + +// represents a single request and performs the i/o. Can be called on either +// worker thread or app thread, but must hold pcsFile across file accesses. +// (ie across SetFilePointer/ReadFile pairs) +class CAsyncRequest +{ + CAsyncIo *m_pIo; + CAsyncStream *m_pStream; + LONGLONG m_llPos; + BOOL m_bAligned; + LONG m_lLength; + BYTE* m_pBuffer; + LPVOID m_pContext; + DWORD_PTR m_dwUser; + HRESULT m_hr; + +public: + // init the params for this request. Issue the i/o + // if overlapped i/o is possible. + HRESULT Request( + CAsyncIo *pIo, + CAsyncStream *pStream, + LONGLONG llPos, + LONG lLength, + BOOL bAligned, + BYTE* pBuffer, + LPVOID pContext, // filter's context + DWORD_PTR dwUser); // downstream filter's context + + // issue the i/o if not overlapped, and block until i/o complete. + // returns error code of file i/o + HRESULT Complete(); + + // cancels the i/o. blocks until i/o is no longer pending + HRESULT Cancel() + { + return S_OK; + }; + + // accessor functions + LPVOID GetContext() + { + return m_pContext; + }; + + DWORD_PTR GetUser() + { + return m_dwUser; + }; + + HRESULT GetHResult() { + return m_hr; + }; + + // we set m_lLength to the actual length + LONG GetActualLength() { + return m_lLength; + }; + + LONGLONG GetStart() { + return m_llPos; + }; +}; + + +typedef CGenericList CRequestList; + +// this class needs a worker thread, but the ones defined in classes\base +// are not suitable (they assume you have one message sent or posted per +// request, whereas here for efficiency we want just to set an event when +// there is work on the queue). +// +// we create CAsyncRequest objects and queue them on m_listWork. The worker +// thread pulls them off, completes them and puts them on m_listDone. +// The events m_evWork and m_evDone are set when the corresponding lists are +// not empty. +// +// Synchronous requests are done on the caller thread. These should be +// synchronised by the caller, but to make sure we hold m_csFile across +// the SetFilePointer/ReadFile code. +// +// Flush by calling BeginFlush. This rejects all further requests (by +// setting m_bFlushing within m_csLists), cancels all requests and moves them +// to the done list, and sets m_evDone to ensure that no WaitForNext operations +// will block. Call EndFlush to cancel this state. +// +// we support unaligned calls to SyncRead. This is done by opening the file +// twice if we are using unbuffered i/o (m_dwAlign > 1). +// !!!fix this to buffer on top of existing file handle? +class CAsyncIo +{ + + CCritSec m_csReader; + CAsyncStream *m_pStream; + + CCritSec m_csLists; // locks access to the list and events + BOOL m_bFlushing; // true if between BeginFlush/EndFlush + + CRequestList m_listWork; + CRequestList m_listDone; + + CAMEvent m_evWork; // set when list is not empty + CAMEvent m_evDone; + + // for correct flush behaviour: all protected by m_csLists + LONG m_cItemsOut; // nr of items not on listDone or listWork + BOOL m_bWaiting; // TRUE if someone waiting for m_evAllDone + CAMEvent m_evAllDone; // signal when m_cItemsOut goes to 0 if m_cWaiting + + + CAMEvent m_evStop; // set when thread should exit + HANDLE m_hThread; + + LONGLONG Size() { + ASSERT(m_pStream != NULL); + return m_pStream->Size(); + }; + + // start the thread + HRESULT StartThread(void); + + // stop the thread and close the handle + HRESULT CloseThread(void); + + // manage the list of requests. hold m_csLists and ensure + // that the (manual reset) event hevList is set when things on + // the list but reset when the list is empty. + // returns null if list empty + CAsyncRequest* GetWorkItem(); + + // get an item from the done list + CAsyncRequest* GetDoneItem(); + + // put an item on the work list + HRESULT PutWorkItem(CAsyncRequest* pRequest); + + // put an item on the done list + HRESULT PutDoneItem(CAsyncRequest* pRequest); + + // called on thread to process any active requests + void ProcessRequests(void); + + // initial static thread proc calls ThreadProc with DWORD + // param as this + static DWORD WINAPI InitialThreadProc(LPVOID pv) { + CAsyncIo * pThis = (CAsyncIo*) pv; + return pThis->ThreadProc(); + }; + + DWORD ThreadProc(void); + +public: + + CAsyncIo(CAsyncStream *pStream); + ~CAsyncIo(); + + // open the file + HRESULT Open(LPCTSTR pName); + + // ready for async activity - call this before + // calling Request + HRESULT AsyncActive(void); + + // call this when no more async activity will happen before + // the next AsyncActive call + HRESULT AsyncInactive(void); + + // queue a requested read. must be aligned. + HRESULT Request( + LONGLONG llPos, + LONG lLength, + BOOL bAligned, + BYTE* pBuffer, + LPVOID pContext, + DWORD_PTR dwUser); + + // wait for the next read to complete + HRESULT WaitForNext( + DWORD dwTimeout, + LPVOID *ppContext, + DWORD_PTR * pdwUser, + LONG * pcbActual); + + // perform a read of an already aligned buffer + HRESULT SyncReadAligned( + LONGLONG llPos, + LONG lLength, + BYTE* pBuffer, + LONG* pcbActual, + PVOID pvContext); + + // perform a synchronous read. will be buffered + // if not aligned. + HRESULT SyncRead( + LONGLONG llPos, + LONG lLength, + BYTE* pBuffer); + + // return length + HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable); + + // all Reader positions, read lengths and memory locations must + // be aligned to this. + HRESULT Alignment(LONG* pl); + + HRESULT BeginFlush(); + HRESULT EndFlush(); + + LONG Alignment() + { + return m_pStream->Alignment(); + }; + + BOOL IsAligned(LONG_PTR l) + { + // LONG_PTR is long on 32-bit or __int64 on 64-bit. + if ( (static_cast(l & 0xffffffff) & (Alignment() -1)) == 0 ) + { + return TRUE; + } + else + { + return FALSE; + } + }; + +#ifndef _WIN64 + BOOL IsAligned(LONGLONG ll) { + return IsAligned( (LONG) (ll & 0xffffffff)); + }; +#endif + + // Accessor + HANDLE StopEvent() const { return m_evDone; } +}; + +#endif // __ASYNCIO_H__ diff --git a/src/thirdparty/AsyncReader/asyncrdr.cpp b/src/thirdparty/AsyncReader/asyncrdr.cpp index 524afe52b1f..3213ba4e50c 100644 --- a/src/thirdparty/AsyncReader/asyncrdr.cpp +++ b/src/thirdparty/AsyncReader/asyncrdr.cpp @@ -1,454 +1,454 @@ -//------------------------------------------------------------------------------ -// File: AsyncRdr.cpp -// -// Desc: DirectShow sample code - base library with I/O functionality. -// This file implements I/O source filter methods and output pin -// methods for CAsyncReader and CAsyncOutputPin. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "stdafx.h" -#include "BaseClasses/streams.h" -#include "asyncio.h" -#include "asyncrdr.h" - -// --- CAsyncOutputPin implementation --- - -CAsyncOutputPin::CAsyncOutputPin( - HRESULT * phr, - CAsyncReader *pReader, - CAsyncIo *pIo, - CCritSec * pLock) - : CBasePin( - NAME("Async output pin"), - pReader, - pLock, - phr, - L"Output", - PINDIR_OUTPUT), - m_pReader(pReader), - m_pIo(pIo), - m_bQueriedForAsyncReader(FALSE) -{ -} - -CAsyncOutputPin::~CAsyncOutputPin() -{ -} - - -STDMETHODIMP CAsyncOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv,E_POINTER); - - if(riid == IID_IAsyncReader) - { - m_bQueriedForAsyncReader = TRUE; - return GetInterface((IAsyncReader*) this, ppv); - } - else - { - return CBasePin::NonDelegatingQueryInterface(riid, ppv); - } -} - - -HRESULT CAsyncOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType) -{ - if(iPosition < 0) - { - return E_INVALIDARG; - } - if(iPosition > 0) - { - return VFW_S_NO_MORE_ITEMS; - } - - CheckPointer(pMediaType,E_POINTER); - CheckPointer(m_pReader,E_UNEXPECTED); - - *pMediaType = *m_pReader->LoadType(); - - return S_OK; -} - - -HRESULT CAsyncOutputPin::CheckMediaType(const CMediaType* pType) -{ - CAutoLock lck(m_pLock); - - /* We treat MEDIASUBTYPE_NULL subtype as a wild card */ - if((m_pReader->LoadType()->majortype == pType->majortype) && - (m_pReader->LoadType()->subtype == MEDIASUBTYPE_NULL || - m_pReader->LoadType()->subtype == pType->subtype)) - { - return S_OK; - } - - return S_FALSE; -} - - -HRESULT CAsyncOutputPin::InitAllocator(IMemAllocator **ppAlloc) -{ - CheckPointer(ppAlloc,E_POINTER); - - HRESULT hr = NOERROR; - CMemAllocator *pMemObject = NULL; - - *ppAlloc = NULL; - - /* Create a default memory allocator */ - pMemObject = new CMemAllocator(NAME("Base memory allocator"), NULL, &hr); - if(pMemObject == NULL) - { - return E_OUTOFMEMORY; - } - if(FAILED(hr)) - { - delete pMemObject; - return hr; - } - - /* Get a reference counted IID_IMemAllocator interface */ - hr = pMemObject->QueryInterface(IID_IMemAllocator,(void **)ppAlloc); - if(FAILED(hr)) - { - delete pMemObject; - return E_NOINTERFACE; - } - - ASSERT(*ppAlloc != NULL); - return NOERROR; -} - - -// we need to return an addrefed allocator, even if it is the preferred -// one, since he doesn't know whether it is the preferred one or not. -STDMETHODIMP -CAsyncOutputPin::RequestAllocator( - IMemAllocator* pPreferred, - ALLOCATOR_PROPERTIES* pProps, - IMemAllocator ** ppActual) -{ - CheckPointer(pPreferred,E_POINTER); - CheckPointer(pProps,E_POINTER); - CheckPointer(ppActual,E_POINTER); - ASSERT(m_pIo); - - // we care about alignment but nothing else - if(!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign)) - { - m_pIo->Alignment(&pProps->cbAlign); - } - - ALLOCATOR_PROPERTIES Actual; - HRESULT hr; - - if(pPreferred) - { - hr = pPreferred->SetProperties(pProps, &Actual); - - if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) - { - pPreferred->AddRef(); - *ppActual = pPreferred; - return S_OK; - } - } - - // create our own allocator - IMemAllocator* pAlloc; - hr = InitAllocator(&pAlloc); - if(FAILED(hr)) - { - return hr; - } - - //...and see if we can make it suitable - hr = pAlloc->SetProperties(pProps, &Actual); - if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) - { - // we need to release our refcount on pAlloc, and addref - // it to pass a refcount to the caller - this is a net nothing. - *ppActual = pAlloc; - return S_OK; - } - - // failed to find a suitable allocator - pAlloc->Release(); - - // if we failed because of the IsAligned test, the error code will - // not be failure - if(SUCCEEDED(hr)) - { - hr = VFW_E_BADALIGN; - } - return hr; -} - - -// queue an aligned read request. call WaitForNext to get -// completion. -STDMETHODIMP CAsyncOutputPin::Request( - IMediaSample* pSample, - DWORD_PTR dwUser) // user context -{ - CheckPointer(pSample,E_POINTER); - - REFERENCE_TIME tStart, tStop; - HRESULT hr = pSample->GetTime(&tStart, &tStop); - if(FAILED(hr)) - { - return hr; - } - - LONGLONG llPos = tStart / UNITS; - LONG lLength = (LONG) ((tStop - tStart) / UNITS); - - LONGLONG llTotal=0, llAvailable=0; - - hr = m_pIo->Length(&llTotal, &llAvailable); - if(llPos + lLength > llTotal) - { - // the end needs to be aligned, but may have been aligned - // on a coarser alignment. - LONG lAlign; - m_pIo->Alignment(&lAlign); - - llTotal = (llTotal + lAlign -1) & ~(lAlign-1); - - if(llPos + lLength > llTotal) - { - lLength = (LONG) (llTotal - llPos); - - // must be reducing this! - ASSERT((llTotal * UNITS) <= tStop); - tStop = llTotal * UNITS; - pSample->SetTime(&tStart, &tStop); - } - } - - BYTE* pBuffer; - hr = pSample->GetPointer(&pBuffer); - if(FAILED(hr)) - { - return hr; - } - - return m_pIo->Request(llPos, - lLength, - TRUE, - pBuffer, - (LPVOID)pSample, - dwUser); -} - - -// sync-aligned request. just like a request/waitfornext pair. -STDMETHODIMP -CAsyncOutputPin::SyncReadAligned( - IMediaSample* pSample) -{ - CheckPointer(pSample,E_POINTER); - - REFERENCE_TIME tStart, tStop; - HRESULT hr = pSample->GetTime(&tStart, &tStop); - if(FAILED(hr)) - { - return hr; - } - - LONGLONG llPos = tStart / UNITS; - LONG lLength = (LONG) ((tStop - tStart) / UNITS); - - LONGLONG llTotal; - LONGLONG llAvailable; - - hr = m_pIo->Length(&llTotal, &llAvailable); - if(llPos + lLength > llTotal) - { - // the end needs to be aligned, but may have been aligned - // on a coarser alignment. - LONG lAlign; - m_pIo->Alignment(&lAlign); - - llTotal = (llTotal + lAlign -1) & ~(lAlign-1); - - if(llPos + lLength > llTotal) - { - lLength = (LONG) (llTotal - llPos); - - // must be reducing this! - ASSERT((llTotal * UNITS) <= tStop); - tStop = llTotal * UNITS; - pSample->SetTime(&tStart, &tStop); - } - } - - BYTE* pBuffer; - hr = pSample->GetPointer(&pBuffer); - if(FAILED(hr)) - { - return hr; - } - - LONG cbActual; - hr = m_pIo->SyncReadAligned(llPos, - lLength, - pBuffer, - &cbActual, - pSample); - - pSample->SetActualDataLength(cbActual); - return hr; -} - - -// -// collect the next ready sample -STDMETHODIMP -CAsyncOutputPin::WaitForNext( - DWORD dwTimeout, - IMediaSample** ppSample, // completed sample - DWORD_PTR * pdwUser) // user context -{ - CheckPointer(ppSample,E_POINTER); - - LONG cbActual; - IMediaSample* pSample=0; - - HRESULT hr = m_pIo->WaitForNext(dwTimeout, - (LPVOID*) &pSample, - pdwUser, - &cbActual); - - if(SUCCEEDED(hr)) - { - pSample->SetActualDataLength(cbActual); - } - - *ppSample = pSample; - return hr; -} - - -// -// synchronous read that need not be aligned. -STDMETHODIMP -CAsyncOutputPin::SyncRead( - LONGLONG llPosition, // absolute Io position - LONG lLength, // nr bytes required - BYTE* pBuffer) // write data here -{ - return m_pIo->SyncRead(llPosition, lLength, pBuffer); -} - - -// return the length of the file, and the length currently -// available locally. We only support locally accessible files, -// so they are always the same -STDMETHODIMP -CAsyncOutputPin::Length( - LONGLONG* pTotal, - LONGLONG* pAvailable) -{ - return m_pIo->Length(pTotal, pAvailable); -} - - -STDMETHODIMP -CAsyncOutputPin::BeginFlush(void) -{ - return m_pIo->BeginFlush(); -} - - -STDMETHODIMP -CAsyncOutputPin::EndFlush(void) -{ - return m_pIo->EndFlush(); -} - - -STDMETHODIMP -CAsyncOutputPin::Connect( - IPin * pReceivePin, - const AM_MEDIA_TYPE *pmt // optional media type -) -{ - return m_pReader->Connect(pReceivePin, pmt); -} - - - -// --- CAsyncReader implementation --- - -#pragma warning(disable:4355) - -CAsyncReader::CAsyncReader( - LPCTSTR pName, - LPUNKNOWN pUnk, - CAsyncStream *pStream, - HRESULT *phr, - const CLSID& clsid) // MPC-HC patch - : CBaseFilter( - pName, - pUnk, - &m_csFilter, - clsid, // MPC-HC patch - NULL - ), - m_Io(pStream), - m_OutputPin( - phr, - this, - &m_Io, - &m_csFilter) - -{ -} - -CAsyncReader::~CAsyncReader() -{ -} - -// MPC-HC patch start -STDMETHODIMP CAsyncReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) -{ - CheckPointer(ppv, E_POINTER); - - return - (riid == __uuidof(IAMFilterMiscFlags)) ? GetInterface((IAMFilterMiscFlags*)this, ppv) : - __super::NonDelegatingQueryInterface(riid, ppv); -} - -// IAMFilterMiscFlags - -ULONG CAsyncReader::GetMiscFlags() -{ - return AM_FILTER_MISC_FLAGS_IS_SOURCE; -} -// MPC-HC patch end - -int CAsyncReader::GetPinCount() -{ - return 1; -} - -CBasePin * CAsyncReader::GetPin(int n) -{ - if((GetPinCount() > 0) && (n == 0)) - { - return &m_OutputPin; - } - else - { - return NULL; - } -} - - - +//------------------------------------------------------------------------------ +// File: AsyncRdr.cpp +// +// Desc: DirectShow sample code - base library with I/O functionality. +// This file implements I/O source filter methods and output pin +// methods for CAsyncReader and CAsyncOutputPin. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "stdafx.h" +#include "BaseClasses/streams.h" +#include "asyncio.h" +#include "asyncrdr.h" + +// --- CAsyncOutputPin implementation --- + +CAsyncOutputPin::CAsyncOutputPin( + HRESULT * phr, + CAsyncReader *pReader, + CAsyncIo *pIo, + CCritSec * pLock) + : CBasePin( + NAME("Async output pin"), + pReader, + pLock, + phr, + L"Output", + PINDIR_OUTPUT), + m_pReader(pReader), + m_pIo(pIo), + m_bQueriedForAsyncReader(FALSE) +{ +} + +CAsyncOutputPin::~CAsyncOutputPin() +{ +} + + +STDMETHODIMP CAsyncOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv,E_POINTER); + + if(riid == IID_IAsyncReader) + { + m_bQueriedForAsyncReader = TRUE; + return GetInterface((IAsyncReader*) this, ppv); + } + else + { + return CBasePin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +HRESULT CAsyncOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType) +{ + if(iPosition < 0) + { + return E_INVALIDARG; + } + if(iPosition > 0) + { + return VFW_S_NO_MORE_ITEMS; + } + + CheckPointer(pMediaType,E_POINTER); + CheckPointer(m_pReader,E_UNEXPECTED); + + *pMediaType = *m_pReader->LoadType(); + + return S_OK; +} + + +HRESULT CAsyncOutputPin::CheckMediaType(const CMediaType* pType) +{ + CAutoLock lck(m_pLock); + + /* We treat MEDIASUBTYPE_NULL subtype as a wild card */ + if((m_pReader->LoadType()->majortype == pType->majortype) && + (m_pReader->LoadType()->subtype == MEDIASUBTYPE_NULL || + m_pReader->LoadType()->subtype == pType->subtype)) + { + return S_OK; + } + + return S_FALSE; +} + + +HRESULT CAsyncOutputPin::InitAllocator(IMemAllocator **ppAlloc) +{ + CheckPointer(ppAlloc,E_POINTER); + + HRESULT hr = NOERROR; + CMemAllocator *pMemObject = NULL; + + *ppAlloc = NULL; + + /* Create a default memory allocator */ + pMemObject = new CMemAllocator(NAME("Base memory allocator"), NULL, &hr); + if(pMemObject == NULL) + { + return E_OUTOFMEMORY; + } + if(FAILED(hr)) + { + delete pMemObject; + return hr; + } + + /* Get a reference counted IID_IMemAllocator interface */ + hr = pMemObject->QueryInterface(IID_IMemAllocator,(void **)ppAlloc); + if(FAILED(hr)) + { + delete pMemObject; + return E_NOINTERFACE; + } + + ASSERT(*ppAlloc != NULL); + return NOERROR; +} + + +// we need to return an addrefed allocator, even if it is the preferred +// one, since he doesn't know whether it is the preferred one or not. +STDMETHODIMP +CAsyncOutputPin::RequestAllocator( + IMemAllocator* pPreferred, + ALLOCATOR_PROPERTIES* pProps, + IMemAllocator ** ppActual) +{ + CheckPointer(pPreferred,E_POINTER); + CheckPointer(pProps,E_POINTER); + CheckPointer(ppActual,E_POINTER); + ASSERT(m_pIo); + + // we care about alignment but nothing else + if(!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign)) + { + m_pIo->Alignment(&pProps->cbAlign); + } + + ALLOCATOR_PROPERTIES Actual; + HRESULT hr; + + if(pPreferred) + { + hr = pPreferred->SetProperties(pProps, &Actual); + + if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) + { + pPreferred->AddRef(); + *ppActual = pPreferred; + return S_OK; + } + } + + // create our own allocator + IMemAllocator* pAlloc; + hr = InitAllocator(&pAlloc); + if(FAILED(hr)) + { + return hr; + } + + //...and see if we can make it suitable + hr = pAlloc->SetProperties(pProps, &Actual); + if(SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) + { + // we need to release our refcount on pAlloc, and addref + // it to pass a refcount to the caller - this is a net nothing. + *ppActual = pAlloc; + return S_OK; + } + + // failed to find a suitable allocator + pAlloc->Release(); + + // if we failed because of the IsAligned test, the error code will + // not be failure + if(SUCCEEDED(hr)) + { + hr = VFW_E_BADALIGN; + } + return hr; +} + + +// queue an aligned read request. call WaitForNext to get +// completion. +STDMETHODIMP CAsyncOutputPin::Request( + IMediaSample* pSample, + DWORD_PTR dwUser) // user context +{ + CheckPointer(pSample,E_POINTER); + + REFERENCE_TIME tStart, tStop; + HRESULT hr = pSample->GetTime(&tStart, &tStop); + if(FAILED(hr)) + { + return hr; + } + + LONGLONG llPos = tStart / UNITS; + LONG lLength = (LONG) ((tStop - tStart) / UNITS); + + LONGLONG llTotal=0, llAvailable=0; + + hr = m_pIo->Length(&llTotal, &llAvailable); + if(llPos + lLength > llTotal) + { + // the end needs to be aligned, but may have been aligned + // on a coarser alignment. + LONG lAlign; + m_pIo->Alignment(&lAlign); + + llTotal = (llTotal + lAlign -1) & ~(lAlign-1); + + if(llPos + lLength > llTotal) + { + lLength = (LONG) (llTotal - llPos); + + // must be reducing this! + ASSERT((llTotal * UNITS) <= tStop); + tStop = llTotal * UNITS; + pSample->SetTime(&tStart, &tStop); + } + } + + BYTE* pBuffer; + hr = pSample->GetPointer(&pBuffer); + if(FAILED(hr)) + { + return hr; + } + + return m_pIo->Request(llPos, + lLength, + TRUE, + pBuffer, + (LPVOID)pSample, + dwUser); +} + + +// sync-aligned request. just like a request/waitfornext pair. +STDMETHODIMP +CAsyncOutputPin::SyncReadAligned( + IMediaSample* pSample) +{ + CheckPointer(pSample,E_POINTER); + + REFERENCE_TIME tStart, tStop; + HRESULT hr = pSample->GetTime(&tStart, &tStop); + if(FAILED(hr)) + { + return hr; + } + + LONGLONG llPos = tStart / UNITS; + LONG lLength = (LONG) ((tStop - tStart) / UNITS); + + LONGLONG llTotal; + LONGLONG llAvailable; + + hr = m_pIo->Length(&llTotal, &llAvailable); + if(llPos + lLength > llTotal) + { + // the end needs to be aligned, but may have been aligned + // on a coarser alignment. + LONG lAlign; + m_pIo->Alignment(&lAlign); + + llTotal = (llTotal + lAlign -1) & ~(lAlign-1); + + if(llPos + lLength > llTotal) + { + lLength = (LONG) (llTotal - llPos); + + // must be reducing this! + ASSERT((llTotal * UNITS) <= tStop); + tStop = llTotal * UNITS; + pSample->SetTime(&tStart, &tStop); + } + } + + BYTE* pBuffer; + hr = pSample->GetPointer(&pBuffer); + if(FAILED(hr)) + { + return hr; + } + + LONG cbActual; + hr = m_pIo->SyncReadAligned(llPos, + lLength, + pBuffer, + &cbActual, + pSample); + + pSample->SetActualDataLength(cbActual); + return hr; +} + + +// +// collect the next ready sample +STDMETHODIMP +CAsyncOutputPin::WaitForNext( + DWORD dwTimeout, + IMediaSample** ppSample, // completed sample + DWORD_PTR * pdwUser) // user context +{ + CheckPointer(ppSample,E_POINTER); + + LONG cbActual; + IMediaSample* pSample=0; + + HRESULT hr = m_pIo->WaitForNext(dwTimeout, + (LPVOID*) &pSample, + pdwUser, + &cbActual); + + if(SUCCEEDED(hr)) + { + pSample->SetActualDataLength(cbActual); + } + + *ppSample = pSample; + return hr; +} + + +// +// synchronous read that need not be aligned. +STDMETHODIMP +CAsyncOutputPin::SyncRead( + LONGLONG llPosition, // absolute Io position + LONG lLength, // nr bytes required + BYTE* pBuffer) // write data here +{ + return m_pIo->SyncRead(llPosition, lLength, pBuffer); +} + + +// return the length of the file, and the length currently +// available locally. We only support locally accessible files, +// so they are always the same +STDMETHODIMP +CAsyncOutputPin::Length( + LONGLONG* pTotal, + LONGLONG* pAvailable) +{ + return m_pIo->Length(pTotal, pAvailable); +} + + +STDMETHODIMP +CAsyncOutputPin::BeginFlush(void) +{ + return m_pIo->BeginFlush(); +} + + +STDMETHODIMP +CAsyncOutputPin::EndFlush(void) +{ + return m_pIo->EndFlush(); +} + + +STDMETHODIMP +CAsyncOutputPin::Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type +) +{ + return m_pReader->Connect(pReceivePin, pmt); +} + + + +// --- CAsyncReader implementation --- + +#pragma warning(disable:4355) + +CAsyncReader::CAsyncReader( + LPCTSTR pName, + LPUNKNOWN pUnk, + CAsyncStream *pStream, + HRESULT *phr, + const CLSID& clsid) // MPC-HC patch + : CBaseFilter( + pName, + pUnk, + &m_csFilter, + clsid, // MPC-HC patch + NULL + ), + m_Io(pStream), + m_OutputPin( + phr, + this, + &m_Io, + &m_csFilter) + +{ +} + +CAsyncReader::~CAsyncReader() +{ +} + +// MPC-HC patch start +STDMETHODIMP CAsyncReader::NonDelegatingQueryInterface(REFIID riid, void** ppv) +{ + CheckPointer(ppv, E_POINTER); + + return + (riid == __uuidof(IAMFilterMiscFlags)) ? GetInterface((IAMFilterMiscFlags*)this, ppv) : + __super::NonDelegatingQueryInterface(riid, ppv); +} + +// IAMFilterMiscFlags + +ULONG CAsyncReader::GetMiscFlags() +{ + return AM_FILTER_MISC_FLAGS_IS_SOURCE; +} +// MPC-HC patch end + +int CAsyncReader::GetPinCount() +{ + return 1; +} + +CBasePin * CAsyncReader::GetPin(int n) +{ + if((GetPinCount() > 0) && (n == 0)) + { + return &m_OutputPin; + } + else + { + return NULL; + } +} + + + diff --git a/src/thirdparty/AsyncReader/asyncrdr.h b/src/thirdparty/AsyncReader/asyncrdr.h index e4a6ea6505c..33f447ef660 100644 --- a/src/thirdparty/AsyncReader/asyncrdr.h +++ b/src/thirdparty/AsyncReader/asyncrdr.h @@ -1,236 +1,236 @@ -//------------------------------------------------------------------------------ -// File: AsyncRdr.h -// -// Desc: DirectShow sample code - base library for I/O functionality. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __ASYNCRDR_H__ -#define __ASYNCRDR_H__ - - -// -// AsyncRdr -// -// Defines an IO source filter. -// -// This filter (CAsyncReader) supports IBaseFilter and IFileSourceFilter interfaces from the -// filter object itself. It has a single output pin (CAsyncOutputPin) -// which supports IPin and IAsyncReader. -// -// This filter is essentially a wrapper for the CAsyncFile class that does -// all the work. -// - - -// the filter class (defined below) -class CAsyncReader; - - -// the output pin class -class CAsyncOutputPin - : public IAsyncReader, - public CBasePin -{ -protected: - CAsyncReader* m_pReader; - CAsyncIo * m_pIo; - - // This is set every time we're asked to return an IAsyncReader - // interface - // This allows us to know if the downstream pin can use - // this transport, otherwise we can hook up to thinks like the - // dump filter and nothing happens - BOOL m_bQueriedForAsyncReader; - - HRESULT InitAllocator(IMemAllocator **ppAlloc); - -public: - // constructor and destructor - CAsyncOutputPin( - HRESULT * phr, - CAsyncReader *pReader, - CAsyncIo *pIo, - CCritSec * pLock); - - ~CAsyncOutputPin(); - - // --- CUnknown --- - - // need to expose IAsyncReader - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID, void**); - - // --- IPin methods --- - STDMETHODIMP Connect( - IPin * pReceivePin, - const AM_MEDIA_TYPE *pmt // optional media type - ); - - // --- CBasePin methods --- - - // return the types we prefer - this will return the known - // file type - HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); - - // can we support this type? - HRESULT CheckMediaType(const CMediaType* pType); - - // Clear the flag so we see if IAsyncReader is queried for - HRESULT CheckConnect(IPin *pPin) - { - m_bQueriedForAsyncReader = FALSE; - return CBasePin::CheckConnect(pPin); - } - - // See if it was asked for - HRESULT CompleteConnect(IPin *pReceivePin) - { - if (m_bQueriedForAsyncReader) { - return CBasePin::CompleteConnect(pReceivePin); - } else { - -#ifdef VFW_E_NO_TRANSPORT - return VFW_E_NO_TRANSPORT; -#else - return E_FAIL; -#endif - } - } - - // Remove our connection status - HRESULT BreakConnect() - { - m_bQueriedForAsyncReader = FALSE; - return CBasePin::BreakConnect(); - } - - // --- IAsyncReader methods --- - // pass in your preferred allocator and your preferred properties. - // method returns the actual allocator to be used. Call GetProperties - // on returned allocator to learn alignment and prefix etc chosen. - // this allocator will be not be committed and decommitted by - // the async reader, only by the consumer. - STDMETHODIMP RequestAllocator( - IMemAllocator* pPreferred, - ALLOCATOR_PROPERTIES* pProps, - IMemAllocator ** ppActual); - - // queue a request for data. - // media sample start and stop times contain the requested absolute - // byte position (start inclusive, stop exclusive). - // may fail if sample not obtained from agreed allocator. - // may fail if start/stop position does not match agreed alignment. - // samples allocated from source pin's allocator may fail - // GetPointer until after returning from WaitForNext. - STDMETHODIMP Request( - IMediaSample* pSample, - DWORD_PTR dwUser); // user context - - // block until the next sample is completed or the timeout occurs. - // timeout (millisecs) may be 0 or INFINITE. Samples may not - // be delivered in order. If there is a read error of any sort, a - // notification will already have been sent by the source filter, - // and STDMETHODIMP will be an error. - STDMETHODIMP WaitForNext( - DWORD dwTimeout, - IMediaSample** ppSample, // completed sample - DWORD_PTR * pdwUser); // user context - - // sync read of data. Sample passed in must have been acquired from - // the agreed allocator. Start and stop position must be aligned. - // equivalent to a Request/WaitForNext pair, but may avoid the - // need for a thread on the source filter. - STDMETHODIMP SyncReadAligned( - IMediaSample* pSample); - - - // sync read. works in stopped state as well as run state. - // need not be aligned. Will fail if read is beyond actual total - // length. - STDMETHODIMP SyncRead( - LONGLONG llPosition, // absolute file position - LONG lLength, // nr bytes required - BYTE* pBuffer); // write data here - - // return total length of stream, and currently available length. - // reads for beyond the available length but within the total length will - // normally succeed but may block for a long period. - STDMETHODIMP Length( - LONGLONG* pTotal, - LONGLONG* pAvailable); - - // cause all outstanding reads to return, possibly with a failure code - // (VFW_E_TIMEOUT) indicating they were cancelled. - // these are defined on IAsyncReader and IPin - STDMETHODIMP BeginFlush(void); - STDMETHODIMP EndFlush(void); - -}; - - -// -// The filter object itself. Supports IBaseFilter through -// CBaseFilter and also IFileSourceFilter directly in this object - -class CAsyncReader : public CBaseFilter, public IAMFilterMiscFlags -{ - -protected: - // filter-wide lock - CCritSec m_csFilter; - - // all i/o done here - CAsyncIo m_Io; - - // our output pin - CAsyncOutputPin m_OutputPin; - - // Type we think our data is - CMediaType m_mt; - -public: - - // construction / destruction - - CAsyncReader( - LPCTSTR pName, - LPUNKNOWN pUnk, - CAsyncStream *pStream, - HRESULT *phr, - const CLSID& clsid); // MPC-HC patch - - ~CAsyncReader(); - -// MPC-HC patch start - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); - - // IAMFilterMiscFlags - STDMETHODIMP_(ULONG) GetMiscFlags(); -// MPC-HC patch end - - // --- CBaseFilter methods --- - int GetPinCount(); - CBasePin *GetPin(int n); - - // --- Access our media type - const CMediaType *LoadType() const - { - return &m_mt; - } - - virtual HRESULT Connect( - IPin * pReceivePin, - const AM_MEDIA_TYPE *pmt // optional media type - ) - { - return m_OutputPin.CBasePin::Connect(pReceivePin, pmt); - } -}; - - - -#endif //__ASYNCRDR_H__ +//------------------------------------------------------------------------------ +// File: AsyncRdr.h +// +// Desc: DirectShow sample code - base library for I/O functionality. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __ASYNCRDR_H__ +#define __ASYNCRDR_H__ + + +// +// AsyncRdr +// +// Defines an IO source filter. +// +// This filter (CAsyncReader) supports IBaseFilter and IFileSourceFilter interfaces from the +// filter object itself. It has a single output pin (CAsyncOutputPin) +// which supports IPin and IAsyncReader. +// +// This filter is essentially a wrapper for the CAsyncFile class that does +// all the work. +// + + +// the filter class (defined below) +class CAsyncReader; + + +// the output pin class +class CAsyncOutputPin + : public IAsyncReader, + public CBasePin +{ +protected: + CAsyncReader* m_pReader; + CAsyncIo * m_pIo; + + // This is set every time we're asked to return an IAsyncReader + // interface + // This allows us to know if the downstream pin can use + // this transport, otherwise we can hook up to thinks like the + // dump filter and nothing happens + BOOL m_bQueriedForAsyncReader; + + HRESULT InitAllocator(IMemAllocator **ppAlloc); + +public: + // constructor and destructor + CAsyncOutputPin( + HRESULT * phr, + CAsyncReader *pReader, + CAsyncIo *pIo, + CCritSec * pLock); + + ~CAsyncOutputPin(); + + // --- CUnknown --- + + // need to expose IAsyncReader + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID, void**); + + // --- IPin methods --- + STDMETHODIMP Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type + ); + + // --- CBasePin methods --- + + // return the types we prefer - this will return the known + // file type + HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); + + // can we support this type? + HRESULT CheckMediaType(const CMediaType* pType); + + // Clear the flag so we see if IAsyncReader is queried for + HRESULT CheckConnect(IPin *pPin) + { + m_bQueriedForAsyncReader = FALSE; + return CBasePin::CheckConnect(pPin); + } + + // See if it was asked for + HRESULT CompleteConnect(IPin *pReceivePin) + { + if (m_bQueriedForAsyncReader) { + return CBasePin::CompleteConnect(pReceivePin); + } else { + +#ifdef VFW_E_NO_TRANSPORT + return VFW_E_NO_TRANSPORT; +#else + return E_FAIL; +#endif + } + } + + // Remove our connection status + HRESULT BreakConnect() + { + m_bQueriedForAsyncReader = FALSE; + return CBasePin::BreakConnect(); + } + + // --- IAsyncReader methods --- + // pass in your preferred allocator and your preferred properties. + // method returns the actual allocator to be used. Call GetProperties + // on returned allocator to learn alignment and prefix etc chosen. + // this allocator will be not be committed and decommitted by + // the async reader, only by the consumer. + STDMETHODIMP RequestAllocator( + IMemAllocator* pPreferred, + ALLOCATOR_PROPERTIES* pProps, + IMemAllocator ** ppActual); + + // queue a request for data. + // media sample start and stop times contain the requested absolute + // byte position (start inclusive, stop exclusive). + // may fail if sample not obtained from agreed allocator. + // may fail if start/stop position does not match agreed alignment. + // samples allocated from source pin's allocator may fail + // GetPointer until after returning from WaitForNext. + STDMETHODIMP Request( + IMediaSample* pSample, + DWORD_PTR dwUser); // user context + + // block until the next sample is completed or the timeout occurs. + // timeout (millisecs) may be 0 or INFINITE. Samples may not + // be delivered in order. If there is a read error of any sort, a + // notification will already have been sent by the source filter, + // and STDMETHODIMP will be an error. + STDMETHODIMP WaitForNext( + DWORD dwTimeout, + IMediaSample** ppSample, // completed sample + DWORD_PTR * pdwUser); // user context + + // sync read of data. Sample passed in must have been acquired from + // the agreed allocator. Start and stop position must be aligned. + // equivalent to a Request/WaitForNext pair, but may avoid the + // need for a thread on the source filter. + STDMETHODIMP SyncReadAligned( + IMediaSample* pSample); + + + // sync read. works in stopped state as well as run state. + // need not be aligned. Will fail if read is beyond actual total + // length. + STDMETHODIMP SyncRead( + LONGLONG llPosition, // absolute file position + LONG lLength, // nr bytes required + BYTE* pBuffer); // write data here + + // return total length of stream, and currently available length. + // reads for beyond the available length but within the total length will + // normally succeed but may block for a long period. + STDMETHODIMP Length( + LONGLONG* pTotal, + LONGLONG* pAvailable); + + // cause all outstanding reads to return, possibly with a failure code + // (VFW_E_TIMEOUT) indicating they were cancelled. + // these are defined on IAsyncReader and IPin + STDMETHODIMP BeginFlush(void); + STDMETHODIMP EndFlush(void); + +}; + + +// +// The filter object itself. Supports IBaseFilter through +// CBaseFilter and also IFileSourceFilter directly in this object + +class CAsyncReader : public CBaseFilter, public IAMFilterMiscFlags +{ + +protected: + // filter-wide lock + CCritSec m_csFilter; + + // all i/o done here + CAsyncIo m_Io; + + // our output pin + CAsyncOutputPin m_OutputPin; + + // Type we think our data is + CMediaType m_mt; + +public: + + // construction / destruction + + CAsyncReader( + LPCTSTR pName, + LPUNKNOWN pUnk, + CAsyncStream *pStream, + HRESULT *phr, + const CLSID& clsid); // MPC-HC patch + + ~CAsyncReader(); + +// MPC-HC patch start + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); + + // IAMFilterMiscFlags + STDMETHODIMP_(ULONG) GetMiscFlags(); +// MPC-HC patch end + + // --- CBaseFilter methods --- + int GetPinCount(); + CBasePin *GetPin(int n); + + // --- Access our media type + const CMediaType *LoadType() const + { + return &m_mt; + } + + virtual HRESULT Connect( + IPin * pReceivePin, + const AM_MEDIA_TYPE *pmt // optional media type + ) + { + return m_OutputPin.CBasePin::Connect(pReceivePin, pmt); + } +}; + + + +#endif //__ASYNCRDR_H__ diff --git a/src/thirdparty/AsyncReader/stdafx.cpp b/src/thirdparty/AsyncReader/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/thirdparty/AsyncReader/stdafx.cpp +++ b/src/thirdparty/AsyncReader/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/thirdparty/AsyncReader/stdafx.h b/src/thirdparty/AsyncReader/stdafx.h index bf1cd08b021..eff1a53f6f4 100644 --- a/src/thirdparty/AsyncReader/stdafx.h +++ b/src/thirdparty/AsyncReader/stdafx.h @@ -1,28 +1,28 @@ -/* - * (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 . - * - */ - -#pragma once - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif - -#include "BaseClasses/streams.h" +/* + * (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 . + * + */ + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif + +#include "BaseClasses/streams.h" diff --git a/src/thirdparty/BaseClasses/BaseClasses.vcxproj b/src/thirdparty/BaseClasses/BaseClasses.vcxproj index 91160f6e31b..08b173e6574 100644 --- a/src/thirdparty/BaseClasses/BaseClasses.vcxproj +++ b/src/thirdparty/BaseClasses/BaseClasses.vcxproj @@ -1,130 +1,130 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA} - BaseClasses - Win32Proj - BaseClasses - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - streams.h - - - strmiids.lib;Winmm.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {E8A3F6FA-AE1C-4C8E-A0B6-9C8480324EAA} + BaseClasses + Win32Proj + BaseClasses + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + streams.h + + + strmiids.lib;Winmm.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/BaseClasses/BaseClasses.vcxproj.filters b/src/thirdparty/BaseClasses/BaseClasses.vcxproj.filters index de39b30833c..604be071873 100644 --- a/src/thirdparty/BaseClasses/BaseClasses.vcxproj.filters +++ b/src/thirdparty/BaseClasses/BaseClasses.vcxproj.filters @@ -1,224 +1,224 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/src/thirdparty/BaseClasses/amextra.cpp b/src/thirdparty/BaseClasses/amextra.cpp index 518f9859a9a..582451bc9b6 100644 --- a/src/thirdparty/BaseClasses/amextra.cpp +++ b/src/thirdparty/BaseClasses/amextra.cpp @@ -1,111 +1,111 @@ -//------------------------------------------------------------------------------ -// File: AMExtra.cpp -// -// Desc: DirectShow base classes - implements CRenderedInputPin class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" // DirectShow base class definitions -#include // Needed for definition of timeGetTime -#include // Standard data type limit definitions -#include "measure.h" // Used for time critical log functions - -#include "amextra.h" - -#pragma warning(disable:4355) - -// Implements CRenderedInputPin class - -CRenderedInputPin::CRenderedInputPin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), - m_bAtEndOfStream(FALSE), - m_bCompleteNotified(FALSE) -{ -} -#ifdef UNICODE -CRenderedInputPin::CRenderedInputPin(__in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), - m_bAtEndOfStream(FALSE), - m_bCompleteNotified(FALSE) -{ -} -#endif - -// Flush end of stream condition - caller should do any -// necessary stream level locking before calling this - -STDMETHODIMP CRenderedInputPin::EndOfStream() -{ - HRESULT hr = CheckStreaming(); - - // Do EC_COMPLETE handling for rendered pins - if (S_OK == hr && !m_bAtEndOfStream) { - m_bAtEndOfStream = TRUE; - FILTER_STATE fs; - EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs))); - if (fs == State_Running) { - DoCompleteHandling(); - } - } - return hr; -} - - -// Called to complete the flush - -STDMETHODIMP CRenderedInputPin::EndFlush() -{ - CAutoLock lck(m_pLock); - - // Clean up renderer state - m_bAtEndOfStream = FALSE; - m_bCompleteNotified = FALSE; - - return CBaseInputPin::EndFlush(); -} - - -// Notify of Run() from filter - -HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart) -{ - UNREFERENCED_PARAMETER(tStart); - m_bCompleteNotified = FALSE; - if (m_bAtEndOfStream) { - DoCompleteHandling(); - } - return S_OK; -} - - -// Clear status on going into paused state - -HRESULT CRenderedInputPin::Active() -{ - m_bAtEndOfStream = FALSE; - m_bCompleteNotified = FALSE; - return CBaseInputPin::Active(); -} - - -// Do stuff to deliver end of stream - -void CRenderedInputPin::DoCompleteHandling() -{ - ASSERT(m_bAtEndOfStream); - if (!m_bCompleteNotified) { - m_bCompleteNotified = TRUE; - m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter); - } -} - +//------------------------------------------------------------------------------ +// File: AMExtra.cpp +// +// Desc: DirectShow base classes - implements CRenderedInputPin class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" // DirectShow base class definitions +#include // Needed for definition of timeGetTime +#include // Standard data type limit definitions +#include "measure.h" // Used for time critical log functions + +#include "amextra.h" + +#pragma warning(disable:4355) + +// Implements CRenderedInputPin class + +CRenderedInputPin::CRenderedInputPin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), + m_bAtEndOfStream(FALSE), + m_bCompleteNotified(FALSE) +{ +} +#ifdef UNICODE +CRenderedInputPin::CRenderedInputPin(__in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBaseInputPin(pObjectName, pFilter, pLock, phr, pName), + m_bAtEndOfStream(FALSE), + m_bCompleteNotified(FALSE) +{ +} +#endif + +// Flush end of stream condition - caller should do any +// necessary stream level locking before calling this + +STDMETHODIMP CRenderedInputPin::EndOfStream() +{ + HRESULT hr = CheckStreaming(); + + // Do EC_COMPLETE handling for rendered pins + if (S_OK == hr && !m_bAtEndOfStream) { + m_bAtEndOfStream = TRUE; + FILTER_STATE fs; + EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs))); + if (fs == State_Running) { + DoCompleteHandling(); + } + } + return hr; +} + + +// Called to complete the flush + +STDMETHODIMP CRenderedInputPin::EndFlush() +{ + CAutoLock lck(m_pLock); + + // Clean up renderer state + m_bAtEndOfStream = FALSE; + m_bCompleteNotified = FALSE; + + return CBaseInputPin::EndFlush(); +} + + +// Notify of Run() from filter + +HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart) +{ + UNREFERENCED_PARAMETER(tStart); + m_bCompleteNotified = FALSE; + if (m_bAtEndOfStream) { + DoCompleteHandling(); + } + return S_OK; +} + + +// Clear status on going into paused state + +HRESULT CRenderedInputPin::Active() +{ + m_bAtEndOfStream = FALSE; + m_bCompleteNotified = FALSE; + return CBaseInputPin::Active(); +} + + +// Do stuff to deliver end of stream + +void CRenderedInputPin::DoCompleteHandling() +{ + ASSERT(m_bAtEndOfStream); + if (!m_bCompleteNotified) { + m_bCompleteNotified = TRUE; + m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter); + } +} + diff --git a/src/thirdparty/BaseClasses/amextra.h b/src/thirdparty/BaseClasses/amextra.h index 3caf64ce9f9..5a861bf12a2 100644 --- a/src/thirdparty/BaseClasses/amextra.h +++ b/src/thirdparty/BaseClasses/amextra.h @@ -1,56 +1,56 @@ -//------------------------------------------------------------------------------ -// File: AMExtra.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __AMEXTRA__ -#define __AMEXTRA__ - -// Simple rendered input pin -// -// NOTE if your filter queues stuff before rendering then it may not be -// appropriate to use this class -// -// In that case queue the end of stream condition until the last sample -// is actually rendered and flush the condition appropriately - -class CRenderedInputPin : public CBaseInputPin -{ -public: - - CRenderedInputPin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CRenderedInputPin(__in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#endif - - // Override methods to track end of stream state - STDMETHODIMP EndOfStream(); - STDMETHODIMP EndFlush(); - - HRESULT Active(); - HRESULT Run(REFERENCE_TIME tStart); - -protected: - - // Member variables to track state - BOOL m_bAtEndOfStream; // Set by EndOfStream - BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE - -private: - void DoCompleteHandling(); -}; - -#endif // __AMEXTRA__ - +//------------------------------------------------------------------------------ +// File: AMExtra.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __AMEXTRA__ +#define __AMEXTRA__ + +// Simple rendered input pin +// +// NOTE if your filter queues stuff before rendering then it may not be +// appropriate to use this class +// +// In that case queue the end of stream condition until the last sample +// is actually rendered and flush the condition appropriately + +class CRenderedInputPin : public CBaseInputPin +{ +public: + + CRenderedInputPin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CRenderedInputPin(__in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#endif + + // Override methods to track end of stream state + STDMETHODIMP EndOfStream(); + STDMETHODIMP EndFlush(); + + HRESULT Active(); + HRESULT Run(REFERENCE_TIME tStart); + +protected: + + // Member variables to track state + BOOL m_bAtEndOfStream; // Set by EndOfStream + BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE + +private: + void DoCompleteHandling(); +}; + +#endif // __AMEXTRA__ + diff --git a/src/thirdparty/BaseClasses/amfilter.cpp b/src/thirdparty/BaseClasses/amfilter.cpp index 835d36fd5ce..175f04c2520 100644 --- a/src/thirdparty/BaseClasses/amfilter.cpp +++ b/src/thirdparty/BaseClasses/amfilter.cpp @@ -1,5373 +1,5373 @@ -//------------------------------------------------------------------------------ -// File: AMFilter.cpp -// -// Desc: DirectShow base classes - implements class hierarchy for streams -// architecture. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -//===================================================================== -//===================================================================== -// The following classes are declared in this header: -// -// -// CBaseMediaFilter Basic IMediaFilter support (abstract class) -// CBaseFilter Support for IBaseFilter (incl. IMediaFilter) -// CEnumPins Enumerate input and output pins -// CEnumMediaTypes Enumerate the preferred pin formats -// CBasePin Abstract base class for IPin interface -// CBaseOutputPin Adds data provider member functions -// CBaseInputPin Implements IMemInputPin interface -// CMediaSample Basic transport unit for IMemInputPin -// CBaseAllocator General list guff for most allocators -// CMemAllocator Implements memory buffer allocation -// -//===================================================================== -//===================================================================== - -#include "streams.h" -#include - -#ifdef DXMPERF -#include "dxmperf.h" -#endif // DXMPERF - - -//===================================================================== -// Helpers -//===================================================================== -STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator) -{ - return CoCreateInstance(CLSID_MemoryAllocator, - 0, - CLSCTX_INPROC_SERVER, - IID_IMemAllocator, - (void **)ppAllocator); -} - -// Put this one here rather than in ctlutil.cpp to avoid linking -// anything brought in by ctlutil.cpp -STDAPI CreatePosPassThru( - __in_opt LPUNKNOWN pAgg, - BOOL bRenderer, - IPin *pPin, - __deref_out IUnknown **ppPassThru -) -{ - *ppPassThru = NULL; - IUnknown *pUnkSeek; - HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru, - pAgg, - CLSCTX_INPROC_SERVER, - IID_IUnknown, - (void **)&pUnkSeek - ); - if (FAILED(hr)) { - return hr; - } - - ISeekingPassThru *pPassThru; - hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru); - if (FAILED(hr)) { - pUnkSeek->Release(); - return hr; - } - hr = pPassThru->Init(bRenderer, pPin); - pPassThru->Release(); - if (FAILED(hr)) { - pUnkSeek->Release(); - return hr; - } - *ppPassThru = pUnkSeek; - return S_OK; -} - - - -#define CONNECT_TRACE_LEVEL 3 - -//===================================================================== -//===================================================================== -// Implements CBaseMediaFilter -//===================================================================== -//===================================================================== - - -/* Constructor */ - -CBaseMediaFilter::CBaseMediaFilter(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid) : - CUnknown(pName, pUnk), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL) -{ -} - - -/* Destructor */ - -CBaseMediaFilter::~CBaseMediaFilter() -{ - // must be stopped, but can't call Stop here since - // our critsec has been destroyed. - - /* Release any clock we were using */ - - if (m_pClock) { - m_pClock->Release(); - m_pClock = NULL; - } -} - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP -CBaseMediaFilter::NonDelegatingQueryInterface( - REFIID riid, - __deref_out void ** ppv) -{ - if (riid == IID_IMediaFilter) { - return GetInterface((IMediaFilter *) this, ppv); - } else if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - -/* Return the filter's clsid */ -STDMETHODIMP -CBaseMediaFilter::GetClassID(__out CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = m_clsid; - return NOERROR; -} - -/* Override this if your state changes are not done synchronously */ - -STDMETHODIMP -CBaseMediaFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State) -{ - UNREFERENCED_PARAMETER(dwMSecs); - CheckPointer(State,E_POINTER); - ValidateReadWritePtr(State,sizeof(FILTER_STATE)); - - *State = m_State; - return S_OK; -} - - -/* Set the clock we will use for synchronisation */ - -STDMETHODIMP -CBaseMediaFilter::SetSyncSource(__inout_opt IReferenceClock *pClock) -{ - CAutoLock cObjectLock(m_pLock); - - // Ensure the new one does not go away - even if the same as the old - if (pClock) { - pClock->AddRef(); - } - - // if we have a clock, release it - if (m_pClock) { - m_pClock->Release(); - } - - // Set the new reference clock (might be NULL) - // Should we query it to ensure it is a clock? Consider for a debug build. - m_pClock = pClock; - - return NOERROR; -} - -/* Return the clock we are using for synchronisation */ -STDMETHODIMP -CBaseMediaFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock) -{ - CheckPointer(pClock,E_POINTER); - ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pClock) { - // returning an interface... addref it... - m_pClock->AddRef(); - } - *pClock = (IReferenceClock*)m_pClock; - return NOERROR; -} - - -/* Put the filter into a stopped state */ - -STDMETHODIMP -CBaseMediaFilter::Stop() -{ - CAutoLock cObjectLock(m_pLock); - - m_State = State_Stopped; - return S_OK; -} - - -/* Put the filter into a paused state */ - -STDMETHODIMP -CBaseMediaFilter::Pause() -{ - CAutoLock cObjectLock(m_pLock); - - m_State = State_Paused; - return S_OK; -} - - -// Put the filter into a running state. - -// The time parameter is the offset to be added to the samples' -// stream time to get the reference time at which they should be presented. -// -// you can either add these two and compare it against the reference clock, -// or you can call CBaseMediaFilter::StreamTime and compare that against -// the sample timestamp. - -STDMETHODIMP -CBaseMediaFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cObjectLock(m_pLock); - - // remember the stream time offset - m_tStart = tStart; - - if (m_State == State_Stopped){ - HRESULT hr = Pause(); - - if (FAILED(hr)) { - return hr; - } - } - m_State = State_Running; - return S_OK; -} - - -// -// return the current stream time - samples with start timestamps of this -// time or before should be rendered by now -HRESULT -CBaseMediaFilter::StreamTime(CRefTime& rtStream) -{ - // Caller must lock for synchronization - // We can't grab the filter lock because we want to be able to call - // this from worker threads without deadlocking - - if (m_pClock == NULL) { - return VFW_E_NO_CLOCK; - } - - // get the current reference time - HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); - if (FAILED(hr)) { - return hr; - } - - // subtract the stream offset to get stream time - rtStream -= m_tStart; - - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CBaseFilter -//===================================================================== -//===================================================================== - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid, - __deref_out void **ppv) -{ - /* Do we have this interface */ - - if (riid == IID_IBaseFilter) { - return GetInterface((IBaseFilter *) this, ppv); - } else if (riid == IID_IMediaFilter) { - return GetInterface((IMediaFilter *) this, ppv); - } else if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); - } else if (riid == IID_IAMovieSetup) { - return GetInterface((IAMovieSetup *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - -#ifdef _DEBUG -STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease() -{ - if (m_cRef == 1) { - KASSERT(m_pGraph == NULL); - } - return CUnknown::NonDelegatingRelease(); -} -#endif - - -/* Constructor */ - -CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - ASSERT(pLock != NULL); -} - -/* Passes in a redundant HRESULT argument */ - -CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid, - __inout HRESULT *phr) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - ASSERT(pLock != NULL); - UNREFERENCED_PARAMETER(phr); -} - -#ifdef UNICODE -CBaseFilter::CBaseFilter(__in_opt LPCSTR pName, - __in_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - ASSERT(pLock != NULL); -} -CBaseFilter::CBaseFilter(__in_opt LPCSTR pName, - __in_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid, - __inout HRESULT *phr) : - CUnknown( pName, pUnk ), - m_pLock(pLock), - m_clsid(clsid), - m_State(State_Stopped), - m_pClock(NULL), - m_pGraph(NULL), - m_pSink(NULL), - m_pName(NULL), - m_PinVersion(1) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - ASSERT(pLock != NULL); - UNREFERENCED_PARAMETER(phr); -} -#endif - -/* Destructor */ - -CBaseFilter::~CBaseFilter() -{ -#ifdef DXMPERF - PERFLOG_DTOR( L"CBaseFilter", (IBaseFilter *) this ); -#endif // DXMPERF - - // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink - // When we did we had the circular reference problem. Nothing would go away. - - delete[] m_pName; - - // must be stopped, but can't call Stop here since - // our critsec has been destroyed. - - /* Release any clock we were using */ - if (m_pClock) { - m_pClock->Release(); - m_pClock = NULL; - } -} - -/* Return the filter's clsid */ -STDMETHODIMP -CBaseFilter::GetClassID(__out CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = m_clsid; - return NOERROR; -} - -/* Override this if your state changes are not done synchronously */ -STDMETHODIMP -CBaseFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State) -{ - UNREFERENCED_PARAMETER(dwMSecs); - CheckPointer(State,E_POINTER); - ValidateReadWritePtr(State,sizeof(FILTER_STATE)); - - *State = m_State; - return S_OK; -} - - -/* Set the clock we will use for synchronisation */ - -STDMETHODIMP -CBaseFilter::SetSyncSource(__in_opt IReferenceClock *pClock) -{ - CAutoLock cObjectLock(m_pLock); - - // Ensure the new one does not go away - even if the same as the old - if (pClock) { - pClock->AddRef(); - } - - // if we have a clock, release it - if (m_pClock) { - m_pClock->Release(); - } - - // Set the new reference clock (might be NULL) - // Should we query it to ensure it is a clock? Consider for a debug build. - m_pClock = pClock; - - return NOERROR; -} - -/* Return the clock we are using for synchronisation */ -STDMETHODIMP -CBaseFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock) -{ - CheckPointer(pClock,E_POINTER); - ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pClock) { - // returning an interface... addref it... - m_pClock->AddRef(); - } - *pClock = (IReferenceClock*)m_pClock; - return NOERROR; -} - - - -// override CBaseMediaFilter Stop method, to deactivate any pins this -// filter has. -STDMETHODIMP -CBaseFilter::Stop() -{ - CAutoLock cObjectLock(m_pLock); - HRESULT hr = NOERROR; - - // notify all pins of the state change - if (m_State != State_Stopped) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - if (NULL == pPin) { - break; - } - - // Disconnected pins are not activated - this saves pins worrying - // about this state themselves. We ignore the return code to make - // sure everyone is inactivated regardless. The base input pin - // class can return an error if it has no allocator but Stop can - // be used to resync the graph state after something has gone bad - - if (pPin->IsConnected()) { - HRESULT hrTmp = pPin->Inactive(); - if (FAILED(hrTmp) && SUCCEEDED(hr)) { - hr = hrTmp; - } - } - } - } - -#ifdef DXMPERF - PERFLOG_STOP( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State ); -#endif // DXMPERF - - m_State = State_Stopped; - return hr; -} - - -// override CBaseMediaFilter Pause method to activate any pins -// this filter has (also called from Run) - -STDMETHODIMP -CBaseFilter::Pause() -{ - CAutoLock cObjectLock(m_pLock); - - // notify all pins of the change to active state - if (m_State == State_Stopped) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - if (NULL == pPin) { - break; - } - - // Disconnected pins are not activated - this saves pins - // worrying about this state themselves - - if (pPin->IsConnected()) { - HRESULT hr = pPin->Active(); - if (FAILED(hr)) { - return hr; - } - } - } - } - - -#ifdef DXMPERF - PERFLOG_PAUSE( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State ); -#endif // DXMPERF - - m_State = State_Paused; - return S_OK; -} - -// Put the filter into a running state. - -// The time parameter is the offset to be added to the samples' -// stream time to get the reference time at which they should be presented. -// -// you can either add these two and compare it against the reference clock, -// or you can call CBaseFilter::StreamTime and compare that against -// the sample timestamp. - -STDMETHODIMP -CBaseFilter::Run(REFERENCE_TIME tStart) -{ - CAutoLock cObjectLock(m_pLock); - - // remember the stream time offset - m_tStart = tStart; - - if (m_State == State_Stopped){ - HRESULT hr = Pause(); - - if (FAILED(hr)) { - return hr; - } - } - // notify all pins of the change to active state - if (m_State != State_Running) { - int cPins = GetPinCount(); - for (int c = 0; c < cPins; c++) { - - CBasePin *pPin = GetPin(c); - if (NULL == pPin) { - break; - } - - // Disconnected pins are not activated - this saves pins - // worrying about this state themselves - - if (pPin->IsConnected()) { - HRESULT hr = pPin->Run(tStart); - if (FAILED(hr)) { - return hr; - } - } - } - } - -#ifdef DXMPERF - PERFLOG_RUN( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, tStart, m_State ); -#endif // DXMPERF - - m_State = State_Running; - return S_OK; -} - -// -// return the current stream time - samples with start timestamps of this -// time or before should be rendered by now -HRESULT -CBaseFilter::StreamTime(CRefTime& rtStream) -{ - // Caller must lock for synchronization - // We can't grab the filter lock because we want to be able to call - // this from worker threads without deadlocking - - if (m_pClock == NULL) { - return VFW_E_NO_CLOCK; - } - - // get the current reference time - HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); - if (FAILED(hr)) { - return hr; - } - - // subtract the stream offset to get stream time - rtStream -= m_tStart; - - return S_OK; -} - - -/* Create an enumerator for the pins attached to this filter */ - -STDMETHODIMP -CBaseFilter::EnumPins(__deref_out IEnumPins **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); - - /* Create a new ref counted enumerator */ - - *ppEnum = new CEnumPins(this, - NULL); - - return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR; -} - - -// default behaviour of FindPin is to assume pins are named -// by their pin names -STDMETHODIMP -CBaseFilter::FindPin( - LPCWSTR Id, - __deref_out IPin ** ppPin -) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - - // We're going to search the pin list so maintain integrity - CAutoLock lck(m_pLock); - int iCount = GetPinCount(); - for (int i = 0; i < iCount; i++) { - CBasePin *pPin = GetPin(i); - if (NULL == pPin) { - break; - } - - if (0 == lstrcmpW(pPin->Name(), Id)) { - // Found one that matches - // - // AddRef() and return it - *ppPin = pPin; - pPin->AddRef(); - return S_OK; - } - } - *ppPin = NULL; - return VFW_E_NOT_FOUND; -} - -/* Return information about this filter */ - -STDMETHODIMP -CBaseFilter::QueryFilterInfo(__out FILTER_INFO * pInfo) -{ - CheckPointer(pInfo,E_POINTER); - ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO)); - - if (m_pName) { - (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); - } else { - pInfo->achName[0] = L'\0'; - } - pInfo->pGraph = m_pGraph; - if (m_pGraph) - m_pGraph->AddRef(); - return NOERROR; -} - - -/* Provide the filter with a filter graph */ - -STDMETHODIMP -CBaseFilter::JoinFilterGraph( - __inout_opt IFilterGraph * pGraph, - __in_opt LPCWSTR pName) -{ - CAutoLock cObjectLock(m_pLock); - - // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink) - - m_pGraph = pGraph; - if (m_pGraph) { - HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink, - (void**) &m_pSink); - if (FAILED(hr)) { - ASSERT(m_pSink == NULL); - } - else m_pSink->Release(); // we do NOT keep a reference on it. - } else { - // if graph pointer is null, then we should - // also release the IMediaEventSink on the same object - we don't - // refcount it, so just set it to null - m_pSink = NULL; - } - - - if (m_pName) { - delete[] m_pName; - m_pName = NULL; - } - - if (pName) { - size_t namelen; - HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &namelen); - if (FAILED(hr)) { - return hr; - } - m_pName = new WCHAR[namelen + 1]; - if (m_pName) { - (void)StringCchCopyW(m_pName, namelen + 1, pName); - } else { - return E_OUTOFMEMORY; - } - } - -#ifdef DXMPERF - PERFLOG_JOINGRAPH( m_pName ? m_pName : L"CBaseFilter",(IBaseFilter *) this, pGraph ); -#endif // DXMPERF - - return NOERROR; -} - - -// return a Vendor information string. Optional - may return E_NOTIMPL. -// memory returned should be freed using CoTaskMemFree -// default implementation returns E_NOTIMPL -STDMETHODIMP -CBaseFilter::QueryVendorInfo( - __deref_out LPWSTR* pVendorInfo) -{ - UNREFERENCED_PARAMETER(pVendorInfo); - return E_NOTIMPL; -} - - -// send an event notification to the filter graph if we know about it. -// returns S_OK if delivered, S_FALSE if the filter graph does not sink -// events, or an error otherwise. -HRESULT -CBaseFilter::NotifyEvent( - long EventCode, - LONG_PTR EventParam1, - LONG_PTR EventParam2) -{ - // Snapshot so we don't have to lock up - IMediaEventSink *pSink = m_pSink; - if (pSink) { - if (EC_COMPLETE == EventCode) { - EventParam2 = (LONG_PTR)(IBaseFilter*)this; - } - - return pSink->Notify(EventCode, EventParam1, EventParam2); - } else { - return E_NOTIMPL; - } -} - -// Request reconnect -// pPin is the pin to reconnect -// pmt is the type to reconnect with - can be NULL -// Calls ReconnectEx on the filter graph -HRESULT -CBaseFilter::ReconnectPin( - IPin *pPin, - __in_opt AM_MEDIA_TYPE const *pmt -) -{ - IFilterGraph2 *pGraph2; - if (m_pGraph != NULL) { - HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2); - if (SUCCEEDED(hr)) { - hr = pGraph2->ReconnectEx(pPin, pmt); - pGraph2->Release(); - return hr; - } else { - return m_pGraph->Reconnect(pPin); - } - } else { - return E_NOINTERFACE; - } -} - - - -/* This is the same idea as the media type version does for type enumeration - on pins but for the list of pins available. So if the list of pins you - provide changes dynamically then either override this virtual function - to provide the version number, or more simply call IncrementPinVersion */ - -LONG CBaseFilter::GetPinVersion() -{ - return m_PinVersion; -} - - -/* Increment the current pin version cookie */ - -void CBaseFilter::IncrementPinVersion() -{ - InterlockedIncrement(&m_PinVersion); -} - -/* register filter */ - -STDMETHODIMP CBaseFilter::Register() -{ - // get setup data, if it exists - // - LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - // init is ref counted so call just in case - // we're being called cold. - // - HRESULT hr = CoInitialize( (LPVOID)NULL ); - ASSERT( SUCCEEDED(hr) ); - - // get hold of IFilterMapper - // - IFilterMapper *pIFM; - hr = CoCreateInstance( CLSID_FilterMapper - , NULL - , CLSCTX_INPROC_SERVER - , IID_IFilterMapper - , (void **)&pIFM ); - if( SUCCEEDED(hr) ) - { - hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE ); - pIFM->Release(); - } - - // and clear up - // - CoFreeUnusedLibraries(); - CoUninitialize(); - - return NOERROR; -} - - -/* unregister filter */ - -STDMETHODIMP CBaseFilter::Unregister() -{ - // get setup data, if it exists - // - LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - // OLE init is ref counted so call - // just in case we're being called cold. - // - HRESULT hr = CoInitialize( (LPVOID)NULL ); - ASSERT( SUCCEEDED(hr) ); - - // get hold of IFilterMapper - // - IFilterMapper *pIFM; - hr = CoCreateInstance( CLSID_FilterMapper - , NULL - , CLSCTX_INPROC_SERVER - , IID_IFilterMapper - , (void **)&pIFM ); - if( SUCCEEDED(hr) ) - { - hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE ); - - // release interface - // - pIFM->Release(); - } - - // clear up - // - CoFreeUnusedLibraries(); - CoUninitialize(); - - // handle one acceptable "error" - that - // of filter not being registered! - // (couldn't find a suitable #define'd - // name for the error!) - // - if( 0x80070002 == hr) - return NOERROR; - else - return hr; -} - - -//===================================================================== -//===================================================================== -// Implements CEnumPins -//===================================================================== -//===================================================================== - - -CEnumPins::CEnumPins(__in CBaseFilter *pFilter, - __in_opt CEnumPins *pEnumPins) : - m_Position(0), - m_PinCount(0), - m_pFilter(pFilter), - m_cRef(1), // Already ref counted - m_PinCache(NAME("Pin Cache")) -{ - -#ifdef _DEBUG - m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0); -#endif - - /* We must be owned by a filter derived from CBaseFilter */ - - ASSERT(pFilter != NULL); - - /* Hold a reference count on our filter */ - m_pFilter->AddRef(); - - /* Are we creating a new enumerator */ - - if (pEnumPins == NULL) { - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - } else { - ASSERT(m_Position <= m_PinCount); - m_Position = pEnumPins->m_Position; - m_PinCount = pEnumPins->m_PinCount; - m_Version = pEnumPins->m_Version; - m_PinCache.AddTail(&(pEnumPins->m_PinCache)); - } -} - - -/* Destructor releases the reference count on our filter NOTE since we hold - a reference count on the filter who created us we know it is safe to - release it, no access can be made to it afterwards though as we have just - caused the last reference count to go and the object to be deleted */ - -CEnumPins::~CEnumPins() -{ - m_pFilter->Release(); - -#ifdef _DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif -} - - -/* Override this to say what interfaces we support where */ - -STDMETHODIMP -CEnumPins::QueryInterface(REFIID riid, __deref_out void **ppv) -{ - CheckPointer(ppv, E_POINTER); - - /* Do we have this interface */ - - if (riid == IID_IEnumPins || riid == IID_IUnknown) { - return GetInterface((IEnumPins *) this, ppv); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CEnumPins::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -STDMETHODIMP_(ULONG) -CEnumPins::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) { - delete this; - } - return cRef; -} - -/* One of an enumerator's basic member functions allows us to create a cloned - interface that initially has the same state. Since we are taking a snapshot - of an object (current position and all) we must lock access at the start */ - -STDMETHODIMP -CEnumPins::Clone(__deref_out IEnumPins **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); - HRESULT hr = NOERROR; - - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - *ppEnum = NULL; - hr = VFW_E_ENUM_OUT_OF_SYNC; - } else { - *ppEnum = new CEnumPins(m_pFilter, - this); - if (*ppEnum == NULL) { - hr = E_OUTOFMEMORY; - } - } - return hr; -} - - -/* Return the next pin after the current position */ - -STDMETHODIMP -CEnumPins::Next(ULONG cPins, // place this many pins... - __out_ecount(cPins) IPin **ppPins, // ...in this array - __out_opt ULONG *pcFetched) // actual count passed returned here -{ - CheckPointer(ppPins,E_POINTER); - ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *)); - - ASSERT(ppPins); - - if (pcFetched!=NULL) { - ValidateWritePtr(pcFetched, sizeof(ULONG)); - *pcFetched = 0; // default unless we succeed - } - // now check that the parameter is valid - else if (cPins>1) { // pcFetched == NULL - return E_INVALIDARG; - } - ULONG cFetched = 0; // increment as we get each one. - - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - // If we are out of sync, we should refresh the enumerator. - // This will reset the position and update the other members, but - // will not clear cache of pins we have already returned. - Refresh(); - } - - /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed - so we must QI for the IPin (which increments its reference count) - If while we are retrieving a pin from the filter an error occurs we - assume that our internal state is stale with respect to the filter - (for example someone has deleted a pin) so we - return VFW_E_ENUM_OUT_OF_SYNC */ - - while (cFetched < cPins && m_PinCount > m_Position) { - - /* Get the next pin object from the filter */ - - CBasePin *pPin = m_pFilter->GetPin(m_Position++); - if (pPin == NULL) { - // If this happend, and it's not the first time through, then we've got a problem, - // since we should really go back and release the iPins, which we have previously - // AddRef'ed. - ASSERT( cFetched==0 ); - return VFW_E_ENUM_OUT_OF_SYNC; - } - // MPC-HC custom code begin - if (pPin == (CBasePin *)0x3) { - return E_FAIL; - } - // MPC-HC custom code end - - /* We only want to return this pin, if it is not in our cache */ - if (0 == m_PinCache.Find(pPin)) - { - /* From the object get an IPin interface */ - - *ppPins = pPin; - pPin->AddRef(); - - cFetched++; - ppPins++; - - m_PinCache.AddTail(pPin); - } - } - - if (pcFetched!=NULL) { - *pcFetched = cFetched; - } - - return (cPins==cFetched ? NOERROR : S_FALSE); -} - - -/* Skip over one or more entries in the enumerator */ - -STDMETHODIMP -CEnumPins::Skip(ULONG cPins) -{ - /* Check we are still in sync with the filter */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - /* Work out how many pins are left to skip over */ - /* We could position at the end if we are asked to skip too many... */ - /* ..which would match the base implementation for CEnumMediaTypes::Skip */ - - ULONG PinsLeft = m_PinCount - m_Position; - if (cPins > PinsLeft) { - return S_FALSE; - } - m_Position += cPins; - return NOERROR; -} - - -/* Set the current position back to the start */ -/* Reset has 4 simple steps: - * - * Set position to head of list - * Sync enumerator with object being enumerated - * Clear the cache of pins already returned - * return S_OK - */ - -STDMETHODIMP -CEnumPins::Reset() -{ - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - - m_Position = 0; - - // Clear the cache - m_PinCache.RemoveAll(); - - return S_OK; -} - - -/* Set the current position back to the start */ -/* Refresh has 3 simple steps: - * - * Set position to head of list - * Sync enumerator with object being enumerated - * return S_OK - */ - -STDMETHODIMP -CEnumPins::Refresh() -{ - m_Version = m_pFilter->GetPinVersion(); - m_PinCount = m_pFilter->GetPinCount(); - - m_Position = 0; - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CEnumMediaTypes -//===================================================================== -//===================================================================== - - -CEnumMediaTypes::CEnumMediaTypes(__in CBasePin *pPin, - __in_opt CEnumMediaTypes *pEnumMediaTypes) : - m_Position(0), - m_pPin(pPin), - m_cRef(1) -{ - -#ifdef _DEBUG - m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0); -#endif - - /* We must be owned by a pin derived from CBasePin */ - - ASSERT(pPin != NULL); - - /* Hold a reference count on our pin */ - m_pPin->AddRef(); - - /* Are we creating a new enumerator */ - - if (pEnumMediaTypes == NULL) { - m_Version = m_pPin->GetMediaTypeVersion(); - return; - } - - m_Position = pEnumMediaTypes->m_Position; - m_Version = pEnumMediaTypes->m_Version; -} - - -/* Destructor releases the reference count on our base pin. NOTE since we hold - a reference count on the pin who created us we know it is safe to release - it, no access can be made to it afterwards though as we might have just - caused the last reference count to go and the object to be deleted */ - -CEnumMediaTypes::~CEnumMediaTypes() -{ -#ifdef _DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif - m_pPin->Release(); -} - - -/* Override this to say what interfaces we support where */ - -STDMETHODIMP -CEnumMediaTypes::QueryInterface(REFIID riid, __deref_out void **ppv) -{ - CheckPointer(ppv, E_POINTER); - - /* Do we have this interface */ - - if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) { - return GetInterface((IEnumMediaTypes *) this, ppv); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CEnumMediaTypes::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -STDMETHODIMP_(ULONG) -CEnumMediaTypes::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) { - delete this; - } - return cRef; -} - -/* One of an enumerator's basic member functions allows us to create a cloned - interface that initially has the same state. Since we are taking a snapshot - of an object (current position and all) we must lock access at the start */ - -STDMETHODIMP -CEnumMediaTypes::Clone(__deref_out IEnumMediaTypes **ppEnum) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); - HRESULT hr = NOERROR; - - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - *ppEnum = NULL; - hr = VFW_E_ENUM_OUT_OF_SYNC; - } else { - - *ppEnum = new CEnumMediaTypes(m_pPin, - this); - - if (*ppEnum == NULL) { - hr = E_OUTOFMEMORY; - } - } - return hr; -} - - -/* Enumerate the next pin(s) after the current position. The client using this - interface passes in a pointer to an array of pointers each of which will - be filled in with a pointer to a fully initialised media type format - Return NOERROR if it all works, - S_FALSE if fewer than cMediaTypes were enumerated. - VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by - state changes in the filter - The actual count always correctly reflects the number of types in the array. -*/ - -STDMETHODIMP -CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types... - __out_ecount(cMediaTypes) AM_MEDIA_TYPE **ppMediaTypes, // ...in this array - __out ULONG *pcFetched) // actual count passed -{ - CheckPointer(ppMediaTypes,E_POINTER); - ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *)); - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - if (pcFetched!=NULL) { - ValidateWritePtr(pcFetched, sizeof(ULONG)); - *pcFetched = 0; // default unless we succeed - } - // now check that the parameter is valid - else if (cMediaTypes>1) { // pcFetched == NULL - return E_INVALIDARG; - } - ULONG cFetched = 0; // increment as we get each one. - - /* Return each media type by asking the filter for them in turn - If we - have an error code retured to us while we are retrieving a media type - we assume that our internal state is stale with respect to the filter - (for example the window size changing) so we return - VFW_E_ENUM_OUT_OF_SYNC */ - - while (cMediaTypes) { - - CMediaType cmt; - - HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt); - if (S_OK != hr) { - break; - } - - /* We now have a CMediaType object that contains the next media type - but when we assign it to the array position we CANNOT just assign - the AM_MEDIA_TYPE structure because as soon as the object goes out of - scope it will delete the memory we have just copied. The function - we use is CreateMediaType which allocates a task memory block */ - - /* Transfer across the format block manually to save an allocate - and free on the format block and generally go faster */ - - *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - if (*ppMediaTypes == NULL) { - break; - } - - /* Do a regular copy */ - **ppMediaTypes = cmt; - - /* Make sure the destructor doesn't free these */ - cmt.pbFormat = NULL; - cmt.cbFormat = NULL; - cmt.pUnk = NULL; - - - ppMediaTypes++; - cFetched++; - cMediaTypes--; - } - - if (pcFetched!=NULL) { - *pcFetched = cFetched; - } - - return ( cMediaTypes==0 ? NOERROR : S_FALSE ); -} - - -/* Skip over one or more entries in the enumerator */ - -STDMETHODIMP -CEnumMediaTypes::Skip(ULONG cMediaTypes) -{ - // If we're skipping 0 elements we're guaranteed to skip the - // correct number of elements - if (cMediaTypes == 0) { - return S_OK; - } - - /* Check we are still in sync with the pin */ - if (AreWeOutOfSync() == TRUE) { - return VFW_E_ENUM_OUT_OF_SYNC; - } - - m_Position += cMediaTypes; - - /* See if we're over the end */ - CMediaType cmt; - return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE; -} - - -/* Set the current position back to the start */ -/* Reset has 3 simple steps: - * - * set position to head of list - * sync enumerator with object being enumerated - * return S_OK - */ - -STDMETHODIMP -CEnumMediaTypes::Reset() - -{ - m_Position = 0; - - // Bring the enumerator back into step with the current state. This - // may be a noop but ensures that the enumerator will be valid on the - // next call. - m_Version = m_pPin->GetMediaTypeVersion(); - return NOERROR; -} - - -//===================================================================== -//===================================================================== -// Implements CBasePin -//===================================================================== -//===================================================================== - - -/* NOTE The implementation of this class calls the CUnknown constructor with - a NULL outer unknown pointer. This has the effect of making us a self - contained class, ie any QueryInterface, AddRef or Release calls will be - routed to the class's NonDelegatingUnknown methods. You will typically - find that the classes that do this then override one or more of these - virtual functions to provide more specialised behaviour. A good example - of this is where a class wants to keep the QueryInterface internal but - still wants its lifetime controlled by the external object */ - -/* Constructor */ - -CBasePin::CBasePin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName, - PIN_DIRECTION dir) : - CUnknown( pObjectName, NULL ), - m_pFilter(pFilter), - m_pLock(pLock), - m_pName(NULL), - m_Connected(NULL), - m_dir(dir), - m_bRunTimeError(FALSE), - m_pQSink(NULL), - m_TypeVersion(1), - m_tStart(), - m_tStop(MAX_TIME), - m_bCanReconnectWhenActive(false), - m_bTryMyTypesFirst(false), - m_dRate(1.0) -{ - /* WARNING - pFilter is often not a properly constituted object at - this state (in particular QueryInterface may not work) - this - is because its owner is often its containing object and we - have been called from the containing object's constructor so - the filter's owner has not yet had its CUnknown constructor - called - */ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this ); -#endif // DXMPERF - - ASSERT(pFilter != NULL); - ASSERT(pLock != NULL); - - if (pName) { - size_t cchName; - HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName); - if (SUCCEEDED(hr)) { - m_pName = new WCHAR[cchName + 1]; - if (m_pName) { - (void)StringCchCopyW(m_pName, cchName + 1, pName); - } - } - } - -#ifdef _DEBUG - m_cRef = 0; -#endif -} - -#ifdef UNICODE -CBasePin::CBasePin(__in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName, - PIN_DIRECTION dir) : - CUnknown( pObjectName, NULL ), - m_pFilter(pFilter), - m_pLock(pLock), - m_pName(NULL), - m_Connected(NULL), - m_dir(dir), - m_bRunTimeError(FALSE), - m_pQSink(NULL), - m_TypeVersion(1), - m_tStart(), - m_tStop(MAX_TIME), - m_bCanReconnectWhenActive(false), - m_bTryMyTypesFirst(false), - m_dRate(1.0) -{ - /* WARNING - pFilter is often not a properly constituted object at - this state (in particular QueryInterface may not work) - this - is because its owner is often its containing object and we - have been called from the containing object's constructor so - the filter's owner has not yet had its CUnknown constructor - called - */ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this ); -#endif // DXMPERF - - ASSERT(pFilter != NULL); - ASSERT(pLock != NULL); - - if (pName) { - size_t cchName; - HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName); - if (SUCCEEDED(hr)) { - m_pName = new WCHAR[cchName + 1]; - if (m_pName) { - (void)StringCchCopyW(m_pName, cchName + 1, pName); - } - } - } - - -#ifdef _DEBUG - m_cRef = 0; -#endif -} -#endif - -/* Destructor since a connected pin holds a reference count on us there is - no way that we can be deleted unless we are not currently connected */ - -CBasePin::~CBasePin() -{ -#ifdef DXMPERF - PERFLOG_DTOR( m_pName ? m_pName : L"CBasePin", (IPin *) this ); -#endif // DXMPERF - - // We don't call disconnect because if the filter is going away - // all the pins must have a reference count of zero so they must - // have been disconnected anyway - (but check the assumption) - ASSERT(m_Connected == FALSE); - - delete[] m_pName; - - // check the internal reference count is consistent - ASSERT(m_cRef == 0); -} - - -/* Override this to say what interfaces we support and where */ - -STDMETHODIMP -CBasePin::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) -{ - /* Do we have this interface */ - - if (riid == IID_IPin) { - return GetInterface((IPin *) this, ppv); - } else if (riid == IID_IQualityControl) { - return GetInterface((IQualityControl *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* Override to increment the owning filter's reference count */ - -STDMETHODIMP_(ULONG) -CBasePin::NonDelegatingAddRef() -{ - ASSERT(InterlockedIncrement(&m_cRef) > 0); - return m_pFilter->AddRef(); -} - - -/* Override to decrement the owning filter's reference count */ - -STDMETHODIMP_(ULONG) -CBasePin::NonDelegatingRelease() -{ - ASSERT(InterlockedDecrement(&m_cRef) >= 0); - return m_pFilter->Release(); -} - - -/* Displays pin connection information */ - -#ifdef _DEBUG -void -CBasePin::DisplayPinInfo(IPin *pReceivePin) -{ - - if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { - PIN_INFO ConnectPinInfo; - PIN_INFO ReceivePinInfo; - - if (FAILED(QueryPinInfo(&ConnectPinInfo))) { - StringCchCopyW(ConnectPinInfo.achName, sizeof(ConnectPinInfo.achName)/sizeof(WCHAR), L"Bad Pin"); - } else { - QueryPinInfoReleaseFilter(ConnectPinInfo); - } - - if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) { - StringCchCopyW(ReceivePinInfo.achName, sizeof(ReceivePinInfo.achName)/sizeof(WCHAR), L"Bad Pin"); - } else { - QueryPinInfoReleaseFilter(ReceivePinInfo); - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :"))); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName)); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName)); - } -} -#endif - - -/* Displays general information on the pin media type */ - -#ifdef _DEBUG -void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) -{ - UNREFERENCED_PARAMETER(pPin); - if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:"))); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"), - GuidNames[*pmt->Type()])); - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"), - GuidNames[*pmt->Subtype()])); - } -} -#endif - -/* Asked to connect to a pin. A pin is always attached to an owning filter - object so we always delegate our locking to that object. We first of all - retrieve a media type enumerator for the input pin and see if we accept - any of the formats that it would ideally like, failing that we retrieve - our enumerator and see if it will accept any of our preferred types */ - -STDMETHODIMP -CBasePin::Connect( - IPin * pReceivePin, - __in_opt const AM_MEDIA_TYPE *pmt // optional media type -) -{ - CheckPointer(pReceivePin,E_POINTER); - ValidateReadPtr(pReceivePin,sizeof(IPin)); - CAutoLock cObjectLock(m_pLock); - DisplayPinInfo(pReceivePin); - - /* See if we are already connected */ - - if (m_Connected) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected"))); - return VFW_E_ALREADY_CONNECTED; - } - - /* See if the filter is active */ - if (!IsStopped() && !m_bCanReconnectWhenActive) { - return VFW_E_NOT_STOPPED; - } - - - // Find a mutually agreeable media type - - // Pass in the template media type. If this is partially specified, - // each of the enumerated media types will need to be checked against - // it. If it is non-null and fully specified, we will just try to connect - // with this. - - const CMediaType * ptype = (CMediaType*)pmt; - HRESULT hr = AgreeMediaType(pReceivePin, ptype); - if (FAILED(hr)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type"))); - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - -#ifdef DXMPERF - PERFLOG_CONNECT( (IPin *) this, pReceivePin, hr, pmt ); -#endif // DXMPERF - - return hr; - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded"))); - -#ifdef DXMPERF - PERFLOG_CONNECT( (IPin *) this, pReceivePin, NOERROR, pmt ); -#endif // DXMPERF - - return NOERROR; -} - -// given a specific media type, attempt a connection (includes -// checking that the type is acceptable to this pin) -HRESULT -CBasePin::AttemptConnection( - IPin* pReceivePin, // connect to this pin - const CMediaType* pmt // using this type -) -{ - // The caller should hold the filter lock becasue this function - // uses m_Connected. The caller should also hold the filter lock - // because this function calls SetMediaType(), IsStopped() and - // CompleteConnect(). - ASSERT(CritCheckIn(m_pLock)); - - // Check that the connection is valid -- need to do this for every - // connect attempt since BreakConnect will undo it. - HRESULT hr = CheckConnect(pReceivePin); - if (FAILED(hr)) { - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed"))); - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - return hr; - } - - DisplayTypeInfo(pReceivePin, pmt); - - /* Check we will accept this media type */ - - hr = CheckMediaType(pmt); - if (hr == NOERROR) { - - /* Make ourselves look connected otherwise ReceiveConnection - may not be able to complete the connection - */ - m_Connected = pReceivePin; - m_Connected->AddRef(); - hr = SetMediaType(pmt); - if (SUCCEEDED(hr)) { - /* See if the other pin will accept this type */ - - hr = pReceivePin->ReceiveConnection((IPin *)this, pmt); - if (SUCCEEDED(hr)) { - /* Complete the connection */ - - hr = CompleteConnect(pReceivePin); - if (SUCCEEDED(hr)) { - return hr; - } else { - DbgLog((LOG_TRACE, - CONNECT_TRACE_LEVEL, - TEXT("Failed to complete connection"))); - pReceivePin->Disconnect(); - } - } - } - } else { - // we cannot use this media type - - // return a specific media type error if there is one - // or map a general failure code to something more helpful - // (in particular S_FALSE gets changed to an error code) - if (SUCCEEDED(hr) || - (hr == E_FAIL) || - (hr == E_INVALIDARG)) { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } - } - - // BreakConnect and release any connection here in case CheckMediaType - // failed, or if we set anything up during a call back during - // ReceiveConnection. - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - /* If failed then undo our state */ - if (m_Connected) { - m_Connected->Release(); - m_Connected = NULL; - } - - return hr; -} - -/* Given an enumerator we cycle through all the media types it proposes and - firstly suggest them to our derived pin class and if that succeeds try - them with the pin in a ReceiveConnection call. This means that if our pin - proposes a media type we still check in here that we can support it. This - is deliberate so that in simple cases the enumerator can hold all of the - media types even if some of them are not really currently available */ - -HRESULT CBasePin::TryMediaTypes( - IPin *pReceivePin, - __in_opt const CMediaType *pmt, - IEnumMediaTypes *pEnum) -{ - /* Reset the current enumerator position */ - - HRESULT hr = pEnum->Reset(); - if (FAILED(hr)) { - return hr; - } - - CMediaType *pMediaType = NULL; - ULONG ulMediaCount = 0; - - // attempt to remember a specific error code if there is one - HRESULT hrFailure = S_OK; - - for (;;) { - - /* Retrieve the next media type NOTE each time round the loop the - enumerator interface will allocate another AM_MEDIA_TYPE structure - If we are successful then we copy it into our output object, if - not then we must delete the memory allocated before returning */ - - hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount); - if (hr != S_OK) { - if (S_OK == hrFailure) { - hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; - } - return hrFailure; - } - - - ASSERT(ulMediaCount == 1); - ASSERT(pMediaType); - - // check that this matches the partial type (if any) - - if (pMediaType && - ((pmt == NULL) || - pMediaType->MatchesPartial(pmt))) { - - hr = AttemptConnection(pReceivePin, pMediaType); - - // attempt to remember a specific error code - if (FAILED(hr) && - SUCCEEDED(hrFailure) && - (hr != E_FAIL) && - (hr != E_INVALIDARG) && - (hr != VFW_E_TYPE_NOT_ACCEPTED)) { - hrFailure = hr; - } - } else { - hr = VFW_E_NO_ACCEPTABLE_TYPES; - } - - if(pMediaType) { - DeleteMediaType(pMediaType); - pMediaType = NULL; - } - - if (S_OK == hr) { - return hr; - } - } -} - - -/* This is called to make the connection, including the taask of finding - a media type for the pin connection. pmt is the proposed media type - from the Connect call: if this is fully specified, we will try that. - Otherwise we enumerate and try all the input pin's types first and - if that fails we then enumerate and try all our preferred media types. - For each media type we check it against pmt (if non-null and partially - specified) as well as checking that both pins will accept it. - */ - -HRESULT CBasePin::AgreeMediaType( - IPin *pReceivePin, - const CMediaType *pmt) -{ - ASSERT(pReceivePin); - IEnumMediaTypes *pEnumMediaTypes = NULL; - - // if the media type is fully specified then use that - if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) { - - // if this media type fails, then we must fail the connection - // since if pmt is nonnull we are only allowed to connect - // using a type that matches it. - - return AttemptConnection(pReceivePin, pmt); - } - - - /* Try the other pin's enumerator */ - - HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; - - for (int i = 0; i < 2; i++) { - HRESULT hr; - if (i == (int)m_bTryMyTypesFirst) { - hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes); - } else { - hr = EnumMediaTypes(&pEnumMediaTypes); - } - if (SUCCEEDED(hr)) { - ASSERT(pEnumMediaTypes); - hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes); - pEnumMediaTypes->Release(); - if (SUCCEEDED(hr)) { - return NOERROR; - } else { - // try to remember specific error codes if there are any - if ((hr != E_FAIL) && - (hr != E_INVALIDARG) && - (hr != VFW_E_TYPE_NOT_ACCEPTED)) { - hrFailure = hr; - } - } - } - } - - return hrFailure; -} - - -/* Called when we want to complete a connection to another filter. Failing - this will also fail the connection and disconnect the other pin as well */ - -HRESULT -CBasePin::CompleteConnect(IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - return NOERROR; -} - - -/* This is called to set the format for a pin connection - CheckMediaType - will have been called to check the connection format and if it didn't - return an error code then this (virtual) function will be invoked */ - -HRESULT -CBasePin::SetMediaType(const CMediaType *pmt) -{ - HRESULT hr = m_mt.Set(*pmt); - if (FAILED(hr)) { - return hr; - } - - return NOERROR; -} - - -/* This is called during Connect() to provide a virtual method that can do - any specific check needed for connection such as QueryInterface. This - base class method just checks that the pin directions don't match */ - -HRESULT -CBasePin::CheckConnect(IPin * pPin) -{ - /* Check that pin directions DONT match */ - - PIN_DIRECTION pd; - pPin->QueryDirection(&pd); - - ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT)); - ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT)); - - // we should allow for non-input and non-output connections? - if (pd == m_dir) { - return VFW_E_INVALID_DIRECTION; - } - return NOERROR; -} - - -/* This is called when we realise we can't make a connection to the pin and - must undo anything we did in CheckConnect - override to release QIs done */ - -HRESULT -CBasePin::BreakConnect() -{ - return NOERROR; -} - - -/* Called normally by an output pin on an input pin to try and establish a - connection. -*/ - -STDMETHODIMP -CBasePin::ReceiveConnection( - IPin * pConnector, // this is the pin who we will connect to - const AM_MEDIA_TYPE *pmt // this is the media type we will exchange -) -{ - CheckPointer(pConnector,E_POINTER); - CheckPointer(pmt,E_POINTER); - ValidateReadPtr(pConnector,sizeof(IPin)); - ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); - CAutoLock cObjectLock(m_pLock); - - /* Are we already connected */ - if (m_Connected) { - return VFW_E_ALREADY_CONNECTED; - } - - /* See if the filter is active */ - if (!IsStopped() && !m_bCanReconnectWhenActive) { - return VFW_E_NOT_STOPPED; - } - - HRESULT hr = CheckConnect(pConnector); - if (FAILED(hr)) { - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - -#ifdef DXMPERF - PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); -#endif // DXMPERF - - return hr; - } - - /* Ask derived class if this media type is ok */ - - CMediaType * pcmt = (CMediaType*) pmt; - hr = CheckMediaType(pcmt); - if (hr != NOERROR) { - // no -we don't support this media type - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - - // return a specific media type error if there is one - // or map a general failure code to something more helpful - // (in particular S_FALSE gets changed to an error code) - if (SUCCEEDED(hr) || - (hr == E_FAIL) || - (hr == E_INVALIDARG)) { - hr = VFW_E_TYPE_NOT_ACCEPTED; - } - -#ifdef DXMPERF - PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); -#endif // DXMPERF - - return hr; - } - - /* Complete the connection */ - - m_Connected = pConnector; - m_Connected->AddRef(); - hr = SetMediaType(pcmt); - if (SUCCEEDED(hr)) { - hr = CompleteConnect(pConnector); - if (SUCCEEDED(hr)) { - -#ifdef DXMPERF - PERFLOG_RXCONNECT( pConnector, (IPin *) this, NOERROR, pmt ); -#endif // DXMPERF - - return NOERROR; - } - } - - DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection."))); - m_Connected->Release(); - m_Connected = NULL; - - // Since the procedure is already returning an error code, there - // is nothing else this function can do to report the error. - EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); - -#ifdef DXMPERF - PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); -#endif // DXMPERF - - return hr; -} - - -/* Called when we want to terminate a pin connection */ - -STDMETHODIMP -CBasePin::Disconnect() -{ - CAutoLock cObjectLock(m_pLock); - - /* See if the filter is active */ - if (!IsStopped()) { - return VFW_E_NOT_STOPPED; - } - - return DisconnectInternal(); -} - -STDMETHODIMP -CBasePin::DisconnectInternal() -{ - ASSERT(CritCheckIn(m_pLock)); - - if (m_Connected) { - HRESULT hr = BreakConnect(); - if( FAILED( hr ) ) { - -#ifdef DXMPERF - PERFLOG_DISCONNECT( (IPin *) this, m_Connected, hr ); -#endif // DXMPERF - - // There is usually a bug in the program if BreakConnect() fails. - DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." ); - return hr; - } - - m_Connected->Release(); - m_Connected = NULL; - -#ifdef DXMPERF - PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_OK ); -#endif // DXMPERF - - return S_OK; - } else { - // no connection - not an error - -#ifdef DXMPERF - PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_FALSE ); -#endif // DXMPERF - - return S_FALSE; - } -} - - -/* Return an AddRef()'d pointer to the connected pin if there is one */ -STDMETHODIMP -CBasePin::ConnectedTo( - __deref_out IPin **ppPin -) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - // - // It's pointless to lock here. - // The caller should ensure integrity. - // - - IPin *pPin = m_Connected; - *ppPin = pPin; - if (pPin != NULL) { - pPin->AddRef(); - return S_OK; - } else { - ASSERT(*ppPin == NULL); - return VFW_E_NOT_CONNECTED; - } -} - -/* Return the media type of the connection */ -STDMETHODIMP -CBasePin::ConnectionMediaType( - __out AM_MEDIA_TYPE *pmt -) -{ - CheckPointer(pmt,E_POINTER); - ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE)); - CAutoLock cObjectLock(m_pLock); - - /* Copy constructor of m_mt allocates the memory */ - if (IsConnected()) { - CopyMediaType( pmt, &m_mt ); - return S_OK; - } else { - ((CMediaType *)pmt)->InitMediaType(); - return VFW_E_NOT_CONNECTED; - } -} - -/* Return information about the filter we are connect to */ - -STDMETHODIMP -CBasePin::QueryPinInfo( - __out PIN_INFO * pInfo -) -{ - CheckPointer(pInfo,E_POINTER); - ValidateReadWritePtr(pInfo,sizeof(PIN_INFO)); - - pInfo->pFilter = m_pFilter; - if (m_pFilter) { - m_pFilter->AddRef(); - } - - if (m_pName) { - (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); - } else { - pInfo->achName[0] = L'\0'; - } - - pInfo->dir = m_dir; - - return NOERROR; -} - -STDMETHODIMP -CBasePin::QueryDirection( - __out PIN_DIRECTION * pPinDir -) -{ - CheckPointer(pPinDir,E_POINTER); - ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION)); - - *pPinDir = m_dir; - return NOERROR; -} - -// Default QueryId to return the pin's name -STDMETHODIMP -CBasePin::QueryId( - __deref_out LPWSTR * Id -) -{ - // We're not going away because someone's got a pointer to us - // so there's no need to lock - - return AMGetWideString(Name(), Id); -} - -/* Does this pin support this media type WARNING this interface function does - not lock the main object as it is meant to be asynchronous by nature - if - the media types you support depend on some internal state that is updated - dynamically then you will need to implement locking in a derived class */ - -STDMETHODIMP -CBasePin::QueryAccept( - const AM_MEDIA_TYPE *pmt -) -{ - CheckPointer(pmt,E_POINTER); - ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); - - /* The CheckMediaType method is valid to return error codes if the media - type is horrible, an example might be E_INVALIDARG. What we do here - is map all the error codes into either S_OK or S_FALSE regardless */ - - HRESULT hr = CheckMediaType((CMediaType*)pmt); - if (FAILED(hr)) { - return S_FALSE; - } - // note that the only defined success codes should be S_OK and S_FALSE... - return hr; -} - - -/* This can be called to return an enumerator for the pin's list of preferred - media types. An input pin is not obliged to have any preferred formats - although it can do. For example, the window renderer has a preferred type - which describes a video image that matches the current window size. All - output pins should expose at least one preferred format otherwise it is - possible that neither pin has any types and so no connection is possible */ - -STDMETHODIMP -CBasePin::EnumMediaTypes( - __deref_out IEnumMediaTypes **ppEnum -) -{ - CheckPointer(ppEnum,E_POINTER); - ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); - - /* Create a new ref counted enumerator */ - - *ppEnum = new CEnumMediaTypes(this, - NULL); - - if (*ppEnum == NULL) { - return E_OUTOFMEMORY; - } - - return NOERROR; -} - - - -/* This is a virtual function that returns a media type corresponding with - place iPosition in the list. This base class simply returns an error as - we support no media types by default but derived classes should override */ - -HRESULT CBasePin::GetMediaType(int iPosition, __inout CMediaType *pMediaType) -{ - UNREFERENCED_PARAMETER(iPosition); - UNREFERENCED_PARAMETER(pMediaType); - return E_UNEXPECTED; -} - - -/* This is a virtual function that returns the current media type version. - The base class initialises the media type enumerators with the value 1 - By default we always returns that same value. A Derived class may change - the list of media types available and after doing so it should increment - the version either in a method derived from this, or more simply by just - incrementing the m_TypeVersion base pin variable. The type enumerators - call this when they want to see if their enumerations are out of date */ - -LONG CBasePin::GetMediaTypeVersion() -{ - return m_TypeVersion; -} - - -/* Increment the cookie representing the current media type version */ - -void CBasePin::IncrementTypeVersion() -{ - InterlockedIncrement(&m_TypeVersion); -} - - -/* Called by IMediaFilter implementation when the state changes from Stopped - to either paused or running and in derived classes could do things like - commit memory and grab hardware resource (the default is to do nothing) */ - -HRESULT -CBasePin::Active(void) -{ - return NOERROR; -} - -/* Called by IMediaFilter implementation when the state changes from - to either paused to running and in derived classes could do things like - commit memory and grab hardware resource (the default is to do nothing) */ - -HRESULT -CBasePin::Run(REFERENCE_TIME tStart) -{ - UNREFERENCED_PARAMETER(tStart); - return NOERROR; -} - - -/* Also called by the IMediaFilter implementation when the state changes to - Stopped at which point you should decommit allocators and free hardware - resources you grabbed in the Active call (default is also to do nothing) */ - -HRESULT -CBasePin::Inactive(void) -{ - m_bRunTimeError = FALSE; - return NOERROR; -} - - -// Called when no more data will arrive -STDMETHODIMP -CBasePin::EndOfStream(void) -{ - return S_OK; -} - - -STDMETHODIMP -CBasePin::SetSink(IQualityControl * piqc) -{ - CAutoLock cObjectLock(m_pLock); - if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl)); - m_pQSink = piqc; - return NOERROR; -} // SetSink - - -STDMETHODIMP -CBasePin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(q); - UNREFERENCED_PARAMETER(pSender); - DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)"); - return E_NOTIMPL; -} //Notify - - -// NewSegment notifies of the start/stop/rate applying to the data -// about to be received. Default implementation records data and -// returns S_OK. -// Override this to pass downstream. -STDMETHODIMP -CBasePin::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - m_tStart = tStart; - m_tStop = tStop; - m_dRate = dRate; - - return S_OK; -} - - -//===================================================================== -//===================================================================== -// Implements CBaseOutputPin -//===================================================================== -//===================================================================== - - -CBaseOutputPin::CBaseOutputPin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), - m_pAllocator(NULL), - m_pInputPin(NULL) -{ - ASSERT(pFilter); -} - -#ifdef UNICODE -CBaseOutputPin::CBaseOutputPin(__in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), - m_pAllocator(NULL), - m_pInputPin(NULL) -{ - ASSERT(pFilter); -} -#endif - -/* This is called after a media type has been proposed - - Try to complete the connection by agreeing the allocator -*/ -HRESULT -CBaseOutputPin::CompleteConnect(IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - return DecideAllocator(m_pInputPin, &m_pAllocator); -} - - -/* This method is called when the output pin is about to try and connect to - an input pin. It is at this point that you should try and grab any extra - interfaces that you need, in this case IMemInputPin. Because this is - only called if we are not currently connected we do NOT need to call - BreakConnect. This also makes it easier to derive classes from us as - BreakConnect is only called when we actually have to break a connection - (or a partly made connection) and not when we are checking a connection */ - -/* Overriden from CBasePin */ - -HRESULT -CBaseOutputPin::CheckConnect(IPin * pPin) -{ - HRESULT hr = CBasePin::CheckConnect(pPin); - if (FAILED(hr)) { - return hr; - } - - // get an input pin and an allocator interface - hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin); - if (FAILED(hr)) { - return hr; - } - return NOERROR; -} - - -/* Overriden from CBasePin */ - -HRESULT -CBaseOutputPin::BreakConnect() -{ - /* Release any allocator we hold */ - - if (m_pAllocator) { - // Always decommit the allocator because a downstream filter may or - // may not decommit the connection's allocator. A memory leak could - // occur if the allocator is not decommited when a connection is broken. - HRESULT hr = m_pAllocator->Decommit(); - if( FAILED( hr ) ) { - return hr; - } - - m_pAllocator->Release(); - m_pAllocator = NULL; - } - - /* Release any input pin interface we hold */ - - if (m_pInputPin) { - m_pInputPin->Release(); - m_pInputPin = NULL; - } - return NOERROR; -} - - -/* This is called when the input pin didn't give us a valid allocator */ - -HRESULT -CBaseOutputPin::InitAllocator(__deref_out IMemAllocator **ppAlloc) -{ - return CreateMemoryAllocator(ppAlloc); -} - - -/* Decide on an allocator, override this if you want to use your own allocator - Override DecideBufferSize to call SetProperties. If the input pin fails - the GetAllocator call then this will construct a CMemAllocator and call - DecideBufferSize on that, and if that fails then we are completely hosed. - If the you succeed the DecideBufferSize call, we will notify the input - pin of the selected allocator. NOTE this is called during Connect() which - therefore looks after grabbing and locking the object's critical section */ - -// We query the input pin for its requested properties and pass this to -// DecideBufferSize to allow it to fulfill requests that it is happy -// with (eg most people don't care about alignment and are thus happy to -// use the downstream pin's alignment request). - -HRESULT -CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, __deref_out IMemAllocator **ppAlloc) -{ - HRESULT hr = NOERROR; - *ppAlloc = NULL; - - // get downstream prop request - // the derived class may modify this in DecideBufferSize, but - // we assume that he will consistently modify it the same way, - // so we only get it once - ALLOCATOR_PROPERTIES prop; - ZeroMemory(&prop, sizeof(prop)); - - // whatever he returns, we assume prop is either all zeros - // or he has filled it out. - pPin->GetAllocatorRequirements(&prop); - - // if he doesn't care about alignment, then set it to 1 - if (prop.cbAlign == 0) { - prop.cbAlign = 1; - } - - /* Try the allocator provided by the input pin */ - - hr = pPin->GetAllocator(ppAlloc); - if (SUCCEEDED(hr)) { - - hr = DecideBufferSize(*ppAlloc, &prop); - if (SUCCEEDED(hr)) { - hr = pPin->NotifyAllocator(*ppAlloc, FALSE); - if (SUCCEEDED(hr)) { - return NOERROR; - } - } - } - - /* If the GetAllocator failed we may not have an interface */ - - if (*ppAlloc) { - (*ppAlloc)->Release(); - *ppAlloc = NULL; - } - - /* Try the output pin's allocator by the same method */ - - hr = InitAllocator(ppAlloc); - if (SUCCEEDED(hr)) { - - // note - the properties passed here are in the same - // structure as above and may have been modified by - // the previous call to DecideBufferSize - hr = DecideBufferSize(*ppAlloc, &prop); - if (SUCCEEDED(hr)) { - hr = pPin->NotifyAllocator(*ppAlloc, FALSE); - if (SUCCEEDED(hr)) { - return NOERROR; - } - } - } - - /* Likewise we may not have an interface to release */ - - if (*ppAlloc) { - (*ppAlloc)->Release(); - *ppAlloc = NULL; - } - return hr; -} - - -/* This returns an empty sample buffer from the allocator WARNING the same - dangers and restrictions apply here as described below for Deliver() */ - -HRESULT -CBaseOutputPin::GetDeliveryBuffer(__deref_out IMediaSample ** ppSample, - __in_opt REFERENCE_TIME * pStartTime, - __in_opt REFERENCE_TIME * pEndTime, - DWORD dwFlags) -{ - if (m_pAllocator != NULL) { - return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags); - } else { - return E_NOINTERFACE; - } -} - - -/* Deliver a filled-in sample to the connected input pin. NOTE the object must - have locked itself before calling us otherwise we may get halfway through - executing this method only to find the filter graph has got in and - disconnected us from the input pin. If the filter has no worker threads - then the lock is best applied on Receive(), otherwise it should be done - when the worker thread is ready to deliver. There is a wee snag to worker - threads that this shows up. The worker thread must lock the object when - it is ready to deliver a sample, but it may have to wait until a state - change has completed, but that may never complete because the state change - is waiting for the worker thread to complete. The way to handle this is for - the state change code to grab the critical section, then set an abort event - for the worker thread, then release the critical section and wait for the - worker thread to see the event we set and then signal that it has finished - (with another event). At which point the state change code can complete */ - -// note (if you've still got any breath left after reading that) that you -// need to release the sample yourself after this call. if the connected -// input pin needs to hold onto the sample beyond the call, it will addref -// the sample itself. - -// of course you must release this one and call GetDeliveryBuffer for the -// next. You cannot reuse it directly. - -HRESULT -CBaseOutputPin::Deliver(IMediaSample * pSample) -{ - if (m_pInputPin == NULL) { - return VFW_E_NOT_CONNECTED; - } - -#ifdef DXMPERF - PERFLOG_DELIVER( m_pName ? m_pName : L"CBaseOutputPin", (IPin *) this, (IPin *) m_pInputPin, pSample, &m_mt ); -#endif // DXMPERF - - return m_pInputPin->Receive(pSample); -} - - -// called from elsewhere in our filter to pass EOS downstream to -// our connected input pin -HRESULT -CBaseOutputPin::DeliverEndOfStream(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->EndOfStream(); -} - - -/* Commit the allocator's memory, this is called through IMediaFilter - which is responsible for locking the object before calling us */ - -HRESULT -CBaseOutputPin::Active(void) -{ - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - return m_pAllocator->Commit(); -} - - -/* Free up or unprepare allocator's memory, this is called through - IMediaFilter which is responsible for locking the object first */ - -HRESULT -CBaseOutputPin::Inactive(void) -{ - m_bRunTimeError = FALSE; - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - return m_pAllocator->Decommit(); -} - -// we have a default handling of EndOfStream which is to return -// an error, since this should be called on input pins only -STDMETHODIMP -CBaseOutputPin::EndOfStream(void) -{ - return E_UNEXPECTED; -} - - -// BeginFlush should be called on input pins only -STDMETHODIMP -CBaseOutputPin::BeginFlush(void) -{ - return E_UNEXPECTED; -} - -// EndFlush should be called on input pins only -STDMETHODIMP -CBaseOutputPin::EndFlush(void) -{ - return E_UNEXPECTED; -} - -// call BeginFlush on the connected input pin -HRESULT -CBaseOutputPin::DeliverBeginFlush(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->BeginFlush(); -} - -// call EndFlush on the connected input pin -HRESULT -CBaseOutputPin::DeliverEndFlush(void) -{ - // remember this is on IPin not IMemInputPin - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->EndFlush(); -} -// deliver NewSegment to connected pin -HRESULT -CBaseOutputPin::DeliverNewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (m_Connected == NULL) { - return VFW_E_NOT_CONNECTED; - } - return m_Connected->NewSegment(tStart, tStop, dRate); -} - - -//===================================================================== -//===================================================================== -// Implements CBaseInputPin -//===================================================================== -//===================================================================== - - -/* Constructor creates a default allocator object */ - -CBaseInputPin::CBaseInputPin(__in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pPinName) : - CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), - m_pAllocator(NULL), - m_bReadOnly(FALSE), - m_bFlushing(FALSE) -{ - ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); -} - -#ifdef UNICODE -CBaseInputPin::CBaseInputPin(__in LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pPinName) : - CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), - m_pAllocator(NULL), - m_bReadOnly(FALSE), - m_bFlushing(FALSE) -{ - ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); -} -#endif - -/* Destructor releases it's reference count on the default allocator */ - -CBaseInputPin::~CBaseInputPin() -{ - if (m_pAllocator != NULL) { - m_pAllocator->Release(); - m_pAllocator = NULL; - } -} - - -// override this to publicise our interfaces -STDMETHODIMP -CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - /* Do we know about this interface */ - - if (riid == IID_IMemInputPin) { - return GetInterface((IMemInputPin *) this, ppv); - } else { - return CBasePin::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* Return the allocator interface that this input pin would like the output - pin to use. NOTE subsequent calls to GetAllocator should all return an - interface onto the SAME object so we create one object at the start - - Note: - The allocator is Release()'d on disconnect and replaced on - NotifyAllocator(). - - Override this to provide your own allocator. -*/ - -STDMETHODIMP -CBaseInputPin::GetAllocator( - __deref_out IMemAllocator **ppAllocator) -{ - CheckPointer(ppAllocator,E_POINTER); - ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); - CAutoLock cObjectLock(m_pLock); - - if (m_pAllocator == NULL) { - HRESULT hr = CreateMemoryAllocator(&m_pAllocator); - if (FAILED(hr)) { - return hr; - } - } - ASSERT(m_pAllocator != NULL); - *ppAllocator = m_pAllocator; - m_pAllocator->AddRef(); - return NOERROR; -} - - -/* Tell the input pin which allocator the output pin is actually going to use - Override this if you care - NOTE the locking we do both here and also in - GetAllocator is unnecessary but derived classes that do something useful - will undoubtedly have to lock the object so this might help remind people */ - -STDMETHODIMP -CBaseInputPin::NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly) -{ - CheckPointer(pAllocator,E_POINTER); - ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); - CAutoLock cObjectLock(m_pLock); - - IMemAllocator *pOldAllocator = m_pAllocator; - pAllocator->AddRef(); - m_pAllocator = pAllocator; - - if (pOldAllocator != NULL) { - pOldAllocator->Release(); - } - - // the readonly flag indicates whether samples from this allocator should - // be regarded as readonly - if true, then inplace transforms will not be - // allowed. - m_bReadOnly = (BYTE)bReadOnly; - return NOERROR; -} - - -HRESULT -CBaseInputPin::BreakConnect() -{ - /* We don't need our allocator any more */ - if (m_pAllocator) { - // Always decommit the allocator because a downstream filter may or - // may not decommit the connection's allocator. A memory leak could - // occur if the allocator is not decommited when a pin is disconnected. - HRESULT hr = m_pAllocator->Decommit(); - if( FAILED( hr ) ) { - return hr; - } - - m_pAllocator->Release(); - m_pAllocator = NULL; - } - - return S_OK; -} - - -/* Do something with this media sample - this base class checks to see if the - format has changed with this media sample and if so checks that the filter - will accept it, generating a run time error if not. Once we have raised a - run time error we set a flag so that no more samples will be accepted - - It is important that any filter should override this method and implement - synchronization so that samples are not processed when the pin is - disconnected etc -*/ - -STDMETHODIMP -CBaseInputPin::Receive(IMediaSample *pSample) -{ - CheckPointer(pSample,E_POINTER); - ValidateReadPtr(pSample,sizeof(IMediaSample)); - ASSERT(pSample); - - HRESULT hr = CheckStreaming(); - if (S_OK != hr) { - return hr; - } - -#ifdef DXMPERF - PERFLOG_RECEIVE( m_pName ? m_pName : L"CBaseInputPin", (IPin *) m_Connected, (IPin *) this, pSample, &m_mt ); -#endif // DXMPERF - - - /* Check for IMediaSample2 */ - IMediaSample2 *pSample2; - if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { - hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps); - pSample2->Release(); - if (FAILED(hr)) { - return hr; - } - } else { - /* Get the properties the hard way */ - m_SampleProps.cbData = sizeof(m_SampleProps); - m_SampleProps.dwTypeSpecificFlags = 0; - m_SampleProps.dwStreamId = AM_STREAM_MEDIA; - m_SampleProps.dwSampleFlags = 0; - if (S_OK == pSample->IsDiscontinuity()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; - } - if (S_OK == pSample->IsPreroll()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL; - } - if (S_OK == pSample->IsSyncPoint()) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; - } - if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart, - &m_SampleProps.tStop))) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID | - AM_SAMPLE_STOPVALID; - } - if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) { - m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED; - } - pSample->GetPointer(&m_SampleProps.pbBuffer); - m_SampleProps.lActual = pSample->GetActualDataLength(); - m_SampleProps.cbBuffer = pSample->GetSize(); - } - - /* Has the format changed in this sample */ - - if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) { - return NOERROR; - } - - /* Check the derived class accepts this format */ - /* This shouldn't fail as the source must call QueryAccept first */ - - hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType); - - if (hr == NOERROR) { - return NOERROR; - } - - /* Raise a runtime error if we fail the media type */ - - m_bRunTimeError = TRUE; - EndOfStream(); - m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0); - return VFW_E_INVALIDMEDIATYPE; -} - - -/* Receive multiple samples */ -STDMETHODIMP -CBaseInputPin::ReceiveMultiple ( - __in_ecount(nSamples) IMediaSample **pSamples, - long nSamples, - __out long *nSamplesProcessed) -{ - CheckPointer(pSamples,E_POINTER); - ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *)); - - HRESULT hr = S_OK; - *nSamplesProcessed = 0; - while (nSamples-- > 0) { - hr = Receive(pSamples[*nSamplesProcessed]); - - /* S_FALSE means don't send any more */ - if (hr != S_OK) { - break; - } - (*nSamplesProcessed)++; - } - return hr; -} - -/* See if Receive() might block */ -STDMETHODIMP -CBaseInputPin::ReceiveCanBlock() -{ - /* Ask all the output pins if they block - If there are no output pin assume we do block - */ - int cPins = m_pFilter->GetPinCount(); - int cOutputPins = 0; - for (int c = 0; c < cPins; c++) { - CBasePin *pPin = m_pFilter->GetPin(c); - if (NULL == pPin) { - break; - } - PIN_DIRECTION pd; - HRESULT hr = pPin->QueryDirection(&pd); - if (FAILED(hr)) { - return hr; - } - - if (pd == PINDIR_OUTPUT) { - - IPin *pConnected; - hr = pPin->ConnectedTo(&pConnected); - if (SUCCEEDED(hr)) { - ASSERT(pConnected != NULL); - cOutputPins++; - IMemInputPin *pInputPin; - hr = pConnected->QueryInterface( - IID_IMemInputPin, - (void **)&pInputPin); - pConnected->Release(); - if (SUCCEEDED(hr)) { - hr = pInputPin->ReceiveCanBlock(); - pInputPin->Release(); - if (hr != S_FALSE) { - return S_OK; - } - } else { - /* There's a transport we don't understand here */ - return S_OK; - } - } - } - } - return cOutputPins == 0 ? S_OK : S_FALSE; -} - -// Default handling for BeginFlush - call at the beginning -// of your implementation (makes sure that all Receive calls -// fail). After calling this, you need to free any queued data -// and then call downstream. -STDMETHODIMP -CBaseInputPin::BeginFlush(void) -{ - // BeginFlush is NOT synchronized with streaming but is part of - // a control action - hence we synchronize with the filter - CAutoLock lck(m_pLock); - - // if we are already in mid-flush, this is probably a mistake - // though not harmful - try to pick it up for now so I can think about it - ASSERT(!m_bFlushing); - - // first thing to do is ensure that no further Receive calls succeed - m_bFlushing = TRUE; - - // now discard any data and call downstream - must do that - // in derived classes - return S_OK; -} - -// default handling for EndFlush - call at end of your implementation -// - before calling this, ensure that there is no queued data and no thread -// pushing any more without a further receive, then call downstream, -// then call this method to clear the m_bFlushing flag and re-enable -// receives -STDMETHODIMP -CBaseInputPin::EndFlush(void) -{ - // Endlush is NOT synchronized with streaming but is part of - // a control action - hence we synchronize with the filter - CAutoLock lck(m_pLock); - - // almost certainly a mistake if we are not in mid-flush - ASSERT(m_bFlushing); - - // before calling, sync with pushing thread and ensure - // no more data is going downstream, then call EndFlush on - // downstream pins. - - // now re-enable Receives - m_bFlushing = FALSE; - - // No more errors - m_bRunTimeError = FALSE; - - return S_OK; -} - - -STDMETHODIMP -CBaseInputPin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(q); - CheckPointer(pSender,E_POINTER); - ValidateReadPtr(pSender,sizeof(IBaseFilter)); - DbgBreak("IQuality::Notify called on an input pin"); - return NOERROR; -} // Notify - -/* Free up or unprepare allocator's memory, this is called through - IMediaFilter which is responsible for locking the object first */ - -HRESULT -CBaseInputPin::Inactive(void) -{ - m_bRunTimeError = FALSE; - if (m_pAllocator == NULL) { - return VFW_E_NO_ALLOCATOR; - } - - m_bFlushing = FALSE; - - return m_pAllocator->Decommit(); -} - -// what requirements do we have of the allocator - override if you want -// to support other people's allocators but need a specific alignment -// or prefix. -STDMETHODIMP -CBaseInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps) -{ - UNREFERENCED_PARAMETER(pProps); - return E_NOTIMPL; -} - -// Check if it's OK to process data -// -HRESULT -CBaseInputPin::CheckStreaming() -{ - // Shouldn't be able to get any data if we're not connected! - ASSERT(IsConnected()); - - // Don't process stuff in Stopped state - if (IsStopped()) { - return VFW_E_WRONG_STATE; - } - if (m_bFlushing) { - return S_FALSE; - } - if (m_bRunTimeError) { - return VFW_E_RUNTIME_ERROR; - } - return S_OK; -} - -// Pass on the Quality notification q to -// a. Our QualityControl sink (if we have one) or else -// b. to our upstream filter -// and if that doesn't work, throw it away with a bad return code -HRESULT -CBaseInputPin::PassNotify(Quality& q) -{ - // We pass the message on, which means that we find the quality sink - // for our input pin and send it there - - DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform"))); - if (m_pQSink!=NULL) { - return m_pQSink->Notify(m_pFilter, q); - } else { - // no sink set, so pass it upstream - HRESULT hr; - IQualityControl * pIQC; - - hr = VFW_E_NOT_FOUND; // default - if (m_Connected) { - m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC); - - if (pIQC!=NULL) { - hr = pIQC->Notify(m_pFilter, q); - pIQC->Release(); - } - } - return hr; - } - -} // PassNotify - -//===================================================================== -//===================================================================== -// Memory allocation class, implements CMediaSample -//===================================================================== -//===================================================================== - - -/* NOTE The implementation of this class calls the CUnknown constructor with - a NULL outer unknown pointer. This has the effect of making us a self - contained class, ie any QueryInterface, AddRef or Release calls will be - routed to the class's NonDelegatingUnknown methods. You will typically - find that the classes that do this then override one or more of these - virtual functions to provide more specialised behaviour. A good example - of this is where a class wants to keep the QueryInterface internal but - still wants it's lifetime controlled by the external object */ - -/* The last two parameters have default values of NULL and zero */ - -CMediaSample::CMediaSample(__in_opt LPCTSTR pName, - __in_opt CBaseAllocator *pAllocator, - __inout_opt HRESULT *phr, - __in_bcount_opt(length) LPBYTE pBuffer, - LONG length) : - m_pBuffer(pBuffer), // Initialise the buffer - m_cbBuffer(length), // And it's length - m_lActual(length), // By default, actual = length - m_pMediaType(NULL), // No media type change - m_dwFlags(0), // Nothing set - m_cRef(0), // 0 ref count - m_dwTypeSpecificFlags(0), // Type specific flags - m_dwStreamId(AM_STREAM_MEDIA), // Stream id - m_pAllocator(pAllocator), // Allocator - m_pNext(NULL), - m_Start(0), - m_End(0), - m_MediaStart(0), - m_MediaEnd(0) -{ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CMediaSample", (IMediaSample *) this ); -#endif // DXMPERF - - /* We must have an owner and it must also be derived from class - CBaseAllocator BUT we do not hold a reference count on it */ - - ASSERT(pAllocator); - - if (length < 0) { - *phr = VFW_E_BUFFER_OVERFLOW; - m_cbBuffer = 0; - } -} - -#ifdef UNICODE -CMediaSample::CMediaSample(__in_opt LPCSTR pName, - __in_opt CBaseAllocator *pAllocator, - __inout_opt HRESULT *phr, - __in_bcount_opt(length) LPBYTE pBuffer, - LONG length) : - m_pBuffer(pBuffer), // Initialise the buffer - m_cbBuffer(length), // And it's length - m_lActual(length), // By default, actual = length - m_pMediaType(NULL), // No media type change - m_dwFlags(0), // Nothing set - m_cRef(0), // 0 ref count - m_dwTypeSpecificFlags(0), // Type specific flags - m_dwStreamId(AM_STREAM_MEDIA), // Stream id - m_pAllocator(pAllocator), // Allocator - m_pNext(NULL), - m_Start(0), - m_End(0), - m_MediaStart(0), - m_MediaEnd(0) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CMediaSample", (IMediaSample *) this ); -#endif // DXMPERF - - /* We must have an owner and it must also be derived from class - CBaseAllocator BUT we do not hold a reference count on it */ - - ASSERT(pAllocator); -} -#endif - -/* Destructor deletes the media type memory */ - -CMediaSample::~CMediaSample() -{ -#ifdef DXMPERF - PERFLOG_DTOR( L"CMediaSample", (IMediaSample *) this ); -#endif // DXMPERF - - if (m_pMediaType) { - DeleteMediaType(m_pMediaType); - } -} - -/* Override this to publicise our interfaces */ - -STDMETHODIMP -CMediaSample::QueryInterface(REFIID riid, __deref_out void **ppv) -{ - if (riid == IID_IMediaSample || - riid == IID_IMediaSample2 || - riid == IID_IUnknown) { - return GetInterface((IMediaSample *) this, ppv); - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -STDMETHODIMP_(ULONG) -CMediaSample::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - - -// -- CMediaSample lifetimes -- -// -// On final release of this sample buffer it is not deleted but -// returned to the freelist of the owning memory allocator -// -// The allocator may be waiting for the last buffer to be placed on the free -// list in order to decommit all the memory, so the ReleaseBuffer() call may -// result in this sample being deleted. We also need to hold a refcount on -// the allocator to stop that going away until we have finished with this. -// However, we cannot release the allocator before the ReleaseBuffer, as the -// release may cause us to be deleted. Similarly we can't do it afterwards. -// -// Thus we must leave it to the allocator to hold an addref on our behalf. -// When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer -// is called, he releases himself, possibly causing us and him to be deleted. - - -STDMETHODIMP_(ULONG) -CMediaSample::Release() -{ - /* Decrement our own private reference count */ - LONG lRef; - if (m_cRef == 1) { - lRef = 0; - m_cRef = 0; - } else { - lRef = InterlockedDecrement(&m_cRef); - } - ASSERT(lRef >= 0); - - DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"), - this, m_cRef)); - - /* Did we release our final reference count */ - if (lRef == 0) { - /* Free all resources */ - if (m_dwFlags & Sample_TypeChanged) { - SetMediaType(NULL); - } - ASSERT(m_pMediaType == NULL); - m_dwFlags = 0; - m_dwTypeSpecificFlags = 0; - m_dwStreamId = AM_STREAM_MEDIA; - - /* This may cause us to be deleted */ - // Our refcount is reliably 0 thus no-one will mess with us - m_pAllocator->ReleaseBuffer(this); - } - return (ULONG)lRef; -} - - -// set the buffer pointer and length. Used by allocators that -// want variable sized pointers or pointers into already-read data. -// This is only available through a CMediaSample* not an IMediaSample* -// and so cannot be changed by clients. -HRESULT -CMediaSample::SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes) -{ - if (cBytes < 0) { - return VFW_E_BUFFER_OVERFLOW; - } - m_pBuffer = ptr; // new buffer area (could be null) - m_cbBuffer = cBytes; // length of buffer - m_lActual = cBytes; // length of data in buffer (assume full) - - return S_OK; -} - - -// get me a read/write pointer to this buffer's memory. I will actually -// want to use sizeUsed bytes. -STDMETHODIMP -CMediaSample::GetPointer(__deref_out BYTE ** ppBuffer) -{ - ValidateReadWritePtr(ppBuffer,sizeof(BYTE *)); - - // creator must have set pointer either during - // constructor or by SetPointer - ASSERT(m_pBuffer); - - *ppBuffer = m_pBuffer; - return NOERROR; -} - - -// return the size in bytes of this buffer -STDMETHODIMP_(LONG) -CMediaSample::GetSize(void) -{ - return m_cbBuffer; -} - - -// get the stream time at which this sample should start and finish. -STDMETHODIMP -CMediaSample::GetTime( - __out REFERENCE_TIME * pTimeStart, // put time here - __out REFERENCE_TIME * pTimeEnd -) -{ - ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME)); - ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME)); - - if (!(m_dwFlags & Sample_StopValid)) { - if (!(m_dwFlags & Sample_TimeValid)) { - return VFW_E_SAMPLE_TIME_NOT_SET; - } else { - *pTimeStart = m_Start; - - // Make sure old stuff works - *pTimeEnd = m_Start + 1; - return VFW_S_NO_STOP_TIME; - } - } - - *pTimeStart = m_Start; - *pTimeEnd = m_End; - return NOERROR; -} - - -// Set the stream time at which this sample should start and finish. -// NULL pointers means the time is reset -STDMETHODIMP -CMediaSample::SetTime( - __in_opt REFERENCE_TIME * pTimeStart, - __in_opt REFERENCE_TIME * pTimeEnd -) -{ - if (pTimeStart == NULL) { - ASSERT(pTimeEnd == NULL); - m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid); - } else { - if (pTimeEnd == NULL) { - m_Start = *pTimeStart; - m_dwFlags |= Sample_TimeValid; - m_dwFlags &= ~Sample_StopValid; - } else { - ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME)); - ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME)); - ASSERT(*pTimeEnd >= *pTimeStart); - - m_Start = *pTimeStart; - m_End = *pTimeEnd; - m_dwFlags |= Sample_TimeValid | Sample_StopValid; - } - } - return NOERROR; -} - - -// get the media times (eg bytes) for this sample -STDMETHODIMP -CMediaSample::GetMediaTime( - __out LONGLONG * pTimeStart, - __out LONGLONG * pTimeEnd -) -{ - ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG)); - ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG)); - - if (!(m_dwFlags & Sample_MediaTimeValid)) { - return VFW_E_MEDIA_TIME_NOT_SET; - } - - *pTimeStart = m_MediaStart; - *pTimeEnd = (m_MediaStart + m_MediaEnd); - return NOERROR; -} - - -// Set the media times for this sample -STDMETHODIMP -CMediaSample::SetMediaTime( - __in_opt LONGLONG * pTimeStart, - __in_opt LONGLONG * pTimeEnd -) -{ - if (pTimeStart == NULL) { - ASSERT(pTimeEnd == NULL); - m_dwFlags &= ~Sample_MediaTimeValid; - } else { - if (NULL == pTimeEnd) { - return E_POINTER; - } - ValidateReadPtr(pTimeStart,sizeof(LONGLONG)); - ValidateReadPtr(pTimeEnd,sizeof(LONGLONG)); - ASSERT(*pTimeEnd >= *pTimeStart); - - m_MediaStart = *pTimeStart; - m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart); - m_dwFlags |= Sample_MediaTimeValid; - } - return NOERROR; -} - - -STDMETHODIMP -CMediaSample::IsSyncPoint(void) -{ - if (m_dwFlags & Sample_SyncPoint) { - return S_OK; - } else { - return S_FALSE; - } -} - - -STDMETHODIMP -CMediaSample::SetSyncPoint(BOOL bIsSyncPoint) -{ - if (bIsSyncPoint) { - m_dwFlags |= Sample_SyncPoint; - } else { - m_dwFlags &= ~Sample_SyncPoint; - } - return NOERROR; -} - -// returns S_OK if there is a discontinuity in the data (this same is -// not a continuation of the previous stream of data -// - there has been a seek). -STDMETHODIMP -CMediaSample::IsDiscontinuity(void) -{ - if (m_dwFlags & Sample_Discontinuity) { - return S_OK; - } else { - return S_FALSE; - } -} - -// set the discontinuity property - TRUE if this sample is not a -// continuation, but a new sample after a seek. -STDMETHODIMP -CMediaSample::SetDiscontinuity(BOOL bDiscont) -{ - // should be TRUE or FALSE - if (bDiscont) { - m_dwFlags |= Sample_Discontinuity; - } else { - m_dwFlags &= ~Sample_Discontinuity; - } - return S_OK; -} - -STDMETHODIMP -CMediaSample::IsPreroll(void) -{ - if (m_dwFlags & Sample_Preroll) { - return S_OK; - } else { - return S_FALSE; - } -} - - -STDMETHODIMP -CMediaSample::SetPreroll(BOOL bIsPreroll) -{ - if (bIsPreroll) { - m_dwFlags |= Sample_Preroll; - } else { - m_dwFlags &= ~Sample_Preroll; - } - return NOERROR; -} - -STDMETHODIMP_(LONG) -CMediaSample::GetActualDataLength(void) -{ - return m_lActual; -} - - -STDMETHODIMP -CMediaSample::SetActualDataLength(LONG lActual) -{ - if (lActual > m_cbBuffer || lActual < 0) { - ASSERT(lActual <= GetSize()); - return VFW_E_BUFFER_OVERFLOW; - } - m_lActual = lActual; - return NOERROR; -} - - -/* These allow for limited format changes in band */ - -STDMETHODIMP -CMediaSample::GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType) -{ - ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *)); - ASSERT(ppMediaType); - - /* Do we have a new media type for them */ - - if (!(m_dwFlags & Sample_TypeChanged)) { - ASSERT(m_pMediaType == NULL); - *ppMediaType = NULL; - return S_FALSE; - } - - ASSERT(m_pMediaType); - - /* Create a copy of our media type */ - - *ppMediaType = CreateMediaType(m_pMediaType); - if (*ppMediaType == NULL) { - return E_OUTOFMEMORY; - } - return NOERROR; -} - - -/* Mark this sample as having a different format type */ - -STDMETHODIMP -CMediaSample::SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType) -{ - /* Delete the current media type */ - - if (m_pMediaType) { - DeleteMediaType(m_pMediaType); - m_pMediaType = NULL; - } - - /* Mechanism for resetting the format type */ - - if (pMediaType == NULL) { - m_dwFlags &= ~Sample_TypeChanged; - return NOERROR; - } - - ASSERT(pMediaType); - ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE)); - - /* Take a copy of the media type */ - - m_pMediaType = CreateMediaType(pMediaType); - if (m_pMediaType == NULL) { - m_dwFlags &= ~Sample_TypeChanged; - return E_OUTOFMEMORY; - } - - m_dwFlags |= Sample_TypeChanged; - return NOERROR; -} - -// Set and get properties (IMediaSample2) -STDMETHODIMP CMediaSample::GetProperties( - DWORD cbProperties, - __out_bcount(cbProperties) BYTE * pbProperties -) -{ - if (0 != cbProperties) { - CheckPointer(pbProperties, E_POINTER); - // Return generic stuff up to the length - AM_SAMPLE2_PROPERTIES Props; - Props.cbData = std::min(cbProperties, (ULONG)sizeof(Props)); - Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid; - Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags; - Props.pbBuffer = m_pBuffer; - Props.cbBuffer = m_cbBuffer; - Props.lActual = m_lActual; - Props.tStart = m_Start; - Props.tStop = m_End; - Props.dwStreamId = m_dwStreamId; - if (m_dwFlags & AM_SAMPLE_TYPECHANGED) { - Props.pMediaType = m_pMediaType; - } else { - Props.pMediaType = NULL; - } - CopyMemory(pbProperties, &Props, Props.cbData); - } - return S_OK; -} - -#define CONTAINS_FIELD(type, field, offset) \ - ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset) - -HRESULT CMediaSample::SetProperties( - DWORD cbProperties, - __in_bcount(cbProperties) const BYTE * pbProperties -) -{ - - /* Generic properties */ - AM_MEDIA_TYPE *pMediaType = NULL; - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) { - CheckPointer(pbProperties, E_POINTER); - AM_SAMPLE2_PROPERTIES *pProps = - (AM_SAMPLE2_PROPERTIES *)pbProperties; - - /* Don't use more data than is actually there */ - if (pProps->cbData < cbProperties) { - cbProperties = pProps->cbData; - } - /* We only handle IMediaSample2 */ - if (cbProperties > sizeof(*pProps) || - pProps->cbData > sizeof(*pProps)) { - return E_INVALIDARG; - } - /* Do checks first, the assignments (for backout) */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { - /* Check the flags */ - if (pProps->dwSampleFlags & - (~Sample_ValidFlags | Sample_MediaTimeValid)) { - return E_INVALIDARG; - } - /* Check a flag isn't being set for a property - not being provided - */ - if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) && - !(m_dwFlags & AM_SAMPLE_TIMEVALID) && - !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { - return E_INVALIDARG; - } - } - /* NB - can't SET the pointer or size */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) { - - /* Check pbBuffer */ - if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) { - return E_INVALIDARG; - } - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) { - - /* Check cbBuffer */ - if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) { - return E_INVALIDARG; - } - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) && - CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { - - /* Check lActual */ - if (pProps->cbBuffer < pProps->lActual) { - return E_INVALIDARG; - } - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { - - /* Check pMediaType */ - if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { - CheckPointer(pProps->pMediaType, E_POINTER); - pMediaType = CreateMediaType(pProps->pMediaType); - if (pMediaType == NULL) { - return E_OUTOFMEMORY; - } - } - } - - /* Now do the assignments */ - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) { - m_dwStreamId = pProps->dwStreamId; - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { - /* Set the flags */ - m_dwFlags = pProps->dwSampleFlags | - (m_dwFlags & Sample_MediaTimeValid); - m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - } else { - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) { - m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - } - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { - /* Set lActual */ - m_lActual = pProps->lActual; - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { - - /* Set the times */ - m_End = pProps->tStop; - } - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) { - - /* Set the times */ - m_Start = pProps->tStart; - } - - if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { - /* Set pMediaType */ - if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { - if (m_pMediaType != NULL) { - DeleteMediaType(m_pMediaType); - } - m_pMediaType = pMediaType; - } - } - - /* Fix up the type changed flag to correctly reflect the current state - If, for instance the input contained no type change but the - output does then if we don't do this we'd lose the - output media type. - */ - if (m_pMediaType) { - m_dwFlags |= Sample_TypeChanged; - } else { - m_dwFlags &= ~Sample_TypeChanged; - } - } - - return S_OK; -} - - -// -// The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(), -// IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the -// connected input pin. The application thread calls Block(). The -// following class members can only be called by the streaming thread. -// -// Deliver() -// DeliverNewSegment() -// StartUsingOutputPin() -// StopUsingOutputPin() -// ChangeOutputFormat() -// ChangeMediaType() -// DynamicReconnect() -// -// The following class members can only be called by the application thread. -// -// Block() -// SynchronousBlockOutputPin() -// AsynchronousBlockOutputPin() -// - -CDynamicOutputPin::CDynamicOutputPin( - __in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), - m_hStopEvent(NULL), - m_pGraphConfig(NULL), - m_bPinUsesReadOnlyAllocator(FALSE), - m_BlockState(NOT_BLOCKED), - m_hUnblockOutputPinEvent(NULL), - m_hNotifyCallerPinBlockedEvent(NULL), - m_dwBlockCallerThreadID(0), - m_dwNumOutstandingOutputPinUsers(0) -{ - HRESULT hr = Initialize(); - if( FAILED( hr ) ) { - *phr = hr; - return; - } -} - -#ifdef UNICODE -CDynamicOutputPin::CDynamicOutputPin( - __in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName) : - CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), - m_hStopEvent(NULL), - m_pGraphConfig(NULL), - m_bPinUsesReadOnlyAllocator(FALSE), - m_BlockState(NOT_BLOCKED), - m_hUnblockOutputPinEvent(NULL), - m_hNotifyCallerPinBlockedEvent(NULL), - m_dwBlockCallerThreadID(0), - m_dwNumOutstandingOutputPinUsers(0) -{ - HRESULT hr = Initialize(); - if( FAILED( hr ) ) { - *phr = hr; - return; - } -} -#endif - -CDynamicOutputPin::~CDynamicOutputPin() -{ - if(NULL != m_hUnblockOutputPinEvent) { - // This call should not fail because we have access to m_hUnblockOutputPinEvent - // and m_hUnblockOutputPinEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent)); - } - - if(NULL != m_hNotifyCallerPinBlockedEvent) { - // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent - // and m_hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - } -} - -HRESULT CDynamicOutputPin::Initialize(void) -{ - m_hUnblockOutputPinEvent = ::CreateEvent( NULL, // The event will have the default security descriptor. - TRUE, // This is a manual reset event. - TRUE, // The event is initially signaled. - NULL ); // The event is not named. - - // CreateEvent() returns NULL if an error occurs. - if(NULL == m_hUnblockOutputPinEvent) { - return AmGetLastErrorToHResult(); - } - - // Set flag to say we can reconnect while streaming. - SetReconnectWhenActive(true); - - return S_OK; -} - -STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - if(riid == IID_IPinFlowControl) { - return GetInterface(static_cast(this), ppv); - } else { - return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); - } -} - -STDMETHODIMP CDynamicOutputPin::Disconnect(void) -{ - CAutoLock cObjectLock(m_pLock); - return DisconnectInternal(); -} - -STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent) -{ - const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK; - - // Check for illegal flags. - if(dwBlockFlags & ~VALID_FLAGS) { - return E_INVALIDARG; - } - - // Make sure the event is unsignaled. - if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) { - if( !::ResetEvent( hEvent ) ) { - return AmGetLastErrorToHResult(); - } - } - - // No flags are set if we are unblocking the output pin. - if(0 == dwBlockFlags) { - - // This parameter should be NULL because unblock operations are always synchronous. - // There is no need to notify the caller when the event is done. - if(NULL != hEvent) { - return E_INVALIDARG; - } - } - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - HRESULT hr; - - if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) { - // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous. - // If hEvent is not NULL, the block is asynchronous. - if(NULL == hEvent) { - hr = SynchronousBlockOutputPin(); - } else { - hr = AsynchronousBlockOutputPin(hEvent); - } - } else { - hr = UnblockOutputPin(); - } - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - if(FAILED(hr)) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void) -{ - HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL, // The event will have the default security attributes. - FALSE, // This is an automatic reset event. - FALSE, // The event is initially unsignaled. - NULL ); // The event is not named. - - // CreateEvent() returns NULL if an error occurs. - if(NULL == hNotifyCallerPinBlockedEvent) { - return AmGetLastErrorToHResult(); - } - - HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent); - if(FAILED(hr)) { - // This call should not fail because we have access to hNotifyCallerPinBlockedEvent - // and hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); - - return hr; - } - - hr = WaitEvent(hNotifyCallerPinBlockedEvent); - - // This call should not fail because we have access to hNotifyCallerPinBlockedEvent - // and hNotifyCallerPinBlockedEvent is a valid event. - EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); - - if(FAILED(hr)) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent) -{ - // This function holds the m_BlockStateLock because it uses - // m_dwBlockCallerThreadID, m_BlockState and - // m_hNotifyCallerPinBlockedEvent. - CAutoLock alBlockStateLock(&m_BlockStateLock); - - if(NOT_BLOCKED != m_BlockState) { - if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) { - return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD; - } else { - return VFW_E_PIN_ALREADY_BLOCKED; - } - } - - BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(), - hNotifyCallerPinBlockedEvent, - ::GetCurrentProcess(), - &m_hNotifyCallerPinBlockedEvent, - EVENT_MODIFY_STATE, - FALSE, - 0 ); - if( !fSuccess ) { - return AmGetLastErrorToHResult(); - } - - m_BlockState = PENDING; - m_dwBlockCallerThreadID = ::GetCurrentThreadId(); - - // The output pin cannot be blocked if the streaming thread is - // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive() - // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it - // cannot be blocked if the streaming thread is calling DynamicReconnect(), - // ChangeMediaType() or ChangeOutputFormat(). - if(!StreamingThreadUsingOutputPin()) { - - // The output pin can be immediately blocked. - BlockOutputPin(); - } - - return S_OK; -} - -void CDynamicOutputPin::BlockOutputPin(void) -{ - // The caller should always hold the m_BlockStateLock because this function - // uses m_BlockState and m_hNotifyCallerPinBlockedEvent. - ASSERT(CritCheckIn(&m_BlockStateLock)); - - // This function should not be called if the streaming thread is modifying - // the connection state or it's passing data downstream. - ASSERT(!StreamingThreadUsingOutputPin()); - - // This should not fail because we successfully created the event - // and we have the security permissions to change it's state. - EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent)); - - // This event should not fail because AsynchronousBlockOutputPin() successfully - // duplicated this handle and we have the appropriate security permissions. - EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - - m_BlockState = BLOCKED; - m_hNotifyCallerPinBlockedEvent = NULL; -} - -HRESULT CDynamicOutputPin::UnblockOutputPin(void) -{ - // UnblockOutputPin() holds the m_BlockStateLock because it - // uses m_BlockState, m_dwBlockCallerThreadID and - // m_hNotifyCallerPinBlockedEvent. - CAutoLock alBlockStateLock(&m_BlockStateLock); - - if(NOT_BLOCKED == m_BlockState) { - return S_FALSE; - } - - // This should not fail because we successfully created the event - // and we have the security permissions to change it's state. - EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent)); - - // Cancel the block operation if it's still pending. - if(NULL != m_hNotifyCallerPinBlockedEvent) { - // This event should not fail because AsynchronousBlockOutputPin() successfully - // duplicated this handle and we have the appropriate security permissions. - EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); - EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); - } - - m_BlockState = NOT_BLOCKED; - m_dwBlockCallerThreadID = 0; - m_hNotifyCallerPinBlockedEvent = NULL; - - return S_OK; -} - -HRESULT CDynamicOutputPin::StartUsingOutputPin(void) -{ - // The caller should not hold m_BlockStateLock. If the caller does, - // a deadlock could occur. - ASSERT(CritCheckOut(&m_BlockStateLock)); - - CAutoLock alBlockStateLock(&m_BlockStateLock); - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - // Are we in the middle of a block operation? - while(BLOCKED == m_BlockState) { - m_BlockStateLock.Unlock(); - - // If this ASSERT fires, a deadlock could occur. The caller should make sure - // that this thread never acquires the Block State lock more than once. - ASSERT(CritCheckOut( &m_BlockStateLock )); - - // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event - // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired. - // See the Windows SDK documentation for more information on - // WaitForMultipleObjects(). - const DWORD UNBLOCK = WAIT_OBJECT_0; - const DWORD STOP = WAIT_OBJECT_0 + 1; - - HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent }; - DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE); - - DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE ); - - m_BlockStateLock.Lock(); - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - switch( dwReturnValue ) { - case UNBLOCK: - break; - - case STOP: - return VFW_E_STATE_CHANGED; - - case WAIT_FAILED: - return AmGetLastErrorToHResult(); - - default: - DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." ); - return E_UNEXPECTED; - } - } - - m_dwNumOutstandingOutputPinUsers++; - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - return S_OK; -} - -void CDynamicOutputPin::StopUsingOutputPin(void) -{ - CAutoLock alBlockStateLock(&m_BlockStateLock); - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG - - m_dwNumOutstandingOutputPinUsers--; - - if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) { - BlockOutputPin(); - } - - #ifdef _DEBUG - AssertValid(); - #endif // DEBUG -} - -bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void) -{ - CAutoLock alBlockStateLock(&m_BlockStateLock); - - return (m_dwNumOutstandingOutputPinUsers > 0); -} - -void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent) -{ - // This pointer is not addrefed because filters are not allowed to - // hold references to the filter graph manager. See the documentation for - // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information. - m_pGraphConfig = pGraphConfig; - - m_hStopEvent = hStopEvent; -} - -HRESULT CDynamicOutputPin::Active(void) -{ - // Make sure the user initialized the object by calling SetConfigInfo(). - if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) { - DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. ); - return E_FAIL; - } - - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then Active() is called. An event - // handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); - - return CBaseOutputPin::Active(); -} - -HRESULT CDynamicOutputPin::Inactive(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then Active() is called. An event - // handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(SetEvent(m_hStopEvent)); - - return CBaseOutputPin::Inactive(); -} - -HRESULT CDynamicOutputPin::DeliverBeginFlush(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. - // An event handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(SetEvent(m_hStopEvent)); - - return CBaseOutputPin::DeliverBeginFlush(); -} - -HRESULT CDynamicOutputPin::DeliverEndFlush(void) -{ - // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). - // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. - // An event handle is invalid if 1) the event does not exist or the user does not have the security - // permissions to use the event. - EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); - - return CBaseOutputPin::DeliverEndFlush(); -} - - -// ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly -// reconnects the output pin. -HRESULT CDynamicOutputPin::ChangeOutputFormat - ( - const AM_MEDIA_TYPE *pmt, - REFERENCE_TIME tSegmentStart, - REFERENCE_TIME tSegmentStop, - double dSegmentRate - ) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - // Callers should always pass a valid media type to ChangeOutputFormat() . - ASSERT(NULL != pmt); - - CMediaType cmt(*pmt); - HRESULT hr = ChangeMediaType(&cmt); - if (FAILED(hr)) { - return hr; - } - - hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate); - if( FAILED( hr ) ) { - return hr; - } - - return S_OK; -} - -HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - // This function assumes the filter graph is running. - ASSERT(!IsStopped()); - - if(!IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - /* First check if the downstream pin will accept a dynamic - format change - */ - QzCComPtr pConnection; - - m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection); - if(pConnection != NULL) { - - if(S_OK == pConnection->DynamicQueryAccept(pmt)) { - - HRESULT hr = ChangeMediaTypeHelper(pmt); - if(FAILED(hr)) { - return hr; - } - - return S_OK; - } - } - - /* Can't do the dynamic connection */ - return DynamicReconnect(pmt); -} - -HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - HRESULT hr = m_Connected->ReceiveConnection(this, pmt); - if(FAILED(hr)) { - return hr; - } - - hr = SetMediaType(pmt); - if(FAILED(hr)) { - return hr; - } - - // Does this pin use the local memory transport? - if(NULL != m_pInputPin) { - // This function assumes that m_pInputPin and m_Connected are - // two different interfaces to the same object. - ASSERT(::IsEqualObject(m_Connected, m_pInputPin)); - - ALLOCATOR_PROPERTIES apInputPinRequirements; - apInputPinRequirements.cbAlign = 0; - apInputPinRequirements.cbBuffer = 0; - apInputPinRequirements.cbPrefix = 0; - apInputPinRequirements.cBuffers = 0; - - m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements); - - // A zero allignment does not make any sense. - if(0 == apInputPinRequirements.cbAlign) { - apInputPinRequirements.cbAlign = 1; - } - - hr = m_pAllocator->Decommit(); - if(FAILED(hr)) { - return hr; - } - - hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements); - if(FAILED(hr)) { - return hr; - } - - hr = m_pAllocator->Commit(); - if(FAILED(hr)) { - return hr; - } - - hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator); - if(FAILED(hr)) { - return hr; - } - } - - return S_OK; -} - -// this method has to be called from the thread that is pushing data, -// and it's the caller's responsibility to make sure that the thread -// has no outstand samples because they cannot be delivered after a -// reconnect -// -HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt ) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) { - return E_FAIL; - } - - HRESULT hr = m_pGraphConfig->Reconnect( - this, - NULL, - pmt, - NULL, - m_hStopEvent, - AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS ); - - return hr; -} - -HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); - if(SUCCEEDED(hr)) { - if(!IsStopped() && m_pAllocator) { - hr = m_pAllocator->Commit(); - ASSERT(hr != VFW_E_ALREADY_COMMITTED); - } - } - - return hr; -} - -#ifdef _DEBUG -void CDynamicOutputPin::AssertValid(void) -{ - // Make sure the object was correctly initialized. - - // This ASSERT only fires if the object failed to initialize - // and the user ignored the constructor's return code (phr). - ASSERT(NULL != m_hUnblockOutputPinEvent); - - // If either of these ASSERTs fire, the user did not correctly call - // SetConfigInfo(). - ASSERT(NULL != m_hStopEvent); - ASSERT(NULL != m_pGraphConfig); - - // Make sure the block state is consistent. - - CAutoLock alBlockStateLock(&m_BlockStateLock); - - // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED. - ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState)); - - // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete - // immediately. - ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) || - ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) ); - - // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and - // the user is not trying to block the pin. - ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState)); - - // If this ASSERT fires, the streaming thread is using the output pin and the - // output pin is blocked. - ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) || - ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) || - ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) ); -} -#endif // DEBUG - -HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent) -{ - const DWORD EVENT_SIGNALED = WAIT_OBJECT_0; - - DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE); - - switch( dwReturnValue ) { - case EVENT_SIGNALED: - return S_OK; - - case WAIT_FAILED: - return AmGetLastErrorToHResult(); - - default: - DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." ); - return E_UNEXPECTED; - } -} - -//===================================================================== -//===================================================================== -// Implements CBaseAllocator -//===================================================================== -//===================================================================== - - -/* Constructor overrides the default settings for the free list to request - that it be alertable (ie the list can be cast to a handle which can be - passed to WaitForSingleObject). Both of the allocator lists also ask for - object locking, the all list matches the object default settings but I - have included them here just so it is obvious what kind of list it is */ - -CBaseAllocator::CBaseAllocator(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - BOOL bEvent, - BOOL fEnableReleaseCallback - ) : - CUnknown(pName, pUnk), - m_lAllocated(0), - m_bChanged(FALSE), - m_bCommitted(FALSE), - m_bDecommitInProgress(FALSE), - m_lSize(0), - m_lCount(0), - m_lAlignment(0), - m_lPrefix(0), - m_hSem(NULL), - m_lWaiting(0), - m_fEnableReleaseCallback(fEnableReleaseCallback), - m_pNotify(NULL) -{ -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBaseAllocator", (IMemAllocator *) this ); -#endif // DXMPERF - - if (bEvent) { - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - } -} - -#ifdef UNICODE -CBaseAllocator::CBaseAllocator(__in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - BOOL bEvent, - BOOL fEnableReleaseCallback) : - CUnknown(pName, pUnk), - m_lAllocated(0), - m_bChanged(FALSE), - m_bCommitted(FALSE), - m_bDecommitInProgress(FALSE), - m_lSize(0), - m_lCount(0), - m_lAlignment(0), - m_lPrefix(0), - m_hSem(NULL), - m_lWaiting(0), - m_fEnableReleaseCallback(fEnableReleaseCallback), - m_pNotify(NULL) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CBaseAllocator", (IMemAllocator *) this ); -#endif // DXMPERF - - if (bEvent) { - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - } -} -#endif - -/* Destructor */ - -CBaseAllocator::~CBaseAllocator() -{ - // we can't call Decommit here since that would mean a call to a - // pure virtual in destructor. - // We must assume that the derived class has gone into decommit state in - // its destructor. -#ifdef DXMPERF - PERFLOG_DTOR( L"CBaseAllocator", (IMemAllocator *) this ); -#endif // DXMPERF - - ASSERT(!m_bCommitted); - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } - if (m_pNotify) { - m_pNotify->Release(); - } -} - - -/* Override this to publicise our interfaces */ - -STDMETHODIMP -CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - /* Do we know about this interface */ - - if (riid == IID_IMemAllocator || - riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) { - return GetInterface((IMemAllocatorCallbackTemp *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -/* This sets the size and count of the required samples. The memory isn't - actually allocated until Commit() is called, if memory has already been - allocated then assuming no samples are outstanding the user may call us - to change the buffering, the memory will be released in Commit() */ - -STDMETHODIMP -CBaseAllocator::SetProperties( - __in ALLOCATOR_PROPERTIES* pRequest, - __out ALLOCATOR_PROPERTIES* pActual) -{ - CheckPointer(pRequest, E_POINTER); - CheckPointer(pActual, E_POINTER); - ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES)); - CAutoLock cObjectLock(this); - - ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); - - ASSERT(pRequest->cbBuffer > 0); - - /* Check the alignment requested */ - if (pRequest->cbAlign != 1) { - DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"), - pRequest->cbAlign)); - return VFW_E_BADALIGN; - } - - /* Can't do this if already committed, there is an argument that says we - should not reject the SetProperties call if there are buffers still - active. However this is called by the source filter, which is the same - person who is holding the samples. Therefore it is not unreasonable - for them to free all their samples before changing the requirements */ - - if (m_bCommitted) { - return VFW_E_ALREADY_COMMITTED; - } - - /* Must be no outstanding buffers */ - - if (m_lAllocated != m_lFree.GetCount()) { - return VFW_E_BUFFERS_OUTSTANDING; - } - - /* There isn't any real need to check the parameters as they - will just be rejected when the user finally calls Commit */ - - pActual->cbBuffer = m_lSize = pRequest->cbBuffer; - pActual->cBuffers = m_lCount = pRequest->cBuffers; - pActual->cbAlign = m_lAlignment = pRequest->cbAlign; - pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; - - m_bChanged = TRUE; - return NOERROR; -} - -STDMETHODIMP -CBaseAllocator::GetProperties( - __out ALLOCATOR_PROPERTIES * pActual) -{ - CheckPointer(pActual,E_POINTER); - ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); - - CAutoLock cObjectLock(this); - pActual->cbBuffer = m_lSize; - pActual->cBuffers = m_lCount; - pActual->cbAlign = m_lAlignment; - pActual->cbPrefix = m_lPrefix; - return NOERROR; -} - -// get container for a sample. Blocking, synchronous call to get the -// next free buffer (as represented by an IMediaSample interface). -// on return, the time etc properties will be invalid, but the buffer -// pointer and size will be correct. - -HRESULT CBaseAllocator::GetBuffer(__deref_out IMediaSample **ppBuffer, - __in_opt REFERENCE_TIME *pStartTime, - __in_opt REFERENCE_TIME *pEndTime, - DWORD dwFlags - ) -{ - UNREFERENCED_PARAMETER(pStartTime); - UNREFERENCED_PARAMETER(pEndTime); - UNREFERENCED_PARAMETER(dwFlags); - CMediaSample *pSample; - - *ppBuffer = NULL; - for (;;) - { - { // scope for lock - CAutoLock cObjectLock(this); - - /* Check we are committed */ - if (!m_bCommitted) { - return VFW_E_NOT_COMMITTED; - } - pSample = (CMediaSample *) m_lFree.RemoveHead(); - if (pSample == NULL) { - SetWaiting(); - } - } - - /* If we didn't get a sample then wait for the list to signal */ - - if (pSample) { - break; - } - if (dwFlags & AM_GBF_NOWAIT) { - return VFW_E_TIMEOUT; - } - ASSERT(m_hSem != NULL); - WaitForSingleObject(m_hSem, INFINITE); - } - - /* Addref the buffer up to one. On release - back to zero instead of being deleted, it will requeue itself by - calling the ReleaseBuffer member function. NOTE the owner of a - media sample must always be derived from CBaseAllocator */ - - - ASSERT(pSample->m_cRef == 0); - pSample->m_cRef = 1; - *ppBuffer = pSample; - -#ifdef DXMPERF - PERFLOG_GETBUFFER( (IMemAllocator *) this, pSample ); -#endif // DXMPERF - - return NOERROR; -} - - -/* Final release of a CMediaSample will call this */ - -STDMETHODIMP -CBaseAllocator::ReleaseBuffer(IMediaSample * pSample) -{ - CheckPointer(pSample,E_POINTER); - ValidateReadPtr(pSample,sizeof(IMediaSample)); - -#ifdef DXMPERF - PERFLOG_RELBUFFER( (IMemAllocator *) this, pSample ); -#endif // DXMPERF - - - BOOL bRelease = FALSE; - { - CAutoLock cal(this); - - /* Put back on the free list */ - - m_lFree.Add((CMediaSample *)pSample); - if (m_lWaiting != 0) { - NotifySample(); - } - - // if there is a pending Decommit, then we need to complete it by - // calling Free() when the last buffer is placed on the free list - - LONG l1 = m_lFree.GetCount(); - if (m_bDecommitInProgress && (l1 == m_lAllocated)) { - Free(); - m_bDecommitInProgress = FALSE; - bRelease = TRUE; - } - } - - if (m_pNotify) { - - ASSERT(m_fEnableReleaseCallback); - - // - // Note that this is not synchronized with setting up a notification - // method. - // - m_pNotify->NotifyRelease(); - } - - /* For each buffer there is one AddRef, made in GetBuffer and released - here. This may cause the allocator and all samples to be deleted */ - - if (bRelease) { - Release(); - } - return NOERROR; -} - -STDMETHODIMP -CBaseAllocator::SetNotify( - IMemAllocatorNotifyCallbackTemp* pNotify - ) -{ - ASSERT(m_fEnableReleaseCallback); - CAutoLock lck(this); - if (pNotify) { - pNotify->AddRef(); - } - if (m_pNotify) { - m_pNotify->Release(); - } - m_pNotify = pNotify; - return S_OK; -} - -STDMETHODIMP -CBaseAllocator::GetFreeCount( - __out LONG* plBuffersFree - ) -{ - ASSERT(m_fEnableReleaseCallback); - CAutoLock cObjectLock(this); - *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount(); - return NOERROR; -} - -void -CBaseAllocator::NotifySample() -{ - if (m_lWaiting != 0) { - ASSERT(m_hSem != NULL); - ReleaseSemaphore(m_hSem, m_lWaiting, 0); - m_lWaiting = 0; - } -} - -STDMETHODIMP -CBaseAllocator::Commit() -{ - /* Check we are not decommitted */ - CAutoLock cObjectLock(this); - - // cannot need to alloc or re-alloc if we are committed - if (m_bCommitted) { - return NOERROR; - } - - /* Allow GetBuffer calls */ - - m_bCommitted = TRUE; - - // is there a pending decommit ? if so, just cancel it - if (m_bDecommitInProgress) { - m_bDecommitInProgress = FALSE; - - // don't call Alloc at this point. He cannot allow SetProperties - // between Decommit and the last free, so the buffer size cannot have - // changed. And because some of the buffers are not free yet, he - // cannot re-alloc anyway. - return NOERROR; - } - - DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize)); - - // actually need to allocate the samples - HRESULT hr = Alloc(); - if (FAILED(hr)) { - m_bCommitted = FALSE; - return hr; - } - AddRef(); - return NOERROR; -} - - -STDMETHODIMP -CBaseAllocator::Decommit() -{ - BOOL bRelease = FALSE; - { - /* Check we are not already decommitted */ - CAutoLock cObjectLock(this); - if (m_bCommitted == FALSE) { - if (m_bDecommitInProgress == FALSE) { - return NOERROR; - } - } - - /* No more GetBuffer calls will succeed */ - m_bCommitted = FALSE; - - // are any buffers outstanding? - if (m_lFree.GetCount() < m_lAllocated) { - // please complete the decommit when last buffer is freed - m_bDecommitInProgress = TRUE; - } else { - m_bDecommitInProgress = FALSE; - - // need to complete the decommit here as there are no - // outstanding buffers - - Free(); - bRelease = TRUE; - } - - // Tell anyone waiting that they can go now so we can - // reject their call -#pragma warning(push) -#ifndef _PREFAST_ -#pragma warning(disable:4068) -#endif -#pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "Suppress warning related to Free() invalidating 'this' which is no applicable to CBaseAllocator::Free()") - NotifySample(); - -#pragma warning(pop) - } - - if (bRelease) { - Release(); - } - return NOERROR; -} - - -/* Base definition of allocation which checks we are ok to go ahead and do - the full allocation. We return S_FALSE if the requirements are the same */ - -HRESULT -CBaseAllocator::Alloc(void) -{ - /* Error if he hasn't set the size yet */ - if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) { - return VFW_E_SIZENOTSET; - } - - /* should never get here while buffers outstanding */ - ASSERT(m_lFree.GetCount() == m_lAllocated); - - /* If the requirements haven't changed then don't reallocate */ - if (m_bChanged == FALSE) { - return S_FALSE; - } - - return NOERROR; -} - -/* Implement CBaseAllocator::CSampleList::Remove(pSample) - Removes pSample from the list -*/ -void -CBaseAllocator::CSampleList::Remove(__inout CMediaSample * pSample) -{ - CMediaSample **pSearch; - for (pSearch = &m_List; - *pSearch != NULL; - pSearch = &(CBaseAllocator::NextSample(*pSearch))) { - if (*pSearch == pSample) { - *pSearch = CBaseAllocator::NextSample(pSample); - CBaseAllocator::NextSample(pSample) = NULL; - m_nOnList--; - return; - } - } - DbgBreak("Couldn't find sample in list"); -} - -//===================================================================== -//===================================================================== -// Implements CMemAllocator -//===================================================================== -//===================================================================== - - -/* This goes in the factory template table to create new instances */ -CUnknown *CMemAllocator::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) -{ - CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr); - return pUnkRet; -} - -CMemAllocator::CMemAllocator( - __in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr) - : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), - m_pBuffer(NULL) -{ -} - -#ifdef UNICODE -CMemAllocator::CMemAllocator( - __in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr) - : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), - m_pBuffer(NULL) -{ -} -#endif - -/* This sets the size and count of the required samples. The memory isn't - actually allocated until Commit() is called, if memory has already been - allocated then assuming no samples are outstanding the user may call us - to change the buffering, the memory will be released in Commit() */ -STDMETHODIMP -CMemAllocator::SetProperties( - __in ALLOCATOR_PROPERTIES* pRequest, - __out ALLOCATOR_PROPERTIES* pActual) -{ - CheckPointer(pActual,E_POINTER); - ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); - CAutoLock cObjectLock(this); - - ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); - - ASSERT(pRequest->cbBuffer > 0); - - SYSTEM_INFO SysInfo; - GetSystemInfo(&SysInfo); - - /* Check the alignment request is a power of 2 */ - if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) { - DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"), - pRequest->cbAlign)); - } - /* Check the alignment requested */ - if (pRequest->cbAlign == 0 || - (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) { - DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"), - pRequest->cbAlign, SysInfo.dwAllocationGranularity)); - return VFW_E_BADALIGN; - } - - /* Can't do this if already committed, there is an argument that says we - should not reject the SetProperties call if there are buffers still - active. However this is called by the source filter, which is the same - person who is holding the samples. Therefore it is not unreasonable - for them to free all their samples before changing the requirements */ - - if (m_bCommitted == TRUE) { - return VFW_E_ALREADY_COMMITTED; - } - - /* Must be no outstanding buffers */ - - if (m_lFree.GetCount() < m_lAllocated) { - return VFW_E_BUFFERS_OUTSTANDING; - } - - /* There isn't any real need to check the parameters as they - will just be rejected when the user finally calls Commit */ - - // round length up to alignment - remember that prefix is included in - // the alignment - LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix; - LONG lRemainder = lSize % pRequest->cbAlign; - if (lRemainder != 0) { - lSize = lSize - lRemainder + pRequest->cbAlign; - } - pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix); - - pActual->cBuffers = m_lCount = pRequest->cBuffers; - pActual->cbAlign = m_lAlignment = pRequest->cbAlign; - pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; - - m_bChanged = TRUE; - return NOERROR; -} - -// override this to allocate our resources when Commit is called. -// -// note that our resources may be already allocated when this is called, -// since we don't free them on Decommit. We will only be called when in -// decommit state with all buffers free. -// -// object locked by caller -HRESULT -CMemAllocator::Alloc(void) -{ - CAutoLock lck(this); - - /* Check he has called SetProperties */ - HRESULT hr = CBaseAllocator::Alloc(); - if (FAILED(hr)) { - return hr; - } - - /* If the requirements haven't changed then don't reallocate */ - if (hr == S_FALSE) { - ASSERT(m_pBuffer); - return NOERROR; - } - ASSERT(hr == S_OK); // we use this fact in the loop below - - /* Free the old resources */ - if (m_pBuffer) { - ReallyFree(); - } - - /* Make sure we've got reasonable values */ - if ( m_lSize < 0 || m_lPrefix < 0 || m_lCount < 0 ) { - return E_OUTOFMEMORY; - } - - /* Compute the aligned size */ - LONG lAlignedSize = m_lSize + m_lPrefix; - - /* Check overflow */ - if (lAlignedSize < m_lSize) { - return E_OUTOFMEMORY; - } - - if (m_lAlignment > 1) { - LONG lRemainder = lAlignedSize % m_lAlignment; - if (lRemainder != 0) { - LONG lNewSize = lAlignedSize + m_lAlignment - lRemainder; - if (lNewSize < lAlignedSize) { - return E_OUTOFMEMORY; - } - lAlignedSize = lNewSize; - } - } - - /* Create the contiguous memory block for the samples - making sure it's properly aligned (64K should be enough!) - */ - ASSERT(lAlignedSize % m_lAlignment == 0); - - LONGLONG lToAllocate = m_lCount * (LONGLONG)lAlignedSize; - - /* Check overflow */ - if (lToAllocate > MAXLONG) { - return E_OUTOFMEMORY; - } - - m_pBuffer = (PBYTE)VirtualAlloc(NULL, - (LONG)lToAllocate, - MEM_COMMIT, - PAGE_READWRITE); - - if (m_pBuffer == NULL) { - return E_OUTOFMEMORY; - } - - LPBYTE pNext = m_pBuffer; - CMediaSample *pSample; - - ASSERT(m_lAllocated == 0); - - // Create the new samples - we have allocated m_lSize bytes for each sample - // plus m_lPrefix bytes per sample as a prefix. We set the pointer to - // the memory after the prefix - so that GetPointer() will return a pointer - // to m_lSize bytes. - for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { - - - pSample = new CMediaSample( - NAME("Default memory media sample"), - this, - &hr, - pNext + m_lPrefix, // GetPointer() value - m_lSize); // not including prefix - - ASSERT(SUCCEEDED(hr)); - if (pSample == NULL) { - return E_OUTOFMEMORY; - } - - // This CANNOT fail - m_lFree.Add(pSample); - } - - m_bChanged = FALSE; - return NOERROR; -} - - -// override this to free up any resources we have allocated. -// called from the base class on Decommit when all buffers have been -// returned to the free list. -// -// caller has already locked the object. - -// in our case, we keep the memory until we are deleted, so -// we do nothing here. The memory is deleted in the destructor by -// calling ReallyFree() -void -CMemAllocator::Free(void) -{ - return; -} - - -// called from the destructor (and from Alloc if changing size/count) to -// actually free up the memory -void -CMemAllocator::ReallyFree(void) -{ - /* Should never be deleting this unless all buffers are freed */ - - ASSERT(m_lAllocated == m_lFree.GetCount()); - - /* Free up all the CMediaSamples */ - - CMediaSample *pSample; - for (;;) { - pSample = m_lFree.RemoveHead(); - if (pSample != NULL) { - delete pSample; - } else { - break; - } - } - - m_lAllocated = 0; - - // free the block of buffer memory - if (m_pBuffer) { - EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE)); - m_pBuffer = NULL; - } -} - - -/* Destructor frees our memory resources */ - -CMemAllocator::~CMemAllocator() -{ - Decommit(); - ReallyFree(); -} - -// ------------------------------------------------------------------------ -// filter registration through IFilterMapper. used if IFilterMapper is -// not found (Quartz 1.0 install) - -STDAPI -AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper * pIFM - , BOOL bRegister ) -{ - DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - - // unregister filter - // (as pins are subkeys of filter's CLSID key - // they do not need to be removed separately). - // - DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); - HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) ); - - - if( bRegister ) - { - // register filter - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); - hr = pIFM->RegisterFilter( *(psetupdata->clsID) - , psetupdata->strName - , psetupdata->dwMerit ); - if( SUCCEEDED(hr) ) - { - // all its pins - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins"))); - for( UINT m1=0; m1 < psetupdata->nPins; m1++ ) - { - hr = pIFM->RegisterPin( *(psetupdata->clsID) - , psetupdata->lpPin[m1].strName - , psetupdata->lpPin[m1].bRendered - , psetupdata->lpPin[m1].bOutput - , psetupdata->lpPin[m1].bZero - , psetupdata->lpPin[m1].bMany - , *(psetupdata->lpPin[m1].clsConnectsToFilter) - , psetupdata->lpPin[m1].strConnectsToPin ); - - if( SUCCEEDED(hr) ) - { - // and each pin's media types - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types"))); - for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ ) - { - hr = pIFM->RegisterPinType( *(psetupdata->clsID) - , psetupdata->lpPin[m1].strName - , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType) - , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) ); - if( FAILED(hr) ) break; - } - if( FAILED(hr) ) break; - } - if( FAILED(hr) ) break; - } - } - } - - // handle one acceptable "error" - that - // of filter not being registered! - // (couldn't find a suitable #define'd - // name for the error!) - // - if( 0x80070002 == hr) - return NOERROR; - else - return hr; -} - -// Remove warnings about unreferenced inline functions -#pragma warning(disable:4514) - +//------------------------------------------------------------------------------ +// File: AMFilter.cpp +// +// Desc: DirectShow base classes - implements class hierarchy for streams +// architecture. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +//===================================================================== +//===================================================================== +// The following classes are declared in this header: +// +// +// CBaseMediaFilter Basic IMediaFilter support (abstract class) +// CBaseFilter Support for IBaseFilter (incl. IMediaFilter) +// CEnumPins Enumerate input and output pins +// CEnumMediaTypes Enumerate the preferred pin formats +// CBasePin Abstract base class for IPin interface +// CBaseOutputPin Adds data provider member functions +// CBaseInputPin Implements IMemInputPin interface +// CMediaSample Basic transport unit for IMemInputPin +// CBaseAllocator General list guff for most allocators +// CMemAllocator Implements memory buffer allocation +// +//===================================================================== +//===================================================================== + +#include "streams.h" +#include + +#ifdef DXMPERF +#include "dxmperf.h" +#endif // DXMPERF + + +//===================================================================== +// Helpers +//===================================================================== +STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator) +{ + return CoCreateInstance(CLSID_MemoryAllocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IMemAllocator, + (void **)ppAllocator); +} + +// Put this one here rather than in ctlutil.cpp to avoid linking +// anything brought in by ctlutil.cpp +STDAPI CreatePosPassThru( + __in_opt LPUNKNOWN pAgg, + BOOL bRenderer, + IPin *pPin, + __deref_out IUnknown **ppPassThru +) +{ + *ppPassThru = NULL; + IUnknown *pUnkSeek; + HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru, + pAgg, + CLSCTX_INPROC_SERVER, + IID_IUnknown, + (void **)&pUnkSeek + ); + if (FAILED(hr)) { + return hr; + } + + ISeekingPassThru *pPassThru; + hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru); + if (FAILED(hr)) { + pUnkSeek->Release(); + return hr; + } + hr = pPassThru->Init(bRenderer, pPin); + pPassThru->Release(); + if (FAILED(hr)) { + pUnkSeek->Release(); + return hr; + } + *ppPassThru = pUnkSeek; + return S_OK; +} + + + +#define CONNECT_TRACE_LEVEL 3 + +//===================================================================== +//===================================================================== +// Implements CBaseMediaFilter +//===================================================================== +//===================================================================== + + +/* Constructor */ + +CBaseMediaFilter::CBaseMediaFilter(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid) : + CUnknown(pName, pUnk), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL) +{ +} + + +/* Destructor */ + +CBaseMediaFilter::~CBaseMediaFilter() +{ + // must be stopped, but can't call Stop here since + // our critsec has been destroyed. + + /* Release any clock we were using */ + + if (m_pClock) { + m_pClock->Release(); + m_pClock = NULL; + } +} + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP +CBaseMediaFilter::NonDelegatingQueryInterface( + REFIID riid, + __deref_out void ** ppv) +{ + if (riid == IID_IMediaFilter) { + return GetInterface((IMediaFilter *) this, ppv); + } else if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + +/* Return the filter's clsid */ +STDMETHODIMP +CBaseMediaFilter::GetClassID(__out CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = m_clsid; + return NOERROR; +} + +/* Override this if your state changes are not done synchronously */ + +STDMETHODIMP +CBaseMediaFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State) +{ + UNREFERENCED_PARAMETER(dwMSecs); + CheckPointer(State,E_POINTER); + ValidateReadWritePtr(State,sizeof(FILTER_STATE)); + + *State = m_State; + return S_OK; +} + + +/* Set the clock we will use for synchronisation */ + +STDMETHODIMP +CBaseMediaFilter::SetSyncSource(__inout_opt IReferenceClock *pClock) +{ + CAutoLock cObjectLock(m_pLock); + + // Ensure the new one does not go away - even if the same as the old + if (pClock) { + pClock->AddRef(); + } + + // if we have a clock, release it + if (m_pClock) { + m_pClock->Release(); + } + + // Set the new reference clock (might be NULL) + // Should we query it to ensure it is a clock? Consider for a debug build. + m_pClock = pClock; + + return NOERROR; +} + +/* Return the clock we are using for synchronisation */ +STDMETHODIMP +CBaseMediaFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock) +{ + CheckPointer(pClock,E_POINTER); + ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pClock) { + // returning an interface... addref it... + m_pClock->AddRef(); + } + *pClock = (IReferenceClock*)m_pClock; + return NOERROR; +} + + +/* Put the filter into a stopped state */ + +STDMETHODIMP +CBaseMediaFilter::Stop() +{ + CAutoLock cObjectLock(m_pLock); + + m_State = State_Stopped; + return S_OK; +} + + +/* Put the filter into a paused state */ + +STDMETHODIMP +CBaseMediaFilter::Pause() +{ + CAutoLock cObjectLock(m_pLock); + + m_State = State_Paused; + return S_OK; +} + + +// Put the filter into a running state. + +// The time parameter is the offset to be added to the samples' +// stream time to get the reference time at which they should be presented. +// +// you can either add these two and compare it against the reference clock, +// or you can call CBaseMediaFilter::StreamTime and compare that against +// the sample timestamp. + +STDMETHODIMP +CBaseMediaFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cObjectLock(m_pLock); + + // remember the stream time offset + m_tStart = tStart; + + if (m_State == State_Stopped){ + HRESULT hr = Pause(); + + if (FAILED(hr)) { + return hr; + } + } + m_State = State_Running; + return S_OK; +} + + +// +// return the current stream time - samples with start timestamps of this +// time or before should be rendered by now +HRESULT +CBaseMediaFilter::StreamTime(CRefTime& rtStream) +{ + // Caller must lock for synchronization + // We can't grab the filter lock because we want to be able to call + // this from worker threads without deadlocking + + if (m_pClock == NULL) { + return VFW_E_NO_CLOCK; + } + + // get the current reference time + HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); + if (FAILED(hr)) { + return hr; + } + + // subtract the stream offset to get stream time + rtStream -= m_tStart; + + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CBaseFilter +//===================================================================== +//===================================================================== + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid, + __deref_out void **ppv) +{ + /* Do we have this interface */ + + if (riid == IID_IBaseFilter) { + return GetInterface((IBaseFilter *) this, ppv); + } else if (riid == IID_IMediaFilter) { + return GetInterface((IMediaFilter *) this, ppv); + } else if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); + } else if (riid == IID_IAMovieSetup) { + return GetInterface((IAMovieSetup *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + +#ifdef _DEBUG +STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease() +{ + if (m_cRef == 1) { + KASSERT(m_pGraph == NULL); + } + return CUnknown::NonDelegatingRelease(); +} +#endif + + +/* Constructor */ + +CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + ASSERT(pLock != NULL); +} + +/* Passes in a redundant HRESULT argument */ + +CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid, + __inout HRESULT *phr) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + ASSERT(pLock != NULL); + UNREFERENCED_PARAMETER(phr); +} + +#ifdef UNICODE +CBaseFilter::CBaseFilter(__in_opt LPCSTR pName, + __in_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + ASSERT(pLock != NULL); +} +CBaseFilter::CBaseFilter(__in_opt LPCSTR pName, + __in_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid, + __inout HRESULT *phr) : + CUnknown( pName, pUnk ), + m_pLock(pLock), + m_clsid(clsid), + m_State(State_Stopped), + m_pClock(NULL), + m_pGraph(NULL), + m_pSink(NULL), + m_pName(NULL), + m_PinVersion(1) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + ASSERT(pLock != NULL); + UNREFERENCED_PARAMETER(phr); +} +#endif + +/* Destructor */ + +CBaseFilter::~CBaseFilter() +{ +#ifdef DXMPERF + PERFLOG_DTOR( L"CBaseFilter", (IBaseFilter *) this ); +#endif // DXMPERF + + // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink + // When we did we had the circular reference problem. Nothing would go away. + + delete[] m_pName; + + // must be stopped, but can't call Stop here since + // our critsec has been destroyed. + + /* Release any clock we were using */ + if (m_pClock) { + m_pClock->Release(); + m_pClock = NULL; + } +} + +/* Return the filter's clsid */ +STDMETHODIMP +CBaseFilter::GetClassID(__out CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = m_clsid; + return NOERROR; +} + +/* Override this if your state changes are not done synchronously */ +STDMETHODIMP +CBaseFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State) +{ + UNREFERENCED_PARAMETER(dwMSecs); + CheckPointer(State,E_POINTER); + ValidateReadWritePtr(State,sizeof(FILTER_STATE)); + + *State = m_State; + return S_OK; +} + + +/* Set the clock we will use for synchronisation */ + +STDMETHODIMP +CBaseFilter::SetSyncSource(__in_opt IReferenceClock *pClock) +{ + CAutoLock cObjectLock(m_pLock); + + // Ensure the new one does not go away - even if the same as the old + if (pClock) { + pClock->AddRef(); + } + + // if we have a clock, release it + if (m_pClock) { + m_pClock->Release(); + } + + // Set the new reference clock (might be NULL) + // Should we query it to ensure it is a clock? Consider for a debug build. + m_pClock = pClock; + + return NOERROR; +} + +/* Return the clock we are using for synchronisation */ +STDMETHODIMP +CBaseFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock) +{ + CheckPointer(pClock,E_POINTER); + ValidateReadWritePtr(pClock,sizeof(IReferenceClock *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pClock) { + // returning an interface... addref it... + m_pClock->AddRef(); + } + *pClock = (IReferenceClock*)m_pClock; + return NOERROR; +} + + + +// override CBaseMediaFilter Stop method, to deactivate any pins this +// filter has. +STDMETHODIMP +CBaseFilter::Stop() +{ + CAutoLock cObjectLock(m_pLock); + HRESULT hr = NOERROR; + + // notify all pins of the state change + if (m_State != State_Stopped) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + if (NULL == pPin) { + break; + } + + // Disconnected pins are not activated - this saves pins worrying + // about this state themselves. We ignore the return code to make + // sure everyone is inactivated regardless. The base input pin + // class can return an error if it has no allocator but Stop can + // be used to resync the graph state after something has gone bad + + if (pPin->IsConnected()) { + HRESULT hrTmp = pPin->Inactive(); + if (FAILED(hrTmp) && SUCCEEDED(hr)) { + hr = hrTmp; + } + } + } + } + +#ifdef DXMPERF + PERFLOG_STOP( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State ); +#endif // DXMPERF + + m_State = State_Stopped; + return hr; +} + + +// override CBaseMediaFilter Pause method to activate any pins +// this filter has (also called from Run) + +STDMETHODIMP +CBaseFilter::Pause() +{ + CAutoLock cObjectLock(m_pLock); + + // notify all pins of the change to active state + if (m_State == State_Stopped) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + if (NULL == pPin) { + break; + } + + // Disconnected pins are not activated - this saves pins + // worrying about this state themselves + + if (pPin->IsConnected()) { + HRESULT hr = pPin->Active(); + if (FAILED(hr)) { + return hr; + } + } + } + } + + +#ifdef DXMPERF + PERFLOG_PAUSE( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State ); +#endif // DXMPERF + + m_State = State_Paused; + return S_OK; +} + +// Put the filter into a running state. + +// The time parameter is the offset to be added to the samples' +// stream time to get the reference time at which they should be presented. +// +// you can either add these two and compare it against the reference clock, +// or you can call CBaseFilter::StreamTime and compare that against +// the sample timestamp. + +STDMETHODIMP +CBaseFilter::Run(REFERENCE_TIME tStart) +{ + CAutoLock cObjectLock(m_pLock); + + // remember the stream time offset + m_tStart = tStart; + + if (m_State == State_Stopped){ + HRESULT hr = Pause(); + + if (FAILED(hr)) { + return hr; + } + } + // notify all pins of the change to active state + if (m_State != State_Running) { + int cPins = GetPinCount(); + for (int c = 0; c < cPins; c++) { + + CBasePin *pPin = GetPin(c); + if (NULL == pPin) { + break; + } + + // Disconnected pins are not activated - this saves pins + // worrying about this state themselves + + if (pPin->IsConnected()) { + HRESULT hr = pPin->Run(tStart); + if (FAILED(hr)) { + return hr; + } + } + } + } + +#ifdef DXMPERF + PERFLOG_RUN( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, tStart, m_State ); +#endif // DXMPERF + + m_State = State_Running; + return S_OK; +} + +// +// return the current stream time - samples with start timestamps of this +// time or before should be rendered by now +HRESULT +CBaseFilter::StreamTime(CRefTime& rtStream) +{ + // Caller must lock for synchronization + // We can't grab the filter lock because we want to be able to call + // this from worker threads without deadlocking + + if (m_pClock == NULL) { + return VFW_E_NO_CLOCK; + } + + // get the current reference time + HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream); + if (FAILED(hr)) { + return hr; + } + + // subtract the stream offset to get stream time + rtStream -= m_tStart; + + return S_OK; +} + + +/* Create an enumerator for the pins attached to this filter */ + +STDMETHODIMP +CBaseFilter::EnumPins(__deref_out IEnumPins **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); + + /* Create a new ref counted enumerator */ + + *ppEnum = new CEnumPins(this, + NULL); + + return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR; +} + + +// default behaviour of FindPin is to assume pins are named +// by their pin names +STDMETHODIMP +CBaseFilter::FindPin( + LPCWSTR Id, + __deref_out IPin ** ppPin +) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + + // We're going to search the pin list so maintain integrity + CAutoLock lck(m_pLock); + int iCount = GetPinCount(); + for (int i = 0; i < iCount; i++) { + CBasePin *pPin = GetPin(i); + if (NULL == pPin) { + break; + } + + if (0 == lstrcmpW(pPin->Name(), Id)) { + // Found one that matches + // + // AddRef() and return it + *ppPin = pPin; + pPin->AddRef(); + return S_OK; + } + } + *ppPin = NULL; + return VFW_E_NOT_FOUND; +} + +/* Return information about this filter */ + +STDMETHODIMP +CBaseFilter::QueryFilterInfo(__out FILTER_INFO * pInfo) +{ + CheckPointer(pInfo,E_POINTER); + ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO)); + + if (m_pName) { + (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); + } else { + pInfo->achName[0] = L'\0'; + } + pInfo->pGraph = m_pGraph; + if (m_pGraph) + m_pGraph->AddRef(); + return NOERROR; +} + + +/* Provide the filter with a filter graph */ + +STDMETHODIMP +CBaseFilter::JoinFilterGraph( + __inout_opt IFilterGraph * pGraph, + __in_opt LPCWSTR pName) +{ + CAutoLock cObjectLock(m_pLock); + + // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink) + + m_pGraph = pGraph; + if (m_pGraph) { + HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink, + (void**) &m_pSink); + if (FAILED(hr)) { + ASSERT(m_pSink == NULL); + } + else m_pSink->Release(); // we do NOT keep a reference on it. + } else { + // if graph pointer is null, then we should + // also release the IMediaEventSink on the same object - we don't + // refcount it, so just set it to null + m_pSink = NULL; + } + + + if (m_pName) { + delete[] m_pName; + m_pName = NULL; + } + + if (pName) { + size_t namelen; + HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &namelen); + if (FAILED(hr)) { + return hr; + } + m_pName = new WCHAR[namelen + 1]; + if (m_pName) { + (void)StringCchCopyW(m_pName, namelen + 1, pName); + } else { + return E_OUTOFMEMORY; + } + } + +#ifdef DXMPERF + PERFLOG_JOINGRAPH( m_pName ? m_pName : L"CBaseFilter",(IBaseFilter *) this, pGraph ); +#endif // DXMPERF + + return NOERROR; +} + + +// return a Vendor information string. Optional - may return E_NOTIMPL. +// memory returned should be freed using CoTaskMemFree +// default implementation returns E_NOTIMPL +STDMETHODIMP +CBaseFilter::QueryVendorInfo( + __deref_out LPWSTR* pVendorInfo) +{ + UNREFERENCED_PARAMETER(pVendorInfo); + return E_NOTIMPL; +} + + +// send an event notification to the filter graph if we know about it. +// returns S_OK if delivered, S_FALSE if the filter graph does not sink +// events, or an error otherwise. +HRESULT +CBaseFilter::NotifyEvent( + long EventCode, + LONG_PTR EventParam1, + LONG_PTR EventParam2) +{ + // Snapshot so we don't have to lock up + IMediaEventSink *pSink = m_pSink; + if (pSink) { + if (EC_COMPLETE == EventCode) { + EventParam2 = (LONG_PTR)(IBaseFilter*)this; + } + + return pSink->Notify(EventCode, EventParam1, EventParam2); + } else { + return E_NOTIMPL; + } +} + +// Request reconnect +// pPin is the pin to reconnect +// pmt is the type to reconnect with - can be NULL +// Calls ReconnectEx on the filter graph +HRESULT +CBaseFilter::ReconnectPin( + IPin *pPin, + __in_opt AM_MEDIA_TYPE const *pmt +) +{ + IFilterGraph2 *pGraph2; + if (m_pGraph != NULL) { + HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2); + if (SUCCEEDED(hr)) { + hr = pGraph2->ReconnectEx(pPin, pmt); + pGraph2->Release(); + return hr; + } else { + return m_pGraph->Reconnect(pPin); + } + } else { + return E_NOINTERFACE; + } +} + + + +/* This is the same idea as the media type version does for type enumeration + on pins but for the list of pins available. So if the list of pins you + provide changes dynamically then either override this virtual function + to provide the version number, or more simply call IncrementPinVersion */ + +LONG CBaseFilter::GetPinVersion() +{ + return m_PinVersion; +} + + +/* Increment the current pin version cookie */ + +void CBaseFilter::IncrementPinVersion() +{ + InterlockedIncrement(&m_PinVersion); +} + +/* register filter */ + +STDMETHODIMP CBaseFilter::Register() +{ + // get setup data, if it exists + // + LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + // init is ref counted so call just in case + // we're being called cold. + // + HRESULT hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper + // + IFilterMapper *pIFM; + hr = CoCreateInstance( CLSID_FilterMapper + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper + , (void **)&pIFM ); + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE ); + pIFM->Release(); + } + + // and clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + + return NOERROR; +} + + +/* unregister filter */ + +STDMETHODIMP CBaseFilter::Unregister() +{ + // get setup data, if it exists + // + LPAMOVIESETUP_FILTER psetupdata = GetSetupData(); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + // OLE init is ref counted so call + // just in case we're being called cold. + // + HRESULT hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper + // + IFilterMapper *pIFM; + hr = CoCreateInstance( CLSID_FilterMapper + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper + , (void **)&pIFM ); + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE ); + + // release interface + // + pIFM->Release(); + } + + // clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + + +//===================================================================== +//===================================================================== +// Implements CEnumPins +//===================================================================== +//===================================================================== + + +CEnumPins::CEnumPins(__in CBaseFilter *pFilter, + __in_opt CEnumPins *pEnumPins) : + m_Position(0), + m_PinCount(0), + m_pFilter(pFilter), + m_cRef(1), // Already ref counted + m_PinCache(NAME("Pin Cache")) +{ + +#ifdef _DEBUG + m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0); +#endif + + /* We must be owned by a filter derived from CBaseFilter */ + + ASSERT(pFilter != NULL); + + /* Hold a reference count on our filter */ + m_pFilter->AddRef(); + + /* Are we creating a new enumerator */ + + if (pEnumPins == NULL) { + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + } else { + ASSERT(m_Position <= m_PinCount); + m_Position = pEnumPins->m_Position; + m_PinCount = pEnumPins->m_PinCount; + m_Version = pEnumPins->m_Version; + m_PinCache.AddTail(&(pEnumPins->m_PinCache)); + } +} + + +/* Destructor releases the reference count on our filter NOTE since we hold + a reference count on the filter who created us we know it is safe to + release it, no access can be made to it afterwards though as we have just + caused the last reference count to go and the object to be deleted */ + +CEnumPins::~CEnumPins() +{ + m_pFilter->Release(); + +#ifdef _DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + + +/* Override this to say what interfaces we support where */ + +STDMETHODIMP +CEnumPins::QueryInterface(REFIID riid, __deref_out void **ppv) +{ + CheckPointer(ppv, E_POINTER); + + /* Do we have this interface */ + + if (riid == IID_IEnumPins || riid == IID_IUnknown) { + return GetInterface((IEnumPins *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CEnumPins::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) +CEnumPins::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) { + delete this; + } + return cRef; +} + +/* One of an enumerator's basic member functions allows us to create a cloned + interface that initially has the same state. Since we are taking a snapshot + of an object (current position and all) we must lock access at the start */ + +STDMETHODIMP +CEnumPins::Clone(__deref_out IEnumPins **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *)); + HRESULT hr = NOERROR; + + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + *ppEnum = NULL; + hr = VFW_E_ENUM_OUT_OF_SYNC; + } else { + *ppEnum = new CEnumPins(m_pFilter, + this); + if (*ppEnum == NULL) { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + + +/* Return the next pin after the current position */ + +STDMETHODIMP +CEnumPins::Next(ULONG cPins, // place this many pins... + __out_ecount(cPins) IPin **ppPins, // ...in this array + __out_opt ULONG *pcFetched) // actual count passed returned here +{ + CheckPointer(ppPins,E_POINTER); + ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *)); + + ASSERT(ppPins); + + if (pcFetched!=NULL) { + ValidateWritePtr(pcFetched, sizeof(ULONG)); + *pcFetched = 0; // default unless we succeed + } + // now check that the parameter is valid + else if (cPins>1) { // pcFetched == NULL + return E_INVALIDARG; + } + ULONG cFetched = 0; // increment as we get each one. + + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + // If we are out of sync, we should refresh the enumerator. + // This will reset the position and update the other members, but + // will not clear cache of pins we have already returned. + Refresh(); + } + + /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed + so we must QI for the IPin (which increments its reference count) + If while we are retrieving a pin from the filter an error occurs we + assume that our internal state is stale with respect to the filter + (for example someone has deleted a pin) so we + return VFW_E_ENUM_OUT_OF_SYNC */ + + while (cFetched < cPins && m_PinCount > m_Position) { + + /* Get the next pin object from the filter */ + + CBasePin *pPin = m_pFilter->GetPin(m_Position++); + if (pPin == NULL) { + // If this happend, and it's not the first time through, then we've got a problem, + // since we should really go back and release the iPins, which we have previously + // AddRef'ed. + ASSERT( cFetched==0 ); + return VFW_E_ENUM_OUT_OF_SYNC; + } + // MPC-HC custom code begin + if (pPin == (CBasePin *)0x3) { + return E_FAIL; + } + // MPC-HC custom code end + + /* We only want to return this pin, if it is not in our cache */ + if (0 == m_PinCache.Find(pPin)) + { + /* From the object get an IPin interface */ + + *ppPins = pPin; + pPin->AddRef(); + + cFetched++; + ppPins++; + + m_PinCache.AddTail(pPin); + } + } + + if (pcFetched!=NULL) { + *pcFetched = cFetched; + } + + return (cPins==cFetched ? NOERROR : S_FALSE); +} + + +/* Skip over one or more entries in the enumerator */ + +STDMETHODIMP +CEnumPins::Skip(ULONG cPins) +{ + /* Check we are still in sync with the filter */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + /* Work out how many pins are left to skip over */ + /* We could position at the end if we are asked to skip too many... */ + /* ..which would match the base implementation for CEnumMediaTypes::Skip */ + + ULONG PinsLeft = m_PinCount - m_Position; + if (cPins > PinsLeft) { + return S_FALSE; + } + m_Position += cPins; + return NOERROR; +} + + +/* Set the current position back to the start */ +/* Reset has 4 simple steps: + * + * Set position to head of list + * Sync enumerator with object being enumerated + * Clear the cache of pins already returned + * return S_OK + */ + +STDMETHODIMP +CEnumPins::Reset() +{ + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + + m_Position = 0; + + // Clear the cache + m_PinCache.RemoveAll(); + + return S_OK; +} + + +/* Set the current position back to the start */ +/* Refresh has 3 simple steps: + * + * Set position to head of list + * Sync enumerator with object being enumerated + * return S_OK + */ + +STDMETHODIMP +CEnumPins::Refresh() +{ + m_Version = m_pFilter->GetPinVersion(); + m_PinCount = m_pFilter->GetPinCount(); + + m_Position = 0; + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CEnumMediaTypes +//===================================================================== +//===================================================================== + + +CEnumMediaTypes::CEnumMediaTypes(__in CBasePin *pPin, + __in_opt CEnumMediaTypes *pEnumMediaTypes) : + m_Position(0), + m_pPin(pPin), + m_cRef(1) +{ + +#ifdef _DEBUG + m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0); +#endif + + /* We must be owned by a pin derived from CBasePin */ + + ASSERT(pPin != NULL); + + /* Hold a reference count on our pin */ + m_pPin->AddRef(); + + /* Are we creating a new enumerator */ + + if (pEnumMediaTypes == NULL) { + m_Version = m_pPin->GetMediaTypeVersion(); + return; + } + + m_Position = pEnumMediaTypes->m_Position; + m_Version = pEnumMediaTypes->m_Version; +} + + +/* Destructor releases the reference count on our base pin. NOTE since we hold + a reference count on the pin who created us we know it is safe to release + it, no access can be made to it afterwards though as we might have just + caused the last reference count to go and the object to be deleted */ + +CEnumMediaTypes::~CEnumMediaTypes() +{ +#ifdef _DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif + m_pPin->Release(); +} + + +/* Override this to say what interfaces we support where */ + +STDMETHODIMP +CEnumMediaTypes::QueryInterface(REFIID riid, __deref_out void **ppv) +{ + CheckPointer(ppv, E_POINTER); + + /* Do we have this interface */ + + if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) { + return GetInterface((IEnumMediaTypes *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CEnumMediaTypes::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +STDMETHODIMP_(ULONG) +CEnumMediaTypes::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) { + delete this; + } + return cRef; +} + +/* One of an enumerator's basic member functions allows us to create a cloned + interface that initially has the same state. Since we are taking a snapshot + of an object (current position and all) we must lock access at the start */ + +STDMETHODIMP +CEnumMediaTypes::Clone(__deref_out IEnumMediaTypes **ppEnum) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + HRESULT hr = NOERROR; + + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + *ppEnum = NULL; + hr = VFW_E_ENUM_OUT_OF_SYNC; + } else { + + *ppEnum = new CEnumMediaTypes(m_pPin, + this); + + if (*ppEnum == NULL) { + hr = E_OUTOFMEMORY; + } + } + return hr; +} + + +/* Enumerate the next pin(s) after the current position. The client using this + interface passes in a pointer to an array of pointers each of which will + be filled in with a pointer to a fully initialised media type format + Return NOERROR if it all works, + S_FALSE if fewer than cMediaTypes were enumerated. + VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by + state changes in the filter + The actual count always correctly reflects the number of types in the array. +*/ + +STDMETHODIMP +CEnumMediaTypes::Next(ULONG cMediaTypes, // place this many types... + __out_ecount(cMediaTypes) AM_MEDIA_TYPE **ppMediaTypes, // ...in this array + __out ULONG *pcFetched) // actual count passed +{ + CheckPointer(ppMediaTypes,E_POINTER); + ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *)); + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + if (pcFetched!=NULL) { + ValidateWritePtr(pcFetched, sizeof(ULONG)); + *pcFetched = 0; // default unless we succeed + } + // now check that the parameter is valid + else if (cMediaTypes>1) { // pcFetched == NULL + return E_INVALIDARG; + } + ULONG cFetched = 0; // increment as we get each one. + + /* Return each media type by asking the filter for them in turn - If we + have an error code retured to us while we are retrieving a media type + we assume that our internal state is stale with respect to the filter + (for example the window size changing) so we return + VFW_E_ENUM_OUT_OF_SYNC */ + + while (cMediaTypes) { + + CMediaType cmt; + + HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt); + if (S_OK != hr) { + break; + } + + /* We now have a CMediaType object that contains the next media type + but when we assign it to the array position we CANNOT just assign + the AM_MEDIA_TYPE structure because as soon as the object goes out of + scope it will delete the memory we have just copied. The function + we use is CreateMediaType which allocates a task memory block */ + + /* Transfer across the format block manually to save an allocate + and free on the format block and generally go faster */ + + *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (*ppMediaTypes == NULL) { + break; + } + + /* Do a regular copy */ + **ppMediaTypes = cmt; + + /* Make sure the destructor doesn't free these */ + cmt.pbFormat = NULL; + cmt.cbFormat = NULL; + cmt.pUnk = NULL; + + + ppMediaTypes++; + cFetched++; + cMediaTypes--; + } + + if (pcFetched!=NULL) { + *pcFetched = cFetched; + } + + return ( cMediaTypes==0 ? NOERROR : S_FALSE ); +} + + +/* Skip over one or more entries in the enumerator */ + +STDMETHODIMP +CEnumMediaTypes::Skip(ULONG cMediaTypes) +{ + // If we're skipping 0 elements we're guaranteed to skip the + // correct number of elements + if (cMediaTypes == 0) { + return S_OK; + } + + /* Check we are still in sync with the pin */ + if (AreWeOutOfSync() == TRUE) { + return VFW_E_ENUM_OUT_OF_SYNC; + } + + m_Position += cMediaTypes; + + /* See if we're over the end */ + CMediaType cmt; + return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE; +} + + +/* Set the current position back to the start */ +/* Reset has 3 simple steps: + * + * set position to head of list + * sync enumerator with object being enumerated + * return S_OK + */ + +STDMETHODIMP +CEnumMediaTypes::Reset() + +{ + m_Position = 0; + + // Bring the enumerator back into step with the current state. This + // may be a noop but ensures that the enumerator will be valid on the + // next call. + m_Version = m_pPin->GetMediaTypeVersion(); + return NOERROR; +} + + +//===================================================================== +//===================================================================== +// Implements CBasePin +//===================================================================== +//===================================================================== + + +/* NOTE The implementation of this class calls the CUnknown constructor with + a NULL outer unknown pointer. This has the effect of making us a self + contained class, ie any QueryInterface, AddRef or Release calls will be + routed to the class's NonDelegatingUnknown methods. You will typically + find that the classes that do this then override one or more of these + virtual functions to provide more specialised behaviour. A good example + of this is where a class wants to keep the QueryInterface internal but + still wants its lifetime controlled by the external object */ + +/* Constructor */ + +CBasePin::CBasePin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName, + PIN_DIRECTION dir) : + CUnknown( pObjectName, NULL ), + m_pFilter(pFilter), + m_pLock(pLock), + m_pName(NULL), + m_Connected(NULL), + m_dir(dir), + m_bRunTimeError(FALSE), + m_pQSink(NULL), + m_TypeVersion(1), + m_tStart(), + m_tStop(MAX_TIME), + m_bCanReconnectWhenActive(false), + m_bTryMyTypesFirst(false), + m_dRate(1.0) +{ + /* WARNING - pFilter is often not a properly constituted object at + this state (in particular QueryInterface may not work) - this + is because its owner is often its containing object and we + have been called from the containing object's constructor so + the filter's owner has not yet had its CUnknown constructor + called + */ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this ); +#endif // DXMPERF + + ASSERT(pFilter != NULL); + ASSERT(pLock != NULL); + + if (pName) { + size_t cchName; + HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName); + if (SUCCEEDED(hr)) { + m_pName = new WCHAR[cchName + 1]; + if (m_pName) { + (void)StringCchCopyW(m_pName, cchName + 1, pName); + } + } + } + +#ifdef _DEBUG + m_cRef = 0; +#endif +} + +#ifdef UNICODE +CBasePin::CBasePin(__in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName, + PIN_DIRECTION dir) : + CUnknown( pObjectName, NULL ), + m_pFilter(pFilter), + m_pLock(pLock), + m_pName(NULL), + m_Connected(NULL), + m_dir(dir), + m_bRunTimeError(FALSE), + m_pQSink(NULL), + m_TypeVersion(1), + m_tStart(), + m_tStop(MAX_TIME), + m_bCanReconnectWhenActive(false), + m_bTryMyTypesFirst(false), + m_dRate(1.0) +{ + /* WARNING - pFilter is often not a properly constituted object at + this state (in particular QueryInterface may not work) - this + is because its owner is often its containing object and we + have been called from the containing object's constructor so + the filter's owner has not yet had its CUnknown constructor + called + */ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this ); +#endif // DXMPERF + + ASSERT(pFilter != NULL); + ASSERT(pLock != NULL); + + if (pName) { + size_t cchName; + HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName); + if (SUCCEEDED(hr)) { + m_pName = new WCHAR[cchName + 1]; + if (m_pName) { + (void)StringCchCopyW(m_pName, cchName + 1, pName); + } + } + } + + +#ifdef _DEBUG + m_cRef = 0; +#endif +} +#endif + +/* Destructor since a connected pin holds a reference count on us there is + no way that we can be deleted unless we are not currently connected */ + +CBasePin::~CBasePin() +{ +#ifdef DXMPERF + PERFLOG_DTOR( m_pName ? m_pName : L"CBasePin", (IPin *) this ); +#endif // DXMPERF + + // We don't call disconnect because if the filter is going away + // all the pins must have a reference count of zero so they must + // have been disconnected anyway - (but check the assumption) + ASSERT(m_Connected == FALSE); + + delete[] m_pName; + + // check the internal reference count is consistent + ASSERT(m_cRef == 0); +} + + +/* Override this to say what interfaces we support and where */ + +STDMETHODIMP +CBasePin::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) +{ + /* Do we have this interface */ + + if (riid == IID_IPin) { + return GetInterface((IPin *) this, ppv); + } else if (riid == IID_IQualityControl) { + return GetInterface((IQualityControl *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* Override to increment the owning filter's reference count */ + +STDMETHODIMP_(ULONG) +CBasePin::NonDelegatingAddRef() +{ + ASSERT(InterlockedIncrement(&m_cRef) > 0); + return m_pFilter->AddRef(); +} + + +/* Override to decrement the owning filter's reference count */ + +STDMETHODIMP_(ULONG) +CBasePin::NonDelegatingRelease() +{ + ASSERT(InterlockedDecrement(&m_cRef) >= 0); + return m_pFilter->Release(); +} + + +/* Displays pin connection information */ + +#ifdef _DEBUG +void +CBasePin::DisplayPinInfo(IPin *pReceivePin) +{ + + if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { + PIN_INFO ConnectPinInfo; + PIN_INFO ReceivePinInfo; + + if (FAILED(QueryPinInfo(&ConnectPinInfo))) { + StringCchCopyW(ConnectPinInfo.achName, sizeof(ConnectPinInfo.achName)/sizeof(WCHAR), L"Bad Pin"); + } else { + QueryPinInfoReleaseFilter(ConnectPinInfo); + } + + if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) { + StringCchCopyW(ReceivePinInfo.achName, sizeof(ReceivePinInfo.achName)/sizeof(WCHAR), L"Bad Pin"); + } else { + QueryPinInfoReleaseFilter(ReceivePinInfo); + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :"))); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName)); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName)); + } +} +#endif + + +/* Displays general information on the pin media type */ + +#ifdef _DEBUG +void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) +{ + UNREFERENCED_PARAMETER(pPin); + if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:"))); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"), + GuidNames[*pmt->Type()])); + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"), + GuidNames[*pmt->Subtype()])); + } +} +#endif + +/* Asked to connect to a pin. A pin is always attached to an owning filter + object so we always delegate our locking to that object. We first of all + retrieve a media type enumerator for the input pin and see if we accept + any of the formats that it would ideally like, failing that we retrieve + our enumerator and see if it will accept any of our preferred types */ + +STDMETHODIMP +CBasePin::Connect( + IPin * pReceivePin, + __in_opt const AM_MEDIA_TYPE *pmt // optional media type +) +{ + CheckPointer(pReceivePin,E_POINTER); + ValidateReadPtr(pReceivePin,sizeof(IPin)); + CAutoLock cObjectLock(m_pLock); + DisplayPinInfo(pReceivePin); + + /* See if we are already connected */ + + if (m_Connected) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected"))); + return VFW_E_ALREADY_CONNECTED; + } + + /* See if the filter is active */ + if (!IsStopped() && !m_bCanReconnectWhenActive) { + return VFW_E_NOT_STOPPED; + } + + + // Find a mutually agreeable media type - + // Pass in the template media type. If this is partially specified, + // each of the enumerated media types will need to be checked against + // it. If it is non-null and fully specified, we will just try to connect + // with this. + + const CMediaType * ptype = (CMediaType*)pmt; + HRESULT hr = AgreeMediaType(pReceivePin, ptype); + if (FAILED(hr)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type"))); + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + +#ifdef DXMPERF + PERFLOG_CONNECT( (IPin *) this, pReceivePin, hr, pmt ); +#endif // DXMPERF + + return hr; + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded"))); + +#ifdef DXMPERF + PERFLOG_CONNECT( (IPin *) this, pReceivePin, NOERROR, pmt ); +#endif // DXMPERF + + return NOERROR; +} + +// given a specific media type, attempt a connection (includes +// checking that the type is acceptable to this pin) +HRESULT +CBasePin::AttemptConnection( + IPin* pReceivePin, // connect to this pin + const CMediaType* pmt // using this type +) +{ + // The caller should hold the filter lock becasue this function + // uses m_Connected. The caller should also hold the filter lock + // because this function calls SetMediaType(), IsStopped() and + // CompleteConnect(). + ASSERT(CritCheckIn(m_pLock)); + + // Check that the connection is valid -- need to do this for every + // connect attempt since BreakConnect will undo it. + HRESULT hr = CheckConnect(pReceivePin); + if (FAILED(hr)) { + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed"))); + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + return hr; + } + + DisplayTypeInfo(pReceivePin, pmt); + + /* Check we will accept this media type */ + + hr = CheckMediaType(pmt); + if (hr == NOERROR) { + + /* Make ourselves look connected otherwise ReceiveConnection + may not be able to complete the connection + */ + m_Connected = pReceivePin; + m_Connected->AddRef(); + hr = SetMediaType(pmt); + if (SUCCEEDED(hr)) { + /* See if the other pin will accept this type */ + + hr = pReceivePin->ReceiveConnection((IPin *)this, pmt); + if (SUCCEEDED(hr)) { + /* Complete the connection */ + + hr = CompleteConnect(pReceivePin); + if (SUCCEEDED(hr)) { + return hr; + } else { + DbgLog((LOG_TRACE, + CONNECT_TRACE_LEVEL, + TEXT("Failed to complete connection"))); + pReceivePin->Disconnect(); + } + } + } + } else { + // we cannot use this media type + + // return a specific media type error if there is one + // or map a general failure code to something more helpful + // (in particular S_FALSE gets changed to an error code) + if (SUCCEEDED(hr) || + (hr == E_FAIL) || + (hr == E_INVALIDARG)) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + } + + // BreakConnect and release any connection here in case CheckMediaType + // failed, or if we set anything up during a call back during + // ReceiveConnection. + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + /* If failed then undo our state */ + if (m_Connected) { + m_Connected->Release(); + m_Connected = NULL; + } + + return hr; +} + +/* Given an enumerator we cycle through all the media types it proposes and + firstly suggest them to our derived pin class and if that succeeds try + them with the pin in a ReceiveConnection call. This means that if our pin + proposes a media type we still check in here that we can support it. This + is deliberate so that in simple cases the enumerator can hold all of the + media types even if some of them are not really currently available */ + +HRESULT CBasePin::TryMediaTypes( + IPin *pReceivePin, + __in_opt const CMediaType *pmt, + IEnumMediaTypes *pEnum) +{ + /* Reset the current enumerator position */ + + HRESULT hr = pEnum->Reset(); + if (FAILED(hr)) { + return hr; + } + + CMediaType *pMediaType = NULL; + ULONG ulMediaCount = 0; + + // attempt to remember a specific error code if there is one + HRESULT hrFailure = S_OK; + + for (;;) { + + /* Retrieve the next media type NOTE each time round the loop the + enumerator interface will allocate another AM_MEDIA_TYPE structure + If we are successful then we copy it into our output object, if + not then we must delete the memory allocated before returning */ + + hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount); + if (hr != S_OK) { + if (S_OK == hrFailure) { + hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; + } + return hrFailure; + } + + + ASSERT(ulMediaCount == 1); + ASSERT(pMediaType); + + // check that this matches the partial type (if any) + + if (pMediaType && + ((pmt == NULL) || + pMediaType->MatchesPartial(pmt))) { + + hr = AttemptConnection(pReceivePin, pMediaType); + + // attempt to remember a specific error code + if (FAILED(hr) && + SUCCEEDED(hrFailure) && + (hr != E_FAIL) && + (hr != E_INVALIDARG) && + (hr != VFW_E_TYPE_NOT_ACCEPTED)) { + hrFailure = hr; + } + } else { + hr = VFW_E_NO_ACCEPTABLE_TYPES; + } + + if(pMediaType) { + DeleteMediaType(pMediaType); + pMediaType = NULL; + } + + if (S_OK == hr) { + return hr; + } + } +} + + +/* This is called to make the connection, including the taask of finding + a media type for the pin connection. pmt is the proposed media type + from the Connect call: if this is fully specified, we will try that. + Otherwise we enumerate and try all the input pin's types first and + if that fails we then enumerate and try all our preferred media types. + For each media type we check it against pmt (if non-null and partially + specified) as well as checking that both pins will accept it. + */ + +HRESULT CBasePin::AgreeMediaType( + IPin *pReceivePin, + const CMediaType *pmt) +{ + ASSERT(pReceivePin); + IEnumMediaTypes *pEnumMediaTypes = NULL; + + // if the media type is fully specified then use that + if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) { + + // if this media type fails, then we must fail the connection + // since if pmt is nonnull we are only allowed to connect + // using a type that matches it. + + return AttemptConnection(pReceivePin, pmt); + } + + + /* Try the other pin's enumerator */ + + HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES; + + for (int i = 0; i < 2; i++) { + HRESULT hr; + if (i == (int)m_bTryMyTypesFirst) { + hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes); + } else { + hr = EnumMediaTypes(&pEnumMediaTypes); + } + if (SUCCEEDED(hr)) { + ASSERT(pEnumMediaTypes); + hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes); + pEnumMediaTypes->Release(); + if (SUCCEEDED(hr)) { + return NOERROR; + } else { + // try to remember specific error codes if there are any + if ((hr != E_FAIL) && + (hr != E_INVALIDARG) && + (hr != VFW_E_TYPE_NOT_ACCEPTED)) { + hrFailure = hr; + } + } + } + } + + return hrFailure; +} + + +/* Called when we want to complete a connection to another filter. Failing + this will also fail the connection and disconnect the other pin as well */ + +HRESULT +CBasePin::CompleteConnect(IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + return NOERROR; +} + + +/* This is called to set the format for a pin connection - CheckMediaType + will have been called to check the connection format and if it didn't + return an error code then this (virtual) function will be invoked */ + +HRESULT +CBasePin::SetMediaType(const CMediaType *pmt) +{ + HRESULT hr = m_mt.Set(*pmt); + if (FAILED(hr)) { + return hr; + } + + return NOERROR; +} + + +/* This is called during Connect() to provide a virtual method that can do + any specific check needed for connection such as QueryInterface. This + base class method just checks that the pin directions don't match */ + +HRESULT +CBasePin::CheckConnect(IPin * pPin) +{ + /* Check that pin directions DONT match */ + + PIN_DIRECTION pd; + pPin->QueryDirection(&pd); + + ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT)); + ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT)); + + // we should allow for non-input and non-output connections? + if (pd == m_dir) { + return VFW_E_INVALID_DIRECTION; + } + return NOERROR; +} + + +/* This is called when we realise we can't make a connection to the pin and + must undo anything we did in CheckConnect - override to release QIs done */ + +HRESULT +CBasePin::BreakConnect() +{ + return NOERROR; +} + + +/* Called normally by an output pin on an input pin to try and establish a + connection. +*/ + +STDMETHODIMP +CBasePin::ReceiveConnection( + IPin * pConnector, // this is the pin who we will connect to + const AM_MEDIA_TYPE *pmt // this is the media type we will exchange +) +{ + CheckPointer(pConnector,E_POINTER); + CheckPointer(pmt,E_POINTER); + ValidateReadPtr(pConnector,sizeof(IPin)); + ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); + CAutoLock cObjectLock(m_pLock); + + /* Are we already connected */ + if (m_Connected) { + return VFW_E_ALREADY_CONNECTED; + } + + /* See if the filter is active */ + if (!IsStopped() && !m_bCanReconnectWhenActive) { + return VFW_E_NOT_STOPPED; + } + + HRESULT hr = CheckConnect(pConnector); + if (FAILED(hr)) { + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + +#ifdef DXMPERF + PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); +#endif // DXMPERF + + return hr; + } + + /* Ask derived class if this media type is ok */ + + CMediaType * pcmt = (CMediaType*) pmt; + hr = CheckMediaType(pcmt); + if (hr != NOERROR) { + // no -we don't support this media type + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + + // return a specific media type error if there is one + // or map a general failure code to something more helpful + // (in particular S_FALSE gets changed to an error code) + if (SUCCEEDED(hr) || + (hr == E_FAIL) || + (hr == E_INVALIDARG)) { + hr = VFW_E_TYPE_NOT_ACCEPTED; + } + +#ifdef DXMPERF + PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); +#endif // DXMPERF + + return hr; + } + + /* Complete the connection */ + + m_Connected = pConnector; + m_Connected->AddRef(); + hr = SetMediaType(pcmt); + if (SUCCEEDED(hr)) { + hr = CompleteConnect(pConnector); + if (SUCCEEDED(hr)) { + +#ifdef DXMPERF + PERFLOG_RXCONNECT( pConnector, (IPin *) this, NOERROR, pmt ); +#endif // DXMPERF + + return NOERROR; + } + } + + DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection."))); + m_Connected->Release(); + m_Connected = NULL; + + // Since the procedure is already returning an error code, there + // is nothing else this function can do to report the error. + EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) ); + +#ifdef DXMPERF + PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt ); +#endif // DXMPERF + + return hr; +} + + +/* Called when we want to terminate a pin connection */ + +STDMETHODIMP +CBasePin::Disconnect() +{ + CAutoLock cObjectLock(m_pLock); + + /* See if the filter is active */ + if (!IsStopped()) { + return VFW_E_NOT_STOPPED; + } + + return DisconnectInternal(); +} + +STDMETHODIMP +CBasePin::DisconnectInternal() +{ + ASSERT(CritCheckIn(m_pLock)); + + if (m_Connected) { + HRESULT hr = BreakConnect(); + if( FAILED( hr ) ) { + +#ifdef DXMPERF + PERFLOG_DISCONNECT( (IPin *) this, m_Connected, hr ); +#endif // DXMPERF + + // There is usually a bug in the program if BreakConnect() fails. + DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." ); + return hr; + } + + m_Connected->Release(); + m_Connected = NULL; + +#ifdef DXMPERF + PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_OK ); +#endif // DXMPERF + + return S_OK; + } else { + // no connection - not an error + +#ifdef DXMPERF + PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_FALSE ); +#endif // DXMPERF + + return S_FALSE; + } +} + + +/* Return an AddRef()'d pointer to the connected pin if there is one */ +STDMETHODIMP +CBasePin::ConnectedTo( + __deref_out IPin **ppPin +) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + // + // It's pointless to lock here. + // The caller should ensure integrity. + // + + IPin *pPin = m_Connected; + *ppPin = pPin; + if (pPin != NULL) { + pPin->AddRef(); + return S_OK; + } else { + ASSERT(*ppPin == NULL); + return VFW_E_NOT_CONNECTED; + } +} + +/* Return the media type of the connection */ +STDMETHODIMP +CBasePin::ConnectionMediaType( + __out AM_MEDIA_TYPE *pmt +) +{ + CheckPointer(pmt,E_POINTER); + ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE)); + CAutoLock cObjectLock(m_pLock); + + /* Copy constructor of m_mt allocates the memory */ + if (IsConnected()) { + CopyMediaType( pmt, &m_mt ); + return S_OK; + } else { + ((CMediaType *)pmt)->InitMediaType(); + return VFW_E_NOT_CONNECTED; + } +} + +/* Return information about the filter we are connect to */ + +STDMETHODIMP +CBasePin::QueryPinInfo( + __out PIN_INFO * pInfo +) +{ + CheckPointer(pInfo,E_POINTER); + ValidateReadWritePtr(pInfo,sizeof(PIN_INFO)); + + pInfo->pFilter = m_pFilter; + if (m_pFilter) { + m_pFilter->AddRef(); + } + + if (m_pName) { + (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); + } else { + pInfo->achName[0] = L'\0'; + } + + pInfo->dir = m_dir; + + return NOERROR; +} + +STDMETHODIMP +CBasePin::QueryDirection( + __out PIN_DIRECTION * pPinDir +) +{ + CheckPointer(pPinDir,E_POINTER); + ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION)); + + *pPinDir = m_dir; + return NOERROR; +} + +// Default QueryId to return the pin's name +STDMETHODIMP +CBasePin::QueryId( + __deref_out LPWSTR * Id +) +{ + // We're not going away because someone's got a pointer to us + // so there's no need to lock + + return AMGetWideString(Name(), Id); +} + +/* Does this pin support this media type WARNING this interface function does + not lock the main object as it is meant to be asynchronous by nature - if + the media types you support depend on some internal state that is updated + dynamically then you will need to implement locking in a derived class */ + +STDMETHODIMP +CBasePin::QueryAccept( + const AM_MEDIA_TYPE *pmt +) +{ + CheckPointer(pmt,E_POINTER); + ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE)); + + /* The CheckMediaType method is valid to return error codes if the media + type is horrible, an example might be E_INVALIDARG. What we do here + is map all the error codes into either S_OK or S_FALSE regardless */ + + HRESULT hr = CheckMediaType((CMediaType*)pmt); + if (FAILED(hr)) { + return S_FALSE; + } + // note that the only defined success codes should be S_OK and S_FALSE... + return hr; +} + + +/* This can be called to return an enumerator for the pin's list of preferred + media types. An input pin is not obliged to have any preferred formats + although it can do. For example, the window renderer has a preferred type + which describes a video image that matches the current window size. All + output pins should expose at least one preferred format otherwise it is + possible that neither pin has any types and so no connection is possible */ + +STDMETHODIMP +CBasePin::EnumMediaTypes( + __deref_out IEnumMediaTypes **ppEnum +) +{ + CheckPointer(ppEnum,E_POINTER); + ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *)); + + /* Create a new ref counted enumerator */ + + *ppEnum = new CEnumMediaTypes(this, + NULL); + + if (*ppEnum == NULL) { + return E_OUTOFMEMORY; + } + + return NOERROR; +} + + + +/* This is a virtual function that returns a media type corresponding with + place iPosition in the list. This base class simply returns an error as + we support no media types by default but derived classes should override */ + +HRESULT CBasePin::GetMediaType(int iPosition, __inout CMediaType *pMediaType) +{ + UNREFERENCED_PARAMETER(iPosition); + UNREFERENCED_PARAMETER(pMediaType); + return E_UNEXPECTED; +} + + +/* This is a virtual function that returns the current media type version. + The base class initialises the media type enumerators with the value 1 + By default we always returns that same value. A Derived class may change + the list of media types available and after doing so it should increment + the version either in a method derived from this, or more simply by just + incrementing the m_TypeVersion base pin variable. The type enumerators + call this when they want to see if their enumerations are out of date */ + +LONG CBasePin::GetMediaTypeVersion() +{ + return m_TypeVersion; +} + + +/* Increment the cookie representing the current media type version */ + +void CBasePin::IncrementTypeVersion() +{ + InterlockedIncrement(&m_TypeVersion); +} + + +/* Called by IMediaFilter implementation when the state changes from Stopped + to either paused or running and in derived classes could do things like + commit memory and grab hardware resource (the default is to do nothing) */ + +HRESULT +CBasePin::Active(void) +{ + return NOERROR; +} + +/* Called by IMediaFilter implementation when the state changes from + to either paused to running and in derived classes could do things like + commit memory and grab hardware resource (the default is to do nothing) */ + +HRESULT +CBasePin::Run(REFERENCE_TIME tStart) +{ + UNREFERENCED_PARAMETER(tStart); + return NOERROR; +} + + +/* Also called by the IMediaFilter implementation when the state changes to + Stopped at which point you should decommit allocators and free hardware + resources you grabbed in the Active call (default is also to do nothing) */ + +HRESULT +CBasePin::Inactive(void) +{ + m_bRunTimeError = FALSE; + return NOERROR; +} + + +// Called when no more data will arrive +STDMETHODIMP +CBasePin::EndOfStream(void) +{ + return S_OK; +} + + +STDMETHODIMP +CBasePin::SetSink(IQualityControl * piqc) +{ + CAutoLock cObjectLock(m_pLock); + if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl)); + m_pQSink = piqc; + return NOERROR; +} // SetSink + + +STDMETHODIMP +CBasePin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(q); + UNREFERENCED_PARAMETER(pSender); + DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)"); + return E_NOTIMPL; +} //Notify + + +// NewSegment notifies of the start/stop/rate applying to the data +// about to be received. Default implementation records data and +// returns S_OK. +// Override this to pass downstream. +STDMETHODIMP +CBasePin::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + m_tStart = tStart; + m_tStop = tStop; + m_dRate = dRate; + + return S_OK; +} + + +//===================================================================== +//===================================================================== +// Implements CBaseOutputPin +//===================================================================== +//===================================================================== + + +CBaseOutputPin::CBaseOutputPin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), + m_pAllocator(NULL), + m_pInputPin(NULL) +{ + ASSERT(pFilter); +} + +#ifdef UNICODE +CBaseOutputPin::CBaseOutputPin(__in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT), + m_pAllocator(NULL), + m_pInputPin(NULL) +{ + ASSERT(pFilter); +} +#endif + +/* This is called after a media type has been proposed + + Try to complete the connection by agreeing the allocator +*/ +HRESULT +CBaseOutputPin::CompleteConnect(IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + return DecideAllocator(m_pInputPin, &m_pAllocator); +} + + +/* This method is called when the output pin is about to try and connect to + an input pin. It is at this point that you should try and grab any extra + interfaces that you need, in this case IMemInputPin. Because this is + only called if we are not currently connected we do NOT need to call + BreakConnect. This also makes it easier to derive classes from us as + BreakConnect is only called when we actually have to break a connection + (or a partly made connection) and not when we are checking a connection */ + +/* Overriden from CBasePin */ + +HRESULT +CBaseOutputPin::CheckConnect(IPin * pPin) +{ + HRESULT hr = CBasePin::CheckConnect(pPin); + if (FAILED(hr)) { + return hr; + } + + // get an input pin and an allocator interface + hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin); + if (FAILED(hr)) { + return hr; + } + return NOERROR; +} + + +/* Overriden from CBasePin */ + +HRESULT +CBaseOutputPin::BreakConnect() +{ + /* Release any allocator we hold */ + + if (m_pAllocator) { + // Always decommit the allocator because a downstream filter may or + // may not decommit the connection's allocator. A memory leak could + // occur if the allocator is not decommited when a connection is broken. + HRESULT hr = m_pAllocator->Decommit(); + if( FAILED( hr ) ) { + return hr; + } + + m_pAllocator->Release(); + m_pAllocator = NULL; + } + + /* Release any input pin interface we hold */ + + if (m_pInputPin) { + m_pInputPin->Release(); + m_pInputPin = NULL; + } + return NOERROR; +} + + +/* This is called when the input pin didn't give us a valid allocator */ + +HRESULT +CBaseOutputPin::InitAllocator(__deref_out IMemAllocator **ppAlloc) +{ + return CreateMemoryAllocator(ppAlloc); +} + + +/* Decide on an allocator, override this if you want to use your own allocator + Override DecideBufferSize to call SetProperties. If the input pin fails + the GetAllocator call then this will construct a CMemAllocator and call + DecideBufferSize on that, and if that fails then we are completely hosed. + If the you succeed the DecideBufferSize call, we will notify the input + pin of the selected allocator. NOTE this is called during Connect() which + therefore looks after grabbing and locking the object's critical section */ + +// We query the input pin for its requested properties and pass this to +// DecideBufferSize to allow it to fulfill requests that it is happy +// with (eg most people don't care about alignment and are thus happy to +// use the downstream pin's alignment request). + +HRESULT +CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, __deref_out IMemAllocator **ppAlloc) +{ + HRESULT hr = NOERROR; + *ppAlloc = NULL; + + // get downstream prop request + // the derived class may modify this in DecideBufferSize, but + // we assume that he will consistently modify it the same way, + // so we only get it once + ALLOCATOR_PROPERTIES prop; + ZeroMemory(&prop, sizeof(prop)); + + // whatever he returns, we assume prop is either all zeros + // or he has filled it out. + pPin->GetAllocatorRequirements(&prop); + + // if he doesn't care about alignment, then set it to 1 + if (prop.cbAlign == 0) { + prop.cbAlign = 1; + } + + /* Try the allocator provided by the input pin */ + + hr = pPin->GetAllocator(ppAlloc); + if (SUCCEEDED(hr)) { + + hr = DecideBufferSize(*ppAlloc, &prop); + if (SUCCEEDED(hr)) { + hr = pPin->NotifyAllocator(*ppAlloc, FALSE); + if (SUCCEEDED(hr)) { + return NOERROR; + } + } + } + + /* If the GetAllocator failed we may not have an interface */ + + if (*ppAlloc) { + (*ppAlloc)->Release(); + *ppAlloc = NULL; + } + + /* Try the output pin's allocator by the same method */ + + hr = InitAllocator(ppAlloc); + if (SUCCEEDED(hr)) { + + // note - the properties passed here are in the same + // structure as above and may have been modified by + // the previous call to DecideBufferSize + hr = DecideBufferSize(*ppAlloc, &prop); + if (SUCCEEDED(hr)) { + hr = pPin->NotifyAllocator(*ppAlloc, FALSE); + if (SUCCEEDED(hr)) { + return NOERROR; + } + } + } + + /* Likewise we may not have an interface to release */ + + if (*ppAlloc) { + (*ppAlloc)->Release(); + *ppAlloc = NULL; + } + return hr; +} + + +/* This returns an empty sample buffer from the allocator WARNING the same + dangers and restrictions apply here as described below for Deliver() */ + +HRESULT +CBaseOutputPin::GetDeliveryBuffer(__deref_out IMediaSample ** ppSample, + __in_opt REFERENCE_TIME * pStartTime, + __in_opt REFERENCE_TIME * pEndTime, + DWORD dwFlags) +{ + if (m_pAllocator != NULL) { + return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags); + } else { + return E_NOINTERFACE; + } +} + + +/* Deliver a filled-in sample to the connected input pin. NOTE the object must + have locked itself before calling us otherwise we may get halfway through + executing this method only to find the filter graph has got in and + disconnected us from the input pin. If the filter has no worker threads + then the lock is best applied on Receive(), otherwise it should be done + when the worker thread is ready to deliver. There is a wee snag to worker + threads that this shows up. The worker thread must lock the object when + it is ready to deliver a sample, but it may have to wait until a state + change has completed, but that may never complete because the state change + is waiting for the worker thread to complete. The way to handle this is for + the state change code to grab the critical section, then set an abort event + for the worker thread, then release the critical section and wait for the + worker thread to see the event we set and then signal that it has finished + (with another event). At which point the state change code can complete */ + +// note (if you've still got any breath left after reading that) that you +// need to release the sample yourself after this call. if the connected +// input pin needs to hold onto the sample beyond the call, it will addref +// the sample itself. + +// of course you must release this one and call GetDeliveryBuffer for the +// next. You cannot reuse it directly. + +HRESULT +CBaseOutputPin::Deliver(IMediaSample * pSample) +{ + if (m_pInputPin == NULL) { + return VFW_E_NOT_CONNECTED; + } + +#ifdef DXMPERF + PERFLOG_DELIVER( m_pName ? m_pName : L"CBaseOutputPin", (IPin *) this, (IPin *) m_pInputPin, pSample, &m_mt ); +#endif // DXMPERF + + return m_pInputPin->Receive(pSample); +} + + +// called from elsewhere in our filter to pass EOS downstream to +// our connected input pin +HRESULT +CBaseOutputPin::DeliverEndOfStream(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->EndOfStream(); +} + + +/* Commit the allocator's memory, this is called through IMediaFilter + which is responsible for locking the object before calling us */ + +HRESULT +CBaseOutputPin::Active(void) +{ + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + return m_pAllocator->Commit(); +} + + +/* Free up or unprepare allocator's memory, this is called through + IMediaFilter which is responsible for locking the object first */ + +HRESULT +CBaseOutputPin::Inactive(void) +{ + m_bRunTimeError = FALSE; + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + return m_pAllocator->Decommit(); +} + +// we have a default handling of EndOfStream which is to return +// an error, since this should be called on input pins only +STDMETHODIMP +CBaseOutputPin::EndOfStream(void) +{ + return E_UNEXPECTED; +} + + +// BeginFlush should be called on input pins only +STDMETHODIMP +CBaseOutputPin::BeginFlush(void) +{ + return E_UNEXPECTED; +} + +// EndFlush should be called on input pins only +STDMETHODIMP +CBaseOutputPin::EndFlush(void) +{ + return E_UNEXPECTED; +} + +// call BeginFlush on the connected input pin +HRESULT +CBaseOutputPin::DeliverBeginFlush(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->BeginFlush(); +} + +// call EndFlush on the connected input pin +HRESULT +CBaseOutputPin::DeliverEndFlush(void) +{ + // remember this is on IPin not IMemInputPin + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->EndFlush(); +} +// deliver NewSegment to connected pin +HRESULT +CBaseOutputPin::DeliverNewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (m_Connected == NULL) { + return VFW_E_NOT_CONNECTED; + } + return m_Connected->NewSegment(tStart, tStop, dRate); +} + + +//===================================================================== +//===================================================================== +// Implements CBaseInputPin +//===================================================================== +//===================================================================== + + +/* Constructor creates a default allocator object */ + +CBaseInputPin::CBaseInputPin(__in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pPinName) : + CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), + m_pAllocator(NULL), + m_bReadOnly(FALSE), + m_bFlushing(FALSE) +{ + ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); +} + +#ifdef UNICODE +CBaseInputPin::CBaseInputPin(__in LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pPinName) : + CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT), + m_pAllocator(NULL), + m_bReadOnly(FALSE), + m_bFlushing(FALSE) +{ + ZeroMemory(&m_SampleProps, sizeof(m_SampleProps)); +} +#endif + +/* Destructor releases it's reference count on the default allocator */ + +CBaseInputPin::~CBaseInputPin() +{ + if (m_pAllocator != NULL) { + m_pAllocator->Release(); + m_pAllocator = NULL; + } +} + + +// override this to publicise our interfaces +STDMETHODIMP +CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + /* Do we know about this interface */ + + if (riid == IID_IMemInputPin) { + return GetInterface((IMemInputPin *) this, ppv); + } else { + return CBasePin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* Return the allocator interface that this input pin would like the output + pin to use. NOTE subsequent calls to GetAllocator should all return an + interface onto the SAME object so we create one object at the start + + Note: + The allocator is Release()'d on disconnect and replaced on + NotifyAllocator(). + + Override this to provide your own allocator. +*/ + +STDMETHODIMP +CBaseInputPin::GetAllocator( + __deref_out IMemAllocator **ppAllocator) +{ + CheckPointer(ppAllocator,E_POINTER); + ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); + CAutoLock cObjectLock(m_pLock); + + if (m_pAllocator == NULL) { + HRESULT hr = CreateMemoryAllocator(&m_pAllocator); + if (FAILED(hr)) { + return hr; + } + } + ASSERT(m_pAllocator != NULL); + *ppAllocator = m_pAllocator; + m_pAllocator->AddRef(); + return NOERROR; +} + + +/* Tell the input pin which allocator the output pin is actually going to use + Override this if you care - NOTE the locking we do both here and also in + GetAllocator is unnecessary but derived classes that do something useful + will undoubtedly have to lock the object so this might help remind people */ + +STDMETHODIMP +CBaseInputPin::NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly) +{ + CheckPointer(pAllocator,E_POINTER); + ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); + CAutoLock cObjectLock(m_pLock); + + IMemAllocator *pOldAllocator = m_pAllocator; + pAllocator->AddRef(); + m_pAllocator = pAllocator; + + if (pOldAllocator != NULL) { + pOldAllocator->Release(); + } + + // the readonly flag indicates whether samples from this allocator should + // be regarded as readonly - if true, then inplace transforms will not be + // allowed. + m_bReadOnly = (BYTE)bReadOnly; + return NOERROR; +} + + +HRESULT +CBaseInputPin::BreakConnect() +{ + /* We don't need our allocator any more */ + if (m_pAllocator) { + // Always decommit the allocator because a downstream filter may or + // may not decommit the connection's allocator. A memory leak could + // occur if the allocator is not decommited when a pin is disconnected. + HRESULT hr = m_pAllocator->Decommit(); + if( FAILED( hr ) ) { + return hr; + } + + m_pAllocator->Release(); + m_pAllocator = NULL; + } + + return S_OK; +} + + +/* Do something with this media sample - this base class checks to see if the + format has changed with this media sample and if so checks that the filter + will accept it, generating a run time error if not. Once we have raised a + run time error we set a flag so that no more samples will be accepted + + It is important that any filter should override this method and implement + synchronization so that samples are not processed when the pin is + disconnected etc +*/ + +STDMETHODIMP +CBaseInputPin::Receive(IMediaSample *pSample) +{ + CheckPointer(pSample,E_POINTER); + ValidateReadPtr(pSample,sizeof(IMediaSample)); + ASSERT(pSample); + + HRESULT hr = CheckStreaming(); + if (S_OK != hr) { + return hr; + } + +#ifdef DXMPERF + PERFLOG_RECEIVE( m_pName ? m_pName : L"CBaseInputPin", (IPin *) m_Connected, (IPin *) this, pSample, &m_mt ); +#endif // DXMPERF + + + /* Check for IMediaSample2 */ + IMediaSample2 *pSample2; + if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { + hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps); + pSample2->Release(); + if (FAILED(hr)) { + return hr; + } + } else { + /* Get the properties the hard way */ + m_SampleProps.cbData = sizeof(m_SampleProps); + m_SampleProps.dwTypeSpecificFlags = 0; + m_SampleProps.dwStreamId = AM_STREAM_MEDIA; + m_SampleProps.dwSampleFlags = 0; + if (S_OK == pSample->IsDiscontinuity()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + } + if (S_OK == pSample->IsPreroll()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL; + } + if (S_OK == pSample->IsSyncPoint()) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; + } + if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart, + &m_SampleProps.tStop))) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID | + AM_SAMPLE_STOPVALID; + } + if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) { + m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED; + } + pSample->GetPointer(&m_SampleProps.pbBuffer); + m_SampleProps.lActual = pSample->GetActualDataLength(); + m_SampleProps.cbBuffer = pSample->GetSize(); + } + + /* Has the format changed in this sample */ + + if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) { + return NOERROR; + } + + /* Check the derived class accepts this format */ + /* This shouldn't fail as the source must call QueryAccept first */ + + hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType); + + if (hr == NOERROR) { + return NOERROR; + } + + /* Raise a runtime error if we fail the media type */ + + m_bRunTimeError = TRUE; + EndOfStream(); + m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0); + return VFW_E_INVALIDMEDIATYPE; +} + + +/* Receive multiple samples */ +STDMETHODIMP +CBaseInputPin::ReceiveMultiple ( + __in_ecount(nSamples) IMediaSample **pSamples, + long nSamples, + __out long *nSamplesProcessed) +{ + CheckPointer(pSamples,E_POINTER); + ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *)); + + HRESULT hr = S_OK; + *nSamplesProcessed = 0; + while (nSamples-- > 0) { + hr = Receive(pSamples[*nSamplesProcessed]); + + /* S_FALSE means don't send any more */ + if (hr != S_OK) { + break; + } + (*nSamplesProcessed)++; + } + return hr; +} + +/* See if Receive() might block */ +STDMETHODIMP +CBaseInputPin::ReceiveCanBlock() +{ + /* Ask all the output pins if they block + If there are no output pin assume we do block + */ + int cPins = m_pFilter->GetPinCount(); + int cOutputPins = 0; + for (int c = 0; c < cPins; c++) { + CBasePin *pPin = m_pFilter->GetPin(c); + if (NULL == pPin) { + break; + } + PIN_DIRECTION pd; + HRESULT hr = pPin->QueryDirection(&pd); + if (FAILED(hr)) { + return hr; + } + + if (pd == PINDIR_OUTPUT) { + + IPin *pConnected; + hr = pPin->ConnectedTo(&pConnected); + if (SUCCEEDED(hr)) { + ASSERT(pConnected != NULL); + cOutputPins++; + IMemInputPin *pInputPin; + hr = pConnected->QueryInterface( + IID_IMemInputPin, + (void **)&pInputPin); + pConnected->Release(); + if (SUCCEEDED(hr)) { + hr = pInputPin->ReceiveCanBlock(); + pInputPin->Release(); + if (hr != S_FALSE) { + return S_OK; + } + } else { + /* There's a transport we don't understand here */ + return S_OK; + } + } + } + } + return cOutputPins == 0 ? S_OK : S_FALSE; +} + +// Default handling for BeginFlush - call at the beginning +// of your implementation (makes sure that all Receive calls +// fail). After calling this, you need to free any queued data +// and then call downstream. +STDMETHODIMP +CBaseInputPin::BeginFlush(void) +{ + // BeginFlush is NOT synchronized with streaming but is part of + // a control action - hence we synchronize with the filter + CAutoLock lck(m_pLock); + + // if we are already in mid-flush, this is probably a mistake + // though not harmful - try to pick it up for now so I can think about it + ASSERT(!m_bFlushing); + + // first thing to do is ensure that no further Receive calls succeed + m_bFlushing = TRUE; + + // now discard any data and call downstream - must do that + // in derived classes + return S_OK; +} + +// default handling for EndFlush - call at end of your implementation +// - before calling this, ensure that there is no queued data and no thread +// pushing any more without a further receive, then call downstream, +// then call this method to clear the m_bFlushing flag and re-enable +// receives +STDMETHODIMP +CBaseInputPin::EndFlush(void) +{ + // Endlush is NOT synchronized with streaming but is part of + // a control action - hence we synchronize with the filter + CAutoLock lck(m_pLock); + + // almost certainly a mistake if we are not in mid-flush + ASSERT(m_bFlushing); + + // before calling, sync with pushing thread and ensure + // no more data is going downstream, then call EndFlush on + // downstream pins. + + // now re-enable Receives + m_bFlushing = FALSE; + + // No more errors + m_bRunTimeError = FALSE; + + return S_OK; +} + + +STDMETHODIMP +CBaseInputPin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(q); + CheckPointer(pSender,E_POINTER); + ValidateReadPtr(pSender,sizeof(IBaseFilter)); + DbgBreak("IQuality::Notify called on an input pin"); + return NOERROR; +} // Notify + +/* Free up or unprepare allocator's memory, this is called through + IMediaFilter which is responsible for locking the object first */ + +HRESULT +CBaseInputPin::Inactive(void) +{ + m_bRunTimeError = FALSE; + if (m_pAllocator == NULL) { + return VFW_E_NO_ALLOCATOR; + } + + m_bFlushing = FALSE; + + return m_pAllocator->Decommit(); +} + +// what requirements do we have of the allocator - override if you want +// to support other people's allocators but need a specific alignment +// or prefix. +STDMETHODIMP +CBaseInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps) +{ + UNREFERENCED_PARAMETER(pProps); + return E_NOTIMPL; +} + +// Check if it's OK to process data +// +HRESULT +CBaseInputPin::CheckStreaming() +{ + // Shouldn't be able to get any data if we're not connected! + ASSERT(IsConnected()); + + // Don't process stuff in Stopped state + if (IsStopped()) { + return VFW_E_WRONG_STATE; + } + if (m_bFlushing) { + return S_FALSE; + } + if (m_bRunTimeError) { + return VFW_E_RUNTIME_ERROR; + } + return S_OK; +} + +// Pass on the Quality notification q to +// a. Our QualityControl sink (if we have one) or else +// b. to our upstream filter +// and if that doesn't work, throw it away with a bad return code +HRESULT +CBaseInputPin::PassNotify(Quality& q) +{ + // We pass the message on, which means that we find the quality sink + // for our input pin and send it there + + DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform"))); + if (m_pQSink!=NULL) { + return m_pQSink->Notify(m_pFilter, q); + } else { + // no sink set, so pass it upstream + HRESULT hr; + IQualityControl * pIQC; + + hr = VFW_E_NOT_FOUND; // default + if (m_Connected) { + m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC); + + if (pIQC!=NULL) { + hr = pIQC->Notify(m_pFilter, q); + pIQC->Release(); + } + } + return hr; + } + +} // PassNotify + +//===================================================================== +//===================================================================== +// Memory allocation class, implements CMediaSample +//===================================================================== +//===================================================================== + + +/* NOTE The implementation of this class calls the CUnknown constructor with + a NULL outer unknown pointer. This has the effect of making us a self + contained class, ie any QueryInterface, AddRef or Release calls will be + routed to the class's NonDelegatingUnknown methods. You will typically + find that the classes that do this then override one or more of these + virtual functions to provide more specialised behaviour. A good example + of this is where a class wants to keep the QueryInterface internal but + still wants it's lifetime controlled by the external object */ + +/* The last two parameters have default values of NULL and zero */ + +CMediaSample::CMediaSample(__in_opt LPCTSTR pName, + __in_opt CBaseAllocator *pAllocator, + __inout_opt HRESULT *phr, + __in_bcount_opt(length) LPBYTE pBuffer, + LONG length) : + m_pBuffer(pBuffer), // Initialise the buffer + m_cbBuffer(length), // And it's length + m_lActual(length), // By default, actual = length + m_pMediaType(NULL), // No media type change + m_dwFlags(0), // Nothing set + m_cRef(0), // 0 ref count + m_dwTypeSpecificFlags(0), // Type specific flags + m_dwStreamId(AM_STREAM_MEDIA), // Stream id + m_pAllocator(pAllocator), // Allocator + m_pNext(NULL), + m_Start(0), + m_End(0), + m_MediaStart(0), + m_MediaEnd(0) +{ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CMediaSample", (IMediaSample *) this ); +#endif // DXMPERF + + /* We must have an owner and it must also be derived from class + CBaseAllocator BUT we do not hold a reference count on it */ + + ASSERT(pAllocator); + + if (length < 0) { + *phr = VFW_E_BUFFER_OVERFLOW; + m_cbBuffer = 0; + } +} + +#ifdef UNICODE +CMediaSample::CMediaSample(__in_opt LPCSTR pName, + __in_opt CBaseAllocator *pAllocator, + __inout_opt HRESULT *phr, + __in_bcount_opt(length) LPBYTE pBuffer, + LONG length) : + m_pBuffer(pBuffer), // Initialise the buffer + m_cbBuffer(length), // And it's length + m_lActual(length), // By default, actual = length + m_pMediaType(NULL), // No media type change + m_dwFlags(0), // Nothing set + m_cRef(0), // 0 ref count + m_dwTypeSpecificFlags(0), // Type specific flags + m_dwStreamId(AM_STREAM_MEDIA), // Stream id + m_pAllocator(pAllocator), // Allocator + m_pNext(NULL), + m_Start(0), + m_End(0), + m_MediaStart(0), + m_MediaEnd(0) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CMediaSample", (IMediaSample *) this ); +#endif // DXMPERF + + /* We must have an owner and it must also be derived from class + CBaseAllocator BUT we do not hold a reference count on it */ + + ASSERT(pAllocator); +} +#endif + +/* Destructor deletes the media type memory */ + +CMediaSample::~CMediaSample() +{ +#ifdef DXMPERF + PERFLOG_DTOR( L"CMediaSample", (IMediaSample *) this ); +#endif // DXMPERF + + if (m_pMediaType) { + DeleteMediaType(m_pMediaType); + } +} + +/* Override this to publicise our interfaces */ + +STDMETHODIMP +CMediaSample::QueryInterface(REFIID riid, __deref_out void **ppv) +{ + if (riid == IID_IMediaSample || + riid == IID_IMediaSample2 || + riid == IID_IUnknown) { + return GetInterface((IMediaSample *) this, ppv); + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +STDMETHODIMP_(ULONG) +CMediaSample::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + + +// -- CMediaSample lifetimes -- +// +// On final release of this sample buffer it is not deleted but +// returned to the freelist of the owning memory allocator +// +// The allocator may be waiting for the last buffer to be placed on the free +// list in order to decommit all the memory, so the ReleaseBuffer() call may +// result in this sample being deleted. We also need to hold a refcount on +// the allocator to stop that going away until we have finished with this. +// However, we cannot release the allocator before the ReleaseBuffer, as the +// release may cause us to be deleted. Similarly we can't do it afterwards. +// +// Thus we must leave it to the allocator to hold an addref on our behalf. +// When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer +// is called, he releases himself, possibly causing us and him to be deleted. + + +STDMETHODIMP_(ULONG) +CMediaSample::Release() +{ + /* Decrement our own private reference count */ + LONG lRef; + if (m_cRef == 1) { + lRef = 0; + m_cRef = 0; + } else { + lRef = InterlockedDecrement(&m_cRef); + } + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"), + this, m_cRef)); + + /* Did we release our final reference count */ + if (lRef == 0) { + /* Free all resources */ + if (m_dwFlags & Sample_TypeChanged) { + SetMediaType(NULL); + } + ASSERT(m_pMediaType == NULL); + m_dwFlags = 0; + m_dwTypeSpecificFlags = 0; + m_dwStreamId = AM_STREAM_MEDIA; + + /* This may cause us to be deleted */ + // Our refcount is reliably 0 thus no-one will mess with us + m_pAllocator->ReleaseBuffer(this); + } + return (ULONG)lRef; +} + + +// set the buffer pointer and length. Used by allocators that +// want variable sized pointers or pointers into already-read data. +// This is only available through a CMediaSample* not an IMediaSample* +// and so cannot be changed by clients. +HRESULT +CMediaSample::SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes) +{ + if (cBytes < 0) { + return VFW_E_BUFFER_OVERFLOW; + } + m_pBuffer = ptr; // new buffer area (could be null) + m_cbBuffer = cBytes; // length of buffer + m_lActual = cBytes; // length of data in buffer (assume full) + + return S_OK; +} + + +// get me a read/write pointer to this buffer's memory. I will actually +// want to use sizeUsed bytes. +STDMETHODIMP +CMediaSample::GetPointer(__deref_out BYTE ** ppBuffer) +{ + ValidateReadWritePtr(ppBuffer,sizeof(BYTE *)); + + // creator must have set pointer either during + // constructor or by SetPointer + ASSERT(m_pBuffer); + + *ppBuffer = m_pBuffer; + return NOERROR; +} + + +// return the size in bytes of this buffer +STDMETHODIMP_(LONG) +CMediaSample::GetSize(void) +{ + return m_cbBuffer; +} + + +// get the stream time at which this sample should start and finish. +STDMETHODIMP +CMediaSample::GetTime( + __out REFERENCE_TIME * pTimeStart, // put time here + __out REFERENCE_TIME * pTimeEnd +) +{ + ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME)); + ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME)); + + if (!(m_dwFlags & Sample_StopValid)) { + if (!(m_dwFlags & Sample_TimeValid)) { + return VFW_E_SAMPLE_TIME_NOT_SET; + } else { + *pTimeStart = m_Start; + + // Make sure old stuff works + *pTimeEnd = m_Start + 1; + return VFW_S_NO_STOP_TIME; + } + } + + *pTimeStart = m_Start; + *pTimeEnd = m_End; + return NOERROR; +} + + +// Set the stream time at which this sample should start and finish. +// NULL pointers means the time is reset +STDMETHODIMP +CMediaSample::SetTime( + __in_opt REFERENCE_TIME * pTimeStart, + __in_opt REFERENCE_TIME * pTimeEnd +) +{ + if (pTimeStart == NULL) { + ASSERT(pTimeEnd == NULL); + m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid); + } else { + if (pTimeEnd == NULL) { + m_Start = *pTimeStart; + m_dwFlags |= Sample_TimeValid; + m_dwFlags &= ~Sample_StopValid; + } else { + ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME)); + ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME)); + ASSERT(*pTimeEnd >= *pTimeStart); + + m_Start = *pTimeStart; + m_End = *pTimeEnd; + m_dwFlags |= Sample_TimeValid | Sample_StopValid; + } + } + return NOERROR; +} + + +// get the media times (eg bytes) for this sample +STDMETHODIMP +CMediaSample::GetMediaTime( + __out LONGLONG * pTimeStart, + __out LONGLONG * pTimeEnd +) +{ + ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG)); + ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG)); + + if (!(m_dwFlags & Sample_MediaTimeValid)) { + return VFW_E_MEDIA_TIME_NOT_SET; + } + + *pTimeStart = m_MediaStart; + *pTimeEnd = (m_MediaStart + m_MediaEnd); + return NOERROR; +} + + +// Set the media times for this sample +STDMETHODIMP +CMediaSample::SetMediaTime( + __in_opt LONGLONG * pTimeStart, + __in_opt LONGLONG * pTimeEnd +) +{ + if (pTimeStart == NULL) { + ASSERT(pTimeEnd == NULL); + m_dwFlags &= ~Sample_MediaTimeValid; + } else { + if (NULL == pTimeEnd) { + return E_POINTER; + } + ValidateReadPtr(pTimeStart,sizeof(LONGLONG)); + ValidateReadPtr(pTimeEnd,sizeof(LONGLONG)); + ASSERT(*pTimeEnd >= *pTimeStart); + + m_MediaStart = *pTimeStart; + m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart); + m_dwFlags |= Sample_MediaTimeValid; + } + return NOERROR; +} + + +STDMETHODIMP +CMediaSample::IsSyncPoint(void) +{ + if (m_dwFlags & Sample_SyncPoint) { + return S_OK; + } else { + return S_FALSE; + } +} + + +STDMETHODIMP +CMediaSample::SetSyncPoint(BOOL bIsSyncPoint) +{ + if (bIsSyncPoint) { + m_dwFlags |= Sample_SyncPoint; + } else { + m_dwFlags &= ~Sample_SyncPoint; + } + return NOERROR; +} + +// returns S_OK if there is a discontinuity in the data (this same is +// not a continuation of the previous stream of data +// - there has been a seek). +STDMETHODIMP +CMediaSample::IsDiscontinuity(void) +{ + if (m_dwFlags & Sample_Discontinuity) { + return S_OK; + } else { + return S_FALSE; + } +} + +// set the discontinuity property - TRUE if this sample is not a +// continuation, but a new sample after a seek. +STDMETHODIMP +CMediaSample::SetDiscontinuity(BOOL bDiscont) +{ + // should be TRUE or FALSE + if (bDiscont) { + m_dwFlags |= Sample_Discontinuity; + } else { + m_dwFlags &= ~Sample_Discontinuity; + } + return S_OK; +} + +STDMETHODIMP +CMediaSample::IsPreroll(void) +{ + if (m_dwFlags & Sample_Preroll) { + return S_OK; + } else { + return S_FALSE; + } +} + + +STDMETHODIMP +CMediaSample::SetPreroll(BOOL bIsPreroll) +{ + if (bIsPreroll) { + m_dwFlags |= Sample_Preroll; + } else { + m_dwFlags &= ~Sample_Preroll; + } + return NOERROR; +} + +STDMETHODIMP_(LONG) +CMediaSample::GetActualDataLength(void) +{ + return m_lActual; +} + + +STDMETHODIMP +CMediaSample::SetActualDataLength(LONG lActual) +{ + if (lActual > m_cbBuffer || lActual < 0) { + ASSERT(lActual <= GetSize()); + return VFW_E_BUFFER_OVERFLOW; + } + m_lActual = lActual; + return NOERROR; +} + + +/* These allow for limited format changes in band */ + +STDMETHODIMP +CMediaSample::GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType) +{ + ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *)); + ASSERT(ppMediaType); + + /* Do we have a new media type for them */ + + if (!(m_dwFlags & Sample_TypeChanged)) { + ASSERT(m_pMediaType == NULL); + *ppMediaType = NULL; + return S_FALSE; + } + + ASSERT(m_pMediaType); + + /* Create a copy of our media type */ + + *ppMediaType = CreateMediaType(m_pMediaType); + if (*ppMediaType == NULL) { + return E_OUTOFMEMORY; + } + return NOERROR; +} + + +/* Mark this sample as having a different format type */ + +STDMETHODIMP +CMediaSample::SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType) +{ + /* Delete the current media type */ + + if (m_pMediaType) { + DeleteMediaType(m_pMediaType); + m_pMediaType = NULL; + } + + /* Mechanism for resetting the format type */ + + if (pMediaType == NULL) { + m_dwFlags &= ~Sample_TypeChanged; + return NOERROR; + } + + ASSERT(pMediaType); + ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE)); + + /* Take a copy of the media type */ + + m_pMediaType = CreateMediaType(pMediaType); + if (m_pMediaType == NULL) { + m_dwFlags &= ~Sample_TypeChanged; + return E_OUTOFMEMORY; + } + + m_dwFlags |= Sample_TypeChanged; + return NOERROR; +} + +// Set and get properties (IMediaSample2) +STDMETHODIMP CMediaSample::GetProperties( + DWORD cbProperties, + __out_bcount(cbProperties) BYTE * pbProperties +) +{ + if (0 != cbProperties) { + CheckPointer(pbProperties, E_POINTER); + // Return generic stuff up to the length + AM_SAMPLE2_PROPERTIES Props; + Props.cbData = std::min(cbProperties, (ULONG)sizeof(Props)); + Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid; + Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags; + Props.pbBuffer = m_pBuffer; + Props.cbBuffer = m_cbBuffer; + Props.lActual = m_lActual; + Props.tStart = m_Start; + Props.tStop = m_End; + Props.dwStreamId = m_dwStreamId; + if (m_dwFlags & AM_SAMPLE_TYPECHANGED) { + Props.pMediaType = m_pMediaType; + } else { + Props.pMediaType = NULL; + } + CopyMemory(pbProperties, &Props, Props.cbData); + } + return S_OK; +} + +#define CONTAINS_FIELD(type, field, offset) \ + ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset) + +HRESULT CMediaSample::SetProperties( + DWORD cbProperties, + __in_bcount(cbProperties) const BYTE * pbProperties +) +{ + + /* Generic properties */ + AM_MEDIA_TYPE *pMediaType = NULL; + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) { + CheckPointer(pbProperties, E_POINTER); + AM_SAMPLE2_PROPERTIES *pProps = + (AM_SAMPLE2_PROPERTIES *)pbProperties; + + /* Don't use more data than is actually there */ + if (pProps->cbData < cbProperties) { + cbProperties = pProps->cbData; + } + /* We only handle IMediaSample2 */ + if (cbProperties > sizeof(*pProps) || + pProps->cbData > sizeof(*pProps)) { + return E_INVALIDARG; + } + /* Do checks first, the assignments (for backout) */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { + /* Check the flags */ + if (pProps->dwSampleFlags & + (~Sample_ValidFlags | Sample_MediaTimeValid)) { + return E_INVALIDARG; + } + /* Check a flag isn't being set for a property + not being provided + */ + if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) && + !(m_dwFlags & AM_SAMPLE_TIMEVALID) && + !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { + return E_INVALIDARG; + } + } + /* NB - can't SET the pointer or size */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) { + + /* Check pbBuffer */ + if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) { + return E_INVALIDARG; + } + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) { + + /* Check cbBuffer */ + if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) { + return E_INVALIDARG; + } + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) && + CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { + + /* Check lActual */ + if (pProps->cbBuffer < pProps->lActual) { + return E_INVALIDARG; + } + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { + + /* Check pMediaType */ + if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { + CheckPointer(pProps->pMediaType, E_POINTER); + pMediaType = CreateMediaType(pProps->pMediaType); + if (pMediaType == NULL) { + return E_OUTOFMEMORY; + } + } + } + + /* Now do the assignments */ + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) { + m_dwStreamId = pProps->dwStreamId; + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) { + /* Set the flags */ + m_dwFlags = pProps->dwSampleFlags | + (m_dwFlags & Sample_MediaTimeValid); + m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + } else { + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) { + m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + } + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) { + /* Set lActual */ + m_lActual = pProps->lActual; + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) { + + /* Set the times */ + m_End = pProps->tStop; + } + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) { + + /* Set the times */ + m_Start = pProps->tStart; + } + + if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) { + /* Set pMediaType */ + if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) { + if (m_pMediaType != NULL) { + DeleteMediaType(m_pMediaType); + } + m_pMediaType = pMediaType; + } + } + + /* Fix up the type changed flag to correctly reflect the current state + If, for instance the input contained no type change but the + output does then if we don't do this we'd lose the + output media type. + */ + if (m_pMediaType) { + m_dwFlags |= Sample_TypeChanged; + } else { + m_dwFlags &= ~Sample_TypeChanged; + } + } + + return S_OK; +} + + +// +// The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(), +// IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the +// connected input pin. The application thread calls Block(). The +// following class members can only be called by the streaming thread. +// +// Deliver() +// DeliverNewSegment() +// StartUsingOutputPin() +// StopUsingOutputPin() +// ChangeOutputFormat() +// ChangeMediaType() +// DynamicReconnect() +// +// The following class members can only be called by the application thread. +// +// Block() +// SynchronousBlockOutputPin() +// AsynchronousBlockOutputPin() +// + +CDynamicOutputPin::CDynamicOutputPin( + __in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), + m_hStopEvent(NULL), + m_pGraphConfig(NULL), + m_bPinUsesReadOnlyAllocator(FALSE), + m_BlockState(NOT_BLOCKED), + m_hUnblockOutputPinEvent(NULL), + m_hNotifyCallerPinBlockedEvent(NULL), + m_dwBlockCallerThreadID(0), + m_dwNumOutstandingOutputPinUsers(0) +{ + HRESULT hr = Initialize(); + if( FAILED( hr ) ) { + *phr = hr; + return; + } +} + +#ifdef UNICODE +CDynamicOutputPin::CDynamicOutputPin( + __in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName) : + CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName), + m_hStopEvent(NULL), + m_pGraphConfig(NULL), + m_bPinUsesReadOnlyAllocator(FALSE), + m_BlockState(NOT_BLOCKED), + m_hUnblockOutputPinEvent(NULL), + m_hNotifyCallerPinBlockedEvent(NULL), + m_dwBlockCallerThreadID(0), + m_dwNumOutstandingOutputPinUsers(0) +{ + HRESULT hr = Initialize(); + if( FAILED( hr ) ) { + *phr = hr; + return; + } +} +#endif + +CDynamicOutputPin::~CDynamicOutputPin() +{ + if(NULL != m_hUnblockOutputPinEvent) { + // This call should not fail because we have access to m_hUnblockOutputPinEvent + // and m_hUnblockOutputPinEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent)); + } + + if(NULL != m_hNotifyCallerPinBlockedEvent) { + // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent + // and m_hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + } +} + +HRESULT CDynamicOutputPin::Initialize(void) +{ + m_hUnblockOutputPinEvent = ::CreateEvent( NULL, // The event will have the default security descriptor. + TRUE, // This is a manual reset event. + TRUE, // The event is initially signaled. + NULL ); // The event is not named. + + // CreateEvent() returns NULL if an error occurs. + if(NULL == m_hUnblockOutputPinEvent) { + return AmGetLastErrorToHResult(); + } + + // Set flag to say we can reconnect while streaming. + SetReconnectWhenActive(true); + + return S_OK; +} + +STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + if(riid == IID_IPinFlowControl) { + return GetInterface(static_cast(this), ppv); + } else { + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); + } +} + +STDMETHODIMP CDynamicOutputPin::Disconnect(void) +{ + CAutoLock cObjectLock(m_pLock); + return DisconnectInternal(); +} + +STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent) +{ + const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK; + + // Check for illegal flags. + if(dwBlockFlags & ~VALID_FLAGS) { + return E_INVALIDARG; + } + + // Make sure the event is unsignaled. + if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) { + if( !::ResetEvent( hEvent ) ) { + return AmGetLastErrorToHResult(); + } + } + + // No flags are set if we are unblocking the output pin. + if(0 == dwBlockFlags) { + + // This parameter should be NULL because unblock operations are always synchronous. + // There is no need to notify the caller when the event is done. + if(NULL != hEvent) { + return E_INVALIDARG; + } + } + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + HRESULT hr; + + if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) { + // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous. + // If hEvent is not NULL, the block is asynchronous. + if(NULL == hEvent) { + hr = SynchronousBlockOutputPin(); + } else { + hr = AsynchronousBlockOutputPin(hEvent); + } + } else { + hr = UnblockOutputPin(); + } + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + if(FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void) +{ + HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL, // The event will have the default security attributes. + FALSE, // This is an automatic reset event. + FALSE, // The event is initially unsignaled. + NULL ); // The event is not named. + + // CreateEvent() returns NULL if an error occurs. + if(NULL == hNotifyCallerPinBlockedEvent) { + return AmGetLastErrorToHResult(); + } + + HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent); + if(FAILED(hr)) { + // This call should not fail because we have access to hNotifyCallerPinBlockedEvent + // and hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); + + return hr; + } + + hr = WaitEvent(hNotifyCallerPinBlockedEvent); + + // This call should not fail because we have access to hNotifyCallerPinBlockedEvent + // and hNotifyCallerPinBlockedEvent is a valid event. + EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent)); + + if(FAILED(hr)) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent) +{ + // This function holds the m_BlockStateLock because it uses + // m_dwBlockCallerThreadID, m_BlockState and + // m_hNotifyCallerPinBlockedEvent. + CAutoLock alBlockStateLock(&m_BlockStateLock); + + if(NOT_BLOCKED != m_BlockState) { + if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) { + return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD; + } else { + return VFW_E_PIN_ALREADY_BLOCKED; + } + } + + BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(), + hNotifyCallerPinBlockedEvent, + ::GetCurrentProcess(), + &m_hNotifyCallerPinBlockedEvent, + EVENT_MODIFY_STATE, + FALSE, + 0 ); + if( !fSuccess ) { + return AmGetLastErrorToHResult(); + } + + m_BlockState = PENDING; + m_dwBlockCallerThreadID = ::GetCurrentThreadId(); + + // The output pin cannot be blocked if the streaming thread is + // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive() + // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it + // cannot be blocked if the streaming thread is calling DynamicReconnect(), + // ChangeMediaType() or ChangeOutputFormat(). + if(!StreamingThreadUsingOutputPin()) { + + // The output pin can be immediately blocked. + BlockOutputPin(); + } + + return S_OK; +} + +void CDynamicOutputPin::BlockOutputPin(void) +{ + // The caller should always hold the m_BlockStateLock because this function + // uses m_BlockState and m_hNotifyCallerPinBlockedEvent. + ASSERT(CritCheckIn(&m_BlockStateLock)); + + // This function should not be called if the streaming thread is modifying + // the connection state or it's passing data downstream. + ASSERT(!StreamingThreadUsingOutputPin()); + + // This should not fail because we successfully created the event + // and we have the security permissions to change it's state. + EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent)); + + // This event should not fail because AsynchronousBlockOutputPin() successfully + // duplicated this handle and we have the appropriate security permissions. + EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + + m_BlockState = BLOCKED; + m_hNotifyCallerPinBlockedEvent = NULL; +} + +HRESULT CDynamicOutputPin::UnblockOutputPin(void) +{ + // UnblockOutputPin() holds the m_BlockStateLock because it + // uses m_BlockState, m_dwBlockCallerThreadID and + // m_hNotifyCallerPinBlockedEvent. + CAutoLock alBlockStateLock(&m_BlockStateLock); + + if(NOT_BLOCKED == m_BlockState) { + return S_FALSE; + } + + // This should not fail because we successfully created the event + // and we have the security permissions to change it's state. + EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent)); + + // Cancel the block operation if it's still pending. + if(NULL != m_hNotifyCallerPinBlockedEvent) { + // This event should not fail because AsynchronousBlockOutputPin() successfully + // duplicated this handle and we have the appropriate security permissions. + EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent)); + EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent)); + } + + m_BlockState = NOT_BLOCKED; + m_dwBlockCallerThreadID = 0; + m_hNotifyCallerPinBlockedEvent = NULL; + + return S_OK; +} + +HRESULT CDynamicOutputPin::StartUsingOutputPin(void) +{ + // The caller should not hold m_BlockStateLock. If the caller does, + // a deadlock could occur. + ASSERT(CritCheckOut(&m_BlockStateLock)); + + CAutoLock alBlockStateLock(&m_BlockStateLock); + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + // Are we in the middle of a block operation? + while(BLOCKED == m_BlockState) { + m_BlockStateLock.Unlock(); + + // If this ASSERT fires, a deadlock could occur. The caller should make sure + // that this thread never acquires the Block State lock more than once. + ASSERT(CritCheckOut( &m_BlockStateLock )); + + // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event + // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired. + // See the Windows SDK documentation for more information on + // WaitForMultipleObjects(). + const DWORD UNBLOCK = WAIT_OBJECT_0; + const DWORD STOP = WAIT_OBJECT_0 + 1; + + HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent }; + DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE); + + DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE ); + + m_BlockStateLock.Lock(); + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + switch( dwReturnValue ) { + case UNBLOCK: + break; + + case STOP: + return VFW_E_STATE_CHANGED; + + case WAIT_FAILED: + return AmGetLastErrorToHResult(); + + default: + DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." ); + return E_UNEXPECTED; + } + } + + m_dwNumOutstandingOutputPinUsers++; + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + return S_OK; +} + +void CDynamicOutputPin::StopUsingOutputPin(void) +{ + CAutoLock alBlockStateLock(&m_BlockStateLock); + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG + + m_dwNumOutstandingOutputPinUsers--; + + if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) { + BlockOutputPin(); + } + + #ifdef _DEBUG + AssertValid(); + #endif // DEBUG +} + +bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void) +{ + CAutoLock alBlockStateLock(&m_BlockStateLock); + + return (m_dwNumOutstandingOutputPinUsers > 0); +} + +void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent) +{ + // This pointer is not addrefed because filters are not allowed to + // hold references to the filter graph manager. See the documentation for + // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information. + m_pGraphConfig = pGraphConfig; + + m_hStopEvent = hStopEvent; +} + +HRESULT CDynamicOutputPin::Active(void) +{ + // Make sure the user initialized the object by calling SetConfigInfo(). + if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) { + DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. ); + return E_FAIL; + } + + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then Active() is called. An event + // handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); + + return CBaseOutputPin::Active(); +} + +HRESULT CDynamicOutputPin::Inactive(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then Active() is called. An event + // handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(SetEvent(m_hStopEvent)); + + return CBaseOutputPin::Inactive(); +} + +HRESULT CDynamicOutputPin::DeliverBeginFlush(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. + // An event handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(SetEvent(m_hStopEvent)); + + return CBaseOutputPin::DeliverBeginFlush(); +} + +HRESULT CDynamicOutputPin::DeliverEndFlush(void) +{ + // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo(). + // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called. + // An event handle is invalid if 1) the event does not exist or the user does not have the security + // permissions to use the event. + EXECUTE_ASSERT(ResetEvent(m_hStopEvent)); + + return CBaseOutputPin::DeliverEndFlush(); +} + + +// ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly +// reconnects the output pin. +HRESULT CDynamicOutputPin::ChangeOutputFormat + ( + const AM_MEDIA_TYPE *pmt, + REFERENCE_TIME tSegmentStart, + REFERENCE_TIME tSegmentStop, + double dSegmentRate + ) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + // Callers should always pass a valid media type to ChangeOutputFormat() . + ASSERT(NULL != pmt); + + CMediaType cmt(*pmt); + HRESULT hr = ChangeMediaType(&cmt); + if (FAILED(hr)) { + return hr; + } + + hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate); + if( FAILED( hr ) ) { + return hr; + } + + return S_OK; +} + +HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + // This function assumes the filter graph is running. + ASSERT(!IsStopped()); + + if(!IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + /* First check if the downstream pin will accept a dynamic + format change + */ + QzCComPtr pConnection; + + m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection); + if(pConnection != NULL) { + + if(S_OK == pConnection->DynamicQueryAccept(pmt)) { + + HRESULT hr = ChangeMediaTypeHelper(pmt); + if(FAILED(hr)) { + return hr; + } + + return S_OK; + } + } + + /* Can't do the dynamic connection */ + return DynamicReconnect(pmt); +} + +HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + HRESULT hr = m_Connected->ReceiveConnection(this, pmt); + if(FAILED(hr)) { + return hr; + } + + hr = SetMediaType(pmt); + if(FAILED(hr)) { + return hr; + } + + // Does this pin use the local memory transport? + if(NULL != m_pInputPin) { + // This function assumes that m_pInputPin and m_Connected are + // two different interfaces to the same object. + ASSERT(::IsEqualObject(m_Connected, m_pInputPin)); + + ALLOCATOR_PROPERTIES apInputPinRequirements; + apInputPinRequirements.cbAlign = 0; + apInputPinRequirements.cbBuffer = 0; + apInputPinRequirements.cbPrefix = 0; + apInputPinRequirements.cBuffers = 0; + + m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements); + + // A zero allignment does not make any sense. + if(0 == apInputPinRequirements.cbAlign) { + apInputPinRequirements.cbAlign = 1; + } + + hr = m_pAllocator->Decommit(); + if(FAILED(hr)) { + return hr; + } + + hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements); + if(FAILED(hr)) { + return hr; + } + + hr = m_pAllocator->Commit(); + if(FAILED(hr)) { + return hr; + } + + hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator); + if(FAILED(hr)) { + return hr; + } + } + + return S_OK; +} + +// this method has to be called from the thread that is pushing data, +// and it's the caller's responsibility to make sure that the thread +// has no outstand samples because they cannot be delivered after a +// reconnect +// +HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt ) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) { + return E_FAIL; + } + + HRESULT hr = m_pGraphConfig->Reconnect( + this, + NULL, + pmt, + NULL, + m_hStopEvent, + AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS ); + + return hr; +} + +HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); + if(SUCCEEDED(hr)) { + if(!IsStopped() && m_pAllocator) { + hr = m_pAllocator->Commit(); + ASSERT(hr != VFW_E_ALREADY_COMMITTED); + } + } + + return hr; +} + +#ifdef _DEBUG +void CDynamicOutputPin::AssertValid(void) +{ + // Make sure the object was correctly initialized. + + // This ASSERT only fires if the object failed to initialize + // and the user ignored the constructor's return code (phr). + ASSERT(NULL != m_hUnblockOutputPinEvent); + + // If either of these ASSERTs fire, the user did not correctly call + // SetConfigInfo(). + ASSERT(NULL != m_hStopEvent); + ASSERT(NULL != m_pGraphConfig); + + // Make sure the block state is consistent. + + CAutoLock alBlockStateLock(&m_BlockStateLock); + + // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED. + ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState)); + + // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete + // immediately. + ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) || + ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) ); + + // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and + // the user is not trying to block the pin. + ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState)); + + // If this ASSERT fires, the streaming thread is using the output pin and the + // output pin is blocked. + ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) || + ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) || + ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) ); +} +#endif // DEBUG + +HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent) +{ + const DWORD EVENT_SIGNALED = WAIT_OBJECT_0; + + DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE); + + switch( dwReturnValue ) { + case EVENT_SIGNALED: + return S_OK; + + case WAIT_FAILED: + return AmGetLastErrorToHResult(); + + default: + DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." ); + return E_UNEXPECTED; + } +} + +//===================================================================== +//===================================================================== +// Implements CBaseAllocator +//===================================================================== +//===================================================================== + + +/* Constructor overrides the default settings for the free list to request + that it be alertable (ie the list can be cast to a handle which can be + passed to WaitForSingleObject). Both of the allocator lists also ask for + object locking, the all list matches the object default settings but I + have included them here just so it is obvious what kind of list it is */ + +CBaseAllocator::CBaseAllocator(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + BOOL bEvent, + BOOL fEnableReleaseCallback + ) : + CUnknown(pName, pUnk), + m_lAllocated(0), + m_bChanged(FALSE), + m_bCommitted(FALSE), + m_bDecommitInProgress(FALSE), + m_lSize(0), + m_lCount(0), + m_lAlignment(0), + m_lPrefix(0), + m_hSem(NULL), + m_lWaiting(0), + m_fEnableReleaseCallback(fEnableReleaseCallback), + m_pNotify(NULL) +{ +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBaseAllocator", (IMemAllocator *) this ); +#endif // DXMPERF + + if (bEvent) { + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + } +} + +#ifdef UNICODE +CBaseAllocator::CBaseAllocator(__in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + BOOL bEvent, + BOOL fEnableReleaseCallback) : + CUnknown(pName, pUnk), + m_lAllocated(0), + m_bChanged(FALSE), + m_bCommitted(FALSE), + m_bDecommitInProgress(FALSE), + m_lSize(0), + m_lCount(0), + m_lAlignment(0), + m_lPrefix(0), + m_hSem(NULL), + m_lWaiting(0), + m_fEnableReleaseCallback(fEnableReleaseCallback), + m_pNotify(NULL) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CBaseAllocator", (IMemAllocator *) this ); +#endif // DXMPERF + + if (bEvent) { + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + } +} +#endif + +/* Destructor */ + +CBaseAllocator::~CBaseAllocator() +{ + // we can't call Decommit here since that would mean a call to a + // pure virtual in destructor. + // We must assume that the derived class has gone into decommit state in + // its destructor. +#ifdef DXMPERF + PERFLOG_DTOR( L"CBaseAllocator", (IMemAllocator *) this ); +#endif // DXMPERF + + ASSERT(!m_bCommitted); + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } + if (m_pNotify) { + m_pNotify->Release(); + } +} + + +/* Override this to publicise our interfaces */ + +STDMETHODIMP +CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + /* Do we know about this interface */ + + if (riid == IID_IMemAllocator || + riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) { + return GetInterface((IMemAllocatorCallbackTemp *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +/* This sets the size and count of the required samples. The memory isn't + actually allocated until Commit() is called, if memory has already been + allocated then assuming no samples are outstanding the user may call us + to change the buffering, the memory will be released in Commit() */ + +STDMETHODIMP +CBaseAllocator::SetProperties( + __in ALLOCATOR_PROPERTIES* pRequest, + __out ALLOCATOR_PROPERTIES* pActual) +{ + CheckPointer(pRequest, E_POINTER); + CheckPointer(pActual, E_POINTER); + ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES)); + CAutoLock cObjectLock(this); + + ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); + + ASSERT(pRequest->cbBuffer > 0); + + /* Check the alignment requested */ + if (pRequest->cbAlign != 1) { + DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"), + pRequest->cbAlign)); + return VFW_E_BADALIGN; + } + + /* Can't do this if already committed, there is an argument that says we + should not reject the SetProperties call if there are buffers still + active. However this is called by the source filter, which is the same + person who is holding the samples. Therefore it is not unreasonable + for them to free all their samples before changing the requirements */ + + if (m_bCommitted) { + return VFW_E_ALREADY_COMMITTED; + } + + /* Must be no outstanding buffers */ + + if (m_lAllocated != m_lFree.GetCount()) { + return VFW_E_BUFFERS_OUTSTANDING; + } + + /* There isn't any real need to check the parameters as they + will just be rejected when the user finally calls Commit */ + + pActual->cbBuffer = m_lSize = pRequest->cbBuffer; + pActual->cBuffers = m_lCount = pRequest->cBuffers; + pActual->cbAlign = m_lAlignment = pRequest->cbAlign; + pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; + + m_bChanged = TRUE; + return NOERROR; +} + +STDMETHODIMP +CBaseAllocator::GetProperties( + __out ALLOCATOR_PROPERTIES * pActual) +{ + CheckPointer(pActual,E_POINTER); + ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); + + CAutoLock cObjectLock(this); + pActual->cbBuffer = m_lSize; + pActual->cBuffers = m_lCount; + pActual->cbAlign = m_lAlignment; + pActual->cbPrefix = m_lPrefix; + return NOERROR; +} + +// get container for a sample. Blocking, synchronous call to get the +// next free buffer (as represented by an IMediaSample interface). +// on return, the time etc properties will be invalid, but the buffer +// pointer and size will be correct. + +HRESULT CBaseAllocator::GetBuffer(__deref_out IMediaSample **ppBuffer, + __in_opt REFERENCE_TIME *pStartTime, + __in_opt REFERENCE_TIME *pEndTime, + DWORD dwFlags + ) +{ + UNREFERENCED_PARAMETER(pStartTime); + UNREFERENCED_PARAMETER(pEndTime); + UNREFERENCED_PARAMETER(dwFlags); + CMediaSample *pSample; + + *ppBuffer = NULL; + for (;;) + { + { // scope for lock + CAutoLock cObjectLock(this); + + /* Check we are committed */ + if (!m_bCommitted) { + return VFW_E_NOT_COMMITTED; + } + pSample = (CMediaSample *) m_lFree.RemoveHead(); + if (pSample == NULL) { + SetWaiting(); + } + } + + /* If we didn't get a sample then wait for the list to signal */ + + if (pSample) { + break; + } + if (dwFlags & AM_GBF_NOWAIT) { + return VFW_E_TIMEOUT; + } + ASSERT(m_hSem != NULL); + WaitForSingleObject(m_hSem, INFINITE); + } + + /* Addref the buffer up to one. On release + back to zero instead of being deleted, it will requeue itself by + calling the ReleaseBuffer member function. NOTE the owner of a + media sample must always be derived from CBaseAllocator */ + + + ASSERT(pSample->m_cRef == 0); + pSample->m_cRef = 1; + *ppBuffer = pSample; + +#ifdef DXMPERF + PERFLOG_GETBUFFER( (IMemAllocator *) this, pSample ); +#endif // DXMPERF + + return NOERROR; +} + + +/* Final release of a CMediaSample will call this */ + +STDMETHODIMP +CBaseAllocator::ReleaseBuffer(IMediaSample * pSample) +{ + CheckPointer(pSample,E_POINTER); + ValidateReadPtr(pSample,sizeof(IMediaSample)); + +#ifdef DXMPERF + PERFLOG_RELBUFFER( (IMemAllocator *) this, pSample ); +#endif // DXMPERF + + + BOOL bRelease = FALSE; + { + CAutoLock cal(this); + + /* Put back on the free list */ + + m_lFree.Add((CMediaSample *)pSample); + if (m_lWaiting != 0) { + NotifySample(); + } + + // if there is a pending Decommit, then we need to complete it by + // calling Free() when the last buffer is placed on the free list + + LONG l1 = m_lFree.GetCount(); + if (m_bDecommitInProgress && (l1 == m_lAllocated)) { + Free(); + m_bDecommitInProgress = FALSE; + bRelease = TRUE; + } + } + + if (m_pNotify) { + + ASSERT(m_fEnableReleaseCallback); + + // + // Note that this is not synchronized with setting up a notification + // method. + // + m_pNotify->NotifyRelease(); + } + + /* For each buffer there is one AddRef, made in GetBuffer and released + here. This may cause the allocator and all samples to be deleted */ + + if (bRelease) { + Release(); + } + return NOERROR; +} + +STDMETHODIMP +CBaseAllocator::SetNotify( + IMemAllocatorNotifyCallbackTemp* pNotify + ) +{ + ASSERT(m_fEnableReleaseCallback); + CAutoLock lck(this); + if (pNotify) { + pNotify->AddRef(); + } + if (m_pNotify) { + m_pNotify->Release(); + } + m_pNotify = pNotify; + return S_OK; +} + +STDMETHODIMP +CBaseAllocator::GetFreeCount( + __out LONG* plBuffersFree + ) +{ + ASSERT(m_fEnableReleaseCallback); + CAutoLock cObjectLock(this); + *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount(); + return NOERROR; +} + +void +CBaseAllocator::NotifySample() +{ + if (m_lWaiting != 0) { + ASSERT(m_hSem != NULL); + ReleaseSemaphore(m_hSem, m_lWaiting, 0); + m_lWaiting = 0; + } +} + +STDMETHODIMP +CBaseAllocator::Commit() +{ + /* Check we are not decommitted */ + CAutoLock cObjectLock(this); + + // cannot need to alloc or re-alloc if we are committed + if (m_bCommitted) { + return NOERROR; + } + + /* Allow GetBuffer calls */ + + m_bCommitted = TRUE; + + // is there a pending decommit ? if so, just cancel it + if (m_bDecommitInProgress) { + m_bDecommitInProgress = FALSE; + + // don't call Alloc at this point. He cannot allow SetProperties + // between Decommit and the last free, so the buffer size cannot have + // changed. And because some of the buffers are not free yet, he + // cannot re-alloc anyway. + return NOERROR; + } + + DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize)); + + // actually need to allocate the samples + HRESULT hr = Alloc(); + if (FAILED(hr)) { + m_bCommitted = FALSE; + return hr; + } + AddRef(); + return NOERROR; +} + + +STDMETHODIMP +CBaseAllocator::Decommit() +{ + BOOL bRelease = FALSE; + { + /* Check we are not already decommitted */ + CAutoLock cObjectLock(this); + if (m_bCommitted == FALSE) { + if (m_bDecommitInProgress == FALSE) { + return NOERROR; + } + } + + /* No more GetBuffer calls will succeed */ + m_bCommitted = FALSE; + + // are any buffers outstanding? + if (m_lFree.GetCount() < m_lAllocated) { + // please complete the decommit when last buffer is freed + m_bDecommitInProgress = TRUE; + } else { + m_bDecommitInProgress = FALSE; + + // need to complete the decommit here as there are no + // outstanding buffers + + Free(); + bRelease = TRUE; + } + + // Tell anyone waiting that they can go now so we can + // reject their call +#pragma warning(push) +#ifndef _PREFAST_ +#pragma warning(disable:4068) +#endif +#pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "Suppress warning related to Free() invalidating 'this' which is no applicable to CBaseAllocator::Free()") + NotifySample(); + +#pragma warning(pop) + } + + if (bRelease) { + Release(); + } + return NOERROR; +} + + +/* Base definition of allocation which checks we are ok to go ahead and do + the full allocation. We return S_FALSE if the requirements are the same */ + +HRESULT +CBaseAllocator::Alloc(void) +{ + /* Error if he hasn't set the size yet */ + if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) { + return VFW_E_SIZENOTSET; + } + + /* should never get here while buffers outstanding */ + ASSERT(m_lFree.GetCount() == m_lAllocated); + + /* If the requirements haven't changed then don't reallocate */ + if (m_bChanged == FALSE) { + return S_FALSE; + } + + return NOERROR; +} + +/* Implement CBaseAllocator::CSampleList::Remove(pSample) + Removes pSample from the list +*/ +void +CBaseAllocator::CSampleList::Remove(__inout CMediaSample * pSample) +{ + CMediaSample **pSearch; + for (pSearch = &m_List; + *pSearch != NULL; + pSearch = &(CBaseAllocator::NextSample(*pSearch))) { + if (*pSearch == pSample) { + *pSearch = CBaseAllocator::NextSample(pSample); + CBaseAllocator::NextSample(pSample) = NULL; + m_nOnList--; + return; + } + } + DbgBreak("Couldn't find sample in list"); +} + +//===================================================================== +//===================================================================== +// Implements CMemAllocator +//===================================================================== +//===================================================================== + + +/* This goes in the factory template table to create new instances */ +CUnknown *CMemAllocator::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) +{ + CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr); + return pUnkRet; +} + +CMemAllocator::CMemAllocator( + __in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr) + : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), + m_pBuffer(NULL) +{ +} + +#ifdef UNICODE +CMemAllocator::CMemAllocator( + __in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr) + : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE), + m_pBuffer(NULL) +{ +} +#endif + +/* This sets the size and count of the required samples. The memory isn't + actually allocated until Commit() is called, if memory has already been + allocated then assuming no samples are outstanding the user may call us + to change the buffering, the memory will be released in Commit() */ +STDMETHODIMP +CMemAllocator::SetProperties( + __in ALLOCATOR_PROPERTIES* pRequest, + __out ALLOCATOR_PROPERTIES* pActual) +{ + CheckPointer(pActual,E_POINTER); + ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES)); + CAutoLock cObjectLock(this); + + ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); + + ASSERT(pRequest->cbBuffer > 0); + + SYSTEM_INFO SysInfo; + GetSystemInfo(&SysInfo); + + /* Check the alignment request is a power of 2 */ + if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) { + DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"), + pRequest->cbAlign)); + } + /* Check the alignment requested */ + if (pRequest->cbAlign == 0 || + (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) { + DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"), + pRequest->cbAlign, SysInfo.dwAllocationGranularity)); + return VFW_E_BADALIGN; + } + + /* Can't do this if already committed, there is an argument that says we + should not reject the SetProperties call if there are buffers still + active. However this is called by the source filter, which is the same + person who is holding the samples. Therefore it is not unreasonable + for them to free all their samples before changing the requirements */ + + if (m_bCommitted == TRUE) { + return VFW_E_ALREADY_COMMITTED; + } + + /* Must be no outstanding buffers */ + + if (m_lFree.GetCount() < m_lAllocated) { + return VFW_E_BUFFERS_OUTSTANDING; + } + + /* There isn't any real need to check the parameters as they + will just be rejected when the user finally calls Commit */ + + // round length up to alignment - remember that prefix is included in + // the alignment + LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix; + LONG lRemainder = lSize % pRequest->cbAlign; + if (lRemainder != 0) { + lSize = lSize - lRemainder + pRequest->cbAlign; + } + pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix); + + pActual->cBuffers = m_lCount = pRequest->cBuffers; + pActual->cbAlign = m_lAlignment = pRequest->cbAlign; + pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix; + + m_bChanged = TRUE; + return NOERROR; +} + +// override this to allocate our resources when Commit is called. +// +// note that our resources may be already allocated when this is called, +// since we don't free them on Decommit. We will only be called when in +// decommit state with all buffers free. +// +// object locked by caller +HRESULT +CMemAllocator::Alloc(void) +{ + CAutoLock lck(this); + + /* Check he has called SetProperties */ + HRESULT hr = CBaseAllocator::Alloc(); + if (FAILED(hr)) { + return hr; + } + + /* If the requirements haven't changed then don't reallocate */ + if (hr == S_FALSE) { + ASSERT(m_pBuffer); + return NOERROR; + } + ASSERT(hr == S_OK); // we use this fact in the loop below + + /* Free the old resources */ + if (m_pBuffer) { + ReallyFree(); + } + + /* Make sure we've got reasonable values */ + if ( m_lSize < 0 || m_lPrefix < 0 || m_lCount < 0 ) { + return E_OUTOFMEMORY; + } + + /* Compute the aligned size */ + LONG lAlignedSize = m_lSize + m_lPrefix; + + /* Check overflow */ + if (lAlignedSize < m_lSize) { + return E_OUTOFMEMORY; + } + + if (m_lAlignment > 1) { + LONG lRemainder = lAlignedSize % m_lAlignment; + if (lRemainder != 0) { + LONG lNewSize = lAlignedSize + m_lAlignment - lRemainder; + if (lNewSize < lAlignedSize) { + return E_OUTOFMEMORY; + } + lAlignedSize = lNewSize; + } + } + + /* Create the contiguous memory block for the samples + making sure it's properly aligned (64K should be enough!) + */ + ASSERT(lAlignedSize % m_lAlignment == 0); + + LONGLONG lToAllocate = m_lCount * (LONGLONG)lAlignedSize; + + /* Check overflow */ + if (lToAllocate > MAXLONG) { + return E_OUTOFMEMORY; + } + + m_pBuffer = (PBYTE)VirtualAlloc(NULL, + (LONG)lToAllocate, + MEM_COMMIT, + PAGE_READWRITE); + + if (m_pBuffer == NULL) { + return E_OUTOFMEMORY; + } + + LPBYTE pNext = m_pBuffer; + CMediaSample *pSample; + + ASSERT(m_lAllocated == 0); + + // Create the new samples - we have allocated m_lSize bytes for each sample + // plus m_lPrefix bytes per sample as a prefix. We set the pointer to + // the memory after the prefix - so that GetPointer() will return a pointer + // to m_lSize bytes. + for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { + + + pSample = new CMediaSample( + NAME("Default memory media sample"), + this, + &hr, + pNext + m_lPrefix, // GetPointer() value + m_lSize); // not including prefix + + ASSERT(SUCCEEDED(hr)); + if (pSample == NULL) { + return E_OUTOFMEMORY; + } + + // This CANNOT fail + m_lFree.Add(pSample); + } + + m_bChanged = FALSE; + return NOERROR; +} + + +// override this to free up any resources we have allocated. +// called from the base class on Decommit when all buffers have been +// returned to the free list. +// +// caller has already locked the object. + +// in our case, we keep the memory until we are deleted, so +// we do nothing here. The memory is deleted in the destructor by +// calling ReallyFree() +void +CMemAllocator::Free(void) +{ + return; +} + + +// called from the destructor (and from Alloc if changing size/count) to +// actually free up the memory +void +CMemAllocator::ReallyFree(void) +{ + /* Should never be deleting this unless all buffers are freed */ + + ASSERT(m_lAllocated == m_lFree.GetCount()); + + /* Free up all the CMediaSamples */ + + CMediaSample *pSample; + for (;;) { + pSample = m_lFree.RemoveHead(); + if (pSample != NULL) { + delete pSample; + } else { + break; + } + } + + m_lAllocated = 0; + + // free the block of buffer memory + if (m_pBuffer) { + EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE)); + m_pBuffer = NULL; + } +} + + +/* Destructor frees our memory resources */ + +CMemAllocator::~CMemAllocator() +{ + Decommit(); + ReallyFree(); +} + +// ------------------------------------------------------------------------ +// filter registration through IFilterMapper. used if IFilterMapper is +// not found (Quartz 1.0 install) + +STDAPI +AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper * pIFM + , BOOL bRegister ) +{ + DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + + // unregister filter + // (as pins are subkeys of filter's CLSID key + // they do not need to be removed separately). + // + DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); + HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) ); + + + if( bRegister ) + { + // register filter + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); + hr = pIFM->RegisterFilter( *(psetupdata->clsID) + , psetupdata->strName + , psetupdata->dwMerit ); + if( SUCCEEDED(hr) ) + { + // all its pins + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins"))); + for( UINT m1=0; m1 < psetupdata->nPins; m1++ ) + { + hr = pIFM->RegisterPin( *(psetupdata->clsID) + , psetupdata->lpPin[m1].strName + , psetupdata->lpPin[m1].bRendered + , psetupdata->lpPin[m1].bOutput + , psetupdata->lpPin[m1].bZero + , psetupdata->lpPin[m1].bMany + , *(psetupdata->lpPin[m1].clsConnectsToFilter) + , psetupdata->lpPin[m1].strConnectsToPin ); + + if( SUCCEEDED(hr) ) + { + // and each pin's media types + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types"))); + for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ ) + { + hr = pIFM->RegisterPinType( *(psetupdata->clsID) + , psetupdata->lpPin[m1].strName + , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType) + , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) ); + if( FAILED(hr) ) break; + } + if( FAILED(hr) ) break; + } + if( FAILED(hr) ) break; + } + } + } + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + +// Remove warnings about unreferenced inline functions +#pragma warning(disable:4514) + diff --git a/src/thirdparty/BaseClasses/amfilter.h b/src/thirdparty/BaseClasses/amfilter.h index 1f725437489..82e0268f4c6 100644 --- a/src/thirdparty/BaseClasses/amfilter.h +++ b/src/thirdparty/BaseClasses/amfilter.h @@ -1,1587 +1,1587 @@ -//------------------------------------------------------------------------------ -// File: AMFilter.h -// -// Desc: DirectShow base classes - efines class hierarchy for streams -// architecture. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __FILTER__ -#define __FILTER__ - -/* The following classes are declared in this header: */ - -class CBaseMediaFilter; // IMediaFilter support -class CBaseFilter; // IBaseFilter,IMediaFilter support -class CBasePin; // Abstract base class for IPin interface -class CEnumPins; // Enumerate input and output pins -class CEnumMediaTypes; // Enumerate the pin's preferred formats -class CBaseOutputPin; // Adds data provider member functions -class CBaseInputPin; // Implements IMemInputPin interface -class CMediaSample; // Basic transport unit for IMemInputPin -class CBaseAllocator; // General list guff for most allocators -class CMemAllocator; // Implements memory buffer allocation - - -//===================================================================== -//===================================================================== -// -// QueryFilterInfo and QueryPinInfo AddRef the interface pointers -// they return. You can use the macro below to release the interface. -// -//===================================================================== -//===================================================================== - -#define QueryFilterInfoReleaseGraph(fi) if ((fi).pGraph) (fi).pGraph->Release(); - -#define QueryPinInfoReleaseFilter(pi) if ((pi).pFilter) (pi).pFilter->Release(); - -//===================================================================== -//===================================================================== -// Defines CBaseMediaFilter -// -// Abstract base class implementing IMediaFilter. -// -// Typically you will derive your filter from CBaseFilter rather than -// this, unless you are implementing an object such as a plug-in -// distributor that needs to support IMediaFilter but not IBaseFilter. -// -// Note that IMediaFilter is derived from IPersist to allow query of -// class id. -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseMediaFilter : public CUnknown, - public IMediaFilter -{ - -protected: - - FILTER_STATE m_State; // current state: running, paused - IReferenceClock *m_pClock; // this filter's reference clock - // note: all filters in a filter graph use the same clock - - // offset from stream time to reference time - CRefTime m_tStart; - - CLSID m_clsid; // This filters clsid - // used for serialization - CCritSec *m_pLock; // Object we use for locking - -public: - - CBaseMediaFilter( - __in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __in CCritSec *pLock, - REFCLSID clsid); - - virtual ~CBaseMediaFilter(); - - DECLARE_IUNKNOWN - - // override this to say what interfaces we support where - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - - // - // --- IPersist method --- - // - - STDMETHODIMP GetClassID(__out CLSID *pClsID); - - // --- IMediaFilter methods --- - - STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); - - STDMETHODIMP SetSyncSource(__inout_opt IReferenceClock *pClock); - - STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock); - - // default implementation of Stop and Pause just record the - // state. Override to activate or de-activate your filter. - // Note that Run when called from Stopped state will call Pause - // to ensure activation, so if you are a source or transform - // you will probably not need to override Run. - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - - - // the start parameter is the difference to be added to the - // sample's stream time to get the reference time for - // its presentation - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // --- helper methods --- - - // return the current stream time - ie find out what - // stream time should be appearing now - virtual HRESULT StreamTime(CRefTime& rtStream); - - // Is the filter currently active? (running or paused) - BOOL IsActive() { - CAutoLock cObjectLock(m_pLock); - return ((m_State == State_Paused) || (m_State == State_Running)); - }; -}; - -//===================================================================== -//===================================================================== -// Defines CBaseFilter -// -// An abstract class providing basic IBaseFilter support for pin -// enumeration and filter information reading. -// -// We cannot derive from CBaseMediaFilter since methods in IMediaFilter -// are also in IBaseFilter and would be ambiguous. Since much of the code -// assumes that they derive from a class that has m_State and other state -// directly available, we duplicate code from CBaseMediaFilter rather than -// having a member variable. -// -// Derive your filter from this, or from a derived object such as -// CTransformFilter. -//===================================================================== -//===================================================================== - - -class AM_NOVTABLE CBaseFilter : public CUnknown, // Handles an IUnknown - public IBaseFilter, // The Filter Interface - public IAMovieSetup // For un/registration -{ - -friend class CBasePin; - -protected: - FILTER_STATE m_State; // current state: running, paused - IReferenceClock *m_pClock; // this graph's ref clock - CRefTime m_tStart; // offset from stream time to reference time - CLSID m_clsid; // This filters clsid - // used for serialization - CCritSec *m_pLock; // Object we use for locking - - WCHAR *m_pName; // Full filter name - IFilterGraph *m_pGraph; // Graph we belong to - IMediaEventSink *m_pSink; // Called with notify events - LONG m_PinVersion; // Current pin version - -public: - - CBaseFilter( - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // IUnknown of delegating object - __in CCritSec *pLock, // Object who maintains lock - REFCLSID clsid); // The clsid to be used to serialize this filter - - CBaseFilter( - __in_opt LPCTSTR pName, // Object description - __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object - __in CCritSec *pLock, // Object who maintains lock - REFCLSID clsid, // The clsid to be used to serialize this filter - __inout HRESULT *phr); // General OLE return code -#ifdef UNICODE - CBaseFilter( - __in_opt LPCSTR pName, // Object description - __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object - __in CCritSec *pLock, // Object who maintains lock - REFCLSID clsid); // The clsid to be used to serialize this filter - - CBaseFilter( - __in_opt LPCSTR pName, // Object description - __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object - __in CCritSec *pLock, // Object who maintains lock - REFCLSID clsid, // The clsid to be used to serialize this filter - __inout HRESULT *phr); // General OLE return code -#endif - ~CBaseFilter(); - - DECLARE_IUNKNOWN - - // override this to say what interfaces we support where - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); -#ifdef _DEBUG - STDMETHODIMP_(ULONG) NonDelegatingRelease(); -#endif - - // - // --- IPersist method --- - // - - STDMETHODIMP GetClassID(__out CLSID *pClsID); - - // --- IMediaFilter methods --- - - STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); - - STDMETHODIMP SetSyncSource(__in_opt IReferenceClock *pClock); - - STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock); - - - // override Stop and Pause so we can activate the pins. - // Note that Run will call Pause first if activation needed. - // Override these if you want to activate your filter rather than - // your pins. - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - - // the start parameter is the difference to be added to the - // sample's stream time to get the reference time for - // its presentation - STDMETHODIMP Run(REFERENCE_TIME tStart); - - // --- helper methods --- - - // return the current stream time - ie find out what - // stream time should be appearing now - virtual HRESULT StreamTime(CRefTime& rtStream); - - // Is the filter currently active? - BOOL IsActive() { - CAutoLock cObjectLock(m_pLock); - return ((m_State == State_Paused) || (m_State == State_Running)); - }; - - // Is this filter stopped (without locking) - BOOL IsStopped() { - return (m_State == State_Stopped); - }; - - // - // --- IBaseFilter methods --- - // - - // pin enumerator - STDMETHODIMP EnumPins( - __deref_out IEnumPins ** ppEnum); - - - // default behaviour of FindPin assumes pin ids are their names - STDMETHODIMP FindPin( - LPCWSTR Id, - __deref_out IPin ** ppPin - ); - - STDMETHODIMP QueryFilterInfo( - __out FILTER_INFO * pInfo); - - STDMETHODIMP JoinFilterGraph( - __inout_opt IFilterGraph * pGraph, - __in_opt LPCWSTR pName); - - // return a Vendor information string. Optional - may return E_NOTIMPL. - // memory returned should be freed using CoTaskMemFree - // default implementation returns E_NOTIMPL - STDMETHODIMP QueryVendorInfo( - __deref_out LPWSTR* pVendorInfo - ); - - // --- helper methods --- - - // send an event notification to the filter graph if we know about it. - // returns S_OK if delivered, S_FALSE if the filter graph does not sink - // events, or an error otherwise. - HRESULT NotifyEvent( - long EventCode, - LONG_PTR EventParam1, - LONG_PTR EventParam2); - - // return the filter graph we belong to - __out_opt IFilterGraph *GetFilterGraph() { - return m_pGraph; - } - - // Request reconnect - // pPin is the pin to reconnect - // pmt is the type to reconnect with - can be NULL - // Calls ReconnectEx on the filter graph - HRESULT ReconnectPin(IPin *pPin, __in_opt AM_MEDIA_TYPE const *pmt); - - // find out the current pin version (used by enumerators) - virtual LONG GetPinVersion(); - void IncrementPinVersion(); - - // you need to supply these to access the pins from the enumerator - // and for default Stop and Pause/Run activation. - virtual int GetPinCount() PURE; - virtual CBasePin *GetPin(int n) PURE; - - // --- IAMovieSetup methods --- - - STDMETHODIMP Register(); // ask filter to register itself - STDMETHODIMP Unregister(); // and unregister itself - - // --- setup helper methods --- - // (override to return filters setup data) - - virtual __out_opt LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; } - -}; - - -//===================================================================== -//===================================================================== -// Defines CBasePin -// -// Abstract class that supports the basics of IPin -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl -{ - -protected: - - WCHAR * m_pName; // This pin's name - IPin *m_Connected; // Pin we have connected to - PIN_DIRECTION m_dir; // Direction of this pin - CCritSec *m_pLock; // Object we use for locking - bool m_bRunTimeError; // Run time error generated - bool m_bCanReconnectWhenActive; // OK to reconnect when active - bool m_bTryMyTypesFirst; // When connecting enumerate - // this pin's types first - CBaseFilter *m_pFilter; // Filter we were created by - IQualityControl *m_pQSink; // Target for Quality messages - LONG m_TypeVersion; // Holds current type version - CMediaType m_mt; // Media type of connection - - CRefTime m_tStart; // time from NewSegment call - CRefTime m_tStop; // time from NewSegment - double m_dRate; // rate from NewSegment - -#ifdef _DEBUG - LONG m_cRef; // Ref count tracing -#endif - - // displays pin connection information - -#ifdef _DEBUG - void DisplayPinInfo(IPin *pReceivePin); - void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt); -#else - void DisplayPinInfo(IPin *pReceivePin) {}; - void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {}; -#endif - - // used to agree a media type for a pin connection - - // given a specific media type, attempt a connection (includes - // checking that the type is acceptable to this pin) - HRESULT - AttemptConnection( - IPin* pReceivePin, // connect to this pin - const CMediaType* pmt // using this type - ); - - // try all the media types in this enumerator - for each that - // we accept, try to connect using ReceiveConnection. - HRESULT TryMediaTypes( - IPin *pReceivePin, // connect to this pin - __in_opt const CMediaType *pmt, // proposed type from Connect - IEnumMediaTypes *pEnum); // try this enumerator - - // establish a connection with a suitable mediatype. Needs to - // propose a media type if the pmt pointer is null or partially - // specified - use TryMediaTypes on both our and then the other pin's - // enumerator until we find one that works. - HRESULT AgreeMediaType( - IPin *pReceivePin, // connect to this pin - const CMediaType *pmt); // proposed type from Connect - -public: - - CBasePin( - __in_opt LPCTSTR pObjectName, // Object description - __in CBaseFilter *pFilter, // Owning filter who knows about pins - __in CCritSec *pLock, // Object who implements the lock - __inout HRESULT *phr, // General OLE return code - __in_opt LPCWSTR pName, // Pin name for us - PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT -#ifdef UNICODE - CBasePin( - __in_opt LPCSTR pObjectName, // Object description - __in CBaseFilter *pFilter, // Owning filter who knows about pins - __in CCritSec *pLock, // Object who implements the lock - __inout HRESULT *phr, // General OLE return code - __in_opt LPCWSTR pName, // Pin name for us - PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT -#endif - virtual ~CBasePin(); - - DECLARE_IUNKNOWN - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - - // --- IPin methods --- - - // take lead role in establishing a connection. Media type pointer - // may be null, or may point to partially-specified mediatype - // (subtype or format type may be GUID_NULL). - STDMETHODIMP Connect( - IPin * pReceivePin, - __in_opt const AM_MEDIA_TYPE *pmt // optional media type - ); - - // (passive) accept a connection from another pin - STDMETHODIMP ReceiveConnection( - IPin * pConnector, // this is the initiating connecting pin - const AM_MEDIA_TYPE *pmt // this is the media type we will exchange - ); - - STDMETHODIMP Disconnect(); - - STDMETHODIMP ConnectedTo(__deref_out IPin **pPin); - - STDMETHODIMP ConnectionMediaType(__out AM_MEDIA_TYPE *pmt); - - STDMETHODIMP QueryPinInfo( - __out PIN_INFO * pInfo - ); - - STDMETHODIMP QueryDirection( - __out PIN_DIRECTION * pPinDir - ); - - STDMETHODIMP QueryId( - __deref_out LPWSTR * Id - ); - - // does the pin support this media type - STDMETHODIMP QueryAccept( - const AM_MEDIA_TYPE *pmt - ); - - // return an enumerator for this pins preferred media types - STDMETHODIMP EnumMediaTypes( - __deref_out IEnumMediaTypes **ppEnum - ); - - // return an array of IPin* - the pins that this pin internally connects to - // All pins put in the array must be AddReffed (but no others) - // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE - // Default: return E_NOTIMPL - // The filter graph will interpret NOT_IMPL as any input pin connects to - // all visible output pins and vice versa. - // apPin can be NULL if nPin==0 (not otherwise). - STDMETHODIMP QueryInternalConnections( - __out_ecount_part(*nPin,*nPin) IPin* *apPin, // array of IPin* - __inout ULONG *nPin // on input, the number of slots - // on output the number of pins - ) { return E_NOTIMPL; } - - // Called when no more data will be sent - STDMETHODIMP EndOfStream(void); - - // Begin/EndFlush still PURE - - // NewSegment notifies of the start/stop/rate applying to the data - // about to be received. Default implementation records data and - // returns S_OK. - // Override this to pass downstream. - STDMETHODIMP NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - //================================================================================ - // IQualityControl methods - //================================================================================ - - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - STDMETHODIMP SetSink(IQualityControl * piqc); - - // --- helper methods --- - - // Returns true if the pin is connected. false otherwise. - BOOL IsConnected(void) {return (m_Connected != NULL); }; - // Return the pin this is connected to (if any) - IPin * GetConnected() { return m_Connected; }; - - // Check if our filter is currently stopped - BOOL IsStopped() { - return (m_pFilter->m_State == State_Stopped); - }; - - // find out the current type version (used by enumerators) - virtual LONG GetMediaTypeVersion(); - void IncrementTypeVersion(); - - // switch the pin to active (paused or running) mode - // not an error to call this if already active - virtual HRESULT Active(void); - - // switch the pin to inactive state - may already be inactive - virtual HRESULT Inactive(void); - - // Notify of Run() from filter - virtual HRESULT Run(REFERENCE_TIME tStart); - - // check if the pin can support this specific proposed type and format - virtual HRESULT CheckMediaType(const CMediaType *) PURE; - - // set the connection to use this format (previously agreed) - virtual HRESULT SetMediaType(const CMediaType *); - - // check that the connection is ok before verifying it - // can be overridden eg to check what interfaces will be supported. - virtual HRESULT CheckConnect(IPin *); - - // Set and release resources required for a connection - virtual HRESULT BreakConnect(); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // returns the preferred formats for a pin - virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); - - // access to NewSegment values - REFERENCE_TIME CurrentStopTime() { - return m_tStop; - } - REFERENCE_TIME CurrentStartTime() { - return m_tStart; - } - double CurrentRate() { - return m_dRate; - } - - // Access name - LPWSTR Name() { return m_pName; }; - - // Can reconnectwhen active? - void SetReconnectWhenActive(bool bCanReconnect) - { - m_bCanReconnectWhenActive = bCanReconnect; - } - - bool CanReconnectWhenActive() - { - return m_bCanReconnectWhenActive; - } - -protected: - STDMETHODIMP DisconnectInternal(); -}; - - -//===================================================================== -//===================================================================== -// Defines CEnumPins -// -// Pin enumerator class that works by calling CBaseFilter. This interface -// is provided by CBaseFilter::EnumPins and calls GetPinCount() and -// GetPin() to enumerate existing pins. Needs to be a separate object so -// that it can be cloned (creating an existing object at the same -// position in the enumeration) -// -//===================================================================== -//===================================================================== - -class CEnumPins : public IEnumPins // The interface we support -{ - int m_Position; // Current ordinal position - int m_PinCount; // Number of pins available - CBaseFilter *m_pFilter; // The filter who owns us - LONG m_Version; // Pin version information - LONG m_cRef; - - typedef CGenericList CPinList; - - CPinList m_PinCache; // These pointers have not been AddRef'ed and - // so they should not be dereferenced. They are - // merely kept to ID which pins have been enumerated. - -#ifdef _DEBUG - DWORD m_dwCookie; -#endif - - /* If while we are retrieving a pin for example from the filter an error - occurs we assume that our internal state is stale with respect to the - filter (someone may have deleted all the pins). We can check before - starting whether or not the operation is likely to fail by asking the - filter what it's current version number is. If the filter has not - overriden the GetPinVersion method then this will always match */ - - BOOL AreWeOutOfSync() { - return (m_pFilter->GetPinVersion() == m_Version ? FALSE : TRUE); - }; - - /* This method performs the same operations as Reset, except is does not clear - the cache of pins already enumerated. */ - - STDMETHODIMP Refresh(); - -public: - - CEnumPins( - __in CBaseFilter *pFilter, - __in_opt CEnumPins *pEnumPins); - - virtual ~CEnumPins(); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // IEnumPins - STDMETHODIMP Next( - ULONG cPins, // place this many pins... - __out_ecount(cPins) IPin ** ppPins, // ...in this array of IPin* - __out_opt ULONG * pcFetched // actual count passed returned here - ); - - STDMETHODIMP Skip(ULONG cPins); - STDMETHODIMP Reset(); - STDMETHODIMP Clone(__deref_out IEnumPins **ppEnum); - - -}; - - -//===================================================================== -//===================================================================== -// Defines CEnumMediaTypes -// -// Enumerates the preferred formats for input and output pins -//===================================================================== -//===================================================================== - -class CEnumMediaTypes : public IEnumMediaTypes // The interface we support -{ - int m_Position; // Current ordinal position - CBasePin *m_pPin; // The pin who owns us - LONG m_Version; // Media type version value - LONG m_cRef; -#ifdef _DEBUG - DWORD m_dwCookie; -#endif - - /* The media types a filter supports can be quite dynamic so we add to - the general IEnumXXXX interface the ability to be signaled when they - change via an event handle the connected filter supplies. Until the - Reset method is called after the state changes all further calls to - the enumerator (except Reset) will return E_UNEXPECTED error code */ - - BOOL AreWeOutOfSync() { - return (m_pPin->GetMediaTypeVersion() == m_Version ? FALSE : TRUE); - }; - -public: - - CEnumMediaTypes( - __in CBasePin *pPin, - __in_opt CEnumMediaTypes *pEnumMediaTypes); - - virtual ~CEnumMediaTypes(); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // IEnumMediaTypes - STDMETHODIMP Next( - ULONG cMediaTypes, // place this many pins... - __out_ecount(cMediaTypes) AM_MEDIA_TYPE ** ppMediaTypes, // ...in this array - __out_opt ULONG * pcFetched // actual count passed - ); - - STDMETHODIMP Skip(ULONG cMediaTypes); - STDMETHODIMP Reset(); - STDMETHODIMP Clone(__deref_out IEnumMediaTypes **ppEnum); -}; - - - - -//===================================================================== -//===================================================================== -// Defines CBaseOutputPin -// -// class derived from CBasePin that can pass buffers to a connected pin -// that supports IMemInputPin. Supports IPin. -// -// Derive your output pin from this. -// -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseOutputPin : public CBasePin -{ - -protected: - - IMemAllocator *m_pAllocator; - IMemInputPin *m_pInputPin; // interface on the downstreaminput pin - // set up in CheckConnect when we connect. - -public: - - CBaseOutputPin( - __in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CBaseOutputPin( - __in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#endif - // override CompleteConnect() so we can negotiate an allocator - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // negotiate the allocator and its buffer size/count and other properties - // Calls DecideBufferSize to set properties - virtual HRESULT DecideAllocator(IMemInputPin * pPin, __deref_out IMemAllocator ** pAlloc); - - // override this to set the buffer size and count. Return an error - // if the size/count is not to your liking. - // The allocator properties passed in are those requested by the - // input pin - use eg the alignment and prefix members if you have - // no preference on these. - virtual HRESULT DecideBufferSize( - IMemAllocator * pAlloc, - __inout ALLOCATOR_PROPERTIES * ppropInputRequest - ) PURE; - - // returns an empty sample buffer from the allocator - virtual HRESULT GetDeliveryBuffer(__deref_out IMediaSample ** ppSample, - __in_opt REFERENCE_TIME * pStartTime, - __in_opt REFERENCE_TIME * pEndTime, - DWORD dwFlags); - - // deliver a filled-in sample to the connected input pin - // note - you need to release it after calling this. The receiving - // pin will addref the sample if it needs to hold it beyond the - // call. - virtual HRESULT Deliver(IMediaSample *); - - // override this to control the connection - virtual HRESULT InitAllocator(__deref_out IMemAllocator **ppAlloc); - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - - // override to call Commit and Decommit - HRESULT Active(void); - HRESULT Inactive(void); - - // we have a default handling of EndOfStream which is to return - // an error, since this should be called on input pins only - STDMETHODIMP EndOfStream(void); - - // called from elsewhere in our filter to pass EOS downstream to - // our connected input pin - virtual HRESULT DeliverEndOfStream(void); - - // same for Begin/EndFlush - we handle Begin/EndFlush since it - // is an error on an output pin, and we have Deliver methods to - // call the methods on the connected pin - STDMETHODIMP BeginFlush(void); - STDMETHODIMP EndFlush(void); - virtual HRESULT DeliverBeginFlush(void); - virtual HRESULT DeliverEndFlush(void); - - // deliver NewSegment to connected pin - you will need to - // override this if you queue any data in your output pin. - virtual HRESULT DeliverNewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - //================================================================================ - // IQualityControl methods - //================================================================================ - - // All inherited from CBasePin and not overridden here. - // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - // STDMETHODIMP SetSink(IQualityControl * piqc); -}; - - -//===================================================================== -//===================================================================== -// Defines CBaseInputPin -// -// derive your standard input pin from this. -// you need to supply GetMediaType and CheckConnect etc (see CBasePin), -// and you need to supply Receive to do something more useful. -// -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseInputPin : public CBasePin, - public IMemInputPin -{ - -protected: - - IMemAllocator *m_pAllocator; // Default memory allocator - - // allocator is read-only, so received samples - // cannot be modified (probably only relevant to in-place - // transforms - BYTE m_bReadOnly; - - // in flushing state (between BeginFlush and EndFlush) - // if TRUE, all Receives are returned with S_FALSE - BYTE m_bFlushing; - - // Sample properties - initalized in Receive - AM_SAMPLE2_PROPERTIES m_SampleProps; - -public: - - CBaseInputPin( - __in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CBaseInputPin( - __in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#endif - virtual ~CBaseInputPin(); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - // return the allocator interface that this input pin - // would like the output pin to use - STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator); - - // tell the input pin which allocator the output pin is actually - // going to use. - STDMETHODIMP NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly); - - // do something with this media sample - STDMETHODIMP Receive(IMediaSample *pSample); - - // do something with these media samples - STDMETHODIMP ReceiveMultiple ( - __in_ecount(nSamples) IMediaSample **pSamples, - long nSamples, - __out long *nSamplesProcessed); - - // See if Receive() blocks - STDMETHODIMP ReceiveCanBlock(); - - // Default handling for BeginFlush - call at the beginning - // of your implementation (makes sure that all Receive calls - // fail). After calling this, you need to free any queued data - // and then call downstream. - STDMETHODIMP BeginFlush(void); - - // default handling for EndFlush - call at end of your implementation - // - before calling this, ensure that there is no queued data and no thread - // pushing any more without a further receive, then call downstream, - // then call this method to clear the m_bFlushing flag and re-enable - // receives - STDMETHODIMP EndFlush(void); - - // this method is optional (can return E_NOTIMPL). - // default implementation returns E_NOTIMPL. Override if you have - // specific alignment or prefix needs, but could use an upstream - // allocator - STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps); - - // Release the pin's allocator. - HRESULT BreakConnect(); - - // helper method to check the read-only flag - BOOL IsReadOnly() { - return m_bReadOnly; - }; - - // helper method to see if we are flushing - BOOL IsFlushing() { - return m_bFlushing; - }; - - // Override this for checking whether it's OK to process samples - // Also call this from EndOfStream. - virtual HRESULT CheckStreaming(); - - // Pass a Quality notification on to the appropriate sink - HRESULT PassNotify(Quality& q); - - - //================================================================================ - // IQualityControl methods (from CBasePin) - //================================================================================ - - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - // no need to override: - // STDMETHODIMP SetSink(IQualityControl * piqc); - - - // switch the pin to inactive state - may already be inactive - virtual HRESULT Inactive(void); - - // Return sample properties pointer - AM_SAMPLE2_PROPERTIES * SampleProps() { - ASSERT(m_SampleProps.cbData != 0); - return &m_SampleProps; - } - -}; - -/////////////////////////////////////////////////////////////////////////// -// CDynamicOutputPin -// - -class CDynamicOutputPin : public CBaseOutputPin, - public IPinFlowControl -{ -public: -#ifdef UNICODE - CDynamicOutputPin( - __in_opt LPCSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); -#endif - - CDynamicOutputPin( - __in_opt LPCTSTR pObjectName, - __in CBaseFilter *pFilter, - __in CCritSec *pLock, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); - - ~CDynamicOutputPin(); - - // IUnknown Methods - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - // IPin Methods - STDMETHODIMP Disconnect(void); - - // IPinFlowControl Methods - STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent); - - // Set graph config info - void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent); - - #ifdef _DEBUG - virtual HRESULT Deliver(IMediaSample *pSample); - virtual HRESULT DeliverEndOfStream(void); - virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - #endif // DEBUG - - HRESULT DeliverBeginFlush(void); - HRESULT DeliverEndFlush(void); - - HRESULT Inactive(void); - HRESULT Active(void); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - virtual HRESULT StartUsingOutputPin(void); - virtual void StopUsingOutputPin(void); - virtual bool StreamingThreadUsingOutputPin(void); - - HRESULT ChangeOutputFormat - ( - const AM_MEDIA_TYPE *pmt, - REFERENCE_TIME tSegmentStart, - REFERENCE_TIME tSegmentStop, - double dSegmentRate - ); - HRESULT ChangeMediaType(const CMediaType *pmt); - HRESULT DynamicReconnect(const CMediaType *pmt); - -protected: - HRESULT SynchronousBlockOutputPin(void); - HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent); - HRESULT UnblockOutputPin(void); - - void BlockOutputPin(void); - void ResetBlockState(void); - - static HRESULT WaitEvent(HANDLE hEvent); - - enum BLOCK_STATE - { - NOT_BLOCKED, - PENDING, - BLOCKED - }; - - // This lock should be held when the following class members are - // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState, - // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers. - CCritSec m_BlockStateLock; - - // This event should be signaled when the output pin is - // not blocked. This is a manual reset event. For more - // information on events, see the documentation for - // CreateEvent() in the Windows SDK. - HANDLE m_hUnblockOutputPinEvent; - - // This event will be signaled when block operation succeedes or - // when the user cancels the block operation. The block operation - // can be canceled by calling IPinFlowControl2::Block( 0, NULL ) - // while the block operation is pending. - HANDLE m_hNotifyCallerPinBlockedEvent; - - // The state of the current block operation. - BLOCK_STATE m_BlockState; - - // The ID of the thread which last called IPinFlowControl::Block(). - // For more information on thread IDs, see the documentation for - // GetCurrentThreadID() in the Windows SDK. - DWORD m_dwBlockCallerThreadID; - - // The number of times StartUsingOutputPin() has been sucessfully - // called and a corresponding call to StopUsingOutputPin() has not - // been made. When this variable is greater than 0, the streaming - // thread is calling IPin::NewSegment(), IPin::EndOfStream(), - // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The - // streaming thread could also be calling: DynamicReconnect(), - // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot - // be blocked while the output pin is being used. - DWORD m_dwNumOutstandingOutputPinUsers; - - // This event should be set when the IMediaFilter::Stop() is called. - // This is a manual reset event. It is also set when the output pin - // delivers a flush to the connected input pin. - HANDLE m_hStopEvent; - IGraphConfig* m_pGraphConfig; - - // TRUE if the output pin's allocator's samples are read only. - // Otherwise FALSE. For more information, see the documentation - // for IMemInputPin::NotifyAllocator(). - BOOL m_bPinUsesReadOnlyAllocator; - -private: - HRESULT Initialize(void); - HRESULT ChangeMediaTypeHelper(const CMediaType *pmt); - - #ifdef _DEBUG - void AssertValid(void); - #endif // DEBUG -}; - -class CAutoUsingOutputPin -{ -public: - CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ); - ~CAutoUsingOutputPin(); - -private: - CDynamicOutputPin* m_pOutputPin; -}; - -inline CAutoUsingOutputPin::CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ) : - m_pOutputPin(NULL) -{ - // The caller should always pass in valid pointers. - ASSERT( NULL != pOutputPin ); - ASSERT( NULL != phr ); - - // Make sure the user initialized phr. - ASSERT( S_OK == *phr ); - - HRESULT hr = pOutputPin->StartUsingOutputPin(); - if( FAILED( hr ) ) - { - *phr = hr; - return; - } - - m_pOutputPin = pOutputPin; -} - -inline CAutoUsingOutputPin::~CAutoUsingOutputPin() -{ - if( NULL != m_pOutputPin ) - { - m_pOutputPin->StopUsingOutputPin(); - } -} - -#ifdef _DEBUG - -inline HRESULT CDynamicOutputPin::Deliver(IMediaSample *pSample) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - return CBaseOutputPin::Deliver(pSample); -} - -inline HRESULT CDynamicOutputPin::DeliverEndOfStream(void) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT( StreamingThreadUsingOutputPin() ); - - return CBaseOutputPin::DeliverEndOfStream(); -} - -inline HRESULT CDynamicOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - // The caller should call StartUsingOutputPin() before calling this - // method. - ASSERT(StreamingThreadUsingOutputPin()); - - return CBaseOutputPin::DeliverNewSegment(tStart, tStop, dRate); -} - -#endif // DEBUG - -//===================================================================== -//===================================================================== -// Memory allocators -// -// the shared memory transport between pins requires the input pin -// to provide a memory allocator that can provide sample objects. A -// sample object supports the IMediaSample interface. -// -// CBaseAllocator handles the management of free and busy samples. It -// allocates CMediaSample objects. CBaseAllocator is an abstract class: -// in particular it has no method of initializing the list of free -// samples. CMemAllocator is derived from CBaseAllocator and initializes -// the list of samples using memory from the standard IMalloc interface. -// -// If you want your buffers to live in some special area of memory, -// derive your allocator object from CBaseAllocator. If you derive your -// IMemInputPin interface object from CBaseMemInputPin, you will get -// CMemAllocator-based allocation etc for free and will just need to -// supply the Receive handling, and media type / format negotiation. -//===================================================================== -//===================================================================== - - -//===================================================================== -//===================================================================== -// Defines CMediaSample -// -// an object of this class supports IMediaSample and represents a buffer -// for media data with some associated properties. Releasing it returns -// it to a freelist managed by a CBaseAllocator derived object. -//===================================================================== -//===================================================================== - -class CMediaSample : public IMediaSample2 // The interface we support -{ - -protected: - - friend class CBaseAllocator; - - /* Values for dwFlags - these are used for backward compatiblity - only now - use AM_SAMPLE_xxx - */ - enum { Sample_SyncPoint = 0x01, /* Is this a sync point */ - Sample_Preroll = 0x02, /* Is this a preroll sample */ - Sample_Discontinuity = 0x04, /* Set if start of new segment */ - Sample_TypeChanged = 0x08, /* Has the type changed */ - Sample_TimeValid = 0x10, /* Set if time is valid */ - Sample_MediaTimeValid = 0x20, /* Is the media time valid */ - Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */ - Sample_StopValid = 0x100, /* Stop time valid */ - Sample_ValidFlags = 0x1FF - }; - - /* Properties, the media sample class can be a container for a format - change in which case we take a copy of a type through the SetMediaType - interface function and then return it when GetMediaType is called. As - we do no internal processing on it we leave it as a pointer */ - - DWORD m_dwFlags; /* Flags for this sample */ - /* Type specific flags are packed - into the top word - */ - DWORD m_dwTypeSpecificFlags; /* Media type specific flags */ - __field_ecount_opt(m_cbBuffer) LPBYTE m_pBuffer; /* Pointer to the complete buffer */ - LONG m_lActual; /* Length of data in this sample */ - LONG m_cbBuffer; /* Size of the buffer */ - CBaseAllocator *m_pAllocator; /* The allocator who owns us */ - CMediaSample *m_pNext; /* Chaining in free list */ - REFERENCE_TIME m_Start; /* Start sample time */ - REFERENCE_TIME m_End; /* End sample time */ - LONGLONG m_MediaStart; /* Real media start position */ - LONG m_MediaEnd; /* A difference to get the end */ - AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */ - DWORD m_dwStreamId; /* Stream id */ -public: - LONG m_cRef; /* Reference count */ - - -public: - - CMediaSample( - __in_opt LPCTSTR pName, - __in_opt CBaseAllocator *pAllocator, - __inout_opt HRESULT *phr, - __in_bcount_opt(length) LPBYTE pBuffer = NULL, - LONG length = 0); -#ifdef UNICODE - CMediaSample( - __in_opt LPCSTR pName, - __in_opt CBaseAllocator *pAllocator, - __inout_opt HRESULT *phr, - __in_bcount_opt(length) LPBYTE pBuffer = NULL, - LONG length = 0); -#endif - - virtual ~CMediaSample(); - - /* Note the media sample does not delegate to its owner */ - - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP_(ULONG) AddRef(); - STDMETHODIMP_(ULONG) Release(); - - // set the buffer pointer and length. Used by allocators that - // want variable sized pointers or pointers into already-read data. - // This is only available through a CMediaSample* not an IMediaSample* - // and so cannot be changed by clients. - HRESULT SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes); - - // Get me a read/write pointer to this buffer's memory. - STDMETHODIMP GetPointer(__deref_out BYTE ** ppBuffer); - - STDMETHODIMP_(LONG) GetSize(void); - - // get the stream time at which this sample should start and finish. - STDMETHODIMP GetTime( - __out REFERENCE_TIME * pTimeStart, // put time here - __out REFERENCE_TIME * pTimeEnd - ); - - // Set the stream time at which this sample should start and finish. - STDMETHODIMP SetTime( - __in_opt REFERENCE_TIME * pTimeStart, // put time here - __in_opt REFERENCE_TIME * pTimeEnd - ); - STDMETHODIMP IsSyncPoint(void); - STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint); - STDMETHODIMP IsPreroll(void); - STDMETHODIMP SetPreroll(BOOL bIsPreroll); - - STDMETHODIMP_(LONG) GetActualDataLength(void); - STDMETHODIMP SetActualDataLength(LONG lActual); - - // these allow for limited format changes in band - - STDMETHODIMP GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType); - STDMETHODIMP SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType); - - // returns S_OK if there is a discontinuity in the data (this same is - // not a continuation of the previous stream of data - // - there has been a seek). - STDMETHODIMP IsDiscontinuity(void); - // set the discontinuity property - TRUE if this sample is not a - // continuation, but a new sample after a seek. - STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity); - - // get the media times for this sample - STDMETHODIMP GetMediaTime( - __out LONGLONG * pTimeStart, - __out LONGLONG * pTimeEnd - ); - - // Set the media times for this sample - STDMETHODIMP SetMediaTime( - __in_opt LONGLONG * pTimeStart, - __in_opt LONGLONG * pTimeEnd - ); - - // Set and get properties (IMediaSample2) - STDMETHODIMP GetProperties( - DWORD cbProperties, - __out_bcount(cbProperties) BYTE * pbProperties - ); - - STDMETHODIMP SetProperties( - DWORD cbProperties, - __in_bcount(cbProperties) const BYTE * pbProperties - ); -}; - - -//===================================================================== -//===================================================================== -// Defines CBaseAllocator -// -// Abstract base class that manages a list of media samples -// -// This class provides support for getting buffers from the free list, -// including handling of commit and (asynchronous) decommit. -// -// Derive from this class and override the Alloc and Free functions to -// allocate your CMediaSample (or derived) objects and add them to the -// free list, preparing them as necessary. -//===================================================================== -//===================================================================== - -class AM_NOVTABLE CBaseAllocator : public CUnknown,// A non delegating IUnknown - public IMemAllocatorCallbackTemp, // The interface we support - public CCritSec // Provides object locking -{ - class CSampleList; - friend class CSampleList; - - /* Trick to get at protected member in CMediaSample */ - static CMediaSample * &NextSample(__in CMediaSample *pSample) - { - return pSample->m_pNext; - }; - - /* Mini list class for the free list */ - class CSampleList - { - public: - CSampleList() : m_List(NULL), m_nOnList(0) {}; -#ifdef _DEBUG - ~CSampleList() - { - ASSERT(m_nOnList == 0); - }; -#endif - CMediaSample *Head() const { return m_List; }; - CMediaSample *Next(__in CMediaSample *pSample) const { return CBaseAllocator::NextSample(pSample); }; - int GetCount() const { return m_nOnList; }; - void Add(__inout CMediaSample *pSample) - { - ASSERT(pSample != NULL); - CBaseAllocator::NextSample(pSample) = m_List; - m_List = pSample; - m_nOnList++; - }; - CMediaSample *RemoveHead() - { - CMediaSample *pSample = m_List; - if (pSample != NULL) { - m_List = CBaseAllocator::NextSample(m_List); - m_nOnList--; - } - return pSample; - }; - void Remove(__inout CMediaSample *pSample); - - public: - CMediaSample *m_List; - int m_nOnList; - }; -protected: - - CSampleList m_lFree; // Free list - - /* Note to overriders of CBaseAllocator. - - We use a lazy signalling mechanism for waiting for samples. - This means we don't call the OS if no waits occur. - - In order to implement this: - - 1. When a new sample is added to m_lFree call NotifySample() which - calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and - sets m_lWaiting to 0. - This must all be done holding the allocator's critical section. - - 2. When waiting for a sample call SetWaiting() which increments - m_lWaiting BEFORE leaving the allocator's critical section. - - 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE) - having left the allocator's critical section. The effect of - this is to remove 1 from the semaphore's count. You MUST call - this once having incremented m_lWaiting. - - The following are then true when the critical section is not held : - (let nWaiting = number about to wait or waiting) - - (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0) - (2) m_lWaiting + Semaphore count == nWaiting - - We would deadlock if - nWaiting != 0 && - m_lFree.GetCount() != 0 && - Semaphore count == 0 - - But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so - from (2) Semaphore count == nWaiting (which is non-0) so the - deadlock can't happen. - */ - - HANDLE m_hSem; // For signalling - long m_lWaiting; // Waiting for a free element - long m_lCount; // how many buffers we have agreed to provide - long m_lAllocated; // how many buffers are currently allocated - long m_lSize; // agreed size of each buffer - long m_lAlignment; // agreed alignment - long m_lPrefix; // agreed prefix (preceeds GetPointer() value) - BOOL m_bChanged; // Have the buffer requirements changed - - // if true, we are decommitted and can't allocate memory - BOOL m_bCommitted; - // if true, the decommit has happened, but we haven't called Free yet - // as there are still outstanding buffers - BOOL m_bDecommitInProgress; - - // Notification interface - IMemAllocatorNotifyCallbackTemp *m_pNotify; - - BOOL m_fEnableReleaseCallback; - - // called to decommit the memory when the last buffer is freed - // pure virtual - need to override this - virtual void Free(void) PURE; - - // override to allocate the memory when commit called - virtual HRESULT Alloc(void); - -public: - - CBaseAllocator( - __in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *, - BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); -#ifdef UNICODE - CBaseAllocator( - __in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *, - BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); -#endif - virtual ~CBaseAllocator(); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - STDMETHODIMP SetProperties( - __in ALLOCATOR_PROPERTIES* pRequest, - __out ALLOCATOR_PROPERTIES* pActual); - - // return the properties actually being used on this allocator - STDMETHODIMP GetProperties( - __out ALLOCATOR_PROPERTIES* pProps); - - // override Commit to allocate memory. We handle the GetBuffer - //state changes - STDMETHODIMP Commit(); - - // override this to handle the memory freeing. We handle any outstanding - // GetBuffer calls - STDMETHODIMP Decommit(); - - // get container for a sample. Blocking, synchronous call to get the - // next free buffer (as represented by an IMediaSample interface). - // on return, the time etc properties will be invalid, but the buffer - // pointer and size will be correct. The two time parameters are - // optional and either may be NULL, they may alternatively be set to - // the start and end times the sample will have attached to it - // bPrevFramesSkipped is not used (used only by the video renderer's - // allocator where it affects quality management in direct draw). - - STDMETHODIMP GetBuffer(__deref_out IMediaSample **ppBuffer, - __in_opt REFERENCE_TIME * pStartTime, - __in_opt REFERENCE_TIME * pEndTime, - DWORD dwFlags); - - // final release of a CMediaSample will call this - STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer); - // obsolete:: virtual void PutOnFreeList(CMediaSample * pSample); - - STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); - - STDMETHODIMP GetFreeCount(__out LONG *plBuffersFree); - - // Notify that a sample is available - void NotifySample(); - - // Notify that we're waiting for a sample - void SetWaiting() { m_lWaiting++; }; -}; - - -//===================================================================== -//===================================================================== -// Defines CMemAllocator -// -// this is an allocator based on CBaseAllocator that allocates sample -// buffers in main memory (from 'new'). You must call SetProperties -// before calling Commit. -// -// we don't free the memory when going into Decommit state. The simplest -// way to implement this without complicating CBaseAllocator is to -// have a Free() function, called to go into decommit state, that does -// nothing and a ReallyFree function called from our destructor that -// actually frees the memory. -//===================================================================== -//===================================================================== - -// Make me one from quartz.dll -STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator); - -class CMemAllocator : public CBaseAllocator -{ - -protected: - - LPBYTE m_pBuffer; // combined memory for all buffers - - // override to free the memory when decommit completes - // - we actually do nothing, and save the memory until deletion. - void Free(void); - - // called from the destructor (and from Alloc if changing size/count) to - // actually free up the memory - void ReallyFree(void); - - // overriden to allocate the memory when commit called - HRESULT Alloc(void); - -public: - /* This goes in the factory template table to create new instances */ - static CUnknown *CreateInstance(__inout_opt LPUNKNOWN, __inout HRESULT *); - - STDMETHODIMP SetProperties( - __in ALLOCATOR_PROPERTIES* pRequest, - __out ALLOCATOR_PROPERTIES* pActual); - - CMemAllocator(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *); -#ifdef UNICODE - CMemAllocator(__in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *); -#endif - ~CMemAllocator(); -}; - -// helper used by IAMovieSetup implementation -STDAPI -AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper * pIFM - , BOOL bRegister ); - - -/////////////////////////////////////////////////////////////////////////// -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -// ------------------------------------------------------------------------ -/////////////////////////////////////////////////////////////////////////// - -#endif /* __FILTER__ */ - - - +//------------------------------------------------------------------------------ +// File: AMFilter.h +// +// Desc: DirectShow base classes - efines class hierarchy for streams +// architecture. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __FILTER__ +#define __FILTER__ + +/* The following classes are declared in this header: */ + +class CBaseMediaFilter; // IMediaFilter support +class CBaseFilter; // IBaseFilter,IMediaFilter support +class CBasePin; // Abstract base class for IPin interface +class CEnumPins; // Enumerate input and output pins +class CEnumMediaTypes; // Enumerate the pin's preferred formats +class CBaseOutputPin; // Adds data provider member functions +class CBaseInputPin; // Implements IMemInputPin interface +class CMediaSample; // Basic transport unit for IMemInputPin +class CBaseAllocator; // General list guff for most allocators +class CMemAllocator; // Implements memory buffer allocation + + +//===================================================================== +//===================================================================== +// +// QueryFilterInfo and QueryPinInfo AddRef the interface pointers +// they return. You can use the macro below to release the interface. +// +//===================================================================== +//===================================================================== + +#define QueryFilterInfoReleaseGraph(fi) if ((fi).pGraph) (fi).pGraph->Release(); + +#define QueryPinInfoReleaseFilter(pi) if ((pi).pFilter) (pi).pFilter->Release(); + +//===================================================================== +//===================================================================== +// Defines CBaseMediaFilter +// +// Abstract base class implementing IMediaFilter. +// +// Typically you will derive your filter from CBaseFilter rather than +// this, unless you are implementing an object such as a plug-in +// distributor that needs to support IMediaFilter but not IBaseFilter. +// +// Note that IMediaFilter is derived from IPersist to allow query of +// class id. +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseMediaFilter : public CUnknown, + public IMediaFilter +{ + +protected: + + FILTER_STATE m_State; // current state: running, paused + IReferenceClock *m_pClock; // this filter's reference clock + // note: all filters in a filter graph use the same clock + + // offset from stream time to reference time + CRefTime m_tStart; + + CLSID m_clsid; // This filters clsid + // used for serialization + CCritSec *m_pLock; // Object we use for locking + +public: + + CBaseMediaFilter( + __in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __in CCritSec *pLock, + REFCLSID clsid); + + virtual ~CBaseMediaFilter(); + + DECLARE_IUNKNOWN + + // override this to say what interfaces we support where + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + + // + // --- IPersist method --- + // + + STDMETHODIMP GetClassID(__out CLSID *pClsID); + + // --- IMediaFilter methods --- + + STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); + + STDMETHODIMP SetSyncSource(__inout_opt IReferenceClock *pClock); + + STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock); + + // default implementation of Stop and Pause just record the + // state. Override to activate or de-activate your filter. + // Note that Run when called from Stopped state will call Pause + // to ensure activation, so if you are a source or transform + // you will probably not need to override Run. + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + + + // the start parameter is the difference to be added to the + // sample's stream time to get the reference time for + // its presentation + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // --- helper methods --- + + // return the current stream time - ie find out what + // stream time should be appearing now + virtual HRESULT StreamTime(CRefTime& rtStream); + + // Is the filter currently active? (running or paused) + BOOL IsActive() { + CAutoLock cObjectLock(m_pLock); + return ((m_State == State_Paused) || (m_State == State_Running)); + }; +}; + +//===================================================================== +//===================================================================== +// Defines CBaseFilter +// +// An abstract class providing basic IBaseFilter support for pin +// enumeration and filter information reading. +// +// We cannot derive from CBaseMediaFilter since methods in IMediaFilter +// are also in IBaseFilter and would be ambiguous. Since much of the code +// assumes that they derive from a class that has m_State and other state +// directly available, we duplicate code from CBaseMediaFilter rather than +// having a member variable. +// +// Derive your filter from this, or from a derived object such as +// CTransformFilter. +//===================================================================== +//===================================================================== + + +class AM_NOVTABLE CBaseFilter : public CUnknown, // Handles an IUnknown + public IBaseFilter, // The Filter Interface + public IAMovieSetup // For un/registration +{ + +friend class CBasePin; + +protected: + FILTER_STATE m_State; // current state: running, paused + IReferenceClock *m_pClock; // this graph's ref clock + CRefTime m_tStart; // offset from stream time to reference time + CLSID m_clsid; // This filters clsid + // used for serialization + CCritSec *m_pLock; // Object we use for locking + + WCHAR *m_pName; // Full filter name + IFilterGraph *m_pGraph; // Graph we belong to + IMediaEventSink *m_pSink; // Called with notify events + LONG m_PinVersion; // Current pin version + +public: + + CBaseFilter( + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // IUnknown of delegating object + __in CCritSec *pLock, // Object who maintains lock + REFCLSID clsid); // The clsid to be used to serialize this filter + + CBaseFilter( + __in_opt LPCTSTR pName, // Object description + __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object + __in CCritSec *pLock, // Object who maintains lock + REFCLSID clsid, // The clsid to be used to serialize this filter + __inout HRESULT *phr); // General OLE return code +#ifdef UNICODE + CBaseFilter( + __in_opt LPCSTR pName, // Object description + __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object + __in CCritSec *pLock, // Object who maintains lock + REFCLSID clsid); // The clsid to be used to serialize this filter + + CBaseFilter( + __in_opt LPCSTR pName, // Object description + __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object + __in CCritSec *pLock, // Object who maintains lock + REFCLSID clsid, // The clsid to be used to serialize this filter + __inout HRESULT *phr); // General OLE return code +#endif + ~CBaseFilter(); + + DECLARE_IUNKNOWN + + // override this to say what interfaces we support where + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); +#ifdef _DEBUG + STDMETHODIMP_(ULONG) NonDelegatingRelease(); +#endif + + // + // --- IPersist method --- + // + + STDMETHODIMP GetClassID(__out CLSID *pClsID); + + // --- IMediaFilter methods --- + + STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); + + STDMETHODIMP SetSyncSource(__in_opt IReferenceClock *pClock); + + STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock); + + + // override Stop and Pause so we can activate the pins. + // Note that Run will call Pause first if activation needed. + // Override these if you want to activate your filter rather than + // your pins. + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + + // the start parameter is the difference to be added to the + // sample's stream time to get the reference time for + // its presentation + STDMETHODIMP Run(REFERENCE_TIME tStart); + + // --- helper methods --- + + // return the current stream time - ie find out what + // stream time should be appearing now + virtual HRESULT StreamTime(CRefTime& rtStream); + + // Is the filter currently active? + BOOL IsActive() { + CAutoLock cObjectLock(m_pLock); + return ((m_State == State_Paused) || (m_State == State_Running)); + }; + + // Is this filter stopped (without locking) + BOOL IsStopped() { + return (m_State == State_Stopped); + }; + + // + // --- IBaseFilter methods --- + // + + // pin enumerator + STDMETHODIMP EnumPins( + __deref_out IEnumPins ** ppEnum); + + + // default behaviour of FindPin assumes pin ids are their names + STDMETHODIMP FindPin( + LPCWSTR Id, + __deref_out IPin ** ppPin + ); + + STDMETHODIMP QueryFilterInfo( + __out FILTER_INFO * pInfo); + + STDMETHODIMP JoinFilterGraph( + __inout_opt IFilterGraph * pGraph, + __in_opt LPCWSTR pName); + + // return a Vendor information string. Optional - may return E_NOTIMPL. + // memory returned should be freed using CoTaskMemFree + // default implementation returns E_NOTIMPL + STDMETHODIMP QueryVendorInfo( + __deref_out LPWSTR* pVendorInfo + ); + + // --- helper methods --- + + // send an event notification to the filter graph if we know about it. + // returns S_OK if delivered, S_FALSE if the filter graph does not sink + // events, or an error otherwise. + HRESULT NotifyEvent( + long EventCode, + LONG_PTR EventParam1, + LONG_PTR EventParam2); + + // return the filter graph we belong to + __out_opt IFilterGraph *GetFilterGraph() { + return m_pGraph; + } + + // Request reconnect + // pPin is the pin to reconnect + // pmt is the type to reconnect with - can be NULL + // Calls ReconnectEx on the filter graph + HRESULT ReconnectPin(IPin *pPin, __in_opt AM_MEDIA_TYPE const *pmt); + + // find out the current pin version (used by enumerators) + virtual LONG GetPinVersion(); + void IncrementPinVersion(); + + // you need to supply these to access the pins from the enumerator + // and for default Stop and Pause/Run activation. + virtual int GetPinCount() PURE; + virtual CBasePin *GetPin(int n) PURE; + + // --- IAMovieSetup methods --- + + STDMETHODIMP Register(); // ask filter to register itself + STDMETHODIMP Unregister(); // and unregister itself + + // --- setup helper methods --- + // (override to return filters setup data) + + virtual __out_opt LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; } + +}; + + +//===================================================================== +//===================================================================== +// Defines CBasePin +// +// Abstract class that supports the basics of IPin +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl +{ + +protected: + + WCHAR * m_pName; // This pin's name + IPin *m_Connected; // Pin we have connected to + PIN_DIRECTION m_dir; // Direction of this pin + CCritSec *m_pLock; // Object we use for locking + bool m_bRunTimeError; // Run time error generated + bool m_bCanReconnectWhenActive; // OK to reconnect when active + bool m_bTryMyTypesFirst; // When connecting enumerate + // this pin's types first + CBaseFilter *m_pFilter; // Filter we were created by + IQualityControl *m_pQSink; // Target for Quality messages + LONG m_TypeVersion; // Holds current type version + CMediaType m_mt; // Media type of connection + + CRefTime m_tStart; // time from NewSegment call + CRefTime m_tStop; // time from NewSegment + double m_dRate; // rate from NewSegment + +#ifdef _DEBUG + LONG m_cRef; // Ref count tracing +#endif + + // displays pin connection information + +#ifdef _DEBUG + void DisplayPinInfo(IPin *pReceivePin); + void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt); +#else + void DisplayPinInfo(IPin *pReceivePin) {}; + void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {}; +#endif + + // used to agree a media type for a pin connection + + // given a specific media type, attempt a connection (includes + // checking that the type is acceptable to this pin) + HRESULT + AttemptConnection( + IPin* pReceivePin, // connect to this pin + const CMediaType* pmt // using this type + ); + + // try all the media types in this enumerator - for each that + // we accept, try to connect using ReceiveConnection. + HRESULT TryMediaTypes( + IPin *pReceivePin, // connect to this pin + __in_opt const CMediaType *pmt, // proposed type from Connect + IEnumMediaTypes *pEnum); // try this enumerator + + // establish a connection with a suitable mediatype. Needs to + // propose a media type if the pmt pointer is null or partially + // specified - use TryMediaTypes on both our and then the other pin's + // enumerator until we find one that works. + HRESULT AgreeMediaType( + IPin *pReceivePin, // connect to this pin + const CMediaType *pmt); // proposed type from Connect + +public: + + CBasePin( + __in_opt LPCTSTR pObjectName, // Object description + __in CBaseFilter *pFilter, // Owning filter who knows about pins + __in CCritSec *pLock, // Object who implements the lock + __inout HRESULT *phr, // General OLE return code + __in_opt LPCWSTR pName, // Pin name for us + PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT +#ifdef UNICODE + CBasePin( + __in_opt LPCSTR pObjectName, // Object description + __in CBaseFilter *pFilter, // Owning filter who knows about pins + __in CCritSec *pLock, // Object who implements the lock + __inout HRESULT *phr, // General OLE return code + __in_opt LPCWSTR pName, // Pin name for us + PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT +#endif + virtual ~CBasePin(); + + DECLARE_IUNKNOWN + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + + // --- IPin methods --- + + // take lead role in establishing a connection. Media type pointer + // may be null, or may point to partially-specified mediatype + // (subtype or format type may be GUID_NULL). + STDMETHODIMP Connect( + IPin * pReceivePin, + __in_opt const AM_MEDIA_TYPE *pmt // optional media type + ); + + // (passive) accept a connection from another pin + STDMETHODIMP ReceiveConnection( + IPin * pConnector, // this is the initiating connecting pin + const AM_MEDIA_TYPE *pmt // this is the media type we will exchange + ); + + STDMETHODIMP Disconnect(); + + STDMETHODIMP ConnectedTo(__deref_out IPin **pPin); + + STDMETHODIMP ConnectionMediaType(__out AM_MEDIA_TYPE *pmt); + + STDMETHODIMP QueryPinInfo( + __out PIN_INFO * pInfo + ); + + STDMETHODIMP QueryDirection( + __out PIN_DIRECTION * pPinDir + ); + + STDMETHODIMP QueryId( + __deref_out LPWSTR * Id + ); + + // does the pin support this media type + STDMETHODIMP QueryAccept( + const AM_MEDIA_TYPE *pmt + ); + + // return an enumerator for this pins preferred media types + STDMETHODIMP EnumMediaTypes( + __deref_out IEnumMediaTypes **ppEnum + ); + + // return an array of IPin* - the pins that this pin internally connects to + // All pins put in the array must be AddReffed (but no others) + // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE + // Default: return E_NOTIMPL + // The filter graph will interpret NOT_IMPL as any input pin connects to + // all visible output pins and vice versa. + // apPin can be NULL if nPin==0 (not otherwise). + STDMETHODIMP QueryInternalConnections( + __out_ecount_part(*nPin,*nPin) IPin* *apPin, // array of IPin* + __inout ULONG *nPin // on input, the number of slots + // on output the number of pins + ) { return E_NOTIMPL; } + + // Called when no more data will be sent + STDMETHODIMP EndOfStream(void); + + // Begin/EndFlush still PURE + + // NewSegment notifies of the start/stop/rate applying to the data + // about to be received. Default implementation records data and + // returns S_OK. + // Override this to pass downstream. + STDMETHODIMP NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + //================================================================================ + // IQualityControl methods + //================================================================================ + + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + STDMETHODIMP SetSink(IQualityControl * piqc); + + // --- helper methods --- + + // Returns true if the pin is connected. false otherwise. + BOOL IsConnected(void) {return (m_Connected != NULL); }; + // Return the pin this is connected to (if any) + IPin * GetConnected() { return m_Connected; }; + + // Check if our filter is currently stopped + BOOL IsStopped() { + return (m_pFilter->m_State == State_Stopped); + }; + + // find out the current type version (used by enumerators) + virtual LONG GetMediaTypeVersion(); + void IncrementTypeVersion(); + + // switch the pin to active (paused or running) mode + // not an error to call this if already active + virtual HRESULT Active(void); + + // switch the pin to inactive state - may already be inactive + virtual HRESULT Inactive(void); + + // Notify of Run() from filter + virtual HRESULT Run(REFERENCE_TIME tStart); + + // check if the pin can support this specific proposed type and format + virtual HRESULT CheckMediaType(const CMediaType *) PURE; + + // set the connection to use this format (previously agreed) + virtual HRESULT SetMediaType(const CMediaType *); + + // check that the connection is ok before verifying it + // can be overridden eg to check what interfaces will be supported. + virtual HRESULT CheckConnect(IPin *); + + // Set and release resources required for a connection + virtual HRESULT BreakConnect(); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // returns the preferred formats for a pin + virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); + + // access to NewSegment values + REFERENCE_TIME CurrentStopTime() { + return m_tStop; + } + REFERENCE_TIME CurrentStartTime() { + return m_tStart; + } + double CurrentRate() { + return m_dRate; + } + + // Access name + LPWSTR Name() { return m_pName; }; + + // Can reconnectwhen active? + void SetReconnectWhenActive(bool bCanReconnect) + { + m_bCanReconnectWhenActive = bCanReconnect; + } + + bool CanReconnectWhenActive() + { + return m_bCanReconnectWhenActive; + } + +protected: + STDMETHODIMP DisconnectInternal(); +}; + + +//===================================================================== +//===================================================================== +// Defines CEnumPins +// +// Pin enumerator class that works by calling CBaseFilter. This interface +// is provided by CBaseFilter::EnumPins and calls GetPinCount() and +// GetPin() to enumerate existing pins. Needs to be a separate object so +// that it can be cloned (creating an existing object at the same +// position in the enumeration) +// +//===================================================================== +//===================================================================== + +class CEnumPins : public IEnumPins // The interface we support +{ + int m_Position; // Current ordinal position + int m_PinCount; // Number of pins available + CBaseFilter *m_pFilter; // The filter who owns us + LONG m_Version; // Pin version information + LONG m_cRef; + + typedef CGenericList CPinList; + + CPinList m_PinCache; // These pointers have not been AddRef'ed and + // so they should not be dereferenced. They are + // merely kept to ID which pins have been enumerated. + +#ifdef _DEBUG + DWORD m_dwCookie; +#endif + + /* If while we are retrieving a pin for example from the filter an error + occurs we assume that our internal state is stale with respect to the + filter (someone may have deleted all the pins). We can check before + starting whether or not the operation is likely to fail by asking the + filter what it's current version number is. If the filter has not + overriden the GetPinVersion method then this will always match */ + + BOOL AreWeOutOfSync() { + return (m_pFilter->GetPinVersion() == m_Version ? FALSE : TRUE); + }; + + /* This method performs the same operations as Reset, except is does not clear + the cache of pins already enumerated. */ + + STDMETHODIMP Refresh(); + +public: + + CEnumPins( + __in CBaseFilter *pFilter, + __in_opt CEnumPins *pEnumPins); + + virtual ~CEnumPins(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IEnumPins + STDMETHODIMP Next( + ULONG cPins, // place this many pins... + __out_ecount(cPins) IPin ** ppPins, // ...in this array of IPin* + __out_opt ULONG * pcFetched // actual count passed returned here + ); + + STDMETHODIMP Skip(ULONG cPins); + STDMETHODIMP Reset(); + STDMETHODIMP Clone(__deref_out IEnumPins **ppEnum); + + +}; + + +//===================================================================== +//===================================================================== +// Defines CEnumMediaTypes +// +// Enumerates the preferred formats for input and output pins +//===================================================================== +//===================================================================== + +class CEnumMediaTypes : public IEnumMediaTypes // The interface we support +{ + int m_Position; // Current ordinal position + CBasePin *m_pPin; // The pin who owns us + LONG m_Version; // Media type version value + LONG m_cRef; +#ifdef _DEBUG + DWORD m_dwCookie; +#endif + + /* The media types a filter supports can be quite dynamic so we add to + the general IEnumXXXX interface the ability to be signaled when they + change via an event handle the connected filter supplies. Until the + Reset method is called after the state changes all further calls to + the enumerator (except Reset) will return E_UNEXPECTED error code */ + + BOOL AreWeOutOfSync() { + return (m_pPin->GetMediaTypeVersion() == m_Version ? FALSE : TRUE); + }; + +public: + + CEnumMediaTypes( + __in CBasePin *pPin, + __in_opt CEnumMediaTypes *pEnumMediaTypes); + + virtual ~CEnumMediaTypes(); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IEnumMediaTypes + STDMETHODIMP Next( + ULONG cMediaTypes, // place this many pins... + __out_ecount(cMediaTypes) AM_MEDIA_TYPE ** ppMediaTypes, // ...in this array + __out_opt ULONG * pcFetched // actual count passed + ); + + STDMETHODIMP Skip(ULONG cMediaTypes); + STDMETHODIMP Reset(); + STDMETHODIMP Clone(__deref_out IEnumMediaTypes **ppEnum); +}; + + + + +//===================================================================== +//===================================================================== +// Defines CBaseOutputPin +// +// class derived from CBasePin that can pass buffers to a connected pin +// that supports IMemInputPin. Supports IPin. +// +// Derive your output pin from this. +// +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseOutputPin : public CBasePin +{ + +protected: + + IMemAllocator *m_pAllocator; + IMemInputPin *m_pInputPin; // interface on the downstreaminput pin + // set up in CheckConnect when we connect. + +public: + + CBaseOutputPin( + __in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CBaseOutputPin( + __in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#endif + // override CompleteConnect() so we can negotiate an allocator + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // negotiate the allocator and its buffer size/count and other properties + // Calls DecideBufferSize to set properties + virtual HRESULT DecideAllocator(IMemInputPin * pPin, __deref_out IMemAllocator ** pAlloc); + + // override this to set the buffer size and count. Return an error + // if the size/count is not to your liking. + // The allocator properties passed in are those requested by the + // input pin - use eg the alignment and prefix members if you have + // no preference on these. + virtual HRESULT DecideBufferSize( + IMemAllocator * pAlloc, + __inout ALLOCATOR_PROPERTIES * ppropInputRequest + ) PURE; + + // returns an empty sample buffer from the allocator + virtual HRESULT GetDeliveryBuffer(__deref_out IMediaSample ** ppSample, + __in_opt REFERENCE_TIME * pStartTime, + __in_opt REFERENCE_TIME * pEndTime, + DWORD dwFlags); + + // deliver a filled-in sample to the connected input pin + // note - you need to release it after calling this. The receiving + // pin will addref the sample if it needs to hold it beyond the + // call. + virtual HRESULT Deliver(IMediaSample *); + + // override this to control the connection + virtual HRESULT InitAllocator(__deref_out IMemAllocator **ppAlloc); + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + + // override to call Commit and Decommit + HRESULT Active(void); + HRESULT Inactive(void); + + // we have a default handling of EndOfStream which is to return + // an error, since this should be called on input pins only + STDMETHODIMP EndOfStream(void); + + // called from elsewhere in our filter to pass EOS downstream to + // our connected input pin + virtual HRESULT DeliverEndOfStream(void); + + // same for Begin/EndFlush - we handle Begin/EndFlush since it + // is an error on an output pin, and we have Deliver methods to + // call the methods on the connected pin + STDMETHODIMP BeginFlush(void); + STDMETHODIMP EndFlush(void); + virtual HRESULT DeliverBeginFlush(void); + virtual HRESULT DeliverEndFlush(void); + + // deliver NewSegment to connected pin - you will need to + // override this if you queue any data in your output pin. + virtual HRESULT DeliverNewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + //================================================================================ + // IQualityControl methods + //================================================================================ + + // All inherited from CBasePin and not overridden here. + // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + // STDMETHODIMP SetSink(IQualityControl * piqc); +}; + + +//===================================================================== +//===================================================================== +// Defines CBaseInputPin +// +// derive your standard input pin from this. +// you need to supply GetMediaType and CheckConnect etc (see CBasePin), +// and you need to supply Receive to do something more useful. +// +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseInputPin : public CBasePin, + public IMemInputPin +{ + +protected: + + IMemAllocator *m_pAllocator; // Default memory allocator + + // allocator is read-only, so received samples + // cannot be modified (probably only relevant to in-place + // transforms + BYTE m_bReadOnly; + + // in flushing state (between BeginFlush and EndFlush) + // if TRUE, all Receives are returned with S_FALSE + BYTE m_bFlushing; + + // Sample properties - initalized in Receive + AM_SAMPLE2_PROPERTIES m_SampleProps; + +public: + + CBaseInputPin( + __in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CBaseInputPin( + __in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#endif + virtual ~CBaseInputPin(); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + // return the allocator interface that this input pin + // would like the output pin to use + STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator); + + // tell the input pin which allocator the output pin is actually + // going to use. + STDMETHODIMP NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly); + + // do something with this media sample + STDMETHODIMP Receive(IMediaSample *pSample); + + // do something with these media samples + STDMETHODIMP ReceiveMultiple ( + __in_ecount(nSamples) IMediaSample **pSamples, + long nSamples, + __out long *nSamplesProcessed); + + // See if Receive() blocks + STDMETHODIMP ReceiveCanBlock(); + + // Default handling for BeginFlush - call at the beginning + // of your implementation (makes sure that all Receive calls + // fail). After calling this, you need to free any queued data + // and then call downstream. + STDMETHODIMP BeginFlush(void); + + // default handling for EndFlush - call at end of your implementation + // - before calling this, ensure that there is no queued data and no thread + // pushing any more without a further receive, then call downstream, + // then call this method to clear the m_bFlushing flag and re-enable + // receives + STDMETHODIMP EndFlush(void); + + // this method is optional (can return E_NOTIMPL). + // default implementation returns E_NOTIMPL. Override if you have + // specific alignment or prefix needs, but could use an upstream + // allocator + STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps); + + // Release the pin's allocator. + HRESULT BreakConnect(); + + // helper method to check the read-only flag + BOOL IsReadOnly() { + return m_bReadOnly; + }; + + // helper method to see if we are flushing + BOOL IsFlushing() { + return m_bFlushing; + }; + + // Override this for checking whether it's OK to process samples + // Also call this from EndOfStream. + virtual HRESULT CheckStreaming(); + + // Pass a Quality notification on to the appropriate sink + HRESULT PassNotify(Quality& q); + + + //================================================================================ + // IQualityControl methods (from CBasePin) + //================================================================================ + + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + // no need to override: + // STDMETHODIMP SetSink(IQualityControl * piqc); + + + // switch the pin to inactive state - may already be inactive + virtual HRESULT Inactive(void); + + // Return sample properties pointer + AM_SAMPLE2_PROPERTIES * SampleProps() { + ASSERT(m_SampleProps.cbData != 0); + return &m_SampleProps; + } + +}; + +/////////////////////////////////////////////////////////////////////////// +// CDynamicOutputPin +// + +class CDynamicOutputPin : public CBaseOutputPin, + public IPinFlowControl +{ +public: +#ifdef UNICODE + CDynamicOutputPin( + __in_opt LPCSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); +#endif + + CDynamicOutputPin( + __in_opt LPCTSTR pObjectName, + __in CBaseFilter *pFilter, + __in CCritSec *pLock, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); + + ~CDynamicOutputPin(); + + // IUnknown Methods + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + // IPin Methods + STDMETHODIMP Disconnect(void); + + // IPinFlowControl Methods + STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent); + + // Set graph config info + void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent); + + #ifdef _DEBUG + virtual HRESULT Deliver(IMediaSample *pSample); + virtual HRESULT DeliverEndOfStream(void); + virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + #endif // DEBUG + + HRESULT DeliverBeginFlush(void); + HRESULT DeliverEndFlush(void); + + HRESULT Inactive(void); + HRESULT Active(void); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + virtual HRESULT StartUsingOutputPin(void); + virtual void StopUsingOutputPin(void); + virtual bool StreamingThreadUsingOutputPin(void); + + HRESULT ChangeOutputFormat + ( + const AM_MEDIA_TYPE *pmt, + REFERENCE_TIME tSegmentStart, + REFERENCE_TIME tSegmentStop, + double dSegmentRate + ); + HRESULT ChangeMediaType(const CMediaType *pmt); + HRESULT DynamicReconnect(const CMediaType *pmt); + +protected: + HRESULT SynchronousBlockOutputPin(void); + HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent); + HRESULT UnblockOutputPin(void); + + void BlockOutputPin(void); + void ResetBlockState(void); + + static HRESULT WaitEvent(HANDLE hEvent); + + enum BLOCK_STATE + { + NOT_BLOCKED, + PENDING, + BLOCKED + }; + + // This lock should be held when the following class members are + // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState, + // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers. + CCritSec m_BlockStateLock; + + // This event should be signaled when the output pin is + // not blocked. This is a manual reset event. For more + // information on events, see the documentation for + // CreateEvent() in the Windows SDK. + HANDLE m_hUnblockOutputPinEvent; + + // This event will be signaled when block operation succeedes or + // when the user cancels the block operation. The block operation + // can be canceled by calling IPinFlowControl2::Block( 0, NULL ) + // while the block operation is pending. + HANDLE m_hNotifyCallerPinBlockedEvent; + + // The state of the current block operation. + BLOCK_STATE m_BlockState; + + // The ID of the thread which last called IPinFlowControl::Block(). + // For more information on thread IDs, see the documentation for + // GetCurrentThreadID() in the Windows SDK. + DWORD m_dwBlockCallerThreadID; + + // The number of times StartUsingOutputPin() has been sucessfully + // called and a corresponding call to StopUsingOutputPin() has not + // been made. When this variable is greater than 0, the streaming + // thread is calling IPin::NewSegment(), IPin::EndOfStream(), + // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The + // streaming thread could also be calling: DynamicReconnect(), + // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot + // be blocked while the output pin is being used. + DWORD m_dwNumOutstandingOutputPinUsers; + + // This event should be set when the IMediaFilter::Stop() is called. + // This is a manual reset event. It is also set when the output pin + // delivers a flush to the connected input pin. + HANDLE m_hStopEvent; + IGraphConfig* m_pGraphConfig; + + // TRUE if the output pin's allocator's samples are read only. + // Otherwise FALSE. For more information, see the documentation + // for IMemInputPin::NotifyAllocator(). + BOOL m_bPinUsesReadOnlyAllocator; + +private: + HRESULT Initialize(void); + HRESULT ChangeMediaTypeHelper(const CMediaType *pmt); + + #ifdef _DEBUG + void AssertValid(void); + #endif // DEBUG +}; + +class CAutoUsingOutputPin +{ +public: + CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ); + ~CAutoUsingOutputPin(); + +private: + CDynamicOutputPin* m_pOutputPin; +}; + +inline CAutoUsingOutputPin::CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ) : + m_pOutputPin(NULL) +{ + // The caller should always pass in valid pointers. + ASSERT( NULL != pOutputPin ); + ASSERT( NULL != phr ); + + // Make sure the user initialized phr. + ASSERT( S_OK == *phr ); + + HRESULT hr = pOutputPin->StartUsingOutputPin(); + if( FAILED( hr ) ) + { + *phr = hr; + return; + } + + m_pOutputPin = pOutputPin; +} + +inline CAutoUsingOutputPin::~CAutoUsingOutputPin() +{ + if( NULL != m_pOutputPin ) + { + m_pOutputPin->StopUsingOutputPin(); + } +} + +#ifdef _DEBUG + +inline HRESULT CDynamicOutputPin::Deliver(IMediaSample *pSample) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + return CBaseOutputPin::Deliver(pSample); +} + +inline HRESULT CDynamicOutputPin::DeliverEndOfStream(void) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT( StreamingThreadUsingOutputPin() ); + + return CBaseOutputPin::DeliverEndOfStream(); +} + +inline HRESULT CDynamicOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + // The caller should call StartUsingOutputPin() before calling this + // method. + ASSERT(StreamingThreadUsingOutputPin()); + + return CBaseOutputPin::DeliverNewSegment(tStart, tStop, dRate); +} + +#endif // DEBUG + +//===================================================================== +//===================================================================== +// Memory allocators +// +// the shared memory transport between pins requires the input pin +// to provide a memory allocator that can provide sample objects. A +// sample object supports the IMediaSample interface. +// +// CBaseAllocator handles the management of free and busy samples. It +// allocates CMediaSample objects. CBaseAllocator is an abstract class: +// in particular it has no method of initializing the list of free +// samples. CMemAllocator is derived from CBaseAllocator and initializes +// the list of samples using memory from the standard IMalloc interface. +// +// If you want your buffers to live in some special area of memory, +// derive your allocator object from CBaseAllocator. If you derive your +// IMemInputPin interface object from CBaseMemInputPin, you will get +// CMemAllocator-based allocation etc for free and will just need to +// supply the Receive handling, and media type / format negotiation. +//===================================================================== +//===================================================================== + + +//===================================================================== +//===================================================================== +// Defines CMediaSample +// +// an object of this class supports IMediaSample and represents a buffer +// for media data with some associated properties. Releasing it returns +// it to a freelist managed by a CBaseAllocator derived object. +//===================================================================== +//===================================================================== + +class CMediaSample : public IMediaSample2 // The interface we support +{ + +protected: + + friend class CBaseAllocator; + + /* Values for dwFlags - these are used for backward compatiblity + only now - use AM_SAMPLE_xxx + */ + enum { Sample_SyncPoint = 0x01, /* Is this a sync point */ + Sample_Preroll = 0x02, /* Is this a preroll sample */ + Sample_Discontinuity = 0x04, /* Set if start of new segment */ + Sample_TypeChanged = 0x08, /* Has the type changed */ + Sample_TimeValid = 0x10, /* Set if time is valid */ + Sample_MediaTimeValid = 0x20, /* Is the media time valid */ + Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */ + Sample_StopValid = 0x100, /* Stop time valid */ + Sample_ValidFlags = 0x1FF + }; + + /* Properties, the media sample class can be a container for a format + change in which case we take a copy of a type through the SetMediaType + interface function and then return it when GetMediaType is called. As + we do no internal processing on it we leave it as a pointer */ + + DWORD m_dwFlags; /* Flags for this sample */ + /* Type specific flags are packed + into the top word + */ + DWORD m_dwTypeSpecificFlags; /* Media type specific flags */ + __field_ecount_opt(m_cbBuffer) LPBYTE m_pBuffer; /* Pointer to the complete buffer */ + LONG m_lActual; /* Length of data in this sample */ + LONG m_cbBuffer; /* Size of the buffer */ + CBaseAllocator *m_pAllocator; /* The allocator who owns us */ + CMediaSample *m_pNext; /* Chaining in free list */ + REFERENCE_TIME m_Start; /* Start sample time */ + REFERENCE_TIME m_End; /* End sample time */ + LONGLONG m_MediaStart; /* Real media start position */ + LONG m_MediaEnd; /* A difference to get the end */ + AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */ + DWORD m_dwStreamId; /* Stream id */ +public: + LONG m_cRef; /* Reference count */ + + +public: + + CMediaSample( + __in_opt LPCTSTR pName, + __in_opt CBaseAllocator *pAllocator, + __inout_opt HRESULT *phr, + __in_bcount_opt(length) LPBYTE pBuffer = NULL, + LONG length = 0); +#ifdef UNICODE + CMediaSample( + __in_opt LPCSTR pName, + __in_opt CBaseAllocator *pAllocator, + __inout_opt HRESULT *phr, + __in_bcount_opt(length) LPBYTE pBuffer = NULL, + LONG length = 0); +#endif + + virtual ~CMediaSample(); + + /* Note the media sample does not delegate to its owner */ + + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // set the buffer pointer and length. Used by allocators that + // want variable sized pointers or pointers into already-read data. + // This is only available through a CMediaSample* not an IMediaSample* + // and so cannot be changed by clients. + HRESULT SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes); + + // Get me a read/write pointer to this buffer's memory. + STDMETHODIMP GetPointer(__deref_out BYTE ** ppBuffer); + + STDMETHODIMP_(LONG) GetSize(void); + + // get the stream time at which this sample should start and finish. + STDMETHODIMP GetTime( + __out REFERENCE_TIME * pTimeStart, // put time here + __out REFERENCE_TIME * pTimeEnd + ); + + // Set the stream time at which this sample should start and finish. + STDMETHODIMP SetTime( + __in_opt REFERENCE_TIME * pTimeStart, // put time here + __in_opt REFERENCE_TIME * pTimeEnd + ); + STDMETHODIMP IsSyncPoint(void); + STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint); + STDMETHODIMP IsPreroll(void); + STDMETHODIMP SetPreroll(BOOL bIsPreroll); + + STDMETHODIMP_(LONG) GetActualDataLength(void); + STDMETHODIMP SetActualDataLength(LONG lActual); + + // these allow for limited format changes in band + + STDMETHODIMP GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType); + STDMETHODIMP SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType); + + // returns S_OK if there is a discontinuity in the data (this same is + // not a continuation of the previous stream of data + // - there has been a seek). + STDMETHODIMP IsDiscontinuity(void); + // set the discontinuity property - TRUE if this sample is not a + // continuation, but a new sample after a seek. + STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity); + + // get the media times for this sample + STDMETHODIMP GetMediaTime( + __out LONGLONG * pTimeStart, + __out LONGLONG * pTimeEnd + ); + + // Set the media times for this sample + STDMETHODIMP SetMediaTime( + __in_opt LONGLONG * pTimeStart, + __in_opt LONGLONG * pTimeEnd + ); + + // Set and get properties (IMediaSample2) + STDMETHODIMP GetProperties( + DWORD cbProperties, + __out_bcount(cbProperties) BYTE * pbProperties + ); + + STDMETHODIMP SetProperties( + DWORD cbProperties, + __in_bcount(cbProperties) const BYTE * pbProperties + ); +}; + + +//===================================================================== +//===================================================================== +// Defines CBaseAllocator +// +// Abstract base class that manages a list of media samples +// +// This class provides support for getting buffers from the free list, +// including handling of commit and (asynchronous) decommit. +// +// Derive from this class and override the Alloc and Free functions to +// allocate your CMediaSample (or derived) objects and add them to the +// free list, preparing them as necessary. +//===================================================================== +//===================================================================== + +class AM_NOVTABLE CBaseAllocator : public CUnknown,// A non delegating IUnknown + public IMemAllocatorCallbackTemp, // The interface we support + public CCritSec // Provides object locking +{ + class CSampleList; + friend class CSampleList; + + /* Trick to get at protected member in CMediaSample */ + static CMediaSample * &NextSample(__in CMediaSample *pSample) + { + return pSample->m_pNext; + }; + + /* Mini list class for the free list */ + class CSampleList + { + public: + CSampleList() : m_List(NULL), m_nOnList(0) {}; +#ifdef _DEBUG + ~CSampleList() + { + ASSERT(m_nOnList == 0); + }; +#endif + CMediaSample *Head() const { return m_List; }; + CMediaSample *Next(__in CMediaSample *pSample) const { return CBaseAllocator::NextSample(pSample); }; + int GetCount() const { return m_nOnList; }; + void Add(__inout CMediaSample *pSample) + { + ASSERT(pSample != NULL); + CBaseAllocator::NextSample(pSample) = m_List; + m_List = pSample; + m_nOnList++; + }; + CMediaSample *RemoveHead() + { + CMediaSample *pSample = m_List; + if (pSample != NULL) { + m_List = CBaseAllocator::NextSample(m_List); + m_nOnList--; + } + return pSample; + }; + void Remove(__inout CMediaSample *pSample); + + public: + CMediaSample *m_List; + int m_nOnList; + }; +protected: + + CSampleList m_lFree; // Free list + + /* Note to overriders of CBaseAllocator. + + We use a lazy signalling mechanism for waiting for samples. + This means we don't call the OS if no waits occur. + + In order to implement this: + + 1. When a new sample is added to m_lFree call NotifySample() which + calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and + sets m_lWaiting to 0. + This must all be done holding the allocator's critical section. + + 2. When waiting for a sample call SetWaiting() which increments + m_lWaiting BEFORE leaving the allocator's critical section. + + 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE) + having left the allocator's critical section. The effect of + this is to remove 1 from the semaphore's count. You MUST call + this once having incremented m_lWaiting. + + The following are then true when the critical section is not held : + (let nWaiting = number about to wait or waiting) + + (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0) + (2) m_lWaiting + Semaphore count == nWaiting + + We would deadlock if + nWaiting != 0 && + m_lFree.GetCount() != 0 && + Semaphore count == 0 + + But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so + from (2) Semaphore count == nWaiting (which is non-0) so the + deadlock can't happen. + */ + + HANDLE m_hSem; // For signalling + long m_lWaiting; // Waiting for a free element + long m_lCount; // how many buffers we have agreed to provide + long m_lAllocated; // how many buffers are currently allocated + long m_lSize; // agreed size of each buffer + long m_lAlignment; // agreed alignment + long m_lPrefix; // agreed prefix (preceeds GetPointer() value) + BOOL m_bChanged; // Have the buffer requirements changed + + // if true, we are decommitted and can't allocate memory + BOOL m_bCommitted; + // if true, the decommit has happened, but we haven't called Free yet + // as there are still outstanding buffers + BOOL m_bDecommitInProgress; + + // Notification interface + IMemAllocatorNotifyCallbackTemp *m_pNotify; + + BOOL m_fEnableReleaseCallback; + + // called to decommit the memory when the last buffer is freed + // pure virtual - need to override this + virtual void Free(void) PURE; + + // override to allocate the memory when commit called + virtual HRESULT Alloc(void); + +public: + + CBaseAllocator( + __in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *, + BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); +#ifdef UNICODE + CBaseAllocator( + __in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *, + BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE); +#endif + virtual ~CBaseAllocator(); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + STDMETHODIMP SetProperties( + __in ALLOCATOR_PROPERTIES* pRequest, + __out ALLOCATOR_PROPERTIES* pActual); + + // return the properties actually being used on this allocator + STDMETHODIMP GetProperties( + __out ALLOCATOR_PROPERTIES* pProps); + + // override Commit to allocate memory. We handle the GetBuffer + //state changes + STDMETHODIMP Commit(); + + // override this to handle the memory freeing. We handle any outstanding + // GetBuffer calls + STDMETHODIMP Decommit(); + + // get container for a sample. Blocking, synchronous call to get the + // next free buffer (as represented by an IMediaSample interface). + // on return, the time etc properties will be invalid, but the buffer + // pointer and size will be correct. The two time parameters are + // optional and either may be NULL, they may alternatively be set to + // the start and end times the sample will have attached to it + // bPrevFramesSkipped is not used (used only by the video renderer's + // allocator where it affects quality management in direct draw). + + STDMETHODIMP GetBuffer(__deref_out IMediaSample **ppBuffer, + __in_opt REFERENCE_TIME * pStartTime, + __in_opt REFERENCE_TIME * pEndTime, + DWORD dwFlags); + + // final release of a CMediaSample will call this + STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer); + // obsolete:: virtual void PutOnFreeList(CMediaSample * pSample); + + STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); + + STDMETHODIMP GetFreeCount(__out LONG *plBuffersFree); + + // Notify that a sample is available + void NotifySample(); + + // Notify that we're waiting for a sample + void SetWaiting() { m_lWaiting++; }; +}; + + +//===================================================================== +//===================================================================== +// Defines CMemAllocator +// +// this is an allocator based on CBaseAllocator that allocates sample +// buffers in main memory (from 'new'). You must call SetProperties +// before calling Commit. +// +// we don't free the memory when going into Decommit state. The simplest +// way to implement this without complicating CBaseAllocator is to +// have a Free() function, called to go into decommit state, that does +// nothing and a ReallyFree function called from our destructor that +// actually frees the memory. +//===================================================================== +//===================================================================== + +// Make me one from quartz.dll +STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator); + +class CMemAllocator : public CBaseAllocator +{ + +protected: + + LPBYTE m_pBuffer; // combined memory for all buffers + + // override to free the memory when decommit completes + // - we actually do nothing, and save the memory until deletion. + void Free(void); + + // called from the destructor (and from Alloc if changing size/count) to + // actually free up the memory + void ReallyFree(void); + + // overriden to allocate the memory when commit called + HRESULT Alloc(void); + +public: + /* This goes in the factory template table to create new instances */ + static CUnknown *CreateInstance(__inout_opt LPUNKNOWN, __inout HRESULT *); + + STDMETHODIMP SetProperties( + __in ALLOCATOR_PROPERTIES* pRequest, + __out ALLOCATOR_PROPERTIES* pActual); + + CMemAllocator(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *); +#ifdef UNICODE + CMemAllocator(__in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *); +#endif + ~CMemAllocator(); +}; + +// helper used by IAMovieSetup implementation +STDAPI +AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper * pIFM + , BOOL bRegister ); + + +/////////////////////////////////////////////////////////////////////////// +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +/////////////////////////////////////////////////////////////////////////// + +#endif /* __FILTER__ */ + + + diff --git a/src/thirdparty/BaseClasses/amvideo.cpp b/src/thirdparty/BaseClasses/amvideo.cpp index c407fe34466..6af1a3fddd5 100644 --- a/src/thirdparty/BaseClasses/amvideo.cpp +++ b/src/thirdparty/BaseClasses/amvideo.cpp @@ -1,275 +1,275 @@ -//------------------------------------------------------------------------------ -// File: AMVideo.cpp -// -// Desc: DirectShow base classes - implements helper functions for -// bitmap formats. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -// These are bit field masks for true colour devices - -const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F}; -const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F}; -const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF}; - -// This maps bitmap subtypes into a bits per pixel value and also a -// name. unicode and ansi versions are stored because we have to -// return a pointer to a static string. -const struct { - const GUID *pSubtype; - WORD BitCount; - LPCSTR pName; - LPCWSTR wszName; -} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome", - &MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA", - &MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8", - &MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)", - &MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)", - &MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24", - &MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32", - &MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32", - &MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay", - &GUID_NULL, 0, "UNKNOWN", L"UNKNOWN" -}; - -// Return the size of the bitmap as defined by this header - -STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader) -{ - return DIBSIZE(*pHeader); -} - - -// This is called if the header has a 16 bit colour depth and needs to work -// out the detailed type from the bit fields (either RGB 565 or RGB 555) - -STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader) -{ - BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader; - ASSERT(pbmiHeader->biBitCount == 16); - - // If its BI_RGB then it's RGB 555 by default - - if (pbmiHeader->biCompression == BI_RGB) { - return MEDIASUBTYPE_RGB555; - } - - // Compare the bit fields with RGB 555 - - DWORD *pMask = (DWORD *) pbmInfo->bmiColors; - if (pMask[0] == bits555[0]) { - if (pMask[1] == bits555[1]) { - if (pMask[2] == bits555[2]) { - return MEDIASUBTYPE_RGB555; - } - } - } - - // Compare the bit fields with RGB 565 - - pMask = (DWORD *) pbmInfo->bmiColors; - if (pMask[0] == bits565[0]) { - if (pMask[1] == bits565[1]) { - if (pMask[2] == bits565[2]) { - return MEDIASUBTYPE_RGB565; - } - } - } - return GUID_NULL; -} - - -// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is -// used to describe it in format negotiations. For example a video codec fills -// in the format block with a VIDEOINFO structure, it also fills in the major -// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit -// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8 - -STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader) -{ - ASSERT(pbmiHeader); - - // If it's not RGB then create a GUID from the compression type - - if (pbmiHeader->biCompression != BI_RGB) { - if (pbmiHeader->biCompression != BI_BITFIELDS) { - FOURCCMap FourCCMap(pbmiHeader->biCompression); - return (const GUID) FourCCMap; - } - } - - // Map the RGB DIB bit depth to a image GUID - - switch(pbmiHeader->biBitCount) { - case 1 : return MEDIASUBTYPE_RGB1; - case 4 : return MEDIASUBTYPE_RGB4; - case 8 : return MEDIASUBTYPE_RGB8; - case 16 : return GetTrueColorType(pbmiHeader); - case 24 : return MEDIASUBTYPE_RGB24; - case 32 : return MEDIASUBTYPE_RGB32; - } - return GUID_NULL; -} - - -// Given a video bitmap subtype we return the number of bits per pixel it uses -// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the -// GUID subtype is not found in the table we return an invalid USHRT_MAX - -STDAPI_(WORD) GetBitCount(const GUID *pSubtype) -{ - ASSERT(pSubtype); - const GUID *pMediaSubtype; - INT iPosition = 0; - - // Scan the mapping list seeing if the source GUID matches any known - // bitmap subtypes, the list is terminated by a GUID_NULL entry - - for (;;) { - pMediaSubtype = BitCountMap[iPosition].pSubtype; - if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) { - return USHRT_MAX; - } - if (IsEqualGUID(*pMediaSubtype,*pSubtype)) { - return BitCountMap[iPosition].BitCount; - } - iPosition++; - } -} - - -// Given a bitmap subtype we return a description name that can be used for -// debug purposes. In a retail build this function still returns the names -// If the subtype isn't found in the lookup table we return string UNKNOWN - -int LocateSubtype(const GUID *pSubtype) -{ - ASSERT(pSubtype); - const GUID *pMediaSubtype; - INT iPosition = 0; - - // Scan the mapping list seeing if the source GUID matches any known - // bitmap subtypes, the list is terminated by a GUID_NULL entry - - for (;;) { - pMediaSubtype = BitCountMap[iPosition].pSubtype; - if (IsEqualGUID(*pMediaSubtype,*pSubtype) || - IsEqualGUID(*pMediaSubtype,GUID_NULL) - ) - { - break; - } - - iPosition++; - } - - return iPosition; -} - - - -STDAPI_(LPCWSTR) GetSubtypeNameW(const GUID *pSubtype) -{ - return BitCountMap[LocateSubtype(pSubtype)].wszName; -} - -STDAPI_(LPCSTR) GetSubtypeNameA(const GUID *pSubtype) -{ - return BitCountMap[LocateSubtype(pSubtype)].pName; -} - -#ifndef GetSubtypeName -#error wxutil.h should have defined GetSubtypeName -#endif -#undef GetSubtypeName - -// this is here for people that linked to it directly; most people -// would use the header file that picks the A or W version. -STDAPI_(LPCSTR) GetSubtypeName(const GUID *pSubtype) -{ - return GetSubtypeNameA(pSubtype); -} - - -// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER -// This is really messy to deal with because it invariably has fields that -// follow it holding bit fields, palettes and the rest. This function gives -// the number of bytes required to hold a VIDEOINFO that represents it. This -// count includes the prefix information (like the rcSource rectangle) the -// BITMAPINFOHEADER field, and any other colour information on the end. -// -// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make -// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't -// right at the start of the VIDEOINFO (there are a number of other fields), -// -// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); -// - -STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader) -{ - // Everyone has this to start with this - LONG Size = SIZE_PREHEADER + pHeader->biSize; - - ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER)); - - // Does this format use a palette, if the number of colours actually used - // is zero then it is set to the maximum that are allowed for that colour - // depth (an example is 256 for eight bits). Truecolour formats may also - // pass a palette with them in which case the used count is non zero - - // This would scare me. - ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0); - - if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) { - LONG Entries = (DWORD) 1 << pHeader->biBitCount; - if (pHeader->biClrUsed) { - Entries = pHeader->biClrUsed; - } - Size += Entries * sizeof(RGBQUAD); - } - - // Truecolour formats may have a BI_BITFIELDS specifier for compression - // type which means that room for three DWORDs should be allocated that - // specify where in each pixel the RGB colour components may be found - - if (pHeader->biCompression == BI_BITFIELDS) { - Size += SIZE_MASKS; - } - - // A BITMAPINFO for a palettised image may also contain a palette map that - // provides the information to map from a source palette to a destination - // palette during a BitBlt for example, because this information is only - // ever processed during drawing you don't normally store the palette map - // nor have any way of knowing if it is present in the data structure - - return Size; -} - - -// Returns TRUE if the VIDEOINFO contains a palette - -STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo) -{ - if (PALETTISED(pVideoInfo) == FALSE) { - if (pVideoInfo->bmiHeader.biClrUsed == 0) { - return FALSE; - } - } - return TRUE; -} - - -// Return a pointer to the first entry in a palette - -STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo) -{ - if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { - return TRUECOLOR(pVideoInfo)->bmiColors; - } - return COLORS(pVideoInfo); -} +//------------------------------------------------------------------------------ +// File: AMVideo.cpp +// +// Desc: DirectShow base classes - implements helper functions for +// bitmap formats. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +// These are bit field masks for true colour devices + +const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F}; +const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F}; +const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF}; + +// This maps bitmap subtypes into a bits per pixel value and also a +// name. unicode and ansi versions are stored because we have to +// return a pointer to a static string. +const struct { + const GUID *pSubtype; + WORD BitCount; + LPCSTR pName; + LPCWSTR wszName; +} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome", + &MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA", + &MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8", + &MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)", + &MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)", + &MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24", + &MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32", + &MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32", + &MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay", + &GUID_NULL, 0, "UNKNOWN", L"UNKNOWN" +}; + +// Return the size of the bitmap as defined by this header + +STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader) +{ + return DIBSIZE(*pHeader); +} + + +// This is called if the header has a 16 bit colour depth and needs to work +// out the detailed type from the bit fields (either RGB 565 or RGB 555) + +STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader) +{ + BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader; + ASSERT(pbmiHeader->biBitCount == 16); + + // If its BI_RGB then it's RGB 555 by default + + if (pbmiHeader->biCompression == BI_RGB) { + return MEDIASUBTYPE_RGB555; + } + + // Compare the bit fields with RGB 555 + + DWORD *pMask = (DWORD *) pbmInfo->bmiColors; + if (pMask[0] == bits555[0]) { + if (pMask[1] == bits555[1]) { + if (pMask[2] == bits555[2]) { + return MEDIASUBTYPE_RGB555; + } + } + } + + // Compare the bit fields with RGB 565 + + pMask = (DWORD *) pbmInfo->bmiColors; + if (pMask[0] == bits565[0]) { + if (pMask[1] == bits565[1]) { + if (pMask[2] == bits565[2]) { + return MEDIASUBTYPE_RGB565; + } + } + } + return GUID_NULL; +} + + +// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is +// used to describe it in format negotiations. For example a video codec fills +// in the format block with a VIDEOINFO structure, it also fills in the major +// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit +// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8 + +STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader) +{ + ASSERT(pbmiHeader); + + // If it's not RGB then create a GUID from the compression type + + if (pbmiHeader->biCompression != BI_RGB) { + if (pbmiHeader->biCompression != BI_BITFIELDS) { + FOURCCMap FourCCMap(pbmiHeader->biCompression); + return (const GUID) FourCCMap; + } + } + + // Map the RGB DIB bit depth to a image GUID + + switch(pbmiHeader->biBitCount) { + case 1 : return MEDIASUBTYPE_RGB1; + case 4 : return MEDIASUBTYPE_RGB4; + case 8 : return MEDIASUBTYPE_RGB8; + case 16 : return GetTrueColorType(pbmiHeader); + case 24 : return MEDIASUBTYPE_RGB24; + case 32 : return MEDIASUBTYPE_RGB32; + } + return GUID_NULL; +} + + +// Given a video bitmap subtype we return the number of bits per pixel it uses +// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the +// GUID subtype is not found in the table we return an invalid USHRT_MAX + +STDAPI_(WORD) GetBitCount(const GUID *pSubtype) +{ + ASSERT(pSubtype); + const GUID *pMediaSubtype; + INT iPosition = 0; + + // Scan the mapping list seeing if the source GUID matches any known + // bitmap subtypes, the list is terminated by a GUID_NULL entry + + for (;;) { + pMediaSubtype = BitCountMap[iPosition].pSubtype; + if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) { + return USHRT_MAX; + } + if (IsEqualGUID(*pMediaSubtype,*pSubtype)) { + return BitCountMap[iPosition].BitCount; + } + iPosition++; + } +} + + +// Given a bitmap subtype we return a description name that can be used for +// debug purposes. In a retail build this function still returns the names +// If the subtype isn't found in the lookup table we return string UNKNOWN + +int LocateSubtype(const GUID *pSubtype) +{ + ASSERT(pSubtype); + const GUID *pMediaSubtype; + INT iPosition = 0; + + // Scan the mapping list seeing if the source GUID matches any known + // bitmap subtypes, the list is terminated by a GUID_NULL entry + + for (;;) { + pMediaSubtype = BitCountMap[iPosition].pSubtype; + if (IsEqualGUID(*pMediaSubtype,*pSubtype) || + IsEqualGUID(*pMediaSubtype,GUID_NULL) + ) + { + break; + } + + iPosition++; + } + + return iPosition; +} + + + +STDAPI_(LPCWSTR) GetSubtypeNameW(const GUID *pSubtype) +{ + return BitCountMap[LocateSubtype(pSubtype)].wszName; +} + +STDAPI_(LPCSTR) GetSubtypeNameA(const GUID *pSubtype) +{ + return BitCountMap[LocateSubtype(pSubtype)].pName; +} + +#ifndef GetSubtypeName +#error wxutil.h should have defined GetSubtypeName +#endif +#undef GetSubtypeName + +// this is here for people that linked to it directly; most people +// would use the header file that picks the A or W version. +STDAPI_(LPCSTR) GetSubtypeName(const GUID *pSubtype) +{ + return GetSubtypeNameA(pSubtype); +} + + +// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER +// This is really messy to deal with because it invariably has fields that +// follow it holding bit fields, palettes and the rest. This function gives +// the number of bytes required to hold a VIDEOINFO that represents it. This +// count includes the prefix information (like the rcSource rectangle) the +// BITMAPINFOHEADER field, and any other colour information on the end. +// +// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make +// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't +// right at the start of the VIDEOINFO (there are a number of other fields), +// +// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER)); +// + +STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader) +{ + // Everyone has this to start with this + LONG Size = SIZE_PREHEADER + pHeader->biSize; + + ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER)); + + // Does this format use a palette, if the number of colours actually used + // is zero then it is set to the maximum that are allowed for that colour + // depth (an example is 256 for eight bits). Truecolour formats may also + // pass a palette with them in which case the used count is non zero + + // This would scare me. + ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0); + + if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) { + LONG Entries = (DWORD) 1 << pHeader->biBitCount; + if (pHeader->biClrUsed) { + Entries = pHeader->biClrUsed; + } + Size += Entries * sizeof(RGBQUAD); + } + + // Truecolour formats may have a BI_BITFIELDS specifier for compression + // type which means that room for three DWORDs should be allocated that + // specify where in each pixel the RGB colour components may be found + + if (pHeader->biCompression == BI_BITFIELDS) { + Size += SIZE_MASKS; + } + + // A BITMAPINFO for a palettised image may also contain a palette map that + // provides the information to map from a source palette to a destination + // palette during a BitBlt for example, because this information is only + // ever processed during drawing you don't normally store the palette map + // nor have any way of knowing if it is present in the data structure + + return Size; +} + + +// Returns TRUE if the VIDEOINFO contains a palette + +STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo) +{ + if (PALETTISED(pVideoInfo) == FALSE) { + if (pVideoInfo->bmiHeader.biClrUsed == 0) { + return FALSE; + } + } + return TRUE; +} + + +// Return a pointer to the first entry in a palette + +STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo) +{ + if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { + return TRUECOLOR(pVideoInfo)->bmiColors; + } + return COLORS(pVideoInfo); +} diff --git a/src/thirdparty/BaseClasses/arithutil.cpp b/src/thirdparty/BaseClasses/arithutil.cpp index 5e0bd1fffb3..54156cd8e02 100644 --- a/src/thirdparty/BaseClasses/arithutil.cpp +++ b/src/thirdparty/BaseClasses/arithutil.cpp @@ -1,360 +1,360 @@ -//------------------------------------------------------------------------------ -// File: ArithUtil.cpp -// -// Desc: DirectShow base classes - implements helper classes for building -// multimedia filters. -// -// Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - -#include "streams.h" - -// -// Declare function from largeint.h we need so that PPC can build -// - -// -// Enlarged integer divide - 64-bits / 32-bits > 32-bits -// - -#ifndef _X86_ - -#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) - -__inline -ULONG -WINAPI -EnlargedUnsignedDivide ( - IN ULARGE_INTEGER Dividend, - IN ULONG Divisor, - IN PULONG Remainder - ) -{ - // return remainder if necessary - if (Remainder != NULL) - *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); - return (ULONG)(LLtoU64(Dividend) / Divisor); -} - -#else -__inline -ULONG -WINAPI -EnlargedUnsignedDivide ( - IN ULARGE_INTEGER Dividend, - IN ULONG Divisor, - IN PULONG Remainder - ) -{ - ULONG ulResult; - _asm { - mov eax,Dividend.LowPart - mov edx,Dividend.HighPart - mov ecx,Remainder - div Divisor - or ecx,ecx - jz short label - mov [ecx],edx -label: - mov ulResult,eax - } - return ulResult; -} -#endif - - -/* Arithmetic functions to help with time format conversions -*/ - -#ifdef _M_ALPHA -// work around bug in version 12.00.8385 of the alpha compiler where -// UInt32x32To64 sign-extends its arguments (?) -#undef UInt32x32To64 -#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) -#endif - -/* Compute (a * b + d) / c */ -LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) -{ - /* Compute the absolute values to avoid signed arithmetic problems */ - ULARGE_INTEGER ua, ub; - DWORDLONG uc; - - ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); - ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); - uc = (DWORDLONG)(c >= 0 ? c : -c); - BOOL bSign = (a < 0) ^ (b < 0); - - /* Do long multiplication */ - ULARGE_INTEGER p[2]; - p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); - - /* This next computation cannot overflow into p[1].HighPart because - the max number we can compute here is: - - (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart - (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 - - == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) - == 2 ** 96 - 2 ** 33 + 1 - < 2 ** 96 - */ - - ULARGE_INTEGER x; - x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + - UInt32x32To64(ua.HighPart, ub.LowPart) + - p[0].HighPart; - p[0].HighPart = x.LowPart; - p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; - - if (d != 0) { - ULARGE_INTEGER ud[2]; - if (bSign) { - ud[0].QuadPart = (DWORDLONG)(-d); - if (d > 0) { - /* -d < 0 */ - ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; - } else { - ud[1].QuadPart = (DWORDLONG)0; - } - } else { - ud[0].QuadPart = (DWORDLONG)d; - if (d < 0) { - ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; - } else { - ud[1].QuadPart = (DWORDLONG)0; - } - } - /* Now do extended addition */ - ULARGE_INTEGER uliTotal; - - /* Add ls DWORDs */ - uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; - p[0].LowPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add 2nd most ls DWORDs */ - uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; - p[0].HighPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add MS DWORDLONGs - no carry expected */ - p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; - - /* Now see if we got a sign change from the addition */ - if ((LONG)p[1].HighPart < 0) { - bSign = !bSign; - - /* Negate the current value (ugh!) */ - p[0].QuadPart = ~p[0].QuadPart; - p[1].QuadPart = ~p[1].QuadPart; - p[0].QuadPart += 1; - p[1].QuadPart += (p[0].QuadPart == 0); - } - } - - /* Now for the division */ - if (c < 0) { - bSign = !bSign; - } - - - /* This will catch c == 0 and overflow */ - if (uc <= p[1].QuadPart) { - return bSign ? (LONGLONG)0x8000000000000000 : - (LONGLONG)0x7FFFFFFFFFFFFFFF; - } - - DWORDLONG ullResult; - - /* Do the division */ - /* If the dividend is a DWORD_LONG use the compiler */ - if (p[1].QuadPart == 0) { - ullResult = p[0].QuadPart / uc; - return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; - } - - /* If the divisor is a DWORD then its simpler */ - ULARGE_INTEGER ulic; - ulic.QuadPart = uc; - if (ulic.HighPart == 0) { - ULARGE_INTEGER uliDividend; - ULARGE_INTEGER uliResult; - DWORD dwDivisor = (DWORD)uc; - // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); - uliDividend.HighPart = p[1].LowPart; - uliDividend.LowPart = p[0].HighPart; -#ifndef USE_LARGEINT - uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); - p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); - uliResult.LowPart = 0; - uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; -#else - /* NOTE - this routine will take exceptions if - the result does not fit in a DWORD - */ - if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { - uliResult.HighPart = EnlargedUnsignedDivide( - uliDividend, - dwDivisor, - &p[0].HighPart); - } else { - uliResult.HighPart = 0; - } - uliResult.LowPart = EnlargedUnsignedDivide( - p[0], - dwDivisor, - NULL); -#endif - return bSign ? -(LONGLONG)uliResult.QuadPart : - (LONGLONG)uliResult.QuadPart; - } - - - ullResult = 0; - - /* OK - do long division */ - for (int i = 0; i < 64; i++) { - ullResult <<= 1; - - /* Shift 128 bit p left 1 */ - p[1].QuadPart <<= 1; - if ((p[0].HighPart & 0x80000000) != 0) { - p[1].LowPart++; - } - p[0].QuadPart <<= 1; - - /* Compare */ - if (uc <= p[1].QuadPart) { - p[1].QuadPart -= uc; - ullResult += 1; - } - } - - return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; -} - -LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) -{ - ULARGE_INTEGER ua; - DWORD ub; - DWORD uc; - - /* Compute the absolute values to avoid signed arithmetic problems */ - ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); - ub = (DWORD)(b >= 0 ? b : -b); - uc = (DWORD)(c >= 0 ? c : -c); - BOOL bSign = (a < 0) ^ (b < 0); - - /* Do long multiplication */ - ULARGE_INTEGER p0; - DWORD p1; - p0.QuadPart = UInt32x32To64(ua.LowPart, ub); - - if (ua.HighPart != 0) { - ULARGE_INTEGER x; - x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; - p0.HighPart = x.LowPart; - p1 = x.HighPart; - } else { - p1 = 0; - } - - if (d != 0) { - ULARGE_INTEGER ud0; - DWORD ud1; - - if (bSign) { - // - // Cast d to LONGLONG first otherwise -0x80000000 sign extends - // incorrectly - // - ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); - if (d > 0) { - /* -d < 0 */ - ud1 = (DWORD)-1; - } else { - ud1 = (DWORD)0; - } - } else { - ud0.QuadPart = (DWORDLONG)d; - if (d < 0) { - ud1 = (DWORD)-1; - } else { - ud1 = (DWORD)0; - } - } - /* Now do extended addition */ - ULARGE_INTEGER uliTotal; - - /* Add ls DWORDs */ - uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; - p0.LowPart = uliTotal.LowPart; - - /* Propagate carry */ - uliTotal.LowPart = uliTotal.HighPart; - uliTotal.HighPart = 0; - - /* Add 2nd most ls DWORDs */ - uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; - p0.HighPart = uliTotal.LowPart; - - /* Add MS DWORDLONGs - no carry expected */ - p1 += ud1 + uliTotal.HighPart; - - /* Now see if we got a sign change from the addition */ - if ((LONG)p1 < 0) { - bSign = !bSign; - - /* Negate the current value (ugh!) */ - p0.QuadPart = ~p0.QuadPart; - p1 = ~p1; - p0.QuadPart += 1; - p1 += (p0.QuadPart == 0); - } - } - - /* Now for the division */ - if (c < 0) { - bSign = !bSign; - } - - - /* This will catch c == 0 and overflow */ - if (uc <= p1) { - return bSign ? (LONGLONG)0x8000000000000000 : - (LONGLONG)0x7FFFFFFFFFFFFFFF; - } - - /* Do the division */ - - /* If the divisor is a DWORD then its simpler */ - ULARGE_INTEGER uliDividend; - ULARGE_INTEGER uliResult; - DWORD dwDivisor = uc; - uliDividend.HighPart = p1; - uliDividend.LowPart = p0.HighPart; - /* NOTE - this routine will take exceptions if - the result does not fit in a DWORD - */ - if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { - uliResult.HighPart = EnlargedUnsignedDivide( - uliDividend, - dwDivisor, - &p0.HighPart); - } else { - uliResult.HighPart = 0; - } - uliResult.LowPart = EnlargedUnsignedDivide( - p0, - dwDivisor, - NULL); - return bSign ? -(LONGLONG)uliResult.QuadPart : - (LONGLONG)uliResult.QuadPart; -} +//------------------------------------------------------------------------------ +// File: ArithUtil.cpp +// +// Desc: DirectShow base classes - implements helper classes for building +// multimedia filters. +// +// Copyright (c) 1992-2004 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +#include "streams.h" + +// +// Declare function from largeint.h we need so that PPC can build +// + +// +// Enlarged integer divide - 64-bits / 32-bits > 32-bits +// + +#ifndef _X86_ + +#define LLtoU64(x) (*(unsigned __int64*)(void*)(&(x))) + +__inline +ULONG +WINAPI +EnlargedUnsignedDivide ( + IN ULARGE_INTEGER Dividend, + IN ULONG Divisor, + IN PULONG Remainder + ) +{ + // return remainder if necessary + if (Remainder != NULL) + *Remainder = (ULONG)(LLtoU64(Dividend) % Divisor); + return (ULONG)(LLtoU64(Dividend) / Divisor); +} + +#else +__inline +ULONG +WINAPI +EnlargedUnsignedDivide ( + IN ULARGE_INTEGER Dividend, + IN ULONG Divisor, + IN PULONG Remainder + ) +{ + ULONG ulResult; + _asm { + mov eax,Dividend.LowPart + mov edx,Dividend.HighPart + mov ecx,Remainder + div Divisor + or ecx,ecx + jz short label + mov [ecx],edx +label: + mov ulResult,eax + } + return ulResult; +} +#endif + + +/* Arithmetic functions to help with time format conversions +*/ + +#ifdef _M_ALPHA +// work around bug in version 12.00.8385 of the alpha compiler where +// UInt32x32To64 sign-extends its arguments (?) +#undef UInt32x32To64 +#define UInt32x32To64(a, b) (((ULONGLONG)((ULONG)(a)) & 0xffffffff) * ((ULONGLONG)((ULONG)(b)) & 0xffffffff)) +#endif + +/* Compute (a * b + d) / c */ +LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG d) +{ + /* Compute the absolute values to avoid signed arithmetic problems */ + ULARGE_INTEGER ua, ub; + DWORDLONG uc; + + ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); + ub.QuadPart = (DWORDLONG)(b >= 0 ? b : -b); + uc = (DWORDLONG)(c >= 0 ? c : -c); + BOOL bSign = (a < 0) ^ (b < 0); + + /* Do long multiplication */ + ULARGE_INTEGER p[2]; + p[0].QuadPart = UInt32x32To64(ua.LowPart, ub.LowPart); + + /* This next computation cannot overflow into p[1].HighPart because + the max number we can compute here is: + + (2 ** 32 - 1) * (2 ** 32 - 1) + // ua.LowPart * ub.LowPart + (2 ** 32) * (2 ** 31) * (2 ** 32 - 1) * 2 // x.LowPart * y.HighPart * 2 + + == 2 ** 96 - 2 ** 64 + (2 ** 64 - 2 ** 33 + 1) + == 2 ** 96 - 2 ** 33 + 1 + < 2 ** 96 + */ + + ULARGE_INTEGER x; + x.QuadPart = UInt32x32To64(ua.LowPart, ub.HighPart) + + UInt32x32To64(ua.HighPart, ub.LowPart) + + p[0].HighPart; + p[0].HighPart = x.LowPart; + p[1].QuadPart = UInt32x32To64(ua.HighPart, ub.HighPart) + x.HighPart; + + if (d != 0) { + ULARGE_INTEGER ud[2]; + if (bSign) { + ud[0].QuadPart = (DWORDLONG)(-d); + if (d > 0) { + /* -d < 0 */ + ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; + } else { + ud[1].QuadPart = (DWORDLONG)0; + } + } else { + ud[0].QuadPart = (DWORDLONG)d; + if (d < 0) { + ud[1].QuadPart = (DWORDLONG)(LONGLONG)-1; + } else { + ud[1].QuadPart = (DWORDLONG)0; + } + } + /* Now do extended addition */ + ULARGE_INTEGER uliTotal; + + /* Add ls DWORDs */ + uliTotal.QuadPart = (DWORDLONG)ud[0].LowPart + p[0].LowPart; + p[0].LowPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add 2nd most ls DWORDs */ + uliTotal.QuadPart += (DWORDLONG)ud[0].HighPart + p[0].HighPart; + p[0].HighPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add MS DWORDLONGs - no carry expected */ + p[1].QuadPart += ud[1].QuadPart + uliTotal.QuadPart; + + /* Now see if we got a sign change from the addition */ + if ((LONG)p[1].HighPart < 0) { + bSign = !bSign; + + /* Negate the current value (ugh!) */ + p[0].QuadPart = ~p[0].QuadPart; + p[1].QuadPart = ~p[1].QuadPart; + p[0].QuadPart += 1; + p[1].QuadPart += (p[0].QuadPart == 0); + } + } + + /* Now for the division */ + if (c < 0) { + bSign = !bSign; + } + + + /* This will catch c == 0 and overflow */ + if (uc <= p[1].QuadPart) { + return bSign ? (LONGLONG)0x8000000000000000 : + (LONGLONG)0x7FFFFFFFFFFFFFFF; + } + + DWORDLONG ullResult; + + /* Do the division */ + /* If the dividend is a DWORD_LONG use the compiler */ + if (p[1].QuadPart == 0) { + ullResult = p[0].QuadPart / uc; + return bSign ? -(LONGLONG)ullResult : (LONGLONG)ullResult; + } + + /* If the divisor is a DWORD then its simpler */ + ULARGE_INTEGER ulic; + ulic.QuadPart = uc; + if (ulic.HighPart == 0) { + ULARGE_INTEGER uliDividend; + ULARGE_INTEGER uliResult; + DWORD dwDivisor = (DWORD)uc; + // ASSERT(p[1].HighPart == 0 && p[1].LowPart < dwDivisor); + uliDividend.HighPart = p[1].LowPart; + uliDividend.LowPart = p[0].HighPart; +#ifndef USE_LARGEINT + uliResult.HighPart = (DWORD)(uliDividend.QuadPart / dwDivisor); + p[0].HighPart = (DWORD)(uliDividend.QuadPart % dwDivisor); + uliResult.LowPart = 0; + uliResult.QuadPart = p[0].QuadPart / dwDivisor + uliResult.QuadPart; +#else + /* NOTE - this routine will take exceptions if + the result does not fit in a DWORD + */ + if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { + uliResult.HighPart = EnlargedUnsignedDivide( + uliDividend, + dwDivisor, + &p[0].HighPart); + } else { + uliResult.HighPart = 0; + } + uliResult.LowPart = EnlargedUnsignedDivide( + p[0], + dwDivisor, + NULL); +#endif + return bSign ? -(LONGLONG)uliResult.QuadPart : + (LONGLONG)uliResult.QuadPart; + } + + + ullResult = 0; + + /* OK - do long division */ + for (int i = 0; i < 64; i++) { + ullResult <<= 1; + + /* Shift 128 bit p left 1 */ + p[1].QuadPart <<= 1; + if ((p[0].HighPart & 0x80000000) != 0) { + p[1].LowPart++; + } + p[0].QuadPart <<= 1; + + /* Compare */ + if (uc <= p[1].QuadPart) { + p[1].QuadPart -= uc; + ullResult += 1; + } + } + + return bSign ? - (LONGLONG)ullResult : (LONGLONG)ullResult; +} + +LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG d) +{ + ULARGE_INTEGER ua; + DWORD ub; + DWORD uc; + + /* Compute the absolute values to avoid signed arithmetic problems */ + ua.QuadPart = (DWORDLONG)(a >= 0 ? a : -a); + ub = (DWORD)(b >= 0 ? b : -b); + uc = (DWORD)(c >= 0 ? c : -c); + BOOL bSign = (a < 0) ^ (b < 0); + + /* Do long multiplication */ + ULARGE_INTEGER p0; + DWORD p1; + p0.QuadPart = UInt32x32To64(ua.LowPart, ub); + + if (ua.HighPart != 0) { + ULARGE_INTEGER x; + x.QuadPart = UInt32x32To64(ua.HighPart, ub) + p0.HighPart; + p0.HighPart = x.LowPart; + p1 = x.HighPart; + } else { + p1 = 0; + } + + if (d != 0) { + ULARGE_INTEGER ud0; + DWORD ud1; + + if (bSign) { + // + // Cast d to LONGLONG first otherwise -0x80000000 sign extends + // incorrectly + // + ud0.QuadPart = (DWORDLONG)(-(LONGLONG)d); + if (d > 0) { + /* -d < 0 */ + ud1 = (DWORD)-1; + } else { + ud1 = (DWORD)0; + } + } else { + ud0.QuadPart = (DWORDLONG)d; + if (d < 0) { + ud1 = (DWORD)-1; + } else { + ud1 = (DWORD)0; + } + } + /* Now do extended addition */ + ULARGE_INTEGER uliTotal; + + /* Add ls DWORDs */ + uliTotal.QuadPart = (DWORDLONG)ud0.LowPart + p0.LowPart; + p0.LowPart = uliTotal.LowPart; + + /* Propagate carry */ + uliTotal.LowPart = uliTotal.HighPart; + uliTotal.HighPart = 0; + + /* Add 2nd most ls DWORDs */ + uliTotal.QuadPart += (DWORDLONG)ud0.HighPart + p0.HighPart; + p0.HighPart = uliTotal.LowPart; + + /* Add MS DWORDLONGs - no carry expected */ + p1 += ud1 + uliTotal.HighPart; + + /* Now see if we got a sign change from the addition */ + if ((LONG)p1 < 0) { + bSign = !bSign; + + /* Negate the current value (ugh!) */ + p0.QuadPart = ~p0.QuadPart; + p1 = ~p1; + p0.QuadPart += 1; + p1 += (p0.QuadPart == 0); + } + } + + /* Now for the division */ + if (c < 0) { + bSign = !bSign; + } + + + /* This will catch c == 0 and overflow */ + if (uc <= p1) { + return bSign ? (LONGLONG)0x8000000000000000 : + (LONGLONG)0x7FFFFFFFFFFFFFFF; + } + + /* Do the division */ + + /* If the divisor is a DWORD then its simpler */ + ULARGE_INTEGER uliDividend; + ULARGE_INTEGER uliResult; + DWORD dwDivisor = uc; + uliDividend.HighPart = p1; + uliDividend.LowPart = p0.HighPart; + /* NOTE - this routine will take exceptions if + the result does not fit in a DWORD + */ + if (uliDividend.QuadPart >= (DWORDLONG)dwDivisor) { + uliResult.HighPart = EnlargedUnsignedDivide( + uliDividend, + dwDivisor, + &p0.HighPart); + } else { + uliResult.HighPart = 0; + } + uliResult.LowPart = EnlargedUnsignedDivide( + p0, + dwDivisor, + NULL); + return bSign ? -(LONGLONG)uliResult.QuadPart : + (LONGLONG)uliResult.QuadPart; +} diff --git a/src/thirdparty/BaseClasses/cache.h b/src/thirdparty/BaseClasses/cache.h index a2d57524ac7..0a807c27ef9 100644 --- a/src/thirdparty/BaseClasses/cache.h +++ b/src/thirdparty/BaseClasses/cache.h @@ -1,74 +1,74 @@ -//------------------------------------------------------------------------------ -// File: Cache.h -// -// Desc: DirectShow base classes - efines a non-MFC generic cache class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* This class implements a simple cache. A cache object is instantiated - with the number of items it is to hold. An item is a pointer to an - object derived from CBaseObject (helps reduce memory leaks). The cache - can then have objects added to it and removed from it. The cache size - is fixed at construction time and may therefore run out or be flooded. - If it runs out it returns a NULL pointer, if it fills up it also returns - a NULL pointer instead of a pointer to the object just inserted */ - -/* Making these classes inherit from CBaseObject does nothing for their - functionality but it allows us to check there are no memory leaks */ - -/* WARNING Be very careful when using this class, what it lets you do is - store and retrieve objects so that you can minimise object creation - which in turns improves efficiency. However the object you store is - exactly the same as the object you get back which means that it short - circuits the constructor initialisation phase. This means any class - variables the object has (eg pointers) are highly likely to be invalid. - Therefore ensure you reinitialise the object before using it again */ - - -#ifndef __CACHE__ -#define __CACHE__ - - -class CCache : CBaseObject { - - /* Make copy constructor and assignment operator inaccessible */ - - CCache(const CCache &refCache); - CCache &operator=(const CCache &refCache); - -private: - - /* These are initialised in the constructor. The first variable points to - an array of pointers, each of which points to a CBaseObject derived - object. The m_iCacheSize is the static fixed size for the cache and the - m_iUsed defines the number of places filled with objects at any time. - We fill the array of pointers from the start (ie m_ppObjects[0] first) - and then only add and remove objects from the end position, so in this - respect the array of object pointers should be treated as a stack */ - - CBaseObject **m_ppObjects; - const INT m_iCacheSize; - INT m_iUsed; - -public: - - CCache(__in_opt LPCTSTR pName,INT iItems); - virtual ~CCache(); - - /* Add an item to the cache */ - CBaseObject *AddToCache(__in CBaseObject *pObject); - - /* Remove an item from the cache */ - CBaseObject *RemoveFromCache(); - - /* Delete all the objects held in the cache */ - void RemoveAll(void); - - /* Return the cache size which is set during construction */ - INT GetCacheSize(void) const {return m_iCacheSize;}; -}; - -#endif /* __CACHE__ */ - +//------------------------------------------------------------------------------ +// File: Cache.h +// +// Desc: DirectShow base classes - efines a non-MFC generic cache class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* This class implements a simple cache. A cache object is instantiated + with the number of items it is to hold. An item is a pointer to an + object derived from CBaseObject (helps reduce memory leaks). The cache + can then have objects added to it and removed from it. The cache size + is fixed at construction time and may therefore run out or be flooded. + If it runs out it returns a NULL pointer, if it fills up it also returns + a NULL pointer instead of a pointer to the object just inserted */ + +/* Making these classes inherit from CBaseObject does nothing for their + functionality but it allows us to check there are no memory leaks */ + +/* WARNING Be very careful when using this class, what it lets you do is + store and retrieve objects so that you can minimise object creation + which in turns improves efficiency. However the object you store is + exactly the same as the object you get back which means that it short + circuits the constructor initialisation phase. This means any class + variables the object has (eg pointers) are highly likely to be invalid. + Therefore ensure you reinitialise the object before using it again */ + + +#ifndef __CACHE__ +#define __CACHE__ + + +class CCache : CBaseObject { + + /* Make copy constructor and assignment operator inaccessible */ + + CCache(const CCache &refCache); + CCache &operator=(const CCache &refCache); + +private: + + /* These are initialised in the constructor. The first variable points to + an array of pointers, each of which points to a CBaseObject derived + object. The m_iCacheSize is the static fixed size for the cache and the + m_iUsed defines the number of places filled with objects at any time. + We fill the array of pointers from the start (ie m_ppObjects[0] first) + and then only add and remove objects from the end position, so in this + respect the array of object pointers should be treated as a stack */ + + CBaseObject **m_ppObjects; + const INT m_iCacheSize; + INT m_iUsed; + +public: + + CCache(__in_opt LPCTSTR pName,INT iItems); + virtual ~CCache(); + + /* Add an item to the cache */ + CBaseObject *AddToCache(__in CBaseObject *pObject); + + /* Remove an item from the cache */ + CBaseObject *RemoveFromCache(); + + /* Delete all the objects held in the cache */ + void RemoveAll(void); + + /* Return the cache size which is set during construction */ + INT GetCacheSize(void) const {return m_iCacheSize;}; +}; + +#endif /* __CACHE__ */ + diff --git a/src/thirdparty/BaseClasses/checkbmi.h b/src/thirdparty/BaseClasses/checkbmi.h index 9761daec24e..72879679c1f 100644 --- a/src/thirdparty/BaseClasses/checkbmi.h +++ b/src/thirdparty/BaseClasses/checkbmi.h @@ -1,120 +1,120 @@ -// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. - -#ifndef _CHECKBMI_H_ -#define _CHECKBMI_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -// Helper -__inline BOOL MultiplyCheckOverflow(DWORD a, DWORD b, __deref_out_range(==, a * b) DWORD *pab) { - *pab = a * b; - if ((a == 0) || (((*pab) / a) == b)) { - return TRUE; - } - return FALSE; -} - - -// Checks if the fields in a BITMAPINFOHEADER won't generate -// overlows and buffer overruns -// This is not a complete check and does not guarantee code using this structure will be secure -// from attack -// Bugs this is guarding against: -// 1. Total structure size calculation overflowing -// 2. biClrUsed > 256 for 8-bit palettized content -// 3. Total bitmap size in bytes overflowing -// 4. biSize < size of the base structure leading to accessessing random memory -// 5. Total structure size exceeding know size of data -// - -__success(return != 0) __inline BOOL ValidateBitmapInfoHeader( - const BITMAPINFOHEADER *pbmi, // pointer to structure to check - __out_range(>=, sizeof(BITMAPINFOHEADER)) DWORD cbSize // size of memory block containing structure -) -{ - DWORD dwWidthInBytes; - DWORD dwBpp; - DWORD dwWidthInBits; - DWORD dwHeight; - DWORD dwSizeImage; - DWORD dwClrUsed; - - // Reject bad parameters - do the size check first to avoid reading bad memory - if (cbSize < sizeof(BITMAPINFOHEADER) || - pbmi->biSize < sizeof(BITMAPINFOHEADER) || - pbmi->biSize > 4096) { - return FALSE; - } - - // Reject 0 size - if (pbmi->biWidth == 0 || pbmi->biHeight == 0) { - return FALSE; - } - - // Use bpp of 200 for validating against further overflows if not set for compressed format - dwBpp = 200; - - if (pbmi->biBitCount > dwBpp) { - return FALSE; - } - - // Strictly speaking abs can overflow so cast explicitly to DWORD - dwHeight = (DWORD)abs(pbmi->biHeight); - - if (!MultiplyCheckOverflow(dwBpp, (DWORD)pbmi->biWidth, &dwWidthInBits)) { - return FALSE; - } - - // Compute correct width in bytes - rounding up to 4 bytes - dwWidthInBytes = (dwWidthInBits / 8 + 3) & ~3; - - if (!MultiplyCheckOverflow(dwWidthInBytes, dwHeight, &dwSizeImage)) { - return FALSE; - } - - // Fail if total size is 0 - this catches indivual quantities being 0 - // Also don't allow huge values > 1GB which might cause arithmetic - // errors for users - if (dwSizeImage > 0x40000000 || - pbmi->biSizeImage > 0x40000000) { - return FALSE; - } - - // Fail if biClrUsed looks bad - if (pbmi->biClrUsed > 256) { - return FALSE; - } - - if (pbmi->biClrUsed == 0 && pbmi->biBitCount <= 8 && pbmi->biBitCount > 0) { - dwClrUsed = (1 << pbmi->biBitCount); - } else { - dwClrUsed = pbmi->biClrUsed; - } - - // Check total size - if (cbSize < pbmi->biSize + dwClrUsed * sizeof(RGBQUAD) + - (pbmi->biCompression == BI_BITFIELDS ? 3 * sizeof(DWORD) : 0)) { - return FALSE; - } - - // If it is RGB validate biSizeImage - lots of code assumes the size is correct - if (pbmi->biCompression == BI_RGB || pbmi->biCompression == BI_BITFIELDS) { - if (pbmi->biSizeImage != 0) { - DWORD dwBits = (DWORD)pbmi->biWidth * (DWORD)pbmi->biBitCount; - DWORD dwWidthInBytes = ((DWORD)((dwBits+31) & (~31)) / 8); - DWORD dwTotalSize = (DWORD)abs(pbmi->biHeight) * dwWidthInBytes; - if (dwTotalSize > pbmi->biSizeImage) { - return FALSE; - } - } - } - return TRUE; -} - -#ifdef __cplusplus -} -#endif - -#endif // _CHECKBMI_H_ +// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. + +#ifndef _CHECKBMI_H_ +#define _CHECKBMI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Helper +__inline BOOL MultiplyCheckOverflow(DWORD a, DWORD b, __deref_out_range(==, a * b) DWORD *pab) { + *pab = a * b; + if ((a == 0) || (((*pab) / a) == b)) { + return TRUE; + } + return FALSE; +} + + +// Checks if the fields in a BITMAPINFOHEADER won't generate +// overlows and buffer overruns +// This is not a complete check and does not guarantee code using this structure will be secure +// from attack +// Bugs this is guarding against: +// 1. Total structure size calculation overflowing +// 2. biClrUsed > 256 for 8-bit palettized content +// 3. Total bitmap size in bytes overflowing +// 4. biSize < size of the base structure leading to accessessing random memory +// 5. Total structure size exceeding know size of data +// + +__success(return != 0) __inline BOOL ValidateBitmapInfoHeader( + const BITMAPINFOHEADER *pbmi, // pointer to structure to check + __out_range(>=, sizeof(BITMAPINFOHEADER)) DWORD cbSize // size of memory block containing structure +) +{ + DWORD dwWidthInBytes; + DWORD dwBpp; + DWORD dwWidthInBits; + DWORD dwHeight; + DWORD dwSizeImage; + DWORD dwClrUsed; + + // Reject bad parameters - do the size check first to avoid reading bad memory + if (cbSize < sizeof(BITMAPINFOHEADER) || + pbmi->biSize < sizeof(BITMAPINFOHEADER) || + pbmi->biSize > 4096) { + return FALSE; + } + + // Reject 0 size + if (pbmi->biWidth == 0 || pbmi->biHeight == 0) { + return FALSE; + } + + // Use bpp of 200 for validating against further overflows if not set for compressed format + dwBpp = 200; + + if (pbmi->biBitCount > dwBpp) { + return FALSE; + } + + // Strictly speaking abs can overflow so cast explicitly to DWORD + dwHeight = (DWORD)abs(pbmi->biHeight); + + if (!MultiplyCheckOverflow(dwBpp, (DWORD)pbmi->biWidth, &dwWidthInBits)) { + return FALSE; + } + + // Compute correct width in bytes - rounding up to 4 bytes + dwWidthInBytes = (dwWidthInBits / 8 + 3) & ~3; + + if (!MultiplyCheckOverflow(dwWidthInBytes, dwHeight, &dwSizeImage)) { + return FALSE; + } + + // Fail if total size is 0 - this catches indivual quantities being 0 + // Also don't allow huge values > 1GB which might cause arithmetic + // errors for users + if (dwSizeImage > 0x40000000 || + pbmi->biSizeImage > 0x40000000) { + return FALSE; + } + + // Fail if biClrUsed looks bad + if (pbmi->biClrUsed > 256) { + return FALSE; + } + + if (pbmi->biClrUsed == 0 && pbmi->biBitCount <= 8 && pbmi->biBitCount > 0) { + dwClrUsed = (1 << pbmi->biBitCount); + } else { + dwClrUsed = pbmi->biClrUsed; + } + + // Check total size + if (cbSize < pbmi->biSize + dwClrUsed * sizeof(RGBQUAD) + + (pbmi->biCompression == BI_BITFIELDS ? 3 * sizeof(DWORD) : 0)) { + return FALSE; + } + + // If it is RGB validate biSizeImage - lots of code assumes the size is correct + if (pbmi->biCompression == BI_RGB || pbmi->biCompression == BI_BITFIELDS) { + if (pbmi->biSizeImage != 0) { + DWORD dwBits = (DWORD)pbmi->biWidth * (DWORD)pbmi->biBitCount; + DWORD dwWidthInBytes = ((DWORD)((dwBits+31) & (~31)) / 8); + DWORD dwTotalSize = (DWORD)abs(pbmi->biHeight) * dwWidthInBytes; + if (dwTotalSize > pbmi->biSizeImage) { + return FALSE; + } + } + } + return TRUE; +} + +#ifdef __cplusplus +} +#endif + +#endif // _CHECKBMI_H_ diff --git a/src/thirdparty/BaseClasses/combase.cpp b/src/thirdparty/BaseClasses/combase.cpp index dd1b5a7996e..c369bbf1c2f 100644 --- a/src/thirdparty/BaseClasses/combase.cpp +++ b/src/thirdparty/BaseClasses/combase.cpp @@ -1,266 +1,266 @@ -//------------------------------------------------------------------------------ -// File: ComBase.cpp -// -// Desc: DirectShow base classes - implements class hierarchy for creating -// COM objects. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions - - -/* Define the static member variable */ - -LONG CBaseObject::m_cObjects = 0; - - -/* Constructor */ - -CBaseObject::CBaseObject(__in_opt LPCTSTR pName) -{ - /* Increment the number of active objects */ - InterlockedIncrement(&m_cObjects); - -#ifdef _DEBUG - -#ifdef UNICODE - m_dwCookie = DbgRegisterObjectCreation(0, pName); -#else - m_dwCookie = DbgRegisterObjectCreation(pName, 0); -#endif - -#endif -} - -#ifdef UNICODE -CBaseObject::CBaseObject(const char *pName) -{ - /* Increment the number of active objects */ - InterlockedIncrement(&m_cObjects); - -#ifdef _DEBUG - m_dwCookie = DbgRegisterObjectCreation(pName, 0); -#endif -} -#endif - -HINSTANCE hlibOLEAut32; - -/* Destructor */ - -CBaseObject::~CBaseObject() -{ - /* Decrement the number of objects active */ - if (InterlockedDecrement(&m_cObjects) == 0) { - if (hlibOLEAut32) { - FreeLibrary(hlibOLEAut32); - - hlibOLEAut32 = 0; - } - }; - - -#ifdef _DEBUG - DbgRegisterObjectDestruction(m_dwCookie); -#endif -} - -static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll"); - -HINSTANCE LoadOLEAut32() -{ - if (hlibOLEAut32 == 0) { - - hlibOLEAut32 = LoadLibrary(szOle32Aut); - } - - return hlibOLEAut32; -} - - -/* Constructor */ - -// We know we use "this" in the initialization list, we also know we don't modify *phr. -#pragma warning( disable : 4355 4100 ) -CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk) -: CBaseObject(pName) -/* Start the object with a reference count of zero - when the */ -/* object is queried for it's first interface this may be */ -/* incremented depending on whether or not this object is */ -/* currently being aggregated upon */ -, m_cRef(0) -/* Set our pointer to our IUnknown interface. */ -/* If we have an outer, use its, otherwise use ours. */ -/* This pointer effectivly points to the owner of */ -/* this object and can be accessed by the GetOwner() method. */ -, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) - /* Why the double cast? Well, the inner cast is a type-safe cast */ - /* to pointer to a type from which we inherit. The second is */ - /* type-unsafe but works because INonDelegatingUnknown "behaves */ - /* like" IUnknown. (Only the names on the methods change.) */ -{ - // Everything we need to do has been done in the initializer list -} - -// This does the same as above except it has a useless HRESULT argument -// use the previous constructor, this is just left for compatibility... -CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) : - CBaseObject(pName), - m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ -} - -#ifdef UNICODE -CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk) -: CBaseObject(pName), m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ } - -CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) : - CBaseObject(pName), m_cRef(0), - m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) -{ } - -#endif - -#pragma warning( default : 4355 4100 ) - - -/* QueryInterface */ - -STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) -{ - CheckPointer(ppv,E_POINTER); - ValidateReadWritePtr(ppv,sizeof(PVOID)); - - /* We know only about IUnknown */ - - if (riid == IID_IUnknown) { - GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv); - return NOERROR; - } else { - *ppv = NULL; - return E_NOINTERFACE; - } -} - -/* We have to ensure that we DON'T use a max macro, since these will typically */ -/* lead to one of the parameters being evaluated twice. Since we are worried */ -/* about concurrency, we can't afford to access the m_cRef twice since we can't */ -/* afford to run the risk that its value having changed between accesses. */ - -template inline static T ourmax( const T & a, const T & b ) -{ - return a > b ? a : b; -} - -/* AddRef */ - -STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef() -{ - LONG lRef = InterlockedIncrement( &m_cRef ); - ASSERT(lRef > 0); - UNREFERENCED_PARAMETER(lRef); - DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"), - m_dwCookie, m_cRef)); - return ourmax(ULONG(m_cRef), 1ul); -} - - -/* Release */ - -STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease() -{ - /* If the reference count drops to zero delete ourselves */ - - LONG lRef = InterlockedDecrement( &m_cRef ); - ASSERT(lRef >= 0); - - DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"), - m_dwCookie, m_cRef)); - if (lRef == 0) { - - // COM rules say we must protect against re-entrancy. - // If we are an aggregator and we hold our own interfaces - // on the aggregatee, the QI for these interfaces will - // addref ourselves. So after doing the QI we must release - // a ref count on ourselves. Then, before releasing the - // private interface, we must addref ourselves. When we do - // this from the destructor here it will result in the ref - // count going to 1 and then back to 0 causing us to - // re-enter the destructor. Hence we add an extra refcount here - // once we know we will delete the object. - // for an example aggregator see filgraph\distrib.cpp. - - m_cRef++; - - delete this; - return ULONG(0); - } else { - // Don't touch m_cRef again even in this leg as the object - // may have just been released on another thread too - return ourmax(ULONG(lRef), 1ul); - } -} - - -/* Return an interface pointer to a requesting client - performing a thread safe AddRef as necessary */ - -STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv) -{ - CheckPointer(ppv, E_POINTER); - *ppv = pUnk; - pUnk->AddRef(); - return NOERROR; -} - - -/* Compares two interfaces and returns TRUE if they are on the same object */ - -BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond) -{ - /* Different objects can't have the same interface pointer for - any interface - */ - if (pFirst == pSecond) { - return TRUE; - } - /* OK - do it the hard way - check if they have the same - IUnknown pointers - a single object can only have one of these - */ - LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface - LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface - HRESULT hr; // General OLE return code - - ASSERT(pFirst); - ASSERT(pSecond); - - /* See if the IUnknown pointers match */ - - hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1); - if (FAILED(hr)) { - return FALSE; - } - ASSERT(pUnknown1); - - /* Release the extra interface we hold */ - - pUnknown1->Release(); - - hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2); - if (FAILED(hr)) { - return FALSE; - } - ASSERT(pUnknown2); - - /* Release the extra interface we hold */ - - pUnknown2->Release(); - return (pUnknown1 == pUnknown2); -} - +//------------------------------------------------------------------------------ +// File: ComBase.cpp +// +// Desc: DirectShow base classes - implements class hierarchy for creating +// COM objects. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions + + +/* Define the static member variable */ + +LONG CBaseObject::m_cObjects = 0; + + +/* Constructor */ + +CBaseObject::CBaseObject(__in_opt LPCTSTR pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef _DEBUG + +#ifdef UNICODE + m_dwCookie = DbgRegisterObjectCreation(0, pName); +#else + m_dwCookie = DbgRegisterObjectCreation(pName, 0); +#endif + +#endif +} + +#ifdef UNICODE +CBaseObject::CBaseObject(const char *pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef _DEBUG + m_dwCookie = DbgRegisterObjectCreation(pName, 0); +#endif +} +#endif + +HINSTANCE hlibOLEAut32; + +/* Destructor */ + +CBaseObject::~CBaseObject() +{ + /* Decrement the number of objects active */ + if (InterlockedDecrement(&m_cObjects) == 0) { + if (hlibOLEAut32) { + FreeLibrary(hlibOLEAut32); + + hlibOLEAut32 = 0; + } + }; + + +#ifdef _DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + +static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll"); + +HINSTANCE LoadOLEAut32() +{ + if (hlibOLEAut32 == 0) { + + hlibOLEAut32 = LoadLibrary(szOle32Aut); + } + + return hlibOLEAut32; +} + + +/* Constructor */ + +// We know we use "this" in the initialization list, we also know we don't modify *phr. +#pragma warning( disable : 4355 4100 ) +CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk) +: CBaseObject(pName) +/* Start the object with a reference count of zero - when the */ +/* object is queried for it's first interface this may be */ +/* incremented depending on whether or not this object is */ +/* currently being aggregated upon */ +, m_cRef(0) +/* Set our pointer to our IUnknown interface. */ +/* If we have an outer, use its, otherwise use ours. */ +/* This pointer effectivly points to the owner of */ +/* this object and can be accessed by the GetOwner() method. */ +, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) + /* Why the double cast? Well, the inner cast is a type-safe cast */ + /* to pointer to a type from which we inherit. The second is */ + /* type-unsafe but works because INonDelegatingUnknown "behaves */ + /* like" IUnknown. (Only the names on the methods change.) */ +{ + // Everything we need to do has been done in the initializer list +} + +// This does the same as above except it has a useless HRESULT argument +// use the previous constructor, this is just left for compatibility... +CUnknown::CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) : + CBaseObject(pName), + m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ +} + +#ifdef UNICODE +CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk) +: CBaseObject(pName), m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ } + +CUnknown::CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) : + CBaseObject(pName), m_cRef(0), + m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) +{ } + +#endif + +#pragma warning( default : 4355 4100 ) + + +/* QueryInterface */ + +STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + + /* We know only about IUnknown */ + + if (riid == IID_IUnknown) { + GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv); + return NOERROR; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +/* We have to ensure that we DON'T use a max macro, since these will typically */ +/* lead to one of the parameters being evaluated twice. Since we are worried */ +/* about concurrency, we can't afford to access the m_cRef twice since we can't */ +/* afford to run the risk that its value having changed between accesses. */ + +template inline static T ourmax( const T & a, const T & b ) +{ + return a > b ? a : b; +} + +/* AddRef */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef() +{ + LONG lRef = InterlockedIncrement( &m_cRef ); + ASSERT(lRef > 0); + UNREFERENCED_PARAMETER(lRef); + DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"), + m_dwCookie, m_cRef)); + return ourmax(ULONG(m_cRef), 1ul); +} + + +/* Release */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease() +{ + /* If the reference count drops to zero delete ourselves */ + + LONG lRef = InterlockedDecrement( &m_cRef ); + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"), + m_dwCookie, m_cRef)); + if (lRef == 0) { + + // COM rules say we must protect against re-entrancy. + // If we are an aggregator and we hold our own interfaces + // on the aggregatee, the QI for these interfaces will + // addref ourselves. So after doing the QI we must release + // a ref count on ourselves. Then, before releasing the + // private interface, we must addref ourselves. When we do + // this from the destructor here it will result in the ref + // count going to 1 and then back to 0 causing us to + // re-enter the destructor. Hence we add an extra refcount here + // once we know we will delete the object. + // for an example aggregator see filgraph\distrib.cpp. + + m_cRef++; + + delete this; + return ULONG(0); + } else { + // Don't touch m_cRef again even in this leg as the object + // may have just been released on another thread too + return ourmax(ULONG(lRef), 1ul); + } +} + + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = pUnk; + pUnk->AddRef(); + return NOERROR; +} + + +/* Compares two interfaces and returns TRUE if they are on the same object */ + +BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond) +{ + /* Different objects can't have the same interface pointer for + any interface + */ + if (pFirst == pSecond) { + return TRUE; + } + /* OK - do it the hard way - check if they have the same + IUnknown pointers - a single object can only have one of these + */ + LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface + LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface + HRESULT hr; // General OLE return code + + ASSERT(pFirst); + ASSERT(pSecond); + + /* See if the IUnknown pointers match */ + + hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1); + if (FAILED(hr)) { + return FALSE; + } + ASSERT(pUnknown1); + + /* Release the extra interface we hold */ + + pUnknown1->Release(); + + hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2); + if (FAILED(hr)) { + return FALSE; + } + ASSERT(pUnknown2); + + /* Release the extra interface we hold */ + + pUnknown2->Release(); + return (pUnknown1 == pUnknown2); +} + diff --git a/src/thirdparty/BaseClasses/combase.h b/src/thirdparty/BaseClasses/combase.h index cf7907bdedb..d051bf92518 100644 --- a/src/thirdparty/BaseClasses/combase.h +++ b/src/thirdparty/BaseClasses/combase.h @@ -1,315 +1,315 @@ -//------------------------------------------------------------------------------ -// File: ComBase.h -// -// Desc: DirectShow base classes - defines a class hierarchy for creating -// COM objects. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* - -a. Derive your COM object from CUnknown - -b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * - and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls - to. The HRESULT * allows error codes to be passed around constructors and - the TCHAR * is a descriptive name that can be printed on the debugger. - - It is important that constructors only change the HRESULT * if they have - to set an ERROR code, if it was successful then leave it alone or you may - overwrite an error code from an object previously created. - - When you call a constructor the descriptive name should be in static store - as we do not copy the string. To stop large amounts of memory being used - in retail builds by all these static strings use the NAME macro, - - CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); - if (FAILED(hr)) { - return hr; - } - - In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class - knows not to do anything with objects that don't have a name. - -c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and - TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an - error, or just simply pass it through to the constructor. - - The object creation will fail in the class factory if the HRESULT indicates - an error (ie FAILED(HRESULT) == TRUE) - -d. Create a FactoryTemplate with your object's class id and CreateInstance - function. - -Then (for each interface) either - -Multiple inheritance - -1. Also derive it from ISomeInterface -2. Include DECLARE_IUNKNOWN in your class definition to declare - implementations of QueryInterface, AddRef and Release that - call the outer unknown -3. Override NonDelegatingQueryInterface to expose ISomeInterface by - code something like - - if (riid == IID_ISomeInterface) { - return GetInterface((ISomeInterface *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -4. Declare and implement the member functions of ISomeInterface. - -or: Nested interfaces - -1. Declare a class derived from CUnknown -2. Include DECLARE_IUNKNOWN in your class definition -3. Override NonDelegatingQueryInterface to expose ISomeInterface by - code something like - - if (riid == IID_ISomeInterface) { - return GetInterface((ISomeInterface *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -4. Implement the member functions of ISomeInterface. Use GetOwner() to - access the COM object class. - -And in your COM object class: - -5. Make the nested class a friend of the COM object class, and declare - an instance of the nested class as a member of the COM object class. - - NOTE that because you must always pass the outer unknown and an hResult - to the CUnknown constructor you cannot use a default constructor, in - other words you will have to make the member variable a pointer to the - class and make a NEW call in your constructor to actually create it. - -6. override the NonDelegatingQueryInterface with code like this: - - if (riid == IID_ISomeInterface) { - return m_pImplFilter-> - NonDelegatingQueryInterface(IID_ISomeInterface, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - -You can have mixed classes which support some interfaces via multiple -inheritance and some via nested classes - -*/ - -#ifndef __COMBASE__ -#define __COMBASE__ - -// Filter Setup data structures no defined in axextend.idl - -typedef REGPINTYPES -AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE; - -typedef REGFILTERPINS -AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN; - -// warning C4510: '_AMOVIESETUP_FILTER' : default constructor could not be generated, see declaration of '_AMOVIESETUP_FILTER' -// warning C4610: struct '_AMOVIESETUP_FILTER' can never be instantiated - user defined constructor required -// http://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx -// 'once' - Display the specified message(s) only one time. -// warning-specifier 'once' doesn't work -//#pragma warning( once : 4510 4610 ) -#pragma warning( push ) -#pragma warning( disable : 4510 4610 ) -typedef struct _AMOVIESETUP_FILTER -{ - const CLSID * clsID; - const WCHAR * strName; - DWORD dwMerit; - UINT nPins; - const AMOVIESETUP_PIN * lpPin; - const CLSID filterCategory; -} -AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER; -#pragma warning( pop ) - -/* The DLLENTRY module initializes the module handle on loading */ - -extern HINSTANCE g_hInst; - -/* On DLL load remember which platform we are running on */ - -extern DWORD g_amPlatform; -extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx - -/* Version of IUnknown that is renamed to allow a class to support both - non delegating and delegating IUnknowns in the same COM object */ - -#ifndef INONDELEGATINGUNKNOWN_DEFINED -DECLARE_INTERFACE(INonDelegatingUnknown) -{ - STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; - STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; - STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; -}; -#define INONDELEGATINGUNKNOWN_DEFINED -#endif - -typedef INonDelegatingUnknown *PNDUNKNOWN; - - -/* This is the base object class that supports active object counting. As - part of the debug facilities we trace every time a C++ object is created - or destroyed. The name of the object has to be passed up through the class - derivation list during construction as you cannot call virtual functions - in the constructor. The downside of all this is that every single object - constructor has to take an object name parameter that describes it */ - -class CBaseObject -{ - -private: - - // Disable the copy constructor and assignment by default so you will get - // compiler errors instead of unexpected behaviour if you pass objects - // by value or assign objects. - CBaseObject(const CBaseObject& objectSrc); // no implementation - void operator=(const CBaseObject& objectSrc); // no implementation - -private: - static LONG m_cObjects; /* Total number of objects active */ - -protected: -#ifdef _DEBUG - DWORD m_dwCookie; /* Cookie identifying this object */ -#endif - - -public: - - /* These increment and decrement the number of active objects */ - - CBaseObject(__in_opt LPCTSTR pName); -#ifdef UNICODE - CBaseObject(__in_opt LPCSTR pName); -#endif - ~CBaseObject(); - - /* Call this to find if there are any CUnknown derived objects active */ - - static LONG ObjectsActive() { - return m_cObjects; - }; -}; - - -/* An object that supports one or more COM interfaces will be based on - this class. It supports counting of total objects for DLLCanUnloadNow - support, and an implementation of the core non delegating IUnknown */ - -class AM_NOVTABLE CUnknown : public INonDelegatingUnknown, - public CBaseObject -{ -private: - const LPUNKNOWN m_pUnknown; /* Owner of this object */ - -protected: /* So we can override NonDelegatingRelease() */ - volatile LONG m_cRef; /* Number of reference counts */ - -public: - - CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk); - virtual ~CUnknown() {}; - - // This is redundant, just use the other constructor - // as we never touch the HRESULT in this anyway - CUnknown(__in_opt LPCTSTR Name, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr); -#ifdef UNICODE - CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk); - CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk,__inout_opt HRESULT *phr); -#endif - - /* Return the owner of this object */ - - LPUNKNOWN GetOwner() const { - return m_pUnknown; - }; - - /* Called from the class factory to create a new instance, it is - pure virtual so it must be overriden in your derived class */ - - /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ - - /* Non delegating unknown implementation */ - - STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **); - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); -}; - -/* Return an interface pointer to a requesting client - performing a thread safe AddRef as necessary */ - -STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv); - -/* A function that can create a new COM object */ - -typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(__in_opt LPUNKNOWN pUnkOuter, __inout_opt HRESULT *phr); - -/* A function (can be NULL) which is called from the DLL entrypoint - routine for each factory template: - - bLoading - TRUE on DLL load, FALSE on DLL unload - rclsid - the m_ClsID of the entry -*/ -typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); - -/* Create one of these per object class in an array so that - the default class factory code can create new instances */ - -class CFactoryTemplate { - -public: - - const WCHAR * m_Name; - const CLSID * m_ClsID; - LPFNNewCOMObject m_lpfnNew; - LPFNInitRoutine m_lpfnInit; - const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; - - BOOL IsClassID(REFCLSID rclsid) const { - return (IsEqualCLSID(*m_ClsID,rclsid)); - }; - - CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) const { - CheckPointer(phr,NULL); - return m_lpfnNew(pUnk, phr); - }; -}; - - -/* You must override the (pure virtual) NonDelegatingQueryInterface to return - interface pointers (using GetInterface) to the interfaces your derived - class supports (the default implementation only supports IUnknown) */ - -#define DECLARE_IUNKNOWN \ - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \ - return GetOwner()->QueryInterface(riid,ppv); \ - }; \ - STDMETHODIMP_(ULONG) AddRef() { \ - return GetOwner()->AddRef(); \ - }; \ - STDMETHODIMP_(ULONG) Release() { \ - return GetOwner()->Release(); \ - }; - - - -HINSTANCE LoadOLEAut32(); - - -#endif /* __COMBASE__ */ - - - - +//------------------------------------------------------------------------------ +// File: ComBase.h +// +// Desc: DirectShow base classes - defines a class hierarchy for creating +// COM objects. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* + +a. Derive your COM object from CUnknown + +b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * + and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls + to. The HRESULT * allows error codes to be passed around constructors and + the TCHAR * is a descriptive name that can be printed on the debugger. + + It is important that constructors only change the HRESULT * if they have + to set an ERROR code, if it was successful then leave it alone or you may + overwrite an error code from an object previously created. + + When you call a constructor the descriptive name should be in static store + as we do not copy the string. To stop large amounts of memory being used + in retail builds by all these static strings use the NAME macro, + + CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); + if (FAILED(hr)) { + return hr; + } + + In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class + knows not to do anything with objects that don't have a name. + +c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and + TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an + error, or just simply pass it through to the constructor. + + The object creation will fail in the class factory if the HRESULT indicates + an error (ie FAILED(HRESULT) == TRUE) + +d. Create a FactoryTemplate with your object's class id and CreateInstance + function. + +Then (for each interface) either + +Multiple inheritance + +1. Also derive it from ISomeInterface +2. Include DECLARE_IUNKNOWN in your class definition to declare + implementations of QueryInterface, AddRef and Release that + call the outer unknown +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Declare and implement the member functions of ISomeInterface. + +or: Nested interfaces + +1. Declare a class derived from CUnknown +2. Include DECLARE_IUNKNOWN in your class definition +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Implement the member functions of ISomeInterface. Use GetOwner() to + access the COM object class. + +And in your COM object class: + +5. Make the nested class a friend of the COM object class, and declare + an instance of the nested class as a member of the COM object class. + + NOTE that because you must always pass the outer unknown and an hResult + to the CUnknown constructor you cannot use a default constructor, in + other words you will have to make the member variable a pointer to the + class and make a NEW call in your constructor to actually create it. + +6. override the NonDelegatingQueryInterface with code like this: + + if (riid == IID_ISomeInterface) { + return m_pImplFilter-> + NonDelegatingQueryInterface(IID_ISomeInterface, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +You can have mixed classes which support some interfaces via multiple +inheritance and some via nested classes + +*/ + +#ifndef __COMBASE__ +#define __COMBASE__ + +// Filter Setup data structures no defined in axextend.idl + +typedef REGPINTYPES +AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE; + +typedef REGFILTERPINS +AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN; + +// warning C4510: '_AMOVIESETUP_FILTER' : default constructor could not be generated, see declaration of '_AMOVIESETUP_FILTER' +// warning C4610: struct '_AMOVIESETUP_FILTER' can never be instantiated - user defined constructor required +// http://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx +// 'once' - Display the specified message(s) only one time. +// warning-specifier 'once' doesn't work +//#pragma warning( once : 4510 4610 ) +#pragma warning( push ) +#pragma warning( disable : 4510 4610 ) +typedef struct _AMOVIESETUP_FILTER +{ + const CLSID * clsID; + const WCHAR * strName; + DWORD dwMerit; + UINT nPins; + const AMOVIESETUP_PIN * lpPin; + const CLSID filterCategory; +} +AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER; +#pragma warning( pop ) + +/* The DLLENTRY module initializes the module handle on loading */ + +extern HINSTANCE g_hInst; + +/* On DLL load remember which platform we are running on */ + +extern DWORD g_amPlatform; +extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx + +/* Version of IUnknown that is renamed to allow a class to support both + non delegating and delegating IUnknowns in the same COM object */ + +#ifndef INONDELEGATINGUNKNOWN_DEFINED +DECLARE_INTERFACE(INonDelegatingUnknown) +{ + STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; + STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; +}; +#define INONDELEGATINGUNKNOWN_DEFINED +#endif + +typedef INonDelegatingUnknown *PNDUNKNOWN; + + +/* This is the base object class that supports active object counting. As + part of the debug facilities we trace every time a C++ object is created + or destroyed. The name of the object has to be passed up through the class + derivation list during construction as you cannot call virtual functions + in the constructor. The downside of all this is that every single object + constructor has to take an object name parameter that describes it */ + +class CBaseObject +{ + +private: + + // Disable the copy constructor and assignment by default so you will get + // compiler errors instead of unexpected behaviour if you pass objects + // by value or assign objects. + CBaseObject(const CBaseObject& objectSrc); // no implementation + void operator=(const CBaseObject& objectSrc); // no implementation + +private: + static LONG m_cObjects; /* Total number of objects active */ + +protected: +#ifdef _DEBUG + DWORD m_dwCookie; /* Cookie identifying this object */ +#endif + + +public: + + /* These increment and decrement the number of active objects */ + + CBaseObject(__in_opt LPCTSTR pName); +#ifdef UNICODE + CBaseObject(__in_opt LPCSTR pName); +#endif + ~CBaseObject(); + + /* Call this to find if there are any CUnknown derived objects active */ + + static LONG ObjectsActive() { + return m_cObjects; + }; +}; + + +/* An object that supports one or more COM interfaces will be based on + this class. It supports counting of total objects for DLLCanUnloadNow + support, and an implementation of the core non delegating IUnknown */ + +class AM_NOVTABLE CUnknown : public INonDelegatingUnknown, + public CBaseObject +{ +private: + const LPUNKNOWN m_pUnknown; /* Owner of this object */ + +protected: /* So we can override NonDelegatingRelease() */ + volatile LONG m_cRef; /* Number of reference counts */ + +public: + + CUnknown(__in_opt LPCTSTR pName, __in_opt LPUNKNOWN pUnk); + virtual ~CUnknown() {}; + + // This is redundant, just use the other constructor + // as we never touch the HRESULT in this anyway + CUnknown(__in_opt LPCTSTR Name, __in_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr); +#ifdef UNICODE + CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk); + CUnknown(__in_opt LPCSTR pName, __in_opt LPUNKNOWN pUnk,__inout_opt HRESULT *phr); +#endif + + /* Return the owner of this object */ + + LPUNKNOWN GetOwner() const { + return m_pUnknown; + }; + + /* Called from the class factory to create a new instance, it is + pure virtual so it must be overriden in your derived class */ + + /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ + + /* Non delegating unknown implementation */ + + STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); +}; + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +STDAPI GetInterface(LPUNKNOWN pUnk, __out void **ppv); + +/* A function that can create a new COM object */ + +typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(__in_opt LPUNKNOWN pUnkOuter, __inout_opt HRESULT *phr); + +/* A function (can be NULL) which is called from the DLL entrypoint + routine for each factory template: + + bLoading - TRUE on DLL load, FALSE on DLL unload + rclsid - the m_ClsID of the entry +*/ +typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); + +/* Create one of these per object class in an array so that + the default class factory code can create new instances */ + +class CFactoryTemplate { + +public: + + const WCHAR * m_Name; + const CLSID * m_ClsID; + LPFNNewCOMObject m_lpfnNew; + LPFNInitRoutine m_lpfnInit; + const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; + + BOOL IsClassID(REFCLSID rclsid) const { + return (IsEqualCLSID(*m_ClsID,rclsid)); + }; + + CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout_opt HRESULT *phr) const { + CheckPointer(phr,NULL); + return m_lpfnNew(pUnk, phr); + }; +}; + + +/* You must override the (pure virtual) NonDelegatingQueryInterface to return + interface pointers (using GetInterface) to the interfaces your derived + class supports (the default implementation only supports IUnknown) */ + +#define DECLARE_IUNKNOWN \ + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv) { \ + return GetOwner()->QueryInterface(riid,ppv); \ + }; \ + STDMETHODIMP_(ULONG) AddRef() { \ + return GetOwner()->AddRef(); \ + }; \ + STDMETHODIMP_(ULONG) Release() { \ + return GetOwner()->Release(); \ + }; + + + +HINSTANCE LoadOLEAut32(); + + +#endif /* __COMBASE__ */ + + + + diff --git a/src/thirdparty/BaseClasses/cprop.cpp b/src/thirdparty/BaseClasses/cprop.cpp index 08993b01c21..58bf8654dc7 100644 --- a/src/thirdparty/BaseClasses/cprop.cpp +++ b/src/thirdparty/BaseClasses/cprop.cpp @@ -1,384 +1,384 @@ -//------------------------------------------------------------------------------ -// File: CProp.cpp -// -// Desc: DirectShow base classes - implements CBasePropertyPage class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - -// Constructor for the base property page class. As described in the header -// file we must be initialised with dialog and title resource identifiers. -// The class supports IPropertyPage and overrides AddRef and Release calls -// to keep track of the reference counts. When the last count is released -// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces -// previously obtained by the property page when it had SetObjects called - -CBasePropertyPage::CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name - __inout_opt LPUNKNOWN pUnk, // COM Delegator - int DialogId, // Resource ID - int TitleId) : // To get tital - CUnknown(pName,pUnk), - m_DialogId(DialogId), - m_TitleId(TitleId), - m_hwnd(NULL), - m_Dlg(NULL), - m_pPageSite(NULL), - m_bObjectSet(FALSE), - m_bDirty(FALSE) -{ -} - -#ifdef UNICODE -CBasePropertyPage::CBasePropertyPage(__in_opt LPCSTR pName, // Debug only name - __inout_opt LPUNKNOWN pUnk, // COM Delegator - int DialogId, // Resource ID - int TitleId) : // To get tital - CUnknown(pName,pUnk), - m_DialogId(DialogId), - m_TitleId(TitleId), - m_hwnd(NULL), - m_Dlg(NULL), - m_pPageSite(NULL), - m_bObjectSet(FALSE), - m_bDirty(FALSE) -{ -} -#endif - -// Increment our reference count - -STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef() -{ - LONG lRef = InterlockedIncrement(&m_cRef); - ASSERT(lRef > 0); - UNREFERENCED_PARAMETER(lRef); - return std::max(ULONG(m_cRef),1ul); -} - - -// Release a reference count and protect against reentrancy - -STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease() -{ - // If the reference count drops to zero delete ourselves - - LONG lRef = InterlockedDecrement(&m_cRef); - if (lRef == 0) { - m_cRef++; - SetPageSite(NULL); - SetObjects(0,NULL); - delete this; - return ULONG(0); - } else { - // Don't touch m_cRef again here! - return std::max(ULONG(lRef),1ul); - } -} - - -// Expose our IPropertyPage interface - -STDMETHODIMP -CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) -{ - if (riid == IID_IPropertyPage) { - return GetInterface((IPropertyPage *)this,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid,ppv); - } -} - - -// Get the page info so that the page site can size itself - -STDMETHODIMP CBasePropertyPage::GetPageInfo(__out LPPROPPAGEINFO pPageInfo) -{ - CheckPointer(pPageInfo,E_POINTER); - WCHAR wszTitle[STR_MAX_LENGTH]; - WideStringFromResource(wszTitle,m_TitleId); - - // Allocate dynamic memory for the property page title - - LPOLESTR pszTitle; - HRESULT hr = AMGetWideString(wszTitle, &pszTitle); - if (FAILED(hr)) { - NOTE("No caption memory"); - return hr; - } - - pPageInfo->cb = sizeof(PROPPAGEINFO); - pPageInfo->pszTitle = pszTitle; - pPageInfo->pszDocString = NULL; - pPageInfo->pszHelpFile = NULL; - pPageInfo->dwHelpContext = 0; - - // Set defaults in case GetDialogSize fails - pPageInfo->size.cx = 340; - pPageInfo->size.cy = 150; - - GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size); - return NOERROR; -} - - -// Handles the messages for our property window - -INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - CBasePropertyPage *pPropertyPage; - - switch (uMsg) { - - case WM_INITDIALOG: - - SetWindowLongPtr(hwnd, DWLP_USER, lParam); - - // This pointer may be NULL when calculating size - - pPropertyPage = (CBasePropertyPage *) lParam; - if (pPropertyPage == NULL) { - return (LRESULT) 1; - } - pPropertyPage->m_Dlg = hwnd; - } - - // This pointer may be NULL when calculating size - - pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); - if (pPropertyPage == NULL) { - return (LRESULT) 1; - } - return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam); -} - - -// Tells us the object that should be informed of the property changes - -STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,__in_ecount_opt(cObjects) LPUNKNOWN *ppUnk) -{ - if (cObjects == 1) { - - if ((ppUnk == NULL) || (*ppUnk == NULL)) { - return E_POINTER; - } - - // Set a flag to say that we have set the Object - m_bObjectSet = TRUE ; - return OnConnect(*ppUnk); - - } else if (cObjects == 0) { - - // Set a flag to say that we have not set the Object for the page - m_bObjectSet = FALSE ; - return OnDisconnect(); - } - - DbgBreak("No support for more than one object"); - return E_UNEXPECTED; -} - - -// Create the window we will use to edit properties - -STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent, - LPCRECT pRect, - BOOL fModal) -{ - CheckPointer(pRect,E_POINTER); - - // Return failure if SetObject has not been called. - if (m_bObjectSet == FALSE) { - return E_UNEXPECTED; - } - - if (m_hwnd) { - return E_UNEXPECTED; - } - - m_hwnd = CreateDialogParam(g_hInst, - MAKEINTRESOURCE(m_DialogId), - hwndParent, - DialogProc, - (LPARAM) this); - if (m_hwnd == NULL) { - return E_OUTOFMEMORY; - } - - OnActivate(); - Move(pRect); - return Show(SW_SHOWNORMAL); -} - - -// Set the position of the property page - -STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect) -{ - CheckPointer(pRect,E_POINTER); - - if (m_hwnd == NULL) { - return E_UNEXPECTED; - } - - MoveWindow(m_hwnd, // Property page handle - pRect->left, // x coordinate - pRect->top, // y coordinate - WIDTH(pRect), // Overall window width - HEIGHT(pRect), // And likewise height - TRUE); // Should we repaint it - - return NOERROR; -} - - -// Display the property dialog - -STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow) -{ - // Have we been activated yet - - if (m_hwnd == NULL) { - return E_UNEXPECTED; - } - - // Ignore wrong show flags - - if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { - return E_INVALIDARG; - } - - ShowWindow(m_hwnd,nCmdShow); - InvalidateRect(m_hwnd,NULL,TRUE); - return NOERROR; -} - - -// Destroy the property page dialog - -STDMETHODIMP CBasePropertyPage::Deactivate(void) -{ - if (m_hwnd == NULL) { - return E_UNEXPECTED; - } - - // Remove WS_EX_CONTROLPARENT before DestroyWindow call - - DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE); - dwStyle = dwStyle & (~WS_EX_CONTROLPARENT); - - // Set m_hwnd to be NULL temporarily so the message handler - // for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT - // style back in - HWND hwnd = m_hwnd; - m_hwnd = NULL; - SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle); - m_hwnd = hwnd; - - OnDeactivate(); - - // Destroy the dialog window - - DestroyWindow(m_hwnd); - m_hwnd = NULL; - return NOERROR; -} - - -// Tells the application property page site - -STDMETHODIMP CBasePropertyPage::SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite) -{ - if (pPageSite) { - - if (m_pPageSite) { - return E_UNEXPECTED; - } - - m_pPageSite = pPageSite; - m_pPageSite->AddRef(); - - } else { - - if (m_pPageSite == NULL) { - return E_UNEXPECTED; - } - - m_pPageSite->Release(); - m_pPageSite = NULL; - } - return NOERROR; -} - - -// Apply any changes so far made - -STDMETHODIMP CBasePropertyPage::Apply() -{ - // In ActiveMovie 1.0 we used to check whether we had been activated or - // not. This is too constrictive. Apply should be allowed as long as - // SetObject was called to set an object. So we will no longer check to - // see if we have been activated (ie., m_hWnd != NULL), but instead - // make sure that m_bObjectSet is TRUE (ie., SetObject has been called). - - if (m_bObjectSet == FALSE) { - return E_UNEXPECTED; - } - - // Must have had a site set - - if (m_pPageSite == NULL) { - return E_UNEXPECTED; - } - - // Has anything changed - - if (m_bDirty == FALSE) { - return NOERROR; - } - - // Commit derived class changes - - HRESULT hr = OnApplyChanges(); - if (SUCCEEDED(hr)) { - m_bDirty = FALSE; - } - return hr; -} - - -// Base class definition for message handling - -INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) -{ - // we would like the TAB key to move around the tab stops in our property - // page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT - // style behind our back, so we need to switch it back on now behind its - // back. Otherwise the tab key will be useless in every page. - // - - CBasePropertyPage *pPropertyPage; - { - pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); - - if (pPropertyPage->m_hwnd == NULL) { - return 0; - } - switch (uMsg) { - case WM_STYLECHANGING: - if (wParam == GWL_EXSTYLE) { - LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam; - lpss->styleNew |= WS_EX_CONTROLPARENT; - return 0; - } - } - } - - return DefWindowProc(hwnd,uMsg,wParam,lParam); -} - +//------------------------------------------------------------------------------ +// File: CProp.cpp +// +// Desc: DirectShow base classes - implements CBasePropertyPage class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + +// Constructor for the base property page class. As described in the header +// file we must be initialised with dialog and title resource identifiers. +// The class supports IPropertyPage and overrides AddRef and Release calls +// to keep track of the reference counts. When the last count is released +// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces +// previously obtained by the property page when it had SetObjects called + +CBasePropertyPage::CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name + __inout_opt LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId) : // To get tital + CUnknown(pName,pUnk), + m_DialogId(DialogId), + m_TitleId(TitleId), + m_hwnd(NULL), + m_Dlg(NULL), + m_pPageSite(NULL), + m_bObjectSet(FALSE), + m_bDirty(FALSE) +{ +} + +#ifdef UNICODE +CBasePropertyPage::CBasePropertyPage(__in_opt LPCSTR pName, // Debug only name + __inout_opt LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId) : // To get tital + CUnknown(pName,pUnk), + m_DialogId(DialogId), + m_TitleId(TitleId), + m_hwnd(NULL), + m_Dlg(NULL), + m_pPageSite(NULL), + m_bObjectSet(FALSE), + m_bDirty(FALSE) +{ +} +#endif + +// Increment our reference count + +STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef() +{ + LONG lRef = InterlockedIncrement(&m_cRef); + ASSERT(lRef > 0); + UNREFERENCED_PARAMETER(lRef); + return std::max(ULONG(m_cRef),1ul); +} + + +// Release a reference count and protect against reentrancy + +STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease() +{ + // If the reference count drops to zero delete ourselves + + LONG lRef = InterlockedDecrement(&m_cRef); + if (lRef == 0) { + m_cRef++; + SetPageSite(NULL); + SetObjects(0,NULL); + delete this; + return ULONG(0); + } else { + // Don't touch m_cRef again here! + return std::max(ULONG(lRef),1ul); + } +} + + +// Expose our IPropertyPage interface + +STDMETHODIMP +CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) +{ + if (riid == IID_IPropertyPage) { + return GetInterface((IPropertyPage *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +// Get the page info so that the page site can size itself + +STDMETHODIMP CBasePropertyPage::GetPageInfo(__out LPPROPPAGEINFO pPageInfo) +{ + CheckPointer(pPageInfo,E_POINTER); + WCHAR wszTitle[STR_MAX_LENGTH]; + WideStringFromResource(wszTitle,m_TitleId); + + // Allocate dynamic memory for the property page title + + LPOLESTR pszTitle; + HRESULT hr = AMGetWideString(wszTitle, &pszTitle); + if (FAILED(hr)) { + NOTE("No caption memory"); + return hr; + } + + pPageInfo->cb = sizeof(PROPPAGEINFO); + pPageInfo->pszTitle = pszTitle; + pPageInfo->pszDocString = NULL; + pPageInfo->pszHelpFile = NULL; + pPageInfo->dwHelpContext = 0; + + // Set defaults in case GetDialogSize fails + pPageInfo->size.cx = 340; + pPageInfo->size.cy = 150; + + GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size); + return NOERROR; +} + + +// Handles the messages for our property window + +INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + CBasePropertyPage *pPropertyPage; + + switch (uMsg) { + + case WM_INITDIALOG: + + SetWindowLongPtr(hwnd, DWLP_USER, lParam); + + // This pointer may be NULL when calculating size + + pPropertyPage = (CBasePropertyPage *) lParam; + if (pPropertyPage == NULL) { + return (LRESULT) 1; + } + pPropertyPage->m_Dlg = hwnd; + } + + // This pointer may be NULL when calculating size + + pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); + if (pPropertyPage == NULL) { + return (LRESULT) 1; + } + return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam); +} + + +// Tells us the object that should be informed of the property changes + +STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,__in_ecount_opt(cObjects) LPUNKNOWN *ppUnk) +{ + if (cObjects == 1) { + + if ((ppUnk == NULL) || (*ppUnk == NULL)) { + return E_POINTER; + } + + // Set a flag to say that we have set the Object + m_bObjectSet = TRUE ; + return OnConnect(*ppUnk); + + } else if (cObjects == 0) { + + // Set a flag to say that we have not set the Object for the page + m_bObjectSet = FALSE ; + return OnDisconnect(); + } + + DbgBreak("No support for more than one object"); + return E_UNEXPECTED; +} + + +// Create the window we will use to edit properties + +STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent, + LPCRECT pRect, + BOOL fModal) +{ + CheckPointer(pRect,E_POINTER); + + // Return failure if SetObject has not been called. + if (m_bObjectSet == FALSE) { + return E_UNEXPECTED; + } + + if (m_hwnd) { + return E_UNEXPECTED; + } + + m_hwnd = CreateDialogParam(g_hInst, + MAKEINTRESOURCE(m_DialogId), + hwndParent, + DialogProc, + (LPARAM) this); + if (m_hwnd == NULL) { + return E_OUTOFMEMORY; + } + + OnActivate(); + Move(pRect); + return Show(SW_SHOWNORMAL); +} + + +// Set the position of the property page + +STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect) +{ + CheckPointer(pRect,E_POINTER); + + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + MoveWindow(m_hwnd, // Property page handle + pRect->left, // x coordinate + pRect->top, // y coordinate + WIDTH(pRect), // Overall window width + HEIGHT(pRect), // And likewise height + TRUE); // Should we repaint it + + return NOERROR; +} + + +// Display the property dialog + +STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow) +{ + // Have we been activated yet + + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + // Ignore wrong show flags + + if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { + return E_INVALIDARG; + } + + ShowWindow(m_hwnd,nCmdShow); + InvalidateRect(m_hwnd,NULL,TRUE); + return NOERROR; +} + + +// Destroy the property page dialog + +STDMETHODIMP CBasePropertyPage::Deactivate(void) +{ + if (m_hwnd == NULL) { + return E_UNEXPECTED; + } + + // Remove WS_EX_CONTROLPARENT before DestroyWindow call + + DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE); + dwStyle = dwStyle & (~WS_EX_CONTROLPARENT); + + // Set m_hwnd to be NULL temporarily so the message handler + // for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT + // style back in + HWND hwnd = m_hwnd; + m_hwnd = NULL; + SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle); + m_hwnd = hwnd; + + OnDeactivate(); + + // Destroy the dialog window + + DestroyWindow(m_hwnd); + m_hwnd = NULL; + return NOERROR; +} + + +// Tells the application property page site + +STDMETHODIMP CBasePropertyPage::SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite) +{ + if (pPageSite) { + + if (m_pPageSite) { + return E_UNEXPECTED; + } + + m_pPageSite = pPageSite; + m_pPageSite->AddRef(); + + } else { + + if (m_pPageSite == NULL) { + return E_UNEXPECTED; + } + + m_pPageSite->Release(); + m_pPageSite = NULL; + } + return NOERROR; +} + + +// Apply any changes so far made + +STDMETHODIMP CBasePropertyPage::Apply() +{ + // In ActiveMovie 1.0 we used to check whether we had been activated or + // not. This is too constrictive. Apply should be allowed as long as + // SetObject was called to set an object. So we will no longer check to + // see if we have been activated (ie., m_hWnd != NULL), but instead + // make sure that m_bObjectSet is TRUE (ie., SetObject has been called). + + if (m_bObjectSet == FALSE) { + return E_UNEXPECTED; + } + + // Must have had a site set + + if (m_pPageSite == NULL) { + return E_UNEXPECTED; + } + + // Has anything changed + + if (m_bDirty == FALSE) { + return NOERROR; + } + + // Commit derived class changes + + HRESULT hr = OnApplyChanges(); + if (SUCCEEDED(hr)) { + m_bDirty = FALSE; + } + return hr; +} + + +// Base class definition for message handling + +INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + // we would like the TAB key to move around the tab stops in our property + // page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT + // style behind our back, so we need to switch it back on now behind its + // back. Otherwise the tab key will be useless in every page. + // + + CBasePropertyPage *pPropertyPage; + { + pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER); + + if (pPropertyPage->m_hwnd == NULL) { + return 0; + } + switch (uMsg) { + case WM_STYLECHANGING: + if (wParam == GWL_EXSTYLE) { + LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam; + lpss->styleNew |= WS_EX_CONTROLPARENT; + return 0; + } + } + } + + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + diff --git a/src/thirdparty/BaseClasses/cprop.h b/src/thirdparty/BaseClasses/cprop.h index a030f8ff077..db4494067ef 100644 --- a/src/thirdparty/BaseClasses/cprop.h +++ b/src/thirdparty/BaseClasses/cprop.h @@ -1,95 +1,95 @@ -//------------------------------------------------------------------------------ -// File: CProp.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __CPROP__ -#define __CPROP__ - -// Base property page class. Filters typically expose custom properties by -// implementing special control interfaces, examples are IDirectDrawVideo -// and IQualProp on renderers. This allows property pages to be built that -// use the given interface. Applications such as the ActiveMovie OCX query -// filters for the property pages they support and expose them to the user -// -// This class provides all the framework for a property page. A property -// page is a COM object that supports IPropertyPage. We should be created -// with a resource ID for the dialog which we will load when required. We -// should also be given in the constructor a resource ID for a title string -// we will load from the DLLs STRINGTABLE. The property page titles must be -// stored in resource files so that they can be easily internationalised -// -// We have a number of virtual methods (not PURE) that may be overriden in -// derived classes to query for interfaces and so on. These functions have -// simple implementations here that just return NOERROR. Derived classes -// will almost definately have to override the message handler method called -// OnReceiveMessage. We have a static dialog procedure that calls the method -// so that derived classes don't have to fiddle around with the this pointer - -class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown -{ -protected: - - LPPROPERTYPAGESITE m_pPageSite; // Details for our property site - HWND m_hwnd; // Window handle for the page - HWND m_Dlg; // Actual dialog window handle - BOOL m_bDirty; // Has anything been changed - int m_TitleId; // Resource identifier for title - int m_DialogId; // Dialog resource identifier - - static INT_PTR CALLBACK DialogProc(HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); - -private: - BOOL m_bObjectSet ; // SetObject has been called or not. -public: - - CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name - __inout_opt LPUNKNOWN pUnk, // COM Delegator - int DialogId, // Resource ID - int TitleId); // To get tital - -#ifdef UNICODE - CBasePropertyPage(__in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - int DialogId, - int TitleId); -#endif - virtual ~CBasePropertyPage() { }; - DECLARE_IUNKNOWN - - // Override these virtual methods - - virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; }; - virtual HRESULT OnDisconnect() { return NOERROR; }; - virtual HRESULT OnActivate() { return NOERROR; }; - virtual HRESULT OnDeactivate() { return NOERROR; }; - virtual HRESULT OnApplyChanges() { return NOERROR; }; - virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); - - // These implement an IPropertyPage interface - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite); - STDMETHODIMP Activate(HWND hwndParent, LPCRECT prect,BOOL fModal); - STDMETHODIMP Deactivate(void); - STDMETHODIMP GetPageInfo(__out LPPROPPAGEINFO pPageInfo); - STDMETHODIMP SetObjects(ULONG cObjects, __in_ecount_opt(cObjects) LPUNKNOWN *ppUnk); - STDMETHODIMP Show(UINT nCmdShow); - STDMETHODIMP Move(LPCRECT prect); - STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; } - STDMETHODIMP Apply(void); - STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; } - STDMETHODIMP TranslateAccelerator(__inout LPMSG lpMsg) { return E_NOTIMPL; } -}; - -#endif // __CPROP__ - +//------------------------------------------------------------------------------ +// File: CProp.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CPROP__ +#define __CPROP__ + +// Base property page class. Filters typically expose custom properties by +// implementing special control interfaces, examples are IDirectDrawVideo +// and IQualProp on renderers. This allows property pages to be built that +// use the given interface. Applications such as the ActiveMovie OCX query +// filters for the property pages they support and expose them to the user +// +// This class provides all the framework for a property page. A property +// page is a COM object that supports IPropertyPage. We should be created +// with a resource ID for the dialog which we will load when required. We +// should also be given in the constructor a resource ID for a title string +// we will load from the DLLs STRINGTABLE. The property page titles must be +// stored in resource files so that they can be easily internationalised +// +// We have a number of virtual methods (not PURE) that may be overriden in +// derived classes to query for interfaces and so on. These functions have +// simple implementations here that just return NOERROR. Derived classes +// will almost definately have to override the message handler method called +// OnReceiveMessage. We have a static dialog procedure that calls the method +// so that derived classes don't have to fiddle around with the this pointer + +class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown +{ +protected: + + LPPROPERTYPAGESITE m_pPageSite; // Details for our property site + HWND m_hwnd; // Window handle for the page + HWND m_Dlg; // Actual dialog window handle + BOOL m_bDirty; // Has anything been changed + int m_TitleId; // Resource identifier for title + int m_DialogId; // Dialog resource identifier + + static INT_PTR CALLBACK DialogProc(HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); + +private: + BOOL m_bObjectSet ; // SetObject has been called or not. +public: + + CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name + __inout_opt LPUNKNOWN pUnk, // COM Delegator + int DialogId, // Resource ID + int TitleId); // To get tital + +#ifdef UNICODE + CBasePropertyPage(__in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + int DialogId, + int TitleId); +#endif + virtual ~CBasePropertyPage() { }; + DECLARE_IUNKNOWN + + // Override these virtual methods + + virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; }; + virtual HRESULT OnDisconnect() { return NOERROR; }; + virtual HRESULT OnActivate() { return NOERROR; }; + virtual HRESULT OnDeactivate() { return NOERROR; }; + virtual HRESULT OnApplyChanges() { return NOERROR; }; + virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); + + // These implement an IPropertyPage interface + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite); + STDMETHODIMP Activate(HWND hwndParent, LPCRECT prect,BOOL fModal); + STDMETHODIMP Deactivate(void); + STDMETHODIMP GetPageInfo(__out LPPROPPAGEINFO pPageInfo); + STDMETHODIMP SetObjects(ULONG cObjects, __in_ecount_opt(cObjects) LPUNKNOWN *ppUnk); + STDMETHODIMP Show(UINT nCmdShow); + STDMETHODIMP Move(LPCRECT prect); + STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; } + STDMETHODIMP Apply(void); + STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; } + STDMETHODIMP TranslateAccelerator(__inout LPMSG lpMsg) { return E_NOTIMPL; } +}; + +#endif // __CPROP__ + diff --git a/src/thirdparty/BaseClasses/ctlutil.cpp b/src/thirdparty/BaseClasses/ctlutil.cpp index 07cb089cb05..04870767d2b 100644 --- a/src/thirdparty/BaseClasses/ctlutil.cpp +++ b/src/thirdparty/BaseClasses/ctlutil.cpp @@ -1,2539 +1,2539 @@ -//------------------------------------------------------------------------------ -// File: CtlUtil.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Base classes implementing IDispatch parsing for the basic control dual -// interfaces. Derive from these and implement just the custom method and -// property methods. We also implement CPosPassThru that can be used by -// renderers and transforms to pass by IMediaPosition and IMediaSeeking - - -#include "streams.h" -#include -#include "seekpt.h" - -// 'bool' non standard reserved word -#pragma warning(disable:4237) - - -// --- CBaseDispatch implementation ---------- -CBaseDispatch::~CBaseDispatch() -{ - if (m_pti) { - m_pti->Release(); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CBaseDispatch::GetTypeInfoCount(__out UINT * pctinfo) -{ - CheckPointer(pctinfo,E_POINTER); - ValidateReadWritePtr(pctinfo,sizeof(UINT *)); - *pctinfo = 1; - return S_OK; -} - - -typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)( - const OLECHAR FAR *szFile, - __deref_out ITypeLib FAR* FAR* pptlib); - -typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid, - WORD wVerMajor, - WORD wVerMinor, - LCID lcid, - __deref_out ITypeLib FAR* FAR* pptlib); - -// attempt to find our type library - -STDMETHODIMP -CBaseDispatch::GetTypeInfo( - REFIID riid, - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - CheckPointer(pptinfo,E_POINTER); - ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *)); - HRESULT hr; - - *pptinfo = NULL; - - // we only support one type element - if (0 != itinfo) { - return TYPE_E_ELEMENTNOTFOUND; - } - - // always look for neutral - if (NULL == m_pti) { - - LPLOADTYPELIB lpfnLoadTypeLib; - LPLOADREGTYPELIB lpfnLoadRegTypeLib; - ITypeLib *ptlib; - HINSTANCE hInst; - - static const char szTypeLib[] = "LoadTypeLib"; - static const char szRegTypeLib[] = "LoadRegTypeLib"; - static const WCHAR szControl[] = L"control.tlb"; - - // - // Try to get the Ole32Aut.dll module handle. - // - - hInst = LoadOLEAut32(); - if (hInst == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst, - szRegTypeLib); - if (lpfnLoadRegTypeLib == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - - hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0 - lcid, &ptlib); - - if (FAILED(hr)) { - - // attempt to load directly - this will fill the - // registry in if it finds it - - lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib); - if (lpfnLoadTypeLib == NULL) { - DWORD dwError = GetLastError(); - return AmHresultFromWin32(dwError); - } - - hr = (*lpfnLoadTypeLib)(szControl, &ptlib); - if (FAILED(hr)) { - return hr; - } - } - - hr = ptlib->GetTypeInfoOfGuid( - riid, - &m_pti); - - ptlib->Release(); - - if (FAILED(hr)) { - return hr; - } - } - - *pptinfo = m_pti; - m_pti->AddRef(); - return S_OK; -} - - -STDMETHODIMP -CBaseDispatch::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - // although the IDispatch riid is dead, we use this to pass from - // the interface implementation class to us the iid we are talking about. - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti); - - if (SUCCEEDED(hr)) { - hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid); - - pti->Release(); - } - return hr; -} - - -// --- CMediaControl implementation --------- - -CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - -// expose our interfaces IMediaControl and IUnknown - -STDMETHODIMP -CMediaControl::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaControl) { - return GetInterface( (IMediaControl *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaControl::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaControl::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaControl, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaControl::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaControl, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaControl::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaControl *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- CMediaEvent implementation ---------- - - -CMediaEvent::CMediaEvent(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - - -// expose our interfaces IMediaEvent and IUnknown - -STDMETHODIMP -CMediaEvent::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) { - return GetInterface( (IMediaEventEx *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaEvent::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaEvent::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaEvent, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaEvent::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaEvent, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaEvent::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaEvent *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- CMediaPosition implementation ---------- - - -CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : - CUnknown(name, pUnk) -{ -} - -CMediaPosition::CMediaPosition(__in_opt LPCTSTR name, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT * phr) : - CUnknown(name, pUnk) -{ - UNREFERENCED_PARAMETER(phr); -} - - -// expose our interfaces IMediaPosition and IUnknown - -STDMETHODIMP -CMediaPosition::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IMediaPosition) { - return GetInterface( (IMediaPosition *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// return 1 if we support GetTypeInfo - -STDMETHODIMP -CMediaPosition::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -// attempt to find our type library - -STDMETHODIMP -CMediaPosition::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IMediaPosition, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CMediaPosition::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IMediaPosition, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CMediaPosition::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IMediaPosition *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IMediaPosition and IMediaSeeking pass through class ---------- - - -CPosPassThru::CPosPassThru(__in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - IPin *pPin) : - CMediaPosition(pName,pUnk), - m_pPin(pPin) -{ - if (pPin == NULL) { - *phr = E_POINTER; - return; - } -} - - -// Expose our IMediaSeeking and IMediaPosition interfaces - -STDMETHODIMP -CPosPassThru::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) -{ - CheckPointer(ppv,E_POINTER); - *ppv = NULL; - - if (riid == IID_IMediaSeeking) { - return GetInterface( static_cast(this), ppv); - } - return CMediaPosition::NonDelegatingQueryInterface(riid,ppv); -} - - -// Return the IMediaPosition interface from our peer - -HRESULT -CPosPassThru::GetPeer(IMediaPosition ** ppMP) -{ - *ppMP = NULL; - - IPin *pConnected; - HRESULT hr = m_pPin->ConnectedTo(&pConnected); - if (FAILED(hr)) { - return E_NOTIMPL; - } - IMediaPosition * pMP; - hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP); - pConnected->Release(); - if (FAILED(hr)) { - return E_NOTIMPL; - } - - *ppMP = pMP; - return S_OK; -} - - -// Return the IMediaSeeking interface from our peer - -HRESULT -CPosPassThru::GetPeerSeeking(__deref_out IMediaSeeking ** ppMS) -{ - *ppMS = NULL; - - IPin *pConnected; - HRESULT hr = m_pPin->ConnectedTo(&pConnected); - if (FAILED(hr)) { - return E_NOTIMPL; - } - IMediaSeeking * pMS; - hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS); - pConnected->Release(); - if (FAILED(hr)) { - return E_NOTIMPL; - } - - *ppMS = pMS; - return S_OK; -} - - -// --- IMediaSeeking methods ---------- - - -STDMETHODIMP -CPosPassThru::GetCapabilities(__out DWORD * pCaps) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetCapabilities(pCaps); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::CheckCapabilities(__inout DWORD * pCaps) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->CheckCapabilities(pCaps); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::IsFormatSupported(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->IsFormatSupported(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::QueryPreferredFormat(__out GUID *pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->QueryPreferredFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetTimeFormat(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->SetTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetTimeFormat(__out GUID *pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::IsUsingTimeFormat(const GUID * pFormat) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->IsUsingTimeFormat(pFormat); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::ConvertTimeFormat(__out LONGLONG * pTarget, - __in_opt const GUID * pTargetFormat, - LONGLONG Source, - __in_opt const GUID * pSourceFormat ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat ); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetPositions( __inout_opt LONGLONG * pCurrent, - DWORD CurrentFlags, - __inout_opt LONGLONG * pStop, - DWORD StopFlags ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags ); - pMS->Release(); - return hr; -} - -STDMETHODIMP -CPosPassThru::GetPositions(__out_opt LONGLONG *pCurrent, __out_opt LONGLONG * pStop) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetPositions(pCurrent,pStop); - pMS->Release(); - return hr; -} - -HRESULT -CPosPassThru::GetSeekingLongLong -( HRESULT (__stdcall IMediaSeeking::*pMethod)( __out LONGLONG * ) -, LONGLONG * pll -) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (SUCCEEDED(hr)) - { - hr = (pMS->*pMethod)(pll); - pMS->Release(); - } - return hr; -} - -// If we don't have a current position then ask upstream - -STDMETHODIMP -CPosPassThru::GetCurrentPosition(__out LONGLONG *pCurrent) -{ - // Can we report the current position - HRESULT hr = GetMediaTime(pCurrent,NULL); - if (SUCCEEDED(hr)) hr = NOERROR; - else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent ); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetStopPosition(__out LONGLONG *pStop) -{ - return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop ); -} - -STDMETHODIMP -CPosPassThru::GetDuration(__out LONGLONG *pDuration) -{ - return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration ); -} - - -STDMETHODIMP -CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll) -{ - return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll ); -} - - -STDMETHODIMP -CPosPassThru::GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - - hr = pMS->GetAvailable( pEarliest, pLatest ); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::GetRate(__out double * pdRate) -{ - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - hr = pMS->GetRate(pdRate); - pMS->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::SetRate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - - IMediaSeeking* pMS; - HRESULT hr = GetPeerSeeking(&pMS); - if (FAILED(hr)) { - return hr; - } - hr = pMS->SetRate(dRate); - pMS->Release(); - return hr; -} - - - - -// --- IMediaPosition methods ---------- - - -STDMETHODIMP -CPosPassThru::get_Duration(__out REFTIME * plength) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - - hr = pMP->get_Duration(plength); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_CurrentPosition(__out REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_CurrentPosition(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_CurrentPosition(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_CurrentPosition(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_StopTime(__out REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_StopTime(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_StopTime(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_StopTime(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_PrerollTime(__out REFTIME * pllTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_PrerollTime(pllTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_PrerollTime(REFTIME llTime) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_PrerollTime(llTime); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::get_Rate(__out double * pdRate) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->get_Rate(pdRate); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::put_Rate(double dRate) -{ - if (0.0 == dRate) { - return E_INVALIDARG; - } - - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->put_Rate(dRate); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::CanSeekForward(__out LONG *pCanSeekForward) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->CanSeekForward(pCanSeekForward); - pMP->Release(); - return hr; -} - - -STDMETHODIMP -CPosPassThru::CanSeekBackward(__out LONG *pCanSeekBackward) -{ - IMediaPosition* pMP; - HRESULT hr = GetPeer(&pMP); - if (FAILED(hr)) { - return hr; - } - hr = pMP->CanSeekBackward(pCanSeekBackward); - pMP->Release(); - return hr; -} - - -// --- Implements the CRendererPosPassThru class ---------- - - -// Media times (eg current frame, field, sample etc) are passed through the -// filtergraph in media samples. When a renderer gets a sample with media -// times in it, it will call one of the RegisterMediaTime methods we expose -// (one takes an IMediaSample, the other takes the media times direct). We -// store the media times internally and return them in GetCurrentPosition. - -CRendererPosPassThru::CRendererPosPassThru(__in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - IPin *pPin) : - CPosPassThru(pName,pUnk,phr,pPin), - m_StartMedia(0), - m_EndMedia(0), - m_bReset(TRUE) -{ -} - - -// Sets the media times the object should report - -HRESULT -CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample) -{ - ASSERT(pMediaSample); - LONGLONG StartMedia; - LONGLONG EndMedia; - - CAutoLock cAutoLock(&m_PositionLock); - - // Get the media times from the sample - - HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia); - if (FAILED(hr)) - { - ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET); - return hr; - } - - m_StartMedia = StartMedia; - m_EndMedia = EndMedia; - m_bReset = FALSE; - return NOERROR; -} - - -// Sets the media times the object should report - -HRESULT -CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime) -{ - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = StartTime; - m_EndMedia = EndTime; - m_bReset = FALSE; - return NOERROR; -} - - -// Return the current media times registered in the object - -HRESULT -CRendererPosPassThru::GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) -{ - ASSERT(pStartTime); - - CAutoLock cAutoLock(&m_PositionLock); - if (m_bReset == TRUE) { - return E_FAIL; - } - - // We don't have to return the end time - - HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME ); - if (pEndTime && SUCCEEDED(hr)) { - hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME ); - } - return hr; -} - - -// Resets the media times we hold - -HRESULT -CRendererPosPassThru::ResetMediaTime() -{ - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = 0; - m_EndMedia = 0; - m_bReset = TRUE; - return NOERROR; -} - -// Intended to be called by the owing filter during EOS processing so -// that the media times can be adjusted to the stop time. This ensures -// that the GetCurrentPosition will actully get to the stop position. -HRESULT -CRendererPosPassThru::EOS() -{ - HRESULT hr; - - if ( m_bReset == TRUE ) hr = E_FAIL; - else - { - LONGLONG llStop; - if (SUCCEEDED(hr=GetStopPosition(&llStop))) - { - CAutoLock cAutoLock(&m_PositionLock); - m_StartMedia = - m_EndMedia = llStop; - } - } - return hr; -} - -// -- CSourceSeeking implementation ------------ - -CSourceSeeking::CSourceSeeking( - __in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT* phr, - __in CCritSec * pLock) : - CUnknown(pName, pUnk), - m_pLock(pLock), - m_rtStart((long)0) -{ - m_rtStop = _I64_MAX / 2; - m_rtDuration = m_rtStop; - m_dRateSeeking = 1.0; - - m_dwSeekingCaps = AM_SEEKING_CanSeekForwards - | AM_SEEKING_CanSeekBackwards - | AM_SEEKING_CanSeekAbsolute - | AM_SEEKING_CanGetStopPos - | AM_SEEKING_CanGetDuration; -} - -HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - if(riid == IID_IMediaSeeking) { - CheckPointer(ppv, E_POINTER); - return GetInterface(static_cast(this), ppv); - } - else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - // only seeking in time (REFERENCE_TIME units) is supported - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -HRESULT CSourceSeeking::QueryPreferredFormat(__out GUID *pFormat) -{ - CheckPointer(pFormat, E_POINTER); - *pFormat = TIME_FORMAT_MEDIA_TIME; - return S_OK; -} - -HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - - // nothing to set; just check that it's TIME_FORMAT_TIME - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG; -} - -HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat) -{ - CheckPointer(pFormat, E_POINTER); - return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; -} - -HRESULT CSourceSeeking::GetTimeFormat(__out GUID *pFormat) -{ - CheckPointer(pFormat, E_POINTER); - *pFormat = TIME_FORMAT_MEDIA_TIME; - return S_OK; -} - -HRESULT CSourceSeeking::GetDuration(__out LONGLONG *pDuration) -{ - CheckPointer(pDuration, E_POINTER); - CAutoLock lock(m_pLock); - *pDuration = m_rtDuration; - return S_OK; -} - -HRESULT CSourceSeeking::GetStopPosition(__out LONGLONG *pStop) -{ - CheckPointer(pStop, E_POINTER); - CAutoLock lock(m_pLock); - *pStop = m_rtStop; - return S_OK; -} - -HRESULT CSourceSeeking::GetCurrentPosition(__out LONGLONG *pCurrent) -{ - // GetCurrentPosition is typically supported only in renderers and - // not in source filters. - return E_NOTIMPL; -} - -HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities ) -{ - CheckPointer(pCapabilities, E_POINTER); - *pCapabilities = m_dwSeekingCaps; - return S_OK; -} - -HRESULT CSourceSeeking::CheckCapabilities( __inout DWORD * pCapabilities ) -{ - CheckPointer(pCapabilities, E_POINTER); - - // make sure all requested capabilities are in our mask - return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK; -} - -HRESULT CSourceSeeking::ConvertTimeFormat( __out LONGLONG * pTarget, - __in_opt const GUID * pTargetFormat, - LONGLONG Source, - __in_opt const GUID * pSourceFormat ) -{ - CheckPointer(pTarget, E_POINTER); - // format guids can be null to indicate current format - - // since we only support TIME_FORMAT_MEDIA_TIME, we don't really - // offer any conversions. - if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME) - { - if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME) - { - *pTarget = Source; - return S_OK; - } - } - - return E_INVALIDARG; -} - - -HRESULT CSourceSeeking::SetPositions( __inout_opt LONGLONG * pCurrent, - DWORD CurrentFlags, - __inout_opt LONGLONG * pStop, - DWORD StopFlags ) -{ - DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask; - DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask; - - if(StopFlags) { - CheckPointer(pStop, E_POINTER); - - // accept only relative, incremental, or absolute positioning - if(StopPosBits != StopFlags) { - return E_INVALIDARG; - } - } - - if(CurrentFlags) { - CheckPointer(pCurrent, E_POINTER); - if(StartPosBits != AM_SEEKING_AbsolutePositioning && - StartPosBits != AM_SEEKING_RelativePositioning) { - return E_INVALIDARG; - } - } - - - // scope for autolock - { - CAutoLock lock(m_pLock); - - // set start position - if(StartPosBits == AM_SEEKING_AbsolutePositioning) - { - m_rtStart = *pCurrent; - } - else if(StartPosBits == AM_SEEKING_RelativePositioning) - { - m_rtStart += *pCurrent; - } - - // set stop position - if(StopPosBits == AM_SEEKING_AbsolutePositioning) - { - m_rtStop = *pStop; - } - else if(StopPosBits == AM_SEEKING_IncrementalPositioning) - { - m_rtStop = m_rtStart + *pStop; - } - else if(StopPosBits == AM_SEEKING_RelativePositioning) - { - m_rtStop = m_rtStop + *pStop; - } - } - - - HRESULT hr = S_OK; - if(SUCCEEDED(hr) && StopPosBits) { - hr = ChangeStop(); - } - if(StartPosBits) { - hr = ChangeStart(); - } - - return hr; -} - - -HRESULT CSourceSeeking::GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ) -{ - if(pCurrent) { - *pCurrent = m_rtStart; - } - if(pStop) { - *pStop = m_rtStop; - } - - return S_OK; -} - - -HRESULT CSourceSeeking::GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ) -{ - if(pEarliest) { - *pEarliest = 0; - } - if(pLatest) { - CAutoLock lock(m_pLock); - *pLatest = m_rtDuration; - } - return S_OK; -} - -HRESULT CSourceSeeking::SetRate( double dRate) -{ - { - CAutoLock lock(m_pLock); - m_dRateSeeking = dRate; - } - return ChangeRate(); -} - -HRESULT CSourceSeeking::GetRate( __out double * pdRate) -{ - CheckPointer(pdRate, E_POINTER); - CAutoLock lock(m_pLock); - *pdRate = m_dRateSeeking; - return S_OK; -} - -HRESULT CSourceSeeking::GetPreroll(__out LONGLONG *pPreroll) -{ - CheckPointer(pPreroll, E_POINTER); - *pPreroll = 0; - return S_OK; -} - - - - - -// --- CSourcePosition implementation ---------- - - -CSourcePosition::CSourcePosition(__in_opt LPCTSTR pName, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT* phr, - __in CCritSec * pLock) : - CMediaPosition(pName, pUnk), - m_pLock(pLock), - m_Start(CRefTime((LONGLONG)0)) -{ - m_Stop = _I64_MAX; - m_Rate = 1.0; -} - - -STDMETHODIMP -CSourcePosition::get_Duration(__out REFTIME * plength) -{ - CheckPointer(plength,E_POINTER); - ValidateReadWritePtr(plength,sizeof(REFTIME)); - CAutoLock lock(m_pLock); - - *plength = m_Duration; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_CurrentPosition(REFTIME llTime) -{ - m_pLock->Lock(); - m_Start = llTime; - m_pLock->Unlock(); - - return ChangeStart(); -} - - -STDMETHODIMP -CSourcePosition::get_StopTime(__out REFTIME * pllTime) -{ - CheckPointer(pllTime,E_POINTER); - ValidateReadWritePtr(pllTime,sizeof(REFTIME)); - CAutoLock lock(m_pLock); - - *pllTime = m_Stop; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_StopTime(REFTIME llTime) -{ - m_pLock->Lock(); - m_Stop = llTime; - m_pLock->Unlock(); - - return ChangeStop(); -} - - -STDMETHODIMP -CSourcePosition::get_PrerollTime(__out REFTIME * pllTime) -{ - CheckPointer(pllTime,E_POINTER); - ValidateReadWritePtr(pllTime,sizeof(REFTIME)); - return E_NOTIMPL; -} - - -STDMETHODIMP -CSourcePosition::put_PrerollTime(REFTIME llTime) -{ - return E_NOTIMPL; -} - - -STDMETHODIMP -CSourcePosition::get_Rate(__out double * pdRate) -{ - CheckPointer(pdRate,E_POINTER); - ValidateReadWritePtr(pdRate,sizeof(double)); - CAutoLock lock(m_pLock); - - *pdRate = m_Rate; - return S_OK; -} - - -STDMETHODIMP -CSourcePosition::put_Rate(double dRate) -{ - m_pLock->Lock(); - m_Rate = dRate; - m_pLock->Unlock(); - - return ChangeRate(); -} - - -// By default we can seek forwards - -STDMETHODIMP -CSourcePosition::CanSeekForward(__out LONG *pCanSeekForward) -{ - CheckPointer(pCanSeekForward,E_POINTER); - *pCanSeekForward = OATRUE; - return S_OK; -} - - -// By default we can seek backwards - -STDMETHODIMP -CSourcePosition::CanSeekBackward(__out LONG *pCanSeekBackward) -{ - CheckPointer(pCanSeekBackward,E_POINTER); - *pCanSeekBackward = OATRUE; - return S_OK; -} - - -// --- Implementation of CBasicAudio class ---------- - - -CBasicAudio::CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - -// overriden to publicise our interfaces - -STDMETHODIMP -CBasicAudio::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IBasicAudio) { - return GetInterface( (IBasicAudio *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBasicAudio::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IBasicAudio, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBasicAudio::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IBasicAudio, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBasicAudio::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IBasicAudio *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IVideoWindow implementation ---------- - -CBaseVideoWindow::CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - - -// overriden to publicise our interfaces - -STDMETHODIMP -CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IVideoWindow) { - return GetInterface( (IVideoWindow *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBaseVideoWindow::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IVideoWindow, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBaseVideoWindow::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IVideoWindow, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBaseVideoWindow::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IVideoWindow *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- IBasicVideo implementation ---------- - - -CBaseBasicVideo::CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : - CUnknown(pName, punk) -{ -} - - -// overriden to publicise our interfaces - -STDMETHODIMP -CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) { - return GetInterface( static_cast(this), ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -STDMETHODIMP -CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo) -{ - return m_basedisp.GetTypeInfoCount(pctinfo); -} - - -STDMETHODIMP -CBaseBasicVideo::GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo) -{ - return m_basedisp.GetTypeInfo( - IID_IBasicVideo, - itinfo, - lcid, - pptinfo); -} - - -STDMETHODIMP -CBaseBasicVideo::GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid) -{ - return m_basedisp.GetIDsOfNames( - IID_IBasicVideo, - rgszNames, - cNames, - lcid, - rgdispid); -} - - -STDMETHODIMP -CBaseBasicVideo::Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr) -{ - // this parameter is a dead leftover from an earlier interface - if (IID_NULL != riid) { - return DISP_E_UNKNOWNINTERFACE; - } - - ITypeInfo * pti; - HRESULT hr = GetTypeInfo(0, lcid, &pti); - - if (FAILED(hr)) { - return hr; - } - - hr = pti->Invoke( - (IBasicVideo *)this, - dispidMember, - wFlags, - pdispparams, - pvarResult, - pexcepinfo, - puArgErr); - - pti->Release(); - return hr; -} - - -// --- Implementation of Deferred Commands ---------- - - -CDispParams::CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr) -{ - cNamedArgs = 0; - rgdispidNamedArgs = NULL; - cArgs = nArgs; - - if (cArgs) { - rgvarg = new VARIANT[cArgs]; - if (NULL == rgvarg) { - cArgs = 0; - if (phr) { - *phr = E_OUTOFMEMORY; - } - return; - } - - for (UINT i = 0; i < cArgs; i++) { - - // Why aren't we using VariantCopy? - - VARIANT * pDest = &rgvarg[i]; - VARIANT * pSrc = &pArgs[i]; - - pDest->vt = pSrc->vt; - switch(pDest->vt) { - - case VT_I4: - pDest->lVal = pSrc->lVal; - break; - - case VT_UI1: - pDest->bVal = pSrc->bVal; - break; - - case VT_I2: - pDest->iVal = pSrc->iVal; - break; - - case VT_R4: - pDest->fltVal = pSrc->fltVal; - break; - - case VT_R8: - pDest->dblVal = pSrc->dblVal; - break; - - case VT_BOOL: - pDest->boolVal = pSrc->boolVal; - break; - - case VT_ERROR: - pDest->scode = pSrc->scode; - break; - - case VT_CY: - pDest->cyVal = pSrc->cyVal; - break; - - case VT_DATE: - pDest->date = pSrc->date; - break; - - case VT_BSTR: - if ((PVOID)pSrc->bstrVal == NULL) { - pDest->bstrVal = NULL; - } else { - - // a BSTR is a WORD followed by a UNICODE string. - // the pointer points just after the WORD - - WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR))); - OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))]; - if (pch) { - WORD *pui = (WORD*)pch; - *pui = len; - pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR)); - CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR)); - } else { - cArgs = i; - if (phr) { - *phr = E_OUTOFMEMORY; - } - } - } - break; - - case VT_UNKNOWN: - pDest->punkVal = pSrc->punkVal; - pDest->punkVal->AddRef(); - break; - - case VT_DISPATCH: - pDest->pdispVal = pSrc->pdispVal; - pDest->pdispVal->AddRef(); - break; - - default: - // a type we haven't got round to adding yet! - ASSERT(0); - break; - } - } - - } else { - rgvarg = NULL; - } - -} - - -CDispParams::~CDispParams() -{ - for (UINT i = 0; i < cArgs; i++) { - switch(rgvarg[i].vt) { - case VT_BSTR: - // Explicitly cast BSTR to PVOID to tell code scanning tools we really mean to test the pointer - if ((PVOID)rgvarg[i].bstrVal != NULL) { - OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR)); - delete pch; - } - break; - - case VT_UNKNOWN: - rgvarg[i].punkVal->Release(); - break; - - case VT_DISPATCH: - rgvarg[i].pdispVal->Release(); - break; - } - } - delete[] rgvarg; -} - - -// lifetime is controlled by refcounts (see defer.h) - -CDeferredCommand::CDeferredCommand( - __inout CCmdQueue * pQ, - __in_opt LPUNKNOWN pUnk, - __inout HRESULT * phr, - __in LPUNKNOWN pUnkExecutor, - REFTIME time, - __in GUID* iid, - long dispidMethod, - short wFlags, - long nArgs, - __in_ecount(nArgs) VARIANT* pDispParams, - __out VARIANT* pvarResult, - __out short* puArgErr, - BOOL bStream - ) : - CUnknown(NAME("DeferredCommand"), pUnk), - m_pQueue(pQ), - m_pUnk(pUnkExecutor), - m_iid(iid), - m_dispidMethod(dispidMethod), - m_wFlags(wFlags), - m_DispParams(nArgs, pDispParams, phr), - m_pvarResult(pvarResult), - m_bStream(bStream), - m_hrResult(E_ABORT), - m_DispId(0) - -{ - // convert REFTIME to REFERENCE_TIME - COARefTime convertor(time); - m_time = convertor; - - // no check of time validity - it's ok to queue a command that's - // already late - - // check iid is supportable on pUnk by QueryInterface for it - IUnknown * pInterface; - HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); - if (FAILED(hr)) { - *phr = hr; - return; - } - pInterface->Release(); - - - // !!! check dispidMethod and param/return types using typelib - ITypeInfo *pti; - hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti); - if (FAILED(hr)) { - *phr = hr; - return; - } - // !!! some sort of ITypeInfo validity check here - pti->Release(); - - - // Fix up the dispid for put and get - if (wFlags == DISPATCH_PROPERTYPUT) { - m_DispParams.cNamedArgs = 1; - m_DispId = DISPID_PROPERTYPUT; - m_DispParams.rgdispidNamedArgs = &m_DispId; - } - - // all checks ok - add to queue - hr = pQ->Insert(this); - if (FAILED(hr)) { - *phr = hr; - } -} - - -// refcounts are held by caller of InvokeAt... and by list. So if -// we get here, we can't be on the list - -#if 0 -CDeferredCommand::~CDeferredCommand() -{ - // this assert is invalid since if the queue is deleted while we are - // still on the queue, we will have been removed by the queue and this - // m_pQueue will not have been modified. - // ASSERT(m_pQueue == NULL); - - // we don't hold a ref count on pUnk, which is the object that should - // execute the command. - // This is because there would otherwise be a circular refcount problem - // since pUnk probably owns the CmdQueue object that has a refcount - // on us. - // The lifetime of pUnk is guaranteed by it being part of, or lifetime - // controlled by, our parent object. As long as we are on the list, pUnk - // must be valid. Once we are off the list, we do not use pUnk. - -} -#endif - - -// overriden to publicise our interfaces - -STDMETHODIMP -CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, __out void **ppv) -{ - ValidateReadWritePtr(ppv,sizeof(PVOID)); - if (riid == IID_IDeferredCommand) { - return GetInterface( (IDeferredCommand *) this, ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// remove from q. this will reduce the refcount by one (since the q -// holds a count) but can't make us go away since he must have a -// refcount in order to call this method. - -STDMETHODIMP -CDeferredCommand::Cancel() -{ - if (m_pQueue == NULL) { - return VFW_E_ALREADY_CANCELLED; - } - - HRESULT hr = m_pQueue->Remove(this); - if (FAILED(hr)) { - return hr; - } - - m_pQueue = NULL; - return S_OK; -} - - -STDMETHODIMP -CDeferredCommand::Confidence(__out LONG* pConfidence) -{ - return E_NOTIMPL; -} - - -STDMETHODIMP -CDeferredCommand::GetHResult(__out HRESULT * phrResult) -{ - CheckPointer(phrResult,E_POINTER); - ValidateReadWritePtr(phrResult,sizeof(HRESULT)); - - if (m_pQueue != NULL) { - return E_ABORT; - } - *phrResult = m_hrResult; - return S_OK; -} - - -// set the time to be a new time (checking that it is valid) and -// then requeue - -STDMETHODIMP -CDeferredCommand::Postpone(REFTIME newtime) -{ - - // check that this time is not past - // convert REFTIME to REFERENCE_TIME - COARefTime convertor(newtime); - - // check that the time has not passed - if (m_pQueue->CheckTime(convertor, IsStreamTime())) { - return VFW_E_TIME_ALREADY_PASSED; - } - - // extract from list - HRESULT hr = m_pQueue->Remove(this); - if (FAILED(hr)) { - return hr; - } - - // change time - m_time = convertor; - - // requeue - hr = m_pQueue->Insert(this); - - return hr; -} - - -HRESULT -CDeferredCommand::Invoke() -{ - // check that we are still outstanding - if (m_pQueue == NULL) { - return VFW_E_ALREADY_CANCELLED; - } - - // get the type info - ITypeInfo* pti; - HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti); - if (FAILED(hr)) { - return hr; - } - - // qi for the expected interface and then invoke it. Note that we have to - // treat the returned interface as IUnknown since we don't know its type. - IUnknown* pInterface; - - hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); - if (FAILED(hr)) { - pti->Release(); - return hr; - } - - EXCEPINFO expinfo; - UINT uArgErr; - m_hrResult = pti->Invoke( - pInterface, - GetMethod(), - GetFlags(), - GetParams(), - GetResult(), - &expinfo, - &uArgErr); - - // release the interface we QI'd for - pInterface->Release(); - pti->Release(); - - - // remove from list whether or not successful - // or we loop indefinitely - hr = m_pQueue->Remove(this); - m_pQueue = NULL; - return hr; -} - - - -// --- CCmdQueue methods ---------- - - -CCmdQueue::CCmdQueue(__inout_opt HRESULT *phr) : - m_listPresentation(NAME("Presentation time command list")), - m_listStream(NAME("Stream time command list")), - m_evDue(TRUE, phr), // manual reset - m_dwAdvise(0), - m_pClock(NULL), - m_bRunning(FALSE) -{ -} - - -CCmdQueue::~CCmdQueue() -{ - // empty all our lists - - // we hold a refcount on each, so traverse and Release each - // entry then RemoveAll to empty the list - POSITION pos = m_listPresentation.GetHeadPosition(); - - while(pos) { - CDeferredCommand* pCmd = m_listPresentation.GetNext(pos); - pCmd->Release(); - } - m_listPresentation.RemoveAll(); - - pos = m_listStream.GetHeadPosition(); - - while(pos) { - CDeferredCommand* pCmd = m_listStream.GetNext(pos); - pCmd->Release(); - } - m_listStream.RemoveAll(); - - if (m_pClock) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - m_dwAdvise = 0; - } - m_pClock->Release(); - } -} - - -// returns a new CDeferredCommand object that will be initialised with -// the parameters and will be added to the queue during construction. -// returns S_OK if successfully created otherwise an error and -// no object has been queued. - -HRESULT -CCmdQueue::New( - __out CDeferredCommand **ppCmd, - __in LPUNKNOWN pUnk, // this object will execute command - REFTIME time, - __in GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - __in_ecount(cArgs) VARIANT* pDispParams, - __out VARIANT* pvarResult, - __out short* puArgErr, - BOOL bStream -) -{ - CAutoLock lock(&m_Lock); - - HRESULT hr = S_OK; - *ppCmd = NULL; - - CDeferredCommand* pCmd; - pCmd = new CDeferredCommand( - this, - NULL, // not aggregated - &hr, - pUnk, // this guy will execute - time, - iid, - dispidMethod, - wFlags, - cArgs, - pDispParams, - pvarResult, - puArgErr, - bStream); - - if (pCmd == NULL) { - hr = E_OUTOFMEMORY; - } else { - *ppCmd = pCmd; - } - return hr; -} - - -HRESULT -CCmdQueue::Insert(__in CDeferredCommand* pCmd) -{ - CAutoLock lock(&m_Lock); - - // addref the item - pCmd->AddRef(); - - CGenericList * pList; - if (pCmd->IsStreamTime()) { - pList = &m_listStream; - } else { - pList = &m_listPresentation; - } - POSITION pos = pList->GetHeadPosition(); - - // seek past all items that are before us - while (pos && - (pList->GetValid(pos)->GetTime() <= pCmd->GetTime())) { - - pList->GetNext(pos); - } - - // now at end of list or in front of items that come later - if (!pos) { - pList->AddTail(pCmd); - } else { - pList->AddBefore(pos, pCmd); - } - - SetTimeAdvise(); - return S_OK; -} - - -HRESULT -CCmdQueue::Remove(__in CDeferredCommand* pCmd) -{ - CAutoLock lock(&m_Lock); - HRESULT hr = S_OK; - - CGenericList * pList; - if (pCmd->IsStreamTime()) { - pList = &m_listStream; - } else { - pList = &m_listPresentation; - } - POSITION pos = pList->GetHeadPosition(); - - // traverse the list - while (pos && (pList->GetValid(pos) != pCmd)) { - pList->GetNext(pos); - } - - // did we drop off the end? - if (!pos) { - hr = VFW_E_NOT_FOUND; - } else { - - // found it - now take off list - pList->Remove(pos); - - // Insert did an AddRef, so release it - pCmd->Release(); - - // check that timer request is still for earliest time - SetTimeAdvise(); - } - return hr; -} - - -// set the clock used for timing - -HRESULT -CCmdQueue::SetSyncSource(__in_opt IReferenceClock* pClock) -{ - CAutoLock lock(&m_Lock); - - // addref the new clock first in case they are the same - if (pClock) { - pClock->AddRef(); - } - - // kill any advise on the old clock - if (m_pClock) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - m_dwAdvise = 0; - } - m_pClock->Release(); - } - m_pClock = pClock; - - // set up a new advise - SetTimeAdvise(); - return S_OK; -} - - -// set up a timer event with the reference clock - -void -CCmdQueue::SetTimeAdvise(void) -{ - // make sure we have a clock to use - if (!m_pClock) { - return; - } - - // reset the event whenever we are requesting a new signal - m_evDue.Reset(); - - // time 0 is earliest - CRefTime current; - - // find the earliest presentation time - POSITION pos = m_listPresentation.GetHeadPosition(); - if (pos != NULL) { - current = m_listPresentation.GetValid(pos)->GetTime(); - } - - // if we're running, check the stream times too - if (m_bRunning) { - - CRefTime t; - pos = m_listStream.GetHeadPosition(); - if (NULL != pos) { - t = m_listStream.GetValid(pos)->GetTime(); - - // add on stream time offset to get presentation time - t += m_StreamTimeOffset; - - // is this earlier? - if ((current == TimeZero) || (t < current)) { - current = t; - } - } - } - - // need to change? - if ((current > TimeZero) && (current != m_tCurrentAdvise)) { - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - // reset the event whenever we are requesting a new signal - m_evDue.Reset(); - } - - // ask for time advice - the first two params are either - // stream time offset and stream time or - // presentation time and 0. we always use the latter - HRESULT hr = m_pClock->AdviseTime( - (REFERENCE_TIME)current, - TimeZero, - (HEVENT) HANDLE(m_evDue), - &m_dwAdvise); - - ASSERT(SUCCEEDED(hr)); - UNREFERENCED_PARAMETER(hr); - m_tCurrentAdvise = current; - } -} - - -// switch to run mode. Streamtime to Presentation time mapping known. - -HRESULT -CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset) -{ - CAutoLock lock(&m_Lock); - - m_StreamTimeOffset = tStreamTimeOffset; - m_bRunning = TRUE; - - // ensure advise is accurate - SetTimeAdvise(); - return S_OK; -} - - -// switch to Stopped or Paused mode. Time mapping not known. - -HRESULT -CCmdQueue::EndRun() -{ - CAutoLock lock(&m_Lock); - - m_bRunning = FALSE; - - // check timer setting - stream times - SetTimeAdvise(); - return S_OK; -} - - -// return a pointer to the next due command. Blocks for msTimeout -// milliseconds until there is a due command. -// Stream-time commands will only become due between Run and Endrun calls. -// The command remains queued until invoked or cancelled. -// Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). -// -// returns an AddRef'd object - -HRESULT -CCmdQueue::GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout) -{ - // loop until we timeout or find a due command - for (;;) { - - { - CAutoLock lock(&m_Lock); - - - // find the earliest command - CDeferredCommand * pCmd = NULL; - - // check the presentation time and the - // stream time list to find the earliest - - POSITION pos = m_listPresentation.GetHeadPosition(); - - if (NULL != pos) { - pCmd = m_listPresentation.GetValid(pos); - } - - if (m_bRunning) { - pos = m_listStream.GetHeadPosition(); - if (NULL != pos) { - CDeferredCommand* pStrm = m_listStream.GetValid(pos); - - CRefTime t = pStrm->GetTime() + m_StreamTimeOffset; - if (!pCmd || (t < pCmd->GetTime())) { - pCmd = pStrm; - } - } - } - - // if we have found one, is it due? - if (pCmd) { - if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) { - - // yes it's due - addref it - pCmd->AddRef(); - *ppCmd = pCmd; - return S_OK; - } - } - } - - // block until the advise is signalled - if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) { - return E_ABORT; - } - } -} - - -// return a pointer to a command that will be due for a given time. -// Pass in a stream time here. The stream time offset will be passed -// in via the Run method. -// Commands remain queued until invoked or cancelled. -// This method will not block. It will report E_ABORT if there are no -// commands due yet. -// -// returns an AddRef'd object - -HRESULT -CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, __out CDeferredCommand**ppCmd) -{ - CAutoLock lock(&m_Lock); - - CRefTime tStream(rtStream); - - // find the earliest stream and presentation time commands - CDeferredCommand* pStream = NULL; - POSITION pos = m_listStream.GetHeadPosition(); - if (NULL != pos) { - pStream = m_listStream.GetValid(pos); - } - CDeferredCommand* pPresent = NULL; - pos = m_listPresentation.GetHeadPosition(); - if (NULL != pos) { - pPresent = m_listPresentation.GetValid(pos); - } - - // is there a presentation time that has passed already - if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) { - pPresent->AddRef(); - *ppCmd = pPresent; - return S_OK; - } - - // is there a stream time command due before this stream time - if (pStream && (pStream->GetTime() <= tStream)) { - pStream->AddRef(); - *ppCmd = pStream; - return S_OK; - } - - // if we are running, we can map presentation times to - // stream time. In this case, is there a presentation time command - // that will be due before this stream time is presented? - if (m_bRunning && pPresent) { - - // this stream time will appear at... - tStream += m_StreamTimeOffset; - - // due before that? - if (pPresent->GetTime() <= tStream) { - *ppCmd = pPresent; - return S_OK; - } - } - - // no commands due yet - return VFW_E_NOT_FOUND; -} - +//------------------------------------------------------------------------------ +// File: CtlUtil.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Base classes implementing IDispatch parsing for the basic control dual +// interfaces. Derive from these and implement just the custom method and +// property methods. We also implement CPosPassThru that can be used by +// renderers and transforms to pass by IMediaPosition and IMediaSeeking + + +#include "streams.h" +#include +#include "seekpt.h" + +// 'bool' non standard reserved word +#pragma warning(disable:4237) + + +// --- CBaseDispatch implementation ---------- +CBaseDispatch::~CBaseDispatch() +{ + if (m_pti) { + m_pti->Release(); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CBaseDispatch::GetTypeInfoCount(__out UINT * pctinfo) +{ + CheckPointer(pctinfo,E_POINTER); + ValidateReadWritePtr(pctinfo,sizeof(UINT *)); + *pctinfo = 1; + return S_OK; +} + + +typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)( + const OLECHAR FAR *szFile, + __deref_out ITypeLib FAR* FAR* pptlib); + +typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid, + WORD wVerMajor, + WORD wVerMinor, + LCID lcid, + __deref_out ITypeLib FAR* FAR* pptlib); + +// attempt to find our type library + +STDMETHODIMP +CBaseDispatch::GetTypeInfo( + REFIID riid, + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + CheckPointer(pptinfo,E_POINTER); + ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *)); + HRESULT hr; + + *pptinfo = NULL; + + // we only support one type element + if (0 != itinfo) { + return TYPE_E_ELEMENTNOTFOUND; + } + + // always look for neutral + if (NULL == m_pti) { + + LPLOADTYPELIB lpfnLoadTypeLib; + LPLOADREGTYPELIB lpfnLoadRegTypeLib; + ITypeLib *ptlib; + HINSTANCE hInst; + + static const char szTypeLib[] = "LoadTypeLib"; + static const char szRegTypeLib[] = "LoadRegTypeLib"; + static const WCHAR szControl[] = L"control.tlb"; + + // + // Try to get the Ole32Aut.dll module handle. + // + + hInst = LoadOLEAut32(); + if (hInst == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst, + szRegTypeLib); + if (lpfnLoadRegTypeLib == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + + hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0 + lcid, &ptlib); + + if (FAILED(hr)) { + + // attempt to load directly - this will fill the + // registry in if it finds it + + lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib); + if (lpfnLoadTypeLib == NULL) { + DWORD dwError = GetLastError(); + return AmHresultFromWin32(dwError); + } + + hr = (*lpfnLoadTypeLib)(szControl, &ptlib); + if (FAILED(hr)) { + return hr; + } + } + + hr = ptlib->GetTypeInfoOfGuid( + riid, + &m_pti); + + ptlib->Release(); + + if (FAILED(hr)) { + return hr; + } + } + + *pptinfo = m_pti; + m_pti->AddRef(); + return S_OK; +} + + +STDMETHODIMP +CBaseDispatch::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + // although the IDispatch riid is dead, we use this to pass from + // the interface implementation class to us the iid we are talking about. + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti); + + if (SUCCEEDED(hr)) { + hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid); + + pti->Release(); + } + return hr; +} + + +// --- CMediaControl implementation --------- + +CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + +// expose our interfaces IMediaControl and IUnknown + +STDMETHODIMP +CMediaControl::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaControl) { + return GetInterface( (IMediaControl *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaControl::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaControl::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaControl, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaControl::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaControl, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaControl::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaControl *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- CMediaEvent implementation ---------- + + +CMediaEvent::CMediaEvent(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + + +// expose our interfaces IMediaEvent and IUnknown + +STDMETHODIMP +CMediaEvent::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) { + return GetInterface( (IMediaEventEx *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaEvent::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaEvent::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaEvent, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaEvent::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaEvent, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaEvent::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaEvent *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- CMediaPosition implementation ---------- + + +CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : + CUnknown(name, pUnk) +{ +} + +CMediaPosition::CMediaPosition(__in_opt LPCTSTR name, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT * phr) : + CUnknown(name, pUnk) +{ + UNREFERENCED_PARAMETER(phr); +} + + +// expose our interfaces IMediaPosition and IUnknown + +STDMETHODIMP +CMediaPosition::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IMediaPosition) { + return GetInterface( (IMediaPosition *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// return 1 if we support GetTypeInfo + +STDMETHODIMP +CMediaPosition::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +// attempt to find our type library + +STDMETHODIMP +CMediaPosition::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IMediaPosition, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CMediaPosition::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IMediaPosition, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CMediaPosition::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IMediaPosition *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IMediaPosition and IMediaSeeking pass through class ---------- + + +CPosPassThru::CPosPassThru(__in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + IPin *pPin) : + CMediaPosition(pName,pUnk), + m_pPin(pPin) +{ + if (pPin == NULL) { + *phr = E_POINTER; + return; + } +} + + +// Expose our IMediaSeeking and IMediaPosition interfaces + +STDMETHODIMP +CPosPassThru::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) +{ + CheckPointer(ppv,E_POINTER); + *ppv = NULL; + + if (riid == IID_IMediaSeeking) { + return GetInterface( static_cast(this), ppv); + } + return CMediaPosition::NonDelegatingQueryInterface(riid,ppv); +} + + +// Return the IMediaPosition interface from our peer + +HRESULT +CPosPassThru::GetPeer(IMediaPosition ** ppMP) +{ + *ppMP = NULL; + + IPin *pConnected; + HRESULT hr = m_pPin->ConnectedTo(&pConnected); + if (FAILED(hr)) { + return E_NOTIMPL; + } + IMediaPosition * pMP; + hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP); + pConnected->Release(); + if (FAILED(hr)) { + return E_NOTIMPL; + } + + *ppMP = pMP; + return S_OK; +} + + +// Return the IMediaSeeking interface from our peer + +HRESULT +CPosPassThru::GetPeerSeeking(__deref_out IMediaSeeking ** ppMS) +{ + *ppMS = NULL; + + IPin *pConnected; + HRESULT hr = m_pPin->ConnectedTo(&pConnected); + if (FAILED(hr)) { + return E_NOTIMPL; + } + IMediaSeeking * pMS; + hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS); + pConnected->Release(); + if (FAILED(hr)) { + return E_NOTIMPL; + } + + *ppMS = pMS; + return S_OK; +} + + +// --- IMediaSeeking methods ---------- + + +STDMETHODIMP +CPosPassThru::GetCapabilities(__out DWORD * pCaps) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetCapabilities(pCaps); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::CheckCapabilities(__inout DWORD * pCaps) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->CheckCapabilities(pCaps); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::IsFormatSupported(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->IsFormatSupported(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::QueryPreferredFormat(__out GUID *pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->QueryPreferredFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetTimeFormat(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->SetTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetTimeFormat(__out GUID *pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::IsUsingTimeFormat(const GUID * pFormat) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->IsUsingTimeFormat(pFormat); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::ConvertTimeFormat(__out LONGLONG * pTarget, + __in_opt const GUID * pTargetFormat, + LONGLONG Source, + __in_opt const GUID * pSourceFormat ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat ); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetPositions( __inout_opt LONGLONG * pCurrent, + DWORD CurrentFlags, + __inout_opt LONGLONG * pStop, + DWORD StopFlags ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags ); + pMS->Release(); + return hr; +} + +STDMETHODIMP +CPosPassThru::GetPositions(__out_opt LONGLONG *pCurrent, __out_opt LONGLONG * pStop) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetPositions(pCurrent,pStop); + pMS->Release(); + return hr; +} + +HRESULT +CPosPassThru::GetSeekingLongLong +( HRESULT (__stdcall IMediaSeeking::*pMethod)( __out LONGLONG * ) +, LONGLONG * pll +) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (SUCCEEDED(hr)) + { + hr = (pMS->*pMethod)(pll); + pMS->Release(); + } + return hr; +} + +// If we don't have a current position then ask upstream + +STDMETHODIMP +CPosPassThru::GetCurrentPosition(__out LONGLONG *pCurrent) +{ + // Can we report the current position + HRESULT hr = GetMediaTime(pCurrent,NULL); + if (SUCCEEDED(hr)) hr = NOERROR; + else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent ); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetStopPosition(__out LONGLONG *pStop) +{ + return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop ); +} + +STDMETHODIMP +CPosPassThru::GetDuration(__out LONGLONG *pDuration) +{ + return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration ); +} + + +STDMETHODIMP +CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll) +{ + return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll ); +} + + +STDMETHODIMP +CPosPassThru::GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + + hr = pMS->GetAvailable( pEarliest, pLatest ); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::GetRate(__out double * pdRate) +{ + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + hr = pMS->GetRate(pdRate); + pMS->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::SetRate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + + IMediaSeeking* pMS; + HRESULT hr = GetPeerSeeking(&pMS); + if (FAILED(hr)) { + return hr; + } + hr = pMS->SetRate(dRate); + pMS->Release(); + return hr; +} + + + + +// --- IMediaPosition methods ---------- + + +STDMETHODIMP +CPosPassThru::get_Duration(__out REFTIME * plength) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + + hr = pMP->get_Duration(plength); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_CurrentPosition(__out REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_CurrentPosition(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_CurrentPosition(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_CurrentPosition(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_StopTime(__out REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_StopTime(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_StopTime(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_StopTime(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_PrerollTime(__out REFTIME * pllTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_PrerollTime(pllTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_PrerollTime(REFTIME llTime) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_PrerollTime(llTime); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::get_Rate(__out double * pdRate) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->get_Rate(pdRate); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::put_Rate(double dRate) +{ + if (0.0 == dRate) { + return E_INVALIDARG; + } + + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->put_Rate(dRate); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::CanSeekForward(__out LONG *pCanSeekForward) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->CanSeekForward(pCanSeekForward); + pMP->Release(); + return hr; +} + + +STDMETHODIMP +CPosPassThru::CanSeekBackward(__out LONG *pCanSeekBackward) +{ + IMediaPosition* pMP; + HRESULT hr = GetPeer(&pMP); + if (FAILED(hr)) { + return hr; + } + hr = pMP->CanSeekBackward(pCanSeekBackward); + pMP->Release(); + return hr; +} + + +// --- Implements the CRendererPosPassThru class ---------- + + +// Media times (eg current frame, field, sample etc) are passed through the +// filtergraph in media samples. When a renderer gets a sample with media +// times in it, it will call one of the RegisterMediaTime methods we expose +// (one takes an IMediaSample, the other takes the media times direct). We +// store the media times internally and return them in GetCurrentPosition. + +CRendererPosPassThru::CRendererPosPassThru(__in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + IPin *pPin) : + CPosPassThru(pName,pUnk,phr,pPin), + m_StartMedia(0), + m_EndMedia(0), + m_bReset(TRUE) +{ +} + + +// Sets the media times the object should report + +HRESULT +CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample) +{ + ASSERT(pMediaSample); + LONGLONG StartMedia; + LONGLONG EndMedia; + + CAutoLock cAutoLock(&m_PositionLock); + + // Get the media times from the sample + + HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia); + if (FAILED(hr)) + { + ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET); + return hr; + } + + m_StartMedia = StartMedia; + m_EndMedia = EndMedia; + m_bReset = FALSE; + return NOERROR; +} + + +// Sets the media times the object should report + +HRESULT +CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime) +{ + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = StartTime; + m_EndMedia = EndTime; + m_bReset = FALSE; + return NOERROR; +} + + +// Return the current media times registered in the object + +HRESULT +CRendererPosPassThru::GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) +{ + ASSERT(pStartTime); + + CAutoLock cAutoLock(&m_PositionLock); + if (m_bReset == TRUE) { + return E_FAIL; + } + + // We don't have to return the end time + + HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME ); + if (pEndTime && SUCCEEDED(hr)) { + hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME ); + } + return hr; +} + + +// Resets the media times we hold + +HRESULT +CRendererPosPassThru::ResetMediaTime() +{ + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = 0; + m_EndMedia = 0; + m_bReset = TRUE; + return NOERROR; +} + +// Intended to be called by the owing filter during EOS processing so +// that the media times can be adjusted to the stop time. This ensures +// that the GetCurrentPosition will actully get to the stop position. +HRESULT +CRendererPosPassThru::EOS() +{ + HRESULT hr; + + if ( m_bReset == TRUE ) hr = E_FAIL; + else + { + LONGLONG llStop; + if (SUCCEEDED(hr=GetStopPosition(&llStop))) + { + CAutoLock cAutoLock(&m_PositionLock); + m_StartMedia = + m_EndMedia = llStop; + } + } + return hr; +} + +// -- CSourceSeeking implementation ------------ + +CSourceSeeking::CSourceSeeking( + __in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT* phr, + __in CCritSec * pLock) : + CUnknown(pName, pUnk), + m_pLock(pLock), + m_rtStart((long)0) +{ + m_rtStop = _I64_MAX / 2; + m_rtDuration = m_rtStop; + m_dRateSeeking = 1.0; + + m_dwSeekingCaps = AM_SEEKING_CanSeekForwards + | AM_SEEKING_CanSeekBackwards + | AM_SEEKING_CanSeekAbsolute + | AM_SEEKING_CanGetStopPos + | AM_SEEKING_CanGetDuration; +} + +HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + if(riid == IID_IMediaSeeking) { + CheckPointer(ppv, E_POINTER); + return GetInterface(static_cast(this), ppv); + } + else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + // only seeking in time (REFERENCE_TIME units) is supported + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +HRESULT CSourceSeeking::QueryPreferredFormat(__out GUID *pFormat) +{ + CheckPointer(pFormat, E_POINTER); + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + + // nothing to set; just check that it's TIME_FORMAT_TIME + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG; +} + +HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat) +{ + CheckPointer(pFormat, E_POINTER); + return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; +} + +HRESULT CSourceSeeking::GetTimeFormat(__out GUID *pFormat) +{ + CheckPointer(pFormat, E_POINTER); + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT CSourceSeeking::GetDuration(__out LONGLONG *pDuration) +{ + CheckPointer(pDuration, E_POINTER); + CAutoLock lock(m_pLock); + *pDuration = m_rtDuration; + return S_OK; +} + +HRESULT CSourceSeeking::GetStopPosition(__out LONGLONG *pStop) +{ + CheckPointer(pStop, E_POINTER); + CAutoLock lock(m_pLock); + *pStop = m_rtStop; + return S_OK; +} + +HRESULT CSourceSeeking::GetCurrentPosition(__out LONGLONG *pCurrent) +{ + // GetCurrentPosition is typically supported only in renderers and + // not in source filters. + return E_NOTIMPL; +} + +HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities ) +{ + CheckPointer(pCapabilities, E_POINTER); + *pCapabilities = m_dwSeekingCaps; + return S_OK; +} + +HRESULT CSourceSeeking::CheckCapabilities( __inout DWORD * pCapabilities ) +{ + CheckPointer(pCapabilities, E_POINTER); + + // make sure all requested capabilities are in our mask + return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK; +} + +HRESULT CSourceSeeking::ConvertTimeFormat( __out LONGLONG * pTarget, + __in_opt const GUID * pTargetFormat, + LONGLONG Source, + __in_opt const GUID * pSourceFormat ) +{ + CheckPointer(pTarget, E_POINTER); + // format guids can be null to indicate current format + + // since we only support TIME_FORMAT_MEDIA_TIME, we don't really + // offer any conversions. + if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME) + { + if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME) + { + *pTarget = Source; + return S_OK; + } + } + + return E_INVALIDARG; +} + + +HRESULT CSourceSeeking::SetPositions( __inout_opt LONGLONG * pCurrent, + DWORD CurrentFlags, + __inout_opt LONGLONG * pStop, + DWORD StopFlags ) +{ + DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask; + DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask; + + if(StopFlags) { + CheckPointer(pStop, E_POINTER); + + // accept only relative, incremental, or absolute positioning + if(StopPosBits != StopFlags) { + return E_INVALIDARG; + } + } + + if(CurrentFlags) { + CheckPointer(pCurrent, E_POINTER); + if(StartPosBits != AM_SEEKING_AbsolutePositioning && + StartPosBits != AM_SEEKING_RelativePositioning) { + return E_INVALIDARG; + } + } + + + // scope for autolock + { + CAutoLock lock(m_pLock); + + // set start position + if(StartPosBits == AM_SEEKING_AbsolutePositioning) + { + m_rtStart = *pCurrent; + } + else if(StartPosBits == AM_SEEKING_RelativePositioning) + { + m_rtStart += *pCurrent; + } + + // set stop position + if(StopPosBits == AM_SEEKING_AbsolutePositioning) + { + m_rtStop = *pStop; + } + else if(StopPosBits == AM_SEEKING_IncrementalPositioning) + { + m_rtStop = m_rtStart + *pStop; + } + else if(StopPosBits == AM_SEEKING_RelativePositioning) + { + m_rtStop = m_rtStop + *pStop; + } + } + + + HRESULT hr = S_OK; + if(SUCCEEDED(hr) && StopPosBits) { + hr = ChangeStop(); + } + if(StartPosBits) { + hr = ChangeStart(); + } + + return hr; +} + + +HRESULT CSourceSeeking::GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ) +{ + if(pCurrent) { + *pCurrent = m_rtStart; + } + if(pStop) { + *pStop = m_rtStop; + } + + return S_OK; +} + + +HRESULT CSourceSeeking::GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ) +{ + if(pEarliest) { + *pEarliest = 0; + } + if(pLatest) { + CAutoLock lock(m_pLock); + *pLatest = m_rtDuration; + } + return S_OK; +} + +HRESULT CSourceSeeking::SetRate( double dRate) +{ + { + CAutoLock lock(m_pLock); + m_dRateSeeking = dRate; + } + return ChangeRate(); +} + +HRESULT CSourceSeeking::GetRate( __out double * pdRate) +{ + CheckPointer(pdRate, E_POINTER); + CAutoLock lock(m_pLock); + *pdRate = m_dRateSeeking; + return S_OK; +} + +HRESULT CSourceSeeking::GetPreroll(__out LONGLONG *pPreroll) +{ + CheckPointer(pPreroll, E_POINTER); + *pPreroll = 0; + return S_OK; +} + + + + + +// --- CSourcePosition implementation ---------- + + +CSourcePosition::CSourcePosition(__in_opt LPCTSTR pName, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT* phr, + __in CCritSec * pLock) : + CMediaPosition(pName, pUnk), + m_pLock(pLock), + m_Start(CRefTime((LONGLONG)0)) +{ + m_Stop = _I64_MAX; + m_Rate = 1.0; +} + + +STDMETHODIMP +CSourcePosition::get_Duration(__out REFTIME * plength) +{ + CheckPointer(plength,E_POINTER); + ValidateReadWritePtr(plength,sizeof(REFTIME)); + CAutoLock lock(m_pLock); + + *plength = m_Duration; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_CurrentPosition(REFTIME llTime) +{ + m_pLock->Lock(); + m_Start = llTime; + m_pLock->Unlock(); + + return ChangeStart(); +} + + +STDMETHODIMP +CSourcePosition::get_StopTime(__out REFTIME * pllTime) +{ + CheckPointer(pllTime,E_POINTER); + ValidateReadWritePtr(pllTime,sizeof(REFTIME)); + CAutoLock lock(m_pLock); + + *pllTime = m_Stop; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_StopTime(REFTIME llTime) +{ + m_pLock->Lock(); + m_Stop = llTime; + m_pLock->Unlock(); + + return ChangeStop(); +} + + +STDMETHODIMP +CSourcePosition::get_PrerollTime(__out REFTIME * pllTime) +{ + CheckPointer(pllTime,E_POINTER); + ValidateReadWritePtr(pllTime,sizeof(REFTIME)); + return E_NOTIMPL; +} + + +STDMETHODIMP +CSourcePosition::put_PrerollTime(REFTIME llTime) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP +CSourcePosition::get_Rate(__out double * pdRate) +{ + CheckPointer(pdRate,E_POINTER); + ValidateReadWritePtr(pdRate,sizeof(double)); + CAutoLock lock(m_pLock); + + *pdRate = m_Rate; + return S_OK; +} + + +STDMETHODIMP +CSourcePosition::put_Rate(double dRate) +{ + m_pLock->Lock(); + m_Rate = dRate; + m_pLock->Unlock(); + + return ChangeRate(); +} + + +// By default we can seek forwards + +STDMETHODIMP +CSourcePosition::CanSeekForward(__out LONG *pCanSeekForward) +{ + CheckPointer(pCanSeekForward,E_POINTER); + *pCanSeekForward = OATRUE; + return S_OK; +} + + +// By default we can seek backwards + +STDMETHODIMP +CSourcePosition::CanSeekBackward(__out LONG *pCanSeekBackward) +{ + CheckPointer(pCanSeekBackward,E_POINTER); + *pCanSeekBackward = OATRUE; + return S_OK; +} + + +// --- Implementation of CBasicAudio class ---------- + + +CBasicAudio::CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + +// overriden to publicise our interfaces + +STDMETHODIMP +CBasicAudio::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IBasicAudio) { + return GetInterface( (IBasicAudio *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBasicAudio::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IBasicAudio, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBasicAudio::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IBasicAudio, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBasicAudio::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IBasicAudio *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IVideoWindow implementation ---------- + +CBaseVideoWindow::CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + + +// overriden to publicise our interfaces + +STDMETHODIMP +CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IVideoWindow) { + return GetInterface( (IVideoWindow *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBaseVideoWindow::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IVideoWindow, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBaseVideoWindow::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IVideoWindow, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBaseVideoWindow::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IVideoWindow *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- IBasicVideo implementation ---------- + + +CBaseBasicVideo::CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : + CUnknown(pName, punk) +{ +} + + +// overriden to publicise our interfaces + +STDMETHODIMP +CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) { + return GetInterface( static_cast(this), ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +STDMETHODIMP +CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo) +{ + return m_basedisp.GetTypeInfoCount(pctinfo); +} + + +STDMETHODIMP +CBaseBasicVideo::GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo) +{ + return m_basedisp.GetTypeInfo( + IID_IBasicVideo, + itinfo, + lcid, + pptinfo); +} + + +STDMETHODIMP +CBaseBasicVideo::GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid) +{ + return m_basedisp.GetIDsOfNames( + IID_IBasicVideo, + rgszNames, + cNames, + lcid, + rgdispid); +} + + +STDMETHODIMP +CBaseBasicVideo::Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr) +{ + // this parameter is a dead leftover from an earlier interface + if (IID_NULL != riid) { + return DISP_E_UNKNOWNINTERFACE; + } + + ITypeInfo * pti; + HRESULT hr = GetTypeInfo(0, lcid, &pti); + + if (FAILED(hr)) { + return hr; + } + + hr = pti->Invoke( + (IBasicVideo *)this, + dispidMember, + wFlags, + pdispparams, + pvarResult, + pexcepinfo, + puArgErr); + + pti->Release(); + return hr; +} + + +// --- Implementation of Deferred Commands ---------- + + +CDispParams::CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr) +{ + cNamedArgs = 0; + rgdispidNamedArgs = NULL; + cArgs = nArgs; + + if (cArgs) { + rgvarg = new VARIANT[cArgs]; + if (NULL == rgvarg) { + cArgs = 0; + if (phr) { + *phr = E_OUTOFMEMORY; + } + return; + } + + for (UINT i = 0; i < cArgs; i++) { + + // Why aren't we using VariantCopy? + + VARIANT * pDest = &rgvarg[i]; + VARIANT * pSrc = &pArgs[i]; + + pDest->vt = pSrc->vt; + switch(pDest->vt) { + + case VT_I4: + pDest->lVal = pSrc->lVal; + break; + + case VT_UI1: + pDest->bVal = pSrc->bVal; + break; + + case VT_I2: + pDest->iVal = pSrc->iVal; + break; + + case VT_R4: + pDest->fltVal = pSrc->fltVal; + break; + + case VT_R8: + pDest->dblVal = pSrc->dblVal; + break; + + case VT_BOOL: + pDest->boolVal = pSrc->boolVal; + break; + + case VT_ERROR: + pDest->scode = pSrc->scode; + break; + + case VT_CY: + pDest->cyVal = pSrc->cyVal; + break; + + case VT_DATE: + pDest->date = pSrc->date; + break; + + case VT_BSTR: + if ((PVOID)pSrc->bstrVal == NULL) { + pDest->bstrVal = NULL; + } else { + + // a BSTR is a WORD followed by a UNICODE string. + // the pointer points just after the WORD + + WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR))); + OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))]; + if (pch) { + WORD *pui = (WORD*)pch; + *pui = len; + pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR)); + CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR)); + } else { + cArgs = i; + if (phr) { + *phr = E_OUTOFMEMORY; + } + } + } + break; + + case VT_UNKNOWN: + pDest->punkVal = pSrc->punkVal; + pDest->punkVal->AddRef(); + break; + + case VT_DISPATCH: + pDest->pdispVal = pSrc->pdispVal; + pDest->pdispVal->AddRef(); + break; + + default: + // a type we haven't got round to adding yet! + ASSERT(0); + break; + } + } + + } else { + rgvarg = NULL; + } + +} + + +CDispParams::~CDispParams() +{ + for (UINT i = 0; i < cArgs; i++) { + switch(rgvarg[i].vt) { + case VT_BSTR: + // Explicitly cast BSTR to PVOID to tell code scanning tools we really mean to test the pointer + if ((PVOID)rgvarg[i].bstrVal != NULL) { + OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR)); + delete pch; + } + break; + + case VT_UNKNOWN: + rgvarg[i].punkVal->Release(); + break; + + case VT_DISPATCH: + rgvarg[i].pdispVal->Release(); + break; + } + } + delete[] rgvarg; +} + + +// lifetime is controlled by refcounts (see defer.h) + +CDeferredCommand::CDeferredCommand( + __inout CCmdQueue * pQ, + __in_opt LPUNKNOWN pUnk, + __inout HRESULT * phr, + __in LPUNKNOWN pUnkExecutor, + REFTIME time, + __in GUID* iid, + long dispidMethod, + short wFlags, + long nArgs, + __in_ecount(nArgs) VARIANT* pDispParams, + __out VARIANT* pvarResult, + __out short* puArgErr, + BOOL bStream + ) : + CUnknown(NAME("DeferredCommand"), pUnk), + m_pQueue(pQ), + m_pUnk(pUnkExecutor), + m_iid(iid), + m_dispidMethod(dispidMethod), + m_wFlags(wFlags), + m_DispParams(nArgs, pDispParams, phr), + m_pvarResult(pvarResult), + m_bStream(bStream), + m_hrResult(E_ABORT), + m_DispId(0) + +{ + // convert REFTIME to REFERENCE_TIME + COARefTime convertor(time); + m_time = convertor; + + // no check of time validity - it's ok to queue a command that's + // already late + + // check iid is supportable on pUnk by QueryInterface for it + IUnknown * pInterface; + HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); + if (FAILED(hr)) { + *phr = hr; + return; + } + pInterface->Release(); + + + // !!! check dispidMethod and param/return types using typelib + ITypeInfo *pti; + hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti); + if (FAILED(hr)) { + *phr = hr; + return; + } + // !!! some sort of ITypeInfo validity check here + pti->Release(); + + + // Fix up the dispid for put and get + if (wFlags == DISPATCH_PROPERTYPUT) { + m_DispParams.cNamedArgs = 1; + m_DispId = DISPID_PROPERTYPUT; + m_DispParams.rgdispidNamedArgs = &m_DispId; + } + + // all checks ok - add to queue + hr = pQ->Insert(this); + if (FAILED(hr)) { + *phr = hr; + } +} + + +// refcounts are held by caller of InvokeAt... and by list. So if +// we get here, we can't be on the list + +#if 0 +CDeferredCommand::~CDeferredCommand() +{ + // this assert is invalid since if the queue is deleted while we are + // still on the queue, we will have been removed by the queue and this + // m_pQueue will not have been modified. + // ASSERT(m_pQueue == NULL); + + // we don't hold a ref count on pUnk, which is the object that should + // execute the command. + // This is because there would otherwise be a circular refcount problem + // since pUnk probably owns the CmdQueue object that has a refcount + // on us. + // The lifetime of pUnk is guaranteed by it being part of, or lifetime + // controlled by, our parent object. As long as we are on the list, pUnk + // must be valid. Once we are off the list, we do not use pUnk. + +} +#endif + + +// overriden to publicise our interfaces + +STDMETHODIMP +CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, __out void **ppv) +{ + ValidateReadWritePtr(ppv,sizeof(PVOID)); + if (riid == IID_IDeferredCommand) { + return GetInterface( (IDeferredCommand *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// remove from q. this will reduce the refcount by one (since the q +// holds a count) but can't make us go away since he must have a +// refcount in order to call this method. + +STDMETHODIMP +CDeferredCommand::Cancel() +{ + if (m_pQueue == NULL) { + return VFW_E_ALREADY_CANCELLED; + } + + HRESULT hr = m_pQueue->Remove(this); + if (FAILED(hr)) { + return hr; + } + + m_pQueue = NULL; + return S_OK; +} + + +STDMETHODIMP +CDeferredCommand::Confidence(__out LONG* pConfidence) +{ + return E_NOTIMPL; +} + + +STDMETHODIMP +CDeferredCommand::GetHResult(__out HRESULT * phrResult) +{ + CheckPointer(phrResult,E_POINTER); + ValidateReadWritePtr(phrResult,sizeof(HRESULT)); + + if (m_pQueue != NULL) { + return E_ABORT; + } + *phrResult = m_hrResult; + return S_OK; +} + + +// set the time to be a new time (checking that it is valid) and +// then requeue + +STDMETHODIMP +CDeferredCommand::Postpone(REFTIME newtime) +{ + + // check that this time is not past + // convert REFTIME to REFERENCE_TIME + COARefTime convertor(newtime); + + // check that the time has not passed + if (m_pQueue->CheckTime(convertor, IsStreamTime())) { + return VFW_E_TIME_ALREADY_PASSED; + } + + // extract from list + HRESULT hr = m_pQueue->Remove(this); + if (FAILED(hr)) { + return hr; + } + + // change time + m_time = convertor; + + // requeue + hr = m_pQueue->Insert(this); + + return hr; +} + + +HRESULT +CDeferredCommand::Invoke() +{ + // check that we are still outstanding + if (m_pQueue == NULL) { + return VFW_E_ALREADY_CANCELLED; + } + + // get the type info + ITypeInfo* pti; + HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti); + if (FAILED(hr)) { + return hr; + } + + // qi for the expected interface and then invoke it. Note that we have to + // treat the returned interface as IUnknown since we don't know its type. + IUnknown* pInterface; + + hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); + if (FAILED(hr)) { + pti->Release(); + return hr; + } + + EXCEPINFO expinfo; + UINT uArgErr; + m_hrResult = pti->Invoke( + pInterface, + GetMethod(), + GetFlags(), + GetParams(), + GetResult(), + &expinfo, + &uArgErr); + + // release the interface we QI'd for + pInterface->Release(); + pti->Release(); + + + // remove from list whether or not successful + // or we loop indefinitely + hr = m_pQueue->Remove(this); + m_pQueue = NULL; + return hr; +} + + + +// --- CCmdQueue methods ---------- + + +CCmdQueue::CCmdQueue(__inout_opt HRESULT *phr) : + m_listPresentation(NAME("Presentation time command list")), + m_listStream(NAME("Stream time command list")), + m_evDue(TRUE, phr), // manual reset + m_dwAdvise(0), + m_pClock(NULL), + m_bRunning(FALSE) +{ +} + + +CCmdQueue::~CCmdQueue() +{ + // empty all our lists + + // we hold a refcount on each, so traverse and Release each + // entry then RemoveAll to empty the list + POSITION pos = m_listPresentation.GetHeadPosition(); + + while(pos) { + CDeferredCommand* pCmd = m_listPresentation.GetNext(pos); + pCmd->Release(); + } + m_listPresentation.RemoveAll(); + + pos = m_listStream.GetHeadPosition(); + + while(pos) { + CDeferredCommand* pCmd = m_listStream.GetNext(pos); + pCmd->Release(); + } + m_listStream.RemoveAll(); + + if (m_pClock) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + m_dwAdvise = 0; + } + m_pClock->Release(); + } +} + + +// returns a new CDeferredCommand object that will be initialised with +// the parameters and will be added to the queue during construction. +// returns S_OK if successfully created otherwise an error and +// no object has been queued. + +HRESULT +CCmdQueue::New( + __out CDeferredCommand **ppCmd, + __in LPUNKNOWN pUnk, // this object will execute command + REFTIME time, + __in GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + __in_ecount(cArgs) VARIANT* pDispParams, + __out VARIANT* pvarResult, + __out short* puArgErr, + BOOL bStream +) +{ + CAutoLock lock(&m_Lock); + + HRESULT hr = S_OK; + *ppCmd = NULL; + + CDeferredCommand* pCmd; + pCmd = new CDeferredCommand( + this, + NULL, // not aggregated + &hr, + pUnk, // this guy will execute + time, + iid, + dispidMethod, + wFlags, + cArgs, + pDispParams, + pvarResult, + puArgErr, + bStream); + + if (pCmd == NULL) { + hr = E_OUTOFMEMORY; + } else { + *ppCmd = pCmd; + } + return hr; +} + + +HRESULT +CCmdQueue::Insert(__in CDeferredCommand* pCmd) +{ + CAutoLock lock(&m_Lock); + + // addref the item + pCmd->AddRef(); + + CGenericList * pList; + if (pCmd->IsStreamTime()) { + pList = &m_listStream; + } else { + pList = &m_listPresentation; + } + POSITION pos = pList->GetHeadPosition(); + + // seek past all items that are before us + while (pos && + (pList->GetValid(pos)->GetTime() <= pCmd->GetTime())) { + + pList->GetNext(pos); + } + + // now at end of list or in front of items that come later + if (!pos) { + pList->AddTail(pCmd); + } else { + pList->AddBefore(pos, pCmd); + } + + SetTimeAdvise(); + return S_OK; +} + + +HRESULT +CCmdQueue::Remove(__in CDeferredCommand* pCmd) +{ + CAutoLock lock(&m_Lock); + HRESULT hr = S_OK; + + CGenericList * pList; + if (pCmd->IsStreamTime()) { + pList = &m_listStream; + } else { + pList = &m_listPresentation; + } + POSITION pos = pList->GetHeadPosition(); + + // traverse the list + while (pos && (pList->GetValid(pos) != pCmd)) { + pList->GetNext(pos); + } + + // did we drop off the end? + if (!pos) { + hr = VFW_E_NOT_FOUND; + } else { + + // found it - now take off list + pList->Remove(pos); + + // Insert did an AddRef, so release it + pCmd->Release(); + + // check that timer request is still for earliest time + SetTimeAdvise(); + } + return hr; +} + + +// set the clock used for timing + +HRESULT +CCmdQueue::SetSyncSource(__in_opt IReferenceClock* pClock) +{ + CAutoLock lock(&m_Lock); + + // addref the new clock first in case they are the same + if (pClock) { + pClock->AddRef(); + } + + // kill any advise on the old clock + if (m_pClock) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + m_dwAdvise = 0; + } + m_pClock->Release(); + } + m_pClock = pClock; + + // set up a new advise + SetTimeAdvise(); + return S_OK; +} + + +// set up a timer event with the reference clock + +void +CCmdQueue::SetTimeAdvise(void) +{ + // make sure we have a clock to use + if (!m_pClock) { + return; + } + + // reset the event whenever we are requesting a new signal + m_evDue.Reset(); + + // time 0 is earliest + CRefTime current; + + // find the earliest presentation time + POSITION pos = m_listPresentation.GetHeadPosition(); + if (pos != NULL) { + current = m_listPresentation.GetValid(pos)->GetTime(); + } + + // if we're running, check the stream times too + if (m_bRunning) { + + CRefTime t; + pos = m_listStream.GetHeadPosition(); + if (NULL != pos) { + t = m_listStream.GetValid(pos)->GetTime(); + + // add on stream time offset to get presentation time + t += m_StreamTimeOffset; + + // is this earlier? + if ((current == TimeZero) || (t < current)) { + current = t; + } + } + } + + // need to change? + if ((current > TimeZero) && (current != m_tCurrentAdvise)) { + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + // reset the event whenever we are requesting a new signal + m_evDue.Reset(); + } + + // ask for time advice - the first two params are either + // stream time offset and stream time or + // presentation time and 0. we always use the latter + HRESULT hr = m_pClock->AdviseTime( + (REFERENCE_TIME)current, + TimeZero, + (HEVENT) HANDLE(m_evDue), + &m_dwAdvise); + + ASSERT(SUCCEEDED(hr)); + UNREFERENCED_PARAMETER(hr); + m_tCurrentAdvise = current; + } +} + + +// switch to run mode. Streamtime to Presentation time mapping known. + +HRESULT +CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset) +{ + CAutoLock lock(&m_Lock); + + m_StreamTimeOffset = tStreamTimeOffset; + m_bRunning = TRUE; + + // ensure advise is accurate + SetTimeAdvise(); + return S_OK; +} + + +// switch to Stopped or Paused mode. Time mapping not known. + +HRESULT +CCmdQueue::EndRun() +{ + CAutoLock lock(&m_Lock); + + m_bRunning = FALSE; + + // check timer setting - stream times + SetTimeAdvise(); + return S_OK; +} + + +// return a pointer to the next due command. Blocks for msTimeout +// milliseconds until there is a due command. +// Stream-time commands will only become due between Run and Endrun calls. +// The command remains queued until invoked or cancelled. +// Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). +// +// returns an AddRef'd object + +HRESULT +CCmdQueue::GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout) +{ + // loop until we timeout or find a due command + for (;;) { + + { + CAutoLock lock(&m_Lock); + + + // find the earliest command + CDeferredCommand * pCmd = NULL; + + // check the presentation time and the + // stream time list to find the earliest + + POSITION pos = m_listPresentation.GetHeadPosition(); + + if (NULL != pos) { + pCmd = m_listPresentation.GetValid(pos); + } + + if (m_bRunning) { + pos = m_listStream.GetHeadPosition(); + if (NULL != pos) { + CDeferredCommand* pStrm = m_listStream.GetValid(pos); + + CRefTime t = pStrm->GetTime() + m_StreamTimeOffset; + if (!pCmd || (t < pCmd->GetTime())) { + pCmd = pStrm; + } + } + } + + // if we have found one, is it due? + if (pCmd) { + if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) { + + // yes it's due - addref it + pCmd->AddRef(); + *ppCmd = pCmd; + return S_OK; + } + } + } + + // block until the advise is signalled + if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) { + return E_ABORT; + } + } +} + + +// return a pointer to a command that will be due for a given time. +// Pass in a stream time here. The stream time offset will be passed +// in via the Run method. +// Commands remain queued until invoked or cancelled. +// This method will not block. It will report E_ABORT if there are no +// commands due yet. +// +// returns an AddRef'd object + +HRESULT +CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, __out CDeferredCommand**ppCmd) +{ + CAutoLock lock(&m_Lock); + + CRefTime tStream(rtStream); + + // find the earliest stream and presentation time commands + CDeferredCommand* pStream = NULL; + POSITION pos = m_listStream.GetHeadPosition(); + if (NULL != pos) { + pStream = m_listStream.GetValid(pos); + } + CDeferredCommand* pPresent = NULL; + pos = m_listPresentation.GetHeadPosition(); + if (NULL != pos) { + pPresent = m_listPresentation.GetValid(pos); + } + + // is there a presentation time that has passed already + if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) { + pPresent->AddRef(); + *ppCmd = pPresent; + return S_OK; + } + + // is there a stream time command due before this stream time + if (pStream && (pStream->GetTime() <= tStream)) { + pStream->AddRef(); + *ppCmd = pStream; + return S_OK; + } + + // if we are running, we can map presentation times to + // stream time. In this case, is there a presentation time command + // that will be due before this stream time is presented? + if (m_bRunning && pPresent) { + + // this stream time will appear at... + tStream += m_StreamTimeOffset; + + // due before that? + if (pPresent->GetTime() <= tStream) { + *ppCmd = pPresent; + return S_OK; + } + } + + // no commands due yet + return VFW_E_NOT_FOUND; +} + diff --git a/src/thirdparty/BaseClasses/ctlutil.h b/src/thirdparty/BaseClasses/ctlutil.h index 0c6665ef2e0..79af5e1df23 100644 --- a/src/thirdparty/BaseClasses/ctlutil.h +++ b/src/thirdparty/BaseClasses/ctlutil.h @@ -1,923 +1,923 @@ -//------------------------------------------------------------------------------ -// File: CtlUtil.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Base classes implementing IDispatch parsing for the basic control dual -// interfaces. Derive from these and implement just the custom method and -// property methods. We also implement CPosPassThru that can be used by -// renderers and transforms to pass by IMediaPosition and IMediaSeeking - -#ifndef __CTLUTIL__ -#define __CTLUTIL__ - -// OLE Automation has different ideas of TRUE and FALSE - -#define OATRUE (-1) -#define OAFALSE (0) - - -// It's possible that we could replace this class with CreateStdDispatch - -class CBaseDispatch -{ - ITypeInfo * m_pti; - -public: - - CBaseDispatch() : m_pti(NULL) {} - ~CBaseDispatch(); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - REFIID riid, - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); -}; - - -class AM_NOVTABLE CMediaControl : - public IMediaControl, - public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CMediaControl(const TCHAR *, LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); -}; - - -class AM_NOVTABLE CMediaEvent : - public IMediaEventEx, - public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CMediaEvent(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); -}; - - -class AM_NOVTABLE CMediaPosition : - public IMediaPosition, - public CUnknown -{ - CBaseDispatch m_basedisp; - - -public: - - CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT *phr); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); - -}; - - -// OA-compatibility means that we must use double as the RefTime value, -// and REFERENCE_TIME (essentially a LONGLONG) within filters. -// this class converts between the two - -class COARefTime : public CRefTime { -public: - - COARefTime() { - }; - - COARefTime(CRefTime t) - : CRefTime(t) - { - }; - - COARefTime(REFERENCE_TIME t) - : CRefTime(t) - { - }; - - COARefTime(double d) { - m_time = (LONGLONG) (d * 10000000); - }; - - operator double() { - return double(m_time) / 10000000; - }; - - operator REFERENCE_TIME() { - return m_time; - }; - - COARefTime& operator=(const double& rd) { - m_time = (LONGLONG) (rd * 10000000); - return *this; - } - - COARefTime& operator=(const REFERENCE_TIME& rt) { - m_time = rt; - return *this; - } - - inline BOOL operator==(const COARefTime& rt) - { - return m_time == rt.m_time; - }; - - inline BOOL operator!=(const COARefTime& rt) - { - return m_time != rt.m_time; - }; - - inline BOOL operator < (const COARefTime& rt) - { - return m_time < rt.m_time; - }; - - inline BOOL operator > (const COARefTime& rt) - { - return m_time > rt.m_time; - }; - - inline BOOL operator >= (const COARefTime& rt) - { - return m_time >= rt.m_time; - }; - - inline BOOL operator <= (const COARefTime& rt) - { - return m_time <= rt.m_time; - }; - - inline COARefTime operator+(const COARefTime& rt) - { - return COARefTime(m_time + rt.m_time); - }; - - inline COARefTime operator-(const COARefTime& rt) - { - return COARefTime(m_time - rt.m_time); - }; - - inline COARefTime operator*(LONG l) - { - return COARefTime(m_time * l); - }; - - inline COARefTime operator/(LONG l) - { - return COARefTime(m_time / l); - }; - -private: - // Prevent bugs from constructing from LONG (which gets - // converted to double and then multiplied by 10000000 - COARefTime(LONG); - LONG operator=(LONG); -}; - - -// A utility class that handles IMediaPosition and IMediaSeeking on behalf -// of single-input pin renderers, or transform filters. -// -// Renderers will expose this from the filter; transform filters will -// expose it from the output pin and not the renderer. -// -// Create one of these, giving it your IPin* for your input pin, and delegate -// all IMediaPosition methods to it. It will query the input pin for -// IMediaPosition and respond appropriately. -// -// Call ForceRefresh if the pin connection changes. -// -// This class no longer caches the upstream IMediaPosition or IMediaSeeking -// it acquires it on each method call. This means ForceRefresh is not needed. -// The method is kept for source compatibility and to minimise the changes -// if we need to put it back later for performance reasons. - -class CPosPassThru : public IMediaSeeking, public CMediaPosition -{ - IPin *m_pPin; - - HRESULT GetPeer(__deref_out IMediaPosition **ppMP); - HRESULT GetPeerSeeking(__deref_out IMediaSeeking **ppMS); - -public: - - CPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); - DECLARE_IUNKNOWN - - HRESULT ForceRefresh() { - return S_OK; - }; - - // override to return an accurate current position - virtual HRESULT GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) { - return E_FAIL; - } - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); - - // IMediaSeeking methods - STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); - STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); - STDMETHODIMP SetTimeFormat(const GUID * pFormat); - STDMETHODIMP GetTimeFormat(__out GUID *pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); - STDMETHODIMP IsFormatSupported( const GUID * pFormat); - STDMETHODIMP QueryPreferredFormat( __out GUID *pFormat); - STDMETHODIMP ConvertTimeFormat(__out LONGLONG * pTarget, - __in_opt const GUID * pTargetFormat, - LONGLONG Source, - __in_opt const GUID * pSourceFormat ); - STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags - , __inout_opt LONGLONG * pStop, DWORD StopFlags ); - - STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); - STDMETHODIMP GetCurrentPosition( __out LONGLONG * pCurrent ); - STDMETHODIMP GetStopPosition( __out LONGLONG * pStop ); - STDMETHODIMP SetRate( double dRate); - STDMETHODIMP GetRate( __out double * pdRate); - STDMETHODIMP GetDuration( __out LONGLONG *pDuration); - STDMETHODIMP GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ); - STDMETHODIMP GetPreroll( __out LONGLONG *pllPreroll ); - - // IMediaPosition properties - STDMETHODIMP get_Duration(__out REFTIME * plength); - STDMETHODIMP put_CurrentPosition(REFTIME llTime); - STDMETHODIMP get_StopTime(__out REFTIME * pllTime); - STDMETHODIMP put_StopTime(REFTIME llTime); - STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); - STDMETHODIMP put_PrerollTime(REFTIME llTime); - STDMETHODIMP get_Rate(__out double * pdRate); - STDMETHODIMP put_Rate(double dRate); - STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime); - STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); - STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); - -private: - HRESULT GetSeekingLongLong( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ), - __out LONGLONG * pll ); -}; - - -// Adds the ability to return a current position - -class CRendererPosPassThru : public CPosPassThru -{ - CCritSec m_PositionLock; // Locks access to our position - LONGLONG m_StartMedia; // Start media time last seen - LONGLONG m_EndMedia; // And likewise the end media - BOOL m_bReset; // Have media times been set - -public: - - // Used to help with passing media times through graph - - CRendererPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); - HRESULT RegisterMediaTime(IMediaSample *pMediaSample); - HRESULT RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime); - HRESULT GetMediaTime(__out LONGLONG *pStartTime,__out_opt LONGLONG *pEndTime); - HRESULT ResetMediaTime(); - HRESULT EOS(); -}; - -STDAPI CreatePosPassThru( - __in_opt LPUNKNOWN pAgg, - BOOL bRenderer, - IPin *pPin, - __deref_out IUnknown **ppPassThru -); - -// A class that handles the IDispatch part of IBasicAudio and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBasicAudio : public IBasicAudio, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBasicAudio(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); -}; - - -// A class that handles the IDispatch part of IBasicVideo and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBaseBasicVideo : public IBasicVideo2, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBaseBasicVideo(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); - - STDMETHODIMP GetPreferredAspectRatio( - __out long *plAspectX, - __out long *plAspectY) - { - return E_NOTIMPL; - } -}; - - -// A class that handles the IDispatch part of IVideoWindow and leaves the -// properties and methods themselves pure virtual. - -class AM_NOVTABLE CBaseVideoWindow : public IVideoWindow, public CUnknown -{ - CBaseDispatch m_basedisp; - -public: - - CBaseVideoWindow(__in_opt LPCTSTR, __in_opt LPUNKNOWN); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - /* IDispatch methods */ - STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); - - STDMETHODIMP GetTypeInfo( - UINT itinfo, - LCID lcid, - __deref_out ITypeInfo ** pptinfo); - - STDMETHODIMP GetIDsOfNames( - REFIID riid, - __in_ecount(cNames) LPOLESTR * rgszNames, - UINT cNames, - LCID lcid, - __out_ecount(cNames) DISPID * rgdispid); - - STDMETHODIMP Invoke( - DISPID dispidMember, - REFIID riid, - LCID lcid, - WORD wFlags, - __in DISPPARAMS * pdispparams, - __out_opt VARIANT * pvarResult, - __out_opt EXCEPINFO * pexcepinfo, - __out_opt UINT * puArgErr); -}; - - -// abstract class to help source filters with their implementation -// of IMediaPosition. Derive from this and set the duration (and stop -// position). Also override NotifyChange to do something when the properties -// change. - -class AM_NOVTABLE CSourcePosition : public CMediaPosition -{ - -public: - CSourcePosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); - - // IMediaPosition methods - STDMETHODIMP get_Duration(__out REFTIME * plength); - STDMETHODIMP put_CurrentPosition(REFTIME llTime); - STDMETHODIMP get_StopTime(__out REFTIME * pllTime); - STDMETHODIMP put_StopTime(REFTIME llTime); - STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); - STDMETHODIMP put_PrerollTime(REFTIME llTime); - STDMETHODIMP get_Rate(__out double * pdRate); - STDMETHODIMP put_Rate(double dRate); - STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); - STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); - - // override if you can return the data you are actually working on - STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime) { - return E_NOTIMPL; - }; - -protected: - - // we call this to notify changes. Override to handle them - virtual HRESULT ChangeStart() PURE; - virtual HRESULT ChangeStop() PURE; - virtual HRESULT ChangeRate() PURE; - - COARefTime m_Duration; - COARefTime m_Start; - COARefTime m_Stop; - double m_Rate; - - CCritSec * m_pLock; -}; - -class AM_NOVTABLE CSourceSeeking : - public IMediaSeeking, - public CUnknown -{ - -public: - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - // IMediaSeeking methods - - STDMETHODIMP IsFormatSupported(const GUID * pFormat); - STDMETHODIMP QueryPreferredFormat(__out GUID *pFormat); - STDMETHODIMP SetTimeFormat(const GUID * pFormat); - STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); - STDMETHODIMP GetTimeFormat(__out GUID *pFormat); - STDMETHODIMP GetDuration(__out LONGLONG *pDuration); - STDMETHODIMP GetStopPosition(__out LONGLONG *pStop); - STDMETHODIMP GetCurrentPosition(__out LONGLONG *pCurrent); - STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); - STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); - STDMETHODIMP ConvertTimeFormat( __out LONGLONG * pTarget, - __in_opt const GUID * pTargetFormat, - LONGLONG Source, - __in_opt const GUID * pSourceFormat ); - - STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags - , __inout_opt LONGLONG * pStop, DWORD StopFlags ); - - STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); - - STDMETHODIMP GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ); - STDMETHODIMP SetRate( double dRate); - STDMETHODIMP GetRate( __out double * pdRate); - STDMETHODIMP GetPreroll(__out LONGLONG *pPreroll); - - -protected: - - // ctor - CSourceSeeking(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); - - // we call this to notify changes. Override to handle them - virtual HRESULT ChangeStart() PURE; - virtual HRESULT ChangeStop() PURE; - virtual HRESULT ChangeRate() PURE; - - REFERENCE_TIME m_rtDuration; // length of stream - REFERENCE_TIME m_rtStart; // source will start here - REFERENCE_TIME m_rtStop; // source will stop here - double m_dRateSeeking; - - // seeking capabilities - DWORD m_dwSeekingCaps; - - CCritSec * m_pLock; -}; - - -// Base classes supporting Deferred commands. - -// Deferred commands are queued by calls to methods on the IQueueCommand -// interface, exposed by the filtergraph and by some filters. A successful -// call to one of these methods will return an IDeferredCommand interface -// representing the queued command. -// -// A CDeferredCommand object represents a single deferred command, and exposes -// the IDeferredCommand interface as well as other methods permitting time -// checks and actual execution. It contains a reference to the CCommandQueue -// object on which it is queued. -// -// CCommandQueue is a base class providing a queue of CDeferredCommand -// objects, and methods to add, remove, check status and invoke the queued -// commands. A CCommandQueue object would be part of an object that -// implemented IQueueCommand. - -class CCmdQueue; - -// take a copy of the params and store them. Release any allocated -// memory in destructor - -class CDispParams : public DISPPARAMS -{ -public: - CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr = NULL); - ~CDispParams(); -}; - - -// CDeferredCommand lifetime is controlled by refcounts. Caller of -// InvokeAt.. gets a refcounted interface pointer, and the CCmdQueue -// object also holds a refcount on us. Calling Cancel or Invoke takes -// us off the CCmdQueue and thus reduces the refcount by 1. Once taken -// off the queue we cannot be put back on the queue. - -class CDeferredCommand - : public CUnknown, - public IDeferredCommand -{ -public: - - CDeferredCommand( - __inout CCmdQueue * pQ, - __in_opt LPUNKNOWN pUnk, // aggregation outer unk - __inout HRESULT * phr, - __in LPUNKNOWN pUnkExecutor, // object that will execute this cmd - REFTIME time, - __in GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - __in_ecount(cArgs) VARIANT* pDispParams, - __out VARIANT* pvarResult, - __out short* puArgErr, - BOOL bStream - ); - - DECLARE_IUNKNOWN - - // override this to publicise our interfaces - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __out void **ppv); - - // IDeferredCommand methods - STDMETHODIMP Cancel(); - STDMETHODIMP Confidence( - __out LONG* pConfidence); - STDMETHODIMP Postpone( - REFTIME newtime); - STDMETHODIMP GetHResult( - __out HRESULT* phrResult); - - // other public methods - - HRESULT Invoke(); - - // access methods - - // returns TRUE if streamtime, FALSE if presentation time - BOOL IsStreamTime() { - return m_bStream; - }; - - CRefTime GetTime() { - return m_time; - }; - - REFIID GetIID() { - return *m_iid; - }; - - long GetMethod() { - return m_dispidMethod; - }; - - short GetFlags() { - return m_wFlags; - }; - - DISPPARAMS* GetParams() { - return &m_DispParams; - }; - - VARIANT* GetResult() { - return m_pvarResult; - }; - -protected: - - CCmdQueue* m_pQueue; - - // pUnk for the interface that we will execute the command on - LPUNKNOWN m_pUnk; - - // stored command data - REFERENCE_TIME m_time; - GUID* m_iid; - long m_dispidMethod; - short m_wFlags; - VARIANT* m_pvarResult; - BOOL m_bStream; - CDispParams m_DispParams; - DISPID m_DispId; // For get and put - - // we use this for ITypeInfo access - CBaseDispatch m_Dispatch; - - // save retval here - HRESULT m_hrResult; -}; - - -// a list of CDeferredCommand objects. this is a base class providing -// the basics of access to the list. If you want to use CDeferredCommand -// objects then your queue needs to be derived from this class. - -class AM_NOVTABLE CCmdQueue -{ -public: - CCmdQueue(__inout_opt HRESULT *phr = NULL); - virtual ~CCmdQueue(); - - // returns a new CDeferredCommand object that will be initialised with - // the parameters and will be added to the queue during construction. - // returns S_OK if successfully created otherwise an error and - // no object has been queued. - virtual HRESULT New( - __out CDeferredCommand **ppCmd, - __in LPUNKNOWN pUnk, - REFTIME time, - __in GUID* iid, - long dispidMethod, - short wFlags, - long cArgs, - __in_ecount(cArgs) VARIANT* pDispParams, - __out VARIANT* pvarResult, - __out short* puArgErr, - BOOL bStream - ); - - // called by the CDeferredCommand object to add and remove itself - // from the queue - virtual HRESULT Insert(__in CDeferredCommand* pCmd); - virtual HRESULT Remove(__in CDeferredCommand* pCmd); - - // Command-Due Checking - // - // There are two schemes of synchronisation: coarse and accurate. In - // coarse mode, you wait till the time arrives and then execute the cmd. - // In accurate mode, you wait until you are processing the sample that - // will appear at the time, and then execute the command. It's up to the - // filter which one it will implement. The filtergraph will always - // implement coarse mode for commands queued at the filtergraph. - // - // If you want coarse sync, you probably want to wait until there is a - // command due, and then execute it. You can do this by calling - // GetDueCommand. If you have several things to wait for, get the - // event handle from GetDueHandle() and when this is signalled then call - // GetDueCommand. Stream time will only advance between calls to Run and - // EndRun. Note that to avoid an extra thread there is no guarantee that - // if the handle is set there will be a command ready. Each time the - // event is signalled, call GetDueCommand (probably with a 0 timeout); - // This may return E_ABORT. - // - // If you want accurate sync, you must call GetCommandDueFor, passing - // as a parameter the stream time of the samples you are about to process. - // This will return: - // -- a stream-time command due at or before that stream time - // -- a presentation-time command due at or before the - // time that stream time will be presented (only between Run - // and EndRun calls, since outside of this, the mapping from - // stream time to presentation time is not known. - // -- any presentation-time command due now. - // This means that if you want accurate synchronisation on samples that - // might be processed during Paused mode, you need to use - // stream-time commands. - // - // In all cases, commands remain queued until Invoked or Cancelled. The - // setting and resetting of the event handle is managed entirely by this - // queue object. - - // set the clock used for timing - virtual HRESULT SetSyncSource(__in_opt IReferenceClock*); - - // switch to run mode. Streamtime to Presentation time mapping known. - virtual HRESULT Run(REFERENCE_TIME tStreamTimeOffset); - - // switch to Stopped or Paused mode. Time mapping not known. - virtual HRESULT EndRun(); - - // return a pointer to the next due command. Blocks for msTimeout - // milliseconds until there is a due command. - // Stream-time commands will only become due between Run and Endrun calls. - // The command remains queued until invoked or cancelled. - // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). - // Returns an AddRef-ed object - virtual HRESULT GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout); - - // return the event handle that will be signalled whenever - // there are deferred commands due for execution (when GetDueCommand - // will not block). - HANDLE GetDueHandle() { - return HANDLE(m_evDue); - }; - - // return a pointer to a command that will be due for a given time. - // Pass in a stream time here. The stream time offset will be passed - // in via the Run method. - // Commands remain queued until invoked or cancelled. - // This method will not block. It will report VFW_E_NOT_FOUND if there - // are no commands due yet. - // Returns an AddRef-ed object - virtual HRESULT GetCommandDueFor(REFERENCE_TIME tStream, __out CDeferredCommand**ppCmd); - - // check if a given time is due (TRUE if it is due yet) - BOOL CheckTime(CRefTime time, BOOL bStream) { - - // if no clock, nothing is due! - if (!m_pClock) { - return FALSE; - } - - // stream time - if (bStream) { - - // not valid if not running - if (!m_bRunning) { - return FALSE; - } - // add on known stream time offset to get presentation time - time += m_StreamTimeOffset; - } - - CRefTime Now; - m_pClock->GetTime((REFERENCE_TIME*)&Now); - return (time <= Now); - }; - -protected: - - // protect access to lists etc - CCritSec m_Lock; - - // commands queued in presentation time are stored here - CGenericList m_listPresentation; - - // commands queued in stream time are stored here - CGenericList m_listStream; - - // set when any commands are due - CAMEvent m_evDue; - - // creates an advise for the earliest time required, if any - void SetTimeAdvise(void); - - // advise id from reference clock (0 if no outstanding advise) - DWORD_PTR m_dwAdvise; - - // advise time is for this presentation time - CRefTime m_tCurrentAdvise; - - // the reference clock we are using (addrefed) - IReferenceClock* m_pClock; - - // true when running - BOOL m_bRunning; - - // contains stream time offset when m_bRunning is true - CRefTime m_StreamTimeOffset; -}; - -#endif // __CTLUTIL__ +//------------------------------------------------------------------------------ +// File: CtlUtil.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Base classes implementing IDispatch parsing for the basic control dual +// interfaces. Derive from these and implement just the custom method and +// property methods. We also implement CPosPassThru that can be used by +// renderers and transforms to pass by IMediaPosition and IMediaSeeking + +#ifndef __CTLUTIL__ +#define __CTLUTIL__ + +// OLE Automation has different ideas of TRUE and FALSE + +#define OATRUE (-1) +#define OAFALSE (0) + + +// It's possible that we could replace this class with CreateStdDispatch + +class CBaseDispatch +{ + ITypeInfo * m_pti; + +public: + + CBaseDispatch() : m_pti(NULL) {} + ~CBaseDispatch(); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + REFIID riid, + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); +}; + + +class AM_NOVTABLE CMediaControl : + public IMediaControl, + public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CMediaControl(const TCHAR *, LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); +}; + + +class AM_NOVTABLE CMediaEvent : + public IMediaEventEx, + public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CMediaEvent(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); +}; + + +class AM_NOVTABLE CMediaPosition : + public IMediaPosition, + public CUnknown +{ + CBaseDispatch m_basedisp; + + +public: + + CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT *phr); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); + +}; + + +// OA-compatibility means that we must use double as the RefTime value, +// and REFERENCE_TIME (essentially a LONGLONG) within filters. +// this class converts between the two + +class COARefTime : public CRefTime { +public: + + COARefTime() { + }; + + COARefTime(CRefTime t) + : CRefTime(t) + { + }; + + COARefTime(REFERENCE_TIME t) + : CRefTime(t) + { + }; + + COARefTime(double d) { + m_time = (LONGLONG) (d * 10000000); + }; + + operator double() { + return double(m_time) / 10000000; + }; + + operator REFERENCE_TIME() { + return m_time; + }; + + COARefTime& operator=(const double& rd) { + m_time = (LONGLONG) (rd * 10000000); + return *this; + } + + COARefTime& operator=(const REFERENCE_TIME& rt) { + m_time = rt; + return *this; + } + + inline BOOL operator==(const COARefTime& rt) + { + return m_time == rt.m_time; + }; + + inline BOOL operator!=(const COARefTime& rt) + { + return m_time != rt.m_time; + }; + + inline BOOL operator < (const COARefTime& rt) + { + return m_time < rt.m_time; + }; + + inline BOOL operator > (const COARefTime& rt) + { + return m_time > rt.m_time; + }; + + inline BOOL operator >= (const COARefTime& rt) + { + return m_time >= rt.m_time; + }; + + inline BOOL operator <= (const COARefTime& rt) + { + return m_time <= rt.m_time; + }; + + inline COARefTime operator+(const COARefTime& rt) + { + return COARefTime(m_time + rt.m_time); + }; + + inline COARefTime operator-(const COARefTime& rt) + { + return COARefTime(m_time - rt.m_time); + }; + + inline COARefTime operator*(LONG l) + { + return COARefTime(m_time * l); + }; + + inline COARefTime operator/(LONG l) + { + return COARefTime(m_time / l); + }; + +private: + // Prevent bugs from constructing from LONG (which gets + // converted to double and then multiplied by 10000000 + COARefTime(LONG); + LONG operator=(LONG); +}; + + +// A utility class that handles IMediaPosition and IMediaSeeking on behalf +// of single-input pin renderers, or transform filters. +// +// Renderers will expose this from the filter; transform filters will +// expose it from the output pin and not the renderer. +// +// Create one of these, giving it your IPin* for your input pin, and delegate +// all IMediaPosition methods to it. It will query the input pin for +// IMediaPosition and respond appropriately. +// +// Call ForceRefresh if the pin connection changes. +// +// This class no longer caches the upstream IMediaPosition or IMediaSeeking +// it acquires it on each method call. This means ForceRefresh is not needed. +// The method is kept for source compatibility and to minimise the changes +// if we need to put it back later for performance reasons. + +class CPosPassThru : public IMediaSeeking, public CMediaPosition +{ + IPin *m_pPin; + + HRESULT GetPeer(__deref_out IMediaPosition **ppMP); + HRESULT GetPeerSeeking(__deref_out IMediaSeeking **ppMS); + +public: + + CPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); + DECLARE_IUNKNOWN + + HRESULT ForceRefresh() { + return S_OK; + }; + + // override to return an accurate current position + virtual HRESULT GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) { + return E_FAIL; + } + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); + + // IMediaSeeking methods + STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); + STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); + STDMETHODIMP SetTimeFormat(const GUID * pFormat); + STDMETHODIMP GetTimeFormat(__out GUID *pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); + STDMETHODIMP IsFormatSupported( const GUID * pFormat); + STDMETHODIMP QueryPreferredFormat( __out GUID *pFormat); + STDMETHODIMP ConvertTimeFormat(__out LONGLONG * pTarget, + __in_opt const GUID * pTargetFormat, + LONGLONG Source, + __in_opt const GUID * pSourceFormat ); + STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags + , __inout_opt LONGLONG * pStop, DWORD StopFlags ); + + STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); + STDMETHODIMP GetCurrentPosition( __out LONGLONG * pCurrent ); + STDMETHODIMP GetStopPosition( __out LONGLONG * pStop ); + STDMETHODIMP SetRate( double dRate); + STDMETHODIMP GetRate( __out double * pdRate); + STDMETHODIMP GetDuration( __out LONGLONG *pDuration); + STDMETHODIMP GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ); + STDMETHODIMP GetPreroll( __out LONGLONG *pllPreroll ); + + // IMediaPosition properties + STDMETHODIMP get_Duration(__out REFTIME * plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(__out REFTIME * pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(__out double * pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime); + STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); + STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); + +private: + HRESULT GetSeekingLongLong( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ), + __out LONGLONG * pll ); +}; + + +// Adds the ability to return a current position + +class CRendererPosPassThru : public CPosPassThru +{ + CCritSec m_PositionLock; // Locks access to our position + LONGLONG m_StartMedia; // Start media time last seen + LONGLONG m_EndMedia; // And likewise the end media + BOOL m_bReset; // Have media times been set + +public: + + // Used to help with passing media times through graph + + CRendererPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); + HRESULT RegisterMediaTime(IMediaSample *pMediaSample); + HRESULT RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime); + HRESULT GetMediaTime(__out LONGLONG *pStartTime,__out_opt LONGLONG *pEndTime); + HRESULT ResetMediaTime(); + HRESULT EOS(); +}; + +STDAPI CreatePosPassThru( + __in_opt LPUNKNOWN pAgg, + BOOL bRenderer, + IPin *pPin, + __deref_out IUnknown **ppPassThru +); + +// A class that handles the IDispatch part of IBasicAudio and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBasicAudio : public IBasicAudio, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBasicAudio(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); +}; + + +// A class that handles the IDispatch part of IBasicVideo and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBaseBasicVideo : public IBasicVideo2, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBaseBasicVideo(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); + + STDMETHODIMP GetPreferredAspectRatio( + __out long *plAspectX, + __out long *plAspectY) + { + return E_NOTIMPL; + } +}; + + +// A class that handles the IDispatch part of IVideoWindow and leaves the +// properties and methods themselves pure virtual. + +class AM_NOVTABLE CBaseVideoWindow : public IVideoWindow, public CUnknown +{ + CBaseDispatch m_basedisp; + +public: + + CBaseVideoWindow(__in_opt LPCTSTR, __in_opt LPUNKNOWN); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + /* IDispatch methods */ + STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); + + STDMETHODIMP GetTypeInfo( + UINT itinfo, + LCID lcid, + __deref_out ITypeInfo ** pptinfo); + + STDMETHODIMP GetIDsOfNames( + REFIID riid, + __in_ecount(cNames) LPOLESTR * rgszNames, + UINT cNames, + LCID lcid, + __out_ecount(cNames) DISPID * rgdispid); + + STDMETHODIMP Invoke( + DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + __in DISPPARAMS * pdispparams, + __out_opt VARIANT * pvarResult, + __out_opt EXCEPINFO * pexcepinfo, + __out_opt UINT * puArgErr); +}; + + +// abstract class to help source filters with their implementation +// of IMediaPosition. Derive from this and set the duration (and stop +// position). Also override NotifyChange to do something when the properties +// change. + +class AM_NOVTABLE CSourcePosition : public CMediaPosition +{ + +public: + CSourcePosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); + + // IMediaPosition methods + STDMETHODIMP get_Duration(__out REFTIME * plength); + STDMETHODIMP put_CurrentPosition(REFTIME llTime); + STDMETHODIMP get_StopTime(__out REFTIME * pllTime); + STDMETHODIMP put_StopTime(REFTIME llTime); + STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); + STDMETHODIMP put_PrerollTime(REFTIME llTime); + STDMETHODIMP get_Rate(__out double * pdRate); + STDMETHODIMP put_Rate(double dRate); + STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); + STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); + + // override if you can return the data you are actually working on + STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime) { + return E_NOTIMPL; + }; + +protected: + + // we call this to notify changes. Override to handle them + virtual HRESULT ChangeStart() PURE; + virtual HRESULT ChangeStop() PURE; + virtual HRESULT ChangeRate() PURE; + + COARefTime m_Duration; + COARefTime m_Start; + COARefTime m_Stop; + double m_Rate; + + CCritSec * m_pLock; +}; + +class AM_NOVTABLE CSourceSeeking : + public IMediaSeeking, + public CUnknown +{ + +public: + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + // IMediaSeeking methods + + STDMETHODIMP IsFormatSupported(const GUID * pFormat); + STDMETHODIMP QueryPreferredFormat(__out GUID *pFormat); + STDMETHODIMP SetTimeFormat(const GUID * pFormat); + STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); + STDMETHODIMP GetTimeFormat(__out GUID *pFormat); + STDMETHODIMP GetDuration(__out LONGLONG *pDuration); + STDMETHODIMP GetStopPosition(__out LONGLONG *pStop); + STDMETHODIMP GetCurrentPosition(__out LONGLONG *pCurrent); + STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); + STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); + STDMETHODIMP ConvertTimeFormat( __out LONGLONG * pTarget, + __in_opt const GUID * pTargetFormat, + LONGLONG Source, + __in_opt const GUID * pSourceFormat ); + + STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags + , __inout_opt LONGLONG * pStop, DWORD StopFlags ); + + STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); + + STDMETHODIMP GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ); + STDMETHODIMP SetRate( double dRate); + STDMETHODIMP GetRate( __out double * pdRate); + STDMETHODIMP GetPreroll(__out LONGLONG *pPreroll); + + +protected: + + // ctor + CSourceSeeking(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); + + // we call this to notify changes. Override to handle them + virtual HRESULT ChangeStart() PURE; + virtual HRESULT ChangeStop() PURE; + virtual HRESULT ChangeRate() PURE; + + REFERENCE_TIME m_rtDuration; // length of stream + REFERENCE_TIME m_rtStart; // source will start here + REFERENCE_TIME m_rtStop; // source will stop here + double m_dRateSeeking; + + // seeking capabilities + DWORD m_dwSeekingCaps; + + CCritSec * m_pLock; +}; + + +// Base classes supporting Deferred commands. + +// Deferred commands are queued by calls to methods on the IQueueCommand +// interface, exposed by the filtergraph and by some filters. A successful +// call to one of these methods will return an IDeferredCommand interface +// representing the queued command. +// +// A CDeferredCommand object represents a single deferred command, and exposes +// the IDeferredCommand interface as well as other methods permitting time +// checks and actual execution. It contains a reference to the CCommandQueue +// object on which it is queued. +// +// CCommandQueue is a base class providing a queue of CDeferredCommand +// objects, and methods to add, remove, check status and invoke the queued +// commands. A CCommandQueue object would be part of an object that +// implemented IQueueCommand. + +class CCmdQueue; + +// take a copy of the params and store them. Release any allocated +// memory in destructor + +class CDispParams : public DISPPARAMS +{ +public: + CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr = NULL); + ~CDispParams(); +}; + + +// CDeferredCommand lifetime is controlled by refcounts. Caller of +// InvokeAt.. gets a refcounted interface pointer, and the CCmdQueue +// object also holds a refcount on us. Calling Cancel or Invoke takes +// us off the CCmdQueue and thus reduces the refcount by 1. Once taken +// off the queue we cannot be put back on the queue. + +class CDeferredCommand + : public CUnknown, + public IDeferredCommand +{ +public: + + CDeferredCommand( + __inout CCmdQueue * pQ, + __in_opt LPUNKNOWN pUnk, // aggregation outer unk + __inout HRESULT * phr, + __in LPUNKNOWN pUnkExecutor, // object that will execute this cmd + REFTIME time, + __in GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + __in_ecount(cArgs) VARIANT* pDispParams, + __out VARIANT* pvarResult, + __out short* puArgErr, + BOOL bStream + ); + + DECLARE_IUNKNOWN + + // override this to publicise our interfaces + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __out void **ppv); + + // IDeferredCommand methods + STDMETHODIMP Cancel(); + STDMETHODIMP Confidence( + __out LONG* pConfidence); + STDMETHODIMP Postpone( + REFTIME newtime); + STDMETHODIMP GetHResult( + __out HRESULT* phrResult); + + // other public methods + + HRESULT Invoke(); + + // access methods + + // returns TRUE if streamtime, FALSE if presentation time + BOOL IsStreamTime() { + return m_bStream; + }; + + CRefTime GetTime() { + return m_time; + }; + + REFIID GetIID() { + return *m_iid; + }; + + long GetMethod() { + return m_dispidMethod; + }; + + short GetFlags() { + return m_wFlags; + }; + + DISPPARAMS* GetParams() { + return &m_DispParams; + }; + + VARIANT* GetResult() { + return m_pvarResult; + }; + +protected: + + CCmdQueue* m_pQueue; + + // pUnk for the interface that we will execute the command on + LPUNKNOWN m_pUnk; + + // stored command data + REFERENCE_TIME m_time; + GUID* m_iid; + long m_dispidMethod; + short m_wFlags; + VARIANT* m_pvarResult; + BOOL m_bStream; + CDispParams m_DispParams; + DISPID m_DispId; // For get and put + + // we use this for ITypeInfo access + CBaseDispatch m_Dispatch; + + // save retval here + HRESULT m_hrResult; +}; + + +// a list of CDeferredCommand objects. this is a base class providing +// the basics of access to the list. If you want to use CDeferredCommand +// objects then your queue needs to be derived from this class. + +class AM_NOVTABLE CCmdQueue +{ +public: + CCmdQueue(__inout_opt HRESULT *phr = NULL); + virtual ~CCmdQueue(); + + // returns a new CDeferredCommand object that will be initialised with + // the parameters and will be added to the queue during construction. + // returns S_OK if successfully created otherwise an error and + // no object has been queued. + virtual HRESULT New( + __out CDeferredCommand **ppCmd, + __in LPUNKNOWN pUnk, + REFTIME time, + __in GUID* iid, + long dispidMethod, + short wFlags, + long cArgs, + __in_ecount(cArgs) VARIANT* pDispParams, + __out VARIANT* pvarResult, + __out short* puArgErr, + BOOL bStream + ); + + // called by the CDeferredCommand object to add and remove itself + // from the queue + virtual HRESULT Insert(__in CDeferredCommand* pCmd); + virtual HRESULT Remove(__in CDeferredCommand* pCmd); + + // Command-Due Checking + // + // There are two schemes of synchronisation: coarse and accurate. In + // coarse mode, you wait till the time arrives and then execute the cmd. + // In accurate mode, you wait until you are processing the sample that + // will appear at the time, and then execute the command. It's up to the + // filter which one it will implement. The filtergraph will always + // implement coarse mode for commands queued at the filtergraph. + // + // If you want coarse sync, you probably want to wait until there is a + // command due, and then execute it. You can do this by calling + // GetDueCommand. If you have several things to wait for, get the + // event handle from GetDueHandle() and when this is signalled then call + // GetDueCommand. Stream time will only advance between calls to Run and + // EndRun. Note that to avoid an extra thread there is no guarantee that + // if the handle is set there will be a command ready. Each time the + // event is signalled, call GetDueCommand (probably with a 0 timeout); + // This may return E_ABORT. + // + // If you want accurate sync, you must call GetCommandDueFor, passing + // as a parameter the stream time of the samples you are about to process. + // This will return: + // -- a stream-time command due at or before that stream time + // -- a presentation-time command due at or before the + // time that stream time will be presented (only between Run + // and EndRun calls, since outside of this, the mapping from + // stream time to presentation time is not known. + // -- any presentation-time command due now. + // This means that if you want accurate synchronisation on samples that + // might be processed during Paused mode, you need to use + // stream-time commands. + // + // In all cases, commands remain queued until Invoked or Cancelled. The + // setting and resetting of the event handle is managed entirely by this + // queue object. + + // set the clock used for timing + virtual HRESULT SetSyncSource(__in_opt IReferenceClock*); + + // switch to run mode. Streamtime to Presentation time mapping known. + virtual HRESULT Run(REFERENCE_TIME tStreamTimeOffset); + + // switch to Stopped or Paused mode. Time mapping not known. + virtual HRESULT EndRun(); + + // return a pointer to the next due command. Blocks for msTimeout + // milliseconds until there is a due command. + // Stream-time commands will only become due between Run and Endrun calls. + // The command remains queued until invoked or cancelled. + // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). + // Returns an AddRef-ed object + virtual HRESULT GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout); + + // return the event handle that will be signalled whenever + // there are deferred commands due for execution (when GetDueCommand + // will not block). + HANDLE GetDueHandle() { + return HANDLE(m_evDue); + }; + + // return a pointer to a command that will be due for a given time. + // Pass in a stream time here. The stream time offset will be passed + // in via the Run method. + // Commands remain queued until invoked or cancelled. + // This method will not block. It will report VFW_E_NOT_FOUND if there + // are no commands due yet. + // Returns an AddRef-ed object + virtual HRESULT GetCommandDueFor(REFERENCE_TIME tStream, __out CDeferredCommand**ppCmd); + + // check if a given time is due (TRUE if it is due yet) + BOOL CheckTime(CRefTime time, BOOL bStream) { + + // if no clock, nothing is due! + if (!m_pClock) { + return FALSE; + } + + // stream time + if (bStream) { + + // not valid if not running + if (!m_bRunning) { + return FALSE; + } + // add on known stream time offset to get presentation time + time += m_StreamTimeOffset; + } + + CRefTime Now; + m_pClock->GetTime((REFERENCE_TIME*)&Now); + return (time <= Now); + }; + +protected: + + // protect access to lists etc + CCritSec m_Lock; + + // commands queued in presentation time are stored here + CGenericList m_listPresentation; + + // commands queued in stream time are stored here + CGenericList m_listStream; + + // set when any commands are due + CAMEvent m_evDue; + + // creates an advise for the earliest time required, if any + void SetTimeAdvise(void); + + // advise id from reference clock (0 if no outstanding advise) + DWORD_PTR m_dwAdvise; + + // advise time is for this presentation time + CRefTime m_tCurrentAdvise; + + // the reference clock we are using (addrefed) + IReferenceClock* m_pClock; + + // true when running + BOOL m_bRunning; + + // contains stream time offset when m_bRunning is true + CRefTime m_StreamTimeOffset; +}; + +#endif // __CTLUTIL__ diff --git a/src/thirdparty/BaseClasses/ddmm.cpp b/src/thirdparty/BaseClasses/ddmm.cpp index 79b8a093758..0bcdeb944d8 100644 --- a/src/thirdparty/BaseClasses/ddmm.cpp +++ b/src/thirdparty/BaseClasses/ddmm.cpp @@ -1,129 +1,129 @@ -//------------------------------------------------------------------------------ -// File: DDMM.cpp -// -// Desc: DirectShow base classes - implements routines for using DirectDraw -// on a multimonitor system. -// -// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include -#include "ddmm.h" - -/* - * FindDeviceCallback - */ -typedef struct { - LPSTR szDevice; - GUID* lpGUID; - GUID GUID; - BOOL fFound; -} FindDeviceData; - -BOOL CALLBACK FindDeviceCallback(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam) -{ - FindDeviceData *p = (FindDeviceData*)lParam; - - if (lstrcmpiA(p->szDevice, szDevice) == 0) { - if (lpGUID) { - p->GUID = *lpGUID; - p->lpGUID = &p->GUID; - } else { - p->lpGUID = NULL; - } - p->fFound = TRUE; - return FALSE; - } - return TRUE; -} - - -BOOL CALLBACK FindDeviceCallbackEx(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam, HMONITOR hMonitor) -{ - FindDeviceData *p = (FindDeviceData*)lParam; - - if (lstrcmpiA(p->szDevice, szDevice) == 0) { - if (lpGUID) { - p->GUID = *lpGUID; - p->lpGUID = &p->GUID; - } else { - p->lpGUID = NULL; - } - p->fFound = TRUE; - return FALSE; - } - return TRUE; -} - - -/* - * DirectDrawCreateFromDevice - * - * create a DirectDraw object for a particular device - */ -IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) -{ - IDirectDraw* pdd = NULL; - FindDeviceData find; - - if (szDevice == NULL) { - DirectDrawCreateP(NULL, &pdd, NULL); - return pdd; - } - - find.szDevice = szDevice; - find.fFound = FALSE; - DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find); - - if (find.fFound) - { - // - // In 4bpp mode the following DDraw call causes a message box to be popped - // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we - // make sure it doesn't happen. - // - UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - DirectDrawCreateP(find.lpGUID, &pdd, NULL); - SetErrorMode(ErrorMode); - } - - return pdd; -} - - -/* - * DirectDrawCreateFromDeviceEx - * - * create a DirectDraw object for a particular device - */ -IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) -{ - IDirectDraw* pdd = NULL; - FindDeviceData find; - - if (szDevice == NULL) { - DirectDrawCreateP(NULL, &pdd, NULL); - return pdd; - } - - find.szDevice = szDevice; - find.fFound = FALSE; - DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find, - DDENUM_ATTACHEDSECONDARYDEVICES); - - if (find.fFound) - { - // - // In 4bpp mode the following DDraw call causes a message box to be popped - // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we - // make sure it doesn't happen. - // - UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - DirectDrawCreateP(find.lpGUID, &pdd, NULL); - SetErrorMode(ErrorMode); - } - - return pdd; -} +//------------------------------------------------------------------------------ +// File: DDMM.cpp +// +// Desc: DirectShow base classes - implements routines for using DirectDraw +// on a multimonitor system. +// +// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include +#include "ddmm.h" + +/* + * FindDeviceCallback + */ +typedef struct { + LPSTR szDevice; + GUID* lpGUID; + GUID GUID; + BOOL fFound; +} FindDeviceData; + +BOOL CALLBACK FindDeviceCallback(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam) +{ + FindDeviceData *p = (FindDeviceData*)lParam; + + if (lstrcmpiA(p->szDevice, szDevice) == 0) { + if (lpGUID) { + p->GUID = *lpGUID; + p->lpGUID = &p->GUID; + } else { + p->lpGUID = NULL; + } + p->fFound = TRUE; + return FALSE; + } + return TRUE; +} + + +BOOL CALLBACK FindDeviceCallbackEx(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam, HMONITOR hMonitor) +{ + FindDeviceData *p = (FindDeviceData*)lParam; + + if (lstrcmpiA(p->szDevice, szDevice) == 0) { + if (lpGUID) { + p->GUID = *lpGUID; + p->lpGUID = &p->GUID; + } else { + p->lpGUID = NULL; + } + p->fFound = TRUE; + return FALSE; + } + return TRUE; +} + + +/* + * DirectDrawCreateFromDevice + * + * create a DirectDraw object for a particular device + */ +IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) +{ + IDirectDraw* pdd = NULL; + FindDeviceData find; + + if (szDevice == NULL) { + DirectDrawCreateP(NULL, &pdd, NULL); + return pdd; + } + + find.szDevice = szDevice; + find.fFound = FALSE; + DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find); + + if (find.fFound) + { + // + // In 4bpp mode the following DDraw call causes a message box to be popped + // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we + // make sure it doesn't happen. + // + UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + DirectDrawCreateP(find.lpGUID, &pdd, NULL); + SetErrorMode(ErrorMode); + } + + return pdd; +} + + +/* + * DirectDrawCreateFromDeviceEx + * + * create a DirectDraw object for a particular device + */ +IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) +{ + IDirectDraw* pdd = NULL; + FindDeviceData find; + + if (szDevice == NULL) { + DirectDrawCreateP(NULL, &pdd, NULL); + return pdd; + } + + find.szDevice = szDevice; + find.fFound = FALSE; + DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find, + DDENUM_ATTACHEDSECONDARYDEVICES); + + if (find.fFound) + { + // + // In 4bpp mode the following DDraw call causes a message box to be popped + // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we + // make sure it doesn't happen. + // + UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + DirectDrawCreateP(find.lpGUID, &pdd, NULL); + SetErrorMode(ErrorMode); + } + + return pdd; +} diff --git a/src/thirdparty/BaseClasses/ddmm.h b/src/thirdparty/BaseClasses/ddmm.h index c773d58891d..7b311bc101e 100644 --- a/src/thirdparty/BaseClasses/ddmm.h +++ b/src/thirdparty/BaseClasses/ddmm.h @@ -1,28 +1,28 @@ -//------------------------------------------------------------------------------ -// File: DDMM.h -// -// Desc: DirectShow base classes - efines routines for using DirectDraw -// on a multimonitor system. -// -// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifdef __cplusplus -extern "C" { /* Assume C declarations for C++ */ -#endif /* __cplusplus */ - -// DDRAW.H might not include these -#ifndef DDENUM_ATTACHEDSECONDARYDEVICES -#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L -#endif - -typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN); -typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID); - -IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR, PDRAWCREATE, PDRAWENUM); -IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +//------------------------------------------------------------------------------ +// File: DDMM.h +// +// Desc: DirectShow base classes - efines routines for using DirectDraw +// on a multimonitor system. +// +// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +// DDRAW.H might not include these +#ifndef DDENUM_ATTACHEDSECONDARYDEVICES +#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L +#endif + +typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN); +typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID); + +IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR, PDRAWCREATE, PDRAWENUM); +IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/src/thirdparty/BaseClasses/dllentry.cpp b/src/thirdparty/BaseClasses/dllentry.cpp index f6d46da9010..6424f27f445 100644 --- a/src/thirdparty/BaseClasses/dllentry.cpp +++ b/src/thirdparty/BaseClasses/dllentry.cpp @@ -1,365 +1,365 @@ -//------------------------------------------------------------------------------ -// File: DlleEntry.cpp -// -// Desc: DirectShow base classes - implements classes used to support dll -// entry points for COM objects. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -#ifdef _DEBUG -#ifdef UNICODE -#ifndef _UNICODE -#define _UNICODE -#endif // _UNICODE -#endif // UNICODE - -#include -#endif // DEBUG -#include - -extern CFactoryTemplate g_Templates[]; -extern int g_cTemplates; - -HINSTANCE g_hInst; -DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx) -OSVERSIONINFO g_osInfo; - -// -// an instance of this is created by the DLLGetClassObject entrypoint -// it uses the CFactoryTemplate object it is given to support the -// IClassFactory interface - -class CClassFactory : public IClassFactory, public CBaseObject -{ - -private: - const CFactoryTemplate *const m_pTemplate; - - ULONG m_cRef; - - static int m_cLocked; -public: - CClassFactory(const CFactoryTemplate *); - - // IUnknown - STDMETHODIMP QueryInterface(REFIID riid, __deref_out void ** ppv); - STDMETHODIMP_(ULONG)AddRef(); - STDMETHODIMP_(ULONG)Release(); - - // IClassFactory - STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, __deref_out void **pv); - STDMETHODIMP LockServer(BOOL fLock); - - // allow DLLGetClassObject to know about global server lock status - static BOOL IsLocked() { - return (m_cLocked > 0); - }; -}; - -// process-wide dll locked state -int CClassFactory::m_cLocked = 0; - -CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate) -: CBaseObject(NAME("Class Factory")) -, m_cRef(0) -, m_pTemplate(pTemplate) -{ -} - - -STDMETHODIMP -CClassFactory::QueryInterface(REFIID riid,__deref_out void **ppv) -{ - CheckPointer(ppv,E_POINTER) - ValidateReadWritePtr(ppv,sizeof(PVOID)); - *ppv = NULL; - - // any interface on this object is the object pointer. - if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) { - *ppv = (LPVOID) this; - // AddRef returned interface pointer - ((LPUNKNOWN) *ppv)->AddRef(); - return NOERROR; - } - - return ResultFromScode(E_NOINTERFACE); -} - - -STDMETHODIMP_(ULONG) -CClassFactory::AddRef() -{ - return ++m_cRef; -} - -STDMETHODIMP_(ULONG) -CClassFactory::Release() -{ - LONG lRef = InterlockedDecrement((volatile LONG *)&m_cRef); - if (lRef == 0) { - delete this; - return 0; - } else { - return lRef; - } -} - -STDMETHODIMP -CClassFactory::CreateInstance( - LPUNKNOWN pUnkOuter, - REFIID riid, - __deref_out void **pv) -{ - CheckPointer(pv,E_POINTER) - ValidateReadWritePtr(pv,sizeof(void *)); - *pv = NULL; - - /* Enforce the normal OLE rules regarding interfaces and delegation */ - - if (pUnkOuter != NULL) { - if (IsEqualIID(riid,IID_IUnknown) == FALSE) { - *pv = NULL; - return ResultFromScode(E_NOINTERFACE); - } - } - - /* Create the new object through the derived class's create function */ - - HRESULT hr = NOERROR; - CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr); - - if (pObj == NULL) { - *pv = NULL; - if (SUCCEEDED(hr)) { - hr = E_OUTOFMEMORY; - } - return hr; - } - - /* Delete the object if we got a construction error */ - - if (FAILED(hr)) { - delete pObj; - *pv = NULL; - return hr; - } - - /* Get a reference counted interface on the object */ - - /* We wrap the non-delegating QI with NDAddRef & NDRelease. */ - /* This protects any outer object from being prematurely */ - /* released by an inner object that may have to be created */ - /* in order to supply the requested interface. */ - pObj->NonDelegatingAddRef(); - hr = pObj->NonDelegatingQueryInterface(riid, pv); - pObj->NonDelegatingRelease(); - /* Note that if NonDelegatingQueryInterface fails, it will */ - /* not increment the ref count, so the NonDelegatingRelease */ - /* will drop the ref back to zero and the object will "self-*/ - /* destruct". Hence we don't need additional tidy-up code */ - /* to cope with NonDelegatingQueryInterface failing. */ - - if (SUCCEEDED(hr)) { - ASSERT(*pv); - } - - return hr; -} - -STDMETHODIMP -CClassFactory::LockServer(BOOL fLock) -{ - if (fLock) { - m_cLocked++; - } else { - m_cLocked--; - } - return NOERROR; -} - - -// --- COM entrypoints ----------------------------------------- - -//called by COM to get the class factory object for a given class -__control_entrypoint(DllExport) STDAPI -DllGetClassObject( - __in REFCLSID rClsID, - __in REFIID riid, - __deref_out void **pv) -{ - *pv = NULL; - if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) { - return E_NOINTERFACE; - } - - // traverse the array of templates looking for one with this - // class id - for (int i = 0; i < g_cTemplates; i++) { - const CFactoryTemplate * pT = &g_Templates[i]; - if (pT->IsClassID(rClsID)) { - - // found a template - make a class factory based on this - // template - - *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT); - if (*pv == NULL) { - return E_OUTOFMEMORY; - } - ((LPUNKNOWN)*pv)->AddRef(); - return NOERROR; - } - } - return CLASS_E_CLASSNOTAVAILABLE; -} - -// -// Call any initialization routines -// -void -DllInitClasses(BOOL bLoading) -{ - int i; - - // traverse the array of templates calling the init routine - // if they have one - for (i = 0; i < g_cTemplates; i++) { - const CFactoryTemplate * pT = &g_Templates[i]; - if (pT->m_lpfnInit != NULL) { - (*pT->m_lpfnInit)(bLoading, pT->m_ClsID); - } - } - -} - -// called by COM to determine if this dll can be unloaded -// return ok unless there are outstanding objects or a lock requested -// by IClassFactory::LockServer -// -// CClassFactory has a static function that can tell us about the locks, -// and CCOMObject has a static function that can tell us about the active -// object count -STDAPI -DllCanUnloadNow() -{ - DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"), - CClassFactory::IsLocked(), - CBaseObject::ObjectsActive())); - - if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) { - return S_FALSE; - } else { - return S_OK; - } -} - - -// --- standard WIN32 entrypoints -------------------------------------- -extern "C" void __cdecl __security_init_cookie(void); -extern "C" BOOL WINAPI _DllEntryPoint(HINSTANCE, ULONG, __inout_opt LPVOID); -#pragma comment(linker, "/merge:.CRT=.rdata") - -extern "C" -DECLSPEC_NOINLINE -BOOL -WINAPI -DllEntryPoint( - HINSTANCE hInstance, - ULONG ulReason, - __inout_opt LPVOID pv - ) -{ - if ( ulReason == DLL_PROCESS_ATTACH ) { - // Must happen before any other code is executed. Thankfully - it's re-entrant - __security_init_cookie(); - } - return _DllEntryPoint(hInstance, ulReason, pv); -} - - -DECLSPEC_NOINLINE -BOOL -WINAPI -_DllEntryPoint( - HINSTANCE hInstance, - ULONG ulReason, - __inout_opt LPVOID pv - ) -{ -#ifdef _DEBUG - extern bool g_fDbgInDllEntryPoint; - g_fDbgInDllEntryPoint = true; -#endif - - switch (ulReason) - { - - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hInstance); - DbgInitialise(hInstance); - - { - // The platform identifier is used to work out whether - // full unicode support is available or not. Hence the - // default will be the lowest common denominator - i.e. N/A - g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails - - g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo); - if (GetVersionEx(&g_osInfo)) { - g_amPlatform = g_osInfo.dwPlatformId; - } else { - DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95"))); - } - } - - g_hInst = hInstance; - DllInitClasses(TRUE); - break; - - case DLL_PROCESS_DETACH: - DllInitClasses(FALSE); - -#ifdef _DEBUG - if (CBaseObject::ObjectsActive()) { - DbgSetModuleLevel(LOG_MEMORY, 2); - TCHAR szInfo[512]; - extern TCHAR m_ModuleName[]; // Cut down module name - - TCHAR FullName[MAX_PATH]; // Load the full path and module name - TCHAR *pName; // Searches from the end for a backslash - - GetModuleFileName(NULL,FullName,MAX_PATH); - pName = _tcsrchr(FullName,'\\'); - if (pName == NULL) { - pName = FullName; - } else { - pName++; - } - - (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("Executable: %s Pid %x Tid %x. "), - pName, GetCurrentProcessId(), GetCurrentThreadId()); - - (void)StringCchPrintf(szInfo+lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), TEXT("Module %s, %d objects left active!"), - m_ModuleName, CBaseObject::ObjectsActive()); - DbgAssert(szInfo, TEXT(__FILE__),__LINE__); - - // If running remotely wait for the Assert to be acknowledged - // before dumping out the object register - DbgDumpObjectRegister(); - } - DbgTerminate(); -#endif - break; - } - -#ifdef _DEBUG - g_fDbgInDllEntryPoint = false; -#endif - return TRUE; -} - - +//------------------------------------------------------------------------------ +// File: DlleEntry.cpp +// +// Desc: DirectShow base classes - implements classes used to support dll +// entry points for COM objects. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +#ifdef _DEBUG +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif // _UNICODE +#endif // UNICODE + +#include +#endif // DEBUG +#include + +extern CFactoryTemplate g_Templates[]; +extern int g_cTemplates; + +HINSTANCE g_hInst; +DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx) +OSVERSIONINFO g_osInfo; + +// +// an instance of this is created by the DLLGetClassObject entrypoint +// it uses the CFactoryTemplate object it is given to support the +// IClassFactory interface + +class CClassFactory : public IClassFactory, public CBaseObject +{ + +private: + const CFactoryTemplate *const m_pTemplate; + + ULONG m_cRef; + + static int m_cLocked; +public: + CClassFactory(const CFactoryTemplate *); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, __deref_out void ** ppv); + STDMETHODIMP_(ULONG)AddRef(); + STDMETHODIMP_(ULONG)Release(); + + // IClassFactory + STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, __deref_out void **pv); + STDMETHODIMP LockServer(BOOL fLock); + + // allow DLLGetClassObject to know about global server lock status + static BOOL IsLocked() { + return (m_cLocked > 0); + }; +}; + +// process-wide dll locked state +int CClassFactory::m_cLocked = 0; + +CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate) +: CBaseObject(NAME("Class Factory")) +, m_cRef(0) +, m_pTemplate(pTemplate) +{ +} + + +STDMETHODIMP +CClassFactory::QueryInterface(REFIID riid,__deref_out void **ppv) +{ + CheckPointer(ppv,E_POINTER) + ValidateReadWritePtr(ppv,sizeof(PVOID)); + *ppv = NULL; + + // any interface on this object is the object pointer. + if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) { + *ppv = (LPVOID) this; + // AddRef returned interface pointer + ((LPUNKNOWN) *ppv)->AddRef(); + return NOERROR; + } + + return ResultFromScode(E_NOINTERFACE); +} + + +STDMETHODIMP_(ULONG) +CClassFactory::AddRef() +{ + return ++m_cRef; +} + +STDMETHODIMP_(ULONG) +CClassFactory::Release() +{ + LONG lRef = InterlockedDecrement((volatile LONG *)&m_cRef); + if (lRef == 0) { + delete this; + return 0; + } else { + return lRef; + } +} + +STDMETHODIMP +CClassFactory::CreateInstance( + LPUNKNOWN pUnkOuter, + REFIID riid, + __deref_out void **pv) +{ + CheckPointer(pv,E_POINTER) + ValidateReadWritePtr(pv,sizeof(void *)); + *pv = NULL; + + /* Enforce the normal OLE rules regarding interfaces and delegation */ + + if (pUnkOuter != NULL) { + if (IsEqualIID(riid,IID_IUnknown) == FALSE) { + *pv = NULL; + return ResultFromScode(E_NOINTERFACE); + } + } + + /* Create the new object through the derived class's create function */ + + HRESULT hr = NOERROR; + CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr); + + if (pObj == NULL) { + *pv = NULL; + if (SUCCEEDED(hr)) { + hr = E_OUTOFMEMORY; + } + return hr; + } + + /* Delete the object if we got a construction error */ + + if (FAILED(hr)) { + delete pObj; + *pv = NULL; + return hr; + } + + /* Get a reference counted interface on the object */ + + /* We wrap the non-delegating QI with NDAddRef & NDRelease. */ + /* This protects any outer object from being prematurely */ + /* released by an inner object that may have to be created */ + /* in order to supply the requested interface. */ + pObj->NonDelegatingAddRef(); + hr = pObj->NonDelegatingQueryInterface(riid, pv); + pObj->NonDelegatingRelease(); + /* Note that if NonDelegatingQueryInterface fails, it will */ + /* not increment the ref count, so the NonDelegatingRelease */ + /* will drop the ref back to zero and the object will "self-*/ + /* destruct". Hence we don't need additional tidy-up code */ + /* to cope with NonDelegatingQueryInterface failing. */ + + if (SUCCEEDED(hr)) { + ASSERT(*pv); + } + + return hr; +} + +STDMETHODIMP +CClassFactory::LockServer(BOOL fLock) +{ + if (fLock) { + m_cLocked++; + } else { + m_cLocked--; + } + return NOERROR; +} + + +// --- COM entrypoints ----------------------------------------- + +//called by COM to get the class factory object for a given class +__control_entrypoint(DllExport) STDAPI +DllGetClassObject( + __in REFCLSID rClsID, + __in REFIID riid, + __deref_out void **pv) +{ + *pv = NULL; + if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) { + return E_NOINTERFACE; + } + + // traverse the array of templates looking for one with this + // class id + for (int i = 0; i < g_cTemplates; i++) { + const CFactoryTemplate * pT = &g_Templates[i]; + if (pT->IsClassID(rClsID)) { + + // found a template - make a class factory based on this + // template + + *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT); + if (*pv == NULL) { + return E_OUTOFMEMORY; + } + ((LPUNKNOWN)*pv)->AddRef(); + return NOERROR; + } + } + return CLASS_E_CLASSNOTAVAILABLE; +} + +// +// Call any initialization routines +// +void +DllInitClasses(BOOL bLoading) +{ + int i; + + // traverse the array of templates calling the init routine + // if they have one + for (i = 0; i < g_cTemplates; i++) { + const CFactoryTemplate * pT = &g_Templates[i]; + if (pT->m_lpfnInit != NULL) { + (*pT->m_lpfnInit)(bLoading, pT->m_ClsID); + } + } + +} + +// called by COM to determine if this dll can be unloaded +// return ok unless there are outstanding objects or a lock requested +// by IClassFactory::LockServer +// +// CClassFactory has a static function that can tell us about the locks, +// and CCOMObject has a static function that can tell us about the active +// object count +STDAPI +DllCanUnloadNow() +{ + DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"), + CClassFactory::IsLocked(), + CBaseObject::ObjectsActive())); + + if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) { + return S_FALSE; + } else { + return S_OK; + } +} + + +// --- standard WIN32 entrypoints -------------------------------------- +extern "C" void __cdecl __security_init_cookie(void); +extern "C" BOOL WINAPI _DllEntryPoint(HINSTANCE, ULONG, __inout_opt LPVOID); +#pragma comment(linker, "/merge:.CRT=.rdata") + +extern "C" +DECLSPEC_NOINLINE +BOOL +WINAPI +DllEntryPoint( + HINSTANCE hInstance, + ULONG ulReason, + __inout_opt LPVOID pv + ) +{ + if ( ulReason == DLL_PROCESS_ATTACH ) { + // Must happen before any other code is executed. Thankfully - it's re-entrant + __security_init_cookie(); + } + return _DllEntryPoint(hInstance, ulReason, pv); +} + + +DECLSPEC_NOINLINE +BOOL +WINAPI +_DllEntryPoint( + HINSTANCE hInstance, + ULONG ulReason, + __inout_opt LPVOID pv + ) +{ +#ifdef _DEBUG + extern bool g_fDbgInDllEntryPoint; + g_fDbgInDllEntryPoint = true; +#endif + + switch (ulReason) + { + + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstance); + DbgInitialise(hInstance); + + { + // The platform identifier is used to work out whether + // full unicode support is available or not. Hence the + // default will be the lowest common denominator - i.e. N/A + g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails + + g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo); + if (GetVersionEx(&g_osInfo)) { + g_amPlatform = g_osInfo.dwPlatformId; + } else { + DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95"))); + } + } + + g_hInst = hInstance; + DllInitClasses(TRUE); + break; + + case DLL_PROCESS_DETACH: + DllInitClasses(FALSE); + +#ifdef _DEBUG + if (CBaseObject::ObjectsActive()) { + DbgSetModuleLevel(LOG_MEMORY, 2); + TCHAR szInfo[512]; + extern TCHAR m_ModuleName[]; // Cut down module name + + TCHAR FullName[MAX_PATH]; // Load the full path and module name + TCHAR *pName; // Searches from the end for a backslash + + GetModuleFileName(NULL,FullName,MAX_PATH); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) { + pName = FullName; + } else { + pName++; + } + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("Executable: %s Pid %x Tid %x. "), + pName, GetCurrentProcessId(), GetCurrentThreadId()); + + (void)StringCchPrintf(szInfo+lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), TEXT("Module %s, %d objects left active!"), + m_ModuleName, CBaseObject::ObjectsActive()); + DbgAssert(szInfo, TEXT(__FILE__),__LINE__); + + // If running remotely wait for the Assert to be acknowledged + // before dumping out the object register + DbgDumpObjectRegister(); + } + DbgTerminate(); +#endif + break; + } + +#ifdef _DEBUG + g_fDbgInDllEntryPoint = false; +#endif + return TRUE; +} + + diff --git a/src/thirdparty/BaseClasses/dllsetup.cpp b/src/thirdparty/BaseClasses/dllsetup.cpp index aaa95d04692..28454b73fca 100644 --- a/src/thirdparty/BaseClasses/dllsetup.cpp +++ b/src/thirdparty/BaseClasses/dllsetup.cpp @@ -1,696 +1,696 @@ -//------------------------------------------------------------------------------ -// File: DllSetup.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -//--------------------------------------------------------------------------- -// defines - -#define MAX_KEY_LEN 260 - - -//--------------------------------------------------------------------------- -// externally defined functions/variable - -extern int g_cTemplates; -extern CFactoryTemplate g_Templates[]; - -//--------------------------------------------------------------------------- -// -// EliminateSubKey -// -// Try to enumerate all keys under this one. -// if we find anything, delete it completely. -// Otherwise just delete it. -// -// note - this was pinched/duplicated from -// Filgraph\Mapper.cpp - so should it be in -// a lib somewhere? -// -//--------------------------------------------------------------------------- - -STDAPI -EliminateSubKey( HKEY hkey, LPCTSTR strSubKey ) -{ - HKEY hk; - if (0 == lstrlen(strSubKey) ) { - // defensive approach - return E_FAIL; - } - - LONG lreturn = RegOpenKeyEx( hkey - , strSubKey - , 0 - , MAXIMUM_ALLOWED - , &hk ); - - ASSERT( lreturn == ERROR_SUCCESS - || lreturn == ERROR_FILE_NOT_FOUND - || lreturn == ERROR_INVALID_HANDLE ); - - if( ERROR_SUCCESS == lreturn ) - { - // Keep on enumerating the first (zero-th) - // key and deleting that - - for( ; ; ) - { - TCHAR Buffer[MAX_KEY_LEN]; - DWORD dw = MAX_KEY_LEN; - FILETIME ft; - - lreturn = RegEnumKeyEx( hk - , 0 - , Buffer - , &dw - , NULL - , NULL - , NULL - , &ft); - - ASSERT( lreturn == ERROR_SUCCESS - || lreturn == ERROR_NO_MORE_ITEMS ); - - if( ERROR_SUCCESS == lreturn ) - { - EliminateSubKey(hk, Buffer); - } - else - { - break; - } - } - - RegCloseKey(hk); - RegDeleteKey(hkey, strSubKey); - } - - return NOERROR; -} - - -//--------------------------------------------------------------------------- -// -// AMovieSetupRegisterServer() -// -// registers specfied file "szFileName" as server for -// CLSID "clsServer". A description is also required. -// The ThreadingModel and ServerType are optional, as -// they default to InprocServer32 (i.e. dll) and Both. -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieSetupRegisterServer( CLSID clsServer - , LPCWSTR szDescription - , LPCWSTR szFileName - , LPCWSTR szThreadingModel = L"Both" - , LPCWSTR szServerType = L"InprocServer32" ) -{ - // temp buffer - // - TCHAR achTemp[MAX_PATH]; - - // convert CLSID uuid to string and write - // out subkey as string - CLSID\{} - // - OLECHAR szCLSID[CHARS_IN_GUID]; - HRESULT hr = StringFromGUID2( clsServer - , szCLSID - , CHARS_IN_GUID ); - ASSERT( SUCCEEDED(hr) ); - UNREFERENCED_PARAMETER(hr); - - // create key - // - HKEY hkey; - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("CLSID\\%ls"), szCLSID ); - LONG lreturn = RegCreateKey( HKEY_CLASSES_ROOT - , (LPCTSTR)achTemp - , &hkey ); - if( ERROR_SUCCESS != lreturn ) - { - return AmHresultFromWin32(lreturn); - } - - // set description string - // - - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szDescription ); - lreturn = RegSetValue( hkey - , (LPCTSTR)NULL - , REG_SZ - , achTemp - , sizeof(achTemp) ); - if( ERROR_SUCCESS != lreturn ) - { - RegCloseKey( hkey ); - return AmHresultFromWin32(lreturn); - } - - // create CLSID\\{"CLSID"}\\"ServerType" key, - // using key to CLSID\\{"CLSID"} passed back by - // last call to RegCreateKey(). - // - HKEY hsubkey; - - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szServerType ); - lreturn = RegCreateKey( hkey - , achTemp - , &hsubkey ); - if( ERROR_SUCCESS != lreturn ) - { - RegCloseKey( hkey ); - return AmHresultFromWin32(lreturn); - } - - // set Server string - // - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szFileName ); - lreturn = RegSetValue( hsubkey - , (LPCTSTR)NULL - , REG_SZ - , (LPCTSTR)achTemp - , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); - if( ERROR_SUCCESS != lreturn ) - { - RegCloseKey( hkey ); - RegCloseKey( hsubkey ); - return AmHresultFromWin32(lreturn); - } - - (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szThreadingModel ); - lreturn = RegSetValueEx( hsubkey - , TEXT("ThreadingModel") - , 0L - , REG_SZ - , (CONST BYTE *)achTemp - , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); - - // close hkeys - // - RegCloseKey( hkey ); - RegCloseKey( hsubkey ); - - // and return - // - return HRESULT_FROM_WIN32(lreturn); - -} - - -//--------------------------------------------------------------------------- -// -// AMovieSetupUnregisterServer() -// -// default ActiveMovie dll setup function -// - to use must be called from an exported -// function named DllRegisterServer() -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieSetupUnregisterServer( CLSID clsServer ) -{ - // convert CLSID uuid to string and write - // out subkey CLSID\{} - // - OLECHAR szCLSID[CHARS_IN_GUID]; - HRESULT hr = StringFromGUID2( clsServer - , szCLSID - , CHARS_IN_GUID ); - ASSERT( SUCCEEDED(hr) ); - - TCHAR achBuffer[MAX_KEY_LEN]; - (void)StringCchPrintf( achBuffer, NUMELMS(achBuffer), TEXT("CLSID\\%ls"), szCLSID ); - - // delete subkey - // - - hr = EliminateSubKey( HKEY_CLASSES_ROOT, achBuffer ); - ASSERT( SUCCEEDED(hr) ); - - // return - // - return NOERROR; -} - - -//--------------------------------------------------------------------------- -// -// AMovieSetupRegisterFilter through IFilterMapper2 -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper2 * pIFM2 - , BOOL bRegister ) -{ - DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); - - // check we've got data - // - if( NULL == psetupdata ) return S_FALSE; - - - // unregister filter - // (as pins are subkeys of filter's CLSID key - // they do not need to be removed separately). - // - DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); - HRESULT hr = pIFM2->UnregisterFilter( - 0, // default category - 0, // default instance name - *psetupdata->clsID ); - - - if( bRegister ) - { - REGFILTER2 rf2; - rf2.dwVersion = 1; - rf2.dwMerit = psetupdata->dwMerit; - rf2.cPins = psetupdata->nPins; - rf2.rgPins = psetupdata->lpPin; - - const CLSID *filterCategory=&psetupdata->filterCategory; - - // register filter - // - DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); - hr = pIFM2->RegisterFilter(*psetupdata->clsID - , psetupdata->strName - , 0 // moniker - ,filterCategory // category - , NULL // instance - , &rf2); - } - - // handle one acceptable "error" - that - // of filter not being registered! - // (couldn't find a suitable #define'd - // name for the error!) - // - if( 0x80070002 == hr) - return NOERROR; - else - return hr; -} - - -//--------------------------------------------------------------------------- -// -// RegisterAllServers() -// -//--------------------------------------------------------------------------- - -STDAPI -RegisterAllServers( LPCWSTR szFileName, BOOL bRegister ) -{ - HRESULT hr = NOERROR; - - for( int i = 0; i < g_cTemplates; i++ ) - { - // get i'th template - // - const CFactoryTemplate *pT = &g_Templates[i]; - - DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), - (LPCWSTR)pT->m_Name )); - - // register CLSID and InprocServer32 - // - if( bRegister ) - { - hr = AMovieSetupRegisterServer( *(pT->m_ClsID) - , (LPCWSTR)pT->m_Name - , szFileName ); - } - else - { - hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); - } - - // check final error for this pass - // and break loop if we failed - // - if( FAILED(hr) ) - break; - } - - return hr; -} - - -//--------------------------------------------------------------------------- -// -// AMovieDllRegisterServer2() -// -// default ActiveMovie dll setup function -// - to use must be called from an exported -// function named DllRegisterServer() -// -// this function is table driven using the -// static members of the CFactoryTemplate -// class defined in the dll. -// -// it registers the Dll as the InprocServer32 -// and then calls the IAMovieSetup.Register -// method. -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieDllRegisterServer2( BOOL bRegister ) -{ - HRESULT hr = NOERROR; - - DbgLog((LOG_TRACE, 2, TEXT("AMovieDllRegisterServer2()"))); - - // get file name (where g_hInst is the - // instance handle of the filter dll) - // - WCHAR achFileName[MAX_PATH]; - - // WIN95 doesn't support GetModuleFileNameW - // - { - char achTemp[MAX_PATH]; - - DbgLog((LOG_TRACE, 2, TEXT("- get module file name"))); - - // g_hInst handle is set in our dll entry point. Make sure - // DllEntryPoint in dllentry.cpp is called - ASSERT(g_hInst != 0); - - if( 0 == GetModuleFileNameA( g_hInst - , achTemp - , sizeof(achTemp) ) ) - { - // we've failed! - DWORD dwerr = GetLastError(); - return AmHresultFromWin32(dwerr); - } - - MultiByteToWideChar( CP_ACP - , 0L - , achTemp - , lstrlenA(achTemp) + 1 - , achFileName - , NUMELMS(achFileName) ); - } - - // - // first registering, register all OLE servers - // - if( bRegister ) - { - DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); - hr = RegisterAllServers( achFileName, TRUE ); - } - - // - // next, register/unregister all filters - // - - if( SUCCEEDED(hr) ) - { - // init is ref counted so call just in case - // we're being called cold. - // - DbgLog((LOG_TRACE, 2, TEXT("- CoInitialize"))); - hr = CoInitialize( (LPVOID)NULL ); - ASSERT( SUCCEEDED(hr) ); - - // get hold of IFilterMapper2 - // - DbgLog((LOG_TRACE, 2, TEXT("- obtain IFilterMapper2"))); - IFilterMapper2 *pIFM2 = 0; - IFilterMapper *pIFM = 0; - hr = CoCreateInstance( CLSID_FilterMapper2 - , NULL - , CLSCTX_INPROC_SERVER - , IID_IFilterMapper2 - , (void **)&pIFM2 ); - if(FAILED(hr)) - { - DbgLog((LOG_TRACE, 2, TEXT("- trying IFilterMapper instead"))); - - hr = CoCreateInstance( - CLSID_FilterMapper, - NULL, - CLSCTX_INPROC_SERVER, - IID_IFilterMapper, - (void **)&pIFM); - } - if( SUCCEEDED(hr) ) - { - // scan through array of CFactoryTemplates - // registering servers and filters. - // - DbgLog((LOG_TRACE, 2, TEXT("- register Filters"))); - for( int i = 0; i < g_cTemplates; i++ ) - { - // get i'th template - // - const CFactoryTemplate *pT = &g_Templates[i]; - - if( NULL != pT->m_pAMovieSetup_Filter ) - { - DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), (LPCWSTR)pT->m_Name )); - - if(pIFM2) - { - hr = AMovieSetupRegisterFilter2( pT->m_pAMovieSetup_Filter, pIFM2, bRegister ); - } - else - { - hr = AMovieSetupRegisterFilter( pT->m_pAMovieSetup_Filter, pIFM, bRegister ); - } - } - - // check final error for this pass - // and break loop if we failed - // - if( FAILED(hr) ) - break; - } - - // release interface - // - if(pIFM2) - pIFM2->Release(); - else - pIFM->Release(); - - } - - // and clear up - // - CoFreeUnusedLibraries(); - CoUninitialize(); - } - - // - // if unregistering, unregister all OLE servers - // - if( SUCCEEDED(hr) && !bRegister ) - { - DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); - hr = RegisterAllServers( achFileName, FALSE ); - } - - DbgLog((LOG_TRACE, 2, TEXT("- return %0x"), hr)); - return hr; -} - - -//--------------------------------------------------------------------------- -// -// AMovieDllRegisterServer() -// -// default ActiveMovie dll setup function -// - to use must be called from an exported -// function named DllRegisterServer() -// -// this function is table driven using the -// static members of the CFactoryTemplate -// class defined in the dll. -// -// it registers the Dll as the InprocServer32 -// and then calls the IAMovieSetup.Register -// method. -// -//--------------------------------------------------------------------------- - - -STDAPI -AMovieDllRegisterServer( void ) -{ - HRESULT hr = NOERROR; - - // get file name (where g_hInst is the - // instance handle of the filter dll) - // - WCHAR achFileName[MAX_PATH]; - - { - // WIN95 doesn't support GetModuleFileNameW - // - char achTemp[MAX_PATH]; - - if( 0 == GetModuleFileNameA( g_hInst - , achTemp - , sizeof(achTemp) ) ) - { - // we've failed! - DWORD dwerr = GetLastError(); - return AmHresultFromWin32(dwerr); - } - - MultiByteToWideChar( CP_ACP - , 0L - , achTemp - , lstrlenA(achTemp) + 1 - , achFileName - , NUMELMS(achFileName) ); - } - - // scan through array of CFactoryTemplates - // registering servers and filters. - // - for( int i = 0; i < g_cTemplates; i++ ) - { - // get i'th template - // - const CFactoryTemplate *pT = &g_Templates[i]; - - // register CLSID and InprocServer32 - // - hr = AMovieSetupRegisterServer( *(pT->m_ClsID) - , (LPCWSTR)pT->m_Name - , achFileName ); - - // instantiate all servers and get hold of - // IAMovieSetup, if implemented, and call - // IAMovieSetup.Register() method - // - if( SUCCEEDED(hr) && (NULL != pT->m_lpfnNew) ) - { - // instantiate object - // - PAMOVIESETUP psetup; - hr = CoCreateInstance( *(pT->m_ClsID) - , 0 - , CLSCTX_INPROC_SERVER - , IID_IAMovieSetup - , reinterpret_cast(&psetup) ); - if( SUCCEEDED(hr) ) - { - hr = psetup->Unregister(); - if( SUCCEEDED(hr) ) - hr = psetup->Register(); - psetup->Release(); - } - else - { - if( (E_NOINTERFACE == hr ) - || (VFW_E_NEED_OWNER == hr ) ) - hr = NOERROR; - } - } - - // check final error for this pass - // and break loop if we failed - // - if( FAILED(hr) ) - break; - - } // end-for - - return hr; -} - - -//--------------------------------------------------------------------------- -// -// AMovieDllUnregisterServer() -// -// default ActiveMovie dll uninstall function -// - to use must be called from an exported -// function named DllRegisterServer() -// -// this function is table driven using the -// static members of the CFactoryTemplate -// class defined in the dll. -// -// it calls the IAMovieSetup.Unregister -// method and then unregisters the Dll -// as the InprocServer32 -// -//--------------------------------------------------------------------------- - -STDAPI -AMovieDllUnregisterServer() -{ - // initialize return code - // - HRESULT hr = NOERROR; - - // scan through CFactory template and unregister - // all OLE servers and filters. - // - for( int i = g_cTemplates; i--; ) - { - // get i'th template - // - const CFactoryTemplate *pT = &g_Templates[i]; - - // check method exists - // - if( NULL != pT->m_lpfnNew ) - { - // instantiate object - // - PAMOVIESETUP psetup; - hr = CoCreateInstance( *(pT->m_ClsID) - , 0 - , CLSCTX_INPROC_SERVER - , IID_IAMovieSetup - , reinterpret_cast(&psetup) ); - if( SUCCEEDED(hr) ) - { - hr = psetup->Unregister(); - psetup->Release(); - } - else - { - if( (E_NOINTERFACE == hr ) - || (VFW_E_NEED_OWNER == hr ) ) - hr = NOERROR; - } - } - - // unregister CLSID and InprocServer32 - // - if( SUCCEEDED(hr) ) - { - hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); - } - - // check final error for this pass - // and break loop if we failed - // - if( FAILED(hr) ) - break; - } - - return hr; -} +//------------------------------------------------------------------------------ +// File: DllSetup.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +//--------------------------------------------------------------------------- +// defines + +#define MAX_KEY_LEN 260 + + +//--------------------------------------------------------------------------- +// externally defined functions/variable + +extern int g_cTemplates; +extern CFactoryTemplate g_Templates[]; + +//--------------------------------------------------------------------------- +// +// EliminateSubKey +// +// Try to enumerate all keys under this one. +// if we find anything, delete it completely. +// Otherwise just delete it. +// +// note - this was pinched/duplicated from +// Filgraph\Mapper.cpp - so should it be in +// a lib somewhere? +// +//--------------------------------------------------------------------------- + +STDAPI +EliminateSubKey( HKEY hkey, LPCTSTR strSubKey ) +{ + HKEY hk; + if (0 == lstrlen(strSubKey) ) { + // defensive approach + return E_FAIL; + } + + LONG lreturn = RegOpenKeyEx( hkey + , strSubKey + , 0 + , MAXIMUM_ALLOWED + , &hk ); + + ASSERT( lreturn == ERROR_SUCCESS + || lreturn == ERROR_FILE_NOT_FOUND + || lreturn == ERROR_INVALID_HANDLE ); + + if( ERROR_SUCCESS == lreturn ) + { + // Keep on enumerating the first (zero-th) + // key and deleting that + + for( ; ; ) + { + TCHAR Buffer[MAX_KEY_LEN]; + DWORD dw = MAX_KEY_LEN; + FILETIME ft; + + lreturn = RegEnumKeyEx( hk + , 0 + , Buffer + , &dw + , NULL + , NULL + , NULL + , &ft); + + ASSERT( lreturn == ERROR_SUCCESS + || lreturn == ERROR_NO_MORE_ITEMS ); + + if( ERROR_SUCCESS == lreturn ) + { + EliminateSubKey(hk, Buffer); + } + else + { + break; + } + } + + RegCloseKey(hk); + RegDeleteKey(hkey, strSubKey); + } + + return NOERROR; +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupRegisterServer() +// +// registers specfied file "szFileName" as server for +// CLSID "clsServer". A description is also required. +// The ThreadingModel and ServerType are optional, as +// they default to InprocServer32 (i.e. dll) and Both. +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupRegisterServer( CLSID clsServer + , LPCWSTR szDescription + , LPCWSTR szFileName + , LPCWSTR szThreadingModel = L"Both" + , LPCWSTR szServerType = L"InprocServer32" ) +{ + // temp buffer + // + TCHAR achTemp[MAX_PATH]; + + // convert CLSID uuid to string and write + // out subkey as string - CLSID\{} + // + OLECHAR szCLSID[CHARS_IN_GUID]; + HRESULT hr = StringFromGUID2( clsServer + , szCLSID + , CHARS_IN_GUID ); + ASSERT( SUCCEEDED(hr) ); + UNREFERENCED_PARAMETER(hr); + + // create key + // + HKEY hkey; + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("CLSID\\%ls"), szCLSID ); + LONG lreturn = RegCreateKey( HKEY_CLASSES_ROOT + , (LPCTSTR)achTemp + , &hkey ); + if( ERROR_SUCCESS != lreturn ) + { + return AmHresultFromWin32(lreturn); + } + + // set description string + // + + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szDescription ); + lreturn = RegSetValue( hkey + , (LPCTSTR)NULL + , REG_SZ + , achTemp + , sizeof(achTemp) ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + return AmHresultFromWin32(lreturn); + } + + // create CLSID\\{"CLSID"}\\"ServerType" key, + // using key to CLSID\\{"CLSID"} passed back by + // last call to RegCreateKey(). + // + HKEY hsubkey; + + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szServerType ); + lreturn = RegCreateKey( hkey + , achTemp + , &hsubkey ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + return AmHresultFromWin32(lreturn); + } + + // set Server string + // + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szFileName ); + lreturn = RegSetValue( hsubkey + , (LPCTSTR)NULL + , REG_SZ + , (LPCTSTR)achTemp + , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); + if( ERROR_SUCCESS != lreturn ) + { + RegCloseKey( hkey ); + RegCloseKey( hsubkey ); + return AmHresultFromWin32(lreturn); + } + + (void)StringCchPrintf( achTemp, NUMELMS(achTemp), TEXT("%ls"), szThreadingModel ); + lreturn = RegSetValueEx( hsubkey + , TEXT("ThreadingModel") + , 0L + , REG_SZ + , (CONST BYTE *)achTemp + , sizeof(TCHAR) * (lstrlen(achTemp)+1) ); + + // close hkeys + // + RegCloseKey( hkey ); + RegCloseKey( hsubkey ); + + // and return + // + return HRESULT_FROM_WIN32(lreturn); + +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupUnregisterServer() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupUnregisterServer( CLSID clsServer ) +{ + // convert CLSID uuid to string and write + // out subkey CLSID\{} + // + OLECHAR szCLSID[CHARS_IN_GUID]; + HRESULT hr = StringFromGUID2( clsServer + , szCLSID + , CHARS_IN_GUID ); + ASSERT( SUCCEEDED(hr) ); + + TCHAR achBuffer[MAX_KEY_LEN]; + (void)StringCchPrintf( achBuffer, NUMELMS(achBuffer), TEXT("CLSID\\%ls"), szCLSID ); + + // delete subkey + // + + hr = EliminateSubKey( HKEY_CLASSES_ROOT, achBuffer ); + ASSERT( SUCCEEDED(hr) ); + + // return + // + return NOERROR; +} + + +//--------------------------------------------------------------------------- +// +// AMovieSetupRegisterFilter through IFilterMapper2 +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper2 * pIFM2 + , BOOL bRegister ) +{ + DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter"))); + + // check we've got data + // + if( NULL == psetupdata ) return S_FALSE; + + + // unregister filter + // (as pins are subkeys of filter's CLSID key + // they do not need to be removed separately). + // + DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter"))); + HRESULT hr = pIFM2->UnregisterFilter( + 0, // default category + 0, // default instance name + *psetupdata->clsID ); + + + if( bRegister ) + { + REGFILTER2 rf2; + rf2.dwVersion = 1; + rf2.dwMerit = psetupdata->dwMerit; + rf2.cPins = psetupdata->nPins; + rf2.rgPins = psetupdata->lpPin; + + const CLSID *filterCategory=&psetupdata->filterCategory; + + // register filter + // + DbgLog((LOG_TRACE, 3, TEXT("= = register filter"))); + hr = pIFM2->RegisterFilter(*psetupdata->clsID + , psetupdata->strName + , 0 // moniker + ,filterCategory // category + , NULL // instance + , &rf2); + } + + // handle one acceptable "error" - that + // of filter not being registered! + // (couldn't find a suitable #define'd + // name for the error!) + // + if( 0x80070002 == hr) + return NOERROR; + else + return hr; +} + + +//--------------------------------------------------------------------------- +// +// RegisterAllServers() +// +//--------------------------------------------------------------------------- + +STDAPI +RegisterAllServers( LPCWSTR szFileName, BOOL bRegister ) +{ + HRESULT hr = NOERROR; + + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), + (LPCWSTR)pT->m_Name )); + + // register CLSID and InprocServer32 + // + if( bRegister ) + { + hr = AMovieSetupRegisterServer( *(pT->m_ClsID) + , (LPCWSTR)pT->m_Name + , szFileName ); + } + else + { + hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllRegisterServer2() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it registers the Dll as the InprocServer32 +// and then calls the IAMovieSetup.Register +// method. +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieDllRegisterServer2( BOOL bRegister ) +{ + HRESULT hr = NOERROR; + + DbgLog((LOG_TRACE, 2, TEXT("AMovieDllRegisterServer2()"))); + + // get file name (where g_hInst is the + // instance handle of the filter dll) + // + WCHAR achFileName[MAX_PATH]; + + // WIN95 doesn't support GetModuleFileNameW + // + { + char achTemp[MAX_PATH]; + + DbgLog((LOG_TRACE, 2, TEXT("- get module file name"))); + + // g_hInst handle is set in our dll entry point. Make sure + // DllEntryPoint in dllentry.cpp is called + ASSERT(g_hInst != 0); + + if( 0 == GetModuleFileNameA( g_hInst + , achTemp + , sizeof(achTemp) ) ) + { + // we've failed! + DWORD dwerr = GetLastError(); + return AmHresultFromWin32(dwerr); + } + + MultiByteToWideChar( CP_ACP + , 0L + , achTemp + , lstrlenA(achTemp) + 1 + , achFileName + , NUMELMS(achFileName) ); + } + + // + // first registering, register all OLE servers + // + if( bRegister ) + { + DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); + hr = RegisterAllServers( achFileName, TRUE ); + } + + // + // next, register/unregister all filters + // + + if( SUCCEEDED(hr) ) + { + // init is ref counted so call just in case + // we're being called cold. + // + DbgLog((LOG_TRACE, 2, TEXT("- CoInitialize"))); + hr = CoInitialize( (LPVOID)NULL ); + ASSERT( SUCCEEDED(hr) ); + + // get hold of IFilterMapper2 + // + DbgLog((LOG_TRACE, 2, TEXT("- obtain IFilterMapper2"))); + IFilterMapper2 *pIFM2 = 0; + IFilterMapper *pIFM = 0; + hr = CoCreateInstance( CLSID_FilterMapper2 + , NULL + , CLSCTX_INPROC_SERVER + , IID_IFilterMapper2 + , (void **)&pIFM2 ); + if(FAILED(hr)) + { + DbgLog((LOG_TRACE, 2, TEXT("- trying IFilterMapper instead"))); + + hr = CoCreateInstance( + CLSID_FilterMapper, + NULL, + CLSCTX_INPROC_SERVER, + IID_IFilterMapper, + (void **)&pIFM); + } + if( SUCCEEDED(hr) ) + { + // scan through array of CFactoryTemplates + // registering servers and filters. + // + DbgLog((LOG_TRACE, 2, TEXT("- register Filters"))); + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + if( NULL != pT->m_pAMovieSetup_Filter ) + { + DbgLog((LOG_TRACE, 2, TEXT("- - register %ls"), (LPCWSTR)pT->m_Name )); + + if(pIFM2) + { + hr = AMovieSetupRegisterFilter2( pT->m_pAMovieSetup_Filter, pIFM2, bRegister ); + } + else + { + hr = AMovieSetupRegisterFilter( pT->m_pAMovieSetup_Filter, pIFM, bRegister ); + } + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + // release interface + // + if(pIFM2) + pIFM2->Release(); + else + pIFM->Release(); + + } + + // and clear up + // + CoFreeUnusedLibraries(); + CoUninitialize(); + } + + // + // if unregistering, unregister all OLE servers + // + if( SUCCEEDED(hr) && !bRegister ) + { + DbgLog((LOG_TRACE, 2, TEXT("- register OLE Servers"))); + hr = RegisterAllServers( achFileName, FALSE ); + } + + DbgLog((LOG_TRACE, 2, TEXT("- return %0x"), hr)); + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllRegisterServer() +// +// default ActiveMovie dll setup function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it registers the Dll as the InprocServer32 +// and then calls the IAMovieSetup.Register +// method. +// +//--------------------------------------------------------------------------- + + +STDAPI +AMovieDllRegisterServer( void ) +{ + HRESULT hr = NOERROR; + + // get file name (where g_hInst is the + // instance handle of the filter dll) + // + WCHAR achFileName[MAX_PATH]; + + { + // WIN95 doesn't support GetModuleFileNameW + // + char achTemp[MAX_PATH]; + + if( 0 == GetModuleFileNameA( g_hInst + , achTemp + , sizeof(achTemp) ) ) + { + // we've failed! + DWORD dwerr = GetLastError(); + return AmHresultFromWin32(dwerr); + } + + MultiByteToWideChar( CP_ACP + , 0L + , achTemp + , lstrlenA(achTemp) + 1 + , achFileName + , NUMELMS(achFileName) ); + } + + // scan through array of CFactoryTemplates + // registering servers and filters. + // + for( int i = 0; i < g_cTemplates; i++ ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + // register CLSID and InprocServer32 + // + hr = AMovieSetupRegisterServer( *(pT->m_ClsID) + , (LPCWSTR)pT->m_Name + , achFileName ); + + // instantiate all servers and get hold of + // IAMovieSetup, if implemented, and call + // IAMovieSetup.Register() method + // + if( SUCCEEDED(hr) && (NULL != pT->m_lpfnNew) ) + { + // instantiate object + // + PAMOVIESETUP psetup; + hr = CoCreateInstance( *(pT->m_ClsID) + , 0 + , CLSCTX_INPROC_SERVER + , IID_IAMovieSetup + , reinterpret_cast(&psetup) ); + if( SUCCEEDED(hr) ) + { + hr = psetup->Unregister(); + if( SUCCEEDED(hr) ) + hr = psetup->Register(); + psetup->Release(); + } + else + { + if( (E_NOINTERFACE == hr ) + || (VFW_E_NEED_OWNER == hr ) ) + hr = NOERROR; + } + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + + } // end-for + + return hr; +} + + +//--------------------------------------------------------------------------- +// +// AMovieDllUnregisterServer() +// +// default ActiveMovie dll uninstall function +// - to use must be called from an exported +// function named DllRegisterServer() +// +// this function is table driven using the +// static members of the CFactoryTemplate +// class defined in the dll. +// +// it calls the IAMovieSetup.Unregister +// method and then unregisters the Dll +// as the InprocServer32 +// +//--------------------------------------------------------------------------- + +STDAPI +AMovieDllUnregisterServer() +{ + // initialize return code + // + HRESULT hr = NOERROR; + + // scan through CFactory template and unregister + // all OLE servers and filters. + // + for( int i = g_cTemplates; i--; ) + { + // get i'th template + // + const CFactoryTemplate *pT = &g_Templates[i]; + + // check method exists + // + if( NULL != pT->m_lpfnNew ) + { + // instantiate object + // + PAMOVIESETUP psetup; + hr = CoCreateInstance( *(pT->m_ClsID) + , 0 + , CLSCTX_INPROC_SERVER + , IID_IAMovieSetup + , reinterpret_cast(&psetup) ); + if( SUCCEEDED(hr) ) + { + hr = psetup->Unregister(); + psetup->Release(); + } + else + { + if( (E_NOINTERFACE == hr ) + || (VFW_E_NEED_OWNER == hr ) ) + hr = NOERROR; + } + } + + // unregister CLSID and InprocServer32 + // + if( SUCCEEDED(hr) ) + { + hr = AMovieSetupUnregisterServer( *(pT->m_ClsID) ); + } + + // check final error for this pass + // and break loop if we failed + // + if( FAILED(hr) ) + break; + } + + return hr; +} diff --git a/src/thirdparty/BaseClasses/dllsetup.h b/src/thirdparty/BaseClasses/dllsetup.h index aaac2ec5e98..e363b8b6ac2 100644 --- a/src/thirdparty/BaseClasses/dllsetup.h +++ b/src/thirdparty/BaseClasses/dllsetup.h @@ -1,46 +1,46 @@ -//------------------------------------------------------------------------------ -// File: DllSetup.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// To be self registering, OLE servers must -// export functions named DllRegisterServer -// and DllUnregisterServer. To allow use of -// custom and default implementations the -// defaults are named AMovieDllRegisterServer -// and AMovieDllUnregisterServer. -// -// To the use the default implementation you -// must provide stub functions. -// -// i.e. STDAPI DllRegisterServer() -// { -// return AMovieDllRegisterServer(); -// } -// -// STDAPI DllUnregisterServer() -// { -// return AMovieDllUnregisterServer(); -// } -// -// -// AMovieDllRegisterServer calls IAMovieSetup.Register(), and -// AMovieDllUnregisterServer calls IAMovieSetup.Unregister(). - -STDAPI AMovieDllRegisterServer2( BOOL ); -STDAPI AMovieDllRegisterServer(); -STDAPI AMovieDllUnregisterServer(); - -// helper functions -STDAPI EliminateSubKey( HKEY, LPCTSTR ); - - -STDAPI -AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata - , IFilterMapper2 * pIFM2 - , BOOL bRegister ); - +//------------------------------------------------------------------------------ +// File: DllSetup.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// To be self registering, OLE servers must +// export functions named DllRegisterServer +// and DllUnregisterServer. To allow use of +// custom and default implementations the +// defaults are named AMovieDllRegisterServer +// and AMovieDllUnregisterServer. +// +// To the use the default implementation you +// must provide stub functions. +// +// i.e. STDAPI DllRegisterServer() +// { +// return AMovieDllRegisterServer(); +// } +// +// STDAPI DllUnregisterServer() +// { +// return AMovieDllUnregisterServer(); +// } +// +// +// AMovieDllRegisterServer calls IAMovieSetup.Register(), and +// AMovieDllUnregisterServer calls IAMovieSetup.Unregister(). + +STDAPI AMovieDllRegisterServer2( BOOL ); +STDAPI AMovieDllRegisterServer(); +STDAPI AMovieDllUnregisterServer(); + +// helper functions +STDAPI EliminateSubKey( HKEY, LPCTSTR ); + + +STDAPI +AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata + , IFilterMapper2 * pIFM2 + , BOOL bRegister ); + diff --git a/src/thirdparty/BaseClasses/dxmperf.h b/src/thirdparty/BaseClasses/dxmperf.h index dc58ad72383..54a21203b83 100644 --- a/src/thirdparty/BaseClasses/dxmperf.h +++ b/src/thirdparty/BaseClasses/dxmperf.h @@ -1,250 +1,250 @@ -//------------------------------------------------------------------------------ -// File: DXMPerf.h -// -// Desc: Macros for DirectShow performance logging. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef _DXMPERF_H_ -#define _DXMPERF_H_ - -#include -#include "perflog.h" - -#ifdef _IA64_ -extern "C" unsigned __int64 __getReg( int whichReg ); -#pragma intrinsic(__getReg) -#endif // _IA64_ - - -inline ULONGLONG _RDTSC( void ) { -#ifdef _X86_ - LARGE_INTEGER li; - __asm { - _emit 0x0F - _emit 0x31 - mov li.LowPart,eax - mov li.HighPart,edx - } - return li.QuadPart; - -#if 0 // This isn't tested yet - -#elif defined (_IA64_) - -#define INL_REGID_APITC 3116 - return __getReg( INL_REGID_APITC ); - -#endif // 0 - -#else // unsupported platform - // not implemented on non x86/IA64 platforms - return 0; -#endif // _X86_/_IA64_ -} - -#define DXMPERF_VIDEOREND 0x00000001 -#define DXMPERF_AUDIOGLITCH 0x00000002 -//#define GETTIME_BIT 0x00000001 -//#define AUDIOREND_BIT 0x00000004 -//#define FRAMEDROP_BIT 0x00000008 -#define AUDIOBREAK_BIT 0x00000010 -#define DXMPERF_AUDIORECV 0x00000020 -#define DXMPERF_AUDIOSLAVE 0x00000040 -#define DXMPERF_AUDIOBREAK 0x00000080 - -#define PERFLOG_CTOR( name, iface ) -#define PERFLOG_DTOR( name, iface ) -#define PERFLOG_DELIVER( name, source, dest, sample, pmt ) -#define PERFLOG_RECEIVE( name, source, dest, sample, pmt ) -#define PERFLOG_RUN( name, iface, time, oldstate ) -#define PERFLOG_PAUSE( name, iface, oldstate ) -#define PERFLOG_STOP( name, iface, oldstate ) -#define PERFLOG_JOINGRAPH( name, iface, graph ) -#define PERFLOG_GETBUFFER( allocator, sample ) -#define PERFLOG_RELBUFFER( allocator, sample ) -#define PERFLOG_CONNECT( connector, connectee, status, pmt ) -#define PERFLOG_RXCONNECT( connector, connectee, status, pmt ) -#define PERFLOG_DISCONNECT( disconnector, disconnectee, status ) - -#define PERFLOG_GETTIME( clock, time ) /*{ \ - PERFINFO_WMI_GETTIME perfData; \ - if (NULL != g_pTraceEvent) { \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_GETTIME; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (ULONGLONG) (time); \ - if (g_perfMasks[GETTIME_INDEX] & GETTIME_BIT) \ - (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ - } \ - }*/ - -#define PERFLOG_AUDIOREND( clocktime, sampletime, psample, bytetime, cbytes ) /*{ \ - PERFINFO_WMI_AVREND perfData; \ - if (NULL != g_pTraceEvent) { \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOREND; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (clocktime); \ - perfData.data.sampleTime = (sampletime); \ - if (g_perfMasks[AUDIOREND_INDEX] & AUDIOREND_BIT) \ - (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ - } \ - }*/ - -#define PERFLOG_AUDIORECV(StreamTime,SampleStart,SampleStop,Discontinuity,Duration) \ - if (PerflogEnableFlags & DXMPERF_AUDIORECV) { \ - PERFINFO_WMI_AUDIORECV perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIORECV; \ - perfData.data.streamTime = StreamTime; \ - perfData.data.sampleStart = SampleStart; \ - perfData.data.sampleStop = SampleStop; \ - perfData.data.discontinuity = Discontinuity; \ - perfData.data.hwduration = Duration; \ - PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_AUDIOSLAVE(MasterClock,SlaveClock,ErrorAccum,LastHighErrorSeen,LastLowErrorSeen) \ - if (PerflogEnableFlags & DXMPERF_AUDIOSLAVE) { \ - PERFINFO_WMI_AUDIOSLAVE perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOSLAVE; \ - perfData.data.masterClock = MasterClock; \ - perfData.data.slaveClock = SlaveClock; \ - perfData.data.errorAccum = ErrorAccum; \ - perfData.data.lastHighErrorSeen = LastHighErrorSeen;\ - perfData.data.lastLowErrorSeen = LastLowErrorSeen; \ - PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_AUDIOADDBREAK(IterNextWrite,OffsetNextWrite,IterWrite,OffsetWrite) \ - if (PerflogEnableFlags & DXMPERF_AUDIOBREAK) { \ - PERFINFO_WMI_AUDIOADDBREAK perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOADDBREAK; \ - perfData.data.iterNextWrite = IterNextWrite; \ - perfData.data.offsetNextWrite = OffsetNextWrite; \ - perfData.data.iterWrite = IterWrite; \ - perfData.data.offsetWrite = OffsetWrite; \ - PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_VIDEOREND( sampletime, clocktime, psample ) \ - if (PerflogEnableFlags & DXMPERF_VIDEOREND) { \ - PERFINFO_WMI_AVREND perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_VIDEOREND; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (clocktime); \ - perfData.data.sampleTime = (sampletime); \ - PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_AUDIOGLITCH( instance, glitchtype, currenttime, previoustime ) \ - if (PerflogEnableFlags & DXMPERF_AUDIOGLITCH) { \ - PERFINFO_WMI_AUDIOGLITCH perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_DSOUNDGLITCH; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.glitchType = (glitchtype); \ - perfData.data.sampleTime = (currenttime); \ - perfData.data.previousTime = (previoustime); \ - perfData.data.instanceId = (instance); \ - PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ - } - -#define PERFLOG_FRAMEDROP( sampletime, clocktime, psample, renderer ) /*{ \ - PERFINFO_WMI_FRAMEDROP perfData; \ - if (NULL != g_pTraceEvent) { \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_FRAMEDROP; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (clocktime); \ - perfData.data.frameTime = (sampletime); \ - if (g_perfMasks[FRAMEDROP_INDEX] & FRAMEDROP_BIT) \ - (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ - } \ - }*/ - -/* -#define PERFLOG_AUDIOBREAK( nextwrite, writepos, msecs ) { \ - PERFINFO_WMI_AUDIOBREAK perfData; \ - if (NULL != g_pTraceEvent) { \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOBREAK; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (writepos); \ - perfData.data.sampleTime = (nextwrite); \ - perfData.data.sampleDuration = (msecs); \ - if (g_perfMasks[AUDIOBREAK_INDEX] & AUDIOBREAK_BIT) \ - (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ - } \ - } -*/ - -#define PERFLOG_AUDIOBREAK( nextwrite, writepos, msecs ) \ - if (PerflogEnableFlags & AUDIOBREAK_BIT) { \ - PERFINFO_WMI_AUDIOBREAK perfData; \ - memset( &perfData, 0, sizeof( perfData ) ); \ - perfData.header.Size = sizeof( perfData ); \ - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ - perfData.header.Guid = GUID_AUDIOBREAK; \ - perfData.data.cycleCounter = _RDTSC(); \ - perfData.data.dshowClock = (writepos); \ - perfData.data.sampleTime = (nextwrite); \ - perfData.data.sampleDuration = (msecs); \ - PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ - } \ - - -inline -VOID PERFLOG_STREAMTRACE( - ULONG Level, - ULONG Id, - ULONGLONG DShowClock, - ULONGLONG Data1, - ULONGLONG Data2, - ULONGLONG Data3, - ULONGLONG Data4 - ) -{ - if (Level <= PerflogModuleLevel) - { - PERFINFO_WMI_STREAMTRACE perfData; - memset( &perfData, 0, sizeof( perfData ) ); - perfData.header.Size = sizeof( perfData ); - perfData.header.Flags = WNODE_FLAG_TRACED_GUID; - perfData.header.Guid = GUID_STREAMTRACE; - perfData.data.dshowClock = DShowClock; - perfData.data.id = Id; - perfData.data.data[0] = Data1; - perfData.data.data[1] = Data2; - perfData.data.data[2] = Data3; - perfData.data.data[3] = Data4; - PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); - } -} - - -#endif // _DXMPERF_H_ +//------------------------------------------------------------------------------ +// File: DXMPerf.h +// +// Desc: Macros for DirectShow performance logging. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef _DXMPERF_H_ +#define _DXMPERF_H_ + +#include +#include "perflog.h" + +#ifdef _IA64_ +extern "C" unsigned __int64 __getReg( int whichReg ); +#pragma intrinsic(__getReg) +#endif // _IA64_ + + +inline ULONGLONG _RDTSC( void ) { +#ifdef _X86_ + LARGE_INTEGER li; + __asm { + _emit 0x0F + _emit 0x31 + mov li.LowPart,eax + mov li.HighPart,edx + } + return li.QuadPart; + +#if 0 // This isn't tested yet + +#elif defined (_IA64_) + +#define INL_REGID_APITC 3116 + return __getReg( INL_REGID_APITC ); + +#endif // 0 + +#else // unsupported platform + // not implemented on non x86/IA64 platforms + return 0; +#endif // _X86_/_IA64_ +} + +#define DXMPERF_VIDEOREND 0x00000001 +#define DXMPERF_AUDIOGLITCH 0x00000002 +//#define GETTIME_BIT 0x00000001 +//#define AUDIOREND_BIT 0x00000004 +//#define FRAMEDROP_BIT 0x00000008 +#define AUDIOBREAK_BIT 0x00000010 +#define DXMPERF_AUDIORECV 0x00000020 +#define DXMPERF_AUDIOSLAVE 0x00000040 +#define DXMPERF_AUDIOBREAK 0x00000080 + +#define PERFLOG_CTOR( name, iface ) +#define PERFLOG_DTOR( name, iface ) +#define PERFLOG_DELIVER( name, source, dest, sample, pmt ) +#define PERFLOG_RECEIVE( name, source, dest, sample, pmt ) +#define PERFLOG_RUN( name, iface, time, oldstate ) +#define PERFLOG_PAUSE( name, iface, oldstate ) +#define PERFLOG_STOP( name, iface, oldstate ) +#define PERFLOG_JOINGRAPH( name, iface, graph ) +#define PERFLOG_GETBUFFER( allocator, sample ) +#define PERFLOG_RELBUFFER( allocator, sample ) +#define PERFLOG_CONNECT( connector, connectee, status, pmt ) +#define PERFLOG_RXCONNECT( connector, connectee, status, pmt ) +#define PERFLOG_DISCONNECT( disconnector, disconnectee, status ) + +#define PERFLOG_GETTIME( clock, time ) /*{ \ + PERFINFO_WMI_GETTIME perfData; \ + if (NULL != g_pTraceEvent) { \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_GETTIME; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (ULONGLONG) (time); \ + if (g_perfMasks[GETTIME_INDEX] & GETTIME_BIT) \ + (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ + } \ + }*/ + +#define PERFLOG_AUDIOREND( clocktime, sampletime, psample, bytetime, cbytes ) /*{ \ + PERFINFO_WMI_AVREND perfData; \ + if (NULL != g_pTraceEvent) { \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOREND; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (clocktime); \ + perfData.data.sampleTime = (sampletime); \ + if (g_perfMasks[AUDIOREND_INDEX] & AUDIOREND_BIT) \ + (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ + } \ + }*/ + +#define PERFLOG_AUDIORECV(StreamTime,SampleStart,SampleStop,Discontinuity,Duration) \ + if (PerflogEnableFlags & DXMPERF_AUDIORECV) { \ + PERFINFO_WMI_AUDIORECV perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIORECV; \ + perfData.data.streamTime = StreamTime; \ + perfData.data.sampleStart = SampleStart; \ + perfData.data.sampleStop = SampleStop; \ + perfData.data.discontinuity = Discontinuity; \ + perfData.data.hwduration = Duration; \ + PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_AUDIOSLAVE(MasterClock,SlaveClock,ErrorAccum,LastHighErrorSeen,LastLowErrorSeen) \ + if (PerflogEnableFlags & DXMPERF_AUDIOSLAVE) { \ + PERFINFO_WMI_AUDIOSLAVE perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOSLAVE; \ + perfData.data.masterClock = MasterClock; \ + perfData.data.slaveClock = SlaveClock; \ + perfData.data.errorAccum = ErrorAccum; \ + perfData.data.lastHighErrorSeen = LastHighErrorSeen;\ + perfData.data.lastLowErrorSeen = LastLowErrorSeen; \ + PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_AUDIOADDBREAK(IterNextWrite,OffsetNextWrite,IterWrite,OffsetWrite) \ + if (PerflogEnableFlags & DXMPERF_AUDIOBREAK) { \ + PERFINFO_WMI_AUDIOADDBREAK perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOADDBREAK; \ + perfData.data.iterNextWrite = IterNextWrite; \ + perfData.data.offsetNextWrite = OffsetNextWrite; \ + perfData.data.iterWrite = IterWrite; \ + perfData.data.offsetWrite = OffsetWrite; \ + PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_VIDEOREND( sampletime, clocktime, psample ) \ + if (PerflogEnableFlags & DXMPERF_VIDEOREND) { \ + PERFINFO_WMI_AVREND perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_VIDEOREND; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (clocktime); \ + perfData.data.sampleTime = (sampletime); \ + PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_AUDIOGLITCH( instance, glitchtype, currenttime, previoustime ) \ + if (PerflogEnableFlags & DXMPERF_AUDIOGLITCH) { \ + PERFINFO_WMI_AUDIOGLITCH perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_DSOUNDGLITCH; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.glitchType = (glitchtype); \ + perfData.data.sampleTime = (currenttime); \ + perfData.data.previousTime = (previoustime); \ + perfData.data.instanceId = (instance); \ + PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ + } + +#define PERFLOG_FRAMEDROP( sampletime, clocktime, psample, renderer ) /*{ \ + PERFINFO_WMI_FRAMEDROP perfData; \ + if (NULL != g_pTraceEvent) { \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_FRAMEDROP; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (clocktime); \ + perfData.data.frameTime = (sampletime); \ + if (g_perfMasks[FRAMEDROP_INDEX] & FRAMEDROP_BIT) \ + (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ + } \ + }*/ + +/* +#define PERFLOG_AUDIOBREAK( nextwrite, writepos, msecs ) { \ + PERFINFO_WMI_AUDIOBREAK perfData; \ + if (NULL != g_pTraceEvent) { \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOBREAK; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (writepos); \ + perfData.data.sampleTime = (nextwrite); \ + perfData.data.sampleDuration = (msecs); \ + if (g_perfMasks[AUDIOBREAK_INDEX] & AUDIOBREAK_BIT) \ + (*g_pTraceEvent)( g_traceHandle, (PEVENT_TRACE_HEADER) &perfData ); \ + } \ + } +*/ + +#define PERFLOG_AUDIOBREAK( nextwrite, writepos, msecs ) \ + if (PerflogEnableFlags & AUDIOBREAK_BIT) { \ + PERFINFO_WMI_AUDIOBREAK perfData; \ + memset( &perfData, 0, sizeof( perfData ) ); \ + perfData.header.Size = sizeof( perfData ); \ + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; \ + perfData.header.Guid = GUID_AUDIOBREAK; \ + perfData.data.cycleCounter = _RDTSC(); \ + perfData.data.dshowClock = (writepos); \ + perfData.data.sampleTime = (nextwrite); \ + perfData.data.sampleDuration = (msecs); \ + PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData); \ + } \ + + +inline +VOID PERFLOG_STREAMTRACE( + ULONG Level, + ULONG Id, + ULONGLONG DShowClock, + ULONGLONG Data1, + ULONGLONG Data2, + ULONGLONG Data3, + ULONGLONG Data4 + ) +{ + if (Level <= PerflogModuleLevel) + { + PERFINFO_WMI_STREAMTRACE perfData; + memset( &perfData, 0, sizeof( perfData ) ); + perfData.header.Size = sizeof( perfData ); + perfData.header.Flags = WNODE_FLAG_TRACED_GUID; + perfData.header.Guid = GUID_STREAMTRACE; + perfData.data.dshowClock = DShowClock; + perfData.data.id = Id; + perfData.data.data[0] = Data1; + perfData.data.data[1] = Data2; + perfData.data.data[2] = Data3; + perfData.data.data[3] = Data4; + PerflogTraceEvent((PEVENT_TRACE_HEADER) &perfData); + } +} + + +#endif // _DXMPERF_H_ diff --git a/src/thirdparty/BaseClasses/fourcc.h b/src/thirdparty/BaseClasses/fourcc.h index f4f71e9621f..19c0fcdbc56 100644 --- a/src/thirdparty/BaseClasses/fourcc.h +++ b/src/thirdparty/BaseClasses/fourcc.h @@ -1,101 +1,101 @@ -//------------------------------------------------------------------------------ -// File: FourCC.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// FOURCCMap -// -// provides a mapping between old-style multimedia format DWORDs -// and new-style GUIDs. -// -// A range of 4 billion GUIDs has been allocated to ensure that this -// mapping can be done straightforwardly one-to-one in both directions. -// -// January 95 - - -#ifndef __FOURCC__ -#define __FOURCC__ - - -// Multimedia format types are marked with DWORDs built from four 8-bit -// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include -// a subtype GUID. In order to simplify the mapping, GUIDs in the range: -// XXXXXXXX-0000-0010-8000-00AA00389B71 -// are reserved for FOURCCs. - -class FOURCCMap : public GUID -{ - -public: - FOURCCMap(); - FOURCCMap(DWORD Fourcc); - FOURCCMap(const GUID *); - - - DWORD GetFOURCC(void); - void SetFOURCC(DWORD fourcc); - void SetFOURCC(const GUID *); - -private: - void InitGUID(); -}; - -#define GUID_Data2 0 -#define GUID_Data3 0x10 -#define GUID_Data4_1 0xaa000080 -#define GUID_Data4_2 0x719b3800 - -inline void -FOURCCMap::InitGUID() { - Data2 = GUID_Data2; - Data3 = GUID_Data3; - ((DWORD *)Data4)[0] = GUID_Data4_1; - ((DWORD *)Data4)[1] = GUID_Data4_2; -} - -inline -FOURCCMap::FOURCCMap() { - InitGUID(); - SetFOURCC( DWORD(0)); -} - -inline -FOURCCMap::FOURCCMap(DWORD fourcc) -{ - InitGUID(); - SetFOURCC(fourcc); -} - -inline -FOURCCMap::FOURCCMap(const GUID * pGuid) -{ - InitGUID(); - SetFOURCC(pGuid); -} - -inline void -FOURCCMap::SetFOURCC(const GUID * pGuid) -{ - FOURCCMap * p = (FOURCCMap*) pGuid; - SetFOURCC(p->GetFOURCC()); -} - -inline void -FOURCCMap::SetFOURCC(DWORD fourcc) -{ - Data1 = fourcc; -} - -inline DWORD -FOURCCMap::GetFOURCC(void) -{ - return Data1; -} - -#endif /* __FOURCC__ */ - +//------------------------------------------------------------------------------ +// File: FourCC.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// FOURCCMap +// +// provides a mapping between old-style multimedia format DWORDs +// and new-style GUIDs. +// +// A range of 4 billion GUIDs has been allocated to ensure that this +// mapping can be done straightforwardly one-to-one in both directions. +// +// January 95 + + +#ifndef __FOURCC__ +#define __FOURCC__ + + +// Multimedia format types are marked with DWORDs built from four 8-bit +// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include +// a subtype GUID. In order to simplify the mapping, GUIDs in the range: +// XXXXXXXX-0000-0010-8000-00AA00389B71 +// are reserved for FOURCCs. + +class FOURCCMap : public GUID +{ + +public: + FOURCCMap(); + FOURCCMap(DWORD Fourcc); + FOURCCMap(const GUID *); + + + DWORD GetFOURCC(void); + void SetFOURCC(DWORD fourcc); + void SetFOURCC(const GUID *); + +private: + void InitGUID(); +}; + +#define GUID_Data2 0 +#define GUID_Data3 0x10 +#define GUID_Data4_1 0xaa000080 +#define GUID_Data4_2 0x719b3800 + +inline void +FOURCCMap::InitGUID() { + Data2 = GUID_Data2; + Data3 = GUID_Data3; + ((DWORD *)Data4)[0] = GUID_Data4_1; + ((DWORD *)Data4)[1] = GUID_Data4_2; +} + +inline +FOURCCMap::FOURCCMap() { + InitGUID(); + SetFOURCC( DWORD(0)); +} + +inline +FOURCCMap::FOURCCMap(DWORD fourcc) +{ + InitGUID(); + SetFOURCC(fourcc); +} + +inline +FOURCCMap::FOURCCMap(const GUID * pGuid) +{ + InitGUID(); + SetFOURCC(pGuid); +} + +inline void +FOURCCMap::SetFOURCC(const GUID * pGuid) +{ + FOURCCMap * p = (FOURCCMap*) pGuid; + SetFOURCC(p->GetFOURCC()); +} + +inline void +FOURCCMap::SetFOURCC(DWORD fourcc) +{ + Data1 = fourcc; +} + +inline DWORD +FOURCCMap::GetFOURCC(void) +{ + return Data1; +} + +#endif /* __FOURCC__ */ + diff --git a/src/thirdparty/BaseClasses/measure.h b/src/thirdparty/BaseClasses/measure.h index 0babc86008e..a71a0753260 100644 --- a/src/thirdparty/BaseClasses/measure.h +++ b/src/thirdparty/BaseClasses/measure.h @@ -1,222 +1,222 @@ -//------------------------------------------------------------------------------ -// File: Measure.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* - The idea is to pepper the source code with interesting measurements and - have the last few thousand of these recorded in a circular buffer that - can be post-processed to give interesting numbers. - - WHAT THE LOG LOOKS LIKE: - - Time (sec) Type Delta Incident_Name - 0.055,41 NOTE -. Incident Nine - Another note - 0.055,42 NOTE 0.000,01 Incident Nine - Another note - 0.055,44 NOTE 0.000,02 Incident Nine - Another note - 0.055,45 STOP -. Incident Eight - Also random - 0.055,47 START -. Incident Seven - Random - 0.055,49 NOTE 0.000,05 Incident Nine - Another note - ------- ---------------- - 0.125,60 STOP 0.000,03 Msr_Stop - 0.125,62 START -. Msr_Start - 0.125,63 START -. Incident Two - Start/Stop - 0.125,65 STOP 0.000,03 Msr_Start - 0.125,66 START -. Msr_Stop - 0.125,68 STOP 0.000,05 Incident Two - Start/Stop - 0.125,70 STOP 0.000,04 Msr_Stop - 0.125,72 START -. Msr_Start - 0.125,73 START -. Incident Two - Start/Stop - 0.125,75 STOP 0.000,03 Msr_Start - 0.125,77 START -. Msr_Stop - 0.125,78 STOP 0.000,05 Incident Two - Start/Stop - 0.125,80 STOP 0.000,03 Msr_Stop - 0.125,81 NOTE -. Incident Three - single Note - 0.125,83 START -. Incident Four - Start, no stop - 0.125,85 START -. Incident Five - Single Start/Stop - 0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop - -Number Average StdDev Smallest Largest Incident_Name - 10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note - 50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop - 1 -. -. -. -. Incident Three - single Note - 0 -. -. -. -. Incident Four - Start, no stop - 1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop - 0 -. -. -. -. Incident Six - zero occurrences - 100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random - 100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random - 5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note - 10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note - 50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start - 50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop - - WHAT IT MEANS: - The log shows what happened and when. Each line shows the time at which - something happened (see WHAT YOU CODE below) what it was that happened - and (if approporate) the time since the corresponding previous event - (that's the delta column). - - The statistics show how many times each event occurred, what the average - delta time was, also the standard deviation, largest and smalles delta. - - WHAT YOU CODE: - - Before anything else executes: - register your ids - - int id1 = Msr_Register("Incident One - Note"); - int id2 = Msr_Register("Incident Two - Start/Stop"); - int id3 = Msr_Register("Incident Three - single Note"); - etc. - - At interesting moments: - - // To measure a repetitive event - e.g. end of bitblt to screen - Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!" - - or - - // To measure an elapsed time e.g. time taken to decode an MPEG B-frame - Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame" - . . . - MsrStop(Id2); // "Finished MPEG decode" - - At the end: - - HANDLE hFile; - hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - Msr_Dump(hFile); // This writes the log out to the file - CloseHandle(hFile); - - or - - Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... )); - // but if you are writing it out to the debugger - // then the times are probably all garbage because - // the debugger can make things run awfully slow. - - A given id should be used either for start / stop or Note calls. If Notes - are mixed in with Starts and Stops their statistics will be gibberish. - - If you code the calls in upper case i.e. MSR_START(idMunge); then you get - macros which will turn into nothing unless PERF is defined. - - You can reset the statistical counts for a given id by calling Reset(Id). - They are reset by default at the start. - It logs Reset as a special incident, so you can see it in the log. - - The log is a circular buffer in storage (to try to minimise disk I/O). - It overwrites the oldest entries once full. The statistics include ALL - incidents since the last Reset, whether still visible in the log or not. -*/ - -#ifndef __MEASURE__ -#define __MEASURE__ - -#ifdef PERF -#define MSR_INIT() Msr_Init() -#define MSR_TERMINATE() Msr_Terminate() -#define MSR_REGISTER(a) Msr_Register(a) -#define MSR_RESET(a) Msr_Reset(a) -#define MSR_CONTROL(a) Msr_Control(a) -#define MSR_START(a) Msr_Start(a) -#define MSR_STOP(a) Msr_Stop(a) -#define MSR_NOTE(a) Msr_Note(a) -#define MSR_INTEGER(a,b) Msr_Integer(a,b) -#define MSR_DUMP(a) Msr_Dump(a) -#define MSR_DUMPSTATS(a) Msr_DumpStats(a) -#else -#define MSR_INIT() ((void)0) -#define MSR_TERMINATE() ((void)0) -#define MSR_REGISTER(a) 0 -#define MSR_RESET(a) ((void)0) -#define MSR_CONTROL(a) ((void)0) -#define MSR_START(a) ((void)0) -#define MSR_STOP(a) ((void)0) -#define MSR_NOTE(a) ((void)0) -#define MSR_INTEGER(a,b) ((void)0) -#define MSR_DUMP(a) ((void)0) -#define MSR_DUMPSTATS(a) ((void)0) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// This must be called first - (called by the DllEntry) - -void WINAPI Msr_Init(void); - - -// Call this last to clean up (or just let it fall off the end - who cares?) - -void WINAPI Msr_Terminate(void); - - -// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note -// everything that's logged is called an "incident". - -int WINAPI Msr_Register(__in LPTSTR Incident); - - -// Reset the statistical counts for an incident - -void WINAPI Msr_Reset(int Id); - - -// Reset all the counts for all incidents -#define MSR_RESET_ALL 0 -#define MSR_PAUSE 1 -#define MSR_RUN 2 - -void WINAPI Msr_Control(int iAction); - - -// log the start of an operation - -void WINAPI Msr_Start(int Id); - - -// log the end of an operation - -void WINAPI Msr_Stop(int Id); - - -// log a one-off or repetitive operation - -void WINAPI Msr_Note(int Id); - - -// log an integer (on which we can see statistics later) -void WINAPI Msr_Integer(int Id, int n); - - -// print out all the vaialable log (it may have wrapped) and then the statistics. -// When the log wraps you lose log but the statistics are still complete. -// hFIle==NULL => use DbgLog -// otherwise hFile must have come from CreateFile or OpenFile. - -void WINAPI Msr_Dump(HANDLE hFile); - - -// just dump the statistics - never mind the log - -void WINAPI Msr_DumpStats(HANDLE hFile); - -// Type definitions in case you want to declare a pointer to the dump functions -// (makes it a trifle easier to do dynamic linking -// i.e. LoadModule, GetProcAddress and call that) - -// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever -typedef void WINAPI MSR_DUMPPROC(HANDLE hFile); -typedef void WINAPI MSR_CONTROLPROC(int iAction); - - -#ifdef __cplusplus -} -#endif - -#endif // __MEASURE__ +//------------------------------------------------------------------------------ +// File: Measure.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* + The idea is to pepper the source code with interesting measurements and + have the last few thousand of these recorded in a circular buffer that + can be post-processed to give interesting numbers. + + WHAT THE LOG LOOKS LIKE: + + Time (sec) Type Delta Incident_Name + 0.055,41 NOTE -. Incident Nine - Another note + 0.055,42 NOTE 0.000,01 Incident Nine - Another note + 0.055,44 NOTE 0.000,02 Incident Nine - Another note + 0.055,45 STOP -. Incident Eight - Also random + 0.055,47 START -. Incident Seven - Random + 0.055,49 NOTE 0.000,05 Incident Nine - Another note + ------- ---------------- + 0.125,60 STOP 0.000,03 Msr_Stop + 0.125,62 START -. Msr_Start + 0.125,63 START -. Incident Two - Start/Stop + 0.125,65 STOP 0.000,03 Msr_Start + 0.125,66 START -. Msr_Stop + 0.125,68 STOP 0.000,05 Incident Two - Start/Stop + 0.125,70 STOP 0.000,04 Msr_Stop + 0.125,72 START -. Msr_Start + 0.125,73 START -. Incident Two - Start/Stop + 0.125,75 STOP 0.000,03 Msr_Start + 0.125,77 START -. Msr_Stop + 0.125,78 STOP 0.000,05 Incident Two - Start/Stop + 0.125,80 STOP 0.000,03 Msr_Stop + 0.125,81 NOTE -. Incident Three - single Note + 0.125,83 START -. Incident Four - Start, no stop + 0.125,85 START -. Incident Five - Single Start/Stop + 0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop + +Number Average StdDev Smallest Largest Incident_Name + 10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note + 50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop + 1 -. -. -. -. Incident Three - single Note + 0 -. -. -. -. Incident Four - Start, no stop + 1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop + 0 -. -. -. -. Incident Six - zero occurrences + 100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random + 100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random + 5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note + 10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note + 50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start + 50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop + + WHAT IT MEANS: + The log shows what happened and when. Each line shows the time at which + something happened (see WHAT YOU CODE below) what it was that happened + and (if approporate) the time since the corresponding previous event + (that's the delta column). + + The statistics show how many times each event occurred, what the average + delta time was, also the standard deviation, largest and smalles delta. + + WHAT YOU CODE: + + Before anything else executes: - register your ids + + int id1 = Msr_Register("Incident One - Note"); + int id2 = Msr_Register("Incident Two - Start/Stop"); + int id3 = Msr_Register("Incident Three - single Note"); + etc. + + At interesting moments: + + // To measure a repetitive event - e.g. end of bitblt to screen + Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!" + + or + + // To measure an elapsed time e.g. time taken to decode an MPEG B-frame + Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame" + . . . + MsrStop(Id2); // "Finished MPEG decode" + + At the end: + + HANDLE hFile; + hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + Msr_Dump(hFile); // This writes the log out to the file + CloseHandle(hFile); + + or + + Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... )); + // but if you are writing it out to the debugger + // then the times are probably all garbage because + // the debugger can make things run awfully slow. + + A given id should be used either for start / stop or Note calls. If Notes + are mixed in with Starts and Stops their statistics will be gibberish. + + If you code the calls in upper case i.e. MSR_START(idMunge); then you get + macros which will turn into nothing unless PERF is defined. + + You can reset the statistical counts for a given id by calling Reset(Id). + They are reset by default at the start. + It logs Reset as a special incident, so you can see it in the log. + + The log is a circular buffer in storage (to try to minimise disk I/O). + It overwrites the oldest entries once full. The statistics include ALL + incidents since the last Reset, whether still visible in the log or not. +*/ + +#ifndef __MEASURE__ +#define __MEASURE__ + +#ifdef PERF +#define MSR_INIT() Msr_Init() +#define MSR_TERMINATE() Msr_Terminate() +#define MSR_REGISTER(a) Msr_Register(a) +#define MSR_RESET(a) Msr_Reset(a) +#define MSR_CONTROL(a) Msr_Control(a) +#define MSR_START(a) Msr_Start(a) +#define MSR_STOP(a) Msr_Stop(a) +#define MSR_NOTE(a) Msr_Note(a) +#define MSR_INTEGER(a,b) Msr_Integer(a,b) +#define MSR_DUMP(a) Msr_Dump(a) +#define MSR_DUMPSTATS(a) Msr_DumpStats(a) +#else +#define MSR_INIT() ((void)0) +#define MSR_TERMINATE() ((void)0) +#define MSR_REGISTER(a) 0 +#define MSR_RESET(a) ((void)0) +#define MSR_CONTROL(a) ((void)0) +#define MSR_START(a) ((void)0) +#define MSR_STOP(a) ((void)0) +#define MSR_NOTE(a) ((void)0) +#define MSR_INTEGER(a,b) ((void)0) +#define MSR_DUMP(a) ((void)0) +#define MSR_DUMPSTATS(a) ((void)0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// This must be called first - (called by the DllEntry) + +void WINAPI Msr_Init(void); + + +// Call this last to clean up (or just let it fall off the end - who cares?) + +void WINAPI Msr_Terminate(void); + + +// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note +// everything that's logged is called an "incident". + +int WINAPI Msr_Register(__in LPTSTR Incident); + + +// Reset the statistical counts for an incident + +void WINAPI Msr_Reset(int Id); + + +// Reset all the counts for all incidents +#define MSR_RESET_ALL 0 +#define MSR_PAUSE 1 +#define MSR_RUN 2 + +void WINAPI Msr_Control(int iAction); + + +// log the start of an operation + +void WINAPI Msr_Start(int Id); + + +// log the end of an operation + +void WINAPI Msr_Stop(int Id); + + +// log a one-off or repetitive operation + +void WINAPI Msr_Note(int Id); + + +// log an integer (on which we can see statistics later) +void WINAPI Msr_Integer(int Id, int n); + + +// print out all the vaialable log (it may have wrapped) and then the statistics. +// When the log wraps you lose log but the statistics are still complete. +// hFIle==NULL => use DbgLog +// otherwise hFile must have come from CreateFile or OpenFile. + +void WINAPI Msr_Dump(HANDLE hFile); + + +// just dump the statistics - never mind the log + +void WINAPI Msr_DumpStats(HANDLE hFile); + +// Type definitions in case you want to declare a pointer to the dump functions +// (makes it a trifle easier to do dynamic linking +// i.e. LoadModule, GetProcAddress and call that) + +// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever +typedef void WINAPI MSR_DUMPPROC(HANDLE hFile); +typedef void WINAPI MSR_CONTROLPROC(int iAction); + + +#ifdef __cplusplus +} +#endif + +#endif // __MEASURE__ diff --git a/src/thirdparty/BaseClasses/msgthrd.h b/src/thirdparty/BaseClasses/msgthrd.h index 208f03c82d6..45adc01cf09 100644 --- a/src/thirdparty/BaseClasses/msgthrd.h +++ b/src/thirdparty/BaseClasses/msgthrd.h @@ -1,120 +1,120 @@ -//------------------------------------------------------------------------------ -// File: MsgThrd.h -// -// Desc: DirectShow base classes - provides support for a worker thread -// class to which one can asynchronously post messages. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Message class - really just a structure. -// -class CMsg { -public: - UINT uMsg; - DWORD dwFlags; - LPVOID lpParam; - CAMEvent *pEvent; - - CMsg(UINT u, DWORD dw, __inout_opt LPVOID lp, __in_opt CAMEvent *pEvnt) - : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {} - - CMsg() - : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {} -}; - -// This is the actual thread class. It exports all the usual thread control -// functions. The created thread is different from a normal WIN32 thread in -// that it is prompted to perform particaular tasks by responding to messages -// posted to its message queue. -// -class AM_NOVTABLE CMsgThread { -private: - static DWORD WINAPI DefaultThreadProc(__inout LPVOID lpParam); - DWORD m_ThreadId; - HANDLE m_hThread; - -protected: - - // if you want to override GetThreadMsg to block on other things - // as well as this queue, you need access to this - CGenericList m_ThreadQueue; - CCritSec m_Lock; - HANDLE m_hSem; - LONG m_lWaiting; - -public: - CMsgThread() - : m_ThreadId(0), - m_hThread(NULL), - m_lWaiting(0), - m_hSem(NULL), - // make a list with a cache of 5 items - m_ThreadQueue(NAME("MsgThread list"), 5) - { - } - - ~CMsgThread(); - // override this if you want to block on other things as well - // as the message loop - void virtual GetThreadMsg(__out CMsg *msg); - - // override this if you want to do something on thread startup - virtual void OnThreadInit() { - }; - - BOOL CreateThread(); - - BOOL WaitForThreadExit(__out LPDWORD lpdwExitCode) { - if (m_hThread != NULL) { - WaitForSingleObject(m_hThread, INFINITE); - return GetExitCodeThread(m_hThread, lpdwExitCode); - } - return FALSE; - } - - DWORD ResumeThread() { - return ::ResumeThread(m_hThread); - } - - DWORD SuspendThread() { - return ::SuspendThread(m_hThread); - } - - int GetThreadPriority() { - return ::GetThreadPriority(m_hThread); - } - - BOOL SetThreadPriority(int nPriority) { - return ::SetThreadPriority(m_hThread, nPriority); - } - - HANDLE GetThreadHandle() { - return m_hThread; - } - - DWORD GetThreadId() { - return m_ThreadId; - } - - - void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags, - __in_opt LPVOID lpMsgParam, __in_opt CAMEvent *pEvent = NULL) { - CAutoLock lck(&m_Lock); - CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent); - m_ThreadQueue.AddTail(pMsg); - if (m_lWaiting != 0) { - ReleaseSemaphore(m_hSem, m_lWaiting, 0); - m_lWaiting = 0; - } - } - - // This is the function prototype of the function that the client - // supplies. It is always called on the created thread, never on - // the creator thread. - // - virtual LRESULT ThreadMessageProc( - UINT uMsg, DWORD dwFlags, __inout_opt LPVOID lpParam, __in_opt CAMEvent *pEvent) = 0; -}; - +//------------------------------------------------------------------------------ +// File: MsgThrd.h +// +// Desc: DirectShow base classes - provides support for a worker thread +// class to which one can asynchronously post messages. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Message class - really just a structure. +// +class CMsg { +public: + UINT uMsg; + DWORD dwFlags; + LPVOID lpParam; + CAMEvent *pEvent; + + CMsg(UINT u, DWORD dw, __inout_opt LPVOID lp, __in_opt CAMEvent *pEvnt) + : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {} + + CMsg() + : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {} +}; + +// This is the actual thread class. It exports all the usual thread control +// functions. The created thread is different from a normal WIN32 thread in +// that it is prompted to perform particaular tasks by responding to messages +// posted to its message queue. +// +class AM_NOVTABLE CMsgThread { +private: + static DWORD WINAPI DefaultThreadProc(__inout LPVOID lpParam); + DWORD m_ThreadId; + HANDLE m_hThread; + +protected: + + // if you want to override GetThreadMsg to block on other things + // as well as this queue, you need access to this + CGenericList m_ThreadQueue; + CCritSec m_Lock; + HANDLE m_hSem; + LONG m_lWaiting; + +public: + CMsgThread() + : m_ThreadId(0), + m_hThread(NULL), + m_lWaiting(0), + m_hSem(NULL), + // make a list with a cache of 5 items + m_ThreadQueue(NAME("MsgThread list"), 5) + { + } + + ~CMsgThread(); + // override this if you want to block on other things as well + // as the message loop + void virtual GetThreadMsg(__out CMsg *msg); + + // override this if you want to do something on thread startup + virtual void OnThreadInit() { + }; + + BOOL CreateThread(); + + BOOL WaitForThreadExit(__out LPDWORD lpdwExitCode) { + if (m_hThread != NULL) { + WaitForSingleObject(m_hThread, INFINITE); + return GetExitCodeThread(m_hThread, lpdwExitCode); + } + return FALSE; + } + + DWORD ResumeThread() { + return ::ResumeThread(m_hThread); + } + + DWORD SuspendThread() { + return ::SuspendThread(m_hThread); + } + + int GetThreadPriority() { + return ::GetThreadPriority(m_hThread); + } + + BOOL SetThreadPriority(int nPriority) { + return ::SetThreadPriority(m_hThread, nPriority); + } + + HANDLE GetThreadHandle() { + return m_hThread; + } + + DWORD GetThreadId() { + return m_ThreadId; + } + + + void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags, + __in_opt LPVOID lpMsgParam, __in_opt CAMEvent *pEvent = NULL) { + CAutoLock lck(&m_Lock); + CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent); + m_ThreadQueue.AddTail(pMsg); + if (m_lWaiting != 0) { + ReleaseSemaphore(m_hSem, m_lWaiting, 0); + m_lWaiting = 0; + } + } + + // This is the function prototype of the function that the client + // supplies. It is always called on the created thread, never on + // the creator thread. + // + virtual LRESULT ThreadMessageProc( + UINT uMsg, DWORD dwFlags, __inout_opt LPVOID lpParam, __in_opt CAMEvent *pEvent) = 0; +}; + diff --git a/src/thirdparty/BaseClasses/mtype.cpp b/src/thirdparty/BaseClasses/mtype.cpp index 4fb78df7635..325c2c07cec 100644 --- a/src/thirdparty/BaseClasses/mtype.cpp +++ b/src/thirdparty/BaseClasses/mtype.cpp @@ -1,478 +1,478 @@ -//------------------------------------------------------------------------------ -// File: MType.cpp -// -// Desc: DirectShow base classes - implements a class that holds and -// manages media type information. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// helper class that derived pin objects can use to compare media -// types etc. Has same data members as the struct AM_MEDIA_TYPE defined -// in the streams IDL file, but also has (non-virtual) functions - -#include "streams.h" -#include - -CMediaType::~CMediaType(){ - FreeMediaType(*this); -} - - -CMediaType::CMediaType() -{ - InitMediaType(); -} - - -CMediaType::CMediaType(const GUID * type) -{ - InitMediaType(); - majortype = *type; -} - - -// copy constructor does a deep copy of the format block - -CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, __out_opt HRESULT* phr) -{ - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr) && (NULL != phr)) { - *phr = hr; - } -} - - -CMediaType::CMediaType(const CMediaType& rt, __out_opt HRESULT* phr) -{ - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr) && (NULL != phr)) { - *phr = hr; - } -} - - -// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate -// the following assignment operator itself, however it could introduce some -// memory conflicts and leaks in the process because the structure contains -// a dynamically allocated block (pbFormat) which it will not copy correctly - -CMediaType& -CMediaType::operator=(const AM_MEDIA_TYPE& rt) -{ - Set(rt); - return *this; -} - -CMediaType& -CMediaType::operator=(const CMediaType& rt) -{ - *this = (AM_MEDIA_TYPE &) rt; - return *this; -} - -BOOL -CMediaType::operator == (const CMediaType& rt) const -{ - // I don't believe we need to check sample size or - // temporal compression flags, since I think these must - // be represented in the type, subtype and format somehow. They - // are pulled out as separate flags so that people who don't understand - // the particular format representation can still see them, but - // they should duplicate information in the format block. - - return ((IsEqualGUID(majortype,rt.majortype) == TRUE) && - (IsEqualGUID(subtype,rt.subtype) == TRUE) && - (IsEqualGUID(formattype,rt.formattype) == TRUE) && - (cbFormat == rt.cbFormat) && - ( (cbFormat == 0) || - pbFormat != NULL && rt.pbFormat != NULL && - (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0))); -} - - -BOOL -CMediaType::operator != (const CMediaType& rt) const -{ - /* Check to see if they are equal */ - - if (*this == rt) { - return FALSE; - } - return TRUE; -} - - -HRESULT -CMediaType::Set(const CMediaType& rt) -{ - return Set((AM_MEDIA_TYPE &) rt); -} - - -HRESULT -CMediaType::Set(const AM_MEDIA_TYPE& rt) -{ - if (&rt != this) { - FreeMediaType(*this); - HRESULT hr = CopyMediaType(this, &rt); - if (FAILED(hr)) { - return E_OUTOFMEMORY; - } - } - - return S_OK; -} - - -BOOL -CMediaType::IsValid() const -{ - return (!IsEqualGUID(majortype,GUID_NULL)); -} - - -void -CMediaType::SetType(const GUID* ptype) -{ - majortype = *ptype; -} - - -void -CMediaType::SetSubtype(const GUID* ptype) -{ - subtype = *ptype; -} - - -ULONG -CMediaType::GetSampleSize() const { - if (IsFixedSize()) { - return lSampleSize; - } else { - return 0; - } -} - - -void -CMediaType::SetSampleSize(ULONG sz) { - if (sz == 0) { - SetVariableSize(); - } else { - bFixedSizeSamples = TRUE; - lSampleSize = sz; - } -} - - -void -CMediaType::SetVariableSize() { - bFixedSizeSamples = FALSE; -} - - -void -CMediaType::SetTemporalCompression(BOOL bCompressed) { - bTemporalCompression = bCompressed; -} - -BOOL -CMediaType::SetFormat(__in_bcount(cb) BYTE * pformat, ULONG cb) -{ - if (NULL == AllocFormatBuffer(cb)) - return(FALSE); - - ASSERT(pbFormat); - memcpy(pbFormat, pformat, cb); - return(TRUE); -} - - -// set the type of the media type format block, this type defines what you -// will actually find in the format pointer. For example FORMAT_VideoInfo or -// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a -// property set. Before sending out media types this should be filled in. - -void -CMediaType::SetFormatType(const GUID *pformattype) -{ - formattype = *pformattype; -} - - -// reset the format buffer - -void CMediaType::ResetFormatBuffer() -{ - if (cbFormat) { - CoTaskMemFree((PVOID)pbFormat); - } - cbFormat = 0; - pbFormat = NULL; -} - - -// allocate length bytes for the format and return a read/write pointer -// If we cannot allocate the new block of memory we return NULL leaving -// the original block of memory untouched (as does ReallocFormatBuffer) - -BYTE* -CMediaType::AllocFormatBuffer(ULONG length) -{ - ASSERT(length); - - // do the types have the same buffer size - - if (cbFormat == length) { - return pbFormat; - } - - // allocate the new format buffer - - BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); - if (pNewFormat == NULL) { - if (length <= cbFormat) return pbFormat; //reuse the old block anyway. - return NULL; - } - - // delete the old format - - if (cbFormat != 0) { - ASSERT(pbFormat); - CoTaskMemFree((PVOID)pbFormat); - } - - cbFormat = length; - pbFormat = pNewFormat; - return pbFormat; -} - - -// reallocate length bytes for the format and return a read/write pointer -// to it. We keep as much information as we can given the new buffer size -// if this fails the original format buffer is left untouched. The caller -// is responsible for ensuring the size of memory required is non zero - -BYTE* -CMediaType::ReallocFormatBuffer(ULONG length) -{ - ASSERT(length); - - // do the types have the same buffer size - - if (cbFormat == length) { - return pbFormat; - } - - // allocate the new format buffer - - BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); - if (pNewFormat == NULL) { - if (length <= cbFormat) return pbFormat; //reuse the old block anyway. - return NULL; - } - - // copy any previous format (or part of if new is smaller) - // delete the old format and replace with the new one - - if (cbFormat != 0) { - ASSERT(pbFormat); - memcpy(pNewFormat,pbFormat,std::min(length,cbFormat)); - CoTaskMemFree((PVOID)pbFormat); - } - - cbFormat = length; - pbFormat = pNewFormat; - return pNewFormat; -} - -// initialise a media type structure - -void CMediaType::InitMediaType() -{ - ZeroMemory((PVOID)this, sizeof(*this)); - lSampleSize = 1; - bFixedSizeSamples = TRUE; -} - - -// a partially specified media type can be passed to IPin::Connect -// as a constraint on the media type used in the connection. -// the type, subtype or format type can be null. -BOOL -CMediaType::IsPartiallySpecified(void) const -{ - if ((majortype == GUID_NULL) || - (formattype == GUID_NULL)) { - return TRUE; - } else { - return FALSE; - } -} - -BOOL -CMediaType::MatchesPartial(const CMediaType* ppartial) const -{ - if ((ppartial->majortype != GUID_NULL) && - (majortype != ppartial->majortype)) { - return FALSE; - } - if ((ppartial->subtype != GUID_NULL) && - (subtype != ppartial->subtype)) { - return FALSE; - } - - if (ppartial->formattype != GUID_NULL) { - // if the format block is specified then it must match exactly - if (formattype != ppartial->formattype) { - return FALSE; - } - if (cbFormat != ppartial->cbFormat) { - return FALSE; - } - if ((cbFormat != 0) && - (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) { - return FALSE; - } - } - - return TRUE; - -} - - - -// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure -// which is useful when calling IEnumMediaTypes::Next as the interface -// implementation allocates the structures which you must later delete -// the format block may also be a pointer to an interface to release - -void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt) -{ - // allow NULL pointers for coding simplicity - - if (pmt == NULL) { - return; - } - - FreeMediaType(*pmt); - CoTaskMemFree((PVOID)pmt); -} - - -// this also comes in useful when using the IEnumMediaTypes interface so -// that you can copy a media type, you can do nearly the same by creating -// a CMediaType object but as soon as it goes out of scope the destructor -// will delete the memory it allocated (this takes a copy of the memory) - -AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc) -{ - ASSERT(pSrc); - - // Allocate a block of memory for the media type - - AM_MEDIA_TYPE *pMediaType = - (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - - if (pMediaType == NULL) { - return NULL; - } - // Copy the variable length format block - - HRESULT hr = CopyMediaType(pMediaType,pSrc); - if (FAILED(hr)) { - CoTaskMemFree((PVOID)pMediaType); - return NULL; - } - - return pMediaType; -} - - -// Copy 1 media type to another - -HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) -{ - // We'll leak if we copy onto one that already exists - there's one - // case we can check like that - copying to itself. - ASSERT(pmtSource != pmtTarget); - *pmtTarget = *pmtSource; - if (pmtSource->cbFormat != 0) { - ASSERT(pmtSource->pbFormat != NULL); - pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat); - if (pmtTarget->pbFormat == NULL) { - pmtTarget->cbFormat = 0; - return E_OUTOFMEMORY; - } else { - CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat, - pmtTarget->cbFormat); - } - } - if (pmtTarget->pUnk != NULL) { - pmtTarget->pUnk->AddRef(); - } - - return S_OK; -} - -// Free an existing media type (ie free resources it holds) - -void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt) -{ - if (mt.cbFormat != 0) { - CoTaskMemFree((PVOID)mt.pbFormat); - - // Strictly unnecessary but tidier - mt.cbFormat = 0; - mt.pbFormat = NULL; - } - if (mt.pUnk != NULL) { - mt.pUnk->Release(); - mt.pUnk = NULL; - } -} - -// Initialize a media type from a WAVEFORMATEX - -STDAPI CreateAudioMediaType( - const WAVEFORMATEX *pwfx, - __out AM_MEDIA_TYPE *pmt, - BOOL bSetFormat -) -{ - pmt->majortype = MEDIATYPE_Audio; - if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat; - } else { - pmt->subtype = FOURCCMap(pwfx->wFormatTag); - } - pmt->formattype = FORMAT_WaveFormatEx; - pmt->bFixedSizeSamples = TRUE; - pmt->bTemporalCompression = FALSE; - pmt->lSampleSize = pwfx->nBlockAlign; - pmt->pUnk = NULL; - if (bSetFormat) { - if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { - pmt->cbFormat = sizeof(WAVEFORMATEX); - } else { - pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize; - } - pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat); - if (pmt->pbFormat == NULL) { - return E_OUTOFMEMORY; - } - if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { - CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); - ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0; - } else { - CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat); - } - } - return S_OK; -} - -// eliminate very many spurious warnings from MS compiler -#pragma warning(disable:4514) +//------------------------------------------------------------------------------ +// File: MType.cpp +// +// Desc: DirectShow base classes - implements a class that holds and +// manages media type information. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// helper class that derived pin objects can use to compare media +// types etc. Has same data members as the struct AM_MEDIA_TYPE defined +// in the streams IDL file, but also has (non-virtual) functions + +#include "streams.h" +#include + +CMediaType::~CMediaType(){ + FreeMediaType(*this); +} + + +CMediaType::CMediaType() +{ + InitMediaType(); +} + + +CMediaType::CMediaType(const GUID * type) +{ + InitMediaType(); + majortype = *type; +} + + +// copy constructor does a deep copy of the format block + +CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, __out_opt HRESULT* phr) +{ + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr) && (NULL != phr)) { + *phr = hr; + } +} + + +CMediaType::CMediaType(const CMediaType& rt, __out_opt HRESULT* phr) +{ + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr) && (NULL != phr)) { + *phr = hr; + } +} + + +// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate +// the following assignment operator itself, however it could introduce some +// memory conflicts and leaks in the process because the structure contains +// a dynamically allocated block (pbFormat) which it will not copy correctly + +CMediaType& +CMediaType::operator=(const AM_MEDIA_TYPE& rt) +{ + Set(rt); + return *this; +} + +CMediaType& +CMediaType::operator=(const CMediaType& rt) +{ + *this = (AM_MEDIA_TYPE &) rt; + return *this; +} + +BOOL +CMediaType::operator == (const CMediaType& rt) const +{ + // I don't believe we need to check sample size or + // temporal compression flags, since I think these must + // be represented in the type, subtype and format somehow. They + // are pulled out as separate flags so that people who don't understand + // the particular format representation can still see them, but + // they should duplicate information in the format block. + + return ((IsEqualGUID(majortype,rt.majortype) == TRUE) && + (IsEqualGUID(subtype,rt.subtype) == TRUE) && + (IsEqualGUID(formattype,rt.formattype) == TRUE) && + (cbFormat == rt.cbFormat) && + ( (cbFormat == 0) || + pbFormat != NULL && rt.pbFormat != NULL && + (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0))); +} + + +BOOL +CMediaType::operator != (const CMediaType& rt) const +{ + /* Check to see if they are equal */ + + if (*this == rt) { + return FALSE; + } + return TRUE; +} + + +HRESULT +CMediaType::Set(const CMediaType& rt) +{ + return Set((AM_MEDIA_TYPE &) rt); +} + + +HRESULT +CMediaType::Set(const AM_MEDIA_TYPE& rt) +{ + if (&rt != this) { + FreeMediaType(*this); + HRESULT hr = CopyMediaType(this, &rt); + if (FAILED(hr)) { + return E_OUTOFMEMORY; + } + } + + return S_OK; +} + + +BOOL +CMediaType::IsValid() const +{ + return (!IsEqualGUID(majortype,GUID_NULL)); +} + + +void +CMediaType::SetType(const GUID* ptype) +{ + majortype = *ptype; +} + + +void +CMediaType::SetSubtype(const GUID* ptype) +{ + subtype = *ptype; +} + + +ULONG +CMediaType::GetSampleSize() const { + if (IsFixedSize()) { + return lSampleSize; + } else { + return 0; + } +} + + +void +CMediaType::SetSampleSize(ULONG sz) { + if (sz == 0) { + SetVariableSize(); + } else { + bFixedSizeSamples = TRUE; + lSampleSize = sz; + } +} + + +void +CMediaType::SetVariableSize() { + bFixedSizeSamples = FALSE; +} + + +void +CMediaType::SetTemporalCompression(BOOL bCompressed) { + bTemporalCompression = bCompressed; +} + +BOOL +CMediaType::SetFormat(__in_bcount(cb) BYTE * pformat, ULONG cb) +{ + if (NULL == AllocFormatBuffer(cb)) + return(FALSE); + + ASSERT(pbFormat); + memcpy(pbFormat, pformat, cb); + return(TRUE); +} + + +// set the type of the media type format block, this type defines what you +// will actually find in the format pointer. For example FORMAT_VideoInfo or +// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a +// property set. Before sending out media types this should be filled in. + +void +CMediaType::SetFormatType(const GUID *pformattype) +{ + formattype = *pformattype; +} + + +// reset the format buffer + +void CMediaType::ResetFormatBuffer() +{ + if (cbFormat) { + CoTaskMemFree((PVOID)pbFormat); + } + cbFormat = 0; + pbFormat = NULL; +} + + +// allocate length bytes for the format and return a read/write pointer +// If we cannot allocate the new block of memory we return NULL leaving +// the original block of memory untouched (as does ReallocFormatBuffer) + +BYTE* +CMediaType::AllocFormatBuffer(ULONG length) +{ + ASSERT(length); + + // do the types have the same buffer size + + if (cbFormat == length) { + return pbFormat; + } + + // allocate the new format buffer + + BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); + if (pNewFormat == NULL) { + if (length <= cbFormat) return pbFormat; //reuse the old block anyway. + return NULL; + } + + // delete the old format + + if (cbFormat != 0) { + ASSERT(pbFormat); + CoTaskMemFree((PVOID)pbFormat); + } + + cbFormat = length; + pbFormat = pNewFormat; + return pbFormat; +} + + +// reallocate length bytes for the format and return a read/write pointer +// to it. We keep as much information as we can given the new buffer size +// if this fails the original format buffer is left untouched. The caller +// is responsible for ensuring the size of memory required is non zero + +BYTE* +CMediaType::ReallocFormatBuffer(ULONG length) +{ + ASSERT(length); + + // do the types have the same buffer size + + if (cbFormat == length) { + return pbFormat; + } + + // allocate the new format buffer + + BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); + if (pNewFormat == NULL) { + if (length <= cbFormat) return pbFormat; //reuse the old block anyway. + return NULL; + } + + // copy any previous format (or part of if new is smaller) + // delete the old format and replace with the new one + + if (cbFormat != 0) { + ASSERT(pbFormat); + memcpy(pNewFormat,pbFormat,std::min(length,cbFormat)); + CoTaskMemFree((PVOID)pbFormat); + } + + cbFormat = length; + pbFormat = pNewFormat; + return pNewFormat; +} + +// initialise a media type structure + +void CMediaType::InitMediaType() +{ + ZeroMemory((PVOID)this, sizeof(*this)); + lSampleSize = 1; + bFixedSizeSamples = TRUE; +} + + +// a partially specified media type can be passed to IPin::Connect +// as a constraint on the media type used in the connection. +// the type, subtype or format type can be null. +BOOL +CMediaType::IsPartiallySpecified(void) const +{ + if ((majortype == GUID_NULL) || + (formattype == GUID_NULL)) { + return TRUE; + } else { + return FALSE; + } +} + +BOOL +CMediaType::MatchesPartial(const CMediaType* ppartial) const +{ + if ((ppartial->majortype != GUID_NULL) && + (majortype != ppartial->majortype)) { + return FALSE; + } + if ((ppartial->subtype != GUID_NULL) && + (subtype != ppartial->subtype)) { + return FALSE; + } + + if (ppartial->formattype != GUID_NULL) { + // if the format block is specified then it must match exactly + if (formattype != ppartial->formattype) { + return FALSE; + } + if (cbFormat != ppartial->cbFormat) { + return FALSE; + } + if ((cbFormat != 0) && + (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) { + return FALSE; + } + } + + return TRUE; + +} + + + +// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure +// which is useful when calling IEnumMediaTypes::Next as the interface +// implementation allocates the structures which you must later delete +// the format block may also be a pointer to an interface to release + +void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt) +{ + // allow NULL pointers for coding simplicity + + if (pmt == NULL) { + return; + } + + FreeMediaType(*pmt); + CoTaskMemFree((PVOID)pmt); +} + + +// this also comes in useful when using the IEnumMediaTypes interface so +// that you can copy a media type, you can do nearly the same by creating +// a CMediaType object but as soon as it goes out of scope the destructor +// will delete the memory it allocated (this takes a copy of the memory) + +AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc) +{ + ASSERT(pSrc); + + // Allocate a block of memory for the media type + + AM_MEDIA_TYPE *pMediaType = + (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + + if (pMediaType == NULL) { + return NULL; + } + // Copy the variable length format block + + HRESULT hr = CopyMediaType(pMediaType,pSrc); + if (FAILED(hr)) { + CoTaskMemFree((PVOID)pMediaType); + return NULL; + } + + return pMediaType; +} + + +// Copy 1 media type to another + +HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) +{ + // We'll leak if we copy onto one that already exists - there's one + // case we can check like that - copying to itself. + ASSERT(pmtSource != pmtTarget); + *pmtTarget = *pmtSource; + if (pmtSource->cbFormat != 0) { + ASSERT(pmtSource->pbFormat != NULL); + pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat); + if (pmtTarget->pbFormat == NULL) { + pmtTarget->cbFormat = 0; + return E_OUTOFMEMORY; + } else { + CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat, + pmtTarget->cbFormat); + } + } + if (pmtTarget->pUnk != NULL) { + pmtTarget->pUnk->AddRef(); + } + + return S_OK; +} + +// Free an existing media type (ie free resources it holds) + +void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt) +{ + if (mt.cbFormat != 0) { + CoTaskMemFree((PVOID)mt.pbFormat); + + // Strictly unnecessary but tidier + mt.cbFormat = 0; + mt.pbFormat = NULL; + } + if (mt.pUnk != NULL) { + mt.pUnk->Release(); + mt.pUnk = NULL; + } +} + +// Initialize a media type from a WAVEFORMATEX + +STDAPI CreateAudioMediaType( + const WAVEFORMATEX *pwfx, + __out AM_MEDIA_TYPE *pmt, + BOOL bSetFormat +) +{ + pmt->majortype = MEDIATYPE_Audio; + if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { + pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat; + } else { + pmt->subtype = FOURCCMap(pwfx->wFormatTag); + } + pmt->formattype = FORMAT_WaveFormatEx; + pmt->bFixedSizeSamples = TRUE; + pmt->bTemporalCompression = FALSE; + pmt->lSampleSize = pwfx->nBlockAlign; + pmt->pUnk = NULL; + if (bSetFormat) { + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { + pmt->cbFormat = sizeof(WAVEFORMATEX); + } else { + pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize; + } + pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat); + if (pmt->pbFormat == NULL) { + return E_OUTOFMEMORY; + } + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { + CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); + ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0; + } else { + CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat); + } + } + return S_OK; +} + +// eliminate very many spurious warnings from MS compiler +#pragma warning(disable:4514) diff --git a/src/thirdparty/BaseClasses/mtype.h b/src/thirdparty/BaseClasses/mtype.h index 9402f0644a1..fc2fe53eeda 100644 --- a/src/thirdparty/BaseClasses/mtype.h +++ b/src/thirdparty/BaseClasses/mtype.h @@ -1,89 +1,89 @@ -//------------------------------------------------------------------------------ -// File: MtType.h -// -// Desc: DirectShow base classes - defines a class that holds and manages -// media type information. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __MTYPE__ -#define __MTYPE__ - -/* Helper class that derived pin objects can use to compare media - types etc. Has same data members as the struct AM_MEDIA_TYPE defined - in the streams IDL file, but also has (non-virtual) functions */ - -class CMediaType : public _AMMediaType { - -public: - - ~CMediaType(); - CMediaType(); - CMediaType(const GUID * majortype); - CMediaType(const AM_MEDIA_TYPE&, __out_opt HRESULT* phr = NULL); - CMediaType(const CMediaType&, __out_opt HRESULT* phr = NULL); - - CMediaType& operator=(const CMediaType&); - CMediaType& operator=(const AM_MEDIA_TYPE&); - - BOOL operator == (const CMediaType&) const; - BOOL operator != (const CMediaType&) const; - - HRESULT Set(const CMediaType& rt); - HRESULT Set(const AM_MEDIA_TYPE& rt); - - BOOL IsValid() const; - - const GUID *Type() const { return &majortype;} ; - void SetType(const GUID *); - const GUID *Subtype() const { return &subtype;} ; - void SetSubtype(const GUID *); - - BOOL IsFixedSize() const {return bFixedSizeSamples; }; - BOOL IsTemporalCompressed() const {return bTemporalCompression; }; - ULONG GetSampleSize() const; - - void SetSampleSize(ULONG sz); - void SetVariableSize(); - void SetTemporalCompression(BOOL bCompressed); - - // read/write pointer to format - can't change length without - // calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer - - BYTE* Format() const {return pbFormat; }; - ULONG FormatLength() const { return cbFormat; }; - - void SetFormatType(const GUID *); - const GUID *FormatType() const {return &formattype; }; - BOOL SetFormat(__in_bcount(length) BYTE *pFormat, ULONG length); - void ResetFormatBuffer(); - BYTE* AllocFormatBuffer(ULONG length); - BYTE* ReallocFormatBuffer(ULONG length); - - void InitMediaType(); - - BOOL MatchesPartial(const CMediaType* ppartial) const; - BOOL IsPartiallySpecified(void) const; -}; - - -/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE - structure which is useful when using the IEnumMediaFormats interface as - the implementation allocates the structures which you must later delete */ - -void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt); -AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc); -HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource); -void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt); - -// Initialize a media type from a WAVEFORMATEX - -STDAPI CreateAudioMediaType( - const WAVEFORMATEX *pwfx, - __out AM_MEDIA_TYPE *pmt, - BOOL bSetFormat); - -#endif /* __MTYPE__ */ - +//------------------------------------------------------------------------------ +// File: MtType.h +// +// Desc: DirectShow base classes - defines a class that holds and manages +// media type information. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __MTYPE__ +#define __MTYPE__ + +/* Helper class that derived pin objects can use to compare media + types etc. Has same data members as the struct AM_MEDIA_TYPE defined + in the streams IDL file, but also has (non-virtual) functions */ + +class CMediaType : public _AMMediaType { + +public: + + ~CMediaType(); + CMediaType(); + CMediaType(const GUID * majortype); + CMediaType(const AM_MEDIA_TYPE&, __out_opt HRESULT* phr = NULL); + CMediaType(const CMediaType&, __out_opt HRESULT* phr = NULL); + + CMediaType& operator=(const CMediaType&); + CMediaType& operator=(const AM_MEDIA_TYPE&); + + BOOL operator == (const CMediaType&) const; + BOOL operator != (const CMediaType&) const; + + HRESULT Set(const CMediaType& rt); + HRESULT Set(const AM_MEDIA_TYPE& rt); + + BOOL IsValid() const; + + const GUID *Type() const { return &majortype;} ; + void SetType(const GUID *); + const GUID *Subtype() const { return &subtype;} ; + void SetSubtype(const GUID *); + + BOOL IsFixedSize() const {return bFixedSizeSamples; }; + BOOL IsTemporalCompressed() const {return bTemporalCompression; }; + ULONG GetSampleSize() const; + + void SetSampleSize(ULONG sz); + void SetVariableSize(); + void SetTemporalCompression(BOOL bCompressed); + + // read/write pointer to format - can't change length without + // calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer + + BYTE* Format() const {return pbFormat; }; + ULONG FormatLength() const { return cbFormat; }; + + void SetFormatType(const GUID *); + const GUID *FormatType() const {return &formattype; }; + BOOL SetFormat(__in_bcount(length) BYTE *pFormat, ULONG length); + void ResetFormatBuffer(); + BYTE* AllocFormatBuffer(ULONG length); + BYTE* ReallocFormatBuffer(ULONG length); + + void InitMediaType(); + + BOOL MatchesPartial(const CMediaType* ppartial) const; + BOOL IsPartiallySpecified(void) const; +}; + + +/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE + structure which is useful when using the IEnumMediaFormats interface as + the implementation allocates the structures which you must later delete */ + +void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt); +AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc); +HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource); +void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt); + +// Initialize a media type from a WAVEFORMATEX + +STDAPI CreateAudioMediaType( + const WAVEFORMATEX *pwfx, + __out AM_MEDIA_TYPE *pmt, + BOOL bSetFormat); + +#endif /* __MTYPE__ */ + diff --git a/src/thirdparty/BaseClasses/outputq.cpp b/src/thirdparty/BaseClasses/outputq.cpp index 9d4cc97211e..d290e300800 100644 --- a/src/thirdparty/BaseClasses/outputq.cpp +++ b/src/thirdparty/BaseClasses/outputq.cpp @@ -1,801 +1,801 @@ -//------------------------------------------------------------------------------ -// File: OutputQ.cpp -// -// Desc: DirectShow base classes - implements COutputQueue class used by an -// output pin which may sometimes want to queue output samples on a -// separate thread and sometimes call Receive() directly on the input -// pin. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - - -// -// COutputQueue Constructor : -// -// Determines if a thread is to be created and creates resources -// -// pInputPin - the downstream input pin we're queueing samples to -// -// phr - changed to a failure code if this function fails -// (otherwise unchanges) -// -// bAuto - Ask pInputPin if it can block in Receive by calling -// its ReceiveCanBlock method and create a thread if -// it can block, otherwise not. -// -// bQueue - if bAuto == FALSE then we create a thread if and only -// if bQueue == TRUE -// -// lBatchSize - work in batches of lBatchSize -// -// bBatchEact - Use exact batch sizes so don't send until the -// batch is full or SendAnyway() is called -// -// lListSize - If we create a thread make the list of samples queued -// to the thread have this size cache -// -// dwPriority - If we create a thread set its priority to this -// -COutputQueue::COutputQueue( - IPin *pInputPin, // Pin to send stuff to - __inout HRESULT *phr, // 'Return code' - BOOL bAuto, // Ask pin if queue or not - BOOL bQueue, // Send through queue - LONG lBatchSize, // Batch - BOOL bBatchExact, // Batch exactly to BatchSize - LONG lListSize, - DWORD dwPriority, - bool bFlushingOpt // flushing optimization - ) : m_lBatchSize(lBatchSize), - m_bBatchExact(bBatchExact && (lBatchSize > 1)), - m_hThread(NULL), - m_hSem(NULL), - m_List(NULL), - m_pPin(pInputPin), - m_ppSamples(NULL), - m_lWaiting(0), - m_evFlushComplete(FALSE, phr), - m_pInputPin(NULL), - m_bSendAnyway(FALSE), - m_nBatched(0), - m_bFlushing(FALSE), - m_bFlushed(TRUE), - m_bFlushingOpt(bFlushingOpt), - m_bTerminate(FALSE), - m_hEventPop(NULL), - m_hr(S_OK) -{ - ASSERT(m_lBatchSize > 0); - - - if (FAILED(*phr)) { - return; - } - - // Check the input pin is OK and cache its IMemInputPin interface - - *phr = pInputPin->QueryInterface(IID_IMemInputPin, (void **)&m_pInputPin); - if (FAILED(*phr)) { - return; - } - - // See if we should ask the downstream pin - - if (bAuto) { - HRESULT hr = m_pInputPin->ReceiveCanBlock(); - if (SUCCEEDED(hr)) { - bQueue = hr == S_OK; - } - } - - // Create our sample batch - - m_ppSamples = new PMEDIASAMPLE[m_lBatchSize]; - if (m_ppSamples == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - - // If we're queueing allocate resources - - if (bQueue) { - DbgLog((LOG_TRACE, 2, TEXT("Creating thread for output pin"))); - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - DWORD dwError = GetLastError(); - *phr = AmHresultFromWin32(dwError); - return; - } - m_List = new CSampleList(NAME("Sample Queue List"), - lListSize, - FALSE // No lock - ); - if (m_List == NULL) { - *phr = E_OUTOFMEMORY; - return; - } - - - DWORD dwThreadId; - m_hThread = CreateThread(NULL, - 0, - InitialThreadProc, - (LPVOID)this, - 0, - &dwThreadId); - if (m_hThread == NULL) { - DWORD dwError = GetLastError(); - *phr = AmHresultFromWin32(dwError); - return; - } - SetThreadPriority(m_hThread, dwPriority); - } else { - DbgLog((LOG_TRACE, 2, TEXT("Calling input pin directly - no thread"))); - } -} - -// -// COutputQueuee Destructor : -// -// Free all resources - -// -// Thread, -// Batched samples -// -COutputQueue::~COutputQueue() -{ - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue::~COutputQueue"))); - /* Free our pointer */ - if (m_pInputPin != NULL) { - m_pInputPin->Release(); - } - if (m_hThread != NULL) { - { - CAutoLock lck(this); - m_bTerminate = TRUE; - m_hr = S_FALSE; - NotifyThread(); - } - DbgWaitForSingleObject(m_hThread); - EXECUTE_ASSERT(CloseHandle(m_hThread)); - - // The thread frees the samples when asked to terminate - - ASSERT(m_List->GetCount() == 0); - delete m_List; - } else { - FreeSamples(); - } - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } - delete [] m_ppSamples; -} - -// -// Call the real thread proc as a member function -// -DWORD WINAPI COutputQueue::InitialThreadProc(__in LPVOID pv) -{ - HRESULT hrCoInit = CAMThread::CoInitializeHelper(); - - COutputQueue *pSampleQueue = (COutputQueue *)pv; - DWORD dwReturn = pSampleQueue->ThreadProc(); - - if(hrCoInit == S_OK) { - CoUninitialize(); - } - - return dwReturn; -} - -// -// Thread sending the samples downstream : -// -// When there is nothing to do the thread sets m_lWaiting (while -// holding the critical section) and then waits for m_hSem to be -// set (not holding the critical section) -// -DWORD COutputQueue::ThreadProc() -{ - for (;;) { - BOOL bWait = FALSE; - IMediaSample *pSample; - LONG lNumberToSend = 0; // Local copy - NewSegmentPacket* ppacket = NULL; - - // - // Get a batch of samples and send it if possible - // In any case exit the loop if there is a control action - // requested - // - { - CAutoLock lck(this); - for (;;) { - - if (m_bTerminate) { - FreeSamples(); - return 0; - } - if (m_bFlushing) { - FreeSamples(); - SetEvent(m_evFlushComplete); - } - - // Get a sample off the list - - pSample = m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - if (pSample != NULL && - !IsSpecialSample(pSample)) { - - // If its just a regular sample just add it to the batch - // and exit the loop if the batch is full - - m_ppSamples[m_nBatched++] = pSample; - if (m_nBatched == m_lBatchSize) { - break; - } - } else { - - // If there was nothing in the queue and there's nothing - // to send (either because there's nothing or the batch - // isn't full) then prepare to wait - - if (pSample == NULL && - (m_bBatchExact || m_nBatched == 0)) { - - // Tell other thread to set the event when there's - // something do to - - ASSERT(m_lWaiting == 0); - m_lWaiting++; - bWait = TRUE; - } else { - - // We break out of the loop on SEND_PACKET unless - // there's nothing to send - - if (pSample == SEND_PACKET && m_nBatched == 0) { - continue; - } - - if (pSample == NEW_SEGMENT) { - // now we need the parameters - we are - // guaranteed that the next packet contains them - ppacket = (NewSegmentPacket *) m_List->RemoveHead(); - // we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - ASSERT(ppacket); - } - // EOS_PACKET falls through here and we exit the loop - // In this way it acts like SEND_PACKET - } - break; - } - } - if (!bWait) { - // We look at m_nBatched from the client side so keep - // it up to date inside the critical section - lNumberToSend = m_nBatched; // Local copy - m_nBatched = 0; - } - } - - // Wait for some more data - - if (bWait) { - DbgWaitForSingleObject(m_hSem); - continue; - } - - - - // OK - send it if there's anything to send - // We DON'T check m_bBatchExact here because either we've got - // a full batch or we dropped through because we got - // SEND_PACKET or EOS_PACKET - both of which imply we should - // flush our batch - - if (lNumberToSend != 0) { - long nProcessed; - if (m_hr == S_OK) { - ASSERT(!m_bFlushed); - HRESULT hr = m_pInputPin->ReceiveMultiple(m_ppSamples, - lNumberToSend, - &nProcessed); - /* Don't overwrite a flushing state HRESULT */ - CAutoLock lck(this); - if (m_hr == S_OK) { - m_hr = hr; - } - ASSERT(!m_bFlushed); - } - while (lNumberToSend != 0) { - m_ppSamples[--lNumberToSend]->Release(); - } - if (m_hr != S_OK) { - - // In any case wait for more data - S_OK just - // means there wasn't an error - - DbgLog((LOG_ERROR, 2, TEXT("ReceiveMultiple returned %8.8X"), - m_hr)); - } - } - - // Check for end of stream - - if (pSample == EOS_PACKET) { - - // We don't send even end of stream on if we've previously - // returned something other than S_OK - // This is because in that case the pin which returned - // something other than S_OK should have either sent - // EndOfStream() or notified the filter graph - - if (m_hr == S_OK) { - DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); - HRESULT hr = m_pPin->EndOfStream(); - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); - } - } - } - - // Data from a new source - - if (pSample == RESET_PACKET) { - m_hr = S_OK; - SetEvent(m_evFlushComplete); - } - - if (pSample == NEW_SEGMENT) { - m_pPin->NewSegment(ppacket->tStart, ppacket->tStop, ppacket->dRate); - delete ppacket; - } - } -} - -// Send batched stuff anyway -void COutputQueue::SendAnyway() -{ - if (!IsQueued()) { - - // m_bSendAnyway is a private parameter checked in ReceiveMultiple - - m_bSendAnyway = TRUE; - LONG nProcessed; - ReceiveMultiple(NULL, 0, &nProcessed); - m_bSendAnyway = FALSE; - - } else { - CAutoLock lck(this); - QueueSample(SEND_PACKET); - NotifyThread(); - } -} - -void -COutputQueue::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (!IsQueued()) { - if (S_OK == m_hr) { - if (m_bBatchExact) { - SendAnyway(); - } - m_pPin->NewSegment(tStart, tStop, dRate); - } - } else { - if (m_hr == S_OK) { - // - // we need to queue the new segment to appear in order in the - // data, but we need to pass parameters to it. Rather than - // take the hit of wrapping every single sample so we can tell - // special ones apart, we queue special pointers to indicate - // special packets, and we guarantee (by holding the - // critical section) that the packet immediately following a - // NEW_SEGMENT value is a NewSegmentPacket containing the - // parameters. - NewSegmentPacket * ppack = new NewSegmentPacket; - if (ppack == NULL) { - return; - } - ppack->tStart = tStart; - ppack->tStop = tStop; - ppack->dRate = dRate; - - CAutoLock lck(this); - QueueSample(NEW_SEGMENT); - QueueSample( (IMediaSample*) ppack); - NotifyThread(); - } - } -} - - -// -// End of Stream is queued to output device -// -void COutputQueue::EOS() -{ - CAutoLock lck(this); - if (!IsQueued()) { - if (m_bBatchExact) { - SendAnyway(); - } - if (m_hr == S_OK) { - DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); - m_bFlushed = FALSE; - HRESULT hr = m_pPin->EndOfStream(); - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); - } - } - } else { - if (m_hr == S_OK) { - m_bFlushed = FALSE; - QueueSample(EOS_PACKET); - NotifyThread(); - } - } -} - -// -// Flush all the samples in the queue -// -void COutputQueue::BeginFlush() -{ - if (IsQueued()) { - { - CAutoLock lck(this); - - // block receives -- we assume this is done by the - // filter in which we are a component - - // discard all queued data - - m_bFlushing = TRUE; - - // Make sure we discard all samples from now on - - if (m_hr == S_OK) { - m_hr = S_FALSE; - } - - // Optimize so we don't keep calling downstream all the time - - if (m_bFlushed && m_bFlushingOpt) { - return; - } - - // Make sure we really wait for the flush to complete - m_evFlushComplete.Reset(); - - NotifyThread(); - } - - // pass this downstream - - m_pPin->BeginFlush(); - } else { - // pass downstream first to avoid deadlocks - m_pPin->BeginFlush(); - CAutoLock lck(this); - // discard all queued data - - m_bFlushing = TRUE; - - // Make sure we discard all samples from now on - - if (m_hr == S_OK) { - m_hr = S_FALSE; - } - } - -} - -// -// leave flush mode - pass this downstream -void COutputQueue::EndFlush() -{ - { - CAutoLock lck(this); - ASSERT(m_bFlushing); - if (m_bFlushingOpt && m_bFlushed && IsQueued()) { - m_bFlushing = FALSE; - m_hr = S_OK; - return; - } - } - - // sync with pushing thread -- done in BeginFlush - // ensure no more data to go downstream -- done in BeginFlush - // - // Because we are synching here there is no need to hold the critical - // section (in fact we'd deadlock if we did!) - - if (IsQueued()) { - m_evFlushComplete.Wait(); - } else { - FreeSamples(); - } - - // Be daring - the caller has guaranteed no samples will arrive - // before EndFlush() returns - - m_bFlushing = FALSE; - m_bFlushed = TRUE; - - // call EndFlush on downstream pins - - m_pPin->EndFlush(); - - m_hr = S_OK; -} - -// COutputQueue::QueueSample -// -// private method to Send a sample to the output queue -// The critical section MUST be held when this is called - -void COutputQueue::QueueSample(IMediaSample *pSample) -{ - if (NULL == m_List->AddTail(pSample)) { - if (!IsSpecialSample(pSample)) { - pSample->Release(); - } - } -} - -// -// COutputQueue::Receive() -// -// Send a single sample by the multiple sample route -// (NOTE - this could be optimized if necessary) -// -// On return the sample will have been Release()'d -// - -HRESULT COutputQueue::Receive(IMediaSample *pSample) -{ - LONG nProcessed; - return ReceiveMultiple(&pSample, 1, &nProcessed); -} - -// -// COutputQueue::ReceiveMultiple() -// -// Send a set of samples to the downstream pin -// -// ppSamples - array of samples -// nSamples - how many -// nSamplesProcessed - How many were processed -// -// On return all samples will have been Release()'d -// - -HRESULT COutputQueue::ReceiveMultiple ( - __in_ecount(nSamples) IMediaSample **ppSamples, - long nSamples, - __out long *nSamplesProcessed) -{ - if (nSamples < 0) { - return E_INVALIDARG; - } - - CAutoLock lck(this); - // Either call directly or queue up the samples - - if (!IsQueued()) { - - // If we already had a bad return code then just return - - if (S_OK != m_hr) { - - // If we've never received anything since the last Flush() - // and the sticky return code is not S_OK we must be - // flushing - // ((!A || B) is equivalent to A implies B) - ASSERT(!m_bFlushed || m_bFlushing); - - // We're supposed to Release() them anyway! - *nSamplesProcessed = 0; - for (int i = 0; i < nSamples; i++) { - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (direct) : Discarding %d samples code 0x%8.8X"), - nSamples, m_hr)); - ppSamples[i]->Release(); - } - - return m_hr; - } - // - // If we're flushing the sticky return code should be S_FALSE - // - ASSERT(!m_bFlushing); - m_bFlushed = FALSE; - - ASSERT(m_nBatched < m_lBatchSize); - ASSERT(m_nBatched == 0 || m_bBatchExact); - - // Loop processing the samples in batches - - LONG iLost = 0; - long iDone = 0; - for (iDone = 0; - iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway); - ) { - -//pragma message (REMIND("Implement threshold scheme")) - ASSERT(m_nBatched < m_lBatchSize); - if (iDone < nSamples) { - m_ppSamples[m_nBatched++] = ppSamples[iDone++]; - } - if (m_nBatched == m_lBatchSize || - nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) { - LONG nDone; - DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"), - m_nBatched)); - - if (m_hr == S_OK) { - m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples, - m_nBatched, - &nDone); - } else { - nDone = 0; - } - iLost += m_nBatched - nDone; - for (LONG i = 0; i < m_nBatched; i++) { - m_ppSamples[i]->Release(); - } - m_nBatched = 0; - } - } - *nSamplesProcessed = iDone - iLost; - if (*nSamplesProcessed < 0) { - *nSamplesProcessed = 0; - } - return m_hr; - } else { - /* We're sending to our thread */ - - if (m_hr != S_OK) { - *nSamplesProcessed = 0; - DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (queued) : Discarding %d samples code 0x%8.8X"), - nSamples, m_hr)); - for (int i = 0; i < nSamples; i++) { - ppSamples[i]->Release(); - } - return m_hr; - } - m_bFlushed = FALSE; - for (long i = 0; i < nSamples; i++) { - QueueSample(ppSamples[i]); - } - *nSamplesProcessed = nSamples; - if (!m_bBatchExact || - m_nBatched + m_List->GetCount() >= m_lBatchSize) { - NotifyThread(); - } - return S_OK; - } -} - -// Get ready for new data - cancels sticky m_hr -void COutputQueue::Reset() -{ - if (!IsQueued()) { - m_hr = S_OK; - } else { - { - CAutoLock lck(this); - QueueSample(RESET_PACKET); - NotifyThread(); - } - m_evFlushComplete.Wait(); - } -} - -// Remove and Release() all queued and Batched samples -void COutputQueue::FreeSamples() -{ - CAutoLock lck(this); - if (IsQueued()) { - for (;;) { - IMediaSample *pSample = m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - if (pSample == NULL) { - break; - } - if (!IsSpecialSample(pSample)) { - pSample->Release(); - } else { - if (pSample == NEW_SEGMENT) { - // Free NEW_SEGMENT packet - NewSegmentPacket *ppacket = - (NewSegmentPacket *) m_List->RemoveHead(); - // inform derived class we took something off the queue - if (m_hEventPop) { - //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); - SetEvent(m_hEventPop); - } - - ASSERT(ppacket != NULL); - delete ppacket; - } - } - } - } - for (int i = 0; i < m_nBatched; i++) { - m_ppSamples[i]->Release(); - } - m_nBatched = 0; -} - -// Notify the thread if there is something to do -// -// The critical section MUST be held when this is called -void COutputQueue::NotifyThread() -{ - // Optimize - no need to signal if it's not waiting - ASSERT(IsQueued()); - if (m_lWaiting) { - ReleaseSemaphore(m_hSem, m_lWaiting, NULL); - m_lWaiting = 0; - } -} - -// See if there's any work to do -// Returns -// TRUE if there is nothing on the queue and nothing in the batch -// and all data has been sent -// FALSE otherwise -// -BOOL COutputQueue::IsIdle() -{ - CAutoLock lck(this); - - // We're idle if - // there is no thread (!IsQueued()) OR - // the thread is waiting for more work (m_lWaiting != 0) - // AND - // there's nothing in the current batch (m_nBatched == 0) - - if (IsQueued() && m_lWaiting == 0 || m_nBatched != 0) { - return FALSE; - } else { - - // If we're idle it shouldn't be possible for there - // to be anything on the work queue - - ASSERT(!IsQueued() || m_List->GetCount() == 0); - return TRUE; - } -} - - -void COutputQueue::SetPopEvent(HANDLE hEvent) -{ - m_hEventPop = hEvent; -} +//------------------------------------------------------------------------------ +// File: OutputQ.cpp +// +// Desc: DirectShow base classes - implements COutputQueue class used by an +// output pin which may sometimes want to queue output samples on a +// separate thread and sometimes call Receive() directly on the input +// pin. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + + +// +// COutputQueue Constructor : +// +// Determines if a thread is to be created and creates resources +// +// pInputPin - the downstream input pin we're queueing samples to +// +// phr - changed to a failure code if this function fails +// (otherwise unchanges) +// +// bAuto - Ask pInputPin if it can block in Receive by calling +// its ReceiveCanBlock method and create a thread if +// it can block, otherwise not. +// +// bQueue - if bAuto == FALSE then we create a thread if and only +// if bQueue == TRUE +// +// lBatchSize - work in batches of lBatchSize +// +// bBatchEact - Use exact batch sizes so don't send until the +// batch is full or SendAnyway() is called +// +// lListSize - If we create a thread make the list of samples queued +// to the thread have this size cache +// +// dwPriority - If we create a thread set its priority to this +// +COutputQueue::COutputQueue( + IPin *pInputPin, // Pin to send stuff to + __inout HRESULT *phr, // 'Return code' + BOOL bAuto, // Ask pin if queue or not + BOOL bQueue, // Send through queue + LONG lBatchSize, // Batch + BOOL bBatchExact, // Batch exactly to BatchSize + LONG lListSize, + DWORD dwPriority, + bool bFlushingOpt // flushing optimization + ) : m_lBatchSize(lBatchSize), + m_bBatchExact(bBatchExact && (lBatchSize > 1)), + m_hThread(NULL), + m_hSem(NULL), + m_List(NULL), + m_pPin(pInputPin), + m_ppSamples(NULL), + m_lWaiting(0), + m_evFlushComplete(FALSE, phr), + m_pInputPin(NULL), + m_bSendAnyway(FALSE), + m_nBatched(0), + m_bFlushing(FALSE), + m_bFlushed(TRUE), + m_bFlushingOpt(bFlushingOpt), + m_bTerminate(FALSE), + m_hEventPop(NULL), + m_hr(S_OK) +{ + ASSERT(m_lBatchSize > 0); + + + if (FAILED(*phr)) { + return; + } + + // Check the input pin is OK and cache its IMemInputPin interface + + *phr = pInputPin->QueryInterface(IID_IMemInputPin, (void **)&m_pInputPin); + if (FAILED(*phr)) { + return; + } + + // See if we should ask the downstream pin + + if (bAuto) { + HRESULT hr = m_pInputPin->ReceiveCanBlock(); + if (SUCCEEDED(hr)) { + bQueue = hr == S_OK; + } + } + + // Create our sample batch + + m_ppSamples = new PMEDIASAMPLE[m_lBatchSize]; + if (m_ppSamples == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + + // If we're queueing allocate resources + + if (bQueue) { + DbgLog((LOG_TRACE, 2, TEXT("Creating thread for output pin"))); + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + DWORD dwError = GetLastError(); + *phr = AmHresultFromWin32(dwError); + return; + } + m_List = new CSampleList(NAME("Sample Queue List"), + lListSize, + FALSE // No lock + ); + if (m_List == NULL) { + *phr = E_OUTOFMEMORY; + return; + } + + + DWORD dwThreadId; + m_hThread = CreateThread(NULL, + 0, + InitialThreadProc, + (LPVOID)this, + 0, + &dwThreadId); + if (m_hThread == NULL) { + DWORD dwError = GetLastError(); + *phr = AmHresultFromWin32(dwError); + return; + } + SetThreadPriority(m_hThread, dwPriority); + } else { + DbgLog((LOG_TRACE, 2, TEXT("Calling input pin directly - no thread"))); + } +} + +// +// COutputQueuee Destructor : +// +// Free all resources - +// +// Thread, +// Batched samples +// +COutputQueue::~COutputQueue() +{ + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue::~COutputQueue"))); + /* Free our pointer */ + if (m_pInputPin != NULL) { + m_pInputPin->Release(); + } + if (m_hThread != NULL) { + { + CAutoLock lck(this); + m_bTerminate = TRUE; + m_hr = S_FALSE; + NotifyThread(); + } + DbgWaitForSingleObject(m_hThread); + EXECUTE_ASSERT(CloseHandle(m_hThread)); + + // The thread frees the samples when asked to terminate + + ASSERT(m_List->GetCount() == 0); + delete m_List; + } else { + FreeSamples(); + } + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } + delete [] m_ppSamples; +} + +// +// Call the real thread proc as a member function +// +DWORD WINAPI COutputQueue::InitialThreadProc(__in LPVOID pv) +{ + HRESULT hrCoInit = CAMThread::CoInitializeHelper(); + + COutputQueue *pSampleQueue = (COutputQueue *)pv; + DWORD dwReturn = pSampleQueue->ThreadProc(); + + if(hrCoInit == S_OK) { + CoUninitialize(); + } + + return dwReturn; +} + +// +// Thread sending the samples downstream : +// +// When there is nothing to do the thread sets m_lWaiting (while +// holding the critical section) and then waits for m_hSem to be +// set (not holding the critical section) +// +DWORD COutputQueue::ThreadProc() +{ + for (;;) { + BOOL bWait = FALSE; + IMediaSample *pSample; + LONG lNumberToSend = 0; // Local copy + NewSegmentPacket* ppacket = NULL; + + // + // Get a batch of samples and send it if possible + // In any case exit the loop if there is a control action + // requested + // + { + CAutoLock lck(this); + for (;;) { + + if (m_bTerminate) { + FreeSamples(); + return 0; + } + if (m_bFlushing) { + FreeSamples(); + SetEvent(m_evFlushComplete); + } + + // Get a sample off the list + + pSample = m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + if (pSample != NULL && + !IsSpecialSample(pSample)) { + + // If its just a regular sample just add it to the batch + // and exit the loop if the batch is full + + m_ppSamples[m_nBatched++] = pSample; + if (m_nBatched == m_lBatchSize) { + break; + } + } else { + + // If there was nothing in the queue and there's nothing + // to send (either because there's nothing or the batch + // isn't full) then prepare to wait + + if (pSample == NULL && + (m_bBatchExact || m_nBatched == 0)) { + + // Tell other thread to set the event when there's + // something do to + + ASSERT(m_lWaiting == 0); + m_lWaiting++; + bWait = TRUE; + } else { + + // We break out of the loop on SEND_PACKET unless + // there's nothing to send + + if (pSample == SEND_PACKET && m_nBatched == 0) { + continue; + } + + if (pSample == NEW_SEGMENT) { + // now we need the parameters - we are + // guaranteed that the next packet contains them + ppacket = (NewSegmentPacket *) m_List->RemoveHead(); + // we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + ASSERT(ppacket); + } + // EOS_PACKET falls through here and we exit the loop + // In this way it acts like SEND_PACKET + } + break; + } + } + if (!bWait) { + // We look at m_nBatched from the client side so keep + // it up to date inside the critical section + lNumberToSend = m_nBatched; // Local copy + m_nBatched = 0; + } + } + + // Wait for some more data + + if (bWait) { + DbgWaitForSingleObject(m_hSem); + continue; + } + + + + // OK - send it if there's anything to send + // We DON'T check m_bBatchExact here because either we've got + // a full batch or we dropped through because we got + // SEND_PACKET or EOS_PACKET - both of which imply we should + // flush our batch + + if (lNumberToSend != 0) { + long nProcessed; + if (m_hr == S_OK) { + ASSERT(!m_bFlushed); + HRESULT hr = m_pInputPin->ReceiveMultiple(m_ppSamples, + lNumberToSend, + &nProcessed); + /* Don't overwrite a flushing state HRESULT */ + CAutoLock lck(this); + if (m_hr == S_OK) { + m_hr = hr; + } + ASSERT(!m_bFlushed); + } + while (lNumberToSend != 0) { + m_ppSamples[--lNumberToSend]->Release(); + } + if (m_hr != S_OK) { + + // In any case wait for more data - S_OK just + // means there wasn't an error + + DbgLog((LOG_ERROR, 2, TEXT("ReceiveMultiple returned %8.8X"), + m_hr)); + } + } + + // Check for end of stream + + if (pSample == EOS_PACKET) { + + // We don't send even end of stream on if we've previously + // returned something other than S_OK + // This is because in that case the pin which returned + // something other than S_OK should have either sent + // EndOfStream() or notified the filter graph + + if (m_hr == S_OK) { + DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); + HRESULT hr = m_pPin->EndOfStream(); + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); + } + } + } + + // Data from a new source + + if (pSample == RESET_PACKET) { + m_hr = S_OK; + SetEvent(m_evFlushComplete); + } + + if (pSample == NEW_SEGMENT) { + m_pPin->NewSegment(ppacket->tStart, ppacket->tStop, ppacket->dRate); + delete ppacket; + } + } +} + +// Send batched stuff anyway +void COutputQueue::SendAnyway() +{ + if (!IsQueued()) { + + // m_bSendAnyway is a private parameter checked in ReceiveMultiple + + m_bSendAnyway = TRUE; + LONG nProcessed; + ReceiveMultiple(NULL, 0, &nProcessed); + m_bSendAnyway = FALSE; + + } else { + CAutoLock lck(this); + QueueSample(SEND_PACKET); + NotifyThread(); + } +} + +void +COutputQueue::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (!IsQueued()) { + if (S_OK == m_hr) { + if (m_bBatchExact) { + SendAnyway(); + } + m_pPin->NewSegment(tStart, tStop, dRate); + } + } else { + if (m_hr == S_OK) { + // + // we need to queue the new segment to appear in order in the + // data, but we need to pass parameters to it. Rather than + // take the hit of wrapping every single sample so we can tell + // special ones apart, we queue special pointers to indicate + // special packets, and we guarantee (by holding the + // critical section) that the packet immediately following a + // NEW_SEGMENT value is a NewSegmentPacket containing the + // parameters. + NewSegmentPacket * ppack = new NewSegmentPacket; + if (ppack == NULL) { + return; + } + ppack->tStart = tStart; + ppack->tStop = tStop; + ppack->dRate = dRate; + + CAutoLock lck(this); + QueueSample(NEW_SEGMENT); + QueueSample( (IMediaSample*) ppack); + NotifyThread(); + } + } +} + + +// +// End of Stream is queued to output device +// +void COutputQueue::EOS() +{ + CAutoLock lck(this); + if (!IsQueued()) { + if (m_bBatchExact) { + SendAnyway(); + } + if (m_hr == S_OK) { + DbgLog((LOG_TRACE, 2, TEXT("COutputQueue sending EndOfStream()"))); + m_bFlushed = FALSE; + HRESULT hr = m_pPin->EndOfStream(); + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 2, TEXT("COutputQueue got code 0x%8.8X from EndOfStream()"))); + } + } + } else { + if (m_hr == S_OK) { + m_bFlushed = FALSE; + QueueSample(EOS_PACKET); + NotifyThread(); + } + } +} + +// +// Flush all the samples in the queue +// +void COutputQueue::BeginFlush() +{ + if (IsQueued()) { + { + CAutoLock lck(this); + + // block receives -- we assume this is done by the + // filter in which we are a component + + // discard all queued data + + m_bFlushing = TRUE; + + // Make sure we discard all samples from now on + + if (m_hr == S_OK) { + m_hr = S_FALSE; + } + + // Optimize so we don't keep calling downstream all the time + + if (m_bFlushed && m_bFlushingOpt) { + return; + } + + // Make sure we really wait for the flush to complete + m_evFlushComplete.Reset(); + + NotifyThread(); + } + + // pass this downstream + + m_pPin->BeginFlush(); + } else { + // pass downstream first to avoid deadlocks + m_pPin->BeginFlush(); + CAutoLock lck(this); + // discard all queued data + + m_bFlushing = TRUE; + + // Make sure we discard all samples from now on + + if (m_hr == S_OK) { + m_hr = S_FALSE; + } + } + +} + +// +// leave flush mode - pass this downstream +void COutputQueue::EndFlush() +{ + { + CAutoLock lck(this); + ASSERT(m_bFlushing); + if (m_bFlushingOpt && m_bFlushed && IsQueued()) { + m_bFlushing = FALSE; + m_hr = S_OK; + return; + } + } + + // sync with pushing thread -- done in BeginFlush + // ensure no more data to go downstream -- done in BeginFlush + // + // Because we are synching here there is no need to hold the critical + // section (in fact we'd deadlock if we did!) + + if (IsQueued()) { + m_evFlushComplete.Wait(); + } else { + FreeSamples(); + } + + // Be daring - the caller has guaranteed no samples will arrive + // before EndFlush() returns + + m_bFlushing = FALSE; + m_bFlushed = TRUE; + + // call EndFlush on downstream pins + + m_pPin->EndFlush(); + + m_hr = S_OK; +} + +// COutputQueue::QueueSample +// +// private method to Send a sample to the output queue +// The critical section MUST be held when this is called + +void COutputQueue::QueueSample(IMediaSample *pSample) +{ + if (NULL == m_List->AddTail(pSample)) { + if (!IsSpecialSample(pSample)) { + pSample->Release(); + } + } +} + +// +// COutputQueue::Receive() +// +// Send a single sample by the multiple sample route +// (NOTE - this could be optimized if necessary) +// +// On return the sample will have been Release()'d +// + +HRESULT COutputQueue::Receive(IMediaSample *pSample) +{ + LONG nProcessed; + return ReceiveMultiple(&pSample, 1, &nProcessed); +} + +// +// COutputQueue::ReceiveMultiple() +// +// Send a set of samples to the downstream pin +// +// ppSamples - array of samples +// nSamples - how many +// nSamplesProcessed - How many were processed +// +// On return all samples will have been Release()'d +// + +HRESULT COutputQueue::ReceiveMultiple ( + __in_ecount(nSamples) IMediaSample **ppSamples, + long nSamples, + __out long *nSamplesProcessed) +{ + if (nSamples < 0) { + return E_INVALIDARG; + } + + CAutoLock lck(this); + // Either call directly or queue up the samples + + if (!IsQueued()) { + + // If we already had a bad return code then just return + + if (S_OK != m_hr) { + + // If we've never received anything since the last Flush() + // and the sticky return code is not S_OK we must be + // flushing + // ((!A || B) is equivalent to A implies B) + ASSERT(!m_bFlushed || m_bFlushing); + + // We're supposed to Release() them anyway! + *nSamplesProcessed = 0; + for (int i = 0; i < nSamples; i++) { + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (direct) : Discarding %d samples code 0x%8.8X"), + nSamples, m_hr)); + ppSamples[i]->Release(); + } + + return m_hr; + } + // + // If we're flushing the sticky return code should be S_FALSE + // + ASSERT(!m_bFlushing); + m_bFlushed = FALSE; + + ASSERT(m_nBatched < m_lBatchSize); + ASSERT(m_nBatched == 0 || m_bBatchExact); + + // Loop processing the samples in batches + + LONG iLost = 0; + long iDone = 0; + for (iDone = 0; + iDone < nSamples || (m_nBatched != 0 && m_bSendAnyway); + ) { + +//pragma message (REMIND("Implement threshold scheme")) + ASSERT(m_nBatched < m_lBatchSize); + if (iDone < nSamples) { + m_ppSamples[m_nBatched++] = ppSamples[iDone++]; + } + if (m_nBatched == m_lBatchSize || + nSamples == 0 && (m_bSendAnyway || !m_bBatchExact)) { + LONG nDone; + DbgLog((LOG_TRACE, 4, TEXT("Batching %d samples"), + m_nBatched)); + + if (m_hr == S_OK) { + m_hr = m_pInputPin->ReceiveMultiple(m_ppSamples, + m_nBatched, + &nDone); + } else { + nDone = 0; + } + iLost += m_nBatched - nDone; + for (LONG i = 0; i < m_nBatched; i++) { + m_ppSamples[i]->Release(); + } + m_nBatched = 0; + } + } + *nSamplesProcessed = iDone - iLost; + if (*nSamplesProcessed < 0) { + *nSamplesProcessed = 0; + } + return m_hr; + } else { + /* We're sending to our thread */ + + if (m_hr != S_OK) { + *nSamplesProcessed = 0; + DbgLog((LOG_TRACE, 3, TEXT("COutputQueue (queued) : Discarding %d samples code 0x%8.8X"), + nSamples, m_hr)); + for (int i = 0; i < nSamples; i++) { + ppSamples[i]->Release(); + } + return m_hr; + } + m_bFlushed = FALSE; + for (long i = 0; i < nSamples; i++) { + QueueSample(ppSamples[i]); + } + *nSamplesProcessed = nSamples; + if (!m_bBatchExact || + m_nBatched + m_List->GetCount() >= m_lBatchSize) { + NotifyThread(); + } + return S_OK; + } +} + +// Get ready for new data - cancels sticky m_hr +void COutputQueue::Reset() +{ + if (!IsQueued()) { + m_hr = S_OK; + } else { + { + CAutoLock lck(this); + QueueSample(RESET_PACKET); + NotifyThread(); + } + m_evFlushComplete.Wait(); + } +} + +// Remove and Release() all queued and Batched samples +void COutputQueue::FreeSamples() +{ + CAutoLock lck(this); + if (IsQueued()) { + for (;;) { + IMediaSample *pSample = m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + if (pSample == NULL) { + break; + } + if (!IsSpecialSample(pSample)) { + pSample->Release(); + } else { + if (pSample == NEW_SEGMENT) { + // Free NEW_SEGMENT packet + NewSegmentPacket *ppacket = + (NewSegmentPacket *) m_List->RemoveHead(); + // inform derived class we took something off the queue + if (m_hEventPop) { + //DbgLog((LOG_TRACE,3,TEXT("Queue: Delivered SET EVENT"))); + SetEvent(m_hEventPop); + } + + ASSERT(ppacket != NULL); + delete ppacket; + } + } + } + } + for (int i = 0; i < m_nBatched; i++) { + m_ppSamples[i]->Release(); + } + m_nBatched = 0; +} + +// Notify the thread if there is something to do +// +// The critical section MUST be held when this is called +void COutputQueue::NotifyThread() +{ + // Optimize - no need to signal if it's not waiting + ASSERT(IsQueued()); + if (m_lWaiting) { + ReleaseSemaphore(m_hSem, m_lWaiting, NULL); + m_lWaiting = 0; + } +} + +// See if there's any work to do +// Returns +// TRUE if there is nothing on the queue and nothing in the batch +// and all data has been sent +// FALSE otherwise +// +BOOL COutputQueue::IsIdle() +{ + CAutoLock lck(this); + + // We're idle if + // there is no thread (!IsQueued()) OR + // the thread is waiting for more work (m_lWaiting != 0) + // AND + // there's nothing in the current batch (m_nBatched == 0) + + if (IsQueued() && m_lWaiting == 0 || m_nBatched != 0) { + return FALSE; + } else { + + // If we're idle it shouldn't be possible for there + // to be anything on the work queue + + ASSERT(!IsQueued() || m_List->GetCount() == 0); + return TRUE; + } +} + + +void COutputQueue::SetPopEvent(HANDLE hEvent) +{ + m_hEventPop = hEvent; +} diff --git a/src/thirdparty/BaseClasses/outputq.h b/src/thirdparty/BaseClasses/outputq.h index 7e60b53a990..db3d42433f1 100644 --- a/src/thirdparty/BaseClasses/outputq.h +++ b/src/thirdparty/BaseClasses/outputq.h @@ -1,137 +1,137 @@ -//------------------------------------------------------------------------------ -// File: OutputQ.h -// -// Desc: DirectShow base classes - defines the COutputQueue class, which -// makes a queue of samples and sends them to an output pin. The -// class will optionally send the samples to the pin directly. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -typedef CGenericList CSampleList; - -class COutputQueue : public CCritSec -{ -public: - // Constructor - COutputQueue(IPin *pInputPin, // Pin to send stuff to - __inout HRESULT *phr, // 'Return code' - BOOL bAuto = TRUE, // Ask pin if blocks - BOOL bQueue = TRUE, // Send through queue (ignored if - // bAuto set) - LONG lBatchSize = 1, // Batch - BOOL bBatchExact = FALSE,// Batch exactly to BatchSize - LONG lListSize = // Likely number in the list - DEFAULTCACHE, - DWORD dwPriority = // Priority of thread to create - THREAD_PRIORITY_NORMAL, - bool bFlushingOpt = false // flushing optimization - ); - ~COutputQueue(); - - // enter flush state - discard all data - void BeginFlush(); // Begin flushing samples - - // re-enable receives (pass this downstream) - void EndFlush(); // Complete flush of samples - downstream - // pin guaranteed not to block at this stage - - void EOS(); // Call this on End of stream - - void SendAnyway(); // Send batched samples anyway (if bBatchExact set) - - void NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - HRESULT Receive(IMediaSample *pSample); - - // do something with these media samples - HRESULT ReceiveMultiple ( - __in_ecount(nSamples) IMediaSample **pSamples, - long nSamples, - __out long *nSamplesProcessed); - - void Reset(); // Reset m_hr ready for more data - - // See if its idle or not - BOOL IsIdle(); - - // give the class an event to fire after everything removed from the queue - void SetPopEvent(HANDLE hEvent); - -protected: - static DWORD WINAPI InitialThreadProc(__in LPVOID pv); - DWORD ThreadProc(); - BOOL IsQueued() - { - return m_List != NULL; - }; - - // The critical section MUST be held when this is called - void QueueSample(IMediaSample *pSample); - - BOOL IsSpecialSample(IMediaSample *pSample) - { - return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16); - }; - - // Remove and Release() batched and queued samples - void FreeSamples(); - - // Notify the thread there is something to do - void NotifyThread(); - - -protected: - // Queue 'messages' - #define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch - #define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream - #define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr - #define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment - - // new segment packet is always followed by one of these - struct NewSegmentPacket { - REFERENCE_TIME tStart; - REFERENCE_TIME tStop; - double dRate; - }; - - // Remember input stuff - IPin * const m_pPin; - IMemInputPin * m_pInputPin; - BOOL const m_bBatchExact; - LONG const m_lBatchSize; - - CSampleList * m_List; - HANDLE m_hSem; - CAMEvent m_evFlushComplete; - HANDLE m_hThread; - __field_ecount_opt(m_lBatchSize) IMediaSample ** m_ppSamples; - __range(0, m_lBatchSize) LONG m_nBatched; - - // Wait optimization - LONG m_lWaiting; - // Flush synchronization - BOOL m_bFlushing; - - // flushing optimization. some downstream filters have trouble - // with the queue's flushing optimization. other rely on it - BOOL m_bFlushed; - bool m_bFlushingOpt; - - // Terminate now - BOOL m_bTerminate; - - // Send anyway flag for batching - BOOL m_bSendAnyway; - - // Deferred 'return code' - HRESULT volatile m_hr; - - // an event that can be fired after every deliver - HANDLE m_hEventPop; -}; - +//------------------------------------------------------------------------------ +// File: OutputQ.h +// +// Desc: DirectShow base classes - defines the COutputQueue class, which +// makes a queue of samples and sends them to an output pin. The +// class will optionally send the samples to the pin directly. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +typedef CGenericList CSampleList; + +class COutputQueue : public CCritSec +{ +public: + // Constructor + COutputQueue(IPin *pInputPin, // Pin to send stuff to + __inout HRESULT *phr, // 'Return code' + BOOL bAuto = TRUE, // Ask pin if blocks + BOOL bQueue = TRUE, // Send through queue (ignored if + // bAuto set) + LONG lBatchSize = 1, // Batch + BOOL bBatchExact = FALSE,// Batch exactly to BatchSize + LONG lListSize = // Likely number in the list + DEFAULTCACHE, + DWORD dwPriority = // Priority of thread to create + THREAD_PRIORITY_NORMAL, + bool bFlushingOpt = false // flushing optimization + ); + ~COutputQueue(); + + // enter flush state - discard all data + void BeginFlush(); // Begin flushing samples + + // re-enable receives (pass this downstream) + void EndFlush(); // Complete flush of samples - downstream + // pin guaranteed not to block at this stage + + void EOS(); // Call this on End of stream + + void SendAnyway(); // Send batched samples anyway (if bBatchExact set) + + void NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + HRESULT Receive(IMediaSample *pSample); + + // do something with these media samples + HRESULT ReceiveMultiple ( + __in_ecount(nSamples) IMediaSample **pSamples, + long nSamples, + __out long *nSamplesProcessed); + + void Reset(); // Reset m_hr ready for more data + + // See if its idle or not + BOOL IsIdle(); + + // give the class an event to fire after everything removed from the queue + void SetPopEvent(HANDLE hEvent); + +protected: + static DWORD WINAPI InitialThreadProc(__in LPVOID pv); + DWORD ThreadProc(); + BOOL IsQueued() + { + return m_List != NULL; + }; + + // The critical section MUST be held when this is called + void QueueSample(IMediaSample *pSample); + + BOOL IsSpecialSample(IMediaSample *pSample) + { + return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16); + }; + + // Remove and Release() batched and queued samples + void FreeSamples(); + + // Notify the thread there is something to do + void NotifyThread(); + + +protected: + // Queue 'messages' + #define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch + #define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream + #define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr + #define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment + + // new segment packet is always followed by one of these + struct NewSegmentPacket { + REFERENCE_TIME tStart; + REFERENCE_TIME tStop; + double dRate; + }; + + // Remember input stuff + IPin * const m_pPin; + IMemInputPin * m_pInputPin; + BOOL const m_bBatchExact; + LONG const m_lBatchSize; + + CSampleList * m_List; + HANDLE m_hSem; + CAMEvent m_evFlushComplete; + HANDLE m_hThread; + __field_ecount_opt(m_lBatchSize) IMediaSample ** m_ppSamples; + __range(0, m_lBatchSize) LONG m_nBatched; + + // Wait optimization + LONG m_lWaiting; + // Flush synchronization + BOOL m_bFlushing; + + // flushing optimization. some downstream filters have trouble + // with the queue's flushing optimization. other rely on it + BOOL m_bFlushed; + bool m_bFlushingOpt; + + // Terminate now + BOOL m_bTerminate; + + // Send anyway flag for batching + BOOL m_bSendAnyway; + + // Deferred 'return code' + HRESULT volatile m_hr; + + // an event that can be fired after every deliver + HANDLE m_hEventPop; +}; + diff --git a/src/thirdparty/BaseClasses/perflog.cpp b/src/thirdparty/BaseClasses/perflog.cpp index 3b90fe6a0c5..4c35faf82c4 100644 --- a/src/thirdparty/BaseClasses/perflog.cpp +++ b/src/thirdparty/BaseClasses/perflog.cpp @@ -1,347 +1,347 @@ -//------------------------------------------------------------------------------ -// File: perflog.cpp -// -// Desc: Macros for DirectShow performance logging. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - -#pragma warning (disable:4201) - -#include "streams.h" -#include -#include -#include -#include -#include -#include -#include "perflog.h" - -// -// Local function prototypes. -// - -ULONG -WINAPI -PerflogCallback ( - WMIDPREQUESTCODE RequestCode, - __in PVOID Context, - __out ULONG* BufferSize, - __in PVOID Buffer - ); - -// -// Event tracing function pointers. -// We have to do this to run on down-level platforms. -// - -#ifdef UNICODE - -ULONG -(__stdcall * _RegisterTraceGuids) ( - __in IN WMIDPREQUEST RequestAddress, - __in IN PVOID RequestContext, - IN LPCGUID ControlGuid, - IN ULONG GuidCount, - __in IN PTRACE_GUID_REGISTRATION TraceGuidReg, - IN LPCWSTR MofImagePath, - IN LPCWSTR MofResourceName, - OUT PTRACEHANDLE RegistrationHandle - ); - -#define REGISTERTRACEGUIDS_NAME "RegisterTraceGuidsW" - -#else - -ULONG -(__stdcall * _RegisterTraceGuids) ( - __in IN WMIDPREQUEST RequestAddress, - __in IN PVOID RequestContext, - IN LPCGUID ControlGuid, - IN ULONG GuidCount, - __in IN PTRACE_GUID_REGISTRATION TraceGuidReg, - IN LPCSTR MofImagePath, - IN LPCSTR MofResourceName, - __out OUT PTRACEHANDLE RegistrationHandle - ); - -#define REGISTERTRACEGUIDS_NAME "RegisterTraceGuidsA" - -#endif - -ULONG -(__stdcall * _UnregisterTraceGuids) ( - TRACEHANDLE RegistrationHandle - ); - -TRACEHANDLE -(__stdcall * _GetTraceLoggerHandle) ( - __in PVOID Buffer - ); - -UCHAR -(__stdcall * _GetTraceEnableLevel) ( - TRACEHANDLE TraceHandle - ); - -ULONG -(__stdcall * _GetTraceEnableFlags) ( - TRACEHANDLE TraceHandle - ); - -ULONG -(__stdcall * _TraceEvent) ( - TRACEHANDLE TraceHandle, - __in PEVENT_TRACE_HEADER EventTrace - ); - -HINSTANCE _Advapi32; - -// -// Global variables. -// - -BOOL EventTracingAvailable=FALSE; -ULONG PerflogEnableFlags; -UCHAR PerflogEnableLevel; -ULONG PerflogModuleLevel = 0; -void (*OnStateChanged)(void); -TRACEHANDLE PerflogTraceHandle=NULL; -TRACEHANDLE PerflogRegHandle; - -// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. -// See the documentation for wsprintf()'s lpOut parameter for more information. -const INT iDEBUGINFO = 1024; // Used to format strings - -// -// This routine initializes performance logging. -// It should be called from DllMain(). -// - - -VOID -PerflogReadModuleLevel( - HINSTANCE hInstance - ) -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - TCHAR szFullName[iDEBUGINFO]; // Load the full path and module name - HKEY hModuleKey; // Module key handle - LPTSTR pName; // Searches from the end for a backslash - DWORD dwKeySize, dwKeyType, dwKeyValue; - - DWORD dwSize = GetModuleFileName( - (hInstance ? hInstance : GetModuleHandle( NULL )), - szFullName, - iDEBUGINFO ); - - if (0 == dwSize || iDEBUGINFO == dwSize) { - return; - } - - pName = _tcsrchr(szFullName,'\\'); - if (pName == NULL) { - pName = szFullName; - } else { - pName++; - } - - /* Construct the base key name */ - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("SOFTWARE\\Debug\\%s"),pName); - - /* Open the key for this module */ - lReturn = - RegOpenKeyEx( - HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - KEY_QUERY_VALUE, // Desired security access - &hModuleKey ); // Opened handle buffer - - if (lReturn != ERROR_SUCCESS) { - return; - } - - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hModuleKey, // Handle to an open key - TEXT("PERFLOG"), - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) &dwKeyValue, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - if ((lReturn == ERROR_SUCCESS) && (dwKeyType == REG_DWORD)) - { - PerflogModuleLevel = dwKeyValue; - } - - RegCloseKey(hModuleKey); -} - -BOOL PerflogInitIfEnabled( - IN HINSTANCE hInstance, - __in IN PPERFLOG_LOGGING_PARAMS LogParams - ) -{ - PerflogReadModuleLevel( hInstance ); - if (PerflogModuleLevel) - { - return PerflogInitialize( LogParams ); - } - else - { - return FALSE; - } -} - -BOOL -PerflogInitialize ( - __in IN PPERFLOG_LOGGING_PARAMS LogParams - ) -{ - ULONG status; - - // - // If we're running on a recent-enough platform, this will get - // pointers to the event tracing routines. - // - - _Advapi32 = GetModuleHandle (_T("ADVAPI32.DLL")); - if (_Advapi32 == NULL) { - return FALSE; - } - - *((FARPROC*) &_RegisterTraceGuids) = GetProcAddress (_Advapi32, REGISTERTRACEGUIDS_NAME); - *((FARPROC*) &_UnregisterTraceGuids) = GetProcAddress (_Advapi32, "UnregisterTraceGuids"); - *((FARPROC*) &_GetTraceLoggerHandle) = GetProcAddress (_Advapi32, "GetTraceLoggerHandle"); - *((FARPROC*) &_GetTraceEnableLevel) = GetProcAddress (_Advapi32, "GetTraceEnableLevel"); - *((FARPROC*) &_GetTraceEnableFlags) = GetProcAddress (_Advapi32, "GetTraceEnableFlags"); - *((FARPROC*) &_TraceEvent) = GetProcAddress (_Advapi32, "TraceEvent"); - - if (_RegisterTraceGuids == NULL || - _UnregisterTraceGuids == NULL || - _GetTraceEnableLevel == NULL || - _GetTraceEnableFlags == NULL || - _TraceEvent == NULL) { - - return FALSE; - } - - EventTracingAvailable = TRUE; - - OnStateChanged = LogParams->OnStateChanged; - - // - // Register our GUIDs. - // - - status = _RegisterTraceGuids (PerflogCallback, - LogParams, - &LogParams->ControlGuid, - LogParams->NumberOfTraceGuids, - LogParams->TraceGuids, - NULL, - NULL, - &PerflogRegHandle); - - return (status == ERROR_SUCCESS); -} - -// -// This routine shuts down performance logging. -// - -VOID -PerflogShutdown ( - VOID - ) -{ - if (!EventTracingAvailable) { - return; - } - - _UnregisterTraceGuids (PerflogRegHandle); - PerflogRegHandle = NULL; - PerflogTraceHandle = NULL; -} - -// -// Event tracing callback routine. -// It's called when controllers call event tracing control functions. -// - -ULONG -WINAPI -PerflogCallback ( - WMIDPREQUESTCODE RequestCode, - __in PVOID Context, - __out ULONG* BufferSize, - __in PVOID Buffer - ) -{ - ULONG status; - - UNREFERENCED_PARAMETER (Context); - - ASSERT (EventTracingAvailable); - - status = ERROR_SUCCESS; - - switch (RequestCode) { - - case WMI_ENABLE_EVENTS: - PerflogTraceHandle = _GetTraceLoggerHandle (Buffer); - PerflogEnableFlags = _GetTraceEnableFlags (PerflogTraceHandle); - PerflogEnableLevel = _GetTraceEnableLevel (PerflogTraceHandle); - break; - - case WMI_DISABLE_EVENTS: - PerflogTraceHandle = NULL; - PerflogEnableFlags = 0; - PerflogEnableLevel = 0; - break; - - default: - status = ERROR_INVALID_PARAMETER; - } - - if (OnStateChanged != NULL) { - OnStateChanged(); - } - - *BufferSize = 0; - return status; -} - -// -// Logging routine. -// - -VOID -PerflogTraceEvent ( - __in PEVENT_TRACE_HEADER Event - ) -{ - if (!EventTracingAvailable) { - return; - } - - _TraceEvent (PerflogTraceHandle, Event); -} - -VOID -PerflogTraceEventLevel( - ULONG Level, - __in PEVENT_TRACE_HEADER Event - ) -{ - if ((!EventTracingAvailable) || (Level <= PerflogModuleLevel)) { - return; - } - - _TraceEvent (PerflogTraceHandle, Event); -} - - +//------------------------------------------------------------------------------ +// File: perflog.cpp +// +// Desc: Macros for DirectShow performance logging. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +#pragma warning (disable:4201) + +#include "streams.h" +#include +#include +#include +#include +#include +#include +#include "perflog.h" + +// +// Local function prototypes. +// + +ULONG +WINAPI +PerflogCallback ( + WMIDPREQUESTCODE RequestCode, + __in PVOID Context, + __out ULONG* BufferSize, + __in PVOID Buffer + ); + +// +// Event tracing function pointers. +// We have to do this to run on down-level platforms. +// + +#ifdef UNICODE + +ULONG +(__stdcall * _RegisterTraceGuids) ( + __in IN WMIDPREQUEST RequestAddress, + __in IN PVOID RequestContext, + IN LPCGUID ControlGuid, + IN ULONG GuidCount, + __in IN PTRACE_GUID_REGISTRATION TraceGuidReg, + IN LPCWSTR MofImagePath, + IN LPCWSTR MofResourceName, + OUT PTRACEHANDLE RegistrationHandle + ); + +#define REGISTERTRACEGUIDS_NAME "RegisterTraceGuidsW" + +#else + +ULONG +(__stdcall * _RegisterTraceGuids) ( + __in IN WMIDPREQUEST RequestAddress, + __in IN PVOID RequestContext, + IN LPCGUID ControlGuid, + IN ULONG GuidCount, + __in IN PTRACE_GUID_REGISTRATION TraceGuidReg, + IN LPCSTR MofImagePath, + IN LPCSTR MofResourceName, + __out OUT PTRACEHANDLE RegistrationHandle + ); + +#define REGISTERTRACEGUIDS_NAME "RegisterTraceGuidsA" + +#endif + +ULONG +(__stdcall * _UnregisterTraceGuids) ( + TRACEHANDLE RegistrationHandle + ); + +TRACEHANDLE +(__stdcall * _GetTraceLoggerHandle) ( + __in PVOID Buffer + ); + +UCHAR +(__stdcall * _GetTraceEnableLevel) ( + TRACEHANDLE TraceHandle + ); + +ULONG +(__stdcall * _GetTraceEnableFlags) ( + TRACEHANDLE TraceHandle + ); + +ULONG +(__stdcall * _TraceEvent) ( + TRACEHANDLE TraceHandle, + __in PEVENT_TRACE_HEADER EventTrace + ); + +HINSTANCE _Advapi32; + +// +// Global variables. +// + +BOOL EventTracingAvailable=FALSE; +ULONG PerflogEnableFlags; +UCHAR PerflogEnableLevel; +ULONG PerflogModuleLevel = 0; +void (*OnStateChanged)(void); +TRACEHANDLE PerflogTraceHandle=NULL; +TRACEHANDLE PerflogRegHandle; + +// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. +// See the documentation for wsprintf()'s lpOut parameter for more information. +const INT iDEBUGINFO = 1024; // Used to format strings + +// +// This routine initializes performance logging. +// It should be called from DllMain(). +// + + +VOID +PerflogReadModuleLevel( + HINSTANCE hInstance + ) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + TCHAR szFullName[iDEBUGINFO]; // Load the full path and module name + HKEY hModuleKey; // Module key handle + LPTSTR pName; // Searches from the end for a backslash + DWORD dwKeySize, dwKeyType, dwKeyValue; + + DWORD dwSize = GetModuleFileName( + (hInstance ? hInstance : GetModuleHandle( NULL )), + szFullName, + iDEBUGINFO ); + + if (0 == dwSize || iDEBUGINFO == dwSize) { + return; + } + + pName = _tcsrchr(szFullName,'\\'); + if (pName == NULL) { + pName = szFullName; + } else { + pName++; + } + + /* Construct the base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("SOFTWARE\\Debug\\%s"),pName); + + /* Open the key for this module */ + lReturn = + RegOpenKeyEx( + HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + KEY_QUERY_VALUE, // Desired security access + &hModuleKey ); // Opened handle buffer + + if (lReturn != ERROR_SUCCESS) { + return; + } + + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hModuleKey, // Handle to an open key + TEXT("PERFLOG"), + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwKeyValue, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + if ((lReturn == ERROR_SUCCESS) && (dwKeyType == REG_DWORD)) + { + PerflogModuleLevel = dwKeyValue; + } + + RegCloseKey(hModuleKey); +} + +BOOL PerflogInitIfEnabled( + IN HINSTANCE hInstance, + __in IN PPERFLOG_LOGGING_PARAMS LogParams + ) +{ + PerflogReadModuleLevel( hInstance ); + if (PerflogModuleLevel) + { + return PerflogInitialize( LogParams ); + } + else + { + return FALSE; + } +} + +BOOL +PerflogInitialize ( + __in IN PPERFLOG_LOGGING_PARAMS LogParams + ) +{ + ULONG status; + + // + // If we're running on a recent-enough platform, this will get + // pointers to the event tracing routines. + // + + _Advapi32 = GetModuleHandle (_T("ADVAPI32.DLL")); + if (_Advapi32 == NULL) { + return FALSE; + } + + *((FARPROC*) &_RegisterTraceGuids) = GetProcAddress (_Advapi32, REGISTERTRACEGUIDS_NAME); + *((FARPROC*) &_UnregisterTraceGuids) = GetProcAddress (_Advapi32, "UnregisterTraceGuids"); + *((FARPROC*) &_GetTraceLoggerHandle) = GetProcAddress (_Advapi32, "GetTraceLoggerHandle"); + *((FARPROC*) &_GetTraceEnableLevel) = GetProcAddress (_Advapi32, "GetTraceEnableLevel"); + *((FARPROC*) &_GetTraceEnableFlags) = GetProcAddress (_Advapi32, "GetTraceEnableFlags"); + *((FARPROC*) &_TraceEvent) = GetProcAddress (_Advapi32, "TraceEvent"); + + if (_RegisterTraceGuids == NULL || + _UnregisterTraceGuids == NULL || + _GetTraceEnableLevel == NULL || + _GetTraceEnableFlags == NULL || + _TraceEvent == NULL) { + + return FALSE; + } + + EventTracingAvailable = TRUE; + + OnStateChanged = LogParams->OnStateChanged; + + // + // Register our GUIDs. + // + + status = _RegisterTraceGuids (PerflogCallback, + LogParams, + &LogParams->ControlGuid, + LogParams->NumberOfTraceGuids, + LogParams->TraceGuids, + NULL, + NULL, + &PerflogRegHandle); + + return (status == ERROR_SUCCESS); +} + +// +// This routine shuts down performance logging. +// + +VOID +PerflogShutdown ( + VOID + ) +{ + if (!EventTracingAvailable) { + return; + } + + _UnregisterTraceGuids (PerflogRegHandle); + PerflogRegHandle = NULL; + PerflogTraceHandle = NULL; +} + +// +// Event tracing callback routine. +// It's called when controllers call event tracing control functions. +// + +ULONG +WINAPI +PerflogCallback ( + WMIDPREQUESTCODE RequestCode, + __in PVOID Context, + __out ULONG* BufferSize, + __in PVOID Buffer + ) +{ + ULONG status; + + UNREFERENCED_PARAMETER (Context); + + ASSERT (EventTracingAvailable); + + status = ERROR_SUCCESS; + + switch (RequestCode) { + + case WMI_ENABLE_EVENTS: + PerflogTraceHandle = _GetTraceLoggerHandle (Buffer); + PerflogEnableFlags = _GetTraceEnableFlags (PerflogTraceHandle); + PerflogEnableLevel = _GetTraceEnableLevel (PerflogTraceHandle); + break; + + case WMI_DISABLE_EVENTS: + PerflogTraceHandle = NULL; + PerflogEnableFlags = 0; + PerflogEnableLevel = 0; + break; + + default: + status = ERROR_INVALID_PARAMETER; + } + + if (OnStateChanged != NULL) { + OnStateChanged(); + } + + *BufferSize = 0; + return status; +} + +// +// Logging routine. +// + +VOID +PerflogTraceEvent ( + __in PEVENT_TRACE_HEADER Event + ) +{ + if (!EventTracingAvailable) { + return; + } + + _TraceEvent (PerflogTraceHandle, Event); +} + +VOID +PerflogTraceEventLevel( + ULONG Level, + __in PEVENT_TRACE_HEADER Event + ) +{ + if ((!EventTracingAvailable) || (Level <= PerflogModuleLevel)) { + return; + } + + _TraceEvent (PerflogTraceHandle, Event); +} + + diff --git a/src/thirdparty/BaseClasses/perflog.h b/src/thirdparty/BaseClasses/perflog.h index 05d6404f6ae..503a1304f25 100644 --- a/src/thirdparty/BaseClasses/perflog.h +++ b/src/thirdparty/BaseClasses/perflog.h @@ -1,56 +1,56 @@ -//------------------------------------------------------------------------------ -// File: perflog.h -// -// Desc: Performance logging framework. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - -typedef struct _PERFLOG_LOGGING_PARAMS { - GUID ControlGuid; - void (*OnStateChanged)(void); - ULONG NumberOfTraceGuids; - TRACE_GUID_REGISTRATION TraceGuids[ANYSIZE_ARRAY]; -} PERFLOG_LOGGING_PARAMS, *PPERFLOG_LOGGING_PARAMS; - -BOOL -PerflogInitIfEnabled( - IN HINSTANCE hInstance, - __in PPERFLOG_LOGGING_PARAMS LogParams - ); - -BOOL -PerflogInitialize ( - __in PPERFLOG_LOGGING_PARAMS LogParams - ); - -VOID -PerflogShutdown ( - VOID - ); - -VOID -PerflogTraceEvent ( - __in PEVENT_TRACE_HEADER Event - ); - -extern ULONG PerflogEnableFlags; -extern UCHAR PerflogEnableLevel; -extern ULONG PerflogModuleLevel; -extern TRACEHANDLE PerflogTraceHandle; -extern TRACEHANDLE PerflogRegHandle; - -#define PerflogTracingEnabled() (PerflogTraceHandle != 0) - -#define PerflogEvent( _x_ ) PerflogTraceEventLevel _x_ - -VOID -PerflogTraceEventLevel( - ULONG Level, - __in PEVENT_TRACE_HEADER Event - ); - -VOID -PerflogTraceEvent ( - __in PEVENT_TRACE_HEADER Event - ); +//------------------------------------------------------------------------------ +// File: perflog.h +// +// Desc: Performance logging framework. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + +typedef struct _PERFLOG_LOGGING_PARAMS { + GUID ControlGuid; + void (*OnStateChanged)(void); + ULONG NumberOfTraceGuids; + TRACE_GUID_REGISTRATION TraceGuids[ANYSIZE_ARRAY]; +} PERFLOG_LOGGING_PARAMS, *PPERFLOG_LOGGING_PARAMS; + +BOOL +PerflogInitIfEnabled( + IN HINSTANCE hInstance, + __in PPERFLOG_LOGGING_PARAMS LogParams + ); + +BOOL +PerflogInitialize ( + __in PPERFLOG_LOGGING_PARAMS LogParams + ); + +VOID +PerflogShutdown ( + VOID + ); + +VOID +PerflogTraceEvent ( + __in PEVENT_TRACE_HEADER Event + ); + +extern ULONG PerflogEnableFlags; +extern UCHAR PerflogEnableLevel; +extern ULONG PerflogModuleLevel; +extern TRACEHANDLE PerflogTraceHandle; +extern TRACEHANDLE PerflogRegHandle; + +#define PerflogTracingEnabled() (PerflogTraceHandle != 0) + +#define PerflogEvent( _x_ ) PerflogTraceEventLevel _x_ + +VOID +PerflogTraceEventLevel( + ULONG Level, + __in PEVENT_TRACE_HEADER Event + ); + +VOID +PerflogTraceEvent ( + __in PEVENT_TRACE_HEADER Event + ); diff --git a/src/thirdparty/BaseClasses/perfstruct.h b/src/thirdparty/BaseClasses/perfstruct.h index b57657c820c..9c67b738d0b 100644 --- a/src/thirdparty/BaseClasses/perfstruct.h +++ b/src/thirdparty/BaseClasses/perfstruct.h @@ -1,194 +1,194 @@ -//------------------------------------------------------------------------------ -// File: PerfStruct.h -// -// Desc: Structures for DirectShow performance logging. -// -// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef _PERFSTRUCT_H_ -#define _PERFSTRUCT_H_ - -#include -#include - -// {28CF047A-2437-4b24-B653-B9446A419A69} -DEFINE_GUID(GUID_DSHOW_CTL, -0x28cf047a, 0x2437, 0x4b24, 0xb6, 0x53, 0xb9, 0x44, 0x6a, 0x41, 0x9a, 0x69); - -// {D0DA7AD6-AE80-4de5-AAFC-C126711E7593} -DEFINE_GUID(GUID_VIDEOREND, -0xd0da7ad6, 0xae80, 0x4de5, 0xaa, 0xfc, 0xc1, 0x26, 0x71, 0x1e, 0x75, 0x93); - -// {DC70AC3E-93E5-48db-88AB-E42064EC276A} -DEFINE_GUID(GUID_DSOUNDGLITCH, -0xdc70ac3e, 0x93e5, 0x48db, 0x88, 0xab, 0xe4, 0x20, 0x64, 0xec, 0x27, 0x6a); - -// {3d7e7d93-2fc8-4a07-a719-e0922ff2899} -DEFINE_GUID(GUID_STREAMTRACE, -0x3d7e7d93, 0x2fc8, 0x4a07, 0xa7, 0x19, 0xe0, 0x92, 0x2f, 0xf2, 0x89, 0x9e); - -// AZFIX: the following GUIDs aren't useful right now. - -// {3C33F7F5-EE54-493c-BA25-1656539C05AC} -DEFINE_GUID(GUID_GETTIME, -0x3c33f7f5, 0xee54, 0x493c, 0xba, 0x25, 0x16, 0x56, 0x53, 0x9c, 0x5, 0xac); - -// {CC44B44D-8169-4952-9E4A-A4E13295E492} -DEFINE_GUID(GUID_AUDIOREND, -0xcc44b44d, 0x8169, 0x4952, 0x9e, 0x4a, 0xa4, 0xe1, 0x32, 0x95, 0xe4, 0x92); - -// {775D19BF-4D8B-4de6-8DC9-66BAC7B310A2} -DEFINE_GUID(GUID_FRAMEDROP, -0x775d19bf, 0x4d8b, 0x4de6, 0x8d, 0xc9, 0x66, 0xba, 0xc7, 0xb3, 0x10, 0xa2); - -// {56D29065-EFBE-42dc-8C29-E325DC9C27D5} -DEFINE_GUID(GUID_AUDIOBREAK, -0x56d29065, 0xefbe, 0x42dc, 0x8c, 0x29, 0xe3, 0x25, 0xdc, 0x9c, 0x27, 0xd5); - -// {E1E6EA87-95A8-497e-BFBA-0295AEBCC707} -DEFINE_GUID(GUID_AUDIORECV, -0xe1e6ea87, 0x95a8, 0x497e, 0xbf, 0xba, 0x2, 0x95, 0xae, 0xbc, 0xc7, 0x7); - -// {10F7768A-B1E7-4242-AD90-A2D44683D9F0} -DEFINE_GUID(GUID_AUDIOSLAVE, -0x10f7768a, 0xb1e7, 0x4242, 0xad, 0x90, 0xa2, 0xd4, 0x46, 0x83, 0xd9, 0xf0); - -// {8983803D-691A-49bc-8FF6-962A39C0198F} -DEFINE_GUID(GUID_AUDIOADDBREAK, -0x8983803d, 0x691a, 0x49bc, 0x8f, 0xf6, 0x96, 0x2a, 0x39, 0xc0, 0x19, 0x8f); - -#define GLITCHTYPE_DSOUNDFIRSTGOOD 0 -#define GLITCHTYPE_DSOUNDFIRSTBAD 1 - -typedef struct PERFINFO_DSHOW_AUDIOGLITCH { - ULONGLONG cycleCounter; - DWORD glitchType; - LONGLONG sampleTime; - LONGLONG previousTime; - ULONG_PTR instanceId; -} PERFINFO_DSHOW_AUDIOGLITCH, *PPERFINFO_DSHOW_AUDIOGLITCH; - -typedef struct PERFINFO_WMI_AUDIOGLITCH { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIOGLITCH data; -} PERFINFO_WMI_AUDIO_GLITCH, *PPERFINFO_WMI_AUDIOGLITCH; - -typedef struct PERFINFO_DSHOW_GETTIME { - ULONGLONG cycleCounter; - ULONGLONG dshowClock; -} PERFINFO_DSHOW_GETTIME, *PPERFINFO_DSHOW_GETTIME; - -typedef struct PERFINFO_WMI_GETTIME { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_GETTIME data; -} PERFINFO_WMI_GETTIME, *PPERFINFO_WMI_GETTIME; - -typedef struct PERFINFO_DSHOW_AVREND { - ULONGLONG cycleCounter; - ULONGLONG dshowClock; - ULONGLONG sampleTime; -} PERFINFO_DSHOW_AVREND, *PPERFINFO_DSHOW_AVREND; - -typedef struct PERFINFO_WMI_AVREND { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AVREND data; -} PERFINFO_WMI_AVREND, *PPERFINFO_WMI_AVREND; - -typedef struct PERFINFO_DSHOW_AUDIOBREAK { - ULONGLONG cycleCounter; - ULONGLONG dshowClock; - ULONGLONG sampleTime; - ULONGLONG sampleDuration; -} PERFINFO_DSHOW_AUDIOBREAK, *PPERFINFO_DSHOW_AUDIOBREAK; - -typedef struct PERFINFO_WMI_AUDIOBREAK { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIOBREAK data; -} PERFINFO_WMI_AUDIOBREAK, *PPERFINFO_WMI_AUDIOBREAK; - -typedef struct PERFINFO_DSHOW_FRAMEDROP { - ULONGLONG cycleCounter; - ULONGLONG dshowClock; - ULONGLONG frameTime; -} PERFINFO_DSHOW_FRAMEDROP, *PPERFINFO_DSHOW_FRAMEDROP; - -typedef struct PERFINFO_WMI_FRAMEDROP { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_FRAMEDROP data; -} PERFINFO_WMI_FRAMEDROP, *PPERFINFO_WMI_FRAMEDROP; - -#define PERFINFO_STREAMTRACE_MPEG2DEMUX_PTS_TRANSLATION 1 -#define PERFINFO_STREAMTRACE_MPEG2DEMUX_SAMPLE_RECEIVED 2 -#define PERFINFO_STREAMTRACE_VMR_BEGIN_ADVISE 3 -#define PERFINFO_STREAMTRACE_VMR_END_ADVISE 4 -#define PERFINFO_STREAMTRACE_VMR_RECEIVE 5 -#define PERFINFO_STREAMTRACE_VMR_BEGIN_DEINTERLACE 6 -#define PERFINFO_STREAMTRACE_VMR_END_DEINTERLACE 7 -#define PERFINFO_STREAMTRACE_VMR_BEGIN_DECODE 8 -#define PERFINFO_STREAMTRACE_VMR_END_DECODE 9 -#define PERFINFO_STREAMTRACE_VMR_DROPPED_FRAME 10 -#define PERFINFO_STREAMTRACE_ENCDEC_DTFILTERINPUT 11 -#define PERFINFO_STREAMTRACE_ENCDEC_DTFILTEROUTPUT 12 -#define PERFINFO_STREAMTRACE_ENCDEC_ETFILTERINPUT 13 -#define PERFINFO_STREAMTRACE_ENCDEC_ETFILTEROUTPUT 14 -#define PERFINFO_STREAMTRACE_ENCDEC_XDSCODECINPUT 15 -#define PERFINFO_STREAMTRACE_SBE_DVRANALYSISINPUT_RECEIVE 16 -#define PERFINFO_STREAMTRACE_SBE_DVRANALYSISINPUT_DELIVER 17 -#define PERFINFO_STREAMTRACE_SBE_DVRINPUTPIN_RECEIVE 18 -#define PERFINFO_STREAMTRACE_SBE_DVROUTPUTPIN_RECEIVE 19 -#define PERFINFO_STREAMTRACE_VMR_RENDER_TIME 20 - -typedef struct _PERFINFO_DSHOW_STREAMTRACE { - ULONG id; - ULONG reserved; - ULONGLONG dshowClock; - ULONGLONG data[ 4 ]; -} PERFINFO_DSHOW_STREAMTRACE, *PPERFINFO_DSHOW_STREAMTRACE; - -typedef struct _PERFINFO_WMI_STREAMTRACE { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_STREAMTRACE data; -} PERFINFO_WMI_STREAMTRACE, *PPERFINFO_WMI_STREAMTRACE; - - -typedef struct PERFINFO_DSHOW_AUDIORECV { - LONGLONG streamTime ; - LONGLONG sampleStart ; - LONGLONG sampleStop ; - LONGLONG hwduration ; - BOOL discontinuity ; -} PERFINFO_DSHOW_AUDIORECV, *PPERFINFO_DSHOW_AUDIORECV; - -typedef struct PERFINFO_WMI_AUDIORECV { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIORECV data; -} PERFINFO_WMI_AUDIORECV, *PPERFINFO_WMI_AUDIORECV; - -typedef struct PERFINFO_DSHOW_AUDIOSLAVE { - LONGLONG masterClock ; - LONGLONG slaveClock ; - LONGLONG errorAccum ; - LONGLONG lastHighErrorSeen ; - LONGLONG lastLowErrorSeen ; -} PERFINFO_DSHOW_AUDIOSLAVE, *PPERFINFO_DSHOW_AUDIOSLAVE; - -typedef struct PERFINFO_WMI_AUDIOSLAVE { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIOSLAVE data; -} PERFINFO_WMI_AUDIOSLAVE, *PPERFINFO_WMI_AUDIOSLAVE; - -typedef struct PERFINFO_DSHOW_AUDIOADDBREAK { - DWORD iterNextWrite ; - DWORD offsetNextWrite ; - DWORD iterWrite ; - DWORD offsetWrite ; -} PERFINFO_DSHOW_AUDIOADDBREAK, *PPERFINFO_DSHOW_AUDIOADDBREAK; - -typedef struct PERFINFO_WMI_AUDIOADDBREAK { - EVENT_TRACE_HEADER header; - PERFINFO_DSHOW_AUDIOADDBREAK data; -} PERFINFO_WMI_AUDIOADDBREAK, *PPERFINFO_WMI_AUDIOADDBREAK; - -#endif // _PREFSTRUCT_H_ +//------------------------------------------------------------------------------ +// File: PerfStruct.h +// +// Desc: Structures for DirectShow performance logging. +// +// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef _PERFSTRUCT_H_ +#define _PERFSTRUCT_H_ + +#include +#include + +// {28CF047A-2437-4b24-B653-B9446A419A69} +DEFINE_GUID(GUID_DSHOW_CTL, +0x28cf047a, 0x2437, 0x4b24, 0xb6, 0x53, 0xb9, 0x44, 0x6a, 0x41, 0x9a, 0x69); + +// {D0DA7AD6-AE80-4de5-AAFC-C126711E7593} +DEFINE_GUID(GUID_VIDEOREND, +0xd0da7ad6, 0xae80, 0x4de5, 0xaa, 0xfc, 0xc1, 0x26, 0x71, 0x1e, 0x75, 0x93); + +// {DC70AC3E-93E5-48db-88AB-E42064EC276A} +DEFINE_GUID(GUID_DSOUNDGLITCH, +0xdc70ac3e, 0x93e5, 0x48db, 0x88, 0xab, 0xe4, 0x20, 0x64, 0xec, 0x27, 0x6a); + +// {3d7e7d93-2fc8-4a07-a719-e0922ff2899} +DEFINE_GUID(GUID_STREAMTRACE, +0x3d7e7d93, 0x2fc8, 0x4a07, 0xa7, 0x19, 0xe0, 0x92, 0x2f, 0xf2, 0x89, 0x9e); + +// AZFIX: the following GUIDs aren't useful right now. + +// {3C33F7F5-EE54-493c-BA25-1656539C05AC} +DEFINE_GUID(GUID_GETTIME, +0x3c33f7f5, 0xee54, 0x493c, 0xba, 0x25, 0x16, 0x56, 0x53, 0x9c, 0x5, 0xac); + +// {CC44B44D-8169-4952-9E4A-A4E13295E492} +DEFINE_GUID(GUID_AUDIOREND, +0xcc44b44d, 0x8169, 0x4952, 0x9e, 0x4a, 0xa4, 0xe1, 0x32, 0x95, 0xe4, 0x92); + +// {775D19BF-4D8B-4de6-8DC9-66BAC7B310A2} +DEFINE_GUID(GUID_FRAMEDROP, +0x775d19bf, 0x4d8b, 0x4de6, 0x8d, 0xc9, 0x66, 0xba, 0xc7, 0xb3, 0x10, 0xa2); + +// {56D29065-EFBE-42dc-8C29-E325DC9C27D5} +DEFINE_GUID(GUID_AUDIOBREAK, +0x56d29065, 0xefbe, 0x42dc, 0x8c, 0x29, 0xe3, 0x25, 0xdc, 0x9c, 0x27, 0xd5); + +// {E1E6EA87-95A8-497e-BFBA-0295AEBCC707} +DEFINE_GUID(GUID_AUDIORECV, +0xe1e6ea87, 0x95a8, 0x497e, 0xbf, 0xba, 0x2, 0x95, 0xae, 0xbc, 0xc7, 0x7); + +// {10F7768A-B1E7-4242-AD90-A2D44683D9F0} +DEFINE_GUID(GUID_AUDIOSLAVE, +0x10f7768a, 0xb1e7, 0x4242, 0xad, 0x90, 0xa2, 0xd4, 0x46, 0x83, 0xd9, 0xf0); + +// {8983803D-691A-49bc-8FF6-962A39C0198F} +DEFINE_GUID(GUID_AUDIOADDBREAK, +0x8983803d, 0x691a, 0x49bc, 0x8f, 0xf6, 0x96, 0x2a, 0x39, 0xc0, 0x19, 0x8f); + +#define GLITCHTYPE_DSOUNDFIRSTGOOD 0 +#define GLITCHTYPE_DSOUNDFIRSTBAD 1 + +typedef struct PERFINFO_DSHOW_AUDIOGLITCH { + ULONGLONG cycleCounter; + DWORD glitchType; + LONGLONG sampleTime; + LONGLONG previousTime; + ULONG_PTR instanceId; +} PERFINFO_DSHOW_AUDIOGLITCH, *PPERFINFO_DSHOW_AUDIOGLITCH; + +typedef struct PERFINFO_WMI_AUDIOGLITCH { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIOGLITCH data; +} PERFINFO_WMI_AUDIO_GLITCH, *PPERFINFO_WMI_AUDIOGLITCH; + +typedef struct PERFINFO_DSHOW_GETTIME { + ULONGLONG cycleCounter; + ULONGLONG dshowClock; +} PERFINFO_DSHOW_GETTIME, *PPERFINFO_DSHOW_GETTIME; + +typedef struct PERFINFO_WMI_GETTIME { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_GETTIME data; +} PERFINFO_WMI_GETTIME, *PPERFINFO_WMI_GETTIME; + +typedef struct PERFINFO_DSHOW_AVREND { + ULONGLONG cycleCounter; + ULONGLONG dshowClock; + ULONGLONG sampleTime; +} PERFINFO_DSHOW_AVREND, *PPERFINFO_DSHOW_AVREND; + +typedef struct PERFINFO_WMI_AVREND { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AVREND data; +} PERFINFO_WMI_AVREND, *PPERFINFO_WMI_AVREND; + +typedef struct PERFINFO_DSHOW_AUDIOBREAK { + ULONGLONG cycleCounter; + ULONGLONG dshowClock; + ULONGLONG sampleTime; + ULONGLONG sampleDuration; +} PERFINFO_DSHOW_AUDIOBREAK, *PPERFINFO_DSHOW_AUDIOBREAK; + +typedef struct PERFINFO_WMI_AUDIOBREAK { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIOBREAK data; +} PERFINFO_WMI_AUDIOBREAK, *PPERFINFO_WMI_AUDIOBREAK; + +typedef struct PERFINFO_DSHOW_FRAMEDROP { + ULONGLONG cycleCounter; + ULONGLONG dshowClock; + ULONGLONG frameTime; +} PERFINFO_DSHOW_FRAMEDROP, *PPERFINFO_DSHOW_FRAMEDROP; + +typedef struct PERFINFO_WMI_FRAMEDROP { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_FRAMEDROP data; +} PERFINFO_WMI_FRAMEDROP, *PPERFINFO_WMI_FRAMEDROP; + +#define PERFINFO_STREAMTRACE_MPEG2DEMUX_PTS_TRANSLATION 1 +#define PERFINFO_STREAMTRACE_MPEG2DEMUX_SAMPLE_RECEIVED 2 +#define PERFINFO_STREAMTRACE_VMR_BEGIN_ADVISE 3 +#define PERFINFO_STREAMTRACE_VMR_END_ADVISE 4 +#define PERFINFO_STREAMTRACE_VMR_RECEIVE 5 +#define PERFINFO_STREAMTRACE_VMR_BEGIN_DEINTERLACE 6 +#define PERFINFO_STREAMTRACE_VMR_END_DEINTERLACE 7 +#define PERFINFO_STREAMTRACE_VMR_BEGIN_DECODE 8 +#define PERFINFO_STREAMTRACE_VMR_END_DECODE 9 +#define PERFINFO_STREAMTRACE_VMR_DROPPED_FRAME 10 +#define PERFINFO_STREAMTRACE_ENCDEC_DTFILTERINPUT 11 +#define PERFINFO_STREAMTRACE_ENCDEC_DTFILTEROUTPUT 12 +#define PERFINFO_STREAMTRACE_ENCDEC_ETFILTERINPUT 13 +#define PERFINFO_STREAMTRACE_ENCDEC_ETFILTEROUTPUT 14 +#define PERFINFO_STREAMTRACE_ENCDEC_XDSCODECINPUT 15 +#define PERFINFO_STREAMTRACE_SBE_DVRANALYSISINPUT_RECEIVE 16 +#define PERFINFO_STREAMTRACE_SBE_DVRANALYSISINPUT_DELIVER 17 +#define PERFINFO_STREAMTRACE_SBE_DVRINPUTPIN_RECEIVE 18 +#define PERFINFO_STREAMTRACE_SBE_DVROUTPUTPIN_RECEIVE 19 +#define PERFINFO_STREAMTRACE_VMR_RENDER_TIME 20 + +typedef struct _PERFINFO_DSHOW_STREAMTRACE { + ULONG id; + ULONG reserved; + ULONGLONG dshowClock; + ULONGLONG data[ 4 ]; +} PERFINFO_DSHOW_STREAMTRACE, *PPERFINFO_DSHOW_STREAMTRACE; + +typedef struct _PERFINFO_WMI_STREAMTRACE { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_STREAMTRACE data; +} PERFINFO_WMI_STREAMTRACE, *PPERFINFO_WMI_STREAMTRACE; + + +typedef struct PERFINFO_DSHOW_AUDIORECV { + LONGLONG streamTime ; + LONGLONG sampleStart ; + LONGLONG sampleStop ; + LONGLONG hwduration ; + BOOL discontinuity ; +} PERFINFO_DSHOW_AUDIORECV, *PPERFINFO_DSHOW_AUDIORECV; + +typedef struct PERFINFO_WMI_AUDIORECV { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIORECV data; +} PERFINFO_WMI_AUDIORECV, *PPERFINFO_WMI_AUDIORECV; + +typedef struct PERFINFO_DSHOW_AUDIOSLAVE { + LONGLONG masterClock ; + LONGLONG slaveClock ; + LONGLONG errorAccum ; + LONGLONG lastHighErrorSeen ; + LONGLONG lastLowErrorSeen ; +} PERFINFO_DSHOW_AUDIOSLAVE, *PPERFINFO_DSHOW_AUDIOSLAVE; + +typedef struct PERFINFO_WMI_AUDIOSLAVE { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIOSLAVE data; +} PERFINFO_WMI_AUDIOSLAVE, *PPERFINFO_WMI_AUDIOSLAVE; + +typedef struct PERFINFO_DSHOW_AUDIOADDBREAK { + DWORD iterNextWrite ; + DWORD offsetNextWrite ; + DWORD iterWrite ; + DWORD offsetWrite ; +} PERFINFO_DSHOW_AUDIOADDBREAK, *PPERFINFO_DSHOW_AUDIOADDBREAK; + +typedef struct PERFINFO_WMI_AUDIOADDBREAK { + EVENT_TRACE_HEADER header; + PERFINFO_DSHOW_AUDIOADDBREAK data; +} PERFINFO_WMI_AUDIOADDBREAK, *PPERFINFO_WMI_AUDIOADDBREAK; + +#endif // _PREFSTRUCT_H_ diff --git a/src/thirdparty/BaseClasses/pstream.cpp b/src/thirdparty/BaseClasses/pstream.cpp index 6d47269521c..01ab0b00b27 100644 --- a/src/thirdparty/BaseClasses/pstream.cpp +++ b/src/thirdparty/BaseClasses/pstream.cpp @@ -1,197 +1,197 @@ -//------------------------------------------------------------------------------ -// File: PStream.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -#ifdef PERF -#include -#endif -// #include "pstream.h" in streams.h - -// -// Constructor -// -CPersistStream::CPersistStream(IUnknown *punk, __inout HRESULT *phr) - : mPS_fDirty(FALSE) -{ - mPS_dwFileVersion = GetSoftwareVersion(); -} - - -// -// Destructor -// -CPersistStream::~CPersistStream() { - // Nothing to do -} - -#if 0 -SAMPLE CODE TO COPY - not active at the moment - -// -// NonDelegatingQueryInterface -// -// This object supports IPersist & IPersistStream -STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - if (riid == IID_IPersist) { - return GetInterface((IPersist *) this, ppv); // ??? - } - else if (riid == IID_IPersistStream) { - return GetInterface((IPersistStream *) this, ppv); - } - else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } -} -#endif - - -// -// WriteToStream -// -// Writes to the stream (default action is to write nothing) -HRESULT CPersistStream::WriteToStream(IStream *pStream) -{ - // You can override this to do things like - // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL); - - return NOERROR; -} - - - -HRESULT CPersistStream::ReadFromStream(IStream * pStream) -{ - // You can override this to do things like - // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL); - - return NOERROR; -} - - -// -// Load -// -// Load all the data from the given stream -STDMETHODIMP CPersistStream::Load(LPSTREAM pStm) -{ - HRESULT hr; - // Load the version number then the data - mPS_dwFileVersion = ReadInt(pStm, hr); - if (FAILED(hr)) { - return hr; - } - - return ReadFromStream(pStm); -} // Load - - - -// -// Save -// -// Save the contents of this Stream. -STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty) -{ - - HRESULT hr = WriteInt(pStm, GetSoftwareVersion()); - if (FAILED(hr)) { - return hr; - } - - hr = WriteToStream(pStm); - if (FAILED(hr)) { - return hr; - } - - mPS_fDirty = !fClearDirty; - - return hr; -} // Save - - -// WriteInt -// -// Writes an integer to an IStream as 11 UNICODE characters followed by one space. -// You could use this for shorts or unsigneds or anything (up to 32 bits) -// where the value isn't actually truncated by squeezing it into 32 bits. -// Values such as (unsigned) 0x80000000 would come out as -2147483648 -// but would then load as 0x80000000 through ReadInt. Cast as you please. - -STDAPI WriteInt(IStream *pIStream, int n) -{ - WCHAR Buff[13]; // Allows for trailing null that we don't write - (void)StringCchPrintfW(Buff, NUMELMS(Buff),L"%011d ",n); - return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL); -} // WriteInt - - -// ReadInt -// -// Reads an integer from an IStream. -// Read as 4 bytes. You could use this for shorts or unsigneds or anything -// where the value isn't actually truncated by squeezing it into 32 bits -// Striped down subset of what sscanf can do (without dragging in the C runtime) - -STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr) -{ - - int Sign = 1; - unsigned int n = 0; // result wil be n*Sign - WCHAR wch; - - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - - if (wch==L'-'){ - Sign = -1; - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - } - - for( ; ; ) { - if (wch>=L'0' && wch<=L'9') { - n = 10*n+(int)(wch-L'0'); - } else if ( wch == L' ' - || wch == L'\t' - || wch == L'\r' - || wch == L'\n' - || wch == L'\0' - ) { - break; - } else { - hr = VFW_E_INVALID_FILE_FORMAT; - return 0; - } - - hr = pIStream->Read( &wch, sizeof(wch), NULL); - if (FAILED(hr)) { - return 0; - } - } - - if (n==0x80000000 && Sign==-1) { - // This is the negative number that has no positive version! - return (int)n; - } - else return (int)n * Sign; -} // ReadInt - - -// The microsoft C/C++ compile generates level 4 warnings to the effect that -// a particular inline function (from some base class) was not needed. -// This line gets rid of hundreds of such unwanted messages and makes -// -W4 compilation feasible: -#pragma warning(disable: 4514) +//------------------------------------------------------------------------------ +// File: PStream.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +#ifdef PERF +#include +#endif +// #include "pstream.h" in streams.h + +// +// Constructor +// +CPersistStream::CPersistStream(IUnknown *punk, __inout HRESULT *phr) + : mPS_fDirty(FALSE) +{ + mPS_dwFileVersion = GetSoftwareVersion(); +} + + +// +// Destructor +// +CPersistStream::~CPersistStream() { + // Nothing to do +} + +#if 0 +SAMPLE CODE TO COPY - not active at the moment + +// +// NonDelegatingQueryInterface +// +// This object supports IPersist & IPersistStream +STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + if (riid == IID_IPersist) { + return GetInterface((IPersist *) this, ppv); // ??? + } + else if (riid == IID_IPersistStream) { + return GetInterface((IPersistStream *) this, ppv); + } + else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } +} +#endif + + +// +// WriteToStream +// +// Writes to the stream (default action is to write nothing) +HRESULT CPersistStream::WriteToStream(IStream *pStream) +{ + // You can override this to do things like + // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL); + + return NOERROR; +} + + + +HRESULT CPersistStream::ReadFromStream(IStream * pStream) +{ + // You can override this to do things like + // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL); + + return NOERROR; +} + + +// +// Load +// +// Load all the data from the given stream +STDMETHODIMP CPersistStream::Load(LPSTREAM pStm) +{ + HRESULT hr; + // Load the version number then the data + mPS_dwFileVersion = ReadInt(pStm, hr); + if (FAILED(hr)) { + return hr; + } + + return ReadFromStream(pStm); +} // Load + + + +// +// Save +// +// Save the contents of this Stream. +STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty) +{ + + HRESULT hr = WriteInt(pStm, GetSoftwareVersion()); + if (FAILED(hr)) { + return hr; + } + + hr = WriteToStream(pStm); + if (FAILED(hr)) { + return hr; + } + + mPS_fDirty = !fClearDirty; + + return hr; +} // Save + + +// WriteInt +// +// Writes an integer to an IStream as 11 UNICODE characters followed by one space. +// You could use this for shorts or unsigneds or anything (up to 32 bits) +// where the value isn't actually truncated by squeezing it into 32 bits. +// Values such as (unsigned) 0x80000000 would come out as -2147483648 +// but would then load as 0x80000000 through ReadInt. Cast as you please. + +STDAPI WriteInt(IStream *pIStream, int n) +{ + WCHAR Buff[13]; // Allows for trailing null that we don't write + (void)StringCchPrintfW(Buff, NUMELMS(Buff),L"%011d ",n); + return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL); +} // WriteInt + + +// ReadInt +// +// Reads an integer from an IStream. +// Read as 4 bytes. You could use this for shorts or unsigneds or anything +// where the value isn't actually truncated by squeezing it into 32 bits +// Striped down subset of what sscanf can do (without dragging in the C runtime) + +STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr) +{ + + int Sign = 1; + unsigned int n = 0; // result wil be n*Sign + WCHAR wch; + + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + + if (wch==L'-'){ + Sign = -1; + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + } + + for( ; ; ) { + if (wch>=L'0' && wch<=L'9') { + n = 10*n+(int)(wch-L'0'); + } else if ( wch == L' ' + || wch == L'\t' + || wch == L'\r' + || wch == L'\n' + || wch == L'\0' + ) { + break; + } else { + hr = VFW_E_INVALID_FILE_FORMAT; + return 0; + } + + hr = pIStream->Read( &wch, sizeof(wch), NULL); + if (FAILED(hr)) { + return 0; + } + } + + if (n==0x80000000 && Sign==-1) { + // This is the negative number that has no positive version! + return (int)n; + } + else return (int)n * Sign; +} // ReadInt + + +// The microsoft C/C++ compile generates level 4 warnings to the effect that +// a particular inline function (from some base class) was not needed. +// This line gets rid of hundreds of such unwanted messages and makes +// -W4 compilation feasible: +#pragma warning(disable: 4514) diff --git a/src/thirdparty/BaseClasses/pstream.h b/src/thirdparty/BaseClasses/pstream.h index 2e278abf0c3..04b6af62434 100644 --- a/src/thirdparty/BaseClasses/pstream.h +++ b/src/thirdparty/BaseClasses/pstream.h @@ -1,114 +1,114 @@ -//------------------------------------------------------------------------------ -// File: PStream.h -// -// Desc: DirectShow base classes - defines a class for persistent properties -// of filters. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __PSTREAM__ -#define __PSTREAM__ - -// Base class for persistent properties of filters -// (i.e. filter properties in saved graphs) - -// The simplest way to use this is: -// 1. Arrange for your filter to inherit this class -// 2. Implement in your class WriteToStream and ReadFromStream -// These will override the "do nothing" functions here. -// 3. Change your NonDelegatingQueryInterface to handle IPersistStream -// 4. Implement SizeMax to return the number of bytes of data you save. -// If you save UNICODE data, don't forget a char is 2 bytes. -// 5. Whenever your data changes, call SetDirty() -// -// At some point you may decide to alter, or extend the format of your data. -// At that point you will wish that you had a version number in all the old -// saved graphs, so that you can tell, when you read them, whether they -// represent the old or new form. To assist you in this, this class -// writes and reads a version number. -// When it writes, it calls GetSoftwareVersion() to enquire what version -// of the software we have at the moment. (In effect this is a version number -// of the data layout in the file). It writes this as the first thing in the data. -// If you want to change the version, implement (override) GetSoftwareVersion(). -// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream, -// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading -// an old version file. -// Normally you should accept files whose version is no newer than the software -// version that's reading them. - - -// CPersistStream -// -// Implements IPersistStream. -// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for -// more implementation information. -class CPersistStream : public IPersistStream { - private: - - // Internal state: - - protected: - DWORD mPS_dwFileVersion; // version number of file (being read) - BOOL mPS_fDirty; - - public: - - // IPersistStream methods - - STDMETHODIMP IsDirty() - {return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean - STDMETHODIMP Load(LPSTREAM pStm); - STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty); - STDMETHODIMP GetSizeMax(__out ULARGE_INTEGER * pcbSize) - // Allow 24 bytes for version. - { pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; } - - // implementation - - CPersistStream(IUnknown *punk, __inout HRESULT *phr); - ~CPersistStream(); - - HRESULT SetDirty(BOOL fDirty) - { mPS_fDirty = fDirty; return NOERROR;} - - - // override to reveal IPersist & IPersistStream - // STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); - - // --- IPersist --- - - // You must override this to provide your own class id - STDMETHODIMP GetClassID(__out CLSID *pClsid) PURE; - - // overrideable if you want - // file version number. Override it if you ever change format - virtual DWORD GetSoftwareVersion(void) { return 0; } - - - //========================================================================= - // OVERRIDE THESE to read and write your data - // OVERRIDE THESE to read and write your data - // OVERRIDE THESE to read and write your data - - virtual int SizeMax() {return 0;} - virtual HRESULT WriteToStream(IStream *pStream); - virtual HRESULT ReadFromStream(IStream *pStream); - //========================================================================= - - private: - -}; - - -// --- Useful helpers --- - - -// Writes an int to an IStream as UNICODE. -STDAPI WriteInt(IStream *pIStream, int n); - -// inverse of WriteInt -STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr); - -#endif // __PSTREAM__ +//------------------------------------------------------------------------------ +// File: PStream.h +// +// Desc: DirectShow base classes - defines a class for persistent properties +// of filters. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __PSTREAM__ +#define __PSTREAM__ + +// Base class for persistent properties of filters +// (i.e. filter properties in saved graphs) + +// The simplest way to use this is: +// 1. Arrange for your filter to inherit this class +// 2. Implement in your class WriteToStream and ReadFromStream +// These will override the "do nothing" functions here. +// 3. Change your NonDelegatingQueryInterface to handle IPersistStream +// 4. Implement SizeMax to return the number of bytes of data you save. +// If you save UNICODE data, don't forget a char is 2 bytes. +// 5. Whenever your data changes, call SetDirty() +// +// At some point you may decide to alter, or extend the format of your data. +// At that point you will wish that you had a version number in all the old +// saved graphs, so that you can tell, when you read them, whether they +// represent the old or new form. To assist you in this, this class +// writes and reads a version number. +// When it writes, it calls GetSoftwareVersion() to enquire what version +// of the software we have at the moment. (In effect this is a version number +// of the data layout in the file). It writes this as the first thing in the data. +// If you want to change the version, implement (override) GetSoftwareVersion(). +// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream, +// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading +// an old version file. +// Normally you should accept files whose version is no newer than the software +// version that's reading them. + + +// CPersistStream +// +// Implements IPersistStream. +// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for +// more implementation information. +class CPersistStream : public IPersistStream { + private: + + // Internal state: + + protected: + DWORD mPS_dwFileVersion; // version number of file (being read) + BOOL mPS_fDirty; + + public: + + // IPersistStream methods + + STDMETHODIMP IsDirty() + {return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean + STDMETHODIMP Load(LPSTREAM pStm); + STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty); + STDMETHODIMP GetSizeMax(__out ULARGE_INTEGER * pcbSize) + // Allow 24 bytes for version. + { pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; } + + // implementation + + CPersistStream(IUnknown *punk, __inout HRESULT *phr); + ~CPersistStream(); + + HRESULT SetDirty(BOOL fDirty) + { mPS_fDirty = fDirty; return NOERROR;} + + + // override to reveal IPersist & IPersistStream + // STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv); + + // --- IPersist --- + + // You must override this to provide your own class id + STDMETHODIMP GetClassID(__out CLSID *pClsid) PURE; + + // overrideable if you want + // file version number. Override it if you ever change format + virtual DWORD GetSoftwareVersion(void) { return 0; } + + + //========================================================================= + // OVERRIDE THESE to read and write your data + // OVERRIDE THESE to read and write your data + // OVERRIDE THESE to read and write your data + + virtual int SizeMax() {return 0;} + virtual HRESULT WriteToStream(IStream *pStream); + virtual HRESULT ReadFromStream(IStream *pStream); + //========================================================================= + + private: + +}; + + +// --- Useful helpers --- + + +// Writes an int to an IStream as UNICODE. +STDAPI WriteInt(IStream *pIStream, int n); + +// inverse of WriteInt +STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr); + +#endif // __PSTREAM__ diff --git a/src/thirdparty/BaseClasses/pullpin.cpp b/src/thirdparty/BaseClasses/pullpin.cpp index 9bcbf6a50f8..c979270c97b 100644 --- a/src/thirdparty/BaseClasses/pullpin.cpp +++ b/src/thirdparty/BaseClasses/pullpin.cpp @@ -1,593 +1,593 @@ -//------------------------------------------------------------------------------ -// File: PullPin.cpp -// -// Desc: DirectShow base classes - implements CPullPin class that pulls data -// from IAsyncReader. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "pullpin.h" - -#ifdef DXMPERF -#include "dxmperf.h" -#endif // DXMPERF - - -CPullPin::CPullPin() - : m_pReader(NULL), - m_pAlloc(NULL), - m_State(TM_Exit), - m_tStart(0), - m_tStop(0), - m_tDuration(0), - m_bSync(FALSE) -{ -#ifdef DXMPERF - PERFLOG_CTOR( L"CPullPin", this ); -#endif // DXMPERF - -} - -CPullPin::~CPullPin() -{ - Disconnect(); - -#ifdef DXMPERF - PERFLOG_DTOR( L"CPullPin", this ); -#endif // DXMPERF - -} - -// returns S_OK if successfully connected to an IAsyncReader interface -// from this object -// Optional allocator should be proposed as a preferred allocator if -// necessary -HRESULT -CPullPin::Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync) -{ - CAutoLock lock(&m_AccessLock); - - if (m_pReader) { - return VFW_E_ALREADY_CONNECTED; - } - - HRESULT hr = pUnk->QueryInterface(IID_IAsyncReader, (void**)&m_pReader); - if (FAILED(hr)) { - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - PERFLOG_CONNECT( this, pUnk, hr, pmt ); - } -#endif // DXMPERF - - return(hr); - } - - hr = DecideAllocator(pAlloc, NULL); - if (FAILED(hr)) { - Disconnect(); - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - PERFLOG_CONNECT( this, pUnk, hr, pmt ); - } -#endif // DXMPERF - - return hr; - } - - LONGLONG llTotal, llAvail; - hr = m_pReader->Length(&llTotal, &llAvail); - if (FAILED(hr)) { - Disconnect(); - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - PERFLOG_CONNECT( this, pUnk, hr, pmt ); - } -#endif - - return hr; - } - - // convert from file position to reference time - m_tDuration = llTotal * UNITS; - m_tStop = m_tDuration; - m_tStart = 0; - - m_bSync = bSync; - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - PERFLOG_CONNECT( this, pUnk, S_OK, pmt ); - } -#endif // DXMPERF - - - return S_OK; -} - -// disconnect any connection made in Connect -HRESULT -CPullPin::Disconnect() -{ - CAutoLock lock(&m_AccessLock); - - StopThread(); - - -#ifdef DXMPERF - PERFLOG_DISCONNECT( this, m_pReader, S_OK ); -#endif // DXMPERF - - - if (m_pReader) { - m_pReader->Release(); - m_pReader = NULL; - } - - if (m_pAlloc) { - m_pAlloc->Release(); - m_pAlloc = NULL; - } - - return S_OK; -} - -// agree an allocator using RequestAllocator - optional -// props param specifies your requirements (non-zero fields). -// returns an error code if fail to match requirements. -// optional IMemAllocator interface is offered as a preferred allocator -// but no error occurs if it can't be met. -HRESULT -CPullPin::DecideAllocator( - IMemAllocator * pAlloc, - __inout_opt ALLOCATOR_PROPERTIES * pProps) -{ - ALLOCATOR_PROPERTIES *pRequest; - ALLOCATOR_PROPERTIES Request; - if (pProps == NULL) { - Request.cBuffers = 3; - Request.cbBuffer = 64*1024; - Request.cbAlign = 0; - Request.cbPrefix = 0; - pRequest = &Request; - } else { - pRequest = pProps; - } - HRESULT hr = m_pReader->RequestAllocator( - pAlloc, - pRequest, - &m_pAlloc); - return hr; -} - -// start pulling data -HRESULT -CPullPin::Active(void) -{ - ASSERT(!ThreadExists()); - return StartThread(); -} - -// stop pulling data -HRESULT -CPullPin::Inactive(void) -{ - StopThread(); - - return S_OK; -} - -HRESULT -CPullPin::Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop) -{ - CAutoLock lock(&m_AccessLock); - - ThreadMsg AtStart = m_State; - - if (AtStart == TM_Start) { - BeginFlush(); - PauseThread(); - EndFlush(); - } - - m_tStart = tStart; - m_tStop = tStop; - - HRESULT hr = S_OK; - if (AtStart == TM_Start) { - hr = StartThread(); - } - - return hr; -} - -HRESULT -CPullPin::Duration(__out REFERENCE_TIME* ptDuration) -{ - *ptDuration = m_tDuration; - return S_OK; -} - - -HRESULT -CPullPin::StartThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!m_pAlloc || !m_pReader) { - return E_UNEXPECTED; - } - - HRESULT hr; - if (!ThreadExists()) { - - // commit allocator - hr = m_pAlloc->Commit(); - if (FAILED(hr)) { - return hr; - } - - // start thread - if (!Create()) { - return E_FAIL; - } - } - - m_State = TM_Start; - hr = (HRESULT) CallWorker(m_State); - return hr; -} - -HRESULT -CPullPin::PauseThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return E_UNEXPECTED; - } - - // need to flush to ensure the thread is not blocked - // in WaitForNext - HRESULT hr = m_pReader->BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - m_State = TM_Pause; - hr = CallWorker(TM_Pause); - - m_pReader->EndFlush(); - return hr; -} - -HRESULT -CPullPin::StopThread() -{ - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return S_FALSE; - } - - // need to flush to ensure the thread is not blocked - // in WaitForNext - HRESULT hr = m_pReader->BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - m_State = TM_Exit; - hr = CallWorker(TM_Exit); - - m_pReader->EndFlush(); - - // wait for thread to completely exit - Close(); - - // decommit allocator - if (m_pAlloc) { - m_pAlloc->Decommit(); - } - - return S_OK; -} - - -DWORD -CPullPin::ThreadProc(void) -{ - for (;;) { - DWORD cmd = GetRequest(); - switch(cmd) { - case TM_Exit: - Reply(S_OK); - return 0; - - case TM_Pause: - // we are paused already - Reply(S_OK); - break; - - case TM_Start: - Reply(S_OK); - Process(); - break; - } - - // at this point, there should be no outstanding requests on the - // upstream filter. - // We should force begin/endflush to ensure that this is true. - // !!!Note that we may currently be inside a BeginFlush/EndFlush pair - // on another thread, but the premature EndFlush will do no harm now - // that we are idle. - m_pReader->BeginFlush(); - CleanupCancelled(); - m_pReader->EndFlush(); - } -} - -HRESULT -CPullPin::QueueSample( - __inout REFERENCE_TIME& tCurrent, - REFERENCE_TIME tAlignStop, - BOOL bDiscontinuity - ) -{ - IMediaSample* pSample; - - HRESULT hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); - if (FAILED(hr)) { - return hr; - } - - LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); - if (tStopThis > tAlignStop) { - tStopThis = tAlignStop; - } - pSample->SetTime(&tCurrent, &tStopThis); - tCurrent = tStopThis; - - pSample->SetDiscontinuity(bDiscontinuity); - - hr = m_pReader->Request( - pSample, - 0); - if (FAILED(hr)) { - pSample->Release(); - - CleanupCancelled(); - OnError(hr); - } - return hr; -} - -HRESULT -CPullPin::CollectAndDeliver( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop) -{ - IMediaSample* pSample = NULL; // better be sure pSample is set - DWORD_PTR dwUnused; - HRESULT hr = m_pReader->WaitForNext( - INFINITE, - &pSample, - &dwUnused); - if (FAILED(hr)) { - if (pSample) { - pSample->Release(); - } - } else { - hr = DeliverSample(pSample, tStart, tStop); - } - if (FAILED(hr)) { - CleanupCancelled(); - OnError(hr); - } - return hr; - -} - -HRESULT -CPullPin::DeliverSample( - IMediaSample* pSample, - REFERENCE_TIME tStart, - REFERENCE_TIME tStop - ) -{ - // fix up sample if past actual stop (for sector alignment) - REFERENCE_TIME t1, t2; - if (S_OK == pSample->GetTime(&t1, &t2)) { - if (t2 > tStop) { - t2 = tStop; - } - - // adjust times to be relative to (aligned) start time - t1 -= tStart; - t2 -= tStart; - HRESULT hr = pSample->SetTime(&t1, &t2); - if (FAILED(hr)) { - return hr; - } - } - -#ifdef DXMPERF - { - AM_MEDIA_TYPE * pmt = NULL; - pSample->GetMediaType( &pmt ); - PERFLOG_RECEIVE( L"CPullPin", m_pReader, this, pSample, pmt ); - } -#endif - - HRESULT hr = Receive(pSample); - pSample->Release(); - return hr; -} - -void -CPullPin::Process(void) -{ - // is there anything to do? - if (m_tStop <= m_tStart) { - EndOfStream(); - return; - } - - BOOL bDiscontinuity = TRUE; - - // if there is more than one sample at the allocator, - // then try to queue 2 at once in order to overlap. - // -- get buffer count and required alignment - ALLOCATOR_PROPERTIES Actual; - HRESULT hr = m_pAlloc->GetProperties(&Actual); - - // align the start position downwards - REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS; - REFERENCE_TIME tCurrent = tStart; - - REFERENCE_TIME tStop = m_tStop; - if (tStop > m_tDuration) { - tStop = m_tDuration; - } - - // align the stop position - may be past stop, but that - // doesn't matter - REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS; - - - DWORD dwRequest; - - if (!m_bSync) { - - // Break out of the loop either if we get to the end or we're asked - // to do something else - while (tCurrent < tAlignStop) { - - // Break out without calling EndOfStream if we're asked to - // do something different - if (CheckRequest(&dwRequest)) { - return; - } - - // queue a first sample - if (Actual.cBuffers > 1) { - - hr = QueueSample(tCurrent, tAlignStop, TRUE); - bDiscontinuity = FALSE; - - if (FAILED(hr)) { - return; - } - } - - - - // loop queueing second and waiting for first.. - while (tCurrent < tAlignStop) { - - hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity); - bDiscontinuity = FALSE; - - if (FAILED(hr)) { - return; - } - - hr = CollectAndDeliver(tStart, tStop); - if (S_OK != hr) { - - // stop if error, or if downstream filter said - // to stop. - return; - } - } - - if (Actual.cBuffers > 1) { - hr = CollectAndDeliver(tStart, tStop); - if (FAILED(hr)) { - return; - } - } - } - } else { - - // sync version of above loop - while (tCurrent < tAlignStop) { - - // Break out without calling EndOfStream if we're asked to - // do something different - if (CheckRequest(&dwRequest)) { - return; - } - - IMediaSample* pSample; - - hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); - if (FAILED(hr)) { - OnError(hr); - return; - } - - LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); - if (tStopThis > tAlignStop) { - tStopThis = tAlignStop; - } - pSample->SetTime(&tCurrent, &tStopThis); - tCurrent = tStopThis; - - if (bDiscontinuity) { - pSample->SetDiscontinuity(TRUE); - bDiscontinuity = FALSE; - } - - hr = m_pReader->SyncReadAligned(pSample); - - if (FAILED(hr)) { - pSample->Release(); - OnError(hr); - return; - } - - hr = DeliverSample(pSample, tStart, tStop); - if (hr != S_OK) { - if (FAILED(hr)) { - OnError(hr); - } - return; - } - } - } - - EndOfStream(); -} - -// after a flush, cancelled i/o will be waiting for collection -// and release -void -CPullPin::CleanupCancelled(void) -{ - for (;;) { - IMediaSample * pSample; - DWORD_PTR dwUnused; - - HRESULT hr = m_pReader->WaitForNext( - 0, // no wait - &pSample, - &dwUnused); - UNREFERENCED_PARAMETER(hr); - if(pSample) { - pSample->Release(); - } else { - // no more samples - return; - } - } -} +//------------------------------------------------------------------------------ +// File: PullPin.cpp +// +// Desc: DirectShow base classes - implements CPullPin class that pulls data +// from IAsyncReader. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "pullpin.h" + +#ifdef DXMPERF +#include "dxmperf.h" +#endif // DXMPERF + + +CPullPin::CPullPin() + : m_pReader(NULL), + m_pAlloc(NULL), + m_State(TM_Exit), + m_tStart(0), + m_tStop(0), + m_tDuration(0), + m_bSync(FALSE) +{ +#ifdef DXMPERF + PERFLOG_CTOR( L"CPullPin", this ); +#endif // DXMPERF + +} + +CPullPin::~CPullPin() +{ + Disconnect(); + +#ifdef DXMPERF + PERFLOG_DTOR( L"CPullPin", this ); +#endif // DXMPERF + +} + +// returns S_OK if successfully connected to an IAsyncReader interface +// from this object +// Optional allocator should be proposed as a preferred allocator if +// necessary +HRESULT +CPullPin::Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync) +{ + CAutoLock lock(&m_AccessLock); + + if (m_pReader) { + return VFW_E_ALREADY_CONNECTED; + } + + HRESULT hr = pUnk->QueryInterface(IID_IAsyncReader, (void**)&m_pReader); + if (FAILED(hr)) { + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + PERFLOG_CONNECT( this, pUnk, hr, pmt ); + } +#endif // DXMPERF + + return(hr); + } + + hr = DecideAllocator(pAlloc, NULL); + if (FAILED(hr)) { + Disconnect(); + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + PERFLOG_CONNECT( this, pUnk, hr, pmt ); + } +#endif // DXMPERF + + return hr; + } + + LONGLONG llTotal, llAvail; + hr = m_pReader->Length(&llTotal, &llAvail); + if (FAILED(hr)) { + Disconnect(); + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + PERFLOG_CONNECT( this, pUnk, hr, pmt ); + } +#endif + + return hr; + } + + // convert from file position to reference time + m_tDuration = llTotal * UNITS; + m_tStop = m_tDuration; + m_tStart = 0; + + m_bSync = bSync; + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + PERFLOG_CONNECT( this, pUnk, S_OK, pmt ); + } +#endif // DXMPERF + + + return S_OK; +} + +// disconnect any connection made in Connect +HRESULT +CPullPin::Disconnect() +{ + CAutoLock lock(&m_AccessLock); + + StopThread(); + + +#ifdef DXMPERF + PERFLOG_DISCONNECT( this, m_pReader, S_OK ); +#endif // DXMPERF + + + if (m_pReader) { + m_pReader->Release(); + m_pReader = NULL; + } + + if (m_pAlloc) { + m_pAlloc->Release(); + m_pAlloc = NULL; + } + + return S_OK; +} + +// agree an allocator using RequestAllocator - optional +// props param specifies your requirements (non-zero fields). +// returns an error code if fail to match requirements. +// optional IMemAllocator interface is offered as a preferred allocator +// but no error occurs if it can't be met. +HRESULT +CPullPin::DecideAllocator( + IMemAllocator * pAlloc, + __inout_opt ALLOCATOR_PROPERTIES * pProps) +{ + ALLOCATOR_PROPERTIES *pRequest; + ALLOCATOR_PROPERTIES Request; + if (pProps == NULL) { + Request.cBuffers = 3; + Request.cbBuffer = 64*1024; + Request.cbAlign = 0; + Request.cbPrefix = 0; + pRequest = &Request; + } else { + pRequest = pProps; + } + HRESULT hr = m_pReader->RequestAllocator( + pAlloc, + pRequest, + &m_pAlloc); + return hr; +} + +// start pulling data +HRESULT +CPullPin::Active(void) +{ + ASSERT(!ThreadExists()); + return StartThread(); +} + +// stop pulling data +HRESULT +CPullPin::Inactive(void) +{ + StopThread(); + + return S_OK; +} + +HRESULT +CPullPin::Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop) +{ + CAutoLock lock(&m_AccessLock); + + ThreadMsg AtStart = m_State; + + if (AtStart == TM_Start) { + BeginFlush(); + PauseThread(); + EndFlush(); + } + + m_tStart = tStart; + m_tStop = tStop; + + HRESULT hr = S_OK; + if (AtStart == TM_Start) { + hr = StartThread(); + } + + return hr; +} + +HRESULT +CPullPin::Duration(__out REFERENCE_TIME* ptDuration) +{ + *ptDuration = m_tDuration; + return S_OK; +} + + +HRESULT +CPullPin::StartThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!m_pAlloc || !m_pReader) { + return E_UNEXPECTED; + } + + HRESULT hr; + if (!ThreadExists()) { + + // commit allocator + hr = m_pAlloc->Commit(); + if (FAILED(hr)) { + return hr; + } + + // start thread + if (!Create()) { + return E_FAIL; + } + } + + m_State = TM_Start; + hr = (HRESULT) CallWorker(m_State); + return hr; +} + +HRESULT +CPullPin::PauseThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return E_UNEXPECTED; + } + + // need to flush to ensure the thread is not blocked + // in WaitForNext + HRESULT hr = m_pReader->BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + m_State = TM_Pause; + hr = CallWorker(TM_Pause); + + m_pReader->EndFlush(); + return hr; +} + +HRESULT +CPullPin::StopThread() +{ + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return S_FALSE; + } + + // need to flush to ensure the thread is not blocked + // in WaitForNext + HRESULT hr = m_pReader->BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + m_State = TM_Exit; + hr = CallWorker(TM_Exit); + + m_pReader->EndFlush(); + + // wait for thread to completely exit + Close(); + + // decommit allocator + if (m_pAlloc) { + m_pAlloc->Decommit(); + } + + return S_OK; +} + + +DWORD +CPullPin::ThreadProc(void) +{ + for (;;) { + DWORD cmd = GetRequest(); + switch(cmd) { + case TM_Exit: + Reply(S_OK); + return 0; + + case TM_Pause: + // we are paused already + Reply(S_OK); + break; + + case TM_Start: + Reply(S_OK); + Process(); + break; + } + + // at this point, there should be no outstanding requests on the + // upstream filter. + // We should force begin/endflush to ensure that this is true. + // !!!Note that we may currently be inside a BeginFlush/EndFlush pair + // on another thread, but the premature EndFlush will do no harm now + // that we are idle. + m_pReader->BeginFlush(); + CleanupCancelled(); + m_pReader->EndFlush(); + } +} + +HRESULT +CPullPin::QueueSample( + __inout REFERENCE_TIME& tCurrent, + REFERENCE_TIME tAlignStop, + BOOL bDiscontinuity + ) +{ + IMediaSample* pSample; + + HRESULT hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); + if (FAILED(hr)) { + return hr; + } + + LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); + if (tStopThis > tAlignStop) { + tStopThis = tAlignStop; + } + pSample->SetTime(&tCurrent, &tStopThis); + tCurrent = tStopThis; + + pSample->SetDiscontinuity(bDiscontinuity); + + hr = m_pReader->Request( + pSample, + 0); + if (FAILED(hr)) { + pSample->Release(); + + CleanupCancelled(); + OnError(hr); + } + return hr; +} + +HRESULT +CPullPin::CollectAndDeliver( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop) +{ + IMediaSample* pSample = NULL; // better be sure pSample is set + DWORD_PTR dwUnused; + HRESULT hr = m_pReader->WaitForNext( + INFINITE, + &pSample, + &dwUnused); + if (FAILED(hr)) { + if (pSample) { + pSample->Release(); + } + } else { + hr = DeliverSample(pSample, tStart, tStop); + } + if (FAILED(hr)) { + CleanupCancelled(); + OnError(hr); + } + return hr; + +} + +HRESULT +CPullPin::DeliverSample( + IMediaSample* pSample, + REFERENCE_TIME tStart, + REFERENCE_TIME tStop + ) +{ + // fix up sample if past actual stop (for sector alignment) + REFERENCE_TIME t1, t2; + if (S_OK == pSample->GetTime(&t1, &t2)) { + if (t2 > tStop) { + t2 = tStop; + } + + // adjust times to be relative to (aligned) start time + t1 -= tStart; + t2 -= tStart; + HRESULT hr = pSample->SetTime(&t1, &t2); + if (FAILED(hr)) { + return hr; + } + } + +#ifdef DXMPERF + { + AM_MEDIA_TYPE * pmt = NULL; + pSample->GetMediaType( &pmt ); + PERFLOG_RECEIVE( L"CPullPin", m_pReader, this, pSample, pmt ); + } +#endif + + HRESULT hr = Receive(pSample); + pSample->Release(); + return hr; +} + +void +CPullPin::Process(void) +{ + // is there anything to do? + if (m_tStop <= m_tStart) { + EndOfStream(); + return; + } + + BOOL bDiscontinuity = TRUE; + + // if there is more than one sample at the allocator, + // then try to queue 2 at once in order to overlap. + // -- get buffer count and required alignment + ALLOCATOR_PROPERTIES Actual; + HRESULT hr = m_pAlloc->GetProperties(&Actual); + + // align the start position downwards + REFERENCE_TIME tStart = AlignDown(m_tStart / UNITS, Actual.cbAlign) * UNITS; + REFERENCE_TIME tCurrent = tStart; + + REFERENCE_TIME tStop = m_tStop; + if (tStop > m_tDuration) { + tStop = m_tDuration; + } + + // align the stop position - may be past stop, but that + // doesn't matter + REFERENCE_TIME tAlignStop = AlignUp(tStop / UNITS, Actual.cbAlign) * UNITS; + + + DWORD dwRequest; + + if (!m_bSync) { + + // Break out of the loop either if we get to the end or we're asked + // to do something else + while (tCurrent < tAlignStop) { + + // Break out without calling EndOfStream if we're asked to + // do something different + if (CheckRequest(&dwRequest)) { + return; + } + + // queue a first sample + if (Actual.cBuffers > 1) { + + hr = QueueSample(tCurrent, tAlignStop, TRUE); + bDiscontinuity = FALSE; + + if (FAILED(hr)) { + return; + } + } + + + + // loop queueing second and waiting for first.. + while (tCurrent < tAlignStop) { + + hr = QueueSample(tCurrent, tAlignStop, bDiscontinuity); + bDiscontinuity = FALSE; + + if (FAILED(hr)) { + return; + } + + hr = CollectAndDeliver(tStart, tStop); + if (S_OK != hr) { + + // stop if error, or if downstream filter said + // to stop. + return; + } + } + + if (Actual.cBuffers > 1) { + hr = CollectAndDeliver(tStart, tStop); + if (FAILED(hr)) { + return; + } + } + } + } else { + + // sync version of above loop + while (tCurrent < tAlignStop) { + + // Break out without calling EndOfStream if we're asked to + // do something different + if (CheckRequest(&dwRequest)) { + return; + } + + IMediaSample* pSample; + + hr = m_pAlloc->GetBuffer(&pSample, NULL, NULL, 0); + if (FAILED(hr)) { + OnError(hr); + return; + } + + LONGLONG tStopThis = tCurrent + (pSample->GetSize() * UNITS); + if (tStopThis > tAlignStop) { + tStopThis = tAlignStop; + } + pSample->SetTime(&tCurrent, &tStopThis); + tCurrent = tStopThis; + + if (bDiscontinuity) { + pSample->SetDiscontinuity(TRUE); + bDiscontinuity = FALSE; + } + + hr = m_pReader->SyncReadAligned(pSample); + + if (FAILED(hr)) { + pSample->Release(); + OnError(hr); + return; + } + + hr = DeliverSample(pSample, tStart, tStop); + if (hr != S_OK) { + if (FAILED(hr)) { + OnError(hr); + } + return; + } + } + } + + EndOfStream(); +} + +// after a flush, cancelled i/o will be waiting for collection +// and release +void +CPullPin::CleanupCancelled(void) +{ + for (;;) { + IMediaSample * pSample; + DWORD_PTR dwUnused; + + HRESULT hr = m_pReader->WaitForNext( + 0, // no wait + &pSample, + &dwUnused); + UNREFERENCED_PARAMETER(hr); + if(pSample) { + pSample->Release(); + } else { + // no more samples + return; + } + } +} diff --git a/src/thirdparty/BaseClasses/pullpin.h b/src/thirdparty/BaseClasses/pullpin.h index db4f4071e2e..03ad40ec9af 100644 --- a/src/thirdparty/BaseClasses/pullpin.h +++ b/src/thirdparty/BaseClasses/pullpin.h @@ -1,152 +1,152 @@ -//------------------------------------------------------------------------------ -// File: PullPin.h -// -// Desc: DirectShow base classes - defines CPullPin class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __PULLPIN_H__ -#define __PULLPIN_H__ - -// -// CPullPin -// -// object supporting pulling data from an IAsyncReader interface. -// Given a start/stop position, calls a pure Receive method with each -// IMediaSample received. -// -// This is essentially for use in a MemInputPin when it finds itself -// connected to an IAsyncReader pin instead of a pushing pin. -// - -class CPullPin : public CAMThread -{ - IAsyncReader* m_pReader; - REFERENCE_TIME m_tStart; - REFERENCE_TIME m_tStop; - REFERENCE_TIME m_tDuration; - BOOL m_bSync; - - enum ThreadMsg { - TM_Pause, // stop pulling and wait for next message - TM_Start, // start pulling - TM_Exit, // stop and exit - }; - - ThreadMsg m_State; - - // override pure thread proc from CAMThread - DWORD ThreadProc(void); - - // running pull method (check m_bSync) - void Process(void); - - // clean up any cancelled i/o after a flush - void CleanupCancelled(void); - - // suspend thread from pulling, eg during seek - HRESULT PauseThread(); - - // start thread pulling - create thread if necy - HRESULT StartThread(); - - // stop and close thread - HRESULT StopThread(); - - // called from ProcessAsync to queue and collect requests - HRESULT QueueSample( - __inout REFERENCE_TIME& tCurrent, - REFERENCE_TIME tAlignStop, - BOOL bDiscontinuity); - - HRESULT CollectAndDeliver( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop); - - HRESULT DeliverSample( - IMediaSample* pSample, - REFERENCE_TIME tStart, - REFERENCE_TIME tStop); - -protected: - IMemAllocator * m_pAlloc; - -public: - CPullPin(); - virtual ~CPullPin(); - - // returns S_OK if successfully connected to an IAsyncReader interface - // from this object - // Optional allocator should be proposed as a preferred allocator if - // necessary - // bSync is TRUE if we are to use sync reads instead of the - // async methods. - HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync); - - // disconnect any connection made in Connect - HRESULT Disconnect(); - - // agree an allocator using RequestAllocator - optional - // props param specifies your requirements (non-zero fields). - // returns an error code if fail to match requirements. - // optional IMemAllocator interface is offered as a preferred allocator - // but no error occurs if it can't be met. - virtual HRESULT DecideAllocator( - IMemAllocator* pAlloc, - __inout_opt ALLOCATOR_PROPERTIES * pProps); - - // set start and stop position. if active, will start immediately at - // the new position. Default is 0 to duration - HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop); - - // return the total duration - HRESULT Duration(__out REFERENCE_TIME* ptDuration); - - // start pulling data - HRESULT Active(void); - - // stop pulling data - HRESULT Inactive(void); - - // helper functions - LONGLONG AlignDown(LONGLONG ll, LONG lAlign) { - // aligning downwards is just truncation - return ll & ~(lAlign-1); - }; - - LONGLONG AlignUp(LONGLONG ll, LONG lAlign) { - // align up: round up to next boundary - return (ll + (lAlign -1)) & ~(lAlign -1); - }; - - // GetReader returns the (addrefed) IAsyncReader interface - // for SyncRead etc - IAsyncReader* GetReader() { - m_pReader->AddRef(); - return m_pReader; - }; - - // -- pure -- - - // override this to handle data arrival - // return value other than S_OK will stop data - virtual HRESULT Receive(IMediaSample*) PURE; - - // override this to handle end-of-stream - virtual HRESULT EndOfStream(void) PURE; - - // called on runtime errors that will have caused pulling - // to stop - // these errors are all returned from the upstream filter, who - // will have already reported any errors to the filtergraph. - virtual void OnError(HRESULT hr) PURE; - - // flush this pin and all downstream - virtual HRESULT BeginFlush() PURE; - virtual HRESULT EndFlush() PURE; - -}; - -#endif //__PULLPIN_H__ +//------------------------------------------------------------------------------ +// File: PullPin.h +// +// Desc: DirectShow base classes - defines CPullPin class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __PULLPIN_H__ +#define __PULLPIN_H__ + +// +// CPullPin +// +// object supporting pulling data from an IAsyncReader interface. +// Given a start/stop position, calls a pure Receive method with each +// IMediaSample received. +// +// This is essentially for use in a MemInputPin when it finds itself +// connected to an IAsyncReader pin instead of a pushing pin. +// + +class CPullPin : public CAMThread +{ + IAsyncReader* m_pReader; + REFERENCE_TIME m_tStart; + REFERENCE_TIME m_tStop; + REFERENCE_TIME m_tDuration; + BOOL m_bSync; + + enum ThreadMsg { + TM_Pause, // stop pulling and wait for next message + TM_Start, // start pulling + TM_Exit, // stop and exit + }; + + ThreadMsg m_State; + + // override pure thread proc from CAMThread + DWORD ThreadProc(void); + + // running pull method (check m_bSync) + void Process(void); + + // clean up any cancelled i/o after a flush + void CleanupCancelled(void); + + // suspend thread from pulling, eg during seek + HRESULT PauseThread(); + + // start thread pulling - create thread if necy + HRESULT StartThread(); + + // stop and close thread + HRESULT StopThread(); + + // called from ProcessAsync to queue and collect requests + HRESULT QueueSample( + __inout REFERENCE_TIME& tCurrent, + REFERENCE_TIME tAlignStop, + BOOL bDiscontinuity); + + HRESULT CollectAndDeliver( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop); + + HRESULT DeliverSample( + IMediaSample* pSample, + REFERENCE_TIME tStart, + REFERENCE_TIME tStop); + +protected: + IMemAllocator * m_pAlloc; + +public: + CPullPin(); + virtual ~CPullPin(); + + // returns S_OK if successfully connected to an IAsyncReader interface + // from this object + // Optional allocator should be proposed as a preferred allocator if + // necessary + // bSync is TRUE if we are to use sync reads instead of the + // async methods. + HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync); + + // disconnect any connection made in Connect + HRESULT Disconnect(); + + // agree an allocator using RequestAllocator - optional + // props param specifies your requirements (non-zero fields). + // returns an error code if fail to match requirements. + // optional IMemAllocator interface is offered as a preferred allocator + // but no error occurs if it can't be met. + virtual HRESULT DecideAllocator( + IMemAllocator* pAlloc, + __inout_opt ALLOCATOR_PROPERTIES * pProps); + + // set start and stop position. if active, will start immediately at + // the new position. Default is 0 to duration + HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop); + + // return the total duration + HRESULT Duration(__out REFERENCE_TIME* ptDuration); + + // start pulling data + HRESULT Active(void); + + // stop pulling data + HRESULT Inactive(void); + + // helper functions + LONGLONG AlignDown(LONGLONG ll, LONG lAlign) { + // aligning downwards is just truncation + return ll & ~(lAlign-1); + }; + + LONGLONG AlignUp(LONGLONG ll, LONG lAlign) { + // align up: round up to next boundary + return (ll + (lAlign -1)) & ~(lAlign -1); + }; + + // GetReader returns the (addrefed) IAsyncReader interface + // for SyncRead etc + IAsyncReader* GetReader() { + m_pReader->AddRef(); + return m_pReader; + }; + + // -- pure -- + + // override this to handle data arrival + // return value other than S_OK will stop data + virtual HRESULT Receive(IMediaSample*) PURE; + + // override this to handle end-of-stream + virtual HRESULT EndOfStream(void) PURE; + + // called on runtime errors that will have caused pulling + // to stop + // these errors are all returned from the upstream filter, who + // will have already reported any errors to the filtergraph. + virtual void OnError(HRESULT hr) PURE; + + // flush this pin and all downstream + virtual HRESULT BeginFlush() PURE; + virtual HRESULT EndFlush() PURE; + +}; + +#endif //__PULLPIN_H__ diff --git a/src/thirdparty/BaseClasses/refclock.cpp b/src/thirdparty/BaseClasses/refclock.cpp index a35033f1729..993204e11e4 100644 --- a/src/thirdparty/BaseClasses/refclock.cpp +++ b/src/thirdparty/BaseClasses/refclock.cpp @@ -1,403 +1,403 @@ -//------------------------------------------------------------------------------ -// File: RefClock.cpp -// -// Desc: DirectShow base classes - implements the IReferenceClock interface. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - -#ifdef DXMPERF -#include "dxmperf.h" -#endif // DXMPERF - - -// 'this' used in constructor list -#pragma warning(disable:4355) - - -STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface( - REFIID riid, - __deref_out void ** ppv) -{ - HRESULT hr; - - if (riid == IID_IReferenceClock) - { - hr = GetInterface((IReferenceClock *) this, ppv); - } - else if (riid == IID_IReferenceClockTimerControl) - { - hr = GetInterface((IReferenceClockTimerControl *) this, ppv); - } - else - { - hr = CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - return hr; -} - -CBaseReferenceClock::~CBaseReferenceClock() -{ -#ifdef DXMPERF - PERFLOG_DTOR( L"CBaseReferenceClock", (IReferenceClock *) this ); -#endif // DXMPERF - - if (m_TimerResolution) timeEndPeriod(m_TimerResolution); - - if (m_pSchedule) - { - m_pSchedule->DumpLinkedList(); - } - - if (m_hThread) - { - m_bAbort = TRUE; - TriggerThread(); - WaitForSingleObject( m_hThread, INFINITE ); - EXECUTE_ASSERT( CloseHandle(m_hThread) ); - m_hThread = NULL; - EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); - delete m_pSchedule; - } -} - -// A derived class may supply a hThreadEvent if it has its own thread that will take care -// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread() -// to see what such a thread has to do.) -CBaseReferenceClock::CBaseReferenceClock( __in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - __inout_opt CAMSchedule * pShed ) -: CUnknown( pName, pUnk ) -, m_rtLastGotTime(0) -, m_TimerResolution(0) -, m_bAbort( FALSE ) -, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) -, m_hThread(NULL) -, m_rtNextAdvise(0) -{ - -#ifdef DXMPERF - PERFLOG_CTOR( pName ? pName : L"CBaseReferenceClock", (IReferenceClock *) this ); -#endif // DXMPERF - - ASSERT(m_pSchedule); - if (!m_pSchedule) - { - *phr = E_OUTOFMEMORY; - } - else - { - // Set up the highest resolution timer we can manage - TIMECAPS tc; - m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) - ? tc.wPeriodMin - : 1; - - timeBeginPeriod(m_TimerResolution); - - /* Initialise our system times - the derived clock should set the right values */ - m_dwPrevSystemTime = timeGetTime(); - m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime; - - #ifdef PERF - m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime")); - #endif - - if ( !pShed ) - { - DWORD ThreadID; - m_hThread = ::CreateThread(NULL, // Security attributes - (DWORD) 0, // Initial stack size - AdviseThreadFunction, // Thread start address - (LPVOID) this, // Thread parameter - (DWORD) 0, // Creation flags - &ThreadID); // Thread identifier - - if (m_hThread) - { - SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL ); - } - else - { - *phr = E_FAIL; - EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); - delete m_pSchedule; - m_pSchedule = NULL; - } - } - } -} - -void CBaseReferenceClock::Restart (IN REFERENCE_TIME rtMinTime) -{ - Lock(); - m_rtLastGotTime = rtMinTime ; - Unlock(); -} - -STDMETHODIMP CBaseReferenceClock::GetTime(__out REFERENCE_TIME *pTime) -{ - HRESULT hr; - if (pTime) - { - REFERENCE_TIME rtNow; - Lock(); - rtNow = GetPrivateTime(); - if (rtNow > m_rtLastGotTime) - { - m_rtLastGotTime = rtNow; - hr = S_OK; - } - else - { - hr = S_FALSE; - } - *pTime = m_rtLastGotTime; - Unlock(); - MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)) ); - -#ifdef DXMPERF - PERFLOG_GETTIME( (IReferenceClock *) this, *pTime ); -#endif // DXMPERF - - } - else hr = E_POINTER; - - return hr; -} - -/* Ask for an async notification that a time has elapsed */ - -STDMETHODIMP CBaseReferenceClock::AdviseTime( - REFERENCE_TIME baseTime, // base reference time - REFERENCE_TIME streamTime, // stream offset time - HEVENT hEvent, // advise via this event - __out DWORD_PTR *pdwAdviseCookie)// where your cookie goes -{ - CheckPointer(pdwAdviseCookie, E_POINTER); - *pdwAdviseCookie = 0; - - // Check that the event is not already set - ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0)); - - HRESULT hr; - - const REFERENCE_TIME lRefTime = baseTime + streamTime; - if ( lRefTime <= 0 || lRefTime == MAX_TIME ) - { - hr = E_INVALIDARG; - } - else - { - *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE ); - hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; - } - return hr; -} - - -/* Ask for an asynchronous periodic notification that a time has elapsed */ - -STDMETHODIMP CBaseReferenceClock::AdvisePeriodic( - REFERENCE_TIME StartTime, // starting at this time - REFERENCE_TIME PeriodTime, // time between notifications - HSEMAPHORE hSemaphore, // advise via a semaphore - __out DWORD_PTR *pdwAdviseCookie) // where your cookie goes -{ - CheckPointer(pdwAdviseCookie, E_POINTER); - *pdwAdviseCookie = 0; - - HRESULT hr; - if (StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME ) - { - *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE ); - hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; - } - else hr = E_INVALIDARG; - - return hr; -} - - -STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) -{ - return m_pSchedule->Unadvise(dwAdviseCookie); -} - - -REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() -{ - CAutoLock cObjectLock(this); - - - /* If the clock has wrapped then the current time will be less than - * the last time we were notified so add on the extra milliseconds - * - * The time period is long enough so that the likelihood of - * successive calls spanning the clock cycle is not considered. - */ - - DWORD dwTime = timeGetTime(); - { - m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime)); - m_dwPrevSystemTime = dwTime; - } - - return m_rtPrivateTime; -} - - -/* Adjust the current time by the input value. This allows an - external time source to work out some of the latency of the clock - system and adjust the "current" time accordingly. The intent is - that the time returned to the user is synchronised to a clock - source and allows drift to be catered for. - - For example: if the clock source detects a drift it can pass a delta - to the current time rather than having to set an explicit time. -*/ - -STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) -{ -#ifdef _DEBUG - - // Just break if passed an improper time delta value - LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta; - if (llDelta > UNITS * 1000) { - DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta"))); - //DebugBreak(); - } - - // We're going to calculate a "severity" for the time change. Max -1 - // min 8. We'll then use this as the debug logging level for a - // debug log message. - const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs - - DWORD delta = abs(usDelta); // varying delta - // Severity == 8 - ceil(log(abs( micro-secs delta))) - int Severity = 8; - while ( delta > 0 ) - { - delta >>= 3; // div 8 - Severity--; - } - - // Sev == 0 => > 2 second delta! - DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity, - TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."), - Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)), - DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) )); - - // Don't want the DbgBreak to fire when running stress on debug-builds. - #ifdef BREAK_ON_SEVERE_TIME_DELTA - if (Severity < 0) - DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"), - TEXT(__FILE__),__LINE__); - #endif - -#endif - - CAutoLock cObjectLock(this); - m_rtPrivateTime += TimeDelta; - // If time goes forwards, and we have advises, then we need to - // trigger the thread so that it can re-evaluate its wait time. - // Since we don't want the cost of the thread switches if the change - // is really small, only do it if clock goes forward by more than - // 0.5 millisecond. If the time goes backwards, the thread will - // wake up "early" (relativly speaking) and will re-evaluate at - // that time. - if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread(); - return NOERROR; -} - -// Thread stuff - -DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(__in LPVOID p) -{ - return DWORD(reinterpret_cast(p)->AdviseThread()); -} - -HRESULT CBaseReferenceClock::AdviseThread() -{ - DWORD dwWait = INFINITE; - - // The first thing we do is wait until something interesting happens - // (meaning a first advise or shutdown). This prevents us calling - // GetPrivateTime immediately which is goodness as that is a virtual - // routine and the derived class may not yet be constructed. (This - // thread is created in the base class constructor.) - - while ( !m_bAbort ) - { - // Wait for an interesting event to happen - DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait )); - WaitForSingleObject(m_pSchedule->GetEvent(), dwWait); - if (m_bAbort) break; - - // There are several reasons why we need to work from the internal - // time, mainly to do with what happens when time goes backwards. - // Mainly, it stop us looping madly if an event is just about to - // expire when the clock goes backward (i.e. GetTime stop for a - // while). - const REFERENCE_TIME rtNow = GetPrivateTime(); - - DbgLog((LOG_TIMING, 3, - TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"), - ConvertToMilliseconds(rtNow) )); - - // We must add in a millisecond, since this is the resolution of our - // WaitForSingleObject timer. Failure to do so will cause us to loop - // franticly for (approx) 1 a millisecond. - m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow ); - LONGLONG llWait = m_rtNextAdvise - rtNow; - - ASSERT( llWait > 0 ); - - llWait = ConvertToMilliseconds(llWait); - // DON'T replace this with a max!! (The type's of these things is VERY important) - dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait); - }; - return NOERROR; -} - -HRESULT CBaseReferenceClock::SetDefaultTimerResolution( - REFERENCE_TIME timerResolution // in 100ns - ) -{ - CAutoLock cObjectLock(this); - if( 0 == timerResolution ) { - if( m_TimerResolution ) { - timeEndPeriod( m_TimerResolution ); - m_TimerResolution = 0; - } - } else { - TIMECAPS tc; - DWORD dwMinResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) - ? tc.wPeriodMin - : 1; - DWORD dwResolution = std::max(dwMinResolution, DWORD(timerResolution / 10000)); - if( dwResolution != m_TimerResolution ) { - timeEndPeriod(m_TimerResolution); - m_TimerResolution = dwResolution; - timeBeginPeriod( m_TimerResolution ); - } - } - return S_OK; -} - -HRESULT CBaseReferenceClock::GetDefaultTimerResolution( - __out REFERENCE_TIME* pTimerResolution // in 100ns - ) -{ - if( !pTimerResolution ) { - return E_POINTER; - } - CAutoLock cObjectLock(this); - *pTimerResolution = m_TimerResolution * 10000i64; - return S_OK; -} +//------------------------------------------------------------------------------ +// File: RefClock.cpp +// +// Desc: DirectShow base classes - implements the IReferenceClock interface. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + +#ifdef DXMPERF +#include "dxmperf.h" +#endif // DXMPERF + + +// 'this' used in constructor list +#pragma warning(disable:4355) + + +STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface( + REFIID riid, + __deref_out void ** ppv) +{ + HRESULT hr; + + if (riid == IID_IReferenceClock) + { + hr = GetInterface((IReferenceClock *) this, ppv); + } + else if (riid == IID_IReferenceClockTimerControl) + { + hr = GetInterface((IReferenceClockTimerControl *) this, ppv); + } + else + { + hr = CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + return hr; +} + +CBaseReferenceClock::~CBaseReferenceClock() +{ +#ifdef DXMPERF + PERFLOG_DTOR( L"CBaseReferenceClock", (IReferenceClock *) this ); +#endif // DXMPERF + + if (m_TimerResolution) timeEndPeriod(m_TimerResolution); + + if (m_pSchedule) + { + m_pSchedule->DumpLinkedList(); + } + + if (m_hThread) + { + m_bAbort = TRUE; + TriggerThread(); + WaitForSingleObject( m_hThread, INFINITE ); + EXECUTE_ASSERT( CloseHandle(m_hThread) ); + m_hThread = NULL; + EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); + delete m_pSchedule; + } +} + +// A derived class may supply a hThreadEvent if it has its own thread that will take care +// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread() +// to see what such a thread has to do.) +CBaseReferenceClock::CBaseReferenceClock( __in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + __inout_opt CAMSchedule * pShed ) +: CUnknown( pName, pUnk ) +, m_rtLastGotTime(0) +, m_TimerResolution(0) +, m_bAbort( FALSE ) +, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) +, m_hThread(NULL) +, m_rtNextAdvise(0) +{ + +#ifdef DXMPERF + PERFLOG_CTOR( pName ? pName : L"CBaseReferenceClock", (IReferenceClock *) this ); +#endif // DXMPERF + + ASSERT(m_pSchedule); + if (!m_pSchedule) + { + *phr = E_OUTOFMEMORY; + } + else + { + // Set up the highest resolution timer we can manage + TIMECAPS tc; + m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) + ? tc.wPeriodMin + : 1; + + timeBeginPeriod(m_TimerResolution); + + /* Initialise our system times - the derived clock should set the right values */ + m_dwPrevSystemTime = timeGetTime(); + m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime; + + #ifdef PERF + m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime")); + #endif + + if ( !pShed ) + { + DWORD ThreadID; + m_hThread = ::CreateThread(NULL, // Security attributes + (DWORD) 0, // Initial stack size + AdviseThreadFunction, // Thread start address + (LPVOID) this, // Thread parameter + (DWORD) 0, // Creation flags + &ThreadID); // Thread identifier + + if (m_hThread) + { + SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL ); + } + else + { + *phr = E_FAIL; + EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) ); + delete m_pSchedule; + m_pSchedule = NULL; + } + } + } +} + +void CBaseReferenceClock::Restart (IN REFERENCE_TIME rtMinTime) +{ + Lock(); + m_rtLastGotTime = rtMinTime ; + Unlock(); +} + +STDMETHODIMP CBaseReferenceClock::GetTime(__out REFERENCE_TIME *pTime) +{ + HRESULT hr; + if (pTime) + { + REFERENCE_TIME rtNow; + Lock(); + rtNow = GetPrivateTime(); + if (rtNow > m_rtLastGotTime) + { + m_rtLastGotTime = rtNow; + hr = S_OK; + } + else + { + hr = S_FALSE; + } + *pTime = m_rtLastGotTime; + Unlock(); + MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)) ); + +#ifdef DXMPERF + PERFLOG_GETTIME( (IReferenceClock *) this, *pTime ); +#endif // DXMPERF + + } + else hr = E_POINTER; + + return hr; +} + +/* Ask for an async notification that a time has elapsed */ + +STDMETHODIMP CBaseReferenceClock::AdviseTime( + REFERENCE_TIME baseTime, // base reference time + REFERENCE_TIME streamTime, // stream offset time + HEVENT hEvent, // advise via this event + __out DWORD_PTR *pdwAdviseCookie)// where your cookie goes +{ + CheckPointer(pdwAdviseCookie, E_POINTER); + *pdwAdviseCookie = 0; + + // Check that the event is not already set + ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0)); + + HRESULT hr; + + const REFERENCE_TIME lRefTime = baseTime + streamTime; + if ( lRefTime <= 0 || lRefTime == MAX_TIME ) + { + hr = E_INVALIDARG; + } + else + { + *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE ); + hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; + } + return hr; +} + + +/* Ask for an asynchronous periodic notification that a time has elapsed */ + +STDMETHODIMP CBaseReferenceClock::AdvisePeriodic( + REFERENCE_TIME StartTime, // starting at this time + REFERENCE_TIME PeriodTime, // time between notifications + HSEMAPHORE hSemaphore, // advise via a semaphore + __out DWORD_PTR *pdwAdviseCookie) // where your cookie goes +{ + CheckPointer(pdwAdviseCookie, E_POINTER); + *pdwAdviseCookie = 0; + + HRESULT hr; + if (StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME ) + { + *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE ); + hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY; + } + else hr = E_INVALIDARG; + + return hr; +} + + +STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) +{ + return m_pSchedule->Unadvise(dwAdviseCookie); +} + + +REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() +{ + CAutoLock cObjectLock(this); + + + /* If the clock has wrapped then the current time will be less than + * the last time we were notified so add on the extra milliseconds + * + * The time period is long enough so that the likelihood of + * successive calls spanning the clock cycle is not considered. + */ + + DWORD dwTime = timeGetTime(); + { + m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime)); + m_dwPrevSystemTime = dwTime; + } + + return m_rtPrivateTime; +} + + +/* Adjust the current time by the input value. This allows an + external time source to work out some of the latency of the clock + system and adjust the "current" time accordingly. The intent is + that the time returned to the user is synchronised to a clock + source and allows drift to be catered for. + + For example: if the clock source detects a drift it can pass a delta + to the current time rather than having to set an explicit time. +*/ + +STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) +{ +#ifdef _DEBUG + + // Just break if passed an improper time delta value + LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta; + if (llDelta > UNITS * 1000) { + DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta"))); + //DebugBreak(); + } + + // We're going to calculate a "severity" for the time change. Max -1 + // min 8. We'll then use this as the debug logging level for a + // debug log message. + const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs + + DWORD delta = abs(usDelta); // varying delta + // Severity == 8 - ceil(log(abs( micro-secs delta))) + int Severity = 8; + while ( delta > 0 ) + { + delta >>= 3; // div 8 + Severity--; + } + + // Sev == 0 => > 2 second delta! + DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity, + TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."), + Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)), + DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) )); + + // Don't want the DbgBreak to fire when running stress on debug-builds. + #ifdef BREAK_ON_SEVERE_TIME_DELTA + if (Severity < 0) + DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"), + TEXT(__FILE__),__LINE__); + #endif + +#endif + + CAutoLock cObjectLock(this); + m_rtPrivateTime += TimeDelta; + // If time goes forwards, and we have advises, then we need to + // trigger the thread so that it can re-evaluate its wait time. + // Since we don't want the cost of the thread switches if the change + // is really small, only do it if clock goes forward by more than + // 0.5 millisecond. If the time goes backwards, the thread will + // wake up "early" (relativly speaking) and will re-evaluate at + // that time. + if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread(); + return NOERROR; +} + +// Thread stuff + +DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(__in LPVOID p) +{ + return DWORD(reinterpret_cast(p)->AdviseThread()); +} + +HRESULT CBaseReferenceClock::AdviseThread() +{ + DWORD dwWait = INFINITE; + + // The first thing we do is wait until something interesting happens + // (meaning a first advise or shutdown). This prevents us calling + // GetPrivateTime immediately which is goodness as that is a virtual + // routine and the derived class may not yet be constructed. (This + // thread is created in the base class constructor.) + + while ( !m_bAbort ) + { + // Wait for an interesting event to happen + DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait )); + WaitForSingleObject(m_pSchedule->GetEvent(), dwWait); + if (m_bAbort) break; + + // There are several reasons why we need to work from the internal + // time, mainly to do with what happens when time goes backwards. + // Mainly, it stop us looping madly if an event is just about to + // expire when the clock goes backward (i.e. GetTime stop for a + // while). + const REFERENCE_TIME rtNow = GetPrivateTime(); + + DbgLog((LOG_TIMING, 3, + TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"), + ConvertToMilliseconds(rtNow) )); + + // We must add in a millisecond, since this is the resolution of our + // WaitForSingleObject timer. Failure to do so will cause us to loop + // franticly for (approx) 1 a millisecond. + m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow ); + LONGLONG llWait = m_rtNextAdvise - rtNow; + + ASSERT( llWait > 0 ); + + llWait = ConvertToMilliseconds(llWait); + // DON'T replace this with a max!! (The type's of these things is VERY important) + dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait); + }; + return NOERROR; +} + +HRESULT CBaseReferenceClock::SetDefaultTimerResolution( + REFERENCE_TIME timerResolution // in 100ns + ) +{ + CAutoLock cObjectLock(this); + if( 0 == timerResolution ) { + if( m_TimerResolution ) { + timeEndPeriod( m_TimerResolution ); + m_TimerResolution = 0; + } + } else { + TIMECAPS tc; + DWORD dwMinResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) + ? tc.wPeriodMin + : 1; + DWORD dwResolution = std::max(dwMinResolution, DWORD(timerResolution / 10000)); + if( dwResolution != m_TimerResolution ) { + timeEndPeriod(m_TimerResolution); + m_TimerResolution = dwResolution; + timeBeginPeriod( m_TimerResolution ); + } + } + return S_OK; +} + +HRESULT CBaseReferenceClock::GetDefaultTimerResolution( + __out REFERENCE_TIME* pTimerResolution // in 100ns + ) +{ + if( !pTimerResolution ) { + return E_POINTER; + } + CAutoLock cObjectLock(this); + *pTimerResolution = m_TimerResolution * 10000i64; + return S_OK; +} diff --git a/src/thirdparty/BaseClasses/refclock.h b/src/thirdparty/BaseClasses/refclock.h index d5e9affbcb0..2a8d38434b7 100644 --- a/src/thirdparty/BaseClasses/refclock.h +++ b/src/thirdparty/BaseClasses/refclock.h @@ -1,184 +1,184 @@ -//------------------------------------------------------------------------------ -// File: RefClock.h -// -// Desc: DirectShow base classes - defines the IReferenceClock interface. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __BASEREFCLOCK__ -#define __BASEREFCLOCK__ - -#include "Schedule.h" - -const UINT RESOLUTION = 1; /* High resolution timer */ -const INT ADVISE_CACHE = 4; /* Default cache size */ -const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */ - -inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT) -{ - /* This converts an arbitrary value representing a reference time - into a MILLISECONDS value for use in subsequent system calls */ - - return (RT / (UNITS / MILLISECONDS)); -} - -/* This class hierarchy will support an IReferenceClock interface so - that an audio card (or other externally driven clock) can update the - system wide clock that everyone uses. - - The interface will be pretty thin with probably just one update method - This interface has not yet been defined. - */ - -/* This abstract base class implements the IReferenceClock - * interface. Classes that actually provide clock signals (from - * whatever source) have to be derived from this class. - * - * The abstract class provides implementations for: - * CUnknown support - * locking support (CCritSec) - * client advise code (creates a thread) - * - * Question: what can we do about quality? Change the timer - * resolution to lower the system load? Up the priority of the - * timer thread to force more responsive signals? - * - * During class construction we create a worker thread that is destroyed during - * destuction. This thread executes a series of WaitForSingleObject calls, - * waking up when a command is given to the thread or the next wake up point - * is reached. The wakeup points are determined by clients making Advise - * calls. - * - * Each advise call defines a point in time when they wish to be notified. A - * periodic advise is a series of these such events. We maintain a list of - * advise links and calculate when the nearest event notification is due for. - * We then call WaitForSingleObject with a timeout equal to this time. The - * handle we wait on is used by the class to signal that something has changed - * and that we must reschedule the next event. This typically happens when - * someone comes in and asks for an advise link while we are waiting for an - * event to timeout. - * - * While we are modifying the list of advise requests we - * are protected from interference through a critical section. Clients are NOT - * advised through callbacks. One shot clients have an event set, while - * periodic clients have a semaphore released for each event notification. A - * semaphore allows a client to be kept up to date with the number of events - * actually triggered and be assured that they can't miss multiple events being - * set. - * - * Keeping track of advises is taken care of by the CAMSchedule class. - */ - -class CBaseReferenceClock -: public CUnknown, public IReferenceClock, public CCritSec, public IReferenceClockTimerControl -{ -protected: - virtual ~CBaseReferenceClock(); // Don't let me be created on the stack! -public: - CBaseReferenceClock(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - __inout HRESULT *phr, - __inout_opt CAMSchedule * pSched = 0 ); - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - - DECLARE_IUNKNOWN - - /* IReferenceClock methods */ - // Derived classes must implement GetPrivateTime(). All our GetTime - // does is call GetPrivateTime and then check so that time does not - // go backwards. A return code of S_FALSE implies that the internal - // clock has gone backwards and GetTime time has halted until internal - // time has caught up. (Don't know if this will be much use to folk, - // but it seems odd not to use the return code for something useful.) - STDMETHODIMP GetTime(__out REFERENCE_TIME *pTime); - // When this is called, it sets m_rtLastGotTime to the time it returns. - - /* Provide standard mechanisms for scheduling events */ - - /* Ask for an async notification that a time has elapsed */ - STDMETHODIMP AdviseTime( - REFERENCE_TIME baseTime, // base reference time - REFERENCE_TIME streamTime, // stream offset time - HEVENT hEvent, // advise via this event - __out DWORD_PTR *pdwAdviseCookie// where your cookie goes - ); - - /* Ask for an asynchronous periodic notification that a time has elapsed */ - STDMETHODIMP AdvisePeriodic( - REFERENCE_TIME StartTime, // starting at this time - REFERENCE_TIME PeriodTime, // time between notifications - HSEMAPHORE hSemaphore, // advise via a semaphore - __out DWORD_PTR *pdwAdviseCookie// where your cookie goes - ); - - /* Cancel a request for notification(s) - if the notification was - * a one shot timer then this function doesn't need to be called - * as the advise is automatically cancelled, however it does no - * harm to explicitly cancel a one-shot advise. It is REQUIRED that - * clients call Unadvise to clear a Periodic advise setting. - */ - - STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie); - - /* Methods for the benefit of derived classes or outer objects */ - - // GetPrivateTime() is the REAL clock. GetTime is just a cover for - // it. Derived classes will probably override this method but not - // GetTime() itself. - // The important point about GetPrivateTime() is it's allowed to go - // backwards. Our GetTime() will keep returning the LastGotTime - // until GetPrivateTime() catches up. - virtual REFERENCE_TIME GetPrivateTime(); - - /* Provide a method for correcting drift */ - STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta ); - - CAMSchedule * GetSchedule() const { return m_pSchedule; } - - // IReferenceClockTimerControl methods - // - // Setting a default of 0 disables the default of 1ms - STDMETHODIMP SetDefaultTimerResolution( - REFERENCE_TIME timerResolution // in 100ns - ); - STDMETHODIMP GetDefaultTimerResolution( - __out REFERENCE_TIME* pTimerResolution // in 100ns - ); - -private: - REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time - DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime - REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime - REFERENCE_TIME m_rtNextAdvise; // Time of next advise - UINT m_TimerResolution; - -#ifdef PERF - int m_idGetSystemTime; -#endif - -// Thread stuff -public: - void TriggerThread() // Wakes thread up. Need to do this if - { // time to next advise needs reevaluating. - EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent())); - } - - -private: - BOOL m_bAbort; // Flag used for thread shutdown - HANDLE m_hThread; // Thread handle - - HRESULT AdviseThread(); // Method in which the advise thread runs - static DWORD __stdcall AdviseThreadFunction(__in LPVOID); // Function used to get there - -protected: - CAMSchedule * m_pSchedule; - - void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ; -}; - -#endif - +//------------------------------------------------------------------------------ +// File: RefClock.h +// +// Desc: DirectShow base classes - defines the IReferenceClock interface. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __BASEREFCLOCK__ +#define __BASEREFCLOCK__ + +#include "Schedule.h" + +const UINT RESOLUTION = 1; /* High resolution timer */ +const INT ADVISE_CACHE = 4; /* Default cache size */ +const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */ + +inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT) +{ + /* This converts an arbitrary value representing a reference time + into a MILLISECONDS value for use in subsequent system calls */ + + return (RT / (UNITS / MILLISECONDS)); +} + +/* This class hierarchy will support an IReferenceClock interface so + that an audio card (or other externally driven clock) can update the + system wide clock that everyone uses. + + The interface will be pretty thin with probably just one update method + This interface has not yet been defined. + */ + +/* This abstract base class implements the IReferenceClock + * interface. Classes that actually provide clock signals (from + * whatever source) have to be derived from this class. + * + * The abstract class provides implementations for: + * CUnknown support + * locking support (CCritSec) + * client advise code (creates a thread) + * + * Question: what can we do about quality? Change the timer + * resolution to lower the system load? Up the priority of the + * timer thread to force more responsive signals? + * + * During class construction we create a worker thread that is destroyed during + * destuction. This thread executes a series of WaitForSingleObject calls, + * waking up when a command is given to the thread or the next wake up point + * is reached. The wakeup points are determined by clients making Advise + * calls. + * + * Each advise call defines a point in time when they wish to be notified. A + * periodic advise is a series of these such events. We maintain a list of + * advise links and calculate when the nearest event notification is due for. + * We then call WaitForSingleObject with a timeout equal to this time. The + * handle we wait on is used by the class to signal that something has changed + * and that we must reschedule the next event. This typically happens when + * someone comes in and asks for an advise link while we are waiting for an + * event to timeout. + * + * While we are modifying the list of advise requests we + * are protected from interference through a critical section. Clients are NOT + * advised through callbacks. One shot clients have an event set, while + * periodic clients have a semaphore released for each event notification. A + * semaphore allows a client to be kept up to date with the number of events + * actually triggered and be assured that they can't miss multiple events being + * set. + * + * Keeping track of advises is taken care of by the CAMSchedule class. + */ + +class CBaseReferenceClock +: public CUnknown, public IReferenceClock, public CCritSec, public IReferenceClockTimerControl +{ +protected: + virtual ~CBaseReferenceClock(); // Don't let me be created on the stack! +public: + CBaseReferenceClock(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + __inout HRESULT *phr, + __inout_opt CAMSchedule * pSched = 0 ); + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + + DECLARE_IUNKNOWN + + /* IReferenceClock methods */ + // Derived classes must implement GetPrivateTime(). All our GetTime + // does is call GetPrivateTime and then check so that time does not + // go backwards. A return code of S_FALSE implies that the internal + // clock has gone backwards and GetTime time has halted until internal + // time has caught up. (Don't know if this will be much use to folk, + // but it seems odd not to use the return code for something useful.) + STDMETHODIMP GetTime(__out REFERENCE_TIME *pTime); + // When this is called, it sets m_rtLastGotTime to the time it returns. + + /* Provide standard mechanisms for scheduling events */ + + /* Ask for an async notification that a time has elapsed */ + STDMETHODIMP AdviseTime( + REFERENCE_TIME baseTime, // base reference time + REFERENCE_TIME streamTime, // stream offset time + HEVENT hEvent, // advise via this event + __out DWORD_PTR *pdwAdviseCookie// where your cookie goes + ); + + /* Ask for an asynchronous periodic notification that a time has elapsed */ + STDMETHODIMP AdvisePeriodic( + REFERENCE_TIME StartTime, // starting at this time + REFERENCE_TIME PeriodTime, // time between notifications + HSEMAPHORE hSemaphore, // advise via a semaphore + __out DWORD_PTR *pdwAdviseCookie// where your cookie goes + ); + + /* Cancel a request for notification(s) - if the notification was + * a one shot timer then this function doesn't need to be called + * as the advise is automatically cancelled, however it does no + * harm to explicitly cancel a one-shot advise. It is REQUIRED that + * clients call Unadvise to clear a Periodic advise setting. + */ + + STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie); + + /* Methods for the benefit of derived classes or outer objects */ + + // GetPrivateTime() is the REAL clock. GetTime is just a cover for + // it. Derived classes will probably override this method but not + // GetTime() itself. + // The important point about GetPrivateTime() is it's allowed to go + // backwards. Our GetTime() will keep returning the LastGotTime + // until GetPrivateTime() catches up. + virtual REFERENCE_TIME GetPrivateTime(); + + /* Provide a method for correcting drift */ + STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta ); + + CAMSchedule * GetSchedule() const { return m_pSchedule; } + + // IReferenceClockTimerControl methods + // + // Setting a default of 0 disables the default of 1ms + STDMETHODIMP SetDefaultTimerResolution( + REFERENCE_TIME timerResolution // in 100ns + ); + STDMETHODIMP GetDefaultTimerResolution( + __out REFERENCE_TIME* pTimerResolution // in 100ns + ); + +private: + REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time + DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime + REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime + REFERENCE_TIME m_rtNextAdvise; // Time of next advise + UINT m_TimerResolution; + +#ifdef PERF + int m_idGetSystemTime; +#endif + +// Thread stuff +public: + void TriggerThread() // Wakes thread up. Need to do this if + { // time to next advise needs reevaluating. + EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent())); + } + + +private: + BOOL m_bAbort; // Flag used for thread shutdown + HANDLE m_hThread; // Thread handle + + HRESULT AdviseThread(); // Method in which the advise thread runs + static DWORD __stdcall AdviseThreadFunction(__in LPVOID); // Function used to get there + +protected: + CAMSchedule * m_pSchedule; + + void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ; +}; + +#endif + diff --git a/src/thirdparty/BaseClasses/reftime.h b/src/thirdparty/BaseClasses/reftime.h index 0ed32f6e175..5bc99a6946d 100644 --- a/src/thirdparty/BaseClasses/reftime.h +++ b/src/thirdparty/BaseClasses/reftime.h @@ -1,116 +1,116 @@ -//------------------------------------------------------------------------------ -// File: RefTime.h -// -// Desc: DirectShow base classes - defines CRefTime, a class that manages -// reference times. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// CRefTime -// -// Manage reference times. -// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual) -// functions providing simple comparison, conversion and arithmetic. -// -// A reference time (at the moment) is a unit of seconds represented in -// 100ns units as is used in the Win32 FILETIME structure. BUT the time -// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it -// will either be stream time or reference time depending upon context -// -// This class provides simple arithmetic operations on reference times -// -// keep non-virtual otherwise the data layout will not be the same as -// REFERENCE_TIME - - -// ----- -// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but -// you will need to do so explicitly -// ----- - - -#ifndef __REFTIME__ -#define __REFTIME__ - - -const LONGLONG MILLISECONDS = (1000); // 10 ^ 3 -const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9 -const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7 - -/* Unfortunately an inline function here generates a call to __allmul - - even for constants! -*/ -#define MILLISECONDS_TO_100NS_UNITS(lMs) \ - Int32x32To64((lMs), (UNITS / MILLISECONDS)) - -class CRefTime -{ -public: - - // *MUST* be the only data member so that this class is exactly - // equivalent to a REFERENCE_TIME. - // Also, must be *no virtual functions* - - REFERENCE_TIME m_time; - - inline CRefTime() - { - // default to 0 time - m_time = 0; - }; - - inline CRefTime(LONG msecs) - { - m_time = MILLISECONDS_TO_100NS_UNITS(msecs); - }; - - inline CRefTime(REFERENCE_TIME rt) - { - m_time = rt; - }; - - inline operator REFERENCE_TIME() const - { - return m_time; - }; - - inline CRefTime& operator=(const CRefTime& rt) - { - m_time = rt.m_time; - return *this; - }; - - inline CRefTime& operator=(const LONGLONG ll) - { - m_time = ll; - return *this; - }; - - inline CRefTime& operator+=(const CRefTime& rt) - { - return (*this = *this + rt); - }; - - inline CRefTime& operator-=(const CRefTime& rt) - { - return (*this = *this - rt); - }; - - inline LONG Millisecs(void) - { - return (LONG)(m_time / (UNITS / MILLISECONDS)); - }; - - inline LONGLONG GetUnits(void) - { - return m_time; - }; -}; - -const LONGLONG TimeZero = 0; - -#endif /* __REFTIME__ */ - +//------------------------------------------------------------------------------ +// File: RefTime.h +// +// Desc: DirectShow base classes - defines CRefTime, a class that manages +// reference times. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// CRefTime +// +// Manage reference times. +// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual) +// functions providing simple comparison, conversion and arithmetic. +// +// A reference time (at the moment) is a unit of seconds represented in +// 100ns units as is used in the Win32 FILETIME structure. BUT the time +// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it +// will either be stream time or reference time depending upon context +// +// This class provides simple arithmetic operations on reference times +// +// keep non-virtual otherwise the data layout will not be the same as +// REFERENCE_TIME + + +// ----- +// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but +// you will need to do so explicitly +// ----- + + +#ifndef __REFTIME__ +#define __REFTIME__ + + +const LONGLONG MILLISECONDS = (1000); // 10 ^ 3 +const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9 +const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7 + +/* Unfortunately an inline function here generates a call to __allmul + - even for constants! +*/ +#define MILLISECONDS_TO_100NS_UNITS(lMs) \ + Int32x32To64((lMs), (UNITS / MILLISECONDS)) + +class CRefTime +{ +public: + + // *MUST* be the only data member so that this class is exactly + // equivalent to a REFERENCE_TIME. + // Also, must be *no virtual functions* + + REFERENCE_TIME m_time; + + inline CRefTime() + { + // default to 0 time + m_time = 0; + }; + + inline CRefTime(LONG msecs) + { + m_time = MILLISECONDS_TO_100NS_UNITS(msecs); + }; + + inline CRefTime(REFERENCE_TIME rt) + { + m_time = rt; + }; + + inline operator REFERENCE_TIME() const + { + return m_time; + }; + + inline CRefTime& operator=(const CRefTime& rt) + { + m_time = rt.m_time; + return *this; + }; + + inline CRefTime& operator=(const LONGLONG ll) + { + m_time = ll; + return *this; + }; + + inline CRefTime& operator+=(const CRefTime& rt) + { + return (*this = *this + rt); + }; + + inline CRefTime& operator-=(const CRefTime& rt) + { + return (*this = *this - rt); + }; + + inline LONG Millisecs(void) + { + return (LONG)(m_time / (UNITS / MILLISECONDS)); + }; + + inline LONGLONG GetUnits(void) + { + return m_time; + }; +}; + +const LONGLONG TimeZero = 0; + +#endif /* __REFTIME__ */ + diff --git a/src/thirdparty/BaseClasses/renbase.cpp b/src/thirdparty/BaseClasses/renbase.cpp index fb6956eb7c4..27018a22e1b 100644 --- a/src/thirdparty/BaseClasses/renbase.cpp +++ b/src/thirdparty/BaseClasses/renbase.cpp @@ -1,2858 +1,2858 @@ -//------------------------------------------------------------------------------ -// File: RenBase.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" // DirectShow base class definitions -#include // Needed for definition of timeGetTime -#include // Standard data type limit definitions -#include "measure.h" // Used for time critical log functions - -#pragma warning(disable:4355) - -// Helper function for clamping time differences -int inline TimeDiff(REFERENCE_TIME rt) -{ - if (rt < - (50 * UNITS)) { - return -(50 * UNITS); - } else - if (rt > 50 * UNITS) { - return 50 * UNITS; - } else return (int)rt; -} - -// Implements the CBaseRenderer class - -CBaseRenderer::CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer - __in_opt LPCTSTR pName, // Debug ONLY description - __inout_opt LPUNKNOWN pUnk, // Aggregated owner object - __inout HRESULT *phr) : // General OLE return code - - CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass), - m_evComplete(TRUE, phr), - m_RenderEvent(FALSE, phr), - m_bAbort(FALSE), - m_pPosition(NULL), - m_ThreadSignal(TRUE, phr), - m_bStreaming(FALSE), - m_bEOS(FALSE), - m_bEOSDelivered(FALSE), - m_pMediaSample(NULL), - m_dwAdvise(0), - m_pQSink(NULL), - m_pInputPin(NULL), - m_bRepaintStatus(TRUE), - m_SignalTime(0), - m_bInReceive(FALSE), - m_EndOfStreamTimer(0) -{ - if (SUCCEEDED(*phr)) { - Ready(); -#ifdef PERF - m_idBaseStamp = MSR_REGISTER(TEXT("BaseRenderer: sample time stamp")); - m_idBaseRenderTime = MSR_REGISTER(TEXT("BaseRenderer: draw time (msec)")); - m_idBaseAccuracy = MSR_REGISTER(TEXT("BaseRenderer: Accuracy (msec)")); -#endif - } -} - - -// Delete the dynamically allocated IMediaPosition and IMediaSeeking helper -// object. The object is created when somebody queries us. These are standard -// control interfaces for seeking and setting start/stop positions and rates. -// We will probably also have made an input pin based on CRendererInputPin -// that has to be deleted, it's created when an enumerator calls our GetPin - -CBaseRenderer::~CBaseRenderer() -{ - ASSERT(m_bStreaming == FALSE); - ASSERT(m_EndOfStreamTimer == 0); - StopStreaming(); - ClearPendingSample(); - - // Delete any IMediaPosition implementation - - if (m_pPosition) { - delete m_pPosition; - m_pPosition = NULL; - } - - // Delete any input pin created - - if (m_pInputPin) { - delete m_pInputPin; - m_pInputPin = NULL; - } - - // Release any Quality sink - - ASSERT(m_pQSink == NULL); -} - - -// This returns the IMediaPosition and IMediaSeeking interfaces - -HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid, __deref_out void **ppv) -{ - CAutoLock cObjectCreationLock(&m_ObjectCreationLock); - if (m_pPosition) { - return m_pPosition->NonDelegatingQueryInterface(riid,ppv); - } - - CBasePin *pPin = GetPin(0); - if (NULL == pPin) { - return E_OUTOFMEMORY; - } - - HRESULT hr = NOERROR; - - // Create implementation of this dynamically since sometimes we may - // never try and do a seek. The helper object implements a position - // control interface (IMediaPosition) which in fact simply takes the - // calls normally from the filter graph and passes them upstream - - m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"), - CBaseFilter::GetOwner(), - (HRESULT *) &hr, - pPin); - if (m_pPosition == NULL) { - return E_OUTOFMEMORY; - } - - if (FAILED(hr)) { - delete m_pPosition; - m_pPosition = NULL; - return E_NOINTERFACE; - } - return GetMediaPositionInterface(riid,ppv); -} - - -// Overriden to say what interfaces we support and where - -STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - // Do we have this interface - - if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { - return GetMediaPositionInterface(riid,ppv); - } else { - return CBaseFilter::NonDelegatingQueryInterface(riid,ppv); - } -} - - -// This is called whenever we change states, we have a manual reset event that -// is signalled whenever we don't won't the source filter thread to wait in us -// (such as in a stopped state) and likewise is not signalled whenever it can -// wait (during paused and running) this function sets or resets the thread -// event. The event is used to stop source filter threads waiting in Receive - -HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait) -{ - if (bCanWait == TRUE) { - m_ThreadSignal.Reset(); - } else { - m_ThreadSignal.Set(); - } - return NOERROR; -} - - -#ifdef _DEBUG -// Dump the current renderer state to the debug terminal. The hardest part of -// the renderer is the window where we unlock everything to wait for a clock -// to signal it is time to draw or for the application to cancel everything -// by stopping the filter. If we get things wrong we can leave the thread in -// WaitForRenderTime with no way for it to ever get out and we will deadlock - -void CBaseRenderer::DisplayRendererState() -{ - DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime"))); - - // No way should this be signalled at this point - - BOOL bSignalled = m_ThreadSignal.Check(); - DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled)); - - // Now output the current renderer state variables - - DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State)); - - DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort)); - - DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming)); - - DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise)); - - DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample)); - - DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS)); - - DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered)); - - DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus)); - - - // Output the delayed end of stream timer information - - DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer)); - - DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime))); - - - // Should never timeout during a flushing state - - BOOL bFlushing = m_pInputPin->IsFlushing(); - DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing)); - - // Display the time we were told to start at - DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time))); - - // Have we got a reference clock - if (m_pClock == NULL) return; - - // Get the current time from the wall clock - - CRefTime CurrentTime,StartTime,EndTime; - m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime); - CRefTime Offset = CurrentTime - m_tStart; - - // Display the current time from the clock - - DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time))); - - DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs())); - - - // Do we have a sample ready to render - if (m_pMediaSample == NULL) return; - - m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime); - DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"), - StartTime.Millisecs(),EndTime.Millisecs())); - - // Calculate how long it is until it is due for rendering - CRefTime Wait = (m_tStart + StartTime) - CurrentTime; - DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs())); -} -#endif - - -// Wait until the clock sets the timer event or we're otherwise signalled. We -// set an arbitrary timeout for this wait and if it fires then we display the -// current renderer state on the debugger. It will often fire if the filter's -// left paused in an application however it may also fire during stress tests -// if the synchronisation with application seeks and state changes is faulty - -#define RENDER_TIMEOUT 10000 - -HRESULT CBaseRenderer::WaitForRenderTime() -{ - HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent }; - DWORD Result = WAIT_TIMEOUT; - - // Wait for either the time to arrive or for us to be stopped - - OnWaitStart(); - while (Result == WAIT_TIMEOUT) { - Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT); - -#ifdef _DEBUG - if (Result == WAIT_TIMEOUT) DisplayRendererState(); -#endif - - } - OnWaitEnd(); - - // We may have been awoken without the timer firing - - if (Result == WAIT_OBJECT_0) { - return VFW_E_STATE_CHANGED; - } - - SignalTimerFired(); - return NOERROR; -} - - -// Poll waiting for Receive to complete. This really matters when -// Receive may set the palette and cause window messages -// The problem is that if we don't really wait for a renderer to -// stop processing we can deadlock waiting for a transform which -// is calling the renderer's Receive() method because the transform's -// Stop method doesn't know to process window messages to unblock -// the renderer's Receive processing -void CBaseRenderer::WaitForReceiveToComplete() -{ - for (;;) { - if (!m_bInReceive) { - break; - } - - MSG msg; - // Receive all interthread snedmessages - PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); - - Sleep(1); - } - - // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call - // above just cleared the changebit which will cause some messaging - // calls to block (waitMessage, MsgWaitFor...) now. - // Post a dummy message to set the QS_POSTMESSAGE bit again - if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { - // Send dummy message - PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); - } -} - -// A filter can have four discrete states, namely Stopped, Running, Paused, -// Intermediate. We are in an intermediate state if we are currently trying -// to pause but haven't yet got the first sample (or if we have been flushed -// in paused state and therefore still have to wait for a sample to arrive) - -// This class contains an event called m_evComplete which is signalled when -// the current state is completed and is not signalled when we are waiting to -// complete the last state transition. As mentioned above the only time we -// use this at the moment is when we wait for a media sample in paused state -// If while we are waiting we receive an end of stream notification from the -// source filter then we know no data is imminent so we can reset the event -// This means that when we transition to paused the source filter must call -// end of stream on us or send us an image otherwise we'll hang indefinately - - -// Simple internal way of getting the real state - -FILTER_STATE CBaseRenderer::GetRealState() { - return m_State; -} - - -// The renderer doesn't complete the full transition to paused states until -// it has got one media sample to render. If you ask it for its state while -// it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE - -STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State) -{ - CheckPointer(State,E_POINTER); - - if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) { - *State = m_State; - return VFW_S_STATE_INTERMEDIATE; - } - *State = m_State; - return NOERROR; -} - - -// If we're pausing and we have no samples we don't complete the transition -// to State_Paused and we return S_FALSE. However if the m_bAbort flag has -// been set then all samples are rejected so there is no point waiting for -// one. If we do have a sample then return NOERROR. We will only ever return -// VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample -// (calling GetState after either being stopped or Run will NOT return this) - -HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState) -{ - // Allow us to be paused when disconnected - - if (m_pInputPin->IsConnected() == FALSE) { - Ready(); - return S_OK; - } - - // Have we run off the end of stream - - if (IsEndOfStream() == TRUE) { - Ready(); - return S_OK; - } - - // Make sure we get fresh data after being stopped - - if (HaveCurrentSample() == TRUE) { - if (OldState != State_Stopped) { - Ready(); - return S_OK; - } - } - NotReady(); - return S_FALSE; -} - - -// When we stop the filter the things we do are:- - -// Decommit the allocator being used in the connection -// Release the source filter if it's waiting in Receive -// Cancel any advise link we set up with the clock -// Any end of stream signalled is now obsolete so reset -// Allow us to be stopped when we are not connected - -STDMETHODIMP CBaseRenderer::Stop() -{ - CAutoLock cRendererLock(&m_InterfaceLock); - - // Make sure there really is a state change - - if (m_State == State_Stopped) { - return NOERROR; - } - - // Is our input pin connected - - if (m_pInputPin->IsConnected() == FALSE) { - NOTE("Input pin is not connected"); - m_State = State_Stopped; - return NOERROR; - } - - CBaseFilter::Stop(); - - // If we are going into a stopped state then we must decommit whatever - // allocator we are using it so that any source filter waiting in the - // GetBuffer can be released and unlock themselves for a state change - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Decommit(); - } - - // Cancel any scheduled rendering - - SetRepaintStatus(TRUE); - StopStreaming(); - SourceThreadCanWait(FALSE); - ResetEndOfStream(); - CancelNotification(); - - // There should be no outstanding clock advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - - Ready(); - WaitForReceiveToComplete(); - m_bAbort = FALSE; - - return NOERROR; -} - - -// When we pause the filter the things we do are:- - -// Commit the allocator being used in the connection -// Allow a source filter thread to wait in Receive -// Cancel any clock advise link (we may be running) -// Possibly complete the state change if we have data -// Allow us to be paused when we are not connected - -STDMETHODIMP CBaseRenderer::Pause() -{ - CAutoLock cRendererLock(&m_InterfaceLock); - FILTER_STATE OldState = m_State; - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // Make sure there really is a state change - - if (m_State == State_Paused) { - return CompleteStateChange(State_Paused); - } - - // Has our input pin been connected - - if (m_pInputPin->IsConnected() == FALSE) { - NOTE("Input pin is not connected"); - m_State = State_Paused; - return CompleteStateChange(State_Paused); - } - - // Pause the base filter class - - HRESULT hr = CBaseFilter::Pause(); - if (FAILED(hr)) { - NOTE("Pause failed"); - return hr; - } - - // Enable EC_REPAINT events again - - SetRepaintStatus(TRUE); - StopStreaming(); - SourceThreadCanWait(TRUE); - CancelNotification(); - ResetEndOfStreamTimer(); - - // If we are going into a paused state then we must commit whatever - // allocator we are using it so that any source filter can call the - // GetBuffer and expect to get a buffer without returning an error - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Commit(); - } - - // There should be no outstanding advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // When we come out of a stopped state we must clear any image we were - // holding onto for frame refreshing. Since renderers see state changes - // first we can reset ourselves ready to accept the source thread data - // Paused or running after being stopped causes the current position to - // be reset so we're not interested in passing end of stream signals - - if (OldState == State_Stopped) { - m_bAbort = FALSE; - ClearPendingSample(); - } - return CompleteStateChange(OldState); -} - - -// When we run the filter the things we do are:- - -// Commit the allocator being used in the connection -// Allow a source filter thread to wait in Receive -// Signal the render event just to get us going -// Start the base class by calling StartStreaming -// Allow us to be run when we are not connected -// Signal EC_COMPLETE if we are not connected - -STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime) -{ - CAutoLock cRendererLock(&m_InterfaceLock); - FILTER_STATE OldState = m_State; - - // Make sure there really is a state change - - if (m_State == State_Running) { - return NOERROR; - } - - // Send EC_COMPLETE if we're not connected - - if (m_pInputPin->IsConnected() == FALSE) { - NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); - m_State = State_Running; - return NOERROR; - } - - Ready(); - - // Pause the base filter class - - HRESULT hr = CBaseFilter::Run(StartTime); - if (FAILED(hr)) { - NOTE("Run failed"); - return hr; - } - - // Allow the source thread to wait - ASSERT(m_pInputPin->IsFlushing() == FALSE); - SourceThreadCanWait(TRUE); - SetRepaintStatus(FALSE); - - // There should be no outstanding advise - ASSERT(CancelNotification() == S_FALSE); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(m_EndOfStreamTimer == 0); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - - // If we are going into a running state then we must commit whatever - // allocator we are using it so that any source filter can call the - // GetBuffer and expect to get a buffer without returning an error - - if (m_pInputPin->Allocator()) { - m_pInputPin->Allocator()->Commit(); - } - - // When we come out of a stopped state we must clear any image we were - // holding onto for frame refreshing. Since renderers see state changes - // first we can reset ourselves ready to accept the source thread data - // Paused or running after being stopped causes the current position to - // be reset so we're not interested in passing end of stream signals - - if (OldState == State_Stopped) { - m_bAbort = FALSE; - ClearPendingSample(); - } - return StartStreaming(); -} - - -// Return the number of input pins we support - -int CBaseRenderer::GetPinCount() -{ - if (m_pInputPin == NULL) { - // Try to create it - (void)GetPin(0); - } - return m_pInputPin != NULL ? 1 : 0; -} - - -// We only support one input pin and it is numbered zero - -CBasePin *CBaseRenderer::GetPin(int n) -{ - CAutoLock cObjectCreationLock(&m_ObjectCreationLock); - - // Should only ever be called with zero - ASSERT(n == 0); - - if (n != 0) { - return NULL; - } - - // Create the input pin if not already done so - - if (m_pInputPin == NULL) { - - // hr must be initialized to NOERROR because - // CRendererInputPin's constructor only changes - // hr's value if an error occurs. - HRESULT hr = NOERROR; - - m_pInputPin = new CRendererInputPin(this,&hr,L"In"); - if (NULL == m_pInputPin) { - return NULL; - } - - if (FAILED(hr)) { - delete m_pInputPin; - m_pInputPin = NULL; - return NULL; - } - } - return m_pInputPin; -} - - -// If "In" then return the IPin for our input pin, otherwise NULL and error - -STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - - if (0==lstrcmpW(Id,L"In")) { - *ppPin = GetPin(0); - if (*ppPin) { - (*ppPin)->AddRef(); - } else { - return E_OUTOFMEMORY; - } - } else { - *ppPin = NULL; - return VFW_E_NOT_FOUND; - } - return NOERROR; -} - - -// Called when the input pin receives an EndOfStream notification. If we have -// not got a sample, then notify EC_COMPLETE now. If we have samples, then set -// m_bEOS and check for this on completing samples. If we're waiting to pause -// then complete the transition to paused state by setting the state event - -HRESULT CBaseRenderer::EndOfStream() -{ - // Ignore these calls if we are stopped - - if (m_State == State_Stopped) { - return NOERROR; - } - - // If we have a sample then wait for it to be rendered - - m_bEOS = TRUE; - if (m_pMediaSample) { - return NOERROR; - } - - // If we are waiting for pause then we are now ready since we cannot now - // carry on waiting for a sample to arrive since we are being told there - // won't be any. This sets an event that the GetState function picks up - - Ready(); - - // Only signal completion now if we are running otherwise queue it until - // we do run in StartStreaming. This is used when we seek because a seek - // causes a pause where early notification of completion is misleading - - if (m_bStreaming) { - SendEndOfStream(); - } - return NOERROR; -} - - -// When we are told to flush we should release the source thread - -HRESULT CBaseRenderer::BeginFlush() -{ - // If paused then report state intermediate until we get some data - - if (m_State == State_Paused) { - NotReady(); - } - - SourceThreadCanWait(FALSE); - CancelNotification(); - ClearPendingSample(); - // Wait for Receive to complete - WaitForReceiveToComplete(); - - return NOERROR; -} - - -// After flushing the source thread can wait in Receive again - -HRESULT CBaseRenderer::EndFlush() -{ - // Reset the current sample media time - if (m_pPosition) m_pPosition->ResetMediaTime(); - - // There should be no outstanding advise - - ASSERT(CancelNotification() == S_FALSE); - SourceThreadCanWait(TRUE); - return NOERROR; -} - - -// We can now send EC_REPAINTs if so required - -HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin) -{ - // The caller should always hold the interface lock because - // the function uses CBaseFilter::m_State. - ASSERT(CritCheckIn(&m_InterfaceLock)); - - m_bAbort = FALSE; - - if (State_Running == GetRealState()) { - HRESULT hr = StartStreaming(); - if (FAILED(hr)) { - return hr; - } - - SetRepaintStatus(FALSE); - } else { - SetRepaintStatus(TRUE); - } - - return NOERROR; -} - - -// Called when we go paused or running - -HRESULT CBaseRenderer::Active() -{ - return NOERROR; -} - - -// Called when we go into a stopped state - -HRESULT CBaseRenderer::Inactive() -{ - if (m_pPosition) { - m_pPosition->ResetMediaTime(); - } - // People who derive from this may want to override this behaviour - // to keep hold of the sample in some circumstances - ClearPendingSample(); - - return NOERROR; -} - - -// Tell derived classes about the media type agreed - -HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt) -{ - return NOERROR; -} - - -// When we break the input pin connection we should reset the EOS flags. When -// we are asked for either IMediaPosition or IMediaSeeking we will create a -// CPosPassThru object to handles media time pass through. When we're handed -// samples we store (by calling CPosPassThru::RegisterMediaTime) their media -// times so we can then return a real current position of data being rendered - -HRESULT CBaseRenderer::BreakConnect() -{ - // Do we have a quality management sink - - if (m_pQSink) { - m_pQSink->Release(); - m_pQSink = NULL; - } - - // Check we have a valid connection - - if (m_pInputPin->IsConnected() == FALSE) { - return S_FALSE; - } - - // Check we are stopped before disconnecting - if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) { - return VFW_E_NOT_STOPPED; - } - - SetRepaintStatus(FALSE); - ResetEndOfStream(); - ClearPendingSample(); - m_bAbort = FALSE; - - if (State_Running == m_State) { - StopStreaming(); - } - - return NOERROR; -} - - -// Retrieves the sample times for this samples (note the sample times are -// passed in by reference not value). We return S_FALSE to say schedule this -// sample according to the times on the sample. We also return S_OK in -// which case the object should simply render the sample data immediately - -HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample, - __out REFERENCE_TIME *pStartTime, - __out REFERENCE_TIME *pEndTime) -{ - ASSERT(m_dwAdvise == 0); - ASSERT(pMediaSample); - - // If the stop time for this sample is before or the same as start time, - // then just ignore it (release it) and schedule the next one in line - // Source filters should always fill in the start and end times properly! - - if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) { - if (*pEndTime < *pStartTime) { - return VFW_E_START_TIME_AFTER_END; - } - } else { - // no time set in the sample... draw it now? - return S_OK; - } - - // Can't synchronise without a clock so we return S_OK which tells the - // caller that the sample should be rendered immediately without going - // through the overhead of setting a timer advise link with the clock - - if (m_pClock == NULL) { - return S_OK; - } - return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime); -} - - -// By default all samples are drawn according to their time stamps so we -// return S_FALSE. Returning S_OK means draw immediately, this is used -// by the derived video renderer class in its quality management. - -HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, - __out REFERENCE_TIME *ptrStart, - __out REFERENCE_TIME *ptrEnd) -{ - return S_FALSE; -} - - -// We must always reset the current advise time to zero after a timer fires -// because there are several possible ways which lead us not to do any more -// scheduling such as the pending image being cleared after state changes - -void CBaseRenderer::SignalTimerFired() -{ - m_dwAdvise = 0; -} - - -// Cancel any notification currently scheduled. This is called by the owning -// window object when it is told to stop streaming. If there is no timer link -// outstanding then calling this is benign otherwise we go ahead and cancel -// We must always reset the render event as the quality management code can -// signal immediate rendering by setting the event without setting an advise -// link. If we're subsequently stopped and run the first attempt to setup an -// advise link with the reference clock will find the event still signalled - -HRESULT CBaseRenderer::CancelNotification() -{ - ASSERT(m_dwAdvise == 0 || m_pClock); - DWORD_PTR dwAdvise = m_dwAdvise; - - // Have we a live advise link - - if (m_dwAdvise) { - m_pClock->Unadvise(m_dwAdvise); - SignalTimerFired(); - ASSERT(m_dwAdvise == 0); - } - - // Clear the event and return our status - - m_RenderEvent.Reset(); - return (dwAdvise ? S_OK : S_FALSE); -} - - -// Responsible for setting up one shot advise links with the clock -// Return FALSE if the sample is to be dropped (not drawn at all) -// Return TRUE if the sample is to be drawn and in this case also -// arrange for m_RenderEvent to be set at the appropriate time - -BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample) -{ - REFERENCE_TIME StartSample, EndSample; - - // Is someone pulling our leg - - if (pMediaSample == NULL) { - return FALSE; - } - - // Get the next sample due up for rendering. If there aren't any ready - // then GetNextSampleTimes returns an error. If there is one to be done - // then it succeeds and yields the sample times. If it is due now then - // it returns S_OK other if it's to be done when due it returns S_FALSE - - HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample); - if (FAILED(hr)) { - return FALSE; - } - - // If we don't have a reference clock then we cannot set up the advise - // time so we simply set the event indicating an image to render. This - // will cause us to run flat out without any timing or synchronisation - - if (hr == S_OK) { - EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent)); - return TRUE; - } - - ASSERT(m_dwAdvise == 0); - ASSERT(m_pClock); - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - - // We do have a valid reference clock interface so we can ask it to - // set an event when the image comes due for rendering. We pass in - // the reference time we were told to start at and also the current - // stream time which is the offset from the start reference time - - hr = m_pClock->AdviseTime( - (REFERENCE_TIME) m_tStart, // Start run time - StartSample, // Stream time - (HEVENT)(HANDLE) m_RenderEvent, // Render notification - &m_dwAdvise); // Advise cookie - - if (SUCCEEDED(hr)) { - return TRUE; - } - - // We could not schedule the next sample for rendering despite the fact - // we have a valid sample here. This is a fair indication that either - // the system clock is wrong or the time stamp for the sample is duff - - ASSERT(m_dwAdvise == 0); - return FALSE; -} - - -// This is called when a sample comes due for rendering. We pass the sample -// on to the derived class. After rendering we will initialise the timer for -// the next sample, NOTE signal that the last one fired first, if we don't -// do this it thinks there is still one outstanding that hasn't completed - -HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample) -{ - // If the media sample is NULL then we will have been notified by the - // clock that another sample is ready but in the mean time someone has - // stopped us streaming which causes the next sample to be released - - if (pMediaSample == NULL) { - return S_FALSE; - } - - // If we have stopped streaming then don't render any more samples, the - // thread that got in and locked us and then reset this flag does not - // clear the pending sample as we can use it to refresh any output device - - if (m_bStreaming == FALSE) { - return S_FALSE; - } - - // Time how long the rendering takes - - OnRenderStart(pMediaSample); - DoRenderSample(pMediaSample); - OnRenderEnd(pMediaSample); - - return NOERROR; -} - - -// Checks if there is a sample waiting at the renderer - -BOOL CBaseRenderer::HaveCurrentSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - return (m_pMediaSample == NULL ? FALSE : TRUE); -} - - -// Returns the current sample waiting at the video renderer. We AddRef the -// sample before returning so that should it come due for rendering the -// person who called this method will hold the remaining reference count -// that will stop the sample being added back onto the allocator free list - -IMediaSample *CBaseRenderer::GetCurrentSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_pMediaSample) { - m_pMediaSample->AddRef(); - } - return m_pMediaSample; -} - - -// Called when the source delivers us a sample. We go through a few checks to -// make sure the sample can be rendered. If we are running (streaming) then we -// have the sample scheduled with the reference clock, if we are not streaming -// then we have received an sample in paused mode so we can complete any state -// transition. On leaving this function everything will be unlocked so an app -// thread may get in and change our state to stopped (for example) in which -// case it will also signal the thread event so that our wait call is stopped - -HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample) -{ - CAutoLock cInterfaceLock(&m_InterfaceLock); - m_bInReceive = TRUE; - - // Check our flushing and filter state - - // This function must hold the interface lock because it calls - // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses - // CBasePin::m_bRunTimeError. - HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample); - - if (hr != NOERROR) { - m_bInReceive = FALSE; - return E_FAIL; - } - - // Has the type changed on a media sample. We do all rendering - // synchronously on the source thread, which has a side effect - // that only one buffer is ever outstanding. Therefore when we - // have Receive called we can go ahead and change the format - // Since the format change can cause a SendMessage we just don't - // lock - if (m_pInputPin->SampleProps()->pMediaType) { - hr = m_pInputPin->SetMediaType( - (CMediaType *)m_pInputPin->SampleProps()->pMediaType); - if (FAILED(hr)) { - m_bInReceive = FALSE; - return hr; - } - } - - - CAutoLock cSampleLock(&m_RendererLock); - - ASSERT(IsActive() == TRUE); - ASSERT(m_pInputPin->IsFlushing() == FALSE); - ASSERT(m_pInputPin->IsConnected() == TRUE); - ASSERT(m_pMediaSample == NULL); - - // Return an error if we already have a sample waiting for rendering - // source pins must serialise the Receive calls - we also check that - // no data is being sent after the source signalled an end of stream - - if (m_pMediaSample || m_bEOS || m_bAbort) { - Ready(); - m_bInReceive = FALSE; - return E_UNEXPECTED; - } - - // Store the media times from this sample - if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample); - - // Schedule the next sample if we are streaming - - if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) { - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(CancelNotification() == S_FALSE); - m_bInReceive = FALSE; - return VFW_E_SAMPLE_REJECTED; - } - - // Store the sample end time for EC_COMPLETE handling - m_SignalTime = m_pInputPin->SampleProps()->tStop; - - // BEWARE we sometimes keep the sample even after returning the thread to - // the source filter such as when we go into a stopped state (we keep it - // to refresh the device with) so we must AddRef it to keep it safely. If - // we start flushing the source thread is released and any sample waiting - // will be released otherwise GetBuffer may never return (see BeginFlush) - - m_pMediaSample = pMediaSample; - m_pMediaSample->AddRef(); - - if (m_bStreaming == FALSE) { - SetRepaintStatus(TRUE); - } - return NOERROR; -} - - -// Called by the source filter when we have a sample to render. Under normal -// circumstances we set an advise link with the clock, wait for the time to -// arrive and then render the data using the PURE virtual DoRenderSample that -// the derived class will have overriden. After rendering the sample we may -// also signal EOS if it was the last one sent before EndOfStream was called - -HRESULT CBaseRenderer::Receive(IMediaSample *pSample) -{ - ASSERT(pSample); - - // It may return VFW_E_SAMPLE_REJECTED code to say don't bother - - HRESULT hr = PrepareReceive(pSample); - ASSERT(m_bInReceive == SUCCEEDED(hr)); - if (FAILED(hr)) { - if (hr == VFW_E_SAMPLE_REJECTED) { - return NOERROR; - } - return hr; - } - - // We realize the palette in "PrepareRender()" so we have to give away the - // filter lock here. - if (m_State == State_Paused) { - PrepareRender(); - // no need to use InterlockedExchange - m_bInReceive = FALSE; - { - // We must hold both these locks - CAutoLock cRendererLock(&m_InterfaceLock); - if (m_State == State_Stopped) - return NOERROR; - - m_bInReceive = TRUE; - CAutoLock cSampleLock(&m_RendererLock); - OnReceiveFirstSample(pSample); - } - Ready(); - } - // Having set an advise link with the clock we sit and wait. We may be - // awoken by the clock firing or by a state change. The rendering call - // will lock the critical section and check we can still render the data - - hr = WaitForRenderTime(); - if (FAILED(hr)) { - m_bInReceive = FALSE; - return NOERROR; - } - - PrepareRender(); - - // Set this here and poll it until we work out the locking correctly - // It can't be right that the streaming stuff grabs the interface - // lock - after all we want to be able to wait for this stuff - // to complete - m_bInReceive = FALSE; - - // We must hold both these locks - CAutoLock cRendererLock(&m_InterfaceLock); - - // since we gave away the filter wide lock, the sate of the filter could - // have chnaged to Stopped - if (m_State == State_Stopped) - return NOERROR; - - CAutoLock cSampleLock(&m_RendererLock); - - // Deal with this sample - - Render(m_pMediaSample); - ClearPendingSample(); - SendEndOfStream(); - CancelNotification(); - return NOERROR; -} - - -// This is called when we stop or are inactivated to clear the pending sample -// We release the media sample interface so that they can be allocated to the -// source filter again, unless of course we are changing state to inactive in -// which case GetBuffer will return an error. We must also reset the current -// media sample to NULL so that we know we do not currently have an image - -HRESULT CBaseRenderer::ClearPendingSample() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_pMediaSample) { - m_pMediaSample->Release(); - m_pMediaSample = NULL; - } - return NOERROR; -} - - -// Used to signal end of stream according to the sample end time - -void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier - UINT uMsg, // Not currently used - DWORD_PTR dwUser,// User information - DWORD_PTR dw1, // Windows reserved - DWORD_PTR dw2) // is also reserved -{ - CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser; - NOTE1("EndOfStreamTimer called (%d)",uID); - pRenderer->TimerCallback(); -} - -// Do the timer callback work -void CBaseRenderer::TimerCallback() -{ - // Lock for synchronization (but don't hold this lock when calling - // timeKillEvent) - CAutoLock cRendererLock(&m_RendererLock); - - // See if we should signal end of stream now - - if (m_EndOfStreamTimer) { - m_EndOfStreamTimer = 0; - SendEndOfStream(); - } -} - - -// If we are at the end of the stream signal the filter graph but do not set -// the state flag back to FALSE. Once we drop off the end of the stream we -// leave the flag set (until a subsequent ResetEndOfStream). Each sample we -// get delivered will update m_SignalTime to be the last sample's end time. -// We must wait this long before signalling end of stream to the filtergraph - -#define TIMEOUT_DELIVERYWAIT 50 -#define TIMEOUT_RESOLUTION 10 - -HRESULT CBaseRenderer::SendEndOfStream() -{ - ASSERT(CritCheckIn(&m_RendererLock)); - if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) { - return NOERROR; - } - - // If there is no clock then signal immediately - if (m_pClock == NULL) { - return NotifyEndOfStream(); - } - - // How long into the future is the delivery time - - REFERENCE_TIME Signal = m_tStart + m_SignalTime; - REFERENCE_TIME CurrentTime; - m_pClock->GetTime(&CurrentTime); - LONG Delay = LONG((Signal - CurrentTime) / 10000); - - // Dump the timing information to the debugger - - NOTE1("Delay until end of stream delivery %d",Delay); - NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime)); - NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal)); - - // Wait for the delivery time to arrive - - if (Delay < TIMEOUT_DELIVERYWAIT) { - return NotifyEndOfStream(); - } - - // Signal a timer callback on another worker thread - - m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer - TIMEOUT_RESOLUTION, // Timer resolution - EndOfStreamTimer, // Callback function - DWORD_PTR(this), // Used information - TIME_ONESHOT); // Type of callback - if (m_EndOfStreamTimer == 0) { - return NotifyEndOfStream(); - } - return NOERROR; -} - - -// Signals EC_COMPLETE to the filtergraph manager - -HRESULT CBaseRenderer::NotifyEndOfStream() -{ - CAutoLock cRendererLock(&m_RendererLock); - ASSERT(m_bEOSDelivered == FALSE); - ASSERT(m_EndOfStreamTimer == 0); - - // Has the filter changed state - - if (m_bStreaming == FALSE) { - ASSERT(m_EndOfStreamTimer == 0); - return NOERROR; - } - - // Reset the end of stream timer - m_EndOfStreamTimer = 0; - - // If we've been using the IMediaPosition interface, set it's start - // and end media "times" to the stop position by hand. This ensures - // that we actually get to the end, even if the MPEG guestimate has - // been bad or if the quality management dropped the last few frames - - if (m_pPosition) m_pPosition->EOS(); - m_bEOSDelivered = TRUE; - NOTE("Sending EC_COMPLETE..."); - return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); -} - - -// Reset the end of stream flag, this is typically called when we transfer to -// stopped states since that resets the current position back to the start so -// we will receive more samples or another EndOfStream if there aren't any. We -// keep two separate flags one to say we have run off the end of the stream -// (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE -// to the filter graph. We need the latter otherwise we can end up sending an -// EC_COMPLETE every time the source changes state and calls our EndOfStream - -HRESULT CBaseRenderer::ResetEndOfStream() -{ - ResetEndOfStreamTimer(); - CAutoLock cRendererLock(&m_RendererLock); - - m_bEOS = FALSE; - m_bEOSDelivered = FALSE; - m_SignalTime = 0; - - return NOERROR; -} - - -// Kills any outstanding end of stream timer - -void CBaseRenderer::ResetEndOfStreamTimer() -{ - ASSERT(CritCheckOut(&m_RendererLock)); - if (m_EndOfStreamTimer) { - timeKillEvent(m_EndOfStreamTimer); - m_EndOfStreamTimer = 0; - } -} - - -// This is called when we start running so that we can schedule any pending -// image we have with the clock and display any timing information. If we -// don't have any sample but we have queued an EOS flag then we send it. If -// we do have a sample then we wait until that has been rendered before we -// signal the filter graph otherwise we may change state before it's done - -HRESULT CBaseRenderer::StartStreaming() -{ - CAutoLock cRendererLock(&m_RendererLock); - if (m_bStreaming == TRUE) { - return NOERROR; - } - - // Reset the streaming times ready for running - - m_bStreaming = TRUE; - - timeBeginPeriod(1); - OnStartStreaming(); - - // There should be no outstanding advise - ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); - ASSERT(CancelNotification() == S_FALSE); - - // If we have an EOS and no data then deliver it now - - if (m_pMediaSample == NULL) { - return SendEndOfStream(); - } - - // Have the data rendered - - ASSERT(m_pMediaSample); - if (!ScheduleSample(m_pMediaSample)) - m_RenderEvent.Set(); - - return NOERROR; -} - - -// This is called when we stop streaming so that we can set our internal flag -// indicating we are not now to schedule any more samples arriving. The state -// change methods in the filter implementation take care of cancelling any -// clock advise link we have set up and clearing any pending sample we have - -HRESULT CBaseRenderer::StopStreaming() -{ - CAutoLock cRendererLock(&m_RendererLock); - m_bEOSDelivered = FALSE; - - if (m_bStreaming == TRUE) { - m_bStreaming = FALSE; - OnStopStreaming(); - timeEndPeriod(1); - } - return NOERROR; -} - - -// We have a boolean flag that is reset when we have signalled EC_REPAINT to -// the filter graph. We set this when we receive an image so that should any -// conditions arise again we can send another one. By having a flag we ensure -// we don't flood the filter graph with redundant calls. We do not set the -// event when we receive an EndOfStream call since there is no point in us -// sending further EC_REPAINTs. In particular the AutoShowWindow method and -// the DirectDraw object use this method to control the window repainting - -void CBaseRenderer::SetRepaintStatus(BOOL bRepaint) -{ - CAutoLock cSampleLock(&m_RendererLock); - m_bRepaintStatus = bRepaint; -} - - -// Pass the window handle to the upstream filter - -void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd) -{ - IMediaEventSink *pSink; - - // Does the pin support IMediaEventSink - HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink); - if (SUCCEEDED(hr)) { - pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); - pSink->Release(); - } - NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); -} - - -// Signal an EC_REPAINT to the filter graph. This can be used to have data -// sent to us. For example when a video window is first displayed it may -// not have an image to display, at which point it signals EC_REPAINT. The -// filtergraph will either pause the graph if stopped or if already paused -// it will call put_CurrentPosition of the current position. Setting the -// current position to itself has the stream flushed and the image resent - -#define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_))); - -void CBaseRenderer::SendRepaint() -{ - CAutoLock cSampleLock(&m_RendererLock); - ASSERT(m_pInputPin); - - // We should not send repaint notifications when... - // - An end of stream has been notified - // - Our input pin is being flushed - // - The input pin is not connected - // - We have aborted a video playback - // - There is a repaint already sent - - if (m_bAbort == FALSE) { - if (m_pInputPin->IsConnected() == TRUE) { - if (m_pInputPin->IsFlushing() == FALSE) { - if (IsEndOfStream() == FALSE) { - if (m_bRepaintStatus == TRUE) { - IPin *pPin = (IPin *) m_pInputPin; - NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0); - SetRepaintStatus(FALSE); - RLOG("Sending repaint"); - } - } - } - } - } -} - - -// When a video window detects a display change (WM_DISPLAYCHANGE message) it -// can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The -// filtergraph will stop everyone and reconnect our input pin. As we're then -// reconnected we can accept the media type that matches the new display mode -// since we may no longer be able to draw the current image type efficiently - -BOOL CBaseRenderer::OnDisplayChange() -{ - // Ignore if we are not connected yet - - CAutoLock cSampleLock(&m_RendererLock); - if (m_pInputPin->IsConnected() == FALSE) { - return FALSE; - } - - RLOG("Notification of EC_DISPLAY_CHANGE"); - - // Pass our input pin as parameter on the event - - IPin *pPin = (IPin *) m_pInputPin; - m_pInputPin->AddRef(); - NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0); - SetAbortSignal(TRUE); - ClearPendingSample(); - m_pInputPin->Release(); - - return TRUE; -} - - -// Called just before we start drawing. -// Store the current time in m_trRenderStart to allow the rendering time to be -// logged. Log the time stamp of the sample and how late it is (neg is early) - -void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample) -{ -#ifdef PERF - REFERENCE_TIME trStart, trEnd; - pMediaSample->GetTime(&trStart, &trEnd); - - MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits - - m_pClock->GetTime(&m_trRenderStart); - MSR_INTEGER(0, (int)m_trRenderStart); - REFERENCE_TIME trStream; - trStream = m_trRenderStart-m_tStart; // convert reftime to stream time - MSR_INTEGER(0,(int)trStream); - - const int trLate = (int)(trStream - trStart); - MSR_INTEGER(m_idBaseAccuracy, trLate/10000); // dump in mSec -#endif - -} // OnRenderStart - - -// Called directly after drawing an image. -// calculate the time spent drawing and log it. - -void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample) -{ -#ifdef PERF - REFERENCE_TIME trNow; - m_pClock->GetTime(&trNow); - MSR_INTEGER(0,(int)trNow); - int t = (int)((trNow - m_trRenderStart)/10000); // convert UNITS->msec - MSR_INTEGER(m_idBaseRenderTime, t); -#endif -} // OnRenderEnd - - - - -// Constructor must be passed the base renderer object - -CRendererInputPin::CRendererInputPin(__inout CBaseRenderer *pRenderer, - __inout HRESULT *phr, - __in_opt LPCWSTR pPinName) : - CBaseInputPin(NAME("Renderer pin"), - pRenderer, - &pRenderer->m_InterfaceLock, - (HRESULT *) phr, - pPinName) -{ - m_pRenderer = pRenderer; - ASSERT(m_pRenderer); -} - - -// Signals end of data stream on the input pin - -STDMETHODIMP CRendererInputPin::EndOfStream() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - - // Make sure we're streaming ok - - HRESULT hr = CheckStreaming(); - if (hr != NOERROR) { - return hr; - } - - // Pass it onto the renderer - - hr = m_pRenderer->EndOfStream(); - if (SUCCEEDED(hr)) { - hr = CBaseInputPin::EndOfStream(); - } - return hr; -} - - -// Signals start of flushing on the input pin - we do the final reset end of -// stream with the renderer lock unlocked but with the interface lock locked -// We must do this because we call timeKillEvent, our timer callback method -// has to take the renderer lock to serialise our state. Therefore holding a -// renderer lock when calling timeKillEvent could cause a deadlock condition - -STDMETHODIMP CRendererInputPin::BeginFlush() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - { - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - CBaseInputPin::BeginFlush(); - m_pRenderer->BeginFlush(); - } - return m_pRenderer->ResetEndOfStream(); -} - - -// Signals end of flushing on the input pin - -STDMETHODIMP CRendererInputPin::EndFlush() -{ - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); - - HRESULT hr = m_pRenderer->EndFlush(); - if (SUCCEEDED(hr)) { - hr = CBaseInputPin::EndFlush(); - } - return hr; -} - - -// Pass the sample straight through to the renderer object - -STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample) -{ - HRESULT hr = m_pRenderer->Receive(pSample); - if (FAILED(hr)) { - - // A deadlock could occur if the caller holds the renderer lock and - // attempts to acquire the interface lock. - ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock)); - - { - // The interface lock must be held when the filter is calling - // IsStopped() or IsFlushing(). The interface lock must also - // be held because the function uses m_bRunTimeError. - CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); - - // We do not report errors which occur while the filter is stopping, - // flushing or if the m_bAbort flag is set . Errors are expected to - // occur during these operations and the streaming thread correctly - // handles the errors. - if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) { - - // EC_ERRORABORT's first parameter is the error which caused - // the event and its' last parameter is 0. See the Direct - // Show SDK documentation for more information. - m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0); - - { - CAutoLock alRendererLock(&m_pRenderer->m_RendererLock); - if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) { - m_pRenderer->NotifyEndOfStream(); - } - } - - m_bRunTimeError = TRUE; - } - } - } - - return hr; -} - - -// Called when the input pin is disconnected - -HRESULT CRendererInputPin::BreakConnect() -{ - HRESULT hr = m_pRenderer->BreakConnect(); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::BreakConnect(); -} - - -// Called when the input pin is connected - -HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CompleteConnect(pReceivePin); -} - - -// Give the pin id of our one and only pin - -STDMETHODIMP CRendererInputPin::QueryId(__deref_out LPWSTR *Id) -{ - CheckPointer(Id,E_POINTER); - - const WCHAR szIn[] = L"In"; - - *Id = (LPWSTR)CoTaskMemAlloc(sizeof(szIn)); - if (*Id == NULL) { - return E_OUTOFMEMORY; - } - CopyMemory(*Id, szIn, sizeof(szIn)); - return NOERROR; -} - - -// Will the filter accept this media type - -HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt) -{ - return m_pRenderer->CheckMediaType(pmt); -} - - -// Called when we go paused or running - -HRESULT CRendererInputPin::Active() -{ - return m_pRenderer->Active(); -} - - -// Called when we go into a stopped state - -HRESULT CRendererInputPin::Inactive() -{ - // The caller must hold the interface lock because - // this function uses m_bRunTimeError. - ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock)); - - m_bRunTimeError = FALSE; - - return m_pRenderer->Inactive(); -} - - -// Tell derived classes about the media type agreed - -HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt) -{ - HRESULT hr = CBaseInputPin::SetMediaType(pmt); - if (FAILED(hr)) { - return hr; - } - return m_pRenderer->SetMediaType(pmt); -} - - -// We do not keep an event object to use when setting up a timer link with -// the clock but are given a pointer to one by the owning object through the -// SetNotificationObject method - this must be initialised before starting -// We can override the default quality management process to have it always -// draw late frames, this is currently done by having the following registry -// key (actually an INI key) called DrawLateFrames set to 1 (default is 0) - -const TCHAR AMQUALITY[] = TEXT("ActiveMovie"); -const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames"); - -CBaseVideoRenderer::CBaseVideoRenderer( - REFCLSID RenderClass, // CLSID for this renderer - __in_opt LPCTSTR pName, // Debug ONLY description - __inout_opt LPUNKNOWN pUnk, // Aggregated owner object - __inout HRESULT *phr) : // General OLE return code - - CBaseRenderer(RenderClass,pName,pUnk,phr), - m_cFramesDropped(0), - m_cFramesDrawn(0), - m_bSupplierHandlingQuality(FALSE) -{ - ResetStreamingTimes(); - -#ifdef PERF - m_idTimeStamp = MSR_REGISTER(TEXT("Frame time stamp")); - m_idEarliness = MSR_REGISTER(TEXT("Earliness fudge")); - m_idTarget = MSR_REGISTER(TEXT("Target (mSec)")); - m_idSchLateTime = MSR_REGISTER(TEXT("mSec late when scheduled")); - m_idDecision = MSR_REGISTER(TEXT("Scheduler decision code")); - m_idQualityRate = MSR_REGISTER(TEXT("Quality rate sent")); - m_idQualityTime = MSR_REGISTER(TEXT("Quality time sent")); - m_idWaitReal = MSR_REGISTER(TEXT("Render wait")); - // m_idWait = MSR_REGISTER(TEXT("wait time recorded (msec)")); - m_idFrameAccuracy = MSR_REGISTER(TEXT("Frame accuracy (msecs)")); - m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE); - //m_idSendQuality = MSR_REGISTER(TEXT("Processing Quality message")); - - m_idRenderAvg = MSR_REGISTER(TEXT("Render draw time Avg")); - m_idFrameAvg = MSR_REGISTER(TEXT("FrameAvg")); - m_idWaitAvg = MSR_REGISTER(TEXT("WaitAvg")); - m_idDuration = MSR_REGISTER(TEXT("Duration")); - m_idThrottle = MSR_REGISTER(TEXT("Audio-video throttle wait")); - // m_idDebug = MSR_REGISTER(TEXT("Debug stuff")); -#endif // PERF -} // Constructor - - -// Destructor is just a placeholder - -CBaseVideoRenderer::~CBaseVideoRenderer() -{ - ASSERT(m_dwAdvise == 0); -} - - -// The timing functions in this class are called by the window object and by -// the renderer's allocator. -// The windows object calls timing functions as it receives media sample -// images for drawing using GDI. -// The allocator calls timing functions when it starts passing DCI/DirectDraw -// surfaces which are not rendered in the same way; The decompressor writes -// directly to the surface with no separate rendering, so those code paths -// call direct into us. Since we only ever hand out DCI/DirectDraw surfaces -// when we have allocated one and only one image we know there cannot be any -// conflict between the two. -// -// We use timeGetTime to return the timing counts we use (since it's relative -// performance we are interested in rather than absolute compared to a clock) -// The window object sets the accuracy of the system clock (normally 1ms) by -// calling timeBeginPeriod/timeEndPeriod when it changes streaming states - - -// Reset all times controlling streaming. -// Set them so that -// 1. Frames will not initially be dropped -// 2. The first frame will definitely be drawn (achieved by saying that there -// has not ben a frame drawn for a long time). - -HRESULT CBaseVideoRenderer::ResetStreamingTimes() -{ - m_trLastDraw = -1000; // set up as first frame since ages (1 sec) ago - m_tStreamingStart = timeGetTime(); - m_trRenderAvg = 0; - m_trFrameAvg = -1; // -1000 fps == "unset" - m_trDuration = 0; // 0 - strange value - m_trRenderLast = 0; - m_trWaitAvg = 0; - m_tRenderStart = 0; - m_cFramesDrawn = 0; - m_cFramesDropped = 0; - m_iTotAcc = 0; - m_iSumSqAcc = 0; - m_iSumSqFrameTime = 0; - m_trFrame = 0; // hygeine - not really needed - m_trLate = 0; // hygeine - not really needed - m_iSumFrameTime = 0; - m_nNormal = 0; - m_trEarliness = 0; - m_trTarget = -300000; // 30mSec early - m_trThrottle = 0; - m_trRememberStampForPerf = 0; - -#ifdef PERF - m_trRememberFrameForPerf = 0; -#endif - - return NOERROR; -} // ResetStreamingTimes - - -// Reset all times controlling streaming. Note that we're now streaming. We -// don't need to set the rendering event to have the source filter released -// as it is done during the Run processing. When we are run we immediately -// release the source filter thread and draw any image waiting (that image -// may already have been drawn once as a poster frame while we were paused) - -HRESULT CBaseVideoRenderer::OnStartStreaming() -{ - ResetStreamingTimes(); - return NOERROR; -} // OnStartStreaming - - -// Called at end of streaming. Fixes times for property page report - -HRESULT CBaseVideoRenderer::OnStopStreaming() -{ - m_tStreamingStart = timeGetTime()-m_tStreamingStart; - return NOERROR; -} // OnStopStreaming - - -// Called when we start waiting for a rendering event. -// Used to update times spent waiting and not waiting. - -void CBaseVideoRenderer::OnWaitStart() -{ - MSR_START(m_idWaitReal); -} // OnWaitStart - - -// Called when we are awoken from the wait in the window OR by our allocator -// when it is hanging around until the next sample is due for rendering on a -// DCI/DirectDraw surface. We add the wait time into our rolling average. -// We grab the interface lock so that we're serialised with the application -// thread going through the run code - which in due course ends up calling -// ResetStreaming times - possibly as we run through this section of code - -void CBaseVideoRenderer::OnWaitEnd() -{ -#ifdef PERF - MSR_STOP(m_idWaitReal); - // for a perf build we want to know just exactly how late we REALLY are. - // even if this means that we have to look at the clock again. - - REFERENCE_TIME trRealStream; // the real time now expressed as stream time. -#if 0 - m_pClock->GetTime(&trRealStream); // Calling clock here causes W95 deadlock! -#else - // We will be discarding overflows like mad here! - // This is wrong really because timeGetTime() can wrap but it's - // only for PERF - REFERENCE_TIME tr = timeGetTime()*10000; - trRealStream = tr + m_llTimeOffset; -#endif - trRealStream -= m_tStart; // convert to stream time (this is a reftime) - - if (m_trRememberStampForPerf==0) { - // This is probably the poster frame at the start, and it is not scheduled - // in the usual way at all. Just count it. The rememberstamp gets set - // in ShouldDrawSampleNow, so this does invalid frame recording until we - // actually start playing. - PreparePerformanceData(0, 0); - } else { - int trLate = (int)(trRealStream - m_trRememberStampForPerf); - int trFrame = (int)(tr - m_trRememberFrameForPerf); - PreparePerformanceData(trLate, trFrame); - } - m_trRememberFrameForPerf = tr; -#endif //PERF -} // OnWaitEnd - - -// Put data on one side that describes the lateness of the current frame. -// We don't yet know whether it will actually be drawn. In direct draw mode, -// this decision is up to the filter upstream, and it could change its mind. -// The rules say that if it did draw it must call Receive(). One way or -// another we eventually get into either OnRenderStart or OnDirectRender and -// these both call RecordFrameLateness to update the statistics. - -void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame) -{ - m_trLate = trLate; - m_trFrame = trFrame; -} // PreparePerformanceData - - -// update the statistics: -// m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn -// Note that because the properties page reports using these variables, -// 1. We need to be inside a critical section -// 2. They must all be updated together. Updating the sums here and the count -// elsewhere can result in imaginary jitter (i.e. attempts to find square roots -// of negative numbers) in the property page code. - -void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame) -{ - // Record how timely we are. - int tLate = trLate/10000; - - // Best estimate of moment of appearing on the screen is average of - // start and end draw times. Here we have only the end time. This may - // tend to show us as spuriously late by up to 1/2 frame rate achieved. - // Decoder probably monitors draw time. We don't bother. - MSR_INTEGER( m_idFrameAccuracy, tLate ); - - // This is a kludge - we can get frames that are very late - // especially (at start-up) and they invalidate the statistics. - // So ignore things that are more than 1 sec off. - if (tLate>1000 || tLate<-1000) { - if (m_cFramesDrawn<=1) { - tLate = 0; - } else if (tLate>0) { - tLate = 1000; - } else { - tLate = -1000; - } - } - // The very first frame often has a invalid time, so don't - // count it into the statistics. (???) - if (m_cFramesDrawn>1) { - m_iTotAcc += tLate; - m_iSumSqAcc += (tLate*tLate); - } - - // calculate inter-frame time. Doesn't make sense for first frame - // second frame suffers from invalid first frame stamp. - if (m_cFramesDrawn>2) { - int tFrame = trFrame/10000; // convert to mSec else it overflows - - // This is a kludge. It can overflow anyway (a pause can cause - // a very long inter-frame time) and it overflows at 2**31/10**7 - // or about 215 seconds i.e. 3min 35sec - if (tFrame>1000||tFrame<0) tFrame = 1000; - m_iSumSqFrameTime += tFrame*tFrame; - ASSERT(m_iSumSqFrameTime>=0); - m_iSumFrameTime += tFrame; - } - ++m_cFramesDrawn; - -} // RecordFrameLateness - - -void CBaseVideoRenderer::ThrottleWait() -{ - if (m_trThrottle>0) { - int iThrottle = m_trThrottle/10000; // convert to mSec - MSR_INTEGER( m_idThrottle, iThrottle); - DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle)); - Sleep(iThrottle); - } else { - Sleep(0); - } -} // ThrottleWait - - -// Whenever a frame is rendered it goes though either OnRenderStart -// or OnDirectRender. Data that are generated during ShouldDrawSample -// are added to the statistics by calling RecordFrameLateness from both -// these two places. - -// Called in place of OnRenderStart..OnRenderEnd -// When a DirectDraw image is drawn -void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample) -{ - m_trRenderAvg = 0; - m_trRenderLast = 5000000; // If we mode switch, we do NOT want this - // to inhibit the new average getting going! - // so we set it to half a second - // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); - RecordFrameLateness(m_trLate, m_trFrame); - ThrottleWait(); -} // OnDirectRender - - -// Called just before we start drawing. All we do is to get the current clock -// time (from the system) and return. We have to store the start render time -// in a member variable because it isn't used until we complete the drawing -// The rest is just performance logging. - -void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample) -{ - RecordFrameLateness(m_trLate, m_trFrame); - m_tRenderStart = timeGetTime(); -} // OnRenderStart - - -// Called directly after drawing an image. We calculate the time spent in the -// drawing code and if this doesn't appear to have any odd looking spikes in -// it then we add it to the current average draw time. Measurement spikes may -// occur if the drawing thread is interrupted and switched to somewhere else. - -void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample) -{ - // The renderer time can vary erratically if we are interrupted so we do - // some smoothing to help get more sensible figures out but even that is - // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83 - - int tr = (timeGetTime() - m_tRenderStart)*10000; // convert mSec->UNITS - if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) { - // DO_MOVING_AVG(m_trRenderAvg, tr); - m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD; - } - m_trRenderLast = tr; - ThrottleWait(); -} // OnRenderEnd - - -STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc) -{ - - m_pQSink = piqc; - - return NOERROR; -} // SetSink - - -STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q) -{ - // NOTE: We are NOT getting any locks here. We could be called - // asynchronously and possibly even on a time critical thread of - // someone else's - so we do the minumum. We only set one state - // variable (an integer) and if that happens to be in the middle - // of another thread reading it they will just get either the new - // or the old value. Locking would achieve no more than this. - - // It might be nice to check that we are being called from m_pGraph, but - // it turns out to be a millisecond or so per throw! - - // This is heuristics, these numbers are aimed at being "what works" - // rather than anything based on some theory. - // We use a hyperbola because it's easy to calculate and it includes - // a panic button asymptote (which we push off just to the left) - // The throttling fits the following table (roughly) - // Proportion Throttle (msec) - // >=1000 0 - // 900 3 - // 800 7 - // 700 11 - // 600 17 - // 500 25 - // 400 35 - // 300 50 - // 200 72 - // 125 100 - // 100 112 - // 50 146 - // 0 200 - - // (some evidence that we could go for a sharper kink - e.g. no throttling - // until below the 750 mark - might give fractionally more frames on a - // P60-ish machine). The easy way to get these coefficients is to use - // Renbase.xls follow the instructions therein using excel solver. - - if (q.Proportion>=1000) { m_trThrottle = 0; } - else { - // The DWORD is to make quite sure I get unsigned arithmetic - // as the constant is between 2**31 and 2**32 - m_trThrottle = -330000 + (388880000/(q.Proportion+167)); - } - return NOERROR; -} // Notify - - -// Send a message to indicate what our supplier should do about quality. -// Theory: -// What a supplier wants to know is "is the frame I'm working on NOW -// going to be late?". -// F1 is the frame at the supplier (as above) -// Tf1 is the due time for F1 -// T1 is the time at that point (NOW!) -// Tr1 is the time that f1 WILL actually be rendered -// L1 is the latency of the graph for frame F1 = Tr1-T1 -// D1 (for delay) is how late F1 will be beyond its due time i.e. -// D1 = (Tr1-Tf1) which is what the supplier really wants to know. -// Unfortunately Tr1 is in the future and is unknown, so is L1 -// -// We could estimate L1 by its value for a previous frame, -// L0 = Tr0-T0 and work off -// D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1) -// Rearranging terms: -// D1' = (T1-T0) + (Tr0-Tf1) -// adding (Tf0-Tf0) and rearranging again: -// = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1) -// = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0) -// But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the -// Late field in the quality message that we send. -// The other two terms just state what correction should be applied before -// using the lateness of F0 to predict the lateness of F1. -// (T1-T0) says how much time has actually passed (we have lost this much) -// (Tf1-Tf0) says how much time should have passed if we were keeping pace -// (we have gained this much). -// -// Suppliers should therefore work off: -// Quality.Late + (T1-T0) - (Tf1-Tf0) -// and see if this is "acceptably late" or even early (i.e. negative). -// They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from -// the time stamps in the frames. They get Quality.Late from us. -// - -HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate, - REFERENCE_TIME trRealStream) -{ - Quality q; - HRESULT hr; - - // If we are the main user of time, then report this as Flood/Dry. - // If our suppliers are, then report it as Famine/Glut. - // - // We need to take action, but avoid hunting. Hunting is caused by - // 1. Taking too much action too soon and overshooting - // 2. Taking too long to react (so averaging can CAUSE hunting). - // - // The reason why we use trLate as well as Wait is to reduce hunting; - // if the wait time is coming down and about to go into the red, we do - // NOT want to rely on some average which is only telling is that it used - // to be OK once. - - q.TimeStamp = (REFERENCE_TIME)trRealStream; - - if (m_trFrameAvg<0) { - q.Type = Famine; // guess - } - // Is the greater part of the time taken bltting or something else - else if (m_trFrameAvg > 2*m_trRenderAvg) { - q.Type = Famine; // mainly other - } else { - q.Type = Flood; // mainly bltting - } - - q.Proportion = 1000; // default - - if (m_trFrameAvg<0) { - // leave it alone - we don't know enough - } - else if ( trLate> 0 ) { - // try to catch up over the next second - // We could be Really, REALLY late, but rendering all the frames - // anyway, just because it's so cheap. - - q.Proportion = 1000 - (int)((trLate)/(UNITS/1000)); - if (q.Proportion<500) { - q.Proportion = 500; // don't go daft. (could've been negative!) - } else { - } - - } else if ( m_trWaitAvg>20000 - && trLate<-20000 - ){ - // Go cautiously faster - aim at 2mSec wait. - if (m_trWaitAvg>=m_trFrameAvg) { - // This can happen because of some fudges. - // The waitAvg is how long we originally planned to wait - // The frameAvg is more honest. - // It means that we are spending a LOT of time waiting - q.Proportion = 2000; // double. - } else { - if (m_trFrameAvg+20000 > m_trWaitAvg) { - q.Proportion - = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg)); - } else { - // We're apparently spending more than the whole frame time waiting. - // Assume that the averages are slightly out of kilter, but that we - // are indeed doing a lot of waiting. (This leg probably never - // happens, but the code avoids any potential divide by zero). - q.Proportion = 2000; - } - } - - if (q.Proportion>2000) { - q.Proportion = 2000; // don't go crazy. - } - } - - // Tell the supplier how late frames are when they get rendered - // That's how late we are now. - // If we are in directdraw mode then the guy upstream can see the drawing - // times and we'll just report on the start time. He can figure out any - // offset to apply. If we are in DIB Section mode then we will apply an - // extra offset which is half of our drawing time. This is usually small - // but can sometimes be the dominant effect. For this we will use the - // average drawing time rather than the last frame. If the last frame took - // a long time to draw and made us late, that's already in the lateness - // figure. We should not add it in again unless we expect the next frame - // to be the same. We don't, we expect the average to be a better shot. - // In direct draw mode the RenderAvg will be zero. - - q.Late = trLate + m_trRenderAvg/2; - - // log what we're doing - MSR_INTEGER(m_idQualityRate, q.Proportion); - MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 ); - - // A specific sink interface may be set through IPin - - if (m_pQSink==NULL) { - // Get our input pin's peer. We send quality management messages - // to any nominated receiver of these things (set in the IPin - // interface), or else to our source filter. - - IQualityControl *pQC = NULL; - IPin *pOutputPin = m_pInputPin->GetConnected(); - ASSERT(pOutputPin != NULL); - - // And get an AddRef'd quality control interface - - hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC); - if (SUCCEEDED(hr)) { - m_pQSink = pQC; - } - } - if (m_pQSink) { - return m_pQSink->Notify(this,q); - } - - return S_FALSE; - -} // SendQuality - - -// We are called with a valid IMediaSample image to decide whether this is to -// be drawn or not. There must be a reference clock in operation. -// Return S_OK if it is to be drawn Now (as soon as possible) -// Return S_FALSE if it is to be drawn when it's due -// Return an error if we want to drop it -// m_nNormal=-1 indicates that we dropped the previous frame and so this -// one should be drawn early. Respect it and update it. -// Use current stream time plus a number of heuristics (detailed below) -// to make the decision - -HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, - __inout REFERENCE_TIME *ptrStart, - __inout REFERENCE_TIME *ptrEnd) -{ - - // Don't call us unless there's a clock interface to synchronise with - ASSERT(m_pClock); - - MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32)); // high order 32 bits - MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart)); // low order 32 bits - - // We lose a bit of time depending on the monitor type waiting for the next - // screen refresh. On average this might be about 8mSec - so it will be - // later than we think when the picture appears. To compensate a bit - // we bias the media samples by -8mSec i.e. 80000 UNITs. - // We don't ever make a stream time negative (call it paranoia) - if (*ptrStart>=80000) { - *ptrStart -= 80000; - *ptrEnd -= 80000; // bias stop to to retain valid frame duration - } - - // Cache the time stamp now. We will want to compare what we did with what - // we started with (after making the monitor allowance). - m_trRememberStampForPerf = *ptrStart; - - // Get reference times (current and late) - REFERENCE_TIME trRealStream; // the real time now expressed as stream time. - m_pClock->GetTime(&trRealStream); -#ifdef PERF - // While the reference clock is expensive: - // Remember the offset from timeGetTime and use that. - // This overflows all over the place, but when we subtract to get - // differences the overflows all cancel out. - m_llTimeOffset = trRealStream-timeGetTime()*10000; -#endif - trRealStream -= m_tStart; // convert to stream time (this is a reftime) - - // We have to wory about two versions of "lateness". The truth, which we - // try to work out here and the one measured against m_trTarget which - // includes long term feedback. We report statistics against the truth - // but for operational decisions we work to the target. - // We use TimeDiff to make sure we get an integer because we - // may actually be late (or more likely early if there is a big time - // gap) by a very long time. - const int trTrueLate = TimeDiff(trRealStream - *ptrStart); - const int trLate = trTrueLate; - - MSR_INTEGER(m_idSchLateTime, trTrueLate/10000); - - // Send quality control messages upstream, measured against target - HRESULT hr = SendQuality(trLate, trRealStream); - // Note: the filter upstream is allowed to this FAIL meaning "you do it". - m_bSupplierHandlingQuality = (hr==S_OK); - - // Decision time! Do we drop, draw when ready or draw immediately? - - const int trDuration = (int)(*ptrEnd - *ptrStart); - { - // We need to see if the frame rate of the file has just changed. - // This would make comparing our previous frame rate with the current - // frame rate inefficent. Hang on a moment though. I've seen files - // where the frames vary between 33 and 34 mSec so as to average - // 30fps. A minor variation like that won't hurt us. - int t = m_trDuration/32; - if ( trDuration > m_trDuration+t - || trDuration < m_trDuration-t - ) { - // There's a major variation. Reset the average frame rate to - // exactly the current rate to disable decision 9002 for this frame, - // and remember the new rate. - m_trFrameAvg = trDuration; - m_trDuration = trDuration; - } - } - - MSR_INTEGER(m_idEarliness, m_trEarliness/10000); - MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); - MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000); - MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000); - MSR_INTEGER(m_idDuration, trDuration/10000); - -#ifdef PERF - if (S_OK==pMediaSample->IsDiscontinuity()) { - MSR_INTEGER(m_idDecision, 9000); - } -#endif - - // Control the graceful slide back from slow to fast machine mode. - // After a frame drop accept an early frame and set the earliness to here - // If this frame is already later than the earliness then slide it to here - // otherwise do the standard slide (reduce by about 12% per frame). - // Note: earliness is normally NEGATIVE - BOOL bJustDroppedFrame - = ( m_bSupplierHandlingQuality - // Can't use the pin sample properties because we might - // not be in Receive when we call this - && (S_OK == pMediaSample->IsDiscontinuity()) // he just dropped one - ) - || (m_nNormal==-1); // we just dropped one - - - // Set m_trEarliness (slide back from slow to fast machine mode) - if (trLate>0) { - m_trEarliness = 0; // we are no longer in fast machine mode at all! - } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) { - m_trEarliness = trLate; // Things have slipped of their own accord - } else { - m_trEarliness = m_trEarliness - m_trEarliness/8; // graceful slide - } - - // prepare the new wait average - but don't pollute the old one until - // we have finished with it. - int trWaitAvg; - { - // We never mix in a negative wait. This causes us to believe in fast machines - // slightly more. - int trL = trLate<0 ? -trLate : 0; - trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; - } - - - int trFrame; - { - REFERENCE_TIME tr = trRealStream - m_trLastDraw; // Cd be large - 4 min pause! - if (tr>10000000) { - tr = 10000000; // 1 second - arbitrarily. - } - trFrame = int(tr); - } - - // We will DRAW this frame IF... - if ( - // ...the time we are spending drawing is a small fraction of the total - // observed inter-frame time so that dropping it won't help much. - (3*m_trRenderAvg <= m_trFrameAvg) - - // ...or our supplier is NOT handling things and the next frame would - // be less timely than this one or our supplier CLAIMS to be handling - // things, and is now less than a full FOUR frames late. - || ( m_bSupplierHandlingQuality - ? (trLate <= trDuration*4) - : (trLate+trLate < trDuration) - ) - - // ...or we are on average waiting for over eight milliseconds then - // this may be just a glitch. Draw it and we'll hope to catch up. - || (m_trWaitAvg > 80000) - - // ...or we haven't drawn an image for over a second. We will update - // the display, which stops the video looking hung. - // Do this regardless of how late this media sample is. - || ((trRealStream - m_trLastDraw) > UNITS) - - ) { - HRESULT Result; - - // We are going to play this frame. We may want to play it early. - // We will play it early if we think we are in slow machine mode. - // If we think we are NOT in slow machine mode, we will still play - // it early by m_trEarliness as this controls the graceful slide back. - // and in addition we aim at being m_trTarget late rather than "on time". - - BOOL bPlayASAP = FALSE; - - // we will play it AT ONCE (slow machine mode) if... - - // ...we are playing catch-up - if ( bJustDroppedFrame) { - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9001); - } - - // ...or if we are running below the true frame rate - // exact comparisons are glitchy, for these measurements, - // so add an extra 5% or so - else if ( (m_trFrameAvg > trDuration + trDuration/16) - - // It's possible to get into a state where we are losing ground, but - // are a very long way ahead. To avoid this or recover from it - // we refuse to play early by more than 10 frames. - && (trLate > - trDuration*10) - ){ - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9002); - } -#if 0 - // ...or if we have been late and are less than one frame early - else if ( (trLate + trDuration > 0) - && (m_trWaitAvg<=20000) - ) { - bPlayASAP = TRUE; - MSR_INTEGER(m_idDecision, 9003); - } -#endif - // We will NOT play it at once if we are grossly early. On very slow frame - // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just - // because we got starved (for instance by the net) and dropped one frame - // some time or other. If we are more than 900mSec early, then wait. - if (trLate<-9000000) { - bPlayASAP = FALSE; - } - - if (bPlayASAP) { - - m_nNormal = 0; - MSR_INTEGER(m_idDecision, 0); - // When we are here, we are in slow-machine mode. trLate may well - // oscillate between negative and positive when the supplier is - // dropping frames to keep sync. We should not let that mislead - // us into thinking that we have as much as zero spare time! - // We just update with a zero wait. - m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; - - // Assume that we draw it immediately. Update inter-frame stats - m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD; -#ifndef PERF - // If this is NOT a perf build, then report what we know so far - // without looking at the clock any more. This assumes that we - // actually wait for exactly the time we hope to. It also reports - // how close we get to the manipulated time stamps that we now have - // rather than the ones we originally started with. It will - // therefore be a little optimistic. However it's fast. - PreparePerformanceData(trTrueLate, trFrame); -#endif - m_trLastDraw = trRealStream; - if (m_trEarliness > trLate) { - m_trEarliness = trLate; // if we are actually early, this is neg - } - Result = S_OK; // Draw it now - - } else { - ++m_nNormal; - // Set the average frame rate to EXACTLY the ideal rate. - // If we are exiting slow-machine mode then we will have caught up - // and be running ahead, so as we slide back to exact timing we will - // have a longer than usual gap at this point. If we record this - // real gap then we'll think that we're running slow and go back - // into slow-machine mode and vever get it straight. - m_trFrameAvg = trDuration; - MSR_INTEGER(m_idDecision, 1); - - // Play it early by m_trEarliness and by m_trTarget - - { - int trE = m_trEarliness; - if (trE < -m_trFrameAvg) { - trE = -m_trFrameAvg; - } - *ptrStart += trE; // N.B. earliness is negative - } - - int Delay = -trTrueLate; - Result = Delay<=0 ? S_OK : S_FALSE; // OK = draw now, FALSE = wait - - m_trWaitAvg = trWaitAvg; - - // Predict when it will actually be drawn and update frame stats - - if (Result==S_FALSE) { // We are going to wait - trFrame = TimeDiff(*ptrStart-m_trLastDraw); - m_trLastDraw = *ptrStart; - } else { - // trFrame is already = trRealStream-m_trLastDraw; - m_trLastDraw = trRealStream; - } -#ifndef PERF - int iAccuracy; - if (Delay>0) { - // Report lateness based on when we intend to play it - iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf); - } else { - // Report lateness based on playing it *now*. - iAccuracy = trTrueLate; // trRealStream-RememberStampForPerf; - } - PreparePerformanceData(iAccuracy, trFrame); -#endif - } - return Result; - } - - // We are going to drop this frame! - // Of course in DirectDraw mode the guy upstream may draw it anyway. - - // This will probably give a large negative wack to the wait avg. - m_trWaitAvg = trWaitAvg; - -#ifdef PERF - // Respect registry setting - debug only! - if (m_bDrawLateFrames) { - return S_OK; // draw it when it's ready - } // even though it's late. -#endif - - // We are going to drop this frame so draw the next one early - // n.b. if the supplier is doing direct draw then he may draw it anyway - // but he's doing something funny to arrive here in that case. - - MSR_INTEGER(m_idDecision, 2); - m_nNormal = -1; - return E_FAIL; // drop it - -} // ShouldDrawSampleNow - - -// NOTE we're called by both the window thread and the source filter thread -// so we have to be protected by a critical section (locked before called) -// Also, when the window thread gets signalled to render an image, it always -// does so regardless of how late it is. All the degradation is done when we -// are scheduling the next sample to be drawn. Hence when we start an advise -// link to draw a sample, that sample's time will always become the last one -// drawn - unless of course we stop streaming in which case we cancel links - -BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample) -{ - // We override ShouldDrawSampleNow to add quality management - - BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample); - if (bDrawImage == FALSE) { - ++m_cFramesDropped; - return FALSE; - } - - // m_cFramesDrawn must NOT be updated here. It has to be updated - // in RecordFrameLateness at the same time as the other statistics. - return TRUE; -} - - -// Implementation of IQualProp interface needed to support the property page -// This is how the property page gets the data out of the scheduler. We are -// passed into the constructor the owning object in the COM sense, this will -// either be the video renderer or an external IUnknown if we're aggregated. -// We initialise our CUnknown base class with this interface pointer. Then -// all we have to do is to override NonDelegatingQueryInterface to expose -// our IQualProp interface. The AddRef and Release are handled automatically -// by the base class and will be passed on to the appropriate outer object - -STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(__out int *pcFramesDropped) -{ - CheckPointer(pcFramesDropped,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - *pcFramesDropped = m_cFramesDropped; - return NOERROR; -} // get_FramesDroppedInRenderer - - -// Set *pcFramesDrawn to the number of frames drawn since -// streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn) -{ - CheckPointer(pcFramesDrawn,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - *pcFramesDrawn = m_cFramesDrawn; - return NOERROR; -} // get_FramesDrawn - - -// Set iAvgFrameRate to the frames per hundred secs since -// streaming started. 0 otherwise. - -STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate) -{ - CheckPointer(piAvgFrameRate,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - int t; - if (m_bStreaming) { - t = timeGetTime()-m_tStreamingStart; - } else { - t = m_tStreamingStart; - } - - if (t<=0) { - *piAvgFrameRate = 0; - ASSERT(m_cFramesDrawn == 0); - } else { - // i is frames per hundred seconds - *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t); - } - return NOERROR; -} // get_AvgFrameRate - - -// Set *piAvg to the average sync offset since streaming started -// in mSec. The sync offset is the time in mSec between when the frame -// should have been drawn and when the frame was actually drawn. - -STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset(__out int *piAvg) -{ - CheckPointer(piAvg,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - if (NULL==m_pClock) { - *piAvg = 0; - return NOERROR; - } - - // Note that we didn't gather the stats on the first frame - // so we use m_cFramesDrawn-1 here - if (m_cFramesDrawn<=1) { - *piAvg = 0; - } else { - *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1)); - } - return NOERROR; -} // get_AvgSyncOffset - - -// To avoid dragging in the maths library - a cheap -// approximate integer square root. -// We do this by getting a starting guess which is between 1 -// and 2 times too large, followed by THREE iterations of -// Newton Raphson. (That will give accuracy to the nearest mSec -// for the range in question - roughly 0..1000) -// -// It would be faster to use a linear interpolation and ONE NR, but -// who cares. If anyone does - the best linear interpolation is -// to approximates sqrt(x) by -// y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1)) -// 0r y = x*0.41421 + 0.59467 -// This minimises the maximal error in the range in question. -// (error is about +0.008883 and then one NR will give error .0000something -// (Of course these are integers, so you can't just multiply by 0.41421 -// you'd have to do some sort of MulDiv). -// Anyone wanna check my maths? (This is only for a property display!) - -int isqrt(int x) -{ - int s = 1; - // Make s an initial guess for sqrt(x) - if (x > 0x40000000) { - s = 0x8000; // prevent any conceivable closed loop - } else { - while (s*s=0) s = (s*s+x)/(2*s); - if (s>=0) s = (s*s+x)/(2*s); - } - } - return s; -} - -// -// Do estimates for standard deviations for per-frame -// statistics -// -HRESULT CBaseVideoRenderer::GetStdDev( - int nSamples, - __out int *piResult, - LONGLONG llSumSq, - LONGLONG iTot -) -{ - CheckPointer(piResult,E_POINTER); - CAutoLock cVideoLock(&m_InterfaceLock); - - if (NULL==m_pClock) { - *piResult = 0; - return NOERROR; - } - - // If S is the Sum of the Squares of observations and - // T the Total (i.e. sum) of the observations and there were - // N observations, then an estimate of the standard deviation is - // sqrt( (S - T**2/N) / (N-1) ) - - if (nSamples<=1) { - *piResult = 0; - } else { - LONGLONG x; - // First frames have invalid stamps, so we get no stats for them - // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 - - // so we use m_cFramesDrawn-1 here - x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0); - x = x / (nSamples-1); - ASSERT(x>=0); - *piResult = isqrt((LONG)x); - } - return NOERROR; -} - -// Set *piDev to the standard deviation in mSec of the sync offset -// of each frame since streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset(__out int *piDev) -{ - // First frames have invalid stamps, so we get no stats for them - // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 - return GetStdDev(m_cFramesDrawn - 1, - piDev, - m_iSumSqAcc, - m_iTotAcc); -} // get_DevSyncOffset - - -// Set *piJitter to the standard deviation in mSec of the inter-frame time -// of frames since streaming started. - -STDMETHODIMP CBaseVideoRenderer::get_Jitter(__out int *piJitter) -{ - // First frames have invalid stamps, so we get no stats for them - // So second frame gives invalid inter-frame time - // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2 - return GetStdDev(m_cFramesDrawn - 2, - piJitter, - m_iSumSqFrameTime, - m_iSumFrameTime); -} // get_Jitter - - -// Overidden to return our IQualProp interface - -STDMETHODIMP -CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv) -{ - // We return IQualProp and delegate everything else - - if (riid == IID_IQualProp) { - return GetInterface( (IQualProp *)this, ppv); - } else if (riid == IID_IQualityControl) { - return GetInterface( (IQualityControl *)this, ppv); - } - return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv); -} - - -// Override JoinFilterGraph so that, just before leaving -// the graph we can send an EC_WINDOW_DESTROYED event - -STDMETHODIMP -CBaseVideoRenderer::JoinFilterGraph(__inout_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName) -{ - // Since we send EC_ACTIVATE, we also need to ensure - // we send EC_WINDOW_DESTROYED or the resource manager may be - // holding us as a focus object - if (!pGraph && m_pGraph) { - - // We were in a graph and now we're not - // Do this properly in case we are aggregated - IBaseFilter* pFilter = this; - NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0); - } - return CBaseFilter::JoinFilterGraph(pGraph, pName); -} - - -// This removes a large number of level 4 warnings from the -// Microsoft compiler which in this case are not very useful -#pragma warning(disable: 4514) - +//------------------------------------------------------------------------------ +// File: RenBase.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" // DirectShow base class definitions +#include // Needed for definition of timeGetTime +#include // Standard data type limit definitions +#include "measure.h" // Used for time critical log functions + +#pragma warning(disable:4355) + +// Helper function for clamping time differences +int inline TimeDiff(REFERENCE_TIME rt) +{ + if (rt < - (50 * UNITS)) { + return -(50 * UNITS); + } else + if (rt > 50 * UNITS) { + return 50 * UNITS; + } else return (int)rt; +} + +// Implements the CBaseRenderer class + +CBaseRenderer::CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer + __in_opt LPCTSTR pName, // Debug ONLY description + __inout_opt LPUNKNOWN pUnk, // Aggregated owner object + __inout HRESULT *phr) : // General OLE return code + + CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass), + m_evComplete(TRUE, phr), + m_RenderEvent(FALSE, phr), + m_bAbort(FALSE), + m_pPosition(NULL), + m_ThreadSignal(TRUE, phr), + m_bStreaming(FALSE), + m_bEOS(FALSE), + m_bEOSDelivered(FALSE), + m_pMediaSample(NULL), + m_dwAdvise(0), + m_pQSink(NULL), + m_pInputPin(NULL), + m_bRepaintStatus(TRUE), + m_SignalTime(0), + m_bInReceive(FALSE), + m_EndOfStreamTimer(0) +{ + if (SUCCEEDED(*phr)) { + Ready(); +#ifdef PERF + m_idBaseStamp = MSR_REGISTER(TEXT("BaseRenderer: sample time stamp")); + m_idBaseRenderTime = MSR_REGISTER(TEXT("BaseRenderer: draw time (msec)")); + m_idBaseAccuracy = MSR_REGISTER(TEXT("BaseRenderer: Accuracy (msec)")); +#endif + } +} + + +// Delete the dynamically allocated IMediaPosition and IMediaSeeking helper +// object. The object is created when somebody queries us. These are standard +// control interfaces for seeking and setting start/stop positions and rates. +// We will probably also have made an input pin based on CRendererInputPin +// that has to be deleted, it's created when an enumerator calls our GetPin + +CBaseRenderer::~CBaseRenderer() +{ + ASSERT(m_bStreaming == FALSE); + ASSERT(m_EndOfStreamTimer == 0); + StopStreaming(); + ClearPendingSample(); + + // Delete any IMediaPosition implementation + + if (m_pPosition) { + delete m_pPosition; + m_pPosition = NULL; + } + + // Delete any input pin created + + if (m_pInputPin) { + delete m_pInputPin; + m_pInputPin = NULL; + } + + // Release any Quality sink + + ASSERT(m_pQSink == NULL); +} + + +// This returns the IMediaPosition and IMediaSeeking interfaces + +HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid, __deref_out void **ppv) +{ + CAutoLock cObjectCreationLock(&m_ObjectCreationLock); + if (m_pPosition) { + return m_pPosition->NonDelegatingQueryInterface(riid,ppv); + } + + CBasePin *pPin = GetPin(0); + if (NULL == pPin) { + return E_OUTOFMEMORY; + } + + HRESULT hr = NOERROR; + + // Create implementation of this dynamically since sometimes we may + // never try and do a seek. The helper object implements a position + // control interface (IMediaPosition) which in fact simply takes the + // calls normally from the filter graph and passes them upstream + + m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"), + CBaseFilter::GetOwner(), + (HRESULT *) &hr, + pPin); + if (m_pPosition == NULL) { + return E_OUTOFMEMORY; + } + + if (FAILED(hr)) { + delete m_pPosition; + m_pPosition = NULL; + return E_NOINTERFACE; + } + return GetMediaPositionInterface(riid,ppv); +} + + +// Overriden to say what interfaces we support and where + +STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + // Do we have this interface + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + return GetMediaPositionInterface(riid,ppv); + } else { + return CBaseFilter::NonDelegatingQueryInterface(riid,ppv); + } +} + + +// This is called whenever we change states, we have a manual reset event that +// is signalled whenever we don't won't the source filter thread to wait in us +// (such as in a stopped state) and likewise is not signalled whenever it can +// wait (during paused and running) this function sets or resets the thread +// event. The event is used to stop source filter threads waiting in Receive + +HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait) +{ + if (bCanWait == TRUE) { + m_ThreadSignal.Reset(); + } else { + m_ThreadSignal.Set(); + } + return NOERROR; +} + + +#ifdef _DEBUG +// Dump the current renderer state to the debug terminal. The hardest part of +// the renderer is the window where we unlock everything to wait for a clock +// to signal it is time to draw or for the application to cancel everything +// by stopping the filter. If we get things wrong we can leave the thread in +// WaitForRenderTime with no way for it to ever get out and we will deadlock + +void CBaseRenderer::DisplayRendererState() +{ + DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime"))); + + // No way should this be signalled at this point + + BOOL bSignalled = m_ThreadSignal.Check(); + DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled)); + + // Now output the current renderer state variables + + DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State)); + + DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort)); + + DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming)); + + DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise)); + + DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample)); + + DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS)); + + DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered)); + + DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus)); + + + // Output the delayed end of stream timer information + + DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer)); + + DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime))); + + + // Should never timeout during a flushing state + + BOOL bFlushing = m_pInputPin->IsFlushing(); + DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing)); + + // Display the time we were told to start at + DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time))); + + // Have we got a reference clock + if (m_pClock == NULL) return; + + // Get the current time from the wall clock + + CRefTime CurrentTime,StartTime,EndTime; + m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime); + CRefTime Offset = CurrentTime - m_tStart; + + // Display the current time from the clock + + DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time))); + + DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs())); + + + // Do we have a sample ready to render + if (m_pMediaSample == NULL) return; + + m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime); + DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"), + StartTime.Millisecs(),EndTime.Millisecs())); + + // Calculate how long it is until it is due for rendering + CRefTime Wait = (m_tStart + StartTime) - CurrentTime; + DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs())); +} +#endif + + +// Wait until the clock sets the timer event or we're otherwise signalled. We +// set an arbitrary timeout for this wait and if it fires then we display the +// current renderer state on the debugger. It will often fire if the filter's +// left paused in an application however it may also fire during stress tests +// if the synchronisation with application seeks and state changes is faulty + +#define RENDER_TIMEOUT 10000 + +HRESULT CBaseRenderer::WaitForRenderTime() +{ + HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent }; + DWORD Result = WAIT_TIMEOUT; + + // Wait for either the time to arrive or for us to be stopped + + OnWaitStart(); + while (Result == WAIT_TIMEOUT) { + Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT); + +#ifdef _DEBUG + if (Result == WAIT_TIMEOUT) DisplayRendererState(); +#endif + + } + OnWaitEnd(); + + // We may have been awoken without the timer firing + + if (Result == WAIT_OBJECT_0) { + return VFW_E_STATE_CHANGED; + } + + SignalTimerFired(); + return NOERROR; +} + + +// Poll waiting for Receive to complete. This really matters when +// Receive may set the palette and cause window messages +// The problem is that if we don't really wait for a renderer to +// stop processing we can deadlock waiting for a transform which +// is calling the renderer's Receive() method because the transform's +// Stop method doesn't know to process window messages to unblock +// the renderer's Receive processing +void CBaseRenderer::WaitForReceiveToComplete() +{ + for (;;) { + if (!m_bInReceive) { + break; + } + + MSG msg; + // Receive all interthread snedmessages + PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); + + Sleep(1); + } + + // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call + // above just cleared the changebit which will cause some messaging + // calls to block (waitMessage, MsgWaitFor...) now. + // Post a dummy message to set the QS_POSTMESSAGE bit again + if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { + // Send dummy message + PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); + } +} + +// A filter can have four discrete states, namely Stopped, Running, Paused, +// Intermediate. We are in an intermediate state if we are currently trying +// to pause but haven't yet got the first sample (or if we have been flushed +// in paused state and therefore still have to wait for a sample to arrive) + +// This class contains an event called m_evComplete which is signalled when +// the current state is completed and is not signalled when we are waiting to +// complete the last state transition. As mentioned above the only time we +// use this at the moment is when we wait for a media sample in paused state +// If while we are waiting we receive an end of stream notification from the +// source filter then we know no data is imminent so we can reset the event +// This means that when we transition to paused the source filter must call +// end of stream on us or send us an image otherwise we'll hang indefinately + + +// Simple internal way of getting the real state + +FILTER_STATE CBaseRenderer::GetRealState() { + return m_State; +} + + +// The renderer doesn't complete the full transition to paused states until +// it has got one media sample to render. If you ask it for its state while +// it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE + +STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State) +{ + CheckPointer(State,E_POINTER); + + if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) { + *State = m_State; + return VFW_S_STATE_INTERMEDIATE; + } + *State = m_State; + return NOERROR; +} + + +// If we're pausing and we have no samples we don't complete the transition +// to State_Paused and we return S_FALSE. However if the m_bAbort flag has +// been set then all samples are rejected so there is no point waiting for +// one. If we do have a sample then return NOERROR. We will only ever return +// VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample +// (calling GetState after either being stopped or Run will NOT return this) + +HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState) +{ + // Allow us to be paused when disconnected + + if (m_pInputPin->IsConnected() == FALSE) { + Ready(); + return S_OK; + } + + // Have we run off the end of stream + + if (IsEndOfStream() == TRUE) { + Ready(); + return S_OK; + } + + // Make sure we get fresh data after being stopped + + if (HaveCurrentSample() == TRUE) { + if (OldState != State_Stopped) { + Ready(); + return S_OK; + } + } + NotReady(); + return S_FALSE; +} + + +// When we stop the filter the things we do are:- + +// Decommit the allocator being used in the connection +// Release the source filter if it's waiting in Receive +// Cancel any advise link we set up with the clock +// Any end of stream signalled is now obsolete so reset +// Allow us to be stopped when we are not connected + +STDMETHODIMP CBaseRenderer::Stop() +{ + CAutoLock cRendererLock(&m_InterfaceLock); + + // Make sure there really is a state change + + if (m_State == State_Stopped) { + return NOERROR; + } + + // Is our input pin connected + + if (m_pInputPin->IsConnected() == FALSE) { + NOTE("Input pin is not connected"); + m_State = State_Stopped; + return NOERROR; + } + + CBaseFilter::Stop(); + + // If we are going into a stopped state then we must decommit whatever + // allocator we are using it so that any source filter waiting in the + // GetBuffer can be released and unlock themselves for a state change + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Decommit(); + } + + // Cancel any scheduled rendering + + SetRepaintStatus(TRUE); + StopStreaming(); + SourceThreadCanWait(FALSE); + ResetEndOfStream(); + CancelNotification(); + + // There should be no outstanding clock advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + + Ready(); + WaitForReceiveToComplete(); + m_bAbort = FALSE; + + return NOERROR; +} + + +// When we pause the filter the things we do are:- + +// Commit the allocator being used in the connection +// Allow a source filter thread to wait in Receive +// Cancel any clock advise link (we may be running) +// Possibly complete the state change if we have data +// Allow us to be paused when we are not connected + +STDMETHODIMP CBaseRenderer::Pause() +{ + CAutoLock cRendererLock(&m_InterfaceLock); + FILTER_STATE OldState = m_State; + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // Make sure there really is a state change + + if (m_State == State_Paused) { + return CompleteStateChange(State_Paused); + } + + // Has our input pin been connected + + if (m_pInputPin->IsConnected() == FALSE) { + NOTE("Input pin is not connected"); + m_State = State_Paused; + return CompleteStateChange(State_Paused); + } + + // Pause the base filter class + + HRESULT hr = CBaseFilter::Pause(); + if (FAILED(hr)) { + NOTE("Pause failed"); + return hr; + } + + // Enable EC_REPAINT events again + + SetRepaintStatus(TRUE); + StopStreaming(); + SourceThreadCanWait(TRUE); + CancelNotification(); + ResetEndOfStreamTimer(); + + // If we are going into a paused state then we must commit whatever + // allocator we are using it so that any source filter can call the + // GetBuffer and expect to get a buffer without returning an error + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Commit(); + } + + // There should be no outstanding advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // When we come out of a stopped state we must clear any image we were + // holding onto for frame refreshing. Since renderers see state changes + // first we can reset ourselves ready to accept the source thread data + // Paused or running after being stopped causes the current position to + // be reset so we're not interested in passing end of stream signals + + if (OldState == State_Stopped) { + m_bAbort = FALSE; + ClearPendingSample(); + } + return CompleteStateChange(OldState); +} + + +// When we run the filter the things we do are:- + +// Commit the allocator being used in the connection +// Allow a source filter thread to wait in Receive +// Signal the render event just to get us going +// Start the base class by calling StartStreaming +// Allow us to be run when we are not connected +// Signal EC_COMPLETE if we are not connected + +STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime) +{ + CAutoLock cRendererLock(&m_InterfaceLock); + FILTER_STATE OldState = m_State; + + // Make sure there really is a state change + + if (m_State == State_Running) { + return NOERROR; + } + + // Send EC_COMPLETE if we're not connected + + if (m_pInputPin->IsConnected() == FALSE) { + NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); + m_State = State_Running; + return NOERROR; + } + + Ready(); + + // Pause the base filter class + + HRESULT hr = CBaseFilter::Run(StartTime); + if (FAILED(hr)) { + NOTE("Run failed"); + return hr; + } + + // Allow the source thread to wait + ASSERT(m_pInputPin->IsFlushing() == FALSE); + SourceThreadCanWait(TRUE); + SetRepaintStatus(FALSE); + + // There should be no outstanding advise + ASSERT(CancelNotification() == S_FALSE); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(m_EndOfStreamTimer == 0); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + + // If we are going into a running state then we must commit whatever + // allocator we are using it so that any source filter can call the + // GetBuffer and expect to get a buffer without returning an error + + if (m_pInputPin->Allocator()) { + m_pInputPin->Allocator()->Commit(); + } + + // When we come out of a stopped state we must clear any image we were + // holding onto for frame refreshing. Since renderers see state changes + // first we can reset ourselves ready to accept the source thread data + // Paused or running after being stopped causes the current position to + // be reset so we're not interested in passing end of stream signals + + if (OldState == State_Stopped) { + m_bAbort = FALSE; + ClearPendingSample(); + } + return StartStreaming(); +} + + +// Return the number of input pins we support + +int CBaseRenderer::GetPinCount() +{ + if (m_pInputPin == NULL) { + // Try to create it + (void)GetPin(0); + } + return m_pInputPin != NULL ? 1 : 0; +} + + +// We only support one input pin and it is numbered zero + +CBasePin *CBaseRenderer::GetPin(int n) +{ + CAutoLock cObjectCreationLock(&m_ObjectCreationLock); + + // Should only ever be called with zero + ASSERT(n == 0); + + if (n != 0) { + return NULL; + } + + // Create the input pin if not already done so + + if (m_pInputPin == NULL) { + + // hr must be initialized to NOERROR because + // CRendererInputPin's constructor only changes + // hr's value if an error occurs. + HRESULT hr = NOERROR; + + m_pInputPin = new CRendererInputPin(this,&hr,L"In"); + if (NULL == m_pInputPin) { + return NULL; + } + + if (FAILED(hr)) { + delete m_pInputPin; + m_pInputPin = NULL; + return NULL; + } + } + return m_pInputPin; +} + + +// If "In" then return the IPin for our input pin, otherwise NULL and error + +STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + + if (0==lstrcmpW(Id,L"In")) { + *ppPin = GetPin(0); + if (*ppPin) { + (*ppPin)->AddRef(); + } else { + return E_OUTOFMEMORY; + } + } else { + *ppPin = NULL; + return VFW_E_NOT_FOUND; + } + return NOERROR; +} + + +// Called when the input pin receives an EndOfStream notification. If we have +// not got a sample, then notify EC_COMPLETE now. If we have samples, then set +// m_bEOS and check for this on completing samples. If we're waiting to pause +// then complete the transition to paused state by setting the state event + +HRESULT CBaseRenderer::EndOfStream() +{ + // Ignore these calls if we are stopped + + if (m_State == State_Stopped) { + return NOERROR; + } + + // If we have a sample then wait for it to be rendered + + m_bEOS = TRUE; + if (m_pMediaSample) { + return NOERROR; + } + + // If we are waiting for pause then we are now ready since we cannot now + // carry on waiting for a sample to arrive since we are being told there + // won't be any. This sets an event that the GetState function picks up + + Ready(); + + // Only signal completion now if we are running otherwise queue it until + // we do run in StartStreaming. This is used when we seek because a seek + // causes a pause where early notification of completion is misleading + + if (m_bStreaming) { + SendEndOfStream(); + } + return NOERROR; +} + + +// When we are told to flush we should release the source thread + +HRESULT CBaseRenderer::BeginFlush() +{ + // If paused then report state intermediate until we get some data + + if (m_State == State_Paused) { + NotReady(); + } + + SourceThreadCanWait(FALSE); + CancelNotification(); + ClearPendingSample(); + // Wait for Receive to complete + WaitForReceiveToComplete(); + + return NOERROR; +} + + +// After flushing the source thread can wait in Receive again + +HRESULT CBaseRenderer::EndFlush() +{ + // Reset the current sample media time + if (m_pPosition) m_pPosition->ResetMediaTime(); + + // There should be no outstanding advise + + ASSERT(CancelNotification() == S_FALSE); + SourceThreadCanWait(TRUE); + return NOERROR; +} + + +// We can now send EC_REPAINTs if so required + +HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin) +{ + // The caller should always hold the interface lock because + // the function uses CBaseFilter::m_State. + ASSERT(CritCheckIn(&m_InterfaceLock)); + + m_bAbort = FALSE; + + if (State_Running == GetRealState()) { + HRESULT hr = StartStreaming(); + if (FAILED(hr)) { + return hr; + } + + SetRepaintStatus(FALSE); + } else { + SetRepaintStatus(TRUE); + } + + return NOERROR; +} + + +// Called when we go paused or running + +HRESULT CBaseRenderer::Active() +{ + return NOERROR; +} + + +// Called when we go into a stopped state + +HRESULT CBaseRenderer::Inactive() +{ + if (m_pPosition) { + m_pPosition->ResetMediaTime(); + } + // People who derive from this may want to override this behaviour + // to keep hold of the sample in some circumstances + ClearPendingSample(); + + return NOERROR; +} + + +// Tell derived classes about the media type agreed + +HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt) +{ + return NOERROR; +} + + +// When we break the input pin connection we should reset the EOS flags. When +// we are asked for either IMediaPosition or IMediaSeeking we will create a +// CPosPassThru object to handles media time pass through. When we're handed +// samples we store (by calling CPosPassThru::RegisterMediaTime) their media +// times so we can then return a real current position of data being rendered + +HRESULT CBaseRenderer::BreakConnect() +{ + // Do we have a quality management sink + + if (m_pQSink) { + m_pQSink->Release(); + m_pQSink = NULL; + } + + // Check we have a valid connection + + if (m_pInputPin->IsConnected() == FALSE) { + return S_FALSE; + } + + // Check we are stopped before disconnecting + if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) { + return VFW_E_NOT_STOPPED; + } + + SetRepaintStatus(FALSE); + ResetEndOfStream(); + ClearPendingSample(); + m_bAbort = FALSE; + + if (State_Running == m_State) { + StopStreaming(); + } + + return NOERROR; +} + + +// Retrieves the sample times for this samples (note the sample times are +// passed in by reference not value). We return S_FALSE to say schedule this +// sample according to the times on the sample. We also return S_OK in +// which case the object should simply render the sample data immediately + +HRESULT CBaseRenderer::GetSampleTimes(IMediaSample *pMediaSample, + __out REFERENCE_TIME *pStartTime, + __out REFERENCE_TIME *pEndTime) +{ + ASSERT(m_dwAdvise == 0); + ASSERT(pMediaSample); + + // If the stop time for this sample is before or the same as start time, + // then just ignore it (release it) and schedule the next one in line + // Source filters should always fill in the start and end times properly! + + if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) { + if (*pEndTime < *pStartTime) { + return VFW_E_START_TIME_AFTER_END; + } + } else { + // no time set in the sample... draw it now? + return S_OK; + } + + // Can't synchronise without a clock so we return S_OK which tells the + // caller that the sample should be rendered immediately without going + // through the overhead of setting a timer advise link with the clock + + if (m_pClock == NULL) { + return S_OK; + } + return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime); +} + + +// By default all samples are drawn according to their time stamps so we +// return S_FALSE. Returning S_OK means draw immediately, this is used +// by the derived video renderer class in its quality management. + +HRESULT CBaseRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, + __out REFERENCE_TIME *ptrStart, + __out REFERENCE_TIME *ptrEnd) +{ + return S_FALSE; +} + + +// We must always reset the current advise time to zero after a timer fires +// because there are several possible ways which lead us not to do any more +// scheduling such as the pending image being cleared after state changes + +void CBaseRenderer::SignalTimerFired() +{ + m_dwAdvise = 0; +} + + +// Cancel any notification currently scheduled. This is called by the owning +// window object when it is told to stop streaming. If there is no timer link +// outstanding then calling this is benign otherwise we go ahead and cancel +// We must always reset the render event as the quality management code can +// signal immediate rendering by setting the event without setting an advise +// link. If we're subsequently stopped and run the first attempt to setup an +// advise link with the reference clock will find the event still signalled + +HRESULT CBaseRenderer::CancelNotification() +{ + ASSERT(m_dwAdvise == 0 || m_pClock); + DWORD_PTR dwAdvise = m_dwAdvise; + + // Have we a live advise link + + if (m_dwAdvise) { + m_pClock->Unadvise(m_dwAdvise); + SignalTimerFired(); + ASSERT(m_dwAdvise == 0); + } + + // Clear the event and return our status + + m_RenderEvent.Reset(); + return (dwAdvise ? S_OK : S_FALSE); +} + + +// Responsible for setting up one shot advise links with the clock +// Return FALSE if the sample is to be dropped (not drawn at all) +// Return TRUE if the sample is to be drawn and in this case also +// arrange for m_RenderEvent to be set at the appropriate time + +BOOL CBaseRenderer::ScheduleSample(IMediaSample *pMediaSample) +{ + REFERENCE_TIME StartSample, EndSample; + + // Is someone pulling our leg + + if (pMediaSample == NULL) { + return FALSE; + } + + // Get the next sample due up for rendering. If there aren't any ready + // then GetNextSampleTimes returns an error. If there is one to be done + // then it succeeds and yields the sample times. If it is due now then + // it returns S_OK other if it's to be done when due it returns S_FALSE + + HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample); + if (FAILED(hr)) { + return FALSE; + } + + // If we don't have a reference clock then we cannot set up the advise + // time so we simply set the event indicating an image to render. This + // will cause us to run flat out without any timing or synchronisation + + if (hr == S_OK) { + EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent)); + return TRUE; + } + + ASSERT(m_dwAdvise == 0); + ASSERT(m_pClock); + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + + // We do have a valid reference clock interface so we can ask it to + // set an event when the image comes due for rendering. We pass in + // the reference time we were told to start at and also the current + // stream time which is the offset from the start reference time + + hr = m_pClock->AdviseTime( + (REFERENCE_TIME) m_tStart, // Start run time + StartSample, // Stream time + (HEVENT)(HANDLE) m_RenderEvent, // Render notification + &m_dwAdvise); // Advise cookie + + if (SUCCEEDED(hr)) { + return TRUE; + } + + // We could not schedule the next sample for rendering despite the fact + // we have a valid sample here. This is a fair indication that either + // the system clock is wrong or the time stamp for the sample is duff + + ASSERT(m_dwAdvise == 0); + return FALSE; +} + + +// This is called when a sample comes due for rendering. We pass the sample +// on to the derived class. After rendering we will initialise the timer for +// the next sample, NOTE signal that the last one fired first, if we don't +// do this it thinks there is still one outstanding that hasn't completed + +HRESULT CBaseRenderer::Render(IMediaSample *pMediaSample) +{ + // If the media sample is NULL then we will have been notified by the + // clock that another sample is ready but in the mean time someone has + // stopped us streaming which causes the next sample to be released + + if (pMediaSample == NULL) { + return S_FALSE; + } + + // If we have stopped streaming then don't render any more samples, the + // thread that got in and locked us and then reset this flag does not + // clear the pending sample as we can use it to refresh any output device + + if (m_bStreaming == FALSE) { + return S_FALSE; + } + + // Time how long the rendering takes + + OnRenderStart(pMediaSample); + DoRenderSample(pMediaSample); + OnRenderEnd(pMediaSample); + + return NOERROR; +} + + +// Checks if there is a sample waiting at the renderer + +BOOL CBaseRenderer::HaveCurrentSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + return (m_pMediaSample == NULL ? FALSE : TRUE); +} + + +// Returns the current sample waiting at the video renderer. We AddRef the +// sample before returning so that should it come due for rendering the +// person who called this method will hold the remaining reference count +// that will stop the sample being added back onto the allocator free list + +IMediaSample *CBaseRenderer::GetCurrentSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_pMediaSample) { + m_pMediaSample->AddRef(); + } + return m_pMediaSample; +} + + +// Called when the source delivers us a sample. We go through a few checks to +// make sure the sample can be rendered. If we are running (streaming) then we +// have the sample scheduled with the reference clock, if we are not streaming +// then we have received an sample in paused mode so we can complete any state +// transition. On leaving this function everything will be unlocked so an app +// thread may get in and change our state to stopped (for example) in which +// case it will also signal the thread event so that our wait call is stopped + +HRESULT CBaseRenderer::PrepareReceive(IMediaSample *pMediaSample) +{ + CAutoLock cInterfaceLock(&m_InterfaceLock); + m_bInReceive = TRUE; + + // Check our flushing and filter state + + // This function must hold the interface lock because it calls + // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses + // CBasePin::m_bRunTimeError. + HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample); + + if (hr != NOERROR) { + m_bInReceive = FALSE; + return E_FAIL; + } + + // Has the type changed on a media sample. We do all rendering + // synchronously on the source thread, which has a side effect + // that only one buffer is ever outstanding. Therefore when we + // have Receive called we can go ahead and change the format + // Since the format change can cause a SendMessage we just don't + // lock + if (m_pInputPin->SampleProps()->pMediaType) { + hr = m_pInputPin->SetMediaType( + (CMediaType *)m_pInputPin->SampleProps()->pMediaType); + if (FAILED(hr)) { + m_bInReceive = FALSE; + return hr; + } + } + + + CAutoLock cSampleLock(&m_RendererLock); + + ASSERT(IsActive() == TRUE); + ASSERT(m_pInputPin->IsFlushing() == FALSE); + ASSERT(m_pInputPin->IsConnected() == TRUE); + ASSERT(m_pMediaSample == NULL); + + // Return an error if we already have a sample waiting for rendering + // source pins must serialise the Receive calls - we also check that + // no data is being sent after the source signalled an end of stream + + if (m_pMediaSample || m_bEOS || m_bAbort) { + Ready(); + m_bInReceive = FALSE; + return E_UNEXPECTED; + } + + // Store the media times from this sample + if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample); + + // Schedule the next sample if we are streaming + + if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) { + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(CancelNotification() == S_FALSE); + m_bInReceive = FALSE; + return VFW_E_SAMPLE_REJECTED; + } + + // Store the sample end time for EC_COMPLETE handling + m_SignalTime = m_pInputPin->SampleProps()->tStop; + + // BEWARE we sometimes keep the sample even after returning the thread to + // the source filter such as when we go into a stopped state (we keep it + // to refresh the device with) so we must AddRef it to keep it safely. If + // we start flushing the source thread is released and any sample waiting + // will be released otherwise GetBuffer may never return (see BeginFlush) + + m_pMediaSample = pMediaSample; + m_pMediaSample->AddRef(); + + if (m_bStreaming == FALSE) { + SetRepaintStatus(TRUE); + } + return NOERROR; +} + + +// Called by the source filter when we have a sample to render. Under normal +// circumstances we set an advise link with the clock, wait for the time to +// arrive and then render the data using the PURE virtual DoRenderSample that +// the derived class will have overriden. After rendering the sample we may +// also signal EOS if it was the last one sent before EndOfStream was called + +HRESULT CBaseRenderer::Receive(IMediaSample *pSample) +{ + ASSERT(pSample); + + // It may return VFW_E_SAMPLE_REJECTED code to say don't bother + + HRESULT hr = PrepareReceive(pSample); + ASSERT(m_bInReceive == SUCCEEDED(hr)); + if (FAILED(hr)) { + if (hr == VFW_E_SAMPLE_REJECTED) { + return NOERROR; + } + return hr; + } + + // We realize the palette in "PrepareRender()" so we have to give away the + // filter lock here. + if (m_State == State_Paused) { + PrepareRender(); + // no need to use InterlockedExchange + m_bInReceive = FALSE; + { + // We must hold both these locks + CAutoLock cRendererLock(&m_InterfaceLock); + if (m_State == State_Stopped) + return NOERROR; + + m_bInReceive = TRUE; + CAutoLock cSampleLock(&m_RendererLock); + OnReceiveFirstSample(pSample); + } + Ready(); + } + // Having set an advise link with the clock we sit and wait. We may be + // awoken by the clock firing or by a state change. The rendering call + // will lock the critical section and check we can still render the data + + hr = WaitForRenderTime(); + if (FAILED(hr)) { + m_bInReceive = FALSE; + return NOERROR; + } + + PrepareRender(); + + // Set this here and poll it until we work out the locking correctly + // It can't be right that the streaming stuff grabs the interface + // lock - after all we want to be able to wait for this stuff + // to complete + m_bInReceive = FALSE; + + // We must hold both these locks + CAutoLock cRendererLock(&m_InterfaceLock); + + // since we gave away the filter wide lock, the sate of the filter could + // have chnaged to Stopped + if (m_State == State_Stopped) + return NOERROR; + + CAutoLock cSampleLock(&m_RendererLock); + + // Deal with this sample + + Render(m_pMediaSample); + ClearPendingSample(); + SendEndOfStream(); + CancelNotification(); + return NOERROR; +} + + +// This is called when we stop or are inactivated to clear the pending sample +// We release the media sample interface so that they can be allocated to the +// source filter again, unless of course we are changing state to inactive in +// which case GetBuffer will return an error. We must also reset the current +// media sample to NULL so that we know we do not currently have an image + +HRESULT CBaseRenderer::ClearPendingSample() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_pMediaSample) { + m_pMediaSample->Release(); + m_pMediaSample = NULL; + } + return NOERROR; +} + + +// Used to signal end of stream according to the sample end time + +void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier + UINT uMsg, // Not currently used + DWORD_PTR dwUser,// User information + DWORD_PTR dw1, // Windows reserved + DWORD_PTR dw2) // is also reserved +{ + CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser; + NOTE1("EndOfStreamTimer called (%d)",uID); + pRenderer->TimerCallback(); +} + +// Do the timer callback work +void CBaseRenderer::TimerCallback() +{ + // Lock for synchronization (but don't hold this lock when calling + // timeKillEvent) + CAutoLock cRendererLock(&m_RendererLock); + + // See if we should signal end of stream now + + if (m_EndOfStreamTimer) { + m_EndOfStreamTimer = 0; + SendEndOfStream(); + } +} + + +// If we are at the end of the stream signal the filter graph but do not set +// the state flag back to FALSE. Once we drop off the end of the stream we +// leave the flag set (until a subsequent ResetEndOfStream). Each sample we +// get delivered will update m_SignalTime to be the last sample's end time. +// We must wait this long before signalling end of stream to the filtergraph + +#define TIMEOUT_DELIVERYWAIT 50 +#define TIMEOUT_RESOLUTION 10 + +HRESULT CBaseRenderer::SendEndOfStream() +{ + ASSERT(CritCheckIn(&m_RendererLock)); + if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) { + return NOERROR; + } + + // If there is no clock then signal immediately + if (m_pClock == NULL) { + return NotifyEndOfStream(); + } + + // How long into the future is the delivery time + + REFERENCE_TIME Signal = m_tStart + m_SignalTime; + REFERENCE_TIME CurrentTime; + m_pClock->GetTime(&CurrentTime); + LONG Delay = LONG((Signal - CurrentTime) / 10000); + + // Dump the timing information to the debugger + + NOTE1("Delay until end of stream delivery %d",Delay); + NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime)); + NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal)); + + // Wait for the delivery time to arrive + + if (Delay < TIMEOUT_DELIVERYWAIT) { + return NotifyEndOfStream(); + } + + // Signal a timer callback on another worker thread + + m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer + TIMEOUT_RESOLUTION, // Timer resolution + EndOfStreamTimer, // Callback function + DWORD_PTR(this), // Used information + TIME_ONESHOT); // Type of callback + if (m_EndOfStreamTimer == 0) { + return NotifyEndOfStream(); + } + return NOERROR; +} + + +// Signals EC_COMPLETE to the filtergraph manager + +HRESULT CBaseRenderer::NotifyEndOfStream() +{ + CAutoLock cRendererLock(&m_RendererLock); + ASSERT(m_bEOSDelivered == FALSE); + ASSERT(m_EndOfStreamTimer == 0); + + // Has the filter changed state + + if (m_bStreaming == FALSE) { + ASSERT(m_EndOfStreamTimer == 0); + return NOERROR; + } + + // Reset the end of stream timer + m_EndOfStreamTimer = 0; + + // If we've been using the IMediaPosition interface, set it's start + // and end media "times" to the stop position by hand. This ensures + // that we actually get to the end, even if the MPEG guestimate has + // been bad or if the quality management dropped the last few frames + + if (m_pPosition) m_pPosition->EOS(); + m_bEOSDelivered = TRUE; + NOTE("Sending EC_COMPLETE..."); + return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); +} + + +// Reset the end of stream flag, this is typically called when we transfer to +// stopped states since that resets the current position back to the start so +// we will receive more samples or another EndOfStream if there aren't any. We +// keep two separate flags one to say we have run off the end of the stream +// (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE +// to the filter graph. We need the latter otherwise we can end up sending an +// EC_COMPLETE every time the source changes state and calls our EndOfStream + +HRESULT CBaseRenderer::ResetEndOfStream() +{ + ResetEndOfStreamTimer(); + CAutoLock cRendererLock(&m_RendererLock); + + m_bEOS = FALSE; + m_bEOSDelivered = FALSE; + m_SignalTime = 0; + + return NOERROR; +} + + +// Kills any outstanding end of stream timer + +void CBaseRenderer::ResetEndOfStreamTimer() +{ + ASSERT(CritCheckOut(&m_RendererLock)); + if (m_EndOfStreamTimer) { + timeKillEvent(m_EndOfStreamTimer); + m_EndOfStreamTimer = 0; + } +} + + +// This is called when we start running so that we can schedule any pending +// image we have with the clock and display any timing information. If we +// don't have any sample but we have queued an EOS flag then we send it. If +// we do have a sample then we wait until that has been rendered before we +// signal the filter graph otherwise we may change state before it's done + +HRESULT CBaseRenderer::StartStreaming() +{ + CAutoLock cRendererLock(&m_RendererLock); + if (m_bStreaming == TRUE) { + return NOERROR; + } + + // Reset the streaming times ready for running + + m_bStreaming = TRUE; + + timeBeginPeriod(1); + OnStartStreaming(); + + // There should be no outstanding advise + ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); + ASSERT(CancelNotification() == S_FALSE); + + // If we have an EOS and no data then deliver it now + + if (m_pMediaSample == NULL) { + return SendEndOfStream(); + } + + // Have the data rendered + + ASSERT(m_pMediaSample); + if (!ScheduleSample(m_pMediaSample)) + m_RenderEvent.Set(); + + return NOERROR; +} + + +// This is called when we stop streaming so that we can set our internal flag +// indicating we are not now to schedule any more samples arriving. The state +// change methods in the filter implementation take care of cancelling any +// clock advise link we have set up and clearing any pending sample we have + +HRESULT CBaseRenderer::StopStreaming() +{ + CAutoLock cRendererLock(&m_RendererLock); + m_bEOSDelivered = FALSE; + + if (m_bStreaming == TRUE) { + m_bStreaming = FALSE; + OnStopStreaming(); + timeEndPeriod(1); + } + return NOERROR; +} + + +// We have a boolean flag that is reset when we have signalled EC_REPAINT to +// the filter graph. We set this when we receive an image so that should any +// conditions arise again we can send another one. By having a flag we ensure +// we don't flood the filter graph with redundant calls. We do not set the +// event when we receive an EndOfStream call since there is no point in us +// sending further EC_REPAINTs. In particular the AutoShowWindow method and +// the DirectDraw object use this method to control the window repainting + +void CBaseRenderer::SetRepaintStatus(BOOL bRepaint) +{ + CAutoLock cSampleLock(&m_RendererLock); + m_bRepaintStatus = bRepaint; +} + + +// Pass the window handle to the upstream filter + +void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd) +{ + IMediaEventSink *pSink; + + // Does the pin support IMediaEventSink + HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink); + if (SUCCEEDED(hr)) { + pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); + pSink->Release(); + } + NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); +} + + +// Signal an EC_REPAINT to the filter graph. This can be used to have data +// sent to us. For example when a video window is first displayed it may +// not have an image to display, at which point it signals EC_REPAINT. The +// filtergraph will either pause the graph if stopped or if already paused +// it will call put_CurrentPosition of the current position. Setting the +// current position to itself has the stream flushed and the image resent + +#define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_))); + +void CBaseRenderer::SendRepaint() +{ + CAutoLock cSampleLock(&m_RendererLock); + ASSERT(m_pInputPin); + + // We should not send repaint notifications when... + // - An end of stream has been notified + // - Our input pin is being flushed + // - The input pin is not connected + // - We have aborted a video playback + // - There is a repaint already sent + + if (m_bAbort == FALSE) { + if (m_pInputPin->IsConnected() == TRUE) { + if (m_pInputPin->IsFlushing() == FALSE) { + if (IsEndOfStream() == FALSE) { + if (m_bRepaintStatus == TRUE) { + IPin *pPin = (IPin *) m_pInputPin; + NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0); + SetRepaintStatus(FALSE); + RLOG("Sending repaint"); + } + } + } + } + } +} + + +// When a video window detects a display change (WM_DISPLAYCHANGE message) it +// can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The +// filtergraph will stop everyone and reconnect our input pin. As we're then +// reconnected we can accept the media type that matches the new display mode +// since we may no longer be able to draw the current image type efficiently + +BOOL CBaseRenderer::OnDisplayChange() +{ + // Ignore if we are not connected yet + + CAutoLock cSampleLock(&m_RendererLock); + if (m_pInputPin->IsConnected() == FALSE) { + return FALSE; + } + + RLOG("Notification of EC_DISPLAY_CHANGE"); + + // Pass our input pin as parameter on the event + + IPin *pPin = (IPin *) m_pInputPin; + m_pInputPin->AddRef(); + NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0); + SetAbortSignal(TRUE); + ClearPendingSample(); + m_pInputPin->Release(); + + return TRUE; +} + + +// Called just before we start drawing. +// Store the current time in m_trRenderStart to allow the rendering time to be +// logged. Log the time stamp of the sample and how late it is (neg is early) + +void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample) +{ +#ifdef PERF + REFERENCE_TIME trStart, trEnd; + pMediaSample->GetTime(&trStart, &trEnd); + + MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits + + m_pClock->GetTime(&m_trRenderStart); + MSR_INTEGER(0, (int)m_trRenderStart); + REFERENCE_TIME trStream; + trStream = m_trRenderStart-m_tStart; // convert reftime to stream time + MSR_INTEGER(0,(int)trStream); + + const int trLate = (int)(trStream - trStart); + MSR_INTEGER(m_idBaseAccuracy, trLate/10000); // dump in mSec +#endif + +} // OnRenderStart + + +// Called directly after drawing an image. +// calculate the time spent drawing and log it. + +void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample) +{ +#ifdef PERF + REFERENCE_TIME trNow; + m_pClock->GetTime(&trNow); + MSR_INTEGER(0,(int)trNow); + int t = (int)((trNow - m_trRenderStart)/10000); // convert UNITS->msec + MSR_INTEGER(m_idBaseRenderTime, t); +#endif +} // OnRenderEnd + + + + +// Constructor must be passed the base renderer object + +CRendererInputPin::CRendererInputPin(__inout CBaseRenderer *pRenderer, + __inout HRESULT *phr, + __in_opt LPCWSTR pPinName) : + CBaseInputPin(NAME("Renderer pin"), + pRenderer, + &pRenderer->m_InterfaceLock, + (HRESULT *) phr, + pPinName) +{ + m_pRenderer = pRenderer; + ASSERT(m_pRenderer); +} + + +// Signals end of data stream on the input pin + +STDMETHODIMP CRendererInputPin::EndOfStream() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + + // Make sure we're streaming ok + + HRESULT hr = CheckStreaming(); + if (hr != NOERROR) { + return hr; + } + + // Pass it onto the renderer + + hr = m_pRenderer->EndOfStream(); + if (SUCCEEDED(hr)) { + hr = CBaseInputPin::EndOfStream(); + } + return hr; +} + + +// Signals start of flushing on the input pin - we do the final reset end of +// stream with the renderer lock unlocked but with the interface lock locked +// We must do this because we call timeKillEvent, our timer callback method +// has to take the renderer lock to serialise our state. Therefore holding a +// renderer lock when calling timeKillEvent could cause a deadlock condition + +STDMETHODIMP CRendererInputPin::BeginFlush() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + { + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + CBaseInputPin::BeginFlush(); + m_pRenderer->BeginFlush(); + } + return m_pRenderer->ResetEndOfStream(); +} + + +// Signals end of flushing on the input pin + +STDMETHODIMP CRendererInputPin::EndFlush() +{ + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); + + HRESULT hr = m_pRenderer->EndFlush(); + if (SUCCEEDED(hr)) { + hr = CBaseInputPin::EndFlush(); + } + return hr; +} + + +// Pass the sample straight through to the renderer object + +STDMETHODIMP CRendererInputPin::Receive(IMediaSample *pSample) +{ + HRESULT hr = m_pRenderer->Receive(pSample); + if (FAILED(hr)) { + + // A deadlock could occur if the caller holds the renderer lock and + // attempts to acquire the interface lock. + ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock)); + + { + // The interface lock must be held when the filter is calling + // IsStopped() or IsFlushing(). The interface lock must also + // be held because the function uses m_bRunTimeError. + CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); + + // We do not report errors which occur while the filter is stopping, + // flushing or if the m_bAbort flag is set . Errors are expected to + // occur during these operations and the streaming thread correctly + // handles the errors. + if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) { + + // EC_ERRORABORT's first parameter is the error which caused + // the event and its' last parameter is 0. See the Direct + // Show SDK documentation for more information. + m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0); + + { + CAutoLock alRendererLock(&m_pRenderer->m_RendererLock); + if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) { + m_pRenderer->NotifyEndOfStream(); + } + } + + m_bRunTimeError = TRUE; + } + } + } + + return hr; +} + + +// Called when the input pin is disconnected + +HRESULT CRendererInputPin::BreakConnect() +{ + HRESULT hr = m_pRenderer->BreakConnect(); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::BreakConnect(); +} + + +// Called when the input pin is connected + +HRESULT CRendererInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CompleteConnect(pReceivePin); +} + + +// Give the pin id of our one and only pin + +STDMETHODIMP CRendererInputPin::QueryId(__deref_out LPWSTR *Id) +{ + CheckPointer(Id,E_POINTER); + + const WCHAR szIn[] = L"In"; + + *Id = (LPWSTR)CoTaskMemAlloc(sizeof(szIn)); + if (*Id == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(*Id, szIn, sizeof(szIn)); + return NOERROR; +} + + +// Will the filter accept this media type + +HRESULT CRendererInputPin::CheckMediaType(const CMediaType *pmt) +{ + return m_pRenderer->CheckMediaType(pmt); +} + + +// Called when we go paused or running + +HRESULT CRendererInputPin::Active() +{ + return m_pRenderer->Active(); +} + + +// Called when we go into a stopped state + +HRESULT CRendererInputPin::Inactive() +{ + // The caller must hold the interface lock because + // this function uses m_bRunTimeError. + ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock)); + + m_bRunTimeError = FALSE; + + return m_pRenderer->Inactive(); +} + + +// Tell derived classes about the media type agreed + +HRESULT CRendererInputPin::SetMediaType(const CMediaType *pmt) +{ + HRESULT hr = CBaseInputPin::SetMediaType(pmt); + if (FAILED(hr)) { + return hr; + } + return m_pRenderer->SetMediaType(pmt); +} + + +// We do not keep an event object to use when setting up a timer link with +// the clock but are given a pointer to one by the owning object through the +// SetNotificationObject method - this must be initialised before starting +// We can override the default quality management process to have it always +// draw late frames, this is currently done by having the following registry +// key (actually an INI key) called DrawLateFrames set to 1 (default is 0) + +const TCHAR AMQUALITY[] = TEXT("ActiveMovie"); +const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames"); + +CBaseVideoRenderer::CBaseVideoRenderer( + REFCLSID RenderClass, // CLSID for this renderer + __in_opt LPCTSTR pName, // Debug ONLY description + __inout_opt LPUNKNOWN pUnk, // Aggregated owner object + __inout HRESULT *phr) : // General OLE return code + + CBaseRenderer(RenderClass,pName,pUnk,phr), + m_cFramesDropped(0), + m_cFramesDrawn(0), + m_bSupplierHandlingQuality(FALSE) +{ + ResetStreamingTimes(); + +#ifdef PERF + m_idTimeStamp = MSR_REGISTER(TEXT("Frame time stamp")); + m_idEarliness = MSR_REGISTER(TEXT("Earliness fudge")); + m_idTarget = MSR_REGISTER(TEXT("Target (mSec)")); + m_idSchLateTime = MSR_REGISTER(TEXT("mSec late when scheduled")); + m_idDecision = MSR_REGISTER(TEXT("Scheduler decision code")); + m_idQualityRate = MSR_REGISTER(TEXT("Quality rate sent")); + m_idQualityTime = MSR_REGISTER(TEXT("Quality time sent")); + m_idWaitReal = MSR_REGISTER(TEXT("Render wait")); + // m_idWait = MSR_REGISTER(TEXT("wait time recorded (msec)")); + m_idFrameAccuracy = MSR_REGISTER(TEXT("Frame accuracy (msecs)")); + m_bDrawLateFrames = GetProfileInt(AMQUALITY, DRAWLATEFRAMES, FALSE); + //m_idSendQuality = MSR_REGISTER(TEXT("Processing Quality message")); + + m_idRenderAvg = MSR_REGISTER(TEXT("Render draw time Avg")); + m_idFrameAvg = MSR_REGISTER(TEXT("FrameAvg")); + m_idWaitAvg = MSR_REGISTER(TEXT("WaitAvg")); + m_idDuration = MSR_REGISTER(TEXT("Duration")); + m_idThrottle = MSR_REGISTER(TEXT("Audio-video throttle wait")); + // m_idDebug = MSR_REGISTER(TEXT("Debug stuff")); +#endif // PERF +} // Constructor + + +// Destructor is just a placeholder + +CBaseVideoRenderer::~CBaseVideoRenderer() +{ + ASSERT(m_dwAdvise == 0); +} + + +// The timing functions in this class are called by the window object and by +// the renderer's allocator. +// The windows object calls timing functions as it receives media sample +// images for drawing using GDI. +// The allocator calls timing functions when it starts passing DCI/DirectDraw +// surfaces which are not rendered in the same way; The decompressor writes +// directly to the surface with no separate rendering, so those code paths +// call direct into us. Since we only ever hand out DCI/DirectDraw surfaces +// when we have allocated one and only one image we know there cannot be any +// conflict between the two. +// +// We use timeGetTime to return the timing counts we use (since it's relative +// performance we are interested in rather than absolute compared to a clock) +// The window object sets the accuracy of the system clock (normally 1ms) by +// calling timeBeginPeriod/timeEndPeriod when it changes streaming states + + +// Reset all times controlling streaming. +// Set them so that +// 1. Frames will not initially be dropped +// 2. The first frame will definitely be drawn (achieved by saying that there +// has not ben a frame drawn for a long time). + +HRESULT CBaseVideoRenderer::ResetStreamingTimes() +{ + m_trLastDraw = -1000; // set up as first frame since ages (1 sec) ago + m_tStreamingStart = timeGetTime(); + m_trRenderAvg = 0; + m_trFrameAvg = -1; // -1000 fps == "unset" + m_trDuration = 0; // 0 - strange value + m_trRenderLast = 0; + m_trWaitAvg = 0; + m_tRenderStart = 0; + m_cFramesDrawn = 0; + m_cFramesDropped = 0; + m_iTotAcc = 0; + m_iSumSqAcc = 0; + m_iSumSqFrameTime = 0; + m_trFrame = 0; // hygeine - not really needed + m_trLate = 0; // hygeine - not really needed + m_iSumFrameTime = 0; + m_nNormal = 0; + m_trEarliness = 0; + m_trTarget = -300000; // 30mSec early + m_trThrottle = 0; + m_trRememberStampForPerf = 0; + +#ifdef PERF + m_trRememberFrameForPerf = 0; +#endif + + return NOERROR; +} // ResetStreamingTimes + + +// Reset all times controlling streaming. Note that we're now streaming. We +// don't need to set the rendering event to have the source filter released +// as it is done during the Run processing. When we are run we immediately +// release the source filter thread and draw any image waiting (that image +// may already have been drawn once as a poster frame while we were paused) + +HRESULT CBaseVideoRenderer::OnStartStreaming() +{ + ResetStreamingTimes(); + return NOERROR; +} // OnStartStreaming + + +// Called at end of streaming. Fixes times for property page report + +HRESULT CBaseVideoRenderer::OnStopStreaming() +{ + m_tStreamingStart = timeGetTime()-m_tStreamingStart; + return NOERROR; +} // OnStopStreaming + + +// Called when we start waiting for a rendering event. +// Used to update times spent waiting and not waiting. + +void CBaseVideoRenderer::OnWaitStart() +{ + MSR_START(m_idWaitReal); +} // OnWaitStart + + +// Called when we are awoken from the wait in the window OR by our allocator +// when it is hanging around until the next sample is due for rendering on a +// DCI/DirectDraw surface. We add the wait time into our rolling average. +// We grab the interface lock so that we're serialised with the application +// thread going through the run code - which in due course ends up calling +// ResetStreaming times - possibly as we run through this section of code + +void CBaseVideoRenderer::OnWaitEnd() +{ +#ifdef PERF + MSR_STOP(m_idWaitReal); + // for a perf build we want to know just exactly how late we REALLY are. + // even if this means that we have to look at the clock again. + + REFERENCE_TIME trRealStream; // the real time now expressed as stream time. +#if 0 + m_pClock->GetTime(&trRealStream); // Calling clock here causes W95 deadlock! +#else + // We will be discarding overflows like mad here! + // This is wrong really because timeGetTime() can wrap but it's + // only for PERF + REFERENCE_TIME tr = timeGetTime()*10000; + trRealStream = tr + m_llTimeOffset; +#endif + trRealStream -= m_tStart; // convert to stream time (this is a reftime) + + if (m_trRememberStampForPerf==0) { + // This is probably the poster frame at the start, and it is not scheduled + // in the usual way at all. Just count it. The rememberstamp gets set + // in ShouldDrawSampleNow, so this does invalid frame recording until we + // actually start playing. + PreparePerformanceData(0, 0); + } else { + int trLate = (int)(trRealStream - m_trRememberStampForPerf); + int trFrame = (int)(tr - m_trRememberFrameForPerf); + PreparePerformanceData(trLate, trFrame); + } + m_trRememberFrameForPerf = tr; +#endif //PERF +} // OnWaitEnd + + +// Put data on one side that describes the lateness of the current frame. +// We don't yet know whether it will actually be drawn. In direct draw mode, +// this decision is up to the filter upstream, and it could change its mind. +// The rules say that if it did draw it must call Receive(). One way or +// another we eventually get into either OnRenderStart or OnDirectRender and +// these both call RecordFrameLateness to update the statistics. + +void CBaseVideoRenderer::PreparePerformanceData(int trLate, int trFrame) +{ + m_trLate = trLate; + m_trFrame = trFrame; +} // PreparePerformanceData + + +// update the statistics: +// m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn +// Note that because the properties page reports using these variables, +// 1. We need to be inside a critical section +// 2. They must all be updated together. Updating the sums here and the count +// elsewhere can result in imaginary jitter (i.e. attempts to find square roots +// of negative numbers) in the property page code. + +void CBaseVideoRenderer::RecordFrameLateness(int trLate, int trFrame) +{ + // Record how timely we are. + int tLate = trLate/10000; + + // Best estimate of moment of appearing on the screen is average of + // start and end draw times. Here we have only the end time. This may + // tend to show us as spuriously late by up to 1/2 frame rate achieved. + // Decoder probably monitors draw time. We don't bother. + MSR_INTEGER( m_idFrameAccuracy, tLate ); + + // This is a kludge - we can get frames that are very late + // especially (at start-up) and they invalidate the statistics. + // So ignore things that are more than 1 sec off. + if (tLate>1000 || tLate<-1000) { + if (m_cFramesDrawn<=1) { + tLate = 0; + } else if (tLate>0) { + tLate = 1000; + } else { + tLate = -1000; + } + } + // The very first frame often has a invalid time, so don't + // count it into the statistics. (???) + if (m_cFramesDrawn>1) { + m_iTotAcc += tLate; + m_iSumSqAcc += (tLate*tLate); + } + + // calculate inter-frame time. Doesn't make sense for first frame + // second frame suffers from invalid first frame stamp. + if (m_cFramesDrawn>2) { + int tFrame = trFrame/10000; // convert to mSec else it overflows + + // This is a kludge. It can overflow anyway (a pause can cause + // a very long inter-frame time) and it overflows at 2**31/10**7 + // or about 215 seconds i.e. 3min 35sec + if (tFrame>1000||tFrame<0) tFrame = 1000; + m_iSumSqFrameTime += tFrame*tFrame; + ASSERT(m_iSumSqFrameTime>=0); + m_iSumFrameTime += tFrame; + } + ++m_cFramesDrawn; + +} // RecordFrameLateness + + +void CBaseVideoRenderer::ThrottleWait() +{ + if (m_trThrottle>0) { + int iThrottle = m_trThrottle/10000; // convert to mSec + MSR_INTEGER( m_idThrottle, iThrottle); + DbgLog((LOG_TRACE, 0, TEXT("Throttle %d ms"), iThrottle)); + Sleep(iThrottle); + } else { + Sleep(0); + } +} // ThrottleWait + + +// Whenever a frame is rendered it goes though either OnRenderStart +// or OnDirectRender. Data that are generated during ShouldDrawSample +// are added to the statistics by calling RecordFrameLateness from both +// these two places. + +// Called in place of OnRenderStart..OnRenderEnd +// When a DirectDraw image is drawn +void CBaseVideoRenderer::OnDirectRender(IMediaSample *pMediaSample) +{ + m_trRenderAvg = 0; + m_trRenderLast = 5000000; // If we mode switch, we do NOT want this + // to inhibit the new average getting going! + // so we set it to half a second + // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); + RecordFrameLateness(m_trLate, m_trFrame); + ThrottleWait(); +} // OnDirectRender + + +// Called just before we start drawing. All we do is to get the current clock +// time (from the system) and return. We have to store the start render time +// in a member variable because it isn't used until we complete the drawing +// The rest is just performance logging. + +void CBaseVideoRenderer::OnRenderStart(IMediaSample *pMediaSample) +{ + RecordFrameLateness(m_trLate, m_trFrame); + m_tRenderStart = timeGetTime(); +} // OnRenderStart + + +// Called directly after drawing an image. We calculate the time spent in the +// drawing code and if this doesn't appear to have any odd looking spikes in +// it then we add it to the current average draw time. Measurement spikes may +// occur if the drawing thread is interrupted and switched to somewhere else. + +void CBaseVideoRenderer::OnRenderEnd(IMediaSample *pMediaSample) +{ + // The renderer time can vary erratically if we are interrupted so we do + // some smoothing to help get more sensible figures out but even that is + // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83 + + int tr = (timeGetTime() - m_tRenderStart)*10000; // convert mSec->UNITS + if (tr < m_trRenderAvg*2 || tr < 2 * m_trRenderLast) { + // DO_MOVING_AVG(m_trRenderAvg, tr); + m_trRenderAvg = (tr + (AVGPERIOD-1)*m_trRenderAvg)/AVGPERIOD; + } + m_trRenderLast = tr; + ThrottleWait(); +} // OnRenderEnd + + +STDMETHODIMP CBaseVideoRenderer::SetSink( IQualityControl * piqc) +{ + + m_pQSink = piqc; + + return NOERROR; +} // SetSink + + +STDMETHODIMP CBaseVideoRenderer::Notify( IBaseFilter * pSelf, Quality q) +{ + // NOTE: We are NOT getting any locks here. We could be called + // asynchronously and possibly even on a time critical thread of + // someone else's - so we do the minumum. We only set one state + // variable (an integer) and if that happens to be in the middle + // of another thread reading it they will just get either the new + // or the old value. Locking would achieve no more than this. + + // It might be nice to check that we are being called from m_pGraph, but + // it turns out to be a millisecond or so per throw! + + // This is heuristics, these numbers are aimed at being "what works" + // rather than anything based on some theory. + // We use a hyperbola because it's easy to calculate and it includes + // a panic button asymptote (which we push off just to the left) + // The throttling fits the following table (roughly) + // Proportion Throttle (msec) + // >=1000 0 + // 900 3 + // 800 7 + // 700 11 + // 600 17 + // 500 25 + // 400 35 + // 300 50 + // 200 72 + // 125 100 + // 100 112 + // 50 146 + // 0 200 + + // (some evidence that we could go for a sharper kink - e.g. no throttling + // until below the 750 mark - might give fractionally more frames on a + // P60-ish machine). The easy way to get these coefficients is to use + // Renbase.xls follow the instructions therein using excel solver. + + if (q.Proportion>=1000) { m_trThrottle = 0; } + else { + // The DWORD is to make quite sure I get unsigned arithmetic + // as the constant is between 2**31 and 2**32 + m_trThrottle = -330000 + (388880000/(q.Proportion+167)); + } + return NOERROR; +} // Notify + + +// Send a message to indicate what our supplier should do about quality. +// Theory: +// What a supplier wants to know is "is the frame I'm working on NOW +// going to be late?". +// F1 is the frame at the supplier (as above) +// Tf1 is the due time for F1 +// T1 is the time at that point (NOW!) +// Tr1 is the time that f1 WILL actually be rendered +// L1 is the latency of the graph for frame F1 = Tr1-T1 +// D1 (for delay) is how late F1 will be beyond its due time i.e. +// D1 = (Tr1-Tf1) which is what the supplier really wants to know. +// Unfortunately Tr1 is in the future and is unknown, so is L1 +// +// We could estimate L1 by its value for a previous frame, +// L0 = Tr0-T0 and work off +// D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1) +// Rearranging terms: +// D1' = (T1-T0) + (Tr0-Tf1) +// adding (Tf0-Tf0) and rearranging again: +// = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1) +// = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0) +// But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the +// Late field in the quality message that we send. +// The other two terms just state what correction should be applied before +// using the lateness of F0 to predict the lateness of F1. +// (T1-T0) says how much time has actually passed (we have lost this much) +// (Tf1-Tf0) says how much time should have passed if we were keeping pace +// (we have gained this much). +// +// Suppliers should therefore work off: +// Quality.Late + (T1-T0) - (Tf1-Tf0) +// and see if this is "acceptably late" or even early (i.e. negative). +// They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from +// the time stamps in the frames. They get Quality.Late from us. +// + +HRESULT CBaseVideoRenderer::SendQuality(REFERENCE_TIME trLate, + REFERENCE_TIME trRealStream) +{ + Quality q; + HRESULT hr; + + // If we are the main user of time, then report this as Flood/Dry. + // If our suppliers are, then report it as Famine/Glut. + // + // We need to take action, but avoid hunting. Hunting is caused by + // 1. Taking too much action too soon and overshooting + // 2. Taking too long to react (so averaging can CAUSE hunting). + // + // The reason why we use trLate as well as Wait is to reduce hunting; + // if the wait time is coming down and about to go into the red, we do + // NOT want to rely on some average which is only telling is that it used + // to be OK once. + + q.TimeStamp = (REFERENCE_TIME)trRealStream; + + if (m_trFrameAvg<0) { + q.Type = Famine; // guess + } + // Is the greater part of the time taken bltting or something else + else if (m_trFrameAvg > 2*m_trRenderAvg) { + q.Type = Famine; // mainly other + } else { + q.Type = Flood; // mainly bltting + } + + q.Proportion = 1000; // default + + if (m_trFrameAvg<0) { + // leave it alone - we don't know enough + } + else if ( trLate> 0 ) { + // try to catch up over the next second + // We could be Really, REALLY late, but rendering all the frames + // anyway, just because it's so cheap. + + q.Proportion = 1000 - (int)((trLate)/(UNITS/1000)); + if (q.Proportion<500) { + q.Proportion = 500; // don't go daft. (could've been negative!) + } else { + } + + } else if ( m_trWaitAvg>20000 + && trLate<-20000 + ){ + // Go cautiously faster - aim at 2mSec wait. + if (m_trWaitAvg>=m_trFrameAvg) { + // This can happen because of some fudges. + // The waitAvg is how long we originally planned to wait + // The frameAvg is more honest. + // It means that we are spending a LOT of time waiting + q.Proportion = 2000; // double. + } else { + if (m_trFrameAvg+20000 > m_trWaitAvg) { + q.Proportion + = 1000 * (m_trFrameAvg / (m_trFrameAvg + 20000 - m_trWaitAvg)); + } else { + // We're apparently spending more than the whole frame time waiting. + // Assume that the averages are slightly out of kilter, but that we + // are indeed doing a lot of waiting. (This leg probably never + // happens, but the code avoids any potential divide by zero). + q.Proportion = 2000; + } + } + + if (q.Proportion>2000) { + q.Proportion = 2000; // don't go crazy. + } + } + + // Tell the supplier how late frames are when they get rendered + // That's how late we are now. + // If we are in directdraw mode then the guy upstream can see the drawing + // times and we'll just report on the start time. He can figure out any + // offset to apply. If we are in DIB Section mode then we will apply an + // extra offset which is half of our drawing time. This is usually small + // but can sometimes be the dominant effect. For this we will use the + // average drawing time rather than the last frame. If the last frame took + // a long time to draw and made us late, that's already in the lateness + // figure. We should not add it in again unless we expect the next frame + // to be the same. We don't, we expect the average to be a better shot. + // In direct draw mode the RenderAvg will be zero. + + q.Late = trLate + m_trRenderAvg/2; + + // log what we're doing + MSR_INTEGER(m_idQualityRate, q.Proportion); + MSR_INTEGER( m_idQualityTime, (int)q.Late / 10000 ); + + // A specific sink interface may be set through IPin + + if (m_pQSink==NULL) { + // Get our input pin's peer. We send quality management messages + // to any nominated receiver of these things (set in the IPin + // interface), or else to our source filter. + + IQualityControl *pQC = NULL; + IPin *pOutputPin = m_pInputPin->GetConnected(); + ASSERT(pOutputPin != NULL); + + // And get an AddRef'd quality control interface + + hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC); + if (SUCCEEDED(hr)) { + m_pQSink = pQC; + } + } + if (m_pQSink) { + return m_pQSink->Notify(this,q); + } + + return S_FALSE; + +} // SendQuality + + +// We are called with a valid IMediaSample image to decide whether this is to +// be drawn or not. There must be a reference clock in operation. +// Return S_OK if it is to be drawn Now (as soon as possible) +// Return S_FALSE if it is to be drawn when it's due +// Return an error if we want to drop it +// m_nNormal=-1 indicates that we dropped the previous frame and so this +// one should be drawn early. Respect it and update it. +// Use current stream time plus a number of heuristics (detailed below) +// to make the decision + +HRESULT CBaseVideoRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample, + __inout REFERENCE_TIME *ptrStart, + __inout REFERENCE_TIME *ptrEnd) +{ + + // Don't call us unless there's a clock interface to synchronise with + ASSERT(m_pClock); + + MSR_INTEGER(m_idTimeStamp, (int)((*ptrStart)>>32)); // high order 32 bits + MSR_INTEGER(m_idTimeStamp, (int)(*ptrStart)); // low order 32 bits + + // We lose a bit of time depending on the monitor type waiting for the next + // screen refresh. On average this might be about 8mSec - so it will be + // later than we think when the picture appears. To compensate a bit + // we bias the media samples by -8mSec i.e. 80000 UNITs. + // We don't ever make a stream time negative (call it paranoia) + if (*ptrStart>=80000) { + *ptrStart -= 80000; + *ptrEnd -= 80000; // bias stop to to retain valid frame duration + } + + // Cache the time stamp now. We will want to compare what we did with what + // we started with (after making the monitor allowance). + m_trRememberStampForPerf = *ptrStart; + + // Get reference times (current and late) + REFERENCE_TIME trRealStream; // the real time now expressed as stream time. + m_pClock->GetTime(&trRealStream); +#ifdef PERF + // While the reference clock is expensive: + // Remember the offset from timeGetTime and use that. + // This overflows all over the place, but when we subtract to get + // differences the overflows all cancel out. + m_llTimeOffset = trRealStream-timeGetTime()*10000; +#endif + trRealStream -= m_tStart; // convert to stream time (this is a reftime) + + // We have to wory about two versions of "lateness". The truth, which we + // try to work out here and the one measured against m_trTarget which + // includes long term feedback. We report statistics against the truth + // but for operational decisions we work to the target. + // We use TimeDiff to make sure we get an integer because we + // may actually be late (or more likely early if there is a big time + // gap) by a very long time. + const int trTrueLate = TimeDiff(trRealStream - *ptrStart); + const int trLate = trTrueLate; + + MSR_INTEGER(m_idSchLateTime, trTrueLate/10000); + + // Send quality control messages upstream, measured against target + HRESULT hr = SendQuality(trLate, trRealStream); + // Note: the filter upstream is allowed to this FAIL meaning "you do it". + m_bSupplierHandlingQuality = (hr==S_OK); + + // Decision time! Do we drop, draw when ready or draw immediately? + + const int trDuration = (int)(*ptrEnd - *ptrStart); + { + // We need to see if the frame rate of the file has just changed. + // This would make comparing our previous frame rate with the current + // frame rate inefficent. Hang on a moment though. I've seen files + // where the frames vary between 33 and 34 mSec so as to average + // 30fps. A minor variation like that won't hurt us. + int t = m_trDuration/32; + if ( trDuration > m_trDuration+t + || trDuration < m_trDuration-t + ) { + // There's a major variation. Reset the average frame rate to + // exactly the current rate to disable decision 9002 for this frame, + // and remember the new rate. + m_trFrameAvg = trDuration; + m_trDuration = trDuration; + } + } + + MSR_INTEGER(m_idEarliness, m_trEarliness/10000); + MSR_INTEGER(m_idRenderAvg, m_trRenderAvg/10000); + MSR_INTEGER(m_idFrameAvg, m_trFrameAvg/10000); + MSR_INTEGER(m_idWaitAvg, m_trWaitAvg/10000); + MSR_INTEGER(m_idDuration, trDuration/10000); + +#ifdef PERF + if (S_OK==pMediaSample->IsDiscontinuity()) { + MSR_INTEGER(m_idDecision, 9000); + } +#endif + + // Control the graceful slide back from slow to fast machine mode. + // After a frame drop accept an early frame and set the earliness to here + // If this frame is already later than the earliness then slide it to here + // otherwise do the standard slide (reduce by about 12% per frame). + // Note: earliness is normally NEGATIVE + BOOL bJustDroppedFrame + = ( m_bSupplierHandlingQuality + // Can't use the pin sample properties because we might + // not be in Receive when we call this + && (S_OK == pMediaSample->IsDiscontinuity()) // he just dropped one + ) + || (m_nNormal==-1); // we just dropped one + + + // Set m_trEarliness (slide back from slow to fast machine mode) + if (trLate>0) { + m_trEarliness = 0; // we are no longer in fast machine mode at all! + } else if ( (trLate>=m_trEarliness) || bJustDroppedFrame) { + m_trEarliness = trLate; // Things have slipped of their own accord + } else { + m_trEarliness = m_trEarliness - m_trEarliness/8; // graceful slide + } + + // prepare the new wait average - but don't pollute the old one until + // we have finished with it. + int trWaitAvg; + { + // We never mix in a negative wait. This causes us to believe in fast machines + // slightly more. + int trL = trLate<0 ? -trLate : 0; + trWaitAvg = (trL + m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; + } + + + int trFrame; + { + REFERENCE_TIME tr = trRealStream - m_trLastDraw; // Cd be large - 4 min pause! + if (tr>10000000) { + tr = 10000000; // 1 second - arbitrarily. + } + trFrame = int(tr); + } + + // We will DRAW this frame IF... + if ( + // ...the time we are spending drawing is a small fraction of the total + // observed inter-frame time so that dropping it won't help much. + (3*m_trRenderAvg <= m_trFrameAvg) + + // ...or our supplier is NOT handling things and the next frame would + // be less timely than this one or our supplier CLAIMS to be handling + // things, and is now less than a full FOUR frames late. + || ( m_bSupplierHandlingQuality + ? (trLate <= trDuration*4) + : (trLate+trLate < trDuration) + ) + + // ...or we are on average waiting for over eight milliseconds then + // this may be just a glitch. Draw it and we'll hope to catch up. + || (m_trWaitAvg > 80000) + + // ...or we haven't drawn an image for over a second. We will update + // the display, which stops the video looking hung. + // Do this regardless of how late this media sample is. + || ((trRealStream - m_trLastDraw) > UNITS) + + ) { + HRESULT Result; + + // We are going to play this frame. We may want to play it early. + // We will play it early if we think we are in slow machine mode. + // If we think we are NOT in slow machine mode, we will still play + // it early by m_trEarliness as this controls the graceful slide back. + // and in addition we aim at being m_trTarget late rather than "on time". + + BOOL bPlayASAP = FALSE; + + // we will play it AT ONCE (slow machine mode) if... + + // ...we are playing catch-up + if ( bJustDroppedFrame) { + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9001); + } + + // ...or if we are running below the true frame rate + // exact comparisons are glitchy, for these measurements, + // so add an extra 5% or so + else if ( (m_trFrameAvg > trDuration + trDuration/16) + + // It's possible to get into a state where we are losing ground, but + // are a very long way ahead. To avoid this or recover from it + // we refuse to play early by more than 10 frames. + && (trLate > - trDuration*10) + ){ + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9002); + } +#if 0 + // ...or if we have been late and are less than one frame early + else if ( (trLate + trDuration > 0) + && (m_trWaitAvg<=20000) + ) { + bPlayASAP = TRUE; + MSR_INTEGER(m_idDecision, 9003); + } +#endif + // We will NOT play it at once if we are grossly early. On very slow frame + // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just + // because we got starved (for instance by the net) and dropped one frame + // some time or other. If we are more than 900mSec early, then wait. + if (trLate<-9000000) { + bPlayASAP = FALSE; + } + + if (bPlayASAP) { + + m_nNormal = 0; + MSR_INTEGER(m_idDecision, 0); + // When we are here, we are in slow-machine mode. trLate may well + // oscillate between negative and positive when the supplier is + // dropping frames to keep sync. We should not let that mislead + // us into thinking that we have as much as zero spare time! + // We just update with a zero wait. + m_trWaitAvg = (m_trWaitAvg*(AVGPERIOD-1))/AVGPERIOD; + + // Assume that we draw it immediately. Update inter-frame stats + m_trFrameAvg = (trFrame + m_trFrameAvg*(AVGPERIOD-1))/AVGPERIOD; +#ifndef PERF + // If this is NOT a perf build, then report what we know so far + // without looking at the clock any more. This assumes that we + // actually wait for exactly the time we hope to. It also reports + // how close we get to the manipulated time stamps that we now have + // rather than the ones we originally started with. It will + // therefore be a little optimistic. However it's fast. + PreparePerformanceData(trTrueLate, trFrame); +#endif + m_trLastDraw = trRealStream; + if (m_trEarliness > trLate) { + m_trEarliness = trLate; // if we are actually early, this is neg + } + Result = S_OK; // Draw it now + + } else { + ++m_nNormal; + // Set the average frame rate to EXACTLY the ideal rate. + // If we are exiting slow-machine mode then we will have caught up + // and be running ahead, so as we slide back to exact timing we will + // have a longer than usual gap at this point. If we record this + // real gap then we'll think that we're running slow and go back + // into slow-machine mode and vever get it straight. + m_trFrameAvg = trDuration; + MSR_INTEGER(m_idDecision, 1); + + // Play it early by m_trEarliness and by m_trTarget + + { + int trE = m_trEarliness; + if (trE < -m_trFrameAvg) { + trE = -m_trFrameAvg; + } + *ptrStart += trE; // N.B. earliness is negative + } + + int Delay = -trTrueLate; + Result = Delay<=0 ? S_OK : S_FALSE; // OK = draw now, FALSE = wait + + m_trWaitAvg = trWaitAvg; + + // Predict when it will actually be drawn and update frame stats + + if (Result==S_FALSE) { // We are going to wait + trFrame = TimeDiff(*ptrStart-m_trLastDraw); + m_trLastDraw = *ptrStart; + } else { + // trFrame is already = trRealStream-m_trLastDraw; + m_trLastDraw = trRealStream; + } +#ifndef PERF + int iAccuracy; + if (Delay>0) { + // Report lateness based on when we intend to play it + iAccuracy = TimeDiff(*ptrStart-m_trRememberStampForPerf); + } else { + // Report lateness based on playing it *now*. + iAccuracy = trTrueLate; // trRealStream-RememberStampForPerf; + } + PreparePerformanceData(iAccuracy, trFrame); +#endif + } + return Result; + } + + // We are going to drop this frame! + // Of course in DirectDraw mode the guy upstream may draw it anyway. + + // This will probably give a large negative wack to the wait avg. + m_trWaitAvg = trWaitAvg; + +#ifdef PERF + // Respect registry setting - debug only! + if (m_bDrawLateFrames) { + return S_OK; // draw it when it's ready + } // even though it's late. +#endif + + // We are going to drop this frame so draw the next one early + // n.b. if the supplier is doing direct draw then he may draw it anyway + // but he's doing something funny to arrive here in that case. + + MSR_INTEGER(m_idDecision, 2); + m_nNormal = -1; + return E_FAIL; // drop it + +} // ShouldDrawSampleNow + + +// NOTE we're called by both the window thread and the source filter thread +// so we have to be protected by a critical section (locked before called) +// Also, when the window thread gets signalled to render an image, it always +// does so regardless of how late it is. All the degradation is done when we +// are scheduling the next sample to be drawn. Hence when we start an advise +// link to draw a sample, that sample's time will always become the last one +// drawn - unless of course we stop streaming in which case we cancel links + +BOOL CBaseVideoRenderer::ScheduleSample(IMediaSample *pMediaSample) +{ + // We override ShouldDrawSampleNow to add quality management + + BOOL bDrawImage = CBaseRenderer::ScheduleSample(pMediaSample); + if (bDrawImage == FALSE) { + ++m_cFramesDropped; + return FALSE; + } + + // m_cFramesDrawn must NOT be updated here. It has to be updated + // in RecordFrameLateness at the same time as the other statistics. + return TRUE; +} + + +// Implementation of IQualProp interface needed to support the property page +// This is how the property page gets the data out of the scheduler. We are +// passed into the constructor the owning object in the COM sense, this will +// either be the video renderer or an external IUnknown if we're aggregated. +// We initialise our CUnknown base class with this interface pointer. Then +// all we have to do is to override NonDelegatingQueryInterface to expose +// our IQualProp interface. The AddRef and Release are handled automatically +// by the base class and will be passed on to the appropriate outer object + +STDMETHODIMP CBaseVideoRenderer::get_FramesDroppedInRenderer(__out int *pcFramesDropped) +{ + CheckPointer(pcFramesDropped,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + *pcFramesDropped = m_cFramesDropped; + return NOERROR; +} // get_FramesDroppedInRenderer + + +// Set *pcFramesDrawn to the number of frames drawn since +// streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_FramesDrawn( int *pcFramesDrawn) +{ + CheckPointer(pcFramesDrawn,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + *pcFramesDrawn = m_cFramesDrawn; + return NOERROR; +} // get_FramesDrawn + + +// Set iAvgFrameRate to the frames per hundred secs since +// streaming started. 0 otherwise. + +STDMETHODIMP CBaseVideoRenderer::get_AvgFrameRate( int *piAvgFrameRate) +{ + CheckPointer(piAvgFrameRate,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + int t; + if (m_bStreaming) { + t = timeGetTime()-m_tStreamingStart; + } else { + t = m_tStreamingStart; + } + + if (t<=0) { + *piAvgFrameRate = 0; + ASSERT(m_cFramesDrawn == 0); + } else { + // i is frames per hundred seconds + *piAvgFrameRate = MulDiv(100000, m_cFramesDrawn, t); + } + return NOERROR; +} // get_AvgFrameRate + + +// Set *piAvg to the average sync offset since streaming started +// in mSec. The sync offset is the time in mSec between when the frame +// should have been drawn and when the frame was actually drawn. + +STDMETHODIMP CBaseVideoRenderer::get_AvgSyncOffset(__out int *piAvg) +{ + CheckPointer(piAvg,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + if (NULL==m_pClock) { + *piAvg = 0; + return NOERROR; + } + + // Note that we didn't gather the stats on the first frame + // so we use m_cFramesDrawn-1 here + if (m_cFramesDrawn<=1) { + *piAvg = 0; + } else { + *piAvg = (int)(m_iTotAcc / (m_cFramesDrawn-1)); + } + return NOERROR; +} // get_AvgSyncOffset + + +// To avoid dragging in the maths library - a cheap +// approximate integer square root. +// We do this by getting a starting guess which is between 1 +// and 2 times too large, followed by THREE iterations of +// Newton Raphson. (That will give accuracy to the nearest mSec +// for the range in question - roughly 0..1000) +// +// It would be faster to use a linear interpolation and ONE NR, but +// who cares. If anyone does - the best linear interpolation is +// to approximates sqrt(x) by +// y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1)) +// 0r y = x*0.41421 + 0.59467 +// This minimises the maximal error in the range in question. +// (error is about +0.008883 and then one NR will give error .0000something +// (Of course these are integers, so you can't just multiply by 0.41421 +// you'd have to do some sort of MulDiv). +// Anyone wanna check my maths? (This is only for a property display!) + +int isqrt(int x) +{ + int s = 1; + // Make s an initial guess for sqrt(x) + if (x > 0x40000000) { + s = 0x8000; // prevent any conceivable closed loop + } else { + while (s*s=0) s = (s*s+x)/(2*s); + if (s>=0) s = (s*s+x)/(2*s); + } + } + return s; +} + +// +// Do estimates for standard deviations for per-frame +// statistics +// +HRESULT CBaseVideoRenderer::GetStdDev( + int nSamples, + __out int *piResult, + LONGLONG llSumSq, + LONGLONG iTot +) +{ + CheckPointer(piResult,E_POINTER); + CAutoLock cVideoLock(&m_InterfaceLock); + + if (NULL==m_pClock) { + *piResult = 0; + return NOERROR; + } + + // If S is the Sum of the Squares of observations and + // T the Total (i.e. sum) of the observations and there were + // N observations, then an estimate of the standard deviation is + // sqrt( (S - T**2/N) / (N-1) ) + + if (nSamples<=1) { + *piResult = 0; + } else { + LONGLONG x; + // First frames have invalid stamps, so we get no stats for them + // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 + + // so we use m_cFramesDrawn-1 here + x = llSumSq - llMulDiv(iTot, iTot, nSamples, 0); + x = x / (nSamples-1); + ASSERT(x>=0); + *piResult = isqrt((LONG)x); + } + return NOERROR; +} + +// Set *piDev to the standard deviation in mSec of the sync offset +// of each frame since streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_DevSyncOffset(__out int *piDev) +{ + // First frames have invalid stamps, so we get no stats for them + // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1 + return GetStdDev(m_cFramesDrawn - 1, + piDev, + m_iSumSqAcc, + m_iTotAcc); +} // get_DevSyncOffset + + +// Set *piJitter to the standard deviation in mSec of the inter-frame time +// of frames since streaming started. + +STDMETHODIMP CBaseVideoRenderer::get_Jitter(__out int *piJitter) +{ + // First frames have invalid stamps, so we get no stats for them + // So second frame gives invalid inter-frame time + // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2 + return GetStdDev(m_cFramesDrawn - 2, + piJitter, + m_iSumSqFrameTime, + m_iSumFrameTime); +} // get_Jitter + + +// Overidden to return our IQualProp interface + +STDMETHODIMP +CBaseVideoRenderer::NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv) +{ + // We return IQualProp and delegate everything else + + if (riid == IID_IQualProp) { + return GetInterface( (IQualProp *)this, ppv); + } else if (riid == IID_IQualityControl) { + return GetInterface( (IQualityControl *)this, ppv); + } + return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv); +} + + +// Override JoinFilterGraph so that, just before leaving +// the graph we can send an EC_WINDOW_DESTROYED event + +STDMETHODIMP +CBaseVideoRenderer::JoinFilterGraph(__inout_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName) +{ + // Since we send EC_ACTIVATE, we also need to ensure + // we send EC_WINDOW_DESTROYED or the resource manager may be + // holding us as a focus object + if (!pGraph && m_pGraph) { + + // We were in a graph and now we're not + // Do this properly in case we are aggregated + IBaseFilter* pFilter = this; + NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0); + } + return CBaseFilter::JoinFilterGraph(pGraph, pName); +} + + +// This removes a large number of level 4 warnings from the +// Microsoft compiler which in this case are not very useful +#pragma warning(disable: 4514) + diff --git a/src/thirdparty/BaseClasses/renbase.h b/src/thirdparty/BaseClasses/renbase.h index 5ba24d99ae1..695f07837ea 100644 --- a/src/thirdparty/BaseClasses/renbase.h +++ b/src/thirdparty/BaseClasses/renbase.h @@ -1,478 +1,478 @@ -//------------------------------------------------------------------------------ -// File: RenBase.h -// -// Desc: DirectShow base classes - defines a generic ActiveX base renderer -// class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __RENBASE__ -#define __RENBASE__ - -// Forward class declarations - -class CBaseRenderer; -class CBaseVideoRenderer; -class CRendererInputPin; - -// This is our input pin class that channels calls to the renderer - -class CRendererInputPin : public CBaseInputPin -{ -protected: - - CBaseRenderer *m_pRenderer; - -public: - - CRendererInputPin(__inout CBaseRenderer *pRenderer, - __inout HRESULT *phr, - __in_opt LPCWSTR Name); - - // Overriden from the base pin classes - - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - HRESULT SetMediaType(const CMediaType *pmt); - HRESULT CheckMediaType(const CMediaType *pmt); - HRESULT Active(); - HRESULT Inactive(); - - // Add rendering behaviour to interface functions - - STDMETHODIMP QueryId(__deref_out LPWSTR *Id); - STDMETHODIMP EndOfStream(); - STDMETHODIMP BeginFlush(); - STDMETHODIMP EndFlush(); - STDMETHODIMP Receive(IMediaSample *pMediaSample); - - // Helper - IMemAllocator inline *Allocator() const - { - return m_pAllocator; - } -}; - -// Main renderer class that handles synchronisation and state changes - -class CBaseRenderer : public CBaseFilter -{ -protected: - - friend class CRendererInputPin; - - friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier - UINT uMsg, // Not currently used - DWORD_PTR dwUser, // User information - DWORD_PTR dw1, // Windows reserved - DWORD_PTR dw2); // Is also reserved - - CRendererPosPassThru *m_pPosition; // Media seeking pass by object - CAMEvent m_RenderEvent; // Used to signal timer events - CAMEvent m_ThreadSignal; // Signalled to release worker thread - CAMEvent m_evComplete; // Signalled when state complete - BOOL m_bAbort; // Stop us from rendering more data - BOOL m_bStreaming; // Are we currently streaming - DWORD_PTR m_dwAdvise; // Timer advise cookie - IMediaSample *m_pMediaSample; // Current image media sample - BOOL m_bEOS; // Any more samples in the stream - BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE - CRendererInputPin *m_pInputPin; // Our renderer input pin object - CCritSec m_InterfaceLock; // Critical section for interfaces - CCritSec m_RendererLock; // Controls access to internals - IQualityControl * m_pQSink; // QualityControl sink - BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT - // Avoid some deadlocks by tracking filter during stop - volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive - // And actually processing the sample - REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE - UINT m_EndOfStreamTimer; // Used to signal end of stream - CCritSec m_ObjectCreationLock; // This lock protects the creation and - // of m_pPosition and m_pInputPin. It - // ensures that two threads cannot create - // either object simultaneously. - -public: - - CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer - __in_opt LPCTSTR pName, // Debug ONLY description - __inout_opt LPUNKNOWN pUnk, // Aggregated owner object - __inout HRESULT *phr); // General OLE return code - - ~CBaseRenderer(); - - // Overriden to say what interfaces we support and where - - virtual HRESULT GetMediaPositionInterface(REFIID riid, __deref_out void **ppv); - STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **); - - virtual HRESULT SourceThreadCanWait(BOOL bCanWait); - -#ifdef _DEBUG - // Debug only dump of the renderer state - void DisplayRendererState(); -#endif - virtual HRESULT WaitForRenderTime(); - virtual HRESULT CompleteStateChange(FILTER_STATE OldState); - - // Return internal information about this filter - - BOOL IsEndOfStream() { return m_bEOS; }; - BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; - BOOL IsStreaming() { return m_bStreaming; }; - void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; - virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { }; - CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; - - // Permit access to the transition state - - void Ready() { m_evComplete.Set(); }; - void NotReady() { m_evComplete.Reset(); }; - BOOL CheckReady() { return m_evComplete.Check(); }; - - virtual int GetPinCount(); - virtual CBasePin *GetPin(int n); - FILTER_STATE GetRealState(); - void SendRepaint(); - void SendNotifyWindow(IPin *pPin,HWND hwnd); - BOOL OnDisplayChange(); - void SetRepaintStatus(BOOL bRepaint); - - // Override the filter and pin interface functions - - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - STDMETHODIMP Run(REFERENCE_TIME StartTime); - STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); - STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin); - - // These are available for a quality management implementation - - virtual void OnRenderStart(IMediaSample *pMediaSample); - virtual void OnRenderEnd(IMediaSample *pMediaSample); - virtual HRESULT OnStartStreaming() { return NOERROR; }; - virtual HRESULT OnStopStreaming() { return NOERROR; }; - virtual void OnWaitStart() { }; - virtual void OnWaitEnd() { }; - virtual void PrepareRender() { }; - -#ifdef PERF - REFERENCE_TIME m_trRenderStart; // Just before we started drawing - // Set in OnRenderStart, Used in OnRenderEnd - int m_idBaseStamp; // MSR_id for frame time stamp - int m_idBaseRenderTime; // MSR_id for true wait time - int m_idBaseAccuracy; // MSR_id for time frame is late (int) -#endif - - // Quality management implementation for scheduling rendering - - virtual BOOL ScheduleSample(IMediaSample *pMediaSample); - virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, - __out REFERENCE_TIME *pStartTime, - __out REFERENCE_TIME *pEndTime); - - virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, - __out REFERENCE_TIME *ptrStart, - __out REFERENCE_TIME *ptrEnd); - - // Lots of end of stream complexities - - void TimerCallback(); - void ResetEndOfStreamTimer(); - HRESULT NotifyEndOfStream(); - virtual HRESULT SendEndOfStream(); - virtual HRESULT ResetEndOfStream(); - virtual HRESULT EndOfStream(); - - // Rendering is based around the clock - - void SignalTimerFired(); - virtual HRESULT CancelNotification(); - virtual HRESULT ClearPendingSample(); - - // Called when the filter changes state - - virtual HRESULT Active(); - virtual HRESULT Inactive(); - virtual HRESULT StartStreaming(); - virtual HRESULT StopStreaming(); - virtual HRESULT BeginFlush(); - virtual HRESULT EndFlush(); - - // Deal with connections and type changes - - virtual HRESULT BreakConnect(); - virtual HRESULT SetMediaType(const CMediaType *pmt); - virtual HRESULT CompleteConnect(IPin *pReceivePin); - - // These look after the handling of data samples - - virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); - virtual HRESULT Receive(IMediaSample *pMediaSample); - virtual BOOL HaveCurrentSample(); - virtual IMediaSample *GetCurrentSample(); - virtual HRESULT Render(IMediaSample *pMediaSample); - - // Derived classes MUST override these - virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; - virtual HRESULT CheckMediaType(const CMediaType *) PURE; - - // Helper - void WaitForReceiveToComplete(); -}; - - -// CBaseVideoRenderer is a renderer class (see its ancestor class) and -// it handles scheduling of media samples so that they are drawn at the -// correct time by the reference clock. It implements a degradation -// strategy. Possible degradation modes are: -// Drop frames here (only useful if the drawing takes significant time) -// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip. -// Signal supplier to change the frame rate - i.e. ongoing skipping. -// Or any combination of the above. -// In order to determine what's useful to try we need to know what's going -// on. This is done by timing various operations (including the supplier). -// This timing is done by using timeGetTime as it is accurate enough and -// usually cheaper than calling the reference clock. It also tells the -// truth if there is an audio break and the reference clock stops. -// We provide a number of public entry points (named OnXxxStart, OnXxxEnd) -// which the rest of the renderer calls at significant moments. These do -// the timing. - -// the number of frames that the sliding averages are averaged over. -// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD -#define AVGPERIOD 4 -#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD) -// Spot the bug in this macro - I can't. but it doesn't work! - -class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class - public IQualProp, // Property page guff - public IQualityControl // Allow throttling -{ -protected: - - // Hungarian: - // tFoo is the time Foo in mSec (beware m_tStart from filter.h) - // trBar is the time Bar by the reference clock - - //****************************************************************** - // State variables to control synchronisation - //****************************************************************** - - // Control of sending Quality messages. We need to know whether - // we are in trouble (e.g. frames being dropped) and where the time - // is being spent. - - // When we drop a frame we play the next one early. - // The frame after that is likely to wait before drawing and counting this - // wait as spare time is unfair, so we count it as a zero wait. - // We therefore need to know whether we are playing frames early or not. - - int m_nNormal; // The number of consecutive frames - // drawn at their normal time (not early) - // -1 means we just dropped a frame. - -#ifdef PERF - BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm - // not keen on people using it!) -#endif - - BOOL m_bSupplierHandlingQuality;// The response to Quality messages says - // our supplier is handling things. - // We will allow things to go extra late - // before dropping frames. We will play - // very early after he has dropped one. - - // Control of scheduling, frame dropping etc. - // We need to know where the time is being spent so as to tell whether - // we should be taking action here, signalling supplier or what. - // The variables are initialised to a mode of NOT dropping frames. - // They will tell the truth after a few frames. - // We typically record a start time for an event, later we get the time - // again and subtract to get the elapsed time, and we average this over - // a few frames. The average is used to tell what mode we are in. - - // Although these are reference times (64 bit) they are all DIFFERENCES - // between times which are small. An int will go up to 214 secs before - // overflow. Avoiding 64 bit multiplications and divisions seems - // worth while. - - - - // Audio-video throttling. If the user has turned up audio quality - // very high (in principle it could be any other stream, not just audio) - // then we can receive cries for help via the graph manager. In this case - // we put in a wait for some time after rendering each frame. - int m_trThrottle; - - // The time taken to render (i.e. BitBlt) frames controls which component - // needs to degrade. If the blt is expensive, the renderer degrades. - // If the blt is cheap it's done anyway and the supplier degrades. - int m_trRenderAvg; // Time frames are taking to blt - int m_trRenderLast; // Time for last frame blt - int m_tRenderStart; // Just before we started drawing (mSec) - // derived from timeGetTime. - - // When frames are dropped we will play the next frame as early as we can. - // If it was a false alarm and the machine is fast we slide gently back to - // normal timing. To do this, we record the offset showing just how early - // we really are. This will normally be negative meaning early or zero. - int m_trEarliness; - - // Target provides slow long-term feedback to try to reduce the - // average sync offset to zero. Whenever a frame is actually rendered - // early we add a msec or two, whenever late we take off a few. - // We add or take off 1/32 of the error time. - // Eventually we should be hovering around zero. For a really bad case - // where we were (say) 300mSec off, it might take 100 odd frames to - // settle down. The rate of change of this is intended to be slower - // than any other mechanism in Quartz, thereby avoiding hunting. - int m_trTarget; - - // The proportion of time spent waiting for the right moment to blt - // controls whether we bother to drop a frame or whether we reckon that - // we're doing well enough that we can stand a one-frame glitch. - int m_trWaitAvg; // Average of last few wait times - // (actually we just average how early - // we were). Negative here means LATE. - - // The average inter-frame time. - // This is used to calculate the proportion of the time used by the - // three operations (supplying us, waiting, rendering) - int m_trFrameAvg; // Average inter-frame time - int m_trDuration; // duration of last frame. - -#ifdef PERF - // Performance logging identifiers - int m_idTimeStamp; // MSR_id for frame time stamp - int m_idEarliness; // MSR_id for earliness fudge - int m_idTarget; // MSR_id for Target fudge - int m_idWaitReal; // MSR_id for true wait time - int m_idWait; // MSR_id for wait time recorded - int m_idFrameAccuracy; // MSR_id for time frame is late (int) - int m_idRenderAvg; // MSR_id for Render time recorded (int) - int m_idSchLateTime; // MSR_id for lateness at scheduler - int m_idQualityRate; // MSR_id for Quality rate requested - int m_idQualityTime; // MSR_id for Quality time requested - int m_idDecision; // MSR_id for decision code - int m_idDuration; // MSR_id for duration of a frame - int m_idThrottle; // MSR_id for audio-video throttling - //int m_idDebug; // MSR_id for trace style debugging - //int m_idSendQuality; // MSR_id for timing the notifications per se -#endif // PERF - REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame - // with no earliness fudges etc. -#ifdef PERF - REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered - - // debug... - int m_idFrameAvg; - int m_idWaitAvg; -#endif - - // PROPERTY PAGE - // This has edit fields that show the user what's happening - // These member variables hold these counts. - - int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER - int m_cFramesDrawn; // Frames since streaming started seen BY THE - // RENDERER (some may be dropped upstream) - - // Next two support average sync offset and standard deviation of sync offset. - LONGLONG m_iTotAcc; // Sum of accuracies in mSec - LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec) - - // Next two allow jitter calculation. Jitter is std deviation of frame time. - REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times) - LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec) - LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec - - // To get performance statistics on frame rate, jitter etc, we need - // to record the lateness and inter-frame time. What we actually need are the - // data above (sum, sum of squares and number of entries for each) but the data - // is generated just ahead of time and only later do we discover whether the - // frame was actually drawn or not. So we have to hang on to the data - int m_trLate; // hold onto frame lateness - int m_trFrame; // hold onto inter-frame time - - int m_tStreamingStart; // if streaming then time streaming started - // else time of last streaming session - // used for property page statistics -#ifdef PERF - LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time -#endif - -public: - - - CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer - __in_opt LPCTSTR pName, // Debug ONLY description - __inout_opt LPUNKNOWN pUnk, // Aggregated owner object - __inout HRESULT *phr); // General OLE return code - - ~CBaseVideoRenderer(); - - // IQualityControl methods - Notify allows audio-video throttling - - STDMETHODIMP SetSink( IQualityControl * piqc); - STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q); - - // These provide a full video quality management implementation - - void OnRenderStart(IMediaSample *pMediaSample); - void OnRenderEnd(IMediaSample *pMediaSample); - void OnWaitStart(); - void OnWaitEnd(); - HRESULT OnStartStreaming(); - HRESULT OnStopStreaming(); - void ThrottleWait(); - - // Handle the statistics gathering for our quality management - - void PreparePerformanceData(int trLate, int trFrame); - virtual void RecordFrameLateness(int trLate, int trFrame); - virtual void OnDirectRender(IMediaSample *pMediaSample); - virtual HRESULT ResetStreamingTimes(); - BOOL ScheduleSample(IMediaSample *pMediaSample); - HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, - __inout REFERENCE_TIME *ptrStart, - __inout REFERENCE_TIME *ptrEnd); - - virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream); - STDMETHODIMP JoinFilterGraph(__inout_opt IFilterGraph * pGraph, __in_opt LPCWSTR pName); - - // - // Do estimates for standard deviations for per-frame - // statistics - // - // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) / - // (m_cFramesDrawn - 2) - // or 0 if m_cFramesDrawn <= 3 - // - HRESULT GetStdDev( - int nSamples, - __out int *piResult, - LONGLONG llSumSq, - LONGLONG iTot - ); -public: - - // IQualProp property page support - - STDMETHODIMP get_FramesDroppedInRenderer(__out int *cFramesDropped); - STDMETHODIMP get_FramesDrawn(__out int *pcFramesDrawn); - STDMETHODIMP get_AvgFrameRate(__out int *piAvgFrameRate); - STDMETHODIMP get_Jitter(__out int *piJitter); - STDMETHODIMP get_AvgSyncOffset(__out int *piAvg); - STDMETHODIMP get_DevSyncOffset(__out int *piDev); - - // Implement an IUnknown interface and expose IQualProp - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv); -}; - -#endif // __RENBASE__ - +//------------------------------------------------------------------------------ +// File: RenBase.h +// +// Desc: DirectShow base classes - defines a generic ActiveX base renderer +// class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __RENBASE__ +#define __RENBASE__ + +// Forward class declarations + +class CBaseRenderer; +class CBaseVideoRenderer; +class CRendererInputPin; + +// This is our input pin class that channels calls to the renderer + +class CRendererInputPin : public CBaseInputPin +{ +protected: + + CBaseRenderer *m_pRenderer; + +public: + + CRendererInputPin(__inout CBaseRenderer *pRenderer, + __inout HRESULT *phr, + __in_opt LPCWSTR Name); + + // Overriden from the base pin classes + + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + HRESULT SetMediaType(const CMediaType *pmt); + HRESULT CheckMediaType(const CMediaType *pmt); + HRESULT Active(); + HRESULT Inactive(); + + // Add rendering behaviour to interface functions + + STDMETHODIMP QueryId(__deref_out LPWSTR *Id); + STDMETHODIMP EndOfStream(); + STDMETHODIMP BeginFlush(); + STDMETHODIMP EndFlush(); + STDMETHODIMP Receive(IMediaSample *pMediaSample); + + // Helper + IMemAllocator inline *Allocator() const + { + return m_pAllocator; + } +}; + +// Main renderer class that handles synchronisation and state changes + +class CBaseRenderer : public CBaseFilter +{ +protected: + + friend class CRendererInputPin; + + friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier + UINT uMsg, // Not currently used + DWORD_PTR dwUser, // User information + DWORD_PTR dw1, // Windows reserved + DWORD_PTR dw2); // Is also reserved + + CRendererPosPassThru *m_pPosition; // Media seeking pass by object + CAMEvent m_RenderEvent; // Used to signal timer events + CAMEvent m_ThreadSignal; // Signalled to release worker thread + CAMEvent m_evComplete; // Signalled when state complete + BOOL m_bAbort; // Stop us from rendering more data + BOOL m_bStreaming; // Are we currently streaming + DWORD_PTR m_dwAdvise; // Timer advise cookie + IMediaSample *m_pMediaSample; // Current image media sample + BOOL m_bEOS; // Any more samples in the stream + BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE + CRendererInputPin *m_pInputPin; // Our renderer input pin object + CCritSec m_InterfaceLock; // Critical section for interfaces + CCritSec m_RendererLock; // Controls access to internals + IQualityControl * m_pQSink; // QualityControl sink + BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT + // Avoid some deadlocks by tracking filter during stop + volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive + // And actually processing the sample + REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE + UINT m_EndOfStreamTimer; // Used to signal end of stream + CCritSec m_ObjectCreationLock; // This lock protects the creation and + // of m_pPosition and m_pInputPin. It + // ensures that two threads cannot create + // either object simultaneously. + +public: + + CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer + __in_opt LPCTSTR pName, // Debug ONLY description + __inout_opt LPUNKNOWN pUnk, // Aggregated owner object + __inout HRESULT *phr); // General OLE return code + + ~CBaseRenderer(); + + // Overriden to say what interfaces we support and where + + virtual HRESULT GetMediaPositionInterface(REFIID riid, __deref_out void **ppv); + STDMETHODIMP NonDelegatingQueryInterface(REFIID, __deref_out void **); + + virtual HRESULT SourceThreadCanWait(BOOL bCanWait); + +#ifdef _DEBUG + // Debug only dump of the renderer state + void DisplayRendererState(); +#endif + virtual HRESULT WaitForRenderTime(); + virtual HRESULT CompleteStateChange(FILTER_STATE OldState); + + // Return internal information about this filter + + BOOL IsEndOfStream() { return m_bEOS; }; + BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; + BOOL IsStreaming() { return m_bStreaming; }; + void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; + virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { }; + CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; + + // Permit access to the transition state + + void Ready() { m_evComplete.Set(); }; + void NotReady() { m_evComplete.Reset(); }; + BOOL CheckReady() { return m_evComplete.Check(); }; + + virtual int GetPinCount(); + virtual CBasePin *GetPin(int n); + FILTER_STATE GetRealState(); + void SendRepaint(); + void SendNotifyWindow(IPin *pPin,HWND hwnd); + BOOL OnDisplayChange(); + void SetRepaintStatus(BOOL bRepaint); + + // Override the filter and pin interface functions + + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + STDMETHODIMP Run(REFERENCE_TIME StartTime); + STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State); + STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin); + + // These are available for a quality management implementation + + virtual void OnRenderStart(IMediaSample *pMediaSample); + virtual void OnRenderEnd(IMediaSample *pMediaSample); + virtual HRESULT OnStartStreaming() { return NOERROR; }; + virtual HRESULT OnStopStreaming() { return NOERROR; }; + virtual void OnWaitStart() { }; + virtual void OnWaitEnd() { }; + virtual void PrepareRender() { }; + +#ifdef PERF + REFERENCE_TIME m_trRenderStart; // Just before we started drawing + // Set in OnRenderStart, Used in OnRenderEnd + int m_idBaseStamp; // MSR_id for frame time stamp + int m_idBaseRenderTime; // MSR_id for true wait time + int m_idBaseAccuracy; // MSR_id for time frame is late (int) +#endif + + // Quality management implementation for scheduling rendering + + virtual BOOL ScheduleSample(IMediaSample *pMediaSample); + virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, + __out REFERENCE_TIME *pStartTime, + __out REFERENCE_TIME *pEndTime); + + virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, + __out REFERENCE_TIME *ptrStart, + __out REFERENCE_TIME *ptrEnd); + + // Lots of end of stream complexities + + void TimerCallback(); + void ResetEndOfStreamTimer(); + HRESULT NotifyEndOfStream(); + virtual HRESULT SendEndOfStream(); + virtual HRESULT ResetEndOfStream(); + virtual HRESULT EndOfStream(); + + // Rendering is based around the clock + + void SignalTimerFired(); + virtual HRESULT CancelNotification(); + virtual HRESULT ClearPendingSample(); + + // Called when the filter changes state + + virtual HRESULT Active(); + virtual HRESULT Inactive(); + virtual HRESULT StartStreaming(); + virtual HRESULT StopStreaming(); + virtual HRESULT BeginFlush(); + virtual HRESULT EndFlush(); + + // Deal with connections and type changes + + virtual HRESULT BreakConnect(); + virtual HRESULT SetMediaType(const CMediaType *pmt); + virtual HRESULT CompleteConnect(IPin *pReceivePin); + + // These look after the handling of data samples + + virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); + virtual HRESULT Receive(IMediaSample *pMediaSample); + virtual BOOL HaveCurrentSample(); + virtual IMediaSample *GetCurrentSample(); + virtual HRESULT Render(IMediaSample *pMediaSample); + + // Derived classes MUST override these + virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE; + virtual HRESULT CheckMediaType(const CMediaType *) PURE; + + // Helper + void WaitForReceiveToComplete(); +}; + + +// CBaseVideoRenderer is a renderer class (see its ancestor class) and +// it handles scheduling of media samples so that they are drawn at the +// correct time by the reference clock. It implements a degradation +// strategy. Possible degradation modes are: +// Drop frames here (only useful if the drawing takes significant time) +// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip. +// Signal supplier to change the frame rate - i.e. ongoing skipping. +// Or any combination of the above. +// In order to determine what's useful to try we need to know what's going +// on. This is done by timing various operations (including the supplier). +// This timing is done by using timeGetTime as it is accurate enough and +// usually cheaper than calling the reference clock. It also tells the +// truth if there is an audio break and the reference clock stops. +// We provide a number of public entry points (named OnXxxStart, OnXxxEnd) +// which the rest of the renderer calls at significant moments. These do +// the timing. + +// the number of frames that the sliding averages are averaged over. +// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD +#define AVGPERIOD 4 +#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD) +// Spot the bug in this macro - I can't. but it doesn't work! + +class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class + public IQualProp, // Property page guff + public IQualityControl // Allow throttling +{ +protected: + + // Hungarian: + // tFoo is the time Foo in mSec (beware m_tStart from filter.h) + // trBar is the time Bar by the reference clock + + //****************************************************************** + // State variables to control synchronisation + //****************************************************************** + + // Control of sending Quality messages. We need to know whether + // we are in trouble (e.g. frames being dropped) and where the time + // is being spent. + + // When we drop a frame we play the next one early. + // The frame after that is likely to wait before drawing and counting this + // wait as spare time is unfair, so we count it as a zero wait. + // We therefore need to know whether we are playing frames early or not. + + int m_nNormal; // The number of consecutive frames + // drawn at their normal time (not early) + // -1 means we just dropped a frame. + +#ifdef PERF + BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm + // not keen on people using it!) +#endif + + BOOL m_bSupplierHandlingQuality;// The response to Quality messages says + // our supplier is handling things. + // We will allow things to go extra late + // before dropping frames. We will play + // very early after he has dropped one. + + // Control of scheduling, frame dropping etc. + // We need to know where the time is being spent so as to tell whether + // we should be taking action here, signalling supplier or what. + // The variables are initialised to a mode of NOT dropping frames. + // They will tell the truth after a few frames. + // We typically record a start time for an event, later we get the time + // again and subtract to get the elapsed time, and we average this over + // a few frames. The average is used to tell what mode we are in. + + // Although these are reference times (64 bit) they are all DIFFERENCES + // between times which are small. An int will go up to 214 secs before + // overflow. Avoiding 64 bit multiplications and divisions seems + // worth while. + + + + // Audio-video throttling. If the user has turned up audio quality + // very high (in principle it could be any other stream, not just audio) + // then we can receive cries for help via the graph manager. In this case + // we put in a wait for some time after rendering each frame. + int m_trThrottle; + + // The time taken to render (i.e. BitBlt) frames controls which component + // needs to degrade. If the blt is expensive, the renderer degrades. + // If the blt is cheap it's done anyway and the supplier degrades. + int m_trRenderAvg; // Time frames are taking to blt + int m_trRenderLast; // Time for last frame blt + int m_tRenderStart; // Just before we started drawing (mSec) + // derived from timeGetTime. + + // When frames are dropped we will play the next frame as early as we can. + // If it was a false alarm and the machine is fast we slide gently back to + // normal timing. To do this, we record the offset showing just how early + // we really are. This will normally be negative meaning early or zero. + int m_trEarliness; + + // Target provides slow long-term feedback to try to reduce the + // average sync offset to zero. Whenever a frame is actually rendered + // early we add a msec or two, whenever late we take off a few. + // We add or take off 1/32 of the error time. + // Eventually we should be hovering around zero. For a really bad case + // where we were (say) 300mSec off, it might take 100 odd frames to + // settle down. The rate of change of this is intended to be slower + // than any other mechanism in Quartz, thereby avoiding hunting. + int m_trTarget; + + // The proportion of time spent waiting for the right moment to blt + // controls whether we bother to drop a frame or whether we reckon that + // we're doing well enough that we can stand a one-frame glitch. + int m_trWaitAvg; // Average of last few wait times + // (actually we just average how early + // we were). Negative here means LATE. + + // The average inter-frame time. + // This is used to calculate the proportion of the time used by the + // three operations (supplying us, waiting, rendering) + int m_trFrameAvg; // Average inter-frame time + int m_trDuration; // duration of last frame. + +#ifdef PERF + // Performance logging identifiers + int m_idTimeStamp; // MSR_id for frame time stamp + int m_idEarliness; // MSR_id for earliness fudge + int m_idTarget; // MSR_id for Target fudge + int m_idWaitReal; // MSR_id for true wait time + int m_idWait; // MSR_id for wait time recorded + int m_idFrameAccuracy; // MSR_id for time frame is late (int) + int m_idRenderAvg; // MSR_id for Render time recorded (int) + int m_idSchLateTime; // MSR_id for lateness at scheduler + int m_idQualityRate; // MSR_id for Quality rate requested + int m_idQualityTime; // MSR_id for Quality time requested + int m_idDecision; // MSR_id for decision code + int m_idDuration; // MSR_id for duration of a frame + int m_idThrottle; // MSR_id for audio-video throttling + //int m_idDebug; // MSR_id for trace style debugging + //int m_idSendQuality; // MSR_id for timing the notifications per se +#endif // PERF + REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame + // with no earliness fudges etc. +#ifdef PERF + REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered + + // debug... + int m_idFrameAvg; + int m_idWaitAvg; +#endif + + // PROPERTY PAGE + // This has edit fields that show the user what's happening + // These member variables hold these counts. + + int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER + int m_cFramesDrawn; // Frames since streaming started seen BY THE + // RENDERER (some may be dropped upstream) + + // Next two support average sync offset and standard deviation of sync offset. + LONGLONG m_iTotAcc; // Sum of accuracies in mSec + LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec) + + // Next two allow jitter calculation. Jitter is std deviation of frame time. + REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times) + LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec) + LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec + + // To get performance statistics on frame rate, jitter etc, we need + // to record the lateness and inter-frame time. What we actually need are the + // data above (sum, sum of squares and number of entries for each) but the data + // is generated just ahead of time and only later do we discover whether the + // frame was actually drawn or not. So we have to hang on to the data + int m_trLate; // hold onto frame lateness + int m_trFrame; // hold onto inter-frame time + + int m_tStreamingStart; // if streaming then time streaming started + // else time of last streaming session + // used for property page statistics +#ifdef PERF + LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time +#endif + +public: + + + CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer + __in_opt LPCTSTR pName, // Debug ONLY description + __inout_opt LPUNKNOWN pUnk, // Aggregated owner object + __inout HRESULT *phr); // General OLE return code + + ~CBaseVideoRenderer(); + + // IQualityControl methods - Notify allows audio-video throttling + + STDMETHODIMP SetSink( IQualityControl * piqc); + STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q); + + // These provide a full video quality management implementation + + void OnRenderStart(IMediaSample *pMediaSample); + void OnRenderEnd(IMediaSample *pMediaSample); + void OnWaitStart(); + void OnWaitEnd(); + HRESULT OnStartStreaming(); + HRESULT OnStopStreaming(); + void ThrottleWait(); + + // Handle the statistics gathering for our quality management + + void PreparePerformanceData(int trLate, int trFrame); + virtual void RecordFrameLateness(int trLate, int trFrame); + virtual void OnDirectRender(IMediaSample *pMediaSample); + virtual HRESULT ResetStreamingTimes(); + BOOL ScheduleSample(IMediaSample *pMediaSample); + HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, + __inout REFERENCE_TIME *ptrStart, + __inout REFERENCE_TIME *ptrEnd); + + virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream); + STDMETHODIMP JoinFilterGraph(__inout_opt IFilterGraph * pGraph, __in_opt LPCWSTR pName); + + // + // Do estimates for standard deviations for per-frame + // statistics + // + // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) / + // (m_cFramesDrawn - 2) + // or 0 if m_cFramesDrawn <= 3 + // + HRESULT GetStdDev( + int nSamples, + __out int *piResult, + LONGLONG llSumSq, + LONGLONG iTot + ); +public: + + // IQualProp property page support + + STDMETHODIMP get_FramesDroppedInRenderer(__out int *cFramesDropped); + STDMETHODIMP get_FramesDrawn(__out int *pcFramesDrawn); + STDMETHODIMP get_AvgFrameRate(__out int *piAvgFrameRate); + STDMETHODIMP get_Jitter(__out int *piJitter); + STDMETHODIMP get_AvgSyncOffset(__out int *piAvg); + STDMETHODIMP get_DevSyncOffset(__out int *piDev); + + // Implement an IUnknown interface and expose IQualProp + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out VOID **ppv); +}; + +#endif // __RENBASE__ + diff --git a/src/thirdparty/BaseClasses/schedule.cpp b/src/thirdparty/BaseClasses/schedule.cpp index 4638a5e1786..3f20d7c27af 100644 --- a/src/thirdparty/BaseClasses/schedule.cpp +++ b/src/thirdparty/BaseClasses/schedule.cpp @@ -1,288 +1,288 @@ -//------------------------------------------------------------------------------ -// File: Schedule.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" - -// DbgLog values (all on LOG_TIMING): -// -// 2 for schedulting, firing and shunting of events -// 3 for wait delays and wake-up times of event thread -// 4 for details of whats on the list when the thread awakes - -/* Construct & destructors */ - -CAMSchedule::CAMSchedule( HANDLE ev ) -: CBaseObject(TEXT("CAMSchedule")) -, head(&z, 0), z(0, MAX_TIME) -, m_dwNextCookie(0), m_dwAdviseCount(0) -, m_pAdviseCache(0), m_dwCacheCount(0) -, m_ev( ev ) -{ - head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0; -} - -CAMSchedule::~CAMSchedule() -{ - m_Serialize.Lock(); - - // Delete cache - CAdvisePacket * p = m_pAdviseCache; - while (p) - { - CAdvisePacket *const p_next = p->m_next; - delete p; - p = p_next; - } - - ASSERT( m_dwAdviseCount == 0 ); - // Better to be safe than sorry - if ( m_dwAdviseCount > 0 ) - { - DumpLinkedList(); - while ( !head.m_next->IsZ() ) - { - head.DeleteNext(); - --m_dwAdviseCount; - } - } - - // If, in the debug version, we assert twice, it means, not only - // did we have left over advises, but we have also let m_dwAdviseCount - // get out of sync. with the number of advises actually on the list. - ASSERT( m_dwAdviseCount == 0 ); - - m_Serialize.Unlock(); -} - -/* Public methods */ - -DWORD CAMSchedule::GetAdviseCount() -{ - // No need to lock, m_dwAdviseCount is 32bits & declared volatile - return m_dwAdviseCount; -} - -REFERENCE_TIME CAMSchedule::GetNextAdviseTime() -{ - CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing - return head.m_next->m_rtEventTime; -} - -DWORD_PTR CAMSchedule::AddAdvisePacket -( const REFERENCE_TIME & time1 -, const REFERENCE_TIME & time2 -, HANDLE h, BOOL periodic -) -{ - // Since we use MAX_TIME as a sentry, we can't afford to - // schedule a notification at MAX_TIME - ASSERT( time1 < MAX_TIME ); - DWORD_PTR Result; - CAdvisePacket * p; - - m_Serialize.Lock(); - - if (m_pAdviseCache) - { - p = m_pAdviseCache; - m_pAdviseCache = p->m_next; - --m_dwCacheCount; - } - else - { - p = new CAdvisePacket(); - } - if (p) - { - p->m_rtEventTime = time1; p->m_rtPeriod = time2; - p->m_hNotify = h; p->m_bPeriodic = periodic; - Result = AddAdvisePacket( p ); - } - else Result = 0; - - m_Serialize.Unlock(); - - return Result; -} - -HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) -{ - HRESULT hr = S_FALSE; - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - m_Serialize.Lock(); - p_n = p_prev->Next(); - while ( p_n ) // The Next() method returns NULL when it hits z - { - if ( p_n->m_dwAdviseCookie == dwAdviseCookie ) - { - Delete( p_prev->RemoveNext() ); - --m_dwAdviseCount; - hr = S_OK; - // Having found one cookie that matches, there should be no more -#ifdef _DEBUG - p_n = p_prev->Next(); - while (p_n) - { - ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie); - p_prev = p_n; - p_n = p_prev->Next(); - } -#endif - break; - } - p_prev = p_n; - p_n = p_prev->Next(); - }; - m_Serialize.Unlock(); - return hr; -} - -REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) -{ - REFERENCE_TIME rtNextTime; - CAdvisePacket * pAdvise; - - DbgLog((LOG_TIMING, 2, - TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS)))); - - CAutoLock lck(&m_Serialize); - - #ifdef _DEBUG - if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList(); - #endif - - // Note - DON'T cache the difference, it might overflow - while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) && - !pAdvise->IsZ() ) - { - ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!! - - ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE); - - if (pAdvise->m_bPeriodic == TRUE) - { - ReleaseSemaphore(pAdvise->m_hNotify,1,NULL); - pAdvise->m_rtEventTime += pAdvise->m_rtPeriod; - ShuntHead(); - } - else - { - ASSERT( pAdvise->m_bPeriodic == FALSE ); - EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify)); - --m_dwAdviseCount; - Delete( head.RemoveNext() ); - } - - } - - DbgLog((LOG_TIMING, 3, - TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."), - DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie )); - - return rtNextTime; -} - -/* Private methods */ - -DWORD_PTR CAMSchedule::AddAdvisePacket( __inout CAdvisePacket * pPacket ) -{ - ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME); - ASSERT(CritCheckIn(&m_Serialize)); - - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - - const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie; - // This relies on the fact that z is a sentry with a maximal m_rtEventTime - for(;;p_prev = p_n) - { - p_n = p_prev->m_next; - if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break; - } - p_prev->InsertAfter( pPacket ); - ++m_dwAdviseCount; - - DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"), - pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); - - // If packet added at the head, then clock needs to re-evaluate wait time. - if ( p_prev == &head ) SetEvent( m_ev ); - - return Result; -} - -void CAMSchedule::Delete( __inout CAdvisePacket * pPacket ) -{ - if ( m_dwCacheCount >= dwCacheMax ) delete pPacket; - else - { - m_Serialize.Lock(); - pPacket->m_next = m_pAdviseCache; - m_pAdviseCache = pPacket; - ++m_dwCacheCount; - m_Serialize.Unlock(); - } -} - - -// Takes the head of the list & repositions it -void CAMSchedule::ShuntHead() -{ - CAdvisePacket * p_prev = &head; - CAdvisePacket * p_n; - - m_Serialize.Lock(); - CAdvisePacket *const pPacket = head.m_next; - - // This will catch both an empty list, - // and if somehow a MAX_TIME time gets into the list - // (which would also break this method). - ASSERT( pPacket->m_rtEventTime < MAX_TIME ); - - // This relies on the fact that z is a sentry with a maximal m_rtEventTime - for(;;p_prev = p_n) - { - p_n = p_prev->m_next; - if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break; - } - // If p_prev == pPacket then we're already in the right place - if (p_prev != pPacket) - { - head.m_next = pPacket->m_next; - (p_prev->m_next = pPacket)->m_next = p_n; - } - #ifdef _DEBUG - DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"), - pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); - #endif - m_Serialize.Unlock(); -} - - -#ifdef _DEBUG -void CAMSchedule::DumpLinkedList() -{ - m_Serialize.Lock(); - int i=0; - DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this)); - for ( CAdvisePacket * p = &head - ; p - ; p = p->m_next , i++ - ) - { - DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"), - i, - p->m_dwAdviseCookie, - p->m_rtEventTime / (UNITS / MILLISECONDS) - )); - } - m_Serialize.Unlock(); -} -#endif +//------------------------------------------------------------------------------ +// File: Schedule.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" + +// DbgLog values (all on LOG_TIMING): +// +// 2 for schedulting, firing and shunting of events +// 3 for wait delays and wake-up times of event thread +// 4 for details of whats on the list when the thread awakes + +/* Construct & destructors */ + +CAMSchedule::CAMSchedule( HANDLE ev ) +: CBaseObject(TEXT("CAMSchedule")) +, head(&z, 0), z(0, MAX_TIME) +, m_dwNextCookie(0), m_dwAdviseCount(0) +, m_pAdviseCache(0), m_dwCacheCount(0) +, m_ev( ev ) +{ + head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0; +} + +CAMSchedule::~CAMSchedule() +{ + m_Serialize.Lock(); + + // Delete cache + CAdvisePacket * p = m_pAdviseCache; + while (p) + { + CAdvisePacket *const p_next = p->m_next; + delete p; + p = p_next; + } + + ASSERT( m_dwAdviseCount == 0 ); + // Better to be safe than sorry + if ( m_dwAdviseCount > 0 ) + { + DumpLinkedList(); + while ( !head.m_next->IsZ() ) + { + head.DeleteNext(); + --m_dwAdviseCount; + } + } + + // If, in the debug version, we assert twice, it means, not only + // did we have left over advises, but we have also let m_dwAdviseCount + // get out of sync. with the number of advises actually on the list. + ASSERT( m_dwAdviseCount == 0 ); + + m_Serialize.Unlock(); +} + +/* Public methods */ + +DWORD CAMSchedule::GetAdviseCount() +{ + // No need to lock, m_dwAdviseCount is 32bits & declared volatile + return m_dwAdviseCount; +} + +REFERENCE_TIME CAMSchedule::GetNextAdviseTime() +{ + CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing + return head.m_next->m_rtEventTime; +} + +DWORD_PTR CAMSchedule::AddAdvisePacket +( const REFERENCE_TIME & time1 +, const REFERENCE_TIME & time2 +, HANDLE h, BOOL periodic +) +{ + // Since we use MAX_TIME as a sentry, we can't afford to + // schedule a notification at MAX_TIME + ASSERT( time1 < MAX_TIME ); + DWORD_PTR Result; + CAdvisePacket * p; + + m_Serialize.Lock(); + + if (m_pAdviseCache) + { + p = m_pAdviseCache; + m_pAdviseCache = p->m_next; + --m_dwCacheCount; + } + else + { + p = new CAdvisePacket(); + } + if (p) + { + p->m_rtEventTime = time1; p->m_rtPeriod = time2; + p->m_hNotify = h; p->m_bPeriodic = periodic; + Result = AddAdvisePacket( p ); + } + else Result = 0; + + m_Serialize.Unlock(); + + return Result; +} + +HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) +{ + HRESULT hr = S_FALSE; + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + m_Serialize.Lock(); + p_n = p_prev->Next(); + while ( p_n ) // The Next() method returns NULL when it hits z + { + if ( p_n->m_dwAdviseCookie == dwAdviseCookie ) + { + Delete( p_prev->RemoveNext() ); + --m_dwAdviseCount; + hr = S_OK; + // Having found one cookie that matches, there should be no more +#ifdef _DEBUG + p_n = p_prev->Next(); + while (p_n) + { + ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie); + p_prev = p_n; + p_n = p_prev->Next(); + } +#endif + break; + } + p_prev = p_n; + p_n = p_prev->Next(); + }; + m_Serialize.Unlock(); + return hr; +} + +REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) +{ + REFERENCE_TIME rtNextTime; + CAdvisePacket * pAdvise; + + DbgLog((LOG_TIMING, 2, + TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS)))); + + CAutoLock lck(&m_Serialize); + + #ifdef _DEBUG + if (DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList(); + #endif + + // Note - DON'T cache the difference, it might overflow + while ( rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) && + !pAdvise->IsZ() ) + { + ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!! + + ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE); + + if (pAdvise->m_bPeriodic == TRUE) + { + ReleaseSemaphore(pAdvise->m_hNotify,1,NULL); + pAdvise->m_rtEventTime += pAdvise->m_rtPeriod; + ShuntHead(); + } + else + { + ASSERT( pAdvise->m_bPeriodic == FALSE ); + EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify)); + --m_dwAdviseCount; + Delete( head.RemoveNext() ); + } + + } + + DbgLog((LOG_TIMING, 3, + TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."), + DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie )); + + return rtNextTime; +} + +/* Private methods */ + +DWORD_PTR CAMSchedule::AddAdvisePacket( __inout CAdvisePacket * pPacket ) +{ + ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME); + ASSERT(CritCheckIn(&m_Serialize)); + + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + + const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie; + // This relies on the fact that z is a sentry with a maximal m_rtEventTime + for(;;p_prev = p_n) + { + p_n = p_prev->m_next; + if ( p_n->m_rtEventTime >= pPacket->m_rtEventTime ) break; + } + p_prev->InsertAfter( pPacket ); + ++m_dwAdviseCount; + + DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"), + pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); + + // If packet added at the head, then clock needs to re-evaluate wait time. + if ( p_prev == &head ) SetEvent( m_ev ); + + return Result; +} + +void CAMSchedule::Delete( __inout CAdvisePacket * pPacket ) +{ + if ( m_dwCacheCount >= dwCacheMax ) delete pPacket; + else + { + m_Serialize.Lock(); + pPacket->m_next = m_pAdviseCache; + m_pAdviseCache = pPacket; + ++m_dwCacheCount; + m_Serialize.Unlock(); + } +} + + +// Takes the head of the list & repositions it +void CAMSchedule::ShuntHead() +{ + CAdvisePacket * p_prev = &head; + CAdvisePacket * p_n; + + m_Serialize.Lock(); + CAdvisePacket *const pPacket = head.m_next; + + // This will catch both an empty list, + // and if somehow a MAX_TIME time gets into the list + // (which would also break this method). + ASSERT( pPacket->m_rtEventTime < MAX_TIME ); + + // This relies on the fact that z is a sentry with a maximal m_rtEventTime + for(;;p_prev = p_n) + { + p_n = p_prev->m_next; + if ( p_n->m_rtEventTime > pPacket->m_rtEventTime ) break; + } + // If p_prev == pPacket then we're already in the right place + if (p_prev != pPacket) + { + head.m_next = pPacket->m_next; + (p_prev->m_next = pPacket)->m_next = p_n; + } + #ifdef _DEBUG + DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"), + pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) )); + #endif + m_Serialize.Unlock(); +} + + +#ifdef _DEBUG +void CAMSchedule::DumpLinkedList() +{ + m_Serialize.Lock(); + int i=0; + DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this)); + for ( CAdvisePacket * p = &head + ; p + ; p = p->m_next , i++ + ) + { + DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"), + i, + p->m_dwAdviseCookie, + p->m_rtEventTime / (UNITS / MILLISECONDS) + )); + } + m_Serialize.Unlock(); +} +#endif diff --git a/src/thirdparty/BaseClasses/schedule.h b/src/thirdparty/BaseClasses/schedule.h index ff49a44c318..c35e0098b39 100644 --- a/src/thirdparty/BaseClasses/schedule.h +++ b/src/thirdparty/BaseClasses/schedule.h @@ -1,140 +1,140 @@ -//------------------------------------------------------------------------------ -// File: Schedule.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __CAMSchedule__ -#define __CAMSchedule__ - -class CAMSchedule : private CBaseObject -{ -public: - virtual ~CAMSchedule(); - // ev is the event we should fire if the advise time needs re-evaluating - CAMSchedule( HANDLE ev ); - - DWORD GetAdviseCount(); - REFERENCE_TIME GetNextAdviseTime(); - - // We need a method for derived classes to add advise packets, we return the cookie - DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); - // And a way to cancel - HRESULT Unadvise(DWORD_PTR dwAdviseCookie); - - // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. - // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of - // whoever is using this helper class (typically a clock). - REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); - - // Get the event handle which will be set if advise time requires re-evaluation. - HANDLE GetEvent() const { return m_ev; } - -private: - // We define the nodes that will be used in our singly linked list - // of advise packets. The list is ordered by time, with the - // elements that will expire first at the front. - class CAdvisePacket - { - public: - CAdvisePacket() - : m_next(NULL) - , m_rtEventTime(0) - , m_dwAdviseCookie(0) - , m_rtPeriod(0) - , m_hNotify(NULL) - , m_bPeriodic(FALSE) - {} - - CAdvisePacket * m_next; - DWORD_PTR m_dwAdviseCookie; - REFERENCE_TIME m_rtEventTime; // Time at which event should be set - REFERENCE_TIME m_rtPeriod; // Periodic time - HANDLE m_hNotify; // Handle to event or semephore - BOOL m_bPeriodic; // TRUE => Periodic event - - CAdvisePacket( __inout_opt CAdvisePacket * next, LONGLONG time ) - : m_next(next) - , m_rtEventTime(time) - , m_dwAdviseCookie(0) - , m_rtPeriod(0) - , m_hNotify(NULL) - , m_bPeriodic(FALSE) - {} - - void InsertAfter( __inout CAdvisePacket * p ) - { - p->m_next = m_next; - m_next = p; - } - - int IsZ() const // That is, is it the node that represents the end of the list - { return m_next == 0; } - - CAdvisePacket * RemoveNext() - { - CAdvisePacket *const next = m_next; - CAdvisePacket *const new_next = next->m_next; - m_next = new_next; - return next; - } - - void DeleteNext() - { - delete RemoveNext(); - } - - CAdvisePacket * Next() const - { - CAdvisePacket * result = m_next; - if (result->IsZ()) result = 0; - return result; - } - - DWORD_PTR Cookie() const - { return m_dwAdviseCookie; } - }; - - // Structure is: - // head -> elmt1 -> elmt2 -> z -> null - // So an empty list is: head -> z -> null - // Having head & z as links makes insertaion, - // deletion and shunting much easier. - CAdvisePacket head, z; // z is both a tail and a sentry - - volatile DWORD_PTR m_dwNextCookie; // Strictly increasing - volatile DWORD m_dwAdviseCount; // Number of elements on list - - CCritSec m_Serialize; - - // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) - DWORD_PTR AddAdvisePacket( __inout CAdvisePacket * pPacket ); - // Event that we should set if the packed added above will be the next to fire. - const HANDLE m_ev; - - // A Shunt is where we have changed the first element in the - // list and want it re-evaluating (i.e. repositioned) in - // the list. - void ShuntHead(); - - // Rather than delete advise packets, we cache them for future use - CAdvisePacket * m_pAdviseCache; - DWORD m_dwCacheCount; - enum { dwCacheMax = 5 }; // Don't bother caching more than five - - void Delete( __inout CAdvisePacket * pLink );// This "Delete" will cache the Link - -// Attributes and methods for debugging -public: -#ifdef _DEBUG - void DumpLinkedList(); -#else - void DumpLinkedList() {} -#endif - -}; - -#endif // __CAMSchedule__ +//------------------------------------------------------------------------------ +// File: Schedule.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __CAMSchedule__ +#define __CAMSchedule__ + +class CAMSchedule : private CBaseObject +{ +public: + virtual ~CAMSchedule(); + // ev is the event we should fire if the advise time needs re-evaluating + CAMSchedule( HANDLE ev ); + + DWORD GetAdviseCount(); + REFERENCE_TIME GetNextAdviseTime(); + + // We need a method for derived classes to add advise packets, we return the cookie + DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); + // And a way to cancel + HRESULT Unadvise(DWORD_PTR dwAdviseCookie); + + // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. + // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of + // whoever is using this helper class (typically a clock). + REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); + + // Get the event handle which will be set if advise time requires re-evaluation. + HANDLE GetEvent() const { return m_ev; } + +private: + // We define the nodes that will be used in our singly linked list + // of advise packets. The list is ordered by time, with the + // elements that will expire first at the front. + class CAdvisePacket + { + public: + CAdvisePacket() + : m_next(NULL) + , m_rtEventTime(0) + , m_dwAdviseCookie(0) + , m_rtPeriod(0) + , m_hNotify(NULL) + , m_bPeriodic(FALSE) + {} + + CAdvisePacket * m_next; + DWORD_PTR m_dwAdviseCookie; + REFERENCE_TIME m_rtEventTime; // Time at which event should be set + REFERENCE_TIME m_rtPeriod; // Periodic time + HANDLE m_hNotify; // Handle to event or semephore + BOOL m_bPeriodic; // TRUE => Periodic event + + CAdvisePacket( __inout_opt CAdvisePacket * next, LONGLONG time ) + : m_next(next) + , m_rtEventTime(time) + , m_dwAdviseCookie(0) + , m_rtPeriod(0) + , m_hNotify(NULL) + , m_bPeriodic(FALSE) + {} + + void InsertAfter( __inout CAdvisePacket * p ) + { + p->m_next = m_next; + m_next = p; + } + + int IsZ() const // That is, is it the node that represents the end of the list + { return m_next == 0; } + + CAdvisePacket * RemoveNext() + { + CAdvisePacket *const next = m_next; + CAdvisePacket *const new_next = next->m_next; + m_next = new_next; + return next; + } + + void DeleteNext() + { + delete RemoveNext(); + } + + CAdvisePacket * Next() const + { + CAdvisePacket * result = m_next; + if (result->IsZ()) result = 0; + return result; + } + + DWORD_PTR Cookie() const + { return m_dwAdviseCookie; } + }; + + // Structure is: + // head -> elmt1 -> elmt2 -> z -> null + // So an empty list is: head -> z -> null + // Having head & z as links makes insertaion, + // deletion and shunting much easier. + CAdvisePacket head, z; // z is both a tail and a sentry + + volatile DWORD_PTR m_dwNextCookie; // Strictly increasing + volatile DWORD m_dwAdviseCount; // Number of elements on list + + CCritSec m_Serialize; + + // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) + DWORD_PTR AddAdvisePacket( __inout CAdvisePacket * pPacket ); + // Event that we should set if the packed added above will be the next to fire. + const HANDLE m_ev; + + // A Shunt is where we have changed the first element in the + // list and want it re-evaluating (i.e. repositioned) in + // the list. + void ShuntHead(); + + // Rather than delete advise packets, we cache them for future use + CAdvisePacket * m_pAdviseCache; + DWORD m_dwCacheCount; + enum { dwCacheMax = 5 }; // Don't bother caching more than five + + void Delete( __inout CAdvisePacket * pLink );// This "Delete" will cache the Link + +// Attributes and methods for debugging +public: +#ifdef _DEBUG + void DumpLinkedList(); +#else + void DumpLinkedList() {} +#endif + +}; + +#endif // __CAMSchedule__ diff --git a/src/thirdparty/BaseClasses/seekpt.cpp b/src/thirdparty/BaseClasses/seekpt.cpp index 0c5ec923eb0..e679b253873 100644 --- a/src/thirdparty/BaseClasses/seekpt.cpp +++ b/src/thirdparty/BaseClasses/seekpt.cpp @@ -1,83 +1,83 @@ -//------------------------------------------------------------------------------ -// File: SeekPT.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "seekpt.h" - -//================================================================== -// CreateInstance -// This goes in the factory template table to create new instances -// If there is already a mapper instance - return that, else make one -// and save it in a static variable so that forever after we can return that. -//================================================================== - -CUnknown * CSeekingPassThru::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) -{ - return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr); -} - - -STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) -{ - if (riid == IID_ISeekingPassThru) { - return GetInterface((ISeekingPassThru *) this, ppv); - } else { - if (m_pPosPassThru && - (riid == IID_IMediaSeeking || - riid == IID_IMediaPosition)) { - return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid, ppv); - } - } -} - - -CSeekingPassThru::CSeekingPassThru( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr ) - : CUnknown(pName, pUnk, phr), - m_pPosPassThru(NULL) -{ -} - - -CSeekingPassThru::~CSeekingPassThru() -{ - delete m_pPosPassThru; -} - -STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin) -{ - HRESULT hr = NOERROR; - if (m_pPosPassThru) { - hr = E_FAIL; - } else { - m_pPosPassThru = - bRendererSeeking ? - new CRendererPosPassThru( - NAME("Render Seeking COM object"), - (IUnknown *)this, - &hr, - pPin) : - new CPosPassThru( - NAME("Render Seeking COM object"), - (IUnknown *)this, - &hr, - pPin); - if (!m_pPosPassThru) { - hr = E_OUTOFMEMORY; - } else { - if (FAILED(hr)) { - delete m_pPosPassThru; - m_pPosPassThru = NULL; - } - } - } - return hr; -} - +//------------------------------------------------------------------------------ +// File: SeekPT.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "seekpt.h" + +//================================================================== +// CreateInstance +// This goes in the factory template table to create new instances +// If there is already a mapper instance - return that, else make one +// and save it in a static variable so that forever after we can return that. +//================================================================== + +CUnknown * CSeekingPassThru::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) +{ + return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr); +} + + +STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv) +{ + if (riid == IID_ISeekingPassThru) { + return GetInterface((ISeekingPassThru *) this, ppv); + } else { + if (m_pPosPassThru && + (riid == IID_IMediaSeeking || + riid == IID_IMediaPosition)) { + return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + } +} + + +CSeekingPassThru::CSeekingPassThru( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr ) + : CUnknown(pName, pUnk, phr), + m_pPosPassThru(NULL) +{ +} + + +CSeekingPassThru::~CSeekingPassThru() +{ + delete m_pPosPassThru; +} + +STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin) +{ + HRESULT hr = NOERROR; + if (m_pPosPassThru) { + hr = E_FAIL; + } else { + m_pPosPassThru = + bRendererSeeking ? + new CRendererPosPassThru( + NAME("Render Seeking COM object"), + (IUnknown *)this, + &hr, + pPin) : + new CPosPassThru( + NAME("Render Seeking COM object"), + (IUnknown *)this, + &hr, + pPin); + if (!m_pPosPassThru) { + hr = E_OUTOFMEMORY; + } else { + if (FAILED(hr)) { + delete m_pPosPassThru; + m_pPosPassThru = NULL; + } + } + } + return hr; +} + diff --git a/src/thirdparty/BaseClasses/seekpt.h b/src/thirdparty/BaseClasses/seekpt.h index 26abdf3ecec..208d418f8f4 100644 --- a/src/thirdparty/BaseClasses/seekpt.h +++ b/src/thirdparty/BaseClasses/seekpt.h @@ -1,30 +1,30 @@ -//------------------------------------------------------------------------------ -// File: SeekPT.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __seekpt_h__ -#define __seekpt_h__ - - -class CSeekingPassThru : public ISeekingPassThru, public CUnknown -{ -public: - static CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); - CSeekingPassThru(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); - ~CSeekingPassThru(); - - DECLARE_IUNKNOWN; - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - - STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin); - -private: - CPosPassThru *m_pPosPassThru; -}; - -#endif +//------------------------------------------------------------------------------ +// File: SeekPT.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __seekpt_h__ +#define __seekpt_h__ + + +class CSeekingPassThru : public ISeekingPassThru, public CUnknown +{ +public: + static CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); + CSeekingPassThru(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); + ~CSeekingPassThru(); + + DECLARE_IUNKNOWN; + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + + STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin); + +private: + CPosPassThru *m_pPosPassThru; +}; + +#endif diff --git a/src/thirdparty/BaseClasses/source.cpp b/src/thirdparty/BaseClasses/source.cpp index 79ea4966517..b1cfbe8cb86 100644 --- a/src/thirdparty/BaseClasses/source.cpp +++ b/src/thirdparty/BaseClasses/source.cpp @@ -1,522 +1,522 @@ -//------------------------------------------------------------------------------ -// File: Source.cpp -// -// Desc: DirectShow base classes - implements CSource, which is a Quartz -// source filter 'template.' -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Locking Strategy. -// -// Hold the filter critical section (m_pFilter->pStateLock()) to serialise -// access to functions. Note that, in general, this lock may be held -// by a function when the worker thread may want to hold it. Therefore -// if you wish to access shared state from the worker thread you will -// need to add another critical section object. The execption is during -// the threads processing loop, when it is safe to get the filter critical -// section from within FillBuffer(). - -#include "streams.h" - - -// -// CSource::Constructor -// -// Initialise the pin count for the filter. The user will create the pins in -// the derived class. -CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ -} - -CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ - UNREFERENCED_PARAMETER(phr); -} - -#ifdef UNICODE -CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ -} - -CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr) - : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), - m_iPins(0), - m_paStreams(NULL) -{ - UNREFERENCED_PARAMETER(phr); -} -#endif - -// -// CSource::Destructor -// -CSource::~CSource() -{ - /* Free our pins and pin array */ - while (m_iPins != 0) { - // deleting the pins causes them to be removed from the array... - delete m_paStreams[m_iPins - 1]; - } - - ASSERT(m_paStreams == NULL); -} - - -// -// Add a new pin -// -HRESULT CSource::AddPin(__in CSourceStream *pStream) -{ - CAutoLock lock(&m_cStateLock); - - /* Allocate space for this pin and the old ones */ - CSourceStream **paStreams = new CSourceStream *[m_iPins + 1]; - if (paStreams == NULL) { - return E_OUTOFMEMORY; - } - if (m_paStreams != NULL) { - CopyMemory((PVOID)paStreams, (PVOID)m_paStreams, - m_iPins * sizeof(m_paStreams[0])); - paStreams[m_iPins] = pStream; - delete [] m_paStreams; - } - m_paStreams = paStreams; - m_paStreams[m_iPins] = pStream; - m_iPins++; - return S_OK; -} - -// -// Remove a pin - pStream is NOT deleted -// -HRESULT CSource::RemovePin(__in CSourceStream *pStream) -{ - int i; - for (i = 0; i < m_iPins; i++) { - if (m_paStreams[i] == pStream) { - if (m_iPins == 1) { - delete [] m_paStreams; - m_paStreams = NULL; - } else { - /* no need to reallocate */ - while (++i < m_iPins) - m_paStreams[i - 1] = m_paStreams[i]; - } - m_iPins--; - return S_OK; - } - } - return S_FALSE; -} - -// -// FindPin -// -// Set *ppPin to the IPin* that has the id Id. -// or to NULL if the Id cannot be matched. -STDMETHODIMP CSource::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - // The -1 undoes the +1 in QueryId and ensures that totally invalid - // strings (for which WstrToInt delivers 0) give a deliver a NULL pin. - int i = WstrToInt(Id) -1; - *ppPin = GetPin(i); - if (*ppPin!=NULL){ - (*ppPin)->AddRef(); - return NOERROR; - } else { - return VFW_E_NOT_FOUND; - } -} - -// -// FindPinNumber -// -// return the number of the pin with this IPin* or -1 if none -int CSource::FindPinNumber(__in IPin *iPin) { - int i; - for (i=0; in && n>=0 it follows that m_iPins>0 - // which is what used to be checked (i.e. checking that we have a pin) - if ((n >= 0) && (n < m_iPins)) { - - ASSERT(m_paStreams[n]); - return m_paStreams[n]; - } - return NULL; -} - - -// - - -// * -// * --- CSourceStream ---- -// * - -// -// Set Id to point to a CoTaskMemAlloc'd -STDMETHODIMP CSourceStream::QueryId(__deref_out LPWSTR *Id) { - CheckPointer(Id,E_POINTER); - ValidateReadWritePtr(Id,sizeof(LPWSTR)); - - // We give the pins id's which are 1,2,... - // FindPinNumber returns -1 for an invalid pin - int i = 1+ m_pFilter->FindPinNumber(this); - if (i<1) return VFW_E_NOT_FOUND; - *Id = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * 12); - if (*Id==NULL) { - return E_OUTOFMEMORY; - } - IntToWstr(i, *Id); - return NOERROR; -} - - - -// -// CSourceStream::Constructor -// -// increments the number of pins present on the filter -CSourceStream::CSourceStream( - __in_opt LPCTSTR pObjectName, - __inout HRESULT *phr, - __inout CSource *ps, - __in_opt LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), - m_pFilter(ps) { - - *phr = m_pFilter->AddPin(this); -} - -#ifdef UNICODE -CSourceStream::CSourceStream( - __in_opt LPCSTR pObjectName, - __inout HRESULT *phr, - __inout CSource *ps, - __in_opt LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), - m_pFilter(ps) { - - *phr = m_pFilter->AddPin(this); -} -#endif -// -// CSourceStream::Destructor -// -// Decrements the number of pins on this filter -CSourceStream::~CSourceStream(void) { - - m_pFilter->RemovePin(this); -} - - -// -// CheckMediaType -// -// Do we support this type? Provides the default support for 1 type. -HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) { - - CAutoLock lock(m_pFilter->pStateLock()); - - CMediaType mt; - GetMediaType(&mt); - - if (mt == *pMediaType) { - return NOERROR; - } - - return E_FAIL; -} - - -// -// GetMediaType/3 -// -// By default we support only one type -// iPosition indexes are 0-n -HRESULT CSourceStream::GetMediaType(int iPosition, __inout CMediaType *pMediaType) { - - CAutoLock lock(m_pFilter->pStateLock()); - - if (iPosition<0) { - return E_INVALIDARG; - } - if (iPosition>0) { - return VFW_S_NO_MORE_ITEMS; - } - return GetMediaType(pMediaType); -} - - -// -// Active -// -// The pin is active - start up the worker thread -HRESULT CSourceStream::Active(void) { - - CAutoLock lock(m_pFilter->pStateLock()); - - HRESULT hr; - - if (m_pFilter->IsActive()) { - return S_FALSE; // succeeded, but did not allocate resources (they already exist...) - } - - // do nothing if not connected - its ok not to connect to - // all pins of a source filter - if (!IsConnected()) { - return NOERROR; - } - - hr = CBaseOutputPin::Active(); - if (FAILED(hr)) { - return hr; - } - - ASSERT(!ThreadExists()); - - // start the thread - if (!Create()) { - return E_FAIL; - } - - // Tell thread to initialize. If OnThreadCreate Fails, so does this. - hr = Init(); - if (FAILED(hr)) - return hr; - - return Pause(); -} - - -// -// Inactive -// -// Pin is inactive - shut down the worker thread -// Waits for the worker to exit before returning. -HRESULT CSourceStream::Inactive(void) { - - CAutoLock lock(m_pFilter->pStateLock()); - - HRESULT hr; - - // do nothing if not connected - its ok not to connect to - // all pins of a source filter - if (!IsConnected()) { - return NOERROR; - } - - // !!! need to do this before trying to stop the thread, because - // we may be stuck waiting for our own allocator!!! - - hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator - if (FAILED(hr)) { - return hr; - } - - if (ThreadExists()) { - hr = Stop(); - - if (FAILED(hr)) { - return hr; - } - - hr = Exit(); - if (FAILED(hr)) { - return hr; - } - - Close(); // Wait for the thread to exit, then tidy up. - } - - // hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator - //if (FAILED(hr)) { - // return hr; - //} - - return NOERROR; -} - - -// -// ThreadProc -// -// When this returns the thread exits -// Return codes > 0 indicate an error occured -DWORD CSourceStream::ThreadProc(void) { - - HRESULT hr; // the return code from calls - Command com; - - do { - com = GetRequest(); - if (com != CMD_INIT) { - DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command"))); - Reply((DWORD) E_UNEXPECTED); - } - } while (com != CMD_INIT); - - DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing"))); - - hr = OnThreadCreate(); // perform set up tasks - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread."))); - OnThreadDestroy(); - Reply(hr); // send failed return code from OnThreadCreate - return 1; - } - - // Initialisation suceeded - Reply(NOERROR); - - Command cmd; - do { - cmd = GetRequest(); - - switch (cmd) { - - case CMD_EXIT: - Reply(NOERROR); - break; - - case CMD_RUN: - DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???"))); - // !!! fall through??? - - case CMD_PAUSE: - Reply(NOERROR); - DoBufferProcessingLoop(); - break; - - case CMD_STOP: - Reply(NOERROR); - break; - - default: - DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd)); - Reply((DWORD) E_NOTIMPL); - break; - } - } while (cmd != CMD_EXIT); - - hr = OnThreadDestroy(); // tidy up. - if (FAILED(hr)) { - DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread."))); - return 1; - } - - DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting"))); - return 0; -} - - -// -// DoBufferProcessingLoop -// -// Grabs a buffer and calls the users processing function. -// Overridable, so that different delivery styles can be catered for. -HRESULT CSourceStream::DoBufferProcessingLoop(void) { - - Command com; - - OnThreadStartPlay(); - - do { - while (!CheckRequest(&com)) { - - IMediaSample *pSample; - - HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); - if (FAILED(hr)) { - Sleep(1); - continue; // go round again. Perhaps the error will go away - // or the allocator is decommited & we will be asked to - // exit soon. - } - - // Virtual function user will override. - hr = FillBuffer(pSample); - - if (hr == S_OK) { - hr = Deliver(pSample); - pSample->Release(); - - // downstream filter returns S_FALSE if it wants us to - // stop or an error if it's reporting an error. - if(hr != S_OK) - { - DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); - return S_OK; - } - - } else if (hr == S_FALSE) { - // derived class wants us to stop pushing data - pSample->Release(); - DeliverEndOfStream(); - return S_OK; - } else { - // derived class encountered an error - pSample->Release(); - DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); - DeliverEndOfStream(); - m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); - return hr; - } - - // all paths release the sample - } - - // For all commands sent to us there must be a Reply call! - - if (com == CMD_RUN || com == CMD_PAUSE) { - Reply(NOERROR); - } else if (com != CMD_STOP) { - Reply((DWORD) E_UNEXPECTED); - DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); - } - } while (com != CMD_STOP); - - return S_FALSE; -} - +//------------------------------------------------------------------------------ +// File: Source.cpp +// +// Desc: DirectShow base classes - implements CSource, which is a Quartz +// source filter 'template.' +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Locking Strategy. +// +// Hold the filter critical section (m_pFilter->pStateLock()) to serialise +// access to functions. Note that, in general, this lock may be held +// by a function when the worker thread may want to hold it. Therefore +// if you wish to access shared state from the worker thread you will +// need to add another critical section object. The execption is during +// the threads processing loop, when it is safe to get the filter critical +// section from within FillBuffer(). + +#include "streams.h" + + +// +// CSource::Constructor +// +// Initialise the pin count for the filter. The user will create the pins in +// the derived class. +CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ +} + +CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ + UNREFERENCED_PARAMETER(phr); +} + +#ifdef UNICODE +CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ +} + +CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr) + : CBaseFilter(pName, lpunk, &m_cStateLock, clsid), + m_iPins(0), + m_paStreams(NULL) +{ + UNREFERENCED_PARAMETER(phr); +} +#endif + +// +// CSource::Destructor +// +CSource::~CSource() +{ + /* Free our pins and pin array */ + while (m_iPins != 0) { + // deleting the pins causes them to be removed from the array... + delete m_paStreams[m_iPins - 1]; + } + + ASSERT(m_paStreams == NULL); +} + + +// +// Add a new pin +// +HRESULT CSource::AddPin(__in CSourceStream *pStream) +{ + CAutoLock lock(&m_cStateLock); + + /* Allocate space for this pin and the old ones */ + CSourceStream **paStreams = new CSourceStream *[m_iPins + 1]; + if (paStreams == NULL) { + return E_OUTOFMEMORY; + } + if (m_paStreams != NULL) { + CopyMemory((PVOID)paStreams, (PVOID)m_paStreams, + m_iPins * sizeof(m_paStreams[0])); + paStreams[m_iPins] = pStream; + delete [] m_paStreams; + } + m_paStreams = paStreams; + m_paStreams[m_iPins] = pStream; + m_iPins++; + return S_OK; +} + +// +// Remove a pin - pStream is NOT deleted +// +HRESULT CSource::RemovePin(__in CSourceStream *pStream) +{ + int i; + for (i = 0; i < m_iPins; i++) { + if (m_paStreams[i] == pStream) { + if (m_iPins == 1) { + delete [] m_paStreams; + m_paStreams = NULL; + } else { + /* no need to reallocate */ + while (++i < m_iPins) + m_paStreams[i - 1] = m_paStreams[i]; + } + m_iPins--; + return S_OK; + } + } + return S_FALSE; +} + +// +// FindPin +// +// Set *ppPin to the IPin* that has the id Id. +// or to NULL if the Id cannot be matched. +STDMETHODIMP CSource::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + // The -1 undoes the +1 in QueryId and ensures that totally invalid + // strings (for which WstrToInt delivers 0) give a deliver a NULL pin. + int i = WstrToInt(Id) -1; + *ppPin = GetPin(i); + if (*ppPin!=NULL){ + (*ppPin)->AddRef(); + return NOERROR; + } else { + return VFW_E_NOT_FOUND; + } +} + +// +// FindPinNumber +// +// return the number of the pin with this IPin* or -1 if none +int CSource::FindPinNumber(__in IPin *iPin) { + int i; + for (i=0; in && n>=0 it follows that m_iPins>0 + // which is what used to be checked (i.e. checking that we have a pin) + if ((n >= 0) && (n < m_iPins)) { + + ASSERT(m_paStreams[n]); + return m_paStreams[n]; + } + return NULL; +} + + +// + + +// * +// * --- CSourceStream ---- +// * + +// +// Set Id to point to a CoTaskMemAlloc'd +STDMETHODIMP CSourceStream::QueryId(__deref_out LPWSTR *Id) { + CheckPointer(Id,E_POINTER); + ValidateReadWritePtr(Id,sizeof(LPWSTR)); + + // We give the pins id's which are 1,2,... + // FindPinNumber returns -1 for an invalid pin + int i = 1+ m_pFilter->FindPinNumber(this); + if (i<1) return VFW_E_NOT_FOUND; + *Id = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * 12); + if (*Id==NULL) { + return E_OUTOFMEMORY; + } + IntToWstr(i, *Id); + return NOERROR; +} + + + +// +// CSourceStream::Constructor +// +// increments the number of pins present on the filter +CSourceStream::CSourceStream( + __in_opt LPCTSTR pObjectName, + __inout HRESULT *phr, + __inout CSource *ps, + __in_opt LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), + m_pFilter(ps) { + + *phr = m_pFilter->AddPin(this); +} + +#ifdef UNICODE +CSourceStream::CSourceStream( + __in_opt LPCSTR pObjectName, + __inout HRESULT *phr, + __inout CSource *ps, + __in_opt LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName), + m_pFilter(ps) { + + *phr = m_pFilter->AddPin(this); +} +#endif +// +// CSourceStream::Destructor +// +// Decrements the number of pins on this filter +CSourceStream::~CSourceStream(void) { + + m_pFilter->RemovePin(this); +} + + +// +// CheckMediaType +// +// Do we support this type? Provides the default support for 1 type. +HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) { + + CAutoLock lock(m_pFilter->pStateLock()); + + CMediaType mt; + GetMediaType(&mt); + + if (mt == *pMediaType) { + return NOERROR; + } + + return E_FAIL; +} + + +// +// GetMediaType/3 +// +// By default we support only one type +// iPosition indexes are 0-n +HRESULT CSourceStream::GetMediaType(int iPosition, __inout CMediaType *pMediaType) { + + CAutoLock lock(m_pFilter->pStateLock()); + + if (iPosition<0) { + return E_INVALIDARG; + } + if (iPosition>0) { + return VFW_S_NO_MORE_ITEMS; + } + return GetMediaType(pMediaType); +} + + +// +// Active +// +// The pin is active - start up the worker thread +HRESULT CSourceStream::Active(void) { + + CAutoLock lock(m_pFilter->pStateLock()); + + HRESULT hr; + + if (m_pFilter->IsActive()) { + return S_FALSE; // succeeded, but did not allocate resources (they already exist...) + } + + // do nothing if not connected - its ok not to connect to + // all pins of a source filter + if (!IsConnected()) { + return NOERROR; + } + + hr = CBaseOutputPin::Active(); + if (FAILED(hr)) { + return hr; + } + + ASSERT(!ThreadExists()); + + // start the thread + if (!Create()) { + return E_FAIL; + } + + // Tell thread to initialize. If OnThreadCreate Fails, so does this. + hr = Init(); + if (FAILED(hr)) + return hr; + + return Pause(); +} + + +// +// Inactive +// +// Pin is inactive - shut down the worker thread +// Waits for the worker to exit before returning. +HRESULT CSourceStream::Inactive(void) { + + CAutoLock lock(m_pFilter->pStateLock()); + + HRESULT hr; + + // do nothing if not connected - its ok not to connect to + // all pins of a source filter + if (!IsConnected()) { + return NOERROR; + } + + // !!! need to do this before trying to stop the thread, because + // we may be stuck waiting for our own allocator!!! + + hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator + if (FAILED(hr)) { + return hr; + } + + if (ThreadExists()) { + hr = Stop(); + + if (FAILED(hr)) { + return hr; + } + + hr = Exit(); + if (FAILED(hr)) { + return hr; + } + + Close(); // Wait for the thread to exit, then tidy up. + } + + // hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator + //if (FAILED(hr)) { + // return hr; + //} + + return NOERROR; +} + + +// +// ThreadProc +// +// When this returns the thread exits +// Return codes > 0 indicate an error occured +DWORD CSourceStream::ThreadProc(void) { + + HRESULT hr; // the return code from calls + Command com; + + do { + com = GetRequest(); + if (com != CMD_INIT) { + DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command"))); + Reply((DWORD) E_UNEXPECTED); + } + } while (com != CMD_INIT); + + DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing"))); + + hr = OnThreadCreate(); // perform set up tasks + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread."))); + OnThreadDestroy(); + Reply(hr); // send failed return code from OnThreadCreate + return 1; + } + + // Initialisation suceeded + Reply(NOERROR); + + Command cmd; + do { + cmd = GetRequest(); + + switch (cmd) { + + case CMD_EXIT: + Reply(NOERROR); + break; + + case CMD_RUN: + DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???"))); + // !!! fall through??? + + case CMD_PAUSE: + Reply(NOERROR); + DoBufferProcessingLoop(); + break; + + case CMD_STOP: + Reply(NOERROR); + break; + + default: + DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd)); + Reply((DWORD) E_NOTIMPL); + break; + } + } while (cmd != CMD_EXIT); + + hr = OnThreadDestroy(); // tidy up. + if (FAILED(hr)) { + DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread."))); + return 1; + } + + DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting"))); + return 0; +} + + +// +// DoBufferProcessingLoop +// +// Grabs a buffer and calls the users processing function. +// Overridable, so that different delivery styles can be catered for. +HRESULT CSourceStream::DoBufferProcessingLoop(void) { + + Command com; + + OnThreadStartPlay(); + + do { + while (!CheckRequest(&com)) { + + IMediaSample *pSample; + + HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0); + if (FAILED(hr)) { + Sleep(1); + continue; // go round again. Perhaps the error will go away + // or the allocator is decommited & we will be asked to + // exit soon. + } + + // Virtual function user will override. + hr = FillBuffer(pSample); + + if (hr == S_OK) { + hr = Deliver(pSample); + pSample->Release(); + + // downstream filter returns S_FALSE if it wants us to + // stop or an error if it's reporting an error. + if(hr != S_OK) + { + DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr)); + return S_OK; + } + + } else if (hr == S_FALSE) { + // derived class wants us to stop pushing data + pSample->Release(); + DeliverEndOfStream(); + return S_OK; + } else { + // derived class encountered an error + pSample->Release(); + DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr)); + DeliverEndOfStream(); + m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0); + return hr; + } + + // all paths release the sample + } + + // For all commands sent to us there must be a Reply call! + + if (com == CMD_RUN || com == CMD_PAUSE) { + Reply(NOERROR); + } else if (com != CMD_STOP) { + Reply((DWORD) E_UNEXPECTED); + DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!"))); + } + } while (com != CMD_STOP); + + return S_FALSE; +} + diff --git a/src/thirdparty/BaseClasses/source.h b/src/thirdparty/BaseClasses/source.h index e6e451bd057..528d5bcbf39 100644 --- a/src/thirdparty/BaseClasses/source.h +++ b/src/thirdparty/BaseClasses/source.h @@ -1,172 +1,172 @@ -//------------------------------------------------------------------------------ -// File: Source.h -// -// Desc: DirectShow base classes - defines classes to simplify creation of -// ActiveX source filters that support continuous generation of data. -// No support is provided for IMediaControl or IMediaPosition. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// Derive your source filter from CSource. -// During construction either: -// Create some CSourceStream objects to manage your pins -// Provide the user with a means of doing so eg, an IPersistFile interface. -// -// CSource provides: -// IBaseFilter interface management -// IMediaFilter interface management, via CBaseFilter -// Pin counting for CBaseFilter -// -// Derive a class from CSourceStream to manage your output pin types -// Implement GetMediaType/1 to return the type you support. If you support multiple -// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount. -// Implement Fillbuffer() to put data into one buffer. -// -// CSourceStream provides: -// IPin management via CBaseOutputPin -// Worker thread management - -#ifndef __CSOURCE__ -#define __CSOURCE__ - -class CSourceStream; // The class that will handle each pin - - -// -// CSource -// -// Override construction to provide a means of creating -// CSourceStream derived objects - ie a way of creating pins. -class CSource : public CBaseFilter { -public: - - CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr); - CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid); -#ifdef UNICODE - CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr); - CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid); -#endif - ~CSource(); - - int GetPinCount(void); - CBasePin *GetPin(int n); - - // -- Utilities -- - - CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section - - HRESULT AddPin(__in CSourceStream *); - HRESULT RemovePin(__in CSourceStream *); - - STDMETHODIMP FindPin( - LPCWSTR Id, - __deref_out IPin ** ppPin - ); - - int FindPinNumber(__in IPin *iPin); - -protected: - - int m_iPins; // The number of pins on this filter. Updated by CSourceStream - // constructors & destructors. - CSourceStream **m_paStreams; // the pins on this filter. - - CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state - -}; - - -// -// CSourceStream -// -// Use this class to manage a stream of data that comes from a -// pin. -// Uses a worker thread to put data on the pin. -class CSourceStream : public CAMThread, public CBaseOutputPin { -public: - - CSourceStream(__in_opt LPCTSTR pObjectName, - __inout HRESULT *phr, - __inout CSource *pms, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CSourceStream(__in_opt LPCSTR pObjectName, - __inout HRESULT *phr, - __inout CSource *pms, - __in_opt LPCWSTR pName); -#endif - virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too. - -protected: - - CSource *m_pFilter; // The parent of this stream - - // * - // * Data Source - // * - // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are - // * called from within the ThreadProc. They are used in the creation of - // * the media samples this pin will provide - // * - - // Override this to provide the worker thread a means - // of processing a buffer - virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE; - - // Called as the thread is created/destroyed - use to perform - // jobs such as start/stop streaming mode - // If OnThreadCreate returns an error the thread will exit. - virtual HRESULT OnThreadCreate(void) {return NOERROR;}; - virtual HRESULT OnThreadDestroy(void) {return NOERROR;}; - virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}; - - // * - // * Worker Thread - // * - - HRESULT Active(void); // Starts up the worker thread - HRESULT Inactive(void); // Exits the worker thread. - -public: - // thread commands - enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}; - HRESULT Init(void) { return CallWorker(CMD_INIT); } - HRESULT Exit(void) { return CallWorker(CMD_EXIT); } - HRESULT Run(void) { return CallWorker(CMD_RUN); } - HRESULT Pause(void) { return CallWorker(CMD_PAUSE); } - HRESULT Stop(void) { return CallWorker(CMD_STOP); } - -protected: - Command GetRequest(void) { return (Command) CAMThread::GetRequest(); } - BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); } - - // override these if you want to add thread commands - virtual DWORD ThreadProc(void); // the thread function - - virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running - - - // * - // * AM_MEDIA_TYPE support - // * - - // If you support more than one media type then override these 2 functions - virtual HRESULT CheckMediaType(const CMediaType *pMediaType); - virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); // List pos. 0-n - - // If you support only one type then override this fn. - // This will only be called by the default implementations - // of CheckMediaType and GetMediaType(int, CMediaType*) - // You must override this fn. or the above 2! - virtual HRESULT GetMediaType(__inout CMediaType *pMediaType) {return E_UNEXPECTED;} - - STDMETHODIMP QueryId( - __deref_out LPWSTR * Id - ); -}; - -#endif // __CSOURCE__ - +//------------------------------------------------------------------------------ +// File: Source.h +// +// Desc: DirectShow base classes - defines classes to simplify creation of +// ActiveX source filters that support continuous generation of data. +// No support is provided for IMediaControl or IMediaPosition. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// Derive your source filter from CSource. +// During construction either: +// Create some CSourceStream objects to manage your pins +// Provide the user with a means of doing so eg, an IPersistFile interface. +// +// CSource provides: +// IBaseFilter interface management +// IMediaFilter interface management, via CBaseFilter +// Pin counting for CBaseFilter +// +// Derive a class from CSourceStream to manage your output pin types +// Implement GetMediaType/1 to return the type you support. If you support multiple +// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount. +// Implement Fillbuffer() to put data into one buffer. +// +// CSourceStream provides: +// IPin management via CBaseOutputPin +// Worker thread management + +#ifndef __CSOURCE__ +#define __CSOURCE__ + +class CSourceStream; // The class that will handle each pin + + +// +// CSource +// +// Override construction to provide a means of creating +// CSourceStream derived objects - ie a way of creating pins. +class CSource : public CBaseFilter { +public: + + CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr); + CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid); +#ifdef UNICODE + CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr); + CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid); +#endif + ~CSource(); + + int GetPinCount(void); + CBasePin *GetPin(int n); + + // -- Utilities -- + + CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section + + HRESULT AddPin(__in CSourceStream *); + HRESULT RemovePin(__in CSourceStream *); + + STDMETHODIMP FindPin( + LPCWSTR Id, + __deref_out IPin ** ppPin + ); + + int FindPinNumber(__in IPin *iPin); + +protected: + + int m_iPins; // The number of pins on this filter. Updated by CSourceStream + // constructors & destructors. + CSourceStream **m_paStreams; // the pins on this filter. + + CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state + +}; + + +// +// CSourceStream +// +// Use this class to manage a stream of data that comes from a +// pin. +// Uses a worker thread to put data on the pin. +class CSourceStream : public CAMThread, public CBaseOutputPin { +public: + + CSourceStream(__in_opt LPCTSTR pObjectName, + __inout HRESULT *phr, + __inout CSource *pms, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CSourceStream(__in_opt LPCSTR pObjectName, + __inout HRESULT *phr, + __inout CSource *pms, + __in_opt LPCWSTR pName); +#endif + virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too. + +protected: + + CSource *m_pFilter; // The parent of this stream + + // * + // * Data Source + // * + // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are + // * called from within the ThreadProc. They are used in the creation of + // * the media samples this pin will provide + // * + + // Override this to provide the worker thread a means + // of processing a buffer + virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE; + + // Called as the thread is created/destroyed - use to perform + // jobs such as start/stop streaming mode + // If OnThreadCreate returns an error the thread will exit. + virtual HRESULT OnThreadCreate(void) {return NOERROR;}; + virtual HRESULT OnThreadDestroy(void) {return NOERROR;}; + virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}; + + // * + // * Worker Thread + // * + + HRESULT Active(void); // Starts up the worker thread + HRESULT Inactive(void); // Exits the worker thread. + +public: + // thread commands + enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}; + HRESULT Init(void) { return CallWorker(CMD_INIT); } + HRESULT Exit(void) { return CallWorker(CMD_EXIT); } + HRESULT Run(void) { return CallWorker(CMD_RUN); } + HRESULT Pause(void) { return CallWorker(CMD_PAUSE); } + HRESULT Stop(void) { return CallWorker(CMD_STOP); } + +protected: + Command GetRequest(void) { return (Command) CAMThread::GetRequest(); } + BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); } + + // override these if you want to add thread commands + virtual DWORD ThreadProc(void); // the thread function + + virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running + + + // * + // * AM_MEDIA_TYPE support + // * + + // If you support more than one media type then override these 2 functions + virtual HRESULT CheckMediaType(const CMediaType *pMediaType); + virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); // List pos. 0-n + + // If you support only one type then override this fn. + // This will only be called by the default implementations + // of CheckMediaType and GetMediaType(int, CMediaType*) + // You must override this fn. or the above 2! + virtual HRESULT GetMediaType(__inout CMediaType *pMediaType) {return E_UNEXPECTED;} + + STDMETHODIMP QueryId( + __deref_out LPWSTR * Id + ); +}; + +#endif // __CSOURCE__ + diff --git a/src/thirdparty/BaseClasses/stdafx.cpp b/src/thirdparty/BaseClasses/stdafx.cpp index a5e9f4e73ff..e728f2aafae 100644 --- a/src/thirdparty/BaseClasses/stdafx.cpp +++ b/src/thirdparty/BaseClasses/stdafx.cpp @@ -1,23 +1,23 @@ -/* - * (C) 2011-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 . - * - */ - -// precompiled headers support - -#include "streams.h" +/* + * (C) 2011-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 . + * + */ + +// precompiled headers support + +#include "streams.h" diff --git a/src/thirdparty/BaseClasses/streams.h b/src/thirdparty/BaseClasses/streams.h index 750252c698d..e91bdf67914 100644 --- a/src/thirdparty/BaseClasses/streams.h +++ b/src/thirdparty/BaseClasses/streams.h @@ -1,190 +1,190 @@ -//------------------------------------------------------------------------------ -// File: Streams.h -// -// Desc: DirectShow base classes - defines overall streams architecture. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __STREAMS__ -#define __STREAMS__ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#ifdef _MSC_VER -// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable -#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter -#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union -#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated -#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated -#pragma warning(disable:4514) // warning C4514: "unreferenced inline function has been removed" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif - -#if _MSC_VER>=1100 -#define AM_NOVTABLE __declspec(novtable) -#else -#define AM_NOVTABLE -#endif -#endif // MSC_VER - - -// Because of differences between Visual C++ and older Microsoft SDKs, -// you may have defined _DEBUG without defining DEBUG. This logic -// ensures that both will be set if Visual C++ sets _DEBUG. -#ifdef _DEBUG -#ifndef DEBUG -#define DEBUG -#endif -#endif - - -#include -#include -#include -#include -#include -#include - - -#ifndef NUMELMS -#if _WIN32_WINNT < 0x0600 - #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) -#else - #define NUMELMS(aa) ARRAYSIZE(aa) -#endif -#endif - -/////////////////////////////////////////////////////////////////////////// -// The following definitions come from the Platform SDK and are required if -// the applicaiton is being compiled with the headers from Visual C++ 6.0. -/////////////////////////////////////////////////// //////////////////////// -#ifndef InterlockedExchangePointer - #define InterlockedExchangePointer(Target, Value) \ - (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) -#endif - -#ifndef _WAVEFORMATEXTENSIBLE_ -#define _WAVEFORMATEXTENSIBLE_ -typedef struct { - WAVEFORMATEX Format; - union { - WORD wValidBitsPerSample; /* bits of precision */ - WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ - WORD wReserved; /* If neither applies, set to zero. */ - } Samples; - DWORD dwChannelMask; /* which channels are */ - /* present in stream */ - GUID SubFormat; -} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; -#endif // !_WAVEFORMATEXTENSIBLE_ - -#if !defined(WAVE_FORMAT_EXTENSIBLE) -#define WAVE_FORMAT_EXTENSIBLE 0xFFFE -#endif // !defined(WAVE_FORMAT_EXTENSIBLE) - -#ifndef GetWindowLongPtr - #define GetWindowLongPtrA GetWindowLongA - #define GetWindowLongPtrW GetWindowLongW - #ifdef UNICODE - #define GetWindowLongPtr GetWindowLongPtrW - #else - #define GetWindowLongPtr GetWindowLongPtrA - #endif // !UNICODE -#endif // !GetWindowLongPtr - -#ifndef SetWindowLongPtr - #define SetWindowLongPtrA SetWindowLongA - #define SetWindowLongPtrW SetWindowLongW - #ifdef UNICODE - #define SetWindowLongPtr SetWindowLongPtrW - #else - #define SetWindowLongPtr SetWindowLongPtrA - #endif // !UNICODE -#endif // !SetWindowLongPtr - -#ifndef GWLP_WNDPROC - #define GWLP_WNDPROC (-4) -#endif -#ifndef GWLP_HINSTANCE - #define GWLP_HINSTANCE (-6) -#endif -#ifndef GWLP_HWNDPARENT - #define GWLP_HWNDPARENT (-8) -#endif -#ifndef GWLP_USERDATA - #define GWLP_USERDATA (-21) -#endif -#ifndef GWLP_ID - #define GWLP_ID (-12) -#endif -#ifndef DWLP_MSGRESULT - #define DWLP_MSGRESULT 0 -#endif -#ifndef DWLP_DLGPROC - #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) -#endif -#ifndef DWLP_USER - #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) -#endif -/////////////////////////////////////////////////////////////////////////// -// End Platform SDK definitions -/////////////////////////////////////////////////////////////////////////// - - -#include // Generated IDL header file for streams interfaces -#include // required by amvideo.h - -#include "reftime.h" // Helper class for REFERENCE_TIME management -#include "wxdebug.h" // Debug support for logging and ASSERTs -#include // ActiveMovie video interfaces and definitions -//include amaudio.h explicitly if you need it. it requires the DX SDK. -//#include // ActiveMovie audio interfaces and definitions -#include "wxutil.h" // General helper classes for threads etc -#include "combase.h" // Base COM classes to support IUnknown -#include "dllsetup.h" // Filter registration support functions -#include "measure.h" // Performance measurement -#include // Light weight com function prototypes - -#include "cache.h" // Simple cache container class -#include "wxlist.h" // Non MFC generic list class -#include "msgthrd.h" // CMsgThread -#include "mtype.h" // Helper class for managing media types -#include "fourcc.h" // conversions between FOURCCs and GUIDs -#include // generated from control.odl -#include "ctlutil.h" // control interface utility classes -#include // event code definitions -#include "amfilter.h" // Main streams architecture class hierachy -#include "transfrm.h" // Generic transform filter -#include "transip.h" // Generic transform-in-place filter -#include // declaration of type GUIDs and well-known clsids -#include "source.h" // Generic source filter -#include "outputq.h" // Output pin queueing -#include // HRESULT status and error definitions -#include "renbase.h" // Base class for writing ActiveX renderers -#include "winutil.h" // Helps with filters that manage windows -#include "winctrl.h" // Implements the IVideoWindow interface -#include "videoctl.h" // Specifically video related classes -#include "refclock.h" // Base clock class -#include "sysclock.h" // System clock -#include "pstream.h" // IPersistStream helper class -#include "vtrans.h" // Video Transform Filter base class -#include "amextra.h" -#include "cprop.h" // Base property page class -#include "strmctl.h" // IAMStreamControl support -#include // External device control interface defines -#include // audio filter device error event codes - - - -#else - #ifdef _DEBUG - #pragma message("STREAMS.H included TWICE") - #endif -#endif // __STREAMS__ - +//------------------------------------------------------------------------------ +// File: Streams.h +// +// Desc: DirectShow base classes - defines overall streams architecture. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __STREAMS__ +#define __STREAMS__ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifdef _MSC_VER +// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable +#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter +#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union +#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated +#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated +#pragma warning(disable:4514) // warning C4514: "unreferenced inline function has been removed" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif + +#if _MSC_VER>=1100 +#define AM_NOVTABLE __declspec(novtable) +#else +#define AM_NOVTABLE +#endif +#endif // MSC_VER + + +// Because of differences between Visual C++ and older Microsoft SDKs, +// you may have defined _DEBUG without defining DEBUG. This logic +// ensures that both will be set if Visual C++ sets _DEBUG. +#ifdef _DEBUG +#ifndef DEBUG +#define DEBUG +#endif +#endif + + +#include +#include +#include +#include +#include +#include + + +#ifndef NUMELMS +#if _WIN32_WINNT < 0x0600 + #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0])) +#else + #define NUMELMS(aa) ARRAYSIZE(aa) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////// +// The following definitions come from the Platform SDK and are required if +// the applicaiton is being compiled with the headers from Visual C++ 6.0. +/////////////////////////////////////////////////// //////////////////////// +#ifndef InterlockedExchangePointer + #define InterlockedExchangePointer(Target, Value) \ + (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)) +#endif + +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct { + WAVEFORMATEX Format; + union { + WORD wValidBitsPerSample; /* bits of precision */ + WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ + WORD wReserved; /* If neither applies, set to zero. */ + } Samples; + DWORD dwChannelMask; /* which channels are */ + /* present in stream */ + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; +#endif // !_WAVEFORMATEXTENSIBLE_ + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif // !defined(WAVE_FORMAT_EXTENSIBLE) + +#ifndef GetWindowLongPtr + #define GetWindowLongPtrA GetWindowLongA + #define GetWindowLongPtrW GetWindowLongW + #ifdef UNICODE + #define GetWindowLongPtr GetWindowLongPtrW + #else + #define GetWindowLongPtr GetWindowLongPtrA + #endif // !UNICODE +#endif // !GetWindowLongPtr + +#ifndef SetWindowLongPtr + #define SetWindowLongPtrA SetWindowLongA + #define SetWindowLongPtrW SetWindowLongW + #ifdef UNICODE + #define SetWindowLongPtr SetWindowLongPtrW + #else + #define SetWindowLongPtr SetWindowLongPtrA + #endif // !UNICODE +#endif // !SetWindowLongPtr + +#ifndef GWLP_WNDPROC + #define GWLP_WNDPROC (-4) +#endif +#ifndef GWLP_HINSTANCE + #define GWLP_HINSTANCE (-6) +#endif +#ifndef GWLP_HWNDPARENT + #define GWLP_HWNDPARENT (-8) +#endif +#ifndef GWLP_USERDATA + #define GWLP_USERDATA (-21) +#endif +#ifndef GWLP_ID + #define GWLP_ID (-12) +#endif +#ifndef DWLP_MSGRESULT + #define DWLP_MSGRESULT 0 +#endif +#ifndef DWLP_DLGPROC + #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) +#endif +#ifndef DWLP_USER + #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) +#endif +/////////////////////////////////////////////////////////////////////////// +// End Platform SDK definitions +/////////////////////////////////////////////////////////////////////////// + + +#include // Generated IDL header file for streams interfaces +#include // required by amvideo.h + +#include "reftime.h" // Helper class for REFERENCE_TIME management +#include "wxdebug.h" // Debug support for logging and ASSERTs +#include // ActiveMovie video interfaces and definitions +//include amaudio.h explicitly if you need it. it requires the DX SDK. +//#include // ActiveMovie audio interfaces and definitions +#include "wxutil.h" // General helper classes for threads etc +#include "combase.h" // Base COM classes to support IUnknown +#include "dllsetup.h" // Filter registration support functions +#include "measure.h" // Performance measurement +#include // Light weight com function prototypes + +#include "cache.h" // Simple cache container class +#include "wxlist.h" // Non MFC generic list class +#include "msgthrd.h" // CMsgThread +#include "mtype.h" // Helper class for managing media types +#include "fourcc.h" // conversions between FOURCCs and GUIDs +#include // generated from control.odl +#include "ctlutil.h" // control interface utility classes +#include // event code definitions +#include "amfilter.h" // Main streams architecture class hierachy +#include "transfrm.h" // Generic transform filter +#include "transip.h" // Generic transform-in-place filter +#include // declaration of type GUIDs and well-known clsids +#include "source.h" // Generic source filter +#include "outputq.h" // Output pin queueing +#include // HRESULT status and error definitions +#include "renbase.h" // Base class for writing ActiveX renderers +#include "winutil.h" // Helps with filters that manage windows +#include "winctrl.h" // Implements the IVideoWindow interface +#include "videoctl.h" // Specifically video related classes +#include "refclock.h" // Base clock class +#include "sysclock.h" // System clock +#include "pstream.h" // IPersistStream helper class +#include "vtrans.h" // Video Transform Filter base class +#include "amextra.h" +#include "cprop.h" // Base property page class +#include "strmctl.h" // IAMStreamControl support +#include // External device control interface defines +#include // audio filter device error event codes + + + +#else + #ifdef _DEBUG + #pragma message("STREAMS.H included TWICE") + #endif +#endif // __STREAMS__ + diff --git a/src/thirdparty/BaseClasses/strmctl.cpp b/src/thirdparty/BaseClasses/strmctl.cpp index e2bad28b9c3..846b0d24319 100644 --- a/src/thirdparty/BaseClasses/strmctl.cpp +++ b/src/thirdparty/BaseClasses/strmctl.cpp @@ -1,405 +1,405 @@ -//------------------------------------------------------------------------------ -// File: StrmCtl.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "strmctl.h" - -CBaseStreamControl::CBaseStreamControl(__inout HRESULT *phr) -: m_StreamState(STREAM_FLOWING) -, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop -, m_tStartTime(MAX_TIME) -, m_tStopTime(MAX_TIME) -, m_StreamEvent(FALSE, phr) -, m_dwStartCookie(0) -, m_dwStopCookie(0) -, m_pRefClock(NULL) -, m_FilterState(State_Stopped) -, m_bIsFlushing(FALSE) -, m_bStopSendExtra(FALSE) -, m_bStopExtraSent(FALSE) -, m_pSink(NULL) -, m_tRunStart(0) -{} - -CBaseStreamControl::~CBaseStreamControl() -{ - // Make sure we release the clock. - SetSyncSource(NULL); - return; -} - - -STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) -{ - CAutoLock lck(&m_CritSec); - m_bStopSendExtra = FALSE; // reset - m_bStopExtraSent = FALSE; - if (ptStop) - { - if (*ptStop == MAX_TIME) - { - DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop"))); - CancelStop(); - // If there's now a command to start in the future, we assume - // they want to be stopped when the graph is first run - if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) { - m_StreamState = STREAM_DISCARDING; - DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); - } - return NOERROR; - } - DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"), - (int)(*ptStop/10000), bSendExtra)); - // if the first command is to stop in the future, then we assume they - // want to be started when the graph is first run - if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) { - m_StreamState = STREAM_FLOWING; - DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); - } - m_bStopSendExtra = bSendExtra; - m_tStopTime = *ptStop; - m_dwStopCookie = dwCookie; - m_StreamStateOnStop = STREAM_DISCARDING; - } - else - { - DbgLog((LOG_TRACE,2,TEXT("StopAt: now"))); - // sending an extra frame when told to stop now would mess people up - m_bStopSendExtra = FALSE; - m_tStopTime = MAX_TIME; - m_dwStopCookie = 0; - m_StreamState = STREAM_DISCARDING; - m_StreamStateOnStop = STREAM_FLOWING; // no pending stop - } - // we might change our mind what to do with a sample we're blocking - m_StreamEvent.Set(); - return NOERROR; -} - -STDMETHODIMP CBaseStreamControl::StartAt -( const REFERENCE_TIME *ptStart, DWORD dwCookie ) -{ - CAutoLock lck(&m_CritSec); - if (ptStart) - { - if (*ptStart == MAX_TIME) - { - DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start"))); - CancelStart(); - // If there's now a command to stop in the future, we assume - // they want to be started when the graph is first run - if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) { - DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); - m_StreamState = STREAM_FLOWING; - } - return NOERROR; - } - DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000))); - // if the first command is to start in the future, then we assume they - // want to be stopped when the graph is first run - if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) { - DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); - m_StreamState = STREAM_DISCARDING; - } - m_tStartTime = *ptStart; - m_dwStartCookie = dwCookie; - // if (m_tStopTime == m_tStartTime) CancelStop(); - } - else - { - DbgLog((LOG_TRACE,2,TEXT("StartAt: now"))); - m_tStartTime = MAX_TIME; - m_dwStartCookie = 0; - m_StreamState = STREAM_FLOWING; - } - // we might change our mind what to do with a sample we're blocking - m_StreamEvent.Set(); - return NOERROR; -} - -// Retrieve information about current settings -STDMETHODIMP CBaseStreamControl::GetInfo(__out AM_STREAM_INFO *pInfo) -{ - if (pInfo == NULL) - return E_POINTER; - - pInfo->tStart = m_tStartTime; - pInfo->tStop = m_tStopTime; - pInfo->dwStartCookie = m_dwStartCookie; - pInfo->dwStopCookie = m_dwStopCookie; - pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0; - pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED; - pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED; - switch (m_StreamState) { - default: - DbgBreak("Invalid stream state"); - case STREAM_FLOWING: - break; - case STREAM_DISCARDING: - pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING; - break; - } - return S_OK; -} - - -void CBaseStreamControl::ExecuteStop() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_StreamState = m_StreamStateOnStop; - if (m_dwStopCookie && m_pSink) { - DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"), - m_dwStopCookie)); - m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie); - } - CancelStop(); // This will do the tidy up -} - -void CBaseStreamControl::ExecuteStart() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_StreamState = STREAM_FLOWING; - if (m_dwStartCookie) { - DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"), - m_dwStartCookie)); - m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie); - } - CancelStart(); // This will do the tidy up -} - -void CBaseStreamControl::CancelStop() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_tStopTime = MAX_TIME; - m_dwStopCookie = 0; - m_StreamStateOnStop = STREAM_FLOWING; -} - -void CBaseStreamControl::CancelStart() -{ - ASSERT(CritCheckIn(&m_CritSec)); - m_tStartTime = MAX_TIME; - m_dwStartCookie = 0; -} - - -// This guy will return one of the three StreamControlState's. Here's what the caller -// should do for each one: -// -// STREAM_FLOWING: Proceed as usual (render or pass the sample on) -// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long -// for the event handle (GetStreamEventHandle()). If the -// wait expires, throw the sample away. If the event -// fires, call me back, I've changed my mind. -// I use pSampleStart (not Stop) so that live sources don't -// block for the duration of their samples, since the clock -// will always read approximately pSampleStart when called - - -// All through this code, you'll notice the following rules: -// - When start and stop time are the same, it's as if start was first -// - An event is considered inside the sample when it's >= sample start time -// but < sample stop time -// - if any part of the sample is supposed to be sent, we'll send the whole -// thing since we don't break it into smaller pieces -// - If we skip over a start or stop without doing it, we still signal the event -// and reset ourselves in case somebody's waiting for the event, and to make -// sure we notice that the event is past and should be forgotten -// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample): -// -// 1. xo<--> start then stop -// 2. ox<--> stop then start -// 3. x start -// 4. o stop then start -// 5. x<-->o start -// 6. o<-->x stop -// 7. o start -// 8. x no change -// 9. start -// 10. stop then start -// 11. <-->xo no change -// 12. <-->ox no change -// 13. x<--> start -// 14. start -// 15. <-->x no change -// 16. o<--> stop -// 17. no change -// 18. <-->o no change -// 19. <--> no change - - -enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes -( __in const REFERENCE_TIME * pSampleStart, __in const REFERENCE_TIME * pSampleStop ) -{ - CAutoLock lck(&m_CritSec); - - ASSERT(!m_bIsFlushing); - ASSERT(pSampleStart && pSampleStop); - - // Don't ask me how I came up with the code below to handle all 19 cases - // - DannyMi - - if (m_tStopTime >= *pSampleStart) - { - if (m_tStartTime >= *pSampleStop) - return m_StreamState; // cases 8 11 12 15 17 18 19 - if (m_tStopTime < m_tStartTime) - ExecuteStop(); // case 10 - ExecuteStart(); // cases 3 5 7 9 13 14 - return m_StreamState; - } - - if (m_tStartTime >= *pSampleStop) - { - ExecuteStop(); // cases 6 16 - return m_StreamState; - } - - if (m_tStartTime <= m_tStopTime) - { - ExecuteStart(); - ExecuteStop(); - return m_StreamState; // case 1 - } - else - { - ExecuteStop(); - ExecuteStart(); - return m_StreamState; // cases 2 4 - } -} - - -enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) -{ - - REFERENCE_TIME rtBufferStart, rtBufferStop; - const BOOL bNoBufferTimes = - pSample == NULL || - FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop)); - - StreamControlState state; - LONG lWait; - - do - { - // something has to break out of the blocking - if (m_bIsFlushing || m_FilterState == State_Stopped) - return STREAM_DISCARDING; - - if (bNoBufferTimes) { - // Can't do anything until we get a time stamp - state = m_StreamState; - break; - } else { - state = CheckSampleTimes( &rtBufferStart, &rtBufferStop ); - if (state == STREAM_FLOWING) - break; - - // we aren't supposed to send this, but we've been - // told to send one more than we were supposed to - // (and the stop isn't still pending and we're streaming) - if (m_bStopSendExtra && !m_bStopExtraSent && - m_tStopTime == MAX_TIME && - m_FilterState != State_Stopped) { - m_bStopExtraSent = TRUE; - DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"), - m_dwStopCookie)); - state = STREAM_FLOWING; - break; - } - } - - // We're in discarding mode - - // If we've no clock, discard as fast as we can - if (!m_pRefClock) { - break; - - // If we're paused, we can't discard in a timely manner because - // there's no such thing as stream times. We must block until - // we run or stop, or we'll end up throwing the whole stream away - // as quickly as possible - } else if (m_FilterState == State_Paused) { - lWait = INFINITE; - - } else { - // wait until it's time for the sample until we say "discard" - // ("discard in a timely fashion") - REFERENCE_TIME rtNow; - EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow))); - rtNow -= m_tRunStart; // Into relative ref-time - lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms - if (lWait < 10) break; // Not worth waiting - discard early - } - - } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT); - - return state; -} - - -void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) -{ - CAutoLock lck(&m_CritSec); - - // or we will get confused - if (m_FilterState == new_state) - return; - - switch (new_state) - { - case State_Stopped: - - DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED"))); - - // execute any pending starts and stops in the right order, - // to make sure all notifications get sent, and we end up - // in the right state to begin next time (??? why not?) - - if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) { - ExecuteStart(); - } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) { - ExecuteStop(); - } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) { - if (m_tStartTime <= m_tStopTime) { - ExecuteStart(); - ExecuteStop(); - } else { - ExecuteStop(); - ExecuteStart(); - } - } - // always start off flowing when the graph starts streaming - // unless told otherwise - m_StreamState = STREAM_FLOWING; - m_FilterState = new_state; - break; - - case State_Running: - - DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING"))); - - m_tRunStart = tStart; - // fall-through - - default: // case State_Paused: - m_FilterState = new_state; - } - // unblock! - m_StreamEvent.Set(); -} - - -void CBaseStreamControl::Flushing(BOOL bInProgress) -{ - CAutoLock lck(&m_CritSec); - m_bIsFlushing = bInProgress; - m_StreamEvent.Set(); -} +//------------------------------------------------------------------------------ +// File: StrmCtl.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "strmctl.h" + +CBaseStreamControl::CBaseStreamControl(__inout HRESULT *phr) +: m_StreamState(STREAM_FLOWING) +, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop +, m_tStartTime(MAX_TIME) +, m_tStopTime(MAX_TIME) +, m_StreamEvent(FALSE, phr) +, m_dwStartCookie(0) +, m_dwStopCookie(0) +, m_pRefClock(NULL) +, m_FilterState(State_Stopped) +, m_bIsFlushing(FALSE) +, m_bStopSendExtra(FALSE) +, m_bStopExtraSent(FALSE) +, m_pSink(NULL) +, m_tRunStart(0) +{} + +CBaseStreamControl::~CBaseStreamControl() +{ + // Make sure we release the clock. + SetSyncSource(NULL); + return; +} + + +STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) +{ + CAutoLock lck(&m_CritSec); + m_bStopSendExtra = FALSE; // reset + m_bStopExtraSent = FALSE; + if (ptStop) + { + if (*ptStop == MAX_TIME) + { + DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop"))); + CancelStop(); + // If there's now a command to start in the future, we assume + // they want to be stopped when the graph is first run + if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) { + m_StreamState = STREAM_DISCARDING; + DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); + } + return NOERROR; + } + DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"), + (int)(*ptStop/10000), bSendExtra)); + // if the first command is to stop in the future, then we assume they + // want to be started when the graph is first run + if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) { + m_StreamState = STREAM_FLOWING; + DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); + } + m_bStopSendExtra = bSendExtra; + m_tStopTime = *ptStop; + m_dwStopCookie = dwCookie; + m_StreamStateOnStop = STREAM_DISCARDING; + } + else + { + DbgLog((LOG_TRACE,2,TEXT("StopAt: now"))); + // sending an extra frame when told to stop now would mess people up + m_bStopSendExtra = FALSE; + m_tStopTime = MAX_TIME; + m_dwStopCookie = 0; + m_StreamState = STREAM_DISCARDING; + m_StreamStateOnStop = STREAM_FLOWING; // no pending stop + } + // we might change our mind what to do with a sample we're blocking + m_StreamEvent.Set(); + return NOERROR; +} + +STDMETHODIMP CBaseStreamControl::StartAt +( const REFERENCE_TIME *ptStart, DWORD dwCookie ) +{ + CAutoLock lck(&m_CritSec); + if (ptStart) + { + if (*ptStart == MAX_TIME) + { + DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start"))); + CancelStart(); + // If there's now a command to stop in the future, we assume + // they want to be started when the graph is first run + if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) { + DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING"))); + m_StreamState = STREAM_FLOWING; + } + return NOERROR; + } + DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000))); + // if the first command is to start in the future, then we assume they + // want to be stopped when the graph is first run + if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) { + DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING"))); + m_StreamState = STREAM_DISCARDING; + } + m_tStartTime = *ptStart; + m_dwStartCookie = dwCookie; + // if (m_tStopTime == m_tStartTime) CancelStop(); + } + else + { + DbgLog((LOG_TRACE,2,TEXT("StartAt: now"))); + m_tStartTime = MAX_TIME; + m_dwStartCookie = 0; + m_StreamState = STREAM_FLOWING; + } + // we might change our mind what to do with a sample we're blocking + m_StreamEvent.Set(); + return NOERROR; +} + +// Retrieve information about current settings +STDMETHODIMP CBaseStreamControl::GetInfo(__out AM_STREAM_INFO *pInfo) +{ + if (pInfo == NULL) + return E_POINTER; + + pInfo->tStart = m_tStartTime; + pInfo->tStop = m_tStopTime; + pInfo->dwStartCookie = m_dwStartCookie; + pInfo->dwStopCookie = m_dwStopCookie; + pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0; + pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED; + pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED; + switch (m_StreamState) { + default: + DbgBreak("Invalid stream state"); + case STREAM_FLOWING: + break; + case STREAM_DISCARDING: + pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING; + break; + } + return S_OK; +} + + +void CBaseStreamControl::ExecuteStop() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_StreamState = m_StreamStateOnStop; + if (m_dwStopCookie && m_pSink) { + DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"), + m_dwStopCookie)); + m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie); + } + CancelStop(); // This will do the tidy up +} + +void CBaseStreamControl::ExecuteStart() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_StreamState = STREAM_FLOWING; + if (m_dwStartCookie) { + DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"), + m_dwStartCookie)); + m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie); + } + CancelStart(); // This will do the tidy up +} + +void CBaseStreamControl::CancelStop() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_tStopTime = MAX_TIME; + m_dwStopCookie = 0; + m_StreamStateOnStop = STREAM_FLOWING; +} + +void CBaseStreamControl::CancelStart() +{ + ASSERT(CritCheckIn(&m_CritSec)); + m_tStartTime = MAX_TIME; + m_dwStartCookie = 0; +} + + +// This guy will return one of the three StreamControlState's. Here's what the caller +// should do for each one: +// +// STREAM_FLOWING: Proceed as usual (render or pass the sample on) +// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long +// for the event handle (GetStreamEventHandle()). If the +// wait expires, throw the sample away. If the event +// fires, call me back, I've changed my mind. +// I use pSampleStart (not Stop) so that live sources don't +// block for the duration of their samples, since the clock +// will always read approximately pSampleStart when called + + +// All through this code, you'll notice the following rules: +// - When start and stop time are the same, it's as if start was first +// - An event is considered inside the sample when it's >= sample start time +// but < sample stop time +// - if any part of the sample is supposed to be sent, we'll send the whole +// thing since we don't break it into smaller pieces +// - If we skip over a start or stop without doing it, we still signal the event +// and reset ourselves in case somebody's waiting for the event, and to make +// sure we notice that the event is past and should be forgotten +// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample): +// +// 1. xo<--> start then stop +// 2. ox<--> stop then start +// 3. x start +// 4. o stop then start +// 5. x<-->o start +// 6. o<-->x stop +// 7. o start +// 8. x no change +// 9. start +// 10. stop then start +// 11. <-->xo no change +// 12. <-->ox no change +// 13. x<--> start +// 14. start +// 15. <-->x no change +// 16. o<--> stop +// 17. no change +// 18. <-->o no change +// 19. <--> no change + + +enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes +( __in const REFERENCE_TIME * pSampleStart, __in const REFERENCE_TIME * pSampleStop ) +{ + CAutoLock lck(&m_CritSec); + + ASSERT(!m_bIsFlushing); + ASSERT(pSampleStart && pSampleStop); + + // Don't ask me how I came up with the code below to handle all 19 cases + // - DannyMi + + if (m_tStopTime >= *pSampleStart) + { + if (m_tStartTime >= *pSampleStop) + return m_StreamState; // cases 8 11 12 15 17 18 19 + if (m_tStopTime < m_tStartTime) + ExecuteStop(); // case 10 + ExecuteStart(); // cases 3 5 7 9 13 14 + return m_StreamState; + } + + if (m_tStartTime >= *pSampleStop) + { + ExecuteStop(); // cases 6 16 + return m_StreamState; + } + + if (m_tStartTime <= m_tStopTime) + { + ExecuteStart(); + ExecuteStop(); + return m_StreamState; // case 1 + } + else + { + ExecuteStop(); + ExecuteStart(); + return m_StreamState; // cases 2 4 + } +} + + +enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) +{ + + REFERENCE_TIME rtBufferStart, rtBufferStop; + const BOOL bNoBufferTimes = + pSample == NULL || + FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop)); + + StreamControlState state; + LONG lWait; + + do + { + // something has to break out of the blocking + if (m_bIsFlushing || m_FilterState == State_Stopped) + return STREAM_DISCARDING; + + if (bNoBufferTimes) { + // Can't do anything until we get a time stamp + state = m_StreamState; + break; + } else { + state = CheckSampleTimes( &rtBufferStart, &rtBufferStop ); + if (state == STREAM_FLOWING) + break; + + // we aren't supposed to send this, but we've been + // told to send one more than we were supposed to + // (and the stop isn't still pending and we're streaming) + if (m_bStopSendExtra && !m_bStopExtraSent && + m_tStopTime == MAX_TIME && + m_FilterState != State_Stopped) { + m_bStopExtraSent = TRUE; + DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"), + m_dwStopCookie)); + state = STREAM_FLOWING; + break; + } + } + + // We're in discarding mode + + // If we've no clock, discard as fast as we can + if (!m_pRefClock) { + break; + + // If we're paused, we can't discard in a timely manner because + // there's no such thing as stream times. We must block until + // we run or stop, or we'll end up throwing the whole stream away + // as quickly as possible + } else if (m_FilterState == State_Paused) { + lWait = INFINITE; + + } else { + // wait until it's time for the sample until we say "discard" + // ("discard in a timely fashion") + REFERENCE_TIME rtNow; + EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow))); + rtNow -= m_tRunStart; // Into relative ref-time + lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms + if (lWait < 10) break; // Not worth waiting - discard early + } + + } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT); + + return state; +} + + +void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) +{ + CAutoLock lck(&m_CritSec); + + // or we will get confused + if (m_FilterState == new_state) + return; + + switch (new_state) + { + case State_Stopped: + + DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED"))); + + // execute any pending starts and stops in the right order, + // to make sure all notifications get sent, and we end up + // in the right state to begin next time (??? why not?) + + if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) { + ExecuteStart(); + } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) { + ExecuteStop(); + } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) { + if (m_tStartTime <= m_tStopTime) { + ExecuteStart(); + ExecuteStop(); + } else { + ExecuteStop(); + ExecuteStart(); + } + } + // always start off flowing when the graph starts streaming + // unless told otherwise + m_StreamState = STREAM_FLOWING; + m_FilterState = new_state; + break; + + case State_Running: + + DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING"))); + + m_tRunStart = tStart; + // fall-through + + default: // case State_Paused: + m_FilterState = new_state; + } + // unblock! + m_StreamEvent.Set(); +} + + +void CBaseStreamControl::Flushing(BOOL bInProgress) +{ + CAutoLock lck(&m_CritSec); + m_bIsFlushing = bInProgress; + m_StreamEvent.Set(); +} diff --git a/src/thirdparty/BaseClasses/strmctl.h b/src/thirdparty/BaseClasses/strmctl.h index 4077e6c3478..cb2adf30851 100644 --- a/src/thirdparty/BaseClasses/strmctl.h +++ b/src/thirdparty/BaseClasses/strmctl.h @@ -1,157 +1,157 @@ -//------------------------------------------------------------------------------ -// File: StrmCtl.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __strmctl_h__ -#define __strmctl_h__ - -class CBaseStreamControl : public IAMStreamControl -{ -public: - // Used by the implementation - enum StreamControlState - { STREAM_FLOWING = 0x1000, - STREAM_DISCARDING - }; - -private: - enum StreamControlState m_StreamState; // Current stream state - enum StreamControlState m_StreamStateOnStop; // State after next stop - // (i.e.Blocking or Discarding) - - REFERENCE_TIME m_tStartTime; // MAX_TIME implies none - REFERENCE_TIME m_tStopTime; // MAX_TIME implies none - DWORD m_dwStartCookie; // Cookie for notification to app - DWORD m_dwStopCookie; // Cookie for notification to app - volatile BOOL m_bIsFlushing; // No optimization pls! - volatile BOOL m_bStopSendExtra; // bSendExtra was set - volatile BOOL m_bStopExtraSent; // the extra one was sent - - CCritSec m_CritSec; // CritSec to guard above attributes - - // Event to fire when we can come - // out of blocking, or to come out of waiting - // to discard if we change our minds. - // - CAMEvent m_StreamEvent; - - // All of these methods execute immediately. Helpers for others. - // - void ExecuteStop(); - void ExecuteStart(); - void CancelStop(); - void CancelStart(); - - // Some things we need to be told by our owning filter - // Your pin must also expose IAMStreamControl when QI'd for it! - // - IReferenceClock * m_pRefClock; // Need it to set advises - // Filter must tell us via - // SetSyncSource - IMediaEventSink * m_pSink; // Event sink - // Filter must tell us after it - // creates it in JoinFilterGraph() - FILTER_STATE m_FilterState; // Just need it! - // Filter must tell us via - // NotifyFilterState - REFERENCE_TIME m_tRunStart; // Per the Run call to the filter - - // This guy will return one of the three StreamControlState's. Here's what - // the caller should do for each one: - // - // STREAM_FLOWING: Proceed as usual (render or pass the sample on) - // STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait - // that long for the event handle - // (GetStreamEventHandle()). If the wait - // expires, throw the sample away. If the event - // fires, call me back - I've changed my mind. - // - enum StreamControlState CheckSampleTimes( __in const REFERENCE_TIME * pSampleStart, - __in const REFERENCE_TIME * pSampleStop ); - -public: - // You don't have to tell us much when we're created, but there are other - // obligations that must be met. See SetSyncSource & NotifyFilterState - // below. - // - CBaseStreamControl(__inout_opt HRESULT *phr = NULL); - ~CBaseStreamControl(); - - // If you want this class to work properly, there are thing you need to - // (keep) telling it. Filters with pins that use this class - // should ensure that they pass through to this method any calls they - // receive on their SetSyncSource. - - // We need a clock to see what time it is. This is for the - // "discard in a timely fashion" logic. If we discard everything as - // quick as possible, a whole 60 minute file could get discarded in the - // first 10 seconds, and if somebody wants to turn streaming on at 30 - // minutes into the file, and they make the call more than a few seconds - // after the graph is run, it may be too late! - // So we hold every sample until it's time has gone, then we discard it. - // The filter should call this when it gets a SetSyncSource - // - void SetSyncSource( IReferenceClock * pRefClock ) - { - CAutoLock lck(&m_CritSec); - if (m_pRefClock) m_pRefClock->Release(); - m_pRefClock = pRefClock; - if (m_pRefClock) m_pRefClock->AddRef(); - } - - // Set event sink for notifications - // The filter should call this in its JoinFilterGraph after it creates the - // IMediaEventSink - // - void SetFilterGraph( IMediaEventSink *pSink ) { - m_pSink = pSink; - } - - // Since we schedule in stream time, we need the tStart and must track the - // state of our owning filter. - // The app should call this ever state change - // - void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 ); - - // Filter should call Flushing(TRUE) in BeginFlush, - // and Flushing(FALSE) in EndFlush. - // - void Flushing( BOOL bInProgress ); - - - // The two main methods of IAMStreamControl - - // Class adds default values suitable for immediate - // muting and unmuting of the stream. - - STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL, - BOOL bSendExtra = FALSE, - DWORD dwCookie = 0 ); - STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL, - DWORD dwCookie = 0 ); - STDMETHODIMP GetInfo( __out AM_STREAM_INFO *pInfo); - - // Helper function for pin's receive method. Call this with - // the sample and we'll tell you what to do with it. We'll do a - // WaitForSingleObject within this call if one is required. This is - // a "What should I do with this sample?" kind of call. We'll tell the - // caller to either flow it or discard it. - // If pSample is NULL we evaluate based on the current state - // settings - enum StreamControlState CheckStreamState( IMediaSample * pSample ); - -private: - // These don't require locking, but we are relying on the fact that - // m_StreamState can be retrieved with integrity, and is a snap shot that - // may have just been, or may be just about to be, changed. - HANDLE GetStreamEventHandle() const { return m_StreamEvent; } - enum StreamControlState GetStreamState() const { return m_StreamState; } - BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; } -}; - -#endif +//------------------------------------------------------------------------------ +// File: StrmCtl.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __strmctl_h__ +#define __strmctl_h__ + +class CBaseStreamControl : public IAMStreamControl +{ +public: + // Used by the implementation + enum StreamControlState + { STREAM_FLOWING = 0x1000, + STREAM_DISCARDING + }; + +private: + enum StreamControlState m_StreamState; // Current stream state + enum StreamControlState m_StreamStateOnStop; // State after next stop + // (i.e.Blocking or Discarding) + + REFERENCE_TIME m_tStartTime; // MAX_TIME implies none + REFERENCE_TIME m_tStopTime; // MAX_TIME implies none + DWORD m_dwStartCookie; // Cookie for notification to app + DWORD m_dwStopCookie; // Cookie for notification to app + volatile BOOL m_bIsFlushing; // No optimization pls! + volatile BOOL m_bStopSendExtra; // bSendExtra was set + volatile BOOL m_bStopExtraSent; // the extra one was sent + + CCritSec m_CritSec; // CritSec to guard above attributes + + // Event to fire when we can come + // out of blocking, or to come out of waiting + // to discard if we change our minds. + // + CAMEvent m_StreamEvent; + + // All of these methods execute immediately. Helpers for others. + // + void ExecuteStop(); + void ExecuteStart(); + void CancelStop(); + void CancelStart(); + + // Some things we need to be told by our owning filter + // Your pin must also expose IAMStreamControl when QI'd for it! + // + IReferenceClock * m_pRefClock; // Need it to set advises + // Filter must tell us via + // SetSyncSource + IMediaEventSink * m_pSink; // Event sink + // Filter must tell us after it + // creates it in JoinFilterGraph() + FILTER_STATE m_FilterState; // Just need it! + // Filter must tell us via + // NotifyFilterState + REFERENCE_TIME m_tRunStart; // Per the Run call to the filter + + // This guy will return one of the three StreamControlState's. Here's what + // the caller should do for each one: + // + // STREAM_FLOWING: Proceed as usual (render or pass the sample on) + // STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait + // that long for the event handle + // (GetStreamEventHandle()). If the wait + // expires, throw the sample away. If the event + // fires, call me back - I've changed my mind. + // + enum StreamControlState CheckSampleTimes( __in const REFERENCE_TIME * pSampleStart, + __in const REFERENCE_TIME * pSampleStop ); + +public: + // You don't have to tell us much when we're created, but there are other + // obligations that must be met. See SetSyncSource & NotifyFilterState + // below. + // + CBaseStreamControl(__inout_opt HRESULT *phr = NULL); + ~CBaseStreamControl(); + + // If you want this class to work properly, there are thing you need to + // (keep) telling it. Filters with pins that use this class + // should ensure that they pass through to this method any calls they + // receive on their SetSyncSource. + + // We need a clock to see what time it is. This is for the + // "discard in a timely fashion" logic. If we discard everything as + // quick as possible, a whole 60 minute file could get discarded in the + // first 10 seconds, and if somebody wants to turn streaming on at 30 + // minutes into the file, and they make the call more than a few seconds + // after the graph is run, it may be too late! + // So we hold every sample until it's time has gone, then we discard it. + // The filter should call this when it gets a SetSyncSource + // + void SetSyncSource( IReferenceClock * pRefClock ) + { + CAutoLock lck(&m_CritSec); + if (m_pRefClock) m_pRefClock->Release(); + m_pRefClock = pRefClock; + if (m_pRefClock) m_pRefClock->AddRef(); + } + + // Set event sink for notifications + // The filter should call this in its JoinFilterGraph after it creates the + // IMediaEventSink + // + void SetFilterGraph( IMediaEventSink *pSink ) { + m_pSink = pSink; + } + + // Since we schedule in stream time, we need the tStart and must track the + // state of our owning filter. + // The app should call this ever state change + // + void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 ); + + // Filter should call Flushing(TRUE) in BeginFlush, + // and Flushing(FALSE) in EndFlush. + // + void Flushing( BOOL bInProgress ); + + + // The two main methods of IAMStreamControl + + // Class adds default values suitable for immediate + // muting and unmuting of the stream. + + STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL, + BOOL bSendExtra = FALSE, + DWORD dwCookie = 0 ); + STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL, + DWORD dwCookie = 0 ); + STDMETHODIMP GetInfo( __out AM_STREAM_INFO *pInfo); + + // Helper function for pin's receive method. Call this with + // the sample and we'll tell you what to do with it. We'll do a + // WaitForSingleObject within this call if one is required. This is + // a "What should I do with this sample?" kind of call. We'll tell the + // caller to either flow it or discard it. + // If pSample is NULL we evaluate based on the current state + // settings + enum StreamControlState CheckStreamState( IMediaSample * pSample ); + +private: + // These don't require locking, but we are relying on the fact that + // m_StreamState can be retrieved with integrity, and is a snap shot that + // may have just been, or may be just about to be, changed. + HANDLE GetStreamEventHandle() const { return m_StreamEvent; } + enum StreamControlState GetStreamState() const { return m_StreamState; } + BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; } +}; + +#endif diff --git a/src/thirdparty/BaseClasses/sysclock.cpp b/src/thirdparty/BaseClasses/sysclock.cpp index d671da6fbad..046ad839348 100644 --- a/src/thirdparty/BaseClasses/sysclock.cpp +++ b/src/thirdparty/BaseClasses/sysclock.cpp @@ -1,74 +1,74 @@ -//------------------------------------------------------------------------------ -// File: SysClock.cpp -// -// Desc: DirectShow base classes - implements a system clock based on -// IReferenceClock. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include - - -#ifdef FILTER_DLL - -/* List of class IDs and creator functions for the class factory. This - provides the link between the OLE entry point in the DLL and an object - being created. The class factory will call the static CreateInstance - function when it is asked to create a CLSID_SystemClock object */ - -CFactoryTemplate g_Templates[1] = { - {&CLSID_SystemClock, CSystemClock::CreateInstance} -}; - -int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); -#endif - -/* This goes in the factory template table to create new instances */ -CUnknown * WINAPI CSystemClock::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) -{ - return new CSystemClock(NAME("System reference clock"),pUnk, phr); -} - - -CSystemClock::CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) : - CBaseReferenceClock(pName, pUnk, phr) -{ -} - -STDMETHODIMP CSystemClock::NonDelegatingQueryInterface( - REFIID riid, - __deref_out void ** ppv) -{ - if (riid == IID_IPersist) - { - return GetInterface(static_cast(this), ppv); - } - else if (riid == IID_IAMClockAdjust) - { - return GetInterface(static_cast(this), ppv); - } - else - { - return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv); - } -} - -/* Return the clock's clsid */ -STDMETHODIMP -CSystemClock::GetClassID(__out CLSID *pClsID) -{ - CheckPointer(pClsID,E_POINTER); - ValidateReadWritePtr(pClsID,sizeof(CLSID)); - *pClsID = CLSID_SystemClock; - return NOERROR; -} - - -STDMETHODIMP -CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta) -{ - return SetTimeDelta(rtDelta); -} +//------------------------------------------------------------------------------ +// File: SysClock.cpp +// +// Desc: DirectShow base classes - implements a system clock based on +// IReferenceClock. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include + + +#ifdef FILTER_DLL + +/* List of class IDs and creator functions for the class factory. This + provides the link between the OLE entry point in the DLL and an object + being created. The class factory will call the static CreateInstance + function when it is asked to create a CLSID_SystemClock object */ + +CFactoryTemplate g_Templates[1] = { + {&CLSID_SystemClock, CSystemClock::CreateInstance} +}; + +int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); +#endif + +/* This goes in the factory template table to create new instances */ +CUnknown * WINAPI CSystemClock::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) +{ + return new CSystemClock(NAME("System reference clock"),pUnk, phr); +} + + +CSystemClock::CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) : + CBaseReferenceClock(pName, pUnk, phr) +{ +} + +STDMETHODIMP CSystemClock::NonDelegatingQueryInterface( + REFIID riid, + __deref_out void ** ppv) +{ + if (riid == IID_IPersist) + { + return GetInterface(static_cast(this), ppv); + } + else if (riid == IID_IAMClockAdjust) + { + return GetInterface(static_cast(this), ppv); + } + else + { + return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv); + } +} + +/* Return the clock's clsid */ +STDMETHODIMP +CSystemClock::GetClassID(__out CLSID *pClsID) +{ + CheckPointer(pClsID,E_POINTER); + ValidateReadWritePtr(pClsID,sizeof(CLSID)); + *pClsID = CLSID_SystemClock; + return NOERROR; +} + + +STDMETHODIMP +CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta) +{ + return SetTimeDelta(rtDelta); +} diff --git a/src/thirdparty/BaseClasses/sysclock.h b/src/thirdparty/BaseClasses/sysclock.h index bf9192ce4bf..3976d34654f 100644 --- a/src/thirdparty/BaseClasses/sysclock.h +++ b/src/thirdparty/BaseClasses/sysclock.h @@ -1,39 +1,39 @@ -//------------------------------------------------------------------------------ -// File: SysClock.h -// -// Desc: DirectShow base classes - defines a system clock implementation of -// IReferenceClock. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __SYSTEMCLOCK__ -#define __SYSTEMCLOCK__ - -// -// Base clock. Uses timeGetTime ONLY -// Uses most of the code in the base reference clock. -// Provides GetTime -// - -class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist -{ -public: - // We must be able to create an instance of ourselves - static CUnknown * WINAPI CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); - CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); - - DECLARE_IUNKNOWN - - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); - - // Yield up our class id so that we can be persisted - // Implement required Ipersist method - STDMETHODIMP GetClassID(__out CLSID *pClsID); - - // IAMClockAdjust methods - STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta); -}; //CSystemClock - -#endif /* __SYSTEMCLOCK__ */ +//------------------------------------------------------------------------------ +// File: SysClock.h +// +// Desc: DirectShow base classes - defines a system clock implementation of +// IReferenceClock. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __SYSTEMCLOCK__ +#define __SYSTEMCLOCK__ + +// +// Base clock. Uses timeGetTime ONLY +// Uses most of the code in the base reference clock. +// Provides GetTime +// + +class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist +{ +public: + // We must be able to create an instance of ourselves + static CUnknown * WINAPI CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); + CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr); + + DECLARE_IUNKNOWN + + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv); + + // Yield up our class id so that we can be persisted + // Implement required Ipersist method + STDMETHODIMP GetClassID(__out CLSID *pClsID); + + // IAMClockAdjust methods + STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta); +}; //CSystemClock + +#endif /* __SYSTEMCLOCK__ */ diff --git a/src/thirdparty/BaseClasses/transfrm.cpp b/src/thirdparty/BaseClasses/transfrm.cpp index 30e8e1879bc..1c263c247c4 100644 --- a/src/thirdparty/BaseClasses/transfrm.cpp +++ b/src/thirdparty/BaseClasses/transfrm.cpp @@ -1,1016 +1,1016 @@ -//------------------------------------------------------------------------------ -// File: Transfrm.cpp -// -// Desc: DirectShow base classes - implements class for simple transform -// filters such as video decompressors. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "measure.h" - - -// ================================================================= -// Implements the CTransformFilter class -// ================================================================= - -CTransformFilter::CTransformFilter(__in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - REFCLSID clsid) : - CBaseFilter(pName,pUnk,&m_csFilter, clsid), - m_pInput(NULL), - m_pOutput(NULL), - m_bEOSDelivered(FALSE), - m_bQualityChanged(FALSE), - m_bSampleSkipped(FALSE) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} - -#ifdef UNICODE -CTransformFilter::CTransformFilter(__in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - REFCLSID clsid) : - CBaseFilter(pName,pUnk,&m_csFilter, clsid), - m_pInput(NULL), - m_pOutput(NULL), - m_bEOSDelivered(FALSE), - m_bQualityChanged(FALSE), - m_bSampleSkipped(FALSE) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} -#endif - -// destructor - -CTransformFilter::~CTransformFilter() -{ - // Delete the pins - - delete m_pInput; - delete m_pOutput; -} - - -// Transform place holder - should never be called -HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut) -{ - UNREFERENCED_PARAMETER(pIn); - UNREFERENCED_PARAMETER(pOut); - DbgBreak("CTransformFilter::Transform() should never be called"); - return E_UNEXPECTED; -} - - -// return the number of pins we provide - -int CTransformFilter::GetPinCount() -{ - return 2; -} - - -// return a non-addrefed CBasePin * for the user to addref if he holds onto it -// for longer than his pointer to us. We create the pins dynamically when they -// are asked for rather than in the constructor. This is because we want to -// give the derived class an oppportunity to return different pin objects - -// We return the objects as and when they are needed. If either of these fails -// then we return NULL, the assumption being that the caller will realise the -// whole deal is off and destroy us - which in turn will delete everything. - -CBasePin * -CTransformFilter::GetPin(int n) -{ - HRESULT hr = S_OK; - - // Create an input pin if necessary - - if (m_pInput == NULL) { - - m_pInput = new CTransformInputPin(NAME("Transform input pin"), - this, // Owner filter - &hr, // Result code - L"XForm In"); // Pin name - - - // Can't fail - ASSERT(SUCCEEDED(hr)); - if (m_pInput == NULL) { - return NULL; - } - m_pOutput = (CTransformOutputPin *) - new CTransformOutputPin(NAME("Transform output pin"), - this, // Owner filter - &hr, // Result code - L"XForm Out"); // Pin name - - - // Can't fail - ASSERT(SUCCEEDED(hr)); - if (m_pOutput == NULL) { - delete m_pInput; - m_pInput = NULL; - } - } - - // Return the appropriate pin - - if (n == 0) { - return m_pInput; - } else - if (n == 1) { - return m_pOutput; - } else { - return NULL; - } -} - - -// -// FindPin -// -// If Id is In or Out then return the IPin* for that pin -// creating the pin if need be. Otherwise return NULL with an error. - -STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) -{ - CheckPointer(ppPin,E_POINTER); - ValidateReadWritePtr(ppPin,sizeof(IPin *)); - - if (0==lstrcmpW(Id,L"In")) { - *ppPin = GetPin(0); - } else if (0==lstrcmpW(Id,L"Out")) { - *ppPin = GetPin(1); - } else { - *ppPin = NULL; - return VFW_E_NOT_FOUND; - } - - HRESULT hr = NOERROR; - // AddRef() returned pointer - but GetPin could fail if memory is low. - if (*ppPin) { - (*ppPin)->AddRef(); - } else { - hr = E_OUTOFMEMORY; // probably. There's no pin anyway. - } - return hr; -} - - -// override these two functions if you want to inform something -// about entry to or exit from streaming state. - -HRESULT -CTransformFilter::StartStreaming() -{ - return NOERROR; -} - - -HRESULT -CTransformFilter::StopStreaming() -{ - return NOERROR; -} - - -// override this to grab extra interfaces on connection - -HRESULT -CTransformFilter::CheckConnect(PIN_DIRECTION dir, IPin *pPin) -{ - UNREFERENCED_PARAMETER(dir); - UNREFERENCED_PARAMETER(pPin); - return NOERROR; -} - - -// place holder to allow derived classes to release any extra interfaces - -HRESULT -CTransformFilter::BreakConnect(PIN_DIRECTION dir) -{ - UNREFERENCED_PARAMETER(dir); - return NOERROR; -} - - -// Let derived classes know about connection completion - -HRESULT -CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(direction); - UNREFERENCED_PARAMETER(pReceivePin); - return NOERROR; -} - - -// override this to know when the media type is really set - -HRESULT -CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt) -{ - UNREFERENCED_PARAMETER(direction); - UNREFERENCED_PARAMETER(pmt); - return NOERROR; -} - - -// Set up our output sample -HRESULT -CTransformFilter::InitializeOutputSample(IMediaSample *pSample, __deref_out IMediaSample **ppOutSample) -{ - IMediaSample *pOutSample; - - // default - times are the same - - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; - - // This will prevent the image renderer from switching us to DirectDraw - // when we can't do it without skipping frames because we're not on a - // keyframe. If it really has to switch us, it still will, but then we - // will have to wait for the next keyframe - if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { - dwFlags |= AM_GBF_NOTASYNCPOINT; - } - - ASSERT(m_pOutput->m_pAllocator != NULL); - HRESULT hr = m_pOutput->m_pAllocator->GetBuffer( - &pOutSample - , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? - &pProps->tStart : NULL - , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? - &pProps->tStop : NULL - , dwFlags - ); - *ppOutSample = pOutSample; - if (FAILED(hr)) { - return hr; - } - - ASSERT(pOutSample); - IMediaSample2 *pOutSample2; - if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, - (void **)&pOutSample2))) { - /* Modify it */ - AM_SAMPLE2_PROPERTIES OutProps; - EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps) - )); - OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; - OutProps.dwSampleFlags = - (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | - (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); - OutProps.tStart = pProps->tStart; - OutProps.tStop = pProps->tStop; - OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); - hr = pOutSample2->SetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), - (PBYTE)&OutProps - ); - if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - m_bSampleSkipped = FALSE; - } - pOutSample2->Release(); - } else { - if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { - pOutSample->SetTime(&pProps->tStart, - &pProps->tStop); - } - if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { - pOutSample->SetSyncPoint(TRUE); - } - if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { - pOutSample->SetDiscontinuity(TRUE); - m_bSampleSkipped = FALSE; - } - // Copy the media times - - LONGLONG MediaStart, MediaEnd; - if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { - pOutSample->SetMediaTime(&MediaStart,&MediaEnd); - } - } - return S_OK; -} - -// override this to customize the transform process - -HRESULT -CTransformFilter::Receive(IMediaSample *pSample) -{ - /* Check for other streams and pass them on */ - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - if (pProps->dwStreamId != AM_STREAM_MEDIA) { - return m_pOutput->m_pInputPin->Receive(pSample); - } - HRESULT hr; - ASSERT(pSample); - IMediaSample * pOutSample; - - // If no output to deliver to then no point sending us data - - ASSERT (m_pOutput != NULL) ; - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - // Start timing the transform (if PERF is defined) - MSR_START(m_idTransform); - - // have the derived class transform the data - - hr = Transform(pSample, pOutSample); - - // Stop the clock and log it (if PERF is defined) - MSR_STOP(m_idTransform); - - if (FAILED(hr)) { - DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); - } else { - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - if (hr == NOERROR) { - hr = m_pOutput->m_pInputPin->Receive(pOutSample); - m_bSampleSkipped = FALSE; // last thing no longer dropped - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this cause because returning S_FALSE - // from Receive() means that this is the end of the stream and no more data should - // be sent. - if (S_FALSE == hr) { - - // Release the sample before calling notify to avoid - // deadlocks if the sample holds a lock on the system - // such as DirectDraw buffers do - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - NotifyEvent(EC_QUALITY_CHANGE,0,0); - m_bQualityChanged = TRUE; - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - - return hr; -} - - -// Return S_FALSE to mean "pass the note on upstream" -// Return NOERROR (Same as S_OK) -// to mean "I've done something about it, don't pass it on" -HRESULT CTransformFilter::AlterQuality(Quality q) -{ - UNREFERENCED_PARAMETER(q); - return S_FALSE; -} - - -// EndOfStream received. Default behaviour is to deliver straight -// downstream, since we have no queued data. If you overrode Receive -// and have queue data, then you need to handle this and deliver EOS after -// all queued data is sent -HRESULT -CTransformFilter::EndOfStream(void) -{ - HRESULT hr = NOERROR; - if (m_pOutput != NULL) { - hr = m_pOutput->DeliverEndOfStream(); - } - - return hr; -} - - -// enter flush state. Receives already blocked -// must override this if you have queued data or a worker thread -HRESULT -CTransformFilter::BeginFlush(void) -{ - HRESULT hr = NOERROR; - if (m_pOutput != NULL) { - // block receives -- done by caller (CBaseInputPin::BeginFlush) - - // discard queued data -- we have no queued data - - // free anyone blocked on receive - not possible in this filter - - // call downstream - hr = m_pOutput->DeliverBeginFlush(); - } - return hr; -} - - -// leave flush state. must override this if you have queued data -// or a worker thread -HRESULT -CTransformFilter::EndFlush(void) -{ - // sync with pushing thread -- we have no worker thread - - // ensure no more data to go downstream -- we have no queued data - - // call EndFlush on downstream pins - ASSERT (m_pOutput != NULL); - return m_pOutput->DeliverEndFlush(); - - // caller (the input pin's method) will unblock Receives -} - - -// override these so that the derived filter can catch them - -STDMETHODIMP -CTransformFilter::Stop() -{ - CAutoLock lck1(&m_csFilter); - if (m_State == State_Stopped) { - return NOERROR; - } - - // Succeed the Stop if we are not completely connected - - ASSERT(m_pInput == NULL || m_pOutput != NULL); - if (m_pInput == NULL || m_pInput->IsConnected() == FALSE || - m_pOutput->IsConnected() == FALSE) { - m_State = State_Stopped; - m_bEOSDelivered = FALSE; - return NOERROR; - } - - ASSERT(m_pInput); - ASSERT(m_pOutput); - - // decommit the input pin before locking or we can deadlock - m_pInput->Inactive(); - - // synchronize with Receive calls - - CAutoLock lck2(&m_csReceive); - m_pOutput->Inactive(); - - // allow a class derived from CTransformFilter - // to know about starting and stopping streaming - - HRESULT hr = StopStreaming(); - if (SUCCEEDED(hr)) { - // complete the state transition - m_State = State_Stopped; - m_bEOSDelivered = FALSE; - } - return hr; -} - - -STDMETHODIMP -CTransformFilter::Pause() -{ - CAutoLock lck(&m_csFilter); - HRESULT hr = NOERROR; - - if (m_State == State_Paused) { - // (This space left deliberately blank) - } - - // If we have no input pin or it isn't yet connected then when we are - // asked to pause we deliver an end of stream to the downstream filter. - // This makes sure that it doesn't sit there forever waiting for - // samples which we cannot ever deliver without an input connection. - - else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) { - if (m_pOutput && m_bEOSDelivered == FALSE) { - m_pOutput->DeliverEndOfStream(); - m_bEOSDelivered = TRUE; - } - m_State = State_Paused; - } - - // We may have an input connection but no output connection - // However, if we have an input pin we do have an output pin - - else if (m_pOutput->IsConnected() == FALSE) { - m_State = State_Paused; - } - - else { - if (m_State == State_Stopped) { - // allow a class derived from CTransformFilter - // to know about starting and stopping streaming - CAutoLock lck2(&m_csReceive); - hr = StartStreaming(); - } - if (SUCCEEDED(hr)) { - hr = CBaseFilter::Pause(); - } - } - - m_bSampleSkipped = FALSE; - m_bQualityChanged = FALSE; - return hr; -} - -HRESULT -CTransformFilter::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - if (m_pOutput != NULL) { - return m_pOutput->DeliverNewSegment(tStart, tStop, dRate); - } - return S_OK; -} - -// Check streaming status -HRESULT -CTransformInputPin::CheckStreaming() -{ - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } else { - // Shouldn't be able to get any data if we're not connected! - ASSERT(IsConnected()); - - // we're flushing - if (m_bFlushing) { - return S_FALSE; - } - // Don't process stuff in Stopped state - if (IsStopped()) { - return VFW_E_WRONG_STATE; - } - if (m_bRunTimeError) { - return VFW_E_RUNTIME_ERROR; - } - return S_OK; - } -} - - -// ================================================================= -// Implements the CTransformInputPin class -// ================================================================= - - -// constructor - -CTransformInputPin::CTransformInputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName) - : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); - m_pTransformFilter = pTransformFilter; -} - -#ifdef UNICODE -CTransformInputPin::CTransformInputPin( - __in_opt LPCSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName) - : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); - m_pTransformFilter = pTransformFilter; -} -#endif - -// provides derived filter a chance to grab extra interfaces - -HRESULT -CTransformInputPin::CheckConnect(IPin *pPin) -{ - HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CheckConnect(pPin); -} - - -// provides derived filter a chance to release it's extra interfaces - -HRESULT -CTransformInputPin::BreakConnect() -{ - // Can't disconnect unless stopped - ASSERT(IsStopped()); - m_pTransformFilter->BreakConnect(PINDIR_INPUT); - return CBaseInputPin::BreakConnect(); -} - - -// Let derived class know when the input pin is connected - -HRESULT -CTransformInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseInputPin::CompleteConnect(pReceivePin); -} - - -// check that we can support a given media type - -HRESULT -CTransformInputPin::CheckMediaType(const CMediaType* pmt) -{ - // Check the input type - - HRESULT hr = m_pTransformFilter->CheckInputType(pmt); - if (S_OK != hr) { - return hr; - } - - // if the output pin is still connected, then we have - // to check the transform not just the input format - - if ((m_pTransformFilter->m_pOutput != NULL) && - (m_pTransformFilter->m_pOutput->IsConnected())) { - return m_pTransformFilter->CheckTransform( - pmt, - &m_pTransformFilter->m_pOutput->CurrentMediaType()); - } else { - return hr; - } -} - - -// set the media type for this connection - -HRESULT -CTransformInputPin::SetMediaType(const CMediaType* mtIn) -{ - // Set the base class media type (should always succeed) - HRESULT hr = CBasePin::SetMediaType(mtIn); - if (FAILED(hr)) { - return hr; - } - - // check the transform can be done (should always succeed) - ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn))); - - return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn); -} - - -// ================================================================= -// Implements IMemInputPin interface -// ================================================================= - - -// provide EndOfStream that passes straight downstream -// (there is no queued data) -STDMETHODIMP -CTransformInputPin::EndOfStream(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csReceive); - HRESULT hr = CheckStreaming(); - if (S_OK == hr) { - hr = m_pTransformFilter->EndOfStream(); - } - return hr; -} - - -// enter flushing state. Call default handler to block Receives, then -// pass to overridable method in filter -STDMETHODIMP -CTransformInputPin::BeginFlush(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csFilter); - // Are we actually doing anything? - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!IsConnected() || - !m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - HRESULT hr = CBaseInputPin::BeginFlush(); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->BeginFlush(); -} - - -// leave flushing state. -// Pass to overridable method in filter, then call base class -// to unblock receives (finally) -STDMETHODIMP -CTransformInputPin::EndFlush(void) -{ - CAutoLock lck(&m_pTransformFilter->m_csFilter); - // Are we actually doing anything? - ASSERT(m_pTransformFilter->m_pOutput != NULL); - if (!IsConnected() || - !m_pTransformFilter->m_pOutput->IsConnected()) { - return VFW_E_NOT_CONNECTED; - } - - HRESULT hr = m_pTransformFilter->EndFlush(); - if (FAILED(hr)) { - return hr; - } - - return CBaseInputPin::EndFlush(); -} - - -// here's the next block of data from the stream. -// AddRef it yourself if you need to hold it beyond the end -// of this call. - -HRESULT -CTransformInputPin::Receive(IMediaSample * pSample) -{ - HRESULT hr; - CAutoLock lck(&m_pTransformFilter->m_csReceive); - ASSERT(pSample); - - // check all is well with the base class - hr = CBaseInputPin::Receive(pSample); - if (S_OK == hr) { - hr = m_pTransformFilter->Receive(pSample); - } - return hr; -} - - - - -// override to pass downstream -STDMETHODIMP -CTransformInputPin::NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate) -{ - // Save the values in the pin - CBasePin::NewSegment(tStart, tStop, dRate); - return m_pTransformFilter->NewSegment(tStart, tStop, dRate); -} - - - - -// ================================================================= -// Implements the CTransformOutputPin class -// ================================================================= - - -// constructor - -CTransformOutputPin::CTransformOutputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), - m_pPosition(NULL) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); - m_pTransformFilter = pTransformFilter; - -} - -#ifdef UNICODE -CTransformOutputPin::CTransformOutputPin( - __in_opt LPCSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pPinName) - : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), - m_pPosition(NULL) -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); - m_pTransformFilter = pTransformFilter; - -} -#endif - -// destructor - -CTransformOutputPin::~CTransformOutputPin() -{ - DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin"))); - - if (m_pPosition) m_pPosition->Release(); -} - - -// overriden to expose IMediaPosition and IMediaSeeking control interfaces - -STDMETHODIMP -CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - CheckPointer(ppv,E_POINTER); - ValidateReadWritePtr(ppv,sizeof(PVOID)); - *ppv = NULL; - - if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { - - // we should have an input pin by now - - ASSERT(m_pTransformFilter->m_pInput != NULL); - - if (m_pPosition == NULL) { - - HRESULT hr = CreatePosPassThru( - GetOwner(), - FALSE, - (IPin *)m_pTransformFilter->m_pInput, - &m_pPosition); - if (FAILED(hr)) { - return hr; - } - } - return m_pPosition->QueryInterface(riid, ppv); - } else { - return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); - } -} - - -// provides derived filter a chance to grab extra interfaces - -HRESULT -CTransformOutputPin::CheckConnect(IPin *pPin) -{ - // we should have an input connection first - - ASSERT(m_pTransformFilter->m_pInput != NULL); - if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { - return E_UNEXPECTED; - } - - HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin); - if (FAILED(hr)) { - return hr; - } - return CBaseOutputPin::CheckConnect(pPin); -} - - -// provides derived filter a chance to release it's extra interfaces - -HRESULT -CTransformOutputPin::BreakConnect() -{ - // Can't disconnect unless stopped - ASSERT(IsStopped()); - m_pTransformFilter->BreakConnect(PINDIR_OUTPUT); - return CBaseOutputPin::BreakConnect(); -} - - -// Let derived class know when the output pin is connected - -HRESULT -CTransformOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); - if (FAILED(hr)) { - return hr; - } - return CBaseOutputPin::CompleteConnect(pReceivePin); -} - - -// check a given transform - must have selected input type first - -HRESULT -CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut) -{ - // must have selected input first - ASSERT(m_pTransformFilter->m_pInput != NULL); - if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { - return E_INVALIDARG; - } - - return m_pTransformFilter->CheckTransform( - &m_pTransformFilter->m_pInput->CurrentMediaType(), - pmtOut); -} - - -// called after we have agreed a media type to actually set it in which case -// we run the CheckTransform function to get the output format type again - -HRESULT -CTransformOutputPin::SetMediaType(const CMediaType* pmtOut) -{ - HRESULT hr = NOERROR; - ASSERT(m_pTransformFilter->m_pInput != NULL); - - ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid()); - - // Set the base class media type (should always succeed) - hr = CBasePin::SetMediaType(pmtOut); - if (FAILED(hr)) { - return hr; - } - -#ifdef _DEBUG - if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter-> - m_pInput->CurrentMediaType(),pmtOut))) { - DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type"))); - DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope"))); - DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input."))); - } -#endif - - return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut); -} - - -// pass the buffer size decision through to the main transform class - -HRESULT -CTransformOutputPin::DecideBufferSize( - IMemAllocator * pAllocator, - __inout ALLOCATOR_PROPERTIES* pProp) -{ - return m_pTransformFilter->DecideBufferSize(pAllocator, pProp); -} - - - -// return a specific media type indexed by iPosition - -HRESULT -CTransformOutputPin::GetMediaType( - int iPosition, - __inout CMediaType *pMediaType) -{ - ASSERT(m_pTransformFilter->m_pInput != NULL); - - // We don't have any media types if our input is not connected - - if (m_pTransformFilter->m_pInput->IsConnected()) { - return m_pTransformFilter->GetMediaType(iPosition,pMediaType); - } else { - return VFW_S_NO_MORE_ITEMS; - } -} - - -// Override this if you can do something constructive to act on the -// quality message. Consider passing it upstream as well - -// Pass the quality mesage on upstream. - -STDMETHODIMP -CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q) -{ - UNREFERENCED_PARAMETER(pSender); - ValidateReadPtr(pSender,sizeof(IBaseFilter)); - - // First see if we want to handle this ourselves - HRESULT hr = m_pTransformFilter->AlterQuality(q); - if (hr!=S_FALSE) { - return hr; // either S_OK or a failure - } - - // S_FALSE means we pass the message on. - // Find the quality sink for our input pin and send it there - - ASSERT(m_pTransformFilter->m_pInput != NULL); - - return m_pTransformFilter->m_pInput->PassNotify(q); - -} // Notify - - -// the following removes a very large number of level 4 warnings from the microsoft -// compiler output, which are not useful at all in this case. -#pragma warning(disable:4514) +//------------------------------------------------------------------------------ +// File: Transfrm.cpp +// +// Desc: DirectShow base classes - implements class for simple transform +// filters such as video decompressors. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "measure.h" + + +// ================================================================= +// Implements the CTransformFilter class +// ================================================================= + +CTransformFilter::CTransformFilter(__in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + REFCLSID clsid) : + CBaseFilter(pName,pUnk,&m_csFilter, clsid), + m_pInput(NULL), + m_pOutput(NULL), + m_bEOSDelivered(FALSE), + m_bQualityChanged(FALSE), + m_bSampleSkipped(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} + +#ifdef UNICODE +CTransformFilter::CTransformFilter(__in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + REFCLSID clsid) : + CBaseFilter(pName,pUnk,&m_csFilter, clsid), + m_pInput(NULL), + m_pOutput(NULL), + m_bEOSDelivered(FALSE), + m_bQualityChanged(FALSE), + m_bSampleSkipped(FALSE) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} +#endif + +// destructor + +CTransformFilter::~CTransformFilter() +{ + // Delete the pins + + delete m_pInput; + delete m_pOutput; +} + + +// Transform place holder - should never be called +HRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut) +{ + UNREFERENCED_PARAMETER(pIn); + UNREFERENCED_PARAMETER(pOut); + DbgBreak("CTransformFilter::Transform() should never be called"); + return E_UNEXPECTED; +} + + +// return the number of pins we provide + +int CTransformFilter::GetPinCount() +{ + return 2; +} + + +// return a non-addrefed CBasePin * for the user to addref if he holds onto it +// for longer than his pointer to us. We create the pins dynamically when they +// are asked for rather than in the constructor. This is because we want to +// give the derived class an oppportunity to return different pin objects + +// We return the objects as and when they are needed. If either of these fails +// then we return NULL, the assumption being that the caller will realise the +// whole deal is off and destroy us - which in turn will delete everything. + +CBasePin * +CTransformFilter::GetPin(int n) +{ + HRESULT hr = S_OK; + + // Create an input pin if necessary + + if (m_pInput == NULL) { + + m_pInput = new CTransformInputPin(NAME("Transform input pin"), + this, // Owner filter + &hr, // Result code + L"XForm In"); // Pin name + + + // Can't fail + ASSERT(SUCCEEDED(hr)); + if (m_pInput == NULL) { + return NULL; + } + m_pOutput = (CTransformOutputPin *) + new CTransformOutputPin(NAME("Transform output pin"), + this, // Owner filter + &hr, // Result code + L"XForm Out"); // Pin name + + + // Can't fail + ASSERT(SUCCEEDED(hr)); + if (m_pOutput == NULL) { + delete m_pInput; + m_pInput = NULL; + } + } + + // Return the appropriate pin + + if (n == 0) { + return m_pInput; + } else + if (n == 1) { + return m_pOutput; + } else { + return NULL; + } +} + + +// +// FindPin +// +// If Id is In or Out then return the IPin* for that pin +// creating the pin if need be. Otherwise return NULL with an error. + +STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, __deref_out IPin **ppPin) +{ + CheckPointer(ppPin,E_POINTER); + ValidateReadWritePtr(ppPin,sizeof(IPin *)); + + if (0==lstrcmpW(Id,L"In")) { + *ppPin = GetPin(0); + } else if (0==lstrcmpW(Id,L"Out")) { + *ppPin = GetPin(1); + } else { + *ppPin = NULL; + return VFW_E_NOT_FOUND; + } + + HRESULT hr = NOERROR; + // AddRef() returned pointer - but GetPin could fail if memory is low. + if (*ppPin) { + (*ppPin)->AddRef(); + } else { + hr = E_OUTOFMEMORY; // probably. There's no pin anyway. + } + return hr; +} + + +// override these two functions if you want to inform something +// about entry to or exit from streaming state. + +HRESULT +CTransformFilter::StartStreaming() +{ + return NOERROR; +} + + +HRESULT +CTransformFilter::StopStreaming() +{ + return NOERROR; +} + + +// override this to grab extra interfaces on connection + +HRESULT +CTransformFilter::CheckConnect(PIN_DIRECTION dir, IPin *pPin) +{ + UNREFERENCED_PARAMETER(dir); + UNREFERENCED_PARAMETER(pPin); + return NOERROR; +} + + +// place holder to allow derived classes to release any extra interfaces + +HRESULT +CTransformFilter::BreakConnect(PIN_DIRECTION dir) +{ + UNREFERENCED_PARAMETER(dir); + return NOERROR; +} + + +// Let derived classes know about connection completion + +HRESULT +CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(direction); + UNREFERENCED_PARAMETER(pReceivePin); + return NOERROR; +} + + +// override this to know when the media type is really set + +HRESULT +CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt) +{ + UNREFERENCED_PARAMETER(direction); + UNREFERENCED_PARAMETER(pmt); + return NOERROR; +} + + +// Set up our output sample +HRESULT +CTransformFilter::InitializeOutputSample(IMediaSample *pSample, __deref_out IMediaSample **ppOutSample) +{ + IMediaSample *pOutSample; + + // default - times are the same + + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; + + // This will prevent the image renderer from switching us to DirectDraw + // when we can't do it without skipping frames because we're not on a + // keyframe. If it really has to switch us, it still will, but then we + // will have to wait for the next keyframe + if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { + dwFlags |= AM_GBF_NOTASYNCPOINT; + } + + ASSERT(m_pOutput->m_pAllocator != NULL); + HRESULT hr = m_pOutput->m_pAllocator->GetBuffer( + &pOutSample + , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? + &pProps->tStart : NULL + , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? + &pProps->tStop : NULL + , dwFlags + ); + *ppOutSample = pOutSample; + if (FAILED(hr)) { + return hr; + } + + ASSERT(pOutSample); + IMediaSample2 *pOutSample2; + if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, + (void **)&pOutSample2))) { + /* Modify it */ + AM_SAMPLE2_PROPERTIES OutProps; + EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps) + )); + OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; + OutProps.dwSampleFlags = + (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | + (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); + OutProps.tStart = pProps->tStart; + OutProps.tStop = pProps->tStop; + OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); + hr = pOutSample2->SetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), + (PBYTE)&OutProps + ); + if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + m_bSampleSkipped = FALSE; + } + pOutSample2->Release(); + } else { + if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { + pOutSample->SetTime(&pProps->tStart, + &pProps->tStop); + } + if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { + pOutSample->SetSyncPoint(TRUE); + } + if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { + pOutSample->SetDiscontinuity(TRUE); + m_bSampleSkipped = FALSE; + } + // Copy the media times + + LONGLONG MediaStart, MediaEnd; + if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { + pOutSample->SetMediaTime(&MediaStart,&MediaEnd); + } + } + return S_OK; +} + +// override this to customize the transform process + +HRESULT +CTransformFilter::Receive(IMediaSample *pSample) +{ + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->m_pInputPin->Receive(pSample); + } + HRESULT hr; + ASSERT(pSample); + IMediaSample * pOutSample; + + // If no output to deliver to then no point sending us data + + ASSERT (m_pOutput != NULL) ; + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + // Start timing the transform (if PERF is defined) + MSR_START(m_idTransform); + + // have the derived class transform the data + + hr = Transform(pSample, pOutSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransform); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE,1,TEXT("Error from transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->m_pInputPin->Receive(pOutSample); + m_bSampleSkipped = FALSE; // last thing no longer dropped + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // Release the sample before calling notify to avoid + // deadlocks if the sample holds a lock on the system + // such as DirectDraw buffers do + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE,0,0); + m_bQualityChanged = TRUE; + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + + return hr; +} + + +// Return S_FALSE to mean "pass the note on upstream" +// Return NOERROR (Same as S_OK) +// to mean "I've done something about it, don't pass it on" +HRESULT CTransformFilter::AlterQuality(Quality q) +{ + UNREFERENCED_PARAMETER(q); + return S_FALSE; +} + + +// EndOfStream received. Default behaviour is to deliver straight +// downstream, since we have no queued data. If you overrode Receive +// and have queue data, then you need to handle this and deliver EOS after +// all queued data is sent +HRESULT +CTransformFilter::EndOfStream(void) +{ + HRESULT hr = NOERROR; + if (m_pOutput != NULL) { + hr = m_pOutput->DeliverEndOfStream(); + } + + return hr; +} + + +// enter flush state. Receives already blocked +// must override this if you have queued data or a worker thread +HRESULT +CTransformFilter::BeginFlush(void) +{ + HRESULT hr = NOERROR; + if (m_pOutput != NULL) { + // block receives -- done by caller (CBaseInputPin::BeginFlush) + + // discard queued data -- we have no queued data + + // free anyone blocked on receive - not possible in this filter + + // call downstream + hr = m_pOutput->DeliverBeginFlush(); + } + return hr; +} + + +// leave flush state. must override this if you have queued data +// or a worker thread +HRESULT +CTransformFilter::EndFlush(void) +{ + // sync with pushing thread -- we have no worker thread + + // ensure no more data to go downstream -- we have no queued data + + // call EndFlush on downstream pins + ASSERT (m_pOutput != NULL); + return m_pOutput->DeliverEndFlush(); + + // caller (the input pin's method) will unblock Receives +} + + +// override these so that the derived filter can catch them + +STDMETHODIMP +CTransformFilter::Stop() +{ + CAutoLock lck1(&m_csFilter); + if (m_State == State_Stopped) { + return NOERROR; + } + + // Succeed the Stop if we are not completely connected + + ASSERT(m_pInput == NULL || m_pOutput != NULL); + if (m_pInput == NULL || m_pInput->IsConnected() == FALSE || + m_pOutput->IsConnected() == FALSE) { + m_State = State_Stopped; + m_bEOSDelivered = FALSE; + return NOERROR; + } + + ASSERT(m_pInput); + ASSERT(m_pOutput); + + // decommit the input pin before locking or we can deadlock + m_pInput->Inactive(); + + // synchronize with Receive calls + + CAutoLock lck2(&m_csReceive); + m_pOutput->Inactive(); + + // allow a class derived from CTransformFilter + // to know about starting and stopping streaming + + HRESULT hr = StopStreaming(); + if (SUCCEEDED(hr)) { + // complete the state transition + m_State = State_Stopped; + m_bEOSDelivered = FALSE; + } + return hr; +} + + +STDMETHODIMP +CTransformFilter::Pause() +{ + CAutoLock lck(&m_csFilter); + HRESULT hr = NOERROR; + + if (m_State == State_Paused) { + // (This space left deliberately blank) + } + + // If we have no input pin or it isn't yet connected then when we are + // asked to pause we deliver an end of stream to the downstream filter. + // This makes sure that it doesn't sit there forever waiting for + // samples which we cannot ever deliver without an input connection. + + else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) { + if (m_pOutput && m_bEOSDelivered == FALSE) { + m_pOutput->DeliverEndOfStream(); + m_bEOSDelivered = TRUE; + } + m_State = State_Paused; + } + + // We may have an input connection but no output connection + // However, if we have an input pin we do have an output pin + + else if (m_pOutput->IsConnected() == FALSE) { + m_State = State_Paused; + } + + else { + if (m_State == State_Stopped) { + // allow a class derived from CTransformFilter + // to know about starting and stopping streaming + CAutoLock lck2(&m_csReceive); + hr = StartStreaming(); + } + if (SUCCEEDED(hr)) { + hr = CBaseFilter::Pause(); + } + } + + m_bSampleSkipped = FALSE; + m_bQualityChanged = FALSE; + return hr; +} + +HRESULT +CTransformFilter::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + if (m_pOutput != NULL) { + return m_pOutput->DeliverNewSegment(tStart, tStop, dRate); + } + return S_OK; +} + +// Check streaming status +HRESULT +CTransformInputPin::CheckStreaming() +{ + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } else { + // Shouldn't be able to get any data if we're not connected! + ASSERT(IsConnected()); + + // we're flushing + if (m_bFlushing) { + return S_FALSE; + } + // Don't process stuff in Stopped state + if (IsStopped()) { + return VFW_E_WRONG_STATE; + } + if (m_bRunTimeError) { + return VFW_E_RUNTIME_ERROR; + } + return S_OK; + } +} + + +// ================================================================= +// Implements the CTransformInputPin class +// ================================================================= + + +// constructor + +CTransformInputPin::CTransformInputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName) + : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); + m_pTransformFilter = pTransformFilter; +} + +#ifdef UNICODE +CTransformInputPin::CTransformInputPin( + __in_opt LPCSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName) + : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin"))); + m_pTransformFilter = pTransformFilter; +} +#endif + +// provides derived filter a chance to grab extra interfaces + +HRESULT +CTransformInputPin::CheckConnect(IPin *pPin) +{ + HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CheckConnect(pPin); +} + + +// provides derived filter a chance to release it's extra interfaces + +HRESULT +CTransformInputPin::BreakConnect() +{ + // Can't disconnect unless stopped + ASSERT(IsStopped()); + m_pTransformFilter->BreakConnect(PINDIR_INPUT); + return CBaseInputPin::BreakConnect(); +} + + +// Let derived class know when the input pin is connected + +HRESULT +CTransformInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseInputPin::CompleteConnect(pReceivePin); +} + + +// check that we can support a given media type + +HRESULT +CTransformInputPin::CheckMediaType(const CMediaType* pmt) +{ + // Check the input type + + HRESULT hr = m_pTransformFilter->CheckInputType(pmt); + if (S_OK != hr) { + return hr; + } + + // if the output pin is still connected, then we have + // to check the transform not just the input format + + if ((m_pTransformFilter->m_pOutput != NULL) && + (m_pTransformFilter->m_pOutput->IsConnected())) { + return m_pTransformFilter->CheckTransform( + pmt, + &m_pTransformFilter->m_pOutput->CurrentMediaType()); + } else { + return hr; + } +} + + +// set the media type for this connection + +HRESULT +CTransformInputPin::SetMediaType(const CMediaType* mtIn) +{ + // Set the base class media type (should always succeed) + HRESULT hr = CBasePin::SetMediaType(mtIn); + if (FAILED(hr)) { + return hr; + } + + // check the transform can be done (should always succeed) + ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn))); + + return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn); +} + + +// ================================================================= +// Implements IMemInputPin interface +// ================================================================= + + +// provide EndOfStream that passes straight downstream +// (there is no queued data) +STDMETHODIMP +CTransformInputPin::EndOfStream(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csReceive); + HRESULT hr = CheckStreaming(); + if (S_OK == hr) { + hr = m_pTransformFilter->EndOfStream(); + } + return hr; +} + + +// enter flushing state. Call default handler to block Receives, then +// pass to overridable method in filter +STDMETHODIMP +CTransformInputPin::BeginFlush(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csFilter); + // Are we actually doing anything? + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!IsConnected() || + !m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + HRESULT hr = CBaseInputPin::BeginFlush(); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->BeginFlush(); +} + + +// leave flushing state. +// Pass to overridable method in filter, then call base class +// to unblock receives (finally) +STDMETHODIMP +CTransformInputPin::EndFlush(void) +{ + CAutoLock lck(&m_pTransformFilter->m_csFilter); + // Are we actually doing anything? + ASSERT(m_pTransformFilter->m_pOutput != NULL); + if (!IsConnected() || + !m_pTransformFilter->m_pOutput->IsConnected()) { + return VFW_E_NOT_CONNECTED; + } + + HRESULT hr = m_pTransformFilter->EndFlush(); + if (FAILED(hr)) { + return hr; + } + + return CBaseInputPin::EndFlush(); +} + + +// here's the next block of data from the stream. +// AddRef it yourself if you need to hold it beyond the end +// of this call. + +HRESULT +CTransformInputPin::Receive(IMediaSample * pSample) +{ + HRESULT hr; + CAutoLock lck(&m_pTransformFilter->m_csReceive); + ASSERT(pSample); + + // check all is well with the base class + hr = CBaseInputPin::Receive(pSample); + if (S_OK == hr) { + hr = m_pTransformFilter->Receive(pSample); + } + return hr; +} + + + + +// override to pass downstream +STDMETHODIMP +CTransformInputPin::NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate) +{ + // Save the values in the pin + CBasePin::NewSegment(tStart, tStop, dRate); + return m_pTransformFilter->NewSegment(tStart, tStop, dRate); +} + + + + +// ================================================================= +// Implements the CTransformOutputPin class +// ================================================================= + + +// constructor + +CTransformOutputPin::CTransformOutputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), + m_pPosition(NULL) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); + m_pTransformFilter = pTransformFilter; + +} + +#ifdef UNICODE +CTransformOutputPin::CTransformOutputPin( + __in_opt LPCSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pPinName) + : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName), + m_pPosition(NULL) +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin"))); + m_pTransformFilter = pTransformFilter; + +} +#endif + +// destructor + +CTransformOutputPin::~CTransformOutputPin() +{ + DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin"))); + + if (m_pPosition) m_pPosition->Release(); +} + + +// overriden to expose IMediaPosition and IMediaSeeking control interfaces + +STDMETHODIMP +CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + *ppv = NULL; + + if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { + + // we should have an input pin by now + + ASSERT(m_pTransformFilter->m_pInput != NULL); + + if (m_pPosition == NULL) { + + HRESULT hr = CreatePosPassThru( + GetOwner(), + FALSE, + (IPin *)m_pTransformFilter->m_pInput, + &m_pPosition); + if (FAILED(hr)) { + return hr; + } + } + return m_pPosition->QueryInterface(riid, ppv); + } else { + return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); + } +} + + +// provides derived filter a chance to grab extra interfaces + +HRESULT +CTransformOutputPin::CheckConnect(IPin *pPin) +{ + // we should have an input connection first + + ASSERT(m_pTransformFilter->m_pInput != NULL); + if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { + return E_UNEXPECTED; + } + + HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin); + if (FAILED(hr)) { + return hr; + } + return CBaseOutputPin::CheckConnect(pPin); +} + + +// provides derived filter a chance to release it's extra interfaces + +HRESULT +CTransformOutputPin::BreakConnect() +{ + // Can't disconnect unless stopped + ASSERT(IsStopped()); + m_pTransformFilter->BreakConnect(PINDIR_OUTPUT); + return CBaseOutputPin::BreakConnect(); +} + + +// Let derived class know when the output pin is connected + +HRESULT +CTransformOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); + if (FAILED(hr)) { + return hr; + } + return CBaseOutputPin::CompleteConnect(pReceivePin); +} + + +// check a given transform - must have selected input type first + +HRESULT +CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut) +{ + // must have selected input first + ASSERT(m_pTransformFilter->m_pInput != NULL); + if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) { + return E_INVALIDARG; + } + + return m_pTransformFilter->CheckTransform( + &m_pTransformFilter->m_pInput->CurrentMediaType(), + pmtOut); +} + + +// called after we have agreed a media type to actually set it in which case +// we run the CheckTransform function to get the output format type again + +HRESULT +CTransformOutputPin::SetMediaType(const CMediaType* pmtOut) +{ + HRESULT hr = NOERROR; + ASSERT(m_pTransformFilter->m_pInput != NULL); + + ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid()); + + // Set the base class media type (should always succeed) + hr = CBasePin::SetMediaType(pmtOut); + if (FAILED(hr)) { + return hr; + } + +#ifdef _DEBUG + if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter-> + m_pInput->CurrentMediaType(),pmtOut))) { + DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type"))); + DbgLog((LOG_ERROR,0,TEXT(" that it can't currently transform to. I hope"))); + DbgLog((LOG_ERROR,0,TEXT(" it's smart enough to reconnect its input."))); + } +#endif + + return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut); +} + + +// pass the buffer size decision through to the main transform class + +HRESULT +CTransformOutputPin::DecideBufferSize( + IMemAllocator * pAllocator, + __inout ALLOCATOR_PROPERTIES* pProp) +{ + return m_pTransformFilter->DecideBufferSize(pAllocator, pProp); +} + + + +// return a specific media type indexed by iPosition + +HRESULT +CTransformOutputPin::GetMediaType( + int iPosition, + __inout CMediaType *pMediaType) +{ + ASSERT(m_pTransformFilter->m_pInput != NULL); + + // We don't have any media types if our input is not connected + + if (m_pTransformFilter->m_pInput->IsConnected()) { + return m_pTransformFilter->GetMediaType(iPosition,pMediaType); + } else { + return VFW_S_NO_MORE_ITEMS; + } +} + + +// Override this if you can do something constructive to act on the +// quality message. Consider passing it upstream as well + +// Pass the quality mesage on upstream. + +STDMETHODIMP +CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q) +{ + UNREFERENCED_PARAMETER(pSender); + ValidateReadPtr(pSender,sizeof(IBaseFilter)); + + // First see if we want to handle this ourselves + HRESULT hr = m_pTransformFilter->AlterQuality(q); + if (hr!=S_FALSE) { + return hr; // either S_OK or a failure + } + + // S_FALSE means we pass the message on. + // Find the quality sink for our input pin and send it there + + ASSERT(m_pTransformFilter->m_pInput != NULL); + + return m_pTransformFilter->m_pInput->PassNotify(q); + +} // Notify + + +// the following removes a very large number of level 4 warnings from the microsoft +// compiler output, which are not useful at all in this case. +#pragma warning(disable:4514) diff --git a/src/thirdparty/BaseClasses/transfrm.h b/src/thirdparty/BaseClasses/transfrm.h index 36c2e0d10b7..9b276471b68 100644 --- a/src/thirdparty/BaseClasses/transfrm.h +++ b/src/thirdparty/BaseClasses/transfrm.h @@ -1,304 +1,304 @@ -//------------------------------------------------------------------------------ -// File: Transfrm.h -// -// Desc: DirectShow base classes - defines classes from which simple -// transform codecs may be derived. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// It assumes the codec has one input and one output stream, and has no -// interest in memory management, interface negotiation or anything else. -// -// derive your class from this, and supply Transform and the media type/format -// negotiation functions. Implement that class, compile and link and -// you're done. - - -#ifndef __TRANSFRM__ -#define __TRANSFRM__ - -// ====================================================================== -// This is the com object that represents a simple transform filter. It -// supports IBaseFilter, IMediaFilter and two pins through nested interfaces -// ====================================================================== - -class CTransformFilter; - -// ================================================== -// Implements the input pin -// ================================================== - -class CTransformInputPin : public CBaseInputPin -{ - friend class CTransformFilter; - -protected: - CTransformFilter *m_pTransformFilter; - - -public: - - CTransformInputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CTransformInputPin( - __in_opt LPCSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName); -#endif - - STDMETHODIMP QueryId(__deref_out LPWSTR * Id) - { - return AMGetWideString(L"In", Id); - } - - // Grab and release extra interfaces if required - - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - - // check that we can support this output type - HRESULT CheckMediaType(const CMediaType* mtIn); - - // set the connection media type - HRESULT SetMediaType(const CMediaType* mt); - - // --- IMemInputPin ----- - - // here's the next block of data from the stream. - // AddRef it yourself if you need to hold it beyond the end - // of this call. - STDMETHODIMP Receive(IMediaSample * pSample); - - // provide EndOfStream that passes straight downstream - // (there is no queued data) - STDMETHODIMP EndOfStream(void); - - // passes it to CTransformFilter::BeginFlush - STDMETHODIMP BeginFlush(void); - - // passes it to CTransformFilter::EndFlush - STDMETHODIMP EndFlush(void); - - STDMETHODIMP NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - - // Check if it's OK to process samples - virtual HRESULT CheckStreaming(); - - // Media type -public: - CMediaType& CurrentMediaType() { return m_mt; }; - -}; - -// ================================================== -// Implements the output pin -// ================================================== - -class CTransformOutputPin : public CBaseOutputPin -{ - friend class CTransformFilter; - -protected: - CTransformFilter *m_pTransformFilter; - -public: - - // implement IMediaPosition by passing upstream - IUnknown * m_pPosition; - - CTransformOutputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName); -#ifdef UNICODE - CTransformOutputPin( - __in_opt LPCSTR pObjectName, - __inout CTransformFilter *pTransformFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pName); -#endif - ~CTransformOutputPin(); - - // override to expose IMediaPosition - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); - - // --- CBaseOutputPin ------------ - - STDMETHODIMP QueryId(__deref_out LPWSTR * Id) - { - return AMGetWideString(L"Out", Id); - } - - // Grab and release extra interfaces if required - - HRESULT CheckConnect(IPin *pPin); - HRESULT BreakConnect(); - HRESULT CompleteConnect(IPin *pReceivePin); - - // check that we can support this output type - HRESULT CheckMediaType(const CMediaType* mtOut); - - // set the connection media type - HRESULT SetMediaType(const CMediaType *pmt); - - // called from CBaseOutputPin during connection to ask for - // the count and size of buffers we need. - HRESULT DecideBufferSize( - IMemAllocator * pAlloc, - __inout ALLOCATOR_PROPERTIES *pProp); - - // returns the preferred formats for a pin - HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); - - // inherited from IQualityControl via CBasePin - STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); - - // Media type -public: - CMediaType& CurrentMediaType() { return m_mt; }; -}; - - -class AM_NOVTABLE CTransformFilter : public CBaseFilter -{ - -public: - - // map getpin/getpincount for base enum of pins to owner - // override this to return more specialised pin objects - - virtual int GetPinCount(); - virtual CBasePin * GetPin(int n); - STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin); - - // override state changes to allow derived transform filter - // to control streaming start/stop - STDMETHODIMP Stop(); - STDMETHODIMP Pause(); - -public: - - CTransformFilter(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, REFCLSID clsid); -#ifdef UNICODE - CTransformFilter(__in_opt LPCSTR , __inout_opt LPUNKNOWN, REFCLSID clsid); -#endif - ~CTransformFilter(); - - // ================================================================= - // ----- override these bits --------------------------------------- - // ================================================================= - - // These must be supplied in a derived class - - virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); - - // check if you can support mtIn - virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; - - // check if you can support the transform from this input to this output - virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE; - - // this goes in the factory template table to create new instances - // static CCOMObject * CreateInstance(__inout_opt LPUNKNOWN, HRESULT *); - - // call the SetProperties function with appropriate arguments - virtual HRESULT DecideBufferSize( - IMemAllocator * pAllocator, - __inout ALLOCATOR_PROPERTIES *pprop) PURE; - - // override to suggest OUTPUT pin media types - virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType) PURE; - - - - // ================================================================= - // ----- Optional Override Methods ----------------------- - // ================================================================= - - // you can also override these if you want to know about streaming - virtual HRESULT StartStreaming(); - virtual HRESULT StopStreaming(); - - // override if you can do anything constructive with quality notifications - virtual HRESULT AlterQuality(Quality q); - - // override this to know when the media type is actually set - virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); - - // chance to grab extra interfaces on connection - virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); - virtual HRESULT BreakConnect(PIN_DIRECTION dir); - virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); - - // chance to customize the transform process - virtual HRESULT Receive(IMediaSample *pSample); - - // Standard setup for output sample - HRESULT InitializeOutputSample(IMediaSample *pSample, __deref_out IMediaSample **ppOutSample); - - // if you override Receive, you may need to override these three too - virtual HRESULT EndOfStream(void); - virtual HRESULT BeginFlush(void); - virtual HRESULT EndFlush(void); - virtual HRESULT NewSegment( - REFERENCE_TIME tStart, - REFERENCE_TIME tStop, - double dRate); - -#ifdef PERF - // Override to register performance measurement with a less generic string - // You should do this to avoid confusion with other filters - virtual void RegisterPerfId() - {m_idTransform = MSR_REGISTER(TEXT("Transform"));} -#endif // PERF - - -// implementation details - -protected: - -#ifdef PERF - int m_idTransform; // performance measuring id -#endif - BOOL m_bEOSDelivered; // have we sent EndOfStream - BOOL m_bSampleSkipped; // Did we just skip a frame - BOOL m_bQualityChanged; // Have we degraded? - - // critical section protecting filter state. - - CCritSec m_csFilter; - - // critical section stopping state changes (ie Stop) while we're - // processing a sample. - // - // This critical section is held when processing - // events that occur on the receive thread - Receive() and EndOfStream(). - // - // If you want to hold both m_csReceive and m_csFilter then grab - // m_csFilter FIRST - like CTransformFilter::Stop() does. - - CCritSec m_csReceive; - - // these hold our input and output pins - - friend class CTransformInputPin; - friend class CTransformOutputPin; - CTransformInputPin *m_pInput; - CTransformOutputPin *m_pOutput; -}; - -#endif /* __TRANSFRM__ */ - - +//------------------------------------------------------------------------------ +// File: Transfrm.h +// +// Desc: DirectShow base classes - defines classes from which simple +// transform codecs may be derived. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// It assumes the codec has one input and one output stream, and has no +// interest in memory management, interface negotiation or anything else. +// +// derive your class from this, and supply Transform and the media type/format +// negotiation functions. Implement that class, compile and link and +// you're done. + + +#ifndef __TRANSFRM__ +#define __TRANSFRM__ + +// ====================================================================== +// This is the com object that represents a simple transform filter. It +// supports IBaseFilter, IMediaFilter and two pins through nested interfaces +// ====================================================================== + +class CTransformFilter; + +// ================================================== +// Implements the input pin +// ================================================== + +class CTransformInputPin : public CBaseInputPin +{ + friend class CTransformFilter; + +protected: + CTransformFilter *m_pTransformFilter; + + +public: + + CTransformInputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CTransformInputPin( + __in_opt LPCSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName); +#endif + + STDMETHODIMP QueryId(__deref_out LPWSTR * Id) + { + return AMGetWideString(L"In", Id); + } + + // Grab and release extra interfaces if required + + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + + // check that we can support this output type + HRESULT CheckMediaType(const CMediaType* mtIn); + + // set the connection media type + HRESULT SetMediaType(const CMediaType* mt); + + // --- IMemInputPin ----- + + // here's the next block of data from the stream. + // AddRef it yourself if you need to hold it beyond the end + // of this call. + STDMETHODIMP Receive(IMediaSample * pSample); + + // provide EndOfStream that passes straight downstream + // (there is no queued data) + STDMETHODIMP EndOfStream(void); + + // passes it to CTransformFilter::BeginFlush + STDMETHODIMP BeginFlush(void); + + // passes it to CTransformFilter::EndFlush + STDMETHODIMP EndFlush(void); + + STDMETHODIMP NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + + // Check if it's OK to process samples + virtual HRESULT CheckStreaming(); + + // Media type +public: + CMediaType& CurrentMediaType() { return m_mt; }; + +}; + +// ================================================== +// Implements the output pin +// ================================================== + +class CTransformOutputPin : public CBaseOutputPin +{ + friend class CTransformFilter; + +protected: + CTransformFilter *m_pTransformFilter; + +public: + + // implement IMediaPosition by passing upstream + IUnknown * m_pPosition; + + CTransformOutputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName); +#ifdef UNICODE + CTransformOutputPin( + __in_opt LPCSTR pObjectName, + __inout CTransformFilter *pTransformFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pName); +#endif + ~CTransformOutputPin(); + + // override to expose IMediaPosition + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); + + // --- CBaseOutputPin ------------ + + STDMETHODIMP QueryId(__deref_out LPWSTR * Id) + { + return AMGetWideString(L"Out", Id); + } + + // Grab and release extra interfaces if required + + HRESULT CheckConnect(IPin *pPin); + HRESULT BreakConnect(); + HRESULT CompleteConnect(IPin *pReceivePin); + + // check that we can support this output type + HRESULT CheckMediaType(const CMediaType* mtOut); + + // set the connection media type + HRESULT SetMediaType(const CMediaType *pmt); + + // called from CBaseOutputPin during connection to ask for + // the count and size of buffers we need. + HRESULT DecideBufferSize( + IMemAllocator * pAlloc, + __inout ALLOCATOR_PROPERTIES *pProp); + + // returns the preferred formats for a pin + HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType); + + // inherited from IQualityControl via CBasePin + STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); + + // Media type +public: + CMediaType& CurrentMediaType() { return m_mt; }; +}; + + +class AM_NOVTABLE CTransformFilter : public CBaseFilter +{ + +public: + + // map getpin/getpincount for base enum of pins to owner + // override this to return more specialised pin objects + + virtual int GetPinCount(); + virtual CBasePin * GetPin(int n); + STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin); + + // override state changes to allow derived transform filter + // to control streaming start/stop + STDMETHODIMP Stop(); + STDMETHODIMP Pause(); + +public: + + CTransformFilter(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, REFCLSID clsid); +#ifdef UNICODE + CTransformFilter(__in_opt LPCSTR , __inout_opt LPUNKNOWN, REFCLSID clsid); +#endif + ~CTransformFilter(); + + // ================================================================= + // ----- override these bits --------------------------------------- + // ================================================================= + + // These must be supplied in a derived class + + virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); + + // check if you can support mtIn + virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; + + // check if you can support the transform from this input to this output + virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE; + + // this goes in the factory template table to create new instances + // static CCOMObject * CreateInstance(__inout_opt LPUNKNOWN, HRESULT *); + + // call the SetProperties function with appropriate arguments + virtual HRESULT DecideBufferSize( + IMemAllocator * pAllocator, + __inout ALLOCATOR_PROPERTIES *pprop) PURE; + + // override to suggest OUTPUT pin media types + virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType) PURE; + + + + // ================================================================= + // ----- Optional Override Methods ----------------------- + // ================================================================= + + // you can also override these if you want to know about streaming + virtual HRESULT StartStreaming(); + virtual HRESULT StopStreaming(); + + // override if you can do anything constructive with quality notifications + virtual HRESULT AlterQuality(Quality q); + + // override this to know when the media type is actually set + virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); + + // chance to grab extra interfaces on connection + virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); + virtual HRESULT BreakConnect(PIN_DIRECTION dir); + virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); + + // chance to customize the transform process + virtual HRESULT Receive(IMediaSample *pSample); + + // Standard setup for output sample + HRESULT InitializeOutputSample(IMediaSample *pSample, __deref_out IMediaSample **ppOutSample); + + // if you override Receive, you may need to override these three too + virtual HRESULT EndOfStream(void); + virtual HRESULT BeginFlush(void); + virtual HRESULT EndFlush(void); + virtual HRESULT NewSegment( + REFERENCE_TIME tStart, + REFERENCE_TIME tStop, + double dRate); + +#ifdef PERF + // Override to register performance measurement with a less generic string + // You should do this to avoid confusion with other filters + virtual void RegisterPerfId() + {m_idTransform = MSR_REGISTER(TEXT("Transform"));} +#endif // PERF + + +// implementation details + +protected: + +#ifdef PERF + int m_idTransform; // performance measuring id +#endif + BOOL m_bEOSDelivered; // have we sent EndOfStream + BOOL m_bSampleSkipped; // Did we just skip a frame + BOOL m_bQualityChanged; // Have we degraded? + + // critical section protecting filter state. + + CCritSec m_csFilter; + + // critical section stopping state changes (ie Stop) while we're + // processing a sample. + // + // This critical section is held when processing + // events that occur on the receive thread - Receive() and EndOfStream(). + // + // If you want to hold both m_csReceive and m_csFilter then grab + // m_csFilter FIRST - like CTransformFilter::Stop() does. + + CCritSec m_csReceive; + + // these hold our input and output pins + + friend class CTransformInputPin; + friend class CTransformOutputPin; + CTransformInputPin *m_pInput; + CTransformOutputPin *m_pOutput; +}; + +#endif /* __TRANSFRM__ */ + + diff --git a/src/thirdparty/BaseClasses/transip.cpp b/src/thirdparty/BaseClasses/transip.cpp index 374b81a1979..b8bc7ef541e 100644 --- a/src/thirdparty/BaseClasses/transip.cpp +++ b/src/thirdparty/BaseClasses/transip.cpp @@ -1,977 +1,977 @@ -//------------------------------------------------------------------------------ -// File: TransIP.cpp -// -// Desc: DirectShow base classes - implements class for simple Transform- -// In-Place filters such as audio. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// How allocators are decided. -// -// An in-place transform tries to do its work in someone else's buffers. -// It tries to persuade the filters on either side to use the same allocator -// (and for that matter the same media type). In desperation, if the downstream -// filter refuses to supply an allocator and the upstream filter offers only -// a read-only one then it will provide an allocator. -// if the upstream filter insists on a read-only allocator then the transform -// filter will (reluctantly) copy the data before transforming it. -// -// In order to pass an allocator through it needs to remember the one it got -// from the first connection to pass it on to the second one. -// -// It is good if we can avoid insisting on a particular order of connection -// (There is a precedent for insisting on the input -// being connected first. Insisting on the output being connected first is -// not allowed. That would break RenderFile.) -// -// The base pin classes (CBaseOutputPin and CBaseInputPin) both have a -// m_pAllocator member which is used in places like -// CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive. -// To avoid lots of extra overriding, we should keep these happy -// by using these pointers. -// -// When each pin is connected, it will set the corresponding m_pAllocator -// and will have a single ref-count on that allocator. -// -// Refcounts are acquired by GetAllocator calls which return AddReffed -// allocators and are released in one of: -// CBaseInputPin::Disconnect -// CBaseOutputPin::BreakConect -// In each case m_pAllocator is set to NULL after the release, so this -// is the last chance to ever release it. If there should ever be -// multiple refcounts associated with the same pointer, this had better -// be cleared up before that happens. To avoid such problems, we'll -// stick with one per pointer. - - - -// RECONNECTING and STATE CHANGES -// -// Each pin could be disconnected, connected with a read-only allocator, -// connected with an upstream read/write allocator, connected with an -// allocator from downstream or connected with its own allocator. -// Five states for each pin gives a data space of 25 states. -// -// Notation: -// -// R/W == read/write -// R-O == read-only -// -// -// -// 00 means an unconnected pin. -// <- means using a R/W allocator from the upstream filter -// <= means using a R-O allocator from an upstream filter -// || means using our own (R/W) allocator. -// -> means using a R/W allocator from a downstream filter -// (a R-O allocator from downstream is nonsense, it can't ever work). -// -// -// That makes 25 possible states. Some states are nonsense (two different -// allocators from the same place). These are just an artifact of the notation. -// <= <- Nonsense. -// <- <= Nonsense -// Some states are illegal (the output pin never accepts a R-O allocator): -// 00 <= !! Error !! -// <= <= !! Error !! -// || <= !! Error !! -// -> <= !! Error !! -// Three states appears to be inaccessible: -// -> || Inaccessible -// || -> Inaccessible -// || <- Inaccessible -// Some states only ever occur as intermediates with a pending reconnect which -// is guaranteed to finish in another state. -// -> 00 ?? unstable goes to || 00 -// 00 <- ?? unstable goes to 00 || -// -> <- ?? unstable goes to -> -> -// <- || ?? unstable goes to <- <- -// <- -> ?? unstable goes to <- <- -// And that leaves 11 possible resting states: -// 1 00 00 Nothing connected. -// 2 <- 00 Input pin connected. -// 3 <= 00 Input pin connected using R-O allocator. -// 4 || 00 Needs several state changes to get here. -// 5 00 || Output pin connected using our allocator -// 6 00 -> Downstream only connected -// 7 || || Undesirable but can be forced upon us. -// 8 <= || Copy forced. <= -> is preferable -// 9 <= -> OK - forced to copy. -// 10 <- <- Transform in place (ideal) -// 11 -> -> Transform in place (ideal) -// -// The object of the exercise is to ensure that we finish up in states -// 10 or 11 whenever possible. State 10 is only possible if the upstream -// filter has a R/W allocator (the AVI splitter notoriously -// doesn't) and state 11 is only possible if the downstream filter does -// offer an allocator. -// -// The transition table (entries marked * go via a reconnect) -// -// There are 8 possible transitions: -// A: Connect upstream to filter with R-O allocator that insists on using it. -// B: Connect upstream to filter with R-O allocator but chooses not to use it. -// C: Connect upstream to filter with R/W allocator and insists on using it. -// D: Connect upstream to filter with R/W allocator but chooses not to use it. -// E: Connect downstream to a filter that offers an allocator -// F: Connect downstream to a filter that does not offer an allocator -// G: disconnect upstream -// H: Disconnect downstream -// -// A B C D E F G H -// --------------------------------------------------------- -// 00 00 1 | 3 3 2 2 6 5 . . |1 00 00 -// <- 00 2 | . . . . *10/11 10 1 . |2 <- 00 -// <= 00 3 | . . . . *9/11 *7/8 1 . |3 <= 00 -// || 00 4 | . . . . *8 *7 1 . |4 || 00 -// 00 || 5 | 8 7 *10 7 . . . 1 |5 00 || -// 00 -> 6 | 9 11 *10 11 . . . 1 |6 00 -> -// || || 7 | . . . . . . 5 4 |7 || || -// <= || 8 | . . . . . . 5 3 |8 <= || -// <= -> 9 | . . . . . . 6 3 |9 <= -> -// <- <- 10| . . . . . . *5/6 2 |10 <- <- -// -> -> 11| . . . . . . 6 *2/3 |11 -> -> -// --------------------------------------------------------- -// A B C D E F G H -// -// All these states are accessible without requiring any filter to -// change its behaviour but not all transitions are accessible, for -// instance a transition from state 4 to anywhere other than -// state 8 requires that the upstream filter first offer a R-O allocator -// and then changes its mind and offer R/W. This is NOT allowable - it -// leads to things like the output pin getting a R/W allocator from -// upstream and then the input pin being told it can only have a R-O one. -// Note that you CAN change (say) the upstream filter for a different one, but -// only as a disconnect / connect, not as a Reconnect. (Exercise for -// the reader is to see how you get into state 4). -// -// The reconnection stuff goes as follows (some of the cases shown here as -// "no reconnect" may get one to finalise media type - an old story). -// If there is a reconnect where it says "no reconnect" here then the -// reconnection must not change the allocator choice. -// -// state 2: <- 00 transition E <- <- case C <- <- (no change) -// case D -> <- and then to -> -> -// -// state 2: <- 00 transition F <- <- (no reconnect) -// -// state 3: <= 00 transition E <= -> case A <= -> (no change) -// case B -> -> -// transition F <= || case A <= || (no change) -// case B || || -// -// state 4: || 00 transition E || || case B -> || and then all cases to -> -> -// F || || case B || || (no change) -// -// state 5: 00 || transition A <= || (no reconnect) -// B || || (no reconnect) -// C <- || all cases <- <- -// D || || (unfortunate, but upstream's choice) -// -// state 6: 00 -> transition A <= -> (no reconnect) -// B -> -> (no reconnect) -// C <- -> all cases <- <- -// D -> -> (no reconnect) -// -// state 10:<- <- transition G 00 <- case E 00 -> -// case F 00 || -// -// state 11:-> -> transition H -> 00 case A <= 00 (schizo) -// case B <= 00 -// case C <- 00 (schizo) -// case D <- 00 -// -// The Rules: -// To sort out media types: -// The input is reconnected -// if the input pin is connected and the output pin connects -// The output is reconnected -// If the output pin is connected -// and the input pin connects to a different media type -// -// To sort out allocators: -// The input is reconnected -// if the output disconnects and the input was using a downstream allocator -// The output pin calls SetAllocator to pass on a new allocator -// if the output is connected and -// if the input disconnects and the output was using an upstream allocator -// if the input acquires an allocator different from the output one -// and that new allocator is not R-O -// -// Data is copied (i.e. call getbuffer and copy the data before transforming it) -// if the two allocators are different. - - - -// CHAINS of filters: -// -// We sit between two filters (call them A and Z). We should finish up -// with the same allocator on both of our pins and that should be the -// same one that A and Z would have agreed on if we hadn't been in the -// way. Furthermore, it should not matter how many in-place transforms -// are in the way. Let B, C, D... be in-place transforms ("us"). -// Here's how it goes: -// -// 1. -// A connects to B. They agree on A's allocator. -// A-a->B -// -// 2. -// B connects to C. Same story. There is no point in a reconnect, but -// B will request an input reconnect anyway. -// A-a->B-a->C -// -// 3. -// C connects to Z. -// C insists on using A's allocator, but compromises by requesting a reconnect. -// of C's input. -// A-a->B-?->C-a->Z -// -// We now have pending reconnects on both A--->B and B--->C -// -// 4. -// The A--->B link is reconnected. -// A asks B for an allocator. B sees that it has a downstream connection so -// asks its downstream input pin i.e. C's input pin for an allocator. C sees -// that it too has a downstream connection so asks Z for an allocator. -// -// Even though Z's input pin is connected, it is being asked for an allocator. -// It could refuse, in which case the chain is done and will use A's allocator -// Alternatively, Z may supply one. A chooses either Z's or A's own one. -// B's input pin gets NotifyAllocator called to tell it the decision and it -// propagates this downstream by calling ReceiveAllocator on its output pin -// which calls NotifyAllocator on the next input pin downstream etc. -// If the choice is Z then it goes: -// A-z->B-a->C-a->Z -// A-z->B-z->C-a->Z -// A-z->B-z->C-z->Z -// -// And that's IT!! Any further (essentially spurious) reconnects peter out -// with no change in the chain. - -#include "streams.h" -#include "measure.h" -#include "transip.h" - - -// ================================================================= -// Implements the CTransInPlaceFilter class -// ================================================================= - -CTransInPlaceFilter::CTransInPlaceFilter - ( __in_opt LPCTSTR pName, - __inout_opt LPUNKNOWN pUnk, - REFCLSID clsid, - __inout HRESULT *phr, - bool bModifiesData - ) - : CTransformFilter(pName, pUnk, clsid), - m_bModifiesData(bModifiesData) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF - -} // constructor - -#ifdef UNICODE -CTransInPlaceFilter::CTransInPlaceFilter - ( __in_opt LPCSTR pName, - __inout_opt LPUNKNOWN pUnk, - REFCLSID clsid, - __inout HRESULT *phr, - bool bModifiesData - ) - : CTransformFilter(pName, pUnk, clsid), - m_bModifiesData(bModifiesData) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF - -} // constructor -#endif - -// return a non-addrefed CBasePin * for the user to addref if he holds onto it -// for longer than his pointer to us. We create the pins dynamically when they -// are asked for rather than in the constructor. This is because we want to -// give the derived class an oppportunity to return different pin objects - -// As soon as any pin is needed we create both (this is different from the -// usual transform filter) because enumerators, allocators etc are passed -// through from one pin to another and it becomes very painful if the other -// pin isn't there. If we fail to create either pin we ensure we fail both. - -CBasePin * -CTransInPlaceFilter::GetPin(int n) -{ - HRESULT hr = S_OK; - - // Create an input pin if not already done - - if (m_pInput == NULL) { - - m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin") - , this // Owner filter - , &hr // Result code - , L"Input" // Pin name - ); - - // Constructor for CTransInPlaceInputPin can't fail - ASSERT(SUCCEEDED(hr)); - } - - // Create an output pin if not already done - - if (m_pInput!=NULL && m_pOutput == NULL) { - - m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin") - , this // Owner filter - , &hr // Result code - , L"Output" // Pin name - ); - - // a failed return code should delete the object - - ASSERT(SUCCEEDED(hr)); - if (m_pOutput == NULL) { - delete m_pInput; - m_pInput = NULL; - } - } - - // Return the appropriate pin - - ASSERT (n>=0 && n<=1); - if (n == 0) { - return m_pInput; - } else if (n==1) { - return m_pOutput; - } else { - return NULL; - } - -} // GetPin - - - -// dir is the direction of our pin. -// pReceivePin is the pin we are connecting to. -HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir, IPin *pReceivePin) -{ - UNREFERENCED_PARAMETER(pReceivePin); - ASSERT(m_pInput); - ASSERT(m_pOutput); - - // if we are not part of a graph, then don't indirect the pointer - // this probably prevents use of the filter without a filtergraph - if (!m_pGraph) { - return VFW_E_NOT_IN_GRAPH; - } - - // Always reconnect the input to account for buffering changes - // - // Because we don't get to suggest a type on ReceiveConnection - // we need another way of making sure the right type gets used. - // - // One way would be to have our EnumMediaTypes return our output - // connection type first but more deterministic and simple is to - // call ReconnectEx passing the type we want to reconnect with - // via the base class ReconeectPin method. - - if (dir == PINDIR_OUTPUT) { - if( m_pInput->IsConnected() ) { - return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() ); - } - return NOERROR; - } - - ASSERT(dir == PINDIR_INPUT); - - // Reconnect output if necessary - - if( m_pOutput->IsConnected() ) { - - if ( m_pInput->CurrentMediaType() - != m_pOutput->CurrentMediaType() - ) { - return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() ); - } - } - return NOERROR; - -} // ComnpleteConnect - - -// -// DecideBufferSize -// -// Tell the output pin's allocator what size buffers we require. -// *pAlloc will be the allocator our output pin is using. -// - -HRESULT CTransInPlaceFilter::DecideBufferSize - ( IMemAllocator *pAlloc - , __inout ALLOCATOR_PROPERTIES *pProperties - ) -{ - ALLOCATOR_PROPERTIES Request, Actual; - HRESULT hr; - - // If we are connected upstream, get his views - if (m_pInput->IsConnected()) { - // Get the input pin allocator, and get its size and count. - // we don't care about his alignment and prefix. - - hr = InputPin()->PeekAllocator()->GetProperties(&Request); - if (FAILED(hr)) { - // Input connected but with a secretive allocator - enough! - return hr; - } - } else { - // Propose one byte - // If this isn't enough then when the other pin does get connected - // we can revise it. - ZeroMemory(&Request, sizeof(Request)); - Request.cBuffers = 1; - Request.cbBuffer = 1; - } - - - DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); - DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), - Request.cBuffers, Request.cbBuffer)); - - // Pass the allocator requirements to our output side - // but do a little sanity checking first or we'll just hit - // asserts in the allocator. - - pProperties->cBuffers = Request.cBuffers; - pProperties->cbBuffer = Request.cbBuffer; - pProperties->cbAlign = Request.cbAlign; - if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; } - if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; } - hr = pAlloc->SetProperties(pProperties, &Actual); - - if (FAILED(hr)) { - return hr; - } - - DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); - DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), - Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); - - // Make sure we got the right alignment and at least the minimum required - - if ( (Request.cBuffers > Actual.cBuffers) - || (Request.cbBuffer > Actual.cbBuffer) - || (Request.cbAlign > Actual.cbAlign) - ) { - return E_FAIL; - } - return NOERROR; - -} // DecideBufferSize - -// -// Copy -// -// return a pointer to an identical copy of pSample -__out_opt IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) -{ - IMediaSample * pDest; - - HRESULT hr; - REFERENCE_TIME tStart, tStop; - const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); - - // this may block for an indeterminate amount of time - hr = OutputPin()->PeekAllocator()->GetBuffer( - &pDest - , bTime ? &tStart : NULL - , bTime ? &tStop : NULL - , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 - ); - - if (FAILED(hr)) { - return NULL; - } - - ASSERT(pDest); - IMediaSample2 *pSample2; - if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { - HRESULT hrProps = pSample2->SetProperties( - FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), - (PBYTE)m_pInput->SampleProps()); - pSample2->Release(); - if (FAILED(hrProps)) { - pDest->Release(); - return NULL; - } - } else { - if (bTime) { - pDest->SetTime(&tStart, &tStop); - } - - if (S_OK == pSource->IsSyncPoint()) { - pDest->SetSyncPoint(TRUE); - } - if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { - pDest->SetDiscontinuity(TRUE); - } - if (S_OK == pSource->IsPreroll()) { - pDest->SetPreroll(TRUE); - } - - // Copy the media type - AM_MEDIA_TYPE *pMediaType; - if (S_OK == pSource->GetMediaType(&pMediaType)) { - pDest->SetMediaType(pMediaType); - DeleteMediaType( pMediaType ); - } - - } - - m_bSampleSkipped = FALSE; - - // Copy the sample media times - REFERENCE_TIME TimeStart, TimeEnd; - if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { - pDest->SetMediaTime(&TimeStart,&TimeEnd); - } - - // Copy the actual data length and the actual data. - { - const long lDataLength = pSource->GetActualDataLength(); - if (FAILED(pDest->SetActualDataLength(lDataLength))) { - pDest->Release(); - return NULL; - } - - // Copy the sample data - { - BYTE *pSourceBuffer, *pDestBuffer; -#ifdef _DEBUG - long lSourceSize = pSource->GetSize(); -#endif - long lDestSize = pDest->GetSize(); - - ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); - - if (FAILED(pSource->GetPointer(&pSourceBuffer)) || - FAILED(pDest->GetPointer(&pDestBuffer)) || - lDestSize < lDataLength || - lDataLength < 0) { - pDest->Release(); - return NULL; - } - ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); - - CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); - } - } - - return pDest; - -} // Copy - - -// override this to customize the transform process - -HRESULT -CTransInPlaceFilter::Receive(IMediaSample *pSample) -{ - /* Check for other streams and pass them on */ - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); - if (pProps->dwStreamId != AM_STREAM_MEDIA) { - return m_pOutput->Deliver(pSample); - } - HRESULT hr; - - // Start timing the TransInPlace (if PERF is defined) - MSR_START(m_idTransInPlace); - - if (UsingDifferentAllocators()) { - - // We have to copy the data. - - pSample = Copy(pSample); - - if (pSample==NULL) { - MSR_STOP(m_idTransInPlace); - return E_UNEXPECTED; - } - } - - // have the derived class transform the data - hr = Transform(pSample); - - // Stop the clock and log it (if PERF is defined) - MSR_STOP(m_idTransInPlace); - - if (FAILED(hr)) { - DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace"))); - if (UsingDifferentAllocators()) { - pSample->Release(); - } - return hr; - } - - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pSample); - } else { - // But it would be an error to return this private workaround - // to the caller ... - if (S_FALSE == hr) { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this cause because - // returning S_FALSE from Receive() means that this is the end - // of the stream and no more data should be sent. - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - NotifyEvent(EC_QUALITY_CHANGE,0,0); - m_bQualityChanged = TRUE; - } - hr = NOERROR; - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - if (UsingDifferentAllocators()) { - pSample->Release(); - } - - return hr; - -} // Receive - - - -// ================================================================= -// Implements the CTransInPlaceInputPin class -// ================================================================= - - -// constructor - -CTransInPlaceInputPin::CTransInPlaceInputPin - ( __in_opt LPCTSTR pObjectName - , __inout CTransInPlaceFilter *pFilter - , __inout HRESULT *phr - , __in_opt LPCWSTR pName - ) - : CTransformInputPin(pObjectName, - pFilter, - phr, - pName) - , m_bReadOnly(FALSE) - , m_pTIPFilter(pFilter) -{ - DbgLog((LOG_TRACE, 2 - , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin"))); - -} // constructor - - -// ================================================================= -// Implements IMemInputPin interface -// ================================================================= - - -// If the downstream filter has one then offer that (even if our own output -// pin is not using it yet. If the upstream filter chooses it then we will -// tell our output pin to ReceiveAllocator). -// Else if our output pin is using an allocator then offer that. -// ( This could mean offering the upstream filter his own allocator, -// it could mean offerring our own -// ) or it could mean offering the one from downstream -// Else fail to offer any allocator at all. - -STDMETHODIMP CTransInPlaceInputPin::GetAllocator(__deref_out IMemAllocator ** ppAllocator) -{ - CheckPointer(ppAllocator,E_POINTER); - ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); - CAutoLock cObjectLock(m_pLock); - - HRESULT hr; - - if ( m_pTIPFilter->m_pOutput->IsConnected() ) { - // Store the allocator we got - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->GetAllocator( ppAllocator ); - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator ); - } - } - else { - // Help upstream filter (eg TIP filter which is having to do a copy) - // by providing a temp allocator here - we'll never use - // this allocator because when our output is connected we'll - // reconnect this pin - hr = CTransformInputPin::GetAllocator( ppAllocator ); - } - return hr; - -} // GetAllocator - - - -/* Get told which allocator the upstream output pin is actually going to use */ - - -STDMETHODIMP -CTransInPlaceInputPin::NotifyAllocator( - IMemAllocator * pAllocator, - BOOL bReadOnly) -{ - HRESULT hr = S_OK; - CheckPointer(pAllocator,E_POINTER); - ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); - - CAutoLock cObjectLock(m_pLock); - - m_bReadOnly = bReadOnly; - // If we modify data then don't accept the allocator if it's - // the same as the output pin's allocator - - // If our output is not connected just accept the allocator - // We're never going to use this allocator because when our - // output pin is connected we'll reconnect this pin - if (!m_pTIPFilter->OutputPin()->IsConnected()) { - return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly); - } - - // If the allocator is read-only and we're modifying data - // and the allocator is the same as the output pin's - // then reject - if (bReadOnly && m_pTIPFilter->m_bModifiesData) { - IMemAllocator *pOutputAllocator = - m_pTIPFilter->OutputPin()->PeekAllocator(); - - // Make sure we have an output allocator - if (pOutputAllocator == NULL) { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()-> - GetAllocator(&pOutputAllocator); - if(FAILED(hr)) { - hr = CreateMemoryAllocator(&pOutputAllocator); - } - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator); - pOutputAllocator->Release(); - } - } - if (pAllocator == pOutputAllocator) { - hr = E_FAIL; - } else if(SUCCEEDED(hr)) { - // Must copy so set the allocator properties on the output - ALLOCATOR_PROPERTIES Props, Actual; - hr = pAllocator->GetProperties(&Props); - if (SUCCEEDED(hr)) { - hr = pOutputAllocator->SetProperties(&Props, &Actual); - - if (SUCCEEDED(hr)) { - if ( (Props.cBuffers > Actual.cBuffers) - || (Props.cbBuffer > Actual.cbBuffer) - || (Props.cbAlign > Actual.cbAlign) - ) { - hr = E_FAIL; - } - } - } - - // Set the allocator on the output pin - if (SUCCEEDED(hr)) { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->NotifyAllocator( pOutputAllocator, FALSE ); - } - } - } else { - hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() - ->NotifyAllocator( pAllocator, bReadOnly ); - if (SUCCEEDED(hr)) { - m_pTIPFilter->OutputPin()->SetAllocator( pAllocator ); - } - } - - if (SUCCEEDED(hr)) { - - // It's possible that the old and the new are the same thing. - // AddRef before release ensures that we don't unload it. - pAllocator->AddRef(); - - if( m_pAllocator != NULL ) - m_pAllocator->Release(); - - m_pAllocator = pAllocator; // We have an allocator for the input pin - } - - return hr; - -} // NotifyAllocator - - -// EnumMediaTypes -// - pass through to our downstream filter -STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ) -{ - // Can only pass through if connected - if( !m_pTIPFilter->m_pOutput->IsConnected() ) - return VFW_E_NOT_CONNECTED; - - return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum ); - -} // EnumMediaTypes - - -// CheckMediaType -// - agree to anything if not connected, -// otherwise pass through to the downstream filter. -// This assumes that the filter does not change the media type. - -HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt ) -{ - HRESULT hr = m_pTIPFilter->CheckInputType(pmt); - if (hr!=S_OK) return hr; - - if( m_pTIPFilter->m_pOutput->IsConnected() ) - return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt ); - else - return S_OK; - -} // CheckMediaType - - -// If upstream asks us what our requirements are, we will try to ask downstream -// if that doesn't work, we'll just take the defaults. -STDMETHODIMP -CTransInPlaceInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps) -{ - - if( m_pTIPFilter->m_pOutput->IsConnected() ) - return m_pTIPFilter->OutputPin() - ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps ); - else - return E_NOTIMPL; - -} // GetAllocatorRequirements - - -// CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect() -// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because -// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not -// want to reconnect a pin if CBaseInputPin::CompleteConnect() fails. -HRESULT -CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); -} // CompleteConnect - - -// ================================================================= -// Implements the CTransInPlaceOutputPin class -// ================================================================= - - -// constructor - -CTransInPlaceOutputPin::CTransInPlaceOutputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransInPlaceFilter *pFilter, - __inout HRESULT * phr, - __in_opt LPCWSTR pPinName) - : CTransformOutputPin( pObjectName - , pFilter - , phr - , pPinName), - m_pTIPFilter(pFilter) -{ - DbgLog(( LOG_TRACE, 2 - , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin"))); - -} // constructor - - -// EnumMediaTypes -// - pass through to our upstream filter -STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ) -{ - // Can only pass through if connected. - if( ! m_pTIPFilter->m_pInput->IsConnected() ) - return VFW_E_NOT_CONNECTED; - - return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum ); - -} // EnumMediaTypes - - - -// CheckMediaType -// - agree to anything if not connected, -// otherwise pass through to the upstream filter. - -HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt ) -{ - // Don't accept any output pin type changes if we're copying - // between allocators - it's too late to change the input - // allocator size. - if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) { - if (*pmt == m_mt) { - return S_OK; - } else { - return VFW_E_TYPE_NOT_ACCEPTED; - } - } - - // Assumes the type does not change. That's why we're calling - // CheckINPUTType here on the OUTPUT pin. - HRESULT hr = m_pTIPFilter->CheckInputType(pmt); - if (hr!=S_OK) return hr; - - if( m_pTIPFilter->m_pInput->IsConnected() ) - return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt ); - else - return S_OK; - -} // CheckMediaType - - -/* Save the allocator pointer in the output pin -*/ -void -CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator) -{ - pAllocator->AddRef(); - if (m_pAllocator) { - m_pAllocator->Release(); - } - m_pAllocator = pAllocator; -} // SetAllocator - - -// CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect() -// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because -// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to -// reconnect a pin if CBaseOutputPin::CompleteConnect() fails. -// CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected -// to the Video Mixing Renderer. -HRESULT -CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin) -{ - HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); - if (FAILED(hr)) { - return hr; - } - - return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); -} // CompleteConnect +//------------------------------------------------------------------------------ +// File: TransIP.cpp +// +// Desc: DirectShow base classes - implements class for simple Transform- +// In-Place filters such as audio. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// How allocators are decided. +// +// An in-place transform tries to do its work in someone else's buffers. +// It tries to persuade the filters on either side to use the same allocator +// (and for that matter the same media type). In desperation, if the downstream +// filter refuses to supply an allocator and the upstream filter offers only +// a read-only one then it will provide an allocator. +// if the upstream filter insists on a read-only allocator then the transform +// filter will (reluctantly) copy the data before transforming it. +// +// In order to pass an allocator through it needs to remember the one it got +// from the first connection to pass it on to the second one. +// +// It is good if we can avoid insisting on a particular order of connection +// (There is a precedent for insisting on the input +// being connected first. Insisting on the output being connected first is +// not allowed. That would break RenderFile.) +// +// The base pin classes (CBaseOutputPin and CBaseInputPin) both have a +// m_pAllocator member which is used in places like +// CBaseOutputPin::GetDeliveryBuffer and CBaseInputPin::Inactive. +// To avoid lots of extra overriding, we should keep these happy +// by using these pointers. +// +// When each pin is connected, it will set the corresponding m_pAllocator +// and will have a single ref-count on that allocator. +// +// Refcounts are acquired by GetAllocator calls which return AddReffed +// allocators and are released in one of: +// CBaseInputPin::Disconnect +// CBaseOutputPin::BreakConect +// In each case m_pAllocator is set to NULL after the release, so this +// is the last chance to ever release it. If there should ever be +// multiple refcounts associated with the same pointer, this had better +// be cleared up before that happens. To avoid such problems, we'll +// stick with one per pointer. + + + +// RECONNECTING and STATE CHANGES +// +// Each pin could be disconnected, connected with a read-only allocator, +// connected with an upstream read/write allocator, connected with an +// allocator from downstream or connected with its own allocator. +// Five states for each pin gives a data space of 25 states. +// +// Notation: +// +// R/W == read/write +// R-O == read-only +// +// +// +// 00 means an unconnected pin. +// <- means using a R/W allocator from the upstream filter +// <= means using a R-O allocator from an upstream filter +// || means using our own (R/W) allocator. +// -> means using a R/W allocator from a downstream filter +// (a R-O allocator from downstream is nonsense, it can't ever work). +// +// +// That makes 25 possible states. Some states are nonsense (two different +// allocators from the same place). These are just an artifact of the notation. +// <= <- Nonsense. +// <- <= Nonsense +// Some states are illegal (the output pin never accepts a R-O allocator): +// 00 <= !! Error !! +// <= <= !! Error !! +// || <= !! Error !! +// -> <= !! Error !! +// Three states appears to be inaccessible: +// -> || Inaccessible +// || -> Inaccessible +// || <- Inaccessible +// Some states only ever occur as intermediates with a pending reconnect which +// is guaranteed to finish in another state. +// -> 00 ?? unstable goes to || 00 +// 00 <- ?? unstable goes to 00 || +// -> <- ?? unstable goes to -> -> +// <- || ?? unstable goes to <- <- +// <- -> ?? unstable goes to <- <- +// And that leaves 11 possible resting states: +// 1 00 00 Nothing connected. +// 2 <- 00 Input pin connected. +// 3 <= 00 Input pin connected using R-O allocator. +// 4 || 00 Needs several state changes to get here. +// 5 00 || Output pin connected using our allocator +// 6 00 -> Downstream only connected +// 7 || || Undesirable but can be forced upon us. +// 8 <= || Copy forced. <= -> is preferable +// 9 <= -> OK - forced to copy. +// 10 <- <- Transform in place (ideal) +// 11 -> -> Transform in place (ideal) +// +// The object of the exercise is to ensure that we finish up in states +// 10 or 11 whenever possible. State 10 is only possible if the upstream +// filter has a R/W allocator (the AVI splitter notoriously +// doesn't) and state 11 is only possible if the downstream filter does +// offer an allocator. +// +// The transition table (entries marked * go via a reconnect) +// +// There are 8 possible transitions: +// A: Connect upstream to filter with R-O allocator that insists on using it. +// B: Connect upstream to filter with R-O allocator but chooses not to use it. +// C: Connect upstream to filter with R/W allocator and insists on using it. +// D: Connect upstream to filter with R/W allocator but chooses not to use it. +// E: Connect downstream to a filter that offers an allocator +// F: Connect downstream to a filter that does not offer an allocator +// G: disconnect upstream +// H: Disconnect downstream +// +// A B C D E F G H +// --------------------------------------------------------- +// 00 00 1 | 3 3 2 2 6 5 . . |1 00 00 +// <- 00 2 | . . . . *10/11 10 1 . |2 <- 00 +// <= 00 3 | . . . . *9/11 *7/8 1 . |3 <= 00 +// || 00 4 | . . . . *8 *7 1 . |4 || 00 +// 00 || 5 | 8 7 *10 7 . . . 1 |5 00 || +// 00 -> 6 | 9 11 *10 11 . . . 1 |6 00 -> +// || || 7 | . . . . . . 5 4 |7 || || +// <= || 8 | . . . . . . 5 3 |8 <= || +// <= -> 9 | . . . . . . 6 3 |9 <= -> +// <- <- 10| . . . . . . *5/6 2 |10 <- <- +// -> -> 11| . . . . . . 6 *2/3 |11 -> -> +// --------------------------------------------------------- +// A B C D E F G H +// +// All these states are accessible without requiring any filter to +// change its behaviour but not all transitions are accessible, for +// instance a transition from state 4 to anywhere other than +// state 8 requires that the upstream filter first offer a R-O allocator +// and then changes its mind and offer R/W. This is NOT allowable - it +// leads to things like the output pin getting a R/W allocator from +// upstream and then the input pin being told it can only have a R-O one. +// Note that you CAN change (say) the upstream filter for a different one, but +// only as a disconnect / connect, not as a Reconnect. (Exercise for +// the reader is to see how you get into state 4). +// +// The reconnection stuff goes as follows (some of the cases shown here as +// "no reconnect" may get one to finalise media type - an old story). +// If there is a reconnect where it says "no reconnect" here then the +// reconnection must not change the allocator choice. +// +// state 2: <- 00 transition E <- <- case C <- <- (no change) +// case D -> <- and then to -> -> +// +// state 2: <- 00 transition F <- <- (no reconnect) +// +// state 3: <= 00 transition E <= -> case A <= -> (no change) +// case B -> -> +// transition F <= || case A <= || (no change) +// case B || || +// +// state 4: || 00 transition E || || case B -> || and then all cases to -> -> +// F || || case B || || (no change) +// +// state 5: 00 || transition A <= || (no reconnect) +// B || || (no reconnect) +// C <- || all cases <- <- +// D || || (unfortunate, but upstream's choice) +// +// state 6: 00 -> transition A <= -> (no reconnect) +// B -> -> (no reconnect) +// C <- -> all cases <- <- +// D -> -> (no reconnect) +// +// state 10:<- <- transition G 00 <- case E 00 -> +// case F 00 || +// +// state 11:-> -> transition H -> 00 case A <= 00 (schizo) +// case B <= 00 +// case C <- 00 (schizo) +// case D <- 00 +// +// The Rules: +// To sort out media types: +// The input is reconnected +// if the input pin is connected and the output pin connects +// The output is reconnected +// If the output pin is connected +// and the input pin connects to a different media type +// +// To sort out allocators: +// The input is reconnected +// if the output disconnects and the input was using a downstream allocator +// The output pin calls SetAllocator to pass on a new allocator +// if the output is connected and +// if the input disconnects and the output was using an upstream allocator +// if the input acquires an allocator different from the output one +// and that new allocator is not R-O +// +// Data is copied (i.e. call getbuffer and copy the data before transforming it) +// if the two allocators are different. + + + +// CHAINS of filters: +// +// We sit between two filters (call them A and Z). We should finish up +// with the same allocator on both of our pins and that should be the +// same one that A and Z would have agreed on if we hadn't been in the +// way. Furthermore, it should not matter how many in-place transforms +// are in the way. Let B, C, D... be in-place transforms ("us"). +// Here's how it goes: +// +// 1. +// A connects to B. They agree on A's allocator. +// A-a->B +// +// 2. +// B connects to C. Same story. There is no point in a reconnect, but +// B will request an input reconnect anyway. +// A-a->B-a->C +// +// 3. +// C connects to Z. +// C insists on using A's allocator, but compromises by requesting a reconnect. +// of C's input. +// A-a->B-?->C-a->Z +// +// We now have pending reconnects on both A--->B and B--->C +// +// 4. +// The A--->B link is reconnected. +// A asks B for an allocator. B sees that it has a downstream connection so +// asks its downstream input pin i.e. C's input pin for an allocator. C sees +// that it too has a downstream connection so asks Z for an allocator. +// +// Even though Z's input pin is connected, it is being asked for an allocator. +// It could refuse, in which case the chain is done and will use A's allocator +// Alternatively, Z may supply one. A chooses either Z's or A's own one. +// B's input pin gets NotifyAllocator called to tell it the decision and it +// propagates this downstream by calling ReceiveAllocator on its output pin +// which calls NotifyAllocator on the next input pin downstream etc. +// If the choice is Z then it goes: +// A-z->B-a->C-a->Z +// A-z->B-z->C-a->Z +// A-z->B-z->C-z->Z +// +// And that's IT!! Any further (essentially spurious) reconnects peter out +// with no change in the chain. + +#include "streams.h" +#include "measure.h" +#include "transip.h" + + +// ================================================================= +// Implements the CTransInPlaceFilter class +// ================================================================= + +CTransInPlaceFilter::CTransInPlaceFilter + ( __in_opt LPCTSTR pName, + __inout_opt LPUNKNOWN pUnk, + REFCLSID clsid, + __inout HRESULT *phr, + bool bModifiesData + ) + : CTransformFilter(pName, pUnk, clsid), + m_bModifiesData(bModifiesData) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF + +} // constructor + +#ifdef UNICODE +CTransInPlaceFilter::CTransInPlaceFilter + ( __in_opt LPCSTR pName, + __inout_opt LPUNKNOWN pUnk, + REFCLSID clsid, + __inout HRESULT *phr, + bool bModifiesData + ) + : CTransformFilter(pName, pUnk, clsid), + m_bModifiesData(bModifiesData) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF + +} // constructor +#endif + +// return a non-addrefed CBasePin * for the user to addref if he holds onto it +// for longer than his pointer to us. We create the pins dynamically when they +// are asked for rather than in the constructor. This is because we want to +// give the derived class an oppportunity to return different pin objects + +// As soon as any pin is needed we create both (this is different from the +// usual transform filter) because enumerators, allocators etc are passed +// through from one pin to another and it becomes very painful if the other +// pin isn't there. If we fail to create either pin we ensure we fail both. + +CBasePin * +CTransInPlaceFilter::GetPin(int n) +{ + HRESULT hr = S_OK; + + // Create an input pin if not already done + + if (m_pInput == NULL) { + + m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin") + , this // Owner filter + , &hr // Result code + , L"Input" // Pin name + ); + + // Constructor for CTransInPlaceInputPin can't fail + ASSERT(SUCCEEDED(hr)); + } + + // Create an output pin if not already done + + if (m_pInput!=NULL && m_pOutput == NULL) { + + m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin") + , this // Owner filter + , &hr // Result code + , L"Output" // Pin name + ); + + // a failed return code should delete the object + + ASSERT(SUCCEEDED(hr)); + if (m_pOutput == NULL) { + delete m_pInput; + m_pInput = NULL; + } + } + + // Return the appropriate pin + + ASSERT (n>=0 && n<=1); + if (n == 0) { + return m_pInput; + } else if (n==1) { + return m_pOutput; + } else { + return NULL; + } + +} // GetPin + + + +// dir is the direction of our pin. +// pReceivePin is the pin we are connecting to. +HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir, IPin *pReceivePin) +{ + UNREFERENCED_PARAMETER(pReceivePin); + ASSERT(m_pInput); + ASSERT(m_pOutput); + + // if we are not part of a graph, then don't indirect the pointer + // this probably prevents use of the filter without a filtergraph + if (!m_pGraph) { + return VFW_E_NOT_IN_GRAPH; + } + + // Always reconnect the input to account for buffering changes + // + // Because we don't get to suggest a type on ReceiveConnection + // we need another way of making sure the right type gets used. + // + // One way would be to have our EnumMediaTypes return our output + // connection type first but more deterministic and simple is to + // call ReconnectEx passing the type we want to reconnect with + // via the base class ReconeectPin method. + + if (dir == PINDIR_OUTPUT) { + if( m_pInput->IsConnected() ) { + return ReconnectPin( m_pInput, &m_pOutput->CurrentMediaType() ); + } + return NOERROR; + } + + ASSERT(dir == PINDIR_INPUT); + + // Reconnect output if necessary + + if( m_pOutput->IsConnected() ) { + + if ( m_pInput->CurrentMediaType() + != m_pOutput->CurrentMediaType() + ) { + return ReconnectPin( m_pOutput, &m_pInput->CurrentMediaType() ); + } + } + return NOERROR; + +} // ComnpleteConnect + + +// +// DecideBufferSize +// +// Tell the output pin's allocator what size buffers we require. +// *pAlloc will be the allocator our output pin is using. +// + +HRESULT CTransInPlaceFilter::DecideBufferSize + ( IMemAllocator *pAlloc + , __inout ALLOCATOR_PROPERTIES *pProperties + ) +{ + ALLOCATOR_PROPERTIES Request, Actual; + HRESULT hr; + + // If we are connected upstream, get his views + if (m_pInput->IsConnected()) { + // Get the input pin allocator, and get its size and count. + // we don't care about his alignment and prefix. + + hr = InputPin()->PeekAllocator()->GetProperties(&Request); + if (FAILED(hr)) { + // Input connected but with a secretive allocator - enough! + return hr; + } + } else { + // Propose one byte + // If this isn't enough then when the other pin does get connected + // we can revise it. + ZeroMemory(&Request, sizeof(Request)); + Request.cBuffers = 1; + Request.cbBuffer = 1; + } + + + DbgLog((LOG_MEMORY,1,TEXT("Setting Allocator Requirements"))); + DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d"), + Request.cBuffers, Request.cbBuffer)); + + // Pass the allocator requirements to our output side + // but do a little sanity checking first or we'll just hit + // asserts in the allocator. + + pProperties->cBuffers = Request.cBuffers; + pProperties->cbBuffer = Request.cbBuffer; + pProperties->cbAlign = Request.cbAlign; + if (pProperties->cBuffers<=0) {pProperties->cBuffers = 1; } + if (pProperties->cbBuffer<=0) {pProperties->cbBuffer = 1; } + hr = pAlloc->SetProperties(pProperties, &Actual); + + if (FAILED(hr)) { + return hr; + } + + DbgLog((LOG_MEMORY,1,TEXT("Obtained Allocator Requirements"))); + DbgLog((LOG_MEMORY,1,TEXT("Count %d, Size %d, Alignment %d"), + Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign)); + + // Make sure we got the right alignment and at least the minimum required + + if ( (Request.cBuffers > Actual.cBuffers) + || (Request.cbBuffer > Actual.cbBuffer) + || (Request.cbAlign > Actual.cbAlign) + ) { + return E_FAIL; + } + return NOERROR; + +} // DecideBufferSize + +// +// Copy +// +// return a pointer to an identical copy of pSample +__out_opt IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) +{ + IMediaSample * pDest; + + HRESULT hr; + REFERENCE_TIME tStart, tStop; + const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); + + // this may block for an indeterminate amount of time + hr = OutputPin()->PeekAllocator()->GetBuffer( + &pDest + , bTime ? &tStart : NULL + , bTime ? &tStop : NULL + , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 + ); + + if (FAILED(hr)) { + return NULL; + } + + ASSERT(pDest); + IMediaSample2 *pSample2; + if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { + HRESULT hrProps = pSample2->SetProperties( + FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), + (PBYTE)m_pInput->SampleProps()); + pSample2->Release(); + if (FAILED(hrProps)) { + pDest->Release(); + return NULL; + } + } else { + if (bTime) { + pDest->SetTime(&tStart, &tStop); + } + + if (S_OK == pSource->IsSyncPoint()) { + pDest->SetSyncPoint(TRUE); + } + if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { + pDest->SetDiscontinuity(TRUE); + } + if (S_OK == pSource->IsPreroll()) { + pDest->SetPreroll(TRUE); + } + + // Copy the media type + AM_MEDIA_TYPE *pMediaType; + if (S_OK == pSource->GetMediaType(&pMediaType)) { + pDest->SetMediaType(pMediaType); + DeleteMediaType( pMediaType ); + } + + } + + m_bSampleSkipped = FALSE; + + // Copy the sample media times + REFERENCE_TIME TimeStart, TimeEnd; + if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { + pDest->SetMediaTime(&TimeStart,&TimeEnd); + } + + // Copy the actual data length and the actual data. + { + const long lDataLength = pSource->GetActualDataLength(); + if (FAILED(pDest->SetActualDataLength(lDataLength))) { + pDest->Release(); + return NULL; + } + + // Copy the sample data + { + BYTE *pSourceBuffer, *pDestBuffer; +#ifdef _DEBUG + long lSourceSize = pSource->GetSize(); +#endif + long lDestSize = pDest->GetSize(); + + ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); + + if (FAILED(pSource->GetPointer(&pSourceBuffer)) || + FAILED(pDest->GetPointer(&pDestBuffer)) || + lDestSize < lDataLength || + lDataLength < 0) { + pDest->Release(); + return NULL; + } + ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); + + CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); + } + } + + return pDest; + +} // Copy + + +// override this to customize the transform process + +HRESULT +CTransInPlaceFilter::Receive(IMediaSample *pSample) +{ + /* Check for other streams and pass them on */ + AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); + if (pProps->dwStreamId != AM_STREAM_MEDIA) { + return m_pOutput->Deliver(pSample); + } + HRESULT hr; + + // Start timing the TransInPlace (if PERF is defined) + MSR_START(m_idTransInPlace); + + if (UsingDifferentAllocators()) { + + // We have to copy the data. + + pSample = Copy(pSample); + + if (pSample==NULL) { + MSR_STOP(m_idTransInPlace); + return E_UNEXPECTED; + } + } + + // have the derived class transform the data + hr = Transform(pSample); + + // Stop the clock and log it (if PERF is defined) + MSR_STOP(m_idTransInPlace); + + if (FAILED(hr)) { + DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace"))); + if (UsingDifferentAllocators()) { + pSample->Release(); + } + return hr; + } + + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pSample); + } else { + // But it would be an error to return this private workaround + // to the caller ... + if (S_FALSE == hr) { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this cause because + // returning S_FALSE from Receive() means that this is the end + // of the stream and no more data should be sent. + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + NotifyEvent(EC_QUALITY_CHANGE,0,0); + m_bQualityChanged = TRUE; + } + hr = NOERROR; + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + if (UsingDifferentAllocators()) { + pSample->Release(); + } + + return hr; + +} // Receive + + + +// ================================================================= +// Implements the CTransInPlaceInputPin class +// ================================================================= + + +// constructor + +CTransInPlaceInputPin::CTransInPlaceInputPin + ( __in_opt LPCTSTR pObjectName + , __inout CTransInPlaceFilter *pFilter + , __inout HRESULT *phr + , __in_opt LPCWSTR pName + ) + : CTransformInputPin(pObjectName, + pFilter, + phr, + pName) + , m_bReadOnly(FALSE) + , m_pTIPFilter(pFilter) +{ + DbgLog((LOG_TRACE, 2 + , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin"))); + +} // constructor + + +// ================================================================= +// Implements IMemInputPin interface +// ================================================================= + + +// If the downstream filter has one then offer that (even if our own output +// pin is not using it yet. If the upstream filter chooses it then we will +// tell our output pin to ReceiveAllocator). +// Else if our output pin is using an allocator then offer that. +// ( This could mean offering the upstream filter his own allocator, +// it could mean offerring our own +// ) or it could mean offering the one from downstream +// Else fail to offer any allocator at all. + +STDMETHODIMP CTransInPlaceInputPin::GetAllocator(__deref_out IMemAllocator ** ppAllocator) +{ + CheckPointer(ppAllocator,E_POINTER); + ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *)); + CAutoLock cObjectLock(m_pLock); + + HRESULT hr; + + if ( m_pTIPFilter->m_pOutput->IsConnected() ) { + // Store the allocator we got + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->GetAllocator( ppAllocator ); + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator( *ppAllocator ); + } + } + else { + // Help upstream filter (eg TIP filter which is having to do a copy) + // by providing a temp allocator here - we'll never use + // this allocator because when our output is connected we'll + // reconnect this pin + hr = CTransformInputPin::GetAllocator( ppAllocator ); + } + return hr; + +} // GetAllocator + + + +/* Get told which allocator the upstream output pin is actually going to use */ + + +STDMETHODIMP +CTransInPlaceInputPin::NotifyAllocator( + IMemAllocator * pAllocator, + BOOL bReadOnly) +{ + HRESULT hr = S_OK; + CheckPointer(pAllocator,E_POINTER); + ValidateReadPtr(pAllocator,sizeof(IMemAllocator)); + + CAutoLock cObjectLock(m_pLock); + + m_bReadOnly = bReadOnly; + // If we modify data then don't accept the allocator if it's + // the same as the output pin's allocator + + // If our output is not connected just accept the allocator + // We're never going to use this allocator because when our + // output pin is connected we'll reconnect this pin + if (!m_pTIPFilter->OutputPin()->IsConnected()) { + return CTransformInputPin::NotifyAllocator(pAllocator, bReadOnly); + } + + // If the allocator is read-only and we're modifying data + // and the allocator is the same as the output pin's + // then reject + if (bReadOnly && m_pTIPFilter->m_bModifiesData) { + IMemAllocator *pOutputAllocator = + m_pTIPFilter->OutputPin()->PeekAllocator(); + + // Make sure we have an output allocator + if (pOutputAllocator == NULL) { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin()-> + GetAllocator(&pOutputAllocator); + if(FAILED(hr)) { + hr = CreateMemoryAllocator(&pOutputAllocator); + } + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator(pOutputAllocator); + pOutputAllocator->Release(); + } + } + if (pAllocator == pOutputAllocator) { + hr = E_FAIL; + } else if(SUCCEEDED(hr)) { + // Must copy so set the allocator properties on the output + ALLOCATOR_PROPERTIES Props, Actual; + hr = pAllocator->GetProperties(&Props); + if (SUCCEEDED(hr)) { + hr = pOutputAllocator->SetProperties(&Props, &Actual); + + if (SUCCEEDED(hr)) { + if ( (Props.cBuffers > Actual.cBuffers) + || (Props.cbBuffer > Actual.cbBuffer) + || (Props.cbAlign > Actual.cbAlign) + ) { + hr = E_FAIL; + } + } + } + + // Set the allocator on the output pin + if (SUCCEEDED(hr)) { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->NotifyAllocator( pOutputAllocator, FALSE ); + } + } + } else { + hr = m_pTIPFilter->OutputPin()->ConnectedIMemInputPin() + ->NotifyAllocator( pAllocator, bReadOnly ); + if (SUCCEEDED(hr)) { + m_pTIPFilter->OutputPin()->SetAllocator( pAllocator ); + } + } + + if (SUCCEEDED(hr)) { + + // It's possible that the old and the new are the same thing. + // AddRef before release ensures that we don't unload it. + pAllocator->AddRef(); + + if( m_pAllocator != NULL ) + m_pAllocator->Release(); + + m_pAllocator = pAllocator; // We have an allocator for the input pin + } + + return hr; + +} // NotifyAllocator + + +// EnumMediaTypes +// - pass through to our downstream filter +STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ) +{ + // Can only pass through if connected + if( !m_pTIPFilter->m_pOutput->IsConnected() ) + return VFW_E_NOT_CONNECTED; + + return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum ); + +} // EnumMediaTypes + + +// CheckMediaType +// - agree to anything if not connected, +// otherwise pass through to the downstream filter. +// This assumes that the filter does not change the media type. + +HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt ) +{ + HRESULT hr = m_pTIPFilter->CheckInputType(pmt); + if (hr!=S_OK) return hr; + + if( m_pTIPFilter->m_pOutput->IsConnected() ) + return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt ); + else + return S_OK; + +} // CheckMediaType + + +// If upstream asks us what our requirements are, we will try to ask downstream +// if that doesn't work, we'll just take the defaults. +STDMETHODIMP +CTransInPlaceInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps) +{ + + if( m_pTIPFilter->m_pOutput->IsConnected() ) + return m_pTIPFilter->OutputPin() + ->ConnectedIMemInputPin()->GetAllocatorRequirements( pProps ); + else + return E_NOTIMPL; + +} // GetAllocatorRequirements + + +// CTransInPlaceInputPin::CompleteConnect() calls CBaseInputPin::CompleteConnect() +// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because +// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not +// want to reconnect a pin if CBaseInputPin::CompleteConnect() fails. +HRESULT +CTransInPlaceInputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin); +} // CompleteConnect + + +// ================================================================= +// Implements the CTransInPlaceOutputPin class +// ================================================================= + + +// constructor + +CTransInPlaceOutputPin::CTransInPlaceOutputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransInPlaceFilter *pFilter, + __inout HRESULT * phr, + __in_opt LPCWSTR pPinName) + : CTransformOutputPin( pObjectName + , pFilter + , phr + , pPinName), + m_pTIPFilter(pFilter) +{ + DbgLog(( LOG_TRACE, 2 + , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin"))); + +} // constructor + + +// EnumMediaTypes +// - pass through to our upstream filter +STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ) +{ + // Can only pass through if connected. + if( ! m_pTIPFilter->m_pInput->IsConnected() ) + return VFW_E_NOT_CONNECTED; + + return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum ); + +} // EnumMediaTypes + + + +// CheckMediaType +// - agree to anything if not connected, +// otherwise pass through to the upstream filter. + +HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt ) +{ + // Don't accept any output pin type changes if we're copying + // between allocators - it's too late to change the input + // allocator size. + if (m_pTIPFilter->UsingDifferentAllocators() && !m_pFilter->IsStopped()) { + if (*pmt == m_mt) { + return S_OK; + } else { + return VFW_E_TYPE_NOT_ACCEPTED; + } + } + + // Assumes the type does not change. That's why we're calling + // CheckINPUTType here on the OUTPUT pin. + HRESULT hr = m_pTIPFilter->CheckInputType(pmt); + if (hr!=S_OK) return hr; + + if( m_pTIPFilter->m_pInput->IsConnected() ) + return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt ); + else + return S_OK; + +} // CheckMediaType + + +/* Save the allocator pointer in the output pin +*/ +void +CTransInPlaceOutputPin::SetAllocator(IMemAllocator * pAllocator) +{ + pAllocator->AddRef(); + if (m_pAllocator) { + m_pAllocator->Release(); + } + m_pAllocator = pAllocator; +} // SetAllocator + + +// CTransInPlaceOutputPin::CompleteConnect() calls CBaseOutputPin::CompleteConnect() +// and then calls CTransInPlaceFilter::CompleteConnect(). It does this because +// CTransInPlaceFilter::CompleteConnect() can reconnect a pin and we do not want to +// reconnect a pin if CBaseOutputPin::CompleteConnect() fails. +// CBaseOutputPin::CompleteConnect() often fails when our output pin is being connected +// to the Video Mixing Renderer. +HRESULT +CTransInPlaceOutputPin::CompleteConnect(IPin *pReceivePin) +{ + HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin); + if (FAILED(hr)) { + return hr; + } + + return m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin); +} // CompleteConnect diff --git a/src/thirdparty/BaseClasses/transip.h b/src/thirdparty/BaseClasses/transip.h index f65f66b5f61..687efd99ed2 100644 --- a/src/thirdparty/BaseClasses/transip.h +++ b/src/thirdparty/BaseClasses/transip.h @@ -1,250 +1,250 @@ -//------------------------------------------------------------------------------ -// File: TransIP.h -// -// Desc: DirectShow base classes - defines classes from which simple -// Transform-In-Place filters may be derived. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// -// The difference between this and Transfrm.h is that Transfrm copies the data. -// -// It assumes the filter has one input and one output stream, and has no -// interest in memory management, interface negotiation or anything else. -// -// Derive your class from this, and supply Transform and the media type/format -// negotiation functions. Implement that class, compile and link and -// you're done. - - -#ifndef __TRANSIP__ -#define __TRANSIP__ - -// ====================================================================== -// This is the com object that represents a simple transform filter. It -// supports IBaseFilter, IMediaFilter and two pins through nested interfaces -// ====================================================================== - -class CTransInPlaceFilter; - -// Several of the pin functions call filter functions to do the work, -// so you can often use the pin classes unaltered, just overriding the -// functions in CTransInPlaceFilter. If that's not enough and you want -// to derive your own pin class, override GetPin in the filter to supply -// your own pin classes to the filter. - -// ================================================== -// Implements the input pin -// ================================================== - -class CTransInPlaceInputPin : public CTransformInputPin -{ - -protected: - CTransInPlaceFilter * const m_pTIPFilter; // our filter - BOOL m_bReadOnly; // incoming stream is read only - -public: - - CTransInPlaceInputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransInPlaceFilter *pFilter, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); - - // --- IMemInputPin ----- - - // Provide an enumerator for media types by getting one from downstream - STDMETHODIMP EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ); - - // Say whether media type is acceptable. - HRESULT CheckMediaType(const CMediaType* pmt); - - // Return our upstream allocator - STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator); - - // get told which allocator the upstream output pin is actually - // going to use. - STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator, - BOOL bReadOnly); - - // Allow the filter to see what allocator we have - // N.B. This does NOT AddRef - __out IMemAllocator * PeekAllocator() const - { return m_pAllocator; } - - // Pass this on downstream if it ever gets called. - STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps); - - HRESULT CompleteConnect(IPin *pReceivePin); - - inline const BOOL ReadOnly() { return m_bReadOnly ; } - -}; // CTransInPlaceInputPin - -// ================================================== -// Implements the output pin -// ================================================== - -class CTransInPlaceOutputPin : public CTransformOutputPin -{ - -protected: - // m_pFilter points to our CBaseFilter - CTransInPlaceFilter * const m_pTIPFilter; - -public: - - CTransInPlaceOutputPin( - __in_opt LPCTSTR pObjectName, - __inout CTransInPlaceFilter *pFilter, - __inout HRESULT *phr, - __in_opt LPCWSTR pName); - - - // --- CBaseOutputPin ------------ - - // negotiate the allocator and its buffer size/count - // Insists on using our own allocator. (Actually the one upstream of us). - // We don't override this - instead we just agree the default - // then let the upstream filter decide for itself on reconnect - // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); - - // Provide a media type enumerator. Get it from upstream. - STDMETHODIMP EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ); - - // Say whether media type is acceptable. - HRESULT CheckMediaType(const CMediaType* pmt); - - // This just saves the allocator being used on the output pin - // Also called by input pin's GetAllocator() - void SetAllocator(IMemAllocator * pAllocator); - - __out_opt IMemInputPin * ConnectedIMemInputPin() - { return m_pInputPin; } - - // Allow the filter to see what allocator we have - // N.B. This does NOT AddRef - __out IMemAllocator * PeekAllocator() const - { return m_pAllocator; } - - HRESULT CompleteConnect(IPin *pReceivePin); - -}; // CTransInPlaceOutputPin - - -class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter -{ - -public: - - // map getpin/getpincount for base enum of pins to owner - // override this to return more specialised pin objects - - virtual CBasePin *GetPin(int n); - -public: - - // Set bModifiesData == false if your derived filter does - // not modify the data samples (for instance it's just copying - // them somewhere else or looking at the timestamps). - - CTransInPlaceFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, - bool bModifiesData = true); -#ifdef UNICODE - CTransInPlaceFilter(__in_opt LPCSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, - bool bModifiesData = true); -#endif - // The following are defined to avoid undefined pure virtuals. - // Even if they are never called, they will give linkage warnings/errors - - // We override EnumMediaTypes to bypass the transform class enumerator - // which would otherwise call this. - HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType) - { DbgBreak("CTransInPlaceFilter::GetMediaType should never be called"); - return E_UNEXPECTED; - } - - // This is called when we actually have to provide our own allocator. - HRESULT DecideBufferSize(IMemAllocator*, __inout ALLOCATOR_PROPERTIES *); - - // The functions which call this in CTransform are overridden in this - // class to call CheckInputType with the assumption that the type - // does not change. In Debug builds some calls will be made and - // we just ensure that they do not assert. - HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) - { - return S_OK; - }; - - - // ================================================================= - // ----- You may want to override this ----------------------------- - // ================================================================= - - HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin); - - // chance to customize the transform process - virtual HRESULT Receive(IMediaSample *pSample); - - // ================================================================= - // ----- You MUST override these ----------------------------------- - // ================================================================= - - virtual HRESULT Transform(IMediaSample *pSample) PURE; - - // this goes in the factory template table to create new instances - // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); - - -#ifdef PERF - // Override to register performance measurement with a less generic string - // You should do this to avoid confusion with other filters - virtual void RegisterPerfId() - {m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));} -#endif // PERF - - -// implementation details - -protected: - - __out_opt IMediaSample * Copy(IMediaSample *pSource); - -#ifdef PERF - int m_idTransInPlace; // performance measuring id -#endif // PERF - bool m_bModifiesData; // Does this filter change the data? - - // these hold our input and output pins - - friend class CTransInPlaceInputPin; - friend class CTransInPlaceOutputPin; - - __out CTransInPlaceInputPin *InputPin() const - { - return (CTransInPlaceInputPin *)m_pInput; - }; - __out CTransInPlaceOutputPin *OutputPin() const - { - return (CTransInPlaceOutputPin *)m_pOutput; - }; - - // Helper to see if the input and output types match - BOOL TypesMatch() - { - return InputPin()->CurrentMediaType() == - OutputPin()->CurrentMediaType(); - } - - // Are the input and output allocators different? - BOOL UsingDifferentAllocators() const - { - return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator(); - } -}; // CTransInPlaceFilter - -#endif /* __TRANSIP__ */ - +//------------------------------------------------------------------------------ +// File: TransIP.h +// +// Desc: DirectShow base classes - defines classes from which simple +// Transform-In-Place filters may be derived. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// +// The difference between this and Transfrm.h is that Transfrm copies the data. +// +// It assumes the filter has one input and one output stream, and has no +// interest in memory management, interface negotiation or anything else. +// +// Derive your class from this, and supply Transform and the media type/format +// negotiation functions. Implement that class, compile and link and +// you're done. + + +#ifndef __TRANSIP__ +#define __TRANSIP__ + +// ====================================================================== +// This is the com object that represents a simple transform filter. It +// supports IBaseFilter, IMediaFilter and two pins through nested interfaces +// ====================================================================== + +class CTransInPlaceFilter; + +// Several of the pin functions call filter functions to do the work, +// so you can often use the pin classes unaltered, just overriding the +// functions in CTransInPlaceFilter. If that's not enough and you want +// to derive your own pin class, override GetPin in the filter to supply +// your own pin classes to the filter. + +// ================================================== +// Implements the input pin +// ================================================== + +class CTransInPlaceInputPin : public CTransformInputPin +{ + +protected: + CTransInPlaceFilter * const m_pTIPFilter; // our filter + BOOL m_bReadOnly; // incoming stream is read only + +public: + + CTransInPlaceInputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransInPlaceFilter *pFilter, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); + + // --- IMemInputPin ----- + + // Provide an enumerator for media types by getting one from downstream + STDMETHODIMP EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ); + + // Say whether media type is acceptable. + HRESULT CheckMediaType(const CMediaType* pmt); + + // Return our upstream allocator + STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator); + + // get told which allocator the upstream output pin is actually + // going to use. + STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator, + BOOL bReadOnly); + + // Allow the filter to see what allocator we have + // N.B. This does NOT AddRef + __out IMemAllocator * PeekAllocator() const + { return m_pAllocator; } + + // Pass this on downstream if it ever gets called. + STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES *pProps); + + HRESULT CompleteConnect(IPin *pReceivePin); + + inline const BOOL ReadOnly() { return m_bReadOnly ; } + +}; // CTransInPlaceInputPin + +// ================================================== +// Implements the output pin +// ================================================== + +class CTransInPlaceOutputPin : public CTransformOutputPin +{ + +protected: + // m_pFilter points to our CBaseFilter + CTransInPlaceFilter * const m_pTIPFilter; + +public: + + CTransInPlaceOutputPin( + __in_opt LPCTSTR pObjectName, + __inout CTransInPlaceFilter *pFilter, + __inout HRESULT *phr, + __in_opt LPCWSTR pName); + + + // --- CBaseOutputPin ------------ + + // negotiate the allocator and its buffer size/count + // Insists on using our own allocator. (Actually the one upstream of us). + // We don't override this - instead we just agree the default + // then let the upstream filter decide for itself on reconnect + // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc); + + // Provide a media type enumerator. Get it from upstream. + STDMETHODIMP EnumMediaTypes( __deref_out IEnumMediaTypes **ppEnum ); + + // Say whether media type is acceptable. + HRESULT CheckMediaType(const CMediaType* pmt); + + // This just saves the allocator being used on the output pin + // Also called by input pin's GetAllocator() + void SetAllocator(IMemAllocator * pAllocator); + + __out_opt IMemInputPin * ConnectedIMemInputPin() + { return m_pInputPin; } + + // Allow the filter to see what allocator we have + // N.B. This does NOT AddRef + __out IMemAllocator * PeekAllocator() const + { return m_pAllocator; } + + HRESULT CompleteConnect(IPin *pReceivePin); + +}; // CTransInPlaceOutputPin + + +class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter +{ + +public: + + // map getpin/getpincount for base enum of pins to owner + // override this to return more specialised pin objects + + virtual CBasePin *GetPin(int n); + +public: + + // Set bModifiesData == false if your derived filter does + // not modify the data samples (for instance it's just copying + // them somewhere else or looking at the timestamps). + + CTransInPlaceFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, + bool bModifiesData = true); +#ifdef UNICODE + CTransInPlaceFilter(__in_opt LPCSTR, __inout_opt LPUNKNOWN, REFCLSID clsid, __inout HRESULT *, + bool bModifiesData = true); +#endif + // The following are defined to avoid undefined pure virtuals. + // Even if they are never called, they will give linkage warnings/errors + + // We override EnumMediaTypes to bypass the transform class enumerator + // which would otherwise call this. + HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType) + { DbgBreak("CTransInPlaceFilter::GetMediaType should never be called"); + return E_UNEXPECTED; + } + + // This is called when we actually have to provide our own allocator. + HRESULT DecideBufferSize(IMemAllocator*, __inout ALLOCATOR_PROPERTIES *); + + // The functions which call this in CTransform are overridden in this + // class to call CheckInputType with the assumption that the type + // does not change. In Debug builds some calls will be made and + // we just ensure that they do not assert. + HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) + { + return S_OK; + }; + + + // ================================================================= + // ----- You may want to override this ----------------------------- + // ================================================================= + + HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin); + + // chance to customize the transform process + virtual HRESULT Receive(IMediaSample *pSample); + + // ================================================================= + // ----- You MUST override these ----------------------------------- + // ================================================================= + + virtual HRESULT Transform(IMediaSample *pSample) PURE; + + // this goes in the factory template table to create new instances + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + + +#ifdef PERF + // Override to register performance measurement with a less generic string + // You should do this to avoid confusion with other filters + virtual void RegisterPerfId() + {m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));} +#endif // PERF + + +// implementation details + +protected: + + __out_opt IMediaSample * Copy(IMediaSample *pSource); + +#ifdef PERF + int m_idTransInPlace; // performance measuring id +#endif // PERF + bool m_bModifiesData; // Does this filter change the data? + + // these hold our input and output pins + + friend class CTransInPlaceInputPin; + friend class CTransInPlaceOutputPin; + + __out CTransInPlaceInputPin *InputPin() const + { + return (CTransInPlaceInputPin *)m_pInput; + }; + __out CTransInPlaceOutputPin *OutputPin() const + { + return (CTransInPlaceOutputPin *)m_pOutput; + }; + + // Helper to see if the input and output types match + BOOL TypesMatch() + { + return InputPin()->CurrentMediaType() == + OutputPin()->CurrentMediaType(); + } + + // Are the input and output allocators different? + BOOL UsingDifferentAllocators() const + { + return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator(); + } +}; // CTransInPlaceFilter + +#endif /* __TRANSIP__ */ + diff --git a/src/thirdparty/BaseClasses/videoctl.cpp b/src/thirdparty/BaseClasses/videoctl.cpp index 974b1dfb9a8..d8e293d322f 100644 --- a/src/thirdparty/BaseClasses/videoctl.cpp +++ b/src/thirdparty/BaseClasses/videoctl.cpp @@ -1,745 +1,745 @@ -//------------------------------------------------------------------------------ -// File: VideoCtl.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "ddmm.h" - -// Load a string from the resource file string table. The buffer must be at -// least STR_MAX_LENGTH bytes. The easiest way to use this is to declare a -// buffer in the property page class and use it for all string loading. It -// cannot be static as multiple property pages may be active simultaneously - -LPCTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID) -{ - if (LoadString(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { - return TEXT(""); - } - return pBuffer; -} - -#ifdef UNICODE -LPCSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR pBuffer, int iResourceID) -{ - if (LoadStringA(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { - return ""; - } - return pBuffer; -} -#endif - - - -// Property pages typically are called through their OLE interfaces. These -// use UNICODE strings regardless of how the binary is built. So when we -// load strings from the resource file we sometimes want to convert them -// to UNICODE. This method is passed the target UNICODE buffer and does a -// convert after loading the string (if built UNICODE this is not needed) -// On WinNT we can explicitly call LoadStringW which saves two conversions - -#ifndef UNICODE - -LPCWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR pBuffer, int iResourceID) -{ - *pBuffer = 0; - - if (g_amPlatform == VER_PLATFORM_WIN32_NT) { - LoadStringW(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH); - } else { - - CHAR szBuffer[STR_MAX_LENGTH]; - DWORD dwStringLength = LoadString(g_hInst,iResourceID,szBuffer,STR_MAX_LENGTH); - // if we loaded a string convert it to wide characters, ensuring - // that we also null terminate the result. - if (dwStringLength++) { - MultiByteToWideChar(CP_ACP,0,szBuffer,dwStringLength,pBuffer,STR_MAX_LENGTH); - } - } - return pBuffer; -} - -#endif - - -// Helper function to calculate the size of the dialog - -BOOL WINAPI GetDialogSize(int iResourceID, - DLGPROC pDlgProc, - LPARAM lParam, - __out SIZE *pResult) -{ - RECT rc; - HWND hwnd; - - // Create a temporary property page - - hwnd = CreateDialogParam(g_hInst, - MAKEINTRESOURCE(iResourceID), - GetDesktopWindow(), - pDlgProc, - lParam); - if (hwnd == NULL) { - return FALSE; - } - - GetWindowRect(hwnd, &rc); - pResult->cx = rc.right - rc.left; - pResult->cy = rc.bottom - rc.top; - - DestroyWindow(hwnd); - return TRUE; -} - - -// Class that aggregates on the IDirectDraw interface. Although DirectDraw -// has the ability in its interfaces to be aggregated they're not currently -// implemented. This makes it difficult for various parts of Quartz that want -// to aggregate these interfaces. In particular the video renderer passes out -// media samples that expose IDirectDraw and IDirectDrawSurface. The filter -// graph manager also exposes IDirectDraw as a plug in distributor. For these -// objects we provide these aggregation classes that republish the interfaces - -STDMETHODIMP CAggDirectDraw::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ASSERT(m_pDirectDraw); - - // Do we have this interface - - if (riid == IID_IDirectDraw) { - return GetInterface((IDirectDraw *)this,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid,ppv); - } -} - - -STDMETHODIMP CAggDirectDraw::Compact() -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->Compact(); -} - - -STDMETHODIMP CAggDirectDraw::CreateClipper(DWORD dwFlags, __deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper, __inout_opt IUnknown *pUnkOuter) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->CreateClipper(dwFlags,lplpDDClipper,pUnkOuter); -} - - -STDMETHODIMP CAggDirectDraw::CreatePalette(DWORD dwFlags, - __in LPPALETTEENTRY lpColorTable, - __deref_out LPDIRECTDRAWPALETTE *lplpDDPalette, - __inout_opt IUnknown *pUnkOuter) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->CreatePalette(dwFlags,lpColorTable,lplpDDPalette,pUnkOuter); -} - - -STDMETHODIMP CAggDirectDraw::CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc, - __deref_out LPDIRECTDRAWSURFACE *lplpDDSurface, - __inout_opt IUnknown *pUnkOuter) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->CreateSurface(lpDDSurfaceDesc,lplpDDSurface,pUnkOuter); -} - - -STDMETHODIMP CAggDirectDraw::DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface, - __deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->DuplicateSurface(lpDDSurface,lplpDupDDSurface); -} - - -STDMETHODIMP CAggDirectDraw::EnumDisplayModes(DWORD dwSurfaceDescCount, - __in LPDDSURFACEDESC lplpDDSurfaceDescList, - __in LPVOID lpContext, - __in LPDDENUMMODESCALLBACK lpEnumCallback) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->EnumDisplayModes(dwSurfaceDescCount,lplpDDSurfaceDescList,lpContext,lpEnumCallback); -} - - -STDMETHODIMP CAggDirectDraw::EnumSurfaces(DWORD dwFlags, - __in LPDDSURFACEDESC lpDDSD, - __in LPVOID lpContext, - __in LPDDENUMSURFACESCALLBACK lpEnumCallback) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->EnumSurfaces(dwFlags,lpDDSD,lpContext,lpEnumCallback); -} - - -STDMETHODIMP CAggDirectDraw::FlipToGDISurface() -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->FlipToGDISurface(); -} - - -STDMETHODIMP CAggDirectDraw::GetCaps(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetCaps(lpDDDriverCaps,lpDDHELCaps); -} - - -STDMETHODIMP CAggDirectDraw::GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetDisplayMode(lpDDSurfaceDesc); -} - - -STDMETHODIMP CAggDirectDraw::GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetFourCCCodes(lpNumCodes,lpCodes); -} - - -STDMETHODIMP CAggDirectDraw::GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetGDISurface(lplpGDIDDSurface); -} - - -STDMETHODIMP CAggDirectDraw::GetMonitorFrequency(__out LPDWORD lpdwFrequency) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetMonitorFrequency(lpdwFrequency); -} - - -STDMETHODIMP CAggDirectDraw::GetScanLine(__out LPDWORD lpdwScanLine) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetScanLine(lpdwScanLine); -} - - -STDMETHODIMP CAggDirectDraw::GetVerticalBlankStatus(__out LPBOOL lpblsInVB) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->GetVerticalBlankStatus(lpblsInVB); -} - - -STDMETHODIMP CAggDirectDraw::Initialize(__in GUID *lpGUID) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->Initialize(lpGUID); -} - - -STDMETHODIMP CAggDirectDraw::RestoreDisplayMode() -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->RestoreDisplayMode(); -} - - -STDMETHODIMP CAggDirectDraw::SetCooperativeLevel(HWND hWnd,DWORD dwFlags) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->SetCooperativeLevel(hWnd,dwFlags); -} - - -STDMETHODIMP CAggDirectDraw::SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->SetDisplayMode(dwWidth,dwHeight,dwBpp); -} - - -STDMETHODIMP CAggDirectDraw::WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent) -{ - ASSERT(m_pDirectDraw); - return m_pDirectDraw->WaitForVerticalBlank(dwFlags,hEvent); -} - - -// Class that aggregates an IDirectDrawSurface interface. Although DirectDraw -// has the ability in its interfaces to be aggregated they're not currently -// implemented. This makes it difficult for various parts of Quartz that want -// to aggregate these interfaces. In particular the video renderer passes out -// media samples that expose IDirectDraw and IDirectDrawSurface. The filter -// graph manager also exposes IDirectDraw as a plug in distributor. For these -// objects we provide these aggregation classes that republish the interfaces - -STDMETHODIMP CAggDrawSurface::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) -{ - ASSERT(m_pDirectDrawSurface); - - // Do we have this interface - - if (riid == IID_IDirectDrawSurface) { - return GetInterface((IDirectDrawSurface *)this,ppv); - } else { - return CUnknown::NonDelegatingQueryInterface(riid,ppv); - } -} - - -STDMETHODIMP CAggDrawSurface::AddAttachedSurface(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->AddAttachedSurface(lpDDSAttachedSurface); -} - - -STDMETHODIMP CAggDrawSurface::AddOverlayDirtyRect(__in LPRECT lpRect) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->AddOverlayDirtyRect(lpRect); -} - - -STDMETHODIMP CAggDrawSurface::Blt(__in LPRECT lpDestRect, - __in LPDIRECTDRAWSURFACE lpDDSrcSurface, - __in LPRECT lpSrcRect, - DWORD dwFlags, - __in LPDDBLTFX lpDDBltFx) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx); -} - - -STDMETHODIMP CAggDrawSurface::BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->BltBatch(lpDDBltBatch,dwCount,dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::BltFast(DWORD dwX,DWORD dwY, - __in LPDIRECTDRAWSURFACE lpDDSrcSurface, - __in LPRECT lpSrcRect, - DWORD dwTrans) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->BltFast(dwX,dwY,lpDDSrcSurface,lpSrcRect,dwTrans); -} - - -STDMETHODIMP CAggDrawSurface::DeleteAttachedSurface(DWORD dwFlags, - __in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->DeleteAttachedSurface(dwFlags,lpDDSAttachedSurface); -} - - -STDMETHODIMP CAggDrawSurface::EnumAttachedSurfaces(__in LPVOID lpContext, - __in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->EnumAttachedSurfaces(lpContext,lpEnumSurfacesCallback); -} - - -STDMETHODIMP CAggDrawSurface::EnumOverlayZOrders(DWORD dwFlags, - __in LPVOID lpContext, - __in LPDDENUMSURFACESCALLBACK lpfnCallback) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->EnumOverlayZOrders(dwFlags,lpContext,lpfnCallback); -} - - -STDMETHODIMP CAggDrawSurface::Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Flip(lpDDSurfaceTargetOverride,dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::GetAttachedSurface(__in LPDDSCAPS lpDDSCaps, - __deref_out LPDIRECTDRAWSURFACE *lplpDDAttachedSurface) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetAttachedSurface(lpDDSCaps,lplpDDAttachedSurface); -} - - -STDMETHODIMP CAggDrawSurface::GetBltStatus(DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetBltStatus(dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::GetCaps(__out LPDDSCAPS lpDDSCaps) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetCaps(lpDDSCaps); -} - - -STDMETHODIMP CAggDrawSurface::GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetClipper(lplpDDClipper); -} - - -STDMETHODIMP CAggDrawSurface::GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetColorKey(dwFlags,lpDDColorKey); -} - - -STDMETHODIMP CAggDrawSurface::GetDC(__out HDC *lphDC) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetDC(lphDC); -} - - -STDMETHODIMP CAggDrawSurface::GetFlipStatus(DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetFlipStatus(dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::GetOverlayPosition(__out LPLONG lpdwX,__out LPLONG lpdwY) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetOverlayPosition(lpdwX,lpdwY); -} - - -STDMETHODIMP CAggDrawSurface::GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetPalette(lplpDDPalette); -} - - -STDMETHODIMP CAggDrawSurface::GetPixelFormat(__out LPDDPIXELFORMAT lpDDPixelFormat) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->GetPixelFormat(lpDDPixelFormat); -} - - -// A bit of a warning here: Our media samples in DirectShow aggregate on -// IDirectDraw and IDirectDrawSurface (ie are available through IMediaSample -// by QueryInterface). Unfortunately the underlying DirectDraw code cannot -// be aggregated so we have to use these classes. The snag is that when we -// call a different surface and pass in this interface as perhaps the source -// surface the call will fail because DirectDraw dereferences the pointer to -// get at its private data structures. Therefore we supply this workaround to give -// access to the real IDirectDraw surface. A filter can call GetSurfaceDesc -// and we will fill in the lpSurface pointer with the real underlying surface - -STDMETHODIMP CAggDrawSurface::GetSurfaceDesc(__out LPDDSURFACEDESC lpDDSurfaceDesc) -{ - ASSERT(m_pDirectDrawSurface); - - // First call down to the underlying DirectDraw - - HRESULT hr = m_pDirectDrawSurface->GetSurfaceDesc(lpDDSurfaceDesc); - if (FAILED(hr)) { - return hr; - } - - // Store the real DirectDrawSurface interface - lpDDSurfaceDesc->lpSurface = m_pDirectDrawSurface; - return hr; -} - - -STDMETHODIMP CAggDrawSurface::Initialize(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Initialize(lpDD,lpDDSurfaceDesc); -} - - -STDMETHODIMP CAggDrawSurface::IsLost() -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->IsLost(); -} - - -STDMETHODIMP CAggDrawSurface::Lock(__in LPRECT lpDestRect, - __inout LPDDSURFACEDESC lpDDSurfaceDesc, - DWORD dwFlags, - HANDLE hEvent) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Lock(lpDestRect,lpDDSurfaceDesc,dwFlags,hEvent); -} - - -STDMETHODIMP CAggDrawSurface::ReleaseDC(HDC hDC) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->ReleaseDC(hDC); -} - - -STDMETHODIMP CAggDrawSurface::Restore() -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Restore(); -} - - -STDMETHODIMP CAggDrawSurface::SetClipper(__in LPDIRECTDRAWCLIPPER lpDDClipper) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->SetClipper(lpDDClipper); -} - - -STDMETHODIMP CAggDrawSurface::SetColorKey(DWORD dwFlags,__in LPDDCOLORKEY lpDDColorKey) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->SetColorKey(dwFlags,lpDDColorKey); -} - - -STDMETHODIMP CAggDrawSurface::SetOverlayPosition(LONG dwX,LONG dwY) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->SetOverlayPosition(dwX,dwY); -} - - -STDMETHODIMP CAggDrawSurface::SetPalette(__in LPDIRECTDRAWPALETTE lpDDPalette) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->SetPalette(lpDDPalette); -} - - -STDMETHODIMP CAggDrawSurface::Unlock(__in LPVOID lpSurfaceData) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->Unlock(lpSurfaceData); -} - - -STDMETHODIMP CAggDrawSurface::UpdateOverlay(__in LPRECT lpSrcRect, - __in LPDIRECTDRAWSURFACE lpDDDestSurface, - __in LPRECT lpDestRect, - DWORD dwFlags, - __in LPDDOVERLAYFX lpDDOverlayFX) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->UpdateOverlay(lpSrcRect,lpDDDestSurface,lpDestRect,dwFlags,lpDDOverlayFX); -} - - -STDMETHODIMP CAggDrawSurface::UpdateOverlayDisplay(DWORD dwFlags) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->UpdateOverlayDisplay(dwFlags); -} - - -STDMETHODIMP CAggDrawSurface::UpdateOverlayZOrder(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSReference) -{ - ASSERT(m_pDirectDrawSurface); - return m_pDirectDrawSurface->UpdateOverlayZOrder(dwFlags,lpDDSReference); -} - - -// DirectShow must work on multiple platforms. In particular, it also runs on -// Windows NT 3.51 which does not have DirectDraw capabilities. The filters -// cannot therefore link statically to the DirectDraw library. To make their -// lives that little bit easier we provide this class that manages loading -// and unloading the library and creating the initial IDirectDraw interface - -CLoadDirectDraw::CLoadDirectDraw() : - m_pDirectDraw(NULL), - m_hDirectDraw(NULL) -{ -} - - -// Destructor forces unload - -CLoadDirectDraw::~CLoadDirectDraw() -{ - ReleaseDirectDraw(); - - if (m_hDirectDraw) { - NOTE("Unloading library"); - FreeLibrary(m_hDirectDraw); - } -} - - -// We can't be sure that DirectDraw is always available so we can't statically -// link to the library. Therefore we load the library, get the function entry -// point addresses and call them to create the driver objects. We return S_OK -// if we manage to load DirectDraw correctly otherwise we return E_NOINTERFACE -// We initialise a DirectDraw instance by explicitely loading the library and -// calling GetProcAddress on the DirectDrawCreate entry point that it exports - -// On a multi monitor system, we can get the DirectDraw object for any -// monitor (device) with the optional szDevice parameter - -HRESULT CLoadDirectDraw::LoadDirectDraw(__in LPSTR szDevice) -{ - PDRAWCREATE pDrawCreate; - PDRAWENUM pDrawEnum; - LPDIRECTDRAWENUMERATEEXA pDrawEnumEx; - - NOTE("Entering DoLoadDirectDraw"); - - // Is DirectDraw already loaded - - if (m_pDirectDraw) { - NOTE("Already loaded"); - ASSERT(m_hDirectDraw); - return NOERROR; - } - - // Make sure the library is available - - if(!m_hDirectDraw) - { - UINT ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX); - m_hDirectDraw = LoadLibrary(TEXT("ddraw.dll")); - SetErrorMode(ErrorMode); - - if (m_hDirectDraw == NULL) { - DbgLog((LOG_ERROR,1,TEXT("Can't load ddraw.dll"))); - NOTE("No library"); - return E_NOINTERFACE; - } - } - - // Get the DLL address for the creator function - - pDrawCreate = (PDRAWCREATE)GetProcAddress(m_hDirectDraw,"DirectDrawCreate"); - // force ANSI, we assume it - pDrawEnum = (PDRAWENUM)GetProcAddress(m_hDirectDraw,"DirectDrawEnumerateA"); - pDrawEnumEx = (LPDIRECTDRAWENUMERATEEXA)GetProcAddress(m_hDirectDraw, - "DirectDrawEnumerateExA"); - - // We don't NEED DirectDrawEnumerateEx, that's just for multimon stuff - if (pDrawCreate == NULL || pDrawEnum == NULL) { - DbgLog((LOG_ERROR,1,TEXT("Can't get functions: Create=%x Enum=%x"), - pDrawCreate, pDrawEnum)); - NOTE("No entry point"); - ReleaseDirectDraw(); - return E_NOINTERFACE; - } - - DbgLog((LOG_TRACE,3,TEXT("Creating DDraw for device %s"), - szDevice ? szDevice : "")); - - // Create a DirectDraw display provider for this device, using the fancy - // multimon-aware version, if it exists - if (pDrawEnumEx) - m_pDirectDraw = DirectDrawCreateFromDeviceEx(szDevice, pDrawCreate, - pDrawEnumEx); - else - m_pDirectDraw = DirectDrawCreateFromDevice(szDevice, pDrawCreate, - pDrawEnum); - - if (m_pDirectDraw == NULL) { - DbgLog((LOG_ERROR,1,TEXT("Can't create DDraw"))); - NOTE("No instance"); - ReleaseDirectDraw(); - return E_NOINTERFACE; - } - return NOERROR; -} - - -// Called to release any DirectDraw provider we previously loaded. We may be -// called at any time especially when something goes horribly wrong and when -// we need to clean up before returning so we can't guarantee that all state -// variables are consistent so free only those really allocated allocated -// This should only be called once all reference counts have been released - -void CLoadDirectDraw::ReleaseDirectDraw() -{ - NOTE("Releasing DirectDraw driver"); - - // Release any DirectDraw provider interface - - if (m_pDirectDraw) { - NOTE("Releasing instance"); - m_pDirectDraw->Release(); - m_pDirectDraw = NULL; - } - -} - - -// Return NOERROR (S_OK) if DirectDraw has been loaded by this object - -HRESULT CLoadDirectDraw::IsDirectDrawLoaded() -{ - NOTE("Entering IsDirectDrawLoaded"); - - if (m_pDirectDraw == NULL) { - NOTE("DirectDraw not loaded"); - return S_FALSE; - } - return NOERROR; -} - - -// Return the IDirectDraw interface we look after - -LPDIRECTDRAW CLoadDirectDraw::GetDirectDraw() -{ - NOTE("Entering GetDirectDraw"); - - if (m_pDirectDraw == NULL) { - NOTE("No DirectDraw"); - return NULL; - } - - NOTE("Returning DirectDraw"); - m_pDirectDraw->AddRef(); - return m_pDirectDraw; -} - - -// Are we running on Direct Draw version 1? We need to find out as -// we rely on specific bug fixes in DirectDraw 2 for fullscreen playback. To -// find out, we simply see if it supports IDirectDraw2. Only version 2 and -// higher support this. - -BOOL CLoadDirectDraw::IsDirectDrawVersion1() -{ - - if (m_pDirectDraw == NULL) - return FALSE; - - IDirectDraw2 *p = NULL; - HRESULT hr = m_pDirectDraw->QueryInterface(IID_IDirectDraw2, (void **)&p); - if (p) - p->Release(); - if (hr == NOERROR) { - DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 2 or greater"))); - return FALSE; - } else { - DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 1"))); - return TRUE; - } -} +//------------------------------------------------------------------------------ +// File: VideoCtl.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "ddmm.h" + +// Load a string from the resource file string table. The buffer must be at +// least STR_MAX_LENGTH bytes. The easiest way to use this is to declare a +// buffer in the property page class and use it for all string loading. It +// cannot be static as multiple property pages may be active simultaneously + +LPCTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID) +{ + if (LoadString(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { + return TEXT(""); + } + return pBuffer; +} + +#ifdef UNICODE +LPCSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR pBuffer, int iResourceID) +{ + if (LoadStringA(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { + return ""; + } + return pBuffer; +} +#endif + + + +// Property pages typically are called through their OLE interfaces. These +// use UNICODE strings regardless of how the binary is built. So when we +// load strings from the resource file we sometimes want to convert them +// to UNICODE. This method is passed the target UNICODE buffer and does a +// convert after loading the string (if built UNICODE this is not needed) +// On WinNT we can explicitly call LoadStringW which saves two conversions + +#ifndef UNICODE + +LPCWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR pBuffer, int iResourceID) +{ + *pBuffer = 0; + + if (g_amPlatform == VER_PLATFORM_WIN32_NT) { + LoadStringW(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH); + } else { + + CHAR szBuffer[STR_MAX_LENGTH]; + DWORD dwStringLength = LoadString(g_hInst,iResourceID,szBuffer,STR_MAX_LENGTH); + // if we loaded a string convert it to wide characters, ensuring + // that we also null terminate the result. + if (dwStringLength++) { + MultiByteToWideChar(CP_ACP,0,szBuffer,dwStringLength,pBuffer,STR_MAX_LENGTH); + } + } + return pBuffer; +} + +#endif + + +// Helper function to calculate the size of the dialog + +BOOL WINAPI GetDialogSize(int iResourceID, + DLGPROC pDlgProc, + LPARAM lParam, + __out SIZE *pResult) +{ + RECT rc; + HWND hwnd; + + // Create a temporary property page + + hwnd = CreateDialogParam(g_hInst, + MAKEINTRESOURCE(iResourceID), + GetDesktopWindow(), + pDlgProc, + lParam); + if (hwnd == NULL) { + return FALSE; + } + + GetWindowRect(hwnd, &rc); + pResult->cx = rc.right - rc.left; + pResult->cy = rc.bottom - rc.top; + + DestroyWindow(hwnd); + return TRUE; +} + + +// Class that aggregates on the IDirectDraw interface. Although DirectDraw +// has the ability in its interfaces to be aggregated they're not currently +// implemented. This makes it difficult for various parts of Quartz that want +// to aggregate these interfaces. In particular the video renderer passes out +// media samples that expose IDirectDraw and IDirectDrawSurface. The filter +// graph manager also exposes IDirectDraw as a plug in distributor. For these +// objects we provide these aggregation classes that republish the interfaces + +STDMETHODIMP CAggDirectDraw::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ASSERT(m_pDirectDraw); + + // Do we have this interface + + if (riid == IID_IDirectDraw) { + return GetInterface((IDirectDraw *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +STDMETHODIMP CAggDirectDraw::Compact() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->Compact(); +} + + +STDMETHODIMP CAggDirectDraw::CreateClipper(DWORD dwFlags, __deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper, __inout_opt IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreateClipper(dwFlags,lplpDDClipper,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::CreatePalette(DWORD dwFlags, + __in LPPALETTEENTRY lpColorTable, + __deref_out LPDIRECTDRAWPALETTE *lplpDDPalette, + __inout_opt IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreatePalette(dwFlags,lpColorTable,lplpDDPalette,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc, + __deref_out LPDIRECTDRAWSURFACE *lplpDDSurface, + __inout_opt IUnknown *pUnkOuter) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->CreateSurface(lpDDSurfaceDesc,lplpDDSurface,pUnkOuter); +} + + +STDMETHODIMP CAggDirectDraw::DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface, + __deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->DuplicateSurface(lpDDSurface,lplpDupDDSurface); +} + + +STDMETHODIMP CAggDirectDraw::EnumDisplayModes(DWORD dwSurfaceDescCount, + __in LPDDSURFACEDESC lplpDDSurfaceDescList, + __in LPVOID lpContext, + __in LPDDENUMMODESCALLBACK lpEnumCallback) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->EnumDisplayModes(dwSurfaceDescCount,lplpDDSurfaceDescList,lpContext,lpEnumCallback); +} + + +STDMETHODIMP CAggDirectDraw::EnumSurfaces(DWORD dwFlags, + __in LPDDSURFACEDESC lpDDSD, + __in LPVOID lpContext, + __in LPDDENUMSURFACESCALLBACK lpEnumCallback) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->EnumSurfaces(dwFlags,lpDDSD,lpContext,lpEnumCallback); +} + + +STDMETHODIMP CAggDirectDraw::FlipToGDISurface() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->FlipToGDISurface(); +} + + +STDMETHODIMP CAggDirectDraw::GetCaps(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetCaps(lpDDDriverCaps,lpDDHELCaps); +} + + +STDMETHODIMP CAggDirectDraw::GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetDisplayMode(lpDDSurfaceDesc); +} + + +STDMETHODIMP CAggDirectDraw::GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetFourCCCodes(lpNumCodes,lpCodes); +} + + +STDMETHODIMP CAggDirectDraw::GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetGDISurface(lplpGDIDDSurface); +} + + +STDMETHODIMP CAggDirectDraw::GetMonitorFrequency(__out LPDWORD lpdwFrequency) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetMonitorFrequency(lpdwFrequency); +} + + +STDMETHODIMP CAggDirectDraw::GetScanLine(__out LPDWORD lpdwScanLine) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetScanLine(lpdwScanLine); +} + + +STDMETHODIMP CAggDirectDraw::GetVerticalBlankStatus(__out LPBOOL lpblsInVB) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->GetVerticalBlankStatus(lpblsInVB); +} + + +STDMETHODIMP CAggDirectDraw::Initialize(__in GUID *lpGUID) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->Initialize(lpGUID); +} + + +STDMETHODIMP CAggDirectDraw::RestoreDisplayMode() +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->RestoreDisplayMode(); +} + + +STDMETHODIMP CAggDirectDraw::SetCooperativeLevel(HWND hWnd,DWORD dwFlags) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->SetCooperativeLevel(hWnd,dwFlags); +} + + +STDMETHODIMP CAggDirectDraw::SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->SetDisplayMode(dwWidth,dwHeight,dwBpp); +} + + +STDMETHODIMP CAggDirectDraw::WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent) +{ + ASSERT(m_pDirectDraw); + return m_pDirectDraw->WaitForVerticalBlank(dwFlags,hEvent); +} + + +// Class that aggregates an IDirectDrawSurface interface. Although DirectDraw +// has the ability in its interfaces to be aggregated they're not currently +// implemented. This makes it difficult for various parts of Quartz that want +// to aggregate these interfaces. In particular the video renderer passes out +// media samples that expose IDirectDraw and IDirectDrawSurface. The filter +// graph manager also exposes IDirectDraw as a plug in distributor. For these +// objects we provide these aggregation classes that republish the interfaces + +STDMETHODIMP CAggDrawSurface::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) +{ + ASSERT(m_pDirectDrawSurface); + + // Do we have this interface + + if (riid == IID_IDirectDrawSurface) { + return GetInterface((IDirectDrawSurface *)this,ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid,ppv); + } +} + + +STDMETHODIMP CAggDrawSurface::AddAttachedSurface(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->AddAttachedSurface(lpDDSAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::AddOverlayDirtyRect(__in LPRECT lpRect) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->AddOverlayDirtyRect(lpRect); +} + + +STDMETHODIMP CAggDrawSurface::Blt(__in LPRECT lpDestRect, + __in LPDIRECTDRAWSURFACE lpDDSrcSurface, + __in LPRECT lpSrcRect, + DWORD dwFlags, + __in LPDDBLTFX lpDDBltFx) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx); +} + + +STDMETHODIMP CAggDrawSurface::BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->BltBatch(lpDDBltBatch,dwCount,dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::BltFast(DWORD dwX,DWORD dwY, + __in LPDIRECTDRAWSURFACE lpDDSrcSurface, + __in LPRECT lpSrcRect, + DWORD dwTrans) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->BltFast(dwX,dwY,lpDDSrcSurface,lpSrcRect,dwTrans); +} + + +STDMETHODIMP CAggDrawSurface::DeleteAttachedSurface(DWORD dwFlags, + __in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->DeleteAttachedSurface(dwFlags,lpDDSAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::EnumAttachedSurfaces(__in LPVOID lpContext, + __in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->EnumAttachedSurfaces(lpContext,lpEnumSurfacesCallback); +} + + +STDMETHODIMP CAggDrawSurface::EnumOverlayZOrders(DWORD dwFlags, + __in LPVOID lpContext, + __in LPDDENUMSURFACESCALLBACK lpfnCallback) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->EnumOverlayZOrders(dwFlags,lpContext,lpfnCallback); +} + + +STDMETHODIMP CAggDrawSurface::Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Flip(lpDDSurfaceTargetOverride,dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetAttachedSurface(__in LPDDSCAPS lpDDSCaps, + __deref_out LPDIRECTDRAWSURFACE *lplpDDAttachedSurface) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetAttachedSurface(lpDDSCaps,lplpDDAttachedSurface); +} + + +STDMETHODIMP CAggDrawSurface::GetBltStatus(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetBltStatus(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetCaps(__out LPDDSCAPS lpDDSCaps) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetCaps(lpDDSCaps); +} + + +STDMETHODIMP CAggDrawSurface::GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetClipper(lplpDDClipper); +} + + +STDMETHODIMP CAggDrawSurface::GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetColorKey(dwFlags,lpDDColorKey); +} + + +STDMETHODIMP CAggDrawSurface::GetDC(__out HDC *lphDC) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetDC(lphDC); +} + + +STDMETHODIMP CAggDrawSurface::GetFlipStatus(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetFlipStatus(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::GetOverlayPosition(__out LPLONG lpdwX,__out LPLONG lpdwY) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetOverlayPosition(lpdwX,lpdwY); +} + + +STDMETHODIMP CAggDrawSurface::GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetPalette(lplpDDPalette); +} + + +STDMETHODIMP CAggDrawSurface::GetPixelFormat(__out LPDDPIXELFORMAT lpDDPixelFormat) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->GetPixelFormat(lpDDPixelFormat); +} + + +// A bit of a warning here: Our media samples in DirectShow aggregate on +// IDirectDraw and IDirectDrawSurface (ie are available through IMediaSample +// by QueryInterface). Unfortunately the underlying DirectDraw code cannot +// be aggregated so we have to use these classes. The snag is that when we +// call a different surface and pass in this interface as perhaps the source +// surface the call will fail because DirectDraw dereferences the pointer to +// get at its private data structures. Therefore we supply this workaround to give +// access to the real IDirectDraw surface. A filter can call GetSurfaceDesc +// and we will fill in the lpSurface pointer with the real underlying surface + +STDMETHODIMP CAggDrawSurface::GetSurfaceDesc(__out LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDrawSurface); + + // First call down to the underlying DirectDraw + + HRESULT hr = m_pDirectDrawSurface->GetSurfaceDesc(lpDDSurfaceDesc); + if (FAILED(hr)) { + return hr; + } + + // Store the real DirectDrawSurface interface + lpDDSurfaceDesc->lpSurface = m_pDirectDrawSurface; + return hr; +} + + +STDMETHODIMP CAggDrawSurface::Initialize(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Initialize(lpDD,lpDDSurfaceDesc); +} + + +STDMETHODIMP CAggDrawSurface::IsLost() +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->IsLost(); +} + + +STDMETHODIMP CAggDrawSurface::Lock(__in LPRECT lpDestRect, + __inout LPDDSURFACEDESC lpDDSurfaceDesc, + DWORD dwFlags, + HANDLE hEvent) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Lock(lpDestRect,lpDDSurfaceDesc,dwFlags,hEvent); +} + + +STDMETHODIMP CAggDrawSurface::ReleaseDC(HDC hDC) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->ReleaseDC(hDC); +} + + +STDMETHODIMP CAggDrawSurface::Restore() +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Restore(); +} + + +STDMETHODIMP CAggDrawSurface::SetClipper(__in LPDIRECTDRAWCLIPPER lpDDClipper) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetClipper(lpDDClipper); +} + + +STDMETHODIMP CAggDrawSurface::SetColorKey(DWORD dwFlags,__in LPDDCOLORKEY lpDDColorKey) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetColorKey(dwFlags,lpDDColorKey); +} + + +STDMETHODIMP CAggDrawSurface::SetOverlayPosition(LONG dwX,LONG dwY) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetOverlayPosition(dwX,dwY); +} + + +STDMETHODIMP CAggDrawSurface::SetPalette(__in LPDIRECTDRAWPALETTE lpDDPalette) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->SetPalette(lpDDPalette); +} + + +STDMETHODIMP CAggDrawSurface::Unlock(__in LPVOID lpSurfaceData) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->Unlock(lpSurfaceData); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlay(__in LPRECT lpSrcRect, + __in LPDIRECTDRAWSURFACE lpDDDestSurface, + __in LPRECT lpDestRect, + DWORD dwFlags, + __in LPDDOVERLAYFX lpDDOverlayFX) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlay(lpSrcRect,lpDDDestSurface,lpDestRect,dwFlags,lpDDOverlayFX); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlayDisplay(DWORD dwFlags) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlayDisplay(dwFlags); +} + + +STDMETHODIMP CAggDrawSurface::UpdateOverlayZOrder(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSReference) +{ + ASSERT(m_pDirectDrawSurface); + return m_pDirectDrawSurface->UpdateOverlayZOrder(dwFlags,lpDDSReference); +} + + +// DirectShow must work on multiple platforms. In particular, it also runs on +// Windows NT 3.51 which does not have DirectDraw capabilities. The filters +// cannot therefore link statically to the DirectDraw library. To make their +// lives that little bit easier we provide this class that manages loading +// and unloading the library and creating the initial IDirectDraw interface + +CLoadDirectDraw::CLoadDirectDraw() : + m_pDirectDraw(NULL), + m_hDirectDraw(NULL) +{ +} + + +// Destructor forces unload + +CLoadDirectDraw::~CLoadDirectDraw() +{ + ReleaseDirectDraw(); + + if (m_hDirectDraw) { + NOTE("Unloading library"); + FreeLibrary(m_hDirectDraw); + } +} + + +// We can't be sure that DirectDraw is always available so we can't statically +// link to the library. Therefore we load the library, get the function entry +// point addresses and call them to create the driver objects. We return S_OK +// if we manage to load DirectDraw correctly otherwise we return E_NOINTERFACE +// We initialise a DirectDraw instance by explicitely loading the library and +// calling GetProcAddress on the DirectDrawCreate entry point that it exports + +// On a multi monitor system, we can get the DirectDraw object for any +// monitor (device) with the optional szDevice parameter + +HRESULT CLoadDirectDraw::LoadDirectDraw(__in LPSTR szDevice) +{ + PDRAWCREATE pDrawCreate; + PDRAWENUM pDrawEnum; + LPDIRECTDRAWENUMERATEEXA pDrawEnumEx; + + NOTE("Entering DoLoadDirectDraw"); + + // Is DirectDraw already loaded + + if (m_pDirectDraw) { + NOTE("Already loaded"); + ASSERT(m_hDirectDraw); + return NOERROR; + } + + // Make sure the library is available + + if(!m_hDirectDraw) + { + UINT ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX); + m_hDirectDraw = LoadLibrary(TEXT("ddraw.dll")); + SetErrorMode(ErrorMode); + + if (m_hDirectDraw == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't load ddraw.dll"))); + NOTE("No library"); + return E_NOINTERFACE; + } + } + + // Get the DLL address for the creator function + + pDrawCreate = (PDRAWCREATE)GetProcAddress(m_hDirectDraw,"DirectDrawCreate"); + // force ANSI, we assume it + pDrawEnum = (PDRAWENUM)GetProcAddress(m_hDirectDraw,"DirectDrawEnumerateA"); + pDrawEnumEx = (LPDIRECTDRAWENUMERATEEXA)GetProcAddress(m_hDirectDraw, + "DirectDrawEnumerateExA"); + + // We don't NEED DirectDrawEnumerateEx, that's just for multimon stuff + if (pDrawCreate == NULL || pDrawEnum == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't get functions: Create=%x Enum=%x"), + pDrawCreate, pDrawEnum)); + NOTE("No entry point"); + ReleaseDirectDraw(); + return E_NOINTERFACE; + } + + DbgLog((LOG_TRACE,3,TEXT("Creating DDraw for device %s"), + szDevice ? szDevice : "")); + + // Create a DirectDraw display provider for this device, using the fancy + // multimon-aware version, if it exists + if (pDrawEnumEx) + m_pDirectDraw = DirectDrawCreateFromDeviceEx(szDevice, pDrawCreate, + pDrawEnumEx); + else + m_pDirectDraw = DirectDrawCreateFromDevice(szDevice, pDrawCreate, + pDrawEnum); + + if (m_pDirectDraw == NULL) { + DbgLog((LOG_ERROR,1,TEXT("Can't create DDraw"))); + NOTE("No instance"); + ReleaseDirectDraw(); + return E_NOINTERFACE; + } + return NOERROR; +} + + +// Called to release any DirectDraw provider we previously loaded. We may be +// called at any time especially when something goes horribly wrong and when +// we need to clean up before returning so we can't guarantee that all state +// variables are consistent so free only those really allocated allocated +// This should only be called once all reference counts have been released + +void CLoadDirectDraw::ReleaseDirectDraw() +{ + NOTE("Releasing DirectDraw driver"); + + // Release any DirectDraw provider interface + + if (m_pDirectDraw) { + NOTE("Releasing instance"); + m_pDirectDraw->Release(); + m_pDirectDraw = NULL; + } + +} + + +// Return NOERROR (S_OK) if DirectDraw has been loaded by this object + +HRESULT CLoadDirectDraw::IsDirectDrawLoaded() +{ + NOTE("Entering IsDirectDrawLoaded"); + + if (m_pDirectDraw == NULL) { + NOTE("DirectDraw not loaded"); + return S_FALSE; + } + return NOERROR; +} + + +// Return the IDirectDraw interface we look after + +LPDIRECTDRAW CLoadDirectDraw::GetDirectDraw() +{ + NOTE("Entering GetDirectDraw"); + + if (m_pDirectDraw == NULL) { + NOTE("No DirectDraw"); + return NULL; + } + + NOTE("Returning DirectDraw"); + m_pDirectDraw->AddRef(); + return m_pDirectDraw; +} + + +// Are we running on Direct Draw version 1? We need to find out as +// we rely on specific bug fixes in DirectDraw 2 for fullscreen playback. To +// find out, we simply see if it supports IDirectDraw2. Only version 2 and +// higher support this. + +BOOL CLoadDirectDraw::IsDirectDrawVersion1() +{ + + if (m_pDirectDraw == NULL) + return FALSE; + + IDirectDraw2 *p = NULL; + HRESULT hr = m_pDirectDraw->QueryInterface(IID_IDirectDraw2, (void **)&p); + if (p) + p->Release(); + if (hr == NOERROR) { + DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 2 or greater"))); + return FALSE; + } else { + DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 1"))); + return TRUE; + } +} diff --git a/src/thirdparty/BaseClasses/videoctl.h b/src/thirdparty/BaseClasses/videoctl.h index a9713202675..aa74d79e872 100644 --- a/src/thirdparty/BaseClasses/videoctl.h +++ b/src/thirdparty/BaseClasses/videoctl.h @@ -1,168 +1,168 @@ -//------------------------------------------------------------------------------ -// File: VideoCtl.h -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __VIDEOCTL__ -#define __VIDEOCTL__ - -// These help with property page implementations. The first can be used to -// load any string from a resource file. The buffer to load into is passed -// as an input parameter. The same buffer is the return value if the string -// was found otherwise it returns TEXT(""). The GetDialogSize is passed the -// resource ID of a dialog box and returns the size of it in screen pixels - -#define STR_MAX_LENGTH 256 -LPCTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID); - -#ifdef UNICODE -#define WideStringFromResource StringFromResource -LPCSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR pBuffer, int iResourceID); -#else -LPCWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR pBuffer, int iResourceID); -#endif - - -BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier - DLGPROC pDlgProc, // Pointer to dialog procedure - LPARAM lParam, // Any user data wanted in pDlgProc - __out SIZE *pResult);// Returns the size of dialog box - -// Class that aggregates an IDirectDraw interface - -class CAggDirectDraw : public IDirectDraw, public CUnknown -{ -protected: - - LPDIRECTDRAW m_pDirectDraw; - -public: - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); - - // Constructor and destructor - - CAggDirectDraw(__in_opt LPCTSTR pName,__inout_opt LPUNKNOWN pUnk) : - CUnknown(pName,pUnk), - m_pDirectDraw(NULL) { }; - - virtual ~CAggDirectDraw() { }; - - // Set the object we should be aggregating - void SetDirectDraw(__inout LPDIRECTDRAW pDirectDraw) { - m_pDirectDraw = pDirectDraw; - } - - // IDirectDraw methods - - STDMETHODIMP Compact(); - STDMETHODIMP CreateClipper(DWORD dwFlags,__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper,__inout_opt IUnknown *pUnkOuter); - STDMETHODIMP CreatePalette(DWORD dwFlags,__in LPPALETTEENTRY lpColorTable,__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette,__inout_opt IUnknown *pUnkOuter); - STDMETHODIMP CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc,__deref_out LPDIRECTDRAWSURFACE *lplpDDSurface,__inout_opt IUnknown *pUnkOuter); - STDMETHODIMP DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface,__deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface); - STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,__in LPDDSURFACEDESC lplpDDSurfaceDescList,__in LPVOID lpContext,__in LPDDENUMMODESCALLBACK lpEnumCallback); - STDMETHODIMP EnumSurfaces(DWORD dwFlags,__in LPDDSURFACEDESC lpDDSD,__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpEnumCallback); - STDMETHODIMP FlipToGDISurface(); - STDMETHODIMP GetCaps(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps); - STDMETHODIMP GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc); - STDMETHODIMP GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes); - STDMETHODIMP GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface); - STDMETHODIMP GetMonitorFrequency(__out LPDWORD lpdwFrequency); - STDMETHODIMP GetScanLine(__out LPDWORD lpdwScanLine); - STDMETHODIMP GetVerticalBlankStatus(__out LPBOOL lpblsInVB); - STDMETHODIMP Initialize(__in GUID *lpGUID); - STDMETHODIMP RestoreDisplayMode(); - STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags); - STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp); - STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent); -}; - - -// Class that aggregates an IDirectDrawSurface interface - -class CAggDrawSurface : public IDirectDrawSurface, public CUnknown -{ -protected: - - LPDIRECTDRAWSURFACE m_pDirectDrawSurface; - -public: - - DECLARE_IUNKNOWN - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); - - // Constructor and destructor - - CAggDrawSurface(__in_opt LPCTSTR pName,__inout_opt LPUNKNOWN pUnk) : - CUnknown(pName,pUnk), - m_pDirectDrawSurface(NULL) { }; - - virtual ~CAggDrawSurface() { }; - - // Set the object we should be aggregating - void SetDirectDrawSurface(__inout LPDIRECTDRAWSURFACE pDirectDrawSurface) { - m_pDirectDrawSurface = pDirectDrawSurface; - } - - // IDirectDrawSurface methods - - STDMETHODIMP AddAttachedSurface(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface); - STDMETHODIMP AddOverlayDirtyRect(__in LPRECT lpRect); - STDMETHODIMP Blt(__in LPRECT lpDestRect,__in LPDIRECTDRAWSURFACE lpDDSrcSurface,__in LPRECT lpSrcRect,DWORD dwFlags,__in LPDDBLTFX lpDDBltFx); - STDMETHODIMP BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags); - STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,__in LPDIRECTDRAWSURFACE lpDDSrcSurface,__in LPRECT lpSrcRect,DWORD dwTrans); - STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface); - STDMETHODIMP EnumAttachedSurfaces(__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback); - STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpfnCallback); - STDMETHODIMP Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags); - STDMETHODIMP GetAttachedSurface(__in LPDDSCAPS lpDDSCaps,__deref_out LPDIRECTDRAWSURFACE *lplpDDAttachedSurface); - STDMETHODIMP GetBltStatus(DWORD dwFlags); - STDMETHODIMP GetCaps(__out LPDDSCAPS lpDDSCaps); - STDMETHODIMP GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper); - STDMETHODIMP GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey); - STDMETHODIMP GetDC(__out HDC *lphDC); - STDMETHODIMP GetFlipStatus(DWORD dwFlags); - STDMETHODIMP GetOverlayPosition(__out LPLONG lpdwX,__out LPLONG lpdwY); - STDMETHODIMP GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette); - STDMETHODIMP GetPixelFormat(__out LPDDPIXELFORMAT lpDDPixelFormat); - STDMETHODIMP GetSurfaceDesc(__out LPDDSURFACEDESC lpDDSurfaceDesc); - STDMETHODIMP Initialize(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc); - STDMETHODIMP IsLost(); - STDMETHODIMP Lock(__in LPRECT lpDestRect,__inout LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent); - STDMETHODIMP ReleaseDC(HDC hDC); - STDMETHODIMP Restore(); - STDMETHODIMP SetClipper(__in LPDIRECTDRAWCLIPPER lpDDClipper); - STDMETHODIMP SetColorKey(DWORD dwFlags,__in LPDDCOLORKEY lpDDColorKey); - STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY); - STDMETHODIMP SetPalette(__in LPDIRECTDRAWPALETTE lpDDPalette); - STDMETHODIMP Unlock(__in LPVOID lpSurfaceData); - STDMETHODIMP UpdateOverlay(__in LPRECT lpSrcRect,__in LPDIRECTDRAWSURFACE lpDDDestSurface,__in LPRECT lpDestRect,DWORD dwFlags,__in LPDDOVERLAYFX lpDDOverlayFX); - STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags); - STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSReference); -}; - - -class CLoadDirectDraw -{ - LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance - HINSTANCE m_hDirectDraw; // Handle to the loaded library - -public: - - CLoadDirectDraw(); - ~CLoadDirectDraw(); - - HRESULT LoadDirectDraw(__in LPSTR szDevice); - void ReleaseDirectDraw(); - HRESULT IsDirectDrawLoaded(); - LPDIRECTDRAW GetDirectDraw(); - BOOL IsDirectDrawVersion1(); -}; - -#endif // __VIDEOCTL__ - +//------------------------------------------------------------------------------ +// File: VideoCtl.h +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __VIDEOCTL__ +#define __VIDEOCTL__ + +// These help with property page implementations. The first can be used to +// load any string from a resource file. The buffer to load into is passed +// as an input parameter. The same buffer is the return value if the string +// was found otherwise it returns TEXT(""). The GetDialogSize is passed the +// resource ID of a dialog box and returns the size of it in screen pixels + +#define STR_MAX_LENGTH 256 +LPCTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID); + +#ifdef UNICODE +#define WideStringFromResource StringFromResource +LPCSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR pBuffer, int iResourceID); +#else +LPCWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR pBuffer, int iResourceID); +#endif + + +BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier + DLGPROC pDlgProc, // Pointer to dialog procedure + LPARAM lParam, // Any user data wanted in pDlgProc + __out SIZE *pResult);// Returns the size of dialog box + +// Class that aggregates an IDirectDraw interface + +class CAggDirectDraw : public IDirectDraw, public CUnknown +{ +protected: + + LPDIRECTDRAW m_pDirectDraw; + +public: + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); + + // Constructor and destructor + + CAggDirectDraw(__in_opt LPCTSTR pName,__inout_opt LPUNKNOWN pUnk) : + CUnknown(pName,pUnk), + m_pDirectDraw(NULL) { }; + + virtual ~CAggDirectDraw() { }; + + // Set the object we should be aggregating + void SetDirectDraw(__inout LPDIRECTDRAW pDirectDraw) { + m_pDirectDraw = pDirectDraw; + } + + // IDirectDraw methods + + STDMETHODIMP Compact(); + STDMETHODIMP CreateClipper(DWORD dwFlags,__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper,__inout_opt IUnknown *pUnkOuter); + STDMETHODIMP CreatePalette(DWORD dwFlags,__in LPPALETTEENTRY lpColorTable,__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette,__inout_opt IUnknown *pUnkOuter); + STDMETHODIMP CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc,__deref_out LPDIRECTDRAWSURFACE *lplpDDSurface,__inout_opt IUnknown *pUnkOuter); + STDMETHODIMP DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface,__deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface); + STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,__in LPDDSURFACEDESC lplpDDSurfaceDescList,__in LPVOID lpContext,__in LPDDENUMMODESCALLBACK lpEnumCallback); + STDMETHODIMP EnumSurfaces(DWORD dwFlags,__in LPDDSURFACEDESC lpDDSD,__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpEnumCallback); + STDMETHODIMP FlipToGDISurface(); + STDMETHODIMP GetCaps(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps); + STDMETHODIMP GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes); + STDMETHODIMP GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface); + STDMETHODIMP GetMonitorFrequency(__out LPDWORD lpdwFrequency); + STDMETHODIMP GetScanLine(__out LPDWORD lpdwScanLine); + STDMETHODIMP GetVerticalBlankStatus(__out LPBOOL lpblsInVB); + STDMETHODIMP Initialize(__in GUID *lpGUID); + STDMETHODIMP RestoreDisplayMode(); + STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags); + STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp); + STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent); +}; + + +// Class that aggregates an IDirectDrawSurface interface + +class CAggDrawSurface : public IDirectDrawSurface, public CUnknown +{ +protected: + + LPDIRECTDRAWSURFACE m_pDirectDrawSurface; + +public: + + DECLARE_IUNKNOWN + STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); + + // Constructor and destructor + + CAggDrawSurface(__in_opt LPCTSTR pName,__inout_opt LPUNKNOWN pUnk) : + CUnknown(pName,pUnk), + m_pDirectDrawSurface(NULL) { }; + + virtual ~CAggDrawSurface() { }; + + // Set the object we should be aggregating + void SetDirectDrawSurface(__inout LPDIRECTDRAWSURFACE pDirectDrawSurface) { + m_pDirectDrawSurface = pDirectDrawSurface; + } + + // IDirectDrawSurface methods + + STDMETHODIMP AddAttachedSurface(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface); + STDMETHODIMP AddOverlayDirtyRect(__in LPRECT lpRect); + STDMETHODIMP Blt(__in LPRECT lpDestRect,__in LPDIRECTDRAWSURFACE lpDDSrcSurface,__in LPRECT lpSrcRect,DWORD dwFlags,__in LPDDBLTFX lpDDBltFx); + STDMETHODIMP BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags); + STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,__in LPDIRECTDRAWSURFACE lpDDSrcSurface,__in LPRECT lpSrcRect,DWORD dwTrans); + STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface); + STDMETHODIMP EnumAttachedSurfaces(__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback); + STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,__in LPVOID lpContext,__in LPDDENUMSURFACESCALLBACK lpfnCallback); + STDMETHODIMP Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags); + STDMETHODIMP GetAttachedSurface(__in LPDDSCAPS lpDDSCaps,__deref_out LPDIRECTDRAWSURFACE *lplpDDAttachedSurface); + STDMETHODIMP GetBltStatus(DWORD dwFlags); + STDMETHODIMP GetCaps(__out LPDDSCAPS lpDDSCaps); + STDMETHODIMP GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper); + STDMETHODIMP GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey); + STDMETHODIMP GetDC(__out HDC *lphDC); + STDMETHODIMP GetFlipStatus(DWORD dwFlags); + STDMETHODIMP GetOverlayPosition(__out LPLONG lpdwX,__out LPLONG lpdwY); + STDMETHODIMP GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette); + STDMETHODIMP GetPixelFormat(__out LPDDPIXELFORMAT lpDDPixelFormat); + STDMETHODIMP GetSurfaceDesc(__out LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP Initialize(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc); + STDMETHODIMP IsLost(); + STDMETHODIMP Lock(__in LPRECT lpDestRect,__inout LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent); + STDMETHODIMP ReleaseDC(HDC hDC); + STDMETHODIMP Restore(); + STDMETHODIMP SetClipper(__in LPDIRECTDRAWCLIPPER lpDDClipper); + STDMETHODIMP SetColorKey(DWORD dwFlags,__in LPDDCOLORKEY lpDDColorKey); + STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY); + STDMETHODIMP SetPalette(__in LPDIRECTDRAWPALETTE lpDDPalette); + STDMETHODIMP Unlock(__in LPVOID lpSurfaceData); + STDMETHODIMP UpdateOverlay(__in LPRECT lpSrcRect,__in LPDIRECTDRAWSURFACE lpDDDestSurface,__in LPRECT lpDestRect,DWORD dwFlags,__in LPDDOVERLAYFX lpDDOverlayFX); + STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags); + STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,__in LPDIRECTDRAWSURFACE lpDDSReference); +}; + + +class CLoadDirectDraw +{ + LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance + HINSTANCE m_hDirectDraw; // Handle to the loaded library + +public: + + CLoadDirectDraw(); + ~CLoadDirectDraw(); + + HRESULT LoadDirectDraw(__in LPSTR szDevice); + void ReleaseDirectDraw(); + HRESULT IsDirectDrawLoaded(); + LPDIRECTDRAW GetDirectDraw(); + BOOL IsDirectDrawVersion1(); +}; + +#endif // __VIDEOCTL__ + diff --git a/src/thirdparty/BaseClasses/vtrans.cpp b/src/thirdparty/BaseClasses/vtrans.cpp index 28cd234ea1e..e20e4836001 100644 --- a/src/thirdparty/BaseClasses/vtrans.cpp +++ b/src/thirdparty/BaseClasses/vtrans.cpp @@ -1,469 +1,469 @@ -//------------------------------------------------------------------------------ -// File: Vtrans.cpp -// -// Desc: DirectShow base classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include "measure.h" -// #include // now in precomp file streams.h - -CVideoTransformFilter::CVideoTransformFilter - ( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, REFCLSID clsid) - : CTransformFilter(pName, pUnk, clsid) - , m_itrLate(0) - , m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames - , m_nFramesSinceKeyFrame(0) - , m_bSkipping(FALSE) - , m_tDecodeStart(0) - , m_itrAvgDecode(300000) // 30mSec - probably allows skipping - , m_bQualityChanged(FALSE) - , m_nWaitForKey(0) -{ -#ifdef PERF - RegisterPerfId(); -#endif // PERF -} - - -CVideoTransformFilter::~CVideoTransformFilter() -{ - // nothing to do -} - - -// Reset our quality management state - -HRESULT CVideoTransformFilter::StartStreaming() -{ - m_itrLate = 0; - m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames - m_nFramesSinceKeyFrame = 0; - m_bSkipping = FALSE; - m_tDecodeStart = 0; - m_itrAvgDecode = 300000; // 30mSec - probably allows skipping - m_bQualityChanged = FALSE; - m_bSampleSkipped = FALSE; - return NOERROR; -} - - -// Overriden to reset quality management information - -HRESULT CVideoTransformFilter::EndFlush() -{ - { - // Synchronize - CAutoLock lck(&m_csReceive); - - // Reset our stats - // - // Note - we don't want to call derived classes here, - // we only want to reset our internal variables and this - // is a convenient way to do it - CVideoTransformFilter::StartStreaming(); - } - return CTransformFilter::EndFlush(); -} - - -HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) -{ - NotifyEvent(EC_ERRORABORT, hr, 0); - m_pOutput->DeliverEndOfStream(); - return hr; -} - - -// Receive() -// -// Accept a sample from upstream, decide whether to process it -// or drop it. If we process it then get a buffer from the -// allocator of the downstream connection, transform it into the -// new buffer and deliver it to the downstream filter. -// If we decide not to process it then we do not get a buffer. - -// Remember that although this code will notice format changes coming into -// the input pin, it will NOT change its output format if that results -// in the filter needing to make a corresponding output format change. Your -// derived filter will have to take care of that. (eg. a palette change if -// the input and output is an 8 bit format). If the input sample is discarded -// and nothing is sent out for this Receive, please remember to put the format -// change on the first output sample that you actually do send. -// If your filter will produce the same output type even when the input type -// changes, then this base class code will do everything you need. - -HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) -{ - // If the next filter downstream is the video renderer, then it may - // be able to operate in DirectDraw mode which saves copying the data - // and gives higher performance. In that case the buffer which we - // get from GetDeliveryBuffer will be a DirectDraw buffer, and - // drawing into this buffer draws directly onto the display surface. - // This means that any waiting for the correct time to draw occurs - // during GetDeliveryBuffer, and that once the buffer is given to us - // the video renderer will count it in its statistics as a frame drawn. - // This means that any decision to drop the frame must be taken before - // calling GetDeliveryBuffer. - - ASSERT(CritCheckIn(&m_csReceive)); - AM_MEDIA_TYPE *pmtOut, *pmt; -#ifdef _DEBUG - FOURCCMap fccOut; -#endif - HRESULT hr; - ASSERT(pSample); - IMediaSample * pOutSample; - - // If no output pin to deliver to then no point sending us data - ASSERT (m_pOutput != NULL) ; - - // The source filter may dynamically ask us to start transforming from a - // different media type than the one we're using now. If we don't, we'll - // draw garbage. (typically, this is a palette change in the movie, - // but could be something more sinister like the compression type changing, - // or even the video size changing) - -#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource -#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget - - pSample->GetMediaType(&pmt); - if (pmt != NULL && pmt->pbFormat != NULL) { - - // spew some debug output - ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); -#ifdef _DEBUG - fccOut.SetFOURCC(&pmt->subtype); - LONG lCompression = HEADER(pmt->pbFormat)->biCompression; - LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; - LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; - lStride = (lStride + 3) & ~3; - DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); - DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), - fccOut.GetFOURCC(), lCompression, lBitCount)); - DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), - HEADER(pmt->pbFormat)->biHeight, - rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); - DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), - rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, - lStride)); -#endif - - // now switch to using the new format. I am assuming that the - // derived filter will do the right thing when its media type is - // switched and streaming is restarted. - - StopStreaming(); - m_pInput->CurrentMediaType() = *pmt; - DeleteMediaType(pmt); - // if this fails, playback will stop, so signal an error - hr = StartStreaming(); - if (FAILED(hr)) { - return AbortPlayback(hr); - } - } - - // Now that we have noticed any format changes on the input sample, it's - // OK to discard it. - - if (ShouldSkipFrame(pSample)) { - MSR_NOTE(m_idSkip); - m_bSampleSkipped = TRUE; - return NOERROR; - } - - // Set up the output sample - hr = InitializeOutputSample(pSample, &pOutSample); - - if (FAILED(hr)) { - return hr; - } - - m_bSampleSkipped = FALSE; - - // The renderer may ask us to on-the-fly to start transforming to a - // different format. If we don't obey it, we'll draw garbage - -#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource -#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget - - pOutSample->GetMediaType(&pmtOut); - if (pmtOut != NULL && pmtOut->pbFormat != NULL) { - - // spew some debug output - ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); -#ifdef _DEBUG - fccOut.SetFOURCC(&pmtOut->subtype); - LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; - LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; - LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; - lStride = (lStride + 3) & ~3; - DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); - DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), - fccOut.GetFOURCC(), lCompression, lBitCount)); - DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), - HEADER(pmtOut->pbFormat)->biHeight, - rcT.left, rcT.top, rcT.right, rcT.bottom)); - DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), - rcS.left, rcS.top, rcS.right, rcS.bottom, - lStride)); -#endif - - // now switch to using the new format. I am assuming that the - // derived filter will do the right thing when its media type is - // switched and streaming is restarted. - - StopStreaming(); - m_pOutput->CurrentMediaType() = *pmtOut; - DeleteMediaType(pmtOut); - hr = StartStreaming(); - - if (SUCCEEDED(hr)) { - // a new format, means a new empty buffer, so wait for a keyframe - // before passing anything on to the renderer. - // !!! a keyframe may never come, so give up after 30 frames - DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); - m_nWaitForKey = 30; - - // if this fails, playback will stop, so signal an error - } else { - - // Must release the sample before calling AbortPlayback - // because we might be holding the win16 lock or - // ddraw lock - pOutSample->Release(); - AbortPlayback(hr); - return hr; - } - } - - // After a discontinuity, we need to wait for the next key frame - if (pSample->IsDiscontinuity() == S_OK) { - DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); - m_nWaitForKey = 30; - } - - // Start timing the transform (and log it if PERF is defined) - - if (SUCCEEDED(hr)) { - m_tDecodeStart = timeGetTime(); - MSR_START(m_idTransform); - - // have the derived class transform the data - hr = Transform(pSample, pOutSample); - - // Stop the clock (and log it if PERF is defined) - MSR_STOP(m_idTransform); - m_tDecodeStart = timeGetTime()-m_tDecodeStart; - m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); - - // Maybe we're waiting for a keyframe still? - if (m_nWaitForKey) - m_nWaitForKey--; - if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) - m_nWaitForKey = FALSE; - - // if so, then we don't want to pass this on to the renderer - if (m_nWaitForKey && hr == NOERROR) { - DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); - hr = S_FALSE; - } - } - - if (FAILED(hr)) { - DbgLog((LOG_TRACE,1,TEXT("Error from video transform"))); - } else { - // the Transform() function can return S_FALSE to indicate that the - // sample should not be delivered; we only deliver the sample if it's - // really S_OK (same as NOERROR, of course.) - // Try not to return S_FALSE to a direct draw buffer (it's wasteful) - // Try to take the decision earlier - before you get it. - - if (hr == NOERROR) { - hr = m_pOutput->Deliver(pOutSample); - } else { - // S_FALSE returned from Transform is a PRIVATE agreement - // We should return NOERROR from Receive() in this case because returning S_FALSE - // from Receive() means that this is the end of the stream and no more data should - // be sent. - if (S_FALSE == hr) { - - // We must Release() the sample before doing anything - // like calling the filter graph because having the - // sample means we may have the DirectDraw lock - // (== win16 lock on some versions) - pOutSample->Release(); - m_bSampleSkipped = TRUE; - if (!m_bQualityChanged) { - m_bQualityChanged = TRUE; - NotifyEvent(EC_QUALITY_CHANGE,0,0); - } - return NOERROR; - } - } - } - - // release the output buffer. If the connected pin still needs it, - // it will have addrefed it itself. - pOutSample->Release(); - ASSERT(CritCheckIn(&m_csReceive)); - - return hr; -} - - - -BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) -{ - REFERENCE_TIME trStart, trStopAt; - HRESULT hr = pIn->GetTime(&trStart, &trStopAt); - - // Don't skip frames with no timestamps - if (hr != S_OK) - return FALSE; - - int itrFrame = (int)(trStopAt - trStart); // frame duration - - if(S_OK==pIn->IsSyncPoint()) { - MSR_INTEGER(m_idFrameType, 1); - if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) { - // record the max - m_nKeyFramePeriod = m_nFramesSinceKeyFrame; - } - m_nFramesSinceKeyFrame = 0; - m_bSkipping = FALSE; - } else { - MSR_INTEGER(m_idFrameType, 2); - if ( m_nFramesSinceKeyFrame>m_nKeyFramePeriod - && m_nKeyFramePeriod>0 - ) { - // We haven't seen the key frame yet, but we were clearly being - // overoptimistic about how frequent they are. - m_nKeyFramePeriod = m_nFramesSinceKeyFrame; - } - } - - - // Whatever we might otherwise decide, - // if we are taking only a small fraction of the required frame time to decode - // then any quality problems are actually coming from somewhere else. - // Could be a net problem at the source for instance. In this case there's - // no point in us skipping frames here. - if (m_itrAvgDecode*4>itrFrame) { - - // Don't skip unless we are at least a whole frame late. - // (We would skip B frames if more than 1/2 frame late, but they're safe). - if ( m_itrLate > itrFrame ) { - - // Don't skip unless the anticipated key frame would be no more than - // 1 frame early. If the renderer has not been waiting (we *guess* - // it hasn't because we're late) then it will allow frames to be - // played early by up to a frame. - - // Let T = Stream time from now to anticipated next key frame - // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame) - // So we skip if T - Late < one frame i.e. - // (duration) * (freq - FramesSince) - Late < duration - // or (duration) * (freq - FramesSince - 1) < Late - - // We don't dare skip until we have seen some key frames and have - // some idea how often they occur and they are reasonably frequent. - if (m_nKeyFramePeriod>0) { - // It would be crazy - but we could have a stream with key frames - // a very long way apart - and if they are further than about - // 3.5 minutes apart then we could get arithmetic overflow in - // reference time units. Therefore we switch to mSec at this point - int it = (itrFrame/10000) - * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1); - MSR_INTEGER(m_idTimeTillKey, it); - - // For debug - might want to see the details - dump them as scratch pad -#ifdef VTRANSPERF - MSR_INTEGER(0, itrFrame); - MSR_INTEGER(0, m_nFramesSinceKeyFrame); - MSR_INTEGER(0, m_nKeyFramePeriod); -#endif - if (m_itrLate/10000 > it) { - m_bSkipping = TRUE; - // Now we are committed. Once we start skipping, we - // cannot stop until we hit a key frame. - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777770); // not near enough to next key -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777771); // Next key not predictable -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777772); // Less than one frame late - MSR_INTEGER(0, m_itrLate); - MSR_INTEGER(0, itrFrame); -#endif - } - } else { -#ifdef VTRANSPERF - MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping - MSR_INTEGER(0, m_itrAvgDecode); - MSR_INTEGER(0, itrFrame); -#endif - } - - ++m_nFramesSinceKeyFrame; - - if (m_bSkipping) { - // We will count down the lateness as we skip each frame. - // We re-assess each frame. The key frame might not arrive when expected. - // We reset m_itrLate if we get a new Quality message, but actually that's - // not likely because we're not sending frames on to the Renderer. In - // fact if we DID get another one it would mean that there's a long - // pipe between us and the renderer and we might need an altogether - // better strategy to avoid hunting! - m_itrLate = m_itrLate - itrFrame; - } - - MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are - if (m_bSkipping) { - if (!m_bQualityChanged) { - m_bQualityChanged = TRUE; - NotifyEvent(EC_QUALITY_CHANGE,0,0); - } - } - return m_bSkipping; -} - - -HRESULT CVideoTransformFilter::AlterQuality(Quality q) -{ - // to reduce the amount of 64 bit arithmetic, m_itrLate is an int. - // +, -, >, == etc are not too bad, but * and / are painful. - if (m_itrLate>300000000) { - // Avoid overflow and silliness - more than 30 secs late is already silly - m_itrLate = 300000000; - } else { - m_itrLate = (int)q.Late; - } - // We ignore the other fields - - // We're actually not very good at handling this. In non-direct draw mode - // most of the time can be spent in the renderer which can skip any frame. - // In that case we'd rather the renderer handled things. - // Nevertheless we will keep an eye on it and if we really start getting - // a very long way behind then we will actually skip - but we'll still tell - // the renderer (or whoever is downstream) that they should handle quality. - - return E_FAIL; // Tell the renderer to do his thing. - -} - - - -// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4 -#pragma warning(disable:4514) - +//------------------------------------------------------------------------------ +// File: Vtrans.cpp +// +// Desc: DirectShow base classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include "measure.h" +// #include // now in precomp file streams.h + +CVideoTransformFilter::CVideoTransformFilter + ( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, REFCLSID clsid) + : CTransformFilter(pName, pUnk, clsid) + , m_itrLate(0) + , m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames + , m_nFramesSinceKeyFrame(0) + , m_bSkipping(FALSE) + , m_tDecodeStart(0) + , m_itrAvgDecode(300000) // 30mSec - probably allows skipping + , m_bQualityChanged(FALSE) + , m_nWaitForKey(0) +{ +#ifdef PERF + RegisterPerfId(); +#endif // PERF +} + + +CVideoTransformFilter::~CVideoTransformFilter() +{ + // nothing to do +} + + +// Reset our quality management state + +HRESULT CVideoTransformFilter::StartStreaming() +{ + m_itrLate = 0; + m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames + m_nFramesSinceKeyFrame = 0; + m_bSkipping = FALSE; + m_tDecodeStart = 0; + m_itrAvgDecode = 300000; // 30mSec - probably allows skipping + m_bQualityChanged = FALSE; + m_bSampleSkipped = FALSE; + return NOERROR; +} + + +// Overriden to reset quality management information + +HRESULT CVideoTransformFilter::EndFlush() +{ + { + // Synchronize + CAutoLock lck(&m_csReceive); + + // Reset our stats + // + // Note - we don't want to call derived classes here, + // we only want to reset our internal variables and this + // is a convenient way to do it + CVideoTransformFilter::StartStreaming(); + } + return CTransformFilter::EndFlush(); +} + + +HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) +{ + NotifyEvent(EC_ERRORABORT, hr, 0); + m_pOutput->DeliverEndOfStream(); + return hr; +} + + +// Receive() +// +// Accept a sample from upstream, decide whether to process it +// or drop it. If we process it then get a buffer from the +// allocator of the downstream connection, transform it into the +// new buffer and deliver it to the downstream filter. +// If we decide not to process it then we do not get a buffer. + +// Remember that although this code will notice format changes coming into +// the input pin, it will NOT change its output format if that results +// in the filter needing to make a corresponding output format change. Your +// derived filter will have to take care of that. (eg. a palette change if +// the input and output is an 8 bit format). If the input sample is discarded +// and nothing is sent out for this Receive, please remember to put the format +// change on the first output sample that you actually do send. +// If your filter will produce the same output type even when the input type +// changes, then this base class code will do everything you need. + +HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) +{ + // If the next filter downstream is the video renderer, then it may + // be able to operate in DirectDraw mode which saves copying the data + // and gives higher performance. In that case the buffer which we + // get from GetDeliveryBuffer will be a DirectDraw buffer, and + // drawing into this buffer draws directly onto the display surface. + // This means that any waiting for the correct time to draw occurs + // during GetDeliveryBuffer, and that once the buffer is given to us + // the video renderer will count it in its statistics as a frame drawn. + // This means that any decision to drop the frame must be taken before + // calling GetDeliveryBuffer. + + ASSERT(CritCheckIn(&m_csReceive)); + AM_MEDIA_TYPE *pmtOut, *pmt; +#ifdef _DEBUG + FOURCCMap fccOut; +#endif + HRESULT hr; + ASSERT(pSample); + IMediaSample * pOutSample; + + // If no output pin to deliver to then no point sending us data + ASSERT (m_pOutput != NULL) ; + + // The source filter may dynamically ask us to start transforming from a + // different media type than the one we're using now. If we don't, we'll + // draw garbage. (typically, this is a palette change in the movie, + // but could be something more sinister like the compression type changing, + // or even the video size changing) + +#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource +#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget + + pSample->GetMediaType(&pmt); + if (pmt != NULL && pmt->pbFormat != NULL) { + + // spew some debug output + ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL)); +#ifdef _DEBUG + fccOut.SetFOURCC(&pmt->subtype); + LONG lCompression = HEADER(pmt->pbFormat)->biCompression; + LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount; + LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8; + lStride = (lStride + 3) & ~3; + DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to"))); + DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), + fccOut.GetFOURCC(), lCompression, lBitCount)); + DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), + HEADER(pmt->pbFormat)->biHeight, + rcT1.left, rcT1.top, rcT1.right, rcT1.bottom)); + DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), + rcS1.left, rcS1.top, rcS1.right, rcS1.bottom, + lStride)); +#endif + + // now switch to using the new format. I am assuming that the + // derived filter will do the right thing when its media type is + // switched and streaming is restarted. + + StopStreaming(); + m_pInput->CurrentMediaType() = *pmt; + DeleteMediaType(pmt); + // if this fails, playback will stop, so signal an error + hr = StartStreaming(); + if (FAILED(hr)) { + return AbortPlayback(hr); + } + } + + // Now that we have noticed any format changes on the input sample, it's + // OK to discard it. + + if (ShouldSkipFrame(pSample)) { + MSR_NOTE(m_idSkip); + m_bSampleSkipped = TRUE; + return NOERROR; + } + + // Set up the output sample + hr = InitializeOutputSample(pSample, &pOutSample); + + if (FAILED(hr)) { + return hr; + } + + m_bSampleSkipped = FALSE; + + // The renderer may ask us to on-the-fly to start transforming to a + // different format. If we don't obey it, we'll draw garbage + +#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource +#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget + + pOutSample->GetMediaType(&pmtOut); + if (pmtOut != NULL && pmtOut->pbFormat != NULL) { + + // spew some debug output + ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL)); +#ifdef _DEBUG + fccOut.SetFOURCC(&pmtOut->subtype); + LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression; + LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount; + LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8; + lStride = (lStride + 3) & ~3; + DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to"))); + DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"), + fccOut.GetFOURCC(), lCompression, lBitCount)); + DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"), + HEADER(pmtOut->pbFormat)->biHeight, + rcT.left, rcT.top, rcT.right, rcT.bottom)); + DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"), + rcS.left, rcS.top, rcS.right, rcS.bottom, + lStride)); +#endif + + // now switch to using the new format. I am assuming that the + // derived filter will do the right thing when its media type is + // switched and streaming is restarted. + + StopStreaming(); + m_pOutput->CurrentMediaType() = *pmtOut; + DeleteMediaType(pmtOut); + hr = StartStreaming(); + + if (SUCCEEDED(hr)) { + // a new format, means a new empty buffer, so wait for a keyframe + // before passing anything on to the renderer. + // !!! a keyframe may never come, so give up after 30 frames + DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe"))); + m_nWaitForKey = 30; + + // if this fails, playback will stop, so signal an error + } else { + + // Must release the sample before calling AbortPlayback + // because we might be holding the win16 lock or + // ddraw lock + pOutSample->Release(); + AbortPlayback(hr); + return hr; + } + } + + // After a discontinuity, we need to wait for the next key frame + if (pSample->IsDiscontinuity() == S_OK) { + DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe"))); + m_nWaitForKey = 30; + } + + // Start timing the transform (and log it if PERF is defined) + + if (SUCCEEDED(hr)) { + m_tDecodeStart = timeGetTime(); + MSR_START(m_idTransform); + + // have the derived class transform the data + hr = Transform(pSample, pOutSample); + + // Stop the clock (and log it if PERF is defined) + MSR_STOP(m_idTransform); + m_tDecodeStart = timeGetTime()-m_tDecodeStart; + m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16); + + // Maybe we're waiting for a keyframe still? + if (m_nWaitForKey) + m_nWaitForKey--; + if (m_nWaitForKey && pSample->IsSyncPoint() == S_OK) + m_nWaitForKey = FALSE; + + // if so, then we don't want to pass this on to the renderer + if (m_nWaitForKey && hr == NOERROR) { + DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe"))); + hr = S_FALSE; + } + } + + if (FAILED(hr)) { + DbgLog((LOG_TRACE,1,TEXT("Error from video transform"))); + } else { + // the Transform() function can return S_FALSE to indicate that the + // sample should not be delivered; we only deliver the sample if it's + // really S_OK (same as NOERROR, of course.) + // Try not to return S_FALSE to a direct draw buffer (it's wasteful) + // Try to take the decision earlier - before you get it. + + if (hr == NOERROR) { + hr = m_pOutput->Deliver(pOutSample); + } else { + // S_FALSE returned from Transform is a PRIVATE agreement + // We should return NOERROR from Receive() in this case because returning S_FALSE + // from Receive() means that this is the end of the stream and no more data should + // be sent. + if (S_FALSE == hr) { + + // We must Release() the sample before doing anything + // like calling the filter graph because having the + // sample means we may have the DirectDraw lock + // (== win16 lock on some versions) + pOutSample->Release(); + m_bSampleSkipped = TRUE; + if (!m_bQualityChanged) { + m_bQualityChanged = TRUE; + NotifyEvent(EC_QUALITY_CHANGE,0,0); + } + return NOERROR; + } + } + } + + // release the output buffer. If the connected pin still needs it, + // it will have addrefed it itself. + pOutSample->Release(); + ASSERT(CritCheckIn(&m_csReceive)); + + return hr; +} + + + +BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) +{ + REFERENCE_TIME trStart, trStopAt; + HRESULT hr = pIn->GetTime(&trStart, &trStopAt); + + // Don't skip frames with no timestamps + if (hr != S_OK) + return FALSE; + + int itrFrame = (int)(trStopAt - trStart); // frame duration + + if(S_OK==pIn->IsSyncPoint()) { + MSR_INTEGER(m_idFrameType, 1); + if ( m_nKeyFramePeriod < m_nFramesSinceKeyFrame ) { + // record the max + m_nKeyFramePeriod = m_nFramesSinceKeyFrame; + } + m_nFramesSinceKeyFrame = 0; + m_bSkipping = FALSE; + } else { + MSR_INTEGER(m_idFrameType, 2); + if ( m_nFramesSinceKeyFrame>m_nKeyFramePeriod + && m_nKeyFramePeriod>0 + ) { + // We haven't seen the key frame yet, but we were clearly being + // overoptimistic about how frequent they are. + m_nKeyFramePeriod = m_nFramesSinceKeyFrame; + } + } + + + // Whatever we might otherwise decide, + // if we are taking only a small fraction of the required frame time to decode + // then any quality problems are actually coming from somewhere else. + // Could be a net problem at the source for instance. In this case there's + // no point in us skipping frames here. + if (m_itrAvgDecode*4>itrFrame) { + + // Don't skip unless we are at least a whole frame late. + // (We would skip B frames if more than 1/2 frame late, but they're safe). + if ( m_itrLate > itrFrame ) { + + // Don't skip unless the anticipated key frame would be no more than + // 1 frame early. If the renderer has not been waiting (we *guess* + // it hasn't because we're late) then it will allow frames to be + // played early by up to a frame. + + // Let T = Stream time from now to anticipated next key frame + // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame) + // So we skip if T - Late < one frame i.e. + // (duration) * (freq - FramesSince) - Late < duration + // or (duration) * (freq - FramesSince - 1) < Late + + // We don't dare skip until we have seen some key frames and have + // some idea how often they occur and they are reasonably frequent. + if (m_nKeyFramePeriod>0) { + // It would be crazy - but we could have a stream with key frames + // a very long way apart - and if they are further than about + // 3.5 minutes apart then we could get arithmetic overflow in + // reference time units. Therefore we switch to mSec at this point + int it = (itrFrame/10000) + * (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1); + MSR_INTEGER(m_idTimeTillKey, it); + + // For debug - might want to see the details - dump them as scratch pad +#ifdef VTRANSPERF + MSR_INTEGER(0, itrFrame); + MSR_INTEGER(0, m_nFramesSinceKeyFrame); + MSR_INTEGER(0, m_nKeyFramePeriod); +#endif + if (m_itrLate/10000 > it) { + m_bSkipping = TRUE; + // Now we are committed. Once we start skipping, we + // cannot stop until we hit a key frame. + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777770); // not near enough to next key +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777771); // Next key not predictable +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777772); // Less than one frame late + MSR_INTEGER(0, m_itrLate); + MSR_INTEGER(0, itrFrame); +#endif + } + } else { +#ifdef VTRANSPERF + MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping + MSR_INTEGER(0, m_itrAvgDecode); + MSR_INTEGER(0, itrFrame); +#endif + } + + ++m_nFramesSinceKeyFrame; + + if (m_bSkipping) { + // We will count down the lateness as we skip each frame. + // We re-assess each frame. The key frame might not arrive when expected. + // We reset m_itrLate if we get a new Quality message, but actually that's + // not likely because we're not sending frames on to the Renderer. In + // fact if we DID get another one it would mean that there's a long + // pipe between us and the renderer and we might need an altogether + // better strategy to avoid hunting! + m_itrLate = m_itrLate - itrFrame; + } + + MSR_INTEGER(m_idLate, (int)m_itrLate/10000 ); // Note how late we think we are + if (m_bSkipping) { + if (!m_bQualityChanged) { + m_bQualityChanged = TRUE; + NotifyEvent(EC_QUALITY_CHANGE,0,0); + } + } + return m_bSkipping; +} + + +HRESULT CVideoTransformFilter::AlterQuality(Quality q) +{ + // to reduce the amount of 64 bit arithmetic, m_itrLate is an int. + // +, -, >, == etc are not too bad, but * and / are painful. + if (m_itrLate>300000000) { + // Avoid overflow and silliness - more than 30 secs late is already silly + m_itrLate = 300000000; + } else { + m_itrLate = (int)q.Late; + } + // We ignore the other fields + + // We're actually not very good at handling this. In non-direct draw mode + // most of the time can be spent in the renderer which can skip any frame. + // In that case we'd rather the renderer handled things. + // Nevertheless we will keep an eye on it and if we really start getting + // a very long way behind then we will actually skip - but we'll still tell + // the renderer (or whoever is downstream) that they should handle quality. + + return E_FAIL; // Tell the renderer to do his thing. + +} + + + +// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4 +#pragma warning(disable:4514) + diff --git a/src/thirdparty/BaseClasses/vtrans.h b/src/thirdparty/BaseClasses/vtrans.h index 0ebace9148b..7fda41491ec 100644 --- a/src/thirdparty/BaseClasses/vtrans.h +++ b/src/thirdparty/BaseClasses/vtrans.h @@ -1,143 +1,143 @@ -//------------------------------------------------------------------------------ -// File: VTrans.h -// -// Desc: DirectShow base classes - defines a video transform class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// This class is derived from CTransformFilter, but is specialised to handle -// the requirements of video quality control by frame dropping. -// This is a non-in-place transform, (i.e. it copies the data) such as a decoder. - -class CVideoTransformFilter : public CTransformFilter -{ - public: - - CVideoTransformFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid); - ~CVideoTransformFilter(); - HRESULT EndFlush(); - - // ================================================================= - // ----- override these bits --------------------------------------- - // ================================================================= - // The following methods are in CTransformFilter which is inherited. - // They are mentioned here for completeness - // - // These MUST be supplied in a derived class - // - // NOTE: - // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); - // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; - // virtual HRESULT CheckTransform - // (const CMediaType* mtIn, const CMediaType* mtOut) PURE; - // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); - // virtual HRESULT DecideBufferSize - // (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE; - // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; - // - // These MAY also be overridden - // - // virtual HRESULT StopStreaming(); - // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); - // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); - // virtual HRESULT BreakConnect(PIN_DIRECTION dir); - // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); - // virtual HRESULT EndOfStream(void); - // virtual HRESULT BeginFlush(void); - // virtual HRESULT EndFlush(void); - // virtual HRESULT NewSegment - // (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate); -#ifdef PERF - - // If you override this - ensure that you register all these ids - // as well as any of your own, - virtual void RegisterPerfId() { - m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame")); - m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type")); - m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness")); - m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key")); - CTransformFilter::RegisterPerfId(); - } -#endif - - protected: - - // =========== QUALITY MANAGEMENT IMPLEMENTATION ======================== - // Frames are assumed to come in three types: - // Type 1: an AVI key frame or an MPEG I frame. - // This frame can be decoded with no history. - // Dropping this frame means that no further frame can be decoded - // until the next type 1 frame. - // Type 1 frames are sync points. - // Type 2: an AVI non-key frame or an MPEG P frame. - // This frame cannot be decoded unless the previous type 1 frame was - // decoded and all type 2 frames since have been decoded. - // Dropping this frame means that no further frame can be decoded - // until the next type 1 frame. - // Type 3: An MPEG B frame. - // This frame cannot be decoded unless the previous type 1 or 2 frame - // has been decoded AND the subsequent type 1 or 2 frame has also - // been decoded. (This requires decoding the frames out of sequence). - // Dropping this frame affects no other frames. This implementation - // does not allow for these. All non-sync-point frames are treated - // as being type 2. - // - // The spacing of frames of type 1 in a file is not guaranteed. There MUST - // be a type 1 frame at (well, near) the start of the file in order to start - // decoding at all. After that there could be one every half second or so, - // there could be one at the start of each scene (aka "cut", "shot") or - // there could be no more at all. - // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED - // without losing all the rest of the movie. There is no way to tell whether - // this is the case, so we find that we are in the gambling business. - // To try to improve the odds, we record the greatest interval between type 1s - // that we have seen and we bet on things being no worse than this in the - // future. - - // You can tell if it's a type 1 frame by calling IsSyncPoint(). - // there is no architected way to test for a type 3, so you should override - // the quality management here if you have B-frames. - - int m_nKeyFramePeriod; // the largest observed interval between type 1 frames - // 1 means every frame is type 1, 2 means every other. - - int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1. - // becomes the new m_nKeyFramePeriod if greater. - - BOOL m_bSkipping; // we are skipping to the next type 1 frame - -#ifdef PERF - int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key" - int m_idSkip; // MSR id skipping - int m_idLate; // MSR id lateness - int m_idTimeTillKey; // MSR id for guessed time till next key frame. -#endif - - virtual HRESULT StartStreaming(); - - HRESULT AbortPlayback(HRESULT hr); // if something bad happens - - HRESULT Receive(IMediaSample *pSample); - - HRESULT AlterQuality(Quality q); - - BOOL ShouldSkipFrame(IMediaSample * pIn); - - int m_itrLate; // lateness from last Quality message - // (this overflows at 214 secs late). - int m_tDecodeStart; // timeGetTime when decode started. - int m_itrAvgDecode; // Average decode time in reference units. - - //BOOL m_bNoSkip; // debug - no skipping. - - // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade. - // We send one when we start degrading, not one for every frame, this means - // we track whether we've sent one yet. - BOOL m_bQualityChanged; - - // When non-zero, don't pass anything to renderer until next keyframe - // If there are few keys, give up and eventually draw something - int m_nWaitForKey; -}; +//------------------------------------------------------------------------------ +// File: VTrans.h +// +// Desc: DirectShow base classes - defines a video transform class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// This class is derived from CTransformFilter, but is specialised to handle +// the requirements of video quality control by frame dropping. +// This is a non-in-place transform, (i.e. it copies the data) such as a decoder. + +class CVideoTransformFilter : public CTransformFilter +{ + public: + + CVideoTransformFilter(__in_opt LPCTSTR, __inout_opt LPUNKNOWN, REFCLSID clsid); + ~CVideoTransformFilter(); + HRESULT EndFlush(); + + // ================================================================= + // ----- override these bits --------------------------------------- + // ================================================================= + // The following methods are in CTransformFilter which is inherited. + // They are mentioned here for completeness + // + // These MUST be supplied in a derived class + // + // NOTE: + // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut); + // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE; + // virtual HRESULT CheckTransform + // (const CMediaType* mtIn, const CMediaType* mtOut) PURE; + // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *); + // virtual HRESULT DecideBufferSize + // (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE; + // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE; + // + // These MAY also be overridden + // + // virtual HRESULT StopStreaming(); + // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt); + // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin); + // virtual HRESULT BreakConnect(PIN_DIRECTION dir); + // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin); + // virtual HRESULT EndOfStream(void); + // virtual HRESULT BeginFlush(void); + // virtual HRESULT EndFlush(void); + // virtual HRESULT NewSegment + // (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate); +#ifdef PERF + + // If you override this - ensure that you register all these ids + // as well as any of your own, + virtual void RegisterPerfId() { + m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame")); + m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type")); + m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness")); + m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key")); + CTransformFilter::RegisterPerfId(); + } +#endif + + protected: + + // =========== QUALITY MANAGEMENT IMPLEMENTATION ======================== + // Frames are assumed to come in three types: + // Type 1: an AVI key frame or an MPEG I frame. + // This frame can be decoded with no history. + // Dropping this frame means that no further frame can be decoded + // until the next type 1 frame. + // Type 1 frames are sync points. + // Type 2: an AVI non-key frame or an MPEG P frame. + // This frame cannot be decoded unless the previous type 1 frame was + // decoded and all type 2 frames since have been decoded. + // Dropping this frame means that no further frame can be decoded + // until the next type 1 frame. + // Type 3: An MPEG B frame. + // This frame cannot be decoded unless the previous type 1 or 2 frame + // has been decoded AND the subsequent type 1 or 2 frame has also + // been decoded. (This requires decoding the frames out of sequence). + // Dropping this frame affects no other frames. This implementation + // does not allow for these. All non-sync-point frames are treated + // as being type 2. + // + // The spacing of frames of type 1 in a file is not guaranteed. There MUST + // be a type 1 frame at (well, near) the start of the file in order to start + // decoding at all. After that there could be one every half second or so, + // there could be one at the start of each scene (aka "cut", "shot") or + // there could be no more at all. + // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED + // without losing all the rest of the movie. There is no way to tell whether + // this is the case, so we find that we are in the gambling business. + // To try to improve the odds, we record the greatest interval between type 1s + // that we have seen and we bet on things being no worse than this in the + // future. + + // You can tell if it's a type 1 frame by calling IsSyncPoint(). + // there is no architected way to test for a type 3, so you should override + // the quality management here if you have B-frames. + + int m_nKeyFramePeriod; // the largest observed interval between type 1 frames + // 1 means every frame is type 1, 2 means every other. + + int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1. + // becomes the new m_nKeyFramePeriod if greater. + + BOOL m_bSkipping; // we are skipping to the next type 1 frame + +#ifdef PERF + int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key" + int m_idSkip; // MSR id skipping + int m_idLate; // MSR id lateness + int m_idTimeTillKey; // MSR id for guessed time till next key frame. +#endif + + virtual HRESULT StartStreaming(); + + HRESULT AbortPlayback(HRESULT hr); // if something bad happens + + HRESULT Receive(IMediaSample *pSample); + + HRESULT AlterQuality(Quality q); + + BOOL ShouldSkipFrame(IMediaSample * pIn); + + int m_itrLate; // lateness from last Quality message + // (this overflows at 214 secs late). + int m_tDecodeStart; // timeGetTime when decode started. + int m_itrAvgDecode; // Average decode time in reference units. + + //BOOL m_bNoSkip; // debug - no skipping. + + // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade. + // We send one when we start degrading, not one for every frame, this means + // we track whether we've sent one yet. + BOOL m_bQualityChanged; + + // When non-zero, don't pass anything to renderer until next keyframe + // If there are few keys, give up and eventually draw something + int m_nWaitForKey; +}; diff --git a/src/thirdparty/BaseClasses/winctrl.cpp b/src/thirdparty/BaseClasses/winctrl.cpp index b85d0c22c12..a4b0126d3c2 100644 --- a/src/thirdparty/BaseClasses/winctrl.cpp +++ b/src/thirdparty/BaseClasses/winctrl.cpp @@ -1,2081 +1,2081 @@ -//------------------------------------------------------------------------------ -// File: WinCtrl.cpp -// -// Desc: DirectShow base classes - implements video control interface class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include -#include "checkbmi.h" - -// The control interface methods require us to be connected - -#define CheckConnected(pin,code) \ -{ \ - if (pin == NULL) { \ - ASSERT(!TEXT("Pin not set")); \ - } else if (pin->IsConnected() == FALSE) { \ - return (code); \ - } \ -} - -// This checks to see whether the window has a drain. An application can in -// most environments set the owner/parent of windows so that they appear in -// a compound document context (for example). In this case, the application -// would probably like to be told of any keyboard/mouse messages. Therefore -// we pass these messages on untranslated, returning TRUE if we're successful - -BOOL WINAPI PossiblyEatMessage(HWND hwndDrain, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (hwndDrain != NULL && !InSendMessage()) - { - switch (uMsg) - { - case WM_CHAR: - case WM_DEADCHAR: - case WM_KEYDOWN: - case WM_KEYUP: - case WM_LBUTTONDBLCLK: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONDBLCLK: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_MOUSEACTIVATE: - case WM_MOUSEMOVE: - // If we pass this on we don't get any mouse clicks - //case WM_NCHITTEST: - case WM_NCLBUTTONDBLCLK: - case WM_NCLBUTTONDOWN: - case WM_NCLBUTTONUP: - case WM_NCMBUTTONDBLCLK: - case WM_NCMBUTTONDOWN: - case WM_NCMBUTTONUP: - case WM_NCMOUSEMOVE: - case WM_NCRBUTTONDBLCLK: - case WM_NCRBUTTONDOWN: - case WM_NCRBUTTONUP: - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_SYSCHAR: - case WM_SYSDEADCHAR: - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - - DbgLog((LOG_TRACE, 2, TEXT("Forwarding %x to drain"))); - PostMessage(hwndDrain, uMsg, wParam, lParam); - - return TRUE; - } - } - return FALSE; -} - - -// This class implements the IVideoWindow control functions (dual interface) -// we support a large number of properties and methods designed to allow the -// client (whether it be an automation controller or a C/C++ application) to -// set and get a number of window related properties such as it's position. -// We also support some methods that duplicate the properties but provide a -// more direct and efficient mechanism as many values may be changed in one - -CBaseControlWindow::CBaseControlWindow( - __inout CBaseFilter *pFilter, // Owning filter - __in CCritSec *pInterfaceLock, // Locking object - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // Normal COM ownership - __inout HRESULT *phr) : // OLE return code - - CBaseVideoWindow(pName,pUnk), - m_pInterfaceLock(pInterfaceLock), - m_hwndOwner(NULL), - m_hwndDrain(NULL), - m_bAutoShow(TRUE), - m_pFilter(pFilter), - m_bCursorHidden(FALSE), - m_pPin(NULL) -{ - ASSERT(m_pFilter); - ASSERT(m_pInterfaceLock); - ASSERT(phr); - m_BorderColour = VIDEO_COLOUR; -} - - -// Set the title caption on the base window, we don't do any field checking -// as we really don't care what title they intend to have. We can always get -// it back again later with GetWindowText. The only other complication is to -// do the necessary string conversions between ANSI and OLE Unicode strings - -STDMETHODIMP CBaseControlWindow::put_Caption(__in BSTR strCaption) -{ - CheckPointer((PVOID)strCaption,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); -#ifdef UNICODE - SetWindowText(m_hwnd, strCaption); -#else - CHAR Caption[CAPTION]; - - WideCharToMultiByte(CP_ACP,0,strCaption,-1,Caption,CAPTION,NULL,NULL); - SetWindowText(m_hwnd, Caption); -#endif - return NOERROR; -} - - -// Get the current base window title caption, once again we do no real field -// checking. We allocate a string for the window title to be filled in with -// which ensures the interface doesn't fiddle around with getting memory. A -// BSTR is a normal C string with the length at position (-1), we use the -// WriteBSTR helper function to create the caption to try and avoid OLE32 - -STDMETHODIMP CBaseControlWindow::get_Caption(__out BSTR *pstrCaption) -{ - CheckPointer(pstrCaption,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - WCHAR WideCaption[CAPTION]; - -#ifdef UNICODE - GetWindowText(m_hwnd,WideCaption,CAPTION); -#else - // Convert the ASCII caption to a UNICODE string - - TCHAR Caption[CAPTION]; - GetWindowText(m_hwnd,Caption,CAPTION); - MultiByteToWideChar(CP_ACP,0,Caption,-1,WideCaption,CAPTION); -#endif - return WriteBSTR(pstrCaption,WideCaption); -} - - -// Set the window style using GWL_EXSTYLE - -STDMETHODIMP CBaseControlWindow::put_WindowStyleEx(long WindowStyleEx) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Should we be taking off WS_EX_TOPMOST - - if (GetWindowLong(m_hwnd,GWL_EXSTYLE) & WS_EX_TOPMOST) { - if ((WindowStyleEx & WS_EX_TOPMOST) == 0) { - SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) FALSE,(LPARAM) 0); - } - } - - // Likewise should we be adding WS_EX_TOPMOST - - if (WindowStyleEx & WS_EX_TOPMOST) { - SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) TRUE,(LPARAM) 0); - WindowStyleEx &= (~WS_EX_TOPMOST); - if (WindowStyleEx == 0) return NOERROR; - } - return DoSetWindowStyle(WindowStyleEx,GWL_EXSTYLE); -} - - -// Gets the current GWL_EXSTYLE base window style - -STDMETHODIMP CBaseControlWindow::get_WindowStyleEx(__out long *pWindowStyleEx) -{ - CheckPointer(pWindowStyleEx,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - return DoGetWindowStyle(pWindowStyleEx,GWL_EXSTYLE); -} - - -// Set the window style using GWL_STYLE - -STDMETHODIMP CBaseControlWindow::put_WindowStyle(long WindowStyle) -{ - // These styles cannot be changed dynamically - - if ((WindowStyle & WS_DISABLED) || - (WindowStyle & WS_ICONIC) || - (WindowStyle & WS_MAXIMIZE) || - (WindowStyle & WS_MINIMIZE) || - (WindowStyle & WS_HSCROLL) || - (WindowStyle & WS_VSCROLL)) { - - return E_INVALIDARG; - } - - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - return DoSetWindowStyle(WindowStyle,GWL_STYLE); -} - - -// Get the current GWL_STYLE base window style - -STDMETHODIMP CBaseControlWindow::get_WindowStyle(__out long *pWindowStyle) -{ - CheckPointer(pWindowStyle,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - return DoGetWindowStyle(pWindowStyle,GWL_STYLE); -} - - -// Change the base window style or the extended styles depending on whether -// WindowLong is GWL_STYLE or GWL_EXSTYLE. We must call SetWindowPos to have -// the window displayed in it's new style after the change which is a little -// tricky if the window is not currently visible as we realise it offscreen. -// In most cases the client will call get_WindowStyle before they call this -// and then AND and OR in extra bit settings according to the requirements - -HRESULT CBaseControlWindow::DoSetWindowStyle(long Style,long WindowLong) -{ - RECT WindowRect; - - // Get the window's visibility before setting the style - BOOL bVisible = IsWindowVisible(m_hwnd); - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - // Set the new style flags for the window - SetWindowLong(m_hwnd,WindowLong,Style); - UINT WindowFlags = SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE; - WindowFlags |= SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; - - // Show the window again in the current position - - if (bVisible == TRUE) { - - SetWindowPos(m_hwnd, // Base window handle - HWND_TOP, // Just a place holder - 0,0,0,0, // Leave size and position - WindowFlags); // Just draw it again - - return NOERROR; - } - - // Move the window offscreen so the user doesn't see the changes - - MoveWindow((HWND) m_hwnd, // Base window handle - GetSystemMetrics(SM_CXSCREEN), // Current desktop width - GetSystemMetrics(SM_CYSCREEN), // Likewise it's height - WIDTH(&WindowRect), // Use the same width - HEIGHT(&WindowRect), // Keep height same to - TRUE); // May as well repaint - - // Now show the previously hidden window - - SetWindowPos(m_hwnd, // Base window handle - HWND_TOP, // Just a place holder - 0,0,0,0, // Leave size and position - WindowFlags); // Just draw it again - - ShowWindow(m_hwnd,SW_HIDE); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - MoveWindow((HWND) m_hwnd, // Base window handle - WindowRect.left, // Existing x coordinate - WindowRect.top, // Existing y coordinate - WIDTH(&WindowRect), // Use the same width - HEIGHT(&WindowRect), // Keep height same to - TRUE); // May as well repaint - - return NOERROR; -} - - -// Get the current base window style (either GWL_STYLE or GWL_EXSTYLE) - -HRESULT CBaseControlWindow::DoGetWindowStyle(__out long *pStyle,long WindowLong) -{ - *pStyle = GetWindowLong(m_hwnd,WindowLong); - return NOERROR; -} - - -// Change the visibility of the base window, this takes the same parameters -// as the ShowWindow Win32 API does, so the client can have the window hidden -// or shown, minimised to an icon, or maximised to play in full screen mode -// We pass the request on to the base window to actually make the change - -STDMETHODIMP CBaseControlWindow::put_WindowState(long WindowState) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - DoShowWindow(WindowState); - return NOERROR; -} - - -// Get the current window state, this function returns a subset of the SW bit -// settings available in ShowWindow, if the window is visible then SW_SHOW is -// set, if it is hidden then the SW_HIDDEN is set, if it is either minimised -// or maximised then the SW_MINIMIZE or SW_MAXIMIZE is set respectively. The -// other SW bit settings are really set commands not readable output values - -STDMETHODIMP CBaseControlWindow::get_WindowState(__out long *pWindowState) -{ - CheckPointer(pWindowState,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - ASSERT(pWindowState); - *pWindowState = FALSE; - - // Is the window visible, a window is termed visible if it is somewhere on - // the current desktop even if it is completely obscured by other windows - // so the flag is a style for each window set with the WS_VISIBLE bit - - if (IsWindowVisible(m_hwnd) == TRUE) { - - // Is the base window iconic - if (IsIconic(m_hwnd) == TRUE) { - *pWindowState |= SW_MINIMIZE; - } - - // Has the window been maximised - else if (IsZoomed(m_hwnd) == TRUE) { - *pWindowState |= SW_MAXIMIZE; - } - - // Window is normal - else { - *pWindowState |= SW_SHOW; - } - - } else { - *pWindowState |= SW_HIDE; - } - return NOERROR; -} - - -// This makes sure that any palette we realise in the base window (through a -// media type or through the overlay interface) is done in the background and -// is therefore mapped to existing device entries rather than taking it over -// as it will do when we this window gets the keyboard focus. An application -// uses this to make sure it doesn't have it's palette removed by the window - -STDMETHODIMP CBaseControlWindow::put_BackgroundPalette(long BackgroundPalette) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cWindowLock(&m_WindowLock); - - // Check this is a valid automation boolean type - - if (BackgroundPalette != OATRUE) { - if (BackgroundPalette != OAFALSE) { - return E_INVALIDARG; - } - } - - // Make sure the window realises any palette it has again - - m_bBackground = (BackgroundPalette == OATRUE ? TRUE : FALSE); - PostMessage(m_hwnd,m_RealizePalette,0,0); - PaintWindow(FALSE); - - return NOERROR; -} - - -// This returns the current background realisation setting - -STDMETHODIMP -CBaseControlWindow::get_BackgroundPalette(__out long *pBackgroundPalette) -{ - CheckPointer(pBackgroundPalette,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cWindowLock(&m_WindowLock); - - // Get the current background palette setting - - *pBackgroundPalette = (m_bBackground == TRUE ? OATRUE : OAFALSE); - return NOERROR; -} - - -// Change the visibility of the base window - -STDMETHODIMP CBaseControlWindow::put_Visible(long Visible) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Check this is a valid automation boolean type - - if (Visible != OATRUE) { - if (Visible != OAFALSE) { - return E_INVALIDARG; - } - } - - // Convert the boolean visibility into SW_SHOW and SW_HIDE - - INT Mode = (Visible == OATRUE ? SW_SHOWNORMAL : SW_HIDE); - DoShowWindow(Mode); - return NOERROR; -} - - -// Return OATRUE if the window is currently visible otherwise OAFALSE - -STDMETHODIMP CBaseControlWindow::get_Visible(__out long *pVisible) -{ - CheckPointer(pVisible,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // See if the base window has a WS_VISIBLE style - this will return TRUE - // even if the window is completely obscured by other desktop windows, we - // return FALSE if the window is not showing because of earlier calls - - BOOL Mode = IsWindowVisible(m_hwnd); - *pVisible = (Mode == TRUE ? OATRUE : OAFALSE); - return NOERROR; -} - - -// Change the left position of the base window. This keeps the window width -// and height properties the same so it effectively shunts the window left or -// right accordingly - there is the Width property to change that dimension - -STDMETHODIMP CBaseControlWindow::put_Left(long Left) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - RECT WindowRect; - - // Get the current window position in a RECT - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - // Adjust the coordinates ready for SetWindowPos, the window rectangle we - // get back from GetWindowRect is in left,top,right and bottom while the - // coordinates SetWindowPos wants are left,top,width and height values - - WindowRect.bottom = WindowRect.bottom - WindowRect.top; - WindowRect.right = WindowRect.right - WindowRect.left; - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - Left, // New left position - WindowRect.top, // Leave top alone - WindowRect.right, // The WIDTH (not right) - WindowRect.bottom, // The HEIGHT (not bottom) - WindowFlags); // Show window options - - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// Return the current base window left position - -STDMETHODIMP CBaseControlWindow::get_Left(__out long *pLeft) -{ - CheckPointer(pLeft,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - *pLeft = WindowRect.left; - return NOERROR; -} - - -// Change the current width of the base window. This property complements the -// left position property so we must keep the left edge constant and expand or -// contract to the right, the alternative would be to change the left edge so -// keeping the right edge constant but this is maybe a little more intuitive - -STDMETHODIMP CBaseControlWindow::put_Width(long Width) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - RECT WindowRect; - - // Adjust the coordinates ready for SetWindowPos, the window rectangle we - // get back from GetWindowRect is in left,top,right and bottom while the - // coordinates SetWindowPos wants are left,top,width and height values - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - WindowRect.bottom = WindowRect.bottom - WindowRect.top; - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - // This seems to have a bug in that calling SetWindowPos on a window with - // just the width changing causes it to ignore the width that you pass in - // and sets it to a mimimum value of 110 pixels wide (Windows NT 3.51) - - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Leave left alone - WindowRect.top, // Leave top alone - Width, // New WIDTH dimension - WindowRect.bottom, // The HEIGHT (not bottom) - WindowFlags); // Show window options - - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// Return the current base window width - -STDMETHODIMP CBaseControlWindow::get_Width(__out long *pWidth) -{ - CheckPointer(pWidth,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - *pWidth = WindowRect.right - WindowRect.left; - return NOERROR; -} - - -// This allows the client program to change the top position for the window in -// the same way that changing the left position does not affect the width of -// the image so changing the top position does not affect the window height - -STDMETHODIMP CBaseControlWindow::put_Top(long Top) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - RECT WindowRect; - - // Get the current window position in a RECT - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - // Adjust the coordinates ready for SetWindowPos, the window rectangle we - // get back from GetWindowRect is in left,top,right and bottom while the - // coordinates SetWindowPos wants are left,top,width and height values - - WindowRect.bottom = WindowRect.bottom - WindowRect.top; - WindowRect.right = WindowRect.right - WindowRect.left; - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Leave left alone - Top, // New top position - WindowRect.right, // The WIDTH (not right) - WindowRect.bottom, // The HEIGHT (not bottom) - WindowFlags); // Show window flags - - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// Return the current base window top position - -STDMETHODIMP CBaseControlWindow::get_Top(long *pTop) -{ - CheckPointer(pTop,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - *pTop = WindowRect.top; - return NOERROR; -} - - -// Change the height of the window, this complements the top property so when -// we change this we must keep the top position for the base window, as said -// before we could keep the bottom and grow upwards although this is perhaps -// a little more intuitive since we already have a top position property - -STDMETHODIMP CBaseControlWindow::put_Height(long Height) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - RECT WindowRect; - - // Adjust the coordinates ready for SetWindowPos, the window rectangle we - // get back from GetWindowRect is in left,top,right and bottom while the - // coordinates SetWindowPos wants are left,top,width and height values - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - if (GetParent(m_hwnd)) { - - MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); - } - - WindowRect.right = WindowRect.right - WindowRect.left; - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Leave left alone - WindowRect.top, // Leave top alone - WindowRect.right, // The WIDTH (not right) - Height, // New height dimension - WindowFlags); // Show window flags - - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// Return the current base window height - -STDMETHODIMP CBaseControlWindow::get_Height(__out long *pHeight) -{ - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - *pHeight = WindowRect.bottom - WindowRect.top; - return NOERROR; -} - - -// This can be called to change the owning window. Setting the owner is done -// through this function, however to make the window a true child window the -// style must also be set to WS_CHILD. After resetting the owner to NULL an -// application should also set the style to WS_OVERLAPPED | WS_CLIPCHILDREN. - -// We cannot lock the object here because the SetParent causes an interthread -// SendMessage to the owner window. If they are in GetState we will sit here -// incomplete with the critical section locked therefore blocking out source -// filter threads from accessing us. Because the source thread can't enter us -// it can't get buffers or call EndOfStream so the GetState will not complete - -STDMETHODIMP CBaseControlWindow::put_Owner(OAHWND Owner) -{ - // Check we are connected otherwise reject the call - - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - m_hwndOwner = (HWND) Owner; - HWND hwndParent = m_hwndOwner; - - // Add or remove WS_CHILD as appropriate - - LONG Style = GetWindowLong(m_hwnd,GWL_STYLE); - if (Owner == NULL) { - Style &= (~WS_CHILD); - } else { - Style |= (WS_CHILD); - } - SetWindowLong(m_hwnd,GWL_STYLE,Style); - - // Don't call this with the filter locked - - SetParent(m_hwnd,hwndParent); - - PaintWindow(TRUE); - NOTE1("Changed parent %lx",hwndParent); - - return NOERROR; -} - - -// This complements the put_Owner to get the current owning window property -// we always return NOERROR although the returned window handle may be NULL -// to indicate no owning window (the desktop window doesn't qualify as one) -// If an application sets the owner we call SetParent, however that returns -// NULL until the WS_CHILD bit is set on, so we store the owner internally - -STDMETHODIMP CBaseControlWindow::get_Owner(__out OAHWND *Owner) -{ - CheckPointer(Owner,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *Owner = (OAHWND) m_hwndOwner; - return NOERROR; -} - - -// And renderer supporting IVideoWindow may have an HWND set who will get any -// keyboard and mouse messages we receive posted on to them. This is separate -// from setting an owning window. By separating the two, applications may get -// messages sent on even when they have set no owner (perhaps it's maximised) - -STDMETHODIMP CBaseControlWindow::put_MessageDrain(OAHWND Drain) -{ - // Check we are connected otherwise reject the call - - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - m_hwndDrain = (HWND) Drain; - return NOERROR; -} - - -// Return the current message drain - -STDMETHODIMP CBaseControlWindow::get_MessageDrain(__out OAHWND *Drain) -{ - CheckPointer(Drain,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *Drain = (OAHWND) m_hwndDrain; - return NOERROR; -} - - -// This is called by the filter graph to inform us of a message we should know -// is being sent to our owning window. We have this because as a child window -// we do not get certain messages that are only sent to top level windows. We -// must see the palette changed/changing/query messages so that we know if we -// have the foreground palette or not. We pass the message on to our window -// using SendMessage - this will cause an interthread send message to occur - -STDMETHODIMP -CBaseControlWindow::NotifyOwnerMessage(OAHWND hwnd, // Window handle - long uMsg, // Message ID - LONG_PTR wParam, // Parameters - LONG_PTR lParam) // for message -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Only interested in these Windows messages - - switch (uMsg) { - - case WM_SYSCOLORCHANGE: - case WM_PALETTECHANGED: - case WM_PALETTEISCHANGING: - case WM_QUERYNEWPALETTE: - case WM_DEVMODECHANGE: - case WM_DISPLAYCHANGE: - case WM_ACTIVATEAPP: - - // If we do not have an owner then ignore - - if (m_hwndOwner == NULL) { - return NOERROR; - } - SendMessage(m_hwnd,uMsg,(WPARAM)wParam,(LPARAM)lParam); - break; - - // do NOT fwd WM_MOVE. the parameters are the location of the parent - // window, NOT what the renderer should be looking at. But we need - // to make sure the overlay is moved with the parent window, so we - // do this. - case WM_MOVE: - PostMessage(m_hwnd,WM_PAINT,0,0); - break; - } - return NOERROR; -} - - -// Allow an application to have us set the base window in the foreground. We -// have this because it is difficult for one thread to do do this to a window -// owned by another thread. We ask the base window class to do the real work - -STDMETHODIMP CBaseControlWindow::SetWindowForeground(long Focus) -{ - // Check this is a valid automation boolean type - - if (Focus != OATRUE) { - if (Focus != OAFALSE) { - return E_INVALIDARG; - } - } - - // We shouldn't lock as this sends a message - - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bFocus = (Focus == OATRUE ? TRUE : FALSE); - DoSetWindowForeground(bFocus); - - return NOERROR; -} - - -// This allows a client to set the complete window size and position in one -// atomic operation. The same affect can be had by changing each dimension -// in turn through their individual properties although some flashing will -// occur as each of them gets updated (they are better set at design time) - -STDMETHODIMP -CBaseControlWindow::SetWindowPosition(long Left,long Top,long Width,long Height) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - BOOL bSuccess; - - // Set the new size and position - UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; - - ASSERT(IsWindow(m_hwnd)); - bSuccess = SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - Left, // Left position - Top, // Top position - Width, // Window width - Height, // Window height - WindowFlags); // Show window flags - ASSERT(bSuccess); -#ifdef _DEBUG - DbgLog((LOG_TRACE, 1, TEXT("SWP failed error %d"), GetLastError())); -#endif - if (bSuccess == FALSE) { - return E_INVALIDARG; - } - return NOERROR; -} - - -// This complements the SetWindowPosition to return the current window place -// in device coordinates. As before the same information can be retrived by -// calling the property get functions individually but this is atomic and is -// therefore more suitable to a live environment rather than design time - -STDMETHODIMP -CBaseControlWindow::GetWindowPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) -{ - // Should check the pointers are not NULL - - CheckPointer(pLeft,E_POINTER); - CheckPointer(pTop,E_POINTER); - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT WindowRect; - - // Get the current window coordinates - - EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); - - // Convert the RECT into left,top,width and height values - - *pLeft = WindowRect.left; - *pTop = WindowRect.top; - *pWidth = WindowRect.right - WindowRect.left; - *pHeight = WindowRect.bottom - WindowRect.top; - - return NOERROR; -} - - -// When a window is maximised or iconic calling GetWindowPosition will return -// the current window position (likewise for the properties). However if the -// restored size (ie the size we'll return to when normally shown) is needed -// then this should be used. When in a normal position (neither iconic nor -// maximised) then this returns the same coordinates as GetWindowPosition - -STDMETHODIMP -CBaseControlWindow::GetRestorePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) -{ - // Should check the pointers are not NULL - - CheckPointer(pLeft,E_POINTER); - CheckPointer(pTop,E_POINTER); - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Use GetWindowPlacement to find the restore position - - WINDOWPLACEMENT Place; - Place.length = sizeof(WINDOWPLACEMENT); - EXECUTE_ASSERT(GetWindowPlacement(m_hwnd,&Place)); - - RECT WorkArea; - - // We must take into account any task bar present - - if (SystemParametersInfo(SPI_GETWORKAREA,0,&WorkArea,FALSE) == TRUE) { - if (GetParent(m_hwnd) == NULL) { - Place.rcNormalPosition.top += WorkArea.top; - Place.rcNormalPosition.bottom += WorkArea.top; - Place.rcNormalPosition.left += WorkArea.left; - Place.rcNormalPosition.right += WorkArea.left; - } - } - - // Convert the RECT into left,top,width and height values - - *pLeft = Place.rcNormalPosition.left; - *pTop = Place.rcNormalPosition.top; - *pWidth = Place.rcNormalPosition.right - Place.rcNormalPosition.left; - *pHeight = Place.rcNormalPosition.bottom - Place.rcNormalPosition.top; - - return NOERROR; -} - - -// Return the current border colour, if we are playing something to a subset -// of the base window display there is an outside area exposed. The default -// action is to paint this colour in the Windows background colour (defined -// as value COLOR_WINDOW) We reset to this default when we're disconnected - -STDMETHODIMP CBaseControlWindow::get_BorderColor(__out long *Color) -{ - CheckPointer(Color,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *Color = (long) m_BorderColour; - return NOERROR; -} - - -// This can be called to set the current border colour - -STDMETHODIMP CBaseControlWindow::put_BorderColor(long Color) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Have the window repainted with the new border colour - - m_BorderColour = (COLORREF) Color; - PaintWindow(TRUE); - return NOERROR; -} - - -// Delegate fullscreen handling to plug in distributor - -STDMETHODIMP CBaseControlWindow::get_FullScreenMode(__out long *FullScreenMode) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CheckPointer(FullScreenMode,E_POINTER); - return E_NOTIMPL; -} - - -// Delegate fullscreen handling to plug in distributor - -STDMETHODIMP CBaseControlWindow::put_FullScreenMode(long FullScreenMode) -{ - return E_NOTIMPL; -} - - -// This sets the auto show property, this property causes the base window to -// be displayed whenever we change state. This allows an application to have -// to do nothing to have the window appear but still allow them to change the -// default behaviour if for example they want to keep it hidden for longer - -STDMETHODIMP CBaseControlWindow::put_AutoShow(long AutoShow) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Check this is a valid automation boolean type - - if (AutoShow != OATRUE) { - if (AutoShow != OAFALSE) { - return E_INVALIDARG; - } - } - - m_bAutoShow = (AutoShow == OATRUE ? TRUE : FALSE); - return NOERROR; -} - - -// This can be called to get the current auto show flag. The flag is updated -// when we connect and disconnect and through this interface all of which are -// controlled and serialised by means of the main renderer critical section - -STDMETHODIMP CBaseControlWindow::get_AutoShow(__out long *AutoShow) -{ - CheckPointer(AutoShow,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *AutoShow = (m_bAutoShow == TRUE ? OATRUE : OAFALSE); - return NOERROR; -} - - -// Return the minimum ideal image size for the current video. This may differ -// to the actual video dimensions because we may be using DirectDraw hardware -// that has specific stretching requirements. For example the Cirrus Logic -// cards have a minimum stretch factor depending on the overlay surface size - -STDMETHODIMP -CBaseControlWindow::GetMinIdealImageSize(__out long *pWidth,__out long *pHeight) -{ - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - FILTER_STATE State; - - // Must not be stopped for this to work correctly - - m_pFilter->GetState(0,&State); - if (State == State_Stopped) { - return VFW_E_WRONG_STATE; - } - - RECT DefaultRect = GetDefaultRect(); - *pWidth = WIDTH(&DefaultRect); - *pHeight = HEIGHT(&DefaultRect); - return NOERROR; -} - - -// Return the maximum ideal image size for the current video. This may differ -// to the actual video dimensions because we may be using DirectDraw hardware -// that has specific stretching requirements. For example the Cirrus Logic -// cards have a maximum stretch factor depending on the overlay surface size - -STDMETHODIMP -CBaseControlWindow::GetMaxIdealImageSize(__out long *pWidth,__out long *pHeight) -{ - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - FILTER_STATE State; - - // Must not be stopped for this to work correctly - - m_pFilter->GetState(0,&State); - if (State == State_Stopped) { - return VFW_E_WRONG_STATE; - } - - RECT DefaultRect = GetDefaultRect(); - *pWidth = WIDTH(&DefaultRect); - *pHeight = HEIGHT(&DefaultRect); - return NOERROR; -} - - -// Allow an application to hide the cursor on our window - -STDMETHODIMP -CBaseControlWindow::HideCursor(long HideCursor) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - - // Check this is a valid automation boolean type - - if (HideCursor != OATRUE) { - if (HideCursor != OAFALSE) { - return E_INVALIDARG; - } - } - - m_bCursorHidden = (HideCursor == OATRUE ? TRUE : FALSE); - return NOERROR; -} - - -// Returns whether we have the cursor hidden or not - -STDMETHODIMP CBaseControlWindow::IsCursorHidden(__out long *CursorHidden) -{ - CheckPointer(CursorHidden,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - *CursorHidden = (m_bCursorHidden == TRUE ? OATRUE : OAFALSE); - return NOERROR; -} - - -// This class implements the IBasicVideo control functions (dual interface) -// we support a large number of properties and methods designed to allow the -// client (whether it be an automation controller or a C/C++ application) to -// set and get a number of video related properties such as the native video -// size. We support some methods that duplicate the properties but provide a -// more direct and efficient mechanism as many values may be changed in one - -CBaseControlVideo::CBaseControlVideo( - __inout CBaseFilter *pFilter, // Owning filter - __in CCritSec *pInterfaceLock, // Locking object - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // Normal COM ownership - __inout HRESULT *phr) : // OLE return code - - CBaseBasicVideo(pName,pUnk), - m_pFilter(pFilter), - m_pInterfaceLock(pInterfaceLock), - m_pPin(NULL) -{ - ASSERT(m_pFilter); - ASSERT(m_pInterfaceLock); - ASSERT(phr); -} - -// Return an approximate average time per frame - -STDMETHODIMP CBaseControlVideo::get_AvgTimePerFrame(__out REFTIME *pAvgTimePerFrame) -{ - CheckPointer(pAvgTimePerFrame,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - COARefTime AvgTime(pVideoInfo->AvgTimePerFrame); - *pAvgTimePerFrame = (REFTIME) AvgTime; - - return NOERROR; -} - - -// Return an approximate bit rate for the video - -STDMETHODIMP CBaseControlVideo::get_BitRate(__out long *pBitRate) -{ - CheckPointer(pBitRate,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pBitRate = pVideoInfo->dwBitRate; - return NOERROR; -} - - -// Return an approximate bit error rate - -STDMETHODIMP CBaseControlVideo::get_BitErrorRate(__out long *pBitErrorRate) -{ - CheckPointer(pBitErrorRate,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pBitErrorRate = pVideoInfo->dwBitErrorRate; - return NOERROR; -} - - -// This returns the current video width - -STDMETHODIMP CBaseControlVideo::get_VideoWidth(__out long *pVideoWidth) -{ - CheckPointer(pVideoWidth,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pVideoWidth = pVideoInfo->bmiHeader.biWidth; - return NOERROR; -} - - -// This returns the current video height - -STDMETHODIMP CBaseControlVideo::get_VideoHeight(__out long *pVideoHeight) -{ - CheckPointer(pVideoHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pVideoHeight = pVideoInfo->bmiHeader.biHeight; - return NOERROR; -} - - -// This returns the current palette the video is using as an array allocated -// by the user. To remain consistent we use PALETTEENTRY fields to return the -// colours in rather than RGBQUADs that multimedia decided to use. The memory -// is allocated by the user so we simple copy each in turn. We check that the -// number of entries requested and the start position offset are both valid -// If the number of entries evaluates to zero then we return an S_FALSE code - -STDMETHODIMP CBaseControlVideo::GetVideoPaletteEntries(long StartIndex, - long Entries, - __out long *pRetrieved, - __out_ecount_part(Entries, *pRetrieved) long *pPalette) -{ - CheckPointer(pRetrieved,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - CMediaType MediaType; - - // Get the video format from the derived class - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); - - // Is the current format palettised - - if (PALETTISED(pVideoInfo) == FALSE) { - *pRetrieved = 0; - return VFW_E_NO_PALETTE_AVAILABLE; - } - - // Do they just want to know how many are available - - if (pPalette == NULL) { - *pRetrieved = pHeader->biClrUsed; - return NOERROR; - } - - // Make sure the start position is a valid offset - - if (StartIndex >= (LONG) pHeader->biClrUsed || StartIndex < 0) { - *pRetrieved = 0; - return E_INVALIDARG; - } - - // Correct the number we can retrieve - - long Available = (long)pHeader->biClrUsed - StartIndex; - *pRetrieved = std::max(0l, std::min(Available, Entries)); - if (*pRetrieved == 0) { - return S_FALSE; - } - - // Copy the palette entries to the output buffer - - PALETTEENTRY *pEntries = (PALETTEENTRY *) pPalette; - RGBQUAD *pColours = COLORS(pVideoInfo) + StartIndex; - - for (LONG Count = 0;Count < *pRetrieved;Count++) { - pEntries[Count].peRed = pColours[Count].rgbRed; - pEntries[Count].peGreen = pColours[Count].rgbGreen; - pEntries[Count].peBlue = pColours[Count].rgbBlue; - pEntries[Count].peFlags = 0; - } - return NOERROR; -} - - -// This returns the current video dimensions as a method rather than a number -// of individual property get calls. For the same reasons as said before we -// cannot access the renderer media type directly as the window object thread -// may be updating it since dynamic format changes may change these values - -STDMETHODIMP CBaseControlVideo::GetVideoSize(__out long *pWidth,__out long *pHeight) -{ - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - - // Get the video format from the derived class - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - *pWidth = pVideoInfo->bmiHeader.biWidth; - *pHeight = pVideoInfo->bmiHeader.biHeight; - return NOERROR; -} - - -// Set the source video rectangle as left,top,right and bottom coordinates -// rather than left,top,width and height as per OLE automation interfaces -// Then pass the rectangle on to the window object to set the source - -STDMETHODIMP -CBaseControlVideo::SetSourcePosition(long Left,long Top,long Width,long Height) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - SourceRect.left = Left; - SourceRect.top = Top; - SourceRect.right = Left + Width; - SourceRect.bottom = Top + Height; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the source rectangle in left,top,width and height rather than the -// left,top,right and bottom values that RECT uses (and which the window -// object returns through GetSourceRect) which requires a little work - -STDMETHODIMP -CBaseControlVideo::GetSourcePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) -{ - // Should check the pointers are non NULL - - CheckPointer(pLeft,E_POINTER); - CheckPointer(pTop,E_POINTER); - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT SourceRect; - - CAutoLock cInterfaceLock(m_pInterfaceLock); - GetSourceRect(&SourceRect); - - *pLeft = SourceRect.left; - *pTop = SourceRect.top; - *pWidth = WIDTH(&SourceRect); - *pHeight = HEIGHT(&SourceRect); - - return NOERROR; -} - - -// Set the video destination as left,top,right and bottom coordinates rather -// than the left,top,width and height uses as per OLE automation interfaces -// Then pass the rectangle on to the window object to set the destination - -STDMETHODIMP -CBaseControlVideo::SetDestinationPosition(long Left,long Top,long Width,long Height) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - DestinationRect.left = Left; - DestinationRect.top = Top; - DestinationRect.right = Left + Width; - DestinationRect.bottom = Top + Height; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the destination rectangle in left,top,width and height rather than -// the left,top,right and bottom values that RECT uses (and which the window -// object returns through GetDestinationRect) which requires a little work - -STDMETHODIMP -CBaseControlVideo::GetDestinationPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) -{ - // Should check the pointers are not NULL - - CheckPointer(pLeft,E_POINTER); - CheckPointer(pTop,E_POINTER); - CheckPointer(pWidth,E_POINTER); - CheckPointer(pHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - RECT DestinationRect; - - CAutoLock cInterfaceLock(m_pInterfaceLock); - GetTargetRect(&DestinationRect); - - *pLeft = DestinationRect.left; - *pTop = DestinationRect.top; - *pWidth = WIDTH(&DestinationRect); - *pHeight = HEIGHT(&DestinationRect); - - return NOERROR; -} - - -// Set the source left position, the source rectangle we get back from the -// window object is a true rectangle in left,top,right and bottom positions -// so all we have to do is to update the left position and pass it back. We -// must keep the current width constant when we're updating this property - -STDMETHODIMP CBaseControlVideo::put_SourceLeft(long SourceLeft) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - GetSourceRect(&SourceRect); - SourceRect.right = SourceLeft + WIDTH(&SourceRect); - SourceRect.left = SourceLeft; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the current left source video position - -STDMETHODIMP CBaseControlVideo::get_SourceLeft(__out long *pSourceLeft) -{ - CheckPointer(pSourceLeft,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - - GetSourceRect(&SourceRect); - *pSourceLeft = SourceRect.left; - return NOERROR; -} - - -// Set the source width, we get the current source rectangle and then update -// the right position to be the left position (thereby keeping it constant) -// plus the new source width we are passed in (it expands to the right) - -STDMETHODIMP CBaseControlVideo::put_SourceWidth(long SourceWidth) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - GetSourceRect(&SourceRect); - SourceRect.right = SourceRect.left + SourceWidth; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the current source width - -STDMETHODIMP CBaseControlVideo::get_SourceWidth(__out long *pSourceWidth) -{ - CheckPointer(pSourceWidth,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - - GetSourceRect(&SourceRect); - *pSourceWidth = WIDTH(&SourceRect); - return NOERROR; -} - - -// Set the source top position - changing this property does not affect the -// current source height. So changing this shunts the source rectangle up and -// down appropriately. Changing the height complements this functionality by -// keeping the top position constant and simply changing the source height - -STDMETHODIMP CBaseControlVideo::put_SourceTop(long SourceTop) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - GetSourceRect(&SourceRect); - SourceRect.bottom = SourceTop + HEIGHT(&SourceRect); - SourceRect.top = SourceTop; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the current top position - -STDMETHODIMP CBaseControlVideo::get_SourceTop(__out long *pSourceTop) -{ - CheckPointer(pSourceTop,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - - GetSourceRect(&SourceRect); - *pSourceTop = SourceRect.top; - return NOERROR; -} - - -// Set the source height - -STDMETHODIMP CBaseControlVideo::put_SourceHeight(long SourceHeight) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - GetSourceRect(&SourceRect); - SourceRect.bottom = SourceRect.top + SourceHeight; - - // Check the source rectangle is valid - - HRESULT hr = CheckSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the source rectangle - - hr = SetSourceRect(&SourceRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the current source height - -STDMETHODIMP CBaseControlVideo::get_SourceHeight(__out long *pSourceHeight) -{ - CheckPointer(pSourceHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT SourceRect; - - GetSourceRect(&SourceRect); - *pSourceHeight = HEIGHT(&SourceRect); - return NOERROR; -} - - -// Set the target left position, the target rectangle we get back from the -// window object is a true rectangle in left,top,right and bottom positions -// so all we have to do is to update the left position and pass it back. We -// must keep the current width constant when we're updating this property - -STDMETHODIMP CBaseControlVideo::put_DestinationLeft(long DestinationLeft) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - GetTargetRect(&DestinationRect); - DestinationRect.right = DestinationLeft + WIDTH(&DestinationRect); - DestinationRect.left = DestinationLeft; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the left position for the destination rectangle - -STDMETHODIMP CBaseControlVideo::get_DestinationLeft(__out long *pDestinationLeft) -{ - CheckPointer(pDestinationLeft,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - GetTargetRect(&DestinationRect); - *pDestinationLeft = DestinationRect.left; - return NOERROR; -} - - -// Set the destination width - -STDMETHODIMP CBaseControlVideo::put_DestinationWidth(long DestinationWidth) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - GetTargetRect(&DestinationRect); - DestinationRect.right = DestinationRect.left + DestinationWidth; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the width for the destination rectangle - -STDMETHODIMP CBaseControlVideo::get_DestinationWidth(__out long *pDestinationWidth) -{ - CheckPointer(pDestinationWidth,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - GetTargetRect(&DestinationRect); - *pDestinationWidth = WIDTH(&DestinationRect); - return NOERROR; -} - - -// Set the target top position - changing this property does not affect the -// current target height. So changing this shunts the target rectangle up and -// down appropriately. Changing the height complements this functionality by -// keeping the top position constant and simply changing the target height - -STDMETHODIMP CBaseControlVideo::put_DestinationTop(long DestinationTop) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - GetTargetRect(&DestinationRect); - DestinationRect.bottom = DestinationTop + HEIGHT(&DestinationRect); - DestinationRect.top = DestinationTop; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the top position for the destination rectangle - -STDMETHODIMP CBaseControlVideo::get_DestinationTop(__out long *pDestinationTop) -{ - CheckPointer(pDestinationTop,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - GetTargetRect(&DestinationRect); - *pDestinationTop = DestinationRect.top; - return NOERROR; -} - - -// Set the destination height - -STDMETHODIMP CBaseControlVideo::put_DestinationHeight(long DestinationHeight) -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - GetTargetRect(&DestinationRect); - DestinationRect.bottom = DestinationRect.top + DestinationHeight; - - // Check the target rectangle is valid - - HRESULT hr = CheckTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - - // Now set the new target rectangle - - hr = SetTargetRect(&DestinationRect); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return the height for the destination rectangle - -STDMETHODIMP CBaseControlVideo::get_DestinationHeight(__out long *pDestinationHeight) -{ - CheckPointer(pDestinationHeight,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - RECT DestinationRect; - - GetTargetRect(&DestinationRect); - *pDestinationHeight = HEIGHT(&DestinationRect); - return NOERROR; -} - - -// Reset the source rectangle to the full video dimensions - -STDMETHODIMP CBaseControlVideo::SetDefaultSourcePosition() -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - HRESULT hr = SetDefaultSourceRect(); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return S_OK if we're using the default source otherwise S_FALSE - -STDMETHODIMP CBaseControlVideo::IsUsingDefaultSource() -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - return IsDefaultSourceRect(); -} - - -// Reset the video renderer to use the entire playback area - -STDMETHODIMP CBaseControlVideo::SetDefaultDestinationPosition() -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - HRESULT hr = SetDefaultTargetRect(); - if (FAILED(hr)) { - return hr; - } - return OnUpdateRectangles(); -} - - -// Return S_OK if we're using the default target otherwise S_FALSE - -STDMETHODIMP CBaseControlVideo::IsUsingDefaultDestination() -{ - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - return IsDefaultTargetRect(); -} - - -// Return a copy of the current image in the video renderer - -STDMETHODIMP -CBaseControlVideo::GetCurrentImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pVideoImage) -{ - CheckPointer(pBufferSize,E_POINTER); - CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); - CAutoLock cInterfaceLock(m_pInterfaceLock); - FILTER_STATE State; - - // Make sure we are in a paused state - - if (pVideoImage != NULL) { - m_pFilter->GetState(0,&State); - if (State != State_Paused) { - return VFW_E_NOT_PAUSED; - } - return GetStaticImage(pBufferSize,pVideoImage); - } - - // Just return the memory required - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - RECT SourceRect; - GetSourceRect(&SourceRect); - return GetImageSize(pVideoInfo,pBufferSize,&SourceRect); -} - - -// An application has two ways of using GetCurrentImage, one is to pass a real -// buffer which should be filled with the current image. The other is to pass -// a NULL buffer pointer which is interpreted as asking us to return how much -// memory is required for the image. The constraints for when the latter can -// be called are much looser. To calculate the memory required we synthesize -// a VIDEOINFO that takes into account the source rectangle that's being used - -HRESULT CBaseControlVideo::GetImageSize(__in VIDEOINFOHEADER *pVideoInfo, - __out long *pBufferSize, - __in RECT *pSourceRect) -{ - NOTE("Entering GetImageSize"); - ASSERT(pSourceRect); - - // Check we have the correct input parameters - - if (pSourceRect == NULL || - pVideoInfo == NULL || - pBufferSize == NULL) { - - return E_UNEXPECTED; - } - - // Is the data format compatible - - if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { - if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { - return E_INVALIDARG; - } - } - - ASSERT(IsRectEmpty(pSourceRect) == FALSE); - - BITMAPINFOHEADER bih; - bih.biWidth = WIDTH(pSourceRect); - bih.biHeight = HEIGHT(pSourceRect); - bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; - LONG Size = DIBSIZE(bih); - Size += GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; - *pBufferSize = Size; - - return NOERROR; -} - - -// Given an IMediaSample containing a linear buffer with an image and a type -// describing the bitmap make a rendering of the image into the output buffer -// This may be called by derived classes who render typical video images to -// handle the IBasicVideo GetCurrentImage method. The pVideoImage pointer may -// be NULL when passed to GetCurrentImage in which case GetImageSize will be -// called instead, which will just do the calculation of the memory required - -HRESULT CBaseControlVideo::CopyImage(IMediaSample *pMediaSample, - __in VIDEOINFOHEADER *pVideoInfo, - __inout long *pBufferSize, - __out_bcount_part(*pBufferSize, *pBufferSize) BYTE *pVideoImage, - __in RECT *pSourceRect) -{ - NOTE("Entering CopyImage"); - ASSERT(pSourceRect); - BYTE *pCurrentImage; - - // Check we have an image to copy - - if (pMediaSample == NULL || pSourceRect == NULL || - pVideoInfo == NULL || pVideoImage == NULL || - pBufferSize == NULL) { - - return E_UNEXPECTED; - } - - // Is the data format compatible - - if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { - if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { - return E_INVALIDARG; - } - } - - if (*pBufferSize < 0) { - return E_INVALIDARG; - } - - // Arbitrarily large size to prevent integer overflow problems - if (pVideoInfo->bmiHeader.biSize > 4096) - { - return E_INVALIDARG; - } - - ASSERT(IsRectEmpty(pSourceRect) == FALSE); - - BITMAPINFOHEADER bih; - bih.biWidth = WIDTH(pSourceRect); - bih.biHeight = HEIGHT(pSourceRect); - bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; - DWORD Size = GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; - DWORD Total; - DWORD dwDibSize; - - if( !ValidateBitmapInfoHeader( HEADER(pVideoInfo), Size)) { - return E_INVALIDARG; - } - - // ValidateBitmapInfoHeader checks this but for some reason code scanning - // tools aren't picking up the annotation - __analysis_assume(Size >= sizeof(BITMAPINFOHEADER)); - - if (FAILED(SAFE_DIBSIZE(&bih, &dwDibSize))) { - return E_INVALIDARG; - } - - if (FAILED(DWordAdd(Size, dwDibSize, &Total))) { - return E_INVALIDARG; - } - - // Make sure we have a large enough buffer - - if ((DWORD)*pBufferSize < Total) { - return E_OUTOFMEMORY; - } - - // Copy the BITMAPINFO - - CopyMemory((PVOID)pVideoImage, (PVOID)&pVideoInfo->bmiHeader, Size); - ((BITMAPINFOHEADER *)pVideoImage)->biWidth = WIDTH(pSourceRect); - ((BITMAPINFOHEADER *)pVideoImage)->biHeight = HEIGHT(pSourceRect); - ((BITMAPINFOHEADER *)pVideoImage)->biSizeImage = DIBSIZE(bih); - BYTE *pImageData = pVideoImage + Size; - - // Get the pointer to it's image data - - HRESULT hr = pMediaSample->GetPointer(&pCurrentImage); - if (FAILED(hr)) { - return hr; - } - - // Now we are ready to start copying the source scan lines - - LONG ScanLine = (pVideoInfo->bmiHeader.biBitCount / 8) * WIDTH(pSourceRect); - LONG LinesToSkip = pVideoInfo->bmiHeader.biHeight; - LinesToSkip -= pSourceRect->top + HEIGHT(pSourceRect); - pCurrentImage += LinesToSkip * DIBWIDTHBYTES(pVideoInfo->bmiHeader); - pCurrentImage += pSourceRect->left * (pVideoInfo->bmiHeader.biBitCount / 8); - - // Even money on this GP faulting sometime... - - for (LONG Line = 0;Line < HEIGHT(pSourceRect);Line++) { - CopyMemory((PVOID)pImageData, (PVOID)pCurrentImage, ScanLine); - pImageData += DIBWIDTHBYTES(*(BITMAPINFOHEADER *)pVideoImage); - pCurrentImage += DIBWIDTHBYTES(pVideoInfo->bmiHeader); - } - return NOERROR; -} - - -// Called when we change media types either during connection or dynamically -// We inform the filter graph and therefore the application that the video -// size may have changed, we don't bother looking to see if it really has as -// we leave that to the application - the dimensions are the event parameters - -HRESULT CBaseControlVideo::OnVideoSizeChange() -{ - // Get the video format from the derived class - - VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); - if (pVideoInfo == NULL) - return E_OUTOFMEMORY; - WORD Width = (WORD) pVideoInfo->bmiHeader.biWidth; - WORD Height = (WORD) pVideoInfo->bmiHeader.biHeight; - - return m_pFilter->NotifyEvent(EC_VIDEO_SIZE_CHANGED, - MAKELPARAM(Width,Height), - MAKEWPARAM(0,0)); -} - - -// Set the video source rectangle. We must check the source rectangle against -// the actual video dimensions otherwise when we come to draw the pictures we -// get access violations as GDI tries to touch data outside of the image data -// Although we store the rectangle in left, top, right and bottom coordinates -// instead of left, top, width and height as OLE uses we do take into account -// that the rectangle is used up to, but not including, the right column and -// bottom row of pixels, see the Win32 documentation on RECT for more details - -HRESULT CBaseControlVideo::CheckSourceRect(__in RECT *pSourceRect) -{ - CheckPointer(pSourceRect,E_POINTER); - LONG Width,Height; - GetVideoSize(&Width,&Height); - - // Check the coordinates are greater than zero - // and that the rectangle is valid (leftleft >= pSourceRect->right) || - (pSourceRect->left < 0) || - (pSourceRect->top >= pSourceRect->bottom) || - (pSourceRect->top < 0)) { - - return E_INVALIDARG; - } - - // Check the coordinates are less than the extents - - if ((pSourceRect->right > Width) || - (pSourceRect->bottom > Height)) { - - return E_INVALIDARG; - } - return NOERROR; -} - - -// Check the target rectangle has some valid coordinates, which amounts to -// little more than checking the destination rectangle isn't empty. Derived -// classes may call this when they have their SetTargetRect method called to -// check the rectangle validity, we do not update the rectangles passed in -// Although we store the rectangle in left, top, right and bottom coordinates -// instead of left, top, width and height as OLE uses we do take into account -// that the rectangle is used up to, but not including, the right column and -// bottom row of pixels, see the Win32 documentation on RECT for more details - -HRESULT CBaseControlVideo::CheckTargetRect(__in RECT *pTargetRect) -{ - // Check the pointer is valid - - if (pTargetRect == NULL) { - return E_POINTER; - } - - // These overflow the WIDTH and HEIGHT checks - - if (pTargetRect->left > pTargetRect->right || - pTargetRect->top > pTargetRect->bottom) { - return E_INVALIDARG; - } - - // Check the rectangle has valid coordinates - - if (WIDTH(pTargetRect) <= 0 || HEIGHT(pTargetRect) <= 0) { - return E_INVALIDARG; - } - - ASSERT(IsRectEmpty(pTargetRect) == FALSE); - return NOERROR; -} - +//------------------------------------------------------------------------------ +// File: WinCtrl.cpp +// +// Desc: DirectShow base classes - implements video control interface class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include +#include "checkbmi.h" + +// The control interface methods require us to be connected + +#define CheckConnected(pin,code) \ +{ \ + if (pin == NULL) { \ + ASSERT(!TEXT("Pin not set")); \ + } else if (pin->IsConnected() == FALSE) { \ + return (code); \ + } \ +} + +// This checks to see whether the window has a drain. An application can in +// most environments set the owner/parent of windows so that they appear in +// a compound document context (for example). In this case, the application +// would probably like to be told of any keyboard/mouse messages. Therefore +// we pass these messages on untranslated, returning TRUE if we're successful + +BOOL WINAPI PossiblyEatMessage(HWND hwndDrain, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (hwndDrain != NULL && !InSendMessage()) + { + switch (uMsg) + { + case WM_CHAR: + case WM_DEADCHAR: + case WM_KEYDOWN: + case WM_KEYUP: + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEACTIVATE: + case WM_MOUSEMOVE: + // If we pass this on we don't get any mouse clicks + //case WM_NCHITTEST: + case WM_NCLBUTTONDBLCLK: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCMBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMOUSEMOVE: + case WM_NCRBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + + DbgLog((LOG_TRACE, 2, TEXT("Forwarding %x to drain"))); + PostMessage(hwndDrain, uMsg, wParam, lParam); + + return TRUE; + } + } + return FALSE; +} + + +// This class implements the IVideoWindow control functions (dual interface) +// we support a large number of properties and methods designed to allow the +// client (whether it be an automation controller or a C/C++ application) to +// set and get a number of window related properties such as it's position. +// We also support some methods that duplicate the properties but provide a +// more direct and efficient mechanism as many values may be changed in one + +CBaseControlWindow::CBaseControlWindow( + __inout CBaseFilter *pFilter, // Owning filter + __in CCritSec *pInterfaceLock, // Locking object + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // Normal COM ownership + __inout HRESULT *phr) : // OLE return code + + CBaseVideoWindow(pName,pUnk), + m_pInterfaceLock(pInterfaceLock), + m_hwndOwner(NULL), + m_hwndDrain(NULL), + m_bAutoShow(TRUE), + m_pFilter(pFilter), + m_bCursorHidden(FALSE), + m_pPin(NULL) +{ + ASSERT(m_pFilter); + ASSERT(m_pInterfaceLock); + ASSERT(phr); + m_BorderColour = VIDEO_COLOUR; +} + + +// Set the title caption on the base window, we don't do any field checking +// as we really don't care what title they intend to have. We can always get +// it back again later with GetWindowText. The only other complication is to +// do the necessary string conversions between ANSI and OLE Unicode strings + +STDMETHODIMP CBaseControlWindow::put_Caption(__in BSTR strCaption) +{ + CheckPointer((PVOID)strCaption,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); +#ifdef UNICODE + SetWindowText(m_hwnd, strCaption); +#else + CHAR Caption[CAPTION]; + + WideCharToMultiByte(CP_ACP,0,strCaption,-1,Caption,CAPTION,NULL,NULL); + SetWindowText(m_hwnd, Caption); +#endif + return NOERROR; +} + + +// Get the current base window title caption, once again we do no real field +// checking. We allocate a string for the window title to be filled in with +// which ensures the interface doesn't fiddle around with getting memory. A +// BSTR is a normal C string with the length at position (-1), we use the +// WriteBSTR helper function to create the caption to try and avoid OLE32 + +STDMETHODIMP CBaseControlWindow::get_Caption(__out BSTR *pstrCaption) +{ + CheckPointer(pstrCaption,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + WCHAR WideCaption[CAPTION]; + +#ifdef UNICODE + GetWindowText(m_hwnd,WideCaption,CAPTION); +#else + // Convert the ASCII caption to a UNICODE string + + TCHAR Caption[CAPTION]; + GetWindowText(m_hwnd,Caption,CAPTION); + MultiByteToWideChar(CP_ACP,0,Caption,-1,WideCaption,CAPTION); +#endif + return WriteBSTR(pstrCaption,WideCaption); +} + + +// Set the window style using GWL_EXSTYLE + +STDMETHODIMP CBaseControlWindow::put_WindowStyleEx(long WindowStyleEx) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Should we be taking off WS_EX_TOPMOST + + if (GetWindowLong(m_hwnd,GWL_EXSTYLE) & WS_EX_TOPMOST) { + if ((WindowStyleEx & WS_EX_TOPMOST) == 0) { + SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) FALSE,(LPARAM) 0); + } + } + + // Likewise should we be adding WS_EX_TOPMOST + + if (WindowStyleEx & WS_EX_TOPMOST) { + SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) TRUE,(LPARAM) 0); + WindowStyleEx &= (~WS_EX_TOPMOST); + if (WindowStyleEx == 0) return NOERROR; + } + return DoSetWindowStyle(WindowStyleEx,GWL_EXSTYLE); +} + + +// Gets the current GWL_EXSTYLE base window style + +STDMETHODIMP CBaseControlWindow::get_WindowStyleEx(__out long *pWindowStyleEx) +{ + CheckPointer(pWindowStyleEx,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoGetWindowStyle(pWindowStyleEx,GWL_EXSTYLE); +} + + +// Set the window style using GWL_STYLE + +STDMETHODIMP CBaseControlWindow::put_WindowStyle(long WindowStyle) +{ + // These styles cannot be changed dynamically + + if ((WindowStyle & WS_DISABLED) || + (WindowStyle & WS_ICONIC) || + (WindowStyle & WS_MAXIMIZE) || + (WindowStyle & WS_MINIMIZE) || + (WindowStyle & WS_HSCROLL) || + (WindowStyle & WS_VSCROLL)) { + + return E_INVALIDARG; + } + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoSetWindowStyle(WindowStyle,GWL_STYLE); +} + + +// Get the current GWL_STYLE base window style + +STDMETHODIMP CBaseControlWindow::get_WindowStyle(__out long *pWindowStyle) +{ + CheckPointer(pWindowStyle,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + return DoGetWindowStyle(pWindowStyle,GWL_STYLE); +} + + +// Change the base window style or the extended styles depending on whether +// WindowLong is GWL_STYLE or GWL_EXSTYLE. We must call SetWindowPos to have +// the window displayed in it's new style after the change which is a little +// tricky if the window is not currently visible as we realise it offscreen. +// In most cases the client will call get_WindowStyle before they call this +// and then AND and OR in extra bit settings according to the requirements + +HRESULT CBaseControlWindow::DoSetWindowStyle(long Style,long WindowLong) +{ + RECT WindowRect; + + // Get the window's visibility before setting the style + BOOL bVisible = IsWindowVisible(m_hwnd); + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + // Set the new style flags for the window + SetWindowLong(m_hwnd,WindowLong,Style); + UINT WindowFlags = SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE; + WindowFlags |= SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; + + // Show the window again in the current position + + if (bVisible == TRUE) { + + SetWindowPos(m_hwnd, // Base window handle + HWND_TOP, // Just a place holder + 0,0,0,0, // Leave size and position + WindowFlags); // Just draw it again + + return NOERROR; + } + + // Move the window offscreen so the user doesn't see the changes + + MoveWindow((HWND) m_hwnd, // Base window handle + GetSystemMetrics(SM_CXSCREEN), // Current desktop width + GetSystemMetrics(SM_CYSCREEN), // Likewise it's height + WIDTH(&WindowRect), // Use the same width + HEIGHT(&WindowRect), // Keep height same to + TRUE); // May as well repaint + + // Now show the previously hidden window + + SetWindowPos(m_hwnd, // Base window handle + HWND_TOP, // Just a place holder + 0,0,0,0, // Leave size and position + WindowFlags); // Just draw it again + + ShowWindow(m_hwnd,SW_HIDE); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + MoveWindow((HWND) m_hwnd, // Base window handle + WindowRect.left, // Existing x coordinate + WindowRect.top, // Existing y coordinate + WIDTH(&WindowRect), // Use the same width + HEIGHT(&WindowRect), // Keep height same to + TRUE); // May as well repaint + + return NOERROR; +} + + +// Get the current base window style (either GWL_STYLE or GWL_EXSTYLE) + +HRESULT CBaseControlWindow::DoGetWindowStyle(__out long *pStyle,long WindowLong) +{ + *pStyle = GetWindowLong(m_hwnd,WindowLong); + return NOERROR; +} + + +// Change the visibility of the base window, this takes the same parameters +// as the ShowWindow Win32 API does, so the client can have the window hidden +// or shown, minimised to an icon, or maximised to play in full screen mode +// We pass the request on to the base window to actually make the change + +STDMETHODIMP CBaseControlWindow::put_WindowState(long WindowState) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + DoShowWindow(WindowState); + return NOERROR; +} + + +// Get the current window state, this function returns a subset of the SW bit +// settings available in ShowWindow, if the window is visible then SW_SHOW is +// set, if it is hidden then the SW_HIDDEN is set, if it is either minimised +// or maximised then the SW_MINIMIZE or SW_MAXIMIZE is set respectively. The +// other SW bit settings are really set commands not readable output values + +STDMETHODIMP CBaseControlWindow::get_WindowState(__out long *pWindowState) +{ + CheckPointer(pWindowState,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + ASSERT(pWindowState); + *pWindowState = FALSE; + + // Is the window visible, a window is termed visible if it is somewhere on + // the current desktop even if it is completely obscured by other windows + // so the flag is a style for each window set with the WS_VISIBLE bit + + if (IsWindowVisible(m_hwnd) == TRUE) { + + // Is the base window iconic + if (IsIconic(m_hwnd) == TRUE) { + *pWindowState |= SW_MINIMIZE; + } + + // Has the window been maximised + else if (IsZoomed(m_hwnd) == TRUE) { + *pWindowState |= SW_MAXIMIZE; + } + + // Window is normal + else { + *pWindowState |= SW_SHOW; + } + + } else { + *pWindowState |= SW_HIDE; + } + return NOERROR; +} + + +// This makes sure that any palette we realise in the base window (through a +// media type or through the overlay interface) is done in the background and +// is therefore mapped to existing device entries rather than taking it over +// as it will do when we this window gets the keyboard focus. An application +// uses this to make sure it doesn't have it's palette removed by the window + +STDMETHODIMP CBaseControlWindow::put_BackgroundPalette(long BackgroundPalette) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cWindowLock(&m_WindowLock); + + // Check this is a valid automation boolean type + + if (BackgroundPalette != OATRUE) { + if (BackgroundPalette != OAFALSE) { + return E_INVALIDARG; + } + } + + // Make sure the window realises any palette it has again + + m_bBackground = (BackgroundPalette == OATRUE ? TRUE : FALSE); + PostMessage(m_hwnd,m_RealizePalette,0,0); + PaintWindow(FALSE); + + return NOERROR; +} + + +// This returns the current background realisation setting + +STDMETHODIMP +CBaseControlWindow::get_BackgroundPalette(__out long *pBackgroundPalette) +{ + CheckPointer(pBackgroundPalette,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cWindowLock(&m_WindowLock); + + // Get the current background palette setting + + *pBackgroundPalette = (m_bBackground == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Change the visibility of the base window + +STDMETHODIMP CBaseControlWindow::put_Visible(long Visible) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (Visible != OATRUE) { + if (Visible != OAFALSE) { + return E_INVALIDARG; + } + } + + // Convert the boolean visibility into SW_SHOW and SW_HIDE + + INT Mode = (Visible == OATRUE ? SW_SHOWNORMAL : SW_HIDE); + DoShowWindow(Mode); + return NOERROR; +} + + +// Return OATRUE if the window is currently visible otherwise OAFALSE + +STDMETHODIMP CBaseControlWindow::get_Visible(__out long *pVisible) +{ + CheckPointer(pVisible,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // See if the base window has a WS_VISIBLE style - this will return TRUE + // even if the window is completely obscured by other desktop windows, we + // return FALSE if the window is not showing because of earlier calls + + BOOL Mode = IsWindowVisible(m_hwnd); + *pVisible = (Mode == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Change the left position of the base window. This keeps the window width +// and height properties the same so it effectively shunts the window left or +// right accordingly - there is the Width property to change that dimension + +STDMETHODIMP CBaseControlWindow::put_Left(long Left) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Get the current window position in a RECT + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + Left, // New left position + WindowRect.top, // Leave top alone + WindowRect.right, // The WIDTH (not right) + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window options + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window left position + +STDMETHODIMP CBaseControlWindow::get_Left(__out long *pLeft) +{ + CheckPointer(pLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pLeft = WindowRect.left; + return NOERROR; +} + + +// Change the current width of the base window. This property complements the +// left position property so we must keep the left edge constant and expand or +// contract to the right, the alternative would be to change the left edge so +// keeping the right edge constant but this is maybe a little more intuitive + +STDMETHODIMP CBaseControlWindow::put_Width(long Width) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + // This seems to have a bug in that calling SetWindowPos on a window with + // just the width changing causes it to ignore the width that you pass in + // and sets it to a mimimum value of 110 pixels wide (Windows NT 3.51) + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + WindowRect.top, // Leave top alone + Width, // New WIDTH dimension + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window options + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window width + +STDMETHODIMP CBaseControlWindow::get_Width(__out long *pWidth) +{ + CheckPointer(pWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pWidth = WindowRect.right - WindowRect.left; + return NOERROR; +} + + +// This allows the client program to change the top position for the window in +// the same way that changing the left position does not affect the width of +// the image so changing the top position does not affect the window height + +STDMETHODIMP CBaseControlWindow::put_Top(long Top) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Get the current window position in a RECT + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + WindowRect.bottom = WindowRect.bottom - WindowRect.top; + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + Top, // New top position + WindowRect.right, // The WIDTH (not right) + WindowRect.bottom, // The HEIGHT (not bottom) + WindowFlags); // Show window flags + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window top position + +STDMETHODIMP CBaseControlWindow::get_Top(long *pTop) +{ + CheckPointer(pTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pTop = WindowRect.top; + return NOERROR; +} + + +// Change the height of the window, this complements the top property so when +// we change this we must keep the top position for the base window, as said +// before we could keep the bottom and grow upwards although this is perhaps +// a little more intuitive since we already have a top position property + +STDMETHODIMP CBaseControlWindow::put_Height(long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + RECT WindowRect; + + // Adjust the coordinates ready for SetWindowPos, the window rectangle we + // get back from GetWindowRect is in left,top,right and bottom while the + // coordinates SetWindowPos wants are left,top,width and height values + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + if (GetParent(m_hwnd)) { + + MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2); + } + + WindowRect.right = WindowRect.right - WindowRect.left; + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Leave left alone + WindowRect.top, // Leave top alone + WindowRect.right, // The WIDTH (not right) + Height, // New height dimension + WindowFlags); // Show window flags + + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// Return the current base window height + +STDMETHODIMP CBaseControlWindow::get_Height(__out long *pHeight) +{ + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + *pHeight = WindowRect.bottom - WindowRect.top; + return NOERROR; +} + + +// This can be called to change the owning window. Setting the owner is done +// through this function, however to make the window a true child window the +// style must also be set to WS_CHILD. After resetting the owner to NULL an +// application should also set the style to WS_OVERLAPPED | WS_CLIPCHILDREN. + +// We cannot lock the object here because the SetParent causes an interthread +// SendMessage to the owner window. If they are in GetState we will sit here +// incomplete with the critical section locked therefore blocking out source +// filter threads from accessing us. Because the source thread can't enter us +// it can't get buffers or call EndOfStream so the GetState will not complete + +STDMETHODIMP CBaseControlWindow::put_Owner(OAHWND Owner) +{ + // Check we are connected otherwise reject the call + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + m_hwndOwner = (HWND) Owner; + HWND hwndParent = m_hwndOwner; + + // Add or remove WS_CHILD as appropriate + + LONG Style = GetWindowLong(m_hwnd,GWL_STYLE); + if (Owner == NULL) { + Style &= (~WS_CHILD); + } else { + Style |= (WS_CHILD); + } + SetWindowLong(m_hwnd,GWL_STYLE,Style); + + // Don't call this with the filter locked + + SetParent(m_hwnd,hwndParent); + + PaintWindow(TRUE); + NOTE1("Changed parent %lx",hwndParent); + + return NOERROR; +} + + +// This complements the put_Owner to get the current owning window property +// we always return NOERROR although the returned window handle may be NULL +// to indicate no owning window (the desktop window doesn't qualify as one) +// If an application sets the owner we call SetParent, however that returns +// NULL until the WS_CHILD bit is set on, so we store the owner internally + +STDMETHODIMP CBaseControlWindow::get_Owner(__out OAHWND *Owner) +{ + CheckPointer(Owner,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Owner = (OAHWND) m_hwndOwner; + return NOERROR; +} + + +// And renderer supporting IVideoWindow may have an HWND set who will get any +// keyboard and mouse messages we receive posted on to them. This is separate +// from setting an owning window. By separating the two, applications may get +// messages sent on even when they have set no owner (perhaps it's maximised) + +STDMETHODIMP CBaseControlWindow::put_MessageDrain(OAHWND Drain) +{ + // Check we are connected otherwise reject the call + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + m_hwndDrain = (HWND) Drain; + return NOERROR; +} + + +// Return the current message drain + +STDMETHODIMP CBaseControlWindow::get_MessageDrain(__out OAHWND *Drain) +{ + CheckPointer(Drain,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Drain = (OAHWND) m_hwndDrain; + return NOERROR; +} + + +// This is called by the filter graph to inform us of a message we should know +// is being sent to our owning window. We have this because as a child window +// we do not get certain messages that are only sent to top level windows. We +// must see the palette changed/changing/query messages so that we know if we +// have the foreground palette or not. We pass the message on to our window +// using SendMessage - this will cause an interthread send message to occur + +STDMETHODIMP +CBaseControlWindow::NotifyOwnerMessage(OAHWND hwnd, // Window handle + long uMsg, // Message ID + LONG_PTR wParam, // Parameters + LONG_PTR lParam) // for message +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Only interested in these Windows messages + + switch (uMsg) { + + case WM_SYSCOLORCHANGE: + case WM_PALETTECHANGED: + case WM_PALETTEISCHANGING: + case WM_QUERYNEWPALETTE: + case WM_DEVMODECHANGE: + case WM_DISPLAYCHANGE: + case WM_ACTIVATEAPP: + + // If we do not have an owner then ignore + + if (m_hwndOwner == NULL) { + return NOERROR; + } + SendMessage(m_hwnd,uMsg,(WPARAM)wParam,(LPARAM)lParam); + break; + + // do NOT fwd WM_MOVE. the parameters are the location of the parent + // window, NOT what the renderer should be looking at. But we need + // to make sure the overlay is moved with the parent window, so we + // do this. + case WM_MOVE: + PostMessage(m_hwnd,WM_PAINT,0,0); + break; + } + return NOERROR; +} + + +// Allow an application to have us set the base window in the foreground. We +// have this because it is difficult for one thread to do do this to a window +// owned by another thread. We ask the base window class to do the real work + +STDMETHODIMP CBaseControlWindow::SetWindowForeground(long Focus) +{ + // Check this is a valid automation boolean type + + if (Focus != OATRUE) { + if (Focus != OAFALSE) { + return E_INVALIDARG; + } + } + + // We shouldn't lock as this sends a message + + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bFocus = (Focus == OATRUE ? TRUE : FALSE); + DoSetWindowForeground(bFocus); + + return NOERROR; +} + + +// This allows a client to set the complete window size and position in one +// atomic operation. The same affect can be had by changing each dimension +// in turn through their individual properties although some flashing will +// occur as each of them gets updated (they are better set at design time) + +STDMETHODIMP +CBaseControlWindow::SetWindowPosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + BOOL bSuccess; + + // Set the new size and position + UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE; + + ASSERT(IsWindow(m_hwnd)); + bSuccess = SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + Left, // Left position + Top, // Top position + Width, // Window width + Height, // Window height + WindowFlags); // Show window flags + ASSERT(bSuccess); +#ifdef _DEBUG + DbgLog((LOG_TRACE, 1, TEXT("SWP failed error %d"), GetLastError())); +#endif + if (bSuccess == FALSE) { + return E_INVALIDARG; + } + return NOERROR; +} + + +// This complements the SetWindowPosition to return the current window place +// in device coordinates. As before the same information can be retrived by +// calling the property get functions individually but this is atomic and is +// therefore more suitable to a live environment rather than design time + +STDMETHODIMP +CBaseControlWindow::GetWindowPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT WindowRect; + + // Get the current window coordinates + + EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect)); + + // Convert the RECT into left,top,width and height values + + *pLeft = WindowRect.left; + *pTop = WindowRect.top; + *pWidth = WindowRect.right - WindowRect.left; + *pHeight = WindowRect.bottom - WindowRect.top; + + return NOERROR; +} + + +// When a window is maximised or iconic calling GetWindowPosition will return +// the current window position (likewise for the properties). However if the +// restored size (ie the size we'll return to when normally shown) is needed +// then this should be used. When in a normal position (neither iconic nor +// maximised) then this returns the same coordinates as GetWindowPosition + +STDMETHODIMP +CBaseControlWindow::GetRestorePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Use GetWindowPlacement to find the restore position + + WINDOWPLACEMENT Place; + Place.length = sizeof(WINDOWPLACEMENT); + EXECUTE_ASSERT(GetWindowPlacement(m_hwnd,&Place)); + + RECT WorkArea; + + // We must take into account any task bar present + + if (SystemParametersInfo(SPI_GETWORKAREA,0,&WorkArea,FALSE) == TRUE) { + if (GetParent(m_hwnd) == NULL) { + Place.rcNormalPosition.top += WorkArea.top; + Place.rcNormalPosition.bottom += WorkArea.top; + Place.rcNormalPosition.left += WorkArea.left; + Place.rcNormalPosition.right += WorkArea.left; + } + } + + // Convert the RECT into left,top,width and height values + + *pLeft = Place.rcNormalPosition.left; + *pTop = Place.rcNormalPosition.top; + *pWidth = Place.rcNormalPosition.right - Place.rcNormalPosition.left; + *pHeight = Place.rcNormalPosition.bottom - Place.rcNormalPosition.top; + + return NOERROR; +} + + +// Return the current border colour, if we are playing something to a subset +// of the base window display there is an outside area exposed. The default +// action is to paint this colour in the Windows background colour (defined +// as value COLOR_WINDOW) We reset to this default when we're disconnected + +STDMETHODIMP CBaseControlWindow::get_BorderColor(__out long *Color) +{ + CheckPointer(Color,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *Color = (long) m_BorderColour; + return NOERROR; +} + + +// This can be called to set the current border colour + +STDMETHODIMP CBaseControlWindow::put_BorderColor(long Color) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Have the window repainted with the new border colour + + m_BorderColour = (COLORREF) Color; + PaintWindow(TRUE); + return NOERROR; +} + + +// Delegate fullscreen handling to plug in distributor + +STDMETHODIMP CBaseControlWindow::get_FullScreenMode(__out long *FullScreenMode) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CheckPointer(FullScreenMode,E_POINTER); + return E_NOTIMPL; +} + + +// Delegate fullscreen handling to plug in distributor + +STDMETHODIMP CBaseControlWindow::put_FullScreenMode(long FullScreenMode) +{ + return E_NOTIMPL; +} + + +// This sets the auto show property, this property causes the base window to +// be displayed whenever we change state. This allows an application to have +// to do nothing to have the window appear but still allow them to change the +// default behaviour if for example they want to keep it hidden for longer + +STDMETHODIMP CBaseControlWindow::put_AutoShow(long AutoShow) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (AutoShow != OATRUE) { + if (AutoShow != OAFALSE) { + return E_INVALIDARG; + } + } + + m_bAutoShow = (AutoShow == OATRUE ? TRUE : FALSE); + return NOERROR; +} + + +// This can be called to get the current auto show flag. The flag is updated +// when we connect and disconnect and through this interface all of which are +// controlled and serialised by means of the main renderer critical section + +STDMETHODIMP CBaseControlWindow::get_AutoShow(__out long *AutoShow) +{ + CheckPointer(AutoShow,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *AutoShow = (m_bAutoShow == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// Return the minimum ideal image size for the current video. This may differ +// to the actual video dimensions because we may be using DirectDraw hardware +// that has specific stretching requirements. For example the Cirrus Logic +// cards have a minimum stretch factor depending on the overlay surface size + +STDMETHODIMP +CBaseControlWindow::GetMinIdealImageSize(__out long *pWidth,__out long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + FILTER_STATE State; + + // Must not be stopped for this to work correctly + + m_pFilter->GetState(0,&State); + if (State == State_Stopped) { + return VFW_E_WRONG_STATE; + } + + RECT DefaultRect = GetDefaultRect(); + *pWidth = WIDTH(&DefaultRect); + *pHeight = HEIGHT(&DefaultRect); + return NOERROR; +} + + +// Return the maximum ideal image size for the current video. This may differ +// to the actual video dimensions because we may be using DirectDraw hardware +// that has specific stretching requirements. For example the Cirrus Logic +// cards have a maximum stretch factor depending on the overlay surface size + +STDMETHODIMP +CBaseControlWindow::GetMaxIdealImageSize(__out long *pWidth,__out long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + FILTER_STATE State; + + // Must not be stopped for this to work correctly + + m_pFilter->GetState(0,&State); + if (State == State_Stopped) { + return VFW_E_WRONG_STATE; + } + + RECT DefaultRect = GetDefaultRect(); + *pWidth = WIDTH(&DefaultRect); + *pHeight = HEIGHT(&DefaultRect); + return NOERROR; +} + + +// Allow an application to hide the cursor on our window + +STDMETHODIMP +CBaseControlWindow::HideCursor(long HideCursor) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + + // Check this is a valid automation boolean type + + if (HideCursor != OATRUE) { + if (HideCursor != OAFALSE) { + return E_INVALIDARG; + } + } + + m_bCursorHidden = (HideCursor == OATRUE ? TRUE : FALSE); + return NOERROR; +} + + +// Returns whether we have the cursor hidden or not + +STDMETHODIMP CBaseControlWindow::IsCursorHidden(__out long *CursorHidden) +{ + CheckPointer(CursorHidden,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + *CursorHidden = (m_bCursorHidden == TRUE ? OATRUE : OAFALSE); + return NOERROR; +} + + +// This class implements the IBasicVideo control functions (dual interface) +// we support a large number of properties and methods designed to allow the +// client (whether it be an automation controller or a C/C++ application) to +// set and get a number of video related properties such as the native video +// size. We support some methods that duplicate the properties but provide a +// more direct and efficient mechanism as many values may be changed in one + +CBaseControlVideo::CBaseControlVideo( + __inout CBaseFilter *pFilter, // Owning filter + __in CCritSec *pInterfaceLock, // Locking object + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // Normal COM ownership + __inout HRESULT *phr) : // OLE return code + + CBaseBasicVideo(pName,pUnk), + m_pFilter(pFilter), + m_pInterfaceLock(pInterfaceLock), + m_pPin(NULL) +{ + ASSERT(m_pFilter); + ASSERT(m_pInterfaceLock); + ASSERT(phr); +} + +// Return an approximate average time per frame + +STDMETHODIMP CBaseControlVideo::get_AvgTimePerFrame(__out REFTIME *pAvgTimePerFrame) +{ + CheckPointer(pAvgTimePerFrame,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + COARefTime AvgTime(pVideoInfo->AvgTimePerFrame); + *pAvgTimePerFrame = (REFTIME) AvgTime; + + return NOERROR; +} + + +// Return an approximate bit rate for the video + +STDMETHODIMP CBaseControlVideo::get_BitRate(__out long *pBitRate) +{ + CheckPointer(pBitRate,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pBitRate = pVideoInfo->dwBitRate; + return NOERROR; +} + + +// Return an approximate bit error rate + +STDMETHODIMP CBaseControlVideo::get_BitErrorRate(__out long *pBitErrorRate) +{ + CheckPointer(pBitErrorRate,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pBitErrorRate = pVideoInfo->dwBitErrorRate; + return NOERROR; +} + + +// This returns the current video width + +STDMETHODIMP CBaseControlVideo::get_VideoWidth(__out long *pVideoWidth) +{ + CheckPointer(pVideoWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pVideoWidth = pVideoInfo->bmiHeader.biWidth; + return NOERROR; +} + + +// This returns the current video height + +STDMETHODIMP CBaseControlVideo::get_VideoHeight(__out long *pVideoHeight) +{ + CheckPointer(pVideoHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pVideoHeight = pVideoInfo->bmiHeader.biHeight; + return NOERROR; +} + + +// This returns the current palette the video is using as an array allocated +// by the user. To remain consistent we use PALETTEENTRY fields to return the +// colours in rather than RGBQUADs that multimedia decided to use. The memory +// is allocated by the user so we simple copy each in turn. We check that the +// number of entries requested and the start position offset are both valid +// If the number of entries evaluates to zero then we return an S_FALSE code + +STDMETHODIMP CBaseControlVideo::GetVideoPaletteEntries(long StartIndex, + long Entries, + __out long *pRetrieved, + __out_ecount_part(Entries, *pRetrieved) long *pPalette) +{ + CheckPointer(pRetrieved,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + CMediaType MediaType; + + // Get the video format from the derived class + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); + + // Is the current format palettised + + if (PALETTISED(pVideoInfo) == FALSE) { + *pRetrieved = 0; + return VFW_E_NO_PALETTE_AVAILABLE; + } + + // Do they just want to know how many are available + + if (pPalette == NULL) { + *pRetrieved = pHeader->biClrUsed; + return NOERROR; + } + + // Make sure the start position is a valid offset + + if (StartIndex >= (LONG) pHeader->biClrUsed || StartIndex < 0) { + *pRetrieved = 0; + return E_INVALIDARG; + } + + // Correct the number we can retrieve + + long Available = (long)pHeader->biClrUsed - StartIndex; + *pRetrieved = std::max(0l, std::min(Available, Entries)); + if (*pRetrieved == 0) { + return S_FALSE; + } + + // Copy the palette entries to the output buffer + + PALETTEENTRY *pEntries = (PALETTEENTRY *) pPalette; + RGBQUAD *pColours = COLORS(pVideoInfo) + StartIndex; + + for (LONG Count = 0;Count < *pRetrieved;Count++) { + pEntries[Count].peRed = pColours[Count].rgbRed; + pEntries[Count].peGreen = pColours[Count].rgbGreen; + pEntries[Count].peBlue = pColours[Count].rgbBlue; + pEntries[Count].peFlags = 0; + } + return NOERROR; +} + + +// This returns the current video dimensions as a method rather than a number +// of individual property get calls. For the same reasons as said before we +// cannot access the renderer media type directly as the window object thread +// may be updating it since dynamic format changes may change these values + +STDMETHODIMP CBaseControlVideo::GetVideoSize(__out long *pWidth,__out long *pHeight) +{ + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + + // Get the video format from the derived class + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + *pWidth = pVideoInfo->bmiHeader.biWidth; + *pHeight = pVideoInfo->bmiHeader.biHeight; + return NOERROR; +} + + +// Set the source video rectangle as left,top,right and bottom coordinates +// rather than left,top,width and height as per OLE automation interfaces +// Then pass the rectangle on to the window object to set the source + +STDMETHODIMP +CBaseControlVideo::SetSourcePosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + SourceRect.left = Left; + SourceRect.top = Top; + SourceRect.right = Left + Width; + SourceRect.bottom = Top + Height; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the source rectangle in left,top,width and height rather than the +// left,top,right and bottom values that RECT uses (and which the window +// object returns through GetSourceRect) which requires a little work + +STDMETHODIMP +CBaseControlVideo::GetSourcePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) +{ + // Should check the pointers are non NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT SourceRect; + + CAutoLock cInterfaceLock(m_pInterfaceLock); + GetSourceRect(&SourceRect); + + *pLeft = SourceRect.left; + *pTop = SourceRect.top; + *pWidth = WIDTH(&SourceRect); + *pHeight = HEIGHT(&SourceRect); + + return NOERROR; +} + + +// Set the video destination as left,top,right and bottom coordinates rather +// than the left,top,width and height uses as per OLE automation interfaces +// Then pass the rectangle on to the window object to set the destination + +STDMETHODIMP +CBaseControlVideo::SetDestinationPosition(long Left,long Top,long Width,long Height) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + DestinationRect.left = Left; + DestinationRect.top = Top; + DestinationRect.right = Left + Width; + DestinationRect.bottom = Top + Height; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the destination rectangle in left,top,width and height rather than +// the left,top,right and bottom values that RECT uses (and which the window +// object returns through GetDestinationRect) which requires a little work + +STDMETHODIMP +CBaseControlVideo::GetDestinationPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight) +{ + // Should check the pointers are not NULL + + CheckPointer(pLeft,E_POINTER); + CheckPointer(pTop,E_POINTER); + CheckPointer(pWidth,E_POINTER); + CheckPointer(pHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + RECT DestinationRect; + + CAutoLock cInterfaceLock(m_pInterfaceLock); + GetTargetRect(&DestinationRect); + + *pLeft = DestinationRect.left; + *pTop = DestinationRect.top; + *pWidth = WIDTH(&DestinationRect); + *pHeight = HEIGHT(&DestinationRect); + + return NOERROR; +} + + +// Set the source left position, the source rectangle we get back from the +// window object is a true rectangle in left,top,right and bottom positions +// so all we have to do is to update the left position and pass it back. We +// must keep the current width constant when we're updating this property + +STDMETHODIMP CBaseControlVideo::put_SourceLeft(long SourceLeft) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.right = SourceLeft + WIDTH(&SourceRect); + SourceRect.left = SourceLeft; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current left source video position + +STDMETHODIMP CBaseControlVideo::get_SourceLeft(__out long *pSourceLeft) +{ + CheckPointer(pSourceLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceLeft = SourceRect.left; + return NOERROR; +} + + +// Set the source width, we get the current source rectangle and then update +// the right position to be the left position (thereby keeping it constant) +// plus the new source width we are passed in (it expands to the right) + +STDMETHODIMP CBaseControlVideo::put_SourceWidth(long SourceWidth) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.right = SourceRect.left + SourceWidth; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current source width + +STDMETHODIMP CBaseControlVideo::get_SourceWidth(__out long *pSourceWidth) +{ + CheckPointer(pSourceWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceWidth = WIDTH(&SourceRect); + return NOERROR; +} + + +// Set the source top position - changing this property does not affect the +// current source height. So changing this shunts the source rectangle up and +// down appropriately. Changing the height complements this functionality by +// keeping the top position constant and simply changing the source height + +STDMETHODIMP CBaseControlVideo::put_SourceTop(long SourceTop) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.bottom = SourceTop + HEIGHT(&SourceRect); + SourceRect.top = SourceTop; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current top position + +STDMETHODIMP CBaseControlVideo::get_SourceTop(__out long *pSourceTop) +{ + CheckPointer(pSourceTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceTop = SourceRect.top; + return NOERROR; +} + + +// Set the source height + +STDMETHODIMP CBaseControlVideo::put_SourceHeight(long SourceHeight) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + GetSourceRect(&SourceRect); + SourceRect.bottom = SourceRect.top + SourceHeight; + + // Check the source rectangle is valid + + HRESULT hr = CheckSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the source rectangle + + hr = SetSourceRect(&SourceRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the current source height + +STDMETHODIMP CBaseControlVideo::get_SourceHeight(__out long *pSourceHeight) +{ + CheckPointer(pSourceHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT SourceRect; + + GetSourceRect(&SourceRect); + *pSourceHeight = HEIGHT(&SourceRect); + return NOERROR; +} + + +// Set the target left position, the target rectangle we get back from the +// window object is a true rectangle in left,top,right and bottom positions +// so all we have to do is to update the left position and pass it back. We +// must keep the current width constant when we're updating this property + +STDMETHODIMP CBaseControlVideo::put_DestinationLeft(long DestinationLeft) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.right = DestinationLeft + WIDTH(&DestinationRect); + DestinationRect.left = DestinationLeft; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the left position for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationLeft(__out long *pDestinationLeft) +{ + CheckPointer(pDestinationLeft,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationLeft = DestinationRect.left; + return NOERROR; +} + + +// Set the destination width + +STDMETHODIMP CBaseControlVideo::put_DestinationWidth(long DestinationWidth) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.right = DestinationRect.left + DestinationWidth; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the width for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationWidth(__out long *pDestinationWidth) +{ + CheckPointer(pDestinationWidth,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationWidth = WIDTH(&DestinationRect); + return NOERROR; +} + + +// Set the target top position - changing this property does not affect the +// current target height. So changing this shunts the target rectangle up and +// down appropriately. Changing the height complements this functionality by +// keeping the top position constant and simply changing the target height + +STDMETHODIMP CBaseControlVideo::put_DestinationTop(long DestinationTop) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.bottom = DestinationTop + HEIGHT(&DestinationRect); + DestinationRect.top = DestinationTop; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the top position for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationTop(__out long *pDestinationTop) +{ + CheckPointer(pDestinationTop,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationTop = DestinationRect.top; + return NOERROR; +} + + +// Set the destination height + +STDMETHODIMP CBaseControlVideo::put_DestinationHeight(long DestinationHeight) +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + GetTargetRect(&DestinationRect); + DestinationRect.bottom = DestinationRect.top + DestinationHeight; + + // Check the target rectangle is valid + + HRESULT hr = CheckTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + + // Now set the new target rectangle + + hr = SetTargetRect(&DestinationRect); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return the height for the destination rectangle + +STDMETHODIMP CBaseControlVideo::get_DestinationHeight(__out long *pDestinationHeight) +{ + CheckPointer(pDestinationHeight,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + RECT DestinationRect; + + GetTargetRect(&DestinationRect); + *pDestinationHeight = HEIGHT(&DestinationRect); + return NOERROR; +} + + +// Reset the source rectangle to the full video dimensions + +STDMETHODIMP CBaseControlVideo::SetDefaultSourcePosition() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + HRESULT hr = SetDefaultSourceRect(); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return S_OK if we're using the default source otherwise S_FALSE + +STDMETHODIMP CBaseControlVideo::IsUsingDefaultSource() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + return IsDefaultSourceRect(); +} + + +// Reset the video renderer to use the entire playback area + +STDMETHODIMP CBaseControlVideo::SetDefaultDestinationPosition() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + HRESULT hr = SetDefaultTargetRect(); + if (FAILED(hr)) { + return hr; + } + return OnUpdateRectangles(); +} + + +// Return S_OK if we're using the default target otherwise S_FALSE + +STDMETHODIMP CBaseControlVideo::IsUsingDefaultDestination() +{ + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + return IsDefaultTargetRect(); +} + + +// Return a copy of the current image in the video renderer + +STDMETHODIMP +CBaseControlVideo::GetCurrentImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pVideoImage) +{ + CheckPointer(pBufferSize,E_POINTER); + CheckConnected(m_pPin,VFW_E_NOT_CONNECTED); + CAutoLock cInterfaceLock(m_pInterfaceLock); + FILTER_STATE State; + + // Make sure we are in a paused state + + if (pVideoImage != NULL) { + m_pFilter->GetState(0,&State); + if (State != State_Paused) { + return VFW_E_NOT_PAUSED; + } + return GetStaticImage(pBufferSize,pVideoImage); + } + + // Just return the memory required + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + RECT SourceRect; + GetSourceRect(&SourceRect); + return GetImageSize(pVideoInfo,pBufferSize,&SourceRect); +} + + +// An application has two ways of using GetCurrentImage, one is to pass a real +// buffer which should be filled with the current image. The other is to pass +// a NULL buffer pointer which is interpreted as asking us to return how much +// memory is required for the image. The constraints for when the latter can +// be called are much looser. To calculate the memory required we synthesize +// a VIDEOINFO that takes into account the source rectangle that's being used + +HRESULT CBaseControlVideo::GetImageSize(__in VIDEOINFOHEADER *pVideoInfo, + __out long *pBufferSize, + __in RECT *pSourceRect) +{ + NOTE("Entering GetImageSize"); + ASSERT(pSourceRect); + + // Check we have the correct input parameters + + if (pSourceRect == NULL || + pVideoInfo == NULL || + pBufferSize == NULL) { + + return E_UNEXPECTED; + } + + // Is the data format compatible + + if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { + if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { + return E_INVALIDARG; + } + } + + ASSERT(IsRectEmpty(pSourceRect) == FALSE); + + BITMAPINFOHEADER bih; + bih.biWidth = WIDTH(pSourceRect); + bih.biHeight = HEIGHT(pSourceRect); + bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; + LONG Size = DIBSIZE(bih); + Size += GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; + *pBufferSize = Size; + + return NOERROR; +} + + +// Given an IMediaSample containing a linear buffer with an image and a type +// describing the bitmap make a rendering of the image into the output buffer +// This may be called by derived classes who render typical video images to +// handle the IBasicVideo GetCurrentImage method. The pVideoImage pointer may +// be NULL when passed to GetCurrentImage in which case GetImageSize will be +// called instead, which will just do the calculation of the memory required + +HRESULT CBaseControlVideo::CopyImage(IMediaSample *pMediaSample, + __in VIDEOINFOHEADER *pVideoInfo, + __inout long *pBufferSize, + __out_bcount_part(*pBufferSize, *pBufferSize) BYTE *pVideoImage, + __in RECT *pSourceRect) +{ + NOTE("Entering CopyImage"); + ASSERT(pSourceRect); + BYTE *pCurrentImage; + + // Check we have an image to copy + + if (pMediaSample == NULL || pSourceRect == NULL || + pVideoInfo == NULL || pVideoImage == NULL || + pBufferSize == NULL) { + + return E_UNEXPECTED; + } + + // Is the data format compatible + + if (pVideoInfo->bmiHeader.biCompression != BI_RGB) { + if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) { + return E_INVALIDARG; + } + } + + if (*pBufferSize < 0) { + return E_INVALIDARG; + } + + // Arbitrarily large size to prevent integer overflow problems + if (pVideoInfo->bmiHeader.biSize > 4096) + { + return E_INVALIDARG; + } + + ASSERT(IsRectEmpty(pSourceRect) == FALSE); + + BITMAPINFOHEADER bih; + bih.biWidth = WIDTH(pSourceRect); + bih.biHeight = HEIGHT(pSourceRect); + bih.biBitCount = pVideoInfo->bmiHeader.biBitCount; + DWORD Size = GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER; + DWORD Total; + DWORD dwDibSize; + + if( !ValidateBitmapInfoHeader( HEADER(pVideoInfo), Size)) { + return E_INVALIDARG; + } + + // ValidateBitmapInfoHeader checks this but for some reason code scanning + // tools aren't picking up the annotation + __analysis_assume(Size >= sizeof(BITMAPINFOHEADER)); + + if (FAILED(SAFE_DIBSIZE(&bih, &dwDibSize))) { + return E_INVALIDARG; + } + + if (FAILED(DWordAdd(Size, dwDibSize, &Total))) { + return E_INVALIDARG; + } + + // Make sure we have a large enough buffer + + if ((DWORD)*pBufferSize < Total) { + return E_OUTOFMEMORY; + } + + // Copy the BITMAPINFO + + CopyMemory((PVOID)pVideoImage, (PVOID)&pVideoInfo->bmiHeader, Size); + ((BITMAPINFOHEADER *)pVideoImage)->biWidth = WIDTH(pSourceRect); + ((BITMAPINFOHEADER *)pVideoImage)->biHeight = HEIGHT(pSourceRect); + ((BITMAPINFOHEADER *)pVideoImage)->biSizeImage = DIBSIZE(bih); + BYTE *pImageData = pVideoImage + Size; + + // Get the pointer to it's image data + + HRESULT hr = pMediaSample->GetPointer(&pCurrentImage); + if (FAILED(hr)) { + return hr; + } + + // Now we are ready to start copying the source scan lines + + LONG ScanLine = (pVideoInfo->bmiHeader.biBitCount / 8) * WIDTH(pSourceRect); + LONG LinesToSkip = pVideoInfo->bmiHeader.biHeight; + LinesToSkip -= pSourceRect->top + HEIGHT(pSourceRect); + pCurrentImage += LinesToSkip * DIBWIDTHBYTES(pVideoInfo->bmiHeader); + pCurrentImage += pSourceRect->left * (pVideoInfo->bmiHeader.biBitCount / 8); + + // Even money on this GP faulting sometime... + + for (LONG Line = 0;Line < HEIGHT(pSourceRect);Line++) { + CopyMemory((PVOID)pImageData, (PVOID)pCurrentImage, ScanLine); + pImageData += DIBWIDTHBYTES(*(BITMAPINFOHEADER *)pVideoImage); + pCurrentImage += DIBWIDTHBYTES(pVideoInfo->bmiHeader); + } + return NOERROR; +} + + +// Called when we change media types either during connection or dynamically +// We inform the filter graph and therefore the application that the video +// size may have changed, we don't bother looking to see if it really has as +// we leave that to the application - the dimensions are the event parameters + +HRESULT CBaseControlVideo::OnVideoSizeChange() +{ + // Get the video format from the derived class + + VIDEOINFOHEADER *pVideoInfo = GetVideoFormat(); + if (pVideoInfo == NULL) + return E_OUTOFMEMORY; + WORD Width = (WORD) pVideoInfo->bmiHeader.biWidth; + WORD Height = (WORD) pVideoInfo->bmiHeader.biHeight; + + return m_pFilter->NotifyEvent(EC_VIDEO_SIZE_CHANGED, + MAKELPARAM(Width,Height), + MAKEWPARAM(0,0)); +} + + +// Set the video source rectangle. We must check the source rectangle against +// the actual video dimensions otherwise when we come to draw the pictures we +// get access violations as GDI tries to touch data outside of the image data +// Although we store the rectangle in left, top, right and bottom coordinates +// instead of left, top, width and height as OLE uses we do take into account +// that the rectangle is used up to, but not including, the right column and +// bottom row of pixels, see the Win32 documentation on RECT for more details + +HRESULT CBaseControlVideo::CheckSourceRect(__in RECT *pSourceRect) +{ + CheckPointer(pSourceRect,E_POINTER); + LONG Width,Height; + GetVideoSize(&Width,&Height); + + // Check the coordinates are greater than zero + // and that the rectangle is valid (leftleft >= pSourceRect->right) || + (pSourceRect->left < 0) || + (pSourceRect->top >= pSourceRect->bottom) || + (pSourceRect->top < 0)) { + + return E_INVALIDARG; + } + + // Check the coordinates are less than the extents + + if ((pSourceRect->right > Width) || + (pSourceRect->bottom > Height)) { + + return E_INVALIDARG; + } + return NOERROR; +} + + +// Check the target rectangle has some valid coordinates, which amounts to +// little more than checking the destination rectangle isn't empty. Derived +// classes may call this when they have their SetTargetRect method called to +// check the rectangle validity, we do not update the rectangles passed in +// Although we store the rectangle in left, top, right and bottom coordinates +// instead of left, top, width and height as OLE uses we do take into account +// that the rectangle is used up to, but not including, the right column and +// bottom row of pixels, see the Win32 documentation on RECT for more details + +HRESULT CBaseControlVideo::CheckTargetRect(__in RECT *pTargetRect) +{ + // Check the pointer is valid + + if (pTargetRect == NULL) { + return E_POINTER; + } + + // These overflow the WIDTH and HEIGHT checks + + if (pTargetRect->left > pTargetRect->right || + pTargetRect->top > pTargetRect->bottom) { + return E_INVALIDARG; + } + + // Check the rectangle has valid coordinates + + if (WIDTH(pTargetRect) <= 0 || HEIGHT(pTargetRect) <= 0) { + return E_INVALIDARG; + } + + ASSERT(IsRectEmpty(pTargetRect) == FALSE); + return NOERROR; +} + diff --git a/src/thirdparty/BaseClasses/winctrl.h b/src/thirdparty/BaseClasses/winctrl.h index f18ba82317c..1080a47c696 100644 --- a/src/thirdparty/BaseClasses/winctrl.h +++ b/src/thirdparty/BaseClasses/winctrl.h @@ -1,224 +1,224 @@ -//------------------------------------------------------------------------------ -// File: WinCtrl.h -// -// Desc: DirectShow base classes - defines classes for video control -// interfaces. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __WINCTRL__ -#define __WINCTRL__ - -#define ABSOL(x) (x < 0 ? -x : x) -#define NEGAT(x) (x > 0 ? -x : x) - -// Helper -BOOL WINAPI PossiblyEatMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -class CBaseControlWindow : public CBaseVideoWindow, public CBaseWindow -{ -protected: - - CBaseFilter *m_pFilter; // Pointer to owning media filter - CBasePin *m_pPin; // Controls media types for connection - CCritSec *m_pInterfaceLock; // Externally defined critical section - COLORREF m_BorderColour; // Current window border colour - BOOL m_bAutoShow; // What happens when the state changes - HWND m_hwndOwner; // Owner window that we optionally have - HWND m_hwndDrain; // HWND to post any messages received - BOOL m_bCursorHidden; // Should we hide the window cursor - -public: - - // Internal methods for other objects to get information out - - HRESULT DoSetWindowStyle(long Style,long WindowLong); - HRESULT DoGetWindowStyle(__out long *pStyle,long WindowLong); - BOOL IsAutoShowEnabled() { return m_bAutoShow; }; - COLORREF GetBorderColour() { return m_BorderColour; }; - HWND GetOwnerWindow() { return m_hwndOwner; }; - BOOL IsCursorHidden() { return m_bCursorHidden; }; - - inline BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) - { - return ::PossiblyEatMessage(m_hwndDrain, uMsg, wParam, lParam); - } - - // Derived classes must call this to set the pin the filter is using - // We don't have the pin passed in to the constructor (as we do with - // the CBaseFilter object) because filters typically create the - // pins dynamically when requested in CBaseFilter::GetPin. This can - // not be called from our constructor because is is a virtual method - - void SetControlWindowPin(CBasePin *pPin) { - m_pPin = pPin; - } - -public: - - CBaseControlWindow(__inout CBaseFilter *pFilter, // Owning media filter - __in CCritSec *pInterfaceLock, // Locking object - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // Normal COM ownership - __inout HRESULT *phr); // OLE return code - - // These are the properties we support - - STDMETHODIMP put_Caption(__in BSTR strCaption); - STDMETHODIMP get_Caption(__out BSTR *pstrCaption); - STDMETHODIMP put_AutoShow(long AutoShow); - STDMETHODIMP get_AutoShow(__out long *AutoShow); - STDMETHODIMP put_WindowStyle(long WindowStyle); - STDMETHODIMP get_WindowStyle(__out long *pWindowStyle); - STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); - STDMETHODIMP get_WindowStyleEx(__out long *pWindowStyleEx); - STDMETHODIMP put_WindowState(long WindowState); - STDMETHODIMP get_WindowState(__out long *pWindowState); - STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); - STDMETHODIMP get_BackgroundPalette(__out long *pBackgroundPalette); - STDMETHODIMP put_Visible(long Visible); - STDMETHODIMP get_Visible(__out long *pVisible); - STDMETHODIMP put_Left(long Left); - STDMETHODIMP get_Left(__out long *pLeft); - STDMETHODIMP put_Width(long Width); - STDMETHODIMP get_Width(__out long *pWidth); - STDMETHODIMP put_Top(long Top); - STDMETHODIMP get_Top(__out long *pTop); - STDMETHODIMP put_Height(long Height); - STDMETHODIMP get_Height(__out long *pHeight); - STDMETHODIMP put_Owner(OAHWND Owner); - STDMETHODIMP get_Owner(__out OAHWND *Owner); - STDMETHODIMP put_MessageDrain(OAHWND Drain); - STDMETHODIMP get_MessageDrain(__out OAHWND *Drain); - STDMETHODIMP get_BorderColor(__out long *Color); - STDMETHODIMP put_BorderColor(long Color); - STDMETHODIMP get_FullScreenMode(__out long *FullScreenMode); - STDMETHODIMP put_FullScreenMode(long FullScreenMode); - - // And these are the methods - - STDMETHODIMP SetWindowForeground(long Focus); - STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd,long uMsg,LONG_PTR wParam,LONG_PTR lParam); - STDMETHODIMP GetMinIdealImageSize(__out long *pWidth,__out long *pHeight); - STDMETHODIMP GetMaxIdealImageSize(__out long *pWidth,__out long *pHeight); - STDMETHODIMP SetWindowPosition(long Left,long Top,long Width,long Height); - STDMETHODIMP GetWindowPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); - STDMETHODIMP GetRestorePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); - STDMETHODIMP HideCursor(long HideCursor); - STDMETHODIMP IsCursorHidden(__out long *CursorHidden); -}; - -// This class implements the IBasicVideo interface - -class CBaseControlVideo : public CBaseBasicVideo -{ -protected: - - CBaseFilter *m_pFilter; // Pointer to owning media filter - CBasePin *m_pPin; // Controls media types for connection - CCritSec *m_pInterfaceLock; // Externally defined critical section - -public: - - // Derived classes must provide these for the implementation - - virtual HRESULT IsDefaultTargetRect() PURE; - virtual HRESULT SetDefaultTargetRect() PURE; - virtual HRESULT SetTargetRect(RECT *pTargetRect) PURE; - virtual HRESULT GetTargetRect(RECT *pTargetRect) PURE; - virtual HRESULT IsDefaultSourceRect() PURE; - virtual HRESULT SetDefaultSourceRect() PURE; - virtual HRESULT SetSourceRect(RECT *pSourceRect) PURE; - virtual HRESULT GetSourceRect(RECT *pSourceRect) PURE; - virtual HRESULT GetStaticImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pDIBImage) PURE; - - // Derived classes must override this to return a VIDEOINFO representing - // the video format. We cannot call IPin ConnectionMediaType to get this - // format because various filters dynamically change the type when using - // DirectDraw such that the format shows the position of the logical - // bitmap in a frame buffer surface, so the size might be returned as - // 1024x768 pixels instead of 320x240 which is the real video dimensions - - __out virtual VIDEOINFOHEADER *GetVideoFormat() PURE; - - // Helper functions for creating memory renderings of a DIB image - - HRESULT GetImageSize(__in VIDEOINFOHEADER *pVideoInfo, - __out LONG *pBufferSize, - __in RECT *pSourceRect); - - HRESULT CopyImage(IMediaSample *pMediaSample, - __in VIDEOINFOHEADER *pVideoInfo, - __inout LONG *pBufferSize, - __out_bcount_part(*pBufferSize, *pBufferSize) BYTE *pVideoImage, - __in RECT *pSourceRect); - - // Override this if you want notifying when the rectangles change - virtual HRESULT OnUpdateRectangles() { return NOERROR; }; - virtual HRESULT OnVideoSizeChange(); - - // Derived classes must call this to set the pin the filter is using - // We don't have the pin passed in to the constructor (as we do with - // the CBaseFilter object) because filters typically create the - // pins dynamically when requested in CBaseFilter::GetPin. This can - // not be called from our constructor because is is a virtual method - - void SetControlVideoPin(__inout CBasePin *pPin) { - m_pPin = pPin; - } - - // Helper methods for checking rectangles - virtual HRESULT CheckSourceRect(__in RECT *pSourceRect); - virtual HRESULT CheckTargetRect(__in RECT *pTargetRect); - -public: - - CBaseControlVideo(__inout CBaseFilter *pFilter, // Owning media filter - __in CCritSec *pInterfaceLock, // Serialise interface - __in_opt LPCTSTR pName, // Object description - __inout_opt LPUNKNOWN pUnk, // Normal COM ownership - __inout HRESULT *phr); // OLE return code - - // These are the properties we support - - STDMETHODIMP get_AvgTimePerFrame(__out REFTIME *pAvgTimePerFrame); - STDMETHODIMP get_BitRate(__out long *pBitRate); - STDMETHODIMP get_BitErrorRate(__out long *pBitErrorRate); - STDMETHODIMP get_VideoWidth(__out long *pVideoWidth); - STDMETHODIMP get_VideoHeight(__out long *pVideoHeight); - STDMETHODIMP put_SourceLeft(long SourceLeft); - STDMETHODIMP get_SourceLeft(__out long *pSourceLeft); - STDMETHODIMP put_SourceWidth(long SourceWidth); - STDMETHODIMP get_SourceWidth(__out long *pSourceWidth); - STDMETHODIMP put_SourceTop(long SourceTop); - STDMETHODIMP get_SourceTop(__out long *pSourceTop); - STDMETHODIMP put_SourceHeight(long SourceHeight); - STDMETHODIMP get_SourceHeight(__out long *pSourceHeight); - STDMETHODIMP put_DestinationLeft(long DestinationLeft); - STDMETHODIMP get_DestinationLeft(__out long *pDestinationLeft); - STDMETHODIMP put_DestinationWidth(long DestinationWidth); - STDMETHODIMP get_DestinationWidth(__out long *pDestinationWidth); - STDMETHODIMP put_DestinationTop(long DestinationTop); - STDMETHODIMP get_DestinationTop(__out long *pDestinationTop); - STDMETHODIMP put_DestinationHeight(long DestinationHeight); - STDMETHODIMP get_DestinationHeight(__out long *pDestinationHeight); - - // And these are the methods - - STDMETHODIMP GetVideoSize(__out long *pWidth,__out long *pHeight); - STDMETHODIMP SetSourcePosition(long Left,long Top,long Width,long Height); - STDMETHODIMP GetSourcePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); - STDMETHODIMP GetVideoPaletteEntries(long StartIndex,long Entries,__out long *pRetrieved,__out_ecount_part(Entries, *pRetrieved) long *pPalette); - STDMETHODIMP SetDefaultSourcePosition(); - STDMETHODIMP IsUsingDefaultSource(); - STDMETHODIMP SetDestinationPosition(long Left,long Top,long Width,long Height); - STDMETHODIMP GetDestinationPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); - STDMETHODIMP SetDefaultDestinationPosition(); - STDMETHODIMP IsUsingDefaultDestination(); - STDMETHODIMP GetCurrentImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pVideoImage); -}; - -#endif // __WINCTRL__ - +//------------------------------------------------------------------------------ +// File: WinCtrl.h +// +// Desc: DirectShow base classes - defines classes for video control +// interfaces. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WINCTRL__ +#define __WINCTRL__ + +#define ABSOL(x) (x < 0 ? -x : x) +#define NEGAT(x) (x > 0 ? -x : x) + +// Helper +BOOL WINAPI PossiblyEatMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +class CBaseControlWindow : public CBaseVideoWindow, public CBaseWindow +{ +protected: + + CBaseFilter *m_pFilter; // Pointer to owning media filter + CBasePin *m_pPin; // Controls media types for connection + CCritSec *m_pInterfaceLock; // Externally defined critical section + COLORREF m_BorderColour; // Current window border colour + BOOL m_bAutoShow; // What happens when the state changes + HWND m_hwndOwner; // Owner window that we optionally have + HWND m_hwndDrain; // HWND to post any messages received + BOOL m_bCursorHidden; // Should we hide the window cursor + +public: + + // Internal methods for other objects to get information out + + HRESULT DoSetWindowStyle(long Style,long WindowLong); + HRESULT DoGetWindowStyle(__out long *pStyle,long WindowLong); + BOOL IsAutoShowEnabled() { return m_bAutoShow; }; + COLORREF GetBorderColour() { return m_BorderColour; }; + HWND GetOwnerWindow() { return m_hwndOwner; }; + BOOL IsCursorHidden() { return m_bCursorHidden; }; + + inline BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return ::PossiblyEatMessage(m_hwndDrain, uMsg, wParam, lParam); + } + + // Derived classes must call this to set the pin the filter is using + // We don't have the pin passed in to the constructor (as we do with + // the CBaseFilter object) because filters typically create the + // pins dynamically when requested in CBaseFilter::GetPin. This can + // not be called from our constructor because is is a virtual method + + void SetControlWindowPin(CBasePin *pPin) { + m_pPin = pPin; + } + +public: + + CBaseControlWindow(__inout CBaseFilter *pFilter, // Owning media filter + __in CCritSec *pInterfaceLock, // Locking object + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // Normal COM ownership + __inout HRESULT *phr); // OLE return code + + // These are the properties we support + + STDMETHODIMP put_Caption(__in BSTR strCaption); + STDMETHODIMP get_Caption(__out BSTR *pstrCaption); + STDMETHODIMP put_AutoShow(long AutoShow); + STDMETHODIMP get_AutoShow(__out long *AutoShow); + STDMETHODIMP put_WindowStyle(long WindowStyle); + STDMETHODIMP get_WindowStyle(__out long *pWindowStyle); + STDMETHODIMP put_WindowStyleEx(long WindowStyleEx); + STDMETHODIMP get_WindowStyleEx(__out long *pWindowStyleEx); + STDMETHODIMP put_WindowState(long WindowState); + STDMETHODIMP get_WindowState(__out long *pWindowState); + STDMETHODIMP put_BackgroundPalette(long BackgroundPalette); + STDMETHODIMP get_BackgroundPalette(__out long *pBackgroundPalette); + STDMETHODIMP put_Visible(long Visible); + STDMETHODIMP get_Visible(__out long *pVisible); + STDMETHODIMP put_Left(long Left); + STDMETHODIMP get_Left(__out long *pLeft); + STDMETHODIMP put_Width(long Width); + STDMETHODIMP get_Width(__out long *pWidth); + STDMETHODIMP put_Top(long Top); + STDMETHODIMP get_Top(__out long *pTop); + STDMETHODIMP put_Height(long Height); + STDMETHODIMP get_Height(__out long *pHeight); + STDMETHODIMP put_Owner(OAHWND Owner); + STDMETHODIMP get_Owner(__out OAHWND *Owner); + STDMETHODIMP put_MessageDrain(OAHWND Drain); + STDMETHODIMP get_MessageDrain(__out OAHWND *Drain); + STDMETHODIMP get_BorderColor(__out long *Color); + STDMETHODIMP put_BorderColor(long Color); + STDMETHODIMP get_FullScreenMode(__out long *FullScreenMode); + STDMETHODIMP put_FullScreenMode(long FullScreenMode); + + // And these are the methods + + STDMETHODIMP SetWindowForeground(long Focus); + STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd,long uMsg,LONG_PTR wParam,LONG_PTR lParam); + STDMETHODIMP GetMinIdealImageSize(__out long *pWidth,__out long *pHeight); + STDMETHODIMP GetMaxIdealImageSize(__out long *pWidth,__out long *pHeight); + STDMETHODIMP SetWindowPosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetWindowPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); + STDMETHODIMP GetRestorePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); + STDMETHODIMP HideCursor(long HideCursor); + STDMETHODIMP IsCursorHidden(__out long *CursorHidden); +}; + +// This class implements the IBasicVideo interface + +class CBaseControlVideo : public CBaseBasicVideo +{ +protected: + + CBaseFilter *m_pFilter; // Pointer to owning media filter + CBasePin *m_pPin; // Controls media types for connection + CCritSec *m_pInterfaceLock; // Externally defined critical section + +public: + + // Derived classes must provide these for the implementation + + virtual HRESULT IsDefaultTargetRect() PURE; + virtual HRESULT SetDefaultTargetRect() PURE; + virtual HRESULT SetTargetRect(RECT *pTargetRect) PURE; + virtual HRESULT GetTargetRect(RECT *pTargetRect) PURE; + virtual HRESULT IsDefaultSourceRect() PURE; + virtual HRESULT SetDefaultSourceRect() PURE; + virtual HRESULT SetSourceRect(RECT *pSourceRect) PURE; + virtual HRESULT GetSourceRect(RECT *pSourceRect) PURE; + virtual HRESULT GetStaticImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pDIBImage) PURE; + + // Derived classes must override this to return a VIDEOINFO representing + // the video format. We cannot call IPin ConnectionMediaType to get this + // format because various filters dynamically change the type when using + // DirectDraw such that the format shows the position of the logical + // bitmap in a frame buffer surface, so the size might be returned as + // 1024x768 pixels instead of 320x240 which is the real video dimensions + + __out virtual VIDEOINFOHEADER *GetVideoFormat() PURE; + + // Helper functions for creating memory renderings of a DIB image + + HRESULT GetImageSize(__in VIDEOINFOHEADER *pVideoInfo, + __out LONG *pBufferSize, + __in RECT *pSourceRect); + + HRESULT CopyImage(IMediaSample *pMediaSample, + __in VIDEOINFOHEADER *pVideoInfo, + __inout LONG *pBufferSize, + __out_bcount_part(*pBufferSize, *pBufferSize) BYTE *pVideoImage, + __in RECT *pSourceRect); + + // Override this if you want notifying when the rectangles change + virtual HRESULT OnUpdateRectangles() { return NOERROR; }; + virtual HRESULT OnVideoSizeChange(); + + // Derived classes must call this to set the pin the filter is using + // We don't have the pin passed in to the constructor (as we do with + // the CBaseFilter object) because filters typically create the + // pins dynamically when requested in CBaseFilter::GetPin. This can + // not be called from our constructor because is is a virtual method + + void SetControlVideoPin(__inout CBasePin *pPin) { + m_pPin = pPin; + } + + // Helper methods for checking rectangles + virtual HRESULT CheckSourceRect(__in RECT *pSourceRect); + virtual HRESULT CheckTargetRect(__in RECT *pTargetRect); + +public: + + CBaseControlVideo(__inout CBaseFilter *pFilter, // Owning media filter + __in CCritSec *pInterfaceLock, // Serialise interface + __in_opt LPCTSTR pName, // Object description + __inout_opt LPUNKNOWN pUnk, // Normal COM ownership + __inout HRESULT *phr); // OLE return code + + // These are the properties we support + + STDMETHODIMP get_AvgTimePerFrame(__out REFTIME *pAvgTimePerFrame); + STDMETHODIMP get_BitRate(__out long *pBitRate); + STDMETHODIMP get_BitErrorRate(__out long *pBitErrorRate); + STDMETHODIMP get_VideoWidth(__out long *pVideoWidth); + STDMETHODIMP get_VideoHeight(__out long *pVideoHeight); + STDMETHODIMP put_SourceLeft(long SourceLeft); + STDMETHODIMP get_SourceLeft(__out long *pSourceLeft); + STDMETHODIMP put_SourceWidth(long SourceWidth); + STDMETHODIMP get_SourceWidth(__out long *pSourceWidth); + STDMETHODIMP put_SourceTop(long SourceTop); + STDMETHODIMP get_SourceTop(__out long *pSourceTop); + STDMETHODIMP put_SourceHeight(long SourceHeight); + STDMETHODIMP get_SourceHeight(__out long *pSourceHeight); + STDMETHODIMP put_DestinationLeft(long DestinationLeft); + STDMETHODIMP get_DestinationLeft(__out long *pDestinationLeft); + STDMETHODIMP put_DestinationWidth(long DestinationWidth); + STDMETHODIMP get_DestinationWidth(__out long *pDestinationWidth); + STDMETHODIMP put_DestinationTop(long DestinationTop); + STDMETHODIMP get_DestinationTop(__out long *pDestinationTop); + STDMETHODIMP put_DestinationHeight(long DestinationHeight); + STDMETHODIMP get_DestinationHeight(__out long *pDestinationHeight); + + // And these are the methods + + STDMETHODIMP GetVideoSize(__out long *pWidth,__out long *pHeight); + STDMETHODIMP SetSourcePosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetSourcePosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); + STDMETHODIMP GetVideoPaletteEntries(long StartIndex,long Entries,__out long *pRetrieved,__out_ecount_part(Entries, *pRetrieved) long *pPalette); + STDMETHODIMP SetDefaultSourcePosition(); + STDMETHODIMP IsUsingDefaultSource(); + STDMETHODIMP SetDestinationPosition(long Left,long Top,long Width,long Height); + STDMETHODIMP GetDestinationPosition(__out long *pLeft,__out long *pTop,__out long *pWidth,__out long *pHeight); + STDMETHODIMP SetDefaultDestinationPosition(); + STDMETHODIMP IsUsingDefaultDestination(); + STDMETHODIMP GetCurrentImage(__inout long *pBufferSize,__out_bcount_part(*pBufferSize, *pBufferSize) long *pVideoImage); +}; + +#endif // __WINCTRL__ + diff --git a/src/thirdparty/BaseClasses/winutil.cpp b/src/thirdparty/BaseClasses/winutil.cpp index 8df3545de93..205567c6a27 100644 --- a/src/thirdparty/BaseClasses/winutil.cpp +++ b/src/thirdparty/BaseClasses/winutil.cpp @@ -1,2759 +1,2759 @@ -//------------------------------------------------------------------------------ -// File: WinUtil.cpp -// -// Desc: DirectShow base classes - implements generic window handler class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#include -#include -#include -#include "checkbmi.h" - -static UINT MsgDestroy; - -// Constructor - -CBaseWindow::CBaseWindow(BOOL bDoGetDC, bool bDoPostToDestroy) : - m_hInstance(g_hInst), - m_hwnd(NULL), - m_hdc(NULL), - m_bActivated(FALSE), - m_pClassName(NULL), - m_ClassStyles(0), - m_WindowStyles(0), - m_WindowStylesEx(0), - m_ShowStageMessage(0), - m_ShowStageTop(0), - m_MemoryDC(NULL), - m_hPalette(NULL), - m_bBackground(FALSE), -#ifdef _DEBUG - m_bRealizing(FALSE), -#endif - m_bNoRealize(FALSE), - m_bDoPostToDestroy(bDoPostToDestroy), - m_bDoGetDC(bDoGetDC), - m_Width(0), - m_Height(0), - m_RealizePalette(0) -{ -} - - -// Prepare a window by spinning off a worker thread to do the creation and -// also poll the message input queue. We leave this to be called by derived -// classes because they might want to override methods like MessageLoop and -// InitialiseWindow, if we do this during construction they'll ALWAYS call -// this base class methods. We make the worker thread create the window so -// it owns it rather than the filter graph thread which is constructing us - -HRESULT CBaseWindow::PrepareWindow() -{ - if (m_hwnd) return NOERROR; - ASSERT(m_hwnd == NULL); - ASSERT(m_hdc == NULL); - - // Get the derived object's window and class styles - - m_pClassName = GetClassWindowStyles(&m_ClassStyles, - &m_WindowStyles, - &m_WindowStylesEx); - if (m_pClassName == NULL) { - return E_FAIL; - } - - // Register our special private messages - m_ShowStageMessage = RegisterWindowMessage(SHOWSTAGE); - - // RegisterWindowMessage() returns 0 if an error occurs. - if (0 == m_ShowStageMessage) { - return AmGetLastErrorToHResult(); - } - - m_ShowStageTop = RegisterWindowMessage(SHOWSTAGETOP); - if (0 == m_ShowStageTop) { - return AmGetLastErrorToHResult(); - } - - m_RealizePalette = RegisterWindowMessage(REALIZEPALETTE); - if (0 == m_RealizePalette) { - return AmGetLastErrorToHResult(); - } - - MsgDestroy = RegisterWindowMessage(TEXT("AM_DESTROY")); - if (0 == MsgDestroy) { - return AmGetLastErrorToHResult(); - } - - return DoCreateWindow(); -} - - -// Destructor just a placeholder so that we know it becomes virtual -// Derived classes MUST call DoneWithWindow in their destructors so -// that no messages arrive after the derived class constructor ends - -#ifdef _DEBUG -CBaseWindow::~CBaseWindow() -{ - ASSERT(m_hwnd == NULL); - ASSERT(m_hdc == NULL); -} -#endif - - -// We use the sync worker event to have the window destroyed. All we do is -// signal the event and wait on the window thread handle. Trying to send it -// messages causes too many problems, furthermore to be on the safe side we -// just wait on the thread handle while it returns WAIT_TIMEOUT or there is -// a sent message to process on this thread. If the constructor failed to -// create the thread in the first place then the loop will get terminated - -HRESULT CBaseWindow::DoneWithWindow() -{ - if (!IsWindow(m_hwnd) || (GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId())) { - - if (IsWindow(m_hwnd)) { - - // This code should only be executed if the window exists and if the window's - // messages are processed on a different thread. - ASSERT(GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId()); - - if (m_bDoPostToDestroy) { - - HRESULT hr = S_OK; - CAMEvent m_evDone(FALSE, &hr); - if (FAILED(hr)) { - return hr; - } - - // We must post a message to destroy the window - // That way we can't be in the middle of processing a - // message posted to our window when we do go away - // Sending a message gives less synchronization. - PostMessage(m_hwnd, MsgDestroy, (WPARAM)(HANDLE)m_evDone, 0); - WaitDispatchingMessages(m_evDone, INFINITE); - } else { - SendMessage(m_hwnd, MsgDestroy, 0, 0); - } - } - - // - // This is not a leak, the window manager automatically free's - // hdc's that were got via GetDC, which is the case here. - // We set it to NULL so that we don't get any asserts later. - // - m_hdc = NULL; - - // - // We need to free this DC though because USER32 does not know - // anything about it. - // - if (m_MemoryDC) - { - EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); - m_MemoryDC = NULL; - } - - // Reset the window variables - m_hwnd = NULL; - - return NOERROR; - } - const HWND hwnd = m_hwnd; - if (hwnd == NULL) { - return NOERROR; - } - - InactivateWindow(); - NOTE("Inactivated"); - - // Reset the window styles before destruction - - SetWindowLong(hwnd,GWL_STYLE,m_WindowStyles); - ASSERT(GetParent(hwnd) == NULL); - NOTE1("Reset window styles %d",m_WindowStyles); - - // UnintialiseWindow sets m_hwnd to NULL so save a copy - UninitialiseWindow(); - DbgLog((LOG_TRACE, 2, TEXT("Destroying 0x%8.8X"), hwnd)); - if (!DestroyWindow(hwnd)) { - DbgLog((LOG_TRACE, 0, TEXT("DestroyWindow %8.8X failed code %d"), - hwnd, GetLastError())); - DbgBreak(""); - } - - // Reset our state so we can be prepared again - - m_pClassName = NULL; - m_ClassStyles = 0; - m_WindowStyles = 0; - m_WindowStylesEx = 0; - m_ShowStageMessage = 0; - m_ShowStageTop = 0; - - return NOERROR; -} - - -// Called at the end to put the window in an inactive state. The pending list -// will always have been cleared by this time so event if the worker thread -// gets has been signaled and gets in to render something it will find both -// the state has been changed and that there are no available sample images -// Since we wait on the window thread to complete we don't lock the object - -HRESULT CBaseWindow::InactivateWindow() -{ - // Has the window been activated - if (m_bActivated == FALSE) { - return S_FALSE; - } - - m_bActivated = FALSE; - ShowWindow(m_hwnd,SW_HIDE); - return NOERROR; -} - - -HRESULT CBaseWindow::CompleteConnect() -{ - m_bActivated = FALSE; - return NOERROR; -} - -// This displays a normal window. We ask the base window class for default -// sizes which unless overriden will return DEFWIDTH and DEFHEIGHT. We go -// through a couple of extra hoops to get the client area the right size -// as the object specifies which accounts for the AdjustWindowRectEx calls -// We also DWORD align the left and top coordinates of the window here to -// maximise the chance of being able to use DCI/DirectDraw primary surface - -HRESULT CBaseWindow::ActivateWindow() -{ - // Has the window been sized and positioned already - - if (m_bActivated == TRUE || GetParent(m_hwnd) != NULL) { - - SetWindowPos(m_hwnd, // Our window handle - HWND_TOP, // Put it at the top - 0, 0, 0, 0, // Leave in current position - SWP_NOMOVE | // Don't change it's place - SWP_NOSIZE); // Change Z-order only - - m_bActivated = TRUE; - return S_FALSE; - } - - // Calculate the desired client rectangle - - RECT WindowRect, ClientRect = GetDefaultRect(); - GetWindowRect(m_hwnd,&WindowRect); - AdjustWindowRectEx(&ClientRect,GetWindowLong(m_hwnd,GWL_STYLE), - FALSE,GetWindowLong(m_hwnd,GWL_EXSTYLE)); - - // Align left and top edges on DWORD boundaries - - UINT WindowFlags = (SWP_NOACTIVATE | SWP_FRAMECHANGED); - WindowRect.left -= (WindowRect.left & 3); - WindowRect.top -= (WindowRect.top & 3); - - SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Align left edge - WindowRect.top, // And also top place - WIDTH(&ClientRect), // Horizontal size - HEIGHT(&ClientRect), // Vertical size - WindowFlags); // Don't show window - - m_bActivated = TRUE; - return NOERROR; -} - - -// This can be used to DWORD align the window for maximum performance - -HRESULT CBaseWindow::PerformanceAlignWindow() -{ - RECT ClientRect,WindowRect; - GetWindowRect(m_hwnd,&WindowRect); - ASSERT(m_bActivated == TRUE); - - // Don't do this if we're owned - - if (GetParent(m_hwnd)) { - return NOERROR; - } - - // Align left and top edges on DWORD boundaries - - GetClientRect(m_hwnd, &ClientRect); - MapWindowPoints(m_hwnd, HWND_DESKTOP, (LPPOINT) &ClientRect, 2); - WindowRect.left -= (ClientRect.left & 3); - WindowRect.top -= (ClientRect.top & 3); - UINT WindowFlags = (SWP_NOACTIVATE | SWP_NOSIZE); - - SetWindowPos(m_hwnd, // Window handle - HWND_TOP, // Put it at the top - WindowRect.left, // Align left edge - WindowRect.top, // And also top place - (int) 0,(int) 0, // Ignore these sizes - WindowFlags); // Don't show window - - return NOERROR; -} - - -// Install a palette into the base window - we may be called by a different -// thread to the one that owns the window. We have to be careful how we do -// the palette realisation as we could be a different thread to the window -// which would cause an inter thread send message. Therefore we realise the -// palette by sending it a special message but without the window locked - -HRESULT CBaseWindow::SetPalette(HPALETTE hPalette) -{ - // We must own the window lock during the change - { - CAutoLock cWindowLock(&m_WindowLock); - CAutoLock cPaletteLock(&m_PaletteLock); - ASSERT(hPalette); - m_hPalette = hPalette; - } - return SetPalette(); -} - - -HRESULT CBaseWindow::SetPalette() -{ - if (!m_bNoRealize) { - SendMessage(m_hwnd, m_RealizePalette, 0, 0); - return S_OK; - } else { - // Just select the palette - ASSERT(m_hdc); - ASSERT(m_MemoryDC); - - CAutoLock cPaletteLock(&m_PaletteLock); - SelectPalette(m_hdc,m_hPalette,m_bBackground); - SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); - - return S_OK; - } -} - - -void CBaseWindow::UnsetPalette() -{ - CAutoLock cWindowLock(&m_WindowLock); - CAutoLock cPaletteLock(&m_PaletteLock); - - // Get a standard VGA colour palette - - HPALETTE hPalette = (HPALETTE) GetStockObject(DEFAULT_PALETTE); - ASSERT(hPalette); - - SelectPalette(GetWindowHDC(), hPalette, TRUE); - SelectPalette(GetMemoryHDC(), hPalette, TRUE); - - m_hPalette = NULL; -} - - -void CBaseWindow::LockPaletteLock() -{ - m_PaletteLock.Lock(); -} - - -void CBaseWindow::UnlockPaletteLock() -{ - m_PaletteLock.Unlock(); -} - - -// Realise our palettes in the window and device contexts - -HRESULT CBaseWindow::DoRealisePalette(BOOL bForceBackground) -{ - { - CAutoLock cPaletteLock(&m_PaletteLock); - - if (m_hPalette == NULL) { - return NOERROR; - } - - // Realize the palette on the window thread - ASSERT(m_hdc); - ASSERT(m_MemoryDC); - - SelectPalette(m_hdc,m_hPalette,m_bBackground || bForceBackground); - SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); - } - - // If we grab a critical section here we can deadlock - // with the window thread because one of the side effects - // of RealizePalette is to send a WM_PALETTECHANGED message - // to every window in the system. In our handling - // of WM_PALETTECHANGED we used to grab this CS too. - // The really bad case is when our renderer calls DoRealisePalette() - // while we're in the middle of processing a palette change - // for another window. - // So don't hold the critical section while actually realising - // the palette. In any case USER is meant to manage palette - // handling - we shouldn't have to serialize everything as well - ASSERT(CritCheckOut(&m_WindowLock)); - ASSERT(CritCheckOut(&m_PaletteLock)); - - EXECUTE_ASSERT(RealizePalette(m_hdc) != GDI_ERROR); - EXECUTE_ASSERT(RealizePalette(m_MemoryDC) != GDI_ERROR); - - return (GdiFlush() == FALSE ? S_FALSE : S_OK); -} - - -// This is the global window procedure - -LRESULT CALLBACK WndProc(HWND hwnd, // Window handle - UINT uMsg, // Message ID - WPARAM wParam, // First parameter - LPARAM lParam) // Other parameter -{ - - // Get the window long that holds our window object pointer - // If it is NULL then we are initialising the window in which - // case the object pointer has been passed in the window creation - // structure. IF we get any messages before WM_NCCREATE we will - // pass them to DefWindowProc. - - CBaseWindow *pBaseWindow = (CBaseWindow *)GetWindowLongPtr(hwnd,0); - - if (pBaseWindow == NULL) { - - // Get the structure pointer from the create struct. - // We can only do this for WM_NCCREATE which should be one of - // the first messages we receive. Anything before this will - // have to be passed to DefWindowProc (i.e. WM_GETMINMAXINFO) - - // If the message is WM_NCCREATE we set our pBaseWindow pointer - // and will then place it in the window structure - - // turn off WS_EX_LAYOUTRTL style for quartz windows - if (uMsg == WM_NCCREATE) { - SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~0x400000); - } - - if ((uMsg != WM_NCCREATE) - || (NULL == (pBaseWindow = *(CBaseWindow**) ((LPCREATESTRUCT)lParam)->lpCreateParams))) - { - return(DefWindowProc(hwnd, uMsg, wParam, lParam)); - } - - // Set the window LONG to be the object who created us -#ifdef _DEBUG - SetLastError(0); // because of the way SetWindowLong works -#endif - -#ifdef _DEBUG - LONG_PTR rc = -#endif - SetWindowLongPtr(hwnd, (DWORD) 0, (LONG_PTR)pBaseWindow); - - -#ifdef _DEBUG - if (0 == rc) { - // SetWindowLong MIGHT have failed. (Read the docs which admit - // that it is awkward to work out if you have had an error.) - LONG lasterror = GetLastError(); - ASSERT(0 == lasterror); - // If this is not the case we have not set the pBaseWindow pointer - // into the window structure and we will blow up. - } -#endif - - } - // See if this is the packet of death - if (uMsg == MsgDestroy && uMsg != 0) { - pBaseWindow->DoneWithWindow(); - if (pBaseWindow->m_bDoPostToDestroy) { - EXECUTE_ASSERT(SetEvent((HANDLE)wParam)); - } - return 0; - } - return pBaseWindow->OnReceiveMessage(hwnd,uMsg,wParam,lParam); -} - - -// When the window size changes we adjust our member variables that -// contain the dimensions of the client rectangle for our window so -// that we come to render an image we will know whether to stretch - -BOOL CBaseWindow::OnSize(LONG Width, LONG Height) -{ - m_Width = Width; - m_Height = Height; - return TRUE; -} - - -// This function handles the WM_CLOSE message - -BOOL CBaseWindow::OnClose() -{ - ShowWindow(m_hwnd,SW_HIDE); - return TRUE; -} - - -// This is called by the worker window thread when it receives a terminate -// message from the window object destructor to delete all the resources we -// allocated during initialisation. By the time the worker thread exits all -// processing will have been completed as the source filter disconnection -// flushes the image pending sample, therefore the GdiFlush should succeed - -HRESULT CBaseWindow::UninitialiseWindow() -{ - // Have we already cleaned up - - if (m_hwnd == NULL) { - ASSERT(m_hdc == NULL); - ASSERT(m_MemoryDC == NULL); - return NOERROR; - } - - // Release the window resources - - EXECUTE_ASSERT(GdiFlush()); - - if (m_hdc) - { - EXECUTE_ASSERT(ReleaseDC(m_hwnd,m_hdc)); - m_hdc = NULL; - } - - if (m_MemoryDC) - { - EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); - m_MemoryDC = NULL; - } - - // Reset the window variables - m_hwnd = NULL; - - return NOERROR; -} - - -// This is called by the worker window thread after it has created the main -// window and it wants to initialise the rest of the owner objects window -// variables such as the device contexts. We execute this function with the -// critical section still locked. Nothing in this function must generate any -// SendMessage calls to the window because this is executing on the window -// thread so the message will never be processed and we will deadlock - -HRESULT CBaseWindow::InitialiseWindow(HWND hwnd) -{ - // Initialise the window variables - - ASSERT(IsWindow(hwnd)); - m_hwnd = hwnd; - - if (m_bDoGetDC) - { - m_hdc = GetDC(hwnd); - EXECUTE_ASSERT(m_hdc); - m_MemoryDC = CreateCompatibleDC(m_hdc); - EXECUTE_ASSERT(m_MemoryDC); - - EXECUTE_ASSERT(SetStretchBltMode(m_hdc,COLORONCOLOR)); - EXECUTE_ASSERT(SetStretchBltMode(m_MemoryDC,COLORONCOLOR)); - } - - return NOERROR; -} - -HRESULT CBaseWindow::DoCreateWindow() -{ - WNDCLASS wndclass; // Used to register classes - BOOL bRegistered; // Is this class registered - HWND hwnd; // Handle to our window - - bRegistered = GetClassInfo(m_hInstance, // Module instance - m_pClassName, // Window class - &wndclass); // Info structure - - // if the window is to be used for drawing puposes and we are getting a DC - // for the entire lifetime of the window then changes the class style to do - // say so. If we don't set this flag then the DC comes from the cache and is - // really bad. - if (m_bDoGetDC) - { - m_ClassStyles |= CS_OWNDC; - } - - if (bRegistered == FALSE) { - - // Register the renderer window class - - wndclass.lpszClassName = m_pClassName; - wndclass.style = m_ClassStyles; - wndclass.lpfnWndProc = WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = sizeof(CBaseWindow *); - wndclass.hInstance = m_hInstance; - wndclass.hIcon = NULL; - wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); - wndclass.hbrBackground = (HBRUSH) NULL; - wndclass.lpszMenuName = NULL; - - RegisterClass(&wndclass); - } - - // Create the frame window. Pass the pBaseWindow information in the - // CreateStruct which allows our message handling loop to get hold of - // the pBaseWindow pointer. - - CBaseWindow *pBaseWindow = this; // The owner window object - hwnd = CreateWindowEx(m_WindowStylesEx, // Extended styles - m_pClassName, // Registered name - TEXT("ActiveMovie Window"), // Window title - m_WindowStyles, // Window styles - CW_USEDEFAULT, // Start x position - CW_USEDEFAULT, // Start y position - DEFWIDTH, // Window width - DEFHEIGHT, // Window height - NULL, // Parent handle - NULL, // Menu handle - m_hInstance, // Instance handle - &pBaseWindow); // Creation data - - // If we failed signal an error to the object constructor (based on the - // last Win32 error on this thread) then signal the constructor thread - // to continue, release the mutex to let others have a go and exit - - if (hwnd == NULL) { - DWORD Error = GetLastError(); - return AmHresultFromWin32(Error); - } - - // Check the window LONG is the object who created us - ASSERT(GetWindowLongPtr(hwnd, 0) == (LONG_PTR)this); - - // Initialise the window and then signal the constructor so that it can - // continue and then finally unlock the object's critical section. The - // window class is left registered even after we terminate the thread - // as we don't know when the last window has been closed. So we allow - // the operating system to free the class resources as appropriate - - InitialiseWindow(hwnd); - - DbgLog((LOG_TRACE, 2, TEXT("Created window class (%s) HWND(%8.8X)"), - m_pClassName, hwnd)); - - return S_OK; -} - - -// The base class provides some default handling and calls DefWindowProc - -INT_PTR CBaseWindow::OnReceiveMessage(HWND hwnd, // Window handle - UINT uMsg, // Message ID - WPARAM wParam, // First parameter - LPARAM lParam) // Other parameter -{ - ASSERT(IsWindow(hwnd)); - - if (PossiblyEatMessage(uMsg, wParam, lParam)) - return 0; - - // This is sent by the IVideoWindow SetWindowForeground method. If the - // window is invisible we will show it and make it topmost without the - // foreground focus. If the window is visible it will also be made the - // topmost window without the foreground focus. If wParam is TRUE then - // for both cases the window will be forced into the foreground focus - - if (uMsg == m_ShowStageMessage) { - - BOOL bVisible = IsWindowVisible(hwnd); - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | - (bVisible ? SWP_NOACTIVATE : 0)); - - // Should we bring the window to the foreground - if (wParam == TRUE) { - SetForegroundWindow(hwnd); - } - return (LRESULT) 1; - } - - // When we go fullscreen we have to add the WS_EX_TOPMOST style to the - // video window so that it comes out above any task bar (this is more - // relevant to WindowsNT than Windows95). However the SetWindowPos call - // must be on the same thread as that which created the window. The - // wParam parameter can be TRUE or FALSE to set and reset the topmost - - if (uMsg == m_ShowStageTop) { - HWND HwndTop = (wParam == TRUE ? HWND_TOPMOST : HWND_NOTOPMOST); - BOOL bVisible = IsWindowVisible(hwnd); - SetWindowPos(hwnd, HwndTop, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | - (wParam == TRUE ? SWP_SHOWWINDOW : 0) | - (bVisible ? SWP_NOACTIVATE : 0)); - return (LRESULT) 1; - } - - // New palette stuff - if (uMsg == m_RealizePalette) { - ASSERT(m_hwnd == hwnd); - return OnPaletteChange(m_hwnd,WM_QUERYNEWPALETTE); - } - - switch (uMsg) { - - // Repaint the window if the system colours change - - case WM_SYSCOLORCHANGE: - - InvalidateRect(hwnd,NULL,FALSE); - return (LRESULT) 1; - - // Somebody has changed the palette - case WM_PALETTECHANGED: - - OnPaletteChange((HWND)wParam,uMsg); - return (LRESULT) 0; - - // We are about to receive the keyboard focus so we ask GDI to realise - // our logical palette again and hopefully it will be fully installed - // without any mapping having to be done during any picture rendering - - case WM_QUERYNEWPALETTE: - ASSERT(m_hwnd == hwnd); - return OnPaletteChange(m_hwnd,uMsg); - - // do NOT fwd WM_MOVE. the parameters are the location of the parent - // window, NOT what the renderer should be looking at. But we need - // to make sure the overlay is moved with the parent window, so we - // do this. - case WM_MOVE: - if (IsWindowVisible(m_hwnd)) { - PostMessage(m_hwnd,WM_PAINT,0,0); - } - break; - - // Store the width and height as useful base class members - - case WM_SIZE: - - OnSize(LOWORD(lParam), HIWORD(lParam)); - return (LRESULT) 0; - - // Intercept the WM_CLOSE messages to hide the window - - case WM_CLOSE: - - OnClose(); - return (LRESULT) 0; - } - return DefWindowProc(hwnd,uMsg,wParam,lParam); -} - - -// This handles the Windows palette change messages - if we do realise our -// palette then we return TRUE otherwise we return FALSE. If our window is -// foreground application then we should get first choice of colours in the -// system palette entries. We get best performance when our logical palette -// includes the standard VGA colours (at the beginning and end) otherwise -// GDI may have to map from our palette to the device palette while drawing - -LRESULT CBaseWindow::OnPaletteChange(HWND hwnd,UINT Message) -{ - // First check we are not changing the palette during closedown - - if (m_hwnd == NULL || hwnd == NULL) { - return (LRESULT) 0; - } - ASSERT(!m_bRealizing); - - // Should we realise our palette again - - if ((Message == WM_QUERYNEWPALETTE || hwnd != m_hwnd)) { - // It seems that even if we're invisible that we can get asked - // to realize our palette and this can cause really ugly side-effects - // Seems like there's another bug but this masks it a least for the - // shutting down case. - if (!IsWindowVisible(m_hwnd)) { - DbgLog((LOG_TRACE, 1, TEXT("Realizing when invisible!"))); - return (LRESULT) 0; - } - - // Avoid recursion with multiple graphs in the same app -#ifdef _DEBUG - m_bRealizing = TRUE; -#endif - DoRealisePalette(Message != WM_QUERYNEWPALETTE); -#ifdef _DEBUG - m_bRealizing = FALSE; -#endif - - // Should we redraw the window with the new palette - if (Message == WM_PALETTECHANGED) { - InvalidateRect(m_hwnd,NULL,FALSE); - } - } - - return (LRESULT) 1; -} - - -// Determine if the window exists. - -bool CBaseWindow::WindowExists() -{ - return !!IsWindow(m_hwnd); -} - - -// Return the default window rectangle - -RECT CBaseWindow::GetDefaultRect() -{ - RECT DefaultRect = {0,0,DEFWIDTH,DEFHEIGHT}; - ASSERT(m_hwnd); - // ASSERT(m_hdc); - return DefaultRect; -} - - -// Return the current window width - -LONG CBaseWindow::GetWindowWidth() -{ - ASSERT(m_hwnd); - // ASSERT(m_hdc); - return m_Width; -} - - -// Return the current window height - -LONG CBaseWindow::GetWindowHeight() -{ - ASSERT(m_hwnd); - // ASSERT(m_hdc); - return m_Height; -} - - -// Return the window handle - -HWND CBaseWindow::GetWindowHWND() -{ - ASSERT(m_hwnd); - // ASSERT(m_hdc); - return m_hwnd; -} - - -// Return the window drawing device context - -HDC CBaseWindow::GetWindowHDC() -{ - ASSERT(m_hwnd); - ASSERT(m_hdc); - return m_hdc; -} - - -// Return the offscreen window drawing device context - -HDC CBaseWindow::GetMemoryHDC() -{ - ASSERT(m_hwnd); - ASSERT(m_MemoryDC); - return m_MemoryDC; -} - - -#ifdef _DEBUG -HPALETTE CBaseWindow::GetPalette() -{ - // The palette lock should always be held when accessing - // m_hPalette. - ASSERT(CritCheckIn(&m_PaletteLock)); - return m_hPalette; -} -#endif // DEBUG - - -// This is available to clients who want to change the window visiblity. It's -// little more than an indirection to the Win32 ShowWindow although these is -// some benefit in going through here as this function may change sometime - -HRESULT CBaseWindow::DoShowWindow(LONG ShowCmd) -{ - ShowWindow(m_hwnd,ShowCmd); - return NOERROR; -} - - -// Generate a WM_PAINT message for the video window - -void CBaseWindow::PaintWindow(BOOL bErase) -{ - InvalidateRect(m_hwnd,NULL,bErase); -} - - -// Allow an application to have us set the video window in the foreground. We -// have this because it is difficult for one thread to do do this to a window -// owned by another thread. Rather than expose the message we use to execute -// the inter thread send message we provide the interface function. All we do -// is to SendMessage to the video window renderer thread with a WM_SHOWSTAGE - -void CBaseWindow::DoSetWindowForeground(BOOL bFocus) -{ - SendMessage(m_hwnd,m_ShowStageMessage,(WPARAM) bFocus,(LPARAM) 0); -} - - -// Constructor initialises the owning object pointer. Since we are a worker -// class for the main window object we have relatively few state variables to -// look after. We are given device context handles to use later on as well as -// the source and destination rectangles (but reset them here just in case) - -CDrawImage::CDrawImage(__inout CBaseWindow *pBaseWindow) : - m_pBaseWindow(pBaseWindow), - m_hdc(NULL), - m_MemoryDC(NULL), - m_bStretch(FALSE), - m_pMediaType(NULL), - m_bUsingImageAllocator(FALSE) -{ - ASSERT(pBaseWindow); - ResetPaletteVersion(); - SetRectEmpty(&m_TargetRect); - SetRectEmpty(&m_SourceRect); - - m_perfidRenderTime = MSR_REGISTER(TEXT("Single Blt time")); -} - - -// Overlay the image time stamps on the picture. Access to this method is -// serialised by the caller. We display the sample start and end times on -// top of the video using TextOut on the device context we are handed. If -// there isn't enough room in the window for the times we don't show them - -void CDrawImage::DisplaySampleTimes(IMediaSample *pSample) -{ -#ifdef _DEBUG - // - // Only allow the "annoying" time messages if the users has turned the - // logging "way up" - // - BOOL bAccept = DbgCheckModuleLevel(LOG_TRACE, 5); - if (bAccept == FALSE) { - return; - } -#endif - - TCHAR szTimes[TIMELENGTH]; // Time stamp strings - ASSERT(pSample); // Quick sanity check - RECT ClientRect; // Client window size - SIZE Size; // Size of text output - - // Get the time stamps and window size - - pSample->GetTime((REFERENCE_TIME*)&m_StartSample, (REFERENCE_TIME*)&m_EndSample); - HWND hwnd = m_pBaseWindow->GetWindowHWND(); - EXECUTE_ASSERT(GetClientRect(hwnd,&ClientRect)); - - // Format the sample time stamps - - (void)StringCchPrintf(szTimes,NUMELMS(szTimes),TEXT("%08d : %08d"), - m_StartSample.Millisecs(), - m_EndSample.Millisecs()); - - ASSERT(lstrlen(szTimes) < TIMELENGTH); - - // Put the times in the middle at the bottom of the window - - GetTextExtentPoint32(m_hdc,szTimes,lstrlen(szTimes),&Size); - INT XPos = ((ClientRect.right - ClientRect.left) - Size.cx) / 2; - INT YPos = ((ClientRect.bottom - ClientRect.top) - Size.cy) * 4 / 5; - - // Check the window is big enough to have sample times displayed - - if ((XPos > 0) && (YPos > 0)) { - TextOut(m_hdc,XPos,YPos,szTimes,lstrlen(szTimes)); - } -} - - -// This is called when the drawing code sees that the image has a down level -// palette cookie. We simply call the SetDIBColorTable Windows API with the -// palette that is found after the BITMAPINFOHEADER - we return no errors - -void CDrawImage::UpdateColourTable(HDC hdc,__in BITMAPINFOHEADER *pbmi) -{ - ASSERT(pbmi->biClrUsed); - RGBQUAD *pColourTable = (RGBQUAD *)(pbmi+1); - - // Set the new palette in the device context - - UINT uiReturn = SetDIBColorTable(hdc,(UINT) 0, - pbmi->biClrUsed, - pColourTable); - - // Should always succeed but check in debug builds - ASSERT(uiReturn == pbmi->biClrUsed); - UNREFERENCED_PARAMETER(uiReturn); -} - - -// No source rectangle scaling is done by the base class - -RECT CDrawImage::ScaleSourceRect(const RECT *pSource) -{ - ASSERT(pSource); - return *pSource; -} - - -// This is called when the funky output pin uses our allocator. The samples we -// allocate are special because the memory is shared between us and GDI thus -// removing one copy when we ask for the image to be rendered. The source type -// information is in the main renderer m_mtIn field which is initialised when -// the media type is agreed in SetMediaType, the media type may be changed on -// the fly if, for example, the source filter needs to change the palette - -void CDrawImage::FastRender(IMediaSample *pMediaSample) -{ - BITMAPINFOHEADER *pbmi; // Image format data - DIBDATA *pDibData; // Stores DIB information - BYTE *pImage; // Pointer to image data - HBITMAP hOldBitmap; // Store the old bitmap - CImageSample *pSample; // Pointer to C++ object - - ASSERT(m_pMediaType); - - // From the untyped source format block get the VIDEOINFO and subsequently - // the BITMAPINFOHEADER structure. We can cast the IMediaSample interface - // to a CImageSample object so we can retrieve it's DIBSECTION details - - pbmi = HEADER(m_pMediaType->Format()); - pSample = (CImageSample *) pMediaSample; - pDibData = pSample->GetDIBData(); - hOldBitmap = (HBITMAP) SelectObject(m_MemoryDC,pDibData->hBitmap); - - // Get a pointer to the real image data - - HRESULT hr = pMediaSample->GetPointer(&pImage); - if (FAILED(hr)) { - return; - } - - // Do we need to update the colour table, we increment our palette cookie - // each time we get a dynamic format change. The sample palette cookie is - // stored in the DIBDATA structure so we try to keep the fields in sync - // By the time we get to draw the images the format change will be done - // so all we do is ask the renderer for what it's palette version is - - if (pDibData->PaletteVersion < GetPaletteVersion()) { - ASSERT(pbmi->biBitCount <= iPALETTE); - UpdateColourTable(m_MemoryDC,pbmi); - pDibData->PaletteVersion = GetPaletteVersion(); - } - - // This allows derived classes to change the source rectangle that we do - // the drawing with. For example a renderer may ask a codec to stretch - // the video from 320x240 to 640x480, in which case the source we see in - // here will still be 320x240, although the source we want to draw with - // should be scaled up to 640x480. The base class implementation of this - // method does nothing but return the same rectangle as we are passed in - - RECT SourceRect = ScaleSourceRect(&m_SourceRect); - - // Is the window the same size as the video - - if (m_bStretch == FALSE) { - - // Put the image straight into the window - - BitBlt( - (HDC) m_hdc, // Target device HDC - m_TargetRect.left, // X sink position - m_TargetRect.top, // Y sink position - m_TargetRect.right - m_TargetRect.left, // Destination width - m_TargetRect.bottom - m_TargetRect.top, // Destination height - m_MemoryDC, // Source device context - SourceRect.left, // X source position - SourceRect.top, // Y source position - SRCCOPY); // Simple copy - - } else { - - // Stretch the image when copying to the window - - StretchBlt( - (HDC) m_hdc, // Target device HDC - m_TargetRect.left, // X sink position - m_TargetRect.top, // Y sink position - m_TargetRect.right - m_TargetRect.left, // Destination width - m_TargetRect.bottom - m_TargetRect.top, // Destination height - m_MemoryDC, // Source device HDC - SourceRect.left, // X source position - SourceRect.top, // Y source position - SourceRect.right - SourceRect.left, // Source width - SourceRect.bottom - SourceRect.top, // Source height - SRCCOPY); // Simple copy - } - - // This displays the sample times over the top of the image. This used to - // draw the times into the offscreen device context however that actually - // writes the text into the image data buffer which may not be writable - - #ifdef _DEBUG - DisplaySampleTimes(pMediaSample); - #endif - - // Put the old bitmap back into the device context so we don't leak - SelectObject(m_MemoryDC,hOldBitmap); -} - - -// This is called when there is a sample ready to be drawn, unfortunately the -// output pin was being rotten and didn't choose our super excellent shared -// memory DIB allocator so we have to do this slow render using boring old GDI -// SetDIBitsToDevice and StretchDIBits. The down side of using these GDI -// functions is that the image data has to be copied across from our address -// space into theirs before going to the screen (although in reality the cost -// is small because all they do is to map the buffer into their address space) - -void CDrawImage::SlowRender(IMediaSample *pMediaSample) -{ - // Get the BITMAPINFOHEADER for the connection - - ASSERT(m_pMediaType); - BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); - BYTE *pImage; - - // Get the image data buffer - - HRESULT hr = pMediaSample->GetPointer(&pImage); - if (FAILED(hr)) { - return; - } - - // This allows derived classes to change the source rectangle that we do - // the drawing with. For example a renderer may ask a codec to stretch - // the video from 320x240 to 640x480, in which case the source we see in - // here will still be 320x240, although the source we want to draw with - // should be scaled up to 640x480. The base class implementation of this - // method does nothing but return the same rectangle as we are passed in - - RECT SourceRect = ScaleSourceRect(&m_SourceRect); - - LONG lAdjustedSourceTop = SourceRect.top; - // if the origin of bitmap is bottom-left, adjust soruce_rect_top - // to be the bottom-left corner instead of the top-left. - if (pbmi->biHeight > 0) { - lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; - } - // Is the window the same size as the video - - if (m_bStretch == FALSE) { - - // Put the image straight into the window - - SetDIBitsToDevice( - (HDC) m_hdc, // Target device HDC - m_TargetRect.left, // X sink position - m_TargetRect.top, // Y sink position - m_TargetRect.right - m_TargetRect.left, // Destination width - m_TargetRect.bottom - m_TargetRect.top, // Destination height - SourceRect.left, // X source position - lAdjustedSourceTop, // Adjusted Y source position - (UINT) 0, // Start scan line - pbmi->biHeight, // Scan lines present - pImage, // Image data - (BITMAPINFO *) pbmi, // DIB header - DIB_RGB_COLORS); // Type of palette - - } else { - - // Stretch the image when copying to the window - - StretchDIBits( - (HDC) m_hdc, // Target device HDC - m_TargetRect.left, // X sink position - m_TargetRect.top, // Y sink position - m_TargetRect.right - m_TargetRect.left, // Destination width - m_TargetRect.bottom - m_TargetRect.top, // Destination height - SourceRect.left, // X source position - lAdjustedSourceTop, // Adjusted Y source position - SourceRect.right - SourceRect.left, // Source width - SourceRect.bottom - SourceRect.top, // Source height - pImage, // Image data - (BITMAPINFO *) pbmi, // DIB header - DIB_RGB_COLORS, // Type of palette - SRCCOPY); // Simple image copy - } - - // This shows the sample reference times over the top of the image which - // looks a little flickery. I tried using GdiSetBatchLimit and GdiFlush to - // control the screen updates but it doesn't quite work as expected and - // only partially reduces the flicker. I also tried using a memory context - // and combining the two in that before doing a final BitBlt operation to - // the screen, unfortunately this has considerable performance penalties - // and also means that this code is not executed when compiled retail - - #ifdef _DEBUG - DisplaySampleTimes(pMediaSample); - #endif -} - - -// This is called with an IMediaSample interface on the image to be drawn. We -// decide on the drawing mechanism based on who's allocator we are using. We -// may be called when the window wants an image painted by WM_PAINT messages -// We can't realise the palette here because we have the renderer lock, any -// call to realise may cause an interthread send message to the window thread -// which may in turn be waiting to get the renderer lock before servicing it - -BOOL CDrawImage::DrawImage(IMediaSample *pMediaSample) -{ - ASSERT(m_hdc); - ASSERT(m_MemoryDC); - NotifyStartDraw(); - - // If the output pin used our allocator then the samples passed are in - // fact CVideoSample objects that contain CreateDIBSection data that we - // use to do faster image rendering, they may optionally also contain a - // DirectDraw surface pointer in which case we do not do the drawing - - if (m_bUsingImageAllocator == FALSE) { - SlowRender(pMediaSample); - EXECUTE_ASSERT(GdiFlush()); - NotifyEndDraw(); - return TRUE; - } - - // This is a DIBSECTION buffer - - FastRender(pMediaSample); - EXECUTE_ASSERT(GdiFlush()); - NotifyEndDraw(); - return TRUE; -} - - -BOOL CDrawImage::DrawVideoImageHere( - HDC hdc, - IMediaSample *pMediaSample, - __in LPRECT lprcSrc, - __in LPRECT lprcDst - ) -{ - ASSERT(m_pMediaType); - BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); - BYTE *pImage; - - // Get the image data buffer - - HRESULT hr = pMediaSample->GetPointer(&pImage); - if (FAILED(hr)) { - return FALSE; - } - - RECT SourceRect; - RECT TargetRect; - - if (lprcSrc) { - SourceRect = *lprcSrc; - } - else SourceRect = ScaleSourceRect(&m_SourceRect); - - if (lprcDst) { - TargetRect = *lprcDst; - } - else TargetRect = m_TargetRect; - - LONG lAdjustedSourceTop = SourceRect.top; - // if the origin of bitmap is bottom-left, adjust soruce_rect_top - // to be the bottom-left corner instead of the top-left. - if (pbmi->biHeight > 0) { - lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; - } - - - // Stretch the image when copying to the DC - - BOOL bRet = (0 != StretchDIBits(hdc, - TargetRect.left, - TargetRect.top, - TargetRect.right - TargetRect.left, - TargetRect.bottom - TargetRect.top, - SourceRect.left, - lAdjustedSourceTop, - SourceRect.right - SourceRect.left, - SourceRect.bottom - SourceRect.top, - pImage, - (BITMAPINFO *)pbmi, - DIB_RGB_COLORS, - SRCCOPY)); - return bRet; -} - - -// This is called by the owning window object after it has created the window -// and it's drawing contexts. We are constructed with the base window we'll -// be drawing into so when given the notification we retrive the device HDCs -// to draw with. We cannot call these in our constructor as they are virtual - -void CDrawImage::SetDrawContext() -{ - m_MemoryDC = m_pBaseWindow->GetMemoryHDC(); - m_hdc = m_pBaseWindow->GetWindowHDC(); -} - - -// This is called to set the target rectangle in the video window, it will be -// called whenever a WM_SIZE message is retrieved from the message queue. We -// simply store the rectangle and use it later when we do the drawing calls - -void CDrawImage::SetTargetRect(__in RECT *pTargetRect) -{ - ASSERT(pTargetRect); - m_TargetRect = *pTargetRect; - SetStretchMode(); -} - - -// Return the current target rectangle - -void CDrawImage::GetTargetRect(__out RECT *pTargetRect) -{ - ASSERT(pTargetRect); - *pTargetRect = m_TargetRect; -} - - -// This is called when we want to change the section of the image to draw. We -// use this information in the drawing operation calls later on. We must also -// see if the source and destination rectangles have the same dimensions. If -// not we must stretch during the drawing rather than a direct pixel copy - -void CDrawImage::SetSourceRect(__in RECT *pSourceRect) -{ - ASSERT(pSourceRect); - m_SourceRect = *pSourceRect; - SetStretchMode(); -} - - -// Return the current source rectangle - -void CDrawImage::GetSourceRect(__out RECT *pSourceRect) -{ - ASSERT(pSourceRect); - *pSourceRect = m_SourceRect; -} - - -// This is called when either the source or destination rectanges change so we -// can update the stretch flag. If the rectangles don't match we stretch the -// video during the drawing otherwise we call the fast pixel copy functions -// NOTE the source and/or the destination rectangle may be completely empty - -void CDrawImage::SetStretchMode() -{ - // Calculate the overall rectangle dimensions - - LONG SourceWidth = m_SourceRect.right - m_SourceRect.left; - LONG SinkWidth = m_TargetRect.right - m_TargetRect.left; - LONG SourceHeight = m_SourceRect.bottom - m_SourceRect.top; - LONG SinkHeight = m_TargetRect.bottom - m_TargetRect.top; - - m_bStretch = TRUE; - if (SourceWidth == SinkWidth) { - if (SourceHeight == SinkHeight) { - m_bStretch = FALSE; - } - } -} - - -// Tell us whose allocator we are using. This should be called with TRUE if -// the filter agrees to use an allocator based around the CImageAllocator -// SDK base class - whose image buffers are made through CreateDIBSection. -// Otherwise this should be called with FALSE and we will draw the images -// using SetDIBitsToDevice and StretchDIBitsToDevice. None of these calls -// can handle buffers which have non zero strides (like DirectDraw uses) - -void CDrawImage::NotifyAllocator(BOOL bUsingImageAllocator) -{ - m_bUsingImageAllocator = bUsingImageAllocator; -} - - -// Are we using the image DIBSECTION allocator - -BOOL CDrawImage::UsingImageAllocator() -{ - return m_bUsingImageAllocator; -} - - -// We need the media type of the connection so that we can get the BITMAPINFO -// from it. We use that in the calls to draw the image such as StretchDIBits -// and also when updating the colour table held in shared memory DIBSECTIONs - -void CDrawImage::NotifyMediaType(__in CMediaType *pMediaType) -{ - m_pMediaType = pMediaType; -} - - -// We store in this object a cookie maintaining the current palette version. -// Each time a palettised format is changed we increment this value so that -// when we come to draw the images we look at the colour table value they -// have and if less than the current we know to update it. This version is -// only needed and indeed used when working with shared memory DIBSECTIONs - -LONG CDrawImage::GetPaletteVersion() -{ - return m_PaletteVersion; -} - - -// Resets the current palette version number - -void CDrawImage::ResetPaletteVersion() -{ - m_PaletteVersion = PALETTE_VERSION; -} - - -// Increment the current palette version - -void CDrawImage::IncrementPaletteVersion() -{ - m_PaletteVersion++; -} - - -// Constructor must initialise the base allocator. Each sample we create has a -// palette version cookie on board. When the source filter changes the palette -// during streaming the window object increments an internal cookie counter it -// keeps as well. When it comes to render the samples it looks at the cookie -// values and if they don't match then it knows to update the sample's colour -// table. However we always create samples with a cookie of PALETTE_VERSION -// If there have been multiple format changes and we disconnect and reconnect -// thereby causing the samples to be reallocated we will create them with a -// cookie much lower than the current version, this isn't a problem since it -// will be seen by the window object and the versions will then be updated - -CImageAllocator::CImageAllocator(__inout CBaseFilter *pFilter, - __in_opt LPCTSTR pName, - __inout HRESULT *phr) : - CBaseAllocator(pName,NULL,phr,TRUE,TRUE), - m_pFilter(pFilter), - m_pMediaType(NULL) -{ - ASSERT(phr); - ASSERT(pFilter); -} - - -// Check our DIB buffers have been released - -#ifdef _DEBUG -CImageAllocator::~CImageAllocator() -{ - ASSERT(m_bCommitted == FALSE); -} -#endif - - -// Called from destructor and also from base class to free resources. We work -// our way through the list of media samples deleting the DIBSECTION created -// for each. All samples should be back in our list so there is no chance a -// filter is still using one to write on the display or hold on a pending list - -void CImageAllocator::Free() -{ - ASSERT(m_lAllocated == m_lFree.GetCount()); - EXECUTE_ASSERT(GdiFlush()); - CImageSample *pSample; - DIBDATA *pDibData; - - while (m_lFree.GetCount() != 0) { - pSample = (CImageSample *) m_lFree.RemoveHead(); - pDibData = pSample->GetDIBData(); - EXECUTE_ASSERT(DeleteObject(pDibData->hBitmap)); - EXECUTE_ASSERT(CloseHandle(pDibData->hMapping)); - delete pSample; - } - - m_lAllocated = 0; -} - - -// Prepare the allocator by checking all the input parameters - -STDMETHODIMP CImageAllocator::CheckSizes(__in ALLOCATOR_PROPERTIES *pRequest) -{ - // Check we have a valid connection - - if (m_pMediaType == NULL) { - return VFW_E_NOT_CONNECTED; - } - - // NOTE We always create a DIB section with the source format type which - // may contain a source palette. When we do the BitBlt drawing operation - // the target display device may contain a different palette (we may not - // have the focus) in which case GDI will do after the palette mapping - - VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *) m_pMediaType->Format(); - - // When we call CreateDIBSection it implicitly maps only enough memory - // for the image as defined by thee BITMAPINFOHEADER. If the user asks - // for an image smaller than this then we reject the call, if they ask - // for an image larger than this then we return what they can have - - if ((DWORD) pRequest->cbBuffer < pVideoInfo->bmiHeader.biSizeImage) { - return E_INVALIDARG; - } - - // Reject buffer prefixes - - if (pRequest->cbPrefix > 0) { - return E_INVALIDARG; - } - - pRequest->cbBuffer = pVideoInfo->bmiHeader.biSizeImage; - return NOERROR; -} - - -// Agree the number of media sample buffers and their sizes. The base class -// this allocator is derived from allows samples to be aligned only on byte -// boundaries NOTE the buffers are not allocated until the Commit call - -STDMETHODIMP CImageAllocator::SetProperties( - __in ALLOCATOR_PROPERTIES * pRequest, - __out ALLOCATOR_PROPERTIES * pActual) -{ - ALLOCATOR_PROPERTIES Adjusted = *pRequest; - - // Check the parameters fit with the current connection - - HRESULT hr = CheckSizes(&Adjusted); - if (FAILED(hr)) { - return hr; - } - return CBaseAllocator::SetProperties(&Adjusted, pActual); -} - - -// Commit the memory by allocating the agreed number of media samples. For -// each sample we are committed to creating we have a CImageSample object -// that we use to manage it's resources. This is initialised with a DIBDATA -// structure that contains amongst other things the GDI DIBSECTION handle -// We will access the renderer media type during this so we must have locked -// (to prevent the format changing for example). The class overrides Commit -// and Decommit to do this locking (base class Commit in turn calls Alloc) - -HRESULT CImageAllocator::Alloc(void) -{ - ASSERT(m_pMediaType); - CImageSample *pSample; - DIBDATA DibData; - - // Check the base allocator says it's ok to continue - - HRESULT hr = CBaseAllocator::Alloc(); - if (FAILED(hr)) { - return hr; - } - - // We create a new memory mapped object although we don't map it into our - // address space because GDI does that in CreateDIBSection. It is possible - // that we run out of resources before creating all the samples in which - // case the available sample list is left with those already created - - ASSERT(m_lAllocated == 0); - while (m_lAllocated < m_lCount) { - - // Create and initialise a shared memory GDI buffer - - hr = CreateDIB(m_lSize,DibData); - if (FAILED(hr)) { - return hr; - } - - // Create the sample object and pass it the DIBDATA - - pSample = CreateImageSample(DibData.pBase,m_lSize); - if (pSample == NULL) { - EXECUTE_ASSERT(DeleteObject(DibData.hBitmap)); - EXECUTE_ASSERT(CloseHandle(DibData.hMapping)); - return E_OUTOFMEMORY; - } - - // Add the completed sample to the available list - - pSample->SetDIBData(&DibData); - m_lFree.Add(pSample); - m_lAllocated++; - } - return NOERROR; -} - - -// We have a virtual method that allocates the samples so that a derived class -// may override it and allocate more specialised sample objects. So long as it -// derives its samples from CImageSample then all this code will still work ok - -CImageSample *CImageAllocator::CreateImageSample(__in_bcount(Length) LPBYTE pData,LONG Length) -{ - HRESULT hr = NOERROR; - CImageSample *pSample; - - // Allocate the new sample and check the return codes - - pSample = new CImageSample((CBaseAllocator *) this, // Base class - NAME("Video sample"), // DEBUG name - (HRESULT *) &hr, // Return code - (LPBYTE) pData, // DIB address - (LONG) Length); // Size of DIB - - if (pSample == NULL || FAILED(hr)) { - delete pSample; - return NULL; - } - return pSample; -} - - -// This function allocates a shared memory block for use by the source filter -// generating DIBs for us to render. The memory block is created in shared -// memory so that GDI doesn't have to copy the memory when we do a BitBlt - -HRESULT CImageAllocator::CreateDIB(LONG InSize,DIBDATA &DibData) -{ - BITMAPINFO *pbmi = NULL; // Format information for pin - BYTE *pBase = NULL; // Pointer to the actual image - HANDLE hMapping; // Handle to mapped object - HBITMAP hBitmap = NULL; // DIB section bitmap handle - - // Create a file mapping object and map into our address space - - hMapping = CreateFileMapping(hMEMORY, // Use system page file - NULL, // No security attributes - PAGE_READWRITE, // Full access to memory - (DWORD) 0, // Less than 4Gb in size - InSize, // Size of buffer - NULL); // No name to section - if (hMapping == NULL) { - DWORD Error = GetLastError(); - return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); - } - - // NOTE We always create a DIB section with the source format type which - // may contain a source palette. When we do the BitBlt drawing operation - // the target display device may contain a different palette (we may not - // have the focus) in which case GDI will do after the palette mapping - - if (m_pMediaType) { - pbmi = (BITMAPINFO *)HEADER(m_pMediaType->Format()); - hBitmap = CreateDIBSection((HDC)NULL, // NO device context - pbmi, // Format information - DIB_RGB_COLORS, // Use the palette - (VOID **)&pBase, // Pointer to image data - hMapping, // Mapped memory handle - (DWORD)0); // Offset into memory - } else { - DbgBreak("Invalid media type"); - } - - if (hBitmap == NULL || pBase == NULL) { - EXECUTE_ASSERT(CloseHandle(hMapping)); - DWORD Error = GetLastError(); - return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); - } - - // Initialise the DIB information structure - - DibData.hBitmap = hBitmap; - DibData.hMapping = hMapping; - DibData.pBase = pBase; - DibData.PaletteVersion = PALETTE_VERSION; - GetObject(hBitmap,sizeof(DIBSECTION),(VOID *)&DibData.DibSection); - - return NOERROR; -} - - -// We use the media type during the DIBSECTION creation - -void CImageAllocator::NotifyMediaType(__in CMediaType *pMediaType) -{ - m_pMediaType = pMediaType; -} - - -// Overriden to increment the owning object's reference count - -STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingAddRef() -{ - return m_pFilter->AddRef(); -} - - -// Overriden to decrement the owning object's reference count - -STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingRelease() -{ - return m_pFilter->Release(); -} - - -// If you derive a class from CMediaSample that has to transport specialised -// member variables and entry points then there are three alternate solutions -// The first is to create a memory buffer larger than actually required by the -// sample and store your information either at the beginning of it or at the -// end, the former being moderately safer allowing for misbehaving transform -// filters. You then adjust the buffer address when you create the base media -// sample. This has the disadvantage of breaking up the memory allocated to -// the samples into separate blocks. The second solution is to implement a -// class derived from CMediaSample and support additional interface(s) that -// convey your private data. This means defining a custom interface. The final -// alternative is to create a class that inherits from CMediaSample and adds -// the private data structures, when you get an IMediaSample in your Receive() -// call check to see if your allocator is being used, and if it is then cast -// the IMediaSample into one of your objects. Additional checks can be made -// to ensure the sample's this pointer is known to be one of your own objects - -CImageSample::CImageSample(__inout CBaseAllocator *pAllocator, - __in_opt LPCTSTR pName, - __inout HRESULT *phr, - __in_bcount(length) LPBYTE pBuffer, - LONG length) : - CMediaSample(pName,pAllocator,phr,pBuffer,length), - m_bInit(FALSE) -{ - ZeroMemory(&m_DibData, sizeof(DIBDATA)); - ASSERT(pAllocator); - ASSERT(pBuffer); -} - - -// Set the shared memory DIB information - -void CImageSample::SetDIBData(__in DIBDATA *pDibData) -{ - ASSERT(pDibData); - m_DibData = *pDibData; - m_bInit = TRUE; -} - - -// Retrieve the shared memory DIB data - -__out DIBDATA *CImageSample::GetDIBData() -{ - ASSERT(m_bInit == TRUE); - return &m_DibData; -} - - -// This class handles the creation of a palette. It is fairly specialist and -// is intended to simplify palette management for video renderer filters. It -// is for this reason that the constructor requires three other objects with -// which it interacts, namely a base media filter, a base window and a base -// drawing object although the base window or the draw object may be NULL to -// ignore that part of us. We try not to create and install palettes unless -// absolutely necessary as they typically require WM_PALETTECHANGED messages -// to be sent to every window thread in the system which is very expensive - -CImagePalette::CImagePalette(__inout CBaseFilter *pBaseFilter, - __inout CBaseWindow *pBaseWindow, - __inout CDrawImage *pDrawImage) : - m_pBaseWindow(pBaseWindow), - m_pFilter(pBaseFilter), - m_pDrawImage(pDrawImage), - m_hPalette(NULL) -{ - ASSERT(m_pFilter); -} - - -// Destructor - -#ifdef _DEBUG -CImagePalette::~CImagePalette() -{ - ASSERT(m_hPalette == NULL); -} -#endif - - -// We allow dynamic format changes of the palette but rather than change the -// palette every time we call this to work out whether an update is required. -// If the original type didn't use a palette and the new one does (or vica -// versa) then we return TRUE. If neither formats use a palette we'll return -// FALSE. If both formats use a palette we compare their colours and return -// FALSE if they match. This therefore short circuits palette creation unless -// absolutely necessary since installing palettes is an expensive operation - -BOOL CImagePalette::ShouldUpdate(const VIDEOINFOHEADER *pNewInfo, - const VIDEOINFOHEADER *pOldInfo) -{ - // We may not have a current format yet - - if (pOldInfo == NULL) { - return TRUE; - } - - // Do both formats not require a palette - - if (ContainsPalette(pNewInfo) == FALSE) { - if (ContainsPalette(pOldInfo) == FALSE) { - return FALSE; - } - } - - // Compare the colours to see if they match - - DWORD VideoEntries = pNewInfo->bmiHeader.biClrUsed; - if (ContainsPalette(pNewInfo) == TRUE) - if (ContainsPalette(pOldInfo) == TRUE) - if (pOldInfo->bmiHeader.biClrUsed == VideoEntries) - if (pOldInfo->bmiHeader.biClrUsed > 0) - if (memcmp((PVOID) GetBitmapPalette(pNewInfo), - (PVOID) GetBitmapPalette(pOldInfo), - VideoEntries * sizeof(RGBQUAD)) == 0) { - - return FALSE; - } - return TRUE; -} - - -// This is normally called when the input pin type is set to install a palette -// We will typically be called from two different places. The first is when we -// have negotiated a palettised media type after connection, the other is when -// we receive a new type during processing with an updated palette in which -// case we must remove and release the resources held by the current palette - -// We can be passed an optional device name if we wish to prepare a palette -// for a specific monitor on a multi monitor system - -HRESULT CImagePalette::PreparePalette(const CMediaType *pmtNew, - const CMediaType *pmtOld, - __in LPSTR szDevice) -{ - const VIDEOINFOHEADER *pNewInfo = (VIDEOINFOHEADER *) pmtNew->Format(); - const VIDEOINFOHEADER *pOldInfo = (VIDEOINFOHEADER *) pmtOld->Format(); - ASSERT(pNewInfo); - - // This is an performance optimisation, when we get a media type we check - // to see if the format requires a palette change. If either we need one - // when previously we didn't or vica versa then this returns TRUE, if we - // previously needed a palette and we do now it compares their colours - - if (ShouldUpdate(pNewInfo,pOldInfo) == FALSE) { - NOTE("No update needed"); - return S_FALSE; - } - - // We must notify the filter graph that the application may have changed - // the palette although in practice we don't bother checking to see if it - // is really different. If it tries to get the palette either the window - // or renderer lock will ensure it doesn't get in until we are finished - - RemovePalette(); - m_pFilter->NotifyEvent(EC_PALETTE_CHANGED,0,0); - - // Do we need a palette for the new format - - if (ContainsPalette(pNewInfo) == FALSE) { - NOTE("New has no palette"); - return S_FALSE; - } - - if (m_pBaseWindow) { - m_pBaseWindow->LockPaletteLock(); - } - - // If we're changing the palette on the fly then we increment our palette - // cookie which is compared against the cookie also stored in all of our - // DIBSECTION media samples. If they don't match when we come to draw it - // then we know the sample is out of date and we'll update it's palette - - NOTE("Making new colour palette"); - m_hPalette = MakePalette(pNewInfo, szDevice); - ASSERT(m_hPalette != NULL); - - if (m_pBaseWindow) { - m_pBaseWindow->UnlockPaletteLock(); - } - - // The window in which the new palette is to be realised may be a NULL - // pointer to signal that no window is in use, if so we don't call it - // Some filters just want to use this object to create/manage palettes - - if (m_pBaseWindow) m_pBaseWindow->SetPalette(m_hPalette); - - // This is the only time where we need access to the draw object to say - // to it that a new palette will be arriving on a sample real soon. The - // constructor may take a NULL pointer in which case we don't call this - - if (m_pDrawImage) m_pDrawImage->IncrementPaletteVersion(); - return NOERROR; -} - - -// Helper function to copy a palette out of any kind of VIDEOINFO (ie it may -// be YUV or true colour) into a palettised VIDEOINFO. We use this changing -// palettes on DirectDraw samples as a source filter can attach a palette to -// any buffer (eg YUV) and hand it back. We make a new palette out of that -// format and then copy the palette colours into the current connection type - -HRESULT CImagePalette::CopyPalette(const CMediaType *pSrc,__out CMediaType *pDest) -{ - // Reset the destination palette before starting - - VIDEOINFOHEADER *pDestInfo = (VIDEOINFOHEADER *) pDest->Format(); - pDestInfo->bmiHeader.biClrUsed = 0; - pDestInfo->bmiHeader.biClrImportant = 0; - - // Does the destination have a palette - - if (PALETTISED(pDestInfo) == FALSE) { - NOTE("No destination palette"); - return S_FALSE; - } - - // Does the source contain a palette - - const VIDEOINFOHEADER *pSrcInfo = (VIDEOINFOHEADER *) pSrc->Format(); - if (ContainsPalette(pSrcInfo) == FALSE) { - NOTE("No source palette"); - return S_FALSE; - } - - // The number of colours may be zero filled - - DWORD PaletteEntries = pSrcInfo->bmiHeader.biClrUsed; - if (PaletteEntries == 0) { - DWORD Maximum = (1 << pSrcInfo->bmiHeader.biBitCount); - NOTE1("Setting maximum colours (%d)",Maximum); - PaletteEntries = Maximum; - } - - // Make sure the destination has enough room for the palette - - ASSERT(pSrcInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); - ASSERT(pSrcInfo->bmiHeader.biClrImportant <= PaletteEntries); - ASSERT(COLORS(pDestInfo) == GetBitmapPalette(pDestInfo)); - pDestInfo->bmiHeader.biClrUsed = PaletteEntries; - pDestInfo->bmiHeader.biClrImportant = pSrcInfo->bmiHeader.biClrImportant; - ULONG BitmapSize = GetBitmapFormatSize(HEADER(pSrcInfo)); - - if (pDest->FormatLength() < BitmapSize) { - NOTE("Reallocating destination"); - pDest->ReallocFormatBuffer(BitmapSize); - } - - // Now copy the palette colours across - - CopyMemory((PVOID) COLORS(pDestInfo), - (PVOID) GetBitmapPalette(pSrcInfo), - PaletteEntries * sizeof(RGBQUAD)); - - return NOERROR; -} - - -// This is normally called when the palette is changed (typically during a -// dynamic format change) to remove any palette we previously installed. We -// replace it (if necessary) in the video window with a standard VGA palette -// that should always be available even if this is a true colour display - -HRESULT CImagePalette::RemovePalette() -{ - if (m_pBaseWindow) { - m_pBaseWindow->LockPaletteLock(); - } - - // Do we have a palette to remove - - if (m_hPalette != NULL) { - - if (m_pBaseWindow) { - // Make sure that the window's palette handle matches - // our palette handle. - ASSERT(m_hPalette == m_pBaseWindow->GetPalette()); - - m_pBaseWindow->UnsetPalette(); - } - - EXECUTE_ASSERT(DeleteObject(m_hPalette)); - m_hPalette = NULL; - } - - if (m_pBaseWindow) { - m_pBaseWindow->UnlockPaletteLock(); - } - - return NOERROR; -} - - -// Called to create a palette for the object, the data structure used by GDI -// to describe a palette is a LOGPALETTE, this includes a variable number of -// PALETTEENTRY fields which are the colours, we have to convert the RGBQUAD -// colour fields we are handed in a BITMAPINFO from the media type into these -// This handles extraction of palettes from true colour and YUV media formats - -// We can be passed an optional device name if we wish to prepare a palette -// for a specific monitor on a multi monitor system - -HPALETTE CImagePalette::MakePalette(const VIDEOINFOHEADER *pVideoInfo, __in LPSTR szDevice) -{ - ASSERT(ContainsPalette(pVideoInfo) == TRUE); - ASSERT(pVideoInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); - BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); - - const RGBQUAD *pColours; // Pointer to the palette - LOGPALETTE *lp; // Used to create a palette - HPALETTE hPalette; // Logical palette object - - lp = (LOGPALETTE *) new BYTE[sizeof(LOGPALETTE) + SIZE_PALETTE]; - if (lp == NULL) { - return NULL; - } - - // Unfortunately for some hare brained reason a GDI palette entry (a - // PALETTEENTRY structure) is different to a palette entry from a DIB - // format (a RGBQUAD structure) so we have to do the field conversion - // The VIDEOINFO containing the palette may be a true colour type so - // we use GetBitmapPalette to skip over any bit fields if they exist - - lp->palVersion = PALVERSION; - lp->palNumEntries = (USHORT) pHeader->biClrUsed; - if (lp->palNumEntries == 0) lp->palNumEntries = (1 << pHeader->biBitCount); - pColours = GetBitmapPalette(pVideoInfo); - - for (DWORD dwCount = 0;dwCount < lp->palNumEntries;dwCount++) { - lp->palPalEntry[dwCount].peRed = pColours[dwCount].rgbRed; - lp->palPalEntry[dwCount].peGreen = pColours[dwCount].rgbGreen; - lp->palPalEntry[dwCount].peBlue = pColours[dwCount].rgbBlue; - lp->palPalEntry[dwCount].peFlags = 0; - } - - MakeIdentityPalette(lp->palPalEntry, lp->palNumEntries, szDevice); - - // Create a logical palette - - hPalette = CreatePalette(lp); - ASSERT(hPalette != NULL); - delete[] lp; - return hPalette; -} - - -// GDI does a fair job of compressing the palette entries you give it, so for -// example if you have five entries with an RGB colour (0,0,0) it will remove -// all but one of them. When you subsequently draw an image it will map from -// your logical palette to the compressed device palette. This function looks -// to see if it is trying to be an identity palette and if so sets the flags -// field in the PALETTEENTRYs so they remain expanded to boost performance - -// We can be passed an optional device name if we wish to prepare a palette -// for a specific monitor on a multi monitor system - -HRESULT CImagePalette::MakeIdentityPalette(__inout_ecount_full(iColours) PALETTEENTRY *pEntry,INT iColours, __in LPSTR szDevice) -{ - PALETTEENTRY SystemEntries[10]; // System palette entries - BOOL bIdentityPalette = TRUE; // Is an identity palette - ASSERT(iColours <= iPALETTE_COLORS); // Should have a palette - const int PalLoCount = 10; // First ten reserved colours - const int PalHiStart = 246; // Last VGA palette entries - - // Does this have the full colour range - - if (iColours < 10) { - return S_FALSE; - } - - // Apparently some displays have odd numbers of system colours - - // Get a DC on the right monitor - it's ugly, but this is the way you have - // to do it - HDC hdc; - if (szDevice == NULL || lstrcmpiLocaleIndependentA(szDevice, "DISPLAY") == 0) - hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); - else - hdc = CreateDCA(NULL, szDevice, NULL, NULL); - if (NULL == hdc) { - return E_OUTOFMEMORY; - } - INT Reserved = GetDeviceCaps(hdc,NUMRESERVED); - if (Reserved != 20) { - DeleteDC(hdc); - return S_FALSE; - } - - // Compare our palette against the first ten system entries. The reason I - // don't do a memory compare between our two arrays of colours is because - // I am not sure what will be in the flags fields for the system entries - - UINT Result = GetSystemPaletteEntries(hdc,0,PalLoCount,SystemEntries); - for (UINT Count = 0;Count < Result;Count++) { - if (SystemEntries[Count].peRed != pEntry[Count].peRed || - SystemEntries[Count].peGreen != pEntry[Count].peGreen || - SystemEntries[Count].peBlue != pEntry[Count].peBlue) { - bIdentityPalette = FALSE; - } - } - - // And likewise compare against the last ten entries - - Result = GetSystemPaletteEntries(hdc,PalHiStart,PalLoCount,SystemEntries); - for (UINT Count = 0;Count < Result;Count++) { - if (INT(Count) + PalHiStart < iColours) { - if (SystemEntries[Count].peRed != pEntry[PalHiStart + Count].peRed || - SystemEntries[Count].peGreen != pEntry[PalHiStart + Count].peGreen || - SystemEntries[Count].peBlue != pEntry[PalHiStart + Count].peBlue) { - bIdentityPalette = FALSE; - } - } - } - - // If not an identity palette then return S_FALSE - - DeleteDC(hdc); - if (bIdentityPalette == FALSE) { - return S_FALSE; - } - - // Set the non VGA entries so that GDI doesn't map them - - for (UINT Count = PalLoCount; INT(Count) < std::min(PalHiStart, iColours); Count++) { - pEntry[Count].peFlags = PC_NOCOLLAPSE; - } - return NOERROR; -} - - -// Constructor initialises the VIDEOINFO we keep storing the current display -// format. The format can be changed at any time, to reset the format held -// by us call the RefreshDisplayType directly (it's a public method). Since -// more than one thread will typically call us (ie window threads resetting -// the type and source threads in the type checking methods) we have a lock - -CImageDisplay::CImageDisplay() -{ - RefreshDisplayType(NULL); -} - - - -// This initialises the format we hold which contains the display device type -// We do a conversion on the display device type in here so that when we start -// type checking input formats we can assume that certain fields have been set -// correctly, an example is when we make the 16 bit mask fields explicit. This -// is normally called when we receive WM_DEVMODECHANGED device change messages - -// The optional szDeviceName parameter tells us which monitor we are interested -// in for a multi monitor system - -HRESULT CImageDisplay::RefreshDisplayType(__in_opt LPSTR szDeviceName) -{ - CAutoLock cDisplayLock(this); - - // Set the preferred format type - - ZeroMemory((PVOID)&m_Display,sizeof(VIDEOINFOHEADER)+sizeof(TRUECOLORINFO)); - m_Display.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - m_Display.bmiHeader.biBitCount = FALSE; - - // Get the bit depth of a device compatible bitmap - - // get caps of whichever monitor they are interested in (multi monitor) - HDC hdcDisplay; - // it's ugly, but this is the way you have to do it - if (szDeviceName == NULL || lstrcmpiLocaleIndependentA(szDeviceName, "DISPLAY") == 0) - hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL); - else - hdcDisplay = CreateDCA(NULL, szDeviceName, NULL, NULL); - if (hdcDisplay == NULL) { - ASSERT(FALSE); - DbgLog((LOG_ERROR,1,TEXT("ACK! Can't get a DC for %hs"), - szDeviceName ? szDeviceName : "")); - return E_FAIL; - } else { - DbgLog((LOG_TRACE,3,TEXT("Created a DC for %s"), - szDeviceName ? szDeviceName : "")); - } - HBITMAP hbm = CreateCompatibleBitmap(hdcDisplay,1,1); - if ( hbm ) - { - GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); - - // This call will get the colour table or the proper bitfields - GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); - DeleteObject(hbm); - } - DeleteDC(hdcDisplay); - - // Complete the display type initialisation - - ASSERT(CheckHeaderValidity(&m_Display)); - UpdateFormat(&m_Display); - DbgLog((LOG_TRACE,3,TEXT("New DISPLAY bit depth =%d"), - m_Display.bmiHeader.biBitCount)); - return NOERROR; -} - - -// We assume throughout this code that any bitfields masks are allowed no -// more than eight bits to store a colour component. This checks that the -// bit count assumption is enforced and also makes sure that all the bits -// set are contiguous. We return a boolean TRUE if the field checks out ok - -BOOL CImageDisplay::CheckBitFields(const VIDEOINFO *pInput) -{ - DWORD *pBitFields = (DWORD *) BITMASKS(pInput); - - for (INT iColour = iRED;iColour <= iBLUE;iColour++) { - - // First of all work out how many bits are set - - DWORD SetBits = CountSetBits(pBitFields[iColour]); - if (SetBits > iMAXBITS || SetBits == 0) { - NOTE1("Bit fields for component %d invalid",iColour); - return FALSE; - } - - // Next work out the number of zero bits prefix - DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); - - // This is going to see if all the bits set are contiguous (as they - // should be). We know how much to shift them right by from the - // count of prefix bits. The number of bits set defines a mask, we - // invert this (ones complement) and AND it with the shifted bit - // fields. If the result is NON zero then there are bit(s) sticking - // out the left hand end which means they are not contiguous - - DWORD TestField = pBitFields[iColour] >> PrefixBits; - DWORD Mask = ULONG_MAX << SetBits; - if (TestField & Mask) { - NOTE1("Bit fields for component %d not contiguous",iColour); - return FALSE; - } - } - return TRUE; -} - - -// This counts the number of bits set in the input field - -DWORD CImageDisplay::CountSetBits(DWORD Field) -{ - // This is a relatively well known bit counting algorithm - - DWORD Count = 0; - DWORD init = Field; - - // Until the input is exhausted, count the number of bits - - while (init) { - init = init & (init - 1); // Turn off the bottommost bit - Count++; - } - return Count; -} - - -// This counts the number of zero bits upto the first one set NOTE the input -// field should have been previously checked to ensure there is at least one -// set although if we don't find one set we return the impossible value 32 - -DWORD CImageDisplay::CountPrefixBits(DWORD Field) -{ - DWORD Mask = 1; - DWORD Count = 0; - - for (;;) { - if (Field & Mask) { - return Count; - } - Count++; - - ASSERT(Mask != 0x80000000); - if (Mask == 0x80000000) { - return Count; - } - Mask <<= 1; - } -} - - -// This is called to check the BITMAPINFOHEADER for the input type. There are -// many implicit dependancies between the fields in a header structure which -// if we validate now make for easier manipulation in subsequent handling. We -// also check that the BITMAPINFOHEADER matches it's specification such that -// fields likes the number of planes is one, that it's structure size is set -// correctly and that the bitmap dimensions have not been set as negative - -BOOL CImageDisplay::CheckHeaderValidity(const VIDEOINFO *pInput) -{ - // Check the bitmap width and height are not negative. - - if (pInput->bmiHeader.biWidth <= 0 || - pInput->bmiHeader.biHeight <= 0) { - NOTE("Invalid bitmap dimensions"); - return FALSE; - } - - // Check the compression is either BI_RGB or BI_BITFIELDS - - if (pInput->bmiHeader.biCompression != BI_RGB) { - if (pInput->bmiHeader.biCompression != BI_BITFIELDS) { - NOTE("Invalid compression format"); - return FALSE; - } - } - - // If BI_BITFIELDS compression format check the colour depth - - if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { - if (pInput->bmiHeader.biBitCount != 16) { - if (pInput->bmiHeader.biBitCount != 32) { - NOTE("BI_BITFIELDS not 16/32 bit depth"); - return FALSE; - } - } - } - - // Check the assumptions about the layout of the bit fields - - if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { - if (CheckBitFields(pInput) == FALSE) { - NOTE("Bit fields are not valid"); - return FALSE; - } - } - - // Are the number of planes equal to one - - if (pInput->bmiHeader.biPlanes != 1) { - NOTE("Number of planes not one"); - return FALSE; - } - - // Check the image size is consistent (it can be zero) - - if (pInput->bmiHeader.biSizeImage != GetBitmapSize(&pInput->bmiHeader)) { - if (pInput->bmiHeader.biSizeImage) { - NOTE("Image size incorrectly set"); - return FALSE; - } - } - - // Check the size of the structure - - if (pInput->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) { - NOTE("Size of BITMAPINFOHEADER wrong"); - return FALSE; - } - return CheckPaletteHeader(pInput); -} - - -// This runs a few simple tests against the palette fields in the input to -// see if it looks vaguely correct. The tests look at the number of palette -// colours present, the number considered important and the biCompression -// field which should always be BI_RGB as no other formats are meaningful - -BOOL CImageDisplay::CheckPaletteHeader(const VIDEOINFO *pInput) -{ - // The checks here are for palettised videos only - - if (PALETTISED(pInput) == FALSE) { - if (pInput->bmiHeader.biClrUsed) { - NOTE("Invalid palette entries"); - return FALSE; - } - return TRUE; - } - - // Compression type of BI_BITFIELDS is meaningless for palette video - - if (pInput->bmiHeader.biCompression != BI_RGB) { - NOTE("Palettised video must be BI_RGB"); - return FALSE; - } - - // Check the number of palette colours is correct - - if (pInput->bmiHeader.biClrUsed > PALETTE_ENTRIES(pInput)) { - NOTE("Too many colours in palette"); - return FALSE; - } - - // The number of important colours shouldn't exceed the number used - - if (pInput->bmiHeader.biClrImportant > pInput->bmiHeader.biClrUsed) { - NOTE("Too many important colours"); - return FALSE; - } - return TRUE; -} - - -// Return the format of the video display - -const VIDEOINFO *CImageDisplay::GetDisplayFormat() -{ - return &m_Display; -} - - -// Return TRUE if the display uses a palette - -BOOL CImageDisplay::IsPalettised() -{ - return PALETTISED(&m_Display); -} - - -// Return the bit depth of the current display setting - -WORD CImageDisplay::GetDisplayDepth() -{ - return m_Display.bmiHeader.biBitCount; -} - - -// Initialise the optional fields in a VIDEOINFO. These are mainly to do with -// the source and destination rectangles and palette information such as the -// number of colours present. It simplifies our code just a little if we don't -// have to keep checking for all the different valid permutations in a header -// every time we want to do anything with it (an example would be creating a -// palette). We set the base class media type before calling this function so -// that the media types between the pins match after a connection is made - -HRESULT CImageDisplay::UpdateFormat(__inout VIDEOINFO *pVideoInfo) -{ - ASSERT(pVideoInfo); - - BITMAPINFOHEADER *pbmi = HEADER(pVideoInfo); - UNREFERENCED_PARAMETER(pbmi); - SetRectEmpty(&pVideoInfo->rcSource); - SetRectEmpty(&pVideoInfo->rcTarget); - - // Set the number of colours explicitly - - if (PALETTISED(pVideoInfo)) { - if (pVideoInfo->bmiHeader.biClrUsed == 0) { - pVideoInfo->bmiHeader.biClrUsed = PALETTE_ENTRIES(pVideoInfo); - } - } - - // The number of important colours shouldn't exceed the number used, on - // some displays the number of important colours is not initialised when - // retrieving the display type so we set the colours used correctly - - if (pVideoInfo->bmiHeader.biClrImportant > pVideoInfo->bmiHeader.biClrUsed) { - pVideoInfo->bmiHeader.biClrImportant = PALETTE_ENTRIES(pVideoInfo); - } - - // Change the image size field to be explicit - - if (pVideoInfo->bmiHeader.biSizeImage == 0) { - pVideoInfo->bmiHeader.biSizeImage = GetBitmapSize(&pVideoInfo->bmiHeader); - } - return NOERROR; -} - - -// Lots of video rendering filters want code to check proposed formats are ok -// This checks the VIDEOINFO we are passed as a media type. If the media type -// is a valid media type then we return NOERROR otherwise E_INVALIDARG. Note -// however we only accept formats that can be easily displayed in the display -// so if we are on a 16 bit device we will not accept 24 bit images. The one -// complexity is that most displays draw 8 bit palettised images efficiently -// Also if the input format is less colour bits per pixel then we also accept - -HRESULT CImageDisplay::CheckVideoType(const VIDEOINFO *pInput) -{ - // First of all check the VIDEOINFOHEADER looks correct - - if (CheckHeaderValidity(pInput) == FALSE) { - return E_INVALIDARG; - } - - // Virtually all devices support palettised images efficiently - - if (m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount) { - if (PALETTISED(pInput) == TRUE) { - ASSERT(PALETTISED(&m_Display) == TRUE); - NOTE("(Video) Type connection ACCEPTED"); - return NOERROR; - } - } - - - // Is the display depth greater than the input format - - if (m_Display.bmiHeader.biBitCount > pInput->bmiHeader.biBitCount) { - NOTE("(Video) Mismatch agreed"); - return NOERROR; - } - - // Is the display depth less than the input format - - if (m_Display.bmiHeader.biBitCount < pInput->bmiHeader.biBitCount) { - NOTE("(Video) Format mismatch"); - return E_INVALIDARG; - } - - - // Both input and display formats are either BI_RGB or BI_BITFIELDS - - ASSERT(m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount); - ASSERT(PALETTISED(pInput) == FALSE); - ASSERT(PALETTISED(&m_Display) == FALSE); - - // BI_RGB 16 bit representation is implicitly RGB555, and likewise BI_RGB - // 24 bit representation is RGB888. So we initialise a pointer to the bit - // fields they really mean and check against the display device format - // This is only going to be called when both formats are equal bits pixel - - const DWORD *pInputMask = GetBitMasks(pInput); - const DWORD *pDisplayMask = GetBitMasks((VIDEOINFO *)&m_Display); - - if (pInputMask[iRED] != pDisplayMask[iRED] || - pInputMask[iGREEN] != pDisplayMask[iGREEN] || - pInputMask[iBLUE] != pDisplayMask[iBLUE]) { - - NOTE("(Video) Bit field mismatch"); - return E_INVALIDARG; - } - - NOTE("(Video) Type connection ACCEPTED"); - return NOERROR; -} - - -// Return the bit masks for the true colour VIDEOINFO provided - -const DWORD *CImageDisplay::GetBitMasks(const VIDEOINFO *pVideoInfo) -{ - static const DWORD FailMasks[] = {0,0,0}; - - if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { - return BITMASKS(pVideoInfo); - } - - ASSERT(pVideoInfo->bmiHeader.biCompression == BI_RGB); - - switch (pVideoInfo->bmiHeader.biBitCount) { - case 16: return bits555; - case 24: return bits888; - case 32: return bits888; - default: return FailMasks; - } -} - - -// Check to see if we can support media type pmtIn as proposed by the output -// pin - We first check that the major media type is video and also identify -// the media sub type. Then we thoroughly check the VIDEOINFO type provided -// As well as the contained VIDEOINFO being correct the major type must be -// video, the subtype a recognised video format and the type GUID correct - -HRESULT CImageDisplay::CheckMediaType(const CMediaType *pmtIn) -{ - // Does this have a VIDEOINFOHEADER format block - - const GUID *pFormatType = pmtIn->FormatType(); - if (*pFormatType != FORMAT_VideoInfo) { - NOTE("Format GUID not a VIDEOINFOHEADER"); - return E_INVALIDARG; - } - ASSERT(pmtIn->Format()); - - // Check the format looks reasonably ok - - ULONG Length = pmtIn->FormatLength(); - if (Length < SIZE_VIDEOHEADER) { - NOTE("Format smaller than a VIDEOHEADER"); - return E_FAIL; - } - - VIDEOINFO *pInput = (VIDEOINFO *) pmtIn->Format(); - - // Check the major type is MEDIATYPE_Video - - const GUID *pMajorType = pmtIn->Type(); - if (*pMajorType != MEDIATYPE_Video) { - NOTE("Major type not MEDIATYPE_Video"); - return E_INVALIDARG; - } - - // Check we can identify the media subtype - - const GUID *pSubType = pmtIn->Subtype(); - if (GetBitCount(pSubType) == USHRT_MAX) { - NOTE("Invalid video media subtype"); - return E_INVALIDARG; - } - return CheckVideoType(pInput); -} - - -// Given a video format described by a VIDEOINFO structure we return the mask -// that is used to obtain the range of acceptable colours for this type, for -// example, the mask for a 24 bit true colour format is 0xFF in all cases. A -// 16 bit 5:6:5 display format uses 0xF8, 0xFC and 0xF8, therefore given any -// RGB triplets we can AND them with these fields to find one that is valid - -BOOL CImageDisplay::GetColourMask(__out DWORD *pMaskRed, - __out DWORD *pMaskGreen, - __out DWORD *pMaskBlue) -{ - CAutoLock cDisplayLock(this); - *pMaskRed = 0xFF; - *pMaskGreen = 0xFF; - *pMaskBlue = 0xFF; - - // If this format is palettised then it doesn't have bit fields - - if (m_Display.bmiHeader.biBitCount < 16) { - return FALSE; - } - - // If this is a 24 bit true colour display then it can handle all the - // possible colour component ranges described by a byte. It is never - // allowed for a 24 bit colour depth image to have BI_BITFIELDS set - - if (m_Display.bmiHeader.biBitCount == 24) { - ASSERT(m_Display.bmiHeader.biCompression == BI_RGB); - return TRUE; - } - - // Calculate the mask based on the format's bit fields - - const DWORD *pBitFields = (DWORD *) GetBitMasks((VIDEOINFO *)&m_Display); - DWORD *pOutputMask[] = { pMaskRed, pMaskGreen, pMaskBlue }; - - // We know from earlier testing that there are no more than iMAXBITS - // bits set in the mask and that they are all contiguous. All that - // therefore remains is to shift them into the correct position - - for (INT iColour = iRED;iColour <= iBLUE;iColour++) { - - // This works out how many bits there are and where they live - - DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); - DWORD SetBits = CountSetBits(pBitFields[iColour]); - - // The first shift moves the bit field so that it is right justified - // in the DWORD, after which we then shift it back left which then - // puts the leading bit in the bytes most significant bit position - - *(pOutputMask[iColour]) = pBitFields[iColour] >> PrefixBits; - *(pOutputMask[iColour]) <<= (iMAXBITS - SetBits); - } - return TRUE; -} - - -/* Helper to convert to VIDEOINFOHEADER2 -*/ -STDAPI ConvertVideoInfoToVideoInfo2(__inout AM_MEDIA_TYPE *pmt) -{ - if (pmt->formattype != FORMAT_VideoInfo) { - return E_INVALIDARG; - } - if (NULL == pmt->pbFormat || pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { - return E_INVALIDARG; - } - VIDEOINFO *pVideoInfo = (VIDEOINFO *)pmt->pbFormat; - UNREFERENCED_PARAMETER(pVideoInfo); - DWORD dwNewSize; - HRESULT hr = DWordAdd(pmt->cbFormat, sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER), &dwNewSize); - if (FAILED(hr)) { - return hr; - } - PVOID pvNew = CoTaskMemAlloc(dwNewSize); - if (pvNew == NULL) { - return E_OUTOFMEMORY; - } - CopyMemory(pvNew, pmt->pbFormat, FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); - ZeroMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), - sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER)); - CopyMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader), - pmt->pbFormat + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), - pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); - VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pvNew; - pVideoInfo2->dwPictAspectRatioX = (DWORD)pVideoInfo2->bmiHeader.biWidth; - pVideoInfo2->dwPictAspectRatioY = (DWORD)abs(pVideoInfo2->bmiHeader.biHeight); - pmt->formattype = FORMAT_VideoInfo2; - CoTaskMemFree(pmt->pbFormat); - pmt->pbFormat = (PBYTE)pvNew; - pmt->cbFormat += sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER); - return S_OK; -} - - -// Check a media type containing VIDEOINFOHEADER -STDAPI CheckVideoInfoType(const AM_MEDIA_TYPE *pmt) -{ - if (NULL == pmt || NULL == pmt->pbFormat) { - return E_POINTER; - } - if (pmt->majortype != MEDIATYPE_Video || - pmt->formattype != FORMAT_VideoInfo || - pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - const VIDEOINFOHEADER *pHeader = (const VIDEOINFOHEADER *)pmt->pbFormat; - if (!ValidateBitmapInfoHeader( - &pHeader->bmiHeader, - pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader))) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - - return S_OK; -} - -// Check a media type containing VIDEOINFOHEADER2 -STDAPI CheckVideoInfo2Type(const AM_MEDIA_TYPE *pmt) -{ - if (NULL == pmt || NULL == pmt->pbFormat) { - return E_POINTER; - } - if (pmt->majortype != MEDIATYPE_Video || - pmt->formattype != FORMAT_VideoInfo2 || - pmt->cbFormat < sizeof(VIDEOINFOHEADER2)) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - const VIDEOINFOHEADER2 *pHeader = (const VIDEOINFOHEADER2 *)pmt->pbFormat; - if (!ValidateBitmapInfoHeader( - &pHeader->bmiHeader, - pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader))) { - return VFW_E_TYPE_NOT_ACCEPTED; - } - - return S_OK; -} +//------------------------------------------------------------------------------ +// File: WinUtil.cpp +// +// Desc: DirectShow base classes - implements generic window handler class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#include +#include +#include +#include "checkbmi.h" + +static UINT MsgDestroy; + +// Constructor + +CBaseWindow::CBaseWindow(BOOL bDoGetDC, bool bDoPostToDestroy) : + m_hInstance(g_hInst), + m_hwnd(NULL), + m_hdc(NULL), + m_bActivated(FALSE), + m_pClassName(NULL), + m_ClassStyles(0), + m_WindowStyles(0), + m_WindowStylesEx(0), + m_ShowStageMessage(0), + m_ShowStageTop(0), + m_MemoryDC(NULL), + m_hPalette(NULL), + m_bBackground(FALSE), +#ifdef _DEBUG + m_bRealizing(FALSE), +#endif + m_bNoRealize(FALSE), + m_bDoPostToDestroy(bDoPostToDestroy), + m_bDoGetDC(bDoGetDC), + m_Width(0), + m_Height(0), + m_RealizePalette(0) +{ +} + + +// Prepare a window by spinning off a worker thread to do the creation and +// also poll the message input queue. We leave this to be called by derived +// classes because they might want to override methods like MessageLoop and +// InitialiseWindow, if we do this during construction they'll ALWAYS call +// this base class methods. We make the worker thread create the window so +// it owns it rather than the filter graph thread which is constructing us + +HRESULT CBaseWindow::PrepareWindow() +{ + if (m_hwnd) return NOERROR; + ASSERT(m_hwnd == NULL); + ASSERT(m_hdc == NULL); + + // Get the derived object's window and class styles + + m_pClassName = GetClassWindowStyles(&m_ClassStyles, + &m_WindowStyles, + &m_WindowStylesEx); + if (m_pClassName == NULL) { + return E_FAIL; + } + + // Register our special private messages + m_ShowStageMessage = RegisterWindowMessage(SHOWSTAGE); + + // RegisterWindowMessage() returns 0 if an error occurs. + if (0 == m_ShowStageMessage) { + return AmGetLastErrorToHResult(); + } + + m_ShowStageTop = RegisterWindowMessage(SHOWSTAGETOP); + if (0 == m_ShowStageTop) { + return AmGetLastErrorToHResult(); + } + + m_RealizePalette = RegisterWindowMessage(REALIZEPALETTE); + if (0 == m_RealizePalette) { + return AmGetLastErrorToHResult(); + } + + MsgDestroy = RegisterWindowMessage(TEXT("AM_DESTROY")); + if (0 == MsgDestroy) { + return AmGetLastErrorToHResult(); + } + + return DoCreateWindow(); +} + + +// Destructor just a placeholder so that we know it becomes virtual +// Derived classes MUST call DoneWithWindow in their destructors so +// that no messages arrive after the derived class constructor ends + +#ifdef _DEBUG +CBaseWindow::~CBaseWindow() +{ + ASSERT(m_hwnd == NULL); + ASSERT(m_hdc == NULL); +} +#endif + + +// We use the sync worker event to have the window destroyed. All we do is +// signal the event and wait on the window thread handle. Trying to send it +// messages causes too many problems, furthermore to be on the safe side we +// just wait on the thread handle while it returns WAIT_TIMEOUT or there is +// a sent message to process on this thread. If the constructor failed to +// create the thread in the first place then the loop will get terminated + +HRESULT CBaseWindow::DoneWithWindow() +{ + if (!IsWindow(m_hwnd) || (GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId())) { + + if (IsWindow(m_hwnd)) { + + // This code should only be executed if the window exists and if the window's + // messages are processed on a different thread. + ASSERT(GetWindowThreadProcessId(m_hwnd, NULL) != GetCurrentThreadId()); + + if (m_bDoPostToDestroy) { + + HRESULT hr = S_OK; + CAMEvent m_evDone(FALSE, &hr); + if (FAILED(hr)) { + return hr; + } + + // We must post a message to destroy the window + // That way we can't be in the middle of processing a + // message posted to our window when we do go away + // Sending a message gives less synchronization. + PostMessage(m_hwnd, MsgDestroy, (WPARAM)(HANDLE)m_evDone, 0); + WaitDispatchingMessages(m_evDone, INFINITE); + } else { + SendMessage(m_hwnd, MsgDestroy, 0, 0); + } + } + + // + // This is not a leak, the window manager automatically free's + // hdc's that were got via GetDC, which is the case here. + // We set it to NULL so that we don't get any asserts later. + // + m_hdc = NULL; + + // + // We need to free this DC though because USER32 does not know + // anything about it. + // + if (m_MemoryDC) + { + EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); + m_MemoryDC = NULL; + } + + // Reset the window variables + m_hwnd = NULL; + + return NOERROR; + } + const HWND hwnd = m_hwnd; + if (hwnd == NULL) { + return NOERROR; + } + + InactivateWindow(); + NOTE("Inactivated"); + + // Reset the window styles before destruction + + SetWindowLong(hwnd,GWL_STYLE,m_WindowStyles); + ASSERT(GetParent(hwnd) == NULL); + NOTE1("Reset window styles %d",m_WindowStyles); + + // UnintialiseWindow sets m_hwnd to NULL so save a copy + UninitialiseWindow(); + DbgLog((LOG_TRACE, 2, TEXT("Destroying 0x%8.8X"), hwnd)); + if (!DestroyWindow(hwnd)) { + DbgLog((LOG_TRACE, 0, TEXT("DestroyWindow %8.8X failed code %d"), + hwnd, GetLastError())); + DbgBreak(""); + } + + // Reset our state so we can be prepared again + + m_pClassName = NULL; + m_ClassStyles = 0; + m_WindowStyles = 0; + m_WindowStylesEx = 0; + m_ShowStageMessage = 0; + m_ShowStageTop = 0; + + return NOERROR; +} + + +// Called at the end to put the window in an inactive state. The pending list +// will always have been cleared by this time so event if the worker thread +// gets has been signaled and gets in to render something it will find both +// the state has been changed and that there are no available sample images +// Since we wait on the window thread to complete we don't lock the object + +HRESULT CBaseWindow::InactivateWindow() +{ + // Has the window been activated + if (m_bActivated == FALSE) { + return S_FALSE; + } + + m_bActivated = FALSE; + ShowWindow(m_hwnd,SW_HIDE); + return NOERROR; +} + + +HRESULT CBaseWindow::CompleteConnect() +{ + m_bActivated = FALSE; + return NOERROR; +} + +// This displays a normal window. We ask the base window class for default +// sizes which unless overriden will return DEFWIDTH and DEFHEIGHT. We go +// through a couple of extra hoops to get the client area the right size +// as the object specifies which accounts for the AdjustWindowRectEx calls +// We also DWORD align the left and top coordinates of the window here to +// maximise the chance of being able to use DCI/DirectDraw primary surface + +HRESULT CBaseWindow::ActivateWindow() +{ + // Has the window been sized and positioned already + + if (m_bActivated == TRUE || GetParent(m_hwnd) != NULL) { + + SetWindowPos(m_hwnd, // Our window handle + HWND_TOP, // Put it at the top + 0, 0, 0, 0, // Leave in current position + SWP_NOMOVE | // Don't change it's place + SWP_NOSIZE); // Change Z-order only + + m_bActivated = TRUE; + return S_FALSE; + } + + // Calculate the desired client rectangle + + RECT WindowRect, ClientRect = GetDefaultRect(); + GetWindowRect(m_hwnd,&WindowRect); + AdjustWindowRectEx(&ClientRect,GetWindowLong(m_hwnd,GWL_STYLE), + FALSE,GetWindowLong(m_hwnd,GWL_EXSTYLE)); + + // Align left and top edges on DWORD boundaries + + UINT WindowFlags = (SWP_NOACTIVATE | SWP_FRAMECHANGED); + WindowRect.left -= (WindowRect.left & 3); + WindowRect.top -= (WindowRect.top & 3); + + SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Align left edge + WindowRect.top, // And also top place + WIDTH(&ClientRect), // Horizontal size + HEIGHT(&ClientRect), // Vertical size + WindowFlags); // Don't show window + + m_bActivated = TRUE; + return NOERROR; +} + + +// This can be used to DWORD align the window for maximum performance + +HRESULT CBaseWindow::PerformanceAlignWindow() +{ + RECT ClientRect,WindowRect; + GetWindowRect(m_hwnd,&WindowRect); + ASSERT(m_bActivated == TRUE); + + // Don't do this if we're owned + + if (GetParent(m_hwnd)) { + return NOERROR; + } + + // Align left and top edges on DWORD boundaries + + GetClientRect(m_hwnd, &ClientRect); + MapWindowPoints(m_hwnd, HWND_DESKTOP, (LPPOINT) &ClientRect, 2); + WindowRect.left -= (ClientRect.left & 3); + WindowRect.top -= (ClientRect.top & 3); + UINT WindowFlags = (SWP_NOACTIVATE | SWP_NOSIZE); + + SetWindowPos(m_hwnd, // Window handle + HWND_TOP, // Put it at the top + WindowRect.left, // Align left edge + WindowRect.top, // And also top place + (int) 0,(int) 0, // Ignore these sizes + WindowFlags); // Don't show window + + return NOERROR; +} + + +// Install a palette into the base window - we may be called by a different +// thread to the one that owns the window. We have to be careful how we do +// the palette realisation as we could be a different thread to the window +// which would cause an inter thread send message. Therefore we realise the +// palette by sending it a special message but without the window locked + +HRESULT CBaseWindow::SetPalette(HPALETTE hPalette) +{ + // We must own the window lock during the change + { + CAutoLock cWindowLock(&m_WindowLock); + CAutoLock cPaletteLock(&m_PaletteLock); + ASSERT(hPalette); + m_hPalette = hPalette; + } + return SetPalette(); +} + + +HRESULT CBaseWindow::SetPalette() +{ + if (!m_bNoRealize) { + SendMessage(m_hwnd, m_RealizePalette, 0, 0); + return S_OK; + } else { + // Just select the palette + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + + CAutoLock cPaletteLock(&m_PaletteLock); + SelectPalette(m_hdc,m_hPalette,m_bBackground); + SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); + + return S_OK; + } +} + + +void CBaseWindow::UnsetPalette() +{ + CAutoLock cWindowLock(&m_WindowLock); + CAutoLock cPaletteLock(&m_PaletteLock); + + // Get a standard VGA colour palette + + HPALETTE hPalette = (HPALETTE) GetStockObject(DEFAULT_PALETTE); + ASSERT(hPalette); + + SelectPalette(GetWindowHDC(), hPalette, TRUE); + SelectPalette(GetMemoryHDC(), hPalette, TRUE); + + m_hPalette = NULL; +} + + +void CBaseWindow::LockPaletteLock() +{ + m_PaletteLock.Lock(); +} + + +void CBaseWindow::UnlockPaletteLock() +{ + m_PaletteLock.Unlock(); +} + + +// Realise our palettes in the window and device contexts + +HRESULT CBaseWindow::DoRealisePalette(BOOL bForceBackground) +{ + { + CAutoLock cPaletteLock(&m_PaletteLock); + + if (m_hPalette == NULL) { + return NOERROR; + } + + // Realize the palette on the window thread + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + + SelectPalette(m_hdc,m_hPalette,m_bBackground || bForceBackground); + SelectPalette(m_MemoryDC,m_hPalette,m_bBackground); + } + + // If we grab a critical section here we can deadlock + // with the window thread because one of the side effects + // of RealizePalette is to send a WM_PALETTECHANGED message + // to every window in the system. In our handling + // of WM_PALETTECHANGED we used to grab this CS too. + // The really bad case is when our renderer calls DoRealisePalette() + // while we're in the middle of processing a palette change + // for another window. + // So don't hold the critical section while actually realising + // the palette. In any case USER is meant to manage palette + // handling - we shouldn't have to serialize everything as well + ASSERT(CritCheckOut(&m_WindowLock)); + ASSERT(CritCheckOut(&m_PaletteLock)); + + EXECUTE_ASSERT(RealizePalette(m_hdc) != GDI_ERROR); + EXECUTE_ASSERT(RealizePalette(m_MemoryDC) != GDI_ERROR); + + return (GdiFlush() == FALSE ? S_FALSE : S_OK); +} + + +// This is the global window procedure + +LRESULT CALLBACK WndProc(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam) // Other parameter +{ + + // Get the window long that holds our window object pointer + // If it is NULL then we are initialising the window in which + // case the object pointer has been passed in the window creation + // structure. IF we get any messages before WM_NCCREATE we will + // pass them to DefWindowProc. + + CBaseWindow *pBaseWindow = (CBaseWindow *)GetWindowLongPtr(hwnd,0); + + if (pBaseWindow == NULL) { + + // Get the structure pointer from the create struct. + // We can only do this for WM_NCCREATE which should be one of + // the first messages we receive. Anything before this will + // have to be passed to DefWindowProc (i.e. WM_GETMINMAXINFO) + + // If the message is WM_NCCREATE we set our pBaseWindow pointer + // and will then place it in the window structure + + // turn off WS_EX_LAYOUTRTL style for quartz windows + if (uMsg == WM_NCCREATE) { + SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~0x400000); + } + + if ((uMsg != WM_NCCREATE) + || (NULL == (pBaseWindow = *(CBaseWindow**) ((LPCREATESTRUCT)lParam)->lpCreateParams))) + { + return(DefWindowProc(hwnd, uMsg, wParam, lParam)); + } + + // Set the window LONG to be the object who created us +#ifdef _DEBUG + SetLastError(0); // because of the way SetWindowLong works +#endif + +#ifdef _DEBUG + LONG_PTR rc = +#endif + SetWindowLongPtr(hwnd, (DWORD) 0, (LONG_PTR)pBaseWindow); + + +#ifdef _DEBUG + if (0 == rc) { + // SetWindowLong MIGHT have failed. (Read the docs which admit + // that it is awkward to work out if you have had an error.) + LONG lasterror = GetLastError(); + ASSERT(0 == lasterror); + // If this is not the case we have not set the pBaseWindow pointer + // into the window structure and we will blow up. + } +#endif + + } + // See if this is the packet of death + if (uMsg == MsgDestroy && uMsg != 0) { + pBaseWindow->DoneWithWindow(); + if (pBaseWindow->m_bDoPostToDestroy) { + EXECUTE_ASSERT(SetEvent((HANDLE)wParam)); + } + return 0; + } + return pBaseWindow->OnReceiveMessage(hwnd,uMsg,wParam,lParam); +} + + +// When the window size changes we adjust our member variables that +// contain the dimensions of the client rectangle for our window so +// that we come to render an image we will know whether to stretch + +BOOL CBaseWindow::OnSize(LONG Width, LONG Height) +{ + m_Width = Width; + m_Height = Height; + return TRUE; +} + + +// This function handles the WM_CLOSE message + +BOOL CBaseWindow::OnClose() +{ + ShowWindow(m_hwnd,SW_HIDE); + return TRUE; +} + + +// This is called by the worker window thread when it receives a terminate +// message from the window object destructor to delete all the resources we +// allocated during initialisation. By the time the worker thread exits all +// processing will have been completed as the source filter disconnection +// flushes the image pending sample, therefore the GdiFlush should succeed + +HRESULT CBaseWindow::UninitialiseWindow() +{ + // Have we already cleaned up + + if (m_hwnd == NULL) { + ASSERT(m_hdc == NULL); + ASSERT(m_MemoryDC == NULL); + return NOERROR; + } + + // Release the window resources + + EXECUTE_ASSERT(GdiFlush()); + + if (m_hdc) + { + EXECUTE_ASSERT(ReleaseDC(m_hwnd,m_hdc)); + m_hdc = NULL; + } + + if (m_MemoryDC) + { + EXECUTE_ASSERT(DeleteDC(m_MemoryDC)); + m_MemoryDC = NULL; + } + + // Reset the window variables + m_hwnd = NULL; + + return NOERROR; +} + + +// This is called by the worker window thread after it has created the main +// window and it wants to initialise the rest of the owner objects window +// variables such as the device contexts. We execute this function with the +// critical section still locked. Nothing in this function must generate any +// SendMessage calls to the window because this is executing on the window +// thread so the message will never be processed and we will deadlock + +HRESULT CBaseWindow::InitialiseWindow(HWND hwnd) +{ + // Initialise the window variables + + ASSERT(IsWindow(hwnd)); + m_hwnd = hwnd; + + if (m_bDoGetDC) + { + m_hdc = GetDC(hwnd); + EXECUTE_ASSERT(m_hdc); + m_MemoryDC = CreateCompatibleDC(m_hdc); + EXECUTE_ASSERT(m_MemoryDC); + + EXECUTE_ASSERT(SetStretchBltMode(m_hdc,COLORONCOLOR)); + EXECUTE_ASSERT(SetStretchBltMode(m_MemoryDC,COLORONCOLOR)); + } + + return NOERROR; +} + +HRESULT CBaseWindow::DoCreateWindow() +{ + WNDCLASS wndclass; // Used to register classes + BOOL bRegistered; // Is this class registered + HWND hwnd; // Handle to our window + + bRegistered = GetClassInfo(m_hInstance, // Module instance + m_pClassName, // Window class + &wndclass); // Info structure + + // if the window is to be used for drawing puposes and we are getting a DC + // for the entire lifetime of the window then changes the class style to do + // say so. If we don't set this flag then the DC comes from the cache and is + // really bad. + if (m_bDoGetDC) + { + m_ClassStyles |= CS_OWNDC; + } + + if (bRegistered == FALSE) { + + // Register the renderer window class + + wndclass.lpszClassName = m_pClassName; + wndclass.style = m_ClassStyles; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = sizeof(CBaseWindow *); + wndclass.hInstance = m_hInstance; + wndclass.hIcon = NULL; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH) NULL; + wndclass.lpszMenuName = NULL; + + RegisterClass(&wndclass); + } + + // Create the frame window. Pass the pBaseWindow information in the + // CreateStruct which allows our message handling loop to get hold of + // the pBaseWindow pointer. + + CBaseWindow *pBaseWindow = this; // The owner window object + hwnd = CreateWindowEx(m_WindowStylesEx, // Extended styles + m_pClassName, // Registered name + TEXT("ActiveMovie Window"), // Window title + m_WindowStyles, // Window styles + CW_USEDEFAULT, // Start x position + CW_USEDEFAULT, // Start y position + DEFWIDTH, // Window width + DEFHEIGHT, // Window height + NULL, // Parent handle + NULL, // Menu handle + m_hInstance, // Instance handle + &pBaseWindow); // Creation data + + // If we failed signal an error to the object constructor (based on the + // last Win32 error on this thread) then signal the constructor thread + // to continue, release the mutex to let others have a go and exit + + if (hwnd == NULL) { + DWORD Error = GetLastError(); + return AmHresultFromWin32(Error); + } + + // Check the window LONG is the object who created us + ASSERT(GetWindowLongPtr(hwnd, 0) == (LONG_PTR)this); + + // Initialise the window and then signal the constructor so that it can + // continue and then finally unlock the object's critical section. The + // window class is left registered even after we terminate the thread + // as we don't know when the last window has been closed. So we allow + // the operating system to free the class resources as appropriate + + InitialiseWindow(hwnd); + + DbgLog((LOG_TRACE, 2, TEXT("Created window class (%s) HWND(%8.8X)"), + m_pClassName, hwnd)); + + return S_OK; +} + + +// The base class provides some default handling and calls DefWindowProc + +INT_PTR CBaseWindow::OnReceiveMessage(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam) // Other parameter +{ + ASSERT(IsWindow(hwnd)); + + if (PossiblyEatMessage(uMsg, wParam, lParam)) + return 0; + + // This is sent by the IVideoWindow SetWindowForeground method. If the + // window is invisible we will show it and make it topmost without the + // foreground focus. If the window is visible it will also be made the + // topmost window without the foreground focus. If wParam is TRUE then + // for both cases the window will be forced into the foreground focus + + if (uMsg == m_ShowStageMessage) { + + BOOL bVisible = IsWindowVisible(hwnd); + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | + (bVisible ? SWP_NOACTIVATE : 0)); + + // Should we bring the window to the foreground + if (wParam == TRUE) { + SetForegroundWindow(hwnd); + } + return (LRESULT) 1; + } + + // When we go fullscreen we have to add the WS_EX_TOPMOST style to the + // video window so that it comes out above any task bar (this is more + // relevant to WindowsNT than Windows95). However the SetWindowPos call + // must be on the same thread as that which created the window. The + // wParam parameter can be TRUE or FALSE to set and reset the topmost + + if (uMsg == m_ShowStageTop) { + HWND HwndTop = (wParam == TRUE ? HWND_TOPMOST : HWND_NOTOPMOST); + BOOL bVisible = IsWindowVisible(hwnd); + SetWindowPos(hwnd, HwndTop, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | + (wParam == TRUE ? SWP_SHOWWINDOW : 0) | + (bVisible ? SWP_NOACTIVATE : 0)); + return (LRESULT) 1; + } + + // New palette stuff + if (uMsg == m_RealizePalette) { + ASSERT(m_hwnd == hwnd); + return OnPaletteChange(m_hwnd,WM_QUERYNEWPALETTE); + } + + switch (uMsg) { + + // Repaint the window if the system colours change + + case WM_SYSCOLORCHANGE: + + InvalidateRect(hwnd,NULL,FALSE); + return (LRESULT) 1; + + // Somebody has changed the palette + case WM_PALETTECHANGED: + + OnPaletteChange((HWND)wParam,uMsg); + return (LRESULT) 0; + + // We are about to receive the keyboard focus so we ask GDI to realise + // our logical palette again and hopefully it will be fully installed + // without any mapping having to be done during any picture rendering + + case WM_QUERYNEWPALETTE: + ASSERT(m_hwnd == hwnd); + return OnPaletteChange(m_hwnd,uMsg); + + // do NOT fwd WM_MOVE. the parameters are the location of the parent + // window, NOT what the renderer should be looking at. But we need + // to make sure the overlay is moved with the parent window, so we + // do this. + case WM_MOVE: + if (IsWindowVisible(m_hwnd)) { + PostMessage(m_hwnd,WM_PAINT,0,0); + } + break; + + // Store the width and height as useful base class members + + case WM_SIZE: + + OnSize(LOWORD(lParam), HIWORD(lParam)); + return (LRESULT) 0; + + // Intercept the WM_CLOSE messages to hide the window + + case WM_CLOSE: + + OnClose(); + return (LRESULT) 0; + } + return DefWindowProc(hwnd,uMsg,wParam,lParam); +} + + +// This handles the Windows palette change messages - if we do realise our +// palette then we return TRUE otherwise we return FALSE. If our window is +// foreground application then we should get first choice of colours in the +// system palette entries. We get best performance when our logical palette +// includes the standard VGA colours (at the beginning and end) otherwise +// GDI may have to map from our palette to the device palette while drawing + +LRESULT CBaseWindow::OnPaletteChange(HWND hwnd,UINT Message) +{ + // First check we are not changing the palette during closedown + + if (m_hwnd == NULL || hwnd == NULL) { + return (LRESULT) 0; + } + ASSERT(!m_bRealizing); + + // Should we realise our palette again + + if ((Message == WM_QUERYNEWPALETTE || hwnd != m_hwnd)) { + // It seems that even if we're invisible that we can get asked + // to realize our palette and this can cause really ugly side-effects + // Seems like there's another bug but this masks it a least for the + // shutting down case. + if (!IsWindowVisible(m_hwnd)) { + DbgLog((LOG_TRACE, 1, TEXT("Realizing when invisible!"))); + return (LRESULT) 0; + } + + // Avoid recursion with multiple graphs in the same app +#ifdef _DEBUG + m_bRealizing = TRUE; +#endif + DoRealisePalette(Message != WM_QUERYNEWPALETTE); +#ifdef _DEBUG + m_bRealizing = FALSE; +#endif + + // Should we redraw the window with the new palette + if (Message == WM_PALETTECHANGED) { + InvalidateRect(m_hwnd,NULL,FALSE); + } + } + + return (LRESULT) 1; +} + + +// Determine if the window exists. + +bool CBaseWindow::WindowExists() +{ + return !!IsWindow(m_hwnd); +} + + +// Return the default window rectangle + +RECT CBaseWindow::GetDefaultRect() +{ + RECT DefaultRect = {0,0,DEFWIDTH,DEFHEIGHT}; + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return DefaultRect; +} + + +// Return the current window width + +LONG CBaseWindow::GetWindowWidth() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_Width; +} + + +// Return the current window height + +LONG CBaseWindow::GetWindowHeight() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_Height; +} + + +// Return the window handle + +HWND CBaseWindow::GetWindowHWND() +{ + ASSERT(m_hwnd); + // ASSERT(m_hdc); + return m_hwnd; +} + + +// Return the window drawing device context + +HDC CBaseWindow::GetWindowHDC() +{ + ASSERT(m_hwnd); + ASSERT(m_hdc); + return m_hdc; +} + + +// Return the offscreen window drawing device context + +HDC CBaseWindow::GetMemoryHDC() +{ + ASSERT(m_hwnd); + ASSERT(m_MemoryDC); + return m_MemoryDC; +} + + +#ifdef _DEBUG +HPALETTE CBaseWindow::GetPalette() +{ + // The palette lock should always be held when accessing + // m_hPalette. + ASSERT(CritCheckIn(&m_PaletteLock)); + return m_hPalette; +} +#endif // DEBUG + + +// This is available to clients who want to change the window visiblity. It's +// little more than an indirection to the Win32 ShowWindow although these is +// some benefit in going through here as this function may change sometime + +HRESULT CBaseWindow::DoShowWindow(LONG ShowCmd) +{ + ShowWindow(m_hwnd,ShowCmd); + return NOERROR; +} + + +// Generate a WM_PAINT message for the video window + +void CBaseWindow::PaintWindow(BOOL bErase) +{ + InvalidateRect(m_hwnd,NULL,bErase); +} + + +// Allow an application to have us set the video window in the foreground. We +// have this because it is difficult for one thread to do do this to a window +// owned by another thread. Rather than expose the message we use to execute +// the inter thread send message we provide the interface function. All we do +// is to SendMessage to the video window renderer thread with a WM_SHOWSTAGE + +void CBaseWindow::DoSetWindowForeground(BOOL bFocus) +{ + SendMessage(m_hwnd,m_ShowStageMessage,(WPARAM) bFocus,(LPARAM) 0); +} + + +// Constructor initialises the owning object pointer. Since we are a worker +// class for the main window object we have relatively few state variables to +// look after. We are given device context handles to use later on as well as +// the source and destination rectangles (but reset them here just in case) + +CDrawImage::CDrawImage(__inout CBaseWindow *pBaseWindow) : + m_pBaseWindow(pBaseWindow), + m_hdc(NULL), + m_MemoryDC(NULL), + m_bStretch(FALSE), + m_pMediaType(NULL), + m_bUsingImageAllocator(FALSE) +{ + ASSERT(pBaseWindow); + ResetPaletteVersion(); + SetRectEmpty(&m_TargetRect); + SetRectEmpty(&m_SourceRect); + + m_perfidRenderTime = MSR_REGISTER(TEXT("Single Blt time")); +} + + +// Overlay the image time stamps on the picture. Access to this method is +// serialised by the caller. We display the sample start and end times on +// top of the video using TextOut on the device context we are handed. If +// there isn't enough room in the window for the times we don't show them + +void CDrawImage::DisplaySampleTimes(IMediaSample *pSample) +{ +#ifdef _DEBUG + // + // Only allow the "annoying" time messages if the users has turned the + // logging "way up" + // + BOOL bAccept = DbgCheckModuleLevel(LOG_TRACE, 5); + if (bAccept == FALSE) { + return; + } +#endif + + TCHAR szTimes[TIMELENGTH]; // Time stamp strings + ASSERT(pSample); // Quick sanity check + RECT ClientRect; // Client window size + SIZE Size; // Size of text output + + // Get the time stamps and window size + + pSample->GetTime((REFERENCE_TIME*)&m_StartSample, (REFERENCE_TIME*)&m_EndSample); + HWND hwnd = m_pBaseWindow->GetWindowHWND(); + EXECUTE_ASSERT(GetClientRect(hwnd,&ClientRect)); + + // Format the sample time stamps + + (void)StringCchPrintf(szTimes,NUMELMS(szTimes),TEXT("%08d : %08d"), + m_StartSample.Millisecs(), + m_EndSample.Millisecs()); + + ASSERT(lstrlen(szTimes) < TIMELENGTH); + + // Put the times in the middle at the bottom of the window + + GetTextExtentPoint32(m_hdc,szTimes,lstrlen(szTimes),&Size); + INT XPos = ((ClientRect.right - ClientRect.left) - Size.cx) / 2; + INT YPos = ((ClientRect.bottom - ClientRect.top) - Size.cy) * 4 / 5; + + // Check the window is big enough to have sample times displayed + + if ((XPos > 0) && (YPos > 0)) { + TextOut(m_hdc,XPos,YPos,szTimes,lstrlen(szTimes)); + } +} + + +// This is called when the drawing code sees that the image has a down level +// palette cookie. We simply call the SetDIBColorTable Windows API with the +// palette that is found after the BITMAPINFOHEADER - we return no errors + +void CDrawImage::UpdateColourTable(HDC hdc,__in BITMAPINFOHEADER *pbmi) +{ + ASSERT(pbmi->biClrUsed); + RGBQUAD *pColourTable = (RGBQUAD *)(pbmi+1); + + // Set the new palette in the device context + + UINT uiReturn = SetDIBColorTable(hdc,(UINT) 0, + pbmi->biClrUsed, + pColourTable); + + // Should always succeed but check in debug builds + ASSERT(uiReturn == pbmi->biClrUsed); + UNREFERENCED_PARAMETER(uiReturn); +} + + +// No source rectangle scaling is done by the base class + +RECT CDrawImage::ScaleSourceRect(const RECT *pSource) +{ + ASSERT(pSource); + return *pSource; +} + + +// This is called when the funky output pin uses our allocator. The samples we +// allocate are special because the memory is shared between us and GDI thus +// removing one copy when we ask for the image to be rendered. The source type +// information is in the main renderer m_mtIn field which is initialised when +// the media type is agreed in SetMediaType, the media type may be changed on +// the fly if, for example, the source filter needs to change the palette + +void CDrawImage::FastRender(IMediaSample *pMediaSample) +{ + BITMAPINFOHEADER *pbmi; // Image format data + DIBDATA *pDibData; // Stores DIB information + BYTE *pImage; // Pointer to image data + HBITMAP hOldBitmap; // Store the old bitmap + CImageSample *pSample; // Pointer to C++ object + + ASSERT(m_pMediaType); + + // From the untyped source format block get the VIDEOINFO and subsequently + // the BITMAPINFOHEADER structure. We can cast the IMediaSample interface + // to a CImageSample object so we can retrieve it's DIBSECTION details + + pbmi = HEADER(m_pMediaType->Format()); + pSample = (CImageSample *) pMediaSample; + pDibData = pSample->GetDIBData(); + hOldBitmap = (HBITMAP) SelectObject(m_MemoryDC,pDibData->hBitmap); + + // Get a pointer to the real image data + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return; + } + + // Do we need to update the colour table, we increment our palette cookie + // each time we get a dynamic format change. The sample palette cookie is + // stored in the DIBDATA structure so we try to keep the fields in sync + // By the time we get to draw the images the format change will be done + // so all we do is ask the renderer for what it's palette version is + + if (pDibData->PaletteVersion < GetPaletteVersion()) { + ASSERT(pbmi->biBitCount <= iPALETTE); + UpdateColourTable(m_MemoryDC,pbmi); + pDibData->PaletteVersion = GetPaletteVersion(); + } + + // This allows derived classes to change the source rectangle that we do + // the drawing with. For example a renderer may ask a codec to stretch + // the video from 320x240 to 640x480, in which case the source we see in + // here will still be 320x240, although the source we want to draw with + // should be scaled up to 640x480. The base class implementation of this + // method does nothing but return the same rectangle as we are passed in + + RECT SourceRect = ScaleSourceRect(&m_SourceRect); + + // Is the window the same size as the video + + if (m_bStretch == FALSE) { + + // Put the image straight into the window + + BitBlt( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + m_MemoryDC, // Source device context + SourceRect.left, // X source position + SourceRect.top, // Y source position + SRCCOPY); // Simple copy + + } else { + + // Stretch the image when copying to the window + + StretchBlt( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + m_MemoryDC, // Source device HDC + SourceRect.left, // X source position + SourceRect.top, // Y source position + SourceRect.right - SourceRect.left, // Source width + SourceRect.bottom - SourceRect.top, // Source height + SRCCOPY); // Simple copy + } + + // This displays the sample times over the top of the image. This used to + // draw the times into the offscreen device context however that actually + // writes the text into the image data buffer which may not be writable + + #ifdef _DEBUG + DisplaySampleTimes(pMediaSample); + #endif + + // Put the old bitmap back into the device context so we don't leak + SelectObject(m_MemoryDC,hOldBitmap); +} + + +// This is called when there is a sample ready to be drawn, unfortunately the +// output pin was being rotten and didn't choose our super excellent shared +// memory DIB allocator so we have to do this slow render using boring old GDI +// SetDIBitsToDevice and StretchDIBits. The down side of using these GDI +// functions is that the image data has to be copied across from our address +// space into theirs before going to the screen (although in reality the cost +// is small because all they do is to map the buffer into their address space) + +void CDrawImage::SlowRender(IMediaSample *pMediaSample) +{ + // Get the BITMAPINFOHEADER for the connection + + ASSERT(m_pMediaType); + BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); + BYTE *pImage; + + // Get the image data buffer + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return; + } + + // This allows derived classes to change the source rectangle that we do + // the drawing with. For example a renderer may ask a codec to stretch + // the video from 320x240 to 640x480, in which case the source we see in + // here will still be 320x240, although the source we want to draw with + // should be scaled up to 640x480. The base class implementation of this + // method does nothing but return the same rectangle as we are passed in + + RECT SourceRect = ScaleSourceRect(&m_SourceRect); + + LONG lAdjustedSourceTop = SourceRect.top; + // if the origin of bitmap is bottom-left, adjust soruce_rect_top + // to be the bottom-left corner instead of the top-left. + if (pbmi->biHeight > 0) { + lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; + } + // Is the window the same size as the video + + if (m_bStretch == FALSE) { + + // Put the image straight into the window + + SetDIBitsToDevice( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + SourceRect.left, // X source position + lAdjustedSourceTop, // Adjusted Y source position + (UINT) 0, // Start scan line + pbmi->biHeight, // Scan lines present + pImage, // Image data + (BITMAPINFO *) pbmi, // DIB header + DIB_RGB_COLORS); // Type of palette + + } else { + + // Stretch the image when copying to the window + + StretchDIBits( + (HDC) m_hdc, // Target device HDC + m_TargetRect.left, // X sink position + m_TargetRect.top, // Y sink position + m_TargetRect.right - m_TargetRect.left, // Destination width + m_TargetRect.bottom - m_TargetRect.top, // Destination height + SourceRect.left, // X source position + lAdjustedSourceTop, // Adjusted Y source position + SourceRect.right - SourceRect.left, // Source width + SourceRect.bottom - SourceRect.top, // Source height + pImage, // Image data + (BITMAPINFO *) pbmi, // DIB header + DIB_RGB_COLORS, // Type of palette + SRCCOPY); // Simple image copy + } + + // This shows the sample reference times over the top of the image which + // looks a little flickery. I tried using GdiSetBatchLimit and GdiFlush to + // control the screen updates but it doesn't quite work as expected and + // only partially reduces the flicker. I also tried using a memory context + // and combining the two in that before doing a final BitBlt operation to + // the screen, unfortunately this has considerable performance penalties + // and also means that this code is not executed when compiled retail + + #ifdef _DEBUG + DisplaySampleTimes(pMediaSample); + #endif +} + + +// This is called with an IMediaSample interface on the image to be drawn. We +// decide on the drawing mechanism based on who's allocator we are using. We +// may be called when the window wants an image painted by WM_PAINT messages +// We can't realise the palette here because we have the renderer lock, any +// call to realise may cause an interthread send message to the window thread +// which may in turn be waiting to get the renderer lock before servicing it + +BOOL CDrawImage::DrawImage(IMediaSample *pMediaSample) +{ + ASSERT(m_hdc); + ASSERT(m_MemoryDC); + NotifyStartDraw(); + + // If the output pin used our allocator then the samples passed are in + // fact CVideoSample objects that contain CreateDIBSection data that we + // use to do faster image rendering, they may optionally also contain a + // DirectDraw surface pointer in which case we do not do the drawing + + if (m_bUsingImageAllocator == FALSE) { + SlowRender(pMediaSample); + EXECUTE_ASSERT(GdiFlush()); + NotifyEndDraw(); + return TRUE; + } + + // This is a DIBSECTION buffer + + FastRender(pMediaSample); + EXECUTE_ASSERT(GdiFlush()); + NotifyEndDraw(); + return TRUE; +} + + +BOOL CDrawImage::DrawVideoImageHere( + HDC hdc, + IMediaSample *pMediaSample, + __in LPRECT lprcSrc, + __in LPRECT lprcDst + ) +{ + ASSERT(m_pMediaType); + BITMAPINFOHEADER *pbmi = HEADER(m_pMediaType->Format()); + BYTE *pImage; + + // Get the image data buffer + + HRESULT hr = pMediaSample->GetPointer(&pImage); + if (FAILED(hr)) { + return FALSE; + } + + RECT SourceRect; + RECT TargetRect; + + if (lprcSrc) { + SourceRect = *lprcSrc; + } + else SourceRect = ScaleSourceRect(&m_SourceRect); + + if (lprcDst) { + TargetRect = *lprcDst; + } + else TargetRect = m_TargetRect; + + LONG lAdjustedSourceTop = SourceRect.top; + // if the origin of bitmap is bottom-left, adjust soruce_rect_top + // to be the bottom-left corner instead of the top-left. + if (pbmi->biHeight > 0) { + lAdjustedSourceTop = pbmi->biHeight - SourceRect.bottom; + } + + + // Stretch the image when copying to the DC + + BOOL bRet = (0 != StretchDIBits(hdc, + TargetRect.left, + TargetRect.top, + TargetRect.right - TargetRect.left, + TargetRect.bottom - TargetRect.top, + SourceRect.left, + lAdjustedSourceTop, + SourceRect.right - SourceRect.left, + SourceRect.bottom - SourceRect.top, + pImage, + (BITMAPINFO *)pbmi, + DIB_RGB_COLORS, + SRCCOPY)); + return bRet; +} + + +// This is called by the owning window object after it has created the window +// and it's drawing contexts. We are constructed with the base window we'll +// be drawing into so when given the notification we retrive the device HDCs +// to draw with. We cannot call these in our constructor as they are virtual + +void CDrawImage::SetDrawContext() +{ + m_MemoryDC = m_pBaseWindow->GetMemoryHDC(); + m_hdc = m_pBaseWindow->GetWindowHDC(); +} + + +// This is called to set the target rectangle in the video window, it will be +// called whenever a WM_SIZE message is retrieved from the message queue. We +// simply store the rectangle and use it later when we do the drawing calls + +void CDrawImage::SetTargetRect(__in RECT *pTargetRect) +{ + ASSERT(pTargetRect); + m_TargetRect = *pTargetRect; + SetStretchMode(); +} + + +// Return the current target rectangle + +void CDrawImage::GetTargetRect(__out RECT *pTargetRect) +{ + ASSERT(pTargetRect); + *pTargetRect = m_TargetRect; +} + + +// This is called when we want to change the section of the image to draw. We +// use this information in the drawing operation calls later on. We must also +// see if the source and destination rectangles have the same dimensions. If +// not we must stretch during the drawing rather than a direct pixel copy + +void CDrawImage::SetSourceRect(__in RECT *pSourceRect) +{ + ASSERT(pSourceRect); + m_SourceRect = *pSourceRect; + SetStretchMode(); +} + + +// Return the current source rectangle + +void CDrawImage::GetSourceRect(__out RECT *pSourceRect) +{ + ASSERT(pSourceRect); + *pSourceRect = m_SourceRect; +} + + +// This is called when either the source or destination rectanges change so we +// can update the stretch flag. If the rectangles don't match we stretch the +// video during the drawing otherwise we call the fast pixel copy functions +// NOTE the source and/or the destination rectangle may be completely empty + +void CDrawImage::SetStretchMode() +{ + // Calculate the overall rectangle dimensions + + LONG SourceWidth = m_SourceRect.right - m_SourceRect.left; + LONG SinkWidth = m_TargetRect.right - m_TargetRect.left; + LONG SourceHeight = m_SourceRect.bottom - m_SourceRect.top; + LONG SinkHeight = m_TargetRect.bottom - m_TargetRect.top; + + m_bStretch = TRUE; + if (SourceWidth == SinkWidth) { + if (SourceHeight == SinkHeight) { + m_bStretch = FALSE; + } + } +} + + +// Tell us whose allocator we are using. This should be called with TRUE if +// the filter agrees to use an allocator based around the CImageAllocator +// SDK base class - whose image buffers are made through CreateDIBSection. +// Otherwise this should be called with FALSE and we will draw the images +// using SetDIBitsToDevice and StretchDIBitsToDevice. None of these calls +// can handle buffers which have non zero strides (like DirectDraw uses) + +void CDrawImage::NotifyAllocator(BOOL bUsingImageAllocator) +{ + m_bUsingImageAllocator = bUsingImageAllocator; +} + + +// Are we using the image DIBSECTION allocator + +BOOL CDrawImage::UsingImageAllocator() +{ + return m_bUsingImageAllocator; +} + + +// We need the media type of the connection so that we can get the BITMAPINFO +// from it. We use that in the calls to draw the image such as StretchDIBits +// and also when updating the colour table held in shared memory DIBSECTIONs + +void CDrawImage::NotifyMediaType(__in CMediaType *pMediaType) +{ + m_pMediaType = pMediaType; +} + + +// We store in this object a cookie maintaining the current palette version. +// Each time a palettised format is changed we increment this value so that +// when we come to draw the images we look at the colour table value they +// have and if less than the current we know to update it. This version is +// only needed and indeed used when working with shared memory DIBSECTIONs + +LONG CDrawImage::GetPaletteVersion() +{ + return m_PaletteVersion; +} + + +// Resets the current palette version number + +void CDrawImage::ResetPaletteVersion() +{ + m_PaletteVersion = PALETTE_VERSION; +} + + +// Increment the current palette version + +void CDrawImage::IncrementPaletteVersion() +{ + m_PaletteVersion++; +} + + +// Constructor must initialise the base allocator. Each sample we create has a +// palette version cookie on board. When the source filter changes the palette +// during streaming the window object increments an internal cookie counter it +// keeps as well. When it comes to render the samples it looks at the cookie +// values and if they don't match then it knows to update the sample's colour +// table. However we always create samples with a cookie of PALETTE_VERSION +// If there have been multiple format changes and we disconnect and reconnect +// thereby causing the samples to be reallocated we will create them with a +// cookie much lower than the current version, this isn't a problem since it +// will be seen by the window object and the versions will then be updated + +CImageAllocator::CImageAllocator(__inout CBaseFilter *pFilter, + __in_opt LPCTSTR pName, + __inout HRESULT *phr) : + CBaseAllocator(pName,NULL,phr,TRUE,TRUE), + m_pFilter(pFilter), + m_pMediaType(NULL) +{ + ASSERT(phr); + ASSERT(pFilter); +} + + +// Check our DIB buffers have been released + +#ifdef _DEBUG +CImageAllocator::~CImageAllocator() +{ + ASSERT(m_bCommitted == FALSE); +} +#endif + + +// Called from destructor and also from base class to free resources. We work +// our way through the list of media samples deleting the DIBSECTION created +// for each. All samples should be back in our list so there is no chance a +// filter is still using one to write on the display or hold on a pending list + +void CImageAllocator::Free() +{ + ASSERT(m_lAllocated == m_lFree.GetCount()); + EXECUTE_ASSERT(GdiFlush()); + CImageSample *pSample; + DIBDATA *pDibData; + + while (m_lFree.GetCount() != 0) { + pSample = (CImageSample *) m_lFree.RemoveHead(); + pDibData = pSample->GetDIBData(); + EXECUTE_ASSERT(DeleteObject(pDibData->hBitmap)); + EXECUTE_ASSERT(CloseHandle(pDibData->hMapping)); + delete pSample; + } + + m_lAllocated = 0; +} + + +// Prepare the allocator by checking all the input parameters + +STDMETHODIMP CImageAllocator::CheckSizes(__in ALLOCATOR_PROPERTIES *pRequest) +{ + // Check we have a valid connection + + if (m_pMediaType == NULL) { + return VFW_E_NOT_CONNECTED; + } + + // NOTE We always create a DIB section with the source format type which + // may contain a source palette. When we do the BitBlt drawing operation + // the target display device may contain a different palette (we may not + // have the focus) in which case GDI will do after the palette mapping + + VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *) m_pMediaType->Format(); + + // When we call CreateDIBSection it implicitly maps only enough memory + // for the image as defined by thee BITMAPINFOHEADER. If the user asks + // for an image smaller than this then we reject the call, if they ask + // for an image larger than this then we return what they can have + + if ((DWORD) pRequest->cbBuffer < pVideoInfo->bmiHeader.biSizeImage) { + return E_INVALIDARG; + } + + // Reject buffer prefixes + + if (pRequest->cbPrefix > 0) { + return E_INVALIDARG; + } + + pRequest->cbBuffer = pVideoInfo->bmiHeader.biSizeImage; + return NOERROR; +} + + +// Agree the number of media sample buffers and their sizes. The base class +// this allocator is derived from allows samples to be aligned only on byte +// boundaries NOTE the buffers are not allocated until the Commit call + +STDMETHODIMP CImageAllocator::SetProperties( + __in ALLOCATOR_PROPERTIES * pRequest, + __out ALLOCATOR_PROPERTIES * pActual) +{ + ALLOCATOR_PROPERTIES Adjusted = *pRequest; + + // Check the parameters fit with the current connection + + HRESULT hr = CheckSizes(&Adjusted); + if (FAILED(hr)) { + return hr; + } + return CBaseAllocator::SetProperties(&Adjusted, pActual); +} + + +// Commit the memory by allocating the agreed number of media samples. For +// each sample we are committed to creating we have a CImageSample object +// that we use to manage it's resources. This is initialised with a DIBDATA +// structure that contains amongst other things the GDI DIBSECTION handle +// We will access the renderer media type during this so we must have locked +// (to prevent the format changing for example). The class overrides Commit +// and Decommit to do this locking (base class Commit in turn calls Alloc) + +HRESULT CImageAllocator::Alloc(void) +{ + ASSERT(m_pMediaType); + CImageSample *pSample; + DIBDATA DibData; + + // Check the base allocator says it's ok to continue + + HRESULT hr = CBaseAllocator::Alloc(); + if (FAILED(hr)) { + return hr; + } + + // We create a new memory mapped object although we don't map it into our + // address space because GDI does that in CreateDIBSection. It is possible + // that we run out of resources before creating all the samples in which + // case the available sample list is left with those already created + + ASSERT(m_lAllocated == 0); + while (m_lAllocated < m_lCount) { + + // Create and initialise a shared memory GDI buffer + + hr = CreateDIB(m_lSize,DibData); + if (FAILED(hr)) { + return hr; + } + + // Create the sample object and pass it the DIBDATA + + pSample = CreateImageSample(DibData.pBase,m_lSize); + if (pSample == NULL) { + EXECUTE_ASSERT(DeleteObject(DibData.hBitmap)); + EXECUTE_ASSERT(CloseHandle(DibData.hMapping)); + return E_OUTOFMEMORY; + } + + // Add the completed sample to the available list + + pSample->SetDIBData(&DibData); + m_lFree.Add(pSample); + m_lAllocated++; + } + return NOERROR; +} + + +// We have a virtual method that allocates the samples so that a derived class +// may override it and allocate more specialised sample objects. So long as it +// derives its samples from CImageSample then all this code will still work ok + +CImageSample *CImageAllocator::CreateImageSample(__in_bcount(Length) LPBYTE pData,LONG Length) +{ + HRESULT hr = NOERROR; + CImageSample *pSample; + + // Allocate the new sample and check the return codes + + pSample = new CImageSample((CBaseAllocator *) this, // Base class + NAME("Video sample"), // DEBUG name + (HRESULT *) &hr, // Return code + (LPBYTE) pData, // DIB address + (LONG) Length); // Size of DIB + + if (pSample == NULL || FAILED(hr)) { + delete pSample; + return NULL; + } + return pSample; +} + + +// This function allocates a shared memory block for use by the source filter +// generating DIBs for us to render. The memory block is created in shared +// memory so that GDI doesn't have to copy the memory when we do a BitBlt + +HRESULT CImageAllocator::CreateDIB(LONG InSize,DIBDATA &DibData) +{ + BITMAPINFO *pbmi = NULL; // Format information for pin + BYTE *pBase = NULL; // Pointer to the actual image + HANDLE hMapping; // Handle to mapped object + HBITMAP hBitmap = NULL; // DIB section bitmap handle + + // Create a file mapping object and map into our address space + + hMapping = CreateFileMapping(hMEMORY, // Use system page file + NULL, // No security attributes + PAGE_READWRITE, // Full access to memory + (DWORD) 0, // Less than 4Gb in size + InSize, // Size of buffer + NULL); // No name to section + if (hMapping == NULL) { + DWORD Error = GetLastError(); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); + } + + // NOTE We always create a DIB section with the source format type which + // may contain a source palette. When we do the BitBlt drawing operation + // the target display device may contain a different palette (we may not + // have the focus) in which case GDI will do after the palette mapping + + if (m_pMediaType) { + pbmi = (BITMAPINFO *)HEADER(m_pMediaType->Format()); + hBitmap = CreateDIBSection((HDC)NULL, // NO device context + pbmi, // Format information + DIB_RGB_COLORS, // Use the palette + (VOID **)&pBase, // Pointer to image data + hMapping, // Mapped memory handle + (DWORD)0); // Offset into memory + } else { + DbgBreak("Invalid media type"); + } + + if (hBitmap == NULL || pBase == NULL) { + EXECUTE_ASSERT(CloseHandle(hMapping)); + DWORD Error = GetLastError(); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, Error); + } + + // Initialise the DIB information structure + + DibData.hBitmap = hBitmap; + DibData.hMapping = hMapping; + DibData.pBase = pBase; + DibData.PaletteVersion = PALETTE_VERSION; + GetObject(hBitmap,sizeof(DIBSECTION),(VOID *)&DibData.DibSection); + + return NOERROR; +} + + +// We use the media type during the DIBSECTION creation + +void CImageAllocator::NotifyMediaType(__in CMediaType *pMediaType) +{ + m_pMediaType = pMediaType; +} + + +// Overriden to increment the owning object's reference count + +STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingAddRef() +{ + return m_pFilter->AddRef(); +} + + +// Overriden to decrement the owning object's reference count + +STDMETHODIMP_(ULONG) CImageAllocator::NonDelegatingRelease() +{ + return m_pFilter->Release(); +} + + +// If you derive a class from CMediaSample that has to transport specialised +// member variables and entry points then there are three alternate solutions +// The first is to create a memory buffer larger than actually required by the +// sample and store your information either at the beginning of it or at the +// end, the former being moderately safer allowing for misbehaving transform +// filters. You then adjust the buffer address when you create the base media +// sample. This has the disadvantage of breaking up the memory allocated to +// the samples into separate blocks. The second solution is to implement a +// class derived from CMediaSample and support additional interface(s) that +// convey your private data. This means defining a custom interface. The final +// alternative is to create a class that inherits from CMediaSample and adds +// the private data structures, when you get an IMediaSample in your Receive() +// call check to see if your allocator is being used, and if it is then cast +// the IMediaSample into one of your objects. Additional checks can be made +// to ensure the sample's this pointer is known to be one of your own objects + +CImageSample::CImageSample(__inout CBaseAllocator *pAllocator, + __in_opt LPCTSTR pName, + __inout HRESULT *phr, + __in_bcount(length) LPBYTE pBuffer, + LONG length) : + CMediaSample(pName,pAllocator,phr,pBuffer,length), + m_bInit(FALSE) +{ + ZeroMemory(&m_DibData, sizeof(DIBDATA)); + ASSERT(pAllocator); + ASSERT(pBuffer); +} + + +// Set the shared memory DIB information + +void CImageSample::SetDIBData(__in DIBDATA *pDibData) +{ + ASSERT(pDibData); + m_DibData = *pDibData; + m_bInit = TRUE; +} + + +// Retrieve the shared memory DIB data + +__out DIBDATA *CImageSample::GetDIBData() +{ + ASSERT(m_bInit == TRUE); + return &m_DibData; +} + + +// This class handles the creation of a palette. It is fairly specialist and +// is intended to simplify palette management for video renderer filters. It +// is for this reason that the constructor requires three other objects with +// which it interacts, namely a base media filter, a base window and a base +// drawing object although the base window or the draw object may be NULL to +// ignore that part of us. We try not to create and install palettes unless +// absolutely necessary as they typically require WM_PALETTECHANGED messages +// to be sent to every window thread in the system which is very expensive + +CImagePalette::CImagePalette(__inout CBaseFilter *pBaseFilter, + __inout CBaseWindow *pBaseWindow, + __inout CDrawImage *pDrawImage) : + m_pBaseWindow(pBaseWindow), + m_pFilter(pBaseFilter), + m_pDrawImage(pDrawImage), + m_hPalette(NULL) +{ + ASSERT(m_pFilter); +} + + +// Destructor + +#ifdef _DEBUG +CImagePalette::~CImagePalette() +{ + ASSERT(m_hPalette == NULL); +} +#endif + + +// We allow dynamic format changes of the palette but rather than change the +// palette every time we call this to work out whether an update is required. +// If the original type didn't use a palette and the new one does (or vica +// versa) then we return TRUE. If neither formats use a palette we'll return +// FALSE. If both formats use a palette we compare their colours and return +// FALSE if they match. This therefore short circuits palette creation unless +// absolutely necessary since installing palettes is an expensive operation + +BOOL CImagePalette::ShouldUpdate(const VIDEOINFOHEADER *pNewInfo, + const VIDEOINFOHEADER *pOldInfo) +{ + // We may not have a current format yet + + if (pOldInfo == NULL) { + return TRUE; + } + + // Do both formats not require a palette + + if (ContainsPalette(pNewInfo) == FALSE) { + if (ContainsPalette(pOldInfo) == FALSE) { + return FALSE; + } + } + + // Compare the colours to see if they match + + DWORD VideoEntries = pNewInfo->bmiHeader.biClrUsed; + if (ContainsPalette(pNewInfo) == TRUE) + if (ContainsPalette(pOldInfo) == TRUE) + if (pOldInfo->bmiHeader.biClrUsed == VideoEntries) + if (pOldInfo->bmiHeader.biClrUsed > 0) + if (memcmp((PVOID) GetBitmapPalette(pNewInfo), + (PVOID) GetBitmapPalette(pOldInfo), + VideoEntries * sizeof(RGBQUAD)) == 0) { + + return FALSE; + } + return TRUE; +} + + +// This is normally called when the input pin type is set to install a palette +// We will typically be called from two different places. The first is when we +// have negotiated a palettised media type after connection, the other is when +// we receive a new type during processing with an updated palette in which +// case we must remove and release the resources held by the current palette + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HRESULT CImagePalette::PreparePalette(const CMediaType *pmtNew, + const CMediaType *pmtOld, + __in LPSTR szDevice) +{ + const VIDEOINFOHEADER *pNewInfo = (VIDEOINFOHEADER *) pmtNew->Format(); + const VIDEOINFOHEADER *pOldInfo = (VIDEOINFOHEADER *) pmtOld->Format(); + ASSERT(pNewInfo); + + // This is an performance optimisation, when we get a media type we check + // to see if the format requires a palette change. If either we need one + // when previously we didn't or vica versa then this returns TRUE, if we + // previously needed a palette and we do now it compares their colours + + if (ShouldUpdate(pNewInfo,pOldInfo) == FALSE) { + NOTE("No update needed"); + return S_FALSE; + } + + // We must notify the filter graph that the application may have changed + // the palette although in practice we don't bother checking to see if it + // is really different. If it tries to get the palette either the window + // or renderer lock will ensure it doesn't get in until we are finished + + RemovePalette(); + m_pFilter->NotifyEvent(EC_PALETTE_CHANGED,0,0); + + // Do we need a palette for the new format + + if (ContainsPalette(pNewInfo) == FALSE) { + NOTE("New has no palette"); + return S_FALSE; + } + + if (m_pBaseWindow) { + m_pBaseWindow->LockPaletteLock(); + } + + // If we're changing the palette on the fly then we increment our palette + // cookie which is compared against the cookie also stored in all of our + // DIBSECTION media samples. If they don't match when we come to draw it + // then we know the sample is out of date and we'll update it's palette + + NOTE("Making new colour palette"); + m_hPalette = MakePalette(pNewInfo, szDevice); + ASSERT(m_hPalette != NULL); + + if (m_pBaseWindow) { + m_pBaseWindow->UnlockPaletteLock(); + } + + // The window in which the new palette is to be realised may be a NULL + // pointer to signal that no window is in use, if so we don't call it + // Some filters just want to use this object to create/manage palettes + + if (m_pBaseWindow) m_pBaseWindow->SetPalette(m_hPalette); + + // This is the only time where we need access to the draw object to say + // to it that a new palette will be arriving on a sample real soon. The + // constructor may take a NULL pointer in which case we don't call this + + if (m_pDrawImage) m_pDrawImage->IncrementPaletteVersion(); + return NOERROR; +} + + +// Helper function to copy a palette out of any kind of VIDEOINFO (ie it may +// be YUV or true colour) into a palettised VIDEOINFO. We use this changing +// palettes on DirectDraw samples as a source filter can attach a palette to +// any buffer (eg YUV) and hand it back. We make a new palette out of that +// format and then copy the palette colours into the current connection type + +HRESULT CImagePalette::CopyPalette(const CMediaType *pSrc,__out CMediaType *pDest) +{ + // Reset the destination palette before starting + + VIDEOINFOHEADER *pDestInfo = (VIDEOINFOHEADER *) pDest->Format(); + pDestInfo->bmiHeader.biClrUsed = 0; + pDestInfo->bmiHeader.biClrImportant = 0; + + // Does the destination have a palette + + if (PALETTISED(pDestInfo) == FALSE) { + NOTE("No destination palette"); + return S_FALSE; + } + + // Does the source contain a palette + + const VIDEOINFOHEADER *pSrcInfo = (VIDEOINFOHEADER *) pSrc->Format(); + if (ContainsPalette(pSrcInfo) == FALSE) { + NOTE("No source palette"); + return S_FALSE; + } + + // The number of colours may be zero filled + + DWORD PaletteEntries = pSrcInfo->bmiHeader.biClrUsed; + if (PaletteEntries == 0) { + DWORD Maximum = (1 << pSrcInfo->bmiHeader.biBitCount); + NOTE1("Setting maximum colours (%d)",Maximum); + PaletteEntries = Maximum; + } + + // Make sure the destination has enough room for the palette + + ASSERT(pSrcInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); + ASSERT(pSrcInfo->bmiHeader.biClrImportant <= PaletteEntries); + ASSERT(COLORS(pDestInfo) == GetBitmapPalette(pDestInfo)); + pDestInfo->bmiHeader.biClrUsed = PaletteEntries; + pDestInfo->bmiHeader.biClrImportant = pSrcInfo->bmiHeader.biClrImportant; + ULONG BitmapSize = GetBitmapFormatSize(HEADER(pSrcInfo)); + + if (pDest->FormatLength() < BitmapSize) { + NOTE("Reallocating destination"); + pDest->ReallocFormatBuffer(BitmapSize); + } + + // Now copy the palette colours across + + CopyMemory((PVOID) COLORS(pDestInfo), + (PVOID) GetBitmapPalette(pSrcInfo), + PaletteEntries * sizeof(RGBQUAD)); + + return NOERROR; +} + + +// This is normally called when the palette is changed (typically during a +// dynamic format change) to remove any palette we previously installed. We +// replace it (if necessary) in the video window with a standard VGA palette +// that should always be available even if this is a true colour display + +HRESULT CImagePalette::RemovePalette() +{ + if (m_pBaseWindow) { + m_pBaseWindow->LockPaletteLock(); + } + + // Do we have a palette to remove + + if (m_hPalette != NULL) { + + if (m_pBaseWindow) { + // Make sure that the window's palette handle matches + // our palette handle. + ASSERT(m_hPalette == m_pBaseWindow->GetPalette()); + + m_pBaseWindow->UnsetPalette(); + } + + EXECUTE_ASSERT(DeleteObject(m_hPalette)); + m_hPalette = NULL; + } + + if (m_pBaseWindow) { + m_pBaseWindow->UnlockPaletteLock(); + } + + return NOERROR; +} + + +// Called to create a palette for the object, the data structure used by GDI +// to describe a palette is a LOGPALETTE, this includes a variable number of +// PALETTEENTRY fields which are the colours, we have to convert the RGBQUAD +// colour fields we are handed in a BITMAPINFO from the media type into these +// This handles extraction of palettes from true colour and YUV media formats + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HPALETTE CImagePalette::MakePalette(const VIDEOINFOHEADER *pVideoInfo, __in LPSTR szDevice) +{ + ASSERT(ContainsPalette(pVideoInfo) == TRUE); + ASSERT(pVideoInfo->bmiHeader.biClrUsed <= iPALETTE_COLORS); + BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo); + + const RGBQUAD *pColours; // Pointer to the palette + LOGPALETTE *lp; // Used to create a palette + HPALETTE hPalette; // Logical palette object + + lp = (LOGPALETTE *) new BYTE[sizeof(LOGPALETTE) + SIZE_PALETTE]; + if (lp == NULL) { + return NULL; + } + + // Unfortunately for some hare brained reason a GDI palette entry (a + // PALETTEENTRY structure) is different to a palette entry from a DIB + // format (a RGBQUAD structure) so we have to do the field conversion + // The VIDEOINFO containing the palette may be a true colour type so + // we use GetBitmapPalette to skip over any bit fields if they exist + + lp->palVersion = PALVERSION; + lp->palNumEntries = (USHORT) pHeader->biClrUsed; + if (lp->palNumEntries == 0) lp->palNumEntries = (1 << pHeader->biBitCount); + pColours = GetBitmapPalette(pVideoInfo); + + for (DWORD dwCount = 0;dwCount < lp->palNumEntries;dwCount++) { + lp->palPalEntry[dwCount].peRed = pColours[dwCount].rgbRed; + lp->palPalEntry[dwCount].peGreen = pColours[dwCount].rgbGreen; + lp->palPalEntry[dwCount].peBlue = pColours[dwCount].rgbBlue; + lp->palPalEntry[dwCount].peFlags = 0; + } + + MakeIdentityPalette(lp->palPalEntry, lp->palNumEntries, szDevice); + + // Create a logical palette + + hPalette = CreatePalette(lp); + ASSERT(hPalette != NULL); + delete[] lp; + return hPalette; +} + + +// GDI does a fair job of compressing the palette entries you give it, so for +// example if you have five entries with an RGB colour (0,0,0) it will remove +// all but one of them. When you subsequently draw an image it will map from +// your logical palette to the compressed device palette. This function looks +// to see if it is trying to be an identity palette and if so sets the flags +// field in the PALETTEENTRYs so they remain expanded to boost performance + +// We can be passed an optional device name if we wish to prepare a palette +// for a specific monitor on a multi monitor system + +HRESULT CImagePalette::MakeIdentityPalette(__inout_ecount_full(iColours) PALETTEENTRY *pEntry,INT iColours, __in LPSTR szDevice) +{ + PALETTEENTRY SystemEntries[10]; // System palette entries + BOOL bIdentityPalette = TRUE; // Is an identity palette + ASSERT(iColours <= iPALETTE_COLORS); // Should have a palette + const int PalLoCount = 10; // First ten reserved colours + const int PalHiStart = 246; // Last VGA palette entries + + // Does this have the full colour range + + if (iColours < 10) { + return S_FALSE; + } + + // Apparently some displays have odd numbers of system colours + + // Get a DC on the right monitor - it's ugly, but this is the way you have + // to do it + HDC hdc; + if (szDevice == NULL || lstrcmpiLocaleIndependentA(szDevice, "DISPLAY") == 0) + hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); + else + hdc = CreateDCA(NULL, szDevice, NULL, NULL); + if (NULL == hdc) { + return E_OUTOFMEMORY; + } + INT Reserved = GetDeviceCaps(hdc,NUMRESERVED); + if (Reserved != 20) { + DeleteDC(hdc); + return S_FALSE; + } + + // Compare our palette against the first ten system entries. The reason I + // don't do a memory compare between our two arrays of colours is because + // I am not sure what will be in the flags fields for the system entries + + UINT Result = GetSystemPaletteEntries(hdc,0,PalLoCount,SystemEntries); + for (UINT Count = 0;Count < Result;Count++) { + if (SystemEntries[Count].peRed != pEntry[Count].peRed || + SystemEntries[Count].peGreen != pEntry[Count].peGreen || + SystemEntries[Count].peBlue != pEntry[Count].peBlue) { + bIdentityPalette = FALSE; + } + } + + // And likewise compare against the last ten entries + + Result = GetSystemPaletteEntries(hdc,PalHiStart,PalLoCount,SystemEntries); + for (UINT Count = 0;Count < Result;Count++) { + if (INT(Count) + PalHiStart < iColours) { + if (SystemEntries[Count].peRed != pEntry[PalHiStart + Count].peRed || + SystemEntries[Count].peGreen != pEntry[PalHiStart + Count].peGreen || + SystemEntries[Count].peBlue != pEntry[PalHiStart + Count].peBlue) { + bIdentityPalette = FALSE; + } + } + } + + // If not an identity palette then return S_FALSE + + DeleteDC(hdc); + if (bIdentityPalette == FALSE) { + return S_FALSE; + } + + // Set the non VGA entries so that GDI doesn't map them + + for (UINT Count = PalLoCount; INT(Count) < std::min(PalHiStart, iColours); Count++) { + pEntry[Count].peFlags = PC_NOCOLLAPSE; + } + return NOERROR; +} + + +// Constructor initialises the VIDEOINFO we keep storing the current display +// format. The format can be changed at any time, to reset the format held +// by us call the RefreshDisplayType directly (it's a public method). Since +// more than one thread will typically call us (ie window threads resetting +// the type and source threads in the type checking methods) we have a lock + +CImageDisplay::CImageDisplay() +{ + RefreshDisplayType(NULL); +} + + + +// This initialises the format we hold which contains the display device type +// We do a conversion on the display device type in here so that when we start +// type checking input formats we can assume that certain fields have been set +// correctly, an example is when we make the 16 bit mask fields explicit. This +// is normally called when we receive WM_DEVMODECHANGED device change messages + +// The optional szDeviceName parameter tells us which monitor we are interested +// in for a multi monitor system + +HRESULT CImageDisplay::RefreshDisplayType(__in_opt LPSTR szDeviceName) +{ + CAutoLock cDisplayLock(this); + + // Set the preferred format type + + ZeroMemory((PVOID)&m_Display,sizeof(VIDEOINFOHEADER)+sizeof(TRUECOLORINFO)); + m_Display.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + m_Display.bmiHeader.biBitCount = FALSE; + + // Get the bit depth of a device compatible bitmap + + // get caps of whichever monitor they are interested in (multi monitor) + HDC hdcDisplay; + // it's ugly, but this is the way you have to do it + if (szDeviceName == NULL || lstrcmpiLocaleIndependentA(szDeviceName, "DISPLAY") == 0) + hdcDisplay = CreateDCA("DISPLAY", NULL, NULL, NULL); + else + hdcDisplay = CreateDCA(NULL, szDeviceName, NULL, NULL); + if (hdcDisplay == NULL) { + ASSERT(FALSE); + DbgLog((LOG_ERROR,1,TEXT("ACK! Can't get a DC for %hs"), + szDeviceName ? szDeviceName : "")); + return E_FAIL; + } else { + DbgLog((LOG_TRACE,3,TEXT("Created a DC for %s"), + szDeviceName ? szDeviceName : "")); + } + HBITMAP hbm = CreateCompatibleBitmap(hdcDisplay,1,1); + if ( hbm ) + { + GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); + + // This call will get the colour table or the proper bitfields + GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO *)&m_Display.bmiHeader,DIB_RGB_COLORS); + DeleteObject(hbm); + } + DeleteDC(hdcDisplay); + + // Complete the display type initialisation + + ASSERT(CheckHeaderValidity(&m_Display)); + UpdateFormat(&m_Display); + DbgLog((LOG_TRACE,3,TEXT("New DISPLAY bit depth =%d"), + m_Display.bmiHeader.biBitCount)); + return NOERROR; +} + + +// We assume throughout this code that any bitfields masks are allowed no +// more than eight bits to store a colour component. This checks that the +// bit count assumption is enforced and also makes sure that all the bits +// set are contiguous. We return a boolean TRUE if the field checks out ok + +BOOL CImageDisplay::CheckBitFields(const VIDEOINFO *pInput) +{ + DWORD *pBitFields = (DWORD *) BITMASKS(pInput); + + for (INT iColour = iRED;iColour <= iBLUE;iColour++) { + + // First of all work out how many bits are set + + DWORD SetBits = CountSetBits(pBitFields[iColour]); + if (SetBits > iMAXBITS || SetBits == 0) { + NOTE1("Bit fields for component %d invalid",iColour); + return FALSE; + } + + // Next work out the number of zero bits prefix + DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); + + // This is going to see if all the bits set are contiguous (as they + // should be). We know how much to shift them right by from the + // count of prefix bits. The number of bits set defines a mask, we + // invert this (ones complement) and AND it with the shifted bit + // fields. If the result is NON zero then there are bit(s) sticking + // out the left hand end which means they are not contiguous + + DWORD TestField = pBitFields[iColour] >> PrefixBits; + DWORD Mask = ULONG_MAX << SetBits; + if (TestField & Mask) { + NOTE1("Bit fields for component %d not contiguous",iColour); + return FALSE; + } + } + return TRUE; +} + + +// This counts the number of bits set in the input field + +DWORD CImageDisplay::CountSetBits(DWORD Field) +{ + // This is a relatively well known bit counting algorithm + + DWORD Count = 0; + DWORD init = Field; + + // Until the input is exhausted, count the number of bits + + while (init) { + init = init & (init - 1); // Turn off the bottommost bit + Count++; + } + return Count; +} + + +// This counts the number of zero bits upto the first one set NOTE the input +// field should have been previously checked to ensure there is at least one +// set although if we don't find one set we return the impossible value 32 + +DWORD CImageDisplay::CountPrefixBits(DWORD Field) +{ + DWORD Mask = 1; + DWORD Count = 0; + + for (;;) { + if (Field & Mask) { + return Count; + } + Count++; + + ASSERT(Mask != 0x80000000); + if (Mask == 0x80000000) { + return Count; + } + Mask <<= 1; + } +} + + +// This is called to check the BITMAPINFOHEADER for the input type. There are +// many implicit dependancies between the fields in a header structure which +// if we validate now make for easier manipulation in subsequent handling. We +// also check that the BITMAPINFOHEADER matches it's specification such that +// fields likes the number of planes is one, that it's structure size is set +// correctly and that the bitmap dimensions have not been set as negative + +BOOL CImageDisplay::CheckHeaderValidity(const VIDEOINFO *pInput) +{ + // Check the bitmap width and height are not negative. + + if (pInput->bmiHeader.biWidth <= 0 || + pInput->bmiHeader.biHeight <= 0) { + NOTE("Invalid bitmap dimensions"); + return FALSE; + } + + // Check the compression is either BI_RGB or BI_BITFIELDS + + if (pInput->bmiHeader.biCompression != BI_RGB) { + if (pInput->bmiHeader.biCompression != BI_BITFIELDS) { + NOTE("Invalid compression format"); + return FALSE; + } + } + + // If BI_BITFIELDS compression format check the colour depth + + if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { + if (pInput->bmiHeader.biBitCount != 16) { + if (pInput->bmiHeader.biBitCount != 32) { + NOTE("BI_BITFIELDS not 16/32 bit depth"); + return FALSE; + } + } + } + + // Check the assumptions about the layout of the bit fields + + if (pInput->bmiHeader.biCompression == BI_BITFIELDS) { + if (CheckBitFields(pInput) == FALSE) { + NOTE("Bit fields are not valid"); + return FALSE; + } + } + + // Are the number of planes equal to one + + if (pInput->bmiHeader.biPlanes != 1) { + NOTE("Number of planes not one"); + return FALSE; + } + + // Check the image size is consistent (it can be zero) + + if (pInput->bmiHeader.biSizeImage != GetBitmapSize(&pInput->bmiHeader)) { + if (pInput->bmiHeader.biSizeImage) { + NOTE("Image size incorrectly set"); + return FALSE; + } + } + + // Check the size of the structure + + if (pInput->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) { + NOTE("Size of BITMAPINFOHEADER wrong"); + return FALSE; + } + return CheckPaletteHeader(pInput); +} + + +// This runs a few simple tests against the palette fields in the input to +// see if it looks vaguely correct. The tests look at the number of palette +// colours present, the number considered important and the biCompression +// field which should always be BI_RGB as no other formats are meaningful + +BOOL CImageDisplay::CheckPaletteHeader(const VIDEOINFO *pInput) +{ + // The checks here are for palettised videos only + + if (PALETTISED(pInput) == FALSE) { + if (pInput->bmiHeader.biClrUsed) { + NOTE("Invalid palette entries"); + return FALSE; + } + return TRUE; + } + + // Compression type of BI_BITFIELDS is meaningless for palette video + + if (pInput->bmiHeader.biCompression != BI_RGB) { + NOTE("Palettised video must be BI_RGB"); + return FALSE; + } + + // Check the number of palette colours is correct + + if (pInput->bmiHeader.biClrUsed > PALETTE_ENTRIES(pInput)) { + NOTE("Too many colours in palette"); + return FALSE; + } + + // The number of important colours shouldn't exceed the number used + + if (pInput->bmiHeader.biClrImportant > pInput->bmiHeader.biClrUsed) { + NOTE("Too many important colours"); + return FALSE; + } + return TRUE; +} + + +// Return the format of the video display + +const VIDEOINFO *CImageDisplay::GetDisplayFormat() +{ + return &m_Display; +} + + +// Return TRUE if the display uses a palette + +BOOL CImageDisplay::IsPalettised() +{ + return PALETTISED(&m_Display); +} + + +// Return the bit depth of the current display setting + +WORD CImageDisplay::GetDisplayDepth() +{ + return m_Display.bmiHeader.biBitCount; +} + + +// Initialise the optional fields in a VIDEOINFO. These are mainly to do with +// the source and destination rectangles and palette information such as the +// number of colours present. It simplifies our code just a little if we don't +// have to keep checking for all the different valid permutations in a header +// every time we want to do anything with it (an example would be creating a +// palette). We set the base class media type before calling this function so +// that the media types between the pins match after a connection is made + +HRESULT CImageDisplay::UpdateFormat(__inout VIDEOINFO *pVideoInfo) +{ + ASSERT(pVideoInfo); + + BITMAPINFOHEADER *pbmi = HEADER(pVideoInfo); + UNREFERENCED_PARAMETER(pbmi); + SetRectEmpty(&pVideoInfo->rcSource); + SetRectEmpty(&pVideoInfo->rcTarget); + + // Set the number of colours explicitly + + if (PALETTISED(pVideoInfo)) { + if (pVideoInfo->bmiHeader.biClrUsed == 0) { + pVideoInfo->bmiHeader.biClrUsed = PALETTE_ENTRIES(pVideoInfo); + } + } + + // The number of important colours shouldn't exceed the number used, on + // some displays the number of important colours is not initialised when + // retrieving the display type so we set the colours used correctly + + if (pVideoInfo->bmiHeader.biClrImportant > pVideoInfo->bmiHeader.biClrUsed) { + pVideoInfo->bmiHeader.biClrImportant = PALETTE_ENTRIES(pVideoInfo); + } + + // Change the image size field to be explicit + + if (pVideoInfo->bmiHeader.biSizeImage == 0) { + pVideoInfo->bmiHeader.biSizeImage = GetBitmapSize(&pVideoInfo->bmiHeader); + } + return NOERROR; +} + + +// Lots of video rendering filters want code to check proposed formats are ok +// This checks the VIDEOINFO we are passed as a media type. If the media type +// is a valid media type then we return NOERROR otherwise E_INVALIDARG. Note +// however we only accept formats that can be easily displayed in the display +// so if we are on a 16 bit device we will not accept 24 bit images. The one +// complexity is that most displays draw 8 bit palettised images efficiently +// Also if the input format is less colour bits per pixel then we also accept + +HRESULT CImageDisplay::CheckVideoType(const VIDEOINFO *pInput) +{ + // First of all check the VIDEOINFOHEADER looks correct + + if (CheckHeaderValidity(pInput) == FALSE) { + return E_INVALIDARG; + } + + // Virtually all devices support palettised images efficiently + + if (m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount) { + if (PALETTISED(pInput) == TRUE) { + ASSERT(PALETTISED(&m_Display) == TRUE); + NOTE("(Video) Type connection ACCEPTED"); + return NOERROR; + } + } + + + // Is the display depth greater than the input format + + if (m_Display.bmiHeader.biBitCount > pInput->bmiHeader.biBitCount) { + NOTE("(Video) Mismatch agreed"); + return NOERROR; + } + + // Is the display depth less than the input format + + if (m_Display.bmiHeader.biBitCount < pInput->bmiHeader.biBitCount) { + NOTE("(Video) Format mismatch"); + return E_INVALIDARG; + } + + + // Both input and display formats are either BI_RGB or BI_BITFIELDS + + ASSERT(m_Display.bmiHeader.biBitCount == pInput->bmiHeader.biBitCount); + ASSERT(PALETTISED(pInput) == FALSE); + ASSERT(PALETTISED(&m_Display) == FALSE); + + // BI_RGB 16 bit representation is implicitly RGB555, and likewise BI_RGB + // 24 bit representation is RGB888. So we initialise a pointer to the bit + // fields they really mean and check against the display device format + // This is only going to be called when both formats are equal bits pixel + + const DWORD *pInputMask = GetBitMasks(pInput); + const DWORD *pDisplayMask = GetBitMasks((VIDEOINFO *)&m_Display); + + if (pInputMask[iRED] != pDisplayMask[iRED] || + pInputMask[iGREEN] != pDisplayMask[iGREEN] || + pInputMask[iBLUE] != pDisplayMask[iBLUE]) { + + NOTE("(Video) Bit field mismatch"); + return E_INVALIDARG; + } + + NOTE("(Video) Type connection ACCEPTED"); + return NOERROR; +} + + +// Return the bit masks for the true colour VIDEOINFO provided + +const DWORD *CImageDisplay::GetBitMasks(const VIDEOINFO *pVideoInfo) +{ + static const DWORD FailMasks[] = {0,0,0}; + + if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) { + return BITMASKS(pVideoInfo); + } + + ASSERT(pVideoInfo->bmiHeader.biCompression == BI_RGB); + + switch (pVideoInfo->bmiHeader.biBitCount) { + case 16: return bits555; + case 24: return bits888; + case 32: return bits888; + default: return FailMasks; + } +} + + +// Check to see if we can support media type pmtIn as proposed by the output +// pin - We first check that the major media type is video and also identify +// the media sub type. Then we thoroughly check the VIDEOINFO type provided +// As well as the contained VIDEOINFO being correct the major type must be +// video, the subtype a recognised video format and the type GUID correct + +HRESULT CImageDisplay::CheckMediaType(const CMediaType *pmtIn) +{ + // Does this have a VIDEOINFOHEADER format block + + const GUID *pFormatType = pmtIn->FormatType(); + if (*pFormatType != FORMAT_VideoInfo) { + NOTE("Format GUID not a VIDEOINFOHEADER"); + return E_INVALIDARG; + } + ASSERT(pmtIn->Format()); + + // Check the format looks reasonably ok + + ULONG Length = pmtIn->FormatLength(); + if (Length < SIZE_VIDEOHEADER) { + NOTE("Format smaller than a VIDEOHEADER"); + return E_FAIL; + } + + VIDEOINFO *pInput = (VIDEOINFO *) pmtIn->Format(); + + // Check the major type is MEDIATYPE_Video + + const GUID *pMajorType = pmtIn->Type(); + if (*pMajorType != MEDIATYPE_Video) { + NOTE("Major type not MEDIATYPE_Video"); + return E_INVALIDARG; + } + + // Check we can identify the media subtype + + const GUID *pSubType = pmtIn->Subtype(); + if (GetBitCount(pSubType) == USHRT_MAX) { + NOTE("Invalid video media subtype"); + return E_INVALIDARG; + } + return CheckVideoType(pInput); +} + + +// Given a video format described by a VIDEOINFO structure we return the mask +// that is used to obtain the range of acceptable colours for this type, for +// example, the mask for a 24 bit true colour format is 0xFF in all cases. A +// 16 bit 5:6:5 display format uses 0xF8, 0xFC and 0xF8, therefore given any +// RGB triplets we can AND them with these fields to find one that is valid + +BOOL CImageDisplay::GetColourMask(__out DWORD *pMaskRed, + __out DWORD *pMaskGreen, + __out DWORD *pMaskBlue) +{ + CAutoLock cDisplayLock(this); + *pMaskRed = 0xFF; + *pMaskGreen = 0xFF; + *pMaskBlue = 0xFF; + + // If this format is palettised then it doesn't have bit fields + + if (m_Display.bmiHeader.biBitCount < 16) { + return FALSE; + } + + // If this is a 24 bit true colour display then it can handle all the + // possible colour component ranges described by a byte. It is never + // allowed for a 24 bit colour depth image to have BI_BITFIELDS set + + if (m_Display.bmiHeader.biBitCount == 24) { + ASSERT(m_Display.bmiHeader.biCompression == BI_RGB); + return TRUE; + } + + // Calculate the mask based on the format's bit fields + + const DWORD *pBitFields = (DWORD *) GetBitMasks((VIDEOINFO *)&m_Display); + DWORD *pOutputMask[] = { pMaskRed, pMaskGreen, pMaskBlue }; + + // We know from earlier testing that there are no more than iMAXBITS + // bits set in the mask and that they are all contiguous. All that + // therefore remains is to shift them into the correct position + + for (INT iColour = iRED;iColour <= iBLUE;iColour++) { + + // This works out how many bits there are and where they live + + DWORD PrefixBits = CountPrefixBits(pBitFields[iColour]); + DWORD SetBits = CountSetBits(pBitFields[iColour]); + + // The first shift moves the bit field so that it is right justified + // in the DWORD, after which we then shift it back left which then + // puts the leading bit in the bytes most significant bit position + + *(pOutputMask[iColour]) = pBitFields[iColour] >> PrefixBits; + *(pOutputMask[iColour]) <<= (iMAXBITS - SetBits); + } + return TRUE; +} + + +/* Helper to convert to VIDEOINFOHEADER2 +*/ +STDAPI ConvertVideoInfoToVideoInfo2(__inout AM_MEDIA_TYPE *pmt) +{ + if (pmt->formattype != FORMAT_VideoInfo) { + return E_INVALIDARG; + } + if (NULL == pmt->pbFormat || pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { + return E_INVALIDARG; + } + VIDEOINFO *pVideoInfo = (VIDEOINFO *)pmt->pbFormat; + UNREFERENCED_PARAMETER(pVideoInfo); + DWORD dwNewSize; + HRESULT hr = DWordAdd(pmt->cbFormat, sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER), &dwNewSize); + if (FAILED(hr)) { + return hr; + } + PVOID pvNew = CoTaskMemAlloc(dwNewSize); + if (pvNew == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(pvNew, pmt->pbFormat, FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); + ZeroMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), + sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER)); + CopyMemory((PBYTE)pvNew + FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader), + pmt->pbFormat + FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader), + pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader)); + VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pvNew; + pVideoInfo2->dwPictAspectRatioX = (DWORD)pVideoInfo2->bmiHeader.biWidth; + pVideoInfo2->dwPictAspectRatioY = (DWORD)abs(pVideoInfo2->bmiHeader.biHeight); + pmt->formattype = FORMAT_VideoInfo2; + CoTaskMemFree(pmt->pbFormat); + pmt->pbFormat = (PBYTE)pvNew; + pmt->cbFormat += sizeof(VIDEOINFOHEADER2) - sizeof(VIDEOINFOHEADER); + return S_OK; +} + + +// Check a media type containing VIDEOINFOHEADER +STDAPI CheckVideoInfoType(const AM_MEDIA_TYPE *pmt) +{ + if (NULL == pmt || NULL == pmt->pbFormat) { + return E_POINTER; + } + if (pmt->majortype != MEDIATYPE_Video || + pmt->formattype != FORMAT_VideoInfo || + pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + const VIDEOINFOHEADER *pHeader = (const VIDEOINFOHEADER *)pmt->pbFormat; + if (!ValidateBitmapInfoHeader( + &pHeader->bmiHeader, + pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER, bmiHeader))) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + + return S_OK; +} + +// Check a media type containing VIDEOINFOHEADER2 +STDAPI CheckVideoInfo2Type(const AM_MEDIA_TYPE *pmt) +{ + if (NULL == pmt || NULL == pmt->pbFormat) { + return E_POINTER; + } + if (pmt->majortype != MEDIATYPE_Video || + pmt->formattype != FORMAT_VideoInfo2 || + pmt->cbFormat < sizeof(VIDEOINFOHEADER2)) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + const VIDEOINFOHEADER2 *pHeader = (const VIDEOINFOHEADER2 *)pmt->pbFormat; + if (!ValidateBitmapInfoHeader( + &pHeader->bmiHeader, + pmt->cbFormat - FIELD_OFFSET(VIDEOINFOHEADER2, bmiHeader))) { + return VFW_E_TYPE_NOT_ACCEPTED; + } + + return S_OK; +} diff --git a/src/thirdparty/BaseClasses/winutil.h b/src/thirdparty/BaseClasses/winutil.h index 6f4707e5097..79c4642ab44 100644 --- a/src/thirdparty/BaseClasses/winutil.h +++ b/src/thirdparty/BaseClasses/winutil.h @@ -1,421 +1,421 @@ -//------------------------------------------------------------------------------ -// File: WinUtil.h -// -// Desc: DirectShow base classes - defines generic handler classes. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -// Make sure that you call PrepareWindow to initialise the window after -// the object has been constructed. It is a separate method so that -// derived classes can override useful methods like MessageLoop. Also -// any derived class must call DoneWithWindow in its destructor. If it -// doesn't a message may be retrieved and call a derived class member -// function while a thread is executing the base class destructor code - -#ifndef __WINUTIL__ -#define __WINUTIL__ - -const int DEFWIDTH = 320; // Initial window width -const int DEFHEIGHT = 240; // Initial window height -const int CAPTION = 256; // Maximum length of caption -const int TIMELENGTH = 50; // Maximum length of times -const int PROFILESTR = 128; // Normal profile string -const WORD PALVERSION = 0x300; // GDI palette version -const LONG PALETTE_VERSION = (LONG) 1; // Initial palette version -const COLORREF VIDEO_COLOUR = 0; // Defaults to black background -const HANDLE hMEMORY = (HANDLE) (-1); // Says to open as memory file - -#define WIDTH(x) ((*(x)).right - (*(x)).left) -#define HEIGHT(x) ((*(x)).bottom - (*(x)).top) -#define SHOWSTAGE TEXT("WM_SHOWSTAGE") -#define SHOWSTAGETOP TEXT("WM_SHOWSTAGETOP") -#define REALIZEPALETTE TEXT("WM_REALIZEPALETTE") - -class AM_NOVTABLE CBaseWindow -{ -protected: - - HINSTANCE m_hInstance; // Global module instance handle - HWND m_hwnd; // Handle for our window - HDC m_hdc; // Device context for the window - LONG m_Width; // Client window width - LONG m_Height; // Client window height - BOOL m_bActivated; // Has the window been activated - LPTSTR m_pClassName; // Static string holding class name - DWORD m_ClassStyles; // Passed in to our constructor - DWORD m_WindowStyles; // Likewise the initial window styles - DWORD m_WindowStylesEx; // And the extended window styles - UINT m_ShowStageMessage; // Have the window shown with focus - UINT m_ShowStageTop; // Makes the window WS_EX_TOPMOST - UINT m_RealizePalette; // Makes us realize our new palette - HDC m_MemoryDC; // Used for fast BitBlt operations - HPALETTE m_hPalette; // Handle to any palette we may have - BYTE m_bNoRealize; // Don't realize palette now - BYTE m_bBackground; // Should we realise in background -#ifdef _DEBUG - BYTE m_bRealizing; // already realizing the palette -#endif - CCritSec m_WindowLock; // Serialise window object access - BOOL m_bDoGetDC; // Should this window get a DC - bool m_bDoPostToDestroy; // Use PostMessage to destroy - CCritSec m_PaletteLock; // This lock protects m_hPalette. - // It should be held anytime the - // program use the value of m_hPalette. - - // Maps windows message procedure into C++ methods - friend LRESULT CALLBACK WndProc(HWND hwnd, // Window handle - UINT uMsg, // Message ID - WPARAM wParam, // First parameter - LPARAM lParam); // Other parameter - - virtual LRESULT OnPaletteChange(HWND hwnd, UINT Message); - -public: - - CBaseWindow(BOOL bDoGetDC = TRUE, bool bPostToDestroy = false); - -#ifdef _DEBUG - virtual ~CBaseWindow(); -#endif - - virtual HRESULT DoneWithWindow(); - virtual HRESULT PrepareWindow(); - virtual HRESULT InactivateWindow(); - virtual HRESULT ActivateWindow(); - virtual BOOL OnSize(LONG Width, LONG Height); - virtual BOOL OnClose(); - virtual RECT GetDefaultRect(); - virtual HRESULT UninitialiseWindow(); - virtual HRESULT InitialiseWindow(HWND hwnd); - - HRESULT CompleteConnect(); - HRESULT DoCreateWindow(); - - HRESULT PerformanceAlignWindow(); - HRESULT DoShowWindow(LONG ShowCmd); - void PaintWindow(BOOL bErase); - void DoSetWindowForeground(BOOL bFocus); - virtual HRESULT SetPalette(HPALETTE hPalette); - void SetRealize(BOOL bRealize) - { - m_bNoRealize = !bRealize; - } - - // Jump over to the window thread to set the current palette - HRESULT SetPalette(); - void UnsetPalette(void); - virtual HRESULT DoRealisePalette(BOOL bForceBackground = FALSE); - - void LockPaletteLock(); - void UnlockPaletteLock(); - - virtual BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) - { return FALSE; }; - - // Access our window information - - bool WindowExists(); - LONG GetWindowWidth(); - LONG GetWindowHeight(); - HWND GetWindowHWND(); - HDC GetMemoryHDC(); - HDC GetWindowHDC(); - - #ifdef _DEBUG - HPALETTE GetPalette(); - #endif // DEBUG - - // This is the window procedure the derived object should override - - virtual INT_PTR OnReceiveMessage(HWND hwnd, // Window handle - UINT uMsg, // Message ID - WPARAM wParam, // First parameter - LPARAM lParam); // Other parameter - - // Must be overriden to return class and window styles - - virtual LPTSTR GetClassWindowStyles( - __out DWORD *pClassStyles, // Class styles - __out DWORD *pWindowStyles, // Window styles - __out DWORD *pWindowStylesEx) PURE; // Extended styles -}; - - -// This helper class is entirely subservient to the owning CBaseWindow object -// All this object does is to split out the actual drawing operation from the -// main object (because it was becoming too large). We have a number of entry -// points to set things like the draw device contexts, to implement the actual -// drawing and to set the destination rectangle in the client window. We have -// no critical section locking in this class because we are used exclusively -// by the owning window object which looks after serialising calls into us - -// If you want to use this class make sure you call NotifyAllocator once the -// allocate has been agreed, also call NotifyMediaType with a pointer to a -// NON stack based CMediaType once that has been set (we keep a pointer to -// the original rather than taking a copy). When the palette changes call -// IncrementPaletteVersion (easiest thing to do is to also call this method -// in the SetMediaType method most filters implement). Finally before you -// start rendering anything call SetDrawContext so that we can get the HDCs -// for drawing from the CBaseWindow object we are given during construction - -class CDrawImage -{ -protected: - - CBaseWindow *m_pBaseWindow; // Owning video window object - CRefTime m_StartSample; // Start time for the current sample - CRefTime m_EndSample; // And likewise it's end sample time - HDC m_hdc; // Main window device context - HDC m_MemoryDC; // Offscreen draw device context - RECT m_TargetRect; // Target destination rectangle - RECT m_SourceRect; // Source image rectangle - BOOL m_bStretch; // Do we have to stretch the images - BOOL m_bUsingImageAllocator; // Are the samples shared DIBSECTIONs - CMediaType *m_pMediaType; // Pointer to the current format - int m_perfidRenderTime; // Time taken to render an image - LONG m_PaletteVersion; // Current palette version cookie - - // Draw the video images in the window - - void SlowRender(IMediaSample *pMediaSample); - void FastRender(IMediaSample *pMediaSample); - void DisplaySampleTimes(IMediaSample *pSample); - void UpdateColourTable(HDC hdc,__in BITMAPINFOHEADER *pbmi); - void SetStretchMode(); - -public: - - // Used to control the image drawing - - CDrawImage(__inout CBaseWindow *pBaseWindow); - BOOL DrawImage(IMediaSample *pMediaSample); - BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, - __in LPRECT lprcSrc, __in LPRECT lprcDst); - void SetDrawContext(); - void SetTargetRect(__in RECT *pTargetRect); - void SetSourceRect(__in RECT *pSourceRect); - void GetTargetRect(__out RECT *pTargetRect); - void GetSourceRect(__out RECT *pSourceRect); - virtual RECT ScaleSourceRect(const RECT *pSource); - - // Handle updating palettes as they change - - LONG GetPaletteVersion(); - void ResetPaletteVersion(); - void IncrementPaletteVersion(); - - // Tell us media types and allocator assignments - - void NotifyAllocator(BOOL bUsingImageAllocator); - void NotifyMediaType(__in CMediaType *pMediaType); - BOOL UsingImageAllocator(); - - // Called when we are about to draw an image - - void NotifyStartDraw() { - MSR_START(m_perfidRenderTime); - }; - - // Called when we complete an image rendering - - void NotifyEndDraw() { - MSR_STOP(m_perfidRenderTime); - }; -}; - - -// This is the structure used to keep information about each GDI DIB. All the -// samples we create from our allocator will have a DIBSECTION allocated to -// them. When we receive the sample we know we can BitBlt straight to an HDC - -typedef struct tagDIBDATA { - - LONG PaletteVersion; // Current palette version in use - DIBSECTION DibSection; // Details of DIB section allocated - HBITMAP hBitmap; // Handle to bitmap for drawing - HANDLE hMapping; // Handle to shared memory block - BYTE *pBase; // Pointer to base memory address - -} DIBDATA; - - -// This class inherits from CMediaSample and uses all of it's methods but it -// overrides the constructor to initialise itself with the DIBDATA structure -// When we come to render an IMediaSample we will know if we are using our own -// allocator, and if we are, we can cast the IMediaSample to a pointer to one -// of these are retrieve the DIB section information and hence the HBITMAP - -class CImageSample : public CMediaSample -{ -protected: - - DIBDATA m_DibData; // Information about the DIBSECTION - BOOL m_bInit; // Is the DIB information setup - -public: - - // Constructor - - CImageSample(__inout CBaseAllocator *pAllocator, - __in_opt LPCTSTR pName, - __inout HRESULT *phr, - __in_bcount(length) LPBYTE pBuffer, - LONG length); - - // Maintain the DIB/DirectDraw state - - void SetDIBData(__in DIBDATA *pDibData); - __out DIBDATA *GetDIBData(); -}; - - -// This is an allocator based on the abstract CBaseAllocator base class that -// allocates sample buffers in shared memory. The number and size of these -// are determined when the output pin calls Prepare on us. The shared memory -// blocks are used in subsequent calls to GDI CreateDIBSection, once that -// has been done the output pin can fill the buffers with data which will -// then be handed to GDI through BitBlt calls and thereby remove one copy - -class CImageAllocator : public CBaseAllocator -{ -protected: - - CBaseFilter *m_pFilter; // Delegate reference counts to - CMediaType *m_pMediaType; // Pointer to the current format - - // Used to create and delete samples - - HRESULT Alloc(); - void Free(); - - // Manage the shared DIBSECTION and DCI/DirectDraw buffers - - HRESULT CreateDIB(LONG InSize,DIBDATA &DibData); - STDMETHODIMP CheckSizes(__in ALLOCATOR_PROPERTIES *pRequest); - virtual CImageSample *CreateImageSample(__in_bcount(Length) LPBYTE pData,LONG Length); - -public: - - // Constructor and destructor - - CImageAllocator(__inout CBaseFilter *pFilter,__in_opt LPCTSTR pName,__inout HRESULT *phr); -#ifdef _DEBUG - ~CImageAllocator(); -#endif - - STDMETHODIMP_(ULONG) NonDelegatingAddRef(); - STDMETHODIMP_(ULONG) NonDelegatingRelease(); - void NotifyMediaType(__in CMediaType *pMediaType); - - // Agree the number of buffers to be used and their size - - STDMETHODIMP SetProperties( - __in ALLOCATOR_PROPERTIES *pRequest, - __out ALLOCATOR_PROPERTIES *pActual); -}; - - -// This class is a fairly specialised helper class for image renderers that -// have to create and manage palettes. The CBaseWindow class looks after -// realising palettes once they have been installed. This class can be used -// to create the palette handles from a media format (which must contain a -// VIDEOINFO structure in the format block). We try to make the palette an -// identity palette to maximise performance and also only change palettes -// if actually required to (we compare palette colours before updating). -// All the methods are virtual so that they can be overriden if so required - -class CImagePalette -{ -protected: - - CBaseWindow *m_pBaseWindow; // Window to realise palette in - CBaseFilter *m_pFilter; // Media filter to send events - CDrawImage *m_pDrawImage; // Object who will be drawing - HPALETTE m_hPalette; // The palette handle we own - -public: - - CImagePalette(__inout CBaseFilter *pBaseFilter, - __inout CBaseWindow *pBaseWindow, - __inout CDrawImage *pDrawImage); - -#ifdef _DEBUG - virtual ~CImagePalette(); -#endif - - static HPALETTE MakePalette(const VIDEOINFOHEADER *pVideoInfo, __in LPSTR szDevice); - HRESULT RemovePalette(); - static HRESULT MakeIdentityPalette(__inout_ecount_full(iColours) PALETTEENTRY *pEntry,INT iColours, __in LPSTR szDevice); - HRESULT CopyPalette(const CMediaType *pSrc,__out CMediaType *pDest); - BOOL ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,const VIDEOINFOHEADER *pOldInfo); - HRESULT PreparePalette(const CMediaType *pmtNew,const CMediaType *pmtOld,__in LPSTR szDevice); - - BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, __in LPRECT lprcSrc, __in LPRECT lprcDst) - { - return m_pDrawImage->DrawVideoImageHere(hdc, pMediaSample, lprcSrc,lprcDst); - } -}; - - -// Another helper class really for video based renderers. Most such renderers -// need to know what the display format is to some degree or another. This -// class initialises itself with the display format. The format can be asked -// for through GetDisplayFormat and various other accessor functions. If a -// filter detects a display format change (perhaps it gets a WM_DEVMODECHANGE -// message then it can call RefreshDisplayType to reset that format). Also -// many video renderers will want to check formats as they are proposed by -// source filters. This class provides methods to check formats and only -// accept those video formats that can be efficiently drawn using GDI calls - -class CImageDisplay : public CCritSec -{ -protected: - - // This holds the display format; biSize should not be too big, so we can - // safely use the VIDEOINFO structure - VIDEOINFO m_Display; - - static DWORD CountSetBits(const DWORD Field); - static DWORD CountPrefixBits(const DWORD Field); - static BOOL CheckBitFields(const VIDEOINFO *pInput); - -public: - - // Constructor and destructor - - CImageDisplay(); - - // Used to manage BITMAPINFOHEADERs and the display format - - const VIDEOINFO *GetDisplayFormat(); - HRESULT RefreshDisplayType(__in_opt LPSTR szDeviceName); - static BOOL CheckHeaderValidity(const VIDEOINFO *pInput); - static BOOL CheckPaletteHeader(const VIDEOINFO *pInput); - BOOL IsPalettised(); - WORD GetDisplayDepth(); - - // Provide simple video format type checking - - HRESULT CheckMediaType(const CMediaType *pmtIn); - HRESULT CheckVideoType(const VIDEOINFO *pInput); - HRESULT UpdateFormat(__inout VIDEOINFO *pVideoInfo); - const DWORD *GetBitMasks(const VIDEOINFO *pVideoInfo); - - BOOL GetColourMask(__out DWORD *pMaskRed, - __out DWORD *pMaskGreen, - __out DWORD *pMaskBlue); -}; - -// Convert a FORMAT_VideoInfo to FORMAT_VideoInfo2 -STDAPI ConvertVideoInfoToVideoInfo2(__inout AM_MEDIA_TYPE *pmt); - -// Check a media type containing VIDEOINFOHEADER -STDAPI CheckVideoInfoType(const AM_MEDIA_TYPE *pmt); - -// Check a media type containing VIDEOINFOHEADER -STDAPI CheckVideoInfo2Type(const AM_MEDIA_TYPE *pmt); - -#endif // __WINUTIL__ - +//------------------------------------------------------------------------------ +// File: WinUtil.h +// +// Desc: DirectShow base classes - defines generic handler classes. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +// Make sure that you call PrepareWindow to initialise the window after +// the object has been constructed. It is a separate method so that +// derived classes can override useful methods like MessageLoop. Also +// any derived class must call DoneWithWindow in its destructor. If it +// doesn't a message may be retrieved and call a derived class member +// function while a thread is executing the base class destructor code + +#ifndef __WINUTIL__ +#define __WINUTIL__ + +const int DEFWIDTH = 320; // Initial window width +const int DEFHEIGHT = 240; // Initial window height +const int CAPTION = 256; // Maximum length of caption +const int TIMELENGTH = 50; // Maximum length of times +const int PROFILESTR = 128; // Normal profile string +const WORD PALVERSION = 0x300; // GDI palette version +const LONG PALETTE_VERSION = (LONG) 1; // Initial palette version +const COLORREF VIDEO_COLOUR = 0; // Defaults to black background +const HANDLE hMEMORY = (HANDLE) (-1); // Says to open as memory file + +#define WIDTH(x) ((*(x)).right - (*(x)).left) +#define HEIGHT(x) ((*(x)).bottom - (*(x)).top) +#define SHOWSTAGE TEXT("WM_SHOWSTAGE") +#define SHOWSTAGETOP TEXT("WM_SHOWSTAGETOP") +#define REALIZEPALETTE TEXT("WM_REALIZEPALETTE") + +class AM_NOVTABLE CBaseWindow +{ +protected: + + HINSTANCE m_hInstance; // Global module instance handle + HWND m_hwnd; // Handle for our window + HDC m_hdc; // Device context for the window + LONG m_Width; // Client window width + LONG m_Height; // Client window height + BOOL m_bActivated; // Has the window been activated + LPTSTR m_pClassName; // Static string holding class name + DWORD m_ClassStyles; // Passed in to our constructor + DWORD m_WindowStyles; // Likewise the initial window styles + DWORD m_WindowStylesEx; // And the extended window styles + UINT m_ShowStageMessage; // Have the window shown with focus + UINT m_ShowStageTop; // Makes the window WS_EX_TOPMOST + UINT m_RealizePalette; // Makes us realize our new palette + HDC m_MemoryDC; // Used for fast BitBlt operations + HPALETTE m_hPalette; // Handle to any palette we may have + BYTE m_bNoRealize; // Don't realize palette now + BYTE m_bBackground; // Should we realise in background +#ifdef _DEBUG + BYTE m_bRealizing; // already realizing the palette +#endif + CCritSec m_WindowLock; // Serialise window object access + BOOL m_bDoGetDC; // Should this window get a DC + bool m_bDoPostToDestroy; // Use PostMessage to destroy + CCritSec m_PaletteLock; // This lock protects m_hPalette. + // It should be held anytime the + // program use the value of m_hPalette. + + // Maps windows message procedure into C++ methods + friend LRESULT CALLBACK WndProc(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam); // Other parameter + + virtual LRESULT OnPaletteChange(HWND hwnd, UINT Message); + +public: + + CBaseWindow(BOOL bDoGetDC = TRUE, bool bPostToDestroy = false); + +#ifdef _DEBUG + virtual ~CBaseWindow(); +#endif + + virtual HRESULT DoneWithWindow(); + virtual HRESULT PrepareWindow(); + virtual HRESULT InactivateWindow(); + virtual HRESULT ActivateWindow(); + virtual BOOL OnSize(LONG Width, LONG Height); + virtual BOOL OnClose(); + virtual RECT GetDefaultRect(); + virtual HRESULT UninitialiseWindow(); + virtual HRESULT InitialiseWindow(HWND hwnd); + + HRESULT CompleteConnect(); + HRESULT DoCreateWindow(); + + HRESULT PerformanceAlignWindow(); + HRESULT DoShowWindow(LONG ShowCmd); + void PaintWindow(BOOL bErase); + void DoSetWindowForeground(BOOL bFocus); + virtual HRESULT SetPalette(HPALETTE hPalette); + void SetRealize(BOOL bRealize) + { + m_bNoRealize = !bRealize; + } + + // Jump over to the window thread to set the current palette + HRESULT SetPalette(); + void UnsetPalette(void); + virtual HRESULT DoRealisePalette(BOOL bForceBackground = FALSE); + + void LockPaletteLock(); + void UnlockPaletteLock(); + + virtual BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { return FALSE; }; + + // Access our window information + + bool WindowExists(); + LONG GetWindowWidth(); + LONG GetWindowHeight(); + HWND GetWindowHWND(); + HDC GetMemoryHDC(); + HDC GetWindowHDC(); + + #ifdef _DEBUG + HPALETTE GetPalette(); + #endif // DEBUG + + // This is the window procedure the derived object should override + + virtual INT_PTR OnReceiveMessage(HWND hwnd, // Window handle + UINT uMsg, // Message ID + WPARAM wParam, // First parameter + LPARAM lParam); // Other parameter + + // Must be overriden to return class and window styles + + virtual LPTSTR GetClassWindowStyles( + __out DWORD *pClassStyles, // Class styles + __out DWORD *pWindowStyles, // Window styles + __out DWORD *pWindowStylesEx) PURE; // Extended styles +}; + + +// This helper class is entirely subservient to the owning CBaseWindow object +// All this object does is to split out the actual drawing operation from the +// main object (because it was becoming too large). We have a number of entry +// points to set things like the draw device contexts, to implement the actual +// drawing and to set the destination rectangle in the client window. We have +// no critical section locking in this class because we are used exclusively +// by the owning window object which looks after serialising calls into us + +// If you want to use this class make sure you call NotifyAllocator once the +// allocate has been agreed, also call NotifyMediaType with a pointer to a +// NON stack based CMediaType once that has been set (we keep a pointer to +// the original rather than taking a copy). When the palette changes call +// IncrementPaletteVersion (easiest thing to do is to also call this method +// in the SetMediaType method most filters implement). Finally before you +// start rendering anything call SetDrawContext so that we can get the HDCs +// for drawing from the CBaseWindow object we are given during construction + +class CDrawImage +{ +protected: + + CBaseWindow *m_pBaseWindow; // Owning video window object + CRefTime m_StartSample; // Start time for the current sample + CRefTime m_EndSample; // And likewise it's end sample time + HDC m_hdc; // Main window device context + HDC m_MemoryDC; // Offscreen draw device context + RECT m_TargetRect; // Target destination rectangle + RECT m_SourceRect; // Source image rectangle + BOOL m_bStretch; // Do we have to stretch the images + BOOL m_bUsingImageAllocator; // Are the samples shared DIBSECTIONs + CMediaType *m_pMediaType; // Pointer to the current format + int m_perfidRenderTime; // Time taken to render an image + LONG m_PaletteVersion; // Current palette version cookie + + // Draw the video images in the window + + void SlowRender(IMediaSample *pMediaSample); + void FastRender(IMediaSample *pMediaSample); + void DisplaySampleTimes(IMediaSample *pSample); + void UpdateColourTable(HDC hdc,__in BITMAPINFOHEADER *pbmi); + void SetStretchMode(); + +public: + + // Used to control the image drawing + + CDrawImage(__inout CBaseWindow *pBaseWindow); + BOOL DrawImage(IMediaSample *pMediaSample); + BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, + __in LPRECT lprcSrc, __in LPRECT lprcDst); + void SetDrawContext(); + void SetTargetRect(__in RECT *pTargetRect); + void SetSourceRect(__in RECT *pSourceRect); + void GetTargetRect(__out RECT *pTargetRect); + void GetSourceRect(__out RECT *pSourceRect); + virtual RECT ScaleSourceRect(const RECT *pSource); + + // Handle updating palettes as they change + + LONG GetPaletteVersion(); + void ResetPaletteVersion(); + void IncrementPaletteVersion(); + + // Tell us media types and allocator assignments + + void NotifyAllocator(BOOL bUsingImageAllocator); + void NotifyMediaType(__in CMediaType *pMediaType); + BOOL UsingImageAllocator(); + + // Called when we are about to draw an image + + void NotifyStartDraw() { + MSR_START(m_perfidRenderTime); + }; + + // Called when we complete an image rendering + + void NotifyEndDraw() { + MSR_STOP(m_perfidRenderTime); + }; +}; + + +// This is the structure used to keep information about each GDI DIB. All the +// samples we create from our allocator will have a DIBSECTION allocated to +// them. When we receive the sample we know we can BitBlt straight to an HDC + +typedef struct tagDIBDATA { + + LONG PaletteVersion; // Current palette version in use + DIBSECTION DibSection; // Details of DIB section allocated + HBITMAP hBitmap; // Handle to bitmap for drawing + HANDLE hMapping; // Handle to shared memory block + BYTE *pBase; // Pointer to base memory address + +} DIBDATA; + + +// This class inherits from CMediaSample and uses all of it's methods but it +// overrides the constructor to initialise itself with the DIBDATA structure +// When we come to render an IMediaSample we will know if we are using our own +// allocator, and if we are, we can cast the IMediaSample to a pointer to one +// of these are retrieve the DIB section information and hence the HBITMAP + +class CImageSample : public CMediaSample +{ +protected: + + DIBDATA m_DibData; // Information about the DIBSECTION + BOOL m_bInit; // Is the DIB information setup + +public: + + // Constructor + + CImageSample(__inout CBaseAllocator *pAllocator, + __in_opt LPCTSTR pName, + __inout HRESULT *phr, + __in_bcount(length) LPBYTE pBuffer, + LONG length); + + // Maintain the DIB/DirectDraw state + + void SetDIBData(__in DIBDATA *pDibData); + __out DIBDATA *GetDIBData(); +}; + + +// This is an allocator based on the abstract CBaseAllocator base class that +// allocates sample buffers in shared memory. The number and size of these +// are determined when the output pin calls Prepare on us. The shared memory +// blocks are used in subsequent calls to GDI CreateDIBSection, once that +// has been done the output pin can fill the buffers with data which will +// then be handed to GDI through BitBlt calls and thereby remove one copy + +class CImageAllocator : public CBaseAllocator +{ +protected: + + CBaseFilter *m_pFilter; // Delegate reference counts to + CMediaType *m_pMediaType; // Pointer to the current format + + // Used to create and delete samples + + HRESULT Alloc(); + void Free(); + + // Manage the shared DIBSECTION and DCI/DirectDraw buffers + + HRESULT CreateDIB(LONG InSize,DIBDATA &DibData); + STDMETHODIMP CheckSizes(__in ALLOCATOR_PROPERTIES *pRequest); + virtual CImageSample *CreateImageSample(__in_bcount(Length) LPBYTE pData,LONG Length); + +public: + + // Constructor and destructor + + CImageAllocator(__inout CBaseFilter *pFilter,__in_opt LPCTSTR pName,__inout HRESULT *phr); +#ifdef _DEBUG + ~CImageAllocator(); +#endif + + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + void NotifyMediaType(__in CMediaType *pMediaType); + + // Agree the number of buffers to be used and their size + + STDMETHODIMP SetProperties( + __in ALLOCATOR_PROPERTIES *pRequest, + __out ALLOCATOR_PROPERTIES *pActual); +}; + + +// This class is a fairly specialised helper class for image renderers that +// have to create and manage palettes. The CBaseWindow class looks after +// realising palettes once they have been installed. This class can be used +// to create the palette handles from a media format (which must contain a +// VIDEOINFO structure in the format block). We try to make the palette an +// identity palette to maximise performance and also only change palettes +// if actually required to (we compare palette colours before updating). +// All the methods are virtual so that they can be overriden if so required + +class CImagePalette +{ +protected: + + CBaseWindow *m_pBaseWindow; // Window to realise palette in + CBaseFilter *m_pFilter; // Media filter to send events + CDrawImage *m_pDrawImage; // Object who will be drawing + HPALETTE m_hPalette; // The palette handle we own + +public: + + CImagePalette(__inout CBaseFilter *pBaseFilter, + __inout CBaseWindow *pBaseWindow, + __inout CDrawImage *pDrawImage); + +#ifdef _DEBUG + virtual ~CImagePalette(); +#endif + + static HPALETTE MakePalette(const VIDEOINFOHEADER *pVideoInfo, __in LPSTR szDevice); + HRESULT RemovePalette(); + static HRESULT MakeIdentityPalette(__inout_ecount_full(iColours) PALETTEENTRY *pEntry,INT iColours, __in LPSTR szDevice); + HRESULT CopyPalette(const CMediaType *pSrc,__out CMediaType *pDest); + BOOL ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,const VIDEOINFOHEADER *pOldInfo); + HRESULT PreparePalette(const CMediaType *pmtNew,const CMediaType *pmtOld,__in LPSTR szDevice); + + BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, __in LPRECT lprcSrc, __in LPRECT lprcDst) + { + return m_pDrawImage->DrawVideoImageHere(hdc, pMediaSample, lprcSrc,lprcDst); + } +}; + + +// Another helper class really for video based renderers. Most such renderers +// need to know what the display format is to some degree or another. This +// class initialises itself with the display format. The format can be asked +// for through GetDisplayFormat and various other accessor functions. If a +// filter detects a display format change (perhaps it gets a WM_DEVMODECHANGE +// message then it can call RefreshDisplayType to reset that format). Also +// many video renderers will want to check formats as they are proposed by +// source filters. This class provides methods to check formats and only +// accept those video formats that can be efficiently drawn using GDI calls + +class CImageDisplay : public CCritSec +{ +protected: + + // This holds the display format; biSize should not be too big, so we can + // safely use the VIDEOINFO structure + VIDEOINFO m_Display; + + static DWORD CountSetBits(const DWORD Field); + static DWORD CountPrefixBits(const DWORD Field); + static BOOL CheckBitFields(const VIDEOINFO *pInput); + +public: + + // Constructor and destructor + + CImageDisplay(); + + // Used to manage BITMAPINFOHEADERs and the display format + + const VIDEOINFO *GetDisplayFormat(); + HRESULT RefreshDisplayType(__in_opt LPSTR szDeviceName); + static BOOL CheckHeaderValidity(const VIDEOINFO *pInput); + static BOOL CheckPaletteHeader(const VIDEOINFO *pInput); + BOOL IsPalettised(); + WORD GetDisplayDepth(); + + // Provide simple video format type checking + + HRESULT CheckMediaType(const CMediaType *pmtIn); + HRESULT CheckVideoType(const VIDEOINFO *pInput); + HRESULT UpdateFormat(__inout VIDEOINFO *pVideoInfo); + const DWORD *GetBitMasks(const VIDEOINFO *pVideoInfo); + + BOOL GetColourMask(__out DWORD *pMaskRed, + __out DWORD *pMaskGreen, + __out DWORD *pMaskBlue); +}; + +// Convert a FORMAT_VideoInfo to FORMAT_VideoInfo2 +STDAPI ConvertVideoInfoToVideoInfo2(__inout AM_MEDIA_TYPE *pmt); + +// Check a media type containing VIDEOINFOHEADER +STDAPI CheckVideoInfoType(const AM_MEDIA_TYPE *pmt); + +// Check a media type containing VIDEOINFOHEADER +STDAPI CheckVideoInfo2Type(const AM_MEDIA_TYPE *pmt); + +#endif // __WINUTIL__ + diff --git a/src/thirdparty/BaseClasses/wxdebug.cpp b/src/thirdparty/BaseClasses/wxdebug.cpp index 7bdfe75055a..410900484fd 100644 --- a/src/thirdparty/BaseClasses/wxdebug.cpp +++ b/src/thirdparty/BaseClasses/wxdebug.cpp @@ -1,1475 +1,1475 @@ -//------------------------------------------------------------------------------ -// File: WXDebug.cpp -// -// Desc: DirectShow base classes - implements ActiveX system debugging -// facilities. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -//#define _WINDLL - -#include "streams.h" -#include -#include -#include - -#ifdef _DEBUG -#ifdef UNICODE -#ifndef _UNICODE -#define _UNICODE -#endif // _UNICODE -#endif // UNICODE -#endif // DEBUG - -#include -#include - -#ifdef _DEBUG -static void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi); -static void DisplayRECT(LPCTSTR szLabel, const RECT& rc); - -// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. -// See the documentation for wsprintf()'s lpOut parameter for more information. -const INT iDEBUGINFO = 1024; // Used to format strings - -/* For every module and executable we store a debugging level for each of - the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy - to isolate and debug individual modules without seeing everybody elses - spurious debug output. The keys are stored in the registry under the - HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\ key values - NOTE these must be in the same order as their enumeration definition */ - -const LPCTSTR pKeyNames[] = { - TEXT("TIMING"), // Timing and performance measurements - TEXT("TRACE"), // General step point call tracing - TEXT("MEMORY"), // Memory and object allocation/destruction - TEXT("LOCKING"), // Locking/unlocking of critical sections - TEXT("ERROR"), // Debug error notification - TEXT("CUSTOM1"), - TEXT("CUSTOM2"), - TEXT("CUSTOM3"), - TEXT("CUSTOM4"), - TEXT("CUSTOM5") - }; - -const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s"); -const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s"); - -const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories - -HINSTANCE m_hInst; // Module instance handle -TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name -DWORD m_Levels[iMAXLEVELS]; // Debug level per category -CRITICAL_SECTION m_CSDebug; // Controls access to list -DWORD m_dwNextCookie; // Next active object ID -ObjectDesc *pListHead = NULL; // First active object -DWORD m_dwObjectCount; // Active object count -BOOL m_bInit = FALSE; // Have we been initialised -HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here -DWORD dwWaitTimeout = INFINITE; // Default timeout value -DWORD dwTimeOffset; // Time of first DbgLog call -bool g_fUseKASSERT = false; // don't create messagebox -bool g_fDbgInDllEntryPoint = false; -bool g_fAutoRefreshLevels = false; - -LPCTSTR pBaseKey = TEXT("SOFTWARE\\Microsoft\\DirectShow\\Debug"); -LPCTSTR pGlobalKey = TEXT("GLOBAL"); -static LPCSTR pUnknownName = "UNKNOWN"; - -LPCTSTR TimeoutName = TEXT("TIMEOUT"); - -/* This sets the instance handle that the debug library uses to find - the module's file name from the Win32 GetModuleFileName function */ - -void WINAPI DbgInitialise(HINSTANCE hInst) -{ - InitializeCriticalSection(&m_CSDebug); - m_bInit = TRUE; - - m_hInst = hInst; - DbgInitModuleName(); - if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0)) - DebugBreak(); - DbgInitModuleSettings(false); - DbgInitGlobalSettings(true); - dwTimeOffset = timeGetTime(); -} - - -/* This is called to clear up any resources the debug library uses - at the - moment we delete our critical section and the object list. The values we - retrieve from the registry are all done during initialisation but we don't - go looking for update notifications while we are running, if the values - are changed then the application has to be restarted to pick them up */ - -void WINAPI DbgTerminate() -{ - if (m_hOutput != INVALID_HANDLE_VALUE) { - EXECUTE_ASSERT(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - DeleteCriticalSection(&m_CSDebug); - m_bInit = FALSE; -} - - -/* This is called by DbgInitLogLevels to read the debug settings - for each logging category for this module from the registry */ - -void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax) -{ - LONG lReturn; // Create key return value - LONG lKeyPos; // Current key category - DWORD dwKeySize; // Size of the key value - DWORD dwKeyType; // Receives it's type - DWORD dwKeyValue; // This fields value - - /* Try and read a value for each key position in turn */ - for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) { - - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[lKeyPos], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) &dwKeyValue, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - /* If either the key was not available or it was not a DWORD value - then we ensure only the high priority debug logging is output - but we try and update the field to a zero filled DWORD value */ - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { - - dwKeyValue = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[lKeyPos], // Address of subkey name - (DWORD) 0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE) &dwKeyValue, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); - dwKeyValue = 0; - } - } - if(fTakeMax) - { - m_Levels[lKeyPos] = std::max(dwKeyValue, m_Levels[lKeyPos]); - } - else - { - if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) { - m_Levels[lKeyPos] = dwKeyValue; - } - } - } - - /* Read the timeout value for catching hangs */ - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - TimeoutName, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) &dwWaitTimeout, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - /* If either the key was not available or it was not a DWORD value - then we ensure only the high priority debug logging is output - but we try and update the field to a zero filled DWORD value */ - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { - - dwWaitTimeout = INFINITE; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - TimeoutName, // Address of subkey name - (DWORD) 0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE) &dwWaitTimeout, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); - dwWaitTimeout = INFINITE; - } - } -} - -void WINAPI DbgOutString(LPCTSTR psz) -{ - if (m_hOutput != INVALID_HANDLE_VALUE) { - UINT cb = lstrlen(psz); - DWORD dw; -#ifdef UNICODE - CHAR szDest[2048]; - WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0); - WriteFile (m_hOutput, szDest, cb, &dw, NULL); -#else - WriteFile (m_hOutput, psz, cb, &dw, NULL); -#endif - } else { - OutputDebugString (psz); - } -} - - - - -HRESULT DbgUniqueProcessName(LPCTSTR inName, LPTSTR outName) -{ - HRESULT hr = S_OK; - const TCHAR *pIn = inName; - int dotPos = -1; - - //scan the input and record the last '.' position - while (*pIn && (pIn - inName) < MAX_PATH) - { - if ( TEXT('.') == *pIn ) - dotPos = (int)(pIn-inName); - ++pIn; - } - - if (*pIn) //input should be zero-terminated within MAX_PATH - return E_INVALIDARG; - - DWORD dwProcessId = GetCurrentProcessId(); - - if (dotPos < 0) - { - //no extension in the input, appending process id to the input - hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d"), inName, dwProcessId); - } - else - { - TCHAR pathAndBasename[MAX_PATH] = {0}; - - //there's an extension - zero-terminate the path and basename first by copying - hr = StringCchCopyN(pathAndBasename, MAX_PATH, inName, (size_t)dotPos); - - //re-combine path, basename and extension with processId appended to a basename - if (SUCCEEDED(hr)) - hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d%s"), pathAndBasename, dwProcessId, inName + dotPos); - } - - return hr; -} - - -/* Called by DbgInitGlobalSettings to setup alternate logging destinations - */ - -void WINAPI DbgInitLogTo ( - HKEY hKey) -{ - LONG lReturn; - DWORD dwKeyType; - DWORD dwKeySize; - TCHAR szFile[MAX_PATH] = {0}; - static const TCHAR cszKey[] = TEXT("LogToFile"); - - dwKeySize = MAX_PATH; - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - cszKey, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) szFile, // Returns the field's value - &dwKeySize); // Number of bytes transferred - - // create an empty key if it does not already exist - // - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) - { - dwKeySize = sizeof(TCHAR); - lReturn = RegSetValueEx( - hKey, // Handle of an open key - cszKey, // Address of subkey name - (DWORD) 0, // Reserved field - REG_SZ, // Type of the key field - (PBYTE)szFile, // Value for the field - dwKeySize); // Size of the field buffer - } - - // if an output-to was specified. try to open it. - // - if (m_hOutput != INVALID_HANDLE_VALUE) { - EXECUTE_ASSERT(CloseHandle (m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - if (szFile[0] != 0) - { - if (!lstrcmpi(szFile, TEXT("Console"))) { - m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); - if (m_hOutput == INVALID_HANDLE_VALUE) { - AllocConsole (); - m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); - } - SetConsoleTitle (TEXT("ActiveX Debug Output")); - } else if (szFile[0] && - lstrcmpi(szFile, TEXT("Debug")) && - lstrcmpi(szFile, TEXT("Debugger")) && - lstrcmpi(szFile, TEXT("Deb"))) - { - m_hOutput = CreateFile(szFile, GENERIC_WRITE, - FILE_SHARE_READ, - NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (INVALID_HANDLE_VALUE == m_hOutput && - GetLastError() == ERROR_SHARING_VIOLATION) - { - TCHAR uniqueName[MAX_PATH] = {0}; - if (SUCCEEDED(DbgUniqueProcessName(szFile, uniqueName))) - { - m_hOutput = CreateFile(uniqueName, GENERIC_WRITE, - FILE_SHARE_READ, - NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - } - } - - if (INVALID_HANDLE_VALUE != m_hOutput) - { - static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); - LARGE_INTEGER zero = {0, 0}; - SetFilePointerEx(m_hOutput, zero, NULL, FILE_END); - DbgOutString (cszBar); - } - } - } -} - - - -/* This is called by DbgInitLogLevels to read the global debug settings for - each logging category for this module from the registry. Normally each - module has it's own values set for it's different debug categories but - setting the global SOFTWARE\Debug\Global applies them to ALL modules */ - -void WINAPI DbgInitGlobalSettings(bool fTakeMax) -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hGlobalKey; // Global override key - - /* Construct the global base key name */ - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey); - - /* Create or open the key for this module */ - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - GENERIC_READ | GENERIC_WRITE, // Desired security access - NULL, // Key security descriptor - &hGlobalKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) { - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - GENERIC_READ, // Desired security access - NULL, // Key security descriptor - &hGlobalKey, // Opened handle buffer - NULL); // What really happened - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,1,TEXT("Could not access GLOBAL module key"))); - } - return; - } - - DbgInitKeyLevels(hGlobalKey, fTakeMax); - RegCloseKey(hGlobalKey); -} - - -/* This sets the debugging log levels for the different categories. We start - by opening (or creating if not already available) the SOFTWARE\Debug key - that all these settings live under. We then look at the global values - set under SOFTWARE\Debug\Global which apply on top of the individual - module settings. We then load the individual module registry settings */ - -void WINAPI DbgInitModuleSettings(bool fTakeMax) -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hModuleKey; // Module key handle - - /* Construct the base key name */ - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,m_ModuleName); - - /* Create or open the key for this module */ - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - GENERIC_READ | GENERIC_WRITE, // Desired security access - NULL, // Key security descriptor - &hModuleKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) { - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD) 0, // Reserved value - NULL, // Address of class name - (DWORD) 0, // Special options flags - GENERIC_READ, // Desired security access - NULL, // Key security descriptor - &hModuleKey, // Opened handle buffer - NULL); // What really happened - if (lReturn != ERROR_SUCCESS) { - DbgLog((LOG_ERROR,1,TEXT("Could not access module key"))); - } - return; - } - - DbgInitLogTo(hModuleKey); - DbgInitKeyLevels(hModuleKey, fTakeMax); - RegCloseKey(hModuleKey); -} - - -/* Initialise the module file name */ - -void WINAPI DbgInitModuleName() -{ - TCHAR FullName[iDEBUGINFO]; // Load the full path and module name - LPTSTR pName; // Searches from the end for a backslash - - GetModuleFileName(m_hInst,FullName,iDEBUGINFO); - pName = _tcsrchr(FullName,'\\'); - if (pName == NULL) { - pName = FullName; - } else { - pName++; - } - (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName); -} - -struct MsgBoxMsg -{ - HWND hwnd; - LPCTSTR szTitle; - LPCTSTR szMessage; - DWORD dwFlags; - INT iResult; -}; - -// -// create a thread to call MessageBox(). calling MessageBox() on -// random threads at bad times can confuse the host (eg IE). -// -DWORD WINAPI MsgBoxThread( - __inout LPVOID lpParameter // thread data - ) -{ - MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter; - pmsg->iResult = MessageBox( - pmsg->hwnd, - pmsg->szTitle, - pmsg->szMessage, - pmsg->dwFlags); - - return 0; -} - -INT MessageBoxOtherThread( - HWND hwnd, - LPCTSTR szTitle, - LPCTSTR szMessage, - DWORD dwFlags) -{ - if(g_fDbgInDllEntryPoint) - { - // can't wait on another thread because we have the loader - // lock held in the dll entry point. - // This can crash sometimes so just skip it - // return MessageBox(hwnd, szTitle, szMessage, dwFlags); - return IDCANCEL; - } - else - { - MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0}; - DWORD dwid; - HANDLE hThread = CreateThread( - 0, // security - 0, // stack size - MsgBoxThread, - (void *)&msg, // arg - 0, // flags - &dwid); - if(hThread) - { - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - return msg.iResult; - } - - // break into debugger on failure. - return IDCANCEL; - } -} - -/* Displays a message box if the condition evaluated to FALSE */ - -void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine) -{ - if(g_fUseKASSERT) - { - DbgKernelAssert(pCondition, pFileName, iLine); - } - else - { - - TCHAR szInfo[iDEBUGINFO]; - - (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), - pCondition, iLine, pFileName); - - INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"), - MB_SYSTEMMODAL | - MB_ICONHAND | - MB_YESNOCANCEL | - MB_SETFOREGROUND); - switch (MsgId) - { - case IDNO: /* Kill the application */ - - FatalAppExit(FALSE, TEXT("Application terminated")); - break; - - case IDCANCEL: /* Break into the debugger */ - - DebugBreak(); - break; - - case IDYES: /* Ignore assertion continue execution */ - break; - } - } -} - -/* Displays a message box at a break point */ - -void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine) -{ - if(g_fUseKASSERT) - { - DbgKernelAssert(pCondition, pFileName, iLine); - } - else - { - TCHAR szInfo[iDEBUGINFO]; - - (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), - pCondition, iLine, pFileName); - - INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"), - MB_SYSTEMMODAL | - MB_ICONHAND | - MB_YESNOCANCEL | - MB_SETFOREGROUND); - switch (MsgId) - { - case IDNO: /* Kill the application */ - - FatalAppExit(FALSE, TEXT("Application terminated")); - break; - - case IDCANCEL: /* Break into the debugger */ - - DebugBreak(); - break; - - case IDYES: /* Ignore break point continue execution */ - break; - } - } -} - -void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...) -{ - // A debug break point message can have at most 2000 characters if - // ANSI or UNICODE characters are being used. A debug break point message - // can have between 1000 and 2000 double byte characters in it. If a - // particular message needs more characters, then the value of this constant - // should be increased. - const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000; - - TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE]; - - va_list va; - va_start( va, szFormatString ); - - HRESULT hr = StringCchVPrintf( szBreakPointMessage, NUMELMS(szBreakPointMessage), szFormatString, va ); - - va_end(va); - - if( FAILED(hr) ) { - DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because StringCchVPrintf() failed." ); - return; - } - - ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine ); -} - - -/* When we initialised the library we stored in the m_Levels array the current - debug output level for this module for each of the five categories. When - some debug logging is sent to us it can be sent with a combination of the - categories (if it is applicable to many for example) in which case we map - the type's categories into their current debug levels and see if any of - them can be accepted. The function looks at each bit position in turn from - the input type field and then compares it's debug level with the modules. - - A level of 0 means that output is always sent to the debugger. This is - due to producing output if the input level is <= m_Levels. -*/ - - -BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level) -{ - if(g_fAutoRefreshLevels) - { - // re-read the registry every second. We cannot use RegNotify() to - // notice registry changes because it's not available on win9x. - static DWORD g_dwLastRefresh = 0; - DWORD dwTime = timeGetTime(); - if(dwTime - g_dwLastRefresh > 1000) { - g_dwLastRefresh = dwTime; - - // there's a race condition: multiple threads could update the - // values. plus read and write not synchronized. no harm - // though. - DbgInitModuleSettings(false); - } - } - - - DWORD Mask = 0x01; - - // If no valid bits are set return FALSE - if ((Type & ((1<m_szName = szObjectName; - pObject->m_wszName = wszObjectName; - pObject->m_dwCookie = ++m_dwNextCookie; - pObject->m_pNext = pListHead; - - pListHead = pObject; - m_dwObjectCount++; - - DWORD ObjectCookie = pObject->m_dwCookie; - ASSERT(ObjectCookie); - - if(wszObjectName) { - DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"), - pObject->m_dwCookie, wszObjectName, m_dwObjectCount)); - } else { - DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"), - pObject->m_dwCookie, szObjectName, m_dwObjectCount)); - } - - LeaveCriticalSection(&m_CSDebug); - return ObjectCookie; -} - - -/* This is called by the CBaseObject destructor when an object is about to be - destroyed, we are passed the cookie we returned during construction that - identifies this object. We scan the object list for a matching cookie and - remove the object if successful. We also update the active object count */ - -BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie) -{ - /* Grab the list critical section */ - EnterCriticalSection(&m_CSDebug); - - ObjectDesc *pObject = pListHead; - ObjectDesc *pPrevious = NULL; - - /* Scan the object list looking for a cookie match */ - - while (pObject) { - if (pObject->m_dwCookie == dwCookie) { - break; - } - pPrevious = pObject; - pObject = pObject->m_pNext; - } - - if (pObject == NULL) { - DbgBreak("Apparently destroying a bogus object"); - LeaveCriticalSection(&m_CSDebug); - return FALSE; - } - - /* Is the object at the head of the list */ - - if (pPrevious == NULL) { - pListHead = pObject->m_pNext; - } else { - pPrevious->m_pNext = pObject->m_pNext; - } - - /* Delete the object and update the housekeeping information */ - - m_dwObjectCount--; - - if(pObject->m_wszName) { - DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"), - pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount)); - } else { - DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"), - pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount)); - } - - delete pObject; - LeaveCriticalSection(&m_CSDebug); - return TRUE; -} - - -/* This runs through the active object list displaying their details */ - -void WINAPI DbgDumpObjectRegister() -{ - TCHAR szInfo[iDEBUGINFO]; - - /* Grab the list critical section */ - - EnterCriticalSection(&m_CSDebug); - ObjectDesc *pObject = pListHead; - - /* Scan the object list displaying the name and cookie */ - - DbgLog((LOG_MEMORY,2,TEXT(""))); - DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description"))); - DbgLog((LOG_MEMORY,2,TEXT(""))); - - while (pObject) { - if(pObject->m_wszName) { - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30ls"),pObject->m_dwCookie, &pObject, pObject->m_wszName); - } else { - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30hs"),pObject->m_dwCookie, &pObject, pObject->m_szName); - } - DbgLog((LOG_MEMORY,2,szInfo)); - pObject = pObject->m_pNext; - } - - (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount); - DbgLog((LOG_MEMORY,2,TEXT(""))); - DbgLog((LOG_MEMORY,1,szInfo)); - LeaveCriticalSection(&m_CSDebug); -} - -/* Debug infinite wait stuff */ -DWORD WINAPI DbgWaitForSingleObject(HANDLE h) -{ - DWORD dwWaitResult; - do { - dwWaitResult = WaitForSingleObject(h, dwWaitTimeout); - ASSERT(dwWaitResult == WAIT_OBJECT_0); - } while (dwWaitResult == WAIT_TIMEOUT); - return dwWaitResult; -} -DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, - __in_ecount(nCount) CONST HANDLE *lpHandles, - BOOL bWaitAll) -{ - DWORD dwWaitResult; - do { - dwWaitResult = WaitForMultipleObjects(nCount, - lpHandles, - bWaitAll, - dwWaitTimeout); - ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS); - } while (dwWaitResult == WAIT_TIMEOUT); - return dwWaitResult; -} - -void WINAPI DbgSetWaitTimeout(DWORD dwTimeout) -{ - dwWaitTimeout = dwTimeout; -} - -#endif /* DEBUG */ - -#ifdef _OBJBASE_H_ - - /* Stuff for printing out our GUID names */ - - constexpr GUID_STRING_ENTRY g_GuidNames[] = { - #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } }, - #include - }; - - CGuidNameList GuidNames; - int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]); - - LPCSTR CGuidNameList::operator [] (const GUID &guid) - { - for (int i = 0; i < g_cGuidNames; i++) { - if (g_GuidNames[i].guid == guid) { - return g_GuidNames[i].szName; - } - } - if (guid == GUID_NULL) { - return "GUID_NULL"; - } - - // !!! add something to print FOURCC guids? - - // shouldn't this print the hex CLSID? - return "Unknown GUID Name"; - } - -#endif /* _OBJBASE_H_ */ - -/* CDisp class - display our data types */ - -// clashes with REFERENCE_TIME -CDisp::CDisp(LONGLONG ll, int Format) -{ - // note: this could be combined with CDisp(LONGLONG) by - // introducing a default format of CDISP_REFTIME - LARGE_INTEGER li; - li.QuadPart = ll; - switch (Format) { - case CDISP_DEC: - { - TCHAR temp[20]; - int pos=20; - temp[--pos] = 0; - int digit; - // always output at least one digit - do { - // Get the rightmost digit - we only need the low word - digit = li.LowPart % 10; - li.QuadPart /= 10; - temp[--pos] = (TCHAR) digit+L'0'; - } while (li.QuadPart); - (void)StringCchCopy(m_String, NUMELMS(m_String), temp+pos); - break; - } - case CDISP_HEX: - default: - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart); - } -}; - -CDisp::CDisp(REFCLSID clsid) -{ -#ifdef UNICODE - (void)StringFromGUID2(clsid, m_String, NUMELMS(m_String)); -#else - WCHAR wszTemp[50]; - (void)StringFromGUID2(clsid, wszTemp, NUMELMS(wszTemp)); - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), wszTemp); -#endif -}; - -#ifdef __STREAMS__ -/* Display stuff */ -CDisp::CDisp(CRefTime llTime) -{ - LONGLONG llDiv; - if (llTime < 0) { - llTime = -llTime; - (void)StringCchCopy(m_String, NUMELMS(m_String), TEXT("-")); - } - llDiv = (LONGLONG)24 * 3600 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d days "), (LONG)(llTime / llDiv)); - llTime = llTime % llDiv; - } - llDiv = (LONGLONG)3600 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d hrs "), (LONG)(llTime / llDiv)); - llTime = llTime % llDiv; - } - llDiv = (LONGLONG)60 * 10000000; - if (llTime >= llDiv) { - (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d mins "), (LONG)(llTime / llDiv)); - llTime = llTime % llDiv; - } - (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d.%3.3d sec"), - (LONG)llTime / 10000000, - (LONG)((llTime % 10000000) / 10000)); -}; - -#endif // __STREAMS__ - - -/* Display pin */ -CDisp::CDisp(IPin *pPin) -{ - PIN_INFO pi; - TCHAR str[MAX_PIN_NAME]; - CLSID clsid; - - if (pPin) { - pPin->QueryPinInfo(&pi); - pi.pFilter->GetClassID(&clsid); - QueryPinInfoReleaseFilter(pi); - #ifndef UNICODE - WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1, - str, MAX_PIN_NAME, NULL, NULL); - #else - (void)StringCchCopy(str, NUMELMS(str), pi.achName); - #endif - } else { - (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin")); - } - - m_pString = (PTCHAR) new TCHAR[lstrlen(str)+64]; - if (!m_pString) { - return; - } - - (void)StringCchPrintf(m_pString, lstrlen(str) + 64, TEXT("%hs(%s)"), GuidNames[clsid], str); -} - -/* Display filter or pin */ -CDisp::CDisp(IUnknown *pUnk) -{ - IBaseFilter *pf; - HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf); - if(SUCCEEDED(hr)) - { - FILTER_INFO fi; - hr = pf->QueryFilterInfo(&fi); - if(SUCCEEDED(hr)) - { - QueryFilterInfoReleaseGraph(fi); - - size_t len = lstrlenW(fi.achName) + 1; - - m_pString = new TCHAR[len]; - if(m_pString) - { -#ifdef UNICODE - (void)StringCchCopy(m_pString, len, fi.achName); -#else - (void)StringCchPrintf(m_pString, len, "%S", fi.achName); -#endif - } - } - - pf->Release(); - - return; - } - - IPin *pp; - hr = pUnk->QueryInterface(IID_IPin, (void **)&pp); - if(SUCCEEDED(hr)) - { - CDisp::CDisp(pp); - pp->Release(); - return; - } -} - - -CDisp::~CDisp() -{ -} - -CDispBasic::~CDispBasic() -{ - if (m_pString != m_String) { - delete [] m_pString; - } -} - -CDisp::CDisp(double d) -{ - (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000)); -} - - -/* If built for debug this will display the media type details. We convert the - major and subtypes into strings and also ask the base classes for a string - description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit - We also display the fields in the BITMAPINFOHEADER structure, this should - succeed as we do not accept input types unless the format is big enough */ - -#ifdef _DEBUG -void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn) -{ - - /* Dump the GUID types and a short description */ - - DbgLog((LOG_TRACE,5,TEXT(""))); - DbgLog((LOG_TRACE,2,TEXT("%s M type %hs S type %hs"), label, - GuidNames[pmtIn->majortype], - GuidNames[pmtIn->subtype])); - DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype))); - - /* Dump the generic media types */ - - if (pmtIn->bTemporalCompression) { - DbgLog((LOG_TRACE,5,TEXT("Temporally compressed"))); - } else { - DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed"))); - } - - if (pmtIn->bFixedSizeSamples) { - DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize)); - } else { - DbgLog((LOG_TRACE,5,TEXT("Variable size samples"))); - } - - if (pmtIn->formattype == FORMAT_VideoInfo) { - - VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat; - - DisplayRECT(TEXT("Source rectangle"),pVideoInfo->rcSource); - DisplayRECT(TEXT("Target rectangle"),pVideoInfo->rcTarget); - DisplayBITMAPINFO(HEADER(pmtIn->pbFormat)); - - } if (pmtIn->formattype == FORMAT_VideoInfo2) { - - VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pmtIn->pbFormat; - - DisplayRECT(TEXT("Source rectangle"),pVideoInfo2->rcSource); - DisplayRECT(TEXT("Target rectangle"),pVideoInfo2->rcTarget); - DbgLog((LOG_TRACE, 5, TEXT("Aspect Ratio: %d:%d"), - pVideoInfo2->dwPictAspectRatioX, - pVideoInfo2->dwPictAspectRatioY)); - DisplayBITMAPINFO(&pVideoInfo2->bmiHeader); - - } else if (pmtIn->majortype == MEDIATYPE_Audio) { - DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), - GuidNames[pmtIn->formattype])); - DbgLog((LOG_TRACE,2,TEXT(" Subtype %hs"), - GuidNames[pmtIn->subtype])); - - if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet) - && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT))) - { - /* Dump the contents of the WAVEFORMATEX type-specific format structure */ - - WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat; - DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag)); - DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels)); - DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec)); - DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec)); - DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign)); - DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample)); - - /* PCM uses a WAVEFORMAT and does not have the extra size field */ - - if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) { - DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize)); - } - } else { - } - - } else { - DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), - GuidNames[pmtIn->formattype])); - } -} - - -void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi) -{ - DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize)); - if (pbmi->biCompression < 256) { - DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit (%d)"), - pbmi->biWidth, pbmi->biHeight, - pbmi->biBitCount, pbmi->biCompression)); - } else { - DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"), - pbmi->biWidth, pbmi->biHeight, - pbmi->biBitCount, &pbmi->biCompression)); - } - - DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage)); - DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes)); - DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter)); - DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter)); - DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed)); -} - - -void DisplayRECT(LPCTSTR szLabel, const RECT& rc) -{ - DbgLog((LOG_TRACE,5,TEXT("%s (Left %d Top %d Right %d Bottom %d)"), - szLabel, - rc.left, - rc.top, - rc.right, - rc.bottom)); -} - - -void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel) -{ - if( !pGraph ) - { - return; - } - - IEnumFilters *pFilters; - - DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph)); - - if (FAILED(pGraph->EnumFilters(&pFilters))) { - DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!"))); - } - - IBaseFilter *pFilter; - ULONG n; - while (pFilters->Next(1, &pFilter, &n) == S_OK) { - FILTER_INFO info; - - if (FAILED(pFilter->QueryFilterInfo(&info))) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] -- failed QueryFilterInfo"), pFilter)); - } else { - QueryFilterInfoReleaseGraph(info); - - // !!! should QueryVendorInfo here! - - DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] '%ls'"), pFilter, info.achName)); - - IEnumPins *pins; - - if (FAILED(pFilter->EnumPins(&pins))) { - DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!"))); - } else { - - IPin *pPin; - while (pins->Next(1, &pPin, &n) == S_OK) { - PIN_INFO pinInfo; - - if (FAILED(pPin->QueryPinInfo(&pinInfo))) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin)); - } else { - QueryPinInfoReleaseFilter(pinInfo); - - IPin *pPinConnected = NULL; - - HRESULT hr = pPin->ConnectedTo(&pPinConnected); - - if (pPinConnected) { - DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%p] '%ls' [%sput]") - TEXT(" Connected to pin [%p]"), - pPin, pinInfo.achName, - pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"), - pPinConnected)); - - pPinConnected->Release(); - - // perhaps we should really dump the type both ways as a sanity - // check? - if (pinInfo.dir == PINDIR_OUTPUT) { - AM_MEDIA_TYPE mt; - - hr = pPin->ConnectionMediaType(&mt); - - if (SUCCEEDED(hr)) { - DisplayType(TEXT("Connection type"), &mt); - - FreeMediaType(mt); - } - } - } else { - DbgLog((LOG_TRACE,dwLevel, - TEXT(" Pin [%x] '%ls' [%sput]"), - pPin, pinInfo.achName, - pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"))); - - } - } - - pPin->Release(); - - } - - pins->Release(); - } - - } - - pFilter->Release(); - } - - pFilters->Release(); - -} - -#endif - +//------------------------------------------------------------------------------ +// File: WXDebug.cpp +// +// Desc: DirectShow base classes - implements ActiveX system debugging +// facilities. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +//#define _WINDLL + +#include "streams.h" +#include +#include +#include + +#ifdef _DEBUG +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif // _UNICODE +#endif // UNICODE +#endif // DEBUG + +#include +#include + +#ifdef _DEBUG +static void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi); +static void DisplayRECT(LPCTSTR szLabel, const RECT& rc); + +// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer. +// See the documentation for wsprintf()'s lpOut parameter for more information. +const INT iDEBUGINFO = 1024; // Used to format strings + +/* For every module and executable we store a debugging level for each of + the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy + to isolate and debug individual modules without seeing everybody elses + spurious debug output. The keys are stored in the registry under the + HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\ key values + NOTE these must be in the same order as their enumeration definition */ + +const LPCTSTR pKeyNames[] = { + TEXT("TIMING"), // Timing and performance measurements + TEXT("TRACE"), // General step point call tracing + TEXT("MEMORY"), // Memory and object allocation/destruction + TEXT("LOCKING"), // Locking/unlocking of critical sections + TEXT("ERROR"), // Debug error notification + TEXT("CUSTOM1"), + TEXT("CUSTOM2"), + TEXT("CUSTOM3"), + TEXT("CUSTOM4"), + TEXT("CUSTOM5") + }; + +const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s"); +const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s"); + +const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories + +HINSTANCE m_hInst; // Module instance handle +TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name +DWORD m_Levels[iMAXLEVELS]; // Debug level per category +CRITICAL_SECTION m_CSDebug; // Controls access to list +DWORD m_dwNextCookie; // Next active object ID +ObjectDesc *pListHead = NULL; // First active object +DWORD m_dwObjectCount; // Active object count +BOOL m_bInit = FALSE; // Have we been initialised +HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here +DWORD dwWaitTimeout = INFINITE; // Default timeout value +DWORD dwTimeOffset; // Time of first DbgLog call +bool g_fUseKASSERT = false; // don't create messagebox +bool g_fDbgInDllEntryPoint = false; +bool g_fAutoRefreshLevels = false; + +LPCTSTR pBaseKey = TEXT("SOFTWARE\\Microsoft\\DirectShow\\Debug"); +LPCTSTR pGlobalKey = TEXT("GLOBAL"); +static LPCSTR pUnknownName = "UNKNOWN"; + +LPCTSTR TimeoutName = TEXT("TIMEOUT"); + +/* This sets the instance handle that the debug library uses to find + the module's file name from the Win32 GetModuleFileName function */ + +void WINAPI DbgInitialise(HINSTANCE hInst) +{ + InitializeCriticalSection(&m_CSDebug); + m_bInit = TRUE; + + m_hInst = hInst; + DbgInitModuleName(); + if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0)) + DebugBreak(); + DbgInitModuleSettings(false); + DbgInitGlobalSettings(true); + dwTimeOffset = timeGetTime(); +} + + +/* This is called to clear up any resources the debug library uses - at the + moment we delete our critical section and the object list. The values we + retrieve from the registry are all done during initialisation but we don't + go looking for update notifications while we are running, if the values + are changed then the application has to be restarted to pick them up */ + +void WINAPI DbgTerminate() +{ + if (m_hOutput != INVALID_HANDLE_VALUE) { + EXECUTE_ASSERT(CloseHandle(m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + DeleteCriticalSection(&m_CSDebug); + m_bInit = FALSE; +} + + +/* This is called by DbgInitLogLevels to read the debug settings + for each logging category for this module from the registry */ + +void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax) +{ + LONG lReturn; // Create key return value + LONG lKeyPos; // Current key category + DWORD dwKeySize; // Size of the key value + DWORD dwKeyType; // Receives it's type + DWORD dwKeyValue; // This fields value + + /* Try and read a value for each key position in turn */ + for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) { + + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + pKeyNames[lKeyPos], // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwKeyValue, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + /* If either the key was not available or it was not a DWORD value + then we ensure only the high priority debug logging is output + but we try and update the field to a zero filled DWORD value */ + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { + + dwKeyValue = 0; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + pKeyNames[lKeyPos], // Address of subkey name + (DWORD) 0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE) &dwKeyValue, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); + dwKeyValue = 0; + } + } + if(fTakeMax) + { + m_Levels[lKeyPos] = std::max(dwKeyValue, m_Levels[lKeyPos]); + } + else + { + if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) { + m_Levels[lKeyPos] = dwKeyValue; + } + } + } + + /* Read the timeout value for catching hangs */ + dwKeySize = sizeof(DWORD); + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + TimeoutName, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) &dwWaitTimeout, // Returns the field's value + &dwKeySize ); // Number of bytes transferred + + /* If either the key was not available or it was not a DWORD value + then we ensure only the high priority debug logging is output + but we try and update the field to a zero filled DWORD value */ + + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) { + + dwWaitTimeout = INFINITE; + lReturn = RegSetValueEx( + hKey, // Handle of an open key + TimeoutName, // Address of subkey name + (DWORD) 0, // Reserved field + REG_DWORD, // Type of the key field + (PBYTE) &dwWaitTimeout, // Value for the field + sizeof(DWORD)); // Size of the field buffer + + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos])); + dwWaitTimeout = INFINITE; + } + } +} + +void WINAPI DbgOutString(LPCTSTR psz) +{ + if (m_hOutput != INVALID_HANDLE_VALUE) { + UINT cb = lstrlen(psz); + DWORD dw; +#ifdef UNICODE + CHAR szDest[2048]; + WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0); + WriteFile (m_hOutput, szDest, cb, &dw, NULL); +#else + WriteFile (m_hOutput, psz, cb, &dw, NULL); +#endif + } else { + OutputDebugString (psz); + } +} + + + + +HRESULT DbgUniqueProcessName(LPCTSTR inName, LPTSTR outName) +{ + HRESULT hr = S_OK; + const TCHAR *pIn = inName; + int dotPos = -1; + + //scan the input and record the last '.' position + while (*pIn && (pIn - inName) < MAX_PATH) + { + if ( TEXT('.') == *pIn ) + dotPos = (int)(pIn-inName); + ++pIn; + } + + if (*pIn) //input should be zero-terminated within MAX_PATH + return E_INVALIDARG; + + DWORD dwProcessId = GetCurrentProcessId(); + + if (dotPos < 0) + { + //no extension in the input, appending process id to the input + hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d"), inName, dwProcessId); + } + else + { + TCHAR pathAndBasename[MAX_PATH] = {0}; + + //there's an extension - zero-terminate the path and basename first by copying + hr = StringCchCopyN(pathAndBasename, MAX_PATH, inName, (size_t)dotPos); + + //re-combine path, basename and extension with processId appended to a basename + if (SUCCEEDED(hr)) + hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d%s"), pathAndBasename, dwProcessId, inName + dotPos); + } + + return hr; +} + + +/* Called by DbgInitGlobalSettings to setup alternate logging destinations + */ + +void WINAPI DbgInitLogTo ( + HKEY hKey) +{ + LONG lReturn; + DWORD dwKeyType; + DWORD dwKeySize; + TCHAR szFile[MAX_PATH] = {0}; + static const TCHAR cszKey[] = TEXT("LogToFile"); + + dwKeySize = MAX_PATH; + lReturn = RegQueryValueEx( + hKey, // Handle to an open key + cszKey, // Subkey name derivation + NULL, // Reserved field + &dwKeyType, // Returns the field type + (LPBYTE) szFile, // Returns the field's value + &dwKeySize); // Number of bytes transferred + + // create an empty key if it does not already exist + // + if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) + { + dwKeySize = sizeof(TCHAR); + lReturn = RegSetValueEx( + hKey, // Handle of an open key + cszKey, // Address of subkey name + (DWORD) 0, // Reserved field + REG_SZ, // Type of the key field + (PBYTE)szFile, // Value for the field + dwKeySize); // Size of the field buffer + } + + // if an output-to was specified. try to open it. + // + if (m_hOutput != INVALID_HANDLE_VALUE) { + EXECUTE_ASSERT(CloseHandle (m_hOutput)); + m_hOutput = INVALID_HANDLE_VALUE; + } + if (szFile[0] != 0) + { + if (!lstrcmpi(szFile, TEXT("Console"))) { + m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); + if (m_hOutput == INVALID_HANDLE_VALUE) { + AllocConsole (); + m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE); + } + SetConsoleTitle (TEXT("ActiveX Debug Output")); + } else if (szFile[0] && + lstrcmpi(szFile, TEXT("Debug")) && + lstrcmpi(szFile, TEXT("Debugger")) && + lstrcmpi(szFile, TEXT("Deb"))) + { + m_hOutput = CreateFile(szFile, GENERIC_WRITE, + FILE_SHARE_READ, + NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (INVALID_HANDLE_VALUE == m_hOutput && + GetLastError() == ERROR_SHARING_VIOLATION) + { + TCHAR uniqueName[MAX_PATH] = {0}; + if (SUCCEEDED(DbgUniqueProcessName(szFile, uniqueName))) + { + m_hOutput = CreateFile(uniqueName, GENERIC_WRITE, + FILE_SHARE_READ, + NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + } + } + + if (INVALID_HANDLE_VALUE != m_hOutput) + { + static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); + LARGE_INTEGER zero = {0, 0}; + SetFilePointerEx(m_hOutput, zero, NULL, FILE_END); + DbgOutString (cszBar); + } + } + } +} + + + +/* This is called by DbgInitLogLevels to read the global debug settings for + each logging category for this module from the registry. Normally each + module has it's own values set for it's different debug categories but + setting the global SOFTWARE\Debug\Global applies them to ALL modules */ + +void WINAPI DbgInitGlobalSettings(bool fTakeMax) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hGlobalKey; // Global override key + + /* Construct the global base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey); + + /* Create or open the key for this module */ + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + GENERIC_READ | GENERIC_WRITE, // Desired security access + NULL, // Key security descriptor + &hGlobalKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) { + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + GENERIC_READ, // Desired security access + NULL, // Key security descriptor + &hGlobalKey, // Opened handle buffer + NULL); // What really happened + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,1,TEXT("Could not access GLOBAL module key"))); + } + return; + } + + DbgInitKeyLevels(hGlobalKey, fTakeMax); + RegCloseKey(hGlobalKey); +} + + +/* This sets the debugging log levels for the different categories. We start + by opening (or creating if not already available) the SOFTWARE\Debug key + that all these settings live under. We then look at the global values + set under SOFTWARE\Debug\Global which apply on top of the individual + module settings. We then load the individual module registry settings */ + +void WINAPI DbgInitModuleSettings(bool fTakeMax) +{ + LONG lReturn; // Create key return value + TCHAR szInfo[iDEBUGINFO]; // Constructs key names + HKEY hModuleKey; // Module key handle + + /* Construct the base key name */ + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,m_ModuleName); + + /* Create or open the key for this module */ + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + GENERIC_READ | GENERIC_WRITE, // Desired security access + NULL, // Key security descriptor + &hModuleKey, // Opened handle buffer + NULL); // What really happened + + if (lReturn != ERROR_SUCCESS) { + lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key + szInfo, // Address of subkey name + (DWORD) 0, // Reserved value + NULL, // Address of class name + (DWORD) 0, // Special options flags + GENERIC_READ, // Desired security access + NULL, // Key security descriptor + &hModuleKey, // Opened handle buffer + NULL); // What really happened + if (lReturn != ERROR_SUCCESS) { + DbgLog((LOG_ERROR,1,TEXT("Could not access module key"))); + } + return; + } + + DbgInitLogTo(hModuleKey); + DbgInitKeyLevels(hModuleKey, fTakeMax); + RegCloseKey(hModuleKey); +} + + +/* Initialise the module file name */ + +void WINAPI DbgInitModuleName() +{ + TCHAR FullName[iDEBUGINFO]; // Load the full path and module name + LPTSTR pName; // Searches from the end for a backslash + + GetModuleFileName(m_hInst,FullName,iDEBUGINFO); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) { + pName = FullName; + } else { + pName++; + } + (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName); +} + +struct MsgBoxMsg +{ + HWND hwnd; + LPCTSTR szTitle; + LPCTSTR szMessage; + DWORD dwFlags; + INT iResult; +}; + +// +// create a thread to call MessageBox(). calling MessageBox() on +// random threads at bad times can confuse the host (eg IE). +// +DWORD WINAPI MsgBoxThread( + __inout LPVOID lpParameter // thread data + ) +{ + MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter; + pmsg->iResult = MessageBox( + pmsg->hwnd, + pmsg->szTitle, + pmsg->szMessage, + pmsg->dwFlags); + + return 0; +} + +INT MessageBoxOtherThread( + HWND hwnd, + LPCTSTR szTitle, + LPCTSTR szMessage, + DWORD dwFlags) +{ + if(g_fDbgInDllEntryPoint) + { + // can't wait on another thread because we have the loader + // lock held in the dll entry point. + // This can crash sometimes so just skip it + // return MessageBox(hwnd, szTitle, szMessage, dwFlags); + return IDCANCEL; + } + else + { + MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0}; + DWORD dwid; + HANDLE hThread = CreateThread( + 0, // security + 0, // stack size + MsgBoxThread, + (void *)&msg, // arg + 0, // flags + &dwid); + if(hThread) + { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + return msg.iResult; + } + + // break into debugger on failure. + return IDCANCEL; + } +} + +/* Displays a message box if the condition evaluated to FALSE */ + +void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine) +{ + if(g_fUseKASSERT) + { + DbgKernelAssert(pCondition, pFileName, iLine); + } + else + { + + TCHAR szInfo[iDEBUGINFO]; + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), + pCondition, iLine, pFileName); + + INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"), + MB_SYSTEMMODAL | + MB_ICONHAND | + MB_YESNOCANCEL | + MB_SETFOREGROUND); + switch (MsgId) + { + case IDNO: /* Kill the application */ + + FatalAppExit(FALSE, TEXT("Application terminated")); + break; + + case IDCANCEL: /* Break into the debugger */ + + DebugBreak(); + break; + + case IDYES: /* Ignore assertion continue execution */ + break; + } + } +} + +/* Displays a message box at a break point */ + +void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine) +{ + if(g_fUseKASSERT) + { + DbgKernelAssert(pCondition, pFileName, iLine); + } + else + { + TCHAR szInfo[iDEBUGINFO]; + + (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"), + pCondition, iLine, pFileName); + + INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"), + MB_SYSTEMMODAL | + MB_ICONHAND | + MB_YESNOCANCEL | + MB_SETFOREGROUND); + switch (MsgId) + { + case IDNO: /* Kill the application */ + + FatalAppExit(FALSE, TEXT("Application terminated")); + break; + + case IDCANCEL: /* Break into the debugger */ + + DebugBreak(); + break; + + case IDYES: /* Ignore break point continue execution */ + break; + } + } +} + +void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...) +{ + // A debug break point message can have at most 2000 characters if + // ANSI or UNICODE characters are being used. A debug break point message + // can have between 1000 and 2000 double byte characters in it. If a + // particular message needs more characters, then the value of this constant + // should be increased. + const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000; + + TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE]; + + va_list va; + va_start( va, szFormatString ); + + HRESULT hr = StringCchVPrintf( szBreakPointMessage, NUMELMS(szBreakPointMessage), szFormatString, va ); + + va_end(va); + + if( FAILED(hr) ) { + DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because StringCchVPrintf() failed." ); + return; + } + + ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine ); +} + + +/* When we initialised the library we stored in the m_Levels array the current + debug output level for this module for each of the five categories. When + some debug logging is sent to us it can be sent with a combination of the + categories (if it is applicable to many for example) in which case we map + the type's categories into their current debug levels and see if any of + them can be accepted. The function looks at each bit position in turn from + the input type field and then compares it's debug level with the modules. + + A level of 0 means that output is always sent to the debugger. This is + due to producing output if the input level is <= m_Levels. +*/ + + +BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level) +{ + if(g_fAutoRefreshLevels) + { + // re-read the registry every second. We cannot use RegNotify() to + // notice registry changes because it's not available on win9x. + static DWORD g_dwLastRefresh = 0; + DWORD dwTime = timeGetTime(); + if(dwTime - g_dwLastRefresh > 1000) { + g_dwLastRefresh = dwTime; + + // there's a race condition: multiple threads could update the + // values. plus read and write not synchronized. no harm + // though. + DbgInitModuleSettings(false); + } + } + + + DWORD Mask = 0x01; + + // If no valid bits are set return FALSE + if ((Type & ((1<m_szName = szObjectName; + pObject->m_wszName = wszObjectName; + pObject->m_dwCookie = ++m_dwNextCookie; + pObject->m_pNext = pListHead; + + pListHead = pObject; + m_dwObjectCount++; + + DWORD ObjectCookie = pObject->m_dwCookie; + ASSERT(ObjectCookie); + + if(wszObjectName) { + DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"), + pObject->m_dwCookie, wszObjectName, m_dwObjectCount)); + } else { + DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"), + pObject->m_dwCookie, szObjectName, m_dwObjectCount)); + } + + LeaveCriticalSection(&m_CSDebug); + return ObjectCookie; +} + + +/* This is called by the CBaseObject destructor when an object is about to be + destroyed, we are passed the cookie we returned during construction that + identifies this object. We scan the object list for a matching cookie and + remove the object if successful. We also update the active object count */ + +BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie) +{ + /* Grab the list critical section */ + EnterCriticalSection(&m_CSDebug); + + ObjectDesc *pObject = pListHead; + ObjectDesc *pPrevious = NULL; + + /* Scan the object list looking for a cookie match */ + + while (pObject) { + if (pObject->m_dwCookie == dwCookie) { + break; + } + pPrevious = pObject; + pObject = pObject->m_pNext; + } + + if (pObject == NULL) { + DbgBreak("Apparently destroying a bogus object"); + LeaveCriticalSection(&m_CSDebug); + return FALSE; + } + + /* Is the object at the head of the list */ + + if (pPrevious == NULL) { + pListHead = pObject->m_pNext; + } else { + pPrevious->m_pNext = pObject->m_pNext; + } + + /* Delete the object and update the housekeeping information */ + + m_dwObjectCount--; + + if(pObject->m_wszName) { + DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"), + pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount)); + } else { + DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"), + pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount)); + } + + delete pObject; + LeaveCriticalSection(&m_CSDebug); + return TRUE; +} + + +/* This runs through the active object list displaying their details */ + +void WINAPI DbgDumpObjectRegister() +{ + TCHAR szInfo[iDEBUGINFO]; + + /* Grab the list critical section */ + + EnterCriticalSection(&m_CSDebug); + ObjectDesc *pObject = pListHead; + + /* Scan the object list displaying the name and cookie */ + + DbgLog((LOG_MEMORY,2,TEXT(""))); + DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description"))); + DbgLog((LOG_MEMORY,2,TEXT(""))); + + while (pObject) { + if(pObject->m_wszName) { + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30ls"),pObject->m_dwCookie, &pObject, pObject->m_wszName); + } else { + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30hs"),pObject->m_dwCookie, &pObject, pObject->m_szName); + } + DbgLog((LOG_MEMORY,2,szInfo)); + pObject = pObject->m_pNext; + } + + (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount); + DbgLog((LOG_MEMORY,2,TEXT(""))); + DbgLog((LOG_MEMORY,1,szInfo)); + LeaveCriticalSection(&m_CSDebug); +} + +/* Debug infinite wait stuff */ +DWORD WINAPI DbgWaitForSingleObject(HANDLE h) +{ + DWORD dwWaitResult; + do { + dwWaitResult = WaitForSingleObject(h, dwWaitTimeout); + ASSERT(dwWaitResult == WAIT_OBJECT_0); + } while (dwWaitResult == WAIT_TIMEOUT); + return dwWaitResult; +} +DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, + __in_ecount(nCount) CONST HANDLE *lpHandles, + BOOL bWaitAll) +{ + DWORD dwWaitResult; + do { + dwWaitResult = WaitForMultipleObjects(nCount, + lpHandles, + bWaitAll, + dwWaitTimeout); + ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS); + } while (dwWaitResult == WAIT_TIMEOUT); + return dwWaitResult; +} + +void WINAPI DbgSetWaitTimeout(DWORD dwTimeout) +{ + dwWaitTimeout = dwTimeout; +} + +#endif /* DEBUG */ + +#ifdef _OBJBASE_H_ + + /* Stuff for printing out our GUID names */ + + constexpr GUID_STRING_ENTRY g_GuidNames[] = { + #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } }, + #include + }; + + CGuidNameList GuidNames; + int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]); + + LPCSTR CGuidNameList::operator [] (const GUID &guid) + { + for (int i = 0; i < g_cGuidNames; i++) { + if (g_GuidNames[i].guid == guid) { + return g_GuidNames[i].szName; + } + } + if (guid == GUID_NULL) { + return "GUID_NULL"; + } + + // !!! add something to print FOURCC guids? + + // shouldn't this print the hex CLSID? + return "Unknown GUID Name"; + } + +#endif /* _OBJBASE_H_ */ + +/* CDisp class - display our data types */ + +// clashes with REFERENCE_TIME +CDisp::CDisp(LONGLONG ll, int Format) +{ + // note: this could be combined with CDisp(LONGLONG) by + // introducing a default format of CDISP_REFTIME + LARGE_INTEGER li; + li.QuadPart = ll; + switch (Format) { + case CDISP_DEC: + { + TCHAR temp[20]; + int pos=20; + temp[--pos] = 0; + int digit; + // always output at least one digit + do { + // Get the rightmost digit - we only need the low word + digit = li.LowPart % 10; + li.QuadPart /= 10; + temp[--pos] = (TCHAR) digit+L'0'; + } while (li.QuadPart); + (void)StringCchCopy(m_String, NUMELMS(m_String), temp+pos); + break; + } + case CDISP_HEX: + default: + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart); + } +}; + +CDisp::CDisp(REFCLSID clsid) +{ +#ifdef UNICODE + (void)StringFromGUID2(clsid, m_String, NUMELMS(m_String)); +#else + WCHAR wszTemp[50]; + (void)StringFromGUID2(clsid, wszTemp, NUMELMS(wszTemp)); + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), wszTemp); +#endif +}; + +#ifdef __STREAMS__ +/* Display stuff */ +CDisp::CDisp(CRefTime llTime) +{ + LONGLONG llDiv; + if (llTime < 0) { + llTime = -llTime; + (void)StringCchCopy(m_String, NUMELMS(m_String), TEXT("-")); + } + llDiv = (LONGLONG)24 * 3600 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d days "), (LONG)(llTime / llDiv)); + llTime = llTime % llDiv; + } + llDiv = (LONGLONG)3600 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d hrs "), (LONG)(llTime / llDiv)); + llTime = llTime % llDiv; + } + llDiv = (LONGLONG)60 * 10000000; + if (llTime >= llDiv) { + (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d mins "), (LONG)(llTime / llDiv)); + llTime = llTime % llDiv; + } + (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d.%3.3d sec"), + (LONG)llTime / 10000000, + (LONG)((llTime % 10000000) / 10000)); +}; + +#endif // __STREAMS__ + + +/* Display pin */ +CDisp::CDisp(IPin *pPin) +{ + PIN_INFO pi; + TCHAR str[MAX_PIN_NAME]; + CLSID clsid; + + if (pPin) { + pPin->QueryPinInfo(&pi); + pi.pFilter->GetClassID(&clsid); + QueryPinInfoReleaseFilter(pi); + #ifndef UNICODE + WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1, + str, MAX_PIN_NAME, NULL, NULL); + #else + (void)StringCchCopy(str, NUMELMS(str), pi.achName); + #endif + } else { + (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin")); + } + + m_pString = (PTCHAR) new TCHAR[lstrlen(str)+64]; + if (!m_pString) { + return; + } + + (void)StringCchPrintf(m_pString, lstrlen(str) + 64, TEXT("%hs(%s)"), GuidNames[clsid], str); +} + +/* Display filter or pin */ +CDisp::CDisp(IUnknown *pUnk) +{ + IBaseFilter *pf; + HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf); + if(SUCCEEDED(hr)) + { + FILTER_INFO fi; + hr = pf->QueryFilterInfo(&fi); + if(SUCCEEDED(hr)) + { + QueryFilterInfoReleaseGraph(fi); + + size_t len = lstrlenW(fi.achName) + 1; + + m_pString = new TCHAR[len]; + if(m_pString) + { +#ifdef UNICODE + (void)StringCchCopy(m_pString, len, fi.achName); +#else + (void)StringCchPrintf(m_pString, len, "%S", fi.achName); +#endif + } + } + + pf->Release(); + + return; + } + + IPin *pp; + hr = pUnk->QueryInterface(IID_IPin, (void **)&pp); + if(SUCCEEDED(hr)) + { + CDisp::CDisp(pp); + pp->Release(); + return; + } +} + + +CDisp::~CDisp() +{ +} + +CDispBasic::~CDispBasic() +{ + if (m_pString != m_String) { + delete [] m_pString; + } +} + +CDisp::CDisp(double d) +{ + (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000)); +} + + +/* If built for debug this will display the media type details. We convert the + major and subtypes into strings and also ask the base classes for a string + description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit + We also display the fields in the BITMAPINFOHEADER structure, this should + succeed as we do not accept input types unless the format is big enough */ + +#ifdef _DEBUG +void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn) +{ + + /* Dump the GUID types and a short description */ + + DbgLog((LOG_TRACE,5,TEXT(""))); + DbgLog((LOG_TRACE,2,TEXT("%s M type %hs S type %hs"), label, + GuidNames[pmtIn->majortype], + GuidNames[pmtIn->subtype])); + DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype))); + + /* Dump the generic media types */ + + if (pmtIn->bTemporalCompression) { + DbgLog((LOG_TRACE,5,TEXT("Temporally compressed"))); + } else { + DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed"))); + } + + if (pmtIn->bFixedSizeSamples) { + DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize)); + } else { + DbgLog((LOG_TRACE,5,TEXT("Variable size samples"))); + } + + if (pmtIn->formattype == FORMAT_VideoInfo) { + + VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat; + + DisplayRECT(TEXT("Source rectangle"),pVideoInfo->rcSource); + DisplayRECT(TEXT("Target rectangle"),pVideoInfo->rcTarget); + DisplayBITMAPINFO(HEADER(pmtIn->pbFormat)); + + } if (pmtIn->formattype == FORMAT_VideoInfo2) { + + VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pmtIn->pbFormat; + + DisplayRECT(TEXT("Source rectangle"),pVideoInfo2->rcSource); + DisplayRECT(TEXT("Target rectangle"),pVideoInfo2->rcTarget); + DbgLog((LOG_TRACE, 5, TEXT("Aspect Ratio: %d:%d"), + pVideoInfo2->dwPictAspectRatioX, + pVideoInfo2->dwPictAspectRatioY)); + DisplayBITMAPINFO(&pVideoInfo2->bmiHeader); + + } else if (pmtIn->majortype == MEDIATYPE_Audio) { + DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), + GuidNames[pmtIn->formattype])); + DbgLog((LOG_TRACE,2,TEXT(" Subtype %hs"), + GuidNames[pmtIn->subtype])); + + if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet) + && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT))) + { + /* Dump the contents of the WAVEFORMATEX type-specific format structure */ + + WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat; + DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag)); + DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels)); + DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec)); + DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec)); + DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign)); + DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample)); + + /* PCM uses a WAVEFORMAT and does not have the extra size field */ + + if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) { + DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize)); + } + } else { + } + + } else { + DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"), + GuidNames[pmtIn->formattype])); + } +} + + +void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi) +{ + DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize)); + if (pbmi->biCompression < 256) { + DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit (%d)"), + pbmi->biWidth, pbmi->biHeight, + pbmi->biBitCount, pbmi->biCompression)); + } else { + DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"), + pbmi->biWidth, pbmi->biHeight, + pbmi->biBitCount, &pbmi->biCompression)); + } + + DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage)); + DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes)); + DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter)); + DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter)); + DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed)); +} + + +void DisplayRECT(LPCTSTR szLabel, const RECT& rc) +{ + DbgLog((LOG_TRACE,5,TEXT("%s (Left %d Top %d Right %d Bottom %d)"), + szLabel, + rc.left, + rc.top, + rc.right, + rc.bottom)); +} + + +void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel) +{ + if( !pGraph ) + { + return; + } + + IEnumFilters *pFilters; + + DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph)); + + if (FAILED(pGraph->EnumFilters(&pFilters))) { + DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!"))); + } + + IBaseFilter *pFilter; + ULONG n; + while (pFilters->Next(1, &pFilter, &n) == S_OK) { + FILTER_INFO info; + + if (FAILED(pFilter->QueryFilterInfo(&info))) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] -- failed QueryFilterInfo"), pFilter)); + } else { + QueryFilterInfoReleaseGraph(info); + + // !!! should QueryVendorInfo here! + + DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] '%ls'"), pFilter, info.achName)); + + IEnumPins *pins; + + if (FAILED(pFilter->EnumPins(&pins))) { + DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!"))); + } else { + + IPin *pPin; + while (pins->Next(1, &pPin, &n) == S_OK) { + PIN_INFO pinInfo; + + if (FAILED(pPin->QueryPinInfo(&pinInfo))) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin)); + } else { + QueryPinInfoReleaseFilter(pinInfo); + + IPin *pPinConnected = NULL; + + HRESULT hr = pPin->ConnectedTo(&pPinConnected); + + if (pPinConnected) { + DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%p] '%ls' [%sput]") + TEXT(" Connected to pin [%p]"), + pPin, pinInfo.achName, + pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"), + pPinConnected)); + + pPinConnected->Release(); + + // perhaps we should really dump the type both ways as a sanity + // check? + if (pinInfo.dir == PINDIR_OUTPUT) { + AM_MEDIA_TYPE mt; + + hr = pPin->ConnectionMediaType(&mt); + + if (SUCCEEDED(hr)) { + DisplayType(TEXT("Connection type"), &mt); + + FreeMediaType(mt); + } + } + } else { + DbgLog((LOG_TRACE,dwLevel, + TEXT(" Pin [%x] '%ls' [%sput]"), + pPin, pinInfo.achName, + pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"))); + + } + } + + pPin->Release(); + + } + + pins->Release(); + } + + } + + pFilter->Release(); + } + + pFilters->Release(); + +} + +#endif + diff --git a/src/thirdparty/BaseClasses/wxdebug.h b/src/thirdparty/BaseClasses/wxdebug.h index 8c537901621..be80d128de4 100644 --- a/src/thirdparty/BaseClasses/wxdebug.h +++ b/src/thirdparty/BaseClasses/wxdebug.h @@ -1,359 +1,359 @@ -//------------------------------------------------------------------------------ -// File: WXDebug.h -// -// Desc: DirectShow base classes - provides debugging facilities. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __WXDEBUG__ -#define __WXDEBUG__ - -// This library provides fairly straight forward debugging functionality, this -// is split into two main sections. The first is assertion handling, there are -// three types of assertions provided here. The most commonly used one is the -// ASSERT(condition) macro which will pop up a message box including the file -// and line number if the condition evaluates to FALSE. Then there is the -// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will -// still be executed in NON debug builds. The final type of assertion is the -// KASSERT macro which is more suitable for pure (perhaps kernel) filters as -// the condition is printed onto the debugger rather than in a message box. -// -// The other part of the debug module facilties is general purpose logging. -// This is accessed by calling DbgLog(). The function takes a type and level -// field which define the type of informational string you are presenting and -// it's relative importance. The type field can be a combination (one or more) -// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level -// is a DWORD value where zero defines highest important. Use of zero as the -// debug logging level is to be encouraged ONLY for major errors or events as -// they will ALWAYS be displayed on the debugger. Other debug output has it's -// level matched against the current debug output level stored in the registry -// for this module and if less than the current setting it will be displayed. -// -// Each module or executable has it's own debug output level for each of the -// five types. These are read in when the DbgInitialise function is called -// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL -// is loaded, executables must call it explicitely with the module instance -// handle given to them through the WINMAIN entry point. An executable must -// also call DbgTerminate when they have finished to clean up the resources -// the debug library uses, once again this is done automatically for DLLs - -// These are the five different categories of logging information - -enum { LOG_TIMING = 0x01, // Timing and performance measurements - LOG_TRACE = 0x02, // General step point call tracing - LOG_MEMORY = 0x04, // Memory and object allocation/destruction - LOG_LOCKING = 0x08, // Locking/unlocking of critical sections - LOG_ERROR = 0x10, // Debug error notification - LOG_CUSTOM1 = 0x20, - LOG_CUSTOM2 = 0x40, - LOG_CUSTOM3 = 0x80, - LOG_CUSTOM4 = 0x100, - LOG_CUSTOM5 = 0x200, -}; - -#define LOG_FORCIBLY_SET 0x80000000 - -enum { CDISP_HEX = 0x01, - CDISP_DEC = 0x02}; - -// For each object created derived from CBaseObject (in debug builds) we -// create a descriptor that holds it's name (statically allocated memory) -// and a cookie we assign it. We keep a list of all the active objects -// we have registered so that we can dump a list of remaining objects - -typedef struct tag_ObjectDesc { - LPCSTR m_szName; - LPCWSTR m_wszName; - DWORD m_dwCookie; - tag_ObjectDesc *m_pNext; -} ObjectDesc; - -#define DLLIMPORT __declspec(dllimport) -#define DLLEXPORT __declspec(dllexport) - -#ifdef _DEBUG - - #define NAME(x) TEXT(x) - - // These are used internally by the debug library (PRIVATE) - - void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax); - void WINAPI DbgInitGlobalSettings(bool fTakeMax); - void WINAPI DbgInitModuleSettings(bool fTakeMax); - void WINAPI DbgInitModuleName(); - DWORD WINAPI DbgRegisterObjectCreation( - LPCSTR szObjectName, LPCWSTR wszObjectName); - - BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie); - - // These are the PUBLIC entry points - - BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level); - void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level); - void WINAPI DbgSetAutoRefreshLevels(bool fAuto); - - // Initialise the library with the module handle - - void WINAPI DbgInitialise(HINSTANCE hInst); - void WINAPI DbgTerminate(); - - void WINAPI DbgDumpObjectRegister(); - - // Display error and logging to the user - - void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); - void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); - void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...); - - void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); - void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCTSTR pFormat,...); -#ifdef UNICODE - void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...); - void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); - void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine); - void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); -#endif - void WINAPI DbgOutString(LPCTSTR psz); - - // Debug infinite wait stuff - DWORD WINAPI DbgWaitForSingleObject(HANDLE h); - DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, - __in_ecount(nCount) CONST HANDLE *lpHandles, - BOOL bWaitAll); - void WINAPI DbgSetWaitTimeout(DWORD dwTimeout); - -#ifdef __strmif_h__ - // Display a media type: Terse at level 2, verbose at level 5 - void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn); - - // Dump lots of information about a filter graph - void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel); -#endif - - #define KASSERT(_x_) if (!(_x_)) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - // Break on the debugger without putting up a message box - // message goes to debugger instead - - #define KDbgBreak(_x_) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - // We chose a common name for our ASSERT macro, MFC also uses this name - // So long as the implementation evaluates the condition and handles it - // then we will be ok. Rather than override the behaviour expected we - // will leave whatever first defines ASSERT as the handler (i.e. MFC) - #ifndef ASSERT - #define ASSERT(_x_) if (!(_x_)) \ - DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - #endif - - #define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0) - - // Put up a message box informing the user of a halt - // condition in the program - - #define DbgBreak(_x_) \ - DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) - - #define EXECUTE_ASSERT(_x_) ASSERT(_x_) - #define DbgLog(_x_) DbgLogInfo _x_ - // MFC style trace macros - - #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))) - #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)) - #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)) - #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)) - #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)) - #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)) - -#else - - // Retail builds make public debug functions inert - WARNING the source - // files do not define or build any of the entry points in debug builds - // (public entry points compile to nothing) so if you go trying to call - // any of the private entry points in your source they won't compile - - #define NAME(_x_) ((LPTSTR) NULL) - - #define DbgInitialise(hInst) - #define DbgTerminate() - #define DbgLog(_x_) 0 - #define DbgOutString(psz) - #define DbgAssertAligned( _ptr_, _alignment_ ) 0 - - #define DbgRegisterObjectCreation(pObjectName) - #define DbgRegisterObjectDestruction(dwCookie) - #define DbgDumpObjectRegister() - - #define DbgCheckModuleLevel(Type,Level) - #define DbgSetModuleLevel(Type,Level) - #define DbgSetAutoRefreshLevels(fAuto) - - #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) - #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ - WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) - #define DbgSetWaitTimeout(dwTimeout) - - #define KDbgBreak(_x_) - #define DbgBreak(_x_) - - #define KASSERT(_x_) ((void)0) - #ifndef ASSERT - #define ASSERT(_x_) ((void)0) - #endif - #define EXECUTE_ASSERT(_x_) ((void)(_x_)) - - // MFC style trace macros - - #define NOTE(_x_) ((void)0) - #define NOTE1(_x_,a) ((void)0) - #define NOTE2(_x_,a,b) ((void)0) - #define NOTE3(_x_,a,b,c) ((void)0) - #define NOTE4(_x_,a,b,c,d) ((void)0) - #define NOTE5(_x_,a,b,c,d,e) ((void)0) - - #define DisplayType(label, pmtIn) ((void)0) - #define DumpGraph(pGraph, label) ((void)0) -#endif - - -// Checks a pointer which should be non NULL - can be used as follows. - -#define CheckPointer(p,ret) {if((p)==NULL) return (ret);} - -// HRESULT Foo(VOID *pBar) -// { -// CheckPointer(pBar,E_INVALIDARG) -// } -// -// Or if the function returns a boolean -// -// BOOL Foo(VOID *pBar) -// { -// CheckPointer(pBar,FALSE) -// } - -#define ValidateReadPtr(p,cb) 0 -#define ValidateWritePtr(p,cb) 0 -#define ValidateReadWritePtr(p,cb) 0 -#define ValidateStringPtr(p) 0 -#define ValidateStringPtrA(p) 0 -#define ValidateStringPtrW(p) 0 - - -#ifdef _OBJBASE_H_ - - // Outputting GUID names. If you want to include the name - // associated with a GUID (eg CLSID_...) then - // - // GuidNames[yourGUID] - // - // Returns the name defined in uuids.h as a string - - typedef struct { - LPCSTR szName; - GUID guid; - } GUID_STRING_ENTRY; - - class CGuidNameList { - public: - LPCSTR operator [] (const GUID& guid); - }; - - extern CGuidNameList GuidNames; - -#endif - -#ifndef REMIND - // REMIND macro - generates warning as reminder to complete coding - // (eg) usage: - // - // #pragma message (REMIND("Add automation support")) - - - #define QUOTE(x) #x - #define QQUOTE(y) QUOTE(y) - #define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str -#endif - -// Method to display objects in a useful format -// -// eg If you want to display a LONGLONG ll in a debug string do (eg) -// -// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); - - -class CDispBasic -{ -public: - CDispBasic() { m_pString = m_String; }; - ~CDispBasic(); -protected: - PTCHAR m_pString; // normally points to m_String... unless too much data - TCHAR m_String[50]; -}; -class CDisp : public CDispBasic -{ -public: - CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form - CDisp(REFCLSID clsid); // Display a GUID - CDisp(double d); // Display a floating point number -#ifdef __strmif_h__ -#ifdef __STREAMS__ - CDisp(CRefTime t); // Display a Reference Time -#endif - CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) - CDisp(IUnknown *pUnk); // Display a filter or pin -#endif // __strmif_h__ - ~CDisp(); - - // Implement cast to (LPCTSTR) as parameter to logger - operator LPCTSTR() - { - return (LPCTSTR)m_pString; - }; -}; - - -#if defined(DEBUG) -class CAutoTrace -{ -private: - LPCTSTR _szBlkName; - const int _level; - static const TCHAR _szEntering[]; - static const TCHAR _szLeaving[]; -public: - CAutoTrace(LPCTSTR szBlkName, const int level = 15) - : _szBlkName(szBlkName), _level(level) - {DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} - - ~CAutoTrace() - {DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} -}; - -#if defined (__FUNCTION__) - -#define AMTRACEFN() CAutoTrace __trace(TEXT(__FUNCTION__)) -#define AMTRACE(_x_) CAutoTrace __trace(TEXT(__FUNCTION__)) - -#else - -#define AMTRACE(_x_) CAutoTrace __trace _x_ -#define AMTRACEFN() - -#endif - -#else - -#define AMTRACE(_x_) -#define AMTRACEFN() - -#endif - -#endif // __WXDEBUG__ - - +//------------------------------------------------------------------------------ +// File: WXDebug.h +// +// Desc: DirectShow base classes - provides debugging facilities. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WXDEBUG__ +#define __WXDEBUG__ + +// This library provides fairly straight forward debugging functionality, this +// is split into two main sections. The first is assertion handling, there are +// three types of assertions provided here. The most commonly used one is the +// ASSERT(condition) macro which will pop up a message box including the file +// and line number if the condition evaluates to FALSE. Then there is the +// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will +// still be executed in NON debug builds. The final type of assertion is the +// KASSERT macro which is more suitable for pure (perhaps kernel) filters as +// the condition is printed onto the debugger rather than in a message box. +// +// The other part of the debug module facilties is general purpose logging. +// This is accessed by calling DbgLog(). The function takes a type and level +// field which define the type of informational string you are presenting and +// it's relative importance. The type field can be a combination (one or more) +// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level +// is a DWORD value where zero defines highest important. Use of zero as the +// debug logging level is to be encouraged ONLY for major errors or events as +// they will ALWAYS be displayed on the debugger. Other debug output has it's +// level matched against the current debug output level stored in the registry +// for this module and if less than the current setting it will be displayed. +// +// Each module or executable has it's own debug output level for each of the +// five types. These are read in when the DbgInitialise function is called +// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL +// is loaded, executables must call it explicitely with the module instance +// handle given to them through the WINMAIN entry point. An executable must +// also call DbgTerminate when they have finished to clean up the resources +// the debug library uses, once again this is done automatically for DLLs + +// These are the five different categories of logging information + +enum { LOG_TIMING = 0x01, // Timing and performance measurements + LOG_TRACE = 0x02, // General step point call tracing + LOG_MEMORY = 0x04, // Memory and object allocation/destruction + LOG_LOCKING = 0x08, // Locking/unlocking of critical sections + LOG_ERROR = 0x10, // Debug error notification + LOG_CUSTOM1 = 0x20, + LOG_CUSTOM2 = 0x40, + LOG_CUSTOM3 = 0x80, + LOG_CUSTOM4 = 0x100, + LOG_CUSTOM5 = 0x200, +}; + +#define LOG_FORCIBLY_SET 0x80000000 + +enum { CDISP_HEX = 0x01, + CDISP_DEC = 0x02}; + +// For each object created derived from CBaseObject (in debug builds) we +// create a descriptor that holds it's name (statically allocated memory) +// and a cookie we assign it. We keep a list of all the active objects +// we have registered so that we can dump a list of remaining objects + +typedef struct tag_ObjectDesc { + LPCSTR m_szName; + LPCWSTR m_wszName; + DWORD m_dwCookie; + tag_ObjectDesc *m_pNext; +} ObjectDesc; + +#define DLLIMPORT __declspec(dllimport) +#define DLLEXPORT __declspec(dllexport) + +#ifdef _DEBUG + + #define NAME(x) TEXT(x) + + // These are used internally by the debug library (PRIVATE) + + void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax); + void WINAPI DbgInitGlobalSettings(bool fTakeMax); + void WINAPI DbgInitModuleSettings(bool fTakeMax); + void WINAPI DbgInitModuleName(); + DWORD WINAPI DbgRegisterObjectCreation( + LPCSTR szObjectName, LPCWSTR wszObjectName); + + BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie); + + // These are the PUBLIC entry points + + BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level); + void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level); + void WINAPI DbgSetAutoRefreshLevels(bool fAuto); + + // Initialise the library with the module handle + + void WINAPI DbgInitialise(HINSTANCE hInst); + void WINAPI DbgTerminate(); + + void WINAPI DbgDumpObjectRegister(); + + // Display error and logging to the user + + void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); + void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); + void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...); + + void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); + void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCTSTR pFormat,...); +#ifdef UNICODE + void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...); + void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); + void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine); + void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); +#endif + void WINAPI DbgOutString(LPCTSTR psz); + + // Debug infinite wait stuff + DWORD WINAPI DbgWaitForSingleObject(HANDLE h); + DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, + __in_ecount(nCount) CONST HANDLE *lpHandles, + BOOL bWaitAll); + void WINAPI DbgSetWaitTimeout(DWORD dwTimeout); + +#ifdef __strmif_h__ + // Display a media type: Terse at level 2, verbose at level 5 + void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn); + + // Dump lots of information about a filter graph + void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel); +#endif + + #define KASSERT(_x_) if (!(_x_)) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // Break on the debugger without putting up a message box + // message goes to debugger instead + + #define KDbgBreak(_x_) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // We chose a common name for our ASSERT macro, MFC also uses this name + // So long as the implementation evaluates the condition and handles it + // then we will be ok. Rather than override the behaviour expected we + // will leave whatever first defines ASSERT as the handler (i.e. MFC) + #ifndef ASSERT + #define ASSERT(_x_) if (!(_x_)) \ + DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + #endif + + #define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0) + + // Put up a message box informing the user of a halt + // condition in the program + + #define DbgBreak(_x_) \ + DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + #define EXECUTE_ASSERT(_x_) ASSERT(_x_) + #define DbgLog(_x_) DbgLogInfo _x_ + // MFC style trace macros + + #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))) + #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)) + #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)) + #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)) + #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)) + #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)) + +#else + + // Retail builds make public debug functions inert - WARNING the source + // files do not define or build any of the entry points in debug builds + // (public entry points compile to nothing) so if you go trying to call + // any of the private entry points in your source they won't compile + + #define NAME(_x_) ((LPTSTR) NULL) + + #define DbgInitialise(hInst) + #define DbgTerminate() + #define DbgLog(_x_) 0 + #define DbgOutString(psz) + #define DbgAssertAligned( _ptr_, _alignment_ ) 0 + + #define DbgRegisterObjectCreation(pObjectName) + #define DbgRegisterObjectDestruction(dwCookie) + #define DbgDumpObjectRegister() + + #define DbgCheckModuleLevel(Type,Level) + #define DbgSetModuleLevel(Type,Level) + #define DbgSetAutoRefreshLevels(fAuto) + + #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) + #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ + WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) + #define DbgSetWaitTimeout(dwTimeout) + + #define KDbgBreak(_x_) + #define DbgBreak(_x_) + + #define KASSERT(_x_) ((void)0) + #ifndef ASSERT + #define ASSERT(_x_) ((void)0) + #endif + #define EXECUTE_ASSERT(_x_) ((void)(_x_)) + + // MFC style trace macros + + #define NOTE(_x_) ((void)0) + #define NOTE1(_x_,a) ((void)0) + #define NOTE2(_x_,a,b) ((void)0) + #define NOTE3(_x_,a,b,c) ((void)0) + #define NOTE4(_x_,a,b,c,d) ((void)0) + #define NOTE5(_x_,a,b,c,d,e) ((void)0) + + #define DisplayType(label, pmtIn) ((void)0) + #define DumpGraph(pGraph, label) ((void)0) +#endif + + +// Checks a pointer which should be non NULL - can be used as follows. + +#define CheckPointer(p,ret) {if((p)==NULL) return (ret);} + +// HRESULT Foo(VOID *pBar) +// { +// CheckPointer(pBar,E_INVALIDARG) +// } +// +// Or if the function returns a boolean +// +// BOOL Foo(VOID *pBar) +// { +// CheckPointer(pBar,FALSE) +// } + +#define ValidateReadPtr(p,cb) 0 +#define ValidateWritePtr(p,cb) 0 +#define ValidateReadWritePtr(p,cb) 0 +#define ValidateStringPtr(p) 0 +#define ValidateStringPtrA(p) 0 +#define ValidateStringPtrW(p) 0 + + +#ifdef _OBJBASE_H_ + + // Outputting GUID names. If you want to include the name + // associated with a GUID (eg CLSID_...) then + // + // GuidNames[yourGUID] + // + // Returns the name defined in uuids.h as a string + + typedef struct { + LPCSTR szName; + GUID guid; + } GUID_STRING_ENTRY; + + class CGuidNameList { + public: + LPCSTR operator [] (const GUID& guid); + }; + + extern CGuidNameList GuidNames; + +#endif + +#ifndef REMIND + // REMIND macro - generates warning as reminder to complete coding + // (eg) usage: + // + // #pragma message (REMIND("Add automation support")) + + + #define QUOTE(x) #x + #define QQUOTE(y) QUOTE(y) + #define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str +#endif + +// Method to display objects in a useful format +// +// eg If you want to display a LONGLONG ll in a debug string do (eg) +// +// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); + + +class CDispBasic +{ +public: + CDispBasic() { m_pString = m_String; }; + ~CDispBasic(); +protected: + PTCHAR m_pString; // normally points to m_String... unless too much data + TCHAR m_String[50]; +}; +class CDisp : public CDispBasic +{ +public: + CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form + CDisp(REFCLSID clsid); // Display a GUID + CDisp(double d); // Display a floating point number +#ifdef __strmif_h__ +#ifdef __STREAMS__ + CDisp(CRefTime t); // Display a Reference Time +#endif + CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) + CDisp(IUnknown *pUnk); // Display a filter or pin +#endif // __strmif_h__ + ~CDisp(); + + // Implement cast to (LPCTSTR) as parameter to logger + operator LPCTSTR() + { + return (LPCTSTR)m_pString; + }; +}; + + +#if defined(DEBUG) +class CAutoTrace +{ +private: + LPCTSTR _szBlkName; + const int _level; + static const TCHAR _szEntering[]; + static const TCHAR _szLeaving[]; +public: + CAutoTrace(LPCTSTR szBlkName, const int level = 15) + : _szBlkName(szBlkName), _level(level) + {DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} + + ~CAutoTrace() + {DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} +}; + +#if defined (__FUNCTION__) + +#define AMTRACEFN() CAutoTrace __trace(TEXT(__FUNCTION__)) +#define AMTRACE(_x_) CAutoTrace __trace(TEXT(__FUNCTION__)) + +#else + +#define AMTRACE(_x_) CAutoTrace __trace _x_ +#define AMTRACEFN() + +#endif + +#else + +#define AMTRACE(_x_) +#define AMTRACEFN() + +#endif + +#endif // __WXDEBUG__ + + diff --git a/src/thirdparty/BaseClasses/wxlist.cpp b/src/thirdparty/BaseClasses/wxlist.cpp index cf9631824bf..5b697cdc5f8 100644 --- a/src/thirdparty/BaseClasses/wxlist.cpp +++ b/src/thirdparty/BaseClasses/wxlist.cpp @@ -1,891 +1,891 @@ -//------------------------------------------------------------------------------ -// File: WXList.cpp -// -// Desc: DirectShow base classes - implements a non-MFC based generic list -// template class. -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* A generic list of pointers to objects. - Objectives: avoid using MFC libraries in ndm kernel mode and - provide a really useful list type. - - The class is thread safe in that separate threads may add and - delete items in the list concurrently although the application - must ensure that constructor and destructor access is suitably - synchronised. - - The list name must not conflict with MFC classes as an - application may use both - - The nodes form a doubly linked, NULL terminated chain with an anchor - block (the list object per se) holding pointers to the first and last - nodes and a count of the nodes. - There is a node cache to reduce the allocation and freeing overhead. - It optionally (determined at construction time) has an Event which is - set whenever the list becomes non-empty and reset whenever it becomes - empty. - It optionally (determined at construction time) has a Critical Section - which is entered during the important part of each operation. (About - all you can do outside it is some parameter checking). - - The node cache is a repository of nodes that are NOT in the list to speed - up storage allocation. Each list has its own cache to reduce locking and - serialising. The list accesses are serialised anyway for a given list - a - common cache would mean that we would have to separately serialise access - of all lists within the cache. Because the cache only stores nodes that are - not in the list, releasing the cache does not release any list nodes. This - means that list nodes can be copied or rechained from one list to another - without danger of creating a dangling reference if the original cache goes - away. - - Questionable design decisions: - 1. Retaining the warts for compatibility - 2. Keeping an element count -i.e. counting whenever we do anything - instead of only when we want the count. - 3. Making the chain pointers NULL terminated. If the list object - itself looks just like a node and the list is kept as a ring then - it reduces the number of special cases. All inserts look the same. -*/ - - -#include "streams.h" - -/* set cursor to the position of each element of list in turn */ -#define INTERNALTRAVERSELIST(list, cursor) \ -for ( cursor = (list).GetHeadPositionI() \ - ; cursor!=NULL \ - ; cursor = (list).Next(cursor) \ - ) - - -/* set cursor to the position of each element of list in turn - in reverse order -*/ -#define INTERNALREVERSETRAVERSELIST(list, cursor) \ -for ( cursor = (list).GetTailPositionI() \ - ; cursor!=NULL \ - ; cursor = (list).Prev(cursor) \ - ) - -/* Constructor calls a separate initialisation function that - creates a node cache, optionally creates a lock object - and optionally creates a signaling object. - - By default we create a locking object, a DEFAULTCACHE sized - cache but no event object so the list cannot be used in calls - to WaitForSingleObject -*/ -CBaseList::CBaseList(__in_opt LPCTSTR pName, // Descriptive list name - INT iItems) : // Node cache size -#ifdef _DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(iItems) -{ -} // constructor - -CBaseList::CBaseList(__in_opt LPCTSTR pName) : // Descriptive list name -#ifdef _DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(DEFAULTCACHE) -{ -} // constructor - -#ifdef UNICODE -CBaseList::CBaseList(__in_opt LPCSTR pName, // Descriptive list name - INT iItems) : // Node cache size -#ifdef _DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(iItems) -{ -} // constructor - -CBaseList::CBaseList(__in_opt LPCSTR pName) : // Descriptive list name -#ifdef _DEBUG - CBaseObject(pName), -#endif - m_pFirst(NULL), - m_pLast(NULL), - m_Count(0), - m_Cache(DEFAULTCACHE) -{ -} // constructor - -#endif - -/* The destructor enumerates all the node objects in the list and - in the cache deleting each in turn. We do not do any processing - on the objects that the list holds (i.e. points to) so if they - represent interfaces for example the creator of the list should - ensure that each of them is released before deleting us -*/ -CBaseList::~CBaseList() -{ - /* Delete all our list nodes */ - - RemoveAll(); - -} // destructor - -/* Remove all the nodes from the list but don't do anything - with the objects that each node looks after (this is the - responsibility of the creator). - Aa a last act we reset the signalling event - (if available) to indicate to clients that the list - does not have any entries in it. -*/ -void CBaseList::RemoveAll() -{ - /* Free up all the CNode objects NOTE we don't bother putting the - deleted nodes into the cache as this method is only really called - in serious times of change such as when we are being deleted at - which point the cache will be deleted anway */ - - CNode *pn = m_pFirst; - while (pn) { - CNode *op = pn; - pn = pn->Next(); - delete op; - } - - /* Reset the object count and the list pointers */ - - m_Count = 0; - m_pFirst = m_pLast = NULL; - -} // RemoveAll - - - -/* Return a position enumerator for the entire list. - A position enumerator is a pointer to a node object cast to a - transparent type so all we do is return the head/tail node - pointer in the list. - WARNING because the position is a pointer to a node there is - an implicit assumption for users a the list class that after - deleting an object from the list that any other position - enumerators that you have may be invalid (since the node - may be gone). -*/ -__out_opt POSITION CBaseList::GetHeadPositionI() const -{ - return (POSITION) m_pFirst; -} // GetHeadPosition - - - -__out_opt POSITION CBaseList::GetTailPositionI() const -{ - return (POSITION) m_pLast; -} // GetTailPosition - - - -/* Get the number of objects in the list, - Get the lock before accessing the count. - Locking may not be entirely necessary but it has the side effect - of making sure that all operations are complete before we get it. - So for example if a list is being added to this list then that - will have completed in full before we continue rather than seeing - an intermediate albeit valid state -*/ -int CBaseList::GetCountI() const -{ - return m_Count; -} // GetCount - - - -/* Return the object at rp, update rp to the next object from - the list or NULL if you have moved over the last object. - You may still call this function once we return NULL but - we will continue to return a NULL position value -*/ -__out void *CBaseList::GetNextI(__inout POSITION& rp) const -{ - /* have we reached the end of the list */ - - if (rp == NULL) { - return NULL; - } - - /* Lock the object before continuing */ - - void *pObject; - - /* Copy the original position then step on */ - - CNode *pn = (CNode *) rp; - ASSERT(pn != NULL); - rp = (POSITION) pn->Next(); - - /* Get the object at the original position from the list */ - - pObject = pn->GetData(); - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - return pObject; -} //GetNext - - - -/* Return the object at p. - Asking for the object at NULL ASSERTs then returns NULL - The object is NOT locked. The list is not being changed - in any way. If another thread is busy deleting the object - then locking would only result in a change from one bad - behaviour to another. -*/ -__out_opt void *CBaseList::GetI(__in_opt POSITION p) const -{ - if (p == NULL) { - return NULL; - } - - CNode * pn = (CNode *) p; - void *pObject = pn->GetData(); - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - return pObject; -} //Get - -__out void *CBaseList::GetValidI(__in POSITION p) const -{ - CNode * pn = (CNode *) p; - void *pObject = pn->GetData(); - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - return pObject; -} //Get - - -/* Return the first position in the list which holds the given pointer. - Return NULL if it's not found. -*/ -__out_opt POSITION CBaseList::FindI( __in void * pObj) const -{ - POSITION pn; - INTERNALTRAVERSELIST(*this, pn){ - if (GetI(pn)==pObj) { - return pn; - } - } - return NULL; -} // Find - - - -/* Remove the first node in the list (deletes the pointer to its object - from the list, does not free the object itself). - Return the pointer to its object or NULL if empty -*/ -__out_opt void *CBaseList::RemoveHeadI() -{ - /* All we do is get the head position and ask for that to be deleted. - We could special case this since some of the code path checking - in Remove() is redundant as we know there is no previous - node for example but it seems to gain little over the - added complexity - */ - - return RemoveI((POSITION)m_pFirst); -} // RemoveHead - - - -/* Remove the last node in the list (deletes the pointer to its object - from the list, does not free the object itself). - Return the pointer to its object or NULL if empty -*/ -__out_opt void *CBaseList::RemoveTailI() -{ - /* All we do is get the tail position and ask for that to be deleted. - We could special case this since some of the code path checking - in Remove() is redundant as we know there is no previous - node for example but it seems to gain little over the - added complexity - */ - - return RemoveI((POSITION)m_pLast); -} // RemoveTail - - - -/* Remove the pointer to the object in this position from the list. - Deal with all the chain pointers - Return a pointer to the object removed from the list. - The node object that is freed as a result - of this operation is added to the node cache where - it can be used again. - Remove(NULL) is a harmless no-op - but probably is a wart. -*/ -__out_opt void *CBaseList::RemoveI(__in_opt POSITION pos) -{ - /* Lock the critical section before continuing */ - - // ASSERT (pos!=NULL); // Removing NULL is to be harmless! - if (pos==NULL) return NULL; - - - CNode *pCurrent = (CNode *) pos; - ASSERT(pCurrent != NULL); - - /* Update the previous node */ - - CNode *pNode = pCurrent->Prev(); - if (pNode == NULL) { - m_pFirst = pCurrent->Next(); - } else { - pNode->SetNext(pCurrent->Next()); - } - - /* Update the following node */ - - pNode = pCurrent->Next(); - if (pNode == NULL) { - m_pLast = pCurrent->Prev(); - } else { - pNode->SetPrev(pCurrent->Prev()); - } - - /* Get the object this node was looking after */ - - void *pObject = pCurrent->GetData(); - - // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. - - /* Try and add the node object to the cache - - a NULL return code from the cache means we ran out of room. - The cache size is fixed by a constructor argument when the - list is created and defaults to DEFAULTCACHE. - This means that the cache will have room for this many - node objects. So if you have a list of media samples - and you know there will never be more than five active at - any given time of them for example then override the default - constructor - */ - - m_Cache.AddToCache(pCurrent); - - /* If the list is empty then reset the list event */ - - --m_Count; - ASSERT(m_Count >= 0); - return pObject; -} // Remove - - - -/* Add this object to the tail end of our list - Return the new tail position. -*/ - -__out_opt POSITION CBaseList::AddTailI(__in void *pObject) -{ - /* Lock the critical section before continuing */ - - CNode *pNode; - // ASSERT(pObject); // NULL pointers in the list are allowed. - - /* If there is a node objects in the cache then use - that otherwise we will have to create a new one */ - - pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObject); - pNode->SetNext(NULL); - pNode->SetPrev(m_pLast); - - if (m_pLast == NULL) { - m_pFirst = pNode; - } else { - m_pLast->SetNext(pNode); - } - - /* Set the new last node pointer and also increment the number - of list entries, the critical section is unlocked when we - exit the function - */ - - m_pLast = pNode; - ++m_Count; - - return (POSITION) pNode; -} // AddTail(object) - - - -/* Add this object to the head end of our list - Return the new head position. -*/ -__out_opt POSITION CBaseList::AddHeadI(__in void *pObject) -{ - CNode *pNode; - // ASSERT(pObject); // NULL pointers in the list are allowed. - - /* If there is a node objects in the cache then use - that otherwise we will have to create a new one */ - - pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObject); - - /* chain it in (set four pointers) */ - pNode->SetPrev(NULL); - pNode->SetNext(m_pFirst); - - if (m_pFirst == NULL) { - m_pLast = pNode; - } else { - m_pFirst->SetPrev(pNode); - } - m_pFirst = pNode; - - ++m_Count; - - return (POSITION) pNode; -} // AddHead(object) - - - -/* Add all the elements in *pList to the tail of this list. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. -*/ -BOOL CBaseList::AddTail(__in CBaseList *pList) -{ - /* lock the object before starting then enumerate - each entry in the source list and add them one by one to - our list (while still holding the object lock) - Lock the other list too. - */ - POSITION pos = pList->GetHeadPositionI(); - - while (pos) { - if (NULL == AddTailI(pList->GetNextI(pos))) { - return FALSE; - } - } - return TRUE; -} // AddTail(list) - - - -/* Add all the elements in *pList to the head of this list. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. -*/ -BOOL CBaseList::AddHead(__in CBaseList *pList) -{ - /* lock the object before starting then enumerate - each entry in the source list and add them one by one to - our list (while still holding the object lock) - Lock the other list too. - - To avoid reversing the list, traverse it backwards. - */ - - POSITION pos; - - INTERNALREVERSETRAVERSELIST(*pList, pos) { - if (NULL== AddHeadI(pList->GetValidI(pos))){ - return FALSE; - } - } - return TRUE; -} // AddHead(list) - - - -/* Add the object after position p - p is still valid after the operation. - AddAfter(NULL,x) adds x to the start - same as AddHead - Return the position of the new object, NULL if it failed -*/ -__out_opt POSITION CBaseList::AddAfterI(__in_opt POSITION pos, __in void * pObj) -{ - if (pos==NULL) - return AddHeadI(pObj); - - /* As someone else might be furkling with the list - - Lock the critical section before continuing - */ - CNode *pAfter = (CNode *) pos; - ASSERT(pAfter != NULL); - if (pAfter==m_pLast) - return AddTailI(pObj); - - /* set pnode to point to a new node, preferably from the cache */ - - CNode *pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObj); - - /* It is to be added to the middle of the list - there is a before - and after node. Chain it after pAfter, before pBefore. - */ - CNode * pBefore = pAfter->Next(); - ASSERT(pBefore != NULL); - - /* chain it in (set four pointers) */ - pNode->SetPrev(pAfter); - pNode->SetNext(pBefore); - pBefore->SetPrev(pNode); - pAfter->SetNext(pNode); - - ++m_Count; - - return (POSITION) pNode; - -} // AddAfter(object) - - - -BOOL CBaseList::AddAfter(__in_opt POSITION p, __in CBaseList *pList) -{ - POSITION pos; - INTERNALTRAVERSELIST(*pList, pos) { - /* p follows along the elements being added */ - p = AddAfterI(p, pList->GetValidI(pos)); - if (p==NULL) return FALSE; - } - return TRUE; -} // AddAfter(list) - - - -/* Mirror images: - Add the element or list after position p. - p is still valid after the operation. - AddBefore(NULL,x) adds x to the end - same as AddTail -*/ -__out_opt POSITION CBaseList::AddBeforeI(__in_opt POSITION pos, __in void * pObj) -{ - if (pos==NULL) - return AddTailI(pObj); - - /* set pnode to point to a new node, preferably from the cache */ - - CNode *pBefore = (CNode *) pos; - ASSERT(pBefore != NULL); - if (pBefore==m_pFirst) - return AddHeadI(pObj); - - CNode * pNode = (CNode *) m_Cache.RemoveFromCache(); - if (pNode == NULL) { - pNode = new CNode; - } - - /* Check we have a valid object */ - - if (pNode == NULL) { - return NULL; - } - - /* Initialise all the CNode object - just in case it came from the cache - */ - - pNode->SetData(pObj); - - /* It is to be added to the middle of the list - there is a before - and after node. Chain it after pAfter, before pBefore. - */ - - CNode * pAfter = pBefore->Prev(); - ASSERT(pAfter != NULL); - - /* chain it in (set four pointers) */ - pNode->SetPrev(pAfter); - pNode->SetNext(pBefore); - pBefore->SetPrev(pNode); - pAfter->SetNext(pNode); - - ++m_Count; - - return (POSITION) pNode; - -} // Addbefore(object) - - - -BOOL CBaseList::AddBefore(__in_opt POSITION p, __in CBaseList *pList) -{ - POSITION pos; - INTERNALREVERSETRAVERSELIST(*pList, pos) { - /* p follows along the elements being added */ - p = AddBeforeI(p, pList->GetValidI(pos)); - if (p==NULL) return FALSE; - } - return TRUE; -} // AddBefore(list) - - - -/* Split *this after position p in *this - Retain as *this the tail portion of the original *this - Add the head portion to the tail end of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToTail(foo->GetHeadPosition(), bar); - moves one element from the head of foo to the tail of bar - foo->MoveToTail(NULL, bar); - is a no-op - foo->MoveToTail(foo->GetTailPosition, bar); - concatenates foo onto the end of bar and empties foo. - - A better, except excessively long name might be - MoveElementsFromHeadThroughPositionToOtherTail -*/ -BOOL CBaseList::MoveToTail - (__in_opt POSITION pos, __in CBaseList *pList) -{ - /* Algorithm: - Note that the elements (including their order) in the concatenation - of *pList to the head of *this is invariant. - 1. Count elements to be moved - 2. Join *pList onto the head of this to make one long chain - 3. Set first/Last pointers in *this and *pList - 4. Break the chain at the new place - 5. Adjust counts - 6. Set/Reset any events - */ - - if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. - - - /* Make cMove the number of nodes to move */ - CNode * p = (CNode *)pos; - int cMove = 0; // number of nodes to move - while(p!=NULL) { - p = p->Prev(); - ++cMove; - } - - - /* Join the two chains together */ - if (pList->m_pLast!=NULL) - pList->m_pLast->SetNext(m_pFirst); - if (m_pFirst!=NULL) - m_pFirst->SetPrev(pList->m_pLast); - - - /* set first and last pointers */ - p = (CNode *)pos; - - if (pList->m_pFirst==NULL) - pList->m_pFirst = m_pFirst; - m_pFirst = p->Next(); - if (m_pFirst==NULL) - m_pLast = NULL; - pList->m_pLast = p; - - - /* Break the chain after p to create the new pieces */ - if (m_pFirst!=NULL) - m_pFirst->SetPrev(NULL); - p->SetNext(NULL); - - - /* Adjust the counts */ - m_Count -= cMove; - pList->m_Count += cMove; - - return TRUE; - -} // MoveToTail - - - -/* Mirror image of MoveToTail: - Split *this before position p in *this. - Retain in *this the head portion of the original *this - Add the tail portion to the start (i.e. head) of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToHead(foo->GetTailPosition(), bar); - moves one element from the tail of foo to the head of bar - foo->MoveToHead(NULL, bar); - is a no-op - foo->MoveToHead(foo->GetHeadPosition, bar); - concatenates foo onto the start of bar and empties foo. -*/ -BOOL CBaseList::MoveToHead - (__in_opt POSITION pos, __in CBaseList *pList) -{ - - /* See the comments on the algorithm in MoveToTail */ - - if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. - - /* Make cMove the number of nodes to move */ - CNode * p = (CNode *)pos; - int cMove = 0; // number of nodes to move - while(p!=NULL) { - p = p->Next(); - ++cMove; - } - - - /* Join the two chains together */ - if (pList->m_pFirst!=NULL) - pList->m_pFirst->SetPrev(m_pLast); - if (m_pLast!=NULL) - m_pLast->SetNext(pList->m_pFirst); - - - /* set first and last pointers */ - p = (CNode *)pos; - - - if (pList->m_pLast==NULL) - pList->m_pLast = m_pLast; - - m_pLast = p->Prev(); - if (m_pLast==NULL) - m_pFirst = NULL; - pList->m_pFirst = p; - - - /* Break the chain after p to create the new pieces */ - if (m_pLast!=NULL) - m_pLast->SetNext(NULL); - p->SetPrev(NULL); - - - /* Adjust the counts */ - m_Count -= cMove; - pList->m_Count += cMove; - - return TRUE; - -} // MoveToHead - - - -/* Reverse the order of the [pointers to] objects in *this -*/ -void CBaseList::Reverse() -{ - /* algorithm: - The obvious booby trap is that you flip pointers around and lose - addressability to the node that you are going to process next. - The easy way to avoid this is do do one chain at a time. - - Run along the forward chain, - For each node, set the reverse pointer to the one ahead of us. - The reverse chain is now a copy of the old forward chain, including - the NULL termination. - - Run along the reverse chain (i.e. old forward chain again) - For each node set the forward pointer of the node ahead to point back - to the one we're standing on. - The first node needs special treatment, - it's new forward pointer is NULL. - Finally set the First/Last pointers - - */ - CNode * p; - - // Yes we COULD use a traverse, but it would look funny! - p = m_pFirst; - while (p!=NULL) { - CNode * q; - q = p->Next(); - p->SetNext(p->Prev()); - p->SetPrev(q); - p = q; - } - - p = m_pFirst; - m_pFirst = m_pLast; - m_pLast = p; - - -#if 0 // old version - - if (m_pFirst==NULL) return; // empty list - if (m_pFirst->Next()==NULL) return; // single node list - - - /* run along forward chain */ - for ( p = m_pFirst - ; p!=NULL - ; p = p->Next() - ){ - p->SetPrev(p->Next()); - } - - - /* special case first element */ - m_pFirst->SetNext(NULL); // fix the old first element - - - /* run along new reverse chain i.e. old forward chain again */ - for ( p = m_pFirst // start at the old first element - ; p->Prev()!=NULL // while there's a node still to be set - ; p = p->Prev() // work in the same direction as before - ){ - p->Prev()->SetNext(p); - } - - - /* fix forward and reverse pointers - - the triple XOR swap would work but all the casts look hideous */ - p = m_pFirst; - m_pFirst = m_pLast; - m_pLast = p; -#endif - -} // Reverse +//------------------------------------------------------------------------------ +// File: WXList.cpp +// +// Desc: DirectShow base classes - implements a non-MFC based generic list +// template class. +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* A generic list of pointers to objects. + Objectives: avoid using MFC libraries in ndm kernel mode and + provide a really useful list type. + + The class is thread safe in that separate threads may add and + delete items in the list concurrently although the application + must ensure that constructor and destructor access is suitably + synchronised. + + The list name must not conflict with MFC classes as an + application may use both + + The nodes form a doubly linked, NULL terminated chain with an anchor + block (the list object per se) holding pointers to the first and last + nodes and a count of the nodes. + There is a node cache to reduce the allocation and freeing overhead. + It optionally (determined at construction time) has an Event which is + set whenever the list becomes non-empty and reset whenever it becomes + empty. + It optionally (determined at construction time) has a Critical Section + which is entered during the important part of each operation. (About + all you can do outside it is some parameter checking). + + The node cache is a repository of nodes that are NOT in the list to speed + up storage allocation. Each list has its own cache to reduce locking and + serialising. The list accesses are serialised anyway for a given list - a + common cache would mean that we would have to separately serialise access + of all lists within the cache. Because the cache only stores nodes that are + not in the list, releasing the cache does not release any list nodes. This + means that list nodes can be copied or rechained from one list to another + without danger of creating a dangling reference if the original cache goes + away. + + Questionable design decisions: + 1. Retaining the warts for compatibility + 2. Keeping an element count -i.e. counting whenever we do anything + instead of only when we want the count. + 3. Making the chain pointers NULL terminated. If the list object + itself looks just like a node and the list is kept as a ring then + it reduces the number of special cases. All inserts look the same. +*/ + + +#include "streams.h" + +/* set cursor to the position of each element of list in turn */ +#define INTERNALTRAVERSELIST(list, cursor) \ +for ( cursor = (list).GetHeadPositionI() \ + ; cursor!=NULL \ + ; cursor = (list).Next(cursor) \ + ) + + +/* set cursor to the position of each element of list in turn + in reverse order +*/ +#define INTERNALREVERSETRAVERSELIST(list, cursor) \ +for ( cursor = (list).GetTailPositionI() \ + ; cursor!=NULL \ + ; cursor = (list).Prev(cursor) \ + ) + +/* Constructor calls a separate initialisation function that + creates a node cache, optionally creates a lock object + and optionally creates a signaling object. + + By default we create a locking object, a DEFAULTCACHE sized + cache but no event object so the list cannot be used in calls + to WaitForSingleObject +*/ +CBaseList::CBaseList(__in_opt LPCTSTR pName, // Descriptive list name + INT iItems) : // Node cache size +#ifdef _DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(iItems) +{ +} // constructor + +CBaseList::CBaseList(__in_opt LPCTSTR pName) : // Descriptive list name +#ifdef _DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(DEFAULTCACHE) +{ +} // constructor + +#ifdef UNICODE +CBaseList::CBaseList(__in_opt LPCSTR pName, // Descriptive list name + INT iItems) : // Node cache size +#ifdef _DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(iItems) +{ +} // constructor + +CBaseList::CBaseList(__in_opt LPCSTR pName) : // Descriptive list name +#ifdef _DEBUG + CBaseObject(pName), +#endif + m_pFirst(NULL), + m_pLast(NULL), + m_Count(0), + m_Cache(DEFAULTCACHE) +{ +} // constructor + +#endif + +/* The destructor enumerates all the node objects in the list and + in the cache deleting each in turn. We do not do any processing + on the objects that the list holds (i.e. points to) so if they + represent interfaces for example the creator of the list should + ensure that each of them is released before deleting us +*/ +CBaseList::~CBaseList() +{ + /* Delete all our list nodes */ + + RemoveAll(); + +} // destructor + +/* Remove all the nodes from the list but don't do anything + with the objects that each node looks after (this is the + responsibility of the creator). + Aa a last act we reset the signalling event + (if available) to indicate to clients that the list + does not have any entries in it. +*/ +void CBaseList::RemoveAll() +{ + /* Free up all the CNode objects NOTE we don't bother putting the + deleted nodes into the cache as this method is only really called + in serious times of change such as when we are being deleted at + which point the cache will be deleted anway */ + + CNode *pn = m_pFirst; + while (pn) { + CNode *op = pn; + pn = pn->Next(); + delete op; + } + + /* Reset the object count and the list pointers */ + + m_Count = 0; + m_pFirst = m_pLast = NULL; + +} // RemoveAll + + + +/* Return a position enumerator for the entire list. + A position enumerator is a pointer to a node object cast to a + transparent type so all we do is return the head/tail node + pointer in the list. + WARNING because the position is a pointer to a node there is + an implicit assumption for users a the list class that after + deleting an object from the list that any other position + enumerators that you have may be invalid (since the node + may be gone). +*/ +__out_opt POSITION CBaseList::GetHeadPositionI() const +{ + return (POSITION) m_pFirst; +} // GetHeadPosition + + + +__out_opt POSITION CBaseList::GetTailPositionI() const +{ + return (POSITION) m_pLast; +} // GetTailPosition + + + +/* Get the number of objects in the list, + Get the lock before accessing the count. + Locking may not be entirely necessary but it has the side effect + of making sure that all operations are complete before we get it. + So for example if a list is being added to this list then that + will have completed in full before we continue rather than seeing + an intermediate albeit valid state +*/ +int CBaseList::GetCountI() const +{ + return m_Count; +} // GetCount + + + +/* Return the object at rp, update rp to the next object from + the list or NULL if you have moved over the last object. + You may still call this function once we return NULL but + we will continue to return a NULL position value +*/ +__out void *CBaseList::GetNextI(__inout POSITION& rp) const +{ + /* have we reached the end of the list */ + + if (rp == NULL) { + return NULL; + } + + /* Lock the object before continuing */ + + void *pObject; + + /* Copy the original position then step on */ + + CNode *pn = (CNode *) rp; + ASSERT(pn != NULL); + rp = (POSITION) pn->Next(); + + /* Get the object at the original position from the list */ + + pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //GetNext + + + +/* Return the object at p. + Asking for the object at NULL ASSERTs then returns NULL + The object is NOT locked. The list is not being changed + in any way. If another thread is busy deleting the object + then locking would only result in a change from one bad + behaviour to another. +*/ +__out_opt void *CBaseList::GetI(__in_opt POSITION p) const +{ + if (p == NULL) { + return NULL; + } + + CNode * pn = (CNode *) p; + void *pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //Get + +__out void *CBaseList::GetValidI(__in POSITION p) const +{ + CNode * pn = (CNode *) p; + void *pObject = pn->GetData(); + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + return pObject; +} //Get + + +/* Return the first position in the list which holds the given pointer. + Return NULL if it's not found. +*/ +__out_opt POSITION CBaseList::FindI( __in void * pObj) const +{ + POSITION pn; + INTERNALTRAVERSELIST(*this, pn){ + if (GetI(pn)==pObj) { + return pn; + } + } + return NULL; +} // Find + + + +/* Remove the first node in the list (deletes the pointer to its object + from the list, does not free the object itself). + Return the pointer to its object or NULL if empty +*/ +__out_opt void *CBaseList::RemoveHeadI() +{ + /* All we do is get the head position and ask for that to be deleted. + We could special case this since some of the code path checking + in Remove() is redundant as we know there is no previous + node for example but it seems to gain little over the + added complexity + */ + + return RemoveI((POSITION)m_pFirst); +} // RemoveHead + + + +/* Remove the last node in the list (deletes the pointer to its object + from the list, does not free the object itself). + Return the pointer to its object or NULL if empty +*/ +__out_opt void *CBaseList::RemoveTailI() +{ + /* All we do is get the tail position and ask for that to be deleted. + We could special case this since some of the code path checking + in Remove() is redundant as we know there is no previous + node for example but it seems to gain little over the + added complexity + */ + + return RemoveI((POSITION)m_pLast); +} // RemoveTail + + + +/* Remove the pointer to the object in this position from the list. + Deal with all the chain pointers + Return a pointer to the object removed from the list. + The node object that is freed as a result + of this operation is added to the node cache where + it can be used again. + Remove(NULL) is a harmless no-op - but probably is a wart. +*/ +__out_opt void *CBaseList::RemoveI(__in_opt POSITION pos) +{ + /* Lock the critical section before continuing */ + + // ASSERT (pos!=NULL); // Removing NULL is to be harmless! + if (pos==NULL) return NULL; + + + CNode *pCurrent = (CNode *) pos; + ASSERT(pCurrent != NULL); + + /* Update the previous node */ + + CNode *pNode = pCurrent->Prev(); + if (pNode == NULL) { + m_pFirst = pCurrent->Next(); + } else { + pNode->SetNext(pCurrent->Next()); + } + + /* Update the following node */ + + pNode = pCurrent->Next(); + if (pNode == NULL) { + m_pLast = pCurrent->Prev(); + } else { + pNode->SetPrev(pCurrent->Prev()); + } + + /* Get the object this node was looking after */ + + void *pObject = pCurrent->GetData(); + + // ASSERT(pObject != NULL); // NULL pointers in the list are allowed. + + /* Try and add the node object to the cache - + a NULL return code from the cache means we ran out of room. + The cache size is fixed by a constructor argument when the + list is created and defaults to DEFAULTCACHE. + This means that the cache will have room for this many + node objects. So if you have a list of media samples + and you know there will never be more than five active at + any given time of them for example then override the default + constructor + */ + + m_Cache.AddToCache(pCurrent); + + /* If the list is empty then reset the list event */ + + --m_Count; + ASSERT(m_Count >= 0); + return pObject; +} // Remove + + + +/* Add this object to the tail end of our list + Return the new tail position. +*/ + +__out_opt POSITION CBaseList::AddTailI(__in void *pObject) +{ + /* Lock the critical section before continuing */ + + CNode *pNode; + // ASSERT(pObject); // NULL pointers in the list are allowed. + + /* If there is a node objects in the cache then use + that otherwise we will have to create a new one */ + + pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObject); + pNode->SetNext(NULL); + pNode->SetPrev(m_pLast); + + if (m_pLast == NULL) { + m_pFirst = pNode; + } else { + m_pLast->SetNext(pNode); + } + + /* Set the new last node pointer and also increment the number + of list entries, the critical section is unlocked when we + exit the function + */ + + m_pLast = pNode; + ++m_Count; + + return (POSITION) pNode; +} // AddTail(object) + + + +/* Add this object to the head end of our list + Return the new head position. +*/ +__out_opt POSITION CBaseList::AddHeadI(__in void *pObject) +{ + CNode *pNode; + // ASSERT(pObject); // NULL pointers in the list are allowed. + + /* If there is a node objects in the cache then use + that otherwise we will have to create a new one */ + + pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObject); + + /* chain it in (set four pointers) */ + pNode->SetPrev(NULL); + pNode->SetNext(m_pFirst); + + if (m_pFirst == NULL) { + m_pLast = pNode; + } else { + m_pFirst->SetPrev(pNode); + } + m_pFirst = pNode; + + ++m_Count; + + return (POSITION) pNode; +} // AddHead(object) + + + +/* Add all the elements in *pList to the tail of this list. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. +*/ +BOOL CBaseList::AddTail(__in CBaseList *pList) +{ + /* lock the object before starting then enumerate + each entry in the source list and add them one by one to + our list (while still holding the object lock) + Lock the other list too. + */ + POSITION pos = pList->GetHeadPositionI(); + + while (pos) { + if (NULL == AddTailI(pList->GetNextI(pos))) { + return FALSE; + } + } + return TRUE; +} // AddTail(list) + + + +/* Add all the elements in *pList to the head of this list. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. +*/ +BOOL CBaseList::AddHead(__in CBaseList *pList) +{ + /* lock the object before starting then enumerate + each entry in the source list and add them one by one to + our list (while still holding the object lock) + Lock the other list too. + + To avoid reversing the list, traverse it backwards. + */ + + POSITION pos; + + INTERNALREVERSETRAVERSELIST(*pList, pos) { + if (NULL== AddHeadI(pList->GetValidI(pos))){ + return FALSE; + } + } + return TRUE; +} // AddHead(list) + + + +/* Add the object after position p + p is still valid after the operation. + AddAfter(NULL,x) adds x to the start - same as AddHead + Return the position of the new object, NULL if it failed +*/ +__out_opt POSITION CBaseList::AddAfterI(__in_opt POSITION pos, __in void * pObj) +{ + if (pos==NULL) + return AddHeadI(pObj); + + /* As someone else might be furkling with the list - + Lock the critical section before continuing + */ + CNode *pAfter = (CNode *) pos; + ASSERT(pAfter != NULL); + if (pAfter==m_pLast) + return AddTailI(pObj); + + /* set pnode to point to a new node, preferably from the cache */ + + CNode *pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObj); + + /* It is to be added to the middle of the list - there is a before + and after node. Chain it after pAfter, before pBefore. + */ + CNode * pBefore = pAfter->Next(); + ASSERT(pBefore != NULL); + + /* chain it in (set four pointers) */ + pNode->SetPrev(pAfter); + pNode->SetNext(pBefore); + pBefore->SetPrev(pNode); + pAfter->SetNext(pNode); + + ++m_Count; + + return (POSITION) pNode; + +} // AddAfter(object) + + + +BOOL CBaseList::AddAfter(__in_opt POSITION p, __in CBaseList *pList) +{ + POSITION pos; + INTERNALTRAVERSELIST(*pList, pos) { + /* p follows along the elements being added */ + p = AddAfterI(p, pList->GetValidI(pos)); + if (p==NULL) return FALSE; + } + return TRUE; +} // AddAfter(list) + + + +/* Mirror images: + Add the element or list after position p. + p is still valid after the operation. + AddBefore(NULL,x) adds x to the end - same as AddTail +*/ +__out_opt POSITION CBaseList::AddBeforeI(__in_opt POSITION pos, __in void * pObj) +{ + if (pos==NULL) + return AddTailI(pObj); + + /* set pnode to point to a new node, preferably from the cache */ + + CNode *pBefore = (CNode *) pos; + ASSERT(pBefore != NULL); + if (pBefore==m_pFirst) + return AddHeadI(pObj); + + CNode * pNode = (CNode *) m_Cache.RemoveFromCache(); + if (pNode == NULL) { + pNode = new CNode; + } + + /* Check we have a valid object */ + + if (pNode == NULL) { + return NULL; + } + + /* Initialise all the CNode object + just in case it came from the cache + */ + + pNode->SetData(pObj); + + /* It is to be added to the middle of the list - there is a before + and after node. Chain it after pAfter, before pBefore. + */ + + CNode * pAfter = pBefore->Prev(); + ASSERT(pAfter != NULL); + + /* chain it in (set four pointers) */ + pNode->SetPrev(pAfter); + pNode->SetNext(pBefore); + pBefore->SetPrev(pNode); + pAfter->SetNext(pNode); + + ++m_Count; + + return (POSITION) pNode; + +} // Addbefore(object) + + + +BOOL CBaseList::AddBefore(__in_opt POSITION p, __in CBaseList *pList) +{ + POSITION pos; + INTERNALREVERSETRAVERSELIST(*pList, pos) { + /* p follows along the elements being added */ + p = AddBeforeI(p, pList->GetValidI(pos)); + if (p==NULL) return FALSE; + } + return TRUE; +} // AddBefore(list) + + + +/* Split *this after position p in *this + Retain as *this the tail portion of the original *this + Add the head portion to the tail end of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToTail(foo->GetHeadPosition(), bar); + moves one element from the head of foo to the tail of bar + foo->MoveToTail(NULL, bar); + is a no-op + foo->MoveToTail(foo->GetTailPosition, bar); + concatenates foo onto the end of bar and empties foo. + + A better, except excessively long name might be + MoveElementsFromHeadThroughPositionToOtherTail +*/ +BOOL CBaseList::MoveToTail + (__in_opt POSITION pos, __in CBaseList *pList) +{ + /* Algorithm: + Note that the elements (including their order) in the concatenation + of *pList to the head of *this is invariant. + 1. Count elements to be moved + 2. Join *pList onto the head of this to make one long chain + 3. Set first/Last pointers in *this and *pList + 4. Break the chain at the new place + 5. Adjust counts + 6. Set/Reset any events + */ + + if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. + + + /* Make cMove the number of nodes to move */ + CNode * p = (CNode *)pos; + int cMove = 0; // number of nodes to move + while(p!=NULL) { + p = p->Prev(); + ++cMove; + } + + + /* Join the two chains together */ + if (pList->m_pLast!=NULL) + pList->m_pLast->SetNext(m_pFirst); + if (m_pFirst!=NULL) + m_pFirst->SetPrev(pList->m_pLast); + + + /* set first and last pointers */ + p = (CNode *)pos; + + if (pList->m_pFirst==NULL) + pList->m_pFirst = m_pFirst; + m_pFirst = p->Next(); + if (m_pFirst==NULL) + m_pLast = NULL; + pList->m_pLast = p; + + + /* Break the chain after p to create the new pieces */ + if (m_pFirst!=NULL) + m_pFirst->SetPrev(NULL); + p->SetNext(NULL); + + + /* Adjust the counts */ + m_Count -= cMove; + pList->m_Count += cMove; + + return TRUE; + +} // MoveToTail + + + +/* Mirror image of MoveToTail: + Split *this before position p in *this. + Retain in *this the head portion of the original *this + Add the tail portion to the start (i.e. head) of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToHead(foo->GetTailPosition(), bar); + moves one element from the tail of foo to the head of bar + foo->MoveToHead(NULL, bar); + is a no-op + foo->MoveToHead(foo->GetHeadPosition, bar); + concatenates foo onto the start of bar and empties foo. +*/ +BOOL CBaseList::MoveToHead + (__in_opt POSITION pos, __in CBaseList *pList) +{ + + /* See the comments on the algorithm in MoveToTail */ + + if (pos==NULL) return TRUE; // no-op. Eliminates special cases later. + + /* Make cMove the number of nodes to move */ + CNode * p = (CNode *)pos; + int cMove = 0; // number of nodes to move + while(p!=NULL) { + p = p->Next(); + ++cMove; + } + + + /* Join the two chains together */ + if (pList->m_pFirst!=NULL) + pList->m_pFirst->SetPrev(m_pLast); + if (m_pLast!=NULL) + m_pLast->SetNext(pList->m_pFirst); + + + /* set first and last pointers */ + p = (CNode *)pos; + + + if (pList->m_pLast==NULL) + pList->m_pLast = m_pLast; + + m_pLast = p->Prev(); + if (m_pLast==NULL) + m_pFirst = NULL; + pList->m_pFirst = p; + + + /* Break the chain after p to create the new pieces */ + if (m_pLast!=NULL) + m_pLast->SetNext(NULL); + p->SetPrev(NULL); + + + /* Adjust the counts */ + m_Count -= cMove; + pList->m_Count += cMove; + + return TRUE; + +} // MoveToHead + + + +/* Reverse the order of the [pointers to] objects in *this +*/ +void CBaseList::Reverse() +{ + /* algorithm: + The obvious booby trap is that you flip pointers around and lose + addressability to the node that you are going to process next. + The easy way to avoid this is do do one chain at a time. + + Run along the forward chain, + For each node, set the reverse pointer to the one ahead of us. + The reverse chain is now a copy of the old forward chain, including + the NULL termination. + + Run along the reverse chain (i.e. old forward chain again) + For each node set the forward pointer of the node ahead to point back + to the one we're standing on. + The first node needs special treatment, + it's new forward pointer is NULL. + Finally set the First/Last pointers + + */ + CNode * p; + + // Yes we COULD use a traverse, but it would look funny! + p = m_pFirst; + while (p!=NULL) { + CNode * q; + q = p->Next(); + p->SetNext(p->Prev()); + p->SetPrev(q); + p = q; + } + + p = m_pFirst; + m_pFirst = m_pLast; + m_pLast = p; + + +#if 0 // old version + + if (m_pFirst==NULL) return; // empty list + if (m_pFirst->Next()==NULL) return; // single node list + + + /* run along forward chain */ + for ( p = m_pFirst + ; p!=NULL + ; p = p->Next() + ){ + p->SetPrev(p->Next()); + } + + + /* special case first element */ + m_pFirst->SetNext(NULL); // fix the old first element + + + /* run along new reverse chain i.e. old forward chain again */ + for ( p = m_pFirst // start at the old first element + ; p->Prev()!=NULL // while there's a node still to be set + ; p = p->Prev() // work in the same direction as before + ){ + p->Prev()->SetNext(p); + } + + + /* fix forward and reverse pointers + - the triple XOR swap would work but all the casts look hideous */ + p = m_pFirst; + m_pFirst = m_pLast; + m_pLast = p; +#endif + +} // Reverse diff --git a/src/thirdparty/BaseClasses/wxlist.h b/src/thirdparty/BaseClasses/wxlist.h index 43b3d855531..4cb8194463a 100644 --- a/src/thirdparty/BaseClasses/wxlist.h +++ b/src/thirdparty/BaseClasses/wxlist.h @@ -1,553 +1,553 @@ -//------------------------------------------------------------------------------ -// File: WXList.h -// -// Desc: DirectShow base classes - defines a non-MFC generic template list -// class. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -/* A generic list of pointers to objects. - No storage management or copying is done on the objects pointed to. - Objectives: avoid using MFC libraries in ndm kernel mode and - provide a really useful list type. - - The class is thread safe in that separate threads may add and - delete items in the list concurrently although the application - must ensure that constructor and destructor access is suitably - synchronised. An application can cause deadlock with operations - which use two lists by simultaneously calling - list1->Operation(list2) and list2->Operation(list1). So don't! - - The names must not conflict with MFC classes as an application - may use both. - */ - -#ifndef __WXLIST__ -#define __WXLIST__ - - /* A POSITION represents (in some fashion that's opaque) a cursor - on the list that can be set to identify any element. NULL is - a valid value and several operations regard NULL as the position - "one step off the end of the list". (In an n element list there - are n+1 places to insert and NULL is that "n+1-th" value). - The POSITION of an element in the list is only invalidated if - that element is deleted. Move operations may mean that what - was a valid POSITION in one list is now a valid POSITION in - a different list. - - Some operations which at first sight are illegal are allowed as - harmless no-ops. For instance RemoveHead is legal on an empty - list and it returns NULL. This allows an atomic way to test if - there is an element there, and if so, get it. The two operations - AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper). - - Single element operations return POSITIONs, non-NULL means it worked. - whole list operations return a BOOL. TRUE means it all worked. - - This definition is the same as the POSITION type for MFCs, so we must - avoid defining it twice. - */ -#ifndef __AFX_H__ -struct __POSITION { int unused; }; -typedef __POSITION* POSITION; -#endif - -const int DEFAULTCACHE = 10; /* Default node object cache size */ - -/* A class representing one node in a list. - Each node knows a pointer to it's adjacent nodes and also a pointer - to the object that it looks after. - All of these pointers can be retrieved or set through member functions. -*/ -class CBaseList -#ifdef _DEBUG - : public CBaseObject -#endif -{ - /* Making these classes inherit from CBaseObject does nothing - functionally but it allows us to check there are no memory - leaks in debug builds. - */ - -public: - -#ifdef _DEBUG - class CNode : public CBaseObject { -#else - class CNode { -#endif - - CNode *m_pPrev = NULL; /* Previous node in the list */ - CNode *m_pNext = NULL; /* Next node in the list */ - void *m_pObject = NULL; /* Pointer to the object */ - - public: - - /* Constructor - initialise the object's pointers */ - CNode() -#ifdef _DEBUG - : CBaseObject(NAME("List node")) -#endif - { - }; - - - /* Return the previous node before this one */ - __out CNode *Prev() const { return m_pPrev; }; - - - /* Return the next node after this one */ - __out CNode *Next() const { return m_pNext; }; - - - /* Set the previous node before this one */ - void SetPrev(__in_opt CNode *p) { m_pPrev = p; }; - - - /* Set the next node after this one */ - void SetNext(__in_opt CNode *p) { m_pNext = p; }; - - - /* Get the pointer to the object for this node */ - __out void *GetData() const { return m_pObject; }; - - - /* Set the pointer to the object for this node */ - void SetData(__in void *p) { m_pObject = p; }; - }; - - class CNodeCache - { - public: - CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize), - m_pHead(NULL), - m_iUsed(0) - {}; - ~CNodeCache() { - CNode *pNode = m_pHead; - while (pNode) { - CNode *pCurrent = pNode; - pNode = pNode->Next(); - delete pCurrent; - } - }; - void AddToCache(__inout CNode *pNode) - { - if (m_iUsed < m_iCacheSize) { - pNode->SetNext(m_pHead); - m_pHead = pNode; - m_iUsed++; - } else { - delete pNode; - } - }; - CNode *RemoveFromCache() - { - CNode *pNode = m_pHead; - if (pNode != NULL) { - m_pHead = pNode->Next(); - m_iUsed--; - ASSERT(m_iUsed >= 0); - } else { - ASSERT(m_iUsed == 0); - } - return pNode; - }; - private: - INT m_iCacheSize; - INT m_iUsed; - CNode *m_pHead; - }; - -protected: - - CNode* m_pFirst; /* Pointer to first node in the list */ - CNode* m_pLast; /* Pointer to the last node in the list */ - LONG m_Count; /* Number of nodes currently in the list */ - -private: - - CNodeCache m_Cache; /* Cache of unused node pointers */ - -private: - - /* These override the default copy constructor and assignment - operator for all list classes. They are in the private class - declaration section so that anybody trying to pass a list - object by value will generate a compile time error of - "cannot access the private member function". If these were - not here then the compiler will create default constructors - and assignment operators which when executed first take a - copy of all member variables and then during destruction - delete them all. This must not be done for any heap - allocated data. - */ - CBaseList(const CBaseList &refList); - CBaseList &operator=(const CBaseList &refList); - -public: - - CBaseList(__in_opt LPCTSTR pName, - INT iItems); - - CBaseList(__in_opt LPCTSTR pName); -#ifdef UNICODE - CBaseList(__in_opt LPCSTR pName, - INT iItems); - - CBaseList(__in_opt LPCSTR pName); -#endif - ~CBaseList(); - - /* Remove all the nodes from *this i.e. make the list empty */ - void RemoveAll(); - - - /* Return a cursor which identifies the first element of *this */ - __out_opt POSITION GetHeadPositionI() const; - - - /* Return a cursor which identifies the last element of *this */ - __out_opt POSITION GetTailPositionI() const; - - - /* Return the number of objects in *this */ - int GetCountI() const; - -protected: - /* Return the pointer to the object at rp, - Update rp to the next node in *this - but make it NULL if it was at the end of *this. - This is a wart retained for backwards compatibility. - GetPrev is not implemented. - Use Next, Prev and Get separately. - */ - __out void *GetNextI(__inout POSITION& rp) const; - - - /* Return a pointer to the object at p - Asking for the object at NULL will return NULL harmlessly. - */ - __out_opt void *GetI(__in_opt POSITION p) const; - __out void *GetValidI(__in POSITION p) const; - -public: - /* return the next / prev position in *this - return NULL when going past the end/start. - Next(NULL) is same as GetHeadPosition() - Prev(NULL) is same as GetTailPosition() - An n element list therefore behaves like a n+1 element - cycle with NULL at the start/end. - - !!WARNING!! - This handling of NULL is DIFFERENT from GetNext. - - Some reasons are: - 1. For a list of n items there are n+1 positions to insert - These are conveniently encoded as the n POSITIONs and NULL. - 2. If you are keeping a list sorted (fairly common) and you - search forward for an element to insert before and don't - find it you finish up with NULL as the element before which - to insert. You then want that NULL to be a valid POSITION - so that you can insert before it and you want that insertion - point to mean the (n+1)-th one that doesn't have a POSITION. - (symmetrically if you are working backwards through the list). - 3. It simplifies the algebra which the methods generate. - e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x) - in ALL cases. All the other arguments probably are reflections - of the algebraic point. - */ - __out_opt POSITION Next(__in_opt POSITION pos) const - { - if (pos == NULL) { - return (POSITION) m_pFirst; - } - CNode *pn = (CNode *) pos; - return (POSITION) pn->Next(); - } //Next - - // See Next - __out_opt POSITION Prev(__in_opt POSITION pos) const - { - if (pos == NULL) { - return (POSITION) m_pLast; - } - CNode *pn = (CNode *) pos; - return (POSITION) pn->Prev(); - } //Prev - - - /* Return the first position in *this which holds the given - pointer. Return NULL if the pointer was not not found. - */ -protected: - __out_opt POSITION FindI( __in void * pObj) const; - - // ??? Should there be (or even should there be only) - // ??? POSITION FindNextAfter(void * pObj, POSITION p) - // ??? And of course FindPrevBefore too. - // ??? List.Find(&Obj) then becomes List.FindNextAfter(&Obj, NULL) - - - /* Remove the first node in *this (deletes the pointer to its - object from the list, does not free the object itself). - Return the pointer to its object. - If *this was already empty it will harmlessly return NULL. - */ - __out_opt void *RemoveHeadI(); - - - /* Remove the last node in *this (deletes the pointer to its - object from the list, does not free the object itself). - Return the pointer to its object. - If *this was already empty it will harmlessly return NULL. - */ - __out_opt void *RemoveTailI(); - - - /* Remove the node identified by p from the list (deletes the pointer - to its object from the list, does not free the object itself). - Asking to Remove the object at NULL will harmlessly return NULL. - Return the pointer to the object removed. - */ - __out_opt void *RemoveI(__in_opt POSITION p); - - /* Add single object *pObj to become a new last element of the list. - Return the new tail position, NULL if it fails. - If you are adding a COM objects, you might want AddRef it first. - Other existing POSITIONs in *this are still valid - */ - __out_opt POSITION AddTailI(__in void * pObj); -public: - - - /* Add all the elements in *pList to the tail of *this. - This duplicates all the nodes in *pList (i.e. duplicates - all its pointers to objects). It does not duplicate the objects. - If you are adding a list of pointers to a COM object into the list - it's a good idea to AddRef them all it when you AddTail it. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some elements may have been added. - Existing POSITIONs in *this are still valid - - If you actually want to MOVE the elements, use MoveToTail instead. - */ - BOOL AddTail(__in CBaseList *pList); - - - /* Mirror images of AddHead: */ - - /* Add single object to become a new first element of the list. - Return the new head position, NULL if it fails. - Existing POSITIONs in *this are still valid - */ -protected: - __out_opt POSITION AddHeadI(__in void * pObj); -public: - - /* Add all the elements in *pList to the head of *this. - Same warnings apply as for AddTail. - Return TRUE if it all worked, FALSE if it didn't. - If it fails some of the objects may have been added. - - If you actually want to MOVE the elements, use MoveToHead instead. - */ - BOOL AddHead(__in CBaseList *pList); - - - /* Add the object *pObj to *this after position p in *this. - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return the position of the object added, NULL if it failed. - Existing POSITIONs in *this are undisturbed, including p. - */ -protected: - __out_opt POSITION AddAfterI(__in_opt POSITION p, __in void * pObj); -public: - - /* Add the list *pList to *this after position p in *this - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return TRUE if it all worked, FALSE if it didn't. - If it fails, some of the objects may be added - Existing POSITIONs in *this are undisturbed, including p. - */ - BOOL AddAfter(__in_opt POSITION p, __in CBaseList *pList); - - - /* Mirror images: - Add the object *pObj to this-List after position p in *this. - AddBefore(NULL,x) adds x to the end - equivalent to AddTail - Return the position of the new object, NULL if it fails - Existing POSITIONs in *this are undisturbed, including p. - */ - protected: - __out_opt POSITION AddBeforeI(__in_opt POSITION p, __in void * pObj); - public: - - /* Add the list *pList to *this before position p in *this - AddAfter(NULL,x) adds x to the start - equivalent to AddHead - Return TRUE if it all worked, FALSE if it didn't. - If it fails, some of the objects may be added - Existing POSITIONs in *this are undisturbed, including p. - */ - BOOL AddBefore(__in_opt POSITION p, __in CBaseList *pList); - - - /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x) - even in cases where p is NULL or Next(p) is NULL. - Similarly for mirror images etc. - This may make it easier to argue about programs. - */ - - - - /* The following operations do not copy any elements. - They move existing blocks of elements around by switching pointers. - They are fairly efficient for long lists as for short lists. - (Alas, the Count slows things down). - - They split the list into two parts. - One part remains as the original list, the other part - is appended to the second list. There are eight possible - variations: - Split the list {after/before} a given element - keep the {head/tail} portion in the original list - append the rest to the {head/tail} of the new list. - - Since After is strictly equivalent to Before Next - we are not in serious need of the Before/After variants. - That leaves only four. - - If you are processing a list left to right and dumping - the bits that you have processed into another list as - you go, the Tail/Tail variant gives the most natural result. - If you are processing in reverse order, Head/Head is best. - - By using NULL positions and empty lists judiciously either - of the other two can be built up in two operations. - - The definition of NULL (see Next/Prev etc) means that - degenerate cases include - "move all elements to new list" - "Split a list into two lists" - "Concatenate two lists" - (and quite a few no-ops) - - !!WARNING!! The type checking won't buy you much if you get list - positions muddled up - e.g. use a POSITION that's in a different - list and see what a mess you get! - */ - - /* Split *this after position p in *this - Retain as *this the tail portion of the original *this - Add the head portion to the tail end of *pList - Return TRUE if it all worked, FALSE if it didn't. - - e.g. - foo->MoveToTail(foo->GetHeadPosition(), bar); - moves one element from the head of foo to the tail of bar - foo->MoveToTail(NULL, bar); - is a no-op, returns NULL - foo->MoveToTail(foo->GetTailPosition, bar); - concatenates foo onto the end of bar and empties foo. - - A better, except excessively long name might be - MoveElementsFromHeadThroughPositionToOtherTail - */ - BOOL MoveToTail(__in_opt POSITION pos, __in CBaseList *pList); - - - /* Mirror image: - Split *this before position p in *this. - Retain in *this the head portion of the original *this - Add the tail portion to the start (i.e. head) of *pList - - e.g. - foo->MoveToHead(foo->GetTailPosition(), bar); - moves one element from the tail of foo to the head of bar - foo->MoveToHead(NULL, bar); - is a no-op, returns NULL - foo->MoveToHead(foo->GetHeadPosition, bar); - concatenates foo onto the start of bar and empties foo. - */ - BOOL MoveToHead(__in_opt POSITION pos, __in CBaseList *pList); - - - /* Reverse the order of the [pointers to] objects in *this - */ - void Reverse(); - - - /* set cursor to the position of each element of list in turn */ - #define TRAVERSELIST(list, cursor) \ - for ( cursor = (list).GetHeadPosition() \ - ; cursor!=NULL \ - ; cursor = (list).Next(cursor) \ - ) - - - /* set cursor to the position of each element of list in turn - in reverse order - */ - #define REVERSETRAVERSELIST(list, cursor) \ - for ( cursor = (list).GetTailPosition() \ - ; cursor!=NULL \ - ; cursor = (list).Prev(cursor) \ - ) - -}; // end of class declaration - -template class CGenericList : public CBaseList -{ -public: - CGenericList(__in_opt LPCTSTR pName, - INT iItems, - BOOL bLock = TRUE, - BOOL bAlert = FALSE) : - CBaseList(pName, iItems) { - UNREFERENCED_PARAMETER(bAlert); - UNREFERENCED_PARAMETER(bLock); - }; - CGenericList(__in_opt LPCTSTR pName) : - CBaseList(pName) { - }; - - __out_opt POSITION GetHeadPosition() const { return (POSITION)m_pFirst; } - __out_opt POSITION GetTailPosition() const { return (POSITION)m_pLast; } - int GetCount() const { return m_Count; } - - __out OBJECT *GetNext(__inout POSITION& rp) const { return (OBJECT *) GetNextI(rp); } - - __out_opt OBJECT *Get(__in_opt POSITION p) const { return (OBJECT *) GetI(p); } - __out OBJECT *GetValid(__in POSITION p) const { return (OBJECT *) GetValidI(p); } - __out_opt OBJECT *GetHead() const { return Get(GetHeadPosition()); } - - __out_opt OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); } - - __out_opt OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); } - - __out_opt OBJECT *Remove(__in_opt POSITION p) { return (OBJECT *) RemoveI(p); } - __out_opt POSITION AddBefore(__in_opt POSITION p, __in OBJECT * pObj) { return AddBeforeI(p, pObj); } - __out_opt POSITION AddAfter(__in_opt POSITION p, __in OBJECT * pObj) { return AddAfterI(p, pObj); } - __out_opt POSITION AddHead(__in OBJECT * pObj) { return AddHeadI(pObj); } - __out_opt POSITION AddTail(__in OBJECT * pObj) { return AddTailI(pObj); } - BOOL AddTail(__in CGenericList *pList) - { return CBaseList::AddTail((CBaseList *) pList); } - BOOL AddHead(__in CGenericList *pList) - { return CBaseList::AddHead((CBaseList *) pList); } - BOOL AddAfter(__in_opt POSITION p, __in CGenericList *pList) - { return CBaseList::AddAfter(p, (CBaseList *) pList); }; - BOOL AddBefore(__in_opt POSITION p, __in CGenericList *pList) - { return CBaseList::AddBefore(p, (CBaseList *) pList); }; - __out_opt POSITION Find( __in OBJECT * pObj) const { return FindI(pObj); } -}; // end of class declaration - - - -/* These define the standard list types */ - -typedef CGenericList CBaseObjectList; -typedef CGenericList CBaseInterfaceList; - -#endif /* __WXLIST__ */ - +//------------------------------------------------------------------------------ +// File: WXList.h +// +// Desc: DirectShow base classes - defines a non-MFC generic template list +// class. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +/* A generic list of pointers to objects. + No storage management or copying is done on the objects pointed to. + Objectives: avoid using MFC libraries in ndm kernel mode and + provide a really useful list type. + + The class is thread safe in that separate threads may add and + delete items in the list concurrently although the application + must ensure that constructor and destructor access is suitably + synchronised. An application can cause deadlock with operations + which use two lists by simultaneously calling + list1->Operation(list2) and list2->Operation(list1). So don't! + + The names must not conflict with MFC classes as an application + may use both. + */ + +#ifndef __WXLIST__ +#define __WXLIST__ + + /* A POSITION represents (in some fashion that's opaque) a cursor + on the list that can be set to identify any element. NULL is + a valid value and several operations regard NULL as the position + "one step off the end of the list". (In an n element list there + are n+1 places to insert and NULL is that "n+1-th" value). + The POSITION of an element in the list is only invalidated if + that element is deleted. Move operations may mean that what + was a valid POSITION in one list is now a valid POSITION in + a different list. + + Some operations which at first sight are illegal are allowed as + harmless no-ops. For instance RemoveHead is legal on an empty + list and it returns NULL. This allows an atomic way to test if + there is an element there, and if so, get it. The two operations + AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper). + + Single element operations return POSITIONs, non-NULL means it worked. + whole list operations return a BOOL. TRUE means it all worked. + + This definition is the same as the POSITION type for MFCs, so we must + avoid defining it twice. + */ +#ifndef __AFX_H__ +struct __POSITION { int unused; }; +typedef __POSITION* POSITION; +#endif + +const int DEFAULTCACHE = 10; /* Default node object cache size */ + +/* A class representing one node in a list. + Each node knows a pointer to it's adjacent nodes and also a pointer + to the object that it looks after. + All of these pointers can be retrieved or set through member functions. +*/ +class CBaseList +#ifdef _DEBUG + : public CBaseObject +#endif +{ + /* Making these classes inherit from CBaseObject does nothing + functionally but it allows us to check there are no memory + leaks in debug builds. + */ + +public: + +#ifdef _DEBUG + class CNode : public CBaseObject { +#else + class CNode { +#endif + + CNode *m_pPrev = NULL; /* Previous node in the list */ + CNode *m_pNext = NULL; /* Next node in the list */ + void *m_pObject = NULL; /* Pointer to the object */ + + public: + + /* Constructor - initialise the object's pointers */ + CNode() +#ifdef _DEBUG + : CBaseObject(NAME("List node")) +#endif + { + }; + + + /* Return the previous node before this one */ + __out CNode *Prev() const { return m_pPrev; }; + + + /* Return the next node after this one */ + __out CNode *Next() const { return m_pNext; }; + + + /* Set the previous node before this one */ + void SetPrev(__in_opt CNode *p) { m_pPrev = p; }; + + + /* Set the next node after this one */ + void SetNext(__in_opt CNode *p) { m_pNext = p; }; + + + /* Get the pointer to the object for this node */ + __out void *GetData() const { return m_pObject; }; + + + /* Set the pointer to the object for this node */ + void SetData(__in void *p) { m_pObject = p; }; + }; + + class CNodeCache + { + public: + CNodeCache(INT iCacheSize) : m_iCacheSize(iCacheSize), + m_pHead(NULL), + m_iUsed(0) + {}; + ~CNodeCache() { + CNode *pNode = m_pHead; + while (pNode) { + CNode *pCurrent = pNode; + pNode = pNode->Next(); + delete pCurrent; + } + }; + void AddToCache(__inout CNode *pNode) + { + if (m_iUsed < m_iCacheSize) { + pNode->SetNext(m_pHead); + m_pHead = pNode; + m_iUsed++; + } else { + delete pNode; + } + }; + CNode *RemoveFromCache() + { + CNode *pNode = m_pHead; + if (pNode != NULL) { + m_pHead = pNode->Next(); + m_iUsed--; + ASSERT(m_iUsed >= 0); + } else { + ASSERT(m_iUsed == 0); + } + return pNode; + }; + private: + INT m_iCacheSize; + INT m_iUsed; + CNode *m_pHead; + }; + +protected: + + CNode* m_pFirst; /* Pointer to first node in the list */ + CNode* m_pLast; /* Pointer to the last node in the list */ + LONG m_Count; /* Number of nodes currently in the list */ + +private: + + CNodeCache m_Cache; /* Cache of unused node pointers */ + +private: + + /* These override the default copy constructor and assignment + operator for all list classes. They are in the private class + declaration section so that anybody trying to pass a list + object by value will generate a compile time error of + "cannot access the private member function". If these were + not here then the compiler will create default constructors + and assignment operators which when executed first take a + copy of all member variables and then during destruction + delete them all. This must not be done for any heap + allocated data. + */ + CBaseList(const CBaseList &refList); + CBaseList &operator=(const CBaseList &refList); + +public: + + CBaseList(__in_opt LPCTSTR pName, + INT iItems); + + CBaseList(__in_opt LPCTSTR pName); +#ifdef UNICODE + CBaseList(__in_opt LPCSTR pName, + INT iItems); + + CBaseList(__in_opt LPCSTR pName); +#endif + ~CBaseList(); + + /* Remove all the nodes from *this i.e. make the list empty */ + void RemoveAll(); + + + /* Return a cursor which identifies the first element of *this */ + __out_opt POSITION GetHeadPositionI() const; + + + /* Return a cursor which identifies the last element of *this */ + __out_opt POSITION GetTailPositionI() const; + + + /* Return the number of objects in *this */ + int GetCountI() const; + +protected: + /* Return the pointer to the object at rp, + Update rp to the next node in *this + but make it NULL if it was at the end of *this. + This is a wart retained for backwards compatibility. + GetPrev is not implemented. + Use Next, Prev and Get separately. + */ + __out void *GetNextI(__inout POSITION& rp) const; + + + /* Return a pointer to the object at p + Asking for the object at NULL will return NULL harmlessly. + */ + __out_opt void *GetI(__in_opt POSITION p) const; + __out void *GetValidI(__in POSITION p) const; + +public: + /* return the next / prev position in *this + return NULL when going past the end/start. + Next(NULL) is same as GetHeadPosition() + Prev(NULL) is same as GetTailPosition() + An n element list therefore behaves like a n+1 element + cycle with NULL at the start/end. + + !!WARNING!! - This handling of NULL is DIFFERENT from GetNext. + + Some reasons are: + 1. For a list of n items there are n+1 positions to insert + These are conveniently encoded as the n POSITIONs and NULL. + 2. If you are keeping a list sorted (fairly common) and you + search forward for an element to insert before and don't + find it you finish up with NULL as the element before which + to insert. You then want that NULL to be a valid POSITION + so that you can insert before it and you want that insertion + point to mean the (n+1)-th one that doesn't have a POSITION. + (symmetrically if you are working backwards through the list). + 3. It simplifies the algebra which the methods generate. + e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x) + in ALL cases. All the other arguments probably are reflections + of the algebraic point. + */ + __out_opt POSITION Next(__in_opt POSITION pos) const + { + if (pos == NULL) { + return (POSITION) m_pFirst; + } + CNode *pn = (CNode *) pos; + return (POSITION) pn->Next(); + } //Next + + // See Next + __out_opt POSITION Prev(__in_opt POSITION pos) const + { + if (pos == NULL) { + return (POSITION) m_pLast; + } + CNode *pn = (CNode *) pos; + return (POSITION) pn->Prev(); + } //Prev + + + /* Return the first position in *this which holds the given + pointer. Return NULL if the pointer was not not found. + */ +protected: + __out_opt POSITION FindI( __in void * pObj) const; + + // ??? Should there be (or even should there be only) + // ??? POSITION FindNextAfter(void * pObj, POSITION p) + // ??? And of course FindPrevBefore too. + // ??? List.Find(&Obj) then becomes List.FindNextAfter(&Obj, NULL) + + + /* Remove the first node in *this (deletes the pointer to its + object from the list, does not free the object itself). + Return the pointer to its object. + If *this was already empty it will harmlessly return NULL. + */ + __out_opt void *RemoveHeadI(); + + + /* Remove the last node in *this (deletes the pointer to its + object from the list, does not free the object itself). + Return the pointer to its object. + If *this was already empty it will harmlessly return NULL. + */ + __out_opt void *RemoveTailI(); + + + /* Remove the node identified by p from the list (deletes the pointer + to its object from the list, does not free the object itself). + Asking to Remove the object at NULL will harmlessly return NULL. + Return the pointer to the object removed. + */ + __out_opt void *RemoveI(__in_opt POSITION p); + + /* Add single object *pObj to become a new last element of the list. + Return the new tail position, NULL if it fails. + If you are adding a COM objects, you might want AddRef it first. + Other existing POSITIONs in *this are still valid + */ + __out_opt POSITION AddTailI(__in void * pObj); +public: + + + /* Add all the elements in *pList to the tail of *this. + This duplicates all the nodes in *pList (i.e. duplicates + all its pointers to objects). It does not duplicate the objects. + If you are adding a list of pointers to a COM object into the list + it's a good idea to AddRef them all it when you AddTail it. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some elements may have been added. + Existing POSITIONs in *this are still valid + + If you actually want to MOVE the elements, use MoveToTail instead. + */ + BOOL AddTail(__in CBaseList *pList); + + + /* Mirror images of AddHead: */ + + /* Add single object to become a new first element of the list. + Return the new head position, NULL if it fails. + Existing POSITIONs in *this are still valid + */ +protected: + __out_opt POSITION AddHeadI(__in void * pObj); +public: + + /* Add all the elements in *pList to the head of *this. + Same warnings apply as for AddTail. + Return TRUE if it all worked, FALSE if it didn't. + If it fails some of the objects may have been added. + + If you actually want to MOVE the elements, use MoveToHead instead. + */ + BOOL AddHead(__in CBaseList *pList); + + + /* Add the object *pObj to *this after position p in *this. + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return the position of the object added, NULL if it failed. + Existing POSITIONs in *this are undisturbed, including p. + */ +protected: + __out_opt POSITION AddAfterI(__in_opt POSITION p, __in void * pObj); +public: + + /* Add the list *pList to *this after position p in *this + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return TRUE if it all worked, FALSE if it didn't. + If it fails, some of the objects may be added + Existing POSITIONs in *this are undisturbed, including p. + */ + BOOL AddAfter(__in_opt POSITION p, __in CBaseList *pList); + + + /* Mirror images: + Add the object *pObj to this-List after position p in *this. + AddBefore(NULL,x) adds x to the end - equivalent to AddTail + Return the position of the new object, NULL if it fails + Existing POSITIONs in *this are undisturbed, including p. + */ + protected: + __out_opt POSITION AddBeforeI(__in_opt POSITION p, __in void * pObj); + public: + + /* Add the list *pList to *this before position p in *this + AddAfter(NULL,x) adds x to the start - equivalent to AddHead + Return TRUE if it all worked, FALSE if it didn't. + If it fails, some of the objects may be added + Existing POSITIONs in *this are undisturbed, including p. + */ + BOOL AddBefore(__in_opt POSITION p, __in CBaseList *pList); + + + /* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x) + even in cases where p is NULL or Next(p) is NULL. + Similarly for mirror images etc. + This may make it easier to argue about programs. + */ + + + + /* The following operations do not copy any elements. + They move existing blocks of elements around by switching pointers. + They are fairly efficient for long lists as for short lists. + (Alas, the Count slows things down). + + They split the list into two parts. + One part remains as the original list, the other part + is appended to the second list. There are eight possible + variations: + Split the list {after/before} a given element + keep the {head/tail} portion in the original list + append the rest to the {head/tail} of the new list. + + Since After is strictly equivalent to Before Next + we are not in serious need of the Before/After variants. + That leaves only four. + + If you are processing a list left to right and dumping + the bits that you have processed into another list as + you go, the Tail/Tail variant gives the most natural result. + If you are processing in reverse order, Head/Head is best. + + By using NULL positions and empty lists judiciously either + of the other two can be built up in two operations. + + The definition of NULL (see Next/Prev etc) means that + degenerate cases include + "move all elements to new list" + "Split a list into two lists" + "Concatenate two lists" + (and quite a few no-ops) + + !!WARNING!! The type checking won't buy you much if you get list + positions muddled up - e.g. use a POSITION that's in a different + list and see what a mess you get! + */ + + /* Split *this after position p in *this + Retain as *this the tail portion of the original *this + Add the head portion to the tail end of *pList + Return TRUE if it all worked, FALSE if it didn't. + + e.g. + foo->MoveToTail(foo->GetHeadPosition(), bar); + moves one element from the head of foo to the tail of bar + foo->MoveToTail(NULL, bar); + is a no-op, returns NULL + foo->MoveToTail(foo->GetTailPosition, bar); + concatenates foo onto the end of bar and empties foo. + + A better, except excessively long name might be + MoveElementsFromHeadThroughPositionToOtherTail + */ + BOOL MoveToTail(__in_opt POSITION pos, __in CBaseList *pList); + + + /* Mirror image: + Split *this before position p in *this. + Retain in *this the head portion of the original *this + Add the tail portion to the start (i.e. head) of *pList + + e.g. + foo->MoveToHead(foo->GetTailPosition(), bar); + moves one element from the tail of foo to the head of bar + foo->MoveToHead(NULL, bar); + is a no-op, returns NULL + foo->MoveToHead(foo->GetHeadPosition, bar); + concatenates foo onto the start of bar and empties foo. + */ + BOOL MoveToHead(__in_opt POSITION pos, __in CBaseList *pList); + + + /* Reverse the order of the [pointers to] objects in *this + */ + void Reverse(); + + + /* set cursor to the position of each element of list in turn */ + #define TRAVERSELIST(list, cursor) \ + for ( cursor = (list).GetHeadPosition() \ + ; cursor!=NULL \ + ; cursor = (list).Next(cursor) \ + ) + + + /* set cursor to the position of each element of list in turn + in reverse order + */ + #define REVERSETRAVERSELIST(list, cursor) \ + for ( cursor = (list).GetTailPosition() \ + ; cursor!=NULL \ + ; cursor = (list).Prev(cursor) \ + ) + +}; // end of class declaration + +template class CGenericList : public CBaseList +{ +public: + CGenericList(__in_opt LPCTSTR pName, + INT iItems, + BOOL bLock = TRUE, + BOOL bAlert = FALSE) : + CBaseList(pName, iItems) { + UNREFERENCED_PARAMETER(bAlert); + UNREFERENCED_PARAMETER(bLock); + }; + CGenericList(__in_opt LPCTSTR pName) : + CBaseList(pName) { + }; + + __out_opt POSITION GetHeadPosition() const { return (POSITION)m_pFirst; } + __out_opt POSITION GetTailPosition() const { return (POSITION)m_pLast; } + int GetCount() const { return m_Count; } + + __out OBJECT *GetNext(__inout POSITION& rp) const { return (OBJECT *) GetNextI(rp); } + + __out_opt OBJECT *Get(__in_opt POSITION p) const { return (OBJECT *) GetI(p); } + __out OBJECT *GetValid(__in POSITION p) const { return (OBJECT *) GetValidI(p); } + __out_opt OBJECT *GetHead() const { return Get(GetHeadPosition()); } + + __out_opt OBJECT *RemoveHead() { return (OBJECT *) RemoveHeadI(); } + + __out_opt OBJECT *RemoveTail() { return (OBJECT *) RemoveTailI(); } + + __out_opt OBJECT *Remove(__in_opt POSITION p) { return (OBJECT *) RemoveI(p); } + __out_opt POSITION AddBefore(__in_opt POSITION p, __in OBJECT * pObj) { return AddBeforeI(p, pObj); } + __out_opt POSITION AddAfter(__in_opt POSITION p, __in OBJECT * pObj) { return AddAfterI(p, pObj); } + __out_opt POSITION AddHead(__in OBJECT * pObj) { return AddHeadI(pObj); } + __out_opt POSITION AddTail(__in OBJECT * pObj) { return AddTailI(pObj); } + BOOL AddTail(__in CGenericList *pList) + { return CBaseList::AddTail((CBaseList *) pList); } + BOOL AddHead(__in CGenericList *pList) + { return CBaseList::AddHead((CBaseList *) pList); } + BOOL AddAfter(__in_opt POSITION p, __in CGenericList *pList) + { return CBaseList::AddAfter(p, (CBaseList *) pList); }; + BOOL AddBefore(__in_opt POSITION p, __in CGenericList *pList) + { return CBaseList::AddBefore(p, (CBaseList *) pList); }; + __out_opt POSITION Find( __in OBJECT * pObj) const { return FindI(pObj); } +}; // end of class declaration + + + +/* These define the standard list types */ + +typedef CGenericList CBaseObjectList; +typedef CGenericList CBaseInterfaceList; + +#endif /* __WXLIST__ */ + diff --git a/src/thirdparty/BaseClasses/wxutil.cpp b/src/thirdparty/BaseClasses/wxutil.cpp index ff645d09fb2..89333c95382 100644 --- a/src/thirdparty/BaseClasses/wxutil.cpp +++ b/src/thirdparty/BaseClasses/wxutil.cpp @@ -1,772 +1,772 @@ -//------------------------------------------------------------------------------ -// File: WXUtil.cpp -// -// Desc: DirectShow base classes - implements helper classes for building -// multimedia filters. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#include "streams.h" -#define STRSAFE_NO_DEPRECATE -#include -#include //MPC-HC patch - - -// --- CAMEvent ----------------------- -CAMEvent::CAMEvent(BOOL fManualReset, __inout_opt HRESULT *phr) -{ - m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL); - if (NULL == m_hEvent) { - if (NULL != phr && SUCCEEDED(*phr)) { - *phr = E_OUTOFMEMORY; - } - } -} - -CAMEvent::CAMEvent(__inout_opt HRESULT *phr) -{ - m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (NULL == m_hEvent) { - if (NULL != phr && SUCCEEDED(*phr)) { - *phr = E_OUTOFMEMORY; - } - } -} - -CAMEvent::~CAMEvent() -{ - if (m_hEvent) { - EXECUTE_ASSERT(CloseHandle(m_hEvent)); - } -} - - -// --- CAMMsgEvent ----------------------- -// One routine. The rest is handled in CAMEvent - -CAMMsgEvent::CAMMsgEvent(__inout_opt HRESULT *phr) : CAMEvent(FALSE, phr) -{ -} - -BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) -{ - // wait for the event to be signalled, or for the - // timeout (in MS) to expire. allow SENT messages - // to be processed while we wait - DWORD dwWait; - DWORD dwStartTime = 0; - - // set the waiting period. - DWORD dwWaitTime = dwTimeout; - - // the timeout will eventually run down as we iterate - // processing messages. grab the start time so that - // we can calculate elapsed times. - if (dwWaitTime != INFINITE) { - dwStartTime = timeGetTime(); - } - - do { - dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE); - if (dwWait == WAIT_OBJECT_0 + 1) { - MSG Message; - PeekMessage(&Message,NULL,0,0,PM_NOREMOVE); - - // If we have an explicit length of time to wait calculate - // the next wake up point - which might be now. - // If dwTimeout is INFINITE, it stays INFINITE - if (dwWaitTime != INFINITE) { - - DWORD dwElapsed = timeGetTime()-dwStartTime; - - dwWaitTime = - (dwElapsed >= dwTimeout) - ? 0 // wake up with WAIT_TIMEOUT - : dwTimeout-dwElapsed; - } - } - } while (dwWait == WAIT_OBJECT_0 + 1); - - // return TRUE if we woke on the event handle, - // FALSE if we timed out. - return (dwWait == WAIT_OBJECT_0); -} - -// --- CAMThread ---------------------- - - -CAMThread::CAMThread(__inout_opt HRESULT *phr) - : m_EventSend(TRUE, phr), // must be manual-reset for CheckRequest() - m_EventComplete(FALSE, phr), - m_hThread(NULL), - m_dwParam(0), - m_dwReturnVal(0) -{ -} - -CAMThread::~CAMThread() { - Close(); -} - - -// when the thread starts, it calls this function. We unwrap the 'this' -//pointer and call ThreadProc. -unsigned int WINAPI //MPC-HC patch -CAMThread::InitialThreadProc(__inout LPVOID pv) -{ - HRESULT hrCoInit = CAMThread::CoInitializeHelper(); - if(FAILED(hrCoInit)) { - DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed."))); - } - - CAMThread * pThread = (CAMThread *) pv; - - HRESULT hr = pThread->ThreadProc(); - - if(SUCCEEDED(hrCoInit)) { - CoUninitialize(); - } - - return hr; -} - -BOOL -CAMThread::Create() -{ - CAutoLock lock(&m_AccessLock); - - if (ThreadExists()) { - return FALSE; - } - - //MPC-HC patch - m_hThread = (HANDLE)_beginthreadex( NULL, /* Security */ - 0, /* Stack Size */ - CAMThread::InitialThreadProc, /* Thread process */ - (LPVOID)this, /* Arguments */ - 0, /* 0 = Start Immediately */ - NULL /* Thread Address */ - ); - - if (!m_hThread) { - return FALSE; - } - - return TRUE; -} - -DWORD -CAMThread::CallWorker(DWORD dwParam) -{ - // lock access to the worker thread for scope of this object - CAutoLock lock(&m_AccessLock); - - if (!ThreadExists()) { - return (DWORD) E_FAIL; - } - - // set the parameter - m_dwParam = dwParam; - - // signal the worker thread - m_EventSend.Set(); - - // wait for the completion to be signalled - m_EventComplete.Wait(); - - // done - this is the thread's return value - return m_dwReturnVal; -} - -// Wait for a request from the client -DWORD -CAMThread::GetRequest() -{ - m_EventSend.Wait(); - return m_dwParam; -} - -// is there a request? -BOOL -CAMThread::CheckRequest(__out_opt DWORD * pParam) -{ - if (!m_EventSend.Check()) { - return FALSE; - } else { - if (pParam) { - *pParam = m_dwParam; - } - return TRUE; - } -} - -// reply to the request -void -CAMThread::Reply(DWORD dw) -{ - m_dwReturnVal = dw; - - // The request is now complete so CheckRequest should fail from - // now on - // - // This event should be reset BEFORE we signal the client or - // the client may Set it before we reset it and we'll then - // reset it (!) - - m_EventSend.Reset(); - - // Tell the client we're finished - - m_EventComplete.Set(); -} - -HRESULT CAMThread::CoInitializeHelper() -{ - // call CoInitializeEx and tell OLE not to create a window (this - // thread probably won't dispatch messages and will hang on - // broadcast msgs o/w). - // - // If CoInitEx is not available, threads that don't call CoCreate - // aren't affected. Threads that do will have to handle the - // failure. Perhaps we should fall back to CoInitialize and risk - // hanging? - // - - // older versions of ole32.dll don't have CoInitializeEx - - HRESULT hr = E_FAIL; - HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll")); - if(hOle) - { - typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)( - LPVOID pvReserved, DWORD dwCoInit); - PCoInitializeEx pCoInitializeEx = - (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx")); - if(pCoInitializeEx) - { - hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE ); - } - } - else - { - // caller must load ole32.dll - DbgBreak("couldn't locate ole32.dll"); - } - - return hr; -} - - -// destructor for CMsgThread - cleans up any messages left in the -// queue when the thread exited -CMsgThread::~CMsgThread() -{ - if (m_hThread != NULL) { - WaitForSingleObject(m_hThread, INFINITE); - EXECUTE_ASSERT(CloseHandle(m_hThread)); - } - - POSITION pos = m_ThreadQueue.GetHeadPosition(); - while (pos) { - CMsg * pMsg = m_ThreadQueue.GetNext(pos); - delete pMsg; - } - m_ThreadQueue.RemoveAll(); - - if (m_hSem != NULL) { - EXECUTE_ASSERT(CloseHandle(m_hSem)); - } -} - -BOOL -CMsgThread::CreateThread( - ) -{ - m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); - if (m_hSem == NULL) { - return FALSE; - } - - m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc, - (LPVOID)this, 0, &m_ThreadId); - return m_hThread != NULL; -} - - -// This is the threads message pump. Here we get and dispatch messages to -// clients thread proc until the client refuses to process a message. -// The client returns a non-zero value to stop the message pump, this -// value becomes the threads exit code. - -DWORD WINAPI -CMsgThread::DefaultThreadProc( - __inout LPVOID lpParam - ) -{ - CMsgThread *lpThis = (CMsgThread *)lpParam; - CMsg msg; - LRESULT lResult; - - // !!! - CoInitialize(NULL); - - // allow a derived class to handle thread startup - lpThis->OnThreadInit(); - - do { - lpThis->GetThreadMsg(&msg); - lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags, - msg.lpParam, msg.pEvent); - } while (lResult == 0L); - - // !!! - CoUninitialize(); - - return (DWORD)lResult; -} - - -// Block until the next message is placed on the list m_ThreadQueue. -// copies the message to the message pointed to by *pmsg -void -CMsgThread::GetThreadMsg(__out CMsg *msg) -{ - CMsg * pmsg = NULL; - - // keep trying until a message appears - for (;;) { - { - CAutoLock lck(&m_Lock); - pmsg = m_ThreadQueue.RemoveHead(); - if (pmsg == NULL) { - m_lWaiting++; - } else { - break; - } - } - // the semaphore will be signaled when it is non-empty - WaitForSingleObject(m_hSem, INFINITE); - } - // copy fields to caller's CMsg - *msg = *pmsg; - - // this CMsg was allocated by the 'new' in PutThreadMsg - delete pmsg; - -} - -// Helper function - convert int to WSTR -void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr) -{ -#ifdef UNICODE - if (FAILED(StringCchPrintf(wstr, 12, L"%d", i))) { - wstr[0] = 0; - } -#else - TCHAR temp[12]; - if (FAILED(StringCchPrintf(temp, NUMELMS(temp), "%d", i))) { - wstr[0] = 0; - } else { - MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, 12); - } -#endif -} // IntToWstr - - -#define MEMORY_ALIGNMENT 4 -#define MEMORY_ALIGNMENT_LOG2 2 -#define MEMORY_ALIGNMENT_MASK MEMORY_ALIGNMENT - 1 - -void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) -{ - void * ret = dst; - -#ifdef _X86_ - if (dst <= src || (char *)dst >= ((char *)src + count)) { - - /* - * Non-Overlapping Buffers - * copy from lower addresses to higher addresses - */ - _asm { - mov esi,src - mov edi,dst - mov ecx,count - cld - mov edx,ecx - and edx,MEMORY_ALIGNMENT_MASK - shr ecx,MEMORY_ALIGNMENT_LOG2 - rep movsd - or ecx,edx - jz memmove_done - rep movsb -memmove_done: - } - } - else { - - /* - * Overlapping Buffers - * copy from higher addresses to lower addresses - */ - _asm { - mov esi,src - mov edi,dst - mov ecx,count - std - add esi,ecx - add edi,ecx - dec esi - dec edi - rep movsb - cld - } - } -#else - MoveMemory(dst, src, count); -#endif - - return ret; -} - -HRESULT AMSafeMemMoveOffset( - __in_bcount(dst_size) void * dst, - __in size_t dst_size, - __in DWORD cb_dst_offset, - __in_bcount(src_size) const void * src, - __in size_t src_size, - __in DWORD cb_src_offset, - __in size_t count) -{ - // prevent read overruns - if( count + cb_src_offset < count || // prevent integer overflow - count + cb_src_offset > src_size) // prevent read overrun - { - return E_INVALIDARG; - } - - // prevent write overruns - if( count + cb_dst_offset < count || // prevent integer overflow - count + cb_dst_offset > dst_size) // prevent write overrun - { - return E_INVALIDARG; - } - - memmoveInternal( (BYTE *)dst+cb_dst_offset, (BYTE *)src+cb_src_offset, count); - return S_OK; -} - - -#ifdef _DEBUG -/******************************Public*Routine******************************\ -* Debug CCritSec helpers -* -* We provide debug versions of the Constructor, destructor, Lock and Unlock -* routines. The debug code tracks who owns each critical section by -* maintaining a depth count. -* -* History: -* -\**************************************************************************/ - -CCritSec::CCritSec() -{ - InitializeCriticalSection(&m_CritSec); - m_currentOwner = m_lockCount = 0; - m_fTrace = FALSE; -} - -CCritSec::~CCritSec() -{ - DeleteCriticalSection(&m_CritSec); -} - -void CCritSec::Lock() -{ - UINT tracelevel=3; - DWORD us = GetCurrentThreadId(); - DWORD currentOwner = m_currentOwner; - if (currentOwner && (currentOwner != us)) { - // already owned, but not by us - if (m_fTrace) { - DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"), - GetCurrentThreadId(), &m_CritSec, currentOwner)); - tracelevel=2; - // if we saw the message about waiting for the critical - // section we ensure we see the message when we get the - // critical section - } - } - EnterCriticalSection(&m_CritSec); - if (0 == m_lockCount++) { - // we now own it for the first time. Set owner information - m_currentOwner = us; - - if (m_fTrace) { - DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec)); - } - } -} - -void CCritSec::Unlock() { - if (0 == --m_lockCount) { - // about to be unowned - if (m_fTrace) { - DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec)); - } - - m_currentOwner = 0; - } - LeaveCriticalSection(&m_CritSec); -} - -void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) -{ - pcCrit->m_fTrace = fTrace; -} - -BOOL WINAPI CritCheckIn(CCritSec * pcCrit) -{ - return (GetCurrentThreadId() == pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) -{ - return (GetCurrentThreadId() == pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckOut(CCritSec * pcCrit) -{ - return (GetCurrentThreadId() != pcCrit->m_currentOwner); -} - -BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) -{ - return (GetCurrentThreadId() != pcCrit->m_currentOwner); -} -#endif - - -STDAPI WriteBSTR(__deref_out BSTR *pstrDest, LPCWSTR szSrc) -{ - *pstrDest = SysAllocString( szSrc ); - if( !(*pstrDest) ) return E_OUTOFMEMORY; - return NOERROR; -} - - -STDAPI FreeBSTR(__deref_in BSTR* pstr) -{ - if( (PVOID)*pstr == NULL ) return S_FALSE; - SysFreeString( *pstr ); - *pstr = NULL; - return NOERROR; -} - - -// Return a wide string - allocating memory for it -// Returns: -// S_OK - no error -// E_POINTER - ppszReturn == NULL -// E_OUTOFMEMORY - can't allocate memory for returned string -STDAPI AMGetWideString(LPCWSTR psz, __deref_out LPWSTR *ppszReturn) -{ - CheckPointer(ppszReturn, E_POINTER); - ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR)); - *ppszReturn = NULL; - size_t nameLen; - HRESULT hr = StringCbLengthW(psz, 100000, &nameLen); - if (FAILED(hr)) { - return hr; - } - *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen + sizeof(WCHAR)); - if (*ppszReturn == NULL) { - return E_OUTOFMEMORY; - } - CopyMemory(*ppszReturn, psz, nameLen + sizeof(WCHAR)); - return NOERROR; -} - -// Waits for the HANDLE hObject. While waiting messages sent -// to windows on our thread by SendMessage will be processed. -// Using this function to do waits and mutual exclusion -// avoids some deadlocks in objects with windows. -// Return codes are the same as for WaitForSingleObject -DWORD WINAPI WaitDispatchingMessages( - HANDLE hObject, - DWORD dwWait, - HWND hwnd, - UINT uMsg, - HANDLE hEvent) -{ - BOOL bPeeked = FALSE; - DWORD dwResult; - DWORD dwStart = 0; - DWORD dwThreadPriority = THREAD_PRIORITY_NORMAL; - - static UINT uMsgId = 0; - - HANDLE hObjects[2] = { hObject, hEvent }; - if (dwWait != INFINITE && dwWait != 0) { - dwStart = GetTickCount(); - } - for (; ; ) { - DWORD nCount = NULL != hEvent ? 2 : 1; - - // Minimize the chance of actually dispatching any messages - // by seeing if we can lock immediately. - dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0); - if (dwResult < WAIT_OBJECT_0 + nCount) { - break; - } - - DWORD dwTimeOut = dwWait; - if (dwTimeOut > 10) { - dwTimeOut = 10; - } - dwResult = MsgWaitForMultipleObjects( - nCount, - hObjects, - FALSE, - dwTimeOut, - hwnd == NULL ? QS_SENDMESSAGE : - QS_SENDMESSAGE + QS_POSTMESSAGE); - if (dwResult == WAIT_OBJECT_0 + nCount || - dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) { - MSG msg; - if (hwnd != NULL) { - while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) { - DispatchMessage(&msg); - } - } - // Do this anyway - the previous peek doesn't flush out the - // messages - PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); - - if (dwWait != INFINITE && dwWait != 0) { - DWORD dwNow = GetTickCount(); - - // Working with differences handles wrap-around - DWORD dwDiff = dwNow - dwStart; - if (dwDiff > dwWait) { - dwWait = 0; - } else { - dwWait -= dwDiff; - } - dwStart = dwNow; - } - if (!bPeeked) { - // Raise our priority to prevent our message queue - // building up - dwThreadPriority = GetThreadPriority(GetCurrentThread()); - if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) { - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); - } - bPeeked = TRUE; - } - } else { - break; - } - } - if (bPeeked) { - SetThreadPriority(GetCurrentThread(), dwThreadPriority); - if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { - if (uMsgId == 0) { - uMsgId = RegisterWindowMessage(TEXT("AMUnblock")); - } - if (uMsgId != 0) { - MSG msg; - // Remove old ones - while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) { - } - } - PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0); - } - } - return dwResult; -} - -HRESULT AmGetLastErrorToHResult() -{ - DWORD dwLastError = GetLastError(); - if(dwLastError != 0) - { - return HRESULT_FROM_WIN32(dwLastError); - } - else - { - return E_FAIL; - } -} - -IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp) -{ - if (lp != NULL) - lp->AddRef(); - if (*pp) - (*pp)->Release(); - *pp = lp; - return lp; -} - -/****************************************************************************** - -CompatibleTimeSetEvent - - CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling -timeSetEvent() if the current operating system supports it. TIME_KILL_SYNCHRONOUS -is supported on Windows XP and later operating systems. - -Parameters: -- The same parameters as timeSetEvent(). See timeSetEvent()'s documentation in -the Platform SDK for more information. - -Return Value: -- The same return value as timeSetEvent(). See timeSetEvent()'s documentation in -the Platform SDK for more information. - -******************************************************************************/ -MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) -{ - #if WINVER >= 0x0501 - { - static bool fCheckedVersion = false; - static bool fTimeKillSynchronousFlagAvailable = false; - - if( !fCheckedVersion ) { - fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable(); - fCheckedVersion = true; - } - - if( fTimeKillSynchronousFlagAvailable ) { - fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS; - } - } - #endif // WINVER >= 0x0501 - - return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent ); -} - -bool TimeKillSynchronousFlagAvailable( void ) -{ - OSVERSIONINFO osverinfo; - - osverinfo.dwOSVersionInfoSize = sizeof(osverinfo); - - if( GetVersionEx( &osverinfo ) ) { - - // Windows XP's major version is 5 and its' minor version is 1. - // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag - // in Windows XP. - if( (osverinfo.dwMajorVersion > 5) || - ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) { - return true; - } - } - - return false; -} - - +//------------------------------------------------------------------------------ +// File: WXUtil.cpp +// +// Desc: DirectShow base classes - implements helper classes for building +// multimedia filters. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#include "streams.h" +#define STRSAFE_NO_DEPRECATE +#include +#include //MPC-HC patch + + +// --- CAMEvent ----------------------- +CAMEvent::CAMEvent(BOOL fManualReset, __inout_opt HRESULT *phr) +{ + m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL); + if (NULL == m_hEvent) { + if (NULL != phr && SUCCEEDED(*phr)) { + *phr = E_OUTOFMEMORY; + } + } +} + +CAMEvent::CAMEvent(__inout_opt HRESULT *phr) +{ + m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (NULL == m_hEvent) { + if (NULL != phr && SUCCEEDED(*phr)) { + *phr = E_OUTOFMEMORY; + } + } +} + +CAMEvent::~CAMEvent() +{ + if (m_hEvent) { + EXECUTE_ASSERT(CloseHandle(m_hEvent)); + } +} + + +// --- CAMMsgEvent ----------------------- +// One routine. The rest is handled in CAMEvent + +CAMMsgEvent::CAMMsgEvent(__inout_opt HRESULT *phr) : CAMEvent(FALSE, phr) +{ +} + +BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) +{ + // wait for the event to be signalled, or for the + // timeout (in MS) to expire. allow SENT messages + // to be processed while we wait + DWORD dwWait; + DWORD dwStartTime = 0; + + // set the waiting period. + DWORD dwWaitTime = dwTimeout; + + // the timeout will eventually run down as we iterate + // processing messages. grab the start time so that + // we can calculate elapsed times. + if (dwWaitTime != INFINITE) { + dwStartTime = timeGetTime(); + } + + do { + dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE); + if (dwWait == WAIT_OBJECT_0 + 1) { + MSG Message; + PeekMessage(&Message,NULL,0,0,PM_NOREMOVE); + + // If we have an explicit length of time to wait calculate + // the next wake up point - which might be now. + // If dwTimeout is INFINITE, it stays INFINITE + if (dwWaitTime != INFINITE) { + + DWORD dwElapsed = timeGetTime()-dwStartTime; + + dwWaitTime = + (dwElapsed >= dwTimeout) + ? 0 // wake up with WAIT_TIMEOUT + : dwTimeout-dwElapsed; + } + } + } while (dwWait == WAIT_OBJECT_0 + 1); + + // return TRUE if we woke on the event handle, + // FALSE if we timed out. + return (dwWait == WAIT_OBJECT_0); +} + +// --- CAMThread ---------------------- + + +CAMThread::CAMThread(__inout_opt HRESULT *phr) + : m_EventSend(TRUE, phr), // must be manual-reset for CheckRequest() + m_EventComplete(FALSE, phr), + m_hThread(NULL), + m_dwParam(0), + m_dwReturnVal(0) +{ +} + +CAMThread::~CAMThread() { + Close(); +} + + +// when the thread starts, it calls this function. We unwrap the 'this' +//pointer and call ThreadProc. +unsigned int WINAPI //MPC-HC patch +CAMThread::InitialThreadProc(__inout LPVOID pv) +{ + HRESULT hrCoInit = CAMThread::CoInitializeHelper(); + if(FAILED(hrCoInit)) { + DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed."))); + } + + CAMThread * pThread = (CAMThread *) pv; + + HRESULT hr = pThread->ThreadProc(); + + if(SUCCEEDED(hrCoInit)) { + CoUninitialize(); + } + + return hr; +} + +BOOL +CAMThread::Create() +{ + CAutoLock lock(&m_AccessLock); + + if (ThreadExists()) { + return FALSE; + } + + //MPC-HC patch + m_hThread = (HANDLE)_beginthreadex( NULL, /* Security */ + 0, /* Stack Size */ + CAMThread::InitialThreadProc, /* Thread process */ + (LPVOID)this, /* Arguments */ + 0, /* 0 = Start Immediately */ + NULL /* Thread Address */ + ); + + if (!m_hThread) { + return FALSE; + } + + return TRUE; +} + +DWORD +CAMThread::CallWorker(DWORD dwParam) +{ + // lock access to the worker thread for scope of this object + CAutoLock lock(&m_AccessLock); + + if (!ThreadExists()) { + return (DWORD) E_FAIL; + } + + // set the parameter + m_dwParam = dwParam; + + // signal the worker thread + m_EventSend.Set(); + + // wait for the completion to be signalled + m_EventComplete.Wait(); + + // done - this is the thread's return value + return m_dwReturnVal; +} + +// Wait for a request from the client +DWORD +CAMThread::GetRequest() +{ + m_EventSend.Wait(); + return m_dwParam; +} + +// is there a request? +BOOL +CAMThread::CheckRequest(__out_opt DWORD * pParam) +{ + if (!m_EventSend.Check()) { + return FALSE; + } else { + if (pParam) { + *pParam = m_dwParam; + } + return TRUE; + } +} + +// reply to the request +void +CAMThread::Reply(DWORD dw) +{ + m_dwReturnVal = dw; + + // The request is now complete so CheckRequest should fail from + // now on + // + // This event should be reset BEFORE we signal the client or + // the client may Set it before we reset it and we'll then + // reset it (!) + + m_EventSend.Reset(); + + // Tell the client we're finished + + m_EventComplete.Set(); +} + +HRESULT CAMThread::CoInitializeHelper() +{ + // call CoInitializeEx and tell OLE not to create a window (this + // thread probably won't dispatch messages and will hang on + // broadcast msgs o/w). + // + // If CoInitEx is not available, threads that don't call CoCreate + // aren't affected. Threads that do will have to handle the + // failure. Perhaps we should fall back to CoInitialize and risk + // hanging? + // + + // older versions of ole32.dll don't have CoInitializeEx + + HRESULT hr = E_FAIL; + HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll")); + if(hOle) + { + typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)( + LPVOID pvReserved, DWORD dwCoInit); + PCoInitializeEx pCoInitializeEx = + (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx")); + if(pCoInitializeEx) + { + hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE ); + } + } + else + { + // caller must load ole32.dll + DbgBreak("couldn't locate ole32.dll"); + } + + return hr; +} + + +// destructor for CMsgThread - cleans up any messages left in the +// queue when the thread exited +CMsgThread::~CMsgThread() +{ + if (m_hThread != NULL) { + WaitForSingleObject(m_hThread, INFINITE); + EXECUTE_ASSERT(CloseHandle(m_hThread)); + } + + POSITION pos = m_ThreadQueue.GetHeadPosition(); + while (pos) { + CMsg * pMsg = m_ThreadQueue.GetNext(pos); + delete pMsg; + } + m_ThreadQueue.RemoveAll(); + + if (m_hSem != NULL) { + EXECUTE_ASSERT(CloseHandle(m_hSem)); + } +} + +BOOL +CMsgThread::CreateThread( + ) +{ + m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); + if (m_hSem == NULL) { + return FALSE; + } + + m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc, + (LPVOID)this, 0, &m_ThreadId); + return m_hThread != NULL; +} + + +// This is the threads message pump. Here we get and dispatch messages to +// clients thread proc until the client refuses to process a message. +// The client returns a non-zero value to stop the message pump, this +// value becomes the threads exit code. + +DWORD WINAPI +CMsgThread::DefaultThreadProc( + __inout LPVOID lpParam + ) +{ + CMsgThread *lpThis = (CMsgThread *)lpParam; + CMsg msg; + LRESULT lResult; + + // !!! + CoInitialize(NULL); + + // allow a derived class to handle thread startup + lpThis->OnThreadInit(); + + do { + lpThis->GetThreadMsg(&msg); + lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags, + msg.lpParam, msg.pEvent); + } while (lResult == 0L); + + // !!! + CoUninitialize(); + + return (DWORD)lResult; +} + + +// Block until the next message is placed on the list m_ThreadQueue. +// copies the message to the message pointed to by *pmsg +void +CMsgThread::GetThreadMsg(__out CMsg *msg) +{ + CMsg * pmsg = NULL; + + // keep trying until a message appears + for (;;) { + { + CAutoLock lck(&m_Lock); + pmsg = m_ThreadQueue.RemoveHead(); + if (pmsg == NULL) { + m_lWaiting++; + } else { + break; + } + } + // the semaphore will be signaled when it is non-empty + WaitForSingleObject(m_hSem, INFINITE); + } + // copy fields to caller's CMsg + *msg = *pmsg; + + // this CMsg was allocated by the 'new' in PutThreadMsg + delete pmsg; + +} + +// Helper function - convert int to WSTR +void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr) +{ +#ifdef UNICODE + if (FAILED(StringCchPrintf(wstr, 12, L"%d", i))) { + wstr[0] = 0; + } +#else + TCHAR temp[12]; + if (FAILED(StringCchPrintf(temp, NUMELMS(temp), "%d", i))) { + wstr[0] = 0; + } else { + MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, 12); + } +#endif +} // IntToWstr + + +#define MEMORY_ALIGNMENT 4 +#define MEMORY_ALIGNMENT_LOG2 2 +#define MEMORY_ALIGNMENT_MASK MEMORY_ALIGNMENT - 1 + +void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) +{ + void * ret = dst; + +#ifdef _X86_ + if (dst <= src || (char *)dst >= ((char *)src + count)) { + + /* + * Non-Overlapping Buffers + * copy from lower addresses to higher addresses + */ + _asm { + mov esi,src + mov edi,dst + mov ecx,count + cld + mov edx,ecx + and edx,MEMORY_ALIGNMENT_MASK + shr ecx,MEMORY_ALIGNMENT_LOG2 + rep movsd + or ecx,edx + jz memmove_done + rep movsb +memmove_done: + } + } + else { + + /* + * Overlapping Buffers + * copy from higher addresses to lower addresses + */ + _asm { + mov esi,src + mov edi,dst + mov ecx,count + std + add esi,ecx + add edi,ecx + dec esi + dec edi + rep movsb + cld + } + } +#else + MoveMemory(dst, src, count); +#endif + + return ret; +} + +HRESULT AMSafeMemMoveOffset( + __in_bcount(dst_size) void * dst, + __in size_t dst_size, + __in DWORD cb_dst_offset, + __in_bcount(src_size) const void * src, + __in size_t src_size, + __in DWORD cb_src_offset, + __in size_t count) +{ + // prevent read overruns + if( count + cb_src_offset < count || // prevent integer overflow + count + cb_src_offset > src_size) // prevent read overrun + { + return E_INVALIDARG; + } + + // prevent write overruns + if( count + cb_dst_offset < count || // prevent integer overflow + count + cb_dst_offset > dst_size) // prevent write overrun + { + return E_INVALIDARG; + } + + memmoveInternal( (BYTE *)dst+cb_dst_offset, (BYTE *)src+cb_src_offset, count); + return S_OK; +} + + +#ifdef _DEBUG +/******************************Public*Routine******************************\ +* Debug CCritSec helpers +* +* We provide debug versions of the Constructor, destructor, Lock and Unlock +* routines. The debug code tracks who owns each critical section by +* maintaining a depth count. +* +* History: +* +\**************************************************************************/ + +CCritSec::CCritSec() +{ + InitializeCriticalSection(&m_CritSec); + m_currentOwner = m_lockCount = 0; + m_fTrace = FALSE; +} + +CCritSec::~CCritSec() +{ + DeleteCriticalSection(&m_CritSec); +} + +void CCritSec::Lock() +{ + UINT tracelevel=3; + DWORD us = GetCurrentThreadId(); + DWORD currentOwner = m_currentOwner; + if (currentOwner && (currentOwner != us)) { + // already owned, but not by us + if (m_fTrace) { + DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"), + GetCurrentThreadId(), &m_CritSec, currentOwner)); + tracelevel=2; + // if we saw the message about waiting for the critical + // section we ensure we see the message when we get the + // critical section + } + } + EnterCriticalSection(&m_CritSec); + if (0 == m_lockCount++) { + // we now own it for the first time. Set owner information + m_currentOwner = us; + + if (m_fTrace) { + DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec)); + } + } +} + +void CCritSec::Unlock() { + if (0 == --m_lockCount) { + // about to be unowned + if (m_fTrace) { + DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec)); + } + + m_currentOwner = 0; + } + LeaveCriticalSection(&m_CritSec); +} + +void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) +{ + pcCrit->m_fTrace = fTrace; +} + +BOOL WINAPI CritCheckIn(CCritSec * pcCrit) +{ + return (GetCurrentThreadId() == pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) +{ + return (GetCurrentThreadId() == pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckOut(CCritSec * pcCrit) +{ + return (GetCurrentThreadId() != pcCrit->m_currentOwner); +} + +BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) +{ + return (GetCurrentThreadId() != pcCrit->m_currentOwner); +} +#endif + + +STDAPI WriteBSTR(__deref_out BSTR *pstrDest, LPCWSTR szSrc) +{ + *pstrDest = SysAllocString( szSrc ); + if( !(*pstrDest) ) return E_OUTOFMEMORY; + return NOERROR; +} + + +STDAPI FreeBSTR(__deref_in BSTR* pstr) +{ + if( (PVOID)*pstr == NULL ) return S_FALSE; + SysFreeString( *pstr ); + *pstr = NULL; + return NOERROR; +} + + +// Return a wide string - allocating memory for it +// Returns: +// S_OK - no error +// E_POINTER - ppszReturn == NULL +// E_OUTOFMEMORY - can't allocate memory for returned string +STDAPI AMGetWideString(LPCWSTR psz, __deref_out LPWSTR *ppszReturn) +{ + CheckPointer(ppszReturn, E_POINTER); + ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR)); + *ppszReturn = NULL; + size_t nameLen; + HRESULT hr = StringCbLengthW(psz, 100000, &nameLen); + if (FAILED(hr)) { + return hr; + } + *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen + sizeof(WCHAR)); + if (*ppszReturn == NULL) { + return E_OUTOFMEMORY; + } + CopyMemory(*ppszReturn, psz, nameLen + sizeof(WCHAR)); + return NOERROR; +} + +// Waits for the HANDLE hObject. While waiting messages sent +// to windows on our thread by SendMessage will be processed. +// Using this function to do waits and mutual exclusion +// avoids some deadlocks in objects with windows. +// Return codes are the same as for WaitForSingleObject +DWORD WINAPI WaitDispatchingMessages( + HANDLE hObject, + DWORD dwWait, + HWND hwnd, + UINT uMsg, + HANDLE hEvent) +{ + BOOL bPeeked = FALSE; + DWORD dwResult; + DWORD dwStart = 0; + DWORD dwThreadPriority = THREAD_PRIORITY_NORMAL; + + static UINT uMsgId = 0; + + HANDLE hObjects[2] = { hObject, hEvent }; + if (dwWait != INFINITE && dwWait != 0) { + dwStart = GetTickCount(); + } + for (; ; ) { + DWORD nCount = NULL != hEvent ? 2 : 1; + + // Minimize the chance of actually dispatching any messages + // by seeing if we can lock immediately. + dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0); + if (dwResult < WAIT_OBJECT_0 + nCount) { + break; + } + + DWORD dwTimeOut = dwWait; + if (dwTimeOut > 10) { + dwTimeOut = 10; + } + dwResult = MsgWaitForMultipleObjects( + nCount, + hObjects, + FALSE, + dwTimeOut, + hwnd == NULL ? QS_SENDMESSAGE : + QS_SENDMESSAGE + QS_POSTMESSAGE); + if (dwResult == WAIT_OBJECT_0 + nCount || + dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) { + MSG msg; + if (hwnd != NULL) { + while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) { + DispatchMessage(&msg); + } + } + // Do this anyway - the previous peek doesn't flush out the + // messages + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); + + if (dwWait != INFINITE && dwWait != 0) { + DWORD dwNow = GetTickCount(); + + // Working with differences handles wrap-around + DWORD dwDiff = dwNow - dwStart; + if (dwDiff > dwWait) { + dwWait = 0; + } else { + dwWait -= dwDiff; + } + dwStart = dwNow; + } + if (!bPeeked) { + // Raise our priority to prevent our message queue + // building up + dwThreadPriority = GetThreadPriority(GetCurrentThread()); + if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + } + bPeeked = TRUE; + } + } else { + break; + } + } + if (bPeeked) { + SetThreadPriority(GetCurrentThread(), dwThreadPriority); + if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { + if (uMsgId == 0) { + uMsgId = RegisterWindowMessage(TEXT("AMUnblock")); + } + if (uMsgId != 0) { + MSG msg; + // Remove old ones + while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) { + } + } + PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0); + } + } + return dwResult; +} + +HRESULT AmGetLastErrorToHResult() +{ + DWORD dwLastError = GetLastError(); + if(dwLastError != 0) + { + return HRESULT_FROM_WIN32(dwLastError); + } + else + { + return E_FAIL; + } +} + +IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp) +{ + if (lp != NULL) + lp->AddRef(); + if (*pp) + (*pp)->Release(); + *pp = lp; + return lp; +} + +/****************************************************************************** + +CompatibleTimeSetEvent + + CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling +timeSetEvent() if the current operating system supports it. TIME_KILL_SYNCHRONOUS +is supported on Windows XP and later operating systems. + +Parameters: +- The same parameters as timeSetEvent(). See timeSetEvent()'s documentation in +the Platform SDK for more information. + +Return Value: +- The same return value as timeSetEvent(). See timeSetEvent()'s documentation in +the Platform SDK for more information. + +******************************************************************************/ +MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) +{ + #if WINVER >= 0x0501 + { + static bool fCheckedVersion = false; + static bool fTimeKillSynchronousFlagAvailable = false; + + if( !fCheckedVersion ) { + fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable(); + fCheckedVersion = true; + } + + if( fTimeKillSynchronousFlagAvailable ) { + fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS; + } + } + #endif // WINVER >= 0x0501 + + return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent ); +} + +bool TimeKillSynchronousFlagAvailable( void ) +{ + OSVERSIONINFO osverinfo; + + osverinfo.dwOSVersionInfoSize = sizeof(osverinfo); + + if( GetVersionEx( &osverinfo ) ) { + + // Windows XP's major version is 5 and its' minor version is 1. + // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag + // in Windows XP. + if( (osverinfo.dwMajorVersion > 5) || + ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) { + return true; + } + } + + return false; +} + + diff --git a/src/thirdparty/BaseClasses/wxutil.h b/src/thirdparty/BaseClasses/wxutil.h index b73a44b36ac..a1c1704bfc1 100644 --- a/src/thirdparty/BaseClasses/wxutil.h +++ b/src/thirdparty/BaseClasses/wxutil.h @@ -1,532 +1,532 @@ -//------------------------------------------------------------------------------ -// File: WXUtil.h -// -// Desc: DirectShow base classes - defines helper classes and functions for -// building multimedia filters. -// -// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. -//------------------------------------------------------------------------------ - - -#ifndef __WXUTIL__ -#define __WXUTIL__ - -// eliminate spurious "statement has no effect" warnings. -#pragma warning(disable: 4705) - -// wrapper for whatever critical section we have -class CCritSec { - - // make copy constructor and assignment operator inaccessible - - CCritSec(const CCritSec &refCritSec); - CCritSec &operator=(const CCritSec &refCritSec); - - CRITICAL_SECTION m_CritSec; - -#ifdef _DEBUG -public: - DWORD m_currentOwner; - DWORD m_lockCount; - BOOL m_fTrace; // Trace this one -public: - CCritSec(); - ~CCritSec(); - void Lock(); - void Unlock(); -#else - -public: - CCritSec() { - InitializeCriticalSection(&m_CritSec); - }; - - ~CCritSec() { - DeleteCriticalSection(&m_CritSec); - }; - - void Lock() { - EnterCriticalSection(&m_CritSec); - }; - - void Unlock() { - LeaveCriticalSection(&m_CritSec); - }; -#endif -}; - -// -// To make deadlocks easier to track it is useful to insert in the -// code an assertion that says whether we own a critical section or -// not. We make the routines that do the checking globals to avoid -// having different numbers of member functions in the debug and -// retail class implementations of CCritSec. In addition we provide -// a routine that allows usage of specific critical sections to be -// traced. This is NOT on by default - there are far too many. -// - -#ifdef _DEBUG - BOOL WINAPI CritCheckIn(CCritSec * pcCrit); - BOOL WINAPI CritCheckIn(const CCritSec * pcCrit); - BOOL WINAPI CritCheckOut(CCritSec * pcCrit); - BOOL WINAPI CritCheckOut(const CCritSec * pcCrit); - void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace); -#else - #define CritCheckIn(x) TRUE - #define CritCheckOut(x) TRUE - #define DbgLockTrace(pc, fT) -#endif - - -// locks a critical section, and unlocks it automatically -// when the lock goes out of scope -class CAutoLock { - - // make copy constructor and assignment operator inaccessible - - CAutoLock(const CAutoLock &refAutoLock); - CAutoLock &operator=(const CAutoLock &refAutoLock); - -protected: - CCritSec * m_pLock; - -public: - CAutoLock(CCritSec * plock) - { - m_pLock = plock; - m_pLock->Lock(); - }; - - ~CAutoLock() { - m_pLock->Unlock(); - }; -}; - - - -// wrapper for event objects -class CAMEvent -{ - - // make copy constructor and assignment operator inaccessible - - CAMEvent(const CAMEvent &refEvent); - CAMEvent &operator=(const CAMEvent &refEvent); - -protected: - HANDLE m_hEvent; -public: - CAMEvent(BOOL fManualReset = FALSE, __inout_opt HRESULT *phr = NULL); - CAMEvent(__inout_opt HRESULT *phr); - ~CAMEvent(); - - // Cast to HANDLE - we don't support this as an lvalue - operator HANDLE () const { return m_hEvent; }; - - void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));}; - BOOL Wait(DWORD dwTimeout = INFINITE) { - return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0); - }; - void Reset() { ResetEvent(m_hEvent); }; - BOOL Check() { return Wait(0); }; -}; - - -// wrapper for event objects that do message processing -// This adds ONE method to the CAMEvent object to allow sent -// messages to be processed while waiting - -class CAMMsgEvent : public CAMEvent -{ - -public: - - CAMMsgEvent(__inout_opt HRESULT *phr = NULL); - - // Allow SEND messages to be processed while waiting - BOOL WaitMsg(DWORD dwTimeout = INFINITE); -}; - -// old name supported for the time being -#define CTimeoutEvent CAMEvent - -// support for a worker thread - -#ifdef AM_NOVTABLE -// simple thread class supports creation of worker thread, synchronization -// and communication. Can be derived to simplify parameter passing -class AM_NOVTABLE CAMThread { - - // make copy constructor and assignment operator inaccessible - - CAMThread(const CAMThread &refThread); - CAMThread &operator=(const CAMThread &refThread); - - CAMEvent m_EventSend; - CAMEvent m_EventComplete; - - DWORD m_dwParam; - DWORD m_dwReturnVal; - -protected: - HANDLE m_hThread; - - // thread will run this function on startup - // must be supplied by derived class - virtual DWORD ThreadProc() = 0; - -public: - CAMThread(__inout_opt HRESULT *phr = NULL); - virtual ~CAMThread(); - - CCritSec m_AccessLock; // locks access by client threads - CCritSec m_WorkerLock; // locks access to shared objects - - // thread initially runs this. param is actually 'this'. function - // just gets this and calls ThreadProc - static unsigned int WINAPI InitialThreadProc(__inout LPVOID pv); // MPC-HC patch - - // start thread running - error if already running - BOOL Create(); - - // signal the thread, and block for a response - // - DWORD CallWorker(DWORD); - - // accessor thread calls this when done with thread (having told thread - // to exit) - void Close() { - - // Disable warning: Conversion from LONG to PVOID of greater size -#pragma warning(push) -#pragma warning(disable: 4312) - HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0); -#pragma warning(pop) - - if (hThread) { - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - } - }; - - // ThreadExists - // Return TRUE if the thread exists. FALSE otherwise - BOOL ThreadExists(void) const - { - if (m_hThread == NULL) { - return FALSE; - } else { - return TRUE; - } - } - - // wait for the next request - DWORD GetRequest(); - - // is there a request? - BOOL CheckRequest(__out_opt DWORD * pParam); - - // reply to the request - void Reply(DWORD); - - // If you want to do WaitForMultipleObjects you'll need to include - // this handle in your wait list or you won't be responsive - HANDLE GetRequestHandle() const { return m_EventSend; }; - - // Find out what the request was - DWORD GetRequestParam() const { return m_dwParam; }; - - // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if - // available. S_FALSE means it's not available. - static HRESULT CoInitializeHelper(); -}; -#endif // AM_NOVTABLE - - -// CQueue -// -// Implements a simple Queue ADT. The queue contains a finite number of -// objects, access to which is controlled by a semaphore. The semaphore -// is created with an initial count (N). Each time an object is added -// a call to WaitForSingleObject is made on the semaphore's handle. When -// this function returns a slot has been reserved in the queue for the new -// object. If no slots are available the function blocks until one becomes -// available. Each time an object is removed from the queue ReleaseSemaphore -// is called on the semaphore's handle, thus freeing a slot in the queue. -// If no objects are present in the queue the function blocks until an -// object has been added. - -#define DEFAULT_QUEUESIZE 2 - -template class CQueue { -private: - HANDLE hSemPut; // Semaphore controlling queue "putting" - HANDLE hSemGet; // Semaphore controlling queue "getting" - CRITICAL_SECTION CritSect; // Thread seriallization - int nMax; // Max objects allowed in queue - int iNextPut; // Array index of next "PutMsg" - int iNextGet; // Array index of next "GetMsg" - T *QueueObjects; // Array of objects (ptr's to void) - - void Initialize(int n) { - iNextPut = iNextGet = 0; - nMax = n; - InitializeCriticalSection(&CritSect); - hSemPut = CreateSemaphore(NULL, n, n, NULL); - hSemGet = CreateSemaphore(NULL, 0, n, NULL); - QueueObjects = new T[n]; - } - - -public: - CQueue(int n) { - Initialize(n); - } - - CQueue() { - Initialize(DEFAULT_QUEUESIZE); - } - - ~CQueue() { - delete [] QueueObjects; - DeleteCriticalSection(&CritSect); - CloseHandle(hSemPut); - CloseHandle(hSemGet); - } - - T GetQueueObject() { - int iSlot; - T Object; - LONG lPrevious; - - // Wait for someone to put something on our queue, returns straight - // away is there is already an object on the queue. - // - WaitForSingleObject(hSemGet, INFINITE); - - EnterCriticalSection(&CritSect); - iSlot = iNextGet++ % nMax; - Object = QueueObjects[iSlot]; - LeaveCriticalSection(&CritSect); - - // Release anyone waiting to put an object onto our queue as there - // is now space available in the queue. - // - ReleaseSemaphore(hSemPut, 1L, &lPrevious); - return Object; - } - - void PutQueueObject(T Object) { - int iSlot; - LONG lPrevious; - - // Wait for someone to get something from our queue, returns straight - // away is there is already an empty slot on the queue. - // - WaitForSingleObject(hSemPut, INFINITE); - - EnterCriticalSection(&CritSect); - iSlot = iNextPut++ % nMax; - QueueObjects[iSlot] = Object; - LeaveCriticalSection(&CritSect); - - // Release anyone waiting to remove an object from our queue as there - // is now an object available to be removed. - // - ReleaseSemaphore(hSemGet, 1L, &lPrevious); - } -}; - -// Ensures that memory is not read past the length source buffer -// and that memory is not written past the length of the dst buffer -// dst - buffer to copy to -// dst_size - total size of destination buffer -// cb_dst_offset - offset, first byte copied to dst+cb_dst_offset -// src - buffer to copy from -// src_size - total size of source buffer -// cb_src_offset - offset, first byte copied from src+cb_src_offset -// count - number of bytes to copy -// -// Returns: -// S_OK - no error -// E_INVALIDARG - values passed would lead to overrun -HRESULT AMSafeMemMoveOffset( - __in_bcount(dst_size) void * dst, - __in size_t dst_size, - __in DWORD cb_dst_offset, - __in_bcount(src_size) const void * src, - __in size_t src_size, - __in DWORD cb_src_offset, - __in size_t count); - -extern "C" -void * __stdcall memmoveInternal(void *, const void *, size_t); - -inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt) -{ -#ifdef _X86_ - void *pRet = NULL; - - _asm { - cld // make sure we get the direction right - mov ecx, cnt // num of bytes to scan - mov edi, buf // pointer byte stream - mov eax, chr // byte to scan for - repne scasb // look for the byte in the byte stream - jnz exit_memchr // Z flag set if byte found - dec edi // scasb always increments edi even when it - // finds the required byte - mov pRet, edi -exit_memchr: - } - return pRet; - -#else - while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) { - buf = (unsigned char *)buf + 1; - cnt--; - } - - return(cnt ? (void *)buf : NULL); -#endif -} - -void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr); - -#define WstrToInt(sz) _wtoi(sz) -#define atoiW(sz) _wtoi(sz) -#define atoiA(sz) atoi(sz) - -// These are available to help managing bitmap VIDEOINFOHEADER media structures - -extern const DWORD bits555[3]; -extern const DWORD bits565[3]; -extern const DWORD bits888[3]; - -// These help convert between VIDEOINFOHEADER and BITMAPINFO structures - -STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader); -STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader); -STDAPI_(WORD) GetBitCount(const GUID *pSubtype); - -// strmbase.lib implements this for compatibility with people who -// managed to link to this directly. we don't want to advertise it. -// -// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype); - -STDAPI_(LPCSTR) GetSubtypeNameA(const GUID *pSubtype); -STDAPI_(LPCWSTR) GetSubtypeNameW(const GUID *pSubtype); - -#ifdef UNICODE -#define GetSubtypeName GetSubtypeNameW -#else -#define GetSubtypeName GetSubtypeNameA -#endif - -STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader); -STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader); - -#ifdef __AMVIDEO__ -STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo); -STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo); -#endif // __AMVIDEO__ - - -// Compares two interfaces and returns TRUE if they are on the same object -BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond); - -// This is for comparing pins -#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2) - - -// Arithmetic helper functions - -// Compute (a * b + rnd) / c -LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd); -LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd); - - -// Avoids us dyna-linking to SysAllocString to copy BSTR strings -STDAPI WriteBSTR(__deref_out BSTR * pstrDest, LPCWSTR szSrc); -STDAPI FreeBSTR(__deref_in BSTR* pstr); - -// Return a wide string - allocating memory for it -// Returns: -// S_OK - no error -// E_POINTER - ppszReturn == NULL -// E_OUTOFMEMORY - can't allocate memory for returned string -STDAPI AMGetWideString(LPCWSTR pszString, __deref_out LPWSTR *ppszReturn); - -// Special wait for objects owning windows -DWORD WINAPI WaitDispatchingMessages( - HANDLE hObject, - DWORD dwWait, - HWND hwnd = NULL, - UINT uMsg = 0, - HANDLE hEvent = NULL); - -// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in -// our use of HRESULT_FROM_WIN32, it typically means a function failed -// to call SetLastError(), and we still want a failure code. -// -#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x)) - -// call GetLastError and return an HRESULT value that will fail the -// SUCCEEDED() macro. -HRESULT AmGetLastErrorToHResult(void); - -// duplicate of ATL's CComPtr to avoid linker conflicts. - -IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp); - -template -class QzCComPtr -{ -public: - typedef T _PtrClass; - QzCComPtr() {p=NULL;} - QzCComPtr(T* lp) - { - if ((p = lp) != NULL) - p->AddRef(); - } - QzCComPtr(const QzCComPtr& lp) - { - if ((p = lp.p) != NULL) - p->AddRef(); - } - ~QzCComPtr() {if (p) p->Release();} - void Release() {if (p) p->Release(); p=NULL;} - operator T*() {return (T*)p;} - T& operator*() {ASSERT(p!=NULL); return *p; } - //The assert on operator& usually indicates a bug. If this is really - //what is needed, however, take the address of the p member explicitly. - T** operator&() { ASSERT(p==NULL); return &p; } - T* operator->() { ASSERT(p!=NULL); return p; } - T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);} - T* operator=(const QzCComPtr& lp) - { - return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p); - } -#if _MSC_VER>1020 - bool operator!(){return (p == NULL);} -#else - BOOL operator!(){return (p == NULL) ? TRUE : FALSE;} -#endif - T* p; -}; - -MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ); -bool TimeKillSynchronousFlagAvailable( void ); - -// Helper to replace lstrcpmi -__inline int lstrcmpiLocaleIndependentW(LPCWSTR lpsz1, LPCWSTR lpsz2) -{ - return CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL; -} -__inline int lstrcmpiLocaleIndependentA(LPCSTR lpsz1, LPCSTR lpsz2) -{ - return CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL; -} - -#endif /* __WXUTIL__ */ +//------------------------------------------------------------------------------ +// File: WXUtil.h +// +// Desc: DirectShow base classes - defines helper classes and functions for +// building multimedia filters. +// +// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. +//------------------------------------------------------------------------------ + + +#ifndef __WXUTIL__ +#define __WXUTIL__ + +// eliminate spurious "statement has no effect" warnings. +#pragma warning(disable: 4705) + +// wrapper for whatever critical section we have +class CCritSec { + + // make copy constructor and assignment operator inaccessible + + CCritSec(const CCritSec &refCritSec); + CCritSec &operator=(const CCritSec &refCritSec); + + CRITICAL_SECTION m_CritSec; + +#ifdef _DEBUG +public: + DWORD m_currentOwner; + DWORD m_lockCount; + BOOL m_fTrace; // Trace this one +public: + CCritSec(); + ~CCritSec(); + void Lock(); + void Unlock(); +#else + +public: + CCritSec() { + InitializeCriticalSection(&m_CritSec); + }; + + ~CCritSec() { + DeleteCriticalSection(&m_CritSec); + }; + + void Lock() { + EnterCriticalSection(&m_CritSec); + }; + + void Unlock() { + LeaveCriticalSection(&m_CritSec); + }; +#endif +}; + +// +// To make deadlocks easier to track it is useful to insert in the +// code an assertion that says whether we own a critical section or +// not. We make the routines that do the checking globals to avoid +// having different numbers of member functions in the debug and +// retail class implementations of CCritSec. In addition we provide +// a routine that allows usage of specific critical sections to be +// traced. This is NOT on by default - there are far too many. +// + +#ifdef _DEBUG + BOOL WINAPI CritCheckIn(CCritSec * pcCrit); + BOOL WINAPI CritCheckIn(const CCritSec * pcCrit); + BOOL WINAPI CritCheckOut(CCritSec * pcCrit); + BOOL WINAPI CritCheckOut(const CCritSec * pcCrit); + void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace); +#else + #define CritCheckIn(x) TRUE + #define CritCheckOut(x) TRUE + #define DbgLockTrace(pc, fT) +#endif + + +// locks a critical section, and unlocks it automatically +// when the lock goes out of scope +class CAutoLock { + + // make copy constructor and assignment operator inaccessible + + CAutoLock(const CAutoLock &refAutoLock); + CAutoLock &operator=(const CAutoLock &refAutoLock); + +protected: + CCritSec * m_pLock; + +public: + CAutoLock(CCritSec * plock) + { + m_pLock = plock; + m_pLock->Lock(); + }; + + ~CAutoLock() { + m_pLock->Unlock(); + }; +}; + + + +// wrapper for event objects +class CAMEvent +{ + + // make copy constructor and assignment operator inaccessible + + CAMEvent(const CAMEvent &refEvent); + CAMEvent &operator=(const CAMEvent &refEvent); + +protected: + HANDLE m_hEvent; +public: + CAMEvent(BOOL fManualReset = FALSE, __inout_opt HRESULT *phr = NULL); + CAMEvent(__inout_opt HRESULT *phr); + ~CAMEvent(); + + // Cast to HANDLE - we don't support this as an lvalue + operator HANDLE () const { return m_hEvent; }; + + void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));}; + BOOL Wait(DWORD dwTimeout = INFINITE) { + return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0); + }; + void Reset() { ResetEvent(m_hEvent); }; + BOOL Check() { return Wait(0); }; +}; + + +// wrapper for event objects that do message processing +// This adds ONE method to the CAMEvent object to allow sent +// messages to be processed while waiting + +class CAMMsgEvent : public CAMEvent +{ + +public: + + CAMMsgEvent(__inout_opt HRESULT *phr = NULL); + + // Allow SEND messages to be processed while waiting + BOOL WaitMsg(DWORD dwTimeout = INFINITE); +}; + +// old name supported for the time being +#define CTimeoutEvent CAMEvent + +// support for a worker thread + +#ifdef AM_NOVTABLE +// simple thread class supports creation of worker thread, synchronization +// and communication. Can be derived to simplify parameter passing +class AM_NOVTABLE CAMThread { + + // make copy constructor and assignment operator inaccessible + + CAMThread(const CAMThread &refThread); + CAMThread &operator=(const CAMThread &refThread); + + CAMEvent m_EventSend; + CAMEvent m_EventComplete; + + DWORD m_dwParam; + DWORD m_dwReturnVal; + +protected: + HANDLE m_hThread; + + // thread will run this function on startup + // must be supplied by derived class + virtual DWORD ThreadProc() = 0; + +public: + CAMThread(__inout_opt HRESULT *phr = NULL); + virtual ~CAMThread(); + + CCritSec m_AccessLock; // locks access by client threads + CCritSec m_WorkerLock; // locks access to shared objects + + // thread initially runs this. param is actually 'this'. function + // just gets this and calls ThreadProc + static unsigned int WINAPI InitialThreadProc(__inout LPVOID pv); // MPC-HC patch + + // start thread running - error if already running + BOOL Create(); + + // signal the thread, and block for a response + // + DWORD CallWorker(DWORD); + + // accessor thread calls this when done with thread (having told thread + // to exit) + void Close() { + + // Disable warning: Conversion from LONG to PVOID of greater size +#pragma warning(push) +#pragma warning(disable: 4312) + HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0); +#pragma warning(pop) + + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + }; + + // ThreadExists + // Return TRUE if the thread exists. FALSE otherwise + BOOL ThreadExists(void) const + { + if (m_hThread == NULL) { + return FALSE; + } else { + return TRUE; + } + } + + // wait for the next request + DWORD GetRequest(); + + // is there a request? + BOOL CheckRequest(__out_opt DWORD * pParam); + + // reply to the request + void Reply(DWORD); + + // If you want to do WaitForMultipleObjects you'll need to include + // this handle in your wait list or you won't be responsive + HANDLE GetRequestHandle() const { return m_EventSend; }; + + // Find out what the request was + DWORD GetRequestParam() const { return m_dwParam; }; + + // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if + // available. S_FALSE means it's not available. + static HRESULT CoInitializeHelper(); +}; +#endif // AM_NOVTABLE + + +// CQueue +// +// Implements a simple Queue ADT. The queue contains a finite number of +// objects, access to which is controlled by a semaphore. The semaphore +// is created with an initial count (N). Each time an object is added +// a call to WaitForSingleObject is made on the semaphore's handle. When +// this function returns a slot has been reserved in the queue for the new +// object. If no slots are available the function blocks until one becomes +// available. Each time an object is removed from the queue ReleaseSemaphore +// is called on the semaphore's handle, thus freeing a slot in the queue. +// If no objects are present in the queue the function blocks until an +// object has been added. + +#define DEFAULT_QUEUESIZE 2 + +template class CQueue { +private: + HANDLE hSemPut; // Semaphore controlling queue "putting" + HANDLE hSemGet; // Semaphore controlling queue "getting" + CRITICAL_SECTION CritSect; // Thread seriallization + int nMax; // Max objects allowed in queue + int iNextPut; // Array index of next "PutMsg" + int iNextGet; // Array index of next "GetMsg" + T *QueueObjects; // Array of objects (ptr's to void) + + void Initialize(int n) { + iNextPut = iNextGet = 0; + nMax = n; + InitializeCriticalSection(&CritSect); + hSemPut = CreateSemaphore(NULL, n, n, NULL); + hSemGet = CreateSemaphore(NULL, 0, n, NULL); + QueueObjects = new T[n]; + } + + +public: + CQueue(int n) { + Initialize(n); + } + + CQueue() { + Initialize(DEFAULT_QUEUESIZE); + } + + ~CQueue() { + delete [] QueueObjects; + DeleteCriticalSection(&CritSect); + CloseHandle(hSemPut); + CloseHandle(hSemGet); + } + + T GetQueueObject() { + int iSlot; + T Object; + LONG lPrevious; + + // Wait for someone to put something on our queue, returns straight + // away is there is already an object on the queue. + // + WaitForSingleObject(hSemGet, INFINITE); + + EnterCriticalSection(&CritSect); + iSlot = iNextGet++ % nMax; + Object = QueueObjects[iSlot]; + LeaveCriticalSection(&CritSect); + + // Release anyone waiting to put an object onto our queue as there + // is now space available in the queue. + // + ReleaseSemaphore(hSemPut, 1L, &lPrevious); + return Object; + } + + void PutQueueObject(T Object) { + int iSlot; + LONG lPrevious; + + // Wait for someone to get something from our queue, returns straight + // away is there is already an empty slot on the queue. + // + WaitForSingleObject(hSemPut, INFINITE); + + EnterCriticalSection(&CritSect); + iSlot = iNextPut++ % nMax; + QueueObjects[iSlot] = Object; + LeaveCriticalSection(&CritSect); + + // Release anyone waiting to remove an object from our queue as there + // is now an object available to be removed. + // + ReleaseSemaphore(hSemGet, 1L, &lPrevious); + } +}; + +// Ensures that memory is not read past the length source buffer +// and that memory is not written past the length of the dst buffer +// dst - buffer to copy to +// dst_size - total size of destination buffer +// cb_dst_offset - offset, first byte copied to dst+cb_dst_offset +// src - buffer to copy from +// src_size - total size of source buffer +// cb_src_offset - offset, first byte copied from src+cb_src_offset +// count - number of bytes to copy +// +// Returns: +// S_OK - no error +// E_INVALIDARG - values passed would lead to overrun +HRESULT AMSafeMemMoveOffset( + __in_bcount(dst_size) void * dst, + __in size_t dst_size, + __in DWORD cb_dst_offset, + __in_bcount(src_size) const void * src, + __in size_t src_size, + __in DWORD cb_src_offset, + __in size_t count); + +extern "C" +void * __stdcall memmoveInternal(void *, const void *, size_t); + +inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt) +{ +#ifdef _X86_ + void *pRet = NULL; + + _asm { + cld // make sure we get the direction right + mov ecx, cnt // num of bytes to scan + mov edi, buf // pointer byte stream + mov eax, chr // byte to scan for + repne scasb // look for the byte in the byte stream + jnz exit_memchr // Z flag set if byte found + dec edi // scasb always increments edi even when it + // finds the required byte + mov pRet, edi +exit_memchr: + } + return pRet; + +#else + while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) { + buf = (unsigned char *)buf + 1; + cnt--; + } + + return(cnt ? (void *)buf : NULL); +#endif +} + +void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr); + +#define WstrToInt(sz) _wtoi(sz) +#define atoiW(sz) _wtoi(sz) +#define atoiA(sz) atoi(sz) + +// These are available to help managing bitmap VIDEOINFOHEADER media structures + +extern const DWORD bits555[3]; +extern const DWORD bits565[3]; +extern const DWORD bits888[3]; + +// These help convert between VIDEOINFOHEADER and BITMAPINFO structures + +STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader); +STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader); +STDAPI_(WORD) GetBitCount(const GUID *pSubtype); + +// strmbase.lib implements this for compatibility with people who +// managed to link to this directly. we don't want to advertise it. +// +// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype); + +STDAPI_(LPCSTR) GetSubtypeNameA(const GUID *pSubtype); +STDAPI_(LPCWSTR) GetSubtypeNameW(const GUID *pSubtype); + +#ifdef UNICODE +#define GetSubtypeName GetSubtypeNameW +#else +#define GetSubtypeName GetSubtypeNameA +#endif + +STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader); +STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader); + +#ifdef __AMVIDEO__ +STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo); +STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo); +#endif // __AMVIDEO__ + + +// Compares two interfaces and returns TRUE if they are on the same object +BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond); + +// This is for comparing pins +#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2) + + +// Arithmetic helper functions + +// Compute (a * b + rnd) / c +LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd); +LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd); + + +// Avoids us dyna-linking to SysAllocString to copy BSTR strings +STDAPI WriteBSTR(__deref_out BSTR * pstrDest, LPCWSTR szSrc); +STDAPI FreeBSTR(__deref_in BSTR* pstr); + +// Return a wide string - allocating memory for it +// Returns: +// S_OK - no error +// E_POINTER - ppszReturn == NULL +// E_OUTOFMEMORY - can't allocate memory for returned string +STDAPI AMGetWideString(LPCWSTR pszString, __deref_out LPWSTR *ppszReturn); + +// Special wait for objects owning windows +DWORD WINAPI WaitDispatchingMessages( + HANDLE hObject, + DWORD dwWait, + HWND hwnd = NULL, + UINT uMsg = 0, + HANDLE hEvent = NULL); + +// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in +// our use of HRESULT_FROM_WIN32, it typically means a function failed +// to call SetLastError(), and we still want a failure code. +// +#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x)) + +// call GetLastError and return an HRESULT value that will fail the +// SUCCEEDED() macro. +HRESULT AmGetLastErrorToHResult(void); + +// duplicate of ATL's CComPtr to avoid linker conflicts. + +IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp); + +template +class QzCComPtr +{ +public: + typedef T _PtrClass; + QzCComPtr() {p=NULL;} + QzCComPtr(T* lp) + { + if ((p = lp) != NULL) + p->AddRef(); + } + QzCComPtr(const QzCComPtr& lp) + { + if ((p = lp.p) != NULL) + p->AddRef(); + } + ~QzCComPtr() {if (p) p->Release();} + void Release() {if (p) p->Release(); p=NULL;} + operator T*() {return (T*)p;} + T& operator*() {ASSERT(p!=NULL); return *p; } + //The assert on operator& usually indicates a bug. If this is really + //what is needed, however, take the address of the p member explicitly. + T** operator&() { ASSERT(p==NULL); return &p; } + T* operator->() { ASSERT(p!=NULL); return p; } + T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);} + T* operator=(const QzCComPtr& lp) + { + return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p); + } +#if _MSC_VER>1020 + bool operator!(){return (p == NULL);} +#else + BOOL operator!(){return (p == NULL) ? TRUE : FALSE;} +#endif + T* p; +}; + +MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ); +bool TimeKillSynchronousFlagAvailable( void ); + +// Helper to replace lstrcpmi +__inline int lstrcmpiLocaleIndependentW(LPCWSTR lpsz1, LPCWSTR lpsz2) +{ + return CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL; +} +__inline int lstrcmpiLocaleIndependentA(LPCSTR lpsz1, LPCSTR lpsz2) +{ + return CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL; +} + +#endif /* __WXUTIL__ */ diff --git a/src/thirdparty/LAVFilters/LAVFilters.vcxproj b/src/thirdparty/LAVFilters/LAVFilters.vcxproj index cf2306793fe..096de5fe8d1 100644 --- a/src/thirdparty/LAVFilters/LAVFilters.vcxproj +++ b/src/thirdparty/LAVFilters/LAVFilters.vcxproj @@ -1,50 +1,50 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {ED257874-E12E-4143-AF0A-0676DA3BB18C} - LAVFilters - LAVFilters - LAVFilters - - - - 10.0 - v142 - false - Makefile - - - - - - - - - - $(IntDir) - build_lavfilters.bat Build $(Platform) $(Configuration) Silent Nocolors - build_lavfilters.bat Rebuild $(Platform) $(Configuration) Silent Nocolors - build_lavfilters.bat Clean $(Platform) $(Configuration) Silent Nocolors - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {ED257874-E12E-4143-AF0A-0676DA3BB18C} + LAVFilters + LAVFilters + LAVFilters + + + + 10.0 + v142 + false + Makefile + + + + + + + + + + $(IntDir) + build_lavfilters.bat Build $(Platform) $(Configuration) Silent Nocolors + build_lavfilters.bat Rebuild $(Platform) $(Configuration) Silent Nocolors + build_lavfilters.bat Clean $(Platform) $(Configuration) Silent Nocolors + + + + \ No newline at end of file diff --git a/src/thirdparty/LAVFilters/build_lavfilters.bat b/src/thirdparty/LAVFilters/build_lavfilters.bat index 0f9782162ae..381f3108452 100755 --- a/src/thirdparty/LAVFilters/build_lavfilters.bat +++ b/src/thirdparty/LAVFilters/build_lavfilters.bat @@ -1,231 +1,231 @@ -@ECHO OFF -REM (C) 2013-2017 see Authors.txt -REM -REM This file is part of MPC-HC. -REM -REM MPC-HC is free software; you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation; either version 3 of the License, or -REM (at your option) any later version. -REM -REM MPC-HC is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with this program. If not, see . - - -SETLOCAL EnableDelayedExpansion -SET "FILE_DIR=%~dp0" -PUSHD "%FILE_DIR%" - -SET ROOT_DIR=..\..\.. -SET "COMMON=%FILE_DIR%%ROOT_DIR%\common.bat" - -CALL "%COMMON%" :SubSetPath -IF %ERRORLEVEL% NEQ 0 EXIT /B 1 -CALL "%COMMON%" :SubDoesExist gcc.exe -IF %ERRORLEVEL% NEQ 0 ( - ECHO ERROR: gcc.exe not found in your MinGW installation - EXIT /B 1 -) - -SET ARG=/%* -SET ARG=%ARG:/=% -SET ARG=%ARG:-=% -SET ARGB=0 -SET ARGBC=0 -SET ARGCOMP=0 -SET ARGPL=0 -SET INPUT=0 -SET VALID=0 - -IF /I "%ARG%" == "?" GOTO ShowHelp - -FOR %%G IN (%ARG%) DO ( - IF /I "%%G" == "help" GOTO ShowHelp - IF /I "%%G" == "Build" SET "BUILDTYPE=Build" & SET /A ARGB+=1 - IF /I "%%G" == "Clean" SET "BUILDTYPE=Clean" & SET /A ARGB+=1 - IF /I "%%G" == "Rebuild" SET "BUILDTYPE=Rebuild" & SET /A ARGB+=1 - IF /I "%%G" == "Both" SET "ARCH=Both" & SET /A ARGPL+=1 - IF /I "%%G" == "Win32" SET "ARCH=x86" & SET /A ARGPL+=1 - IF /I "%%G" == "x86" SET "ARCH=x86" & SET /A ARGPL+=1 - IF /I "%%G" == "x64" SET "ARCH=x64" & SET /A ARGPL+=1 - IF /I "%%G" == "Debug" SET "RELEASETYPE=Debug" & SET /A ARGBC+=1 - IF /I "%%G" == "Release" SET "RELEASETYPE=Release" & SET /A ARGBC+=1 - IF /I "%%G" == "VS2017" SET "COMPILER=VS2017" & SET /A ARGCOMP+=1 +@ECHO OFF +REM (C) 2013-2017 see Authors.txt +REM +REM This file is part of MPC-HC. +REM +REM MPC-HC is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation; either version 3 of the License, or +REM (at your option) any later version. +REM +REM MPC-HC is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with this program. If not, see . + + +SETLOCAL EnableDelayedExpansion +SET "FILE_DIR=%~dp0" +PUSHD "%FILE_DIR%" + +SET ROOT_DIR=..\..\.. +SET "COMMON=%FILE_DIR%%ROOT_DIR%\common.bat" + +CALL "%COMMON%" :SubSetPath +IF %ERRORLEVEL% NEQ 0 EXIT /B 1 +CALL "%COMMON%" :SubDoesExist gcc.exe +IF %ERRORLEVEL% NEQ 0 ( + ECHO ERROR: gcc.exe not found in your MinGW installation + EXIT /B 1 +) + +SET ARG=/%* +SET ARG=%ARG:/=% +SET ARG=%ARG:-=% +SET ARGB=0 +SET ARGBC=0 +SET ARGCOMP=0 +SET ARGPL=0 +SET INPUT=0 +SET VALID=0 + +IF /I "%ARG%" == "?" GOTO ShowHelp + +FOR %%G IN (%ARG%) DO ( + IF /I "%%G" == "help" GOTO ShowHelp + IF /I "%%G" == "Build" SET "BUILDTYPE=Build" & SET /A ARGB+=1 + IF /I "%%G" == "Clean" SET "BUILDTYPE=Clean" & SET /A ARGB+=1 + IF /I "%%G" == "Rebuild" SET "BUILDTYPE=Rebuild" & SET /A ARGB+=1 + IF /I "%%G" == "Both" SET "ARCH=Both" & SET /A ARGPL+=1 + IF /I "%%G" == "Win32" SET "ARCH=x86" & SET /A ARGPL+=1 + IF /I "%%G" == "x86" SET "ARCH=x86" & SET /A ARGPL+=1 + IF /I "%%G" == "x64" SET "ARCH=x64" & SET /A ARGPL+=1 + IF /I "%%G" == "Debug" SET "RELEASETYPE=Debug" & SET /A ARGBC+=1 + IF /I "%%G" == "Release" SET "RELEASETYPE=Release" & SET /A ARGBC+=1 + IF /I "%%G" == "VS2017" SET "COMPILER=VS2017" & SET /A ARGCOMP+=1 IF /I "%%G" == "VS2019" SET "COMPILER=VS2019" & SET /A ARGCOMP+=1 - IF /I "%%G" == "Silent" SET "SILENT=True" & SET /A VALID+=1 - IF /I "%%G" == "Nocolors" SET "NOCOLORS=True" & SET /A VALID+=1 -) - -FOR %%X IN (%*) DO SET /A INPUT+=1 -SET /A VALID+=%ARGB%+%ARGPL%+%ARGBC%+%ARGCOMP% - -IF %VALID% NEQ %INPUT% GOTO UnsupportedSwitch - -IF %ARGB% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGB% == 0 (SET "BUILDTYPE=Build") -IF %ARGPL% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGPL% == 0 (SET "ARCH=Both") -IF %ARGBC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGBC% == 0 (SET "RELEASETYPE=Release") + IF /I "%%G" == "Silent" SET "SILENT=True" & SET /A VALID+=1 + IF /I "%%G" == "Nocolors" SET "NOCOLORS=True" & SET /A VALID+=1 +) + +FOR %%X IN (%*) DO SET /A INPUT+=1 +SET /A VALID+=%ARGB%+%ARGPL%+%ARGBC%+%ARGCOMP% + +IF %VALID% NEQ %INPUT% GOTO UnsupportedSwitch + +IF %ARGB% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGB% == 0 (SET "BUILDTYPE=Build") +IF %ARGPL% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGPL% == 0 (SET "ARCH=Both") +IF %ARGBC% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGBC% == 0 (SET "RELEASETYPE=Release") IF %ARGCOMP% GTR 1 (GOTO UnsupportedSwitch) ELSE IF %ARGCOMP% == 0 (SET "COMPILER=VS2019") IF NOT EXIST "%MPCHC_VS_PATH%" CALL "%COMMON%" :SubVSPath -IF NOT EXIST "!MPCHC_VS_PATH!" ( - ECHO ERROR: Visual Studio install path not found or invalid. You should add MPCHC_VS_PATH to build.user.bat - GOTO MissingVar -) +IF NOT EXIST "!MPCHC_VS_PATH!" ( + ECHO ERROR: Visual Studio install path not found or invalid. You should add MPCHC_VS_PATH to build.user.bat + GOTO MissingVar +) SET "TOOLSET=!MPCHC_VS_PATH!\Common7\Tools\vsdevcmd" -IF NOT EXIST "%TOOLSET%" ( - ECHO ERROR: Visual Studio tool path invalid - GOTO MissingVar -) - -SET "BIN_DIR=%ROOT_DIR%\bin" - -CALL "%COMMON%" :SubParseConfig - -IF /I "%ARCH%" == "Both" ( - SET "ARCH=x86" & CALL :Main - SET "ARCH=x64" & CALL :Main -) ELSE ( - CALL :Main -) -GOTO End - - -:Main -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%ARCH%" == "x86" (SET TOOLSETARCH=x86) ELSE (SET TOOLSETARCH=amd64) -CALL "%TOOLSET%" -no_logo -arch=%TOOLSETARCH% - -SET START_TIME=%TIME% -SET START_DATE=%DATE% - -IF /I "%BUILDTYPE%" == "Rebuild" ( - SET "BUILDTYPE=Clean" & CALL :SubMake - SET "BUILDTYPE=Build" & CALL :SubMake - SET "BUILDTYPE=Rebuild" - EXIT /B -) - -IF /I "%BUILDTYPE%" == "Clean" (CALL :SubMake & EXIT /B) - -CALL :SubMake - -EXIT /B - - -:End -IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% -TITLE Compiling LAV Filters %COMPILER% [FINISHED] -SET END_TIME=%TIME% -CALL "%COMMON%" :SubGetDuration -CALL "%COMMON%" :SubMsg "INFO" "LAV Filters compilation started on %START_DATE%-%START_TIME% and completed on %DATE%-%END_TIME% [%DURATION%]" -POPD -ENDLOCAL -EXIT /B - - -:SubMake -IF %ERRORLEVEL% NEQ 0 EXIT /B - -IF /I "%ARCH%" == "x86" (SET "ARCHVS=Win32") ELSE (SET "ARCHVS=x64") - -REM Build FFmpeg -sh build_ffmpeg.sh %ARCH% %RELEASETYPE% %BUILDTYPE% %COMPILER% -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "'sh build_ffmpeg.sh %ARCH% %RELEASETYPE% %BUILDTYPE% %COMPILER%' failed!" - EXIT /B -) - -PUSHD src - -REM Build LAVFilters -IF /I "%ARCH%" == "x86" (SET "ARCHVS=Win32") ELSE (SET "ARCHVS=x64") - -MSBuild.exe LAVFilters.sln /nologo /consoleloggerparameters:Verbosity=minimal /nodeReuse:true /m /t:%BUILDTYPE% /property:Configuration=%RELEASETYPE%;Platform=%ARCHVS% -IF %ERRORLEVEL% NEQ 0 ( - CALL "%COMMON%" :SubMsg "ERROR" "'MSBuild.exe LAVFilters.sln /nologo /consoleloggerparameters:Verbosity=minimal /nodeReuse:true /m /t:%BUILDTYPE% /property:Configuration=%RELEASETYPE%;Platform=%ARCHVS%' failed!" - EXIT /B -) - -POPD - -IF /I "%RELEASETYPE%" == "Debug" ( - SET "SRCFOLDER=src\bin_%ARCHVS%d" -) ELSE ( - SET "SRCFOLDER=src\bin_%ARCHVS%" -) - -IF /I "%RELEASETYPE%" == "Debug" ( - SET "DESTFOLDER=%BIN_DIR%\mpc-hc_%ARCH%_Debug" -) ELSE ( - SET "DESTFOLDER=%BIN_DIR%\mpc-hc_%ARCH%" -) - -IF /I "%ARCH%" == "x64" ( - SET "DESTFOLDER=%DESTFOLDER%\LAVFilters64" -) ELSE ( - SET "DESTFOLDER=%DESTFOLDER%\LAVFilters" -) - -IF /I "%BUILDTYPE%" == "Build" ( - REM Copy LAVFilters files to MPC-HC output directory - IF NOT EXIST %DESTFOLDER% MD %DESTFOLDER% - - COPY /Y /V %SRCFOLDER%\*.dll %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\*.ax %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\*.manifest %DESTFOLDER% - IF /I "%RELEASETYPE%" == "Release" ( - COPY /Y /V %SRCFOLDER%\IntelQuickSyncDecoder\IntelQuickSyncDecoder.pdb %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\LAVAudio\LAVAudio.pdb %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\LAVSplitter\LAVSplitter.pdb %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\LAVVideo\LAVVideo.pdb %DESTFOLDER% - COPY /Y /V %SRCFOLDER%\libbluray\libbluray.pdb %DESTFOLDER% - ) ELSE ( - COPY /Y /V %SRCFOLDER%\*.pdb %DESTFOLDER% - ) -) ELSE IF /I "%BUILDTYPE%" == "Clean" ( - REM Remove LAVFilters files in MPC-HC output directory - IF EXIST %DESTFOLDER% RD /Q /S %DESTFOLDER% -) - -EXIT /B - - -:MissingVar -ECHO Not all build dependencies were found. -ECHO. -ECHO See "%ROOT_DIR%\docs\Compilation.md" for more information. -CALL "%COMMON%" :SubMsg "ERROR" "LAV Filters compilation failed!" & EXIT /B 1 - - -:UnsupportedSwitch -ECHO. -ECHO Unsupported commandline switch! -ECHO. -ECHO "%~nx0 %*" -ECHO. -ECHO Run "%~nx0 help" for details about the commandline switches. -CALL "%COMMON%" :SubMsg "ERROR" "LAV Filters compilation failed!" & EXIT /B 1 - - -:ShowHelp -TITLE %~nx0 Help -ECHO. -ECHO Usage: +IF NOT EXIST "%TOOLSET%" ( + ECHO ERROR: Visual Studio tool path invalid + GOTO MissingVar +) + +SET "BIN_DIR=%ROOT_DIR%\bin" + +CALL "%COMMON%" :SubParseConfig + +IF /I "%ARCH%" == "Both" ( + SET "ARCH=x86" & CALL :Main + SET "ARCH=x64" & CALL :Main +) ELSE ( + CALL :Main +) +GOTO End + + +:Main +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%ARCH%" == "x86" (SET TOOLSETARCH=x86) ELSE (SET TOOLSETARCH=amd64) +CALL "%TOOLSET%" -no_logo -arch=%TOOLSETARCH% + +SET START_TIME=%TIME% +SET START_DATE=%DATE% + +IF /I "%BUILDTYPE%" == "Rebuild" ( + SET "BUILDTYPE=Clean" & CALL :SubMake + SET "BUILDTYPE=Build" & CALL :SubMake + SET "BUILDTYPE=Rebuild" + EXIT /B +) + +IF /I "%BUILDTYPE%" == "Clean" (CALL :SubMake & EXIT /B) + +CALL :SubMake + +EXIT /B + + +:End +IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% +TITLE Compiling LAV Filters %COMPILER% [FINISHED] +SET END_TIME=%TIME% +CALL "%COMMON%" :SubGetDuration +CALL "%COMMON%" :SubMsg "INFO" "LAV Filters compilation started on %START_DATE%-%START_TIME% and completed on %DATE%-%END_TIME% [%DURATION%]" +POPD +ENDLOCAL +EXIT /B + + +:SubMake +IF %ERRORLEVEL% NEQ 0 EXIT /B + +IF /I "%ARCH%" == "x86" (SET "ARCHVS=Win32") ELSE (SET "ARCHVS=x64") + +REM Build FFmpeg +sh build_ffmpeg.sh %ARCH% %RELEASETYPE% %BUILDTYPE% %COMPILER% +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "'sh build_ffmpeg.sh %ARCH% %RELEASETYPE% %BUILDTYPE% %COMPILER%' failed!" + EXIT /B +) + +PUSHD src + +REM Build LAVFilters +IF /I "%ARCH%" == "x86" (SET "ARCHVS=Win32") ELSE (SET "ARCHVS=x64") + +MSBuild.exe LAVFilters.sln /nologo /consoleloggerparameters:Verbosity=minimal /nodeReuse:true /m /t:%BUILDTYPE% /property:Configuration=%RELEASETYPE%;Platform=%ARCHVS% +IF %ERRORLEVEL% NEQ 0 ( + CALL "%COMMON%" :SubMsg "ERROR" "'MSBuild.exe LAVFilters.sln /nologo /consoleloggerparameters:Verbosity=minimal /nodeReuse:true /m /t:%BUILDTYPE% /property:Configuration=%RELEASETYPE%;Platform=%ARCHVS%' failed!" + EXIT /B +) + +POPD + +IF /I "%RELEASETYPE%" == "Debug" ( + SET "SRCFOLDER=src\bin_%ARCHVS%d" +) ELSE ( + SET "SRCFOLDER=src\bin_%ARCHVS%" +) + +IF /I "%RELEASETYPE%" == "Debug" ( + SET "DESTFOLDER=%BIN_DIR%\mpc-hc_%ARCH%_Debug" +) ELSE ( + SET "DESTFOLDER=%BIN_DIR%\mpc-hc_%ARCH%" +) + +IF /I "%ARCH%" == "x64" ( + SET "DESTFOLDER=%DESTFOLDER%\LAVFilters64" +) ELSE ( + SET "DESTFOLDER=%DESTFOLDER%\LAVFilters" +) + +IF /I "%BUILDTYPE%" == "Build" ( + REM Copy LAVFilters files to MPC-HC output directory + IF NOT EXIST %DESTFOLDER% MD %DESTFOLDER% + + COPY /Y /V %SRCFOLDER%\*.dll %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\*.ax %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\*.manifest %DESTFOLDER% + IF /I "%RELEASETYPE%" == "Release" ( + COPY /Y /V %SRCFOLDER%\IntelQuickSyncDecoder\IntelQuickSyncDecoder.pdb %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\LAVAudio\LAVAudio.pdb %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\LAVSplitter\LAVSplitter.pdb %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\LAVVideo\LAVVideo.pdb %DESTFOLDER% + COPY /Y /V %SRCFOLDER%\libbluray\libbluray.pdb %DESTFOLDER% + ) ELSE ( + COPY /Y /V %SRCFOLDER%\*.pdb %DESTFOLDER% + ) +) ELSE IF /I "%BUILDTYPE%" == "Clean" ( + REM Remove LAVFilters files in MPC-HC output directory + IF EXIST %DESTFOLDER% RD /Q /S %DESTFOLDER% +) + +EXIT /B + + +:MissingVar +ECHO Not all build dependencies were found. +ECHO. +ECHO See "%ROOT_DIR%\docs\Compilation.md" for more information. +CALL "%COMMON%" :SubMsg "ERROR" "LAV Filters compilation failed!" & EXIT /B 1 + + +:UnsupportedSwitch +ECHO. +ECHO Unsupported commandline switch! +ECHO. +ECHO "%~nx0 %*" +ECHO. +ECHO Run "%~nx0 help" for details about the commandline switches. +CALL "%COMMON%" :SubMsg "ERROR" "LAV Filters compilation failed!" & EXIT /B 1 + + +:ShowHelp +TITLE %~nx0 Help +ECHO. +ECHO Usage: ECHO %~nx0 [Clean^|Build^|Rebuild] [x86^|x64^|Both] [Debug^|Release] [VS2017^|VS2019] -ECHO. -ECHO Notes: You can also prefix the commands with "-", "--" or "/". -ECHO The arguments are not case sensitive and can be ommitted. -ECHO. & ECHO. -ECHO Executing %~nx0 without any arguments will use the default ones: +ECHO. +ECHO Notes: You can also prefix the commands with "-", "--" or "/". +ECHO The arguments are not case sensitive and can be ommitted. +ECHO. & ECHO. +ECHO Executing %~nx0 without any arguments will use the default ones: ECHO "%~nx0 Build Both Release VS2019" -ECHO. -POPD -ENDLOCAL -EXIT /B +ECHO. +POPD +ENDLOCAL +EXIT /B diff --git a/src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp b/src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp index 7f4275b35f4..9eb0b9ebd54 100644 --- a/src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp +++ b/src/thirdparty/LCDUI/LCDAnimatedBitmap.cpp @@ -1,146 +1,146 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDAnimatedBitmap.cpp -// -// The CLCDAnimatedBitmap class draws animated bitmaps onto the LCD. -// An animated bitmap consists of a tiled bitmap representing the -// animation. The tile size is set with the SetSubpicWidth. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDAnimatedBitmap::CLCDAnimatedBitmap -// -//************************************************************************ - -CLCDAnimatedBitmap::CLCDAnimatedBitmap(void) -{ - m_dwCurrSubpic = 0; - m_dwTotalSubpics = 0; -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::CLCDAnimatedBitmap -// -//************************************************************************ - -CLCDAnimatedBitmap::~CLCDAnimatedBitmap(void) -{ - -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::Initialize -// -//************************************************************************ - -HRESULT CLCDAnimatedBitmap::Initialize(void) -{ - m_dwRate = 250; - m_dwElapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - - return S_OK; -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::ResetUpdate -// -//************************************************************************ - -void CLCDAnimatedBitmap::ResetUpdate(void) -{ - m_dwCurrSubpic = 0; - m_dwLastUpdate = GetTickCount(); -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::SetSubpicWidth -// -//************************************************************************ - -void CLCDAnimatedBitmap::SetSubpicWidth(DWORD dwWidth) -{ - m_dwSubpicWidth = dwWidth; - LCDUIASSERT(NULL != m_hBitmap); - LCDUIASSERT(0 != dwWidth); - if((NULL != m_hBitmap) && (0 != dwWidth)) - { - // figure out how many tiles we have - BITMAP bitmap; - if(GetObject(m_hBitmap, sizeof(bitmap), &bitmap)) - { - m_dwTotalSubpics = bitmap.bmWidth / dwWidth; - SetLogicalSize(bitmap.bmWidth, bitmap.bmHeight); - } - else - { - m_dwTotalSubpics = 0; - } - } - else - { - m_dwTotalSubpics = 0; - } -} - -//************************************************************************ -// -// CLCDAnimatedBitmap::SetAnimationRate -// -//************************************************************************ - -void CLCDAnimatedBitmap::SetAnimationRate(DWORD dwRate) -{ - m_dwRate = dwRate; -} - - -//************************************************************************ -// -// CLCDAnimatedBitmap::OnUpdate -// -//************************************************************************ - -void CLCDAnimatedBitmap::OnUpdate(DWORD dwTimestamp) -{ - m_dwElapsedTime = (dwTimestamp - m_dwLastUpdate); - - // Just update the logical origin - SetLogicalOrigin(-1 * m_dwSubpicWidth * m_dwCurrSubpic, 0); - - DWORD increment = m_dwElapsedTime / m_dwRate; - if(increment > 0) - { - m_dwCurrSubpic += increment; - m_dwCurrSubpic %= m_dwTotalSubpics; - m_dwElapsedTime %= m_dwRate; - m_dwLastUpdate = GetTickCount(); - } -} - - -//** end of LCDAnimatedBitmap.cpp **************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDAnimatedBitmap.cpp +// +// The CLCDAnimatedBitmap class draws animated bitmaps onto the LCD. +// An animated bitmap consists of a tiled bitmap representing the +// animation. The tile size is set with the SetSubpicWidth. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDAnimatedBitmap::CLCDAnimatedBitmap +// +//************************************************************************ + +CLCDAnimatedBitmap::CLCDAnimatedBitmap(void) +{ + m_dwCurrSubpic = 0; + m_dwTotalSubpics = 0; +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::CLCDAnimatedBitmap +// +//************************************************************************ + +CLCDAnimatedBitmap::~CLCDAnimatedBitmap(void) +{ + +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::Initialize +// +//************************************************************************ + +HRESULT CLCDAnimatedBitmap::Initialize(void) +{ + m_dwRate = 250; + m_dwElapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + + return S_OK; +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::ResetUpdate +// +//************************************************************************ + +void CLCDAnimatedBitmap::ResetUpdate(void) +{ + m_dwCurrSubpic = 0; + m_dwLastUpdate = GetTickCount(); +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::SetSubpicWidth +// +//************************************************************************ + +void CLCDAnimatedBitmap::SetSubpicWidth(DWORD dwWidth) +{ + m_dwSubpicWidth = dwWidth; + LCDUIASSERT(NULL != m_hBitmap); + LCDUIASSERT(0 != dwWidth); + if((NULL != m_hBitmap) && (0 != dwWidth)) + { + // figure out how many tiles we have + BITMAP bitmap; + if(GetObject(m_hBitmap, sizeof(bitmap), &bitmap)) + { + m_dwTotalSubpics = bitmap.bmWidth / dwWidth; + SetLogicalSize(bitmap.bmWidth, bitmap.bmHeight); + } + else + { + m_dwTotalSubpics = 0; + } + } + else + { + m_dwTotalSubpics = 0; + } +} + +//************************************************************************ +// +// CLCDAnimatedBitmap::SetAnimationRate +// +//************************************************************************ + +void CLCDAnimatedBitmap::SetAnimationRate(DWORD dwRate) +{ + m_dwRate = dwRate; +} + + +//************************************************************************ +// +// CLCDAnimatedBitmap::OnUpdate +// +//************************************************************************ + +void CLCDAnimatedBitmap::OnUpdate(DWORD dwTimestamp) +{ + m_dwElapsedTime = (dwTimestamp - m_dwLastUpdate); + + // Just update the logical origin + SetLogicalOrigin(-1 * m_dwSubpicWidth * m_dwCurrSubpic, 0); + + DWORD increment = m_dwElapsedTime / m_dwRate; + if(increment > 0) + { + m_dwCurrSubpic += increment; + m_dwCurrSubpic %= m_dwTotalSubpics; + m_dwElapsedTime %= m_dwRate; + m_dwLastUpdate = GetTickCount(); + } +} + + +//** end of LCDAnimatedBitmap.cpp **************************************** diff --git a/src/thirdparty/LCDUI/LCDAnimatedBitmap.h b/src/thirdparty/LCDUI/LCDAnimatedBitmap.h index 8fb83b7a9ff..42d010ad75f 100644 --- a/src/thirdparty/LCDUI/LCDAnimatedBitmap.h +++ b/src/thirdparty/LCDUI/LCDAnimatedBitmap.h @@ -1,57 +1,57 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDAnimatedBitmap.h -// -// The CLCDAnimatedBitmap class draws animated bitmaps onto the LCD. -// An animated bitmap consists of a tiled bitmap representing the -// animation. The tile size is set with the SetSubpicWidth. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - - -#ifndef _LCDANIMATEDBITMAP_H_INCLUDED_ -#define _LCDANIMATEDBITMAP_H_INCLUDED_ - -#include "LCDBase.h" -#include "LCDBitmap.h" - -class CLCDAnimatedBitmap : public CLCDBitmap -{ -public: - CLCDAnimatedBitmap(void); - virtual ~CLCDAnimatedBitmap(void); - - virtual HRESULT Initialize(void); - virtual void ResetUpdate(void); - - void SetSubpicWidth(DWORD dwWidth); - void SetAnimationRate(DWORD dwRate); // milliseconds/subpicture - -protected: - virtual void OnUpdate(DWORD dwTimestamp); - -private: - DWORD m_dwElapsedTime; // elapsed time in state - DWORD m_dwRate; // milliseconds per subpicture - DWORD m_dwLastUpdate; // milliseconds - - DWORD m_dwSubpicWidth; - DWORD m_dwCurrSubpic; - DWORD m_dwTotalSubpics; -}; - - -#endif // !_LCDANIMATEDBITMAP_H_INCLUDED_ - -//** end of LCDBitmap.h ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDAnimatedBitmap.h +// +// The CLCDAnimatedBitmap class draws animated bitmaps onto the LCD. +// An animated bitmap consists of a tiled bitmap representing the +// animation. The tile size is set with the SetSubpicWidth. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + + +#ifndef _LCDANIMATEDBITMAP_H_INCLUDED_ +#define _LCDANIMATEDBITMAP_H_INCLUDED_ + +#include "LCDBase.h" +#include "LCDBitmap.h" + +class CLCDAnimatedBitmap : public CLCDBitmap +{ +public: + CLCDAnimatedBitmap(void); + virtual ~CLCDAnimatedBitmap(void); + + virtual HRESULT Initialize(void); + virtual void ResetUpdate(void); + + void SetSubpicWidth(DWORD dwWidth); + void SetAnimationRate(DWORD dwRate); // milliseconds/subpicture + +protected: + virtual void OnUpdate(DWORD dwTimestamp); + +private: + DWORD m_dwElapsedTime; // elapsed time in state + DWORD m_dwRate; // milliseconds per subpicture + DWORD m_dwLastUpdate; // milliseconds + + DWORD m_dwSubpicWidth; + DWORD m_dwCurrSubpic; + DWORD m_dwTotalSubpics; +}; + + +#endif // !_LCDANIMATEDBITMAP_H_INCLUDED_ + +//** end of LCDBitmap.h ************************************************** diff --git a/src/thirdparty/LCDUI/LCDBase.cpp b/src/thirdparty/LCDUI/LCDBase.cpp index 8964f0bf570..0b28837c56e 100644 --- a/src/thirdparty/LCDUI/LCDBase.cpp +++ b/src/thirdparty/LCDUI/LCDBase.cpp @@ -1,385 +1,385 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDBase.cpp -// -// The CLCDBase class is the generic base class for all lcd ui objects -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDBase::CLCDBase -// -//************************************************************************ - -CLCDBase::CLCDBase(void) -{ - m_Size.cx = 0; - m_Size.cy = 0; - m_Origin.x = 0; - m_Origin.y = 0; - m_bVisible = TRUE; - m_bInverted = FALSE; - ZeroMemory(&m_ptLogical, sizeof(m_ptLogical)); - ZeroMemory(&m_sizeLogical, sizeof(m_sizeLogical)); - m_nBkMode = TRANSPARENT; - m_objectType = LG_UNKNOWN; - m_crBackgroundColor = RGB(0, 0, 0); - m_crForegroundColor = RGB(255, 255, 255); -} - - -//************************************************************************ -// -// CLCDBase::~CLCDBase -// -//************************************************************************ - -CLCDBase::~CLCDBase(void) -{ -} - - -//************************************************************************ -// -// CLCDBase::Initialize -// -//************************************************************************ - -HRESULT CLCDBase::Initialize(void) -{ - return S_OK; -} - - -//************************************************************************ -// -// CLCDBase::Shutdown -// -//************************************************************************ - -void CLCDBase::Shutdown(void) -{ -} - - -//************************************************************************ -// -// CLCDBase::SetOrigin -// -//************************************************************************ - -void CLCDBase::SetOrigin(POINT pt) -{ - m_Origin = pt; -} - - -//************************************************************************ -// -// CLCDBase::SetOrigin -// -//************************************************************************ - -void CLCDBase::SetOrigin(int nX, int nY) -{ - POINT pt = { nX, nY }; - SetOrigin(pt); -} - - -//************************************************************************ -// -// CLCDBase::GetOrigin -// -//************************************************************************ - -POINT& CLCDBase::GetOrigin(void) -{ - return m_Origin; -} - - -//************************************************************************ -// -// CLCDBase::SetSize -// -//************************************************************************ - -void CLCDBase::SetSize(SIZE& size) -{ - m_Size = size; - SetLogicalSize(m_Size); -} - - -//************************************************************************ -// -// CLCDBase::SetSize -// -//************************************************************************ - -void CLCDBase::SetSize(int nCX, int nCY) -{ - SIZE size = { nCX, nCY }; - SetSize(size); -} - - -//************************************************************************ -// -// CLCDBase::GetSize -// -//************************************************************************ - -SIZE& CLCDBase::GetSize(void) -{ - return m_Size; -} - - -//************************************************************************ -// -// CLCDBase::SetLogicalOrigin -// -//************************************************************************ - -void CLCDBase::SetLogicalOrigin(POINT& pt) -{ - m_ptLogical = pt; -} - - -//************************************************************************ -// -// CLCDBase::SetLogicalOrigin -// -//************************************************************************ - -void CLCDBase::SetLogicalOrigin(int nX, int nY) -{ - m_ptLogical.x = nX; - m_ptLogical.y = nY; -} - - -//************************************************************************ -// -// CLCDBase::GetLogicalOrigin -// -//************************************************************************ - -POINT& CLCDBase::GetLogicalOrigin(void) -{ - return m_ptLogical; -} - - -//************************************************************************ -// -// CLCDBase::SetLogicalSize -// -//************************************************************************ - -void CLCDBase::SetLogicalSize(SIZE& size) -{ - m_sizeLogical = size; -} - - -//************************************************************************ -// -// CLCDBase::SetLogicalSize -// -//************************************************************************ - -void CLCDBase::SetLogicalSize(int nCX, int nCY) -{ - m_sizeLogical.cx = nCX; - m_sizeLogical.cy = nCY; -} - - -//************************************************************************ -// -// CLCDBase::GetLogicalSize -// -//************************************************************************ - -SIZE& CLCDBase::GetLogicalSize(void) -{ - return m_sizeLogical; -} - - -//************************************************************************ -// -// CLCDBase::Show -// -//************************************************************************ - -void CLCDBase::Show(BOOL bShow) -{ - m_bVisible = bShow; -} - - -//************************************************************************ -// -// BOOL CLCDBase:: -// -//************************************************************************ - -BOOL CLCDBase::IsVisible(void) -{ - return m_bVisible; -} - - -//************************************************************************ -// -// CLCDBase::Invert -// -//************************************************************************ - -void CLCDBase::Invert(BOOL bEnable) -{ - m_bInverted = bEnable; -} - - -//************************************************************************ -// -// CLCDBase::ResetUpdate -// -//************************************************************************ - -void CLCDBase::ResetUpdate(void) -{ - // do nothing -} - - -//************************************************************************ -// -// CLCDBase::OnUpdate -// -//************************************************************************ - -void CLCDBase::OnUpdate(DWORD dwTimestamp) -{ - UNREFERENCED_PARAMETER(dwTimestamp); -} - - -//************************************************************************ -// -// CLCDBase::OnPrepareDraw -// -//************************************************************************ - -void CLCDBase::OnPrepareDraw(CLCDGfxBase &rGfx) -{ - UNREFERENCED_PARAMETER(rGfx); -} - - -//************************************************************************ -// -// CLCDBase::OnDraw -// -//************************************************************************ - -void CLCDBase::OnDraw(CLCDGfxBase &rGfx) -{ - UNREFERENCED_PARAMETER(rGfx); -} - - -//************************************************************************ -// -// CLCDBase::SetBackgroundMode -// -//************************************************************************ - -void CLCDBase::SetBackgroundMode(int nMode) -{ - m_nBkMode = nMode; -} - - -//************************************************************************ -// -// CLCDBase::GetBackgroundMode -// -//************************************************************************ - -int CLCDBase::GetBackgroundMode() -{ - return m_nBkMode; -} - - -//************************************************************************ -// -// CLCDBase::GetObjectType -// -//************************************************************************ - -const LGObjectType CLCDBase::GetObjectType() -{ - return m_objectType; -} - - -//************************************************************************ -// -// CLCDBase::SetObjectType -// -//************************************************************************ - -void CLCDBase::SetObjectType(const LGObjectType type) -{ - m_objectType = type; -} - - -//************************************************************************ -// -// CLCDBase::SetForegroundColor -// -//************************************************************************ - -void CLCDBase::SetForegroundColor(COLORREF crForeground) -{ - m_crForegroundColor = crForeground; -} - - -//************************************************************************ -// -// CLCDBase::SetBackgroundColor -// -//************************************************************************ - -void CLCDBase::SetBackgroundColor(COLORREF crBackground) -{ - m_crBackgroundColor = crBackground; -} - - -//** end of LCDBase.cpp ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDBase.cpp +// +// The CLCDBase class is the generic base class for all lcd ui objects +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDBase::CLCDBase +// +//************************************************************************ + +CLCDBase::CLCDBase(void) +{ + m_Size.cx = 0; + m_Size.cy = 0; + m_Origin.x = 0; + m_Origin.y = 0; + m_bVisible = TRUE; + m_bInverted = FALSE; + ZeroMemory(&m_ptLogical, sizeof(m_ptLogical)); + ZeroMemory(&m_sizeLogical, sizeof(m_sizeLogical)); + m_nBkMode = TRANSPARENT; + m_objectType = LG_UNKNOWN; + m_crBackgroundColor = RGB(0, 0, 0); + m_crForegroundColor = RGB(255, 255, 255); +} + + +//************************************************************************ +// +// CLCDBase::~CLCDBase +// +//************************************************************************ + +CLCDBase::~CLCDBase(void) +{ +} + + +//************************************************************************ +// +// CLCDBase::Initialize +// +//************************************************************************ + +HRESULT CLCDBase::Initialize(void) +{ + return S_OK; +} + + +//************************************************************************ +// +// CLCDBase::Shutdown +// +//************************************************************************ + +void CLCDBase::Shutdown(void) +{ +} + + +//************************************************************************ +// +// CLCDBase::SetOrigin +// +//************************************************************************ + +void CLCDBase::SetOrigin(POINT pt) +{ + m_Origin = pt; +} + + +//************************************************************************ +// +// CLCDBase::SetOrigin +// +//************************************************************************ + +void CLCDBase::SetOrigin(int nX, int nY) +{ + POINT pt = { nX, nY }; + SetOrigin(pt); +} + + +//************************************************************************ +// +// CLCDBase::GetOrigin +// +//************************************************************************ + +POINT& CLCDBase::GetOrigin(void) +{ + return m_Origin; +} + + +//************************************************************************ +// +// CLCDBase::SetSize +// +//************************************************************************ + +void CLCDBase::SetSize(SIZE& size) +{ + m_Size = size; + SetLogicalSize(m_Size); +} + + +//************************************************************************ +// +// CLCDBase::SetSize +// +//************************************************************************ + +void CLCDBase::SetSize(int nCX, int nCY) +{ + SIZE size = { nCX, nCY }; + SetSize(size); +} + + +//************************************************************************ +// +// CLCDBase::GetSize +// +//************************************************************************ + +SIZE& CLCDBase::GetSize(void) +{ + return m_Size; +} + + +//************************************************************************ +// +// CLCDBase::SetLogicalOrigin +// +//************************************************************************ + +void CLCDBase::SetLogicalOrigin(POINT& pt) +{ + m_ptLogical = pt; +} + + +//************************************************************************ +// +// CLCDBase::SetLogicalOrigin +// +//************************************************************************ + +void CLCDBase::SetLogicalOrigin(int nX, int nY) +{ + m_ptLogical.x = nX; + m_ptLogical.y = nY; +} + + +//************************************************************************ +// +// CLCDBase::GetLogicalOrigin +// +//************************************************************************ + +POINT& CLCDBase::GetLogicalOrigin(void) +{ + return m_ptLogical; +} + + +//************************************************************************ +// +// CLCDBase::SetLogicalSize +// +//************************************************************************ + +void CLCDBase::SetLogicalSize(SIZE& size) +{ + m_sizeLogical = size; +} + + +//************************************************************************ +// +// CLCDBase::SetLogicalSize +// +//************************************************************************ + +void CLCDBase::SetLogicalSize(int nCX, int nCY) +{ + m_sizeLogical.cx = nCX; + m_sizeLogical.cy = nCY; +} + + +//************************************************************************ +// +// CLCDBase::GetLogicalSize +// +//************************************************************************ + +SIZE& CLCDBase::GetLogicalSize(void) +{ + return m_sizeLogical; +} + + +//************************************************************************ +// +// CLCDBase::Show +// +//************************************************************************ + +void CLCDBase::Show(BOOL bShow) +{ + m_bVisible = bShow; +} + + +//************************************************************************ +// +// BOOL CLCDBase:: +// +//************************************************************************ + +BOOL CLCDBase::IsVisible(void) +{ + return m_bVisible; +} + + +//************************************************************************ +// +// CLCDBase::Invert +// +//************************************************************************ + +void CLCDBase::Invert(BOOL bEnable) +{ + m_bInverted = bEnable; +} + + +//************************************************************************ +// +// CLCDBase::ResetUpdate +// +//************************************************************************ + +void CLCDBase::ResetUpdate(void) +{ + // do nothing +} + + +//************************************************************************ +// +// CLCDBase::OnUpdate +// +//************************************************************************ + +void CLCDBase::OnUpdate(DWORD dwTimestamp) +{ + UNREFERENCED_PARAMETER(dwTimestamp); +} + + +//************************************************************************ +// +// CLCDBase::OnPrepareDraw +// +//************************************************************************ + +void CLCDBase::OnPrepareDraw(CLCDGfxBase &rGfx) +{ + UNREFERENCED_PARAMETER(rGfx); +} + + +//************************************************************************ +// +// CLCDBase::OnDraw +// +//************************************************************************ + +void CLCDBase::OnDraw(CLCDGfxBase &rGfx) +{ + UNREFERENCED_PARAMETER(rGfx); +} + + +//************************************************************************ +// +// CLCDBase::SetBackgroundMode +// +//************************************************************************ + +void CLCDBase::SetBackgroundMode(int nMode) +{ + m_nBkMode = nMode; +} + + +//************************************************************************ +// +// CLCDBase::GetBackgroundMode +// +//************************************************************************ + +int CLCDBase::GetBackgroundMode() +{ + return m_nBkMode; +} + + +//************************************************************************ +// +// CLCDBase::GetObjectType +// +//************************************************************************ + +const LGObjectType CLCDBase::GetObjectType() +{ + return m_objectType; +} + + +//************************************************************************ +// +// CLCDBase::SetObjectType +// +//************************************************************************ + +void CLCDBase::SetObjectType(const LGObjectType type) +{ + m_objectType = type; +} + + +//************************************************************************ +// +// CLCDBase::SetForegroundColor +// +//************************************************************************ + +void CLCDBase::SetForegroundColor(COLORREF crForeground) +{ + m_crForegroundColor = crForeground; +} + + +//************************************************************************ +// +// CLCDBase::SetBackgroundColor +// +//************************************************************************ + +void CLCDBase::SetBackgroundColor(COLORREF crBackground) +{ + m_crBackgroundColor = crBackground; +} + + +//** end of LCDBase.cpp ************************************************** diff --git a/src/thirdparty/LCDUI/LCDBase.h b/src/thirdparty/LCDUI/LCDBase.h index 2913eaba4e0..3ca78c9a19a 100644 --- a/src/thirdparty/LCDUI/LCDBase.h +++ b/src/thirdparty/LCDUI/LCDBase.h @@ -1,97 +1,97 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDBase.h -// -// The CLCDBase class is the generic base class for all lcd ui objects -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDBASE_H_INCLUDED_ -#define _LCDBASE_H_INCLUDED_ - -#include "LCDGfxBase.h" - -typedef enum -{ - LG_SCROLLING_TEXT, LG_STATIC_TEXT, LG_ICON, LG_PROGRESS_BAR, LG_UNKNOWN, LG_RIGHTFOCUS_TEXT, LG_BOTTOMFOCUS_TEXT -} LGObjectType; - -class CLCDBase -{ -public: - CLCDBase(void); - virtual ~CLCDBase(void); - -public: - virtual HRESULT Initialize(void); - virtual void Shutdown(void); - - virtual void SetOrigin(POINT pt); - virtual void SetOrigin(int nX, int nY); - virtual POINT& GetOrigin(void); - - virtual void SetSize(SIZE& size); - virtual void SetSize(int nCX, int nCY); - virtual SIZE& GetSize(void); - - virtual int GetWidth(void) { return GetSize().cx; } - virtual int GetHeight(void) { return GetSize().cy; }; - - virtual void Show(BOOL bShow); - virtual BOOL IsVisible(); - - virtual void Invert(BOOL bEnable); - virtual void ResetUpdate(void); - - // local coordinates - virtual void SetLogicalOrigin(POINT& rLogical); - virtual void SetLogicalOrigin(int nX, int nY); - virtual POINT& GetLogicalOrigin(void); - virtual void SetLogicalSize(SIZE& size); - virtual void SetLogicalSize(int nCX, int nCY); - virtual SIZE& GetLogicalSize(void); - - virtual void SetBackgroundMode(int nMode); - virtual int GetBackgroundMode(); - - virtual const LGObjectType GetObjectType(); - virtual void SetObjectType(const LGObjectType type); - - virtual void SetForegroundColor(COLORREF crForeground); - virtual void SetBackgroundColor(COLORREF crBackground); - -public: - virtual void OnPrepareDraw(CLCDGfxBase &rGfx); - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void OnUpdate(DWORD dwTimestamp); - -protected: - SIZE m_Size; - POINT m_Origin; - BOOL m_bVisible; - BOOL m_bInverted; - - POINT m_ptLogical; - SIZE m_sizeLogical; - int m_nBkMode; - - LGObjectType m_objectType; - - COLORREF m_crBackgroundColor, m_crForegroundColor; -}; - - -#endif // !_LCDBASE_H_INCLUDED_ - -//** end of LCDBase.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDBase.h +// +// The CLCDBase class is the generic base class for all lcd ui objects +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDBASE_H_INCLUDED_ +#define _LCDBASE_H_INCLUDED_ + +#include "LCDGfxBase.h" + +typedef enum +{ + LG_SCROLLING_TEXT, LG_STATIC_TEXT, LG_ICON, LG_PROGRESS_BAR, LG_UNKNOWN, LG_RIGHTFOCUS_TEXT, LG_BOTTOMFOCUS_TEXT +} LGObjectType; + +class CLCDBase +{ +public: + CLCDBase(void); + virtual ~CLCDBase(void); + +public: + virtual HRESULT Initialize(void); + virtual void Shutdown(void); + + virtual void SetOrigin(POINT pt); + virtual void SetOrigin(int nX, int nY); + virtual POINT& GetOrigin(void); + + virtual void SetSize(SIZE& size); + virtual void SetSize(int nCX, int nCY); + virtual SIZE& GetSize(void); + + virtual int GetWidth(void) { return GetSize().cx; } + virtual int GetHeight(void) { return GetSize().cy; }; + + virtual void Show(BOOL bShow); + virtual BOOL IsVisible(); + + virtual void Invert(BOOL bEnable); + virtual void ResetUpdate(void); + + // local coordinates + virtual void SetLogicalOrigin(POINT& rLogical); + virtual void SetLogicalOrigin(int nX, int nY); + virtual POINT& GetLogicalOrigin(void); + virtual void SetLogicalSize(SIZE& size); + virtual void SetLogicalSize(int nCX, int nCY); + virtual SIZE& GetLogicalSize(void); + + virtual void SetBackgroundMode(int nMode); + virtual int GetBackgroundMode(); + + virtual const LGObjectType GetObjectType(); + virtual void SetObjectType(const LGObjectType type); + + virtual void SetForegroundColor(COLORREF crForeground); + virtual void SetBackgroundColor(COLORREF crBackground); + +public: + virtual void OnPrepareDraw(CLCDGfxBase &rGfx); + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void OnUpdate(DWORD dwTimestamp); + +protected: + SIZE m_Size; + POINT m_Origin; + BOOL m_bVisible; + BOOL m_bInverted; + + POINT m_ptLogical; + SIZE m_sizeLogical; + int m_nBkMode; + + LGObjectType m_objectType; + + COLORREF m_crBackgroundColor, m_crForegroundColor; +}; + + +#endif // !_LCDBASE_H_INCLUDED_ + +//** end of LCDBase.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDBitmap.cpp b/src/thirdparty/LCDUI/LCDBitmap.cpp index 31340e2643c..1b2b54df900 100644 --- a/src/thirdparty/LCDUI/LCDBitmap.cpp +++ b/src/thirdparty/LCDUI/LCDBitmap.cpp @@ -1,179 +1,179 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDBitmap.cpp -// -// The CLCDBitmap class draws bitmaps onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDBitmap::CLCDBitmap -// -//************************************************************************ - -CLCDBitmap::CLCDBitmap(void) -{ - m_hBitmap = NULL; - m_dwROP = SRCCOPY; - m_fZoom = 1.0f; - m_bAlpha = TRUE; -} - - -//************************************************************************ -// -// CLCDBitmap::CLCDBitmap -// -//************************************************************************ - -CLCDBitmap::~CLCDBitmap(void) -{ - -} - - -//************************************************************************ -// -// CLCDBitmap::SetBitmap -// -//************************************************************************ - -void CLCDBitmap::SetBitmap(HBITMAP hBitmap) -{ - m_hBitmap = hBitmap; -} - - -//************************************************************************ -// -// CLCDBitmap::GetBitmap -// -//************************************************************************ -HBITMAP CLCDBitmap::GetBitmap(void) -{ - return m_hBitmap; -} - - -//************************************************************************ -// -// CLCDBitmap::SetBitmap -// -//************************************************************************ - -void CLCDBitmap::SetROP(DWORD dwROP) -{ - m_dwROP = dwROP; -} - - -//************************************************************************ -// -// CLCDBitmap::SetZoomLevel -// -//************************************************************************ - -void CLCDBitmap::SetZoomLevel(float fzoom) -{ - m_fZoom = fzoom; -} - - -//************************************************************************ -// -// CLCDBitmap::GetZoomLevel -// -//************************************************************************ - -float CLCDBitmap::GetZoomLevel(void) -{ - return m_fZoom; -} - - -//************************************************************************ -// -// CLCDBitmap::SetAlpha -// -//************************************************************************ - -void CLCDBitmap::SetAlpha(BOOL bAlpha) -{ - m_bAlpha = bAlpha; -} - - -//************************************************************************ -// -// CLCDBitmap::OnDraw -// -// The logical size is our 'canvas'. -// The control size is our 'window'. The window size can be smaller than the canvas. -// The assumption is that the bitmap size is the size of the canvas. -//************************************************************************ - -void CLCDBitmap::OnDraw(CLCDGfxBase &rGfx) -{ - if(m_hBitmap) - { - HDC hCompatibleDC = CreateCompatibleDC(rGfx.GetHDC()); - HBITMAP hOldBitmap = (HBITMAP)SelectObject(hCompatibleDC, m_hBitmap); - - // If monochrome output, don't even bother with alpha blend - if (LGLCD_BMP_FORMAT_160x43x1 == rGfx.GetLCDScreen()->hdr.Format) - { - BitBlt(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_dwROP); - } - else - { - if(0.001f > fabs(1.0f - m_fZoom)) - { - BOOL b = FALSE; - if(m_bAlpha) - { - BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - b = AlphaBlend(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); - } - else - { - BitBlt(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_dwROP); - } - } - else - { - if(m_bAlpha) - { - BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - AlphaBlend(rGfx.GetHDC(), 0, 0, (int)(m_fZoom* m_sizeLogical.cx), (int)(m_fZoom*m_sizeLogical.cy), hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); - } - else - { - BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, 0}; - AlphaBlend(rGfx.GetHDC(), 0, 0, (int)(m_fZoom* m_sizeLogical.cx), (int)(m_fZoom*m_sizeLogical.cy), hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); - } - } - } - - // restores - SelectObject(hCompatibleDC, hOldBitmap); - DeleteDC(hCompatibleDC); - } -} - - -//** end of LCDBitmap.cpp ************************************************ +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDBitmap.cpp +// +// The CLCDBitmap class draws bitmaps onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDBitmap::CLCDBitmap +// +//************************************************************************ + +CLCDBitmap::CLCDBitmap(void) +{ + m_hBitmap = NULL; + m_dwROP = SRCCOPY; + m_fZoom = 1.0f; + m_bAlpha = TRUE; +} + + +//************************************************************************ +// +// CLCDBitmap::CLCDBitmap +// +//************************************************************************ + +CLCDBitmap::~CLCDBitmap(void) +{ + +} + + +//************************************************************************ +// +// CLCDBitmap::SetBitmap +// +//************************************************************************ + +void CLCDBitmap::SetBitmap(HBITMAP hBitmap) +{ + m_hBitmap = hBitmap; +} + + +//************************************************************************ +// +// CLCDBitmap::GetBitmap +// +//************************************************************************ +HBITMAP CLCDBitmap::GetBitmap(void) +{ + return m_hBitmap; +} + + +//************************************************************************ +// +// CLCDBitmap::SetBitmap +// +//************************************************************************ + +void CLCDBitmap::SetROP(DWORD dwROP) +{ + m_dwROP = dwROP; +} + + +//************************************************************************ +// +// CLCDBitmap::SetZoomLevel +// +//************************************************************************ + +void CLCDBitmap::SetZoomLevel(float fzoom) +{ + m_fZoom = fzoom; +} + + +//************************************************************************ +// +// CLCDBitmap::GetZoomLevel +// +//************************************************************************ + +float CLCDBitmap::GetZoomLevel(void) +{ + return m_fZoom; +} + + +//************************************************************************ +// +// CLCDBitmap::SetAlpha +// +//************************************************************************ + +void CLCDBitmap::SetAlpha(BOOL bAlpha) +{ + m_bAlpha = bAlpha; +} + + +//************************************************************************ +// +// CLCDBitmap::OnDraw +// +// The logical size is our 'canvas'. +// The control size is our 'window'. The window size can be smaller than the canvas. +// The assumption is that the bitmap size is the size of the canvas. +//************************************************************************ + +void CLCDBitmap::OnDraw(CLCDGfxBase &rGfx) +{ + if(m_hBitmap) + { + HDC hCompatibleDC = CreateCompatibleDC(rGfx.GetHDC()); + HBITMAP hOldBitmap = (HBITMAP)SelectObject(hCompatibleDC, m_hBitmap); + + // If monochrome output, don't even bother with alpha blend + if (LGLCD_BMP_FORMAT_160x43x1 == rGfx.GetLCDScreen()->hdr.Format) + { + BitBlt(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_dwROP); + } + else + { + if(0.001f > fabs(1.0f - m_fZoom)) + { + BOOL b = FALSE; + if(m_bAlpha) + { + BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; + b = AlphaBlend(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); + } + else + { + BitBlt(rGfx.GetHDC(), 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, hCompatibleDC, 0, 0, m_dwROP); + } + } + else + { + if(m_bAlpha) + { + BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; + AlphaBlend(rGfx.GetHDC(), 0, 0, (int)(m_fZoom* m_sizeLogical.cx), (int)(m_fZoom*m_sizeLogical.cy), hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); + } + else + { + BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, 0}; + AlphaBlend(rGfx.GetHDC(), 0, 0, (int)(m_fZoom* m_sizeLogical.cx), (int)(m_fZoom*m_sizeLogical.cy), hCompatibleDC, 0, 0, m_sizeLogical.cx, m_sizeLogical.cy, opblender); + } + } + } + + // restores + SelectObject(hCompatibleDC, hOldBitmap); + DeleteDC(hCompatibleDC); + } +} + + +//** end of LCDBitmap.cpp ************************************************ diff --git a/src/thirdparty/LCDUI/LCDBitmap.h b/src/thirdparty/LCDUI/LCDBitmap.h index f79ff85d05d..2547d8ce239 100644 --- a/src/thirdparty/LCDUI/LCDBitmap.h +++ b/src/thirdparty/LCDUI/LCDBitmap.h @@ -1,54 +1,54 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDBitmap.h -// -// The CLCDBitmap class draws bitmaps onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDBITMAP_H_INCLUDED_ -#define _LCDBITMAP_H_INCLUDED_ - -#include "LCDBase.h" - -class CLCDBitmap : public CLCDBase -{ -public: - CLCDBitmap(); - virtual ~CLCDBitmap(); - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - - void SetBitmap(HBITMAP hBitmap); - HBITMAP GetBitmap(void); - void SetROP(DWORD dwROP); - void SetZoomLevel(float fzoom); - float GetZoomLevel(void); - void SetAlpha(BOOL bAlpha); - -protected: - HBITMAP m_hBitmap; - DWORD m_dwROP; - float m_fZoom; - // this indicates the bitmap has an alpha channel - BOOL m_bAlpha; - -private: -}; - - -#endif // !_LCDBITMAP_H_INCLUDED_ - -//** end of LCDBitmap.h ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDBitmap.h +// +// The CLCDBitmap class draws bitmaps onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDBITMAP_H_INCLUDED_ +#define _LCDBITMAP_H_INCLUDED_ + +#include "LCDBase.h" + +class CLCDBitmap : public CLCDBase +{ +public: + CLCDBitmap(); + virtual ~CLCDBitmap(); + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + + void SetBitmap(HBITMAP hBitmap); + HBITMAP GetBitmap(void); + void SetROP(DWORD dwROP); + void SetZoomLevel(float fzoom); + float GetZoomLevel(void); + void SetAlpha(BOOL bAlpha); + +protected: + HBITMAP m_hBitmap; + DWORD m_dwROP; + float m_fZoom; + // this indicates the bitmap has an alpha channel + BOOL m_bAlpha; + +private: +}; + + +#endif // !_LCDBITMAP_H_INCLUDED_ + +//** end of LCDBitmap.h ************************************************** diff --git a/src/thirdparty/LCDUI/LCDCollection.cpp b/src/thirdparty/LCDUI/LCDCollection.cpp index 1d3e3ec07ac..2d3dc3a930a 100644 --- a/src/thirdparty/LCDUI/LCDCollection.cpp +++ b/src/thirdparty/LCDUI/LCDCollection.cpp @@ -1,233 +1,233 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDCollection.cpp -// -// Holds a collection of base items. Its draw will draw everything -// in its list. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDCollection::CLCDCollection -// -//************************************************************************ - -CLCDCollection::CLCDCollection(void) -{ -} - - -//************************************************************************ -// -// CLCDCollection::~CLCDCollection -// -//************************************************************************ - -CLCDCollection::~CLCDCollection(void) -{ - -} - - -//************************************************************************ -// -// CLCDCollection::GetObjectCount -// -//************************************************************************ - -int CLCDCollection::GetObjectCount(void) -{ - return (int)m_Objects.size(); -} - - -//************************************************************************ -// -// CLCDCollection::AddObject -// -//************************************************************************ - -bool CLCDCollection::AddObject(CLCDBase* pObject) -{ - m_Objects.push_back(pObject); - return true; -} - - -//************************************************************************ -// -// CLCDCollection::RemoveObject -// -//************************************************************************ - -bool CLCDCollection::RemoveObject(CLCDBase* pObject) -{ - LCD_OBJECT_LIST::iterator it = - std::find(m_Objects.begin(), m_Objects.end(), pObject); - if(it != m_Objects.end()) - { - m_Objects.erase(it); - return true; - } - - return false; -} - - -//************************************************************************ -// -// CLCDCollection::RemoveObject -// -//************************************************************************ - -bool CLCDCollection::RemoveObject(int objpos) -{ - if(!m_Objects.empty()) - { - if((0 <= objpos) && (objpos < (int) m_Objects.size())) - { - m_Objects.erase(m_Objects.begin() + objpos); - return true; - } - } - return false; -} - - -//************************************************************************ -// -// CLCDCollection::RemoveAll -// -//************************************************************************ - -void CLCDCollection::RemoveAll() -{ - m_Objects.clear(); -} - - -//************************************************************************ -// -// CLCDCollection::RetrieveObject -// -//************************************************************************ - -CLCDBase* CLCDCollection::RetrieveObject(int objpos) -{ - if(!m_Objects.empty()) - { - if((0 <= objpos) && (objpos < (int) m_Objects.size())) - { - return m_Objects[objpos]; - } - } - return NULL; -} - - -//************************************************************************ -// -// CLCDCollection::OnDraw -// -//************************************************************************ - -void CLCDCollection::OnDraw(CLCDGfxBase &rGfx) -{ - if(!IsVisible()) - { - return; - } - - //iterate through your objects and draw them - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it++; - LCDUIASSERT(NULL != pObject); - - if (pObject->IsVisible()) - { - pObject->OnPrepareDraw(rGfx); - - // create the clip region - HRGN hRgn = CreateRectRgn(pObject->GetOrigin().x, pObject->GetOrigin().y, - pObject->GetOrigin().x + pObject->GetWidth(), - pObject->GetOrigin().y + pObject->GetHeight()); - - // ensure that controls only draw within their specified region - SelectClipRgn(rGfx.GetHDC(), hRgn); - - // free the region (a copy is used in the call above) - DeleteObject(hRgn); - - // offset the control at its origin so controls use (0,0) - POINT ptPrevViewportOrg = { 0, 0 }; - SetViewportOrgEx(rGfx.GetHDC(), - pObject->GetOrigin().x, - pObject->GetOrigin().y, - &ptPrevViewportOrg); - - // allow controls to supply additional translation - // this allows controls to move freely within the confined viewport - OffsetViewportOrgEx(rGfx.GetHDC(), - pObject->GetLogicalOrigin().x, - pObject->GetLogicalOrigin().y, - NULL); - - pObject->OnDraw(rGfx); - - // set the clipping region to nothing - SelectClipRgn(rGfx.GetHDC(), NULL); - - // restore the viewport origin - SetViewportOrgEx(rGfx.GetHDC(), - ptPrevViewportOrg.x, - ptPrevViewportOrg.y, - NULL); - - // restore the viewport origin offset - OffsetViewportOrgEx(rGfx.GetHDC(), 0, 0, NULL); - } - } -} - - -//************************************************************************ -// -// CLCDCollection::OnUpdate -// -//************************************************************************ - -void CLCDCollection::OnUpdate(DWORD dwTimestamp) -{ - //iterate through your objects and update them - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it++; - LCDUIASSERT(NULL != pObject); - - pObject->OnUpdate(dwTimestamp); - } - - //and update yourself - CLCDBase::OnUpdate(dwTimestamp); -} - - -//** end of LCDCollection.cpp ******************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDCollection.cpp +// +// Holds a collection of base items. Its draw will draw everything +// in its list. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDCollection::CLCDCollection +// +//************************************************************************ + +CLCDCollection::CLCDCollection(void) +{ +} + + +//************************************************************************ +// +// CLCDCollection::~CLCDCollection +// +//************************************************************************ + +CLCDCollection::~CLCDCollection(void) +{ + +} + + +//************************************************************************ +// +// CLCDCollection::GetObjectCount +// +//************************************************************************ + +int CLCDCollection::GetObjectCount(void) +{ + return (int)m_Objects.size(); +} + + +//************************************************************************ +// +// CLCDCollection::AddObject +// +//************************************************************************ + +bool CLCDCollection::AddObject(CLCDBase* pObject) +{ + m_Objects.push_back(pObject); + return true; +} + + +//************************************************************************ +// +// CLCDCollection::RemoveObject +// +//************************************************************************ + +bool CLCDCollection::RemoveObject(CLCDBase* pObject) +{ + LCD_OBJECT_LIST::iterator it = + std::find(m_Objects.begin(), m_Objects.end(), pObject); + if(it != m_Objects.end()) + { + m_Objects.erase(it); + return true; + } + + return false; +} + + +//************************************************************************ +// +// CLCDCollection::RemoveObject +// +//************************************************************************ + +bool CLCDCollection::RemoveObject(int objpos) +{ + if(!m_Objects.empty()) + { + if((0 <= objpos) && (objpos < (int) m_Objects.size())) + { + m_Objects.erase(m_Objects.begin() + objpos); + return true; + } + } + return false; +} + + +//************************************************************************ +// +// CLCDCollection::RemoveAll +// +//************************************************************************ + +void CLCDCollection::RemoveAll() +{ + m_Objects.clear(); +} + + +//************************************************************************ +// +// CLCDCollection::RetrieveObject +// +//************************************************************************ + +CLCDBase* CLCDCollection::RetrieveObject(int objpos) +{ + if(!m_Objects.empty()) + { + if((0 <= objpos) && (objpos < (int) m_Objects.size())) + { + return m_Objects[objpos]; + } + } + return NULL; +} + + +//************************************************************************ +// +// CLCDCollection::OnDraw +// +//************************************************************************ + +void CLCDCollection::OnDraw(CLCDGfxBase &rGfx) +{ + if(!IsVisible()) + { + return; + } + + //iterate through your objects and draw them + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it++; + LCDUIASSERT(NULL != pObject); + + if (pObject->IsVisible()) + { + pObject->OnPrepareDraw(rGfx); + + // create the clip region + HRGN hRgn = CreateRectRgn(pObject->GetOrigin().x, pObject->GetOrigin().y, + pObject->GetOrigin().x + pObject->GetWidth(), + pObject->GetOrigin().y + pObject->GetHeight()); + + // ensure that controls only draw within their specified region + SelectClipRgn(rGfx.GetHDC(), hRgn); + + // free the region (a copy is used in the call above) + DeleteObject(hRgn); + + // offset the control at its origin so controls use (0,0) + POINT ptPrevViewportOrg = { 0, 0 }; + SetViewportOrgEx(rGfx.GetHDC(), + pObject->GetOrigin().x, + pObject->GetOrigin().y, + &ptPrevViewportOrg); + + // allow controls to supply additional translation + // this allows controls to move freely within the confined viewport + OffsetViewportOrgEx(rGfx.GetHDC(), + pObject->GetLogicalOrigin().x, + pObject->GetLogicalOrigin().y, + NULL); + + pObject->OnDraw(rGfx); + + // set the clipping region to nothing + SelectClipRgn(rGfx.GetHDC(), NULL); + + // restore the viewport origin + SetViewportOrgEx(rGfx.GetHDC(), + ptPrevViewportOrg.x, + ptPrevViewportOrg.y, + NULL); + + // restore the viewport origin offset + OffsetViewportOrgEx(rGfx.GetHDC(), 0, 0, NULL); + } + } +} + + +//************************************************************************ +// +// CLCDCollection::OnUpdate +// +//************************************************************************ + +void CLCDCollection::OnUpdate(DWORD dwTimestamp) +{ + //iterate through your objects and update them + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it++; + LCDUIASSERT(NULL != pObject); + + pObject->OnUpdate(dwTimestamp); + } + + //and update yourself + CLCDBase::OnUpdate(dwTimestamp); +} + + +//** end of LCDCollection.cpp ******************************************** diff --git a/src/thirdparty/LCDUI/LCDCollection.h b/src/thirdparty/LCDUI/LCDCollection.h index 801a736deba..6c4a2862af4 100644 --- a/src/thirdparty/LCDUI/LCDCollection.h +++ b/src/thirdparty/LCDUI/LCDCollection.h @@ -1,52 +1,52 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDCollection.h -// -// Holds a collection of base items. Its draw will draw everything -// in its list. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDCOLLECTION_H_INCLUDED_ -#define _LCDCOLLECTION_H_INCLUDED_ - -#include "LCDBase.h" -#include - -class CLCDCollection : public CLCDBase -{ -public: - CLCDCollection(); - virtual ~CLCDCollection(); - - bool AddObject(CLCDBase *pObject); - bool RemoveObject(CLCDBase *pObject); - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void OnUpdate(DWORD dwTimestamp); - -protected: - CLCDBase* RetrieveObject(int objpos); - int GetObjectCount(void); - bool RemoveObject(int objnum); - void RemoveAll(void); - -protected: - typedef std::vector LCD_OBJECT_LIST; - - LCD_OBJECT_LIST m_Objects; -}; - +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDCollection.h +// +// Holds a collection of base items. Its draw will draw everything +// in its list. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDCOLLECTION_H_INCLUDED_ +#define _LCDCOLLECTION_H_INCLUDED_ + +#include "LCDBase.h" +#include + +class CLCDCollection : public CLCDBase +{ +public: + CLCDCollection(); + virtual ~CLCDCollection(); + + bool AddObject(CLCDBase *pObject); + bool RemoveObject(CLCDBase *pObject); + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void OnUpdate(DWORD dwTimestamp); + +protected: + CLCDBase* RetrieveObject(int objpos); + int GetObjectCount(void); + bool RemoveObject(int objnum); + void RemoveAll(void); + +protected: + typedef std::vector LCD_OBJECT_LIST; + + LCD_OBJECT_LIST m_Objects; +}; + #endif \ No newline at end of file diff --git a/src/thirdparty/LCDUI/LCDColorProgressBar.cpp b/src/thirdparty/LCDUI/LCDColorProgressBar.cpp index 46cdf5809ee..ddf330ff0df 100644 --- a/src/thirdparty/LCDUI/LCDColorProgressBar.cpp +++ b/src/thirdparty/LCDUI/LCDColorProgressBar.cpp @@ -1,203 +1,203 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDColorProgressBar.cpp -// -// The CLCDColorProgressBar class draws a progress bar onto the color LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDColorProgressBar::CLCDColorProgressBar -// -//************************************************************************ - -CLCDColorProgressBar::CLCDColorProgressBar(void) - : CLCDProgressBar() -{ - SetProgressStyle(STYLE_FILLED); - SetCursorWidth(25); - SetBackgroundColor(RGB(0, 255, 100)); - SetBorderThickness(3); - - // Show a border by default - EnableBorder(FALSE); - SetBorderColor(RGB(0, 100, 150)); -} - - -//************************************************************************ -// -// CLCDColorProgressBar::~CLCDColorProgressBar -// -//************************************************************************ - -CLCDColorProgressBar::~CLCDColorProgressBar(void) -{ -} - - -//************************************************************************ -// -// CLCDColorProgressBar::OnDraw -// -//************************************************************************ - -void CLCDColorProgressBar::OnDraw(CLCDGfxBase &rGfx) -{ - HBRUSH hCursorBrush = CreateSolidBrush(m_crForegroundColor); - HBRUSH hBackBrush = CreateSolidBrush(m_crBackgroundColor); - - RECT rBoundary = { 0, 0, GetWidth(), GetHeight() }; - - // Draw the background/border or just background - if (m_bBorderOn && (m_nBorderThickness > 0)) - { - HBRUSH hOldBrush = (HBRUSH)SelectObject(rGfx.GetHDC(), hBackBrush); - HPEN hBorderPen = CreatePen(PS_INSIDEFRAME, m_nBorderThickness, m_crBorderColor); - HPEN hOldPen = (HPEN)SelectObject(rGfx.GetHDC(), hBorderPen); - Rectangle(rGfx.GetHDC(), rBoundary.left, rBoundary.top, rBoundary.right, rBoundary.bottom); - SelectObject(rGfx.GetHDC(), hOldPen); - SelectObject(rGfx.GetHDC(), hOldBrush); - DeleteObject(hBorderPen); - - // adjust the progress boundary by the thickness - rBoundary.top += m_nBorderThickness; - rBoundary.bottom -= m_nBorderThickness; - rBoundary.left += m_nBorderThickness; - rBoundary.right -= m_nBorderThickness; - } - else - { - FillRect(rGfx.GetHDC(), &rBoundary, hBackBrush); - } - - //Drawing the cursor - switch(m_eStyle) - { - case STYLE_CURSOR: - { - RECT r = rBoundary; - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), - m_fPos); - r.left = nCursorPos; - r.right = nCursorPos + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, hCursorBrush); - - break; - } - case STYLE_FILLED: - { - RECT r = rBoundary; - int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right), - m_fPos); - r.right = nBarWidth ? nBarWidth : r.left; - FillRect(rGfx.GetHDC(), &r, hCursorBrush); - - break; - } - case STYLE_DASHED_CURSOR: - { - RECT r = rBoundary; - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), - m_fPos); - r.left = nCursorPos; - r.right = nCursorPos + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, hCursorBrush); - HPEN hCursorPen = ::CreatePen(PS_DOT, 1, m_crForegroundColor); - HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), hCursorPen); - - ::MoveToEx(rGfx.GetHDC(), rBoundary.left, (r.bottom - r.top)/2, NULL); - ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top)/2); - - DeleteObject(hCursorPen); - ::SelectObject(rGfx.GetHDC(), hOldPen); - break; - } - - default: - break; - } - - DeleteObject(hBackBrush); - DeleteObject(hCursorBrush); -} - - -//************************************************************************ -// -// CLCDColorProgressBar::SetCursorColor -// -//************************************************************************ - -void CLCDColorProgressBar::SetCursorColor(COLORREF color) -{ - SetForegroundColor(color); -} - - -//************************************************************************ -// -// CLCDColorProgressBar::EnableBorder -// -//************************************************************************ - -void CLCDColorProgressBar::EnableBorder(BOOL bEnable) -{ - m_bBorderOn = bEnable; -} - - -//************************************************************************ -// -// CLCDColorProgressBar::SetBorderColor -// -//************************************************************************ - -void CLCDColorProgressBar::SetBorderColor(COLORREF color) -{ - m_crBorderColor = color; -} - - -//************************************************************************ -// -// CLCDColorProgressBar::SetBorderThickness -// -//************************************************************************ - -void CLCDColorProgressBar::SetBorderThickness(int thickness) -{ - m_nBorderThickness = thickness; -} - - -//************************************************************************ -// -// CLCDColorProgressBar::SetCursorWidth -// -//************************************************************************ - -void CLCDColorProgressBar::SetCursorWidth(int width) -{ - m_nCursorWidth = width; -} - -//** end of LCDColorProgressBar.cpp ************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDColorProgressBar.cpp +// +// The CLCDColorProgressBar class draws a progress bar onto the color LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDColorProgressBar::CLCDColorProgressBar +// +//************************************************************************ + +CLCDColorProgressBar::CLCDColorProgressBar(void) + : CLCDProgressBar() +{ + SetProgressStyle(STYLE_FILLED); + SetCursorWidth(25); + SetBackgroundColor(RGB(0, 255, 100)); + SetBorderThickness(3); + + // Show a border by default + EnableBorder(FALSE); + SetBorderColor(RGB(0, 100, 150)); +} + + +//************************************************************************ +// +// CLCDColorProgressBar::~CLCDColorProgressBar +// +//************************************************************************ + +CLCDColorProgressBar::~CLCDColorProgressBar(void) +{ +} + + +//************************************************************************ +// +// CLCDColorProgressBar::OnDraw +// +//************************************************************************ + +void CLCDColorProgressBar::OnDraw(CLCDGfxBase &rGfx) +{ + HBRUSH hCursorBrush = CreateSolidBrush(m_crForegroundColor); + HBRUSH hBackBrush = CreateSolidBrush(m_crBackgroundColor); + + RECT rBoundary = { 0, 0, GetWidth(), GetHeight() }; + + // Draw the background/border or just background + if (m_bBorderOn && (m_nBorderThickness > 0)) + { + HBRUSH hOldBrush = (HBRUSH)SelectObject(rGfx.GetHDC(), hBackBrush); + HPEN hBorderPen = CreatePen(PS_INSIDEFRAME, m_nBorderThickness, m_crBorderColor); + HPEN hOldPen = (HPEN)SelectObject(rGfx.GetHDC(), hBorderPen); + Rectangle(rGfx.GetHDC(), rBoundary.left, rBoundary.top, rBoundary.right, rBoundary.bottom); + SelectObject(rGfx.GetHDC(), hOldPen); + SelectObject(rGfx.GetHDC(), hOldBrush); + DeleteObject(hBorderPen); + + // adjust the progress boundary by the thickness + rBoundary.top += m_nBorderThickness; + rBoundary.bottom -= m_nBorderThickness; + rBoundary.left += m_nBorderThickness; + rBoundary.right -= m_nBorderThickness; + } + else + { + FillRect(rGfx.GetHDC(), &rBoundary, hBackBrush); + } + + //Drawing the cursor + switch(m_eStyle) + { + case STYLE_CURSOR: + { + RECT r = rBoundary; + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), + m_fPos); + r.left = nCursorPos; + r.right = nCursorPos + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, hCursorBrush); + + break; + } + case STYLE_FILLED: + { + RECT r = rBoundary; + int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right), + m_fPos); + r.right = nBarWidth ? nBarWidth : r.left; + FillRect(rGfx.GetHDC(), &r, hCursorBrush); + + break; + } + case STYLE_DASHED_CURSOR: + { + RECT r = rBoundary; + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), + m_fPos); + r.left = nCursorPos; + r.right = nCursorPos + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, hCursorBrush); + HPEN hCursorPen = ::CreatePen(PS_DOT, 1, m_crForegroundColor); + HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), hCursorPen); + + ::MoveToEx(rGfx.GetHDC(), rBoundary.left, (r.bottom - r.top)/2, NULL); + ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top)/2); + + DeleteObject(hCursorPen); + ::SelectObject(rGfx.GetHDC(), hOldPen); + break; + } + + default: + break; + } + + DeleteObject(hBackBrush); + DeleteObject(hCursorBrush); +} + + +//************************************************************************ +// +// CLCDColorProgressBar::SetCursorColor +// +//************************************************************************ + +void CLCDColorProgressBar::SetCursorColor(COLORREF color) +{ + SetForegroundColor(color); +} + + +//************************************************************************ +// +// CLCDColorProgressBar::EnableBorder +// +//************************************************************************ + +void CLCDColorProgressBar::EnableBorder(BOOL bEnable) +{ + m_bBorderOn = bEnable; +} + + +//************************************************************************ +// +// CLCDColorProgressBar::SetBorderColor +// +//************************************************************************ + +void CLCDColorProgressBar::SetBorderColor(COLORREF color) +{ + m_crBorderColor = color; +} + + +//************************************************************************ +// +// CLCDColorProgressBar::SetBorderThickness +// +//************************************************************************ + +void CLCDColorProgressBar::SetBorderThickness(int thickness) +{ + m_nBorderThickness = thickness; +} + + +//************************************************************************ +// +// CLCDColorProgressBar::SetCursorWidth +// +//************************************************************************ + +void CLCDColorProgressBar::SetCursorWidth(int width) +{ + m_nCursorWidth = width; +} + +//** end of LCDColorProgressBar.cpp ************************************** diff --git a/src/thirdparty/LCDUI/LCDColorProgressBar.h b/src/thirdparty/LCDUI/LCDColorProgressBar.h index 6a620f4e626..560bfa7079c 100644 --- a/src/thirdparty/LCDUI/LCDColorProgressBar.h +++ b/src/thirdparty/LCDUI/LCDColorProgressBar.h @@ -1,53 +1,53 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDColorProgressBar.h -// -// The CLCDColorProgressBar class draws a progress bar onto the color LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDCOLORPROGRESSBAR_H__ -#define __LCDCOLORPROGRESSBAR_H__ - -#include -#include "LCDProgressBar.h" - - -class CLCDColorProgressBar : public CLCDProgressBar -{ -public: - CLCDColorProgressBar(); - virtual ~CLCDColorProgressBar(); - - //CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - - //Style settings - virtual void SetCursorColor(COLORREF color); - virtual void EnableBorder(BOOL bEnable); - virtual void SetBorderColor(COLORREF color); - virtual void SetBorderThickness(int thickness); - virtual void SetCursorWidth(int width); - -protected: - //Does the actual draw work... - void DoDrawWork(); - - BOOL m_bBorderOn; - int m_nBorderThickness; - - COLORREF m_crBorderColor; -}; - +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDColorProgressBar.h +// +// The CLCDColorProgressBar class draws a progress bar onto the color LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDCOLORPROGRESSBAR_H__ +#define __LCDCOLORPROGRESSBAR_H__ + +#include +#include "LCDProgressBar.h" + + +class CLCDColorProgressBar : public CLCDProgressBar +{ +public: + CLCDColorProgressBar(); + virtual ~CLCDColorProgressBar(); + + //CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + + //Style settings + virtual void SetCursorColor(COLORREF color); + virtual void EnableBorder(BOOL bEnable); + virtual void SetBorderColor(COLORREF color); + virtual void SetBorderThickness(int thickness); + virtual void SetCursorWidth(int width); + +protected: + //Does the actual draw work... + void DoDrawWork(); + + BOOL m_bBorderOn; + int m_nBorderThickness; + + COLORREF m_crBorderColor; +}; + #endif \ No newline at end of file diff --git a/src/thirdparty/LCDUI/LCDColorText.cpp b/src/thirdparty/LCDUI/LCDColorText.cpp index e9326da2e88..f8e61e14cbf 100644 --- a/src/thirdparty/LCDUI/LCDColorText.cpp +++ b/src/thirdparty/LCDUI/LCDColorText.cpp @@ -1,301 +1,301 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// CLCDColorText.cpp -// -// The CLCDColorText class draws scrollable color text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - -//************************************************************************ -// -// CLCDColorText::CLCDColorText -// -//************************************************************************ - -CLCDColorText::CLCDColorText(void) -{ - m_nTextLength = 0; - m_hFont = NULL; - m_sText.erase(m_sText.begin(), m_sText.end()); - SetForegroundColor(RGB(255, 0, 255)); - m_bRecalcExtent = TRUE; - ZeroMemory(&m_dtp, sizeof(DRAWTEXTPARAMS)); - m_dtp.cbSize = sizeof(DRAWTEXTPARAMS); - m_nTextFormat = m_nTextAlignment = (DT_LEFT | DT_NOPREFIX); - m_nTextAlignment = DT_LEFT; - ZeroMemory(&m_sizeVExtent, sizeof(m_sizeVExtent)); - ZeroMemory(&m_sizeHExtent, sizeof(m_sizeHExtent)); - - SetBackgroundMode(TRANSPARENT, RGB(255,255,255)); - - //Default font - LOGFONT lf; - lf.lfCharSet = 0; - lf.lfClipPrecision = 2; - lf.lfEscapement = 0; - lf.lfHeight = -32; - lf.lfItalic = 0; - lf.lfOrientation = 0; - lf.lfOutPrecision = 3; - lf.lfPitchAndFamily = 18; - lf.lfQuality = 1; - lf.lfStrikeOut = 0; - lf.lfUnderline = 0; - lf.lfWeight = 400; - lf.lfWidth = 0; - - wsprintf(lf.lfFaceName, _T("Times New Roman") ); - - m_hFont = CreateFontIndirect(&lf); - - m_StartX = 0; - m_LoopX = 0; - m_ScrollRate = 0; - m_PixelLength = 0; - m_RunningTime = 0; - m_ScrollBuffer = 20; - m_JumpDistance = 0; - - m_bAutoScroll = true; -} - - - -//************************************************************************ -// -// CLCDColorText::~CLCDColorText -// -//************************************************************************ - -CLCDColorText::~CLCDColorText() -{ -} - - -//************************************************************************ -// -// CLCDColorText::SetBackgroundMode -// -//************************************************************************ - -void CLCDColorText::SetBackgroundMode(int nMode, COLORREF color) -{ - m_nBkMode = nMode; - m_backColor = color; -} - - -//************************************************************************ -// -// CLCDColorText::OnDraw -// -//************************************************************************ - -void CLCDColorText::OnDraw(CLCDGfxBase &rGfx) -{ - if(GetBackgroundMode() == OPAQUE) - { - HBRUSH backbrush = CreateSolidBrush(m_backColor); - - // clear the clipped area - RECT rcClp = { 0, 0, m_Size.cx, m_Size.cy }; - FillRect(rGfx.GetHDC(), &rcClp, backbrush); - - // clear the logical area - RECT rcLog = { 0, 0, m_sizeLogical.cx, m_sizeLogical.cy }; - FillRect(rGfx.GetHDC(), &rcLog, backbrush); - - DeleteObject(backbrush); - } - - if(m_nTextLength) - { - - // map mode text, with transparency - int nOldMapMode = SetMapMode(rGfx.GetHDC(), MM_TEXT); - - int nOldBkMode = SetBkMode(rGfx.GetHDC(), TRANSPARENT); - - // select current font - HFONT hOldFont = (HFONT)SelectObject(rGfx.GetHDC(), m_hFont); - - // select color - COLORREF crOldTextColor = SetTextColor(rGfx.GetHDC(), m_crForegroundColor); - - if (m_bRecalcExtent) - { - int nTextFormat; - - RECT rExtent; - // calculate vertical extent with word wrap - nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = GetWidth(); - rExtent.bottom = GetHeight(); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeVExtent.cx = rExtent.right; - m_sizeVExtent.cy = rExtent.bottom; - - // calculate horizontal extent w/o word wrap - nTextFormat = (m_nTextFormat | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = GetWidth(); - rExtent.bottom = GetHeight(); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeHExtent.cx = rExtent.right; - m_sizeHExtent.cy = rExtent.bottom; - - m_bRecalcExtent = FALSE; - - //For scrolling - m_PixelLength = m_sizeHExtent.cx; - m_StartX = 0; - - if( m_bAutoScroll ) - { - if( m_PixelLength > GetWidth() ) - { - m_ScrollRate = -1*GetHeight(); - } - else - { - m_ScrollRate = 0; - } - } - - if( m_ScrollRate > 0 ) - { - if( GetWidth() > m_PixelLength + m_ScrollBuffer ) - { - m_JumpDistance = -1 * GetWidth(); - } - else - { - m_JumpDistance = -1 * (m_PixelLength + m_ScrollBuffer); - } - } - else if( m_ScrollRate < 0 ) - { - if( GetWidth() > m_PixelLength + m_ScrollBuffer ) - { - m_JumpDistance = GetWidth(); - } - else - { - m_JumpDistance = m_PixelLength + m_ScrollBuffer; - } - } - - m_LoopX = m_JumpDistance; - } - - if( IsVisible() ) - { - if( m_ScrollRate == 0 ) - { - RECT rBoundary = { 0, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rBoundary, m_nTextFormat, &m_dtp); - } - else - { - RECT rBoundaryFirst = { m_StartX, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; - RECT rBoundarySecond = { m_LoopX, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; - - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), - &rBoundaryFirst, m_nTextFormat, &m_dtp); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), - &rBoundarySecond, m_nTextFormat, &m_dtp); - } - } - - // restores - SetMapMode(rGfx.GetHDC(), nOldMapMode); - SetTextColor(rGfx.GetHDC(), crOldTextColor); - SetBkMode(rGfx.GetHDC(), nOldBkMode); - SelectObject(rGfx.GetHDC(), hOldFont); - } -} - - -//************************************************************************ -// -// CLCDColorText::OnUpdate -// -//************************************************************************ - -void CLCDColorText::OnUpdate(DWORD timestamp) -{ - if( m_ScrollRate != 0 && m_bRecalcExtent == FALSE ) - { - //How much time has passed? - if( m_RunningTime == 0 ) - m_RunningTime = timestamp; - - //Scrollrate is in pixels per second - DWORD elapsed = timestamp - m_RunningTime; //milliseconds - - //Only update if a full second has passed - if( elapsed < 1000 ) - return; - - float secs = elapsed / 1000.0f; //to seconds - int jump = (int)(secs * m_ScrollRate + 0.5f); //to pixels - - m_StartX += jump; - m_LoopX += jump; - - if( (m_ScrollRate > 0 && m_LoopX >= 0) || - (m_ScrollRate < 0 && m_LoopX <= 0) ) - { - m_StartX = m_LoopX; - m_LoopX += m_JumpDistance; - } - - m_RunningTime = timestamp; - } -} - - -//************************************************************************ -// -// CLCDColorText::SetFontColor -// -//************************************************************************ - -void CLCDColorText::SetFontColor(COLORREF color) -{ - m_crForegroundColor = color; -} - - -//************************************************************************ -// -// CLCDColorText::SetScrollRate -// -//************************************************************************ - -void CLCDColorText::SetScrollRate( int pixelspersec ) -{ - m_ScrollRate = pixelspersec; - - m_StartX = 0; - m_bRecalcExtent = TRUE; -} - -//** end of LCDColorText.cpp ********************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// CLCDColorText.cpp +// +// The CLCDColorText class draws scrollable color text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + +//************************************************************************ +// +// CLCDColorText::CLCDColorText +// +//************************************************************************ + +CLCDColorText::CLCDColorText(void) +{ + m_nTextLength = 0; + m_hFont = NULL; + m_sText.erase(m_sText.begin(), m_sText.end()); + SetForegroundColor(RGB(255, 0, 255)); + m_bRecalcExtent = TRUE; + ZeroMemory(&m_dtp, sizeof(DRAWTEXTPARAMS)); + m_dtp.cbSize = sizeof(DRAWTEXTPARAMS); + m_nTextFormat = m_nTextAlignment = (DT_LEFT | DT_NOPREFIX); + m_nTextAlignment = DT_LEFT; + ZeroMemory(&m_sizeVExtent, sizeof(m_sizeVExtent)); + ZeroMemory(&m_sizeHExtent, sizeof(m_sizeHExtent)); + + SetBackgroundMode(TRANSPARENT, RGB(255,255,255)); + + //Default font + LOGFONT lf; + lf.lfCharSet = 0; + lf.lfClipPrecision = 2; + lf.lfEscapement = 0; + lf.lfHeight = -32; + lf.lfItalic = 0; + lf.lfOrientation = 0; + lf.lfOutPrecision = 3; + lf.lfPitchAndFamily = 18; + lf.lfQuality = 1; + lf.lfStrikeOut = 0; + lf.lfUnderline = 0; + lf.lfWeight = 400; + lf.lfWidth = 0; + + wsprintf(lf.lfFaceName, _T("Times New Roman") ); + + m_hFont = CreateFontIndirect(&lf); + + m_StartX = 0; + m_LoopX = 0; + m_ScrollRate = 0; + m_PixelLength = 0; + m_RunningTime = 0; + m_ScrollBuffer = 20; + m_JumpDistance = 0; + + m_bAutoScroll = true; +} + + + +//************************************************************************ +// +// CLCDColorText::~CLCDColorText +// +//************************************************************************ + +CLCDColorText::~CLCDColorText() +{ +} + + +//************************************************************************ +// +// CLCDColorText::SetBackgroundMode +// +//************************************************************************ + +void CLCDColorText::SetBackgroundMode(int nMode, COLORREF color) +{ + m_nBkMode = nMode; + m_backColor = color; +} + + +//************************************************************************ +// +// CLCDColorText::OnDraw +// +//************************************************************************ + +void CLCDColorText::OnDraw(CLCDGfxBase &rGfx) +{ + if(GetBackgroundMode() == OPAQUE) + { + HBRUSH backbrush = CreateSolidBrush(m_backColor); + + // clear the clipped area + RECT rcClp = { 0, 0, m_Size.cx, m_Size.cy }; + FillRect(rGfx.GetHDC(), &rcClp, backbrush); + + // clear the logical area + RECT rcLog = { 0, 0, m_sizeLogical.cx, m_sizeLogical.cy }; + FillRect(rGfx.GetHDC(), &rcLog, backbrush); + + DeleteObject(backbrush); + } + + if(m_nTextLength) + { + + // map mode text, with transparency + int nOldMapMode = SetMapMode(rGfx.GetHDC(), MM_TEXT); + + int nOldBkMode = SetBkMode(rGfx.GetHDC(), TRANSPARENT); + + // select current font + HFONT hOldFont = (HFONT)SelectObject(rGfx.GetHDC(), m_hFont); + + // select color + COLORREF crOldTextColor = SetTextColor(rGfx.GetHDC(), m_crForegroundColor); + + if (m_bRecalcExtent) + { + int nTextFormat; + + RECT rExtent; + // calculate vertical extent with word wrap + nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = GetWidth(); + rExtent.bottom = GetHeight(); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeVExtent.cx = rExtent.right; + m_sizeVExtent.cy = rExtent.bottom; + + // calculate horizontal extent w/o word wrap + nTextFormat = (m_nTextFormat | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = GetWidth(); + rExtent.bottom = GetHeight(); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeHExtent.cx = rExtent.right; + m_sizeHExtent.cy = rExtent.bottom; + + m_bRecalcExtent = FALSE; + + //For scrolling + m_PixelLength = m_sizeHExtent.cx; + m_StartX = 0; + + if( m_bAutoScroll ) + { + if( m_PixelLength > GetWidth() ) + { + m_ScrollRate = -1*GetHeight(); + } + else + { + m_ScrollRate = 0; + } + } + + if( m_ScrollRate > 0 ) + { + if( GetWidth() > m_PixelLength + m_ScrollBuffer ) + { + m_JumpDistance = -1 * GetWidth(); + } + else + { + m_JumpDistance = -1 * (m_PixelLength + m_ScrollBuffer); + } + } + else if( m_ScrollRate < 0 ) + { + if( GetWidth() > m_PixelLength + m_ScrollBuffer ) + { + m_JumpDistance = GetWidth(); + } + else + { + m_JumpDistance = m_PixelLength + m_ScrollBuffer; + } + } + + m_LoopX = m_JumpDistance; + } + + if( IsVisible() ) + { + if( m_ScrollRate == 0 ) + { + RECT rBoundary = { 0, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rBoundary, m_nTextFormat, &m_dtp); + } + else + { + RECT rBoundaryFirst = { m_StartX, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; + RECT rBoundarySecond = { m_LoopX, 0, 0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; + + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), + &rBoundaryFirst, m_nTextFormat, &m_dtp); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), + &rBoundarySecond, m_nTextFormat, &m_dtp); + } + } + + // restores + SetMapMode(rGfx.GetHDC(), nOldMapMode); + SetTextColor(rGfx.GetHDC(), crOldTextColor); + SetBkMode(rGfx.GetHDC(), nOldBkMode); + SelectObject(rGfx.GetHDC(), hOldFont); + } +} + + +//************************************************************************ +// +// CLCDColorText::OnUpdate +// +//************************************************************************ + +void CLCDColorText::OnUpdate(DWORD timestamp) +{ + if( m_ScrollRate != 0 && m_bRecalcExtent == FALSE ) + { + //How much time has passed? + if( m_RunningTime == 0 ) + m_RunningTime = timestamp; + + //Scrollrate is in pixels per second + DWORD elapsed = timestamp - m_RunningTime; //milliseconds + + //Only update if a full second has passed + if( elapsed < 1000 ) + return; + + float secs = elapsed / 1000.0f; //to seconds + int jump = (int)(secs * m_ScrollRate + 0.5f); //to pixels + + m_StartX += jump; + m_LoopX += jump; + + if( (m_ScrollRate > 0 && m_LoopX >= 0) || + (m_ScrollRate < 0 && m_LoopX <= 0) ) + { + m_StartX = m_LoopX; + m_LoopX += m_JumpDistance; + } + + m_RunningTime = timestamp; + } +} + + +//************************************************************************ +// +// CLCDColorText::SetFontColor +// +//************************************************************************ + +void CLCDColorText::SetFontColor(COLORREF color) +{ + m_crForegroundColor = color; +} + + +//************************************************************************ +// +// CLCDColorText::SetScrollRate +// +//************************************************************************ + +void CLCDColorText::SetScrollRate( int pixelspersec ) +{ + m_ScrollRate = pixelspersec; + + m_StartX = 0; + m_bRecalcExtent = TRUE; +} + +//** end of LCDColorText.cpp ********************************************* diff --git a/src/thirdparty/LCDUI/LCDColorText.h b/src/thirdparty/LCDUI/LCDColorText.h index 30bfeecd160..0f88b4d8fa0 100644 --- a/src/thirdparty/LCDUI/LCDColorText.h +++ b/src/thirdparty/LCDUI/LCDColorText.h @@ -1,63 +1,63 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDColorText.h -// -// The CLCDText class draws simple text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDCOLORTEXT_H_INCLUDED_ -#define _LCDCOLORTEXT_H_INCLUDED_ - -#include "LCDText.h" - -class CLCDColorText : public CLCDText -{ -public: - CLCDColorText(); - virtual ~CLCDColorText(); - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void OnUpdate(DWORD timestamp); - - virtual void SetFontColor(COLORREF color); - virtual void SetBackgroundMode(int nMode, COLORREF color=RGB(255,255,255)); - void SetScrollRate( int pixelspersec ); - void SetAutoScroll(bool b) - { m_bAutoScroll = b; } - - enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 12 }; - -private: - COLORREF m_backColor; - - //For scrolling - DWORD m_RunningTime; - int m_StartX; - int m_LoopX; - int m_ScrollRate; //pixels per second - int m_PixelLength; - int m_ScrollBuffer; //how many pixels between scrolls - int m_JumpDistance; - - bool m_bAutoScroll; //automatically scroll if text length > draw area -}; - -#endif // !_LCDCOLORTEXT_H_INCLUDED_ - -//** end of LCDColorText.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDColorText.h +// +// The CLCDText class draws simple text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDCOLORTEXT_H_INCLUDED_ +#define _LCDCOLORTEXT_H_INCLUDED_ + +#include "LCDText.h" + +class CLCDColorText : public CLCDText +{ +public: + CLCDColorText(); + virtual ~CLCDColorText(); + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void OnUpdate(DWORD timestamp); + + virtual void SetFontColor(COLORREF color); + virtual void SetBackgroundMode(int nMode, COLORREF color=RGB(255,255,255)); + void SetScrollRate( int pixelspersec ); + void SetAutoScroll(bool b) + { m_bAutoScroll = b; } + + enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 12 }; + +private: + COLORREF m_backColor; + + //For scrolling + DWORD m_RunningTime; + int m_StartX; + int m_LoopX; + int m_ScrollRate; //pixels per second + int m_PixelLength; + int m_ScrollBuffer; //how many pixels between scrolls + int m_JumpDistance; + + bool m_bAutoScroll; //automatically scroll if text length > draw area +}; + +#endif // !_LCDCOLORTEXT_H_INCLUDED_ + +//** end of LCDColorText.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDConnection.cpp b/src/thirdparty/LCDUI/LCDConnection.cpp index c33f844abff..b6821b859e1 100644 --- a/src/thirdparty/LCDUI/LCDConnection.cpp +++ b/src/thirdparty/LCDUI/LCDConnection.cpp @@ -1,723 +1,723 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDConnection.cpp -// -// The CLCDConnection class manages connections to all LCD devices -// including color and monochrome -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - -// Add the lgLcd.lib to the linker - -// #pragma comment(lib, "lgLcd.lib") - -// to keep track of clients that use multiple CLCDOutput instances -// within the same app -LONG CLCDConnection::g_lInitCount = 0; - -//************************************************************************ -// -// CLCDConnection::CLCDConnection -// -//************************************************************************ - -CLCDConnection::CLCDConnection(void) -{ - m_hConnection = LGLCD_INVALID_CONNECTION; - - ZeroMemory(&m_AppletState, sizeof(m_AppletState)); - - m_plcdSoftButtonsChangedCtx = NULL; - - InitializeCriticalSection(&m_csCallback); -} - - -//************************************************************************ -// -// CLCDConnection::~CLCDConnection -// -//************************************************************************ - -CLCDConnection::~CLCDConnection(void) -{ - Disconnect(); - - FreeMonoOutput(); - FreeColorOutput(); - - if (m_AppletState.Mono.pGfx) - { - delete m_AppletState.Mono.pGfx; - m_AppletState.Mono.pGfx = NULL; - } - if (m_AppletState.Color.pGfx) - { - delete m_AppletState.Color.pGfx; - m_AppletState.Color.pGfx = NULL; - } - DeleteCriticalSection(&m_csCallback); -} - - -//************************************************************************ -// -// CLCDConnection::Initialize -// -//************************************************************************ - -BOOL CLCDConnection::Initialize(lgLcdConnectContext & ConnectContext, - lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext) -{ - // Assume only BW is supported - m_AppletState.Mono.pOutput = new CLCDOutput(); - m_AppletState.Mono.pGfx = new CLCDGfxMono(); - m_AppletState.Mono.pGfx->Initialize(); - m_AppletState.Mono.pOutput->SetGfx(m_AppletState.Mono.pGfx); - - lgLcdConnectContextEx ConnectContextEx; - memset(&ConnectContextEx, 0, sizeof(ConnectContextEx)); - ConnectContextEx.appFriendlyName = ConnectContext.appFriendlyName; - ConnectContextEx.isPersistent = ConnectContext.isPersistent; - ConnectContextEx.isAutostartable = ConnectContext.isAutostartable; - ConnectContextEx.connection = LGLCD_INVALID_CONNECTION; - ConnectContextEx.onConfigure = ConnectContext.onConfigure; - ConnectContextEx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BW; - - return Initialize(ConnectContextEx, pSoftButtonChangedContext); -} - - -//************************************************************************ -// -// CLCDConnection::Initialize -// -//************************************************************************ - -BOOL CLCDConnection::Initialize(lgLcdConnectContextEx & ConnectContext, - lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext) -{ - DWORD res = ERROR_SUCCESS; - - if ((LGLCD_APPLET_CAP_BASIC == ConnectContext.dwAppletCapabilitiesSupported) || - ConnectContext.dwAppletCapabilitiesSupported & LGLCD_APPLET_CAP_BW) - { - m_AppletState.Mono.pOutput = AllocMonoOutput(); - m_AppletState.Mono.pGfx = new CLCDGfxMono(); - m_AppletState.Mono.pGfx->Initialize(); - m_AppletState.Mono.pOutput->SetGfx(m_AppletState.Mono.pGfx); - } - - if (ConnectContext.dwAppletCapabilitiesSupported & LGLCD_APPLET_CAP_QVGA) - { - m_AppletState.Color.pOutput = AllocColorOutput(); - m_AppletState.Color.pGfx = new CLCDGfxColor(); - m_AppletState.Color.pGfx->Initialize(); - m_AppletState.Color.pOutput->SetGfx(m_AppletState.Color.pGfx); - } - - //Assure we only call the lib's init once - LCDUIASSERT(g_lInitCount >= 0); - if(1 == InterlockedIncrement(&g_lInitCount)) - { - // need to call lgLcdInit once - res = lgLcdInit(); - if (ERROR_SUCCESS != res) - { - InterlockedDecrement(&g_lInitCount); - LCDUITRACE(_T("WARNING: lgLcdInit failed\n")); - return FALSE; - } - } - - memset(&m_lcdConnectCtxEx, 0, sizeof(m_lcdConnectCtxEx)); - m_lcdConnectCtxEx.appFriendlyName = NULL; - m_lcdConnectCtxEx.isPersistent = FALSE; - m_lcdConnectCtxEx.isAutostartable = FALSE; - m_lcdConnectCtxEx.connection = LGLCD_INVALID_CONNECTION; - - // Initialize the added version 3.0 API fields - m_lcdConnectCtxEx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BASIC; - m_lcdConnectCtxEx.dwReserved1 = 0; - m_lcdConnectCtxEx.onNotify.notificationCallback = NULL; - m_lcdConnectCtxEx.onNotify.notifyContext = NULL; - - memcpy(&m_lcdConnectCtxEx, &ConnectContext, sizeof(lgLcdConnectContextEx)); - - m_plcdSoftButtonsChangedCtx = pSoftButtonChangedContext; - - // Add internal callback handlers if not specified - if (NULL == m_lcdConnectCtxEx.onNotify.notificationCallback) - { - m_lcdConnectCtxEx.onNotify.notificationCallback = _OnNotificationCallback; - m_lcdConnectCtxEx.onNotify.notifyContext = this; - } - - Connect(); - - if (LGLCD_INVALID_CONNECTION != m_hConnection) - { - // At this point, the asynchronous events have already been sent. - // Let's allow a small amount of time for the callback thread to insert the events - // into the shared queue. - // If you don't care about knowing about devices after Initialize - // completes, you can remove these 2 lines - Sleep(50); - Update(); - } - - return TRUE; -} - - -//************************************************************************ -// -// CLCDConnection::Shutdown -// -//************************************************************************ - -void CLCDConnection::Shutdown(void) -{ - Disconnect(); - - if(0 == InterlockedDecrement(&g_lInitCount)) - { - lgLcdDeInit(); - } - - m_plcdSoftButtonsChangedCtx = NULL; -} - - -//************************************************************************ -// -// CLCDConnection::Connect -// -// This will attempt a connection to LCDMon -//************************************************************************ - -void CLCDConnection::Connect(void) -{ - //Close previous connections - Disconnect(); - - if (LGLCD_INVALID_CONNECTION == m_hConnection) - { - DWORD retval = lgLcdConnectEx(&m_lcdConnectCtxEx); - if (ERROR_SUCCESS == retval) - { - m_hConnection = m_lcdConnectCtxEx.connection; - } - else - { - if( ERROR_SERVICE_NOT_ACTIVE == retval ) - { - LCDUITRACE( _T("lgLcdConnectEx ---> ERROR_INVALID_PARAMETER\n") ); - m_hConnection = LGLCD_INVALID_CONNECTION; - } - - m_hConnection = LGLCD_INVALID_CONNECTION; - } - } -} - - -//************************************************************************ -// -// CLCDConnection::Disconnect -// -//************************************************************************ - -void CLCDConnection::Disconnect(void) -{ - //Close your devices, too - if (m_AppletState.Color.pOutput) - { - m_AppletState.Color.pOutput->Close(); - } - if (m_AppletState.Mono.pOutput) - { - m_AppletState.Mono.pOutput->Close(); - } - - if( LGLCD_INVALID_CONNECTION != m_hConnection ) - { - lgLcdDisconnect(m_hConnection); - m_hConnection = LGLCD_INVALID_CONNECTION; - } -} - - -//************************************************************************ -// -// CLCDConnection::IsConnected -// -//************************************************************************ - -BOOL CLCDConnection::IsConnected(void) -{ - return LGLCD_INVALID_CONNECTION != m_hConnection; -} - - -//************************************************************************ -// -// CLCDConnection::GetConnectionId -// -//************************************************************************ - -int CLCDConnection::GetConnectionId(void) -{ - return m_hConnection; -} - - -//************************************************************************ -// -// CLCDConnection::ColorOutput -// -//************************************************************************ - -CLCDOutput *CLCDConnection::ColorOutput(void) -{ - return m_AppletState.Color.pOutput; -} - - -//************************************************************************ -// -// CLCDConnection::MonoOutput -// -//************************************************************************ - -CLCDOutput *CLCDConnection::MonoOutput(void) -{ - return m_AppletState.Mono.pOutput; -} - - -//************************************************************************ -// -// CLCDConnection::_OnNotificationCallback -// -//************************************************************************ - -DWORD CALLBACK CLCDConnection::_OnNotificationCallback( - IN int connection, - IN const PVOID pContext, - IN DWORD notificationCode, - IN DWORD notifyParm1, - IN DWORD notifyParm2, - IN DWORD notifyParm3, - IN DWORD notifyParm4) -{ - - UNREFERENCED_PARAMETER(connection); - UNREFERENCED_PARAMETER(notifyParm3); - UNREFERENCED_PARAMETER(notifyParm4); - - CLCDConnection* pThis = (CLCDConnection*)pContext; - - CB_EVENT Event; - memset(&Event, 0, sizeof(Event)); - EnterCriticalSection(&pThis->m_csCallback); - Event.Type = CBT_NOTIFICATION; - Event.CallbackCode = notificationCode; - Event.CallbackParam1 = notifyParm1; - Event.CallbackParam2 = notifyParm2; - pThis->m_CallbackEventQueue.push(Event); - LeaveCriticalSection(&pThis->m_csCallback); - - pThis->OnCallbackEvent(); - - return 0; -} - - -//************************************************************************ -// -// CLCDConnection::_OnSoftButtonsCallback -// -//************************************************************************ - -DWORD CALLBACK CLCDConnection::_OnSoftButtonsCallback( - IN int device, - IN DWORD dwButtons, - IN const PVOID pContext) -{ - CLCDConnection* pThis = (CLCDConnection*)pContext; - - CB_EVENT Event; - memset(&Event, 0, sizeof(Event)); - EnterCriticalSection(&pThis->m_csCallback); - Event.Type = CBT_BUTTON; - Event.CallbackCode = device; - Event.CallbackParam1 = dwButtons; - pThis->m_CallbackEventQueue.push(Event); - LeaveCriticalSection(&pThis->m_csCallback); - - pThis->OnCallbackEvent(); - - return 0; -} - - -//************************************************************************ -// -// CLCDConnection::_OnConfigureCallback -// -//************************************************************************ - -DWORD CALLBACK CLCDConnection::_OnConfigureCallback( - IN int connection, - IN const PVOID pContext) -{ - UNREFERENCED_PARAMETER(connection); - - CLCDConnection* pThis = (CLCDConnection*)pContext; - - CB_EVENT Event; - memset(&Event, 0, sizeof(Event)); - EnterCriticalSection(&pThis->m_csCallback); - Event.Type = CBT_CONFIG; - pThis->m_CallbackEventQueue.push(Event); - LeaveCriticalSection(&pThis->m_csCallback); - - return 0; -} - - -//************************************************************************ -// -// CLCDConnection::GetNextCallbackEvent -// -//************************************************************************ - -BOOL CLCDConnection::GetNextCallbackEvent(CB_EVENT& rEvent) -{ - memset(&rEvent, 0, sizeof(rEvent)); - EnterCriticalSection(&m_csCallback); - if(0 < m_CallbackEventQueue.size()) - { - std::swap(rEvent, m_CallbackEventQueue.front()); - m_CallbackEventQueue.pop(); - LeaveCriticalSection(&m_csCallback); - return TRUE; - } - LeaveCriticalSection(&m_csCallback); - return FALSE; -} - - -//************************************************************************ -// -// CLCDConnection::Update -// -//************************************************************************ - -void CLCDConnection::Update(void) -{ - // If we're not connected, connect - if (LGLCD_INVALID_CONNECTION == m_hConnection) - { - Connect(); - } - - // Get events - CB_EVENT Event; - while(GetNextCallbackEvent(Event)) - { - switch(Event.Type) - { - case CBT_NOTIFICATION: - OnNotification(Event.CallbackCode, Event.CallbackParam1); - break; - - case CBT_CONFIG: - OnConfigure(); - break; - - case CBT_BUTTON: - OnSoftButtonEvent(Event.CallbackCode, Event.CallbackParam1); - break; - - default: - break; - } - } - - // For each display type - for (int i = 0; i < 2; i++) - { - LCD_DEVICE_STATE* pDevice = (i == 0) ? &m_AppletState.Mono : &m_AppletState.Color; - - if (NULL == pDevice->pOutput) - { - // Output not supported - continue; - } - - if (pDevice->pOutput->IsOpened()) - { - pDevice->pOutput->OnUpdate(GetTickCount()); - pDevice->pOutput->OnDraw(); - } - - // If the device is closed, but it was opened by OpenByType(), - // we can try to open it again... - if (!pDevice->pOutput->IsOpened() && pDevice->pOutput->HasBeenOpenedByDeviceType()) - { - pDevice->pOutput->ReOpenDeviceType(); - } - } -} - - -//************************************************************************ -// -// CLCDConnection::OnConfigure -// -//************************************************************************ - -void CLCDConnection::OnConfigure(void) -{ - LCDUITRACE(_T("OnConfigure\n")); -} - - -//************************************************************************ -// -// CLCDConnection::OnDeviceArrival -// -//************************************************************************ - -void CLCDConnection::OnDeviceArrival(DWORD dwDisplayType) -{ - LCD_DEVICE_STATE* pDevice = NULL; - - switch(dwDisplayType) - { - case LGLCD_DEVICE_BW: - pDevice = &m_AppletState.Mono; - break; - - case LGLCD_DEVICE_QVGA: - pDevice = &m_AppletState.Color; - break; - - default: - LCDUITRACE(_T("Unhandled DisplayType in OnDeviceArrival()!\n")); - return; - } - - // Ensure that we have a valid output - if (NULL == pDevice->pOutput) - { - LCDUITRACE(_T("Device arrival on unsupported device\n")); - return; - } - - lgLcdOpenByTypeContext OpenCtx; - memset(&OpenCtx, 0, sizeof(OpenCtx)); - - OpenCtx.connection = m_hConnection; - OpenCtx.deviceType = dwDisplayType; - OpenCtx.onSoftbuttonsChanged.softbuttonsChangedCallback = _OnSoftButtonsCallback; - OpenCtx.onSoftbuttonsChanged.softbuttonsChangedContext = this; - OpenCtx.device = LGLCD_INVALID_DEVICE; - - // If user has specified the soft button context, allow user to override - if (NULL != m_plcdSoftButtonsChangedCtx) - { - OpenCtx.onSoftbuttonsChanged = *m_plcdSoftButtonsChangedCtx; - } - - pDevice->pOutput->OpenByType(OpenCtx); -} - - -//************************************************************************ -// -// CLCDConnection::OnDeviceRemoval -// -//************************************************************************ - -void CLCDConnection::OnDeviceRemoval(DWORD dwDisplayType) -{ - LCD_DEVICE_STATE* pDevice = NULL; - - switch(dwDisplayType) - { - case LGLCD_DEVICE_BW: - pDevice = &m_AppletState.Mono; - break; - - case LGLCD_DEVICE_QVGA: - pDevice = &m_AppletState.Color; - break; - - default: - LCDUITRACE(_T("Unhandled DisplayType in OnDeviceArrival()!\n")); - return; - } - - if (pDevice->pOutput) - { - pDevice->pOutput->StopOpeningByDeviceType(); - pDevice->pOutput->Close(); - } -} - - -//************************************************************************ -// -// CLCDConnection::OnAppletEnabled -// -//************************************************************************ - -void CLCDConnection::OnAppletEnabled(void) -{ -} - - -//************************************************************************ -// -// CLCDConnection::OnAppletDisabled -// -//************************************************************************ - -void CLCDConnection::OnAppletDisabled(void) -{ -} - - -//************************************************************************ -// -// CLCDConnection::OnNotification -// -//************************************************************************ - -void CLCDConnection::OnNotification(DWORD dwNotification, DWORD dwParam1) -{ - switch(dwNotification) - { - case LGLCD_NOTIFICATION_DEVICE_ARRIVAL: - LCDUITRACE(_T("LGLCD_NOTIFICATION_DEVICE_ARRIVAL\n")); - OnDeviceArrival(dwParam1); - break; - - case LGLCD_NOTIFICATION_DEVICE_REMOVAL: - LCDUITRACE(_T("LGLCD_NOTIFICATION_DEVICE_REMOVAL\n")); - OnDeviceRemoval(dwParam1); - break; - - case LGLCD_NOTIFICATION_CLOSE_CONNECTION: - LCDUITRACE(_T("LGLCD_NOTIFICATION_CLOSE_CONNECTION\n")); - Disconnect(); - break; - - case LGLCD_NOTIFICATION_APPLET_DISABLED: - LCDUITRACE(_T("LGLCD_NOTIFICATION_APPLET_DISABLED\n")); - OnAppletDisabled(); - break; - - case LGLCD_NOTIFICATION_APPLET_ENABLED: - LCDUITRACE(_T("LGLCD_NOTIFICATION_APPLET_ENABLED\n")); - OnAppletEnabled(); - break; - - case LGLCD_NOTIFICATION_TERMINATE_APPLET: - break; - } -} - - -//************************************************************************ -// -// CLCDConnection::OnSoftButtonEvent -// -//************************************************************************ - -void CLCDConnection::OnSoftButtonEvent(int nDeviceId, DWORD dwButtonState) -{ - // Forward this to the appropriate display - if (m_AppletState.Mono.pOutput && (nDeviceId == m_AppletState.Mono.pOutput->GetDeviceId())) - { - m_AppletState.Mono.pOutput->OnSoftButtonEvent(dwButtonState); - } - else if (m_AppletState.Color.pOutput && (nDeviceId == m_AppletState.Color.pOutput->GetDeviceId())) - { - m_AppletState.Color.pOutput->OnSoftButtonEvent(dwButtonState); - } -} - - -//************************************************************************ -// -// CLCDConnection::AllocMonoOutput -// -//************************************************************************ - -CLCDOutput* CLCDConnection::AllocMonoOutput(void) -{ - return new CLCDOutput(); -} - - -//************************************************************************ -// -// CLCDConnection::AllocColorOutput -// -//************************************************************************ - -CLCDOutput* CLCDConnection::AllocColorOutput(void) -{ - return new CLCDOutput(); -} - - -//************************************************************************ -// -// CLCDConnection::FreeMonoOutput -// -//************************************************************************ - -void CLCDConnection::FreeMonoOutput(void) -{ - if (NULL != m_AppletState.Mono.pOutput) - { - delete m_AppletState.Mono.pOutput; - m_AppletState.Mono.pOutput = NULL; - } -} - - -//************************************************************************ -// -// CLCDConnection::FreeColorOutput -// -//************************************************************************ - -void CLCDConnection::FreeColorOutput(void) -{ - if (NULL != m_AppletState.Color.pOutput) - { - delete m_AppletState.Color.pOutput; - m_AppletState.Color.pOutput = NULL; - } -} - -//** end of LCDConnection.cpp ******************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDConnection.cpp +// +// The CLCDConnection class manages connections to all LCD devices +// including color and monochrome +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + +// Add the lgLcd.lib to the linker + +// #pragma comment(lib, "lgLcd.lib") + +// to keep track of clients that use multiple CLCDOutput instances +// within the same app +LONG CLCDConnection::g_lInitCount = 0; + +//************************************************************************ +// +// CLCDConnection::CLCDConnection +// +//************************************************************************ + +CLCDConnection::CLCDConnection(void) +{ + m_hConnection = LGLCD_INVALID_CONNECTION; + + ZeroMemory(&m_AppletState, sizeof(m_AppletState)); + + m_plcdSoftButtonsChangedCtx = NULL; + + InitializeCriticalSection(&m_csCallback); +} + + +//************************************************************************ +// +// CLCDConnection::~CLCDConnection +// +//************************************************************************ + +CLCDConnection::~CLCDConnection(void) +{ + Disconnect(); + + FreeMonoOutput(); + FreeColorOutput(); + + if (m_AppletState.Mono.pGfx) + { + delete m_AppletState.Mono.pGfx; + m_AppletState.Mono.pGfx = NULL; + } + if (m_AppletState.Color.pGfx) + { + delete m_AppletState.Color.pGfx; + m_AppletState.Color.pGfx = NULL; + } + DeleteCriticalSection(&m_csCallback); +} + + +//************************************************************************ +// +// CLCDConnection::Initialize +// +//************************************************************************ + +BOOL CLCDConnection::Initialize(lgLcdConnectContext & ConnectContext, + lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext) +{ + // Assume only BW is supported + m_AppletState.Mono.pOutput = new CLCDOutput(); + m_AppletState.Mono.pGfx = new CLCDGfxMono(); + m_AppletState.Mono.pGfx->Initialize(); + m_AppletState.Mono.pOutput->SetGfx(m_AppletState.Mono.pGfx); + + lgLcdConnectContextEx ConnectContextEx; + memset(&ConnectContextEx, 0, sizeof(ConnectContextEx)); + ConnectContextEx.appFriendlyName = ConnectContext.appFriendlyName; + ConnectContextEx.isPersistent = ConnectContext.isPersistent; + ConnectContextEx.isAutostartable = ConnectContext.isAutostartable; + ConnectContextEx.connection = LGLCD_INVALID_CONNECTION; + ConnectContextEx.onConfigure = ConnectContext.onConfigure; + ConnectContextEx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BW; + + return Initialize(ConnectContextEx, pSoftButtonChangedContext); +} + + +//************************************************************************ +// +// CLCDConnection::Initialize +// +//************************************************************************ + +BOOL CLCDConnection::Initialize(lgLcdConnectContextEx & ConnectContext, + lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext) +{ + DWORD res = ERROR_SUCCESS; + + if ((LGLCD_APPLET_CAP_BASIC == ConnectContext.dwAppletCapabilitiesSupported) || + ConnectContext.dwAppletCapabilitiesSupported & LGLCD_APPLET_CAP_BW) + { + m_AppletState.Mono.pOutput = AllocMonoOutput(); + m_AppletState.Mono.pGfx = new CLCDGfxMono(); + m_AppletState.Mono.pGfx->Initialize(); + m_AppletState.Mono.pOutput->SetGfx(m_AppletState.Mono.pGfx); + } + + if (ConnectContext.dwAppletCapabilitiesSupported & LGLCD_APPLET_CAP_QVGA) + { + m_AppletState.Color.pOutput = AllocColorOutput(); + m_AppletState.Color.pGfx = new CLCDGfxColor(); + m_AppletState.Color.pGfx->Initialize(); + m_AppletState.Color.pOutput->SetGfx(m_AppletState.Color.pGfx); + } + + //Assure we only call the lib's init once + LCDUIASSERT(g_lInitCount >= 0); + if(1 == InterlockedIncrement(&g_lInitCount)) + { + // need to call lgLcdInit once + res = lgLcdInit(); + if (ERROR_SUCCESS != res) + { + InterlockedDecrement(&g_lInitCount); + LCDUITRACE(_T("WARNING: lgLcdInit failed\n")); + return FALSE; + } + } + + memset(&m_lcdConnectCtxEx, 0, sizeof(m_lcdConnectCtxEx)); + m_lcdConnectCtxEx.appFriendlyName = NULL; + m_lcdConnectCtxEx.isPersistent = FALSE; + m_lcdConnectCtxEx.isAutostartable = FALSE; + m_lcdConnectCtxEx.connection = LGLCD_INVALID_CONNECTION; + + // Initialize the added version 3.0 API fields + m_lcdConnectCtxEx.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BASIC; + m_lcdConnectCtxEx.dwReserved1 = 0; + m_lcdConnectCtxEx.onNotify.notificationCallback = NULL; + m_lcdConnectCtxEx.onNotify.notifyContext = NULL; + + memcpy(&m_lcdConnectCtxEx, &ConnectContext, sizeof(lgLcdConnectContextEx)); + + m_plcdSoftButtonsChangedCtx = pSoftButtonChangedContext; + + // Add internal callback handlers if not specified + if (NULL == m_lcdConnectCtxEx.onNotify.notificationCallback) + { + m_lcdConnectCtxEx.onNotify.notificationCallback = _OnNotificationCallback; + m_lcdConnectCtxEx.onNotify.notifyContext = this; + } + + Connect(); + + if (LGLCD_INVALID_CONNECTION != m_hConnection) + { + // At this point, the asynchronous events have already been sent. + // Let's allow a small amount of time for the callback thread to insert the events + // into the shared queue. + // If you don't care about knowing about devices after Initialize + // completes, you can remove these 2 lines + Sleep(50); + Update(); + } + + return TRUE; +} + + +//************************************************************************ +// +// CLCDConnection::Shutdown +// +//************************************************************************ + +void CLCDConnection::Shutdown(void) +{ + Disconnect(); + + if(0 == InterlockedDecrement(&g_lInitCount)) + { + lgLcdDeInit(); + } + + m_plcdSoftButtonsChangedCtx = NULL; +} + + +//************************************************************************ +// +// CLCDConnection::Connect +// +// This will attempt a connection to LCDMon +//************************************************************************ + +void CLCDConnection::Connect(void) +{ + //Close previous connections + Disconnect(); + + if (LGLCD_INVALID_CONNECTION == m_hConnection) + { + DWORD retval = lgLcdConnectEx(&m_lcdConnectCtxEx); + if (ERROR_SUCCESS == retval) + { + m_hConnection = m_lcdConnectCtxEx.connection; + } + else + { + if( ERROR_SERVICE_NOT_ACTIVE == retval ) + { + LCDUITRACE( _T("lgLcdConnectEx ---> ERROR_INVALID_PARAMETER\n") ); + m_hConnection = LGLCD_INVALID_CONNECTION; + } + + m_hConnection = LGLCD_INVALID_CONNECTION; + } + } +} + + +//************************************************************************ +// +// CLCDConnection::Disconnect +// +//************************************************************************ + +void CLCDConnection::Disconnect(void) +{ + //Close your devices, too + if (m_AppletState.Color.pOutput) + { + m_AppletState.Color.pOutput->Close(); + } + if (m_AppletState.Mono.pOutput) + { + m_AppletState.Mono.pOutput->Close(); + } + + if( LGLCD_INVALID_CONNECTION != m_hConnection ) + { + lgLcdDisconnect(m_hConnection); + m_hConnection = LGLCD_INVALID_CONNECTION; + } +} + + +//************************************************************************ +// +// CLCDConnection::IsConnected +// +//************************************************************************ + +BOOL CLCDConnection::IsConnected(void) +{ + return LGLCD_INVALID_CONNECTION != m_hConnection; +} + + +//************************************************************************ +// +// CLCDConnection::GetConnectionId +// +//************************************************************************ + +int CLCDConnection::GetConnectionId(void) +{ + return m_hConnection; +} + + +//************************************************************************ +// +// CLCDConnection::ColorOutput +// +//************************************************************************ + +CLCDOutput *CLCDConnection::ColorOutput(void) +{ + return m_AppletState.Color.pOutput; +} + + +//************************************************************************ +// +// CLCDConnection::MonoOutput +// +//************************************************************************ + +CLCDOutput *CLCDConnection::MonoOutput(void) +{ + return m_AppletState.Mono.pOutput; +} + + +//************************************************************************ +// +// CLCDConnection::_OnNotificationCallback +// +//************************************************************************ + +DWORD CALLBACK CLCDConnection::_OnNotificationCallback( + IN int connection, + IN const PVOID pContext, + IN DWORD notificationCode, + IN DWORD notifyParm1, + IN DWORD notifyParm2, + IN DWORD notifyParm3, + IN DWORD notifyParm4) +{ + + UNREFERENCED_PARAMETER(connection); + UNREFERENCED_PARAMETER(notifyParm3); + UNREFERENCED_PARAMETER(notifyParm4); + + CLCDConnection* pThis = (CLCDConnection*)pContext; + + CB_EVENT Event; + memset(&Event, 0, sizeof(Event)); + EnterCriticalSection(&pThis->m_csCallback); + Event.Type = CBT_NOTIFICATION; + Event.CallbackCode = notificationCode; + Event.CallbackParam1 = notifyParm1; + Event.CallbackParam2 = notifyParm2; + pThis->m_CallbackEventQueue.push(Event); + LeaveCriticalSection(&pThis->m_csCallback); + + pThis->OnCallbackEvent(); + + return 0; +} + + +//************************************************************************ +// +// CLCDConnection::_OnSoftButtonsCallback +// +//************************************************************************ + +DWORD CALLBACK CLCDConnection::_OnSoftButtonsCallback( + IN int device, + IN DWORD dwButtons, + IN const PVOID pContext) +{ + CLCDConnection* pThis = (CLCDConnection*)pContext; + + CB_EVENT Event; + memset(&Event, 0, sizeof(Event)); + EnterCriticalSection(&pThis->m_csCallback); + Event.Type = CBT_BUTTON; + Event.CallbackCode = device; + Event.CallbackParam1 = dwButtons; + pThis->m_CallbackEventQueue.push(Event); + LeaveCriticalSection(&pThis->m_csCallback); + + pThis->OnCallbackEvent(); + + return 0; +} + + +//************************************************************************ +// +// CLCDConnection::_OnConfigureCallback +// +//************************************************************************ + +DWORD CALLBACK CLCDConnection::_OnConfigureCallback( + IN int connection, + IN const PVOID pContext) +{ + UNREFERENCED_PARAMETER(connection); + + CLCDConnection* pThis = (CLCDConnection*)pContext; + + CB_EVENT Event; + memset(&Event, 0, sizeof(Event)); + EnterCriticalSection(&pThis->m_csCallback); + Event.Type = CBT_CONFIG; + pThis->m_CallbackEventQueue.push(Event); + LeaveCriticalSection(&pThis->m_csCallback); + + return 0; +} + + +//************************************************************************ +// +// CLCDConnection::GetNextCallbackEvent +// +//************************************************************************ + +BOOL CLCDConnection::GetNextCallbackEvent(CB_EVENT& rEvent) +{ + memset(&rEvent, 0, sizeof(rEvent)); + EnterCriticalSection(&m_csCallback); + if(0 < m_CallbackEventQueue.size()) + { + std::swap(rEvent, m_CallbackEventQueue.front()); + m_CallbackEventQueue.pop(); + LeaveCriticalSection(&m_csCallback); + return TRUE; + } + LeaveCriticalSection(&m_csCallback); + return FALSE; +} + + +//************************************************************************ +// +// CLCDConnection::Update +// +//************************************************************************ + +void CLCDConnection::Update(void) +{ + // If we're not connected, connect + if (LGLCD_INVALID_CONNECTION == m_hConnection) + { + Connect(); + } + + // Get events + CB_EVENT Event; + while(GetNextCallbackEvent(Event)) + { + switch(Event.Type) + { + case CBT_NOTIFICATION: + OnNotification(Event.CallbackCode, Event.CallbackParam1); + break; + + case CBT_CONFIG: + OnConfigure(); + break; + + case CBT_BUTTON: + OnSoftButtonEvent(Event.CallbackCode, Event.CallbackParam1); + break; + + default: + break; + } + } + + // For each display type + for (int i = 0; i < 2; i++) + { + LCD_DEVICE_STATE* pDevice = (i == 0) ? &m_AppletState.Mono : &m_AppletState.Color; + + if (NULL == pDevice->pOutput) + { + // Output not supported + continue; + } + + if (pDevice->pOutput->IsOpened()) + { + pDevice->pOutput->OnUpdate(GetTickCount()); + pDevice->pOutput->OnDraw(); + } + + // If the device is closed, but it was opened by OpenByType(), + // we can try to open it again... + if (!pDevice->pOutput->IsOpened() && pDevice->pOutput->HasBeenOpenedByDeviceType()) + { + pDevice->pOutput->ReOpenDeviceType(); + } + } +} + + +//************************************************************************ +// +// CLCDConnection::OnConfigure +// +//************************************************************************ + +void CLCDConnection::OnConfigure(void) +{ + LCDUITRACE(_T("OnConfigure\n")); +} + + +//************************************************************************ +// +// CLCDConnection::OnDeviceArrival +// +//************************************************************************ + +void CLCDConnection::OnDeviceArrival(DWORD dwDisplayType) +{ + LCD_DEVICE_STATE* pDevice = NULL; + + switch(dwDisplayType) + { + case LGLCD_DEVICE_BW: + pDevice = &m_AppletState.Mono; + break; + + case LGLCD_DEVICE_QVGA: + pDevice = &m_AppletState.Color; + break; + + default: + LCDUITRACE(_T("Unhandled DisplayType in OnDeviceArrival()!\n")); + return; + } + + // Ensure that we have a valid output + if (NULL == pDevice->pOutput) + { + LCDUITRACE(_T("Device arrival on unsupported device\n")); + return; + } + + lgLcdOpenByTypeContext OpenCtx; + memset(&OpenCtx, 0, sizeof(OpenCtx)); + + OpenCtx.connection = m_hConnection; + OpenCtx.deviceType = dwDisplayType; + OpenCtx.onSoftbuttonsChanged.softbuttonsChangedCallback = _OnSoftButtonsCallback; + OpenCtx.onSoftbuttonsChanged.softbuttonsChangedContext = this; + OpenCtx.device = LGLCD_INVALID_DEVICE; + + // If user has specified the soft button context, allow user to override + if (NULL != m_plcdSoftButtonsChangedCtx) + { + OpenCtx.onSoftbuttonsChanged = *m_plcdSoftButtonsChangedCtx; + } + + pDevice->pOutput->OpenByType(OpenCtx); +} + + +//************************************************************************ +// +// CLCDConnection::OnDeviceRemoval +// +//************************************************************************ + +void CLCDConnection::OnDeviceRemoval(DWORD dwDisplayType) +{ + LCD_DEVICE_STATE* pDevice = NULL; + + switch(dwDisplayType) + { + case LGLCD_DEVICE_BW: + pDevice = &m_AppletState.Mono; + break; + + case LGLCD_DEVICE_QVGA: + pDevice = &m_AppletState.Color; + break; + + default: + LCDUITRACE(_T("Unhandled DisplayType in OnDeviceArrival()!\n")); + return; + } + + if (pDevice->pOutput) + { + pDevice->pOutput->StopOpeningByDeviceType(); + pDevice->pOutput->Close(); + } +} + + +//************************************************************************ +// +// CLCDConnection::OnAppletEnabled +// +//************************************************************************ + +void CLCDConnection::OnAppletEnabled(void) +{ +} + + +//************************************************************************ +// +// CLCDConnection::OnAppletDisabled +// +//************************************************************************ + +void CLCDConnection::OnAppletDisabled(void) +{ +} + + +//************************************************************************ +// +// CLCDConnection::OnNotification +// +//************************************************************************ + +void CLCDConnection::OnNotification(DWORD dwNotification, DWORD dwParam1) +{ + switch(dwNotification) + { + case LGLCD_NOTIFICATION_DEVICE_ARRIVAL: + LCDUITRACE(_T("LGLCD_NOTIFICATION_DEVICE_ARRIVAL\n")); + OnDeviceArrival(dwParam1); + break; + + case LGLCD_NOTIFICATION_DEVICE_REMOVAL: + LCDUITRACE(_T("LGLCD_NOTIFICATION_DEVICE_REMOVAL\n")); + OnDeviceRemoval(dwParam1); + break; + + case LGLCD_NOTIFICATION_CLOSE_CONNECTION: + LCDUITRACE(_T("LGLCD_NOTIFICATION_CLOSE_CONNECTION\n")); + Disconnect(); + break; + + case LGLCD_NOTIFICATION_APPLET_DISABLED: + LCDUITRACE(_T("LGLCD_NOTIFICATION_APPLET_DISABLED\n")); + OnAppletDisabled(); + break; + + case LGLCD_NOTIFICATION_APPLET_ENABLED: + LCDUITRACE(_T("LGLCD_NOTIFICATION_APPLET_ENABLED\n")); + OnAppletEnabled(); + break; + + case LGLCD_NOTIFICATION_TERMINATE_APPLET: + break; + } +} + + +//************************************************************************ +// +// CLCDConnection::OnSoftButtonEvent +// +//************************************************************************ + +void CLCDConnection::OnSoftButtonEvent(int nDeviceId, DWORD dwButtonState) +{ + // Forward this to the appropriate display + if (m_AppletState.Mono.pOutput && (nDeviceId == m_AppletState.Mono.pOutput->GetDeviceId())) + { + m_AppletState.Mono.pOutput->OnSoftButtonEvent(dwButtonState); + } + else if (m_AppletState.Color.pOutput && (nDeviceId == m_AppletState.Color.pOutput->GetDeviceId())) + { + m_AppletState.Color.pOutput->OnSoftButtonEvent(dwButtonState); + } +} + + +//************************************************************************ +// +// CLCDConnection::AllocMonoOutput +// +//************************************************************************ + +CLCDOutput* CLCDConnection::AllocMonoOutput(void) +{ + return new CLCDOutput(); +} + + +//************************************************************************ +// +// CLCDConnection::AllocColorOutput +// +//************************************************************************ + +CLCDOutput* CLCDConnection::AllocColorOutput(void) +{ + return new CLCDOutput(); +} + + +//************************************************************************ +// +// CLCDConnection::FreeMonoOutput +// +//************************************************************************ + +void CLCDConnection::FreeMonoOutput(void) +{ + if (NULL != m_AppletState.Mono.pOutput) + { + delete m_AppletState.Mono.pOutput; + m_AppletState.Mono.pOutput = NULL; + } +} + + +//************************************************************************ +// +// CLCDConnection::FreeColorOutput +// +//************************************************************************ + +void CLCDConnection::FreeColorOutput(void) +{ + if (NULL != m_AppletState.Color.pOutput) + { + delete m_AppletState.Color.pOutput; + m_AppletState.Color.pOutput = NULL; + } +} + +//** end of LCDConnection.cpp ******************************************** diff --git a/src/thirdparty/LCDUI/LCDConnection.h b/src/thirdparty/LCDUI/LCDConnection.h index 22bc4ae7c09..b24e1fe2ade 100644 --- a/src/thirdparty/LCDUI/LCDConnection.h +++ b/src/thirdparty/LCDUI/LCDConnection.h @@ -1,161 +1,161 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDConnection.h -// -// The CLCDConnection class manages connections to all LCD devices -// including color and monochrome -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDCONNECTION_H__ -#define __LCDCONNECTION_H__ - -#include "LCDOutput.h" -#include "LCDGfxMono.h" -#include "LCDGfxColor.h" -#include - -// LCD device state -typedef struct LCD_DEVICE_STATE -{ - CLCDOutput* pOutput; - CLCDGfxBase* pGfx; - -}LCD_DEVICE_STATE; - -// Applet state -typedef struct APPLET_STATE -{ - LCD_DEVICE_STATE Color; - LCD_DEVICE_STATE Mono; - BOOL isEnabled; - -}APPLET_STATE; - -#define LGLCD_INVALID_DEVICE_COOKIE (0) - - -class CLCDConnection -{ -public: - CLCDConnection(void); - virtual ~CLCDConnection(void); - - //This will attempt to open the library - //Call this function before Connect() - virtual BOOL Initialize(lgLcdConnectContext & ConnectContext, - lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext = NULL); - virtual BOOL Initialize(lgLcdConnectContextEx & ConnectContext, - lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext = NULL); - - //This will close your library - virtual void Shutdown(void); - - //Checks if there is a valid connection - virtual BOOL IsConnected(void); - virtual int GetConnectionId(void); - - // Call this function every game frame - virtual void Update(void); - - // Add your controls to the appropriate display - CLCDOutput *ColorOutput(void); - CLCDOutput *MonoOutput(void); - - BOOL HasColorDevice() { return m_AppletState.Color.pOutput && m_AppletState.Color.pOutput->IsOpened(); } - BOOL HasMonochromeDevice() { return m_AppletState.Mono.pOutput && m_AppletState.Mono.pOutput->IsOpened(); } - -protected: - // dwDisplayType = LGLCD_DEVICE_BW or LGLCD_DEVICE_QVGA - virtual void OnDeviceArrival(DWORD dwDisplayType); - virtual void OnDeviceRemoval(DWORD dwDisplayType); - virtual void OnAppletEnabled(void); - virtual void OnAppletDisabled(void); - virtual void OnNotification(DWORD dwNotification, DWORD dwParam1 = 0); - virtual void OnConfigure(void); - virtual void OnSoftButtonEvent(int nDeviceId, DWORD dwButtonState); - virtual void OnCallbackEvent(void) { } - -protected: - virtual void Connect(void); - virtual void Disconnect(void); - -protected: - // Override only if you need to create custom output classes - virtual CLCDOutput* AllocMonoOutput(void); - virtual CLCDOutput* AllocColorOutput(void); - virtual void FreeMonoOutput(void); - virtual void FreeColorOutput(void); - -protected: - // Internal threaded event handling - enum CB_TYPE { CBT_BUTTON, CBT_CONFIG, CBT_NOTIFICATION }; - typedef struct CB_EVENT - { - CB_TYPE Type; - DWORD CallbackCode; - DWORD CallbackParam1; - DWORD CallbackParam2; - DWORD CallbackParam3; - DWORD CallbackParam; - - } CB_EVENT; - - int m_hConnection; - - APPLET_STATE m_AppletState; - - - BOOL GetNextCallbackEvent(CB_EVENT& rEvent); - -private: - lgLcdConnectContextEx m_lcdConnectCtxEx; - - lgLcdSoftbuttonsChangedContext* m_plcdSoftButtonsChangedCtx; - - - -private: - typedef std::queue LCD_CB_EVENT_QUEUE; - - CRITICAL_SECTION m_csCallback; - LCD_CB_EVENT_QUEUE m_CallbackEventQueue; - - - -private: - static LONG g_lInitCount; - - static DWORD CALLBACK _OnNotificationCallback( - IN int connection, - IN const PVOID pContext, - IN DWORD notificationCode, - IN DWORD notifyParm1, - IN DWORD notifyParm2, - IN DWORD notifyParm3, - IN DWORD notifyParm4); - - static DWORD CALLBACK _OnSoftButtonsCallback( - IN int device, - IN DWORD dwButtons, - IN const PVOID pContext); - - static DWORD CALLBACK _OnConfigureCallback( - IN int connection, - IN const PVOID pContext); -}; - -#endif - -//** end of LCDConnection.h ********************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDConnection.h +// +// The CLCDConnection class manages connections to all LCD devices +// including color and monochrome +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDCONNECTION_H__ +#define __LCDCONNECTION_H__ + +#include "LCDOutput.h" +#include "LCDGfxMono.h" +#include "LCDGfxColor.h" +#include + +// LCD device state +typedef struct LCD_DEVICE_STATE +{ + CLCDOutput* pOutput; + CLCDGfxBase* pGfx; + +}LCD_DEVICE_STATE; + +// Applet state +typedef struct APPLET_STATE +{ + LCD_DEVICE_STATE Color; + LCD_DEVICE_STATE Mono; + BOOL isEnabled; + +}APPLET_STATE; + +#define LGLCD_INVALID_DEVICE_COOKIE (0) + + +class CLCDConnection +{ +public: + CLCDConnection(void); + virtual ~CLCDConnection(void); + + //This will attempt to open the library + //Call this function before Connect() + virtual BOOL Initialize(lgLcdConnectContext & ConnectContext, + lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext = NULL); + virtual BOOL Initialize(lgLcdConnectContextEx & ConnectContext, + lgLcdSoftbuttonsChangedContext* pSoftButtonChangedContext = NULL); + + //This will close your library + virtual void Shutdown(void); + + //Checks if there is a valid connection + virtual BOOL IsConnected(void); + virtual int GetConnectionId(void); + + // Call this function every game frame + virtual void Update(void); + + // Add your controls to the appropriate display + CLCDOutput *ColorOutput(void); + CLCDOutput *MonoOutput(void); + + BOOL HasColorDevice() { return m_AppletState.Color.pOutput && m_AppletState.Color.pOutput->IsOpened(); } + BOOL HasMonochromeDevice() { return m_AppletState.Mono.pOutput && m_AppletState.Mono.pOutput->IsOpened(); } + +protected: + // dwDisplayType = LGLCD_DEVICE_BW or LGLCD_DEVICE_QVGA + virtual void OnDeviceArrival(DWORD dwDisplayType); + virtual void OnDeviceRemoval(DWORD dwDisplayType); + virtual void OnAppletEnabled(void); + virtual void OnAppletDisabled(void); + virtual void OnNotification(DWORD dwNotification, DWORD dwParam1 = 0); + virtual void OnConfigure(void); + virtual void OnSoftButtonEvent(int nDeviceId, DWORD dwButtonState); + virtual void OnCallbackEvent(void) { } + +protected: + virtual void Connect(void); + virtual void Disconnect(void); + +protected: + // Override only if you need to create custom output classes + virtual CLCDOutput* AllocMonoOutput(void); + virtual CLCDOutput* AllocColorOutput(void); + virtual void FreeMonoOutput(void); + virtual void FreeColorOutput(void); + +protected: + // Internal threaded event handling + enum CB_TYPE { CBT_BUTTON, CBT_CONFIG, CBT_NOTIFICATION }; + typedef struct CB_EVENT + { + CB_TYPE Type; + DWORD CallbackCode; + DWORD CallbackParam1; + DWORD CallbackParam2; + DWORD CallbackParam3; + DWORD CallbackParam; + + } CB_EVENT; + + int m_hConnection; + + APPLET_STATE m_AppletState; + + + BOOL GetNextCallbackEvent(CB_EVENT& rEvent); + +private: + lgLcdConnectContextEx m_lcdConnectCtxEx; + + lgLcdSoftbuttonsChangedContext* m_plcdSoftButtonsChangedCtx; + + + +private: + typedef std::queue LCD_CB_EVENT_QUEUE; + + CRITICAL_SECTION m_csCallback; + LCD_CB_EVENT_QUEUE m_CallbackEventQueue; + + + +private: + static LONG g_lInitCount; + + static DWORD CALLBACK _OnNotificationCallback( + IN int connection, + IN const PVOID pContext, + IN DWORD notificationCode, + IN DWORD notifyParm1, + IN DWORD notifyParm2, + IN DWORD notifyParm3, + IN DWORD notifyParm4); + + static DWORD CALLBACK _OnSoftButtonsCallback( + IN int device, + IN DWORD dwButtons, + IN const PVOID pContext); + + static DWORD CALLBACK _OnConfigureCallback( + IN int connection, + IN const PVOID pContext); +}; + +#endif + +//** end of LCDConnection.h ********************************************** diff --git a/src/thirdparty/LCDUI/LCDGfxBase.cpp b/src/thirdparty/LCDUI/LCDGfxBase.cpp index bee106659a5..f441b4e4e50 100644 --- a/src/thirdparty/LCDUI/LCDGfxBase.cpp +++ b/src/thirdparty/LCDUI/LCDGfxBase.cpp @@ -1,300 +1,300 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxBase.cpp -// -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDGfxBase::CLCDGfxBase -// -//************************************************************************ - -CLCDGfxBase::CLCDGfxBase(void) -: m_pLCDScreen(NULL), - m_nWidth(0), - m_nHeight(0), - m_pBitmapInfo(NULL), - m_hDC(NULL), - m_hBitmap(NULL), - m_hPrevBitmap(NULL), - m_pBitmapBits(NULL) -{ -} - - -//************************************************************************ -// -// CLCDGfxBase::~CLCDGfxBase -// -//************************************************************************ - -CLCDGfxBase::~CLCDGfxBase(void) -{ - Shutdown(); -} - - -//************************************************************************ -// -// CLCDGfxBase::Initialize -// -//************************************************************************ - -HRESULT CLCDGfxBase::Initialize(void) -{ - m_hDC = CreateCompatibleDC(NULL); - if(NULL == m_hDC) - { - LCDUITRACE(_T("CLCDGfxBase::Initialize(): failed to create compatible DC.\n")); - Shutdown(); - return E_FAIL; - } - - return S_OK; -} - - -//************************************************************************ -// -// CLCDGfxBase::Shutdown -// -//************************************************************************ - -void CLCDGfxBase::Shutdown(void) -{ - if(NULL != m_hBitmap) - { - DeleteObject(m_hBitmap); - m_hBitmap = NULL; - m_pBitmapBits = NULL; - } - - LCDUIASSERT(NULL == m_hPrevBitmap); - m_hPrevBitmap = NULL; - - if(NULL != m_pBitmapInfo) - { - delete [] m_pBitmapInfo; - m_pBitmapInfo = NULL; - } - - if(NULL != m_hDC) - { - DeleteDC(m_hDC); - m_hDC = NULL; - } - - m_nWidth = 0; - m_nHeight = 0; -} - - -//************************************************************************ -// -// CLCDGfxBase::ClearScreen -// -//************************************************************************ - -void CLCDGfxBase::ClearScreen(void) -{ - // this means, we're inside BeginDraw()/EndDraw() - LCDUIASSERT(NULL != m_hPrevBitmap); - RECT rc = { 0, 0, m_nWidth, m_nHeight }; - FillRect(m_hDC, &rc, (HBRUSH) GetStockObject(BLACK_BRUSH)); -} - - -//************************************************************************ -// -// CLCDGfxBase::BeginDraw -// -//************************************************************************ - -void CLCDGfxBase::BeginDraw(void) -{ - LCDUIASSERT(NULL != m_hBitmap); - LCDUIASSERT(NULL == m_hPrevBitmap); - if(NULL == m_hPrevBitmap) - { - m_hPrevBitmap = (HBITMAP) SelectObject(m_hDC, m_hBitmap); - SetTextColor(m_hDC, RGB(255, 255, 255)); - SetBkColor(m_hDC, RGB(0, 0, 0)); - } -} - - -//************************************************************************ -// -// CLCDGfxBase::EndDraw -// -//************************************************************************ - -void CLCDGfxBase::EndDraw(void) -{ - LCDUIASSERT(NULL != m_hPrevBitmap); - if(NULL != m_hPrevBitmap) - { - GdiFlush(); - m_hPrevBitmap = (HBITMAP) SelectObject(m_hDC, m_hPrevBitmap); - LCDUIASSERT(m_hPrevBitmap == m_hBitmap); - m_hPrevBitmap = NULL; - } -} - - -//************************************************************************ -// -// CLCDGfxBase::GetHDC -// -//************************************************************************ - -HDC CLCDGfxBase::GetHDC(void) -{ - LCDUIASSERT(NULL != m_hDC); - return m_hDC; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetLCDScreen -// -//************************************************************************ - -lgLcdBitmap* CLCDGfxBase::GetLCDScreen(void) -{ - LCDUIASSERT(NULL != m_pLCDScreen); - if(NULL != m_pLCDScreen) - { - // monochrome, as well as color pixels start at the same offset... - memcpy(m_pLCDScreen->bmp_mono.pixels, m_pBitmapBits, m_nWidth * m_nHeight * 4); - } - - return m_pLCDScreen; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetBitmapInfo -// -//************************************************************************ - -BITMAPINFO* CLCDGfxBase::GetBitmapInfo(void) -{ - LCDUIASSERT(NULL != m_pBitmapInfo); - return m_pBitmapInfo; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetHBITMAP -// -//************************************************************************ - -HBITMAP CLCDGfxBase::GetHBITMAP(void) -{ - LCDUIASSERT(NULL != m_hBitmap); - return m_hBitmap; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetWidth -// -//************************************************************************ - -int CLCDGfxBase::GetWidth(void) -{ - return m_nWidth; -} - - -//************************************************************************ -// -// CLCDGfxBase::GetHeight -// -//************************************************************************ - -int CLCDGfxBase::GetHeight(void) -{ - return m_nHeight; -} - - -//************************************************************************ -// -// CLCDGfxBase::CreateBitmap -// -//************************************************************************ - -HRESULT CLCDGfxBase::CreateBitmap(WORD wBitCount) -{ - int nBMISize = sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD); - m_pBitmapInfo = (BITMAPINFO *) new BYTE [nBMISize]; - if(NULL == m_pBitmapInfo) - { - LCDUITRACE(_T("CLCDGfxBase::CreateBitmap(): failed to allocate bitmap info.\n")); - Shutdown(); - return E_OUTOFMEMORY; - } - - ZeroMemory(m_pBitmapInfo, nBMISize); - m_pBitmapInfo->bmiHeader.biSize = sizeof(m_pBitmapInfo->bmiHeader); - m_pBitmapInfo->bmiHeader.biWidth = m_nWidth; - m_pBitmapInfo->bmiHeader.biHeight = -m_nHeight; - m_pBitmapInfo->bmiHeader.biPlanes = 1; - m_pBitmapInfo->bmiHeader.biBitCount = wBitCount; - m_pBitmapInfo->bmiHeader.biCompression = BI_RGB; - m_pBitmapInfo->bmiHeader.biSizeImage = - (m_nWidth * - m_nHeight * - m_pBitmapInfo->bmiHeader.biBitCount) / 8; - m_pBitmapInfo->bmiHeader.biXPelsPerMeter = 3200; - m_pBitmapInfo->bmiHeader.biYPelsPerMeter = 3200; - m_pBitmapInfo->bmiHeader.biClrUsed = 256; - m_pBitmapInfo->bmiHeader.biClrImportant = 256; - - for(int nColor = 0; nColor < 256; ++nColor) - { - m_pBitmapInfo->bmiColors[nColor].rgbRed = (BYTE)((nColor > 128) ? 255 : 0); - m_pBitmapInfo->bmiColors[nColor].rgbGreen = (BYTE)((nColor > 128) ? 255 : 0); - m_pBitmapInfo->bmiColors[nColor].rgbBlue = (BYTE)((nColor > 128) ? 255 : 0); - m_pBitmapInfo->bmiColors[nColor].rgbReserved = 0; - } - - m_hBitmap = CreateDIBSection(m_hDC, m_pBitmapInfo, DIB_RGB_COLORS, - (PVOID *) &m_pBitmapBits, NULL, 0); - if(NULL == m_hBitmap) - { - LCDUITRACE(_T("CLCDGfxBase::CreateBitmap(): failed to create bitmap.\n")); - Shutdown(); - return E_FAIL; - } - - return S_OK; -} - - -//** end of LCDGfxBase.cpp *********************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxBase.cpp +// +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDGfxBase::CLCDGfxBase +// +//************************************************************************ + +CLCDGfxBase::CLCDGfxBase(void) +: m_pLCDScreen(NULL), + m_nWidth(0), + m_nHeight(0), + m_pBitmapInfo(NULL), + m_hDC(NULL), + m_hBitmap(NULL), + m_hPrevBitmap(NULL), + m_pBitmapBits(NULL) +{ +} + + +//************************************************************************ +// +// CLCDGfxBase::~CLCDGfxBase +// +//************************************************************************ + +CLCDGfxBase::~CLCDGfxBase(void) +{ + Shutdown(); +} + + +//************************************************************************ +// +// CLCDGfxBase::Initialize +// +//************************************************************************ + +HRESULT CLCDGfxBase::Initialize(void) +{ + m_hDC = CreateCompatibleDC(NULL); + if(NULL == m_hDC) + { + LCDUITRACE(_T("CLCDGfxBase::Initialize(): failed to create compatible DC.\n")); + Shutdown(); + return E_FAIL; + } + + return S_OK; +} + + +//************************************************************************ +// +// CLCDGfxBase::Shutdown +// +//************************************************************************ + +void CLCDGfxBase::Shutdown(void) +{ + if(NULL != m_hBitmap) + { + DeleteObject(m_hBitmap); + m_hBitmap = NULL; + m_pBitmapBits = NULL; + } + + LCDUIASSERT(NULL == m_hPrevBitmap); + m_hPrevBitmap = NULL; + + if(NULL != m_pBitmapInfo) + { + delete [] m_pBitmapInfo; + m_pBitmapInfo = NULL; + } + + if(NULL != m_hDC) + { + DeleteDC(m_hDC); + m_hDC = NULL; + } + + m_nWidth = 0; + m_nHeight = 0; +} + + +//************************************************************************ +// +// CLCDGfxBase::ClearScreen +// +//************************************************************************ + +void CLCDGfxBase::ClearScreen(void) +{ + // this means, we're inside BeginDraw()/EndDraw() + LCDUIASSERT(NULL != m_hPrevBitmap); + RECT rc = { 0, 0, m_nWidth, m_nHeight }; + FillRect(m_hDC, &rc, (HBRUSH) GetStockObject(BLACK_BRUSH)); +} + + +//************************************************************************ +// +// CLCDGfxBase::BeginDraw +// +//************************************************************************ + +void CLCDGfxBase::BeginDraw(void) +{ + LCDUIASSERT(NULL != m_hBitmap); + LCDUIASSERT(NULL == m_hPrevBitmap); + if(NULL == m_hPrevBitmap) + { + m_hPrevBitmap = (HBITMAP) SelectObject(m_hDC, m_hBitmap); + SetTextColor(m_hDC, RGB(255, 255, 255)); + SetBkColor(m_hDC, RGB(0, 0, 0)); + } +} + + +//************************************************************************ +// +// CLCDGfxBase::EndDraw +// +//************************************************************************ + +void CLCDGfxBase::EndDraw(void) +{ + LCDUIASSERT(NULL != m_hPrevBitmap); + if(NULL != m_hPrevBitmap) + { + GdiFlush(); + m_hPrevBitmap = (HBITMAP) SelectObject(m_hDC, m_hPrevBitmap); + LCDUIASSERT(m_hPrevBitmap == m_hBitmap); + m_hPrevBitmap = NULL; + } +} + + +//************************************************************************ +// +// CLCDGfxBase::GetHDC +// +//************************************************************************ + +HDC CLCDGfxBase::GetHDC(void) +{ + LCDUIASSERT(NULL != m_hDC); + return m_hDC; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetLCDScreen +// +//************************************************************************ + +lgLcdBitmap* CLCDGfxBase::GetLCDScreen(void) +{ + LCDUIASSERT(NULL != m_pLCDScreen); + if(NULL != m_pLCDScreen) + { + // monochrome, as well as color pixels start at the same offset... + memcpy(m_pLCDScreen->bmp_mono.pixels, m_pBitmapBits, m_nWidth * m_nHeight * 4); + } + + return m_pLCDScreen; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetBitmapInfo +// +//************************************************************************ + +BITMAPINFO* CLCDGfxBase::GetBitmapInfo(void) +{ + LCDUIASSERT(NULL != m_pBitmapInfo); + return m_pBitmapInfo; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetHBITMAP +// +//************************************************************************ + +HBITMAP CLCDGfxBase::GetHBITMAP(void) +{ + LCDUIASSERT(NULL != m_hBitmap); + return m_hBitmap; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetWidth +// +//************************************************************************ + +int CLCDGfxBase::GetWidth(void) +{ + return m_nWidth; +} + + +//************************************************************************ +// +// CLCDGfxBase::GetHeight +// +//************************************************************************ + +int CLCDGfxBase::GetHeight(void) +{ + return m_nHeight; +} + + +//************************************************************************ +// +// CLCDGfxBase::CreateBitmap +// +//************************************************************************ + +HRESULT CLCDGfxBase::CreateBitmap(WORD wBitCount) +{ + int nBMISize = sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD); + m_pBitmapInfo = (BITMAPINFO *) new BYTE [nBMISize]; + if(NULL == m_pBitmapInfo) + { + LCDUITRACE(_T("CLCDGfxBase::CreateBitmap(): failed to allocate bitmap info.\n")); + Shutdown(); + return E_OUTOFMEMORY; + } + + ZeroMemory(m_pBitmapInfo, nBMISize); + m_pBitmapInfo->bmiHeader.biSize = sizeof(m_pBitmapInfo->bmiHeader); + m_pBitmapInfo->bmiHeader.biWidth = m_nWidth; + m_pBitmapInfo->bmiHeader.biHeight = -m_nHeight; + m_pBitmapInfo->bmiHeader.biPlanes = 1; + m_pBitmapInfo->bmiHeader.biBitCount = wBitCount; + m_pBitmapInfo->bmiHeader.biCompression = BI_RGB; + m_pBitmapInfo->bmiHeader.biSizeImage = + (m_nWidth * + m_nHeight * + m_pBitmapInfo->bmiHeader.biBitCount) / 8; + m_pBitmapInfo->bmiHeader.biXPelsPerMeter = 3200; + m_pBitmapInfo->bmiHeader.biYPelsPerMeter = 3200; + m_pBitmapInfo->bmiHeader.biClrUsed = 256; + m_pBitmapInfo->bmiHeader.biClrImportant = 256; + + for(int nColor = 0; nColor < 256; ++nColor) + { + m_pBitmapInfo->bmiColors[nColor].rgbRed = (BYTE)((nColor > 128) ? 255 : 0); + m_pBitmapInfo->bmiColors[nColor].rgbGreen = (BYTE)((nColor > 128) ? 255 : 0); + m_pBitmapInfo->bmiColors[nColor].rgbBlue = (BYTE)((nColor > 128) ? 255 : 0); + m_pBitmapInfo->bmiColors[nColor].rgbReserved = 0; + } + + m_hBitmap = CreateDIBSection(m_hDC, m_pBitmapInfo, DIB_RGB_COLORS, + (PVOID *) &m_pBitmapBits, NULL, 0); + if(NULL == m_hBitmap) + { + LCDUITRACE(_T("CLCDGfxBase::CreateBitmap(): failed to create bitmap.\n")); + Shutdown(); + return E_FAIL; + } + + return S_OK; +} + + +//** end of LCDGfxBase.cpp *********************************************** diff --git a/src/thirdparty/LCDUI/LCDGfxBase.h b/src/thirdparty/LCDUI/LCDGfxBase.h index eee95291215..826c6f7b2b6 100644 --- a/src/thirdparty/LCDUI/LCDGfxBase.h +++ b/src/thirdparty/LCDUI/LCDGfxBase.h @@ -1,95 +1,95 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxBase.h -// -// Abstract class for different display types. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDGFXBASE_H__ -#define __LCDGFXBASE_H__ - -#include - - -#if _MSC_VER >= 1400 -#define LCDUI_tcsncpy(x, y, z) _tcsncpy_s(x, _countof(x), y, z) -#define LCDUI_tcscpy(x, y) _tcscpy_s(x, _countof(x), y) -#else -#define LCDUI_tcsncpy(x, y, z) _tcsncpy(x, y, z) -#define LCDUI_tcscpy(x, y) _tcscpy(x, y) -#endif - -#ifndef LCDUITRACE - // .NET compiler uses __noop intrinsic - #if _MSC_VER > 1300 - #define LCDUITRACE __noop - #else - #define LCDUITRACE (void)0 - #endif -#endif - -#ifndef LCDUIASSERT - // .NET compiler uses __noop intrinsic - #if _MSC_VER > 1300 - #define LCDUIASSERT __noop - #else - #define LCDUIASSERT (void)0 - #endif -#endif - - -class CLCDGfxBase -{ -public: - CLCDGfxBase(void); - virtual ~CLCDGfxBase(void); - - virtual HRESULT Initialize(void); - virtual void Shutdown(void); - virtual void ClearScreen(void); - virtual void BeginDraw(void); - virtual void EndDraw(void); - - virtual HDC GetHDC(void); - virtual lgLcdBitmap *GetLCDScreen(void); - virtual BITMAPINFO *GetBitmapInfo(void); - virtual HBITMAP GetHBITMAP(void); - - virtual DWORD GetFamily(void) = 0; - - virtual int GetWidth(void); - virtual int GetHeight(void); - -protected: - HRESULT CreateBitmap(WORD wBitCount); - -protected: - lgLcdBitmap *m_pLCDScreen; - int m_nWidth; - int m_nHeight; - BITMAPINFO *m_pBitmapInfo; - HDC m_hDC; - HBITMAP m_hBitmap; - HBITMAP m_hPrevBitmap; - PBYTE m_pBitmapBits; - -}; - -#endif - -//** end of LCDGfxBase.h ************************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxBase.h +// +// Abstract class for different display types. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDGFXBASE_H__ +#define __LCDGFXBASE_H__ + +#include + + +#if _MSC_VER >= 1400 +#define LCDUI_tcsncpy(x, y, z) _tcsncpy_s(x, _countof(x), y, z) +#define LCDUI_tcscpy(x, y) _tcscpy_s(x, _countof(x), y) +#else +#define LCDUI_tcsncpy(x, y, z) _tcsncpy(x, y, z) +#define LCDUI_tcscpy(x, y) _tcscpy(x, y) +#endif + +#ifndef LCDUITRACE + // .NET compiler uses __noop intrinsic + #if _MSC_VER > 1300 + #define LCDUITRACE __noop + #else + #define LCDUITRACE (void)0 + #endif +#endif + +#ifndef LCDUIASSERT + // .NET compiler uses __noop intrinsic + #if _MSC_VER > 1300 + #define LCDUIASSERT __noop + #else + #define LCDUIASSERT (void)0 + #endif +#endif + + +class CLCDGfxBase +{ +public: + CLCDGfxBase(void); + virtual ~CLCDGfxBase(void); + + virtual HRESULT Initialize(void); + virtual void Shutdown(void); + virtual void ClearScreen(void); + virtual void BeginDraw(void); + virtual void EndDraw(void); + + virtual HDC GetHDC(void); + virtual lgLcdBitmap *GetLCDScreen(void); + virtual BITMAPINFO *GetBitmapInfo(void); + virtual HBITMAP GetHBITMAP(void); + + virtual DWORD GetFamily(void) = 0; + + virtual int GetWidth(void); + virtual int GetHeight(void); + +protected: + HRESULT CreateBitmap(WORD wBitCount); + +protected: + lgLcdBitmap *m_pLCDScreen; + int m_nWidth; + int m_nHeight; + BITMAPINFO *m_pBitmapInfo; + HDC m_hDC; + HBITMAP m_hBitmap; + HBITMAP m_hPrevBitmap; + PBYTE m_pBitmapBits; + +}; + +#endif + +//** end of LCDGfxBase.h ************************************************* diff --git a/src/thirdparty/LCDUI/LCDGfxColor.cpp b/src/thirdparty/LCDUI/LCDGfxColor.cpp index 5d9d569c63e..6b5ff1d3617 100644 --- a/src/thirdparty/LCDUI/LCDGfxColor.cpp +++ b/src/thirdparty/LCDUI/LCDGfxColor.cpp @@ -1,94 +1,94 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxColor.cpp -// -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDGfxColor::CLCDGfxColor -// -//************************************************************************ - -CLCDGfxColor::CLCDGfxColor(void) -{ - m_pLCDScreen = (lgLcdBitmap *) &m_LCDScreen; - m_pLCDScreen->hdr.Format = LGLCD_BMP_FORMAT_QVGAx32; -} - - -//************************************************************************ -// -// CLCDGfxColor::~CLCDGfxColor -// -//************************************************************************ - -CLCDGfxColor::~CLCDGfxColor(void) -{ -} - - -//************************************************************************ -// -// CLCDGfxColor::Initialize -// -//************************************************************************ - -HRESULT CLCDGfxColor::Initialize(void) -{ - //reset everything - Shutdown(); - - m_nWidth = LGLCD_QVGA_BMP_WIDTH; - m_nHeight = LGLCD_QVGA_BMP_HEIGHT; - - HRESULT hRes = CLCDGfxBase::Initialize(); - if(FAILED(hRes)) - { - return hRes; - } - - hRes = CLCDGfxBase::CreateBitmap(32); - if(FAILED(hRes)) - { - return hRes; - } - - return S_OK; -} - - -//************************************************************************ -// -// CLCDGfxColor::GetLCDScreen -// -//************************************************************************ - -lgLcdBitmap* CLCDGfxColor::GetLCDScreen(void) -{ - LCDUIASSERT(m_pLCDScreen == (lgLcdBitmap *) &m_LCDScreen); - m_LCDScreen.hdr.Format = LGLCD_BMP_FORMAT_QVGAx32; - memcpy(m_LCDScreen.pixels, m_pBitmapBits, m_nWidth * m_nHeight * 4); - return m_pLCDScreen; -} - - -//** end of LCDGfxColor.cpp ********************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxColor.cpp +// +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDGfxColor::CLCDGfxColor +// +//************************************************************************ + +CLCDGfxColor::CLCDGfxColor(void) +{ + m_pLCDScreen = (lgLcdBitmap *) &m_LCDScreen; + m_pLCDScreen->hdr.Format = LGLCD_BMP_FORMAT_QVGAx32; +} + + +//************************************************************************ +// +// CLCDGfxColor::~CLCDGfxColor +// +//************************************************************************ + +CLCDGfxColor::~CLCDGfxColor(void) +{ +} + + +//************************************************************************ +// +// CLCDGfxColor::Initialize +// +//************************************************************************ + +HRESULT CLCDGfxColor::Initialize(void) +{ + //reset everything + Shutdown(); + + m_nWidth = LGLCD_QVGA_BMP_WIDTH; + m_nHeight = LGLCD_QVGA_BMP_HEIGHT; + + HRESULT hRes = CLCDGfxBase::Initialize(); + if(FAILED(hRes)) + { + return hRes; + } + + hRes = CLCDGfxBase::CreateBitmap(32); + if(FAILED(hRes)) + { + return hRes; + } + + return S_OK; +} + + +//************************************************************************ +// +// CLCDGfxColor::GetLCDScreen +// +//************************************************************************ + +lgLcdBitmap* CLCDGfxColor::GetLCDScreen(void) +{ + LCDUIASSERT(m_pLCDScreen == (lgLcdBitmap *) &m_LCDScreen); + m_LCDScreen.hdr.Format = LGLCD_BMP_FORMAT_QVGAx32; + memcpy(m_LCDScreen.pixels, m_pBitmapBits, m_nWidth * m_nHeight * 4); + return m_pLCDScreen; +} + + +//** end of LCDGfxColor.cpp ********************************************** diff --git a/src/thirdparty/LCDUI/LCDGfxColor.h b/src/thirdparty/LCDUI/LCDGfxColor.h index ce6ed05c52a..795c60d2bd9 100644 --- a/src/thirdparty/LCDUI/LCDGfxColor.h +++ b/src/thirdparty/LCDUI/LCDGfxColor.h @@ -1,48 +1,48 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxColor.h -// -// This Gfx object handles drawing to a 320x240 color display. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDGFXCOLOR_H__ -#define __LCDGFXCOLOR_H__ - -#include "LCDGfxBase.h" - -class CLCDGfxColor : public CLCDGfxBase -{ -public: - CLCDGfxColor(void); - virtual ~CLCDGfxColor(void); - - virtual HRESULT Initialize(void); - virtual lgLcdBitmap *GetLCDScreen(void); - - virtual DWORD GetFamily(void) - { - return LGLCD_DEVICE_FAMILY_QVGA_BASIC; - } - -private: - lgLcdBitmapQVGAx32 m_LCDScreen; -}; - -#endif - -//** end of LCDGfxColor.h************************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxColor.h +// +// This Gfx object handles drawing to a 320x240 color display. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDGFXCOLOR_H__ +#define __LCDGFXCOLOR_H__ + +#include "LCDGfxBase.h" + +class CLCDGfxColor : public CLCDGfxBase +{ +public: + CLCDGfxColor(void); + virtual ~CLCDGfxColor(void); + + virtual HRESULT Initialize(void); + virtual lgLcdBitmap *GetLCDScreen(void); + + virtual DWORD GetFamily(void) + { + return LGLCD_DEVICE_FAMILY_QVGA_BASIC; + } + +private: + lgLcdBitmapQVGAx32 m_LCDScreen; +}; + +#endif + +//** end of LCDGfxColor.h************************************************* diff --git a/src/thirdparty/LCDUI/LCDGfxMono.cpp b/src/thirdparty/LCDUI/LCDGfxMono.cpp index fa421c66ae2..ed2938073dc 100644 --- a/src/thirdparty/LCDUI/LCDGfxMono.cpp +++ b/src/thirdparty/LCDUI/LCDGfxMono.cpp @@ -1,108 +1,108 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxMono.cpp -// -// This Gfx object handles drawing to a 160x43 monochrome display. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDGfxMono::CLCDGfxMono -// -//************************************************************************ - -CLCDGfxMono::CLCDGfxMono(void) -{ - m_pLCDScreen = (lgLcdBitmap *) &m_LCDScreen; - m_pLCDScreen->hdr.Format = LGLCD_BMP_FORMAT_160x43x1; -} - - -//************************************************************************ -// -// CLCDGfxMono::~CLCDGfxMono -// -//************************************************************************ - -CLCDGfxMono::~CLCDGfxMono(void) -{ -} - - -//************************************************************************ -// -// CLCDGfxMono::Initialize -// -//************************************************************************ - -HRESULT CLCDGfxMono::Initialize(void) -{ - //reset everything - Shutdown(); - - m_nWidth = LGLCD_BW_BMP_WIDTH; - m_nHeight = LGLCD_BW_BMP_HEIGHT; - - HRESULT hRes = CLCDGfxBase::Initialize(); - if(FAILED(hRes)) - { - return hRes; - } - - hRes = CLCDGfxBase::CreateBitmap(8); - if(FAILED(hRes)) - { - return hRes; - } - - return S_OK; -} - - -//************************************************************************ -// -// CLCDGfxMono::GetLCDScreen -// -//************************************************************************ - -lgLcdBitmap* CLCDGfxMono::GetLCDScreen(void) -{ - LCDUIASSERT(m_pLCDScreen == (lgLcdBitmap *) &m_LCDScreen); - m_LCDScreen.hdr.Format = LGLCD_BMP_FORMAT_160x43x1; - memcpy(m_LCDScreen.pixels, m_pBitmapBits, m_nWidth * m_nHeight); - return m_pLCDScreen; -} - - -//************************************************************************ -// -// CLCDGfxMono::ClearScreen -// -//************************************************************************ - -void CLCDGfxMono::ClearScreen(void) -{ - memset(m_pBitmapBits, 0, m_nWidth * m_nHeight); - - CLCDGfxBase::ClearScreen(); -} - -//** end of LCDGfxMono.cpp *********************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxMono.cpp +// +// This Gfx object handles drawing to a 160x43 monochrome display. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDGfxMono::CLCDGfxMono +// +//************************************************************************ + +CLCDGfxMono::CLCDGfxMono(void) +{ + m_pLCDScreen = (lgLcdBitmap *) &m_LCDScreen; + m_pLCDScreen->hdr.Format = LGLCD_BMP_FORMAT_160x43x1; +} + + +//************************************************************************ +// +// CLCDGfxMono::~CLCDGfxMono +// +//************************************************************************ + +CLCDGfxMono::~CLCDGfxMono(void) +{ +} + + +//************************************************************************ +// +// CLCDGfxMono::Initialize +// +//************************************************************************ + +HRESULT CLCDGfxMono::Initialize(void) +{ + //reset everything + Shutdown(); + + m_nWidth = LGLCD_BW_BMP_WIDTH; + m_nHeight = LGLCD_BW_BMP_HEIGHT; + + HRESULT hRes = CLCDGfxBase::Initialize(); + if(FAILED(hRes)) + { + return hRes; + } + + hRes = CLCDGfxBase::CreateBitmap(8); + if(FAILED(hRes)) + { + return hRes; + } + + return S_OK; +} + + +//************************************************************************ +// +// CLCDGfxMono::GetLCDScreen +// +//************************************************************************ + +lgLcdBitmap* CLCDGfxMono::GetLCDScreen(void) +{ + LCDUIASSERT(m_pLCDScreen == (lgLcdBitmap *) &m_LCDScreen); + m_LCDScreen.hdr.Format = LGLCD_BMP_FORMAT_160x43x1; + memcpy(m_LCDScreen.pixels, m_pBitmapBits, m_nWidth * m_nHeight); + return m_pLCDScreen; +} + + +//************************************************************************ +// +// CLCDGfxMono::ClearScreen +// +//************************************************************************ + +void CLCDGfxMono::ClearScreen(void) +{ + memset(m_pBitmapBits, 0, m_nWidth * m_nHeight); + + CLCDGfxBase::ClearScreen(); +} + +//** end of LCDGfxMono.cpp *********************************************** diff --git a/src/thirdparty/LCDUI/LCDGfxMono.h b/src/thirdparty/LCDUI/LCDGfxMono.h index e24e6d515ba..49530ea8750 100644 --- a/src/thirdparty/LCDUI/LCDGfxMono.h +++ b/src/thirdparty/LCDUI/LCDGfxMono.h @@ -1,49 +1,49 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// NOTE: This version of ColorLCDUI is pre-release and is subject to -// change. -// -// LCDGfxMono.h -// -// This Gfx object handles drawing to a 160x43 monochrome display. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDGFXMONO_H__ -#define __LCDGFXMONO_H__ - -#include "LCDGfxBase.h" - -class CLCDGfxMono : public CLCDGfxBase -{ -public: - CLCDGfxMono(void); - virtual ~CLCDGfxMono(void); - - virtual HRESULT Initialize(void); - virtual lgLcdBitmap *GetLCDScreen(void); - virtual void ClearScreen(void); - - virtual DWORD GetFamily(void) - { - return LGLCD_DEVICE_FAMILY_KEYBOARD_G15; - } - -private: - lgLcdBitmap160x43x1 m_LCDScreen; -}; - -#endif - -//** end of LCDGfxMono.h ************************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// NOTE: This version of ColorLCDUI is pre-release and is subject to +// change. +// +// LCDGfxMono.h +// +// This Gfx object handles drawing to a 160x43 monochrome display. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDGFXMONO_H__ +#define __LCDGFXMONO_H__ + +#include "LCDGfxBase.h" + +class CLCDGfxMono : public CLCDGfxBase +{ +public: + CLCDGfxMono(void); + virtual ~CLCDGfxMono(void); + + virtual HRESULT Initialize(void); + virtual lgLcdBitmap *GetLCDScreen(void); + virtual void ClearScreen(void); + + virtual DWORD GetFamily(void) + { + return LGLCD_DEVICE_FAMILY_KEYBOARD_G15; + } + +private: + lgLcdBitmap160x43x1 m_LCDScreen; +}; + +#endif + +//** end of LCDGfxMono.h ************************************************* diff --git a/src/thirdparty/LCDUI/LCDIcon.cpp b/src/thirdparty/LCDUI/LCDIcon.cpp index a5363da8e1d..65e1f955da5 100644 --- a/src/thirdparty/LCDUI/LCDIcon.cpp +++ b/src/thirdparty/LCDUI/LCDIcon.cpp @@ -1,86 +1,86 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDIcon.cpp -// -// The CLCDIcon class draws icons onto the lcd. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDIcon::CLCDIcon -// -//************************************************************************ - -CLCDIcon::CLCDIcon(void) -: m_hIcon(NULL), - m_nIconWidth(16), - m_nIconHeight(16) -{ -} - - -//************************************************************************ -// -// CLCDIcon::CLCDIcon -// -//************************************************************************ - -CLCDIcon::~CLCDIcon(void) -{ -} - - -//************************************************************************ -// -// CLCDIcon::SetIcon -// -//************************************************************************ - -void CLCDIcon::SetIcon(HICON hIcon, int nWidth /* = 16 */, int nHeight /* = 16 */) -{ - m_hIcon = hIcon; - m_nIconWidth = nWidth; - m_nIconHeight = nHeight; -} - - -//************************************************************************ -// -// CLCDIcon::OnDraw -// -//************************************************************************ - -void CLCDIcon::OnDraw(CLCDGfxBase &rGfx) -{ - if (m_hIcon) - { - int nOldBkMode = SetBkMode(rGfx.GetHDC(), TRANSPARENT); - - DrawIconEx(rGfx.GetHDC(), 0, 0, m_hIcon, - m_nIconWidth, m_nIconHeight, 0, NULL, DI_NORMAL); - if (m_bInverted) - { - RECT rBoundary = { 0, 0, m_nIconWidth, m_nIconHeight}; - InvertRect(rGfx.GetHDC(), &rBoundary); - } - SetBkMode(rGfx.GetHDC(), nOldBkMode); - } -} - - -//** end of LCDIcon.cpp ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDIcon.cpp +// +// The CLCDIcon class draws icons onto the lcd. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDIcon::CLCDIcon +// +//************************************************************************ + +CLCDIcon::CLCDIcon(void) +: m_hIcon(NULL), + m_nIconWidth(16), + m_nIconHeight(16) +{ +} + + +//************************************************************************ +// +// CLCDIcon::CLCDIcon +// +//************************************************************************ + +CLCDIcon::~CLCDIcon(void) +{ +} + + +//************************************************************************ +// +// CLCDIcon::SetIcon +// +//************************************************************************ + +void CLCDIcon::SetIcon(HICON hIcon, int nWidth /* = 16 */, int nHeight /* = 16 */) +{ + m_hIcon = hIcon; + m_nIconWidth = nWidth; + m_nIconHeight = nHeight; +} + + +//************************************************************************ +// +// CLCDIcon::OnDraw +// +//************************************************************************ + +void CLCDIcon::OnDraw(CLCDGfxBase &rGfx) +{ + if (m_hIcon) + { + int nOldBkMode = SetBkMode(rGfx.GetHDC(), TRANSPARENT); + + DrawIconEx(rGfx.GetHDC(), 0, 0, m_hIcon, + m_nIconWidth, m_nIconHeight, 0, NULL, DI_NORMAL); + if (m_bInverted) + { + RECT rBoundary = { 0, 0, m_nIconWidth, m_nIconHeight}; + InvertRect(rGfx.GetHDC(), &rBoundary); + } + SetBkMode(rGfx.GetHDC(), nOldBkMode); + } +} + + +//** end of LCDIcon.cpp ************************************************** diff --git a/src/thirdparty/LCDUI/LCDIcon.h b/src/thirdparty/LCDUI/LCDIcon.h index 1de35c39573..ad394604a98 100644 --- a/src/thirdparty/LCDUI/LCDIcon.h +++ b/src/thirdparty/LCDUI/LCDIcon.h @@ -1,50 +1,50 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDIcon.h -// -// The CLCDIcon class draws icons onto the lcd. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDICON_H_INCLUDED_ -#define _LCDICON_H_INCLUDED_ - -#include "LCDBase.h" - -class CLCDIcon : public CLCDBase -{ -public: - CLCDIcon(void); - virtual ~CLCDIcon(void); - - void SetIcon(HICON hIcon, int nWidth = 16, int nHeight = 16); - - HICON GetIcon(void) - { - return m_hIcon; - } - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - -private: - HICON m_hIcon; - int m_nIconWidth; - int m_nIconHeight; -}; - - -#endif // !_LCDICON_H_INCLUDED_ - -//** end of LCDIcon.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDIcon.h +// +// The CLCDIcon class draws icons onto the lcd. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDICON_H_INCLUDED_ +#define _LCDICON_H_INCLUDED_ + +#include "LCDBase.h" + +class CLCDIcon : public CLCDBase +{ +public: + CLCDIcon(void); + virtual ~CLCDIcon(void); + + void SetIcon(HICON hIcon, int nWidth = 16, int nHeight = 16); + + HICON GetIcon(void) + { + return m_hIcon; + } + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + +private: + HICON m_hIcon; + int m_nIconWidth; + int m_nIconHeight; +}; + + +#endif // !_LCDICON_H_INCLUDED_ + +//** end of LCDIcon.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDOutput.cpp b/src/thirdparty/LCDUI/LCDOutput.cpp index efa4b2593b8..54186973e48 100644 --- a/src/thirdparty/LCDUI/LCDOutput.cpp +++ b/src/thirdparty/LCDUI/LCDOutput.cpp @@ -1,654 +1,654 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDOutput.cpp -// -// The CLCDOutput manages the actual device and the various pages that -// are sent to that device -// -// This class is now managed by CLCDConnection. You no longer need to -// derive or instantiate this class yourself -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDOutput::CLCDOutput -// -//************************************************************************ - -CLCDOutput::CLCDOutput(void) -: m_pActivePage(NULL), - m_hDevice(LGLCD_INVALID_DEVICE), - m_bSetAsForeground(FALSE), - m_dwButtonState(0), - m_nPriority(LGLCD_PRIORITY_NORMAL), - m_pGfx(NULL) -{ - ZeroMemory(&m_OpenByTypeContext, sizeof(m_OpenByTypeContext)); -} - - -//************************************************************************ -// -// CLCDOutput::~CLCDOutput -// -//************************************************************************ - -CLCDOutput::~CLCDOutput(void) -{ - Shutdown(); -} - - -//************************************************************************ -// -// CLCDOutput::SetGfx -// -//************************************************************************ - -void CLCDOutput::SetGfx(CLCDGfxBase *gfx) -{ - m_pGfx = gfx; -} - - -//************************************************************************ -// -// CLCDOutput::Open -// -//************************************************************************ - -BOOL CLCDOutput::Open(lgLcdOpenContext & OpenContext) -{ - //Close the old device if there is one - Close(); - - DWORD res = lgLcdOpen(&OpenContext); - if (ERROR_SUCCESS != res) - { - if( res == ERROR_INVALID_PARAMETER ) - { - LCDUITRACE( _T("Open failed: invalid parameter.\n") ); - return FALSE; - } - else if( res == ERROR_ALREADY_EXISTS ) - { - LCDUITRACE( _T("Open failed: already exists.\n") ); - return FALSE; - } - return FALSE; - } - - m_hDevice = OpenContext.device; - m_dwButtonState = 0; - - // restores - SetAsForeground(m_bSetAsForeground); - - OnOpenedDevice(m_hDevice); - - return TRUE; -} - - -//************************************************************************ -// -// CLCDOutput::OpenByType -// -//************************************************************************ - -BOOL CLCDOutput::OpenByType(lgLcdOpenByTypeContext &OpenContext) -{ - //Close the old device if there is one - Close(); - - DWORD res = lgLcdOpenByType(&OpenContext); - if (ERROR_SUCCESS != res) - { - if( res == ERROR_INVALID_PARAMETER ) - { - LCDUITRACE( _T("Open failed: invalid parameter.\n") ); - return FALSE; - } - else if( res == ERROR_ALREADY_EXISTS ) - { - LCDUITRACE( _T("Open failed: already exists.\n") ); - return FALSE; - } - return FALSE; - } - - m_hDevice = OpenContext.device; - m_dwButtonState = 0; - - // restores - SetAsForeground(m_bSetAsForeground); - - m_OpenByTypeContext = OpenContext; - - OnOpenedDevice(m_hDevice); - - return TRUE; -} - - -//************************************************************************ -// -// CLCDOutput::ReOpenDeviceType -// -//************************************************************************ - -BOOL CLCDOutput::ReOpenDeviceType(void) -{ - // The device type must be active - if (!HasBeenOpenedByDeviceType()) - { - return FALSE; - } - - return OpenByType(m_OpenByTypeContext); -} - - -//************************************************************************ -// -// CLCDOutput::Close -// -//************************************************************************ - -void CLCDOutput::Close(void) -{ - if( LGLCD_INVALID_DEVICE != m_hDevice ) - { - OnClosingDevice(m_hDevice); - lgLcdClose(m_hDevice); - m_hDevice = LGLCD_INVALID_DEVICE; - } -} - - -//************************************************************************ -// -// CLCDOutput::Shutdown -// -//************************************************************************ - -void CLCDOutput::Shutdown(void) -{ - Close(); -} - - -//************************************************************************ -// -// CLCDOutput::AddPage -// -//************************************************************************ - -void CLCDOutput::AddPage(CLCDPage *pPage) -{ - pPage->Initialize(); - AddObject(pPage); -} - - -//************************************************************************ -// -// CLCDOutput::RemovePage -// -//************************************************************************ - -void CLCDOutput::RemovePage(CLCDPage *pPage) -{ - RemoveObject(pPage); -} - - -//************************************************************************ -// -// CLCDOutput::ShowPage -// -//************************************************************************ - -void CLCDOutput::ShowPage(CLCDPage *pPage, BOOL bShow) -{ - LCDUIASSERT(NULL != pPage); - - if (bShow) - { - m_pActivePage = pPage; - - OnPageShown(pPage); - } - else - { - // Expire it and update - pPage->SetExpiration(0); - OnUpdate(GetTickCount()); - } -} - - -//************************************************************************ -// -// CLCDOutput::GetShowingPage -// -//************************************************************************ - -CLCDPage* CLCDOutput::GetShowingPage(void) -{ - return m_pActivePage; -} - - -//************************************************************************ -// -// CLCDOutput::SetScreenPriority -// -//************************************************************************ - -void CLCDOutput::SetScreenPriority(DWORD priority) -{ - // Priority has changed - // If we're going into idle, send an idle frame - if (LGLCD_PRIORITY_IDLE_NO_SHOW == priority) - { - lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr, - LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW)); - } - - m_nPriority = priority; -} - - -//************************************************************************ -// -// CLCDOutput::GetScreenPriority -// -//************************************************************************ - -DWORD CLCDOutput::GetScreenPriority(void) -{ - return m_nPriority; -} - - -//************************************************************************ -// -// CLCDOutput::IsOpened -// -//************************************************************************ - -BOOL CLCDOutput::IsOpened(void) -{ - return (LGLCD_INVALID_DEVICE != m_hDevice); -} - - -//************************************************************************ -// -// CLCDOutput::SetAsForeground -// -//************************************************************************ - -HRESULT CLCDOutput::SetAsForeground(BOOL bSetAsForeground) -{ - m_bSetAsForeground = bSetAsForeground; - if (LGLCD_INVALID_DEVICE != m_hDevice) - { - DWORD dwRes = lgLcdSetAsLCDForegroundApp(m_hDevice, bSetAsForeground); - if(ERROR_SUCCESS != dwRes) - { - return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes); - } - } - return E_FAIL; -} - - -//************************************************************************ -// -// CLCDOutput::OnDraw -// -//************************************************************************ - -BOOL CLCDOutput::OnDraw(void) -{ - DWORD dwPriorityToUse = LGLCD_ASYNC_UPDATE(m_nPriority); - - if ( (NULL == m_pActivePage) || - (LGLCD_INVALID_DEVICE == m_hDevice) || - (LGLCD_PRIORITY_IDLE_NO_SHOW == dwPriorityToUse) ) - { - // don't submit the bitmap - return TRUE; - } - - // Render the active screen - m_pGfx->BeginDraw(); - m_pGfx->ClearScreen(); - m_pActivePage->OnDraw(*m_pGfx); - m_pGfx->EndDraw(); - - // Get the active bitmap - lgLcdBitmap* pBitmap = m_pGfx->GetLCDScreen(); - - // Only submit if the bitmap needs to be updated - // (If the priority or bitmap have changed) - DWORD res = ERROR_SUCCESS; - if (DoesBitmapNeedUpdate(pBitmap)) - { - res = lgLcdUpdateBitmap(m_hDevice, &pBitmap->bmp_mono.hdr, dwPriorityToUse); - HandleErrorFromAPI(res); - } - - return (LGLCD_INVALID_DEVICE != m_hDevice); -} - - -//************************************************************************ -// -// CLCDOutput::OnUpdate -// -//************************************************************************ - -void CLCDOutput::OnUpdate(DWORD dwTimestamp) -{ - if (m_pActivePage) - { - m_pActivePage->OnUpdate(dwTimestamp); - } - - // check for expiration - if (m_pActivePage && m_pActivePage->HasExpired()) - { - m_pActivePage = NULL; - //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a - // program sets priority to LGLCD_PRIORITY_BACKGROUND, that - // priority sticks. - - OnPageExpired(m_pActivePage); - - // find the next active screen - for (size_t i = 0; i < m_Objects.size(); i++) - { - CLCDPage *pPage = dynamic_cast(m_Objects[i]); - LCDUIASSERT(NULL != pPage); - - if (!pPage->HasExpired()) - { - ShowPage(pPage); - //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a - // program sets priority to LGLCD_PRIORITY_BACKGROUND, that - // priority sticks. - break; - } - } - - // if no screen found, empty the screen at idle priority - if (NULL == m_pActivePage) - { - OnEnteringIdle(); - if (LGLCD_INVALID_DEVICE != m_hDevice) - { - m_pGfx->ClearScreen(); - lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr, - LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW)); - } - } - } -} - - -//************************************************************************ -// -// CLCDOutput::GetSoftButtonState -// -//************************************************************************ - -DWORD CLCDOutput::GetSoftButtonState(void) -{ - return IsOpened() ? m_dwButtonState : 0; -} - - -//************************************************************************ -// -// CLCDOutput::HandleErrorFromAPI -// -//************************************************************************ - -HRESULT CLCDOutput::HandleErrorFromAPI(DWORD dwRes) -{ - switch(dwRes) - { - // all is well - case ERROR_SUCCESS: - case RPC_S_PROTOCOL_ERROR: - break; - // we lost our device - case ERROR_DEVICE_NOT_CONNECTED: - LCDUITRACE(_T("lgLcdAPI returned with ERROR_DEVICE_NOT_CONNECTED, closing device\n")); - Close(); - break; - default: - LCDUITRACE(_T("lgLcdAPI returned with other error (0x%08x) closing device\n")); - Close(); - // something else happened, such as LCDMon that was terminated - break; - } - - if(ERROR_SUCCESS != dwRes) - { - return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes); - } - - return S_OK; -} - - -//************************************************************************ -// -// CLCDOutput::DoesBitmapNeedUpdate -// -//************************************************************************ - -BOOL CLCDOutput::DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap) -{ - UNREFERENCED_PARAMETER(pBitmap); - // For now, always update - return TRUE; -} - - -//************************************************************************ -// -// CLCDOutput::OnPageExpired -// -//************************************************************************ - -void CLCDOutput::OnPageExpired(CLCDCollection* pScreen) -{ - UNREFERENCED_PARAMETER(pScreen); -} - - -//************************************************************************ -// -// CLCDOutput::OnPageShown -// -//************************************************************************ - -void CLCDOutput::OnPageShown(CLCDCollection* pScreen) -{ - UNREFERENCED_PARAMETER(pScreen); -} - - -//************************************************************************ -// -// CLCDOutput::OnEnteringIdle -// -//************************************************************************ - -void CLCDOutput::OnEnteringIdle(void) -{ -} - - -//************************************************************************ -// -// CLCDOutput::OnClosingDevice -// -//************************************************************************ - -void CLCDOutput::OnClosingDevice(int hDevice) -{ - UNREFERENCED_PARAMETER(hDevice); -} - - -//************************************************************************ -// -// CLCDOutput::OnOpenedDevice -// -//************************************************************************ - -void CLCDOutput::OnOpenedDevice(int hDevice) -{ - UNREFERENCED_PARAMETER(hDevice); -} - - -//************************************************************************ -// -// CLCDOutput::OnSoftButtonEvent -// -//************************************************************************ - -void CLCDOutput::OnSoftButtonEvent(DWORD dwButtonState) -{ - if (LGLCD_DEVICE_FAMILY_QVGA_BASIC == m_pGfx->GetFamily()) - { - HandleButtonState(dwButtonState, LGLCDBUTTON_LEFT); - HandleButtonState(dwButtonState, LGLCDBUTTON_RIGHT); - HandleButtonState(dwButtonState, LGLCDBUTTON_OK); - HandleButtonState(dwButtonState, LGLCDBUTTON_CANCEL); - HandleButtonState(dwButtonState, LGLCDBUTTON_UP); - HandleButtonState(dwButtonState, LGLCDBUTTON_DOWN); - HandleButtonState(dwButtonState, LGLCDBUTTON_MENU); - } - else - { - HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON0); - HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON1); - HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON2); - HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON3); - } - - m_dwButtonState = dwButtonState; -} - - -//************************************************************************ -// -// CLCDOutput::HandleButtonState -// -//************************************************************************ - -void CLCDOutput::HandleButtonState(DWORD dwButtonState, DWORD dwButton) -{ - if ( (m_dwButtonState & dwButton) && !(dwButtonState & dwButton) ) - { - LCDUITRACE(_T("Button 0x%x released\n"), dwButton); - OnLCDButtonUp(dwButton); - } - if ( !(m_dwButtonState & dwButton) && (dwButtonState & dwButton) ) - { - LCDUITRACE(_T("Button 0x%x pressed\n"), dwButton); - OnLCDButtonDown(dwButton); - } -} - - -//************************************************************************ -// -// CLCDOutput::OnLCDButtonDown -// -//************************************************************************ - -void CLCDOutput::OnLCDButtonDown(int nButton) -{ - if (m_pActivePage) - { - m_pActivePage->OnLCDButtonDown(nButton); - } -} - - -//************************************************************************ -// -// CLCDOutput::OnLCDButtonUp -// -//************************************************************************ - -void CLCDOutput::OnLCDButtonUp(int nButton) -{ - if (m_pActivePage) - { - m_pActivePage->OnLCDButtonUp(nButton); - } -} - - -//************************************************************************ -// -// CLCDOutput::GetDeviceId -// -//************************************************************************ - -int CLCDOutput::GetDeviceId(void) -{ - return m_hDevice; -} - - -//************************************************************************ -// -// CLCDOutput::StopOpeningByDeviceType -// -//************************************************************************ - -void CLCDOutput::StopOpeningByDeviceType(void) -{ - m_OpenByTypeContext.deviceType = 0; -} - - -//************************************************************************ -// -// CLCDOutput::HasBeenOpenedByDeviceType -// -//************************************************************************ - -BOOL CLCDOutput::HasBeenOpenedByDeviceType(void) -{ - return (0 != m_OpenByTypeContext.deviceType); -} - - -//** end of LCDOutput.cpp ************************************************ +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDOutput.cpp +// +// The CLCDOutput manages the actual device and the various pages that +// are sent to that device +// +// This class is now managed by CLCDConnection. You no longer need to +// derive or instantiate this class yourself +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDOutput::CLCDOutput +// +//************************************************************************ + +CLCDOutput::CLCDOutput(void) +: m_pActivePage(NULL), + m_hDevice(LGLCD_INVALID_DEVICE), + m_bSetAsForeground(FALSE), + m_dwButtonState(0), + m_nPriority(LGLCD_PRIORITY_NORMAL), + m_pGfx(NULL) +{ + ZeroMemory(&m_OpenByTypeContext, sizeof(m_OpenByTypeContext)); +} + + +//************************************************************************ +// +// CLCDOutput::~CLCDOutput +// +//************************************************************************ + +CLCDOutput::~CLCDOutput(void) +{ + Shutdown(); +} + + +//************************************************************************ +// +// CLCDOutput::SetGfx +// +//************************************************************************ + +void CLCDOutput::SetGfx(CLCDGfxBase *gfx) +{ + m_pGfx = gfx; +} + + +//************************************************************************ +// +// CLCDOutput::Open +// +//************************************************************************ + +BOOL CLCDOutput::Open(lgLcdOpenContext & OpenContext) +{ + //Close the old device if there is one + Close(); + + DWORD res = lgLcdOpen(&OpenContext); + if (ERROR_SUCCESS != res) + { + if( res == ERROR_INVALID_PARAMETER ) + { + LCDUITRACE( _T("Open failed: invalid parameter.\n") ); + return FALSE; + } + else if( res == ERROR_ALREADY_EXISTS ) + { + LCDUITRACE( _T("Open failed: already exists.\n") ); + return FALSE; + } + return FALSE; + } + + m_hDevice = OpenContext.device; + m_dwButtonState = 0; + + // restores + SetAsForeground(m_bSetAsForeground); + + OnOpenedDevice(m_hDevice); + + return TRUE; +} + + +//************************************************************************ +// +// CLCDOutput::OpenByType +// +//************************************************************************ + +BOOL CLCDOutput::OpenByType(lgLcdOpenByTypeContext &OpenContext) +{ + //Close the old device if there is one + Close(); + + DWORD res = lgLcdOpenByType(&OpenContext); + if (ERROR_SUCCESS != res) + { + if( res == ERROR_INVALID_PARAMETER ) + { + LCDUITRACE( _T("Open failed: invalid parameter.\n") ); + return FALSE; + } + else if( res == ERROR_ALREADY_EXISTS ) + { + LCDUITRACE( _T("Open failed: already exists.\n") ); + return FALSE; + } + return FALSE; + } + + m_hDevice = OpenContext.device; + m_dwButtonState = 0; + + // restores + SetAsForeground(m_bSetAsForeground); + + m_OpenByTypeContext = OpenContext; + + OnOpenedDevice(m_hDevice); + + return TRUE; +} + + +//************************************************************************ +// +// CLCDOutput::ReOpenDeviceType +// +//************************************************************************ + +BOOL CLCDOutput::ReOpenDeviceType(void) +{ + // The device type must be active + if (!HasBeenOpenedByDeviceType()) + { + return FALSE; + } + + return OpenByType(m_OpenByTypeContext); +} + + +//************************************************************************ +// +// CLCDOutput::Close +// +//************************************************************************ + +void CLCDOutput::Close(void) +{ + if( LGLCD_INVALID_DEVICE != m_hDevice ) + { + OnClosingDevice(m_hDevice); + lgLcdClose(m_hDevice); + m_hDevice = LGLCD_INVALID_DEVICE; + } +} + + +//************************************************************************ +// +// CLCDOutput::Shutdown +// +//************************************************************************ + +void CLCDOutput::Shutdown(void) +{ + Close(); +} + + +//************************************************************************ +// +// CLCDOutput::AddPage +// +//************************************************************************ + +void CLCDOutput::AddPage(CLCDPage *pPage) +{ + pPage->Initialize(); + AddObject(pPage); +} + + +//************************************************************************ +// +// CLCDOutput::RemovePage +// +//************************************************************************ + +void CLCDOutput::RemovePage(CLCDPage *pPage) +{ + RemoveObject(pPage); +} + + +//************************************************************************ +// +// CLCDOutput::ShowPage +// +//************************************************************************ + +void CLCDOutput::ShowPage(CLCDPage *pPage, BOOL bShow) +{ + LCDUIASSERT(NULL != pPage); + + if (bShow) + { + m_pActivePage = pPage; + + OnPageShown(pPage); + } + else + { + // Expire it and update + pPage->SetExpiration(0); + OnUpdate(GetTickCount()); + } +} + + +//************************************************************************ +// +// CLCDOutput::GetShowingPage +// +//************************************************************************ + +CLCDPage* CLCDOutput::GetShowingPage(void) +{ + return m_pActivePage; +} + + +//************************************************************************ +// +// CLCDOutput::SetScreenPriority +// +//************************************************************************ + +void CLCDOutput::SetScreenPriority(DWORD priority) +{ + // Priority has changed + // If we're going into idle, send an idle frame + if (LGLCD_PRIORITY_IDLE_NO_SHOW == priority) + { + lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr, + LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW)); + } + + m_nPriority = priority; +} + + +//************************************************************************ +// +// CLCDOutput::GetScreenPriority +// +//************************************************************************ + +DWORD CLCDOutput::GetScreenPriority(void) +{ + return m_nPriority; +} + + +//************************************************************************ +// +// CLCDOutput::IsOpened +// +//************************************************************************ + +BOOL CLCDOutput::IsOpened(void) +{ + return (LGLCD_INVALID_DEVICE != m_hDevice); +} + + +//************************************************************************ +// +// CLCDOutput::SetAsForeground +// +//************************************************************************ + +HRESULT CLCDOutput::SetAsForeground(BOOL bSetAsForeground) +{ + m_bSetAsForeground = bSetAsForeground; + if (LGLCD_INVALID_DEVICE != m_hDevice) + { + DWORD dwRes = lgLcdSetAsLCDForegroundApp(m_hDevice, bSetAsForeground); + if(ERROR_SUCCESS != dwRes) + { + return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes); + } + } + return E_FAIL; +} + + +//************************************************************************ +// +// CLCDOutput::OnDraw +// +//************************************************************************ + +BOOL CLCDOutput::OnDraw(void) +{ + DWORD dwPriorityToUse = LGLCD_ASYNC_UPDATE(m_nPriority); + + if ( (NULL == m_pActivePage) || + (LGLCD_INVALID_DEVICE == m_hDevice) || + (LGLCD_PRIORITY_IDLE_NO_SHOW == dwPriorityToUse) ) + { + // don't submit the bitmap + return TRUE; + } + + // Render the active screen + m_pGfx->BeginDraw(); + m_pGfx->ClearScreen(); + m_pActivePage->OnDraw(*m_pGfx); + m_pGfx->EndDraw(); + + // Get the active bitmap + lgLcdBitmap* pBitmap = m_pGfx->GetLCDScreen(); + + // Only submit if the bitmap needs to be updated + // (If the priority or bitmap have changed) + DWORD res = ERROR_SUCCESS; + if (DoesBitmapNeedUpdate(pBitmap)) + { + res = lgLcdUpdateBitmap(m_hDevice, &pBitmap->bmp_mono.hdr, dwPriorityToUse); + HandleErrorFromAPI(res); + } + + return (LGLCD_INVALID_DEVICE != m_hDevice); +} + + +//************************************************************************ +// +// CLCDOutput::OnUpdate +// +//************************************************************************ + +void CLCDOutput::OnUpdate(DWORD dwTimestamp) +{ + if (m_pActivePage) + { + m_pActivePage->OnUpdate(dwTimestamp); + } + + // check for expiration + if (m_pActivePage && m_pActivePage->HasExpired()) + { + m_pActivePage = NULL; + //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a + // program sets priority to LGLCD_PRIORITY_BACKGROUND, that + // priority sticks. + + OnPageExpired(m_pActivePage); + + // find the next active screen + for (size_t i = 0; i < m_Objects.size(); i++) + { + CLCDPage *pPage = dynamic_cast(m_Objects[i]); + LCDUIASSERT(NULL != pPage); + + if (!pPage->HasExpired()) + { + ShowPage(pPage); + //m_nPriority = LGLCD_PRIORITY_FYI; -> needs to go so that if a + // program sets priority to LGLCD_PRIORITY_BACKGROUND, that + // priority sticks. + break; + } + } + + // if no screen found, empty the screen at idle priority + if (NULL == m_pActivePage) + { + OnEnteringIdle(); + if (LGLCD_INVALID_DEVICE != m_hDevice) + { + m_pGfx->ClearScreen(); + lgLcdUpdateBitmap(m_hDevice, &m_pGfx->GetLCDScreen()->bmp_mono.hdr, + LGLCD_ASYNC_UPDATE(LGLCD_PRIORITY_IDLE_NO_SHOW)); + } + } + } +} + + +//************************************************************************ +// +// CLCDOutput::GetSoftButtonState +// +//************************************************************************ + +DWORD CLCDOutput::GetSoftButtonState(void) +{ + return IsOpened() ? m_dwButtonState : 0; +} + + +//************************************************************************ +// +// CLCDOutput::HandleErrorFromAPI +// +//************************************************************************ + +HRESULT CLCDOutput::HandleErrorFromAPI(DWORD dwRes) +{ + switch(dwRes) + { + // all is well + case ERROR_SUCCESS: + case RPC_S_PROTOCOL_ERROR: + break; + // we lost our device + case ERROR_DEVICE_NOT_CONNECTED: + LCDUITRACE(_T("lgLcdAPI returned with ERROR_DEVICE_NOT_CONNECTED, closing device\n")); + Close(); + break; + default: + LCDUITRACE(_T("lgLcdAPI returned with other error (0x%08x) closing device\n")); + Close(); + // something else happened, such as LCDMon that was terminated + break; + } + + if(ERROR_SUCCESS != dwRes) + { + return MAKE_HRESULT(SEVERITY_ERROR, 0, dwRes); + } + + return S_OK; +} + + +//************************************************************************ +// +// CLCDOutput::DoesBitmapNeedUpdate +// +//************************************************************************ + +BOOL CLCDOutput::DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap) +{ + UNREFERENCED_PARAMETER(pBitmap); + // For now, always update + return TRUE; +} + + +//************************************************************************ +// +// CLCDOutput::OnPageExpired +// +//************************************************************************ + +void CLCDOutput::OnPageExpired(CLCDCollection* pScreen) +{ + UNREFERENCED_PARAMETER(pScreen); +} + + +//************************************************************************ +// +// CLCDOutput::OnPageShown +// +//************************************************************************ + +void CLCDOutput::OnPageShown(CLCDCollection* pScreen) +{ + UNREFERENCED_PARAMETER(pScreen); +} + + +//************************************************************************ +// +// CLCDOutput::OnEnteringIdle +// +//************************************************************************ + +void CLCDOutput::OnEnteringIdle(void) +{ +} + + +//************************************************************************ +// +// CLCDOutput::OnClosingDevice +// +//************************************************************************ + +void CLCDOutput::OnClosingDevice(int hDevice) +{ + UNREFERENCED_PARAMETER(hDevice); +} + + +//************************************************************************ +// +// CLCDOutput::OnOpenedDevice +// +//************************************************************************ + +void CLCDOutput::OnOpenedDevice(int hDevice) +{ + UNREFERENCED_PARAMETER(hDevice); +} + + +//************************************************************************ +// +// CLCDOutput::OnSoftButtonEvent +// +//************************************************************************ + +void CLCDOutput::OnSoftButtonEvent(DWORD dwButtonState) +{ + if (LGLCD_DEVICE_FAMILY_QVGA_BASIC == m_pGfx->GetFamily()) + { + HandleButtonState(dwButtonState, LGLCDBUTTON_LEFT); + HandleButtonState(dwButtonState, LGLCDBUTTON_RIGHT); + HandleButtonState(dwButtonState, LGLCDBUTTON_OK); + HandleButtonState(dwButtonState, LGLCDBUTTON_CANCEL); + HandleButtonState(dwButtonState, LGLCDBUTTON_UP); + HandleButtonState(dwButtonState, LGLCDBUTTON_DOWN); + HandleButtonState(dwButtonState, LGLCDBUTTON_MENU); + } + else + { + HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON0); + HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON1); + HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON2); + HandleButtonState(dwButtonState, LGLCDBUTTON_BUTTON3); + } + + m_dwButtonState = dwButtonState; +} + + +//************************************************************************ +// +// CLCDOutput::HandleButtonState +// +//************************************************************************ + +void CLCDOutput::HandleButtonState(DWORD dwButtonState, DWORD dwButton) +{ + if ( (m_dwButtonState & dwButton) && !(dwButtonState & dwButton) ) + { + LCDUITRACE(_T("Button 0x%x released\n"), dwButton); + OnLCDButtonUp(dwButton); + } + if ( !(m_dwButtonState & dwButton) && (dwButtonState & dwButton) ) + { + LCDUITRACE(_T("Button 0x%x pressed\n"), dwButton); + OnLCDButtonDown(dwButton); + } +} + + +//************************************************************************ +// +// CLCDOutput::OnLCDButtonDown +// +//************************************************************************ + +void CLCDOutput::OnLCDButtonDown(int nButton) +{ + if (m_pActivePage) + { + m_pActivePage->OnLCDButtonDown(nButton); + } +} + + +//************************************************************************ +// +// CLCDOutput::OnLCDButtonUp +// +//************************************************************************ + +void CLCDOutput::OnLCDButtonUp(int nButton) +{ + if (m_pActivePage) + { + m_pActivePage->OnLCDButtonUp(nButton); + } +} + + +//************************************************************************ +// +// CLCDOutput::GetDeviceId +// +//************************************************************************ + +int CLCDOutput::GetDeviceId(void) +{ + return m_hDevice; +} + + +//************************************************************************ +// +// CLCDOutput::StopOpeningByDeviceType +// +//************************************************************************ + +void CLCDOutput::StopOpeningByDeviceType(void) +{ + m_OpenByTypeContext.deviceType = 0; +} + + +//************************************************************************ +// +// CLCDOutput::HasBeenOpenedByDeviceType +// +//************************************************************************ + +BOOL CLCDOutput::HasBeenOpenedByDeviceType(void) +{ + return (0 != m_OpenByTypeContext.deviceType); +} + + +//** end of LCDOutput.cpp ************************************************ diff --git a/src/thirdparty/LCDUI/LCDOutput.h b/src/thirdparty/LCDUI/LCDOutput.h index af857fb5dce..a11a2e9107a 100644 --- a/src/thirdparty/LCDUI/LCDOutput.h +++ b/src/thirdparty/LCDUI/LCDOutput.h @@ -1,107 +1,107 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDOutput.h -// -// The CLCDOutput manages the actual device and the various pages that -// are sent to that device -// -// This class is now managed by CLCDConnection. You no longer need to -// derive or instantiate this class yourself -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _CLCDOUTPUT_H_INCLUDED_ -#define _CLCDOUTPUT_H_INCLUDED_ - -#include "LCDCollection.h" -#include "LCDGfxBase.h" -#include "LCDPage.h" - - -class CLCDOutput : public CLCDCollection -{ -public: - CLCDOutput(void); - virtual ~CLCDOutput(void); - - // Assign the type of graphics this output supports. - // This is set by CLCDConnection. - void SetGfx(CLCDGfxBase *gfx); - - void AddPage(CLCDPage *pPage); - void RemovePage(CLCDPage *pPage); - void ShowPage(CLCDPage *pPage, BOOL bShow = TRUE); - CLCDPage* GetShowingPage(void); - - BOOL Open(lgLcdOpenContext &OpenContext); - BOOL OpenByType(lgLcdOpenByTypeContext &OpenContext); - void Close(void); - void Shutdown(void); - - void SetScreenPriority(DWORD priority); - DWORD GetScreenPriority(void); - - BOOL IsOpened(void); - HRESULT SetAsForeground(BOOL bSetAsForeground); - - virtual BOOL OnDraw(void); - virtual void OnUpdate(DWORD dwTimestamp ); - virtual void OnLCDButtonDown(int nButton); - virtual void OnLCDButtonUp(int nButton); - - virtual void OnSoftButtonEvent(DWORD dwButtonState); - DWORD GetSoftButtonState(void); - - // This returns true, if the device got opened through - // OpenByType(), instead of regular Open(). - BOOL HasBeenOpenedByDeviceType(void); - - // This is being called when we receive a device removal - // notification. After that, we can't reopen devices anymore - // (until the next device arrival comes in) - void StopOpeningByDeviceType(void); - - // This is called, when a device function fails. This can - // sometimes happen during plug/unplug and two same devices - // are present. - BOOL ReOpenDeviceType(void); - - int GetDeviceId(void); - -protected: - virtual BOOL DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap); - virtual void OnPageShown(CLCDCollection* pScreen); - virtual void OnPageExpired(CLCDCollection* pScreen); - virtual void OnEnteringIdle(void); - virtual void OnClosingDevice(int hDevice); - virtual void OnOpenedDevice(int hDevice); - - int m_hDevice; - CLCDPage* m_pActivePage; - DWORD m_nPriority; - CLCDGfxBase* m_pGfx; - -private: - HRESULT HandleErrorFromAPI(DWORD dwRes); - void HandleButtonState(DWORD dwButtonState, DWORD dwButton); - - BOOL m_bSetAsForeground; - DWORD m_dwButtonState; - - lgLcdOpenByTypeContext m_OpenByTypeContext; -}; - -#endif - -//** end of LCDOutput.h ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDOutput.h +// +// The CLCDOutput manages the actual device and the various pages that +// are sent to that device +// +// This class is now managed by CLCDConnection. You no longer need to +// derive or instantiate this class yourself +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _CLCDOUTPUT_H_INCLUDED_ +#define _CLCDOUTPUT_H_INCLUDED_ + +#include "LCDCollection.h" +#include "LCDGfxBase.h" +#include "LCDPage.h" + + +class CLCDOutput : public CLCDCollection +{ +public: + CLCDOutput(void); + virtual ~CLCDOutput(void); + + // Assign the type of graphics this output supports. + // This is set by CLCDConnection. + void SetGfx(CLCDGfxBase *gfx); + + void AddPage(CLCDPage *pPage); + void RemovePage(CLCDPage *pPage); + void ShowPage(CLCDPage *pPage, BOOL bShow = TRUE); + CLCDPage* GetShowingPage(void); + + BOOL Open(lgLcdOpenContext &OpenContext); + BOOL OpenByType(lgLcdOpenByTypeContext &OpenContext); + void Close(void); + void Shutdown(void); + + void SetScreenPriority(DWORD priority); + DWORD GetScreenPriority(void); + + BOOL IsOpened(void); + HRESULT SetAsForeground(BOOL bSetAsForeground); + + virtual BOOL OnDraw(void); + virtual void OnUpdate(DWORD dwTimestamp ); + virtual void OnLCDButtonDown(int nButton); + virtual void OnLCDButtonUp(int nButton); + + virtual void OnSoftButtonEvent(DWORD dwButtonState); + DWORD GetSoftButtonState(void); + + // This returns true, if the device got opened through + // OpenByType(), instead of regular Open(). + BOOL HasBeenOpenedByDeviceType(void); + + // This is being called when we receive a device removal + // notification. After that, we can't reopen devices anymore + // (until the next device arrival comes in) + void StopOpeningByDeviceType(void); + + // This is called, when a device function fails. This can + // sometimes happen during plug/unplug and two same devices + // are present. + BOOL ReOpenDeviceType(void); + + int GetDeviceId(void); + +protected: + virtual BOOL DoesBitmapNeedUpdate(lgLcdBitmap* pBitmap); + virtual void OnPageShown(CLCDCollection* pScreen); + virtual void OnPageExpired(CLCDCollection* pScreen); + virtual void OnEnteringIdle(void); + virtual void OnClosingDevice(int hDevice); + virtual void OnOpenedDevice(int hDevice); + + int m_hDevice; + CLCDPage* m_pActivePage; + DWORD m_nPriority; + CLCDGfxBase* m_pGfx; + +private: + HRESULT HandleErrorFromAPI(DWORD dwRes); + void HandleButtonState(DWORD dwButtonState, DWORD dwButton); + + BOOL m_bSetAsForeground; + DWORD m_dwButtonState; + + lgLcdOpenByTypeContext m_OpenByTypeContext; +}; + +#endif + +//** end of LCDOutput.h ************************************************** diff --git a/src/thirdparty/LCDUI/LCDPage.cpp b/src/thirdparty/LCDUI/LCDPage.cpp index 4b1da9cee9b..6e74c189044 100644 --- a/src/thirdparty/LCDUI/LCDPage.cpp +++ b/src/thirdparty/LCDUI/LCDPage.cpp @@ -1,224 +1,224 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPage.cpp -// -// Collection of items representing a page. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDPage::CLCDPage -// -//************************************************************************ - -CLCDPage::CLCDPage(void) -: m_dwStartTime(0), - m_dwEllapsedTime(0), - m_dwExpirationTime(0) -{ - SetExpiration(INFINITE); - m_bUseBitmapBackground = FALSE; - m_bUseColorBackground = FALSE; -} - - -//************************************************************************ -// -// CLCDPage::~CLCDPage -// -//************************************************************************ - -CLCDPage::~CLCDPage(void) -{ -} - - -//************************************************************************ -// -// CLCDPage::OnDraw -// -//************************************************************************ - -void CLCDPage::OnDraw(CLCDGfxBase &rGfx) -{ - if(!IsVisible()) - { - return; - } - - //Draw the background first - if(m_bUseBitmapBackground) - { - m_Background.OnDraw(rGfx); - } - else if(m_bUseColorBackground) - { - HBRUSH hBackBrush = CreateSolidBrush(m_BackgroundColor); - HBRUSH hOldBrush = (HBRUSH)SelectObject(rGfx.GetHDC(), hBackBrush); - Rectangle(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight()); - SelectObject(rGfx.GetHDC(), hOldBrush); - DeleteObject(hBackBrush); - } - - - //iterate through your objects and draw them - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it++; - LCDUIASSERT(NULL != pObject); - - if (pObject->IsVisible()) - { - // create the clip region - // Note that pages can now be added to pages (GetOrigin of the page is now factored in) - HRGN hRgn = CreateRectRgn(GetOrigin().x + pObject->GetOrigin().x, GetOrigin().y + pObject->GetOrigin().y, - GetOrigin().x + pObject->GetOrigin().x + pObject->GetWidth(), - GetOrigin().y + pObject->GetOrigin().y + pObject->GetHeight()); - - // ensure that controls only draw within their specified region - SelectClipRgn(rGfx.GetHDC(), hRgn); - - // free the region (a copy is used in the call above) - DeleteObject(hRgn); - - // offset the control at its origin so controls use (0,0) - POINT ptPrevViewportOrg = { 0, 0 }; - SetViewportOrgEx(rGfx.GetHDC(), - GetOrigin().x + pObject->GetOrigin().x, - GetOrigin().y + pObject->GetOrigin().y, - &ptPrevViewportOrg); - - // allow controls to supply additional translation - // this allows controls to move freely within the confined viewport - OffsetViewportOrgEx(rGfx.GetHDC(), - pObject->GetLogicalOrigin().x, - pObject->GetLogicalOrigin().y, - NULL); - - pObject->OnDraw(rGfx); - - // set the clipping region to nothing - SelectClipRgn(rGfx.GetHDC(), NULL); - - // restore the viewport origin - SetViewportOrgEx(rGfx.GetHDC(), - ptPrevViewportOrg.x, - ptPrevViewportOrg.y, - NULL); - - // restore the viewport origin offset - OffsetViewportOrgEx(rGfx.GetHDC(), 0, 0, NULL); - } - } -} - - -//************************************************************************ -// -// CLCDPage::OnUpdate -// -//************************************************************************ - -void CLCDPage::OnUpdate(DWORD dwTimestamp) -{ - m_dwEllapsedTime = (dwTimestamp - m_dwStartTime); - - CLCDCollection::OnUpdate(dwTimestamp); -} - - -//************************************************************************ -// -// CLCDPage::OnLCDButtonDown -// -//************************************************************************ - -void CLCDPage::OnLCDButtonDown(int nButton) -{ - UNREFERENCED_PARAMETER(nButton); -} - - -//************************************************************************ -// -// CLCDPage::OnLCDButtonUp -// -//************************************************************************ - -void CLCDPage::OnLCDButtonUp(int nButton) -{ - UNREFERENCED_PARAMETER(nButton); -} - - -//************************************************************************ -// -// CLCDPage::SetExpiration -// -//************************************************************************ - -void CLCDPage::SetExpiration(DWORD dwMilliseconds) -{ - m_dwStartTime = GetTickCount(); - m_dwEllapsedTime = 0; - m_dwExpirationTime = dwMilliseconds; -} - - -//************************************************************************ -// -// CLCDPage::HasExpired -// -//************************************************************************ - -BOOL CLCDPage::HasExpired(void) -{ - return (!m_dwStartTime || !m_dwExpirationTime || (m_dwEllapsedTime >= m_dwExpirationTime)); -} - - -//************************************************************************ -// -// CLCDPage::SetBackground (using a bitmap) -// -//************************************************************************ - -void CLCDPage::SetBackground(HBITMAP hBitmap) -{ - m_Background.SetBitmap(hBitmap); - m_Background.SetSize(320, 240); - m_bUseBitmapBackground = TRUE; - m_bUseColorBackground = FALSE; -} - - -//************************************************************************ -// -// CLCDPage::SetBackground (using a color) -// -//************************************************************************ - -void CLCDPage::SetBackground(COLORREF Color) -{ - m_BackgroundColor = Color; - m_bUseColorBackground = TRUE; - m_bUseBitmapBackground = FALSE; -} - -//** end of LCDPage.cpp ************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPage.cpp +// +// Collection of items representing a page. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDPage::CLCDPage +// +//************************************************************************ + +CLCDPage::CLCDPage(void) +: m_dwStartTime(0), + m_dwEllapsedTime(0), + m_dwExpirationTime(0) +{ + SetExpiration(INFINITE); + m_bUseBitmapBackground = FALSE; + m_bUseColorBackground = FALSE; +} + + +//************************************************************************ +// +// CLCDPage::~CLCDPage +// +//************************************************************************ + +CLCDPage::~CLCDPage(void) +{ +} + + +//************************************************************************ +// +// CLCDPage::OnDraw +// +//************************************************************************ + +void CLCDPage::OnDraw(CLCDGfxBase &rGfx) +{ + if(!IsVisible()) + { + return; + } + + //Draw the background first + if(m_bUseBitmapBackground) + { + m_Background.OnDraw(rGfx); + } + else if(m_bUseColorBackground) + { + HBRUSH hBackBrush = CreateSolidBrush(m_BackgroundColor); + HBRUSH hOldBrush = (HBRUSH)SelectObject(rGfx.GetHDC(), hBackBrush); + Rectangle(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight()); + SelectObject(rGfx.GetHDC(), hOldBrush); + DeleteObject(hBackBrush); + } + + + //iterate through your objects and draw them + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it++; + LCDUIASSERT(NULL != pObject); + + if (pObject->IsVisible()) + { + // create the clip region + // Note that pages can now be added to pages (GetOrigin of the page is now factored in) + HRGN hRgn = CreateRectRgn(GetOrigin().x + pObject->GetOrigin().x, GetOrigin().y + pObject->GetOrigin().y, + GetOrigin().x + pObject->GetOrigin().x + pObject->GetWidth(), + GetOrigin().y + pObject->GetOrigin().y + pObject->GetHeight()); + + // ensure that controls only draw within their specified region + SelectClipRgn(rGfx.GetHDC(), hRgn); + + // free the region (a copy is used in the call above) + DeleteObject(hRgn); + + // offset the control at its origin so controls use (0,0) + POINT ptPrevViewportOrg = { 0, 0 }; + SetViewportOrgEx(rGfx.GetHDC(), + GetOrigin().x + pObject->GetOrigin().x, + GetOrigin().y + pObject->GetOrigin().y, + &ptPrevViewportOrg); + + // allow controls to supply additional translation + // this allows controls to move freely within the confined viewport + OffsetViewportOrgEx(rGfx.GetHDC(), + pObject->GetLogicalOrigin().x, + pObject->GetLogicalOrigin().y, + NULL); + + pObject->OnDraw(rGfx); + + // set the clipping region to nothing + SelectClipRgn(rGfx.GetHDC(), NULL); + + // restore the viewport origin + SetViewportOrgEx(rGfx.GetHDC(), + ptPrevViewportOrg.x, + ptPrevViewportOrg.y, + NULL); + + // restore the viewport origin offset + OffsetViewportOrgEx(rGfx.GetHDC(), 0, 0, NULL); + } + } +} + + +//************************************************************************ +// +// CLCDPage::OnUpdate +// +//************************************************************************ + +void CLCDPage::OnUpdate(DWORD dwTimestamp) +{ + m_dwEllapsedTime = (dwTimestamp - m_dwStartTime); + + CLCDCollection::OnUpdate(dwTimestamp); +} + + +//************************************************************************ +// +// CLCDPage::OnLCDButtonDown +// +//************************************************************************ + +void CLCDPage::OnLCDButtonDown(int nButton) +{ + UNREFERENCED_PARAMETER(nButton); +} + + +//************************************************************************ +// +// CLCDPage::OnLCDButtonUp +// +//************************************************************************ + +void CLCDPage::OnLCDButtonUp(int nButton) +{ + UNREFERENCED_PARAMETER(nButton); +} + + +//************************************************************************ +// +// CLCDPage::SetExpiration +// +//************************************************************************ + +void CLCDPage::SetExpiration(DWORD dwMilliseconds) +{ + m_dwStartTime = GetTickCount(); + m_dwEllapsedTime = 0; + m_dwExpirationTime = dwMilliseconds; +} + + +//************************************************************************ +// +// CLCDPage::HasExpired +// +//************************************************************************ + +BOOL CLCDPage::HasExpired(void) +{ + return (!m_dwStartTime || !m_dwExpirationTime || (m_dwEllapsedTime >= m_dwExpirationTime)); +} + + +//************************************************************************ +// +// CLCDPage::SetBackground (using a bitmap) +// +//************************************************************************ + +void CLCDPage::SetBackground(HBITMAP hBitmap) +{ + m_Background.SetBitmap(hBitmap); + m_Background.SetSize(320, 240); + m_bUseBitmapBackground = TRUE; + m_bUseColorBackground = FALSE; +} + + +//************************************************************************ +// +// CLCDPage::SetBackground (using a color) +// +//************************************************************************ + +void CLCDPage::SetBackground(COLORREF Color) +{ + m_BackgroundColor = Color; + m_bUseColorBackground = TRUE; + m_bUseBitmapBackground = FALSE; +} + +//** end of LCDPage.cpp ************************************************** diff --git a/src/thirdparty/LCDUI/LCDPage.h b/src/thirdparty/LCDUI/LCDPage.h index 945394d6a31..522b52ebed2 100644 --- a/src/thirdparty/LCDUI/LCDPage.h +++ b/src/thirdparty/LCDUI/LCDPage.h @@ -1,58 +1,58 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPage.h -// -// Collection of items representing a page. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDPAGE_H_INCLUDED_ -#define _LCDPAGE_H_INCLUDED_ - -#include "LCDCollection.h" -#include "LCDBitmap.h" - -class CLCDPage : public CLCDCollection -{ -public: - CLCDPage(void); - virtual ~CLCDPage(void); - - virtual void SetExpiration(DWORD dwMilliseconds); - virtual BOOL HasExpired(void); - virtual void OnLCDButtonDown(int nButton); - virtual void OnLCDButtonUp(int nButton); - - // CLCDCollection - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void OnUpdate(DWORD dwTimestamp); - - void SetBackground(HBITMAP hBitmap); - void SetBackground(COLORREF Color); - -private: - DWORD m_dwStartTime; - DWORD m_dwEllapsedTime; - DWORD m_dwExpirationTime; - - //Background data - BOOL m_bUseBitmapBackground; - CLCDBitmap m_Background; - BOOL m_bUseColorBackground; - COLORREF m_BackgroundColor; -}; - -#endif - -//** end of LCDPage.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPage.h +// +// Collection of items representing a page. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDPAGE_H_INCLUDED_ +#define _LCDPAGE_H_INCLUDED_ + +#include "LCDCollection.h" +#include "LCDBitmap.h" + +class CLCDPage : public CLCDCollection +{ +public: + CLCDPage(void); + virtual ~CLCDPage(void); + + virtual void SetExpiration(DWORD dwMilliseconds); + virtual BOOL HasExpired(void); + virtual void OnLCDButtonDown(int nButton); + virtual void OnLCDButtonUp(int nButton); + + // CLCDCollection + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void OnUpdate(DWORD dwTimestamp); + + void SetBackground(HBITMAP hBitmap); + void SetBackground(COLORREF Color); + +private: + DWORD m_dwStartTime; + DWORD m_dwEllapsedTime; + DWORD m_dwExpirationTime; + + //Background data + BOOL m_bUseBitmapBackground; + CLCDBitmap m_Background; + BOOL m_bUseColorBackground; + COLORREF m_BackgroundColor; +}; + +#endif + +//** end of LCDPage.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDPaginateText.cpp b/src/thirdparty/LCDUI/LCDPaginateText.cpp index 1d986390196..a9ff4e9aa80 100644 --- a/src/thirdparty/LCDUI/LCDPaginateText.cpp +++ b/src/thirdparty/LCDUI/LCDPaginateText.cpp @@ -1,274 +1,274 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPaginateText.h -// -// The CLCDPaginateText class draws text onto the LCD in pages. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDPaginateText::CLCDPaginateText -// -//************************************************************************ - -CLCDPaginateText::CLCDPaginateText(void) -: m_linePerPage(0), - m_totalPageNum(0), - m_iCurPageNum(0) -{ - ZeroMemory(&m_origSize, sizeof(m_origSize)); -} - - -//************************************************************************ -// -// CLCDPaginateText::~CLCDPaginateText -// -//************************************************************************ - -CLCDPaginateText::~CLCDPaginateText(void) -{ -} - - -//************************************************************************ -// -// CLCDPaginateText::SetSize -// -//************************************************************************ - -void CLCDPaginateText::SetSize(SIZE& size) -{ - CLCDBase::SetSize(size); - m_origSize = size; - m_bRecalcExtent = true; -} - - -//************************************************************************ -// -// CLCDPaginateText::SetSize -// -//************************************************************************ - -void CLCDPaginateText::SetSize(int nCX, int nCY) -{ - CLCDBase::SetSize(nCX, nCY); - m_origSize = m_Size; - m_bRecalcExtent = true; -} - - -//************************************************************************ -// -// CLCDPaginateText::DoPaginate -// -// Force the re-pagination, will set the first page to be the current page -// -//************************************************************************ - -void CLCDPaginateText::DoPaginate(void) -{ - // if m_bRecalcExtent is false, nothing affects pagination changes, don't do anything - if(!m_bRecalcExtent) - { - return; - } - // if the page size is 0, set current page, total number of page, and line of text per page as 0 - if(m_origSize.cx == 0 || m_origSize.cy == 0) - { - m_iCurPageNum = 0; - m_totalPageNum = 0; - m_linePerPage = 0; - } - else - { - HDC hdc = CreateCompatibleDC(NULL); - - int nOldMapMode = SetMapMode(hdc, MM_TEXT); - int nOldBkMode = SetBkMode(hdc, GetBackgroundMode()); - // select current font - HFONT hOldFont = (HFONT)SelectObject(hdc, m_hFont); - - RECT rExtent; - - // calculate horizontal extent w/ single line, we can get the line height - int nTextFormat = (m_nTextFormat | DT_SINGLELINE | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = m_origSize.cx; - rExtent.bottom = m_origSize.cy; - DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeHExtent.cx = rExtent.right; - m_sizeHExtent.cy = rExtent.bottom; - - // calculate vertical extent with word wrap - nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = m_origSize.cx; - rExtent.bottom = m_origSize.cy; - DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeVExtent.cx = rExtent.right; - m_sizeVExtent.cy = rExtent.bottom; - - CLCDText::SetLogicalSize(m_sizeVExtent.cx, m_sizeVExtent.cy); - - // restores - SetMapMode(hdc, nOldMapMode); - SetBkMode(hdc, nOldBkMode); - SelectObject(hdc, hOldFont); - - DeleteDC(hdc); - - m_linePerPage = (int)(m_origSize.cy / m_sizeHExtent.cy); - // we re-set the m_Size.cy to show m_linePerPage line of text exactly (no clipping text) - m_Size.cy = m_linePerPage * m_sizeHExtent.cy; - - // if the control size is too small to fit one line of text, the m_Size.cy is set to 0, - // and we also set total number of pages to be 0 - if(m_Size.cy == 0) - { - m_iCurPageNum = 0; - m_totalPageNum = 0; - m_linePerPage = 0; - } - else - { - m_totalPageNum = (int)(m_sizeVExtent.cy / m_Size.cy); - m_totalPageNum += ((m_sizeVExtent.cy % m_Size.cy) > 0) ? 1 : 0; - - m_totalPageNum = (m_totalPageNum > 0) ? m_totalPageNum : 1; - - // after paginate, always set first page to be the current page - m_iCurPageNum = 0; - } - } - // set m_bRecalcExtent to be false to avoid another calculation at Draw time - m_bRecalcExtent = false; - SetLogicalOrigin(0, (int)((-1) * m_iCurPageNum * m_Size.cy)); -} - - -//************************************************************************ -// -// CLCDPaginateText::GetTotalPages -// -//************************************************************************ - -int CLCDPaginateText::GetTotalPages(void) -{ - DoPaginate(); - return m_totalPageNum; -} - - -//************************************************************************ -// -// CLCDPaginateText::SetCurPage -// -//************************************************************************ - -void CLCDPaginateText::SetCurPage(int iPageNum) -{ - DoPaginate(); - - if(iPageNum > m_totalPageNum - 1) - { - iPageNum = m_totalPageNum - 1; - } - if(iPageNum < 0) - { - iPageNum = 0; - } - - m_iCurPageNum = iPageNum; - - SetLogicalOrigin(0, (int)((-1) * m_iCurPageNum * m_Size.cy)); -} - - -//************************************************************************ -// -// CLCDPaginateText::GetCurPage -// -//************************************************************************ - -int CLCDPaginateText::GetCurPage(void) -{ - DoPaginate(); - return m_iCurPageNum; -} - - -//************************************************************************ -// -// CLCDPaginateText::GotoPrevPage -// -// Go to previous page, return false if it is already at the first page. -// Otherwise, return true; -// -//************************************************************************ - -bool CLCDPaginateText::GotoPrevPage(void) -{ - DoPaginate(); - if(m_iCurPageNum > 0) - { - SetCurPage(--m_iCurPageNum); - return true; - } - - return false; -} - - -//************************************************************************ -// -// CLCDPaginateText::GotoNextPage -// -// Go to next page, return false if it is already at the last page. -// Otherwise, return true; -// -//************************************************************************ - -bool CLCDPaginateText::GotoNextPage(void) -{ - DoPaginate(); - if(m_iCurPageNum < m_totalPageNum -1) - { - SetCurPage(++m_iCurPageNum); - return true; - } - - return false; -} - -//************************************************************************ -// -// CLCDPaginateText::OnDraw -// -// Before drawing, make sure we have a updated pagination -// -//************************************************************************ - -void CLCDPaginateText::OnDraw(CLCDGfxBase &rGfx) -{ - DoPaginate(); - CLCDText::OnDraw(rGfx); -} - -//** end of LCDPaginateText.cpp ****************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPaginateText.h +// +// The CLCDPaginateText class draws text onto the LCD in pages. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDPaginateText::CLCDPaginateText +// +//************************************************************************ + +CLCDPaginateText::CLCDPaginateText(void) +: m_linePerPage(0), + m_totalPageNum(0), + m_iCurPageNum(0) +{ + ZeroMemory(&m_origSize, sizeof(m_origSize)); +} + + +//************************************************************************ +// +// CLCDPaginateText::~CLCDPaginateText +// +//************************************************************************ + +CLCDPaginateText::~CLCDPaginateText(void) +{ +} + + +//************************************************************************ +// +// CLCDPaginateText::SetSize +// +//************************************************************************ + +void CLCDPaginateText::SetSize(SIZE& size) +{ + CLCDBase::SetSize(size); + m_origSize = size; + m_bRecalcExtent = true; +} + + +//************************************************************************ +// +// CLCDPaginateText::SetSize +// +//************************************************************************ + +void CLCDPaginateText::SetSize(int nCX, int nCY) +{ + CLCDBase::SetSize(nCX, nCY); + m_origSize = m_Size; + m_bRecalcExtent = true; +} + + +//************************************************************************ +// +// CLCDPaginateText::DoPaginate +// +// Force the re-pagination, will set the first page to be the current page +// +//************************************************************************ + +void CLCDPaginateText::DoPaginate(void) +{ + // if m_bRecalcExtent is false, nothing affects pagination changes, don't do anything + if(!m_bRecalcExtent) + { + return; + } + // if the page size is 0, set current page, total number of page, and line of text per page as 0 + if(m_origSize.cx == 0 || m_origSize.cy == 0) + { + m_iCurPageNum = 0; + m_totalPageNum = 0; + m_linePerPage = 0; + } + else + { + HDC hdc = CreateCompatibleDC(NULL); + + int nOldMapMode = SetMapMode(hdc, MM_TEXT); + int nOldBkMode = SetBkMode(hdc, GetBackgroundMode()); + // select current font + HFONT hOldFont = (HFONT)SelectObject(hdc, m_hFont); + + RECT rExtent; + + // calculate horizontal extent w/ single line, we can get the line height + int nTextFormat = (m_nTextFormat | DT_SINGLELINE | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = m_origSize.cx; + rExtent.bottom = m_origSize.cy; + DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeHExtent.cx = rExtent.right; + m_sizeHExtent.cy = rExtent.bottom; + + // calculate vertical extent with word wrap + nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = m_origSize.cx; + rExtent.bottom = m_origSize.cy; + DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeVExtent.cx = rExtent.right; + m_sizeVExtent.cy = rExtent.bottom; + + CLCDText::SetLogicalSize(m_sizeVExtent.cx, m_sizeVExtent.cy); + + // restores + SetMapMode(hdc, nOldMapMode); + SetBkMode(hdc, nOldBkMode); + SelectObject(hdc, hOldFont); + + DeleteDC(hdc); + + m_linePerPage = (int)(m_origSize.cy / m_sizeHExtent.cy); + // we re-set the m_Size.cy to show m_linePerPage line of text exactly (no clipping text) + m_Size.cy = m_linePerPage * m_sizeHExtent.cy; + + // if the control size is too small to fit one line of text, the m_Size.cy is set to 0, + // and we also set total number of pages to be 0 + if(m_Size.cy == 0) + { + m_iCurPageNum = 0; + m_totalPageNum = 0; + m_linePerPage = 0; + } + else + { + m_totalPageNum = (int)(m_sizeVExtent.cy / m_Size.cy); + m_totalPageNum += ((m_sizeVExtent.cy % m_Size.cy) > 0) ? 1 : 0; + + m_totalPageNum = (m_totalPageNum > 0) ? m_totalPageNum : 1; + + // after paginate, always set first page to be the current page + m_iCurPageNum = 0; + } + } + // set m_bRecalcExtent to be false to avoid another calculation at Draw time + m_bRecalcExtent = false; + SetLogicalOrigin(0, (int)((-1) * m_iCurPageNum * m_Size.cy)); +} + + +//************************************************************************ +// +// CLCDPaginateText::GetTotalPages +// +//************************************************************************ + +int CLCDPaginateText::GetTotalPages(void) +{ + DoPaginate(); + return m_totalPageNum; +} + + +//************************************************************************ +// +// CLCDPaginateText::SetCurPage +// +//************************************************************************ + +void CLCDPaginateText::SetCurPage(int iPageNum) +{ + DoPaginate(); + + if(iPageNum > m_totalPageNum - 1) + { + iPageNum = m_totalPageNum - 1; + } + if(iPageNum < 0) + { + iPageNum = 0; + } + + m_iCurPageNum = iPageNum; + + SetLogicalOrigin(0, (int)((-1) * m_iCurPageNum * m_Size.cy)); +} + + +//************************************************************************ +// +// CLCDPaginateText::GetCurPage +// +//************************************************************************ + +int CLCDPaginateText::GetCurPage(void) +{ + DoPaginate(); + return m_iCurPageNum; +} + + +//************************************************************************ +// +// CLCDPaginateText::GotoPrevPage +// +// Go to previous page, return false if it is already at the first page. +// Otherwise, return true; +// +//************************************************************************ + +bool CLCDPaginateText::GotoPrevPage(void) +{ + DoPaginate(); + if(m_iCurPageNum > 0) + { + SetCurPage(--m_iCurPageNum); + return true; + } + + return false; +} + + +//************************************************************************ +// +// CLCDPaginateText::GotoNextPage +// +// Go to next page, return false if it is already at the last page. +// Otherwise, return true; +// +//************************************************************************ + +bool CLCDPaginateText::GotoNextPage(void) +{ + DoPaginate(); + if(m_iCurPageNum < m_totalPageNum -1) + { + SetCurPage(++m_iCurPageNum); + return true; + } + + return false; +} + +//************************************************************************ +// +// CLCDPaginateText::OnDraw +// +// Before drawing, make sure we have a updated pagination +// +//************************************************************************ + +void CLCDPaginateText::OnDraw(CLCDGfxBase &rGfx) +{ + DoPaginate(); + CLCDText::OnDraw(rGfx); +} + +//** end of LCDPaginateText.cpp ****************************************** diff --git a/src/thirdparty/LCDUI/LCDPaginateText.h b/src/thirdparty/LCDUI/LCDPaginateText.h index ddea114e10d..e9fda5e49cb 100644 --- a/src/thirdparty/LCDUI/LCDPaginateText.h +++ b/src/thirdparty/LCDUI/LCDPaginateText.h @@ -1,63 +1,63 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPaginateText.h -// -// The CLCDPaginateText class draws text onto the LCD in pages. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDPAGINATETEXT_H_INCLUDED_ -#define _LCDPAGINATETEXT_H_INCLUDED_ - -#include "LCDText.h" - -class CLCDPaginateText: public CLCDText -{ - -public: - CLCDPaginateText(void); - virtual ~CLCDPaginateText(void); - - // CLCDText - virtual void SetSize(SIZE& size); - virtual void SetSize(int nCX, int nCY); - virtual void OnDraw(CLCDGfxBase &rGfx); - - // force the re-pagination, will set the first page to be the current page - void DoPaginate(void); - int GetTotalPages(void); - int GetCurPage(void); - void SetCurPage(int iPageNum); - // go to previous page, return false if it is already at the first page. Otherwise, return true; - bool GotoPrevPage(void); - // go to next page, return false if it is already at the last page. Otherwise, return true; - bool GotoNextPage(void); - -private: - // this is the original size for the control. As we try to squeeze text into - // the rectangle, we squeeze the m_Size to show unclipped text. but if the - // user change settings where a recalc is needed to figure out the total page, - // we need the original size for that calculation - SIZE m_origSize; - - // using the current setting, number of lines fit to one page (w/o clipping) - int m_linePerPage; - int m_totalPageNum; - int m_iCurPageNum; -}; - - -#endif // !_LCDPAGINATETEXT_H_INCLUDED_ - -//** end of LCDPaginateText.h ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPaginateText.h +// +// The CLCDPaginateText class draws text onto the LCD in pages. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDPAGINATETEXT_H_INCLUDED_ +#define _LCDPAGINATETEXT_H_INCLUDED_ + +#include "LCDText.h" + +class CLCDPaginateText: public CLCDText +{ + +public: + CLCDPaginateText(void); + virtual ~CLCDPaginateText(void); + + // CLCDText + virtual void SetSize(SIZE& size); + virtual void SetSize(int nCX, int nCY); + virtual void OnDraw(CLCDGfxBase &rGfx); + + // force the re-pagination, will set the first page to be the current page + void DoPaginate(void); + int GetTotalPages(void); + int GetCurPage(void); + void SetCurPage(int iPageNum); + // go to previous page, return false if it is already at the first page. Otherwise, return true; + bool GotoPrevPage(void); + // go to next page, return false if it is already at the last page. Otherwise, return true; + bool GotoNextPage(void); + +private: + // this is the original size for the control. As we try to squeeze text into + // the rectangle, we squeeze the m_Size to show unclipped text. but if the + // user change settings where a recalc is needed to figure out the total page, + // we need the original size for that calculation + SIZE m_origSize; + + // using the current setting, number of lines fit to one page (w/o clipping) + int m_linePerPage; + int m_totalPageNum; + int m_iCurPageNum; +}; + + +#endif // !_LCDPAGINATETEXT_H_INCLUDED_ + +//** end of LCDPaginateText.h ******************************************* diff --git a/src/thirdparty/LCDUI/LCDPopup.cpp b/src/thirdparty/LCDUI/LCDPopup.cpp index e31cae2bc4c..23d89871060 100644 --- a/src/thirdparty/LCDUI/LCDPopup.cpp +++ b/src/thirdparty/LCDUI/LCDPopup.cpp @@ -1,556 +1,556 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPopup.cpp -// -// Color LCD Popup class -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" -#include "LCDPopup.h" - -// This uses GDI+ -using namespace Gdiplus; - - -//************************************************************************ -// -// CLCDPopupBackground::CLCDPopupBackground -// -//************************************************************************ - -CLCDPopupBackground::CLCDPopupBackground(void) -{ - m_bUseGradient = FALSE; - m_cAlphaStart = 0x9f; - m_cAlphaEnd = m_cAlphaStart/2; - m_cfColor = 0; - m_nRectRadius = 15; - m_pGraphicsPath = NULL; -} - - -//************************************************************************ -// -// CLCDPopupBackground::~CLCDPopupBackground -// -//************************************************************************ - -CLCDPopupBackground::~CLCDPopupBackground(void) -{ - if (m_pGraphicsPath) - { - delete m_pGraphicsPath; - m_pGraphicsPath = NULL; - } -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetSize -// -//************************************************************************ - -void CLCDPopupBackground::SetSize(int nCX, int nCY) -{ - CLCDBase::SetSize(nCX, nCY); - RecalcRoundedRectangle(); -} - - -//************************************************************************ -// -// CLCDPopupBackground::OnDraw -// -//************************************************************************ - -void CLCDPopupBackground::OnDraw(CLCDGfxBase &rGfx) -{ - if (NULL == m_pGraphicsPath) - { - // Size has not been set - return; - } - - // Draw to the extent of the control - Rect r(0, 0, GetWidth(), GetHeight()); - - Graphics gfx(rGfx.GetHDC()); - - if (m_bUseGradient) - { - LinearGradientBrush brush( - r, - Color(Color::MakeARGB(m_cAlphaStart, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))), - Color(Color::MakeARGB(m_cAlphaEnd, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))), - LinearGradientModeVertical - ); // blue - gfx.FillPath(&brush, m_pGraphicsPath); - } - else - { - SolidBrush brush(Color::MakeARGB(m_cAlphaStart, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))); - gfx.FillPath(&brush, m_pGraphicsPath); - } -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetAlphaLevel -// -//************************************************************************ - -void CLCDPopupBackground::SetAlphaLevel(BYTE cAlphaStart, BYTE cAlphaEnd) -{ - m_cAlphaStart = cAlphaStart; - m_cAlphaEnd = cAlphaEnd; -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetGradientMode -// -//************************************************************************ - -void CLCDPopupBackground::SetGradientMode(BOOL bGradient) -{ - m_bUseGradient = bGradient; -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetColor -// -//************************************************************************ - -void CLCDPopupBackground::SetColor(COLORREF cfColor) -{ - m_cfColor = cfColor; -} - - -//************************************************************************ -// -// CLCDPopupBackground::SetRoundedRecteRadius -// -//************************************************************************ - -void CLCDPopupBackground::SetRoundedRecteRadius(int nRadius) -{ - m_nRectRadius = nRadius; - RecalcRoundedRectangle(); -} - - -//************************************************************************ -// -// CLCDPopupBackground::RecalcRoundedRectangle -// -//************************************************************************ - -void CLCDPopupBackground::RecalcRoundedRectangle(void) -{ - if (m_pGraphicsPath) - { - delete m_pGraphicsPath; - m_pGraphicsPath = NULL; - } - - m_pGraphicsPath = new GraphicsPath(); - int l = 0; - int t = 0; - int w = GetWidth(); - int h = GetHeight(); - int d = m_nRectRadius << 1; - m_pGraphicsPath->AddArc(l, t, d, d, 180, 90); - m_pGraphicsPath->AddLine(l + m_nRectRadius, t, l + w - m_nRectRadius, t); - m_pGraphicsPath->AddArc(l + w - d, t, d, d, 270, 90); - m_pGraphicsPath->AddLine(l + w, t + m_nRectRadius, l + w, t + h - m_nRectRadius); - m_pGraphicsPath->AddArc(l + w - d, t + h - d, d, d, 0, 90); - m_pGraphicsPath->AddLine(l + w - m_nRectRadius, t + h, l + m_nRectRadius, t + h); - m_pGraphicsPath->AddArc(l, t + h - d, d, d, 90, 90); - m_pGraphicsPath->AddLine(l, t + h - m_nRectRadius, l, t + m_nRectRadius); - m_pGraphicsPath->CloseFigure(); -} - - - - - - -// Define the maximum popup width as 1/2 of the QVGA width -#define MAX_POPUP_WIDTH (LGLCD_QVGA_BMP_WIDTH / 2) -#define POPUP_MARGIN (12) -#define POPUP_FONT_PT (12) -#define POPUP_FONT_WT FW_BOLD -#define POPUP_FONT_FACE _T("Arial") - -//************************************************************************ -// -// CLCDPopup::CLCDPopup -// -//************************************************************************ - -CLCDPopup::CLCDPopup(void) -{ - m_nMaxPopupWidth = MAX_POPUP_WIDTH; - m_pbType = PB_TEXT; -} - - -//************************************************************************ -// -// CLCDPopup::Initialize -// -//************************************************************************ - -HRESULT CLCDPopup::Initialize(int nMaxPopupWidth /* = 0 */) -{ - if(0 == nMaxPopupWidth) - { - m_nMaxPopupWidth = MAX_POPUP_WIDTH; - } - else - { - m_nMaxPopupWidth = nMaxPopupWidth; - } - // The text gets offset by the margin - m_Background.Initialize(); - m_Background.SetOrigin(0, 0); - - m_MessageText.SetOrigin(POPUP_MARGIN, POPUP_MARGIN); - m_MessageText.SetFontFaceName(POPUP_FONT_FACE); - m_MessageText.SetFontPointSize(POPUP_FONT_PT); - m_MessageText.SetFontWeight(POPUP_FONT_WT); - m_MessageText.SetWordWrap(TRUE); - m_MessageText.SetSize(LGLCD_QVGA_BMP_WIDTH, LGLCD_QVGA_BMP_HEIGHT); - - m_OKText.SetFontFaceName(_T("Arial")); - m_OKText.SetFontPointSize(10); - m_OKText.SetFontWeight(FW_NORMAL); - m_OKText.SetWordWrap(TRUE); - m_OKText.Show(FALSE); - - m_CancelText.SetFontFaceName(_T("Arial")); - m_CancelText.SetFontPointSize(10); - m_CancelText.SetFontWeight(FW_NORMAL); - m_CancelText.SetWordWrap(TRUE); - m_CancelText.Show(FALSE); - - AddObject(&m_Background); - AddObject(&m_MessageText); - AddObject(&m_OKBitmap); - AddObject(&m_CancelBitmap); - AddObject(&m_OKText); - AddObject(&m_CancelText); - - return CLCDBase::Initialize(); -} - - -//************************************************************************ -// -// CLCDPopup::SetPopupType -// -//************************************************************************ - -void CLCDPopup::SetPopupType(PB_TYPE pbType) -{ - m_pbType = pbType; - RecalcLayout(); -} - - -//************************************************************************ -// -// CLCDPopup::SetText -// -//************************************************************************ - -void CLCDPopup::SetText(LPCTSTR szMessage, LPCTSTR szOK, LPCTSTR szCancel) -{ - if (NULL != szMessage) - { - m_MessageText.SetText(szMessage); - } - if (NULL != szOK) - { - m_OKText.SetText(szOK); - } - if (NULL != szCancel) - { - m_CancelText.SetText(szCancel); - } - - RecalcLayout(); -} - - -//************************************************************************ -// -// CLCDPopup::SetSize -// -//************************************************************************ - -void CLCDPopup::SetSize(int nCX, int nCY) -{ - CLCDPage::SetSize(nCX, nCY); -} - - -//************************************************************************ -// -// CLCDPopup::RecalcLayout -// -//************************************************************************ - -void CLCDPopup::RecalcLayout(void) -{ - // First get the size of the text - // If the width > MAX_WIDTH, snap it to the max width - int nTextWidthWithMargin = 2 * POPUP_MARGIN; - int nTextHeightWithMargin = 2 * POPUP_MARGIN; - if(0 < _tcslen(m_MessageText.GetText())) - { - m_MessageText.CalculateExtent(FALSE); - nTextWidthWithMargin = m_MessageText.GetVExtent().cx + 2*POPUP_MARGIN; - nTextHeightWithMargin = m_MessageText.GetVExtent().cy + 2*POPUP_MARGIN; - if(nTextWidthWithMargin > m_nMaxPopupWidth) - { - // Resize the text using a max height - m_MessageText.SetSize(m_nMaxPopupWidth, LGLCD_QVGA_BMP_HEIGHT); - m_MessageText.CalculateExtent(FALSE); - nTextWidthWithMargin = m_MessageText.GetVExtent().cx + 2*POPUP_MARGIN; - nTextHeightWithMargin = m_MessageText.GetVExtent().cy + 2*POPUP_MARGIN; - } - m_MessageText.SetSize(m_MessageText.GetVExtent().cx, m_MessageText.GetVExtent().cy); - } - else - { - nTextHeightWithMargin = POPUP_MARGIN; - nTextWidthWithMargin = 0; - m_MessageText.SetSize(0, 0); - } - - // Determine the size of the popup including.. - // Margin - // Text - // OK Bitmap - // Cancel Bitmap - int nPopupWidth = nTextWidthWithMargin; - int nPopupHeight = nTextHeightWithMargin; - - // Bitmap operations - BITMAP bmOK, bmCancel; - memset(&bmOK, 0, sizeof(bmOK)); - memset(&bmCancel, 0, sizeof(bmCancel)); - - if (NULL != m_OKBitmap.GetBitmap()) - { - GetObject( m_OKBitmap.GetBitmap(), sizeof(BITMAP), &bmOK); - m_OKBitmap.SetSize(bmOK.bmWidth, bmOK.bmHeight); - } - if (NULL != m_CancelBitmap.GetBitmap()) - { - GetObject( m_CancelBitmap.GetBitmap(), sizeof(BITMAP), &bmCancel); - m_CancelBitmap.SetSize(bmCancel.bmWidth, bmCancel.bmHeight); - } - - switch(m_pbType) - { - // Main text block only - case PB_TEXT: - m_OKBitmap.Show(FALSE); - m_CancelBitmap.Show(FALSE); - break; - - // OK is centered against the main text block - case PB_OK: - if (bmOK.bmWidth) - { - // Just factor in a bitmap - // Add the bitmap w/ margin on the bottom - nPopupHeight += bmOK.bmHeight; - nPopupHeight += POPUP_MARGIN; - - // Position the bitmap centered, and vertically after the text+margin - m_OKBitmap.SetOrigin((nPopupWidth-bmOK.bmWidth)/2, nTextHeightWithMargin); - - m_OKBitmap.Show(TRUE); - } - break; - - // OK, Cancel Buttons are aligned on the same row below the text block (like a dialog) - case PB_OKCANCEL: - if (bmOK.bmWidth && bmCancel.bmWidth) - { - // Add the bitmap w/ margin on the bottom - nPopupHeight += bmOK.bmHeight; - nPopupHeight += POPUP_MARGIN; - - // OK is right-aligned with the text - m_OKBitmap.SetOrigin(m_MessageText.GetOrigin().x + m_MessageText.GetSize().cx - bmOK.bmWidth, - nTextHeightWithMargin); - // Cancel is right-aligned with OK (with margin) - m_CancelBitmap.SetOrigin(m_OKBitmap.GetOrigin().x - bmCancel.bmWidth - POPUP_MARGIN, - nTextHeightWithMargin); - - m_OKBitmap.Show(TRUE); - m_CancelBitmap.Show(TRUE); - } - break; - - // OK, Cancel Buttons are on separate rows centered against their own text blocks - case PB_OKCANCEL_TEXT: - { - int nOKTextWithBitmapHeight = 0; - int nMaxOKTextWidth = 0; - m_OKText.SetOrigin(POPUP_MARGIN, nTextHeightWithMargin - POPUP_MARGIN); - - if (bmOK.bmWidth) - { - // OK is left-aligned with the text - m_OKBitmap.SetOrigin(m_MessageText.GetOrigin().x, nTextHeightWithMargin); - - // OK text height is left-aligned with OK bmp and right-aligned with text - // OK bmp is vertically centered against the OK text - nMaxOKTextWidth = m_MessageText.GetWidth() - bmOK.bmWidth - POPUP_MARGIN; - if (nMaxOKTextWidth < 0) - { - nMaxOKTextWidth = LGLCD_QVGA_BMP_WIDTH; - } - m_OKText.SetOrigin(m_OKBitmap.GetOrigin().x + bmOK.bmWidth + POPUP_MARGIN, nTextHeightWithMargin); - m_OKText.SetSize(nMaxOKTextWidth, LGLCD_QVGA_BMP_HEIGHT); - m_OKText.CalculateExtent(FALSE); - m_OKText.SetSize(m_OKText.GetVExtent().cx, m_OKText.GetVExtent().cy); - - // if no main text, figure out required max popup width - int nCalcPopupWidth = POPUP_MARGIN*3 + bmOK.bmWidth + m_OKText.GetSize().cx; - if (nCalcPopupWidth > nPopupWidth) - { - nPopupWidth = nCalcPopupWidth; - } - - // Add the bitmap w/ margin on the bottom - nOKTextWithBitmapHeight = max(bmOK.bmHeight, m_OKText.GetHeight()); - nPopupHeight += nOKTextWithBitmapHeight; - nPopupHeight += POPUP_MARGIN; - - m_OKText.Show(TRUE); - m_OKBitmap.Show(TRUE); - m_OKBitmap.SetOrigin(m_OKBitmap.GetOrigin().x, m_OKText.GetOrigin().y + (m_OKText.GetHeight() - bmOK.bmHeight)/2); - } - - if (bmCancel.bmWidth) - { - // Cancel is left-aligned with the text - m_CancelBitmap.SetOrigin(m_MessageText.GetOrigin().x, m_OKText.GetOrigin().y + nOKTextWithBitmapHeight + POPUP_MARGIN); - - int nMaxCancelTextWidth = m_MessageText.GetWidth() - bmCancel.bmWidth - POPUP_MARGIN; - if (nMaxCancelTextWidth < 0) - { - nMaxCancelTextWidth = LGLCD_QVGA_BMP_WIDTH; - } - m_CancelText.SetOrigin(m_CancelBitmap.GetOrigin().x + bmCancel.bmWidth + POPUP_MARGIN, m_CancelBitmap.GetOrigin().y); - m_CancelText.SetSize(nMaxCancelTextWidth, LGLCD_QVGA_BMP_HEIGHT); - m_CancelText.CalculateExtent(FALSE); - m_CancelText.SetSize(m_CancelText.GetVExtent().cx, m_CancelText.GetVExtent().cy); - - // if no main text, make the - int nCalcPopupWidth = POPUP_MARGIN*3 + bmOK.bmWidth + m_CancelText.GetSize().cx; - if (nCalcPopupWidth > nPopupWidth) - { - nPopupWidth = nCalcPopupWidth; - } - - nPopupHeight += max(bmCancel.bmHeight, m_CancelText.GetHeight()); - nPopupHeight += POPUP_MARGIN; - - // Vertically center the OK and CANCEL bitmaps against their respective texts - m_CancelText.Show(TRUE); - m_CancelBitmap.Show(TRUE); - m_CancelBitmap.SetOrigin(m_CancelBitmap.GetOrigin().x, m_CancelText.GetOrigin().y + (m_CancelText.GetHeight() - bmCancel.bmHeight)/2); - } - } - - break; - } - - // Resize ourself - SetSize(nPopupWidth, nPopupHeight); - - // Center the popup in the middle of the screen - SetOrigin( (LGLCD_QVGA_BMP_WIDTH - nPopupWidth)/2, (LGLCD_QVGA_BMP_HEIGHT - nPopupHeight)/2); - - // Resize the background - m_Background.SetSize(GetWidth(), GetHeight()); -} - - -//************************************************************************ -// -// CLCDPopup::SetBitmaps -// -//************************************************************************ - -void CLCDPopup::SetBitmaps(HBITMAP hbmOK, HBITMAP hbmCancel) -{ - m_OKBitmap.SetBitmap(hbmOK); - m_CancelBitmap.SetBitmap(hbmCancel); - - RecalcLayout(); -} - - -//************************************************************************ -// -// CLCDPopup::SetAlpha -// -//************************************************************************ - -void CLCDPopup::SetAlpha(BYTE bAlphaStart, BYTE bAlphaEnd) -{ - m_Background.SetAlphaLevel(bAlphaStart, bAlphaEnd); -} - - -//************************************************************************ -// -// CLCDPopup::SetGradientMode -// -//************************************************************************ - -void CLCDPopup::SetGradientMode(BOOL bGradient) -{ - m_Background.SetGradientMode(bGradient); -} - - -//************************************************************************ -// -// CLCDPopup::SetColor -// -//************************************************************************ - -void CLCDPopup::SetColor(COLORREF cfColor) -{ - m_Background.SetColor(cfColor); -} - - -//** end of LCDPopup.cpp ************************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPopup.cpp +// +// Color LCD Popup class +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" +#include "LCDPopup.h" + +// This uses GDI+ +using namespace Gdiplus; + + +//************************************************************************ +// +// CLCDPopupBackground::CLCDPopupBackground +// +//************************************************************************ + +CLCDPopupBackground::CLCDPopupBackground(void) +{ + m_bUseGradient = FALSE; + m_cAlphaStart = 0x9f; + m_cAlphaEnd = m_cAlphaStart/2; + m_cfColor = 0; + m_nRectRadius = 15; + m_pGraphicsPath = NULL; +} + + +//************************************************************************ +// +// CLCDPopupBackground::~CLCDPopupBackground +// +//************************************************************************ + +CLCDPopupBackground::~CLCDPopupBackground(void) +{ + if (m_pGraphicsPath) + { + delete m_pGraphicsPath; + m_pGraphicsPath = NULL; + } +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetSize +// +//************************************************************************ + +void CLCDPopupBackground::SetSize(int nCX, int nCY) +{ + CLCDBase::SetSize(nCX, nCY); + RecalcRoundedRectangle(); +} + + +//************************************************************************ +// +// CLCDPopupBackground::OnDraw +// +//************************************************************************ + +void CLCDPopupBackground::OnDraw(CLCDGfxBase &rGfx) +{ + if (NULL == m_pGraphicsPath) + { + // Size has not been set + return; + } + + // Draw to the extent of the control + Rect r(0, 0, GetWidth(), GetHeight()); + + Graphics gfx(rGfx.GetHDC()); + + if (m_bUseGradient) + { + LinearGradientBrush brush( + r, + Color(Color::MakeARGB(m_cAlphaStart, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))), + Color(Color::MakeARGB(m_cAlphaEnd, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))), + LinearGradientModeVertical + ); // blue + gfx.FillPath(&brush, m_pGraphicsPath); + } + else + { + SolidBrush brush(Color::MakeARGB(m_cAlphaStart, GetRValue(m_cfColor), GetGValue(m_cfColor), GetBValue(m_cfColor))); + gfx.FillPath(&brush, m_pGraphicsPath); + } +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetAlphaLevel +// +//************************************************************************ + +void CLCDPopupBackground::SetAlphaLevel(BYTE cAlphaStart, BYTE cAlphaEnd) +{ + m_cAlphaStart = cAlphaStart; + m_cAlphaEnd = cAlphaEnd; +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetGradientMode +// +//************************************************************************ + +void CLCDPopupBackground::SetGradientMode(BOOL bGradient) +{ + m_bUseGradient = bGradient; +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetColor +// +//************************************************************************ + +void CLCDPopupBackground::SetColor(COLORREF cfColor) +{ + m_cfColor = cfColor; +} + + +//************************************************************************ +// +// CLCDPopupBackground::SetRoundedRecteRadius +// +//************************************************************************ + +void CLCDPopupBackground::SetRoundedRecteRadius(int nRadius) +{ + m_nRectRadius = nRadius; + RecalcRoundedRectangle(); +} + + +//************************************************************************ +// +// CLCDPopupBackground::RecalcRoundedRectangle +// +//************************************************************************ + +void CLCDPopupBackground::RecalcRoundedRectangle(void) +{ + if (m_pGraphicsPath) + { + delete m_pGraphicsPath; + m_pGraphicsPath = NULL; + } + + m_pGraphicsPath = new GraphicsPath(); + int l = 0; + int t = 0; + int w = GetWidth(); + int h = GetHeight(); + int d = m_nRectRadius << 1; + m_pGraphicsPath->AddArc(l, t, d, d, 180, 90); + m_pGraphicsPath->AddLine(l + m_nRectRadius, t, l + w - m_nRectRadius, t); + m_pGraphicsPath->AddArc(l + w - d, t, d, d, 270, 90); + m_pGraphicsPath->AddLine(l + w, t + m_nRectRadius, l + w, t + h - m_nRectRadius); + m_pGraphicsPath->AddArc(l + w - d, t + h - d, d, d, 0, 90); + m_pGraphicsPath->AddLine(l + w - m_nRectRadius, t + h, l + m_nRectRadius, t + h); + m_pGraphicsPath->AddArc(l, t + h - d, d, d, 90, 90); + m_pGraphicsPath->AddLine(l, t + h - m_nRectRadius, l, t + m_nRectRadius); + m_pGraphicsPath->CloseFigure(); +} + + + + + + +// Define the maximum popup width as 1/2 of the QVGA width +#define MAX_POPUP_WIDTH (LGLCD_QVGA_BMP_WIDTH / 2) +#define POPUP_MARGIN (12) +#define POPUP_FONT_PT (12) +#define POPUP_FONT_WT FW_BOLD +#define POPUP_FONT_FACE _T("Arial") + +//************************************************************************ +// +// CLCDPopup::CLCDPopup +// +//************************************************************************ + +CLCDPopup::CLCDPopup(void) +{ + m_nMaxPopupWidth = MAX_POPUP_WIDTH; + m_pbType = PB_TEXT; +} + + +//************************************************************************ +// +// CLCDPopup::Initialize +// +//************************************************************************ + +HRESULT CLCDPopup::Initialize(int nMaxPopupWidth /* = 0 */) +{ + if(0 == nMaxPopupWidth) + { + m_nMaxPopupWidth = MAX_POPUP_WIDTH; + } + else + { + m_nMaxPopupWidth = nMaxPopupWidth; + } + // The text gets offset by the margin + m_Background.Initialize(); + m_Background.SetOrigin(0, 0); + + m_MessageText.SetOrigin(POPUP_MARGIN, POPUP_MARGIN); + m_MessageText.SetFontFaceName(POPUP_FONT_FACE); + m_MessageText.SetFontPointSize(POPUP_FONT_PT); + m_MessageText.SetFontWeight(POPUP_FONT_WT); + m_MessageText.SetWordWrap(TRUE); + m_MessageText.SetSize(LGLCD_QVGA_BMP_WIDTH, LGLCD_QVGA_BMP_HEIGHT); + + m_OKText.SetFontFaceName(_T("Arial")); + m_OKText.SetFontPointSize(10); + m_OKText.SetFontWeight(FW_NORMAL); + m_OKText.SetWordWrap(TRUE); + m_OKText.Show(FALSE); + + m_CancelText.SetFontFaceName(_T("Arial")); + m_CancelText.SetFontPointSize(10); + m_CancelText.SetFontWeight(FW_NORMAL); + m_CancelText.SetWordWrap(TRUE); + m_CancelText.Show(FALSE); + + AddObject(&m_Background); + AddObject(&m_MessageText); + AddObject(&m_OKBitmap); + AddObject(&m_CancelBitmap); + AddObject(&m_OKText); + AddObject(&m_CancelText); + + return CLCDBase::Initialize(); +} + + +//************************************************************************ +// +// CLCDPopup::SetPopupType +// +//************************************************************************ + +void CLCDPopup::SetPopupType(PB_TYPE pbType) +{ + m_pbType = pbType; + RecalcLayout(); +} + + +//************************************************************************ +// +// CLCDPopup::SetText +// +//************************************************************************ + +void CLCDPopup::SetText(LPCTSTR szMessage, LPCTSTR szOK, LPCTSTR szCancel) +{ + if (NULL != szMessage) + { + m_MessageText.SetText(szMessage); + } + if (NULL != szOK) + { + m_OKText.SetText(szOK); + } + if (NULL != szCancel) + { + m_CancelText.SetText(szCancel); + } + + RecalcLayout(); +} + + +//************************************************************************ +// +// CLCDPopup::SetSize +// +//************************************************************************ + +void CLCDPopup::SetSize(int nCX, int nCY) +{ + CLCDPage::SetSize(nCX, nCY); +} + + +//************************************************************************ +// +// CLCDPopup::RecalcLayout +// +//************************************************************************ + +void CLCDPopup::RecalcLayout(void) +{ + // First get the size of the text + // If the width > MAX_WIDTH, snap it to the max width + int nTextWidthWithMargin = 2 * POPUP_MARGIN; + int nTextHeightWithMargin = 2 * POPUP_MARGIN; + if(0 < _tcslen(m_MessageText.GetText())) + { + m_MessageText.CalculateExtent(FALSE); + nTextWidthWithMargin = m_MessageText.GetVExtent().cx + 2*POPUP_MARGIN; + nTextHeightWithMargin = m_MessageText.GetVExtent().cy + 2*POPUP_MARGIN; + if(nTextWidthWithMargin > m_nMaxPopupWidth) + { + // Resize the text using a max height + m_MessageText.SetSize(m_nMaxPopupWidth, LGLCD_QVGA_BMP_HEIGHT); + m_MessageText.CalculateExtent(FALSE); + nTextWidthWithMargin = m_MessageText.GetVExtent().cx + 2*POPUP_MARGIN; + nTextHeightWithMargin = m_MessageText.GetVExtent().cy + 2*POPUP_MARGIN; + } + m_MessageText.SetSize(m_MessageText.GetVExtent().cx, m_MessageText.GetVExtent().cy); + } + else + { + nTextHeightWithMargin = POPUP_MARGIN; + nTextWidthWithMargin = 0; + m_MessageText.SetSize(0, 0); + } + + // Determine the size of the popup including.. + // Margin + // Text + // OK Bitmap + // Cancel Bitmap + int nPopupWidth = nTextWidthWithMargin; + int nPopupHeight = nTextHeightWithMargin; + + // Bitmap operations + BITMAP bmOK, bmCancel; + memset(&bmOK, 0, sizeof(bmOK)); + memset(&bmCancel, 0, sizeof(bmCancel)); + + if (NULL != m_OKBitmap.GetBitmap()) + { + GetObject( m_OKBitmap.GetBitmap(), sizeof(BITMAP), &bmOK); + m_OKBitmap.SetSize(bmOK.bmWidth, bmOK.bmHeight); + } + if (NULL != m_CancelBitmap.GetBitmap()) + { + GetObject( m_CancelBitmap.GetBitmap(), sizeof(BITMAP), &bmCancel); + m_CancelBitmap.SetSize(bmCancel.bmWidth, bmCancel.bmHeight); + } + + switch(m_pbType) + { + // Main text block only + case PB_TEXT: + m_OKBitmap.Show(FALSE); + m_CancelBitmap.Show(FALSE); + break; + + // OK is centered against the main text block + case PB_OK: + if (bmOK.bmWidth) + { + // Just factor in a bitmap + // Add the bitmap w/ margin on the bottom + nPopupHeight += bmOK.bmHeight; + nPopupHeight += POPUP_MARGIN; + + // Position the bitmap centered, and vertically after the text+margin + m_OKBitmap.SetOrigin((nPopupWidth-bmOK.bmWidth)/2, nTextHeightWithMargin); + + m_OKBitmap.Show(TRUE); + } + break; + + // OK, Cancel Buttons are aligned on the same row below the text block (like a dialog) + case PB_OKCANCEL: + if (bmOK.bmWidth && bmCancel.bmWidth) + { + // Add the bitmap w/ margin on the bottom + nPopupHeight += bmOK.bmHeight; + nPopupHeight += POPUP_MARGIN; + + // OK is right-aligned with the text + m_OKBitmap.SetOrigin(m_MessageText.GetOrigin().x + m_MessageText.GetSize().cx - bmOK.bmWidth, + nTextHeightWithMargin); + // Cancel is right-aligned with OK (with margin) + m_CancelBitmap.SetOrigin(m_OKBitmap.GetOrigin().x - bmCancel.bmWidth - POPUP_MARGIN, + nTextHeightWithMargin); + + m_OKBitmap.Show(TRUE); + m_CancelBitmap.Show(TRUE); + } + break; + + // OK, Cancel Buttons are on separate rows centered against their own text blocks + case PB_OKCANCEL_TEXT: + { + int nOKTextWithBitmapHeight = 0; + int nMaxOKTextWidth = 0; + m_OKText.SetOrigin(POPUP_MARGIN, nTextHeightWithMargin - POPUP_MARGIN); + + if (bmOK.bmWidth) + { + // OK is left-aligned with the text + m_OKBitmap.SetOrigin(m_MessageText.GetOrigin().x, nTextHeightWithMargin); + + // OK text height is left-aligned with OK bmp and right-aligned with text + // OK bmp is vertically centered against the OK text + nMaxOKTextWidth = m_MessageText.GetWidth() - bmOK.bmWidth - POPUP_MARGIN; + if (nMaxOKTextWidth < 0) + { + nMaxOKTextWidth = LGLCD_QVGA_BMP_WIDTH; + } + m_OKText.SetOrigin(m_OKBitmap.GetOrigin().x + bmOK.bmWidth + POPUP_MARGIN, nTextHeightWithMargin); + m_OKText.SetSize(nMaxOKTextWidth, LGLCD_QVGA_BMP_HEIGHT); + m_OKText.CalculateExtent(FALSE); + m_OKText.SetSize(m_OKText.GetVExtent().cx, m_OKText.GetVExtent().cy); + + // if no main text, figure out required max popup width + int nCalcPopupWidth = POPUP_MARGIN*3 + bmOK.bmWidth + m_OKText.GetSize().cx; + if (nCalcPopupWidth > nPopupWidth) + { + nPopupWidth = nCalcPopupWidth; + } + + // Add the bitmap w/ margin on the bottom + nOKTextWithBitmapHeight = max(bmOK.bmHeight, m_OKText.GetHeight()); + nPopupHeight += nOKTextWithBitmapHeight; + nPopupHeight += POPUP_MARGIN; + + m_OKText.Show(TRUE); + m_OKBitmap.Show(TRUE); + m_OKBitmap.SetOrigin(m_OKBitmap.GetOrigin().x, m_OKText.GetOrigin().y + (m_OKText.GetHeight() - bmOK.bmHeight)/2); + } + + if (bmCancel.bmWidth) + { + // Cancel is left-aligned with the text + m_CancelBitmap.SetOrigin(m_MessageText.GetOrigin().x, m_OKText.GetOrigin().y + nOKTextWithBitmapHeight + POPUP_MARGIN); + + int nMaxCancelTextWidth = m_MessageText.GetWidth() - bmCancel.bmWidth - POPUP_MARGIN; + if (nMaxCancelTextWidth < 0) + { + nMaxCancelTextWidth = LGLCD_QVGA_BMP_WIDTH; + } + m_CancelText.SetOrigin(m_CancelBitmap.GetOrigin().x + bmCancel.bmWidth + POPUP_MARGIN, m_CancelBitmap.GetOrigin().y); + m_CancelText.SetSize(nMaxCancelTextWidth, LGLCD_QVGA_BMP_HEIGHT); + m_CancelText.CalculateExtent(FALSE); + m_CancelText.SetSize(m_CancelText.GetVExtent().cx, m_CancelText.GetVExtent().cy); + + // if no main text, make the + int nCalcPopupWidth = POPUP_MARGIN*3 + bmOK.bmWidth + m_CancelText.GetSize().cx; + if (nCalcPopupWidth > nPopupWidth) + { + nPopupWidth = nCalcPopupWidth; + } + + nPopupHeight += max(bmCancel.bmHeight, m_CancelText.GetHeight()); + nPopupHeight += POPUP_MARGIN; + + // Vertically center the OK and CANCEL bitmaps against their respective texts + m_CancelText.Show(TRUE); + m_CancelBitmap.Show(TRUE); + m_CancelBitmap.SetOrigin(m_CancelBitmap.GetOrigin().x, m_CancelText.GetOrigin().y + (m_CancelText.GetHeight() - bmCancel.bmHeight)/2); + } + } + + break; + } + + // Resize ourself + SetSize(nPopupWidth, nPopupHeight); + + // Center the popup in the middle of the screen + SetOrigin( (LGLCD_QVGA_BMP_WIDTH - nPopupWidth)/2, (LGLCD_QVGA_BMP_HEIGHT - nPopupHeight)/2); + + // Resize the background + m_Background.SetSize(GetWidth(), GetHeight()); +} + + +//************************************************************************ +// +// CLCDPopup::SetBitmaps +// +//************************************************************************ + +void CLCDPopup::SetBitmaps(HBITMAP hbmOK, HBITMAP hbmCancel) +{ + m_OKBitmap.SetBitmap(hbmOK); + m_CancelBitmap.SetBitmap(hbmCancel); + + RecalcLayout(); +} + + +//************************************************************************ +// +// CLCDPopup::SetAlpha +// +//************************************************************************ + +void CLCDPopup::SetAlpha(BYTE bAlphaStart, BYTE bAlphaEnd) +{ + m_Background.SetAlphaLevel(bAlphaStart, bAlphaEnd); +} + + +//************************************************************************ +// +// CLCDPopup::SetGradientMode +// +//************************************************************************ + +void CLCDPopup::SetGradientMode(BOOL bGradient) +{ + m_Background.SetGradientMode(bGradient); +} + + +//************************************************************************ +// +// CLCDPopup::SetColor +// +//************************************************************************ + +void CLCDPopup::SetColor(COLORREF cfColor) +{ + m_Background.SetColor(cfColor); +} + + +//** end of LCDPopup.cpp ************************************************* diff --git a/src/thirdparty/LCDUI/LCDPopup.h b/src/thirdparty/LCDUI/LCDPopup.h index 12b3edbecd2..1f5f02296a8 100644 --- a/src/thirdparty/LCDUI/LCDPopup.h +++ b/src/thirdparty/LCDUI/LCDPopup.h @@ -1,100 +1,100 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDPopup.h -// -// Color LCD Popup class -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDPOPUP_H_INCLUDED_ -#define _LCDPOPUP_H_INCLUDED_ - -#include "LCDPage.h" -#include "LCDText.h" -#include "LCDBitmap.h" -#include - - -//************************************************************************ -// -// CLCDPopupBackground -// -//************************************************************************ - -class CLCDPopupBackground : public CLCDBase -{ -public: - CLCDPopupBackground(void); - virtual ~CLCDPopupBackground(void); - - void SetAlphaLevel(BYTE cAlphaStart, BYTE cAlphaEnd = 0xff); - void SetGradientMode(BOOL bGradient); - void SetColor(COLORREF cfColor); - void SetRoundedRecteRadius(int nRadius); - -public: - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void SetSize(int nCX, int nCY); - -private: - void RecalcRoundedRectangle(void); - BYTE m_cAlphaStart, m_cAlphaEnd; - COLORREF m_cfColor; - BOOL m_bUseGradient; - int m_nRectRadius; - Gdiplus::GraphicsPath* m_pGraphicsPath; -}; - - - -//************************************************************************ -// -// CLCDPopup -// -//************************************************************************ - -class CLCDPopup : public CLCDPage -{ -public: - enum PB_TYPE { PB_TEXT, PB_OK, PB_OKCANCEL, PB_OKCANCEL_TEXT }; - -public: - CLCDPopup(void); - - virtual HRESULT Initialize(int nMaxPopupWidth = 0); - - void SetText(LPCTSTR szMessage, LPCTSTR szOK = NULL, LPCTSTR szCancel = NULL); - void SetPopupType(PB_TYPE pbType); - void SetBitmaps(HBITMAP hbmOK, HBITMAP hbmCancel = NULL); - void SetAlpha(BYTE cAlphaStart, BYTE cAlphaEnd = 0xff); - void SetGradientMode(BOOL bGradient); - void SetColor(COLORREF cfColor); - -protected: - void RecalcLayout(void); - // Resizes automatically, so this is now private - virtual void SetSize(int nCX, int nCY); - - CLCDText m_MessageText, m_OKText, m_CancelText; - CLCDPopupBackground m_Background; - int m_nMaxPopupWidth; -private: - - CLCDBitmap m_OKBitmap, m_CancelBitmap; - PB_TYPE m_pbType; -}; - -#endif - -//** end of LCDPopup.h *************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDPopup.h +// +// Color LCD Popup class +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDPOPUP_H_INCLUDED_ +#define _LCDPOPUP_H_INCLUDED_ + +#include "LCDPage.h" +#include "LCDText.h" +#include "LCDBitmap.h" +#include + + +//************************************************************************ +// +// CLCDPopupBackground +// +//************************************************************************ + +class CLCDPopupBackground : public CLCDBase +{ +public: + CLCDPopupBackground(void); + virtual ~CLCDPopupBackground(void); + + void SetAlphaLevel(BYTE cAlphaStart, BYTE cAlphaEnd = 0xff); + void SetGradientMode(BOOL bGradient); + void SetColor(COLORREF cfColor); + void SetRoundedRecteRadius(int nRadius); + +public: + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void SetSize(int nCX, int nCY); + +private: + void RecalcRoundedRectangle(void); + BYTE m_cAlphaStart, m_cAlphaEnd; + COLORREF m_cfColor; + BOOL m_bUseGradient; + int m_nRectRadius; + Gdiplus::GraphicsPath* m_pGraphicsPath; +}; + + + +//************************************************************************ +// +// CLCDPopup +// +//************************************************************************ + +class CLCDPopup : public CLCDPage +{ +public: + enum PB_TYPE { PB_TEXT, PB_OK, PB_OKCANCEL, PB_OKCANCEL_TEXT }; + +public: + CLCDPopup(void); + + virtual HRESULT Initialize(int nMaxPopupWidth = 0); + + void SetText(LPCTSTR szMessage, LPCTSTR szOK = NULL, LPCTSTR szCancel = NULL); + void SetPopupType(PB_TYPE pbType); + void SetBitmaps(HBITMAP hbmOK, HBITMAP hbmCancel = NULL); + void SetAlpha(BYTE cAlphaStart, BYTE cAlphaEnd = 0xff); + void SetGradientMode(BOOL bGradient); + void SetColor(COLORREF cfColor); + +protected: + void RecalcLayout(void); + // Resizes automatically, so this is now private + virtual void SetSize(int nCX, int nCY); + + CLCDText m_MessageText, m_OKText, m_CancelText; + CLCDPopupBackground m_Background; + int m_nMaxPopupWidth; +private: + + CLCDBitmap m_OKBitmap, m_CancelBitmap; + PB_TYPE m_pbType; +}; + +#endif + +//** end of LCDPopup.h *************************************************** diff --git a/src/thirdparty/LCDUI/LCDProgressBar.cpp b/src/thirdparty/LCDUI/LCDProgressBar.cpp index 06d61cf0520..caeab4e5220 100644 --- a/src/thirdparty/LCDUI/LCDProgressBar.cpp +++ b/src/thirdparty/LCDUI/LCDProgressBar.cpp @@ -1,263 +1,263 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDProgressBar.cpp -// -// The CLCDProgressBar class draws a progress bar onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDProgressBar::CLCDProgressBar -// -//************************************************************************ - -CLCDProgressBar::CLCDProgressBar(void) -: m_fPos(0.0f), - m_eStyle(STYLE_CURSOR), - m_hBrush(NULL), - m_hPen(NULL), - m_nCursorWidth(5) -{ - m_Range.nMin = 0; - m_Range.nMax = 100; -} - - -//************************************************************************ -// -// CLCDProgressBar::~CLCDProgressBar -// -//************************************************************************ - -CLCDProgressBar::~CLCDProgressBar(void) -{ - if (m_hPen != NULL) - { - ::DeleteObject(m_hPen); - m_hPen = NULL; - } -} - - -//************************************************************************ -// -// CLCDProgressBar:Initialize -// -//************************************************************************ - -HRESULT CLCDProgressBar::Initialize(void) -{ - m_hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); - m_hPen = ::CreatePen(PS_DOT, 1, RGB(255, 255, 255)); - - return S_OK; -} - - -//************************************************************************ -// -// CLCDProgressBar::OnDraw -// -//************************************************************************ - -void CLCDProgressBar::OnDraw(CLCDGfxBase &rGfx) -{ - // draw the border - RECT r = { 0, 0, GetWidth(), GetHeight() }; - - FrameRect(rGfx.GetHDC(), &r, m_hBrush); - - // draw the progress - switch(m_eStyle) - { - case STYLE_CURSOR: - { - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)1, (float)(GetWidth() - m_nCursorWidth-1), - m_fPos); - r.left = nCursorPos; - r.right = r.left + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - } - break; - case STYLE_FILLED: - { - int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - 0.0f, (float)GetWidth(), - m_fPos); - r.right = nBarWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - } - break; - case STYLE_DASHED_CURSOR: - { - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)1, (float)(GetWidth() - m_nCursorWidth-1), - m_fPos); - r.left = nCursorPos; - r.right = r.left + m_nCursorWidth; - FillRect(rGfx.GetHDC(), &r, m_hBrush); - HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), m_hPen); - - ::MoveToEx(rGfx.GetHDC(), 0, (r.bottom - r.top)/2, NULL); - ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top)/2); - ::SelectObject(rGfx.GetHDC(), hOldPen); - } - break; - default: - break; - } -} - - -//************************************************************************ -// -// CLCDProgressBar::ResetUpdate -// -//************************************************************************ - -void CLCDProgressBar::ResetUpdate(void) -{ -} - - -//************************************************************************ -// -// CLCDProgressBar::SetRange -// -//************************************************************************ - -void CLCDProgressBar::SetRange(int nMin, int nMax) -{ - m_Range.nMin = nMin; - m_Range.nMax = nMax; -} - - -//************************************************************************ -// -// CLCDProgressBar::SetRange -// -//************************************************************************ - -void CLCDProgressBar::SetRange(RANGE& Range) -{ - m_Range = Range; -} - - -//************************************************************************ -// -// CLCDProgressBar::GetRange -// -//************************************************************************ - -RANGE& CLCDProgressBar::GetRange(void) -{ - return m_Range; -} - - -//************************************************************************ -// -// CLCDProgressBar::SetPos -// -//************************************************************************ - -float CLCDProgressBar::SetPos(float fPos) -{ - return ( m_fPos = max((float)m_Range.nMin, min(fPos, (float)m_Range.nMax)) ); -} - - -//************************************************************************ -// -// CLCDProgressBar::GetPos -// -//************************************************************************ - -float CLCDProgressBar::GetPos(void) -{ - return m_fPos; -} - - -//************************************************************************ -// -// CLCDProgressBar::EnableCursor -// -//************************************************************************ - -void CLCDProgressBar::EnableCursor(BOOL bEnable) -{ - m_eStyle = bEnable ? STYLE_CURSOR : STYLE_FILLED; -} - - -//************************************************************************ -// -// CLCDProgressBar::SetProgressStyle -// -//************************************************************************ - -void CLCDProgressBar::SetProgressStyle(ePROGRESS_STYLE eStyle) -{ - m_eStyle = eStyle; -} - - -//************************************************************************ -// -// CLCDProgressBar::Scalef -// -//************************************************************************ - -float CLCDProgressBar::Scalef(float fFromMin, float fFromMax, - float fToMin, float fToMax, float fFromValue) -{ - - // normalize the input - float fFromValueN = (fFromValue - fFromMin) / (fFromMax - fFromMin); - - // now scale to the output - float fToRange = fToMax - fToMin; - - return ( fToMin + (fFromValueN * fToRange) ); -} - - -//************************************************************************ -// -// CLCDProgressBar::Scale -// -//************************************************************************ - -int CLCDProgressBar::Scale(int nFromMin, int nFromMax, - int nToMin, int nToMax, int nFromValue) -{ - return (int)Scalef( - (float)nFromMin, - (float)nFromMax, - (float)nToMin, - (float)nToMax, - (float)nFromValue - ); -} - - -//** end of LCDProgressBar.cpp ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDProgressBar.cpp +// +// The CLCDProgressBar class draws a progress bar onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDProgressBar::CLCDProgressBar +// +//************************************************************************ + +CLCDProgressBar::CLCDProgressBar(void) +: m_fPos(0.0f), + m_eStyle(STYLE_CURSOR), + m_hBrush(NULL), + m_hPen(NULL), + m_nCursorWidth(5) +{ + m_Range.nMin = 0; + m_Range.nMax = 100; +} + + +//************************************************************************ +// +// CLCDProgressBar::~CLCDProgressBar +// +//************************************************************************ + +CLCDProgressBar::~CLCDProgressBar(void) +{ + if (m_hPen != NULL) + { + ::DeleteObject(m_hPen); + m_hPen = NULL; + } +} + + +//************************************************************************ +// +// CLCDProgressBar:Initialize +// +//************************************************************************ + +HRESULT CLCDProgressBar::Initialize(void) +{ + m_hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); + m_hPen = ::CreatePen(PS_DOT, 1, RGB(255, 255, 255)); + + return S_OK; +} + + +//************************************************************************ +// +// CLCDProgressBar::OnDraw +// +//************************************************************************ + +void CLCDProgressBar::OnDraw(CLCDGfxBase &rGfx) +{ + // draw the border + RECT r = { 0, 0, GetWidth(), GetHeight() }; + + FrameRect(rGfx.GetHDC(), &r, m_hBrush); + + // draw the progress + switch(m_eStyle) + { + case STYLE_CURSOR: + { + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)1, (float)(GetWidth() - m_nCursorWidth-1), + m_fPos); + r.left = nCursorPos; + r.right = r.left + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + } + break; + case STYLE_FILLED: + { + int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + 0.0f, (float)GetWidth(), + m_fPos); + r.right = nBarWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + } + break; + case STYLE_DASHED_CURSOR: + { + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)1, (float)(GetWidth() - m_nCursorWidth-1), + m_fPos); + r.left = nCursorPos; + r.right = r.left + m_nCursorWidth; + FillRect(rGfx.GetHDC(), &r, m_hBrush); + HPEN hOldPen = (HPEN)::SelectObject(rGfx.GetHDC(), m_hPen); + + ::MoveToEx(rGfx.GetHDC(), 0, (r.bottom - r.top)/2, NULL); + ::LineTo(rGfx.GetHDC(), nCursorPos, (r.bottom - r.top)/2); + ::SelectObject(rGfx.GetHDC(), hOldPen); + } + break; + default: + break; + } +} + + +//************************************************************************ +// +// CLCDProgressBar::ResetUpdate +// +//************************************************************************ + +void CLCDProgressBar::ResetUpdate(void) +{ +} + + +//************************************************************************ +// +// CLCDProgressBar::SetRange +// +//************************************************************************ + +void CLCDProgressBar::SetRange(int nMin, int nMax) +{ + m_Range.nMin = nMin; + m_Range.nMax = nMax; +} + + +//************************************************************************ +// +// CLCDProgressBar::SetRange +// +//************************************************************************ + +void CLCDProgressBar::SetRange(RANGE& Range) +{ + m_Range = Range; +} + + +//************************************************************************ +// +// CLCDProgressBar::GetRange +// +//************************************************************************ + +RANGE& CLCDProgressBar::GetRange(void) +{ + return m_Range; +} + + +//************************************************************************ +// +// CLCDProgressBar::SetPos +// +//************************************************************************ + +float CLCDProgressBar::SetPos(float fPos) +{ + return ( m_fPos = max((float)m_Range.nMin, min(fPos, (float)m_Range.nMax)) ); +} + + +//************************************************************************ +// +// CLCDProgressBar::GetPos +// +//************************************************************************ + +float CLCDProgressBar::GetPos(void) +{ + return m_fPos; +} + + +//************************************************************************ +// +// CLCDProgressBar::EnableCursor +// +//************************************************************************ + +void CLCDProgressBar::EnableCursor(BOOL bEnable) +{ + m_eStyle = bEnable ? STYLE_CURSOR : STYLE_FILLED; +} + + +//************************************************************************ +// +// CLCDProgressBar::SetProgressStyle +// +//************************************************************************ + +void CLCDProgressBar::SetProgressStyle(ePROGRESS_STYLE eStyle) +{ + m_eStyle = eStyle; +} + + +//************************************************************************ +// +// CLCDProgressBar::Scalef +// +//************************************************************************ + +float CLCDProgressBar::Scalef(float fFromMin, float fFromMax, + float fToMin, float fToMax, float fFromValue) +{ + + // normalize the input + float fFromValueN = (fFromValue - fFromMin) / (fFromMax - fFromMin); + + // now scale to the output + float fToRange = fToMax - fToMin; + + return ( fToMin + (fFromValueN * fToRange) ); +} + + +//************************************************************************ +// +// CLCDProgressBar::Scale +// +//************************************************************************ + +int CLCDProgressBar::Scale(int nFromMin, int nFromMax, + int nToMin, int nToMax, int nFromValue) +{ + return (int)Scalef( + (float)nFromMin, + (float)nFromMax, + (float)nToMin, + (float)nToMax, + (float)nFromValue + ); +} + + +//** end of LCDProgressBar.cpp ******************************************* diff --git a/src/thirdparty/LCDUI/LCDProgressBar.h b/src/thirdparty/LCDUI/LCDProgressBar.h index 677816f546b..28766c23630 100644 --- a/src/thirdparty/LCDUI/LCDProgressBar.h +++ b/src/thirdparty/LCDUI/LCDProgressBar.h @@ -1,72 +1,72 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDProgressBar.h -// -// The CLCDProgressBar class draws a progress bar onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDPROGRESSBAR_H_INCLUDED_ -#define _LCDPROGRESSBAR_H_INCLUDED_ - -#include "LCDBase.h" - -typedef struct RANGE -{ - int nMin; - int nMax; - -}RANGE, *LPRANGE; - -class CLCDProgressBar : public CLCDBase -{ -public: - enum ePROGRESS_STYLE { STYLE_FILLED, STYLE_CURSOR, STYLE_DASHED_CURSOR }; - - CLCDProgressBar(void); - virtual ~CLCDProgressBar(void); - - // CLCDBase - virtual HRESULT Initialize(void); - virtual void OnDraw(CLCDGfxBase &rGfx); - virtual void ResetUpdate(void); - - // CLCDProgressBar - virtual void SetRange(int nMin, int nMax); - virtual void SetRange(RANGE& Range); - virtual RANGE& GetRange(void); - virtual float SetPos(float fPos); - virtual float GetPos(void); - virtual void EnableCursor(BOOL bEnable); - virtual void SetProgressStyle(ePROGRESS_STYLE eStyle); - -protected: - float Scalef(float fFromMin, float fFromMax, - float fToMin, float fToMax, float fFromValue); - int Scale(int nFromMin, int nFromMax, - int nToMin, int nToMax, int nFromValue); - -protected: - RANGE m_Range; - float m_fPos; - ePROGRESS_STYLE m_eStyle; - HBRUSH m_hBrush; - HPEN m_hPen; - int m_nCursorWidth; -}; - - -#endif // !_LCDPROGRESSBAR_H_INCLUDED_ - -//** end of LCDProgressBar.h ********************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDProgressBar.h +// +// The CLCDProgressBar class draws a progress bar onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDPROGRESSBAR_H_INCLUDED_ +#define _LCDPROGRESSBAR_H_INCLUDED_ + +#include "LCDBase.h" + +typedef struct RANGE +{ + int nMin; + int nMax; + +}RANGE, *LPRANGE; + +class CLCDProgressBar : public CLCDBase +{ +public: + enum ePROGRESS_STYLE { STYLE_FILLED, STYLE_CURSOR, STYLE_DASHED_CURSOR }; + + CLCDProgressBar(void); + virtual ~CLCDProgressBar(void); + + // CLCDBase + virtual HRESULT Initialize(void); + virtual void OnDraw(CLCDGfxBase &rGfx); + virtual void ResetUpdate(void); + + // CLCDProgressBar + virtual void SetRange(int nMin, int nMax); + virtual void SetRange(RANGE& Range); + virtual RANGE& GetRange(void); + virtual float SetPos(float fPos); + virtual float GetPos(void); + virtual void EnableCursor(BOOL bEnable); + virtual void SetProgressStyle(ePROGRESS_STYLE eStyle); + +protected: + float Scalef(float fFromMin, float fFromMax, + float fToMin, float fToMax, float fFromValue); + int Scale(int nFromMin, int nFromMax, + int nToMin, int nToMax, int nFromValue); + +protected: + RANGE m_Range; + float m_fPos; + ePROGRESS_STYLE m_eStyle; + HBRUSH m_hBrush; + HPEN m_hPen; + int m_nCursorWidth; +}; + + +#endif // !_LCDPROGRESSBAR_H_INCLUDED_ + +//** end of LCDProgressBar.h ********************************************* diff --git a/src/thirdparty/LCDUI/LCDScrollingText.cpp b/src/thirdparty/LCDUI/LCDScrollingText.cpp index 5efcfac9428..51889201a0b 100644 --- a/src/thirdparty/LCDUI/LCDScrollingText.cpp +++ b/src/thirdparty/LCDUI/LCDScrollingText.cpp @@ -1,306 +1,306 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDScrollingText.cpp -// -// The CLCDScrollingText class draws scrolling text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDScrollingText::CLCDScrollingText -// -//************************************************************************ - -CLCDScrollingText::CLCDScrollingText(void) -{ - m_eState = STATE_START_DELAY; - m_eScrollDir = SCROLL_HORZ; - m_bRepeat = TRUE; -} - - -//************************************************************************ -// -// CLCDScrollingText::~CLCDScrollingText -// -//************************************************************************ - -CLCDScrollingText::~CLCDScrollingText(void) -{ -} - - -//************************************************************************ -// -// CLCDScrollingText::Initialize -// -//************************************************************************ - -HRESULT CLCDScrollingText::Initialize(void) -{ - m_dwStartDelay = 1000; - m_dwSpeed = 20; - m_nScrollingDistance = -1; - m_dwLastUpdate = 0; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_fTotalDistance = 0; - m_eScrollDir = SCROLL_HORZ; - m_dwEndDelay = 1000; - m_bRepeat = TRUE; - - return CLCDText::Initialize(); -} - - -//************************************************************************ -// -// CLCDScrollingText::ResetUpdate -// -//************************************************************************ - -void CLCDScrollingText::ResetUpdate(void) -{ - m_eState = STATE_START_DELAY; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_nScrollingDistance = -1; - m_fTotalDistance = 0; - SetLeftMargin(0); - SetLogicalOrigin(0, 0); - - CLCDText::ResetUpdate(); -} - - -//************************************************************************ -// -// CLCDScrollingText::SetStartDelay -// -//************************************************************************ - -void CLCDScrollingText::SetStartDelay(DWORD dwMilliseconds) -{ - m_dwStartDelay = dwMilliseconds; -} - - -//************************************************************************ -// -// CLCDScrollingText::SetEndDelay -// -//************************************************************************ - -void CLCDScrollingText::SetEndDelay(DWORD dwMilliseconds) -{ - m_dwEndDelay = dwMilliseconds; -} - - -//************************************************************************ -// -// CLCDScrollingText::SetSpeed -// -//************************************************************************ - -void CLCDScrollingText::SetSpeed(DWORD dwSpeed) -{ - m_dwSpeed = dwSpeed; -} - - -//************************************************************************ -// -// CLCDScrollingText::SetScrollDirection -// -//************************************************************************ - -void CLCDScrollingText::SetScrollDirection(eSCROLL_DIR eScrollDir) -{ - m_eScrollDir = eScrollDir; - SetWordWrap(eScrollDir == SCROLL_VERT); - ResetUpdate(); -} - - -//************************************************************************ -// -// CLCDScrollingText::GetScrollDirection -// -//************************************************************************ - -eSCROLL_DIR CLCDScrollingText::GetScrollDirection() -{ - return m_eScrollDir; -} - - -//************************************************************************ -// -// CLCDScrollingText::SetText -// -//************************************************************************ - -void CLCDScrollingText::SetText(LPCTSTR szText) -{ - if (_tcscmp(szText, m_sText.c_str())) - { - ResetUpdate(); - } - - CLCDText::SetText(szText); -} - - -//************************************************************************ -// -// CLCDScrollingText::IsScrollingDone -// -//************************************************************************ - -BOOL CLCDScrollingText::IsScrollingDone() -{ - return (STATE_DONE == m_eState); -} - - -//************************************************************************ -// -// CLCDScrollingText::EnableRepeat -// -//************************************************************************ - -void CLCDScrollingText::EnableRepeat(BOOL bEnable) -{ - m_bRepeat = bEnable; -} - - -//************************************************************************ -// -// CLCDScrollingText::OnUpdate -// -//************************************************************************ - -void CLCDScrollingText::OnUpdate(DWORD dwTimestamp) -{ - m_dwEllapsedTime = (dwTimestamp - m_dwLastUpdate); -} - - -//************************************************************************ -// -// CLCDScrollingText::OnDraw -// -//************************************************************************ - -void CLCDScrollingText::OnDraw(CLCDGfxBase &rGfx) -{ - if (!m_nTextLength) - { - return; - } - - // calculate the scrolling distance - if (-1 == m_nScrollingDistance) - { - CLCDText::OnDraw(rGfx); - - if (SCROLL_VERT == m_eScrollDir) - { - // determine how far we have to travel until scrolling stops - m_nScrollingDistance = ((GetHeight()) >= GetVExtent().cy) ? - 0 : (GetVExtent().cy - GetHeight()); - SetLogicalSize(GetVExtent().cx, GetVExtent().cy); - } - else - { - // determine how far we have to travel until scrolling stops - m_nScrollingDistance = ((GetWidth()) >= GetHExtent().cx) ? - 0 : (GetHExtent().cx - GetWidth()); - SetLogicalSize(max(GetSize().cx, GetHExtent().cx), GetHExtent().cy); - } - } - - switch(m_eState) - { - case STATE_START_DELAY: - if (m_dwEllapsedTime > m_dwStartDelay) - { - m_eState = STATE_SCROLL; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - } - break; - - case STATE_END_DELAY: - if (m_dwEllapsedTime > m_dwEndDelay) - { - if (m_bRepeat) - { - ResetUpdate(); - break; - } - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_eState = STATE_DONE; - } - break; - - case STATE_SCROLL: - { - // TODO: add some anti-aliasing on the movement - - // how much time has ellapsed? - // given the speed, what is the total displacement? - float fDistance = (float)(m_dwSpeed * m_dwEllapsedTime) / 1000.0f; - m_fTotalDistance += fDistance; - - // we dont want the total distnace exceed our scrolling distance - int nTotalOffset = min((int)m_fTotalDistance, m_nScrollingDistance); - - if (SCROLL_VERT == m_eScrollDir) - { - SetLogicalOrigin(GetLogicalOrigin().x, -1 * nTotalOffset); - } - else - { - SetLogicalOrigin(-1 * nTotalOffset, GetLogicalOrigin().y); - } - - m_dwLastUpdate = GetTickCount(); - - if (nTotalOffset == m_nScrollingDistance) - { - m_eState = STATE_END_DELAY; - } - } - break; - - case STATE_DONE: - break; - - default: - break; - } - - CLCDText::OnDraw(rGfx); -} - - -//** end of LCDScrollingText.cpp ***************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDScrollingText.cpp +// +// The CLCDScrollingText class draws scrolling text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDScrollingText::CLCDScrollingText +// +//************************************************************************ + +CLCDScrollingText::CLCDScrollingText(void) +{ + m_eState = STATE_START_DELAY; + m_eScrollDir = SCROLL_HORZ; + m_bRepeat = TRUE; +} + + +//************************************************************************ +// +// CLCDScrollingText::~CLCDScrollingText +// +//************************************************************************ + +CLCDScrollingText::~CLCDScrollingText(void) +{ +} + + +//************************************************************************ +// +// CLCDScrollingText::Initialize +// +//************************************************************************ + +HRESULT CLCDScrollingText::Initialize(void) +{ + m_dwStartDelay = 1000; + m_dwSpeed = 20; + m_nScrollingDistance = -1; + m_dwLastUpdate = 0; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_fTotalDistance = 0; + m_eScrollDir = SCROLL_HORZ; + m_dwEndDelay = 1000; + m_bRepeat = TRUE; + + return CLCDText::Initialize(); +} + + +//************************************************************************ +// +// CLCDScrollingText::ResetUpdate +// +//************************************************************************ + +void CLCDScrollingText::ResetUpdate(void) +{ + m_eState = STATE_START_DELAY; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_nScrollingDistance = -1; + m_fTotalDistance = 0; + SetLeftMargin(0); + SetLogicalOrigin(0, 0); + + CLCDText::ResetUpdate(); +} + + +//************************************************************************ +// +// CLCDScrollingText::SetStartDelay +// +//************************************************************************ + +void CLCDScrollingText::SetStartDelay(DWORD dwMilliseconds) +{ + m_dwStartDelay = dwMilliseconds; +} + + +//************************************************************************ +// +// CLCDScrollingText::SetEndDelay +// +//************************************************************************ + +void CLCDScrollingText::SetEndDelay(DWORD dwMilliseconds) +{ + m_dwEndDelay = dwMilliseconds; +} + + +//************************************************************************ +// +// CLCDScrollingText::SetSpeed +// +//************************************************************************ + +void CLCDScrollingText::SetSpeed(DWORD dwSpeed) +{ + m_dwSpeed = dwSpeed; +} + + +//************************************************************************ +// +// CLCDScrollingText::SetScrollDirection +// +//************************************************************************ + +void CLCDScrollingText::SetScrollDirection(eSCROLL_DIR eScrollDir) +{ + m_eScrollDir = eScrollDir; + SetWordWrap(eScrollDir == SCROLL_VERT); + ResetUpdate(); +} + + +//************************************************************************ +// +// CLCDScrollingText::GetScrollDirection +// +//************************************************************************ + +eSCROLL_DIR CLCDScrollingText::GetScrollDirection() +{ + return m_eScrollDir; +} + + +//************************************************************************ +// +// CLCDScrollingText::SetText +// +//************************************************************************ + +void CLCDScrollingText::SetText(LPCTSTR szText) +{ + if (_tcscmp(szText, m_sText.c_str())) + { + ResetUpdate(); + } + + CLCDText::SetText(szText); +} + + +//************************************************************************ +// +// CLCDScrollingText::IsScrollingDone +// +//************************************************************************ + +BOOL CLCDScrollingText::IsScrollingDone() +{ + return (STATE_DONE == m_eState); +} + + +//************************************************************************ +// +// CLCDScrollingText::EnableRepeat +// +//************************************************************************ + +void CLCDScrollingText::EnableRepeat(BOOL bEnable) +{ + m_bRepeat = bEnable; +} + + +//************************************************************************ +// +// CLCDScrollingText::OnUpdate +// +//************************************************************************ + +void CLCDScrollingText::OnUpdate(DWORD dwTimestamp) +{ + m_dwEllapsedTime = (dwTimestamp - m_dwLastUpdate); +} + + +//************************************************************************ +// +// CLCDScrollingText::OnDraw +// +//************************************************************************ + +void CLCDScrollingText::OnDraw(CLCDGfxBase &rGfx) +{ + if (!m_nTextLength) + { + return; + } + + // calculate the scrolling distance + if (-1 == m_nScrollingDistance) + { + CLCDText::OnDraw(rGfx); + + if (SCROLL_VERT == m_eScrollDir) + { + // determine how far we have to travel until scrolling stops + m_nScrollingDistance = ((GetHeight()) >= GetVExtent().cy) ? + 0 : (GetVExtent().cy - GetHeight()); + SetLogicalSize(GetVExtent().cx, GetVExtent().cy); + } + else + { + // determine how far we have to travel until scrolling stops + m_nScrollingDistance = ((GetWidth()) >= GetHExtent().cx) ? + 0 : (GetHExtent().cx - GetWidth()); + SetLogicalSize(max(GetSize().cx, GetHExtent().cx), GetHExtent().cy); + } + } + + switch(m_eState) + { + case STATE_START_DELAY: + if (m_dwEllapsedTime > m_dwStartDelay) + { + m_eState = STATE_SCROLL; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + } + break; + + case STATE_END_DELAY: + if (m_dwEllapsedTime > m_dwEndDelay) + { + if (m_bRepeat) + { + ResetUpdate(); + break; + } + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_eState = STATE_DONE; + } + break; + + case STATE_SCROLL: + { + // TODO: add some anti-aliasing on the movement + + // how much time has ellapsed? + // given the speed, what is the total displacement? + float fDistance = (float)(m_dwSpeed * m_dwEllapsedTime) / 1000.0f; + m_fTotalDistance += fDistance; + + // we dont want the total distnace exceed our scrolling distance + int nTotalOffset = min((int)m_fTotalDistance, m_nScrollingDistance); + + if (SCROLL_VERT == m_eScrollDir) + { + SetLogicalOrigin(GetLogicalOrigin().x, -1 * nTotalOffset); + } + else + { + SetLogicalOrigin(-1 * nTotalOffset, GetLogicalOrigin().y); + } + + m_dwLastUpdate = GetTickCount(); + + if (nTotalOffset == m_nScrollingDistance) + { + m_eState = STATE_END_DELAY; + } + } + break; + + case STATE_DONE: + break; + + default: + break; + } + + CLCDText::OnDraw(rGfx); +} + + +//** end of LCDScrollingText.cpp ***************************************** diff --git a/src/thirdparty/LCDUI/LCDScrollingText.h b/src/thirdparty/LCDUI/LCDScrollingText.h index 1fe1cf8ca69..c55fb89a2e2 100644 --- a/src/thirdparty/LCDUI/LCDScrollingText.h +++ b/src/thirdparty/LCDUI/LCDScrollingText.h @@ -1,75 +1,75 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDScrollingText.h -// -// The CLCDScrollingText class draws scrolling text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - - -#ifndef _LCDSCROLLINGTEXT_H_INCLUDED_ -#define _LCDSCROLLINGTEXT_H_INCLUDED_ - -#include "LCDBase.h" -#include "LCDText.h" - -enum eSCROLL_DIR { SCROLL_HORZ, SCROLL_VERT }; - -class CLCDScrollingText : public CLCDText -{ -public: - CLCDScrollingText(); - virtual ~CLCDScrollingText(); - - // CLCDBase - virtual HRESULT Initialize(void); - virtual void ResetUpdate(void); - - // CLCDText - virtual void SetText(LPCTSTR szText); - - void SetStartDelay(DWORD dwMilliseconds); - void SetEndDelay(DWORD dwMilliseconds); - void EnableRepeat(BOOL bEnable); - void SetSpeed(DWORD dwSpeed); - - void SetScrollDirection(eSCROLL_DIR eScrollDir); - eSCROLL_DIR GetScrollDirection(void); - BOOL IsScrollingDone(void); - -protected: - virtual void OnUpdate(DWORD dwTimestamp); - virtual void OnDraw(CLCDGfxBase &rGfx); - -private: - enum eSCROLL_STATES { STATE_START_DELAY, STATE_SCROLL, STATE_END_DELAY, STATE_DONE}; - - DWORD m_dwEllapsedTime; // ellapsed time in state - DWORD m_dwStartDelay; // milliseconds - DWORD m_dwEndDelay; // milliseconds - DWORD m_dwSpeed; // pixels/second - DWORD m_dwLastUpdate; // milliseconds - BOOL m_bRepeat; // repeat - - int m_nScrollingDistance; - float m_fTotalDistance; - - eSCROLL_DIR m_eScrollDir; - eSCROLL_STATES m_eState; -}; - - -#endif // !_LCDSCROLLINGTEXT_H_INCLUDED_ - -//** end of LCDScrollingText.h ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDScrollingText.h +// +// The CLCDScrollingText class draws scrolling text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + + +#ifndef _LCDSCROLLINGTEXT_H_INCLUDED_ +#define _LCDSCROLLINGTEXT_H_INCLUDED_ + +#include "LCDBase.h" +#include "LCDText.h" + +enum eSCROLL_DIR { SCROLL_HORZ, SCROLL_VERT }; + +class CLCDScrollingText : public CLCDText +{ +public: + CLCDScrollingText(); + virtual ~CLCDScrollingText(); + + // CLCDBase + virtual HRESULT Initialize(void); + virtual void ResetUpdate(void); + + // CLCDText + virtual void SetText(LPCTSTR szText); + + void SetStartDelay(DWORD dwMilliseconds); + void SetEndDelay(DWORD dwMilliseconds); + void EnableRepeat(BOOL bEnable); + void SetSpeed(DWORD dwSpeed); + + void SetScrollDirection(eSCROLL_DIR eScrollDir); + eSCROLL_DIR GetScrollDirection(void); + BOOL IsScrollingDone(void); + +protected: + virtual void OnUpdate(DWORD dwTimestamp); + virtual void OnDraw(CLCDGfxBase &rGfx); + +private: + enum eSCROLL_STATES { STATE_START_DELAY, STATE_SCROLL, STATE_END_DELAY, STATE_DONE}; + + DWORD m_dwEllapsedTime; // ellapsed time in state + DWORD m_dwStartDelay; // milliseconds + DWORD m_dwEndDelay; // milliseconds + DWORD m_dwSpeed; // pixels/second + DWORD m_dwLastUpdate; // milliseconds + BOOL m_bRepeat; // repeat + + int m_nScrollingDistance; + float m_fTotalDistance; + + eSCROLL_DIR m_eScrollDir; + eSCROLL_STATES m_eState; +}; + + +#endif // !_LCDSCROLLINGTEXT_H_INCLUDED_ + +//** end of LCDScrollingText.h ******************************************* diff --git a/src/thirdparty/LCDUI/LCDSkinnedProgressBar.cpp b/src/thirdparty/LCDUI/LCDSkinnedProgressBar.cpp index 1ead93b07d3..b53a987aefd 100644 --- a/src/thirdparty/LCDUI/LCDSkinnedProgressBar.cpp +++ b/src/thirdparty/LCDUI/LCDSkinnedProgressBar.cpp @@ -1,323 +1,323 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// CLCDSkinnedProgressBar.cpp -// -// Color LCD Skinned Progress Bar class -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::CLCDSkinnedProgressBar -// -//************************************************************************ - -CLCDSkinnedProgressBar::CLCDSkinnedProgressBar(void) -{ - m_hBackground = NULL; - m_hFiller = NULL; - m_hCursor = NULL; - m_hHighlight = NULL; - m_h3PCursorLeft = NULL; - m_h3PCursorMid = NULL; - m_h3PCursorRight = NULL; - - m_BackgroundHeight = 0; - m_BackgroundWidth = 0; - - m_FillerHeight = 0; - m_FillerWidth = 0; - - m_CursorHeight = 0; - m_CursorWidth = 0; - - m_HighlightHeight = 0; - m_HighlightWidth = 0; - - m_bUse3P = FALSE; - - m_3PCursorLeftHeight = 0; - m_3PCursorLeftWidth = 0; - - m_3PCursorMidHeight = 0; - m_3PCursorMidWidth = 0; - - m_3PCursorRightHeight = 0; - m_3PCursorRightWidth = 0; -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::~CLCDSkinnedProgressBar -// -//************************************************************************ - -CLCDSkinnedProgressBar::~CLCDSkinnedProgressBar(void) -{ -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::SetBackground -// -//************************************************************************ - -void CLCDSkinnedProgressBar::SetBackground(HBITMAP background, int bmpWidth, int bmpHeight) -{ - m_hBackground = background; - m_BackgroundHeight = bmpHeight; - m_BackgroundWidth = bmpWidth; - SetSize(bmpWidth, bmpHeight); -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::SetFiller -// -//************************************************************************ - -void CLCDSkinnedProgressBar::SetFiller(HBITMAP cursor, int bmpWidth, int bmpHeight) -{ - m_bUse3P = FALSE; - m_hFiller = cursor; - m_FillerHeight = bmpHeight; - m_FillerWidth = bmpWidth; - SetSize(bmpWidth, bmpHeight); -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::SetCursor -// -//************************************************************************ - -void CLCDSkinnedProgressBar::SetCursor(HBITMAP cursor, int bmpWidth, int bmpHeight) -{ - m_bUse3P = FALSE; - m_hCursor = cursor; - m_CursorHeight = bmpHeight; - m_CursorWidth = bmpWidth; - m_nCursorWidth = m_CursorWidth; -} - - -//************************************************************************ -// -// CLCDSkinnedProgressBar::SetThreePieceCursor -// -//************************************************************************ - -void CLCDSkinnedProgressBar::SetThreePieceCursor(HBITMAP left, int bmpLeftWidth, int bmpLeftHeight, - HBITMAP mid, int bmpMidWidth, int bmpMidHeight, - HBITMAP right, int bmpRightWidth, int bmpRightHeight ) -{ - m_bUse3P = TRUE; - - m_h3PCursorLeft = left; - m_3PCursorLeftHeight = bmpLeftHeight; - m_3PCursorLeftWidth = bmpLeftWidth; - - m_h3PCursorMid = mid; - m_3PCursorMidHeight = bmpMidHeight; - m_3PCursorMidWidth = bmpMidWidth; - - m_h3PCursorRight = right; - m_3PCursorRightHeight = bmpRightHeight; - m_3PCursorRightWidth = bmpRightWidth; - - m_nCursorWidth = m_3PCursorLeftWidth + m_3PCursorMidWidth + m_3PCursorRightWidth; -} - -//************************************************************************ -// -// CLCDSkinnedProgressBar::AddHighlight -// -//************************************************************************ - -void CLCDSkinnedProgressBar::AddHighlight(HBITMAP highlight, int bmpWidth, int bmpHeight) -{ - m_hHighlight = highlight; - m_HighlightHeight = bmpHeight; - m_HighlightWidth = bmpWidth; -} - -//************************************************************************ -// -// CLCDSkinnedProgressBar::OnDraw -// -//************************************************************************ - -void CLCDSkinnedProgressBar::OnDraw(CLCDGfxBase &rGfx) -{ - RECT rBoundary = { 0, 0, GetWidth(), GetHeight() }; - - HDC hdcMem = CreateCompatibleDC(rGfx.GetHDC()); - HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, m_hBackground); - - //Draw the background - //BitBlt the background onto the screen - BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; - AlphaBlend(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight(), hdcMem, 0, 0, GetWidth(), GetHeight(), opblender); - - SelectObject(hdcMem, hbmOld); - DeleteDC(hdcMem); - - //Drawing the cursor - switch(m_eStyle) - { - case STYLE_FILLED: - { - - - HDC hdcMemCursor = CreateCompatibleDC(rGfx.GetHDC()); - - if(m_bUse3P) - { - RECT r = rBoundary; - r.left = 0; - r.right = GetWidth() - m_3PCursorRightWidth - m_3PCursorLeftWidth; - int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)r.left, (float)r.right, - m_fPos); - - int midstart, midwidth; - midstart = m_3PCursorLeftWidth; - midwidth = nBarWidth; - - //Left - hbmOld = (HBITMAP)SelectObject(hdcMemCursor, m_h3PCursorLeft); - - AlphaBlend(rGfx.GetHDC(), 0, 0, m_3PCursorLeftWidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorLeftWidth, m_3PCursorLeftHeight, opblender); - - //Mid - SelectObject(hdcMemCursor, m_h3PCursorMid); - - AlphaBlend(rGfx.GetHDC(), midstart, 0, midwidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorMidWidth, m_3PCursorMidHeight, opblender); - - //Right - SelectObject(hdcMemCursor, m_h3PCursorRight); - - AlphaBlend(rGfx.GetHDC(), midstart+midwidth, 0, m_3PCursorRightWidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorRightWidth, m_3PCursorRightHeight, opblender); - - // restore previous bitmap - SelectObject(hdcMemCursor, hbmOld); - - } - else - { - RECT r = rBoundary; - int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right), - m_fPos); - r.right = nBarWidth ? nBarWidth : r.left; - - HBITMAP hbmOldCursor = (HBITMAP)SelectObject(hdcMemCursor, m_hFiller); - - BitBlt(rGfx.GetHDC(), 0, 0, nBarWidth, GetHeight(), hdcMemCursor, 0, 0, SRCCOPY); - - SelectObject(hdcMemCursor, hbmOldCursor); - } - - DeleteDC(hdcMemCursor); - - break; - } - //These two cases will be the same - case STYLE_CURSOR: - case STYLE_DASHED_CURSOR: - { - HDC hdcMemCursor = CreateCompatibleDC(rGfx.GetHDC()); - - if(m_bUse3P) - { - RECT r = rBoundary; - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), - m_fPos); - r.left = nCursorPos; - r.right = nCursorPos + m_nCursorWidth; - - int midstart, midwidth; - midstart = r.left+m_3PCursorLeftWidth; - midwidth = m_3PCursorMidWidth; - - //Left - hbmOld = (HBITMAP)SelectObject(hdcMemCursor, m_h3PCursorLeft); - - AlphaBlend(rGfx.GetHDC(), r.left, 0, m_3PCursorLeftWidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorLeftWidth, m_3PCursorLeftHeight, opblender); - - //Mid - SelectObject(hdcMemCursor, m_h3PCursorMid); - - AlphaBlend(rGfx.GetHDC(), midstart, 0, midwidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorMidWidth, m_3PCursorMidHeight, opblender); - - //Right - SelectObject(hdcMemCursor, m_h3PCursorRight); - - AlphaBlend(rGfx.GetHDC(), midstart+midwidth, 0, m_3PCursorRightWidth, GetHeight(), - hdcMemCursor, 0, 0, m_3PCursorRightWidth, m_3PCursorRightHeight, opblender); - - // restore old bitmap - SelectObject(hdcMemCursor, hbmOld); - } - else - { - RECT r = rBoundary; - int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, - (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), - m_fPos); - r.left = nCursorPos; - r.right = nCursorPos + m_nCursorWidth; - - HBITMAP hbmOldCursor = (HBITMAP)SelectObject(hdcMemCursor, m_hCursor); - - BitBlt(rGfx.GetHDC(), r.left, 0, m_nCursorWidth, GetHeight(), hdcMemCursor, 0, 0, SRCCOPY); - - SelectObject(hdcMemCursor, hbmOldCursor); - } - - DeleteDC(hdcMemCursor); - - break; - } - default: - break; - } - - if( NULL != m_hHighlight ) - { - HDC hdcMemHighlight = CreateCompatibleDC(rGfx.GetHDC()); - HBITMAP hbmOldHighlight = (HBITMAP)SelectObject(hdcMemHighlight, m_hHighlight); - - AlphaBlend(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight(), hdcMemHighlight, 0, 0, m_HighlightWidth, m_HighlightHeight, opblender); - - SelectObject(hdcMemHighlight, hbmOldHighlight); - DeleteDC(hdcMemHighlight); - } -} - - -//** end of LCDSkinnedProgressBar.cpp ************************************ +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// CLCDSkinnedProgressBar.cpp +// +// Color LCD Skinned Progress Bar class +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::CLCDSkinnedProgressBar +// +//************************************************************************ + +CLCDSkinnedProgressBar::CLCDSkinnedProgressBar(void) +{ + m_hBackground = NULL; + m_hFiller = NULL; + m_hCursor = NULL; + m_hHighlight = NULL; + m_h3PCursorLeft = NULL; + m_h3PCursorMid = NULL; + m_h3PCursorRight = NULL; + + m_BackgroundHeight = 0; + m_BackgroundWidth = 0; + + m_FillerHeight = 0; + m_FillerWidth = 0; + + m_CursorHeight = 0; + m_CursorWidth = 0; + + m_HighlightHeight = 0; + m_HighlightWidth = 0; + + m_bUse3P = FALSE; + + m_3PCursorLeftHeight = 0; + m_3PCursorLeftWidth = 0; + + m_3PCursorMidHeight = 0; + m_3PCursorMidWidth = 0; + + m_3PCursorRightHeight = 0; + m_3PCursorRightWidth = 0; +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::~CLCDSkinnedProgressBar +// +//************************************************************************ + +CLCDSkinnedProgressBar::~CLCDSkinnedProgressBar(void) +{ +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::SetBackground +// +//************************************************************************ + +void CLCDSkinnedProgressBar::SetBackground(HBITMAP background, int bmpWidth, int bmpHeight) +{ + m_hBackground = background; + m_BackgroundHeight = bmpHeight; + m_BackgroundWidth = bmpWidth; + SetSize(bmpWidth, bmpHeight); +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::SetFiller +// +//************************************************************************ + +void CLCDSkinnedProgressBar::SetFiller(HBITMAP cursor, int bmpWidth, int bmpHeight) +{ + m_bUse3P = FALSE; + m_hFiller = cursor; + m_FillerHeight = bmpHeight; + m_FillerWidth = bmpWidth; + SetSize(bmpWidth, bmpHeight); +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::SetCursor +// +//************************************************************************ + +void CLCDSkinnedProgressBar::SetCursor(HBITMAP cursor, int bmpWidth, int bmpHeight) +{ + m_bUse3P = FALSE; + m_hCursor = cursor; + m_CursorHeight = bmpHeight; + m_CursorWidth = bmpWidth; + m_nCursorWidth = m_CursorWidth; +} + + +//************************************************************************ +// +// CLCDSkinnedProgressBar::SetThreePieceCursor +// +//************************************************************************ + +void CLCDSkinnedProgressBar::SetThreePieceCursor(HBITMAP left, int bmpLeftWidth, int bmpLeftHeight, + HBITMAP mid, int bmpMidWidth, int bmpMidHeight, + HBITMAP right, int bmpRightWidth, int bmpRightHeight ) +{ + m_bUse3P = TRUE; + + m_h3PCursorLeft = left; + m_3PCursorLeftHeight = bmpLeftHeight; + m_3PCursorLeftWidth = bmpLeftWidth; + + m_h3PCursorMid = mid; + m_3PCursorMidHeight = bmpMidHeight; + m_3PCursorMidWidth = bmpMidWidth; + + m_h3PCursorRight = right; + m_3PCursorRightHeight = bmpRightHeight; + m_3PCursorRightWidth = bmpRightWidth; + + m_nCursorWidth = m_3PCursorLeftWidth + m_3PCursorMidWidth + m_3PCursorRightWidth; +} + +//************************************************************************ +// +// CLCDSkinnedProgressBar::AddHighlight +// +//************************************************************************ + +void CLCDSkinnedProgressBar::AddHighlight(HBITMAP highlight, int bmpWidth, int bmpHeight) +{ + m_hHighlight = highlight; + m_HighlightHeight = bmpHeight; + m_HighlightWidth = bmpWidth; +} + +//************************************************************************ +// +// CLCDSkinnedProgressBar::OnDraw +// +//************************************************************************ + +void CLCDSkinnedProgressBar::OnDraw(CLCDGfxBase &rGfx) +{ + RECT rBoundary = { 0, 0, GetWidth(), GetHeight() }; + + HDC hdcMem = CreateCompatibleDC(rGfx.GetHDC()); + HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, m_hBackground); + + //Draw the background + //BitBlt the background onto the screen + BLENDFUNCTION opblender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA}; + AlphaBlend(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight(), hdcMem, 0, 0, GetWidth(), GetHeight(), opblender); + + SelectObject(hdcMem, hbmOld); + DeleteDC(hdcMem); + + //Drawing the cursor + switch(m_eStyle) + { + case STYLE_FILLED: + { + + + HDC hdcMemCursor = CreateCompatibleDC(rGfx.GetHDC()); + + if(m_bUse3P) + { + RECT r = rBoundary; + r.left = 0; + r.right = GetWidth() - m_3PCursorRightWidth - m_3PCursorLeftWidth; + int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)r.left, (float)r.right, + m_fPos); + + int midstart, midwidth; + midstart = m_3PCursorLeftWidth; + midwidth = nBarWidth; + + //Left + hbmOld = (HBITMAP)SelectObject(hdcMemCursor, m_h3PCursorLeft); + + AlphaBlend(rGfx.GetHDC(), 0, 0, m_3PCursorLeftWidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorLeftWidth, m_3PCursorLeftHeight, opblender); + + //Mid + SelectObject(hdcMemCursor, m_h3PCursorMid); + + AlphaBlend(rGfx.GetHDC(), midstart, 0, midwidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorMidWidth, m_3PCursorMidHeight, opblender); + + //Right + SelectObject(hdcMemCursor, m_h3PCursorRight); + + AlphaBlend(rGfx.GetHDC(), midstart+midwidth, 0, m_3PCursorRightWidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorRightWidth, m_3PCursorRightHeight, opblender); + + // restore previous bitmap + SelectObject(hdcMemCursor, hbmOld); + + } + else + { + RECT r = rBoundary; + int nBarWidth = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right), + m_fPos); + r.right = nBarWidth ? nBarWidth : r.left; + + HBITMAP hbmOldCursor = (HBITMAP)SelectObject(hdcMemCursor, m_hFiller); + + BitBlt(rGfx.GetHDC(), 0, 0, nBarWidth, GetHeight(), hdcMemCursor, 0, 0, SRCCOPY); + + SelectObject(hdcMemCursor, hbmOldCursor); + } + + DeleteDC(hdcMemCursor); + + break; + } + //These two cases will be the same + case STYLE_CURSOR: + case STYLE_DASHED_CURSOR: + { + HDC hdcMemCursor = CreateCompatibleDC(rGfx.GetHDC()); + + if(m_bUse3P) + { + RECT r = rBoundary; + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), + m_fPos); + r.left = nCursorPos; + r.right = nCursorPos + m_nCursorWidth; + + int midstart, midwidth; + midstart = r.left+m_3PCursorLeftWidth; + midwidth = m_3PCursorMidWidth; + + //Left + hbmOld = (HBITMAP)SelectObject(hdcMemCursor, m_h3PCursorLeft); + + AlphaBlend(rGfx.GetHDC(), r.left, 0, m_3PCursorLeftWidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorLeftWidth, m_3PCursorLeftHeight, opblender); + + //Mid + SelectObject(hdcMemCursor, m_h3PCursorMid); + + AlphaBlend(rGfx.GetHDC(), midstart, 0, midwidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorMidWidth, m_3PCursorMidHeight, opblender); + + //Right + SelectObject(hdcMemCursor, m_h3PCursorRight); + + AlphaBlend(rGfx.GetHDC(), midstart+midwidth, 0, m_3PCursorRightWidth, GetHeight(), + hdcMemCursor, 0, 0, m_3PCursorRightWidth, m_3PCursorRightHeight, opblender); + + // restore old bitmap + SelectObject(hdcMemCursor, hbmOld); + } + else + { + RECT r = rBoundary; + int nCursorPos = (int)Scalef((float)m_Range.nMin, (float)m_Range.nMax, + (float)rBoundary.left, (float)(rBoundary.right - m_nCursorWidth), + m_fPos); + r.left = nCursorPos; + r.right = nCursorPos + m_nCursorWidth; + + HBITMAP hbmOldCursor = (HBITMAP)SelectObject(hdcMemCursor, m_hCursor); + + BitBlt(rGfx.GetHDC(), r.left, 0, m_nCursorWidth, GetHeight(), hdcMemCursor, 0, 0, SRCCOPY); + + SelectObject(hdcMemCursor, hbmOldCursor); + } + + DeleteDC(hdcMemCursor); + + break; + } + default: + break; + } + + if( NULL != m_hHighlight ) + { + HDC hdcMemHighlight = CreateCompatibleDC(rGfx.GetHDC()); + HBITMAP hbmOldHighlight = (HBITMAP)SelectObject(hdcMemHighlight, m_hHighlight); + + AlphaBlend(rGfx.GetHDC(), 0, 0, GetWidth(), GetHeight(), hdcMemHighlight, 0, 0, m_HighlightWidth, m_HighlightHeight, opblender); + + SelectObject(hdcMemHighlight, hbmOldHighlight); + DeleteDC(hdcMemHighlight); + } +} + + +//** end of LCDSkinnedProgressBar.cpp ************************************ diff --git a/src/thirdparty/LCDUI/LCDSkinnedProgressBar.h b/src/thirdparty/LCDUI/LCDSkinnedProgressBar.h index 6c1ec25e28a..3a54778ec81 100644 --- a/src/thirdparty/LCDUI/LCDSkinnedProgressBar.h +++ b/src/thirdparty/LCDUI/LCDSkinnedProgressBar.h @@ -1,83 +1,83 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDSkinnedProgressBar.h -// -// The CLCDSkinnedProgressBar class draws a progress bar onto the color LCD. -// Unlike the other progress bars, this one uses a bitmap resource to draw -// the progress bar. This scrollbar cannot be scaled. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef __LCDSKINNEDPROGRESSBAR_H__ -#define __LCDSKINNEDPROGRESSBAR_H__ - -#include "LCDProgressBar.h" - -class CLCDSkinnedProgressBar : public CLCDProgressBar -{ -public: - CLCDSkinnedProgressBar(void); - virtual ~CLCDSkinnedProgressBar(void); - - //See example bitmaps for how to make the images - void SetBackground(HBITMAP background, int bmpWidth, int bmpHeight); - void SetFiller(HBITMAP cursor, int bmpWidth, int bmpHeight); //STYLE_FILLED - void SetCursor(HBITMAP cursor, int bmpWidth, int bmpHeight); //STYLE_CURSOR - void SetThreePieceCursor(HBITMAP left, int bmpLeftWidth, int bmpLeftHeight, - HBITMAP mid, int bmpMidWidth, int bmpMidHeight, - HBITMAP right, int bmpRightWidth, int bmpRightHeight ); - - //optional -- draw a highlight on top of the progress bar - //(for example, something like a glass effect) - void AddHighlight(HBITMAP highlight, int bmpWidth, int bmpHeight); - - //CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - -private: - HBITMAP m_hBackground; - int m_BackgroundHeight; - int m_BackgroundWidth; - - HBITMAP m_hFiller; - int m_FillerHeight; - int m_FillerWidth; - - HBITMAP m_hCursor; - int m_CursorHeight; - int m_CursorWidth; - - HBITMAP m_hHighlight; - int m_HighlightHeight; - int m_HighlightWidth; - - //3 piece bitmaps, if used - BOOL m_bUse3P; - - HBITMAP m_h3PCursorLeft; - int m_3PCursorLeftHeight; - int m_3PCursorLeftWidth; - - HBITMAP m_h3PCursorMid; - int m_3PCursorMidHeight; - int m_3PCursorMidWidth; - - HBITMAP m_h3PCursorRight; - int m_3PCursorRightHeight; - int m_3PCursorRightWidth; -}; - -#endif - -//** end of LCDSkinnedProgressBar.h ************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDSkinnedProgressBar.h +// +// The CLCDSkinnedProgressBar class draws a progress bar onto the color LCD. +// Unlike the other progress bars, this one uses a bitmap resource to draw +// the progress bar. This scrollbar cannot be scaled. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef __LCDSKINNEDPROGRESSBAR_H__ +#define __LCDSKINNEDPROGRESSBAR_H__ + +#include "LCDProgressBar.h" + +class CLCDSkinnedProgressBar : public CLCDProgressBar +{ +public: + CLCDSkinnedProgressBar(void); + virtual ~CLCDSkinnedProgressBar(void); + + //See example bitmaps for how to make the images + void SetBackground(HBITMAP background, int bmpWidth, int bmpHeight); + void SetFiller(HBITMAP cursor, int bmpWidth, int bmpHeight); //STYLE_FILLED + void SetCursor(HBITMAP cursor, int bmpWidth, int bmpHeight); //STYLE_CURSOR + void SetThreePieceCursor(HBITMAP left, int bmpLeftWidth, int bmpLeftHeight, + HBITMAP mid, int bmpMidWidth, int bmpMidHeight, + HBITMAP right, int bmpRightWidth, int bmpRightHeight ); + + //optional -- draw a highlight on top of the progress bar + //(for example, something like a glass effect) + void AddHighlight(HBITMAP highlight, int bmpWidth, int bmpHeight); + + //CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + +private: + HBITMAP m_hBackground; + int m_BackgroundHeight; + int m_BackgroundWidth; + + HBITMAP m_hFiller; + int m_FillerHeight; + int m_FillerWidth; + + HBITMAP m_hCursor; + int m_CursorHeight; + int m_CursorWidth; + + HBITMAP m_hHighlight; + int m_HighlightHeight; + int m_HighlightWidth; + + //3 piece bitmaps, if used + BOOL m_bUse3P; + + HBITMAP m_h3PCursorLeft; + int m_3PCursorLeftHeight; + int m_3PCursorLeftWidth; + + HBITMAP m_h3PCursorMid; + int m_3PCursorMidHeight; + int m_3PCursorMidWidth; + + HBITMAP m_h3PCursorRight; + int m_3PCursorRightHeight; + int m_3PCursorRightWidth; +}; + +#endif + +//** end of LCDSkinnedProgressBar.h ************************************** diff --git a/src/thirdparty/LCDUI/LCDStreamingText.cpp b/src/thirdparty/LCDUI/LCDStreamingText.cpp index e1dee4d4720..3f55e12ae55 100644 --- a/src/thirdparty/LCDUI/LCDStreamingText.cpp +++ b/src/thirdparty/LCDUI/LCDStreamingText.cpp @@ -1,755 +1,755 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDStreamingText.cpp -// -// The CLCDStreamingText class draws streaming text onto the LCD. -// Streaming text is a single line of text that is repeatedly streamed -// horizontally across the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - -//************************************************************************ -// -// CLCDStreamingText::CLCDStreamingText -// -//************************************************************************ - -CLCDStreamingText::CLCDStreamingText() -{ - m_sText.erase(m_sText.begin(), m_sText.end()); - m_sGapText.erase(m_sGapText.begin(), m_sGapText.end()); - - m_sGapText.assign(_T(" ")); - m_hFont = NULL; - m_nTextAlignment = DT_LEFT; - - m_bRedoColors = TRUE; -} - - -//************************************************************************ -// -// CLCDStreamingText::~CLCDStreamingText -// -//************************************************************************ - -CLCDStreamingText::~CLCDStreamingText() -{ - RemoveAllText(); - if (m_hFont) - { - DeleteObject(m_hFont); - m_hFont = NULL; - } -} - - -//************************************************************************ -// -// CLCDStreamingText::Initialize -// -//************************************************************************ - -HRESULT CLCDStreamingText::Initialize(void) -{ - m_eState = STATE_DELAY; - m_dwStartDelay = 2000; - m_dwSpeed = 7; - m_dwStepInPixels = 7; - m_dwLastUpdate = 0; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_bRecalcExtent = FALSE; - m_pQueueHead = NULL; - m_fFractDistance = 0.0f; - - m_hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); - if(NULL != m_hFont) - { - SetFontPointSize(DEFAULT_POINTSIZE); - } - - //return CLCDCollection::Initialize(); - return ERROR_SUCCESS; -} - - -//************************************************************************ -// -// CLCDStreamingText::ResetUpdate -// -//************************************************************************ - -void CLCDStreamingText::ResetUpdate(void) -{ - m_eState = STATE_DELAY; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - m_pQueueHead = NULL; - m_fFractDistance = 0.0f; - - // remove, re-add, and recalculate the text - m_bRecalcExtent = TRUE; - RemoveAllText(); - AddText(m_sText.c_str()); -} - - -//************************************************************************ -// -// CLCDStreamingText::Show -// -//************************************************************************ - -void CLCDStreamingText::Show(BOOL bShow) -{ - CLCDCollection::Show(bShow); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetText -// -//************************************************************************ - -void CLCDStreamingText::SetText(LPCTSTR szText) -{ - LCDUIASSERT(NULL != szText); - if(szText && _tcscmp(m_sText.c_str(), szText)) - { - m_sText.assign(szText); - m_bRecalcExtent = TRUE; - ResetUpdate(); - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetOrigin -// -//************************************************************************ - -void CLCDStreamingText::SetOrigin(POINT pt) -{ - m_Origin = pt; - SetOrigin(pt.x, pt.y); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetOrigin -// -//************************************************************************ - -void CLCDStreamingText::SetOrigin(int nX, int nY) -{ - m_Origin.x = nX; - m_Origin.y = nY; - - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it++; - LCDUIASSERT(NULL != pObject); - - POINT ptOldOrigin = pObject->GetOrigin(); - pObject->SetOrigin(nX, nY); - - if ( (ptOldOrigin.x != nX) && (ptOldOrigin.y != nY) ) - { - ResetUpdate(); - break; - } - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetSize -// -//************************************************************************ - -void CLCDStreamingText::SetSize(SIZE& size) -{ - CLCDBase::SetSize(size); - - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - if (it != m_Objects.end()) - { - CLCDBase *pObject = *it; - pObject->SetSize(size); - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetSize -// -//************************************************************************ - -void CLCDStreamingText::SetSize(int nCX, int nCY) -{ - SIZE size = { nCX, nCY }; - SetSize(size); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetBackgroundMode -// -//************************************************************************ - -void CLCDStreamingText::SetBackgroundMode(int nMode) -{ - m_bRedoColors = TRUE; - CLCDBase::SetBackgroundMode(nMode); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetForegroundColor -// -//************************************************************************ - -void CLCDStreamingText::SetForegroundColor(COLORREF crForeground) -{ - m_bRedoColors = TRUE; - CLCDBase::SetForegroundColor(crForeground); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetBackgroundColor -// -//************************************************************************ - -void CLCDStreamingText::SetBackgroundColor(COLORREF crBackground) -{ - m_bRedoColors = TRUE; - CLCDBase::SetBackgroundColor(crBackground); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetGapText -// -//************************************************************************ - -void CLCDStreamingText::SetGapText(LPCTSTR szGapText) -{ - LCDUIASSERT(NULL != szGapText); - if(szGapText && _tcscmp(m_sGapText.c_str(), szGapText)) - { - m_sGapText.assign(szGapText); - m_bRecalcExtent = TRUE; - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetFont -// -//************************************************************************ - -void CLCDStreamingText::SetFont(LOGFONT& lf) -{ - if (m_hFont) - { - DeleteObject(m_hFont); - m_hFont = NULL; - } - - m_hFont = CreateFontIndirect(&lf); - m_bRecalcExtent = TRUE; -} - - -//************************************************************************ -// -// CLCDStreamingText::GetFont -// -//************************************************************************ - -HFONT CLCDStreamingText::GetFont() -{ - return m_hFont; -} - - -//************************************************************************ -// -// CLCDText::SetFontFaceName -// -//************************************************************************ - -void CLCDStreamingText::SetFontFaceName(LPCTSTR szFontName) -{ - // if NULL, uses the default gui font - if (NULL == szFontName) - return; - - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - DeleteObject(m_hFont); - m_hFont = NULL; - - LCDUI_tcsncpy(lf.lfFaceName, szFontName, LF_FACESIZE); - - m_hFont = CreateFontIndirect(&lf); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetFontPointSize -// -//************************************************************************ - -void CLCDStreamingText::SetFontPointSize(int nPointSize) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - DeleteObject(m_hFont); - m_hFont = NULL; - - lf.lfHeight = -MulDiv(nPointSize, DEFAULT_DPI, 72); - - m_hFont = CreateFontIndirect(&lf); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetFontWeight -// -//************************************************************************ - -void CLCDStreamingText::SetFontWeight(int nWeight) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - DeleteObject(m_hFont); - m_hFont = NULL; - - lf.lfWeight = nWeight; - - m_hFont = CreateFontIndirect(&lf); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetFontColor -// -//************************************************************************ - -void CLCDStreamingText::SetFontColor(COLORREF color) -{ - SetForegroundColor(color); - - // Apply it to any existing text objects - for (size_t i = 0; i < m_Objects.size(); i++) - { - m_Objects[i]->SetForegroundColor(color); - } -} - - -//************************************************************************ -// -// CLCDStreamingText::SetAlignment -// -// only relevant if no streaming -//************************************************************************ - -void CLCDStreamingText::SetAlignment(int nAlignment) -{ - m_nTextAlignment = nAlignment; -} - - -//************************************************************************ -// -// CLCDStreamingText::AddText -// -//************************************************************************ - -int CLCDStreamingText::AddText(LPCTSTR szText) -{ - - CLCDText* pText = new CLCDText; - pText->Initialize(); - pText->SetText(szText); - pText->SetOrigin(GetOrigin().x, GetOrigin().y); - pText->SetLogicalOrigin(GetLogicalOrigin().x, GetLogicalOrigin().y); - pText->SetSize(GetWidth(), GetHeight()); - pText->SetBackgroundMode(m_nBkMode); - pText->SetBackgroundColor(m_crBackgroundColor); - pText->SetFontColor(m_crForegroundColor); - - LOGFONT lf; - GetObject(m_hFont, sizeof(LOGFONT), &lf); - pText->SetFont(lf); - - m_bRecalcExtent = TRUE; - - AddObject(pText); - - - if (NULL == m_pQueueHead) - { - m_pQueueHead = pText; - } - - // return the zero-based index - return (int)(m_Objects.size()-1); -} - - -//************************************************************************ -// -// CLCDStreamingText::RemoveText -// -//************************************************************************ - -void CLCDStreamingText::RemoveText(int nIndex) -{ - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - int i = 0; - while(it != m_Objects.end()) - { - CLCDBase *pObject = *it; - LCDUIASSERT(NULL != pObject); - - if (i == nIndex) - { - m_Objects.erase(it); - if(NULL != pObject) - { - delete pObject; - } - break; - } - - ++it; - ++i; - } -} - - -//************************************************************************ -// -// CLCDStreamingText::RemoveAllText -// -//************************************************************************ - -void CLCDStreamingText::RemoveAllText() -{ - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - // we need to delete all the text objects that were placed in to m_Objects - CLCDBase *pObject = *it; - LCDUIASSERT(NULL != pObject); - - if(NULL != pObject) - { - delete pObject; - } - ++it; - } - m_Objects.erase(m_Objects.begin(), m_Objects.end()); -} - - -//************************************************************************ -// -// CLCDStreamingText::SetStartDelay -// -//************************************************************************ - -void CLCDStreamingText::SetStartDelay(DWORD dwMilliseconds) -{ - m_dwStartDelay = dwMilliseconds; -} - - -//************************************************************************ -// -// CLCDStreamingText::SetSpeed -// -//************************************************************************ - -void CLCDStreamingText::SetSpeed(DWORD dwSpeed) -{ - m_dwSpeed = dwSpeed; -} - -//************************************************************************ -// -// CLCDStreamingText::SetScrollingStep: sets the number of pixels the text -// will jump when it scrolls -// -//************************************************************************ - -void CLCDStreamingText::SetScrollingStep(DWORD dwStepInPixels) -{ - m_dwStepInPixels = dwStepInPixels; -} - -//************************************************************************ -// -// CLCDStreamingText::OnUpdate -// -//************************************************************************ - -void CLCDStreamingText::OnUpdate(DWORD dwTimestamp) -{ - m_dwEllapsedTime = (dwTimestamp - m_dwLastUpdate); -} - - -//************************************************************************ -// -// CLCDStreamingText::OnDraw -// -//************************************************************************ - -void CLCDStreamingText::OnDraw(CLCDGfxBase &rGfx) -{ - - if (m_bRecalcExtent) - { - // this just recalculates the text extents - RecalcTextBoxes(rGfx); - m_bRecalcExtent = FALSE; - return; - } - - switch(m_eState) - { - case STATE_DELAY: - if (m_dwEllapsedTime > m_dwStartDelay) - { - m_eState = STATE_SCROLL; - m_dwEllapsedTime = 0; - m_dwLastUpdate = GetTickCount(); - } - break; - case STATE_SCROLL: - { - // update the positions - float fDistance = (float)(m_dwSpeed * m_dwEllapsedTime) / 1000.0f; - m_dwLastUpdate = GetTickCount(); - - if (m_Objects.size() > 1) - { - // extract any previous fractional remainder - // and add it to the current distance - float fTotDistance = (fDistance + m_fFractDistance); - m_fFractDistance = (fTotDistance >= (float)m_dwStepInPixels) ? (float)(fTotDistance - (int)fTotDistance) : fTotDistance; - - if (fTotDistance < 0.0f) - fTotDistance = 0.0f; - if (m_fFractDistance < 0.0f) - m_fFractDistance = 0.0f; - - if (fTotDistance >= (float)m_dwStepInPixels) - ApplyOrigins(-1 * (int)fTotDistance); // left - } - } - break; - default: - break; - } - - if( m_bRedoColors ) - { - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - // we need to delete all the text objects that were placed in to m_Objects - CLCDBase *pObject = *it; - LCDUIASSERT(NULL != pObject); - - if(NULL != pObject) - { - pObject->SetBackgroundMode(m_nBkMode); - pObject->SetBackgroundColor(m_crBackgroundColor); - pObject->SetForegroundColor(m_crForegroundColor); - } - ++it; - } - - m_bRedoColors = FALSE; - } - - CLCDCollection::OnDraw(rGfx); -} - - -//************************************************************************ -// -// CLCDStreamingText::C -// -//************************************************************************ - -BOOL CLCDStreamingText::RecalcTextBoxes(CLCDGfxBase &rGfx) -{ - - // check if we need to add another text box - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - - if (it == m_Objects.end()) - return FALSE; - - CLCDBase* pObject = *it; - CLCDText* pText = (CLCDText*)pObject; - LCDUIASSERT(NULL != pObject); - - LOGFONT lf; - GetObject(m_hFont, sizeof(LOGFONT), &lf); - pText->SetFont(lf); - - // this will re-evaluate the main text object - LCDUIASSERT(m_Objects.size() == 1); - pText->CalculateExtent(TRUE); - - if (it != m_Objects.end()) - { - if (pText->GetHExtent().cx > GetWidth()) - { - - pText->SetAlignment(DT_LEFT); - - // add a gap - AddText(m_sGapText.c_str()); - // add another text - AddText(m_sText.c_str()); - // add last gap - AddText(m_sGapText.c_str()); - } - else - { - pText->SetAlignment(m_nTextAlignment); - } - } - - // this will re-evaluate the other text objects - CLCDCollection::OnDraw(rGfx); - RecalcTextBoxOrigins(); - - return TRUE; -} - - -//************************************************************************ -// -// CLCDStreamingText::RecalcTextBoxOrigins -// -// Puts all the text boxes in order next to each other -//************************************************************************ - -void CLCDStreamingText::RecalcTextBoxOrigins() -{ - - if (m_Objects.size() <= 1) - return; - - // draw everyone to the left by the offset - int nOrgOffset = 0; - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase* pObject = *it; - CLCDText* pText = (CLCDText*)pObject; - LCDUIASSERT(NULL != pObject); - - pText->SetLogicalSize(pText->GetHExtent().cx, pText->GetHExtent().cy); - - // string can be empty which generates zero logical space - //LCDUIASSERT(pText->GetLogicalSize().cx); - //LCDUIASSERT(pText->GetLogicalSize().cy); - - POINT& ptOrigin = pText->GetLogicalOrigin(); - - if (nOrgOffset == 0) - { - nOrgOffset = pText->GetLogicalOrigin().x; - } - - pText->SetLogicalOrigin(nOrgOffset, ptOrigin.y); - nOrgOffset += pText->GetHExtent().cx; - - ++it; - } - -} - - -//************************************************************************ -// -// CLCDStreamingText::ApplyOrigins -// -//************************************************************************ - -void CLCDStreamingText::ApplyOrigins(int nOffset) -{ - - // draw everyone to the left by the offset - LCD_OBJECT_LIST::iterator it = m_Objects.begin(); - while(it != m_Objects.end()) - { - CLCDBase* pObject = *it; - CLCDText* pText = (CLCDText*)pObject; - LCDUIASSERT(NULL != pObject); - - POINT& ptOrigin = pText->GetLogicalOrigin(); - - pText->SetLogicalOrigin(ptOrigin.x + nOffset, ptOrigin.y); - - ++it; - } - - // If the active box is no longer visible, - // pop it off the push it to the end of the list - if (abs(m_pQueueHead->GetLogicalOrigin().x) >= m_pQueueHead->GetHExtent().cx) - { - RemoveObject(0); - AddObject(m_pQueueHead); - RecalcTextBoxOrigins(); - m_pQueueHead = (CLCDText*)RetrieveObject(0); - } -} - - -//** end of LCDStreamingText.cpp ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDStreamingText.cpp +// +// The CLCDStreamingText class draws streaming text onto the LCD. +// Streaming text is a single line of text that is repeatedly streamed +// horizontally across the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + +//************************************************************************ +// +// CLCDStreamingText::CLCDStreamingText +// +//************************************************************************ + +CLCDStreamingText::CLCDStreamingText() +{ + m_sText.erase(m_sText.begin(), m_sText.end()); + m_sGapText.erase(m_sGapText.begin(), m_sGapText.end()); + + m_sGapText.assign(_T(" ")); + m_hFont = NULL; + m_nTextAlignment = DT_LEFT; + + m_bRedoColors = TRUE; +} + + +//************************************************************************ +// +// CLCDStreamingText::~CLCDStreamingText +// +//************************************************************************ + +CLCDStreamingText::~CLCDStreamingText() +{ + RemoveAllText(); + if (m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } +} + + +//************************************************************************ +// +// CLCDStreamingText::Initialize +// +//************************************************************************ + +HRESULT CLCDStreamingText::Initialize(void) +{ + m_eState = STATE_DELAY; + m_dwStartDelay = 2000; + m_dwSpeed = 7; + m_dwStepInPixels = 7; + m_dwLastUpdate = 0; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_bRecalcExtent = FALSE; + m_pQueueHead = NULL; + m_fFractDistance = 0.0f; + + m_hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); + if(NULL != m_hFont) + { + SetFontPointSize(DEFAULT_POINTSIZE); + } + + //return CLCDCollection::Initialize(); + return ERROR_SUCCESS; +} + + +//************************************************************************ +// +// CLCDStreamingText::ResetUpdate +// +//************************************************************************ + +void CLCDStreamingText::ResetUpdate(void) +{ + m_eState = STATE_DELAY; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + m_pQueueHead = NULL; + m_fFractDistance = 0.0f; + + // remove, re-add, and recalculate the text + m_bRecalcExtent = TRUE; + RemoveAllText(); + AddText(m_sText.c_str()); +} + + +//************************************************************************ +// +// CLCDStreamingText::Show +// +//************************************************************************ + +void CLCDStreamingText::Show(BOOL bShow) +{ + CLCDCollection::Show(bShow); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetText +// +//************************************************************************ + +void CLCDStreamingText::SetText(LPCTSTR szText) +{ + LCDUIASSERT(NULL != szText); + if(szText && _tcscmp(m_sText.c_str(), szText)) + { + m_sText.assign(szText); + m_bRecalcExtent = TRUE; + ResetUpdate(); + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetOrigin +// +//************************************************************************ + +void CLCDStreamingText::SetOrigin(POINT pt) +{ + m_Origin = pt; + SetOrigin(pt.x, pt.y); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetOrigin +// +//************************************************************************ + +void CLCDStreamingText::SetOrigin(int nX, int nY) +{ + m_Origin.x = nX; + m_Origin.y = nY; + + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it++; + LCDUIASSERT(NULL != pObject); + + POINT ptOldOrigin = pObject->GetOrigin(); + pObject->SetOrigin(nX, nY); + + if ( (ptOldOrigin.x != nX) && (ptOldOrigin.y != nY) ) + { + ResetUpdate(); + break; + } + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetSize +// +//************************************************************************ + +void CLCDStreamingText::SetSize(SIZE& size) +{ + CLCDBase::SetSize(size); + + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + if (it != m_Objects.end()) + { + CLCDBase *pObject = *it; + pObject->SetSize(size); + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetSize +// +//************************************************************************ + +void CLCDStreamingText::SetSize(int nCX, int nCY) +{ + SIZE size = { nCX, nCY }; + SetSize(size); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetBackgroundMode +// +//************************************************************************ + +void CLCDStreamingText::SetBackgroundMode(int nMode) +{ + m_bRedoColors = TRUE; + CLCDBase::SetBackgroundMode(nMode); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetForegroundColor +// +//************************************************************************ + +void CLCDStreamingText::SetForegroundColor(COLORREF crForeground) +{ + m_bRedoColors = TRUE; + CLCDBase::SetForegroundColor(crForeground); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetBackgroundColor +// +//************************************************************************ + +void CLCDStreamingText::SetBackgroundColor(COLORREF crBackground) +{ + m_bRedoColors = TRUE; + CLCDBase::SetBackgroundColor(crBackground); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetGapText +// +//************************************************************************ + +void CLCDStreamingText::SetGapText(LPCTSTR szGapText) +{ + LCDUIASSERT(NULL != szGapText); + if(szGapText && _tcscmp(m_sGapText.c_str(), szGapText)) + { + m_sGapText.assign(szGapText); + m_bRecalcExtent = TRUE; + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetFont +// +//************************************************************************ + +void CLCDStreamingText::SetFont(LOGFONT& lf) +{ + if (m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } + + m_hFont = CreateFontIndirect(&lf); + m_bRecalcExtent = TRUE; +} + + +//************************************************************************ +// +// CLCDStreamingText::GetFont +// +//************************************************************************ + +HFONT CLCDStreamingText::GetFont() +{ + return m_hFont; +} + + +//************************************************************************ +// +// CLCDText::SetFontFaceName +// +//************************************************************************ + +void CLCDStreamingText::SetFontFaceName(LPCTSTR szFontName) +{ + // if NULL, uses the default gui font + if (NULL == szFontName) + return; + + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + DeleteObject(m_hFont); + m_hFont = NULL; + + LCDUI_tcsncpy(lf.lfFaceName, szFontName, LF_FACESIZE); + + m_hFont = CreateFontIndirect(&lf); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetFontPointSize +// +//************************************************************************ + +void CLCDStreamingText::SetFontPointSize(int nPointSize) +{ + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + DeleteObject(m_hFont); + m_hFont = NULL; + + lf.lfHeight = -MulDiv(nPointSize, DEFAULT_DPI, 72); + + m_hFont = CreateFontIndirect(&lf); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetFontWeight +// +//************************************************************************ + +void CLCDStreamingText::SetFontWeight(int nWeight) +{ + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + DeleteObject(m_hFont); + m_hFont = NULL; + + lf.lfWeight = nWeight; + + m_hFont = CreateFontIndirect(&lf); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetFontColor +// +//************************************************************************ + +void CLCDStreamingText::SetFontColor(COLORREF color) +{ + SetForegroundColor(color); + + // Apply it to any existing text objects + for (size_t i = 0; i < m_Objects.size(); i++) + { + m_Objects[i]->SetForegroundColor(color); + } +} + + +//************************************************************************ +// +// CLCDStreamingText::SetAlignment +// +// only relevant if no streaming +//************************************************************************ + +void CLCDStreamingText::SetAlignment(int nAlignment) +{ + m_nTextAlignment = nAlignment; +} + + +//************************************************************************ +// +// CLCDStreamingText::AddText +// +//************************************************************************ + +int CLCDStreamingText::AddText(LPCTSTR szText) +{ + + CLCDText* pText = new CLCDText; + pText->Initialize(); + pText->SetText(szText); + pText->SetOrigin(GetOrigin().x, GetOrigin().y); + pText->SetLogicalOrigin(GetLogicalOrigin().x, GetLogicalOrigin().y); + pText->SetSize(GetWidth(), GetHeight()); + pText->SetBackgroundMode(m_nBkMode); + pText->SetBackgroundColor(m_crBackgroundColor); + pText->SetFontColor(m_crForegroundColor); + + LOGFONT lf; + GetObject(m_hFont, sizeof(LOGFONT), &lf); + pText->SetFont(lf); + + m_bRecalcExtent = TRUE; + + AddObject(pText); + + + if (NULL == m_pQueueHead) + { + m_pQueueHead = pText; + } + + // return the zero-based index + return (int)(m_Objects.size()-1); +} + + +//************************************************************************ +// +// CLCDStreamingText::RemoveText +// +//************************************************************************ + +void CLCDStreamingText::RemoveText(int nIndex) +{ + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + int i = 0; + while(it != m_Objects.end()) + { + CLCDBase *pObject = *it; + LCDUIASSERT(NULL != pObject); + + if (i == nIndex) + { + m_Objects.erase(it); + if(NULL != pObject) + { + delete pObject; + } + break; + } + + ++it; + ++i; + } +} + + +//************************************************************************ +// +// CLCDStreamingText::RemoveAllText +// +//************************************************************************ + +void CLCDStreamingText::RemoveAllText() +{ + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + // we need to delete all the text objects that were placed in to m_Objects + CLCDBase *pObject = *it; + LCDUIASSERT(NULL != pObject); + + if(NULL != pObject) + { + delete pObject; + } + ++it; + } + m_Objects.erase(m_Objects.begin(), m_Objects.end()); +} + + +//************************************************************************ +// +// CLCDStreamingText::SetStartDelay +// +//************************************************************************ + +void CLCDStreamingText::SetStartDelay(DWORD dwMilliseconds) +{ + m_dwStartDelay = dwMilliseconds; +} + + +//************************************************************************ +// +// CLCDStreamingText::SetSpeed +// +//************************************************************************ + +void CLCDStreamingText::SetSpeed(DWORD dwSpeed) +{ + m_dwSpeed = dwSpeed; +} + +//************************************************************************ +// +// CLCDStreamingText::SetScrollingStep: sets the number of pixels the text +// will jump when it scrolls +// +//************************************************************************ + +void CLCDStreamingText::SetScrollingStep(DWORD dwStepInPixels) +{ + m_dwStepInPixels = dwStepInPixels; +} + +//************************************************************************ +// +// CLCDStreamingText::OnUpdate +// +//************************************************************************ + +void CLCDStreamingText::OnUpdate(DWORD dwTimestamp) +{ + m_dwEllapsedTime = (dwTimestamp - m_dwLastUpdate); +} + + +//************************************************************************ +// +// CLCDStreamingText::OnDraw +// +//************************************************************************ + +void CLCDStreamingText::OnDraw(CLCDGfxBase &rGfx) +{ + + if (m_bRecalcExtent) + { + // this just recalculates the text extents + RecalcTextBoxes(rGfx); + m_bRecalcExtent = FALSE; + return; + } + + switch(m_eState) + { + case STATE_DELAY: + if (m_dwEllapsedTime > m_dwStartDelay) + { + m_eState = STATE_SCROLL; + m_dwEllapsedTime = 0; + m_dwLastUpdate = GetTickCount(); + } + break; + case STATE_SCROLL: + { + // update the positions + float fDistance = (float)(m_dwSpeed * m_dwEllapsedTime) / 1000.0f; + m_dwLastUpdate = GetTickCount(); + + if (m_Objects.size() > 1) + { + // extract any previous fractional remainder + // and add it to the current distance + float fTotDistance = (fDistance + m_fFractDistance); + m_fFractDistance = (fTotDistance >= (float)m_dwStepInPixels) ? (float)(fTotDistance - (int)fTotDistance) : fTotDistance; + + if (fTotDistance < 0.0f) + fTotDistance = 0.0f; + if (m_fFractDistance < 0.0f) + m_fFractDistance = 0.0f; + + if (fTotDistance >= (float)m_dwStepInPixels) + ApplyOrigins(-1 * (int)fTotDistance); // left + } + } + break; + default: + break; + } + + if( m_bRedoColors ) + { + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + // we need to delete all the text objects that were placed in to m_Objects + CLCDBase *pObject = *it; + LCDUIASSERT(NULL != pObject); + + if(NULL != pObject) + { + pObject->SetBackgroundMode(m_nBkMode); + pObject->SetBackgroundColor(m_crBackgroundColor); + pObject->SetForegroundColor(m_crForegroundColor); + } + ++it; + } + + m_bRedoColors = FALSE; + } + + CLCDCollection::OnDraw(rGfx); +} + + +//************************************************************************ +// +// CLCDStreamingText::C +// +//************************************************************************ + +BOOL CLCDStreamingText::RecalcTextBoxes(CLCDGfxBase &rGfx) +{ + + // check if we need to add another text box + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + + if (it == m_Objects.end()) + return FALSE; + + CLCDBase* pObject = *it; + CLCDText* pText = (CLCDText*)pObject; + LCDUIASSERT(NULL != pObject); + + LOGFONT lf; + GetObject(m_hFont, sizeof(LOGFONT), &lf); + pText->SetFont(lf); + + // this will re-evaluate the main text object + LCDUIASSERT(m_Objects.size() == 1); + pText->CalculateExtent(TRUE); + + if (it != m_Objects.end()) + { + if (pText->GetHExtent().cx > GetWidth()) + { + + pText->SetAlignment(DT_LEFT); + + // add a gap + AddText(m_sGapText.c_str()); + // add another text + AddText(m_sText.c_str()); + // add last gap + AddText(m_sGapText.c_str()); + } + else + { + pText->SetAlignment(m_nTextAlignment); + } + } + + // this will re-evaluate the other text objects + CLCDCollection::OnDraw(rGfx); + RecalcTextBoxOrigins(); + + return TRUE; +} + + +//************************************************************************ +// +// CLCDStreamingText::RecalcTextBoxOrigins +// +// Puts all the text boxes in order next to each other +//************************************************************************ + +void CLCDStreamingText::RecalcTextBoxOrigins() +{ + + if (m_Objects.size() <= 1) + return; + + // draw everyone to the left by the offset + int nOrgOffset = 0; + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase* pObject = *it; + CLCDText* pText = (CLCDText*)pObject; + LCDUIASSERT(NULL != pObject); + + pText->SetLogicalSize(pText->GetHExtent().cx, pText->GetHExtent().cy); + + // string can be empty which generates zero logical space + //LCDUIASSERT(pText->GetLogicalSize().cx); + //LCDUIASSERT(pText->GetLogicalSize().cy); + + POINT& ptOrigin = pText->GetLogicalOrigin(); + + if (nOrgOffset == 0) + { + nOrgOffset = pText->GetLogicalOrigin().x; + } + + pText->SetLogicalOrigin(nOrgOffset, ptOrigin.y); + nOrgOffset += pText->GetHExtent().cx; + + ++it; + } + +} + + +//************************************************************************ +// +// CLCDStreamingText::ApplyOrigins +// +//************************************************************************ + +void CLCDStreamingText::ApplyOrigins(int nOffset) +{ + + // draw everyone to the left by the offset + LCD_OBJECT_LIST::iterator it = m_Objects.begin(); + while(it != m_Objects.end()) + { + CLCDBase* pObject = *it; + CLCDText* pText = (CLCDText*)pObject; + LCDUIASSERT(NULL != pObject); + + POINT& ptOrigin = pText->GetLogicalOrigin(); + + pText->SetLogicalOrigin(ptOrigin.x + nOffset, ptOrigin.y); + + ++it; + } + + // If the active box is no longer visible, + // pop it off the push it to the end of the list + if (abs(m_pQueueHead->GetLogicalOrigin().x) >= m_pQueueHead->GetHExtent().cx) + { + RemoveObject(0); + AddObject(m_pQueueHead); + RecalcTextBoxOrigins(); + m_pQueueHead = (CLCDText*)RetrieveObject(0); + } +} + + +//** end of LCDStreamingText.cpp ******************************************* diff --git a/src/thirdparty/LCDUI/LCDStreamingText.h b/src/thirdparty/LCDUI/LCDStreamingText.h index 1848ad364f8..d4c9880d758 100644 --- a/src/thirdparty/LCDUI/LCDStreamingText.h +++ b/src/thirdparty/LCDUI/LCDStreamingText.h @@ -1,120 +1,120 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDStreamingText.h -// -// The CLCDStreamingText class draws streaming text onto the LCD. -// Streaming text is a single line of text that is repeatedly streamed -// horizontally across the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDSTREAMINGTEXT_H_INCLUDED_ -#define _LCDSTREAMINGTEXT_H_INCLUDED_ - -#include "LCDBase.h" -#include "LCDCollection.h" -#include "LCDText.h" - -#include - -class CLCDStreamingText: public CLCDCollection -{ - -public: - CLCDStreamingText(); - virtual ~CLCDStreamingText(); - - // CLCDBase - virtual HRESULT Initialize(void); - virtual void ResetUpdate(void); - virtual void Show(BOOL bShow); - virtual void SetOrigin(POINT pt); - virtual void SetOrigin(int nX, int nY); - virtual void SetSize(SIZE& size); - virtual void SetSize(int nCX, int nCY); - virtual void SetBackgroundMode(int nMode); - virtual void SetForegroundColor(COLORREF crForeground); - virtual void SetBackgroundColor(COLORREF crBackground); - - void SetText(LPCTSTR szText); - void SetGapText(LPCTSTR szGapText); - void SetStartDelay(DWORD dwMilliseconds); - void SetSpeed(DWORD dwSpeed); - void SetScrollingStep(DWORD dwStepInPixels); - void SetAlignment(int nAlignment = DT_LEFT); - void SetFont(LOGFONT& lf); - void SetFontFaceName(LPCTSTR szFontName); - void SetFontPointSize(int nSize); - void SetFontWeight(int nPointSize); - void SetFontColor(COLORREF color); - HFONT GetFont(void); - - enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 8 }; - -protected: - virtual void OnUpdate(DWORD dwTimestamp); - virtual void OnDraw(CLCDGfxBase &rGfx); - -private: - int AddText(LPCTSTR szText); - void RemoveText(int nIndex); - void RemoveAllText(); - -private: - BOOL RecalcTextBoxes(CLCDGfxBase &rGfx); - void RecalcTextBoxOrigins(); - void ApplyOrigins(int nOffset); - - enum eSCROLL_STATES { STATE_DELAY, STATE_SCROLL}; - - // ellapsed time in state - DWORD m_dwEllapsedTime; - - // milliseconds - DWORD m_dwStartDelay; - - // pixels/second - DWORD m_dwSpeed; - - // Number of pixels to shift - DWORD m_dwStepInPixels; - - // milliseconds - DWORD m_dwLastUpdate; - - eSCROLL_STATES m_eState; - BOOL m_bRecalcExtent; - - CLCDText *m_pQueueHead; - - COLORREF m_crColor; - BOOL m_bRedoColors; - -#ifdef UNICODE - std::wstring m_sText; - std::wstring m_sGapText; -#else - std::string m_sText; - std::string m_sGapText; -#endif - - HFONT m_hFont; - int m_nTextAlignment; - float m_fFractDistance; -}; - - -#endif // !_LCDSTREAMINGTEXT_H_INCLUDED_ - -//** end of LCDStreamingText.h ******************************************* +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDStreamingText.h +// +// The CLCDStreamingText class draws streaming text onto the LCD. +// Streaming text is a single line of text that is repeatedly streamed +// horizontally across the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDSTREAMINGTEXT_H_INCLUDED_ +#define _LCDSTREAMINGTEXT_H_INCLUDED_ + +#include "LCDBase.h" +#include "LCDCollection.h" +#include "LCDText.h" + +#include + +class CLCDStreamingText: public CLCDCollection +{ + +public: + CLCDStreamingText(); + virtual ~CLCDStreamingText(); + + // CLCDBase + virtual HRESULT Initialize(void); + virtual void ResetUpdate(void); + virtual void Show(BOOL bShow); + virtual void SetOrigin(POINT pt); + virtual void SetOrigin(int nX, int nY); + virtual void SetSize(SIZE& size); + virtual void SetSize(int nCX, int nCY); + virtual void SetBackgroundMode(int nMode); + virtual void SetForegroundColor(COLORREF crForeground); + virtual void SetBackgroundColor(COLORREF crBackground); + + void SetText(LPCTSTR szText); + void SetGapText(LPCTSTR szGapText); + void SetStartDelay(DWORD dwMilliseconds); + void SetSpeed(DWORD dwSpeed); + void SetScrollingStep(DWORD dwStepInPixels); + void SetAlignment(int nAlignment = DT_LEFT); + void SetFont(LOGFONT& lf); + void SetFontFaceName(LPCTSTR szFontName); + void SetFontPointSize(int nSize); + void SetFontWeight(int nPointSize); + void SetFontColor(COLORREF color); + HFONT GetFont(void); + + enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 8 }; + +protected: + virtual void OnUpdate(DWORD dwTimestamp); + virtual void OnDraw(CLCDGfxBase &rGfx); + +private: + int AddText(LPCTSTR szText); + void RemoveText(int nIndex); + void RemoveAllText(); + +private: + BOOL RecalcTextBoxes(CLCDGfxBase &rGfx); + void RecalcTextBoxOrigins(); + void ApplyOrigins(int nOffset); + + enum eSCROLL_STATES { STATE_DELAY, STATE_SCROLL}; + + // ellapsed time in state + DWORD m_dwEllapsedTime; + + // milliseconds + DWORD m_dwStartDelay; + + // pixels/second + DWORD m_dwSpeed; + + // Number of pixels to shift + DWORD m_dwStepInPixels; + + // milliseconds + DWORD m_dwLastUpdate; + + eSCROLL_STATES m_eState; + BOOL m_bRecalcExtent; + + CLCDText *m_pQueueHead; + + COLORREF m_crColor; + BOOL m_bRedoColors; + +#ifdef UNICODE + std::wstring m_sText; + std::wstring m_sGapText; +#else + std::string m_sText; + std::string m_sGapText; +#endif + + HFONT m_hFont; + int m_nTextAlignment; + float m_fFractDistance; +}; + + +#endif // !_LCDSTREAMINGTEXT_H_INCLUDED_ + +//** end of LCDStreamingText.h ******************************************* diff --git a/src/thirdparty/LCDUI/LCDText.cpp b/src/thirdparty/LCDUI/LCDText.cpp index 67e8a2da24f..94d9d030c6e 100644 --- a/src/thirdparty/LCDUI/LCDText.cpp +++ b/src/thirdparty/LCDUI/LCDText.cpp @@ -1,467 +1,467 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDText.cpp -// -// The CLCDText class draws simple text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#include "LCDUI.h" - - -//************************************************************************ -// -// CLCDText::CLCDText -// -//************************************************************************ - -CLCDText::CLCDText(void) -: m_hFont(NULL), - m_nTextLength(0), - m_nTextFormat(DT_LEFT | DT_NOPREFIX), - m_bRecalcExtent(TRUE), - m_nTextAlignment(DT_LEFT) -{ - ZeroMemory(&m_dtp, sizeof(DRAWTEXTPARAMS)); - m_dtp.cbSize = sizeof(DRAWTEXTPARAMS); - ZeroMemory(&m_sizeVExtent, sizeof(m_sizeVExtent)); - ZeroMemory(&m_sizeHExtent, sizeof(m_sizeHExtent)); - SetBackgroundMode(TRANSPARENT); - Initialize(); -} - - -//************************************************************************ -// -// CLCDText::~CLCDText -// -//************************************************************************ - -CLCDText::~CLCDText(void) -{ - if (m_hFont) - { - DeleteObject(m_hFont); - m_hFont = NULL; - } -} - - -//************************************************************************ -// -// CLCDText::Initialize -// -//************************************************************************ - -HRESULT CLCDText::Initialize() -{ - m_hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); - if(NULL != m_hFont) - { - SetFontPointSize(DEFAULT_POINTSIZE); - } - SetForegroundColor(RGB(255, 255, 255)); - return (NULL != m_hFont) ? S_OK : E_OUTOFMEMORY; -} - - -//************************************************************************ -// -// CLCDText::SetFont -// -//************************************************************************ - -void CLCDText::SetFont(LOGFONT& lf) -{ - if (m_hFont) - { - DeleteObject(m_hFont); - m_hFont = NULL; - } - - m_hFont = CreateFontIndirect(&lf); - m_bRecalcExtent = TRUE; -} - - -//************************************************************************ -// -// CLCDText::GetFont -// -//************************************************************************ - -HFONT CLCDText::GetFont() -{ - return m_hFont; -} - - -//************************************************************************ -// -// CLCDText::SetFontFaceName -// -//************************************************************************ - -void CLCDText::SetFontFaceName(LPCTSTR szFontName) -{ - // if NULL, uses the default gui font - if (NULL == szFontName) - { - return; - } - - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - LCDUI_tcsncpy(lf.lfFaceName, szFontName, LF_FACESIZE); - - SetFont(lf); -} - - -//************************************************************************ -// -// CLCDText::SetFontPointSize -// -//************************************************************************ - -void CLCDText::SetFontPointSize(int nPointSize) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - lf.lfHeight = -MulDiv(nPointSize, DEFAULT_DPI, 72); - - SetFont(lf); -} - - -//************************************************************************ -// -// CLCDText::SetFontWeight -// -//************************************************************************ - -void CLCDText::SetFontWeight(int nWeight) -{ - LOGFONT lf; - ZeroMemory(&lf, sizeof(lf)); - GetObject(m_hFont, sizeof(LOGFONT), &lf); - - lf.lfWeight = nWeight; - - SetFont(lf); -} - - -//************************************************************************ -// -// CLCDText::SetFontColor -// -//************************************************************************ - -void CLCDText::SetFontColor(COLORREF color) -{ - SetForegroundColor(color); -} - - -//************************************************************************ -// -// CLCDText::SetText -// -//************************************************************************ - -void CLCDText::SetText(LPCTSTR szText) -{ - LCDUIASSERT(NULL != szText); - if(szText && _tcscmp(m_sText.c_str(), szText)) - { - m_sText.assign(szText); - m_nTextLength = m_sText.size(); - m_dtp.iLeftMargin = 0; - m_dtp.iRightMargin = 0; - m_bRecalcExtent = TRUE; - } -} - - -//************************************************************************ -// -// CLCDText::GetText -// -//************************************************************************ - -LPCTSTR CLCDText::GetText() -{ - return m_sText.c_str(); -} - - -//************************************************************************ -// -// CLCDText::SetWordWrap -// -//************************************************************************ - -void CLCDText::SetWordWrap(BOOL bEnable) -{ - if (bEnable) - { - m_nTextFormat |= DT_WORDBREAK; - } - else - { - m_nTextFormat &= ~DT_WORDBREAK; - } - m_bRecalcExtent = TRUE; -} - - -//************************************************************************ -// -// CLCDText::SetLeftMargin -// -//************************************************************************ - -void CLCDText::SetLeftMargin(int nLeftMargin) -{ - m_dtp.iLeftMargin = nLeftMargin; -} - - -//************************************************************************ -// -// CLCDText::SetRightMargin -// -//************************************************************************ - -void CLCDText::SetRightMargin(int nRightMargin) -{ - m_dtp.iRightMargin = nRightMargin; -} - - -//************************************************************************ -// -// CLCDText::GetLeftMargin -// -//************************************************************************ - -int CLCDText::GetLeftMargin(void) -{ - return m_dtp.iLeftMargin; -} - - -//************************************************************************ -// -// CLCDText::GetRightMargin -// -//************************************************************************ - -int CLCDText::GetRightMargin(void) -{ - return m_dtp.iRightMargin; -} - - -//************************************************************************ -// -// CLCDText::GetVExtent -// -//************************************************************************ - -SIZE& CLCDText::GetVExtent() -{ - return m_sizeVExtent; -} - - -//************************************************************************ -// -// CLCDText::GetHExtent -// -//************************************************************************ - -SIZE& CLCDText::GetHExtent() -{ - return m_sizeHExtent; -} - - -//************************************************************************ -// -// CLCDText::CalculateExtent -// -//************************************************************************ - -void CLCDText::CalculateExtent(BOOL bSingleLine) -{ - HDC hdc = CreateCompatibleDC(NULL); - - int nOldMapMode = SetMapMode(hdc, MM_TEXT); - int nOldBkMode = SetBkMode(hdc, GetBackgroundMode()); - // select current font - HFONT hOldFont = (HFONT)SelectObject(hdc, m_hFont); - - int nTextFormat; - RECT rExtent; - - if(bSingleLine) - { - // calculate horizontal extent w/ single line, we can get the line height - nTextFormat = (m_nTextFormat | DT_SINGLELINE | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = m_Size.cx; - rExtent.bottom = m_Size.cy; - DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeHExtent.cx = rExtent.right; - m_sizeHExtent.cy = rExtent.bottom; - } - else - { - // calculate vertical extent with word wrap - nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = m_Size.cx; - rExtent.bottom = m_Size.cy; - DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeVExtent.cx = rExtent.right; - m_sizeVExtent.cy = rExtent.bottom; - } - - // restores - SetMapMode(hdc, nOldMapMode); - SetBkMode(hdc, nOldBkMode); - SelectObject(hdc, hOldFont); - - DeleteDC(hdc); -} - - -//************************************************************************ -// -// CLCDText::SetAlignment -// -//************************************************************************ - -void CLCDText::SetAlignment(int nAlignment) -{ - m_nTextFormat &= ~m_nTextAlignment; - m_nTextFormat |= nAlignment; - m_nTextAlignment = nAlignment; -} - - -//************************************************************************ -// -// CLCDText::DrawText -// -//************************************************************************ - -void CLCDText::DrawText(CLCDGfxBase &rGfx) -{ - // draw the text - RECT rBoundary = { 0, 0,0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rBoundary, m_nTextFormat, &m_dtp); - - if (m_bInverted) - { - InvertRect(rGfx.GetHDC(), &rBoundary); - } -} - - -//************************************************************************ -// -// CLCDText::OnDraw -// -//************************************************************************ - -void CLCDText::OnDraw(CLCDGfxBase &rGfx) -{ - if (GetBackgroundMode() == OPAQUE) - { - HBRUSH hBackBrush = CreateSolidBrush(m_crBackgroundColor); - - // clear the clipped area - RECT rcClp = { 0, 0, m_Size.cx, m_Size.cy }; - FillRect(rGfx.GetHDC(), &rcClp, (HBRUSH) GetStockObject(BLACK_BRUSH)); - - // clear the logical area - RECT rcLog = { 0, 0, m_sizeLogical.cx, m_sizeLogical.cy }; - FillRect(rGfx.GetHDC(), &rcLog, hBackBrush); - - DeleteObject(hBackBrush); - } - - if (m_nTextLength) - { - - // map mode text, with transparency - int nOldMapMode = SetMapMode(rGfx.GetHDC(), MM_TEXT); - int nOldBkMode = SetBkMode(rGfx.GetHDC(), GetBackgroundMode()); - COLORREF nOldBkColor = SetBkColor(rGfx.GetHDC(), m_crBackgroundColor); - - // select current font - HFONT hOldFont = (HFONT)SelectObject(rGfx.GetHDC(), m_hFont); - - // select color - COLORREF crOldTextColor = SetTextColor(rGfx.GetHDC(), m_crForegroundColor); - - if (m_bRecalcExtent) - { - int nTextFormat; - - RECT rExtent; - // calculate vertical extent with word wrap - nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = GetWidth(); - rExtent.bottom = GetHeight(); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeVExtent.cx = rExtent.right; - m_sizeVExtent.cy = rExtent.bottom; - - // calculate horizontal extent w/o word wrap - nTextFormat = (m_nTextFormat | DT_CALCRECT); - rExtent.left = rExtent.top = 0; - rExtent.right = GetWidth(); - rExtent.bottom = GetHeight(); - DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); - m_sizeHExtent.cx = rExtent.right; - m_sizeHExtent.cy = rExtent.bottom; - - m_bRecalcExtent = FALSE; - } - - if (IsVisible()) - { - DrawText(rGfx); - } - - // restores - SetMapMode(rGfx.GetHDC(), nOldMapMode); - SetTextColor(rGfx.GetHDC(), crOldTextColor); - SetBkMode(rGfx.GetHDC(), nOldBkMode); - SetBkColor(rGfx.GetHDC(), nOldBkColor); - SelectObject(rGfx.GetHDC(), hOldFont); - } -} - -//** end of LCDText.cpp ************************************************** - +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDText.cpp +// +// The CLCDText class draws simple text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#include "LCDUI.h" + + +//************************************************************************ +// +// CLCDText::CLCDText +// +//************************************************************************ + +CLCDText::CLCDText(void) +: m_hFont(NULL), + m_nTextLength(0), + m_nTextFormat(DT_LEFT | DT_NOPREFIX), + m_bRecalcExtent(TRUE), + m_nTextAlignment(DT_LEFT) +{ + ZeroMemory(&m_dtp, sizeof(DRAWTEXTPARAMS)); + m_dtp.cbSize = sizeof(DRAWTEXTPARAMS); + ZeroMemory(&m_sizeVExtent, sizeof(m_sizeVExtent)); + ZeroMemory(&m_sizeHExtent, sizeof(m_sizeHExtent)); + SetBackgroundMode(TRANSPARENT); + Initialize(); +} + + +//************************************************************************ +// +// CLCDText::~CLCDText +// +//************************************************************************ + +CLCDText::~CLCDText(void) +{ + if (m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } +} + + +//************************************************************************ +// +// CLCDText::Initialize +// +//************************************************************************ + +HRESULT CLCDText::Initialize() +{ + m_hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT); + if(NULL != m_hFont) + { + SetFontPointSize(DEFAULT_POINTSIZE); + } + SetForegroundColor(RGB(255, 255, 255)); + return (NULL != m_hFont) ? S_OK : E_OUTOFMEMORY; +} + + +//************************************************************************ +// +// CLCDText::SetFont +// +//************************************************************************ + +void CLCDText::SetFont(LOGFONT& lf) +{ + if (m_hFont) + { + DeleteObject(m_hFont); + m_hFont = NULL; + } + + m_hFont = CreateFontIndirect(&lf); + m_bRecalcExtent = TRUE; +} + + +//************************************************************************ +// +// CLCDText::GetFont +// +//************************************************************************ + +HFONT CLCDText::GetFont() +{ + return m_hFont; +} + + +//************************************************************************ +// +// CLCDText::SetFontFaceName +// +//************************************************************************ + +void CLCDText::SetFontFaceName(LPCTSTR szFontName) +{ + // if NULL, uses the default gui font + if (NULL == szFontName) + { + return; + } + + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + LCDUI_tcsncpy(lf.lfFaceName, szFontName, LF_FACESIZE); + + SetFont(lf); +} + + +//************************************************************************ +// +// CLCDText::SetFontPointSize +// +//************************************************************************ + +void CLCDText::SetFontPointSize(int nPointSize) +{ + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + lf.lfHeight = -MulDiv(nPointSize, DEFAULT_DPI, 72); + + SetFont(lf); +} + + +//************************************************************************ +// +// CLCDText::SetFontWeight +// +//************************************************************************ + +void CLCDText::SetFontWeight(int nWeight) +{ + LOGFONT lf; + ZeroMemory(&lf, sizeof(lf)); + GetObject(m_hFont, sizeof(LOGFONT), &lf); + + lf.lfWeight = nWeight; + + SetFont(lf); +} + + +//************************************************************************ +// +// CLCDText::SetFontColor +// +//************************************************************************ + +void CLCDText::SetFontColor(COLORREF color) +{ + SetForegroundColor(color); +} + + +//************************************************************************ +// +// CLCDText::SetText +// +//************************************************************************ + +void CLCDText::SetText(LPCTSTR szText) +{ + LCDUIASSERT(NULL != szText); + if(szText && _tcscmp(m_sText.c_str(), szText)) + { + m_sText.assign(szText); + m_nTextLength = m_sText.size(); + m_dtp.iLeftMargin = 0; + m_dtp.iRightMargin = 0; + m_bRecalcExtent = TRUE; + } +} + + +//************************************************************************ +// +// CLCDText::GetText +// +//************************************************************************ + +LPCTSTR CLCDText::GetText() +{ + return m_sText.c_str(); +} + + +//************************************************************************ +// +// CLCDText::SetWordWrap +// +//************************************************************************ + +void CLCDText::SetWordWrap(BOOL bEnable) +{ + if (bEnable) + { + m_nTextFormat |= DT_WORDBREAK; + } + else + { + m_nTextFormat &= ~DT_WORDBREAK; + } + m_bRecalcExtent = TRUE; +} + + +//************************************************************************ +// +// CLCDText::SetLeftMargin +// +//************************************************************************ + +void CLCDText::SetLeftMargin(int nLeftMargin) +{ + m_dtp.iLeftMargin = nLeftMargin; +} + + +//************************************************************************ +// +// CLCDText::SetRightMargin +// +//************************************************************************ + +void CLCDText::SetRightMargin(int nRightMargin) +{ + m_dtp.iRightMargin = nRightMargin; +} + + +//************************************************************************ +// +// CLCDText::GetLeftMargin +// +//************************************************************************ + +int CLCDText::GetLeftMargin(void) +{ + return m_dtp.iLeftMargin; +} + + +//************************************************************************ +// +// CLCDText::GetRightMargin +// +//************************************************************************ + +int CLCDText::GetRightMargin(void) +{ + return m_dtp.iRightMargin; +} + + +//************************************************************************ +// +// CLCDText::GetVExtent +// +//************************************************************************ + +SIZE& CLCDText::GetVExtent() +{ + return m_sizeVExtent; +} + + +//************************************************************************ +// +// CLCDText::GetHExtent +// +//************************************************************************ + +SIZE& CLCDText::GetHExtent() +{ + return m_sizeHExtent; +} + + +//************************************************************************ +// +// CLCDText::CalculateExtent +// +//************************************************************************ + +void CLCDText::CalculateExtent(BOOL bSingleLine) +{ + HDC hdc = CreateCompatibleDC(NULL); + + int nOldMapMode = SetMapMode(hdc, MM_TEXT); + int nOldBkMode = SetBkMode(hdc, GetBackgroundMode()); + // select current font + HFONT hOldFont = (HFONT)SelectObject(hdc, m_hFont); + + int nTextFormat; + RECT rExtent; + + if(bSingleLine) + { + // calculate horizontal extent w/ single line, we can get the line height + nTextFormat = (m_nTextFormat | DT_SINGLELINE | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = m_Size.cx; + rExtent.bottom = m_Size.cy; + DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeHExtent.cx = rExtent.right; + m_sizeHExtent.cy = rExtent.bottom; + } + else + { + // calculate vertical extent with word wrap + nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = m_Size.cx; + rExtent.bottom = m_Size.cy; + DrawTextEx(hdc, (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeVExtent.cx = rExtent.right; + m_sizeVExtent.cy = rExtent.bottom; + } + + // restores + SetMapMode(hdc, nOldMapMode); + SetBkMode(hdc, nOldBkMode); + SelectObject(hdc, hOldFont); + + DeleteDC(hdc); +} + + +//************************************************************************ +// +// CLCDText::SetAlignment +// +//************************************************************************ + +void CLCDText::SetAlignment(int nAlignment) +{ + m_nTextFormat &= ~m_nTextAlignment; + m_nTextFormat |= nAlignment; + m_nTextAlignment = nAlignment; +} + + +//************************************************************************ +// +// CLCDText::DrawText +// +//************************************************************************ + +void CLCDText::DrawText(CLCDGfxBase &rGfx) +{ + // draw the text + RECT rBoundary = { 0, 0,0 + GetLogicalSize().cx, 0 + GetLogicalSize().cy }; + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rBoundary, m_nTextFormat, &m_dtp); + + if (m_bInverted) + { + InvertRect(rGfx.GetHDC(), &rBoundary); + } +} + + +//************************************************************************ +// +// CLCDText::OnDraw +// +//************************************************************************ + +void CLCDText::OnDraw(CLCDGfxBase &rGfx) +{ + if (GetBackgroundMode() == OPAQUE) + { + HBRUSH hBackBrush = CreateSolidBrush(m_crBackgroundColor); + + // clear the clipped area + RECT rcClp = { 0, 0, m_Size.cx, m_Size.cy }; + FillRect(rGfx.GetHDC(), &rcClp, (HBRUSH) GetStockObject(BLACK_BRUSH)); + + // clear the logical area + RECT rcLog = { 0, 0, m_sizeLogical.cx, m_sizeLogical.cy }; + FillRect(rGfx.GetHDC(), &rcLog, hBackBrush); + + DeleteObject(hBackBrush); + } + + if (m_nTextLength) + { + + // map mode text, with transparency + int nOldMapMode = SetMapMode(rGfx.GetHDC(), MM_TEXT); + int nOldBkMode = SetBkMode(rGfx.GetHDC(), GetBackgroundMode()); + COLORREF nOldBkColor = SetBkColor(rGfx.GetHDC(), m_crBackgroundColor); + + // select current font + HFONT hOldFont = (HFONT)SelectObject(rGfx.GetHDC(), m_hFont); + + // select color + COLORREF crOldTextColor = SetTextColor(rGfx.GetHDC(), m_crForegroundColor); + + if (m_bRecalcExtent) + { + int nTextFormat; + + RECT rExtent; + // calculate vertical extent with word wrap + nTextFormat = (m_nTextFormat | DT_WORDBREAK | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = GetWidth(); + rExtent.bottom = GetHeight(); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeVExtent.cx = rExtent.right; + m_sizeVExtent.cy = rExtent.bottom; + + // calculate horizontal extent w/o word wrap + nTextFormat = (m_nTextFormat | DT_CALCRECT); + rExtent.left = rExtent.top = 0; + rExtent.right = GetWidth(); + rExtent.bottom = GetHeight(); + DrawTextEx(rGfx.GetHDC(), (LPTSTR)m_sText.c_str(), static_cast(m_nTextLength), &rExtent, nTextFormat, &m_dtp); + m_sizeHExtent.cx = rExtent.right; + m_sizeHExtent.cy = rExtent.bottom; + + m_bRecalcExtent = FALSE; + } + + if (IsVisible()) + { + DrawText(rGfx); + } + + // restores + SetMapMode(rGfx.GetHDC(), nOldMapMode); + SetTextColor(rGfx.GetHDC(), crOldTextColor); + SetBkMode(rGfx.GetHDC(), nOldBkMode); + SetBkColor(rGfx.GetHDC(), nOldBkColor); + SelectObject(rGfx.GetHDC(), hOldFont); + } +} + +//** end of LCDText.cpp ************************************************** + diff --git a/src/thirdparty/LCDUI/LCDText.h b/src/thirdparty/LCDUI/LCDText.h index 51ecc06d7d3..46cd758300c 100644 --- a/src/thirdparty/LCDUI/LCDText.h +++ b/src/thirdparty/LCDUI/LCDText.h @@ -1,82 +1,82 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDText.h -// -// The CLCDText class draws simple text onto the LCD. -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -//************************************************************************ - -#ifndef _LCDTEXT_H_INCLUDED_ -#define _LCDTEXT_H_INCLUDED_ - - -#include "LCDBase.h" -#include - -class CLCDText : public CLCDBase -{ -public: -#ifdef UNICODE - typedef std::wstring lcdstring; -#else - typedef std::string lcdstring; -#endif - -public: - CLCDText(void); - virtual ~CLCDText(void); - - virtual HRESULT Initialize(void); - - virtual void SetFont(LOGFONT& lf); - virtual void SetFontFaceName(LPCTSTR szFontName); - virtual void SetFontPointSize(int nPointSize); - virtual void SetFontWeight(int nWeight); - virtual void SetFontColor(COLORREF color); - - virtual HFONT GetFont(void); - virtual void SetText(LPCTSTR szText); - virtual LPCTSTR GetText(void); - virtual void SetWordWrap(BOOL bEnable); - virtual SIZE& GetVExtent(void); - virtual SIZE& GetHExtent(void); - virtual void CalculateExtent(BOOL bSingleLine); - virtual void SetLeftMargin(int nLeftMargin); - virtual int GetLeftMargin(void); - virtual void SetRightMargin(int nRightMargin); - virtual int GetRightMargin(void); - virtual void SetAlignment(int nAlignment = DT_LEFT); - - // CLCDBase - virtual void OnDraw(CLCDGfxBase &rGfx); - - enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 8 }; - -protected: - void DrawText(CLCDGfxBase &rGfx); - - lcdstring m_sText; - HFONT m_hFont; - lcdstring::size_type m_nTextLength; - UINT m_nTextFormat; - BOOL m_bRecalcExtent; - DRAWTEXTPARAMS m_dtp; - int m_nTextAlignment; - SIZE m_sizeVExtent, m_sizeHExtent; -}; - - -#endif // !_LCDTEXT_H_INCLUDED_ - -//** end of LCDText.h **************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDText.h +// +// The CLCDText class draws simple text onto the LCD. +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +//************************************************************************ + +#ifndef _LCDTEXT_H_INCLUDED_ +#define _LCDTEXT_H_INCLUDED_ + + +#include "LCDBase.h" +#include + +class CLCDText : public CLCDBase +{ +public: +#ifdef UNICODE + typedef std::wstring lcdstring; +#else + typedef std::string lcdstring; +#endif + +public: + CLCDText(void); + virtual ~CLCDText(void); + + virtual HRESULT Initialize(void); + + virtual void SetFont(LOGFONT& lf); + virtual void SetFontFaceName(LPCTSTR szFontName); + virtual void SetFontPointSize(int nPointSize); + virtual void SetFontWeight(int nWeight); + virtual void SetFontColor(COLORREF color); + + virtual HFONT GetFont(void); + virtual void SetText(LPCTSTR szText); + virtual LPCTSTR GetText(void); + virtual void SetWordWrap(BOOL bEnable); + virtual SIZE& GetVExtent(void); + virtual SIZE& GetHExtent(void); + virtual void CalculateExtent(BOOL bSingleLine); + virtual void SetLeftMargin(int nLeftMargin); + virtual int GetLeftMargin(void); + virtual void SetRightMargin(int nRightMargin); + virtual int GetRightMargin(void); + virtual void SetAlignment(int nAlignment = DT_LEFT); + + // CLCDBase + virtual void OnDraw(CLCDGfxBase &rGfx); + + enum { DEFAULT_DPI = 96, DEFAULT_POINTSIZE = 8 }; + +protected: + void DrawText(CLCDGfxBase &rGfx); + + lcdstring m_sText; + HFONT m_hFont; + lcdstring::size_type m_nTextLength; + UINT m_nTextFormat; + BOOL m_bRecalcExtent; + DRAWTEXTPARAMS m_dtp; + int m_nTextAlignment; + SIZE m_sizeVExtent, m_sizeHExtent; +}; + + +#endif // !_LCDTEXT_H_INCLUDED_ + +//** end of LCDText.h **************************************************** diff --git a/src/thirdparty/LCDUI/LCDUI.h b/src/thirdparty/LCDUI/LCDUI.h index f771b51fced..68f95bb6c10 100644 --- a/src/thirdparty/LCDUI/LCDUI.h +++ b/src/thirdparty/LCDUI/LCDUI.h @@ -1,92 +1,92 @@ -//************************************************************************ -// The Logitech LCD SDK, including all acompanying documentation, -// is protected by intellectual property laws. All use of the Logitech -// LCD SDK is subject to the License Agreement found in the -// "Logitech LCD SDK License Agreement" file and in the Reference Manual. -// All rights not expressly granted by Logitech are reserved. -//************************************************************************ - -//************************************************************************ -// -// LCDUI.h -// -// Common header file for all LCDUI source files -// This file can be used to compile with pre-compiled headers -// under Visual Studio -// -// Logitech LCD SDK -// -// Copyright 2010 Logitech Inc. -// -//************************************************************************ - -#ifndef _LCDUI_H_INCLUDED_ -#define _LCDUI_H_INCLUDED_ - -//************************************************************************ -// all windows header files -//************************************************************************ - -#include -#include -#include -#include -#include -#include - - -//************************************************************************ -// all classes -//************************************************************************ - -class CLCDBase; -class CLCDCollection; -class CLCDPage; -class CLCDPopupBackground; -class CLCDConnection; -class CLCDOutput; -class CLCDGfxBase; -class CLCDGfxMono; -class CLCDGfxColor; -class CLCDText; -class CLCDColorText; -class CLCDScrollingText; -class CLCDStreamingText; -class CLCDPaginateText; -class CLCDIcon; -class CLCDBitmap; -class CLCDAnimatedBitmap; -class CLCDProgressBar; -class CLCDColorProgressBar; -class CLCDSkinnedProgressBar; - - -//************************************************************************ -// all header files -//************************************************************************ - -#include -#include "LCDBase.h" -#include "LCDCollection.h" -#include "LCDPage.h" -#include "LCDConnection.h" -#include "LCDOutput.h" -#include "LCDGfxBase.h" -#include "LCDGfxMono.h" -#include "LCDGfxColor.h" -#include "LCDText.h" -#include "LCDColorText.h" -#include "LCDScrollingText.h" -#include "LCDStreamingText.h" -#include "LCDPaginateText.h" -#include "LCDIcon.h" -#include "LCDBitmap.h" -#include "LCDAnimatedBitmap.h" -#include "LCDProgressBar.h" -#include "LCDColorProgressBar.h" -#include "LCDSkinnedProgressBar.h" - - -#endif //~_LCDUI_H_INCLUDED_ - -//** end of LCDUI.h ****************************************************** +//************************************************************************ +// The Logitech LCD SDK, including all acompanying documentation, +// is protected by intellectual property laws. All use of the Logitech +// LCD SDK is subject to the License Agreement found in the +// "Logitech LCD SDK License Agreement" file and in the Reference Manual. +// All rights not expressly granted by Logitech are reserved. +//************************************************************************ + +//************************************************************************ +// +// LCDUI.h +// +// Common header file for all LCDUI source files +// This file can be used to compile with pre-compiled headers +// under Visual Studio +// +// Logitech LCD SDK +// +// Copyright 2010 Logitech Inc. +// +//************************************************************************ + +#ifndef _LCDUI_H_INCLUDED_ +#define _LCDUI_H_INCLUDED_ + +//************************************************************************ +// all windows header files +//************************************************************************ + +#include +#include +#include +#include +#include +#include + + +//************************************************************************ +// all classes +//************************************************************************ + +class CLCDBase; +class CLCDCollection; +class CLCDPage; +class CLCDPopupBackground; +class CLCDConnection; +class CLCDOutput; +class CLCDGfxBase; +class CLCDGfxMono; +class CLCDGfxColor; +class CLCDText; +class CLCDColorText; +class CLCDScrollingText; +class CLCDStreamingText; +class CLCDPaginateText; +class CLCDIcon; +class CLCDBitmap; +class CLCDAnimatedBitmap; +class CLCDProgressBar; +class CLCDColorProgressBar; +class CLCDSkinnedProgressBar; + + +//************************************************************************ +// all header files +//************************************************************************ + +#include +#include "LCDBase.h" +#include "LCDCollection.h" +#include "LCDPage.h" +#include "LCDConnection.h" +#include "LCDOutput.h" +#include "LCDGfxBase.h" +#include "LCDGfxMono.h" +#include "LCDGfxColor.h" +#include "LCDText.h" +#include "LCDColorText.h" +#include "LCDScrollingText.h" +#include "LCDStreamingText.h" +#include "LCDPaginateText.h" +#include "LCDIcon.h" +#include "LCDBitmap.h" +#include "LCDAnimatedBitmap.h" +#include "LCDProgressBar.h" +#include "LCDColorProgressBar.h" +#include "LCDSkinnedProgressBar.h" + + +#endif //~_LCDUI_H_INCLUDED_ + +//** end of LCDUI.h ****************************************************** diff --git a/src/thirdparty/LCDUI/LCDUI.vcxproj b/src/thirdparty/LCDUI/LCDUI.vcxproj index b53bea0e7f0..ac7966c494b 100644 --- a/src/thirdparty/LCDUI/LCDUI.vcxproj +++ b/src/thirdparty/LCDUI/LCDUI.vcxproj @@ -1,107 +1,107 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {476B97B4-F079-4A44-AF89-52CA30C35E28} - LCDUI - Win32Proj - LCDUI - - - - - StaticLibrary - Unicode - - - - - - - - - - - False - - - - ..\..\..\include;%(AdditionalIncludeDirectories) - _LIB;%(PreprocessorDefinitions) - LCDUI.h - - - lgLcd.lib;%(AdditionalDependencies) - $(SolutionDir)lib;%(AdditionalLibraryDirectories) - $(SolutionDir)lib64;%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {476B97B4-F079-4A44-AF89-52CA30C35E28} + LCDUI + Win32Proj + LCDUI + + + + + StaticLibrary + Unicode + + + + + + + + + + + False + + + + ..\..\..\include;%(AdditionalIncludeDirectories) + _LIB;%(PreprocessorDefinitions) + LCDUI.h + + + lgLcd.lib;%(AdditionalDependencies) + $(SolutionDir)lib;%(AdditionalLibraryDirectories) + $(SolutionDir)lib64;%(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/LCDUI/LCDUI.vcxproj.filters b/src/thirdparty/LCDUI/LCDUI.vcxproj.filters index 09f502fd97d..f0c9f370976 100644 --- a/src/thirdparty/LCDUI/LCDUI.vcxproj.filters +++ b/src/thirdparty/LCDUI/LCDUI.vcxproj.filters @@ -1,143 +1,143 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/LCDUI/stdafx.cpp b/src/thirdparty/LCDUI/stdafx.cpp index aecdbddc5c9..9a097c179fd 100644 --- a/src/thirdparty/LCDUI/stdafx.cpp +++ b/src/thirdparty/LCDUI/stdafx.cpp @@ -1,21 +1,21 @@ -/* - * (C) 2011-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 . - * - */ - -#include "LCDUI.h" +/* + * (C) 2011-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 . + * + */ + +#include "LCDUI.h" diff --git a/src/thirdparty/MessageBoxDialog/MessageBoxDialog.cpp b/src/thirdparty/MessageBoxDialog/MessageBoxDialog.cpp index f9931cb7e63..c798950f27b 100755 --- a/src/thirdparty/MessageBoxDialog/MessageBoxDialog.cpp +++ b/src/thirdparty/MessageBoxDialog/MessageBoxDialog.cpp @@ -1,1073 +1,1073 @@ -/* - * Extended MFC message boxes -- Version 1.2 Lite - * Copyright (c) 2004 Michael P. Mehl. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1a (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/. - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights - * reserved. The Initial Developer of the Original Code is Michael P. Mehl - * . - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU Lesser General Public License Version 2.1 (the "LGPL License"), - * in which case the provisions of LGPL License are applicable instead of - * those above. If you wish to allow use of your version of this file only - * under the terms of the LGPL License and not to allow others to use your - * version of this file under the MPL, indicate your decision by deleting - * the provisions above and replace them with the notice and other provisions - * required by the LGPL License. If you do not delete the provisions above, - * a recipient may use your version of this file under either the MPL or - * the LGPL License. - */ - -/* -MPC-HC -modified from 1.2lite to include code to emulate afxmessagebox styles -modified to use Theme Font -*/ - -#include "stdafx.h" - -#include "MessageBoxDialog.h" -#include "../mpc-hc/CMPCTheme.h" -#include "../mpc-hc/CMPCThemeUtil.h" -#include - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - -IMPLEMENT_DYNAMIC(CMessageBoxDialog, CDialog) - -////////////////////////////////////////////////////////////////////////////// -// Layout values (in dialog units). - -#define CX_BORDER 8 // Width of the border. -#define CY_BORDER 6 // Height of the border. - -#define CX_BUTTON 35 // Standard width of a button. -#define CY_BUTTON 10 // Standard height of a button. -#define CY_TEXTPADDING 14 // Space before and after message. -#define CX_BUTTON_BORDER 4 // Standard border for a button. -#define CX_WINDOW_PADDING 2 // Padding for right side of dialog - -#define CY_BUTTON_BORDER 1 // Standard border for a button. -#define CX_BUTTON_SPACE 7 // Standard space for a button. - -#define CX_DLGUNIT_BASE 1000 // Values used for converting -#define CY_DLGUNIT_BASE 1000 // dialog units to pixels. - -////////////////////////////////////////////////////////////////////////////// -// Constructors and destructors of the class. - -/** - * Constructor of the class. - * - * This constructor is used to provide the strings directly without providing - * resource IDs from which these strings should be retrieved. If no title is - * given, the application name will be used as the title of the dialog. - */ - CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, CString strMessage, - CString strTitle, UINT nStyle, UINT nHelp ) -{ - // Enable the active accessibility. -#if _MSC_VER >= 1300 - EnableActiveAccessibility(); -#endif - - ASSERT(!strMessage.IsEmpty()); - - // Save the information about the message box. - m_pParent = pParent; - m_strMessage = strMessage; - m_strTitle = strTitle.IsEmpty() ? CString(AfxGetAppName()) : strTitle; - m_nStyle = nStyle; - m_nHelp = nHelp; - - // Do the default initialization. - m_uBeepType = (UINT)-1; - m_hIcon = NULL; - m_nDefaultButton = IDC_STATIC; - m_nEscapeButton = IDC_STATIC; - m_sDialogUnit = CSize(0, 0); - m_sIcon = CSize(0, 0); - m_sMessage = CSize(0, 0); - m_sButton = CSize(0, 0); -} - -/** - * Constructor of the class. - * - * This constructor is used to load the strings for the title and the message - * text from the resources of this project. If no title is given, the - * application name will be used as the title of the dialog. - */ -CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, - UINT nTitleID, UINT nStyle, UINT nHelp ) -{ - // Enable the active accessibility. -#if _MSC_VER >= 1300 - EnableActiveAccessibility(); -#endif - - // Check whether a title was given. - if ( nTitleID == 0 ) - { - // Use the application name. - m_strTitle = AfxGetAppName(); - } - else - { - // Try to load the title from the resources. - VERIFY(m_strTitle.LoadString(nTitleID)); - } - - // Save the information about the message box. - m_pParent = pParent; - VERIFY(m_strMessage.LoadString(nMessageID)); - m_nStyle = nStyle; - m_nHelp = nHelp; - - // Do the default initialization. - m_uBeepType = (UINT)-1; - m_hIcon = NULL; - m_nDefaultButton = IDC_STATIC; - m_nEscapeButton = IDC_STATIC; - m_sDialogUnit = CSize(0, 0); - m_sIcon = CSize(0, 0); - m_sMessage = CSize(0, 0); - m_sButton = CSize(0, 0); -} - -/** - * Destructor of the class. - */ -CMessageBoxDialog::~CMessageBoxDialog ( ) -{ - // Check whether an icon was loaded. - if ( m_hIcon != NULL ) - { - // Free the icon. - DestroyIcon(m_hIcon); - - // Reset the icon handle. - m_hIcon = NULL; - } -} - -////////////////////////////////////////////////////////////////////////////// -// Methods for setting and retrieving dialog options. - -/** - * Method for setting the style of the message box. - */ -inline void CMessageBoxDialog::SetStyle ( UINT nStyle ) -{ - // Set the style of the message box. - m_nStyle = nStyle; -} - -/** - * Method for retrieving the style of the message box. - */ -inline UINT CMessageBoxDialog::GetStyle ( ) -{ - // Return the current style of the message box. - return m_nStyle; -} - -/** - * Method for setting the message to be displayed in the message box. - */ -void CMessageBoxDialog::SetMessage ( CString strMessage ) -{ - ASSERT(!strMessage.IsEmpty()); - - // Save the message text. - m_strMessage = strMessage; -} - -/** - * Methods for setting the message to be displayed in the message box. - */ -void CMessageBoxDialog::SetMessage ( UINT nMessageID ) -{ - // Create a string for storing the message. - CString strMessage = _T(""); - - // Load the message from the resources. - VERIFY(strMessage.LoadString(nMessageID)); - - ASSERT(!strMessage.IsEmpty()); - - // Save the message text. - m_strMessage = strMessage; -} - -/** - * Method for retrieving the message to be displayed in the message box. - */ -CString CMessageBoxDialog::GetMessage ( ) -{ - // Return the message text. - return m_strMessage; -} - -/** - * Method for setting the title to be displayed in the message box. - */ -void CMessageBoxDialog::SetTitle ( CString strTitle ) -{ - // Check whether a title was given. - if ( strTitle.IsEmpty() ) - { - // Use the application name as the title. - strTitle = AfxGetAppName(); - } - - // Save the title. - m_strTitle = strTitle; -} - -/** - * Method for setting the title to be displayed in the message box. - */ -void CMessageBoxDialog::SetTitle ( UINT nTitleID ) -{ - // Create a string for storing the title. - CString strTitle = _T(""); - - // Check whether an ID was given. - if ( nTitleID == 0 ) - { - // Use the application name as the title. - strTitle = AfxGetAppName(); - } - else - { - // Try to load the string from the resources. - VERIFY(strTitle.LoadString(nTitleID)); - - ASSERT(!strTitle.IsEmpty()); - } - - // Save the title. - m_strTitle = strTitle; -} - -/** - * Method for retrieving the title to be displayed in the message box. - */ -CString CMessageBoxDialog::GetTitle ( ) -{ - // Return the title of the message box. - return m_strTitle; -} - -void CMessageBoxDialog::SetMessageBeep(UINT uType) -{ - m_uBeepType = uType; -} - -/** - * Method for setting the icon to be displayed in the message box. - */ -void CMessageBoxDialog::SetMessageIcon ( HICON hIcon ) -{ - ASSERT(hIcon != NULL); - - // Save the icon. - m_hIcon = hIcon; -} - -/** - * Method for setting the icon to be displayed in the message box. - */ -void CMessageBoxDialog::SetMessageIcon ( LPCTSTR lpszIconName, BOOL bStandard ) -{ - // Try to load the given icon. - if (bStandard) - { - if (m_uBeepType==-1) - { - if (lpszIconName==IDI_QUESTION) - m_uBeepType = MB_ICONQUESTION; - else if (lpszIconName==IDI_WARNING || lpszIconName==IDI_EXCLAMATION) - m_uBeepType = MB_ICONWARNING; - else if (lpszIconName==IDI_ERROR || lpszIconName==IDI_HAND) - m_uBeepType = MB_ICONERROR; - else if (lpszIconName==IDI_INFORMATION || lpszIconName==IDI_ASTERISK) - m_uBeepType = MB_ICONINFORMATION; - } - m_hIcon = AfxGetApp()->LoadStandardIcon(lpszIconName); - } - else - m_hIcon = AfxGetApp()->LoadIcon(lpszIconName); - - ASSERT(m_hIcon != NULL); -} - -/** - * Method for retrieving the icon to be displayed in the message box. - */ -HICON CMessageBoxDialog::GetMessageIcon ( ) -{ - // Return the icon for the message box. - return m_hIcon; -} - -////////////////////////////////////////////////////////////////////////////// -// Methods for handling common window functions. - -/** - * Method for displaying the dialog. - * - * If the MB_DONT_DISPLAY_AGAIN or MB_DONT_ASK_AGAIN flag is set, this - * method will check, whether a former result for this dialog was stored - * in the registry. If yes, the former result will be returned without - * displaying the dialog. Otherwise the message box will be displayed in - * the normal way. - */ -INT_PTR CMessageBoxDialog::DoModal ( ) -{ - BYTE abyBuff[512]; - memset(abyBuff, 0, sizeof(abyBuff)); - DLGTEMPLATE* pdlgtmplTemplate = (DLGTEMPLATE*)abyBuff; - pdlgtmplTemplate->x = 0; - pdlgtmplTemplate->y = 0; - pdlgtmplTemplate->cx = 200; - pdlgtmplTemplate->cy = 200; - pdlgtmplTemplate->style = DS_MODALFRAME|WS_CAPTION|WS_VISIBLE|WS_POPUP|WS_SYSMENU|WS_BORDER; - pdlgtmplTemplate->dwExtendedStyle = 0; - pdlgtmplTemplate->cdit = 0; - - //This is the MFC function, which does the job - InitModalIndirect(pdlgtmplTemplate, m_pParent); - - return CDialog::DoModal(); -} - -/** - * Method for initializing the dialog. - * - * This method is used for initializing the dialog. It will create the - * content of the dialog, which means it will create all controls and will - * size the dialog to fit it's content. - */ -BOOL CMessageBoxDialog::OnInitDialog ( ) -{ - // Call the parent method. - if ( !CDialog::OnInitDialog() ) - { - // Return with an error. - return FALSE; - } - - if (!CMPCThemeUtil::getFontByType(messageFont, this, CMPCThemeUtil::MessageFont)) { - return FALSE; - } - - // Set the title of the dialog. - SetWindowText(m_strTitle); - - // Set the help ID of the dialog. - SetHelpID(m_nHelp); - - // Parse the style of the message box. - ParseStyle(); - - // Create the elements of the dialog. - CreateIconControl(); - CreateMessageControl(); - CreateButtonControls(); - - // Define the layout of the dialog. - DefineLayout(); - - // Check whether no sound should be generated. - if ( m_uBeepType != -1 ) - { - // Do a beep. - MessageBeep(m_uBeepType); - } - - // Check whether the window should be system modal. - if ( m_nStyle & MB_SYSTEMMODAL ) - { - // Modify the style of the window. - ModifyStyle(0, DS_SYSMODAL); - } - - // Check whether to bring the window to the foreground. - if ( m_nStyle & MB_SETFOREGROUND ) - { - // Bring the window to the foreground. - SetForegroundWindow(); - } - - // Check whether the window should be the topmost window. - if ( m_nStyle & MB_TOPMOST ) - { - // Modify the style of the window. - ModifyStyleEx(0, WS_EX_TOPMOST); - } - - // Check whether an escape button was defined. - if ( m_nEscapeButton == IDC_STATIC ) - { - // Disable the close item from the system menu. - CMenu* sysmenu = GetSystemMenu(FALSE); - if (sysmenu) - sysmenu->EnableMenuItem(SC_CLOSE, MF_GRAYED); - } - - // Check whether a default button was defined. - if ( m_nDefaultButton != IDC_STATIC ) - { - // Set the focus to the default button. - CWnd* item = GetDlgItem(m_nDefaultButton); - if (item) { - item->SetFocus(); - } - - // Set the default ID of the dialog. - SetDefID(m_nDefaultButton); - - // Return FALSE to set the focus correctly. - return FALSE; - } - - // Everything seems to be done successfully. - return TRUE; -} - -/** - * Method for handling command messages. - * - * This method will handle command messages, which are those messages, which - * are generated, when a user clicks a button of the dialog. - */ -BOOL CMessageBoxDialog::OnCmdMsg ( UINT nID, int nCode, void* pExtra, - AFX_CMDHANDLERINFO* pHandlerInfo ) -{ - // Check whether it's the help button. - if ( ( nID == IDHELP ) && ( nCode == CN_COMMAND ) ) - { - // Display the help for this message box. - OnHelp(); - - // The message has been processed successfully. - return TRUE; - } - - // Check whether the ID of the control element is interesting for us. - if ( ( nID != IDC_STATIC ) && ( nCode == CN_COMMAND ) ) - { - // End the dialog with the given ID. - EndDialog(nID); - - // The message has been processed successfully. - return TRUE; - } - - // Call the parent method. - return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); -} - -/** - * Method for handling messages before dispatching them. - * - * This message will handle message before they get dispatched the normal way - * and will therefore implement the additional behavior of this dialog. - */ -BOOL CMessageBoxDialog::PreTranslateMessage ( MSG* pMsg ) -{ - // Check whether it's a key message and whether it's not a disable timeout. - if ( pMsg->message == WM_KEYDOWN ) - { - // Check whether it's the return key. - if ( pMsg->wParam == VK_RETURN ) - { - // Try to retrieve the current focus. - CWnd* pFocusWnd = GetFocus(); - - // Check whether a handle was retrieved. - if ( pFocusWnd != NULL ) - { - // Try to determine the ID of the element. - int nID = pFocusWnd->GetDlgCtrlID(); - - // Check whether the ID is a button. - if ( m_aButtons.FindKey(nID)!=-1 ) - { - EndDialog(nID); - } - else - { - // End the dialog with the default command. - EndDialog(m_nDefaultButton); - } - - // The message has been processed successfully. - return TRUE; - } - } - - // Check whether it's the escape key. - if ( ( pMsg->wParam == VK_ESCAPE ) || ( pMsg->wParam == VK_CANCEL ) ) - { - // Check whether an escape button was defined. - if ( m_nEscapeButton != IDC_STATIC ) - { - // End the dialog with this ID. - EndDialog(m_nEscapeButton); - } - - // The message has been processed successfully. - return TRUE; - } - } - - // Call the parent method. - return CDialog::PreTranslateMessage(pMsg); -} - -////////////////////////////////////////////////////////////////////////////// -// Other dialog handling methods. - -/** - * Method for handling window messages. - */ -BOOL CMessageBoxDialog::OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam, - LRESULT* pResult ) -{ - // Check whether to close the dialog. - if ( message == WM_CLOSE ) - { - // Check whether an escape button is defined. - if ( m_nEscapeButton != IDC_STATIC ) - { - // End the dialog with this command. - EndDialog(m_nEscapeButton); - } - - // The message was handled successfully. - return TRUE; - } - - // Call the parent method. - return CDialog::OnWndMsg(message, wParam, lParam, pResult); -} - -////////////////////////////////////////////////////////////////////////////// -// Helper methods. - -/** - * Method for adding a button to the list of buttons. - * - * This method adds a button to the list of buttons, which will be created in - * the dialog, but it will not create the button control itself. - */ -void CMessageBoxDialog::AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault, - BOOL bIsEscape ) -{ - CString strButtonTitle; - VERIFY(strButtonTitle.LoadString(nTitle)); - - AddButton(nID, strButtonTitle, bIsDefault, bIsEscape); -} - -/** - * Method for adding a button to the list of buttons. - * - * This method adds a button to the list of buttons, which will be created in - * the dialog, but it will not create the button control itself. - */ -void CMessageBoxDialog::AddButton ( UINT nID, CString strTitle, BOOL bIsDefault, - BOOL bIsEscape ) -{ - // Check if one is trying to add the same ID twice - VERIFY( m_aButtons.FindKey(nID)==-1 ); - - // Add the button to the list of buttons. - VERIFY( m_aButtons.Add(nID, strTitle) ); - - // Check whether this button is the default button. - if ( bIsDefault ) - { - // Save the ID of the button as the ID of the default button. - m_nDefaultButton = nID; - } - - // Check whether this button is the escape button. - if ( bIsEscape ) - { - // Save the ID of the button as the ID of the escape button. - m_nEscapeButton = nID; - } -} - -/** - * Method for converting a dialog unit x value to a pixel value. - */ -int CMessageBoxDialog::XDialogUnitToPixel ( int x ) -{ - // Check whether the dimension of a dialog unit has already been determined. - if ( m_sDialogUnit.cx == 0 ) - { - // Create a rect for mapping it to the dialog rect. - CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE); - - // Map the rect to the dialog. - - //mpc-hc: CDialog without a template does not work well with MapDialogRect--use MapDialogRect2 - //MapDialogRect(rcDialog); - CMPCThemeUtil::MapDialogRect2(this, rcDialog); - - // Save the rect. - m_sDialogUnit = rcDialog.Size(); - } - - // Return the converted value. - return ( MulDiv( x , m_sDialogUnit.cx , CX_DLGUNIT_BASE )); -} - -/** - * Method for converting a dialog unit y value to a pixel value. - */ -int CMessageBoxDialog::YDialogUnitToPixel ( int y ) -{ - // Check whether the dimension of a dialog unit has already been determined. - if ( m_sDialogUnit.cy == 0 ) - { - // Create a rect for mapping it to the dialog rect. - CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE); - - // Map the rect to the dialog. - //mpc-hc: CDialog without a template does not work well with MapDialogRect--use MapDialogRect2 - //MapDialogRect(rcDialog); - CMPCThemeUtil::MapDialogRect2(this, rcDialog); - - // Save the rect. - m_sDialogUnit = rcDialog.Size(); - } - - // Return the converted value. - return ( MulDiv( y , m_sDialogUnit.cy , CY_DLGUNIT_BASE ) ); -} - -/** - * Method for parsing the given style. - * - * This method will parse the given style for the message box and will create - * the elements of the dialog box according to it. If you want to add more - * user defined styles, simply modify this method. - */ -void CMessageBoxDialog::ParseStyle ( ) -{ - switch ( m_nStyle & MB_TYPEMASK ) - { - case MB_OKCANCEL: - AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE); - AddButton(IDCANCEL, IDS_CANCEL, FALSE, TRUE); - break; - case MB_ABORTRETRYIGNORE: - AddButton(IDABORT, IDS_MESSAGEBOX_ABORT, TRUE); - AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY); - AddButton(IDIGNORE, IDS_MESSAGEBOX_IGNORE); - break; - case MB_YESNOCANCEL: - AddButton(IDYES, IDS_SUBRESYNC_YES, TRUE); - AddButton(IDNO, IDS_SUBRESYNC_NO); - AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE); - break; - case MB_YESNO: - AddButton(IDYES, IDS_SUBRESYNC_YES, TRUE); - AddButton(IDNO, IDS_SUBRESYNC_NO); - break; - case MB_RETRYCANCEL: - AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY, TRUE); - AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE); - break; - case MB_CANCELTRYCONTINUE: - AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, TRUE, TRUE); - AddButton(IDTRYAGAIN, IDS_MESSAGEBOX_RETRY); - AddButton(IDCONTINUE, IDS_MESSAGEBOX_CONTINUE); - break; - default: - case MB_OK: - AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE, TRUE); - break; - } - // Check whether a default button was defined. - if ( m_nStyle & MB_DEFMASK ) - { - // Create a variable to store the index of the default button. - int nDefaultIndex = 0; - - // Switch the default button. - switch ( m_nStyle & MB_DEFMASK ) - { - - case MB_DEFBUTTON1: - // Set the index of the default button. - nDefaultIndex = 0; - break; - - case MB_DEFBUTTON2: - // Set the index of the default button. - nDefaultIndex = 1; - break; - - case MB_DEFBUTTON3: - // Set the index of the default button. - nDefaultIndex = 2; - break; - - case MB_DEFBUTTON4: - // Set the index of the default button. - nDefaultIndex = 3; - break; - } - - // Check whether enough buttons are available. - if ( m_aButtons.GetSize() >= ( nDefaultIndex + 1 ) ) - { - // Set the new default button. - m_nDefaultButton = m_aButtons.GetKeyAt(nDefaultIndex); - } - } - - // Check whether an icon was specified. - if ( ( m_nStyle & MB_ICONMASK ) && ( m_hIcon == NULL ) ) - { - // Switch the icon. - switch ( m_nStyle & MB_ICONMASK ) - { - case MB_ICONEXCLAMATION: - // Load the icon with the exclamation mark. - SetMessageIcon(IDI_EXCLAMATION, TRUE); - break; - - case MB_ICONHAND: - // Load the icon with the error symbol. - SetMessageIcon(IDI_HAND, TRUE); - break; - - case MB_ICONQUESTION: - // Load the icon with the question mark. - SetMessageIcon(IDI_QUESTION, TRUE); - break; - - case MB_ICONASTERISK: - // Load the icon with the information symbol. - SetMessageIcon(IDI_ASTERISK, TRUE); - break; - } - } -} - -/** - * Method for creating the icon control. - * - * This method will check whether the handle for an icon was defined and if - * yes it will create an control in the dialog to display that icon. - */ -void CMessageBoxDialog::CreateIconControl ( ) -{ - // Check whether an icon was defined. - if ( m_hIcon != NULL ) - { - // Create a structure to read information about the icon. - ICONINFO iiIconInfo; - - // Retrieve information about the icon. - GetIconInfo(m_hIcon, &iiIconInfo); - - ASSERT(iiIconInfo.fIcon); - - // Create a handle to access the bitmap information of the icon. - BITMAP bmIcon; - - // Retrieve the bitmap information of the icon. - GetObject((HGDIOBJ)iiIconInfo.hbmColor, sizeof(bmIcon), &bmIcon); - - // Save the size of the icon. - m_sIcon.cx = bmIcon.bmWidth; - m_sIcon.cy = bmIcon.bmHeight; - - // Create a dummy rect for the icon control. - CRect rcDummy; - - // Create the control for the icon. - m_stcIcon.Create(NULL, WS_CHILD | WS_VISIBLE | WS_DISABLED | SS_ICON, - rcDummy, this, (UINT)IDC_STATIC); - - // Set the icon of the control. - m_stcIcon.SetIcon(m_hIcon); - //m_stcIcon.UnsubclassWindow(); - } -} - -/** - * Method for creating the text control. - * - * This method create the control displaying the text of the message for the - * message box. It will also try to determine the size required for the - * message. - */ -void CMessageBoxDialog::CreateMessageControl ( ) -{ - ASSERT(!m_strMessage.IsEmpty()); - - // Create a DC for accessing the display driver. - CDC dcDisplay; - dcDisplay.CreateDC(_T("DISPLAY"), NULL, NULL, NULL); - - // Select the new font and store the old one. - //mpc-hc use stored font for metrics - //CFont* pOldFont = dcDisplay.SelectObject(GetFont()); - CFont* pOldFont = dcDisplay.SelectObject(&messageFont); - - // Define the maximum width of the message. - int nMaxWidth = GetSystemMetrics(SM_CXSCREEN) - 2 * XDialogUnitToPixel(CX_BORDER); - int minClientHeightExcludingMessage = 2 * YDialogUnitToPixel(CY_TEXTPADDING) + 2 * YDialogUnitToPixel(CY_BORDER) + YDialogUnitToPixel(CY_BUTTON) + 1; - int yPadding = GetThemeSysSize(NULL, SM_CYSIZE) + GetThemeSysSize(NULL, SM_CXPADDEDBORDER) * 2 + minClientHeightExcludingMessage; - int nMaxHeight = GetSystemMetrics(SM_CYSCREEN) - yPadding; - - // Check whether an icon is displayed. - if ( m_hIcon != NULL ) - { - // Decrease the maximum width. - nMaxWidth -= m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); - } - - // Create a rect with the maximum width. - //mpc-hc try to follow windows guidlines for messagebox sizes per https://devblogs.microsoft.com/oldnewthing/20110624-00/?p=10343 - int bestWidth = 99999; - CRect rcMessage(0, 0, nMaxWidth, nMaxHeight); - m_sMessage = rcMessage.Size(); - - for (int widthType = 0; widthType < 5; widthType++) { - int testWidth; - switch (widthType) { - case 0: - testWidth = GetSystemMetrics(SM_CXSCREEN); - break; - case 1: - testWidth = XDialogUnitToPixel(278); - break; - case 2: - testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 5, 8); - break; - case 3: - testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 3, 4); - break; - case 4: - default: - testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 7, 8); - break; - } - rcMessage = CRect(0, 0, testWidth, nMaxHeight); - dcDisplay.DrawText(m_strMessage, rcMessage, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); - if (rcMessage.Width() <= nMaxWidth && rcMessage.Height() <= nMaxHeight) { - if (testWidth < bestWidth) { - m_sMessage = rcMessage.Size(); - bestWidth = testWidth; - } - } - } - - // Select the old font again. - dcDisplay.SelectObject(pOldFont); - - // Create a dummy rect for the control. - CRect rcDummy; - - // Create a variable with the style of the control. - DWORD dwStyle = WS_CHILD | WS_VISIBLE; - - // Check whether the text should be right aligned. - if ( m_nStyle & MB_RIGHT ) - { - // Align the text to the right. - dwStyle |= SS_RIGHT; - } - else - { - // Align the text to the left. - dwStyle |= SS_LEFT; - } - - // Create the static control for the message. - m_stcMessage.Create(m_strMessage, dwStyle, rcDummy, this, - (UINT)IDC_STATIC); - - // Check whether the text will be read from right to left. - if ( m_nStyle & MB_RTLREADING ) - { - // Change the extended style of the control. - m_stcMessage.ModifyStyleEx(0, WS_EX_RTLREADING); - } - - // Set the font of the dialog. - m_stcMessage.SetFont(&messageFont); -} - -/** - * Method for creating the button controls. - * - * According to the list of buttons, which should be displayed in this - * message box, this method will create them and add them to the dialog. - */ -void CMessageBoxDialog::CreateButtonControls ( ) -{ - // Initialize the control with the size of the button. - m_sButton = CSize(XDialogUnitToPixel(CX_BUTTON) + 1,YDialogUnitToPixel(CY_BUTTON) + 1); - - // Create a handle to access the DC of the dialog. - CClientDC dc(this); - - // Retrieve the font for this dialog and select it. - CFont* pWndFont = GetFont(); - CFont* pOldFont = dc.SelectObject(pWndFont); - - // Create a dummy rect. - CRect rcDummy; - - // Run through all buttons defined in the list of the buttons. - for ( int i = 0; i < m_aButtons.GetSize(); i++ ) - { - // Create a string and load the title of the button. - CString strButtonTitle = m_aButtons.GetValueAt(i); - - // Retrieve the size of the text. - CSize sButtonText = dc.GetTextExtent(strButtonTitle); - - // Resize the button. - m_sButton.cx = std::max(m_sButton.cx, sButtonText.cx); - m_sButton.cy = std::max(m_sButton.cy, sButtonText.cy); - - // Create a new handle for creating a button control. - CButton btnControl; - - // Create the button. - btnControl.Create(strButtonTitle, WS_CHILD | WS_VISIBLE | WS_TABSTOP, - rcDummy, this, m_aButtons.GetKeyAt(i)); - - // Set the font of the control. - btnControl.SetFont(&messageFont); - - // Remove the subclassing again. - btnControl.UnsubclassWindow(); - } - - // Add margins to the button size. - m_sButton.cx += 2 * XDialogUnitToPixel(CX_BUTTON_BORDER); - m_sButton.cy += 2 * XDialogUnitToPixel(CY_BUTTON_BORDER); - - // Select the old font again. - dc.SelectObject(pOldFont); -} - -/** - * Method for defining the layout of the dialog. - * - * This method will define the actual layout of the dialog. This layout is - * based on the created controls for the dialog. - */ -void CMessageBoxDialog::DefineLayout ( ) -{ - // Create a variable for storing the size of the dialog. - CSize sClient = CSize(2 * XDialogUnitToPixel(CX_BORDER), - 2 * YDialogUnitToPixel(CY_BORDER)); - - // Create a variable to store the left position for a control element. - int nXPosition = XDialogUnitToPixel(CX_BORDER); - long messageAreaHeight = m_sMessage.cy + 2 * YDialogUnitToPixel(CY_TEXTPADDING); - int nYPosition = YDialogUnitToPixel(CY_TEXTPADDING); - - // Check whether an icon is defined. - if ( m_hIcon != NULL && ::IsWindow(m_stcIcon)) - { - // Move the icon control. - m_stcIcon.MoveWindow(XDialogUnitToPixel(CX_BORDER), YDialogUnitToPixel(CY_BORDER), m_sIcon.cx, m_sIcon.cy); - - // Add the size of the icon to the size of the dialog. - sClient.cx += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); - sClient.cy += m_sIcon.cy + YDialogUnitToPixel(CY_BORDER); - - // Increase the x position for following control elements. - nXPosition += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); - } - - // Change the size of the dialog according to the size of the message. - sClient.cx += m_sMessage.cx + XDialogUnitToPixel(CX_BORDER); - sClient.cy = std::max(sClient.cy, messageAreaHeight); - - // Set the position of the message text. - m_stcMessage.MoveWindow(nXPosition, nYPosition, m_sMessage.cx, - m_sMessage.cy); - - // Define the new y position. - nYPosition = messageAreaHeight; - - // Calculate the width of the buttons. - int cxButtons = - ( m_aButtons.GetSize() - 1 ) * XDialogUnitToPixel(CX_BUTTON_SPACE) + - m_aButtons.GetSize() * m_sButton.cx; - int cyButtons = m_sButton.cy; - - // Add the size of the buttons to the dialog. - sClient.cx = std::max((LONG)sClient.cx, (LONG)2 * XDialogUnitToPixel(CX_BORDER) + cxButtons); - sClient.cy += cyButtons + 2 * YDialogUnitToPixel(CY_BORDER); - - // Calculate the start y position for the buttons. - //mpc-hc align right instead of center - //int nXButtonPosition = (sClient.cx - cxButtons) / 2; - int nXButtonPosition = sClient.cx - cxButtons - XDialogUnitToPixel(CX_BORDER + CX_WINDOW_PADDING); - int nYButtonPosition = sClient.cy - YDialogUnitToPixel(CY_BORDER) - m_sButton.cy; - - buttonAreaY = nYPosition; - - // Run through all buttons. - for ( int i = 0; i < m_aButtons.GetSize(); i++ ) - { - // Try to retrieve the handle to access the button. - CWnd* pButton = GetDlgItem(m_aButtons.GetKeyAt(i)); - - ASSERT(pButton); - - // Check whether the handle was retrieved successfully. - if ( pButton != NULL ) - { - // Move the button. - pButton->MoveWindow(nXButtonPosition, nYButtonPosition, - m_sButton.cx, m_sButton.cy); - - // Set the new x position of the next button. - nXButtonPosition += m_sButton.cx + - XDialogUnitToPixel(CX_BUTTON_SPACE); - } - } - - // Set the dimensions of the dialog. - CRect rcClient(0, 0, sClient.cx, sClient.cy); - - // Calculate the window rect. - CalcWindowRect(rcClient); - - // Move the window. - MoveWindow(rcClient); - - // Center the window. - CenterWindow(); -} +/* + * Extended MFC message boxes -- Version 1.2 Lite + * Copyright (c) 2004 Michael P. Mehl. All rights reserved. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1a (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights + * reserved. The Initial Developer of the Original Code is Michael P. Mehl + * . + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU Lesser General Public License Version 2.1 (the "LGPL License"), + * in which case the provisions of LGPL License are applicable instead of + * those above. If you wish to allow use of your version of this file only + * under the terms of the LGPL License and not to allow others to use your + * version of this file under the MPL, indicate your decision by deleting + * the provisions above and replace them with the notice and other provisions + * required by the LGPL License. If you do not delete the provisions above, + * a recipient may use your version of this file under either the MPL or + * the LGPL License. + */ + +/* +MPC-HC +modified from 1.2lite to include code to emulate afxmessagebox styles +modified to use Theme Font +*/ + +#include "stdafx.h" + +#include "MessageBoxDialog.h" +#include "../mpc-hc/CMPCTheme.h" +#include "../mpc-hc/CMPCThemeUtil.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +IMPLEMENT_DYNAMIC(CMessageBoxDialog, CDialog) + +////////////////////////////////////////////////////////////////////////////// +// Layout values (in dialog units). + +#define CX_BORDER 8 // Width of the border. +#define CY_BORDER 6 // Height of the border. + +#define CX_BUTTON 35 // Standard width of a button. +#define CY_BUTTON 10 // Standard height of a button. +#define CY_TEXTPADDING 14 // Space before and after message. +#define CX_BUTTON_BORDER 4 // Standard border for a button. +#define CX_WINDOW_PADDING 2 // Padding for right side of dialog + +#define CY_BUTTON_BORDER 1 // Standard border for a button. +#define CX_BUTTON_SPACE 7 // Standard space for a button. + +#define CX_DLGUNIT_BASE 1000 // Values used for converting +#define CY_DLGUNIT_BASE 1000 // dialog units to pixels. + +////////////////////////////////////////////////////////////////////////////// +// Constructors and destructors of the class. + +/** + * Constructor of the class. + * + * This constructor is used to provide the strings directly without providing + * resource IDs from which these strings should be retrieved. If no title is + * given, the application name will be used as the title of the dialog. + */ + CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, CString strMessage, + CString strTitle, UINT nStyle, UINT nHelp ) +{ + // Enable the active accessibility. +#if _MSC_VER >= 1300 + EnableActiveAccessibility(); +#endif + + ASSERT(!strMessage.IsEmpty()); + + // Save the information about the message box. + m_pParent = pParent; + m_strMessage = strMessage; + m_strTitle = strTitle.IsEmpty() ? CString(AfxGetAppName()) : strTitle; + m_nStyle = nStyle; + m_nHelp = nHelp; + + // Do the default initialization. + m_uBeepType = (UINT)-1; + m_hIcon = NULL; + m_nDefaultButton = IDC_STATIC; + m_nEscapeButton = IDC_STATIC; + m_sDialogUnit = CSize(0, 0); + m_sIcon = CSize(0, 0); + m_sMessage = CSize(0, 0); + m_sButton = CSize(0, 0); +} + +/** + * Constructor of the class. + * + * This constructor is used to load the strings for the title and the message + * text from the resources of this project. If no title is given, the + * application name will be used as the title of the dialog. + */ +CMessageBoxDialog::CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, + UINT nTitleID, UINT nStyle, UINT nHelp ) +{ + // Enable the active accessibility. +#if _MSC_VER >= 1300 + EnableActiveAccessibility(); +#endif + + // Check whether a title was given. + if ( nTitleID == 0 ) + { + // Use the application name. + m_strTitle = AfxGetAppName(); + } + else + { + // Try to load the title from the resources. + VERIFY(m_strTitle.LoadString(nTitleID)); + } + + // Save the information about the message box. + m_pParent = pParent; + VERIFY(m_strMessage.LoadString(nMessageID)); + m_nStyle = nStyle; + m_nHelp = nHelp; + + // Do the default initialization. + m_uBeepType = (UINT)-1; + m_hIcon = NULL; + m_nDefaultButton = IDC_STATIC; + m_nEscapeButton = IDC_STATIC; + m_sDialogUnit = CSize(0, 0); + m_sIcon = CSize(0, 0); + m_sMessage = CSize(0, 0); + m_sButton = CSize(0, 0); +} + +/** + * Destructor of the class. + */ +CMessageBoxDialog::~CMessageBoxDialog ( ) +{ + // Check whether an icon was loaded. + if ( m_hIcon != NULL ) + { + // Free the icon. + DestroyIcon(m_hIcon); + + // Reset the icon handle. + m_hIcon = NULL; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Methods for setting and retrieving dialog options. + +/** + * Method for setting the style of the message box. + */ +inline void CMessageBoxDialog::SetStyle ( UINT nStyle ) +{ + // Set the style of the message box. + m_nStyle = nStyle; +} + +/** + * Method for retrieving the style of the message box. + */ +inline UINT CMessageBoxDialog::GetStyle ( ) +{ + // Return the current style of the message box. + return m_nStyle; +} + +/** + * Method for setting the message to be displayed in the message box. + */ +void CMessageBoxDialog::SetMessage ( CString strMessage ) +{ + ASSERT(!strMessage.IsEmpty()); + + // Save the message text. + m_strMessage = strMessage; +} + +/** + * Methods for setting the message to be displayed in the message box. + */ +void CMessageBoxDialog::SetMessage ( UINT nMessageID ) +{ + // Create a string for storing the message. + CString strMessage = _T(""); + + // Load the message from the resources. + VERIFY(strMessage.LoadString(nMessageID)); + + ASSERT(!strMessage.IsEmpty()); + + // Save the message text. + m_strMessage = strMessage; +} + +/** + * Method for retrieving the message to be displayed in the message box. + */ +CString CMessageBoxDialog::GetMessage ( ) +{ + // Return the message text. + return m_strMessage; +} + +/** + * Method for setting the title to be displayed in the message box. + */ +void CMessageBoxDialog::SetTitle ( CString strTitle ) +{ + // Check whether a title was given. + if ( strTitle.IsEmpty() ) + { + // Use the application name as the title. + strTitle = AfxGetAppName(); + } + + // Save the title. + m_strTitle = strTitle; +} + +/** + * Method for setting the title to be displayed in the message box. + */ +void CMessageBoxDialog::SetTitle ( UINT nTitleID ) +{ + // Create a string for storing the title. + CString strTitle = _T(""); + + // Check whether an ID was given. + if ( nTitleID == 0 ) + { + // Use the application name as the title. + strTitle = AfxGetAppName(); + } + else + { + // Try to load the string from the resources. + VERIFY(strTitle.LoadString(nTitleID)); + + ASSERT(!strTitle.IsEmpty()); + } + + // Save the title. + m_strTitle = strTitle; +} + +/** + * Method for retrieving the title to be displayed in the message box. + */ +CString CMessageBoxDialog::GetTitle ( ) +{ + // Return the title of the message box. + return m_strTitle; +} + +void CMessageBoxDialog::SetMessageBeep(UINT uType) +{ + m_uBeepType = uType; +} + +/** + * Method for setting the icon to be displayed in the message box. + */ +void CMessageBoxDialog::SetMessageIcon ( HICON hIcon ) +{ + ASSERT(hIcon != NULL); + + // Save the icon. + m_hIcon = hIcon; +} + +/** + * Method for setting the icon to be displayed in the message box. + */ +void CMessageBoxDialog::SetMessageIcon ( LPCTSTR lpszIconName, BOOL bStandard ) +{ + // Try to load the given icon. + if (bStandard) + { + if (m_uBeepType==-1) + { + if (lpszIconName==IDI_QUESTION) + m_uBeepType = MB_ICONQUESTION; + else if (lpszIconName==IDI_WARNING || lpszIconName==IDI_EXCLAMATION) + m_uBeepType = MB_ICONWARNING; + else if (lpszIconName==IDI_ERROR || lpszIconName==IDI_HAND) + m_uBeepType = MB_ICONERROR; + else if (lpszIconName==IDI_INFORMATION || lpszIconName==IDI_ASTERISK) + m_uBeepType = MB_ICONINFORMATION; + } + m_hIcon = AfxGetApp()->LoadStandardIcon(lpszIconName); + } + else + m_hIcon = AfxGetApp()->LoadIcon(lpszIconName); + + ASSERT(m_hIcon != NULL); +} + +/** + * Method for retrieving the icon to be displayed in the message box. + */ +HICON CMessageBoxDialog::GetMessageIcon ( ) +{ + // Return the icon for the message box. + return m_hIcon; +} + +////////////////////////////////////////////////////////////////////////////// +// Methods for handling common window functions. + +/** + * Method for displaying the dialog. + * + * If the MB_DONT_DISPLAY_AGAIN or MB_DONT_ASK_AGAIN flag is set, this + * method will check, whether a former result for this dialog was stored + * in the registry. If yes, the former result will be returned without + * displaying the dialog. Otherwise the message box will be displayed in + * the normal way. + */ +INT_PTR CMessageBoxDialog::DoModal ( ) +{ + BYTE abyBuff[512]; + memset(abyBuff, 0, sizeof(abyBuff)); + DLGTEMPLATE* pdlgtmplTemplate = (DLGTEMPLATE*)abyBuff; + pdlgtmplTemplate->x = 0; + pdlgtmplTemplate->y = 0; + pdlgtmplTemplate->cx = 200; + pdlgtmplTemplate->cy = 200; + pdlgtmplTemplate->style = DS_MODALFRAME|WS_CAPTION|WS_VISIBLE|WS_POPUP|WS_SYSMENU|WS_BORDER; + pdlgtmplTemplate->dwExtendedStyle = 0; + pdlgtmplTemplate->cdit = 0; + + //This is the MFC function, which does the job + InitModalIndirect(pdlgtmplTemplate, m_pParent); + + return CDialog::DoModal(); +} + +/** + * Method for initializing the dialog. + * + * This method is used for initializing the dialog. It will create the + * content of the dialog, which means it will create all controls and will + * size the dialog to fit it's content. + */ +BOOL CMessageBoxDialog::OnInitDialog ( ) +{ + // Call the parent method. + if ( !CDialog::OnInitDialog() ) + { + // Return with an error. + return FALSE; + } + + if (!CMPCThemeUtil::getFontByType(messageFont, this, CMPCThemeUtil::MessageFont)) { + return FALSE; + } + + // Set the title of the dialog. + SetWindowText(m_strTitle); + + // Set the help ID of the dialog. + SetHelpID(m_nHelp); + + // Parse the style of the message box. + ParseStyle(); + + // Create the elements of the dialog. + CreateIconControl(); + CreateMessageControl(); + CreateButtonControls(); + + // Define the layout of the dialog. + DefineLayout(); + + // Check whether no sound should be generated. + if ( m_uBeepType != -1 ) + { + // Do a beep. + MessageBeep(m_uBeepType); + } + + // Check whether the window should be system modal. + if ( m_nStyle & MB_SYSTEMMODAL ) + { + // Modify the style of the window. + ModifyStyle(0, DS_SYSMODAL); + } + + // Check whether to bring the window to the foreground. + if ( m_nStyle & MB_SETFOREGROUND ) + { + // Bring the window to the foreground. + SetForegroundWindow(); + } + + // Check whether the window should be the topmost window. + if ( m_nStyle & MB_TOPMOST ) + { + // Modify the style of the window. + ModifyStyleEx(0, WS_EX_TOPMOST); + } + + // Check whether an escape button was defined. + if ( m_nEscapeButton == IDC_STATIC ) + { + // Disable the close item from the system menu. + CMenu* sysmenu = GetSystemMenu(FALSE); + if (sysmenu) + sysmenu->EnableMenuItem(SC_CLOSE, MF_GRAYED); + } + + // Check whether a default button was defined. + if ( m_nDefaultButton != IDC_STATIC ) + { + // Set the focus to the default button. + CWnd* item = GetDlgItem(m_nDefaultButton); + if (item) { + item->SetFocus(); + } + + // Set the default ID of the dialog. + SetDefID(m_nDefaultButton); + + // Return FALSE to set the focus correctly. + return FALSE; + } + + // Everything seems to be done successfully. + return TRUE; +} + +/** + * Method for handling command messages. + * + * This method will handle command messages, which are those messages, which + * are generated, when a user clicks a button of the dialog. + */ +BOOL CMessageBoxDialog::OnCmdMsg ( UINT nID, int nCode, void* pExtra, + AFX_CMDHANDLERINFO* pHandlerInfo ) +{ + // Check whether it's the help button. + if ( ( nID == IDHELP ) && ( nCode == CN_COMMAND ) ) + { + // Display the help for this message box. + OnHelp(); + + // The message has been processed successfully. + return TRUE; + } + + // Check whether the ID of the control element is interesting for us. + if ( ( nID != IDC_STATIC ) && ( nCode == CN_COMMAND ) ) + { + // End the dialog with the given ID. + EndDialog(nID); + + // The message has been processed successfully. + return TRUE; + } + + // Call the parent method. + return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); +} + +/** + * Method for handling messages before dispatching them. + * + * This message will handle message before they get dispatched the normal way + * and will therefore implement the additional behavior of this dialog. + */ +BOOL CMessageBoxDialog::PreTranslateMessage ( MSG* pMsg ) +{ + // Check whether it's a key message and whether it's not a disable timeout. + if ( pMsg->message == WM_KEYDOWN ) + { + // Check whether it's the return key. + if ( pMsg->wParam == VK_RETURN ) + { + // Try to retrieve the current focus. + CWnd* pFocusWnd = GetFocus(); + + // Check whether a handle was retrieved. + if ( pFocusWnd != NULL ) + { + // Try to determine the ID of the element. + int nID = pFocusWnd->GetDlgCtrlID(); + + // Check whether the ID is a button. + if ( m_aButtons.FindKey(nID)!=-1 ) + { + EndDialog(nID); + } + else + { + // End the dialog with the default command. + EndDialog(m_nDefaultButton); + } + + // The message has been processed successfully. + return TRUE; + } + } + + // Check whether it's the escape key. + if ( ( pMsg->wParam == VK_ESCAPE ) || ( pMsg->wParam == VK_CANCEL ) ) + { + // Check whether an escape button was defined. + if ( m_nEscapeButton != IDC_STATIC ) + { + // End the dialog with this ID. + EndDialog(m_nEscapeButton); + } + + // The message has been processed successfully. + return TRUE; + } + } + + // Call the parent method. + return CDialog::PreTranslateMessage(pMsg); +} + +////////////////////////////////////////////////////////////////////////////// +// Other dialog handling methods. + +/** + * Method for handling window messages. + */ +BOOL CMessageBoxDialog::OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam, + LRESULT* pResult ) +{ + // Check whether to close the dialog. + if ( message == WM_CLOSE ) + { + // Check whether an escape button is defined. + if ( m_nEscapeButton != IDC_STATIC ) + { + // End the dialog with this command. + EndDialog(m_nEscapeButton); + } + + // The message was handled successfully. + return TRUE; + } + + // Call the parent method. + return CDialog::OnWndMsg(message, wParam, lParam, pResult); +} + +////////////////////////////////////////////////////////////////////////////// +// Helper methods. + +/** + * Method for adding a button to the list of buttons. + * + * This method adds a button to the list of buttons, which will be created in + * the dialog, but it will not create the button control itself. + */ +void CMessageBoxDialog::AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault, + BOOL bIsEscape ) +{ + CString strButtonTitle; + VERIFY(strButtonTitle.LoadString(nTitle)); + + AddButton(nID, strButtonTitle, bIsDefault, bIsEscape); +} + +/** + * Method for adding a button to the list of buttons. + * + * This method adds a button to the list of buttons, which will be created in + * the dialog, but it will not create the button control itself. + */ +void CMessageBoxDialog::AddButton ( UINT nID, CString strTitle, BOOL bIsDefault, + BOOL bIsEscape ) +{ + // Check if one is trying to add the same ID twice + VERIFY( m_aButtons.FindKey(nID)==-1 ); + + // Add the button to the list of buttons. + VERIFY( m_aButtons.Add(nID, strTitle) ); + + // Check whether this button is the default button. + if ( bIsDefault ) + { + // Save the ID of the button as the ID of the default button. + m_nDefaultButton = nID; + } + + // Check whether this button is the escape button. + if ( bIsEscape ) + { + // Save the ID of the button as the ID of the escape button. + m_nEscapeButton = nID; + } +} + +/** + * Method for converting a dialog unit x value to a pixel value. + */ +int CMessageBoxDialog::XDialogUnitToPixel ( int x ) +{ + // Check whether the dimension of a dialog unit has already been determined. + if ( m_sDialogUnit.cx == 0 ) + { + // Create a rect for mapping it to the dialog rect. + CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE); + + // Map the rect to the dialog. + + //mpc-hc: CDialog without a template does not work well with MapDialogRect--use MapDialogRect2 + //MapDialogRect(rcDialog); + CMPCThemeUtil::MapDialogRect2(this, rcDialog); + + // Save the rect. + m_sDialogUnit = rcDialog.Size(); + } + + // Return the converted value. + return ( MulDiv( x , m_sDialogUnit.cx , CX_DLGUNIT_BASE )); +} + +/** + * Method for converting a dialog unit y value to a pixel value. + */ +int CMessageBoxDialog::YDialogUnitToPixel ( int y ) +{ + // Check whether the dimension of a dialog unit has already been determined. + if ( m_sDialogUnit.cy == 0 ) + { + // Create a rect for mapping it to the dialog rect. + CRect rcDialog(0, 0, CX_DLGUNIT_BASE, CY_DLGUNIT_BASE); + + // Map the rect to the dialog. + //mpc-hc: CDialog without a template does not work well with MapDialogRect--use MapDialogRect2 + //MapDialogRect(rcDialog); + CMPCThemeUtil::MapDialogRect2(this, rcDialog); + + // Save the rect. + m_sDialogUnit = rcDialog.Size(); + } + + // Return the converted value. + return ( MulDiv( y , m_sDialogUnit.cy , CY_DLGUNIT_BASE ) ); +} + +/** + * Method for parsing the given style. + * + * This method will parse the given style for the message box and will create + * the elements of the dialog box according to it. If you want to add more + * user defined styles, simply modify this method. + */ +void CMessageBoxDialog::ParseStyle ( ) +{ + switch ( m_nStyle & MB_TYPEMASK ) + { + case MB_OKCANCEL: + AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE); + AddButton(IDCANCEL, IDS_CANCEL, FALSE, TRUE); + break; + case MB_ABORTRETRYIGNORE: + AddButton(IDABORT, IDS_MESSAGEBOX_ABORT, TRUE); + AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY); + AddButton(IDIGNORE, IDS_MESSAGEBOX_IGNORE); + break; + case MB_YESNOCANCEL: + AddButton(IDYES, IDS_SUBRESYNC_YES, TRUE); + AddButton(IDNO, IDS_SUBRESYNC_NO); + AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE); + break; + case MB_YESNO: + AddButton(IDYES, IDS_SUBRESYNC_YES, TRUE); + AddButton(IDNO, IDS_SUBRESYNC_NO); + break; + case MB_RETRYCANCEL: + AddButton(IDRETRY, IDS_MESSAGEBOX_RETRY, TRUE); + AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, FALSE, TRUE); + break; + case MB_CANCELTRYCONTINUE: + AddButton(IDCANCEL, IDS_MESSAGEBOX_CANCEL, TRUE, TRUE); + AddButton(IDTRYAGAIN, IDS_MESSAGEBOX_RETRY); + AddButton(IDCONTINUE, IDS_MESSAGEBOX_CONTINUE); + break; + default: + case MB_OK: + AddButton(IDOK, IDS_MESSAGEBOX_OK, TRUE, TRUE); + break; + } + // Check whether a default button was defined. + if ( m_nStyle & MB_DEFMASK ) + { + // Create a variable to store the index of the default button. + int nDefaultIndex = 0; + + // Switch the default button. + switch ( m_nStyle & MB_DEFMASK ) + { + + case MB_DEFBUTTON1: + // Set the index of the default button. + nDefaultIndex = 0; + break; + + case MB_DEFBUTTON2: + // Set the index of the default button. + nDefaultIndex = 1; + break; + + case MB_DEFBUTTON3: + // Set the index of the default button. + nDefaultIndex = 2; + break; + + case MB_DEFBUTTON4: + // Set the index of the default button. + nDefaultIndex = 3; + break; + } + + // Check whether enough buttons are available. + if ( m_aButtons.GetSize() >= ( nDefaultIndex + 1 ) ) + { + // Set the new default button. + m_nDefaultButton = m_aButtons.GetKeyAt(nDefaultIndex); + } + } + + // Check whether an icon was specified. + if ( ( m_nStyle & MB_ICONMASK ) && ( m_hIcon == NULL ) ) + { + // Switch the icon. + switch ( m_nStyle & MB_ICONMASK ) + { + case MB_ICONEXCLAMATION: + // Load the icon with the exclamation mark. + SetMessageIcon(IDI_EXCLAMATION, TRUE); + break; + + case MB_ICONHAND: + // Load the icon with the error symbol. + SetMessageIcon(IDI_HAND, TRUE); + break; + + case MB_ICONQUESTION: + // Load the icon with the question mark. + SetMessageIcon(IDI_QUESTION, TRUE); + break; + + case MB_ICONASTERISK: + // Load the icon with the information symbol. + SetMessageIcon(IDI_ASTERISK, TRUE); + break; + } + } +} + +/** + * Method for creating the icon control. + * + * This method will check whether the handle for an icon was defined and if + * yes it will create an control in the dialog to display that icon. + */ +void CMessageBoxDialog::CreateIconControl ( ) +{ + // Check whether an icon was defined. + if ( m_hIcon != NULL ) + { + // Create a structure to read information about the icon. + ICONINFO iiIconInfo; + + // Retrieve information about the icon. + GetIconInfo(m_hIcon, &iiIconInfo); + + ASSERT(iiIconInfo.fIcon); + + // Create a handle to access the bitmap information of the icon. + BITMAP bmIcon; + + // Retrieve the bitmap information of the icon. + GetObject((HGDIOBJ)iiIconInfo.hbmColor, sizeof(bmIcon), &bmIcon); + + // Save the size of the icon. + m_sIcon.cx = bmIcon.bmWidth; + m_sIcon.cy = bmIcon.bmHeight; + + // Create a dummy rect for the icon control. + CRect rcDummy; + + // Create the control for the icon. + m_stcIcon.Create(NULL, WS_CHILD | WS_VISIBLE | WS_DISABLED | SS_ICON, + rcDummy, this, (UINT)IDC_STATIC); + + // Set the icon of the control. + m_stcIcon.SetIcon(m_hIcon); + //m_stcIcon.UnsubclassWindow(); + } +} + +/** + * Method for creating the text control. + * + * This method create the control displaying the text of the message for the + * message box. It will also try to determine the size required for the + * message. + */ +void CMessageBoxDialog::CreateMessageControl ( ) +{ + ASSERT(!m_strMessage.IsEmpty()); + + // Create a DC for accessing the display driver. + CDC dcDisplay; + dcDisplay.CreateDC(_T("DISPLAY"), NULL, NULL, NULL); + + // Select the new font and store the old one. + //mpc-hc use stored font for metrics + //CFont* pOldFont = dcDisplay.SelectObject(GetFont()); + CFont* pOldFont = dcDisplay.SelectObject(&messageFont); + + // Define the maximum width of the message. + int nMaxWidth = GetSystemMetrics(SM_CXSCREEN) - 2 * XDialogUnitToPixel(CX_BORDER); + int minClientHeightExcludingMessage = 2 * YDialogUnitToPixel(CY_TEXTPADDING) + 2 * YDialogUnitToPixel(CY_BORDER) + YDialogUnitToPixel(CY_BUTTON) + 1; + int yPadding = GetThemeSysSize(NULL, SM_CYSIZE) + GetThemeSysSize(NULL, SM_CXPADDEDBORDER) * 2 + minClientHeightExcludingMessage; + int nMaxHeight = GetSystemMetrics(SM_CYSCREEN) - yPadding; + + // Check whether an icon is displayed. + if ( m_hIcon != NULL ) + { + // Decrease the maximum width. + nMaxWidth -= m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); + } + + // Create a rect with the maximum width. + //mpc-hc try to follow windows guidlines for messagebox sizes per https://devblogs.microsoft.com/oldnewthing/20110624-00/?p=10343 + int bestWidth = 99999; + CRect rcMessage(0, 0, nMaxWidth, nMaxHeight); + m_sMessage = rcMessage.Size(); + + for (int widthType = 0; widthType < 5; widthType++) { + int testWidth; + switch (widthType) { + case 0: + testWidth = GetSystemMetrics(SM_CXSCREEN); + break; + case 1: + testWidth = XDialogUnitToPixel(278); + break; + case 2: + testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 5, 8); + break; + case 3: + testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 3, 4); + break; + case 4: + default: + testWidth = MulDiv(GetSystemMetrics(SM_CXSCREEN), 7, 8); + break; + } + rcMessage = CRect(0, 0, testWidth, nMaxHeight); + dcDisplay.DrawText(m_strMessage, rcMessage, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); + if (rcMessage.Width() <= nMaxWidth && rcMessage.Height() <= nMaxHeight) { + if (testWidth < bestWidth) { + m_sMessage = rcMessage.Size(); + bestWidth = testWidth; + } + } + } + + // Select the old font again. + dcDisplay.SelectObject(pOldFont); + + // Create a dummy rect for the control. + CRect rcDummy; + + // Create a variable with the style of the control. + DWORD dwStyle = WS_CHILD | WS_VISIBLE; + + // Check whether the text should be right aligned. + if ( m_nStyle & MB_RIGHT ) + { + // Align the text to the right. + dwStyle |= SS_RIGHT; + } + else + { + // Align the text to the left. + dwStyle |= SS_LEFT; + } + + // Create the static control for the message. + m_stcMessage.Create(m_strMessage, dwStyle, rcDummy, this, + (UINT)IDC_STATIC); + + // Check whether the text will be read from right to left. + if ( m_nStyle & MB_RTLREADING ) + { + // Change the extended style of the control. + m_stcMessage.ModifyStyleEx(0, WS_EX_RTLREADING); + } + + // Set the font of the dialog. + m_stcMessage.SetFont(&messageFont); +} + +/** + * Method for creating the button controls. + * + * According to the list of buttons, which should be displayed in this + * message box, this method will create them and add them to the dialog. + */ +void CMessageBoxDialog::CreateButtonControls ( ) +{ + // Initialize the control with the size of the button. + m_sButton = CSize(XDialogUnitToPixel(CX_BUTTON) + 1,YDialogUnitToPixel(CY_BUTTON) + 1); + + // Create a handle to access the DC of the dialog. + CClientDC dc(this); + + // Retrieve the font for this dialog and select it. + CFont* pWndFont = GetFont(); + CFont* pOldFont = dc.SelectObject(pWndFont); + + // Create a dummy rect. + CRect rcDummy; + + // Run through all buttons defined in the list of the buttons. + for ( int i = 0; i < m_aButtons.GetSize(); i++ ) + { + // Create a string and load the title of the button. + CString strButtonTitle = m_aButtons.GetValueAt(i); + + // Retrieve the size of the text. + CSize sButtonText = dc.GetTextExtent(strButtonTitle); + + // Resize the button. + m_sButton.cx = std::max(m_sButton.cx, sButtonText.cx); + m_sButton.cy = std::max(m_sButton.cy, sButtonText.cy); + + // Create a new handle for creating a button control. + CButton btnControl; + + // Create the button. + btnControl.Create(strButtonTitle, WS_CHILD | WS_VISIBLE | WS_TABSTOP, + rcDummy, this, m_aButtons.GetKeyAt(i)); + + // Set the font of the control. + btnControl.SetFont(&messageFont); + + // Remove the subclassing again. + btnControl.UnsubclassWindow(); + } + + // Add margins to the button size. + m_sButton.cx += 2 * XDialogUnitToPixel(CX_BUTTON_BORDER); + m_sButton.cy += 2 * XDialogUnitToPixel(CY_BUTTON_BORDER); + + // Select the old font again. + dc.SelectObject(pOldFont); +} + +/** + * Method for defining the layout of the dialog. + * + * This method will define the actual layout of the dialog. This layout is + * based on the created controls for the dialog. + */ +void CMessageBoxDialog::DefineLayout ( ) +{ + // Create a variable for storing the size of the dialog. + CSize sClient = CSize(2 * XDialogUnitToPixel(CX_BORDER), + 2 * YDialogUnitToPixel(CY_BORDER)); + + // Create a variable to store the left position for a control element. + int nXPosition = XDialogUnitToPixel(CX_BORDER); + long messageAreaHeight = m_sMessage.cy + 2 * YDialogUnitToPixel(CY_TEXTPADDING); + int nYPosition = YDialogUnitToPixel(CY_TEXTPADDING); + + // Check whether an icon is defined. + if ( m_hIcon != NULL && ::IsWindow(m_stcIcon)) + { + // Move the icon control. + m_stcIcon.MoveWindow(XDialogUnitToPixel(CX_BORDER), YDialogUnitToPixel(CY_BORDER), m_sIcon.cx, m_sIcon.cy); + + // Add the size of the icon to the size of the dialog. + sClient.cx += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); + sClient.cy += m_sIcon.cy + YDialogUnitToPixel(CY_BORDER); + + // Increase the x position for following control elements. + nXPosition += m_sIcon.cx + XDialogUnitToPixel(CX_BORDER); + } + + // Change the size of the dialog according to the size of the message. + sClient.cx += m_sMessage.cx + XDialogUnitToPixel(CX_BORDER); + sClient.cy = std::max(sClient.cy, messageAreaHeight); + + // Set the position of the message text. + m_stcMessage.MoveWindow(nXPosition, nYPosition, m_sMessage.cx, + m_sMessage.cy); + + // Define the new y position. + nYPosition = messageAreaHeight; + + // Calculate the width of the buttons. + int cxButtons = + ( m_aButtons.GetSize() - 1 ) * XDialogUnitToPixel(CX_BUTTON_SPACE) + + m_aButtons.GetSize() * m_sButton.cx; + int cyButtons = m_sButton.cy; + + // Add the size of the buttons to the dialog. + sClient.cx = std::max((LONG)sClient.cx, (LONG)2 * XDialogUnitToPixel(CX_BORDER) + cxButtons); + sClient.cy += cyButtons + 2 * YDialogUnitToPixel(CY_BORDER); + + // Calculate the start y position for the buttons. + //mpc-hc align right instead of center + //int nXButtonPosition = (sClient.cx - cxButtons) / 2; + int nXButtonPosition = sClient.cx - cxButtons - XDialogUnitToPixel(CX_BORDER + CX_WINDOW_PADDING); + int nYButtonPosition = sClient.cy - YDialogUnitToPixel(CY_BORDER) - m_sButton.cy; + + buttonAreaY = nYPosition; + + // Run through all buttons. + for ( int i = 0; i < m_aButtons.GetSize(); i++ ) + { + // Try to retrieve the handle to access the button. + CWnd* pButton = GetDlgItem(m_aButtons.GetKeyAt(i)); + + ASSERT(pButton); + + // Check whether the handle was retrieved successfully. + if ( pButton != NULL ) + { + // Move the button. + pButton->MoveWindow(nXButtonPosition, nYButtonPosition, + m_sButton.cx, m_sButton.cy); + + // Set the new x position of the next button. + nXButtonPosition += m_sButton.cx + + XDialogUnitToPixel(CX_BUTTON_SPACE); + } + } + + // Set the dimensions of the dialog. + CRect rcClient(0, 0, sClient.cx, sClient.cy); + + // Calculate the window rect. + CalcWindowRect(rcClient); + + // Move the window. + MoveWindow(rcClient); + + // Center the window. + CenterWindow(); +} diff --git a/src/thirdparty/MessageBoxDialog/MessageBoxDialog.h b/src/thirdparty/MessageBoxDialog/MessageBoxDialog.h index 0d2fddab46f..9d724892e81 100755 --- a/src/thirdparty/MessageBoxDialog/MessageBoxDialog.h +++ b/src/thirdparty/MessageBoxDialog/MessageBoxDialog.h @@ -1,188 +1,188 @@ -/* - * Extended MFC message boxes -- Version 1.2 Lite - * Copyright (c) 2004 Michael P. Mehl. All rights reserved. - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1a (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/. - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights - * reserved. The Initial Developer of the Original Code is Michael P. Mehl - * . - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU Lesser General Public License Version 2.1 (the "LGPL License"), - * in which case the provisions of LGPL License are applicable instead of - * those above. If you wish to allow use of your version of this file only - * under the terms of the LGPL License and not to allow others to use your - * version of this file under the MPL, indicate your decision by deleting - * the provisions above and replace them with the notice and other provisions - * required by the LGPL License. If you do not delete the provisions above, - * a recipient may use your version of this file under either the MPL or - * the LGPL License. - */ - -#pragma once -#include "../mpc-hc/CMPCThemeStatic.h" -/* mpc-hc modified to use CMPCThemeStatic*/ - -////////////////////////////////////////////////////////////////////////////// -// Class definition. - -class CMessageBoxDialog : public CDialog -{ - - DECLARE_DYNAMIC(CMessageBoxDialog) - -public: - - ////////////////////////////////////////////////////////////////////////// - // Constructors and destructors of the class. - - // Constructor of the class for direct providing of the message strings. - CMessageBoxDialog ( CWnd* pParent, CString strMessage, - CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0 ); - - // Constructor of the class for loading the strings from the resources. - CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, UINT nTitleID = 0, - UINT nStyle = MB_OK, UINT nHelp = 0 ); - - // Default destructor of the class. - virtual ~CMessageBoxDialog ( ); - -public: - - ////////////////////////////////////////////////////////////////////////// - // Method for adding a button to the list of buttons. - void AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault = FALSE, - BOOL bIsEscape = FALSE ); - - // Method for adding a button to the list of buttons. - void AddButton ( UINT nID, CString strTitle, BOOL bIsDefault = FALSE, - BOOL bIsEscape = FALSE ); - - // Method for setting the style of the message box. - void SetStyle ( UINT nStyle ); - - // Method for retrieving the style of the message box. - UINT GetStyle ( ); - - // Methods for setting the message to be displayed in the message box. - void SetMessage ( CString strMessage ); - void SetMessage ( UINT nMessageID ); - - // Method for retrieving the message to be displayed in the message box. - CString GetMessage ( ); - - // Methods for setting the title to be displayed in the message box. - void SetTitle ( CString strTitle ); - void SetTitle ( UINT nTitleID ); - - // Method for retrieving the title to be displayed in the message box. - CString GetTitle ( ); - - // Methods for setting the icon to be displayed in the message box. - void SetMessageIcon ( HICON hIcon ); - void SetMessageIcon ( LPCTSTR lpszIconName, BOOL bStandard = TRUE); - - void SetMessageBeep ( UINT uType ); - - // Method for retrieving the icon to be displayed in the message box. - HICON GetMessageIcon ( ); - -public: - - ////////////////////////////////////////////////////////////////////////// - // Methods for handling common window functions. - - // Method for displaying the dialog. - virtual INT_PTR DoModal ( ); - - // Method for initializing the dialog. - virtual BOOL OnInitDialog ( ); - - // Method for handling command messages. - virtual BOOL OnCmdMsg ( UINT nID, int nCode, void* pExtra, - AFX_CMDHANDLERINFO* pHandlerInfo ); - - // Method for handling messages before dispatching them. - virtual BOOL PreTranslateMessage ( MSG* pMsg ); - -protected: - - ////////////////////////////////////////////////////////////////////////// - // Other methods for handling common window functions. - - // Method for handling window messages. - virtual BOOL OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam, - LRESULT* pResult ); - int buttonAreaY; //mpc-hc used for painting bg -private: - - ////////////////////////////////////////////////////////////////////////// - // Private member variables of this dialog. - - CString m_strMessage; // Message to be displayed. - CString m_strTitle; // Title to be used. - UINT m_nStyle; // Style of the message box. - UINT m_nHelp; // Help context of the message box. - - HICON m_hIcon; // Icon to be displayed in the dialog. - -private: - CSimpleMap m_aButtons; // List of all buttons in the dialog. - - int m_nDefaultButton; // ID of the default button. - int m_nEscapeButton; // ID of the escape button. - - - CStatic m_stcIcon; // Static control for the icon. - //mpc-hc use themed static instead (for message only--themed static has no impl for icons) - CMPCThemeStatic m_stcMessage; // Static control for the message. - CFont messageFont; - - CWnd* m_pParent; - - UINT m_uBeepType; - -private: - - ////////////////////////////////////////////////////////////////////////// - // Size handling variables. - - CSize m_sDialogUnit; // Variable for the size of a dialog unit. - CSize m_sIcon; // Variable for the size of the icon. - CSize m_sMessage; // Variable for the size of the message. - CSize m_sButton; // Variable for the size of a button. - -private: - - ////////////////////////////////////////////////////////////////////////// - // Helper methods. - - // Methods for converting a dialog units to a pixel values. - int XDialogUnitToPixel ( int x ); - int YDialogUnitToPixel ( int y ); - - // Method for parsing the given style. - void ParseStyle ( ); - - // Method for creating the icon control. - void CreateIconControl ( ); - - // Method for creating the message control. - void CreateMessageControl ( ); - - // Method for creating the button controls. - void CreateButtonControls ( ); - - // Method for defining the layout of the dialog. - void DefineLayout ( ); - -}; +/* + * Extended MFC message boxes -- Version 1.2 Lite + * Copyright (c) 2004 Michael P. Mehl. All rights reserved. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1a (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Copyright (c) 2004 Michael P. Mehl. All rights + * reserved. The Initial Developer of the Original Code is Michael P. Mehl + * . + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU Lesser General Public License Version 2.1 (the "LGPL License"), + * in which case the provisions of LGPL License are applicable instead of + * those above. If you wish to allow use of your version of this file only + * under the terms of the LGPL License and not to allow others to use your + * version of this file under the MPL, indicate your decision by deleting + * the provisions above and replace them with the notice and other provisions + * required by the LGPL License. If you do not delete the provisions above, + * a recipient may use your version of this file under either the MPL or + * the LGPL License. + */ + +#pragma once +#include "../mpc-hc/CMPCThemeStatic.h" +/* mpc-hc modified to use CMPCThemeStatic*/ + +////////////////////////////////////////////////////////////////////////////// +// Class definition. + +class CMessageBoxDialog : public CDialog +{ + + DECLARE_DYNAMIC(CMessageBoxDialog) + +public: + + ////////////////////////////////////////////////////////////////////////// + // Constructors and destructors of the class. + + // Constructor of the class for direct providing of the message strings. + CMessageBoxDialog ( CWnd* pParent, CString strMessage, + CString strTitle = _T(""), UINT nStyle = MB_OK, UINT nHelp = 0 ); + + // Constructor of the class for loading the strings from the resources. + CMessageBoxDialog ( CWnd* pParent, UINT nMessageID, UINT nTitleID = 0, + UINT nStyle = MB_OK, UINT nHelp = 0 ); + + // Default destructor of the class. + virtual ~CMessageBoxDialog ( ); + +public: + + ////////////////////////////////////////////////////////////////////////// + // Method for adding a button to the list of buttons. + void AddButton ( UINT nID, UINT nTitle, BOOL bIsDefault = FALSE, + BOOL bIsEscape = FALSE ); + + // Method for adding a button to the list of buttons. + void AddButton ( UINT nID, CString strTitle, BOOL bIsDefault = FALSE, + BOOL bIsEscape = FALSE ); + + // Method for setting the style of the message box. + void SetStyle ( UINT nStyle ); + + // Method for retrieving the style of the message box. + UINT GetStyle ( ); + + // Methods for setting the message to be displayed in the message box. + void SetMessage ( CString strMessage ); + void SetMessage ( UINT nMessageID ); + + // Method for retrieving the message to be displayed in the message box. + CString GetMessage ( ); + + // Methods for setting the title to be displayed in the message box. + void SetTitle ( CString strTitle ); + void SetTitle ( UINT nTitleID ); + + // Method for retrieving the title to be displayed in the message box. + CString GetTitle ( ); + + // Methods for setting the icon to be displayed in the message box. + void SetMessageIcon ( HICON hIcon ); + void SetMessageIcon ( LPCTSTR lpszIconName, BOOL bStandard = TRUE); + + void SetMessageBeep ( UINT uType ); + + // Method for retrieving the icon to be displayed in the message box. + HICON GetMessageIcon ( ); + +public: + + ////////////////////////////////////////////////////////////////////////// + // Methods for handling common window functions. + + // Method for displaying the dialog. + virtual INT_PTR DoModal ( ); + + // Method for initializing the dialog. + virtual BOOL OnInitDialog ( ); + + // Method for handling command messages. + virtual BOOL OnCmdMsg ( UINT nID, int nCode, void* pExtra, + AFX_CMDHANDLERINFO* pHandlerInfo ); + + // Method for handling messages before dispatching them. + virtual BOOL PreTranslateMessage ( MSG* pMsg ); + +protected: + + ////////////////////////////////////////////////////////////////////////// + // Other methods for handling common window functions. + + // Method for handling window messages. + virtual BOOL OnWndMsg ( UINT message, WPARAM wParam, LPARAM lParam, + LRESULT* pResult ); + int buttonAreaY; //mpc-hc used for painting bg +private: + + ////////////////////////////////////////////////////////////////////////// + // Private member variables of this dialog. + + CString m_strMessage; // Message to be displayed. + CString m_strTitle; // Title to be used. + UINT m_nStyle; // Style of the message box. + UINT m_nHelp; // Help context of the message box. + + HICON m_hIcon; // Icon to be displayed in the dialog. + +private: + CSimpleMap m_aButtons; // List of all buttons in the dialog. + + int m_nDefaultButton; // ID of the default button. + int m_nEscapeButton; // ID of the escape button. + + + CStatic m_stcIcon; // Static control for the icon. + //mpc-hc use themed static instead (for message only--themed static has no impl for icons) + CMPCThemeStatic m_stcMessage; // Static control for the message. + CFont messageFont; + + CWnd* m_pParent; + + UINT m_uBeepType; + +private: + + ////////////////////////////////////////////////////////////////////////// + // Size handling variables. + + CSize m_sDialogUnit; // Variable for the size of a dialog unit. + CSize m_sIcon; // Variable for the size of the icon. + CSize m_sMessage; // Variable for the size of the message. + CSize m_sButton; // Variable for the size of a button. + +private: + + ////////////////////////////////////////////////////////////////////////// + // Helper methods. + + // Methods for converting a dialog units to a pixel values. + int XDialogUnitToPixel ( int x ); + int YDialogUnitToPixel ( int y ); + + // Method for parsing the given style. + void ParseStyle ( ); + + // Method for creating the icon control. + void CreateIconControl ( ); + + // Method for creating the message control. + void CreateMessageControl ( ); + + // Method for creating the button controls. + void CreateButtonControls ( ); + + // Method for defining the layout of the dialog. + void DefineLayout ( ); + +}; diff --git a/src/thirdparty/MessageBoxDialog/lgpl-2.1.txt b/src/thirdparty/MessageBoxDialog/lgpl-2.1.txt index 92b8903ff3f..dc946ddca28 100755 --- a/src/thirdparty/MessageBoxDialog/lgpl-2.1.txt +++ b/src/thirdparty/MessageBoxDialog/lgpl-2.1.txt @@ -1,481 +1,481 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -General Public License (also called "this License"). Each licensee is -addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - c) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - d) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the source code distributed need not include anything that is normally -distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Library General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/src/thirdparty/MessageBoxDialog/mpl-1.1.txt b/src/thirdparty/MessageBoxDialog/mpl-1.1.txt index 7714141d154..7a45bfe8af2 100755 --- a/src/thirdparty/MessageBoxDialog/mpl-1.1.txt +++ b/src/thirdparty/MessageBoxDialog/mpl-1.1.txt @@ -1,470 +1,470 @@ - MOZILLA PUBLIC LICENSE - Version 1.1 - - --------------- - -1. Definitions. - - 1.0.1. "Commercial Use" means distribution or otherwise making the - Covered Code available to a third party. - - 1.1. "Contributor" means each entity that creates or contributes to - the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Code, prior Modifications used by a Contributor, and the Modifications - made by that particular Contributor. - - 1.3. "Covered Code" means the Original Code or Modifications or the - combination of the Original Code and Modifications, in each case - including portions thereof. - - 1.4. "Electronic Distribution Mechanism" means a mechanism generally - accepted in the software development community for the electronic - transfer of data. - - 1.5. "Executable" means Covered Code in any form other than Source - Code. - - 1.6. "Initial Developer" means the individual or entity identified - as the Initial Developer in the Source Code notice required by Exhibit - A. - - 1.7. "Larger Work" means a work which combines Covered Code or - portions thereof with code not governed by the terms of this License. - - 1.8. "License" means this document. - - 1.8.1. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means any addition to or deletion from the - substance or structure of either the Original Code or any previous - Modifications. When Covered Code is released as a series of files, a - Modification is: - A. Any addition to or deletion from the contents of a file - containing Original Code or previous Modifications. - - B. Any new file that contains any part of the Original Code or - previous Modifications. - - 1.10. "Original Code" means Source Code of computer software code - which is described in the Source Code notice required by Exhibit A as - Original Code, and which, at the time of its release under this - License is not already Covered Code governed by this License. - - 1.10.1. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.11. "Source Code" means the preferred form of the Covered Code for - making modifications to it, including all modules it contains, plus - any associated interface definition files, scripts used to control - compilation and installation of an Executable, or source code - differential comparisons against either the Original Code or another - well known, available Covered Code of the Contributor's choice. The - Source Code can be in a compressed or archival form, provided the - appropriate decompression or de-archiving software is widely available - for no charge. - - 1.12. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, this - License or a future version of this License issued under Section 6.1. - For legal entities, "You" includes any entity which controls, is - controlled by, or is under common control with You. For purposes of - this definition, "control" means (a) the power, direct or indirect, - to cause the direction or management of such entity, whether by - contract or otherwise, or (b) ownership of more than fifty percent - (50%) of the outstanding shares or beneficial ownership of such - entity. - -2. Source Code License. - - 2.1. The Initial Developer Grant. - The Initial Developer hereby grants You a world-wide, royalty-free, - non-exclusive license, subject to third party intellectual property - claims: - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Code (or portions thereof) with or without Modifications, and/or - as part of a Larger Work; and - - (b) under Patents Claims infringed by the making, using or - selling of Original Code, to make, have made, use, practice, - sell, and offer for sale, and/or otherwise dispose of the - Original Code (or portions thereof). - - (c) the licenses granted in this Section 2.1(a) and (b) are - effective on the date Initial Developer first distributes - Original Code under the terms of this License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: 1) for code that You delete from the Original Code; 2) - separate from the Original Code; or 3) for infringements caused - by: i) the modification of the Original Code or ii) the - combination of the Original Code with other software or devices. - - 2.2. Contributor Grant. - Subject to third party intellectual property claims, each Contributor - hereby grants You a world-wide, royalty-free, non-exclusive license - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor, to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof) either on an - unmodified basis, with other Modifications, as Covered Code - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either alone - and/or in combination with its Contributor Version (or portions - of such combination), to make, use, sell, offer for sale, have - made, and/or otherwise dispose of: 1) Modifications made by that - Contributor (or portions thereof); and 2) the combination of - Modifications made by that Contributor with its Contributor - Version (or portions of such combination). - - (c) the licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first makes Commercial Use of - the Covered Code. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: 1) for any code that Contributor has deleted from the - Contributor Version; 2) separate from the Contributor Version; - 3) for infringements caused by: i) third party modifications of - Contributor Version or ii) the combination of Modifications made - by that Contributor with other software (except as part of the - Contributor Version) or other devices; or 4) under Patent Claims - infringed by Covered Code in the absence of Modifications made by - that Contributor. - -3. Distribution Obligations. - - 3.1. Application of License. - The Modifications which You create or to which You contribute are - governed by the terms of this License, including without limitation - Section 2.2. The Source Code version of Covered Code may be - distributed only under the terms of this License or a future version - of this License released under Section 6.1, and You must include a - copy of this License with every copy of the Source Code You - distribute. You may not offer or impose any terms on any Source Code - version that alters or restricts the applicable version of this - License or the recipients' rights hereunder. However, You may include - an additional document offering the additional rights described in - Section 3.5. - - 3.2. Availability of Source Code. - Any Modification which You create or to which You contribute must be - made available in Source Code form under the terms of this License - either on the same media as an Executable version or via an accepted - Electronic Distribution Mechanism to anyone to whom you made an - Executable version available; and if made available via Electronic - Distribution Mechanism, must remain available for at least twelve (12) - months after the date it initially became available, or at least six - (6) months after a subsequent version of that particular Modification - has been made available to such recipients. You are responsible for - ensuring that the Source Code version remains available even if the - Electronic Distribution Mechanism is maintained by a third party. - - 3.3. Description of Modifications. - You must cause all Covered Code to which You contribute to contain a - file documenting the changes You made to create that Covered Code and - the date of any change. You must include a prominent statement that - the Modification is derived, directly or indirectly, from Original - Code provided by the Initial Developer and including the name of the - Initial Developer in (a) the Source Code, and (b) in any notice in an - Executable version or related documentation in which You describe the - origin or ownership of the Covered Code. - - 3.4. Intellectual Property Matters - (a) Third Party Claims. - If Contributor has knowledge that a license under a third party's - intellectual property rights is required to exercise the rights - granted by such Contributor under Sections 2.1 or 2.2, - Contributor must include a text file with the Source Code - distribution titled "LEGAL" which describes the claim and the - party making the claim in sufficient detail that a recipient will - know whom to contact. If Contributor obtains such knowledge after - the Modification is made available as described in Section 3.2, - Contributor shall promptly modify the LEGAL file in all copies - Contributor makes available thereafter and shall take other steps - (such as notifying appropriate mailing lists or newsgroups) - reasonably calculated to inform those who received the Covered - Code that new knowledge has been obtained. - - (b) Contributor APIs. - If Contributor's Modifications include an application programming - interface and Contributor has knowledge of patent licenses which - are reasonably necessary to implement that API, Contributor must - also include this information in the LEGAL file. - - (c) Representations. - Contributor represents that, except as disclosed pursuant to - Section 3.4(a) above, Contributor believes that Contributor's - Modifications are Contributor's original creation(s) and/or - Contributor has sufficient rights to grant the rights conveyed by - this License. - - 3.5. Required Notices. - You must duplicate the notice in Exhibit A in each file of the Source - Code. If it is not possible to put such notice in a particular Source - Code file due to its structure, then You must include such notice in a - location (such as a relevant directory) where a user would be likely - to look for such a notice. If You created one or more Modification(s) - You may add your name as a Contributor to the notice described in - Exhibit A. You must also duplicate this License in any documentation - for the Source Code where You describe recipients' rights or ownership - rights relating to Covered Code. You may choose to offer, and to - charge a fee for, warranty, support, indemnity or liability - obligations to one or more recipients of Covered Code. However, You - may do so only on Your own behalf, and not on behalf of the Initial - Developer or any Contributor. You must make it absolutely clear than - any such warranty, support, indemnity or liability obligation is - offered by You alone, and You hereby agree to indemnify the Initial - Developer and every Contributor for any liability incurred by the - Initial Developer or such Contributor as a result of warranty, - support, indemnity or liability terms You offer. - - 3.6. Distribution of Executable Versions. - You may distribute Covered Code in Executable form only if the - requirements of Section 3.1-3.5 have been met for that Covered Code, - and if You include a notice stating that the Source Code version of - the Covered Code is available under the terms of this License, - including a description of how and where You have fulfilled the - obligations of Section 3.2. The notice must be conspicuously included - in any notice in an Executable version, related documentation or - collateral in which You describe recipients' rights relating to the - Covered Code. You may distribute the Executable version of Covered - Code or ownership rights under a license of Your choice, which may - contain terms different from this License, provided that You are in - compliance with the terms of this License and that the license for the - Executable version does not attempt to limit or alter the recipient's - rights in the Source Code version from the rights set forth in this - License. If You distribute the Executable version under a different - license You must make it absolutely clear that any terms which differ - from this License are offered by You alone, not by the Initial - Developer or any Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred by - the Initial Developer or such Contributor as a result of any such - terms You offer. - - 3.7. Larger Works. - You may create a Larger Work by combining Covered Code with other code - not governed by the terms of this License and distribute the Larger - Work as a single product. In such a case, You must make sure the - requirements of this License are fulfilled for the Covered Code. - -4. Inability to Comply Due to Statute or Regulation. - - If it is impossible for You to comply with any of the terms of this - License with respect to some or all of the Covered Code due to - statute, judicial order, or regulation then You must: (a) comply with - the terms of this License to the maximum extent possible; and (b) - describe the limitations and the code they affect. Such description - must be included in the LEGAL file described in Section 3.4 and must - be included with all distributions of the Source Code. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Application of this License. - - This License applies to code to which the Initial Developer has - attached the notice in Exhibit A and to related Covered Code. - -6. Versions of the License. - - 6.1. New Versions. - Netscape Communications Corporation ("Netscape") may publish revised - and/or new versions of the License from time to time. Each version - will be given a distinguishing version number. - - 6.2. Effect of New Versions. - Once Covered Code has been published under a particular version of the - License, You may always continue to use it under the terms of that - version. You may also choose to use such Covered Code under the terms - of any subsequent version of the License published by Netscape. No one - other than Netscape has the right to modify the terms applicable to - Covered Code created under this License. - - 6.3. Derivative Works. - If You create or use a modified version of this License (which you may - only do in order to apply it to code which is not already Covered Code - governed by this License), You must (a) rename Your license so that - the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", - "MPL", "NPL" or any confusingly similar phrase do not appear in your - license (except to note that your license differs from this License) - and (b) otherwise make it clear that Your version of the license - contains terms which differ from the Mozilla Public License and - Netscape Public License. (Filling in the name of the Initial - Developer, Original Code or Contributor in the notice described in - Exhibit A shall not of themselves be deemed to be modifications of - this License.) - -7. DISCLAIMER OF WARRANTY. - - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, - WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF - DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. - THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE - IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, - YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE - COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER - OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -8. TERMINATION. - - 8.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to cure - such breach within 30 days of becoming aware of the breach. All - sublicenses to the Covered Code which are properly granted shall - survive any termination of this License. Provisions which, by their - nature, must remain in effect beyond the termination of this License - shall survive. - - 8.2. If You initiate litigation by asserting a patent infringement - claim (excluding declatory judgment actions) against Initial Developer - or a Contributor (the Initial Developer or Contributor against whom - You file such action is referred to as "Participant") alleging that: - - (a) such Participant's Contributor Version directly or indirectly - infringes any patent, then any and all rights granted by such - Participant to You under Sections 2.1 and/or 2.2 of this License - shall, upon 60 days notice from Participant terminate prospectively, - unless if within 60 days after receipt of notice You either: (i) - agree in writing to pay Participant a mutually agreeable reasonable - royalty for Your past and future use of Modifications made by such - Participant, or (ii) withdraw Your litigation claim with respect to - the Contributor Version against such Participant. If within 60 days - of notice, a reasonable royalty and payment arrangement are not - mutually agreed upon in writing by the parties or the litigation claim - is not withdrawn, the rights granted by Participant to You under - Sections 2.1 and/or 2.2 automatically terminate at the expiration of - the 60 day notice period specified above. - - (b) any software, hardware, or device, other than such Participant's - Contributor Version, directly or indirectly infringes any patent, then - any rights granted to You by such Participant under Sections 2.1(b) - and 2.2(b) are revoked effective as of the date You first made, used, - sold, distributed, or had made, Modifications made by that - Participant. - - 8.3. If You assert a patent infringement claim against Participant - alleging that such Participant's Contributor Version directly or - indirectly infringes any patent where such claim is resolved (such as - by license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 8.4. In the event of termination under Sections 8.1 or 8.2 above, - all end user license agreements (excluding distributors and resellers) - which have been validly granted by You or any distributor hereunder - prior to termination shall survive termination. - -9. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL - DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, - OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR - ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY - CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, - WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY - RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW - PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO - THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - -10. U.S. GOVERNMENT END USERS. - - The Covered Code is a "commercial item," as that term is defined in - 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" and "commercial computer software documentation," as such - terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 - C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), - all U.S. Government End Users acquire Covered Code with only those - rights set forth herein. - -11. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - California law provisions (except to the extent applicable law, if - any, provides otherwise), excluding its conflict-of-law provisions. - With respect to disputes in which at least one party is a citizen of, - or an entity chartered or registered to do business in the United - States of America, any litigation relating to this License shall be - subject to the jurisdiction of the Federal Courts of the Northern - District of California, with venue lying in Santa Clara County, - California, with the losing party responsible for costs, including - without limitation, court costs and reasonable attorneys' fees and - expenses. The application of the United Nations Convention on - Contracts for the International Sale of Goods is expressly excluded. - Any law or regulation which provides that the language of a contract - shall be construed against the drafter shall not apply to this - License. - -12. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - -13. MULTIPLE-LICENSED CODE. - - Initial Developer may designate portions of the Covered Code as - "Multiple-Licensed". "Multiple-Licensed" means that the Initial - Developer permits you to utilize portions of the Covered Code under - Your choice of the NPL or the alternative licenses, if any, specified - by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. - - ``The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is ______________________________________. - - The Initial Developer of the Original Code is ________________________. - Portions created by ______________________ are Copyright (C) ______ - _______________________. All Rights Reserved. - - Contributor(s): ______________________________________. - - Alternatively, the contents of this file may be used under the terms - of the _____ license (the "[___] License"), in which case the - provisions of [______] License are applicable instead of those - above. If you wish to allow use of your version of this file only - under the terms of the [____] License and not to allow others to use - your version of this file under the MPL, indicate your decision by - deleting the provisions above and replace them with the notice and - other provisions required by the [___] License. If you do not delete - the provisions above, a recipient may use your version of this file - under either the MPL or the [___] License." - - [NOTE: The text of this Exhibit A may differ slightly from the text of - the notices in the Source Code files of the Original Code. You should - use the text of this Exhibit A rather than the text found in the - Original Code Source Code for Your Modifications.] - + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + diff --git a/src/thirdparty/RARFileSource/File.h b/src/thirdparty/RARFileSource/File.h index 7ee0e0d989e..0547638d4f5 100644 --- a/src/thirdparty/RARFileSource/File.h +++ b/src/thirdparty/RARFileSource/File.h @@ -36,18 +36,18 @@ class CRFSFile : public CRFSNode delete [] rarFilename; } - class ReadThread { - public: - ReadThread(CRFSFile* file, LONGLONG llPosition, DWORD lLength, BYTE* pBuffer); - DWORD ThreadStart(); - static DWORD WINAPI ThreadStartStatic(void* param); - CRFSFile* file; - LONGLONG llPosition; - DWORD lLength; - BYTE* pBuffer; - LONG read; - }; - static HRESULT SyncRead(void *param); + class ReadThread { + public: + ReadThread(CRFSFile* file, LONGLONG llPosition, DWORD lLength, BYTE* pBuffer); + DWORD ThreadStart(); + static DWORD WINAPI ThreadStartStatic(void* param); + CRFSFile* file; + LONGLONG llPosition; + DWORD lLength; + BYTE* pBuffer; + LONG read; + }; + static HRESULT SyncRead(void *param); HRESULT SyncRead (LONGLONG llPosition, DWORD lLength, BYTE* pBuffer, LONG *cbActual); CMediaType media_type; diff --git a/src/thirdparty/RARFileSource/OutputPin.h b/src/thirdparty/RARFileSource/OutputPin.h index a6dd5822c08..9e8da66d82e 100644 --- a/src/thirdparty/RARFileSource/OutputPin.h +++ b/src/thirdparty/RARFileSource/OutputPin.h @@ -63,7 +63,7 @@ class CRFSOutputPin : // IAsyncReader interface STDMETHODIMP RequestAllocator (IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual); - STDMETHODIMP Request (IMediaSample* pSample, DWORD_PTR dwUser); + STDMETHODIMP Request (IMediaSample* pSample, DWORD_PTR dwUser); STDMETHODIMP WaitForNext (DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser); STDMETHODIMP SyncReadAligned (IMediaSample *pSample); diff --git a/src/thirdparty/RARFileSource/RARFileSource.vcxproj b/src/thirdparty/RARFileSource/RARFileSource.vcxproj index 76764dc8bfa..c328dd132fd 100644 --- a/src/thirdparty/RARFileSource/RARFileSource.vcxproj +++ b/src/thirdparty/RARFileSource/RARFileSource.vcxproj @@ -1,94 +1,94 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {2B7F22D7-1750-47C5-8709-1A3688B62499} - RARFileSource - Win32Proj - RARFileSource - - - - - StaticLibrary - Unicode - - - - - - - - - - - False - - - - ..\..\thirdparty;..\BaseClasses;%(AdditionalIncludeDirectories) - _LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - NotUsing - - - $(OutDir)$(ProjectName).res - - - - - {273b3149-3192-4b75-a791-470320b90812} - - - {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} - - - {da8461c4-7683-4360-9372-2a9e0f1795c2} - - - - - - - - - - - - - - - - - - - true - true - true - true - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2B7F22D7-1750-47C5-8709-1A3688B62499} + RARFileSource + Win32Proj + RARFileSource + + + + + StaticLibrary + Unicode + + + + + + + + + + + False + + + + ..\..\thirdparty;..\BaseClasses;%(AdditionalIncludeDirectories) + _LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + NotUsing + + + $(OutDir)$(ProjectName).res + + + + + {273b3149-3192-4b75-a791-470320b90812} + + + {e8a3f6fa-ae1c-4c8e-a0b6-9c8480324eaa} + + + {da8461c4-7683-4360-9372-2a9e0f1795c2} + + + + + + + + + + + + + + + + + + + true + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/RARFileSource/RARFileSource.vcxproj.filters b/src/thirdparty/RARFileSource/RARFileSource.vcxproj.filters index 4fed9af44e3..2ded65c9351 100644 --- a/src/thirdparty/RARFileSource/RARFileSource.vcxproj.filters +++ b/src/thirdparty/RARFileSource/RARFileSource.vcxproj.filters @@ -1,68 +1,68 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Resource Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/src/thirdparty/ResizableLib/ResizableDialog.cpp b/src/thirdparty/ResizableLib/ResizableDialog.cpp index bdb75fe5aaf..7c95712be7f 100644 --- a/src/thirdparty/ResizableLib/ResizableDialog.cpp +++ b/src/thirdparty/ResizableLib/ResizableDialog.cpp @@ -1,166 +1,166 @@ -// ResizableDialog.cpp : implementation file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "ResizableDialog.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CResizableDialog - -inline void CResizableDialog::PrivateConstruct() -{ - m_bEnableSaveRestore = FALSE; - m_dwGripTempState = 1; - m_bRectOnly = FALSE; -} - -CResizableDialog::CResizableDialog() -{ - PrivateConstruct(); -} - -CResizableDialog::CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd) - : CCmdUIDialog(nIDTemplate, pParentWnd) -{ - PrivateConstruct(); -} - -CResizableDialog::CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) - : CCmdUIDialog(lpszTemplateName, pParentWnd) -{ - PrivateConstruct(); -} - -CResizableDialog::~CResizableDialog() -{ -} - - -BEGIN_MESSAGE_MAP(CResizableDialog, CCmdUIDialog) - //{{AFX_MSG_MAP(CResizableDialog) - ON_WM_GETMINMAXINFO() - ON_WM_SIZE() - ON_WM_DESTROY() - ON_WM_ERASEBKGND() - ON_WM_NCCREATE() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CResizableDialog message handlers - -BOOL CResizableDialog::OnNcCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (!CCmdUIDialog::OnNcCreate(lpCreateStruct)) - return FALSE; - - // child dialogs don't want resizable border or size grip, - // nor they can handle the min/max size constraints - BOOL bChild = lpCreateStruct->style & WS_CHILD; - - // create and init the size-grip - if (!CreateSizeGrip(!bChild)) - return FALSE; - - // Moved from behind if (!bChild) because user could resize the dialog smaller as in resource defined and that causes some static text to be clipped or disappear. - MakeResizable(lpCreateStruct); - - if (!bChild) - { - // set the initial size as the min track size - SetMinTrackSize(CSize(lpCreateStruct->cx, lpCreateStruct->cy)); - } - - return TRUE; -} - -void CResizableDialog::OnDestroy() -{ - if (m_bEnableSaveRestore) - SaveWindowRect(m_sSection, m_bRectOnly); - - // reset instance data - RemoveAllAnchors(); - ResetAllRects(); - PrivateConstruct(); - - __super::OnDestroy(); -} - -void CResizableDialog::OnSize(UINT nType, int cx, int cy) -{ - __super::OnSize(nType, cx, cy); - - if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) - return; // arrangement not needed - - if (nType == SIZE_MAXIMIZED) - HideSizeGrip(&m_dwGripTempState); - else - ShowSizeGrip(&m_dwGripTempState); - - // update grip and layout - UpdateSizeGrip(); - ArrangeLayout(); -} - -void CResizableDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) -{ - MinMaxInfo(lpMMI); -} - -// NOTE: this must be called after setting the layout -// to have the dialog and its controls displayed properly -void CResizableDialog::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly) -{ - m_sSection = pszSection; - - m_bEnableSaveRestore = TRUE; - m_bRectOnly = bRectOnly; - - // restore immediately - LoadWindowRect(pszSection, bRectOnly); -} - -BOOL CResizableDialog::OnEraseBkgnd(CDC* pDC) -{ - ClipChildren(pDC, FALSE); - - BOOL bRet = __super::OnEraseBkgnd(pDC); - - ClipChildren(pDC, TRUE); - - return bRet; -} - -LRESULT CResizableDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message != WM_NCCALCSIZE || wParam == 0) - return __super::WindowProc(message, wParam, lParam); - - LRESULT lResult = 0; - HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - lResult = __super::WindowProc(message, wParam, lParam); - HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - return lResult; -} +// ResizableDialog.cpp : implementation file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ResizableDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CResizableDialog + +inline void CResizableDialog::PrivateConstruct() +{ + m_bEnableSaveRestore = FALSE; + m_dwGripTempState = 1; + m_bRectOnly = FALSE; +} + +CResizableDialog::CResizableDialog() +{ + PrivateConstruct(); +} + +CResizableDialog::CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd) + : CCmdUIDialog(nIDTemplate, pParentWnd) +{ + PrivateConstruct(); +} + +CResizableDialog::CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) + : CCmdUIDialog(lpszTemplateName, pParentWnd) +{ + PrivateConstruct(); +} + +CResizableDialog::~CResizableDialog() +{ +} + + +BEGIN_MESSAGE_MAP(CResizableDialog, CCmdUIDialog) + //{{AFX_MSG_MAP(CResizableDialog) + ON_WM_GETMINMAXINFO() + ON_WM_SIZE() + ON_WM_DESTROY() + ON_WM_ERASEBKGND() + ON_WM_NCCREATE() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CResizableDialog message handlers + +BOOL CResizableDialog::OnNcCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (!CCmdUIDialog::OnNcCreate(lpCreateStruct)) + return FALSE; + + // child dialogs don't want resizable border or size grip, + // nor they can handle the min/max size constraints + BOOL bChild = lpCreateStruct->style & WS_CHILD; + + // create and init the size-grip + if (!CreateSizeGrip(!bChild)) + return FALSE; + + // Moved from behind if (!bChild) because user could resize the dialog smaller as in resource defined and that causes some static text to be clipped or disappear. + MakeResizable(lpCreateStruct); + + if (!bChild) + { + // set the initial size as the min track size + SetMinTrackSize(CSize(lpCreateStruct->cx, lpCreateStruct->cy)); + } + + return TRUE; +} + +void CResizableDialog::OnDestroy() +{ + if (m_bEnableSaveRestore) + SaveWindowRect(m_sSection, m_bRectOnly); + + // reset instance data + RemoveAllAnchors(); + ResetAllRects(); + PrivateConstruct(); + + __super::OnDestroy(); +} + +void CResizableDialog::OnSize(UINT nType, int cx, int cy) +{ + __super::OnSize(nType, cx, cy); + + if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) + return; // arrangement not needed + + if (nType == SIZE_MAXIMIZED) + HideSizeGrip(&m_dwGripTempState); + else + ShowSizeGrip(&m_dwGripTempState); + + // update grip and layout + UpdateSizeGrip(); + ArrangeLayout(); +} + +void CResizableDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + MinMaxInfo(lpMMI); +} + +// NOTE: this must be called after setting the layout +// to have the dialog and its controls displayed properly +void CResizableDialog::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly) +{ + m_sSection = pszSection; + + m_bEnableSaveRestore = TRUE; + m_bRectOnly = bRectOnly; + + // restore immediately + LoadWindowRect(pszSection, bRectOnly); +} + +BOOL CResizableDialog::OnEraseBkgnd(CDC* pDC) +{ + ClipChildren(pDC, FALSE); + + BOOL bRet = __super::OnEraseBkgnd(pDC); + + ClipChildren(pDC, TRUE); + + return bRet; +} + +LRESULT CResizableDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message != WM_NCCALCSIZE || wParam == 0) + return __super::WindowProc(message, wParam, lParam); + + LRESULT lResult = 0; + HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + lResult = __super::WindowProc(message, wParam, lParam); + HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + return lResult; +} diff --git a/src/thirdparty/ResizableLib/ResizableDialog.h b/src/thirdparty/ResizableLib/ResizableDialog.h index 55882c0079c..da03bc3750c 100644 --- a/src/thirdparty/ResizableLib/ResizableDialog.h +++ b/src/thirdparty/ResizableLib/ResizableDialog.h @@ -1,103 +1,103 @@ -#if !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_) -#define AFX_RESIZABLEDIALOG_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -// ResizableDialog.h : header file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "ResizableLayout.h" -#include "ResizableGrip.h" -#include "ResizableMinMax.h" -#include "ResizableWndState.h" -#include "../../CmdUI/CmdUI.h" - -///////////////////////////////////////////////////////////////////////////// -// CResizableDialog window - -class CResizableDialog : public CCmdUIDialog, public CResizableLayout, - public CResizableGrip, public CResizableMinMax, - public CResizableWndState -{ - -// Construction -public: - CResizableDialog(); - explicit CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); - explicit CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); - -// Attributes -private: - // support for temporarily hiding the grip - DWORD m_dwGripTempState; - - // flags - BOOL m_bEnableSaveRestore; - BOOL m_bRectOnly; - - // internal status - CString m_sSection; // section name (identifies a parent window) - -// Operations -public: - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CResizableDialog) - protected: - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CResizableDialog(); - -// used internally -private: - void PrivateConstruct(); - -// callable from derived classes -protected: - // section to use in app's profile - void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE); - - virtual CWnd* GetResizableWnd() const - { - // make the layout know its parent window - return CWnd::FromHandle(m_hWnd); - }; - -// Generated message map functions -protected: - //{{AFX_MSG(CResizableDialog) - afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnDestroy(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_) +#if !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_) +#define AFX_RESIZABLEDIALOG_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// ResizableDialog.h : header file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "ResizableLayout.h" +#include "ResizableGrip.h" +#include "ResizableMinMax.h" +#include "ResizableWndState.h" +#include "../../CmdUI/CmdUI.h" + +///////////////////////////////////////////////////////////////////////////// +// CResizableDialog window + +class CResizableDialog : public CCmdUIDialog, public CResizableLayout, + public CResizableGrip, public CResizableMinMax, + public CResizableWndState +{ + +// Construction +public: + CResizableDialog(); + explicit CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); + explicit CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); + +// Attributes +private: + // support for temporarily hiding the grip + DWORD m_dwGripTempState; + + // flags + BOOL m_bEnableSaveRestore; + BOOL m_bRectOnly; + + // internal status + CString m_sSection; // section name (identifies a parent window) + +// Operations +public: + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CResizableDialog) + protected: + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CResizableDialog(); + +// used internally +private: + void PrivateConstruct(); + +// callable from derived classes +protected: + // section to use in app's profile + void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE); + + virtual CWnd* GetResizableWnd() const + { + // make the layout know its parent window + return CWnd::FromHandle(m_hWnd); + }; + +// Generated message map functions +protected: + //{{AFX_MSG(CResizableDialog) + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnDestroy(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableGrip.cpp b/src/thirdparty/ResizableLib/ResizableGrip.cpp index 2a777fcdba6..0071fdb7371 100644 --- a/src/thirdparty/ResizableLib/ResizableGrip.cpp +++ b/src/thirdparty/ResizableLib/ResizableGrip.cpp @@ -1,319 +1,319 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Implementation of the CResizableGrip class. - */ - -#include "stdafx.h" -#include "ResizableGrip.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[]=__FILE__; -#define new DEBUG_NEW -#endif - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResizableGrip::CResizableGrip() -{ - m_nShowCount = 0; -} - -CResizableGrip::~CResizableGrip() -{ - -} - -void CResizableGrip::UpdateSizeGrip() -{ - if (!::IsWindow(m_wndGrip.m_hWnd)) - return; - - // size-grip goes bottom right in the client area - // (any right-to-left adjustment should go here) - - RECT rect; - GetResizableWnd()->GetClientRect(&rect); - - rect.left = rect.right - m_wndGrip.m_size.cx; - rect.top = rect.bottom - m_wndGrip.m_size.cy; - - // must stay below other children - m_wndGrip.SetWindowPos(&CWnd::wndBottom, rect.left, rect.top, 0, 0, - SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION - | (IsSizeGripVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); -} - -// pStatus points to a variable, maintained by the caller, that -// holds its visibility status. Initialize the variable with 1 -// to allow to temporarily hide the grip, 0 to allow to -// temporarily show the grip (with respect to the dwMask bit). - -// NB: visibility is effective only after an update - -void CResizableGrip::ShowSizeGrip(DWORD* pStatus, DWORD dwMask /*= 1*/) -{ - ASSERT(pStatus != NULL); - - if (!(*pStatus & dwMask)) - { - m_nShowCount++; - (*pStatus) |= dwMask; - } -} - -void CResizableGrip::HideSizeGrip(DWORD* pStatus, DWORD dwMask /*= 1*/) -{ - ASSERT(pStatus != NULL); - - if (*pStatus & dwMask) - { - m_nShowCount--; - (*pStatus) &= ~dwMask; - } -} - -BOOL CResizableGrip::IsSizeGripVisible() const -{ - // NB: visibility is effective only after an update - return (m_nShowCount > 0); -} - -void CResizableGrip::SetSizeGripVisibility(BOOL bVisible) -{ - if (bVisible) - m_nShowCount = 1; - else - m_nShowCount = 0; -} - -BOOL CResizableGrip::SetSizeGripBkMode(int nBkMode) -{ - if (::IsWindow(m_wndGrip.m_hWnd)) - { - if (nBkMode == OPAQUE) - m_wndGrip.SetTransparency(FALSE); - else if (nBkMode == TRANSPARENT) - m_wndGrip.SetTransparency(TRUE); - else - return FALSE; - return TRUE; - } - return FALSE; -} - -void CResizableGrip::SetSizeGripShape(BOOL bTriangular) -{ - if (::IsWindow(m_wndGrip.m_hWnd)) - m_wndGrip.SetTriangularShape(bTriangular); -} - -BOOL CResizableGrip::CreateSizeGrip(BOOL bVisible /*= TRUE*/, - BOOL bTriangular /*= TRUE*/, BOOL bTransparent /*= FALSE*/) -{ - // create grip - CRect rect(0 , 0, m_wndGrip.m_size.cx, m_wndGrip.m_size.cy); - BOOL bRet = m_wndGrip.Create(WS_CHILD | WS_CLIPSIBLINGS - | SBS_SIZEGRIP, rect, GetResizableWnd(), 0); - - if (bRet) - { - // set options - m_wndGrip.SetTriangularShape(bTriangular); - m_wndGrip.SetTransparency(bTransparent); - SetSizeGripVisibility(bVisible); - - // update position - UpdateSizeGrip(); - } - - return bRet; -} - -///////////////////////////////////////////////////////////////////////////// -// CSizeGrip implementation - -BOOL CResizableGrip::CSizeGrip::IsRTL() -{ - return GetExStyle() & WS_EX_LAYOUTRTL; -} - -BOOL CResizableGrip::CSizeGrip::PreCreateWindow(CREATESTRUCT& cs) -{ - // set window size - m_size.cx = GetSystemMetrics(SM_CXVSCROLL); - m_size.cy = GetSystemMetrics(SM_CYHSCROLL); - - cs.cx = m_size.cx; - cs.cy = m_size.cy; - - return CScrollBar::PreCreateWindow(cs); -} - -LRESULT CResizableGrip::CSizeGrip::WindowProc(UINT message, - WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_GETDLGCODE: - // fix to prevent the control to gain focus, using arrow keys - // (standard grip returns DLGC_WANTARROWS, like any standard scrollbar) - return DLGC_STATIC; - - case WM_SETFOCUS: - // fix to prevent the control to gain focus, if set directly - // (for example when it's the only one control in a dialog) - return 0; - - case WM_NCHITTEST: - // choose proper cursor shape - return IsRTL() ? HTBOTTOMLEFT : HTBOTTOMRIGHT; - - case WM_SETTINGCHANGE: - { - // update grip's size - CSize sizeOld = m_size; - m_size.cx = GetSystemMetrics(SM_CXVSCROLL); - m_size.cy = GetSystemMetrics(SM_CYHSCROLL); - - // resize transparency bitmaps - if (m_bTransparent) - { - CClientDC dc(this); - - // destroy bitmaps - m_bmGrip.DeleteObject(); - m_bmMask.DeleteObject(); - - // re-create bitmaps - m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy); - m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL); - } - - // re-calc shape - if (m_bTriangular) - SetTriangularShape(m_bTriangular); - - // reposition the grip - CRect rect; - GetWindowRect(rect); - rect.InflateRect(m_size.cx - sizeOld.cx, m_size.cy - sizeOld.cy, 0, 0); - ::MapWindowPoints(NULL, GetParent()->GetSafeHwnd(), (LPPOINT)&rect, 2); - MoveWindow(rect, TRUE); - } - break; - - case WM_DESTROY: - // perform clean up - if (m_bTransparent) - SetTransparency(FALSE); - break; - - case WM_PAINT: - case WM_PRINTCLIENT: - if (m_bTransparent) - { - PAINTSTRUCT ps; - CDC* pDC = (message == WM_PAINT && wParam == 0) ? - BeginPaint(&ps) : CDC::FromHandle((HDC)wParam); - - // select bitmaps - CBitmap *pOldGrip = m_dcGrip.SelectObject(&m_bmGrip); - CBitmap *pOldMask = m_dcMask.SelectObject(&m_bmMask); - - // obtain original grip bitmap, make the mask and prepare masked bitmap - CScrollBar::WindowProc(message, (WPARAM)m_dcGrip.GetSafeHdc(), lParam); - m_dcGrip.SetBkColor(m_dcGrip.GetPixel(0, 0)); - m_dcMask.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCCOPY); - m_dcGrip.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, 0x00220326); - - // draw transparently - pDC->BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, SRCAND); - pDC->BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCPAINT); - - // unselect bitmaps - m_dcGrip.SelectObject(pOldGrip); - m_dcMask.SelectObject(pOldMask); - - if (message == WM_PAINT && wParam == 0) - EndPaint(&ps); - return 0; - } - } - - return CScrollBar::WindowProc(message, wParam, lParam); -} - -void CResizableGrip::CSizeGrip::SetTransparency(BOOL bActivate) -{ - // creates or deletes DCs and Bitmaps used for - // implementing a transparent size grip - - if (bActivate && !m_bTransparent) - { - m_bTransparent = TRUE; - - CClientDC dc(this); - - // create memory DCs and bitmaps - m_dcGrip.CreateCompatibleDC(&dc); - m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy); - - m_dcMask.CreateCompatibleDC(&dc); - m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL); - } - else if (!bActivate && m_bTransparent) - { - m_bTransparent = FALSE; - - // destroy memory DCs and bitmaps - m_dcGrip.DeleteDC(); - m_bmGrip.DeleteObject(); - - m_dcMask.DeleteDC(); - m_bmMask.DeleteObject(); - } -} - -void CResizableGrip::CSizeGrip::SetTriangularShape(BOOL bEnable) -{ - m_bTriangular = bEnable; - - if (bEnable) - { - // set a triangular window region - CRect rect; - GetWindowRect(rect); - rect.OffsetRect(-rect.TopLeft()); - POINT arrPoints[] = - { - { rect.left, rect.bottom }, - { rect.right, rect.bottom }, - { rect.right, rect.top } - }; - CRgn rgnGrip; - rgnGrip.CreatePolygonRgn(arrPoints, 3, WINDING); - SetWindowRgn((HRGN)rgnGrip.Detach(), IsWindowVisible()); - } - else - { - SetWindowRgn((HRGN)NULL, IsWindowVisible()); - } +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Implementation of the CResizableGrip class. + */ + +#include "stdafx.h" +#include "ResizableGrip.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResizableGrip::CResizableGrip() +{ + m_nShowCount = 0; +} + +CResizableGrip::~CResizableGrip() +{ + +} + +void CResizableGrip::UpdateSizeGrip() +{ + if (!::IsWindow(m_wndGrip.m_hWnd)) + return; + + // size-grip goes bottom right in the client area + // (any right-to-left adjustment should go here) + + RECT rect; + GetResizableWnd()->GetClientRect(&rect); + + rect.left = rect.right - m_wndGrip.m_size.cx; + rect.top = rect.bottom - m_wndGrip.m_size.cy; + + // must stay below other children + m_wndGrip.SetWindowPos(&CWnd::wndBottom, rect.left, rect.top, 0, 0, + SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION + | (IsSizeGripVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); +} + +// pStatus points to a variable, maintained by the caller, that +// holds its visibility status. Initialize the variable with 1 +// to allow to temporarily hide the grip, 0 to allow to +// temporarily show the grip (with respect to the dwMask bit). + +// NB: visibility is effective only after an update + +void CResizableGrip::ShowSizeGrip(DWORD* pStatus, DWORD dwMask /*= 1*/) +{ + ASSERT(pStatus != NULL); + + if (!(*pStatus & dwMask)) + { + m_nShowCount++; + (*pStatus) |= dwMask; + } +} + +void CResizableGrip::HideSizeGrip(DWORD* pStatus, DWORD dwMask /*= 1*/) +{ + ASSERT(pStatus != NULL); + + if (*pStatus & dwMask) + { + m_nShowCount--; + (*pStatus) &= ~dwMask; + } +} + +BOOL CResizableGrip::IsSizeGripVisible() const +{ + // NB: visibility is effective only after an update + return (m_nShowCount > 0); +} + +void CResizableGrip::SetSizeGripVisibility(BOOL bVisible) +{ + if (bVisible) + m_nShowCount = 1; + else + m_nShowCount = 0; +} + +BOOL CResizableGrip::SetSizeGripBkMode(int nBkMode) +{ + if (::IsWindow(m_wndGrip.m_hWnd)) + { + if (nBkMode == OPAQUE) + m_wndGrip.SetTransparency(FALSE); + else if (nBkMode == TRANSPARENT) + m_wndGrip.SetTransparency(TRUE); + else + return FALSE; + return TRUE; + } + return FALSE; +} + +void CResizableGrip::SetSizeGripShape(BOOL bTriangular) +{ + if (::IsWindow(m_wndGrip.m_hWnd)) + m_wndGrip.SetTriangularShape(bTriangular); +} + +BOOL CResizableGrip::CreateSizeGrip(BOOL bVisible /*= TRUE*/, + BOOL bTriangular /*= TRUE*/, BOOL bTransparent /*= FALSE*/) +{ + // create grip + CRect rect(0 , 0, m_wndGrip.m_size.cx, m_wndGrip.m_size.cy); + BOOL bRet = m_wndGrip.Create(WS_CHILD | WS_CLIPSIBLINGS + | SBS_SIZEGRIP, rect, GetResizableWnd(), 0); + + if (bRet) + { + // set options + m_wndGrip.SetTriangularShape(bTriangular); + m_wndGrip.SetTransparency(bTransparent); + SetSizeGripVisibility(bVisible); + + // update position + UpdateSizeGrip(); + } + + return bRet; +} + +///////////////////////////////////////////////////////////////////////////// +// CSizeGrip implementation + +BOOL CResizableGrip::CSizeGrip::IsRTL() +{ + return GetExStyle() & WS_EX_LAYOUTRTL; +} + +BOOL CResizableGrip::CSizeGrip::PreCreateWindow(CREATESTRUCT& cs) +{ + // set window size + m_size.cx = GetSystemMetrics(SM_CXVSCROLL); + m_size.cy = GetSystemMetrics(SM_CYHSCROLL); + + cs.cx = m_size.cx; + cs.cy = m_size.cy; + + return CScrollBar::PreCreateWindow(cs); +} + +LRESULT CResizableGrip::CSizeGrip::WindowProc(UINT message, + WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_GETDLGCODE: + // fix to prevent the control to gain focus, using arrow keys + // (standard grip returns DLGC_WANTARROWS, like any standard scrollbar) + return DLGC_STATIC; + + case WM_SETFOCUS: + // fix to prevent the control to gain focus, if set directly + // (for example when it's the only one control in a dialog) + return 0; + + case WM_NCHITTEST: + // choose proper cursor shape + return IsRTL() ? HTBOTTOMLEFT : HTBOTTOMRIGHT; + + case WM_SETTINGCHANGE: + { + // update grip's size + CSize sizeOld = m_size; + m_size.cx = GetSystemMetrics(SM_CXVSCROLL); + m_size.cy = GetSystemMetrics(SM_CYHSCROLL); + + // resize transparency bitmaps + if (m_bTransparent) + { + CClientDC dc(this); + + // destroy bitmaps + m_bmGrip.DeleteObject(); + m_bmMask.DeleteObject(); + + // re-create bitmaps + m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy); + m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL); + } + + // re-calc shape + if (m_bTriangular) + SetTriangularShape(m_bTriangular); + + // reposition the grip + CRect rect; + GetWindowRect(rect); + rect.InflateRect(m_size.cx - sizeOld.cx, m_size.cy - sizeOld.cy, 0, 0); + ::MapWindowPoints(NULL, GetParent()->GetSafeHwnd(), (LPPOINT)&rect, 2); + MoveWindow(rect, TRUE); + } + break; + + case WM_DESTROY: + // perform clean up + if (m_bTransparent) + SetTransparency(FALSE); + break; + + case WM_PAINT: + case WM_PRINTCLIENT: + if (m_bTransparent) + { + PAINTSTRUCT ps; + CDC* pDC = (message == WM_PAINT && wParam == 0) ? + BeginPaint(&ps) : CDC::FromHandle((HDC)wParam); + + // select bitmaps + CBitmap *pOldGrip = m_dcGrip.SelectObject(&m_bmGrip); + CBitmap *pOldMask = m_dcMask.SelectObject(&m_bmMask); + + // obtain original grip bitmap, make the mask and prepare masked bitmap + CScrollBar::WindowProc(message, (WPARAM)m_dcGrip.GetSafeHdc(), lParam); + m_dcGrip.SetBkColor(m_dcGrip.GetPixel(0, 0)); + m_dcMask.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCCOPY); + m_dcGrip.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, 0x00220326); + + // draw transparently + pDC->BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, SRCAND); + pDC->BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCPAINT); + + // unselect bitmaps + m_dcGrip.SelectObject(pOldGrip); + m_dcMask.SelectObject(pOldMask); + + if (message == WM_PAINT && wParam == 0) + EndPaint(&ps); + return 0; + } + } + + return CScrollBar::WindowProc(message, wParam, lParam); +} + +void CResizableGrip::CSizeGrip::SetTransparency(BOOL bActivate) +{ + // creates or deletes DCs and Bitmaps used for + // implementing a transparent size grip + + if (bActivate && !m_bTransparent) + { + m_bTransparent = TRUE; + + CClientDC dc(this); + + // create memory DCs and bitmaps + m_dcGrip.CreateCompatibleDC(&dc); + m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy); + + m_dcMask.CreateCompatibleDC(&dc); + m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL); + } + else if (!bActivate && m_bTransparent) + { + m_bTransparent = FALSE; + + // destroy memory DCs and bitmaps + m_dcGrip.DeleteDC(); + m_bmGrip.DeleteObject(); + + m_dcMask.DeleteDC(); + m_bmMask.DeleteObject(); + } +} + +void CResizableGrip::CSizeGrip::SetTriangularShape(BOOL bEnable) +{ + m_bTriangular = bEnable; + + if (bEnable) + { + // set a triangular window region + CRect rect; + GetWindowRect(rect); + rect.OffsetRect(-rect.TopLeft()); + POINT arrPoints[] = + { + { rect.left, rect.bottom }, + { rect.right, rect.bottom }, + { rect.right, rect.top } + }; + CRgn rgnGrip; + rgnGrip.CreatePolygonRgn(arrPoints, 3, WINDING); + SetWindowRgn((HRGN)rgnGrip.Detach(), IsWindowVisible()); + } + else + { + SetWindowRgn((HRGN)NULL, IsWindowVisible()); + } } \ No newline at end of file diff --git a/src/thirdparty/ResizableLib/ResizableGrip.h b/src/thirdparty/ResizableLib/ResizableGrip.h index 7445b7b313e..f0ae37da2ad 100644 --- a/src/thirdparty/ResizableLib/ResizableGrip.h +++ b/src/thirdparty/ResizableLib/ResizableGrip.h @@ -1,94 +1,94 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Interface for the CResizableGrip class. - */ - -#if !defined(AFX_RESIZABLEGRIP_H__INCLUDED_) -#define AFX_RESIZABLEGRIP_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -/*! @addtogroup CoreComponents - * @{ - */ - -//! @brief brief_description -/*! - * long_description - */ -class CResizableGrip -{ -private: - class CSizeGrip : public CScrollBar - { - public: - CSizeGrip() - : m_size() - { - m_bTransparent = FALSE; - m_bTriangular = FALSE; - } - - void SetTriangularShape(BOOL bEnable); - void SetTransparency(BOOL bActivate); - - BOOL IsRTL(); // right-to-left layout support - - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - - SIZE m_size; // holds grip size - - protected: - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - - BOOL m_bTriangular; // triangular shape active - BOOL m_bTransparent; // transparency active - - // memory DCs and bitmaps for transparent grip - CDC m_dcGrip, m_dcMask; - CBitmap m_bmGrip, m_bmMask; - }; - - CSizeGrip m_wndGrip; // grip control - int m_nShowCount; // support for hiding the grip - -protected: - // create a size grip, with options - BOOL CreateSizeGrip(BOOL bVisible = TRUE, - BOOL bTriangular = TRUE, BOOL bTransparent = FALSE); - - BOOL IsSizeGripVisible() const; // TRUE if grip is set to be visible - void SetSizeGripVisibility(BOOL bVisible); // set default visibility - void UpdateSizeGrip(); // update the grip's visibility and position - void ShowSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp show the size grip - void HideSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp hide the size grip - BOOL SetSizeGripBkMode(int nBkMode); // like CDC::SetBkMode - void SetSizeGripShape(BOOL bTriangular); - CWnd* GetSizeGripWnd() { return &m_wndGrip; } - - virtual CWnd* GetResizableWnd() const = 0; - -public: - CResizableGrip(); - virtual ~CResizableGrip(); -}; - -// @} -#endif // !defined(AFX_RESIZABLEGRIP_H__INCLUDED_) +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Interface for the CResizableGrip class. + */ + +#if !defined(AFX_RESIZABLEGRIP_H__INCLUDED_) +#define AFX_RESIZABLEGRIP_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/*! @addtogroup CoreComponents + * @{ + */ + +//! @brief brief_description +/*! + * long_description + */ +class CResizableGrip +{ +private: + class CSizeGrip : public CScrollBar + { + public: + CSizeGrip() + : m_size() + { + m_bTransparent = FALSE; + m_bTriangular = FALSE; + } + + void SetTriangularShape(BOOL bEnable); + void SetTransparency(BOOL bActivate); + + BOOL IsRTL(); // right-to-left layout support + + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + + SIZE m_size; // holds grip size + + protected: + virtual BOOL PreCreateWindow(CREATESTRUCT& cs); + + BOOL m_bTriangular; // triangular shape active + BOOL m_bTransparent; // transparency active + + // memory DCs and bitmaps for transparent grip + CDC m_dcGrip, m_dcMask; + CBitmap m_bmGrip, m_bmMask; + }; + + CSizeGrip m_wndGrip; // grip control + int m_nShowCount; // support for hiding the grip + +protected: + // create a size grip, with options + BOOL CreateSizeGrip(BOOL bVisible = TRUE, + BOOL bTriangular = TRUE, BOOL bTransparent = FALSE); + + BOOL IsSizeGripVisible() const; // TRUE if grip is set to be visible + void SetSizeGripVisibility(BOOL bVisible); // set default visibility + void UpdateSizeGrip(); // update the grip's visibility and position + void ShowSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp show the size grip + void HideSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp hide the size grip + BOOL SetSizeGripBkMode(int nBkMode); // like CDC::SetBkMode + void SetSizeGripShape(BOOL bTriangular); + CWnd* GetSizeGripWnd() { return &m_wndGrip; } + + virtual CWnd* GetResizableWnd() const = 0; + +public: + CResizableGrip(); + virtual ~CResizableGrip(); +}; + +// @} +#endif // !defined(AFX_RESIZABLEGRIP_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableLayout.cpp b/src/thirdparty/ResizableLib/ResizableLayout.cpp index e5dedb0deab..3d1b7dcbf16 100644 --- a/src/thirdparty/ResizableLib/ResizableLayout.cpp +++ b/src/thirdparty/ResizableLib/ResizableLayout.cpp @@ -1,920 +1,920 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Implementation of the CResizableLayout class. - */ - -#include "stdafx.h" -#include "ResizableLayout.h" -#include "ResizableVersion.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[]=__FILE__; -#define new DEBUG_NEW -#endif - -/*! - * Definition of the standard anchors - */ -const ANCHOR TOP_LEFT(0, 0); -const ANCHOR TOP_CENTER(50, 0); -const ANCHOR TOP_RIGHT(100, 0); -const ANCHOR MIDDLE_LEFT(0, 50); -const ANCHOR MIDDLE_CENTER(50, 50); -const ANCHOR MIDDLE_RIGHT(100, 50); -const ANCHOR BOTTOM_LEFT(0, 100); -const ANCHOR BOTTOM_CENTER(50, 100); -const ANCHOR BOTTOM_RIGHT(100, 100); - -/*! - * @internal Constant used to detect clipping and refresh properties - * - * @note In August 2002 Platform SDK, some guy at MS thought it was time - * to add the missing symbol BS_TYPEMASK, but forgot its original - * meaning and so now he's telling us not to use that symbol because - * its value is likely to change in the future SDK releases, including - * all the BS_* style bits in the mask, not just the button's type - * as the symbol's name suggests. - * @n So now we're forced to define another symbol, great! - */ -#define _BS_TYPEMASK 0x0000000FL - -/*! - * This function adds a new control to the layout manager and sets anchor - * points for its top-left and bottom-right corners. - * - * @param hWnd Window handle to the control to be added - * @param anchorTopLeft Anchor point for the top-left corner - * @param anchorBottomRight Anchor point for the bottom-right corner - * - * @remarks Overlapping controls, like group boxes and the controls inside, - * must be added from the outer controls to the inner ones, to let - * the clipping routines work correctly. - * - * @sa AddAnchorCallback RemoveAnchor - */ -void CResizableLayout::AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) -{ - CWnd* pParent = GetResizableWnd(); - - // child window must be valid - ASSERT(::IsWindow(hWnd)); - // must be child of parent window - ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd)); - - // get parent window's rect - CRect rectParent; - GetTotalClientRect(&rectParent); - // and child control's rect - CRect rectChild; - ::GetWindowRect(hWnd, &rectChild); - ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); - - // adjust position, if client area has been scrolled - rectChild.OffsetRect(-rectParent.TopLeft()); - - // calculate margin for the top-left corner - CSize marginTopLeft(rectChild.left - rectParent.Width() * anchorTopLeft.cx / 100, - rectChild.top - rectParent.Height() * anchorTopLeft.cy / 100); - - // calculate margin for the bottom-right corner - CSize marginBottomRight(rectChild.right - rectParent.Width() * anchorBottomRight.cx / 100, - rectChild.bottom - rectParent.Height() * anchorBottomRight.cy / 100); - - // prepare the structure - LAYOUTINFO layout(hWnd, anchorTopLeft, marginTopLeft, - anchorBottomRight, marginBottomRight); - - // get control's window class - GetClassName(hWnd, layout.sWndClass, MAX_PATH); - - // initialize resize properties (overridable) - InitResizeProperties(layout); - - // must not be already there! - // (this is probably due to a duplicate call to AddAnchor) - POSITION pos; - ASSERT(!m_mapLayout.Lookup(hWnd, pos)); - - // add to the list and the map - pos = m_listLayout.AddTail(layout); - m_mapLayout.SetAt(hWnd, pos); -} - -/*! - * This function adds all the controls not yet added to the layout manager - * and sets anchor points for its top-left and bottom-right corners. - * - * @param anchorTopLeft Anchor point for the top-left corner - * @param anchorBottomRight Anchor point for the bottom-right corner - * @param anchor Anchor point for the top-left and bottom-right corner - * - * @remarks Overlapping controls, like group boxes and the controls inside, - * may not be handled correctly. Use individual @ref AddAnchor calls - * to solve any issues that may arise with clipping. - * - * @sa AddAnchor - */ -void CResizableLayout::AddAllOtherAnchors(ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) -{ - HWND hParent = GetResizableWnd()->GetSafeHwnd(); - ASSERT(::IsWindow(hParent)); - - HWND hWnd = ::GetWindow(hParent, GW_CHILD); - for (; hWnd != NULL; hWnd = ::GetNextWindow(hWnd, GW_HWNDNEXT)) - { - TCHAR szClassName[32]; - if (::GetClassName(hWnd, szClassName, _countof(szClassName))) - { - if (lstrcmp(szClassName, WC_SCROLLBAR) == 0) - { - // skip size grip (which is handled on its own) - DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE); - if ((dwStyle & (WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP)) == (WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP)) - continue; - } - } - - POSITION pos; - if (!m_mapLayout.Lookup(hWnd, pos)) - AddAnchor(hWnd, anchorTopLeft, anchorBottomRight); - } -} - -/*! - * This function adds a placeholder to the layout manager, that will be - * dynamically set by a callback function whenever required. - * - * @return The return value is an integer used to distinguish between - * different placeholders in the callback implementation. - * - * @remarks You must override @ref ArrangeLayoutCallback to provide layout - * information. - * - * @sa AddAnchor ArrangeLayoutCallback ArrangeLayout - */ -LRESULT CResizableLayout::AddAnchorCallback() -{ - // one callback control cannot rely upon another callback control's - // size and/or position (they're updated all together at the end) - // it can however use a non-callback control, calling GetAnchorPosition() - - // add to the list - LAYOUTINFO layout; - layout.nCallbackID = m_listLayoutCB.GetCount() + 1; - m_listLayoutCB.AddTail(layout); - return layout.nCallbackID; -} - -/*! - * This function is called for each placeholder added to the layout manager - * and must be overridden to provide the necessary layout information. - * - * @param layout Reference to a LAYOUTINFO structure to be filled with - * layout information for the specified placeholder. - * On input, nCallbackID is the identification number - * returned by AddAnchorCallback. On output, anchor points and - * the window handle must be set and valid. - * - * @return The return value is @c TRUE if the layout information has been - * provided successfully, @c FALSE to skip this placeholder. - * - * @remarks When implementing this function, unknown placeholders should be - * passed to the base class. Unhandled cases will fire an assertion - * in the debug version. - * - * @sa AddAnchorCallback ArrangeLayout LAYOUTINFO - */ -BOOL CResizableLayout::ArrangeLayoutCallback(LAYOUTINFO& layout) const -{ - UNREFERENCED_PARAMETER(layout); - - ASSERT(FALSE); // must be overridden, if callback is used - - return FALSE; // no useful output data -} - -/*! - * This function should be called in resizable window classes whenever the - * controls layout should be updated, usually after a resize operation. - * - * @remarks All the controls added to the layout are moved and resized at - * once for performance reasons, so all the controls are in their - * old position when AddAnchorCallback is called. - * To know where a control will be placed use GetAnchorPosition. - * - * @sa AddAnchor AddAnchorCallback ArrangeLayoutCallback GetAnchorPosition - */ -void CResizableLayout::ArrangeLayout() const -{ - const INT_PTR count = m_listLayout.GetCount() + m_listLayoutCB.GetCount(); - if (count <= 0) - return; - - CRect rectParent, rectChild; - - // get parent window's rect - GetTotalClientRect(&rectParent); - - // reposition child windows - HDWP hdwp = ::BeginDeferWindowPos(static_cast(count)); - - for (POSITION pos = m_listLayout.GetHeadPosition(); pos != NULL;) - { - // get layout info - const LAYOUTINFO layout = m_listLayout.GetNext(pos); - - UINT uFlags; - // calculate new child's position, size and flags for SetWindowPos - CalcNewChildPosition(layout, rectParent, rectChild, &uFlags); - - // only if size or position changed - if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) - { - hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, - rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); - } - } - - // for callback items you may use GetAnchorPosition to know the - // new position and size of a non-callback item after resizing - - for (POSITION pos = m_listLayoutCB.GetHeadPosition(); pos != NULL;) - { - // get layout info - LAYOUTINFO layout = m_listLayoutCB.GetNext(pos); - // request layout data - if (!ArrangeLayoutCallback(layout)) - continue; - - UINT uFlags; - // calculate new child's position, size and flags for SetWindowPos - CalcNewChildPosition(layout, rectParent, rectChild, &uFlags); - - // only if size or position changed - if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) - { - hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, - rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); - } - } - - // finally move all the windows at once - ::EndDeferWindowPos(hdwp); -} - -/*! - * @internal This function adds or removes a control window region - * to or from the specified clipping region, according to its layout - * properties. - */ -void CResizableLayout::ClipChildWindow(const LAYOUTINFO& layout, - CRgn* pRegion) const -{ - // obtain window position - CRect rect; - ::GetWindowRect(layout.hWnd, &rect); -#if (_WIN32_WINNT >= 0x0501) - //! @todo decide when to clip client only or non-client too (themes?) - //! (leave disabled meanwhile, until I find a good solution) - //! @note wizard97 with watermark bitmap and themes won't look good! - // if (real_WIN32_WINNT >= 0x501) - // ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); -#endif - ::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2); - - // use window region if any - CRgn rgn; - rgn.CreateRectRgn(0,0,0,0); - switch (::GetWindowRgn(layout.hWnd, rgn)) - { - case COMPLEXREGION: - case SIMPLEREGION: - rgn.OffsetRgn(rect.TopLeft()); - break; - - default: - rgn.SetRectRgn(&rect); - } - - // get the clipping property - const BOOL bClipping = layout.properties.bAskClipping ? - LikesClipping(layout) : layout.properties.bCachedLikesClipping; - - // modify region accordingly - if (bClipping) - pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF); - else - pRegion->CombineRgn(pRegion, &rgn, RGN_OR); -} - -/*! - * This function retrieves the clipping region for the current layout. - * It can be used to draw directly inside the region, without applying - * clipping as the ClipChildren function does. - * - * @param pRegion Pointer to a CRegion object that holds the - * calculated clipping region upon return - * - * @deprecated For anti-flickering ClipChildren should be preferred - * as it is more complete for platform compatibility. - * It will probably become a private function. - */ -void CResizableLayout::GetClippingRegion(CRgn* pRegion) const -{ - const CWnd* pWnd = GetResizableWnd(); - - // System's default clipping area is screen's size, - // not enough for max track size, for example: - // if screen is 1024 x 768 and resizing border is 4 pixels, - // maximized size is 1024+4*2=1032 x 768+4*2=776, - // but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!) - // So, if you resize the window to maximum size, the last 4 pixels - // are clipped out by the default clipping region, that gets created - // as soon as you call clipping functions (my guess). - - // reset clipping region to the whole client area - CRect rect; - pWnd->GetClientRect(&rect); - pRegion->CreateRectRgnIndirect(&rect); - - // clip only anchored controls - - for (POSITION pos = m_listLayout.GetHeadPosition(); pos != NULL;) - { - // get layout info - LAYOUTINFO layout = m_listLayout.GetNext(pos); - - if (::IsWindowVisible(layout.hWnd)) - ClipChildWindow(layout, pRegion); - } - - for (POSITION pos = m_listLayoutCB.GetHeadPosition(); pos != NULL;) - { - // get layout info - LAYOUTINFO layout = m_listLayoutCB.GetNext(pos); - // request data - if (ArrangeLayoutCallback(layout) && ::IsWindowVisible(layout.hWnd)) - ClipChildWindow(layout, pRegion); - } -//! @todo Has XP changed this??? It doesn't seem correct anymore! -/* - // fix for RTL layouts (1 pixel of horz offset) - if (pWnd->GetExStyle() & WS_EX_LAYOUTRTL) - pRegion->OffsetRgn(-1,0); -*/ -} - -//! @internal @brief Implements GetAncestor(pWnd->GetSafeHwnd(), GA_ROOT) -inline CWnd* GetRootParentWnd(CWnd* pWnd) -{ - // GetAncestor API not present, emulate - if (!(pWnd->GetStyle() & WS_CHILD)) - return NULL; - while (pWnd->GetStyle() & WS_CHILD) - pWnd = pWnd->GetParent(); - return pWnd; -} - -/*! - * This function enables or restores clipping on the specified DC when - * appropriate. It should be called whenever drawing on the window client - * area to avoid flickering. - * - * @param pDC Pointer to the target device context - * @param bUndo Flag that specifies whether to restore the clipping region - * - * @return The return value is @c TRUE if the clipping region has been - * modified, @c FALSE otherwise - * - * @remarks For anti-flickering to work, you should wrap your - * @c WM_ERASEBKGND message handler inside a pair of calls to - * this function, with the last parameter set to @c FALSE first - * and to @c TRUE at the end. - */ -BOOL CResizableLayout::ClipChildren(const CDC* pDC, BOOL bUndo) -{ -#if (_WIN32_WINNT >= 0x0501 && !defined(RSZLIB_NO_XP_DOUBLE_BUFFER)) - // clipping not necessary when double-buffering enabled - if (real_WIN32_WINNT >= 0x0501) - { - CWnd *pWnd = GetRootParentWnd(GetResizableWnd()); - if (pWnd == NULL) - pWnd = GetResizableWnd(); - if (pWnd->GetExStyle() & WS_EX_COMPOSITED) - return FALSE; - } -#endif - - const HDC hDC = pDC->GetSafeHdc(); - const HWND hWnd = GetResizableWnd()->GetSafeHwnd(); - - // Some controls (such as transparent toolbars and standard controls - // with XP theme enabled) send a WM_ERASEBKGND msg to the parent - // to draw themselves, in which case we must not enable clipping. - - // We check that the window associated with the DC is the - // resizable window and not a child control. - - if (!bUndo) - { - if (hWnd != ::WindowFromDC(hDC)) - m_nOldClipRgn = -1; // invalid region - else - { - // save old DC clipping region - m_nOldClipRgn = ::GetClipRgn(hDC, m_hOldClipRgn); - // clip out supported child windows - CRgn rgnClip; - GetClippingRegion(&rgnClip); - ::ExtSelectClipRgn(hDC, rgnClip, RGN_AND); - } - return (m_nOldClipRgn >= 0) ? TRUE : FALSE; - } - - if (m_nOldClipRgn >= 0) // restore old clipping region, only if modified and valid - { - ::SelectClipRgn(hDC, (m_nOldClipRgn>0 ? m_hOldClipRgn : NULL)); - return TRUE; - } - - return FALSE; -} - -/*! - * This function is used by this class, and should be used by derived - * classes too, in place of the standard GetClientRect. It can be useful - * for windows with scrollbars or expanding windows, to provide the true - * client area, including even those parts which are not visible. - * - * @param lpRect Pointer to the RECT structure that holds the result - * - * @remarks Override this function to provide the client area the class uses - * to perform layout calculations, both when adding controls and - * when rearranging the layout. - * @n The base implementation simply calls @c GetClientRect - */ -void CResizableLayout::GetTotalClientRect(LPRECT lpRect) const -{ - GetResizableWnd()->GetClientRect(lpRect); -} - -/*! - * This function is used to determine if a control needs to be painted when - * it is moved or resized by the layout manager. - * - * @param layout Reference to a @c LAYOUTINFO structure for the control - * @param rectOld Reference to a @c RECT structure that holds the control - * position and size before the layout update - * @param rectNew Reference to a @c RECT structure that holds the control - * position and size after the layout update - * - * @return The return value is @c TRUE if the control should be freshly - * painted after a layout update, @c FALSE if not necessary. - * - * @remarks The default implementation tries to identify windows that - * need refresh by their class name and window style. - * @n Override this function if you need a different behavior or if - * you have custom controls that fail to be identified. - * - * @sa LikesClipping InitResizeProperties - */ -BOOL CResizableLayout::NeedsRefresh(const LAYOUTINFO& layout, - const CRect& rectOld, const CRect& rectNew) const -{ - if (layout.bMsgSupport) - { - REFRESHPROPERTY refresh; - refresh.rcOld = rectOld; - refresh.rcNew = rectNew; - if (Send_NeedsRefresh(layout.hWnd, &refresh)) - return refresh.bNeedsRefresh; - } - - const int nDiffWidth = (rectNew.Width() - rectOld.Width()); - const int nDiffHeight = (rectNew.Height() - rectOld.Height()); - - // is the same size? - if (nDiffWidth == 0 && nDiffHeight == 0) - return FALSE; - - // optimistic, no need to refresh - BOOL bRefresh = FALSE; - - // window classes that need refresh when resized - if (0 == lstrcmp(layout.sWndClass, WC_STATIC)) - { - LONG_PTR style = ::GetWindowLongPtr(layout.hWnd, GWL_STYLE); - - switch (style & SS_TYPEMASK) - { - case SS_LEFT: - case SS_CENTER: - case SS_RIGHT: - // word-wrapped text - bRefresh = bRefresh || (nDiffWidth != 0); - // vertically centered text - if (style & SS_CENTERIMAGE) - bRefresh = bRefresh || (nDiffHeight != 0); - break; - - case SS_LEFTNOWORDWRAP: - // text with ellipsis - if (style & SS_ELLIPSISMASK) - bRefresh = bRefresh || (nDiffWidth != 0); - // vertically centered text - if (style & SS_CENTERIMAGE) - bRefresh = bRefresh || (nDiffHeight != 0); - break; - - case SS_ENHMETAFILE: - case SS_BITMAP: - case SS_ICON: - // images - case SS_BLACKFRAME: - case SS_GRAYFRAME: - case SS_WHITEFRAME: - case SS_ETCHEDFRAME: - // and frames - bRefresh = TRUE; - break; - } - return bRefresh; - } - - // window classes that don't redraw client area correctly - // when the hor scroll pos changes due to a resizing - const BOOL bHScroll = (0 == lstrcmp(layout.sWndClass, WC_LISTBOX)); - - // fix for horizontally scrollable windows, if wider - if (bHScroll && (nDiffWidth > 0)) - { - // get max scroll position - SCROLLINFO info; - info.cbSize = sizeof(SCROLLINFO); - info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; - if (::GetScrollInfo(layout.hWnd, SB_HORZ, &info) && info.nPage > 1) //fix for unsigned subtraction - { - // subtract the page size - info.nMax -= info.nPage-1; //should not use __max() macro - } - - // resizing will cause the text to scroll on the right - // because the scrollbar is going beyond the right limit - if ((info.nMax > 0) && (info.nPos + nDiffWidth > info.nMax)) - { - // needs repainting, due to horiz scrolling - bRefresh = TRUE; - } - } - - return bRefresh; -} - -/*! - * This function is used to determine if a control can be safely clipped - * out of the parent window client area when it is repainted, usually - * after a resize operation. - * - * @param layout Reference to a @c LAYOUTINFO structure for the control - * - * @return The return value is @c TRUE if clipping is supported by the - * control, @c FALSE otherwise. - * - * @remarks The default implementation tries to identify @a clippable - * windows by their class name and window style. - * @n Override this function if you need a different behavior or if - * you have custom controls that fail to be identified. - * - * @sa NeedsRefresh InitResizeProperties - */ -BOOL CResizableLayout::LikesClipping(const LAYOUTINFO& layout) const -{ - if (layout.bMsgSupport) - { - CLIPPINGPROPERTY clipping; - if (Send_LikesClipping(layout.hWnd, &clipping)) - return clipping.bLikesClipping; - } - - const LONG_PTR style = ::GetWindowLongPtr(layout.hWnd, GWL_STYLE); - - // skip windows that wants background repainted - if (0 == lstrcmp(layout.sWndClass, WC_BUTTON)) - { - CRect rect; - switch (style & _BS_TYPEMASK) - { - case BS_GROUPBOX: - return FALSE; - - case BS_OWNERDRAW: - // ownerdraw buttons must return correct hittest code - // to notify their transparency to the system and this library - // or they could use the registered message (more reliable) - ::GetWindowRect(layout.hWnd, &rect); - ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); - if ( HTTRANSPARENT == ::SendMessage(layout.hWnd, - WM_NCHITTEST, 0, MAKELPARAM(rect.left, rect.top)) ) - return FALSE; - break; - } - return TRUE; - } - else if (0 == lstrcmp(layout.sWndClass, WC_STATIC)) - { - switch (style & SS_TYPEMASK) - { - case SS_LEFT: - case SS_CENTER: - case SS_RIGHT: - case SS_LEFTNOWORDWRAP: - // text - case SS_BLACKRECT: - case SS_GRAYRECT: - case SS_WHITERECT: - // filled rects - case SS_ETCHEDHORZ: - case SS_ETCHEDVERT: - // etched lines - case SS_BITMAP: - // bitmaps - return TRUE; - - case SS_ICON: - case SS_ENHMETAFILE: - if (style & SS_CENTERIMAGE) - return FALSE; - return TRUE; - - default: - return FALSE; - } - } - - // assume the others like clipping - return TRUE; -} - - -/*! - * @internal This function calculates the new size and position of a - * control in the layout and flags for @c SetWindowPos - */ -void CResizableLayout::CalcNewChildPosition(const LAYOUTINFO& layout, - const CRect &rectParent, CRect &rectChild, UINT *lpFlags) const -{ - const CWnd* pParent = GetResizableWnd(); - - ::GetWindowRect(layout.hWnd, &rectChild); - ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); - - CRect rectNew; - - // calculate new top-left corner - rectNew.left = layout.marginTopLeft.cx + rectParent.Width() * layout.anchorTopLeft.cx / 100; - rectNew.top = layout.marginTopLeft.cy + rectParent.Height() * layout.anchorTopLeft.cy / 100; - - // calculate new bottom-right corner - rectNew.right = layout.marginBottomRight.cx + rectParent.Width() * layout.anchorBottomRight.cx / 100; - rectNew.bottom = layout.marginBottomRight.cy + rectParent.Height() * layout.anchorBottomRight.cy / 100; - - // adjust position, if client area has been scrolled - rectNew.OffsetRect(rectParent.TopLeft()); - - // get the refresh property - BOOL bRefresh = layout.properties.bAskRefresh ? - NeedsRefresh(layout, rectChild, rectNew) : layout.properties.bCachedNeedsRefresh; - - // set flags - if (lpFlags) - { - *lpFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION; - if (bRefresh) - *lpFlags |= SWP_NOCOPYBITS; - if (rectNew.TopLeft() == rectChild.TopLeft()) - *lpFlags |= SWP_NOMOVE; - if (rectNew.Size() == rectChild.Size()) - *lpFlags |= SWP_NOSIZE; - } - - // update rect - rectChild = rectNew; -} - -/*! - * This function calculates the top, left, bottom, right margins for a - * given size of the specified control. - * - * @param hWnd Window handle to a control in the layout - * @param sizeChild Size of the control to use in calculations - * @param rectMargins Holds the calculated margins - * - * @return The return value is @c TRUE if successful, @c FALSE otherwise - * - * @remarks This function can be used to infer the parent window size - * from the size of one of its child controls. - * It is used to implement cascading of size constraints. - */ -BOOL CResizableLayout::GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const -{ - POSITION pos; - if (!m_mapLayout.Lookup(hWnd, pos)) - return FALSE; - - const LAYOUTINFO& layout = m_listLayout.GetAt(pos); - - // augmented size, relative to anchor points - const CSize size = sizeChild + layout.marginTopLeft - layout.marginBottomRight; - - // percent of parent size occupied by this control - const CSize percent(layout.anchorBottomRight.cx - layout.anchorTopLeft.cx, - layout.anchorBottomRight.cy - layout.anchorTopLeft.cy); - - // calculate total margins - rectMargins.left = size.cx * layout.anchorTopLeft.cx / percent.cx + layout.marginTopLeft.cx; - rectMargins.top = size.cy * layout.anchorTopLeft.cy / percent.cy + layout.marginTopLeft.cy; - rectMargins.right = size.cx * (100 - layout.anchorBottomRight.cx) / percent.cx - layout.marginBottomRight.cx; - rectMargins.bottom = size.cy * (100 - layout.anchorBottomRight.cy) / percent.cy - layout.marginBottomRight.cy; - - return TRUE; -} - -/*! - * This function is used to set the initial resize properties of a control - * in the layout, that are stored in the @c properties member of the - * related @c LAYOUTINFO structure. - * - * @param layout Reference to the @c LAYOUTINFO structure to be set - * - * @remarks The various flags are used to specify whether the resize - * properties (clipping, refresh) can change at run-time, and a new - * call to the property querying functions is needed at every - * layout update, or they are static properties, and the cached - * value is used whenever necessary. - * @n The default implementation sends a registered message to the - * control, giving it the opportunity to specify its resize - * properties, which takes precedence if the message is supported. - * It then sets the @a clipping property as static, calling - * @c LikesClipping only once, and the @a refresh property as - * dynamic, causing @c NeedsRefresh to be called every time. - * @n This should be right for most situations, as the need for - * @a refresh usually depends on the size of the control, while the - * support for @a clipping is usually linked to the specific type - * of control, which is unlikely to change at run-time, but you can - * still override this function if a different behaviour is needed. - * - * @sa LikesClipping NeedsRefresh LAYOUTINFO RESIZEPROPERTIES - */ -void CResizableLayout::InitResizeProperties(LAYOUTINFO &layout) const -{ - // check if custom window supports this library - // (properties must be correctly set by the window) - layout.bMsgSupport = Send_QueryProperties(layout.hWnd, &layout.properties); - - // default properties - if (!layout.bMsgSupport) - { - // clipping property is assumed as static - layout.properties.bAskClipping = FALSE; - layout.properties.bCachedLikesClipping = LikesClipping(layout); - // refresh property is assumed as dynamic - layout.properties.bAskRefresh = TRUE; - } -} - -/*! - * This function modifies a window to enable resizing functionality. - * This affects the window style, size, system menu and appearance. - * - * @param lpCreateStruct Pointer to a @c CREATESTRUCT structure, usually - * passed by the system to the window procedure in a @c WM_CREATE - * or @c WM_NCCREATE - * - * @remarks The function is intended to be called only inside a @c WM_CREATE - * or @c WM_NCCREATE message handler. - */ -void CResizableLayout::MakeResizable(LPCREATESTRUCT lpCreateStruct) const -{ - if (lpCreateStruct->style & WS_CHILD) - return; - - InitThemeSettings(); //! @todo move theme check in more appropriate place - - CWnd* pWnd = GetResizableWnd(); - -#if (_WIN32_WINNT >= 0x0501 && !defined(RSZLIB_NO_XP_DOUBLE_BUFFER)) - // enable double-buffering on supported platforms - pWnd->ModifyStyleEx(0, WS_EX_COMPOSITED); -#endif - - if (!(lpCreateStruct->style & WS_THICKFRAME)) - { - // keep client area - CRect rect(CPoint(lpCreateStruct->x, lpCreateStruct->y), - CSize(lpCreateStruct->cx, lpCreateStruct->cy)); - pWnd->SendMessage(WM_NCCALCSIZE, FALSE, (LPARAM)&rect); - // set resizable style - pWnd->ModifyStyle(DS_MODALFRAME, WS_THICKFRAME); - // adjust size to reflect new style - ::AdjustWindowRectEx(&rect, pWnd->GetStyle(), - ::IsMenu(pWnd->GetMenu()->GetSafeHmenu()), pWnd->GetExStyle()); - pWnd->SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), - SWP_NOSENDCHANGING|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION); - // update dimensions - lpCreateStruct->cx = rect.Width(); - lpCreateStruct->cy = rect.Height(); - } -} - -/*! - * This function should be called inside the parent window @c WM_NCCALCSIZE - * message handler to help eliminate flickering. - * - * @param bAfterDefault Flag that specifies whether the call is made before - * or after the default handler - * @param lpncsp Pointer to the @c NCCALCSIZE_PARAMS structure that is - * passed to the message handler - * @param lResult Reference to the result of the message handler. - * It contains the default handler result on input and the value to - * return from the window procedure on output. - * - * @remarks This function fixes the annoying flickering effect that is - * visible when resizing the top or left edges of the window - * (at least on a "left to right" Windows localized version). - */ -void CResizableLayout::HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT &lResult) -{ - // prevent useless complication when size is not changing - // prevent recursion when resetting the window region (see below) - if ((lpncsp->lppos->flags & SWP_NOSIZE) -#if (_WIN32_WINNT >= 0x0501) - || m_bNoRecursion -#endif - ) - return; - - if (!bAfterDefault) - { - // save a copy before default handler gets called - m_rectClientBefore = lpncsp->rgrc[2]; - } - else // after default WM_NCCALCSIZE msg processing - { - if (lResult != 0) - { - // default handler already uses an advanced validation policy, give up - return; - } - // default calculated client rect - RECT &rectClientAfter = lpncsp->rgrc[0]; - - // intersection between old and new client area is to be preserved - // set source and destination rects to this intersection - RECT &rectPreserve = lpncsp->rgrc[1]; - ::IntersectRect(&rectPreserve, &rectClientAfter, &m_rectClientBefore); - lpncsp->rgrc[2] = rectPreserve; - - lResult = WVR_VALIDRECTS; - - // FIX: window region must be updated before the result of the - // WM_NCCALCSIZE message gets processed by the system, - // otherwise the old window region will clip the client - // area during the preservation process. - // This is especially evident on WinXP when the non-client - // area is rendered with Visual Styles enabled and the - // windows have a non rectangular region. - // NOTE: Implementers of skin systems that modify the window region - // should not rely on this fix and should handle non-client - // window messages themselves, to avoid flickering -#if (_WIN32_WINNT >= 0x0501) - if ((real_WIN32_WINNT >= 0x0501) - && (real_ThemeSettings & STAP_ALLOW_NONCLIENT)) - { - CWnd* pWnd = GetResizableWnd(); - DWORD dwStyle = pWnd->GetStyle(); - if ((dwStyle & (WS_CAPTION|WS_MAXIMIZE)) == WS_CAPTION) - { - m_bNoRecursion = TRUE; - pWnd->SetWindowRgn(NULL, FALSE); - m_bNoRecursion = FALSE; - } - } -#endif - } -} +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Implementation of the CResizableLayout class. + */ + +#include "stdafx.h" +#include "ResizableLayout.h" +#include "ResizableVersion.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +/*! + * Definition of the standard anchors + */ +const ANCHOR TOP_LEFT(0, 0); +const ANCHOR TOP_CENTER(50, 0); +const ANCHOR TOP_RIGHT(100, 0); +const ANCHOR MIDDLE_LEFT(0, 50); +const ANCHOR MIDDLE_CENTER(50, 50); +const ANCHOR MIDDLE_RIGHT(100, 50); +const ANCHOR BOTTOM_LEFT(0, 100); +const ANCHOR BOTTOM_CENTER(50, 100); +const ANCHOR BOTTOM_RIGHT(100, 100); + +/*! + * @internal Constant used to detect clipping and refresh properties + * + * @note In August 2002 Platform SDK, some guy at MS thought it was time + * to add the missing symbol BS_TYPEMASK, but forgot its original + * meaning and so now he's telling us not to use that symbol because + * its value is likely to change in the future SDK releases, including + * all the BS_* style bits in the mask, not just the button's type + * as the symbol's name suggests. + * @n So now we're forced to define another symbol, great! + */ +#define _BS_TYPEMASK 0x0000000FL + +/*! + * This function adds a new control to the layout manager and sets anchor + * points for its top-left and bottom-right corners. + * + * @param hWnd Window handle to the control to be added + * @param anchorTopLeft Anchor point for the top-left corner + * @param anchorBottomRight Anchor point for the bottom-right corner + * + * @remarks Overlapping controls, like group boxes and the controls inside, + * must be added from the outer controls to the inner ones, to let + * the clipping routines work correctly. + * + * @sa AddAnchorCallback RemoveAnchor + */ +void CResizableLayout::AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) +{ + CWnd* pParent = GetResizableWnd(); + + // child window must be valid + ASSERT(::IsWindow(hWnd)); + // must be child of parent window + ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd)); + + // get parent window's rect + CRect rectParent; + GetTotalClientRect(&rectParent); + // and child control's rect + CRect rectChild; + ::GetWindowRect(hWnd, &rectChild); + ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); + + // adjust position, if client area has been scrolled + rectChild.OffsetRect(-rectParent.TopLeft()); + + // calculate margin for the top-left corner + CSize marginTopLeft(rectChild.left - rectParent.Width() * anchorTopLeft.cx / 100, + rectChild.top - rectParent.Height() * anchorTopLeft.cy / 100); + + // calculate margin for the bottom-right corner + CSize marginBottomRight(rectChild.right - rectParent.Width() * anchorBottomRight.cx / 100, + rectChild.bottom - rectParent.Height() * anchorBottomRight.cy / 100); + + // prepare the structure + LAYOUTINFO layout(hWnd, anchorTopLeft, marginTopLeft, + anchorBottomRight, marginBottomRight); + + // get control's window class + GetClassName(hWnd, layout.sWndClass, MAX_PATH); + + // initialize resize properties (overridable) + InitResizeProperties(layout); + + // must not be already there! + // (this is probably due to a duplicate call to AddAnchor) + POSITION pos; + ASSERT(!m_mapLayout.Lookup(hWnd, pos)); + + // add to the list and the map + pos = m_listLayout.AddTail(layout); + m_mapLayout.SetAt(hWnd, pos); +} + +/*! + * This function adds all the controls not yet added to the layout manager + * and sets anchor points for its top-left and bottom-right corners. + * + * @param anchorTopLeft Anchor point for the top-left corner + * @param anchorBottomRight Anchor point for the bottom-right corner + * @param anchor Anchor point for the top-left and bottom-right corner + * + * @remarks Overlapping controls, like group boxes and the controls inside, + * may not be handled correctly. Use individual @ref AddAnchor calls + * to solve any issues that may arise with clipping. + * + * @sa AddAnchor + */ +void CResizableLayout::AddAllOtherAnchors(ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) +{ + HWND hParent = GetResizableWnd()->GetSafeHwnd(); + ASSERT(::IsWindow(hParent)); + + HWND hWnd = ::GetWindow(hParent, GW_CHILD); + for (; hWnd != NULL; hWnd = ::GetNextWindow(hWnd, GW_HWNDNEXT)) + { + TCHAR szClassName[32]; + if (::GetClassName(hWnd, szClassName, _countof(szClassName))) + { + if (lstrcmp(szClassName, WC_SCROLLBAR) == 0) + { + // skip size grip (which is handled on its own) + DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE); + if ((dwStyle & (WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP)) == (WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP)) + continue; + } + } + + POSITION pos; + if (!m_mapLayout.Lookup(hWnd, pos)) + AddAnchor(hWnd, anchorTopLeft, anchorBottomRight); + } +} + +/*! + * This function adds a placeholder to the layout manager, that will be + * dynamically set by a callback function whenever required. + * + * @return The return value is an integer used to distinguish between + * different placeholders in the callback implementation. + * + * @remarks You must override @ref ArrangeLayoutCallback to provide layout + * information. + * + * @sa AddAnchor ArrangeLayoutCallback ArrangeLayout + */ +LRESULT CResizableLayout::AddAnchorCallback() +{ + // one callback control cannot rely upon another callback control's + // size and/or position (they're updated all together at the end) + // it can however use a non-callback control, calling GetAnchorPosition() + + // add to the list + LAYOUTINFO layout; + layout.nCallbackID = m_listLayoutCB.GetCount() + 1; + m_listLayoutCB.AddTail(layout); + return layout.nCallbackID; +} + +/*! + * This function is called for each placeholder added to the layout manager + * and must be overridden to provide the necessary layout information. + * + * @param layout Reference to a LAYOUTINFO structure to be filled with + * layout information for the specified placeholder. + * On input, nCallbackID is the identification number + * returned by AddAnchorCallback. On output, anchor points and + * the window handle must be set and valid. + * + * @return The return value is @c TRUE if the layout information has been + * provided successfully, @c FALSE to skip this placeholder. + * + * @remarks When implementing this function, unknown placeholders should be + * passed to the base class. Unhandled cases will fire an assertion + * in the debug version. + * + * @sa AddAnchorCallback ArrangeLayout LAYOUTINFO + */ +BOOL CResizableLayout::ArrangeLayoutCallback(LAYOUTINFO& layout) const +{ + UNREFERENCED_PARAMETER(layout); + + ASSERT(FALSE); // must be overridden, if callback is used + + return FALSE; // no useful output data +} + +/*! + * This function should be called in resizable window classes whenever the + * controls layout should be updated, usually after a resize operation. + * + * @remarks All the controls added to the layout are moved and resized at + * once for performance reasons, so all the controls are in their + * old position when AddAnchorCallback is called. + * To know where a control will be placed use GetAnchorPosition. + * + * @sa AddAnchor AddAnchorCallback ArrangeLayoutCallback GetAnchorPosition + */ +void CResizableLayout::ArrangeLayout() const +{ + const INT_PTR count = m_listLayout.GetCount() + m_listLayoutCB.GetCount(); + if (count <= 0) + return; + + CRect rectParent, rectChild; + + // get parent window's rect + GetTotalClientRect(&rectParent); + + // reposition child windows + HDWP hdwp = ::BeginDeferWindowPos(static_cast(count)); + + for (POSITION pos = m_listLayout.GetHeadPosition(); pos != NULL;) + { + // get layout info + const LAYOUTINFO layout = m_listLayout.GetNext(pos); + + UINT uFlags; + // calculate new child's position, size and flags for SetWindowPos + CalcNewChildPosition(layout, rectParent, rectChild, &uFlags); + + // only if size or position changed + if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) + { + hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, + rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); + } + } + + // for callback items you may use GetAnchorPosition to know the + // new position and size of a non-callback item after resizing + + for (POSITION pos = m_listLayoutCB.GetHeadPosition(); pos != NULL;) + { + // get layout info + LAYOUTINFO layout = m_listLayoutCB.GetNext(pos); + // request layout data + if (!ArrangeLayoutCallback(layout)) + continue; + + UINT uFlags; + // calculate new child's position, size and flags for SetWindowPos + CalcNewChildPosition(layout, rectParent, rectChild, &uFlags); + + // only if size or position changed + if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) + { + hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, + rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); + } + } + + // finally move all the windows at once + ::EndDeferWindowPos(hdwp); +} + +/*! + * @internal This function adds or removes a control window region + * to or from the specified clipping region, according to its layout + * properties. + */ +void CResizableLayout::ClipChildWindow(const LAYOUTINFO& layout, + CRgn* pRegion) const +{ + // obtain window position + CRect rect; + ::GetWindowRect(layout.hWnd, &rect); +#if (_WIN32_WINNT >= 0x0501) + //! @todo decide when to clip client only or non-client too (themes?) + //! (leave disabled meanwhile, until I find a good solution) + //! @note wizard97 with watermark bitmap and themes won't look good! + // if (real_WIN32_WINNT >= 0x501) + // ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); +#endif + ::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2); + + // use window region if any + CRgn rgn; + rgn.CreateRectRgn(0,0,0,0); + switch (::GetWindowRgn(layout.hWnd, rgn)) + { + case COMPLEXREGION: + case SIMPLEREGION: + rgn.OffsetRgn(rect.TopLeft()); + break; + + default: + rgn.SetRectRgn(&rect); + } + + // get the clipping property + const BOOL bClipping = layout.properties.bAskClipping ? + LikesClipping(layout) : layout.properties.bCachedLikesClipping; + + // modify region accordingly + if (bClipping) + pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF); + else + pRegion->CombineRgn(pRegion, &rgn, RGN_OR); +} + +/*! + * This function retrieves the clipping region for the current layout. + * It can be used to draw directly inside the region, without applying + * clipping as the ClipChildren function does. + * + * @param pRegion Pointer to a CRegion object that holds the + * calculated clipping region upon return + * + * @deprecated For anti-flickering ClipChildren should be preferred + * as it is more complete for platform compatibility. + * It will probably become a private function. + */ +void CResizableLayout::GetClippingRegion(CRgn* pRegion) const +{ + const CWnd* pWnd = GetResizableWnd(); + + // System's default clipping area is screen's size, + // not enough for max track size, for example: + // if screen is 1024 x 768 and resizing border is 4 pixels, + // maximized size is 1024+4*2=1032 x 768+4*2=776, + // but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!) + // So, if you resize the window to maximum size, the last 4 pixels + // are clipped out by the default clipping region, that gets created + // as soon as you call clipping functions (my guess). + + // reset clipping region to the whole client area + CRect rect; + pWnd->GetClientRect(&rect); + pRegion->CreateRectRgnIndirect(&rect); + + // clip only anchored controls + + for (POSITION pos = m_listLayout.GetHeadPosition(); pos != NULL;) + { + // get layout info + LAYOUTINFO layout = m_listLayout.GetNext(pos); + + if (::IsWindowVisible(layout.hWnd)) + ClipChildWindow(layout, pRegion); + } + + for (POSITION pos = m_listLayoutCB.GetHeadPosition(); pos != NULL;) + { + // get layout info + LAYOUTINFO layout = m_listLayoutCB.GetNext(pos); + // request data + if (ArrangeLayoutCallback(layout) && ::IsWindowVisible(layout.hWnd)) + ClipChildWindow(layout, pRegion); + } +//! @todo Has XP changed this??? It doesn't seem correct anymore! +/* + // fix for RTL layouts (1 pixel of horz offset) + if (pWnd->GetExStyle() & WS_EX_LAYOUTRTL) + pRegion->OffsetRgn(-1,0); +*/ +} + +//! @internal @brief Implements GetAncestor(pWnd->GetSafeHwnd(), GA_ROOT) +inline CWnd* GetRootParentWnd(CWnd* pWnd) +{ + // GetAncestor API not present, emulate + if (!(pWnd->GetStyle() & WS_CHILD)) + return NULL; + while (pWnd->GetStyle() & WS_CHILD) + pWnd = pWnd->GetParent(); + return pWnd; +} + +/*! + * This function enables or restores clipping on the specified DC when + * appropriate. It should be called whenever drawing on the window client + * area to avoid flickering. + * + * @param pDC Pointer to the target device context + * @param bUndo Flag that specifies whether to restore the clipping region + * + * @return The return value is @c TRUE if the clipping region has been + * modified, @c FALSE otherwise + * + * @remarks For anti-flickering to work, you should wrap your + * @c WM_ERASEBKGND message handler inside a pair of calls to + * this function, with the last parameter set to @c FALSE first + * and to @c TRUE at the end. + */ +BOOL CResizableLayout::ClipChildren(const CDC* pDC, BOOL bUndo) +{ +#if (_WIN32_WINNT >= 0x0501 && !defined(RSZLIB_NO_XP_DOUBLE_BUFFER)) + // clipping not necessary when double-buffering enabled + if (real_WIN32_WINNT >= 0x0501) + { + CWnd *pWnd = GetRootParentWnd(GetResizableWnd()); + if (pWnd == NULL) + pWnd = GetResizableWnd(); + if (pWnd->GetExStyle() & WS_EX_COMPOSITED) + return FALSE; + } +#endif + + const HDC hDC = pDC->GetSafeHdc(); + const HWND hWnd = GetResizableWnd()->GetSafeHwnd(); + + // Some controls (such as transparent toolbars and standard controls + // with XP theme enabled) send a WM_ERASEBKGND msg to the parent + // to draw themselves, in which case we must not enable clipping. + + // We check that the window associated with the DC is the + // resizable window and not a child control. + + if (!bUndo) + { + if (hWnd != ::WindowFromDC(hDC)) + m_nOldClipRgn = -1; // invalid region + else + { + // save old DC clipping region + m_nOldClipRgn = ::GetClipRgn(hDC, m_hOldClipRgn); + // clip out supported child windows + CRgn rgnClip; + GetClippingRegion(&rgnClip); + ::ExtSelectClipRgn(hDC, rgnClip, RGN_AND); + } + return (m_nOldClipRgn >= 0) ? TRUE : FALSE; + } + + if (m_nOldClipRgn >= 0) // restore old clipping region, only if modified and valid + { + ::SelectClipRgn(hDC, (m_nOldClipRgn>0 ? m_hOldClipRgn : NULL)); + return TRUE; + } + + return FALSE; +} + +/*! + * This function is used by this class, and should be used by derived + * classes too, in place of the standard GetClientRect. It can be useful + * for windows with scrollbars or expanding windows, to provide the true + * client area, including even those parts which are not visible. + * + * @param lpRect Pointer to the RECT structure that holds the result + * + * @remarks Override this function to provide the client area the class uses + * to perform layout calculations, both when adding controls and + * when rearranging the layout. + * @n The base implementation simply calls @c GetClientRect + */ +void CResizableLayout::GetTotalClientRect(LPRECT lpRect) const +{ + GetResizableWnd()->GetClientRect(lpRect); +} + +/*! + * This function is used to determine if a control needs to be painted when + * it is moved or resized by the layout manager. + * + * @param layout Reference to a @c LAYOUTINFO structure for the control + * @param rectOld Reference to a @c RECT structure that holds the control + * position and size before the layout update + * @param rectNew Reference to a @c RECT structure that holds the control + * position and size after the layout update + * + * @return The return value is @c TRUE if the control should be freshly + * painted after a layout update, @c FALSE if not necessary. + * + * @remarks The default implementation tries to identify windows that + * need refresh by their class name and window style. + * @n Override this function if you need a different behavior or if + * you have custom controls that fail to be identified. + * + * @sa LikesClipping InitResizeProperties + */ +BOOL CResizableLayout::NeedsRefresh(const LAYOUTINFO& layout, + const CRect& rectOld, const CRect& rectNew) const +{ + if (layout.bMsgSupport) + { + REFRESHPROPERTY refresh; + refresh.rcOld = rectOld; + refresh.rcNew = rectNew; + if (Send_NeedsRefresh(layout.hWnd, &refresh)) + return refresh.bNeedsRefresh; + } + + const int nDiffWidth = (rectNew.Width() - rectOld.Width()); + const int nDiffHeight = (rectNew.Height() - rectOld.Height()); + + // is the same size? + if (nDiffWidth == 0 && nDiffHeight == 0) + return FALSE; + + // optimistic, no need to refresh + BOOL bRefresh = FALSE; + + // window classes that need refresh when resized + if (0 == lstrcmp(layout.sWndClass, WC_STATIC)) + { + LONG_PTR style = ::GetWindowLongPtr(layout.hWnd, GWL_STYLE); + + switch (style & SS_TYPEMASK) + { + case SS_LEFT: + case SS_CENTER: + case SS_RIGHT: + // word-wrapped text + bRefresh = bRefresh || (nDiffWidth != 0); + // vertically centered text + if (style & SS_CENTERIMAGE) + bRefresh = bRefresh || (nDiffHeight != 0); + break; + + case SS_LEFTNOWORDWRAP: + // text with ellipsis + if (style & SS_ELLIPSISMASK) + bRefresh = bRefresh || (nDiffWidth != 0); + // vertically centered text + if (style & SS_CENTERIMAGE) + bRefresh = bRefresh || (nDiffHeight != 0); + break; + + case SS_ENHMETAFILE: + case SS_BITMAP: + case SS_ICON: + // images + case SS_BLACKFRAME: + case SS_GRAYFRAME: + case SS_WHITEFRAME: + case SS_ETCHEDFRAME: + // and frames + bRefresh = TRUE; + break; + } + return bRefresh; + } + + // window classes that don't redraw client area correctly + // when the hor scroll pos changes due to a resizing + const BOOL bHScroll = (0 == lstrcmp(layout.sWndClass, WC_LISTBOX)); + + // fix for horizontally scrollable windows, if wider + if (bHScroll && (nDiffWidth > 0)) + { + // get max scroll position + SCROLLINFO info; + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + if (::GetScrollInfo(layout.hWnd, SB_HORZ, &info) && info.nPage > 1) //fix for unsigned subtraction + { + // subtract the page size + info.nMax -= info.nPage-1; //should not use __max() macro + } + + // resizing will cause the text to scroll on the right + // because the scrollbar is going beyond the right limit + if ((info.nMax > 0) && (info.nPos + nDiffWidth > info.nMax)) + { + // needs repainting, due to horiz scrolling + bRefresh = TRUE; + } + } + + return bRefresh; +} + +/*! + * This function is used to determine if a control can be safely clipped + * out of the parent window client area when it is repainted, usually + * after a resize operation. + * + * @param layout Reference to a @c LAYOUTINFO structure for the control + * + * @return The return value is @c TRUE if clipping is supported by the + * control, @c FALSE otherwise. + * + * @remarks The default implementation tries to identify @a clippable + * windows by their class name and window style. + * @n Override this function if you need a different behavior or if + * you have custom controls that fail to be identified. + * + * @sa NeedsRefresh InitResizeProperties + */ +BOOL CResizableLayout::LikesClipping(const LAYOUTINFO& layout) const +{ + if (layout.bMsgSupport) + { + CLIPPINGPROPERTY clipping; + if (Send_LikesClipping(layout.hWnd, &clipping)) + return clipping.bLikesClipping; + } + + const LONG_PTR style = ::GetWindowLongPtr(layout.hWnd, GWL_STYLE); + + // skip windows that wants background repainted + if (0 == lstrcmp(layout.sWndClass, WC_BUTTON)) + { + CRect rect; + switch (style & _BS_TYPEMASK) + { + case BS_GROUPBOX: + return FALSE; + + case BS_OWNERDRAW: + // ownerdraw buttons must return correct hittest code + // to notify their transparency to the system and this library + // or they could use the registered message (more reliable) + ::GetWindowRect(layout.hWnd, &rect); + ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); + if ( HTTRANSPARENT == ::SendMessage(layout.hWnd, + WM_NCHITTEST, 0, MAKELPARAM(rect.left, rect.top)) ) + return FALSE; + break; + } + return TRUE; + } + else if (0 == lstrcmp(layout.sWndClass, WC_STATIC)) + { + switch (style & SS_TYPEMASK) + { + case SS_LEFT: + case SS_CENTER: + case SS_RIGHT: + case SS_LEFTNOWORDWRAP: + // text + case SS_BLACKRECT: + case SS_GRAYRECT: + case SS_WHITERECT: + // filled rects + case SS_ETCHEDHORZ: + case SS_ETCHEDVERT: + // etched lines + case SS_BITMAP: + // bitmaps + return TRUE; + + case SS_ICON: + case SS_ENHMETAFILE: + if (style & SS_CENTERIMAGE) + return FALSE; + return TRUE; + + default: + return FALSE; + } + } + + // assume the others like clipping + return TRUE; +} + + +/*! + * @internal This function calculates the new size and position of a + * control in the layout and flags for @c SetWindowPos + */ +void CResizableLayout::CalcNewChildPosition(const LAYOUTINFO& layout, + const CRect &rectParent, CRect &rectChild, UINT *lpFlags) const +{ + const CWnd* pParent = GetResizableWnd(); + + ::GetWindowRect(layout.hWnd, &rectChild); + ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); + + CRect rectNew; + + // calculate new top-left corner + rectNew.left = layout.marginTopLeft.cx + rectParent.Width() * layout.anchorTopLeft.cx / 100; + rectNew.top = layout.marginTopLeft.cy + rectParent.Height() * layout.anchorTopLeft.cy / 100; + + // calculate new bottom-right corner + rectNew.right = layout.marginBottomRight.cx + rectParent.Width() * layout.anchorBottomRight.cx / 100; + rectNew.bottom = layout.marginBottomRight.cy + rectParent.Height() * layout.anchorBottomRight.cy / 100; + + // adjust position, if client area has been scrolled + rectNew.OffsetRect(rectParent.TopLeft()); + + // get the refresh property + BOOL bRefresh = layout.properties.bAskRefresh ? + NeedsRefresh(layout, rectChild, rectNew) : layout.properties.bCachedNeedsRefresh; + + // set flags + if (lpFlags) + { + *lpFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION; + if (bRefresh) + *lpFlags |= SWP_NOCOPYBITS; + if (rectNew.TopLeft() == rectChild.TopLeft()) + *lpFlags |= SWP_NOMOVE; + if (rectNew.Size() == rectChild.Size()) + *lpFlags |= SWP_NOSIZE; + } + + // update rect + rectChild = rectNew; +} + +/*! + * This function calculates the top, left, bottom, right margins for a + * given size of the specified control. + * + * @param hWnd Window handle to a control in the layout + * @param sizeChild Size of the control to use in calculations + * @param rectMargins Holds the calculated margins + * + * @return The return value is @c TRUE if successful, @c FALSE otherwise + * + * @remarks This function can be used to infer the parent window size + * from the size of one of its child controls. + * It is used to implement cascading of size constraints. + */ +BOOL CResizableLayout::GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const +{ + POSITION pos; + if (!m_mapLayout.Lookup(hWnd, pos)) + return FALSE; + + const LAYOUTINFO& layout = m_listLayout.GetAt(pos); + + // augmented size, relative to anchor points + const CSize size = sizeChild + layout.marginTopLeft - layout.marginBottomRight; + + // percent of parent size occupied by this control + const CSize percent(layout.anchorBottomRight.cx - layout.anchorTopLeft.cx, + layout.anchorBottomRight.cy - layout.anchorTopLeft.cy); + + // calculate total margins + rectMargins.left = size.cx * layout.anchorTopLeft.cx / percent.cx + layout.marginTopLeft.cx; + rectMargins.top = size.cy * layout.anchorTopLeft.cy / percent.cy + layout.marginTopLeft.cy; + rectMargins.right = size.cx * (100 - layout.anchorBottomRight.cx) / percent.cx - layout.marginBottomRight.cx; + rectMargins.bottom = size.cy * (100 - layout.anchorBottomRight.cy) / percent.cy - layout.marginBottomRight.cy; + + return TRUE; +} + +/*! + * This function is used to set the initial resize properties of a control + * in the layout, that are stored in the @c properties member of the + * related @c LAYOUTINFO structure. + * + * @param layout Reference to the @c LAYOUTINFO structure to be set + * + * @remarks The various flags are used to specify whether the resize + * properties (clipping, refresh) can change at run-time, and a new + * call to the property querying functions is needed at every + * layout update, or they are static properties, and the cached + * value is used whenever necessary. + * @n The default implementation sends a registered message to the + * control, giving it the opportunity to specify its resize + * properties, which takes precedence if the message is supported. + * It then sets the @a clipping property as static, calling + * @c LikesClipping only once, and the @a refresh property as + * dynamic, causing @c NeedsRefresh to be called every time. + * @n This should be right for most situations, as the need for + * @a refresh usually depends on the size of the control, while the + * support for @a clipping is usually linked to the specific type + * of control, which is unlikely to change at run-time, but you can + * still override this function if a different behaviour is needed. + * + * @sa LikesClipping NeedsRefresh LAYOUTINFO RESIZEPROPERTIES + */ +void CResizableLayout::InitResizeProperties(LAYOUTINFO &layout) const +{ + // check if custom window supports this library + // (properties must be correctly set by the window) + layout.bMsgSupport = Send_QueryProperties(layout.hWnd, &layout.properties); + + // default properties + if (!layout.bMsgSupport) + { + // clipping property is assumed as static + layout.properties.bAskClipping = FALSE; + layout.properties.bCachedLikesClipping = LikesClipping(layout); + // refresh property is assumed as dynamic + layout.properties.bAskRefresh = TRUE; + } +} + +/*! + * This function modifies a window to enable resizing functionality. + * This affects the window style, size, system menu and appearance. + * + * @param lpCreateStruct Pointer to a @c CREATESTRUCT structure, usually + * passed by the system to the window procedure in a @c WM_CREATE + * or @c WM_NCCREATE + * + * @remarks The function is intended to be called only inside a @c WM_CREATE + * or @c WM_NCCREATE message handler. + */ +void CResizableLayout::MakeResizable(LPCREATESTRUCT lpCreateStruct) const +{ + if (lpCreateStruct->style & WS_CHILD) + return; + + InitThemeSettings(); //! @todo move theme check in more appropriate place + + CWnd* pWnd = GetResizableWnd(); + +#if (_WIN32_WINNT >= 0x0501 && !defined(RSZLIB_NO_XP_DOUBLE_BUFFER)) + // enable double-buffering on supported platforms + pWnd->ModifyStyleEx(0, WS_EX_COMPOSITED); +#endif + + if (!(lpCreateStruct->style & WS_THICKFRAME)) + { + // keep client area + CRect rect(CPoint(lpCreateStruct->x, lpCreateStruct->y), + CSize(lpCreateStruct->cx, lpCreateStruct->cy)); + pWnd->SendMessage(WM_NCCALCSIZE, FALSE, (LPARAM)&rect); + // set resizable style + pWnd->ModifyStyle(DS_MODALFRAME, WS_THICKFRAME); + // adjust size to reflect new style + ::AdjustWindowRectEx(&rect, pWnd->GetStyle(), + ::IsMenu(pWnd->GetMenu()->GetSafeHmenu()), pWnd->GetExStyle()); + pWnd->SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), + SWP_NOSENDCHANGING|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION); + // update dimensions + lpCreateStruct->cx = rect.Width(); + lpCreateStruct->cy = rect.Height(); + } +} + +/*! + * This function should be called inside the parent window @c WM_NCCALCSIZE + * message handler to help eliminate flickering. + * + * @param bAfterDefault Flag that specifies whether the call is made before + * or after the default handler + * @param lpncsp Pointer to the @c NCCALCSIZE_PARAMS structure that is + * passed to the message handler + * @param lResult Reference to the result of the message handler. + * It contains the default handler result on input and the value to + * return from the window procedure on output. + * + * @remarks This function fixes the annoying flickering effect that is + * visible when resizing the top or left edges of the window + * (at least on a "left to right" Windows localized version). + */ +void CResizableLayout::HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT &lResult) +{ + // prevent useless complication when size is not changing + // prevent recursion when resetting the window region (see below) + if ((lpncsp->lppos->flags & SWP_NOSIZE) +#if (_WIN32_WINNT >= 0x0501) + || m_bNoRecursion +#endif + ) + return; + + if (!bAfterDefault) + { + // save a copy before default handler gets called + m_rectClientBefore = lpncsp->rgrc[2]; + } + else // after default WM_NCCALCSIZE msg processing + { + if (lResult != 0) + { + // default handler already uses an advanced validation policy, give up + return; + } + // default calculated client rect + RECT &rectClientAfter = lpncsp->rgrc[0]; + + // intersection between old and new client area is to be preserved + // set source and destination rects to this intersection + RECT &rectPreserve = lpncsp->rgrc[1]; + ::IntersectRect(&rectPreserve, &rectClientAfter, &m_rectClientBefore); + lpncsp->rgrc[2] = rectPreserve; + + lResult = WVR_VALIDRECTS; + + // FIX: window region must be updated before the result of the + // WM_NCCALCSIZE message gets processed by the system, + // otherwise the old window region will clip the client + // area during the preservation process. + // This is especially evident on WinXP when the non-client + // area is rendered with Visual Styles enabled and the + // windows have a non rectangular region. + // NOTE: Implementers of skin systems that modify the window region + // should not rely on this fix and should handle non-client + // window messages themselves, to avoid flickering +#if (_WIN32_WINNT >= 0x0501) + if ((real_WIN32_WINNT >= 0x0501) + && (real_ThemeSettings & STAP_ALLOW_NONCLIENT)) + { + CWnd* pWnd = GetResizableWnd(); + DWORD dwStyle = pWnd->GetStyle(); + if ((dwStyle & (WS_CAPTION|WS_MAXIMIZE)) == WS_CAPTION) + { + m_bNoRecursion = TRUE; + pWnd->SetWindowRgn(NULL, FALSE); + m_bNoRecursion = FALSE; + } + } +#endif + } +} diff --git a/src/thirdparty/ResizableLib/ResizableLayout.h b/src/thirdparty/ResizableLib/ResizableLayout.h index a5473b74c96..3ebb452063a 100644 --- a/src/thirdparty/ResizableLib/ResizableLayout.h +++ b/src/thirdparty/ResizableLib/ResizableLayout.h @@ -1,316 +1,316 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Interface for the CResizableLayout class. - */ - -#if !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_) -#define AFX_RESIZABLELAYOUT_H__INCLUDED_ - -//#include -#include "ResizableMsgSupport.h" - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -/*! @addtogroup CoreComponents - * @{ - */ - -//! @brief Special type for layout alignment -/*! - * Implements anchor points as a percentage of the parent window client area. - * Control corners are always kept at a fixed distance from their anchor points, - * thus allowing a control to resize proportionally as the parent window is resized. - */ -typedef struct tagANCHOR -{ - int cx; //!< horizontal component, in percent - int cy; //!< vertical component, in percent - - tagANCHOR() : cx(0), cy(0) {} - - tagANCHOR(int x, int y) - { - cx = x; - cy = y; - } - -} ANCHOR, *PANCHOR, *LPANCHOR; - -/*! @defgroup ConstAnchors Alignment Constants - * Declare common layout alignment constants for anchor points. - * @{ - */ - //! Anchor to the top-left corner - extern const ANCHOR TOP_LEFT; - //! Anchor to the top edge and center horizontally - extern const ANCHOR TOP_CENTER; - //! Anchor to the top-right corner - extern const ANCHOR TOP_RIGHT; - //! Anchor to the left edge and center vertically - extern const ANCHOR MIDDLE_LEFT; - //! Anchor to the center - extern const ANCHOR MIDDLE_CENTER; - //! Anchor to the right edge and center vertically - extern const ANCHOR MIDDLE_RIGHT; - //! Anchor to the bottom-left corner - extern const ANCHOR BOTTOM_LEFT; - //! Anchor to the bottom edge and center horizontally - extern const ANCHOR BOTTOM_CENTER; - //! Anchor to the bottom-right corner - extern const ANCHOR BOTTOM_RIGHT; -// @} - -//! @brief Holds a control layout settings -/*! - * Layout settings specify how a control must be moved and resized with respect to - * the parent window and how it reacts to dynamic changes to its size when painting - * its client area, with special care for flickering. - */ -typedef struct tagLAYOUTINFO -{ - //! Handle of the window the layout of which is being defined - HWND hWnd; - //! Identification number assigned to the callback slot - LRESULT nCallbackID; - - //! Window class name to identify standard controls - TCHAR sWndClass[MAX_PATH]; - - //! Anchor point for the top-left corner - ANCHOR anchorTopLeft; - //! Fixed distance for the top-left corner - SIZE marginTopLeft; - - //! Anchor point for the bottom-right corner - ANCHOR anchorBottomRight; - //! Fixed distance for the bottom-right corner - SIZE marginBottomRight; - - //! Flag that enables support for custom windows - BOOL bMsgSupport; - //! Redraw settings for anti-flickering and proper painting - RESIZEPROPERTIES properties; - - tagLAYOUTINFO() : hWnd(NULL), nCallbackID(0) - , marginTopLeft(), marginBottomRight(), bMsgSupport(FALSE) - { - sWndClass[0] = 0; - } - - tagLAYOUTINFO(HWND hwnd, ANCHOR tl_type, SIZE tl_margin, - ANCHOR br_type, SIZE br_margin) - : - hWnd(hwnd), nCallbackID(0), - anchorTopLeft(tl_type), marginTopLeft(tl_margin), - anchorBottomRight(br_type), marginBottomRight(br_margin), bMsgSupport(FALSE) - { - sWndClass[0] = 0; - } - -} LAYOUTINFO, *PLAYOUTINFO, *LPLAYOUTINFO; - -//! @brief Layout manager implementation -/*! - * Derive from this class to implement resizable windows, adding the ability - * to dinamically resize and reposition child controls. - * Special care is taken to ensure a smooth animation during the resize - * operations performed by the users, without annoying flickering effects. - */ -class CResizableLayout -{ -private: - //@{ - //! @brief Collection of layout settings for each control - CMap m_mapLayout; - CList m_listLayout; - CList m_listLayoutCB; - //@} - - //@{ - //! @brief Used for clipping implementation - HRGN m_hOldClipRgn; - int m_nOldClipRgn; - //@} - - //@{ - //! @brief Used for advanced anti-flickering - RECT m_rectClientBefore; - BOOL m_bNoRecursion; - //@} - - //! @brief Apply clipping settings for the specified control - void ClipChildWindow(const LAYOUTINFO &layout, CRgn* pRegion) const; - - //! @brief Helper function to calculate new layout - void CalcNewChildPosition(const LAYOUTINFO &layout, - const CRect &rectParent, CRect &rectChild, UINT *lpFlags) const; - -protected: - //! @brief Override to initialize resize properties (clipping, refresh) - virtual void InitResizeProperties(LAYOUTINFO& layout) const; - - //! @brief Override to specify clipping for unsupported windows - virtual BOOL LikesClipping(const LAYOUTINFO &layout) const; - - //! @brief Override to specify refresh for unsupported windows - virtual BOOL NeedsRefresh(const LAYOUTINFO &layout, - const CRect &rectOld, const CRect &rectNew) const; - - //! @brief Clip controls in the layout out of the specified device context - BOOL ClipChildren(const CDC* pDC, BOOL bUndo); - - //! @brief Get the layout clipping region - void GetClippingRegion(CRgn* pRegion) const; - - //! @brief Override for scrollable or expanding parent windows - virtual void GetTotalClientRect(LPRECT lpRect) const; - - //@{ - //! @brief Add anchor points for the specified control to the layout - void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight); - - void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft) - { - AddAnchor(hWnd, anchorTopLeft, anchorTopLeft); - } - - void AddAnchor(UINT nID, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) - { - AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), - anchorTopLeft, anchorBottomRight); - } - - void AddAnchor(UINT nID, ANCHOR anchorTopLeft) - { - AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), - anchorTopLeft, anchorTopLeft); - } - //@} - - //@{ - //! @brief Add anchor points for all the remaining controls to the layout - void AddAllOtherAnchors(ANCHOR anchorTopLeft, ANCHOR anchorBottomRight); - - void AddAllOtherAnchors(ANCHOR anchor) - { - AddAllOtherAnchors(anchor, anchor); - } - - void AddAllOtherAnchors() - { - AddAllOtherAnchors(TOP_LEFT); - } - //@} - - //! @brief Add a callback slot to the layout for dynamic controls or anchor points - LRESULT AddAnchorCallback(); - - //@{ - //! @brief Get position and size of a control in the layout from the parent's client area - BOOL GetAnchorPosition(HWND hWnd, const CRect &rectParent, - CRect &rectChild, UINT* lpFlags = NULL) const - { - POSITION pos; - if (!m_mapLayout.Lookup(hWnd, pos)) - return FALSE; - - CalcNewChildPosition(m_listLayout.GetAt(pos), rectParent, rectChild, lpFlags); - return TRUE; - } - - BOOL GetAnchorPosition(UINT nID, const CRect &rectParent, - CRect &rectChild, UINT* lpFlags = NULL) const - { - return GetAnchorPosition(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), - rectParent, rectChild, lpFlags); - } - //@} - - //@{ - //! @brief Get margins surrounding a control in the layout with the given size - BOOL GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const; - - BOOL GetAnchorMargins(UINT nID, const CSize &sizeChild, CRect &rectMargins) const - { - return GetAnchorMargins(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), - sizeChild, rectMargins); - } - //@} - - //@{ - //! @brief Remove a control from the layout - BOOL RemoveAnchor(HWND hWnd) - { - POSITION pos; - if (!m_mapLayout.Lookup(hWnd, pos)) - return FALSE; - - m_listLayout.RemoveAt(pos); - return m_mapLayout.RemoveKey(hWnd); - } - - BOOL RemoveAnchor(UINT nID) - { - return RemoveAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID)); - } - //@} - - //! @brief Reset the layout content - void RemoveAllAnchors() - { - m_mapLayout.RemoveAll(); - m_listLayout.RemoveAll(); - m_listLayoutCB.RemoveAll(); - } - - //! @brief Reposition and size all the controls in the layout - void ArrangeLayout() const; - - //! @brief Override to provide dynamic control's layout info - virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const; - - //! @brief Override to provide the parent window - virtual CWnd* GetResizableWnd() const = 0; - - //! @brief Enhance anti-flickering - void HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT& lResult); - - //! @brief Enable resizable style for top level parent windows - void MakeResizable(LPCREATESTRUCT lpCreateStruct) const; - -public: - CResizableLayout() - : m_rectClientBefore() - { - m_bNoRecursion = FALSE; - m_hOldClipRgn = ::CreateRectRgn(0,0,0,0); - m_nOldClipRgn = 0; - } - - virtual ~CResizableLayout() - { - ::DeleteObject(m_hOldClipRgn); - // just for safety - RemoveAllAnchors(); - } -}; - -// @} -#endif // !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_) +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Interface for the CResizableLayout class. + */ + +#if !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_) +#define AFX_RESIZABLELAYOUT_H__INCLUDED_ + +//#include +#include "ResizableMsgSupport.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/*! @addtogroup CoreComponents + * @{ + */ + +//! @brief Special type for layout alignment +/*! + * Implements anchor points as a percentage of the parent window client area. + * Control corners are always kept at a fixed distance from their anchor points, + * thus allowing a control to resize proportionally as the parent window is resized. + */ +typedef struct tagANCHOR +{ + int cx; //!< horizontal component, in percent + int cy; //!< vertical component, in percent + + tagANCHOR() : cx(0), cy(0) {} + + tagANCHOR(int x, int y) + { + cx = x; + cy = y; + } + +} ANCHOR, *PANCHOR, *LPANCHOR; + +/*! @defgroup ConstAnchors Alignment Constants + * Declare common layout alignment constants for anchor points. + * @{ + */ + //! Anchor to the top-left corner + extern const ANCHOR TOP_LEFT; + //! Anchor to the top edge and center horizontally + extern const ANCHOR TOP_CENTER; + //! Anchor to the top-right corner + extern const ANCHOR TOP_RIGHT; + //! Anchor to the left edge and center vertically + extern const ANCHOR MIDDLE_LEFT; + //! Anchor to the center + extern const ANCHOR MIDDLE_CENTER; + //! Anchor to the right edge and center vertically + extern const ANCHOR MIDDLE_RIGHT; + //! Anchor to the bottom-left corner + extern const ANCHOR BOTTOM_LEFT; + //! Anchor to the bottom edge and center horizontally + extern const ANCHOR BOTTOM_CENTER; + //! Anchor to the bottom-right corner + extern const ANCHOR BOTTOM_RIGHT; +// @} + +//! @brief Holds a control layout settings +/*! + * Layout settings specify how a control must be moved and resized with respect to + * the parent window and how it reacts to dynamic changes to its size when painting + * its client area, with special care for flickering. + */ +typedef struct tagLAYOUTINFO +{ + //! Handle of the window the layout of which is being defined + HWND hWnd; + //! Identification number assigned to the callback slot + LRESULT nCallbackID; + + //! Window class name to identify standard controls + TCHAR sWndClass[MAX_PATH]; + + //! Anchor point for the top-left corner + ANCHOR anchorTopLeft; + //! Fixed distance for the top-left corner + SIZE marginTopLeft; + + //! Anchor point for the bottom-right corner + ANCHOR anchorBottomRight; + //! Fixed distance for the bottom-right corner + SIZE marginBottomRight; + + //! Flag that enables support for custom windows + BOOL bMsgSupport; + //! Redraw settings for anti-flickering and proper painting + RESIZEPROPERTIES properties; + + tagLAYOUTINFO() : hWnd(NULL), nCallbackID(0) + , marginTopLeft(), marginBottomRight(), bMsgSupport(FALSE) + { + sWndClass[0] = 0; + } + + tagLAYOUTINFO(HWND hwnd, ANCHOR tl_type, SIZE tl_margin, + ANCHOR br_type, SIZE br_margin) + : + hWnd(hwnd), nCallbackID(0), + anchorTopLeft(tl_type), marginTopLeft(tl_margin), + anchorBottomRight(br_type), marginBottomRight(br_margin), bMsgSupport(FALSE) + { + sWndClass[0] = 0; + } + +} LAYOUTINFO, *PLAYOUTINFO, *LPLAYOUTINFO; + +//! @brief Layout manager implementation +/*! + * Derive from this class to implement resizable windows, adding the ability + * to dinamically resize and reposition child controls. + * Special care is taken to ensure a smooth animation during the resize + * operations performed by the users, without annoying flickering effects. + */ +class CResizableLayout +{ +private: + //@{ + //! @brief Collection of layout settings for each control + CMap m_mapLayout; + CList m_listLayout; + CList m_listLayoutCB; + //@} + + //@{ + //! @brief Used for clipping implementation + HRGN m_hOldClipRgn; + int m_nOldClipRgn; + //@} + + //@{ + //! @brief Used for advanced anti-flickering + RECT m_rectClientBefore; + BOOL m_bNoRecursion; + //@} + + //! @brief Apply clipping settings for the specified control + void ClipChildWindow(const LAYOUTINFO &layout, CRgn* pRegion) const; + + //! @brief Helper function to calculate new layout + void CalcNewChildPosition(const LAYOUTINFO &layout, + const CRect &rectParent, CRect &rectChild, UINT *lpFlags) const; + +protected: + //! @brief Override to initialize resize properties (clipping, refresh) + virtual void InitResizeProperties(LAYOUTINFO& layout) const; + + //! @brief Override to specify clipping for unsupported windows + virtual BOOL LikesClipping(const LAYOUTINFO &layout) const; + + //! @brief Override to specify refresh for unsupported windows + virtual BOOL NeedsRefresh(const LAYOUTINFO &layout, + const CRect &rectOld, const CRect &rectNew) const; + + //! @brief Clip controls in the layout out of the specified device context + BOOL ClipChildren(const CDC* pDC, BOOL bUndo); + + //! @brief Get the layout clipping region + void GetClippingRegion(CRgn* pRegion) const; + + //! @brief Override for scrollable or expanding parent windows + virtual void GetTotalClientRect(LPRECT lpRect) const; + + //@{ + //! @brief Add anchor points for the specified control to the layout + void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight); + + void AddAnchor(HWND hWnd, ANCHOR anchorTopLeft) + { + AddAnchor(hWnd, anchorTopLeft, anchorTopLeft); + } + + void AddAnchor(UINT nID, ANCHOR anchorTopLeft, ANCHOR anchorBottomRight) + { + AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), + anchorTopLeft, anchorBottomRight); + } + + void AddAnchor(UINT nID, ANCHOR anchorTopLeft) + { + AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), + anchorTopLeft, anchorTopLeft); + } + //@} + + //@{ + //! @brief Add anchor points for all the remaining controls to the layout + void AddAllOtherAnchors(ANCHOR anchorTopLeft, ANCHOR anchorBottomRight); + + void AddAllOtherAnchors(ANCHOR anchor) + { + AddAllOtherAnchors(anchor, anchor); + } + + void AddAllOtherAnchors() + { + AddAllOtherAnchors(TOP_LEFT); + } + //@} + + //! @brief Add a callback slot to the layout for dynamic controls or anchor points + LRESULT AddAnchorCallback(); + + //@{ + //! @brief Get position and size of a control in the layout from the parent's client area + BOOL GetAnchorPosition(HWND hWnd, const CRect &rectParent, + CRect &rectChild, UINT* lpFlags = NULL) const + { + POSITION pos; + if (!m_mapLayout.Lookup(hWnd, pos)) + return FALSE; + + CalcNewChildPosition(m_listLayout.GetAt(pos), rectParent, rectChild, lpFlags); + return TRUE; + } + + BOOL GetAnchorPosition(UINT nID, const CRect &rectParent, + CRect &rectChild, UINT* lpFlags = NULL) const + { + return GetAnchorPosition(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), + rectParent, rectChild, lpFlags); + } + //@} + + //@{ + //! @brief Get margins surrounding a control in the layout with the given size + BOOL GetAnchorMargins(HWND hWnd, const CSize &sizeChild, CRect &rectMargins) const; + + BOOL GetAnchorMargins(UINT nID, const CSize &sizeChild, CRect &rectMargins) const + { + return GetAnchorMargins(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID), + sizeChild, rectMargins); + } + //@} + + //@{ + //! @brief Remove a control from the layout + BOOL RemoveAnchor(HWND hWnd) + { + POSITION pos; + if (!m_mapLayout.Lookup(hWnd, pos)) + return FALSE; + + m_listLayout.RemoveAt(pos); + return m_mapLayout.RemoveKey(hWnd); + } + + BOOL RemoveAnchor(UINT nID) + { + return RemoveAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID)); + } + //@} + + //! @brief Reset the layout content + void RemoveAllAnchors() + { + m_mapLayout.RemoveAll(); + m_listLayout.RemoveAll(); + m_listLayoutCB.RemoveAll(); + } + + //! @brief Reposition and size all the controls in the layout + void ArrangeLayout() const; + + //! @brief Override to provide dynamic control's layout info + virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const; + + //! @brief Override to provide the parent window + virtual CWnd* GetResizableWnd() const = 0; + + //! @brief Enhance anti-flickering + void HandleNcCalcSize(BOOL bAfterDefault, LPNCCALCSIZE_PARAMS lpncsp, LRESULT& lResult); + + //! @brief Enable resizable style for top level parent windows + void MakeResizable(LPCREATESTRUCT lpCreateStruct) const; + +public: + CResizableLayout() + : m_rectClientBefore() + { + m_bNoRecursion = FALSE; + m_hOldClipRgn = ::CreateRectRgn(0,0,0,0); + m_nOldClipRgn = 0; + } + + virtual ~CResizableLayout() + { + ::DeleteObject(m_hOldClipRgn); + // just for safety + RemoveAllAnchors(); + } +}; + +// @} +#endif // !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableLib.vcxproj b/src/thirdparty/ResizableLib/ResizableLib.vcxproj index 3f5991ea4ee..f0b2c10f707 100644 --- a/src/thirdparty/ResizableLib/ResizableLib.vcxproj +++ b/src/thirdparty/ResizableLib/ResizableLib.vcxproj @@ -1,81 +1,81 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {4CC7AE86-3E0A-430A-BFF4-BF00204CAFB0} - ResizableLib - MFCProj - ResizableLib - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4CC7AE86-3E0A-430A-BFF4-BF00204CAFB0} + ResizableLib + MFCProj + ResizableLib + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/ResizableLib/ResizableLib.vcxproj.filters b/src/thirdparty/ResizableLib/ResizableLib.vcxproj.filters index 09004146205..4591a4c2c53 100644 --- a/src/thirdparty/ResizableLib/ResizableLib.vcxproj.filters +++ b/src/thirdparty/ResizableLib/ResizableLib.vcxproj.filters @@ -1,89 +1,89 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/ResizableLib/ResizableMinMax.cpp b/src/thirdparty/ResizableLib/ResizableMinMax.cpp index a9bf852cbbf..59e3ea37786 100644 --- a/src/thirdparty/ResizableLib/ResizableMinMax.cpp +++ b/src/thirdparty/ResizableLib/ResizableMinMax.cpp @@ -1,211 +1,211 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Implementation of the CResizableMinMax class. - */ - -#include "stdafx.h" -#include "ResizableMinMax.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[]=__FILE__; -#define new DEBUG_NEW -#endif - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResizableMinMax::CResizableMinMax() - : m_ptMinTrackSize(), m_ptMaxTrackSize(), m_ptMaxPos(), m_ptMaxSize() -{ - m_bUseMinTrack = FALSE; - m_bUseMaxTrack = FALSE; - m_bUseMaxRect = FALSE; -} - -CResizableMinMax::~CResizableMinMax() -{ - -} - -void CResizableMinMax::ApplyMinMaxTrackSize(LPMINMAXINFO lpMMI) -{ - lpMMI->ptMaxSize.x = __max(lpMMI->ptMaxSize.x, lpMMI->ptMinTrackSize.x); - lpMMI->ptMaxSize.y = __max(lpMMI->ptMaxSize.y, lpMMI->ptMinTrackSize.y); - - lpMMI->ptMaxSize.x = __min(lpMMI->ptMaxSize.x, lpMMI->ptMaxTrackSize.x); - lpMMI->ptMaxSize.y = __min(lpMMI->ptMaxSize.y, lpMMI->ptMaxTrackSize.y); -} - -void CResizableMinMax::MinMaxInfo(LPMINMAXINFO lpMMI) const -{ - if (m_bUseMinTrack) - lpMMI->ptMinTrackSize = m_ptMinTrackSize; - - if (m_bUseMaxTrack) - lpMMI->ptMaxTrackSize = m_ptMaxTrackSize; - - if (m_bUseMaxRect) - { - lpMMI->ptMaxPosition = m_ptMaxPos; - lpMMI->ptMaxSize = m_ptMaxSize; - } - - ApplyMinMaxTrackSize(lpMMI); -} - -void CResizableMinMax::ChainMinMaxInfo(LPMINMAXINFO lpMMI, CWnd* pParentFrame, const CWnd* pWnd) -{ - // get the extra size from child to parent - CRect rectClient, rectWnd; - if ((pParentFrame->GetStyle() & WS_CHILD) && pParentFrame->IsZoomed()) - pParentFrame->GetClientRect(rectWnd); - else - pParentFrame->GetWindowRect(rectWnd); - pParentFrame->RepositionBars(0, 0xFFFF, - AFX_IDW_PANE_FIRST, CWnd::reposQuery, rectClient); - const CSize sizeExtra = rectWnd.Size() - rectClient.Size(); - - ChainMinMaxInfo(lpMMI, pWnd->GetSafeHwnd(), sizeExtra); -} - -void CResizableMinMax::ChainMinMaxInfo(LPMINMAXINFO lpMMI, HWND hWndChild, const CSize& sizeExtra) -{ - // ask the child window for track size - MINMAXINFO mmiChild = *lpMMI; - ::SendMessage(hWndChild, WM_GETMINMAXINFO, 0, (LPARAM)&mmiChild); - BOOL bRetMax = (lpMMI->ptMaxTrackSize.x != mmiChild.ptMaxTrackSize.x - || lpMMI->ptMaxTrackSize.y != mmiChild.ptMaxTrackSize.y); - BOOL bRetMin = (lpMMI->ptMinTrackSize.x != mmiChild.ptMinTrackSize.x - || lpMMI->ptMinTrackSize.y != mmiChild.ptMinTrackSize.y); - - // add static extra size - mmiChild.ptMaxTrackSize = sizeExtra + mmiChild.ptMaxTrackSize; - mmiChild.ptMinTrackSize = sizeExtra + mmiChild.ptMinTrackSize; - - // min size is the largest - if (bRetMin) - { - lpMMI->ptMinTrackSize.x = __max(lpMMI->ptMinTrackSize.x, - mmiChild.ptMinTrackSize.x); - lpMMI->ptMinTrackSize.y = __max(lpMMI->ptMinTrackSize.y, - mmiChild.ptMinTrackSize.y); - } - // max size is the shortest - if (bRetMax) - { - lpMMI->ptMaxTrackSize.x = __min(lpMMI->ptMaxTrackSize.x, - mmiChild.ptMaxTrackSize.x); - lpMMI->ptMaxTrackSize.y = __min(lpMMI->ptMaxTrackSize.y, - mmiChild.ptMaxTrackSize.y); - } - - ApplyMinMaxTrackSize(lpMMI); -} - -BOOL CResizableMinMax::CalcSizeExtra(HWND /*hWndChild*/, const CSize& /*sizeChild*/, CSize& /*sizeExtra*/) -{ - // should be overridden if you use ChainMinMaxInfoCB - ASSERT(FALSE); - return FALSE; -} - -void CResizableMinMax::ChainMinMaxInfoCB(LPMINMAXINFO lpMMI, HWND hWndChild) -{ - // ask the child window for track size - MINMAXINFO mmiChild = *lpMMI; - ::SendMessage(hWndChild, WM_GETMINMAXINFO, 0, (LPARAM)&mmiChild); - BOOL bRetMax = (lpMMI->ptMaxTrackSize.x != mmiChild.ptMaxTrackSize.x - || lpMMI->ptMaxTrackSize.y != mmiChild.ptMaxTrackSize.y); - BOOL bRetMin = (lpMMI->ptMinTrackSize.x != mmiChild.ptMinTrackSize.x - || lpMMI->ptMinTrackSize.y != mmiChild.ptMinTrackSize.y); - - // use a callback to determine extra size - CSize sizeExtra(0, 0); - bRetMax = bRetMax && CalcSizeExtra(hWndChild, mmiChild.ptMaxTrackSize, sizeExtra); - mmiChild.ptMaxTrackSize = sizeExtra + mmiChild.ptMaxTrackSize; - bRetMin = bRetMin && CalcSizeExtra(hWndChild, mmiChild.ptMinTrackSize, sizeExtra); - mmiChild.ptMinTrackSize = sizeExtra + mmiChild.ptMinTrackSize; - - // min size is the largest - if (bRetMin) - { - lpMMI->ptMinTrackSize.x = __max(lpMMI->ptMinTrackSize.x, - mmiChild.ptMinTrackSize.x); - lpMMI->ptMinTrackSize.y = __max(lpMMI->ptMinTrackSize.y, - mmiChild.ptMinTrackSize.y); - } - // max size is the shortest - if (bRetMax) - { - lpMMI->ptMaxTrackSize.x = __min(lpMMI->ptMaxTrackSize.x, - mmiChild.ptMaxTrackSize.x); - lpMMI->ptMaxTrackSize.y = __min(lpMMI->ptMaxTrackSize.y, - mmiChild.ptMaxTrackSize.y); - } - - ApplyMinMaxTrackSize(lpMMI); -} - -void CResizableMinMax::ResetAllRects() -{ - m_bUseMinTrack = FALSE; - m_bUseMaxTrack = FALSE; - m_bUseMaxRect = FALSE; -} - -void CResizableMinMax::SetMaximizedRect(const CRect& rc) -{ - m_bUseMaxRect = TRUE; - - m_ptMaxPos = rc.TopLeft(); - m_ptMaxSize.x = rc.Width(); - m_ptMaxSize.y = rc.Height(); -} - -void CResizableMinMax::ResetMaximizedRect() -{ - m_bUseMaxRect = FALSE; -} - -void CResizableMinMax::SetMinTrackSize(const CSize& size) -{ - m_bUseMinTrack = TRUE; - - m_ptMinTrackSize.x = size.cx; - m_ptMinTrackSize.y = size.cy; -} - -void CResizableMinMax::ResetMinTrackSize() -{ - m_bUseMinTrack = FALSE; -} - -void CResizableMinMax::SetMaxTrackSize(const CSize& size) -{ - m_bUseMaxTrack = TRUE; - - m_ptMaxTrackSize.x = size.cx; - m_ptMaxTrackSize.y = size.cy; -} - -void CResizableMinMax::ResetMaxTrackSize() -{ - m_bUseMaxTrack = FALSE; -} +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Implementation of the CResizableMinMax class. + */ + +#include "stdafx.h" +#include "ResizableMinMax.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResizableMinMax::CResizableMinMax() + : m_ptMinTrackSize(), m_ptMaxTrackSize(), m_ptMaxPos(), m_ptMaxSize() +{ + m_bUseMinTrack = FALSE; + m_bUseMaxTrack = FALSE; + m_bUseMaxRect = FALSE; +} + +CResizableMinMax::~CResizableMinMax() +{ + +} + +void CResizableMinMax::ApplyMinMaxTrackSize(LPMINMAXINFO lpMMI) +{ + lpMMI->ptMaxSize.x = __max(lpMMI->ptMaxSize.x, lpMMI->ptMinTrackSize.x); + lpMMI->ptMaxSize.y = __max(lpMMI->ptMaxSize.y, lpMMI->ptMinTrackSize.y); + + lpMMI->ptMaxSize.x = __min(lpMMI->ptMaxSize.x, lpMMI->ptMaxTrackSize.x); + lpMMI->ptMaxSize.y = __min(lpMMI->ptMaxSize.y, lpMMI->ptMaxTrackSize.y); +} + +void CResizableMinMax::MinMaxInfo(LPMINMAXINFO lpMMI) const +{ + if (m_bUseMinTrack) + lpMMI->ptMinTrackSize = m_ptMinTrackSize; + + if (m_bUseMaxTrack) + lpMMI->ptMaxTrackSize = m_ptMaxTrackSize; + + if (m_bUseMaxRect) + { + lpMMI->ptMaxPosition = m_ptMaxPos; + lpMMI->ptMaxSize = m_ptMaxSize; + } + + ApplyMinMaxTrackSize(lpMMI); +} + +void CResizableMinMax::ChainMinMaxInfo(LPMINMAXINFO lpMMI, CWnd* pParentFrame, const CWnd* pWnd) +{ + // get the extra size from child to parent + CRect rectClient, rectWnd; + if ((pParentFrame->GetStyle() & WS_CHILD) && pParentFrame->IsZoomed()) + pParentFrame->GetClientRect(rectWnd); + else + pParentFrame->GetWindowRect(rectWnd); + pParentFrame->RepositionBars(0, 0xFFFF, + AFX_IDW_PANE_FIRST, CWnd::reposQuery, rectClient); + const CSize sizeExtra = rectWnd.Size() - rectClient.Size(); + + ChainMinMaxInfo(lpMMI, pWnd->GetSafeHwnd(), sizeExtra); +} + +void CResizableMinMax::ChainMinMaxInfo(LPMINMAXINFO lpMMI, HWND hWndChild, const CSize& sizeExtra) +{ + // ask the child window for track size + MINMAXINFO mmiChild = *lpMMI; + ::SendMessage(hWndChild, WM_GETMINMAXINFO, 0, (LPARAM)&mmiChild); + BOOL bRetMax = (lpMMI->ptMaxTrackSize.x != mmiChild.ptMaxTrackSize.x + || lpMMI->ptMaxTrackSize.y != mmiChild.ptMaxTrackSize.y); + BOOL bRetMin = (lpMMI->ptMinTrackSize.x != mmiChild.ptMinTrackSize.x + || lpMMI->ptMinTrackSize.y != mmiChild.ptMinTrackSize.y); + + // add static extra size + mmiChild.ptMaxTrackSize = sizeExtra + mmiChild.ptMaxTrackSize; + mmiChild.ptMinTrackSize = sizeExtra + mmiChild.ptMinTrackSize; + + // min size is the largest + if (bRetMin) + { + lpMMI->ptMinTrackSize.x = __max(lpMMI->ptMinTrackSize.x, + mmiChild.ptMinTrackSize.x); + lpMMI->ptMinTrackSize.y = __max(lpMMI->ptMinTrackSize.y, + mmiChild.ptMinTrackSize.y); + } + // max size is the shortest + if (bRetMax) + { + lpMMI->ptMaxTrackSize.x = __min(lpMMI->ptMaxTrackSize.x, + mmiChild.ptMaxTrackSize.x); + lpMMI->ptMaxTrackSize.y = __min(lpMMI->ptMaxTrackSize.y, + mmiChild.ptMaxTrackSize.y); + } + + ApplyMinMaxTrackSize(lpMMI); +} + +BOOL CResizableMinMax::CalcSizeExtra(HWND /*hWndChild*/, const CSize& /*sizeChild*/, CSize& /*sizeExtra*/) +{ + // should be overridden if you use ChainMinMaxInfoCB + ASSERT(FALSE); + return FALSE; +} + +void CResizableMinMax::ChainMinMaxInfoCB(LPMINMAXINFO lpMMI, HWND hWndChild) +{ + // ask the child window for track size + MINMAXINFO mmiChild = *lpMMI; + ::SendMessage(hWndChild, WM_GETMINMAXINFO, 0, (LPARAM)&mmiChild); + BOOL bRetMax = (lpMMI->ptMaxTrackSize.x != mmiChild.ptMaxTrackSize.x + || lpMMI->ptMaxTrackSize.y != mmiChild.ptMaxTrackSize.y); + BOOL bRetMin = (lpMMI->ptMinTrackSize.x != mmiChild.ptMinTrackSize.x + || lpMMI->ptMinTrackSize.y != mmiChild.ptMinTrackSize.y); + + // use a callback to determine extra size + CSize sizeExtra(0, 0); + bRetMax = bRetMax && CalcSizeExtra(hWndChild, mmiChild.ptMaxTrackSize, sizeExtra); + mmiChild.ptMaxTrackSize = sizeExtra + mmiChild.ptMaxTrackSize; + bRetMin = bRetMin && CalcSizeExtra(hWndChild, mmiChild.ptMinTrackSize, sizeExtra); + mmiChild.ptMinTrackSize = sizeExtra + mmiChild.ptMinTrackSize; + + // min size is the largest + if (bRetMin) + { + lpMMI->ptMinTrackSize.x = __max(lpMMI->ptMinTrackSize.x, + mmiChild.ptMinTrackSize.x); + lpMMI->ptMinTrackSize.y = __max(lpMMI->ptMinTrackSize.y, + mmiChild.ptMinTrackSize.y); + } + // max size is the shortest + if (bRetMax) + { + lpMMI->ptMaxTrackSize.x = __min(lpMMI->ptMaxTrackSize.x, + mmiChild.ptMaxTrackSize.x); + lpMMI->ptMaxTrackSize.y = __min(lpMMI->ptMaxTrackSize.y, + mmiChild.ptMaxTrackSize.y); + } + + ApplyMinMaxTrackSize(lpMMI); +} + +void CResizableMinMax::ResetAllRects() +{ + m_bUseMinTrack = FALSE; + m_bUseMaxTrack = FALSE; + m_bUseMaxRect = FALSE; +} + +void CResizableMinMax::SetMaximizedRect(const CRect& rc) +{ + m_bUseMaxRect = TRUE; + + m_ptMaxPos = rc.TopLeft(); + m_ptMaxSize.x = rc.Width(); + m_ptMaxSize.y = rc.Height(); +} + +void CResizableMinMax::ResetMaximizedRect() +{ + m_bUseMaxRect = FALSE; +} + +void CResizableMinMax::SetMinTrackSize(const CSize& size) +{ + m_bUseMinTrack = TRUE; + + m_ptMinTrackSize.x = size.cx; + m_ptMinTrackSize.y = size.cy; +} + +void CResizableMinMax::ResetMinTrackSize() +{ + m_bUseMinTrack = FALSE; +} + +void CResizableMinMax::SetMaxTrackSize(const CSize& size) +{ + m_bUseMaxTrack = TRUE; + + m_ptMaxTrackSize.x = size.cx; + m_ptMaxTrackSize.y = size.cy; +} + +void CResizableMinMax::ResetMaxTrackSize() +{ + m_bUseMaxTrack = FALSE; +} diff --git a/src/thirdparty/ResizableLib/ResizableMinMax.h b/src/thirdparty/ResizableLib/ResizableMinMax.h index 05a4aa19a74..74f7a599178 100644 --- a/src/thirdparty/ResizableLib/ResizableMinMax.h +++ b/src/thirdparty/ResizableLib/ResizableMinMax.h @@ -1,82 +1,82 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Interface for the CResizableMinMax class. - */ - -#if !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_) -#define AFX_RESIZABLEMINMAX_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -/*! @addtogroup CoreComponents - * @{ - */ - -//! @brief brief_description -/*! - * long_description - */ -class CResizableMinMax -{ -// Attributes -private: - // flags - BOOL m_bUseMaxTrack; - BOOL m_bUseMinTrack; - BOOL m_bUseMaxRect; - - POINT m_ptMinTrackSize; // min tracking size - POINT m_ptMaxTrackSize; // max tracking size - POINT m_ptMaxPos; // maximized position - POINT m_ptMaxSize; // maximized size - -public: - CResizableMinMax(); - virtual ~CResizableMinMax(); - -protected: - static void ApplyMinMaxTrackSize(LPMINMAXINFO lpMMI); - - void MinMaxInfo(LPMINMAXINFO lpMMI) const; - static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, CWnd* pParentFrame, const CWnd* pWnd); - - static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, HWND hWndChild, const CSize& sizeExtra); - - static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, const CWnd* pParentWnd, UINT nID, const CSize& sizeExtra) - { - ChainMinMaxInfo(lpMMI, - ::GetDlgItem(pParentWnd->GetSafeHwnd(), nID), sizeExtra); - } - - void ChainMinMaxInfoCB(LPMINMAXINFO lpMMI, HWND hWndChild); - virtual BOOL CalcSizeExtra(HWND hWndChild, const CSize& sizeChild, CSize& sizeExtra); - - void ResetAllRects(); - - void SetMaximizedRect(const CRect& rc); // set window rect when maximized - void ResetMaximizedRect(); // reset to default maximized rect - void SetMinTrackSize(const CSize& size); // set minimum tracking size - void ResetMinTrackSize(); // reset to default minimum tracking size - void SetMaxTrackSize(const CSize& size); // set maximum tracking size - void ResetMaxTrackSize(); // reset to default maximum tracking size -}; - -// @} -#endif // !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_) +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Interface for the CResizableMinMax class. + */ + +#if !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_) +#define AFX_RESIZABLEMINMAX_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/*! @addtogroup CoreComponents + * @{ + */ + +//! @brief brief_description +/*! + * long_description + */ +class CResizableMinMax +{ +// Attributes +private: + // flags + BOOL m_bUseMaxTrack; + BOOL m_bUseMinTrack; + BOOL m_bUseMaxRect; + + POINT m_ptMinTrackSize; // min tracking size + POINT m_ptMaxTrackSize; // max tracking size + POINT m_ptMaxPos; // maximized position + POINT m_ptMaxSize; // maximized size + +public: + CResizableMinMax(); + virtual ~CResizableMinMax(); + +protected: + static void ApplyMinMaxTrackSize(LPMINMAXINFO lpMMI); + + void MinMaxInfo(LPMINMAXINFO lpMMI) const; + static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, CWnd* pParentFrame, const CWnd* pWnd); + + static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, HWND hWndChild, const CSize& sizeExtra); + + static void ChainMinMaxInfo(LPMINMAXINFO lpMMI, const CWnd* pParentWnd, UINT nID, const CSize& sizeExtra) + { + ChainMinMaxInfo(lpMMI, + ::GetDlgItem(pParentWnd->GetSafeHwnd(), nID), sizeExtra); + } + + void ChainMinMaxInfoCB(LPMINMAXINFO lpMMI, HWND hWndChild); + virtual BOOL CalcSizeExtra(HWND hWndChild, const CSize& sizeChild, CSize& sizeExtra); + + void ResetAllRects(); + + void SetMaximizedRect(const CRect& rc); // set window rect when maximized + void ResetMaximizedRect(); // reset to default maximized rect + void SetMinTrackSize(const CSize& size); // set minimum tracking size + void ResetMinTrackSize(); // reset to default minimum tracking size + void SetMaxTrackSize(const CSize& size); // set maximum tracking size + void ResetMaxTrackSize(); // reset to default maximum tracking size +}; + +// @} +#endif // !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableMsgSupport.h b/src/thirdparty/ResizableLib/ResizableMsgSupport.h index 28c99905639..009f35b4f58 100644 --- a/src/thirdparty/ResizableLib/ResizableMsgSupport.h +++ b/src/thirdparty/ResizableLib/ResizableMsgSupport.h @@ -1,104 +1,104 @@ -// ResizableMsgSupport.h: some declarations to support custom resizable wnds -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_) -#define AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -typedef struct tagRESIZEPROPERTIES -{ - // whether to ask for resizing properties every time - BOOL bAskClipping; - BOOL bAskRefresh; - // otherwise, use the cached properties - BOOL bCachedLikesClipping; - BOOL bCachedNeedsRefresh; - - // initialize with valid data - tagRESIZEPROPERTIES() : bAskClipping(TRUE), bAskRefresh(TRUE), bCachedLikesClipping(FALSE), bCachedNeedsRefresh(TRUE) {} - -} RESIZEPROPERTIES, *PRESIZEPROPERTIES, *LPRESIZEPROPERTIES; - - -typedef struct tagCLIPPINGPROPERTY -{ - BOOL bLikesClipping; - - // initialize with valid data - tagCLIPPINGPROPERTY() : bLikesClipping(FALSE) {} - -} CLIPPINGPROPERTY, *PCLIPPINGPROPERTY, *LPCLIPPINGPROPERTY; - - -typedef struct tagREFRESHPROPERTY -{ - BOOL bNeedsRefresh; - RECT rcOld; - RECT rcNew; - - // initialize with valid data - tagREFRESHPROPERTY() : bNeedsRefresh(TRUE), rcOld(), rcNew() {} - -} REFRESHPROPERTY, *PREFRESHPROPERTY, *LPREFRESHPROPERTY; - - -// registered message to communicate with the library -extern const UINT WMU_RESIZESUPPORT; - -// if the message is implemented the returned value must be non-zero -// the default window procedure returns zero for unhandled messages - -// wParam is one of the following RSZSUP_* values, lParam as specified -enum ResizeSupport -{ - RSZSUP_QUERYPROPERTIES = 101, // lParam = LPRESIZEPROPERTIES - RSZSUP_LIKESCLIPPING = 102, // lParam = LPCLIPPINGPROPERTY - RSZSUP_NEEDSREFRESH = 103, // lParam = LPREFRESHPROPERTY - RSZSUP_SHEETPAGEEXHACK = 104, // lParam = HWND (source prop.page) -}; - -///////////////////////////////////////////////////////////////////////////// -// utility functions - -inline BOOL Send_QueryProperties(HWND hWnd, LPRESIZEPROPERTIES pResizeProperties) -{ - return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, - RSZSUP_QUERYPROPERTIES, (LPARAM)pResizeProperties)); -} - -inline BOOL Send_LikesClipping(HWND hWnd, LPCLIPPINGPROPERTY pClippingProperty) -{ - return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, - RSZSUP_LIKESCLIPPING, (LPARAM)pClippingProperty)); -} - -inline BOOL Send_NeedsRefresh(HWND hWnd, LPREFRESHPROPERTY pRefreshProperty) -{ - return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, - RSZSUP_NEEDSREFRESH, (LPARAM)pRefreshProperty)); -} - -inline void Post_SheetPageExHack(HWND hWndSheet, HWND hWndPage) -{ - PostMessage(hWndSheet, WMU_RESIZESUPPORT, - RSZSUP_SHEETPAGEEXHACK, (LPARAM)hWndPage); -} - -#endif // !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_) +// ResizableMsgSupport.h: some declarations to support custom resizable wnds +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_) +#define AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +typedef struct tagRESIZEPROPERTIES +{ + // whether to ask for resizing properties every time + BOOL bAskClipping; + BOOL bAskRefresh; + // otherwise, use the cached properties + BOOL bCachedLikesClipping; + BOOL bCachedNeedsRefresh; + + // initialize with valid data + tagRESIZEPROPERTIES() : bAskClipping(TRUE), bAskRefresh(TRUE), bCachedLikesClipping(FALSE), bCachedNeedsRefresh(TRUE) {} + +} RESIZEPROPERTIES, *PRESIZEPROPERTIES, *LPRESIZEPROPERTIES; + + +typedef struct tagCLIPPINGPROPERTY +{ + BOOL bLikesClipping; + + // initialize with valid data + tagCLIPPINGPROPERTY() : bLikesClipping(FALSE) {} + +} CLIPPINGPROPERTY, *PCLIPPINGPROPERTY, *LPCLIPPINGPROPERTY; + + +typedef struct tagREFRESHPROPERTY +{ + BOOL bNeedsRefresh; + RECT rcOld; + RECT rcNew; + + // initialize with valid data + tagREFRESHPROPERTY() : bNeedsRefresh(TRUE), rcOld(), rcNew() {} + +} REFRESHPROPERTY, *PREFRESHPROPERTY, *LPREFRESHPROPERTY; + + +// registered message to communicate with the library +extern const UINT WMU_RESIZESUPPORT; + +// if the message is implemented the returned value must be non-zero +// the default window procedure returns zero for unhandled messages + +// wParam is one of the following RSZSUP_* values, lParam as specified +enum ResizeSupport +{ + RSZSUP_QUERYPROPERTIES = 101, // lParam = LPRESIZEPROPERTIES + RSZSUP_LIKESCLIPPING = 102, // lParam = LPCLIPPINGPROPERTY + RSZSUP_NEEDSREFRESH = 103, // lParam = LPREFRESHPROPERTY + RSZSUP_SHEETPAGEEXHACK = 104, // lParam = HWND (source prop.page) +}; + +///////////////////////////////////////////////////////////////////////////// +// utility functions + +inline BOOL Send_QueryProperties(HWND hWnd, LPRESIZEPROPERTIES pResizeProperties) +{ + return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, + RSZSUP_QUERYPROPERTIES, (LPARAM)pResizeProperties)); +} + +inline BOOL Send_LikesClipping(HWND hWnd, LPCLIPPINGPROPERTY pClippingProperty) +{ + return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, + RSZSUP_LIKESCLIPPING, (LPARAM)pClippingProperty)); +} + +inline BOOL Send_NeedsRefresh(HWND hWnd, LPREFRESHPROPERTY pRefreshProperty) +{ + return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT, + RSZSUP_NEEDSREFRESH, (LPARAM)pRefreshProperty)); +} + +inline void Post_SheetPageExHack(HWND hWndSheet, HWND hWndPage) +{ + PostMessage(hWndSheet, WMU_RESIZESUPPORT, + RSZSUP_SHEETPAGEEXHACK, (LPARAM)hWndPage); +} + +#endif // !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizablePage.cpp b/src/thirdparty/ResizableLib/ResizablePage.cpp index 3fcb4027464..9fd5932ee19 100644 --- a/src/thirdparty/ResizableLib/ResizablePage.cpp +++ b/src/thirdparty/ResizableLib/ResizablePage.cpp @@ -1,119 +1,119 @@ -// ResizablePage.cpp : implementation file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "ResizablePage.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CResizablePage - -IMPLEMENT_DYNCREATE(CResizablePage, CPropertyPage) - -CResizablePage::CResizablePage() -{ -} - -CResizablePage::CResizablePage(UINT nIDTemplate, UINT nIDCaption) - : CPropertyPage(nIDTemplate, nIDCaption) -{ -} - -CResizablePage::CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption) - : CPropertyPage(lpszTemplateName, nIDCaption) -{ -} - -CResizablePage::~CResizablePage() -{ -} - - -BEGIN_MESSAGE_MAP(CResizablePage, CPropertyPage) - //{{AFX_MSG_MAP(CResizablePage) - ON_WM_SIZE() - ON_WM_ERASEBKGND() - ON_WM_GETMINMAXINFO() - ON_WM_DESTROY() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - - -///////////////////////////////////////////////////////////////////////////// -// CResizablePage message handlers - -void CResizablePage::OnSize(UINT nType, int cx, int cy) -{ - CWnd::OnSize(nType, cx, cy); - - ArrangeLayout(); -} - -BOOL CResizablePage::OnEraseBkgnd(CDC* pDC) -{ - ClipChildren(pDC, FALSE); - - BOOL bRet = CPropertyPage::OnEraseBkgnd(pDC); - - ClipChildren(pDC, TRUE); - - return bRet; -} - -void CResizablePage::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) -{ - MinMaxInfo(lpMMI); -} - -BOOL CResizablePage::OnInitDialog() -{ - CPropertyPage::OnInitDialog(); - - // set the initial size as the min track size - CRect rc; - GetWindowRect(&rc); - SetMinTrackSize(rc.Size()); - - return TRUE; // return TRUE unless you set the focus to a control - // EXCEPTION: OCX Property Pages should return FALSE -} - -void CResizablePage::OnDestroy() -{ - // remove child windows - RemoveAllAnchors(); - ResetAllRects(); - - CPropertyPage::OnDestroy(); -} - -LRESULT CResizablePage::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message != WM_NCCALCSIZE || wParam == 0) - return CPropertyPage::WindowProc(message, wParam, lParam); - - LRESULT lResult = 0; - HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - lResult = CPropertyPage::WindowProc(message, wParam, lParam); - HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - return lResult; -} +// ResizablePage.cpp : implementation file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ResizablePage.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CResizablePage + +IMPLEMENT_DYNCREATE(CResizablePage, CPropertyPage) + +CResizablePage::CResizablePage() +{ +} + +CResizablePage::CResizablePage(UINT nIDTemplate, UINT nIDCaption) + : CPropertyPage(nIDTemplate, nIDCaption) +{ +} + +CResizablePage::CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption) + : CPropertyPage(lpszTemplateName, nIDCaption) +{ +} + +CResizablePage::~CResizablePage() +{ +} + + +BEGIN_MESSAGE_MAP(CResizablePage, CPropertyPage) + //{{AFX_MSG_MAP(CResizablePage) + ON_WM_SIZE() + ON_WM_ERASEBKGND() + ON_WM_GETMINMAXINFO() + ON_WM_DESTROY() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CResizablePage message handlers + +void CResizablePage::OnSize(UINT nType, int cx, int cy) +{ + CWnd::OnSize(nType, cx, cy); + + ArrangeLayout(); +} + +BOOL CResizablePage::OnEraseBkgnd(CDC* pDC) +{ + ClipChildren(pDC, FALSE); + + BOOL bRet = CPropertyPage::OnEraseBkgnd(pDC); + + ClipChildren(pDC, TRUE); + + return bRet; +} + +void CResizablePage::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + MinMaxInfo(lpMMI); +} + +BOOL CResizablePage::OnInitDialog() +{ + CPropertyPage::OnInitDialog(); + + // set the initial size as the min track size + CRect rc; + GetWindowRect(&rc); + SetMinTrackSize(rc.Size()); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CResizablePage::OnDestroy() +{ + // remove child windows + RemoveAllAnchors(); + ResetAllRects(); + + CPropertyPage::OnDestroy(); +} + +LRESULT CResizablePage::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message != WM_NCCALCSIZE || wParam == 0) + return CPropertyPage::WindowProc(message, wParam, lParam); + + LRESULT lResult = 0; + HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + lResult = CPropertyPage::WindowProc(message, wParam, lParam); + HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + return lResult; +} diff --git a/src/thirdparty/ResizableLib/ResizablePage.h b/src/thirdparty/ResizableLib/ResizablePage.h index 0a950e0f528..e2133b2ef75 100644 --- a/src/thirdparty/ResizableLib/ResizablePage.h +++ b/src/thirdparty/ResizableLib/ResizablePage.h @@ -1,82 +1,82 @@ -#if !defined(AFX_RESIZABLEPAGE_H__INCLUDED_) -#define AFX_RESIZABLEPAGE_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -// ResizablePage.h : header file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "ResizableLayout.h" -#include "ResizableMinMax.h" - -///////////////////////////////////////////////////////////////////////////// -// CResizablePage window - -class CResizablePage : public CPropertyPage, public CResizableLayout, - public CResizableMinMax -{ - DECLARE_DYNCREATE(CResizablePage) - -// Construction -public: - CResizablePage(); - explicit CResizablePage(UINT nIDTemplate, UINT nIDCaption = 0); - explicit CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption = 0); - -// Attributes - -// Operations - -// Overrides - virtual BOOL OnInitDialog(); - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CResizablePage) -protected: - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CResizablePage(); - -// callable from derived classes -protected: - - virtual CWnd* GetResizableWnd() const - { - // make the layout know its parent window - return CWnd::FromHandle(m_hWnd); - }; - -// Generated message map functions - //{{AFX_MSG(CResizablePage) - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); - afx_msg void OnDestroy(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_RESIZABLEPAGE_H__INCLUDED_) +#if !defined(AFX_RESIZABLEPAGE_H__INCLUDED_) +#define AFX_RESIZABLEPAGE_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// ResizablePage.h : header file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "ResizableLayout.h" +#include "ResizableMinMax.h" + +///////////////////////////////////////////////////////////////////////////// +// CResizablePage window + +class CResizablePage : public CPropertyPage, public CResizableLayout, + public CResizableMinMax +{ + DECLARE_DYNCREATE(CResizablePage) + +// Construction +public: + CResizablePage(); + explicit CResizablePage(UINT nIDTemplate, UINT nIDCaption = 0); + explicit CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption = 0); + +// Attributes + +// Operations + +// Overrides + virtual BOOL OnInitDialog(); + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CResizablePage) +protected: + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CResizablePage(); + +// callable from derived classes +protected: + + virtual CWnd* GetResizableWnd() const + { + // make the layout know its parent window + return CWnd::FromHandle(m_hWnd); + }; + +// Generated message map functions + //{{AFX_MSG(CResizablePage) + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnDestroy(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_RESIZABLEPAGE_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/ResizableSheet.cpp b/src/thirdparty/ResizableLib/ResizableSheet.cpp index 686cb96cca0..d897101a60a 100644 --- a/src/thirdparty/ResizableLib/ResizableSheet.cpp +++ b/src/thirdparty/ResizableLib/ResizableSheet.cpp @@ -1,476 +1,476 @@ -// ResizableSheet.cpp : implementation file -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "ResizableSheet.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -///////////////////////////////////////////////////////////////////////////// -// CResizableSheet - -IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet) - -inline void CResizableSheet::PrivateConstruct() -{ - m_bEnableSaveRestore = FALSE; - m_bSavePage = FALSE; - m_dwGripTempState = 1; - m_bLayoutDone = FALSE; - m_bRectOnly = FALSE; - m_nCallbackID = 0; -} - -inline BOOL CResizableSheet::IsWizard() const -{ - return (m_psh.dwFlags & PSH_WIZARD); -} - -CResizableSheet::CResizableSheet() -{ - PrivateConstruct(); -} - -CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage) - : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) -{ - PrivateConstruct(); -} - -CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage) - : CPropertySheet(pszCaption, pParentWnd, iSelectPage) -{ - PrivateConstruct(); -} - -CResizableSheet::~CResizableSheet() -{ -} - -BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet) - //{{AFX_MSG_MAP(CResizableSheet) - ON_WM_GETMINMAXINFO() - ON_WM_SIZE() - ON_WM_DESTROY() - ON_WM_ERASEBKGND() - ON_WM_NCCREATE() - //}}AFX_MSG_MAP - ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////////// -// CResizableSheet message handlers - -BOOL CResizableSheet::OnNcCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (!CPropertySheet::OnNcCreate(lpCreateStruct)) - return FALSE; - - // child dialogs don't want resizable border or size grip, - // nor they can handle the min/max size constraints - BOOL bChild = lpCreateStruct->style & WS_CHILD; - - // create and init the size-grip - if (!CreateSizeGrip(!bChild)) - return FALSE; - - MakeResizable(lpCreateStruct); - - return TRUE; -} - -BOOL CResizableSheet::OnInitDialog() -{ - BOOL bResult = CPropertySheet::OnInitDialog(); - - // initialize layout - PresetLayout(); - m_bLayoutDone = TRUE; - - return bResult; -} - -void CResizableSheet::OnDestroy() -{ - if (m_bEnableSaveRestore) - { - SaveWindowRect(m_sSection, m_bRectOnly); - if (m_bSavePage) - SavePage(m_sSection); - } - - // reset instance data - RemoveAllAnchors(); - ResetAllRects(); - PrivateConstruct(); - - CPropertySheet::OnDestroy(); -} - -// maps an index to a button ID and vice-versa -static UINT _propButtons[] = -{ - IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP, - ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH -}; -const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT); - -// horizontal line in wizard mode -#define ID_WIZLINE ID_WIZFINISH+1 - -void CResizableSheet::PresetLayout() -{ - // set the initial size as the min track size - CRect rc; - GetWindowRect(&rc); - SetMinTrackSize(rc.Size()); - - // use *total* parent size to have correct margins - CRect rectPage, rectSheet; - GetTotalClientRect(&rectSheet); - - // get page area - if (IsWizard()) - { - HWND hPage = PropSheet_GetCurrentPageHwnd(m_hWnd); - ::GetWindowRect(hPage, &rectPage); - } - else - { - GetTabControl()->GetWindowRect(&rectPage); - } - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2); - - // calculate margins - CRect rect; - int cxDiff = rectSheet.right - rectPage.right; - int cyDiff = 0; - - // try all possible buttons - for (int i = 0; i < _propButtonsCount; i++) - { - CWnd* pWnd = GetDlgItem(_propButtons[i]); - if (NULL != pWnd) - { - // move buttons if necessary - if (GetStyle() & WS_CHILD) - { - pWnd->GetWindowRect(&rect); - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rect, 2); - - cyDiff = rectSheet.bottom - rect.bottom; - rect.OffsetRect(cxDiff, cyDiff); - - pWnd->MoveWindow(&rect); - } - // add buttons to the layout manager - AddAnchor(_propButtons[i], BOTTOM_RIGHT); - } - } - - // setup pages area - if (IsWizard()) - { - // move line and pages if necessary - if (GetStyle() & WS_CHILD) - { - GetDlgItem(ID_WIZLINE)->GetWindowRect(&rect); - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rect, 2); - - rect.OffsetRect(0, cyDiff); - rect.InflateRect(cxDiff, 0); - - GetDlgItem(ID_WIZLINE)->MoveWindow(&rect); - - rectPage.bottom += cyDiff; - rectPage.left = 0; - rectPage.top = 0; - rectPage.right = rectSheet.right; - } - - AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT); - - // hide tab control - GetTabControl()->ShowWindow(SW_HIDE); - - // pre-calculate margins - m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft(); - m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight(); - } - else - { - // grow tab to the available sheet space - if (cyDiff > 0) - rectSheet.bottom = rectPage.bottom + cyDiff; - - if (GetStyle() & WS_CHILD) - GetTabControl()->MoveWindow(&rectSheet); - - AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT); - } - - // add a callback for active page (which can change at run-time) - m_nCallbackID = AddAnchorCallback(); - - // prevent flickering - GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS); -} - -BOOL CResizableSheet::ArrangeLayoutCallback(LAYOUTINFO &layout) const -{ - if (layout.nCallbackID != m_nCallbackID) // we only added 1 callback - return CResizableLayout::ArrangeLayoutCallback(layout); - - // set layout info for active page - layout.hWnd = PropSheet_GetCurrentPageHwnd(m_hWnd); - if (!::IsWindow(layout.hWnd)) - return FALSE; - - // set margins - if (IsWizard()) // wizard mode - { - // use pre-calculated margins - layout.marginTopLeft = m_sizePageTL; - layout.marginBottomRight = m_sizePageBR; - } - else // tab mode - { - CTabCtrl* pTab = GetTabControl(); - ASSERT(pTab != NULL); - - // get tab position after resizing and calc page rect - CRect rectPage, rectSheet; - GetTotalClientRect(&rectSheet); - - if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)) - return FALSE; // no page yet - - // calculate page size/position from tab rect - AdjustTabRects(rectPage); - - // set margins - layout.marginTopLeft = rectPage.TopLeft() - rectSheet.TopLeft(); - layout.marginBottomRight = rectPage.BottomRight() - rectSheet.BottomRight(); - } - - // set anchor types - layout.anchorTopLeft = TOP_LEFT; - layout.anchorBottomRight = BOTTOM_RIGHT; - - // use this layout info - return TRUE; -} - -void CResizableSheet::OnSize(UINT nType, int cx, int cy) -{ - CWnd::OnSize(nType, cx, cy); - - if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) - return; // arrangement not needed - - if (nType == SIZE_MAXIMIZED) - HideSizeGrip(&m_dwGripTempState); - else - ShowSizeGrip(&m_dwGripTempState); - - // update grip and layout - UpdateSizeGrip(); - ArrangeLayout(); -} - -BOOL CResizableSheet::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/) -{ - // update new wizard page - // active page changes after this notification - PostMessage(WM_SIZE); - - return FALSE; // continue routing -} - -BOOL CResizableSheet::OnEraseBkgnd(CDC* pDC) -{ - ClipChildren(pDC, FALSE); - - BOOL bRet = CPropertySheet::OnEraseBkgnd(pDC); - - ClipChildren(pDC, TRUE); - - return bRet; -} - -BOOL CResizableSheet::CalcSizeExtra(HWND /*hWndChild*/, const CSize& sizeChild, CSize& sizeExtra) -{ - CTabCtrl* pTab = GetTabControl(); - if (!pTab) - return FALSE; - - // get margins of tabcontrol - CRect rectMargins; - if (!GetAnchorMargins(pTab->m_hWnd, sizeChild, rectMargins)) - return FALSE; - - // get tab position after resizing and calc page rect - CRect rectPage, rectSheet; - GetTotalClientRect(&rectSheet); - - if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)) - return FALSE; // no page yet - - // calculate tab margins - CRect rectTabMargins = AdjustTabRects(rectPage); - - // add non-client size - const DWORD dwStyle = GetStyle(); - ::AdjustWindowRectEx(&rectTabMargins, dwStyle, !(dwStyle & WS_CHILD) && - ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle()); - // compute extra size - sizeExtra = rectMargins.TopLeft() + rectMargins.BottomRight() + - rectTabMargins.Size(); - return TRUE; -} - -CRect CResizableSheet::AdjustTabRects(CRect &rectPage) const -{ - CTabCtrl* pTab = GetTabControl(); - CRect rectTabMargins; - if (m_rectLastPage == rectPage) - { - // use cached rects to avoid flickering while moving the window - rectPage = m_rectLastAjustedPage; - rectTabMargins = m_rectLastTabMargins; - } - else - { - m_rectLastPage = rectPage; - - // temporarily resize the tab control to calc page size - CRect rectSave; - pTab->GetWindowRect(rectSave); - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2); - pTab->SetRedraw(FALSE); - pTab->MoveWindow(rectPage, FALSE); - pTab->AdjustRect(FALSE, &rectPage); - pTab->AdjustRect(TRUE, &rectTabMargins); - pTab->MoveWindow(rectSave, FALSE); - pTab->SetRedraw(TRUE); - - m_rectLastAjustedPage = rectPage; - m_rectLastTabMargins = rectTabMargins; - } - return rectTabMargins; -} - -void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) -{ - MinMaxInfo(lpMMI); - - if (!GetTabControl()) - return; - - int idx = GetPageCount(); - if (IsWizard()) // wizard mode - { - CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR)); - const DWORD dwStyle = GetStyle(); - ::AdjustWindowRectEx(&rectExtra, dwStyle, !(dwStyle & WS_CHILD) && - ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle()); - while (--idx >= 0) - ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size()); - } - else // tab mode - { - while (--idx >= 0) - ChainMinMaxInfoCB(lpMMI, *GetPage(idx)); - } -} - -// protected members - -int CResizableSheet::GetMinWidth() -{ - CRect rectWnd, rectSheet; - GetTotalClientRect(&rectSheet); - - int max = 0, min = rectSheet.Width(); - // search for leftmost and rightmost button margins - for (int i = 0; i < 7; ++i) - { - const CWnd* pWnd = GetDlgItem(_propButtons[i]); - // exclude not present or hidden buttons - if (pWnd != NULL && (pWnd->GetStyle() & WS_VISIBLE)) - { - // left position is relative to the right border - // of the parent window (negative value) - pWnd->GetWindowRect(&rectWnd); - ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2); - const int left = rectSheet.right - rectWnd.left; - const int right = rectSheet.right - rectWnd.right; - - if (left > max) - max = left; - if (right < min) - min = right; - } - } - - // sizing border width - const int border = GetSystemMetrics(SM_CXSIZEFRAME); - - // compute total width - return max + min + 2*border; -} - - -// NOTE: this must be called after all the other settings -// to have the window and its controls displayed properly -void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage) -{ - m_sSection = pszSection; - m_bSavePage = bWithPage; - - m_bEnableSaveRestore = TRUE; - m_bRectOnly = bRectOnly; - - // restore immediately - LoadWindowRect(pszSection, bRectOnly); - { - LoadPage(pszSection); - ArrangeLayout(); // needs refresh - } -} - -void CResizableSheet::RefreshLayout() -{ - SendMessage(WM_SIZE); -} - -LRESULT CResizableSheet::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message != WM_NCCALCSIZE || wParam == 0 || !m_bLayoutDone) - return CPropertySheet::WindowProc(message, wParam, lParam); - - // specifying valid rects needs controls already anchored - LRESULT lResult = 0; - HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - lResult = CPropertySheet::WindowProc(message, wParam, lParam); - HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); - return lResult; -} +// ResizableSheet.cpp : implementation file +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "ResizableSheet.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CResizableSheet + +IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet) + +inline void CResizableSheet::PrivateConstruct() +{ + m_bEnableSaveRestore = FALSE; + m_bSavePage = FALSE; + m_dwGripTempState = 1; + m_bLayoutDone = FALSE; + m_bRectOnly = FALSE; + m_nCallbackID = 0; +} + +inline BOOL CResizableSheet::IsWizard() const +{ + return (m_psh.dwFlags & PSH_WIZARD); +} + +CResizableSheet::CResizableSheet() +{ + PrivateConstruct(); +} + +CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage) + : CPropertySheet(nIDCaption, pParentWnd, iSelectPage) +{ + PrivateConstruct(); +} + +CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage) + : CPropertySheet(pszCaption, pParentWnd, iSelectPage) +{ + PrivateConstruct(); +} + +CResizableSheet::~CResizableSheet() +{ +} + +BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet) + //{{AFX_MSG_MAP(CResizableSheet) + ON_WM_GETMINMAXINFO() + ON_WM_SIZE() + ON_WM_DESTROY() + ON_WM_ERASEBKGND() + ON_WM_NCCREATE() + //}}AFX_MSG_MAP + ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CResizableSheet message handlers + +BOOL CResizableSheet::OnNcCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (!CPropertySheet::OnNcCreate(lpCreateStruct)) + return FALSE; + + // child dialogs don't want resizable border or size grip, + // nor they can handle the min/max size constraints + BOOL bChild = lpCreateStruct->style & WS_CHILD; + + // create and init the size-grip + if (!CreateSizeGrip(!bChild)) + return FALSE; + + MakeResizable(lpCreateStruct); + + return TRUE; +} + +BOOL CResizableSheet::OnInitDialog() +{ + BOOL bResult = CPropertySheet::OnInitDialog(); + + // initialize layout + PresetLayout(); + m_bLayoutDone = TRUE; + + return bResult; +} + +void CResizableSheet::OnDestroy() +{ + if (m_bEnableSaveRestore) + { + SaveWindowRect(m_sSection, m_bRectOnly); + if (m_bSavePage) + SavePage(m_sSection); + } + + // reset instance data + RemoveAllAnchors(); + ResetAllRects(); + PrivateConstruct(); + + CPropertySheet::OnDestroy(); +} + +// maps an index to a button ID and vice-versa +static UINT _propButtons[] = +{ + IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP, + ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH +}; +const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT); + +// horizontal line in wizard mode +#define ID_WIZLINE ID_WIZFINISH+1 + +void CResizableSheet::PresetLayout() +{ + // set the initial size as the min track size + CRect rc; + GetWindowRect(&rc); + SetMinTrackSize(rc.Size()); + + // use *total* parent size to have correct margins + CRect rectPage, rectSheet; + GetTotalClientRect(&rectSheet); + + // get page area + if (IsWizard()) + { + HWND hPage = PropSheet_GetCurrentPageHwnd(m_hWnd); + ::GetWindowRect(hPage, &rectPage); + } + else + { + GetTabControl()->GetWindowRect(&rectPage); + } + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2); + + // calculate margins + CRect rect; + int cxDiff = rectSheet.right - rectPage.right; + int cyDiff = 0; + + // try all possible buttons + for (int i = 0; i < _propButtonsCount; i++) + { + CWnd* pWnd = GetDlgItem(_propButtons[i]); + if (NULL != pWnd) + { + // move buttons if necessary + if (GetStyle() & WS_CHILD) + { + pWnd->GetWindowRect(&rect); + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rect, 2); + + cyDiff = rectSheet.bottom - rect.bottom; + rect.OffsetRect(cxDiff, cyDiff); + + pWnd->MoveWindow(&rect); + } + // add buttons to the layout manager + AddAnchor(_propButtons[i], BOTTOM_RIGHT); + } + } + + // setup pages area + if (IsWizard()) + { + // move line and pages if necessary + if (GetStyle() & WS_CHILD) + { + GetDlgItem(ID_WIZLINE)->GetWindowRect(&rect); + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rect, 2); + + rect.OffsetRect(0, cyDiff); + rect.InflateRect(cxDiff, 0); + + GetDlgItem(ID_WIZLINE)->MoveWindow(&rect); + + rectPage.bottom += cyDiff; + rectPage.left = 0; + rectPage.top = 0; + rectPage.right = rectSheet.right; + } + + AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT); + + // hide tab control + GetTabControl()->ShowWindow(SW_HIDE); + + // pre-calculate margins + m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft(); + m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight(); + } + else + { + // grow tab to the available sheet space + if (cyDiff > 0) + rectSheet.bottom = rectPage.bottom + cyDiff; + + if (GetStyle() & WS_CHILD) + GetTabControl()->MoveWindow(&rectSheet); + + AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT); + } + + // add a callback for active page (which can change at run-time) + m_nCallbackID = AddAnchorCallback(); + + // prevent flickering + GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS); +} + +BOOL CResizableSheet::ArrangeLayoutCallback(LAYOUTINFO &layout) const +{ + if (layout.nCallbackID != m_nCallbackID) // we only added 1 callback + return CResizableLayout::ArrangeLayoutCallback(layout); + + // set layout info for active page + layout.hWnd = PropSheet_GetCurrentPageHwnd(m_hWnd); + if (!::IsWindow(layout.hWnd)) + return FALSE; + + // set margins + if (IsWizard()) // wizard mode + { + // use pre-calculated margins + layout.marginTopLeft = m_sizePageTL; + layout.marginBottomRight = m_sizePageBR; + } + else // tab mode + { + CTabCtrl* pTab = GetTabControl(); + ASSERT(pTab != NULL); + + // get tab position after resizing and calc page rect + CRect rectPage, rectSheet; + GetTotalClientRect(&rectSheet); + + if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)) + return FALSE; // no page yet + + // calculate page size/position from tab rect + AdjustTabRects(rectPage); + + // set margins + layout.marginTopLeft = rectPage.TopLeft() - rectSheet.TopLeft(); + layout.marginBottomRight = rectPage.BottomRight() - rectSheet.BottomRight(); + } + + // set anchor types + layout.anchorTopLeft = TOP_LEFT; + layout.anchorBottomRight = BOTTOM_RIGHT; + + // use this layout info + return TRUE; +} + +void CResizableSheet::OnSize(UINT nType, int cx, int cy) +{ + CWnd::OnSize(nType, cx, cy); + + if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW) + return; // arrangement not needed + + if (nType == SIZE_MAXIMIZED) + HideSizeGrip(&m_dwGripTempState); + else + ShowSizeGrip(&m_dwGripTempState); + + // update grip and layout + UpdateSizeGrip(); + ArrangeLayout(); +} + +BOOL CResizableSheet::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/) +{ + // update new wizard page + // active page changes after this notification + PostMessage(WM_SIZE); + + return FALSE; // continue routing +} + +BOOL CResizableSheet::OnEraseBkgnd(CDC* pDC) +{ + ClipChildren(pDC, FALSE); + + BOOL bRet = CPropertySheet::OnEraseBkgnd(pDC); + + ClipChildren(pDC, TRUE); + + return bRet; +} + +BOOL CResizableSheet::CalcSizeExtra(HWND /*hWndChild*/, const CSize& sizeChild, CSize& sizeExtra) +{ + CTabCtrl* pTab = GetTabControl(); + if (!pTab) + return FALSE; + + // get margins of tabcontrol + CRect rectMargins; + if (!GetAnchorMargins(pTab->m_hWnd, sizeChild, rectMargins)) + return FALSE; + + // get tab position after resizing and calc page rect + CRect rectPage, rectSheet; + GetTotalClientRect(&rectSheet); + + if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage)) + return FALSE; // no page yet + + // calculate tab margins + CRect rectTabMargins = AdjustTabRects(rectPage); + + // add non-client size + const DWORD dwStyle = GetStyle(); + ::AdjustWindowRectEx(&rectTabMargins, dwStyle, !(dwStyle & WS_CHILD) && + ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle()); + // compute extra size + sizeExtra = rectMargins.TopLeft() + rectMargins.BottomRight() + + rectTabMargins.Size(); + return TRUE; +} + +CRect CResizableSheet::AdjustTabRects(CRect &rectPage) const +{ + CTabCtrl* pTab = GetTabControl(); + CRect rectTabMargins; + if (m_rectLastPage == rectPage) + { + // use cached rects to avoid flickering while moving the window + rectPage = m_rectLastAjustedPage; + rectTabMargins = m_rectLastTabMargins; + } + else + { + m_rectLastPage = rectPage; + + // temporarily resize the tab control to calc page size + CRect rectSave; + pTab->GetWindowRect(rectSave); + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2); + pTab->SetRedraw(FALSE); + pTab->MoveWindow(rectPage, FALSE); + pTab->AdjustRect(FALSE, &rectPage); + pTab->AdjustRect(TRUE, &rectTabMargins); + pTab->MoveWindow(rectSave, FALSE); + pTab->SetRedraw(TRUE); + + m_rectLastAjustedPage = rectPage; + m_rectLastTabMargins = rectTabMargins; + } + return rectTabMargins; +} + +void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + MinMaxInfo(lpMMI); + + if (!GetTabControl()) + return; + + int idx = GetPageCount(); + if (IsWizard()) // wizard mode + { + CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR)); + const DWORD dwStyle = GetStyle(); + ::AdjustWindowRectEx(&rectExtra, dwStyle, !(dwStyle & WS_CHILD) && + ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle()); + while (--idx >= 0) + ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size()); + } + else // tab mode + { + while (--idx >= 0) + ChainMinMaxInfoCB(lpMMI, *GetPage(idx)); + } +} + +// protected members + +int CResizableSheet::GetMinWidth() +{ + CRect rectWnd, rectSheet; + GetTotalClientRect(&rectSheet); + + int max = 0, min = rectSheet.Width(); + // search for leftmost and rightmost button margins + for (int i = 0; i < 7; ++i) + { + const CWnd* pWnd = GetDlgItem(_propButtons[i]); + // exclude not present or hidden buttons + if (pWnd != NULL && (pWnd->GetStyle() & WS_VISIBLE)) + { + // left position is relative to the right border + // of the parent window (negative value) + pWnd->GetWindowRect(&rectWnd); + ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2); + const int left = rectSheet.right - rectWnd.left; + const int right = rectSheet.right - rectWnd.right; + + if (left > max) + max = left; + if (right < min) + min = right; + } + } + + // sizing border width + const int border = GetSystemMetrics(SM_CXSIZEFRAME); + + // compute total width + return max + min + 2*border; +} + + +// NOTE: this must be called after all the other settings +// to have the window and its controls displayed properly +void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage) +{ + m_sSection = pszSection; + m_bSavePage = bWithPage; + + m_bEnableSaveRestore = TRUE; + m_bRectOnly = bRectOnly; + + // restore immediately + LoadWindowRect(pszSection, bRectOnly); + { + LoadPage(pszSection); + ArrangeLayout(); // needs refresh + } +} + +void CResizableSheet::RefreshLayout() +{ + SendMessage(WM_SIZE); +} + +LRESULT CResizableSheet::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message != WM_NCCALCSIZE || wParam == 0 || !m_bLayoutDone) + return CPropertySheet::WindowProc(message, wParam, lParam); + + // specifying valid rects needs controls already anchored + LRESULT lResult = 0; + HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + lResult = CPropertySheet::WindowProc(message, wParam, lParam); + HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult); + return lResult; +} diff --git a/src/thirdparty/ResizableLib/ResizableSheet.h b/src/thirdparty/ResizableLib/ResizableSheet.h index 4ae64421509..faede2fb6e2 100644 --- a/src/thirdparty/ResizableLib/ResizableSheet.h +++ b/src/thirdparty/ResizableLib/ResizableSheet.h @@ -1,121 +1,121 @@ -#if !defined(AFX_RESIZABLESHEET_H__INCLUDED_) -#define AFX_RESIZABLESHEET_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#include "ResizableLayout.h" -#include "ResizableGrip.h" -#include "ResizableMinMax.h" -#include "ResizableSheetState.h" - -///////////////////////////////////////////////////////////////////////////// -// ResizableSheet.h : header file -// - -class CResizableSheet : public CPropertySheet, public CResizableLayout, - public CResizableGrip, public CResizableMinMax, - public CResizableSheetState -{ - DECLARE_DYNAMIC(CResizableSheet) - -// Construction -public: - CResizableSheet(); - explicit CResizableSheet(UINT nIDCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0); - explicit CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0); - -// Attributes -private: - // support for temporarily hiding the grip - DWORD m_dwGripTempState; - - // flags - BOOL m_bEnableSaveRestore; - BOOL m_bRectOnly; - BOOL m_bSavePage; - - // layout vars - LRESULT m_nCallbackID; - CSize m_sizePageTL, m_sizePageBR; - BOOL m_bLayoutDone; - - // internal status - CString m_sSection; // section name (identifies a parent window) - - // cached tab rects - mutable CRect m_rectLastPage, m_rectLastAjustedPage, m_rectLastTabMargins; - -// Operations -public: - -// Overrides - virtual BOOL OnInitDialog(); - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CResizableSheet) - protected: - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CResizableSheet(); - -// used internally -private: - void PrivateConstruct(); - - BOOL IsWizard() const; - CRect AdjustTabRects(CRect &rectPage) const; - -// callable from derived classes -protected: - void PresetLayout(); - void RefreshLayout(); - - // section to use in app's profile - void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE, - BOOL bWithPage = FALSE); - int GetMinWidth(); // minimum width to display all buttons - - - virtual CWnd* GetResizableWnd() const - { - // make the layout know its parent window - return CWnd::FromHandle(m_hWnd); - }; - -// Generated message map functions -protected: - virtual BOOL CalcSizeExtra(HWND hWndChild, const CSize& sizeChild, CSize& sizeExtra); - virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const; - //{{AFX_MSG(CResizableSheet) - afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg void OnDestroy(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct); - //}}AFX_MSG - afx_msg BOOL OnPageChanging(NMHDR* pNotifyStruct, LRESULT* pResult); - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////////// - -#endif // AFX_RESIZABLESHEET_H__INCLUDED_ +#if !defined(AFX_RESIZABLESHEET_H__INCLUDED_) +#define AFX_RESIZABLESHEET_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#include "ResizableLayout.h" +#include "ResizableGrip.h" +#include "ResizableMinMax.h" +#include "ResizableSheetState.h" + +///////////////////////////////////////////////////////////////////////////// +// ResizableSheet.h : header file +// + +class CResizableSheet : public CPropertySheet, public CResizableLayout, + public CResizableGrip, public CResizableMinMax, + public CResizableSheetState +{ + DECLARE_DYNAMIC(CResizableSheet) + +// Construction +public: + CResizableSheet(); + explicit CResizableSheet(UINT nIDCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0); + explicit CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0); + +// Attributes +private: + // support for temporarily hiding the grip + DWORD m_dwGripTempState; + + // flags + BOOL m_bEnableSaveRestore; + BOOL m_bRectOnly; + BOOL m_bSavePage; + + // layout vars + LRESULT m_nCallbackID; + CSize m_sizePageTL, m_sizePageBR; + BOOL m_bLayoutDone; + + // internal status + CString m_sSection; // section name (identifies a parent window) + + // cached tab rects + mutable CRect m_rectLastPage, m_rectLastAjustedPage, m_rectLastTabMargins; + +// Operations +public: + +// Overrides + virtual BOOL OnInitDialog(); + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CResizableSheet) + protected: + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CResizableSheet(); + +// used internally +private: + void PrivateConstruct(); + + BOOL IsWizard() const; + CRect AdjustTabRects(CRect &rectPage) const; + +// callable from derived classes +protected: + void PresetLayout(); + void RefreshLayout(); + + // section to use in app's profile + void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE, + BOOL bWithPage = FALSE); + int GetMinWidth(); // minimum width to display all buttons + + + virtual CWnd* GetResizableWnd() const + { + // make the layout know its parent window + return CWnd::FromHandle(m_hWnd); + }; + +// Generated message map functions +protected: + virtual BOOL CalcSizeExtra(HWND hWndChild, const CSize& sizeChild, CSize& sizeExtra); + virtual BOOL ArrangeLayoutCallback(LAYOUTINFO& layout) const; + //{{AFX_MSG(CResizableSheet) + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnDestroy(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct); + //}}AFX_MSG + afx_msg BOOL OnPageChanging(NMHDR* pNotifyStruct, LRESULT* pResult); + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +#endif // AFX_RESIZABLESHEET_H__INCLUDED_ diff --git a/src/thirdparty/ResizableLib/ResizableState.cpp b/src/thirdparty/ResizableLib/ResizableState.cpp index b9c4bcde043..f889efdfb28 100644 --- a/src/thirdparty/ResizableLib/ResizableState.cpp +++ b/src/thirdparty/ResizableLib/ResizableState.cpp @@ -1,132 +1,132 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Implementation of the CResizableState class. - */ - -#include "stdafx.h" -#include "ResizableState.h" - -#ifdef _DEBUG -#undef THIS_FILE -static char THIS_FILE[]=__FILE__; -#define new DEBUG_NEW -#endif - -LPCTSTR CResizableState::m_sDefaultStorePath = _T("ResizableState"); - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CResizableState::CResizableState() -{ - m_sStorePath = m_sDefaultStorePath; -} - -CResizableState::~CResizableState() -{ - -} - -/*! - * Static function to set the default path used to store state information. - * This path is used to initialize all the instances of this class. - * @sa GetDefaultStateStore GetStateStore SetStateStore - * - * @param szPath String that specifies the new path to be set - */ -void CResizableState::SetDefaultStateStore(LPCTSTR szPath) -{ - m_sDefaultStorePath = szPath; -} - -/*! - * Static function to retrieve the default path used to store state - * information. - * This path is used to initialize all the instances of this class. - * @sa SetDefaultStateStore GetStateStore SetStateStore - * - * @return The return value is a string that specifies the current path - */ -LPCTSTR CResizableState::GetDefaultStateStore() -{ - return m_sDefaultStorePath; -} - -/*! - * This function sets the path used to store state information by - * the current instance of the class. - * @sa GetStateStore GetDefaultStateStore SetDefaultStateStore - * - * @param szPath String that specifies the new path to be set - */ -void CResizableState::SetStateStore(LPCTSTR szPath) -{ - m_sStorePath = szPath; -} - -/*! - * This function retrieves the path used to store state information by - * the current instance of the class. - * @sa SetStateStore GetDefaultStateStore SetDefaultStateStore - * - * @return The return value is a string that specifies the current path - */ -LPCTSTR CResizableState::GetStateStore() const -{ - return m_sStorePath; -} - -/*! - * This function writes state information and associates it with some - * identification text for later retrieval. - * The base implementation uses the application profile to persist state - * information, but this function can be overridden to implement - * different methods. - * - * @param szId String that identifies the stored settings - * @param szState String that represents the state information to store - * - * @return The return value is @a TRUE if settings have been successfully - * stored, @a FALSE otherwise. - */ -// MPC-HC custom code--adds LPCTSTR szValue -BOOL CResizableState::WriteState(LPCTSTR szId, LPCTSTR szValue, LPCTSTR szState) -{ - return AfxGetApp()->WriteProfileString(szId, szValue, szState); -} - -/*! - * This function reads state information previously associated with some - * identification text. - * The base implementation uses the application profile to persist state - * information, but this function can be overridden to implement - * different methods. - * - * @param szId String that identifies the stored settings - * @param rsState String to be filled with the retrieved state information - * - * @return The return value is @a TRUE if settings have been successfully - * retrieved, @a FALSE otherwise. - */ -// MPC-HC custom code--adds LPCTSTR szValue -BOOL CResizableState::ReadState(LPCTSTR szId, LPCTSTR szValue, CString &rsState) -{ - rsState = AfxGetApp()->GetProfileString(szId, szValue); - return !rsState.IsEmpty(); -} +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Implementation of the CResizableState class. + */ + +#include "stdafx.h" +#include "ResizableState.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +LPCTSTR CResizableState::m_sDefaultStorePath = _T("ResizableState"); + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +CResizableState::CResizableState() +{ + m_sStorePath = m_sDefaultStorePath; +} + +CResizableState::~CResizableState() +{ + +} + +/*! + * Static function to set the default path used to store state information. + * This path is used to initialize all the instances of this class. + * @sa GetDefaultStateStore GetStateStore SetStateStore + * + * @param szPath String that specifies the new path to be set + */ +void CResizableState::SetDefaultStateStore(LPCTSTR szPath) +{ + m_sDefaultStorePath = szPath; +} + +/*! + * Static function to retrieve the default path used to store state + * information. + * This path is used to initialize all the instances of this class. + * @sa SetDefaultStateStore GetStateStore SetStateStore + * + * @return The return value is a string that specifies the current path + */ +LPCTSTR CResizableState::GetDefaultStateStore() +{ + return m_sDefaultStorePath; +} + +/*! + * This function sets the path used to store state information by + * the current instance of the class. + * @sa GetStateStore GetDefaultStateStore SetDefaultStateStore + * + * @param szPath String that specifies the new path to be set + */ +void CResizableState::SetStateStore(LPCTSTR szPath) +{ + m_sStorePath = szPath; +} + +/*! + * This function retrieves the path used to store state information by + * the current instance of the class. + * @sa SetStateStore GetDefaultStateStore SetDefaultStateStore + * + * @return The return value is a string that specifies the current path + */ +LPCTSTR CResizableState::GetStateStore() const +{ + return m_sStorePath; +} + +/*! + * This function writes state information and associates it with some + * identification text for later retrieval. + * The base implementation uses the application profile to persist state + * information, but this function can be overridden to implement + * different methods. + * + * @param szId String that identifies the stored settings + * @param szState String that represents the state information to store + * + * @return The return value is @a TRUE if settings have been successfully + * stored, @a FALSE otherwise. + */ +// MPC-HC custom code--adds LPCTSTR szValue +BOOL CResizableState::WriteState(LPCTSTR szId, LPCTSTR szValue, LPCTSTR szState) +{ + return AfxGetApp()->WriteProfileString(szId, szValue, szState); +} + +/*! + * This function reads state information previously associated with some + * identification text. + * The base implementation uses the application profile to persist state + * information, but this function can be overridden to implement + * different methods. + * + * @param szId String that identifies the stored settings + * @param rsState String to be filled with the retrieved state information + * + * @return The return value is @a TRUE if settings have been successfully + * retrieved, @a FALSE otherwise. + */ +// MPC-HC custom code--adds LPCTSTR szValue +BOOL CResizableState::ReadState(LPCTSTR szId, LPCTSTR szValue, CString &rsState) +{ + rsState = AfxGetApp()->GetProfileString(szId, szValue); + return !rsState.IsEmpty(); +} diff --git a/src/thirdparty/ResizableLib/ResizableState.h b/src/thirdparty/ResizableLib/ResizableState.h index ce08eedb283..ba677feecdd 100644 --- a/src/thirdparty/ResizableLib/ResizableState.h +++ b/src/thirdparty/ResizableLib/ResizableState.h @@ -1,77 +1,77 @@ -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -/*! - * @file - * @brief Interface for the CResizableState class. - */ - -#if !defined(AFX_RESIZABLESTATE_H__INCLUDED_) -#define AFX_RESIZABLESTATE_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -/*! @addtogroup CoreComponents - * @{ - */ - -//! @brief Provides basic persisting capabilities -/*! - * Derive from this class to persist user interface settings, or anything - * suitable. The base implementation uses the application profile, which can - * be set to either the Registry or an INI File. Other storing methods - * can be implemented in derived classes. - */ -class CResizableState -{ - static LPCTSTR m_sDefaultStorePath; - CString m_sStorePath; - -protected: - - //! @brief Get default path where state is stored - static LPCTSTR GetDefaultStateStore(); - - //! @brief Set default path where state is stored - static void SetDefaultStateStore(LPCTSTR szPath); - - //! @brief Get current path where state is stored - LPCTSTR GetStateStore() const; - - //! @brief Set current path where state is stored - void SetStateStore(LPCTSTR szPath); - - //! @name Overridables - //@{ - - //! @brief Read state information - // MPC-HC custom code--adds LPCTSTR szValue - virtual BOOL ReadState(LPCTSTR szId, LPCTSTR szValue, CString& rsState); - - //! @brief Write state information - // MPC-HC custom code--adds LPCTSTR szValue - virtual BOOL WriteState(LPCTSTR szId, LPCTSTR szValue, LPCTSTR szState); - - //@} - -public: - CResizableState(); - virtual ~CResizableState(); -}; - -// @} -#endif // !defined(AFX_RESIZABLESTATE_H__INCLUDED_) +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +/*! + * @file + * @brief Interface for the CResizableState class. + */ + +#if !defined(AFX_RESIZABLESTATE_H__INCLUDED_) +#define AFX_RESIZABLESTATE_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +/*! @addtogroup CoreComponents + * @{ + */ + +//! @brief Provides basic persisting capabilities +/*! + * Derive from this class to persist user interface settings, or anything + * suitable. The base implementation uses the application profile, which can + * be set to either the Registry or an INI File. Other storing methods + * can be implemented in derived classes. + */ +class CResizableState +{ + static LPCTSTR m_sDefaultStorePath; + CString m_sStorePath; + +protected: + + //! @brief Get default path where state is stored + static LPCTSTR GetDefaultStateStore(); + + //! @brief Set default path where state is stored + static void SetDefaultStateStore(LPCTSTR szPath); + + //! @brief Get current path where state is stored + LPCTSTR GetStateStore() const; + + //! @brief Set current path where state is stored + void SetStateStore(LPCTSTR szPath); + + //! @name Overridables + //@{ + + //! @brief Read state information + // MPC-HC custom code--adds LPCTSTR szValue + virtual BOOL ReadState(LPCTSTR szId, LPCTSTR szValue, CString& rsState); + + //! @brief Write state information + // MPC-HC custom code--adds LPCTSTR szValue + virtual BOOL WriteState(LPCTSTR szId, LPCTSTR szValue, LPCTSTR szState); + + //@} + +public: + CResizableState(); + virtual ~CResizableState(); +}; + +// @} +#endif // !defined(AFX_RESIZABLESTATE_H__INCLUDED_) diff --git a/src/thirdparty/ResizableLib/stdafx.cpp b/src/thirdparty/ResizableLib/stdafx.cpp index a7c3002e327..e634be5853e 100644 --- a/src/thirdparty/ResizableLib/stdafx.cpp +++ b/src/thirdparty/ResizableLib/stdafx.cpp @@ -1,6 +1,6 @@ -// stdafx.cpp : source file that includes just the standard includes -// ResizableLib.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - +// stdafx.cpp : source file that includes just the standard includes +// ResizableLib.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + diff --git a/src/thirdparty/ResizableLib/stdafx.h b/src/thirdparty/ResizableLib/stdafx.h index 9636e7a68df..335e0acd646 100644 --- a/src/thirdparty/ResizableLib/stdafx.h +++ b/src/thirdparty/ResizableLib/stdafx.h @@ -1,68 +1,68 @@ -// stdafx.h : include file for standard system include files, or project -// specific include files that are used frequently, but are changed infrequently -// -///////////////////////////////////////////////////////////////////////////// -// -// This file is part of ResizableLib -// https://github.com/ppescher/resizablelib -// -// Copyright (C) 2000-2024 by Paolo Messina -// mailto:ppescher@hotmail.com -// -// The contents of this file are subject to the Artistic License 2.0 -// http://opensource.org/licenses/Artistic-2.0 -// -// If you find this code useful, credits would be nice! -// -///////////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_RESIZABLESTDAFX_H__INCLUDED_) -#define AFX_RESIZABLESTDAFX_H__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -// Set max target Windows platform -#define WINVER 0x0501 -#define _WIN32_WINNT 0x0501 - -// Use target Common Controls version for compatibility -// with CPropertyPageEx, CPropertySheetEx -#define _WIN32_IE 0x0500 - -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -#include // MFC core and standard components -#include // MFC extensions -#include // MFC support for Windows Common Controls -#include // DLL Version support -#if _WIN32_WINNT >= 0x0501 -#include // Windows XP Visual Style API support -#endif - -#ifndef WS_EX_LAYOUTRTL -#pragma message("Please update your Windows header files, get the latest SDK") -#pragma message("WinUser.h is out of date!") - -#define WS_EX_LAYOUTRTL 0x00400000 -#endif - -#ifndef WC_BUTTON -#pragma message("Please update your Windows header files, get the latest SDK") -#pragma message("CommCtrl.h is out of date!") - -#define WC_BUTTON TEXT("Button") -#define WC_STATIC TEXT("Static") -#define WC_EDIT TEXT("Edit") -#define WC_LISTBOX TEXT("ListBox") -#define WC_COMBOBOX TEXT("ComboBox") -#define WC_SCROLLBAR TEXT("ScrollBar") -#endif - -#define RSZLIB_NO_XP_DOUBLE_BUFFER - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_RESIZABLESTDAFX_H__INCLUDED_) +// stdafx.h : include file for standard system include files, or project +// specific include files that are used frequently, but are changed infrequently +// +///////////////////////////////////////////////////////////////////////////// +// +// This file is part of ResizableLib +// https://github.com/ppescher/resizablelib +// +// Copyright (C) 2000-2024 by Paolo Messina +// mailto:ppescher@hotmail.com +// +// The contents of this file are subject to the Artistic License 2.0 +// http://opensource.org/licenses/Artistic-2.0 +// +// If you find this code useful, credits would be nice! +// +///////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_RESIZABLESTDAFX_H__INCLUDED_) +#define AFX_RESIZABLESTDAFX_H__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// Set max target Windows platform +#define WINVER 0x0501 +#define _WIN32_WINNT 0x0501 + +// Use target Common Controls version for compatibility +// with CPropertyPageEx, CPropertySheetEx +#define _WIN32_IE 0x0500 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC core and standard components +#include // MFC extensions +#include // MFC support for Windows Common Controls +#include // DLL Version support +#if _WIN32_WINNT >= 0x0501 +#include // Windows XP Visual Style API support +#endif + +#ifndef WS_EX_LAYOUTRTL +#pragma message("Please update your Windows header files, get the latest SDK") +#pragma message("WinUser.h is out of date!") + +#define WS_EX_LAYOUTRTL 0x00400000 +#endif + +#ifndef WC_BUTTON +#pragma message("Please update your Windows header files, get the latest SDK") +#pragma message("CommCtrl.h is out of date!") + +#define WC_BUTTON TEXT("Button") +#define WC_STATIC TEXT("Static") +#define WC_EDIT TEXT("Edit") +#define WC_LISTBOX TEXT("ListBox") +#define WC_COMBOBOX TEXT("ComboBox") +#define WC_SCROLLBAR TEXT("ScrollBar") +#endif + +#define RSZLIB_NO_XP_DOUBLE_BUFFER + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_RESIZABLESTDAFX_H__INCLUDED_) diff --git a/src/thirdparty/TreePropSheet/PropPageFrame.cpp b/src/thirdparty/TreePropSheet/PropPageFrame.cpp index ee367aeb2a7..37de78ccf2c 100644 --- a/src/thirdparty/TreePropSheet/PropPageFrame.cpp +++ b/src/thirdparty/TreePropSheet/PropPageFrame.cpp @@ -1,187 +1,187 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - -#include "stdafx.h" -#include "PropPageFrame.h" - -namespace TreePropSheet -{ - - -//------------------------------------------------------------------- -// class CPropPageFrame -//------------------------------------------------------------------- - -CPropPageFrame::CPropPageFrame() -: m_bShowCaption(FALSE), - m_nCaptionHeight(0), - m_hCaptionIcon(NULL), - m_dwMsgFormat(DT_CENTER|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE) -{ -} - - -CPropPageFrame::~CPropPageFrame() -{ -} - - -///////////////////////////////////////////////////////////////////// -// Operations - - -void CPropPageFrame::ShowCaption(BOOL bEnable) -{ - m_bShowCaption = bEnable; - SafeUpdateWindow(CalcCaptionArea()); -} - - -BOOL CPropPageFrame::GetShowCaption() const -{ - return m_bShowCaption; -} - - -void CPropPageFrame::SetCaption(LPCTSTR lpszCaption, HICON hIcon /*= NULL*/) -{ - m_strCaption = lpszCaption; - m_hCaptionIcon = hIcon; - SafeUpdateWindow(CalcCaptionArea()); -} - - -CString CPropPageFrame::GetCaption(HICON *pIcon /* = NULL */) const -{ - if (pIcon) - *pIcon = m_hCaptionIcon; - return m_strCaption; -} - - -void CPropPageFrame::SetCaptionHeight(int nCaptionHeight) -{ - m_nCaptionHeight = nCaptionHeight; - SafeUpdateWindow(CalcCaptionArea()); -} - - -int CPropPageFrame::GetCaptionHeight() const -{ - return m_nCaptionHeight; -} - - -void CPropPageFrame::SetMsgText(LPCTSTR lpszMsg) -{ - m_strMsg = lpszMsg; - SafeUpdateWindow(CalcMsgArea()); -} - - -CString CPropPageFrame::GetMsgText() const -{ - return m_strMsg; -} - - -void CPropPageFrame::SetMsgFormat(DWORD dwFormat) -{ - m_dwMsgFormat = dwFormat; - SafeUpdateWindow(CalcMsgArea()); -} - - -DWORD CPropPageFrame::GetMsgFormat() const -{ - return m_dwMsgFormat; -} - - -///////////////////////////////////////////////////////////////////// -// Overridable implementation helpers - -void CPropPageFrame::Draw(CDC *pDc) -{ - if (GetShowCaption()) - DrawCaption(pDc, CalcCaptionArea(), m_strCaption, m_hCaptionIcon); - DrawMsg(pDc, CalcMsgArea(), m_strMsg, m_dwMsgFormat); -} - - -CRect CPropPageFrame::CalcMsgArea() -{ - ASSERT(IsWindow(GetWnd()->GetSafeHwnd())); - - CRect rectMsg; - GetWnd()->GetClientRect(rectMsg); - if (GetShowCaption()) - rectMsg.top+= GetCaptionHeight(); - - return rectMsg; -} - - -void CPropPageFrame::DrawMsg(CDC *pDc, CRect rect, LPCTSTR /*lpszMsg*/, DWORD /*dwFormat*/) -{ - CFont *pPrevFont = dynamic_cast(pDc->SelectStockObject(DEFAULT_GUI_FONT)); - int nPrevBkMode = pDc->SetBkMode(TRANSPARENT); - - pDc->DrawText(GetMsgText(), rect, GetMsgFormat()); - - pDc->SetBkMode(nPrevBkMode); - pDc->SelectObject(pPrevFont); -} - - -CRect CPropPageFrame::CalcCaptionArea() -{ - ASSERT(IsWindow(GetWnd()->GetSafeHwnd())); - - CRect rectCaption; - GetWnd()->GetClientRect(rectCaption); - if (!GetShowCaption()) - rectCaption.bottom = rectCaption.top; - else - rectCaption.bottom = rectCaption.top+GetCaptionHeight(); - - return rectCaption; -} - - -void CPropPageFrame::DrawCaption(CDC* /*pDc*/, CRect /*rect*/, LPCTSTR /*lpszCaption*/, HICON /*hIcon*/) -{ - // should be implemented by specialized classes -} - - -///////////////////////////////////////////////////////////////////// -// Implementation helpers - -void CPropPageFrame::SafeUpdateWindow(LPCRECT lpRect /* = NULL */) -{ - if (!IsWindow(GetWnd()->GetSafeHwnd())) - return; - - GetWnd()->InvalidateRect(lpRect, TRUE); -} - - - -} //namespace TreePropSheet +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + +#include "stdafx.h" +#include "PropPageFrame.h" + +namespace TreePropSheet +{ + + +//------------------------------------------------------------------- +// class CPropPageFrame +//------------------------------------------------------------------- + +CPropPageFrame::CPropPageFrame() +: m_bShowCaption(FALSE), + m_nCaptionHeight(0), + m_hCaptionIcon(NULL), + m_dwMsgFormat(DT_CENTER|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE) +{ +} + + +CPropPageFrame::~CPropPageFrame() +{ +} + + +///////////////////////////////////////////////////////////////////// +// Operations + + +void CPropPageFrame::ShowCaption(BOOL bEnable) +{ + m_bShowCaption = bEnable; + SafeUpdateWindow(CalcCaptionArea()); +} + + +BOOL CPropPageFrame::GetShowCaption() const +{ + return m_bShowCaption; +} + + +void CPropPageFrame::SetCaption(LPCTSTR lpszCaption, HICON hIcon /*= NULL*/) +{ + m_strCaption = lpszCaption; + m_hCaptionIcon = hIcon; + SafeUpdateWindow(CalcCaptionArea()); +} + + +CString CPropPageFrame::GetCaption(HICON *pIcon /* = NULL */) const +{ + if (pIcon) + *pIcon = m_hCaptionIcon; + return m_strCaption; +} + + +void CPropPageFrame::SetCaptionHeight(int nCaptionHeight) +{ + m_nCaptionHeight = nCaptionHeight; + SafeUpdateWindow(CalcCaptionArea()); +} + + +int CPropPageFrame::GetCaptionHeight() const +{ + return m_nCaptionHeight; +} + + +void CPropPageFrame::SetMsgText(LPCTSTR lpszMsg) +{ + m_strMsg = lpszMsg; + SafeUpdateWindow(CalcMsgArea()); +} + + +CString CPropPageFrame::GetMsgText() const +{ + return m_strMsg; +} + + +void CPropPageFrame::SetMsgFormat(DWORD dwFormat) +{ + m_dwMsgFormat = dwFormat; + SafeUpdateWindow(CalcMsgArea()); +} + + +DWORD CPropPageFrame::GetMsgFormat() const +{ + return m_dwMsgFormat; +} + + +///////////////////////////////////////////////////////////////////// +// Overridable implementation helpers + +void CPropPageFrame::Draw(CDC *pDc) +{ + if (GetShowCaption()) + DrawCaption(pDc, CalcCaptionArea(), m_strCaption, m_hCaptionIcon); + DrawMsg(pDc, CalcMsgArea(), m_strMsg, m_dwMsgFormat); +} + + +CRect CPropPageFrame::CalcMsgArea() +{ + ASSERT(IsWindow(GetWnd()->GetSafeHwnd())); + + CRect rectMsg; + GetWnd()->GetClientRect(rectMsg); + if (GetShowCaption()) + rectMsg.top+= GetCaptionHeight(); + + return rectMsg; +} + + +void CPropPageFrame::DrawMsg(CDC *pDc, CRect rect, LPCTSTR /*lpszMsg*/, DWORD /*dwFormat*/) +{ + CFont *pPrevFont = dynamic_cast(pDc->SelectStockObject(DEFAULT_GUI_FONT)); + int nPrevBkMode = pDc->SetBkMode(TRANSPARENT); + + pDc->DrawText(GetMsgText(), rect, GetMsgFormat()); + + pDc->SetBkMode(nPrevBkMode); + pDc->SelectObject(pPrevFont); +} + + +CRect CPropPageFrame::CalcCaptionArea() +{ + ASSERT(IsWindow(GetWnd()->GetSafeHwnd())); + + CRect rectCaption; + GetWnd()->GetClientRect(rectCaption); + if (!GetShowCaption()) + rectCaption.bottom = rectCaption.top; + else + rectCaption.bottom = rectCaption.top+GetCaptionHeight(); + + return rectCaption; +} + + +void CPropPageFrame::DrawCaption(CDC* /*pDc*/, CRect /*rect*/, LPCTSTR /*lpszCaption*/, HICON /*hIcon*/) +{ + // should be implemented by specialized classes +} + + +///////////////////////////////////////////////////////////////////// +// Implementation helpers + +void CPropPageFrame::SafeUpdateWindow(LPCRECT lpRect /* = NULL */) +{ + if (!IsWindow(GetWnd()->GetSafeHwnd())) + return; + + GetWnd()->InvalidateRect(lpRect, TRUE); +} + + + +} //namespace TreePropSheet diff --git a/src/thirdparty/TreePropSheet/PropPageFrame.h b/src/thirdparty/TreePropSheet/PropPageFrame.h index 2de997d72d8..998d30bf4c4 100644 --- a/src/thirdparty/TreePropSheet/PropPageFrame.h +++ b/src/thirdparty/TreePropSheet/PropPageFrame.h @@ -1,306 +1,306 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - - -#if !defined(AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_) -#define AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - - -namespace TreePropSheet -{ - - -/** -An object of an CPropertyPageFrame-derived class is used by -CTreePropSheet to display a frame for the property pages. - -Derived classes have to implement at least the Create() and the -GetWnd() method, which -returns a pointer to the CWnd-obect of the window, that has been -created by the call to the Create() method. An implementation can -provide the CWnd-object by using it as a property or by deriving -from CWnd or a more specialiced class. This way has been choosen -instead of deriving CPropPageFrame from CWnd, to allow derived class -to derive from more specialized classes than CWnd -(i.e. CStatic, etc.). From the WM_PAINT-handler of your derived class -you have to call the Draw()-method. - -Most implementations will also implement the DrawCaption() and -DrawMsg() methods, to provide custom drawing functionality. - -@author Sven Wiegand -*/ -class /*AFX_EXT_CLASS*/ CPropPageFrame -{ -// Construction/Destruction -public: - CPropPageFrame(); - virtual ~CPropPageFrame(); - -// Operations -public: - /** - Has to create a window with the specified properties. - - @param dwWindowStyle - Standard window styles, to apply to the window to create. - @param rect - Position and size of the window to create. - @param pwndParent - Parent window. (Never be NULL). - @param nID - Window id. - - @return - TRUE on success, FALSE otherwise. - */ - virtual BOOL Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID) = 0; - - /** - Returns a pointer to the window object, that represents the frame. - */ - virtual CWnd* GetWnd() = 0; - - /** - Enables or disables page caption. - - This default implementation calls the SafeUpdateWindow() method - with the caption rectangle, to force it to be redrawn. - */ - virtual void ShowCaption(BOOL bEnable); - - /** - Returns TRUE if captions are enabled, FALSE otherwise. - */ - BOOL GetShowCaption() const; - - /** - Sets the height of the caption in pixels. This value is ignored - until the caption is enabled by ShowCaption(TRUE). - - This default implementation calls the SafeUpdateWindow() method - with the caption rectangle, to force it to be redrawn. - */ - virtual void SetCaptionHeight(int nCaptionHeight); - - /** - Returns the caption height, that has been most recently set by a - call to the SetCaptionHeight() method. - */ - int GetCaptionHeight() const; - - /** - Sets caption text an icon. - - This default implementation calls the SafeUpdateWindow() method - with the caption rectangle, to force it to be redrawn. - - @param lpszCaption - Text to display for the caption. - @param hIcon - Icon to display for the caption. - */ - virtual void SetCaption(LPCTSTR lpszCaption, HICON hIcon = NULL); - - /** - Returns the caption, that has been set most recently using the - SetCaption() method. - - @param pIcon - Pointer to a HICON variable, that should receive the handle of - the currently set icon or NULL, if there is no icon or a NULL - pointer, if the caller is not interested in the icon. - - @return - The text that has been set most recently using the SetCaption() - method. - */ - CString GetCaption(HICON *pIcon = NULL) const; - - /** - Sets the text to display. - - This default implementation calls the SafeUpdateWindow() method - with the message rectangle, to force it to be redrawn. - */ - virtual void SetMsgText(LPCTSTR lpszMsg); - - /** - Returns the text currently displayed. - */ - CString GetMsgText() const; - - /** - Specifies the format to draw the text with, set by SetMsgText(). - - This default implementation calls the SafeUpdateWindow() method - with the message rectangle, to force it to be redrawn. - - @param dwFormat - Combination of the DT_* flags, specified by the Win32 function - DrawText(). - */ - virtual void SetMsgFormat(DWORD dwFormat); - - /** - Returns the format to draw the text with, set by SetMsgText(). - - @see SetMsgFormat() - */ - DWORD GetMsgFormat() const; - -// Overridable implementation helpers -protected: - /** - Draws the whole frame including caption (if enabled) and message. - - This method calculates the rectangles for the message area and - the caption area using the CalcMsgArea() and the CalcCaptionArea() - methods, draws then the caption calling the DrawCaption() method - (only if caption is enabled) and afterwards the message calling - the DrawMsg() method. - - You should call this method from the WM_PAINT-handler of your - derived class. - - @param pDc - Device context to draw in. - */ - virtual void Draw(CDC *pDc); - - /** - Calculates the area, the message, set by SetMsgText() should be - displayed in. The returned rectangle (client coordinates) will be - passed to DrawMsg(). - - This default implementation calls the CalcCaptionArea() method, - substracts the returned rectangle from the client area and returns - the result. - */ - virtual CRect CalcMsgArea(); - - /** - Draws the message with the specified format. - - This default implementation draws the given msg using the specified - properties. - - @param pDc - Device context to draw in. - @param rect - Rectangle to draw the message in. - @param lpszMsg - Message to draw. - @param dwFormat. - Combination of the DT_* flags, specified by the Win32 function - DrawText() to draw the message with. - */ - virtual void DrawMsg(CDC *pDc, CRect rect, LPCTSTR lpszMsg, DWORD dwFormat); - - /** - Calculates the caption area. The caption area is the rectangular - range, the current page's caption should be drawn in. - - The caption can be enabled or disabled using the ShowCaption() - method. This method should return an empty rect, if the caption - is disabled. If the caption is enabled the height of the rect - should be as large, as specified by the latest call to the - SetCaptionHeight() method. - - The rectangle, returned by this method will be passed to the - DrawCaption() method to draw the caption. - - If the caption is enabled currently, this default implementation - returns a rectangle, that has the width of the client area and - the height, specified by the latest call to SetCaptionHeight(), - starting and y-position 0. If the caption is disabled at the - moment, this method returns an empty rectangle with the width of - the client area. - */ - virtual CRect CalcCaptionArea(); - - /** - Draws the caption. - - This default implementation draws nothing. - - @param pDc - Device context to draw in. - @param rect - Rectangle to draw the caption in. - @param lpszCaption - Text to display in the caption. - @param hIcon - Icon to display in the caption. - */ - virtual void DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); - -// Implementation helpers -protected: - /** - If the m_hWnd property of the CWnd-object returend by GetWnd() - specifies a valid window, this method will invalidate the specified - rectangle, to schedule it for repaint, otherwise the method will - return without doing anything. - - @param lpRect - Pointer to the rectangular area, that should be marked for - repainting or NULL, if the whole client area should be marked - for repainting. - */ - void SafeUpdateWindow(LPCRECT lpRect = NULL); - -// Properties -private: - /** TRUE if the caption should be drawn, FALSE otherwise. */ - BOOL m_bShowCaption; - - /** Height of the caption in pixels, if it is enabled. */ - int m_nCaptionHeight; - - /** Text to display in the caption. */ - CString m_strCaption; - - /** - Icon to display in the caption or NULL if no icon should be - displayed. - */ - HICON m_hCaptionIcon; - - /** Message text to display. */ - CString m_strMsg; - - /** Style to use when drawing the message text m_strMsg. */ - DWORD m_dwMsgFormat; -}; - - -} //namespace TreePropSheet - - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_ +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + + +#if !defined(AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_) +#define AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +namespace TreePropSheet +{ + + +/** +An object of an CPropertyPageFrame-derived class is used by +CTreePropSheet to display a frame for the property pages. + +Derived classes have to implement at least the Create() and the +GetWnd() method, which +returns a pointer to the CWnd-obect of the window, that has been +created by the call to the Create() method. An implementation can +provide the CWnd-object by using it as a property or by deriving +from CWnd or a more specialiced class. This way has been choosen +instead of deriving CPropPageFrame from CWnd, to allow derived class +to derive from more specialized classes than CWnd +(i.e. CStatic, etc.). From the WM_PAINT-handler of your derived class +you have to call the Draw()-method. + +Most implementations will also implement the DrawCaption() and +DrawMsg() methods, to provide custom drawing functionality. + +@author Sven Wiegand +*/ +class /*AFX_EXT_CLASS*/ CPropPageFrame +{ +// Construction/Destruction +public: + CPropPageFrame(); + virtual ~CPropPageFrame(); + +// Operations +public: + /** + Has to create a window with the specified properties. + + @param dwWindowStyle + Standard window styles, to apply to the window to create. + @param rect + Position and size of the window to create. + @param pwndParent + Parent window. (Never be NULL). + @param nID + Window id. + + @return + TRUE on success, FALSE otherwise. + */ + virtual BOOL Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID) = 0; + + /** + Returns a pointer to the window object, that represents the frame. + */ + virtual CWnd* GetWnd() = 0; + + /** + Enables or disables page caption. + + This default implementation calls the SafeUpdateWindow() method + with the caption rectangle, to force it to be redrawn. + */ + virtual void ShowCaption(BOOL bEnable); + + /** + Returns TRUE if captions are enabled, FALSE otherwise. + */ + BOOL GetShowCaption() const; + + /** + Sets the height of the caption in pixels. This value is ignored + until the caption is enabled by ShowCaption(TRUE). + + This default implementation calls the SafeUpdateWindow() method + with the caption rectangle, to force it to be redrawn. + */ + virtual void SetCaptionHeight(int nCaptionHeight); + + /** + Returns the caption height, that has been most recently set by a + call to the SetCaptionHeight() method. + */ + int GetCaptionHeight() const; + + /** + Sets caption text an icon. + + This default implementation calls the SafeUpdateWindow() method + with the caption rectangle, to force it to be redrawn. + + @param lpszCaption + Text to display for the caption. + @param hIcon + Icon to display for the caption. + */ + virtual void SetCaption(LPCTSTR lpszCaption, HICON hIcon = NULL); + + /** + Returns the caption, that has been set most recently using the + SetCaption() method. + + @param pIcon + Pointer to a HICON variable, that should receive the handle of + the currently set icon or NULL, if there is no icon or a NULL + pointer, if the caller is not interested in the icon. + + @return + The text that has been set most recently using the SetCaption() + method. + */ + CString GetCaption(HICON *pIcon = NULL) const; + + /** + Sets the text to display. + + This default implementation calls the SafeUpdateWindow() method + with the message rectangle, to force it to be redrawn. + */ + virtual void SetMsgText(LPCTSTR lpszMsg); + + /** + Returns the text currently displayed. + */ + CString GetMsgText() const; + + /** + Specifies the format to draw the text with, set by SetMsgText(). + + This default implementation calls the SafeUpdateWindow() method + with the message rectangle, to force it to be redrawn. + + @param dwFormat + Combination of the DT_* flags, specified by the Win32 function + DrawText(). + */ + virtual void SetMsgFormat(DWORD dwFormat); + + /** + Returns the format to draw the text with, set by SetMsgText(). + + @see SetMsgFormat() + */ + DWORD GetMsgFormat() const; + +// Overridable implementation helpers +protected: + /** + Draws the whole frame including caption (if enabled) and message. + + This method calculates the rectangles for the message area and + the caption area using the CalcMsgArea() and the CalcCaptionArea() + methods, draws then the caption calling the DrawCaption() method + (only if caption is enabled) and afterwards the message calling + the DrawMsg() method. + + You should call this method from the WM_PAINT-handler of your + derived class. + + @param pDc + Device context to draw in. + */ + virtual void Draw(CDC *pDc); + + /** + Calculates the area, the message, set by SetMsgText() should be + displayed in. The returned rectangle (client coordinates) will be + passed to DrawMsg(). + + This default implementation calls the CalcCaptionArea() method, + substracts the returned rectangle from the client area and returns + the result. + */ + virtual CRect CalcMsgArea(); + + /** + Draws the message with the specified format. + + This default implementation draws the given msg using the specified + properties. + + @param pDc + Device context to draw in. + @param rect + Rectangle to draw the message in. + @param lpszMsg + Message to draw. + @param dwFormat. + Combination of the DT_* flags, specified by the Win32 function + DrawText() to draw the message with. + */ + virtual void DrawMsg(CDC *pDc, CRect rect, LPCTSTR lpszMsg, DWORD dwFormat); + + /** + Calculates the caption area. The caption area is the rectangular + range, the current page's caption should be drawn in. + + The caption can be enabled or disabled using the ShowCaption() + method. This method should return an empty rect, if the caption + is disabled. If the caption is enabled the height of the rect + should be as large, as specified by the latest call to the + SetCaptionHeight() method. + + The rectangle, returned by this method will be passed to the + DrawCaption() method to draw the caption. + + If the caption is enabled currently, this default implementation + returns a rectangle, that has the width of the client area and + the height, specified by the latest call to SetCaptionHeight(), + starting and y-position 0. If the caption is disabled at the + moment, this method returns an empty rectangle with the width of + the client area. + */ + virtual CRect CalcCaptionArea(); + + /** + Draws the caption. + + This default implementation draws nothing. + + @param pDc + Device context to draw in. + @param rect + Rectangle to draw the caption in. + @param lpszCaption + Text to display in the caption. + @param hIcon + Icon to display in the caption. + */ + virtual void DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); + +// Implementation helpers +protected: + /** + If the m_hWnd property of the CWnd-object returend by GetWnd() + specifies a valid window, this method will invalidate the specified + rectangle, to schedule it for repaint, otherwise the method will + return without doing anything. + + @param lpRect + Pointer to the rectangular area, that should be marked for + repainting or NULL, if the whole client area should be marked + for repainting. + */ + void SafeUpdateWindow(LPCRECT lpRect = NULL); + +// Properties +private: + /** TRUE if the caption should be drawn, FALSE otherwise. */ + BOOL m_bShowCaption; + + /** Height of the caption in pixels, if it is enabled. */ + int m_nCaptionHeight; + + /** Text to display in the caption. */ + CString m_strCaption; + + /** + Icon to display in the caption or NULL if no icon should be + displayed. + */ + HICON m_hCaptionIcon; + + /** Message text to display. */ + CString m_strMsg; + + /** Style to use when drawing the message text m_strMsg. */ + DWORD m_dwMsgFormat; +}; + + +} //namespace TreePropSheet + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // AFX_PROPPAGEFRAME_H__B968548B_F0B4_4C35_85DD_C44242A9D368__INCLUDED_ diff --git a/src/thirdparty/TreePropSheet/PropPageFrameDefault.cpp b/src/thirdparty/TreePropSheet/PropPageFrameDefault.cpp index 37f12acec7d..4b6ca3268c1 100644 --- a/src/thirdparty/TreePropSheet/PropPageFrameDefault.cpp +++ b/src/thirdparty/TreePropSheet/PropPageFrameDefault.cpp @@ -1,410 +1,410 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - -#include "stdafx.h" -#include "PropPageFrameDefault.h" -// -#include "../../DSUtil/WinAPIUtils.h" -// - - -namespace TreePropSheet -{ - -#include -#include - -//------------------------------------------------------------------- -// class CThemeLib -//------------------------------------------------------------------- - - -/** -Helper class for loading the uxtheme DLL and providing their -functions. - -One global object of this class exists. - -@author Sven Wiegand -*/ -class CThemeLib -{ -// construction/destruction -public: - CThemeLib(); - ~CThemeLib(); - -// operations -public: - /** - Returns TRUE if the call wrappers are available, FALSE otherwise. - */ - BOOL IsAvailable() const; - -// call wrappers -public: - BOOL IsThemeActive() const - {return (*m_pIsThemeActive)();} - - HTHEME OpenThemeData(HWND hwnd, LPCWSTR pszClassList) const - {return (*m_pOpenThemeData)(hwnd, pszClassList);} - - HRESULT CloseThemeData(HTHEME hTheme) const - {return (*m_pCloseThemeData)(hTheme);} - - HRESULT GetThemeBackgroundContentRect(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, OUT RECT *pContentRect) const - {return (*m_pGetThemeBackgroundContentRect)(hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect);} - - HRESULT DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect) const - {return (*m_pDrawThemeBackground)(hTheme, hdc, iPartId, iStateId, pRect, pClipRect);} - - HRESULT DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, UINT uEdge, UINT uFlags, OPTIONAL const RECT * pContentRect) const - {return (*m_pDrawThemeEdge)(hTheme, hdc, iPartId, iStateId, pRect, uEdge, uFlags, pContentRect);} - -// function pointers -private: - typedef BOOL (__stdcall *_IsThemeActive)(); - _IsThemeActive m_pIsThemeActive; - - typedef HTHEME (__stdcall *_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList); - _OpenThemeData m_pOpenThemeData; - - typedef HRESULT(__stdcall *_CloseThemeData)(HTHEME hTheme); - _CloseThemeData m_pCloseThemeData; - - typedef HRESULT(__stdcall *_GetThemeBackgroundContentRect)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, OUT RECT *pContentRect); - _GetThemeBackgroundContentRect m_pGetThemeBackgroundContentRect; - - typedef HRESULT(__stdcall* _DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, OPTIONAL const RECT* pClipRect); - _DrawThemeBackground m_pDrawThemeBackground; - - typedef HRESULT(__stdcall* _DrawThemeEdge)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, UINT uEdge, UINT uFlags, OPTIONAL const RECT* pContentRect); - _DrawThemeEdge m_pDrawThemeEdge; - -// properties -private: - /** instance handle to the library or NULL. */ - HINSTANCE m_hThemeLib; -}; - -/** -One and only instance of CThemeLib. -*/ -static CThemeLib g_ThemeLib; - - -CThemeLib::CThemeLib() - : m_pIsThemeActive(NULL) - , m_pOpenThemeData(NULL) - , m_pCloseThemeData(NULL) - , m_pGetThemeBackgroundContentRect(NULL) - , m_pDrawThemeBackground(NULL) - , m_hThemeLib(NULL) -{ - m_hThemeLib = LoadLibrary(_T("uxtheme.dll")); - if (!m_hThemeLib) - return; - - m_pIsThemeActive = (_IsThemeActive)GetProcAddress(m_hThemeLib, "IsThemeActive"); - m_pOpenThemeData = (_OpenThemeData)GetProcAddress(m_hThemeLib, "OpenThemeData"); - m_pCloseThemeData = (_CloseThemeData)GetProcAddress(m_hThemeLib, "CloseThemeData"); - m_pGetThemeBackgroundContentRect = (_GetThemeBackgroundContentRect)GetProcAddress(m_hThemeLib, "GetThemeBackgroundContentRect"); - m_pDrawThemeBackground = (_DrawThemeBackground)GetProcAddress(m_hThemeLib, "DrawThemeBackground"); - m_pDrawThemeEdge = (_DrawThemeEdge)GetProcAddress(m_hThemeLib, "DrawThemeEdge"); -} - - -CThemeLib::~CThemeLib() -{ - if (m_hThemeLib) - FreeLibrary(m_hThemeLib); -} - - -BOOL CThemeLib::IsAvailable() const -{ - return m_hThemeLib!=NULL; -} - - -//------------------------------------------------------------------- -// class CPropPageFrameDefault -//------------------------------------------------------------------- - -BEGIN_MESSAGE_MAP(CPropPageFrameDefault, CWnd) - //{{AFX_MSG_MAP(CPropPageFrameDefault) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - - -CPropPageFrameDefault::CPropPageFrameDefault() -{ -} - - -CPropPageFrameDefault::~CPropPageFrameDefault() -{ - if (m_Images.GetSafeHandle()) - m_Images.DeleteImageList(); -} - - -///////////////////////////////////////////////////////////////////// -// Overridings - -BOOL CPropPageFrameDefault::Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID) -{ - return CWnd::Create( - AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), GetSysColorBrush(COLOR_3DFACE)), - _T("Page Frame"), - dwWindowStyle, rect, pwndParent, nID); -} - - -CWnd* CPropPageFrameDefault::GetWnd() -{ - return static_cast(this); -} - - -void CPropPageFrameDefault::SetCaption(LPCTSTR lpszCaption, HICON hIcon /*= NULL*/) -{ - CPropPageFrame::SetCaption(lpszCaption, hIcon); - - // build image list - if (m_Images.GetSafeHandle()) - m_Images.DeleteImageList(); - if (hIcon) - { - ICONINFO ii; - if (!GetIconInfo(hIcon, &ii)) - return; - - CBitmap bmMask; - bmMask.Attach(ii.hbmMask); - if (ii.hbmColor) DeleteObject(ii.hbmColor); - - BITMAP bm; - bmMask.GetBitmap(&bm); - - if (!m_Images.Create(bm.bmWidth, bm.bmHeight, ILC_COLOR32|ILC_MASK, 0, 1)) - return; - - if (m_Images.Add(hIcon) == -1) - m_Images.DeleteImageList(); - } -} - - -CRect CPropPageFrameDefault::CalcMsgArea() -{ - CRect rect; - GetClientRect(rect); - if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) - { - HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); - if (hTheme) - { - CRect rectContent; - CDC *pDc = GetDC(); - g_ThemeLib.GetThemeBackgroundContentRect(hTheme, pDc->m_hDC, TABP_PANE, 0, rect, rectContent); - ReleaseDC(pDc); - g_ThemeLib.CloseThemeData(hTheme); - - if (GetShowCaption()) - rectContent.top = rect.top+GetCaptionHeight()+1; - rect = rectContent; - } - } - else if (GetShowCaption()) - rect.top+= GetCaptionHeight()+1; - - return rect; -} - - -CRect CPropPageFrameDefault::CalcCaptionArea() -{ - CRect rect; - GetClientRect(rect); - if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) - { - HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); - if (hTheme) - { - CRect rectContent; - CDC *pDc = GetDC(); - g_ThemeLib.GetThemeBackgroundContentRect(hTheme, pDc->m_hDC, TABP_PANE, 0, rect, rectContent); - ReleaseDC(pDc); - g_ThemeLib.CloseThemeData(hTheme); - - if (GetShowCaption()) - rectContent.bottom = rect.top+GetCaptionHeight(); - else - rectContent.bottom = rectContent.top; - - rect = rectContent; - } - } - else - { - if (GetShowCaption()) - rect.bottom = rect.top+GetCaptionHeight(); - else - rect.bottom = rect.top; - } - - return rect; -} - -void CPropPageFrameDefault::DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon) -{ - // - COLORREF clrLeft = GetSysColor(COLOR_ACTIVECAPTION); - // - COLORREF clrRight = pDc->GetPixel(rect.right-1, rect.top); - FillGradientRectH(pDc, rect, clrLeft, clrRight); - - // draw icon - if (hIcon && m_Images.GetSafeHandle() && m_Images.GetImageCount() == 1) - { - IMAGEINFO ii; - m_Images.GetImageInfo(0, &ii); - CPoint pt(3, rect.CenterPoint().y - (ii.rcImage.bottom-ii.rcImage.top)/2); - m_Images.Draw(pDc, 0, pt, ILD_TRANSPARENT); - rect.left+= (ii.rcImage.right-ii.rcImage.left) + 3; - } - - // draw text - rect.left+= 2; - - COLORREF clrPrev = pDc->SetTextColor(GetSysColor(COLOR_CAPTIONTEXT)); - int nBkStyle = pDc->SetBkMode(TRANSPARENT); - CFont *pFont = (CFont*)pDc->SelectStockObject(SYSTEM_FONT); - -// - LOGFONT lf; - GetMessageFont(&lf); - lf.lfHeight = static_cast(-.8f * rect.Height()); - lf.lfWeight = FW_BOLD; - CFont f; - f.CreateFontIndirectW(&lf); - pFont = pDc->SelectObject(&f); - - TEXTMETRIC GDIMetrics; - GetTextMetricsW(pDc->GetSafeHdc(), &GDIMetrics); - while (GDIMetrics.tmHeight > rect.Height() && abs(lf.lfHeight) > 10) { - pDc->SelectObject(pFont); - f.DeleteObject(); - lf.lfHeight++; - f.CreateFontIndirectW(&lf); - pDc->SelectObject(&f); - GetTextMetricsW(pDc->GetSafeHdc(), &GDIMetrics); - } - - rect.top -= GDIMetrics.tmDescent - 1; -// CFont f; -// f.CreateFontIndirect(&lf); -// pDc->SelectObject(&f); - pDc->DrawText(lpszCaption, rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); -// - - - pDc->SetTextColor(clrPrev); - pDc->SetBkMode(nBkStyle); - pDc->SelectObject(pFont); -} - - -///////////////////////////////////////////////////////////////////// -// Implementation helpers - -void CPropPageFrameDefault::FillGradientRectH(CDC *pDc, const RECT &rect, COLORREF clrLeft, COLORREF clrRight) -{ - // pre calculation - int nSteps = rect.right-rect.left; - int nRRange = GetRValue(clrRight)-GetRValue(clrLeft); - int nGRange = GetGValue(clrRight)-GetGValue(clrLeft); - int nBRange = GetBValue(clrRight)-GetBValue(clrLeft); - - double dRStep = (double)nRRange/(double)nSteps; - double dGStep = (double)nGRange/(double)nSteps; - double dBStep = (double)nBRange/(double)nSteps; - - double dR = (double)GetRValue(clrLeft); - double dG = (double)GetGValue(clrLeft); - double dB = (double)GetBValue(clrLeft); - - CPen *pPrevPen = NULL; - for (int x = rect.left; x <= rect.right; ++x) - { - CPen Pen(PS_SOLID, 1, RGB((BYTE)dR, (BYTE)dG, (BYTE)dB)); - pPrevPen = pDc->SelectObject(&Pen); - pDc->MoveTo(x, rect.top); - pDc->LineTo(x, rect.bottom); - pDc->SelectObject(pPrevPen); - - dR+= dRStep; - dG+= dGStep; - dB+= dBStep; - } -} - - -///////////////////////////////////////////////////////////////////// -// message handlers - -void CPropPageFrameDefault::OnPaint() -{ - CPaintDC dc(this); - Draw(&dc); -} - - -BOOL CPropPageFrameDefault::OnEraseBkgnd(CDC* pDC) -{ - if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) - { - HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); - if (hTheme) - { - CRect rect; - GetClientRect(rect); - //g_ThemeLib.DrawThemeBackground(hTheme, pDC->m_hDC, TABP_PANE, 0, rect, NULL); - - //mpc-hc: TABP_PANE draws a border 1 pixel short of bottom, and two pixels short of right. - //instead we fill using TABP_BODY and draw the edge separately (using BDR_SUNKENOUTER for 1 pixel only) - g_ThemeLib.DrawThemeBackground(hTheme, pDC->m_hDC, TABP_BODY, 0, rect, NULL); - g_ThemeLib.DrawThemeEdge(hTheme, pDC->m_hDC, TABP_BODY, 0, rect, BDR_SUNKENOUTER, BF_FLAT | BF_RECT, NULL); - - g_ThemeLib.CloseThemeData(hTheme); - } - return TRUE; - } - else - { - return CWnd::OnEraseBkgnd(pDC); - } -} - - - -} //namespace TreePropSheet +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + +#include "stdafx.h" +#include "PropPageFrameDefault.h" +// +#include "../../DSUtil/WinAPIUtils.h" +// + + +namespace TreePropSheet +{ + +#include +#include + +//------------------------------------------------------------------- +// class CThemeLib +//------------------------------------------------------------------- + + +/** +Helper class for loading the uxtheme DLL and providing their +functions. + +One global object of this class exists. + +@author Sven Wiegand +*/ +class CThemeLib +{ +// construction/destruction +public: + CThemeLib(); + ~CThemeLib(); + +// operations +public: + /** + Returns TRUE if the call wrappers are available, FALSE otherwise. + */ + BOOL IsAvailable() const; + +// call wrappers +public: + BOOL IsThemeActive() const + {return (*m_pIsThemeActive)();} + + HTHEME OpenThemeData(HWND hwnd, LPCWSTR pszClassList) const + {return (*m_pOpenThemeData)(hwnd, pszClassList);} + + HRESULT CloseThemeData(HTHEME hTheme) const + {return (*m_pCloseThemeData)(hTheme);} + + HRESULT GetThemeBackgroundContentRect(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, OUT RECT *pContentRect) const + {return (*m_pGetThemeBackgroundContentRect)(hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect);} + + HRESULT DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect) const + {return (*m_pDrawThemeBackground)(hTheme, hdc, iPartId, iStateId, pRect, pClipRect);} + + HRESULT DrawThemeEdge(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, UINT uEdge, UINT uFlags, OPTIONAL const RECT * pContentRect) const + {return (*m_pDrawThemeEdge)(hTheme, hdc, iPartId, iStateId, pRect, uEdge, uFlags, pContentRect);} + +// function pointers +private: + typedef BOOL (__stdcall *_IsThemeActive)(); + _IsThemeActive m_pIsThemeActive; + + typedef HTHEME (__stdcall *_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList); + _OpenThemeData m_pOpenThemeData; + + typedef HRESULT(__stdcall *_CloseThemeData)(HTHEME hTheme); + _CloseThemeData m_pCloseThemeData; + + typedef HRESULT(__stdcall *_GetThemeBackgroundContentRect)(HTHEME hTheme, OPTIONAL HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, OUT RECT *pContentRect); + _GetThemeBackgroundContentRect m_pGetThemeBackgroundContentRect; + + typedef HRESULT(__stdcall* _DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, OPTIONAL const RECT* pClipRect); + _DrawThemeBackground m_pDrawThemeBackground; + + typedef HRESULT(__stdcall* _DrawThemeEdge)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, UINT uEdge, UINT uFlags, OPTIONAL const RECT* pContentRect); + _DrawThemeEdge m_pDrawThemeEdge; + +// properties +private: + /** instance handle to the library or NULL. */ + HINSTANCE m_hThemeLib; +}; + +/** +One and only instance of CThemeLib. +*/ +static CThemeLib g_ThemeLib; + + +CThemeLib::CThemeLib() + : m_pIsThemeActive(NULL) + , m_pOpenThemeData(NULL) + , m_pCloseThemeData(NULL) + , m_pGetThemeBackgroundContentRect(NULL) + , m_pDrawThemeBackground(NULL) + , m_hThemeLib(NULL) +{ + m_hThemeLib = LoadLibrary(_T("uxtheme.dll")); + if (!m_hThemeLib) + return; + + m_pIsThemeActive = (_IsThemeActive)GetProcAddress(m_hThemeLib, "IsThemeActive"); + m_pOpenThemeData = (_OpenThemeData)GetProcAddress(m_hThemeLib, "OpenThemeData"); + m_pCloseThemeData = (_CloseThemeData)GetProcAddress(m_hThemeLib, "CloseThemeData"); + m_pGetThemeBackgroundContentRect = (_GetThemeBackgroundContentRect)GetProcAddress(m_hThemeLib, "GetThemeBackgroundContentRect"); + m_pDrawThemeBackground = (_DrawThemeBackground)GetProcAddress(m_hThemeLib, "DrawThemeBackground"); + m_pDrawThemeEdge = (_DrawThemeEdge)GetProcAddress(m_hThemeLib, "DrawThemeEdge"); +} + + +CThemeLib::~CThemeLib() +{ + if (m_hThemeLib) + FreeLibrary(m_hThemeLib); +} + + +BOOL CThemeLib::IsAvailable() const +{ + return m_hThemeLib!=NULL; +} + + +//------------------------------------------------------------------- +// class CPropPageFrameDefault +//------------------------------------------------------------------- + +BEGIN_MESSAGE_MAP(CPropPageFrameDefault, CWnd) + //{{AFX_MSG_MAP(CPropPageFrameDefault) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +CPropPageFrameDefault::CPropPageFrameDefault() +{ +} + + +CPropPageFrameDefault::~CPropPageFrameDefault() +{ + if (m_Images.GetSafeHandle()) + m_Images.DeleteImageList(); +} + + +///////////////////////////////////////////////////////////////////// +// Overridings + +BOOL CPropPageFrameDefault::Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID) +{ + return CWnd::Create( + AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), GetSysColorBrush(COLOR_3DFACE)), + _T("Page Frame"), + dwWindowStyle, rect, pwndParent, nID); +} + + +CWnd* CPropPageFrameDefault::GetWnd() +{ + return static_cast(this); +} + + +void CPropPageFrameDefault::SetCaption(LPCTSTR lpszCaption, HICON hIcon /*= NULL*/) +{ + CPropPageFrame::SetCaption(lpszCaption, hIcon); + + // build image list + if (m_Images.GetSafeHandle()) + m_Images.DeleteImageList(); + if (hIcon) + { + ICONINFO ii; + if (!GetIconInfo(hIcon, &ii)) + return; + + CBitmap bmMask; + bmMask.Attach(ii.hbmMask); + if (ii.hbmColor) DeleteObject(ii.hbmColor); + + BITMAP bm; + bmMask.GetBitmap(&bm); + + if (!m_Images.Create(bm.bmWidth, bm.bmHeight, ILC_COLOR32|ILC_MASK, 0, 1)) + return; + + if (m_Images.Add(hIcon) == -1) + m_Images.DeleteImageList(); + } +} + + +CRect CPropPageFrameDefault::CalcMsgArea() +{ + CRect rect; + GetClientRect(rect); + if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) + { + HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); + if (hTheme) + { + CRect rectContent; + CDC *pDc = GetDC(); + g_ThemeLib.GetThemeBackgroundContentRect(hTheme, pDc->m_hDC, TABP_PANE, 0, rect, rectContent); + ReleaseDC(pDc); + g_ThemeLib.CloseThemeData(hTheme); + + if (GetShowCaption()) + rectContent.top = rect.top+GetCaptionHeight()+1; + rect = rectContent; + } + } + else if (GetShowCaption()) + rect.top+= GetCaptionHeight()+1; + + return rect; +} + + +CRect CPropPageFrameDefault::CalcCaptionArea() +{ + CRect rect; + GetClientRect(rect); + if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) + { + HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); + if (hTheme) + { + CRect rectContent; + CDC *pDc = GetDC(); + g_ThemeLib.GetThemeBackgroundContentRect(hTheme, pDc->m_hDC, TABP_PANE, 0, rect, rectContent); + ReleaseDC(pDc); + g_ThemeLib.CloseThemeData(hTheme); + + if (GetShowCaption()) + rectContent.bottom = rect.top+GetCaptionHeight(); + else + rectContent.bottom = rectContent.top; + + rect = rectContent; + } + } + else + { + if (GetShowCaption()) + rect.bottom = rect.top+GetCaptionHeight(); + else + rect.bottom = rect.top; + } + + return rect; +} + +void CPropPageFrameDefault::DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon) +{ + // + COLORREF clrLeft = GetSysColor(COLOR_ACTIVECAPTION); + // + COLORREF clrRight = pDc->GetPixel(rect.right-1, rect.top); + FillGradientRectH(pDc, rect, clrLeft, clrRight); + + // draw icon + if (hIcon && m_Images.GetSafeHandle() && m_Images.GetImageCount() == 1) + { + IMAGEINFO ii; + m_Images.GetImageInfo(0, &ii); + CPoint pt(3, rect.CenterPoint().y - (ii.rcImage.bottom-ii.rcImage.top)/2); + m_Images.Draw(pDc, 0, pt, ILD_TRANSPARENT); + rect.left+= (ii.rcImage.right-ii.rcImage.left) + 3; + } + + // draw text + rect.left+= 2; + + COLORREF clrPrev = pDc->SetTextColor(GetSysColor(COLOR_CAPTIONTEXT)); + int nBkStyle = pDc->SetBkMode(TRANSPARENT); + CFont *pFont = (CFont*)pDc->SelectStockObject(SYSTEM_FONT); + +// + LOGFONT lf; + GetMessageFont(&lf); + lf.lfHeight = static_cast(-.8f * rect.Height()); + lf.lfWeight = FW_BOLD; + CFont f; + f.CreateFontIndirectW(&lf); + pFont = pDc->SelectObject(&f); + + TEXTMETRIC GDIMetrics; + GetTextMetricsW(pDc->GetSafeHdc(), &GDIMetrics); + while (GDIMetrics.tmHeight > rect.Height() && abs(lf.lfHeight) > 10) { + pDc->SelectObject(pFont); + f.DeleteObject(); + lf.lfHeight++; + f.CreateFontIndirectW(&lf); + pDc->SelectObject(&f); + GetTextMetricsW(pDc->GetSafeHdc(), &GDIMetrics); + } + + rect.top -= GDIMetrics.tmDescent - 1; +// CFont f; +// f.CreateFontIndirect(&lf); +// pDc->SelectObject(&f); + pDc->DrawText(lpszCaption, rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); +// + + + pDc->SetTextColor(clrPrev); + pDc->SetBkMode(nBkStyle); + pDc->SelectObject(pFont); +} + + +///////////////////////////////////////////////////////////////////// +// Implementation helpers + +void CPropPageFrameDefault::FillGradientRectH(CDC *pDc, const RECT &rect, COLORREF clrLeft, COLORREF clrRight) +{ + // pre calculation + int nSteps = rect.right-rect.left; + int nRRange = GetRValue(clrRight)-GetRValue(clrLeft); + int nGRange = GetGValue(clrRight)-GetGValue(clrLeft); + int nBRange = GetBValue(clrRight)-GetBValue(clrLeft); + + double dRStep = (double)nRRange/(double)nSteps; + double dGStep = (double)nGRange/(double)nSteps; + double dBStep = (double)nBRange/(double)nSteps; + + double dR = (double)GetRValue(clrLeft); + double dG = (double)GetGValue(clrLeft); + double dB = (double)GetBValue(clrLeft); + + CPen *pPrevPen = NULL; + for (int x = rect.left; x <= rect.right; ++x) + { + CPen Pen(PS_SOLID, 1, RGB((BYTE)dR, (BYTE)dG, (BYTE)dB)); + pPrevPen = pDc->SelectObject(&Pen); + pDc->MoveTo(x, rect.top); + pDc->LineTo(x, rect.bottom); + pDc->SelectObject(pPrevPen); + + dR+= dRStep; + dG+= dGStep; + dB+= dBStep; + } +} + + +///////////////////////////////////////////////////////////////////// +// message handlers + +void CPropPageFrameDefault::OnPaint() +{ + CPaintDC dc(this); + Draw(&dc); +} + + +BOOL CPropPageFrameDefault::OnEraseBkgnd(CDC* pDC) +{ + if (g_ThemeLib.IsAvailable() && g_ThemeLib.IsThemeActive()) + { + HTHEME hTheme = g_ThemeLib.OpenThemeData(m_hWnd, L"Tab"); + if (hTheme) + { + CRect rect; + GetClientRect(rect); + //g_ThemeLib.DrawThemeBackground(hTheme, pDC->m_hDC, TABP_PANE, 0, rect, NULL); + + //mpc-hc: TABP_PANE draws a border 1 pixel short of bottom, and two pixels short of right. + //instead we fill using TABP_BODY and draw the edge separately (using BDR_SUNKENOUTER for 1 pixel only) + g_ThemeLib.DrawThemeBackground(hTheme, pDC->m_hDC, TABP_BODY, 0, rect, NULL); + g_ThemeLib.DrawThemeEdge(hTheme, pDC->m_hDC, TABP_BODY, 0, rect, BDR_SUNKENOUTER, BF_FLAT | BF_RECT, NULL); + + g_ThemeLib.CloseThemeData(hTheme); + } + return TRUE; + } + else + { + return CWnd::OnEraseBkgnd(pDC); + } +} + + + +} //namespace TreePropSheet diff --git a/src/thirdparty/TreePropSheet/PropPageFrameDefault.h b/src/thirdparty/TreePropSheet/PropPageFrameDefault.h index ce9c576f5fb..883a696ae74 100644 --- a/src/thirdparty/TreePropSheet/PropPageFrameDefault.h +++ b/src/thirdparty/TreePropSheet/PropPageFrameDefault.h @@ -1,117 +1,117 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - - -#if !defined(AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_) -#define AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include "PropPageFrame.h" - - -namespace TreePropSheet -{ - - -/** -An implementation of CPropPageFrame, that works well for Windows XP -styled systems and older windows versions (without themes). - -@author Sven Wiegand -*/ -class /*AFX_EXT_CLASS*/ CPropPageFrameDefault : public CWnd, - public CPropPageFrame -{ -// construction/destruction -public: - CPropPageFrameDefault(); - virtual ~CPropPageFrameDefault(); - -// operations -public: - -// overridings -public: - virtual BOOL Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID); - virtual CWnd* GetWnd(); - virtual void SetCaption(LPCTSTR lpszCaption, HICON hIcon = NULL); - -protected: - virtual CRect CalcMsgArea(); - virtual CRect CalcCaptionArea(); - virtual void DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); - -// Implementation helpers -protected: - /** - Fills a rectangular area with a gradient color starting at the left - side with the color clrLeft and ending at the right sight with the - color clrRight. - - @param pDc - Device context to draw the rectangle in. - @param rect - Rectangular area to fill. - @param clrLeft - Color on the left side. - @param clrRight - Color on the right side. - */ - void FillGradientRectH(CDC *pDc, const RECT &rect, COLORREF clrLeft, COLORREF clrRight); - - /** - Returns TRUE if Windows XP theme support is available, FALSE - otherwise. - */ - BOOL ThemeSupport() const; - -protected: - //{{AFX_VIRTUAL(CPropPageFrameDefault) - //}}AFX_VIRTUAL - -// message handlers -protected: - //{{AFX_MSG(CPropPageFrameDefault) - afx_msg void OnPaint(); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() - -// attributes -protected: - /** - Image list that contains only the current icon or nothing if there - is no icon. - */ - CImageList m_Images; -}; - - -} //namespace TreePropSheet - - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_ +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + + +#if !defined(AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_) +#define AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "PropPageFrame.h" + + +namespace TreePropSheet +{ + + +/** +An implementation of CPropPageFrame, that works well for Windows XP +styled systems and older windows versions (without themes). + +@author Sven Wiegand +*/ +class /*AFX_EXT_CLASS*/ CPropPageFrameDefault : public CWnd, + public CPropPageFrame +{ +// construction/destruction +public: + CPropPageFrameDefault(); + virtual ~CPropPageFrameDefault(); + +// operations +public: + +// overridings +public: + virtual BOOL Create(DWORD dwWindowStyle, const RECT &rect, CWnd *pwndParent, UINT nID); + virtual CWnd* GetWnd(); + virtual void SetCaption(LPCTSTR lpszCaption, HICON hIcon = NULL); + +protected: + virtual CRect CalcMsgArea(); + virtual CRect CalcCaptionArea(); + virtual void DrawCaption(CDC *pDc, CRect rect, LPCTSTR lpszCaption, HICON hIcon); + +// Implementation helpers +protected: + /** + Fills a rectangular area with a gradient color starting at the left + side with the color clrLeft and ending at the right sight with the + color clrRight. + + @param pDc + Device context to draw the rectangle in. + @param rect + Rectangular area to fill. + @param clrLeft + Color on the left side. + @param clrRight + Color on the right side. + */ + void FillGradientRectH(CDC *pDc, const RECT &rect, COLORREF clrLeft, COLORREF clrRight); + + /** + Returns TRUE if Windows XP theme support is available, FALSE + otherwise. + */ + BOOL ThemeSupport() const; + +protected: + //{{AFX_VIRTUAL(CPropPageFrameDefault) + //}}AFX_VIRTUAL + +// message handlers +protected: + //{{AFX_MSG(CPropPageFrameDefault) + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +// attributes +protected: + /** + Image list that contains only the current icon or nothing if there + is no icon. + */ + CImageList m_Images; +}; + + +} //namespace TreePropSheet + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // AFX_PROPPAGEFRAMEDEFAULT_H__5C5B7AC9_2DF5_4E8C_8F5E_DE2CC04BBED7__INCLUDED_ diff --git a/src/thirdparty/TreePropSheet/TreePropSheet.cpp b/src/thirdparty/TreePropSheet/TreePropSheet.cpp index 0d493646290..40d7ba02e8e 100644 --- a/src/thirdparty/TreePropSheet/TreePropSheet.cpp +++ b/src/thirdparty/TreePropSheet/TreePropSheet.cpp @@ -1,1000 +1,1000 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - - -#include "stdafx.h" -#include "TreePropSheet.h" -#include "PropPageFrameDefault.h" -#include "../../../src/mpc-hc/DpiHelper.h" -#include "../../../src/DSUtil/VersionHelpersInternal.h" - -namespace TreePropSheet -{ - -//------------------------------------------------------------------- -// class CTreePropSheet -//------------------------------------------------------------------- - -BEGIN_MESSAGE_MAP(CTreePropSheet, CPropertySheet) - //{{AFX_MSG_MAP(CTreePropSheet) - ON_WM_DESTROY() - //}}AFX_MSG_MAP - ON_MESSAGE(PSM_ADDPAGE, OnAddPage) - ON_MESSAGE(PSM_REMOVEPAGE, OnRemovePage) - ON_MESSAGE(PSM_SETCURSEL, OnSetCurSel) - ON_MESSAGE(PSM_SETCURSELID, OnSetCurSelId) - ON_MESSAGE(PSM_ISDIALOGMESSAGE, OnIsDialogMessage) - - ON_NOTIFY(TVN_SELCHANGINGA, s_unPageTreeId, OnPageTreeSelChanging) - ON_NOTIFY(TVN_SELCHANGINGW, s_unPageTreeId, OnPageTreeSelChanging) - ON_NOTIFY(TVN_SELCHANGEDA, s_unPageTreeId, OnPageTreeSelChanged) - ON_NOTIFY(TVN_SELCHANGEDW, s_unPageTreeId, OnPageTreeSelChanged) -END_MESSAGE_MAP() - -IMPLEMENT_DYNAMIC(CTreePropSheet, CPropertySheet) - -const UINT CTreePropSheet::s_unPageTreeId = 0x7EEE; - -CTreePropSheet::CTreePropSheet() -: CPropertySheet(), - m_bTreeViewMode(TRUE), - m_pwndPageTree(NULL), - m_pFrame(NULL), - m_bPageTreeSelChangedActive(FALSE), - m_bPageCaption(FALSE), - m_bTreeImages(FALSE), - m_nPageTreeWidth(150) -{ -} - - -CTreePropSheet::CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) -: CPropertySheet(nIDCaption, pParentWnd, iSelectPage), - m_bTreeViewMode(TRUE), - m_pwndPageTree(NULL), - m_pFrame(NULL), - m_bPageTreeSelChangedActive(FALSE), - m_bPageCaption(FALSE), - m_bTreeImages(FALSE), - m_nPageTreeWidth(150) -{ -} - - -CTreePropSheet::CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) -: CPropertySheet(pszCaption, pParentWnd, iSelectPage), - m_bTreeViewMode(TRUE), - m_pwndPageTree(NULL), - m_pFrame(NULL), - m_bPageTreeSelChangedActive(FALSE), - m_bPageCaption(FALSE), - m_bTreeImages(FALSE), - m_nPageTreeWidth(150) -{ -} - - -CTreePropSheet::~CTreePropSheet() -{ -} - - -///////////////////////////////////////////////////////////////////// -// Operationen - -BOOL CTreePropSheet::SetTreeViewMode(BOOL bTreeViewMode /* = TRUE */, BOOL bPageCaption /* = FALSE */, BOOL bTreeImages /* = FALSE */) -{ - if (IsWindow(m_hWnd)) - { - // needs to becalled, before the window has been created - ASSERT(FALSE); - return FALSE; - } - - m_bTreeViewMode = bTreeViewMode; - if (m_bTreeViewMode) - { - m_bPageCaption = bPageCaption; - m_bTreeImages = bTreeImages; - } - - return TRUE; -} - - -BOOL CTreePropSheet::SetTreeWidth(int nWidth) -{ - if (IsWindow(m_hWnd)) - { - // needs to be called, before the window is created. - ASSERT(FALSE); - return FALSE; - } - - m_nPageTreeWidth = nWidth; - - return TRUE; -} - - -void CTreePropSheet::SetEmptyPageText(LPCTSTR lpszEmptyPageText) -{ - m_strEmptyPageMessage = lpszEmptyPageText; -} - - -DWORD CTreePropSheet::SetEmptyPageTextFormat(DWORD dwFormat) -{ - DWORD dwPrevFormat = m_pFrame->GetMsgFormat(); - m_pFrame->SetMsgFormat(dwFormat); - return dwPrevFormat; -} - - -BOOL CTreePropSheet::SetTreeDefaultImages(CImageList *pImages) -{ - if (pImages->GetImageCount() != 2) - { - ASSERT(FALSE); - return FALSE; - } - - if (m_DefaultImages.GetSafeHandle()) - m_DefaultImages.DeleteImageList(); - m_DefaultImages.Create(pImages); - - // update, if necessary - if (IsWindow(m_hWnd)) - RefillPageTree(); - - return TRUE; -} - - -BOOL CTreePropSheet::SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask) -{ - if (m_DefaultImages.GetSafeHandle()) - m_DefaultImages.DeleteImageList(); - if (!m_DefaultImages.Create(unBitmapID, cx, 0, crMask)) - return FALSE; - - if (m_DefaultImages.GetImageCount() != 2) - { - m_DefaultImages.DeleteImageList(); - return FALSE; - } - - return TRUE; -} - - -CTreeCtrl* CTreePropSheet::GetPageTreeControl() -{ - return m_pwndPageTree; -} - - -///////////////////////////////////////////////////////////////////// -// public helpers - -BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, HICON hIcon) -{ - pPage->m_psp.dwFlags|= PSP_USEHICON; - pPage->m_psp.hIcon = hIcon; - return TRUE; -} - - -BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, UINT unIconId) -{ - HICON hIcon = AfxGetApp()->LoadIcon(unIconId); - if (!hIcon) - return FALSE; - - return SetPageIcon(pPage, hIcon); -} - - -BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage) -{ - HICON hIcon = Images.ExtractIcon(nImage); - if (!hIcon) - return FALSE; - - return SetPageIcon(pPage, hIcon); -} - - -BOOL CTreePropSheet::DestroyPageIcon(CPropertyPage *pPage) -{ - if (!pPage || !(pPage->m_psp.dwFlags&PSP_USEHICON) || !pPage->m_psp.hIcon) - return FALSE; - - DestroyIcon(pPage->m_psp.hIcon); - pPage->m_psp.dwFlags&= ~PSP_USEHICON; - pPage->m_psp.hIcon = NULL; - - return TRUE; -} - - -///////////////////////////////////////////////////////////////////// -// Overridable implementation helpers - -CString CTreePropSheet::GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption) -{ - CString strMsg; - strMsg.Format(lpszEmptyPageMessage, lpszCaption); - return strMsg; -} - - -CTreeCtrl* CTreePropSheet::CreatePageTreeObject() -{ - return new CTreeCtrl; -} - -//added for mpc-hc theming -void CTreePropSheet::SetTreeCtrlTheme(CTreeCtrl *ctrl) { - SetWindowTheme(ctrl->GetSafeHwnd(), L"Explorer", NULL); -} - - -CPropPageFrame* CTreePropSheet::CreatePageFrame() -{ - return new CPropPageFrameDefault; -} - - -///////////////////////////////////////////////////////////////////// -// Implementation helpers - -void CTreePropSheet::MoveChildWindows(int nDx, int nDy) -{ - CWnd *pWnd = GetWindow(GW_CHILD); - while (pWnd) - { - CRect rect; - pWnd->GetWindowRect(rect); - ScreenToClient(rect); - rect.OffsetRect(nDx, nDy); - pWnd->MoveWindow(rect); - - pWnd = pWnd->GetNextWindow(); - } -} - - -void CTreePropSheet::RefillPageTree() -{ - if (!IsWindow(m_hWnd)) - return; - - m_pwndPageTree->DeleteAllItems(); - - CTabCtrl *pTabCtrl = GetTabControl(); - if (!IsWindow(pTabCtrl->GetSafeHwnd())) - { - ASSERT(FALSE); - return; - } - - const int nPageCount = pTabCtrl->GetItemCount(); - - // rebuild image list - if (m_bTreeImages) - { - for (int i = m_Images.GetImageCount()-1; i >= 0; --i) - m_Images.Remove(i); - - // add page images - CImageList *pPageImages = pTabCtrl->GetImageList(); - if (pPageImages) - { - for (int nImage = 0; nImage < pPageImages->GetImageCount(); ++nImage) - { - HICON hIcon = pPageImages->ExtractIcon(nImage); - m_Images.Add(hIcon); - DestroyIcon(hIcon); - } - } - - // add default images - if (m_DefaultImages.GetSafeHandle()) - { - HICON hIcon; - - // add default images - hIcon = m_DefaultImages.ExtractIcon(0); - if (hIcon) - { - m_Images.Add(hIcon); - DestroyIcon(hIcon); - } - hIcon = m_DefaultImages.ExtractIcon(1); - { - m_Images.Add(hIcon); - DestroyIcon(hIcon); - } - } - } - - // insert tree items - for (int nPage = 0; nPage < nPageCount; ++nPage) - { - // Get title and image of the page - CString strPagePath; - - TCITEM ti; - ZeroMemory(&ti, sizeof(ti)); - ti.mask = TCIF_TEXT|TCIF_IMAGE; - ti.cchTextMax = MAX_PATH; - ti.pszText = strPagePath.GetBuffer(ti.cchTextMax); - ASSERT(ti.pszText); - if (!ti.pszText) - return; - - pTabCtrl->GetItem(nPage, &ti); - strPagePath.ReleaseBuffer(); - - // Create an item in the tree for the page - HTREEITEM hItem = CreatePageTreeItem(ti.pszText); - ASSERT(hItem); - if (hItem) - { - m_pwndPageTree->SetItemData(hItem, nPage); - - // set image - if (m_bTreeImages) - { - int nImage = ti.iImage; - if (nImage < 0 || nImage >= m_Images.GetImageCount()) - nImage = m_DefaultImages.GetSafeHandle()? m_Images.GetImageCount()-1 : -1; - - m_pwndPageTree->SetItemImage(hItem, nImage, nImage); - } - m_pwndPageTree->Expand(m_pwndPageTree->GetParentItem(hItem), TVE_EXPAND); - } - } -} - - -HTREEITEM CTreePropSheet::CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent /* = TVI_ROOT */) -{ - CString strPath(lpszPath); - CString strTopMostItem(SplitPageTreePath(strPath)); - - // Check if an item with the given text does already exist - HTREEITEM hItem = NULL; - HTREEITEM hChild = m_pwndPageTree->GetChildItem(hParent); - while (hChild) - { - if (m_pwndPageTree->GetItemText(hChild) == strTopMostItem) - { - hItem = hChild; - break; - } - hChild = m_pwndPageTree->GetNextItem(hChild, TVGN_NEXT); - } - - // If item with that text does not already exist, create a new one - if (!hItem) - { - hItem = m_pwndPageTree->InsertItem(strTopMostItem, hParent); - m_pwndPageTree->SetItemData(hItem, (DWORD_PTR)-1); - if (!strPath.IsEmpty() && m_bTreeImages && m_DefaultImages.GetSafeHandle()) - // set folder image - m_pwndPageTree->SetItemImage(hItem, m_Images.GetImageCount()-2, m_Images.GetImageCount()-2); - } - if (!hItem) - { - ASSERT(FALSE); - return NULL; - } - - if (strPath.IsEmpty()) - return hItem; - else - return CreatePageTreeItem(strPath, hItem); -} - - -CString CTreePropSheet::SplitPageTreePath(CString &strRest) -{ - int nSeperatorPos = 0; - for (;;) - { - nSeperatorPos = strRest.Find(_T("::"), nSeperatorPos); - if (nSeperatorPos == -1) - { - CString strItem(strRest); - strRest.Empty(); - return strItem; - } - else if (nSeperatorPos>0) - { - // if there is an odd number of backslashes infront of the - // seperator, than do not interpret it as separator - int nBackslashCount = 0; - for (int nPos = nSeperatorPos-1; nPos >= 0 && strRest[nPos]==_T('\\'); --nPos, ++nBackslashCount); - if (nBackslashCount%2 == 0) - break; - else - ++nSeperatorPos; - } - } - - CString strItem(strRest.Left(nSeperatorPos)); - strItem.Replace(_T("\\::"), _T("::")); - strItem.Replace(_T("\\\\"), _T("\\")); - strRest = strRest.Mid(nSeperatorPos+2); - return strItem; -} - - -BOOL CTreePropSheet::KillActiveCurrentPage() -{ - HWND hCurrentPage = PropSheet_GetCurrentPageHwnd(m_hWnd); - if (!IsWindow(hCurrentPage)) - { - ASSERT(FALSE); - return TRUE; - } - - // Check if the current page is really active (if page is invisible - // an virtual empty page is the active one. - if (!::IsWindowVisible(hCurrentPage)) - return TRUE; - - // Try to deactivate current page - PSHNOTIFY pshn; - pshn.hdr.code = PSN_KILLACTIVE; - pshn.hdr.hwndFrom = m_hWnd; - pshn.hdr.idFrom = GetDlgCtrlID(); - pshn.lParam = 0; - if (::SendMessage(hCurrentPage, WM_NOTIFY, pshn.hdr.idFrom, (LPARAM)&pshn)) - // current page does not allow page change - return FALSE; - - // Hide the page - ::ShowWindow(hCurrentPage, SW_HIDE); - - return TRUE; -} - - -HTREEITEM CTreePropSheet::GetPageTreeItem(int nPage, HTREEITEM hRoot /* = TVI_ROOT */) -{ - // Special handling for root case - if (hRoot == TVI_ROOT) - hRoot = m_pwndPageTree->GetNextItem(NULL, TVGN_ROOT); - - // Check parameters - if (nPage < 0 || nPage >= GetPageCount()) - { - ASSERT(FALSE); - return NULL; - } - - if (hRoot == NULL) - { - ASSERT(FALSE); - return NULL; - } - - // we are performing a simple linear search here, because we are - // expecting only little data - HTREEITEM hItem = hRoot; - while (hItem) - { - if ((signed)m_pwndPageTree->GetItemData(hItem) == nPage) - return hItem; - if (m_pwndPageTree->ItemHasChildren(hItem)) - { - HTREEITEM hResult = GetPageTreeItem(nPage, m_pwndPageTree->GetNextItem(hItem, TVGN_CHILD)); - if (hResult) - return hResult; - } - - hItem = m_pwndPageTree->GetNextItem(hItem, TVGN_NEXT); - } - - // we've found nothing, if we arrive here - return hItem; -} - - -BOOL CTreePropSheet::SelectPageTreeItem(int nPage) -{ - HTREEITEM hItem = GetPageTreeItem(nPage); - if (!hItem) - return FALSE; - - return m_pwndPageTree->SelectItem(hItem); -} - - -BOOL CTreePropSheet::SelectCurrentPageTreeItem() -{ - CTabCtrl *pTab = GetTabControl(); - if (!IsWindow(pTab->GetSafeHwnd())) - return FALSE; - - return SelectPageTreeItem(pTab->GetCurSel()); -} - - -void CTreePropSheet::UpdateCaption() -{ - HWND hPage = PropSheet_GetCurrentPageHwnd(GetSafeHwnd()); - BOOL bRealPage = IsWindow(hPage) && ::IsWindowVisible(hPage); - HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); - if (!hItem) - return; - CString strCaption = m_pwndPageTree->GetItemText(hItem); - - // if empty page, then update empty page message - if (!bRealPage) - m_pFrame->SetMsgText(GenerateEmptyPageMessage(m_strEmptyPageMessage, strCaption)); - - // if no captions are displayed, cancel here - if (!m_pFrame->GetShowCaption()) - return; - - // get tab control, to the the images from - CTabCtrl *pTabCtrl = GetTabControl(); - if (!IsWindow(pTabCtrl->GetSafeHwnd())) - { - ASSERT(FALSE); - return; - } - - if (m_bTreeImages) - { - // get image from tree - int nImage; - m_pwndPageTree->GetItemImage(hItem, nImage, nImage); - HICON hIcon = m_Images.ExtractIcon(nImage); - m_pFrame->SetCaption(strCaption, hIcon); - if (hIcon) - DestroyIcon(hIcon); - } - else if (bRealPage) - { - // get image from hidden (original) tab provided by the original - // implementation - CImageList *pImages = pTabCtrl->GetImageList(); - if (pImages) - { - TCITEM ti; - ZeroMemory(&ti, sizeof(ti)); - ti.mask = TCIF_IMAGE; - - HICON hIcon = NULL; - if (pTabCtrl->GetItem((int)m_pwndPageTree->GetItemData(hItem), &ti)) - hIcon = pImages->ExtractIcon(ti.iImage); - - m_pFrame->SetCaption(strCaption, hIcon); - if (hIcon) - DestroyIcon(hIcon); - } - else - m_pFrame->SetCaption(strCaption); - } - else - m_pFrame->SetCaption(strCaption); -} - - -void CTreePropSheet::ActivatePreviousPage() -{ - if (!IsWindow(m_hWnd)) - return; - - if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) - { - // normal tab property sheet. Simply use page index - int nPageIndex = GetActiveIndex(); - if (nPageIndex<0 || nPageIndex>=GetPageCount()) - return; - - int nPrevIndex = (nPageIndex==0)? GetPageCount()-1 : nPageIndex-1; - SetActivePage(nPrevIndex); - } - else - { - // property sheet with page tree. - // we need a more sophisticated handling here, than simply using - // the page index, because we won't skip empty pages. - // so we have to walk the page tree - HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); - ASSERT(hItem); - if (!hItem) - return; - - HTREEITEM hPrevItem = m_pwndPageTree->GetPrevSiblingItem(hItem); - if (hPrevItem) - { - while (m_pwndPageTree->ItemHasChildren(hPrevItem)) - { - hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); - while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) - hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); - } - } - else - hPrevItem = m_pwndPageTree->GetParentItem(hItem); - - if (!hPrevItem) - { - // no prev item, so cycle to the last item - hPrevItem = m_pwndPageTree->GetRootItem(); - - for (;;) - { - while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) - hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); - - if (m_pwndPageTree->ItemHasChildren(hPrevItem)) - hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); - else - break; - } - } - - if (hPrevItem) - m_pwndPageTree->SelectItem(hPrevItem); - } -} - - -void CTreePropSheet::ActivateNextPage() -{ - if (!IsWindow(m_hWnd)) - return; - - if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) - { - // normal tab property sheet. Simply use page index - int nPageIndex = GetActiveIndex(); - if (nPageIndex<0 || nPageIndex>=GetPageCount()) - return; - - int nNextIndex = (nPageIndex==GetPageCount()-1)? 0 : nPageIndex+1; - SetActivePage(nNextIndex); - } - else - { - // property sheet with page tree. - // we need a more sophisticated handling here, than simply using - // the page index, because we won't skip empty pages. - // so we have to walk the page tree - HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); - ASSERT(hItem); - if (!hItem) - return; - - HTREEITEM hNextItem = m_pwndPageTree->GetChildItem(hItem); - if (!hNextItem) - { - hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); - if (!hNextItem && m_pwndPageTree->GetParentItem(hItem)) - { - while (!hNextItem) - { - hItem = m_pwndPageTree->GetParentItem(hItem); - if (!hItem) - break; - - hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); - } - } - } - - if (!hNextItem) - // no next item -- so cycle to the first item - hNextItem = m_pwndPageTree->GetRootItem(); - - if (hNextItem) - m_pwndPageTree->SelectItem(hNextItem); - } -} - - -///////////////////////////////////////////////////////////////////// -// Overridings - -BOOL CTreePropSheet::OnInitDialog() -{ - if (m_bTreeViewMode) - { - // be sure, there are no stacked tabs, because otherwise the - // page caption will be to large in tree view mode - EnableStackedTabs(FALSE); - - // Initialize image list. - if (m_DefaultImages.GetSafeHandle()) - { - IMAGEINFO ii; - m_DefaultImages.GetImageInfo(0, &ii); - if (ii.hbmImage) DeleteObject(ii.hbmImage); - if (ii.hbmMask) DeleteObject(ii.hbmMask); - m_Images.Create(ii.rcImage.right-ii.rcImage.left, ii.rcImage.bottom-ii.rcImage.top, ILC_COLOR32|ILC_MASK, 0, 1); - } - else - m_Images.Create(16, 16, ILC_COLOR32|ILC_MASK, 0, 1); - } - - // perform default implementation - - BOOL bResult = CPropertySheet::OnInitDialog(); - - if (!m_bTreeViewMode) - // stop here, if we would like to use tabs - return bResult; - - // Get tab control... - CTabCtrl *pTab = GetTabControl(); - if (!IsWindow(pTab->GetSafeHwnd())) - { - ASSERT(FALSE); - return bResult; - } - - // ... and hide it - pTab->ShowWindow(SW_HIDE); - pTab->EnableWindow(FALSE); - - // Place another (empty) tab ctrl, to get a frame instead - CRect rectFrame; - pTab->GetWindowRect(rectFrame); - ScreenToClient(rectFrame); - - m_pFrame = CreatePageFrame(); - if (!m_pFrame) - { - ASSERT(FALSE); - AfxThrowMemoryException(); - } - m_pFrame->Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0xFFFF); - m_pFrame->ShowCaption(m_bPageCaption); - - DpiHelper dpiWindow; - dpiWindow.Override(GetParent()->GetSafeHwnd()); - - // Lets make place for the tree ctrl - const int nTreeWidth = dpiWindow.ScaleX(m_nPageTreeWidth); - const int nTreeSpace = dpiWindow.ScaleX(5); - - CRect rectSheet; - GetWindowRect(rectSheet); - rectSheet.right+= nTreeWidth; - SetWindowPos(NULL, -1, -1, rectSheet.Width(), rectSheet.Height(), SWP_NOZORDER|SWP_NOMOVE); - CenterWindow(); - - MoveChildWindows(nTreeWidth, 0); - - // Lets calculate the rectangle for the tree ctrl - CRect rectTree(rectFrame); - rectTree.right = rectTree.left + nTreeWidth - nTreeSpace; - - //originally, using a dummy tabctrl to get a default height for the caption - //tabs do not scale sanely with dpi (96->font 11 height 21, 120-> font 12 height 21), so we will scale manually - int frameCaptionHeight; - if (DpiHelper::CanUsePerMonitorV2()) { - frameCaptionHeight = dpiWindow.ScaleX(21); //hard code 21 as the 96 dpi value and scale - } else { - // calculate caption height - CTabCtrl wndTabCtrl; - wndTabCtrl.Create(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, rectFrame, this, 0x1234); - wndTabCtrl.InsertItem(0, _T("")); - CRect rectFrameCaption; - wndTabCtrl.GetItemRect(0, rectFrameCaption); - wndTabCtrl.DestroyWindow(); - - frameCaptionHeight = rectFrameCaption.Height(); - } - m_pFrame->SetCaptionHeight(frameCaptionHeight); - - // if no caption should be displayed, make the window smaller in - // height - if (!m_bPageCaption) - { - // make frame smaller - m_pFrame->GetWnd()->GetWindowRect(rectFrame); - ScreenToClient(rectFrame); - rectFrame.top+= frameCaptionHeight; - m_pFrame->GetWnd()->MoveWindow(rectFrame); - - // move all child windows up - MoveChildWindows(0, -frameCaptionHeight); - - // modify rectangle for the tree ctrl - rectTree.bottom-= frameCaptionHeight; - - // make us smaller - CRect rect; - GetWindowRect(rect); - rect.top+= frameCaptionHeight/2; - rect.bottom-= frameCaptionHeight-frameCaptionHeight/2; - if (GetParent()) - GetParent()->ScreenToClient(rect); - MoveWindow(rect); - } - - // finally create the tree control - const DWORD dwTreeStyle = TVS_SHOWSELALWAYS|TVS_TRACKSELECT|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS; - m_pwndPageTree = CreatePageTreeObject(); - if (!m_pwndPageTree) - { - ASSERT(FALSE); - AfxThrowMemoryException(); - } - - // MFC7-support here (Thanks to Rainer Wollgarten) - // YT: Cast tree control to CWnd and calls CWnd::CreateEx in all cases (VC 6 and7). - ((CWnd*)m_pwndPageTree)->CreateEx( - WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY|TVS_EX_DOUBLEBUFFER, - _T("SysTreeView32"), _T("PageTree"), - WS_TABSTOP|WS_CHILD|WS_VISIBLE|dwTreeStyle, - rectTree, this, s_unPageTreeId); - - if (m_bTreeImages) - { - m_pwndPageTree->SetImageList(&m_Images, TVSIL_NORMAL); - m_pwndPageTree->SetImageList(&m_Images, TVSIL_STATE); - } - - //SetWindowTheme(m_pwndPageTree->GetSafeHwnd(), L"Explorer", NULL); - SetTreeCtrlTheme(m_pwndPageTree); - - // Fill the tree ctrl - RefillPageTree(); - - // Select item for the current page - if (pTab->GetCurSel() > -1) - SelectPageTreeItem(pTab->GetCurSel()); - - return bResult; -} - - -void CTreePropSheet::OnDestroy() -{ - CPropertySheet::OnDestroy(); - - if (m_Images.GetSafeHandle()) - m_Images.DeleteImageList(); - - delete m_pwndPageTree; - m_pwndPageTree = NULL; - - if (m_pFrame) { - CWnd* frameWnd = m_pFrame->GetWnd(); - if (nullptr != frameWnd && IsWindow(frameWnd->m_hWnd)) frameWnd->DestroyWindow(); //fix memory leak of CWnd - delete m_pFrame; - m_pFrame = NULL; - } -} - - -LRESULT CTreePropSheet::OnAddPage(WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = DefWindowProc(PSM_ADDPAGE, wParam, lParam); - if (!m_bTreeViewMode) - return lResult; - - RefillPageTree(); - SelectCurrentPageTreeItem(); - - return lResult; -} - - -LRESULT CTreePropSheet::OnRemovePage(WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = DefWindowProc(PSM_REMOVEPAGE, wParam, lParam); - if (!m_bTreeViewMode) - return lResult; - - RefillPageTree(); - SelectCurrentPageTreeItem(); - - return lResult; -} - - -LRESULT CTreePropSheet::OnSetCurSel(WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam); - if (!m_bTreeViewMode) - return lResult; - - SelectCurrentPageTreeItem(); - UpdateCaption(); - return lResult; -} - -LRESULT CTreePropSheet::OnSetCurSelId(WPARAM wParam, LPARAM lParam) -{ - return OnSetCurSel(wParam, lParam); -} - - -void CTreePropSheet::OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult) -{ - *plResult = 0; - if (m_bPageTreeSelChangedActive) - return; - else - m_bPageTreeSelChangedActive = TRUE; - - NMTREEVIEW *pTvn = reinterpret_cast(pNotifyStruct); - int nPage = (int)m_pwndPageTree->GetItemData(pTvn->itemNew.hItem); - if (nPage < 0) - { - HTREEITEM nextItem = m_pwndPageTree->GetChildItem(pTvn->itemNew.hItem); - nPage = (int)m_pwndPageTree->GetItemData(nextItem); - } - BOOL bResult; - if (nPage >= (int)m_pwndPageTree->GetCount()) - bResult = KillActiveCurrentPage(); - else - bResult = SetActivePage(nPage); - - if (!bResult) - // prevent selection to change - *plResult = TRUE; - - // Set focus to tree ctrl (I guess that's what the user expects) - m_pwndPageTree->SetFocus(); - - m_bPageTreeSelChangedActive = FALSE; - - return; -} - - -void CTreePropSheet::OnPageTreeSelChanged(NMHDR * /*pNotifyStruct*/, LRESULT *plResult) -{ - *plResult = 0; - - UpdateCaption(); - - return; -} - - -LRESULT CTreePropSheet::OnIsDialogMessage(WPARAM wParam, LPARAM lParam) -{ - MSG *pMsg = reinterpret_cast(lParam); - if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_TAB && GetKeyState(VK_CONTROL)&0x8000) - { - if (GetKeyState(VK_SHIFT)&0x8000) - ActivatePreviousPage(); - else - ActivateNextPage(); - return TRUE; - } - - - return CPropertySheet::DefWindowProc(PSM_ISDIALOGMESSAGE, wParam, lParam); -} - -} //namespace TreePropSheet +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + + +#include "stdafx.h" +#include "TreePropSheet.h" +#include "PropPageFrameDefault.h" +#include "../../../src/mpc-hc/DpiHelper.h" +#include "../../../src/DSUtil/VersionHelpersInternal.h" + +namespace TreePropSheet +{ + +//------------------------------------------------------------------- +// class CTreePropSheet +//------------------------------------------------------------------- + +BEGIN_MESSAGE_MAP(CTreePropSheet, CPropertySheet) + //{{AFX_MSG_MAP(CTreePropSheet) + ON_WM_DESTROY() + //}}AFX_MSG_MAP + ON_MESSAGE(PSM_ADDPAGE, OnAddPage) + ON_MESSAGE(PSM_REMOVEPAGE, OnRemovePage) + ON_MESSAGE(PSM_SETCURSEL, OnSetCurSel) + ON_MESSAGE(PSM_SETCURSELID, OnSetCurSelId) + ON_MESSAGE(PSM_ISDIALOGMESSAGE, OnIsDialogMessage) + + ON_NOTIFY(TVN_SELCHANGINGA, s_unPageTreeId, OnPageTreeSelChanging) + ON_NOTIFY(TVN_SELCHANGINGW, s_unPageTreeId, OnPageTreeSelChanging) + ON_NOTIFY(TVN_SELCHANGEDA, s_unPageTreeId, OnPageTreeSelChanged) + ON_NOTIFY(TVN_SELCHANGEDW, s_unPageTreeId, OnPageTreeSelChanged) +END_MESSAGE_MAP() + +IMPLEMENT_DYNAMIC(CTreePropSheet, CPropertySheet) + +const UINT CTreePropSheet::s_unPageTreeId = 0x7EEE; + +CTreePropSheet::CTreePropSheet() +: CPropertySheet(), + m_bTreeViewMode(TRUE), + m_pwndPageTree(NULL), + m_pFrame(NULL), + m_bPageTreeSelChangedActive(FALSE), + m_bPageCaption(FALSE), + m_bTreeImages(FALSE), + m_nPageTreeWidth(150) +{ +} + + +CTreePropSheet::CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage) +: CPropertySheet(nIDCaption, pParentWnd, iSelectPage), + m_bTreeViewMode(TRUE), + m_pwndPageTree(NULL), + m_pFrame(NULL), + m_bPageTreeSelChangedActive(FALSE), + m_bPageCaption(FALSE), + m_bTreeImages(FALSE), + m_nPageTreeWidth(150) +{ +} + + +CTreePropSheet::CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage) +: CPropertySheet(pszCaption, pParentWnd, iSelectPage), + m_bTreeViewMode(TRUE), + m_pwndPageTree(NULL), + m_pFrame(NULL), + m_bPageTreeSelChangedActive(FALSE), + m_bPageCaption(FALSE), + m_bTreeImages(FALSE), + m_nPageTreeWidth(150) +{ +} + + +CTreePropSheet::~CTreePropSheet() +{ +} + + +///////////////////////////////////////////////////////////////////// +// Operationen + +BOOL CTreePropSheet::SetTreeViewMode(BOOL bTreeViewMode /* = TRUE */, BOOL bPageCaption /* = FALSE */, BOOL bTreeImages /* = FALSE */) +{ + if (IsWindow(m_hWnd)) + { + // needs to becalled, before the window has been created + ASSERT(FALSE); + return FALSE; + } + + m_bTreeViewMode = bTreeViewMode; + if (m_bTreeViewMode) + { + m_bPageCaption = bPageCaption; + m_bTreeImages = bTreeImages; + } + + return TRUE; +} + + +BOOL CTreePropSheet::SetTreeWidth(int nWidth) +{ + if (IsWindow(m_hWnd)) + { + // needs to be called, before the window is created. + ASSERT(FALSE); + return FALSE; + } + + m_nPageTreeWidth = nWidth; + + return TRUE; +} + + +void CTreePropSheet::SetEmptyPageText(LPCTSTR lpszEmptyPageText) +{ + m_strEmptyPageMessage = lpszEmptyPageText; +} + + +DWORD CTreePropSheet::SetEmptyPageTextFormat(DWORD dwFormat) +{ + DWORD dwPrevFormat = m_pFrame->GetMsgFormat(); + m_pFrame->SetMsgFormat(dwFormat); + return dwPrevFormat; +} + + +BOOL CTreePropSheet::SetTreeDefaultImages(CImageList *pImages) +{ + if (pImages->GetImageCount() != 2) + { + ASSERT(FALSE); + return FALSE; + } + + if (m_DefaultImages.GetSafeHandle()) + m_DefaultImages.DeleteImageList(); + m_DefaultImages.Create(pImages); + + // update, if necessary + if (IsWindow(m_hWnd)) + RefillPageTree(); + + return TRUE; +} + + +BOOL CTreePropSheet::SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask) +{ + if (m_DefaultImages.GetSafeHandle()) + m_DefaultImages.DeleteImageList(); + if (!m_DefaultImages.Create(unBitmapID, cx, 0, crMask)) + return FALSE; + + if (m_DefaultImages.GetImageCount() != 2) + { + m_DefaultImages.DeleteImageList(); + return FALSE; + } + + return TRUE; +} + + +CTreeCtrl* CTreePropSheet::GetPageTreeControl() +{ + return m_pwndPageTree; +} + + +///////////////////////////////////////////////////////////////////// +// public helpers + +BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, HICON hIcon) +{ + pPage->m_psp.dwFlags|= PSP_USEHICON; + pPage->m_psp.hIcon = hIcon; + return TRUE; +} + + +BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, UINT unIconId) +{ + HICON hIcon = AfxGetApp()->LoadIcon(unIconId); + if (!hIcon) + return FALSE; + + return SetPageIcon(pPage, hIcon); +} + + +BOOL CTreePropSheet::SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage) +{ + HICON hIcon = Images.ExtractIcon(nImage); + if (!hIcon) + return FALSE; + + return SetPageIcon(pPage, hIcon); +} + + +BOOL CTreePropSheet::DestroyPageIcon(CPropertyPage *pPage) +{ + if (!pPage || !(pPage->m_psp.dwFlags&PSP_USEHICON) || !pPage->m_psp.hIcon) + return FALSE; + + DestroyIcon(pPage->m_psp.hIcon); + pPage->m_psp.dwFlags&= ~PSP_USEHICON; + pPage->m_psp.hIcon = NULL; + + return TRUE; +} + + +///////////////////////////////////////////////////////////////////// +// Overridable implementation helpers + +CString CTreePropSheet::GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption) +{ + CString strMsg; + strMsg.Format(lpszEmptyPageMessage, lpszCaption); + return strMsg; +} + + +CTreeCtrl* CTreePropSheet::CreatePageTreeObject() +{ + return new CTreeCtrl; +} + +//added for mpc-hc theming +void CTreePropSheet::SetTreeCtrlTheme(CTreeCtrl *ctrl) { + SetWindowTheme(ctrl->GetSafeHwnd(), L"Explorer", NULL); +} + + +CPropPageFrame* CTreePropSheet::CreatePageFrame() +{ + return new CPropPageFrameDefault; +} + + +///////////////////////////////////////////////////////////////////// +// Implementation helpers + +void CTreePropSheet::MoveChildWindows(int nDx, int nDy) +{ + CWnd *pWnd = GetWindow(GW_CHILD); + while (pWnd) + { + CRect rect; + pWnd->GetWindowRect(rect); + ScreenToClient(rect); + rect.OffsetRect(nDx, nDy); + pWnd->MoveWindow(rect); + + pWnd = pWnd->GetNextWindow(); + } +} + + +void CTreePropSheet::RefillPageTree() +{ + if (!IsWindow(m_hWnd)) + return; + + m_pwndPageTree->DeleteAllItems(); + + CTabCtrl *pTabCtrl = GetTabControl(); + if (!IsWindow(pTabCtrl->GetSafeHwnd())) + { + ASSERT(FALSE); + return; + } + + const int nPageCount = pTabCtrl->GetItemCount(); + + // rebuild image list + if (m_bTreeImages) + { + for (int i = m_Images.GetImageCount()-1; i >= 0; --i) + m_Images.Remove(i); + + // add page images + CImageList *pPageImages = pTabCtrl->GetImageList(); + if (pPageImages) + { + for (int nImage = 0; nImage < pPageImages->GetImageCount(); ++nImage) + { + HICON hIcon = pPageImages->ExtractIcon(nImage); + m_Images.Add(hIcon); + DestroyIcon(hIcon); + } + } + + // add default images + if (m_DefaultImages.GetSafeHandle()) + { + HICON hIcon; + + // add default images + hIcon = m_DefaultImages.ExtractIcon(0); + if (hIcon) + { + m_Images.Add(hIcon); + DestroyIcon(hIcon); + } + hIcon = m_DefaultImages.ExtractIcon(1); + { + m_Images.Add(hIcon); + DestroyIcon(hIcon); + } + } + } + + // insert tree items + for (int nPage = 0; nPage < nPageCount; ++nPage) + { + // Get title and image of the page + CString strPagePath; + + TCITEM ti; + ZeroMemory(&ti, sizeof(ti)); + ti.mask = TCIF_TEXT|TCIF_IMAGE; + ti.cchTextMax = MAX_PATH; + ti.pszText = strPagePath.GetBuffer(ti.cchTextMax); + ASSERT(ti.pszText); + if (!ti.pszText) + return; + + pTabCtrl->GetItem(nPage, &ti); + strPagePath.ReleaseBuffer(); + + // Create an item in the tree for the page + HTREEITEM hItem = CreatePageTreeItem(ti.pszText); + ASSERT(hItem); + if (hItem) + { + m_pwndPageTree->SetItemData(hItem, nPage); + + // set image + if (m_bTreeImages) + { + int nImage = ti.iImage; + if (nImage < 0 || nImage >= m_Images.GetImageCount()) + nImage = m_DefaultImages.GetSafeHandle()? m_Images.GetImageCount()-1 : -1; + + m_pwndPageTree->SetItemImage(hItem, nImage, nImage); + } + m_pwndPageTree->Expand(m_pwndPageTree->GetParentItem(hItem), TVE_EXPAND); + } + } +} + + +HTREEITEM CTreePropSheet::CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent /* = TVI_ROOT */) +{ + CString strPath(lpszPath); + CString strTopMostItem(SplitPageTreePath(strPath)); + + // Check if an item with the given text does already exist + HTREEITEM hItem = NULL; + HTREEITEM hChild = m_pwndPageTree->GetChildItem(hParent); + while (hChild) + { + if (m_pwndPageTree->GetItemText(hChild) == strTopMostItem) + { + hItem = hChild; + break; + } + hChild = m_pwndPageTree->GetNextItem(hChild, TVGN_NEXT); + } + + // If item with that text does not already exist, create a new one + if (!hItem) + { + hItem = m_pwndPageTree->InsertItem(strTopMostItem, hParent); + m_pwndPageTree->SetItemData(hItem, (DWORD_PTR)-1); + if (!strPath.IsEmpty() && m_bTreeImages && m_DefaultImages.GetSafeHandle()) + // set folder image + m_pwndPageTree->SetItemImage(hItem, m_Images.GetImageCount()-2, m_Images.GetImageCount()-2); + } + if (!hItem) + { + ASSERT(FALSE); + return NULL; + } + + if (strPath.IsEmpty()) + return hItem; + else + return CreatePageTreeItem(strPath, hItem); +} + + +CString CTreePropSheet::SplitPageTreePath(CString &strRest) +{ + int nSeperatorPos = 0; + for (;;) + { + nSeperatorPos = strRest.Find(_T("::"), nSeperatorPos); + if (nSeperatorPos == -1) + { + CString strItem(strRest); + strRest.Empty(); + return strItem; + } + else if (nSeperatorPos>0) + { + // if there is an odd number of backslashes infront of the + // seperator, than do not interpret it as separator + int nBackslashCount = 0; + for (int nPos = nSeperatorPos-1; nPos >= 0 && strRest[nPos]==_T('\\'); --nPos, ++nBackslashCount); + if (nBackslashCount%2 == 0) + break; + else + ++nSeperatorPos; + } + } + + CString strItem(strRest.Left(nSeperatorPos)); + strItem.Replace(_T("\\::"), _T("::")); + strItem.Replace(_T("\\\\"), _T("\\")); + strRest = strRest.Mid(nSeperatorPos+2); + return strItem; +} + + +BOOL CTreePropSheet::KillActiveCurrentPage() +{ + HWND hCurrentPage = PropSheet_GetCurrentPageHwnd(m_hWnd); + if (!IsWindow(hCurrentPage)) + { + ASSERT(FALSE); + return TRUE; + } + + // Check if the current page is really active (if page is invisible + // an virtual empty page is the active one. + if (!::IsWindowVisible(hCurrentPage)) + return TRUE; + + // Try to deactivate current page + PSHNOTIFY pshn; + pshn.hdr.code = PSN_KILLACTIVE; + pshn.hdr.hwndFrom = m_hWnd; + pshn.hdr.idFrom = GetDlgCtrlID(); + pshn.lParam = 0; + if (::SendMessage(hCurrentPage, WM_NOTIFY, pshn.hdr.idFrom, (LPARAM)&pshn)) + // current page does not allow page change + return FALSE; + + // Hide the page + ::ShowWindow(hCurrentPage, SW_HIDE); + + return TRUE; +} + + +HTREEITEM CTreePropSheet::GetPageTreeItem(int nPage, HTREEITEM hRoot /* = TVI_ROOT */) +{ + // Special handling for root case + if (hRoot == TVI_ROOT) + hRoot = m_pwndPageTree->GetNextItem(NULL, TVGN_ROOT); + + // Check parameters + if (nPage < 0 || nPage >= GetPageCount()) + { + ASSERT(FALSE); + return NULL; + } + + if (hRoot == NULL) + { + ASSERT(FALSE); + return NULL; + } + + // we are performing a simple linear search here, because we are + // expecting only little data + HTREEITEM hItem = hRoot; + while (hItem) + { + if ((signed)m_pwndPageTree->GetItemData(hItem) == nPage) + return hItem; + if (m_pwndPageTree->ItemHasChildren(hItem)) + { + HTREEITEM hResult = GetPageTreeItem(nPage, m_pwndPageTree->GetNextItem(hItem, TVGN_CHILD)); + if (hResult) + return hResult; + } + + hItem = m_pwndPageTree->GetNextItem(hItem, TVGN_NEXT); + } + + // we've found nothing, if we arrive here + return hItem; +} + + +BOOL CTreePropSheet::SelectPageTreeItem(int nPage) +{ + HTREEITEM hItem = GetPageTreeItem(nPage); + if (!hItem) + return FALSE; + + return m_pwndPageTree->SelectItem(hItem); +} + + +BOOL CTreePropSheet::SelectCurrentPageTreeItem() +{ + CTabCtrl *pTab = GetTabControl(); + if (!IsWindow(pTab->GetSafeHwnd())) + return FALSE; + + return SelectPageTreeItem(pTab->GetCurSel()); +} + + +void CTreePropSheet::UpdateCaption() +{ + HWND hPage = PropSheet_GetCurrentPageHwnd(GetSafeHwnd()); + BOOL bRealPage = IsWindow(hPage) && ::IsWindowVisible(hPage); + HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); + if (!hItem) + return; + CString strCaption = m_pwndPageTree->GetItemText(hItem); + + // if empty page, then update empty page message + if (!bRealPage) + m_pFrame->SetMsgText(GenerateEmptyPageMessage(m_strEmptyPageMessage, strCaption)); + + // if no captions are displayed, cancel here + if (!m_pFrame->GetShowCaption()) + return; + + // get tab control, to the the images from + CTabCtrl *pTabCtrl = GetTabControl(); + if (!IsWindow(pTabCtrl->GetSafeHwnd())) + { + ASSERT(FALSE); + return; + } + + if (m_bTreeImages) + { + // get image from tree + int nImage; + m_pwndPageTree->GetItemImage(hItem, nImage, nImage); + HICON hIcon = m_Images.ExtractIcon(nImage); + m_pFrame->SetCaption(strCaption, hIcon); + if (hIcon) + DestroyIcon(hIcon); + } + else if (bRealPage) + { + // get image from hidden (original) tab provided by the original + // implementation + CImageList *pImages = pTabCtrl->GetImageList(); + if (pImages) + { + TCITEM ti; + ZeroMemory(&ti, sizeof(ti)); + ti.mask = TCIF_IMAGE; + + HICON hIcon = NULL; + if (pTabCtrl->GetItem((int)m_pwndPageTree->GetItemData(hItem), &ti)) + hIcon = pImages->ExtractIcon(ti.iImage); + + m_pFrame->SetCaption(strCaption, hIcon); + if (hIcon) + DestroyIcon(hIcon); + } + else + m_pFrame->SetCaption(strCaption); + } + else + m_pFrame->SetCaption(strCaption); +} + + +void CTreePropSheet::ActivatePreviousPage() +{ + if (!IsWindow(m_hWnd)) + return; + + if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) + { + // normal tab property sheet. Simply use page index + int nPageIndex = GetActiveIndex(); + if (nPageIndex<0 || nPageIndex>=GetPageCount()) + return; + + int nPrevIndex = (nPageIndex==0)? GetPageCount()-1 : nPageIndex-1; + SetActivePage(nPrevIndex); + } + else + { + // property sheet with page tree. + // we need a more sophisticated handling here, than simply using + // the page index, because we won't skip empty pages. + // so we have to walk the page tree + HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); + ASSERT(hItem); + if (!hItem) + return; + + HTREEITEM hPrevItem = m_pwndPageTree->GetPrevSiblingItem(hItem); + if (hPrevItem) + { + while (m_pwndPageTree->ItemHasChildren(hPrevItem)) + { + hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); + while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) + hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); + } + } + else + hPrevItem = m_pwndPageTree->GetParentItem(hItem); + + if (!hPrevItem) + { + // no prev item, so cycle to the last item + hPrevItem = m_pwndPageTree->GetRootItem(); + + for (;;) + { + while (m_pwndPageTree->GetNextSiblingItem(hPrevItem)) + hPrevItem = m_pwndPageTree->GetNextSiblingItem(hPrevItem); + + if (m_pwndPageTree->ItemHasChildren(hPrevItem)) + hPrevItem = m_pwndPageTree->GetChildItem(hPrevItem); + else + break; + } + } + + if (hPrevItem) + m_pwndPageTree->SelectItem(hPrevItem); + } +} + + +void CTreePropSheet::ActivateNextPage() +{ + if (!IsWindow(m_hWnd)) + return; + + if (!IsWindow(m_pwndPageTree->GetSafeHwnd())) + { + // normal tab property sheet. Simply use page index + int nPageIndex = GetActiveIndex(); + if (nPageIndex<0 || nPageIndex>=GetPageCount()) + return; + + int nNextIndex = (nPageIndex==GetPageCount()-1)? 0 : nPageIndex+1; + SetActivePage(nNextIndex); + } + else + { + // property sheet with page tree. + // we need a more sophisticated handling here, than simply using + // the page index, because we won't skip empty pages. + // so we have to walk the page tree + HTREEITEM hItem = m_pwndPageTree->GetSelectedItem(); + ASSERT(hItem); + if (!hItem) + return; + + HTREEITEM hNextItem = m_pwndPageTree->GetChildItem(hItem); + if (!hNextItem) + { + hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); + if (!hNextItem && m_pwndPageTree->GetParentItem(hItem)) + { + while (!hNextItem) + { + hItem = m_pwndPageTree->GetParentItem(hItem); + if (!hItem) + break; + + hNextItem = m_pwndPageTree->GetNextSiblingItem(hItem); + } + } + } + + if (!hNextItem) + // no next item -- so cycle to the first item + hNextItem = m_pwndPageTree->GetRootItem(); + + if (hNextItem) + m_pwndPageTree->SelectItem(hNextItem); + } +} + + +///////////////////////////////////////////////////////////////////// +// Overridings + +BOOL CTreePropSheet::OnInitDialog() +{ + if (m_bTreeViewMode) + { + // be sure, there are no stacked tabs, because otherwise the + // page caption will be to large in tree view mode + EnableStackedTabs(FALSE); + + // Initialize image list. + if (m_DefaultImages.GetSafeHandle()) + { + IMAGEINFO ii; + m_DefaultImages.GetImageInfo(0, &ii); + if (ii.hbmImage) DeleteObject(ii.hbmImage); + if (ii.hbmMask) DeleteObject(ii.hbmMask); + m_Images.Create(ii.rcImage.right-ii.rcImage.left, ii.rcImage.bottom-ii.rcImage.top, ILC_COLOR32|ILC_MASK, 0, 1); + } + else + m_Images.Create(16, 16, ILC_COLOR32|ILC_MASK, 0, 1); + } + + // perform default implementation + + BOOL bResult = CPropertySheet::OnInitDialog(); + + if (!m_bTreeViewMode) + // stop here, if we would like to use tabs + return bResult; + + // Get tab control... + CTabCtrl *pTab = GetTabControl(); + if (!IsWindow(pTab->GetSafeHwnd())) + { + ASSERT(FALSE); + return bResult; + } + + // ... and hide it + pTab->ShowWindow(SW_HIDE); + pTab->EnableWindow(FALSE); + + // Place another (empty) tab ctrl, to get a frame instead + CRect rectFrame; + pTab->GetWindowRect(rectFrame); + ScreenToClient(rectFrame); + + m_pFrame = CreatePageFrame(); + if (!m_pFrame) + { + ASSERT(FALSE); + AfxThrowMemoryException(); + } + m_pFrame->Create(WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, rectFrame, this, 0xFFFF); + m_pFrame->ShowCaption(m_bPageCaption); + + DpiHelper dpiWindow; + dpiWindow.Override(GetParent()->GetSafeHwnd()); + + // Lets make place for the tree ctrl + const int nTreeWidth = dpiWindow.ScaleX(m_nPageTreeWidth); + const int nTreeSpace = dpiWindow.ScaleX(5); + + CRect rectSheet; + GetWindowRect(rectSheet); + rectSheet.right+= nTreeWidth; + SetWindowPos(NULL, -1, -1, rectSheet.Width(), rectSheet.Height(), SWP_NOZORDER|SWP_NOMOVE); + CenterWindow(); + + MoveChildWindows(nTreeWidth, 0); + + // Lets calculate the rectangle for the tree ctrl + CRect rectTree(rectFrame); + rectTree.right = rectTree.left + nTreeWidth - nTreeSpace; + + //originally, using a dummy tabctrl to get a default height for the caption + //tabs do not scale sanely with dpi (96->font 11 height 21, 120-> font 12 height 21), so we will scale manually + int frameCaptionHeight; + if (DpiHelper::CanUsePerMonitorV2()) { + frameCaptionHeight = dpiWindow.ScaleX(21); //hard code 21 as the 96 dpi value and scale + } else { + // calculate caption height + CTabCtrl wndTabCtrl; + wndTabCtrl.Create(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, rectFrame, this, 0x1234); + wndTabCtrl.InsertItem(0, _T("")); + CRect rectFrameCaption; + wndTabCtrl.GetItemRect(0, rectFrameCaption); + wndTabCtrl.DestroyWindow(); + + frameCaptionHeight = rectFrameCaption.Height(); + } + m_pFrame->SetCaptionHeight(frameCaptionHeight); + + // if no caption should be displayed, make the window smaller in + // height + if (!m_bPageCaption) + { + // make frame smaller + m_pFrame->GetWnd()->GetWindowRect(rectFrame); + ScreenToClient(rectFrame); + rectFrame.top+= frameCaptionHeight; + m_pFrame->GetWnd()->MoveWindow(rectFrame); + + // move all child windows up + MoveChildWindows(0, -frameCaptionHeight); + + // modify rectangle for the tree ctrl + rectTree.bottom-= frameCaptionHeight; + + // make us smaller + CRect rect; + GetWindowRect(rect); + rect.top+= frameCaptionHeight/2; + rect.bottom-= frameCaptionHeight-frameCaptionHeight/2; + if (GetParent()) + GetParent()->ScreenToClient(rect); + MoveWindow(rect); + } + + // finally create the tree control + const DWORD dwTreeStyle = TVS_SHOWSELALWAYS|TVS_TRACKSELECT|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS; + m_pwndPageTree = CreatePageTreeObject(); + if (!m_pwndPageTree) + { + ASSERT(FALSE); + AfxThrowMemoryException(); + } + + // MFC7-support here (Thanks to Rainer Wollgarten) + // YT: Cast tree control to CWnd and calls CWnd::CreateEx in all cases (VC 6 and7). + ((CWnd*)m_pwndPageTree)->CreateEx( + WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY|TVS_EX_DOUBLEBUFFER, + _T("SysTreeView32"), _T("PageTree"), + WS_TABSTOP|WS_CHILD|WS_VISIBLE|dwTreeStyle, + rectTree, this, s_unPageTreeId); + + if (m_bTreeImages) + { + m_pwndPageTree->SetImageList(&m_Images, TVSIL_NORMAL); + m_pwndPageTree->SetImageList(&m_Images, TVSIL_STATE); + } + + //SetWindowTheme(m_pwndPageTree->GetSafeHwnd(), L"Explorer", NULL); + SetTreeCtrlTheme(m_pwndPageTree); + + // Fill the tree ctrl + RefillPageTree(); + + // Select item for the current page + if (pTab->GetCurSel() > -1) + SelectPageTreeItem(pTab->GetCurSel()); + + return bResult; +} + + +void CTreePropSheet::OnDestroy() +{ + CPropertySheet::OnDestroy(); + + if (m_Images.GetSafeHandle()) + m_Images.DeleteImageList(); + + delete m_pwndPageTree; + m_pwndPageTree = NULL; + + if (m_pFrame) { + CWnd* frameWnd = m_pFrame->GetWnd(); + if (nullptr != frameWnd && IsWindow(frameWnd->m_hWnd)) frameWnd->DestroyWindow(); //fix memory leak of CWnd + delete m_pFrame; + m_pFrame = NULL; + } +} + + +LRESULT CTreePropSheet::OnAddPage(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = DefWindowProc(PSM_ADDPAGE, wParam, lParam); + if (!m_bTreeViewMode) + return lResult; + + RefillPageTree(); + SelectCurrentPageTreeItem(); + + return lResult; +} + + +LRESULT CTreePropSheet::OnRemovePage(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = DefWindowProc(PSM_REMOVEPAGE, wParam, lParam); + if (!m_bTreeViewMode) + return lResult; + + RefillPageTree(); + SelectCurrentPageTreeItem(); + + return lResult; +} + + +LRESULT CTreePropSheet::OnSetCurSel(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = DefWindowProc(PSM_SETCURSEL, wParam, lParam); + if (!m_bTreeViewMode) + return lResult; + + SelectCurrentPageTreeItem(); + UpdateCaption(); + return lResult; +} + +LRESULT CTreePropSheet::OnSetCurSelId(WPARAM wParam, LPARAM lParam) +{ + return OnSetCurSel(wParam, lParam); +} + + +void CTreePropSheet::OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult) +{ + *plResult = 0; + if (m_bPageTreeSelChangedActive) + return; + else + m_bPageTreeSelChangedActive = TRUE; + + NMTREEVIEW *pTvn = reinterpret_cast(pNotifyStruct); + int nPage = (int)m_pwndPageTree->GetItemData(pTvn->itemNew.hItem); + if (nPage < 0) + { + HTREEITEM nextItem = m_pwndPageTree->GetChildItem(pTvn->itemNew.hItem); + nPage = (int)m_pwndPageTree->GetItemData(nextItem); + } + BOOL bResult; + if (nPage >= (int)m_pwndPageTree->GetCount()) + bResult = KillActiveCurrentPage(); + else + bResult = SetActivePage(nPage); + + if (!bResult) + // prevent selection to change + *plResult = TRUE; + + // Set focus to tree ctrl (I guess that's what the user expects) + m_pwndPageTree->SetFocus(); + + m_bPageTreeSelChangedActive = FALSE; + + return; +} + + +void CTreePropSheet::OnPageTreeSelChanged(NMHDR * /*pNotifyStruct*/, LRESULT *plResult) +{ + *plResult = 0; + + UpdateCaption(); + + return; +} + + +LRESULT CTreePropSheet::OnIsDialogMessage(WPARAM wParam, LPARAM lParam) +{ + MSG *pMsg = reinterpret_cast(lParam); + if (pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_TAB && GetKeyState(VK_CONTROL)&0x8000) + { + if (GetKeyState(VK_SHIFT)&0x8000) + ActivatePreviousPage(); + else + ActivateNextPage(); + return TRUE; + } + + + return CPropertySheet::DefWindowProc(PSM_ISDIALOGMESSAGE, wParam, lParam); +} + +} //namespace TreePropSheet diff --git a/src/thirdparty/TreePropSheet/TreePropSheet.h b/src/thirdparty/TreePropSheet/TreePropSheet.h index 99523c1510b..654c13d720f 100644 --- a/src/thirdparty/TreePropSheet/TreePropSheet.h +++ b/src/thirdparty/TreePropSheet/TreePropSheet.h @@ -1,487 +1,487 @@ -/******************************************************************** -* -* Copyright (c) 2002 Sven Wiegand -* -* You can use this and modify this in any way you want, -* BUT LEAVE THIS HEADER INTACT. -* -* Redistribution is appreciated. -* -* $Workfile:$ -* $Revision:$ -* $Modtime:$ -* $Author:$ -* -* Revision History: -* $History:$ -* -*********************************************************************/ - - -#if !defined(AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_) -#define AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include "PropPageFrame.h" -#include -#include // Needed for CPropertySheet -#include // Needed for CTreeCtrl - -namespace TreePropSheet -{ - -/** -A property sheet, which can use a tree control instead of a tab -control, to give the user access to the different pages. - -You can use it exactly the same way, as a CPropertySheet object. -Simply create CPropertyPage objects and add them via AddPage() to -the sheet. If you would like to use the tree view mode (default), -you can specify the path of the pages in the tree, by their name: -The names of the pages can contain -double colons ("::"), which will specify the path of that page in the -tree control. I.e. if you have three pages with the following names: -1. _T("Appearance::Toolbars") -2. _T("Appearance::Menus") -3. _T("Directories") -the tree would look as follow: -\verbatim -Appearance -| -+-Toolbars -| -+-Menus - -Directories -\endverbatim -If you would like to use a double colon, which should not be -interpreted as a path seperator, prefix it with a backslash ("\\::"). - -To disable tree view mode and use the standard tabbed mode, call -the SetTreeViewMode() method. This also allows you, to enable page -captions and tree images for tree view mode. If you would like to -have images in the tree, but not all of your pages specify images or -there are tree view items, which are not attached to a page (only -parent items for real page items), you have to set default images -using the SetTreeDefaultImages() method -- otherwise their may appear -display errors. - -If the user selects a tree view item, which does not belong to a page, -because it is just a parent item for real page items, no page will -be displayed, instead a message will be displayed, that can be set -via SetEmptyPageText(). - -@author Sven Wiegand -*/ -class /*AFX_EXT_CLASS*/ CTreePropSheet : public CPropertySheet -{ - DECLARE_DYNAMIC(CTreePropSheet) - -// Construction/Destruction -public: - CTreePropSheet(); - CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); - CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); - virtual ~CTreePropSheet(); - -// Operations -public: - /** - Call this method, if you would like to use a tree control to browse - the pages, instead of the tab control. - - This method needs to becalled, before DoModal() or Create(). If the - window has already been created, the method will fail. - - @param bTreeViewMode - Pass TRUE to provide a tree view control instead of a tab control - to browse the pages, pass FALSE to use the normal tab control. - @param bPageCaption - TRUE if a caption should be displayed for each page. The caption - contains the page title and an icon if specified with the page. - Ignored if bTreeViewMode is FALSE. - @param bTreeImages - TRUE if the page icons should be displayed in the page tree, - FALSE if there should be no icons in the page tree. Ignored if - bTreeViewMode is FALSE. If not all of your pages are containing - icons, or if there will be empty pages (parent nodes without a - related page, you need to call SetTreeDefaultImages() to avoid - display errors. - - @return - TRUE on success or FALSE, if the window has already been created. - */ - BOOL SetTreeViewMode(BOOL bTreeViewMode = TRUE, BOOL bPageCaption = FALSE, BOOL bTreeImages = FALSE); - - /** - Specifies the width of the tree control, when the sheet is in tree - view mode. The default value (if this method is not called) is 150 - pixels. - - This method needs to be called, before DoModeal() or Create(). - Otherwise it will fail. - - @param nWidth - The width in pixels for the page tree. - - @return - TRUE on success, FALSE otherwise (if the window has already been - created). - */ - BOOL SetTreeWidth(int nWidth); - - /** - Specifies the text to be drawn on empty pages (pages for tree view - items, that are not related to a page, because they are only - parents for other items). This is only needed in tree view mode. - - The specified text can contains a single "%s" placeholder which - will be replaced with the title of the empty page. - */ - void SetEmptyPageText(LPCTSTR lpszEmptyPageText); - - /** - Allows you to specify, how the empty page message (see - SetEmptyPageText()) should be drawn. - - @param dwFormat - A combination of the DT_* flags available for the Win32-API - function DrawText(), that should be used to draw the text. - The default value is: - \code - DT_CENTER|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE - \endcode - - @return - The previous format. - */ - DWORD SetEmptyPageTextFormat(DWORD dwFormat); - - //@{ - /** - Defines the images, that should be used for pages without icons and - for empty parent nodes. The list contains exactly to images: - 1. An image that should be used for parent tree nodes, without a - page asignd. - 2. An image that should be used for pages, which are not specifying - any icons. - Standard image size is 16x16 Pixels, but if you call this method - before creating the sheet, the size of image 0 in this list will - be assumed as your preferred image size and all other icons must - have the same size. - - @param pImages - Pointer to an image list with exactly to images, that should be - used as default images. The images are copied to an internal - list, so that the given list can be deleted after this call. - @param unBitmapID - Resource identifier for the bitmap, that contains the default - images. The resource should contain exactly to images. - @param cx - Width of a singe image in pixels. - @param crMask - Color that should be interpreted as transparent. - - @return - TRUE on success, FALSE otherwise. - */ - BOOL SetTreeDefaultImages(CImageList *pImages); - BOOL SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask); - //@} - - /** - Returns a pointer to the tree control, when the sheet is in - tree view mode, NULL otherwise. - */ - CTreeCtrl* GetPageTreeControl(); - -// Public helpers -public: - //@{ - /** - This helper allows you to easily set the icon of a property page. - - This static method does nothing more, than extracting the specified - image as an icon from the given image list and assign the - icon-handle to the hIcon property of the pages PROPSHEETPAGE - structure (m_psp) and modify the structures flags, so that the - image will be recognized. - - You need to call this method for a page, before adding the page - to a property sheet. - - @important - If you are using the CImageList-version, you are responsible for - destroying the extracted icon with DestroyIcon() or the static - DestroyPageIcon() method. - - @see DestroyPageIcon() - - @param pPage - Property page to set the image for. - @param hIcon - Handle to icon that should be set for the page. - @param unIconId - Ressource identifier for the icon to set. - @param Images - Reference of the image list to extract the icon from. - @param nImage - Zero based index of the image in pImages, that should be used - as an icon. - - @return - TRUE on success, FALSE if an error occured. - */ - static BOOL SetPageIcon(CPropertyPage *pPage, HICON hIcon); - static BOOL SetPageIcon(CPropertyPage *pPage, UINT unIconId); - static BOOL SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage); - //@} - - /** - Checks, if the PSP_USEHICON flag is set in the PROPSHEETPAGE struct; - If this is the case, the flag will be removed and the icon - specified by the hIcon attribute of the PROPSHEETPAGE struct will - be destroyed using DestroyIcon(). - - @note - You only have to call DestroyIcon() for icons, that have been - created using CreateIconIndirect() (i.e. used by - CImageList::ExtractIcon()). - - @return - TRUE on success, FALSE if the PSP_USEHICON flag was not set or - if the icon handle was NULL. - */ - static BOOL DestroyPageIcon(CPropertyPage *pPage); - -// Overridable implementation helpers -protected: - /** - Will be called to generate the message, that should be displayed on - an empty page, when the sheet is in tree view mode - - This default implementation simply returns lpszEmptyPageMessage - with the optional "%s" placeholder replaced by lpszCaption. - - @param lpszEmptyPageMessage - The string, set by SetEmptyPageMessage(). This string may contain - a "%s" placeholder. - @param lpszCaption - The title of the empty page. - */ - virtual CString GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption); - - /** - Will be called during creation process, to create the CTreeCtrl - object (the object, not the window!). - - Allows you to inject your own CTreeCtrl-derived classes. - - This default implementation simply creates a CTreeCtrl with new - and returns it. - */ - virtual CTreeCtrl* CreatePageTreeObject(); - - //added for mpc-hc theming - virtual void SetTreeCtrlTheme(CTreeCtrl* ctrl); - - /** - Will be called during creation process, to create the object, that - is responsible for drawing the frame around the pages, drawing the - empty page message and the caption. - - Allows you to inject your own CPropPageFrame-derived classes. - - This default implementation simply creates a CPropPageFrameTab with - new and returns it. - */ - virtual CPropPageFrame* CreatePageFrame(); - -// Implementation helpers -protected: - /** - Moves all childs by the specified amount of pixels. - - @param nDx - Pixels to move the childs in horizontal direction (can be - negative). - @param nDy - Pixels to move the childs in vertical direction (can be - negative). - */ - void MoveChildWindows(int nDx, int nDy); - - /** - Refills the tree that contains the entries for the several pages. - */ - void RefillPageTree(); - - /** - Creates the specified path in the page tree and returns the handle - of the most child item created. - - @param lpszPath - Path of the item to create (see description of this class). - @param hParentItem - Handle of the item under which the path should be created or - TVI_ROOT to start from the root. - */ - HTREEITEM CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent = TVI_ROOT); - - /** - Splits the given path into the topmost item and the rest. See - description of this class for detailed path information. - - I.e. when given the string "Appearance::Toolbars::Customize", the - method will return "Appearance" and after the call strRest will - be "Toolbars::Customize". - */ - CString SplitPageTreePath(CString &strRest); - - /** - Tries to deactivate the current page, and hides it if successfull, - so that an empty page becomes visible. - - @return - TRUE if the current page has been deactivated successfully, - FALSE if the currently active page prevents a page change. - */ - BOOL KillActiveCurrentPage(); - - /** - Returns the page tree item, that representates the specified page - or NULL, if no such icon exists. - - @param nPage - Zero based page index, for which the item to retrieve. - @param hRoot - Item to start the search at or TVI_ROOT to search the whole - tree. - */ - HTREEITEM GetPageTreeItem(int nPage, HTREEITEM hRoot = TVI_ROOT); - - /** - Selects and shows the item, representing the specified page. - - @param nPage - Zero based page index. - - @return - TRUE on success, FALSE if no item does exist for the specified - page. - */ - BOOL SelectPageTreeItem(int nPage); - - /** - Selects and shows the tree item for the currently active page. - - @return - TRUE on success, FALSE if no item exists for the currently active - page or if it was not possible to get information about the - currently active page. - */ - BOOL SelectCurrentPageTreeItem(); - - /** - Updates the caption for the currently selected page (if the caption - is enabled). - */ - void UpdateCaption(); - - /** - Activates the previous page in the page order or the last one, if - the current one is the first. - - This method does never fail. - */ - void ActivatePreviousPage(); - - /** - Activates the next page in the page order or the first one, if the - current one is the last. - - This method does never fail. - */ - void ActivateNextPage(); - -// Overridings -protected: - //{{AFX_VIRTUAL(CTreePropSheet) - public: - virtual BOOL OnInitDialog(); - //}}AFX_VIRTUAL - -// Message handlers -protected: - //{{AFX_MSG(CTreePropSheet) - afx_msg void OnDestroy(); - //}}AFX_MSG - afx_msg LRESULT OnAddPage(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnRemovePage(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnSetCurSel(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnSetCurSelId(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnIsDialogMessage(WPARAM wParam, LPARAM lParam); - - afx_msg void OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult); - afx_msg void OnPageTreeSelChanged(NMHDR *pNotifyStruct, LRESULT *plResult); - DECLARE_MESSAGE_MAP() - -// Properties -private: - /** TRUE if we should use the tree control instead of the tab ctrl. */ - BOOL m_bTreeViewMode; - - /** The tree control */ - CTreeCtrl *m_pwndPageTree; - -protected: - /** The frame around the pages */ - CPropPageFrame *m_pFrame; - -private: - /** - TRUE, if a tree item selection by OnPageTreeSelChanged() is - performed currently. - */ - BOOL m_bPageTreeSelChangedActive; - - /** TRUE if a page caption should be displayed, FALSE otherwise. */ - BOOL m_bPageCaption; - - /** TRUE if images should be displayed in the tree. */ - BOOL m_bTreeImages; - - /** Images to be displayed in the tree control. */ - CImageList m_Images; - - /** Default images. */ - CImageList m_DefaultImages; - - /** - Message to be displayed on empty pages. May contain a "%s" - placeholder which will be replaced by the caption of the empty - page. - */ - CString m_strEmptyPageMessage; - - /** The width of the page tree control in pixels. */ - int m_nPageTreeWidth; - -// Static Properties -private: - /** The id of the tree view control, that shows the pages. */ - static const UINT s_unPageTreeId; -}; - - -} //namespace TreePropSheet - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_ +/******************************************************************** +* +* Copyright (c) 2002 Sven Wiegand +* +* You can use this and modify this in any way you want, +* BUT LEAVE THIS HEADER INTACT. +* +* Redistribution is appreciated. +* +* $Workfile:$ +* $Revision:$ +* $Modtime:$ +* $Author:$ +* +* Revision History: +* $History:$ +* +*********************************************************************/ + + +#if !defined(AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_) +#define AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "PropPageFrame.h" +#include +#include // Needed for CPropertySheet +#include // Needed for CTreeCtrl + +namespace TreePropSheet +{ + +/** +A property sheet, which can use a tree control instead of a tab +control, to give the user access to the different pages. + +You can use it exactly the same way, as a CPropertySheet object. +Simply create CPropertyPage objects and add them via AddPage() to +the sheet. If you would like to use the tree view mode (default), +you can specify the path of the pages in the tree, by their name: +The names of the pages can contain +double colons ("::"), which will specify the path of that page in the +tree control. I.e. if you have three pages with the following names: +1. _T("Appearance::Toolbars") +2. _T("Appearance::Menus") +3. _T("Directories") +the tree would look as follow: +\verbatim +Appearance +| ++-Toolbars +| ++-Menus + +Directories +\endverbatim +If you would like to use a double colon, which should not be +interpreted as a path seperator, prefix it with a backslash ("\\::"). + +To disable tree view mode and use the standard tabbed mode, call +the SetTreeViewMode() method. This also allows you, to enable page +captions and tree images for tree view mode. If you would like to +have images in the tree, but not all of your pages specify images or +there are tree view items, which are not attached to a page (only +parent items for real page items), you have to set default images +using the SetTreeDefaultImages() method -- otherwise their may appear +display errors. + +If the user selects a tree view item, which does not belong to a page, +because it is just a parent item for real page items, no page will +be displayed, instead a message will be displayed, that can be set +via SetEmptyPageText(). + +@author Sven Wiegand +*/ +class /*AFX_EXT_CLASS*/ CTreePropSheet : public CPropertySheet +{ + DECLARE_DYNAMIC(CTreePropSheet) + +// Construction/Destruction +public: + CTreePropSheet(); + CTreePropSheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); + CTreePropSheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0); + virtual ~CTreePropSheet(); + +// Operations +public: + /** + Call this method, if you would like to use a tree control to browse + the pages, instead of the tab control. + + This method needs to becalled, before DoModal() or Create(). If the + window has already been created, the method will fail. + + @param bTreeViewMode + Pass TRUE to provide a tree view control instead of a tab control + to browse the pages, pass FALSE to use the normal tab control. + @param bPageCaption + TRUE if a caption should be displayed for each page. The caption + contains the page title and an icon if specified with the page. + Ignored if bTreeViewMode is FALSE. + @param bTreeImages + TRUE if the page icons should be displayed in the page tree, + FALSE if there should be no icons in the page tree. Ignored if + bTreeViewMode is FALSE. If not all of your pages are containing + icons, or if there will be empty pages (parent nodes without a + related page, you need to call SetTreeDefaultImages() to avoid + display errors. + + @return + TRUE on success or FALSE, if the window has already been created. + */ + BOOL SetTreeViewMode(BOOL bTreeViewMode = TRUE, BOOL bPageCaption = FALSE, BOOL bTreeImages = FALSE); + + /** + Specifies the width of the tree control, when the sheet is in tree + view mode. The default value (if this method is not called) is 150 + pixels. + + This method needs to be called, before DoModeal() or Create(). + Otherwise it will fail. + + @param nWidth + The width in pixels for the page tree. + + @return + TRUE on success, FALSE otherwise (if the window has already been + created). + */ + BOOL SetTreeWidth(int nWidth); + + /** + Specifies the text to be drawn on empty pages (pages for tree view + items, that are not related to a page, because they are only + parents for other items). This is only needed in tree view mode. + + The specified text can contains a single "%s" placeholder which + will be replaced with the title of the empty page. + */ + void SetEmptyPageText(LPCTSTR lpszEmptyPageText); + + /** + Allows you to specify, how the empty page message (see + SetEmptyPageText()) should be drawn. + + @param dwFormat + A combination of the DT_* flags available for the Win32-API + function DrawText(), that should be used to draw the text. + The default value is: + \code + DT_CENTER|DT_VCENTER|DT_NOPREFIX|DT_SINGLELINE + \endcode + + @return + The previous format. + */ + DWORD SetEmptyPageTextFormat(DWORD dwFormat); + + //@{ + /** + Defines the images, that should be used for pages without icons and + for empty parent nodes. The list contains exactly to images: + 1. An image that should be used for parent tree nodes, without a + page asignd. + 2. An image that should be used for pages, which are not specifying + any icons. + Standard image size is 16x16 Pixels, but if you call this method + before creating the sheet, the size of image 0 in this list will + be assumed as your preferred image size and all other icons must + have the same size. + + @param pImages + Pointer to an image list with exactly to images, that should be + used as default images. The images are copied to an internal + list, so that the given list can be deleted after this call. + @param unBitmapID + Resource identifier for the bitmap, that contains the default + images. The resource should contain exactly to images. + @param cx + Width of a singe image in pixels. + @param crMask + Color that should be interpreted as transparent. + + @return + TRUE on success, FALSE otherwise. + */ + BOOL SetTreeDefaultImages(CImageList *pImages); + BOOL SetTreeDefaultImages(UINT unBitmapID, int cx, COLORREF crMask); + //@} + + /** + Returns a pointer to the tree control, when the sheet is in + tree view mode, NULL otherwise. + */ + CTreeCtrl* GetPageTreeControl(); + +// Public helpers +public: + //@{ + /** + This helper allows you to easily set the icon of a property page. + + This static method does nothing more, than extracting the specified + image as an icon from the given image list and assign the + icon-handle to the hIcon property of the pages PROPSHEETPAGE + structure (m_psp) and modify the structures flags, so that the + image will be recognized. + + You need to call this method for a page, before adding the page + to a property sheet. + + @important + If you are using the CImageList-version, you are responsible for + destroying the extracted icon with DestroyIcon() or the static + DestroyPageIcon() method. + + @see DestroyPageIcon() + + @param pPage + Property page to set the image for. + @param hIcon + Handle to icon that should be set for the page. + @param unIconId + Ressource identifier for the icon to set. + @param Images + Reference of the image list to extract the icon from. + @param nImage + Zero based index of the image in pImages, that should be used + as an icon. + + @return + TRUE on success, FALSE if an error occured. + */ + static BOOL SetPageIcon(CPropertyPage *pPage, HICON hIcon); + static BOOL SetPageIcon(CPropertyPage *pPage, UINT unIconId); + static BOOL SetPageIcon(CPropertyPage *pPage, CImageList &Images, int nImage); + //@} + + /** + Checks, if the PSP_USEHICON flag is set in the PROPSHEETPAGE struct; + If this is the case, the flag will be removed and the icon + specified by the hIcon attribute of the PROPSHEETPAGE struct will + be destroyed using DestroyIcon(). + + @note + You only have to call DestroyIcon() for icons, that have been + created using CreateIconIndirect() (i.e. used by + CImageList::ExtractIcon()). + + @return + TRUE on success, FALSE if the PSP_USEHICON flag was not set or + if the icon handle was NULL. + */ + static BOOL DestroyPageIcon(CPropertyPage *pPage); + +// Overridable implementation helpers +protected: + /** + Will be called to generate the message, that should be displayed on + an empty page, when the sheet is in tree view mode + + This default implementation simply returns lpszEmptyPageMessage + with the optional "%s" placeholder replaced by lpszCaption. + + @param lpszEmptyPageMessage + The string, set by SetEmptyPageMessage(). This string may contain + a "%s" placeholder. + @param lpszCaption + The title of the empty page. + */ + virtual CString GenerateEmptyPageMessage(LPCTSTR lpszEmptyPageMessage, LPCTSTR lpszCaption); + + /** + Will be called during creation process, to create the CTreeCtrl + object (the object, not the window!). + + Allows you to inject your own CTreeCtrl-derived classes. + + This default implementation simply creates a CTreeCtrl with new + and returns it. + */ + virtual CTreeCtrl* CreatePageTreeObject(); + + //added for mpc-hc theming + virtual void SetTreeCtrlTheme(CTreeCtrl* ctrl); + + /** + Will be called during creation process, to create the object, that + is responsible for drawing the frame around the pages, drawing the + empty page message and the caption. + + Allows you to inject your own CPropPageFrame-derived classes. + + This default implementation simply creates a CPropPageFrameTab with + new and returns it. + */ + virtual CPropPageFrame* CreatePageFrame(); + +// Implementation helpers +protected: + /** + Moves all childs by the specified amount of pixels. + + @param nDx + Pixels to move the childs in horizontal direction (can be + negative). + @param nDy + Pixels to move the childs in vertical direction (can be + negative). + */ + void MoveChildWindows(int nDx, int nDy); + + /** + Refills the tree that contains the entries for the several pages. + */ + void RefillPageTree(); + + /** + Creates the specified path in the page tree and returns the handle + of the most child item created. + + @param lpszPath + Path of the item to create (see description of this class). + @param hParentItem + Handle of the item under which the path should be created or + TVI_ROOT to start from the root. + */ + HTREEITEM CreatePageTreeItem(LPCTSTR lpszPath, HTREEITEM hParent = TVI_ROOT); + + /** + Splits the given path into the topmost item and the rest. See + description of this class for detailed path information. + + I.e. when given the string "Appearance::Toolbars::Customize", the + method will return "Appearance" and after the call strRest will + be "Toolbars::Customize". + */ + CString SplitPageTreePath(CString &strRest); + + /** + Tries to deactivate the current page, and hides it if successfull, + so that an empty page becomes visible. + + @return + TRUE if the current page has been deactivated successfully, + FALSE if the currently active page prevents a page change. + */ + BOOL KillActiveCurrentPage(); + + /** + Returns the page tree item, that representates the specified page + or NULL, if no such icon exists. + + @param nPage + Zero based page index, for which the item to retrieve. + @param hRoot + Item to start the search at or TVI_ROOT to search the whole + tree. + */ + HTREEITEM GetPageTreeItem(int nPage, HTREEITEM hRoot = TVI_ROOT); + + /** + Selects and shows the item, representing the specified page. + + @param nPage + Zero based page index. + + @return + TRUE on success, FALSE if no item does exist for the specified + page. + */ + BOOL SelectPageTreeItem(int nPage); + + /** + Selects and shows the tree item for the currently active page. + + @return + TRUE on success, FALSE if no item exists for the currently active + page or if it was not possible to get information about the + currently active page. + */ + BOOL SelectCurrentPageTreeItem(); + + /** + Updates the caption for the currently selected page (if the caption + is enabled). + */ + void UpdateCaption(); + + /** + Activates the previous page in the page order or the last one, if + the current one is the first. + + This method does never fail. + */ + void ActivatePreviousPage(); + + /** + Activates the next page in the page order or the first one, if the + current one is the last. + + This method does never fail. + */ + void ActivateNextPage(); + +// Overridings +protected: + //{{AFX_VIRTUAL(CTreePropSheet) + public: + virtual BOOL OnInitDialog(); + //}}AFX_VIRTUAL + +// Message handlers +protected: + //{{AFX_MSG(CTreePropSheet) + afx_msg void OnDestroy(); + //}}AFX_MSG + afx_msg LRESULT OnAddPage(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnRemovePage(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnSetCurSel(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnSetCurSelId(WPARAM wParam, LPARAM lParam); + afx_msg LRESULT OnIsDialogMessage(WPARAM wParam, LPARAM lParam); + + afx_msg void OnPageTreeSelChanging(NMHDR *pNotifyStruct, LRESULT *plResult); + afx_msg void OnPageTreeSelChanged(NMHDR *pNotifyStruct, LRESULT *plResult); + DECLARE_MESSAGE_MAP() + +// Properties +private: + /** TRUE if we should use the tree control instead of the tab ctrl. */ + BOOL m_bTreeViewMode; + + /** The tree control */ + CTreeCtrl *m_pwndPageTree; + +protected: + /** The frame around the pages */ + CPropPageFrame *m_pFrame; + +private: + /** + TRUE, if a tree item selection by OnPageTreeSelChanged() is + performed currently. + */ + BOOL m_bPageTreeSelChangedActive; + + /** TRUE if a page caption should be displayed, FALSE otherwise. */ + BOOL m_bPageCaption; + + /** TRUE if images should be displayed in the tree. */ + BOOL m_bTreeImages; + + /** Images to be displayed in the tree control. */ + CImageList m_Images; + + /** Default images. */ + CImageList m_DefaultImages; + + /** + Message to be displayed on empty pages. May contain a "%s" + placeholder which will be replaced by the caption of the empty + page. + */ + CString m_strEmptyPageMessage; + + /** The width of the page tree control in pixels. */ + int m_nPageTreeWidth; + +// Static Properties +private: + /** The id of the tree view control, that shows the pages. */ + static const UINT s_unPageTreeId; +}; + + +} //namespace TreePropSheet + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // AFX_TREEPROPSHEET_H__50695CFB_FCE4_4188_ADB4_BF05A5488E41__INCLUDED_ diff --git a/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj b/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj index a5037f90b76..1d2ef5681fd 100644 --- a/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj +++ b/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj @@ -1,65 +1,65 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {AB494732-EF6D-44D0-BCF8-80FF04858D10} - TreePropSheet - MFCProj - TreePropSheet - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - - - - - - - Create - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {AB494732-EF6D-44D0-BCF8-80FF04858D10} + TreePropSheet + MFCProj + TreePropSheet + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + + + + + + + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj.filters b/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj.filters index 766b5176dab..236ef81d662 100644 --- a/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj.filters +++ b/src/thirdparty/TreePropSheet/TreePropSheet.vcxproj.filters @@ -1,41 +1,41 @@ - - - - - {669fa26f-0c7f-40c4-bc82-db7a76c85378} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {7bde8366-984f-44a0-8338-3a69a9e0511d} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {669fa26f-0c7f-40c4-bc82-db7a76c85378} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {7bde8366-984f-44a0-8338-3a69a9e0511d} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/TreePropSheet/stdafx.cpp b/src/thirdparty/TreePropSheet/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/thirdparty/TreePropSheet/stdafx.cpp +++ b/src/thirdparty/TreePropSheet/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/thirdparty/TreePropSheet/stdafx.h b/src/thirdparty/TreePropSheet/stdafx.h index 62396238601..fbfc4a00442 100644 --- a/src/thirdparty/TreePropSheet/stdafx.h +++ b/src/thirdparty/TreePropSheet/stdafx.h @@ -1,34 +1,34 @@ -/* - * (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 . - * - */ - -#pragma once - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#endif - -#include -#include // MFC core and standard components +/* + * (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 . + * + */ + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +#include +#include // MFC core and standard components diff --git a/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj b/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj index e90487408a8..c7dd043a18f 100644 --- a/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj +++ b/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj @@ -1,200 +1,200 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {0D252872-7542-4232-8D02-53F9182AEE15} - Kasumi - Kasumi - - - - - StaticLibrary - - - - - - - - - - - - - - h;..\h;%(AdditionalIncludeDirectories) - _LIB;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - - - - - - - - - true - - - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - - - - - {c2082189-3ecb-4079-91fa-89d3c8a305c0} - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {0D252872-7542-4232-8D02-53F9182AEE15} + Kasumi + Kasumi + + + + + StaticLibrary + + + + + + + + + + + + + + h;..\h;%(AdditionalIncludeDirectories) + _LIB;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + + + + + + + + + true + + + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + + + + + {c2082189-3ecb-4079-91fa-89d3c8a305c0} + + + + + + \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj.filters b/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj.filters index f3ef6873cf0..3b185008f63 100644 --- a/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj.filters +++ b/src/thirdparty/VirtualDub/Kasumi/Kasumi.vcxproj.filters @@ -1,324 +1,324 @@ - - - - - {0ee6e95d-30d8-431b-a0e0-af0605aaaa63} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {e512fbf3-a14d-4853-af1c-c78f14330e75} - h;hpp;hxx;hm;inl - - - {93bf2ee2-032d-4f6c-8392-c34c36b1cebe} - asm - - - {c5b06aa4-1b08-48f7-b9af-c897dc7e5267} - - - {98a60592-632a-4eeb-9953-045c541d14a4} - .asm64 - - - {97dabd7e-4b11-43ae-beee-a7e675367b2e} - - - {b69f77b1-cab6-4c5c-9c28-736eb17ce889} - - - {8d72d2d5-c182-4c11-aa60-d0a265b0f440} - - - {8e7ccb0e-3ac7-4207-9c64-a24b5028014f} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files %28x86%29 - - - Source Files %28x86%29 - - - Source Files %28x86%29 - - - Source Files %28x86%29 - - - Source Files %28x64%29 - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Interface Header Files - - - Interface Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28x86%29 - - - Assembly files %28AMD64%29 - - - - - - Source Data Files - - - Autogenerated Header Files - - + + + + + {0ee6e95d-30d8-431b-a0e0-af0605aaaa63} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {e512fbf3-a14d-4853-af1c-c78f14330e75} + h;hpp;hxx;hm;inl + + + {93bf2ee2-032d-4f6c-8392-c34c36b1cebe} + asm + + + {c5b06aa4-1b08-48f7-b9af-c897dc7e5267} + + + {98a60592-632a-4eeb-9953-045c541d14a4} + .asm64 + + + {97dabd7e-4b11-43ae-beee-a7e675367b2e} + + + {b69f77b1-cab6-4c5c-9c28-736eb17ce889} + + + {8d72d2d5-c182-4c11-aa60-d0a265b0f440} + + + {8e7ccb0e-3ac7-4207-9c64-a24b5028014f} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files %28x86%29 + + + Source Files %28x86%29 + + + Source Files %28x86%29 + + + Source Files %28x86%29 + + + Source Files %28x64%29 + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Interface Header Files + + + Interface Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28x86%29 + + + Assembly files %28AMD64%29 + + + + + + Source Data Files + + + Autogenerated Header Files + + \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/h/bitutils.h b/src/thirdparty/VirtualDub/Kasumi/h/bitutils.h index 7a0c1a359b6..8cba85ffda0 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/bitutils.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/bitutils.h @@ -1,26 +1,26 @@ -#ifndef f_VD2_KASUMI_BITUTILS_H -#define f_VD2_KASUMI_BITUTILS_H - -#include - -namespace nsVDPixmapBitUtils { - inline uint32 avg_8888_11(uint32 x, uint32 y) { - return (x|y) - (((x^y)&0xfefefefe)>>1); - } - - inline uint32 avg_8888_121(uint32 x, uint32 y, uint32 z) { - return avg_8888_11(avg_8888_11(x,z), y); - } - - inline uint32 avg_0808_14641(uint32 a, uint32 b, uint32 c, uint32 d, uint32 e) { - a &= 0xff00ff; - b &= 0xff00ff; - c &= 0xff00ff; - d &= 0xff00ff; - e &= 0xff00ff; - - return (((a+e) + 4*(b+d) + 6*c + 0x080008)&0x0ff00ff0)>>4; - } -}; - -#endif +#ifndef f_VD2_KASUMI_BITUTILS_H +#define f_VD2_KASUMI_BITUTILS_H + +#include + +namespace nsVDPixmapBitUtils { + inline uint32 avg_8888_11(uint32 x, uint32 y) { + return (x|y) - (((x^y)&0xfefefefe)>>1); + } + + inline uint32 avg_8888_121(uint32 x, uint32 y, uint32 z) { + return avg_8888_11(avg_8888_11(x,z), y); + } + + inline uint32 avg_0808_14641(uint32 a, uint32 b, uint32 c, uint32 d, uint32 e) { + a &= 0xff00ff; + b &= 0xff00ff; + c &= 0xff00ff; + d &= 0xff00ff; + e &= 0xff00ff; + + return (((a+e) + 4*(b+d) + 6*c + 0x080008)&0x0ff00ff0)>>4; + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/blt_setup.h b/src/thirdparty/VirtualDub/Kasumi/h/blt_setup.h index af0620dd1c6..19b7bc62ca1 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/blt_setup.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/blt_setup.h @@ -1,62 +1,62 @@ -#ifndef f_VD2_KASUMI_BLT_SETUP_H -#define f_VD2_KASUMI_BLT_SETUP_H - -#include -#include - -typedef void (*VDPixmapPalettedBlitterFn)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal); -typedef void (*VDPixmapChunkyBlitterFn)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); - -void VDPixmapBltDirectPalettedConversion(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h, VDPixmapPalettedBlitterFn pBlitter); - -template -void VDPixmapBlitterPalettedAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) -{ - if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) - palettedBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h, src.palette); - else - VDPixmapBltDirectPalettedConversion(dst, src, w, h, palettedBlitter); -} - -template -void VDPixmapBlitterChunkyAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) -{ - chunkyBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h); -} - -struct VDPixmapFormatSubset { -public: - VDPixmapFormatSubset() : mFormatCount(0) {} - - VDPixmapFormatSubset& operator=(int format) { - mFormatCount = 0; - mFormats[mFormatCount++] = format; - return *this; - } - - VDPixmapFormatSubset& operator,(int format) { - VDASSERT(mFormatCount < nsVDPixmap::kPixFormat_Max_Standard); - mFormats[mFormatCount++] = format; - return *this; - } - - int mFormatCount; - int mFormats[nsVDPixmap::kPixFormat_Max_Standard]; -}; - -class VDPixmapBlitterTable { -public: - void Clear(); - void AddBlitter(int srcFormat, int dstFormat, VDPixmapBlitterFn blitter); - void AddBlitter(const VDPixmapFormatSubset& srcFormats, VDPixmapFormatSubset& dstFormats, VDPixmapBlitterFn blitter); - - VDPixmapBlitterFn mTable[nsVDPixmap::kPixFormat_Max_Standard][nsVDPixmap::kPixFormat_Max_Standard]; -}; - -inline void VDPixmapBlitterTable::AddBlitter(int srcFormat, int dstFormat, VDPixmapBlitterFn blitter) { - mTable[srcFormat][dstFormat] = blitter; -} - - - -#endif +#ifndef f_VD2_KASUMI_BLT_SETUP_H +#define f_VD2_KASUMI_BLT_SETUP_H + +#include +#include + +typedef void (*VDPixmapPalettedBlitterFn)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal); +typedef void (*VDPixmapChunkyBlitterFn)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); + +void VDPixmapBltDirectPalettedConversion(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h, VDPixmapPalettedBlitterFn pBlitter); + +template +void VDPixmapBlitterPalettedAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) +{ + if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) + palettedBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h, src.palette); + else + VDPixmapBltDirectPalettedConversion(dst, src, w, h, palettedBlitter); +} + +template +void VDPixmapBlitterChunkyAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) +{ + chunkyBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h); +} + +struct VDPixmapFormatSubset { +public: + VDPixmapFormatSubset() : mFormatCount(0) {} + + VDPixmapFormatSubset& operator=(int format) { + mFormatCount = 0; + mFormats[mFormatCount++] = format; + return *this; + } + + VDPixmapFormatSubset& operator,(int format) { + VDASSERT(mFormatCount < nsVDPixmap::kPixFormat_Max_Standard); + mFormats[mFormatCount++] = format; + return *this; + } + + int mFormatCount; + int mFormats[nsVDPixmap::kPixFormat_Max_Standard]; +}; + +class VDPixmapBlitterTable { +public: + void Clear(); + void AddBlitter(int srcFormat, int dstFormat, VDPixmapBlitterFn blitter); + void AddBlitter(const VDPixmapFormatSubset& srcFormats, VDPixmapFormatSubset& dstFormats, VDPixmapBlitterFn blitter); + + VDPixmapBlitterFn mTable[nsVDPixmap::kPixFormat_Max_Standard][nsVDPixmap::kPixFormat_Max_Standard]; +}; + +inline void VDPixmapBlitterTable::AddBlitter(int srcFormat, int dstFormat, VDPixmapBlitterFn blitter) { + mTable[srcFormat][dstFormat] = blitter; +} + + + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils.h b/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils.h index ba64df6d8bd..ef723b3f825 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils.h @@ -1,23 +1,23 @@ -#ifndef f_VD2_KASUMI_BLT_SPANUTILS_H -#define f_VD2_KASUMI_BLT_SPANUTILS_H - -#include - -namespace nsVDPixmapSpanUtils { - void horiz_expand2x_centered (uint8 *dst, const uint8 *src, sint32 w); - void horiz_expand2x_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void horiz_expand4x_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void horiz_compress2x_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void horiz_compress2x_centered (uint8 *dst, const uint8 *src, sint32 w); - void horiz_compress4x_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void horiz_compress4x_centered (uint8 *dst, const uint8 *src, sint32 w); - void horiz_realign_to_centered (uint8 *dst, const uint8 *src, sint32 w); - void horiz_realign_to_coaligned (uint8 *dst, const uint8 *src, sint32 w); - void vert_expand2x_centered (uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); - void vert_expand4x_centered (uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); - void vert_compress2x_centered_fast (uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); - void vert_compress2x_centered (uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); - void vert_compress4x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); -} - -#endif +#ifndef f_VD2_KASUMI_BLT_SPANUTILS_H +#define f_VD2_KASUMI_BLT_SPANUTILS_H + +#include + +namespace nsVDPixmapSpanUtils { + void horiz_expand2x_centered (uint8 *dst, const uint8 *src, sint32 w); + void horiz_expand2x_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void horiz_expand4x_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void horiz_compress2x_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void horiz_compress2x_centered (uint8 *dst, const uint8 *src, sint32 w); + void horiz_compress4x_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void horiz_compress4x_centered (uint8 *dst, const uint8 *src, sint32 w); + void horiz_realign_to_centered (uint8 *dst, const uint8 *src, sint32 w); + void horiz_realign_to_coaligned (uint8 *dst, const uint8 *src, sint32 w); + void vert_expand2x_centered (uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); + void vert_expand4x_centered (uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); + void vert_compress2x_centered_fast (uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); + void vert_compress2x_centered (uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); + void vert_compress4x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase); +} + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils_x86.h b/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils_x86.h index 56e3b763d9c..d0893558a09 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils_x86.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/blt_spanutils_x86.h @@ -1,35 +1,35 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_BLT_SPANUTILS_X86_H -#define f_VD2_KASUMI_BLT_SPANUTILS_X86_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -namespace nsVDPixmapSpanUtils { - void horiz_expand2x_coaligned_ISSE(uint8 *dst, const uint8 *src, sint32 w); - void horiz_expand4x_coaligned_MMX(uint8 *dst, const uint8 *src, sint32 w); - void vert_expand2x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); - void vert_expand4x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); -} - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_BLT_SPANUTILS_X86_H +#define f_VD2_KASUMI_BLT_SPANUTILS_X86_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +namespace nsVDPixmapSpanUtils { + void horiz_expand2x_coaligned_ISSE(uint8 *dst, const uint8 *src, sint32 w); + void horiz_expand4x_coaligned_MMX(uint8 *dst, const uint8 *src, sint32 w); + void vert_expand2x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); + void vert_expand4x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); +} + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages.h b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages.h index 2f76d98db4b..588fda9ad19 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages.h @@ -1,80 +1,80 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_H -#define f_VD2_KASUMI_RESAMPLE_STAGES_H - -#include - -class IVDResamplerFilter; -struct VDResamplerAxis; - -class VDSteppedAllocator { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - VDSteppedAllocator(size_t initialSize = 1024); - ~VDSteppedAllocator(); - - void clear(); - void *allocate(size_type n); - -protected: - struct Block { - Block *next; - }; - - Block *mpHead; - char *mpAllocNext; - size_t mAllocLeft; - size_t mAllocNext; - size_t mAllocInit; -}; - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (common) -// -/////////////////////////////////////////////////////////////////////////// - -class IVDResamplerStage { -public: - virtual ~IVDResamplerStage() {} - -#if 0 - void *operator new(size_t n, VDSteppedAllocator& a) { - return a.allocate(n); - } - - void operator delete(void *p, VDSteppedAllocator& a) { - } - -private: - // these should NEVER be called - void operator delete(void *p) {} -#endif -}; - -class IVDResamplerSeparableRowStage2 { -public: - virtual void Init(const VDResamplerAxis& axis, uint32 srcw) = 0; - virtual void Process(void *dst, const void *src, uint32 w) = 0; -}; - -class IVDResamplerSeparableRowStage : public IVDResamplerStage { -public: - virtual IVDResamplerSeparableRowStage2 *AsRowStage2() { return NULL; } - virtual void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) = 0; - virtual int GetWindowSize() const = 0; -}; - -class IVDResamplerSeparableColStage : public IVDResamplerStage { -public: - virtual int GetWindowSize() const = 0; - virtual void Process(void *dst, const void *const *src, uint32 w, sint32 phase) = 0; -}; - -void VDResamplerGenerateTable(sint32 *dst, const IVDResamplerFilter& filter); -void VDResamplerGenerateTableF(float *dst, const IVDResamplerFilter& filter); -void VDResamplerGenerateTable2(sint32 *dst, const IVDResamplerFilter& filter, sint32 count, sint32 u, sint32 dudx); -void VDResamplerSwizzleTable(sint32 *dst, unsigned pairs); - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_H +#define f_VD2_KASUMI_RESAMPLE_STAGES_H + +#include + +class IVDResamplerFilter; +struct VDResamplerAxis; + +class VDSteppedAllocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + VDSteppedAllocator(size_t initialSize = 1024); + ~VDSteppedAllocator(); + + void clear(); + void *allocate(size_type n); + +protected: + struct Block { + Block *next; + }; + + Block *mpHead; + char *mpAllocNext; + size_t mAllocLeft; + size_t mAllocNext; + size_t mAllocInit; +}; + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (common) +// +/////////////////////////////////////////////////////////////////////////// + +class IVDResamplerStage { +public: + virtual ~IVDResamplerStage() {} + +#if 0 + void *operator new(size_t n, VDSteppedAllocator& a) { + return a.allocate(n); + } + + void operator delete(void *p, VDSteppedAllocator& a) { + } + +private: + // these should NEVER be called + void operator delete(void *p) {} +#endif +}; + +class IVDResamplerSeparableRowStage2 { +public: + virtual void Init(const VDResamplerAxis& axis, uint32 srcw) = 0; + virtual void Process(void *dst, const void *src, uint32 w) = 0; +}; + +class IVDResamplerSeparableRowStage : public IVDResamplerStage { +public: + virtual IVDResamplerSeparableRowStage2 *AsRowStage2() { return NULL; } + virtual void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) = 0; + virtual int GetWindowSize() const = 0; +}; + +class IVDResamplerSeparableColStage : public IVDResamplerStage { +public: + virtual int GetWindowSize() const = 0; + virtual void Process(void *dst, const void *const *src, uint32 w, sint32 phase) = 0; +}; + +void VDResamplerGenerateTable(sint32 *dst, const IVDResamplerFilter& filter); +void VDResamplerGenerateTableF(float *dst, const IVDResamplerFilter& filter); +void VDResamplerGenerateTable2(sint32 *dst, const IVDResamplerFilter& filter, sint32 count, sint32 u, sint32 dudx); +void VDResamplerSwizzleTable(sint32 *dst, unsigned pairs); + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_reference.h b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_reference.h index 18545c45919..296882ceb2a 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_reference.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_reference.h @@ -1,156 +1,156 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_REFERENCE_H -#define f_VD2_KASUMI_RESAMPLE_STAGES_REFERENCE_H - -#include -#include "resample_stages.h" - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (portable) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerRowStageSeparablePoint8 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparablePoint16 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparablePoint32 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparableLinear8 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - virtual void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf : public VDResamplerRowStageSeparableLinear8 { -public: - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerRowStageSeparableLinear32 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerColStageSeparableLinear8 : public IVDResamplerSeparableColStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); -}; - -class VDResamplerColStageSeparableLinear32 : public IVDResamplerSeparableColStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); -}; - -class VDResamplerRowStageSeparableTable8 : public IVDResamplerSeparableRowStage { -public: - VDResamplerRowStageSeparableTable8(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerRowStageSeparableTable32 : public IVDResamplerSeparableRowStage { -public: - VDResamplerRowStageSeparableTable32(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerRowStageSeparableTable32F : public IVDResamplerSeparableRowStage { -public: - VDResamplerRowStageSeparableTable32F(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerRowStageSeparableTable32Fx4 : public IVDResamplerSeparableRowStage { -public: - VDResamplerRowStageSeparableTable32Fx4(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerColStageSeparableTable8 : public IVDResamplerSeparableColStage { -public: - VDResamplerColStageSeparableTable8(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerColStageSeparableTable32 : public IVDResamplerSeparableColStage { -public: - VDResamplerColStageSeparableTable32(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerColStageSeparableTable32F : public IVDResamplerSeparableColStage { -public: - VDResamplerColStageSeparableTable32F(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerColStageSeparableTable32Fx4 : public IVDResamplerSeparableColStage { -public: - VDResamplerColStageSeparableTable32Fx4(const IVDResamplerFilter& filter); - - int GetWindowSize() const; - - void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_REFERENCE_H +#define f_VD2_KASUMI_RESAMPLE_STAGES_REFERENCE_H + +#include +#include "resample_stages.h" + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (portable) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerRowStageSeparablePoint8 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparablePoint16 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparablePoint32 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparableLinear8 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + virtual void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf : public VDResamplerRowStageSeparableLinear8 { +public: + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerRowStageSeparableLinear32 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerColStageSeparableLinear8 : public IVDResamplerSeparableColStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); +}; + +class VDResamplerColStageSeparableLinear32 : public IVDResamplerSeparableColStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); +}; + +class VDResamplerRowStageSeparableTable8 : public IVDResamplerSeparableRowStage { +public: + VDResamplerRowStageSeparableTable8(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerRowStageSeparableTable32 : public IVDResamplerSeparableRowStage { +public: + VDResamplerRowStageSeparableTable32(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerRowStageSeparableTable32F : public IVDResamplerSeparableRowStage { +public: + VDResamplerRowStageSeparableTable32F(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerRowStageSeparableTable32Fx4 : public IVDResamplerSeparableRowStage { +public: + VDResamplerRowStageSeparableTable32Fx4(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerColStageSeparableTable8 : public IVDResamplerSeparableColStage { +public: + VDResamplerColStageSeparableTable8(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerColStageSeparableTable32 : public IVDResamplerSeparableColStage { +public: + VDResamplerColStageSeparableTable32(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerColStageSeparableTable32F : public IVDResamplerSeparableColStage { +public: + VDResamplerColStageSeparableTable32F(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerColStageSeparableTable32Fx4 : public IVDResamplerSeparableColStage { +public: + VDResamplerColStageSeparableTable32Fx4(const IVDResamplerFilter& filter); + + int GetWindowSize() const; + + void Process(void *dst0, const void *const *src0, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x64.h b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x64.h index 814020b693c..fd719f732d0 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x64.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x64.h @@ -1,26 +1,26 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_X64_H -#define f_VD2_KASUMI_RESAMPLE_STAGES_X64_H - -#include "resample_stages_reference.h" - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE2, AMD64) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerRowStageSeparableTable32 { -public: - VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableTableColStageSSE2 : public VDResamplerColStageSeparableTable32 { -public: - VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_X64_H +#define f_VD2_KASUMI_RESAMPLE_STAGES_X64_H + +#include "resample_stages_reference.h" + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE2, AMD64) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerRowStageSeparableTable32 { +public: + VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableTableColStageSSE2 : public VDResamplerColStageSeparableTable32 { +public: + VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x86.h b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x86.h index 64e3572e1b0..41e16b23d1a 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x86.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/resample_stages_x86.h @@ -1,193 +1,193 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_X86 -#define f_VD2_KASUMI_RESAMPLE_STAGES_X86 - -#include "resample_stages_reference.h" - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (scalar, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparablePointRowStageX86 : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (MMX, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparablePointRowStageMMX : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableLinearRowStageMMX : public IVDResamplerSeparableRowStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableLinearColStageMMX : public IVDResamplerSeparableColStage { -public: - int GetWindowSize() const; - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); -}; - -class VDResamplerSeparableCubicRowStageMMX : public IVDResamplerSeparableRowStage { -public: - VDResamplerSeparableCubicRowStageMMX(double A); - - int GetWindowSize() const; - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerSeparableCubicColStageMMX : public IVDResamplerSeparableColStage { -public: - VDResamplerSeparableCubicColStageMMX(double A); - - int GetWindowSize() const; - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); - -protected: - vdblock > mFilterBank; -}; - -class VDResamplerSeparableTableRowStage8MMX : public VDResamplerRowStageSeparableTable32, public IVDResamplerSeparableRowStage2 { -public: - VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter); - - IVDResamplerSeparableRowStage2 *AsRowStage2() { return this; } - - void Init(const VDResamplerAxis& axis, uint32 srcw); - void Process(void *dst, const void *src, uint32 w); - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); - -protected: - void RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw); - - int mAlignedKernelWidth; - int mAlignedKernelSize; - ptrdiff_t mRowKernelSize; - uint32 mLastSrcWidth; - uint32 mLastDstWidth; - sint32 mLastU; - sint32 mLastDUDX; - - bool mbQuadOptimizationEnabled[4]; - int mKernelSizeByOffset[4]; - ptrdiff_t mTailOffset[4]; - - vdfastvector > mRowKernels; -}; - -class VDResamplerSeparableTableRowStageMMX : public VDResamplerRowStageSeparableTable32 { -public: - VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableTableColStage8MMX : public VDResamplerColStageSeparableTable8 { -public: - VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -class VDResamplerSeparableTableColStageMMX : public VDResamplerColStageSeparableTable32 { -public: - VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (ISSE, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE : public VDResamplerRowStageSeparableLinear8 { -public: - void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); -}; - - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE2, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparableCubicColStageSSE2 : public VDResamplerSeparableCubicColStageMMX { -public: - VDResamplerSeparableCubicColStageSSE2(double A); - - void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); -}; - -class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerSeparableTableRowStageMMX { -public: - VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); -}; - -class VDResamplerSeparableTableColStageSSE2 : public VDResamplerSeparableTableColStageMMX { -public: - VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE4.1, x86) -// -/////////////////////////////////////////////////////////////////////////// - -class VDResamplerSeparableTableRowStage8SSE41 : public VDResamplerRowStageSeparableTable32, public IVDResamplerSeparableRowStage2 { -public: - VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter); - - IVDResamplerSeparableRowStage2 *AsRowStage2() { return this; } - - void Init(const VDResamplerAxis& axis, uint32 srcw); - void Process(void *dst, const void *src, uint32 w); - void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); - -protected: - void RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw); - - int mAlignedKernelWidth; - int mAlignedKernelSize; - ptrdiff_t mRowKernelSize; - uint32 mLastSrcWidth; - uint32 mLastDstWidth; - sint32 mLastU; - sint32 mLastDUDX; - - bool mbQuadOptimizationEnabled[8]; - int mKernelSizeByOffset[8]; - ptrdiff_t mTailOffset[8]; - - vdfastvector > mRowKernels; -}; - -class VDResamplerSeparableTableColStage8SSE41 : public VDResamplerColStageSeparableTable8 { -public: - VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter); - - void Process(void *dst, const void *const *src, uint32 w, sint32 phase); -}; - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_STAGES_X86 +#define f_VD2_KASUMI_RESAMPLE_STAGES_X86 + +#include "resample_stages_reference.h" + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (scalar, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparablePointRowStageX86 : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (MMX, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparablePointRowStageMMX : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableLinearRowStageMMX : public IVDResamplerSeparableRowStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableLinearColStageMMX : public IVDResamplerSeparableColStage { +public: + int GetWindowSize() const; + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); +}; + +class VDResamplerSeparableCubicRowStageMMX : public IVDResamplerSeparableRowStage { +public: + VDResamplerSeparableCubicRowStageMMX(double A); + + int GetWindowSize() const; + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerSeparableCubicColStageMMX : public IVDResamplerSeparableColStage { +public: + VDResamplerSeparableCubicColStageMMX(double A); + + int GetWindowSize() const; + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); + +protected: + vdblock > mFilterBank; +}; + +class VDResamplerSeparableTableRowStage8MMX : public VDResamplerRowStageSeparableTable32, public IVDResamplerSeparableRowStage2 { +public: + VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter); + + IVDResamplerSeparableRowStage2 *AsRowStage2() { return this; } + + void Init(const VDResamplerAxis& axis, uint32 srcw); + void Process(void *dst, const void *src, uint32 w); + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); + +protected: + void RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw); + + int mAlignedKernelWidth; + int mAlignedKernelSize; + ptrdiff_t mRowKernelSize; + uint32 mLastSrcWidth; + uint32 mLastDstWidth; + sint32 mLastU; + sint32 mLastDUDX; + + bool mbQuadOptimizationEnabled[4]; + int mKernelSizeByOffset[4]; + ptrdiff_t mTailOffset[4]; + + vdfastvector > mRowKernels; +}; + +class VDResamplerSeparableTableRowStageMMX : public VDResamplerRowStageSeparableTable32 { +public: + VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableTableColStage8MMX : public VDResamplerColStageSeparableTable8 { +public: + VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +class VDResamplerSeparableTableColStageMMX : public VDResamplerColStageSeparableTable32 { +public: + VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (ISSE, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE : public VDResamplerRowStageSeparableLinear8 { +public: + void Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx); +}; + + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE2, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparableCubicColStageSSE2 : public VDResamplerSeparableCubicColStageMMX { +public: + VDResamplerSeparableCubicColStageSSE2(double A); + + void Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase); +}; + +class VDResamplerSeparableTableRowStageSSE2 : public VDResamplerSeparableTableRowStageMMX { +public: + VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); +}; + +class VDResamplerSeparableTableColStageSSE2 : public VDResamplerSeparableTableColStageMMX { +public: + VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE4.1, x86) +// +/////////////////////////////////////////////////////////////////////////// + +class VDResamplerSeparableTableRowStage8SSE41 : public VDResamplerRowStageSeparableTable32, public IVDResamplerSeparableRowStage2 { +public: + VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter); + + IVDResamplerSeparableRowStage2 *AsRowStage2() { return this; } + + void Init(const VDResamplerAxis& axis, uint32 srcw); + void Process(void *dst, const void *src, uint32 w); + void Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx); + +protected: + void RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw); + + int mAlignedKernelWidth; + int mAlignedKernelSize; + ptrdiff_t mRowKernelSize; + uint32 mLastSrcWidth; + uint32 mLastDstWidth; + sint32 mLastU; + sint32 mLastDUDX; + + bool mbQuadOptimizationEnabled[8]; + int mKernelSizeByOffset[8]; + ptrdiff_t mTailOffset[8]; + + vdfastvector > mRowKernels; +}; + +class VDResamplerSeparableTableColStage8SSE41 : public VDResamplerColStageSeparableTable8 { +public: + VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter); + + void Process(void *dst, const void *const *src, uint32 w, sint32 phase); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/stdafx.h b/src/thirdparty/VirtualDub/Kasumi/h/stdafx.h index 8cff036ee04..0ba6b7915bb 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/stdafx.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/stdafx.h @@ -1,22 +1,22 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include // MPC-HC patch -#include +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include // MPC-HC patch +#include #include \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit.h index e2e00ed8f8c..16116609694 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit.h @@ -1,95 +1,95 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_H -#define f_VD2_KASUMI_UBERBLIT_H - -#include -#include -#include -#include - -struct VDPixmap; - -enum VDPixmapFormatToken { - kVDPixType_1 = 0x00000001, - kVDPixType_2 = 0x00000002, - kVDPixType_4 = 0x00000003, - kVDPixType_8 = 0x00000004, - kVDPixType_555_LE = 0x00000005, - kVDPixType_565_LE = 0x00000006, - kVDPixType_1555_LE = 0x00000007, - kVDPixType_888 = 0x00000008, - kVDPixType_8888 = 0x00000009, - kVDPixType_16F_LE = 0x0000000A, - kVDPixType_16Fx4_LE = 0x0000000B, - kVDPixType_16F_16F_16F_LE = 0x0000000C, - kVDPixType_32F_LE = 0x0000000D, - kVDPixType_32Fx4_LE = 0x0000000E, - kVDPixType_32F_32F_32F_LE = 0x0000000F, - kVDPixType_8_8_8 = 0x00000010, - kVDPixType_B8G8_R8G8 = 0x00000011, // UYVY - kVDPixType_G8B8_G8R8 = 0x00000012, // YUYV - kVDPixType_V210 = 0x00000013, // v210 (4:2:2 10 bit) - kVDPixType_8_B8R8 = 0x00000014, // NV12 - kVDPixType_B8R8 = 0x00000015, - kVDPixType_Mask = 0x0000003F, - - kVDPixSamp_444 = 0x00000040, - kVDPixSamp_422 = 0x00000080, - kVDPixSamp_422_JPEG = 0x000000C0, - kVDPixSamp_420_MPEG2 = 0x00000100, - kVDPixSamp_420_MPEG2INT = 0x00000140, - kVDPixSamp_420_MPEG2INT1= 0x00000180, // MPEG-2 interlaced, top field - kVDPixSamp_420_MPEG2INT2= 0x000001C0, // MPEG-2 interlaced, bottom field - kVDPixSamp_420_MPEG1 = 0x00000200, - kVDPixSamp_420_DVPAL = 0x00000240, - kVDPixSamp_411 = 0x00000280, - kVDPixSamp_410 = 0x000002C0, - kVDPixSamp_Mask = 0x00000FC0, - kVDPixSamp_Bits = 6, - - kVDPixSpace_Pal = 0x00001000, -// kVDPixSpace_RGB = 0x00002000, - kVDPixSpace_BGR = 0x00003000, - kVDPixSpace_BGR_Studio = 0x00004000, - kVDPixSpace_Y_601 = 0x00005000, - kVDPixSpace_Y_709 = 0x00006000, - kVDPixSpace_Y_601_FR = 0x00007000, - kVDPixSpace_Y_709_FR = 0x00008000, - kVDPixSpace_YCC_601 = 0x0000B000, - kVDPixSpace_YCC_709 = 0x0000C000, - kVDPixSpace_YCC_601_FR = 0x0000D000, - kVDPixSpace_YCC_709_FR = 0x0000E000, - kVDPixSpace_Mask = 0x0003F000, -}; - -struct VDPixmapPlaneSamplingInfo { - int mX; ///< X offset of sample from center location, in 16ths of plane pixels. - int mY; ///< Y offset of sample from center location, in 16ths of plane pixels. - int mXBits; ///< Horizontal subsampling factor in bits. - int mYBits; ///< Vertical subsampling factor in bits. -}; - -struct VDPixmapSamplingInfo { - bool mbInterlaced; - VDPixmapPlaneSamplingInfo mPlane1Cr; - VDPixmapPlaneSamplingInfo mPlane1Cb; - VDPixmapPlaneSamplingInfo mPlane2Cr; - VDPixmapPlaneSamplingInfo mPlane2Cb; -}; - -uint32 VDPixmapGetFormatTokenFromFormat(int format); -const VDPixmapSamplingInfo& VDPixmapGetSamplingInfo(uint32 samplingToken); - -class IVDPixmapGen { -public: - virtual ~IVDPixmapGen() {} - virtual void AddWindowRequest(int minY, int maxY) = 0; - virtual void Start() = 0; - virtual sint32 GetWidth(int srcIndex) const = 0; - virtual sint32 GetHeight(int srcIndex) const = 0; - virtual bool IsStateful() const = 0; - virtual uint32 GetType(uint32 output) const = 0; - virtual const void *GetRow(sint32 y, uint32 output) = 0; - virtual void ProcessRow(void *dst, sint32 y) = 0; -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_H +#define f_VD2_KASUMI_UBERBLIT_H + +#include +#include +#include +#include + +struct VDPixmap; + +enum VDPixmapFormatToken { + kVDPixType_1 = 0x00000001, + kVDPixType_2 = 0x00000002, + kVDPixType_4 = 0x00000003, + kVDPixType_8 = 0x00000004, + kVDPixType_555_LE = 0x00000005, + kVDPixType_565_LE = 0x00000006, + kVDPixType_1555_LE = 0x00000007, + kVDPixType_888 = 0x00000008, + kVDPixType_8888 = 0x00000009, + kVDPixType_16F_LE = 0x0000000A, + kVDPixType_16Fx4_LE = 0x0000000B, + kVDPixType_16F_16F_16F_LE = 0x0000000C, + kVDPixType_32F_LE = 0x0000000D, + kVDPixType_32Fx4_LE = 0x0000000E, + kVDPixType_32F_32F_32F_LE = 0x0000000F, + kVDPixType_8_8_8 = 0x00000010, + kVDPixType_B8G8_R8G8 = 0x00000011, // UYVY + kVDPixType_G8B8_G8R8 = 0x00000012, // YUYV + kVDPixType_V210 = 0x00000013, // v210 (4:2:2 10 bit) + kVDPixType_8_B8R8 = 0x00000014, // NV12 + kVDPixType_B8R8 = 0x00000015, + kVDPixType_Mask = 0x0000003F, + + kVDPixSamp_444 = 0x00000040, + kVDPixSamp_422 = 0x00000080, + kVDPixSamp_422_JPEG = 0x000000C0, + kVDPixSamp_420_MPEG2 = 0x00000100, + kVDPixSamp_420_MPEG2INT = 0x00000140, + kVDPixSamp_420_MPEG2INT1= 0x00000180, // MPEG-2 interlaced, top field + kVDPixSamp_420_MPEG2INT2= 0x000001C0, // MPEG-2 interlaced, bottom field + kVDPixSamp_420_MPEG1 = 0x00000200, + kVDPixSamp_420_DVPAL = 0x00000240, + kVDPixSamp_411 = 0x00000280, + kVDPixSamp_410 = 0x000002C0, + kVDPixSamp_Mask = 0x00000FC0, + kVDPixSamp_Bits = 6, + + kVDPixSpace_Pal = 0x00001000, +// kVDPixSpace_RGB = 0x00002000, + kVDPixSpace_BGR = 0x00003000, + kVDPixSpace_BGR_Studio = 0x00004000, + kVDPixSpace_Y_601 = 0x00005000, + kVDPixSpace_Y_709 = 0x00006000, + kVDPixSpace_Y_601_FR = 0x00007000, + kVDPixSpace_Y_709_FR = 0x00008000, + kVDPixSpace_YCC_601 = 0x0000B000, + kVDPixSpace_YCC_709 = 0x0000C000, + kVDPixSpace_YCC_601_FR = 0x0000D000, + kVDPixSpace_YCC_709_FR = 0x0000E000, + kVDPixSpace_Mask = 0x0003F000, +}; + +struct VDPixmapPlaneSamplingInfo { + int mX; ///< X offset of sample from center location, in 16ths of plane pixels. + int mY; ///< Y offset of sample from center location, in 16ths of plane pixels. + int mXBits; ///< Horizontal subsampling factor in bits. + int mYBits; ///< Vertical subsampling factor in bits. +}; + +struct VDPixmapSamplingInfo { + bool mbInterlaced; + VDPixmapPlaneSamplingInfo mPlane1Cr; + VDPixmapPlaneSamplingInfo mPlane1Cb; + VDPixmapPlaneSamplingInfo mPlane2Cr; + VDPixmapPlaneSamplingInfo mPlane2Cb; +}; + +uint32 VDPixmapGetFormatTokenFromFormat(int format); +const VDPixmapSamplingInfo& VDPixmapGetSamplingInfo(uint32 samplingToken); + +class IVDPixmapGen { +public: + virtual ~IVDPixmapGen() {} + virtual void AddWindowRequest(int minY, int maxY) = 0; + virtual void Start() = 0; + virtual sint32 GetWidth(int srcIndex) const = 0; + virtual sint32 GetHeight(int srcIndex) const = 0; + virtual bool IsStateful() const = 0; + virtual uint32 GetType(uint32 output) const = 0; + virtual const void *GetRow(sint32 y, uint32 output) = 0; + virtual void ProcessRow(void *dst, sint32 y) = 0; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_16f.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_16f.h index 3ee1e2da8a5..513c4fb4ff3 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_16f.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_16f.h @@ -1,39 +1,39 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_16F_H -#define f_VD2_KASUMI_UBERBLIT_16F_H - -#include -#include "uberblit_base.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32F -> 16F -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_32F_To_16F : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start(); - - uint32 GetType(uint32 output) const; - -protected: - void Compute(void *dst0, sint32 y); -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 16F -> 32F -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_16F_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start(); - - uint32 GetType(uint32 output) const; - -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_16F_H +#define f_VD2_KASUMI_UBERBLIT_16F_H + +#include +#include "uberblit_base.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32F -> 16F +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_32F_To_16F : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start(); + + uint32 GetType(uint32 output) const; + +protected: + void Compute(void *dst0, sint32 y); +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 16F -> 32F +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_16F_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start(); + + uint32 GetType(uint32 output) const; + +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_base.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_base.h index 487bd3cef7e..e01ef73fea1 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_base.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_base.h @@ -1,129 +1,129 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_BASE_H -#define f_VD2_KASUMI_UBERBLIT_BASE_H - -#include -#include "uberblit.h" - -class VDPixmapGenWindowBased : public IVDPixmapGen { -public: - VDPixmapGenWindowBased() - : mWindowMinDY(0xffff) - , mWindowMaxDY(-0xffff) {} - - void SetOutputSize(sint32 w, sint32 h) { - mWidth = w; - mHeight = h; - } - - void AddWindowRequest(int minDY, int maxDY) { - if (mWindowMinDY > minDY) - mWindowMinDY = minDY; - if (mWindowMaxDY < maxDY) - mWindowMaxDY = maxDY; - } - - void StartWindow(uint32 rowbytes, int outputCount = 1) { - VDASSERT(mWindowMaxDY >= mWindowMinDY); - mWindowSize = mWindowMaxDY + 1 - mWindowMinDY; - - mWindowPitch = (rowbytes + 15) & ~15; - mWindowBuffer.resize(mWindowPitch * mWindowSize * outputCount); - mWindow.resize(mWindowSize * 2); - - for(sint32 i=0; i= mWindowLastY - (sint32)mWindowSize + 1); - - if (tostep >= mWindowSize) { - mWindowLastY = y - 1; - tostep = 1; - } - - while(tostep-- > 0) { - ++mWindowLastY; - Compute(mWindow[mWindowIndex], mWindowLastY); - if (++mWindowIndex >= mWindowSize) - mWindowIndex = 0; - } - - return mWindow[y + mWindowSize - 1 - mWindowLastY + mWindowIndex]; - } - - void ProcessRow(void *dst, sint32 y) { - Compute(dst, y); - } - -protected: - virtual void Compute(void *dst0, sint32 y) = 0; - - vdfastvector mWindowBuffer; - vdfastvector mWindow; - sint32 mWindowPitch; - sint32 mWindowIndex; - sint32 mWindowMinDY; - sint32 mWindowMaxDY; - sint32 mWindowSize; - sint32 mWindowLastY; - sint32 mWidth; - sint32 mHeight; -}; - -class VDPixmapGenWindowBasedOneSource : public VDPixmapGenWindowBased { -public: - void InitSource(IVDPixmapGen *src, uint32 srcindex) { - mpSrc = src; - mSrcIndex = srcindex; - mSrcWidth = src->GetWidth(srcindex); - mSrcHeight = src->GetHeight(srcindex); - mWidth = mSrcWidth; - mHeight = mSrcHeight; - } - - void AddWindowRequest(int minDY, int maxDY) { - VDPixmapGenWindowBased::AddWindowRequest(minDY, maxDY); - mpSrc->AddWindowRequest(minDY, maxDY); - } - - void StartWindow(uint32 rowbytes, int outputCount = 1) { - mpSrc->Start(); - - VDPixmapGenWindowBased::StartWindow(rowbytes, outputCount); - } - - uint32 GetType(uint32 output) const { - return mpSrc->GetType(mSrcIndex); - } - -protected: - virtual void Compute(void *dst0, sint32 y) = 0; - - IVDPixmapGen *mpSrc; - uint32 mSrcIndex; - sint32 mSrcWidth; - sint32 mSrcHeight; -}; - -class VDPixmapGenWindowBasedOneSourceSimple : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcindex) { - InitSource(src, srcindex); - - src->AddWindowRequest(0, 0); - } -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_BASE_H +#define f_VD2_KASUMI_UBERBLIT_BASE_H + +#include +#include "uberblit.h" + +class VDPixmapGenWindowBased : public IVDPixmapGen { +public: + VDPixmapGenWindowBased() + : mWindowMinDY(0xffff) + , mWindowMaxDY(-0xffff) {} + + void SetOutputSize(sint32 w, sint32 h) { + mWidth = w; + mHeight = h; + } + + void AddWindowRequest(int minDY, int maxDY) { + if (mWindowMinDY > minDY) + mWindowMinDY = minDY; + if (mWindowMaxDY < maxDY) + mWindowMaxDY = maxDY; + } + + void StartWindow(uint32 rowbytes, int outputCount = 1) { + VDASSERT(mWindowMaxDY >= mWindowMinDY); + mWindowSize = mWindowMaxDY + 1 - mWindowMinDY; + + mWindowPitch = (rowbytes + 15) & ~15; + mWindowBuffer.resize(mWindowPitch * mWindowSize * outputCount); + mWindow.resize(mWindowSize * 2); + + for(sint32 i=0; i= mWindowLastY - (sint32)mWindowSize + 1); + + if (tostep >= mWindowSize) { + mWindowLastY = y - 1; + tostep = 1; + } + + while(tostep-- > 0) { + ++mWindowLastY; + Compute(mWindow[mWindowIndex], mWindowLastY); + if (++mWindowIndex >= mWindowSize) + mWindowIndex = 0; + } + + return mWindow[y + mWindowSize - 1 - mWindowLastY + mWindowIndex]; + } + + void ProcessRow(void *dst, sint32 y) { + Compute(dst, y); + } + +protected: + virtual void Compute(void *dst0, sint32 y) = 0; + + vdfastvector mWindowBuffer; + vdfastvector mWindow; + sint32 mWindowPitch; + sint32 mWindowIndex; + sint32 mWindowMinDY; + sint32 mWindowMaxDY; + sint32 mWindowSize; + sint32 mWindowLastY; + sint32 mWidth; + sint32 mHeight; +}; + +class VDPixmapGenWindowBasedOneSource : public VDPixmapGenWindowBased { +public: + void InitSource(IVDPixmapGen *src, uint32 srcindex) { + mpSrc = src; + mSrcIndex = srcindex; + mSrcWidth = src->GetWidth(srcindex); + mSrcHeight = src->GetHeight(srcindex); + mWidth = mSrcWidth; + mHeight = mSrcHeight; + } + + void AddWindowRequest(int minDY, int maxDY) { + VDPixmapGenWindowBased::AddWindowRequest(minDY, maxDY); + mpSrc->AddWindowRequest(minDY, maxDY); + } + + void StartWindow(uint32 rowbytes, int outputCount = 1) { + mpSrc->Start(); + + VDPixmapGenWindowBased::StartWindow(rowbytes, outputCount); + } + + uint32 GetType(uint32 output) const { + return mpSrc->GetType(mSrcIndex); + } + +protected: + virtual void Compute(void *dst0, sint32 y) = 0; + + IVDPixmapGen *mpSrc; + uint32 mSrcIndex; + sint32 mSrcWidth; + sint32 mSrcHeight; +}; + +class VDPixmapGenWindowBasedOneSourceSimple : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcindex) { + InitSource(src, srcindex); + + src->AddWindowRequest(0, 0); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_fill.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_fill.h index 7d3f288ebc1..ba02a287711 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_fill.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_fill.h @@ -1,55 +1,55 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_FILL_H -#define f_VD2_KASUMI_UBERBLIT_FILL_H - -#include "uberblit.h" -#include "uberblit_base.h" - -class VDPixmapGenFill8 : public IVDPixmapGen { -public: - void Init(uint8 fill, uint32 bpr, sint32 width, sint32 height, uint32 type) { - mRow.resize(bpr, fill); - mWidth = width; - mHeight = height; - mType = type; - } - - void AddWindowRequest(int minY, int maxY) { - } - - void Start() { - } - - sint32 GetWidth(int) const { - return mWidth; - } - - sint32 GetHeight(int) const { - return mHeight; - } - - bool IsStateful() const { - return false; - } - - const void *GetRow(sint32 y, uint32 output) { - return mRow.data(); - } - - void ProcessRow(void *dst, sint32 y) { - if (!mRow.empty()) - memset(dst, mRow[0], mRow.size()); - } - - uint32 GetType(uint32 index) const { - return mType; - } - -protected: - sint32 mWidth; - sint32 mHeight; - uint32 mType; - - vdfastvector mRow; -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_FILL_H +#define f_VD2_KASUMI_UBERBLIT_FILL_H + +#include "uberblit.h" +#include "uberblit_base.h" + +class VDPixmapGenFill8 : public IVDPixmapGen { +public: + void Init(uint8 fill, uint32 bpr, sint32 width, sint32 height, uint32 type) { + mRow.resize(bpr, fill); + mWidth = width; + mHeight = height; + mType = type; + } + + void AddWindowRequest(int minY, int maxY) { + } + + void Start() { + } + + sint32 GetWidth(int) const { + return mWidth; + } + + sint32 GetHeight(int) const { + return mHeight; + } + + bool IsStateful() const { + return false; + } + + const void *GetRow(sint32 y, uint32 output) { + return mRow.data(); + } + + void ProcessRow(void *dst, sint32 y) { + if (!mRow.empty()) + memset(dst, mRow[0], mRow.size()); + } + + uint32 GetType(uint32 index) const { + return mType; + } + +protected: + sint32 mWidth; + sint32 mHeight; + uint32 mType; + + vdfastvector mRow; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_gen.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_gen.h index 0a5809b6cab..20543016134 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_gen.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_gen.h @@ -1,177 +1,177 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_GEN_H -#define f_VD2_KASUMI_UBERBLIT_GEN_H - -#include -#include "uberblit.h" - -class IVDPixmapGenSrc; -struct VDPixmapGenYCbCrBasis; - -class VDPixmapUberBlitterDirectCopy : public IVDPixmapBlitter { -public: - VDPixmapUberBlitterDirectCopy(); - ~VDPixmapUberBlitterDirectCopy(); - - void Blit(const VDPixmap& dst, const VDPixmap& src); - void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src); -}; - -class VDPixmapUberBlitter : public IVDPixmapBlitter { -public: - VDPixmapUberBlitter(); - ~VDPixmapUberBlitter(); - - void Blit(const VDPixmap& dst, const VDPixmap& src); - void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src); - -protected: - void Blit(const VDPixmap& dst, const vdrect32 *rDst); - void Blit3(const VDPixmap& dst, const vdrect32 *rDst); - void Blit3Split(const VDPixmap& dst, const vdrect32 *rDst); - void Blit3Separated(const VDPixmap& px, const vdrect32 *rDst); - void Blit2(const VDPixmap& dst, const vdrect32 *rDst); - void Blit2Separated(const VDPixmap& px, const vdrect32 *rDst); - - friend class VDPixmapUberBlitterGenerator; - - struct OutputEntry { - IVDPixmapGen *mpSrc; - int mSrcIndex; - } mOutputs[3]; - - struct SourceEntry { - IVDPixmapGenSrc *mpSrc; - int mSrcIndex; - int mSrcPlane; - int mSrcX; - int mSrcY; - }; - - typedef vdfastvector Generators; - Generators mGenerators; - - typedef vdfastvector Sources; - Sources mSources; - - bool mbIndependentChromaPlanes; - bool mbIndependentPlanes; -}; - -class VDPixmapUberBlitterGenerator { -public: - VDPixmapUberBlitterGenerator(); - ~VDPixmapUberBlitterGenerator(); - - void swap(int index); - void dup(); - void pop(); - - void ldsrc(int srcIndex, int srcPlane, int x, int y, uint32 w, uint32 h, uint32 type, uint32 bpr); - - void ldconst(uint8 fill, uint32 bpr, uint32 w, uint32 h, uint32 type); - - void extract_8in16(int offset, uint32 w, uint32 h); - void extract_8in32(int offset, uint32 w, uint32 h); - void swap_8in16(uint32 w, uint32 h, uint32 bpr); - - void conv_Pal1_to_8888(int srcIndex); - void conv_Pal2_to_8888(int srcIndex); - void conv_Pal4_to_8888(int srcIndex); - void conv_Pal8_to_8888(int srcIndex); - - void conv_555_to_8888(); - void conv_565_to_8888(); - void conv_888_to_8888(); - void conv_555_to_565(); - void conv_565_to_555(); - void conv_8888_to_X32F(); - void conv_8_to_32F(); - void conv_16F_to_32F(); - void conv_V210_to_32F(); - - void conv_8888_to_555(); - void conv_8888_to_565(); - void conv_8888_to_888(); - void conv_32F_to_8(); - void conv_X32F_to_8888(); - void conv_32F_to_16F(); - void conv_32F_to_V210(); - - void convd_8888_to_555(); - void convd_8888_to_565(); - void convd_32F_to_8(); - void convd_X32F_to_8888(); - - void interleave_B8G8_R8G8(); - void interleave_G8B8_G8R8(); - void interleave_X8R8G8B8(); - void interleave_B8R8(); - - void merge_fields(uint32 w, uint32 h, uint32 bpr); - void split_fields(uint32 bpr); - - void ycbcr601_to_rgb32(); - void ycbcr709_to_rgb32(); - void rgb32_to_ycbcr601(); - void rgb32_to_ycbcr709(); - - void ycbcr601_to_rgb32_32f(); - void ycbcr709_to_rgb32_32f(); - void rgb32_to_ycbcr601_32f(); - void rgb32_to_ycbcr709_32f(); - - void ycbcr601_to_ycbcr709(); - void ycbcr709_to_ycbcr601(); - - void ycbcr_to_rgb32_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB); - void ycbcr_to_rgb32f_generic(const VDPixmapGenYCbCrBasis& basis); - void rgb32_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB, uint32 colorSpace); - void rgb32f_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace); - void ycbcr_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basisDst, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& basisSrc, bool srcLimitedRange, uint32 colorSpace); - - void pointh(float xoffset, float xfactor, uint32 w); - void pointv(float yoffset, float yfactor, uint32 h); - void linearh(float xoffset, float xfactor, uint32 w, bool interpOnly); - void linearv(float yoffset, float yfactor, uint32 h, bool interpOnly); - void linear(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h); - void cubich(float xoffset, float xfactor, uint32 w, float splineFactor, bool interpOnly); - void cubicv(float yoffset, float yfactor, uint32 h, float splineFactor, bool interpOnly); - void cubic(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h, float splineFactor); - void lanczos3h(float xoffset, float xfactor, uint32 w); - void lanczos3v(float yoffset, float yfactor, uint32 h); - void lanczos3(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h); - - IVDPixmapBlitter *create(); - -protected: - void MarkDependency(IVDPixmapGen *dst, IVDPixmapGen *src); - - struct StackEntry { - IVDPixmapGen *mpSrc; - uint32 mSrcIndex; - - StackEntry() {} - StackEntry(IVDPixmapGen *src, uint32 index) : mpSrc(src), mSrcIndex(index) {} - }; - - vdfastvector mStack; - - typedef vdfastvector Generators; - Generators mGenerators; - - struct Dependency { - int mDstIdx; - int mSrcIdx; - }; - - vdfastvector mDependencies; - - typedef VDPixmapUberBlitter::SourceEntry SourceEntry; - vdfastvector mSources; -}; - -void VDPixmapGenerate(void *dst, ptrdiff_t pitch, sint32 bpr, sint32 height, IVDPixmapGen *gen, int genIndex); -IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmap& dst, const VDPixmap& src); -IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmapLayout& dst, const VDPixmapLayout& src); - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_GEN_H +#define f_VD2_KASUMI_UBERBLIT_GEN_H + +#include +#include "uberblit.h" + +class IVDPixmapGenSrc; +struct VDPixmapGenYCbCrBasis; + +class VDPixmapUberBlitterDirectCopy : public IVDPixmapBlitter { +public: + VDPixmapUberBlitterDirectCopy(); + ~VDPixmapUberBlitterDirectCopy(); + + void Blit(const VDPixmap& dst, const VDPixmap& src); + void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src); +}; + +class VDPixmapUberBlitter : public IVDPixmapBlitter { +public: + VDPixmapUberBlitter(); + ~VDPixmapUberBlitter(); + + void Blit(const VDPixmap& dst, const VDPixmap& src); + void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src); + +protected: + void Blit(const VDPixmap& dst, const vdrect32 *rDst); + void Blit3(const VDPixmap& dst, const vdrect32 *rDst); + void Blit3Split(const VDPixmap& dst, const vdrect32 *rDst); + void Blit3Separated(const VDPixmap& px, const vdrect32 *rDst); + void Blit2(const VDPixmap& dst, const vdrect32 *rDst); + void Blit2Separated(const VDPixmap& px, const vdrect32 *rDst); + + friend class VDPixmapUberBlitterGenerator; + + struct OutputEntry { + IVDPixmapGen *mpSrc; + int mSrcIndex; + } mOutputs[3]; + + struct SourceEntry { + IVDPixmapGenSrc *mpSrc; + int mSrcIndex; + int mSrcPlane; + int mSrcX; + int mSrcY; + }; + + typedef vdfastvector Generators; + Generators mGenerators; + + typedef vdfastvector Sources; + Sources mSources; + + bool mbIndependentChromaPlanes; + bool mbIndependentPlanes; +}; + +class VDPixmapUberBlitterGenerator { +public: + VDPixmapUberBlitterGenerator(); + ~VDPixmapUberBlitterGenerator(); + + void swap(int index); + void dup(); + void pop(); + + void ldsrc(int srcIndex, int srcPlane, int x, int y, uint32 w, uint32 h, uint32 type, uint32 bpr); + + void ldconst(uint8 fill, uint32 bpr, uint32 w, uint32 h, uint32 type); + + void extract_8in16(int offset, uint32 w, uint32 h); + void extract_8in32(int offset, uint32 w, uint32 h); + void swap_8in16(uint32 w, uint32 h, uint32 bpr); + + void conv_Pal1_to_8888(int srcIndex); + void conv_Pal2_to_8888(int srcIndex); + void conv_Pal4_to_8888(int srcIndex); + void conv_Pal8_to_8888(int srcIndex); + + void conv_555_to_8888(); + void conv_565_to_8888(); + void conv_888_to_8888(); + void conv_555_to_565(); + void conv_565_to_555(); + void conv_8888_to_X32F(); + void conv_8_to_32F(); + void conv_16F_to_32F(); + void conv_V210_to_32F(); + + void conv_8888_to_555(); + void conv_8888_to_565(); + void conv_8888_to_888(); + void conv_32F_to_8(); + void conv_X32F_to_8888(); + void conv_32F_to_16F(); + void conv_32F_to_V210(); + + void convd_8888_to_555(); + void convd_8888_to_565(); + void convd_32F_to_8(); + void convd_X32F_to_8888(); + + void interleave_B8G8_R8G8(); + void interleave_G8B8_G8R8(); + void interleave_X8R8G8B8(); + void interleave_B8R8(); + + void merge_fields(uint32 w, uint32 h, uint32 bpr); + void split_fields(uint32 bpr); + + void ycbcr601_to_rgb32(); + void ycbcr709_to_rgb32(); + void rgb32_to_ycbcr601(); + void rgb32_to_ycbcr709(); + + void ycbcr601_to_rgb32_32f(); + void ycbcr709_to_rgb32_32f(); + void rgb32_to_ycbcr601_32f(); + void rgb32_to_ycbcr709_32f(); + + void ycbcr601_to_ycbcr709(); + void ycbcr709_to_ycbcr601(); + + void ycbcr_to_rgb32_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB); + void ycbcr_to_rgb32f_generic(const VDPixmapGenYCbCrBasis& basis); + void rgb32_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB, uint32 colorSpace); + void rgb32f_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace); + void ycbcr_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basisDst, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& basisSrc, bool srcLimitedRange, uint32 colorSpace); + + void pointh(float xoffset, float xfactor, uint32 w); + void pointv(float yoffset, float yfactor, uint32 h); + void linearh(float xoffset, float xfactor, uint32 w, bool interpOnly); + void linearv(float yoffset, float yfactor, uint32 h, bool interpOnly); + void linear(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h); + void cubich(float xoffset, float xfactor, uint32 w, float splineFactor, bool interpOnly); + void cubicv(float yoffset, float yfactor, uint32 h, float splineFactor, bool interpOnly); + void cubic(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h, float splineFactor); + void lanczos3h(float xoffset, float xfactor, uint32 w); + void lanczos3v(float yoffset, float yfactor, uint32 h); + void lanczos3(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h); + + IVDPixmapBlitter *create(); + +protected: + void MarkDependency(IVDPixmapGen *dst, IVDPixmapGen *src); + + struct StackEntry { + IVDPixmapGen *mpSrc; + uint32 mSrcIndex; + + StackEntry() {} + StackEntry(IVDPixmapGen *src, uint32 index) : mpSrc(src), mSrcIndex(index) {} + }; + + vdfastvector mStack; + + typedef vdfastvector Generators; + Generators mGenerators; + + struct Dependency { + int mDstIdx; + int mSrcIdx; + }; + + vdfastvector mDependencies; + + typedef VDPixmapUberBlitter::SourceEntry SourceEntry; + vdfastvector mSources; +}; + +void VDPixmapGenerate(void *dst, ptrdiff_t pitch, sint32 bpr, sint32 height, IVDPixmapGen *gen, int genIndex); +IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmap& dst, const VDPixmap& src); +IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmapLayout& dst, const VDPixmapLayout& src); + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_input.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_input.h index 4fdfdb4f4c9..bfd5ebad5d5 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_input.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_input.h @@ -1,69 +1,69 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_INPUT_H -#define f_VD2_KASUMI_UBERBLIT_INPUT_H - -#include "uberblit.h" -#include "uberblit_base.h" - -class IVDPixmapGenSrc { -public: - virtual void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) = 0; -}; - -class VDPixmapGenSrc : public IVDPixmapGen, public IVDPixmapGenSrc { -public: - void Init(sint32 width, sint32 height, uint32 type, uint32 bpr) { - mWidth = width; - mHeight = height; - mType = type; - mBpr = bpr; - } - - void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) { - mpSrc = src; - mPitch = pitch; - } - - void AddWindowRequest(int minY, int maxY) { - } - - void Start() { - } - - sint32 GetWidth(int) const { - return mWidth; - } - - sint32 GetHeight(int) const { - return mHeight; - } - - bool IsStateful() const { - return false; - } - - const void *GetRow(sint32 y, uint32 output) { - if (y < 0) - y = 0; - else if (y >= mHeight) - y = mHeight - 1; - return vdptroffset(mpSrc, mPitch*y); - } - - void ProcessRow(void *dst, sint32 y) { - memcpy(dst, GetRow(y, 0), mBpr); - } - - uint32 GetType(uint32 index) const { - return mType; - } - -protected: - const void *mpSrc; - ptrdiff_t mPitch; - size_t mBpr; - sint32 mWidth; - sint32 mHeight; - uint32 mType; -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_INPUT_H +#define f_VD2_KASUMI_UBERBLIT_INPUT_H + +#include "uberblit.h" +#include "uberblit_base.h" + +class IVDPixmapGenSrc { +public: + virtual void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) = 0; +}; + +class VDPixmapGenSrc : public IVDPixmapGen, public IVDPixmapGenSrc { +public: + void Init(sint32 width, sint32 height, uint32 type, uint32 bpr) { + mWidth = width; + mHeight = height; + mType = type; + mBpr = bpr; + } + + void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) { + mpSrc = src; + mPitch = pitch; + } + + void AddWindowRequest(int minY, int maxY) { + } + + void Start() { + } + + sint32 GetWidth(int) const { + return mWidth; + } + + sint32 GetHeight(int) const { + return mHeight; + } + + bool IsStateful() const { + return false; + } + + const void *GetRow(sint32 y, uint32 output) { + if (y < 0) + y = 0; + else if (y >= mHeight) + y = mHeight - 1; + return vdptroffset(mpSrc, mPitch*y); + } + + void ProcessRow(void *dst, sint32 y) { + memcpy(dst, GetRow(y, 0), mBpr); + } + + uint32 GetType(uint32 index) const { + return mType; + } + +protected: + const void *mpSrc; + ptrdiff_t mPitch; + size_t mBpr; + sint32 mWidth; + sint32 mHeight; + uint32 mType; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_interlace.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_interlace.h index d5345639285..23adaa76b35 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_interlace.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_interlace.h @@ -1,123 +1,123 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_UBERBLIT_INTERLACE_H -#define f_VD2_KASUMI_UBERBLIT_INTERLACE_H - -#include "uberblit_base.h" - -class VDPixmapGen_SplitFields : public IVDPixmapGen { -public: - void AddWindowRequest(int minDY, int maxDY) { - mpSrc->AddWindowRequest(minDY*2, maxDY*2+1); - } - - void Start() { - mpSrc->Start(); - } - - sint32 GetWidth(int) const { return mWidth; } - sint32 GetHeight(int idx) const { return mHeight[idx]; } - - bool IsStateful() const { - return false; - } - - uint32 GetType(uint32 output) const { - return mpSrc->GetType(mSrcIndex); - } - - const void *GetRow(sint32 y, uint32 index) { - return mpSrc->GetRow(y+y+index, mSrcIndex); - } - - void ProcessRow(void *dst, sint32 y) { - memcpy(dst, GetRow(y, 0), mBpr); - } - - void Init(IVDPixmapGen *src, uint32 srcindex, uint32 bpr) { - mpSrc = src; - mSrcIndex = srcindex; - mBpr = bpr; - mWidth = src->GetWidth(srcindex); - - uint32 h = src->GetHeight(srcindex); - mHeight[0] = (h + 1) >> 1; - mHeight[1] = h >> 1; - } - -protected: - IVDPixmapGen *mpSrc; - uint32 mSrcIndex; - sint32 mWidth; - sint32 mHeight[2]; - uint32 mBpr; -}; - -class VDPixmapGen_MergeFields : public IVDPixmapGen { -public: - void AddWindowRequest(int minDY, int maxDY) { - mpSrc[0]->AddWindowRequest(minDY >> 1, maxDY >> 1); - mpSrc[1]->AddWindowRequest(minDY >> 1, maxDY >> 1); - } - - void Start() { - mpSrc[0]->Start(); - mpSrc[1]->Start(); - } - - sint32 GetWidth(int) const { return mWidth; } - sint32 GetHeight(int) const { return mHeight; } - - bool IsStateful() const { - return false; - } - - uint32 GetType(uint32 output) const { - return mpSrc[0]->GetType(mSrcIndex[0]); - } - - const void *GetRow(sint32 y, uint32 index) { - int srcIndex = y & 1; - return mpSrc[srcIndex]->GetRow(y >> 1, mSrcIndex[srcIndex]); - } - - void ProcessRow(void *dst, sint32 y) { - memcpy(dst, GetRow(y, 0), mBpr); - } - - void Init(IVDPixmapGen *src1, uint32 srcindex1, IVDPixmapGen *src2, uint32 srcindex2, uint32 w, uint32 h, uint32 bpr) { - mpSrc[0] = src1; - mpSrc[1] = src2; - mSrcIndex[0] = srcindex1; - mSrcIndex[1] = srcindex2; - - mWidth = w; - mHeight = h; - mBpr = bpr; - } - -protected: - IVDPixmapGen *mpSrc[2]; - uint32 mSrcIndex[2]; - sint32 mWidth; - sint32 mHeight; - uint32 mBpr; -}; - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_UBERBLIT_INTERLACE_H +#define f_VD2_KASUMI_UBERBLIT_INTERLACE_H + +#include "uberblit_base.h" + +class VDPixmapGen_SplitFields : public IVDPixmapGen { +public: + void AddWindowRequest(int minDY, int maxDY) { + mpSrc->AddWindowRequest(minDY*2, maxDY*2+1); + } + + void Start() { + mpSrc->Start(); + } + + sint32 GetWidth(int) const { return mWidth; } + sint32 GetHeight(int idx) const { return mHeight[idx]; } + + bool IsStateful() const { + return false; + } + + uint32 GetType(uint32 output) const { + return mpSrc->GetType(mSrcIndex); + } + + const void *GetRow(sint32 y, uint32 index) { + return mpSrc->GetRow(y+y+index, mSrcIndex); + } + + void ProcessRow(void *dst, sint32 y) { + memcpy(dst, GetRow(y, 0), mBpr); + } + + void Init(IVDPixmapGen *src, uint32 srcindex, uint32 bpr) { + mpSrc = src; + mSrcIndex = srcindex; + mBpr = bpr; + mWidth = src->GetWidth(srcindex); + + uint32 h = src->GetHeight(srcindex); + mHeight[0] = (h + 1) >> 1; + mHeight[1] = h >> 1; + } + +protected: + IVDPixmapGen *mpSrc; + uint32 mSrcIndex; + sint32 mWidth; + sint32 mHeight[2]; + uint32 mBpr; +}; + +class VDPixmapGen_MergeFields : public IVDPixmapGen { +public: + void AddWindowRequest(int minDY, int maxDY) { + mpSrc[0]->AddWindowRequest(minDY >> 1, maxDY >> 1); + mpSrc[1]->AddWindowRequest(minDY >> 1, maxDY >> 1); + } + + void Start() { + mpSrc[0]->Start(); + mpSrc[1]->Start(); + } + + sint32 GetWidth(int) const { return mWidth; } + sint32 GetHeight(int) const { return mHeight; } + + bool IsStateful() const { + return false; + } + + uint32 GetType(uint32 output) const { + return mpSrc[0]->GetType(mSrcIndex[0]); + } + + const void *GetRow(sint32 y, uint32 index) { + int srcIndex = y & 1; + return mpSrc[srcIndex]->GetRow(y >> 1, mSrcIndex[srcIndex]); + } + + void ProcessRow(void *dst, sint32 y) { + memcpy(dst, GetRow(y, 0), mBpr); + } + + void Init(IVDPixmapGen *src1, uint32 srcindex1, IVDPixmapGen *src2, uint32 srcindex2, uint32 w, uint32 h, uint32 bpr) { + mpSrc[0] = src1; + mpSrc[1] = src2; + mSrcIndex[0] = srcindex1; + mSrcIndex[1] = srcindex2; + + mWidth = w; + mHeight = h; + mBpr = bpr; + } + +protected: + IVDPixmapGen *mpSrc[2]; + uint32 mSrcIndex[2]; + sint32 mWidth; + sint32 mHeight; + uint32 mBpr; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_pal.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_pal.h index dfa1ff7bccf..e3958b45856 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_pal.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_pal.h @@ -1,148 +1,148 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_PAL_H -#define f_VD2_KASUMI_UBERBLIT_PAL_H - -#include "uberblit_base.h" -#include "uberblit_input.h" - -class VDPixmapGenBase_Pal_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple, public IVDPixmapGenSrc { -public: - void Start() { - StartWindow(mWidth * 4); - } - - void Init(IVDPixmapGen *src, int srcIndex) { - InitSource(src, srcIndex); - } - - void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) { - mpPal = palette; - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - const uint32 *mpPal; -}; - -class VDPixmapGen_Pal1_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - sint32 h = mHeight; - - const uint32 *pal = mpPal; - - src += (w-1) >> 3; - dst += (w-1) & ~7; - - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - - switch(wt & 7) { - do { - v = src[0]; - - case 0: dst[7] = pal[v&1]; v >>= 1; - case 7: dst[6] = pal[v&1]; v >>= 1; - case 6: dst[5] = pal[v&1]; v >>= 1; - case 5: dst[4] = pal[v&1]; v >>= 1; - case 4: dst[3] = pal[v&1]; v >>= 1; - case 3: dst[2] = pal[v&1]; v >>= 1; - case 2: dst[1] = pal[v&1]; v >>= 1; - case 1: dst[0] = pal[v&1]; v >>= 1; - - dst -= 8; - --src; - } while((wt -= 8) > 0); - } - } -}; - -class VDPixmapGen_Pal2_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - sint32 h = mHeight; - - const uint32 *pal = mpPal; - - src += (w-1) >> 2; - dst += (w-1) & ~3; - - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - - switch(wt & 3) { - do { - v = src[0]; - - case 0: dst[3] = pal[v&3]; v >>= 2; - case 3: dst[2] = pal[v&3]; v >>= 2; - case 2: dst[1] = pal[v&3]; v >>= 2; - case 1: dst[0] = pal[v&3]; v >>= 2; - - dst -= 4; - --src; - } while((wt -= 4) > 0); - } - } -}; - -class VDPixmapGen_Pal4_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - sint32 h = mHeight; - - const uint32 *pal = mpPal; - - src += (w-1) >> 1; - dst += ((w-1) & ~1); - - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - - switch(wt & 1) { - do { - v = src[0]; - - case 0: dst[1] = pal[v&15]; v >>= 4; - case 1: dst[0] = pal[v&15]; v >>= 4; - - dst -= 2; - --src; - } while((wt -= 2) > 0); - } - } -}; - -class VDPixmapGen_Pal8_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - sint32 h = mHeight; - - const uint32 *pal = mpPal; - - int wt = w; - - do { - *dst++ = pal[*src++]; - } while(--wt); - } -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_PAL_H +#define f_VD2_KASUMI_UBERBLIT_PAL_H + +#include "uberblit_base.h" +#include "uberblit_input.h" + +class VDPixmapGenBase_Pal_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple, public IVDPixmapGenSrc { +public: + void Start() { + StartWindow(mWidth * 4); + } + + void Init(IVDPixmapGen *src, int srcIndex) { + InitSource(src, srcIndex); + } + + void SetSource(const void *src, ptrdiff_t pitch, const uint32 *palette) { + mpPal = palette; + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + const uint32 *mpPal; +}; + +class VDPixmapGen_Pal1_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + sint32 h = mHeight; + + const uint32 *pal = mpPal; + + src += (w-1) >> 3; + dst += (w-1) & ~7; + + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + + switch(wt & 7) { + do { + v = src[0]; + + case 0: dst[7] = pal[v&1]; v >>= 1; + case 7: dst[6] = pal[v&1]; v >>= 1; + case 6: dst[5] = pal[v&1]; v >>= 1; + case 5: dst[4] = pal[v&1]; v >>= 1; + case 4: dst[3] = pal[v&1]; v >>= 1; + case 3: dst[2] = pal[v&1]; v >>= 1; + case 2: dst[1] = pal[v&1]; v >>= 1; + case 1: dst[0] = pal[v&1]; v >>= 1; + + dst -= 8; + --src; + } while((wt -= 8) > 0); + } + } +}; + +class VDPixmapGen_Pal2_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + sint32 h = mHeight; + + const uint32 *pal = mpPal; + + src += (w-1) >> 2; + dst += (w-1) & ~3; + + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + + switch(wt & 3) { + do { + v = src[0]; + + case 0: dst[3] = pal[v&3]; v >>= 2; + case 3: dst[2] = pal[v&3]; v >>= 2; + case 2: dst[1] = pal[v&3]; v >>= 2; + case 1: dst[0] = pal[v&3]; v >>= 2; + + dst -= 4; + --src; + } while((wt -= 4) > 0); + } + } +}; + +class VDPixmapGen_Pal4_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + sint32 h = mHeight; + + const uint32 *pal = mpPal; + + src += (w-1) >> 1; + dst += ((w-1) & ~1); + + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + + switch(wt & 1) { + do { + v = src[0]; + + case 0: dst[1] = pal[v&15]; v >>= 4; + case 1: dst[0] = pal[v&15]; v >>= 4; + + dst -= 2; + --src; + } while((wt -= 2) > 0); + } + } +}; + +class VDPixmapGen_Pal8_To_X8R8G8B8 : public VDPixmapGenBase_Pal_To_X8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + sint32 h = mHeight; + + const uint32 *pal = mpPal; + + int wt = w; + + do { + *dst++ = pal[*src++]; + } while(--wt); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample.h index 11bfff99cb7..a3bb7e70c0e 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample.h @@ -1,83 +1,83 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_H -#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_H - -#include -#include -#include "uberblit.h" -#include "uberblit_base.h" -#include - -class IVDResamplerSeparableRowStage; -class IVDResamplerSeparableRowStage2; -class IVDResamplerSeparableColStage; - -namespace nsVDPixmap { - enum FilterMode { - kFilterPoint, - kFilterLinear, - kFilterCubic, - kFilterLanczos3, - kFilterCount - }; -} - -class VDPixmapGenResampleRow : public VDPixmapGenWindowBasedOneSource { -public: - VDPixmapGenResampleRow(); - ~VDPixmapGenResampleRow(); - - void Init(IVDPixmapGen *src, uint32 srcIndex, uint32 width, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly); - - void Start(); - - uint32 GetType(uint32 output) const { - return mpSrc->GetType(mSrcIndex); - } - -protected: - void Compute(void *dst0, sint32 y); - void Compute8(void *dst0, sint32 y); - void Compute32(void *dst0, sint32 y); - void Compute128(void *dst0, sint32 y); - - IVDResamplerSeparableRowStage *mpRowStage; - IVDResamplerSeparableRowStage2 *mpRowStage2; - - uint32 mRowFiltW; - uint32 mBytesPerSample; - - VDResamplerAxis mAxis; - - vdblock mWindow; - void **mpAllocWindow; - vdblock > mTempSpace; -}; - -class VDPixmapGenResampleCol : public VDPixmapGenWindowBasedOneSource { -public: - VDPixmapGenResampleCol(); - ~VDPixmapGenResampleCol(); - - void Init(IVDPixmapGen *src, uint32 srcIndex, uint32 height, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly); - - void Start(); - - uint32 GetType(uint32 output) const { - return mpSrc->GetType(mSrcIndex); - } - -protected: - void Compute(void *dst0, sint32 y); - - IVDResamplerSeparableColStage *mpColStage; - - uint32 mWinSize; - uint32 mBytesPerSample; - uint32 mBytesPerRow; - - VDResamplerAxis mAxis; - - vdblock mWindow; -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_H +#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_H + +#include +#include +#include "uberblit.h" +#include "uberblit_base.h" +#include + +class IVDResamplerSeparableRowStage; +class IVDResamplerSeparableRowStage2; +class IVDResamplerSeparableColStage; + +namespace nsVDPixmap { + enum FilterMode { + kFilterPoint, + kFilterLinear, + kFilterCubic, + kFilterLanczos3, + kFilterCount + }; +} + +class VDPixmapGenResampleRow : public VDPixmapGenWindowBasedOneSource { +public: + VDPixmapGenResampleRow(); + ~VDPixmapGenResampleRow(); + + void Init(IVDPixmapGen *src, uint32 srcIndex, uint32 width, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly); + + void Start(); + + uint32 GetType(uint32 output) const { + return mpSrc->GetType(mSrcIndex); + } + +protected: + void Compute(void *dst0, sint32 y); + void Compute8(void *dst0, sint32 y); + void Compute32(void *dst0, sint32 y); + void Compute128(void *dst0, sint32 y); + + IVDResamplerSeparableRowStage *mpRowStage; + IVDResamplerSeparableRowStage2 *mpRowStage2; + + uint32 mRowFiltW; + uint32 mBytesPerSample; + + VDResamplerAxis mAxis; + + vdblock mWindow; + void **mpAllocWindow; + vdblock > mTempSpace; +}; + +class VDPixmapGenResampleCol : public VDPixmapGenWindowBasedOneSource { +public: + VDPixmapGenResampleCol(); + ~VDPixmapGenResampleCol(); + + void Init(IVDPixmapGen *src, uint32 srcIndex, uint32 height, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly); + + void Start(); + + uint32 GetType(uint32 output) const { + return mpSrc->GetType(mSrcIndex); + } + +protected: + void Compute(void *dst0, sint32 y); + + IVDResamplerSeparableColStage *mpColStage; + + uint32 mWinSize; + uint32 mBytesPerSample; + uint32 mBytesPerRow; + + VDResamplerAxis mAxis; + + vdblock mWindow; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special.h index f5ffa6c462d..0f97ba1cf6b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special.h @@ -1,81 +1,81 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_H -#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_H - -#include -#include -#include "uberblit.h" -#include "uberblit_base.h" - -class VDPixmapGenResampleRow_d2_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleRow_d4_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleRow_x2_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleRow_x4_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_x2_phalf_lin_u8: public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_x4_p1half_lin_u8: public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_d2_pnqrtr_lin_u8: public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_d4_pn38_lin_u8: public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcIndex); - void Start(); - -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_H +#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_H + +#include +#include +#include "uberblit.h" +#include "uberblit_base.h" + +class VDPixmapGenResampleRow_d2_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleRow_d4_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleRow_x2_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleRow_x4_p0_lin_u8 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_x2_phalf_lin_u8: public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_x4_p1half_lin_u8: public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_d2_pnqrtr_lin_u8: public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_d4_pn38_lin_u8: public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcIndex); + void Start(); + +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special_x86.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special_x86.h index b49629cf24b..6634869aaec 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special_x86.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_resample_special_x86.h @@ -1,26 +1,26 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_X86_H -#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_X86_H - -#include "uberblit_resample_special.h" - -class VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE : public VDPixmapGenResampleRow_x2_p0_lin_u8 { -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleRow_x4_p0_lin_u8_MMX : public VDPixmapGenResampleRow_x4_p0_lin_u8 { -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE: public VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 { -protected: - void Compute(void *dst0, sint32 y); -}; - -class VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE: public VDPixmapGenResampleCol_d4_pn38_lin_u8 { -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_X86_H +#define f_VD2_KASUMI_UBERBLIT_RESAMPLE_SPECIAL_X86_H + +#include "uberblit_resample_special.h" + +class VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE : public VDPixmapGenResampleRow_x2_p0_lin_u8 { +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleRow_x4_p0_lin_u8_MMX : public VDPixmapGenResampleRow_x4_p0_lin_u8 { +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE: public VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 { +protected: + void Compute(void *dst0, sint32 y); +}; + +class VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE: public VDPixmapGenResampleCol_d4_pn38_lin_u8 { +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb.h index e1a4c5fe7b5..21925af2a20 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb.h @@ -1,552 +1,552 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RGB_H -#define f_VD2_KASUMI_UBERBLIT_RGB_H - -#include -#include "uberblit_base.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 16-bit crossconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X1R5G5B5_To_R5G6B5 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; - } - -protected: - virtual void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 5; - - dst[i] = (uint16)px; - } - } -}; - -class VDPixmapGen_R5G6B5_To_X1R5G5B5 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 1; - - dst[i] = (uint16)px; - } - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32-bit upconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X1R5G5B5_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - virtual void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 5) & 0x070707); - } - } -}; - -class VDPixmapGen_R5G6B5_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 5) + (px_g6 >> 6)) & 0x070307); - } - } -}; - -class VDPixmapGen_R8G8B8_To_A8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_1555_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 9) & 0x7c00) + ((px >> 6) & 0x03e0) + ((px >> 3) & 0x001f); - } - } -}; - -class VDPixmapGen_X8R8G8B8_To_R5G6B5 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; i> 8) & 0xf800) + ((px >> 5) & 0x07e0) + ((px >> 3) & 0x001f); - } - } -}; - -class VDPixmapGen_X8R8G8B8_To_R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 3); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_1555_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - static const uint32 kDitherMatrix[4][4][2]={ - { 0x00000000, 0x00000000, 0x04000400, 0x00040000, 0x01000100, 0x00010000, 0x05000500, 0x00050000 }, - { 0x06000600, 0x00060000, 0x02000200, 0x00020000, 0x07000700, 0x00070000, 0x03000300, 0x00030000 }, - { 0x01800180, 0x00018000, 0x05800580, 0x00058000, 0x00800080, 0x00008000, 0x04800480, 0x00048000 }, - { 0x07800780, 0x00078000, 0x03800380, 0x00038000, 0x06800680, 0x00068000, 0x02800280, 0x00028000 }, - }; - - const uint32 (*drow)[2] = kDitherMatrix[y & 3]; - - for(sint32 i=0; i> 17) & 0x7c00) + ((g >> 14) & 0x03e0) + ((rb >> 11) & 0x001f); - } - } -}; - -class VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - static const uint32 kDitherMatrix[4][4][2]={ - { 0x00000000, 0x00000000, 0x04000400, 0x00020000, 0x01000100, 0x00008000, 0x05000500, 0x00028000 }, - { 0x06000600, 0x00030000, 0x02000200, 0x00010000, 0x07000700, 0x00038000, 0x03000300, 0x00018000 }, - { 0x01800180, 0x0000c000, 0x05800580, 0x0002c000, 0x00800080, 0x00004000, 0x04800480, 0x00024000 }, - { 0x07800780, 0x0003c000, 0x03800380, 0x0001c000, 0x06800680, 0x00034000, 0x02800280, 0x00014000 }, - }; - - const uint32 (*drow)[2] = kDitherMatrix[y & 3]; - - for(sint32 i=0; i> 16) & 0xf800) + ((g >> 13) & 0x07e0) + ((rb >> 11) & 0x001f); - } - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32F upconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_8_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32Fx4_LE; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - sint32 w = mWidth; - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - VDCPUCleanupExtensions(); - - sint32 w = mWidth; - -#define X(v) ((v) - 0x49400000) - - static const sint32 kDitherMatrix[4][4]={ - { X( 0), X( 8), X( 2), X(10), }, - { X(12), X( 4), X(14), X( 6), }, - { X( 3), X(11), X( 1), X( 9), }, - { X(15), X( 7), X(13), X( 5), }, - }; - -#undef X - - const sint32 *pDitherRow = kDitherMatrix[y & 3]; - - for(sint32 i=0; i> 4; - - if ((uint32)vb >= 0x100) - vb = (uint8)(~vb >> 31); - - dst[i] = (uint8)vb; - } - } -}; - -class VDPixmapGen_X32B32G32R32F_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start() { - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - sint32 w = mWidth; - - for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - sint32 w = mWidth; - -#define X(v) ((v) - 0x49400000) - - static const sint32 kDitherMatrix[4][4]={ - { X( 0), X( 8), X( 2), X(10), }, - { X(12), X( 4), X(14), X( 6), }, - { X( 3), X(11), X( 1), X( 9), }, - { X(15), X( 7), X(13), X( 5), }, - }; - -#undef X - - const sint32 *pDitherRow = kDitherMatrix[y & 3]; - - for(sint32 i=0; i> 4; - sint32 vg = ((sint32)cg.i + addend) >> 4; - sint32 vb = ((sint32)cb.i + addend) >> 4; - - if ((uint32)vr >= 0x100) - vr = (uint8)(~vr >> 31); - - if ((uint32)vg >= 0x100) - vg = (uint8)(~vg >> 31); - - if ((uint32)vb >= 0x100) - vb = (uint8)(~vb >> 31); - - dst[i] = (vr << 16) + (vg << 8) + vb; - } - } -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RGB_H +#define f_VD2_KASUMI_UBERBLIT_RGB_H + +#include +#include "uberblit_base.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 16-bit crossconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X1R5G5B5_To_R5G6B5 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; + } + +protected: + virtual void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 5; + + dst[i] = (uint16)px; + } + } +}; + +class VDPixmapGen_R5G6B5_To_X1R5G5B5 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 1; + + dst[i] = (uint16)px; + } + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32-bit upconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X1R5G5B5_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + virtual void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 5) & 0x070707); + } + } +}; + +class VDPixmapGen_R5G6B5_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 5) + (px_g6 >> 6)) & 0x070307); + } + } +}; + +class VDPixmapGen_R8G8B8_To_A8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_1555_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 9) & 0x7c00) + ((px >> 6) & 0x03e0) + ((px >> 3) & 0x001f); + } + } +}; + +class VDPixmapGen_X8R8G8B8_To_R5G6B5 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; i> 8) & 0xf800) + ((px >> 5) & 0x07e0) + ((px >> 3) & 0x001f); + } + } +}; + +class VDPixmapGen_X8R8G8B8_To_R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 3); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_1555_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + static const uint32 kDitherMatrix[4][4][2]={ + { 0x00000000, 0x00000000, 0x04000400, 0x00040000, 0x01000100, 0x00010000, 0x05000500, 0x00050000 }, + { 0x06000600, 0x00060000, 0x02000200, 0x00020000, 0x07000700, 0x00070000, 0x03000300, 0x00030000 }, + { 0x01800180, 0x00018000, 0x05800580, 0x00058000, 0x00800080, 0x00008000, 0x04800480, 0x00048000 }, + { 0x07800780, 0x00078000, 0x03800380, 0x00038000, 0x06800680, 0x00068000, 0x02800280, 0x00028000 }, + }; + + const uint32 (*drow)[2] = kDitherMatrix[y & 3]; + + for(sint32 i=0; i> 17) & 0x7c00) + ((g >> 14) & 0x03e0) + ((rb >> 11) & 0x001f); + } + } +}; + +class VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_565_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + static const uint32 kDitherMatrix[4][4][2]={ + { 0x00000000, 0x00000000, 0x04000400, 0x00020000, 0x01000100, 0x00008000, 0x05000500, 0x00028000 }, + { 0x06000600, 0x00030000, 0x02000200, 0x00010000, 0x07000700, 0x00038000, 0x03000300, 0x00018000 }, + { 0x01800180, 0x0000c000, 0x05800580, 0x0002c000, 0x00800080, 0x00004000, 0x04800480, 0x00024000 }, + { 0x07800780, 0x0003c000, 0x03800380, 0x0001c000, 0x06800680, 0x00034000, 0x02800280, 0x00014000 }, + }; + + const uint32 (*drow)[2] = kDitherMatrix[y & 3]; + + for(sint32 i=0; i> 16) & 0xf800) + ((g >> 13) & 0x07e0) + ((rb >> 11) & 0x001f); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32F upconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_8_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32Fx4_LE; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + sint32 w = mWidth; + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + VDCPUCleanupExtensions(); + + sint32 w = mWidth; + +#define X(v) ((v) - 0x49400000) + + static const sint32 kDitherMatrix[4][4]={ + { X( 0), X( 8), X( 2), X(10), }, + { X(12), X( 4), X(14), X( 6), }, + { X( 3), X(11), X( 1), X( 9), }, + { X(15), X( 7), X(13), X( 5), }, + }; + +#undef X + + const sint32 *pDitherRow = kDitherMatrix[y & 3]; + + for(sint32 i=0; i> 4; + + if ((uint32)vb >= 0x100) + vb = (uint8)(~vb >> 31); + + dst[i] = (uint8)vb; + } + } +}; + +class VDPixmapGen_X32B32G32R32F_To_X8R8G8B8 : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start() { + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + sint32 w = mWidth; + + for(sint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + sint32 w = mWidth; + +#define X(v) ((v) - 0x49400000) + + static const sint32 kDitherMatrix[4][4]={ + { X( 0), X( 8), X( 2), X(10), }, + { X(12), X( 4), X(14), X( 6), }, + { X( 3), X(11), X( 1), X( 9), }, + { X(15), X( 7), X(13), X( 5), }, + }; + +#undef X + + const sint32 *pDitherRow = kDitherMatrix[y & 3]; + + for(sint32 i=0; i> 4; + sint32 vg = ((sint32)cg.i + addend) >> 4; + sint32 vb = ((sint32)cb.i + addend) >> 4; + + if ((uint32)vr >= 0x100) + vr = (uint8)(~vr >> 31); + + if ((uint32)vg >= 0x100) + vg = (uint8)(~vg >> 31); + + if ((uint32)vb >= 0x100) + vb = (uint8)(~vb >> 31); + + dst[i] = (vr << 16) + (vg << 8) + vb; + } + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb_x86.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb_x86.h index da78eeb673b..ececed12042 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb_x86.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_rgb_x86.h @@ -1,114 +1,114 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_RGB_X86_H -#define f_VD2_KASUMI_UBERBLIT_RGB_X86_H - -#include -#include "uberblit_base.h" - -extern "C" void vdasm_pixblt_XRGB1555_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_RGB565_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_RGB565_to_XRGB1555_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_XRGB1555_to_RGB565_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_XRGB8888_to_XRGB1555_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_XRGB8888_to_RGB565_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_XRGB8888_to_RGB888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -extern "C" void vdasm_pixblt_RGB888_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 16-bit crossconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X1R5G5B5_To_R5G6B5_MMX : public VDPixmapGen_X1R5G5B5_To_R5G6B5 { -protected: - virtual void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB1555_to_RGB565_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_R5G6B5_To_X1R5G5B5_MMX : public VDPixmapGen_R5G6B5_To_X1R5G5B5 { -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_RGB565_to_XRGB1555_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32-bit upconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X1R5G5B5_To_X8R8G8B8_MMX : public VDPixmapGen_X1R5G5B5_To_X8R8G8B8 { -protected: - virtual void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB1555_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_R5G6B5_To_X8R8G8B8_MMX : public VDPixmapGen_R5G6B5_To_X8R8G8B8 { -protected: - virtual void Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_RGB565_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_R8G8B8_To_X8R8G8B8_MMX : public VDPixmapGen_R8G8B8_To_A8R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_RGB888_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32-bit downconverters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_X8R8G8B8_To_X1R5G5B5_MMX : public VDPixmapGen_X8R8G8B8_To_X1R5G5B5 { -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB8888_to_XRGB1555_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_X8R8G8B8_To_R5G6B5_MMX : public VDPixmapGen_X8R8G8B8_To_R5G6B5 { -protected: - void Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB8888_to_RGB565_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -class VDPixmapGen_X8R8G8B8_To_R8G8B8_MMX : public VDPixmapGen_X8R8G8B8_To_R8G8B8 { -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_pixblt_XRGB8888_to_RGB888_MMX(dst, 0, src, 0, mWidth, 1); - } -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_RGB_X86_H +#define f_VD2_KASUMI_UBERBLIT_RGB_X86_H + +#include +#include "uberblit_base.h" + +extern "C" void vdasm_pixblt_XRGB1555_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_RGB565_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_RGB565_to_XRGB1555_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_XRGB1555_to_RGB565_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_XRGB8888_to_XRGB1555_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_XRGB8888_to_RGB565_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_XRGB8888_to_RGB888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +extern "C" void vdasm_pixblt_RGB888_to_XRGB8888_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 16-bit crossconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X1R5G5B5_To_R5G6B5_MMX : public VDPixmapGen_X1R5G5B5_To_R5G6B5 { +protected: + virtual void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB1555_to_RGB565_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_R5G6B5_To_X1R5G5B5_MMX : public VDPixmapGen_R5G6B5_To_X1R5G5B5 { +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_RGB565_to_XRGB1555_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32-bit upconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X1R5G5B5_To_X8R8G8B8_MMX : public VDPixmapGen_X1R5G5B5_To_X8R8G8B8 { +protected: + virtual void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB1555_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_R5G6B5_To_X8R8G8B8_MMX : public VDPixmapGen_R5G6B5_To_X8R8G8B8 { +protected: + virtual void Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_RGB565_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_R8G8B8_To_X8R8G8B8_MMX : public VDPixmapGen_R8G8B8_To_A8R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_RGB888_to_XRGB8888_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32-bit downconverters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_X8R8G8B8_To_X1R5G5B5_MMX : public VDPixmapGen_X8R8G8B8_To_X1R5G5B5 { +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB8888_to_XRGB1555_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_X8R8G8B8_To_R5G6B5_MMX : public VDPixmapGen_X8R8G8B8_To_R5G6B5 { +protected: + void Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB8888_to_RGB565_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +class VDPixmapGen_X8R8G8B8_To_R8G8B8_MMX : public VDPixmapGen_X8R8G8B8_To_R8G8B8 { +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_pixblt_XRGB8888_to_RGB888_MMX(dst, 0, src, 0, mWidth, 1); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_swizzle.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_swizzle.h index 66aa7b6b87b..a87fe1f5cf9 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_swizzle.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_swizzle.h @@ -1,343 +1,343 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2008 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_UBERBLIT_SWIZZLE_H -#define f_VD2_KASUMI_UBERBLIT_SWIZZLE_H - -#include -#include "uberblit_base.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// generic converters -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_Swap8In16 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *gen, int srcIndex, uint32 w, uint32 h, uint32 bpr); - void Start(); - - uint32 GetType(uint32 index) const; - -protected: - void Compute(void *dst0, sint32 y); - - uint32 mRowLength; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32-bit deinterleavers -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_8In16 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *gen, int srcIndex, int offset, uint32 w, uint32 h) { - InitSource(gen, srcIndex); - mOffset = offset; - SetOutputSize(w, h); - gen->AddWindowRequest(0, 0); - } - - void Start() { - StartWindow(mWidth); - } - - uint32 GetType(uint32 index) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; - } - -protected: - void Compute(void *dst0, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex) + mOffset; - uint8 *dst = (uint8 *)dst0; - sint32 w = mWidth; - for(sint32 x=0; xAddWindowRequest(0, 0); - } - - void Start() { - StartWindow(mWidth); - } - - uint32 GetType(uint32 index) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; - } - -protected: - void Compute(void *dst0, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex) + mOffset; - uint8 *dst = (uint8 *)dst0; - sint32 w = mWidth; - for(sint32 x=0; xGetWidth(srcindexY); - mHeight = srcY->GetHeight(srcindexY); - - srcY->AddWindowRequest(0, 0); - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); - } - - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(((mWidth + 1) & ~1) * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_B8G8_R8G8; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *)dst0; - const uint8 *VDRESTRICT srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - sint32 w = mWidth >> 1; - for(sint32 x=0; xGetWidth(srcindexY); - mHeight = srcY->GetHeight(srcindexY); - - srcY->AddWindowRequest(0, 0); - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); - } - - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(((mWidth + 1) & ~1) * 2); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_G8B8_G8R8; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 * VDRESTRICT dst = (uint8 *)dst0; - const uint8 *VDRESTRICT srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - sint32 w2 = mWidth >> 1; - for(sint32 x=0; xGetWidth(srcindexY); - mHeight = srcY->GetHeight(srcindexY); - - srcY->AddWindowRequest(0, 0); - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); - } - - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_8888; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - for(sint32 x=0; x +#include "uberblit_base.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// generic converters +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_Swap8In16 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *gen, int srcIndex, uint32 w, uint32 h, uint32 bpr); + void Start(); + + uint32 GetType(uint32 index) const; + +protected: + void Compute(void *dst0, sint32 y); + + uint32 mRowLength; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32-bit deinterleavers +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_8In16 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *gen, int srcIndex, int offset, uint32 w, uint32 h) { + InitSource(gen, srcIndex); + mOffset = offset; + SetOutputSize(w, h); + gen->AddWindowRequest(0, 0); + } + + void Start() { + StartWindow(mWidth); + } + + uint32 GetType(uint32 index) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; + } + +protected: + void Compute(void *dst0, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex) + mOffset; + uint8 *dst = (uint8 *)dst0; + sint32 w = mWidth; + for(sint32 x=0; xAddWindowRequest(0, 0); + } + + void Start() { + StartWindow(mWidth); + } + + uint32 GetType(uint32 index) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_8; + } + +protected: + void Compute(void *dst0, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex) + mOffset; + uint8 *dst = (uint8 *)dst0; + sint32 w = mWidth; + for(sint32 x=0; xGetWidth(srcindexY); + mHeight = srcY->GetHeight(srcindexY); + + srcY->AddWindowRequest(0, 0); + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); + } + + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(((mWidth + 1) & ~1) * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_B8G8_R8G8; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *)dst0; + const uint8 *VDRESTRICT srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + sint32 w = mWidth >> 1; + for(sint32 x=0; xGetWidth(srcindexY); + mHeight = srcY->GetHeight(srcindexY); + + srcY->AddWindowRequest(0, 0); + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); + } + + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(((mWidth + 1) & ~1) * 2); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_G8B8_G8R8; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 * VDRESTRICT dst = (uint8 *)dst0; + const uint8 *VDRESTRICT srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + sint32 w2 = mWidth >> 1; + for(sint32 x=0; xGetWidth(srcindexY); + mHeight = srcY->GetHeight(srcindexY); + + srcY->AddWindowRequest(0, 0); + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); + } + + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixType_Mask) | kVDPixType_8888; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + for(sint32 x=0; x -#include "uberblit_base.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// 32F -> V210 -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_32F_To_V210 : public VDPixmapGenWindowBased { -public: - void Init(IVDPixmapGen *srcR, uint32 srcindexR, IVDPixmapGen *srcG, uint32 srcindexG, IVDPixmapGen *srcB, uint32 srcindexB) { - mpSrcR = srcR; - mSrcIndexR = srcindexR; - mpSrcG = srcG; - mSrcIndexG = srcindexG; - mpSrcB = srcB; - mSrcIndexB = srcindexB; - mWidth = srcG->GetWidth(srcindexG); - mHeight = srcG->GetHeight(srcindexG); - - srcR->AddWindowRequest(0, 0); - srcG->AddWindowRequest(0, 0); - srcB->AddWindowRequest(0, 0); - } - - void Start() { - mpSrcR->Start(); - mpSrcG->Start(); - mpSrcB->Start(); - - int qw = (mWidth + 47) / 48; - StartWindow(qw * 128); - } - - uint32 GetType(uint32 output) const { - return (mpSrcG->GetType(mSrcIndexG) & ~kVDPixType_Mask) | kVDPixType_V210; - } - -protected: - void Compute(void *dst0, sint32 y); - - IVDPixmapGen *mpSrcR; - uint32 mSrcIndexR; - IVDPixmapGen *mpSrcG; - uint32 mSrcIndexG; - IVDPixmapGen *mpSrcB; - uint32 mSrcIndexB; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// V210 -> 32F -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGen_V210_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { -public: - void Start(); - const void *GetRow(sint32 y, uint32 index); - - sint32 GetWidth(int index) const; - uint32 GetType(uint32 output) const; - -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif // f_VD2_KASUMI_UBERBLIT_V210_H +#ifndef f_VD2_KASUMI_UBERBLIT_V210_H +#define f_VD2_KASUMI_UBERBLIT_V210_H + +#include +#include "uberblit_base.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// 32F -> V210 +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_32F_To_V210 : public VDPixmapGenWindowBased { +public: + void Init(IVDPixmapGen *srcR, uint32 srcindexR, IVDPixmapGen *srcG, uint32 srcindexG, IVDPixmapGen *srcB, uint32 srcindexB) { + mpSrcR = srcR; + mSrcIndexR = srcindexR; + mpSrcG = srcG; + mSrcIndexG = srcindexG; + mpSrcB = srcB; + mSrcIndexB = srcindexB; + mWidth = srcG->GetWidth(srcindexG); + mHeight = srcG->GetHeight(srcindexG); + + srcR->AddWindowRequest(0, 0); + srcG->AddWindowRequest(0, 0); + srcB->AddWindowRequest(0, 0); + } + + void Start() { + mpSrcR->Start(); + mpSrcG->Start(); + mpSrcB->Start(); + + int qw = (mWidth + 47) / 48; + StartWindow(qw * 128); + } + + uint32 GetType(uint32 output) const { + return (mpSrcG->GetType(mSrcIndexG) & ~kVDPixType_Mask) | kVDPixType_V210; + } + +protected: + void Compute(void *dst0, sint32 y); + + IVDPixmapGen *mpSrcR; + uint32 mSrcIndexR; + IVDPixmapGen *mpSrcG; + uint32 mSrcIndexG; + IVDPixmapGen *mpSrcB; + uint32 mSrcIndexB; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// V210 -> 32F +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGen_V210_To_32F : public VDPixmapGenWindowBasedOneSourceSimple { +public: + void Start(); + const void *GetRow(sint32 y, uint32 index); + + sint32 GetWidth(int index) const; + uint32 GetType(uint32 output) const; + +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif // f_VD2_KASUMI_UBERBLIT_V210_H diff --git a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_ycbcr.h b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_ycbcr.h index bdd965165ad..d6ad5a6a7b4 100644 --- a/src/thirdparty/VirtualDub/Kasumi/h/uberblit_ycbcr.h +++ b/src/thirdparty/VirtualDub/Kasumi/h/uberblit_ycbcr.h @@ -1,600 +1,600 @@ -#ifndef f_VD2_KASUMI_UBERBLIT_YCBCR_H -#define f_VD2_KASUMI_UBERBLIT_YCBCR_H - -#include -#include -#include -#include "uberblit.h" -#include "uberblit_base.h" - -class VDPixmapGenYCbCrToRGBBase : public VDPixmapGenWindowBased { -public: - void Init(IVDPixmapGen *srcCr, uint32 srcindexCr, IVDPixmapGen *srcY, uint32 srcindexY, IVDPixmapGen *srcCb, uint32 srcindexCb) { - mpSrcY = srcY; - mSrcIndexY = srcindexY; - mpSrcCb = srcCb; - mSrcIndexCb = srcindexCb; - mpSrcCr = srcCr; - mSrcIndexCr = srcindexCr; - mWidth = srcY->GetWidth(srcindexY); - mHeight = srcY->GetHeight(srcindexY); - - srcY->AddWindowRequest(0, 0); - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); - } - - -protected: - IVDPixmapGen *mpSrcY; - uint32 mSrcIndexY; - IVDPixmapGen *mpSrcCb; - uint32 mSrcIndexCb; - IVDPixmapGen *mpSrcCr; - uint32 mSrcIndexCr; -}; - -class VDPixmapGenYCbCrToRGB32Base : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 4); - } -}; - - -class VDPixmapGenYCbCrToRGB32FBase : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 16); - } -}; - - -class VDPixmapGenRGB32ToYCbCrBase : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcindex) { - InitSource(src, srcindex); - } - - void Start() { - StartWindow(mWidth, 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; - } -}; - -class VDPixmapGenRGB32FToYCbCrBase : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcindex) { - InitSource(src, srcindex); - } - - void Start() { - StartWindow(mWidth * sizeof(float), 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; - } -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Rec.601 converters -// -// -->Kr=0.299; Kb=0.114; Z=0; S=255; L = [Kr 1-Kr-Kb Kb]; Y = [219*(L-Z)/S 16]; U = [112*([0 0 1]-L)/((1-Kb)*S) 128]; V = -// [112*([1 0 0]-L)/((1-Kr)*S) 128]; M = [Y; U; V; 0 0 0 1]; disp(M); disp(inv(M)); -// -// ! 0.2567882 0.5041294 0.0979059 16. ! -// ! - 0.1482229 - 0.2909928 0.4392157 128. ! -// ! 0.4392157 - 0.3677883 - 0.0714274 128. ! -// ! 0. 0. 0. 1. ! -// -// ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! -// ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! -// ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! -// ! 0. 0. 0. 1. ! -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGenYCbCr601ToRGB32 : public VDPixmapGenYCbCrToRGB32Base { -public: - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; - } - -protected: - virtual void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_601; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - for(sint32 i=0; iround(inv([1 0 0 0; 0 1 0 0; 0 0 1 0; -16 -128 -128 1] * [1.1643828 1.1643828 1.1643828 0; 1.5960273 -0.8129688 0 0; - // 0 -0.3917617 2.0172305 0; 0 0 0 1]) .* 65536) - // ans = - // - // ! 16829. 28784. - 9714. 0. ! - // ! 33039. - 24103. - 19071. 0. ! - // ! 6416. - 4681. 28784. 0. ! - // ! 1048576. 8388608. 8388608. 65536. ! - - *dstCr++ = (28784*r - 24103*g - 4681*b + 8388608 + 32768) >> 16; - *dstY ++ = (16829*r + 33039*g + 6416*b + 1048576 + 32768) >> 16; - *dstCb++ = (-9714*r - 19071*g + 28784*b + 8388608 + 32768) >> 16; - } - } -}; - -class VDPixmapGenRGB32FToYCbCr601 : public VDPixmapGenRGB32FToYCbCrBase { -public: - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_601; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dstCb = (float *)dst0; - float *dstY = dstCb + mWindowPitch; - float *dstCr = dstY + mWindowPitch; - - const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iKr=0.2126; Kb=0.0722; Z=0; S=255; L = [Kr 1-Kr-Kb Kb]; Y = [219*(L-Z)/S 16]; U = [112*([0 0 1]-L)/((1-Kb)*S) 128]; V -// = [112*([1 0 0]-L)/((1-Kr)*S) 128]; M = [Y; U; V; 0 0 0 1]; disp(M); disp(inv(M)); -// -// ! 0.1825859 0.6142306 0.0620071 16. ! -// ! - 0.1006437 - 0.3385720 0.4392157 128. ! -// ! 0.4392157 - 0.3989422 - 0.0402735 128. ! -// ! 0. 0. 0. 1. ! -// -// ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! -// ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! -// ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! -// ! 0. 0. 0. 1. ! -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGenYCbCr709ToRGB32 : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 4); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; - } - -protected: - virtual void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iStart(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 16); - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - for(sint32 i=0; i> 16; - *dstY ++ = (11966*r + 40254*g + 4064*b + 1048576 + 32768) >> 16; - *dstCb++ = (-6596*r - 22189*g + 28784*b + 8388608 + 32768) >> 16; - } - } -}; - -class VDPixmapGenRGB32FToYCbCr709 : public VDPixmapGenWindowBasedOneSource { -public: - void Init(IVDPixmapGen *src, uint32 srcindex) { - InitSource(src, srcindex); - } - - void Start() { - StartWindow(mWidth * sizeof(float), 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 y) { - float *dstCr = (float *)dst0; - float *dstY = dstCr + mWindowPitch; - float *dstCb = dstY + mWindowPitch; - - const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; i Rec.709 converters -// -// Rec.601 to Rec.709: -// -// 1. - 0.1155497 - 0.2079376 41.406386 -// 0 1.0186397 0.1146180 - 17.056983 -// 0 0.0750494 1.0253271 - 12.848195 -// -// Rec.709 to Rec.601: -// -// 1. 0.0993117 0.1916995 - 37.249435 -// 0 0.9898538 - 0.1106525 15.462234 -// 0 - 0.0724530 0.9833978 11.399058 -// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -class VDPixmapGenYCbCr601ToYCbCr709 : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth, 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 ypos) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(ypos, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - for(sint32 i=0; i> 16); - *dstCb++ = (66758*cb + 7512*cr - 1117846 + 32768) >> 16; - *dstCr++ = (4918*cb + 67196*cr - 842019 + 32768) >> 16; - } - } -}; - -class VDPixmapGenYCbCr709ToYCbCr601 : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth, 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 ypos) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(ypos, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - for(sint32 i=0; i> 16); - *dstCb++ = (64871*cb - 7252*cr + 1013376 + 32768) >> 16; - *dstCr++ = (-4748*cb + 64448*cr + 747008 + 32768) >> 16; - } - } -}; - -class VDPixmapGenYCbCr601ToYCbCr709_32F : public VDPixmapGenYCbCrToRGBBase { -public: - void Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * sizeof(float), 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 ypos) { - float *dstCr = (float *)dst0; - float *dstY = vdptroffset(dstCr, mWindowPitch); - float *dstCb = vdptroffset(dstY, mWindowPitch); - - const float *srcY = (const float *)mpSrcY->GetRow(ypos, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; iStart(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * sizeof(float), 3); - } - - const void *GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; - } - - uint32 GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; - } - -protected: - void Compute(void *dst0, sint32 ypos) { - float *dstCr = (float *)dst0; - float *dstY = vdptroffset(dstCr, mWindowPitch); - float *dstCb = vdptroffset(dstY, mWindowPitch); - - const float *srcY = (const float *)mpSrcY->GetRow(ypos, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - for(sint32 i=0; i +#include +#include +#include "uberblit.h" +#include "uberblit_base.h" + +class VDPixmapGenYCbCrToRGBBase : public VDPixmapGenWindowBased { +public: + void Init(IVDPixmapGen *srcCr, uint32 srcindexCr, IVDPixmapGen *srcY, uint32 srcindexY, IVDPixmapGen *srcCb, uint32 srcindexCb) { + mpSrcY = srcY; + mSrcIndexY = srcindexY; + mpSrcCb = srcCb; + mSrcIndexCb = srcindexCb; + mpSrcCr = srcCr; + mSrcIndexCr = srcindexCr; + mWidth = srcY->GetWidth(srcindexY); + mHeight = srcY->GetHeight(srcindexY); + + srcY->AddWindowRequest(0, 0); + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); + } + + +protected: + IVDPixmapGen *mpSrcY; + uint32 mSrcIndexY; + IVDPixmapGen *mpSrcCb; + uint32 mSrcIndexCb; + IVDPixmapGen *mpSrcCr; + uint32 mSrcIndexCr; +}; + +class VDPixmapGenYCbCrToRGB32Base : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 4); + } +}; + + +class VDPixmapGenYCbCrToRGB32FBase : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 16); + } +}; + + +class VDPixmapGenRGB32ToYCbCrBase : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcindex) { + InitSource(src, srcindex); + } + + void Start() { + StartWindow(mWidth, 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; + } +}; + +class VDPixmapGenRGB32FToYCbCrBase : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcindex) { + InitSource(src, srcindex); + } + + void Start() { + StartWindow(mWidth * sizeof(float), 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; + } +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Rec.601 converters +// +// -->Kr=0.299; Kb=0.114; Z=0; S=255; L = [Kr 1-Kr-Kb Kb]; Y = [219*(L-Z)/S 16]; U = [112*([0 0 1]-L)/((1-Kb)*S) 128]; V = +// [112*([1 0 0]-L)/((1-Kr)*S) 128]; M = [Y; U; V; 0 0 0 1]; disp(M); disp(inv(M)); +// +// ! 0.2567882 0.5041294 0.0979059 16. ! +// ! - 0.1482229 - 0.2909928 0.4392157 128. ! +// ! 0.4392157 - 0.3677883 - 0.0714274 128. ! +// ! 0. 0. 0. 1. ! +// +// ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! +// ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! +// ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! +// ! 0. 0. 0. 1. ! +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGenYCbCr601ToRGB32 : public VDPixmapGenYCbCrToRGB32Base { +public: + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; + } + +protected: + virtual void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_601; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + for(sint32 i=0; iround(inv([1 0 0 0; 0 1 0 0; 0 0 1 0; -16 -128 -128 1] * [1.1643828 1.1643828 1.1643828 0; 1.5960273 -0.8129688 0 0; + // 0 -0.3917617 2.0172305 0; 0 0 0 1]) .* 65536) + // ans = + // + // ! 16829. 28784. - 9714. 0. ! + // ! 33039. - 24103. - 19071. 0. ! + // ! 6416. - 4681. 28784. 0. ! + // ! 1048576. 8388608. 8388608. 65536. ! + + *dstCr++ = (28784*r - 24103*g - 4681*b + 8388608 + 32768) >> 16; + *dstY ++ = (16829*r + 33039*g + 6416*b + 1048576 + 32768) >> 16; + *dstCb++ = (-9714*r - 19071*g + 28784*b + 8388608 + 32768) >> 16; + } + } +}; + +class VDPixmapGenRGB32FToYCbCr601 : public VDPixmapGenRGB32FToYCbCrBase { +public: + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_601; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dstCb = (float *)dst0; + float *dstY = dstCb + mWindowPitch; + float *dstCr = dstY + mWindowPitch; + + const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iKr=0.2126; Kb=0.0722; Z=0; S=255; L = [Kr 1-Kr-Kb Kb]; Y = [219*(L-Z)/S 16]; U = [112*([0 0 1]-L)/((1-Kb)*S) 128]; V +// = [112*([1 0 0]-L)/((1-Kr)*S) 128]; M = [Y; U; V; 0 0 0 1]; disp(M); disp(inv(M)); +// +// ! 0.1825859 0.6142306 0.0620071 16. ! +// ! - 0.1006437 - 0.3385720 0.4392157 128. ! +// ! 0.4392157 - 0.3989422 - 0.0402735 128. ! +// ! 0. 0. 0. 1. ! +// +// ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! +// ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! +// ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! +// ! 0. 0. 0. 1. ! +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGenYCbCr709ToRGB32 : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 4); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; + } + +protected: + virtual void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iStart(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 16); + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + for(sint32 i=0; i> 16; + *dstY ++ = (11966*r + 40254*g + 4064*b + 1048576 + 32768) >> 16; + *dstCb++ = (-6596*r - 22189*g + 28784*b + 8388608 + 32768) >> 16; + } + } +}; + +class VDPixmapGenRGB32FToYCbCr709 : public VDPixmapGenWindowBasedOneSource { +public: + void Init(IVDPixmapGen *src, uint32 srcindex) { + InitSource(src, srcindex); + } + + void Start() { + StartWindow(mWidth * sizeof(float), 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 y) { + float *dstCr = (float *)dst0; + float *dstY = dstCr + mWindowPitch; + float *dstCb = dstY + mWindowPitch; + + const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; i Rec.709 converters +// +// Rec.601 to Rec.709: +// +// 1. - 0.1155497 - 0.2079376 41.406386 +// 0 1.0186397 0.1146180 - 17.056983 +// 0 0.0750494 1.0253271 - 12.848195 +// +// Rec.709 to Rec.601: +// +// 1. 0.0993117 0.1916995 - 37.249435 +// 0 0.9898538 - 0.1106525 15.462234 +// 0 - 0.0724530 0.9833978 11.399058 +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class VDPixmapGenYCbCr601ToYCbCr709 : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth, 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 ypos) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(ypos, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + for(sint32 i=0; i> 16); + *dstCb++ = (66758*cb + 7512*cr - 1117846 + 32768) >> 16; + *dstCr++ = (4918*cb + 67196*cr - 842019 + 32768) >> 16; + } + } +}; + +class VDPixmapGenYCbCr709ToYCbCr601 : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth, 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 ypos) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(ypos, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + for(sint32 i=0; i> 16); + *dstCb++ = (64871*cb - 7252*cr + 1013376 + 32768) >> 16; + *dstCr++ = (-4748*cb + 64448*cr + 747008 + 32768) >> 16; + } + } +}; + +class VDPixmapGenYCbCr601ToYCbCr709_32F : public VDPixmapGenYCbCrToRGBBase { +public: + void Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * sizeof(float), 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 ypos) { + float *dstCr = (float *)dst0; + float *dstY = vdptroffset(dstCr, mWindowPitch); + float *dstCb = vdptroffset(dstY, mWindowPitch); + + const float *srcY = (const float *)mpSrcY->GetRow(ypos, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; iStart(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * sizeof(float), 3); + } + + const void *GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; + } + + uint32 GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | kVDPixSpace_YCC_709; + } + +protected: + void Compute(void *dst0, sint32 ypos) { + float *dstCr = (float *)dst0; + float *dstY = vdptroffset(dstCr, mWindowPitch); + float *dstCb = vdptroffset(dstY, mWindowPitch); + + const float *srcY = (const float *)mpSrcY->GetRow(ypos, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + for(sint32 i=0; i -#include "uberblit.h" -#include "uberblit_ycbcr.h" - -extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); - -class VDPixmapGenYCbCr601ToRGB32_MMX : public VDPixmapGenYCbCr601ToRGB32 { -protected: - void Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(dst, srcY, srcCb, srcCr, mWidth); - } -}; - -class VDPixmapGenRGB32ToYCbCr601_SSE2 : public VDPixmapGenRGB32ToYCbCr601 { -protected: - void Compute(void *dst0, sint32 y); -}; - -#endif +#ifndef f_VD2_KASUMI_UBERBLIT_YCBCR_X86_H +#define f_VD2_KASUMI_UBERBLIT_YCBCR_X86_H + +#include +#include "uberblit.h" +#include "uberblit_ycbcr.h" + +extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); + +class VDPixmapGenYCbCr601ToRGB32_MMX : public VDPixmapGenYCbCr601ToRGB32 { +protected: + void Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(dst, srcY, srcCb, srcCr, mWidth); + } +}; + +class VDPixmapGenRGB32ToYCbCr601_SSE2 : public VDPixmapGenRGB32ToYCbCr601 { +protected: + void Compute(void *dst0, sint32 y); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a64_resample.asm64 b/src/thirdparty/VirtualDub/Kasumi/source/a64_resample.asm64 index 91c676fe220..e6de1eabf02 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a64_resample.asm64 +++ b/src/thirdparty/VirtualDub/Kasumi/source/a64_resample.asm64 @@ -1,620 +1,620 @@ -; VirtualDub - Video processing and capture application -; Graphics support library -; Copyright (C) 1998-2004 Avery Lee -; -; This program 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 2 of the License, or -; (at your option) any later version. -; -; This program 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, write to the Free Software -; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -; - - default rel - - segment .rdata, align=16 - - align 16 -roundval dq 0000200000002000h, 0000200000002000h - - - segment .text - - -%macro VDSAVE 1-* - - %rep %0 - %rotate -1 - push %1 - [pushreg %1] - %endrep - -%endmacro - -%macro VDRESTORE 1-* - - %rep %0 - pop %1 - - %rotate 1 - %endrep - -%endmacro - -%macro VDSAVEXMM128 2 -%assign %%count %2 + 1 - %1 -%assign %%stkoffset 0 -%assign %%reg %1 - - sub rsp, %%count*16+8 - [allocstack %%count*16] - - %rep %%count - movdqa oword [rsp+%%stkoffset], xmm %+ %%reg - [savexmm128 xmm %+ %%reg, %%stkoffset] - - %assign %%stkoffset %%stkoffset + 16 - %assign %%reg %%reg + 1 - %endrep -%endmacro - -%macro VDRESTOREXMM128 2 -%assign %%count %2+1-%1 -%assign %%stkoffset %%count*16 -%assign %%reg %2 - - %rep %%count - %assign %%stkoffset %%stkoffset-16 - movdqa xmm %+ %%reg, oword [rsp+%%stkoffset] - - %assign %%reg %%reg-1 - %endrep - - add rsp, %%count*16+8 -%endmacro - -;------------------------------------------------------------------------- -; -; long vdasm_resize_table_row_SSE2( -; Pixel *out, // rcx -; Pixel *in, // rdx -; int *filter, // r8 -; int filter_width, // r9d -; PixDim w, // [rsp+40] -; long accum, // [rsp+48] -; long frac); // [rsp+56] -; - global vdasm_resize_table_row_SSE2 -proc_frame vdasm_resize_table_row_SSE2 - - VDSAVE rbx, rsi, rdi, rbp, r12, r13, r14, r15 - VDSAVEXMM128 6, 15 -end_prolog - - .parms equ rsp+168+64 - - mov r10d, dword [.parms+40] - shl r10, 2 - add rcx, r10 - neg r10 - shl r9d, 2 ;filter_width <<= 2 - - movaps xmm6, oword [roundval] - pxor xmm5, xmm5 - mov rsi, rdx - shr rsi, 2 - - mov edi, [.parms+48] - mov eax, edi - shl edi, 16 - sar rax, 16 - add rsi, rax - mov ebp, [.parms+56] - movsxd r11, ebp - shl ebp, 16 - sar r11, 16 - - ;register map - ; - ;eax temp coefficient pair counter - ;rbx temp coefficient pointer - ;rcx destination - ;rdx temp source - ;rsi source/4 - ;edi accumulator - ;ebp fractional increment - ;r8 filter - ;r9 filter_width*4 - ;r10 -width*4 - ;r11 integral increment - ;r12 - ;r13 - ;r14 - ;r15 - - cmp r9d, 16 - jz .accel_4coeff - cmp r9d, 24 - jz .accel_6coeff - - test r9d, 8 - jz .pixelloop_even_pairs - cmp r9d, 8 - jnz .pixelloop_odd_pairs - -.pixelloop_single_pairs: - mov eax, edi - shr eax, 24 - imul eax, r9d - - lea rdx, [rsi*4] - - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - punpcklbw xmm0, xmm1 - punpcklbw xmm0, xmm5 - movq xmm1, qword [r8+rax] - pshufd xmm1, xmm1, 01000100b - pmaddwd xmm0, xmm1 - - movdqa xmm4, xmm6 - paddd xmm4, xmm0 - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_single_pairs - jmp .xit - -.pixelloop_odd_pairs: - movdqa xmm4, xmm6 - - mov eax, edi - shr eax, 24 - imul eax, r9d - lea rbx, [r8+rax] - - lea rdx, [rsi*4] - lea rax, [r9-8] -.coeffloop_odd_pairs: - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - movd xmm2, dword [rdx+8] ;xmm2 = p2 - movd xmm3, dword [rdx+12] ;xmm3 = p3 - add rdx, 16 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - movq xmm1, qword [rbx] - movq xmm3, qword [rbx+8] - add rbx, 16 - pshufd xmm1, xmm1, 01000100b - pshufd xmm3, xmm3, 01000100b - pmaddwd xmm0, xmm1 - pmaddwd xmm2, xmm3 - paddd xmm0, xmm2 - paddd xmm4, xmm0 - sub eax, 16 - jnz .coeffloop_odd_pairs - - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - punpcklbw xmm0, xmm1 - punpcklbw xmm0, xmm5 - movq xmm1, qword [rbx] - pshufd xmm1, xmm1, 01000100b - pmaddwd xmm0, xmm1 - paddd xmm4, xmm0 - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_odd_pairs - jmp .xit - -.pixelloop_even_pairs: - movdqa xmm4, xmm6 - - mov eax, edi - shr eax, 24 - imul eax, r9d - lea rbx, [r8+rax] - - lea rdx, [rsi*4] - mov eax, r9d -.coeffloop_even_pairs: - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - movd xmm2, dword [rdx+8] ;xmm2 = p2 - movd xmm3, dword [rdx+12] ;xmm3 = p3 - add rdx, 16 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - movq xmm1, qword [rbx] - movq xmm3, qword [rbx+8] - add rbx, 16 - pshufd xmm1, xmm1, 01000100b - pshufd xmm3, xmm3, 01000100b - pmaddwd xmm0, xmm1 - pmaddwd xmm2, xmm3 - paddd xmm0, xmm2 - paddd xmm4, xmm0 - sub eax, 16 - jnz .coeffloop_even_pairs - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_even_pairs - -.xit: - VDRESTOREXMM128 6, 15 - VDRESTORE rbx, rsi, rdi, rbp, r12, r13, r14, r15 - ret - -.accel_4coeff: -.pixelloop_4coeff: - pxor xmm5, xmm5 - movdqa xmm4, xmm6 - - mov eax, 0ff000000h - lea rdx, [rsi*4] - and eax, edi - shr eax, 20 - lea rbx, [r8+rax] - - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - movd xmm2, dword [rdx+8] ;xmm2 = p2 - movd xmm3, dword [rdx+12] ;xmm3 = p3 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - movq xmm1, qword [rbx] - movq xmm3, qword [rbx+8] - pshufd xmm1, xmm1, 01000100b - pshufd xmm3, xmm3, 01000100b - pmaddwd xmm0, xmm1 - pmaddwd xmm2, xmm3 - paddd xmm0, xmm2 - paddd xmm4, xmm0 - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_4coeff - jmp .xit - -.accel_6coeff: -.pixelloop_6coeff: - pxor xmm5, xmm5 - movdqa xmm4, xmm6 - - lea rdx, [rsi*4] - mov eax, edi - shr eax, 24 - lea rax, [rax+rax*2] - lea rbx, [r8+rax*8] - - movd xmm0, dword [rdx] ;xmm0 = p0 - movd xmm1, dword [rdx+4] ;xmm1 = p1 - movd xmm2, dword [rdx+8] ;xmm2 = p2 - movd xmm3, dword [rdx+12] ;xmm3 = p3 - movd xmm8, dword [rdx+16] ;xmm6 = p4 - movd xmm9, dword [rdx+20] ;xmm7 = p5 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm8, xmm9 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - punpcklbw xmm8, xmm5 - movq xmm1, qword [rbx] - movq xmm3, qword [rbx+8] - movq xmm9, qword [rbx+16] - pshufd xmm1, xmm1, 01000100b - pshufd xmm3, xmm3, 01000100b - pshufd xmm9, xmm9, 01000100b - pmaddwd xmm0, xmm1 - pmaddwd xmm2, xmm3 - pmaddwd xmm8, xmm9 - paddd xmm0, xmm2 - paddd xmm4, xmm0 - paddd xmm4, xmm8 - - psrad xmm4, 14 - packssdw xmm4, xmm4 - packuswb xmm4, xmm4 - - add edi, ebp - adc rsi, r11 - - movd dword [rcx+r10], xmm4 - add r10, 4 - jnz .pixelloop_6coeff - jmp .xit -endproc_frame - - -;-------------------------------------------------------------------------- -; -; vdasm_resize_table_col_SSE2( -; uint32 *dst, // rcx -; const uint32 *const *srcs, // rdx -; int *filter, // r8 -; int filter_width, // r9d -; PixDim w, // [rsp+40] -> r10d -; ); -; - global vdasm_resize_table_col_SSE2 -proc_frame vdasm_resize_table_col_SSE2 - VDSAVE rbx, rsi, rdi, rbp, r12, r13, r14, r15 - VDSAVEXMM128 6, 15 -end_prolog - - .parms equ rsp+168+64 - - mov r10d, [.parms+40] ;r10d = w - - pxor xmm5, xmm5 - movdqa xmm4, oword [roundval] - xor rbx, rbx ;rbx = source offset - - cmp r9d, 4 - jz .accel_4coeff - cmp r9d, 6 - jz .accel_6coeff - - shr r9d, 1 ;r9d = filter pair count - -.pixelloop: - mov rax, rdx ;rax = row pointer table - mov rdi, r8 ;rdi = filter - mov r11d, r9d ;r11d = filter width counter - movdqa xmm2, xmm4 -.coeffloop: - mov rsi, [rax] - - movd xmm0, dword [rsi+rbx] - - mov rsi, [rax+8] - add rax, 16 - - movd xmm1, dword [rsi+rbx] - punpcklbw xmm0, xmm1 - - punpcklbw xmm0, xmm5 - - movq xmm1, qword [rdi] - pshufd xmm1, xmm1, 01000100b - - pmaddwd xmm0, xmm1 - - paddd xmm2, xmm0 - - add rdi,8 - - sub r11d,1 - jne .coeffloop - - psrad xmm2,14 - packssdw xmm2,xmm2 - add rbx,4 - packuswb xmm2,xmm2 - - movd dword [rcx],xmm2 - add rcx,4 - sub r10d,1 - jne .pixelloop - -.xit: - VDRESTOREXMM128 6, 15 - VDRESTORE rbx, rsi, rdi, rbp, r12, r13, r14, r15 - ret - -.accel_4coeff: - mov r12, [rdx] - mov r13, [rdx+8] - mov r14, [rdx+16] - mov r15, [rdx+24] - movq xmm8, qword [r8] - punpcklqdq xmm8, xmm8 - movq xmm9, qword [r8+8] - punpcklqdq xmm9, xmm9 - - sub r10d, 1 - jc .oddpixel_4coeff -.pixelloop_4coeff: - movq xmm0, qword [r12+rbx] - movq xmm1, qword [r13+rbx] - movq xmm2, qword [r14+rbx] - movq xmm3, qword [r15+rbx] - - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - - punpcklbw xmm0, xmm5 - punpckhbw xmm1, xmm5 - punpcklbw xmm2, xmm5 - punpckhbw xmm3, xmm5 - - pmaddwd xmm0, xmm8 - pmaddwd xmm1, xmm8 - pmaddwd xmm2, xmm9 - pmaddwd xmm3, xmm9 - - paddd xmm0, xmm4 - paddd xmm1, xmm4 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - - psrad xmm0, 14 - psrad xmm1, 14 - packssdw xmm0, xmm1 - packuswb xmm0, xmm0 - - movq qword [rcx], xmm0 - add rcx, 8 - add rbx, 8 - sub r10d, 2 - ja .pixelloop_4coeff - jnz .xit -.oddpixel_4coeff: - movd xmm0, dword [r12+rbx] - movd xmm1, dword [r13+rbx] - movd xmm2, dword [r14+rbx] - movd xmm3, dword [r15+rbx] - - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - - pmaddwd xmm0, xmm8 - pmaddwd xmm2, xmm9 - - paddd xmm0, xmm4 - paddd xmm0, xmm2 - - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - - movd dword [rcx], xmm0 - - jmp .xit - -.accel_6coeff: - mov r12, [rdx] - mov r13, [rdx+8] - mov r14, [rdx+16] - mov r15, [rdx+24] - mov rsi, [rdx+32] - mov rdx, [rdx+40] - movq xmm10, qword [r8] - punpcklqdq xmm10, xmm10 - movq xmm11, qword [r8+8] - punpcklqdq xmm11, xmm11 - movq xmm12, qword [r8+16] - punpcklqdq xmm12, xmm12 - - sub r10d, 1 - jc .oddpixel_6coeff -.pixelloop_6coeff: - movq xmm0, qword [r12+rbx] - movq xmm1, qword [r13+rbx] - movq xmm2, qword [r14+rbx] - movq xmm3, qword [r15+rbx] - movq xmm8, qword [rsi+rbx] - movq xmm9, qword [rdx+rbx] - - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm8, xmm9 - - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - movdqa xmm9, xmm8 - - punpcklbw xmm0, xmm5 - punpckhbw xmm1, xmm5 - punpcklbw xmm2, xmm5 - punpckhbw xmm3, xmm5 - punpcklbw xmm8, xmm5 - punpckhbw xmm9, xmm5 - - pmaddwd xmm0, xmm10 - pmaddwd xmm1, xmm10 - pmaddwd xmm2, xmm11 - pmaddwd xmm3, xmm11 - pmaddwd xmm8, xmm12 - pmaddwd xmm9, xmm12 - - paddd xmm0, xmm4 - paddd xmm1, xmm4 - paddd xmm2, xmm8 - paddd xmm3, xmm9 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - - psrad xmm0, 14 - psrad xmm1, 14 - packssdw xmm0, xmm1 - packuswb xmm0, xmm0 - - movq qword [rcx], xmm0 - add rcx, 8 - add rbx, 8 - sub r10d, 2 - ja .pixelloop_6coeff - jnz .xit -.oddpixel_6coeff: - movd xmm0, dword [r12+rbx] - movd xmm1, dword [r13+rbx] - movd xmm2, dword [r14+rbx] - movd xmm3, dword [r15+rbx] - movd xmm8, dword [rsi+rbx] - movd xmm9, dword [rdx+rbx] - - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm8, xmm9 - punpcklbw xmm0, xmm5 - punpcklbw xmm2, xmm5 - punpcklbw xmm8, xmm5 - - pmaddwd xmm0, xmm10 - pmaddwd xmm2, xmm11 - pmaddwd xmm8, xmm12 - - paddd xmm0, xmm4 - paddd xmm2, xmm8 - paddd xmm0, xmm2 - - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - - movd dword [rcx], xmm0 - - jmp .xit -endproc_frame - - end +; VirtualDub - Video processing and capture application +; Graphics support library +; Copyright (C) 1998-2004 Avery Lee +; +; This program 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 2 of the License, or +; (at your option) any later version. +; +; This program 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, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +; + + default rel + + segment .rdata, align=16 + + align 16 +roundval dq 0000200000002000h, 0000200000002000h + + + segment .text + + +%macro VDSAVE 1-* + + %rep %0 + %rotate -1 + push %1 + [pushreg %1] + %endrep + +%endmacro + +%macro VDRESTORE 1-* + + %rep %0 + pop %1 + + %rotate 1 + %endrep + +%endmacro + +%macro VDSAVEXMM128 2 +%assign %%count %2 + 1 - %1 +%assign %%stkoffset 0 +%assign %%reg %1 + + sub rsp, %%count*16+8 + [allocstack %%count*16] + + %rep %%count + movdqa oword [rsp+%%stkoffset], xmm %+ %%reg + [savexmm128 xmm %+ %%reg, %%stkoffset] + + %assign %%stkoffset %%stkoffset + 16 + %assign %%reg %%reg + 1 + %endrep +%endmacro + +%macro VDRESTOREXMM128 2 +%assign %%count %2+1-%1 +%assign %%stkoffset %%count*16 +%assign %%reg %2 + + %rep %%count + %assign %%stkoffset %%stkoffset-16 + movdqa xmm %+ %%reg, oword [rsp+%%stkoffset] + + %assign %%reg %%reg-1 + %endrep + + add rsp, %%count*16+8 +%endmacro + +;------------------------------------------------------------------------- +; +; long vdasm_resize_table_row_SSE2( +; Pixel *out, // rcx +; Pixel *in, // rdx +; int *filter, // r8 +; int filter_width, // r9d +; PixDim w, // [rsp+40] +; long accum, // [rsp+48] +; long frac); // [rsp+56] +; + global vdasm_resize_table_row_SSE2 +proc_frame vdasm_resize_table_row_SSE2 + + VDSAVE rbx, rsi, rdi, rbp, r12, r13, r14, r15 + VDSAVEXMM128 6, 15 +end_prolog + + .parms equ rsp+168+64 + + mov r10d, dword [.parms+40] + shl r10, 2 + add rcx, r10 + neg r10 + shl r9d, 2 ;filter_width <<= 2 + + movaps xmm6, oword [roundval] + pxor xmm5, xmm5 + mov rsi, rdx + shr rsi, 2 + + mov edi, [.parms+48] + mov eax, edi + shl edi, 16 + sar rax, 16 + add rsi, rax + mov ebp, [.parms+56] + movsxd r11, ebp + shl ebp, 16 + sar r11, 16 + + ;register map + ; + ;eax temp coefficient pair counter + ;rbx temp coefficient pointer + ;rcx destination + ;rdx temp source + ;rsi source/4 + ;edi accumulator + ;ebp fractional increment + ;r8 filter + ;r9 filter_width*4 + ;r10 -width*4 + ;r11 integral increment + ;r12 + ;r13 + ;r14 + ;r15 + + cmp r9d, 16 + jz .accel_4coeff + cmp r9d, 24 + jz .accel_6coeff + + test r9d, 8 + jz .pixelloop_even_pairs + cmp r9d, 8 + jnz .pixelloop_odd_pairs + +.pixelloop_single_pairs: + mov eax, edi + shr eax, 24 + imul eax, r9d + + lea rdx, [rsi*4] + + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + punpcklbw xmm0, xmm1 + punpcklbw xmm0, xmm5 + movq xmm1, qword [r8+rax] + pshufd xmm1, xmm1, 01000100b + pmaddwd xmm0, xmm1 + + movdqa xmm4, xmm6 + paddd xmm4, xmm0 + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_single_pairs + jmp .xit + +.pixelloop_odd_pairs: + movdqa xmm4, xmm6 + + mov eax, edi + shr eax, 24 + imul eax, r9d + lea rbx, [r8+rax] + + lea rdx, [rsi*4] + lea rax, [r9-8] +.coeffloop_odd_pairs: + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + movd xmm2, dword [rdx+8] ;xmm2 = p2 + movd xmm3, dword [rdx+12] ;xmm3 = p3 + add rdx, 16 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + movq xmm1, qword [rbx] + movq xmm3, qword [rbx+8] + add rbx, 16 + pshufd xmm1, xmm1, 01000100b + pshufd xmm3, xmm3, 01000100b + pmaddwd xmm0, xmm1 + pmaddwd xmm2, xmm3 + paddd xmm0, xmm2 + paddd xmm4, xmm0 + sub eax, 16 + jnz .coeffloop_odd_pairs + + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + punpcklbw xmm0, xmm1 + punpcklbw xmm0, xmm5 + movq xmm1, qword [rbx] + pshufd xmm1, xmm1, 01000100b + pmaddwd xmm0, xmm1 + paddd xmm4, xmm0 + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_odd_pairs + jmp .xit + +.pixelloop_even_pairs: + movdqa xmm4, xmm6 + + mov eax, edi + shr eax, 24 + imul eax, r9d + lea rbx, [r8+rax] + + lea rdx, [rsi*4] + mov eax, r9d +.coeffloop_even_pairs: + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + movd xmm2, dword [rdx+8] ;xmm2 = p2 + movd xmm3, dword [rdx+12] ;xmm3 = p3 + add rdx, 16 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + movq xmm1, qword [rbx] + movq xmm3, qword [rbx+8] + add rbx, 16 + pshufd xmm1, xmm1, 01000100b + pshufd xmm3, xmm3, 01000100b + pmaddwd xmm0, xmm1 + pmaddwd xmm2, xmm3 + paddd xmm0, xmm2 + paddd xmm4, xmm0 + sub eax, 16 + jnz .coeffloop_even_pairs + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_even_pairs + +.xit: + VDRESTOREXMM128 6, 15 + VDRESTORE rbx, rsi, rdi, rbp, r12, r13, r14, r15 + ret + +.accel_4coeff: +.pixelloop_4coeff: + pxor xmm5, xmm5 + movdqa xmm4, xmm6 + + mov eax, 0ff000000h + lea rdx, [rsi*4] + and eax, edi + shr eax, 20 + lea rbx, [r8+rax] + + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + movd xmm2, dword [rdx+8] ;xmm2 = p2 + movd xmm3, dword [rdx+12] ;xmm3 = p3 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + movq xmm1, qword [rbx] + movq xmm3, qword [rbx+8] + pshufd xmm1, xmm1, 01000100b + pshufd xmm3, xmm3, 01000100b + pmaddwd xmm0, xmm1 + pmaddwd xmm2, xmm3 + paddd xmm0, xmm2 + paddd xmm4, xmm0 + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_4coeff + jmp .xit + +.accel_6coeff: +.pixelloop_6coeff: + pxor xmm5, xmm5 + movdqa xmm4, xmm6 + + lea rdx, [rsi*4] + mov eax, edi + shr eax, 24 + lea rax, [rax+rax*2] + lea rbx, [r8+rax*8] + + movd xmm0, dword [rdx] ;xmm0 = p0 + movd xmm1, dword [rdx+4] ;xmm1 = p1 + movd xmm2, dword [rdx+8] ;xmm2 = p2 + movd xmm3, dword [rdx+12] ;xmm3 = p3 + movd xmm8, dword [rdx+16] ;xmm6 = p4 + movd xmm9, dword [rdx+20] ;xmm7 = p5 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm8, xmm9 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + punpcklbw xmm8, xmm5 + movq xmm1, qword [rbx] + movq xmm3, qword [rbx+8] + movq xmm9, qword [rbx+16] + pshufd xmm1, xmm1, 01000100b + pshufd xmm3, xmm3, 01000100b + pshufd xmm9, xmm9, 01000100b + pmaddwd xmm0, xmm1 + pmaddwd xmm2, xmm3 + pmaddwd xmm8, xmm9 + paddd xmm0, xmm2 + paddd xmm4, xmm0 + paddd xmm4, xmm8 + + psrad xmm4, 14 + packssdw xmm4, xmm4 + packuswb xmm4, xmm4 + + add edi, ebp + adc rsi, r11 + + movd dword [rcx+r10], xmm4 + add r10, 4 + jnz .pixelloop_6coeff + jmp .xit +endproc_frame + + +;-------------------------------------------------------------------------- +; +; vdasm_resize_table_col_SSE2( +; uint32 *dst, // rcx +; const uint32 *const *srcs, // rdx +; int *filter, // r8 +; int filter_width, // r9d +; PixDim w, // [rsp+40] -> r10d +; ); +; + global vdasm_resize_table_col_SSE2 +proc_frame vdasm_resize_table_col_SSE2 + VDSAVE rbx, rsi, rdi, rbp, r12, r13, r14, r15 + VDSAVEXMM128 6, 15 +end_prolog + + .parms equ rsp+168+64 + + mov r10d, [.parms+40] ;r10d = w + + pxor xmm5, xmm5 + movdqa xmm4, oword [roundval] + xor rbx, rbx ;rbx = source offset + + cmp r9d, 4 + jz .accel_4coeff + cmp r9d, 6 + jz .accel_6coeff + + shr r9d, 1 ;r9d = filter pair count + +.pixelloop: + mov rax, rdx ;rax = row pointer table + mov rdi, r8 ;rdi = filter + mov r11d, r9d ;r11d = filter width counter + movdqa xmm2, xmm4 +.coeffloop: + mov rsi, [rax] + + movd xmm0, dword [rsi+rbx] + + mov rsi, [rax+8] + add rax, 16 + + movd xmm1, dword [rsi+rbx] + punpcklbw xmm0, xmm1 + + punpcklbw xmm0, xmm5 + + movq xmm1, qword [rdi] + pshufd xmm1, xmm1, 01000100b + + pmaddwd xmm0, xmm1 + + paddd xmm2, xmm0 + + add rdi,8 + + sub r11d,1 + jne .coeffloop + + psrad xmm2,14 + packssdw xmm2,xmm2 + add rbx,4 + packuswb xmm2,xmm2 + + movd dword [rcx],xmm2 + add rcx,4 + sub r10d,1 + jne .pixelloop + +.xit: + VDRESTOREXMM128 6, 15 + VDRESTORE rbx, rsi, rdi, rbp, r12, r13, r14, r15 + ret + +.accel_4coeff: + mov r12, [rdx] + mov r13, [rdx+8] + mov r14, [rdx+16] + mov r15, [rdx+24] + movq xmm8, qword [r8] + punpcklqdq xmm8, xmm8 + movq xmm9, qword [r8+8] + punpcklqdq xmm9, xmm9 + + sub r10d, 1 + jc .oddpixel_4coeff +.pixelloop_4coeff: + movq xmm0, qword [r12+rbx] + movq xmm1, qword [r13+rbx] + movq xmm2, qword [r14+rbx] + movq xmm3, qword [r15+rbx] + + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + + punpcklbw xmm0, xmm5 + punpckhbw xmm1, xmm5 + punpcklbw xmm2, xmm5 + punpckhbw xmm3, xmm5 + + pmaddwd xmm0, xmm8 + pmaddwd xmm1, xmm8 + pmaddwd xmm2, xmm9 + pmaddwd xmm3, xmm9 + + paddd xmm0, xmm4 + paddd xmm1, xmm4 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + + psrad xmm0, 14 + psrad xmm1, 14 + packssdw xmm0, xmm1 + packuswb xmm0, xmm0 + + movq qword [rcx], xmm0 + add rcx, 8 + add rbx, 8 + sub r10d, 2 + ja .pixelloop_4coeff + jnz .xit +.oddpixel_4coeff: + movd xmm0, dword [r12+rbx] + movd xmm1, dword [r13+rbx] + movd xmm2, dword [r14+rbx] + movd xmm3, dword [r15+rbx] + + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + + pmaddwd xmm0, xmm8 + pmaddwd xmm2, xmm9 + + paddd xmm0, xmm4 + paddd xmm0, xmm2 + + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + + movd dword [rcx], xmm0 + + jmp .xit + +.accel_6coeff: + mov r12, [rdx] + mov r13, [rdx+8] + mov r14, [rdx+16] + mov r15, [rdx+24] + mov rsi, [rdx+32] + mov rdx, [rdx+40] + movq xmm10, qword [r8] + punpcklqdq xmm10, xmm10 + movq xmm11, qword [r8+8] + punpcklqdq xmm11, xmm11 + movq xmm12, qword [r8+16] + punpcklqdq xmm12, xmm12 + + sub r10d, 1 + jc .oddpixel_6coeff +.pixelloop_6coeff: + movq xmm0, qword [r12+rbx] + movq xmm1, qword [r13+rbx] + movq xmm2, qword [r14+rbx] + movq xmm3, qword [r15+rbx] + movq xmm8, qword [rsi+rbx] + movq xmm9, qword [rdx+rbx] + + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm8, xmm9 + + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + movdqa xmm9, xmm8 + + punpcklbw xmm0, xmm5 + punpckhbw xmm1, xmm5 + punpcklbw xmm2, xmm5 + punpckhbw xmm3, xmm5 + punpcklbw xmm8, xmm5 + punpckhbw xmm9, xmm5 + + pmaddwd xmm0, xmm10 + pmaddwd xmm1, xmm10 + pmaddwd xmm2, xmm11 + pmaddwd xmm3, xmm11 + pmaddwd xmm8, xmm12 + pmaddwd xmm9, xmm12 + + paddd xmm0, xmm4 + paddd xmm1, xmm4 + paddd xmm2, xmm8 + paddd xmm3, xmm9 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + + psrad xmm0, 14 + psrad xmm1, 14 + packssdw xmm0, xmm1 + packuswb xmm0, xmm0 + + movq qword [rcx], xmm0 + add rcx, 8 + add rbx, 8 + sub r10d, 2 + ja .pixelloop_6coeff + jnz .xit +.oddpixel_6coeff: + movd xmm0, dword [r12+rbx] + movd xmm1, dword [r13+rbx] + movd xmm2, dword [r14+rbx] + movd xmm3, dword [r15+rbx] + movd xmm8, dword [rsi+rbx] + movd xmm9, dword [rdx+rbx] + + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm8, xmm9 + punpcklbw xmm0, xmm5 + punpcklbw xmm2, xmm5 + punpcklbw xmm8, xmm5 + + pmaddwd xmm0, xmm10 + pmaddwd xmm2, xmm11 + pmaddwd xmm8, xmm12 + + paddd xmm0, xmm4 + paddd xmm2, xmm8 + paddd xmm0, xmm2 + + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + + movd dword [rcx], xmm0 + + jmp .xit +endproc_frame + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb.asm index 9582736901c..f3503807e55 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb.asm @@ -1,812 +1,812 @@ - section .text - - global _vdasm_pixblt_RGB565_to_XRGB1555 -_vdasm_pixblt_RGB565_to_XRGB1555: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-2] - lea ecx, [ecx+ebp-2] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp] - mov ebx, 0ffc0ffc0h - - and ebx, eax - and eax, 0001f001fh - - shr ebx, 1 - - add eax, ebx - - mov [edx+ebp], eax - add ebp, 4 - - jnc .xloop - jnz .noodd -.odd: - movzx eax, word [ecx] - mov ebx, 0ffc0ffc0h - and ebx, eax - and eax, 0001f001fh - shr ebx, 1 - add eax, ebx - mov [edx], ax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_pixblt_RGB888_to_XRGB1555 -_vdasm_pixblt_RGB888_to_XRGB1555: - push ebp - push edi - push esi - push ebx - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ebp,[esp+20+16] - lea eax,[ebp+ebp] - lea ebx,[ebp+eax] - sub [esp+8+16],eax - sub [esp+16+16],ebx - - mov edx,[esp+24+16] -.yloop: - mov ebp,[esp+20+16] - push ebp - push edx - shr ebp,1 - jz .checkodd -.xloop: - mov eax,[esi+2] ;u - add esi,6 ;v - - mov ebx,eax ;u - mov ecx,eax ;v - shr ebx,11 ;u - and ecx,00f80000h ;v - shr eax,17 ;u - and ebx,0000001fh ;v - shr ecx,14 ;u - and eax,00007c00h ;v - or ebx,ecx ;u - add edi,4 ;v - or ebx,eax ;u - - mov ecx,[esi-6] ;v - mov edx,ebx ;u - mov eax,ecx ;v - - shl edx,16 ;u - mov ebx,ecx ;v - shr ebx,3 ;u - and ecx,0000f800h ;v - shr eax,9 ;u - and ebx,0000001fh ;v - shr ecx,6 ;u - and eax,00007c00h ;v - or eax,ecx ;u - or edx,ebx ;v - or edx,eax ;u - sub ebp,1 ;v - mov [edi-4],edx ;u - jne .xloop ;v -.checkodd: - pop edx - pop ebp - and ebp,1 - jz .noodd - movzx eax,word [esi] - movzx ebx,byte [esi+2] - shl ebx,16 - add esi,3 - add eax,ebx - - mov ebx,eax - mov ecx,eax - shr ebx,3 - and ecx,0000f800h - shr eax,9 - and ebx,0000001fh - shr ecx,6 - and eax,00007c00h - or ebx,ecx - or ebx,eax - mov [edi+0],bl - mov [edi+1],bh - add edi,2 -.noodd: - - add esi,[esp+16+16] - add edi,[esp+ 8+16] - - sub edx,1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - - ret - - global _vdasm_pixblt_XRGB8888_to_XRGB1555 -_vdasm_pixblt_XRGB8888_to_XRGB1555: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - mov edx, [esp+4+16] - add ebp, ebp - mov ecx, [esp+12+16] - lea edx, [edx+ebp-2] - lea ecx, [ecx+ebp*2-4] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp*2] - mov ebx, 00f80000h - and ebx, eax - mov esi, eax - shr ebx, 9 - and esi, 0000f800h - shr esi, 6 - and eax, 000000f8h - shr eax, 3 - add ebx, esi - mov esi, [ecx+ebp*2+4] - add eax, ebx - mov ebx, esi - and esi, 00f80000h - shl esi, 7 - mov edi, ebx - and edi, 0000f800h - add eax, esi - shl edi, 10 - and ebx, 000000f8h - shl ebx, 13 - add eax, edi - add eax, ebx - mov [edx+ebp], eax - add ebp, 4 - jnc .xloop - jnz .noodd -.odd: - mov eax, [ecx] - mov ebx, 00f80000h - and ebx, eax - mov esi, eax - shr ebx, 9 - and esi, 0000f800h - shr esi, 6 - and eax, 000000f8h - shr eax, 3 - add ebx, esi - add eax, ebx - mov [edx], ax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec dword [esp+24+16] - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_pixblt_XRGB1555_to_RGB565 -_vdasm_pixblt_XRGB1555_to_RGB565: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-2] - lea ecx, [ecx+ebp-2] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp] - mov ebx, 02000200h - - mov esi, eax - and ebx, eax - - shr ebx, 4 - and esi, 0ffe0ffe0h - - add eax, esi - - add eax, ebx - - mov [edx+ebp], eax - add ebp, 4 - - jnc .xloop - jnz .noodd -.odd: - movzx eax, word [ecx] - mov ebx, 02000200h - mov esi, eax - and ebx, eax - shr ebx, 4 - and esi, 0ffe0ffe0h - add eax, esi - add eax, ebx - mov [edx], ax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_pixblt_RGB888_to_RGB565 -_vdasm_pixblt_RGB888_to_RGB565: - push ebp - push edi - push esi - push ebx - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ebp,[esp+20+16] - lea eax,[ebp+ebp] - lea ebx,[ebp+eax] - sub [esp+8+16],eax - sub [esp+16+16],ebx - - mov edx,[esp+24+16] -.yloop: - mov ebp,[esp+20+16] - push ebp - push edx - shr ebp,1 - jz .checkodd -.xloop: - mov eax,[esi+2] ;u - add esi,6 ;v - - mov ebx,eax ;u - mov ecx,eax ;v - shr ebx,11 ;u - and ecx,00fc0000h ;v - shr eax,16 ;u - and ebx,0000001fh ;v - shr ecx,13 ;u - and eax,0000f800h ;v - or ebx,ecx ;u - add edi,4 ;v - or ebx,eax ;u - - mov ecx,[esi-6] ;v - mov edx,ebx ;u - mov eax,ecx ;v - - shl edx,16 ;u - mov ebx,ecx ;v - shr ebx,3 ;u - and ecx,0000fc00h ;v - shr eax,8 ;u - and ebx,0000001fh ;v - shr ecx,5 ;u - and eax,0000f800h ;v - or eax,ecx ;u - or edx,ebx ;v - or edx,eax ;u - sub ebp,1 ;v - mov [edi-4],edx ;u - jne .xloop ;v -.checkodd: - pop edx - pop ebp - and ebp,1 - jz .noodd - movzx eax,word [esi] - movzx ebx,byte [esi+2] - shl ebx,16 - add esi,3 - add eax,ebx - - mov ebx,eax - mov ecx,eax - shr ebx,3 - and ecx,0000fc00h - shr eax,8 - and ebx,0000001fh - shr ecx,5 - and eax,0000f800h - or ebx,ecx - or ebx,eax - mov [edi+0],bl - mov [edi+1],bh - add edi,2 -.noodd: - - add esi,[esp+16+16] - add edi,[esp+ 8+16] - - sub edx,1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - - ret - - global _vdasm_pixblt_XRGB8888_to_RGB565 -_vdasm_pixblt_XRGB8888_to_RGB565: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - mov edx, [esp+4+16] - add ebp, ebp - mov ecx, [esp+12+16] - lea edx, [edx+ebp-2] - lea ecx, [ecx+ebp*2-4] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp*2] - mov ebx, 00f80000h - and ebx, eax - mov esi, eax - shr ebx, 8 - and esi, 0000fc00h - shr esi, 5 - and eax, 000000f8h - shr eax, 3 - add ebx, esi - mov esi, [ecx+ebp*2+4] - add eax, ebx - mov ebx, esi - and esi, 00f80000h - shl esi, 8 - mov edi, ebx - and edi, 0000fc00h - add eax, esi - shl edi, 11 - and ebx, 000000f8h - shl ebx, 13 - add eax, edi - add eax, ebx - mov [edx+ebp], eax - add ebp, 4 - jnc .xloop - jnz .noodd -.odd: - mov eax, [ecx] - mov ebx, 00f80000h - and ebx, eax - mov esi, eax - shr ebx, 8 - and esi, 0000fc00h - shr esi, 5 - and eax, 000000f8h - shr eax, 3 - add ebx, esi - add eax, ebx - mov [edx], ax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec dword [esp+24+16] - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_pixblt_XRGB8888_to_RGB888 -_vdasm_pixblt_XRGB8888_to_RGB888: - push ebp - push edi - push esi - push ebx - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ecx,[esp+20+16] - lea eax,[ecx+ecx*2] - lea ebx,[ecx*4] - sub [esp+8+16],eax - sub [esp+16+16],ebx - - mov edx,[esp+24+16] -.yloop: - mov ecx,[esp+20+16] - push ecx - push edx - shr ecx,2 - jz .checkodd -.xloop: - mov eax,[esi] ;EAX = xxr0g0b0 - mov ebx,[esi+4] ;EBX = xxr1g1b1 - mov edx,ebx ;EDX = xxr1g1b1 - mov ebp,[esi+8] ;EBP = xxr2g2b2 - shl ebx,24 ;EBX = b1000000 - and eax,00ffffffh ;EAX = 00r0g0b0 - shr edx,8 ;EDX = 00xxr1g1 - or eax,ebx ;EAX = b1r0g0b0 - mov [edi],eax - mov ebx,ebp ;EBX = xxr2g2b2 - shl ebp,16 ;EBP = g2b20000 - and edx,0000ffffh ;EDX = 0000r1g1 - or ebp,edx ;EBP = g2b2r1g1 - mov eax,[esi+12] ;EAX = xxr3g3b3 - shr ebx,16 ;EBX = 0000xxr2 - add edi,12 - shl eax,8 ;EAX = r3g3b300 - and ebx,000000ffh ;EBX = 000000r2 - or eax,ebx ;EAX = r3g3b3r2 - mov [edi+4-12],ebp - add esi,16 - mov [edi+8-12],eax - sub ecx,1 - jne .xloop -.checkodd: - pop edx - pop ecx - and ecx,3 - jz .noodd -.oddloop: - mov eax,[esi] - add esi,4 - mov [edi],ax - shr eax,16 - mov [edi+2],al - add edi,3 - sub ecx,1 - jnz .oddloop -.noodd: - add esi,[esp+16+16] - add edi,[esp+ 8+16] - - sub edx,1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_pixblt_XRGB1555_to_XRGB8888 -_vdasm_pixblt_XRGB1555_to_XRGB8888: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp*2-4] - lea ecx, [ecx+ebp-2] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - mov eax, [ecx+ebp] - mov ebx, 00007c00h - and ebx, eax - mov esi, eax - shl ebx, 9 - and esi, 000003e0h - shl esi, 6 - mov edi, eax - and eax, 0000001fh - add ebx, esi - shl eax, 3 - mov esi, edi - shr edi, 7 - add eax, ebx - and edi, 00f80000h - mov ebx, esi - shr esi, 13 - and ebx, 03e00000h - shr ebx, 10 - and esi, 000000f8h - add ebx, edi - add ebx, esi - mov edi, eax - and eax, 00e0e0e0h - shr eax, 5 - mov esi, ebx - shr ebx, 5 - add eax, edi - and ebx, 00070707h - add ebx, esi - mov [edx+ebp*2], eax - mov [edx+ebp*2+4], ebx - add ebp, 4 - jnc .xloop - jnz .noodd -.odd: - movzx eax, word [ecx] - mov ebx, 00007c00h - and ebx, eax - mov esi, eax - shl ebx, 9 - and esi, 000003e0h - shl esi, 6 - and eax, 0000001fh - shl eax, 3 - add ebx, esi - add eax, ebx - mov ebx, 00e0e0e0h - and ebx, eax - shr ebx, 5 - add eax, ebx - mov [edx], eax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec dword [esp+24+16] - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_pixblt_RGB565_to_XRGB8888 -_vdasm_pixblt_RGB565_to_XRGB8888: - push ebp - push edi - push esi - push ebx - - mov ebp, [esp+20+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp*2-4] - lea ecx, [ecx+ebp-2] - neg ebp - mov [esp+20+16], ebp - -.yloop: - mov ebp, [esp+20+16] - add ebp, 2 - jbe .odd - -.xloop: - movzx eax, word [ecx+ebp] - mov ebx, 0000f800h - and ebx, eax - mov esi, eax - shl ebx, 8 - mov edi, eax - shl eax, 3 - and esi, 000007e0h - and eax, 000000f8h - add ebx, eax - shl esi, 5 - mov eax, ebx - shr ebx, 5 - and edi, 00000600h - shr edi, 1 - and ebx, 00070007h - add esi, edi - add eax, ebx - add eax, esi - mov [edx+ebp*2], eax - - movzx eax, word [ecx+ebp+2] - mov ebx, 0000f800h - and ebx, eax - mov esi, eax - shl ebx, 8 - mov edi, eax - shl eax, 3 - and esi, 000007e0h - and eax, 000000f8h - add ebx, eax - shl esi, 5 - mov eax, ebx - shr ebx, 5 - and edi, 00000600h - shr edi, 1 - and ebx, 00070007h - add esi, edi - add eax, ebx - add eax, esi - mov [edx+ebp*2+4], eax - - add ebp, 4 - - jnc .xloop - jnz .noodd -.odd: - movzx eax, word [ecx] - mov ebx, 0000f800h - and ebx, eax - mov esi, eax - shl ebx, 8 - mov edi, eax - shl eax, 3 - and esi, 000007e0h - and eax, 000000f8h - add ebx, eax - shl esi, 5 - mov eax, ebx - shr ebx, 5 - and edi, 00000600h - shr edi, 1 - and ebx, 00070007h - add esi, edi - add eax, ebx - add eax, esi - mov [edx], eax -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec dword [esp+24+16] - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_pixblt_RGB888_to_XRGB8888 -_vdasm_pixblt_RGB888_to_XRGB8888: - push ebp - push edi - push esi - push ebx - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ecx,[esp+20+16] - lea eax,[ecx+ecx*2] - lea ebx,[ecx*4] - sub [esp+8+16],ebx - sub [esp+16+16],eax - - mov edx,[esp+24+16] -.yloop: - mov ebp,[esp+20+16] - shr ebp,2 - push edx - jz .checkodd -.xloop: - mov eax,[esi] ;EAX: b1r0g0b0 - mov ebx,[esi+4] ;EBX: g2b2r1g1 - - mov [edi],eax - mov ecx,ebx ;ECX: g2b2r1g1 - - shr eax,24 ;EAX: ------b1 - mov edx,[esi+8] ;EDX: r3g3b3r2 - - shr ecx,16 ;ECX: ----g2b2 - add edi,16 - - shl ebx,8 ;EBX: b2r1g1-- - add esi,12 - - or eax,ebx ;EAX: b2r1g1b1 - mov ebx,edx ;EBX: r3g3b3r2 - - shr ebx,8 ;EBX: --r3g3b3 - mov [edi+4-16],eax - - shl edx,16 ;EDX: b3r2---- - mov [edi+12-16],ebx - - or edx,ecx ;EDX: b3r2g2b2 - sub ebp,1 - - mov [edi+8-16],edx - jne .xloop - -.checkodd: - pop edx - mov ebx,[esp+20+16] - and ebx,3 - jz .noodd -.oddloop: - mov ax,[esi] - mov cl,[esi+2] - mov [edi],ax - mov [edi+2],cl - add esi,3 - add edi,4 - sub ebx,1 - jne .oddloop -.noodd: - - add esi,[esp+16+16] - add edi,[esp+ 8+16] - - sub edx,1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - - ret - - end + section .text + + global _vdasm_pixblt_RGB565_to_XRGB1555 +_vdasm_pixblt_RGB565_to_XRGB1555: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-2] + lea ecx, [ecx+ebp-2] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp] + mov ebx, 0ffc0ffc0h + + and ebx, eax + and eax, 0001f001fh + + shr ebx, 1 + + add eax, ebx + + mov [edx+ebp], eax + add ebp, 4 + + jnc .xloop + jnz .noodd +.odd: + movzx eax, word [ecx] + mov ebx, 0ffc0ffc0h + and ebx, eax + and eax, 0001f001fh + shr ebx, 1 + add eax, ebx + mov [edx], ax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_pixblt_RGB888_to_XRGB1555 +_vdasm_pixblt_RGB888_to_XRGB1555: + push ebp + push edi + push esi + push ebx + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ebp,[esp+20+16] + lea eax,[ebp+ebp] + lea ebx,[ebp+eax] + sub [esp+8+16],eax + sub [esp+16+16],ebx + + mov edx,[esp+24+16] +.yloop: + mov ebp,[esp+20+16] + push ebp + push edx + shr ebp,1 + jz .checkodd +.xloop: + mov eax,[esi+2] ;u + add esi,6 ;v + + mov ebx,eax ;u + mov ecx,eax ;v + shr ebx,11 ;u + and ecx,00f80000h ;v + shr eax,17 ;u + and ebx,0000001fh ;v + shr ecx,14 ;u + and eax,00007c00h ;v + or ebx,ecx ;u + add edi,4 ;v + or ebx,eax ;u + + mov ecx,[esi-6] ;v + mov edx,ebx ;u + mov eax,ecx ;v + + shl edx,16 ;u + mov ebx,ecx ;v + shr ebx,3 ;u + and ecx,0000f800h ;v + shr eax,9 ;u + and ebx,0000001fh ;v + shr ecx,6 ;u + and eax,00007c00h ;v + or eax,ecx ;u + or edx,ebx ;v + or edx,eax ;u + sub ebp,1 ;v + mov [edi-4],edx ;u + jne .xloop ;v +.checkodd: + pop edx + pop ebp + and ebp,1 + jz .noodd + movzx eax,word [esi] + movzx ebx,byte [esi+2] + shl ebx,16 + add esi,3 + add eax,ebx + + mov ebx,eax + mov ecx,eax + shr ebx,3 + and ecx,0000f800h + shr eax,9 + and ebx,0000001fh + shr ecx,6 + and eax,00007c00h + or ebx,ecx + or ebx,eax + mov [edi+0],bl + mov [edi+1],bh + add edi,2 +.noodd: + + add esi,[esp+16+16] + add edi,[esp+ 8+16] + + sub edx,1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + + ret + + global _vdasm_pixblt_XRGB8888_to_XRGB1555 +_vdasm_pixblt_XRGB8888_to_XRGB1555: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + mov edx, [esp+4+16] + add ebp, ebp + mov ecx, [esp+12+16] + lea edx, [edx+ebp-2] + lea ecx, [ecx+ebp*2-4] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp*2] + mov ebx, 00f80000h + and ebx, eax + mov esi, eax + shr ebx, 9 + and esi, 0000f800h + shr esi, 6 + and eax, 000000f8h + shr eax, 3 + add ebx, esi + mov esi, [ecx+ebp*2+4] + add eax, ebx + mov ebx, esi + and esi, 00f80000h + shl esi, 7 + mov edi, ebx + and edi, 0000f800h + add eax, esi + shl edi, 10 + and ebx, 000000f8h + shl ebx, 13 + add eax, edi + add eax, ebx + mov [edx+ebp], eax + add ebp, 4 + jnc .xloop + jnz .noodd +.odd: + mov eax, [ecx] + mov ebx, 00f80000h + and ebx, eax + mov esi, eax + shr ebx, 9 + and esi, 0000f800h + shr esi, 6 + and eax, 000000f8h + shr eax, 3 + add ebx, esi + add eax, ebx + mov [edx], ax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec dword [esp+24+16] + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_pixblt_XRGB1555_to_RGB565 +_vdasm_pixblt_XRGB1555_to_RGB565: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-2] + lea ecx, [ecx+ebp-2] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp] + mov ebx, 02000200h + + mov esi, eax + and ebx, eax + + shr ebx, 4 + and esi, 0ffe0ffe0h + + add eax, esi + + add eax, ebx + + mov [edx+ebp], eax + add ebp, 4 + + jnc .xloop + jnz .noodd +.odd: + movzx eax, word [ecx] + mov ebx, 02000200h + mov esi, eax + and ebx, eax + shr ebx, 4 + and esi, 0ffe0ffe0h + add eax, esi + add eax, ebx + mov [edx], ax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_pixblt_RGB888_to_RGB565 +_vdasm_pixblt_RGB888_to_RGB565: + push ebp + push edi + push esi + push ebx + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ebp,[esp+20+16] + lea eax,[ebp+ebp] + lea ebx,[ebp+eax] + sub [esp+8+16],eax + sub [esp+16+16],ebx + + mov edx,[esp+24+16] +.yloop: + mov ebp,[esp+20+16] + push ebp + push edx + shr ebp,1 + jz .checkodd +.xloop: + mov eax,[esi+2] ;u + add esi,6 ;v + + mov ebx,eax ;u + mov ecx,eax ;v + shr ebx,11 ;u + and ecx,00fc0000h ;v + shr eax,16 ;u + and ebx,0000001fh ;v + shr ecx,13 ;u + and eax,0000f800h ;v + or ebx,ecx ;u + add edi,4 ;v + or ebx,eax ;u + + mov ecx,[esi-6] ;v + mov edx,ebx ;u + mov eax,ecx ;v + + shl edx,16 ;u + mov ebx,ecx ;v + shr ebx,3 ;u + and ecx,0000fc00h ;v + shr eax,8 ;u + and ebx,0000001fh ;v + shr ecx,5 ;u + and eax,0000f800h ;v + or eax,ecx ;u + or edx,ebx ;v + or edx,eax ;u + sub ebp,1 ;v + mov [edi-4],edx ;u + jne .xloop ;v +.checkodd: + pop edx + pop ebp + and ebp,1 + jz .noodd + movzx eax,word [esi] + movzx ebx,byte [esi+2] + shl ebx,16 + add esi,3 + add eax,ebx + + mov ebx,eax + mov ecx,eax + shr ebx,3 + and ecx,0000fc00h + shr eax,8 + and ebx,0000001fh + shr ecx,5 + and eax,0000f800h + or ebx,ecx + or ebx,eax + mov [edi+0],bl + mov [edi+1],bh + add edi,2 +.noodd: + + add esi,[esp+16+16] + add edi,[esp+ 8+16] + + sub edx,1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + + ret + + global _vdasm_pixblt_XRGB8888_to_RGB565 +_vdasm_pixblt_XRGB8888_to_RGB565: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + mov edx, [esp+4+16] + add ebp, ebp + mov ecx, [esp+12+16] + lea edx, [edx+ebp-2] + lea ecx, [ecx+ebp*2-4] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp*2] + mov ebx, 00f80000h + and ebx, eax + mov esi, eax + shr ebx, 8 + and esi, 0000fc00h + shr esi, 5 + and eax, 000000f8h + shr eax, 3 + add ebx, esi + mov esi, [ecx+ebp*2+4] + add eax, ebx + mov ebx, esi + and esi, 00f80000h + shl esi, 8 + mov edi, ebx + and edi, 0000fc00h + add eax, esi + shl edi, 11 + and ebx, 000000f8h + shl ebx, 13 + add eax, edi + add eax, ebx + mov [edx+ebp], eax + add ebp, 4 + jnc .xloop + jnz .noodd +.odd: + mov eax, [ecx] + mov ebx, 00f80000h + and ebx, eax + mov esi, eax + shr ebx, 8 + and esi, 0000fc00h + shr esi, 5 + and eax, 000000f8h + shr eax, 3 + add ebx, esi + add eax, ebx + mov [edx], ax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec dword [esp+24+16] + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_pixblt_XRGB8888_to_RGB888 +_vdasm_pixblt_XRGB8888_to_RGB888: + push ebp + push edi + push esi + push ebx + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ecx,[esp+20+16] + lea eax,[ecx+ecx*2] + lea ebx,[ecx*4] + sub [esp+8+16],eax + sub [esp+16+16],ebx + + mov edx,[esp+24+16] +.yloop: + mov ecx,[esp+20+16] + push ecx + push edx + shr ecx,2 + jz .checkodd +.xloop: + mov eax,[esi] ;EAX = xxr0g0b0 + mov ebx,[esi+4] ;EBX = xxr1g1b1 + mov edx,ebx ;EDX = xxr1g1b1 + mov ebp,[esi+8] ;EBP = xxr2g2b2 + shl ebx,24 ;EBX = b1000000 + and eax,00ffffffh ;EAX = 00r0g0b0 + shr edx,8 ;EDX = 00xxr1g1 + or eax,ebx ;EAX = b1r0g0b0 + mov [edi],eax + mov ebx,ebp ;EBX = xxr2g2b2 + shl ebp,16 ;EBP = g2b20000 + and edx,0000ffffh ;EDX = 0000r1g1 + or ebp,edx ;EBP = g2b2r1g1 + mov eax,[esi+12] ;EAX = xxr3g3b3 + shr ebx,16 ;EBX = 0000xxr2 + add edi,12 + shl eax,8 ;EAX = r3g3b300 + and ebx,000000ffh ;EBX = 000000r2 + or eax,ebx ;EAX = r3g3b3r2 + mov [edi+4-12],ebp + add esi,16 + mov [edi+8-12],eax + sub ecx,1 + jne .xloop +.checkodd: + pop edx + pop ecx + and ecx,3 + jz .noodd +.oddloop: + mov eax,[esi] + add esi,4 + mov [edi],ax + shr eax,16 + mov [edi+2],al + add edi,3 + sub ecx,1 + jnz .oddloop +.noodd: + add esi,[esp+16+16] + add edi,[esp+ 8+16] + + sub edx,1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_pixblt_XRGB1555_to_XRGB8888 +_vdasm_pixblt_XRGB1555_to_XRGB8888: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp*2-4] + lea ecx, [ecx+ebp-2] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + mov eax, [ecx+ebp] + mov ebx, 00007c00h + and ebx, eax + mov esi, eax + shl ebx, 9 + and esi, 000003e0h + shl esi, 6 + mov edi, eax + and eax, 0000001fh + add ebx, esi + shl eax, 3 + mov esi, edi + shr edi, 7 + add eax, ebx + and edi, 00f80000h + mov ebx, esi + shr esi, 13 + and ebx, 03e00000h + shr ebx, 10 + and esi, 000000f8h + add ebx, edi + add ebx, esi + mov edi, eax + and eax, 00e0e0e0h + shr eax, 5 + mov esi, ebx + shr ebx, 5 + add eax, edi + and ebx, 00070707h + add ebx, esi + mov [edx+ebp*2], eax + mov [edx+ebp*2+4], ebx + add ebp, 4 + jnc .xloop + jnz .noodd +.odd: + movzx eax, word [ecx] + mov ebx, 00007c00h + and ebx, eax + mov esi, eax + shl ebx, 9 + and esi, 000003e0h + shl esi, 6 + and eax, 0000001fh + shl eax, 3 + add ebx, esi + add eax, ebx + mov ebx, 00e0e0e0h + and ebx, eax + shr ebx, 5 + add eax, ebx + mov [edx], eax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec dword [esp+24+16] + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_pixblt_RGB565_to_XRGB8888 +_vdasm_pixblt_RGB565_to_XRGB8888: + push ebp + push edi + push esi + push ebx + + mov ebp, [esp+20+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp*2-4] + lea ecx, [ecx+ebp-2] + neg ebp + mov [esp+20+16], ebp + +.yloop: + mov ebp, [esp+20+16] + add ebp, 2 + jbe .odd + +.xloop: + movzx eax, word [ecx+ebp] + mov ebx, 0000f800h + and ebx, eax + mov esi, eax + shl ebx, 8 + mov edi, eax + shl eax, 3 + and esi, 000007e0h + and eax, 000000f8h + add ebx, eax + shl esi, 5 + mov eax, ebx + shr ebx, 5 + and edi, 00000600h + shr edi, 1 + and ebx, 00070007h + add esi, edi + add eax, ebx + add eax, esi + mov [edx+ebp*2], eax + + movzx eax, word [ecx+ebp+2] + mov ebx, 0000f800h + and ebx, eax + mov esi, eax + shl ebx, 8 + mov edi, eax + shl eax, 3 + and esi, 000007e0h + and eax, 000000f8h + add ebx, eax + shl esi, 5 + mov eax, ebx + shr ebx, 5 + and edi, 00000600h + shr edi, 1 + and ebx, 00070007h + add esi, edi + add eax, ebx + add eax, esi + mov [edx+ebp*2+4], eax + + add ebp, 4 + + jnc .xloop + jnz .noodd +.odd: + movzx eax, word [ecx] + mov ebx, 0000f800h + and ebx, eax + mov esi, eax + shl ebx, 8 + mov edi, eax + shl eax, 3 + and esi, 000007e0h + and eax, 000000f8h + add ebx, eax + shl esi, 5 + mov eax, ebx + shr ebx, 5 + and edi, 00000600h + shr edi, 1 + and ebx, 00070007h + add esi, edi + add eax, ebx + add eax, esi + mov [edx], eax +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec dword [esp+24+16] + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_pixblt_RGB888_to_XRGB8888 +_vdasm_pixblt_RGB888_to_XRGB8888: + push ebp + push edi + push esi + push ebx + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ecx,[esp+20+16] + lea eax,[ecx+ecx*2] + lea ebx,[ecx*4] + sub [esp+8+16],ebx + sub [esp+16+16],eax + + mov edx,[esp+24+16] +.yloop: + mov ebp,[esp+20+16] + shr ebp,2 + push edx + jz .checkodd +.xloop: + mov eax,[esi] ;EAX: b1r0g0b0 + mov ebx,[esi+4] ;EBX: g2b2r1g1 + + mov [edi],eax + mov ecx,ebx ;ECX: g2b2r1g1 + + shr eax,24 ;EAX: ------b1 + mov edx,[esi+8] ;EDX: r3g3b3r2 + + shr ecx,16 ;ECX: ----g2b2 + add edi,16 + + shl ebx,8 ;EBX: b2r1g1-- + add esi,12 + + or eax,ebx ;EAX: b2r1g1b1 + mov ebx,edx ;EBX: r3g3b3r2 + + shr ebx,8 ;EBX: --r3g3b3 + mov [edi+4-16],eax + + shl edx,16 ;EDX: b3r2---- + mov [edi+12-16],ebx + + or edx,ecx ;EDX: b3r2g2b2 + sub ebp,1 + + mov [edi+8-16],edx + jne .xloop + +.checkodd: + pop edx + mov ebx,[esp+20+16] + and ebx,3 + jz .noodd +.oddloop: + mov ax,[esi] + mov cl,[esi+2] + mov [edi],ax + mov [edi+2],cl + add esi,3 + add edi,4 + sub ebx,1 + jne .oddloop +.noodd: + + add esi,[esp+16+16] + add edi,[esp+ 8+16] + + sub edx,1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb2yuv_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb2yuv_mmx.asm index 2c9286041a0..637e7910b3c 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb2yuv_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb2yuv_mmx.asm @@ -1,652 +1,652 @@ - section .rdata, rdata - -y_co dq 0004a004a004a004ah -cr_co_r dq 000cc00cc00cc00cch -cb_co_b dq 00081008100810081h ;note: divided by two -cr_co_g dq 0ff98ff98ff98ff98h -cb_co_g dq 0ffceffceffceffceh -y_bias dq 0fb7afb7afb7afb7ah -c_bias dq 0ff80ff80ff80ff80h -interp dq 06000400020000000h -rb_mask_555 dq 07c1f7c1f7c1f7c1fh -g_mask_555 dq 003e003e003e003e0h -rb_mask_565 dq 0f81ff81ff81ff81fh -g_mask_565 dq 007e007e007e007e0h - -cr_coeff dq 000003313e5fc0000h -cb_coeff dq 000000000f377408dh -rgb_bias dq 000007f2180887eebh - -msb_inv dq 08000800080008000h - - section .text - -;============================================================================ - -%macro YUV411PLANAR_TO_RGB_PROLOG 0 - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - mov ecx, [esp+8+16] - mov edx, [esp+12+16] - mov ebx, [esp+16+16] - mov ebp, [esp+20+16] - - pxor mm7, mm7 -%endmacro - -%macro YUV411PLANAR_TO_RGB_CORE_MMX 0 - movd mm0, dword [ecx] ;mm0 = Y3Y2Y1Y0 - add ecx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - movq mm1, mm0 - pmullw mm0, [y_co] - paddw mm1, [y_bias] - paddsw mm0, mm0 - paddsw mm0, mm1 - - movzx esi, word [ebx] - movzx edi, word [edx] - add ebx, 1 - add edx, 1 - - movd mm1, esi - movd mm2, edi - - punpcklbw mm1, mm7 - paddw mm1, [c_bias] - punpcklwd mm1, mm1 - movq mm3, mm1 - punpckldq mm1, mm1 - punpckhdq mm3, mm3 - - punpcklbw mm2, mm7 - paddw mm2, [c_bias] - punpcklwd mm2, mm2 - movq mm4, mm2 - punpckldq mm2, mm2 - punpckhdq mm4, mm4 - - psubw mm3, mm1 - psubw mm4, mm2 - paddw mm3, mm3 - paddw mm4, mm4 - - pmulhw mm3, [interp] - pmulhw mm4, [interp] - - paddw mm1, mm3 - paddw mm2, mm4 - - movq mm3, mm1 - movq mm4, mm2 - - pmullw mm1, [cr_co_r] - pmullw mm2, [cb_co_b] - pmullw mm3, [cr_co_g] - pmullw mm4, [cb_co_g] - - paddsw mm2, mm2 - paddsw mm1, mm0 - paddsw mm3, mm4 - paddsw mm2, mm0 - paddsw mm3, mm0 - - psraw mm1, 7 - psraw mm2, 7 - psraw mm3, 7 - - packuswb mm1, mm1 - packuswb mm2, mm2 - packuswb mm3, mm3 -%endmacro - -%macro YUV411PLANAR_TO_RGB_CORE_ISSE 0 - movd mm0, dword [ecx] ;mm0 = Y3Y2Y1Y0 - add ecx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - movq mm1, mm0 - pmullw mm0, [y_co] - paddw mm1, [y_bias] - paddsw mm0, mm0 - paddsw mm0, mm1 - - movzx esi, word [ebx] - movzx edi, word [edx] - add ebx, 1 - add edx, 1 - - movd mm1, esi - movd mm2, edi - - punpcklbw mm1, mm7 - paddw mm1, [c_bias] - pshufw mm3, mm1, 01010101b - pshufw mm1, mm1, 00000000b - - punpcklbw mm2, mm7 - paddw mm2, [c_bias] - pshufw mm4, mm2, 01010101b - pshufw mm2, mm2, 00000000b - - psubw mm3, mm1 - psubw mm4, mm2 - paddw mm3, mm3 - paddw mm4, mm4 - - pmulhw mm3, [interp] - pmulhw mm4, [interp] - - paddw mm1, mm3 - paddw mm2, mm4 - - psllw mm1, 3 - psllw mm2, 3 - - movq mm3, [cr_co_g] - movq mm4, [cb_co_g] - - pmullw mm3, mm1 - pmullw mm4, mm2 - pmullw mm1, [cr_co_r] - pmullw mm2, [cb_co_b] - - paddsw mm2, mm2 - paddsw mm1, mm0 - paddsw mm3, mm4 - paddsw mm2, mm0 - paddsw mm3, mm0 - - psraw mm1, 7 - psraw mm2, 7 - psraw mm3, 7 - - packuswb mm1, mm1 - packuswb mm2, mm2 - packuswb mm3, mm3 -%endmacro - -%macro YUV411PLANAR_TO_RGB_EPILOG 0 - pop ebx - pop esi - pop edi - pop ebp - ret -%endmacro - - global _vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX -_vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_CORE_MMX - - psrlw mm1, 1 - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 2 - pand mm2, [rb_mask_555] - pand mm3, [g_mask_555] - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX -_vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_CORE_MMX - - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 3 - pand mm2, [rb_mask_565] - pand mm3, [g_mask_565] - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX -_vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_PROLOG - - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - movq mm1, mm2 - punpcklbw mm1, mm3 - punpckhbw mm2, mm3 - - movq [eax], mm1 - movq [eax+8], mm2 - add eax, 16 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE -_vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_CORE_ISSE - - psrlw mm1, 1 - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 2 - pand mm2, [rb_mask_555] - pand mm3, [g_mask_555] - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE -_vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE: - YUV411PLANAR_TO_RGB_PROLOG -.xloop: - YUV411PLANAR_TO_RGB_CORE_ISSE - - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 3 - pand mm2, [rb_mask_565] - pand mm3, [g_mask_565] - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;============================================================================ - - global _vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE -_vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - mov ecx, [esp+8+16] - mov edx, [esp+12+16] - mov ebx, [esp+16+16] - mov ebp, [esp+20+16] - - pxor mm7, mm7 - - movzx esi, byte [ebx] - movzx edi, byte [edx] - add ebx, 1 - add edx, 1 - - movd mm1, esi - movd mm2, edi - - psllw mm1, 3 - psllw mm2, 3 - - pshufw mm5, mm1, 0 - pshufw mm6, mm2, 0 - - pmulhw mm5, [cr_coeff] - pmulhw mm6, [cb_coeff] - paddw mm6, mm5 - paddw mm6, [rgb_bias] - -.xloop: - movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 - add ecx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - psllw mm0, 3 - pmulhw mm0, [y_co] - pxor mm0, [msb_inv] - - movzx esi, byte [ebx] - movzx edi, byte [edx] - add ebx, 1 - add edx, 1 - - movd mm1, esi - movd mm2, edi - - psllw mm1, 3 - psllw mm2, 3 - - pshufw mm1, mm1, 0 - pshufw mm2, mm2, 0 - - pmulhw mm1, [cr_coeff] - pmulhw mm2, [cb_coeff] - paddw mm1, mm2 - paddw mm1, [rgb_bias] - - movq mm2, mm1 - pavgw mm2, mm6 ;mm2 = 1/2 - pshufw mm3, mm0, 00000000b - paddw mm3, mm6 - pavgw mm6, mm2 ;mm1 = 1/4 - pshufw mm4, mm0, 01010101b - paddw mm4, mm6 - packuswb mm3, mm4 - movq [eax], mm3 - - pshufw mm3, mm0, 10101010b - paddw mm3, mm2 - pshufw mm0, mm0, 11111111b - pavgw mm2, mm1 ;mm2 = 3/4 - paddw mm2, mm0 - packuswb mm3, mm2 - movq [eax+8], mm3 - - movq mm6, mm1 - - add eax, 16 - - sub ebp, 1 - jne .xloop - - YUV411PLANAR_TO_RGB_EPILOG - -;========================================================================== - -%macro YUV444PLANAR_TO_RGB_PROLOG 0 - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - mov ecx, [esp+8+16] - mov edx, [esp+12+16] - mov ebx, [esp+16+16] - mov ebp, [esp+20+16] -%endmacro - -%macro YUV444PLANAR_TO_RGB_CORE 0 - movq mm3, mm0 - pmullw mm0, [y_co] - paddw mm1, [c_bias] - paddw mm2, [c_bias] - paddw mm0, [y_bias] - paddsw mm0, mm0 - paddsw mm0, mm3 - - movq mm3, [cr_co_g] - movq mm4, [cb_co_g] - - pmullw mm3, mm1 - pmullw mm4, mm2 - pmullw mm1, [cr_co_r] - pmullw mm2, [cb_co_b] - - paddsw mm2, mm2 - paddsw mm1, mm0 - paddsw mm3, mm4 - paddsw mm2, mm0 - paddsw mm3, mm0 - - psraw mm1, 7 - psraw mm2, 7 - psraw mm3, 7 - - packuswb mm1, mm1 - packuswb mm2, mm2 - packuswb mm3, mm3 -%endmacro - -%macro YUV444PLANAR_TO_RGB_EPILOG 0 - pop ebx - pop esi - pop edi - pop ebp - ret -%endmacro - -;========================================================================== - - global _vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX -_vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX: - YUV444PLANAR_TO_RGB_PROLOG - - pxor mm7, mm7 - movq mm5, [rb_mask_555] - movq mm6, [g_mask_555] - - sub ebp, 3 - jbe .oddcheck -.xloop4: - movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 - movd mm1, dword [ebx] - movd mm2, dword [edx] - add ecx, 4 - add ebx, 4 - add edx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - punpcklbw mm1, mm7 - punpcklbw mm2, mm7 - - YUV444PLANAR_TO_RGB_CORE - - psrlw mm1, 1 - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 2 - pand mm2, mm5 - pand mm3, mm6 - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 4 - ja .xloop4 -.oddcheck: - add ebp, 3 - jz .noodd -.xloop: - movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 - movd mm0, edi - movzx edi, byte [ebx] - movd mm1, edi - movzx edi, byte [edx] - movd mm2, edi - add ecx, 1 - add ebx, 1 - add edx, 1 - - YUV444PLANAR_TO_RGB_CORE - - psrlw mm1, 1 - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 2 - pand mm2, mm5 - pand mm3, mm6 - por mm2, mm3 - - movd edi, mm2 - mov [eax], di - add eax, 2 - - sub ebp, 1 - jnz .xloop -.noodd: - YUV444PLANAR_TO_RGB_EPILOG - -;========================================================================== - - global _vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX -_vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX: - YUV444PLANAR_TO_RGB_PROLOG - - pxor mm7, mm7 - movq mm5, [rb_mask_565] - movq mm6, [g_mask_565] - - sub ebp, 3 - jbe .oddcheck -.xloop4: - movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 - movd mm1, dword [ebx] - movd mm2, dword [edx] - add ecx, 4 - add ebx, 4 - add edx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - punpcklbw mm1, mm7 - punpcklbw mm2, mm7 - - YUV444PLANAR_TO_RGB_CORE - - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 3 - pand mm2, mm5 - pand mm3, mm6 - por mm2, mm3 - - movq [eax], mm2 - add eax, 8 - - sub ebp, 4 - ja .xloop4 -.oddcheck: - add ebp, 3 - jz .noodd -.xloop: - movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 - movd mm0, edi - movzx edi, byte [ebx] - movd mm1, edi - movzx edi, byte [edx] - movd mm2, edi - add ecx, 1 - add ebx, 1 - add edx, 1 - - YUV444PLANAR_TO_RGB_CORE - - psrlw mm2, 3 - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - psllw mm3, 3 - pand mm2, mm5 - pand mm3, mm6 - por mm2, mm3 - - movd edi, mm2 - mov [eax], di - add eax, 2 - - sub ebp, 1 - jnz .xloop -.noodd: - YUV444PLANAR_TO_RGB_EPILOG - -;========================================================================== - - global _vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX -_vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX: - YUV444PLANAR_TO_RGB_PROLOG - - pxor mm7, mm7 - - sub ebp, 3 - jbe .oddcheck -.xloop4: - movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 - movd mm1, dword [ebx] - movd mm2, dword [edx] - add ecx, 4 - add ebx, 4 - add edx, 4 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - punpcklbw mm1, mm7 - punpcklbw mm2, mm7 - - YUV444PLANAR_TO_RGB_CORE - - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - movq mm1, mm2 - punpcklbw mm1, mm3 - punpckhbw mm2, mm3 - - movq [eax], mm1 - movq [eax+8], mm2 - add eax, 16 - - sub ebp, 4 - ja .xloop4 -.oddcheck: - add ebp, 3 - jz .noodd -.xloop: - movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 - movd mm0, edi - movzx edi, byte [ebx] - movd mm1, edi - movzx edi, byte [edx] - movd mm2, edi - add ecx, 1 - add ebx, 1 - add edx, 1 - punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 - - YUV444PLANAR_TO_RGB_CORE - - punpcklbw mm2, mm1 - punpcklbw mm3, mm3 - punpcklbw mm2, mm3 - - movd dword [eax], mm2 - add eax, 4 - - sub ebp, 1 - jnz .xloop -.noodd: - YUV444PLANAR_TO_RGB_EPILOG - + section .rdata, rdata + +y_co dq 0004a004a004a004ah +cr_co_r dq 000cc00cc00cc00cch +cb_co_b dq 00081008100810081h ;note: divided by two +cr_co_g dq 0ff98ff98ff98ff98h +cb_co_g dq 0ffceffceffceffceh +y_bias dq 0fb7afb7afb7afb7ah +c_bias dq 0ff80ff80ff80ff80h +interp dq 06000400020000000h +rb_mask_555 dq 07c1f7c1f7c1f7c1fh +g_mask_555 dq 003e003e003e003e0h +rb_mask_565 dq 0f81ff81ff81ff81fh +g_mask_565 dq 007e007e007e007e0h + +cr_coeff dq 000003313e5fc0000h +cb_coeff dq 000000000f377408dh +rgb_bias dq 000007f2180887eebh + +msb_inv dq 08000800080008000h + + section .text + +;============================================================================ + +%macro YUV411PLANAR_TO_RGB_PROLOG 0 + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + mov ecx, [esp+8+16] + mov edx, [esp+12+16] + mov ebx, [esp+16+16] + mov ebp, [esp+20+16] + + pxor mm7, mm7 +%endmacro + +%macro YUV411PLANAR_TO_RGB_CORE_MMX 0 + movd mm0, dword [ecx] ;mm0 = Y3Y2Y1Y0 + add ecx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + movq mm1, mm0 + pmullw mm0, [y_co] + paddw mm1, [y_bias] + paddsw mm0, mm0 + paddsw mm0, mm1 + + movzx esi, word [ebx] + movzx edi, word [edx] + add ebx, 1 + add edx, 1 + + movd mm1, esi + movd mm2, edi + + punpcklbw mm1, mm7 + paddw mm1, [c_bias] + punpcklwd mm1, mm1 + movq mm3, mm1 + punpckldq mm1, mm1 + punpckhdq mm3, mm3 + + punpcklbw mm2, mm7 + paddw mm2, [c_bias] + punpcklwd mm2, mm2 + movq mm4, mm2 + punpckldq mm2, mm2 + punpckhdq mm4, mm4 + + psubw mm3, mm1 + psubw mm4, mm2 + paddw mm3, mm3 + paddw mm4, mm4 + + pmulhw mm3, [interp] + pmulhw mm4, [interp] + + paddw mm1, mm3 + paddw mm2, mm4 + + movq mm3, mm1 + movq mm4, mm2 + + pmullw mm1, [cr_co_r] + pmullw mm2, [cb_co_b] + pmullw mm3, [cr_co_g] + pmullw mm4, [cb_co_g] + + paddsw mm2, mm2 + paddsw mm1, mm0 + paddsw mm3, mm4 + paddsw mm2, mm0 + paddsw mm3, mm0 + + psraw mm1, 7 + psraw mm2, 7 + psraw mm3, 7 + + packuswb mm1, mm1 + packuswb mm2, mm2 + packuswb mm3, mm3 +%endmacro + +%macro YUV411PLANAR_TO_RGB_CORE_ISSE 0 + movd mm0, dword [ecx] ;mm0 = Y3Y2Y1Y0 + add ecx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + movq mm1, mm0 + pmullw mm0, [y_co] + paddw mm1, [y_bias] + paddsw mm0, mm0 + paddsw mm0, mm1 + + movzx esi, word [ebx] + movzx edi, word [edx] + add ebx, 1 + add edx, 1 + + movd mm1, esi + movd mm2, edi + + punpcklbw mm1, mm7 + paddw mm1, [c_bias] + pshufw mm3, mm1, 01010101b + pshufw mm1, mm1, 00000000b + + punpcklbw mm2, mm7 + paddw mm2, [c_bias] + pshufw mm4, mm2, 01010101b + pshufw mm2, mm2, 00000000b + + psubw mm3, mm1 + psubw mm4, mm2 + paddw mm3, mm3 + paddw mm4, mm4 + + pmulhw mm3, [interp] + pmulhw mm4, [interp] + + paddw mm1, mm3 + paddw mm2, mm4 + + psllw mm1, 3 + psllw mm2, 3 + + movq mm3, [cr_co_g] + movq mm4, [cb_co_g] + + pmullw mm3, mm1 + pmullw mm4, mm2 + pmullw mm1, [cr_co_r] + pmullw mm2, [cb_co_b] + + paddsw mm2, mm2 + paddsw mm1, mm0 + paddsw mm3, mm4 + paddsw mm2, mm0 + paddsw mm3, mm0 + + psraw mm1, 7 + psraw mm2, 7 + psraw mm3, 7 + + packuswb mm1, mm1 + packuswb mm2, mm2 + packuswb mm3, mm3 +%endmacro + +%macro YUV411PLANAR_TO_RGB_EPILOG 0 + pop ebx + pop esi + pop edi + pop ebp + ret +%endmacro + + global _vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX +_vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_CORE_MMX + + psrlw mm1, 1 + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 2 + pand mm2, [rb_mask_555] + pand mm3, [g_mask_555] + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX +_vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_CORE_MMX + + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 3 + pand mm2, [rb_mask_565] + pand mm3, [g_mask_565] + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX +_vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_PROLOG + + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + movq mm1, mm2 + punpcklbw mm1, mm3 + punpckhbw mm2, mm3 + + movq [eax], mm1 + movq [eax+8], mm2 + add eax, 16 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE +_vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_CORE_ISSE + + psrlw mm1, 1 + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 2 + pand mm2, [rb_mask_555] + pand mm3, [g_mask_555] + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE +_vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE: + YUV411PLANAR_TO_RGB_PROLOG +.xloop: + YUV411PLANAR_TO_RGB_CORE_ISSE + + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 3 + pand mm2, [rb_mask_565] + pand mm3, [g_mask_565] + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;============================================================================ + + global _vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE +_vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + mov ecx, [esp+8+16] + mov edx, [esp+12+16] + mov ebx, [esp+16+16] + mov ebp, [esp+20+16] + + pxor mm7, mm7 + + movzx esi, byte [ebx] + movzx edi, byte [edx] + add ebx, 1 + add edx, 1 + + movd mm1, esi + movd mm2, edi + + psllw mm1, 3 + psllw mm2, 3 + + pshufw mm5, mm1, 0 + pshufw mm6, mm2, 0 + + pmulhw mm5, [cr_coeff] + pmulhw mm6, [cb_coeff] + paddw mm6, mm5 + paddw mm6, [rgb_bias] + +.xloop: + movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 + add ecx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + psllw mm0, 3 + pmulhw mm0, [y_co] + pxor mm0, [msb_inv] + + movzx esi, byte [ebx] + movzx edi, byte [edx] + add ebx, 1 + add edx, 1 + + movd mm1, esi + movd mm2, edi + + psllw mm1, 3 + psllw mm2, 3 + + pshufw mm1, mm1, 0 + pshufw mm2, mm2, 0 + + pmulhw mm1, [cr_coeff] + pmulhw mm2, [cb_coeff] + paddw mm1, mm2 + paddw mm1, [rgb_bias] + + movq mm2, mm1 + pavgw mm2, mm6 ;mm2 = 1/2 + pshufw mm3, mm0, 00000000b + paddw mm3, mm6 + pavgw mm6, mm2 ;mm1 = 1/4 + pshufw mm4, mm0, 01010101b + paddw mm4, mm6 + packuswb mm3, mm4 + movq [eax], mm3 + + pshufw mm3, mm0, 10101010b + paddw mm3, mm2 + pshufw mm0, mm0, 11111111b + pavgw mm2, mm1 ;mm2 = 3/4 + paddw mm2, mm0 + packuswb mm3, mm2 + movq [eax+8], mm3 + + movq mm6, mm1 + + add eax, 16 + + sub ebp, 1 + jne .xloop + + YUV411PLANAR_TO_RGB_EPILOG + +;========================================================================== + +%macro YUV444PLANAR_TO_RGB_PROLOG 0 + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + mov ecx, [esp+8+16] + mov edx, [esp+12+16] + mov ebx, [esp+16+16] + mov ebp, [esp+20+16] +%endmacro + +%macro YUV444PLANAR_TO_RGB_CORE 0 + movq mm3, mm0 + pmullw mm0, [y_co] + paddw mm1, [c_bias] + paddw mm2, [c_bias] + paddw mm0, [y_bias] + paddsw mm0, mm0 + paddsw mm0, mm3 + + movq mm3, [cr_co_g] + movq mm4, [cb_co_g] + + pmullw mm3, mm1 + pmullw mm4, mm2 + pmullw mm1, [cr_co_r] + pmullw mm2, [cb_co_b] + + paddsw mm2, mm2 + paddsw mm1, mm0 + paddsw mm3, mm4 + paddsw mm2, mm0 + paddsw mm3, mm0 + + psraw mm1, 7 + psraw mm2, 7 + psraw mm3, 7 + + packuswb mm1, mm1 + packuswb mm2, mm2 + packuswb mm3, mm3 +%endmacro + +%macro YUV444PLANAR_TO_RGB_EPILOG 0 + pop ebx + pop esi + pop edi + pop ebp + ret +%endmacro + +;========================================================================== + + global _vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX +_vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX: + YUV444PLANAR_TO_RGB_PROLOG + + pxor mm7, mm7 + movq mm5, [rb_mask_555] + movq mm6, [g_mask_555] + + sub ebp, 3 + jbe .oddcheck +.xloop4: + movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 + movd mm1, dword [ebx] + movd mm2, dword [edx] + add ecx, 4 + add ebx, 4 + add edx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + punpcklbw mm1, mm7 + punpcklbw mm2, mm7 + + YUV444PLANAR_TO_RGB_CORE + + psrlw mm1, 1 + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 2 + pand mm2, mm5 + pand mm3, mm6 + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 4 + ja .xloop4 +.oddcheck: + add ebp, 3 + jz .noodd +.xloop: + movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 + movd mm0, edi + movzx edi, byte [ebx] + movd mm1, edi + movzx edi, byte [edx] + movd mm2, edi + add ecx, 1 + add ebx, 1 + add edx, 1 + + YUV444PLANAR_TO_RGB_CORE + + psrlw mm1, 1 + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 2 + pand mm2, mm5 + pand mm3, mm6 + por mm2, mm3 + + movd edi, mm2 + mov [eax], di + add eax, 2 + + sub ebp, 1 + jnz .xloop +.noodd: + YUV444PLANAR_TO_RGB_EPILOG + +;========================================================================== + + global _vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX +_vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX: + YUV444PLANAR_TO_RGB_PROLOG + + pxor mm7, mm7 + movq mm5, [rb_mask_565] + movq mm6, [g_mask_565] + + sub ebp, 3 + jbe .oddcheck +.xloop4: + movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 + movd mm1, dword [ebx] + movd mm2, dword [edx] + add ecx, 4 + add ebx, 4 + add edx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + punpcklbw mm1, mm7 + punpcklbw mm2, mm7 + + YUV444PLANAR_TO_RGB_CORE + + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 3 + pand mm2, mm5 + pand mm3, mm6 + por mm2, mm3 + + movq [eax], mm2 + add eax, 8 + + sub ebp, 4 + ja .xloop4 +.oddcheck: + add ebp, 3 + jz .noodd +.xloop: + movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 + movd mm0, edi + movzx edi, byte [ebx] + movd mm1, edi + movzx edi, byte [edx] + movd mm2, edi + add ecx, 1 + add ebx, 1 + add edx, 1 + + YUV444PLANAR_TO_RGB_CORE + + psrlw mm2, 3 + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + psllw mm3, 3 + pand mm2, mm5 + pand mm3, mm6 + por mm2, mm3 + + movd edi, mm2 + mov [eax], di + add eax, 2 + + sub ebp, 1 + jnz .xloop +.noodd: + YUV444PLANAR_TO_RGB_EPILOG + +;========================================================================== + + global _vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX +_vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX: + YUV444PLANAR_TO_RGB_PROLOG + + pxor mm7, mm7 + + sub ebp, 3 + jbe .oddcheck +.xloop4: + movd mm0, dword [ecx];mm0 = Y3Y2Y1Y0 + movd mm1, dword [ebx] + movd mm2, dword [edx] + add ecx, 4 + add ebx, 4 + add edx, 4 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + punpcklbw mm1, mm7 + punpcklbw mm2, mm7 + + YUV444PLANAR_TO_RGB_CORE + + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + movq mm1, mm2 + punpcklbw mm1, mm3 + punpckhbw mm2, mm3 + + movq [eax], mm1 + movq [eax+8], mm2 + add eax, 16 + + sub ebp, 4 + ja .xloop4 +.oddcheck: + add ebp, 3 + jz .noodd +.xloop: + movzx edi, byte [ecx] ;mm0 = Y3Y2Y1Y0 + movd mm0, edi + movzx edi, byte [ebx] + movd mm1, edi + movzx edi, byte [edx] + movd mm2, edi + add ecx, 1 + add ebx, 1 + add edx, 1 + punpcklbw mm0, mm7 ;mm0 = Y3 | Y2 | Y1 | Y0 + + YUV444PLANAR_TO_RGB_CORE + + punpcklbw mm2, mm1 + punpcklbw mm3, mm3 + punpcklbw mm2, mm3 + + movd dword [eax], mm2 + add eax, 4 + + sub ebp, 1 + jnz .xloop +.noodd: + YUV444PLANAR_TO_RGB_EPILOG + end \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb_mmx.asm index 9fccfad4d72..aa0b99987eb 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_bltrgb_mmx.asm @@ -1,806 +1,806 @@ - section .rdata, rdata - -x07b dq 00707070707070707h -x0200w dq 00200020002000200h -x001fw dq 0001f001f001f001fh -xffc0w dq 0ffc0ffc0ffc0ffc0h -xffe0w dq 0ffe0ffe0ffe0ffe0h -x2080w dq 02080208020802080h -x4200w dq 04200420042004200h -rb_mask5 dq 000f800f800f800f8h -g_mask5 dq 00000f8000000f800h -g_mask6 dq 00000fc000000fc00h -rb_mul_565 dq 02000000420000004h -rb_mul_555 dq 02000000820000008h -r_mask_555 dq 07c007c007c007c00h -g_mask_555 dq 003e003e003e003e0h -b_mask_555 dq 0001f001f001f001fh -r_mask_565 dq 0f800f800f800f800h -g_mask_565 dq 007e007e007e007e0h -b_mask_565 dq 0001f001f001f001fh - -%macro prologue 1 - push ebx - push esi - push edi - push ebp - ;.fpo (0,%1,4,4,1,0) -%endmacro - -%macro epilogue 0 - pop ebp - pop edi - pop esi - pop ebx -%endmacro - - section .text - - global _vdasm_pixblt_RGB565_to_XRGB1555_MMX -_vdasm_pixblt_RGB565_to_XRGB1555_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-6] - lea ecx, [ecx+ebp-6] - neg ebp - mov [esp+20+16], ebp - - movq mm5, [x001fw] - movq mm4, [xffc0w] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 6 - jbe .odd - -.xloop: - movq mm0, [ecx+ebp] - movq mm1, mm5 - pand mm1, mm0 - pand mm0, mm4 - psrlq mm0, 1 - paddw mm0, mm1 - movq [edx+ebp], mm0 - add ebp, 8 - jnc .xloop - - sub ebp, 6 - jz .noodd -.odd: - movzx eax, word [ecx+ebp+6] - mov ebx, 0001f001fh - and ebx, eax - and eax, 0ffc0ffc0h - shr eax, 1 - add eax, ebx - mov [edx+ebp+6], ax - add ebp, 2 - jnz .odd -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - global _vdasm_pixblt_XRGB8888_to_XRGB1555_MMX -_vdasm_pixblt_XRGB8888_to_XRGB1555_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-14] - lea ecx, [ecx+ebp*2-28] - neg ebp - mov [esp+20+16], ebp - - movq mm5,[rb_mul_555] - movq mm6,[rb_mask5] - movq mm7,[g_mask5] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 14 - jbe .odd - - ;This code uses the "pmaddwd" trick for 32->16 conversions from Intel's MMX - ;Application Notes. - - movq mm0,[ecx+ebp*2] ;allocate 0 (0123) - movq mm2,mm0 ;allocate 2 (0 23) - - movq mm1,[ecx+ebp*2+8] ;allocate 1 (0123) - movq mm3,mm1 ;allocate 3 (0123) - pand mm0,mm6 - pmaddwd mm0,mm5 - pand mm1,mm6 - pmaddwd mm1,mm5 - pand mm2,mm7 - pand mm3,mm7 - jmp .xloopstart - - align 16 -.xloop: - movq mm0,[ecx+ebp*2] ;allocate 0 (01234) - por mm4,mm2 ;free 2 (01 34) - - por mm3,mm1 ;free 3 (01 34) - movq mm2,mm0 ;allocate 2 (0 234) - - movq mm1,[ecx+ebp*2+8] ;allocate 1 (01234) - psrld mm4,6 - - psrld mm3,6 - pand mm0,mm6 - - packssdw mm4,mm3 ;free 3 (012 4) - movq mm3,mm1 ;allocate 3 (01234) - - pmaddwd mm0,mm5 - pand mm1,mm6 - - pmaddwd mm1,mm5 - pand mm2,mm7 - - movq [edx+ebp-8],mm4 ;free 4 (0123 ) - pand mm3,mm7 - -.xloopstart: - movq mm4,[ecx+ebp*2+16] ;allocate 4 (01234) - por mm0,mm2 ;free 2 (01 34) - - por mm1,mm3 ;free 3 (01 4) - psrld mm0,6 - - movq mm3,[ecx+ebp*2+24] ;allocate 3 (01 34) - movq mm2,mm4 ;allocate 2 (01234) - - psrld mm1,6 - pand mm4,mm6 - - packssdw mm0,mm1 ;free 1 (0 234) - movq mm1,mm3 ;allocate 1 (01234) - - movq [edx+ebp],mm0 ;free 0 ( 1234) - pand mm3,mm6 - - pmaddwd mm4,mm5 - add ebp,16 - - pmaddwd mm3,mm5 - pand mm2,mm7 - - pand mm1,mm7 - jnc .xloop - - por mm4,mm2 ;free 2 (01 34) - por mm3,mm1 ;free 3 (01 34) - psrld mm4,6 - psrld mm3,6 - packssdw mm4,mm3 ;free 3 (012 4) - movq [edx+ebp-8],mm4 ;free 4 (0123 ) - -.odd: - sub ebp, 14 - jz .noodd -.oddloop: - mov eax, [ecx+ebp*2+28] - mov ebx, 00f80000h - mov esi, eax - and ebx, eax - shr ebx, 9 - and esi, 0000f800h - shr esi, 6 - and eax, 000000f8h - shr eax, 3 - add esi, ebx - add eax, esi - mov [edx+ebp+14], ax - add ebp, 2 - jnz .oddloop -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - global _vdasm_pixblt_XRGB1555_to_RGB565_MMX -_vdasm_pixblt_XRGB1555_to_RGB565_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-6] - lea ecx, [ecx+ebp-6] - neg ebp - mov [esp+20+16], ebp - - movq mm5, [x0200w] - movq mm4, [xffe0w] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 6 - jbe .odd - -.xloop: - movq mm0, [ecx+ebp] - movq mm1, mm4 - movq mm2, mm0 - pand mm1, mm0 - pand mm0, mm5 - paddw mm1, mm2 - psrlq mm0, 4 - paddw mm0, mm1 - movq [edx+ebp], mm0 - add ebp, 8 - jnc .xloop - -.odd: - sub ebp, 6 - jz .noodd -.oddloop: - movzx eax, word [ecx+ebp+6] - mov ebx, 02000200h - mov esi, eax - and ebx, eax - shr ebx, 4 - and esi, 0ffe0ffe0h - add eax, esi - add eax, ebx - mov [edx+ebp+6], ax - add ebp, 2 - jnz .oddloop -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - - global _vdasm_pixblt_XRGB8888_to_RGB565_MMX -_vdasm_pixblt_XRGB8888_to_RGB565_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp-14] - lea ecx, [ecx+ebp*2-28] - neg ebp - mov [esp+20+16], ebp - - movq mm5,[rb_mul_565] - movq mm6,[rb_mask5] - movq mm7,[g_mask6] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 14 - jbe .odd - - ;This code uses the "pmaddwd" trick for 32->16 conversions from Intel's MMX - ;Application Notes. - - movq mm0,[ecx+ebp*2] ;allocate 0 (0123) - movq mm2,mm0 ;allocate 2 (0 23) - - movq mm1,[ecx+ebp*2+8] ;allocate 1 (0123) - movq mm3,mm1 ;allocate 3 (0123) - pand mm0,mm6 - pmaddwd mm0,mm5 - pand mm1,mm6 - pmaddwd mm1,mm5 - pand mm2,mm7 - pand mm3,mm7 - jmp .xloopstart - - align 16 -.xloop: - movq mm0,[ecx+ebp*2] ;allocate 0 (01234) - por mm4,mm2 ;free 2 (01 34) - - por mm3,mm1 ;free 3 (01 34) - pslld mm4,16-5 - - pslld mm3,16-5 - movq mm2,mm0 ;allocate 2 (0 234) - - movq mm1,[ecx+ebp*2+8] ;allocate 1 (01234) - psrad mm4,16 - - psrad mm3,16 - pand mm0,mm6 - - packssdw mm4,mm3 ;free 3 (012 4) - movq mm3,mm1 ;allocate 3 (01234) - - pmaddwd mm0,mm5 - pand mm1,mm6 - - pmaddwd mm1,mm5 - pand mm2,mm7 - - movq [edx+ebp-8],mm4 ;free 4 (0123 ) - pand mm3,mm7 - -.xloopstart: - movq mm4,[ecx+ebp*2+16] ;allocate 4 (01234) - por mm0,mm2 ;free 2 (01 34) - - por mm1,mm3 ;free 3 (01 4) - pslld mm0,16-5 - - movq mm3,[ecx+ebp*2+24] ;allocate 3 (01 34) - pslld mm1,16-5 - - psrad mm0,16 - movq mm2,mm4 ;allocate 2 (01234) - - psrad mm1,16 - pand mm4,mm6 - - packssdw mm0,mm1 ;free 1 (0 234) - movq mm1,mm3 ;allocate 1 (01234) - - movq [edx+ebp],mm0 ;free 0 ( 1234) - pand mm3,mm6 - - pmaddwd mm4,mm5 - add ebp,16 - - pmaddwd mm3,mm5 - pand mm2,mm7 - - pand mm1,mm7 - jnc .xloop - - por mm4,mm2 ;free 2 (01 34) - por mm3,mm1 ;free 3 (01 34) - psllq mm4,16-5 - psllq mm3,16-5 - psrad mm4,16 - psrad mm3,16 - packssdw mm4,mm3 ;free 3 (012 4) - movq [edx+ebp-8],mm4 ;free 4 (0123 ) - -.odd: - sub ebp, 14 - jz .noodd -.oddloop: - mov eax, [ecx+ebp*2+28] - mov ebx, 00f80000h - mov esi, eax - and ebx, eax - and eax, 000000f8h - shr eax, 3 - and esi, 0000fc00h - shr ebx, 8 - shr esi, 5 - add eax, ebx - add eax, esi - mov [edx+ebp+14], ax - add ebp, 2 - jnz .oddloop -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - global _vdasm_pixblt_XRGB8888_to_RGB888_MMX -_vdasm_pixblt_XRGB8888_to_RGB888_MMX: - prologue 6 - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ecx,[esp+20+16] - lea eax,[ecx+ecx*2] - lea ebx,[ecx*4] - sub [esp+8+16],eax - sub [esp+16+16],ebx - - pcmpeqb mm7,mm7 - psrld mm7,8 - movq mm6,mm7 - psllq mm7,32 ;mm7 = high rgb mask - psrlq mm6,32 ;mm6 = low rgb mask - - mov ebp,[esp+20+16] - mov edx,[esp+24+16] - mov eax,[esp+16+16] - mov ebx,[esp+ 8+16] -.yloop: - mov ecx,ebp - shr ecx,3 - jz .checkodd -.xloop: - movq mm0,[esi] ;mm0 = a1r1g1b1a0r0g0b0 - movq mm1,mm6 - - movq mm2,[esi+8] ;mm2 = a3r3g3b3a2r2g2b2 - pand mm1,mm0 ;mm1 = ----------r0g0b0 - - movq mm3,mm6 - pand mm0,mm7 ;mm0 = --r1g1b1-------- - - movq mm4,mm2 - pand mm3,mm2 ;mm3 = ----------r2g2b2 - - psrlq mm0,8 ;mm0 = ----r1g1b1------ - pand mm2,mm7 ;mm2 = --r3g3b3-------- - - movq mm5,[esi+16] ;mm5 = a5r5g5b5a4r4g4b4 - psllq mm4,48 ;mm4 = g2b2------------ - - por mm0,mm1 ;mm0 = ----r1g1b1r0g0b0 - psrlq mm3,16 ;mm3 = --------------r2 - - por mm0,mm4 ;mm0 = g2b2r1g1b1r0g0b0 - movq mm1,mm6 - - pand mm1,mm5 ;mm1 = ----------r4g4b4 - psrlq mm2,24 ;mm2 = --------r3g3b3-- - - movq [edi],mm0 - pand mm5,mm7 ;mm5 = --r5g5b5-------- - - psllq mm1,32 ;mm1 = --r4g4b4-------- - movq mm4,mm5 ;mm4 = --r5g5b5-------- - - por mm2,mm3 ;mm2 = --------r3g3b3r2 - psllq mm5,24 ;mm5 = b5-------------- - - movq mm3,[esi+24] ;mm3 = a7r7g7b7a6r6g6b6 - por mm2,mm1 ;mm2 = --r4g4b4r3g3b3r2 - - movq mm1,mm6 - por mm2,mm5 ;mm2 = b5r4g4b4r3g3b3r2 - - psrlq mm4,40 ;mm4 = ------------r5g5 - pand mm1,mm3 ;mm1 = ----------r6g6b6 - - psllq mm1,16 ;mm1 = ------r6g6b6---- - pand mm3,mm7 ;mm3 = --r7g7b7-------- - - por mm4,mm1 ;mm4 = ------r6g6b6r5g5 - psllq mm3,8 ;mm3 = r7g7b7---------- - - movq [edi+8],mm2 - por mm4,mm3 ;mm4 = r7g7b7r6g6b6r5g5 - - add esi,32 - sub ecx,1 - - movq [edi+16],mm4 ;mm3 - - lea edi,[edi+24] - jne .xloop - -.checkodd: - mov ecx,ebp - and ecx,7 - jz .noodd - movd mm0,eax -.oddloop: - mov eax,[esi] - add esi,4 - mov [edi],ax - shr eax,16 - mov [edi+2],al - add edi,3 - sub ecx,1 - jnz .oddloop - movd eax,mm0 -.noodd: - add esi,eax - add edi,ebx - - sub edx,1 - jne .yloop - - emms - - epilogue - ret - - global _vdasm_pixblt_XRGB1555_to_XRGB8888_MMX -_vdasm_pixblt_XRGB1555_to_XRGB8888_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp*2-12] - lea ecx, [ecx+ebp-6] - neg ebp - mov [esp+20+16], ebp - - movq mm5, [r_mask_555] - movq mm6, [g_mask_555] - movq mm7, [b_mask_555] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 6 - jbe .odd - -.xloop: - movq mm0, [ecx+ebp] - movq mm1, mm6 - movq mm2, mm7 - pand mm1, mm0 - pand mm2, mm0 - pand mm0, mm5 - - paddw mm0, mm0 - pmulhw mm1, [x4200w] - psllq mm2, 3 - paddw mm0, mm2 - movq mm2, mm0 - psrlw mm0, 5 - pand mm0, [x07b] - paddw mm0, mm2 - movq mm2, mm0 - punpcklbw mm0, mm1 - punpckhbw mm2, mm1 - - movq [edx+ebp*2], mm0 - movq [edx+ebp*2+8], mm2 - add ebp, 8 - jnc .xloop -.odd: - sub ebp, 6 - jz .noodd -.oddloop: - movzx eax, word [ecx+ebp+6] - mov ebx, 03e0h - mov esi, 001fh - and ebx, eax - and esi, eax - and eax, 07c00h - shl esi, 3 - shl ebx, 6 - shl eax, 9 - add ebx, esi - add eax, ebx - mov ebx, eax - shr eax, 5 - and eax, 070707h - add eax, ebx - mov [edx+ebp*2+12], eax - add ebp, 2 - jnz .oddloop -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - - global _vdasm_pixblt_RGB565_to_XRGB8888_MMX -_vdasm_pixblt_RGB565_to_XRGB8888_MMX: - prologue 6 - - mov ebp, [esp+20+16] - mov edi, [esp+24+16] - add ebp, ebp - mov edx, [esp+4+16] - mov ecx, [esp+12+16] - lea edx, [edx+ebp*2-12] - lea ecx, [ecx+ebp-6] - neg ebp - mov [esp+20+16], ebp - - movq mm5, [r_mask_565] - movq mm6, [g_mask_565] - movq mm7, [b_mask_565] - -.yloop: - mov ebp, [esp+20+16] - add ebp, 6 - jbe .odd - -.xloop: - movq mm0, [ecx+ebp] - movq mm1, mm6 - movq mm2, mm7 - pand mm1, mm0 - pand mm2, mm0 - pand mm0, mm5 - - pmulhw mm1, [x2080w] - psllq mm2, 3 - paddw mm0, mm2 - movq mm2, mm0 - psrlw mm0, 5 - pand mm0, [x07b] - paddw mm0, mm2 - movq mm2, mm0 - punpcklbw mm0, mm1 - punpckhbw mm2, mm1 - - movq [edx+ebp*2], mm0 - movq [edx+ebp*2+8], mm2 - add ebp, 8 - jnc .xloop - -.odd: - sub ebp, 6 - jz .noodd - push edi -.oddloop: - movzx eax, word [ecx+ebp+6] - mov ebx, 0000f800h - and ebx, eax - mov esi, eax - shl ebx, 8 - mov edi, eax - shl eax, 3 - and esi, 000007e0h - and eax, 000000f8h - add ebx, eax - shl esi, 5 - mov eax, ebx - shr ebx, 5 - and edi, 00000600h - shr edi, 1 - and ebx, 00070007h - add esi, edi - add eax, ebx - add eax, esi - mov [edx+ebp*2+12], eax - add ebp, 2 - jnz .oddloop - pop edi -.noodd: - add ecx, [esp+16+16] - add edx, [esp+8+16] - dec edi - jne .yloop - - emms - epilogue - ret - - - global _vdasm_pixblt_RGB888_to_XRGB8888_MMX -_vdasm_pixblt_RGB888_to_XRGB8888_MMX: - prologue 6 - - mov esi,[esp+12+16] - mov edi,[esp+4+16] - - mov ecx,[esp+20+16] - lea eax,[ecx+ecx*2] - lea ebx,[ecx*4] - sub [esp+8+16],ebx - sub [esp+16+16],eax - - mov edx,[esp+24+16] - mov ebx,[esp+20+16] - mov ecx,[esp+16+16] - mov eax,[esp+ 8+16] - - ;ebx horizontal count backup - ;ecx source modulo - ;edx vertical count - ;esi source - ;edi destination - ;ebp horizontal count - -.yloop: - mov ebp,ebx - shr ebp,3 - jz .checkodd -.xloop: - movq mm0,[esi] ;mm0: g2b2r1g1b1r0g0b0 - movq mm1,mm0 ; - - psrlq mm1,24 ;mm1: ------g2b2r1g1b1 - movq mm2,mm0 ; - - movq mm3,[esi+8] ;mm3: b5r4g4b4r3g3b3r2 - punpckldq mm0,mm1 ;mm0: b2r1g1b1b1r0g0b0 [qword 0 ready] - - movq mm4,mm3 ;mm4: b5r4g4b4r3g3b3r2 - psllq mm3,48 ;mm3: b3r2------------ - - movq mm5,mm4 ;mm5: b5r4g4b4r3g3b3r2 - psrlq mm2,16 ;mm2: ----g2b2-------- - - movq mm1,[esi+16] ;mm1: r7g7b7r6g6b6r5g5 - por mm2,mm3 ;mm2: b3r2g2b2-------- - - movq [edi],mm0 ; - psllq mm4,24 ;mm4: b4r3g3b3r2------ - - movq mm3,mm5 ;mm3: b5r4g4b4r3g3b3r2 - psrlq mm5,24 ;mm5: ------b5r4g4b4r3 - - movq mm0,mm1 ;mm0: r7g7b7r6g6b6r5g5 - psllq mm1,40 ;mm1: b6r5g5---------- - - punpckhdq mm2,mm4 ;mm2: b4r3g3b3b3r2g2b2 [qword 1 ready] - por mm1,mm5 ;mm1: b6r5g5b5r4g4b4r3 - - movq mm4,mm0 ;mm4: r7g7b7r6g6b6r5g5 - punpckhdq mm3,mm1 ;mm3: b6r5g5b5b5r4g4b4 [qword 2 ready] - - movq [edi+8],mm2 - psrlq mm0,16 ;mm0: ----r7g7b7r6g6b6 - - movq [edi+16],mm3 - psrlq mm4,40 ;mm4: ----------r7g7b7 - - punpckldq mm0,mm4 ;mm0: --r7g7b7b7r6g6b6 [qword 3 ready] - add esi,24 - - movq [edi+24],mm0 - - add edi,32 - sub ebp,1 - jne .xloop - -.checkodd: - mov ebp,ebx - and ebp,7 - jz .noodd - movd mm7,eax -.oddloop: - mov ax,[esi] - mov [edi],ax - mov al,[esi+2] - mov [edi+2],al - add esi,3 - add edi,4 - sub ebp,1 - jne .oddloop - - movd eax,mm7 -.noodd: - add esi,ecx - add edi,eax - - sub edx,1 - jne .yloop - emms - epilogue - ret - - end + section .rdata, rdata + +x07b dq 00707070707070707h +x0200w dq 00200020002000200h +x001fw dq 0001f001f001f001fh +xffc0w dq 0ffc0ffc0ffc0ffc0h +xffe0w dq 0ffe0ffe0ffe0ffe0h +x2080w dq 02080208020802080h +x4200w dq 04200420042004200h +rb_mask5 dq 000f800f800f800f8h +g_mask5 dq 00000f8000000f800h +g_mask6 dq 00000fc000000fc00h +rb_mul_565 dq 02000000420000004h +rb_mul_555 dq 02000000820000008h +r_mask_555 dq 07c007c007c007c00h +g_mask_555 dq 003e003e003e003e0h +b_mask_555 dq 0001f001f001f001fh +r_mask_565 dq 0f800f800f800f800h +g_mask_565 dq 007e007e007e007e0h +b_mask_565 dq 0001f001f001f001fh + +%macro prologue 1 + push ebx + push esi + push edi + push ebp + ;.fpo (0,%1,4,4,1,0) +%endmacro + +%macro epilogue 0 + pop ebp + pop edi + pop esi + pop ebx +%endmacro + + section .text + + global _vdasm_pixblt_RGB565_to_XRGB1555_MMX +_vdasm_pixblt_RGB565_to_XRGB1555_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-6] + lea ecx, [ecx+ebp-6] + neg ebp + mov [esp+20+16], ebp + + movq mm5, [x001fw] + movq mm4, [xffc0w] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 6 + jbe .odd + +.xloop: + movq mm0, [ecx+ebp] + movq mm1, mm5 + pand mm1, mm0 + pand mm0, mm4 + psrlq mm0, 1 + paddw mm0, mm1 + movq [edx+ebp], mm0 + add ebp, 8 + jnc .xloop + + sub ebp, 6 + jz .noodd +.odd: + movzx eax, word [ecx+ebp+6] + mov ebx, 0001f001fh + and ebx, eax + and eax, 0ffc0ffc0h + shr eax, 1 + add eax, ebx + mov [edx+ebp+6], ax + add ebp, 2 + jnz .odd +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + global _vdasm_pixblt_XRGB8888_to_XRGB1555_MMX +_vdasm_pixblt_XRGB8888_to_XRGB1555_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-14] + lea ecx, [ecx+ebp*2-28] + neg ebp + mov [esp+20+16], ebp + + movq mm5,[rb_mul_555] + movq mm6,[rb_mask5] + movq mm7,[g_mask5] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 14 + jbe .odd + + ;This code uses the "pmaddwd" trick for 32->16 conversions from Intel's MMX + ;Application Notes. + + movq mm0,[ecx+ebp*2] ;allocate 0 (0123) + movq mm2,mm0 ;allocate 2 (0 23) + + movq mm1,[ecx+ebp*2+8] ;allocate 1 (0123) + movq mm3,mm1 ;allocate 3 (0123) + pand mm0,mm6 + pmaddwd mm0,mm5 + pand mm1,mm6 + pmaddwd mm1,mm5 + pand mm2,mm7 + pand mm3,mm7 + jmp .xloopstart + + align 16 +.xloop: + movq mm0,[ecx+ebp*2] ;allocate 0 (01234) + por mm4,mm2 ;free 2 (01 34) + + por mm3,mm1 ;free 3 (01 34) + movq mm2,mm0 ;allocate 2 (0 234) + + movq mm1,[ecx+ebp*2+8] ;allocate 1 (01234) + psrld mm4,6 + + psrld mm3,6 + pand mm0,mm6 + + packssdw mm4,mm3 ;free 3 (012 4) + movq mm3,mm1 ;allocate 3 (01234) + + pmaddwd mm0,mm5 + pand mm1,mm6 + + pmaddwd mm1,mm5 + pand mm2,mm7 + + movq [edx+ebp-8],mm4 ;free 4 (0123 ) + pand mm3,mm7 + +.xloopstart: + movq mm4,[ecx+ebp*2+16] ;allocate 4 (01234) + por mm0,mm2 ;free 2 (01 34) + + por mm1,mm3 ;free 3 (01 4) + psrld mm0,6 + + movq mm3,[ecx+ebp*2+24] ;allocate 3 (01 34) + movq mm2,mm4 ;allocate 2 (01234) + + psrld mm1,6 + pand mm4,mm6 + + packssdw mm0,mm1 ;free 1 (0 234) + movq mm1,mm3 ;allocate 1 (01234) + + movq [edx+ebp],mm0 ;free 0 ( 1234) + pand mm3,mm6 + + pmaddwd mm4,mm5 + add ebp,16 + + pmaddwd mm3,mm5 + pand mm2,mm7 + + pand mm1,mm7 + jnc .xloop + + por mm4,mm2 ;free 2 (01 34) + por mm3,mm1 ;free 3 (01 34) + psrld mm4,6 + psrld mm3,6 + packssdw mm4,mm3 ;free 3 (012 4) + movq [edx+ebp-8],mm4 ;free 4 (0123 ) + +.odd: + sub ebp, 14 + jz .noodd +.oddloop: + mov eax, [ecx+ebp*2+28] + mov ebx, 00f80000h + mov esi, eax + and ebx, eax + shr ebx, 9 + and esi, 0000f800h + shr esi, 6 + and eax, 000000f8h + shr eax, 3 + add esi, ebx + add eax, esi + mov [edx+ebp+14], ax + add ebp, 2 + jnz .oddloop +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + global _vdasm_pixblt_XRGB1555_to_RGB565_MMX +_vdasm_pixblt_XRGB1555_to_RGB565_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-6] + lea ecx, [ecx+ebp-6] + neg ebp + mov [esp+20+16], ebp + + movq mm5, [x0200w] + movq mm4, [xffe0w] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 6 + jbe .odd + +.xloop: + movq mm0, [ecx+ebp] + movq mm1, mm4 + movq mm2, mm0 + pand mm1, mm0 + pand mm0, mm5 + paddw mm1, mm2 + psrlq mm0, 4 + paddw mm0, mm1 + movq [edx+ebp], mm0 + add ebp, 8 + jnc .xloop + +.odd: + sub ebp, 6 + jz .noodd +.oddloop: + movzx eax, word [ecx+ebp+6] + mov ebx, 02000200h + mov esi, eax + and ebx, eax + shr ebx, 4 + and esi, 0ffe0ffe0h + add eax, esi + add eax, ebx + mov [edx+ebp+6], ax + add ebp, 2 + jnz .oddloop +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + + global _vdasm_pixblt_XRGB8888_to_RGB565_MMX +_vdasm_pixblt_XRGB8888_to_RGB565_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp-14] + lea ecx, [ecx+ebp*2-28] + neg ebp + mov [esp+20+16], ebp + + movq mm5,[rb_mul_565] + movq mm6,[rb_mask5] + movq mm7,[g_mask6] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 14 + jbe .odd + + ;This code uses the "pmaddwd" trick for 32->16 conversions from Intel's MMX + ;Application Notes. + + movq mm0,[ecx+ebp*2] ;allocate 0 (0123) + movq mm2,mm0 ;allocate 2 (0 23) + + movq mm1,[ecx+ebp*2+8] ;allocate 1 (0123) + movq mm3,mm1 ;allocate 3 (0123) + pand mm0,mm6 + pmaddwd mm0,mm5 + pand mm1,mm6 + pmaddwd mm1,mm5 + pand mm2,mm7 + pand mm3,mm7 + jmp .xloopstart + + align 16 +.xloop: + movq mm0,[ecx+ebp*2] ;allocate 0 (01234) + por mm4,mm2 ;free 2 (01 34) + + por mm3,mm1 ;free 3 (01 34) + pslld mm4,16-5 + + pslld mm3,16-5 + movq mm2,mm0 ;allocate 2 (0 234) + + movq mm1,[ecx+ebp*2+8] ;allocate 1 (01234) + psrad mm4,16 + + psrad mm3,16 + pand mm0,mm6 + + packssdw mm4,mm3 ;free 3 (012 4) + movq mm3,mm1 ;allocate 3 (01234) + + pmaddwd mm0,mm5 + pand mm1,mm6 + + pmaddwd mm1,mm5 + pand mm2,mm7 + + movq [edx+ebp-8],mm4 ;free 4 (0123 ) + pand mm3,mm7 + +.xloopstart: + movq mm4,[ecx+ebp*2+16] ;allocate 4 (01234) + por mm0,mm2 ;free 2 (01 34) + + por mm1,mm3 ;free 3 (01 4) + pslld mm0,16-5 + + movq mm3,[ecx+ebp*2+24] ;allocate 3 (01 34) + pslld mm1,16-5 + + psrad mm0,16 + movq mm2,mm4 ;allocate 2 (01234) + + psrad mm1,16 + pand mm4,mm6 + + packssdw mm0,mm1 ;free 1 (0 234) + movq mm1,mm3 ;allocate 1 (01234) + + movq [edx+ebp],mm0 ;free 0 ( 1234) + pand mm3,mm6 + + pmaddwd mm4,mm5 + add ebp,16 + + pmaddwd mm3,mm5 + pand mm2,mm7 + + pand mm1,mm7 + jnc .xloop + + por mm4,mm2 ;free 2 (01 34) + por mm3,mm1 ;free 3 (01 34) + psllq mm4,16-5 + psllq mm3,16-5 + psrad mm4,16 + psrad mm3,16 + packssdw mm4,mm3 ;free 3 (012 4) + movq [edx+ebp-8],mm4 ;free 4 (0123 ) + +.odd: + sub ebp, 14 + jz .noodd +.oddloop: + mov eax, [ecx+ebp*2+28] + mov ebx, 00f80000h + mov esi, eax + and ebx, eax + and eax, 000000f8h + shr eax, 3 + and esi, 0000fc00h + shr ebx, 8 + shr esi, 5 + add eax, ebx + add eax, esi + mov [edx+ebp+14], ax + add ebp, 2 + jnz .oddloop +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + global _vdasm_pixblt_XRGB8888_to_RGB888_MMX +_vdasm_pixblt_XRGB8888_to_RGB888_MMX: + prologue 6 + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ecx,[esp+20+16] + lea eax,[ecx+ecx*2] + lea ebx,[ecx*4] + sub [esp+8+16],eax + sub [esp+16+16],ebx + + pcmpeqb mm7,mm7 + psrld mm7,8 + movq mm6,mm7 + psllq mm7,32 ;mm7 = high rgb mask + psrlq mm6,32 ;mm6 = low rgb mask + + mov ebp,[esp+20+16] + mov edx,[esp+24+16] + mov eax,[esp+16+16] + mov ebx,[esp+ 8+16] +.yloop: + mov ecx,ebp + shr ecx,3 + jz .checkodd +.xloop: + movq mm0,[esi] ;mm0 = a1r1g1b1a0r0g0b0 + movq mm1,mm6 + + movq mm2,[esi+8] ;mm2 = a3r3g3b3a2r2g2b2 + pand mm1,mm0 ;mm1 = ----------r0g0b0 + + movq mm3,mm6 + pand mm0,mm7 ;mm0 = --r1g1b1-------- + + movq mm4,mm2 + pand mm3,mm2 ;mm3 = ----------r2g2b2 + + psrlq mm0,8 ;mm0 = ----r1g1b1------ + pand mm2,mm7 ;mm2 = --r3g3b3-------- + + movq mm5,[esi+16] ;mm5 = a5r5g5b5a4r4g4b4 + psllq mm4,48 ;mm4 = g2b2------------ + + por mm0,mm1 ;mm0 = ----r1g1b1r0g0b0 + psrlq mm3,16 ;mm3 = --------------r2 + + por mm0,mm4 ;mm0 = g2b2r1g1b1r0g0b0 + movq mm1,mm6 + + pand mm1,mm5 ;mm1 = ----------r4g4b4 + psrlq mm2,24 ;mm2 = --------r3g3b3-- + + movq [edi],mm0 + pand mm5,mm7 ;mm5 = --r5g5b5-------- + + psllq mm1,32 ;mm1 = --r4g4b4-------- + movq mm4,mm5 ;mm4 = --r5g5b5-------- + + por mm2,mm3 ;mm2 = --------r3g3b3r2 + psllq mm5,24 ;mm5 = b5-------------- + + movq mm3,[esi+24] ;mm3 = a7r7g7b7a6r6g6b6 + por mm2,mm1 ;mm2 = --r4g4b4r3g3b3r2 + + movq mm1,mm6 + por mm2,mm5 ;mm2 = b5r4g4b4r3g3b3r2 + + psrlq mm4,40 ;mm4 = ------------r5g5 + pand mm1,mm3 ;mm1 = ----------r6g6b6 + + psllq mm1,16 ;mm1 = ------r6g6b6---- + pand mm3,mm7 ;mm3 = --r7g7b7-------- + + por mm4,mm1 ;mm4 = ------r6g6b6r5g5 + psllq mm3,8 ;mm3 = r7g7b7---------- + + movq [edi+8],mm2 + por mm4,mm3 ;mm4 = r7g7b7r6g6b6r5g5 + + add esi,32 + sub ecx,1 + + movq [edi+16],mm4 ;mm3 + + lea edi,[edi+24] + jne .xloop + +.checkodd: + mov ecx,ebp + and ecx,7 + jz .noodd + movd mm0,eax +.oddloop: + mov eax,[esi] + add esi,4 + mov [edi],ax + shr eax,16 + mov [edi+2],al + add edi,3 + sub ecx,1 + jnz .oddloop + movd eax,mm0 +.noodd: + add esi,eax + add edi,ebx + + sub edx,1 + jne .yloop + + emms + + epilogue + ret + + global _vdasm_pixblt_XRGB1555_to_XRGB8888_MMX +_vdasm_pixblt_XRGB1555_to_XRGB8888_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp*2-12] + lea ecx, [ecx+ebp-6] + neg ebp + mov [esp+20+16], ebp + + movq mm5, [r_mask_555] + movq mm6, [g_mask_555] + movq mm7, [b_mask_555] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 6 + jbe .odd + +.xloop: + movq mm0, [ecx+ebp] + movq mm1, mm6 + movq mm2, mm7 + pand mm1, mm0 + pand mm2, mm0 + pand mm0, mm5 + + paddw mm0, mm0 + pmulhw mm1, [x4200w] + psllq mm2, 3 + paddw mm0, mm2 + movq mm2, mm0 + psrlw mm0, 5 + pand mm0, [x07b] + paddw mm0, mm2 + movq mm2, mm0 + punpcklbw mm0, mm1 + punpckhbw mm2, mm1 + + movq [edx+ebp*2], mm0 + movq [edx+ebp*2+8], mm2 + add ebp, 8 + jnc .xloop +.odd: + sub ebp, 6 + jz .noodd +.oddloop: + movzx eax, word [ecx+ebp+6] + mov ebx, 03e0h + mov esi, 001fh + and ebx, eax + and esi, eax + and eax, 07c00h + shl esi, 3 + shl ebx, 6 + shl eax, 9 + add ebx, esi + add eax, ebx + mov ebx, eax + shr eax, 5 + and eax, 070707h + add eax, ebx + mov [edx+ebp*2+12], eax + add ebp, 2 + jnz .oddloop +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + + global _vdasm_pixblt_RGB565_to_XRGB8888_MMX +_vdasm_pixblt_RGB565_to_XRGB8888_MMX: + prologue 6 + + mov ebp, [esp+20+16] + mov edi, [esp+24+16] + add ebp, ebp + mov edx, [esp+4+16] + mov ecx, [esp+12+16] + lea edx, [edx+ebp*2-12] + lea ecx, [ecx+ebp-6] + neg ebp + mov [esp+20+16], ebp + + movq mm5, [r_mask_565] + movq mm6, [g_mask_565] + movq mm7, [b_mask_565] + +.yloop: + mov ebp, [esp+20+16] + add ebp, 6 + jbe .odd + +.xloop: + movq mm0, [ecx+ebp] + movq mm1, mm6 + movq mm2, mm7 + pand mm1, mm0 + pand mm2, mm0 + pand mm0, mm5 + + pmulhw mm1, [x2080w] + psllq mm2, 3 + paddw mm0, mm2 + movq mm2, mm0 + psrlw mm0, 5 + pand mm0, [x07b] + paddw mm0, mm2 + movq mm2, mm0 + punpcklbw mm0, mm1 + punpckhbw mm2, mm1 + + movq [edx+ebp*2], mm0 + movq [edx+ebp*2+8], mm2 + add ebp, 8 + jnc .xloop + +.odd: + sub ebp, 6 + jz .noodd + push edi +.oddloop: + movzx eax, word [ecx+ebp+6] + mov ebx, 0000f800h + and ebx, eax + mov esi, eax + shl ebx, 8 + mov edi, eax + shl eax, 3 + and esi, 000007e0h + and eax, 000000f8h + add ebx, eax + shl esi, 5 + mov eax, ebx + shr ebx, 5 + and edi, 00000600h + shr edi, 1 + and ebx, 00070007h + add esi, edi + add eax, ebx + add eax, esi + mov [edx+ebp*2+12], eax + add ebp, 2 + jnz .oddloop + pop edi +.noodd: + add ecx, [esp+16+16] + add edx, [esp+8+16] + dec edi + jne .yloop + + emms + epilogue + ret + + + global _vdasm_pixblt_RGB888_to_XRGB8888_MMX +_vdasm_pixblt_RGB888_to_XRGB8888_MMX: + prologue 6 + + mov esi,[esp+12+16] + mov edi,[esp+4+16] + + mov ecx,[esp+20+16] + lea eax,[ecx+ecx*2] + lea ebx,[ecx*4] + sub [esp+8+16],ebx + sub [esp+16+16],eax + + mov edx,[esp+24+16] + mov ebx,[esp+20+16] + mov ecx,[esp+16+16] + mov eax,[esp+ 8+16] + + ;ebx horizontal count backup + ;ecx source modulo + ;edx vertical count + ;esi source + ;edi destination + ;ebp horizontal count + +.yloop: + mov ebp,ebx + shr ebp,3 + jz .checkodd +.xloop: + movq mm0,[esi] ;mm0: g2b2r1g1b1r0g0b0 + movq mm1,mm0 ; + + psrlq mm1,24 ;mm1: ------g2b2r1g1b1 + movq mm2,mm0 ; + + movq mm3,[esi+8] ;mm3: b5r4g4b4r3g3b3r2 + punpckldq mm0,mm1 ;mm0: b2r1g1b1b1r0g0b0 [qword 0 ready] + + movq mm4,mm3 ;mm4: b5r4g4b4r3g3b3r2 + psllq mm3,48 ;mm3: b3r2------------ + + movq mm5,mm4 ;mm5: b5r4g4b4r3g3b3r2 + psrlq mm2,16 ;mm2: ----g2b2-------- + + movq mm1,[esi+16] ;mm1: r7g7b7r6g6b6r5g5 + por mm2,mm3 ;mm2: b3r2g2b2-------- + + movq [edi],mm0 ; + psllq mm4,24 ;mm4: b4r3g3b3r2------ + + movq mm3,mm5 ;mm3: b5r4g4b4r3g3b3r2 + psrlq mm5,24 ;mm5: ------b5r4g4b4r3 + + movq mm0,mm1 ;mm0: r7g7b7r6g6b6r5g5 + psllq mm1,40 ;mm1: b6r5g5---------- + + punpckhdq mm2,mm4 ;mm2: b4r3g3b3b3r2g2b2 [qword 1 ready] + por mm1,mm5 ;mm1: b6r5g5b5r4g4b4r3 + + movq mm4,mm0 ;mm4: r7g7b7r6g6b6r5g5 + punpckhdq mm3,mm1 ;mm3: b6r5g5b5b5r4g4b4 [qword 2 ready] + + movq [edi+8],mm2 + psrlq mm0,16 ;mm0: ----r7g7b7r6g6b6 + + movq [edi+16],mm3 + psrlq mm4,40 ;mm4: ----------r7g7b7 + + punpckldq mm0,mm4 ;mm0: --r7g7b7b7r6g6b6 [qword 3 ready] + add esi,24 + + movq [edi+24],mm0 + + add edi,32 + sub ebp,1 + jne .xloop + +.checkodd: + mov ebp,ebx + and ebp,7 + jz .noodd + movd mm7,eax +.oddloop: + mov ax,[esi] + mov [edi],ax + mov al,[esi+2] + mov [edi+2],al + add esi,3 + add edi,4 + sub ebp,1 + jne .oddloop + + movd eax,mm7 +.noodd: + add esi,ecx + add edi,eax + + sub edx,1 + jne .yloop + emms + epilogue + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_bltyuv2rgb_sse2.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_bltyuv2rgb_sse2.asm index 7a1e193766e..87ff13b5620 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_bltyuv2rgb_sse2.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_bltyuv2rgb_sse2.asm @@ -1,161 +1,161 @@ - section .rdata, rdata - - align 16 - -bytemasks dd 000000ffh, 0000ffffh, 00ffffffh - - section .text - -;============================================================================ - - global _vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2 -_vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2: - push edi - push esi - push ebx - - mov eax, [esp+4+12] - mov ebx, [esp+8+12] - mov ecx, [esp+12+12] - mov edx, [esp+16+12] - mov esi, [esp+20+12] - mov edi, [esp+24+12] - - pcmpeqb xmm6, xmm6 - psrlw xmm6, 8 ;xmm6 = 00FF x 8 - - sub esi, 4 - js .postcheck -.xloop: - movdqu xmm2, [edx] ;xmm0 = X3R3G3B3X2R2G2B2X1R1G1B1X0R0G0B0 - add edx, 16 - movdqa xmm5, xmm2 - pand xmm2, xmm6 ;xmm0 = R3 B3 R2 B2 R1 B1 R0 B0 - psrlw xmm5, 8 ;xmm1 = X3 G3 X2 G2 X1 G1 X0 G0 - movdqa xmm0, [edi+0] ;coeff_rb_to_y - movdqa xmm1, [edi+16] ;coeff_rb_to_u - movdqa xmm3, [edi+32] ;coeff_g_to_y - movdqa xmm4, [edi+48] ;coeff_g_to_u - pmaddwd xmm0, xmm2 - pmaddwd xmm1, xmm2 - pmaddwd xmm2, [edi+64] ;coeff_rb_to_v - pmaddwd xmm3, xmm5 - pmaddwd xmm4, xmm5 - pmaddwd xmm5, [edi+80] ;coeff_g_to_v - paddd xmm0, xmm3 - paddd xmm1, xmm4 - paddd xmm2, xmm5 - paddd xmm0, [edi+96] ;bias_y - paddd xmm1, [edi+112] ;bias_c - paddd xmm2, [edi+112] ;bias_c - psrad xmm0, 15 - psrad xmm1, 15 - psrad xmm2, 15 - packssdw xmm0, xmm0 - packssdw xmm1, xmm1 - packssdw xmm2, xmm2 - packuswb xmm0, xmm0 - packuswb xmm1, xmm1 - packuswb xmm2, xmm2 - movd [eax], xmm0 - movd [ebx], xmm1 - movd [ecx], xmm2 - add eax, 4 - add ebx, 4 - add ecx, 4 - sub esi, 4 - jns .xloop -.postcheck: - jmp dword [.finaltable + esi*4 + 16] -.complete: - pop ebx - pop esi - pop edi - ret - -.finaltable: - dd .complete - dd .do1 - dd .do2 - dd .do3 - -.finaltable2: - dd .fin1 - dd .fin2 - dd .fin3 - -.do1: - movd xmm2, [edx] - jmp short .dofinal -.do2: - movq xmm2, [edx] - jmp short .dofinal -.do3: - movq xmm2, [edx] - movd xmm1, [edx] - movlhps xmm2, xmm1 -.dofinal: - movdqa xmm5, xmm2 - pand xmm2, xmm6 ;xmm0 = R3 B3 R2 B2 R1 B1 R0 B0 - psrlw xmm5, 8 ;xmm1 = X3 G3 X2 G2 X1 G1 X0 G0 - movdqa xmm0, [edi+0] ;coeff_rb_to_y - movdqa xmm1, [edi+16] ;coeff_rb_to_u - movdqa xmm3, [edi+32] ;coeff_g_to_y - movdqa xmm4, [edi+48] ;coeff_g_to_u - pmaddwd xmm0, xmm2 - pmaddwd xmm1, xmm2 - pmaddwd xmm2, [edi+64] ;coeff_rb_to_v - pmaddwd xmm3, xmm5 - pmaddwd xmm4, xmm5 - pmaddwd xmm5, [edi+80] ;coeff_g_to_v - paddd xmm0, xmm3 - paddd xmm1, xmm4 - paddd xmm2, xmm5 - paddd xmm0, [edi+96] ;bias_y - paddd xmm1, [edi+112] ;bias_c - paddd xmm2, [edi+112] ;bias_c - psrad xmm0, 15 - psrad xmm1, 15 - psrad xmm2, 15 - packssdw xmm0, xmm0 - packssdw xmm1, xmm1 - packssdw xmm2, xmm2 - packuswb xmm0, xmm0 - packuswb xmm1, xmm1 - movd xmm7, [bytemasks + esi*4 + 12] - packuswb xmm2, xmm2 - - jmp dword [.finaltable2 + esi*4 + 12] - -.fin1: - movd edx, xmm0 - mov [eax], dl - movd edx, xmm1 - mov [ebx], dl - movd edx, xmm2 - mov [ecx], dl - jmp .complete -.fin2: - movd edx, xmm0 - mov [eax], dx - movd edx, xmm1 - mov [ebx], dx - movd edx, xmm2 - mov [ecx], dx - jmp .complete -.fin3: - movd edx, xmm0 - mov [eax], dx - shr edx, 16 - mov [eax+2], dl - movd edx, xmm1 - mov [ebx], dx - shr edx, 16 - mov [ebx+2], dl - movd edx, xmm2 - mov [ecx], dx - shr edx, 16 - mov [ecx+2], dl - jmp .complete - - end + section .rdata, rdata + + align 16 + +bytemasks dd 000000ffh, 0000ffffh, 00ffffffh + + section .text + +;============================================================================ + + global _vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2 +_vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2: + push edi + push esi + push ebx + + mov eax, [esp+4+12] + mov ebx, [esp+8+12] + mov ecx, [esp+12+12] + mov edx, [esp+16+12] + mov esi, [esp+20+12] + mov edi, [esp+24+12] + + pcmpeqb xmm6, xmm6 + psrlw xmm6, 8 ;xmm6 = 00FF x 8 + + sub esi, 4 + js .postcheck +.xloop: + movdqu xmm2, [edx] ;xmm0 = X3R3G3B3X2R2G2B2X1R1G1B1X0R0G0B0 + add edx, 16 + movdqa xmm5, xmm2 + pand xmm2, xmm6 ;xmm0 = R3 B3 R2 B2 R1 B1 R0 B0 + psrlw xmm5, 8 ;xmm1 = X3 G3 X2 G2 X1 G1 X0 G0 + movdqa xmm0, [edi+0] ;coeff_rb_to_y + movdqa xmm1, [edi+16] ;coeff_rb_to_u + movdqa xmm3, [edi+32] ;coeff_g_to_y + movdqa xmm4, [edi+48] ;coeff_g_to_u + pmaddwd xmm0, xmm2 + pmaddwd xmm1, xmm2 + pmaddwd xmm2, [edi+64] ;coeff_rb_to_v + pmaddwd xmm3, xmm5 + pmaddwd xmm4, xmm5 + pmaddwd xmm5, [edi+80] ;coeff_g_to_v + paddd xmm0, xmm3 + paddd xmm1, xmm4 + paddd xmm2, xmm5 + paddd xmm0, [edi+96] ;bias_y + paddd xmm1, [edi+112] ;bias_c + paddd xmm2, [edi+112] ;bias_c + psrad xmm0, 15 + psrad xmm1, 15 + psrad xmm2, 15 + packssdw xmm0, xmm0 + packssdw xmm1, xmm1 + packssdw xmm2, xmm2 + packuswb xmm0, xmm0 + packuswb xmm1, xmm1 + packuswb xmm2, xmm2 + movd [eax], xmm0 + movd [ebx], xmm1 + movd [ecx], xmm2 + add eax, 4 + add ebx, 4 + add ecx, 4 + sub esi, 4 + jns .xloop +.postcheck: + jmp dword [.finaltable + esi*4 + 16] +.complete: + pop ebx + pop esi + pop edi + ret + +.finaltable: + dd .complete + dd .do1 + dd .do2 + dd .do3 + +.finaltable2: + dd .fin1 + dd .fin2 + dd .fin3 + +.do1: + movd xmm2, [edx] + jmp short .dofinal +.do2: + movq xmm2, [edx] + jmp short .dofinal +.do3: + movq xmm2, [edx] + movd xmm1, [edx] + movlhps xmm2, xmm1 +.dofinal: + movdqa xmm5, xmm2 + pand xmm2, xmm6 ;xmm0 = R3 B3 R2 B2 R1 B1 R0 B0 + psrlw xmm5, 8 ;xmm1 = X3 G3 X2 G2 X1 G1 X0 G0 + movdqa xmm0, [edi+0] ;coeff_rb_to_y + movdqa xmm1, [edi+16] ;coeff_rb_to_u + movdqa xmm3, [edi+32] ;coeff_g_to_y + movdqa xmm4, [edi+48] ;coeff_g_to_u + pmaddwd xmm0, xmm2 + pmaddwd xmm1, xmm2 + pmaddwd xmm2, [edi+64] ;coeff_rb_to_v + pmaddwd xmm3, xmm5 + pmaddwd xmm4, xmm5 + pmaddwd xmm5, [edi+80] ;coeff_g_to_v + paddd xmm0, xmm3 + paddd xmm1, xmm4 + paddd xmm2, xmm5 + paddd xmm0, [edi+96] ;bias_y + paddd xmm1, [edi+112] ;bias_c + paddd xmm2, [edi+112] ;bias_c + psrad xmm0, 15 + psrad xmm1, 15 + psrad xmm2, 15 + packssdw xmm0, xmm0 + packssdw xmm1, xmm1 + packssdw xmm2, xmm2 + packuswb xmm0, xmm0 + packuswb xmm1, xmm1 + movd xmm7, [bytemasks + esi*4 + 12] + packuswb xmm2, xmm2 + + jmp dword [.finaltable2 + esi*4 + 12] + +.fin1: + movd edx, xmm0 + mov [eax], dl + movd edx, xmm1 + mov [ebx], dl + movd edx, xmm2 + mov [ecx], dl + jmp .complete +.fin2: + movd edx, xmm0 + mov [eax], dx + movd edx, xmm1 + mov [ebx], dx + movd edx, xmm2 + mov [ecx], dx + jmp .complete +.fin3: + movd edx, xmm0 + mov [eax], dx + shr edx, 16 + mov [eax+2], dl + movd edx, xmm1 + mov [ebx], dx + shr edx, 16 + mov [ebx+2], dl + movd edx, xmm2 + mov [ecx], dx + shr edx, 16 + mov [ecx+2], dl + jmp .complete + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_resample_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_resample_mmx.asm index ff504be2e64..912c655abd0 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_resample_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_resample_mmx.asm @@ -1,1559 +1,1559 @@ -; VirtualDub - Video processing and capture application -; Graphics support library -; Copyright (C) 1998-2004 Avery Lee -; -; This program 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 2 of the License, or -; (at your option) any later version. -; -; This program 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, write to the Free Software -; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -; - section .rdata, rdata, align=16 - -x0002000200020002 dq 0002000200020002h -x0004000400040004 dq 0004000400040004h -x0008000800080008 dq 0008000800080008h -x0000200000002000 dq 0000200000002000h - - align 16 -MMX_roundval dq 0000200000002000h, 0000200000002000h - - -;************************************************************************** - -x0000FFFF0000FFFF dq 0000FFFF0000FFFFh -x0000010100000101 dq 0000010100000101h -x0100010001000100 dq 0100010001000100h - - section .text - -;-------------------------------------------------------------------------- -;_vdasm_resize_interp_row_run_MMX( -; [esp+ 4] void *dst, -; [esp+ 8] void *src, -; [esp+12] ulong width, -; [esp+16] __int64 xaccum, -; [esp+24] __int64 x_inc); -; - global _vdasm_resize_interp_row_run_MMX -_vdasm_resize_interp_row_run_MMX: - push ebp - push edi - push esi - push ebx - - mov esi, [esp+8+16] - mov edi, [esp+4+16] - mov ebp, [esp+12+16] - - movd mm4, dword [esp+16+16] - pxor mm7, mm7 - movd mm6, dword [esp+24+16] - punpckldq mm4, mm4 - punpckldq mm6, mm6 - - shr esi, 2 - - mov eax, [esp+16+16] - mov ebx, [esp+20+16] - add esi, ebx - mov ebx, [esp+24+16] - mov ecx, [esp+28+16] - - shl ebp,2 - add edi,ebp - neg ebp - -.colloop: - movd mm1, dword [esi*4+4] - movq mm5, mm4 - - movd mm0, dword [esi*4] - punpcklbw mm1, mm7 - - punpcklbw mm0, mm7 - psrld mm5, 24 - - movq mm3, [x0100010001000100] - packssdw mm5, mm5 - - pmullw mm1, mm5 - psubw mm3, mm5 - - pmullw mm0, mm3 - paddd mm4, mm6 - - ;stall - ;stall - - ;stall - ;stall - - paddw mm0, mm1 - - psrlw mm0, 8 - add eax, ebx - - adc esi, ecx - packuswb mm0, mm0 - - movd dword [edi+ebp],mm0 - - add ebp, 4 - jnz .colloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - -;************************************************************************** - -;vdasm_resize_interp_col_run_MMX( -; [esp+ 4] void *dst, -; [esp+ 8] void *src1, -; [esp+12] void *src2, -; [esp+16] ulong width, -; [esp+20] ulong yaccum); - - - global _vdasm_resize_interp_col_run_MMX -_vdasm_resize_interp_col_run_MMX: - push ebp - push edi - push esi - push ebx - - mov esi, [esp+8+16] - mov edx, [esp+12+16] - mov edi, [esp+4+16] - mov ebp, [esp+16+16] - - movd mm4, dword [esp+20+16] - pxor mm7, mm7 - punpcklwd mm4, mm4 - punpckldq mm4, mm4 - psrlw mm4, 8 - pxor mm4, [x0000FFFF0000FFFF] - paddw mm4, [x0000010100000101] - - shl ebp, 2 - add edi, ebp - add esi, ebp - add edx, ebp - neg ebp - -.colloop: - movd mm0, dword [esi+ebp] - movd mm2, dword [edx+ebp] - - punpcklbw mm0, mm7 - punpcklbw mm2, mm7 - - movq mm1, mm0 - punpcklwd mm0, mm2 - punpckhwd mm1, mm2 - - pmaddwd mm0, mm4 - pmaddwd mm1, mm4 - - psrad mm0, 8 - psrad mm1, 8 - - packssdw mm0, mm1 - packuswb mm0, mm0 - - movd dword [edi+ebp],mm0 - - add ebp, 4 - jnz .colloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - -;-------------------------------------------------------------------------- -;vdasm_resize_ccint_row_MMX(dst, src, count, xaccum, xinc, tbl); - - global _vdasm_resize_ccint_row_MMX -_vdasm_resize_ccint_row_MMX: - push ebx - push esi - push edi - push ebp - - mov ebx, [esp+4+16] ;ebx = dest addr - mov ecx, [esp+12+16] ;ecx = count - - mov ebp, [esp+20+16] ;ebp = increment - mov edi, ebp ;edi = increment - shl ebp, 16 ;ebp = fractional increment - mov esi, [esp+16+16] ;esi = 16:16 position - sar edi, 16 ;edi = integer increment - mov [esp+20+16], ebp ;xinc = fractional increment - mov ebp, esi ;ebp = 16:16 position - shr esi, 16 ;esi = integer position - shl ebp, 16 ;ebp = fraction - mov [esp+16+16], ebp ;xaccum = fraction - - mov eax, [esp+8+16] - - shr ebp, 24 ;ebp = fraction (0...255) - mov [esp+8+16], edi - shl ebp, 4 ;ebp = fraction*16 - mov edi, ebp - mov ebp, [esp+4+16] ;ebp = destination - - shr eax, 2 - add eax, esi - shl ecx, 2 ;ecx = count*4 - lea ebp, [ebp+ecx-4] - neg ecx ;ecx = -count*4 - - movq mm6, [x0000200000002000] - pxor mm7, mm7 - - mov edx,[esp+16+16] ;edx = fractional accumulator - mov esi,[esp+20+16] ;esi = fractional increment - - mov ebx,[esp+24+16] ;ebx = coefficient pointer - - movd mm0,dword [eax*4] - movd mm1,dword [eax*4+4] - punpcklbw mm0,mm7 ;mm0 = [a1][r1][g1][b1] - - ;borrow stack pointer - push 0 ;don't crash - push dword [fs:0] - mov dword [fs:0], esp - mov esp, [esp+8+24] ;esp = integer increment - jmp short ccint_loop_MMX_start - - ;EAX source pointer / 4 - ;EBX coefficient pointer - ;ECX count - ;EDX fractional accumulator - ;ESI fractional increment - ;EDI coefficient offset - ;ESP integer increment - ;EBP destination pointer - - align 16 -ccint_loop_MMX: - movd mm0,dword [eax*4] - packuswb mm2,mm2 ;mm0 = [a][r][g][b][a][r][g][b] - - movd mm1,dword [eax*4+4] - punpcklbw mm0,mm7 ;mm0 = [a1][r1][g1][b1] - - movd dword [ebp+ecx],mm2 -ccint_loop_MMX_start: - movq mm4,mm0 ;mm0 = [a1][r1][g1][b1] - - movd mm2,dword [eax*4+8] - punpcklbw mm1,mm7 ;mm1 = [a2][r2][g2][b2] - - movd mm3,dword [eax*4+12] - punpcklbw mm2,mm7 ;mm2 = [a3][r3][g3][b3] - - punpcklbw mm3,mm7 ;mm3 = [a4][r4][g4][b4] - movq mm5,mm2 ;mm2 = [a3][r3][g3][b3] - - add edx,esi ;add fractional increment - punpcklwd mm0,mm1 ;mm0 = [g2][g1][b2][b1] - - pmaddwd mm0,[ebx+edi] - punpcklwd mm2,mm3 ;mm2 = [g4][g3][b4][b3] - - pmaddwd mm2,[ebx+edi+8] - punpckhwd mm4,mm1 ;mm4 = [a2][a1][r2][r1] - - pmaddwd mm4,[ebx+edi] - punpckhwd mm5,mm3 ;mm5 = [a4][a3][b4][b3] - - pmaddwd mm5,[ebx+edi+8] - paddd mm0,mm6 - - adc eax,esp ;add integer increment and fractional bump to offset - mov edi,0ff000000h - - paddd mm2,mm0 ;mm0 = [ g ][ b ] - paddd mm4,mm6 - - psrad mm2,14 - paddd mm4,mm5 ;mm4 = [ a ][ r ] - - and edi,edx - psrad mm4,14 - - shr edi,20 ;edi = fraction (0...255)*16 - add ecx,4 - - packssdw mm2,mm4 ;mm0 = [ a ][ r ][ g ][ b ] - jnc ccint_loop_MMX - - packuswb mm2,mm2 ;mm0 = [a][r][g][b][a][r][g][b] - movd dword [ebp],mm2 - - mov esp, dword [fs:0] - pop dword [fs:0] - pop eax - - pop ebp - pop edi - pop esi - pop ebx - ret - -;-------------------------------------------------------------------------- -;vdasm_resize_ccint_col_MMX(dst, src1, src2, src3, src4, count, tbl); - - global _vdasm_resize_ccint_col_MMX -_vdasm_resize_ccint_col_MMX: - push ebx - push esi - push edi - push ebp - - mov ebp, [esp+4+16] ;ebp = dest addr - mov esi, [esp+24+16] ;esi = count - add esi, esi - add esi, esi - - mov eax, [esp+8+16] ;eax = row 1 - mov ebx, [esp+12+16] ;ebx = row 2 - mov ecx, [esp+16+16] ;ecx = row 3 - mov edx, [esp+20+16] ;edx = row 4 - mov edi, [esp+28+16] ;edi = coefficient ptr - - add eax, esi - add ebx, esi - add ecx, esi - add edx, esi - add ebp, esi - neg esi - - movq mm4,[edi] - movq mm5,[edi+8] - movq mm6,[x0000200000002000] - pxor mm7,mm7 - - movd mm2,dword [eax+esi] - movd mm1,dword [ebx+esi] ;mm1 = pixel1 - punpcklbw mm2,mm7 - jmp short ccint_col_loop_MMX.entry - - align 16 -ccint_col_loop_MMX: - movd mm2,dword [eax+esi] ;mm2 = pixel0 - packuswb mm0,mm0 - - movd mm1,dword [ebx+esi] ;mm1 = pixel1 - pxor mm7,mm7 - - movd dword [ebp+esi-4],mm0 - punpcklbw mm2,mm7 - -ccint_col_loop_MMX.entry: - punpcklbw mm1,mm7 - movq mm0,mm2 - - movd mm3,dword [edx+esi] ;mm3 = pixel3 - punpcklwd mm0,mm1 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm0,mm4 - punpckhwd mm2,mm1 ;mm2 = [a1][a0][r1][r0] - - movd mm1,dword [ecx+esi] ;mm1 = pixel2 - punpcklbw mm3,mm7 - - pmaddwd mm2,mm4 - punpcklbw mm1,mm7 - - movq mm7,mm1 - punpcklwd mm1,mm3 ;mm1 = [g3][g2][b3][b2] - - punpckhwd mm7,mm3 ;mm7 = [a3][a2][r3][r2] - pmaddwd mm1,mm5 - - pmaddwd mm7,mm5 - paddd mm0,mm6 - - paddd mm2,mm6 - paddd mm0,mm1 - - paddd mm2,mm7 - psrad mm0,14 - - psrad mm2,14 - add esi,4 - - packssdw mm0,mm2 - jne ccint_col_loop_MMX - - packuswb mm0,mm0 - movd dword [ebp-4],mm0 - - pop ebp - pop edi - pop esi - pop ebx - ret - -;-------------------------------------------------------------------------- -;vdasm_resize_ccint_col_SSE2(dst, src1, src2, src3, src4, count, tbl); - - global _vdasm_resize_ccint_col_SSE2 -_vdasm_resize_ccint_col_SSE2: - push ebx - push esi - push edi - push ebp - - mov ebp,[esp + 4 + 16] ;ebp = dest addr - mov esi,[esp + 24 + 16] ;esi = count - add esi,esi - add esi,esi - - mov eax,[esp + 8 + 16] ;eax = row 1 - mov ebx,[esp + 12 + 16] ;ebx = row 2 - mov ecx,[esp + 16 + 16] ;ecx = row 3 - mov edx,[esp + 20 + 16] ;edx = row 4 - mov edi,[esp + 28 + 16] ;edi = coefficient ptr - - neg esi - - add esi,4 - jz ccint_col_SSE2_odd - - movq xmm4,qword [edi] - movq xmm5,qword [edi+8] - punpcklqdq xmm4,xmm4 - punpcklqdq xmm5,xmm5 - movq xmm6,[x0000200000002000] - punpcklqdq xmm6,xmm6 - pxor xmm7,xmm7 - -; jmp short ccint_col_loop_SSE2.entry - -; align 16 -ccint_col_loop_SSE2: - movq xmm0, qword [eax] - add eax, 8 - movq xmm1, qword [ebx] - add ebx, 8 - movq xmm2, qword [ecx] - add ecx, 8 - movq xmm3, qword [edx] - add edx, 8 - punpcklbw xmm0,xmm1 - punpcklbw xmm2,xmm3 - movdqa xmm1,xmm0 - movdqa xmm3,xmm2 - punpcklbw xmm0,xmm7 - punpckhbw xmm1,xmm7 - punpcklbw xmm2,xmm7 - punpckhbw xmm3,xmm7 - pmaddwd xmm0,xmm4 - pmaddwd xmm1,xmm4 - pmaddwd xmm2,xmm5 - pmaddwd xmm3,xmm5 - paddd xmm0,xmm6 - paddd xmm1,xmm6 - paddd xmm0,xmm2 - paddd xmm1,xmm3 - psrad xmm0,14 - psrad xmm1,14 - packssdw xmm0,xmm1 - packuswb xmm0,xmm0 - movdq2q mm0,xmm0 - movntq [ebp],mm0 - add ebp,8 - add esi,8 - jnc ccint_col_loop_SSE2 - jnz ccint_col_SSE2_noodd -ccint_col_SSE2_odd: - movd mm0, dword [eax] - pxor mm7,mm7 - movd mm1, dword [ebx] - movdq2q mm4,xmm4 - movd mm2, dword [ecx] - movdq2q mm5,xmm5 - movd mm3, dword [edx] - movdq2q mm6,xmm6 - punpcklbw mm0,mm1 - punpcklbw mm2,mm3 - movq mm1,mm0 - movq mm3,mm2 - punpcklbw mm0,mm7 - punpckhbw mm1,mm7 - punpcklbw mm2,mm7 - punpckhbw mm3,mm7 - pmaddwd mm0,mm4 - pmaddwd mm1,mm4 - pmaddwd mm2,mm5 - pmaddwd mm3,mm5 - paddd mm0,mm6 - paddd mm2,mm6 - paddd mm0,mm2 - paddd mm1,mm3 - psrad mm0,14 - psrad mm1,14 - packssdw mm0,mm1 - packuswb mm0,mm0 - movd eax,mm0 - movnti [ebp],eax - -ccint_col_SSE2_noodd: - pop ebp - pop edi - pop esi - pop ebx - ret - - - -;------------------------------------------------------------------------- -; -; long resize_table_row_MMX(Pixel *out, Pixel *in, int *filter, int filter_width, PixDim w, long accum, long frac); - - .code - - global _vdasm_resize_table_row_MMX -_vdasm_resize_table_row_MMX: - push ebp - push esi - push edi - push ebx - - cmp dword [esp+16+16], 4 - jz .accel_4coeff - cmp dword [esp+16+16], 6 - jz .accel_6coeff - cmp dword [esp+16+16], 8 - jz .accel_8coeff - - mov eax,[esp + 24 + 16] - mov ebp,[esp + 20 + 16] - mov ebx,[esp + 8 + 16] - mov edi,[esp + 4 + 16] - - mov esi,eax - mov edx,eax - - pxor mm5,mm5 - - mov ecx,[esp + 16 + 16] - shr ecx,1 - mov [esp+16+16],ecx - test ecx,1 - jnz .pixelloop_odd_pairs - -.pixelloop_even_pairs: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - mov ecx,[esp + 16 + 16] - shr edx,5 - add esi,ebx - imul edx,ecx - add eax,[esp + 28 + 16] - add edx,[esp + 12 + 16] - - movq mm6,[MMX_roundval] - pxor mm3,mm3 - movq mm7,mm6 - pxor mm2,mm2 - -.coeffloop_unaligned_even_pairs: - movd mm0,dword [esi+0] - paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) - - punpcklbw mm0,[esi+4] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) - - movd mm2,dword [esi+8] - movq mm1,mm0 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm7,mm0 ;accumulate alpha/red (pixels 0/1) - - paddd mm6,mm1 ;accumulate green/blue (pixels 0/1) - add edx,16 - - add esi,16 - sub ecx,2 - - jne .coeffloop_unaligned_even_pairs - - paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) - - psrad mm7,14 - psrad mm6,14 - - packssdw mm6,mm7 - add edi,4 - - packuswb mm6,mm6 - sub ebp,1 - - mov esi,eax - mov edx,eax - - movd dword [edi-4],mm6 - jne .pixelloop_even_pairs - - pop ebx - pop edi - pop esi - pop ebp - - ret - -;---------------------------------------------------------------- - -.pixelloop_odd_pairs: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - mov ecx,[esp + 16 + 16] - shr edx,5 - add esi,ebx - imul edx,ecx - add eax,[esp + 28 + 16] - sub ecx,1 - add edx,[esp + 12 + 16] - - movq mm6,[MMX_roundval] - pxor mm3,mm3 - pxor mm2,mm2 - movq mm7,mm6 - -.coeffloop_unaligned_odd_pairs: - movd mm0,dword [esi+0] - paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) - - punpcklbw mm0,[esi+4] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) - - movd mm2,dword [esi+8] - movq mm1,mm0 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm7,mm0 ;accumulate alpha/red (pixels 0/1) - - paddd mm6,mm1 ;accumulate green/blue (pixels 0/1) - add edx,16 - - add esi,16 - sub ecx,2 - - jne .coeffloop_unaligned_odd_pairs - - paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) - - ;finish up odd pair - - movd mm0,dword [esi] ;mm0 = [x1][r1][g1][b1] - punpcklbw mm0,[esi+4] ;mm2 = [x0][x1][r0][r1][g0][g1][b0][b1] - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g0][g1][b0][b1] - punpckhbw mm1,mm5 ;mm1 = [x0][x1][r0][r1] - - pmaddwd mm0,[edx] - pmaddwd mm1,[edx] - - paddd mm6,mm0 - paddd mm7,mm1 - - ;combine into pixel - - psrad mm6,14 - - psrad mm7,14 - - packssdw mm6,mm7 - add edi,4 - - packuswb mm6,mm6 - sub ebp,1 - - mov esi,eax - mov edx,eax - - movd dword [edi-4],mm6 - jne .pixelloop_odd_pairs - - pop ebx - pop edi - pop esi - pop ebp - - ret - -;---------------------------------------------------------------- - -.accel_4coeff: - mov eax,[esp + 24 + 16] - mov ebp,[esp + 20 + 16] - add ebp,ebp - add ebp,ebp - mov ebx,[esp + 8 + 16] - mov edi,[esp + 4 + 16] - add edi,ebp - neg ebp - - mov esi,eax - mov edx,eax - - movq mm4,[MMX_roundval] - pxor mm5,mm5 - - mov ecx,[esp+12+16] - -.pixelloop_4coeff: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - shr edx,4 - add esi,ebx - add eax,[esp+28+16] - add edx,ecx - - movd mm0,dword [esi+0] - movd mm2,dword [esi+8] - punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) - - paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) - - psrad mm0,14 - psrad mm1,14 - - packssdw mm1,mm0 - mov esi,eax - - packuswb mm1,mm1 - mov edx,eax - - movd dword [edi+ebp],mm1 - add ebp,4 - jne .pixelloop_4coeff - - pop ebx - pop edi - pop esi - pop ebp - - ret - - -;---------------------------------------------------------------- - -.accel_6coeff: - mov eax,[esp + 24 + 16] - mov ebp,[esp + 20 + 16] - add ebp,ebp - add ebp,ebp - mov ebx,[esp + 8 + 16] - mov edi,[esp + 4 + 16] - add edi,ebp - neg ebp - - mov esi,eax - mov edx,eax - - movq mm4,[MMX_roundval] - pxor mm5,mm5 - - mov ecx,[esp+12+16] - -.pixelloop_6coeff: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - shr edx,5 - lea edx,[edx+edx*2] - add esi,ebx - add eax,[esp+28+16] - add edx,ecx - - movd mm0,dword [esi+0] - movd mm2,dword [esi+8] - punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) - - paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) - - movd mm6,dword [esi+16] - - punpcklbw mm6,[esi+20] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - movq mm7,mm6 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm6,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - - pmaddwd mm6,[edx+16] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm7,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm7,[edx+16] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - paddd mm0,mm6 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm7 ;accumulate green/blue (pixels 0/1) - - - psrad mm0,14 - psrad mm1,14 - - packssdw mm1,mm0 - mov esi,eax - - packuswb mm1,mm1 - mov edx,eax - - movd dword [edi+ebp],mm1 - add ebp,4 - jne .pixelloop_6coeff - - pop ebx - pop edi - pop esi - pop ebp - - ret - -;---------------------------------------------------------------- - -.accel_8coeff: - mov eax,[esp + 24 + 16] - mov ebp,[esp + 20 + 16] - add ebp,ebp - add ebp,ebp - mov ebx,[esp + 8 + 16] - mov edi,[esp + 4 + 16] - add edi,ebp - neg ebp - - mov esi,eax - mov edx,eax - - movq mm4,[MMX_roundval] - pxor mm5,mm5 - - mov ecx,[esp+12+16] - -.pixelloop_8coeff: - shr esi,14 - and edx,0000ff00h - and esi,byte -4 - - shr edx,3 - add esi,ebx - add eax,[esp+28+16] - add edx,ecx - - movd mm0,dword [esi+0] - movd mm2,dword [esi+8] - punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - - pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) - - paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) - paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) - - - movd mm6,dword [esi+16] - - punpcklbw mm6,[esi+20] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] - - movd mm2,dword [esi+24] - - punpcklbw mm2,[esi+28] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] - movq mm7,mm6 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] - - punpckhbw mm6,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] - movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] - - pmaddwd mm6,[edx+16] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] - punpcklbw mm7,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] - - pmaddwd mm7,[edx+16] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] - punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] - - pmaddwd mm2,[edx+24] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] - punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] - - pmaddwd mm3,[edx+24] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] - paddd mm0,mm6 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm7 ;accumulate green/blue (pixels 0/1) - paddd mm0,mm2 ;accumulate alpha/red (pixels 0/1) - - paddd mm1,mm3 ;accumulate green/blue (pixels 0/1) - - - psrad mm0,14 - psrad mm1,14 - - packssdw mm1,mm0 - mov esi,eax - - packuswb mm1,mm1 - mov edx,eax - - movd dword [edi+ebp],mm1 - add ebp,4 - jne .pixelloop_8coeff - - pop ebx - pop edi - pop esi - pop ebp - - ret - - - - - - - -;------------------------------------------------------------------------- -; -; long resize_table_col_MMX(Pixel *out, Pixel **in_table, int *filter, int filter_width, PixDim w, long frac); - - global _vdasm_resize_table_col_MMX -_vdasm_resize_table_col_MMX: - push ebp - push esi - push edi - push ebx - - mov edx,[esp + 12 + 16] - mov eax,[esp + 24 + 16] - shl eax,2 - imul eax,[esp + 16 + 16] - add edx,eax - mov [esp + 12 + 16], edx ;[esp+12+28] = filter pointer - - mov ebp,[esp + 20 + 16] ;ebp = pixel counter - mov edi,[esp + 4 + 16] ;edi = destination pointer - - pxor mm5,mm5 - - cmp dword [esp+16+16], 4 - jz .accel_4coeff - cmp dword [esp+16+16], 6 - jz .accel_6coeff - - mov ecx,[esp + 16 + 16] - shr ecx,1 - mov [esp + 16 + 16],ecx ;ecx = filter pair count - - xor ebx,ebx ;ebx = source offset - - mov ecx,[esp + 16 + 16] ;ecx = filter width counter -.pixelloop: - mov eax,[esp + 8 + 16] ;esi = row pointer table - movq mm6,[MMX_roundval] - movq mm7,mm6 - pxor mm0,mm0 - pxor mm1,mm1 -.coeffloop: - mov esi,[eax] - paddd mm6,mm0 - - movd mm0,dword [esi+ebx] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - paddd mm7,mm1 - - mov esi,[eax+4] - add eax,8 - - movd mm1,dword [esi+ebx] ;mm1 = [0][0][0][0][x1][r1][g1][b1] - punpcklbw mm0,mm1 ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm0,[edx] - punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] - - pmaddwd mm1,[edx] - add edx,8 - - sub ecx,1 - jne .coeffloop - - paddd mm6,mm0 - paddd mm7,mm1 - - psrad mm6,14 - psrad mm7,14 - add edi,4 - packssdw mm6,mm7 - add ebx,4 - packuswb mm6,mm6 - sub ebp,1 - - mov ecx,[esp + 16 + 16] ;ecx = filter width counter - mov edx,[esp + 12 + 16] ;edx = filter bank pointer - - movd dword [edi-4],mm6 - jne .pixelloop - -.xit: - pop ebx - pop edi - pop esi - pop ebp - ret - - - -.accel_4coeff: - movq mm2,[edx] - movq mm3,[edx+8] - - mov esi,[esp+8+16] ;esi = row pointer table - mov eax,[esi] - add ebp,ebp - mov ebx,[esi+4] - add ebp,ebp - mov ecx,[esi+8] - mov esi,[esi+12] - add eax,ebp - add ebx,ebp - add ecx,ebp - add esi,ebp - add edi,ebp - neg ebp - - ;EAX source 0 - ;EBX source 1 - ;ECX source 2 - ;ESI source 3 - ;EDI destination - ;EBP counter - - movq mm4,[MMX_roundval] - -.pixelloop4: - movd mm6,dword [eax+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - - punpcklbw mm6,[ebx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - - movq mm7,mm6 - punpcklbw mm6,mm5 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm6,mm2 - punpckhbw mm7,mm5 ;mm1 = [x1][x0][r1][r0] - - movd mm0,dword [ecx+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - pmaddwd mm7,mm2 - - punpcklbw mm0,[esi+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - paddd mm6,mm4 - - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm0,mm3 - punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] - - pmaddwd mm1,mm3 - paddd mm7,mm4 - - paddd mm6,mm0 - paddd mm7,mm1 - - psrad mm6,14 - psrad mm7,14 - packssdw mm6,mm7 - packuswb mm6,mm6 - - movd dword [edi+ebp],mm6 - - add ebp,4 - jne .pixelloop4 - jmp .xit - -.accel_6coeff: - movq mm2,[edx] - movq mm3,[edx+8] - movq mm4,[edx+16] - - push 0 - push dword [fs:0] - mov dword [fs:0],esp - - mov esp,[esp+8+24] ;esp = row pointer table - mov eax,[esp] - add ebp,ebp - mov ebx,[esp+4] - add ebp,ebp - mov ecx,[esp+8] - mov edx,[esp+12] - mov esi,[esp+16] - mov esp,[esp+20] - add eax,ebp - add ebx,ebp - add ecx,ebp - add edx,ebp - add esi,ebp - add edi,ebp - add esp,ebp - neg ebp - - ;EAX source 0 - ;EBX source 1 - ;ECX source 2 - ;EDX source 3 - ;ESI source 4 - ;EDI destination - ;ESP source 5 - ;EBP counter - -.pixelloop6: - movd mm6,dword [eax+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - - punpcklbw mm6,[ebx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - - movq mm7,mm6 - punpcklbw mm6,mm5 ;mm0 = [g1][g0][b1][b0] - - movd mm0,dword [ecx+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - punpckhbw mm7,mm5 ;mm1 = [x1][x0][r1][r0] - - punpcklbw mm0,[edx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - pmaddwd mm6,mm2 - - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] - - pmaddwd mm7,mm2 - punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] - - paddd mm6,[MMX_roundval] - pmaddwd mm0,mm3 - - paddd mm7,[MMX_roundval] - pmaddwd mm1,mm3 - - paddd mm6,mm0 - - movd mm0,dword [esi+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] - paddd mm7,mm1 - - punpcklbw mm0,[esp+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] - movq mm1,mm0 - punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] - punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] - pmaddwd mm0,mm4 - pmaddwd mm1,mm4 - paddd mm6,mm0 - paddd mm7,mm1 - - psrad mm6,14 - psrad mm7,14 - packssdw mm6,mm7 - packuswb mm6,mm6 - - movd dword [edi+ebp],mm6 - - add ebp,4 - jne .pixelloop6 - - mov esp, dword [fs:0] - pop dword [fs:0] - pop eax - - jmp .xit - - - global _vdasm_resize_table_col_SSE2 -_vdasm_resize_table_col_SSE2: - push ebp - push esi - push edi - push ebx - - mov edx,[esp+12+16] - mov eax,[esp+24+16] - shl eax,2 - imul eax,[esp+16+16] - add edx,eax - mov [esp+12+16], edx ;[esp+12+16] = filter pointer - - mov ebp,[esp+20+16] ;ebp = pixel counter - mov edi,[esp+4+16] ;edi = destination pointer - - pxor xmm7, xmm7 - movdqa xmm6, [MMX_roundval] - - cmp dword [esp+16+16], 4 - jz .accel_4coeff - cmp dword [esp+16+16], 6 - jz .accel_6coeff - - mov ecx,[esp+16+16] - shr ecx,1 - mov [esp+16+16],ecx ;ecx = filter pair count - - xor ebx,ebx ;ebx = source offset - - mov ecx,[esp+16+16] ;ecx = filter width counter -.pixelloop: - mov eax, [esp+8+16] ;esi = row pointer table - movdqa xmm4, xmm6 -.coeffloop: - mov esi,[eax] - - movd xmm0, dword [esi+ebx] - - mov esi,[eax+4] - add eax,8 - - movd xmm1, dword [esi+ebx] - punpcklbw xmm0, xmm1 - - punpcklbw xmm0, xmm7 - - movq xmm2, qword [edx] - pshufd xmm2, xmm2, 01000100b - - pmaddwd xmm0, xmm2 - - paddd xmm4, xmm0 - - add edx,8 - - sub ecx,1 - jne .coeffloop - - psrad xmm4,14 - add edi,4 - packssdw xmm4,xmm4 - add ebx,4 - packuswb xmm4,xmm4 - sub ebp,1 - - mov ecx,[esp+16+16] ;ecx = filter width counter - mov edx,[esp+12+16] ;edx = filter bank pointer - - movd dword [edi-4],xmm4 - jne .pixelloop - -.xit: - pop ebx - pop edi - pop esi - pop ebp - ret - -.accel_4coeff: - shl ebp, 2 - mov eax, [esp+8+16] ;eax = row pointer table - mov esi, [eax+12] - mov ecx, [eax+8] - mov ebx, [eax+4] - mov eax, [eax] - lea edi, [edi+ebp-4] - neg ebp - - ;registers: - ; - ;EAX source 0 - ;EBX source 1 - ;ECX source 2 - ;ESI source 3 - ;EDI destination - ;EBP counter - ; - movq xmm4, qword [edx] ;xmm4 = coeff 0/1 - movq xmm5, qword [edx+8] ;xmm5 = coeff 2/3 - punpcklqdq xmm4, xmm4 - punpcklqdq xmm5, xmm5 - - add ebp, 4 - jz .oddpixel_4coeff - -.pixelloop_4coeff_dualpel: - movq xmm0, qword [eax] - movq xmm1, qword [ebx] - movq xmm2, qword [ecx] - movq xmm3, qword [esi] - add eax,8 - add ebx,8 - add ecx,8 - add esi,8 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - punpcklbw xmm0, xmm7 - punpckhbw xmm1, xmm7 - punpcklbw xmm2, xmm7 - punpckhbw xmm3, xmm7 - pmaddwd xmm0, xmm4 - pmaddwd xmm1, xmm4 - pmaddwd xmm2, xmm5 - pmaddwd xmm3, xmm5 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - paddd xmm0, xmm6 - paddd xmm1, xmm6 - psrad xmm0, 14 - psrad xmm1, 14 - packssdw xmm0, xmm1 - packuswb xmm0, xmm0 - movq qword [edi+ebp],xmm0 - add ebp, 8 - jae .pixelloop_4coeff_dualpel - jnz .xit - -.oddpixel_4coeff: - movd xmm0, dword [eax] - movd xmm1, dword [ebx] - movd xmm2, dword [ecx] - movd xmm3, dword [esi] - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - punpcklbw xmm0, xmm7 - punpcklbw xmm2, xmm7 - pmaddwd xmm0, xmm4 - pmaddwd xmm2, xmm5 - paddd xmm0, xmm2 - paddd xmm0, xmm6 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd dword [edi],xmm0 - jmp .xit - - -.accel_6coeff: - movq xmm4, qword [edx] ;xmm4 = coeff 0/1 - movq xmm5, qword [edx+8] ;xmm5 = coeff 2/3 - movq xmm6, qword [edx+16] ;xmm5 = coeff 4/5 - punpcklqdq xmm4, xmm4 - punpcklqdq xmm5, xmm5 - punpcklqdq xmm6, xmm6 - - push 0 - push dword [fs:0] - mov dword [fs:0],esp - - shl ebp, 2 - mov eax, [esp+8+24] ;eax = row pointer table - mov esp, [eax+20] - mov esi, [eax+16] - mov edx, [eax+12] - mov ecx, [eax+8] - mov ebx, [eax+4] - mov eax, [eax] - lea edi, [edi+ebp-4] - neg ebp - - ;registers: - ; - ;EAX source 0 - ;EBX source 1 - ;ECX source 2 - ;EDX source 3 - ;ESI source 4 - ;EDI destination - ;ESP source 5 - ;EBP counter - ; - - add ebp, 4 - jz .oddpixel_6coeff - -.pixelloop_6coeff_dualpel: - movq xmm0, qword [eax] - movq xmm1, qword [ebx] - movq xmm2, qword [ecx] - movq xmm3, qword [edx] - add eax,8 - add ebx,8 - add ecx,8 - add edx,8 - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - movdqa xmm1, xmm0 - movdqa xmm3, xmm2 - punpcklbw xmm0, xmm7 - punpckhbw xmm1, xmm7 - punpcklbw xmm2, xmm7 - punpckhbw xmm3, xmm7 - pmaddwd xmm0, xmm4 - pmaddwd xmm1, xmm4 - pmaddwd xmm2, xmm5 - pmaddwd xmm3, xmm5 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - - movq xmm2, qword [esi] - movq xmm3, qword [esp] - add esi, 8 - add esp, 8 - punpcklbw xmm2, xmm3 - movdqa xmm3, xmm2 - punpcklbw xmm2, xmm7 - punpckhbw xmm3, xmm7 - pmaddwd xmm2, xmm6 - pmaddwd xmm3, xmm6 - paddd xmm0, xmm2 - paddd xmm1, xmm3 - paddd xmm0, [MMX_roundval] - paddd xmm1, [MMX_roundval] - psrad xmm0, 14 - psrad xmm1, 14 - packssdw xmm0, xmm1 - packuswb xmm0, xmm0 - movq qword [edi+ebp],xmm0 - add ebp, 8 - jae .pixelloop_6coeff_dualpel - jnz .xit_6coeff - -.oddpixel_6coeff: - movd xmm0, dword [eax] - movd xmm1, dword [ebx] - movd xmm2, dword [ecx] - movd xmm3, dword [edx] - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - movd xmm1, dword [esi] - movd xmm3, dword [esp] - punpcklbw xmm0, xmm7 - punpcklbw xmm2, xmm7 - pmaddwd xmm0, xmm4 - punpcklbw xmm1, xmm3 - pmaddwd xmm2, xmm5 - punpcklbw xmm1, xmm7 - pmaddwd xmm1, xmm6 - paddd xmm0, xmm2 - paddd xmm1, [MMX_roundval] - paddd xmm0, xmm1 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd dword [edi],xmm0 - -.xit_6coeff: - mov esp, dword [fs:0] - pop dword [fs:0] - pop eax - jmp .xit - - - end +; VirtualDub - Video processing and capture application +; Graphics support library +; Copyright (C) 1998-2004 Avery Lee +; +; This program 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 2 of the License, or +; (at your option) any later version. +; +; This program 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, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +; + section .rdata, rdata, align=16 + +x0002000200020002 dq 0002000200020002h +x0004000400040004 dq 0004000400040004h +x0008000800080008 dq 0008000800080008h +x0000200000002000 dq 0000200000002000h + + align 16 +MMX_roundval dq 0000200000002000h, 0000200000002000h + + +;************************************************************************** + +x0000FFFF0000FFFF dq 0000FFFF0000FFFFh +x0000010100000101 dq 0000010100000101h +x0100010001000100 dq 0100010001000100h + + section .text + +;-------------------------------------------------------------------------- +;_vdasm_resize_interp_row_run_MMX( +; [esp+ 4] void *dst, +; [esp+ 8] void *src, +; [esp+12] ulong width, +; [esp+16] __int64 xaccum, +; [esp+24] __int64 x_inc); +; + global _vdasm_resize_interp_row_run_MMX +_vdasm_resize_interp_row_run_MMX: + push ebp + push edi + push esi + push ebx + + mov esi, [esp+8+16] + mov edi, [esp+4+16] + mov ebp, [esp+12+16] + + movd mm4, dword [esp+16+16] + pxor mm7, mm7 + movd mm6, dword [esp+24+16] + punpckldq mm4, mm4 + punpckldq mm6, mm6 + + shr esi, 2 + + mov eax, [esp+16+16] + mov ebx, [esp+20+16] + add esi, ebx + mov ebx, [esp+24+16] + mov ecx, [esp+28+16] + + shl ebp,2 + add edi,ebp + neg ebp + +.colloop: + movd mm1, dword [esi*4+4] + movq mm5, mm4 + + movd mm0, dword [esi*4] + punpcklbw mm1, mm7 + + punpcklbw mm0, mm7 + psrld mm5, 24 + + movq mm3, [x0100010001000100] + packssdw mm5, mm5 + + pmullw mm1, mm5 + psubw mm3, mm5 + + pmullw mm0, mm3 + paddd mm4, mm6 + + ;stall + ;stall + + ;stall + ;stall + + paddw mm0, mm1 + + psrlw mm0, 8 + add eax, ebx + + adc esi, ecx + packuswb mm0, mm0 + + movd dword [edi+ebp],mm0 + + add ebp, 4 + jnz .colloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + +;************************************************************************** + +;vdasm_resize_interp_col_run_MMX( +; [esp+ 4] void *dst, +; [esp+ 8] void *src1, +; [esp+12] void *src2, +; [esp+16] ulong width, +; [esp+20] ulong yaccum); + + + global _vdasm_resize_interp_col_run_MMX +_vdasm_resize_interp_col_run_MMX: + push ebp + push edi + push esi + push ebx + + mov esi, [esp+8+16] + mov edx, [esp+12+16] + mov edi, [esp+4+16] + mov ebp, [esp+16+16] + + movd mm4, dword [esp+20+16] + pxor mm7, mm7 + punpcklwd mm4, mm4 + punpckldq mm4, mm4 + psrlw mm4, 8 + pxor mm4, [x0000FFFF0000FFFF] + paddw mm4, [x0000010100000101] + + shl ebp, 2 + add edi, ebp + add esi, ebp + add edx, ebp + neg ebp + +.colloop: + movd mm0, dword [esi+ebp] + movd mm2, dword [edx+ebp] + + punpcklbw mm0, mm7 + punpcklbw mm2, mm7 + + movq mm1, mm0 + punpcklwd mm0, mm2 + punpckhwd mm1, mm2 + + pmaddwd mm0, mm4 + pmaddwd mm1, mm4 + + psrad mm0, 8 + psrad mm1, 8 + + packssdw mm0, mm1 + packuswb mm0, mm0 + + movd dword [edi+ebp],mm0 + + add ebp, 4 + jnz .colloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + +;-------------------------------------------------------------------------- +;vdasm_resize_ccint_row_MMX(dst, src, count, xaccum, xinc, tbl); + + global _vdasm_resize_ccint_row_MMX +_vdasm_resize_ccint_row_MMX: + push ebx + push esi + push edi + push ebp + + mov ebx, [esp+4+16] ;ebx = dest addr + mov ecx, [esp+12+16] ;ecx = count + + mov ebp, [esp+20+16] ;ebp = increment + mov edi, ebp ;edi = increment + shl ebp, 16 ;ebp = fractional increment + mov esi, [esp+16+16] ;esi = 16:16 position + sar edi, 16 ;edi = integer increment + mov [esp+20+16], ebp ;xinc = fractional increment + mov ebp, esi ;ebp = 16:16 position + shr esi, 16 ;esi = integer position + shl ebp, 16 ;ebp = fraction + mov [esp+16+16], ebp ;xaccum = fraction + + mov eax, [esp+8+16] + + shr ebp, 24 ;ebp = fraction (0...255) + mov [esp+8+16], edi + shl ebp, 4 ;ebp = fraction*16 + mov edi, ebp + mov ebp, [esp+4+16] ;ebp = destination + + shr eax, 2 + add eax, esi + shl ecx, 2 ;ecx = count*4 + lea ebp, [ebp+ecx-4] + neg ecx ;ecx = -count*4 + + movq mm6, [x0000200000002000] + pxor mm7, mm7 + + mov edx,[esp+16+16] ;edx = fractional accumulator + mov esi,[esp+20+16] ;esi = fractional increment + + mov ebx,[esp+24+16] ;ebx = coefficient pointer + + movd mm0,dword [eax*4] + movd mm1,dword [eax*4+4] + punpcklbw mm0,mm7 ;mm0 = [a1][r1][g1][b1] + + ;borrow stack pointer + push 0 ;don't crash + push dword [fs:0] + mov dword [fs:0], esp + mov esp, [esp+8+24] ;esp = integer increment + jmp short ccint_loop_MMX_start + + ;EAX source pointer / 4 + ;EBX coefficient pointer + ;ECX count + ;EDX fractional accumulator + ;ESI fractional increment + ;EDI coefficient offset + ;ESP integer increment + ;EBP destination pointer + + align 16 +ccint_loop_MMX: + movd mm0,dword [eax*4] + packuswb mm2,mm2 ;mm0 = [a][r][g][b][a][r][g][b] + + movd mm1,dword [eax*4+4] + punpcklbw mm0,mm7 ;mm0 = [a1][r1][g1][b1] + + movd dword [ebp+ecx],mm2 +ccint_loop_MMX_start: + movq mm4,mm0 ;mm0 = [a1][r1][g1][b1] + + movd mm2,dword [eax*4+8] + punpcklbw mm1,mm7 ;mm1 = [a2][r2][g2][b2] + + movd mm3,dword [eax*4+12] + punpcklbw mm2,mm7 ;mm2 = [a3][r3][g3][b3] + + punpcklbw mm3,mm7 ;mm3 = [a4][r4][g4][b4] + movq mm5,mm2 ;mm2 = [a3][r3][g3][b3] + + add edx,esi ;add fractional increment + punpcklwd mm0,mm1 ;mm0 = [g2][g1][b2][b1] + + pmaddwd mm0,[ebx+edi] + punpcklwd mm2,mm3 ;mm2 = [g4][g3][b4][b3] + + pmaddwd mm2,[ebx+edi+8] + punpckhwd mm4,mm1 ;mm4 = [a2][a1][r2][r1] + + pmaddwd mm4,[ebx+edi] + punpckhwd mm5,mm3 ;mm5 = [a4][a3][b4][b3] + + pmaddwd mm5,[ebx+edi+8] + paddd mm0,mm6 + + adc eax,esp ;add integer increment and fractional bump to offset + mov edi,0ff000000h + + paddd mm2,mm0 ;mm0 = [ g ][ b ] + paddd mm4,mm6 + + psrad mm2,14 + paddd mm4,mm5 ;mm4 = [ a ][ r ] + + and edi,edx + psrad mm4,14 + + shr edi,20 ;edi = fraction (0...255)*16 + add ecx,4 + + packssdw mm2,mm4 ;mm0 = [ a ][ r ][ g ][ b ] + jnc ccint_loop_MMX + + packuswb mm2,mm2 ;mm0 = [a][r][g][b][a][r][g][b] + movd dword [ebp],mm2 + + mov esp, dword [fs:0] + pop dword [fs:0] + pop eax + + pop ebp + pop edi + pop esi + pop ebx + ret + +;-------------------------------------------------------------------------- +;vdasm_resize_ccint_col_MMX(dst, src1, src2, src3, src4, count, tbl); + + global _vdasm_resize_ccint_col_MMX +_vdasm_resize_ccint_col_MMX: + push ebx + push esi + push edi + push ebp + + mov ebp, [esp+4+16] ;ebp = dest addr + mov esi, [esp+24+16] ;esi = count + add esi, esi + add esi, esi + + mov eax, [esp+8+16] ;eax = row 1 + mov ebx, [esp+12+16] ;ebx = row 2 + mov ecx, [esp+16+16] ;ecx = row 3 + mov edx, [esp+20+16] ;edx = row 4 + mov edi, [esp+28+16] ;edi = coefficient ptr + + add eax, esi + add ebx, esi + add ecx, esi + add edx, esi + add ebp, esi + neg esi + + movq mm4,[edi] + movq mm5,[edi+8] + movq mm6,[x0000200000002000] + pxor mm7,mm7 + + movd mm2,dword [eax+esi] + movd mm1,dword [ebx+esi] ;mm1 = pixel1 + punpcklbw mm2,mm7 + jmp short ccint_col_loop_MMX.entry + + align 16 +ccint_col_loop_MMX: + movd mm2,dword [eax+esi] ;mm2 = pixel0 + packuswb mm0,mm0 + + movd mm1,dword [ebx+esi] ;mm1 = pixel1 + pxor mm7,mm7 + + movd dword [ebp+esi-4],mm0 + punpcklbw mm2,mm7 + +ccint_col_loop_MMX.entry: + punpcklbw mm1,mm7 + movq mm0,mm2 + + movd mm3,dword [edx+esi] ;mm3 = pixel3 + punpcklwd mm0,mm1 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm0,mm4 + punpckhwd mm2,mm1 ;mm2 = [a1][a0][r1][r0] + + movd mm1,dword [ecx+esi] ;mm1 = pixel2 + punpcklbw mm3,mm7 + + pmaddwd mm2,mm4 + punpcklbw mm1,mm7 + + movq mm7,mm1 + punpcklwd mm1,mm3 ;mm1 = [g3][g2][b3][b2] + + punpckhwd mm7,mm3 ;mm7 = [a3][a2][r3][r2] + pmaddwd mm1,mm5 + + pmaddwd mm7,mm5 + paddd mm0,mm6 + + paddd mm2,mm6 + paddd mm0,mm1 + + paddd mm2,mm7 + psrad mm0,14 + + psrad mm2,14 + add esi,4 + + packssdw mm0,mm2 + jne ccint_col_loop_MMX + + packuswb mm0,mm0 + movd dword [ebp-4],mm0 + + pop ebp + pop edi + pop esi + pop ebx + ret + +;-------------------------------------------------------------------------- +;vdasm_resize_ccint_col_SSE2(dst, src1, src2, src3, src4, count, tbl); + + global _vdasm_resize_ccint_col_SSE2 +_vdasm_resize_ccint_col_SSE2: + push ebx + push esi + push edi + push ebp + + mov ebp,[esp + 4 + 16] ;ebp = dest addr + mov esi,[esp + 24 + 16] ;esi = count + add esi,esi + add esi,esi + + mov eax,[esp + 8 + 16] ;eax = row 1 + mov ebx,[esp + 12 + 16] ;ebx = row 2 + mov ecx,[esp + 16 + 16] ;ecx = row 3 + mov edx,[esp + 20 + 16] ;edx = row 4 + mov edi,[esp + 28 + 16] ;edi = coefficient ptr + + neg esi + + add esi,4 + jz ccint_col_SSE2_odd + + movq xmm4,qword [edi] + movq xmm5,qword [edi+8] + punpcklqdq xmm4,xmm4 + punpcklqdq xmm5,xmm5 + movq xmm6,[x0000200000002000] + punpcklqdq xmm6,xmm6 + pxor xmm7,xmm7 + +; jmp short ccint_col_loop_SSE2.entry + +; align 16 +ccint_col_loop_SSE2: + movq xmm0, qword [eax] + add eax, 8 + movq xmm1, qword [ebx] + add ebx, 8 + movq xmm2, qword [ecx] + add ecx, 8 + movq xmm3, qword [edx] + add edx, 8 + punpcklbw xmm0,xmm1 + punpcklbw xmm2,xmm3 + movdqa xmm1,xmm0 + movdqa xmm3,xmm2 + punpcklbw xmm0,xmm7 + punpckhbw xmm1,xmm7 + punpcklbw xmm2,xmm7 + punpckhbw xmm3,xmm7 + pmaddwd xmm0,xmm4 + pmaddwd xmm1,xmm4 + pmaddwd xmm2,xmm5 + pmaddwd xmm3,xmm5 + paddd xmm0,xmm6 + paddd xmm1,xmm6 + paddd xmm0,xmm2 + paddd xmm1,xmm3 + psrad xmm0,14 + psrad xmm1,14 + packssdw xmm0,xmm1 + packuswb xmm0,xmm0 + movdq2q mm0,xmm0 + movntq [ebp],mm0 + add ebp,8 + add esi,8 + jnc ccint_col_loop_SSE2 + jnz ccint_col_SSE2_noodd +ccint_col_SSE2_odd: + movd mm0, dword [eax] + pxor mm7,mm7 + movd mm1, dword [ebx] + movdq2q mm4,xmm4 + movd mm2, dword [ecx] + movdq2q mm5,xmm5 + movd mm3, dword [edx] + movdq2q mm6,xmm6 + punpcklbw mm0,mm1 + punpcklbw mm2,mm3 + movq mm1,mm0 + movq mm3,mm2 + punpcklbw mm0,mm7 + punpckhbw mm1,mm7 + punpcklbw mm2,mm7 + punpckhbw mm3,mm7 + pmaddwd mm0,mm4 + pmaddwd mm1,mm4 + pmaddwd mm2,mm5 + pmaddwd mm3,mm5 + paddd mm0,mm6 + paddd mm2,mm6 + paddd mm0,mm2 + paddd mm1,mm3 + psrad mm0,14 + psrad mm1,14 + packssdw mm0,mm1 + packuswb mm0,mm0 + movd eax,mm0 + movnti [ebp],eax + +ccint_col_SSE2_noodd: + pop ebp + pop edi + pop esi + pop ebx + ret + + + +;------------------------------------------------------------------------- +; +; long resize_table_row_MMX(Pixel *out, Pixel *in, int *filter, int filter_width, PixDim w, long accum, long frac); + + .code + + global _vdasm_resize_table_row_MMX +_vdasm_resize_table_row_MMX: + push ebp + push esi + push edi + push ebx + + cmp dword [esp+16+16], 4 + jz .accel_4coeff + cmp dword [esp+16+16], 6 + jz .accel_6coeff + cmp dword [esp+16+16], 8 + jz .accel_8coeff + + mov eax,[esp + 24 + 16] + mov ebp,[esp + 20 + 16] + mov ebx,[esp + 8 + 16] + mov edi,[esp + 4 + 16] + + mov esi,eax + mov edx,eax + + pxor mm5,mm5 + + mov ecx,[esp + 16 + 16] + shr ecx,1 + mov [esp+16+16],ecx + test ecx,1 + jnz .pixelloop_odd_pairs + +.pixelloop_even_pairs: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + mov ecx,[esp + 16 + 16] + shr edx,5 + add esi,ebx + imul edx,ecx + add eax,[esp + 28 + 16] + add edx,[esp + 12 + 16] + + movq mm6,[MMX_roundval] + pxor mm3,mm3 + movq mm7,mm6 + pxor mm2,mm2 + +.coeffloop_unaligned_even_pairs: + movd mm0,dword [esi+0] + paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) + + punpcklbw mm0,[esi+4] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) + + movd mm2,dword [esi+8] + movq mm1,mm0 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm7,mm0 ;accumulate alpha/red (pixels 0/1) + + paddd mm6,mm1 ;accumulate green/blue (pixels 0/1) + add edx,16 + + add esi,16 + sub ecx,2 + + jne .coeffloop_unaligned_even_pairs + + paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) + + psrad mm7,14 + psrad mm6,14 + + packssdw mm6,mm7 + add edi,4 + + packuswb mm6,mm6 + sub ebp,1 + + mov esi,eax + mov edx,eax + + movd dword [edi-4],mm6 + jne .pixelloop_even_pairs + + pop ebx + pop edi + pop esi + pop ebp + + ret + +;---------------------------------------------------------------- + +.pixelloop_odd_pairs: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + mov ecx,[esp + 16 + 16] + shr edx,5 + add esi,ebx + imul edx,ecx + add eax,[esp + 28 + 16] + sub ecx,1 + add edx,[esp + 12 + 16] + + movq mm6,[MMX_roundval] + pxor mm3,mm3 + pxor mm2,mm2 + movq mm7,mm6 + +.coeffloop_unaligned_odd_pairs: + movd mm0,dword [esi+0] + paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) + + punpcklbw mm0,[esi+4] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) + + movd mm2,dword [esi+8] + movq mm1,mm0 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm7,mm0 ;accumulate alpha/red (pixels 0/1) + + paddd mm6,mm1 ;accumulate green/blue (pixels 0/1) + add edx,16 + + add esi,16 + sub ecx,2 + + jne .coeffloop_unaligned_odd_pairs + + paddd mm7,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm6,mm3 ;accumulate green/blue (pixels 2/3) + + ;finish up odd pair + + movd mm0,dword [esi] ;mm0 = [x1][r1][g1][b1] + punpcklbw mm0,[esi+4] ;mm2 = [x0][x1][r0][r1][g0][g1][b0][b1] + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g0][g1][b0][b1] + punpckhbw mm1,mm5 ;mm1 = [x0][x1][r0][r1] + + pmaddwd mm0,[edx] + pmaddwd mm1,[edx] + + paddd mm6,mm0 + paddd mm7,mm1 + + ;combine into pixel + + psrad mm6,14 + + psrad mm7,14 + + packssdw mm6,mm7 + add edi,4 + + packuswb mm6,mm6 + sub ebp,1 + + mov esi,eax + mov edx,eax + + movd dword [edi-4],mm6 + jne .pixelloop_odd_pairs + + pop ebx + pop edi + pop esi + pop ebp + + ret + +;---------------------------------------------------------------- + +.accel_4coeff: + mov eax,[esp + 24 + 16] + mov ebp,[esp + 20 + 16] + add ebp,ebp + add ebp,ebp + mov ebx,[esp + 8 + 16] + mov edi,[esp + 4 + 16] + add edi,ebp + neg ebp + + mov esi,eax + mov edx,eax + + movq mm4,[MMX_roundval] + pxor mm5,mm5 + + mov ecx,[esp+12+16] + +.pixelloop_4coeff: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + shr edx,4 + add esi,ebx + add eax,[esp+28+16] + add edx,ecx + + movd mm0,dword [esi+0] + movd mm2,dword [esi+8] + punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) + + paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) + + psrad mm0,14 + psrad mm1,14 + + packssdw mm1,mm0 + mov esi,eax + + packuswb mm1,mm1 + mov edx,eax + + movd dword [edi+ebp],mm1 + add ebp,4 + jne .pixelloop_4coeff + + pop ebx + pop edi + pop esi + pop ebp + + ret + + +;---------------------------------------------------------------- + +.accel_6coeff: + mov eax,[esp + 24 + 16] + mov ebp,[esp + 20 + 16] + add ebp,ebp + add ebp,ebp + mov ebx,[esp + 8 + 16] + mov edi,[esp + 4 + 16] + add edi,ebp + neg ebp + + mov esi,eax + mov edx,eax + + movq mm4,[MMX_roundval] + pxor mm5,mm5 + + mov ecx,[esp+12+16] + +.pixelloop_6coeff: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + shr edx,5 + lea edx,[edx+edx*2] + add esi,ebx + add eax,[esp+28+16] + add edx,ecx + + movd mm0,dword [esi+0] + movd mm2,dword [esi+8] + punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) + + paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) + + movd mm6,dword [esi+16] + + punpcklbw mm6,[esi+20] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + movq mm7,mm6 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm6,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + + pmaddwd mm6,[edx+16] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm7,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm7,[edx+16] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + paddd mm0,mm6 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm7 ;accumulate green/blue (pixels 0/1) + + + psrad mm0,14 + psrad mm1,14 + + packssdw mm1,mm0 + mov esi,eax + + packuswb mm1,mm1 + mov edx,eax + + movd dword [edi+ebp],mm1 + add ebp,4 + jne .pixelloop_6coeff + + pop ebx + pop edi + pop esi + pop ebp + + ret + +;---------------------------------------------------------------- + +.accel_8coeff: + mov eax,[esp + 24 + 16] + mov ebp,[esp + 20 + 16] + add ebp,ebp + add ebp,ebp + mov ebx,[esp + 8 + 16] + mov edi,[esp + 4 + 16] + add edi,ebp + neg ebp + + mov esi,eax + mov edx,eax + + movq mm4,[MMX_roundval] + pxor mm5,mm5 + + mov ecx,[esp+12+16] + +.pixelloop_8coeff: + shr esi,14 + and edx,0000ff00h + and esi,byte -4 + + shr edx,3 + add esi,ebx + add eax,[esp+28+16] + add edx,ecx + + movd mm0,dword [esi+0] + movd mm2,dword [esi+8] + punpcklbw mm0,[esi+4] ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + movq mm1,mm0 ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm0,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + + pmaddwd mm0,[edx] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm2,[esi+12] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + punpcklbw mm1,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm1,[edx] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+8] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+8] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm0,mm4 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm4 ;accumulate green/blue (pixels 0/1) + + paddd mm0,mm2 ;accumulate alpha/red (pixels 2/3) + paddd mm1,mm3 ;accumulate green/blue (pixels 2/3) + + + movd mm6,dword [esi+16] + + punpcklbw mm6,[esi+20] ;mm1=[a0][a1][r0][r1][g0][g1][b0][b1] + + movd mm2,dword [esi+24] + + punpcklbw mm2,[esi+28] ;mm2=[a2][a3][r2][r3][g2][g3][b2][b3] + movq mm7,mm6 ;mm0=[a0][a1][r0][r1][g0][g1][b0][b1] + + punpckhbw mm6,mm5 ;mm0=[ a0 ][ a1 ][ r0 ][ r1 ] + movq mm3,mm2 ;mm3=[a2][a3][r2][r3][g2][g3][b2][b3] + + pmaddwd mm6,[edx+16] ;mm0=[a0*f0+a1*f1][r0*f0+r1*f1] + punpcklbw mm7,mm5 ;mm1=[ g0 ][ g1 ][ b0 ][ b1 ] + + pmaddwd mm7,[edx+16] ;mm1=[g0*f0+g1*f1][b0*f0+b1*f1] + punpckhbw mm2,mm5 ;mm2=[ a2 ][ a3 ][ r0 ][ r1 ] + + pmaddwd mm2,[edx+24] ;mm2=[a2*f2+a3*f3][r2*f2+r3*f3] + punpcklbw mm3,mm5 ;mm3=[ g2 ][ g3 ][ b2 ][ b3 ] + + pmaddwd mm3,[edx+24] ;mm3=[g2*f2+g3*f3][b2*f2+b3*f3] + paddd mm0,mm6 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm7 ;accumulate green/blue (pixels 0/1) + paddd mm0,mm2 ;accumulate alpha/red (pixels 0/1) + + paddd mm1,mm3 ;accumulate green/blue (pixels 0/1) + + + psrad mm0,14 + psrad mm1,14 + + packssdw mm1,mm0 + mov esi,eax + + packuswb mm1,mm1 + mov edx,eax + + movd dword [edi+ebp],mm1 + add ebp,4 + jne .pixelloop_8coeff + + pop ebx + pop edi + pop esi + pop ebp + + ret + + + + + + + +;------------------------------------------------------------------------- +; +; long resize_table_col_MMX(Pixel *out, Pixel **in_table, int *filter, int filter_width, PixDim w, long frac); + + global _vdasm_resize_table_col_MMX +_vdasm_resize_table_col_MMX: + push ebp + push esi + push edi + push ebx + + mov edx,[esp + 12 + 16] + mov eax,[esp + 24 + 16] + shl eax,2 + imul eax,[esp + 16 + 16] + add edx,eax + mov [esp + 12 + 16], edx ;[esp+12+28] = filter pointer + + mov ebp,[esp + 20 + 16] ;ebp = pixel counter + mov edi,[esp + 4 + 16] ;edi = destination pointer + + pxor mm5,mm5 + + cmp dword [esp+16+16], 4 + jz .accel_4coeff + cmp dword [esp+16+16], 6 + jz .accel_6coeff + + mov ecx,[esp + 16 + 16] + shr ecx,1 + mov [esp + 16 + 16],ecx ;ecx = filter pair count + + xor ebx,ebx ;ebx = source offset + + mov ecx,[esp + 16 + 16] ;ecx = filter width counter +.pixelloop: + mov eax,[esp + 8 + 16] ;esi = row pointer table + movq mm6,[MMX_roundval] + movq mm7,mm6 + pxor mm0,mm0 + pxor mm1,mm1 +.coeffloop: + mov esi,[eax] + paddd mm6,mm0 + + movd mm0,dword [esi+ebx] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + paddd mm7,mm1 + + mov esi,[eax+4] + add eax,8 + + movd mm1,dword [esi+ebx] ;mm1 = [0][0][0][0][x1][r1][g1][b1] + punpcklbw mm0,mm1 ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm0,[edx] + punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] + + pmaddwd mm1,[edx] + add edx,8 + + sub ecx,1 + jne .coeffloop + + paddd mm6,mm0 + paddd mm7,mm1 + + psrad mm6,14 + psrad mm7,14 + add edi,4 + packssdw mm6,mm7 + add ebx,4 + packuswb mm6,mm6 + sub ebp,1 + + mov ecx,[esp + 16 + 16] ;ecx = filter width counter + mov edx,[esp + 12 + 16] ;edx = filter bank pointer + + movd dword [edi-4],mm6 + jne .pixelloop + +.xit: + pop ebx + pop edi + pop esi + pop ebp + ret + + + +.accel_4coeff: + movq mm2,[edx] + movq mm3,[edx+8] + + mov esi,[esp+8+16] ;esi = row pointer table + mov eax,[esi] + add ebp,ebp + mov ebx,[esi+4] + add ebp,ebp + mov ecx,[esi+8] + mov esi,[esi+12] + add eax,ebp + add ebx,ebp + add ecx,ebp + add esi,ebp + add edi,ebp + neg ebp + + ;EAX source 0 + ;EBX source 1 + ;ECX source 2 + ;ESI source 3 + ;EDI destination + ;EBP counter + + movq mm4,[MMX_roundval] + +.pixelloop4: + movd mm6,dword [eax+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + + punpcklbw mm6,[ebx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + + movq mm7,mm6 + punpcklbw mm6,mm5 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm6,mm2 + punpckhbw mm7,mm5 ;mm1 = [x1][x0][r1][r0] + + movd mm0,dword [ecx+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + pmaddwd mm7,mm2 + + punpcklbw mm0,[esi+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + paddd mm6,mm4 + + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm0,mm3 + punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] + + pmaddwd mm1,mm3 + paddd mm7,mm4 + + paddd mm6,mm0 + paddd mm7,mm1 + + psrad mm6,14 + psrad mm7,14 + packssdw mm6,mm7 + packuswb mm6,mm6 + + movd dword [edi+ebp],mm6 + + add ebp,4 + jne .pixelloop4 + jmp .xit + +.accel_6coeff: + movq mm2,[edx] + movq mm3,[edx+8] + movq mm4,[edx+16] + + push 0 + push dword [fs:0] + mov dword [fs:0],esp + + mov esp,[esp+8+24] ;esp = row pointer table + mov eax,[esp] + add ebp,ebp + mov ebx,[esp+4] + add ebp,ebp + mov ecx,[esp+8] + mov edx,[esp+12] + mov esi,[esp+16] + mov esp,[esp+20] + add eax,ebp + add ebx,ebp + add ecx,ebp + add edx,ebp + add esi,ebp + add edi,ebp + add esp,ebp + neg ebp + + ;EAX source 0 + ;EBX source 1 + ;ECX source 2 + ;EDX source 3 + ;ESI source 4 + ;EDI destination + ;ESP source 5 + ;EBP counter + +.pixelloop6: + movd mm6,dword [eax+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + + punpcklbw mm6,[ebx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + + movq mm7,mm6 + punpcklbw mm6,mm5 ;mm0 = [g1][g0][b1][b0] + + movd mm0,dword [ecx+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + punpckhbw mm7,mm5 ;mm1 = [x1][x0][r1][r0] + + punpcklbw mm0,[edx+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + pmaddwd mm6,mm2 + + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] + + pmaddwd mm7,mm2 + punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] + + paddd mm6,[MMX_roundval] + pmaddwd mm0,mm3 + + paddd mm7,[MMX_roundval] + pmaddwd mm1,mm3 + + paddd mm6,mm0 + + movd mm0,dword [esi+ebp] ;mm0 = [0][0][0][0][x0][r0][g0][b0] + paddd mm7,mm1 + + punpcklbw mm0,[esp+ebp] ;mm0 = [x0][x1][r0][r1][g0][g1][b0][b1] + movq mm1,mm0 + punpcklbw mm0,mm5 ;mm0 = [g1][g0][b1][b0] + punpckhbw mm1,mm5 ;mm1 = [x1][x0][r1][r0] + pmaddwd mm0,mm4 + pmaddwd mm1,mm4 + paddd mm6,mm0 + paddd mm7,mm1 + + psrad mm6,14 + psrad mm7,14 + packssdw mm6,mm7 + packuswb mm6,mm6 + + movd dword [edi+ebp],mm6 + + add ebp,4 + jne .pixelloop6 + + mov esp, dword [fs:0] + pop dword [fs:0] + pop eax + + jmp .xit + + + global _vdasm_resize_table_col_SSE2 +_vdasm_resize_table_col_SSE2: + push ebp + push esi + push edi + push ebx + + mov edx,[esp+12+16] + mov eax,[esp+24+16] + shl eax,2 + imul eax,[esp+16+16] + add edx,eax + mov [esp+12+16], edx ;[esp+12+16] = filter pointer + + mov ebp,[esp+20+16] ;ebp = pixel counter + mov edi,[esp+4+16] ;edi = destination pointer + + pxor xmm7, xmm7 + movdqa xmm6, [MMX_roundval] + + cmp dword [esp+16+16], 4 + jz .accel_4coeff + cmp dword [esp+16+16], 6 + jz .accel_6coeff + + mov ecx,[esp+16+16] + shr ecx,1 + mov [esp+16+16],ecx ;ecx = filter pair count + + xor ebx,ebx ;ebx = source offset + + mov ecx,[esp+16+16] ;ecx = filter width counter +.pixelloop: + mov eax, [esp+8+16] ;esi = row pointer table + movdqa xmm4, xmm6 +.coeffloop: + mov esi,[eax] + + movd xmm0, dword [esi+ebx] + + mov esi,[eax+4] + add eax,8 + + movd xmm1, dword [esi+ebx] + punpcklbw xmm0, xmm1 + + punpcklbw xmm0, xmm7 + + movq xmm2, qword [edx] + pshufd xmm2, xmm2, 01000100b + + pmaddwd xmm0, xmm2 + + paddd xmm4, xmm0 + + add edx,8 + + sub ecx,1 + jne .coeffloop + + psrad xmm4,14 + add edi,4 + packssdw xmm4,xmm4 + add ebx,4 + packuswb xmm4,xmm4 + sub ebp,1 + + mov ecx,[esp+16+16] ;ecx = filter width counter + mov edx,[esp+12+16] ;edx = filter bank pointer + + movd dword [edi-4],xmm4 + jne .pixelloop + +.xit: + pop ebx + pop edi + pop esi + pop ebp + ret + +.accel_4coeff: + shl ebp, 2 + mov eax, [esp+8+16] ;eax = row pointer table + mov esi, [eax+12] + mov ecx, [eax+8] + mov ebx, [eax+4] + mov eax, [eax] + lea edi, [edi+ebp-4] + neg ebp + + ;registers: + ; + ;EAX source 0 + ;EBX source 1 + ;ECX source 2 + ;ESI source 3 + ;EDI destination + ;EBP counter + ; + movq xmm4, qword [edx] ;xmm4 = coeff 0/1 + movq xmm5, qword [edx+8] ;xmm5 = coeff 2/3 + punpcklqdq xmm4, xmm4 + punpcklqdq xmm5, xmm5 + + add ebp, 4 + jz .oddpixel_4coeff + +.pixelloop_4coeff_dualpel: + movq xmm0, qword [eax] + movq xmm1, qword [ebx] + movq xmm2, qword [ecx] + movq xmm3, qword [esi] + add eax,8 + add ebx,8 + add ecx,8 + add esi,8 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + punpcklbw xmm0, xmm7 + punpckhbw xmm1, xmm7 + punpcklbw xmm2, xmm7 + punpckhbw xmm3, xmm7 + pmaddwd xmm0, xmm4 + pmaddwd xmm1, xmm4 + pmaddwd xmm2, xmm5 + pmaddwd xmm3, xmm5 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + paddd xmm0, xmm6 + paddd xmm1, xmm6 + psrad xmm0, 14 + psrad xmm1, 14 + packssdw xmm0, xmm1 + packuswb xmm0, xmm0 + movq qword [edi+ebp],xmm0 + add ebp, 8 + jae .pixelloop_4coeff_dualpel + jnz .xit + +.oddpixel_4coeff: + movd xmm0, dword [eax] + movd xmm1, dword [ebx] + movd xmm2, dword [ecx] + movd xmm3, dword [esi] + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + punpcklbw xmm0, xmm7 + punpcklbw xmm2, xmm7 + pmaddwd xmm0, xmm4 + pmaddwd xmm2, xmm5 + paddd xmm0, xmm2 + paddd xmm0, xmm6 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd dword [edi],xmm0 + jmp .xit + + +.accel_6coeff: + movq xmm4, qword [edx] ;xmm4 = coeff 0/1 + movq xmm5, qword [edx+8] ;xmm5 = coeff 2/3 + movq xmm6, qword [edx+16] ;xmm5 = coeff 4/5 + punpcklqdq xmm4, xmm4 + punpcklqdq xmm5, xmm5 + punpcklqdq xmm6, xmm6 + + push 0 + push dword [fs:0] + mov dword [fs:0],esp + + shl ebp, 2 + mov eax, [esp+8+24] ;eax = row pointer table + mov esp, [eax+20] + mov esi, [eax+16] + mov edx, [eax+12] + mov ecx, [eax+8] + mov ebx, [eax+4] + mov eax, [eax] + lea edi, [edi+ebp-4] + neg ebp + + ;registers: + ; + ;EAX source 0 + ;EBX source 1 + ;ECX source 2 + ;EDX source 3 + ;ESI source 4 + ;EDI destination + ;ESP source 5 + ;EBP counter + ; + + add ebp, 4 + jz .oddpixel_6coeff + +.pixelloop_6coeff_dualpel: + movq xmm0, qword [eax] + movq xmm1, qword [ebx] + movq xmm2, qword [ecx] + movq xmm3, qword [edx] + add eax,8 + add ebx,8 + add ecx,8 + add edx,8 + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + movdqa xmm1, xmm0 + movdqa xmm3, xmm2 + punpcklbw xmm0, xmm7 + punpckhbw xmm1, xmm7 + punpcklbw xmm2, xmm7 + punpckhbw xmm3, xmm7 + pmaddwd xmm0, xmm4 + pmaddwd xmm1, xmm4 + pmaddwd xmm2, xmm5 + pmaddwd xmm3, xmm5 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + + movq xmm2, qword [esi] + movq xmm3, qword [esp] + add esi, 8 + add esp, 8 + punpcklbw xmm2, xmm3 + movdqa xmm3, xmm2 + punpcklbw xmm2, xmm7 + punpckhbw xmm3, xmm7 + pmaddwd xmm2, xmm6 + pmaddwd xmm3, xmm6 + paddd xmm0, xmm2 + paddd xmm1, xmm3 + paddd xmm0, [MMX_roundval] + paddd xmm1, [MMX_roundval] + psrad xmm0, 14 + psrad xmm1, 14 + packssdw xmm0, xmm1 + packuswb xmm0, xmm0 + movq qword [edi+ebp],xmm0 + add ebp, 8 + jae .pixelloop_6coeff_dualpel + jnz .xit_6coeff + +.oddpixel_6coeff: + movd xmm0, dword [eax] + movd xmm1, dword [ebx] + movd xmm2, dword [ecx] + movd xmm3, dword [edx] + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + movd xmm1, dword [esi] + movd xmm3, dword [esp] + punpcklbw xmm0, xmm7 + punpcklbw xmm2, xmm7 + pmaddwd xmm0, xmm4 + punpcklbw xmm1, xmm3 + pmaddwd xmm2, xmm5 + punpcklbw xmm1, xmm7 + pmaddwd xmm1, xmm6 + paddd xmm0, xmm2 + paddd xmm1, [MMX_roundval] + paddd xmm0, xmm1 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd dword [edi],xmm0 + +.xit_6coeff: + mov esp, dword [fs:0] + pop dword [fs:0] + pop eax + jmp .xit + + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_resample_sse41.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_resample_sse41.asm index 0ccc2010a23..cf7332cb2bf 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_resample_sse41.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_resample_sse41.asm @@ -1,358 +1,358 @@ - segment .rdata, align=16 - -round dq 0000000000002000h -colround dq 0000200000002000h - - segment .text - - global _vdasm_resize_table_row_8_k8_4x_SSE41 -_vdasm_resize_table_row_8_k8_4x_SSE41: - push ebp - push edi - push esi - push ebx - - movq xmm6, [round] - pshufd xmm6, xmm6, 0 - - mov ebp, [esp + 4 + 16] ;ebp = dst - mov esi, [esp + 12 + 16] ;esi = width - mov edi, [esp + 16 + 16] ;edi = kernel -.yloop: - ;eax = temp - ;ebx = temp - ;ecx = temp - ;edx = temp - ;esi = horiz counter - ;edi = filter list - ;ebp = destination - - mov eax, [edi+0] - mov ebx, [edi+4] - mov ecx, [edi+8] - mov edx, [esp+8+16] - add eax, edx - add ebx, edx - add ecx, edx - add edx, [edi+12] - - pmovzxbw xmm0, [eax] - pmaddwd xmm0, [edi+10h] - pmovzxbw xmm1, [ebx] - pmaddwd xmm1, [edi+20h] - pmovzxbw xmm2, [ecx] - pmaddwd xmm2, [edi+30h] - pmovzxbw xmm3, [edx] - pmaddwd xmm3, [edi+40h] - add edi, 50h - phaddd xmm0, xmm1 - phaddd xmm2, xmm3 - phaddd xmm0, xmm2 - paddd xmm0, xmm6 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd [ebp], xmm0 - - add ebp, 4 - sub esi, 1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_resize_table_row_8_k16_4x_SSE41 -_vdasm_resize_table_row_8_k16_4x_SSE41: - push ebp - push edi - push esi - push ebx - - movq xmm6, [round] - pshufd xmm6, xmm6, 0 - - mov ebp, [esp + 4 + 16] ;ebp = dst - mov esi, [esp + 12 + 16] ;esi = width - mov edi, [esp + 16 + 16] ;edi = kernel -.yloop: - ;eax = temp - ;ebx = temp - ;ecx = temp - ;edx = temp - ;esi = horiz counter - ;edi = filter list - ;ebp = destination - - mov eax, [edi+0] - mov ebx, [edi+4] - mov ecx, [edi+8] - mov edx, [esp+8+16] - add eax, edx - add ebx, edx - add ecx, edx - add edx, [edi+12] - - pmovzxbw xmm0, [eax] - pmaddwd xmm0, [edi+10h] - pmovzxbw xmm1, [ebx] - pmaddwd xmm1, [edi+20h] - pmovzxbw xmm2, [ecx] - pmaddwd xmm2, [edi+30h] - pmovzxbw xmm3, [edx] - pmaddwd xmm3, [edi+40h] - pmovzxbw xmm4, [eax+8] - pmaddwd xmm4, [edi+50h] - pmovzxbw xmm5, [ebx+8] - pmaddwd xmm5, [edi+60h] - paddd xmm0, xmm4 - pmovzxbw xmm4, [ecx+8] - pmaddwd xmm4, [edi+70h] - paddd xmm1, xmm5 - pmovzxbw xmm5, [edx+8] - pmaddwd xmm5, [edi+80h] - paddd xmm2, xmm4 - paddd xmm3, xmm5 - add edi, 90h - phaddd xmm0, xmm1 - phaddd xmm2, xmm3 - phaddd xmm0, xmm2 - paddd xmm0, xmm6 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd [ebp], xmm0 - - add ebp, 4 - sub esi, 1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_resize_table_row_8_SSE41 -_vdasm_resize_table_row_8_SSE41: - push ebp - push edi - push esi - push ebx - - pxor xmm7, xmm7 - movq xmm6, [round] - - mov edi, [esp + 4 + 16] ;edi = dst - mov ebx, [esp + 8 + 16] ;ebx = src - mov ebp, [esp + 12 + 16] ;ebp = width - mov edx, [esp + 16 + 16] ;edx = kernel -.yloop: - ;eax = temp - ;ebx = source base address - ;ecx = (temp) source - ;edx = filter list - ;esi = (temp) kernel width - ;edi = destination - ;ebp = horiz counter - - mov eax, [edx] - add edx, 16 - lea ecx, [ebx + eax] - mov esi, [esp + 20 + 16] ;esi = kernel width - - movq xmm2, xmm6 -.xloop: - pmovzxbw xmm0, [ecx] - add ecx, 8 - pmaddwd xmm0, [edx] - paddd xmm2, xmm0 - add edx, 16 - sub esi, 8 - jne .xloop - - phaddd xmm2, xmm2 - phaddd xmm2, xmm2 - psrad xmm2, 14 - packssdw xmm2, xmm2 - packuswb xmm2, xmm2 - movd eax, xmm2 - mov [edi], al - add edi, 1 - sub ebp, 1 - jne .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_resize_table_col_8_k2_SSE41 -_vdasm_resize_table_col_8_k2_SSE41: - push ebp - push edi - push esi - push ebx - - movq xmm6, [colround] - pshufd xmm6, xmm6, 0 - - mov esi, [esp + 4 + 16] ;esi = dst - mov edi, [esp + 16 + 16] ;edi = kernel - mov ebp, [esp + 12 + 16] ;ebp = width - - movq xmm7, [edi] - pshufd xmm7, xmm7, 0 - - mov edx, [esp + 8 + 16] ;ebx = srcs - mov eax, [edx+0] - mov ebx, [edx+4] - add eax, ebp - add ebx, ebp - neg ebp - -.yloop: - ;eax = row0 - ;ebx = row1 - ;ecx = - ;edx = - ;edi = kernel - ;esi = dest - ;ebp = width counter - - movd xmm0, [eax+ebp] - movd xmm2, [ebx+ebp] - punpcklbw xmm0, xmm2 - pmovzxbw xmm0, xmm0 - pmaddwd xmm0, xmm7 - - paddd xmm0, xmm6 - - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd [esi], xmm0 - add esi, 4 - add ebp, 4 - jnz .yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_resize_table_col_8_k4_SSE41 -_vdasm_resize_table_col_8_k4_SSE41: - push ebp - push edi - push esi - push ebx - - movq xmm7, [colround] - pshufd xmm7, xmm7, 0 - - mov esi, [esp + 4 + 16] ;esi = dst - mov edi, [esp + 16 + 16] ;edi = kernel - - movdqu xmm6, [edi] - pshufd xmm5, xmm6, 0 - pshufd xmm6, xmm6, 0aah - - mov edx, [esp + 8 + 16] ;ebx = srcs - mov ebp, [esp + 12 + 16] - mov eax, [edx+0] - mov ebx, [edx+4] - mov ecx, [edx+8] - mov edx, [edx+12] - lea eax, [eax+ebp-4] - lea ebx, [ebx+ebp-4] - lea ecx, [ecx+ebp-4] - lea edx, [edx+ebp-4] - lea esi, [esi+ebp-4] - neg ebp - add ebp,4 - jz .odd -.yloop: - ;eax = row0 - ;ebx = row1 - ;ecx = row2 - ;edx = row3 - ;edi = kernel - ;esi = dest - ;ebp = width counter - - movd xmm0, [eax+ebp] - movd xmm1, [ebx+ebp] - punpcklbw xmm0, xmm1 - - movd xmm1, [ecx+ebp] - movd xmm2, [edx+ebp] - punpcklbw xmm1, xmm2 - - movd xmm2, [eax+ebp+4] - movd xmm3, [ebx+ebp+4] - punpcklbw xmm2, xmm3 - - movd xmm3, [ecx+ebp+4] - movd xmm4, [edx+ebp+4] - punpcklbw xmm3, xmm4 - - pmovzxbw xmm0, xmm0 - pmaddwd xmm0, xmm5 - - pmovzxbw xmm1, xmm1 - pmaddwd xmm1, xmm6 - - pmovzxbw xmm2, xmm2 - pmaddwd xmm2, xmm5 - - pmovzxbw xmm3, xmm3 - pmaddwd xmm3, xmm6 - - paddd xmm0, xmm1 - paddd xmm2, xmm3 - - paddd xmm0, xmm7 - paddd xmm2, xmm7 - - psrad xmm0, 14 - psrad xmm2, 14 - - packssdw xmm0, xmm2 - packuswb xmm0, xmm0 - movq [esi+ebp], xmm0 - add ebp, 8 - js .yloop - jnz .noodd - -.odd: - movd xmm0, [eax] - movd xmm1, [ebx] - movd xmm2, [ecx] - movd xmm3, [edx] - punpcklbw xmm0, xmm1 - punpcklbw xmm2, xmm3 - pmovzxbw xmm0, xmm0 - pmovzxbw xmm2, xmm2 - pmaddwd xmm0, xmm5 - pmaddwd xmm2, xmm6 - paddd xmm0, xmm2 - paddd xmm0, xmm7 - psrad xmm0, 14 - packssdw xmm0, xmm0 - packuswb xmm0, xmm0 - movd [esi], xmm0 -.noodd: - - pop ebx - pop esi - pop edi - pop ebp - ret - - end + segment .rdata, align=16 + +round dq 0000000000002000h +colround dq 0000200000002000h + + segment .text + + global _vdasm_resize_table_row_8_k8_4x_SSE41 +_vdasm_resize_table_row_8_k8_4x_SSE41: + push ebp + push edi + push esi + push ebx + + movq xmm6, [round] + pshufd xmm6, xmm6, 0 + + mov ebp, [esp + 4 + 16] ;ebp = dst + mov esi, [esp + 12 + 16] ;esi = width + mov edi, [esp + 16 + 16] ;edi = kernel +.yloop: + ;eax = temp + ;ebx = temp + ;ecx = temp + ;edx = temp + ;esi = horiz counter + ;edi = filter list + ;ebp = destination + + mov eax, [edi+0] + mov ebx, [edi+4] + mov ecx, [edi+8] + mov edx, [esp+8+16] + add eax, edx + add ebx, edx + add ecx, edx + add edx, [edi+12] + + pmovzxbw xmm0, [eax] + pmaddwd xmm0, [edi+10h] + pmovzxbw xmm1, [ebx] + pmaddwd xmm1, [edi+20h] + pmovzxbw xmm2, [ecx] + pmaddwd xmm2, [edi+30h] + pmovzxbw xmm3, [edx] + pmaddwd xmm3, [edi+40h] + add edi, 50h + phaddd xmm0, xmm1 + phaddd xmm2, xmm3 + phaddd xmm0, xmm2 + paddd xmm0, xmm6 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd [ebp], xmm0 + + add ebp, 4 + sub esi, 1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_resize_table_row_8_k16_4x_SSE41 +_vdasm_resize_table_row_8_k16_4x_SSE41: + push ebp + push edi + push esi + push ebx + + movq xmm6, [round] + pshufd xmm6, xmm6, 0 + + mov ebp, [esp + 4 + 16] ;ebp = dst + mov esi, [esp + 12 + 16] ;esi = width + mov edi, [esp + 16 + 16] ;edi = kernel +.yloop: + ;eax = temp + ;ebx = temp + ;ecx = temp + ;edx = temp + ;esi = horiz counter + ;edi = filter list + ;ebp = destination + + mov eax, [edi+0] + mov ebx, [edi+4] + mov ecx, [edi+8] + mov edx, [esp+8+16] + add eax, edx + add ebx, edx + add ecx, edx + add edx, [edi+12] + + pmovzxbw xmm0, [eax] + pmaddwd xmm0, [edi+10h] + pmovzxbw xmm1, [ebx] + pmaddwd xmm1, [edi+20h] + pmovzxbw xmm2, [ecx] + pmaddwd xmm2, [edi+30h] + pmovzxbw xmm3, [edx] + pmaddwd xmm3, [edi+40h] + pmovzxbw xmm4, [eax+8] + pmaddwd xmm4, [edi+50h] + pmovzxbw xmm5, [ebx+8] + pmaddwd xmm5, [edi+60h] + paddd xmm0, xmm4 + pmovzxbw xmm4, [ecx+8] + pmaddwd xmm4, [edi+70h] + paddd xmm1, xmm5 + pmovzxbw xmm5, [edx+8] + pmaddwd xmm5, [edi+80h] + paddd xmm2, xmm4 + paddd xmm3, xmm5 + add edi, 90h + phaddd xmm0, xmm1 + phaddd xmm2, xmm3 + phaddd xmm0, xmm2 + paddd xmm0, xmm6 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd [ebp], xmm0 + + add ebp, 4 + sub esi, 1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_resize_table_row_8_SSE41 +_vdasm_resize_table_row_8_SSE41: + push ebp + push edi + push esi + push ebx + + pxor xmm7, xmm7 + movq xmm6, [round] + + mov edi, [esp + 4 + 16] ;edi = dst + mov ebx, [esp + 8 + 16] ;ebx = src + mov ebp, [esp + 12 + 16] ;ebp = width + mov edx, [esp + 16 + 16] ;edx = kernel +.yloop: + ;eax = temp + ;ebx = source base address + ;ecx = (temp) source + ;edx = filter list + ;esi = (temp) kernel width + ;edi = destination + ;ebp = horiz counter + + mov eax, [edx] + add edx, 16 + lea ecx, [ebx + eax] + mov esi, [esp + 20 + 16] ;esi = kernel width + + movq xmm2, xmm6 +.xloop: + pmovzxbw xmm0, [ecx] + add ecx, 8 + pmaddwd xmm0, [edx] + paddd xmm2, xmm0 + add edx, 16 + sub esi, 8 + jne .xloop + + phaddd xmm2, xmm2 + phaddd xmm2, xmm2 + psrad xmm2, 14 + packssdw xmm2, xmm2 + packuswb xmm2, xmm2 + movd eax, xmm2 + mov [edi], al + add edi, 1 + sub ebp, 1 + jne .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_resize_table_col_8_k2_SSE41 +_vdasm_resize_table_col_8_k2_SSE41: + push ebp + push edi + push esi + push ebx + + movq xmm6, [colround] + pshufd xmm6, xmm6, 0 + + mov esi, [esp + 4 + 16] ;esi = dst + mov edi, [esp + 16 + 16] ;edi = kernel + mov ebp, [esp + 12 + 16] ;ebp = width + + movq xmm7, [edi] + pshufd xmm7, xmm7, 0 + + mov edx, [esp + 8 + 16] ;ebx = srcs + mov eax, [edx+0] + mov ebx, [edx+4] + add eax, ebp + add ebx, ebp + neg ebp + +.yloop: + ;eax = row0 + ;ebx = row1 + ;ecx = + ;edx = + ;edi = kernel + ;esi = dest + ;ebp = width counter + + movd xmm0, [eax+ebp] + movd xmm2, [ebx+ebp] + punpcklbw xmm0, xmm2 + pmovzxbw xmm0, xmm0 + pmaddwd xmm0, xmm7 + + paddd xmm0, xmm6 + + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd [esi], xmm0 + add esi, 4 + add ebp, 4 + jnz .yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_resize_table_col_8_k4_SSE41 +_vdasm_resize_table_col_8_k4_SSE41: + push ebp + push edi + push esi + push ebx + + movq xmm7, [colround] + pshufd xmm7, xmm7, 0 + + mov esi, [esp + 4 + 16] ;esi = dst + mov edi, [esp + 16 + 16] ;edi = kernel + + movdqu xmm6, [edi] + pshufd xmm5, xmm6, 0 + pshufd xmm6, xmm6, 0aah + + mov edx, [esp + 8 + 16] ;ebx = srcs + mov ebp, [esp + 12 + 16] + mov eax, [edx+0] + mov ebx, [edx+4] + mov ecx, [edx+8] + mov edx, [edx+12] + lea eax, [eax+ebp-4] + lea ebx, [ebx+ebp-4] + lea ecx, [ecx+ebp-4] + lea edx, [edx+ebp-4] + lea esi, [esi+ebp-4] + neg ebp + add ebp,4 + jz .odd +.yloop: + ;eax = row0 + ;ebx = row1 + ;ecx = row2 + ;edx = row3 + ;edi = kernel + ;esi = dest + ;ebp = width counter + + movd xmm0, [eax+ebp] + movd xmm1, [ebx+ebp] + punpcklbw xmm0, xmm1 + + movd xmm1, [ecx+ebp] + movd xmm2, [edx+ebp] + punpcklbw xmm1, xmm2 + + movd xmm2, [eax+ebp+4] + movd xmm3, [ebx+ebp+4] + punpcklbw xmm2, xmm3 + + movd xmm3, [ecx+ebp+4] + movd xmm4, [edx+ebp+4] + punpcklbw xmm3, xmm4 + + pmovzxbw xmm0, xmm0 + pmaddwd xmm0, xmm5 + + pmovzxbw xmm1, xmm1 + pmaddwd xmm1, xmm6 + + pmovzxbw xmm2, xmm2 + pmaddwd xmm2, xmm5 + + pmovzxbw xmm3, xmm3 + pmaddwd xmm3, xmm6 + + paddd xmm0, xmm1 + paddd xmm2, xmm3 + + paddd xmm0, xmm7 + paddd xmm2, xmm7 + + psrad xmm0, 14 + psrad xmm2, 14 + + packssdw xmm0, xmm2 + packuswb xmm0, xmm0 + movq [esi+ebp], xmm0 + add ebp, 8 + js .yloop + jnz .noodd + +.odd: + movd xmm0, [eax] + movd xmm1, [ebx] + movd xmm2, [ecx] + movd xmm3, [edx] + punpcklbw xmm0, xmm1 + punpcklbw xmm2, xmm3 + pmovzxbw xmm0, xmm0 + pmovzxbw xmm2, xmm2 + pmaddwd xmm0, xmm5 + pmaddwd xmm2, xmm6 + paddd xmm0, xmm2 + paddd xmm0, xmm7 + psrad xmm0, 14 + packssdw xmm0, xmm0 + packuswb xmm0, xmm0 + movd [esi], xmm0 +.noodd: + + pop ebx + pop esi + pop edi + pop ebp + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_spanutils_isse.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_spanutils_isse.asm index 60200e2159b..3fe7cedbc59 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_spanutils_isse.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_spanutils_isse.asm @@ -1,193 +1,193 @@ - section .rdata, rdata, align=16 - -xfefefefefefefefe dq 0fefefefefefefefeh -xe0e0e0e0e0e0e0e0 dq 0e0e0e0e0e0e0e0e0h -x0002000200020002 dq 00002000200020002h - - section .text - -;============================================================================== - global _vdasm_horiz_expand2x_coaligned_ISSE -_vdasm_horiz_expand2x_coaligned_ISSE: - mov ecx, [esp+8] - mov edx, [esp+4] - mov eax, [esp+12] -.xloop: - movq mm0, [ecx] - movq mm1, mm0 - pavgb mm0, [ecx+1] - movq mm2, mm1 - punpcklbw mm1, mm0 - punpckhbw mm2, mm0 - - movq [edx], mm1 - movq [edx+8], mm2 - add edx, 16 - add ecx, 8 - - sub eax, 16 - jne .xloop - ret - -;============================================================================== - global _vdasm_vert_average_13_ISSE -_vdasm_vert_average_13_ISSE: - push ebx - mov ebx, [esp+12+4] - mov ecx, [esp+8+4] - mov edx, [esp+4+4] - mov eax, [esp+16+4] - - add ebx, eax - add ecx, eax - add edx, eax - neg eax - - pcmpeqb mm7, mm7 -.xloop: - movq mm0, [ebx+eax] - movq mm1, [ecx+eax] - movq mm2, mm0 - - movq mm3, [ebx+eax+8] - pxor mm0, mm7 - pxor mm1, mm7 - - movq mm4, [ecx+eax+8] - movq mm5, mm3 - pxor mm3, mm7 - - pxor mm4, mm7 - pavgb mm0, mm1 - pavgb mm3, mm4 - - pxor mm0, mm7 - pxor mm3, mm7 - pavgb mm0, mm2 - - movq [edx+eax], mm0 - pavgb mm3, mm5 - - movq [edx+eax+8], mm3 - add eax, 16 - jne .xloop - - pop ebx - ret - -;============================================================================== - global _vdasm_vert_average_17_ISSE -_vdasm_vert_average_17_ISSE: - push ebx - mov ebx, [esp+12+4] - mov ecx, [esp+8+4] - mov edx, [esp+4+4] - mov eax, [esp+16+4] - - add ebx, eax - add ecx, eax - add edx, eax - neg eax - - ;r = avgup(avgdown(avgdown(a, b), a), a) - ; = pavgb(~pavgb(pavgb(~a, ~b), ~a), a) - - pcmpeqb mm7, mm7 -.xloop: - movq mm0, [ecx+eax] - movq mm1, [ebx+eax] - movq mm2, mm0 - pxor mm0, mm7 ;~a - pxor mm1, mm7 ;~b - pavgb mm1, mm0 ;pavgb(~a, ~b) = ~avgdown(a, b) - pavgb mm1, mm0 ;pavgb(~avgdown(a, b), ~a) = ~avgdown(avgdown(a, b), a) - pxor mm1, mm7 ;avgdown(avgdown(a, b), a) - pavgb mm1, mm2 ;pavgb(avgdown(avgdown(a, b), a), a) = round((7*a + b)/8) - movq [edx+eax], mm1 - - add eax, 8 - jne .xloop - - pop ebx - ret - -;============================================================================== - global _vdasm_vert_average_35_ISSE -_vdasm_vert_average_35_ISSE: - push ebx - mov ebx, [esp+12+4] - mov ecx, [esp+8+4] - mov edx, [esp+4+4] - mov eax, [esp+16+4] - - add ebx, eax - add ecx, eax - add edx, eax - neg eax - - ;r = avgup(avgdown(avgdown(a, b), b), a) - ; = pavgb(~pavgb(pavgb(~a, ~b), ~b), a) - - pcmpeqb mm7, mm7 -.xloop: - movq mm0, [ecx+eax] - movq mm1, [ebx+eax] - movq mm2, mm0 - pxor mm0, mm7 ;~a - pxor mm1, mm7 ;~b - pavgb mm0, mm1 ;avgup(~a, ~b) = ~avgdown(a, b) - pavgb mm0, mm1 ;avgup(~avgdown(a, b), ~b) = ~avgdown(avgdown(a, b), b) - pxor mm0, mm7 ;avgdown(avgdown(a, b), b) - pavgb mm0, mm2 ;avgup(avgdown(avgdown(a, b), b), a) = round((5*a + 3*b) / 8) - movq [edx+eax], mm0 - - add eax, 8 - jne .xloop - - pop ebx - ret - -;============================================================================== - global _vdasm_horiz_expand4x_coaligned_MMX -_vdasm_horiz_expand4x_coaligned_MMX: - mov edx, [esp+4] - mov ecx, [esp+8] - mov eax, [esp+12] - movq mm6, qword [x0002000200020002] - pxor mm7, mm7 -.xloop: - movd mm0, [ecx] - movd mm1, [ecx+1] - add ecx, 4 - punpcklbw mm0, mm7 - punpcklbw mm1, mm7 - psubw mm1, mm0 ;x1 - movq mm2, mm1 - paddw mm1, mm6 ;x1 + 2 - movq mm3, mm1 - paddw mm2, mm2 ;x2 - paddw mm3, mm2 ;x3 + 2 - paddw mm2, mm6 ;x2 + 2 - psraw mm1, 2 ;x1/4 - psraw mm2, 2 ;x2/4 - psraw mm3, 2 ;x3/4 - paddw mm1, mm0 - paddw mm2, mm0 - paddw mm3, mm0 - movd mm0, [ecx-4] - packuswb mm1, mm1 - packuswb mm2, mm2 - packuswb mm3, mm3 - punpcklbw mm0, mm1 - punpcklbw mm2, mm3 - movq mm1, mm0 - punpcklwd mm0, mm2 - punpckhwd mm1, mm2 - - movq [edx], mm0 - movq [edx+8], mm1 - add edx, 16 - sub eax, 1 - jne .xloop - - ret + section .rdata, rdata, align=16 + +xfefefefefefefefe dq 0fefefefefefefefeh +xe0e0e0e0e0e0e0e0 dq 0e0e0e0e0e0e0e0e0h +x0002000200020002 dq 00002000200020002h + + section .text + +;============================================================================== + global _vdasm_horiz_expand2x_coaligned_ISSE +_vdasm_horiz_expand2x_coaligned_ISSE: + mov ecx, [esp+8] + mov edx, [esp+4] + mov eax, [esp+12] +.xloop: + movq mm0, [ecx] + movq mm1, mm0 + pavgb mm0, [ecx+1] + movq mm2, mm1 + punpcklbw mm1, mm0 + punpckhbw mm2, mm0 + + movq [edx], mm1 + movq [edx+8], mm2 + add edx, 16 + add ecx, 8 + + sub eax, 16 + jne .xloop + ret + +;============================================================================== + global _vdasm_vert_average_13_ISSE +_vdasm_vert_average_13_ISSE: + push ebx + mov ebx, [esp+12+4] + mov ecx, [esp+8+4] + mov edx, [esp+4+4] + mov eax, [esp+16+4] + + add ebx, eax + add ecx, eax + add edx, eax + neg eax + + pcmpeqb mm7, mm7 +.xloop: + movq mm0, [ebx+eax] + movq mm1, [ecx+eax] + movq mm2, mm0 + + movq mm3, [ebx+eax+8] + pxor mm0, mm7 + pxor mm1, mm7 + + movq mm4, [ecx+eax+8] + movq mm5, mm3 + pxor mm3, mm7 + + pxor mm4, mm7 + pavgb mm0, mm1 + pavgb mm3, mm4 + + pxor mm0, mm7 + pxor mm3, mm7 + pavgb mm0, mm2 + + movq [edx+eax], mm0 + pavgb mm3, mm5 + + movq [edx+eax+8], mm3 + add eax, 16 + jne .xloop + + pop ebx + ret + +;============================================================================== + global _vdasm_vert_average_17_ISSE +_vdasm_vert_average_17_ISSE: + push ebx + mov ebx, [esp+12+4] + mov ecx, [esp+8+4] + mov edx, [esp+4+4] + mov eax, [esp+16+4] + + add ebx, eax + add ecx, eax + add edx, eax + neg eax + + ;r = avgup(avgdown(avgdown(a, b), a), a) + ; = pavgb(~pavgb(pavgb(~a, ~b), ~a), a) + + pcmpeqb mm7, mm7 +.xloop: + movq mm0, [ecx+eax] + movq mm1, [ebx+eax] + movq mm2, mm0 + pxor mm0, mm7 ;~a + pxor mm1, mm7 ;~b + pavgb mm1, mm0 ;pavgb(~a, ~b) = ~avgdown(a, b) + pavgb mm1, mm0 ;pavgb(~avgdown(a, b), ~a) = ~avgdown(avgdown(a, b), a) + pxor mm1, mm7 ;avgdown(avgdown(a, b), a) + pavgb mm1, mm2 ;pavgb(avgdown(avgdown(a, b), a), a) = round((7*a + b)/8) + movq [edx+eax], mm1 + + add eax, 8 + jne .xloop + + pop ebx + ret + +;============================================================================== + global _vdasm_vert_average_35_ISSE +_vdasm_vert_average_35_ISSE: + push ebx + mov ebx, [esp+12+4] + mov ecx, [esp+8+4] + mov edx, [esp+4+4] + mov eax, [esp+16+4] + + add ebx, eax + add ecx, eax + add edx, eax + neg eax + + ;r = avgup(avgdown(avgdown(a, b), b), a) + ; = pavgb(~pavgb(pavgb(~a, ~b), ~b), a) + + pcmpeqb mm7, mm7 +.xloop: + movq mm0, [ecx+eax] + movq mm1, [ebx+eax] + movq mm2, mm0 + pxor mm0, mm7 ;~a + pxor mm1, mm7 ;~b + pavgb mm0, mm1 ;avgup(~a, ~b) = ~avgdown(a, b) + pavgb mm0, mm1 ;avgup(~avgdown(a, b), ~b) = ~avgdown(avgdown(a, b), b) + pxor mm0, mm7 ;avgdown(avgdown(a, b), b) + pavgb mm0, mm2 ;avgup(avgdown(avgdown(a, b), b), a) = round((5*a + 3*b) / 8) + movq [edx+eax], mm0 + + add eax, 8 + jne .xloop + + pop ebx + ret + +;============================================================================== + global _vdasm_horiz_expand4x_coaligned_MMX +_vdasm_horiz_expand4x_coaligned_MMX: + mov edx, [esp+4] + mov ecx, [esp+8] + mov eax, [esp+12] + movq mm6, qword [x0002000200020002] + pxor mm7, mm7 +.xloop: + movd mm0, [ecx] + movd mm1, [ecx+1] + add ecx, 4 + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm1, mm0 ;x1 + movq mm2, mm1 + paddw mm1, mm6 ;x1 + 2 + movq mm3, mm1 + paddw mm2, mm2 ;x2 + paddw mm3, mm2 ;x3 + 2 + paddw mm2, mm6 ;x2 + 2 + psraw mm1, 2 ;x1/4 + psraw mm2, 2 ;x2/4 + psraw mm3, 2 ;x3/4 + paddw mm1, mm0 + paddw mm2, mm0 + paddw mm3, mm0 + movd mm0, [ecx-4] + packuswb mm1, mm1 + packuswb mm2, mm2 + packuswb mm3, mm3 + punpcklbw mm0, mm1 + punpcklbw mm2, mm3 + movq mm1, mm0 + punpcklwd mm0, mm2 + punpckhwd mm1, mm2 + + movq [edx], mm0 + movq [edx+8], mm1 + add edx, 16 + sub eax, 1 + jne .xloop + + ret diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_mmx.asm index 88e0955c086..3db442fa28f 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_mmx.asm @@ -1,326 +1,326 @@ - segment .rdata, align=16 - -x0020w dq 00020002000200020h -rb_mask_555 dq 07c1f7c1f7c1f7c1fh -g_mask_555 dq 003e003e003e003e0h -rb_mask_888 dq 000ff00ff00ff00ffh -g_mask_888 dq 00000ff000000ff00h - - segment .text - - struc VDPixmapReferenceStretchBltBilinearParameters -.dst resd 1 -.src resd 1 -.u resd 1 -.uinc resd 1 -.dudx resd 1 - -.xprepos resd 1 -.xpostpos resd 1 -.xprecopy resd 1 -.xpostcopy resd 1 -.xmidsize resd 1 - endstruc - - - - global _vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX -_vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+20+16] - and eax, 0f8000000h - mov ebx, [esp+8+16] - mov ecx, [esp+12+16] - jz .noreverse - xchg ebx, ecx - js .noreverse - neg eax - xchg ebx, ecx -.noreverse: - shr eax, 16 - mov [esp+20+16], eax - mov edx, [esp+4+16] - mov eax, [esp+16+16] - add eax, eax - lea ebx, [ebx+eax-6] - lea ecx, [ecx+eax-6] - lea edx, [edx+eax-6] - neg eax - - movd mm4, dword [esp+20+16] - punpcklwd mm4, mm4 - punpckldq mm4, mm4 - - movq mm6, [rb_mask_555] - movq mm7, [g_mask_555] - -.xstart: - add eax, 6 - jbe .doodd -.xloop: - movq mm0, [ebx+eax] - movq mm1, [ecx+eax] - movq mm2, mm7 - movq mm3, mm7 - - pand mm2, mm0 - pand mm3, mm1 - pand mm0, mm6 - pand mm1, mm6 - - psubw mm3, mm2 - psubw mm1, mm0 - - pmulhw mm3, mm4 - pmulhw mm1, mm4 - - psubw mm0, mm1 - psubw mm2, mm3 - - pand mm0, mm6 - pand mm2, mm7 - - paddw mm0, mm2 - - movq [edx+eax], mm0 - add eax, 8 - jnc .xloop - -.doodd: - sub eax, 6 - jz .noodd -.odd: - movzx esi, word [ebx+eax+6] - movd mm0, esi - movzx esi, word [ecx+eax+6] - movd mm1, esi - movq mm2, mm7 - movq mm3, mm7 - - pand mm2, mm0 - pand mm3, mm1 - pand mm0, mm6 - pand mm1, mm6 - - psubw mm3, mm2 - psubw mm1, mm0 - - pmulhw mm3, mm4 - pmulhw mm1, mm4 - - psubw mm0, mm1 - psubw mm2, mm3 - - pand mm0, mm6 - pand mm2, mm7 - - paddw mm0, mm2 - - movd esi, mm0 - mov [edx+eax+6], si - add eax,2 - jne .odd - -.noodd: - emms - pop ebx - pop esi - pop edi - pop ebp - ret - - - global _vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX -_vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX: - push ebp - push edi - push esi - push ebx - - mov edx, [esp+4+16] - - mov ebx, [edx+VDPixmapReferenceStretchBltBilinearParameters.src] - mov edi, [edx+VDPixmapReferenceStretchBltBilinearParameters.dst] - - mov ecx, [edx+VDPixmapReferenceStretchBltBilinearParameters.xprecopy] - or ecx, ecx - jz .noprecopy - mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.xprepos] - mov eax, [ebx+eax] - lea ebp, [ecx*4] - sub edi, ebp - rep stosd -.noprecopy: - mov ebp, [edx+VDPixmapReferenceStretchBltBilinearParameters.xmidsize] - add ebp, ebp - add ebp, ebp - add edi, ebp - neg ebp - - mov esi, [edx+VDPixmapReferenceStretchBltBilinearParameters.u] - mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.dudx] - mov edx, [edx+VDPixmapReferenceStretchBltBilinearParameters.uinc] - movd mm2, esi - movd mm3, eax - shr ebx, 2 - - movq mm5, mm2 - punpcklwd mm5, mm5 - punpckhdq mm5, mm5 - movq mm4, mm5 - psraw mm4, 15 - -.xloop: - movd mm0, dword [ebx*4] - pxor mm7, mm7 - movd mm1, dword [ebx*4+4] - punpcklbw mm0, mm7 - punpcklbw mm1, mm7 - psubw mm1, mm0 - pand mm4, mm1 - pmulhw mm1, mm5 - paddw mm1, mm4 - paddw mm0, mm1 - packuswb mm0, mm0 - movd dword [edi+ebp], mm0 - - add esi, eax - adc ebx, edx - - paddd mm2, mm3 - movq mm5, mm2 - punpcklwd mm5, mm5 - punpckhdq mm5, mm5 - movq mm4, mm5 - psraw mm4, 15 - add ebp, 4 - jnz .xloop - - mov edx, [esp+4+16] - mov ecx, [edx+VDPixmapReferenceStretchBltBilinearParameters.xpostcopy] - or ecx, ecx - jz .nopostcopy - mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.xpostpos] - add eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.src] - mov eax, [eax] - rep stosd -.nopostcopy: - - emms - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX -_vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+20+16] - and eax, 0ff000000h - mov ebx, [esp+8+16] - mov ecx, [esp+12+16] - jz .noreverse - xchg ebx, ecx - js .noreverse - neg eax - xchg ebx, ecx -.noreverse: - shr eax, 16 - mov [esp+20+16], eax - mov edx, [esp+4+16] - mov eax, [esp+16+16] - add eax, eax - add eax, eax - lea ebx, [ebx+eax-4] - lea ecx, [ecx+eax-4] - lea edx, [edx+eax-4] - neg eax - - movd mm4, dword [esp+20+16] - punpcklwd mm4, mm4 - punpckldq mm4, mm4 - - movq mm6, [rb_mask_888] - movq mm7, [g_mask_888] - -.xstart: - add eax, 4 - jbe .doodd -.xloop: - movq mm0, [ebx+eax] - movq mm1, [ecx+eax] - movq mm2, mm0 - movq mm3, mm1 - psrlw mm2, 8 - psrlw mm3, 8 - pand mm0, mm6 - pand mm1, mm6 - - psubw mm3, mm2 - psubw mm1, mm0 - - pmulhw mm3, mm4 - pmulhw mm1, mm4 - - psubw mm0, mm1 - psubw mm2, mm3 - - pand mm0, mm6 - - psllw mm2, 8 - - paddw mm0, mm2 - - movq qword [edx+eax], mm0 - add eax, 8 - jnc .xloop - -.doodd: - sub eax, 4 - jz .noodd -.odd: - movd mm0, dword [ebx] - movd mm1, dword [ecx] - movq mm2, mm0 - movq mm3, mm1 - psrlw mm2, 8 - psrlw mm3, 8 - pand mm0, mm6 - pand mm1, mm6 - - psubw mm3, mm2 - psubw mm1, mm0 - - pmulhw mm3, mm4 - pmulhw mm1, mm4 - - psubw mm0, mm1 - psubw mm2, mm3 - - pand mm0, mm6 - - psllw mm2, 8 - - paddw mm0, mm2 - - movd dword [edx], mm0 - -.noodd: - emms - pop ebx - pop esi - pop edi - pop ebp - ret - - - end + segment .rdata, align=16 + +x0020w dq 00020002000200020h +rb_mask_555 dq 07c1f7c1f7c1f7c1fh +g_mask_555 dq 003e003e003e003e0h +rb_mask_888 dq 000ff00ff00ff00ffh +g_mask_888 dq 00000ff000000ff00h + + segment .text + + struc VDPixmapReferenceStretchBltBilinearParameters +.dst resd 1 +.src resd 1 +.u resd 1 +.uinc resd 1 +.dudx resd 1 + +.xprepos resd 1 +.xpostpos resd 1 +.xprecopy resd 1 +.xpostcopy resd 1 +.xmidsize resd 1 + endstruc + + + + global _vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX +_vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+20+16] + and eax, 0f8000000h + mov ebx, [esp+8+16] + mov ecx, [esp+12+16] + jz .noreverse + xchg ebx, ecx + js .noreverse + neg eax + xchg ebx, ecx +.noreverse: + shr eax, 16 + mov [esp+20+16], eax + mov edx, [esp+4+16] + mov eax, [esp+16+16] + add eax, eax + lea ebx, [ebx+eax-6] + lea ecx, [ecx+eax-6] + lea edx, [edx+eax-6] + neg eax + + movd mm4, dword [esp+20+16] + punpcklwd mm4, mm4 + punpckldq mm4, mm4 + + movq mm6, [rb_mask_555] + movq mm7, [g_mask_555] + +.xstart: + add eax, 6 + jbe .doodd +.xloop: + movq mm0, [ebx+eax] + movq mm1, [ecx+eax] + movq mm2, mm7 + movq mm3, mm7 + + pand mm2, mm0 + pand mm3, mm1 + pand mm0, mm6 + pand mm1, mm6 + + psubw mm3, mm2 + psubw mm1, mm0 + + pmulhw mm3, mm4 + pmulhw mm1, mm4 + + psubw mm0, mm1 + psubw mm2, mm3 + + pand mm0, mm6 + pand mm2, mm7 + + paddw mm0, mm2 + + movq [edx+eax], mm0 + add eax, 8 + jnc .xloop + +.doodd: + sub eax, 6 + jz .noodd +.odd: + movzx esi, word [ebx+eax+6] + movd mm0, esi + movzx esi, word [ecx+eax+6] + movd mm1, esi + movq mm2, mm7 + movq mm3, mm7 + + pand mm2, mm0 + pand mm3, mm1 + pand mm0, mm6 + pand mm1, mm6 + + psubw mm3, mm2 + psubw mm1, mm0 + + pmulhw mm3, mm4 + pmulhw mm1, mm4 + + psubw mm0, mm1 + psubw mm2, mm3 + + pand mm0, mm6 + pand mm2, mm7 + + paddw mm0, mm2 + + movd esi, mm0 + mov [edx+eax+6], si + add eax,2 + jne .odd + +.noodd: + emms + pop ebx + pop esi + pop edi + pop ebp + ret + + + global _vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX +_vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX: + push ebp + push edi + push esi + push ebx + + mov edx, [esp+4+16] + + mov ebx, [edx+VDPixmapReferenceStretchBltBilinearParameters.src] + mov edi, [edx+VDPixmapReferenceStretchBltBilinearParameters.dst] + + mov ecx, [edx+VDPixmapReferenceStretchBltBilinearParameters.xprecopy] + or ecx, ecx + jz .noprecopy + mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.xprepos] + mov eax, [ebx+eax] + lea ebp, [ecx*4] + sub edi, ebp + rep stosd +.noprecopy: + mov ebp, [edx+VDPixmapReferenceStretchBltBilinearParameters.xmidsize] + add ebp, ebp + add ebp, ebp + add edi, ebp + neg ebp + + mov esi, [edx+VDPixmapReferenceStretchBltBilinearParameters.u] + mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.dudx] + mov edx, [edx+VDPixmapReferenceStretchBltBilinearParameters.uinc] + movd mm2, esi + movd mm3, eax + shr ebx, 2 + + movq mm5, mm2 + punpcklwd mm5, mm5 + punpckhdq mm5, mm5 + movq mm4, mm5 + psraw mm4, 15 + +.xloop: + movd mm0, dword [ebx*4] + pxor mm7, mm7 + movd mm1, dword [ebx*4+4] + punpcklbw mm0, mm7 + punpcklbw mm1, mm7 + psubw mm1, mm0 + pand mm4, mm1 + pmulhw mm1, mm5 + paddw mm1, mm4 + paddw mm0, mm1 + packuswb mm0, mm0 + movd dword [edi+ebp], mm0 + + add esi, eax + adc ebx, edx + + paddd mm2, mm3 + movq mm5, mm2 + punpcklwd mm5, mm5 + punpckhdq mm5, mm5 + movq mm4, mm5 + psraw mm4, 15 + add ebp, 4 + jnz .xloop + + mov edx, [esp+4+16] + mov ecx, [edx+VDPixmapReferenceStretchBltBilinearParameters.xpostcopy] + or ecx, ecx + jz .nopostcopy + mov eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.xpostpos] + add eax, [edx+VDPixmapReferenceStretchBltBilinearParameters.src] + mov eax, [eax] + rep stosd +.nopostcopy: + + emms + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX +_vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+20+16] + and eax, 0ff000000h + mov ebx, [esp+8+16] + mov ecx, [esp+12+16] + jz .noreverse + xchg ebx, ecx + js .noreverse + neg eax + xchg ebx, ecx +.noreverse: + shr eax, 16 + mov [esp+20+16], eax + mov edx, [esp+4+16] + mov eax, [esp+16+16] + add eax, eax + add eax, eax + lea ebx, [ebx+eax-4] + lea ecx, [ecx+eax-4] + lea edx, [edx+eax-4] + neg eax + + movd mm4, dword [esp+20+16] + punpcklwd mm4, mm4 + punpckldq mm4, mm4 + + movq mm6, [rb_mask_888] + movq mm7, [g_mask_888] + +.xstart: + add eax, 4 + jbe .doodd +.xloop: + movq mm0, [ebx+eax] + movq mm1, [ecx+eax] + movq mm2, mm0 + movq mm3, mm1 + psrlw mm2, 8 + psrlw mm3, 8 + pand mm0, mm6 + pand mm1, mm6 + + psubw mm3, mm2 + psubw mm1, mm0 + + pmulhw mm3, mm4 + pmulhw mm1, mm4 + + psubw mm0, mm1 + psubw mm2, mm3 + + pand mm0, mm6 + + psllw mm2, 8 + + paddw mm0, mm2 + + movq qword [edx+eax], mm0 + add eax, 8 + jnc .xloop + +.doodd: + sub eax, 4 + jz .noodd +.odd: + movd mm0, dword [ebx] + movd mm1, dword [ecx] + movq mm2, mm0 + movq mm3, mm1 + psrlw mm2, 8 + psrlw mm3, 8 + pand mm0, mm6 + pand mm1, mm6 + + psubw mm3, mm2 + psubw mm1, mm0 + + pmulhw mm3, mm4 + pmulhw mm1, mm4 + + psubw mm0, mm1 + psubw mm2, mm3 + + pand mm0, mm6 + + psllw mm2, 8 + + paddw mm0, mm2 + + movd dword [edx], mm0 + +.noodd: + emms + pop ebx + pop esi + pop edi + pop ebp + ret + + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_point.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_point.asm index c00de22cb97..dca765b926f 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_point.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_stretchrgb_point.asm @@ -1,96 +1,96 @@ - segment .text - - struc scaleinfo -.dst resd 1 -.src resd 1 -.xaccum resd 1 -.xfracinc resd 1 -.xintinc resd 1 -.count resd 1 - endstruc - - global _vdasm_resize_point32 -_vdasm_resize_point32: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - - mov ebx, [eax+scaleinfo.xaccum] - mov ecx, [eax+scaleinfo.xfracinc] - mov edx, [eax+scaleinfo.src] - mov esi, [eax+scaleinfo.xintinc] - mov edi, [eax+scaleinfo.dst] - mov ebp, [eax+scaleinfo.count] -.xloop: - mov eax,[edx*4] - add ebx,ecx - adc edx,esi - mov [edi+ebp],eax - add ebp,4 - jne .xloop - - pop ebx - pop esi - pop edi - pop ebp - ret - - global _vdasm_resize_point32_MMX -_vdasm_resize_point32_MMX: - push ebp - push edi - push esi - push ebx - - mov eax, [esp+4+16] - - push 0 - push dword [fs:0] - mov dword [fs:0], esp - - mov ebx, [eax+scaleinfo.xaccum] - mov esp, [eax+scaleinfo.xfracinc] - mov edx, [eax+scaleinfo.src] - mov esi, [eax+scaleinfo.xintinc] - mov edi, [eax+scaleinfo.dst] - mov ebp, [eax+scaleinfo.count] - - mov eax, ebx - mov ecx, edx - add ebx, esp - adc edx, esi - add esp, esp - adc esi, esi - - add ebp, 4 - jz .odd -.dualloop: - movd mm0, dword [ecx*4] - punpckldq mm0,[edx*4] - add eax,esp - adc ecx,esi - add ebx,esp - adc edx,esi - movq [edi+ebp-4],mm0 - - add ebp,8 - jnc .dualloop - jnz .noodd -.odd: - mov eax, [ecx*4] - mov [edi-4], eax -.noodd: - mov esp, dword [fs:0] - pop eax - pop eax - - pop ebx - pop esi - pop edi - pop ebp - ret - - end + segment .text + + struc scaleinfo +.dst resd 1 +.src resd 1 +.xaccum resd 1 +.xfracinc resd 1 +.xintinc resd 1 +.count resd 1 + endstruc + + global _vdasm_resize_point32 +_vdasm_resize_point32: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + + mov ebx, [eax+scaleinfo.xaccum] + mov ecx, [eax+scaleinfo.xfracinc] + mov edx, [eax+scaleinfo.src] + mov esi, [eax+scaleinfo.xintinc] + mov edi, [eax+scaleinfo.dst] + mov ebp, [eax+scaleinfo.count] +.xloop: + mov eax,[edx*4] + add ebx,ecx + adc edx,esi + mov [edi+ebp],eax + add ebp,4 + jne .xloop + + pop ebx + pop esi + pop edi + pop ebp + ret + + global _vdasm_resize_point32_MMX +_vdasm_resize_point32_MMX: + push ebp + push edi + push esi + push ebx + + mov eax, [esp+4+16] + + push 0 + push dword [fs:0] + mov dword [fs:0], esp + + mov ebx, [eax+scaleinfo.xaccum] + mov esp, [eax+scaleinfo.xfracinc] + mov edx, [eax+scaleinfo.src] + mov esi, [eax+scaleinfo.xintinc] + mov edi, [eax+scaleinfo.dst] + mov ebp, [eax+scaleinfo.count] + + mov eax, ebx + mov ecx, edx + add ebx, esp + adc edx, esi + add esp, esp + adc esi, esi + + add ebp, 4 + jz .odd +.dualloop: + movd mm0, dword [ecx*4] + punpckldq mm0,[edx*4] + add eax,esp + adc ecx,esi + add ebx,esp + adc edx,esi + movq [edi+ebp-4],mm0 + + add ebp,8 + jnc .dualloop + jnz .noodd +.odd: + mov eax, [ecx*4] + mov [edi-4], eax +.noodd: + mov esp, dword [fs:0] + pop eax + pop eax + + pop ebx + pop esi + pop edi + pop ebp + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt.inc b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt.inc index dbeb5505890..fb969c56fca 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt.inc +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt.inc @@ -1,24 +1,24 @@ - struc span -.u resd 1 -.v resd 1 - endstruc - - struc mipspan -.u resd 1 -.v resd 1 -.lambda resd 1 - endstruc - - struc mipmap -.bits resd 1 -.pitch resd 1 -.uvmul resd 1 - resd 1 - endstruc - - struc texinfo -.mips resd 16*4 -.dst resd 1 -.src resd 1 -.w resd 1 - endstruc + struc span +.u resd 1 +.v resd 1 + endstruc + + struc mipspan +.u resd 1 +.v resd 1 +.lambda resd 1 + endstruc + + struc mipmap +.bits resd 1 +.pitch resd 1 +.uvmul resd 1 + resd 1 + endstruc + + struc texinfo +.mips resd 16*4 +.dst resd 1 +.src resd 1 +.w resd 1 + endstruc diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_mmx.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_mmx.asm index 82a55d6a484..3836488aa79 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_mmx.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_mmx.asm @@ -1,425 +1,425 @@ - segment .rdata, align=16 - -correct dq 0000800000008000h -round dq 0000200000002000h -round1 dq 0000020000000200h -round2 dq 0002000000020000h - - segment .text - - %include "a_triblt.inc" - - extern _kVDCubicInterpTableFX14_075_MMX - -;-------------------------------------------------------------------------- - global _vdasm_triblt_span_bilinear_mmx -_vdasm_triblt_span_bilinear_mmx: - push ebp - push edi - push esi - push ebx - mov edi,[esp+4+16] - mov edx,[edi+texinfo.dst] - mov ebp,[edi+texinfo.w] - shl ebp,2 - mov ebx,[edi+texinfo.mips+mipmap.bits] - add edx,ebp - mov esi,[edi+texinfo.mips+mipmap.pitch] - neg ebp - movd mm6,[edi+texinfo.mips+mipmap.uvmul] - pxor mm7,mm7 - mov edi,[edi+texinfo.src] -.xloop: - movq mm4,[edi] - movq mm0,mm4 - psrld mm0,16 - movq mm5,mm4 - packssdw mm0,mm0 - pmaddwd mm0,mm6 - add edi,8 - punpcklwd mm4,mm4 - punpckldq mm4,mm4 - movd ecx,mm0 - add ecx,ebx - psrlw mm4,1 - movd mm0,dword [ecx] - movd mm1,dword [ecx+4] - punpcklbw mm0,mm7 - movd mm2,dword [ecx+esi] - punpcklbw mm1,mm7 - movd mm3,dword [ecx+esi+4] - punpcklbw mm2,mm7 - punpcklbw mm3,mm7 - psubw mm1,mm0 - psubw mm3,mm2 - paddw mm1,mm1 - paddw mm3,mm3 - pmulhw mm1,mm4 - pmulhw mm3,mm4 - punpckhwd mm5,mm5 - punpckldq mm5,mm5 - paddw mm0,mm1 - psrlw mm5,1 - paddw mm2,mm3 - psubw mm2,mm0 - paddw mm2,mm2 - pmulhw mm2,mm5 - paddw mm0,mm2 - packuswb mm0,mm0 - movd dword [edx+ebp],mm0 - add ebp,4 - jnc .xloop - pop ebx - pop esi - pop edi - pop ebp - emms - ret - -;-------------------------------------------------------------------------- - global _vdasm_triblt_span_trilinear_mmx -_vdasm_triblt_span_trilinear_mmx: - push ebp - push edi - push esi - push ebx - mov esi,[esp+4+16] - mov edx,[esi+texinfo.dst] - mov ebp,[esi+texinfo.w] - shl ebp,2 - add edx,ebp - neg ebp - mov edi,[esi+texinfo.src] - pxor mm7,mm7 -.xloop: - movd mm6,[edi+mipspan.u] - punpckldq mm6,[edi+mipspan.v] - mov eax,[edi+mipspan.lambda] - shr eax,4 - and eax,byte -16 - movd mm2,eax - psrlq mm2,4 - psrld mm6,mm2 - paddd mm6,[correct] - - ;fetch mipmap 1 - mov ebx,[esi+eax+mipmap.pitch] - movd mm1,[esi+eax+mipmap.uvmul] - movq mm4,mm6 - movq mm0,mm6 - psrld mm0,16 - packssdw mm0,mm0 - pmaddwd mm0,mm1 - movq mm5,mm4 - punpcklwd mm4,mm4 - punpckldq mm4,mm4 - punpckhwd mm5,mm5 - punpckldq mm5,mm5 - movd ecx,mm0 - add ecx,[esi+eax+mipmap.bits] - psrlw mm4,1 - movd mm0,dword [ecx] - movd mm1,dword [ecx+4] - punpcklbw mm0,mm7 - movd mm2,dword [ecx+ebx] - punpcklbw mm1,mm7 - movd mm3,dword [ecx+ebx+4] - punpcklbw mm2,mm7 - punpcklbw mm3,mm7 - psubw mm1,mm0 - psubw mm3,mm2 - paddw mm1,mm1 - paddw mm3,mm3 - pmulhw mm1,mm4 - pmulhw mm3,mm4 - paddw mm0,mm1 - psrlw mm5,1 - paddw mm2,mm3 - psubw mm2,mm0 - paddw mm2,mm2 - pmulhw mm2,mm5 - paddw mm0,mm2 - - ;fetch mipmap 2 - mov ebx,[esi+eax+16+mipmap.pitch] - movd mm1,[esi+eax+16+mipmap.uvmul] - paddd mm6,[correct] - psrld mm6,1 - movq mm4,mm6 - psrld mm6,16 - packssdw mm6,mm6 - pmaddwd mm6,mm1 - movq mm5,mm4 - punpcklwd mm4,mm4 - punpckldq mm4,mm4 - punpckhwd mm5,mm5 - punpckldq mm5,mm5 - movd ecx,mm6 - add ecx,[esi+eax+16+mipmap.bits] - psrlw mm4,1 - movd mm6,dword [ecx] - movd mm1,dword [ecx+4] - punpcklbw mm6,mm7 - movd mm2,dword [ecx+ebx] - punpcklbw mm1,mm7 - movd mm3,dword [ecx+ebx+4] - punpcklbw mm2,mm7 - punpcklbw mm3,mm7 - psubw mm1,mm6 - psubw mm3,mm2 - paddw mm1,mm1 - paddw mm3,mm3 - pmulhw mm1,mm4 - pmulhw mm3,mm4 - paddw mm6,mm1 - psrlw mm5,1 - paddw mm2,mm3 - psubw mm2,mm6 - paddw mm2,mm2 - pmulhw mm2,mm5 - paddw mm6,mm2 - - ;blend mips - movd mm1,[edi+mipspan.lambda] - punpcklwd mm1,mm1 - punpckldq mm1,mm1 - psllw mm1,8 - psrlq mm1,1 - psubw mm6,mm0 - paddw mm6,mm6 - pmulhw mm6,mm1 - paddw mm0,mm6 - packuswb mm0,mm0 - - movd dword [edx+ebp],mm0 - add edi, mipspan_size - add ebp,4 - jnc .xloop - pop ebx - pop esi - pop edi - pop ebp - emms - ret - -;-------------------------------------------------------------------------- -%macro .SETUPADDR 1 - ;compute mipmap index and UV - movd mm0, [edi + mipspan.u] - punpckldq mm0, [edi + mipspan.v] - mov ebx, [edi + mipspan.lambda] - shr ebx, 4 - and ebx, byte -16 - - add ebx, mipmap_size*%1 - movd mm2, ebx - add ebx, [esp + .af_mipbase] - psrlq mm2, 4 - psrad mm0, mm2 - paddd mm0, [correct] - movq mm1, mm0 - psrlq mm1, 32 - - ;compute horizontal filters - movd ecx, mm0 - shr ecx, 4 - and ecx, 0ff0h - add ecx, _kVDCubicInterpTableFX14_075_MMX - - ;compute vertical filter - movd edx, mm1 - and edx, 0ff00h - shr edx, 4 - add edx, _kVDCubicInterpTableFX14_075_MMX - - ;compute texel address - movd mm1, [ebx + mipmap.uvmul] - psrld mm0, 16 - packssdw mm0, mm0 - pmaddwd mm0, mm1 - movd eax, mm0 - add eax, [ebx + mipmap.bits] -%endmacro - -%macro .HCUBIC 4 - movd %1, dword [eax] - punpcklbw %1, qword [eax+4] - movd %3, dword [eax+8] - punpcklbw %3, qword [eax+12] - movq %2, %1 - movq %4, %3 - punpcklbw %1, mm7 - pmaddwd %1, [ecx] - punpcklbw %3, mm7 - pmaddwd %3, [ecx+8] - punpckhbw %2, mm7 - pmaddwd %2, [ecx] - punpckhbw %4, mm7 - pmaddwd %4, [ecx+8] - paddd %1, %3 - paddd %2, %4 -%endmacro - -%macro .VCUBIC 1 - .HCUBIC mm0, mm1, mm2, mm3 - add eax, %1 - - .HCUBIC mm4, mm5, mm2, mm3 - add eax, %1 - - movq mm2, [round1] - - paddd mm0, mm2 - paddd mm1, mm2 - paddd mm4, mm2 - paddd mm5, mm2 - - psrad mm0, 10 - psrad mm1, 10 - psrad mm4, 10 - psrad mm5, 10 - - packssdw mm0, mm0 - packssdw mm1, mm1 - packssdw mm4, mm4 - packssdw mm5, mm5 - - punpcklwd mm0, mm4 - punpcklwd mm1, mm5 - - movq mm3, [edx] - - pmaddwd mm0, mm3 - pmaddwd mm1, mm3 - - movq [esp + .af_htemp0], mm0 - movq [esp + .af_htemp1], mm1 - - .HCUBIC mm0, mm1, mm2, mm3 - add eax, %1 - .HCUBIC mm4, mm5, mm2, mm3 - - movq mm2, [round1] - - paddd mm0, mm2 - paddd mm1, mm2 - paddd mm4, mm2 - paddd mm5, mm2 - - psrad mm0, 10 - psrad mm1, 10 - psrad mm4, 10 - psrad mm5, 10 - - packssdw mm0, mm0 - packssdw mm1, mm1 - packssdw mm4, mm4 - packssdw mm5, mm5 - - punpcklwd mm0, mm4 - punpcklwd mm1, mm5 - - movq mm2, [round2] - movq mm3, [edx + 8] - - pmaddwd mm0, mm3 - pmaddwd mm1, mm3 - - paddd mm0, [esp + .af_htemp0] - paddd mm1, [esp + .af_htemp1] - - paddd mm0, mm2 - paddd mm1, mm2 - - psrad mm0, 18 - psrad mm1, 18 - packssdw mm0, mm1 -%endmacro - - global _vdasm_triblt_span_bicubic_mip_linear_mmx -_vdasm_triblt_span_bicubic_mip_linear_mmx: - -;parameters -%define .p_texinfo 20 - -;aligned frame -%define .af_htemp0 0 -%define .af_htemp1 8 -%define .af_vtemp0 16 -%define .af_mipbase 24 -%define .af_prevesp 28 -%define .afsize 32 - - push ebp - lea ebp, [esp-12] - push edi - push esi - push ebx - - sub esp, .afsize - and esp, -8 - - mov [esp + .af_prevesp], ebp - - mov ebx, [ebp + .p_texinfo] - mov ebp, [ebx + texinfo.dst] - mov esi, [ebx + texinfo.w] - shl esi, 2 - add ebp,esi - neg esi - - mov edi, [ebx + texinfo.src] - mov [esp + .af_mipbase], ebx - pxor mm7, mm7 - -.xloop: - - ;registers: - ; eax base texel address - ; ebx first mip info - ; ecx horizontal filter - ; edx vertical filter - ; esi horizontal count - ; edi mipspan - ; ebp destination - - ;fetch mipmap 1 - .SETUPADDR 0 - .VCUBIC [ebx+mipmap.pitch] - - movq [esp + .af_vtemp0], mm0 - - ;fetch mipmap 2 - .SETUPADDR 1 - .VCUBIC [ebx+mipmap.pitch] - - ;blend mips - movq mm1, [esp + .af_vtemp0] - - psubw mm0, mm1 - - movd mm3,[edi+mipspan.lambda] - punpcklwd mm3,mm3 - punpckldq mm3,mm3 - psllw mm3,8 - psrlq mm3,1 - - paddw mm0,mm0 - pmulhw mm0,mm3 - paddw mm0,mm1 - packuswb mm0,mm0 - - movd dword [ebp+esi],mm0 - add edi, mipspan_size - add esi,4 - jnc .xloop - - mov esp, [esp + .af_prevesp] - pop ebx - pop esi - pop edi - pop ebp - emms - ret - - end + segment .rdata, align=16 + +correct dq 0000800000008000h +round dq 0000200000002000h +round1 dq 0000020000000200h +round2 dq 0002000000020000h + + segment .text + + %include "a_triblt.inc" + + extern _kVDCubicInterpTableFX14_075_MMX + +;-------------------------------------------------------------------------- + global _vdasm_triblt_span_bilinear_mmx +_vdasm_triblt_span_bilinear_mmx: + push ebp + push edi + push esi + push ebx + mov edi,[esp+4+16] + mov edx,[edi+texinfo.dst] + mov ebp,[edi+texinfo.w] + shl ebp,2 + mov ebx,[edi+texinfo.mips+mipmap.bits] + add edx,ebp + mov esi,[edi+texinfo.mips+mipmap.pitch] + neg ebp + movd mm6,[edi+texinfo.mips+mipmap.uvmul] + pxor mm7,mm7 + mov edi,[edi+texinfo.src] +.xloop: + movq mm4,[edi] + movq mm0,mm4 + psrld mm0,16 + movq mm5,mm4 + packssdw mm0,mm0 + pmaddwd mm0,mm6 + add edi,8 + punpcklwd mm4,mm4 + punpckldq mm4,mm4 + movd ecx,mm0 + add ecx,ebx + psrlw mm4,1 + movd mm0,dword [ecx] + movd mm1,dword [ecx+4] + punpcklbw mm0,mm7 + movd mm2,dword [ecx+esi] + punpcklbw mm1,mm7 + movd mm3,dword [ecx+esi+4] + punpcklbw mm2,mm7 + punpcklbw mm3,mm7 + psubw mm1,mm0 + psubw mm3,mm2 + paddw mm1,mm1 + paddw mm3,mm3 + pmulhw mm1,mm4 + pmulhw mm3,mm4 + punpckhwd mm5,mm5 + punpckldq mm5,mm5 + paddw mm0,mm1 + psrlw mm5,1 + paddw mm2,mm3 + psubw mm2,mm0 + paddw mm2,mm2 + pmulhw mm2,mm5 + paddw mm0,mm2 + packuswb mm0,mm0 + movd dword [edx+ebp],mm0 + add ebp,4 + jnc .xloop + pop ebx + pop esi + pop edi + pop ebp + emms + ret + +;-------------------------------------------------------------------------- + global _vdasm_triblt_span_trilinear_mmx +_vdasm_triblt_span_trilinear_mmx: + push ebp + push edi + push esi + push ebx + mov esi,[esp+4+16] + mov edx,[esi+texinfo.dst] + mov ebp,[esi+texinfo.w] + shl ebp,2 + add edx,ebp + neg ebp + mov edi,[esi+texinfo.src] + pxor mm7,mm7 +.xloop: + movd mm6,[edi+mipspan.u] + punpckldq mm6,[edi+mipspan.v] + mov eax,[edi+mipspan.lambda] + shr eax,4 + and eax,byte -16 + movd mm2,eax + psrlq mm2,4 + psrld mm6,mm2 + paddd mm6,[correct] + + ;fetch mipmap 1 + mov ebx,[esi+eax+mipmap.pitch] + movd mm1,[esi+eax+mipmap.uvmul] + movq mm4,mm6 + movq mm0,mm6 + psrld mm0,16 + packssdw mm0,mm0 + pmaddwd mm0,mm1 + movq mm5,mm4 + punpcklwd mm4,mm4 + punpckldq mm4,mm4 + punpckhwd mm5,mm5 + punpckldq mm5,mm5 + movd ecx,mm0 + add ecx,[esi+eax+mipmap.bits] + psrlw mm4,1 + movd mm0,dword [ecx] + movd mm1,dword [ecx+4] + punpcklbw mm0,mm7 + movd mm2,dword [ecx+ebx] + punpcklbw mm1,mm7 + movd mm3,dword [ecx+ebx+4] + punpcklbw mm2,mm7 + punpcklbw mm3,mm7 + psubw mm1,mm0 + psubw mm3,mm2 + paddw mm1,mm1 + paddw mm3,mm3 + pmulhw mm1,mm4 + pmulhw mm3,mm4 + paddw mm0,mm1 + psrlw mm5,1 + paddw mm2,mm3 + psubw mm2,mm0 + paddw mm2,mm2 + pmulhw mm2,mm5 + paddw mm0,mm2 + + ;fetch mipmap 2 + mov ebx,[esi+eax+16+mipmap.pitch] + movd mm1,[esi+eax+16+mipmap.uvmul] + paddd mm6,[correct] + psrld mm6,1 + movq mm4,mm6 + psrld mm6,16 + packssdw mm6,mm6 + pmaddwd mm6,mm1 + movq mm5,mm4 + punpcklwd mm4,mm4 + punpckldq mm4,mm4 + punpckhwd mm5,mm5 + punpckldq mm5,mm5 + movd ecx,mm6 + add ecx,[esi+eax+16+mipmap.bits] + psrlw mm4,1 + movd mm6,dword [ecx] + movd mm1,dword [ecx+4] + punpcklbw mm6,mm7 + movd mm2,dword [ecx+ebx] + punpcklbw mm1,mm7 + movd mm3,dword [ecx+ebx+4] + punpcklbw mm2,mm7 + punpcklbw mm3,mm7 + psubw mm1,mm6 + psubw mm3,mm2 + paddw mm1,mm1 + paddw mm3,mm3 + pmulhw mm1,mm4 + pmulhw mm3,mm4 + paddw mm6,mm1 + psrlw mm5,1 + paddw mm2,mm3 + psubw mm2,mm6 + paddw mm2,mm2 + pmulhw mm2,mm5 + paddw mm6,mm2 + + ;blend mips + movd mm1,[edi+mipspan.lambda] + punpcklwd mm1,mm1 + punpckldq mm1,mm1 + psllw mm1,8 + psrlq mm1,1 + psubw mm6,mm0 + paddw mm6,mm6 + pmulhw mm6,mm1 + paddw mm0,mm6 + packuswb mm0,mm0 + + movd dword [edx+ebp],mm0 + add edi, mipspan_size + add ebp,4 + jnc .xloop + pop ebx + pop esi + pop edi + pop ebp + emms + ret + +;-------------------------------------------------------------------------- +%macro .SETUPADDR 1 + ;compute mipmap index and UV + movd mm0, [edi + mipspan.u] + punpckldq mm0, [edi + mipspan.v] + mov ebx, [edi + mipspan.lambda] + shr ebx, 4 + and ebx, byte -16 + + add ebx, mipmap_size*%1 + movd mm2, ebx + add ebx, [esp + .af_mipbase] + psrlq mm2, 4 + psrad mm0, mm2 + paddd mm0, [correct] + movq mm1, mm0 + psrlq mm1, 32 + + ;compute horizontal filters + movd ecx, mm0 + shr ecx, 4 + and ecx, 0ff0h + add ecx, _kVDCubicInterpTableFX14_075_MMX + + ;compute vertical filter + movd edx, mm1 + and edx, 0ff00h + shr edx, 4 + add edx, _kVDCubicInterpTableFX14_075_MMX + + ;compute texel address + movd mm1, [ebx + mipmap.uvmul] + psrld mm0, 16 + packssdw mm0, mm0 + pmaddwd mm0, mm1 + movd eax, mm0 + add eax, [ebx + mipmap.bits] +%endmacro + +%macro .HCUBIC 4 + movd %1, dword [eax] + punpcklbw %1, qword [eax+4] + movd %3, dword [eax+8] + punpcklbw %3, qword [eax+12] + movq %2, %1 + movq %4, %3 + punpcklbw %1, mm7 + pmaddwd %1, [ecx] + punpcklbw %3, mm7 + pmaddwd %3, [ecx+8] + punpckhbw %2, mm7 + pmaddwd %2, [ecx] + punpckhbw %4, mm7 + pmaddwd %4, [ecx+8] + paddd %1, %3 + paddd %2, %4 +%endmacro + +%macro .VCUBIC 1 + .HCUBIC mm0, mm1, mm2, mm3 + add eax, %1 + + .HCUBIC mm4, mm5, mm2, mm3 + add eax, %1 + + movq mm2, [round1] + + paddd mm0, mm2 + paddd mm1, mm2 + paddd mm4, mm2 + paddd mm5, mm2 + + psrad mm0, 10 + psrad mm1, 10 + psrad mm4, 10 + psrad mm5, 10 + + packssdw mm0, mm0 + packssdw mm1, mm1 + packssdw mm4, mm4 + packssdw mm5, mm5 + + punpcklwd mm0, mm4 + punpcklwd mm1, mm5 + + movq mm3, [edx] + + pmaddwd mm0, mm3 + pmaddwd mm1, mm3 + + movq [esp + .af_htemp0], mm0 + movq [esp + .af_htemp1], mm1 + + .HCUBIC mm0, mm1, mm2, mm3 + add eax, %1 + .HCUBIC mm4, mm5, mm2, mm3 + + movq mm2, [round1] + + paddd mm0, mm2 + paddd mm1, mm2 + paddd mm4, mm2 + paddd mm5, mm2 + + psrad mm0, 10 + psrad mm1, 10 + psrad mm4, 10 + psrad mm5, 10 + + packssdw mm0, mm0 + packssdw mm1, mm1 + packssdw mm4, mm4 + packssdw mm5, mm5 + + punpcklwd mm0, mm4 + punpcklwd mm1, mm5 + + movq mm2, [round2] + movq mm3, [edx + 8] + + pmaddwd mm0, mm3 + pmaddwd mm1, mm3 + + paddd mm0, [esp + .af_htemp0] + paddd mm1, [esp + .af_htemp1] + + paddd mm0, mm2 + paddd mm1, mm2 + + psrad mm0, 18 + psrad mm1, 18 + packssdw mm0, mm1 +%endmacro + + global _vdasm_triblt_span_bicubic_mip_linear_mmx +_vdasm_triblt_span_bicubic_mip_linear_mmx: + +;parameters +%define .p_texinfo 20 + +;aligned frame +%define .af_htemp0 0 +%define .af_htemp1 8 +%define .af_vtemp0 16 +%define .af_mipbase 24 +%define .af_prevesp 28 +%define .afsize 32 + + push ebp + lea ebp, [esp-12] + push edi + push esi + push ebx + + sub esp, .afsize + and esp, -8 + + mov [esp + .af_prevesp], ebp + + mov ebx, [ebp + .p_texinfo] + mov ebp, [ebx + texinfo.dst] + mov esi, [ebx + texinfo.w] + shl esi, 2 + add ebp,esi + neg esi + + mov edi, [ebx + texinfo.src] + mov [esp + .af_mipbase], ebx + pxor mm7, mm7 + +.xloop: + + ;registers: + ; eax base texel address + ; ebx first mip info + ; ecx horizontal filter + ; edx vertical filter + ; esi horizontal count + ; edi mipspan + ; ebp destination + + ;fetch mipmap 1 + .SETUPADDR 0 + .VCUBIC [ebx+mipmap.pitch] + + movq [esp + .af_vtemp0], mm0 + + ;fetch mipmap 2 + .SETUPADDR 1 + .VCUBIC [ebx+mipmap.pitch] + + ;blend mips + movq mm1, [esp + .af_vtemp0] + + psubw mm0, mm1 + + movd mm3,[edi+mipspan.lambda] + punpcklwd mm3,mm3 + punpckldq mm3,mm3 + psllw mm3,8 + psrlq mm3,1 + + paddw mm0,mm0 + pmulhw mm0,mm3 + paddw mm0,mm1 + packuswb mm0,mm0 + + movd dword [ebp+esi],mm0 + add edi, mipspan_size + add esi,4 + jnc .xloop + + mov esp, [esp + .af_prevesp] + pop ebx + pop esi + pop edi + pop ebp + emms + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_scalar.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_scalar.asm index f364aa9e832..71e17802801 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_scalar.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_scalar.asm @@ -1,36 +1,36 @@ - segment .text - - %include "a_triblt.inc" - - global _vdasm_triblt_span_point -_vdasm_triblt_span_point: - push ebp - push edi - push esi - push ebx - mov eax,[esp+4+16] - mov ebp,[eax+texinfo.w] - mov ebx,[eax+texinfo.mips+mipmap.pitch] - shl ebp,2 - mov edi,[eax+texinfo.src] - mov edx,[eax+texinfo.dst] - mov ecx,[eax+texinfo.mips+mipmap.bits] - sar ebx,2 - add edx,ebp - neg ebp -.xloop: - mov eax,[edi+span.v] - imul eax,ebx - add eax,[edi+span.u] - add edi,8 - mov eax,[ecx+eax*4] - mov [edx+ebp],eax - add ebp,4 - jnc .xloop - pop ebx - pop esi - pop edi - pop ebp - ret - + segment .text + + %include "a_triblt.inc" + + global _vdasm_triblt_span_point +_vdasm_triblt_span_point: + push ebp + push edi + push esi + push ebx + mov eax,[esp+4+16] + mov ebp,[eax+texinfo.w] + mov ebx,[eax+texinfo.mips+mipmap.pitch] + shl ebp,2 + mov edi,[eax+texinfo.src] + mov edx,[eax+texinfo.dst] + mov ecx,[eax+texinfo.mips+mipmap.bits] + sar ebx,2 + add edx,ebp + neg ebp +.xloop: + mov eax,[edi+span.v] + imul eax,ebx + add eax,[edi+span.u] + add edi,8 + mov eax,[ecx+eax*4] + mov [edx+ebp],eax + add ebp,4 + jnc .xloop + pop ebx + pop esi + pop edi + pop ebp + ret + end \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_sse2.asm b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_sse2.asm index 94136757f5f..54514b31780 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_sse2.asm +++ b/src/thirdparty/VirtualDub/Kasumi/source/a_triblt_sse2.asm @@ -1,197 +1,197 @@ - segment .rdata, align=16 - -correct dq 0000800000008000h, 0000800000008000h -round dq 0000200000002000h, 0000200000002000h -round1 dq 0000020000000200h, 0000020000000200h -round2 dq 0002000000020000h, 0002000000020000h - - segment .text - - %include "a_triblt.inc" - - extern _kVDCubicInterpTableFX14_075_MMX - -;-------------------------------------------------------------------------- - global _vdasm_triblt_span_bicubic_mip_linear_sse2 -_vdasm_triblt_span_bicubic_mip_linear_sse2: - -;parameters -%define .p_texinfo 20 - -;aligned frame -%define .af_vtemp0 0 -%define .af_mipbase 16 -%define .af_prevesp 20 -%define .afsize 24 - - push ebp - lea ebp, [esp-12] - push edi - push esi - push ebx - - sub esp, .afsize - and esp, -16 - - mov [esp + .af_prevesp], ebp - - mov ebx, [ebp + .p_texinfo] - mov ebp, [ebx + texinfo.dst] - mov esi, [ebx + texinfo.w] - shl esi, 2 - add ebp,esi - neg esi - - mov edi, [ebx + texinfo.src] - mov [esp + .af_mipbase], ebx - pxor xmm7, xmm7 - -.xloop: - - ;registers: - ; eax base texel address - ; ebx first mip info - ; ecx horizontal filter - ; edx vertical filter - ; esi horizontal count - ; edi mipspan - ; ebp destination - -%macro .SETUPADDR 1 - ;compute mipmap index and UV - movd xmm0, [edi + mipspan.u] - movd xmm1, [edi + mipspan.v] - punpckldq xmm0, xmm1 - mov ebx, [edi + mipspan.lambda] - shr ebx, 4 - and ebx, byte -16 - - add ebx, mipmap_size*%1 - movd xmm2, ebx - add ebx, [esp + .af_mipbase] - psrlq xmm2, 4 - psrad xmm0, xmm2 - paddd xmm0, [correct] - pshufd xmm1, xmm0, 01010101b - - ;compute horizontal filters - movd ecx, xmm0 - shr ecx, 4 - and ecx, 0ff0h - add ecx, _kVDCubicInterpTableFX14_075_MMX - - ;compute vertical filter - movd edx, xmm1 - and edx, 0ff00h - shr edx, 4 - add edx, _kVDCubicInterpTableFX14_075_MMX - - ;compute texel address - movd xmm1, [ebx + mipmap.uvmul] - psrld xmm0, 16 - packssdw xmm0, xmm0 - pmaddwd xmm0, xmm1 - movd eax, xmm0 - add eax, [ebx + mipmap.bits] -%endmacro - -%macro .HCUBIC 4 - movd %1, dword [eax] - movd %3, dword [eax+4] - movd %2, dword [eax+8] - movd %4, dword [eax+12] - punpcklbw %1, %3 - punpcklbw %2, %4 - punpcklbw %1, xmm7 - punpcklbw %2, xmm7 - movdqa %3, [ecx] - pshufd %4, %3, 11101110b - pshufd %3, %3, 01000100b - pmaddwd %1, %3 - pmaddwd %2, %4 - paddd %1, %2 -%endmacro - -%macro .VCUBIC 1 - .HCUBIC xmm0, xmm4, xmm5, xmm6 - add eax, %1 - .HCUBIC xmm1, xmm4, xmm5, xmm6 - add eax, %1 - .HCUBIC xmm2, xmm4, xmm5, xmm6 - add eax, %1 - .HCUBIC xmm3, xmm4, xmm5, xmm6 - - movq xmm4, [round1] - - paddd xmm0, xmm4 - - paddd xmm1, xmm4 - psrad xmm0, 10 - - paddd xmm2, xmm4 - psrad xmm1, 10 - packssdw xmm0, xmm0 - - paddd xmm3, xmm4 - psrad xmm2, 10 - packssdw xmm1, xmm1 - - movdqa xmm5, [edx] - psrad xmm3, 10 - punpcklwd xmm0, xmm1 - - packssdw xmm2, xmm2 - packssdw xmm3, xmm3 - pshufd xmm4, xmm5, 01000100b - - pmaddwd xmm0, xmm4 - punpcklwd xmm2, xmm3 - - pshufd xmm5, xmm5, 11101110b - - pmaddwd xmm2, xmm5 - paddd xmm0, xmm2 - paddd xmm0, [round2] - psrad xmm0, 18 - - packssdw xmm0, xmm0 -%endmacro - - ;fetch mipmap 1 - .SETUPADDR 0 - .VCUBIC [ebx+mipmap.pitch] - - movq [esp + .af_vtemp0], xmm0 - - ;fetch mipmap 2 - .SETUPADDR 1 - .VCUBIC [ebx+mipmap.pitch] - - ;blend mips - movq xmm1, [esp + .af_vtemp0] - - psubw xmm0, xmm1 - - movd xmm3, [edi+mipspan.lambda] - pshuflw xmm3, xmm3, 0 - psllw xmm3, 8 - psrlq xmm3, 1 - - paddw xmm0, xmm0 - pmulhw xmm0, xmm3 - paddw xmm0, xmm1 - packuswb xmm0, xmm0 - - movd dword [ebp+esi], xmm0 - add edi, mipspan_size - add esi,4 - jnc .xloop - - mov esp, [esp + .af_prevesp] - pop ebx - pop esi - pop edi - pop ebp - ret - - end + segment .rdata, align=16 + +correct dq 0000800000008000h, 0000800000008000h +round dq 0000200000002000h, 0000200000002000h +round1 dq 0000020000000200h, 0000020000000200h +round2 dq 0002000000020000h, 0002000000020000h + + segment .text + + %include "a_triblt.inc" + + extern _kVDCubicInterpTableFX14_075_MMX + +;-------------------------------------------------------------------------- + global _vdasm_triblt_span_bicubic_mip_linear_sse2 +_vdasm_triblt_span_bicubic_mip_linear_sse2: + +;parameters +%define .p_texinfo 20 + +;aligned frame +%define .af_vtemp0 0 +%define .af_mipbase 16 +%define .af_prevesp 20 +%define .afsize 24 + + push ebp + lea ebp, [esp-12] + push edi + push esi + push ebx + + sub esp, .afsize + and esp, -16 + + mov [esp + .af_prevesp], ebp + + mov ebx, [ebp + .p_texinfo] + mov ebp, [ebx + texinfo.dst] + mov esi, [ebx + texinfo.w] + shl esi, 2 + add ebp,esi + neg esi + + mov edi, [ebx + texinfo.src] + mov [esp + .af_mipbase], ebx + pxor xmm7, xmm7 + +.xloop: + + ;registers: + ; eax base texel address + ; ebx first mip info + ; ecx horizontal filter + ; edx vertical filter + ; esi horizontal count + ; edi mipspan + ; ebp destination + +%macro .SETUPADDR 1 + ;compute mipmap index and UV + movd xmm0, [edi + mipspan.u] + movd xmm1, [edi + mipspan.v] + punpckldq xmm0, xmm1 + mov ebx, [edi + mipspan.lambda] + shr ebx, 4 + and ebx, byte -16 + + add ebx, mipmap_size*%1 + movd xmm2, ebx + add ebx, [esp + .af_mipbase] + psrlq xmm2, 4 + psrad xmm0, xmm2 + paddd xmm0, [correct] + pshufd xmm1, xmm0, 01010101b + + ;compute horizontal filters + movd ecx, xmm0 + shr ecx, 4 + and ecx, 0ff0h + add ecx, _kVDCubicInterpTableFX14_075_MMX + + ;compute vertical filter + movd edx, xmm1 + and edx, 0ff00h + shr edx, 4 + add edx, _kVDCubicInterpTableFX14_075_MMX + + ;compute texel address + movd xmm1, [ebx + mipmap.uvmul] + psrld xmm0, 16 + packssdw xmm0, xmm0 + pmaddwd xmm0, xmm1 + movd eax, xmm0 + add eax, [ebx + mipmap.bits] +%endmacro + +%macro .HCUBIC 4 + movd %1, dword [eax] + movd %3, dword [eax+4] + movd %2, dword [eax+8] + movd %4, dword [eax+12] + punpcklbw %1, %3 + punpcklbw %2, %4 + punpcklbw %1, xmm7 + punpcklbw %2, xmm7 + movdqa %3, [ecx] + pshufd %4, %3, 11101110b + pshufd %3, %3, 01000100b + pmaddwd %1, %3 + pmaddwd %2, %4 + paddd %1, %2 +%endmacro + +%macro .VCUBIC 1 + .HCUBIC xmm0, xmm4, xmm5, xmm6 + add eax, %1 + .HCUBIC xmm1, xmm4, xmm5, xmm6 + add eax, %1 + .HCUBIC xmm2, xmm4, xmm5, xmm6 + add eax, %1 + .HCUBIC xmm3, xmm4, xmm5, xmm6 + + movq xmm4, [round1] + + paddd xmm0, xmm4 + + paddd xmm1, xmm4 + psrad xmm0, 10 + + paddd xmm2, xmm4 + psrad xmm1, 10 + packssdw xmm0, xmm0 + + paddd xmm3, xmm4 + psrad xmm2, 10 + packssdw xmm1, xmm1 + + movdqa xmm5, [edx] + psrad xmm3, 10 + punpcklwd xmm0, xmm1 + + packssdw xmm2, xmm2 + packssdw xmm3, xmm3 + pshufd xmm4, xmm5, 01000100b + + pmaddwd xmm0, xmm4 + punpcklwd xmm2, xmm3 + + pshufd xmm5, xmm5, 11101110b + + pmaddwd xmm2, xmm5 + paddd xmm0, xmm2 + paddd xmm0, [round2] + psrad xmm0, 18 + + packssdw xmm0, xmm0 +%endmacro + + ;fetch mipmap 1 + .SETUPADDR 0 + .VCUBIC [ebx+mipmap.pitch] + + movq [esp + .af_vtemp0], xmm0 + + ;fetch mipmap 2 + .SETUPADDR 1 + .VCUBIC [ebx+mipmap.pitch] + + ;blend mips + movq xmm1, [esp + .af_vtemp0] + + psubw xmm0, xmm1 + + movd xmm3, [edi+mipspan.lambda] + pshuflw xmm3, xmm3, 0 + psllw xmm3, 8 + psrlq xmm3, 1 + + paddw xmm0, xmm0 + pmulhw xmm0, xmm3 + paddw xmm0, xmm1 + packuswb xmm0, xmm0 + + movd dword [ebp+esi], xmm0 + add edi, mipspan_size + add esi,4 + jnc .xloop + + mov esp, [esp + .af_prevesp] + pop ebx + pop esi + pop edi + pop ebp + ret + + end diff --git a/src/thirdparty/VirtualDub/Kasumi/source/alphablt.cpp b/src/thirdparty/VirtualDub/Kasumi/source/alphablt.cpp index 0e2e218613b..93501ede4f3 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/alphablt.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/alphablt.cpp @@ -1,95 +1,95 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include - -void VDPixmapBltAlphaConst8(uint8 *dst, ptrdiff_t dstpitch, const uint8 *src, ptrdiff_t srcpitch, uint32 w, uint32 h, uint32 ialpha); - -bool VDPixmapBltAlphaConst(const VDPixmap& dst, const VDPixmap& src, float alpha) { - if (!(alpha >= 0.0f)) - alpha = 0.0f; - else if (!(alpha <= 1.0f)) - alpha = 1.0f; - - uint32 ialpha = VDRoundToInt32(alpha * 256.0f); - - // format check - if (dst.format != src.format || !src.format) - return false; - - // degenerate case check - if (!dst.w || !dst.h) - return false; - - // size check - if (src.w != dst.w || src.h != dst.h) - return false; - - // check for formats that are not 8bpp - switch(src.format) { - case nsVDPixmap::kPixFormat_Pal1: - case nsVDPixmap::kPixFormat_Pal2: - case nsVDPixmap::kPixFormat_Pal4: - case nsVDPixmap::kPixFormat_Pal8: - case nsVDPixmap::kPixFormat_RGB565: - case nsVDPixmap::kPixFormat_XRGB1555: - return false; - } - - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(src.format); - - const int qw = -(-dst.w >> formatInfo.qwbits); - const int qh = -(-dst.h >> formatInfo.qhbits); - const int auxw = -(-dst.w >> formatInfo.auxwbits); - const int auxh = -(-dst.h >> formatInfo.auxhbits); - - switch(formatInfo.auxbufs) { - case 2: - VDPixmapBltAlphaConst8((uint8 *)dst.data3, dst.pitch3, (const uint8 *)src.data3, src.pitch3, auxw, auxh, ialpha); - case 1: - VDPixmapBltAlphaConst8((uint8 *)dst.data2, dst.pitch2, (const uint8 *)src.data2, src.pitch2, auxw, auxh, ialpha); - case 0: - VDPixmapBltAlphaConst8((uint8 *)dst.data, dst.pitch, (const uint8 *)src.data, src.pitch, formatInfo.qsize * qw, qh, ialpha); - } - - return true; -} - -void VDPixmapBltAlphaConst8(uint8 *dst, ptrdiff_t dstpitch, const uint8 *src, ptrdiff_t srcpitch, uint32 w, uint32 h, uint32 ialpha) { - dstpitch -= w; - srcpitch -= w; - do { - uint32 w2 = w; - do { - sint32 sc = *src; - sint32 dc = *dst; - - *dst = dc + (((sc-dc)*ialpha + 128) >> 8); - ++src; - ++dst; - } while(--w2); - - src += srcpitch; - dst += dstpitch; - } while(--h); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include + +void VDPixmapBltAlphaConst8(uint8 *dst, ptrdiff_t dstpitch, const uint8 *src, ptrdiff_t srcpitch, uint32 w, uint32 h, uint32 ialpha); + +bool VDPixmapBltAlphaConst(const VDPixmap& dst, const VDPixmap& src, float alpha) { + if (!(alpha >= 0.0f)) + alpha = 0.0f; + else if (!(alpha <= 1.0f)) + alpha = 1.0f; + + uint32 ialpha = VDRoundToInt32(alpha * 256.0f); + + // format check + if (dst.format != src.format || !src.format) + return false; + + // degenerate case check + if (!dst.w || !dst.h) + return false; + + // size check + if (src.w != dst.w || src.h != dst.h) + return false; + + // check for formats that are not 8bpp + switch(src.format) { + case nsVDPixmap::kPixFormat_Pal1: + case nsVDPixmap::kPixFormat_Pal2: + case nsVDPixmap::kPixFormat_Pal4: + case nsVDPixmap::kPixFormat_Pal8: + case nsVDPixmap::kPixFormat_RGB565: + case nsVDPixmap::kPixFormat_XRGB1555: + return false; + } + + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(src.format); + + const int qw = -(-dst.w >> formatInfo.qwbits); + const int qh = -(-dst.h >> formatInfo.qhbits); + const int auxw = -(-dst.w >> formatInfo.auxwbits); + const int auxh = -(-dst.h >> formatInfo.auxhbits); + + switch(formatInfo.auxbufs) { + case 2: + VDPixmapBltAlphaConst8((uint8 *)dst.data3, dst.pitch3, (const uint8 *)src.data3, src.pitch3, auxw, auxh, ialpha); + case 1: + VDPixmapBltAlphaConst8((uint8 *)dst.data2, dst.pitch2, (const uint8 *)src.data2, src.pitch2, auxw, auxh, ialpha); + case 0: + VDPixmapBltAlphaConst8((uint8 *)dst.data, dst.pitch, (const uint8 *)src.data, src.pitch, formatInfo.qsize * qw, qh, ialpha); + } + + return true; +} + +void VDPixmapBltAlphaConst8(uint8 *dst, ptrdiff_t dstpitch, const uint8 *src, ptrdiff_t srcpitch, uint32 w, uint32 h, uint32 ialpha) { + dstpitch -= w; + srcpitch -= w; + do { + uint32 w2 = w; + do { + sint32 sc = *src; + sint32 dc = *dst; + + *dst = dc + (((sc-dc)*ialpha + 128) >> 8); + ++src; + ++dst; + } while(--w2); + + src += srcpitch; + dst += dstpitch; + } while(--h); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blitter.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blitter.cpp index a9542e2584d..0879424d242 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blitter.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blitter.cpp @@ -1,52 +1,52 @@ -#include -#include - -VDPixmapCachedBlitter::VDPixmapCachedBlitter() - : mSrcWidth(0) - , mSrcHeight(0) - , mSrcFormat(0) - , mDstWidth(0) - , mDstHeight(0) - , mDstFormat(0) - , mpCachedBlitter(NULL) -{ -} - -VDPixmapCachedBlitter::~VDPixmapCachedBlitter() { - Invalidate(); -} - -void VDPixmapCachedBlitter::Blit(const VDPixmap& dst, const VDPixmap& src) { - VDASSERT(src.w == dst.w && src.h == dst.h); - - if (!mpCachedBlitter || - dst.w != mDstWidth || - dst.h != mDstHeight || - dst.format != mDstFormat || - src.w != mSrcWidth || - src.h != mSrcHeight || - src.format != mSrcFormat) - { - if (mpCachedBlitter) - delete mpCachedBlitter; - mpCachedBlitter = VDPixmapCreateBlitter(dst, src); - if (!mpCachedBlitter) - return; - - mDstWidth = dst.w; - mDstHeight = dst.h; - mDstFormat = dst.format; - mSrcWidth = src.w; - mSrcHeight = src.h; - mSrcFormat = src.format; - } - - mpCachedBlitter->Blit(dst, src); -} - -void VDPixmapCachedBlitter::Invalidate() { - if (mpCachedBlitter) { - delete mpCachedBlitter; - mpCachedBlitter = NULL; - } -} +#include +#include + +VDPixmapCachedBlitter::VDPixmapCachedBlitter() + : mSrcWidth(0) + , mSrcHeight(0) + , mSrcFormat(0) + , mDstWidth(0) + , mDstHeight(0) + , mDstFormat(0) + , mpCachedBlitter(NULL) +{ +} + +VDPixmapCachedBlitter::~VDPixmapCachedBlitter() { + Invalidate(); +} + +void VDPixmapCachedBlitter::Blit(const VDPixmap& dst, const VDPixmap& src) { + VDASSERT(src.w == dst.w && src.h == dst.h); + + if (!mpCachedBlitter || + dst.w != mDstWidth || + dst.h != mDstHeight || + dst.format != mDstFormat || + src.w != mSrcWidth || + src.h != mSrcHeight || + src.format != mSrcFormat) + { + if (mpCachedBlitter) + delete mpCachedBlitter; + mpCachedBlitter = VDPixmapCreateBlitter(dst, src); + if (!mpCachedBlitter) + return; + + mDstWidth = dst.w; + mDstHeight = dst.h; + mDstFormat = dst.format; + mSrcWidth = src.w; + mSrcHeight = src.h; + mSrcFormat = src.format; + } + + mpCachedBlitter->Blit(dst, src); +} + +void VDPixmapCachedBlitter::Invalidate() { + if (mpCachedBlitter) { + delete mpCachedBlitter; + mpCachedBlitter = NULL; + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt.cpp index a003217bb0f..7a3fabea006 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt.cpp @@ -1,292 +1,292 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace nsVDPixmap; - -namespace { - typedef void (*tpPalettedBlitter)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal); - typedef void (*tpChunkyBlitter)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); - typedef void (*tpPlanarBlitter)(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -} - -bool VDPixmapBltDirect(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); - -void VDPixmapBltDirectPalettedConversion(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h, tpPalettedBlitter pBlitter) { - uint8 palbytes[256 * 3]; - - int palsize; - - switch(src.format) { - case kPixFormat_Pal1: - palsize = 2; - break; - case kPixFormat_Pal2: - palsize = 4; - break; - case kPixFormat_Pal4: - palsize = 16; - break; - case kPixFormat_Pal8: - palsize = 256; - break; - default: - VDNEVERHERE; - } - - VDASSERT(src.palette); - - VDPixmap srcpal = { (void *)src.palette, NULL, palsize, 1, 0, kPixFormat_XRGB8888 }; - VDPixmap dstpal = { palbytes, NULL, palsize, 1, 0, dst.format }; - - VDVERIFY(VDPixmapBltDirect(dstpal, srcpal, palsize, 1)); - - pBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h, palbytes); -} - -tpVDPixBltTable VDPixmapGetBlitterTable() { -#if defined(_WIN32) && defined(_M_IX86) - static tpVDPixBltTable pBltTable; - - if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) { - return VDGetPixBltTableX86MMX(); - } else { - return VDGetPixBltTableX86Scalar(); - } -#else - static tpVDPixBltTable pBltTable = VDGetPixBltTableReference(); - return pBltTable; -#endif -} - -bool VDPixmapBltDirect(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - if ((unsigned)src.format >= kPixFormat_Max_Standard) { - VDASSERT(false); - return false; - } - - if ((unsigned)dst.format >= kPixFormat_Max_Standard) { - VDASSERT(false); - return false; - } - - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); - - if (src.format == dst.format) { - int qw = w; - int qh = h; - - if (srcinfo.qchunky) { - qw = (qw + srcinfo.qw - 1) / srcinfo.qw; - qh = -(-h >> srcinfo.qhbits); - } - - const int auxw = -(-w >> srcinfo.auxwbits); - const int auxh = -(-h >> srcinfo.auxhbits); - - switch(srcinfo.auxbufs) { - case 2: - VDMemcpyRect(dst.data3, dst.pitch3, src.data3, src.pitch3, srcinfo.auxsize * auxw, auxh); - case 1: - VDMemcpyRect(dst.data2, dst.pitch2, src.data2, src.pitch2, srcinfo.auxsize * auxw, auxh); - case 0: - VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, srcinfo.qsize * qw, qh); - } - - return true; - } - - VDPixmapBlitterFn pBlitter = VDPixmapGetBlitterTable()[src.format][dst.format]; - - if (!pBlitter) - return false; - - pBlitter(dst, src, w, h); - return true; -} - -bool VDPixmapIsBltPossible(int dst_format, int src_format) { - if (src_format == dst_format) - return true; - - tpVDPixBltTable tab(VDPixmapGetBlitterTable()); - - if (tab[src_format][dst_format]) - return true; - - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src_format); - const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dst_format); - - if (srcinfo.auxbufs > 0 || dstinfo.auxbufs > 0) - return false; // fail, planar buffers involved (can't do scanlines independently) - - return (tab[src_format][kPixFormat_YUV444_XVYU] && tab[kPixFormat_YUV444_XVYU][dst_format]) - ||(tab[src_format][kPixFormat_XRGB8888] && tab[kPixFormat_XRGB8888][dst_format]); -} - -bool VDNOINLINE VDPixmapBltTwoStage(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); - const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dst.format); - - if (srcinfo.auxbufs > 0 || dstinfo.auxbufs > 0) - return false; // fail, planar buffers involved - - if (srcinfo.qh > 1) - return false; // fail, vertically packed formats involved - - if (srcinfo.palsize) - return false; // fail, paletted formats involved - - // Allocate a 4xW buffer and try round-tripping through either - // RGB32 or XYVU. - vdblock tempBuf; - - tpVDPixBltTable tab(VDPixmapGetBlitterTable()); - - VDPixmap linesrc(src); - VDPixmap linedst(dst); - VDPixmap linetmp = {}; - - if (w < 1024) { - linetmp.data = alloca(sizeof(uint32) * w); - } else { - tempBuf.resize(w + 1); - linetmp.data = tempBuf.data(); - } - linetmp.pitch = 0; - linetmp.format = kPixFormat_YUV444_XVYU; - linetmp.w = w; - linetmp.h = 1; - - VDPixmapBlitterFn pb1 = tab[src.format][kPixFormat_YUV444_XVYU]; - VDPixmapBlitterFn pb2 = tab[kPixFormat_YUV444_XVYU][dst.format]; - if (!pb1 || !pb2) { - pb1 = tab[src.format][kPixFormat_XRGB8888]; - pb2 = tab[kPixFormat_XRGB8888][dst.format]; - if (!pb1 || !pb2) - return false; - - linetmp.format = kPixFormat_XRGB8888; - } - - do { - pb1(linetmp, linesrc, w, 1); - pb2(linedst, linetmp, w, 1); - vdptrstep(linesrc.data, linesrc.pitch); - vdptrstep(linedst.data, linedst.pitch); - } while(--h); - return true; -} - -bool VDPixmapBltFast(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - if (w <= 0 || h <= 0) { - VDASSERT((w|h) >= 0); - return true; - } - - if (VDPixmapBltDirect(dst, src, w, h)) - return true; - - // Oro... let's see if we can do a two-stage conversion. - return VDPixmapBltTwoStage(dst, src, w, h); -} - -bool VDPixmapBlt(const VDPixmap& dst, const VDPixmap& src) { - vdpixsize w = std::min(src.w, dst.w); - vdpixsize h = std::min(src.h, dst.h); - - if (!w || !h) - return true; - - return VDPixmapBltFast(dst, src, w, h); -} - -bool VDPixmapBlt(const VDPixmap& dst, vdpixpos x1, vdpixpos y1, const VDPixmap& src, vdpixpos x2, vdpixpos y2, vdpixsize w, vdpixsize h) { - if (x1 < 0) { - x2 -= x1; - w -= x1; - x1 = 0; - } - - if (y1 < 0) { - y2 -= y1; - h -= y1; - y1 = 0; - } - - if (x2 < 0) { - x1 -= x2; - w -= x2; - x2 = 0; - } - - if (y2 < 0) { - y1 -= y2; - h -= y2; - y2 = 0; - } - - if (w > dst.w - x1) - w = dst.w - x1; - - if (h > dst.h - y1) - h = dst.h - y1; - - if (w > src.w - x2) - w = src.w - x2; - - if (h > src.h - y2) - h = src.h - y2; - - if (w>=0 && h >= 0) { - VDPixmap dst2(VDPixmapOffset(dst, x1, y1)); - VDPixmap src2(VDPixmapOffset(src, x2, y2)); - - return VDPixmapBltFast(dst2, src2, w, h); - } - - return true; -} - -extern bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); -extern bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); - -bool VDPixmapStretchBltNearest(const VDPixmap& dst, const VDPixmap& src) { - return VDPixmapStretchBltNearest(dst, 0, 0, dst.w<<16, dst.h<<16, src, 0, 0, src.w<<16, src.h<<16); -} - -bool VDPixmapStretchBltNearest(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { - return VDPixmapStretchBltNearest_reference(dst, x1, y1, x2, y2, src, u1, v1, u2, v2); -} - -bool VDPixmapStretchBltBilinear(const VDPixmap& dst, const VDPixmap& src) { - return VDPixmapStretchBltBilinear(dst, 0, 0, dst.w<<16, dst.h<<16, src, 0, 0, src.w<<16, src.h<<16); -} - -bool VDPixmapStretchBltBilinear(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { - return VDPixmapStretchBltBilinear_reference(dst, x1, y1, x2, y2, src, u1, v1, u2, v2); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace nsVDPixmap; + +namespace { + typedef void (*tpPalettedBlitter)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal); + typedef void (*tpChunkyBlitter)(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); + typedef void (*tpPlanarBlitter)(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +} + +bool VDPixmapBltDirect(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); + +void VDPixmapBltDirectPalettedConversion(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h, tpPalettedBlitter pBlitter) { + uint8 palbytes[256 * 3]; + + int palsize; + + switch(src.format) { + case kPixFormat_Pal1: + palsize = 2; + break; + case kPixFormat_Pal2: + palsize = 4; + break; + case kPixFormat_Pal4: + palsize = 16; + break; + case kPixFormat_Pal8: + palsize = 256; + break; + default: + VDNEVERHERE; + } + + VDASSERT(src.palette); + + VDPixmap srcpal = { (void *)src.palette, NULL, palsize, 1, 0, kPixFormat_XRGB8888 }; + VDPixmap dstpal = { palbytes, NULL, palsize, 1, 0, dst.format }; + + VDVERIFY(VDPixmapBltDirect(dstpal, srcpal, palsize, 1)); + + pBlitter(dst.data, dst.pitch, src.data, src.pitch, w, h, palbytes); +} + +tpVDPixBltTable VDPixmapGetBlitterTable() { +#if defined(_WIN32) && defined(_M_IX86) + static tpVDPixBltTable pBltTable; + + if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) { + return VDGetPixBltTableX86MMX(); + } else { + return VDGetPixBltTableX86Scalar(); + } +#else + static tpVDPixBltTable pBltTable = VDGetPixBltTableReference(); + return pBltTable; +#endif +} + +bool VDPixmapBltDirect(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + if ((unsigned)src.format >= kPixFormat_Max_Standard) { + VDASSERT(false); + return false; + } + + if ((unsigned)dst.format >= kPixFormat_Max_Standard) { + VDASSERT(false); + return false; + } + + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); + + if (src.format == dst.format) { + int qw = w; + int qh = h; + + if (srcinfo.qchunky) { + qw = (qw + srcinfo.qw - 1) / srcinfo.qw; + qh = -(-h >> srcinfo.qhbits); + } + + const int auxw = -(-w >> srcinfo.auxwbits); + const int auxh = -(-h >> srcinfo.auxhbits); + + switch(srcinfo.auxbufs) { + case 2: + VDMemcpyRect(dst.data3, dst.pitch3, src.data3, src.pitch3, srcinfo.auxsize * auxw, auxh); + case 1: + VDMemcpyRect(dst.data2, dst.pitch2, src.data2, src.pitch2, srcinfo.auxsize * auxw, auxh); + case 0: + VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, srcinfo.qsize * qw, qh); + } + + return true; + } + + VDPixmapBlitterFn pBlitter = VDPixmapGetBlitterTable()[src.format][dst.format]; + + if (!pBlitter) + return false; + + pBlitter(dst, src, w, h); + return true; +} + +bool VDPixmapIsBltPossible(int dst_format, int src_format) { + if (src_format == dst_format) + return true; + + tpVDPixBltTable tab(VDPixmapGetBlitterTable()); + + if (tab[src_format][dst_format]) + return true; + + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src_format); + const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dst_format); + + if (srcinfo.auxbufs > 0 || dstinfo.auxbufs > 0) + return false; // fail, planar buffers involved (can't do scanlines independently) + + return (tab[src_format][kPixFormat_YUV444_XVYU] && tab[kPixFormat_YUV444_XVYU][dst_format]) + ||(tab[src_format][kPixFormat_XRGB8888] && tab[kPixFormat_XRGB8888][dst_format]); +} + +bool VDNOINLINE VDPixmapBltTwoStage(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); + const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dst.format); + + if (srcinfo.auxbufs > 0 || dstinfo.auxbufs > 0) + return false; // fail, planar buffers involved + + if (srcinfo.qh > 1) + return false; // fail, vertically packed formats involved + + if (srcinfo.palsize) + return false; // fail, paletted formats involved + + // Allocate a 4xW buffer and try round-tripping through either + // RGB32 or XYVU. + vdblock tempBuf; + + tpVDPixBltTable tab(VDPixmapGetBlitterTable()); + + VDPixmap linesrc(src); + VDPixmap linedst(dst); + VDPixmap linetmp = {}; + + if (w < 1024) { + linetmp.data = alloca(sizeof(uint32) * w); + } else { + tempBuf.resize(w + 1); + linetmp.data = tempBuf.data(); + } + linetmp.pitch = 0; + linetmp.format = kPixFormat_YUV444_XVYU; + linetmp.w = w; + linetmp.h = 1; + + VDPixmapBlitterFn pb1 = tab[src.format][kPixFormat_YUV444_XVYU]; + VDPixmapBlitterFn pb2 = tab[kPixFormat_YUV444_XVYU][dst.format]; + if (!pb1 || !pb2) { + pb1 = tab[src.format][kPixFormat_XRGB8888]; + pb2 = tab[kPixFormat_XRGB8888][dst.format]; + if (!pb1 || !pb2) + return false; + + linetmp.format = kPixFormat_XRGB8888; + } + + do { + pb1(linetmp, linesrc, w, 1); + pb2(linedst, linetmp, w, 1); + vdptrstep(linesrc.data, linesrc.pitch); + vdptrstep(linedst.data, linedst.pitch); + } while(--h); + return true; +} + +bool VDPixmapBltFast(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + if (w <= 0 || h <= 0) { + VDASSERT((w|h) >= 0); + return true; + } + + if (VDPixmapBltDirect(dst, src, w, h)) + return true; + + // Oro... let's see if we can do a two-stage conversion. + return VDPixmapBltTwoStage(dst, src, w, h); +} + +bool VDPixmapBlt(const VDPixmap& dst, const VDPixmap& src) { + vdpixsize w = std::min(src.w, dst.w); + vdpixsize h = std::min(src.h, dst.h); + + if (!w || !h) + return true; + + return VDPixmapBltFast(dst, src, w, h); +} + +bool VDPixmapBlt(const VDPixmap& dst, vdpixpos x1, vdpixpos y1, const VDPixmap& src, vdpixpos x2, vdpixpos y2, vdpixsize w, vdpixsize h) { + if (x1 < 0) { + x2 -= x1; + w -= x1; + x1 = 0; + } + + if (y1 < 0) { + y2 -= y1; + h -= y1; + y1 = 0; + } + + if (x2 < 0) { + x1 -= x2; + w -= x2; + x2 = 0; + } + + if (y2 < 0) { + y1 -= y2; + h -= y2; + y2 = 0; + } + + if (w > dst.w - x1) + w = dst.w - x1; + + if (h > dst.h - y1) + h = dst.h - y1; + + if (w > src.w - x2) + w = src.w - x2; + + if (h > src.h - y2) + h = src.h - y2; + + if (w>=0 && h >= 0) { + VDPixmap dst2(VDPixmapOffset(dst, x1, y1)); + VDPixmap src2(VDPixmapOffset(src, x2, y2)); + + return VDPixmapBltFast(dst2, src2, w, h); + } + + return true; +} + +extern bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); +extern bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); + +bool VDPixmapStretchBltNearest(const VDPixmap& dst, const VDPixmap& src) { + return VDPixmapStretchBltNearest(dst, 0, 0, dst.w<<16, dst.h<<16, src, 0, 0, src.w<<16, src.h<<16); +} + +bool VDPixmapStretchBltNearest(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { + return VDPixmapStretchBltNearest_reference(dst, x1, y1, x2, y2, src, u1, v1, u2, v2); +} + +bool VDPixmapStretchBltBilinear(const VDPixmap& dst, const VDPixmap& src) { + return VDPixmapStretchBltBilinear(dst, 0, 0, dst.w<<16, dst.h<<16, src, 0, 0, src.w<<16, src.h<<16); +} + +bool VDPixmapStretchBltBilinear(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { + return VDPixmapStretchBltBilinear_reference(dst, x1, y1, x2, y2, src, u1, v1, u2, v2); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference.cpp index 0c826f18549..4ee033bde02 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference.cpp @@ -1,344 +1,344 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include "blt_setup.h" - -#define DECLARE_PALETTED(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0) -#define DECLARE_RGB(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV_PLANAR(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) - -DECLARE_RGB(RGB565, XRGB1555); -DECLARE_RGB(RGB888, XRGB1555); -DECLARE_RGB(XRGB8888, XRGB1555); -DECLARE_RGB(XRGB1555, RGB565); -DECLARE_RGB(RGB888, RGB565); -DECLARE_RGB(XRGB8888, RGB565); -DECLARE_RGB(XRGB1555, RGB888); -DECLARE_RGB(RGB565, RGB888); -DECLARE_RGB(XRGB8888, RGB888); -DECLARE_RGB(XRGB1555, XRGB8888); -DECLARE_RGB(RGB565, XRGB8888); -DECLARE_RGB(RGB888, XRGB8888); - -DECLARE_PALETTED(Pal1, Any8); -DECLARE_PALETTED(Pal1, Any16); -DECLARE_PALETTED(Pal1, Any24); -DECLARE_PALETTED(Pal1, Any32); -DECLARE_PALETTED(Pal2, Any8); -DECLARE_PALETTED(Pal2, Any16); -DECLARE_PALETTED(Pal2, Any24); -DECLARE_PALETTED(Pal2, Any32); -DECLARE_PALETTED(Pal4, Any8); -DECLARE_PALETTED(Pal4, Any16); -DECLARE_PALETTED(Pal4, Any24); -DECLARE_PALETTED(Pal4, Any32); -DECLARE_PALETTED(Pal8, Any8); -DECLARE_PALETTED(Pal8, Any16); -DECLARE_PALETTED(Pal8, Any24); -DECLARE_PALETTED(Pal8, Any32); - -DECLARE_YUV(XVYU, UYVY); -DECLARE_YUV(XVYU, YUYV); -DECLARE_YUV(Y8, UYVY); -DECLARE_YUV(Y8, YUYV); -DECLARE_YUV(UYVY, Y8); -DECLARE_YUV(YUYV, Y8); -DECLARE_YUV(UYVY, YUYV); -DECLARE_YUV_PLANAR(YUV411, YV12); - -DECLARE_YUV(UYVY, XRGB1555); -DECLARE_YUV(UYVY, RGB565); -DECLARE_YUV(UYVY, RGB888); -DECLARE_YUV(UYVY, XRGB8888); -DECLARE_YUV(YUYV, XRGB1555); -DECLARE_YUV(YUYV, RGB565); -DECLARE_YUV(YUYV, RGB888); -DECLARE_YUV(YUYV, XRGB8888); -DECLARE_YUV(Y8, XRGB1555); -DECLARE_YUV(Y8, RGB565); -DECLARE_YUV(Y8, RGB888); -DECLARE_YUV(Y8, XRGB8888); - -DECLARE_YUV_REV(XRGB1555, Y8); -DECLARE_YUV_REV(RGB565, Y8); -DECLARE_YUV_REV(RGB888, Y8); -DECLARE_YUV_REV(XRGB8888, Y8); - -DECLARE_YUV_REV(XRGB1555, XVYU); -DECLARE_YUV_REV(RGB565, XVYU); -DECLARE_YUV_REV(RGB888, XVYU); -DECLARE_YUV_REV(XRGB8888, XVYU); - -DECLARE_YUV_PLANAR(YV12, XRGB1555); -DECLARE_YUV_PLANAR(YV12, RGB565); -DECLARE_YUV_PLANAR(YV12, RGB888); -DECLARE_YUV_PLANAR(YV12, XRGB8888); - -DECLARE_YUV_PLANAR(YUV411, XRGB1555); -DECLARE_YUV_PLANAR(YUV411, RGB565); -DECLARE_YUV_PLANAR(YUV411, RGB888); -DECLARE_YUV_PLANAR(YUV411, XRGB8888); - -extern void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_UberblitAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); - -using namespace nsVDPixmap; - -void VDPixmapInitBlittersReference(VDPixmapBlitterTable& table) { - // use uberblit as the baseline - VDPixmapFormatSubset uberblitSrcFormats; - VDPixmapFormatSubset uberblitDstFormats; - - uberblitSrcFormats = - kPixFormat_Pal1, - kPixFormat_Pal2, - kPixFormat_Pal4, - kPixFormat_Pal8, - kPixFormat_XRGB1555, - kPixFormat_RGB565, - kPixFormat_RGB888, - kPixFormat_XRGB8888, - kPixFormat_Y8, - kPixFormat_YUV422_UYVY, - kPixFormat_YUV422_YUYV, - kPixFormat_YUV444_XVYU, - kPixFormat_YUV444_Planar, - kPixFormat_YUV422_Planar, - kPixFormat_YUV422_Planar_16F, - kPixFormat_YUV420_Planar, - kPixFormat_YUV411_Planar, - kPixFormat_YUV410_Planar, - kPixFormat_YUV422_Planar_Centered, - kPixFormat_YUV420_Planar_Centered, - kPixFormat_YUV422_V210, - kPixFormat_YUV422_UYVY_709, - kPixFormat_YUV420_NV12, - kPixFormat_Y8_FR, - kPixFormat_YUV422_YUYV_709, - kPixFormat_YUV444_Planar_709, - kPixFormat_YUV422_Planar_709, - kPixFormat_YUV420_Planar_709, - kPixFormat_YUV411_Planar_709, - kPixFormat_YUV410_Planar_709, - kPixFormat_YUV422_UYVY_FR, - kPixFormat_YUV422_YUYV_FR, - kPixFormat_YUV444_Planar_FR, - kPixFormat_YUV422_Planar_FR, - kPixFormat_YUV420_Planar_FR, - kPixFormat_YUV411_Planar_FR, - kPixFormat_YUV410_Planar_FR, - kPixFormat_YUV422_UYVY_709_FR, - kPixFormat_YUV422_YUYV_709_FR, - kPixFormat_YUV444_Planar_709_FR, - kPixFormat_YUV422_Planar_709_FR, - kPixFormat_YUV420_Planar_709_FR, - kPixFormat_YUV411_Planar_709_FR, - kPixFormat_YUV410_Planar_709_FR, - kPixFormat_YUV420i_Planar, - kPixFormat_YUV420i_Planar_FR, - kPixFormat_YUV420i_Planar_709, - kPixFormat_YUV420i_Planar_709_FR, - kPixFormat_YUV420it_Planar, - kPixFormat_YUV420it_Planar_FR, - kPixFormat_YUV420it_Planar_709, - kPixFormat_YUV420it_Planar_709_FR, - kPixFormat_YUV420ib_Planar, - kPixFormat_YUV420ib_Planar_FR, - kPixFormat_YUV420ib_Planar_709, - kPixFormat_YUV420ib_Planar_709_FR; - - uberblitDstFormats = - kPixFormat_XRGB1555, - kPixFormat_RGB565, - kPixFormat_RGB888, - kPixFormat_XRGB8888, - kPixFormat_Y8, - kPixFormat_YUV422_UYVY, - kPixFormat_YUV422_YUYV, - kPixFormat_YUV444_XVYU, - kPixFormat_YUV444_Planar, - kPixFormat_YUV422_Planar, - kPixFormat_YUV422_Planar_16F, - kPixFormat_YUV420_Planar, - kPixFormat_YUV411_Planar, - kPixFormat_YUV410_Planar, - kPixFormat_YUV422_Planar_Centered, - kPixFormat_YUV420_Planar_Centered, - kPixFormat_YUV422_V210, - kPixFormat_YUV422_UYVY_709, - kPixFormat_YUV420_NV12, - kPixFormat_Y8_FR, - kPixFormat_YUV422_YUYV_709, - kPixFormat_YUV444_Planar_709, - kPixFormat_YUV422_Planar_709, - kPixFormat_YUV420_Planar_709, - kPixFormat_YUV411_Planar_709, - kPixFormat_YUV410_Planar_709, - kPixFormat_YUV422_UYVY_FR, - kPixFormat_YUV422_YUYV_FR, - kPixFormat_YUV444_Planar_FR, - kPixFormat_YUV422_Planar_FR, - kPixFormat_YUV420_Planar_FR, - kPixFormat_YUV411_Planar_FR, - kPixFormat_YUV410_Planar_FR, - kPixFormat_YUV422_UYVY_709_FR, - kPixFormat_YUV422_YUYV_709_FR, - kPixFormat_YUV444_Planar_709_FR, - kPixFormat_YUV422_Planar_709_FR, - kPixFormat_YUV420_Planar_709_FR, - kPixFormat_YUV411_Planar_709_FR, - kPixFormat_YUV410_Planar_709_FR, - kPixFormat_YUV420i_Planar, - kPixFormat_YUV420i_Planar_FR, - kPixFormat_YUV420i_Planar_709, - kPixFormat_YUV420i_Planar_709_FR, - kPixFormat_YUV420it_Planar, - kPixFormat_YUV420it_Planar_FR, - kPixFormat_YUV420it_Planar_709, - kPixFormat_YUV420it_Planar_709_FR, - kPixFormat_YUV420ib_Planar, - kPixFormat_YUV420ib_Planar_FR, - kPixFormat_YUV420ib_Planar_709, - kPixFormat_YUV420ib_Planar_709_FR; - - table.AddBlitter(uberblitSrcFormats, uberblitDstFormats, VDPixmapBlt_UberblitAdapter); - - // standard formats - - table.AddBlitter(kPixFormat_Pal1, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal1, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal1, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal1, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal1, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal2, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal4, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); - table.AddBlitter(kPixFormat_Pal8, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); - - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_YUV444_XVYU, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV444_XVYU, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_Y8, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); - - table.AddBlitter(kPixFormat_YUV411_Planar, kPixFormat_YUV420_Planar, VDPixmapBlt_YUV411_to_YV12_reference); - - table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); // not an error -- same routine - - ////////////////////////////////////////////////////////// - - VDPixmapFormatSubset srcFormats; - VDPixmapFormatSubset dstFormats; - - srcFormats = kPixFormat_YUV444_Planar, - kPixFormat_YUV422_Planar, - kPixFormat_YUV420_Planar, - kPixFormat_YUV411_Planar, - kPixFormat_YUV410_Planar, - kPixFormat_YUV422_Planar_Centered, - kPixFormat_YUV420_Planar_Centered; - - dstFormats = kPixFormat_XRGB1555, kPixFormat_RGB565, kPixFormat_RGB888, kPixFormat_XRGB8888, kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV; - - table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_decode_reference); - - ////////////////////////////////////////////////////////// - - dstFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; - srcFormats = kPixFormat_XRGB1555, kPixFormat_RGB565, kPixFormat_RGB888, kPixFormat_XRGB8888, kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV; - - table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_encode_reference); - - ////////////////////////////////////////////////////////// - - srcFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_Y8, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; - dstFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_Y8, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; - - table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_convert_reference); -} - -tpVDPixBltTable VDGetPixBltTableReferenceInternal() { - static VDPixmapBlitterTable sReferenceTable; - - VDPixmapInitBlittersReference(sReferenceTable); - - return sReferenceTable.mTable; -} - -tpVDPixBltTable VDGetPixBltTableReference() { - static tpVDPixBltTable spTable = VDGetPixBltTableReferenceInternal(); - - return spTable; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include "blt_setup.h" + +#define DECLARE_PALETTED(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0) +#define DECLARE_RGB(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV_PLANAR(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) + +DECLARE_RGB(RGB565, XRGB1555); +DECLARE_RGB(RGB888, XRGB1555); +DECLARE_RGB(XRGB8888, XRGB1555); +DECLARE_RGB(XRGB1555, RGB565); +DECLARE_RGB(RGB888, RGB565); +DECLARE_RGB(XRGB8888, RGB565); +DECLARE_RGB(XRGB1555, RGB888); +DECLARE_RGB(RGB565, RGB888); +DECLARE_RGB(XRGB8888, RGB888); +DECLARE_RGB(XRGB1555, XRGB8888); +DECLARE_RGB(RGB565, XRGB8888); +DECLARE_RGB(RGB888, XRGB8888); + +DECLARE_PALETTED(Pal1, Any8); +DECLARE_PALETTED(Pal1, Any16); +DECLARE_PALETTED(Pal1, Any24); +DECLARE_PALETTED(Pal1, Any32); +DECLARE_PALETTED(Pal2, Any8); +DECLARE_PALETTED(Pal2, Any16); +DECLARE_PALETTED(Pal2, Any24); +DECLARE_PALETTED(Pal2, Any32); +DECLARE_PALETTED(Pal4, Any8); +DECLARE_PALETTED(Pal4, Any16); +DECLARE_PALETTED(Pal4, Any24); +DECLARE_PALETTED(Pal4, Any32); +DECLARE_PALETTED(Pal8, Any8); +DECLARE_PALETTED(Pal8, Any16); +DECLARE_PALETTED(Pal8, Any24); +DECLARE_PALETTED(Pal8, Any32); + +DECLARE_YUV(XVYU, UYVY); +DECLARE_YUV(XVYU, YUYV); +DECLARE_YUV(Y8, UYVY); +DECLARE_YUV(Y8, YUYV); +DECLARE_YUV(UYVY, Y8); +DECLARE_YUV(YUYV, Y8); +DECLARE_YUV(UYVY, YUYV); +DECLARE_YUV_PLANAR(YUV411, YV12); + +DECLARE_YUV(UYVY, XRGB1555); +DECLARE_YUV(UYVY, RGB565); +DECLARE_YUV(UYVY, RGB888); +DECLARE_YUV(UYVY, XRGB8888); +DECLARE_YUV(YUYV, XRGB1555); +DECLARE_YUV(YUYV, RGB565); +DECLARE_YUV(YUYV, RGB888); +DECLARE_YUV(YUYV, XRGB8888); +DECLARE_YUV(Y8, XRGB1555); +DECLARE_YUV(Y8, RGB565); +DECLARE_YUV(Y8, RGB888); +DECLARE_YUV(Y8, XRGB8888); + +DECLARE_YUV_REV(XRGB1555, Y8); +DECLARE_YUV_REV(RGB565, Y8); +DECLARE_YUV_REV(RGB888, Y8); +DECLARE_YUV_REV(XRGB8888, Y8); + +DECLARE_YUV_REV(XRGB1555, XVYU); +DECLARE_YUV_REV(RGB565, XVYU); +DECLARE_YUV_REV(RGB888, XVYU); +DECLARE_YUV_REV(XRGB8888, XVYU); + +DECLARE_YUV_PLANAR(YV12, XRGB1555); +DECLARE_YUV_PLANAR(YV12, RGB565); +DECLARE_YUV_PLANAR(YV12, RGB888); +DECLARE_YUV_PLANAR(YV12, XRGB8888); + +DECLARE_YUV_PLANAR(YUV411, XRGB1555); +DECLARE_YUV_PLANAR(YUV411, RGB565); +DECLARE_YUV_PLANAR(YUV411, RGB888); +DECLARE_YUV_PLANAR(YUV411, XRGB8888); + +extern void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_UberblitAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); + +using namespace nsVDPixmap; + +void VDPixmapInitBlittersReference(VDPixmapBlitterTable& table) { + // use uberblit as the baseline + VDPixmapFormatSubset uberblitSrcFormats; + VDPixmapFormatSubset uberblitDstFormats; + + uberblitSrcFormats = + kPixFormat_Pal1, + kPixFormat_Pal2, + kPixFormat_Pal4, + kPixFormat_Pal8, + kPixFormat_XRGB1555, + kPixFormat_RGB565, + kPixFormat_RGB888, + kPixFormat_XRGB8888, + kPixFormat_Y8, + kPixFormat_YUV422_UYVY, + kPixFormat_YUV422_YUYV, + kPixFormat_YUV444_XVYU, + kPixFormat_YUV444_Planar, + kPixFormat_YUV422_Planar, + kPixFormat_YUV422_Planar_16F, + kPixFormat_YUV420_Planar, + kPixFormat_YUV411_Planar, + kPixFormat_YUV410_Planar, + kPixFormat_YUV422_Planar_Centered, + kPixFormat_YUV420_Planar_Centered, + kPixFormat_YUV422_V210, + kPixFormat_YUV422_UYVY_709, + kPixFormat_YUV420_NV12, + kPixFormat_Y8_FR, + kPixFormat_YUV422_YUYV_709, + kPixFormat_YUV444_Planar_709, + kPixFormat_YUV422_Planar_709, + kPixFormat_YUV420_Planar_709, + kPixFormat_YUV411_Planar_709, + kPixFormat_YUV410_Planar_709, + kPixFormat_YUV422_UYVY_FR, + kPixFormat_YUV422_YUYV_FR, + kPixFormat_YUV444_Planar_FR, + kPixFormat_YUV422_Planar_FR, + kPixFormat_YUV420_Planar_FR, + kPixFormat_YUV411_Planar_FR, + kPixFormat_YUV410_Planar_FR, + kPixFormat_YUV422_UYVY_709_FR, + kPixFormat_YUV422_YUYV_709_FR, + kPixFormat_YUV444_Planar_709_FR, + kPixFormat_YUV422_Planar_709_FR, + kPixFormat_YUV420_Planar_709_FR, + kPixFormat_YUV411_Planar_709_FR, + kPixFormat_YUV410_Planar_709_FR, + kPixFormat_YUV420i_Planar, + kPixFormat_YUV420i_Planar_FR, + kPixFormat_YUV420i_Planar_709, + kPixFormat_YUV420i_Planar_709_FR, + kPixFormat_YUV420it_Planar, + kPixFormat_YUV420it_Planar_FR, + kPixFormat_YUV420it_Planar_709, + kPixFormat_YUV420it_Planar_709_FR, + kPixFormat_YUV420ib_Planar, + kPixFormat_YUV420ib_Planar_FR, + kPixFormat_YUV420ib_Planar_709, + kPixFormat_YUV420ib_Planar_709_FR; + + uberblitDstFormats = + kPixFormat_XRGB1555, + kPixFormat_RGB565, + kPixFormat_RGB888, + kPixFormat_XRGB8888, + kPixFormat_Y8, + kPixFormat_YUV422_UYVY, + kPixFormat_YUV422_YUYV, + kPixFormat_YUV444_XVYU, + kPixFormat_YUV444_Planar, + kPixFormat_YUV422_Planar, + kPixFormat_YUV422_Planar_16F, + kPixFormat_YUV420_Planar, + kPixFormat_YUV411_Planar, + kPixFormat_YUV410_Planar, + kPixFormat_YUV422_Planar_Centered, + kPixFormat_YUV420_Planar_Centered, + kPixFormat_YUV422_V210, + kPixFormat_YUV422_UYVY_709, + kPixFormat_YUV420_NV12, + kPixFormat_Y8_FR, + kPixFormat_YUV422_YUYV_709, + kPixFormat_YUV444_Planar_709, + kPixFormat_YUV422_Planar_709, + kPixFormat_YUV420_Planar_709, + kPixFormat_YUV411_Planar_709, + kPixFormat_YUV410_Planar_709, + kPixFormat_YUV422_UYVY_FR, + kPixFormat_YUV422_YUYV_FR, + kPixFormat_YUV444_Planar_FR, + kPixFormat_YUV422_Planar_FR, + kPixFormat_YUV420_Planar_FR, + kPixFormat_YUV411_Planar_FR, + kPixFormat_YUV410_Planar_FR, + kPixFormat_YUV422_UYVY_709_FR, + kPixFormat_YUV422_YUYV_709_FR, + kPixFormat_YUV444_Planar_709_FR, + kPixFormat_YUV422_Planar_709_FR, + kPixFormat_YUV420_Planar_709_FR, + kPixFormat_YUV411_Planar_709_FR, + kPixFormat_YUV410_Planar_709_FR, + kPixFormat_YUV420i_Planar, + kPixFormat_YUV420i_Planar_FR, + kPixFormat_YUV420i_Planar_709, + kPixFormat_YUV420i_Planar_709_FR, + kPixFormat_YUV420it_Planar, + kPixFormat_YUV420it_Planar_FR, + kPixFormat_YUV420it_Planar_709, + kPixFormat_YUV420it_Planar_709_FR, + kPixFormat_YUV420ib_Planar, + kPixFormat_YUV420ib_Planar_FR, + kPixFormat_YUV420ib_Planar_709, + kPixFormat_YUV420ib_Planar_709_FR; + + table.AddBlitter(uberblitSrcFormats, uberblitDstFormats, VDPixmapBlt_UberblitAdapter); + + // standard formats + + table.AddBlitter(kPixFormat_Pal1, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal1, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal1, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal1, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal1, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal2, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal4, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_Y8, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_XRGB1555, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_RGB565, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_RGB888, VDPixmapBlitterPalettedAdapter); + table.AddBlitter(kPixFormat_Pal8, kPixFormat_XRGB8888, VDPixmapBlitterPalettedAdapter); + + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_YUV444_XVYU, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV444_XVYU, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_Y8, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_YUV444_XVYU, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_Y8, VDPixmapBlitterChunkyAdapter); + + table.AddBlitter(kPixFormat_YUV411_Planar, kPixFormat_YUV420_Planar, VDPixmapBlt_YUV411_to_YV12_reference); + + table.AddBlitter(kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_YUV422_YUYV, kPixFormat_YUV422_UYVY, VDPixmapBlitterChunkyAdapter); // not an error -- same routine + + ////////////////////////////////////////////////////////// + + VDPixmapFormatSubset srcFormats; + VDPixmapFormatSubset dstFormats; + + srcFormats = kPixFormat_YUV444_Planar, + kPixFormat_YUV422_Planar, + kPixFormat_YUV420_Planar, + kPixFormat_YUV411_Planar, + kPixFormat_YUV410_Planar, + kPixFormat_YUV422_Planar_Centered, + kPixFormat_YUV420_Planar_Centered; + + dstFormats = kPixFormat_XRGB1555, kPixFormat_RGB565, kPixFormat_RGB888, kPixFormat_XRGB8888, kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV; + + table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_decode_reference); + + ////////////////////////////////////////////////////////// + + dstFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; + srcFormats = kPixFormat_XRGB1555, kPixFormat_RGB565, kPixFormat_RGB888, kPixFormat_XRGB8888, kPixFormat_YUV422_UYVY, kPixFormat_YUV422_YUYV; + + table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_encode_reference); + + ////////////////////////////////////////////////////////// + + srcFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_Y8, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; + dstFormats = kPixFormat_YUV444_Planar, kPixFormat_YUV422_Planar, kPixFormat_YUV420_Planar, kPixFormat_YUV411_Planar, kPixFormat_YUV410_Planar, kPixFormat_Y8, kPixFormat_YUV422_Planar_Centered, kPixFormat_YUV420_Planar_Centered; + + table.AddBlitter(srcFormats, dstFormats, VDPixmapBlt_YUVPlanar_convert_reference); +} + +tpVDPixBltTable VDGetPixBltTableReferenceInternal() { + static VDPixmapBlitterTable sReferenceTable; + + VDPixmapInitBlittersReference(sReferenceTable); + + return sReferenceTable.mTable; +} + +tpVDPixBltTable VDGetPixBltTableReference() { + static tpVDPixBltTable spTable = VDGetPixBltTableReferenceInternal(); + + return spTable; +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_pal.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_pal.cpp index debf3c253cb..4bf5a5f7156 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_pal.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_pal.cpp @@ -1,564 +1,564 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include - -#define DECLARE_PALETTED(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0) - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: Pal1 -> -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_PALETTED(Pal1, Any8) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 3; - dst += (w-1) & ~7; - - srcpitch += (w+7) >> 3; - dstpitch += (w+7) & ~7; - - do { - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - - switch(wt & 7) { - do { - v = src[0]; - - case 0: dst[7] = pal[v&1]; v >>= 1; - case 7: dst[6] = pal[v&1]; v >>= 1; - case 6: dst[5] = pal[v&1]; v >>= 1; - case 5: dst[4] = pal[v&1]; v >>= 1; - case 4: dst[3] = pal[v&1]; v >>= 1; - case 3: dst[2] = pal[v&1]; v >>= 1; - case 2: dst[1] = pal[v&1]; v >>= 1; - case 1: dst[0] = pal[v&1]; v >>= 1; - - dst -= 8; - --src; - } while((wt -= 8) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal1, Any16) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - const uint16 *pal = (const uint16 *)pal0; - - src += (w-1) >> 3; - dst += (w-1) & ~7; - - srcpitch += (w+7) >> 3; - dstpitch += ((w+7) & ~7) * 2; - - do { - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - - switch(wt & 7) { - do { - v = src[0]; - - case 0: dst[7] = pal[v&1]; v >>= 1; - case 7: dst[6] = pal[v&1]; v >>= 1; - case 6: dst[5] = pal[v&1]; v >>= 1; - case 5: dst[4] = pal[v&1]; v >>= 1; - case 4: dst[3] = pal[v&1]; v >>= 1; - case 3: dst[2] = pal[v&1]; v >>= 1; - case 2: dst[1] = pal[v&1]; v >>= 1; - case 1: dst[0] = pal[v&1]; v >>= 1; - - dst -= 8; - --src; - } while((wt -= 8) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal1, Any24) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 3; - dst += ((w-1) & ~7) * 3; - - srcpitch += (w+7) >> 3; - dstpitch += ((w+7) & ~7) * 3; - - do { - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - const uint8 *pe; - - switch(wt & 7) { - do { - v = src[0]; - - case 0: pe = &pal[3*(v&1)]; dst[7*3+0] = pe[0]; dst[7*3+1] = pe[1]; dst[7*3+2] = pe[2]; v >>= 1; - case 7: pe = &pal[3*(v&1)]; dst[6*3+0] = pe[0]; dst[6*3+1] = pe[1]; dst[6*3+2] = pe[2]; v >>= 1; - case 6: pe = &pal[3*(v&1)]; dst[5*3+0] = pe[0]; dst[5*3+1] = pe[1]; dst[5*3+2] = pe[2]; v >>= 1; - case 5: pe = &pal[3*(v&1)]; dst[4*3+0] = pe[0]; dst[4*3+1] = pe[1]; dst[4*3+2] = pe[2]; v >>= 1; - case 4: pe = &pal[3*(v&1)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 1; - case 3: pe = &pal[3*(v&1)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 1; - case 2: pe = &pal[3*(v&1)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 1; - case 1: pe = &pal[3*(v&1)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 1; - - dst -= 24; - --src; - } while((wt -= 8) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal1, Any32) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - const uint32 *pal = (const uint32 *)pal0; - - src += (w-1) >> 3; - dst += (w-1) & ~7; - - srcpitch += (w+7) >> 3; - dstpitch += ((w+7) & ~7) * 4; - - do { - int wt = w; - - uint8 v = src[0] >> ((-wt) & 7); - - switch(wt & 7) { - do { - v = src[0]; - - case 0: dst[7] = pal[v&1]; v >>= 1; - case 7: dst[6] = pal[v&1]; v >>= 1; - case 6: dst[5] = pal[v&1]; v >>= 1; - case 5: dst[4] = pal[v&1]; v >>= 1; - case 4: dst[3] = pal[v&1]; v >>= 1; - case 3: dst[2] = pal[v&1]; v >>= 1; - case 2: dst[1] = pal[v&1]; v >>= 1; - case 1: dst[0] = pal[v&1]; v >>= 1; - - dst -= 8; - --src; - } while((wt -= 8) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: Pal2 -> -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_PALETTED(Pal2, Any8) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 2; - dst += (w-1) & ~3; - - srcpitch += (w+3) >> 2; - dstpitch += (w+3) & ~3; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - - switch(wt & 3) { - do { - v = src[0]; - - case 0: dst[3] = pal[v&3]; v >>= 2; - case 3: dst[2] = pal[v&3]; v >>= 2; - case 2: dst[1] = pal[v&3]; v >>= 2; - case 1: dst[0] = pal[v&3]; v >>= 2; - - dst -= 4; - --src; - } while((wt -= 4) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal2, Any16) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - const uint16 *pal = (const uint16 *)pal0; - - src += (w-1) >> 2; - dst += (w-1) & ~3; - - srcpitch += (w+3) >> 2; - dstpitch += ((w+3) & ~3) * 2; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - - switch(wt & 3) { - do { - v = src[0]; - - case 0: dst[3] = pal[v&3]; v >>= 2; - case 3: dst[2] = pal[v&3]; v >>= 2; - case 2: dst[1] = pal[v&3]; v >>= 2; - case 1: dst[0] = pal[v&3]; v >>= 2; - - dst -= 4; - --src; - } while((wt -= 4) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal2, Any24) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 2; - dst += ((w-1) & ~3) * 3; - - srcpitch += (w+3) >> 2; - dstpitch += ((w+3) & ~3) * 3; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - const uint8 *pe; - - switch(wt & 3) { - do { - v = src[0]; - - case 0: pe = &pal[3*(v&3)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 2; - case 3: pe = &pal[3*(v&3)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 2; - case 2: pe = &pal[3*(v&3)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 2; - case 1: pe = &pal[3*(v&3)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 2; - - dst -= 12; - --src; - } while((wt -= 4) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal2, Any32) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - const uint32 *pal = (const uint32 *)pal0; - - src += (w-1) >> 2; - dst += (w-1) & ~3; - - srcpitch += (w+3) >> 2; - dstpitch += ((w+3) & ~3) * 4; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 3)*2); - - switch(wt & 3) { - do { - v = src[0]; - - case 0: dst[3] = pal[v&3]; v >>= 2; - case 3: dst[2] = pal[v&3]; v >>= 2; - case 2: dst[1] = pal[v&3]; v >>= 2; - case 1: dst[0] = pal[v&3]; v >>= 2; - - dst -= 4; - --src; - } while((wt -= 4) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: Pal4 -> -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_PALETTED(Pal4, Any8) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 1; - dst += ((w-1) & ~1); - - srcpitch += (w+1) >> 1; - dstpitch += (w+1) & ~1; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - - switch(wt & 1) { - do { - v = src[0]; - - case 0: dst[1] = pal[v&15]; v >>= 4; - case 1: dst[0] = pal[v&15]; v >>= 4; - - dst -= 2; - --src; - } while((wt -= 2) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal4, Any16) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - const uint16 *pal = (const uint16 *)pal0; - - src += (w-1) >> 1; - dst += ((w-1) & ~1); - - srcpitch += (w+1) >> 1; - dstpitch += ((w+1) & ~1) * 2; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - - switch(wt & 1) { - do { - v = src[0]; - - case 0: dst[1] = pal[v&15]; v >>= 4; - case 1: dst[0] = pal[v&15]; v >>= 4; - - dst -= 2; - --src; - } while((wt -= 2) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal4, Any24) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - src += (w-1) >> 1; - dst += ((w-1) & ~1) * 3; - - srcpitch += (w+1) >> 1; - dstpitch += ((w+1) & ~1) * 3; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - const uint8 *pe; - - switch(wt & 1) { - do { - v = src[0]; - - case 0: pe = &pal[3*(v&15)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 4; - case 1: pe = &pal[3*(v&15)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 4; - - dst -= 6; - --src; - } while((wt -= 2) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal4, Any32) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - const uint32 *pal = (const uint32 *)pal0; - - src += (w-1) >> 1; - dst += ((w-1) & ~1); - - srcpitch += (w+1) >> 1; - dstpitch += ((w+1) & ~1) * 4; - - do { - int wt = w; - - uint8 v = src[0] >> (((-wt) & 1)*4); - - switch(wt & 1) { - do { - v = src[0]; - - case 0: dst[1] = pal[v&15]; v >>= 4; - case 1: dst[0] = pal[v&15]; v >>= 4; - - dst -= 2; - --src; - } while((wt -= 2) > 0); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: Pal8 -> -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_PALETTED(Pal8, Any8) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - srcpitch -= w; - dstpitch -= w; - - do { - int wt = w; - - do { - *dst++ = pal[*src++]; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal8, Any16) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - const uint16 *pal = (const uint16 *)pal0; - - srcpitch -= w; - dstpitch -= w*2; - - do { - int wt = w; - - do { - *dst++ = pal[*src++]; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal8, Any24) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - const uint8 *pal = (const uint8 *)pal0; - - srcpitch -= w; - dstpitch -= w*3; - - do { - int wt = w; - do { - const uint8 *pe = &pal[3**src++]; - - dst[0] = pe[0]; - dst[1] = pe[1]; - dst[2] = pe[2]; - dst += 3; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_PALETTED(Pal8, Any32) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - const uint32 *pal = (const uint32 *)pal0; - - srcpitch -= w; - dstpitch -= w*4; - - do { - int wt = w; - - do { - *dst++ = pal[*src++]; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include + +#define DECLARE_PALETTED(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0) + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: Pal1 -> +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_PALETTED(Pal1, Any8) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 3; + dst += (w-1) & ~7; + + srcpitch += (w+7) >> 3; + dstpitch += (w+7) & ~7; + + do { + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + + switch(wt & 7) { + do { + v = src[0]; + + case 0: dst[7] = pal[v&1]; v >>= 1; + case 7: dst[6] = pal[v&1]; v >>= 1; + case 6: dst[5] = pal[v&1]; v >>= 1; + case 5: dst[4] = pal[v&1]; v >>= 1; + case 4: dst[3] = pal[v&1]; v >>= 1; + case 3: dst[2] = pal[v&1]; v >>= 1; + case 2: dst[1] = pal[v&1]; v >>= 1; + case 1: dst[0] = pal[v&1]; v >>= 1; + + dst -= 8; + --src; + } while((wt -= 8) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal1, Any16) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + const uint16 *pal = (const uint16 *)pal0; + + src += (w-1) >> 3; + dst += (w-1) & ~7; + + srcpitch += (w+7) >> 3; + dstpitch += ((w+7) & ~7) * 2; + + do { + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + + switch(wt & 7) { + do { + v = src[0]; + + case 0: dst[7] = pal[v&1]; v >>= 1; + case 7: dst[6] = pal[v&1]; v >>= 1; + case 6: dst[5] = pal[v&1]; v >>= 1; + case 5: dst[4] = pal[v&1]; v >>= 1; + case 4: dst[3] = pal[v&1]; v >>= 1; + case 3: dst[2] = pal[v&1]; v >>= 1; + case 2: dst[1] = pal[v&1]; v >>= 1; + case 1: dst[0] = pal[v&1]; v >>= 1; + + dst -= 8; + --src; + } while((wt -= 8) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal1, Any24) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 3; + dst += ((w-1) & ~7) * 3; + + srcpitch += (w+7) >> 3; + dstpitch += ((w+7) & ~7) * 3; + + do { + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + const uint8 *pe; + + switch(wt & 7) { + do { + v = src[0]; + + case 0: pe = &pal[3*(v&1)]; dst[7*3+0] = pe[0]; dst[7*3+1] = pe[1]; dst[7*3+2] = pe[2]; v >>= 1; + case 7: pe = &pal[3*(v&1)]; dst[6*3+0] = pe[0]; dst[6*3+1] = pe[1]; dst[6*3+2] = pe[2]; v >>= 1; + case 6: pe = &pal[3*(v&1)]; dst[5*3+0] = pe[0]; dst[5*3+1] = pe[1]; dst[5*3+2] = pe[2]; v >>= 1; + case 5: pe = &pal[3*(v&1)]; dst[4*3+0] = pe[0]; dst[4*3+1] = pe[1]; dst[4*3+2] = pe[2]; v >>= 1; + case 4: pe = &pal[3*(v&1)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 1; + case 3: pe = &pal[3*(v&1)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 1; + case 2: pe = &pal[3*(v&1)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 1; + case 1: pe = &pal[3*(v&1)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 1; + + dst -= 24; + --src; + } while((wt -= 8) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal1, Any32) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + const uint32 *pal = (const uint32 *)pal0; + + src += (w-1) >> 3; + dst += (w-1) & ~7; + + srcpitch += (w+7) >> 3; + dstpitch += ((w+7) & ~7) * 4; + + do { + int wt = w; + + uint8 v = src[0] >> ((-wt) & 7); + + switch(wt & 7) { + do { + v = src[0]; + + case 0: dst[7] = pal[v&1]; v >>= 1; + case 7: dst[6] = pal[v&1]; v >>= 1; + case 6: dst[5] = pal[v&1]; v >>= 1; + case 5: dst[4] = pal[v&1]; v >>= 1; + case 4: dst[3] = pal[v&1]; v >>= 1; + case 3: dst[2] = pal[v&1]; v >>= 1; + case 2: dst[1] = pal[v&1]; v >>= 1; + case 1: dst[0] = pal[v&1]; v >>= 1; + + dst -= 8; + --src; + } while((wt -= 8) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: Pal2 -> +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_PALETTED(Pal2, Any8) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 2; + dst += (w-1) & ~3; + + srcpitch += (w+3) >> 2; + dstpitch += (w+3) & ~3; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + + switch(wt & 3) { + do { + v = src[0]; + + case 0: dst[3] = pal[v&3]; v >>= 2; + case 3: dst[2] = pal[v&3]; v >>= 2; + case 2: dst[1] = pal[v&3]; v >>= 2; + case 1: dst[0] = pal[v&3]; v >>= 2; + + dst -= 4; + --src; + } while((wt -= 4) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal2, Any16) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + const uint16 *pal = (const uint16 *)pal0; + + src += (w-1) >> 2; + dst += (w-1) & ~3; + + srcpitch += (w+3) >> 2; + dstpitch += ((w+3) & ~3) * 2; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + + switch(wt & 3) { + do { + v = src[0]; + + case 0: dst[3] = pal[v&3]; v >>= 2; + case 3: dst[2] = pal[v&3]; v >>= 2; + case 2: dst[1] = pal[v&3]; v >>= 2; + case 1: dst[0] = pal[v&3]; v >>= 2; + + dst -= 4; + --src; + } while((wt -= 4) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal2, Any24) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 2; + dst += ((w-1) & ~3) * 3; + + srcpitch += (w+3) >> 2; + dstpitch += ((w+3) & ~3) * 3; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + const uint8 *pe; + + switch(wt & 3) { + do { + v = src[0]; + + case 0: pe = &pal[3*(v&3)]; dst[3*3+0] = pe[0]; dst[3*3+1] = pe[1]; dst[3*3+2] = pe[2]; v >>= 2; + case 3: pe = &pal[3*(v&3)]; dst[2*3+0] = pe[0]; dst[2*3+1] = pe[1]; dst[2*3+2] = pe[2]; v >>= 2; + case 2: pe = &pal[3*(v&3)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 2; + case 1: pe = &pal[3*(v&3)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 2; + + dst -= 12; + --src; + } while((wt -= 4) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal2, Any32) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + const uint32 *pal = (const uint32 *)pal0; + + src += (w-1) >> 2; + dst += (w-1) & ~3; + + srcpitch += (w+3) >> 2; + dstpitch += ((w+3) & ~3) * 4; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 3)*2); + + switch(wt & 3) { + do { + v = src[0]; + + case 0: dst[3] = pal[v&3]; v >>= 2; + case 3: dst[2] = pal[v&3]; v >>= 2; + case 2: dst[1] = pal[v&3]; v >>= 2; + case 1: dst[0] = pal[v&3]; v >>= 2; + + dst -= 4; + --src; + } while((wt -= 4) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: Pal4 -> +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_PALETTED(Pal4, Any8) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 1; + dst += ((w-1) & ~1); + + srcpitch += (w+1) >> 1; + dstpitch += (w+1) & ~1; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + + switch(wt & 1) { + do { + v = src[0]; + + case 0: dst[1] = pal[v&15]; v >>= 4; + case 1: dst[0] = pal[v&15]; v >>= 4; + + dst -= 2; + --src; + } while((wt -= 2) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal4, Any16) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + const uint16 *pal = (const uint16 *)pal0; + + src += (w-1) >> 1; + dst += ((w-1) & ~1); + + srcpitch += (w+1) >> 1; + dstpitch += ((w+1) & ~1) * 2; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + + switch(wt & 1) { + do { + v = src[0]; + + case 0: dst[1] = pal[v&15]; v >>= 4; + case 1: dst[0] = pal[v&15]; v >>= 4; + + dst -= 2; + --src; + } while((wt -= 2) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal4, Any24) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + src += (w-1) >> 1; + dst += ((w-1) & ~1) * 3; + + srcpitch += (w+1) >> 1; + dstpitch += ((w+1) & ~1) * 3; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + const uint8 *pe; + + switch(wt & 1) { + do { + v = src[0]; + + case 0: pe = &pal[3*(v&15)]; dst[1*3+0] = pe[0]; dst[1*3+1] = pe[1]; dst[1*3+2] = pe[2]; v >>= 4; + case 1: pe = &pal[3*(v&15)]; dst[0*3+0] = pe[0]; dst[0*3+1] = pe[1]; dst[0*3+2] = pe[2]; v >>= 4; + + dst -= 6; + --src; + } while((wt -= 2) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal4, Any32) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + const uint32 *pal = (const uint32 *)pal0; + + src += (w-1) >> 1; + dst += ((w-1) & ~1); + + srcpitch += (w+1) >> 1; + dstpitch += ((w+1) & ~1) * 4; + + do { + int wt = w; + + uint8 v = src[0] >> (((-wt) & 1)*4); + + switch(wt & 1) { + do { + v = src[0]; + + case 0: dst[1] = pal[v&15]; v >>= 4; + case 1: dst[0] = pal[v&15]; v >>= 4; + + dst -= 2; + --src; + } while((wt -= 2) > 0); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: Pal8 -> +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_PALETTED(Pal8, Any8) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + srcpitch -= w; + dstpitch -= w; + + do { + int wt = w; + + do { + *dst++ = pal[*src++]; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal8, Any16) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + const uint16 *pal = (const uint16 *)pal0; + + srcpitch -= w; + dstpitch -= w*2; + + do { + int wt = w; + + do { + *dst++ = pal[*src++]; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal8, Any24) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + const uint8 *pal = (const uint8 *)pal0; + + srcpitch -= w; + dstpitch -= w*3; + + do { + int wt = w; + do { + const uint8 *pe = &pal[3**src++]; + + dst[0] = pe[0]; + dst[1] = pe[1]; + dst[2] = pe[2]; + dst += 3; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_PALETTED(Pal8, Any32) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + const uint32 *pal = (const uint32 *)pal0; + + srcpitch -= w; + dstpitch -= w*4; + + do { + int wt = w; + + do { + *dst++ = pal[*src++]; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_rgb.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_rgb.cpp index b3bf695ec8d..8f7c2df6a18 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_rgb.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_rgb.cpp @@ -1,329 +1,329 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include - -#define DECLARE_RGB(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: -> XRGB1555 -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_RGB(RGB565, XRGB1555) { - const uint16 *src = (const uint16 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - *dst++ = (px&0x001f) + ((px&0xffc0)>>1); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB888, XRGB1555) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 3*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 r = ((uint32)src[2] & 0xf8) << 7; - const uint32 g = ((uint32)src[1] & 0xf8) << 2; - const uint32 b = (uint32)src[0] >> 3; - src += 3; - - *dst++ = (uint16)(r + g + b); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(XRGB8888, XRGB1555) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 4*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 r = ((uint32)src[2] & 0xf8) << 7; - const uint32 g = ((uint32)src[1] & 0xf8) << 2; - const uint32 b = (uint32)src[0] >> 3; - src += 4; - - *dst++ = (uint16)(r + g + b); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: -> RGB565 -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_RGB(XRGB1555, RGB565) { - const uint16 *src = (const uint16 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - *dst++ = (uint16)(px + (px&0xffe0) + ((px&0x0200)>>4)); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB888, RGB565) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 3*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 r = ((uint32)src[2] & 0xf8) << 8; - const uint32 g = ((uint32)src[1] & 0xfc) << 3; - const uint32 b = (uint32)src[0] >> 3; - src += 3; - - *dst++ = (uint16)(r + g + b); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(XRGB8888, RGB565) { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - srcpitch -= 4*w; - dstpitch -= 2*w; - - do { - int wt = w; - - do { - const uint32 r = ((uint32)src[2] & 0xf8) << 8; - const uint32 g = ((uint32)src[1] & 0xfc) << 3; - const uint32 b = (uint32)src[0] >> 3; - src += 4; - - *dst++ = (uint16)(r + g + b); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: -> RGB888 -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_RGB(XRGB1555, RGB888) { - const uint16 *src = (const uint16 *)src0; - uint8 *dst = (uint8 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 3*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - uint32 rb = px & 0x7c1f; - uint32 g = px & 0x03e0; - - rb += rb<<5; - g += g<<5; - - dst[0] = (uint8)(rb>>2); - dst[1] = (uint8)(g>>7); - dst[2] = (uint8)(rb>>12); - dst += 3; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB565, RGB888) { - const uint16 *src = (const uint16 *)src0; - uint8 *dst = (uint8 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 3*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - uint32 rb = px & 0xf81f; - uint32 g = px & 0x07e0; - - rb += rb<<5; - g += g<<6; - - dst[0] = (uint8)(rb>>2); - dst[1] = (uint8)(g>>9); - dst[2] = (uint8)(rb>>13); - dst += 3; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(XRGB8888, RGB888) { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - srcpitch -= 4*w; - dstpitch -= 3*w; - - do { - int wt = w; - - do { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst += 3; - src += 4; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -/////////////////////////////////////////////////////////////////////////// -// -// RGB blitters: -> XRGB8888 -// -/////////////////////////////////////////////////////////////////////////// - -DECLARE_RGB(XRGB1555, XRGB8888) { - const uint16 *src = (const uint16 *)src0; - uint32 *dst = (uint32 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 4*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - const uint32 rgb = ((px & 0x7c00) << 9) + ((px & 0x03e0) << 6) + ((px & 0x001f) << 3); - - *dst++ = rgb + ((rgb & 0xe0e0e0)>>5); - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB565, XRGB8888) { - const uint16 *src = (const uint16 *)src0; - uint32 *dst = (uint32 *)dst0; - - srcpitch -= 2*w; - dstpitch -= 4*w; - - do { - int wt = w; - - do { - const uint32 px = *src++; - const uint32 rb = ((px & 0xf800) << 8) + ((px & 0x001f) << 3); - const uint32 g = ((px & 0x07e0) << 5) + (px & 0x0300); - - *dst++ = rb + ((rb & 0xe000e0)>>5) + g; - } while(--wt); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_RGB(RGB888, XRGB8888) { - const uint8 *src = (const uint8 *)src0; - uint32 *dst = (uint32 *)dst0; - - srcpitch -= 3*w; - dstpitch -= 4*w; - - do { - int wt = w; - - do { - *dst++ = (uint32)src[0] + ((uint32)src[1]<<8) + ((uint32)src[2]<<16); - src += 3; - } while(--wt); - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include + +#define DECLARE_RGB(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: -> XRGB1555 +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_RGB(RGB565, XRGB1555) { + const uint16 *src = (const uint16 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + *dst++ = (px&0x001f) + ((px&0xffc0)>>1); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB888, XRGB1555) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 3*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 r = ((uint32)src[2] & 0xf8) << 7; + const uint32 g = ((uint32)src[1] & 0xf8) << 2; + const uint32 b = (uint32)src[0] >> 3; + src += 3; + + *dst++ = (uint16)(r + g + b); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(XRGB8888, XRGB1555) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 4*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 r = ((uint32)src[2] & 0xf8) << 7; + const uint32 g = ((uint32)src[1] & 0xf8) << 2; + const uint32 b = (uint32)src[0] >> 3; + src += 4; + + *dst++ = (uint16)(r + g + b); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: -> RGB565 +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_RGB(XRGB1555, RGB565) { + const uint16 *src = (const uint16 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + *dst++ = (uint16)(px + (px&0xffe0) + ((px&0x0200)>>4)); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB888, RGB565) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 3*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 r = ((uint32)src[2] & 0xf8) << 8; + const uint32 g = ((uint32)src[1] & 0xfc) << 3; + const uint32 b = (uint32)src[0] >> 3; + src += 3; + + *dst++ = (uint16)(r + g + b); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(XRGB8888, RGB565) { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + srcpitch -= 4*w; + dstpitch -= 2*w; + + do { + int wt = w; + + do { + const uint32 r = ((uint32)src[2] & 0xf8) << 8; + const uint32 g = ((uint32)src[1] & 0xfc) << 3; + const uint32 b = (uint32)src[0] >> 3; + src += 4; + + *dst++ = (uint16)(r + g + b); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: -> RGB888 +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_RGB(XRGB1555, RGB888) { + const uint16 *src = (const uint16 *)src0; + uint8 *dst = (uint8 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 3*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + uint32 rb = px & 0x7c1f; + uint32 g = px & 0x03e0; + + rb += rb<<5; + g += g<<5; + + dst[0] = (uint8)(rb>>2); + dst[1] = (uint8)(g>>7); + dst[2] = (uint8)(rb>>12); + dst += 3; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB565, RGB888) { + const uint16 *src = (const uint16 *)src0; + uint8 *dst = (uint8 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 3*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + uint32 rb = px & 0xf81f; + uint32 g = px & 0x07e0; + + rb += rb<<5; + g += g<<6; + + dst[0] = (uint8)(rb>>2); + dst[1] = (uint8)(g>>9); + dst[2] = (uint8)(rb>>13); + dst += 3; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(XRGB8888, RGB888) { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + srcpitch -= 4*w; + dstpitch -= 3*w; + + do { + int wt = w; + + do { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst += 3; + src += 4; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +/////////////////////////////////////////////////////////////////////////// +// +// RGB blitters: -> XRGB8888 +// +/////////////////////////////////////////////////////////////////////////// + +DECLARE_RGB(XRGB1555, XRGB8888) { + const uint16 *src = (const uint16 *)src0; + uint32 *dst = (uint32 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 4*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + const uint32 rgb = ((px & 0x7c00) << 9) + ((px & 0x03e0) << 6) + ((px & 0x001f) << 3); + + *dst++ = rgb + ((rgb & 0xe0e0e0)>>5); + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB565, XRGB8888) { + const uint16 *src = (const uint16 *)src0; + uint32 *dst = (uint32 *)dst0; + + srcpitch -= 2*w; + dstpitch -= 4*w; + + do { + int wt = w; + + do { + const uint32 px = *src++; + const uint32 rb = ((px & 0xf800) << 8) + ((px & 0x001f) << 3); + const uint32 g = ((px & 0x07e0) << 5) + (px & 0x0300); + + *dst++ = rb + ((rb & 0xe000e0)>>5) + g; + } while(--wt); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_RGB(RGB888, XRGB8888) { + const uint8 *src = (const uint8 *)src0; + uint32 *dst = (uint32 *)dst0; + + srcpitch -= 3*w; + dstpitch -= 4*w; + + do { + int wt = w; + + do { + *dst++ = (uint32)src[0] + ((uint32)src[1]<<8) + ((uint32)src[2]<<16); + src += 3; + } while(--wt); + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv.cpp index 81093f92e7a..de6ac77b031 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv.cpp @@ -1,1610 +1,1610 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "blt_spanutils.h" - -#ifdef _M_IX86 - #include "blt_spanutils_x86.h" -#endif - -using namespace nsVDPixmapSpanUtils; - -namespace { - struct YCbCrToRGB { - sint16 y_tab[256]; - sint16 r_cr_tab[256]; - sint16 b_cb_tab[256]; - sint16 g_cr_tab[256]; - sint16 g_cb_tab[256]; - uint8 cliptab[277+256+279]; - uint16 cliptab15[277+256+279]; - uint16 cliptab16[277+256+279]; - - YCbCrToRGB() { - int i; - - memset(cliptab, 0, 277); - memset(cliptab+277+256, 255, 279); - - memset(cliptab15, 0, sizeof cliptab15[0] * 277); - memset(cliptab16, 0, sizeof cliptab16[0] * 277); - memset(cliptab15+277+256, 0xff, sizeof cliptab15[0] * 279); - memset(cliptab16+277+256, 0xff, sizeof cliptab16[0] * 279); - - for(i=0; i<256; ++i) { - y_tab[i] = (sint16)(((i-16) * 76309 + 32768) >> 16); - r_cr_tab[i] = (sint16)(((i-128) * 104597 + 32768) >> 16); - b_cb_tab[i] = (sint16)(((i-128) * 132201 + 32768) >> 16); - g_cr_tab[i] = (sint16)(((i-128) * -53279 + 32768) >> 16); - g_cb_tab[i] = (sint16)(((i-128) * -25674 + 32768) >> 16); - cliptab[i+277] = (uint8)i; - cliptab15[i+277] = 0x421 * ((unsigned)i>>3); - cliptab16[i+277] = 0x801 * ((unsigned)i>>3) + 0x20 * ((unsigned)i>>2); - } - } - } static const colorconv; - - struct YCbCrFormatInfo { - ptrdiff_t ystep; - ptrdiff_t cstep; - ptrdiff_t yinc[4]; - ptrdiff_t cinc[4]; - sint8 ypos[4]; - sint8 cbpos[4]; - sint8 crpos[4]; - }; - - YCbCrFormatInfo g_formatInfo_YUV444_Planar = { -4, -4, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,1,2,3}, {0,1,2,3}}; - YCbCrFormatInfo g_formatInfo_YUV422_YUYV = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,2,4,6}, {1,1,5,5}, {3,3,7,7}}; - YCbCrFormatInfo g_formatInfo_YUV422_UYVY = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {1,3,5,7}, {0,0,4,4}, {2,2,6,6}}; - YCbCrFormatInfo g_formatInfo_YUV420_YV12 = { -4, -2, {-1,-1,-1,-1}, { 0,-1, 0,-1}, {0,1,2,3}, {0,0,1,1}, {0,0,1,1}}; - YCbCrFormatInfo g_formatInfo_YUV411_YV12 = { -4, -1, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,0,0,0}, {0,0,0,0}}; - - inline uint16 ycbcr_to_1555(uint8 y, uint8 cb0, uint8 cr0) { - const uint16 *p = &colorconv.cliptab15[277 + colorconv.y_tab[y]]; - uint32 r = 0x7c00 & p[colorconv.r_cr_tab[cr0]]; - uint32 g = 0x03e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; - uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]]; - - return r + g + b; - } - - inline uint16 ycbcr_to_565(uint8 y, uint8 cb0, uint8 cr0) { - const uint16 *p = &colorconv.cliptab16[277 + colorconv.y_tab[y]]; - uint32 r = 0xf800 & p[colorconv.r_cr_tab[cr0]]; - uint32 g = 0x07e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; - uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]]; - - return r + g + b; - } - - inline void ycbcr_to_888(uint8 *dst, uint8 y, uint8 cb0, uint8 cr0) { - const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]]; - uint8 r = p[colorconv.r_cr_tab[cr0]]; - uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; - uint8 b = p[colorconv.b_cb_tab[cb0]]; - - dst[0] = b; - dst[1] = g; - dst[2] = r; - } - - inline uint32 ycbcr_to_8888(uint8 y, uint8 cb0, uint8 cr0) { - const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]]; - uint8 r = p[colorconv.r_cr_tab[cr0]]; - uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; - uint8 b = p[colorconv.b_cb_tab[cb0]]; - - return (r << 16) + (g << 8) + b; - } - - void VDYCbCrToXRGB1555Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint16 *dst = (uint16 *)dst0; - - do { - *dst++ = ycbcr_to_1555(*y++, *cb++, *cr++); - } while(--w); - } - - void VDYCbCrToRGB565Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint16 *dst = (uint16 *)dst0; - - do { - *dst++ = ycbcr_to_565(*y++, *cb++, *cr++); - } while(--w); - } - - void VDYCbCrToRGB888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint8 *dst = (uint8 *)dst0; - - do { - ycbcr_to_888(dst, *y++, *cb++, *cr++); - dst += 3; - } while(--w); - } - - void VDYCbCrToXRGB8888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint32 *dst = (uint32 *)dst0; - - do { - *dst++ = ycbcr_to_8888(*y++, *cb++, *cr++); - } while(--w); - } - - void VDYCbCrToUYVYSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint32 *dst = (uint32 *)dst0; - - if (--w) { - do { - *dst++ = (uint32)*cb++ + ((uint32)y[0] << 8) + ((uint32)*cr++ << 16) + ((uint32)y[1] << 24); - y += 2; - } while((sint32)(w-=2)>0); - } - - if (!(w & 1)) - *dst++ = (uint32)*cb + ((uint32)y[0] << 8) + ((uint32)*cr << 16) + ((uint32)y[0] << 24); - } - - void VDYCbCrToYUYVSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { - uint32 *dst = (uint32 *)dst0; - - if (--w) { - do { - *dst++ = (uint32)y[0] + ((uint32)*cb++ << 8) + ((uint32)y[1] << 16) + ((uint32)*cr++ << 24); - y += 2; - } while((sint32)(w-=2)>0); - } - - if (!(w & 1)) - *dst++ = (uint32)y[0] + ((uint32)*cb << 8) + ((uint32)y[0] << 16) + ((uint32)*cr << 24); - } - - void VDYCbCrToRGB1555Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { - const ptrdiff_t ystep = formatinfo.ystep; - const ptrdiff_t cstep = formatinfo.cstep; - const ptrdiff_t ypos0 = formatinfo.ypos[0]; - const ptrdiff_t ypos1 = formatinfo.ypos[1]; - const ptrdiff_t ypos2 = formatinfo.ypos[2]; - const ptrdiff_t ypos3 = formatinfo.ypos[3]; - const ptrdiff_t crpos0 = formatinfo.crpos[0]; - const ptrdiff_t crpos1 = formatinfo.crpos[1]; - const ptrdiff_t crpos2 = formatinfo.crpos[2]; - const ptrdiff_t crpos3 = formatinfo.crpos[3]; - const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; - const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; - const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; - const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; - - yrow = (char *)yrow - ystep * ((w-1) >> 2); - crrow = (char *)crrow - cstep * ((w-1) >> 2); - cbrow = (char *)cbrow - cstep * ((w-1) >> 2); - dst = (char *)dst + 2*((w-1) & ~3); - - int y = 0; - do { - const uint8 *ysrc = (const uint8 *)yrow; - const uint8 *crsrc = (const uint8 *)crrow; - const uint8 *cbsrc = (const uint8 *)cbrow; - uint16 *out = (uint16 *)dst; - int w2 = -w; - - switch(w2 & 3) { - do { - case 0: out[3] = ycbcr_to_1555(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); - case 1: out[2] = ycbcr_to_1555(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); - case 2: out[1] = ycbcr_to_1555(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); - case 3: out[0] = ycbcr_to_1555(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); - out -= 4; - ysrc += ystep; - crsrc += cstep; - cbsrc += cstep; - } while((w2 += 4) < 0); - } - - dst = (char *)dst + dststride; - yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); - cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); - crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); - } while(++y < h); - } - - void VDYCbCrToRGB565Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { - const ptrdiff_t ystep = formatinfo.ystep; - const ptrdiff_t cstep = formatinfo.cstep; - const ptrdiff_t ypos0 = formatinfo.ypos[0]; - const ptrdiff_t ypos1 = formatinfo.ypos[1]; - const ptrdiff_t ypos2 = formatinfo.ypos[2]; - const ptrdiff_t ypos3 = formatinfo.ypos[3]; - const ptrdiff_t crpos0 = formatinfo.crpos[0]; - const ptrdiff_t crpos1 = formatinfo.crpos[1]; - const ptrdiff_t crpos2 = formatinfo.crpos[2]; - const ptrdiff_t crpos3 = formatinfo.crpos[3]; - const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; - const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; - const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; - const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; - - yrow = (char *)yrow - ystep * ((w-1) >> 2); - crrow = (char *)crrow - cstep * ((w-1) >> 2); - cbrow = (char *)cbrow - cstep * ((w-1) >> 2); - dst = (char *)dst + 2*((w-1) & ~3); - - int y = 0; - do { - const uint8 *ysrc = (const uint8 *)yrow; - const uint8 *crsrc = (const uint8 *)crrow; - const uint8 *cbsrc = (const uint8 *)cbrow; - uint16 *out = (uint16 *)dst; - int w2 = -w; - - switch(w2 & 3) { - do { - case 0: out[3] = ycbcr_to_565(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); - case 1: out[2] = ycbcr_to_565(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); - case 2: out[1] = ycbcr_to_565(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); - case 3: out[0] = ycbcr_to_565(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); - out -= 4; - ysrc += ystep; - crsrc += cstep; - cbsrc += cstep; - } while((w2 += 4) < 0); - } - - dst = (char *)dst + dststride; - yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); - cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); - crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); - } while(++y < h); - } - - void VDYCbCrToRGB888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { - const ptrdiff_t ystep = formatinfo.ystep; - const ptrdiff_t cstep = formatinfo.cstep; - const ptrdiff_t ypos0 = formatinfo.ypos[0]; - const ptrdiff_t ypos1 = formatinfo.ypos[1]; - const ptrdiff_t ypos2 = formatinfo.ypos[2]; - const ptrdiff_t ypos3 = formatinfo.ypos[3]; - const ptrdiff_t crpos0 = formatinfo.crpos[0]; - const ptrdiff_t crpos1 = formatinfo.crpos[1]; - const ptrdiff_t crpos2 = formatinfo.crpos[2]; - const ptrdiff_t crpos3 = formatinfo.crpos[3]; - const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; - const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; - const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; - const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; - - yrow = (char *)yrow - ystep * ((w-1) >> 2); - crrow = (char *)crrow - cstep * ((w-1) >> 2); - cbrow = (char *)cbrow - cstep * ((w-1) >> 2); - dst = (char *)dst + 3*((w-1) & ~3); - - int y = 0; - do { - const uint8 *ysrc = (const uint8 *)yrow; - const uint8 *crsrc = (const uint8 *)crrow; - const uint8 *cbsrc = (const uint8 *)cbrow; - uint8 *out = (uint8 *)dst; - int w2 = -w; - - switch(w2 & 3) { - do { - case 0: ycbcr_to_888(out+9, ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); - case 1: ycbcr_to_888(out+6, ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); - case 2: ycbcr_to_888(out+3, ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); - case 3: ycbcr_to_888(out, ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); - out -= 12; - ysrc += ystep; - crsrc += cstep; - cbsrc += cstep; - } while((w2 += 4) < 0); - } - - dst = (char *)dst + dststride; - yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); - cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); - crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); - } while(++y < h); - } - - void VDYCbCrToRGB8888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { - const ptrdiff_t ystep = formatinfo.ystep; - const ptrdiff_t cstep = formatinfo.cstep; - const ptrdiff_t ypos0 = formatinfo.ypos[0]; - const ptrdiff_t ypos1 = formatinfo.ypos[1]; - const ptrdiff_t ypos2 = formatinfo.ypos[2]; - const ptrdiff_t ypos3 = formatinfo.ypos[3]; - const ptrdiff_t crpos0 = formatinfo.crpos[0]; - const ptrdiff_t crpos1 = formatinfo.crpos[1]; - const ptrdiff_t crpos2 = formatinfo.crpos[2]; - const ptrdiff_t crpos3 = formatinfo.crpos[3]; - const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; - const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; - const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; - const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; - - yrow = (char *)yrow - ystep * ((w-1) >> 2); - crrow = (char *)crrow - cstep * ((w-1) >> 2); - cbrow = (char *)cbrow - cstep * ((w-1) >> 2); - dst = (char *)dst + 4*((w-1) & ~3); - - int y = 0; - do { - const uint8 *ysrc = (const uint8 *)yrow; - const uint8 *crsrc = (const uint8 *)crrow; - const uint8 *cbsrc = (const uint8 *)cbrow; - uint32 *out = (uint32 *)dst; - int w2 = -w; - - switch(w2 & 3) { - do { - case 0: out[3] = ycbcr_to_8888(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); - case 1: out[2] = ycbcr_to_8888(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); - case 2: out[1] = ycbcr_to_8888(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); - case 3: out[0] = ycbcr_to_8888(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); - out -= 4; - ysrc += ystep; - crsrc += cstep; - cbsrc += cstep; - } while((w2 += 4) < 0); - } - - dst = (char *)dst + dststride; - yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); - cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); - crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); - } while(++y < h); - } -} - -#define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) - -DECLARE_YUV(UYVY, XRGB1555) { - do { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint16 *y; - - cb = src[0]; - cr = src[2]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[1]]]; - *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[4]; - cr = src[6]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]]; - dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f); - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[5]]]; - dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - - dst += 2; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]]; - *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, RGB565) { - do { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint16 *y; - - cb = src[0]; - cr = src[2]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[1]]]; - *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[4]; - cr = src[6]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]]; - dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f); - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[5]]]; - dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - - dst += 2; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]]; - *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, RGB888) { - do { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint8 *y; - - cb = src[0]; - cr = src[2]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - dst += 3; - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[4]; - cr = src[6]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; - dst[0] = y[(bc0+bc1+1)>>1]; - dst[1] = y[(gc0+gc1+1)>>1]; - dst[2] = y[(rc0+rc1+1)>>1]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]]; - dst[3] = y[bc1]; - dst[4] = y[gc1]; - dst[5] = y[rc1]; - - dst += 6; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, XRGB8888) { - do { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint8 *y; - - cb = src[0]; - cr = src[2]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - dst += 4; - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[4]; - cr = src[6]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; - dst[0] = y[(bc0+bc1+1)>>1]; - dst[1] = y[(gc0+gc1+1)>>1]; - dst[2] = y[(rc0+rc1+1)>>1]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]]; - dst[4] = y[bc1]; - dst[5] = y[gc1]; - dst[6] = y[rc1]; - - dst += 8; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, XRGB1555) { - do { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint16 *y; - - cb = src[1]; - cr = src[3]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[0]]]; - *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[5]; - cr = src[7]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]]; - dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f); - - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[4]]]; - dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - - dst += 2; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]]; - *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, RGB565) { - do { - const uint8 *src = (const uint8 *)src0; - uint16 *dst = (uint16 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint16 *y; - - cb = src[1]; - cr = src[3]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[0]]]; - *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[5]; - cr = src[7]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]]; - dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f); - - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[4]]]; - dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - - dst += 2; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]]; - *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, RGB888) { - do { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint8 *y; - - cb = src[1]; - cr = src[3]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - dst += 3; - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[5]; - cr = src[7]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; - dst[0] = y[(bc0+bc1+1)>>1]; - dst[1] = y[(gc0+gc1+1)>>1]; - dst[2] = y[(rc0+rc1+1)>>1]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]]; - dst[3] = y[bc1]; - dst[4] = y[gc1]; - dst[5] = y[rc1]; - - dst += 6; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, XRGB8888) { - do { - const uint8 *src = (const uint8 *)src0; - uint8 *dst = (uint8 *)dst0; - - // convert first pixel - int cb, cr; - int rc0, gc0, bc0, rc1, gc1, bc1; - const uint8 *y; - - cb = src[1]; - cr = src[3]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - dst += 4; - - // convert pairs of pixels - int w2 = w; - - if ((w2 -= 2) > 0) { - do { - rc0 = rc1; - gc0 = gc1; - bc0 = bc1; - - cb = src[5]; - cr = src[7]; - rc1 = colorconv.r_cr_tab[cr]; - gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; - bc1 = colorconv.b_cb_tab[cb]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; - dst[0] = y[(bc0+bc1+1)>>1]; - dst[1] = y[(gc0+gc1+1)>>1]; - dst[2] = y[(rc0+rc1+1)>>1]; - - y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]]; - dst[4] = y[bc1]; - dst[5] = y[gc1]; - dst[6] = y[rc1]; - - dst += 8; - src += 4; - } while((w2 -= 2) > 0); - } - - // handle oddballs - if (!(w2 & 1)) { - y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; - dst[0] = y[bc1]; - dst[1] = y[gc1]; - dst[2] = y[rc1]; - } - - vdptrstep(src0, srcpitch); - vdptrstep(dst0, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, XRGB1555) { - uint16 *dst = (uint16 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 2*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = colorconv.cliptab15[colorconv.y_tab[*src++] + 277]; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, RGB565) { - uint16 *dst = (uint16 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 2*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = colorconv.cliptab16[colorconv.y_tab[*src++] + 277]; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, RGB888) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 3*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - dst[0] = dst[1] = dst[2] = colorconv.cliptab[colorconv.y_tab[*src++] + 277]; - dst += 3; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, XRGB8888) { - uint32 *dst = (uint32 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 4*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = 0x010101 * colorconv.cliptab[colorconv.y_tab[*src++] + 277]; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -#define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) - - -namespace { - typedef void (*tpYUVPlanarFinalDecoder)(void *, const uint8 *, const uint8 *, const uint8 *, uint32); - typedef void (*tpYUVPlanarHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w); - typedef void (*tpYUVPlanarVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); -} - -#ifdef _M_IX86 - extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); - extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); - extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); -#endif - - -void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); - int hbits = srcinfo.auxwbits; - int vbits = srcinfo.auxhbits; - - if (src.format == nsVDPixmap::kPixFormat_YUV422_UYVY || src.format == nsVDPixmap::kPixFormat_YUV422_YUYV) - hbits = 1; - - bool h_coaligned = true; - bool v_coaligned = false; - - if (src.format == nsVDPixmap::kPixFormat_YUV422_Planar_Centered || - src.format == nsVDPixmap::kPixFormat_YUV420_Planar_Centered) { - h_coaligned = false; - } - - tpYUVPlanarVertDecoder vfunc = NULL; - tpYUVPlanarHorizDecoder hfunc = NULL; - uint32 horiz_buffer_size = 0; - uint32 vert_buffer_size = 0; - uint32 horiz_count = 0; - sint32 yaccum = 8; - sint32 yinc = 8; - uint32 yleft = h; - - switch(vbits*2+v_coaligned) { - case 0: // 4:4:4, 4:2:2 - case 1: - break; - case 2: // 4:2:0 (centered) - vfunc = vert_expand2x_centered; - vert_buffer_size = w>>1; - yaccum = 6; - yinc = 4; - yleft >>= 1; - break; - case 4: // 4:1:0 (centered) - vfunc = vert_expand4x_centered; - vert_buffer_size = w>>2; - yaccum = 5; - yinc = 2; - yleft >>= 2; - break; - default: - VDNEVERHERE; - return; - } - - --yleft; - - tpYUVPlanarFinalDecoder dfunc = NULL; - -#ifdef _M_IX86 - uint32 cpuflags = CPUGetEnabledExtensions(); - - if (cpuflags & CPUF_SUPPORTS_MMX) { - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (vfunc == vert_expand2x_centered) - vfunc = vert_expand2x_centered_ISSE; - } - - switch(dst.format) { - case nsVDPixmap::kPixFormat_XRGB1555: dfunc = vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX; break; - case nsVDPixmap::kPixFormat_RGB565: dfunc = vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX; break; - case nsVDPixmap::kPixFormat_XRGB8888: dfunc = vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX; break; - } - } -#endif - - bool halfchroma = false; - - if (!dfunc) { - switch(dst.format) { - case nsVDPixmap::kPixFormat_XRGB1555: dfunc = VDYCbCrToXRGB1555Span; break; - case nsVDPixmap::kPixFormat_RGB565: dfunc = VDYCbCrToRGB565Span; break; - case nsVDPixmap::kPixFormat_RGB888: dfunc = VDYCbCrToRGB888Span; break; - case nsVDPixmap::kPixFormat_XRGB8888: dfunc = VDYCbCrToXRGB8888Span; break; - case nsVDPixmap::kPixFormat_YUV422_UYVY: dfunc = VDYCbCrToUYVYSpan; halfchroma = true; break; - case nsVDPixmap::kPixFormat_YUV422_YUYV: dfunc = VDYCbCrToYUYVSpan; halfchroma = true; break; - default: - VDNEVERHERE; - return; - } - } - - switch(hbits*2+h_coaligned) { - case 0: // 4:4:4 - case 1: - if (halfchroma) { - hfunc = horiz_compress2x_coaligned; - horiz_buffer_size = (w + 1) >> 1; - horiz_count = w; - } - break; - case 2: // 4:2:0 MPEG-1 (centered) - if (halfchroma) { - hfunc = horiz_realign_to_coaligned; - horiz_buffer_size = (w + 1) >> 1; - horiz_count = (w + 1) >> 1; - } else { - hfunc = horiz_expand2x_centered; - horiz_buffer_size = w; - horiz_count = w; - } - break; - case 3: // 4:2:0/4:2:2 MPEG-2 (coaligned) - if (!halfchroma) { - hfunc = horiz_expand2x_coaligned; - horiz_buffer_size = w; - horiz_count = w; - } - break; - case 5: // 4:1:1 (coaligned) - if (halfchroma) { - hfunc = horiz_expand2x_coaligned; - horiz_buffer_size = (w + 1) >> 1; - horiz_count = (w + 1) >> 1; - } else { - hfunc = horiz_expand4x_coaligned; - horiz_buffer_size = w; - horiz_count = w; - } - break; - - default: - VDNEVERHERE; - return; - } - -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (hfunc == horiz_expand2x_coaligned) - hfunc = horiz_expand2x_coaligned_ISSE; - } -#endif - - uint32 chroma_srcwidth = -(-w >> srcinfo.auxwbits); - horiz_buffer_size = (horiz_buffer_size + 15) & ~15; - vert_buffer_size = (vert_buffer_size + 15) & ~15; - - // allocate buffers - - vdblock tempbuf((horiz_buffer_size + vert_buffer_size)*2 + 1); - - uint8 *const crbufh = tempbuf.data(); - uint8 *const crbufv = crbufh + horiz_buffer_size; - uint8 *const cbbufh = crbufv + vert_buffer_size; - uint8 *const cbbufv = cbbufh + horiz_buffer_size; - - const uint8 *cb0 = (const uint8*)src.data2; - const uint8 *cr0 = (const uint8*)src.data3; - const uint8 *cb1 = cb0; - const uint8 *cr1 = cr0; - const uint8 *y = (const uint8 *)src.data; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - void *out = dst.data; - ptrdiff_t outpitch = dst.pitch; - - for(;;) { - if (yaccum >= 8) { - yaccum &= 7; - - cb0 = cb1; - cr0 = cr1; - - if (yleft > 0) { - --yleft; - vdptrstep(cb1, cbpitch); - vdptrstep(cr1, crpitch); - } - } - - const uint8 *cr = cr0; - const uint8 *cb = cb0; - - // vertical interpolation: cr - if(yaccum & 7) { - const uint8 *const srcs[2]={cr0, cr1}; - vfunc(crbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5); - cr = crbufv; - } - - // horizontal interpolation: cr - if (hfunc) { - hfunc(crbufh, cr, horiz_count); - cr = crbufh; - } - - // vertical interpolation: cb - if(yaccum & 7) { - const uint8 *const srcs[2]={cb0, cb1}; - vfunc(cbbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5); - cb = cbbufv; - } - - // horizontal interpolation: cb - if (hfunc) { - hfunc(cbbufh, cb, horiz_count); - cb = cbbufh; - } - - dfunc(out, y, cb, cr, w); - vdptrstep(out, outpitch); - vdptrstep(y, ypitch); - - if (!--h) - break; - - yaccum += yinc; - } - -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_MMX) { - _mm_empty(); - } -#endif -} - -namespace { - typedef void (*tpUVBltHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w); - typedef void (*tpUVBltVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); - - void uvplaneblt(uint8 *dst, ptrdiff_t dstpitch, int dstformat, const uint8 *src, ptrdiff_t srcpitch, int srcformat, vdpixsize w, vdpixsize h) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(srcformat); - const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dstformat); - - int xshift = srcinfo.auxwbits - dstinfo.auxwbits; - int yshift = srcinfo.auxhbits - dstinfo.auxhbits; - - tpUVBltHorizDecoder hfunc = NULL; - tpUVBltVertDecoder vfunc = NULL; - - switch(xshift) { - case +2: - hfunc = horiz_expand4x_coaligned; - break; - case +1: - hfunc = horiz_expand2x_coaligned; - break; - case 0: - break; - case -1: - hfunc = horiz_compress2x_coaligned; - break; - case -2: - hfunc = horiz_compress4x_coaligned; - break; - default: - VDNEVERHERE; - return; - } - -#ifdef _M_IX86 - uint32 cpuflags = CPUGetEnabledExtensions(); - - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (hfunc == horiz_expand2x_coaligned) - hfunc = horiz_expand2x_coaligned_ISSE; - } -#endif - - int winsize, winposnext, winstep; - - switch(yshift) { - case +2: - vfunc = vert_expand4x_centered; - winsize = 2; - winposnext = 0xa0; - winstep = 0x40; - break; - case +1: - vfunc = vert_expand2x_centered; - winsize = 2; - winposnext = 0xc0; - winstep = 0x80; - break; - case 0: - winsize = 1; - winposnext = 0; - winstep = 0x100; - break; - case -1: - vfunc = vert_compress2x_centered; - winsize = 4; - winposnext = 0x200; - winstep = 0x200; - break; - case -2: - vfunc = vert_compress4x_centered; - winsize = 8; - winposnext = 0x500; - winstep = 0x400; - break; - default: - VDNEVERHERE; - return; - } - -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (vfunc == vert_expand2x_centered) - vfunc = vert_expand2x_centered_ISSE; - } -#endif - - int dsth = -(-h >> dstinfo.auxhbits); - int srch = -(-h >> srcinfo.auxhbits); - int dstw = -(-w >> dstinfo.auxwbits); - int w2 = -(-w >> std::min(dstinfo.auxwbits, srcinfo.auxwbits)); - - int winpos = (winposnext>>8) - winsize; - - const uint8 *window[16]; - - vdblock tmpbuf; - ptrdiff_t tmppitch = (w+15) & ~15; - - if (vfunc && hfunc) - tmpbuf.resize(tmppitch * winsize); - - do { - int desiredpos = winposnext >> 8; - - while(winpos < desiredpos) { - const uint8 *srcrow = vdptroffset(src, srcpitch * std::max(0, std::min(srch-1, ++winpos))); - int winoffset = (winpos-1) & (winsize-1); - - if (hfunc) { - uint8 *dstrow = vfunc ? tmpbuf.data() + tmppitch * winoffset : dst; - hfunc(dstrow, srcrow, w2); - srcrow = dstrow; - } - - window[winoffset] = window[winoffset + winsize] = srcrow; - } - - if (vfunc) - vfunc(dst, window + (winpos & (winsize-1)), dstw, winposnext & 255); - else if (!hfunc) - memcpy(dst, window[winpos & (winsize-1)], dstw); - - winposnext += winstep; - vdptrstep(dst, dstpitch); - } while(--dsth); - -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_MMX) { - _mm_empty(); - } -#endif - } -} - -void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dstpm, const VDPixmap& srcpm, vdpixsize w, vdpixsize h) { - VDMemcpyRect(dstpm.data, dstpm.pitch, srcpm.data, srcpm.pitch, dstpm.w, dstpm.h); - - if (srcpm.format != nsVDPixmap::kPixFormat_Y8) { - if (dstpm.format != nsVDPixmap::kPixFormat_Y8) { - // YCbCr -> YCbCr - uvplaneblt((uint8 *)dstpm.data2, dstpm.pitch2, dstpm.format, (uint8 *)srcpm.data2, srcpm.pitch2, srcpm.format, w, h); - uvplaneblt((uint8 *)dstpm.data3, dstpm.pitch3, dstpm.format, (uint8 *)srcpm.data3, srcpm.pitch3, srcpm.format, w, h); - } - } else { - if (dstpm.format != nsVDPixmap::kPixFormat_Y8) { - const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstpm.format); - VDMemset8Rect(dstpm.data2, dstpm.pitch2, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits)); - VDMemset8Rect(dstpm.data3, dstpm.pitch3, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits)); - } - } -} - -extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); -extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); - -DECLARE_YUV_PLANAR(YUV411, XRGB1555) { - uint16 *out = (uint16 *)dst.data; - const ptrdiff_t opitch = dst.pitch; - const uint8 *yrow = (const uint8 *)src.data; - const uint8 *cbrow = (const uint8 *)src.data2; - const uint8 *crrow = (const uint8 *)src.data3; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - vdpixsize wpairs = (w-1)>>2; - vdpixsize wleft = w - (wpairs<<2); - - do { - uint16 *p = out; - const uint8 *y = yrow; - const uint8 *cb = cbrow; - const uint8 *cr = crrow; - vdpixsize wt; - - if (wpairs > 0) { -#if !defined(VD_CPU_X86) - wt = wpairs; - - do { - const unsigned cb0 = cb[0]; - const unsigned cb1 = cb[1]; - const unsigned cr0 = cr[0]; - const unsigned cr1 = cr[1]; - - p[0] = ycbcr_to_1555(y[0], cb0, cr0); - p[1] = ycbcr_to_1555(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); - p[2] = ycbcr_to_1555(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); - p[3] = ycbcr_to_1555(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); - - y += 4; - p += 4; - ++cb; - ++cr; - } while(--wt); -#else - vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(p, y, cb, cr, wpairs); - y += 4*wpairs; - cr += wpairs; - cb += wpairs; - p += 4*wpairs; -#endif - } - - if (wleft > 0) { - wt = wleft; - - const uint8 cr0 = *cr; - const uint8 cb0 = *cb; - - do { - *p++ = ycbcr_to_1555(*y++, cb0, cr0); - } while(--wt); - } - - vdptrstep(out, opitch); - vdptrstep(yrow, ypitch); - vdptrstep(cbrow, cbpitch); - vdptrstep(crrow, crpitch); - } while(--h); - -#ifdef VD_CPU_X86 - _mm_empty(); -#endif -} - -DECLARE_YUV_PLANAR(YUV411, RGB565) { - uint16 *out = (uint16 *)dst.data; - const ptrdiff_t opitch = dst.pitch; - const uint8 *yrow = (const uint8 *)src.data; - const uint8 *cbrow = (const uint8 *)src.data2; - const uint8 *crrow = (const uint8 *)src.data3; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - vdpixsize wpairs = (w-1)>>2; - vdpixsize wleft = w - (wpairs<<2); - - do { - uint16 *p = out; - const uint8 *y = yrow; - const uint8 *cb = cbrow; - const uint8 *cr = crrow; - vdpixsize wt; - - if (wpairs > 0) { -#if !defined(VD_CPU_X86) - wt = wpairs; - - do { - const unsigned cb0 = cb[0]; - const unsigned cb1 = cb[1]; - const unsigned cr0 = cr[0]; - const unsigned cr1 = cr[1]; - - p[0] = ycbcr_to_565(y[0], cb0, cr0); - p[1] = ycbcr_to_565(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); - p[2] = ycbcr_to_565(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); - p[3] = ycbcr_to_565(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); - - y += 4; - p += 4; - ++cb; - ++cr; - } while(--wt); -#else - vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(p, y, cb, cr, wpairs); -#endif - } - - if (wleft > 0) { - wt = wleft; - - const uint8 cr0 = *cr; - const uint8 cb0 = *cb; - - do { - *p++ = ycbcr_to_565(*y++, cb0, cr0); - } while(--wt); - } - - vdptrstep(out, opitch); - vdptrstep(yrow, ypitch); - vdptrstep(cbrow, cbpitch); - vdptrstep(crrow, crpitch); - } while(--h); - -#ifdef VD_CPU_X86 - _mm_empty(); -#endif -} - -DECLARE_YUV_PLANAR(YUV411, RGB888) { - uint8 *out = (uint8 *)dst.data; - const ptrdiff_t opitch = dst.pitch; - const uint8 *yrow = (const uint8 *)src.data; - const uint8 *cbrow = (const uint8 *)src.data2; - const uint8 *crrow = (const uint8 *)src.data3; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - vdpixsize wpairs = (w-1)>>2; - vdpixsize wleft = w - (wpairs<<2); - - do { - uint8 *p = out; - const uint8 *y = yrow; - const uint8 *cb = cbrow; - const uint8 *cr = crrow; - vdpixsize wt; - - if (wpairs > 0) { - wt = wpairs; - - do { - const unsigned cb0 = cb[0]; - const unsigned cb1 = cb[1]; - const unsigned cr0 = cr[0]; - const unsigned cr1 = cr[1]; - - ycbcr_to_888(p+0, y[0], cb0, cr0); - ycbcr_to_888(p+3, y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); - ycbcr_to_888(p+6, y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); - ycbcr_to_888(p+9, y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); - - y += 4; - p += 12; - ++cb; - ++cr; - } while(--wt); - } - - if (wleft > 0) { - wt = wleft; - - const uint8 cr0 = *cr; - const uint8 cb0 = *cb; - - do { - ycbcr_to_888(p, *y++, cb0, cr0); - p += 4; - } while(--wt); - } - - vdptrstep(out, opitch); - vdptrstep(yrow, ypitch); - vdptrstep(cbrow, cbpitch); - vdptrstep(crrow, crpitch); - } while(--h); -} - -DECLARE_YUV_PLANAR(YUV411, XRGB8888) { - uint32 *out = (uint32 *)dst.data; - const ptrdiff_t opitch = dst.pitch; - const uint8 *yrow = (const uint8 *)src.data; - const uint8 *cbrow = (const uint8 *)src.data2; - const uint8 *crrow = (const uint8 *)src.data3; - const ptrdiff_t ypitch = src.pitch; - const ptrdiff_t cbpitch = src.pitch2; - const ptrdiff_t crpitch = src.pitch3; - - vdpixsize wpairs = (w-1)>>2; - vdpixsize wleft = w - (wpairs<<2); - - do { - uint32 *p = out; - const uint8 *y = yrow; - const uint8 *cb = cbrow; - const uint8 *cr = crrow; - vdpixsize wt; - - if (wpairs > 0) { -#if !defined(VD_CPU_X86) - wt = wpairs; - - do { - const unsigned cb0 = cb[0]; - const unsigned cb1 = cb[1]; - const unsigned cr0 = cr[0]; - const unsigned cr1 = cr[1]; - - p[0] = ycbcr_to_8888(y[0], cb0, cr0); - p[1] = ycbcr_to_8888(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); - p[2] = ycbcr_to_8888(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); - p[3] = ycbcr_to_8888(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); - - y += 4; - p += 4; - ++cb; - ++cr; - } while(--wt); -#else - vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(p, y, cb, cr, wpairs); - y += 4*wpairs; - cr += wpairs; - cb += wpairs; - p += 4*wpairs; -#endif - } - - if (wleft > 0) { - wt = wleft; - - const uint8 cr0 = *cr; - const uint8 cb0 = *cb; - - do { - *p++ = ycbcr_to_8888(*y++, cb0, cr0); - } while(--wt); - } - - vdptrstep(out, opitch); - vdptrstep(yrow, ypitch); - vdptrstep(cbrow, cbpitch); - vdptrstep(crrow, crpitch); - } while(--h); - -#ifdef VD_CPU_X86 - _mm_empty(); -#endif -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "blt_spanutils.h" + +#ifdef _M_IX86 + #include "blt_spanutils_x86.h" +#endif + +using namespace nsVDPixmapSpanUtils; + +namespace { + struct YCbCrToRGB { + sint16 y_tab[256]; + sint16 r_cr_tab[256]; + sint16 b_cb_tab[256]; + sint16 g_cr_tab[256]; + sint16 g_cb_tab[256]; + uint8 cliptab[277+256+279]; + uint16 cliptab15[277+256+279]; + uint16 cliptab16[277+256+279]; + + YCbCrToRGB() { + int i; + + memset(cliptab, 0, 277); + memset(cliptab+277+256, 255, 279); + + memset(cliptab15, 0, sizeof cliptab15[0] * 277); + memset(cliptab16, 0, sizeof cliptab16[0] * 277); + memset(cliptab15+277+256, 0xff, sizeof cliptab15[0] * 279); + memset(cliptab16+277+256, 0xff, sizeof cliptab16[0] * 279); + + for(i=0; i<256; ++i) { + y_tab[i] = (sint16)(((i-16) * 76309 + 32768) >> 16); + r_cr_tab[i] = (sint16)(((i-128) * 104597 + 32768) >> 16); + b_cb_tab[i] = (sint16)(((i-128) * 132201 + 32768) >> 16); + g_cr_tab[i] = (sint16)(((i-128) * -53279 + 32768) >> 16); + g_cb_tab[i] = (sint16)(((i-128) * -25674 + 32768) >> 16); + cliptab[i+277] = (uint8)i; + cliptab15[i+277] = 0x421 * ((unsigned)i>>3); + cliptab16[i+277] = 0x801 * ((unsigned)i>>3) + 0x20 * ((unsigned)i>>2); + } + } + } static const colorconv; + + struct YCbCrFormatInfo { + ptrdiff_t ystep; + ptrdiff_t cstep; + ptrdiff_t yinc[4]; + ptrdiff_t cinc[4]; + sint8 ypos[4]; + sint8 cbpos[4]; + sint8 crpos[4]; + }; + + YCbCrFormatInfo g_formatInfo_YUV444_Planar = { -4, -4, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,1,2,3}, {0,1,2,3}}; + YCbCrFormatInfo g_formatInfo_YUV422_YUYV = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,2,4,6}, {1,1,5,5}, {3,3,7,7}}; + YCbCrFormatInfo g_formatInfo_YUV422_UYVY = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {1,3,5,7}, {0,0,4,4}, {2,2,6,6}}; + YCbCrFormatInfo g_formatInfo_YUV420_YV12 = { -4, -2, {-1,-1,-1,-1}, { 0,-1, 0,-1}, {0,1,2,3}, {0,0,1,1}, {0,0,1,1}}; + YCbCrFormatInfo g_formatInfo_YUV411_YV12 = { -4, -1, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,0,0,0}, {0,0,0,0}}; + + inline uint16 ycbcr_to_1555(uint8 y, uint8 cb0, uint8 cr0) { + const uint16 *p = &colorconv.cliptab15[277 + colorconv.y_tab[y]]; + uint32 r = 0x7c00 & p[colorconv.r_cr_tab[cr0]]; + uint32 g = 0x03e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; + uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]]; + + return r + g + b; + } + + inline uint16 ycbcr_to_565(uint8 y, uint8 cb0, uint8 cr0) { + const uint16 *p = &colorconv.cliptab16[277 + colorconv.y_tab[y]]; + uint32 r = 0xf800 & p[colorconv.r_cr_tab[cr0]]; + uint32 g = 0x07e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; + uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]]; + + return r + g + b; + } + + inline void ycbcr_to_888(uint8 *dst, uint8 y, uint8 cb0, uint8 cr0) { + const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]]; + uint8 r = p[colorconv.r_cr_tab[cr0]]; + uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; + uint8 b = p[colorconv.b_cb_tab[cb0]]; + + dst[0] = b; + dst[1] = g; + dst[2] = r; + } + + inline uint32 ycbcr_to_8888(uint8 y, uint8 cb0, uint8 cr0) { + const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]]; + uint8 r = p[colorconv.r_cr_tab[cr0]]; + uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]]; + uint8 b = p[colorconv.b_cb_tab[cb0]]; + + return (r << 16) + (g << 8) + b; + } + + void VDYCbCrToXRGB1555Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint16 *dst = (uint16 *)dst0; + + do { + *dst++ = ycbcr_to_1555(*y++, *cb++, *cr++); + } while(--w); + } + + void VDYCbCrToRGB565Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint16 *dst = (uint16 *)dst0; + + do { + *dst++ = ycbcr_to_565(*y++, *cb++, *cr++); + } while(--w); + } + + void VDYCbCrToRGB888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint8 *dst = (uint8 *)dst0; + + do { + ycbcr_to_888(dst, *y++, *cb++, *cr++); + dst += 3; + } while(--w); + } + + void VDYCbCrToXRGB8888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint32 *dst = (uint32 *)dst0; + + do { + *dst++ = ycbcr_to_8888(*y++, *cb++, *cr++); + } while(--w); + } + + void VDYCbCrToUYVYSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint32 *dst = (uint32 *)dst0; + + if (--w) { + do { + *dst++ = (uint32)*cb++ + ((uint32)y[0] << 8) + ((uint32)*cr++ << 16) + ((uint32)y[1] << 24); + y += 2; + } while((sint32)(w-=2)>0); + } + + if (!(w & 1)) + *dst++ = (uint32)*cb + ((uint32)y[0] << 8) + ((uint32)*cr << 16) + ((uint32)y[0] << 24); + } + + void VDYCbCrToYUYVSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) { + uint32 *dst = (uint32 *)dst0; + + if (--w) { + do { + *dst++ = (uint32)y[0] + ((uint32)*cb++ << 8) + ((uint32)y[1] << 16) + ((uint32)*cr++ << 24); + y += 2; + } while((sint32)(w-=2)>0); + } + + if (!(w & 1)) + *dst++ = (uint32)y[0] + ((uint32)*cb << 8) + ((uint32)y[0] << 16) + ((uint32)*cr << 24); + } + + void VDYCbCrToRGB1555Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { + const ptrdiff_t ystep = formatinfo.ystep; + const ptrdiff_t cstep = formatinfo.cstep; + const ptrdiff_t ypos0 = formatinfo.ypos[0]; + const ptrdiff_t ypos1 = formatinfo.ypos[1]; + const ptrdiff_t ypos2 = formatinfo.ypos[2]; + const ptrdiff_t ypos3 = formatinfo.ypos[3]; + const ptrdiff_t crpos0 = formatinfo.crpos[0]; + const ptrdiff_t crpos1 = formatinfo.crpos[1]; + const ptrdiff_t crpos2 = formatinfo.crpos[2]; + const ptrdiff_t crpos3 = formatinfo.crpos[3]; + const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; + const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; + const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; + const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; + + yrow = (char *)yrow - ystep * ((w-1) >> 2); + crrow = (char *)crrow - cstep * ((w-1) >> 2); + cbrow = (char *)cbrow - cstep * ((w-1) >> 2); + dst = (char *)dst + 2*((w-1) & ~3); + + int y = 0; + do { + const uint8 *ysrc = (const uint8 *)yrow; + const uint8 *crsrc = (const uint8 *)crrow; + const uint8 *cbsrc = (const uint8 *)cbrow; + uint16 *out = (uint16 *)dst; + int w2 = -w; + + switch(w2 & 3) { + do { + case 0: out[3] = ycbcr_to_1555(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); + case 1: out[2] = ycbcr_to_1555(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); + case 2: out[1] = ycbcr_to_1555(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); + case 3: out[0] = ycbcr_to_1555(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); + out -= 4; + ysrc += ystep; + crsrc += cstep; + cbsrc += cstep; + } while((w2 += 4) < 0); + } + + dst = (char *)dst + dststride; + yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); + cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); + crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); + } while(++y < h); + } + + void VDYCbCrToRGB565Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { + const ptrdiff_t ystep = formatinfo.ystep; + const ptrdiff_t cstep = formatinfo.cstep; + const ptrdiff_t ypos0 = formatinfo.ypos[0]; + const ptrdiff_t ypos1 = formatinfo.ypos[1]; + const ptrdiff_t ypos2 = formatinfo.ypos[2]; + const ptrdiff_t ypos3 = formatinfo.ypos[3]; + const ptrdiff_t crpos0 = formatinfo.crpos[0]; + const ptrdiff_t crpos1 = formatinfo.crpos[1]; + const ptrdiff_t crpos2 = formatinfo.crpos[2]; + const ptrdiff_t crpos3 = formatinfo.crpos[3]; + const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; + const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; + const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; + const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; + + yrow = (char *)yrow - ystep * ((w-1) >> 2); + crrow = (char *)crrow - cstep * ((w-1) >> 2); + cbrow = (char *)cbrow - cstep * ((w-1) >> 2); + dst = (char *)dst + 2*((w-1) & ~3); + + int y = 0; + do { + const uint8 *ysrc = (const uint8 *)yrow; + const uint8 *crsrc = (const uint8 *)crrow; + const uint8 *cbsrc = (const uint8 *)cbrow; + uint16 *out = (uint16 *)dst; + int w2 = -w; + + switch(w2 & 3) { + do { + case 0: out[3] = ycbcr_to_565(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); + case 1: out[2] = ycbcr_to_565(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); + case 2: out[1] = ycbcr_to_565(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); + case 3: out[0] = ycbcr_to_565(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); + out -= 4; + ysrc += ystep; + crsrc += cstep; + cbsrc += cstep; + } while((w2 += 4) < 0); + } + + dst = (char *)dst + dststride; + yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); + cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); + crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); + } while(++y < h); + } + + void VDYCbCrToRGB888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { + const ptrdiff_t ystep = formatinfo.ystep; + const ptrdiff_t cstep = formatinfo.cstep; + const ptrdiff_t ypos0 = formatinfo.ypos[0]; + const ptrdiff_t ypos1 = formatinfo.ypos[1]; + const ptrdiff_t ypos2 = formatinfo.ypos[2]; + const ptrdiff_t ypos3 = formatinfo.ypos[3]; + const ptrdiff_t crpos0 = formatinfo.crpos[0]; + const ptrdiff_t crpos1 = formatinfo.crpos[1]; + const ptrdiff_t crpos2 = formatinfo.crpos[2]; + const ptrdiff_t crpos3 = formatinfo.crpos[3]; + const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; + const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; + const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; + const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; + + yrow = (char *)yrow - ystep * ((w-1) >> 2); + crrow = (char *)crrow - cstep * ((w-1) >> 2); + cbrow = (char *)cbrow - cstep * ((w-1) >> 2); + dst = (char *)dst + 3*((w-1) & ~3); + + int y = 0; + do { + const uint8 *ysrc = (const uint8 *)yrow; + const uint8 *crsrc = (const uint8 *)crrow; + const uint8 *cbsrc = (const uint8 *)cbrow; + uint8 *out = (uint8 *)dst; + int w2 = -w; + + switch(w2 & 3) { + do { + case 0: ycbcr_to_888(out+9, ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); + case 1: ycbcr_to_888(out+6, ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); + case 2: ycbcr_to_888(out+3, ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); + case 3: ycbcr_to_888(out, ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); + out -= 12; + ysrc += ystep; + crsrc += cstep; + cbsrc += cstep; + } while((w2 += 4) < 0); + } + + dst = (char *)dst + dststride; + yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); + cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); + crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); + } while(++y < h); + } + + void VDYCbCrToRGB8888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) { + const ptrdiff_t ystep = formatinfo.ystep; + const ptrdiff_t cstep = formatinfo.cstep; + const ptrdiff_t ypos0 = formatinfo.ypos[0]; + const ptrdiff_t ypos1 = formatinfo.ypos[1]; + const ptrdiff_t ypos2 = formatinfo.ypos[2]; + const ptrdiff_t ypos3 = formatinfo.ypos[3]; + const ptrdiff_t crpos0 = formatinfo.crpos[0]; + const ptrdiff_t crpos1 = formatinfo.crpos[1]; + const ptrdiff_t crpos2 = formatinfo.crpos[2]; + const ptrdiff_t crpos3 = formatinfo.crpos[3]; + const ptrdiff_t cbpos0 = formatinfo.cbpos[0]; + const ptrdiff_t cbpos1 = formatinfo.cbpos[1]; + const ptrdiff_t cbpos2 = formatinfo.cbpos[2]; + const ptrdiff_t cbpos3 = formatinfo.cbpos[3]; + + yrow = (char *)yrow - ystep * ((w-1) >> 2); + crrow = (char *)crrow - cstep * ((w-1) >> 2); + cbrow = (char *)cbrow - cstep * ((w-1) >> 2); + dst = (char *)dst + 4*((w-1) & ~3); + + int y = 0; + do { + const uint8 *ysrc = (const uint8 *)yrow; + const uint8 *crsrc = (const uint8 *)crrow; + const uint8 *cbsrc = (const uint8 *)cbrow; + uint32 *out = (uint32 *)dst; + int w2 = -w; + + switch(w2 & 3) { + do { + case 0: out[3] = ycbcr_to_8888(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]); + case 1: out[2] = ycbcr_to_8888(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]); + case 2: out[1] = ycbcr_to_8888(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]); + case 3: out[0] = ycbcr_to_8888(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]); + out -= 4; + ysrc += ystep; + crsrc += cstep; + cbsrc += cstep; + } while((w2 += 4) < 0); + } + + dst = (char *)dst + dststride; + yrow = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]); + cbrow = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]); + crrow = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]); + } while(++y < h); + } +} + +#define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) + +DECLARE_YUV(UYVY, XRGB1555) { + do { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint16 *y; + + cb = src[0]; + cr = src[2]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[1]]]; + *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[4]; + cr = src[6]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]]; + dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f); + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[5]]]; + dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + + dst += 2; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]]; + *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, RGB565) { + do { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint16 *y; + + cb = src[0]; + cr = src[2]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[1]]]; + *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[4]; + cr = src[6]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]]; + dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f); + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[5]]]; + dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + + dst += 2; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]]; + *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, RGB888) { + do { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint8 *y; + + cb = src[0]; + cr = src[2]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + dst += 3; + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[4]; + cr = src[6]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; + dst[0] = y[(bc0+bc1+1)>>1]; + dst[1] = y[(gc0+gc1+1)>>1]; + dst[2] = y[(rc0+rc1+1)>>1]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]]; + dst[3] = y[bc1]; + dst[4] = y[gc1]; + dst[5] = y[rc1]; + + dst += 6; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, XRGB8888) { + do { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint8 *y; + + cb = src[0]; + cr = src[2]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + dst += 4; + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[4]; + cr = src[6]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; + dst[0] = y[(bc0+bc1+1)>>1]; + dst[1] = y[(gc0+gc1+1)>>1]; + dst[2] = y[(rc0+rc1+1)>>1]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]]; + dst[4] = y[bc1]; + dst[5] = y[gc1]; + dst[6] = y[rc1]; + + dst += 8; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, XRGB1555) { + do { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint16 *y; + + cb = src[1]; + cr = src[3]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[0]]]; + *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[5]; + cr = src[7]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]]; + dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f); + + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[4]]]; + dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + + dst += 2; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]]; + *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f); + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, RGB565) { + do { + const uint8 *src = (const uint8 *)src0; + uint16 *dst = (uint16 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint16 *y; + + cb = src[1]; + cr = src[3]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[0]]]; + *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[5]; + cr = src[7]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]]; + dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f); + + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[4]]]; + dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + + dst += 2; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]]; + *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f); + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, RGB888) { + do { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint8 *y; + + cb = src[1]; + cr = src[3]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + dst += 3; + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[5]; + cr = src[7]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; + dst[0] = y[(bc0+bc1+1)>>1]; + dst[1] = y[(gc0+gc1+1)>>1]; + dst[2] = y[(rc0+rc1+1)>>1]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]]; + dst[3] = y[bc1]; + dst[4] = y[gc1]; + dst[5] = y[rc1]; + + dst += 6; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, XRGB8888) { + do { + const uint8 *src = (const uint8 *)src0; + uint8 *dst = (uint8 *)dst0; + + // convert first pixel + int cb, cr; + int rc0, gc0, bc0, rc1, gc1, bc1; + const uint8 *y; + + cb = src[1]; + cr = src[3]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + dst += 4; + + // convert pairs of pixels + int w2 = w; + + if ((w2 -= 2) > 0) { + do { + rc0 = rc1; + gc0 = gc1; + bc0 = bc1; + + cb = src[5]; + cr = src[7]; + rc1 = colorconv.r_cr_tab[cr]; + gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb]; + bc1 = colorconv.b_cb_tab[cb]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; + dst[0] = y[(bc0+bc1+1)>>1]; + dst[1] = y[(gc0+gc1+1)>>1]; + dst[2] = y[(rc0+rc1+1)>>1]; + + y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]]; + dst[4] = y[bc1]; + dst[5] = y[gc1]; + dst[6] = y[rc1]; + + dst += 8; + src += 4; + } while((w2 -= 2) > 0); + } + + // handle oddballs + if (!(w2 & 1)) { + y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]]; + dst[0] = y[bc1]; + dst[1] = y[gc1]; + dst[2] = y[rc1]; + } + + vdptrstep(src0, srcpitch); + vdptrstep(dst0, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, XRGB1555) { + uint16 *dst = (uint16 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 2*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = colorconv.cliptab15[colorconv.y_tab[*src++] + 277]; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, RGB565) { + uint16 *dst = (uint16 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 2*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = colorconv.cliptab16[colorconv.y_tab[*src++] + 277]; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, RGB888) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 3*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + dst[0] = dst[1] = dst[2] = colorconv.cliptab[colorconv.y_tab[*src++] + 277]; + dst += 3; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, XRGB8888) { + uint32 *dst = (uint32 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 4*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = 0x010101 * colorconv.cliptab[colorconv.y_tab[*src++] + 277]; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +#define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) + + +namespace { + typedef void (*tpYUVPlanarFinalDecoder)(void *, const uint8 *, const uint8 *, const uint8 *, uint32); + typedef void (*tpYUVPlanarHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w); + typedef void (*tpYUVPlanarVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); +} + +#ifdef _M_IX86 + extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); + extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); + extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count); +#endif + + +void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); + int hbits = srcinfo.auxwbits; + int vbits = srcinfo.auxhbits; + + if (src.format == nsVDPixmap::kPixFormat_YUV422_UYVY || src.format == nsVDPixmap::kPixFormat_YUV422_YUYV) + hbits = 1; + + bool h_coaligned = true; + bool v_coaligned = false; + + if (src.format == nsVDPixmap::kPixFormat_YUV422_Planar_Centered || + src.format == nsVDPixmap::kPixFormat_YUV420_Planar_Centered) { + h_coaligned = false; + } + + tpYUVPlanarVertDecoder vfunc = NULL; + tpYUVPlanarHorizDecoder hfunc = NULL; + uint32 horiz_buffer_size = 0; + uint32 vert_buffer_size = 0; + uint32 horiz_count = 0; + sint32 yaccum = 8; + sint32 yinc = 8; + uint32 yleft = h; + + switch(vbits*2+v_coaligned) { + case 0: // 4:4:4, 4:2:2 + case 1: + break; + case 2: // 4:2:0 (centered) + vfunc = vert_expand2x_centered; + vert_buffer_size = w>>1; + yaccum = 6; + yinc = 4; + yleft >>= 1; + break; + case 4: // 4:1:0 (centered) + vfunc = vert_expand4x_centered; + vert_buffer_size = w>>2; + yaccum = 5; + yinc = 2; + yleft >>= 2; + break; + default: + VDNEVERHERE; + return; + } + + --yleft; + + tpYUVPlanarFinalDecoder dfunc = NULL; + +#ifdef _M_IX86 + uint32 cpuflags = CPUGetEnabledExtensions(); + + if (cpuflags & CPUF_SUPPORTS_MMX) { + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (vfunc == vert_expand2x_centered) + vfunc = vert_expand2x_centered_ISSE; + } + + switch(dst.format) { + case nsVDPixmap::kPixFormat_XRGB1555: dfunc = vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX; break; + case nsVDPixmap::kPixFormat_RGB565: dfunc = vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX; break; + case nsVDPixmap::kPixFormat_XRGB8888: dfunc = vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX; break; + } + } +#endif + + bool halfchroma = false; + + if (!dfunc) { + switch(dst.format) { + case nsVDPixmap::kPixFormat_XRGB1555: dfunc = VDYCbCrToXRGB1555Span; break; + case nsVDPixmap::kPixFormat_RGB565: dfunc = VDYCbCrToRGB565Span; break; + case nsVDPixmap::kPixFormat_RGB888: dfunc = VDYCbCrToRGB888Span; break; + case nsVDPixmap::kPixFormat_XRGB8888: dfunc = VDYCbCrToXRGB8888Span; break; + case nsVDPixmap::kPixFormat_YUV422_UYVY: dfunc = VDYCbCrToUYVYSpan; halfchroma = true; break; + case nsVDPixmap::kPixFormat_YUV422_YUYV: dfunc = VDYCbCrToYUYVSpan; halfchroma = true; break; + default: + VDNEVERHERE; + return; + } + } + + switch(hbits*2+h_coaligned) { + case 0: // 4:4:4 + case 1: + if (halfchroma) { + hfunc = horiz_compress2x_coaligned; + horiz_buffer_size = (w + 1) >> 1; + horiz_count = w; + } + break; + case 2: // 4:2:0 MPEG-1 (centered) + if (halfchroma) { + hfunc = horiz_realign_to_coaligned; + horiz_buffer_size = (w + 1) >> 1; + horiz_count = (w + 1) >> 1; + } else { + hfunc = horiz_expand2x_centered; + horiz_buffer_size = w; + horiz_count = w; + } + break; + case 3: // 4:2:0/4:2:2 MPEG-2 (coaligned) + if (!halfchroma) { + hfunc = horiz_expand2x_coaligned; + horiz_buffer_size = w; + horiz_count = w; + } + break; + case 5: // 4:1:1 (coaligned) + if (halfchroma) { + hfunc = horiz_expand2x_coaligned; + horiz_buffer_size = (w + 1) >> 1; + horiz_count = (w + 1) >> 1; + } else { + hfunc = horiz_expand4x_coaligned; + horiz_buffer_size = w; + horiz_count = w; + } + break; + + default: + VDNEVERHERE; + return; + } + +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (hfunc == horiz_expand2x_coaligned) + hfunc = horiz_expand2x_coaligned_ISSE; + } +#endif + + uint32 chroma_srcwidth = -(-w >> srcinfo.auxwbits); + horiz_buffer_size = (horiz_buffer_size + 15) & ~15; + vert_buffer_size = (vert_buffer_size + 15) & ~15; + + // allocate buffers + + vdblock tempbuf((horiz_buffer_size + vert_buffer_size)*2 + 1); + + uint8 *const crbufh = tempbuf.data(); + uint8 *const crbufv = crbufh + horiz_buffer_size; + uint8 *const cbbufh = crbufv + vert_buffer_size; + uint8 *const cbbufv = cbbufh + horiz_buffer_size; + + const uint8 *cb0 = (const uint8*)src.data2; + const uint8 *cr0 = (const uint8*)src.data3; + const uint8 *cb1 = cb0; + const uint8 *cr1 = cr0; + const uint8 *y = (const uint8 *)src.data; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + void *out = dst.data; + ptrdiff_t outpitch = dst.pitch; + + for(;;) { + if (yaccum >= 8) { + yaccum &= 7; + + cb0 = cb1; + cr0 = cr1; + + if (yleft > 0) { + --yleft; + vdptrstep(cb1, cbpitch); + vdptrstep(cr1, crpitch); + } + } + + const uint8 *cr = cr0; + const uint8 *cb = cb0; + + // vertical interpolation: cr + if(yaccum & 7) { + const uint8 *const srcs[2]={cr0, cr1}; + vfunc(crbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5); + cr = crbufv; + } + + // horizontal interpolation: cr + if (hfunc) { + hfunc(crbufh, cr, horiz_count); + cr = crbufh; + } + + // vertical interpolation: cb + if(yaccum & 7) { + const uint8 *const srcs[2]={cb0, cb1}; + vfunc(cbbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5); + cb = cbbufv; + } + + // horizontal interpolation: cb + if (hfunc) { + hfunc(cbbufh, cb, horiz_count); + cb = cbbufh; + } + + dfunc(out, y, cb, cr, w); + vdptrstep(out, outpitch); + vdptrstep(y, ypitch); + + if (!--h) + break; + + yaccum += yinc; + } + +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_MMX) { + _mm_empty(); + } +#endif +} + +namespace { + typedef void (*tpUVBltHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w); + typedef void (*tpUVBltVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase); + + void uvplaneblt(uint8 *dst, ptrdiff_t dstpitch, int dstformat, const uint8 *src, ptrdiff_t srcpitch, int srcformat, vdpixsize w, vdpixsize h) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(srcformat); + const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dstformat); + + int xshift = srcinfo.auxwbits - dstinfo.auxwbits; + int yshift = srcinfo.auxhbits - dstinfo.auxhbits; + + tpUVBltHorizDecoder hfunc = NULL; + tpUVBltVertDecoder vfunc = NULL; + + switch(xshift) { + case +2: + hfunc = horiz_expand4x_coaligned; + break; + case +1: + hfunc = horiz_expand2x_coaligned; + break; + case 0: + break; + case -1: + hfunc = horiz_compress2x_coaligned; + break; + case -2: + hfunc = horiz_compress4x_coaligned; + break; + default: + VDNEVERHERE; + return; + } + +#ifdef _M_IX86 + uint32 cpuflags = CPUGetEnabledExtensions(); + + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (hfunc == horiz_expand2x_coaligned) + hfunc = horiz_expand2x_coaligned_ISSE; + } +#endif + + int winsize, winposnext, winstep; + + switch(yshift) { + case +2: + vfunc = vert_expand4x_centered; + winsize = 2; + winposnext = 0xa0; + winstep = 0x40; + break; + case +1: + vfunc = vert_expand2x_centered; + winsize = 2; + winposnext = 0xc0; + winstep = 0x80; + break; + case 0: + winsize = 1; + winposnext = 0; + winstep = 0x100; + break; + case -1: + vfunc = vert_compress2x_centered; + winsize = 4; + winposnext = 0x200; + winstep = 0x200; + break; + case -2: + vfunc = vert_compress4x_centered; + winsize = 8; + winposnext = 0x500; + winstep = 0x400; + break; + default: + VDNEVERHERE; + return; + } + +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (vfunc == vert_expand2x_centered) + vfunc = vert_expand2x_centered_ISSE; + } +#endif + + int dsth = -(-h >> dstinfo.auxhbits); + int srch = -(-h >> srcinfo.auxhbits); + int dstw = -(-w >> dstinfo.auxwbits); + int w2 = -(-w >> std::min(dstinfo.auxwbits, srcinfo.auxwbits)); + + int winpos = (winposnext>>8) - winsize; + + const uint8 *window[16]; + + vdblock tmpbuf; + ptrdiff_t tmppitch = (w+15) & ~15; + + if (vfunc && hfunc) + tmpbuf.resize(tmppitch * winsize); + + do { + int desiredpos = winposnext >> 8; + + while(winpos < desiredpos) { + const uint8 *srcrow = vdptroffset(src, srcpitch * std::max(0, std::min(srch-1, ++winpos))); + int winoffset = (winpos-1) & (winsize-1); + + if (hfunc) { + uint8 *dstrow = vfunc ? tmpbuf.data() + tmppitch * winoffset : dst; + hfunc(dstrow, srcrow, w2); + srcrow = dstrow; + } + + window[winoffset] = window[winoffset + winsize] = srcrow; + } + + if (vfunc) + vfunc(dst, window + (winpos & (winsize-1)), dstw, winposnext & 255); + else if (!hfunc) + memcpy(dst, window[winpos & (winsize-1)], dstw); + + winposnext += winstep; + vdptrstep(dst, dstpitch); + } while(--dsth); + +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_MMX) { + _mm_empty(); + } +#endif + } +} + +void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dstpm, const VDPixmap& srcpm, vdpixsize w, vdpixsize h) { + VDMemcpyRect(dstpm.data, dstpm.pitch, srcpm.data, srcpm.pitch, dstpm.w, dstpm.h); + + if (srcpm.format != nsVDPixmap::kPixFormat_Y8) { + if (dstpm.format != nsVDPixmap::kPixFormat_Y8) { + // YCbCr -> YCbCr + uvplaneblt((uint8 *)dstpm.data2, dstpm.pitch2, dstpm.format, (uint8 *)srcpm.data2, srcpm.pitch2, srcpm.format, w, h); + uvplaneblt((uint8 *)dstpm.data3, dstpm.pitch3, dstpm.format, (uint8 *)srcpm.data3, srcpm.pitch3, srcpm.format, w, h); + } + } else { + if (dstpm.format != nsVDPixmap::kPixFormat_Y8) { + const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstpm.format); + VDMemset8Rect(dstpm.data2, dstpm.pitch2, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits)); + VDMemset8Rect(dstpm.data3, dstpm.pitch3, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits)); + } + } +} + +extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); +extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count); + +DECLARE_YUV_PLANAR(YUV411, XRGB1555) { + uint16 *out = (uint16 *)dst.data; + const ptrdiff_t opitch = dst.pitch; + const uint8 *yrow = (const uint8 *)src.data; + const uint8 *cbrow = (const uint8 *)src.data2; + const uint8 *crrow = (const uint8 *)src.data3; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + vdpixsize wpairs = (w-1)>>2; + vdpixsize wleft = w - (wpairs<<2); + + do { + uint16 *p = out; + const uint8 *y = yrow; + const uint8 *cb = cbrow; + const uint8 *cr = crrow; + vdpixsize wt; + + if (wpairs > 0) { +#if !defined(VD_CPU_X86) + wt = wpairs; + + do { + const unsigned cb0 = cb[0]; + const unsigned cb1 = cb[1]; + const unsigned cr0 = cr[0]; + const unsigned cr1 = cr[1]; + + p[0] = ycbcr_to_1555(y[0], cb0, cr0); + p[1] = ycbcr_to_1555(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); + p[2] = ycbcr_to_1555(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); + p[3] = ycbcr_to_1555(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); + + y += 4; + p += 4; + ++cb; + ++cr; + } while(--wt); +#else + vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(p, y, cb, cr, wpairs); + y += 4*wpairs; + cr += wpairs; + cb += wpairs; + p += 4*wpairs; +#endif + } + + if (wleft > 0) { + wt = wleft; + + const uint8 cr0 = *cr; + const uint8 cb0 = *cb; + + do { + *p++ = ycbcr_to_1555(*y++, cb0, cr0); + } while(--wt); + } + + vdptrstep(out, opitch); + vdptrstep(yrow, ypitch); + vdptrstep(cbrow, cbpitch); + vdptrstep(crrow, crpitch); + } while(--h); + +#ifdef VD_CPU_X86 + _mm_empty(); +#endif +} + +DECLARE_YUV_PLANAR(YUV411, RGB565) { + uint16 *out = (uint16 *)dst.data; + const ptrdiff_t opitch = dst.pitch; + const uint8 *yrow = (const uint8 *)src.data; + const uint8 *cbrow = (const uint8 *)src.data2; + const uint8 *crrow = (const uint8 *)src.data3; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + vdpixsize wpairs = (w-1)>>2; + vdpixsize wleft = w - (wpairs<<2); + + do { + uint16 *p = out; + const uint8 *y = yrow; + const uint8 *cb = cbrow; + const uint8 *cr = crrow; + vdpixsize wt; + + if (wpairs > 0) { +#if !defined(VD_CPU_X86) + wt = wpairs; + + do { + const unsigned cb0 = cb[0]; + const unsigned cb1 = cb[1]; + const unsigned cr0 = cr[0]; + const unsigned cr1 = cr[1]; + + p[0] = ycbcr_to_565(y[0], cb0, cr0); + p[1] = ycbcr_to_565(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); + p[2] = ycbcr_to_565(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); + p[3] = ycbcr_to_565(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); + + y += 4; + p += 4; + ++cb; + ++cr; + } while(--wt); +#else + vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(p, y, cb, cr, wpairs); +#endif + } + + if (wleft > 0) { + wt = wleft; + + const uint8 cr0 = *cr; + const uint8 cb0 = *cb; + + do { + *p++ = ycbcr_to_565(*y++, cb0, cr0); + } while(--wt); + } + + vdptrstep(out, opitch); + vdptrstep(yrow, ypitch); + vdptrstep(cbrow, cbpitch); + vdptrstep(crrow, crpitch); + } while(--h); + +#ifdef VD_CPU_X86 + _mm_empty(); +#endif +} + +DECLARE_YUV_PLANAR(YUV411, RGB888) { + uint8 *out = (uint8 *)dst.data; + const ptrdiff_t opitch = dst.pitch; + const uint8 *yrow = (const uint8 *)src.data; + const uint8 *cbrow = (const uint8 *)src.data2; + const uint8 *crrow = (const uint8 *)src.data3; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + vdpixsize wpairs = (w-1)>>2; + vdpixsize wleft = w - (wpairs<<2); + + do { + uint8 *p = out; + const uint8 *y = yrow; + const uint8 *cb = cbrow; + const uint8 *cr = crrow; + vdpixsize wt; + + if (wpairs > 0) { + wt = wpairs; + + do { + const unsigned cb0 = cb[0]; + const unsigned cb1 = cb[1]; + const unsigned cr0 = cr[0]; + const unsigned cr1 = cr[1]; + + ycbcr_to_888(p+0, y[0], cb0, cr0); + ycbcr_to_888(p+3, y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); + ycbcr_to_888(p+6, y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); + ycbcr_to_888(p+9, y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); + + y += 4; + p += 12; + ++cb; + ++cr; + } while(--wt); + } + + if (wleft > 0) { + wt = wleft; + + const uint8 cr0 = *cr; + const uint8 cb0 = *cb; + + do { + ycbcr_to_888(p, *y++, cb0, cr0); + p += 4; + } while(--wt); + } + + vdptrstep(out, opitch); + vdptrstep(yrow, ypitch); + vdptrstep(cbrow, cbpitch); + vdptrstep(crrow, crpitch); + } while(--h); +} + +DECLARE_YUV_PLANAR(YUV411, XRGB8888) { + uint32 *out = (uint32 *)dst.data; + const ptrdiff_t opitch = dst.pitch; + const uint8 *yrow = (const uint8 *)src.data; + const uint8 *cbrow = (const uint8 *)src.data2; + const uint8 *crrow = (const uint8 *)src.data3; + const ptrdiff_t ypitch = src.pitch; + const ptrdiff_t cbpitch = src.pitch2; + const ptrdiff_t crpitch = src.pitch3; + + vdpixsize wpairs = (w-1)>>2; + vdpixsize wleft = w - (wpairs<<2); + + do { + uint32 *p = out; + const uint8 *y = yrow; + const uint8 *cb = cbrow; + const uint8 *cr = crrow; + vdpixsize wt; + + if (wpairs > 0) { +#if !defined(VD_CPU_X86) + wt = wpairs; + + do { + const unsigned cb0 = cb[0]; + const unsigned cb1 = cb[1]; + const unsigned cr0 = cr[0]; + const unsigned cr1 = cr[1]; + + p[0] = ycbcr_to_8888(y[0], cb0, cr0); + p[1] = ycbcr_to_8888(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2); + p[2] = ycbcr_to_8888(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1); + p[3] = ycbcr_to_8888(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2); + + y += 4; + p += 4; + ++cb; + ++cr; + } while(--wt); +#else + vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(p, y, cb, cr, wpairs); + y += 4*wpairs; + cr += wpairs; + cb += wpairs; + p += 4*wpairs; +#endif + } + + if (wleft > 0) { + wt = wleft; + + const uint8 cr0 = *cr; + const uint8 cb0 = *cb; + + do { + *p++ = ycbcr_to_8888(*y++, cb0, cr0); + } while(--wt); + } + + vdptrstep(out, opitch); + vdptrstep(yrow, ypitch); + vdptrstep(cbrow, cbpitch); + vdptrstep(crrow, crpitch); + } while(--h); + +#ifdef VD_CPU_X86 + _mm_empty(); +#endif +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv2yuv.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv2yuv.cpp index 208d6d35f03..093ac536033 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv2yuv.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuv2yuv.cpp @@ -1,279 +1,279 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include - -#include "bitutils.h" -#include "blt_spanutils.h" - -#define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) - -using namespace nsVDPixmapBitUtils; -using namespace nsVDPixmapSpanUtils; - -DECLARE_YUV(XVYU, UYVY) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - srcpitch -= (w&~1)*4; - dstpitch -= (w&~1)*2; - - do { - vdpixsize wt = w; - - wt = -wt; - - if (++wt) { - uint32 a, b, c; - - a = src[0]; - b = src[1]; - *dst++ = (avg_8888_121(a, a, b) & 0xff00ff) + (a & 0xff00) + ((b & 0xff00)<<16); - src += 2; - - if ((wt+=2) < 0) { - do { - a = src[-1]; - b = src[0]; - c = src[1]; - - *dst++ = (avg_8888_121(a, b, c) & 0xff00ff) + (b & 0xff00) + ((c & 0xff00)<<16); - src += 2; - } while((wt+=2) < 0); - } - } - - if (!(wt&1)) - *dst = *src; - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(XVYU, YUYV) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - srcpitch -= (w&~1)*4; - dstpitch -= (w&~1)*2; - - do { - vdpixsize wt = w; - - wt = -wt; - - if (++wt) { - uint32 a, b, c; - - a = src[0]; - b = src[1]; - *dst++ = ((avg_8888_121(a, a, b) & 0xff00ff)<<8) + ((a & 0xff00)>>8) + ((b & 0xff00)<<8); - src += 2; - - if ((wt+=2)<0) { - do { - a = src[-1]; - b = src[0]; - c = src[1]; - - *dst++ = ((avg_8888_121(a, b, c) & 0xff00ff)<<8) + ((b & 0xff00)>>8) + ((c & 0xff00)<<8); - src += 2; - } while((wt+=2) < 0); - } - } - - if (!(wt&1)) { - uint32 v = *src; - *dst = ((v&0xff00ff)<<8) + ((v&0xff00ff00)>>8); - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, YUYV) { // also YUYV->UYVY - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - w = (w+1) >> 1; - - dstpitch -= 4*w; - srcpitch -= 4*w; - - do { - vdpixsize w2 = w; - - do { - const uint32 p = *src++; - - *dst++ = ((p & 0xff00ff00)>>8) + ((p & 0x00ff00ff)<<8); - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(UYVY, Y8) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= w; - srcpitch -= 2*w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = src[1]; - src += 2; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(YUYV, Y8) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= w; - srcpitch -= 2*w; - - do { - vdpixsize w2 = w; - - do { - *dst++ = src[0]; - src += 2; - } while(--w2); - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, UYVY) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 2*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - dst[0] = 0x80; - dst[1] = *src++; - dst += 2; - } while(--w2); - - if (w & 1) { - dst[0] = 0x80; - dst[1] = dst[-1]; - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV(Y8, YUYV) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - dstpitch -= 2*w; - srcpitch -= w; - - do { - vdpixsize w2 = w; - - do { - dst[0] = *src++; - dst[1] = 0x80; - dst += 2; - } while(--w2); - - if (w & 1) { - dst[0] = dst[-1]; - dst[1] = 0x80; - } - - vdptrstep(src, srcpitch); - vdptrstep(dst, dstpitch); - } while(--h); -} - -DECLARE_YUV_PLANAR(YUV411, YV12) { - VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, w, h); - - vdblock tmprow(w); - const uint8 *srcp = (const uint8 *)src.data2; - ptrdiff_t srcpitch = src.pitch2; - uint8 *dstp = (uint8 *)dst.data2; - ptrdiff_t dstpitch = dst.pitch2; - const uint8 *src1, *src2; - - vdpixsize h2; - for(h2 = h; h2 > 0; h2 -= 2) { - src1 = srcp; - vdptrstep(srcp, srcpitch); - if (h2 > 1) - src2 = srcp; - else - src2 = src1; - vdptrstep(srcp, srcpitch); - - const uint8 *sources[2] = {src1, src2}; - - vert_compress2x_centered_fast(tmprow.data(), sources, w, 0); - horiz_expand2x_coaligned(dstp, tmprow.data(), w); - - vdptrstep(dstp, dstpitch); - } - - srcp = (const uint8 *)src.data3; - srcpitch = src.pitch3; - dstp = (uint8 *)dst.data3; - dstpitch = dst.pitch3; - for(h2 = h; h2 > 0; h2 -= 2) { - src1 = srcp; - vdptrstep(srcp, srcpitch); - if (h2 > 1) - src2 = srcp; - else - src2 = src1; - vdptrstep(srcp, srcpitch); - - const uint8 *sources[2] = {src1, src2}; - vert_compress2x_centered_fast(tmprow.data(), sources, w, 0); - horiz_expand2x_coaligned(dstp, tmprow.data(), w); - - vdptrstep(dstp, dstpitch); - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include + +#include "bitutils.h" +#include "blt_spanutils.h" + +#define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) + +using namespace nsVDPixmapBitUtils; +using namespace nsVDPixmapSpanUtils; + +DECLARE_YUV(XVYU, UYVY) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + srcpitch -= (w&~1)*4; + dstpitch -= (w&~1)*2; + + do { + vdpixsize wt = w; + + wt = -wt; + + if (++wt) { + uint32 a, b, c; + + a = src[0]; + b = src[1]; + *dst++ = (avg_8888_121(a, a, b) & 0xff00ff) + (a & 0xff00) + ((b & 0xff00)<<16); + src += 2; + + if ((wt+=2) < 0) { + do { + a = src[-1]; + b = src[0]; + c = src[1]; + + *dst++ = (avg_8888_121(a, b, c) & 0xff00ff) + (b & 0xff00) + ((c & 0xff00)<<16); + src += 2; + } while((wt+=2) < 0); + } + } + + if (!(wt&1)) + *dst = *src; + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(XVYU, YUYV) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + srcpitch -= (w&~1)*4; + dstpitch -= (w&~1)*2; + + do { + vdpixsize wt = w; + + wt = -wt; + + if (++wt) { + uint32 a, b, c; + + a = src[0]; + b = src[1]; + *dst++ = ((avg_8888_121(a, a, b) & 0xff00ff)<<8) + ((a & 0xff00)>>8) + ((b & 0xff00)<<8); + src += 2; + + if ((wt+=2)<0) { + do { + a = src[-1]; + b = src[0]; + c = src[1]; + + *dst++ = ((avg_8888_121(a, b, c) & 0xff00ff)<<8) + ((b & 0xff00)>>8) + ((c & 0xff00)<<8); + src += 2; + } while((wt+=2) < 0); + } + } + + if (!(wt&1)) { + uint32 v = *src; + *dst = ((v&0xff00ff)<<8) + ((v&0xff00ff00)>>8); + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, YUYV) { // also YUYV->UYVY + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + w = (w+1) >> 1; + + dstpitch -= 4*w; + srcpitch -= 4*w; + + do { + vdpixsize w2 = w; + + do { + const uint32 p = *src++; + + *dst++ = ((p & 0xff00ff00)>>8) + ((p & 0x00ff00ff)<<8); + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(UYVY, Y8) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= w; + srcpitch -= 2*w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = src[1]; + src += 2; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(YUYV, Y8) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= w; + srcpitch -= 2*w; + + do { + vdpixsize w2 = w; + + do { + *dst++ = src[0]; + src += 2; + } while(--w2); + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, UYVY) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 2*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + dst[0] = 0x80; + dst[1] = *src++; + dst += 2; + } while(--w2); + + if (w & 1) { + dst[0] = 0x80; + dst[1] = dst[-1]; + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV(Y8, YUYV) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + dstpitch -= 2*w; + srcpitch -= w; + + do { + vdpixsize w2 = w; + + do { + dst[0] = *src++; + dst[1] = 0x80; + dst += 2; + } while(--w2); + + if (w & 1) { + dst[0] = dst[-1]; + dst[1] = 0x80; + } + + vdptrstep(src, srcpitch); + vdptrstep(dst, dstpitch); + } while(--h); +} + +DECLARE_YUV_PLANAR(YUV411, YV12) { + VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, w, h); + + vdblock tmprow(w); + const uint8 *srcp = (const uint8 *)src.data2; + ptrdiff_t srcpitch = src.pitch2; + uint8 *dstp = (uint8 *)dst.data2; + ptrdiff_t dstpitch = dst.pitch2; + const uint8 *src1, *src2; + + vdpixsize h2; + for(h2 = h; h2 > 0; h2 -= 2) { + src1 = srcp; + vdptrstep(srcp, srcpitch); + if (h2 > 1) + src2 = srcp; + else + src2 = src1; + vdptrstep(srcp, srcpitch); + + const uint8 *sources[2] = {src1, src2}; + + vert_compress2x_centered_fast(tmprow.data(), sources, w, 0); + horiz_expand2x_coaligned(dstp, tmprow.data(), w); + + vdptrstep(dstp, dstpitch); + } + + srcp = (const uint8 *)src.data3; + srcpitch = src.pitch3; + dstp = (uint8 *)dst.data3; + dstpitch = dst.pitch3; + for(h2 = h; h2 > 0; h2 -= 2) { + src1 = srcp; + vdptrstep(srcp, srcpitch); + if (h2 > 1) + src2 = srcp; + else + src2 = src1; + vdptrstep(srcp, srcpitch); + + const uint8 *sources[2] = {src1, src2}; + vert_compress2x_centered_fast(tmprow.data(), sources, w, 0); + horiz_expand2x_coaligned(dstp, tmprow.data(), w); + + vdptrstep(dstp, dstpitch); + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuvrev.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuvrev.cpp index 701c2111123..d6f6ce75d91 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuvrev.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_reference_yuvrev.cpp @@ -1,549 +1,549 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include "blt_spanutils.h" - -#ifdef _M_IX86 - #include "blt_spanutils_x86.h" -#endif - -using namespace nsVDPixmapSpanUtils; - -namespace { - // From Jim Blinn's "Dirty Pixels": - // - // Y = .299R + .587G + .114B - // Cr = 0.713(R-Y) - // Cb = 0.564(B-Y) - // - // IY = 219Y + 16 = ((yt = 1052IR + 2065IG + 401IB) + 67584) >> 12 - // ICr = 224Cr + 128 = (yt*2987 - 10507932IR + 2155872256) >> 24 - // ICb = 224Cb + 128 = (yt*2363 - 8312025IB + 2155872256) >> 24 - - void ConvertRGB32ToXVYU32(uint32 *dst, const uint8 *src, sint32 count) { - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - const sint32 yt = 1052*r + 2065*g + 401*b; - const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift - const sint32 cr = (10507932*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift - const sint32 cb = ( 8312025*b - yt*2363 + 2155872256U) >> 24; - - *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order - src += 4; - } while(--count); - } - - void ConvertRGB24ToXVYU32(uint32 *dst, const uint8 *src, sint32 count) { - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - const sint32 yt = 1052*r + 2065*g + 401*b; - const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift - const sint32 cr = (10507932*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift - const sint32 cb = ( 8312025*b - yt*2363 + 2155872256U) >> 24; - - *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order - src += 3; - } while(--count); - } - - void ConvertRGB16ToXVYU32(uint32 *dst, const uint16 *src, sint32 count) { - do { - const sint16 px = *src++; - const sint32 r = (px & 0xf800) >> 11; - const sint32 g = (px & 0x07e0) >> 5; - const sint32 b = (px & 0x001f); - const sint32 yt = 8652*r + 8358*g + 3299*b; - const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift - const sint32 cr = (86436217*r - yt*2987 + 2155872256U) >> 8; - const sint32 cb = (68373108*b - yt*2363 + 2155872256U) >> 24; // <<16 alignment shift - - *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order - } while(--count); - } - - void ConvertRGB15ToXVYU32(uint32 *dst, const uint16 *src, sint32 count) { - do { - const sint16 px = *src++; - const sint32 r = (px & 0x7c00) >> 10; - const sint32 g = (px & 0x03e0) >> 5; - const sint32 b = (px & 0x001f); - const sint32 yt = 8652*r + 16986*g + 3299*b; - const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift - const sint32 cr = (86436217*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift - const sint32 cb = (68373108*b - yt*2363 + 2155872256U) >> 24; - - *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order - } while(--count); - } - - void ConvertRGB32ToY8(uint8 *dst, const uint8 *src, sint32 count) { - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - *dst++ = (uint8)((1052*r + 2065*g + 401*b + 67584) >> 12); - src += 4; - } while(--count); - } - - void ConvertRGB24ToY8(uint8 *dst, const uint8 *src, sint32 count) { - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - *dst++ = (uint8)((1052*r + 2065*g + 401*b + 67584) >> 12); - src += 3; - } while(--count); - } - - void ConvertRGB16ToY8(uint8 *dst, const uint16 *src, sint32 count) { - do { - const sint16 px = *src++; - const sint32 r = (px & 0xf800) >> 11; - const sint32 g = (px & 0x07e0) >> 5; - const sint32 b = (px & 0x001f); - *dst++ = (uint8)((8652*r + 8358*g + 3299*b + 67584) >> 12); - } while(--count); - } - - void ConvertRGB15ToY8(uint8 *dst, const uint16 *src, sint32 count) { - do { - const sint16 px = *src++; - const sint32 r = (px & 0x7c00) >> 10; - const sint32 g = (px & 0x03e0) >> 5; - const sint32 b = (px & 0x001f); - *dst++ = (uint8)((8652*r + 16986*g + 3299*b + 67584) >> 12); - } while(--count); - } -} - -#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) - -DECLARE_YUV_REV(XRGB1555, XVYU) { - do { - ConvertRGB15ToXVYU32((uint32 *)dst0, (const uint16 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(RGB565, XVYU) { - do { - ConvertRGB16ToXVYU32((uint32 *)dst0, (const uint16 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(RGB888, XVYU) { - do { - ConvertRGB24ToXVYU32((uint32 *)dst0, (const uint8 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(XRGB8888, XVYU) { - do { - ConvertRGB32ToXVYU32((uint32 *)dst0, (const uint8 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(XRGB1555, Y8) { - do { - ConvertRGB15ToY8((uint8 *)dst0, (const uint16 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(RGB565, Y8) { - do { - ConvertRGB16ToY8((uint8 *)dst0, (const uint16 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(RGB888, Y8) { - do { - ConvertRGB24ToY8((uint8 *)dst0, (const uint8 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - -DECLARE_YUV_REV(XRGB8888, Y8) { - do { - ConvertRGB32ToY8((uint8 *)dst0, (const uint8 *)src0, w); - - vdptrstep(dst0, dstpitch); - vdptrstep(src0, srcpitch); - } while(--h); -} - - - - - -namespace { - void ConvertRGB32ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint8 *src = (const uint8 *)src0; - - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - const sint32 yt = 1052*r + 2065*g + 401*b; - *ydst++ = (yt + 67584) >> 12; - *crdst++ = (10507932*r - yt*2987 + 2155872256U) >> 24; - *cbdst++ = ( 8312025*b - yt*2363 + 2155872256U) >> 24; - src += 4; - } while(--count); - } - - void ConvertRGB24ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint8 *src = (const uint8 *)src0; - - do { - const sint32 r = src[2]; - const sint32 g = src[1]; - const sint32 b = src[0]; - const sint32 yt = 1052*r + 2065*g + 401*b; - *ydst++ = (yt + 67584) >> 12; - *crdst++ = (10507932*r - yt*2987 + 2155872256U) >> 24; - *cbdst++ = ( 8312025*b - yt*2363 + 2155872256U) >> 24; - src += 3; - } while(--count); - } - - void ConvertRGB16ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint16 *src = (const uint16 *)src0; - - do { - const sint16 px = *src++; - const sint32 r = (px & 0xf800) >> 11; - const sint32 g = (px & 0x07e0) >> 5; - const sint32 b = (px & 0x001f); - const sint32 yt = 8652*r + 8358*g + 3299*b; - *ydst++ = (yt + 67584) >> 12; - *crdst++ = (86436217*r - yt*2987 + 2155872256U) >> 24; - *cbdst++ = (68373108*b - yt*2363 + 2155872256U) >> 24; - } while(--count); - } - - void ConvertRGB15ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint16 *src = (const uint16 *)src0; - - do { - const sint16 px = *src++; - const sint32 r = (px & 0x7c00) >> 10; - const sint32 g = (px & 0x03e0) >> 5; - const sint32 b = (px & 0x001f); - const sint32 yt = 8652*r + 16986*g + 3299*b; - *ydst++ = (yt + 67584) >> 12; - *crdst++ = (86436217*r - yt*2987 + 2155872256U) >> 24; - *cbdst++ = (68373108*b - yt*2363 + 2155872256U) >> 24; - } while(--count); - } - - void ConvertUYVYToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint8 *src = (const uint8 *)src0; - - do { - *cbdst++ = src[0]; - *ydst++ = src[1]; - *crdst++ = src[2]; - if (!--count) - break; - *ydst++ = src[3]; - src += 4; - } while(--count); - } - - void ConvertYUYVToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { - const uint8 *src = (const uint8 *)src0; - - do { - *cbdst++ = src[1]; - *ydst++ = src[0]; - *crdst++ = src[3]; - if (!--count) - break; - *ydst++ = src[2]; - src += 4; - } while(--count); - } -} - -void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dstbm, const VDPixmap& srcbm, vdpixsize w, vdpixsize h) { - void (*cfunc)(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src, sint32 w) = NULL; - void (*hfunc)(uint8 *dst, const uint8 *src, sint32 w) = NULL; - void (*vfunc)(uint8 *dst, const uint8 *const *sources, sint32 w, uint8 phase) = NULL; - - bool halfchroma = false; - - switch(srcbm.format) { - case nsVDPixmap::kPixFormat_XRGB1555: - cfunc = ConvertRGB15ToYUVPlanar; - break; - case nsVDPixmap::kPixFormat_RGB565: - cfunc = ConvertRGB16ToYUVPlanar; - break; - case nsVDPixmap::kPixFormat_RGB888: - cfunc = ConvertRGB24ToYUVPlanar; - break; - case nsVDPixmap::kPixFormat_XRGB8888: - cfunc = ConvertRGB32ToYUVPlanar; - break; - case nsVDPixmap::kPixFormat_YUV422_UYVY: - cfunc = ConvertUYVYToYUVPlanar; - halfchroma = true; - break; - case nsVDPixmap::kPixFormat_YUV422_YUYV: - cfunc = ConvertYUYVToYUVPlanar; - halfchroma = true; - break; - default: - VDNEVERHERE; - return; - } - - vdpixsize w2 = w; - vdpixsize h2 = h; - int winstep = 1; - int winsize = 1; - int winposnext = 0; - vdpixsize chroma_srcw = w; - - switch(dstbm.format) { - - case nsVDPixmap::kPixFormat_YUV444_Planar: - if (halfchroma) - hfunc = horiz_expand2x_coaligned; - break; - - case nsVDPixmap::kPixFormat_YUV422_Planar: - if (halfchroma) - chroma_srcw = (chroma_srcw + 1) >> 1; - else - hfunc = horiz_compress2x_coaligned; - - w2 = (w2+1) >> 1; - break; - - case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: - if (halfchroma) { - chroma_srcw = (chroma_srcw + 1) >> 1; - hfunc = horiz_realign_to_centered; - } else - hfunc = horiz_compress2x_centered; - - w2 = (w2+1) >> 1; - break; - - case nsVDPixmap::kPixFormat_YUV420_Planar: - if (halfchroma) - chroma_srcw = (chroma_srcw + 1) >> 1; - else - hfunc = horiz_compress2x_coaligned; - - vfunc = vert_compress2x_centered; - winstep = 2; - winposnext = 2; - winsize = 4; - h2 = (h+1) >> 1; - w2 = (w2+1) >> 1; - break; - - case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: - if (halfchroma) { - chroma_srcw = (chroma_srcw + 1) >> 1; - hfunc = horiz_realign_to_centered; - } else - hfunc = horiz_compress2x_centered; - - vfunc = vert_compress2x_centered; - winstep = 2; - winposnext = 2; - winsize = 4; - h2 = (h+1) >> 1; - w2 = (w2+1) >> 1; - break; - - case nsVDPixmap::kPixFormat_YUV411_Planar: - if (halfchroma) { - chroma_srcw = (chroma_srcw + 1) >> 1; - hfunc = horiz_compress2x_coaligned; - } else - hfunc = horiz_compress4x_coaligned; - w2 = (w2+1) >> 2; - break; - - case nsVDPixmap::kPixFormat_YUV410_Planar: - if (halfchroma) { - chroma_srcw = (chroma_srcw + 1) >> 1; - hfunc = horiz_compress2x_coaligned; - } else - hfunc = horiz_compress4x_coaligned; - vfunc = vert_compress4x_centered; - winsize = 8; - winposnext = 5; - winstep = 4; - h2 = (h+3) >> 2; - w2 = (w2+3) >> 2; - break; - } - -#ifdef _M_IX86 - uint32 cpuflags = CPUGetEnabledExtensions(); - - if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { - if (hfunc == horiz_expand2x_coaligned) - hfunc = horiz_expand2x_coaligned_ISSE; - } -#endif - - const uint8 *src = (const uint8 *)srcbm.data; - const ptrdiff_t srcpitch = srcbm.pitch; - - uint8 *ydst = (uint8 *)dstbm.data; - uint8 *cbdst = (uint8 *)dstbm.data2; - uint8 *crdst = (uint8 *)dstbm.data3; - const ptrdiff_t ydstpitch = dstbm.pitch; - const ptrdiff_t cbdstpitch = dstbm.pitch2; - const ptrdiff_t crdstpitch = dstbm.pitch3; - - if (!vfunc) { - if (hfunc) { - uint32 tmpsize = (w + 15) & ~15; - - vdblock tmp(tmpsize * 2); - uint8 *const cbtmp = tmp.data(); - uint8 *const crtmp = cbtmp + tmpsize; - - do { - cfunc(ydst, cbtmp, crtmp, src, w); - src += srcpitch; - ydst += ydstpitch; - hfunc(cbdst, cbtmp, chroma_srcw); - hfunc(crdst, crtmp, chroma_srcw); - cbdst += cbdstpitch; - crdst += crdstpitch; - } while(--h); - } else if (dstbm.format == nsVDPixmap::kPixFormat_Y8) { - // wasteful, but oh well - uint32 tmpsize = (w2+15)&~15; - vdblock tmp(tmpsize); - - cbdst = tmp.data(); - crdst = cbdst + tmpsize; - - do { - cfunc(ydst, cbdst, crdst, src, w); - src += srcpitch; - ydst += ydstpitch; - } while(--h2); - } else { - do { - cfunc(ydst, cbdst, crdst, src, w); - src += srcpitch; - ydst += ydstpitch; - cbdst += cbdstpitch; - crdst += crdstpitch; - } while(--h2); - } - } else { - const uint32 tmpsize = w2; - - vdblock tmpbuf(tmpsize * (winsize + 1) * 2 + 2 * w); - - uint8 *cbwindow[16]; - uint8 *crwindow[16]; - - uint8 *p = tmpbuf.data(); - for(int i=0; i +#include +#include +#include +#include +#include +#include "blt_spanutils.h" + +#ifdef _M_IX86 + #include "blt_spanutils_x86.h" +#endif + +using namespace nsVDPixmapSpanUtils; + +namespace { + // From Jim Blinn's "Dirty Pixels": + // + // Y = .299R + .587G + .114B + // Cr = 0.713(R-Y) + // Cb = 0.564(B-Y) + // + // IY = 219Y + 16 = ((yt = 1052IR + 2065IG + 401IB) + 67584) >> 12 + // ICr = 224Cr + 128 = (yt*2987 - 10507932IR + 2155872256) >> 24 + // ICb = 224Cb + 128 = (yt*2363 - 8312025IB + 2155872256) >> 24 + + void ConvertRGB32ToXVYU32(uint32 *dst, const uint8 *src, sint32 count) { + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + const sint32 yt = 1052*r + 2065*g + 401*b; + const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift + const sint32 cr = (10507932*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift + const sint32 cb = ( 8312025*b - yt*2363 + 2155872256U) >> 24; + + *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order + src += 4; + } while(--count); + } + + void ConvertRGB24ToXVYU32(uint32 *dst, const uint8 *src, sint32 count) { + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + const sint32 yt = 1052*r + 2065*g + 401*b; + const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift + const sint32 cr = (10507932*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift + const sint32 cb = ( 8312025*b - yt*2363 + 2155872256U) >> 24; + + *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order + src += 3; + } while(--count); + } + + void ConvertRGB16ToXVYU32(uint32 *dst, const uint16 *src, sint32 count) { + do { + const sint16 px = *src++; + const sint32 r = (px & 0xf800) >> 11; + const sint32 g = (px & 0x07e0) >> 5; + const sint32 b = (px & 0x001f); + const sint32 yt = 8652*r + 8358*g + 3299*b; + const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift + const sint32 cr = (86436217*r - yt*2987 + 2155872256U) >> 8; + const sint32 cb = (68373108*b - yt*2363 + 2155872256U) >> 24; // <<16 alignment shift + + *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order + } while(--count); + } + + void ConvertRGB15ToXVYU32(uint32 *dst, const uint16 *src, sint32 count) { + do { + const sint16 px = *src++; + const sint32 r = (px & 0x7c00) >> 10; + const sint32 g = (px & 0x03e0) >> 5; + const sint32 b = (px & 0x001f); + const sint32 yt = 8652*r + 16986*g + 3299*b; + const sint32 y = (yt + 67584) >> 4; // <<8 alignment shift + const sint32 cr = (86436217*r - yt*2987 + 2155872256U) >> 8; // <<16 alignment shift + const sint32 cb = (68373108*b - yt*2363 + 2155872256U) >> 24; + + *dst++ = (y&0xff00) + cb + (cr&0xff0000); // VYU order + } while(--count); + } + + void ConvertRGB32ToY8(uint8 *dst, const uint8 *src, sint32 count) { + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + *dst++ = (uint8)((1052*r + 2065*g + 401*b + 67584) >> 12); + src += 4; + } while(--count); + } + + void ConvertRGB24ToY8(uint8 *dst, const uint8 *src, sint32 count) { + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + *dst++ = (uint8)((1052*r + 2065*g + 401*b + 67584) >> 12); + src += 3; + } while(--count); + } + + void ConvertRGB16ToY8(uint8 *dst, const uint16 *src, sint32 count) { + do { + const sint16 px = *src++; + const sint32 r = (px & 0xf800) >> 11; + const sint32 g = (px & 0x07e0) >> 5; + const sint32 b = (px & 0x001f); + *dst++ = (uint8)((8652*r + 8358*g + 3299*b + 67584) >> 12); + } while(--count); + } + + void ConvertRGB15ToY8(uint8 *dst, const uint16 *src, sint32 count) { + do { + const sint16 px = *src++; + const sint32 r = (px & 0x7c00) >> 10; + const sint32 g = (px & 0x03e0) >> 5; + const sint32 b = (px & 0x001f); + *dst++ = (uint8)((8652*r + 16986*g + 3299*b + 67584) >> 12); + } while(--count); + } +} + +#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) + +DECLARE_YUV_REV(XRGB1555, XVYU) { + do { + ConvertRGB15ToXVYU32((uint32 *)dst0, (const uint16 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(RGB565, XVYU) { + do { + ConvertRGB16ToXVYU32((uint32 *)dst0, (const uint16 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(RGB888, XVYU) { + do { + ConvertRGB24ToXVYU32((uint32 *)dst0, (const uint8 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(XRGB8888, XVYU) { + do { + ConvertRGB32ToXVYU32((uint32 *)dst0, (const uint8 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(XRGB1555, Y8) { + do { + ConvertRGB15ToY8((uint8 *)dst0, (const uint16 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(RGB565, Y8) { + do { + ConvertRGB16ToY8((uint8 *)dst0, (const uint16 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(RGB888, Y8) { + do { + ConvertRGB24ToY8((uint8 *)dst0, (const uint8 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + +DECLARE_YUV_REV(XRGB8888, Y8) { + do { + ConvertRGB32ToY8((uint8 *)dst0, (const uint8 *)src0, w); + + vdptrstep(dst0, dstpitch); + vdptrstep(src0, srcpitch); + } while(--h); +} + + + + + +namespace { + void ConvertRGB32ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint8 *src = (const uint8 *)src0; + + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + const sint32 yt = 1052*r + 2065*g + 401*b; + *ydst++ = (yt + 67584) >> 12; + *crdst++ = (10507932*r - yt*2987 + 2155872256U) >> 24; + *cbdst++ = ( 8312025*b - yt*2363 + 2155872256U) >> 24; + src += 4; + } while(--count); + } + + void ConvertRGB24ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint8 *src = (const uint8 *)src0; + + do { + const sint32 r = src[2]; + const sint32 g = src[1]; + const sint32 b = src[0]; + const sint32 yt = 1052*r + 2065*g + 401*b; + *ydst++ = (yt + 67584) >> 12; + *crdst++ = (10507932*r - yt*2987 + 2155872256U) >> 24; + *cbdst++ = ( 8312025*b - yt*2363 + 2155872256U) >> 24; + src += 3; + } while(--count); + } + + void ConvertRGB16ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint16 *src = (const uint16 *)src0; + + do { + const sint16 px = *src++; + const sint32 r = (px & 0xf800) >> 11; + const sint32 g = (px & 0x07e0) >> 5; + const sint32 b = (px & 0x001f); + const sint32 yt = 8652*r + 8358*g + 3299*b; + *ydst++ = (yt + 67584) >> 12; + *crdst++ = (86436217*r - yt*2987 + 2155872256U) >> 24; + *cbdst++ = (68373108*b - yt*2363 + 2155872256U) >> 24; + } while(--count); + } + + void ConvertRGB15ToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint16 *src = (const uint16 *)src0; + + do { + const sint16 px = *src++; + const sint32 r = (px & 0x7c00) >> 10; + const sint32 g = (px & 0x03e0) >> 5; + const sint32 b = (px & 0x001f); + const sint32 yt = 8652*r + 16986*g + 3299*b; + *ydst++ = (yt + 67584) >> 12; + *crdst++ = (86436217*r - yt*2987 + 2155872256U) >> 24; + *cbdst++ = (68373108*b - yt*2363 + 2155872256U) >> 24; + } while(--count); + } + + void ConvertUYVYToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint8 *src = (const uint8 *)src0; + + do { + *cbdst++ = src[0]; + *ydst++ = src[1]; + *crdst++ = src[2]; + if (!--count) + break; + *ydst++ = src[3]; + src += 4; + } while(--count); + } + + void ConvertYUYVToYUVPlanar(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src0, sint32 count) { + const uint8 *src = (const uint8 *)src0; + + do { + *cbdst++ = src[1]; + *ydst++ = src[0]; + *crdst++ = src[3]; + if (!--count) + break; + *ydst++ = src[2]; + src += 4; + } while(--count); + } +} + +void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dstbm, const VDPixmap& srcbm, vdpixsize w, vdpixsize h) { + void (*cfunc)(uint8 *ydst, uint8 *cbdst, uint8 *crdst, const void *src, sint32 w) = NULL; + void (*hfunc)(uint8 *dst, const uint8 *src, sint32 w) = NULL; + void (*vfunc)(uint8 *dst, const uint8 *const *sources, sint32 w, uint8 phase) = NULL; + + bool halfchroma = false; + + switch(srcbm.format) { + case nsVDPixmap::kPixFormat_XRGB1555: + cfunc = ConvertRGB15ToYUVPlanar; + break; + case nsVDPixmap::kPixFormat_RGB565: + cfunc = ConvertRGB16ToYUVPlanar; + break; + case nsVDPixmap::kPixFormat_RGB888: + cfunc = ConvertRGB24ToYUVPlanar; + break; + case nsVDPixmap::kPixFormat_XRGB8888: + cfunc = ConvertRGB32ToYUVPlanar; + break; + case nsVDPixmap::kPixFormat_YUV422_UYVY: + cfunc = ConvertUYVYToYUVPlanar; + halfchroma = true; + break; + case nsVDPixmap::kPixFormat_YUV422_YUYV: + cfunc = ConvertYUYVToYUVPlanar; + halfchroma = true; + break; + default: + VDNEVERHERE; + return; + } + + vdpixsize w2 = w; + vdpixsize h2 = h; + int winstep = 1; + int winsize = 1; + int winposnext = 0; + vdpixsize chroma_srcw = w; + + switch(dstbm.format) { + + case nsVDPixmap::kPixFormat_YUV444_Planar: + if (halfchroma) + hfunc = horiz_expand2x_coaligned; + break; + + case nsVDPixmap::kPixFormat_YUV422_Planar: + if (halfchroma) + chroma_srcw = (chroma_srcw + 1) >> 1; + else + hfunc = horiz_compress2x_coaligned; + + w2 = (w2+1) >> 1; + break; + + case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: + if (halfchroma) { + chroma_srcw = (chroma_srcw + 1) >> 1; + hfunc = horiz_realign_to_centered; + } else + hfunc = horiz_compress2x_centered; + + w2 = (w2+1) >> 1; + break; + + case nsVDPixmap::kPixFormat_YUV420_Planar: + if (halfchroma) + chroma_srcw = (chroma_srcw + 1) >> 1; + else + hfunc = horiz_compress2x_coaligned; + + vfunc = vert_compress2x_centered; + winstep = 2; + winposnext = 2; + winsize = 4; + h2 = (h+1) >> 1; + w2 = (w2+1) >> 1; + break; + + case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: + if (halfchroma) { + chroma_srcw = (chroma_srcw + 1) >> 1; + hfunc = horiz_realign_to_centered; + } else + hfunc = horiz_compress2x_centered; + + vfunc = vert_compress2x_centered; + winstep = 2; + winposnext = 2; + winsize = 4; + h2 = (h+1) >> 1; + w2 = (w2+1) >> 1; + break; + + case nsVDPixmap::kPixFormat_YUV411_Planar: + if (halfchroma) { + chroma_srcw = (chroma_srcw + 1) >> 1; + hfunc = horiz_compress2x_coaligned; + } else + hfunc = horiz_compress4x_coaligned; + w2 = (w2+1) >> 2; + break; + + case nsVDPixmap::kPixFormat_YUV410_Planar: + if (halfchroma) { + chroma_srcw = (chroma_srcw + 1) >> 1; + hfunc = horiz_compress2x_coaligned; + } else + hfunc = horiz_compress4x_coaligned; + vfunc = vert_compress4x_centered; + winsize = 8; + winposnext = 5; + winstep = 4; + h2 = (h+3) >> 2; + w2 = (w2+3) >> 2; + break; + } + +#ifdef _M_IX86 + uint32 cpuflags = CPUGetEnabledExtensions(); + + if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) { + if (hfunc == horiz_expand2x_coaligned) + hfunc = horiz_expand2x_coaligned_ISSE; + } +#endif + + const uint8 *src = (const uint8 *)srcbm.data; + const ptrdiff_t srcpitch = srcbm.pitch; + + uint8 *ydst = (uint8 *)dstbm.data; + uint8 *cbdst = (uint8 *)dstbm.data2; + uint8 *crdst = (uint8 *)dstbm.data3; + const ptrdiff_t ydstpitch = dstbm.pitch; + const ptrdiff_t cbdstpitch = dstbm.pitch2; + const ptrdiff_t crdstpitch = dstbm.pitch3; + + if (!vfunc) { + if (hfunc) { + uint32 tmpsize = (w + 15) & ~15; + + vdblock tmp(tmpsize * 2); + uint8 *const cbtmp = tmp.data(); + uint8 *const crtmp = cbtmp + tmpsize; + + do { + cfunc(ydst, cbtmp, crtmp, src, w); + src += srcpitch; + ydst += ydstpitch; + hfunc(cbdst, cbtmp, chroma_srcw); + hfunc(crdst, crtmp, chroma_srcw); + cbdst += cbdstpitch; + crdst += crdstpitch; + } while(--h); + } else if (dstbm.format == nsVDPixmap::kPixFormat_Y8) { + // wasteful, but oh well + uint32 tmpsize = (w2+15)&~15; + vdblock tmp(tmpsize); + + cbdst = tmp.data(); + crdst = cbdst + tmpsize; + + do { + cfunc(ydst, cbdst, crdst, src, w); + src += srcpitch; + ydst += ydstpitch; + } while(--h2); + } else { + do { + cfunc(ydst, cbdst, crdst, src, w); + src += srcpitch; + ydst += ydstpitch; + cbdst += cbdstpitch; + crdst += crdstpitch; + } while(--h2); + } + } else { + const uint32 tmpsize = w2; + + vdblock tmpbuf(tmpsize * (winsize + 1) * 2 + 2 * w); + + uint8 *cbwindow[16]; + uint8 *crwindow[16]; + + uint8 *p = tmpbuf.data(); + for(int i=0; i -#include "blt_setup.h" - -void VDPixmapBlitterTable::Clear() { - memset(mTable, 0, sizeof mTable); -} - -void VDPixmapBlitterTable::AddBlitter(const VDPixmapFormatSubset& srcFormats, VDPixmapFormatSubset& dstFormats, VDPixmapBlitterFn blitter) { - for(int i=0; i +#include "blt_setup.h" + +void VDPixmapBlitterTable::Clear() { + memset(mTable, 0, sizeof mTable); +} + +void VDPixmapBlitterTable::AddBlitter(const VDPixmapFormatSubset& srcFormats, VDPixmapFormatSubset& dstFormats, VDPixmapBlitterFn blitter) { + for(int i=0; i -#include "blt_spanutils.h" -#include "bitutils.h" - -using namespace nsVDPixmapBitUtils; - -namespace nsVDPixmapSpanUtils { - void horiz_expand2x_centered(uint8 *dst, const uint8 *src, sint32 w) { - w = -w; - - *dst++ = *src; - - if (++w) { - if (++w) { - do { - dst[0] = (uint8)((3*src[0] + src[1] + 2)>>2); - dst[1] = (uint8)((src[0] + 3*src[1] + 2)>>2); - dst += 2; - ++src; - } while((w+=2)<0); - } - - if (!(w & 1)) { - *dst = src[0]; - } - } - } - - void horiz_expand2x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - w = -w; - - if ((w+=2) < 0) { - do { - dst[0] = src[0]; - dst[1] = (uint8)((src[0] + src[1] + 1)>>1); - dst += 2; - ++src; - } while((w+=2)<0); - } - - w -= 2; - while(w < 0) { - ++w; - *dst++ = src[0]; - } - } - - void horiz_expand4x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - w = -w; - - if ((w+=4) < 0) { - do { - dst[0] = src[0]; - dst[1] = (uint8)((3*src[0] + src[1] + 2)>>2); - dst[2] = (uint8)((src[0] + src[1] + 1)>>1); - dst[3] = (uint8)((src[0] + 3*src[1] + 2)>>2); - dst += 4; - ++src; - } while((w+=4)<0); - } - - w -= 4; - while(w < 0) { - ++w; - *dst++ = src[0]; - } - } - - void horiz_compress2x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - if (w == 1) { - *dst = *src; - return; - } - - *dst++ = (uint8)((3*src[0] + src[1] + 2) >> 2); - ++src; - --w; - - while(w >= 3) { - w -= 2; - *dst++ = (uint8)((src[0] + 2*src[1] + src[2] + 2) >> 2); - src += 2; - } - - if (w >= 2) - *dst++ = (uint8)((src[0] + 3*src[1] + 2) >> 2); - } - - void horiz_compress2x_centered(uint8 *dst, const uint8 *src, sint32 w) { - if (w == 1) { - *dst = *src; - return; - } - - if (w == 2) { - *dst = (uint8)((src[0] + src[1] + 1) >> 1); - return; - } - - *dst++ = (uint8)((4*src[0] + 3*src[1] + src[2] + 4) >> 3); - --w; - ++src; - - while(w >= 4) { - w -= 2; - *dst++ = (uint8)(((src[0] + src[3]) + 3*(src[1] + src[2]) + 4) >> 3); - src += 2; - } - - switch(w) { - case 3: - *dst++ = (uint8)((src[0] + 3*src[1] + 4*src[2] + 4) >> 3); - break; - case 2: - *dst++ = (uint8)((src[0] + 7*src[1] + 4) >> 3); - break; - } - } - - void horiz_compress4x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - if (w == 1) { - *dst = *src; - return; - } - - if (w == 2) { - *dst++ = (uint8)((11*src[0] + 5*src[1] + 8) >> 4); - return; - } - - *dst++ = (uint8)((11*src[0] + 4*src[1] + src[2] + 8) >> 4); - src += 2; - w -= 2; - - while(w >= 5) { - w -= 4; - *dst++ = (uint8)(((src[0] + src[4]) + 4*(src[1] + src[3]) + 6*src[2] + 8) >> 4); - src += 4; - } - - switch(w) { - case 4: - *dst = (uint8)((src[0] + 4*src[1] + 6*src[2] + 5*src[3] + 8) >> 4); - break; - case 3: - *dst = (uint8)((src[0] + 4*src[1] + 11*src[2] + 8) >> 4); - break; - } - } - - void horiz_compress4x_centered(uint8 *dst, const uint8 *src, sint32 w) { - - switch(w) { - case 1: - *dst = *src; - return; - case 2: // 29 99 - *dst = (uint8)((29*src[0] + 99*src[1] + 64) >> 7); - return; - case 3: // 29 35 64 - *dst = (uint8)((29*src[0] + 35*src[1] + 64*src[1] + 64) >> 7); - return; - case 4: // 29 35 35 29 - *dst = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 29*src[3] + 64) >> 7); - return; - case 5: // 29 35 35 21 8 - // 1 7 120 - dst[0] = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 21*src[3] + 8*src[4] + 64) >> 7); - dst[1] = (uint8)((src[2] + 7*src[3] + 120*src[4] + 64) >> 7); - return; - } - - *dst++ = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 21*src[3] + 7*src[4] + src[5] + 64) >> 7); - src += 2; - w -= 2; - - while(w >= 8) { - w -= 4; - *dst++ = (uint8)(((src[0] + src[7]) + 7*(src[1] + src[6]) + 21*(src[2] + src[5]) + 35*(src[3] + src[4]) + 64) >> 7); - src += 4; - } - - switch(w) { - case 4: // 1 7 21 99 - *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 99*src[3] + 64) >> 7); - break; - case 5: // 1 7 21 35 64 - *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 35*src[3] + 64*src[4] + 64) >> 7); - break; - case 6: // 1 7 21 35 35 29 - *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 29*src[5] + 35*(src[3] + src[4]) + 64) >> 7); - break; - case 7: // 1 7 21 35 35 21 8 - // 1 7 120 - dst[0] = (uint8)((src[0] + 7*src[1] + 8*src[6] + 21*(src[2] + src[5]) + 35*(src[3] + src[4]) + 64) >> 7); - dst[1] = (uint8)((src[4] + 7*src[5] + 120*src[6] + 64) >> 7); - break; - } - } - - void horiz_realign_to_centered(uint8 *dst, const uint8 *src, sint32 w) { - // luma samples: Y Y Y Y Y - // coaligned: C C C - // centered: C C - // - // To realign coaligned samples to centered, we need to shift them - // right by a quarter sample in chroma space. This can be done via - // a [3 1]/4 filter. - - for(sint32 i=1; i> 2); - ++dst; - ++src; - } - - *dst++ = *src++; - } - - void horiz_realign_to_coaligned(uint8 *dst, const uint8 *src, sint32 w) { - // luma samples: Y Y Y Y Y - // coaligned: C C C - // centered: C C - // - // To realign centered samples to coaligned, we need to shift them - // left by a quarter sample in chroma space. This can be done via - // a [1 3]/4 filter. - - *dst++ = *src++; - - for(sint32 i=1; i> 2); - ++dst; - ++src; - } - } - - void vert_expand2x_centered(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { - const uint8 *src3 = srcs[0]; - const uint8 *src1 = srcs[1]; - - if (phase >= 128) - std::swap(src1, src3); - - sint32 w4 = w>>2; - w &= 3; - - if (w4) { - const uint32 *src34 = (const uint32 *)src3; - const uint32 *src14 = (const uint32 *)src1; - uint32 *dst4 = ( uint32 *)dst; - - do { - const uint32 a = *src34++; - const uint32 b = *src14++; - const uint32 ab = (a&b) + (((a^b)&0xfefefefe)>>1); - - *dst4++ = (a|ab) - (((a^ab)&0xfefefefe)>>1); - } while(--w4); - - src3 = (const uint8 *)src34; - src1 = (const uint8 *)src14; - dst = ( uint8 *)dst4; - } - - if (w) { - do { - *dst++ = (uint8)((*src1++ + 3**src3++ + 2) >> 2); - } while(--w); - } - } - - void vert_expand4x_centered(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { - const uint8 *src3 = srcs[0]; - const uint8 *src1 = srcs[1]; - - switch(phase & 0xc0) { - case 0x00: - do { - *dst++ = (uint8)((1**src1++ + 7**src3++ + 4) >> 3); - } while(--w); - break; - case 0x40: - do { - *dst++ = (uint8)((3**src1++ + 5**src3++ + 4) >> 3); - } while(--w); - break; - case 0x80: - do { - *dst++ = (uint8)((5**src1++ + 3**src3++ + 4) >> 3); - } while(--w); - break; - case 0xc0: - do { - *dst++ = (uint8)((7**src1++ + 1**src3++ + 4) >> 3); - } while(--w); - break; - default: - VDNEVERHERE; - } - } - - void vert_compress2x_centered_fast(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { - const uint8 *src1 = srcarray[0]; - const uint8 *src2 = srcarray[1]; - - w = -w; - w += 3; - - while(w < 0) { - *(uint32 *)dst = avg_8888_11(*(uint32 *)src1, *(uint32 *)src2); - dst += 4; - src1 += 4; - src2 += 4; - w += 4; - } - - w -= 3; - - while(w < 0) { - *dst = (uint8)((*src1 + *src2 + 1)>>1); - ++dst; - ++src1; - ++src2; - ++w; - } - } - - void vert_compress2x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { - const uint8 *src1 = srcarray[0]; - const uint8 *src2 = srcarray[1]; - const uint8 *src3 = srcarray[2]; - const uint8 *src4 = srcarray[3]; - - w = -w; - - while(w < 0) { - *dst++ = (uint8)(((*src1++ + *src4++) + 3*(*src2++ + *src3++) + 4)>>3); - ++w; - } - } - - void vert_compress4x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { - const uint8 *src1 = srcarray[0]; - const uint8 *src2 = srcarray[1]; - const uint8 *src3 = srcarray[2]; - const uint8 *src4 = srcarray[3]; - const uint8 *src5 = srcarray[4]; - const uint8 *src6 = srcarray[5]; - const uint8 *src7 = srcarray[6]; - const uint8 *src8 = srcarray[7]; - - w = -w; - - while(w < 0) { - int sum18 = *src1++ + *src8++; - int sum27 = *src2++ + *src7++; - int sum36 = *src3++ + *src6++; - int sum45 = *src4++ + *src5++; - - *dst++ = (uint8)((sum18 + 7*sum27 + 21*sum36 + 35*sum45 + 64) >> 7); - - ++w; - } - } -} - +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "blt_spanutils.h" +#include "bitutils.h" + +using namespace nsVDPixmapBitUtils; + +namespace nsVDPixmapSpanUtils { + void horiz_expand2x_centered(uint8 *dst, const uint8 *src, sint32 w) { + w = -w; + + *dst++ = *src; + + if (++w) { + if (++w) { + do { + dst[0] = (uint8)((3*src[0] + src[1] + 2)>>2); + dst[1] = (uint8)((src[0] + 3*src[1] + 2)>>2); + dst += 2; + ++src; + } while((w+=2)<0); + } + + if (!(w & 1)) { + *dst = src[0]; + } + } + } + + void horiz_expand2x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + w = -w; + + if ((w+=2) < 0) { + do { + dst[0] = src[0]; + dst[1] = (uint8)((src[0] + src[1] + 1)>>1); + dst += 2; + ++src; + } while((w+=2)<0); + } + + w -= 2; + while(w < 0) { + ++w; + *dst++ = src[0]; + } + } + + void horiz_expand4x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + w = -w; + + if ((w+=4) < 0) { + do { + dst[0] = src[0]; + dst[1] = (uint8)((3*src[0] + src[1] + 2)>>2); + dst[2] = (uint8)((src[0] + src[1] + 1)>>1); + dst[3] = (uint8)((src[0] + 3*src[1] + 2)>>2); + dst += 4; + ++src; + } while((w+=4)<0); + } + + w -= 4; + while(w < 0) { + ++w; + *dst++ = src[0]; + } + } + + void horiz_compress2x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + if (w == 1) { + *dst = *src; + return; + } + + *dst++ = (uint8)((3*src[0] + src[1] + 2) >> 2); + ++src; + --w; + + while(w >= 3) { + w -= 2; + *dst++ = (uint8)((src[0] + 2*src[1] + src[2] + 2) >> 2); + src += 2; + } + + if (w >= 2) + *dst++ = (uint8)((src[0] + 3*src[1] + 2) >> 2); + } + + void horiz_compress2x_centered(uint8 *dst, const uint8 *src, sint32 w) { + if (w == 1) { + *dst = *src; + return; + } + + if (w == 2) { + *dst = (uint8)((src[0] + src[1] + 1) >> 1); + return; + } + + *dst++ = (uint8)((4*src[0] + 3*src[1] + src[2] + 4) >> 3); + --w; + ++src; + + while(w >= 4) { + w -= 2; + *dst++ = (uint8)(((src[0] + src[3]) + 3*(src[1] + src[2]) + 4) >> 3); + src += 2; + } + + switch(w) { + case 3: + *dst++ = (uint8)((src[0] + 3*src[1] + 4*src[2] + 4) >> 3); + break; + case 2: + *dst++ = (uint8)((src[0] + 7*src[1] + 4) >> 3); + break; + } + } + + void horiz_compress4x_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + if (w == 1) { + *dst = *src; + return; + } + + if (w == 2) { + *dst++ = (uint8)((11*src[0] + 5*src[1] + 8) >> 4); + return; + } + + *dst++ = (uint8)((11*src[0] + 4*src[1] + src[2] + 8) >> 4); + src += 2; + w -= 2; + + while(w >= 5) { + w -= 4; + *dst++ = (uint8)(((src[0] + src[4]) + 4*(src[1] + src[3]) + 6*src[2] + 8) >> 4); + src += 4; + } + + switch(w) { + case 4: + *dst = (uint8)((src[0] + 4*src[1] + 6*src[2] + 5*src[3] + 8) >> 4); + break; + case 3: + *dst = (uint8)((src[0] + 4*src[1] + 11*src[2] + 8) >> 4); + break; + } + } + + void horiz_compress4x_centered(uint8 *dst, const uint8 *src, sint32 w) { + + switch(w) { + case 1: + *dst = *src; + return; + case 2: // 29 99 + *dst = (uint8)((29*src[0] + 99*src[1] + 64) >> 7); + return; + case 3: // 29 35 64 + *dst = (uint8)((29*src[0] + 35*src[1] + 64*src[1] + 64) >> 7); + return; + case 4: // 29 35 35 29 + *dst = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 29*src[3] + 64) >> 7); + return; + case 5: // 29 35 35 21 8 + // 1 7 120 + dst[0] = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 21*src[3] + 8*src[4] + 64) >> 7); + dst[1] = (uint8)((src[2] + 7*src[3] + 120*src[4] + 64) >> 7); + return; + } + + *dst++ = (uint8)((29*src[0] + 35*(src[1] + src[2]) + 21*src[3] + 7*src[4] + src[5] + 64) >> 7); + src += 2; + w -= 2; + + while(w >= 8) { + w -= 4; + *dst++ = (uint8)(((src[0] + src[7]) + 7*(src[1] + src[6]) + 21*(src[2] + src[5]) + 35*(src[3] + src[4]) + 64) >> 7); + src += 4; + } + + switch(w) { + case 4: // 1 7 21 99 + *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 99*src[3] + 64) >> 7); + break; + case 5: // 1 7 21 35 64 + *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 35*src[3] + 64*src[4] + 64) >> 7); + break; + case 6: // 1 7 21 35 35 29 + *dst = (uint8)((src[0] + 7*src[1] + 21*src[2] + 29*src[5] + 35*(src[3] + src[4]) + 64) >> 7); + break; + case 7: // 1 7 21 35 35 21 8 + // 1 7 120 + dst[0] = (uint8)((src[0] + 7*src[1] + 8*src[6] + 21*(src[2] + src[5]) + 35*(src[3] + src[4]) + 64) >> 7); + dst[1] = (uint8)((src[4] + 7*src[5] + 120*src[6] + 64) >> 7); + break; + } + } + + void horiz_realign_to_centered(uint8 *dst, const uint8 *src, sint32 w) { + // luma samples: Y Y Y Y Y + // coaligned: C C C + // centered: C C + // + // To realign coaligned samples to centered, we need to shift them + // right by a quarter sample in chroma space. This can be done via + // a [3 1]/4 filter. + + for(sint32 i=1; i> 2); + ++dst; + ++src; + } + + *dst++ = *src++; + } + + void horiz_realign_to_coaligned(uint8 *dst, const uint8 *src, sint32 w) { + // luma samples: Y Y Y Y Y + // coaligned: C C C + // centered: C C + // + // To realign centered samples to coaligned, we need to shift them + // left by a quarter sample in chroma space. This can be done via + // a [1 3]/4 filter. + + *dst++ = *src++; + + for(sint32 i=1; i> 2); + ++dst; + ++src; + } + } + + void vert_expand2x_centered(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { + const uint8 *src3 = srcs[0]; + const uint8 *src1 = srcs[1]; + + if (phase >= 128) + std::swap(src1, src3); + + sint32 w4 = w>>2; + w &= 3; + + if (w4) { + const uint32 *src34 = (const uint32 *)src3; + const uint32 *src14 = (const uint32 *)src1; + uint32 *dst4 = ( uint32 *)dst; + + do { + const uint32 a = *src34++; + const uint32 b = *src14++; + const uint32 ab = (a&b) + (((a^b)&0xfefefefe)>>1); + + *dst4++ = (a|ab) - (((a^ab)&0xfefefefe)>>1); + } while(--w4); + + src3 = (const uint8 *)src34; + src1 = (const uint8 *)src14; + dst = ( uint8 *)dst4; + } + + if (w) { + do { + *dst++ = (uint8)((*src1++ + 3**src3++ + 2) >> 2); + } while(--w); + } + } + + void vert_expand4x_centered(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { + const uint8 *src3 = srcs[0]; + const uint8 *src1 = srcs[1]; + + switch(phase & 0xc0) { + case 0x00: + do { + *dst++ = (uint8)((1**src1++ + 7**src3++ + 4) >> 3); + } while(--w); + break; + case 0x40: + do { + *dst++ = (uint8)((3**src1++ + 5**src3++ + 4) >> 3); + } while(--w); + break; + case 0x80: + do { + *dst++ = (uint8)((5**src1++ + 3**src3++ + 4) >> 3); + } while(--w); + break; + case 0xc0: + do { + *dst++ = (uint8)((7**src1++ + 1**src3++ + 4) >> 3); + } while(--w); + break; + default: + VDNEVERHERE; + } + } + + void vert_compress2x_centered_fast(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { + const uint8 *src1 = srcarray[0]; + const uint8 *src2 = srcarray[1]; + + w = -w; + w += 3; + + while(w < 0) { + *(uint32 *)dst = avg_8888_11(*(uint32 *)src1, *(uint32 *)src2); + dst += 4; + src1 += 4; + src2 += 4; + w += 4; + } + + w -= 3; + + while(w < 0) { + *dst = (uint8)((*src1 + *src2 + 1)>>1); + ++dst; + ++src1; + ++src2; + ++w; + } + } + + void vert_compress2x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { + const uint8 *src1 = srcarray[0]; + const uint8 *src2 = srcarray[1]; + const uint8 *src3 = srcarray[2]; + const uint8 *src4 = srcarray[3]; + + w = -w; + + while(w < 0) { + *dst++ = (uint8)(((*src1++ + *src4++) + 3*(*src2++ + *src3++) + 4)>>3); + ++w; + } + } + + void vert_compress4x_centered(uint8 *dst, const uint8 *const *srcarray, sint32 w, uint8 phase) { + const uint8 *src1 = srcarray[0]; + const uint8 *src2 = srcarray[1]; + const uint8 *src3 = srcarray[2]; + const uint8 *src4 = srcarray[3]; + const uint8 *src5 = srcarray[4]; + const uint8 *src6 = srcarray[5]; + const uint8 *src7 = srcarray[6]; + const uint8 *src8 = srcarray[7]; + + w = -w; + + while(w < 0) { + int sum18 = *src1++ + *src8++; + int sum27 = *src2++ + *src7++; + int sum36 = *src3++ + *src6++; + int sum45 = *src4++ + *src5++; + + *dst++ = (uint8)((sum18 + 7*sum27 + 21*sum36 + 35*sum45 + 64) >> 7); + + ++w; + } + } +} + diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_spanutils_x86.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_spanutils_x86.cpp index ffe4cafb702..f529444caed 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_spanutils_x86.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_spanutils_x86.cpp @@ -1,171 +1,171 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include "blt_spanutils_x86.h" - -#ifdef _MSC_VER - #pragma warning(disable: 4799) // warning C4799: function 'nsVDPixmapSpanUtils::vdasm_horiz_expand2x_coaligned_ISSE' has no EMMS instruction -#endif - -extern "C" void __cdecl vdasm_horiz_expand2x_coaligned_ISSE(void *dst, const void *src, uint32 count); -extern "C" void __cdecl vdasm_horiz_expand4x_coaligned_MMX(void *dst, const void *src, uint32 count); -extern "C" void __cdecl vdasm_vert_average_13_ISSE(void *dst, const void *src1, const void *src3, uint32 count); -extern "C" void __cdecl vdasm_vert_average_17_ISSE(void *dst, const void *src1, const void *src3, uint32 count); -extern "C" void __cdecl vdasm_vert_average_35_ISSE(void *dst, const void *src1, const void *src3, uint32 count); - -namespace nsVDPixmapSpanUtils { - - void horiz_expand2x_coaligned_ISSE(uint8 *dst, const uint8 *src, sint32 w) { - if (w >= 17) { - uint32 fastcount = (w - 1) & ~15; - - vdasm_horiz_expand2x_coaligned_ISSE(dst, src, fastcount); - dst += fastcount; - src += fastcount >> 1; - w -= fastcount; - } - - w = -w; - if ((w+=2) < 0) { - do { - dst[0] = src[0]; - dst[1] = (uint8)((src[0] + src[1] + 1)>>1); - dst += 2; - ++src; - } while((w+=2)<0); - } - - w -= 2; - while(w < 0) { - ++w; - *dst++ = src[0]; - } - } - - void horiz_expand4x_coaligned_MMX(uint8 *dst, const uint8 *src, sint32 w) { - if (w >= 17) { - uint32 fastcount = (w - 1) >> 4; - - vdasm_horiz_expand4x_coaligned_MMX(dst, src, fastcount); - dst += fastcount << 4; - src += fastcount << 2; - w -= fastcount << 4; - } - - w = -w; - if ((w+=4) < 0) { - do { - dst[0] = src[0]; - dst[1] = (uint8)((3*src[0] + src[1] + 2)>>2); - dst[2] = (uint8)((src[0] + src[1] + 1)>>1); - dst[3] = (uint8)((src[0] + 3*src[1] + 2)>>2); - dst += 4; - ++src; - } while((w+=4)<0); - } - - w -= 4; - while(w < 0) { - ++w; - *dst++ = src[0]; - } - } - - void vert_expand2x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { - const uint8 *src3 = srcs[0]; - const uint8 *src1 = srcs[1]; - - if (phase >= 128) - std::swap(src1, src3); - - uint32 fastcount = w & ~15; - - if (fastcount) { - vdasm_vert_average_13_ISSE(dst, src1, src3, fastcount); - dst += fastcount; - src1 += fastcount; - src3 += fastcount; - w -= fastcount; - } - - if (w) { - do { - *dst++ = (uint8)((*src1++ + 3**src3++ + 2) >> 2); - } while(--w); - } - } - - void vert_average_1_7_ISSE(uint8 *dst, const uint8 *src7, const uint8 *src1, sint32 w) { - uint32 fastcount = w & ~7; - - if (fastcount) { - vdasm_vert_average_17_ISSE(dst, src1, src7, fastcount); - dst += fastcount; - src1 += fastcount; - src7 += fastcount; - w -= fastcount; - } - - if (w) { - do { - *dst++ = (uint8)((*src1++ + 7**src7++ + 4) >> 3); - } while(--w); - } - } - - void vert_average_3_5_ISSE(uint8 *dst, const uint8 *src7, const uint8 *src1, sint32 w) { - uint32 fastcount = w & ~7; - - if (fastcount) { - vdasm_vert_average_35_ISSE(dst, src1, src7, fastcount); - dst += fastcount; - src1 += fastcount; - src7 += fastcount; - w -= fastcount; - } - - if (w) { - do { - *dst++ = (uint8)((3**src1++ + 5**src7++ + 4) >> 3); - } while(--w); - } - } - - void vert_expand4x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { - const uint8 *src1 = srcs[0]; - const uint8 *src2 = srcs[1]; - - switch(phase & 0xc0) { - case 0x00: - vert_average_1_7_ISSE(dst, src2, src1, w); - break; - case 0x40: - vert_average_3_5_ISSE(dst, src2, src1, w); - break; - case 0x80: - vert_average_3_5_ISSE(dst, src1, src2, w); - break; - case 0xc0: - vert_average_1_7_ISSE(dst, src1, src2, w); - break; - default: - VDNEVERHERE; - } - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "blt_spanutils_x86.h" + +#ifdef _MSC_VER + #pragma warning(disable: 4799) // warning C4799: function 'nsVDPixmapSpanUtils::vdasm_horiz_expand2x_coaligned_ISSE' has no EMMS instruction +#endif + +extern "C" void __cdecl vdasm_horiz_expand2x_coaligned_ISSE(void *dst, const void *src, uint32 count); +extern "C" void __cdecl vdasm_horiz_expand4x_coaligned_MMX(void *dst, const void *src, uint32 count); +extern "C" void __cdecl vdasm_vert_average_13_ISSE(void *dst, const void *src1, const void *src3, uint32 count); +extern "C" void __cdecl vdasm_vert_average_17_ISSE(void *dst, const void *src1, const void *src3, uint32 count); +extern "C" void __cdecl vdasm_vert_average_35_ISSE(void *dst, const void *src1, const void *src3, uint32 count); + +namespace nsVDPixmapSpanUtils { + + void horiz_expand2x_coaligned_ISSE(uint8 *dst, const uint8 *src, sint32 w) { + if (w >= 17) { + uint32 fastcount = (w - 1) & ~15; + + vdasm_horiz_expand2x_coaligned_ISSE(dst, src, fastcount); + dst += fastcount; + src += fastcount >> 1; + w -= fastcount; + } + + w = -w; + if ((w+=2) < 0) { + do { + dst[0] = src[0]; + dst[1] = (uint8)((src[0] + src[1] + 1)>>1); + dst += 2; + ++src; + } while((w+=2)<0); + } + + w -= 2; + while(w < 0) { + ++w; + *dst++ = src[0]; + } + } + + void horiz_expand4x_coaligned_MMX(uint8 *dst, const uint8 *src, sint32 w) { + if (w >= 17) { + uint32 fastcount = (w - 1) >> 4; + + vdasm_horiz_expand4x_coaligned_MMX(dst, src, fastcount); + dst += fastcount << 4; + src += fastcount << 2; + w -= fastcount << 4; + } + + w = -w; + if ((w+=4) < 0) { + do { + dst[0] = src[0]; + dst[1] = (uint8)((3*src[0] + src[1] + 2)>>2); + dst[2] = (uint8)((src[0] + src[1] + 1)>>1); + dst[3] = (uint8)((src[0] + 3*src[1] + 2)>>2); + dst += 4; + ++src; + } while((w+=4)<0); + } + + w -= 4; + while(w < 0) { + ++w; + *dst++ = src[0]; + } + } + + void vert_expand2x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { + const uint8 *src3 = srcs[0]; + const uint8 *src1 = srcs[1]; + + if (phase >= 128) + std::swap(src1, src3); + + uint32 fastcount = w & ~15; + + if (fastcount) { + vdasm_vert_average_13_ISSE(dst, src1, src3, fastcount); + dst += fastcount; + src1 += fastcount; + src3 += fastcount; + w -= fastcount; + } + + if (w) { + do { + *dst++ = (uint8)((*src1++ + 3**src3++ + 2) >> 2); + } while(--w); + } + } + + void vert_average_1_7_ISSE(uint8 *dst, const uint8 *src7, const uint8 *src1, sint32 w) { + uint32 fastcount = w & ~7; + + if (fastcount) { + vdasm_vert_average_17_ISSE(dst, src1, src7, fastcount); + dst += fastcount; + src1 += fastcount; + src7 += fastcount; + w -= fastcount; + } + + if (w) { + do { + *dst++ = (uint8)((*src1++ + 7**src7++ + 4) >> 3); + } while(--w); + } + } + + void vert_average_3_5_ISSE(uint8 *dst, const uint8 *src7, const uint8 *src1, sint32 w) { + uint32 fastcount = w & ~7; + + if (fastcount) { + vdasm_vert_average_35_ISSE(dst, src1, src7, fastcount); + dst += fastcount; + src1 += fastcount; + src7 += fastcount; + w -= fastcount; + } + + if (w) { + do { + *dst++ = (uint8)((3**src1++ + 5**src7++ + 4) >> 3); + } while(--w); + } + } + + void vert_expand4x_centered_ISSE(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase) { + const uint8 *src1 = srcs[0]; + const uint8 *src2 = srcs[1]; + + switch(phase & 0xc0) { + case 0x00: + vert_average_1_7_ISSE(dst, src2, src1, w); + break; + case 0x40: + vert_average_3_5_ISSE(dst, src2, src1, w); + break; + case 0x80: + vert_average_3_5_ISSE(dst, src1, src2, w); + break; + case 0xc0: + vert_average_1_7_ISSE(dst, src1, src2, w); + break; + default: + VDNEVERHERE; + } + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_uberblit.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_uberblit.cpp index ce654ae310c..73eb269e8d1 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_uberblit.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_uberblit.cpp @@ -1,38 +1,38 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include "uberblit.h" - -void VDPixmapBlt_UberblitAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { - vdautoptr blitter(VDPixmapCreateBlitter(dst, src)); - - if (w > src.w) - w = src.w; - if (w > dst.w) - w = dst.w; - if (h > src.h) - h = src.h; - if (h > dst.h) - h = dst.h; - - vdrect32 r(0, 0, w, h); - blitter->Blit(dst, &r, src); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include "uberblit.h" + +void VDPixmapBlt_UberblitAdapter(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) { + vdautoptr blitter(VDPixmapCreateBlitter(dst, src)); + + if (w > src.w) + w = src.w; + if (w > dst.w) + w = dst.w; + if (h > src.h) + h = src.h; + if (h > dst.h) + h = dst.h; + + vdrect32 r(0, 0, w, h); + blitter->Blit(dst, &r, src); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/blt_x86.cpp b/src/thirdparty/VirtualDub/Kasumi/source/blt_x86.cpp index a37c50a95a6..29cce407fc5 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/blt_x86.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/blt_x86.cpp @@ -1,163 +1,163 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include "blt_setup.h" - -void VDPixmapInitBlittersReference(VDPixmapBlitterTable& table); - -#define DECLARE_PALETTED(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0); -#define DECLARE_RGB(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -#define DECLARE_RGB_ASM(x, y) extern "C" void vdasm_pixblt_##x##_to_##y(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -#define DECLARE_RGB_ASM_MMX(x, y) extern "C" void vdasm_pixblt_##x##_to_##y##_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -#define DECLARE_YUV(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); -#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) -#define DECLARE_YUV_PLANAR(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); - - DECLARE_RGB_ASM(RGB565, XRGB1555); DECLARE_RGB_ASM_MMX(RGB565, XRGB1555); - DECLARE_RGB_ASM(RGB888, XRGB1555); - DECLARE_RGB_ASM(XRGB8888, XRGB1555); DECLARE_RGB_ASM_MMX(XRGB8888, XRGB1555); - DECLARE_RGB_ASM(XRGB1555, RGB565); DECLARE_RGB_ASM_MMX(XRGB1555, RGB565); - DECLARE_RGB_ASM(RGB888, RGB565); - DECLARE_RGB_ASM(XRGB8888, RGB565); DECLARE_RGB_ASM_MMX(XRGB8888, RGB565); -DECLARE_RGB(XRGB1555, RGB888); -DECLARE_RGB(RGB565, RGB888); - DECLARE_RGB_ASM(XRGB8888, RGB888); DECLARE_RGB_ASM_MMX(XRGB8888, RGB888); - DECLARE_RGB_ASM(XRGB1555, XRGB8888); DECLARE_RGB_ASM_MMX(XRGB1555, XRGB8888); - DECLARE_RGB_ASM(RGB565, XRGB8888); DECLARE_RGB_ASM_MMX(RGB565, XRGB8888); - DECLARE_RGB_ASM(RGB888, XRGB8888); DECLARE_RGB_ASM_MMX(RGB888, XRGB8888); - -DECLARE_PALETTED(Pal1, Any8); -DECLARE_PALETTED(Pal1, Any16); -DECLARE_PALETTED(Pal1, Any24); -DECLARE_PALETTED(Pal1, Any32); -DECLARE_PALETTED(Pal2, Any8); -DECLARE_PALETTED(Pal2, Any16); -DECLARE_PALETTED(Pal2, Any24); -DECLARE_PALETTED(Pal2, Any32); -DECLARE_PALETTED(Pal4, Any8); -DECLARE_PALETTED(Pal4, Any16); -DECLARE_PALETTED(Pal4, Any24); -DECLARE_PALETTED(Pal4, Any32); -DECLARE_PALETTED(Pal8, Any8); -DECLARE_PALETTED(Pal8, Any16); -DECLARE_PALETTED(Pal8, Any24); -DECLARE_PALETTED(Pal8, Any32); - -DECLARE_YUV(XVYU, UYVY); -DECLARE_YUV(XVYU, YUYV); -DECLARE_YUV(Y8, UYVY); -DECLARE_YUV(Y8, YUYV); -DECLARE_YUV(UYVY, Y8); -DECLARE_YUV(YUYV, Y8); -DECLARE_YUV(UYVY, YUYV); -DECLARE_YUV_PLANAR(YUV411, YV12); - -DECLARE_YUV(UYVY, XRGB1555); -DECLARE_YUV(UYVY, RGB565); -DECLARE_YUV(UYVY, RGB888); -DECLARE_YUV(UYVY, XRGB8888); -DECLARE_YUV(YUYV, XRGB1555); -DECLARE_YUV(YUYV, RGB565); -DECLARE_YUV(YUYV, RGB888); -DECLARE_YUV(YUYV, XRGB8888); -DECLARE_YUV(Y8, XRGB1555); -DECLARE_YUV(Y8, RGB565); -DECLARE_YUV(Y8, RGB888); -DECLARE_YUV(Y8, XRGB8888); - -DECLARE_YUV_REV(XRGB1555, Y8); -DECLARE_YUV_REV(RGB565, Y8); -DECLARE_YUV_REV(RGB888, Y8); -DECLARE_YUV_REV(XRGB8888, Y8); - -DECLARE_YUV_REV(XRGB1555, XVYU); -DECLARE_YUV_REV(RGB565, XVYU); -DECLARE_YUV_REV(RGB888, XVYU); -DECLARE_YUV_REV(XRGB8888, XVYU); - -DECLARE_YUV_PLANAR(YV12, XRGB1555); -DECLARE_YUV_PLANAR(YV12, RGB565); -DECLARE_YUV_PLANAR(YV12, RGB888); -DECLARE_YUV_PLANAR(YV12, XRGB8888); - -DECLARE_YUV_PLANAR(YUV411, XRGB1555); -DECLARE_YUV_PLANAR(YUV411, RGB565); -DECLARE_YUV_PLANAR(YUV411, RGB888); -DECLARE_YUV_PLANAR(YUV411, XRGB8888); - -extern void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -extern void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); - -using namespace nsVDPixmap; - -void VDPixmapInitBlittersX86(VDPixmapBlitterTable& table) { - VDPixmapInitBlittersReference(table); - - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); -} - -tpVDPixBltTable VDGetPixBltTableX86ScalarInternal() { - static VDPixmapBlitterTable sReferenceTable; - - VDPixmapInitBlittersX86(sReferenceTable); - - return sReferenceTable.mTable; -} - -tpVDPixBltTable VDGetPixBltTableX86MMXInternal() { - static VDPixmapBlitterTable sReferenceTable; - - VDPixmapInitBlittersX86(sReferenceTable); - - sReferenceTable.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); - sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); - - return sReferenceTable.mTable; -} - -tpVDPixBltTable VDGetPixBltTableX86Scalar() { - static tpVDPixBltTable spTable = VDGetPixBltTableX86ScalarInternal(); - - return spTable; -} - -tpVDPixBltTable VDGetPixBltTableX86MMX() { - static tpVDPixBltTable spTable = VDGetPixBltTableX86MMXInternal(); - - return spTable; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include "blt_setup.h" + +void VDPixmapInitBlittersReference(VDPixmapBlitterTable& table); + +#define DECLARE_PALETTED(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h, const void *pal0); +#define DECLARE_RGB(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +#define DECLARE_RGB_ASM(x, y) extern "C" void vdasm_pixblt_##x##_to_##y(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +#define DECLARE_RGB_ASM_MMX(x, y) extern "C" void vdasm_pixblt_##x##_to_##y##_MMX(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +#define DECLARE_YUV(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h); +#define DECLARE_YUV_REV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h) +#define DECLARE_YUV_PLANAR(x, y) extern void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); + + DECLARE_RGB_ASM(RGB565, XRGB1555); DECLARE_RGB_ASM_MMX(RGB565, XRGB1555); + DECLARE_RGB_ASM(RGB888, XRGB1555); + DECLARE_RGB_ASM(XRGB8888, XRGB1555); DECLARE_RGB_ASM_MMX(XRGB8888, XRGB1555); + DECLARE_RGB_ASM(XRGB1555, RGB565); DECLARE_RGB_ASM_MMX(XRGB1555, RGB565); + DECLARE_RGB_ASM(RGB888, RGB565); + DECLARE_RGB_ASM(XRGB8888, RGB565); DECLARE_RGB_ASM_MMX(XRGB8888, RGB565); +DECLARE_RGB(XRGB1555, RGB888); +DECLARE_RGB(RGB565, RGB888); + DECLARE_RGB_ASM(XRGB8888, RGB888); DECLARE_RGB_ASM_MMX(XRGB8888, RGB888); + DECLARE_RGB_ASM(XRGB1555, XRGB8888); DECLARE_RGB_ASM_MMX(XRGB1555, XRGB8888); + DECLARE_RGB_ASM(RGB565, XRGB8888); DECLARE_RGB_ASM_MMX(RGB565, XRGB8888); + DECLARE_RGB_ASM(RGB888, XRGB8888); DECLARE_RGB_ASM_MMX(RGB888, XRGB8888); + +DECLARE_PALETTED(Pal1, Any8); +DECLARE_PALETTED(Pal1, Any16); +DECLARE_PALETTED(Pal1, Any24); +DECLARE_PALETTED(Pal1, Any32); +DECLARE_PALETTED(Pal2, Any8); +DECLARE_PALETTED(Pal2, Any16); +DECLARE_PALETTED(Pal2, Any24); +DECLARE_PALETTED(Pal2, Any32); +DECLARE_PALETTED(Pal4, Any8); +DECLARE_PALETTED(Pal4, Any16); +DECLARE_PALETTED(Pal4, Any24); +DECLARE_PALETTED(Pal4, Any32); +DECLARE_PALETTED(Pal8, Any8); +DECLARE_PALETTED(Pal8, Any16); +DECLARE_PALETTED(Pal8, Any24); +DECLARE_PALETTED(Pal8, Any32); + +DECLARE_YUV(XVYU, UYVY); +DECLARE_YUV(XVYU, YUYV); +DECLARE_YUV(Y8, UYVY); +DECLARE_YUV(Y8, YUYV); +DECLARE_YUV(UYVY, Y8); +DECLARE_YUV(YUYV, Y8); +DECLARE_YUV(UYVY, YUYV); +DECLARE_YUV_PLANAR(YUV411, YV12); + +DECLARE_YUV(UYVY, XRGB1555); +DECLARE_YUV(UYVY, RGB565); +DECLARE_YUV(UYVY, RGB888); +DECLARE_YUV(UYVY, XRGB8888); +DECLARE_YUV(YUYV, XRGB1555); +DECLARE_YUV(YUYV, RGB565); +DECLARE_YUV(YUYV, RGB888); +DECLARE_YUV(YUYV, XRGB8888); +DECLARE_YUV(Y8, XRGB1555); +DECLARE_YUV(Y8, RGB565); +DECLARE_YUV(Y8, RGB888); +DECLARE_YUV(Y8, XRGB8888); + +DECLARE_YUV_REV(XRGB1555, Y8); +DECLARE_YUV_REV(RGB565, Y8); +DECLARE_YUV_REV(RGB888, Y8); +DECLARE_YUV_REV(XRGB8888, Y8); + +DECLARE_YUV_REV(XRGB1555, XVYU); +DECLARE_YUV_REV(RGB565, XVYU); +DECLARE_YUV_REV(RGB888, XVYU); +DECLARE_YUV_REV(XRGB8888, XVYU); + +DECLARE_YUV_PLANAR(YV12, XRGB1555); +DECLARE_YUV_PLANAR(YV12, RGB565); +DECLARE_YUV_PLANAR(YV12, RGB888); +DECLARE_YUV_PLANAR(YV12, XRGB8888); + +DECLARE_YUV_PLANAR(YUV411, XRGB1555); +DECLARE_YUV_PLANAR(YUV411, RGB565); +DECLARE_YUV_PLANAR(YUV411, RGB888); +DECLARE_YUV_PLANAR(YUV411, XRGB8888); + +extern void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_YUVPlanar_encode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +extern void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); + +using namespace nsVDPixmap; + +void VDPixmapInitBlittersX86(VDPixmapBlitterTable& table) { + VDPixmapInitBlittersReference(table); + + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + table.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); +} + +tpVDPixBltTable VDGetPixBltTableX86ScalarInternal() { + static VDPixmapBlitterTable sReferenceTable; + + VDPixmapInitBlittersX86(sReferenceTable); + + return sReferenceTable.mTable; +} + +tpVDPixBltTable VDGetPixBltTableX86MMXInternal() { + static VDPixmapBlitterTable sReferenceTable; + + VDPixmapInitBlittersX86(sReferenceTable); + + sReferenceTable.AddBlitter(kPixFormat_XRGB1555, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_XRGB1555, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_RGB565, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_RGB888, kPixFormat_XRGB8888, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_XRGB1555, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB565, VDPixmapBlitterChunkyAdapter); + sReferenceTable.AddBlitter(kPixFormat_XRGB8888, kPixFormat_RGB888, VDPixmapBlitterChunkyAdapter); + + return sReferenceTable.mTable; +} + +tpVDPixBltTable VDGetPixBltTableX86Scalar() { + static tpVDPixBltTable spTable = VDGetPixBltTableX86ScalarInternal(); + + return spTable; +} + +tpVDPixBltTable VDGetPixBltTableX86MMX() { + static tpVDPixBltTable spTable = VDGetPixBltTableX86MMXInternal(); + + return spTable; +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/pixel.cpp b/src/thirdparty/VirtualDub/Kasumi/source/pixel.cpp index 207bd597d16..d8d845f827e 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/pixel.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/pixel.cpp @@ -1,942 +1,942 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include - -uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y) { - if (x >= px.w) - x = px.w - 1; - if (y >= px.h) - y = px.h - 1; - if (x < 0) - x = 0; - if (y < 0) - y = 0; - - switch(px.format) { - case nsVDPixmap::kPixFormat_Pal1: - { - uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 3]; - - return px.palette[(idx >> (7 - (x & 7))) & 1]; - } - - case nsVDPixmap::kPixFormat_Pal2: - { - uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 2]; - - return px.palette[(idx >> (6 - (x & 3)*2)) & 3]; - } - - case nsVDPixmap::kPixFormat_Pal4: - { - uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 1]; - - if (!(x & 1)) - idx >>= 4; - - return px.palette[idx & 15]; - } - - case nsVDPixmap::kPixFormat_Pal8: - { - uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x]; - - return px.palette[idx]; - } - - case nsVDPixmap::kPixFormat_XRGB1555: - { - uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; - uint32 r = c & 0x7c00; - uint32 g = c & 0x03e0; - uint32 b = c & 0x001f; - uint32 rgb = (r << 9) + (g << 6) + (b << 3); - - return rgb + ((rgb >> 5) & 0x070707); - } - break; - - case nsVDPixmap::kPixFormat_RGB565: - { - uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; - uint32 r = c & 0xf800; - uint32 g = c & 0x07e0; - uint32 b = c & 0x001f; - uint32 rb = (r << 8) + (b << 3); - - return rb + ((rb >> 5) & 0x070007) + (g << 5) + ((g >> 1) & 0x0300); - } - break; - - case nsVDPixmap::kPixFormat_RGB888: - { - const uint8 *src = (const uint8 *)px.data + px.pitch*y + 3*x; - uint32 b = src[0]; - uint32 g = src[1]; - uint32 r = src[2]; - - return (r << 16) + (g << 8) + b; - } - break; - - case nsVDPixmap::kPixFormat_XRGB8888: - return ((const uint32 *)((const uint8 *)px.data + px.pitch*y))[x]; - - case nsVDPixmap::kPixFormat_Y8: - { - uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; - - return ((luma - 16)*255/219) * 0x010101; - } - break; - - case nsVDPixmap::kPixFormat_Y8_FR: - { - uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; - - return (uint32)luma * 0x010101; - } - break; - - case nsVDPixmap::kPixFormat_YUV444_Planar: - return VDConvertYCbCrToRGB(VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapSample8(px.data2, px.pitch2, x, y), VDPixmapSample8(px.data3, px.pitch3, x, y), false, false); - - case nsVDPixmap::kPixFormat_YUV422_Planar: - { - sint32 u = (x << 7) + 128; - sint32 v = (y << 8); - uint32 w2 = px.w >> 1; - uint32 h2 = px.h; - - return VDConvertYCbCrToRGB( - VDPixmapSample8(px.data, px.pitch, x, y), - VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), - VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), - false, false); - } - - case nsVDPixmap::kPixFormat_YUV420_Planar: - { - sint32 u = (x << 7) + 128; - sint32 v = (y << 7); - uint32 w2 = px.w >> 1; - uint32 h2 = px.h >> 1; - - return VDConvertYCbCrToRGB( - VDPixmapSample8(px.data, px.pitch, x, y), - VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), - VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), - false, false); - } - - case nsVDPixmap::kPixFormat_YUV411_Planar: - { - sint32 u = (x << 6) + 128; - sint32 v = (y << 8); - uint32 w2 = px.w >> 2; - uint32 h2 = px.h; - - return VDConvertYCbCrToRGB( - VDPixmapSample8(px.data, px.pitch, x, y), - VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), - VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), - false, false); - } - - case nsVDPixmap::kPixFormat_YUV410_Planar: - { - sint32 u = (x << 6) + 128; - sint32 v = (y << 6); - uint32 w2 = px.w >> 2; - uint32 h2 = px.h >> 2; - - return VDConvertYCbCrToRGB( - VDPixmapSample8(px.data, px.pitch, x, y), - VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), - VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), - false, false); - } - - default: - return VDPixmapInterpolateSampleRGB24(px, (x << 8) + 128, (y << 8) + 128); - } -} - -uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - uint32 w_256 = (w - 1) << 8; - uint32 h_256 = (h - 1) << 8; - x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); - y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); - - const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8); - const uint8 *row1 = row0; - - if ((uint32)y_256 < h_256) - row1 += pitch; - - ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; - sint32 xoffset = x_256 & 255; - sint32 yoffset = y_256 & 255; - sint32 p00 = row0[0]; - sint32 p10 = row0[xstep]; - sint32 p01 = row1[0]; - sint32 p11 = row1[xstep]; - sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; - sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; - sint32 p = ((p0 << 8) + (p1 - p0)*yoffset + 0x8000) >> 16; - - return (uint8)p; -} - -uint32 VDPixmapInterpolateSample8To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - sint32 w_256 = (w - 1) << 8; - sint32 h_256 = (h - 1) << 8; - x_256 += (w_256 - x_256) & ((w_256 - x_256) >> 31); - y_256 += (h_256 - y_256) & ((h_256 - y_256) >> 31); - - const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8); - const uint8 *row1 = row0; - - if (y_256 < h_256) - row1 += pitch; - - ptrdiff_t xstep = x_256 < w_256 ? 1 : 0; - sint32 xoffset = x_256 & 255; - sint32 yoffset = y_256 & 255; - sint32 p00 = row0[0]; - sint32 p10 = row0[xstep]; - sint32 p01 = row1[0]; - sint32 p11 = row1[xstep]; - sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; - sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; - sint32 p = (p0 << 8) + (p1 - p0)*yoffset; - - return p; -} - -uint32 VDPixmapInterpolateSample8x2To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - uint32 w_256 = (w - 1) << 8; - uint32 h_256 = (h - 1) << 8; - x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); - y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); - - const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2; - const uint8 *row1 = row0; - - if ((uint32)y_256 < h_256) - row1 += pitch; - - ptrdiff_t xstep = (uint32)x_256 < w_256 ? 2 : 0; - sint32 xoffset = x_256 & 255; - sint32 yoffset = y_256 & 255; - sint32 p00 = row0[0]; - sint32 p10 = row0[xstep]; - sint32 p01 = row1[0]; - sint32 p11 = row1[xstep]; - sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; - sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; - sint32 p = (p0 << 8) + (p1 - p0)*yoffset; - - return p; -} - -uint32 VDPixmapInterpolateSample8x4To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - uint32 w_256 = (w - 1) << 8; - uint32 h_256 = (h - 1) << 8; - x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); - y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); - - const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*4; - const uint8 *row1 = row0; - - if ((uint32)y_256 < h_256) - row1 += pitch; - - ptrdiff_t xstep = (uint32)x_256 < w_256 ? 4 : 0; - sint32 xoffset = x_256 & 255; - sint32 yoffset = y_256 & 255; - sint32 p00 = row0[0]; - sint32 p10 = row0[xstep]; - sint32 p01 = row1[0]; - sint32 p11 = row1[xstep]; - sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; - sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; - sint32 p = (p0 << 8) + (p1 - p0)*yoffset; - - return p; -} - -float VDPixmapInterpolateSample16F(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { - // bias coordinates to integer - x_256 -= 128; - y_256 -= 128; - - // clamp coordinates - x_256 &= ~(x_256 >> 31); - y_256 &= ~(y_256 >> 31); - - uint32 w_256 = (w - 1) << 8; - uint32 h_256 = (h - 1) << 8; - x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); - y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); - - const uint16 *row0 = (const uint16 *)((const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2); - const uint16 *row1 = row0; - - if ((uint32)y_256 < h_256) - row1 = (const uint16 *)((const char *)row1 + pitch); - - ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; - float xoffset = (float)(x_256 & 255) * (1.0f / 255.0f); - float yoffset = (float)(y_256 & 255) * (1.0f / 255.0f); - - float p00; - float p10; - float p01; - float p11; - VDConvertHalfToFloat(row0[0], &p00); - VDConvertHalfToFloat(row0[xstep], &p10); - VDConvertHalfToFloat(row1[0], &p01); - VDConvertHalfToFloat(row1[xstep], &p11); - - float p0 = p00 + (p10 - p00)*xoffset; - float p1 = p01 + (p11 - p01)*xoffset; - - return p0 + (p1 - p0)*yoffset; -} - -namespace { - uint32 Lerp8888(uint32 p0, uint32 p1, uint32 p2, uint32 p3, uint32 xf, uint32 yf) { - uint32 rb0 = p0 & 0x00ff00ff; - uint32 ag0 = p0 & 0xff00ff00; - uint32 rb1 = p1 & 0x00ff00ff; - uint32 ag1 = p1 & 0xff00ff00; - uint32 rb2 = p2 & 0x00ff00ff; - uint32 ag2 = p2 & 0xff00ff00; - uint32 rb3 = p3 & 0x00ff00ff; - uint32 ag3 = p3 & 0xff00ff00; - - uint32 rbt = (rb0 + ((( rb1 - rb0 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; - uint32 agt = (ag0 + ((((ag1 >> 8) - (ag0 >> 8))*xf + 0x00800080) )) & 0xff00ff00; - uint32 rbb = (rb2 + ((( rb3 - rb2 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; - uint32 agb = (ag2 + ((((ag3 >> 8) - (ag2 >> 8))*xf + 0x00800080) )) & 0xff00ff00; - uint32 rb = (rbt + ((( rbb - rbt )*yf + 0x00800080) >> 8)) & 0x00ff00ff; - uint32 ag = (agt + ((((agb >> 8) - (agt >> 8))*yf + 0x00800080) )) & 0xff00ff00; - - return rb + ag; - } - - uint32 InterpPlanarY8(const VDPixmap& px, sint32 x1, sint32 y1) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - - return VDClampedRoundFixedToUint8Fast((float)(y-0x100000) * (1.1643836f/65536.0f/255.0f))*0x010101; - } - - uint32 ConvertYCC72ToRGB24(sint32 iy, sint32 icb, sint32 icr) { - float y = (float)iy; - float cb = (float)icb; - float cr = (float)icr; - - // ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! - // ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! - // ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! - uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.5960268f/65536.0f/255.0f)*cr - (222.92157f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.3917623f/65536.0f/255.0f)*cb - (0.8129676f/65536.0f/255.0f)*cr + (135.57529f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.0172321f/65536.0f/255.0f)*cb - (276.83585f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - uint32 ConvertYCC72ToRGB24_FR(sint32 iy, sint32 icb, sint32 icr) { - float y = (float)iy; - float cb = (float)icb; - float cr = (float)icr; - - // 1. 0. 1.402 - 179.456 - // 1. - 0.3441363 - 0.7141363 135.45889 - // 1. 1.772 - 2.220D-16 - 226.816 - uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.4020000f/65536.0f/255.0f)*cr - (179.456f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.3441363f/65536.0f/255.0f)*cb - (0.7141363f/65536.0f/255.0f)*cr + (135.45889f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.7720000f/65536.0f/255.0f)*cb - (226.816f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - uint32 ConvertYCC72ToRGB24_709(sint32 iy, sint32 icb, sint32 icr) { - float y = (float)iy; - float cb = (float)icb; - float cr = (float)icr; - - // ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! - // ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! - // ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! - uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.7927411f/65536.0f/255.0f)*cr - (248.10099f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.2132486f/65536.0f/255.0f)*cb - (0.5329093f/65536.0f/255.0f)*cr + (76.87808f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.1124018f/65536.0f/255.0f)*cb - (289.01757f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - uint32 ConvertYCC72ToRGB24_709_FR(sint32 iy, sint32 icb, sint32 icr) { - float y = (float)iy; - float cb = (float)icb; - float cr = (float)icr; - - // 1. 0. 1.5748 - 201.5744 - // 1. - 0.1873243 - 0.4681243 83.897414 - // 1. 1.8556 0. - 237.5168 - uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.5748f/65536.0f/255.0f)*cr - (201.5744f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.1873243f/65536.0f/255.0f)*cb - (0.4681243f/65536.0f/255.0f)*cr + (83.897414f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.8556f/65536.0f/255.0f)*cb - (237.5168f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - uint32 InterpPlanarYCC888(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); - sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); - - return ConvertYCC72ToRGB24(y, cb, cr); - } - - uint32 InterpPlanarYCC888_709(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); - sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); - - return ConvertYCC72ToRGB24_709(y, cb, cr); - } - - uint32 InterpPlanarYCC888_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); - sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); - - return ConvertYCC72ToRGB24_FR(y, cb, cr); - } - - uint32 InterpPlanarYCC888_709_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); - sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); - - return ConvertYCC72ToRGB24_709_FR(y, cb, cr); - } - - template - uint32 InterpPlanarYCC888_420i(const VDPixmap& px, sint32 x1, sint32 y1) { - sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); - sint32 cb; - sint32 cr; - - const uint8 *src2 = (const uint8 *)px.data2; - const uint8 *src3 = (const uint8 *)px.data3; - const ptrdiff_t pitch2 = px.pitch2 + px.pitch2; - const ptrdiff_t pitch3 = px.pitch3 + px.pitch3; - const uint32 w23 = (px.w + 1) >> 1; - const uint32 h23 = (px.h + 1) >> 1; - const sint32 xc = (x1 >> 1) + 64; - sint32 yc = (y1 >> 1) + 64; - - if (y1 & 1) { - yc -= 256; - cb = VDPixmapInterpolateSample8To24(src2, pitch2, w23, h23 >> 1, xc, yc); - cr = VDPixmapInterpolateSample8To24(src3, pitch3, w23, h23 >> 1, xc, yc); - } else { - cb = VDPixmapInterpolateSample8To24(src2 + px.pitch2, pitch2, w23, (h23 + 1) >> 1, xc, yc); - cr = VDPixmapInterpolateSample8To24(src3 + px.pitch3, pitch3, w23, (h23 + 1) >> 1, xc, yc); - } - - return ConvFn(y, cb, cr); - } - - uint32 SampleV210_Y(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { - if (x < 0) - x = 0; - if ((uint32)x >= w) - x = w - 1; - if (y < 0) - y = 0; - if ((uint32)y >= h) - y = h - 1; - - const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 6)*4; - - switch((uint32)x % 6) { - default: - case 0: return (p[0] >> 10) & 0x3ff; - case 1: return (p[1] >> 0) & 0x3ff; - case 2: return (p[1] >> 20) & 0x3ff; - case 3: return (p[2] >> 10) & 0x3ff; - case 4: return (p[3] >> 0) & 0x3ff; - case 5: return (p[3] >> 20) & 0x3ff; - } - } - - uint32 SampleV210_Cb(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { - if (x < 0) - x = 0; - if ((uint32)x >= w) - x = w - 1; - if (y < 0) - y = 0; - if ((uint32)y >= h) - y = h - 1; - - const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; - - switch((uint32)x % 3) { - default: - case 0: return (p[0] >> 0) & 0x3ff; - case 1: return (p[1] >> 10) & 0x3ff; - case 2: return (p[2] >> 20) & 0x3ff; - } - } - - uint32 SampleV210_Cr(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { - if (x < 0) - x = 0; - if ((uint32)x >= w) - x = w - 1; - if (y < 0) - y = 0; - if ((uint32)y >= h) - y = h - 1; - - const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; - - switch((uint32)x % 3) { - default: - case 0: return (p[0] >> 20) & 0x3ff; - case 1: return (p[2] >> 0) & 0x3ff; - case 2: return (p[3] >> 10) & 0x3ff; - } - } -} - -uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x_256, sint32 y_256) { - switch(px.format) { - case nsVDPixmap::kPixFormat_Pal1: - case nsVDPixmap::kPixFormat_Pal2: - case nsVDPixmap::kPixFormat_Pal4: - case nsVDPixmap::kPixFormat_Pal8: - case nsVDPixmap::kPixFormat_RGB565: - case nsVDPixmap::kPixFormat_RGB888: - case nsVDPixmap::kPixFormat_XRGB1555: - case nsVDPixmap::kPixFormat_XRGB8888: - { - x_256 -= 128; - y_256 -= 128; - int ix = x_256 >> 8; - int iy = y_256 >> 8; - uint32 p0 = VDPixmapSample(px, ix, iy); - uint32 p1 = VDPixmapSample(px, ix+1, iy); - uint32 p2 = VDPixmapSample(px, ix, iy+1); - uint32 p3 = VDPixmapSample(px, ix+1, iy+1); - - return Lerp8888(p0, p1, p2, p3, x_256 & 255, y_256 & 255); - } - break; - - case nsVDPixmap::kPixFormat_Y8: - return InterpPlanarY8(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV422_UYVY: - return ConvertYCC72ToRGB24( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_YUYV: - return ConvertYCC72ToRGB24( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_UYVY_FR: - return ConvertYCC72ToRGB24_FR( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_YUYV_FR: - return ConvertYCC72ToRGB24_FR( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV444_XVYU: - return ConvertYCC72ToRGB24( - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, px.w, px.h, x_256, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_UYVY_709: - return ConvertYCC72ToRGB24_709( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_YUYV_709: - return ConvertYCC72ToRGB24_709( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_UYVY_709_FR: - return ConvertYCC72ToRGB24_709_FR( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV422_YUYV_709_FR: - return ConvertYCC72ToRGB24_709_FR( - VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), - VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) - ); - - case nsVDPixmap::kPixFormat_YUV420_NV12: - return ConvertYCC72ToRGB24( - VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x_256, y_256), - VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 0, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1), - VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 1, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1) - ); - - case nsVDPixmap::kPixFormat_YUV444_Planar: - return InterpPlanarYCC888(px, x_256, y_256, x_256, y_256, px.w, px.h); - - case nsVDPixmap::kPixFormat_YUV422_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV411_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); - - case nsVDPixmap::kPixFormat_YUV420_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420it_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420ib_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV410_Planar: - return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); - - case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: - return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: - return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, x_256, y_256, px.w, px.h); - - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); - - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420it_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420ib_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); - - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); - - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); - - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420it_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420ib_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); - - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); - - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); - - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); - - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); - - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); - - case nsVDPixmap::kPixFormat_YUV420i_Planar: - return InterpPlanarYCC888_420i(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: - return InterpPlanarYCC888_420i(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV420i_Planar_709: - return InterpPlanarYCC888_420i(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: - return InterpPlanarYCC888_420i(px, x_256, y_256); - - case nsVDPixmap::kPixFormat_YUV422_Planar_16F: - { - float y = VDPixmapInterpolateSample16F(px.data, px.pitch, px.w, px.h, x_256, y_256); - float cb = VDPixmapInterpolateSample16F(px.data2, px.pitch2, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); - float cr = VDPixmapInterpolateSample16F(px.data3, px.pitch3, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); - - uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 1.5960268f*cr - (222.92157f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*y - 0.3917623f*cb - 0.8129676f*cr + (135.57529f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 2.0172321f*cb - (276.83585f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - - case nsVDPixmap::kPixFormat_YUV422_V210: - { - sint32 luma_x = x_256 - 128; - sint32 luma_y = y_256 - 128; - - if (luma_x < 0) - luma_x = 0; - - if (luma_y < 0) - luma_y = 0; - - if (luma_x > (sint32)((px.w - 1) << 8)) - luma_x = (sint32)((px.w - 1) << 8); - - if (luma_y > (sint32)((px.h - 1) << 8)) - luma_y = (sint32)((px.h - 1) << 8); - - sint32 luma_ix = luma_x >> 8; - sint32 luma_iy = luma_y >> 8; - float luma_fx = (float)(luma_x & 255) * (1.0f / 255.0f); - float luma_fy = (float)(luma_y & 255) * (1.0f / 255.0f); - - float y0 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); - float y1 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); - float y2 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); - float y3 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); - float yt = y0 + (y1 - y0)*luma_fx; - float yb = y2 + (y3 - y2)*luma_fx; - float yr = yt + (yb - yt)*luma_fy; - - uint32 chroma_w = (px.w + 1) >> 1; - uint32 chroma_h = px.h; - sint32 chroma_x = x_256 >> 1; - sint32 chroma_y = y_256 - 128; - - if (chroma_x < 0) - chroma_x = 0; - - if (chroma_y < 0) - chroma_y = 0; - - if (chroma_x > (sint32)((chroma_w - 1) << 8)) - chroma_x = (sint32)((chroma_w - 1) << 8); - - if (chroma_y > (sint32)((chroma_h - 1) << 8)) - chroma_y = (sint32)((chroma_h - 1) << 8); - - sint32 chroma_ix = chroma_x >> 8; - sint32 chroma_iy = chroma_y >> 8; - float chroma_fx = (float)(chroma_x & 255) * (1.0f / 255.0f); - float chroma_fy = (float)(chroma_y & 255) * (1.0f / 255.0f); - - float cb0 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cb1 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cb2 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cb3 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cbt = cb0 + (cb1 - cb0)*chroma_fx; - float cbb = cb2 + (cb3 - cb2)*chroma_fx; - float cbr = cbt + (cbb - cbt)*chroma_fy; - - float cr0 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cr1 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cr2 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); - float cr3 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); - float crt = cr0 + (cr1 - cr0)*chroma_fx; - float crb = cr2 + (cr3 - cr2)*chroma_fx; - float crr = crt + (crb - crt)*chroma_fy; - - uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 1.5960268f*crr - (222.92157f / 255.0f)); - uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*yr - 0.3917623f*cbr - 0.8129676f*crr + (135.57529f / 255.0f)); - uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 2.0172321f*cbr - (276.83585f / 255.0f)); - - return (ir << 16) + (ig << 8) + ib; - } - break; - - default: - return 0; - } -} - -uint32 VDConvertYCbCrToRGB(uint8 y0, uint8 cb0, uint8 cr0, bool use709, bool useFullRange) { - sint32 y = y0; - sint32 cb = cb0 - 128; - sint32 cr = cr0 - 128; - sint32 r; - sint32 g; - sint32 b; - - if (use709) { - if (useFullRange) { - sint32 y2 = (y << 16) + 0x8000; - r = y2 + cr * 103206; - g = y2 + cr * -30679 + cb * -12276; - b = y2 + cb * 121609; - } else { - sint32 y2 = (y - 16) * 76309 + 0x8000; - r = y2 + cr * 117489; - g = y2 + cr * -34925 + cb * -13975; - b = y2 + cb * 138438; - } - } else { - if (useFullRange) { - sint32 y2 = (y << 16) + 0x8000; - r = y2 + cr * 91181; - g = y2 + cr * -46802 + cb * -22554; - b = y2 + cb * 166130; - } else { - sint32 y2 = (y - 16) * 76309 + 0x8000; - r = y2 + cr * 104597; - g = y2 + cr * -53279 + cb * -25674; - b = y2 + cb * 132201; - } - } - - r &= ~(r >> 31); - g &= ~(g >> 31); - b &= ~(b >> 31); - r += (0xffffff - r) & ((0xffffff - r) >> 31); - g += (0xffffff - g) & ((0xffffff - g) >> 31); - b += (0xffffff - b) & ((0xffffff - b) >> 31); - - return (r & 0xff0000) + ((g & 0xff0000) >> 8) + (b >> 16); -} - -uint32 VDConvertRGBToYCbCr(uint32 c) { - return VDConvertRGBToYCbCr((uint8)(c >> 16), (uint8)(c >> 8), (uint8)c, false, false); -} - -uint32 VDConvertRGBToYCbCr(uint8 r8, uint8 g8, uint8 b8, bool use709, bool useFullRange) { - sint32 r = r8; - sint32 g = g8; - sint32 b = b8; - sint32 y; - sint32 cb; - sint32 cr; - - if (use709) { - if (useFullRange) { - y = ( 13933*r + 46871*g + 4732*b + 0x8000) >> 8; - cb = ( -7509*r - 25259*g + 32768*b + 0x808000) >> 16; - cr = ( 32768*r - 29763*g - 3005*b + 0x808000); - } else { - y = ( 11966*r + 40254*g + 4064*b + 0x108000) >> 8; - cb = ( -6596*r - 22189*g + 28784*b + 0x808000) >> 16; - cr = ( 28784*r - 26145*g - 2639*b + 0x808000); - } - } else { - if (useFullRange) { - y = ( 19595*r + 38470*g + 7471*b + 0x8000) >> 8; - cb = (-11058*r - 21710*g + 32768*b + 0x808000) >> 16; - cr = ( 32768*r - 27439*g - 5329*b + 0x808000); - } else { - y = ( 16829*r + 33039*g + 6416*b + 0x108000) >> 8; - cb = ( -9714*r - 19071*g + 28784*b + 0x808000) >> 16; - cr = ( 28784*r - 24103*g - 4681*b + 0x808000); - } - } - - return (uint8)cb + (y & 0xff00) + (cr&0xff0000); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include + +uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y) { + if (x >= px.w) + x = px.w - 1; + if (y >= px.h) + y = px.h - 1; + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + switch(px.format) { + case nsVDPixmap::kPixFormat_Pal1: + { + uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 3]; + + return px.palette[(idx >> (7 - (x & 7))) & 1]; + } + + case nsVDPixmap::kPixFormat_Pal2: + { + uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 2]; + + return px.palette[(idx >> (6 - (x & 3)*2)) & 3]; + } + + case nsVDPixmap::kPixFormat_Pal4: + { + uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x >> 1]; + + if (!(x & 1)) + idx >>= 4; + + return px.palette[idx & 15]; + } + + case nsVDPixmap::kPixFormat_Pal8: + { + uint8 idx = ((const uint8 *)px.data + px.pitch*y)[x]; + + return px.palette[idx]; + } + + case nsVDPixmap::kPixFormat_XRGB1555: + { + uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; + uint32 r = c & 0x7c00; + uint32 g = c & 0x03e0; + uint32 b = c & 0x001f; + uint32 rgb = (r << 9) + (g << 6) + (b << 3); + + return rgb + ((rgb >> 5) & 0x070707); + } + break; + + case nsVDPixmap::kPixFormat_RGB565: + { + uint16 c = ((const uint16 *)((const uint8 *)px.data + px.pitch*y))[x]; + uint32 r = c & 0xf800; + uint32 g = c & 0x07e0; + uint32 b = c & 0x001f; + uint32 rb = (r << 8) + (b << 3); + + return rb + ((rb >> 5) & 0x070007) + (g << 5) + ((g >> 1) & 0x0300); + } + break; + + case nsVDPixmap::kPixFormat_RGB888: + { + const uint8 *src = (const uint8 *)px.data + px.pitch*y + 3*x; + uint32 b = src[0]; + uint32 g = src[1]; + uint32 r = src[2]; + + return (r << 16) + (g << 8) + b; + } + break; + + case nsVDPixmap::kPixFormat_XRGB8888: + return ((const uint32 *)((const uint8 *)px.data + px.pitch*y))[x]; + + case nsVDPixmap::kPixFormat_Y8: + { + uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; + + return ((luma - 16)*255/219) * 0x010101; + } + break; + + case nsVDPixmap::kPixFormat_Y8_FR: + { + uint8 luma = ((const uint8 *)px.data + px.pitch*y)[x]; + + return (uint32)luma * 0x010101; + } + break; + + case nsVDPixmap::kPixFormat_YUV444_Planar: + return VDConvertYCbCrToRGB(VDPixmapSample8(px.data, px.pitch, x, y), VDPixmapSample8(px.data2, px.pitch2, x, y), VDPixmapSample8(px.data3, px.pitch3, x, y), false, false); + + case nsVDPixmap::kPixFormat_YUV422_Planar: + { + sint32 u = (x << 7) + 128; + sint32 v = (y << 8); + uint32 w2 = px.w >> 1; + uint32 h2 = px.h; + + return VDConvertYCbCrToRGB( + VDPixmapSample8(px.data, px.pitch, x, y), + VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), + VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), + false, false); + } + + case nsVDPixmap::kPixFormat_YUV420_Planar: + { + sint32 u = (x << 7) + 128; + sint32 v = (y << 7); + uint32 w2 = px.w >> 1; + uint32 h2 = px.h >> 1; + + return VDConvertYCbCrToRGB( + VDPixmapSample8(px.data, px.pitch, x, y), + VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), + VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), + false, false); + } + + case nsVDPixmap::kPixFormat_YUV411_Planar: + { + sint32 u = (x << 6) + 128; + sint32 v = (y << 8); + uint32 w2 = px.w >> 2; + uint32 h2 = px.h; + + return VDConvertYCbCrToRGB( + VDPixmapSample8(px.data, px.pitch, x, y), + VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), + VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), + false, false); + } + + case nsVDPixmap::kPixFormat_YUV410_Planar: + { + sint32 u = (x << 6) + 128; + sint32 v = (y << 6); + uint32 w2 = px.w >> 2; + uint32 h2 = px.h >> 2; + + return VDConvertYCbCrToRGB( + VDPixmapSample8(px.data, px.pitch, x, y), + VDPixmapInterpolateSample8(px.data2, px.pitch2, w2, h2, u, v), + VDPixmapInterpolateSample8(px.data3, px.pitch3, w2, h2, u, v), + false, false); + } + + default: + return VDPixmapInterpolateSampleRGB24(px, (x << 8) + 128, (y << 8) + 128); + } +} + +uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + uint32 w_256 = (w - 1) << 8; + uint32 h_256 = (h - 1) << 8; + x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); + y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); + + const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8); + const uint8 *row1 = row0; + + if ((uint32)y_256 < h_256) + row1 += pitch; + + ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; + sint32 xoffset = x_256 & 255; + sint32 yoffset = y_256 & 255; + sint32 p00 = row0[0]; + sint32 p10 = row0[xstep]; + sint32 p01 = row1[0]; + sint32 p11 = row1[xstep]; + sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; + sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; + sint32 p = ((p0 << 8) + (p1 - p0)*yoffset + 0x8000) >> 16; + + return (uint8)p; +} + +uint32 VDPixmapInterpolateSample8To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + sint32 w_256 = (w - 1) << 8; + sint32 h_256 = (h - 1) << 8; + x_256 += (w_256 - x_256) & ((w_256 - x_256) >> 31); + y_256 += (h_256 - y_256) & ((h_256 - y_256) >> 31); + + const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8); + const uint8 *row1 = row0; + + if (y_256 < h_256) + row1 += pitch; + + ptrdiff_t xstep = x_256 < w_256 ? 1 : 0; + sint32 xoffset = x_256 & 255; + sint32 yoffset = y_256 & 255; + sint32 p00 = row0[0]; + sint32 p10 = row0[xstep]; + sint32 p01 = row1[0]; + sint32 p11 = row1[xstep]; + sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; + sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; + sint32 p = (p0 << 8) + (p1 - p0)*yoffset; + + return p; +} + +uint32 VDPixmapInterpolateSample8x2To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + uint32 w_256 = (w - 1) << 8; + uint32 h_256 = (h - 1) << 8; + x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); + y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); + + const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2; + const uint8 *row1 = row0; + + if ((uint32)y_256 < h_256) + row1 += pitch; + + ptrdiff_t xstep = (uint32)x_256 < w_256 ? 2 : 0; + sint32 xoffset = x_256 & 255; + sint32 yoffset = y_256 & 255; + sint32 p00 = row0[0]; + sint32 p10 = row0[xstep]; + sint32 p01 = row1[0]; + sint32 p11 = row1[xstep]; + sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; + sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; + sint32 p = (p0 << 8) + (p1 - p0)*yoffset; + + return p; +} + +uint32 VDPixmapInterpolateSample8x4To24(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + uint32 w_256 = (w - 1) << 8; + uint32 h_256 = (h - 1) << 8; + x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); + y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); + + const uint8 *row0 = (const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*4; + const uint8 *row1 = row0; + + if ((uint32)y_256 < h_256) + row1 += pitch; + + ptrdiff_t xstep = (uint32)x_256 < w_256 ? 4 : 0; + sint32 xoffset = x_256 & 255; + sint32 yoffset = y_256 & 255; + sint32 p00 = row0[0]; + sint32 p10 = row0[xstep]; + sint32 p01 = row1[0]; + sint32 p11 = row1[xstep]; + sint32 p0 = (p00 << 8) + (p10 - p00)*xoffset; + sint32 p1 = (p01 << 8) + (p11 - p01)*xoffset; + sint32 p = (p0 << 8) + (p1 - p0)*yoffset; + + return p; +} + +float VDPixmapInterpolateSample16F(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256) { + // bias coordinates to integer + x_256 -= 128; + y_256 -= 128; + + // clamp coordinates + x_256 &= ~(x_256 >> 31); + y_256 &= ~(y_256 >> 31); + + uint32 w_256 = (w - 1) << 8; + uint32 h_256 = (h - 1) << 8; + x_256 ^= (x_256 ^ w_256) & ((x_256 - w_256) >> 31); + y_256 ^= (y_256 ^ h_256) & ((y_256 - h_256) >> 31); + + const uint16 *row0 = (const uint16 *)((const uint8 *)data + pitch * (y_256 >> 8) + (x_256 >> 8)*2); + const uint16 *row1 = row0; + + if ((uint32)y_256 < h_256) + row1 = (const uint16 *)((const char *)row1 + pitch); + + ptrdiff_t xstep = (uint32)x_256 < w_256 ? 1 : 0; + float xoffset = (float)(x_256 & 255) * (1.0f / 255.0f); + float yoffset = (float)(y_256 & 255) * (1.0f / 255.0f); + + float p00; + float p10; + float p01; + float p11; + VDConvertHalfToFloat(row0[0], &p00); + VDConvertHalfToFloat(row0[xstep], &p10); + VDConvertHalfToFloat(row1[0], &p01); + VDConvertHalfToFloat(row1[xstep], &p11); + + float p0 = p00 + (p10 - p00)*xoffset; + float p1 = p01 + (p11 - p01)*xoffset; + + return p0 + (p1 - p0)*yoffset; +} + +namespace { + uint32 Lerp8888(uint32 p0, uint32 p1, uint32 p2, uint32 p3, uint32 xf, uint32 yf) { + uint32 rb0 = p0 & 0x00ff00ff; + uint32 ag0 = p0 & 0xff00ff00; + uint32 rb1 = p1 & 0x00ff00ff; + uint32 ag1 = p1 & 0xff00ff00; + uint32 rb2 = p2 & 0x00ff00ff; + uint32 ag2 = p2 & 0xff00ff00; + uint32 rb3 = p3 & 0x00ff00ff; + uint32 ag3 = p3 & 0xff00ff00; + + uint32 rbt = (rb0 + ((( rb1 - rb0 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; + uint32 agt = (ag0 + ((((ag1 >> 8) - (ag0 >> 8))*xf + 0x00800080) )) & 0xff00ff00; + uint32 rbb = (rb2 + ((( rb3 - rb2 )*xf + 0x00800080) >> 8)) & 0x00ff00ff; + uint32 agb = (ag2 + ((((ag3 >> 8) - (ag2 >> 8))*xf + 0x00800080) )) & 0xff00ff00; + uint32 rb = (rbt + ((( rbb - rbt )*yf + 0x00800080) >> 8)) & 0x00ff00ff; + uint32 ag = (agt + ((((agb >> 8) - (agt >> 8))*yf + 0x00800080) )) & 0xff00ff00; + + return rb + ag; + } + + uint32 InterpPlanarY8(const VDPixmap& px, sint32 x1, sint32 y1) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + + return VDClampedRoundFixedToUint8Fast((float)(y-0x100000) * (1.1643836f/65536.0f/255.0f))*0x010101; + } + + uint32 ConvertYCC72ToRGB24(sint32 iy, sint32 icb, sint32 icr) { + float y = (float)iy; + float cb = (float)icb; + float cr = (float)icr; + + // ! 1.1643836 - 5.599D-17 1.5960268 - 222.92157 ! + // ! 1.1643836 - 0.3917623 - 0.8129676 135.57529 ! + // ! 1.1643836 2.0172321 - 1.110D-16 - 276.83585 ! + uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.5960268f/65536.0f/255.0f)*cr - (222.92157f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.3917623f/65536.0f/255.0f)*cb - (0.8129676f/65536.0f/255.0f)*cr + (135.57529f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.0172321f/65536.0f/255.0f)*cb - (276.83585f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + uint32 ConvertYCC72ToRGB24_FR(sint32 iy, sint32 icb, sint32 icr) { + float y = (float)iy; + float cb = (float)icb; + float cr = (float)icr; + + // 1. 0. 1.402 - 179.456 + // 1. - 0.3441363 - 0.7141363 135.45889 + // 1. 1.772 - 2.220D-16 - 226.816 + uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.4020000f/65536.0f/255.0f)*cr - (179.456f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.3441363f/65536.0f/255.0f)*cb - (0.7141363f/65536.0f/255.0f)*cr + (135.45889f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.7720000f/65536.0f/255.0f)*cb - (226.816f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + uint32 ConvertYCC72ToRGB24_709(sint32 iy, sint32 icb, sint32 icr) { + float y = (float)iy; + float cb = (float)icb; + float cr = (float)icr; + + // ! 1.1643836 - 2.932D-17 1.7927411 - 248.10099 ! + // ! 1.1643836 - 0.2132486 - 0.5329093 76.87808 ! + // ! 1.1643836 2.1124018 - 5.551D-17 - 289.01757 ! + uint32 ir = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (1.7927411f/65536.0f/255.0f)*cr - (248.10099f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y - (0.2132486f/65536.0f/255.0f)*cb - (0.5329093f/65536.0f/255.0f)*cr + (76.87808f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast((1.1643836f/65536.0f/255.0f)*y + (2.1124018f/65536.0f/255.0f)*cb - (289.01757f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + uint32 ConvertYCC72ToRGB24_709_FR(sint32 iy, sint32 icb, sint32 icr) { + float y = (float)iy; + float cb = (float)icb; + float cr = (float)icr; + + // 1. 0. 1.5748 - 201.5744 + // 1. - 0.1873243 - 0.4681243 83.897414 + // 1. 1.8556 0. - 237.5168 + uint32 ir = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.5748f/65536.0f/255.0f)*cr - (201.5744f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y - (0.1873243f/65536.0f/255.0f)*cb - (0.4681243f/65536.0f/255.0f)*cr + (83.897414f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast((1.0f/65536.0f/255.0f)*y + (1.8556f/65536.0f/255.0f)*cb - (237.5168f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + uint32 InterpPlanarYCC888(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); + sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); + + return ConvertYCC72ToRGB24(y, cb, cr); + } + + uint32 InterpPlanarYCC888_709(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); + sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); + + return ConvertYCC72ToRGB24_709(y, cb, cr); + } + + uint32 InterpPlanarYCC888_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); + sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); + + return ConvertYCC72ToRGB24_FR(y, cb, cr); + } + + uint32 InterpPlanarYCC888_709_FR(const VDPixmap& px, sint32 x1, sint32 y1, sint32 x23, sint32 y23, uint32 w23, uint32 h23) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb = VDPixmapInterpolateSample8To24(px.data2, px.pitch2, w23, h23, x23, y23); + sint32 cr = VDPixmapInterpolateSample8To24(px.data3, px.pitch3, w23, h23, x23, y23); + + return ConvertYCC72ToRGB24_709_FR(y, cb, cr); + } + + template + uint32 InterpPlanarYCC888_420i(const VDPixmap& px, sint32 x1, sint32 y1) { + sint32 y = VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x1, y1); + sint32 cb; + sint32 cr; + + const uint8 *src2 = (const uint8 *)px.data2; + const uint8 *src3 = (const uint8 *)px.data3; + const ptrdiff_t pitch2 = px.pitch2 + px.pitch2; + const ptrdiff_t pitch3 = px.pitch3 + px.pitch3; + const uint32 w23 = (px.w + 1) >> 1; + const uint32 h23 = (px.h + 1) >> 1; + const sint32 xc = (x1 >> 1) + 64; + sint32 yc = (y1 >> 1) + 64; + + if (y1 & 1) { + yc -= 256; + cb = VDPixmapInterpolateSample8To24(src2, pitch2, w23, h23 >> 1, xc, yc); + cr = VDPixmapInterpolateSample8To24(src3, pitch3, w23, h23 >> 1, xc, yc); + } else { + cb = VDPixmapInterpolateSample8To24(src2 + px.pitch2, pitch2, w23, (h23 + 1) >> 1, xc, yc); + cr = VDPixmapInterpolateSample8To24(src3 + px.pitch3, pitch3, w23, (h23 + 1) >> 1, xc, yc); + } + + return ConvFn(y, cb, cr); + } + + uint32 SampleV210_Y(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { + if (x < 0) + x = 0; + if ((uint32)x >= w) + x = w - 1; + if (y < 0) + y = 0; + if ((uint32)y >= h) + y = h - 1; + + const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 6)*4; + + switch((uint32)x % 6) { + default: + case 0: return (p[0] >> 10) & 0x3ff; + case 1: return (p[1] >> 0) & 0x3ff; + case 2: return (p[1] >> 20) & 0x3ff; + case 3: return (p[2] >> 10) & 0x3ff; + case 4: return (p[3] >> 0) & 0x3ff; + case 5: return (p[3] >> 20) & 0x3ff; + } + } + + uint32 SampleV210_Cb(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { + if (x < 0) + x = 0; + if ((uint32)x >= w) + x = w - 1; + if (y < 0) + y = 0; + if ((uint32)y >= h) + y = h - 1; + + const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; + + switch((uint32)x % 3) { + default: + case 0: return (p[0] >> 0) & 0x3ff; + case 1: return (p[1] >> 10) & 0x3ff; + case 2: return (p[2] >> 20) & 0x3ff; + } + } + + uint32 SampleV210_Cr(const void *src, ptrdiff_t srcpitch, sint32 x, sint32 y, uint32 w, uint32 h) { + if (x < 0) + x = 0; + if ((uint32)x >= w) + x = w - 1; + if (y < 0) + y = 0; + if ((uint32)y >= h) + y = h - 1; + + const uint32 *p = (const uint32 *)((const char *)src + srcpitch*y) + (x / 3)*4; + + switch((uint32)x % 3) { + default: + case 0: return (p[0] >> 20) & 0x3ff; + case 1: return (p[2] >> 0) & 0x3ff; + case 2: return (p[3] >> 10) & 0x3ff; + } + } +} + +uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x_256, sint32 y_256) { + switch(px.format) { + case nsVDPixmap::kPixFormat_Pal1: + case nsVDPixmap::kPixFormat_Pal2: + case nsVDPixmap::kPixFormat_Pal4: + case nsVDPixmap::kPixFormat_Pal8: + case nsVDPixmap::kPixFormat_RGB565: + case nsVDPixmap::kPixFormat_RGB888: + case nsVDPixmap::kPixFormat_XRGB1555: + case nsVDPixmap::kPixFormat_XRGB8888: + { + x_256 -= 128; + y_256 -= 128; + int ix = x_256 >> 8; + int iy = y_256 >> 8; + uint32 p0 = VDPixmapSample(px, ix, iy); + uint32 p1 = VDPixmapSample(px, ix+1, iy); + uint32 p2 = VDPixmapSample(px, ix, iy+1); + uint32 p3 = VDPixmapSample(px, ix+1, iy+1); + + return Lerp8888(p0, p1, p2, p3, x_256 & 255, y_256 & 255); + } + break; + + case nsVDPixmap::kPixFormat_Y8: + return InterpPlanarY8(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV422_UYVY: + return ConvertYCC72ToRGB24( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_YUYV: + return ConvertYCC72ToRGB24( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_UYVY_FR: + return ConvertYCC72ToRGB24_FR( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_YUYV_FR: + return ConvertYCC72ToRGB24_FR( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV444_XVYU: + return ConvertYCC72ToRGB24( + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, px.w, px.h, x_256, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_UYVY_709: + return ConvertYCC72ToRGB24_709( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_YUYV_709: + return ConvertYCC72ToRGB24_709( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_UYVY_709_FR: + return ConvertYCC72ToRGB24_709_FR( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 1, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 0, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 2, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV422_YUYV_709_FR: + return ConvertYCC72ToRGB24_709_FR( + VDPixmapInterpolateSample8x2To24((const char *)px.data + 0, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 1, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256), + VDPixmapInterpolateSample8x4To24((const char *)px.data + 3, px.pitch, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256) + ); + + case nsVDPixmap::kPixFormat_YUV420_NV12: + return ConvertYCC72ToRGB24( + VDPixmapInterpolateSample8To24(px.data, px.pitch, px.w, px.h, x_256, y_256), + VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 0, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1), + VDPixmapInterpolateSample8x2To24((const char *)px.data2 + 1, px.pitch2, (px.w + 1) >> 1, (px.h + 1) >> 1, (x_256 >> 1) + 128, y_256 >> 1) + ); + + case nsVDPixmap::kPixFormat_YUV444_Planar: + return InterpPlanarYCC888(px, x_256, y_256, x_256, y_256, px.w, px.h); + + case nsVDPixmap::kPixFormat_YUV422_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV411_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); + + case nsVDPixmap::kPixFormat_YUV420_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420it_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420ib_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV410_Planar: + return InterpPlanarYCC888(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); + + case nsVDPixmap::kPixFormat_YUV420_Planar_Centered: + return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV422_Planar_Centered: + return InterpPlanarYCC888(px, x_256, y_256, x_256 >> 1, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, x_256, y_256, px.w, px.h); + + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); + + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420it_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420ib_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + return InterpPlanarYCC888_709(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); + + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); + + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); + + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420it_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420ib_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + return InterpPlanarYCC888_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); + + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, x_256, y_256, px.w, px.h); + + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256, (px.w + 1) >> 1, px.h); + + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256, (px.w + 3) >> 2, px.h); + + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, y_256 >> 1, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) + 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 1) + 64, (y_256 >> 1) - 32, (px.w + 1) >> 1, (px.h + 1) >> 1); + + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + return InterpPlanarYCC888_709_FR(px, x_256, y_256, (x_256 >> 2) + 96, y_256 >> 2, (px.w + 3) >> 2, (px.h + 3) >> 2); + + case nsVDPixmap::kPixFormat_YUV420i_Planar: + return InterpPlanarYCC888_420i(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: + return InterpPlanarYCC888_420i(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV420i_Planar_709: + return InterpPlanarYCC888_420i(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: + return InterpPlanarYCC888_420i(px, x_256, y_256); + + case nsVDPixmap::kPixFormat_YUV422_Planar_16F: + { + float y = VDPixmapInterpolateSample16F(px.data, px.pitch, px.w, px.h, x_256, y_256); + float cb = VDPixmapInterpolateSample16F(px.data2, px.pitch2, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); + float cr = VDPixmapInterpolateSample16F(px.data3, px.pitch3, (px.w + 1) >> 1, px.h, (x_256 >> 1) + 128, y_256); + + uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 1.5960268f*cr - (222.92157f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*y - 0.3917623f*cb - 0.8129676f*cr + (135.57529f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*y + 2.0172321f*cb - (276.83585f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + + case nsVDPixmap::kPixFormat_YUV422_V210: + { + sint32 luma_x = x_256 - 128; + sint32 luma_y = y_256 - 128; + + if (luma_x < 0) + luma_x = 0; + + if (luma_y < 0) + luma_y = 0; + + if (luma_x > (sint32)((px.w - 1) << 8)) + luma_x = (sint32)((px.w - 1) << 8); + + if (luma_y > (sint32)((px.h - 1) << 8)) + luma_y = (sint32)((px.h - 1) << 8); + + sint32 luma_ix = luma_x >> 8; + sint32 luma_iy = luma_y >> 8; + float luma_fx = (float)(luma_x & 255) * (1.0f / 255.0f); + float luma_fy = (float)(luma_y & 255) * (1.0f / 255.0f); + + float y0 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); + float y1 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+0, px.w, px.h) * (1.0f / 1023.0f); + float y2 = SampleV210_Y(px.data, px.pitch, luma_ix+0, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); + float y3 = SampleV210_Y(px.data, px.pitch, luma_ix+1, luma_iy+1, px.w, px.h) * (1.0f / 1023.0f); + float yt = y0 + (y1 - y0)*luma_fx; + float yb = y2 + (y3 - y2)*luma_fx; + float yr = yt + (yb - yt)*luma_fy; + + uint32 chroma_w = (px.w + 1) >> 1; + uint32 chroma_h = px.h; + sint32 chroma_x = x_256 >> 1; + sint32 chroma_y = y_256 - 128; + + if (chroma_x < 0) + chroma_x = 0; + + if (chroma_y < 0) + chroma_y = 0; + + if (chroma_x > (sint32)((chroma_w - 1) << 8)) + chroma_x = (sint32)((chroma_w - 1) << 8); + + if (chroma_y > (sint32)((chroma_h - 1) << 8)) + chroma_y = (sint32)((chroma_h - 1) << 8); + + sint32 chroma_ix = chroma_x >> 8; + sint32 chroma_iy = chroma_y >> 8; + float chroma_fx = (float)(chroma_x & 255) * (1.0f / 255.0f); + float chroma_fy = (float)(chroma_y & 255) * (1.0f / 255.0f); + + float cb0 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cb1 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cb2 = SampleV210_Cb(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cb3 = SampleV210_Cb(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cbt = cb0 + (cb1 - cb0)*chroma_fx; + float cbb = cb2 + (cb3 - cb2)*chroma_fx; + float cbr = cbt + (cbb - cbt)*chroma_fy; + + float cr0 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cr1 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+0, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cr2 = SampleV210_Cr(px.data, px.pitch, chroma_ix+0, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); + float cr3 = SampleV210_Cr(px.data, px.pitch, chroma_ix+1, chroma_iy+1, chroma_w, chroma_h) * (1.0f / 1023.0f); + float crt = cr0 + (cr1 - cr0)*chroma_fx; + float crb = cr2 + (cr3 - cr2)*chroma_fx; + float crr = crt + (crb - crt)*chroma_fy; + + uint32 ir = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 1.5960268f*crr - (222.92157f / 255.0f)); + uint32 ig = VDClampedRoundFixedToUint8Fast(1.1643836f*yr - 0.3917623f*cbr - 0.8129676f*crr + (135.57529f / 255.0f)); + uint32 ib = VDClampedRoundFixedToUint8Fast(1.1643836f*yr + 2.0172321f*cbr - (276.83585f / 255.0f)); + + return (ir << 16) + (ig << 8) + ib; + } + break; + + default: + return 0; + } +} + +uint32 VDConvertYCbCrToRGB(uint8 y0, uint8 cb0, uint8 cr0, bool use709, bool useFullRange) { + sint32 y = y0; + sint32 cb = cb0 - 128; + sint32 cr = cr0 - 128; + sint32 r; + sint32 g; + sint32 b; + + if (use709) { + if (useFullRange) { + sint32 y2 = (y << 16) + 0x8000; + r = y2 + cr * 103206; + g = y2 + cr * -30679 + cb * -12276; + b = y2 + cb * 121609; + } else { + sint32 y2 = (y - 16) * 76309 + 0x8000; + r = y2 + cr * 117489; + g = y2 + cr * -34925 + cb * -13975; + b = y2 + cb * 138438; + } + } else { + if (useFullRange) { + sint32 y2 = (y << 16) + 0x8000; + r = y2 + cr * 91181; + g = y2 + cr * -46802 + cb * -22554; + b = y2 + cb * 166130; + } else { + sint32 y2 = (y - 16) * 76309 + 0x8000; + r = y2 + cr * 104597; + g = y2 + cr * -53279 + cb * -25674; + b = y2 + cb * 132201; + } + } + + r &= ~(r >> 31); + g &= ~(g >> 31); + b &= ~(b >> 31); + r += (0xffffff - r) & ((0xffffff - r) >> 31); + g += (0xffffff - g) & ((0xffffff - g) >> 31); + b += (0xffffff - b) & ((0xffffff - b) >> 31); + + return (r & 0xff0000) + ((g & 0xff0000) >> 8) + (b >> 16); +} + +uint32 VDConvertRGBToYCbCr(uint32 c) { + return VDConvertRGBToYCbCr((uint8)(c >> 16), (uint8)(c >> 8), (uint8)c, false, false); +} + +uint32 VDConvertRGBToYCbCr(uint8 r8, uint8 g8, uint8 b8, bool use709, bool useFullRange) { + sint32 r = r8; + sint32 g = g8; + sint32 b = b8; + sint32 y; + sint32 cb; + sint32 cr; + + if (use709) { + if (useFullRange) { + y = ( 13933*r + 46871*g + 4732*b + 0x8000) >> 8; + cb = ( -7509*r - 25259*g + 32768*b + 0x808000) >> 16; + cr = ( 32768*r - 29763*g - 3005*b + 0x808000); + } else { + y = ( 11966*r + 40254*g + 4064*b + 0x108000) >> 8; + cb = ( -6596*r - 22189*g + 28784*b + 0x808000) >> 16; + cr = ( 28784*r - 26145*g - 2639*b + 0x808000); + } + } else { + if (useFullRange) { + y = ( 19595*r + 38470*g + 7471*b + 0x8000) >> 8; + cb = (-11058*r - 21710*g + 32768*b + 0x808000) >> 16; + cr = ( 32768*r - 27439*g - 5329*b + 0x808000); + } else { + y = ( 16829*r + 33039*g + 6416*b + 0x108000) >> 8; + cb = ( -9714*r - 19071*g + 28784*b + 0x808000) >> 16; + cr = ( 28784*r - 24103*g - 4681*b + 0x808000); + } + } + + return (uint8)cb + (y & 0xff00) + (cr&0xff0000); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/pixmaputils.cpp b/src/thirdparty/VirtualDub/Kasumi/source/pixmaputils.cpp index d1b74672cb6..c16e7bbc13b 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/pixmaputils.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/pixmaputils.cpp @@ -1,633 +1,633 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include - -extern VDPixmapFormatInfo const g_vdPixmapFormats[] = { - // name qchnk qw qh qwb qhb qs ab aw ah as ps - /* Null */ { "null", false, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* Pal1 */ { "Pal1", true, 8, 1, 3, 0, 1, 0, 0, 0, 0, 2 }, - /* Pal2 */ { "Pal2", true, 4, 1, 2, 0, 1, 0, 0, 0, 0, 4 }, - /* Pal4 */ { "Pal4", true, 2, 1, 1, 0, 1, 0, 0, 0, 0, 16 }, - /* Pal8 */ { "Pal8", false, 1, 1, 0, 0, 1, 0, 0, 0, 0, 256 }, - /* RGB16_555 */ { "XRGB1555", false, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0 }, - /* RGB16_565 */ { "RGB565", false, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0 }, - /* RGB24 */ { "RGB888", false, 1, 1, 0, 0, 3, 0, 0, 0, 0, 0 }, - /* RGB32 */ { "XRGB8888", false, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0 }, - /* Y8 */ { "Y8", false, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, - /* YUV422_UYVY */ { "UYVY", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV422_YUYV */ { "YUYV", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_XVYU */ { "XVYU", false, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_Planar */ { "YUV444", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, - /* YUV422_Planar */ { "YUV422", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar */ { "YUV420", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV411_Planar */ { "YUV411", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, - /* YUV410_Planar */ { "YUV410", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, - /* YUV422_Planar_Centered */ { "YUV422C", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar_Centered */ { "YUV420C", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV422_Planar_16F */ { "YUV422_16F", false, 1, 1, 0, 0, 2, 2, 1, 0, 2, 0 }, - /* V210 */ { "v210", true,24, 1, 2, 0, 64, 0, 0, 0, 1, 0 }, - /* YUV422_UYVY_709 */ { "UYVY-709", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* NV12 */ { "NV12", false, 1, 1, 0, 0, 1, 1, 1, 1, 2, 0 }, - /* Y8-FR */ { "I8", false, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0 }, - /* YUV422_YUYV_709 */ { "YUYV-709", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_Planar_709 */ { "YUV444-709", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, - /* YUV422_Planar_709 */ { "YUV422-709", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar_709 */ { "YUV420-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV411_Planar_709 */ { "YUV411-709", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, - /* YUV410_Planar_709 */ { "YUV410-709", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, - /* YUV422_UYVY_FR */ { "UYVY-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV422_YUYV_FR */ { "YUYV-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_Planar_FR */ { "YUV444-FR", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, - /* YUV422_Planar_FR */ { "YUV422-FR", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar_FR */ { "YUV420-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV411_Planar_FR */ { "YUV411-FR", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, - /* YUV410_Planar_FR */ { "YUV410-FR", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, - /* YUV422_UYVY_FR_709 */ { "UYVY-709-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV422_YUYV_FR_709 */ { "YUYV-709-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, - /* YUV444_Planar_FR_709 */ { "YUV444-709-FR", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, - /* YUV422_Planar_FR_709 */ { "YUV422-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, - /* YUV420_Planar_FR_709 */ { "YUV420-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV411_Planar_FR_709 */ { "YUV411-709-FR", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, - /* YUV410_Planar_FR_709 */ { "YUV410-709-FR", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, - /* YUV420i_Planar */ { "YUV420i", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420i_Planar_FR */ { "YUV420i-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420i_Planar_709 */ { "YUV420i-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420i_Planar_709_FR */ { "YUV420i-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420it_Planar */ { "YUV420it", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420it_Planar_FR */ { "YUV420it-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420it_Planar_709 */ { "YUV420it-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420it_Planar_709_FR */ { "YUV420it-709-FR",false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420ib_Planar */ { "YUV420ib", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420ib_Planar_FR */ { "YUV420ib-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420ib_Planar_709 */ { "YUV420ib-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, - /* YUV420ib_Planar_709_FR */ { "YUV420ib-709-FR",false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, -}; - -namespace { - void check() { - VDASSERTCT(sizeof(g_vdPixmapFormats)/sizeof(g_vdPixmapFormats[0]) == nsVDPixmap::kPixFormat_Max_Standard); - } -} - -#ifdef _DEBUG - bool VDIsValidPixmapPlane(const void *p, ptrdiff_t pitch, vdpixsize w, vdpixsize h) { - bool isvalid; - - if (pitch < 0) - isvalid = VDIsValidReadRegion((const char *)p + pitch*(h-1), (-pitch)*(h-1)+w); - else - isvalid = VDIsValidReadRegion(p, pitch*(h-1)+w); - - if (!isvalid) { - VDDEBUG("Kasumi: Invalid pixmap plane detected.\n" - " Base=%p, pitch=%d, size=%dx%d (bytes)\n", p, (int)pitch, w, h); - } - - return isvalid; - } - - bool VDAssertValidPixmap(const VDPixmap& px) { - const VDPixmapFormatInfo& info = VDPixmapGetInfo(px.format); - - if (px.format) { - if (!VDIsValidPixmapPlane(px.data, px.pitch, -(-px.w / info.qw)*info.qsize, -(-px.h >> info.qhbits))) { - VDDEBUG("Kasumi: Invalid primary plane detected in pixmap.\n" - " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); - VDASSERT(!"Kasumi: Invalid primary plane detected in pixmap.\n"); - return false; - } - - if (info.palsize) - if (!VDIsValidReadRegion(px.palette, sizeof(uint32) * info.palsize)) { - VDDEBUG("Kasumi: Invalid palette detected in pixmap.\n" - " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); - VDASSERT(!"Kasumi: Invalid palette detected in pixmap.\n"); - return false; - } - - if (info.auxbufs) { - const vdpixsize auxw = -(-px.w >> info.auxwbits); - const vdpixsize auxh = -(-px.h >> info.auxhbits); - - if (!VDIsValidPixmapPlane(px.data2, px.pitch2, auxw * info.auxsize, auxh)) { - VDDEBUG("Kasumi: Invalid Cb plane detected in pixmap.\n" - " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); - VDASSERT(!"Kasumi: Invalid Cb plane detected in pixmap.\n"); - return false; - } - - if (info.auxbufs > 2) { - if (!VDIsValidPixmapPlane(px.data3, px.pitch3, auxw * info.auxsize, auxh)) { - VDDEBUG("Kasumi: Invalid Cr plane detected in pixmap.\n" - " Pixmap info: format=%d, dimensions=%dx%d\n", px.format, px.w, px.h); - VDASSERT(!"Kasumi: Invalid Cr plane detected in pixmap.\n"); - return false; - } - } - } - } - - return true; - } -#endif - -VDPixmap VDPixmapOffset(const VDPixmap& src, vdpixpos x, vdpixpos y) { - VDPixmap temp(src); - const VDPixmapFormatInfo& info = VDPixmapGetInfo(temp.format); - - if (info.qchunky) { - x = (x + info.qw - 1) / info.qw; - y >>= info.qhbits; - } - - switch(info.auxbufs) { - case 2: - temp.data3 = (char *)temp.data3 + (x >> info.auxwbits)*info.auxsize + (y >> info.auxhbits)*temp.pitch3; - case 1: - temp.data2 = (char *)temp.data2 + (x >> info.auxwbits)*info.auxsize + (y >> info.auxhbits)*temp.pitch2; - case 0: - temp.data = (char *)temp.data + x*info.qsize + y*temp.pitch; - } - - return temp; -} - -VDPixmapLayout VDPixmapLayoutOffset(const VDPixmapLayout& src, vdpixpos x, vdpixpos y) { - VDPixmapLayout temp(src); - const VDPixmapFormatInfo& info = VDPixmapGetInfo(temp.format); - - if (info.qchunky) { - x = (x + info.qw - 1) / info.qw; - y = -(-y >> info.qhbits); - } - - switch(info.auxbufs) { - case 2: - temp.data3 += -(-x >> info.auxwbits)*info.auxsize + -(-y >> info.auxhbits)*temp.pitch3; - case 1: - temp.data2 += -(-x >> info.auxwbits)*info.auxsize + -(-y >> info.auxhbits)*temp.pitch2; - case 0: - temp.data += x*info.qsize + y*temp.pitch; - } - - return temp; -} - -uint32 VDPixmapCreateLinearLayout(VDPixmapLayout& layout, int format, vdpixsize w, vdpixsize h, int alignment) { - const ptrdiff_t alignmask = alignment - 1; - - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(format); - sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-h >> srcinfo.qhbits); - sint32 subw = -(-w >> srcinfo.auxwbits); - sint32 subh = -(-h >> srcinfo.auxhbits); - sint32 auxsize = srcinfo.auxsize; - - ptrdiff_t mainpitch = (srcinfo.qsize * qw + alignmask) & ~alignmask; - size_t mainsize = mainpitch * qh; - - layout.data = 0; - layout.pitch = mainpitch; - layout.palette = NULL; - layout.data2 = 0; - layout.pitch2 = 0; - layout.data3 = 0; - layout.pitch3 = 0; - layout.w = w; - layout.h = h; - layout.format = format; - - if (srcinfo.auxbufs >= 1) { - ptrdiff_t subpitch = (subw * auxsize + alignmask) & ~alignmask; - size_t subsize = subpitch * subh; - - layout.data2 = mainsize; - layout.pitch2 = subpitch; - mainsize += subsize; - - if (srcinfo.auxbufs >= 2) { - layout.data3 = mainsize; - layout.pitch3 = subpitch; - mainsize += subsize; - } - } - - return mainsize; -} - -void VDPixmapFlipV(VDPixmap& px) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(px.format); - sint32 w = px.w; - sint32 h = px.h; - sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-h >> srcinfo.qhbits); - sint32 subh = -(-h >> srcinfo.auxhbits); - - vdptrstep(px.data, px.pitch * (qh - 1)); - px.pitch = -px.pitch; - - if (srcinfo.auxbufs >= 1) { - vdptrstep(px.data2, px.pitch2 * (subh - 1)); - px.pitch2 = -px.pitch2; - - if (srcinfo.auxbufs >= 2) { - vdptrstep(px.data3, px.pitch3 * (subh - 1)); - px.pitch3 = -px.pitch3; - } - } -} - -void VDPixmapLayoutFlipV(VDPixmapLayout& layout) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); - sint32 w = layout.w; - sint32 h = layout.h; - sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-h >> srcinfo.qhbits); - sint32 subh = -(-h >> srcinfo.auxhbits); - - layout.data += layout.pitch * (qh - 1); - layout.pitch = -layout.pitch; - - if (srcinfo.auxbufs >= 1) { - layout.data2 += layout.pitch2 * (subh - 1); - layout.pitch2 = -layout.pitch2; - - if (srcinfo.auxbufs >= 2) { - layout.data3 += layout.pitch3 * (subh - 1); - layout.pitch3 = -layout.pitch3; - } - } -} - -uint32 VDPixmapLayoutGetMinSize(const VDPixmapLayout& layout) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); - sint32 w = layout.w; - sint32 h = layout.h; - sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-h >> srcinfo.qhbits); - sint32 subh = -(-h >> srcinfo.auxhbits); - - uint32 limit = layout.data; - if (layout.pitch >= 0) - limit += layout.pitch * qh; - else - limit -= layout.pitch; - - if (srcinfo.auxbufs >= 1) { - uint32 limit2 = layout.data2; - - if (layout.pitch2 >= 0) - limit2 += layout.pitch2 * subh; - else - limit2 -= layout.pitch2; - - if (limit < limit2) - limit = limit2; - - if (srcinfo.auxbufs >= 2) { - uint32 limit3 = layout.data3; - - if (layout.pitch3 >= 0) - limit3 += layout.pitch3 * subh; - else - limit3 -= layout.pitch3; - - if (limit < limit3) - limit = limit3; - } - } - - return limit; -} - -VDPixmap VDPixmapExtractField(const VDPixmap& src, bool field2) { - VDPixmap px(src); - - if (field2) { - const VDPixmapFormatInfo& info = VDPixmapGetInfo(px.format); - - if (px.data) { - if (info.qh == 1) - vdptrstep(px.data, px.pitch); - - if (!info.auxhbits || - src.format == nsVDPixmap::kPixFormat_YUV420i_Planar || - src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_FR || - src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_709 || - src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR) { - - vdptrstep(px.data2, px.pitch2); - vdptrstep(px.data3, px.pitch3); - } - } - } - - switch(src.format) { - case nsVDPixmap::kPixFormat_YUV420i_Planar: - if (field2) - px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar; - else - px.format = nsVDPixmap::kPixFormat_YUV420it_Planar; - break; - - case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: - if (field2) - px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_FR; - else - px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_FR; - break; - - case nsVDPixmap::kPixFormat_YUV420i_Planar_709: - if (field2) - px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_709; - else - px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_709; - break; - - case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: - if (field2) - px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR; - else - px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR; - break; - } - - px.h >>= 1; - px.pitch += px.pitch; - px.pitch2 += px.pitch2; - px.pitch3 += px.pitch3; - return px; -} - -/////////////////////////////////////////////////////////////////////////// - -VDPixmapBuffer::VDPixmapBuffer(const VDPixmap& src) - : mpBuffer(NULL) - , mLinearSize(0) -{ - assign(src); -} - -VDPixmapBuffer::VDPixmapBuffer(const VDPixmapBuffer& src) - : mpBuffer(NULL) - , mLinearSize(0) -{ - assign(src); -} - -VDPixmapBuffer::VDPixmapBuffer(const VDPixmapLayout& layout) { - init(layout); -} - -VDPixmapBuffer::~VDPixmapBuffer() { -#ifdef _DEBUG - validate(); -#endif - - delete[] mpBuffer; -} - -void VDPixmapBuffer::init(sint32 width, sint32 height, int f) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(f); - sint32 qw = (width + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-height >> srcinfo.qhbits); - sint32 subw = -(-width >> srcinfo.auxwbits); - sint32 subh = -(-height >> srcinfo.auxhbits); - ptrdiff_t mainpitch = (srcinfo.qsize * qw + 15) & ~15; - ptrdiff_t subpitch = (srcinfo.auxsize * subw + 15) & ~15; - uint64 mainsize = (uint64)mainpitch * qh; - uint64 subsize = (uint64)subpitch * subh; - uint64 totalsize64 = mainsize + subsize*srcinfo.auxbufs + 4 * srcinfo.palsize; - -#ifdef _DEBUG - totalsize64 += 28; -#endif - - // reject huge allocations - if (totalsize64 > (size_t)-1 - 4096) - throw MyMemoryError(); - - size_t totalsize = (uint32)totalsize64; - - if (mLinearSize != totalsize) { - clear(); - mpBuffer = new_nothrow char[totalsize + 15]; - if (!mpBuffer) - throw MyMemoryError(totalsize + 15); - mLinearSize = totalsize; - } - - char *p = mpBuffer + (-(int)(uintptr)mpBuffer & 15); - -#ifdef _DEBUG - *(uint32 *)p = totalsize; - for(int i=0; i<12; ++i) - p[4+i] = (char)(0xa0 + i); - - p += 16; -#endif - - data = p; - pitch = mainpitch; - p += mainsize; - - palette = NULL; - data2 = NULL; - pitch2 = NULL; - data3 = NULL; - pitch3 = NULL; - w = width; - h = height; - format = f; - - if (srcinfo.auxbufs >= 1) { - data2 = p; - pitch2 = subpitch; - p += subsize; - } - - if (srcinfo.auxbufs >= 2) { - data3 = p; - pitch3 = subpitch; - p += subsize; - } - - if (srcinfo.palsize) { - palette = (const uint32 *)p; - p += srcinfo.palsize * 4; - } - -#ifdef _DEBUG - for(int j=0; j<12; ++j) - p[j] = (char)(0xb0 + j); -#endif -} - -void VDPixmapBuffer::init(const VDPixmapLayout& layout, uint32 additionalPadding) { - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); - sint32 qw = (layout.w + srcinfo.qw - 1) / srcinfo.qw; - sint32 qh = -(-layout.h >> srcinfo.qhbits); - sint32 subw = -(-layout.w >> srcinfo.auxwbits); - sint32 subh = -(-layout.h >> srcinfo.auxhbits); - - sint64 mino=0, maxo=0; - - if (layout.pitch < 0) { - mino = std::min(mino, layout.data + (sint64)layout.pitch * (qh-1)); - maxo = std::max(maxo, layout.data - (sint64)layout.pitch); - } else { - mino = std::min(mino, layout.data); - maxo = std::max(maxo, layout.data + (sint64)layout.pitch*qh); - } - - if (srcinfo.auxbufs >= 1) { - if (layout.pitch2 < 0) { - mino = std::min(mino, layout.data2 + (sint64)layout.pitch2 * (subh-1)); - maxo = std::max(maxo, layout.data2 - (sint64)layout.pitch2); - } else { - mino = std::min(mino, layout.data2); - maxo = std::max(maxo, layout.data2 + (sint64)layout.pitch2*subh); - } - - if (srcinfo.auxbufs >= 2) { - if (layout.pitch3 < 0) { - mino = std::min(mino, layout.data3 + (sint64)layout.pitch3 * (subh-1)); - maxo = std::max(maxo, layout.data3 - (sint64)layout.pitch3); - } else { - mino = std::min(mino, layout.data3); - maxo = std::max(maxo, layout.data3 + (sint64)layout.pitch3*subh); - } - } - } - - sint64 linsize64 = ((maxo - mino + 3) & ~(uint64)3); - - sint64 totalsize64 = linsize64 + 4*srcinfo.palsize + additionalPadding; - -#ifdef _DEBUG - totalsize64 += 28; -#endif - - // reject huge allocations - if (totalsize64 > (size_t)-1 - 4096) - throw MyMemoryError(); - - size_t totalsize = (uint32)totalsize64; - ptrdiff_t linsize = (uint32)linsize64; - - if (mLinearSize != totalsize) { - clear(); - mpBuffer = new_nothrow char[totalsize + 15]; - if (!mpBuffer) - throw MyMemoryError(totalsize + 15); - mLinearSize = totalsize; - } - - char *p = mpBuffer + (-(int)(uintptr)mpBuffer & 15); - -#ifdef _DEBUG - *(uint32 *)p = totalsize - 28; - for(int i=0; i<12; ++i) - p[4+i] = (char)(0xa0 + i); - - p += 16; -#endif - - w = layout.w; - h = layout.h; - format = layout.format; - data = p + layout.data - mino; - data2 = p + layout.data2 - mino; - data3 = p + layout.data3 - mino; - pitch = layout.pitch; - pitch2 = layout.pitch2; - pitch3 = layout.pitch3; - palette = NULL; - - if (srcinfo.palsize) { - palette = (const uint32 *)(p + linsize); - - if (layout.palette) - memcpy((void *)palette, layout.palette, 4*srcinfo.palsize); - } - -#ifdef _DEBUG - for(int j=0; j<12; ++j) - p[totalsize + j - 28] = (char)(0xb0 + j); -#endif - - VDAssertValidPixmap(*this); -} - -void VDPixmapBuffer::assign(const VDPixmap& src) { - if (!src.format) { - delete[] mpBuffer; - mpBuffer = NULL; - data = NULL; - format = 0; - } else { - init(src.w, src.h, src.format); - - const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); - int qw = (src.w + srcinfo.qw - 1) / srcinfo.qw; - int qh = -(-src.h >> srcinfo.qhbits); - int subw = -(-src.w >> srcinfo.auxwbits); - int subh = -(-src.h >> srcinfo.auxhbits); - - if (srcinfo.palsize) - memcpy((void *)palette, src.palette, 4 * srcinfo.palsize); - - switch(srcinfo.auxbufs) { - case 2: - VDMemcpyRect(data3, pitch3, src.data3, src.pitch3, subw, subh); - case 1: - VDMemcpyRect(data2, pitch2, src.data2, src.pitch2, subw, subh); - case 0: - VDMemcpyRect(data, pitch, src.data, src.pitch, qw * srcinfo.qsize, qh); - } - } -} - -void VDPixmapBuffer::swap(VDPixmapBuffer& dst) { - std::swap(mpBuffer, dst.mpBuffer); - std::swap(mLinearSize, dst.mLinearSize); - std::swap(static_cast(*this), static_cast(dst)); -} - -#ifdef _DEBUG -void VDPixmapBuffer::validate() { - if (mpBuffer) { - char *p = (char *)(((uintptr)mpBuffer + 15) & ~(uintptr)15); - - // verify head bytes - for(int i=0; i<12; ++i) - if (p[i+4] != (char)(0xa0 + i)) - VDASSERT(!"VDPixmapBuffer: Buffer underflow detected.\n"); - - // verify tail bytes - for(int j=0; j<12; ++j) - if (p[mLinearSize - 12 + j] != (char)(0xb0 + j)) - VDASSERT(!"VDPixmapBuffer: Buffer overflow detected.\n"); - } -} -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include + +extern VDPixmapFormatInfo const g_vdPixmapFormats[] = { + // name qchnk qw qh qwb qhb qs ab aw ah as ps + /* Null */ { "null", false, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* Pal1 */ { "Pal1", true, 8, 1, 3, 0, 1, 0, 0, 0, 0, 2 }, + /* Pal2 */ { "Pal2", true, 4, 1, 2, 0, 1, 0, 0, 0, 0, 4 }, + /* Pal4 */ { "Pal4", true, 2, 1, 1, 0, 1, 0, 0, 0, 0, 16 }, + /* Pal8 */ { "Pal8", false, 1, 1, 0, 0, 1, 0, 0, 0, 0, 256 }, + /* RGB16_555 */ { "XRGB1555", false, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0 }, + /* RGB16_565 */ { "RGB565", false, 1, 1, 0, 0, 2, 0, 0, 0, 0, 0 }, + /* RGB24 */ { "RGB888", false, 1, 1, 0, 0, 3, 0, 0, 0, 0, 0 }, + /* RGB32 */ { "XRGB8888", false, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0 }, + /* Y8 */ { "Y8", false, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, + /* YUV422_UYVY */ { "UYVY", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV422_YUYV */ { "YUYV", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_XVYU */ { "XVYU", false, 1, 1, 0, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_Planar */ { "YUV444", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, + /* YUV422_Planar */ { "YUV422", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar */ { "YUV420", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV411_Planar */ { "YUV411", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, + /* YUV410_Planar */ { "YUV410", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, + /* YUV422_Planar_Centered */ { "YUV422C", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar_Centered */ { "YUV420C", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV422_Planar_16F */ { "YUV422_16F", false, 1, 1, 0, 0, 2, 2, 1, 0, 2, 0 }, + /* V210 */ { "v210", true,24, 1, 2, 0, 64, 0, 0, 0, 1, 0 }, + /* YUV422_UYVY_709 */ { "UYVY-709", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* NV12 */ { "NV12", false, 1, 1, 0, 0, 1, 1, 1, 1, 2, 0 }, + /* Y8-FR */ { "I8", false, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0 }, + /* YUV422_YUYV_709 */ { "YUYV-709", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_Planar_709 */ { "YUV444-709", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, + /* YUV422_Planar_709 */ { "YUV422-709", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar_709 */ { "YUV420-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV411_Planar_709 */ { "YUV411-709", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, + /* YUV410_Planar_709 */ { "YUV410-709", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, + /* YUV422_UYVY_FR */ { "UYVY-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV422_YUYV_FR */ { "YUYV-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_Planar_FR */ { "YUV444-FR", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, + /* YUV422_Planar_FR */ { "YUV422-FR", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar_FR */ { "YUV420-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV411_Planar_FR */ { "YUV411-FR", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, + /* YUV410_Planar_FR */ { "YUV410-FR", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, + /* YUV422_UYVY_FR_709 */ { "UYVY-709-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV422_YUYV_FR_709 */ { "YUYV-709-FR", true, 2, 1, 1, 0, 4, 0, 0, 0, 0, 0 }, + /* YUV444_Planar_FR_709 */ { "YUV444-709-FR", false, 1, 1, 0, 0, 1, 2, 0, 0, 1, 0 }, + /* YUV422_Planar_FR_709 */ { "YUV422-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 0, 1, 0 }, + /* YUV420_Planar_FR_709 */ { "YUV420-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV411_Planar_FR_709 */ { "YUV411-709-FR", false, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0 }, + /* YUV410_Planar_FR_709 */ { "YUV410-709-FR", false, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0 }, + /* YUV420i_Planar */ { "YUV420i", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420i_Planar_FR */ { "YUV420i-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420i_Planar_709 */ { "YUV420i-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420i_Planar_709_FR */ { "YUV420i-709-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420it_Planar */ { "YUV420it", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420it_Planar_FR */ { "YUV420it-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420it_Planar_709 */ { "YUV420it-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420it_Planar_709_FR */ { "YUV420it-709-FR",false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420ib_Planar */ { "YUV420ib", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420ib_Planar_FR */ { "YUV420ib-FR", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420ib_Planar_709 */ { "YUV420ib-709", false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, + /* YUV420ib_Planar_709_FR */ { "YUV420ib-709-FR",false, 1, 1, 0, 0, 1, 2, 1, 1, 1, 0 }, +}; + +namespace { + void check() { + VDASSERTCT(sizeof(g_vdPixmapFormats)/sizeof(g_vdPixmapFormats[0]) == nsVDPixmap::kPixFormat_Max_Standard); + } +} + +#ifdef _DEBUG + bool VDIsValidPixmapPlane(const void *p, ptrdiff_t pitch, vdpixsize w, vdpixsize h) { + bool isvalid; + + if (pitch < 0) + isvalid = VDIsValidReadRegion((const char *)p + pitch*(h-1), (-pitch)*(h-1)+w); + else + isvalid = VDIsValidReadRegion(p, pitch*(h-1)+w); + + if (!isvalid) { + VDDEBUG("Kasumi: Invalid pixmap plane detected.\n" + " Base=%p, pitch=%d, size=%dx%d (bytes)\n", p, (int)pitch, w, h); + } + + return isvalid; + } + + bool VDAssertValidPixmap(const VDPixmap& px) { + const VDPixmapFormatInfo& info = VDPixmapGetInfo(px.format); + + if (px.format) { + if (!VDIsValidPixmapPlane(px.data, px.pitch, -(-px.w / info.qw)*info.qsize, -(-px.h >> info.qhbits))) { + VDDEBUG("Kasumi: Invalid primary plane detected in pixmap.\n" + " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); + VDASSERT(!"Kasumi: Invalid primary plane detected in pixmap.\n"); + return false; + } + + if (info.palsize) + if (!VDIsValidReadRegion(px.palette, sizeof(uint32) * info.palsize)) { + VDDEBUG("Kasumi: Invalid palette detected in pixmap.\n" + " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); + VDASSERT(!"Kasumi: Invalid palette detected in pixmap.\n"); + return false; + } + + if (info.auxbufs) { + const vdpixsize auxw = -(-px.w >> info.auxwbits); + const vdpixsize auxh = -(-px.h >> info.auxhbits); + + if (!VDIsValidPixmapPlane(px.data2, px.pitch2, auxw * info.auxsize, auxh)) { + VDDEBUG("Kasumi: Invalid Cb plane detected in pixmap.\n" + " Pixmap info: format=%d (%s), dimensions=%dx%d\n", px.format, info.name, px.w, px.h); + VDASSERT(!"Kasumi: Invalid Cb plane detected in pixmap.\n"); + return false; + } + + if (info.auxbufs > 2) { + if (!VDIsValidPixmapPlane(px.data3, px.pitch3, auxw * info.auxsize, auxh)) { + VDDEBUG("Kasumi: Invalid Cr plane detected in pixmap.\n" + " Pixmap info: format=%d, dimensions=%dx%d\n", px.format, px.w, px.h); + VDASSERT(!"Kasumi: Invalid Cr plane detected in pixmap.\n"); + return false; + } + } + } + } + + return true; + } +#endif + +VDPixmap VDPixmapOffset(const VDPixmap& src, vdpixpos x, vdpixpos y) { + VDPixmap temp(src); + const VDPixmapFormatInfo& info = VDPixmapGetInfo(temp.format); + + if (info.qchunky) { + x = (x + info.qw - 1) / info.qw; + y >>= info.qhbits; + } + + switch(info.auxbufs) { + case 2: + temp.data3 = (char *)temp.data3 + (x >> info.auxwbits)*info.auxsize + (y >> info.auxhbits)*temp.pitch3; + case 1: + temp.data2 = (char *)temp.data2 + (x >> info.auxwbits)*info.auxsize + (y >> info.auxhbits)*temp.pitch2; + case 0: + temp.data = (char *)temp.data + x*info.qsize + y*temp.pitch; + } + + return temp; +} + +VDPixmapLayout VDPixmapLayoutOffset(const VDPixmapLayout& src, vdpixpos x, vdpixpos y) { + VDPixmapLayout temp(src); + const VDPixmapFormatInfo& info = VDPixmapGetInfo(temp.format); + + if (info.qchunky) { + x = (x + info.qw - 1) / info.qw; + y = -(-y >> info.qhbits); + } + + switch(info.auxbufs) { + case 2: + temp.data3 += -(-x >> info.auxwbits)*info.auxsize + -(-y >> info.auxhbits)*temp.pitch3; + case 1: + temp.data2 += -(-x >> info.auxwbits)*info.auxsize + -(-y >> info.auxhbits)*temp.pitch2; + case 0: + temp.data += x*info.qsize + y*temp.pitch; + } + + return temp; +} + +uint32 VDPixmapCreateLinearLayout(VDPixmapLayout& layout, int format, vdpixsize w, vdpixsize h, int alignment) { + const ptrdiff_t alignmask = alignment - 1; + + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(format); + sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-h >> srcinfo.qhbits); + sint32 subw = -(-w >> srcinfo.auxwbits); + sint32 subh = -(-h >> srcinfo.auxhbits); + sint32 auxsize = srcinfo.auxsize; + + ptrdiff_t mainpitch = (srcinfo.qsize * qw + alignmask) & ~alignmask; + size_t mainsize = mainpitch * qh; + + layout.data = 0; + layout.pitch = mainpitch; + layout.palette = NULL; + layout.data2 = 0; + layout.pitch2 = 0; + layout.data3 = 0; + layout.pitch3 = 0; + layout.w = w; + layout.h = h; + layout.format = format; + + if (srcinfo.auxbufs >= 1) { + ptrdiff_t subpitch = (subw * auxsize + alignmask) & ~alignmask; + size_t subsize = subpitch * subh; + + layout.data2 = mainsize; + layout.pitch2 = subpitch; + mainsize += subsize; + + if (srcinfo.auxbufs >= 2) { + layout.data3 = mainsize; + layout.pitch3 = subpitch; + mainsize += subsize; + } + } + + return mainsize; +} + +void VDPixmapFlipV(VDPixmap& px) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(px.format); + sint32 w = px.w; + sint32 h = px.h; + sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-h >> srcinfo.qhbits); + sint32 subh = -(-h >> srcinfo.auxhbits); + + vdptrstep(px.data, px.pitch * (qh - 1)); + px.pitch = -px.pitch; + + if (srcinfo.auxbufs >= 1) { + vdptrstep(px.data2, px.pitch2 * (subh - 1)); + px.pitch2 = -px.pitch2; + + if (srcinfo.auxbufs >= 2) { + vdptrstep(px.data3, px.pitch3 * (subh - 1)); + px.pitch3 = -px.pitch3; + } + } +} + +void VDPixmapLayoutFlipV(VDPixmapLayout& layout) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); + sint32 w = layout.w; + sint32 h = layout.h; + sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-h >> srcinfo.qhbits); + sint32 subh = -(-h >> srcinfo.auxhbits); + + layout.data += layout.pitch * (qh - 1); + layout.pitch = -layout.pitch; + + if (srcinfo.auxbufs >= 1) { + layout.data2 += layout.pitch2 * (subh - 1); + layout.pitch2 = -layout.pitch2; + + if (srcinfo.auxbufs >= 2) { + layout.data3 += layout.pitch3 * (subh - 1); + layout.pitch3 = -layout.pitch3; + } + } +} + +uint32 VDPixmapLayoutGetMinSize(const VDPixmapLayout& layout) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); + sint32 w = layout.w; + sint32 h = layout.h; + sint32 qw = (w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-h >> srcinfo.qhbits); + sint32 subh = -(-h >> srcinfo.auxhbits); + + uint32 limit = layout.data; + if (layout.pitch >= 0) + limit += layout.pitch * qh; + else + limit -= layout.pitch; + + if (srcinfo.auxbufs >= 1) { + uint32 limit2 = layout.data2; + + if (layout.pitch2 >= 0) + limit2 += layout.pitch2 * subh; + else + limit2 -= layout.pitch2; + + if (limit < limit2) + limit = limit2; + + if (srcinfo.auxbufs >= 2) { + uint32 limit3 = layout.data3; + + if (layout.pitch3 >= 0) + limit3 += layout.pitch3 * subh; + else + limit3 -= layout.pitch3; + + if (limit < limit3) + limit = limit3; + } + } + + return limit; +} + +VDPixmap VDPixmapExtractField(const VDPixmap& src, bool field2) { + VDPixmap px(src); + + if (field2) { + const VDPixmapFormatInfo& info = VDPixmapGetInfo(px.format); + + if (px.data) { + if (info.qh == 1) + vdptrstep(px.data, px.pitch); + + if (!info.auxhbits || + src.format == nsVDPixmap::kPixFormat_YUV420i_Planar || + src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_FR || + src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_709 || + src.format == nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR) { + + vdptrstep(px.data2, px.pitch2); + vdptrstep(px.data3, px.pitch3); + } + } + } + + switch(src.format) { + case nsVDPixmap::kPixFormat_YUV420i_Planar: + if (field2) + px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar; + else + px.format = nsVDPixmap::kPixFormat_YUV420it_Planar; + break; + + case nsVDPixmap::kPixFormat_YUV420i_Planar_FR: + if (field2) + px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_FR; + else + px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_FR; + break; + + case nsVDPixmap::kPixFormat_YUV420i_Planar_709: + if (field2) + px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_709; + else + px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_709; + break; + + case nsVDPixmap::kPixFormat_YUV420i_Planar_709_FR: + if (field2) + px.format = nsVDPixmap::kPixFormat_YUV420ib_Planar_709_FR; + else + px.format = nsVDPixmap::kPixFormat_YUV420it_Planar_709_FR; + break; + } + + px.h >>= 1; + px.pitch += px.pitch; + px.pitch2 += px.pitch2; + px.pitch3 += px.pitch3; + return px; +} + +/////////////////////////////////////////////////////////////////////////// + +VDPixmapBuffer::VDPixmapBuffer(const VDPixmap& src) + : mpBuffer(NULL) + , mLinearSize(0) +{ + assign(src); +} + +VDPixmapBuffer::VDPixmapBuffer(const VDPixmapBuffer& src) + : mpBuffer(NULL) + , mLinearSize(0) +{ + assign(src); +} + +VDPixmapBuffer::VDPixmapBuffer(const VDPixmapLayout& layout) { + init(layout); +} + +VDPixmapBuffer::~VDPixmapBuffer() { +#ifdef _DEBUG + validate(); +#endif + + delete[] mpBuffer; +} + +void VDPixmapBuffer::init(sint32 width, sint32 height, int f) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(f); + sint32 qw = (width + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-height >> srcinfo.qhbits); + sint32 subw = -(-width >> srcinfo.auxwbits); + sint32 subh = -(-height >> srcinfo.auxhbits); + ptrdiff_t mainpitch = (srcinfo.qsize * qw + 15) & ~15; + ptrdiff_t subpitch = (srcinfo.auxsize * subw + 15) & ~15; + uint64 mainsize = (uint64)mainpitch * qh; + uint64 subsize = (uint64)subpitch * subh; + uint64 totalsize64 = mainsize + subsize*srcinfo.auxbufs + 4 * srcinfo.palsize; + +#ifdef _DEBUG + totalsize64 += 28; +#endif + + // reject huge allocations + if (totalsize64 > (size_t)-1 - 4096) + throw MyMemoryError(); + + size_t totalsize = (uint32)totalsize64; + + if (mLinearSize != totalsize) { + clear(); + mpBuffer = new_nothrow char[totalsize + 15]; + if (!mpBuffer) + throw MyMemoryError(totalsize + 15); + mLinearSize = totalsize; + } + + char *p = mpBuffer + (-(int)(uintptr)mpBuffer & 15); + +#ifdef _DEBUG + *(uint32 *)p = totalsize; + for(int i=0; i<12; ++i) + p[4+i] = (char)(0xa0 + i); + + p += 16; +#endif + + data = p; + pitch = mainpitch; + p += mainsize; + + palette = NULL; + data2 = NULL; + pitch2 = NULL; + data3 = NULL; + pitch3 = NULL; + w = width; + h = height; + format = f; + + if (srcinfo.auxbufs >= 1) { + data2 = p; + pitch2 = subpitch; + p += subsize; + } + + if (srcinfo.auxbufs >= 2) { + data3 = p; + pitch3 = subpitch; + p += subsize; + } + + if (srcinfo.palsize) { + palette = (const uint32 *)p; + p += srcinfo.palsize * 4; + } + +#ifdef _DEBUG + for(int j=0; j<12; ++j) + p[j] = (char)(0xb0 + j); +#endif +} + +void VDPixmapBuffer::init(const VDPixmapLayout& layout, uint32 additionalPadding) { + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(layout.format); + sint32 qw = (layout.w + srcinfo.qw - 1) / srcinfo.qw; + sint32 qh = -(-layout.h >> srcinfo.qhbits); + sint32 subw = -(-layout.w >> srcinfo.auxwbits); + sint32 subh = -(-layout.h >> srcinfo.auxhbits); + + sint64 mino=0, maxo=0; + + if (layout.pitch < 0) { + mino = std::min(mino, layout.data + (sint64)layout.pitch * (qh-1)); + maxo = std::max(maxo, layout.data - (sint64)layout.pitch); + } else { + mino = std::min(mino, layout.data); + maxo = std::max(maxo, layout.data + (sint64)layout.pitch*qh); + } + + if (srcinfo.auxbufs >= 1) { + if (layout.pitch2 < 0) { + mino = std::min(mino, layout.data2 + (sint64)layout.pitch2 * (subh-1)); + maxo = std::max(maxo, layout.data2 - (sint64)layout.pitch2); + } else { + mino = std::min(mino, layout.data2); + maxo = std::max(maxo, layout.data2 + (sint64)layout.pitch2*subh); + } + + if (srcinfo.auxbufs >= 2) { + if (layout.pitch3 < 0) { + mino = std::min(mino, layout.data3 + (sint64)layout.pitch3 * (subh-1)); + maxo = std::max(maxo, layout.data3 - (sint64)layout.pitch3); + } else { + mino = std::min(mino, layout.data3); + maxo = std::max(maxo, layout.data3 + (sint64)layout.pitch3*subh); + } + } + } + + sint64 linsize64 = ((maxo - mino + 3) & ~(uint64)3); + + sint64 totalsize64 = linsize64 + 4*srcinfo.palsize + additionalPadding; + +#ifdef _DEBUG + totalsize64 += 28; +#endif + + // reject huge allocations + if (totalsize64 > (size_t)-1 - 4096) + throw MyMemoryError(); + + size_t totalsize = (uint32)totalsize64; + ptrdiff_t linsize = (uint32)linsize64; + + if (mLinearSize != totalsize) { + clear(); + mpBuffer = new_nothrow char[totalsize + 15]; + if (!mpBuffer) + throw MyMemoryError(totalsize + 15); + mLinearSize = totalsize; + } + + char *p = mpBuffer + (-(int)(uintptr)mpBuffer & 15); + +#ifdef _DEBUG + *(uint32 *)p = totalsize - 28; + for(int i=0; i<12; ++i) + p[4+i] = (char)(0xa0 + i); + + p += 16; +#endif + + w = layout.w; + h = layout.h; + format = layout.format; + data = p + layout.data - mino; + data2 = p + layout.data2 - mino; + data3 = p + layout.data3 - mino; + pitch = layout.pitch; + pitch2 = layout.pitch2; + pitch3 = layout.pitch3; + palette = NULL; + + if (srcinfo.palsize) { + palette = (const uint32 *)(p + linsize); + + if (layout.palette) + memcpy((void *)palette, layout.palette, 4*srcinfo.palsize); + } + +#ifdef _DEBUG + for(int j=0; j<12; ++j) + p[totalsize + j - 28] = (char)(0xb0 + j); +#endif + + VDAssertValidPixmap(*this); +} + +void VDPixmapBuffer::assign(const VDPixmap& src) { + if (!src.format) { + delete[] mpBuffer; + mpBuffer = NULL; + data = NULL; + format = 0; + } else { + init(src.w, src.h, src.format); + + const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format); + int qw = (src.w + srcinfo.qw - 1) / srcinfo.qw; + int qh = -(-src.h >> srcinfo.qhbits); + int subw = -(-src.w >> srcinfo.auxwbits); + int subh = -(-src.h >> srcinfo.auxhbits); + + if (srcinfo.palsize) + memcpy((void *)palette, src.palette, 4 * srcinfo.palsize); + + switch(srcinfo.auxbufs) { + case 2: + VDMemcpyRect(data3, pitch3, src.data3, src.pitch3, subw, subh); + case 1: + VDMemcpyRect(data2, pitch2, src.data2, src.pitch2, subw, subh); + case 0: + VDMemcpyRect(data, pitch, src.data, src.pitch, qw * srcinfo.qsize, qh); + } + } +} + +void VDPixmapBuffer::swap(VDPixmapBuffer& dst) { + std::swap(mpBuffer, dst.mpBuffer); + std::swap(mLinearSize, dst.mLinearSize); + std::swap(static_cast(*this), static_cast(dst)); +} + +#ifdef _DEBUG +void VDPixmapBuffer::validate() { + if (mpBuffer) { + char *p = (char *)(((uintptr)mpBuffer + 15) & ~(uintptr)15); + + // verify head bytes + for(int i=0; i<12; ++i) + if (p[i+4] != (char)(0xa0 + i)) + VDASSERT(!"VDPixmapBuffer: Buffer underflow detected.\n"); + + // verify tail bytes + for(int j=0; j<12; ++j) + if (p[mLinearSize - 12 + j] != (char)(0xb0 + j)) + VDASSERT(!"VDPixmapBuffer: Buffer overflow detected.\n"); + } +} +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/source/region.cpp b/src/thirdparty/VirtualDub/Kasumi/source/region.cpp index ea6cd638050..b8b607ef079 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/region.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/region.cpp @@ -1,1375 +1,1375 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include - -void VDPixmapRegion::clear() { - mSpans.clear(); -} - -void VDPixmapRegion::swap(VDPixmapRegion& x) { - mSpans.swap(x.mSpans); - std::swap(mBounds, x.mBounds); -} - -VDPixmapPathRasterizer::VDPixmapPathRasterizer() - : mpEdgeBlocks(NULL) - , mpFreeEdgeBlocks(NULL) - , mEdgeBlockIdx(kEdgeBlockMax) - , mpScanBuffer(NULL) -{ - ClearScanBuffer(); -} - -VDPixmapPathRasterizer::VDPixmapPathRasterizer(const VDPixmapPathRasterizer&) - : mpEdgeBlocks(NULL) - , mpFreeEdgeBlocks(NULL) - , mEdgeBlockIdx(kEdgeBlockMax) - , mpScanBuffer(NULL) -{ - ClearScanBuffer(); -} - -VDPixmapPathRasterizer::~VDPixmapPathRasterizer() { - Clear(); - FreeEdgeLists(); -} - -VDPixmapPathRasterizer& VDPixmapPathRasterizer::operator=(const VDPixmapPathRasterizer&) { - return *this; -} - -void VDPixmapPathRasterizer::Clear() { - ClearEdgeList(); - ClearScanBuffer(); -} - -void VDPixmapPathRasterizer::QuadraticBezier(const vdint2 *pts) { - int x0 = pts[0].x; - int x1 = pts[1].x; - int x2 = pts[2].x; - int y0 = pts[0].y; - int y1 = pts[1].y; - int y2 = pts[2].y; - - // P = (1-t)^2*P0 + 2t(1-t)*P1 + t^2*P2 - // P = (1-2t+t^2)P0 + 2(t-t^2)P1 + t^2*P2 - // P = (P0-2P1+P2)t^2 + 2(P1-P0)t + P0 - - int cx2 = x0-2*x1+x2; - int cx1 = -2*x0+2*x1; - int cx0 = x0; - - int cy2 = y0-2*y1+y2; - int cy1 = -2*y0+2*y1; - int cy0 = y0; - - // This equation is from Graphics Gems I. - // - // The idea is that since we're approximating a cubic curve with lines, - // any error we incur is due to the curvature of the line, which we can - // estimate by calculating the maximum acceleration of the curve. For - // a cubic, the acceleration (second derivative) is a line, meaning that - // the absolute maximum acceleration must occur at either the beginning - // (|c2|) or the end (|c2+c3|). Our bounds here are a little more - // conservative than that, but that's okay. - // - // If the acceleration of the parametric formula is zero (c2 = c3 = 0), - // that component of the curve is linear and does not incur any error. - // If a=0 for both X and Y, the curve is a line segment and we can - // use a step size of 1. - - int maxaccel1 = abs(cy2); - int maxaccel2 = abs(cx2); - - int maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; - int h = 1; - - while(maxaccel > 8 && h < 1024) { - maxaccel >>= 2; - h += h; - } - - int lastx = x0; - int lasty = y0; - - // compute forward differences - sint64 h1 = (sint64)(0x40000000 / h) << 2; - sint64 h2 = h1/h; - - sint64 ax0 = (sint64)cx0 << 32; - sint64 ax1 = h1*(sint64)cx1 + h2*(sint64)cx2; - sint64 ax2 = 2*h2*(sint64)cx2; - - sint64 ay0 = (sint64)cy0 << 32; - sint64 ay1 = h1*(sint64)cy1 + h2*(sint64)cy2; - sint64 ay2 = 2*h2*(sint64)cy2; - - // round, not truncate - ax0 += 0x80000000; - ay0 += 0x80000000; - - do { - ax0 += ax1; - ax1 += ax2; - ay0 += ay1; - ay1 += ay2; - - int xi = (int)((uint64)ax0 >> 32); - int yi = (int)((uint64)ay0 >> 32); - - FastLine(lastx, lasty, xi, yi); - lastx = xi; - lasty = yi; - } while(--h); -} - -void VDPixmapPathRasterizer::CubicBezier(const vdint2 *pts) { - int x0 = pts[0].x; - int x1 = pts[1].x; - int x2 = pts[2].x; - int x3 = pts[3].x; - int y0 = pts[0].y; - int y1 = pts[1].y; - int y2 = pts[2].y; - int y3 = pts[3].y; - - int cx3 = - x0+3*x1-3*x2+x3; - int cx2 = 3*x0-6*x1+3*x2; - int cx1 = -3*x0+3*x1; - int cx0 = x0; - - int cy3 = - y0+3*y1-3*y2+y3; - int cy2 = 3*y0-6*y1+3*y2; - int cy1 = -3*y0+3*y1; - int cy0 = y0; - - // This equation is from Graphics Gems I. - // - // The idea is that since we're approximating a cubic curve with lines, - // any error we incur is due to the curvature of the line, which we can - // estimate by calculating the maximum acceleration of the curve. For - // a cubic, the acceleration (second derivative) is a line, meaning that - // the absolute maximum acceleration must occur at either the beginning - // (|c2|) or the end (|c2+c3|). Our bounds here are a little more - // conservative than that, but that's okay. - // - // If the acceleration of the parametric formula is zero (c2 = c3 = 0), - // that component of the curve is linear and does not incur any error. - // If a=0 for both X and Y, the curve is a line segment and we can - // use a step size of 1. - - int maxaccel1 = abs(2*cy2) + abs(6*cy3); - int maxaccel2 = abs(2*cx2) + abs(6*cx3); - - int maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; - int h = 1; - - while(maxaccel > 8 && h < 1024) { - maxaccel >>= 2; - h += h; - } - - int lastx = x0; - int lasty = y0; - - // compute forward differences - sint64 h1 = (sint64)(0x40000000 / h) << 2; - sint64 h2 = h1/h; - sint64 h3 = h2/h; - - sint64 ax0 = (sint64)cx0 << 32; - sint64 ax1 = h1*(sint64)cx1 + h2*(sint64)cx2 + h3*(sint64)cx3; - sint64 ax2 = 2*h2*(sint64)cx2 + 6*h3*(sint64)cx3; - sint64 ax3 = 6*h3*(sint64)cx3; - - sint64 ay0 = (sint64)cy0 << 32; - sint64 ay1 = h1*(sint64)cy1 + h2*(sint64)cy2 + h3*(sint64)cy3; - sint64 ay2 = 2*h2*(sint64)cy2 + 6*h3*(sint64)cy3; - sint64 ay3 = 6*h3*(sint64)cy3; - - // round, not truncate - ax0 += 0x80000000; - ay0 += 0x80000000; - - do { - ax0 += ax1; - ax1 += ax2; - ax2 += ax3; - ay0 += ay1; - ay1 += ay2; - ay2 += ay3; - - int xi = (int)((uint64)ax0 >> 32); - int yi = (int)((uint64)ay0 >> 32); - - FastLine(lastx, lasty, xi, yi); - lastx = xi; - lasty = yi; - } while(--h); -} - -void VDPixmapPathRasterizer::Line(const vdint2& pt1, const vdint2& pt2) { - FastLine(pt1.x, pt1.y, pt2.x, pt2.y); -} - -void VDPixmapPathRasterizer::FastLine(int x0, int y0, int x1, int y1) { - int flag = 1; - - if (y1 == y0) - return; - - if (y1 < y0) { - int t; - - t=x0; x0=x1; x1=t; - t=y0; y0=y1; y1=t; - flag = 0; - } - - int dy = y1-y0; - int xacc = x0<<13; - - // prestep y0 down - int iy0 = (y0+3) >> 3; - int iy1 = (y1+3) >> 3; - - if (iy0 < iy1) { - int invslope = (x1-x0)*65536/dy; - - int prestep = (4-y0) & 7; - xacc += (invslope * prestep)>>3; - - if (iy0 < mScanYMin || iy1 > mScanYMax) { - ReallocateScanBuffer(iy0, iy1); - VDASSERT(iy0 >= mScanYMin && iy1 <= mScanYMax); - } - - while(iy0 < iy1) { - int ix = (xacc+32767)>>16; - - if (mEdgeBlockIdx >= kEdgeBlockMax) { - if (mpFreeEdgeBlocks) { - EdgeBlock *newBlock = mpFreeEdgeBlocks; - mpFreeEdgeBlocks = mpFreeEdgeBlocks->next; - newBlock->next = mpEdgeBlocks; - mpEdgeBlocks = newBlock; - } else { - mpEdgeBlocks = new EdgeBlock(mpEdgeBlocks); - } - - mEdgeBlockIdx = 0; - } - - Edge& e = mpEdgeBlocks->edges[mEdgeBlockIdx]; - Scan& s = mpScanBufferBiased[iy0]; - VDASSERT(iy0 >= mScanYMin && iy0 < mScanYMax); - ++mEdgeBlockIdx; - - e.posandflag = ix*2+flag; - e.next = s.chain; - s.chain = &e; - ++s.count; - - ++iy0; - xacc += invslope; - } - } -} - -void VDPixmapPathRasterizer::ScanConvert(VDPixmapRegion& region) { - // Convert the edges to spans. We couldn't do this before because some of - // the regions may have winding numbers >+1 and it would have been a pain - // to try to adjust the spans on the fly. We use one heap to detangle - // a scanline's worth of edges from the singly-linked lists, and another - // to collect the actual scans. - vdfastvector heap; - - region.mSpans.clear(); - int xmin = INT_MAX; - int xmax = INT_MIN; - int ymin = INT_MAX; - int ymax = INT_MIN; - - for(int y=mScanYMin; ynext) - *heap1++ = ptr->posandflag; - - VDASSERT(heap1 - heap0 == flipcount); - - // Sort edge heap. Note that we conveniently made the opening edges - // one more than closing edges at the same spot, so we won't have any - // problems with abutting spans. - - std::sort(heap0, heap1); - -#if 0 - while(heap0 != heap1) { - int x = *heap0++ >> 1; - region.mSpans.push_back((y<<16) + x + 0x80008000); - region.mSpans.push_back((y<<16) + x + 0x80008001); - } - continue; -#endif - - // Trim any odd edges off, since we can never close on one. - if (flipcount & 1) - --heap1; - - // Process edges and add spans. Since we only check for a non-zero - // winding number, it doesn't matter which way the outlines go. Also, since - // the parity always flips after each edge regardless of direction, we can - // process the edges in pairs. - - size_t spanstart = region.mSpans.size(); - - int x_left; - int count = 0; - while(heap0 != heap1) { - int x = *heap0++; - - if (!count) - x_left = (x>>1); - - count += (x&1); - - x = *heap0++; - - count += (x&1); - - if (!--count) { - int x_right = (x>>1); - - if (x_right > x_left) { - region.mSpans.push_back((y<<16) + x_left + 0x80008000); - region.mSpans.push_back((y<<16) + x_right + 0x80008000); - - } - } - } - - size_t spanend = region.mSpans.size(); - - if (spanend > spanstart) { - if (ymin > y) - ymin = y; - - if (ymax < y) - ymax = y; - - int x1 = (region.mSpans[spanstart] & 0xffff) - 0x8000; - int x2 = (region.mSpans[spanend-1] & 0xffff) - 0x8000; - - if (xmin > x1) - xmin = x1; - - if (xmax < x2) - xmax = x2; - } - } - - if (xmax > xmin) { - region.mBounds.set(xmin, ymin, xmax, ymax); - } else { - region.mBounds.set(0, 0, 0, 0); - } - - // Dump the edge and scan buffers, since we no longer need them. - ClearEdgeList(); - ClearScanBuffer(); -} - -void VDPixmapPathRasterizer::ClearEdgeList() { - if (mpEdgeBlocks) { - EdgeBlock *block = mpEdgeBlocks; - - while(EdgeBlock *next = block->next) - block = next; - - block->next = mpFreeEdgeBlocks; - mpFreeEdgeBlocks = mpEdgeBlocks; - mpEdgeBlocks = NULL; - } - - mEdgeBlockIdx = kEdgeBlockMax; -} - -void VDPixmapPathRasterizer::FreeEdgeLists() { - ClearEdgeList(); - - while(EdgeBlock *block = mpFreeEdgeBlocks) { - mpFreeEdgeBlocks = block->next; - - delete block; - } -} - -void VDPixmapPathRasterizer::ClearScanBuffer() { - delete[] mpScanBuffer; - mpScanBuffer = mpScanBufferBiased = NULL; - mScanYMin = 0; - mScanYMax = 0; -} - -void VDPixmapPathRasterizer::ReallocateScanBuffer(int ymin, int ymax) { - // - // check if there actually is a scan buffer to avoid unintentionally pinning at zero - if (mpScanBuffer) { - int nicedelta = (mScanYMax - mScanYMin); - - if (ymin < mScanYMin) { - int yminnice = mScanYMin - nicedelta; - if (ymin > yminnice) - ymin = yminnice; - - ymin &= ~31; - } else - ymin = mScanYMin; - - if (ymax > mScanYMax) { - int ymaxnice = mScanYMax + nicedelta; - if (ymax < ymaxnice) - ymax = ymaxnice; - - ymax = (ymax + 31) & ~31; - } else - ymax = mScanYMax; - - VDASSERT(ymin <= mScanYMin && ymax >= mScanYMax); - } - - // reallocate scan buffer - Scan *pNewBuffer = new Scan[ymax - ymin]; - Scan *pNewBufferBiased = pNewBuffer - ymin; - - if (mpScanBuffer) { - memcpy(pNewBufferBiased + mScanYMin, mpScanBufferBiased + mScanYMin, (mScanYMax - mScanYMin) * sizeof(Scan)); - delete[] mpScanBuffer; - - // zero new areas of scan buffer - for(int y=ymin; y> 1) & ~1; - - if (region.mSpans[mid + 1] < spanmin) - lo = mid + 2; - else - hi = mid; - } - - start = lo; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w - x) + ((dst.h - y - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // compute bottom clip - int lo = start; - int hi = n; - - while(lo < hi) { - int mid = ((lo + hi) >> 1) & ~1; - - if (region.mSpans[mid] >= spanlimit) - hi = mid; - else - lo = mid+2; - } - - end = lo; - - // check for total bottom clip - if (start >= end) - return true; - } - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - uint32 *dstp; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - uint32 py = (span0 >> 16) - 0x8000 + y; - uint32 px = (span0 & 0xffff) - 0x8000 + x; - uint32 w = span1-span0; - - VDASSERT(py < (uint32)dst.h); - VDASSERT(px < (uint32)dst.w); - VDASSERT(dst.w - (int)px >= (int)w); - - if (lasty != py) - dstp = (uint32 *)vdptroffset(dst.data, dst.pitch * py); - - uint32 *p = dstp + px; - do { - *p++ = color; - } while(--w); - } - - return true; -} - -namespace { - void RenderABuffer32(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint32 *dstp = (uint32 *)vdptroffset(dst.data, dst.pitch * y); - - const uint32 color_rb = color & 0x00FF00FF; - const uint32 color_g = color & 0x0000FF00; - do { - const uint32 px = *dstp; - const uint32 px_rb = px & 0x00FF00FF; - const uint32 px_g = px & 0x0000FF00; - const sint32 a = *alpha++; - - const uint32 result_rb = (((px_rb << 6) + ((sint32)(color_rb - px_rb)*a + 0x00200020)) & 0x3FC03FC0); - const uint32 result_g = (((px_g << 6) + ((sint32)(color_g - px_g )*a + 0x00002000)) & 0x003FC000); - - *dstp++ = (result_rb + result_g) >> 6; - } while(--w); - } - - void RenderABuffer8(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); - - do { - const uint8 px = *dstp; - const sint8 a = *alpha++; - - *dstp++ = px + (((sint32)(color - px) * a + 32) >> 6); - } while(--w); - } - - void RenderABuffer8_128(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); - - do { - const uint8 px = *dstp; - const sint16 a = *alpha++; - - *dstp++ = px + (((sint32)(color - px) * a + 64) >> 7); - } while(--w); - } - - void RenderABuffer8_256(const VDPixmap& dst, int y, const uint16 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); - - do { - const uint8 px = *dstp; - const sint32 a = *alpha++; - - *dstp++ = px + (((sint32)(color - px) * a + 128) >> 8); - } while(--w); - } - - void RenderABuffer8_1024(const VDPixmap& dst, int y, const uint16 *alpha, uint32 w, uint32 color) { - if (!w) - return; - - // update dest pointer - uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); - - do { - const uint8 px = *dstp; - const sint32 a = *alpha++; - - *dstp++ = px + (((sint32)(color - px) * a + 512) >> 10); - } while(--w); - } -} - -bool VDPixmapFillRegionAntialiased_32x_32x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { - if (dst.format != nsVDPixmap::kPixFormat_Y8) - return false; - - // fast out - if (region.mSpans.empty()) - return true; - - // check if vertical clipping is required - const size_t n = region.mSpans.size(); - uint32 start = 0; - uint32 end = n; - - uint32 spanmin = -x + (-y << 16) + 0x80008000; - - if (region.mSpans.front() < spanmin) { - // find first span : x2 > spanmin - start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); - start &= ~1; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w*32 - x) + (((dst.h*32 - y) - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // find last span : x1 < spanlimit - end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); - - end = (end + 1) & ~1; - - // check for total bottom clip - if (start >= end) - return true; - } - - // allocate A-buffer - vdfastvector abuffer(dst.w, 0); - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - - sint32 dstw32 = dst.w * 32; - sint32 dsth32 = dst.h * 32; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - sint32 py = (span0 >> 16) - 0x8000 + y; - - if ((uint32)py >= (uint32)dsth32) - continue; - - sint32 px1 = (span0 & 0xffff) - 0x8000 + x; - sint32 px2 = (span1 & 0xffff) - 0x8000 + x; - sint32 w = span1-span0; - - if (lasty != py) { - if (((lasty ^ py) & 0xFFFFFFE0)) { - if (lasty >= 0) { - // flush scanline - - RenderABuffer8_1024(dst, lasty >> 5, abuffer.data(), dst.w, color); - } - - memset(abuffer.data(), 0, abuffer.size() * sizeof(abuffer[0])); - } - lasty = py; - } - - if (px1 < 0) - px1 = 0; - if (px2 > dstw32) - px2 = dstw32; - - if (px1 >= px2) - continue; - - uint32 ix1 = px1 >> 5; - uint32 ix2 = px2 >> 5; - uint16 *p1 = abuffer.data() + ix1; - uint16 *p2 = abuffer.data() + ix2; - - if (p1 == p2) { - p1[0] += (px2 - px1); - } else { - if (px1 & 31) { - p1[0] += 32 - (px1 & 31); - ++p1; - } - - while(p1 != p2) { - p1[0] += 32; - ++p1; - } - - if (px2 & 31) - p1[0] += px2 & 32; - } - } - - if (lasty >= 0) - RenderABuffer8_1024(dst, lasty >> 5, abuffer.data(), dst.w, color); - - return true; -} - -bool VDPixmapFillRegionAntialiased_16x_16x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { - if (dst.format != nsVDPixmap::kPixFormat_Y8) - return false; - - // fast out - if (region.mSpans.empty()) - return true; - - // check if vertical clipping is required - const size_t n = region.mSpans.size(); - uint32 start = 0; - uint32 end = n; - - uint32 spanmin = -x + (-y << 16) + 0x80008000; - - if (region.mSpans.front() < spanmin) { - // find first span : x2 > spanmin - start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); - start &= ~1; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w*16 - x) + (((dst.h*16 - y) - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // find last span : x1 < spanlimit - end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); - - end = (end + 1) & ~1; - - // check for total bottom clip - if (start >= end) - return true; - } - - // allocate A-buffer - vdfastvector abuffer(dst.w, 0); - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - - sint32 dstw16 = dst.w * 16; - sint32 dsth16 = dst.h * 16; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - sint32 py = (span0 >> 16) - 0x8000 + y; - - if ((uint32)py >= (uint32)dsth16) - continue; - - sint32 px1 = (span0 & 0xffff) - 0x8000 + x; - sint32 px2 = (span1 & 0xffff) - 0x8000 + x; - sint32 w = span1-span0; - - if (lasty != py) { - if (((lasty ^ py) & 0xFFFFFFF0)) { - if (lasty >= 0) { - // flush scanline - - RenderABuffer8_256(dst, lasty >> 4, abuffer.data(), dst.w, color); - } - - memset(abuffer.data(), 0, abuffer.size() * sizeof(abuffer[0])); - } - lasty = py; - } - - if (px1 < 0) - px1 = 0; - if (px2 > dstw16) - px2 = dstw16; - - if (px1 >= px2) - continue; - - uint32 ix1 = px1 >> 4; - uint32 ix2 = px2 >> 4; - uint16 *p1 = abuffer.data() + ix1; - uint16 *p2 = abuffer.data() + ix2; - - if (p1 == p2) { - p1[0] += (px2 - px1); - } else { - if (px1 & 15) { - p1[0] += 16 - (px1 & 15); - ++p1; - } - - while(p1 != p2) { - p1[0] += 16; - ++p1; - } - - if (px2 & 15) - p1[0] += px2 & 15; - } - } - - if (lasty >= 0) - RenderABuffer8_256(dst, lasty >> 4, abuffer.data(), dst.w, color); - - return true; -} - -bool VDPixmapFillRegionAntialiased_16x_8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { - if (dst.format != nsVDPixmap::kPixFormat_XRGB8888 && dst.format != nsVDPixmap::kPixFormat_Y8) - return false; - - // fast out - if (region.mSpans.empty()) - return true; - - // check if vertical clipping is required - const size_t n = region.mSpans.size(); - uint32 start = 0; - uint32 end = n; - - uint32 spanmin = -x + (-y << 16) + 0x80008000; - - if (region.mSpans.front() < spanmin) { - // find first span : x2 > spanmin - start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); - start &= ~1; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w*16 - x) + (((dst.h*8 - y) - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // find last span : x1 < spanlimit - end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); - - end = (end + 1) & ~1; - - // check for total bottom clip - if (start >= end) - return true; - } - - // allocate A-buffer - vdfastvector abuffer(dst.w, 0); - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - - sint32 dstw16 = dst.w * 16; - sint32 dsth8 = dst.h * 8; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - sint32 py = (span0 >> 16) - 0x8000 + y; - - if ((uint32)py >= (uint32)dsth8) - continue; - - sint32 px1 = (span0 & 0xffff) - 0x8000 + x; - sint32 px2 = (span1 & 0xffff) - 0x8000 + x; - sint32 w = span1-span0; - - if (lasty != py) { - if (((lasty ^ py) & 0xFFFFFFF8)) { - if (lasty >= 0) { - // flush scanline - - RenderABuffer8_128(dst, lasty >> 3, abuffer.data(), dst.w, color); - } - - memset(abuffer.data(), 0, abuffer.size()); - } - lasty = py; - } - - if (px1 < 0) - px1 = 0; - if (px2 > dstw16) - px2 = dstw16; - - if (px1 >= px2) - continue; - - uint32 ix1 = px1 >> 4; - uint32 ix2 = px2 >> 4; - uint8 *p1 = abuffer.data() + ix1; - uint8 *p2 = abuffer.data() + ix2; - - if (p1 == p2) { - p1[0] += (px2 - px1); - } else { - if (px1 & 15) { - p1[0] += 16 - (px1 & 15); - ++p1; - } - - while(p1 != p2) { - p1[0] += 16; - ++p1; - } - - if (px2 & 15) - p1[0] += px2 & 15; - } - } - - if (lasty >= 0) - RenderABuffer8_128(dst, lasty >> 3, abuffer.data(), dst.w, color); - - return true; -} - -bool VDPixmapFillRegionAntialiased8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { - switch(dst.format) { - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - { - VDPixmap pxY; - VDPixmap pxCb; - VDPixmap pxCr; - - pxY.format = nsVDPixmap::kPixFormat_Y8; - pxY.data = dst.data; - pxY.pitch = dst.pitch; - pxY.w = dst.w; - pxY.h = dst.h; - - pxCb.format = nsVDPixmap::kPixFormat_Y8; - pxCb.data = dst.data2; - pxCb.pitch = dst.pitch2; - pxCb.w = dst.w; - pxCb.h = dst.h; - - pxCr.format = nsVDPixmap::kPixFormat_Y8; - pxCr.data = dst.data3; - pxCr.pitch = dst.pitch3; - pxCr.w = dst.w; - pxCr.h = dst.h; - - uint32 colorY = (color >> 8) & 0xff; - uint32 colorCb = (color >> 0) & 0xff; - uint32 colorCr = (color >> 16) & 0xff; - - VDPixmapFillRegionAntialiased8x(pxY, region, x, y, colorY); - - switch(dst.format) { - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 2; - pxCr.h = pxCb.h = dst.h >> 2; - x >>= 2; - y >>= 2; - VDPixmapFillRegionAntialiased_32x_32x(pxCb, region, x, y, colorCb); - VDPixmapFillRegionAntialiased_32x_32x(pxCr, region, x, y, colorCr); - return true; - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 1; - pxCr.h = pxCb.h = dst.h >> 1; - x >>= 1; - y >>= 1; - x += 2; - VDPixmapFillRegionAntialiased_16x_16x(pxCb, region, x, y, colorCb); - VDPixmapFillRegionAntialiased_16x_16x(pxCr, region, x, y, colorCr); - return true; - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 1; - x >>= 1; - x += 2; - VDPixmapFillRegionAntialiased_16x_8x(pxCb, region, x, y, colorCb); - VDPixmapFillRegionAntialiased_16x_8x(pxCr, region, x, y, colorCr); - return true; - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - VDPixmapFillRegionAntialiased8x(pxCb, region, x, y, colorCb); - VDPixmapFillRegionAntialiased8x(pxCr, region, x, y, colorCr); - return true; - } - } - } - - if (dst.format != nsVDPixmap::kPixFormat_XRGB8888 && dst.format != nsVDPixmap::kPixFormat_Y8) - return false; - - // fast out - if (region.mSpans.empty()) - return true; - - // check if vertical clipping is required - const size_t n = region.mSpans.size(); - uint32 start = 0; - uint32 end = n; - - uint32 spanmin = -x + (-y << 16) + 0x80008000; - - if (region.mSpans.front() < spanmin) { - // find first span : x2 > spanmin - start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); - start &= ~1; - - // check for total top clip - if (start >= n) - return true; - } - - uint32 spanlimit = (dst.w*8 - x) + (((dst.h*8 - y) - 1) << 16) + 0x80008000; - - if (region.mSpans.back() > spanlimit) { - // find last span : x1 < spanlimit - end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); - - end = (end + 1) & ~1; - - // check for total bottom clip - if (start >= end) - return true; - } - - // allocate A-buffer - vdfastvector abuffer(dst.w, 0); - - // fill region - const uint32 *pSpan = ®ion.mSpans[start]; - const uint32 *pEnd = ®ion.mSpans[0] + end; - int lasty = -1; - - sint32 dstw8 = dst.w * 8; - sint32 dsth8 = dst.h * 8; - - for(; pSpan != pEnd; pSpan += 2) { - uint32 span0 = pSpan[0]; - uint32 span1 = pSpan[1]; - - sint32 py = (span0 >> 16) - 0x8000 + y; - - if ((uint32)py >= (uint32)dsth8) - continue; - - sint32 px1 = (span0 & 0xffff) - 0x8000 + x; - sint32 px2 = (span1 & 0xffff) - 0x8000 + x; - sint32 w = span1-span0; - - if (lasty != py) { - if (((lasty ^ py) & 0xFFFFFFF8)) { - if (lasty >= 0) { - // flush scanline - - if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) - RenderABuffer32(dst, lasty >> 3, abuffer.data(), dst.w, color); - else - RenderABuffer8(dst, lasty >> 3, abuffer.data(), dst.w, color); - } - - memset(abuffer.data(), 0, abuffer.size()); - } - lasty = py; - } - - if (px1 < 0) - px1 = 0; - if (px2 > dstw8) - px2 = dstw8; - - if (px1 >= px2) - continue; - - uint32 ix1 = px1 >> 3; - uint32 ix2 = px2 >> 3; - uint8 *p1 = abuffer.data() + ix1; - uint8 *p2 = abuffer.data() + ix2; - - if (p1 == p2) { - p1[0] += (px2 - px1); - } else { - if (px1 & 7) { - p1[0] += 8 - (px1 & 7); - ++p1; - } - - while(p1 != p2) { - p1[0] += 8; - ++p1; - } - - if (px2 & 7) - p1[0] += px2 & 7; - } - } - - if (lasty >= 0) { - if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) - RenderABuffer32(dst, lasty >> 3, abuffer.data(), dst.w, color); - else - RenderABuffer8(dst, lasty >> 3, abuffer.data(), dst.w, color); - } - - return true; -} - -void VDPixmapCreateRoundRegion(VDPixmapRegion& dst, float r) { - int ir = VDCeilToInt(r); - float r2 = r*r; - - dst.mSpans.clear(); - dst.mBounds.set(-ir, 0, ir+1, 0); - - for(int y = -ir; y <= ir; ++y) { - int dx = VDCeilToInt(sqrtf(r2 - y*y)); - - if (dx > 0) { - dst.mSpans.push_back(0x80008000 + (y << 16) - dx); - dst.mSpans.push_back(0x80008001 + (y << 16) + dx); - if (dst.mBounds.top > y) - dst.mBounds.top = y; - if (dst.mBounds.bottom < y) - dst.mBounds.bottom = y; - } - } -} - -void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, int dx1, int dx2, int dy) { - dst.mSpans.clear(); - dst.mSpans.resize(r1.mSpans.size()+r2.mSpans.size()); - - const uint32 *itA = r1.mSpans.data(); - const uint32 *itAE = itA + r1.mSpans.size(); - const uint32 *itB = r2.mSpans.data(); - const uint32 *itBE = itB + r2.mSpans.size(); - uint32 *dstp0 = dst.mSpans.data(); - uint32 *dstp = dst.mSpans.data(); - - uint32 offset1 = (dy<<16) + dx1; - uint32 offset2 = (dy<<16) + dx2; - - while(itA != itAE && itB != itBE) { - uint32 x1; - uint32 x2; - - if (itB[0] + offset1 < itA[0]) { - // B span is earlier. Use it. - x1 = itB[0] + offset1; - x2 = itB[1] + offset2; - itB += 2; - - // B spans *can* overlap, due to the widening. - while(itB != itBE && itB[0]+offset1 <= x2) { - uint32 bx2 = itB[1] + offset2; - if (x2 < bx2) - x2 = bx2; - - itB += 2; - } - - goto a_start; - } else { - // A span is earlier. Use it. - x1 = itA[0]; - x2 = itA[1]; - itA += 2; - - // A spans don't overlap, so begin merge loop with B first. - } - - for(;;) { - // If we run out of B spans or the B span doesn't overlap, - // then the next A span can't either (because A spans don't - // overlap) and we exit. - - if (itB == itBE || itB[0]+offset1 > x2) - break; - - do { - uint32 bx2 = itB[1] + offset2; - if (x2 < bx2) - x2 = bx2; - - itB += 2; - } while(itB != itBE && itB[0]+offset1 <= x2); - - // If we run out of A spans or the A span doesn't overlap, - // then the next B span can't either, because we would have - // consumed all overlapping B spans in the above loop. -a_start: - if (itA == itAE || itA[0] > x2) - break; - - do { - uint32 ax2 = itA[1]; - if (x2 < ax2) - x2 = ax2; - - itA += 2; - } while(itA != itAE && itA[0] <= x2); - } - - // Flush span. - dstp[0] = x1; - dstp[1] = x2; - dstp += 2; - } - - // Copy over leftover spans. - memcpy(dstp, itA, sizeof(uint32)*(itAE - itA)); - dstp += itAE - itA; - - while(itB != itBE) { - // B span is earlier. Use it. - uint32 x1 = itB[0] + offset1; - uint32 x2 = itB[1] + offset2; - itB += 2; - - // B spans *can* overlap, due to the widening. - while(itB != itBE && itB[0]+offset1 <= x2) { - uint32 bx2 = itB[1] + offset2; - if (x2 < bx2) - x2 = bx2; - - itB += 2; - } - - dstp[0] = x1; - dstp[1] = x2; - dstp += 2; - } - - dst.mSpans.resize(dstp - dst.mSpans.data()); -} - -void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, VDPixmapRegion *tempCache) { - VDPixmapRegion temp; - - if (tempCache) { - tempCache->swap(temp); - - temp.clear(); - } - - const uint32 *src1 = r2.mSpans.data(); - const uint32 *src2 = src1 + r2.mSpans.size(); - - dst.mSpans.clear(); - while(src1 != src2) { - uint32 p1 = src1[0]; - uint32 p2 = src1[1]; - src1 += 2; - - temp.mSpans.swap(dst.mSpans); - VDPixmapConvolveRegion(dst, temp, r1, (p1 & 0xffff) - 0x8000, (p2 & 0xffff) - 0x8000, (p1 >> 16) - 0x8000); - } - - if (tempCache) - tempCache->swap(temp); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include + +void VDPixmapRegion::clear() { + mSpans.clear(); +} + +void VDPixmapRegion::swap(VDPixmapRegion& x) { + mSpans.swap(x.mSpans); + std::swap(mBounds, x.mBounds); +} + +VDPixmapPathRasterizer::VDPixmapPathRasterizer() + : mpEdgeBlocks(NULL) + , mpFreeEdgeBlocks(NULL) + , mEdgeBlockIdx(kEdgeBlockMax) + , mpScanBuffer(NULL) +{ + ClearScanBuffer(); +} + +VDPixmapPathRasterizer::VDPixmapPathRasterizer(const VDPixmapPathRasterizer&) + : mpEdgeBlocks(NULL) + , mpFreeEdgeBlocks(NULL) + , mEdgeBlockIdx(kEdgeBlockMax) + , mpScanBuffer(NULL) +{ + ClearScanBuffer(); +} + +VDPixmapPathRasterizer::~VDPixmapPathRasterizer() { + Clear(); + FreeEdgeLists(); +} + +VDPixmapPathRasterizer& VDPixmapPathRasterizer::operator=(const VDPixmapPathRasterizer&) { + return *this; +} + +void VDPixmapPathRasterizer::Clear() { + ClearEdgeList(); + ClearScanBuffer(); +} + +void VDPixmapPathRasterizer::QuadraticBezier(const vdint2 *pts) { + int x0 = pts[0].x; + int x1 = pts[1].x; + int x2 = pts[2].x; + int y0 = pts[0].y; + int y1 = pts[1].y; + int y2 = pts[2].y; + + // P = (1-t)^2*P0 + 2t(1-t)*P1 + t^2*P2 + // P = (1-2t+t^2)P0 + 2(t-t^2)P1 + t^2*P2 + // P = (P0-2P1+P2)t^2 + 2(P1-P0)t + P0 + + int cx2 = x0-2*x1+x2; + int cx1 = -2*x0+2*x1; + int cx0 = x0; + + int cy2 = y0-2*y1+y2; + int cy1 = -2*y0+2*y1; + int cy0 = y0; + + // This equation is from Graphics Gems I. + // + // The idea is that since we're approximating a cubic curve with lines, + // any error we incur is due to the curvature of the line, which we can + // estimate by calculating the maximum acceleration of the curve. For + // a cubic, the acceleration (second derivative) is a line, meaning that + // the absolute maximum acceleration must occur at either the beginning + // (|c2|) or the end (|c2+c3|). Our bounds here are a little more + // conservative than that, but that's okay. + // + // If the acceleration of the parametric formula is zero (c2 = c3 = 0), + // that component of the curve is linear and does not incur any error. + // If a=0 for both X and Y, the curve is a line segment and we can + // use a step size of 1. + + int maxaccel1 = abs(cy2); + int maxaccel2 = abs(cx2); + + int maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; + int h = 1; + + while(maxaccel > 8 && h < 1024) { + maxaccel >>= 2; + h += h; + } + + int lastx = x0; + int lasty = y0; + + // compute forward differences + sint64 h1 = (sint64)(0x40000000 / h) << 2; + sint64 h2 = h1/h; + + sint64 ax0 = (sint64)cx0 << 32; + sint64 ax1 = h1*(sint64)cx1 + h2*(sint64)cx2; + sint64 ax2 = 2*h2*(sint64)cx2; + + sint64 ay0 = (sint64)cy0 << 32; + sint64 ay1 = h1*(sint64)cy1 + h2*(sint64)cy2; + sint64 ay2 = 2*h2*(sint64)cy2; + + // round, not truncate + ax0 += 0x80000000; + ay0 += 0x80000000; + + do { + ax0 += ax1; + ax1 += ax2; + ay0 += ay1; + ay1 += ay2; + + int xi = (int)((uint64)ax0 >> 32); + int yi = (int)((uint64)ay0 >> 32); + + FastLine(lastx, lasty, xi, yi); + lastx = xi; + lasty = yi; + } while(--h); +} + +void VDPixmapPathRasterizer::CubicBezier(const vdint2 *pts) { + int x0 = pts[0].x; + int x1 = pts[1].x; + int x2 = pts[2].x; + int x3 = pts[3].x; + int y0 = pts[0].y; + int y1 = pts[1].y; + int y2 = pts[2].y; + int y3 = pts[3].y; + + int cx3 = - x0+3*x1-3*x2+x3; + int cx2 = 3*x0-6*x1+3*x2; + int cx1 = -3*x0+3*x1; + int cx0 = x0; + + int cy3 = - y0+3*y1-3*y2+y3; + int cy2 = 3*y0-6*y1+3*y2; + int cy1 = -3*y0+3*y1; + int cy0 = y0; + + // This equation is from Graphics Gems I. + // + // The idea is that since we're approximating a cubic curve with lines, + // any error we incur is due to the curvature of the line, which we can + // estimate by calculating the maximum acceleration of the curve. For + // a cubic, the acceleration (second derivative) is a line, meaning that + // the absolute maximum acceleration must occur at either the beginning + // (|c2|) or the end (|c2+c3|). Our bounds here are a little more + // conservative than that, but that's okay. + // + // If the acceleration of the parametric formula is zero (c2 = c3 = 0), + // that component of the curve is linear and does not incur any error. + // If a=0 for both X and Y, the curve is a line segment and we can + // use a step size of 1. + + int maxaccel1 = abs(2*cy2) + abs(6*cy3); + int maxaccel2 = abs(2*cx2) + abs(6*cx3); + + int maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2; + int h = 1; + + while(maxaccel > 8 && h < 1024) { + maxaccel >>= 2; + h += h; + } + + int lastx = x0; + int lasty = y0; + + // compute forward differences + sint64 h1 = (sint64)(0x40000000 / h) << 2; + sint64 h2 = h1/h; + sint64 h3 = h2/h; + + sint64 ax0 = (sint64)cx0 << 32; + sint64 ax1 = h1*(sint64)cx1 + h2*(sint64)cx2 + h3*(sint64)cx3; + sint64 ax2 = 2*h2*(sint64)cx2 + 6*h3*(sint64)cx3; + sint64 ax3 = 6*h3*(sint64)cx3; + + sint64 ay0 = (sint64)cy0 << 32; + sint64 ay1 = h1*(sint64)cy1 + h2*(sint64)cy2 + h3*(sint64)cy3; + sint64 ay2 = 2*h2*(sint64)cy2 + 6*h3*(sint64)cy3; + sint64 ay3 = 6*h3*(sint64)cy3; + + // round, not truncate + ax0 += 0x80000000; + ay0 += 0x80000000; + + do { + ax0 += ax1; + ax1 += ax2; + ax2 += ax3; + ay0 += ay1; + ay1 += ay2; + ay2 += ay3; + + int xi = (int)((uint64)ax0 >> 32); + int yi = (int)((uint64)ay0 >> 32); + + FastLine(lastx, lasty, xi, yi); + lastx = xi; + lasty = yi; + } while(--h); +} + +void VDPixmapPathRasterizer::Line(const vdint2& pt1, const vdint2& pt2) { + FastLine(pt1.x, pt1.y, pt2.x, pt2.y); +} + +void VDPixmapPathRasterizer::FastLine(int x0, int y0, int x1, int y1) { + int flag = 1; + + if (y1 == y0) + return; + + if (y1 < y0) { + int t; + + t=x0; x0=x1; x1=t; + t=y0; y0=y1; y1=t; + flag = 0; + } + + int dy = y1-y0; + int xacc = x0<<13; + + // prestep y0 down + int iy0 = (y0+3) >> 3; + int iy1 = (y1+3) >> 3; + + if (iy0 < iy1) { + int invslope = (x1-x0)*65536/dy; + + int prestep = (4-y0) & 7; + xacc += (invslope * prestep)>>3; + + if (iy0 < mScanYMin || iy1 > mScanYMax) { + ReallocateScanBuffer(iy0, iy1); + VDASSERT(iy0 >= mScanYMin && iy1 <= mScanYMax); + } + + while(iy0 < iy1) { + int ix = (xacc+32767)>>16; + + if (mEdgeBlockIdx >= kEdgeBlockMax) { + if (mpFreeEdgeBlocks) { + EdgeBlock *newBlock = mpFreeEdgeBlocks; + mpFreeEdgeBlocks = mpFreeEdgeBlocks->next; + newBlock->next = mpEdgeBlocks; + mpEdgeBlocks = newBlock; + } else { + mpEdgeBlocks = new EdgeBlock(mpEdgeBlocks); + } + + mEdgeBlockIdx = 0; + } + + Edge& e = mpEdgeBlocks->edges[mEdgeBlockIdx]; + Scan& s = mpScanBufferBiased[iy0]; + VDASSERT(iy0 >= mScanYMin && iy0 < mScanYMax); + ++mEdgeBlockIdx; + + e.posandflag = ix*2+flag; + e.next = s.chain; + s.chain = &e; + ++s.count; + + ++iy0; + xacc += invslope; + } + } +} + +void VDPixmapPathRasterizer::ScanConvert(VDPixmapRegion& region) { + // Convert the edges to spans. We couldn't do this before because some of + // the regions may have winding numbers >+1 and it would have been a pain + // to try to adjust the spans on the fly. We use one heap to detangle + // a scanline's worth of edges from the singly-linked lists, and another + // to collect the actual scans. + vdfastvector heap; + + region.mSpans.clear(); + int xmin = INT_MAX; + int xmax = INT_MIN; + int ymin = INT_MAX; + int ymax = INT_MIN; + + for(int y=mScanYMin; ynext) + *heap1++ = ptr->posandflag; + + VDASSERT(heap1 - heap0 == flipcount); + + // Sort edge heap. Note that we conveniently made the opening edges + // one more than closing edges at the same spot, so we won't have any + // problems with abutting spans. + + std::sort(heap0, heap1); + +#if 0 + while(heap0 != heap1) { + int x = *heap0++ >> 1; + region.mSpans.push_back((y<<16) + x + 0x80008000); + region.mSpans.push_back((y<<16) + x + 0x80008001); + } + continue; +#endif + + // Trim any odd edges off, since we can never close on one. + if (flipcount & 1) + --heap1; + + // Process edges and add spans. Since we only check for a non-zero + // winding number, it doesn't matter which way the outlines go. Also, since + // the parity always flips after each edge regardless of direction, we can + // process the edges in pairs. + + size_t spanstart = region.mSpans.size(); + + int x_left; + int count = 0; + while(heap0 != heap1) { + int x = *heap0++; + + if (!count) + x_left = (x>>1); + + count += (x&1); + + x = *heap0++; + + count += (x&1); + + if (!--count) { + int x_right = (x>>1); + + if (x_right > x_left) { + region.mSpans.push_back((y<<16) + x_left + 0x80008000); + region.mSpans.push_back((y<<16) + x_right + 0x80008000); + + } + } + } + + size_t spanend = region.mSpans.size(); + + if (spanend > spanstart) { + if (ymin > y) + ymin = y; + + if (ymax < y) + ymax = y; + + int x1 = (region.mSpans[spanstart] & 0xffff) - 0x8000; + int x2 = (region.mSpans[spanend-1] & 0xffff) - 0x8000; + + if (xmin > x1) + xmin = x1; + + if (xmax < x2) + xmax = x2; + } + } + + if (xmax > xmin) { + region.mBounds.set(xmin, ymin, xmax, ymax); + } else { + region.mBounds.set(0, 0, 0, 0); + } + + // Dump the edge and scan buffers, since we no longer need them. + ClearEdgeList(); + ClearScanBuffer(); +} + +void VDPixmapPathRasterizer::ClearEdgeList() { + if (mpEdgeBlocks) { + EdgeBlock *block = mpEdgeBlocks; + + while(EdgeBlock *next = block->next) + block = next; + + block->next = mpFreeEdgeBlocks; + mpFreeEdgeBlocks = mpEdgeBlocks; + mpEdgeBlocks = NULL; + } + + mEdgeBlockIdx = kEdgeBlockMax; +} + +void VDPixmapPathRasterizer::FreeEdgeLists() { + ClearEdgeList(); + + while(EdgeBlock *block = mpFreeEdgeBlocks) { + mpFreeEdgeBlocks = block->next; + + delete block; + } +} + +void VDPixmapPathRasterizer::ClearScanBuffer() { + delete[] mpScanBuffer; + mpScanBuffer = mpScanBufferBiased = NULL; + mScanYMin = 0; + mScanYMax = 0; +} + +void VDPixmapPathRasterizer::ReallocateScanBuffer(int ymin, int ymax) { + // + // check if there actually is a scan buffer to avoid unintentionally pinning at zero + if (mpScanBuffer) { + int nicedelta = (mScanYMax - mScanYMin); + + if (ymin < mScanYMin) { + int yminnice = mScanYMin - nicedelta; + if (ymin > yminnice) + ymin = yminnice; + + ymin &= ~31; + } else + ymin = mScanYMin; + + if (ymax > mScanYMax) { + int ymaxnice = mScanYMax + nicedelta; + if (ymax < ymaxnice) + ymax = ymaxnice; + + ymax = (ymax + 31) & ~31; + } else + ymax = mScanYMax; + + VDASSERT(ymin <= mScanYMin && ymax >= mScanYMax); + } + + // reallocate scan buffer + Scan *pNewBuffer = new Scan[ymax - ymin]; + Scan *pNewBufferBiased = pNewBuffer - ymin; + + if (mpScanBuffer) { + memcpy(pNewBufferBiased + mScanYMin, mpScanBufferBiased + mScanYMin, (mScanYMax - mScanYMin) * sizeof(Scan)); + delete[] mpScanBuffer; + + // zero new areas of scan buffer + for(int y=ymin; y> 1) & ~1; + + if (region.mSpans[mid + 1] < spanmin) + lo = mid + 2; + else + hi = mid; + } + + start = lo; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w - x) + ((dst.h - y - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // compute bottom clip + int lo = start; + int hi = n; + + while(lo < hi) { + int mid = ((lo + hi) >> 1) & ~1; + + if (region.mSpans[mid] >= spanlimit) + hi = mid; + else + lo = mid+2; + } + + end = lo; + + // check for total bottom clip + if (start >= end) + return true; + } + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + uint32 *dstp; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + uint32 py = (span0 >> 16) - 0x8000 + y; + uint32 px = (span0 & 0xffff) - 0x8000 + x; + uint32 w = span1-span0; + + VDASSERT(py < (uint32)dst.h); + VDASSERT(px < (uint32)dst.w); + VDASSERT(dst.w - (int)px >= (int)w); + + if (lasty != py) + dstp = (uint32 *)vdptroffset(dst.data, dst.pitch * py); + + uint32 *p = dstp + px; + do { + *p++ = color; + } while(--w); + } + + return true; +} + +namespace { + void RenderABuffer32(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint32 *dstp = (uint32 *)vdptroffset(dst.data, dst.pitch * y); + + const uint32 color_rb = color & 0x00FF00FF; + const uint32 color_g = color & 0x0000FF00; + do { + const uint32 px = *dstp; + const uint32 px_rb = px & 0x00FF00FF; + const uint32 px_g = px & 0x0000FF00; + const sint32 a = *alpha++; + + const uint32 result_rb = (((px_rb << 6) + ((sint32)(color_rb - px_rb)*a + 0x00200020)) & 0x3FC03FC0); + const uint32 result_g = (((px_g << 6) + ((sint32)(color_g - px_g )*a + 0x00002000)) & 0x003FC000); + + *dstp++ = (result_rb + result_g) >> 6; + } while(--w); + } + + void RenderABuffer8(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); + + do { + const uint8 px = *dstp; + const sint8 a = *alpha++; + + *dstp++ = px + (((sint32)(color - px) * a + 32) >> 6); + } while(--w); + } + + void RenderABuffer8_128(const VDPixmap& dst, int y, const uint8 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); + + do { + const uint8 px = *dstp; + const sint16 a = *alpha++; + + *dstp++ = px + (((sint32)(color - px) * a + 64) >> 7); + } while(--w); + } + + void RenderABuffer8_256(const VDPixmap& dst, int y, const uint16 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); + + do { + const uint8 px = *dstp; + const sint32 a = *alpha++; + + *dstp++ = px + (((sint32)(color - px) * a + 128) >> 8); + } while(--w); + } + + void RenderABuffer8_1024(const VDPixmap& dst, int y, const uint16 *alpha, uint32 w, uint32 color) { + if (!w) + return; + + // update dest pointer + uint8 *dstp = (uint8 *)vdptroffset(dst.data, dst.pitch * y); + + do { + const uint8 px = *dstp; + const sint32 a = *alpha++; + + *dstp++ = px + (((sint32)(color - px) * a + 512) >> 10); + } while(--w); + } +} + +bool VDPixmapFillRegionAntialiased_32x_32x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { + if (dst.format != nsVDPixmap::kPixFormat_Y8) + return false; + + // fast out + if (region.mSpans.empty()) + return true; + + // check if vertical clipping is required + const size_t n = region.mSpans.size(); + uint32 start = 0; + uint32 end = n; + + uint32 spanmin = -x + (-y << 16) + 0x80008000; + + if (region.mSpans.front() < spanmin) { + // find first span : x2 > spanmin + start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); + start &= ~1; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w*32 - x) + (((dst.h*32 - y) - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // find last span : x1 < spanlimit + end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); + + end = (end + 1) & ~1; + + // check for total bottom clip + if (start >= end) + return true; + } + + // allocate A-buffer + vdfastvector abuffer(dst.w, 0); + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + + sint32 dstw32 = dst.w * 32; + sint32 dsth32 = dst.h * 32; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + sint32 py = (span0 >> 16) - 0x8000 + y; + + if ((uint32)py >= (uint32)dsth32) + continue; + + sint32 px1 = (span0 & 0xffff) - 0x8000 + x; + sint32 px2 = (span1 & 0xffff) - 0x8000 + x; + sint32 w = span1-span0; + + if (lasty != py) { + if (((lasty ^ py) & 0xFFFFFFE0)) { + if (lasty >= 0) { + // flush scanline + + RenderABuffer8_1024(dst, lasty >> 5, abuffer.data(), dst.w, color); + } + + memset(abuffer.data(), 0, abuffer.size() * sizeof(abuffer[0])); + } + lasty = py; + } + + if (px1 < 0) + px1 = 0; + if (px2 > dstw32) + px2 = dstw32; + + if (px1 >= px2) + continue; + + uint32 ix1 = px1 >> 5; + uint32 ix2 = px2 >> 5; + uint16 *p1 = abuffer.data() + ix1; + uint16 *p2 = abuffer.data() + ix2; + + if (p1 == p2) { + p1[0] += (px2 - px1); + } else { + if (px1 & 31) { + p1[0] += 32 - (px1 & 31); + ++p1; + } + + while(p1 != p2) { + p1[0] += 32; + ++p1; + } + + if (px2 & 31) + p1[0] += px2 & 32; + } + } + + if (lasty >= 0) + RenderABuffer8_1024(dst, lasty >> 5, abuffer.data(), dst.w, color); + + return true; +} + +bool VDPixmapFillRegionAntialiased_16x_16x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { + if (dst.format != nsVDPixmap::kPixFormat_Y8) + return false; + + // fast out + if (region.mSpans.empty()) + return true; + + // check if vertical clipping is required + const size_t n = region.mSpans.size(); + uint32 start = 0; + uint32 end = n; + + uint32 spanmin = -x + (-y << 16) + 0x80008000; + + if (region.mSpans.front() < spanmin) { + // find first span : x2 > spanmin + start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); + start &= ~1; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w*16 - x) + (((dst.h*16 - y) - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // find last span : x1 < spanlimit + end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); + + end = (end + 1) & ~1; + + // check for total bottom clip + if (start >= end) + return true; + } + + // allocate A-buffer + vdfastvector abuffer(dst.w, 0); + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + + sint32 dstw16 = dst.w * 16; + sint32 dsth16 = dst.h * 16; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + sint32 py = (span0 >> 16) - 0x8000 + y; + + if ((uint32)py >= (uint32)dsth16) + continue; + + sint32 px1 = (span0 & 0xffff) - 0x8000 + x; + sint32 px2 = (span1 & 0xffff) - 0x8000 + x; + sint32 w = span1-span0; + + if (lasty != py) { + if (((lasty ^ py) & 0xFFFFFFF0)) { + if (lasty >= 0) { + // flush scanline + + RenderABuffer8_256(dst, lasty >> 4, abuffer.data(), dst.w, color); + } + + memset(abuffer.data(), 0, abuffer.size() * sizeof(abuffer[0])); + } + lasty = py; + } + + if (px1 < 0) + px1 = 0; + if (px2 > dstw16) + px2 = dstw16; + + if (px1 >= px2) + continue; + + uint32 ix1 = px1 >> 4; + uint32 ix2 = px2 >> 4; + uint16 *p1 = abuffer.data() + ix1; + uint16 *p2 = abuffer.data() + ix2; + + if (p1 == p2) { + p1[0] += (px2 - px1); + } else { + if (px1 & 15) { + p1[0] += 16 - (px1 & 15); + ++p1; + } + + while(p1 != p2) { + p1[0] += 16; + ++p1; + } + + if (px2 & 15) + p1[0] += px2 & 15; + } + } + + if (lasty >= 0) + RenderABuffer8_256(dst, lasty >> 4, abuffer.data(), dst.w, color); + + return true; +} + +bool VDPixmapFillRegionAntialiased_16x_8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { + if (dst.format != nsVDPixmap::kPixFormat_XRGB8888 && dst.format != nsVDPixmap::kPixFormat_Y8) + return false; + + // fast out + if (region.mSpans.empty()) + return true; + + // check if vertical clipping is required + const size_t n = region.mSpans.size(); + uint32 start = 0; + uint32 end = n; + + uint32 spanmin = -x + (-y << 16) + 0x80008000; + + if (region.mSpans.front() < spanmin) { + // find first span : x2 > spanmin + start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); + start &= ~1; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w*16 - x) + (((dst.h*8 - y) - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // find last span : x1 < spanlimit + end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); + + end = (end + 1) & ~1; + + // check for total bottom clip + if (start >= end) + return true; + } + + // allocate A-buffer + vdfastvector abuffer(dst.w, 0); + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + + sint32 dstw16 = dst.w * 16; + sint32 dsth8 = dst.h * 8; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + sint32 py = (span0 >> 16) - 0x8000 + y; + + if ((uint32)py >= (uint32)dsth8) + continue; + + sint32 px1 = (span0 & 0xffff) - 0x8000 + x; + sint32 px2 = (span1 & 0xffff) - 0x8000 + x; + sint32 w = span1-span0; + + if (lasty != py) { + if (((lasty ^ py) & 0xFFFFFFF8)) { + if (lasty >= 0) { + // flush scanline + + RenderABuffer8_128(dst, lasty >> 3, abuffer.data(), dst.w, color); + } + + memset(abuffer.data(), 0, abuffer.size()); + } + lasty = py; + } + + if (px1 < 0) + px1 = 0; + if (px2 > dstw16) + px2 = dstw16; + + if (px1 >= px2) + continue; + + uint32 ix1 = px1 >> 4; + uint32 ix2 = px2 >> 4; + uint8 *p1 = abuffer.data() + ix1; + uint8 *p2 = abuffer.data() + ix2; + + if (p1 == p2) { + p1[0] += (px2 - px1); + } else { + if (px1 & 15) { + p1[0] += 16 - (px1 & 15); + ++p1; + } + + while(p1 != p2) { + p1[0] += 16; + ++p1; + } + + if (px2 & 15) + p1[0] += px2 & 15; + } + } + + if (lasty >= 0) + RenderABuffer8_128(dst, lasty >> 3, abuffer.data(), dst.w, color); + + return true; +} + +bool VDPixmapFillRegionAntialiased8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color) { + switch(dst.format) { + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + { + VDPixmap pxY; + VDPixmap pxCb; + VDPixmap pxCr; + + pxY.format = nsVDPixmap::kPixFormat_Y8; + pxY.data = dst.data; + pxY.pitch = dst.pitch; + pxY.w = dst.w; + pxY.h = dst.h; + + pxCb.format = nsVDPixmap::kPixFormat_Y8; + pxCb.data = dst.data2; + pxCb.pitch = dst.pitch2; + pxCb.w = dst.w; + pxCb.h = dst.h; + + pxCr.format = nsVDPixmap::kPixFormat_Y8; + pxCr.data = dst.data3; + pxCr.pitch = dst.pitch3; + pxCr.w = dst.w; + pxCr.h = dst.h; + + uint32 colorY = (color >> 8) & 0xff; + uint32 colorCb = (color >> 0) & 0xff; + uint32 colorCr = (color >> 16) & 0xff; + + VDPixmapFillRegionAntialiased8x(pxY, region, x, y, colorY); + + switch(dst.format) { + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 2; + pxCr.h = pxCb.h = dst.h >> 2; + x >>= 2; + y >>= 2; + VDPixmapFillRegionAntialiased_32x_32x(pxCb, region, x, y, colorCb); + VDPixmapFillRegionAntialiased_32x_32x(pxCr, region, x, y, colorCr); + return true; + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 1; + pxCr.h = pxCb.h = dst.h >> 1; + x >>= 1; + y >>= 1; + x += 2; + VDPixmapFillRegionAntialiased_16x_16x(pxCb, region, x, y, colorCb); + VDPixmapFillRegionAntialiased_16x_16x(pxCr, region, x, y, colorCr); + return true; + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 1; + x >>= 1; + x += 2; + VDPixmapFillRegionAntialiased_16x_8x(pxCb, region, x, y, colorCb); + VDPixmapFillRegionAntialiased_16x_8x(pxCr, region, x, y, colorCr); + return true; + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + VDPixmapFillRegionAntialiased8x(pxCb, region, x, y, colorCb); + VDPixmapFillRegionAntialiased8x(pxCr, region, x, y, colorCr); + return true; + } + } + } + + if (dst.format != nsVDPixmap::kPixFormat_XRGB8888 && dst.format != nsVDPixmap::kPixFormat_Y8) + return false; + + // fast out + if (region.mSpans.empty()) + return true; + + // check if vertical clipping is required + const size_t n = region.mSpans.size(); + uint32 start = 0; + uint32 end = n; + + uint32 spanmin = -x + (-y << 16) + 0x80008000; + + if (region.mSpans.front() < spanmin) { + // find first span : x2 > spanmin + start = std::upper_bound(region.mSpans.begin(), region.mSpans.end(), spanmin) - region.mSpans.begin(); + start &= ~1; + + // check for total top clip + if (start >= n) + return true; + } + + uint32 spanlimit = (dst.w*8 - x) + (((dst.h*8 - y) - 1) << 16) + 0x80008000; + + if (region.mSpans.back() > spanlimit) { + // find last span : x1 < spanlimit + end = std::lower_bound(region.mSpans.begin(), region.mSpans.end(), spanlimit) - region.mSpans.begin(); + + end = (end + 1) & ~1; + + // check for total bottom clip + if (start >= end) + return true; + } + + // allocate A-buffer + vdfastvector abuffer(dst.w, 0); + + // fill region + const uint32 *pSpan = ®ion.mSpans[start]; + const uint32 *pEnd = ®ion.mSpans[0] + end; + int lasty = -1; + + sint32 dstw8 = dst.w * 8; + sint32 dsth8 = dst.h * 8; + + for(; pSpan != pEnd; pSpan += 2) { + uint32 span0 = pSpan[0]; + uint32 span1 = pSpan[1]; + + sint32 py = (span0 >> 16) - 0x8000 + y; + + if ((uint32)py >= (uint32)dsth8) + continue; + + sint32 px1 = (span0 & 0xffff) - 0x8000 + x; + sint32 px2 = (span1 & 0xffff) - 0x8000 + x; + sint32 w = span1-span0; + + if (lasty != py) { + if (((lasty ^ py) & 0xFFFFFFF8)) { + if (lasty >= 0) { + // flush scanline + + if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) + RenderABuffer32(dst, lasty >> 3, abuffer.data(), dst.w, color); + else + RenderABuffer8(dst, lasty >> 3, abuffer.data(), dst.w, color); + } + + memset(abuffer.data(), 0, abuffer.size()); + } + lasty = py; + } + + if (px1 < 0) + px1 = 0; + if (px2 > dstw8) + px2 = dstw8; + + if (px1 >= px2) + continue; + + uint32 ix1 = px1 >> 3; + uint32 ix2 = px2 >> 3; + uint8 *p1 = abuffer.data() + ix1; + uint8 *p2 = abuffer.data() + ix2; + + if (p1 == p2) { + p1[0] += (px2 - px1); + } else { + if (px1 & 7) { + p1[0] += 8 - (px1 & 7); + ++p1; + } + + while(p1 != p2) { + p1[0] += 8; + ++p1; + } + + if (px2 & 7) + p1[0] += px2 & 7; + } + } + + if (lasty >= 0) { + if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) + RenderABuffer32(dst, lasty >> 3, abuffer.data(), dst.w, color); + else + RenderABuffer8(dst, lasty >> 3, abuffer.data(), dst.w, color); + } + + return true; +} + +void VDPixmapCreateRoundRegion(VDPixmapRegion& dst, float r) { + int ir = VDCeilToInt(r); + float r2 = r*r; + + dst.mSpans.clear(); + dst.mBounds.set(-ir, 0, ir+1, 0); + + for(int y = -ir; y <= ir; ++y) { + int dx = VDCeilToInt(sqrtf(r2 - y*y)); + + if (dx > 0) { + dst.mSpans.push_back(0x80008000 + (y << 16) - dx); + dst.mSpans.push_back(0x80008001 + (y << 16) + dx); + if (dst.mBounds.top > y) + dst.mBounds.top = y; + if (dst.mBounds.bottom < y) + dst.mBounds.bottom = y; + } + } +} + +void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, int dx1, int dx2, int dy) { + dst.mSpans.clear(); + dst.mSpans.resize(r1.mSpans.size()+r2.mSpans.size()); + + const uint32 *itA = r1.mSpans.data(); + const uint32 *itAE = itA + r1.mSpans.size(); + const uint32 *itB = r2.mSpans.data(); + const uint32 *itBE = itB + r2.mSpans.size(); + uint32 *dstp0 = dst.mSpans.data(); + uint32 *dstp = dst.mSpans.data(); + + uint32 offset1 = (dy<<16) + dx1; + uint32 offset2 = (dy<<16) + dx2; + + while(itA != itAE && itB != itBE) { + uint32 x1; + uint32 x2; + + if (itB[0] + offset1 < itA[0]) { + // B span is earlier. Use it. + x1 = itB[0] + offset1; + x2 = itB[1] + offset2; + itB += 2; + + // B spans *can* overlap, due to the widening. + while(itB != itBE && itB[0]+offset1 <= x2) { + uint32 bx2 = itB[1] + offset2; + if (x2 < bx2) + x2 = bx2; + + itB += 2; + } + + goto a_start; + } else { + // A span is earlier. Use it. + x1 = itA[0]; + x2 = itA[1]; + itA += 2; + + // A spans don't overlap, so begin merge loop with B first. + } + + for(;;) { + // If we run out of B spans or the B span doesn't overlap, + // then the next A span can't either (because A spans don't + // overlap) and we exit. + + if (itB == itBE || itB[0]+offset1 > x2) + break; + + do { + uint32 bx2 = itB[1] + offset2; + if (x2 < bx2) + x2 = bx2; + + itB += 2; + } while(itB != itBE && itB[0]+offset1 <= x2); + + // If we run out of A spans or the A span doesn't overlap, + // then the next B span can't either, because we would have + // consumed all overlapping B spans in the above loop. +a_start: + if (itA == itAE || itA[0] > x2) + break; + + do { + uint32 ax2 = itA[1]; + if (x2 < ax2) + x2 = ax2; + + itA += 2; + } while(itA != itAE && itA[0] <= x2); + } + + // Flush span. + dstp[0] = x1; + dstp[1] = x2; + dstp += 2; + } + + // Copy over leftover spans. + memcpy(dstp, itA, sizeof(uint32)*(itAE - itA)); + dstp += itAE - itA; + + while(itB != itBE) { + // B span is earlier. Use it. + uint32 x1 = itB[0] + offset1; + uint32 x2 = itB[1] + offset2; + itB += 2; + + // B spans *can* overlap, due to the widening. + while(itB != itBE && itB[0]+offset1 <= x2) { + uint32 bx2 = itB[1] + offset2; + if (x2 < bx2) + x2 = bx2; + + itB += 2; + } + + dstp[0] = x1; + dstp[1] = x2; + dstp += 2; + } + + dst.mSpans.resize(dstp - dst.mSpans.data()); +} + +void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, VDPixmapRegion *tempCache) { + VDPixmapRegion temp; + + if (tempCache) { + tempCache->swap(temp); + + temp.clear(); + } + + const uint32 *src1 = r2.mSpans.data(); + const uint32 *src2 = src1 + r2.mSpans.size(); + + dst.mSpans.clear(); + while(src1 != src2) { + uint32 p1 = src1[0]; + uint32 p2 = src1[1]; + src1 += 2; + + temp.mSpans.swap(dst.mSpans); + VDPixmapConvolveRegion(dst, temp, r1, (p1 & 0xffff) - 0x8000, (p2 & 0xffff) - 0x8000, (p1 >> 16) - 0x8000); + } + + if (tempCache) + tempCache->swap(temp); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/resample.cpp b/src/thirdparty/VirtualDub/Kasumi/source/resample.cpp index e4705517e4c..8a57be9e3a2 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/resample.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/resample.cpp @@ -1,416 +1,416 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "uberblit_gen.h" - -/////////////////////////////////////////////////////////////////////////// -// -// the resampler (finally) -// -/////////////////////////////////////////////////////////////////////////// - -class VDPixmapResampler : public IVDPixmapResampler { -public: - VDPixmapResampler(); - ~VDPixmapResampler(); - - void SetSplineFactor(double A) { mSplineFactor = A; } - void SetFilters(FilterMode h, FilterMode v, bool interpolationOnly); - bool Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat); - bool Init(const vdrect32f& dstrect, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect, uint32 sw, uint32 sh, int srcformat); - void Shutdown(); - - void Process(const VDPixmap& dst, const VDPixmap& src); - -protected: - void ApplyFilters(VDPixmapUberBlitterGenerator& gen, uint32 dw, uint32 dh, float xoffset, float yoffset, float xfactor, float yfactor); - - vdautoptr mpBlitter; - vdautoptr mpBlitter2; - double mSplineFactor; - FilterMode mFilterH; - FilterMode mFilterV; - bool mbInterpOnly; - - vdrect32 mDstRectPlane0; - vdrect32 mDstRectPlane12; -}; - -IVDPixmapResampler *VDCreatePixmapResampler() { return new VDPixmapResampler; } - -VDPixmapResampler::VDPixmapResampler() - : mSplineFactor(-0.6) - , mFilterH(kFilterCubic) - , mFilterV(kFilterCubic) - , mbInterpOnly(false) -{ -} - -VDPixmapResampler::~VDPixmapResampler() { - Shutdown(); -} - -void VDPixmapResampler::SetFilters(FilterMode h, FilterMode v, bool interpolationOnly) { - mFilterH = h; - mFilterV = v; - mbInterpOnly = interpolationOnly; -} - -bool VDPixmapResampler::Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat) { - vdrect32f rSrc(0.0f, 0.0f, (float)sw, (float)sh); - vdrect32f rDst(0.0f, 0.0f, (float)dw, (float)dh); - return Init(rDst, dw, dh, dstformat, rSrc, sw, sh, srcformat); -} - -bool VDPixmapResampler::Init(const vdrect32f& dstrect0, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect0, uint32 sw, uint32 sh, int srcformat) { - Shutdown(); - - if (dstformat != srcformat) - return false; - - switch(srcformat) { - case nsVDPixmap::kPixFormat_XRGB8888: - case nsVDPixmap::kPixFormat_Y8: - case nsVDPixmap::kPixFormat_Y8_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar: - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - break; - - default: - return false; - } - - // convert destination flips to source flips - vdrect32f dstrect(dstrect0); - vdrect32f srcrect(srcrect0); - - if (dstrect.left > dstrect.right) { - std::swap(dstrect.left, dstrect.right); - std::swap(srcrect.left, srcrect.right); - } - - if (dstrect.top > dstrect.bottom) { - std::swap(dstrect.top, dstrect.bottom); - std::swap(srcrect.top, srcrect.bottom); - } - - // compute source step factors - float xfactor = (float)srcrect.width() / (float)dstrect.width(); - float yfactor = (float)srcrect.height() / (float)dstrect.height(); - - // clip destination rect - if (dstrect.left < 0) { - float clipx1 = -dstrect.left; - srcrect.left += xfactor * clipx1; - dstrect.left = 0.0f; - } - - if (dstrect.top < 0) { - float clipy1 = -dstrect.top; - srcrect.top += yfactor * clipy1; - dstrect.top = 0.0f; - } - - float clipx2 = dstrect.right - (float)dw; - if (clipx2 > 0) { - srcrect.right -= xfactor * clipx2; - dstrect.right = (float)dw; - } - - float clipy2 = dstrect.bottom - (float)dh; - if (clipy2 > 0) { - srcrect.bottom -= yfactor * clipy2; - dstrect.bottom = (float)dh; - } - - // compute plane 0 dest rect in integral quanta - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dstformat); - mDstRectPlane0.left = VDCeilToInt(dstrect.left - 0.5f); - mDstRectPlane0.top = VDCeilToInt(dstrect.top - 0.5f); - mDstRectPlane0.right = VDCeilToInt(dstrect.right - 0.5f); - mDstRectPlane0.bottom = VDCeilToInt(dstrect.bottom - 0.5f); - - // compute plane 0 stepping parameters - float xoffset = (((float)mDstRectPlane0.left + 0.5f) - dstrect.left) * xfactor + srcrect.left; - float yoffset = (((float)mDstRectPlane0.top + 0.5f) - dstrect.top ) * yfactor + srcrect.top; - - // compute plane 1/2 dest rect and stepping parameters - float xoffset2 = 0.0f; - float yoffset2 = 0.0f; - - if (formatInfo.auxbufs > 0) { - float xf2 = (float)(1 << formatInfo.auxwbits); - float yf2 = (float)(1 << formatInfo.auxhbits); - float invxf2 = 1.0f / xf2; - float invyf2 = 1.0f / yf2; - - // convert source and dest rects to plane 1/2 space - vdrect32f srcrect2(srcrect); - vdrect32f dstrect2(dstrect); - - srcrect2.scale(invxf2, invyf2); - dstrect2.scale(invxf2, invyf2); - - switch(srcformat) { - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - break; - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - srcrect2.translate(0.25f, 0.0f); - dstrect2.translate(0.25f, 0.0f); - break; - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - srcrect2.translate(0.25f, 0.0f); - dstrect2.translate(0.25f, 0.0f); - break; - case nsVDPixmap::kPixFormat_YUV411_Planar: - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - srcrect2.translate(0.375f, 0.0f); - dstrect2.translate(0.375f, 0.0f); - break; - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - break; - default: - VDASSERT(false); - } - - mDstRectPlane12.left = VDCeilToInt(dstrect2.left - 0.5f); - mDstRectPlane12.top = VDCeilToInt(dstrect2.top - 0.5f); - mDstRectPlane12.right = VDCeilToInt(dstrect2.right - 0.5f); - mDstRectPlane12.bottom = VDCeilToInt(dstrect2.bottom - 0.5f); - - xoffset2 = (((float)mDstRectPlane12.left + 0.5f) - dstrect2.left) * xfactor + srcrect2.left; - yoffset2 = (((float)mDstRectPlane12.top + 0.5f) - dstrect2.top ) * yfactor + srcrect2.top; - } - - VDPixmapUberBlitterGenerator gen; - - switch(srcformat) { - case nsVDPixmap::kPixFormat_XRGB8888: - gen.ldsrc(0, 0, 0, 0, sw, sh, VDPixmapGetFormatTokenFromFormat(srcformat), sw*4); - ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); - break; - - case nsVDPixmap::kPixFormat_Y8: - gen.ldsrc(0, 0, 0, 0, sw, sh, kVDPixType_8, sw); - ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); - break; - - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV411_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - gen.ldsrc(0, 0, 0, 0, sw, sh, kVDPixType_8, sw); - ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); - - { - const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstformat); - uint32 subsw = -(-(sint32)sw >> info.auxwbits); - uint32 subsh = -(-(sint32)sh >> info.auxhbits); - - VDPixmapUberBlitterGenerator gen2; - gen2.ldsrc(0, 0, 0, 0, subsw, subsh, kVDPixType_8, subsw); - ApplyFilters(gen2, mDstRectPlane12.width(), mDstRectPlane12.height(), xoffset2, yoffset2, xfactor, yfactor); - mpBlitter2 = gen2.create(); - if (!mpBlitter2) - return false; - } - break; - } - - mpBlitter = gen.create(); - if (!mpBlitter) - return false; - - return true; -} - -void VDPixmapResampler::Shutdown() { - mpBlitter = NULL; - mpBlitter2 = NULL; -} - -void VDPixmapResampler::Process(const VDPixmap& dst, const VDPixmap& src) { - if (!mpBlitter) - return; - - switch(dst.format) { - case nsVDPixmap::kPixFormat_XRGB8888: - case nsVDPixmap::kPixFormat_Y8: - mpBlitter->Blit(dst, &mDstRectPlane0, src); - break; - - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV411_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV411_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - // blit primary plane - mpBlitter->Blit(dst, &mDstRectPlane0, src); - - // slice and blit secondary planes - { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); - VDPixmap pxdst; - pxdst.format = nsVDPixmap::kPixFormat_Y8; - pxdst.w = -(-dst.w >> formatInfo.auxwbits); - pxdst.h = -(-dst.h >> formatInfo.auxhbits); - pxdst.pitch = dst.pitch2; - pxdst.data = dst.data2; - - VDPixmap pxsrc; - pxsrc.format = nsVDPixmap::kPixFormat_Y8; - pxsrc.w = -(-src.w >> formatInfo.auxwbits); - pxsrc.h = -(-src.h >> formatInfo.auxhbits); - pxsrc.pitch = src.pitch2; - pxsrc.data = src.data2; - - mpBlitter2->Blit(pxdst, &mDstRectPlane12, pxsrc); - - pxdst.pitch = dst.pitch3; - pxdst.data = dst.data3; - pxsrc.pitch = src.pitch3; - pxsrc.data = src.data3; - mpBlitter2->Blit(pxdst, &mDstRectPlane12, pxsrc); - } - break; - } -} - -void VDPixmapResampler::ApplyFilters(VDPixmapUberBlitterGenerator& gen, uint32 dw, uint32 dh, float xoffset, float yoffset, float xfactor, float yfactor) { - switch(mFilterH) { - case kFilterPoint: - gen.pointh(xoffset, xfactor, dw); - break; - - case kFilterLinear: - gen.linearh(xoffset, xfactor, dw, mbInterpOnly); - break; - - case kFilterCubic: - gen.cubich(xoffset, xfactor, dw, (float)mSplineFactor, mbInterpOnly); - break; - - case kFilterLanczos3: - gen.lanczos3h(xoffset, xfactor, dw); - break; - } - - switch(mFilterV) { - case kFilterPoint: - gen.pointv(yoffset, yfactor, dh); - break; - - case kFilterLinear: - gen.linearv(yoffset, yfactor, dh, mbInterpOnly); - break; - - case kFilterCubic: - gen.cubicv(yoffset, yfactor, dh, (float)mSplineFactor, mbInterpOnly); - break; - - case kFilterLanczos3: - gen.lanczos3v(yoffset, yfactor, dh); - break; - } -} - -bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter) { - VDPixmapResampler r; - - r.SetFilters(filter, filter, false); - - if (!r.Init(dst.w, dst.h, dst.format, src.w, src.h, src.format)) - return false; - - r.Process(dst, src); - return true; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uberblit_gen.h" + +/////////////////////////////////////////////////////////////////////////// +// +// the resampler (finally) +// +/////////////////////////////////////////////////////////////////////////// + +class VDPixmapResampler : public IVDPixmapResampler { +public: + VDPixmapResampler(); + ~VDPixmapResampler(); + + void SetSplineFactor(double A) { mSplineFactor = A; } + void SetFilters(FilterMode h, FilterMode v, bool interpolationOnly); + bool Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat); + bool Init(const vdrect32f& dstrect, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect, uint32 sw, uint32 sh, int srcformat); + void Shutdown(); + + void Process(const VDPixmap& dst, const VDPixmap& src); + +protected: + void ApplyFilters(VDPixmapUberBlitterGenerator& gen, uint32 dw, uint32 dh, float xoffset, float yoffset, float xfactor, float yfactor); + + vdautoptr mpBlitter; + vdautoptr mpBlitter2; + double mSplineFactor; + FilterMode mFilterH; + FilterMode mFilterV; + bool mbInterpOnly; + + vdrect32 mDstRectPlane0; + vdrect32 mDstRectPlane12; +}; + +IVDPixmapResampler *VDCreatePixmapResampler() { return new VDPixmapResampler; } + +VDPixmapResampler::VDPixmapResampler() + : mSplineFactor(-0.6) + , mFilterH(kFilterCubic) + , mFilterV(kFilterCubic) + , mbInterpOnly(false) +{ +} + +VDPixmapResampler::~VDPixmapResampler() { + Shutdown(); +} + +void VDPixmapResampler::SetFilters(FilterMode h, FilterMode v, bool interpolationOnly) { + mFilterH = h; + mFilterV = v; + mbInterpOnly = interpolationOnly; +} + +bool VDPixmapResampler::Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat) { + vdrect32f rSrc(0.0f, 0.0f, (float)sw, (float)sh); + vdrect32f rDst(0.0f, 0.0f, (float)dw, (float)dh); + return Init(rDst, dw, dh, dstformat, rSrc, sw, sh, srcformat); +} + +bool VDPixmapResampler::Init(const vdrect32f& dstrect0, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect0, uint32 sw, uint32 sh, int srcformat) { + Shutdown(); + + if (dstformat != srcformat) + return false; + + switch(srcformat) { + case nsVDPixmap::kPixFormat_XRGB8888: + case nsVDPixmap::kPixFormat_Y8: + case nsVDPixmap::kPixFormat_Y8_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar: + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + break; + + default: + return false; + } + + // convert destination flips to source flips + vdrect32f dstrect(dstrect0); + vdrect32f srcrect(srcrect0); + + if (dstrect.left > dstrect.right) { + std::swap(dstrect.left, dstrect.right); + std::swap(srcrect.left, srcrect.right); + } + + if (dstrect.top > dstrect.bottom) { + std::swap(dstrect.top, dstrect.bottom); + std::swap(srcrect.top, srcrect.bottom); + } + + // compute source step factors + float xfactor = (float)srcrect.width() / (float)dstrect.width(); + float yfactor = (float)srcrect.height() / (float)dstrect.height(); + + // clip destination rect + if (dstrect.left < 0) { + float clipx1 = -dstrect.left; + srcrect.left += xfactor * clipx1; + dstrect.left = 0.0f; + } + + if (dstrect.top < 0) { + float clipy1 = -dstrect.top; + srcrect.top += yfactor * clipy1; + dstrect.top = 0.0f; + } + + float clipx2 = dstrect.right - (float)dw; + if (clipx2 > 0) { + srcrect.right -= xfactor * clipx2; + dstrect.right = (float)dw; + } + + float clipy2 = dstrect.bottom - (float)dh; + if (clipy2 > 0) { + srcrect.bottom -= yfactor * clipy2; + dstrect.bottom = (float)dh; + } + + // compute plane 0 dest rect in integral quanta + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dstformat); + mDstRectPlane0.left = VDCeilToInt(dstrect.left - 0.5f); + mDstRectPlane0.top = VDCeilToInt(dstrect.top - 0.5f); + mDstRectPlane0.right = VDCeilToInt(dstrect.right - 0.5f); + mDstRectPlane0.bottom = VDCeilToInt(dstrect.bottom - 0.5f); + + // compute plane 0 stepping parameters + float xoffset = (((float)mDstRectPlane0.left + 0.5f) - dstrect.left) * xfactor + srcrect.left; + float yoffset = (((float)mDstRectPlane0.top + 0.5f) - dstrect.top ) * yfactor + srcrect.top; + + // compute plane 1/2 dest rect and stepping parameters + float xoffset2 = 0.0f; + float yoffset2 = 0.0f; + + if (formatInfo.auxbufs > 0) { + float xf2 = (float)(1 << formatInfo.auxwbits); + float yf2 = (float)(1 << formatInfo.auxhbits); + float invxf2 = 1.0f / xf2; + float invyf2 = 1.0f / yf2; + + // convert source and dest rects to plane 1/2 space + vdrect32f srcrect2(srcrect); + vdrect32f dstrect2(dstrect); + + srcrect2.scale(invxf2, invyf2); + dstrect2.scale(invxf2, invyf2); + + switch(srcformat) { + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + break; + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + srcrect2.translate(0.25f, 0.0f); + dstrect2.translate(0.25f, 0.0f); + break; + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + srcrect2.translate(0.25f, 0.0f); + dstrect2.translate(0.25f, 0.0f); + break; + case nsVDPixmap::kPixFormat_YUV411_Planar: + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + srcrect2.translate(0.375f, 0.0f); + dstrect2.translate(0.375f, 0.0f); + break; + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + break; + default: + VDASSERT(false); + } + + mDstRectPlane12.left = VDCeilToInt(dstrect2.left - 0.5f); + mDstRectPlane12.top = VDCeilToInt(dstrect2.top - 0.5f); + mDstRectPlane12.right = VDCeilToInt(dstrect2.right - 0.5f); + mDstRectPlane12.bottom = VDCeilToInt(dstrect2.bottom - 0.5f); + + xoffset2 = (((float)mDstRectPlane12.left + 0.5f) - dstrect2.left) * xfactor + srcrect2.left; + yoffset2 = (((float)mDstRectPlane12.top + 0.5f) - dstrect2.top ) * yfactor + srcrect2.top; + } + + VDPixmapUberBlitterGenerator gen; + + switch(srcformat) { + case nsVDPixmap::kPixFormat_XRGB8888: + gen.ldsrc(0, 0, 0, 0, sw, sh, VDPixmapGetFormatTokenFromFormat(srcformat), sw*4); + ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); + break; + + case nsVDPixmap::kPixFormat_Y8: + gen.ldsrc(0, 0, 0, 0, sw, sh, kVDPixType_8, sw); + ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); + break; + + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV411_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + gen.ldsrc(0, 0, 0, 0, sw, sh, kVDPixType_8, sw); + ApplyFilters(gen, mDstRectPlane0.width(), mDstRectPlane0.height(), xoffset, yoffset, xfactor, yfactor); + + { + const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstformat); + uint32 subsw = -(-(sint32)sw >> info.auxwbits); + uint32 subsh = -(-(sint32)sh >> info.auxhbits); + + VDPixmapUberBlitterGenerator gen2; + gen2.ldsrc(0, 0, 0, 0, subsw, subsh, kVDPixType_8, subsw); + ApplyFilters(gen2, mDstRectPlane12.width(), mDstRectPlane12.height(), xoffset2, yoffset2, xfactor, yfactor); + mpBlitter2 = gen2.create(); + if (!mpBlitter2) + return false; + } + break; + } + + mpBlitter = gen.create(); + if (!mpBlitter) + return false; + + return true; +} + +void VDPixmapResampler::Shutdown() { + mpBlitter = NULL; + mpBlitter2 = NULL; +} + +void VDPixmapResampler::Process(const VDPixmap& dst, const VDPixmap& src) { + if (!mpBlitter) + return; + + switch(dst.format) { + case nsVDPixmap::kPixFormat_XRGB8888: + case nsVDPixmap::kPixFormat_Y8: + mpBlitter->Blit(dst, &mDstRectPlane0, src); + break; + + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV411_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV411_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV411_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + // blit primary plane + mpBlitter->Blit(dst, &mDstRectPlane0, src); + + // slice and blit secondary planes + { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); + VDPixmap pxdst; + pxdst.format = nsVDPixmap::kPixFormat_Y8; + pxdst.w = -(-dst.w >> formatInfo.auxwbits); + pxdst.h = -(-dst.h >> formatInfo.auxhbits); + pxdst.pitch = dst.pitch2; + pxdst.data = dst.data2; + + VDPixmap pxsrc; + pxsrc.format = nsVDPixmap::kPixFormat_Y8; + pxsrc.w = -(-src.w >> formatInfo.auxwbits); + pxsrc.h = -(-src.h >> formatInfo.auxhbits); + pxsrc.pitch = src.pitch2; + pxsrc.data = src.data2; + + mpBlitter2->Blit(pxdst, &mDstRectPlane12, pxsrc); + + pxdst.pitch = dst.pitch3; + pxdst.data = dst.data3; + pxsrc.pitch = src.pitch3; + pxsrc.data = src.data3; + mpBlitter2->Blit(pxdst, &mDstRectPlane12, pxsrc); + } + break; + } +} + +void VDPixmapResampler::ApplyFilters(VDPixmapUberBlitterGenerator& gen, uint32 dw, uint32 dh, float xoffset, float yoffset, float xfactor, float yfactor) { + switch(mFilterH) { + case kFilterPoint: + gen.pointh(xoffset, xfactor, dw); + break; + + case kFilterLinear: + gen.linearh(xoffset, xfactor, dw, mbInterpOnly); + break; + + case kFilterCubic: + gen.cubich(xoffset, xfactor, dw, (float)mSplineFactor, mbInterpOnly); + break; + + case kFilterLanczos3: + gen.lanczos3h(xoffset, xfactor, dw); + break; + } + + switch(mFilterV) { + case kFilterPoint: + gen.pointv(yoffset, yfactor, dh); + break; + + case kFilterLinear: + gen.linearv(yoffset, yfactor, dh, mbInterpOnly); + break; + + case kFilterCubic: + gen.cubicv(yoffset, yfactor, dh, (float)mSplineFactor, mbInterpOnly); + break; + + case kFilterLanczos3: + gen.lanczos3v(yoffset, yfactor, dh); + break; + } +} + +bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter) { + VDPixmapResampler r; + + r.SetFilters(filter, filter, false); + + if (!r.Init(dst.w, dst.h, dst.format, src.w, src.h, src.format)) + return false; + + r.Process(dst, src); + return true; +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/resample_kernels.cpp b/src/thirdparty/VirtualDub/Kasumi/source/resample_kernels.cpp index 2307f703237..86911b3256e 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/resample_kernels.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/resample_kernels.cpp @@ -1,292 +1,292 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// -// utility functions -// -/////////////////////////////////////////////////////////////////////////// - -namespace { - inline sint32 scale32x32_fp16(sint32 x, sint32 y) { - return (sint32)(((sint64)x * y + 0x8000) >> 16); - } - - inline double sinc(double x) { - return fabs(x) < 1e-9 ? 1.0 : sin(x) / x; - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDResamplerAxis -// -/////////////////////////////////////////////////////////////////////////// - -void VDResamplerAxis::Init(sint32 dudx) { - this->dudx = dudx; -} - -void VDResamplerAxis::Compute(sint32 count, sint32 u0, sint32 w, sint32 kernel_width) { - u = u0; - dx = count; - - sint32 du_kern = (kernel_width-1) << 16; - sint32 u2 = u + dudx*(dx-1); - sint32 u_limit = w << 16; - - dx_precopy = 0; - dx_preclip = 0; - dx_active = 0; - dx_postclip = 0; - dx_postcopy = 0; - dx_dualclip = 0; - - if (dudx == 0) { - if (u < -du_kern) - dx_precopy = w; - else if (u >= u_limit) - dx_postcopy = w; - else if (u < 0) { - if (u + du_kern < u_limit) - dx_preclip = w; - else - dx_dualclip = w; - } else if (u + du_kern >= u_limit) - dx_postclip = w; - else - dx_active = w; - - return; - } - - sint32 dx_temp = dx; - sint32 u_start = u; - - // (desired - u0 + (dudx-1)) / dudx : first pixel >= desired - - sint32 dudx_m1_mu0 = dudx - 1 - u; - sint32 first_preclip = (dudx_m1_mu0 + 0x10000 - du_kern) / dudx; - sint32 first_active = (dudx_m1_mu0 ) / dudx; - sint32 first_postclip = (dudx_m1_mu0 + u_limit - du_kern) / dudx; - sint32 first_postcopy = (dudx_m1_mu0 + u_limit - 0x10000) / dudx; - - // clamp - if (first_preclip < 0) - first_preclip = 0; - if (first_active < first_preclip) - first_active = first_preclip; - if (first_postclip < first_active) - first_postclip = first_active; - if (first_postcopy < first_postclip) - first_postcopy = first_postclip; - if (first_preclip > dx) - first_preclip = dx; - if (first_active > dx) - first_active = dx; - if (first_postclip > dx) - first_postclip = dx; - if (first_postcopy > dx) - first_postcopy = dx; - - // determine widths - - dx_precopy = first_preclip; - dx_preclip = first_active - first_preclip; - dx_active = first_postclip - first_active; - dx_postclip = first_postcopy - first_postclip; - dx_postcopy = dx - first_postcopy; - - // sanity checks - sint32 pos0 = dx_precopy; - sint32 pos1 = pos0 + dx_preclip; - sint32 pos2 = pos1 + dx_active; - sint32 pos3 = pos2 + dx_postclip; - - VDASSERT(!((dx_precopy|dx_preclip|dx_active|dx_postcopy|dx_postclip) & 0x80000000)); - VDASSERT(dx_precopy + dx_preclip + dx_active + dx_postcopy + dx_postclip == dx); - - VDASSERT(!pos0 || u_start + dudx*(pos0 - 1) < 0x10000 - du_kern); // precopy -> preclip - VDASSERT( pos0 >= pos1 || u_start + dudx*(pos0 ) >= 0x10000 - du_kern); - VDASSERT( pos1 <= pos0 || u_start + dudx*(pos1 - 1) < 0); // preclip -> active - VDASSERT( pos1 >= pos2 || u_start + dudx*(pos1 ) >= 0 || !dx_active); - VDASSERT( pos2 <= pos1 || u_start + dudx*(pos2 - 1) < u_limit - du_kern || !dx_active); // active -> postclip - VDASSERT( pos2 >= pos3 || u_start + dudx*(pos2 ) >= u_limit - du_kern); - VDASSERT( pos3 <= pos2 || u_start + dudx*(pos3 - 1) < u_limit - 0x10000); // postclip -> postcopy - VDASSERT( pos3 >= dx || u_start + dudx*(pos3 ) >= u_limit - 0x10000); - - u += dx_precopy * dudx; - - // test for overlapping clipping regions - if (!dx_active && kernel_width > w) { - dx_dualclip = dx_preclip + dx_postclip; - dx_preclip = dx_postclip = 0; - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDResamplerLinearFilter -// -/////////////////////////////////////////////////////////////////////////// - -VDResamplerLinearFilter::VDResamplerLinearFilter(double twofc) - : mScale(twofc) - , mTaps((int)ceil(1.0 / twofc) * 2) -{ -} - -int VDResamplerLinearFilter::GetFilterWidth() const { - return mTaps; -} - -double VDResamplerLinearFilter::EvaluateFilter(double t) const { - t = 1.0f - fabs(t)*mScale; - - return t + fabs(t); -} - -void VDResamplerLinearFilter::GenerateFilter(float *dst, double offset) const { - double pos = -((double)((mTaps>>1)-1) + offset) * mScale; - - for(unsigned i=0; i>1)-1) + offset) * mScale; - - for(unsigned i=0; i>1)-1) + offset) * mScale); - - for(unsigned i=0; i +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// +// utility functions +// +/////////////////////////////////////////////////////////////////////////// + +namespace { + inline sint32 scale32x32_fp16(sint32 x, sint32 y) { + return (sint32)(((sint64)x * y + 0x8000) >> 16); + } + + inline double sinc(double x) { + return fabs(x) < 1e-9 ? 1.0 : sin(x) / x; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDResamplerAxis +// +/////////////////////////////////////////////////////////////////////////// + +void VDResamplerAxis::Init(sint32 dudx) { + this->dudx = dudx; +} + +void VDResamplerAxis::Compute(sint32 count, sint32 u0, sint32 w, sint32 kernel_width) { + u = u0; + dx = count; + + sint32 du_kern = (kernel_width-1) << 16; + sint32 u2 = u + dudx*(dx-1); + sint32 u_limit = w << 16; + + dx_precopy = 0; + dx_preclip = 0; + dx_active = 0; + dx_postclip = 0; + dx_postcopy = 0; + dx_dualclip = 0; + + if (dudx == 0) { + if (u < -du_kern) + dx_precopy = w; + else if (u >= u_limit) + dx_postcopy = w; + else if (u < 0) { + if (u + du_kern < u_limit) + dx_preclip = w; + else + dx_dualclip = w; + } else if (u + du_kern >= u_limit) + dx_postclip = w; + else + dx_active = w; + + return; + } + + sint32 dx_temp = dx; + sint32 u_start = u; + + // (desired - u0 + (dudx-1)) / dudx : first pixel >= desired + + sint32 dudx_m1_mu0 = dudx - 1 - u; + sint32 first_preclip = (dudx_m1_mu0 + 0x10000 - du_kern) / dudx; + sint32 first_active = (dudx_m1_mu0 ) / dudx; + sint32 first_postclip = (dudx_m1_mu0 + u_limit - du_kern) / dudx; + sint32 first_postcopy = (dudx_m1_mu0 + u_limit - 0x10000) / dudx; + + // clamp + if (first_preclip < 0) + first_preclip = 0; + if (first_active < first_preclip) + first_active = first_preclip; + if (first_postclip < first_active) + first_postclip = first_active; + if (first_postcopy < first_postclip) + first_postcopy = first_postclip; + if (first_preclip > dx) + first_preclip = dx; + if (first_active > dx) + first_active = dx; + if (first_postclip > dx) + first_postclip = dx; + if (first_postcopy > dx) + first_postcopy = dx; + + // determine widths + + dx_precopy = first_preclip; + dx_preclip = first_active - first_preclip; + dx_active = first_postclip - first_active; + dx_postclip = first_postcopy - first_postclip; + dx_postcopy = dx - first_postcopy; + + // sanity checks + sint32 pos0 = dx_precopy; + sint32 pos1 = pos0 + dx_preclip; + sint32 pos2 = pos1 + dx_active; + sint32 pos3 = pos2 + dx_postclip; + + VDASSERT(!((dx_precopy|dx_preclip|dx_active|dx_postcopy|dx_postclip) & 0x80000000)); + VDASSERT(dx_precopy + dx_preclip + dx_active + dx_postcopy + dx_postclip == dx); + + VDASSERT(!pos0 || u_start + dudx*(pos0 - 1) < 0x10000 - du_kern); // precopy -> preclip + VDASSERT( pos0 >= pos1 || u_start + dudx*(pos0 ) >= 0x10000 - du_kern); + VDASSERT( pos1 <= pos0 || u_start + dudx*(pos1 - 1) < 0); // preclip -> active + VDASSERT( pos1 >= pos2 || u_start + dudx*(pos1 ) >= 0 || !dx_active); + VDASSERT( pos2 <= pos1 || u_start + dudx*(pos2 - 1) < u_limit - du_kern || !dx_active); // active -> postclip + VDASSERT( pos2 >= pos3 || u_start + dudx*(pos2 ) >= u_limit - du_kern); + VDASSERT( pos3 <= pos2 || u_start + dudx*(pos3 - 1) < u_limit - 0x10000); // postclip -> postcopy + VDASSERT( pos3 >= dx || u_start + dudx*(pos3 ) >= u_limit - 0x10000); + + u += dx_precopy * dudx; + + // test for overlapping clipping regions + if (!dx_active && kernel_width > w) { + dx_dualclip = dx_preclip + dx_postclip; + dx_preclip = dx_postclip = 0; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDResamplerLinearFilter +// +/////////////////////////////////////////////////////////////////////////// + +VDResamplerLinearFilter::VDResamplerLinearFilter(double twofc) + : mScale(twofc) + , mTaps((int)ceil(1.0 / twofc) * 2) +{ +} + +int VDResamplerLinearFilter::GetFilterWidth() const { + return mTaps; +} + +double VDResamplerLinearFilter::EvaluateFilter(double t) const { + t = 1.0f - fabs(t)*mScale; + + return t + fabs(t); +} + +void VDResamplerLinearFilter::GenerateFilter(float *dst, double offset) const { + double pos = -((double)((mTaps>>1)-1) + offset) * mScale; + + for(unsigned i=0; i>1)-1) + offset) * mScale; + + for(unsigned i=0; i>1)-1) + offset) * mScale); + + for(unsigned i=0; i -#include -#include -#include -#include "resample_stages.h" - -VDSteppedAllocator::VDSteppedAllocator(size_t initialSize) - : mpHead(NULL) - , mpAllocNext(NULL) - , mAllocLeft(0) - , mAllocNext(initialSize) - , mAllocInit(initialSize) -{ -} - -VDSteppedAllocator::~VDSteppedAllocator() { - clear(); -} - -void VDSteppedAllocator::clear() { - while(Block *p = mpHead) { - mpHead = mpHead->next; - free(p); - } - mAllocLeft = 0; - mAllocNext = mAllocInit; -} - -void *VDSteppedAllocator::allocate(size_type n) { - n = (n+15) & ~15; - if (mAllocLeft < n) { - mAllocLeft = mAllocNext; - mAllocNext += (mAllocNext >> 1); - if (mAllocLeft < n) - mAllocLeft = n; - - Block *t = (Block *)malloc(sizeof(Block) + mAllocLeft); - - if (mpHead) - mpHead->next = t; - - mpHead = t; - mpHead->next = NULL; - - mpAllocNext = (char *)(mpHead + 1); - } - - void *p = mpAllocNext; - mpAllocNext += n; - mAllocLeft -= n; - return p; -} - -void VDResamplerGenerateTable(sint32 *dst, const IVDResamplerFilter& filter) { - const unsigned width = filter.GetFilterWidth(); - vdblock filters(width * 256); - float *src = filters.data(); - - filter.GenerateFilterBank(src); - - for(unsigned phase=0; phase < 256; ++phase) { - float sum = 0; - - for(unsigned i=0; i filters(width); - float *src = filters.data(); - - filter.GenerateFilterBank(src); - - for(sint32 i=0; i> 16; - filter.GenerateFilter(src, (double)(u & 0xffff) / 65536.0); - - float sum = 0; - for(uint32 j=0; j> 31) - 1; - while(ierr) { - for(uint32 j=0; j +#include +#include +#include +#include "resample_stages.h" + +VDSteppedAllocator::VDSteppedAllocator(size_t initialSize) + : mpHead(NULL) + , mpAllocNext(NULL) + , mAllocLeft(0) + , mAllocNext(initialSize) + , mAllocInit(initialSize) +{ +} + +VDSteppedAllocator::~VDSteppedAllocator() { + clear(); +} + +void VDSteppedAllocator::clear() { + while(Block *p = mpHead) { + mpHead = mpHead->next; + free(p); + } + mAllocLeft = 0; + mAllocNext = mAllocInit; +} + +void *VDSteppedAllocator::allocate(size_type n) { + n = (n+15) & ~15; + if (mAllocLeft < n) { + mAllocLeft = mAllocNext; + mAllocNext += (mAllocNext >> 1); + if (mAllocLeft < n) + mAllocLeft = n; + + Block *t = (Block *)malloc(sizeof(Block) + mAllocLeft); + + if (mpHead) + mpHead->next = t; + + mpHead = t; + mpHead->next = NULL; + + mpAllocNext = (char *)(mpHead + 1); + } + + void *p = mpAllocNext; + mpAllocNext += n; + mAllocLeft -= n; + return p; +} + +void VDResamplerGenerateTable(sint32 *dst, const IVDResamplerFilter& filter) { + const unsigned width = filter.GetFilterWidth(); + vdblock filters(width * 256); + float *src = filters.data(); + + filter.GenerateFilterBank(src); + + for(unsigned phase=0; phase < 256; ++phase) { + float sum = 0; + + for(unsigned i=0; i filters(width); + float *src = filters.data(); + + filter.GenerateFilterBank(src); + + for(sint32 i=0; i> 16; + filter.GenerateFilter(src, (double)(u & 0xffff) / 65536.0); + + float sum = 0; + for(uint32 j=0; j> 31) - 1; + while(ierr) { + for(uint32 j=0; j -#include -#include -#include -#include "resample_stages_reference.h" -#include -#include "blt_spanutils.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -int VDResamplerRowStageSeparablePoint8::GetWindowSize() const { - return 1; -} - -void VDResamplerRowStageSeparablePoint8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - do { - *dst++ = src[u>>16]; - u += dudx; - } while(--w); -} - -int VDResamplerRowStageSeparablePoint16::GetWindowSize() const { - return 1; -} - -void VDResamplerRowStageSeparablePoint16::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint16 *dst = (uint16 *)dst0; - const uint16 *src = (const uint16 *)src0; - - do { - *dst++ = src[u>>16]; - u += dudx; - } while(--w); -} - -int VDResamplerRowStageSeparablePoint32::GetWindowSize() const { - return 1; -} - -void VDResamplerRowStageSeparablePoint32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - do { - *dst++ = src[u>>16]; - u += dudx; - } while(--w); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -int VDResamplerRowStageSeparableLinear8::GetWindowSize() const {return 2;} -void VDResamplerRowStageSeparableLinear8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - do { - const sint32 iu = u>>16; - const uint32 p0 = src[iu]; - const uint32 p1 = src[iu+1]; - const uint32 f = (u >> 8) & 0xff; - - *dst++ = (uint8)(p0 + (((sint32)(p1 - p0)*f + 0x80)>>8)); - u += dudx; - } while(--w); -} - -void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - VDASSERT(!u && dudx == 0x8000); - - nsVDPixmapSpanUtils::horiz_expand2x_coaligned(dst, src, w); -} - -int VDResamplerRowStageSeparableLinear32::GetWindowSize() const {return 2;} -void VDResamplerRowStageSeparableLinear32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - - do { - const sint32 iu = u>>16; - const uint32 p0 = src[iu]; - const uint32 p1 = src[iu+1]; - const uint32 f = (u >> 8) & 0xff; - - const uint32 p0_rb = p0 & 0xff00ff; - const uint32 p1_rb = p1 & 0xff00ff; - const uint32 p0_g = p0 & 0xff00; - const uint32 p1_g = p1 & 0xff00; - - *dst++ = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff) - + ((p0_g + (((p1_g - p0_g )*f + 0x008000)>>8)) & 0x00ff00); - u += dudx; - } while(--w); -} - -int VDResamplerColStageSeparableLinear8::GetWindowSize() const {return 2;} -void VDResamplerColStageSeparableLinear8::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src0 = (const uint8 *)srcarray[0]; - const uint8 *src1 = (const uint8 *)srcarray[1]; - const uint32 f = (phase >> 8) & 0xff; - - do { - const uint32 p0 = *src0++; - const uint32 p1 = *src1++; - - *dst++ = (uint8)(p0 + (((p1 - p0)*f + 0x80)>>8)); - } while(--w); -} - -int VDResamplerColStageSeparableLinear32::GetWindowSize() const {return 2;} -void VDResamplerColStageSeparableLinear32::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src0 = (const uint32 *)srcarray[0]; - const uint32 *src1 = (const uint32 *)srcarray[1]; - const uint32 f = (phase >> 8) & 0xff; - - do { - const uint32 p0 = *src0++; - const uint32 p1 = *src1++; - - const uint32 p0_rb = p0 & 0xff00ff; - const uint32 p1_rb = p1 & 0xff00ff; - const uint32 p0_g = p0 & 0xff00; - const uint32 p1_g = p1 & 0xff00; - - *dst++ = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff) - + ((p0_g + (((p1_g - p0_g )*f + 0x008000)>>8)) & 0x00ff00); - } while(--w); -} - -VDResamplerRowStageSeparableTable8::VDResamplerRowStageSeparableTable8(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTable(mFilterBank.data(), filter); -} - -int VDResamplerRowStageSeparableTable8::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerRowStageSeparableTable8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - const unsigned ksize = (int)mFilterBank.size() >> 8; - const sint32 *filterBase = mFilterBank.data(); - - do { - const uint8 *src2 = src + (u>>16); - const sint32 *filter = filterBase + ksize*((u>>8)&0xff); - u += dudx; - - int b = 0x2000; - for(unsigned i = ksize; i; --i) { - uint8 p = *src2++; - sint32 coeff = *filter++; - - b += (sint32)p*coeff; - } - - b >>= 14; - - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - *dst++ = (uint8)b; - } while(--w); -} - -VDResamplerRowStageSeparableTable32::VDResamplerRowStageSeparableTable32(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTable(mFilterBank.data(), filter); -} - -int VDResamplerRowStageSeparableTable32::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerRowStageSeparableTable32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint32 *dst = (uint32 *)dst0; - const uint32 *src = (const uint32 *)src0; - const unsigned ksize = (int)mFilterBank.size() >> 8; - const sint32 *filterBase = mFilterBank.data(); - - do { - const uint32 *src2 = src + (u>>16); - const sint32 *filter = filterBase + ksize*((u>>8)&0xff); - u += dudx; - - int r = 0x2000, g = 0x2000, b = 0x2000; - for(unsigned i = ksize; i; --i) { - uint32 p = *src2++; - sint32 coeff = *filter++; - - r += ((p>>16)&0xff)*coeff; - g += ((p>> 8)&0xff)*coeff; - b += ((p )&0xff)*coeff; - } - - r <<= 2; - g >>= 6; - b >>= 14; - - if ((uint32)r >= 0x01000000) - r = ~r >> 31; - if ((uint32)g >= 0x00010000) - g = ~g >> 31; - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff); - } while(--w); -} - -VDResamplerRowStageSeparableTable32Fx4::VDResamplerRowStageSeparableTable32Fx4(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTableF(mFilterBank.data(), filter); -} - -int VDResamplerRowStageSeparableTable32Fx4::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerRowStageSeparableTable32Fx4::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - float *dst = (float *)dst0; - const float *src = (const float *)src0; - const unsigned ksize = (int)mFilterBank.size() >> 8; - const float *filterBase = mFilterBank.data(); - - do { - const float *src2 = src + (u>>16)*4; - const float *filter = filterBase + ksize*((u>>8)&0xff); - u += dudx; - - float r = 0, g = 0, b = 0, a = 0; - for(unsigned i = ksize; i; --i) { - float coeff = *filter++; - - r += coeff * src2[0]; - g += coeff * src2[1]; - b += coeff * src2[2]; - a += coeff * src2[3]; - src2 += 4; - } - - dst[0] = r; - dst[1] = g; - dst[2] = b; - dst[3] = a; - dst += 4; - } while(--w); -} - -VDResamplerRowStageSeparableTable32F::VDResamplerRowStageSeparableTable32F(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTableF(mFilterBank.data(), filter); -} - -int VDResamplerRowStageSeparableTable32F::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerRowStageSeparableTable32F::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - float *dst = (float *)dst0; - const float *src = (const float *)src0; - const unsigned ksize = (int)mFilterBank.size() >> 8; - const float *filterBase = mFilterBank.data(); - - VDCPUCleanupExtensions(); - - do { - const float *src2 = src + (u>>16); - const float *filter = filterBase + ksize*((u>>8)&0xff); - u += dudx; - - float r = 0; - for(unsigned i = ksize; i; --i) { - float coeff = *filter++; - - r += coeff * src2[0]; - ++src2; - } - - dst[0] = r; - ++dst; - } while(--w); -} - -VDResamplerColStageSeparableTable8::VDResamplerColStageSeparableTable8(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTable(mFilterBank.data(), filter); -} - -int VDResamplerColStageSeparableTable8::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerColStageSeparableTable8::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - uint8 *dst = (uint8 *)dst0; - const uint8 *const *src = (const uint8 *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; - - for(uint32 i=0; i>= 14; - - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - *dst++ = (uint8)b; - } -} - -VDResamplerColStageSeparableTable32::VDResamplerColStageSeparableTable32(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTable(mFilterBank.data(), filter); -} - -int VDResamplerColStageSeparableTable32::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerColStageSeparableTable32::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - uint32 *dst = (uint32 *)dst0; - const uint32 *const *src = (const uint32 *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; - - for(uint32 i=0; i>16)&0xff)*coeff; - g += ((p>> 8)&0xff)*coeff; - b += ((p )&0xff)*coeff; - } - - r <<= 2; - g >>= 6; - b >>= 14; - - if ((uint32)r >= 0x01000000) - r = ~r >> 31; - if ((uint32)g >= 0x00010000) - g = ~g >> 31; - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff); - } -} - -VDResamplerColStageSeparableTable32F::VDResamplerColStageSeparableTable32F(const IVDResamplerFilter& filter) { - mFilterBank.resize(filter.GetFilterWidth() * 256); - VDResamplerGenerateTableF(mFilterBank.data(), filter); -} - -int VDResamplerColStageSeparableTable32F::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} - -void VDResamplerColStageSeparableTable32F::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - float *dst = (float *)dst0; - const float *const *src = (const float *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const float *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; - - for(uint32 i=0; i> 8;} - -void VDResamplerColStageSeparableTable32Fx4::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - float *dst = (float *)dst0; - const float *const *src = (const float *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const float *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; - - for(uint32 i=0; i +#include +#include +#include +#include "resample_stages_reference.h" +#include +#include "blt_spanutils.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +int VDResamplerRowStageSeparablePoint8::GetWindowSize() const { + return 1; +} + +void VDResamplerRowStageSeparablePoint8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + do { + *dst++ = src[u>>16]; + u += dudx; + } while(--w); +} + +int VDResamplerRowStageSeparablePoint16::GetWindowSize() const { + return 1; +} + +void VDResamplerRowStageSeparablePoint16::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint16 *dst = (uint16 *)dst0; + const uint16 *src = (const uint16 *)src0; + + do { + *dst++ = src[u>>16]; + u += dudx; + } while(--w); +} + +int VDResamplerRowStageSeparablePoint32::GetWindowSize() const { + return 1; +} + +void VDResamplerRowStageSeparablePoint32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + do { + *dst++ = src[u>>16]; + u += dudx; + } while(--w); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +int VDResamplerRowStageSeparableLinear8::GetWindowSize() const {return 2;} +void VDResamplerRowStageSeparableLinear8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + do { + const sint32 iu = u>>16; + const uint32 p0 = src[iu]; + const uint32 p1 = src[iu+1]; + const uint32 f = (u >> 8) & 0xff; + + *dst++ = (uint8)(p0 + (((sint32)(p1 - p0)*f + 0x80)>>8)); + u += dudx; + } while(--w); +} + +void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + VDASSERT(!u && dudx == 0x8000); + + nsVDPixmapSpanUtils::horiz_expand2x_coaligned(dst, src, w); +} + +int VDResamplerRowStageSeparableLinear32::GetWindowSize() const {return 2;} +void VDResamplerRowStageSeparableLinear32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + + do { + const sint32 iu = u>>16; + const uint32 p0 = src[iu]; + const uint32 p1 = src[iu+1]; + const uint32 f = (u >> 8) & 0xff; + + const uint32 p0_rb = p0 & 0xff00ff; + const uint32 p1_rb = p1 & 0xff00ff; + const uint32 p0_g = p0 & 0xff00; + const uint32 p1_g = p1 & 0xff00; + + *dst++ = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff) + + ((p0_g + (((p1_g - p0_g )*f + 0x008000)>>8)) & 0x00ff00); + u += dudx; + } while(--w); +} + +int VDResamplerColStageSeparableLinear8::GetWindowSize() const {return 2;} +void VDResamplerColStageSeparableLinear8::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src0 = (const uint8 *)srcarray[0]; + const uint8 *src1 = (const uint8 *)srcarray[1]; + const uint32 f = (phase >> 8) & 0xff; + + do { + const uint32 p0 = *src0++; + const uint32 p1 = *src1++; + + *dst++ = (uint8)(p0 + (((p1 - p0)*f + 0x80)>>8)); + } while(--w); +} + +int VDResamplerColStageSeparableLinear32::GetWindowSize() const {return 2;} +void VDResamplerColStageSeparableLinear32::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src0 = (const uint32 *)srcarray[0]; + const uint32 *src1 = (const uint32 *)srcarray[1]; + const uint32 f = (phase >> 8) & 0xff; + + do { + const uint32 p0 = *src0++; + const uint32 p1 = *src1++; + + const uint32 p0_rb = p0 & 0xff00ff; + const uint32 p1_rb = p1 & 0xff00ff; + const uint32 p0_g = p0 & 0xff00; + const uint32 p1_g = p1 & 0xff00; + + *dst++ = ((p0_rb + (((p1_rb - p0_rb)*f + 0x800080)>>8)) & 0xff00ff) + + ((p0_g + (((p1_g - p0_g )*f + 0x008000)>>8)) & 0x00ff00); + } while(--w); +} + +VDResamplerRowStageSeparableTable8::VDResamplerRowStageSeparableTable8(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTable(mFilterBank.data(), filter); +} + +int VDResamplerRowStageSeparableTable8::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerRowStageSeparableTable8::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + const unsigned ksize = (int)mFilterBank.size() >> 8; + const sint32 *filterBase = mFilterBank.data(); + + do { + const uint8 *src2 = src + (u>>16); + const sint32 *filter = filterBase + ksize*((u>>8)&0xff); + u += dudx; + + int b = 0x2000; + for(unsigned i = ksize; i; --i) { + uint8 p = *src2++; + sint32 coeff = *filter++; + + b += (sint32)p*coeff; + } + + b >>= 14; + + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + *dst++ = (uint8)b; + } while(--w); +} + +VDResamplerRowStageSeparableTable32::VDResamplerRowStageSeparableTable32(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTable(mFilterBank.data(), filter); +} + +int VDResamplerRowStageSeparableTable32::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerRowStageSeparableTable32::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint32 *dst = (uint32 *)dst0; + const uint32 *src = (const uint32 *)src0; + const unsigned ksize = (int)mFilterBank.size() >> 8; + const sint32 *filterBase = mFilterBank.data(); + + do { + const uint32 *src2 = src + (u>>16); + const sint32 *filter = filterBase + ksize*((u>>8)&0xff); + u += dudx; + + int r = 0x2000, g = 0x2000, b = 0x2000; + for(unsigned i = ksize; i; --i) { + uint32 p = *src2++; + sint32 coeff = *filter++; + + r += ((p>>16)&0xff)*coeff; + g += ((p>> 8)&0xff)*coeff; + b += ((p )&0xff)*coeff; + } + + r <<= 2; + g >>= 6; + b >>= 14; + + if ((uint32)r >= 0x01000000) + r = ~r >> 31; + if ((uint32)g >= 0x00010000) + g = ~g >> 31; + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff); + } while(--w); +} + +VDResamplerRowStageSeparableTable32Fx4::VDResamplerRowStageSeparableTable32Fx4(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTableF(mFilterBank.data(), filter); +} + +int VDResamplerRowStageSeparableTable32Fx4::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerRowStageSeparableTable32Fx4::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + float *dst = (float *)dst0; + const float *src = (const float *)src0; + const unsigned ksize = (int)mFilterBank.size() >> 8; + const float *filterBase = mFilterBank.data(); + + do { + const float *src2 = src + (u>>16)*4; + const float *filter = filterBase + ksize*((u>>8)&0xff); + u += dudx; + + float r = 0, g = 0, b = 0, a = 0; + for(unsigned i = ksize; i; --i) { + float coeff = *filter++; + + r += coeff * src2[0]; + g += coeff * src2[1]; + b += coeff * src2[2]; + a += coeff * src2[3]; + src2 += 4; + } + + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + dst += 4; + } while(--w); +} + +VDResamplerRowStageSeparableTable32F::VDResamplerRowStageSeparableTable32F(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTableF(mFilterBank.data(), filter); +} + +int VDResamplerRowStageSeparableTable32F::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerRowStageSeparableTable32F::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + float *dst = (float *)dst0; + const float *src = (const float *)src0; + const unsigned ksize = (int)mFilterBank.size() >> 8; + const float *filterBase = mFilterBank.data(); + + VDCPUCleanupExtensions(); + + do { + const float *src2 = src + (u>>16); + const float *filter = filterBase + ksize*((u>>8)&0xff); + u += dudx; + + float r = 0; + for(unsigned i = ksize; i; --i) { + float coeff = *filter++; + + r += coeff * src2[0]; + ++src2; + } + + dst[0] = r; + ++dst; + } while(--w); +} + +VDResamplerColStageSeparableTable8::VDResamplerColStageSeparableTable8(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTable(mFilterBank.data(), filter); +} + +int VDResamplerColStageSeparableTable8::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerColStageSeparableTable8::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + uint8 *dst = (uint8 *)dst0; + const uint8 *const *src = (const uint8 *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; + + for(uint32 i=0; i>= 14; + + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + *dst++ = (uint8)b; + } +} + +VDResamplerColStageSeparableTable32::VDResamplerColStageSeparableTable32(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTable(mFilterBank.data(), filter); +} + +int VDResamplerColStageSeparableTable32::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerColStageSeparableTable32::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + uint32 *dst = (uint32 *)dst0; + const uint32 *const *src = (const uint32 *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const sint32 *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; + + for(uint32 i=0; i>16)&0xff)*coeff; + g += ((p>> 8)&0xff)*coeff; + b += ((p )&0xff)*coeff; + } + + r <<= 2; + g >>= 6; + b >>= 14; + + if ((uint32)r >= 0x01000000) + r = ~r >> 31; + if ((uint32)g >= 0x00010000) + g = ~g >> 31; + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + *dst++ = (r & 0xff0000) + (g & 0xff00) + (b & 0xff); + } +} + +VDResamplerColStageSeparableTable32F::VDResamplerColStageSeparableTable32F(const IVDResamplerFilter& filter) { + mFilterBank.resize(filter.GetFilterWidth() * 256); + VDResamplerGenerateTableF(mFilterBank.data(), filter); +} + +int VDResamplerColStageSeparableTable32F::GetWindowSize() const {return (int)mFilterBank.size() >> 8;} + +void VDResamplerColStageSeparableTable32F::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + float *dst = (float *)dst0; + const float *const *src = (const float *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const float *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; + + for(uint32 i=0; i> 8;} + +void VDResamplerColStageSeparableTable32Fx4::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + float *dst = (float *)dst0; + const float *const *src = (const float *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const float *filter = &mFilterBank[((phase>>8)&0xff) * ksize]; + + for(uint32 i=0; i> 1); -} - -void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_SSE2((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) - : VDResamplerColStageSeparableTable32(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (uint32)mFilterBank.size() >> 1); -} - -void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { - const unsigned filtSize = (unsigned)mFilterBank.size() >> 8; - - vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data() + filtSize*((phase >> 8) & 0xff), filtSize, w); -} +#include "stdafx.h" // MPC-HC patch +#include "resample_stages_x64.h" + +extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w); +extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); + +VDResamplerSeparableTableRowStageSSE2::VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter) + : VDResamplerRowStageSeparableTable32(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (uint32)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_SSE2((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) + : VDResamplerColStageSeparableTable32(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (uint32)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { + const unsigned filtSize = (unsigned)mFilterBank.size() >> 8; + + vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data() + filtSize*((phase >> 8) & 0xff), filtSize, w); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/resample_stages_x86.cpp b/src/thirdparty/VirtualDub/Kasumi/source/resample_stages_x86.cpp index ff5ffb11f76..123fa17c41f 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/resample_stages_x86.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/resample_stages_x86.cpp @@ -1,1296 +1,1296 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include "blt_spanutils_x86.h" -#include "resample_stages_x86.h" -#include - -#ifdef _MSC_VER - #pragma warning(disable: 4799) // warning C4799: function 'vdasm_resize_table_row_8_k8_4x_MMX' has no EMMS instruction -#endif - -/////////////////////////////////////////////////////////////////////////////// - -extern "C" void vdasm_resize_table_row_8_k8_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); -extern "C" void vdasm_resize_table_row_8_k16_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); -extern "C" void vdasm_resize_table_row_8_SSE41(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth); -extern "C" void vdasm_resize_table_col_8_k2_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); -extern "C" void vdasm_resize_table_col_8_k4_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); - -/////////////////////////////////////////////////////////////////////////////// - -namespace { - struct ScaleInfo { - void *dst; - uintptr src; - uint32 accum; - uint32 fracinc; - sint32 intinc; - uint32 count; - }; - - extern "C" void vdasm_resize_point32(const ScaleInfo *); -} - -int VDResamplerSeparablePointRowStageX86::GetWindowSize() const {return 1;} -void VDResamplerSeparablePointRowStageX86::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - ScaleInfo info; - - info.dst = (uint32 *)dst + w; - info.src = ((uintptr)src >> 2) + (u>>16); - info.accum = u<<16; - info.fracinc = dudx << 16; - info.intinc = (sint32)dudx >> 16; - info.count = -(sint32)w*4; - - vdasm_resize_point32(&info); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - uint8 *dst = (uint8 *)dst0; - const uint8 *src = (const uint8 *)src0; - - nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE(dst, src, w); -} - -/////////////////////////////////////////////////////////////////////////////// - -extern "C" void vdasm_resize_point32_MMX(const ScaleInfo *); -extern "C" void vdasm_resize_interp_row_run_MMX(void *dst, const void *src, uint32 width, sint64 xaccum, sint64 x_inc); -extern "C" void vdasm_resize_interp_col_run_MMX(void *dst, const void *src1, const void *src2, uint32 width, uint32 yaccum); -extern "C" void vdasm_resize_ccint_row_MMX(void *dst, const void *src, uint32 count, uint32 xaccum, sint32 xinc, const void *tbl); -extern "C" void vdasm_resize_ccint_col_MMX(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); -extern "C" long vdasm_resize_table_col_MMX(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); -extern "C" long vdasm_resize_table_row_MMX(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); - -int VDResamplerSeparablePointRowStageMMX::GetWindowSize() const {return 1;} -void VDResamplerSeparablePointRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - ScaleInfo info; - - info.dst = (uint32 *)dst + w; - info.src = ((uintptr)src >> 2) + (u>>16); - info.accum = u<<16; - info.fracinc = dudx << 16; - info.intinc = (sint32)dudx >> 16; - info.count = -(sint32)w*4; - - vdasm_resize_point32_MMX(&info); -} - -int VDResamplerSeparableLinearRowStageMMX::GetWindowSize() const {return 2;} -void VDResamplerSeparableLinearRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_interp_row_run_MMX(dst0, src0, w, (sint64)u << 16, (sint64)dudx << 16); -} - -int VDResamplerSeparableLinearColStageMMX::GetWindowSize() const {return 2;} -void VDResamplerSeparableLinearColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - vdasm_resize_interp_col_run_MMX(dst0, srcarray[0], srcarray[1], w, phase); -} - -VDResamplerSeparableCubicRowStageMMX::VDResamplerSeparableCubicRowStageMMX(double A) - : mFilterBank(1024) -{ - sint32 *p = mFilterBank.data(); - VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); - VDResamplerSwizzleTable(p, 512); -} - -int VDResamplerSeparableCubicRowStageMMX::GetWindowSize() const {return 4;} -void VDResamplerSeparableCubicRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_ccint_row_MMX(dst0, src0, w, u, dudx, mFilterBank.data()); -} - -VDResamplerSeparableCubicColStageMMX::VDResamplerSeparableCubicColStageMMX(double A) - : mFilterBank(1024) -{ - sint32 *p = mFilterBank.data(); - VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); - VDResamplerSwizzleTable(p, 512); -} - -int VDResamplerSeparableCubicColStageMMX::GetWindowSize() const {return 4;} -void VDResamplerSeparableCubicColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - vdasm_resize_ccint_col_MMX(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); -} - -VDResamplerSeparableTableRowStage8MMX::VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter) - : VDResamplerRowStageSeparableTable32(filter) - , mLastSrcWidth(0) - , mLastDstWidth(0) - , mLastU(0) - , mLastDUDX(0) -{ - mAlignedKernelWidth = (GetWindowSize() + 6) & ~3; - mAlignedKernelSize = mAlignedKernelWidth + 4; -} - -void VDResamplerSeparableTableRowStage8MMX::Init(const VDResamplerAxis& axis, uint32 srcw) { - uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; - - if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { - mLastSrcWidth = srcw; - mLastDstWidth = w; - mLastU = axis.u; - mLastDUDX = axis.dudx; - - RedoRowFilters(axis, w, srcw); - } -} - -void VDResamplerSeparableTableRowStage8MMX::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { - int kstride = mFilterBank.size() >> 8; - int ksize = mAlignedKernelWidth; - int kesize = mAlignedKernelSize; - - mRowKernels.clear(); - mRowKernelSize = w * kesize; - - mRowKernels.resize(mRowKernelSize * 4, 0); - - for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { - sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; - int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 3) & ~3); - - mKernelSizeByOffset[byteOffset] = ksizeThisOffset; - - sint32 u = axis.u; - sint32 uoffmin = -byteOffset; - sint32 uoffmax = ((srcw + byteOffset + 3) & ~3) - byteOffset - ksizeThisOffset; - for(uint32 i=0; i> 16; - sint32 uoffset2 = ((uoffset + byteOffset) & ~3) - byteOffset; - - if (uoffset2 < uoffmin) - uoffset2 = uoffmin; - - if (uoffset2 > uoffmax) - uoffset2 = uoffmax; - - VDASSERT(uoffset2 + ksizeThisOffset <= (((sint32)srcw + byteOffset + 3) & ~3)); - - *(sint32 *)dst = uoffset2; - dst += 2; - *dst++ = 0; - *dst++ = 0; - - uint32 phase = (u >> 8) & 255; - const sint32 *src = &mFilterBank[kstride * phase]; - - sint32 start = 0; - sint32 end = kstride; - - int dstoffset = uoffset - uoffset2; - - // check for filter kernel overlapping left source boundary - if (uoffset < 0) - start = -uoffset; - - // check for filter kernel overlapping right source boundary - if (uoffset + end > (sint32)srcw) - end = srcw - uoffset; - - VDASSERT(dstoffset + start >= 0); - VDASSERT(dstoffset + end <= ksizeThisOffset); - - sint16 *dst2 = dst + dstoffset; - dst += ksizeThisOffset; - - for(int j=start; j 0) - dst2[start] = std::accumulate(src, src+start, dst2[start]); - - if (end < kstride) - dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); - - u += axis.dudx; - } - } - - // swizzle rows where optimization is possible - vdfastvector temp; - - int quads = w >> 2; - int quadRemainder = w & 3; - - for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { - int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; - int kpairs = ksizeThisOffset >> 2; - - if (ksizeThisOffset < 8 || ksizeThisOffset > 12) { - mbQuadOptimizationEnabled[byteOffset] = false; - } else { - ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 2; - - mbQuadOptimizationEnabled[byteOffset] = true; - mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); - - uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; - temp.resize(mRowKernelSize); - memcpy(temp.data(), dst, mRowKernelSize*2); - - const uint32 *src0 = (const uint32 *)temp.data(); - const uint32 *src1 = src0 + unswizzledStride; - const uint32 *src2 = src1 + unswizzledStride; - const uint32 *src3 = src2 + unswizzledStride; - ptrdiff_t srcskip = unswizzledStride * 3; - - for(int q = 0; q < quads; ++q) { - dst[0] = src0[0]; - dst[1] = src1[0]; - dst[2] = src2[0]; - dst[3] = src3[0]; - src0 += 2; - src1 += 2; - src2 += 2; - src3 += 2; - dst += 4; - - for(int p = 0; p < kpairs; ++p) { - dst[0] = src0[0]; - dst[1] = src0[1]; - dst[2] = src1[0]; - dst[3] = src1[1]; - dst[4] = src2[0]; - dst[5] = src2[1]; - dst[6] = src3[0]; - dst[7] = src3[1]; - dst += 8; - src0 += 2; - src1 += 2; - src2 += 2; - src3 += 2; - } - - src0 += srcskip; - src1 += srcskip; - src2 += srcskip; - src3 += srcskip; - } - - memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); - - VDASSERT(dst + unswizzledStride * quadRemainder <= (void *)(mRowKernels.data() + (mRowKernelSize * (byteOffset + 1)))); - } - } -} - -void __declspec(naked) vdasm_resize_table_row_8_k8_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { - static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov ebp, [esp + 4 + 16] ;ebp = dst - mov esi, [esp + 12 + 16] ;esi = width - mov edi, [esp + 16 + 16] ;edi = kernel -yloop: - ;eax = temp - ;ebx = temp - ;ecx = temp - ;edx = temp - ;esi = horiz counter - ;edi = filter list - ;ebp = destination - - mov eax, [edi+0] - mov ebx, [edi+4] - mov ecx, [edi+8] - mov edx, [esp+8+16] - add eax, edx - add ebx, edx - add ecx, edx - add edx, [edi+12] - - movd mm0, [eax] - punpcklbw mm0, mm7 - - pmaddwd mm0, [edi+16] - movd mm1, [ebx] - punpcklbw mm1, mm7 - - pmaddwd mm1, [edi+24] - movd mm2, [ecx] - punpcklbw mm2, mm7 - - pmaddwd mm2, [edi+32] - movd mm3, [edx] - punpcklbw mm3, mm7 - - pmaddwd mm3, [edi+40] - movd mm4, [eax+4] - paddd mm0, mm6 - - movd mm5, [ebx+4] - punpcklbw mm4, mm7 - paddd mm1, mm6 - - pmaddwd mm4, [edi+48] - punpcklbw mm5, mm7 - paddd mm2, mm6 - - pmaddwd mm5, [edi+56] - paddd mm3, mm6 - paddd mm0, mm4 - - paddd mm1, mm5 - movd mm4, [ecx+4] - punpcklbw mm4, mm7 - - pmaddwd mm4, [edi+64] - movd mm5, [edx+4] - punpcklbw mm5, mm7 - - pmaddwd mm5, [edi+72] - paddd mm2, mm4 - paddd mm3, mm5 - - movq mm4, mm0 - punpckldq mm0, mm1 - movq mm5, mm2 - punpckldq mm2, mm3 - punpckhdq mm4, mm1 - punpckhdq mm5, mm3 - paddd mm0, mm4 - paddd mm2, mm5 - psrad mm0, 14 - psrad mm2, 14 - - packssdw mm0, mm2 - packuswb mm0, mm0 - - add edi, 80 - - movd [ebp], mm0 - add ebp, 4 - sub esi, 1 - jne yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void __declspec(naked) vdasm_resize_table_row_8_k12_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { - static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov ebp, [esp + 4 + 16] ;ebp = dst - mov esi, [esp + 12 + 16] ;esi = width - mov edi, [esp + 16 + 16] ;edi = kernel -yloop: - ;eax = temp - ;ebx = temp - ;ecx = temp - ;edx = temp - ;esi = horiz counter - ;edi = filter list - ;ebp = destination - - mov eax, [edi+0] - mov ebx, [edi+4] - mov ecx, [edi+8] - mov edx, [esp+8+16] - add eax, edx - add ebx, edx - add ecx, edx - add edx, [edi+12] - - movd mm0, [eax] - punpcklbw mm0, mm7 - - pmaddwd mm0, [edi+16] - movd mm1, [ebx] - punpcklbw mm1, mm7 - - pmaddwd mm1, [edi+24] - movd mm2, [ecx] - punpcklbw mm2, mm7 - - pmaddwd mm2, [edi+32] - movd mm3, [edx] - punpcklbw mm3, mm7 - - pmaddwd mm3, [edi+40] - movd mm4, [eax+4] - punpcklbw mm4, mm7 - - pmaddwd mm4, [edi+48] - movd mm5, [ebx+4] - punpcklbw mm5, mm7 - - pmaddwd mm5, [edi+56] - paddd mm0, mm4 - paddd mm1, mm5 - - movd mm4, [ecx+4] - punpcklbw mm4, mm7 - movd mm5, [edx+4] - - pmaddwd mm4, [edi+64] - punpcklbw mm5, mm7 - paddd mm2, mm4 - - pmaddwd mm5, [edi+72] - movd mm4, [eax+8] - punpcklbw mm4, mm7 - - paddd mm3, mm5 - movd mm5, [ebx+8] - punpcklbw mm5, mm7 - - pmaddwd mm4, [edi+80] - paddd mm0, mm4 - movd mm4, [ecx+8] - - pmaddwd mm5, [edi+88] - paddd mm1, mm5 - punpcklbw mm4, mm7 - - pmaddwd mm4, [edi+96] - movd mm5, [edx+8] - punpcklbw mm5, mm7 - - pmaddwd mm5, [edi+104] - paddd mm2, mm4 - paddd mm3, mm5 - - movq mm4, mm0 - punpckldq mm0, mm1 - movq mm5, mm2 - punpckldq mm2, mm3 - punpckhdq mm4, mm1 - punpckhdq mm5, mm3 - paddd mm0, mm4 - paddd mm2, mm5 - paddd mm0, mm6 - paddd mm2, mm6 - psrad mm0, 14 - psrad mm2, 14 - - packssdw mm0, mm2 - packuswb mm0, mm0 - - add edi, 112 - - movd [ebp], mm0 - add ebp, 4 - sub esi, 1 - jne yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void __declspec(naked) vdasm_resize_table_row_8_MMX(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth) { - static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov edi, [esp + 4 + 16] ;edi = dst - mov ebx, [esp + 8 + 16] ;ebx = src - mov ebp, [esp + 12 + 16] ;ebp = width - mov edx, [esp + 16 + 16] ;edx = kernel -yloop: - ;eax = temp - ;ebx = source base address - ;ecx = (temp) source - ;edx = filter list - ;esi = (temp) kernel width - ;edi = destination - ;ebp = horiz counter - - mov eax, [edx] - add edx, 8 - lea ecx, [ebx + eax] - mov esi, [esp + 20 + 16] ;esi = kernel width - - movq mm2, mm6 -xloop: - movd mm0, [ecx] - punpcklbw mm0, mm7 - add ecx, 4 - pmaddwd mm0, [edx] - paddd mm2, mm0 - add edx, 8 - sub esi, 4 - jne xloop - - punpckldq mm0, mm2 - paddd mm0, mm2 - psrad mm0, 14 - psrlq mm0, 32 - packssdw mm0, mm0 - packuswb mm0, mm0 - movd eax, mm0 - mov [edi], al - add edi, 1 - sub ebp, 1 - jne yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w) { - int byteOffset = (int)(ptrdiff_t)src & 3; - const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); -#if 0 - int kwidth = mAlignedKernelWidth; - uint8 *dst2 = (uint8 *)dst; - - do { - int offset = ksrc[0]; - ksrc += 4; - - const uint8 *src2 = (const uint8 *)src + offset; - sint32 accum = 0x8000; - for(int i=0; i>= 14; - - accum &= ~(accum >> 31); - accum |= (255 - accum) >> 31; - - *dst2++ = (uint8)accum; - - } while(--w); -#else - int ksize = mKernelSizeByOffset[byteOffset]; - if (mbQuadOptimizationEnabled[byteOffset]) { - if (w >= 4) { - if (ksize == 12) { - vdasm_resize_table_row_8_k12_4x_MMX(dst, src, w >> 2, ksrc); - -#if 0 - int w4 = w >> 2; - uint8 *dst2 = (uint8 *)dst; - const uint8 *src2 = (const uint8 *)src; - const sint16 *ksrc2 = ksrc; - - do { - int off0 = ksrc2[0]; - int off1 = ksrc2[2]; - int off2 = ksrc2[4]; - int off3 = ksrc2[6]; - const uint8 *d0 = src2 + off0; - const uint8 *d1 = src2 + off1; - const uint8 *d2 = src2 + off2; - const uint8 *d3 = src2 + off3; - - int acc0 = 0; - int acc1 = 0; - int acc2 = 0; - int acc3 = 0; - - acc0 += d0[ 0]*ksrc2[ 8] - + d0[ 1]*ksrc2[ 9] - + d0[ 2]*ksrc2[ 10] - + d0[ 3]*ksrc2[ 11] - + d0[ 4]*ksrc2[ 24] - + d0[ 5]*ksrc2[ 25] - + d0[ 6]*ksrc2[ 26] - + d0[ 7]*ksrc2[ 27] - + d0[ 8]*ksrc2[ 40] - + d0[ 9]*ksrc2[ 41] - + d0[10]*ksrc2[ 42] - + d0[11]*ksrc2[ 43]; - - acc0 = (acc0 + 0x2000) >> 14; - if (acc0 < 0) acc0 = 0; else if (acc0 > 255) acc0 = 255; - - acc1 += d1[ 0]*ksrc2[ 12] - + d1[ 1]*ksrc2[ 13] - + d1[ 2]*ksrc2[ 14] - + d1[ 3]*ksrc2[ 15] - + d1[ 4]*ksrc2[ 28] - + d1[ 5]*ksrc2[ 29] - + d1[ 6]*ksrc2[ 30] - + d1[ 7]*ksrc2[ 31] - + d1[ 8]*ksrc2[ 44] - + d1[ 9]*ksrc2[ 45] - + d1[10]*ksrc2[ 46] - + d1[11]*ksrc2[ 47]; - - acc1 = (acc1 + 0x2000) >> 14; - if (acc1 < 0) acc1 = 0; else if (acc1 > 255) acc1 = 255; - - acc2 += d2[ 0]*ksrc2[ 16] - + d2[ 1]*ksrc2[ 17] - + d2[ 2]*ksrc2[ 18] - + d2[ 3]*ksrc2[ 19] - + d2[ 4]*ksrc2[ 32] - + d2[ 5]*ksrc2[ 33] - + d2[ 6]*ksrc2[ 34] - + d2[ 7]*ksrc2[ 35] - + d2[ 8]*ksrc2[ 48] - + d2[ 9]*ksrc2[ 49] - + d2[10]*ksrc2[ 50] - + d2[11]*ksrc2[ 51]; - - acc2 = (acc2 + 0x2000) >> 14; - if (acc2 < 0) acc2 = 0; else if (acc2 > 255) acc2 = 255; - - acc3 += d3[ 0]*ksrc2[ 20] - + d3[ 1]*ksrc2[ 21] - + d3[ 2]*ksrc2[ 22] - + d3[ 3]*ksrc2[ 23] - + d3[ 4]*ksrc2[ 36] - + d3[ 5]*ksrc2[ 37] - + d3[ 6]*ksrc2[ 38] - + d3[ 7]*ksrc2[ 39] - + d3[ 8]*ksrc2[ 52] - + d3[ 9]*ksrc2[ 53] - + d3[10]*ksrc2[ 54] - + d3[11]*ksrc2[ 55]; - - acc3 = (acc3 + 0x2000) >> 14; - if (acc3 < 0) acc3 = 0; else if (acc3 > 255) acc3 = 255; - - ksrc2 += 56; - - dst2[0] = (uint8)acc0; - dst2[1] = (uint8)acc1; - dst2[2] = (uint8)acc2; - dst2[3] = (uint8)acc3; - dst2 += 4; - } while(--w4); -#endif - } else - vdasm_resize_table_row_8_k8_4x_MMX(dst, src, w >> 2, ksrc); - } - - if (w & 3) - vdasm_resize_table_row_8_MMX((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); - } else if (w) { - vdasm_resize_table_row_8_MMX(dst, src, w, ksrc, ksize); - } -#endif -} - -void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -VDResamplerSeparableTableRowStageMMX::VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter) - : VDResamplerRowStageSeparableTable32(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); -} - -void VDResamplerSeparableTableRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -/////////////////////////////////////////////////////////////////////////// - -VDResamplerSeparableTableColStage8MMX::VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter) - : VDResamplerColStageSeparableTable8(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); -} - -void __declspec(naked) vdasm_resize_table_col_8_k2_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { - static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; - - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov esi, [esp + 4 + 16] ;esi = dst - mov edi, [esp + 16 + 16] ;edi = kernel - mov ebp, [esp + 12 + 16] ;ebp = width - - movq mm5, [edi] - - mov edx, [esp + 8 + 16] ;ebx = srcs - mov eax, [edx+0] - mov ebx, [edx+4] - add eax, ebp - add ebx, ebp - neg ebp -yloop: - ;eax = row0 - ;ebx = row1 - ;ecx = - ;edx = - ;edi = kernel - ;esi = dest - ;ebp = width counter - - movd mm0, [eax+ebp] - punpcklbw mm0, mm7 - movd mm2, [ebx+ebp] - punpcklbw mm2, mm7 - movq mm1, mm0 - punpcklwd mm0, mm2 - punpckhwd mm1, mm2 - pmaddwd mm0, mm5 - pmaddwd mm1, mm5 - - paddd mm0, mm6 - paddd mm1, mm6 - - psrad mm0, 14 - psrad mm1, 14 - packssdw mm0, mm1 - packuswb mm0, mm0 - movd [esi], mm0 - add esi, 4 - add ebp, 4 - jne yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void __declspec(naked) vdasm_resize_table_col_8_k4_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { - static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; - - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov esi, [esp + 4 + 16] ;esi = dst - mov edi, [esp + 16 + 16] ;edi = kernel - xor ebp, ebp - - mov edx, [esp + 8 + 16] ;ebx = srcs - mov eax, [edx+0] - mov ebx, [edx+4] - mov ecx, [edx+8] - mov edx, [edx+12] -yloop: - ;eax = row0 - ;ebx = row1 - ;ecx = row2 - ;edx = row3 - ;edi = kernel - ;esi = dest - ;ebp = width counter - - movd mm0, [eax+ebp] - punpcklbw mm0, mm7 - movd mm2, [ebx+ebp] - punpcklbw mm2, mm7 - movq mm1, mm0 - punpcklwd mm0, mm2 - movq mm5, [edi] - punpckhwd mm1, mm2 - pmaddwd mm0, mm5 - pmaddwd mm1, mm5 - - paddd mm0, mm6 - paddd mm1, mm6 - - movd mm3, [ecx+ebp] - punpcklbw mm3, mm7 - movd mm2, [edx+ebp] - punpcklbw mm2, mm7 - movq mm4, mm3 - punpcklwd mm3, mm2 - movq mm5, [edi+8] - punpckhwd mm4, mm2 - pmaddwd mm3, mm5 - pmaddwd mm4, mm5 - - paddd mm0, mm3 - paddd mm1, mm4 - - psrad mm0, 14 - psrad mm1, 14 - packssdw mm0, mm1 - packuswb mm0, mm0 - add ebp, 4 - movd [esi], mm0 - add esi, 4 - cmp ebp, [esp + 12 + 16] - jb yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void __declspec(naked) vdasm_resize_table_col_8_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel, uint32 kwidth) { - static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; - - __asm { - push ebp - push edi - push esi - push ebx - - pxor mm7, mm7 - movq mm6, kRound - - mov edi, [esp + 4 + 16] ;edi = dst - xor ebp, ebp -yloop: - mov edx, [esp + 16 + 16] ;edx = kernel - mov ebx, [esp + 8 + 16] ;ebx = srcs - mov esi, [esp + 20 + 16] ;esi = kwidth - movq mm3, mm6 - movq mm4, mm6 -xloop: - mov ecx, [ebx] - movd mm0, [ecx+ebp] - punpcklbw mm0, mm7 - mov ecx, [ebx+4] - movd mm2, [ecx+ebp] - punpcklbw mm2, mm7 - movq mm1, mm0 - punpcklwd mm0, mm2 - punpckhwd mm1, mm2 - movq mm5, [edx] - pmaddwd mm0, mm5 - pmaddwd mm1, mm5 - - paddd mm3, mm0 - paddd mm4, mm1 - add ebx, 8 - add edx, 8 - sub esi, 2 - jne xloop - - psrad mm3, 14 - psrad mm4, 14 - packssdw mm3, mm4 - packuswb mm3, mm3 - movd [edi], mm3 - add edi, 4 - add ebp, 4 - cmp ebp, [esp + 12 + 16] - jb yloop - - pop ebx - pop esi - pop edi - pop ebp - ret - } -} - -void VDResamplerSeparableTableColStage8MMX::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - uint8 *dst = (uint8 *)dst0; - const uint8 *const *src = (const uint8 *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; - - int w4 = w & ~3; - - if (w4) { - switch(ksize) { - case 2: - vdasm_resize_table_col_8_k2_MMX(dst, (const void *const *)src, w4, filter); - break; - - case 4: - vdasm_resize_table_col_8_k4_MMX(dst, (const void *const *)src, w4, filter); - break; - - default: - vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); - break; - } - } - - for(uint32 i=w4; i>= 14; - - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - dst[i] = (uint8)b; - } -} - -/////////////////////////////////////////////////////////////////////////// - -VDResamplerSeparableTableColStageMMX::VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter) - : VDResamplerColStageSeparableTable32(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); -} - -void VDResamplerSeparableTableColStageMMX::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { - vdasm_resize_table_col_MMX((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); -} - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE2, x86) -// -/////////////////////////////////////////////////////////////////////////// - -extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); -extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); -extern "C" void vdasm_resize_ccint_col_SSE2(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); - -VDResamplerSeparableCubicColStageSSE2::VDResamplerSeparableCubicColStageSSE2(double A) - : VDResamplerSeparableCubicColStageMMX(A) -{ -} - -void VDResamplerSeparableCubicColStageSSE2::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { - vdasm_resize_ccint_col_SSE2(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); -} - -VDResamplerSeparableTableRowStageSSE2::VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter) - : VDResamplerSeparableTableRowStageMMX(filter) -{ -} - -void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) - : VDResamplerSeparableTableColStageMMX(filter) -{ -} - -void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { - vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); -} - -/////////////////////////////////////////////////////////////////////////// -// -// resampler stages (SSE4.1, x86) -// -/////////////////////////////////////////////////////////////////////////// - -VDResamplerSeparableTableRowStage8SSE41::VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter) - : VDResamplerRowStageSeparableTable32(filter) - , mLastSrcWidth(0) - , mLastDstWidth(0) - , mLastU(0) - , mLastDUDX(0) -{ - mAlignedKernelWidth = (GetWindowSize() + 15) & ~7; - mAlignedKernelSize = mAlignedKernelWidth + 16; -} - -void VDResamplerSeparableTableRowStage8SSE41::Init(const VDResamplerAxis& axis, uint32 srcw) { - uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; - - if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { - mLastSrcWidth = srcw; - mLastDstWidth = w; - mLastU = axis.u; - mLastDUDX = axis.dudx; - - RedoRowFilters(axis, w, srcw); - } -} - -void VDResamplerSeparableTableRowStage8SSE41::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { - int kstride = mFilterBank.size() >> 8; - int ksize = mAlignedKernelWidth; - int kesize = mAlignedKernelSize; - - mRowKernels.clear(); - mRowKernelSize = w * kesize; - - mRowKernels.resize(mRowKernelSize * 8, 0); - - for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { - sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; - int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 7) & ~7); - - mKernelSizeByOffset[byteOffset] = ksizeThisOffset; - - sint32 u = axis.u; - sint32 uoffmin = -byteOffset; - sint32 uoffmax = ((srcw + byteOffset + 7) & ~7) - byteOffset - ksizeThisOffset; - for(uint32 i=0; i> 16; - sint32 uoffset2 = ((uoffset + byteOffset) & ~7) - byteOffset; - - if (uoffset2 < uoffmin) - uoffset2 = uoffmin; - - if (uoffset2 > uoffmax) - uoffset2 = uoffmax; - - *(sint32 *)dst = uoffset2; - dst += 2; - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - - uint32 phase = (u >> 8) & 255; - const sint32 *src = &mFilterBank[kstride * phase]; - - sint32 start = 0; - sint32 end = kstride; - - int dstoffset = uoffset - uoffset2; - - // check for filter kernel overlapping left source boundary - if (uoffset < 0) - start = -uoffset; - - // check for filter kernel overlapping right source boundary - if (uoffset + end > (sint32)srcw) - end = srcw - uoffset; - - VDASSERT(dstoffset + start >= 0); - VDASSERT(dstoffset + end <= ksizeThisOffset); - - sint16 *dst2 = dst + dstoffset; - dst += ksizeThisOffset; - - for(int j=start; j 0) - dst2[start] = std::accumulate(src, src+start, dst2[start]); - - if (end < kstride) - dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); - - u += axis.dudx; - } - } - - // swizzle rows where optimization is possible - vdfastvector temp; - - int quads = w >> 2; - int quadRemainder = w & 3; - - for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { - int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; - int kpairs = ksizeThisOffset >> 3; - - if (ksizeThisOffset < 8 || ksizeThisOffset > 16) { - mbQuadOptimizationEnabled[byteOffset] = false; - } else { - ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 4; - - mbQuadOptimizationEnabled[byteOffset] = true; - mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); - - uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; - temp.resize(mRowKernelSize); - memcpy(temp.data(), dst, mRowKernelSize*2); - - const uint32 *src0 = (const uint32 *)temp.data(); - const uint32 *src1 = src0 + unswizzledStride; - const uint32 *src2 = src1 + unswizzledStride; - const uint32 *src3 = src2 + unswizzledStride; - ptrdiff_t srcskip = unswizzledStride * 3; - - for(int q = 0; q < quads; ++q) { - dst[0] = src0[0]; - dst[1] = src1[0]; - dst[2] = src2[0]; - dst[3] = src3[0]; - src0 += 4; - src1 += 4; - src2 += 4; - src3 += 4; - dst += 4; - - for(int p = 0; p < kpairs; ++p) { - dst[ 0] = src0[0]; - dst[ 1] = src0[1]; - dst[ 2] = src0[2]; - dst[ 3] = src0[3]; - dst[ 4] = src1[0]; - dst[ 5] = src1[1]; - dst[ 6] = src1[2]; - dst[ 7] = src1[3]; - dst[ 8] = src2[0]; - dst[ 9] = src2[1]; - dst[10] = src2[2]; - dst[11] = src2[3]; - dst[12] = src3[0]; - dst[13] = src3[1]; - dst[14] = src3[2]; - dst[15] = src3[3]; - dst += 16; - src0 += 4; - src1 += 4; - src2 += 4; - src3 += 4; - } - - src0 += srcskip; - src1 += srcskip; - src2 += srcskip; - src3 += srcskip; - } - - memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); - } - } -} - -void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w) { - int byteOffset = (int)(ptrdiff_t)src & 7; - const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); - - int ksize = mKernelSizeByOffset[byteOffset]; - if (mbQuadOptimizationEnabled[byteOffset]) { - if (w >= 4) { - if (ksize == 16) - vdasm_resize_table_row_8_k16_4x_SSE41(dst, src, w >> 2, ksrc); - else - vdasm_resize_table_row_8_k8_4x_SSE41(dst, src, w >> 2, ksrc); - } - - if (w & 3) - vdasm_resize_table_row_8_SSE41((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); - } else if (w) { - vdasm_resize_table_row_8_SSE41(dst, src, w, ksrc, ksize); - } -} - -void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { - vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); -} - -/////////////////////////////////////////////////////////////////////////// - -VDResamplerSeparableTableColStage8SSE41::VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter) - : VDResamplerColStageSeparableTable8(filter) -{ - VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); -} - -void VDResamplerSeparableTableColStage8SSE41::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { - uint8 *dst = (uint8 *)dst0; - const uint8 *const *src = (const uint8 *const *)src0; - const unsigned ksize = (unsigned)mFilterBank.size() >> 8; - const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; - - int w4 = w & ~3; - - if (w4) { - switch(ksize) { - case 2: - vdasm_resize_table_col_8_k2_SSE41(dst, (const void *const *)src, w4, filter); - break; - - case 4: - vdasm_resize_table_col_8_k4_SSE41(dst, (const void *const *)src, w4, filter); - break; - - default: - vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); - break; - } - } - - for(uint32 i=w4; i>= 14; - - if ((uint32)b >= 0x00000100) - b = ~b >> 31; - - dst[i] = (uint8)b; - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include "blt_spanutils_x86.h" +#include "resample_stages_x86.h" +#include + +#ifdef _MSC_VER + #pragma warning(disable: 4799) // warning C4799: function 'vdasm_resize_table_row_8_k8_4x_MMX' has no EMMS instruction +#endif + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" void vdasm_resize_table_row_8_k8_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); +extern "C" void vdasm_resize_table_row_8_k16_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); +extern "C" void vdasm_resize_table_row_8_SSE41(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth); +extern "C" void vdasm_resize_table_col_8_k2_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); +extern "C" void vdasm_resize_table_col_8_k4_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + struct ScaleInfo { + void *dst; + uintptr src; + uint32 accum; + uint32 fracinc; + sint32 intinc; + uint32 count; + }; + + extern "C" void vdasm_resize_point32(const ScaleInfo *); +} + +int VDResamplerSeparablePointRowStageX86::GetWindowSize() const {return 1;} +void VDResamplerSeparablePointRowStageX86::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + ScaleInfo info; + + info.dst = (uint32 *)dst + w; + info.src = ((uintptr)src >> 2) + (u>>16); + info.accum = u<<16; + info.fracinc = dudx << 16; + info.intinc = (sint32)dudx >> 16; + info.count = -(sint32)w*4; + + vdasm_resize_point32(&info); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + uint8 *dst = (uint8 *)dst0; + const uint8 *src = (const uint8 *)src0; + + nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE(dst, src, w); +} + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" void vdasm_resize_point32_MMX(const ScaleInfo *); +extern "C" void vdasm_resize_interp_row_run_MMX(void *dst, const void *src, uint32 width, sint64 xaccum, sint64 x_inc); +extern "C" void vdasm_resize_interp_col_run_MMX(void *dst, const void *src1, const void *src2, uint32 width, uint32 yaccum); +extern "C" void vdasm_resize_ccint_row_MMX(void *dst, const void *src, uint32 count, uint32 xaccum, sint32 xinc, const void *tbl); +extern "C" void vdasm_resize_ccint_col_MMX(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); +extern "C" long vdasm_resize_table_col_MMX(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); +extern "C" long vdasm_resize_table_row_MMX(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); + +int VDResamplerSeparablePointRowStageMMX::GetWindowSize() const {return 1;} +void VDResamplerSeparablePointRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + ScaleInfo info; + + info.dst = (uint32 *)dst + w; + info.src = ((uintptr)src >> 2) + (u>>16); + info.accum = u<<16; + info.fracinc = dudx << 16; + info.intinc = (sint32)dudx >> 16; + info.count = -(sint32)w*4; + + vdasm_resize_point32_MMX(&info); +} + +int VDResamplerSeparableLinearRowStageMMX::GetWindowSize() const {return 2;} +void VDResamplerSeparableLinearRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_interp_row_run_MMX(dst0, src0, w, (sint64)u << 16, (sint64)dudx << 16); +} + +int VDResamplerSeparableLinearColStageMMX::GetWindowSize() const {return 2;} +void VDResamplerSeparableLinearColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + vdasm_resize_interp_col_run_MMX(dst0, srcarray[0], srcarray[1], w, phase); +} + +VDResamplerSeparableCubicRowStageMMX::VDResamplerSeparableCubicRowStageMMX(double A) + : mFilterBank(1024) +{ + sint32 *p = mFilterBank.data(); + VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); + VDResamplerSwizzleTable(p, 512); +} + +int VDResamplerSeparableCubicRowStageMMX::GetWindowSize() const {return 4;} +void VDResamplerSeparableCubicRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_ccint_row_MMX(dst0, src0, w, u, dudx, mFilterBank.data()); +} + +VDResamplerSeparableCubicColStageMMX::VDResamplerSeparableCubicColStageMMX(double A) + : mFilterBank(1024) +{ + sint32 *p = mFilterBank.data(); + VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); + VDResamplerSwizzleTable(p, 512); +} + +int VDResamplerSeparableCubicColStageMMX::GetWindowSize() const {return 4;} +void VDResamplerSeparableCubicColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + vdasm_resize_ccint_col_MMX(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); +} + +VDResamplerSeparableTableRowStage8MMX::VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter) + : VDResamplerRowStageSeparableTable32(filter) + , mLastSrcWidth(0) + , mLastDstWidth(0) + , mLastU(0) + , mLastDUDX(0) +{ + mAlignedKernelWidth = (GetWindowSize() + 6) & ~3; + mAlignedKernelSize = mAlignedKernelWidth + 4; +} + +void VDResamplerSeparableTableRowStage8MMX::Init(const VDResamplerAxis& axis, uint32 srcw) { + uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; + + if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { + mLastSrcWidth = srcw; + mLastDstWidth = w; + mLastU = axis.u; + mLastDUDX = axis.dudx; + + RedoRowFilters(axis, w, srcw); + } +} + +void VDResamplerSeparableTableRowStage8MMX::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { + int kstride = mFilterBank.size() >> 8; + int ksize = mAlignedKernelWidth; + int kesize = mAlignedKernelSize; + + mRowKernels.clear(); + mRowKernelSize = w * kesize; + + mRowKernels.resize(mRowKernelSize * 4, 0); + + for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { + sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; + int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 3) & ~3); + + mKernelSizeByOffset[byteOffset] = ksizeThisOffset; + + sint32 u = axis.u; + sint32 uoffmin = -byteOffset; + sint32 uoffmax = ((srcw + byteOffset + 3) & ~3) - byteOffset - ksizeThisOffset; + for(uint32 i=0; i> 16; + sint32 uoffset2 = ((uoffset + byteOffset) & ~3) - byteOffset; + + if (uoffset2 < uoffmin) + uoffset2 = uoffmin; + + if (uoffset2 > uoffmax) + uoffset2 = uoffmax; + + VDASSERT(uoffset2 + ksizeThisOffset <= (((sint32)srcw + byteOffset + 3) & ~3)); + + *(sint32 *)dst = uoffset2; + dst += 2; + *dst++ = 0; + *dst++ = 0; + + uint32 phase = (u >> 8) & 255; + const sint32 *src = &mFilterBank[kstride * phase]; + + sint32 start = 0; + sint32 end = kstride; + + int dstoffset = uoffset - uoffset2; + + // check for filter kernel overlapping left source boundary + if (uoffset < 0) + start = -uoffset; + + // check for filter kernel overlapping right source boundary + if (uoffset + end > (sint32)srcw) + end = srcw - uoffset; + + VDASSERT(dstoffset + start >= 0); + VDASSERT(dstoffset + end <= ksizeThisOffset); + + sint16 *dst2 = dst + dstoffset; + dst += ksizeThisOffset; + + for(int j=start; j 0) + dst2[start] = std::accumulate(src, src+start, dst2[start]); + + if (end < kstride) + dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); + + u += axis.dudx; + } + } + + // swizzle rows where optimization is possible + vdfastvector temp; + + int quads = w >> 2; + int quadRemainder = w & 3; + + for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { + int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; + int kpairs = ksizeThisOffset >> 2; + + if (ksizeThisOffset < 8 || ksizeThisOffset > 12) { + mbQuadOptimizationEnabled[byteOffset] = false; + } else { + ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 2; + + mbQuadOptimizationEnabled[byteOffset] = true; + mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); + + uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; + temp.resize(mRowKernelSize); + memcpy(temp.data(), dst, mRowKernelSize*2); + + const uint32 *src0 = (const uint32 *)temp.data(); + const uint32 *src1 = src0 + unswizzledStride; + const uint32 *src2 = src1 + unswizzledStride; + const uint32 *src3 = src2 + unswizzledStride; + ptrdiff_t srcskip = unswizzledStride * 3; + + for(int q = 0; q < quads; ++q) { + dst[0] = src0[0]; + dst[1] = src1[0]; + dst[2] = src2[0]; + dst[3] = src3[0]; + src0 += 2; + src1 += 2; + src2 += 2; + src3 += 2; + dst += 4; + + for(int p = 0; p < kpairs; ++p) { + dst[0] = src0[0]; + dst[1] = src0[1]; + dst[2] = src1[0]; + dst[3] = src1[1]; + dst[4] = src2[0]; + dst[5] = src2[1]; + dst[6] = src3[0]; + dst[7] = src3[1]; + dst += 8; + src0 += 2; + src1 += 2; + src2 += 2; + src3 += 2; + } + + src0 += srcskip; + src1 += srcskip; + src2 += srcskip; + src3 += srcskip; + } + + memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); + + VDASSERT(dst + unswizzledStride * quadRemainder <= (void *)(mRowKernels.data() + (mRowKernelSize * (byteOffset + 1)))); + } + } +} + +void __declspec(naked) vdasm_resize_table_row_8_k8_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { + static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov ebp, [esp + 4 + 16] ;ebp = dst + mov esi, [esp + 12 + 16] ;esi = width + mov edi, [esp + 16 + 16] ;edi = kernel +yloop: + ;eax = temp + ;ebx = temp + ;ecx = temp + ;edx = temp + ;esi = horiz counter + ;edi = filter list + ;ebp = destination + + mov eax, [edi+0] + mov ebx, [edi+4] + mov ecx, [edi+8] + mov edx, [esp+8+16] + add eax, edx + add ebx, edx + add ecx, edx + add edx, [edi+12] + + movd mm0, [eax] + punpcklbw mm0, mm7 + + pmaddwd mm0, [edi+16] + movd mm1, [ebx] + punpcklbw mm1, mm7 + + pmaddwd mm1, [edi+24] + movd mm2, [ecx] + punpcklbw mm2, mm7 + + pmaddwd mm2, [edi+32] + movd mm3, [edx] + punpcklbw mm3, mm7 + + pmaddwd mm3, [edi+40] + movd mm4, [eax+4] + paddd mm0, mm6 + + movd mm5, [ebx+4] + punpcklbw mm4, mm7 + paddd mm1, mm6 + + pmaddwd mm4, [edi+48] + punpcklbw mm5, mm7 + paddd mm2, mm6 + + pmaddwd mm5, [edi+56] + paddd mm3, mm6 + paddd mm0, mm4 + + paddd mm1, mm5 + movd mm4, [ecx+4] + punpcklbw mm4, mm7 + + pmaddwd mm4, [edi+64] + movd mm5, [edx+4] + punpcklbw mm5, mm7 + + pmaddwd mm5, [edi+72] + paddd mm2, mm4 + paddd mm3, mm5 + + movq mm4, mm0 + punpckldq mm0, mm1 + movq mm5, mm2 + punpckldq mm2, mm3 + punpckhdq mm4, mm1 + punpckhdq mm5, mm3 + paddd mm0, mm4 + paddd mm2, mm5 + psrad mm0, 14 + psrad mm2, 14 + + packssdw mm0, mm2 + packuswb mm0, mm0 + + add edi, 80 + + movd [ebp], mm0 + add ebp, 4 + sub esi, 1 + jne yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void __declspec(naked) vdasm_resize_table_row_8_k12_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { + static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov ebp, [esp + 4 + 16] ;ebp = dst + mov esi, [esp + 12 + 16] ;esi = width + mov edi, [esp + 16 + 16] ;edi = kernel +yloop: + ;eax = temp + ;ebx = temp + ;ecx = temp + ;edx = temp + ;esi = horiz counter + ;edi = filter list + ;ebp = destination + + mov eax, [edi+0] + mov ebx, [edi+4] + mov ecx, [edi+8] + mov edx, [esp+8+16] + add eax, edx + add ebx, edx + add ecx, edx + add edx, [edi+12] + + movd mm0, [eax] + punpcklbw mm0, mm7 + + pmaddwd mm0, [edi+16] + movd mm1, [ebx] + punpcklbw mm1, mm7 + + pmaddwd mm1, [edi+24] + movd mm2, [ecx] + punpcklbw mm2, mm7 + + pmaddwd mm2, [edi+32] + movd mm3, [edx] + punpcklbw mm3, mm7 + + pmaddwd mm3, [edi+40] + movd mm4, [eax+4] + punpcklbw mm4, mm7 + + pmaddwd mm4, [edi+48] + movd mm5, [ebx+4] + punpcklbw mm5, mm7 + + pmaddwd mm5, [edi+56] + paddd mm0, mm4 + paddd mm1, mm5 + + movd mm4, [ecx+4] + punpcklbw mm4, mm7 + movd mm5, [edx+4] + + pmaddwd mm4, [edi+64] + punpcklbw mm5, mm7 + paddd mm2, mm4 + + pmaddwd mm5, [edi+72] + movd mm4, [eax+8] + punpcklbw mm4, mm7 + + paddd mm3, mm5 + movd mm5, [ebx+8] + punpcklbw mm5, mm7 + + pmaddwd mm4, [edi+80] + paddd mm0, mm4 + movd mm4, [ecx+8] + + pmaddwd mm5, [edi+88] + paddd mm1, mm5 + punpcklbw mm4, mm7 + + pmaddwd mm4, [edi+96] + movd mm5, [edx+8] + punpcklbw mm5, mm7 + + pmaddwd mm5, [edi+104] + paddd mm2, mm4 + paddd mm3, mm5 + + movq mm4, mm0 + punpckldq mm0, mm1 + movq mm5, mm2 + punpckldq mm2, mm3 + punpckhdq mm4, mm1 + punpckhdq mm5, mm3 + paddd mm0, mm4 + paddd mm2, mm5 + paddd mm0, mm6 + paddd mm2, mm6 + psrad mm0, 14 + psrad mm2, 14 + + packssdw mm0, mm2 + packuswb mm0, mm0 + + add edi, 112 + + movd [ebp], mm0 + add ebp, 4 + sub esi, 1 + jne yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void __declspec(naked) vdasm_resize_table_row_8_MMX(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth) { + static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov edi, [esp + 4 + 16] ;edi = dst + mov ebx, [esp + 8 + 16] ;ebx = src + mov ebp, [esp + 12 + 16] ;ebp = width + mov edx, [esp + 16 + 16] ;edx = kernel +yloop: + ;eax = temp + ;ebx = source base address + ;ecx = (temp) source + ;edx = filter list + ;esi = (temp) kernel width + ;edi = destination + ;ebp = horiz counter + + mov eax, [edx] + add edx, 8 + lea ecx, [ebx + eax] + mov esi, [esp + 20 + 16] ;esi = kernel width + + movq mm2, mm6 +xloop: + movd mm0, [ecx] + punpcklbw mm0, mm7 + add ecx, 4 + pmaddwd mm0, [edx] + paddd mm2, mm0 + add edx, 8 + sub esi, 4 + jne xloop + + punpckldq mm0, mm2 + paddd mm0, mm2 + psrad mm0, 14 + psrlq mm0, 32 + packssdw mm0, mm0 + packuswb mm0, mm0 + movd eax, mm0 + mov [edi], al + add edi, 1 + sub ebp, 1 + jne yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w) { + int byteOffset = (int)(ptrdiff_t)src & 3; + const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); +#if 0 + int kwidth = mAlignedKernelWidth; + uint8 *dst2 = (uint8 *)dst; + + do { + int offset = ksrc[0]; + ksrc += 4; + + const uint8 *src2 = (const uint8 *)src + offset; + sint32 accum = 0x8000; + for(int i=0; i>= 14; + + accum &= ~(accum >> 31); + accum |= (255 - accum) >> 31; + + *dst2++ = (uint8)accum; + + } while(--w); +#else + int ksize = mKernelSizeByOffset[byteOffset]; + if (mbQuadOptimizationEnabled[byteOffset]) { + if (w >= 4) { + if (ksize == 12) { + vdasm_resize_table_row_8_k12_4x_MMX(dst, src, w >> 2, ksrc); + +#if 0 + int w4 = w >> 2; + uint8 *dst2 = (uint8 *)dst; + const uint8 *src2 = (const uint8 *)src; + const sint16 *ksrc2 = ksrc; + + do { + int off0 = ksrc2[0]; + int off1 = ksrc2[2]; + int off2 = ksrc2[4]; + int off3 = ksrc2[6]; + const uint8 *d0 = src2 + off0; + const uint8 *d1 = src2 + off1; + const uint8 *d2 = src2 + off2; + const uint8 *d3 = src2 + off3; + + int acc0 = 0; + int acc1 = 0; + int acc2 = 0; + int acc3 = 0; + + acc0 += d0[ 0]*ksrc2[ 8] + + d0[ 1]*ksrc2[ 9] + + d0[ 2]*ksrc2[ 10] + + d0[ 3]*ksrc2[ 11] + + d0[ 4]*ksrc2[ 24] + + d0[ 5]*ksrc2[ 25] + + d0[ 6]*ksrc2[ 26] + + d0[ 7]*ksrc2[ 27] + + d0[ 8]*ksrc2[ 40] + + d0[ 9]*ksrc2[ 41] + + d0[10]*ksrc2[ 42] + + d0[11]*ksrc2[ 43]; + + acc0 = (acc0 + 0x2000) >> 14; + if (acc0 < 0) acc0 = 0; else if (acc0 > 255) acc0 = 255; + + acc1 += d1[ 0]*ksrc2[ 12] + + d1[ 1]*ksrc2[ 13] + + d1[ 2]*ksrc2[ 14] + + d1[ 3]*ksrc2[ 15] + + d1[ 4]*ksrc2[ 28] + + d1[ 5]*ksrc2[ 29] + + d1[ 6]*ksrc2[ 30] + + d1[ 7]*ksrc2[ 31] + + d1[ 8]*ksrc2[ 44] + + d1[ 9]*ksrc2[ 45] + + d1[10]*ksrc2[ 46] + + d1[11]*ksrc2[ 47]; + + acc1 = (acc1 + 0x2000) >> 14; + if (acc1 < 0) acc1 = 0; else if (acc1 > 255) acc1 = 255; + + acc2 += d2[ 0]*ksrc2[ 16] + + d2[ 1]*ksrc2[ 17] + + d2[ 2]*ksrc2[ 18] + + d2[ 3]*ksrc2[ 19] + + d2[ 4]*ksrc2[ 32] + + d2[ 5]*ksrc2[ 33] + + d2[ 6]*ksrc2[ 34] + + d2[ 7]*ksrc2[ 35] + + d2[ 8]*ksrc2[ 48] + + d2[ 9]*ksrc2[ 49] + + d2[10]*ksrc2[ 50] + + d2[11]*ksrc2[ 51]; + + acc2 = (acc2 + 0x2000) >> 14; + if (acc2 < 0) acc2 = 0; else if (acc2 > 255) acc2 = 255; + + acc3 += d3[ 0]*ksrc2[ 20] + + d3[ 1]*ksrc2[ 21] + + d3[ 2]*ksrc2[ 22] + + d3[ 3]*ksrc2[ 23] + + d3[ 4]*ksrc2[ 36] + + d3[ 5]*ksrc2[ 37] + + d3[ 6]*ksrc2[ 38] + + d3[ 7]*ksrc2[ 39] + + d3[ 8]*ksrc2[ 52] + + d3[ 9]*ksrc2[ 53] + + d3[10]*ksrc2[ 54] + + d3[11]*ksrc2[ 55]; + + acc3 = (acc3 + 0x2000) >> 14; + if (acc3 < 0) acc3 = 0; else if (acc3 > 255) acc3 = 255; + + ksrc2 += 56; + + dst2[0] = (uint8)acc0; + dst2[1] = (uint8)acc1; + dst2[2] = (uint8)acc2; + dst2[3] = (uint8)acc3; + dst2 += 4; + } while(--w4); +#endif + } else + vdasm_resize_table_row_8_k8_4x_MMX(dst, src, w >> 2, ksrc); + } + + if (w & 3) + vdasm_resize_table_row_8_MMX((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); + } else if (w) { + vdasm_resize_table_row_8_MMX(dst, src, w, ksrc, ksize); + } +#endif +} + +void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +VDResamplerSeparableTableRowStageMMX::VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter) + : VDResamplerRowStageSeparableTable32(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +/////////////////////////////////////////////////////////////////////////// + +VDResamplerSeparableTableColStage8MMX::VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter) + : VDResamplerColStageSeparableTable8(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); +} + +void __declspec(naked) vdasm_resize_table_col_8_k2_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { + static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; + + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov esi, [esp + 4 + 16] ;esi = dst + mov edi, [esp + 16 + 16] ;edi = kernel + mov ebp, [esp + 12 + 16] ;ebp = width + + movq mm5, [edi] + + mov edx, [esp + 8 + 16] ;ebx = srcs + mov eax, [edx+0] + mov ebx, [edx+4] + add eax, ebp + add ebx, ebp + neg ebp +yloop: + ;eax = row0 + ;ebx = row1 + ;ecx = + ;edx = + ;edi = kernel + ;esi = dest + ;ebp = width counter + + movd mm0, [eax+ebp] + punpcklbw mm0, mm7 + movd mm2, [ebx+ebp] + punpcklbw mm2, mm7 + movq mm1, mm0 + punpcklwd mm0, mm2 + punpckhwd mm1, mm2 + pmaddwd mm0, mm5 + pmaddwd mm1, mm5 + + paddd mm0, mm6 + paddd mm1, mm6 + + psrad mm0, 14 + psrad mm1, 14 + packssdw mm0, mm1 + packuswb mm0, mm0 + movd [esi], mm0 + add esi, 4 + add ebp, 4 + jne yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void __declspec(naked) vdasm_resize_table_col_8_k4_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { + static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; + + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov esi, [esp + 4 + 16] ;esi = dst + mov edi, [esp + 16 + 16] ;edi = kernel + xor ebp, ebp + + mov edx, [esp + 8 + 16] ;ebx = srcs + mov eax, [edx+0] + mov ebx, [edx+4] + mov ecx, [edx+8] + mov edx, [edx+12] +yloop: + ;eax = row0 + ;ebx = row1 + ;ecx = row2 + ;edx = row3 + ;edi = kernel + ;esi = dest + ;ebp = width counter + + movd mm0, [eax+ebp] + punpcklbw mm0, mm7 + movd mm2, [ebx+ebp] + punpcklbw mm2, mm7 + movq mm1, mm0 + punpcklwd mm0, mm2 + movq mm5, [edi] + punpckhwd mm1, mm2 + pmaddwd mm0, mm5 + pmaddwd mm1, mm5 + + paddd mm0, mm6 + paddd mm1, mm6 + + movd mm3, [ecx+ebp] + punpcklbw mm3, mm7 + movd mm2, [edx+ebp] + punpcklbw mm2, mm7 + movq mm4, mm3 + punpcklwd mm3, mm2 + movq mm5, [edi+8] + punpckhwd mm4, mm2 + pmaddwd mm3, mm5 + pmaddwd mm4, mm5 + + paddd mm0, mm3 + paddd mm1, mm4 + + psrad mm0, 14 + psrad mm1, 14 + packssdw mm0, mm1 + packuswb mm0, mm0 + add ebp, 4 + movd [esi], mm0 + add esi, 4 + cmp ebp, [esp + 12 + 16] + jb yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void __declspec(naked) vdasm_resize_table_col_8_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel, uint32 kwidth) { + static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; + + __asm { + push ebp + push edi + push esi + push ebx + + pxor mm7, mm7 + movq mm6, kRound + + mov edi, [esp + 4 + 16] ;edi = dst + xor ebp, ebp +yloop: + mov edx, [esp + 16 + 16] ;edx = kernel + mov ebx, [esp + 8 + 16] ;ebx = srcs + mov esi, [esp + 20 + 16] ;esi = kwidth + movq mm3, mm6 + movq mm4, mm6 +xloop: + mov ecx, [ebx] + movd mm0, [ecx+ebp] + punpcklbw mm0, mm7 + mov ecx, [ebx+4] + movd mm2, [ecx+ebp] + punpcklbw mm2, mm7 + movq mm1, mm0 + punpcklwd mm0, mm2 + punpckhwd mm1, mm2 + movq mm5, [edx] + pmaddwd mm0, mm5 + pmaddwd mm1, mm5 + + paddd mm3, mm0 + paddd mm4, mm1 + add ebx, 8 + add edx, 8 + sub esi, 2 + jne xloop + + psrad mm3, 14 + psrad mm4, 14 + packssdw mm3, mm4 + packuswb mm3, mm3 + movd [edi], mm3 + add edi, 4 + add ebp, 4 + cmp ebp, [esp + 12 + 16] + jb yloop + + pop ebx + pop esi + pop edi + pop ebp + ret + } +} + +void VDResamplerSeparableTableColStage8MMX::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + uint8 *dst = (uint8 *)dst0; + const uint8 *const *src = (const uint8 *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; + + int w4 = w & ~3; + + if (w4) { + switch(ksize) { + case 2: + vdasm_resize_table_col_8_k2_MMX(dst, (const void *const *)src, w4, filter); + break; + + case 4: + vdasm_resize_table_col_8_k4_MMX(dst, (const void *const *)src, w4, filter); + break; + + default: + vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); + break; + } + } + + for(uint32 i=w4; i>= 14; + + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + dst[i] = (uint8)b; + } +} + +/////////////////////////////////////////////////////////////////////////// + +VDResamplerSeparableTableColStageMMX::VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter) + : VDResamplerColStageSeparableTable32(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableColStageMMX::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { + vdasm_resize_table_col_MMX((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); +} + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE2, x86) +// +/////////////////////////////////////////////////////////////////////////// + +extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); +extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); +extern "C" void vdasm_resize_ccint_col_SSE2(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); + +VDResamplerSeparableCubicColStageSSE2::VDResamplerSeparableCubicColStageSSE2(double A) + : VDResamplerSeparableCubicColStageMMX(A) +{ +} + +void VDResamplerSeparableCubicColStageSSE2::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { + vdasm_resize_ccint_col_SSE2(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); +} + +VDResamplerSeparableTableRowStageSSE2::VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter) + : VDResamplerSeparableTableRowStageMMX(filter) +{ +} + +void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) + : VDResamplerSeparableTableColStageMMX(filter) +{ +} + +void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { + vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); +} + +/////////////////////////////////////////////////////////////////////////// +// +// resampler stages (SSE4.1, x86) +// +/////////////////////////////////////////////////////////////////////////// + +VDResamplerSeparableTableRowStage8SSE41::VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter) + : VDResamplerRowStageSeparableTable32(filter) + , mLastSrcWidth(0) + , mLastDstWidth(0) + , mLastU(0) + , mLastDUDX(0) +{ + mAlignedKernelWidth = (GetWindowSize() + 15) & ~7; + mAlignedKernelSize = mAlignedKernelWidth + 16; +} + +void VDResamplerSeparableTableRowStage8SSE41::Init(const VDResamplerAxis& axis, uint32 srcw) { + uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; + + if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { + mLastSrcWidth = srcw; + mLastDstWidth = w; + mLastU = axis.u; + mLastDUDX = axis.dudx; + + RedoRowFilters(axis, w, srcw); + } +} + +void VDResamplerSeparableTableRowStage8SSE41::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { + int kstride = mFilterBank.size() >> 8; + int ksize = mAlignedKernelWidth; + int kesize = mAlignedKernelSize; + + mRowKernels.clear(); + mRowKernelSize = w * kesize; + + mRowKernels.resize(mRowKernelSize * 8, 0); + + for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { + sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; + int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 7) & ~7); + + mKernelSizeByOffset[byteOffset] = ksizeThisOffset; + + sint32 u = axis.u; + sint32 uoffmin = -byteOffset; + sint32 uoffmax = ((srcw + byteOffset + 7) & ~7) - byteOffset - ksizeThisOffset; + for(uint32 i=0; i> 16; + sint32 uoffset2 = ((uoffset + byteOffset) & ~7) - byteOffset; + + if (uoffset2 < uoffmin) + uoffset2 = uoffmin; + + if (uoffset2 > uoffmax) + uoffset2 = uoffmax; + + *(sint32 *)dst = uoffset2; + dst += 2; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + + uint32 phase = (u >> 8) & 255; + const sint32 *src = &mFilterBank[kstride * phase]; + + sint32 start = 0; + sint32 end = kstride; + + int dstoffset = uoffset - uoffset2; + + // check for filter kernel overlapping left source boundary + if (uoffset < 0) + start = -uoffset; + + // check for filter kernel overlapping right source boundary + if (uoffset + end > (sint32)srcw) + end = srcw - uoffset; + + VDASSERT(dstoffset + start >= 0); + VDASSERT(dstoffset + end <= ksizeThisOffset); + + sint16 *dst2 = dst + dstoffset; + dst += ksizeThisOffset; + + for(int j=start; j 0) + dst2[start] = std::accumulate(src, src+start, dst2[start]); + + if (end < kstride) + dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); + + u += axis.dudx; + } + } + + // swizzle rows where optimization is possible + vdfastvector temp; + + int quads = w >> 2; + int quadRemainder = w & 3; + + for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { + int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; + int kpairs = ksizeThisOffset >> 3; + + if (ksizeThisOffset < 8 || ksizeThisOffset > 16) { + mbQuadOptimizationEnabled[byteOffset] = false; + } else { + ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 4; + + mbQuadOptimizationEnabled[byteOffset] = true; + mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); + + uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; + temp.resize(mRowKernelSize); + memcpy(temp.data(), dst, mRowKernelSize*2); + + const uint32 *src0 = (const uint32 *)temp.data(); + const uint32 *src1 = src0 + unswizzledStride; + const uint32 *src2 = src1 + unswizzledStride; + const uint32 *src3 = src2 + unswizzledStride; + ptrdiff_t srcskip = unswizzledStride * 3; + + for(int q = 0; q < quads; ++q) { + dst[0] = src0[0]; + dst[1] = src1[0]; + dst[2] = src2[0]; + dst[3] = src3[0]; + src0 += 4; + src1 += 4; + src2 += 4; + src3 += 4; + dst += 4; + + for(int p = 0; p < kpairs; ++p) { + dst[ 0] = src0[0]; + dst[ 1] = src0[1]; + dst[ 2] = src0[2]; + dst[ 3] = src0[3]; + dst[ 4] = src1[0]; + dst[ 5] = src1[1]; + dst[ 6] = src1[2]; + dst[ 7] = src1[3]; + dst[ 8] = src2[0]; + dst[ 9] = src2[1]; + dst[10] = src2[2]; + dst[11] = src2[3]; + dst[12] = src3[0]; + dst[13] = src3[1]; + dst[14] = src3[2]; + dst[15] = src3[3]; + dst += 16; + src0 += 4; + src1 += 4; + src2 += 4; + src3 += 4; + } + + src0 += srcskip; + src1 += srcskip; + src2 += srcskip; + src3 += srcskip; + } + + memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); + } + } +} + +void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w) { + int byteOffset = (int)(ptrdiff_t)src & 7; + const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); + + int ksize = mKernelSizeByOffset[byteOffset]; + if (mbQuadOptimizationEnabled[byteOffset]) { + if (w >= 4) { + if (ksize == 16) + vdasm_resize_table_row_8_k16_4x_SSE41(dst, src, w >> 2, ksrc); + else + vdasm_resize_table_row_8_k8_4x_SSE41(dst, src, w >> 2, ksrc); + } + + if (w & 3) + vdasm_resize_table_row_8_SSE41((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); + } else if (w) { + vdasm_resize_table_row_8_SSE41(dst, src, w, ksrc, ksize); + } +} + +void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { + vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); +} + +/////////////////////////////////////////////////////////////////////////// + +VDResamplerSeparableTableColStage8SSE41::VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter) + : VDResamplerColStageSeparableTable8(filter) +{ + VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); +} + +void VDResamplerSeparableTableColStage8SSE41::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { + uint8 *dst = (uint8 *)dst0; + const uint8 *const *src = (const uint8 *const *)src0; + const unsigned ksize = (unsigned)mFilterBank.size() >> 8; + const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; + + int w4 = w & ~3; + + if (w4) { + switch(ksize) { + case 2: + vdasm_resize_table_col_8_k2_SSE41(dst, (const void *const *)src, w4, filter); + break; + + case 4: + vdasm_resize_table_col_8_k4_SSE41(dst, (const void *const *)src, w4, filter); + break; + + default: + vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); + break; + } + } + + for(uint32 i=w4; i>= 14; + + if ((uint32)b >= 0x00000100) + b = ~b >> 31; + + dst[i] = (uint8)b; + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/stdafx.cpp b/src/thirdparty/VirtualDub/Kasumi/source/stdafx.cpp index 5b3adc67f38..13d8f13506c 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/stdafx.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/stdafx.cpp @@ -1,19 +1,19 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + #include "stdafx.h" \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/Kasumi/source/stretchblt_reference.cpp b/src/thirdparty/VirtualDub/Kasumi/source/stretchblt_reference.cpp index 1774cdfdf3b..19d140ee610 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/stretchblt_reference.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/stretchblt_reference.cpp @@ -1,835 +1,835 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include - -namespace { - struct VDPixmapReferenceStretchBltParameters { - void *dst; - ptrdiff_t dstpitch; - const void *src; - ptrdiff_t srcpitch; - ptrdiff_t srcinc; - sint32 dx; - sint32 dy; - uint32 u; - uint32 uinc; - uint32 dudx; - uint32 v; - uint32 dvdy; - sint32 xprecopy; - sint32 xpostcopy; - ptrdiff_t xprepos; - ptrdiff_t xpostpos; - - void advance() { - dst = (char *)dst + dstpitch; - src = (char *)src + srcinc; - - uint32 vt = v + dvdy; - - if (vt < v) - src = (char *)src + srcpitch; - - v = vt; - } - }; -} - -void VDPixmapStretchBlt_Any8_nearest_reference(VDPixmapReferenceStretchBltParameters params) { - do { - uint8 *dstp = (uint8 *)params.dst; - const uint8 *srcp = (const uint8 *)params.src; - uint32 u = params.u; - - if (params.xprecopy) { - VDMemset8(dstp, *(const uint8 *)((const char *)params.src + params.xprepos), params.xprecopy); - dstp += params.xprecopy; - } - - sint32 wt = params.dx; - - if (wt > 0) - do { - *dstp++ = *srcp; - - uint32 ut = u + params.dudx; - srcp += ut 0) - do { - *dstp++ = *srcp; - - uint32 ut = u + params.dudx; - srcp += ut 0) - do { - dstp[0] = srcp[0]; - dstp[1] = srcp[1]; - dstp[2] = srcp[2]; - dstp += 3; - - uint32 ut = u + params.dudx; - srcp += (ut 0) - do { - *dstp++ = *srcp; - - uint32 ut = u + params.dudx; - srcp += ut= ulimit) - xprecopy = dx; - else - xmain = dx; - } else { - if (tdudx < 0) { - std::swap(ulo, uhi); - tdudx = -tdudx; - } - - if (ulo < 0) { - if (uhi < 0) - xprecopy = dx; - else - xprecopy = (sint32)((-ulo-1) / tdudx) + 1; - - VDASSERT(xprecopy <= 0 || (uint64)ulo >= (uint64)ulimit); - VDASSERT(xprecopy <= 0 || (uint64)(ulo + tdudx * (xprecopy-1)) >= (uint64)ulimit); - } - - if (uhi >= ulimit) { - if (ulo >= ulimit) - xpostcopy = dx; - else - xpostcopy = (sint32)((uhi - ulimit) / tdudx) + 1; - - VDASSERT(xpostcopy <= 0 || (uint64)uhi >= (uint64)ulimit); - VDASSERT(xpostcopy <= 0 || (uint64)(uhi - tdudx * (xpostcopy - 1)) >= (uint64)ulimit); - } - - if (dudx < 0) { - std::swap(xprecopy, xpostcopy); - std::swap(xprepos, xpostpos); - } - - xmain = dx - (xprecopy + xpostcopy); - } - - // sanity-check parameters - - VDASSERT(xprecopy>=0 && xprecopy <= dx); - VDASSERT(xpostcopy>=0 && xpostcopy <= dx); - VDASSERT(xmain>=0 && xmain <= dx); - - VDASSERT(xprecopy <= 0 || (uint64)u64 >= (uint64)ulimit); - VDASSERT(xprecopy <= 0 || (uint64)(u64 + dudx * (xprecopy-1)) >= (uint64)ulimit); - VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * xprecopy) < (uint64)ulimit); - VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * (xprecopy+xmain-1)) < (uint64)ulimit); - VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain)) >= (uint64)ulimit); - VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain + xpostcopy - 1)) >= (uint64)ulimit); - - u64 += dudx * xprecopy; - } -} - -bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { - // we don't support format conversion - if (dst.format != src.format) - return false; - - void (*pBlitter)(VDPixmapReferenceStretchBltParameters); - int bpp; - - switch(src.format) { - case nsVDPixmap::kPixFormat_Pal8: - pBlitter = VDPixmapStretchBlt_Any8_nearest_reference; - bpp = 1; - break; - case nsVDPixmap::kPixFormat_XRGB1555: - case nsVDPixmap::kPixFormat_RGB565: - pBlitter = VDPixmapStretchBlt_Any16_nearest_reference; - bpp = 2; - break; - case nsVDPixmap::kPixFormat_RGB888: - pBlitter = VDPixmapStretchBlt_Any24_nearest_reference; - bpp = 3; - break; - case nsVDPixmap::kPixFormat_XRGB8888: - pBlitter = VDPixmapStretchBlt_Any32_nearest_reference; - bpp = 4; - break; - default: - return false; - } - - // preemptive clip to prevent gradient calculations from crashing - if (x2 == x1 || y2 == y1) - return true; - - // translate destination flips into source flips - if (x1 > x2) { - std::swap(x1, x2); - std::swap(u1, u2); - } - - if (y1 > y2) { - std::swap(y1, y2); - std::swap(v1, v2); - } - - // compute gradients - sint32 dx = x2 - x1; - sint32 dy = y2 - y1; - sint32 du = u2 - u1; - sint32 dv = v2 - v1; - sint64 dudx = ((sint64)du << 32) / dx; // must truncate toward zero to prevent overflow - sint64 dvdy = ((sint64)dv << 32) / dy; - - // prestep top-left point to pixel center and convert destination coordinates to integer - sint64 u64 = (sint64)u1 << 16; - sint64 v64 = (sint64)v1 << 16; - sint32 prestepx = (0x8000 - x1) & 0xffff; - sint32 prestepy = (0x8000 - y1) & 0xffff; - - u64 += (dudx * prestepx) >> 16; - v64 += (dvdy * prestepy) >> 16; - - sint32 x1i = (x1 + 0x8000) >> 16; - sint32 y1i = (y1 + 0x8000) >> 16; - sint32 x2i = (x2 + 0x8000) >> 16; - sint32 y2i = (y2 + 0x8000) >> 16; - - // destination clipping - if (x1i < 0) { - u64 -= dudx * x1i; - x1i = 0; - } - - if (y1i < 0) { - v64 -= dvdy * y1i; - y1i = 0; - } - - if (x2i > dst.w) - x2i = dst.w; - - if (y2i > dst.h) - y2i = dst.h; - - if (x1i >= x2i || y1i >= y2i) - return true; - - // Calculate horizontal clip parameters - sint32 xprecopy = 0, xpostcopy = 0; - int xprepos = 0; - int xpostpos = src.w-1; - int xmain = 0; - - VDSetupNearestSamplingParameters(u64, dudx, x2i-x1i, src.w, xprecopy, xprepos, xmain, xpostcopy, xpostpos); - - // Calculate vertical clip parameters - sint32 yprecopy = 0, ypostcopy = 0; - int yprepos = 0; - int ypostpos = src.h-1; - int ymain = 0; - - VDSetupNearestSamplingParameters(v64, dvdy, y2i-y1i, src.h, yprecopy, yprepos, ymain, ypostcopy, ypostpos); - - // set up parameter block - VDPixmapReferenceStretchBltParameters params; - - char *srcbase = (char *)src.data + (sint32)(u64 >> 32) * bpp; - - params.dst = (char *)dst.data + y1i * dst.pitch + x1i * bpp; - params.dstpitch = dst.pitch; - params.src = srcbase + (sint32)(v64 >> 32) * src.pitch; - params.srcpitch = src.pitch; - params.srcinc = (sint32)(dvdy >> 32) * src.pitch; - params.dx = xmain; - params.dy = ymain; - params.u = (uint32)u64; - params.uinc = (uint32)(dudx >> 32); - params.dudx = (uint32)dudx; - params.v = (uint32)v64; - params.dvdy = (uint32)dvdy; - params.xprecopy = xprecopy; - params.xprepos = (xprepos - (sint32)(u64 >> 32)) * bpp; - params.xpostcopy = xpostcopy; - params.xpostpos = (xpostpos - (sint32)(u64 >> 32)) * bpp; - - if (yprecopy > 0) { - VDPixmapReferenceStretchBltParameters preparams(params); - - preparams.src = srcbase + yprepos * src.pitch; - preparams.srcinc = 0; - preparams.dy = yprecopy; - preparams.v = 0; - preparams.dvdy = 0; - - pBlitter(preparams); - - params.dst = (char *)params.dst + params.dstpitch * yprecopy; - } - - if (ymain > 0) - pBlitter(params); - - if (ypostcopy > 0) { - VDPixmapReferenceStretchBltParameters postparams(params); - - postparams.dst = (char *)params.dst + params.dstpitch * params.dy; - postparams.src = srcbase + ypostpos * src.pitch; - postparams.srcpitch = 0; - postparams.srcinc = 0; - postparams.dy = ypostcopy; - postparams.v = 0; - postparams.dvdy = 0; - - pBlitter(postparams); - } - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////// - -namespace { - uint32 lerp_XRGB1555(sint32 a, sint32 b, sint32 f) { - sint32 a_rb = a & 0x7c1f; - sint32 a_g = a & 0x03e0; - sint32 b_rb = b & 0x7c1f; - sint32 b_g = b & 0x03e0; - - const sint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x4010) >> 5)) & 0x7c1f; - const sint32 g = (a_g + (((b_g - a_g )*f + 0x0200) >> 5)) & 0x03e0; - - return rb + g; - } - - uint32 lerp_XRGB8888(sint32 a, sint32 b, sint32 f) { - sint32 a_rb = a & 0xff00ff; - sint32 a_g = a & 0x00ff00; - sint32 b_rb = b & 0xff00ff; - sint32 b_g = b & 0x00ff00; - - const uint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x00800080) >> 8)) & 0xff00ff; - const uint32 g = (a_g + (((b_g - a_g )*f + 0x00008000) >> 8)) & 0x00ff00; - - return rb + g; - } - - uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { - sint32 a_rb = a & 0xff00ff; - sint32 a_g = a & 0x00ff00; - sint32 b_rb = b & 0xff00ff; - sint32 b_g = b & 0x00ff00; - sint32 c_rb = c & 0xff00ff; - sint32 c_g = c & 0x00ff00; - sint32 d_rb = d & 0xff00ff; - sint32 d_g = d & 0x00ff00; - - const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; - const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 bot_g = (c_g + (((d_g - c_g )*x + 0x00008000) >> 8)) & 0x00ff00; - - const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff; - const uint32 final_g = (top_g + (((bot_g - top_g )*y) >> 8)) & 0x00ff00; - - return final_rb + final_g; - } - - uint32 bilerp_XRGB1555(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { - sint32 a_rb = a & 0x7c1f; - sint32 a_g = a & 0x03e0; - sint32 b_rb = b & 0x7c1f; - sint32 b_g = b & 0x03e0; - sint32 c_rb = c & 0x7c1f; - sint32 c_g = c & 0x03e0; - sint32 d_rb = d & 0x7c1f; - sint32 d_g = d & 0x03e0; - - const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x4010) >> 5)) & 0x7c1f; - const sint32 top_g = (a_g + (((b_g - a_g )*x + 0x0200) >> 5)) & 0x03e0; - const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x4010) >> 5)) & 0x7c1f; - const sint32 bot_g = (c_g + (((d_g - c_g )*x + 0x0200) >> 5)) & 0x03e0; - - const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x4010) >> 5)) & 0x7c1f; - const sint32 final_g = (top_g + (((bot_g - top_g )*y + 0x0200) >> 5)) & 0x03e0; - - return final_rb + final_g; - } - - uint32 bilerp_RGB565(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { - sint32 a_rb = a & 0xf81f; - sint32 a_g = a & 0x07e0; - sint32 b_rb = b & 0xf81f; - sint32 b_g = b & 0x07e0; - sint32 c_rb = c & 0xf81f; - sint32 c_g = c & 0x07e0; - sint32 d_rb = d & 0xf81f; - sint32 d_g = d & 0x07e0; - - const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x8010) >> 6)) & 0xf81f; - const sint32 top_g = (a_g + (((b_g - a_g )*x + 0x0400) >> 6)) & 0x07e0; - const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x8010) >> 6)) & 0xf81f; - const sint32 bot_g = (c_g + (((d_g - c_g )*x + 0x0400) >> 6)) & 0x07e0; - - const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x8010) >> 6)) & 0xf81f; - const sint32 final_g = (top_g + (((bot_g - top_g )*y + 0x0400) >> 6)) & 0x07e0; - - return final_rb + final_g; - } -} - -/////////////////////////////////////////////////////////////////////////// - -namespace { - struct VDPixmapReferenceStretchBltBilinearParameters { - void *dst; - const void *src; - uint32 u; - uint32 uinc; - uint32 dudx; - - ptrdiff_t xprepos; - ptrdiff_t xpostpos; - sint32 xprecopy; - sint32 xpostcopy; - sint32 xmidsize; - }; - - void VDPixmapStretchBiH_XRGB1555_to_XRGB1555(const VDPixmapReferenceStretchBltBilinearParameters& params) { - uint16 *dst = (uint16 *)params.dst; - const uint16 *src = (const uint16 *)params.src; - - if (params.xprecopy) - VDMemset16(dst - params.xprecopy, *(const uint16 *)((const char *)params.src + params.xprepos), params.xprecopy); - - if (params.xmidsize) { - sint32 w = params.xmidsize; - uint32 u = params.u; - const uint32 dudx = params.dudx; - const ptrdiff_t uinc = params.uinc; - - do { - *dst++ = lerp_XRGB1555(src[0], src[1], u >> 27); - - const uint32 ut = u + dudx; - src += uinc + (ut < u); - u = ut; - } while(--w); - } - - if (params.xpostcopy) - VDMemset16(dst, *(const uint16 *)((const char *)params.src + params.xpostpos), params.xpostcopy); - } - - void VDPixmapStretchBiH_XRGB8888_to_XRGB8888(const VDPixmapReferenceStretchBltBilinearParameters& params) { - uint32 *dst = (uint32 *)params.dst; - const uint32 *src = (const uint32 *)params.src; - - if (params.xprecopy) - VDMemset32(dst - params.xprecopy, *(const uint32 *)((const char *)params.src + params.xprepos), params.xprecopy); - - if (params.xmidsize) { - sint32 w = params.xmidsize; - uint32 u = params.u; - const uint32 dudx = params.dudx; - const ptrdiff_t uinc = params.uinc; - - do { - *dst++ = lerp_XRGB8888(src[0], src[1], u >> 24); - - const uint32 ut = u + dudx; - src += uinc + (ut < u); - u = ut; - } while(--w); - } - - if (params.xpostcopy) - VDMemset32(dst, *(const uint32 *)((const char *)params.src + params.xpostpos), params.xpostcopy); - } - - void VDPixmapStretchBiV_XRGB1555_to_XRGB1555(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) { - uint16 *dst = (uint16 *)dstv; - const uint16 *src1 = (const uint16 *)src1v; - const uint16 *src2 = (const uint16 *)src2v; - - f >>= 27; - - do { - *dst++ = lerp_XRGB1555(*src1++, *src2++, f); - } while(--w); - } - - void VDPixmapStretchBiV_XRGB8888_to_XRGB8888(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) { - uint32 *dst = (uint32 *)dstv; - const uint32 *src1 = (const uint32 *)src1v; - const uint32 *src2 = (const uint32 *)src2v; - - f >>= 24; - - do { - *dst++ = lerp_XRGB8888(*src1++, *src2++, f); - } while(--w); - } -} - -#ifdef _M_IX86 -extern "C" void vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX(const VDPixmapReferenceStretchBltBilinearParameters&); - -extern "C" void vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); -extern "C" void vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); -#endif - -bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { - // preemptive clip to prevent gradient calculations from crashing - if (x2 == x1 || y2 == y1) - return true; - - // we don't support source clipping - if ((uint32)u1 > (uint32)(src.w << 16) || (uint32)v1 > (uint32)(src.h << 16)) - return false; - - if ((uint32)u2 > (uint32)(src.w << 16) || (uint32)v2 > (uint32)(src.h << 16)) - return false; - - // we don't support format changes (yet) - if (dst.format != src.format) - return false; - - // format determination - void (*pHorizontalFilter)(const VDPixmapReferenceStretchBltBilinearParameters& params); - void (*pVerticalFilter)(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); - int bpp; - -#pragma vdpragma_TODO("fixme this is b0rken") - switch(src.format) { - case nsVDPixmap::kPixFormat_XRGB1555: - pHorizontalFilter = VDPixmapStretchBiH_XRGB1555_to_XRGB1555; -#ifdef _M_IX86 - if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) - pVerticalFilter = vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX; - else -#endif - pVerticalFilter = VDPixmapStretchBiV_XRGB1555_to_XRGB1555; - bpp = 2; - break; - case nsVDPixmap::kPixFormat_XRGB8888: -#ifdef _M_IX86 - if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) { - pHorizontalFilter = vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX; - pVerticalFilter = vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX; - } else -#endif - { - pHorizontalFilter = VDPixmapStretchBiH_XRGB8888_to_XRGB8888; - pVerticalFilter = VDPixmapStretchBiV_XRGB8888_to_XRGB8888; - } - bpp = 4; - break; - default: - return false; - } - - // translate destination flips into source flips - if (x1 > x2) { - std::swap(x1, x2); - std::swap(u1, u2); - } - - if (y1 > y2) { - std::swap(y1, y2); - std::swap(v1, v2); - } - - // compute gradients - sint32 dx = x2 - x1; - sint32 dy = y2 - y1; - sint32 du = u2 - u1; - sint32 dv = v2 - v1; - sint64 dudx = ((sint64)du << 32) / dx; // must truncate toward zero to prevent overflow - sint64 dvdy = ((sint64)dv << 32) / dy; - - // prestep top-left point to pixel center and convert destination coordinates to integer - sint64 u64 = (sint64)u1 << 16; - sint64 v64 = (sint64)v1 << 16; - sint32 prestepx = (0x8000 - x1) & 0xffff; - sint32 prestepy = (0x8000 - y1) & 0xffff; - - u64 += (dudx * prestepx) >> 16; - v64 += (dvdy * prestepy) >> 16; - - sint32 x1i = (x1 + 0x8000) >> 16; - sint32 y1i = (y1 + 0x8000) >> 16; - sint32 x2i = (x2 + 0x8000) >> 16; - sint32 y2i = (y2 + 0x8000) >> 16; - - // destination clipping - if (x1i < 0) { - u64 -= dudx * x1i; - x1i = 0; - } - - if (y1i < 0) { - v64 -= dvdy * y1i; - y1i = 0; - } - - if (x2i > dst.w) - x2i = dst.w; - - if (y2i > dst.h) - y2i = dst.h; - - if (x1i >= x2i || y1i >= y2i) - return true; - - u64 -= 0x80000000; - v64 -= 0x80000000; - - int xprepos = 0; - int xpostpos = src.w-1; - - sint64 ulo = u64; - sint64 uhi = u64 + dudx * (x2i - x1i - 1); - sint64 tdudx = dudx; - - if (ulo > uhi) { - std::swap(ulo, uhi); - tdudx = -tdudx; - } - - int xprecopy = 0; - int xpostcopy = 0; - - if (ulo < 0) { - xprecopy = (int)((1 - ulo) / tdudx) + 1; - } - - const sint64 ulimit = ((sint64)(src.w-1) << 32); - - if (uhi >= ulimit) - xpostcopy = (int)((uhi - ulimit - 1) / tdudx) + 1; - - if (dudx < 0) { - std::swap(xprecopy, xpostcopy); - std::swap(xprepos, xpostpos); - } - - u64 += dudx * xprecopy; - const int xtotal = x2i - x1i; - int xmidcopy = (x2i - x1i) - (xprecopy + xpostcopy); - const sint32 ui = (sint32)(u64 >> 32); - - // set up parameter block - - VDPixmapReferenceStretchBltBilinearParameters params; - - params.u = (uint32)u64; - params.uinc = (sint32)(dudx >> 32); - params.dudx = (sint32)dudx; - params.xprecopy = xprecopy; - params.xprepos = (xprepos - ui) * bpp; - params.xpostcopy = xpostcopy; - params.xpostpos = (xpostpos - ui) * bpp; - params.xmidsize = xmidcopy; - - void *dstp = (char *)dst.data + y1i * dst.pitch + x1i * bpp; - const void *srcp = (char *)src.data + ui * bpp; - - VDPixmapBuffer window(xtotal, 2, src.format); - - void *pTempRow1 = window.data; - void *pTempRow2 = (char *)window.data + window.pitch; - int windowbottom = dvdy > 0 ? -0x7fffffff : 0x7fffffff; - - do { - sint32 iv = (sint32)(v64 >> 32); - sint32 iv_bottom = iv + 1; - - if (iv < 0) - iv = iv_bottom = 0; - - if (iv >= src.h-1) - iv = iv_bottom = src.h-1; - - if (dvdy < 0) { - if (windowbottom > iv_bottom+1) - windowbottom = iv_bottom+1; - - while(windowbottom > iv) { - std::swap(pTempRow1, pTempRow2); - - --windowbottom; - - params.dst = (char *)pTempRow1 + bpp * params.xprecopy; - params.src = vdptroffset(srcp, windowbottom * src.pitch); - - pHorizontalFilter(params); - } - } else { - if (windowbottom < iv-1) - windowbottom = iv-1; - - while(windowbottom < iv_bottom) { - std::swap(pTempRow1, pTempRow2); - - ++windowbottom; - - params.dst = (char *)pTempRow2 + bpp * params.xprecopy; - params.src = vdptroffset(srcp, windowbottom * src.pitch); - - pHorizontalFilter(params); - } - } - - if (iv == iv_bottom) - if (dvdy < 0) - pVerticalFilter(dstp, pTempRow1, pTempRow1, xtotal, 0); - else - pVerticalFilter(dstp, pTempRow2, pTempRow2, xtotal, 0); - else - pVerticalFilter(dstp, pTempRow1, pTempRow2, xtotal, (uint32)v64); - - v64 += dvdy; - dstp = (char *)dstp + dst.pitch; - } while(++y1i < y2i); - - return true; -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include + +namespace { + struct VDPixmapReferenceStretchBltParameters { + void *dst; + ptrdiff_t dstpitch; + const void *src; + ptrdiff_t srcpitch; + ptrdiff_t srcinc; + sint32 dx; + sint32 dy; + uint32 u; + uint32 uinc; + uint32 dudx; + uint32 v; + uint32 dvdy; + sint32 xprecopy; + sint32 xpostcopy; + ptrdiff_t xprepos; + ptrdiff_t xpostpos; + + void advance() { + dst = (char *)dst + dstpitch; + src = (char *)src + srcinc; + + uint32 vt = v + dvdy; + + if (vt < v) + src = (char *)src + srcpitch; + + v = vt; + } + }; +} + +void VDPixmapStretchBlt_Any8_nearest_reference(VDPixmapReferenceStretchBltParameters params) { + do { + uint8 *dstp = (uint8 *)params.dst; + const uint8 *srcp = (const uint8 *)params.src; + uint32 u = params.u; + + if (params.xprecopy) { + VDMemset8(dstp, *(const uint8 *)((const char *)params.src + params.xprepos), params.xprecopy); + dstp += params.xprecopy; + } + + sint32 wt = params.dx; + + if (wt > 0) + do { + *dstp++ = *srcp; + + uint32 ut = u + params.dudx; + srcp += ut 0) + do { + *dstp++ = *srcp; + + uint32 ut = u + params.dudx; + srcp += ut 0) + do { + dstp[0] = srcp[0]; + dstp[1] = srcp[1]; + dstp[2] = srcp[2]; + dstp += 3; + + uint32 ut = u + params.dudx; + srcp += (ut 0) + do { + *dstp++ = *srcp; + + uint32 ut = u + params.dudx; + srcp += ut= ulimit) + xprecopy = dx; + else + xmain = dx; + } else { + if (tdudx < 0) { + std::swap(ulo, uhi); + tdudx = -tdudx; + } + + if (ulo < 0) { + if (uhi < 0) + xprecopy = dx; + else + xprecopy = (sint32)((-ulo-1) / tdudx) + 1; + + VDASSERT(xprecopy <= 0 || (uint64)ulo >= (uint64)ulimit); + VDASSERT(xprecopy <= 0 || (uint64)(ulo + tdudx * (xprecopy-1)) >= (uint64)ulimit); + } + + if (uhi >= ulimit) { + if (ulo >= ulimit) + xpostcopy = dx; + else + xpostcopy = (sint32)((uhi - ulimit) / tdudx) + 1; + + VDASSERT(xpostcopy <= 0 || (uint64)uhi >= (uint64)ulimit); + VDASSERT(xpostcopy <= 0 || (uint64)(uhi - tdudx * (xpostcopy - 1)) >= (uint64)ulimit); + } + + if (dudx < 0) { + std::swap(xprecopy, xpostcopy); + std::swap(xprepos, xpostpos); + } + + xmain = dx - (xprecopy + xpostcopy); + } + + // sanity-check parameters + + VDASSERT(xprecopy>=0 && xprecopy <= dx); + VDASSERT(xpostcopy>=0 && xpostcopy <= dx); + VDASSERT(xmain>=0 && xmain <= dx); + + VDASSERT(xprecopy <= 0 || (uint64)u64 >= (uint64)ulimit); + VDASSERT(xprecopy <= 0 || (uint64)(u64 + dudx * (xprecopy-1)) >= (uint64)ulimit); + VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * xprecopy) < (uint64)ulimit); + VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * (xprecopy+xmain-1)) < (uint64)ulimit); + VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain)) >= (uint64)ulimit); + VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain + xpostcopy - 1)) >= (uint64)ulimit); + + u64 += dudx * xprecopy; + } +} + +bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { + // we don't support format conversion + if (dst.format != src.format) + return false; + + void (*pBlitter)(VDPixmapReferenceStretchBltParameters); + int bpp; + + switch(src.format) { + case nsVDPixmap::kPixFormat_Pal8: + pBlitter = VDPixmapStretchBlt_Any8_nearest_reference; + bpp = 1; + break; + case nsVDPixmap::kPixFormat_XRGB1555: + case nsVDPixmap::kPixFormat_RGB565: + pBlitter = VDPixmapStretchBlt_Any16_nearest_reference; + bpp = 2; + break; + case nsVDPixmap::kPixFormat_RGB888: + pBlitter = VDPixmapStretchBlt_Any24_nearest_reference; + bpp = 3; + break; + case nsVDPixmap::kPixFormat_XRGB8888: + pBlitter = VDPixmapStretchBlt_Any32_nearest_reference; + bpp = 4; + break; + default: + return false; + } + + // preemptive clip to prevent gradient calculations from crashing + if (x2 == x1 || y2 == y1) + return true; + + // translate destination flips into source flips + if (x1 > x2) { + std::swap(x1, x2); + std::swap(u1, u2); + } + + if (y1 > y2) { + std::swap(y1, y2); + std::swap(v1, v2); + } + + // compute gradients + sint32 dx = x2 - x1; + sint32 dy = y2 - y1; + sint32 du = u2 - u1; + sint32 dv = v2 - v1; + sint64 dudx = ((sint64)du << 32) / dx; // must truncate toward zero to prevent overflow + sint64 dvdy = ((sint64)dv << 32) / dy; + + // prestep top-left point to pixel center and convert destination coordinates to integer + sint64 u64 = (sint64)u1 << 16; + sint64 v64 = (sint64)v1 << 16; + sint32 prestepx = (0x8000 - x1) & 0xffff; + sint32 prestepy = (0x8000 - y1) & 0xffff; + + u64 += (dudx * prestepx) >> 16; + v64 += (dvdy * prestepy) >> 16; + + sint32 x1i = (x1 + 0x8000) >> 16; + sint32 y1i = (y1 + 0x8000) >> 16; + sint32 x2i = (x2 + 0x8000) >> 16; + sint32 y2i = (y2 + 0x8000) >> 16; + + // destination clipping + if (x1i < 0) { + u64 -= dudx * x1i; + x1i = 0; + } + + if (y1i < 0) { + v64 -= dvdy * y1i; + y1i = 0; + } + + if (x2i > dst.w) + x2i = dst.w; + + if (y2i > dst.h) + y2i = dst.h; + + if (x1i >= x2i || y1i >= y2i) + return true; + + // Calculate horizontal clip parameters + sint32 xprecopy = 0, xpostcopy = 0; + int xprepos = 0; + int xpostpos = src.w-1; + int xmain = 0; + + VDSetupNearestSamplingParameters(u64, dudx, x2i-x1i, src.w, xprecopy, xprepos, xmain, xpostcopy, xpostpos); + + // Calculate vertical clip parameters + sint32 yprecopy = 0, ypostcopy = 0; + int yprepos = 0; + int ypostpos = src.h-1; + int ymain = 0; + + VDSetupNearestSamplingParameters(v64, dvdy, y2i-y1i, src.h, yprecopy, yprepos, ymain, ypostcopy, ypostpos); + + // set up parameter block + VDPixmapReferenceStretchBltParameters params; + + char *srcbase = (char *)src.data + (sint32)(u64 >> 32) * bpp; + + params.dst = (char *)dst.data + y1i * dst.pitch + x1i * bpp; + params.dstpitch = dst.pitch; + params.src = srcbase + (sint32)(v64 >> 32) * src.pitch; + params.srcpitch = src.pitch; + params.srcinc = (sint32)(dvdy >> 32) * src.pitch; + params.dx = xmain; + params.dy = ymain; + params.u = (uint32)u64; + params.uinc = (uint32)(dudx >> 32); + params.dudx = (uint32)dudx; + params.v = (uint32)v64; + params.dvdy = (uint32)dvdy; + params.xprecopy = xprecopy; + params.xprepos = (xprepos - (sint32)(u64 >> 32)) * bpp; + params.xpostcopy = xpostcopy; + params.xpostpos = (xpostpos - (sint32)(u64 >> 32)) * bpp; + + if (yprecopy > 0) { + VDPixmapReferenceStretchBltParameters preparams(params); + + preparams.src = srcbase + yprepos * src.pitch; + preparams.srcinc = 0; + preparams.dy = yprecopy; + preparams.v = 0; + preparams.dvdy = 0; + + pBlitter(preparams); + + params.dst = (char *)params.dst + params.dstpitch * yprecopy; + } + + if (ymain > 0) + pBlitter(params); + + if (ypostcopy > 0) { + VDPixmapReferenceStretchBltParameters postparams(params); + + postparams.dst = (char *)params.dst + params.dstpitch * params.dy; + postparams.src = srcbase + ypostpos * src.pitch; + postparams.srcpitch = 0; + postparams.srcinc = 0; + postparams.dy = ypostcopy; + postparams.v = 0; + postparams.dvdy = 0; + + pBlitter(postparams); + } + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////////////// + +namespace { + uint32 lerp_XRGB1555(sint32 a, sint32 b, sint32 f) { + sint32 a_rb = a & 0x7c1f; + sint32 a_g = a & 0x03e0; + sint32 b_rb = b & 0x7c1f; + sint32 b_g = b & 0x03e0; + + const sint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x4010) >> 5)) & 0x7c1f; + const sint32 g = (a_g + (((b_g - a_g )*f + 0x0200) >> 5)) & 0x03e0; + + return rb + g; + } + + uint32 lerp_XRGB8888(sint32 a, sint32 b, sint32 f) { + sint32 a_rb = a & 0xff00ff; + sint32 a_g = a & 0x00ff00; + sint32 b_rb = b & 0xff00ff; + sint32 b_g = b & 0x00ff00; + + const uint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x00800080) >> 8)) & 0xff00ff; + const uint32 g = (a_g + (((b_g - a_g )*f + 0x00008000) >> 8)) & 0x00ff00; + + return rb + g; + } + + uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { + sint32 a_rb = a & 0xff00ff; + sint32 a_g = a & 0x00ff00; + sint32 b_rb = b & 0xff00ff; + sint32 b_g = b & 0x00ff00; + sint32 c_rb = c & 0xff00ff; + sint32 c_g = c & 0x00ff00; + sint32 d_rb = d & 0xff00ff; + sint32 d_g = d & 0x00ff00; + + const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; + const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 bot_g = (c_g + (((d_g - c_g )*x + 0x00008000) >> 8)) & 0x00ff00; + + const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff; + const uint32 final_g = (top_g + (((bot_g - top_g )*y) >> 8)) & 0x00ff00; + + return final_rb + final_g; + } + + uint32 bilerp_XRGB1555(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { + sint32 a_rb = a & 0x7c1f; + sint32 a_g = a & 0x03e0; + sint32 b_rb = b & 0x7c1f; + sint32 b_g = b & 0x03e0; + sint32 c_rb = c & 0x7c1f; + sint32 c_g = c & 0x03e0; + sint32 d_rb = d & 0x7c1f; + sint32 d_g = d & 0x03e0; + + const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x4010) >> 5)) & 0x7c1f; + const sint32 top_g = (a_g + (((b_g - a_g )*x + 0x0200) >> 5)) & 0x03e0; + const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x4010) >> 5)) & 0x7c1f; + const sint32 bot_g = (c_g + (((d_g - c_g )*x + 0x0200) >> 5)) & 0x03e0; + + const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x4010) >> 5)) & 0x7c1f; + const sint32 final_g = (top_g + (((bot_g - top_g )*y + 0x0200) >> 5)) & 0x03e0; + + return final_rb + final_g; + } + + uint32 bilerp_RGB565(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { + sint32 a_rb = a & 0xf81f; + sint32 a_g = a & 0x07e0; + sint32 b_rb = b & 0xf81f; + sint32 b_g = b & 0x07e0; + sint32 c_rb = c & 0xf81f; + sint32 c_g = c & 0x07e0; + sint32 d_rb = d & 0xf81f; + sint32 d_g = d & 0x07e0; + + const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x8010) >> 6)) & 0xf81f; + const sint32 top_g = (a_g + (((b_g - a_g )*x + 0x0400) >> 6)) & 0x07e0; + const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x8010) >> 6)) & 0xf81f; + const sint32 bot_g = (c_g + (((d_g - c_g )*x + 0x0400) >> 6)) & 0x07e0; + + const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x8010) >> 6)) & 0xf81f; + const sint32 final_g = (top_g + (((bot_g - top_g )*y + 0x0400) >> 6)) & 0x07e0; + + return final_rb + final_g; + } +} + +/////////////////////////////////////////////////////////////////////////// + +namespace { + struct VDPixmapReferenceStretchBltBilinearParameters { + void *dst; + const void *src; + uint32 u; + uint32 uinc; + uint32 dudx; + + ptrdiff_t xprepos; + ptrdiff_t xpostpos; + sint32 xprecopy; + sint32 xpostcopy; + sint32 xmidsize; + }; + + void VDPixmapStretchBiH_XRGB1555_to_XRGB1555(const VDPixmapReferenceStretchBltBilinearParameters& params) { + uint16 *dst = (uint16 *)params.dst; + const uint16 *src = (const uint16 *)params.src; + + if (params.xprecopy) + VDMemset16(dst - params.xprecopy, *(const uint16 *)((const char *)params.src + params.xprepos), params.xprecopy); + + if (params.xmidsize) { + sint32 w = params.xmidsize; + uint32 u = params.u; + const uint32 dudx = params.dudx; + const ptrdiff_t uinc = params.uinc; + + do { + *dst++ = lerp_XRGB1555(src[0], src[1], u >> 27); + + const uint32 ut = u + dudx; + src += uinc + (ut < u); + u = ut; + } while(--w); + } + + if (params.xpostcopy) + VDMemset16(dst, *(const uint16 *)((const char *)params.src + params.xpostpos), params.xpostcopy); + } + + void VDPixmapStretchBiH_XRGB8888_to_XRGB8888(const VDPixmapReferenceStretchBltBilinearParameters& params) { + uint32 *dst = (uint32 *)params.dst; + const uint32 *src = (const uint32 *)params.src; + + if (params.xprecopy) + VDMemset32(dst - params.xprecopy, *(const uint32 *)((const char *)params.src + params.xprepos), params.xprecopy); + + if (params.xmidsize) { + sint32 w = params.xmidsize; + uint32 u = params.u; + const uint32 dudx = params.dudx; + const ptrdiff_t uinc = params.uinc; + + do { + *dst++ = lerp_XRGB8888(src[0], src[1], u >> 24); + + const uint32 ut = u + dudx; + src += uinc + (ut < u); + u = ut; + } while(--w); + } + + if (params.xpostcopy) + VDMemset32(dst, *(const uint32 *)((const char *)params.src + params.xpostpos), params.xpostcopy); + } + + void VDPixmapStretchBiV_XRGB1555_to_XRGB1555(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) { + uint16 *dst = (uint16 *)dstv; + const uint16 *src1 = (const uint16 *)src1v; + const uint16 *src2 = (const uint16 *)src2v; + + f >>= 27; + + do { + *dst++ = lerp_XRGB1555(*src1++, *src2++, f); + } while(--w); + } + + void VDPixmapStretchBiV_XRGB8888_to_XRGB8888(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) { + uint32 *dst = (uint32 *)dstv; + const uint32 *src1 = (const uint32 *)src1v; + const uint32 *src2 = (const uint32 *)src2v; + + f >>= 24; + + do { + *dst++ = lerp_XRGB8888(*src1++, *src2++, f); + } while(--w); + } +} + +#ifdef _M_IX86 +extern "C" void vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX(const VDPixmapReferenceStretchBltBilinearParameters&); + +extern "C" void vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); +extern "C" void vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); +#endif + +bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) { + // preemptive clip to prevent gradient calculations from crashing + if (x2 == x1 || y2 == y1) + return true; + + // we don't support source clipping + if ((uint32)u1 > (uint32)(src.w << 16) || (uint32)v1 > (uint32)(src.h << 16)) + return false; + + if ((uint32)u2 > (uint32)(src.w << 16) || (uint32)v2 > (uint32)(src.h << 16)) + return false; + + // we don't support format changes (yet) + if (dst.format != src.format) + return false; + + // format determination + void (*pHorizontalFilter)(const VDPixmapReferenceStretchBltBilinearParameters& params); + void (*pVerticalFilter)(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f); + int bpp; + +#pragma vdpragma_TODO("fixme this is b0rken") + switch(src.format) { + case nsVDPixmap::kPixFormat_XRGB1555: + pHorizontalFilter = VDPixmapStretchBiH_XRGB1555_to_XRGB1555; +#ifdef _M_IX86 + if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) + pVerticalFilter = vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX; + else +#endif + pVerticalFilter = VDPixmapStretchBiV_XRGB1555_to_XRGB1555; + bpp = 2; + break; + case nsVDPixmap::kPixFormat_XRGB8888: +#ifdef _M_IX86 + if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) { + pHorizontalFilter = vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX; + pVerticalFilter = vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX; + } else +#endif + { + pHorizontalFilter = VDPixmapStretchBiH_XRGB8888_to_XRGB8888; + pVerticalFilter = VDPixmapStretchBiV_XRGB8888_to_XRGB8888; + } + bpp = 4; + break; + default: + return false; + } + + // translate destination flips into source flips + if (x1 > x2) { + std::swap(x1, x2); + std::swap(u1, u2); + } + + if (y1 > y2) { + std::swap(y1, y2); + std::swap(v1, v2); + } + + // compute gradients + sint32 dx = x2 - x1; + sint32 dy = y2 - y1; + sint32 du = u2 - u1; + sint32 dv = v2 - v1; + sint64 dudx = ((sint64)du << 32) / dx; // must truncate toward zero to prevent overflow + sint64 dvdy = ((sint64)dv << 32) / dy; + + // prestep top-left point to pixel center and convert destination coordinates to integer + sint64 u64 = (sint64)u1 << 16; + sint64 v64 = (sint64)v1 << 16; + sint32 prestepx = (0x8000 - x1) & 0xffff; + sint32 prestepy = (0x8000 - y1) & 0xffff; + + u64 += (dudx * prestepx) >> 16; + v64 += (dvdy * prestepy) >> 16; + + sint32 x1i = (x1 + 0x8000) >> 16; + sint32 y1i = (y1 + 0x8000) >> 16; + sint32 x2i = (x2 + 0x8000) >> 16; + sint32 y2i = (y2 + 0x8000) >> 16; + + // destination clipping + if (x1i < 0) { + u64 -= dudx * x1i; + x1i = 0; + } + + if (y1i < 0) { + v64 -= dvdy * y1i; + y1i = 0; + } + + if (x2i > dst.w) + x2i = dst.w; + + if (y2i > dst.h) + y2i = dst.h; + + if (x1i >= x2i || y1i >= y2i) + return true; + + u64 -= 0x80000000; + v64 -= 0x80000000; + + int xprepos = 0; + int xpostpos = src.w-1; + + sint64 ulo = u64; + sint64 uhi = u64 + dudx * (x2i - x1i - 1); + sint64 tdudx = dudx; + + if (ulo > uhi) { + std::swap(ulo, uhi); + tdudx = -tdudx; + } + + int xprecopy = 0; + int xpostcopy = 0; + + if (ulo < 0) { + xprecopy = (int)((1 - ulo) / tdudx) + 1; + } + + const sint64 ulimit = ((sint64)(src.w-1) << 32); + + if (uhi >= ulimit) + xpostcopy = (int)((uhi - ulimit - 1) / tdudx) + 1; + + if (dudx < 0) { + std::swap(xprecopy, xpostcopy); + std::swap(xprepos, xpostpos); + } + + u64 += dudx * xprecopy; + const int xtotal = x2i - x1i; + int xmidcopy = (x2i - x1i) - (xprecopy + xpostcopy); + const sint32 ui = (sint32)(u64 >> 32); + + // set up parameter block + + VDPixmapReferenceStretchBltBilinearParameters params; + + params.u = (uint32)u64; + params.uinc = (sint32)(dudx >> 32); + params.dudx = (sint32)dudx; + params.xprecopy = xprecopy; + params.xprepos = (xprepos - ui) * bpp; + params.xpostcopy = xpostcopy; + params.xpostpos = (xpostpos - ui) * bpp; + params.xmidsize = xmidcopy; + + void *dstp = (char *)dst.data + y1i * dst.pitch + x1i * bpp; + const void *srcp = (char *)src.data + ui * bpp; + + VDPixmapBuffer window(xtotal, 2, src.format); + + void *pTempRow1 = window.data; + void *pTempRow2 = (char *)window.data + window.pitch; + int windowbottom = dvdy > 0 ? -0x7fffffff : 0x7fffffff; + + do { + sint32 iv = (sint32)(v64 >> 32); + sint32 iv_bottom = iv + 1; + + if (iv < 0) + iv = iv_bottom = 0; + + if (iv >= src.h-1) + iv = iv_bottom = src.h-1; + + if (dvdy < 0) { + if (windowbottom > iv_bottom+1) + windowbottom = iv_bottom+1; + + while(windowbottom > iv) { + std::swap(pTempRow1, pTempRow2); + + --windowbottom; + + params.dst = (char *)pTempRow1 + bpp * params.xprecopy; + params.src = vdptroffset(srcp, windowbottom * src.pitch); + + pHorizontalFilter(params); + } + } else { + if (windowbottom < iv-1) + windowbottom = iv-1; + + while(windowbottom < iv_bottom) { + std::swap(pTempRow1, pTempRow2); + + ++windowbottom; + + params.dst = (char *)pTempRow2 + bpp * params.xprecopy; + params.src = vdptroffset(srcp, windowbottom * src.pitch); + + pHorizontalFilter(params); + } + } + + if (iv == iv_bottom) + if (dvdy < 0) + pVerticalFilter(dstp, pTempRow1, pTempRow1, xtotal, 0); + else + pVerticalFilter(dstp, pTempRow2, pTempRow2, xtotal, 0); + else + pVerticalFilter(dstp, pTempRow1, pTempRow2, xtotal, (uint32)v64); + + v64 += dvdy; + dstp = (char *)dstp + dst.pitch; + } while(++y1i < y2i); + + return true; +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/tables.cpp b/src/thirdparty/VirtualDub/Kasumi/source/tables.cpp index 0d872aab354..4107ded9541 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/tables.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/tables.cpp @@ -1,205 +1,205 @@ -// Automatically generated by Asuka 'maketables.'" DO NOT EDIT! - -#include -#include - -extern "C" const sint32 kVDCubicInterpTableFX14_075[256][4]={ - { 0, 16384, 0, 0 }, { -48, 16384, 48, 0 }, { -95, 16383, 97, -1 }, { -141, 16380, 147, -2 }, - { -186, 16375, 198, -3 }, { -231, 16371, 249, -5 }, { -275, 16365, 301, -7 }, { -318, 16357, 354, -9 }, - { -360, 16349, 407, -12 }, { -402, 16340, 461, -15 }, { -443, 16329, 516, -18 }, { -484, 16318, 572, -22 }, - { -523, 16305, 628, -26 }, { -562, 16291, 685, -30 }, { -601, 16278, 742, -35 }, { -638, 16262, 800, -40 }, - { -675, 16245, 859, -45 }, { -711, 16228, 918, -51 }, { -747, 16209, 978, -56 }, { -782, 16190, 1039, -63 }, - { -816, 16169, 1100, -69 }, { -849, 16147, 1162, -76 }, { -882, 16124, 1225, -83 }, { -915, 16101, 1288, -90 }, - { -946, 16077, 1351, -98 }, { -977, 16052, 1415, -106 }, { -1007, 16025, 1480, -114 }, { -1037, 15998, 1545, -122 }, - { -1066, 15970, 1611, -131 }, { -1094, 15940, 1678, -140 }, { -1122, 15910, 1745, -149 }, { -1149, 15879, 1812, -158 }, - { -1176, 15848, 1880, -168 }, { -1202, 15815, 1949, -178 }, { -1227, 15781, 2018, -188 }, { -1252, 15747, 2087, -198 }, - { -1276, 15712, 2157, -209 }, { -1300, 15676, 2228, -220 }, { -1323, 15639, 2299, -231 }, { -1345, 15601, 2370, -242 }, - { -1367, 15562, 2442, -253 }, { -1388, 15523, 2514, -265 }, { -1409, 15482, 2587, -276 }, { -1429, 15441, 2660, -288 }, - { -1448, 15399, 2734, -301 }, { -1467, 15356, 2808, -313 }, { -1486, 15312, 2883, -325 }, { -1504, 15268, 2958, -338 }, - { -1521, 15223, 3033, -351 }, { -1538, 15177, 3109, -364 }, { -1554, 15130, 3185, -377 }, { -1570, 15084, 3261, -391 }, - { -1585, 15035, 3338, -404 }, { -1600, 14986, 3416, -418 }, { -1614, 14936, 3493, -431 }, { -1627, 14885, 3571, -445 }, - { -1641, 14834, 3650, -459 }, { -1653, 14783, 3728, -474 }, { -1665, 14730, 3807, -488 }, { -1677, 14676, 3887, -502 }, - { -1688, 14623, 3966, -517 }, { -1699, 14568, 4046, -531 }, { -1709, 14512, 4127, -546 }, { -1719, 14457, 4207, -561 }, - { -1728, 14400, 4288, -576 }, { -1737, 14343, 4369, -591 }, { -1745, 14284, 4451, -606 }, { -1753, 14226, 4532, -621 }, - { -1760, 14167, 4614, -637 }, { -1767, 14107, 4696, -652 }, { -1774, 14047, 4779, -668 }, { -1780, 13986, 4861, -683 }, - { -1785, 13924, 4944, -699 }, { -1791, 13861, 5028, -714 }, { -1795, 13798, 5111, -730 }, { -1800, 13736, 5194, -746 }, - { -1804, 13671, 5278, -761 }, { -1807, 13606, 5362, -777 }, { -1810, 13541, 5446, -793 }, { -1813, 13475, 5531, -809 }, - { -1815, 13409, 5615, -825 }, { -1817, 13342, 5700, -841 }, { -1818, 13275, 5784, -857 }, { -1819, 13207, 5869, -873 }, - { -1820, 13139, 5954, -889 }, { -1820, 13069, 6040, -905 }, { -1820, 13000, 6125, -921 }, { -1820, 12930, 6211, -937 }, - { -1819, 12860, 6296, -953 }, { -1818, 12789, 6382, -969 }, { -1816, 12717, 6468, -985 }, { -1815, 12647, 6553, -1001 }, - { -1812, 12574, 6639, -1017 }, { -1810, 12502, 6725, -1033 }, { -1807, 12427, 6812, -1048 }, { -1804, 12354, 6898, -1064 }, - { -1800, 12280, 6984, -1080 }, { -1796, 12206, 7070, -1096 }, { -1792, 12130, 7157, -1111 }, { -1787, 12055, 7243, -1127 }, - { -1782, 11980, 7329, -1143 }, { -1777, 11903, 7416, -1158 }, { -1772, 11827, 7502, -1173 }, { -1766, 11751, 7588, -1189 }, - { -1760, 11673, 7675, -1204 }, { -1753, 11595, 7761, -1219 }, { -1747, 11517, 7848, -1234 }, { -1740, 11439, 7934, -1249 }, - { -1733, 11361, 8020, -1264 }, { -1725, 11281, 8107, -1279 }, { -1717, 11202, 8193, -1294 }, { -1709, 11123, 8279, -1309 }, - { -1701, 11043, 8365, -1323 }, { -1692, 10962, 8451, -1337 }, { -1684, 10883, 8537, -1352 }, { -1675, 10802, 8623, -1366 }, - { -1665, 10720, 8709, -1380 }, { -1656, 10640, 8794, -1394 }, { -1646, 10557, 8880, -1407 }, { -1636, 10476, 8965, -1421 }, - { -1626, 10393, 9051, -1434 }, { -1615, 10311, 9136, -1448 }, { -1604, 10228, 9221, -1461 }, { -1594, 10146, 9306, -1474 }, - { -1582, 10062, 9391, -1487 }, { -1571, 9979, 9475, -1499 }, { -1560, 9896, 9560, -1512 }, { -1548, 9812, 9644, -1524 }, - { -1536, 9728, 9728, -1536 }, { -1524, 9644, 9812, -1548 }, { -1512, 9560, 9896, -1560 }, { -1499, 9475, 9979, -1571 }, - { -1487, 9391, 10062, -1582 }, { -1474, 9306, 10146, -1594 }, { -1461, 9221, 10228, -1604 }, { -1448, 9136, 10311, -1615 }, - { -1434, 9051, 10393, -1626 }, { -1421, 8965, 10476, -1636 }, { -1407, 8880, 10557, -1646 }, { -1394, 8795, 10639, -1656 }, - { -1380, 8709, 10720, -1665 }, { -1366, 8624, 10801, -1675 }, { -1352, 8538, 10882, -1684 }, { -1337, 8450, 10963, -1692 }, - { -1323, 8365, 11043, -1701 }, { -1309, 8279, 11123, -1709 }, { -1294, 8192, 11203, -1717 }, { -1279, 8106, 11282, -1725 }, - { -1264, 8020, 11361, -1733 }, { -1249, 7934, 11439, -1740 }, { -1234, 7847, 11518, -1747 }, { -1219, 7760, 11596, -1753 }, - { -1204, 7675, 11673, -1760 }, { -1189, 7589, 11750, -1766 }, { -1173, 7502, 11827, -1772 }, { -1158, 7415, 11904, -1777 }, - { -1143, 7329, 11980, -1782 }, { -1127, 7243, 12055, -1787 }, { -1111, 7156, 12131, -1792 }, { -1096, 7070, 12206, -1796 }, - { -1080, 6984, 12280, -1800 }, { -1064, 6898, 12354, -1804 }, { -1048, 6811, 12428, -1807 }, { -1033, 6726, 12501, -1810 }, - { -1017, 6639, 12574, -1812 }, { -1001, 6554, 12646, -1815 }, { -985, 6467, 12718, -1816 }, { -969, 6382, 12789, -1818 }, - { -953, 6296, 12860, -1819 }, { -937, 6211, 12930, -1820 }, { -921, 6125, 13000, -1820 }, { -905, 6039, 13070, -1820 }, - { -889, 5954, 13139, -1820 }, { -873, 5869, 13207, -1819 }, { -857, 5784, 13275, -1818 }, { -841, 5700, 13342, -1817 }, - { -825, 5615, 13409, -1815 }, { -809, 5531, 13475, -1813 }, { -793, 5446, 13541, -1810 }, { -777, 5362, 13606, -1807 }, - { -761, 5278, 13671, -1804 }, { -746, 5195, 13735, -1800 }, { -730, 5111, 13798, -1795 }, { -714, 5028, 13861, -1791 }, - { -699, 4944, 13924, -1785 }, { -683, 4862, 13985, -1780 }, { -668, 4780, 14046, -1774 }, { -652, 4696, 14107, -1767 }, - { -637, 4614, 14167, -1760 }, { -621, 4532, 14226, -1753 }, { -606, 4450, 14285, -1745 }, { -591, 4369, 14343, -1737 }, - { -576, 4288, 14400, -1728 }, { -561, 4207, 14457, -1719 }, { -546, 4126, 14513, -1709 }, { -531, 4046, 14568, -1699 }, - { -517, 3966, 14623, -1688 }, { -502, 3886, 14677, -1677 }, { -488, 3807, 14730, -1665 }, { -474, 3728, 14783, -1653 }, - { -459, 3650, 14834, -1641 }, { -445, 3570, 14886, -1627 }, { -431, 3493, 14936, -1614 }, { -418, 3416, 14986, -1600 }, - { -404, 3338, 15035, -1585 }, { -391, 3262, 15083, -1570 }, { -377, 3185, 15130, -1554 }, { -364, 3109, 15177, -1538 }, - { -351, 3033, 15223, -1521 }, { -338, 2958, 15268, -1504 }, { -325, 2882, 15313, -1486 }, { -313, 2808, 15356, -1467 }, - { -301, 2734, 15399, -1448 }, { -288, 2660, 15441, -1429 }, { -276, 2587, 15482, -1409 }, { -265, 2514, 15523, -1388 }, - { -253, 2442, 15562, -1367 }, { -242, 2370, 15601, -1345 }, { -231, 2299, 15639, -1323 }, { -220, 2228, 15676, -1300 }, - { -209, 2157, 15712, -1276 }, { -198, 2087, 15747, -1252 }, { -188, 2017, 15782, -1227 }, { -178, 1949, 15815, -1202 }, - { -168, 1880, 15848, -1176 }, { -158, 1811, 15880, -1149 }, { -149, 1744, 15911, -1122 }, { -140, 1677, 15941, -1094 }, - { -131, 1611, 15970, -1066 }, { -122, 1545, 15998, -1037 }, { -114, 1480, 16025, -1007 }, { -106, 1415, 16052, -977 }, - { -98, 1351, 16077, -946 }, { -90, 1288, 16101, -915 }, { -83, 1224, 16125, -882 }, { -76, 1162, 16147, -849 }, - { -69, 1100, 16169, -816 }, { -63, 1040, 16189, -782 }, { -56, 978, 16209, -747 }, { -51, 919, 16227, -711 }, - { -45, 859, 16245, -675 }, { -40, 800, 16262, -638 }, { -35, 743, 16277, -601 }, { -30, 684, 16292, -562 }, - { -26, 628, 16305, -523 }, { -22, 572, 16318, -484 }, { -18, 516, 16329, -443 }, { -15, 462, 16339, -402 }, - { -12, 407, 16349, -360 }, { -9, 354, 16357, -318 }, { -7, 302, 16364, -275 }, { -5, 250, 16370, -231 }, - { -3, 198, 16375, -186 }, { -2, 148, 16379, -141 }, { -1, 98, 16382, -95 }, { 0, 49, 16383, -48 }, -}; - -#ifdef _M_IX86 -extern "C" const __declspec(align(16)) sint16 kVDCubicInterpTableFX14_075_MMX[256][8]={ - { 0, 16384, 0, 16384, 0, 0, 0, 0 }, { -48, 16384, -48, 16384, 48, 0, 48, 0 }, - { -95, 16383, -95, 16383, 97, -1, 97, -1 }, { -141, 16380, -141, 16380, 147, -2, 147, -2 }, - { -186, 16375, -186, 16375, 198, -3, 198, -3 }, { -231, 16371, -231, 16371, 249, -5, 249, -5 }, - { -275, 16365, -275, 16365, 301, -7, 301, -7 }, { -318, 16357, -318, 16357, 354, -9, 354, -9 }, - { -360, 16349, -360, 16349, 407, -12, 407, -12 }, { -402, 16340, -402, 16340, 461, -15, 461, -15 }, - { -443, 16329, -443, 16329, 516, -18, 516, -18 }, { -484, 16318, -484, 16318, 572, -22, 572, -22 }, - { -523, 16305, -523, 16305, 628, -26, 628, -26 }, { -562, 16291, -562, 16291, 685, -30, 685, -30 }, - { -601, 16278, -601, 16278, 742, -35, 742, -35 }, { -638, 16262, -638, 16262, 800, -40, 800, -40 }, - { -675, 16245, -675, 16245, 859, -45, 859, -45 }, { -711, 16228, -711, 16228, 918, -51, 918, -51 }, - { -747, 16209, -747, 16209, 978, -56, 978, -56 }, { -782, 16190, -782, 16190, 1039, -63, 1039, -63 }, - { -816, 16169, -816, 16169, 1100, -69, 1100, -69 }, { -849, 16147, -849, 16147, 1162, -76, 1162, -76 }, - { -882, 16124, -882, 16124, 1225, -83, 1225, -83 }, { -915, 16101, -915, 16101, 1288, -90, 1288, -90 }, - { -946, 16077, -946, 16077, 1351, -98, 1351, -98 }, { -977, 16052, -977, 16052, 1415, -106, 1415, -106 }, - { -1007, 16025, -1007, 16025, 1480, -114, 1480, -114 }, { -1037, 15998, -1037, 15998, 1545, -122, 1545, -122 }, - { -1066, 15970, -1066, 15970, 1611, -131, 1611, -131 }, { -1094, 15940, -1094, 15940, 1678, -140, 1678, -140 }, - { -1122, 15910, -1122, 15910, 1745, -149, 1745, -149 }, { -1149, 15879, -1149, 15879, 1812, -158, 1812, -158 }, - { -1176, 15848, -1176, 15848, 1880, -168, 1880, -168 }, { -1202, 15815, -1202, 15815, 1949, -178, 1949, -178 }, - { -1227, 15781, -1227, 15781, 2018, -188, 2018, -188 }, { -1252, 15747, -1252, 15747, 2087, -198, 2087, -198 }, - { -1276, 15712, -1276, 15712, 2157, -209, 2157, -209 }, { -1300, 15676, -1300, 15676, 2228, -220, 2228, -220 }, - { -1323, 15639, -1323, 15639, 2299, -231, 2299, -231 }, { -1345, 15601, -1345, 15601, 2370, -242, 2370, -242 }, - { -1367, 15562, -1367, 15562, 2442, -253, 2442, -253 }, { -1388, 15523, -1388, 15523, 2514, -265, 2514, -265 }, - { -1409, 15482, -1409, 15482, 2587, -276, 2587, -276 }, { -1429, 15441, -1429, 15441, 2660, -288, 2660, -288 }, - { -1448, 15399, -1448, 15399, 2734, -301, 2734, -301 }, { -1467, 15356, -1467, 15356, 2808, -313, 2808, -313 }, - { -1486, 15312, -1486, 15312, 2883, -325, 2883, -325 }, { -1504, 15268, -1504, 15268, 2958, -338, 2958, -338 }, - { -1521, 15223, -1521, 15223, 3033, -351, 3033, -351 }, { -1538, 15177, -1538, 15177, 3109, -364, 3109, -364 }, - { -1554, 15130, -1554, 15130, 3185, -377, 3185, -377 }, { -1570, 15084, -1570, 15084, 3261, -391, 3261, -391 }, - { -1585, 15035, -1585, 15035, 3338, -404, 3338, -404 }, { -1600, 14986, -1600, 14986, 3416, -418, 3416, -418 }, - { -1614, 14936, -1614, 14936, 3493, -431, 3493, -431 }, { -1627, 14885, -1627, 14885, 3571, -445, 3571, -445 }, - { -1641, 14834, -1641, 14834, 3650, -459, 3650, -459 }, { -1653, 14783, -1653, 14783, 3728, -474, 3728, -474 }, - { -1665, 14730, -1665, 14730, 3807, -488, 3807, -488 }, { -1677, 14676, -1677, 14676, 3887, -502, 3887, -502 }, - { -1688, 14623, -1688, 14623, 3966, -517, 3966, -517 }, { -1699, 14568, -1699, 14568, 4046, -531, 4046, -531 }, - { -1709, 14512, -1709, 14512, 4127, -546, 4127, -546 }, { -1719, 14457, -1719, 14457, 4207, -561, 4207, -561 }, - { -1728, 14400, -1728, 14400, 4288, -576, 4288, -576 }, { -1737, 14343, -1737, 14343, 4369, -591, 4369, -591 }, - { -1745, 14284, -1745, 14284, 4451, -606, 4451, -606 }, { -1753, 14226, -1753, 14226, 4532, -621, 4532, -621 }, - { -1760, 14167, -1760, 14167, 4614, -637, 4614, -637 }, { -1767, 14107, -1767, 14107, 4696, -652, 4696, -652 }, - { -1774, 14047, -1774, 14047, 4779, -668, 4779, -668 }, { -1780, 13986, -1780, 13986, 4861, -683, 4861, -683 }, - { -1785, 13924, -1785, 13924, 4944, -699, 4944, -699 }, { -1791, 13861, -1791, 13861, 5028, -714, 5028, -714 }, - { -1795, 13798, -1795, 13798, 5111, -730, 5111, -730 }, { -1800, 13736, -1800, 13736, 5194, -746, 5194, -746 }, - { -1804, 13671, -1804, 13671, 5278, -761, 5278, -761 }, { -1807, 13606, -1807, 13606, 5362, -777, 5362, -777 }, - { -1810, 13541, -1810, 13541, 5446, -793, 5446, -793 }, { -1813, 13475, -1813, 13475, 5531, -809, 5531, -809 }, - { -1815, 13409, -1815, 13409, 5615, -825, 5615, -825 }, { -1817, 13342, -1817, 13342, 5700, -841, 5700, -841 }, - { -1818, 13275, -1818, 13275, 5784, -857, 5784, -857 }, { -1819, 13207, -1819, 13207, 5869, -873, 5869, -873 }, - { -1820, 13139, -1820, 13139, 5954, -889, 5954, -889 }, { -1820, 13069, -1820, 13069, 6040, -905, 6040, -905 }, - { -1820, 13000, -1820, 13000, 6125, -921, 6125, -921 }, { -1820, 12930, -1820, 12930, 6211, -937, 6211, -937 }, - { -1819, 12860, -1819, 12860, 6296, -953, 6296, -953 }, { -1818, 12789, -1818, 12789, 6382, -969, 6382, -969 }, - { -1816, 12717, -1816, 12717, 6468, -985, 6468, -985 }, { -1815, 12647, -1815, 12647, 6553, -1001, 6553, -1001 }, - { -1812, 12574, -1812, 12574, 6639, -1017, 6639, -1017 }, { -1810, 12502, -1810, 12502, 6725, -1033, 6725, -1033 }, - { -1807, 12427, -1807, 12427, 6812, -1048, 6812, -1048 }, { -1804, 12354, -1804, 12354, 6898, -1064, 6898, -1064 }, - { -1800, 12280, -1800, 12280, 6984, -1080, 6984, -1080 }, { -1796, 12206, -1796, 12206, 7070, -1096, 7070, -1096 }, - { -1792, 12130, -1792, 12130, 7157, -1111, 7157, -1111 }, { -1787, 12055, -1787, 12055, 7243, -1127, 7243, -1127 }, - { -1782, 11980, -1782, 11980, 7329, -1143, 7329, -1143 }, { -1777, 11903, -1777, 11903, 7416, -1158, 7416, -1158 }, - { -1772, 11827, -1772, 11827, 7502, -1173, 7502, -1173 }, { -1766, 11751, -1766, 11751, 7588, -1189, 7588, -1189 }, - { -1760, 11673, -1760, 11673, 7675, -1204, 7675, -1204 }, { -1753, 11595, -1753, 11595, 7761, -1219, 7761, -1219 }, - { -1747, 11517, -1747, 11517, 7848, -1234, 7848, -1234 }, { -1740, 11439, -1740, 11439, 7934, -1249, 7934, -1249 }, - { -1733, 11361, -1733, 11361, 8020, -1264, 8020, -1264 }, { -1725, 11281, -1725, 11281, 8107, -1279, 8107, -1279 }, - { -1717, 11202, -1717, 11202, 8193, -1294, 8193, -1294 }, { -1709, 11123, -1709, 11123, 8279, -1309, 8279, -1309 }, - { -1701, 11043, -1701, 11043, 8365, -1323, 8365, -1323 }, { -1692, 10962, -1692, 10962, 8451, -1337, 8451, -1337 }, - { -1684, 10883, -1684, 10883, 8537, -1352, 8537, -1352 }, { -1675, 10802, -1675, 10802, 8623, -1366, 8623, -1366 }, - { -1665, 10720, -1665, 10720, 8709, -1380, 8709, -1380 }, { -1656, 10640, -1656, 10640, 8794, -1394, 8794, -1394 }, - { -1646, 10557, -1646, 10557, 8880, -1407, 8880, -1407 }, { -1636, 10476, -1636, 10476, 8965, -1421, 8965, -1421 }, - { -1626, 10393, -1626, 10393, 9051, -1434, 9051, -1434 }, { -1615, 10311, -1615, 10311, 9136, -1448, 9136, -1448 }, - { -1604, 10228, -1604, 10228, 9221, -1461, 9221, -1461 }, { -1594, 10146, -1594, 10146, 9306, -1474, 9306, -1474 }, - { -1582, 10062, -1582, 10062, 9391, -1487, 9391, -1487 }, { -1571, 9979, -1571, 9979, 9475, -1499, 9475, -1499 }, - { -1560, 9896, -1560, 9896, 9560, -1512, 9560, -1512 }, { -1548, 9812, -1548, 9812, 9644, -1524, 9644, -1524 }, - { -1536, 9728, -1536, 9728, 9728, -1536, 9728, -1536 }, { -1524, 9644, -1524, 9644, 9812, -1548, 9812, -1548 }, - { -1512, 9560, -1512, 9560, 9896, -1560, 9896, -1560 }, { -1499, 9475, -1499, 9475, 9979, -1571, 9979, -1571 }, - { -1487, 9391, -1487, 9391, 10062, -1582, 10062, -1582 }, { -1474, 9306, -1474, 9306, 10146, -1594, 10146, -1594 }, - { -1461, 9221, -1461, 9221, 10228, -1604, 10228, -1604 }, { -1448, 9136, -1448, 9136, 10311, -1615, 10311, -1615 }, - { -1434, 9051, -1434, 9051, 10393, -1626, 10393, -1626 }, { -1421, 8965, -1421, 8965, 10476, -1636, 10476, -1636 }, - { -1407, 8880, -1407, 8880, 10557, -1646, 10557, -1646 }, { -1394, 8795, -1394, 8795, 10639, -1656, 10639, -1656 }, - { -1380, 8709, -1380, 8709, 10720, -1665, 10720, -1665 }, { -1366, 8624, -1366, 8624, 10801, -1675, 10801, -1675 }, - { -1352, 8538, -1352, 8538, 10882, -1684, 10882, -1684 }, { -1337, 8450, -1337, 8450, 10963, -1692, 10963, -1692 }, - { -1323, 8365, -1323, 8365, 11043, -1701, 11043, -1701 }, { -1309, 8279, -1309, 8279, 11123, -1709, 11123, -1709 }, - { -1294, 8192, -1294, 8192, 11203, -1717, 11203, -1717 }, { -1279, 8106, -1279, 8106, 11282, -1725, 11282, -1725 }, - { -1264, 8020, -1264, 8020, 11361, -1733, 11361, -1733 }, { -1249, 7934, -1249, 7934, 11439, -1740, 11439, -1740 }, - { -1234, 7847, -1234, 7847, 11518, -1747, 11518, -1747 }, { -1219, 7760, -1219, 7760, 11596, -1753, 11596, -1753 }, - { -1204, 7675, -1204, 7675, 11673, -1760, 11673, -1760 }, { -1189, 7589, -1189, 7589, 11750, -1766, 11750, -1766 }, - { -1173, 7502, -1173, 7502, 11827, -1772, 11827, -1772 }, { -1158, 7415, -1158, 7415, 11904, -1777, 11904, -1777 }, - { -1143, 7329, -1143, 7329, 11980, -1782, 11980, -1782 }, { -1127, 7243, -1127, 7243, 12055, -1787, 12055, -1787 }, - { -1111, 7156, -1111, 7156, 12131, -1792, 12131, -1792 }, { -1096, 7070, -1096, 7070, 12206, -1796, 12206, -1796 }, - { -1080, 6984, -1080, 6984, 12280, -1800, 12280, -1800 }, { -1064, 6898, -1064, 6898, 12354, -1804, 12354, -1804 }, - { -1048, 6811, -1048, 6811, 12428, -1807, 12428, -1807 }, { -1033, 6726, -1033, 6726, 12501, -1810, 12501, -1810 }, - { -1017, 6639, -1017, 6639, 12574, -1812, 12574, -1812 }, { -1001, 6554, -1001, 6554, 12646, -1815, 12646, -1815 }, - { -985, 6467, -985, 6467, 12718, -1816, 12718, -1816 }, { -969, 6382, -969, 6382, 12789, -1818, 12789, -1818 }, - { -953, 6296, -953, 6296, 12860, -1819, 12860, -1819 }, { -937, 6211, -937, 6211, 12930, -1820, 12930, -1820 }, - { -921, 6125, -921, 6125, 13000, -1820, 13000, -1820 }, { -905, 6039, -905, 6039, 13070, -1820, 13070, -1820 }, - { -889, 5954, -889, 5954, 13139, -1820, 13139, -1820 }, { -873, 5869, -873, 5869, 13207, -1819, 13207, -1819 }, - { -857, 5784, -857, 5784, 13275, -1818, 13275, -1818 }, { -841, 5700, -841, 5700, 13342, -1817, 13342, -1817 }, - { -825, 5615, -825, 5615, 13409, -1815, 13409, -1815 }, { -809, 5531, -809, 5531, 13475, -1813, 13475, -1813 }, - { -793, 5446, -793, 5446, 13541, -1810, 13541, -1810 }, { -777, 5362, -777, 5362, 13606, -1807, 13606, -1807 }, - { -761, 5278, -761, 5278, 13671, -1804, 13671, -1804 }, { -746, 5195, -746, 5195, 13735, -1800, 13735, -1800 }, - { -730, 5111, -730, 5111, 13798, -1795, 13798, -1795 }, { -714, 5028, -714, 5028, 13861, -1791, 13861, -1791 }, - { -699, 4944, -699, 4944, 13924, -1785, 13924, -1785 }, { -683, 4862, -683, 4862, 13985, -1780, 13985, -1780 }, - { -668, 4780, -668, 4780, 14046, -1774, 14046, -1774 }, { -652, 4696, -652, 4696, 14107, -1767, 14107, -1767 }, - { -637, 4614, -637, 4614, 14167, -1760, 14167, -1760 }, { -621, 4532, -621, 4532, 14226, -1753, 14226, -1753 }, - { -606, 4450, -606, 4450, 14285, -1745, 14285, -1745 }, { -591, 4369, -591, 4369, 14343, -1737, 14343, -1737 }, - { -576, 4288, -576, 4288, 14400, -1728, 14400, -1728 }, { -561, 4207, -561, 4207, 14457, -1719, 14457, -1719 }, - { -546, 4126, -546, 4126, 14513, -1709, 14513, -1709 }, { -531, 4046, -531, 4046, 14568, -1699, 14568, -1699 }, - { -517, 3966, -517, 3966, 14623, -1688, 14623, -1688 }, { -502, 3886, -502, 3886, 14677, -1677, 14677, -1677 }, - { -488, 3807, -488, 3807, 14730, -1665, 14730, -1665 }, { -474, 3728, -474, 3728, 14783, -1653, 14783, -1653 }, - { -459, 3650, -459, 3650, 14834, -1641, 14834, -1641 }, { -445, 3570, -445, 3570, 14886, -1627, 14886, -1627 }, - { -431, 3493, -431, 3493, 14936, -1614, 14936, -1614 }, { -418, 3416, -418, 3416, 14986, -1600, 14986, -1600 }, - { -404, 3338, -404, 3338, 15035, -1585, 15035, -1585 }, { -391, 3262, -391, 3262, 15083, -1570, 15083, -1570 }, - { -377, 3185, -377, 3185, 15130, -1554, 15130, -1554 }, { -364, 3109, -364, 3109, 15177, -1538, 15177, -1538 }, - { -351, 3033, -351, 3033, 15223, -1521, 15223, -1521 }, { -338, 2958, -338, 2958, 15268, -1504, 15268, -1504 }, - { -325, 2882, -325, 2882, 15313, -1486, 15313, -1486 }, { -313, 2808, -313, 2808, 15356, -1467, 15356, -1467 }, - { -301, 2734, -301, 2734, 15399, -1448, 15399, -1448 }, { -288, 2660, -288, 2660, 15441, -1429, 15441, -1429 }, - { -276, 2587, -276, 2587, 15482, -1409, 15482, -1409 }, { -265, 2514, -265, 2514, 15523, -1388, 15523, -1388 }, - { -253, 2442, -253, 2442, 15562, -1367, 15562, -1367 }, { -242, 2370, -242, 2370, 15601, -1345, 15601, -1345 }, - { -231, 2299, -231, 2299, 15639, -1323, 15639, -1323 }, { -220, 2228, -220, 2228, 15676, -1300, 15676, -1300 }, - { -209, 2157, -209, 2157, 15712, -1276, 15712, -1276 }, { -198, 2087, -198, 2087, 15747, -1252, 15747, -1252 }, - { -188, 2017, -188, 2017, 15782, -1227, 15782, -1227 }, { -178, 1949, -178, 1949, 15815, -1202, 15815, -1202 }, - { -168, 1880, -168, 1880, 15848, -1176, 15848, -1176 }, { -158, 1811, -158, 1811, 15880, -1149, 15880, -1149 }, - { -149, 1744, -149, 1744, 15911, -1122, 15911, -1122 }, { -140, 1677, -140, 1677, 15941, -1094, 15941, -1094 }, - { -131, 1611, -131, 1611, 15970, -1066, 15970, -1066 }, { -122, 1545, -122, 1545, 15998, -1037, 15998, -1037 }, - { -114, 1480, -114, 1480, 16025, -1007, 16025, -1007 }, { -106, 1415, -106, 1415, 16052, -977, 16052, -977 }, - { -98, 1351, -98, 1351, 16077, -946, 16077, -946 }, { -90, 1288, -90, 1288, 16101, -915, 16101, -915 }, - { -83, 1224, -83, 1224, 16125, -882, 16125, -882 }, { -76, 1162, -76, 1162, 16147, -849, 16147, -849 }, - { -69, 1100, -69, 1100, 16169, -816, 16169, -816 }, { -63, 1040, -63, 1040, 16189, -782, 16189, -782 }, - { -56, 978, -56, 978, 16209, -747, 16209, -747 }, { -51, 919, -51, 919, 16227, -711, 16227, -711 }, - { -45, 859, -45, 859, 16245, -675, 16245, -675 }, { -40, 800, -40, 800, 16262, -638, 16262, -638 }, - { -35, 743, -35, 743, 16277, -601, 16277, -601 }, { -30, 684, -30, 684, 16292, -562, 16292, -562 }, - { -26, 628, -26, 628, 16305, -523, 16305, -523 }, { -22, 572, -22, 572, 16318, -484, 16318, -484 }, - { -18, 516, -18, 516, 16329, -443, 16329, -443 }, { -15, 462, -15, 462, 16339, -402, 16339, -402 }, - { -12, 407, -12, 407, 16349, -360, 16349, -360 }, { -9, 354, -9, 354, 16357, -318, 16357, -318 }, - { -7, 302, -7, 302, 16364, -275, 16364, -275 }, { -5, 250, -5, 250, 16370, -231, 16370, -231 }, - { -3, 198, -3, 198, 16375, -186, 16375, -186 }, { -2, 148, -2, 148, 16379, -141, 16379, -141 }, - { -1, 98, -1, 98, 16382, -95, 16382, -95 }, { 0, 49, 0, 49, 16383, -48, 16383, -48 }, -}; - -#endif +// Automatically generated by Asuka 'maketables.'" DO NOT EDIT! + +#include +#include + +extern "C" const sint32 kVDCubicInterpTableFX14_075[256][4]={ + { 0, 16384, 0, 0 }, { -48, 16384, 48, 0 }, { -95, 16383, 97, -1 }, { -141, 16380, 147, -2 }, + { -186, 16375, 198, -3 }, { -231, 16371, 249, -5 }, { -275, 16365, 301, -7 }, { -318, 16357, 354, -9 }, + { -360, 16349, 407, -12 }, { -402, 16340, 461, -15 }, { -443, 16329, 516, -18 }, { -484, 16318, 572, -22 }, + { -523, 16305, 628, -26 }, { -562, 16291, 685, -30 }, { -601, 16278, 742, -35 }, { -638, 16262, 800, -40 }, + { -675, 16245, 859, -45 }, { -711, 16228, 918, -51 }, { -747, 16209, 978, -56 }, { -782, 16190, 1039, -63 }, + { -816, 16169, 1100, -69 }, { -849, 16147, 1162, -76 }, { -882, 16124, 1225, -83 }, { -915, 16101, 1288, -90 }, + { -946, 16077, 1351, -98 }, { -977, 16052, 1415, -106 }, { -1007, 16025, 1480, -114 }, { -1037, 15998, 1545, -122 }, + { -1066, 15970, 1611, -131 }, { -1094, 15940, 1678, -140 }, { -1122, 15910, 1745, -149 }, { -1149, 15879, 1812, -158 }, + { -1176, 15848, 1880, -168 }, { -1202, 15815, 1949, -178 }, { -1227, 15781, 2018, -188 }, { -1252, 15747, 2087, -198 }, + { -1276, 15712, 2157, -209 }, { -1300, 15676, 2228, -220 }, { -1323, 15639, 2299, -231 }, { -1345, 15601, 2370, -242 }, + { -1367, 15562, 2442, -253 }, { -1388, 15523, 2514, -265 }, { -1409, 15482, 2587, -276 }, { -1429, 15441, 2660, -288 }, + { -1448, 15399, 2734, -301 }, { -1467, 15356, 2808, -313 }, { -1486, 15312, 2883, -325 }, { -1504, 15268, 2958, -338 }, + { -1521, 15223, 3033, -351 }, { -1538, 15177, 3109, -364 }, { -1554, 15130, 3185, -377 }, { -1570, 15084, 3261, -391 }, + { -1585, 15035, 3338, -404 }, { -1600, 14986, 3416, -418 }, { -1614, 14936, 3493, -431 }, { -1627, 14885, 3571, -445 }, + { -1641, 14834, 3650, -459 }, { -1653, 14783, 3728, -474 }, { -1665, 14730, 3807, -488 }, { -1677, 14676, 3887, -502 }, + { -1688, 14623, 3966, -517 }, { -1699, 14568, 4046, -531 }, { -1709, 14512, 4127, -546 }, { -1719, 14457, 4207, -561 }, + { -1728, 14400, 4288, -576 }, { -1737, 14343, 4369, -591 }, { -1745, 14284, 4451, -606 }, { -1753, 14226, 4532, -621 }, + { -1760, 14167, 4614, -637 }, { -1767, 14107, 4696, -652 }, { -1774, 14047, 4779, -668 }, { -1780, 13986, 4861, -683 }, + { -1785, 13924, 4944, -699 }, { -1791, 13861, 5028, -714 }, { -1795, 13798, 5111, -730 }, { -1800, 13736, 5194, -746 }, + { -1804, 13671, 5278, -761 }, { -1807, 13606, 5362, -777 }, { -1810, 13541, 5446, -793 }, { -1813, 13475, 5531, -809 }, + { -1815, 13409, 5615, -825 }, { -1817, 13342, 5700, -841 }, { -1818, 13275, 5784, -857 }, { -1819, 13207, 5869, -873 }, + { -1820, 13139, 5954, -889 }, { -1820, 13069, 6040, -905 }, { -1820, 13000, 6125, -921 }, { -1820, 12930, 6211, -937 }, + { -1819, 12860, 6296, -953 }, { -1818, 12789, 6382, -969 }, { -1816, 12717, 6468, -985 }, { -1815, 12647, 6553, -1001 }, + { -1812, 12574, 6639, -1017 }, { -1810, 12502, 6725, -1033 }, { -1807, 12427, 6812, -1048 }, { -1804, 12354, 6898, -1064 }, + { -1800, 12280, 6984, -1080 }, { -1796, 12206, 7070, -1096 }, { -1792, 12130, 7157, -1111 }, { -1787, 12055, 7243, -1127 }, + { -1782, 11980, 7329, -1143 }, { -1777, 11903, 7416, -1158 }, { -1772, 11827, 7502, -1173 }, { -1766, 11751, 7588, -1189 }, + { -1760, 11673, 7675, -1204 }, { -1753, 11595, 7761, -1219 }, { -1747, 11517, 7848, -1234 }, { -1740, 11439, 7934, -1249 }, + { -1733, 11361, 8020, -1264 }, { -1725, 11281, 8107, -1279 }, { -1717, 11202, 8193, -1294 }, { -1709, 11123, 8279, -1309 }, + { -1701, 11043, 8365, -1323 }, { -1692, 10962, 8451, -1337 }, { -1684, 10883, 8537, -1352 }, { -1675, 10802, 8623, -1366 }, + { -1665, 10720, 8709, -1380 }, { -1656, 10640, 8794, -1394 }, { -1646, 10557, 8880, -1407 }, { -1636, 10476, 8965, -1421 }, + { -1626, 10393, 9051, -1434 }, { -1615, 10311, 9136, -1448 }, { -1604, 10228, 9221, -1461 }, { -1594, 10146, 9306, -1474 }, + { -1582, 10062, 9391, -1487 }, { -1571, 9979, 9475, -1499 }, { -1560, 9896, 9560, -1512 }, { -1548, 9812, 9644, -1524 }, + { -1536, 9728, 9728, -1536 }, { -1524, 9644, 9812, -1548 }, { -1512, 9560, 9896, -1560 }, { -1499, 9475, 9979, -1571 }, + { -1487, 9391, 10062, -1582 }, { -1474, 9306, 10146, -1594 }, { -1461, 9221, 10228, -1604 }, { -1448, 9136, 10311, -1615 }, + { -1434, 9051, 10393, -1626 }, { -1421, 8965, 10476, -1636 }, { -1407, 8880, 10557, -1646 }, { -1394, 8795, 10639, -1656 }, + { -1380, 8709, 10720, -1665 }, { -1366, 8624, 10801, -1675 }, { -1352, 8538, 10882, -1684 }, { -1337, 8450, 10963, -1692 }, + { -1323, 8365, 11043, -1701 }, { -1309, 8279, 11123, -1709 }, { -1294, 8192, 11203, -1717 }, { -1279, 8106, 11282, -1725 }, + { -1264, 8020, 11361, -1733 }, { -1249, 7934, 11439, -1740 }, { -1234, 7847, 11518, -1747 }, { -1219, 7760, 11596, -1753 }, + { -1204, 7675, 11673, -1760 }, { -1189, 7589, 11750, -1766 }, { -1173, 7502, 11827, -1772 }, { -1158, 7415, 11904, -1777 }, + { -1143, 7329, 11980, -1782 }, { -1127, 7243, 12055, -1787 }, { -1111, 7156, 12131, -1792 }, { -1096, 7070, 12206, -1796 }, + { -1080, 6984, 12280, -1800 }, { -1064, 6898, 12354, -1804 }, { -1048, 6811, 12428, -1807 }, { -1033, 6726, 12501, -1810 }, + { -1017, 6639, 12574, -1812 }, { -1001, 6554, 12646, -1815 }, { -985, 6467, 12718, -1816 }, { -969, 6382, 12789, -1818 }, + { -953, 6296, 12860, -1819 }, { -937, 6211, 12930, -1820 }, { -921, 6125, 13000, -1820 }, { -905, 6039, 13070, -1820 }, + { -889, 5954, 13139, -1820 }, { -873, 5869, 13207, -1819 }, { -857, 5784, 13275, -1818 }, { -841, 5700, 13342, -1817 }, + { -825, 5615, 13409, -1815 }, { -809, 5531, 13475, -1813 }, { -793, 5446, 13541, -1810 }, { -777, 5362, 13606, -1807 }, + { -761, 5278, 13671, -1804 }, { -746, 5195, 13735, -1800 }, { -730, 5111, 13798, -1795 }, { -714, 5028, 13861, -1791 }, + { -699, 4944, 13924, -1785 }, { -683, 4862, 13985, -1780 }, { -668, 4780, 14046, -1774 }, { -652, 4696, 14107, -1767 }, + { -637, 4614, 14167, -1760 }, { -621, 4532, 14226, -1753 }, { -606, 4450, 14285, -1745 }, { -591, 4369, 14343, -1737 }, + { -576, 4288, 14400, -1728 }, { -561, 4207, 14457, -1719 }, { -546, 4126, 14513, -1709 }, { -531, 4046, 14568, -1699 }, + { -517, 3966, 14623, -1688 }, { -502, 3886, 14677, -1677 }, { -488, 3807, 14730, -1665 }, { -474, 3728, 14783, -1653 }, + { -459, 3650, 14834, -1641 }, { -445, 3570, 14886, -1627 }, { -431, 3493, 14936, -1614 }, { -418, 3416, 14986, -1600 }, + { -404, 3338, 15035, -1585 }, { -391, 3262, 15083, -1570 }, { -377, 3185, 15130, -1554 }, { -364, 3109, 15177, -1538 }, + { -351, 3033, 15223, -1521 }, { -338, 2958, 15268, -1504 }, { -325, 2882, 15313, -1486 }, { -313, 2808, 15356, -1467 }, + { -301, 2734, 15399, -1448 }, { -288, 2660, 15441, -1429 }, { -276, 2587, 15482, -1409 }, { -265, 2514, 15523, -1388 }, + { -253, 2442, 15562, -1367 }, { -242, 2370, 15601, -1345 }, { -231, 2299, 15639, -1323 }, { -220, 2228, 15676, -1300 }, + { -209, 2157, 15712, -1276 }, { -198, 2087, 15747, -1252 }, { -188, 2017, 15782, -1227 }, { -178, 1949, 15815, -1202 }, + { -168, 1880, 15848, -1176 }, { -158, 1811, 15880, -1149 }, { -149, 1744, 15911, -1122 }, { -140, 1677, 15941, -1094 }, + { -131, 1611, 15970, -1066 }, { -122, 1545, 15998, -1037 }, { -114, 1480, 16025, -1007 }, { -106, 1415, 16052, -977 }, + { -98, 1351, 16077, -946 }, { -90, 1288, 16101, -915 }, { -83, 1224, 16125, -882 }, { -76, 1162, 16147, -849 }, + { -69, 1100, 16169, -816 }, { -63, 1040, 16189, -782 }, { -56, 978, 16209, -747 }, { -51, 919, 16227, -711 }, + { -45, 859, 16245, -675 }, { -40, 800, 16262, -638 }, { -35, 743, 16277, -601 }, { -30, 684, 16292, -562 }, + { -26, 628, 16305, -523 }, { -22, 572, 16318, -484 }, { -18, 516, 16329, -443 }, { -15, 462, 16339, -402 }, + { -12, 407, 16349, -360 }, { -9, 354, 16357, -318 }, { -7, 302, 16364, -275 }, { -5, 250, 16370, -231 }, + { -3, 198, 16375, -186 }, { -2, 148, 16379, -141 }, { -1, 98, 16382, -95 }, { 0, 49, 16383, -48 }, +}; + +#ifdef _M_IX86 +extern "C" const __declspec(align(16)) sint16 kVDCubicInterpTableFX14_075_MMX[256][8]={ + { 0, 16384, 0, 16384, 0, 0, 0, 0 }, { -48, 16384, -48, 16384, 48, 0, 48, 0 }, + { -95, 16383, -95, 16383, 97, -1, 97, -1 }, { -141, 16380, -141, 16380, 147, -2, 147, -2 }, + { -186, 16375, -186, 16375, 198, -3, 198, -3 }, { -231, 16371, -231, 16371, 249, -5, 249, -5 }, + { -275, 16365, -275, 16365, 301, -7, 301, -7 }, { -318, 16357, -318, 16357, 354, -9, 354, -9 }, + { -360, 16349, -360, 16349, 407, -12, 407, -12 }, { -402, 16340, -402, 16340, 461, -15, 461, -15 }, + { -443, 16329, -443, 16329, 516, -18, 516, -18 }, { -484, 16318, -484, 16318, 572, -22, 572, -22 }, + { -523, 16305, -523, 16305, 628, -26, 628, -26 }, { -562, 16291, -562, 16291, 685, -30, 685, -30 }, + { -601, 16278, -601, 16278, 742, -35, 742, -35 }, { -638, 16262, -638, 16262, 800, -40, 800, -40 }, + { -675, 16245, -675, 16245, 859, -45, 859, -45 }, { -711, 16228, -711, 16228, 918, -51, 918, -51 }, + { -747, 16209, -747, 16209, 978, -56, 978, -56 }, { -782, 16190, -782, 16190, 1039, -63, 1039, -63 }, + { -816, 16169, -816, 16169, 1100, -69, 1100, -69 }, { -849, 16147, -849, 16147, 1162, -76, 1162, -76 }, + { -882, 16124, -882, 16124, 1225, -83, 1225, -83 }, { -915, 16101, -915, 16101, 1288, -90, 1288, -90 }, + { -946, 16077, -946, 16077, 1351, -98, 1351, -98 }, { -977, 16052, -977, 16052, 1415, -106, 1415, -106 }, + { -1007, 16025, -1007, 16025, 1480, -114, 1480, -114 }, { -1037, 15998, -1037, 15998, 1545, -122, 1545, -122 }, + { -1066, 15970, -1066, 15970, 1611, -131, 1611, -131 }, { -1094, 15940, -1094, 15940, 1678, -140, 1678, -140 }, + { -1122, 15910, -1122, 15910, 1745, -149, 1745, -149 }, { -1149, 15879, -1149, 15879, 1812, -158, 1812, -158 }, + { -1176, 15848, -1176, 15848, 1880, -168, 1880, -168 }, { -1202, 15815, -1202, 15815, 1949, -178, 1949, -178 }, + { -1227, 15781, -1227, 15781, 2018, -188, 2018, -188 }, { -1252, 15747, -1252, 15747, 2087, -198, 2087, -198 }, + { -1276, 15712, -1276, 15712, 2157, -209, 2157, -209 }, { -1300, 15676, -1300, 15676, 2228, -220, 2228, -220 }, + { -1323, 15639, -1323, 15639, 2299, -231, 2299, -231 }, { -1345, 15601, -1345, 15601, 2370, -242, 2370, -242 }, + { -1367, 15562, -1367, 15562, 2442, -253, 2442, -253 }, { -1388, 15523, -1388, 15523, 2514, -265, 2514, -265 }, + { -1409, 15482, -1409, 15482, 2587, -276, 2587, -276 }, { -1429, 15441, -1429, 15441, 2660, -288, 2660, -288 }, + { -1448, 15399, -1448, 15399, 2734, -301, 2734, -301 }, { -1467, 15356, -1467, 15356, 2808, -313, 2808, -313 }, + { -1486, 15312, -1486, 15312, 2883, -325, 2883, -325 }, { -1504, 15268, -1504, 15268, 2958, -338, 2958, -338 }, + { -1521, 15223, -1521, 15223, 3033, -351, 3033, -351 }, { -1538, 15177, -1538, 15177, 3109, -364, 3109, -364 }, + { -1554, 15130, -1554, 15130, 3185, -377, 3185, -377 }, { -1570, 15084, -1570, 15084, 3261, -391, 3261, -391 }, + { -1585, 15035, -1585, 15035, 3338, -404, 3338, -404 }, { -1600, 14986, -1600, 14986, 3416, -418, 3416, -418 }, + { -1614, 14936, -1614, 14936, 3493, -431, 3493, -431 }, { -1627, 14885, -1627, 14885, 3571, -445, 3571, -445 }, + { -1641, 14834, -1641, 14834, 3650, -459, 3650, -459 }, { -1653, 14783, -1653, 14783, 3728, -474, 3728, -474 }, + { -1665, 14730, -1665, 14730, 3807, -488, 3807, -488 }, { -1677, 14676, -1677, 14676, 3887, -502, 3887, -502 }, + { -1688, 14623, -1688, 14623, 3966, -517, 3966, -517 }, { -1699, 14568, -1699, 14568, 4046, -531, 4046, -531 }, + { -1709, 14512, -1709, 14512, 4127, -546, 4127, -546 }, { -1719, 14457, -1719, 14457, 4207, -561, 4207, -561 }, + { -1728, 14400, -1728, 14400, 4288, -576, 4288, -576 }, { -1737, 14343, -1737, 14343, 4369, -591, 4369, -591 }, + { -1745, 14284, -1745, 14284, 4451, -606, 4451, -606 }, { -1753, 14226, -1753, 14226, 4532, -621, 4532, -621 }, + { -1760, 14167, -1760, 14167, 4614, -637, 4614, -637 }, { -1767, 14107, -1767, 14107, 4696, -652, 4696, -652 }, + { -1774, 14047, -1774, 14047, 4779, -668, 4779, -668 }, { -1780, 13986, -1780, 13986, 4861, -683, 4861, -683 }, + { -1785, 13924, -1785, 13924, 4944, -699, 4944, -699 }, { -1791, 13861, -1791, 13861, 5028, -714, 5028, -714 }, + { -1795, 13798, -1795, 13798, 5111, -730, 5111, -730 }, { -1800, 13736, -1800, 13736, 5194, -746, 5194, -746 }, + { -1804, 13671, -1804, 13671, 5278, -761, 5278, -761 }, { -1807, 13606, -1807, 13606, 5362, -777, 5362, -777 }, + { -1810, 13541, -1810, 13541, 5446, -793, 5446, -793 }, { -1813, 13475, -1813, 13475, 5531, -809, 5531, -809 }, + { -1815, 13409, -1815, 13409, 5615, -825, 5615, -825 }, { -1817, 13342, -1817, 13342, 5700, -841, 5700, -841 }, + { -1818, 13275, -1818, 13275, 5784, -857, 5784, -857 }, { -1819, 13207, -1819, 13207, 5869, -873, 5869, -873 }, + { -1820, 13139, -1820, 13139, 5954, -889, 5954, -889 }, { -1820, 13069, -1820, 13069, 6040, -905, 6040, -905 }, + { -1820, 13000, -1820, 13000, 6125, -921, 6125, -921 }, { -1820, 12930, -1820, 12930, 6211, -937, 6211, -937 }, + { -1819, 12860, -1819, 12860, 6296, -953, 6296, -953 }, { -1818, 12789, -1818, 12789, 6382, -969, 6382, -969 }, + { -1816, 12717, -1816, 12717, 6468, -985, 6468, -985 }, { -1815, 12647, -1815, 12647, 6553, -1001, 6553, -1001 }, + { -1812, 12574, -1812, 12574, 6639, -1017, 6639, -1017 }, { -1810, 12502, -1810, 12502, 6725, -1033, 6725, -1033 }, + { -1807, 12427, -1807, 12427, 6812, -1048, 6812, -1048 }, { -1804, 12354, -1804, 12354, 6898, -1064, 6898, -1064 }, + { -1800, 12280, -1800, 12280, 6984, -1080, 6984, -1080 }, { -1796, 12206, -1796, 12206, 7070, -1096, 7070, -1096 }, + { -1792, 12130, -1792, 12130, 7157, -1111, 7157, -1111 }, { -1787, 12055, -1787, 12055, 7243, -1127, 7243, -1127 }, + { -1782, 11980, -1782, 11980, 7329, -1143, 7329, -1143 }, { -1777, 11903, -1777, 11903, 7416, -1158, 7416, -1158 }, + { -1772, 11827, -1772, 11827, 7502, -1173, 7502, -1173 }, { -1766, 11751, -1766, 11751, 7588, -1189, 7588, -1189 }, + { -1760, 11673, -1760, 11673, 7675, -1204, 7675, -1204 }, { -1753, 11595, -1753, 11595, 7761, -1219, 7761, -1219 }, + { -1747, 11517, -1747, 11517, 7848, -1234, 7848, -1234 }, { -1740, 11439, -1740, 11439, 7934, -1249, 7934, -1249 }, + { -1733, 11361, -1733, 11361, 8020, -1264, 8020, -1264 }, { -1725, 11281, -1725, 11281, 8107, -1279, 8107, -1279 }, + { -1717, 11202, -1717, 11202, 8193, -1294, 8193, -1294 }, { -1709, 11123, -1709, 11123, 8279, -1309, 8279, -1309 }, + { -1701, 11043, -1701, 11043, 8365, -1323, 8365, -1323 }, { -1692, 10962, -1692, 10962, 8451, -1337, 8451, -1337 }, + { -1684, 10883, -1684, 10883, 8537, -1352, 8537, -1352 }, { -1675, 10802, -1675, 10802, 8623, -1366, 8623, -1366 }, + { -1665, 10720, -1665, 10720, 8709, -1380, 8709, -1380 }, { -1656, 10640, -1656, 10640, 8794, -1394, 8794, -1394 }, + { -1646, 10557, -1646, 10557, 8880, -1407, 8880, -1407 }, { -1636, 10476, -1636, 10476, 8965, -1421, 8965, -1421 }, + { -1626, 10393, -1626, 10393, 9051, -1434, 9051, -1434 }, { -1615, 10311, -1615, 10311, 9136, -1448, 9136, -1448 }, + { -1604, 10228, -1604, 10228, 9221, -1461, 9221, -1461 }, { -1594, 10146, -1594, 10146, 9306, -1474, 9306, -1474 }, + { -1582, 10062, -1582, 10062, 9391, -1487, 9391, -1487 }, { -1571, 9979, -1571, 9979, 9475, -1499, 9475, -1499 }, + { -1560, 9896, -1560, 9896, 9560, -1512, 9560, -1512 }, { -1548, 9812, -1548, 9812, 9644, -1524, 9644, -1524 }, + { -1536, 9728, -1536, 9728, 9728, -1536, 9728, -1536 }, { -1524, 9644, -1524, 9644, 9812, -1548, 9812, -1548 }, + { -1512, 9560, -1512, 9560, 9896, -1560, 9896, -1560 }, { -1499, 9475, -1499, 9475, 9979, -1571, 9979, -1571 }, + { -1487, 9391, -1487, 9391, 10062, -1582, 10062, -1582 }, { -1474, 9306, -1474, 9306, 10146, -1594, 10146, -1594 }, + { -1461, 9221, -1461, 9221, 10228, -1604, 10228, -1604 }, { -1448, 9136, -1448, 9136, 10311, -1615, 10311, -1615 }, + { -1434, 9051, -1434, 9051, 10393, -1626, 10393, -1626 }, { -1421, 8965, -1421, 8965, 10476, -1636, 10476, -1636 }, + { -1407, 8880, -1407, 8880, 10557, -1646, 10557, -1646 }, { -1394, 8795, -1394, 8795, 10639, -1656, 10639, -1656 }, + { -1380, 8709, -1380, 8709, 10720, -1665, 10720, -1665 }, { -1366, 8624, -1366, 8624, 10801, -1675, 10801, -1675 }, + { -1352, 8538, -1352, 8538, 10882, -1684, 10882, -1684 }, { -1337, 8450, -1337, 8450, 10963, -1692, 10963, -1692 }, + { -1323, 8365, -1323, 8365, 11043, -1701, 11043, -1701 }, { -1309, 8279, -1309, 8279, 11123, -1709, 11123, -1709 }, + { -1294, 8192, -1294, 8192, 11203, -1717, 11203, -1717 }, { -1279, 8106, -1279, 8106, 11282, -1725, 11282, -1725 }, + { -1264, 8020, -1264, 8020, 11361, -1733, 11361, -1733 }, { -1249, 7934, -1249, 7934, 11439, -1740, 11439, -1740 }, + { -1234, 7847, -1234, 7847, 11518, -1747, 11518, -1747 }, { -1219, 7760, -1219, 7760, 11596, -1753, 11596, -1753 }, + { -1204, 7675, -1204, 7675, 11673, -1760, 11673, -1760 }, { -1189, 7589, -1189, 7589, 11750, -1766, 11750, -1766 }, + { -1173, 7502, -1173, 7502, 11827, -1772, 11827, -1772 }, { -1158, 7415, -1158, 7415, 11904, -1777, 11904, -1777 }, + { -1143, 7329, -1143, 7329, 11980, -1782, 11980, -1782 }, { -1127, 7243, -1127, 7243, 12055, -1787, 12055, -1787 }, + { -1111, 7156, -1111, 7156, 12131, -1792, 12131, -1792 }, { -1096, 7070, -1096, 7070, 12206, -1796, 12206, -1796 }, + { -1080, 6984, -1080, 6984, 12280, -1800, 12280, -1800 }, { -1064, 6898, -1064, 6898, 12354, -1804, 12354, -1804 }, + { -1048, 6811, -1048, 6811, 12428, -1807, 12428, -1807 }, { -1033, 6726, -1033, 6726, 12501, -1810, 12501, -1810 }, + { -1017, 6639, -1017, 6639, 12574, -1812, 12574, -1812 }, { -1001, 6554, -1001, 6554, 12646, -1815, 12646, -1815 }, + { -985, 6467, -985, 6467, 12718, -1816, 12718, -1816 }, { -969, 6382, -969, 6382, 12789, -1818, 12789, -1818 }, + { -953, 6296, -953, 6296, 12860, -1819, 12860, -1819 }, { -937, 6211, -937, 6211, 12930, -1820, 12930, -1820 }, + { -921, 6125, -921, 6125, 13000, -1820, 13000, -1820 }, { -905, 6039, -905, 6039, 13070, -1820, 13070, -1820 }, + { -889, 5954, -889, 5954, 13139, -1820, 13139, -1820 }, { -873, 5869, -873, 5869, 13207, -1819, 13207, -1819 }, + { -857, 5784, -857, 5784, 13275, -1818, 13275, -1818 }, { -841, 5700, -841, 5700, 13342, -1817, 13342, -1817 }, + { -825, 5615, -825, 5615, 13409, -1815, 13409, -1815 }, { -809, 5531, -809, 5531, 13475, -1813, 13475, -1813 }, + { -793, 5446, -793, 5446, 13541, -1810, 13541, -1810 }, { -777, 5362, -777, 5362, 13606, -1807, 13606, -1807 }, + { -761, 5278, -761, 5278, 13671, -1804, 13671, -1804 }, { -746, 5195, -746, 5195, 13735, -1800, 13735, -1800 }, + { -730, 5111, -730, 5111, 13798, -1795, 13798, -1795 }, { -714, 5028, -714, 5028, 13861, -1791, 13861, -1791 }, + { -699, 4944, -699, 4944, 13924, -1785, 13924, -1785 }, { -683, 4862, -683, 4862, 13985, -1780, 13985, -1780 }, + { -668, 4780, -668, 4780, 14046, -1774, 14046, -1774 }, { -652, 4696, -652, 4696, 14107, -1767, 14107, -1767 }, + { -637, 4614, -637, 4614, 14167, -1760, 14167, -1760 }, { -621, 4532, -621, 4532, 14226, -1753, 14226, -1753 }, + { -606, 4450, -606, 4450, 14285, -1745, 14285, -1745 }, { -591, 4369, -591, 4369, 14343, -1737, 14343, -1737 }, + { -576, 4288, -576, 4288, 14400, -1728, 14400, -1728 }, { -561, 4207, -561, 4207, 14457, -1719, 14457, -1719 }, + { -546, 4126, -546, 4126, 14513, -1709, 14513, -1709 }, { -531, 4046, -531, 4046, 14568, -1699, 14568, -1699 }, + { -517, 3966, -517, 3966, 14623, -1688, 14623, -1688 }, { -502, 3886, -502, 3886, 14677, -1677, 14677, -1677 }, + { -488, 3807, -488, 3807, 14730, -1665, 14730, -1665 }, { -474, 3728, -474, 3728, 14783, -1653, 14783, -1653 }, + { -459, 3650, -459, 3650, 14834, -1641, 14834, -1641 }, { -445, 3570, -445, 3570, 14886, -1627, 14886, -1627 }, + { -431, 3493, -431, 3493, 14936, -1614, 14936, -1614 }, { -418, 3416, -418, 3416, 14986, -1600, 14986, -1600 }, + { -404, 3338, -404, 3338, 15035, -1585, 15035, -1585 }, { -391, 3262, -391, 3262, 15083, -1570, 15083, -1570 }, + { -377, 3185, -377, 3185, 15130, -1554, 15130, -1554 }, { -364, 3109, -364, 3109, 15177, -1538, 15177, -1538 }, + { -351, 3033, -351, 3033, 15223, -1521, 15223, -1521 }, { -338, 2958, -338, 2958, 15268, -1504, 15268, -1504 }, + { -325, 2882, -325, 2882, 15313, -1486, 15313, -1486 }, { -313, 2808, -313, 2808, 15356, -1467, 15356, -1467 }, + { -301, 2734, -301, 2734, 15399, -1448, 15399, -1448 }, { -288, 2660, -288, 2660, 15441, -1429, 15441, -1429 }, + { -276, 2587, -276, 2587, 15482, -1409, 15482, -1409 }, { -265, 2514, -265, 2514, 15523, -1388, 15523, -1388 }, + { -253, 2442, -253, 2442, 15562, -1367, 15562, -1367 }, { -242, 2370, -242, 2370, 15601, -1345, 15601, -1345 }, + { -231, 2299, -231, 2299, 15639, -1323, 15639, -1323 }, { -220, 2228, -220, 2228, 15676, -1300, 15676, -1300 }, + { -209, 2157, -209, 2157, 15712, -1276, 15712, -1276 }, { -198, 2087, -198, 2087, 15747, -1252, 15747, -1252 }, + { -188, 2017, -188, 2017, 15782, -1227, 15782, -1227 }, { -178, 1949, -178, 1949, 15815, -1202, 15815, -1202 }, + { -168, 1880, -168, 1880, 15848, -1176, 15848, -1176 }, { -158, 1811, -158, 1811, 15880, -1149, 15880, -1149 }, + { -149, 1744, -149, 1744, 15911, -1122, 15911, -1122 }, { -140, 1677, -140, 1677, 15941, -1094, 15941, -1094 }, + { -131, 1611, -131, 1611, 15970, -1066, 15970, -1066 }, { -122, 1545, -122, 1545, 15998, -1037, 15998, -1037 }, + { -114, 1480, -114, 1480, 16025, -1007, 16025, -1007 }, { -106, 1415, -106, 1415, 16052, -977, 16052, -977 }, + { -98, 1351, -98, 1351, 16077, -946, 16077, -946 }, { -90, 1288, -90, 1288, 16101, -915, 16101, -915 }, + { -83, 1224, -83, 1224, 16125, -882, 16125, -882 }, { -76, 1162, -76, 1162, 16147, -849, 16147, -849 }, + { -69, 1100, -69, 1100, 16169, -816, 16169, -816 }, { -63, 1040, -63, 1040, 16189, -782, 16189, -782 }, + { -56, 978, -56, 978, 16209, -747, 16209, -747 }, { -51, 919, -51, 919, 16227, -711, 16227, -711 }, + { -45, 859, -45, 859, 16245, -675, 16245, -675 }, { -40, 800, -40, 800, 16262, -638, 16262, -638 }, + { -35, 743, -35, 743, 16277, -601, 16277, -601 }, { -30, 684, -30, 684, 16292, -562, 16292, -562 }, + { -26, 628, -26, 628, 16305, -523, 16305, -523 }, { -22, 572, -22, 572, 16318, -484, 16318, -484 }, + { -18, 516, -18, 516, 16329, -443, 16329, -443 }, { -15, 462, -15, 462, 16339, -402, 16339, -402 }, + { -12, 407, -12, 407, 16349, -360, 16349, -360 }, { -9, 354, -9, 354, 16357, -318, 16357, -318 }, + { -7, 302, -7, 302, 16364, -275, 16364, -275 }, { -5, 250, -5, 250, 16370, -231, 16370, -231 }, + { -3, 198, -3, 198, 16375, -186, 16375, -186 }, { -2, 148, -2, 148, 16379, -141, 16379, -141 }, + { -1, 98, -1, 98, 16382, -95, 16382, -95 }, { 0, 49, 0, 49, 16383, -48, 16383, -48 }, +}; + +#endif diff --git a/src/thirdparty/VirtualDub/Kasumi/source/triblt.cpp b/src/thirdparty/VirtualDub/Kasumi/source/triblt.cpp index ffcff760ac8..bf0752353a2 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/triblt.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/triblt.cpp @@ -1,1760 +1,1760 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - uint32 lerp_RGB888(sint32 a, sint32 b, sint32 x) { - sint32 a_rb = a & 0xff00ff; - sint32 a_g = a & 0x00ff00; - sint32 b_rb = b & 0xff00ff; - sint32 b_g = b & 0x00ff00; - - const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; - - return top_rb + top_g; - } - - uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { - sint32 a_rb = a & 0xff00ff; - sint32 a_g = a & 0x00ff00; - sint32 b_rb = b & 0xff00ff; - sint32 b_g = b & 0x00ff00; - sint32 c_rb = c & 0xff00ff; - sint32 c_g = c & 0x00ff00; - sint32 d_rb = d & 0xff00ff; - sint32 d_g = d & 0x00ff00; - - const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; - const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff; - const uint32 bot_g = (c_g + (((d_g - c_g )*x + 0x00008000) >> 8)) & 0x00ff00; - - const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff; - const uint32 final_g = (top_g + (((bot_g - top_g )*y) >> 8)) & 0x00ff00; - - return final_rb + final_g; - } - - uint32 bicubic_RGB888(const uint32 *src0, const uint32 *src1, const uint32 *src2, const uint32 *src3, sint32 x, sint32 y) { - const uint32 p00 = src0[0]; - const uint32 p01 = src0[1]; - const uint32 p02 = src0[2]; - const uint32 p03 = src0[3]; - const uint32 p10 = src1[0]; - const uint32 p11 = src1[1]; - const uint32 p12 = src1[2]; - const uint32 p13 = src1[3]; - const uint32 p20 = src2[0]; - const uint32 p21 = src2[1]; - const uint32 p22 = src2[2]; - const uint32 p23 = src2[3]; - const uint32 p30 = src3[0]; - const uint32 p31 = src3[1]; - const uint32 p32 = src3[2]; - const uint32 p33 = src3[3]; - - const sint32 *htab = kVDCubicInterpTableFX14_075[x]; - const sint32 *vtab = kVDCubicInterpTableFX14_075[y]; - - const int ch0 = htab[0]; - const int ch1 = htab[1]; - const int ch2 = htab[2]; - const int ch3 = htab[3]; - const int cv0 = vtab[0]; - const int cv1 = vtab[1]; - const int cv2 = vtab[2]; - const int cv3 = vtab[3]; - - int r0 = ((int)((p00>>16)&0xff) * ch0 + (int)((p01>>16)&0xff) * ch1 + (int)((p02>>16)&0xff) * ch2 + (int)((p03>>16)&0xff) * ch3 + 128) >> 8; - int g0 = ((int)((p00>> 8)&0xff) * ch0 + (int)((p01>> 8)&0xff) * ch1 + (int)((p02>> 8)&0xff) * ch2 + (int)((p03>> 8)&0xff) * ch3 + 128) >> 8; - int b0 = ((int)((p00 )&0xff) * ch0 + (int)((p01 )&0xff) * ch1 + (int)((p02 )&0xff) * ch2 + (int)((p03 )&0xff) * ch3 + 128) >> 8; - int r1 = ((int)((p10>>16)&0xff) * ch0 + (int)((p11>>16)&0xff) * ch1 + (int)((p12>>16)&0xff) * ch2 + (int)((p13>>16)&0xff) * ch3 + 128) >> 8; - int g1 = ((int)((p10>> 8)&0xff) * ch0 + (int)((p11>> 8)&0xff) * ch1 + (int)((p12>> 8)&0xff) * ch2 + (int)((p13>> 8)&0xff) * ch3 + 128) >> 8; - int b1 = ((int)((p10 )&0xff) * ch0 + (int)((p11 )&0xff) * ch1 + (int)((p12 )&0xff) * ch2 + (int)((p13 )&0xff) * ch3 + 128) >> 8; - int r2 = ((int)((p20>>16)&0xff) * ch0 + (int)((p21>>16)&0xff) * ch1 + (int)((p22>>16)&0xff) * ch2 + (int)((p23>>16)&0xff) * ch3 + 128) >> 8; - int g2 = ((int)((p20>> 8)&0xff) * ch0 + (int)((p21>> 8)&0xff) * ch1 + (int)((p22>> 8)&0xff) * ch2 + (int)((p23>> 8)&0xff) * ch3 + 128) >> 8; - int b2 = ((int)((p20 )&0xff) * ch0 + (int)((p21 )&0xff) * ch1 + (int)((p22 )&0xff) * ch2 + (int)((p23 )&0xff) * ch3 + 128) >> 8; - int r3 = ((int)((p30>>16)&0xff) * ch0 + (int)((p31>>16)&0xff) * ch1 + (int)((p32>>16)&0xff) * ch2 + (int)((p33>>16)&0xff) * ch3 + 128) >> 8; - int g3 = ((int)((p30>> 8)&0xff) * ch0 + (int)((p31>> 8)&0xff) * ch1 + (int)((p32>> 8)&0xff) * ch2 + (int)((p33>> 8)&0xff) * ch3 + 128) >> 8; - int b3 = ((int)((p30 )&0xff) * ch0 + (int)((p31 )&0xff) * ch1 + (int)((p32 )&0xff) * ch2 + (int)((p33 )&0xff) * ch3 + 128) >> 8; - - int r = (r0 * cv0 + r1 * cv1 + r2 * cv2 + r3 * cv3 + (1<<19)) >> 20; - int g = (g0 * cv0 + g1 * cv1 + g2 * cv2 + g3 * cv3 + (1<<19)) >> 20; - int b = (b0 * cv0 + b1 * cv1 + b2 * cv2 + b3 * cv3 + (1<<19)) >> 20; - - if (r<0) r=0; else if (r>255) r=255; - if (g<0) g=0; else if (g>255) g=255; - if (b<0) b=0; else if (b>255) b=255; - - return (r<<16) + (g<<8) + b; - } -} - -namespace { - enum { - kTop = 1, - kBottom = 2, - kLeft = 4, - kRight = 8, - kNear = 16, - kFar = 32 - }; - - struct VDTriBltMipInfo { - const uint32 *mip; - ptrdiff_t pitch; - uint32 uvmul, _pad; - }; - - struct VDTriBltInfo { - VDTriBltMipInfo mips[16]; - uint32 *dst; - const uint32 *src; - sint32 width; - const int *cubictab; - }; - - struct VDTriBltGenInfo { - float u; - float v; - float rhw; - float dudx; - float dvdx; - float drhwdx; - }; - - typedef void (*VDTriBltSpanFunction)(const VDTriBltInfo *); - typedef void (*VDTriBltGenFunction)(const VDTriBltGenInfo *); - - void vd_triblt_span_point(const VDTriBltInfo *pInfo) { - sint32 w = -pInfo->width; - uint32 *dst = pInfo->dst + pInfo->width; - const uint32 *src = pInfo->src; - const uint32 *texture = pInfo->mips[0].mip; - const ptrdiff_t texpitch = pInfo->mips[0].pitch; - - do { - dst[w] = vdptroffset(texture, texpitch * src[1])[src[0]]; - src += 2; - } while(++w); - } - - void vd_triblt_span_bilinear(const VDTriBltInfo *pInfo) { - sint32 w = -pInfo->width; - uint32 *dst = pInfo->dst + pInfo->width; - const uint32 *src = pInfo->src; - const uint32 *texture = pInfo->mips[0].mip; - const ptrdiff_t texpitch = pInfo->mips[0].pitch; - - do { - const sint32 u = src[0]; - const sint32 v = src[1]; - src += 2; - const uint32 *src1 = vdptroffset(texture, texpitch * (v>>8)) + (u>>8); - const uint32 *src2 = vdptroffset(src1, texpitch); - - dst[w] = bilerp_RGB888(src1[0], src1[1], src2[0], src2[1], u&255, v&255); - } while(++w); - } - - void vd_triblt_span_trilinear(const VDTriBltInfo *pInfo) { - sint32 w = -pInfo->width; - uint32 *dst = pInfo->dst + pInfo->width; - const uint32 *src = pInfo->src; - - do { - sint32 u = src[0]; - sint32 v = src[1]; - const sint32 lambda = src[2]; - src += 3; - - const sint32 lod = lambda >> 8; - - const uint32 *texture1 = pInfo->mips[lod].mip; - const ptrdiff_t texpitch1 = pInfo->mips[lod].pitch; - const uint32 *texture2 = pInfo->mips[lod+1].mip; - const ptrdiff_t texpitch2 = pInfo->mips[lod+1].pitch; - - u >>= lod; - v >>= lod; - - u += 128; - v += 128; - - const uint32 *src1 = vdptroffset(texture1, texpitch1 * (v>>8)) + (u>>8); - const uint32 *src2 = vdptroffset(src1, texpitch1); - const uint32 p1 = bilerp_RGB888(src1[0], src1[1], src2[0], src2[1], u&255, v&255); - - u += 128; - v += 128; - - const uint32 *src3 = vdptroffset(texture2, texpitch2 * (v>>9)) + (u>>9); - const uint32 *src4 = vdptroffset(src3, texpitch2); - const uint32 p2 = bilerp_RGB888(src3[0], src3[1], src4[0], src4[1], (u>>1)&255, (v>>1)&255); - - dst[w] = lerp_RGB888(p1, p2, lambda & 255); - } while(++w); - } - - void vd_triblt_span_bicubic_mip_linear(const VDTriBltInfo *pInfo) { - sint32 w = -pInfo->width; - uint32 *dst = pInfo->dst + pInfo->width; - const uint32 *src = pInfo->src; - - do { - sint32 u = src[0]; - sint32 v = src[1]; - const sint32 lambda = src[2]; - src += 3; - - const sint32 lod = lambda >> 8; - - const uint32 *texture1 = pInfo->mips[lod].mip; - const ptrdiff_t texpitch1 = pInfo->mips[lod].pitch; - const uint32 *texture2 = pInfo->mips[lod+1].mip; - const ptrdiff_t texpitch2 = pInfo->mips[lod+1].pitch; - - u >>= lod; - v >>= lod; - - u += 128; - v += 128; - - const uint32 *src1 = vdptroffset(texture1, texpitch1 * (v>>8)) + (u>>8); - const uint32 *src2 = vdptroffset(src1, texpitch1); - const uint32 *src3 = vdptroffset(src2, texpitch1); - const uint32 *src4 = vdptroffset(src3, texpitch1); - const uint32 p1 = bicubic_RGB888(src1, src2, src3, src4, u&255, v&255); - - u += 128; - v += 128; - - const uint32 *src5 = vdptroffset(texture2, texpitch2 * (v>>9)) + (u>>9); - const uint32 *src6 = vdptroffset(src5, texpitch2); - const uint32 *src7 = vdptroffset(src6, texpitch2); - const uint32 *src8 = vdptroffset(src7, texpitch2); - const uint32 p2 = bicubic_RGB888(src5, src6, src7, src8, (u>>1)&255, (v>>1)&255); - - dst[w] = lerp_RGB888(p1, p2, lambda & 255); - } while(++w); - } - -#ifdef _M_IX86 - extern "C" void vdasm_triblt_span_bilinear_mmx(const VDTriBltInfo *pInfo); - extern "C" void vdasm_triblt_span_trilinear_mmx(const VDTriBltInfo *pInfo); - extern "C" void vdasm_triblt_span_bicubic_mip_linear_mmx(const VDTriBltInfo *pInfo); - extern "C" void vdasm_triblt_span_bicubic_mip_linear_sse2(const VDTriBltInfo *pInfo); - extern "C" void vdasm_triblt_span_point(const VDTriBltInfo *pInfo); -#endif - - struct VDTriBltTransformedVertex { - float x, y, z; - union { - float w; - float rhw; - }; - float r, g, b, a; - float u, v; - int outcode; - - void interp(const VDTriBltTransformedVertex *v1, const VDTriBltTransformedVertex *v2, float alpha) { - x = v1->x + alpha * (v2->x - v1->x); - y = v1->y + alpha * (v2->y - v1->y); - z = v1->z + alpha * (v2->z - v1->z); - w = v1->w + alpha * (v2->w - v1->w); - - r = v1->r + alpha * (v2->r - v1->r); - g = v1->g + alpha * (v2->g - v1->g); - b = v1->b + alpha * (v2->b - v1->b); - a = v1->a + alpha * (v2->a - v1->a); - - u = v1->u + alpha * (v2->u - v1->u); - v = v1->v + alpha * (v2->v - v1->v); - - outcode = (x < -w ? kLeft : 0) - + (x > +w ? kRight : 0) - + (y < -w ? kTop : 0) - + (y > +w ? kBottom : 0) - + (z < -w ? kNear : 0) - + (z > +w ? kFar : 0); - } - }; - - void TransformVerts(VDTriBltTransformedVertex *dst, const VDTriBltVertex *src, int nVerts, const float xform[16]) { - const float xflocal[16]={ - xform[ 0], xform[ 1], xform[ 2], xform[ 3], - xform[ 4], xform[ 5], xform[ 6], xform[ 7], - xform[ 8], xform[ 9], xform[10], xform[11], - xform[12], xform[13], xform[14], xform[15], - }; - - if (nVerts <= 0) - return; - - do { - const float x0 = src->x; - const float y0 = src->y; - const float z0 = src->z; - - const float w = x0*xflocal[12] + y0*xflocal[13] + z0*xflocal[14] + xflocal[15]; - const float x = x0*xflocal[ 0] + y0*xflocal[ 1] + z0*xflocal[ 2] + xflocal[ 3]; - const float y = x0*xflocal[ 4] + y0*xflocal[ 5] + z0*xflocal[ 6] + xflocal[ 7]; - const float z = x0*xflocal[ 8] + y0*xflocal[ 9] + z0*xflocal[10] + xflocal[11]; - - int outcode = 0; - - if (x < -w) outcode += kLeft; - if (x > w) outcode += kRight; - if (y < -w) outcode += kTop; - if (y > w) outcode += kBottom; - if (z < -w) outcode += kNear; - if (z > w) outcode += kFar; - - dst->x = x; - dst->y = y; - dst->z = z; - dst->w = w; - dst->u = src->u; - dst->v = src->v; - dst->r = 1.0f; - dst->g = 1.0f; - dst->b = 1.0f; - dst->a = 1.0f; - dst->outcode = outcode; - - ++src; - ++dst; - } while(--nVerts); - } - - void TransformVerts(VDTriBltTransformedVertex *dst, const VDTriColorVertex *src, int nVerts, const float xform[16]) { - const float xflocal[16]={ - xform[ 0], xform[ 1], xform[ 2], xform[ 3], - xform[ 4], xform[ 5], xform[ 6], xform[ 7], - xform[ 8], xform[ 9], xform[10], xform[11], - xform[12], xform[13], xform[14], xform[15], - }; - - if (nVerts <= 0) - return; - - do { - const float x0 = src->x; - const float y0 = src->y; - const float z0 = src->z; - - const float w = x0*xflocal[12] + y0*xflocal[13] + z0*xflocal[14] + xflocal[15]; - const float x = x0*xflocal[ 0] + y0*xflocal[ 1] + z0*xflocal[ 2] + xflocal[ 3]; - const float y = x0*xflocal[ 4] + y0*xflocal[ 5] + z0*xflocal[ 6] + xflocal[ 7]; - const float z = x0*xflocal[ 8] + y0*xflocal[ 9] + z0*xflocal[10] + xflocal[11]; - - int outcode = 0; - - if (x < -w) outcode += kLeft; - if (x > w) outcode += kRight; - if (y < -w) outcode += kTop; - if (y > w) outcode += kBottom; - if (z < -w) outcode += kNear; - if (z > w) outcode += kFar; - - dst->x = x; - dst->y = y; - dst->z = z; - dst->w = w; - dst->u = 0.0f; - dst->v = 0.0f; - dst->r = src->r; - dst->g = src->g; - dst->b = src->b; - dst->a = src->a; - dst->outcode = outcode; - - ++src; - ++dst; - } while(--nVerts); - } - - struct VDTriangleSetupInfo { - const VDTriBltTransformedVertex *pt, *pr, *pl; - VDTriBltTransformedVertex tmp0, tmp1, tmp2; - }; - - void SetupTri( - VDTriangleSetupInfo& setup, - VDPixmap& dst, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2, - const VDTriBltFilterMode *filterMode - ) - { - setup.tmp0 = *vx0; - setup.tmp1 = *vx1; - setup.tmp2 = *vx2; - - // adjust UVs for filter mode - if (filterMode) { - switch(*filterMode) { - case kTriBltFilterBilinear: - setup.tmp0.u += 0.5f; - setup.tmp0.v += 0.5f; - setup.tmp1.u += 0.5f; - setup.tmp1.v += 0.5f; - setup.tmp2.u += 0.5f; - setup.tmp2.v += 0.5f; - case kTriBltFilterTrilinear: - case kTriBltFilterBicubicMipLinear: - setup.tmp0.u *= 256.0f; - setup.tmp0.v *= 256.0f; - setup.tmp1.u *= 256.0f; - setup.tmp1.v *= 256.0f; - setup.tmp2.u *= 256.0f; - setup.tmp2.v *= 256.0f; - break; - case kTriBltFilterPoint: - setup.tmp0.u += 1.0f; - setup.tmp0.v += 1.0f; - setup.tmp1.u += 1.0f; - setup.tmp1.v += 1.0f; - setup.tmp2.u += 1.0f; - setup.tmp2.v += 1.0f; - break; - } - } - - // do perspective divide and NDC space conversion - const float xscale = dst.w * 0.5f; - const float yscale = dst.h * 0.5f; - - setup.tmp0.rhw = 1.0f / setup.tmp0.w; - setup.tmp0.x = (1.0f+setup.tmp0.x*setup.tmp0.rhw)*xscale; - setup.tmp0.y = (1.0f+setup.tmp0.y*setup.tmp0.rhw)*yscale; - setup.tmp0.u *= setup.tmp0.rhw; - setup.tmp0.v *= setup.tmp0.rhw; - setup.tmp0.r *= setup.tmp0.rhw; - setup.tmp0.g *= setup.tmp0.rhw; - setup.tmp0.b *= setup.tmp0.rhw; - setup.tmp0.a *= setup.tmp0.rhw; - setup.tmp1.rhw = 1.0f / setup.tmp1.w; - setup.tmp1.x = (1.0f+setup.tmp1.x*setup.tmp1.rhw)*xscale; - setup.tmp1.y = (1.0f+setup.tmp1.y*setup.tmp1.rhw)*yscale; - setup.tmp1.u *= setup.tmp1.rhw; - setup.tmp1.v *= setup.tmp1.rhw; - setup.tmp1.r *= setup.tmp1.rhw; - setup.tmp1.g *= setup.tmp1.rhw; - setup.tmp1.b *= setup.tmp1.rhw; - setup.tmp1.a *= setup.tmp1.rhw; - setup.tmp2.rhw = 1.0f / setup.tmp2.w; - setup.tmp2.x = (1.0f+setup.tmp2.x*setup.tmp2.rhw)*xscale; - setup.tmp2.y = (1.0f+setup.tmp2.y*setup.tmp2.rhw)*yscale; - setup.tmp2.u *= setup.tmp2.rhw; - setup.tmp2.v *= setup.tmp2.rhw; - setup.tmp2.r *= setup.tmp2.rhw; - setup.tmp2.g *= setup.tmp2.rhw; - setup.tmp2.b *= setup.tmp2.rhw; - setup.tmp2.a *= setup.tmp2.rhw; - - // verify clipping - VDASSERT(setup.tmp0.x >= 0 && setup.tmp0.x <= dst.w); - VDASSERT(setup.tmp1.x >= 0 && setup.tmp1.x <= dst.w); - VDASSERT(setup.tmp2.x >= 0 && setup.tmp2.x <= dst.w); - VDASSERT(setup.tmp0.y >= 0 && setup.tmp0.y <= dst.h); - VDASSERT(setup.tmp1.y >= 0 && setup.tmp1.y <= dst.h); - VDASSERT(setup.tmp2.y >= 0 && setup.tmp2.y <= dst.h); - - vx0 = &setup.tmp0; - vx1 = &setup.tmp1; - vx2 = &setup.tmp2; - - const VDTriBltTransformedVertex *pt, *pl, *pr; - - // sort points - if (vx0->y < vx1->y) // 1 < 2 - if (vx0->y < vx2->y) { // 1 < 2,3 - pt = vx0; - pr = vx1; - pl = vx2; - } else { // 3 < 1 < 2 - pt = vx2; - pr = vx0; - pl = vx1; - } - else // 2 < 1 - if (vx1->y < vx2->y) { // 2 < 1,3 - pt = vx1; - pr = vx2; - pl = vx0; - } else { // 3 < 2 < 1 - pt = vx2; - pr = vx0; - pl = vx1; - } - - setup.pl = pl; - setup.pt = pt; - setup.pr = pr; - } - - void RenderTri(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2, - VDTriBltFilterMode filterMode, - float mipMapLODBias) - { - VDTriangleSetupInfo setup; - - SetupTri(setup, dst, vx0, vx1, vx2, &filterMode); - - const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; - - const float x10 = pl->x - pt->x; - const float x20 = pr->x - pt->x; - const float y10 = pl->y - pt->y; - const float y20 = pr->y - pt->y; - const float A = x20*y10 - x10*y20; - - if (A <= 0.f) - return; - - float invA = 0.f; - if (A >= 1e-5f) - invA = 1.0f / A; - - float x10_A = x10 * invA; - float x20_A = x20 * invA; - float y10_A = y10 * invA; - float y20_A = y20 * invA; - - float u10 = pl->u - pt->u; - float u20 = pr->u - pt->u; - float v10 = pl->v - pt->v; - float v20 = pr->v - pt->v; - float rhw10 = pl->rhw - pt->rhw; - float rhw20 = pr->rhw - pt->rhw; - - float dudx = u20*y10_A - u10*y20_A; - float dudy = u10*x20_A - u20*x10_A; - float dvdx = v20*y10_A - v10*y20_A; - float dvdy = v10*x20_A - v20*x10_A; - float drhwdx = rhw20*y10_A - rhw10*y20_A; - float drhwdy = rhw10*x20_A - rhw20*x10_A; - - // Compute edge walking parameters - - float dxl1=0, dxr1=0, dul1=0, dvl1=0, drhwl1=0; - float dxl2=0, dxr2=0, dul2=0, dvl2=0, drhwl2=0; - - // Compute left-edge interpolation parameters for first half. - - if (pl->y != pt->y) { - dxl1 = (pl->x - pt->x) / (pl->y - pt->y); - - dul1 = dudy + dxl1 * dudx; - dvl1 = dvdy + dxl1 * dvdx; - drhwl1 = drhwdy + dxl1 * drhwdx; - } - - // Compute right-edge interpolation parameters for first half. - - if (pr->y != pt->y) { - dxr1 = (pr->x - pt->x) / (pr->y - pt->y); - } - - // Compute third-edge interpolation parameters. - - if (pr->y != pl->y) { - dxl2 = (pr->x - pl->x) / (pr->y - pl->y); - - dul2 = dudy + dxl2 * dudx; - dvl2 = dvdy + dxl2 * dvdx; - drhwl2 = drhwdy + dxl2 * drhwdx; - - dxr2 = dxl2; - } - - // Initialize parameters for first half. - // - // We place pixel centers at (x+0.5, y+0.5). - - double xl, xr, ul, vl, rhwl, yf; - int y, y1, y2; - - // y_start < y+0.5 to include pixel y. - - y = (int)floor(pt->y + 0.5); - yf = (y+0.5) - pt->y; - - xl = pt->x + dxl1 * yf; - xr = pt->x + dxr1 * yf; - ul = pt->u + dul1 * yf; - vl = pt->v + dvl1 * yf; - rhwl = pt->rhw + drhwl1 * yf; - - // Initialize parameters for second half. - - double xl2, xr2, ul2, vl2, rhwl2; - - if (pl->y > pr->y) { // Left edge is long side - dxl2 = dxl1; - dul2 = dul1; - dvl2 = dvl1; - drhwl2 = drhwl1; - - y1 = (int)floor(pr->y + 0.5); - y2 = (int)floor(pl->y + 0.5); - - yf = (y1+0.5) - pr->y; - - // Step left edge. - - xl2 = xl + dxl1 * (y1 - y); - ul2 = ul + dul1 * (y1 - y); - vl2 = vl + dvl1 * (y1 - y); - rhwl2 = rhwl + drhwl1 * (y1 - y); - - // Prestep right edge. - - xr2 = pr->x + dxr2 * yf; - } else { // Right edge is long side - dxr2 = dxr1; - - y1 = (int)floor(pl->y + 0.5); - y2 = (int)floor(pr->y + 0.5); - - yf = (y1+0.5) - pl->y; - - // Prestep left edge. - - xl2 = pl->x + dxl2 * yf; - ul2 = pl->u + dul2 * yf; - vl2 = pl->v + dvl2 * yf; - rhwl2 = pl->rhw + drhwl2 * yf; - - // Step right edge. - - xr2 = xr + dxr1 * (y1 - y); - } - - // rasterize - const ptrdiff_t dstpitch = dst.pitch; - uint32 *dstp = (uint32 *)((char *)dst.data + dstpitch * y); - - VDTriBltInfo texinfo; - VDTriBltSpanFunction drawSpan; - uint32 cpuflags = CPUGetEnabledExtensions(); - - bool triBlt16 = false; - - switch(filterMode) { - case kTriBltFilterBicubicMipLinear: -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_SSE2) { - drawSpan = vdasm_triblt_span_bicubic_mip_linear_sse2; - triBlt16 = true; - } else if (cpuflags & CPUF_SUPPORTS_MMX) { - drawSpan = vdasm_triblt_span_bicubic_mip_linear_mmx; - triBlt16 = true; - } else -#endif - drawSpan = vd_triblt_span_bicubic_mip_linear; - break; - case kTriBltFilterTrilinear: -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_MMX) { - drawSpan = vdasm_triblt_span_trilinear_mmx; - triBlt16 = true; - } else -#endif - drawSpan = vd_triblt_span_trilinear; - break; - case kTriBltFilterBilinear: -#ifdef _M_IX86 - if (cpuflags & CPUF_SUPPORTS_MMX) { - drawSpan = vdasm_triblt_span_bilinear_mmx; - triBlt16 = true; - } else -#endif - drawSpan = vd_triblt_span_bilinear; - break; - case kTriBltFilterPoint: - drawSpan = vd_triblt_span_point; - break; - } - - float rhobase = sqrtf(std::max(dudx*dudx + dvdx*dvdx, dudy*dudy + dvdy*dvdy) * (1.0f / 65536.0f)) * powf(2.0f, mipMapLODBias); - - if (triBlt16) { - ul *= 256.0f; - vl *= 256.0f; - ul2 *= 256.0f; - vl2 *= 256.0f; - dul1 *= 256.0f; - dvl1 *= 256.0f; - dul2 *= 256.0f; - dvl2 *= 256.0f; - dudx *= 256.0f; - dvdx *= 256.0f; - dudy *= 256.0f; - dvdy *= 256.0f; - } - - int minx1 = (int)floor(std::min(std::min(pl->x, pr->x), pt->x) + 0.5); - int maxx2 = (int)floor(std::max(std::max(pl->x, pr->x), pt->x) + 0.5); - - uint32 *const spanptr = new uint32[3 * (maxx2 - minx1)]; - - while(y < y2) { - if (y == y1) { - xl = xl2; - xr = xr2; - ul = ul2; - vl = vl2; - rhwl = rhwl2; - dxl1 = dxl2; - dxr1 = dxr2; - dul1 = dul2; - dvl1 = dvl2; - drhwl1 = drhwl2; - } - - int x1, x2; - double xf; - double u, v, rhw; - - // x_left must be less than (x+0.5) to include pixel x. - - x1 = (int)floor(xl + 0.5); - x2 = (int)floor(xr + 0.5); - xf = (x1+0.5) - xl; - - u = ul + xf * dudx; - v = vl + xf * dvdx; - rhw = rhwl + xf * drhwdx; - - int x = x1; - uint32 *spanp = spanptr; - - float w = 1.0f / (float)rhw; - - if (x < x2) { - if (filterMode >= kTriBltFilterTrilinear) { - do { - int utexel = VDRoundToIntFastFullRange(u * w); - int vtexel = VDRoundToIntFastFullRange(v * w); - union{ float f; sint32 i; } rho = {rhobase * w}; - - int lambda = ((rho.i - 0x3F800000) >> (23-8)); - if (lambda < 0) - lambda = 0; - if (lambda >= (nMipmaps<<8)-256) - lambda = (nMipmaps<<8)-257; - - spanp[0] = utexel; - spanp[1] = vtexel; - spanp[2] = lambda; - spanp += 3; - - u += dudx; - v += dvdx; - rhw += drhwdx; - - w *= (2.0f - w*(float)rhw); - } while(++x < x2); - } else { - do { - int utexel = VDFloorToInt(u * w); - int vtexel = VDFloorToInt(v * w); - - spanp[0] = utexel; - spanp[1] = vtexel; - spanp += 2; - - u += dudx; - v += dvdx; - rhw += drhwdx; - - w *= (2.0f - w*(float)rhw); - } while(++x < x2); - } - } - - for(int i=0; idata; - texinfo.mips[i].pitch = pSources[i]->pitch; - texinfo.mips[i].uvmul = (pSources[i]->pitch << 16) + 4; - } - texinfo.dst = dstp+x1; - texinfo.src = spanptr; - texinfo.width = x2-x1; - - if (texinfo.width>0) - drawSpan(&texinfo); - - dstp = vdptroffset(dstp, dstpitch); - xl += dxl1; - xr += dxr1; - ul += dul1; - vl += dvl1; - rhwl += drhwl1; - - ++y; - } - - delete[] spanptr; - } - - void FillTri(VDPixmap& dst, uint32 c, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2 - ) - { - - VDTriangleSetupInfo setup; - - SetupTri(setup, dst, vx0, vx1, vx2, NULL); - - const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; - - // Compute edge walking parameters - float dxl1=0, dxr1=0; - float dxl2=0, dxr2=0; - - float x_lt = pl->x - pt->x; - float x_rt = pr->x - pt->x; - float x_rl = pr->x - pl->x; - float y_lt = pl->y - pt->y; - float y_rt = pr->y - pt->y; - float y_rl = pr->y - pl->y; - - // reject backfaces - if (x_lt*y_rt >= x_rt*y_lt) - return; - - // Compute left-edge interpolation parameters for first half. - if (pl->y != pt->y) - dxl1 = x_lt / y_lt; - - // Compute right-edge interpolation parameters for first half. - if (pr->y != pt->y) - dxr1 = x_rt / y_rt; - - // Compute third-edge interpolation parameters. - if (pr->y != pl->y) { - dxl2 = x_rl / y_rl; - - dxr2 = dxl2; - } - - // Initialize parameters for first half. - // - // We place pixel centers at (x+0.5, y+0.5). - - double xl, xr, yf; - int y, y1, y2; - - // y_start < y+0.5 to include pixel y. - - y = (int)floor(pt->y + 0.5); - yf = (y+0.5) - pt->y; - - xl = pt->x + dxl1 * yf; - xr = pt->x + dxr1 * yf; - - // Initialize parameters for second half. - double xl2, xr2; - - if (pl->y > pr->y) { // Left edge is long side - dxl2 = dxl1; - - y1 = (int)floor(pr->y + 0.5); - y2 = (int)floor(pl->y + 0.5); - - yf = (y1+0.5) - pr->y; - - // Prestep right edge. - xr2 = pr->x + dxr2 * yf; - - // Step left edge. - xl2 = xl + dxl1 * (y1 - y); - } else { // Right edge is long side - dxr2 = dxr1; - - y1 = (int)floor(pl->y + 0.5); - y2 = (int)floor(pr->y + 0.5); - - yf = (y1+0.5) - pl->y; - - // Prestep left edge. - xl2 = pl->x + dxl2 * yf; - - // Step right edge. - xr2 = xr + dxr1 * (y1 - y); - } - - // rasterize - const ptrdiff_t dstpitch = dst.pitch; - uint32 *dstp = (uint32 *)((char *)dst.data + dstpitch * y); - - while(y < y2) { - if (y == y1) { - xl = xl2; - xr = xr2; - dxl1 = dxl2; - dxr1 = dxr2; - } - - int x1, x2; - double xf; - - // x_left must be less than (x+0.5) to include pixel x. - - x1 = (int)floor(xl + 0.5); - x2 = (int)floor(xr + 0.5); - xf = (x1+0.5) - xl; - - while(x1 < x2) - dstp[x1++] = c; - - dstp = vdptroffset(dstp, dstpitch); - xl += dxl1; - xr += dxr1; - ++y; - } - } - - void FillTriGrad(VDPixmap& dst, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2 - ) - { - - VDTriangleSetupInfo setup; - - SetupTri(setup, dst, vx0, vx1, vx2, NULL); - - const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; - const float x10 = pl->x - pt->x; - const float x20 = pr->x - pt->x; - const float y10 = pl->y - pt->y; - const float y20 = pr->y - pt->y; - const float A = x20*y10 - x10*y20; - - if (A <= 0.f) - return; - - float invA = 0.f; - if (A >= 1e-5f) - invA = 1.0f / A; - - float x10_A = x10 * invA; - float x20_A = x20 * invA; - float y10_A = y10 * invA; - float y20_A = y20 * invA; - - float r10 = pl->r - pt->r; - float r20 = pr->r - pt->r; - float g10 = pl->g - pt->g; - float g20 = pr->g - pt->g; - float b10 = pl->b - pt->b; - float b20 = pr->b - pt->b; - float a10 = pl->a - pt->a; - float a20 = pr->a - pt->a; - float rhw10 = pl->rhw - pt->rhw; - float rhw20 = pr->rhw - pt->rhw; - - float drdx = r20*y10_A - r10*y20_A; - float drdy = r10*x20_A - r20*x10_A; - float dgdx = g20*y10_A - g10*y20_A; - float dgdy = g10*x20_A - g20*x10_A; - float dbdx = b20*y10_A - b10*y20_A; - float dbdy = b10*x20_A - b20*x10_A; - float dadx = a20*y10_A - a10*y20_A; - float dady = a10*x20_A - a20*x10_A; - float drhwdx = rhw20*y10_A - rhw10*y20_A; - float drhwdy = rhw10*x20_A - rhw20*x10_A; - - // Compute edge walking parameters - float dxl1=0; - float drl1=0; - float dgl1=0; - float dbl1=0; - float dal1=0; - float drhwl1=0; - float dxr1=0; - float dxl2=0; - float drl2=0; - float dgl2=0; - float dbl2=0; - float dal2=0; - float drhwl2=0; - float dxr2=0; - - float x_lt = pl->x - pt->x; - float x_rt = pr->x - pt->x; - float x_rl = pr->x - pl->x; - float y_lt = pl->y - pt->y; - float y_rt = pr->y - pt->y; - float y_rl = pr->y - pl->y; - - // Compute left-edge interpolation parameters for first half. - if (pl->y != pt->y) { - dxl1 = x_lt / y_lt; - drl1 = drdy + dxl1 * drdx; - dgl1 = dgdy + dxl1 * dgdx; - dbl1 = dbdy + dxl1 * dbdx; - dal1 = dady + dxl1 * dadx; - drhwl1 = drhwdy + dxl1 * drhwdx; - } - - // Compute right-edge interpolation parameters for first half. - if (pr->y != pt->y) - dxr1 = x_rt / y_rt; - - // Compute third-edge interpolation parameters. - if (pr->y != pl->y) { - dxl2 = x_rl / y_rl; - - drl2 = drdy + dxl2 * drdx; - dgl2 = dgdy + dxl2 * dgdx; - dbl2 = dbdy + dxl2 * dbdx; - dal2 = dady + dxl2 * dadx; - drhwl2 = drhwdy + dxl2 * drhwdx; - - dxr2 = dxl2; - } - - // Initialize parameters for first half. - // - // We place pixel centers at (x+0.5, y+0.5). - - double xl, xr, yf; - double rl, gl, bl, al, rhwl; - double rl2, gl2, bl2, al2, rhwl2; - int y, y1, y2; - - // y_start < y+0.5 to include pixel y. - - y = (int)floor(pt->y + 0.5); - yf = (y+0.5) - pt->y; - - xl = pt->x + dxl1 * yf; - xr = pt->x + dxr1 * yf; - rl = pt->r + drl1 * yf; - gl = pt->g + dgl1 * yf; - bl = pt->b + dbl1 * yf; - al = pt->a + dal1 * yf; - rhwl = pt->rhw + drhwl1 * yf; - - // Initialize parameters for second half. - double xl2, xr2; - - if (pl->y > pr->y) { // Left edge is long side - dxl2 = dxl1; - drl2 = drl1; - dgl2 = dgl1; - dbl2 = dbl1; - dal2 = dal1; - drhwl2 = drhwl1; - - y1 = (int)floor(pr->y + 0.5); - y2 = (int)floor(pl->y + 0.5); - - yf = (y1+0.5) - pr->y; - - // Step left edge. - xl2 = xl + dxl1 * (y1 - y); - rl2 = rl + drl1 * (y1 - y); - gl2 = gl + dgl1 * (y1 - y); - bl2 = bl + dbl1 * (y1 - y); - al2 = al + dal1 * (y1 - y); - rhwl2 = rhwl + drhwl1 * (y1 - y); - - // Prestep right edge. - xr2 = pr->x + dxr2 * yf; - } else { // Right edge is long side - dxr2 = dxr1; - - y1 = (int)floor(pl->y + 0.5); - y2 = (int)floor(pr->y + 0.5); - - yf = (y1+0.5) - pl->y; - - // Prestep left edge. - xl2 = pl->x + dxl2 * yf; - rl2 = pl->r + drl2 * yf; - gl2 = pl->g + dgl2 * yf; - bl2 = pl->b + dbl2 * yf; - al2 = pl->a + dal2 * yf; - rhwl2 = pl->rhw + drhwl2 * yf; - - // Step right edge. - xr2 = xr + dxr2 * (y1 - y); - } - - // rasterize - const ptrdiff_t dstpitch = dst.pitch; - char *dstp0 = (char *)dst.data + dstpitch * y; - - while(y < y2) { - if (y == y1) { - xl = xl2; - xr = xr2; - rl = rl2; - gl = gl2; - bl = bl2; - al = al2; - rhwl = rhwl2; - dxl1 = dxl2; - drl1 = drl2; - dgl1 = dgl2; - dbl1 = dbl2; - dal1 = dal2; - drhwl1 = drhwl2; - dxr1 = dxr2; - } - - int x1, x2; - double xf; - double r, g, b, a, rhw; - - // x_left must be less than (x+0.5) to include pixel x. - - x1 = (int)floor(xl + 0.5); - x2 = (int)floor(xr + 0.5); - xf = (x1+0.5) - xl; - - r = rl + xf * drdx; - g = gl + xf * dgdx; - b = bl + xf * dbdx; - a = al + xf * dadx; - rhw = rhwl + xf * drhwdx; - - float w = 1.0f / (float)rhw; - - if (x1 < x2) { - if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) { - uint32 *dstp = (uint32 *)dstp0; - - do { - float sr = (float)(r * w); - float sg = (float)(g * w); - float sb = (float)(b * w); - float sa = (float)(a * w); - - uint8 ir = VDClampedRoundFixedToUint8Fast(sr); - uint8 ig = VDClampedRoundFixedToUint8Fast(sg); - uint8 ib = VDClampedRoundFixedToUint8Fast(sb); - uint8 ia = VDClampedRoundFixedToUint8Fast(sa); - - dstp[x1] = ((uint32)ia << 24) + ((uint32)ir << 16) + ((uint32)ig << 8) + ib; - - r += drdx; - g += dgdx; - b += dbdx; - a += dadx; - rhw += drhwdx; - - w *= (2.0f - w*(float)rhw); - } while(++x1 < x2); - } else { - uint8 *dstp = (uint8 *)dstp0; - - do { - float sg = (float)(g * w); - - uint8 ig = VDClampedRoundFixedToUint8Fast(sg); - - dstp[x1] = ig; - - g += dgdx; - rhw += drhwdx; - - w *= (2.0f - w*(float)rhw); - } while(++x1 < x2); - } - } - - dstp0 = vdptroffset(dstp0, dstpitch); - xl += dxl1; - rl += drl1; - gl += dgl1; - bl += dbl1; - al += dal1; - rhwl += drhwl1; - xr += dxr1; - ++y; - } - } - - struct VDTriClipWorkspace { - VDTriBltTransformedVertex *vxheapptr[2][19]; - VDTriBltTransformedVertex vxheap[21]; - }; - - VDTriBltTransformedVertex **VDClipTriangle(VDTriClipWorkspace& ws, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2, - int orflags) { - // Each line segment can intersect all six planes, meaning the maximum bound is - // 18 vertices. Add 3 for the original. - - VDTriBltTransformedVertex *vxheapnext; - VDTriBltTransformedVertex **vxlastheap = ws.vxheapptr[0], **vxnextheap = ws.vxheapptr[1]; - - ws.vxheap[0] = *vx0; - ws.vxheap[1] = *vx1; - ws.vxheap[2] = *vx2; - - vxlastheap[0] = &ws.vxheap[0]; - vxlastheap[1] = &ws.vxheap[1]; - vxlastheap[2] = &ws.vxheap[2]; - vxlastheap[3] = NULL; - - vxheapnext = ws.vxheap + 3; - - // Current Next Action - // ------- ---- ------ - // Unclipped Unclipped Copy vertex - // Unclipped Clipped Copy vertex and add intersection - // Clipped Unclipped Add intersection - // Clipped Clipped No action - -#define DOCLIP(cliptype, _sign_, cliparg) \ - if (orflags & k##cliptype) { \ - VDTriBltTransformedVertex **src = vxlastheap; \ - VDTriBltTransformedVertex **dst = vxnextheap; \ - \ - while(*src) { \ - VDTriBltTransformedVertex *cur = *src; \ - VDTriBltTransformedVertex *next = src[1]; \ - \ - if (!next) \ - next = vxlastheap[0]; \ - \ - if (!(cur->outcode & k##cliptype)) \ - *dst++ = cur; \ - \ - if ((cur->outcode ^ next->outcode) & k##cliptype) { \ - double alpha = (cur->w _sign_ cur->cliparg) / ((cur->w _sign_ cur->cliparg) - (next->w _sign_ next->cliparg)); \ - \ - if (alpha >= 0.0 && alpha <= 1.0) { \ - vxheapnext->interp(cur, next, (float)alpha); \ - vxheapnext->cliparg = -(_sign_ vxheapnext->w); \ - *dst++ = vxheapnext++; \ - } \ - } \ - ++src; \ - } \ - *dst = NULL; \ - if (dst < vxnextheap+3) return NULL; \ - src = vxlastheap; vxlastheap = vxnextheap; vxnextheap = src; \ - } - - - DOCLIP(Far, -, z); - DOCLIP(Near, +, z); - DOCLIP(Bottom, -, y); - DOCLIP(Top, +, y); - DOCLIP(Right, -, x); - DOCLIP(Left, +, x); - -#undef DOCLIP - - return vxlastheap; - } - - void RenderClippedTri(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, - const VDTriBltTransformedVertex *vx0, - const VDTriBltTransformedVertex *vx1, - const VDTriBltTransformedVertex *vx2, - VDTriBltFilterMode filterMode, - float mipMapLODBias, - int orflags) - { - - VDTriBltTransformedVertex *vxheapnext; - VDTriBltTransformedVertex vxheap[21]; - - VDTriBltTransformedVertex *vxheapptr[2][19]; - VDTriBltTransformedVertex **vxlastheap = vxheapptr[0], **vxnextheap = vxheapptr[1]; - - vxheap[0] = *vx0; - vxheap[1] = *vx1; - vxheap[2] = *vx2; - - vxlastheap[0] = &vxheap[0]; - vxlastheap[1] = &vxheap[1]; - vxlastheap[2] = &vxheap[2]; - vxlastheap[3] = NULL; - - vxheapnext = vxheap + 3; - - // Current Next Action - // ------- ---- ------ - // Unclipped Unclipped Copy vertex - // Unclipped Clipped Copy vertex and add intersection - // Clipped Unclipped Add intersection - // Clipped Clipped No action - -#define DOCLIP(cliptype, _sign_, cliparg) \ - if (orflags & k##cliptype) { \ - VDTriBltTransformedVertex **src = vxlastheap; \ - VDTriBltTransformedVertex **dst = vxnextheap; \ - \ - while(*src) { \ - VDTriBltTransformedVertex *cur = *src; \ - VDTriBltTransformedVertex *next = src[1]; \ - \ - if (!next) \ - next = vxlastheap[0]; \ - \ - if (!(cur->outcode & k##cliptype)) \ - *dst++ = cur; \ - \ - if ((cur->outcode ^ next->outcode) & k##cliptype) { \ - double alpha = (cur->w _sign_ cur->cliparg) / ((cur->w _sign_ cur->cliparg) - (next->w _sign_ next->cliparg)); \ - \ - if (alpha >= 0.0 && alpha <= 1.0) { \ - vxheapnext->interp(cur, next, (float)alpha); \ - vxheapnext->cliparg = -(_sign_ vxheapnext->w); \ - *dst++ = vxheapnext++; \ - } \ - } \ - ++src; \ - } \ - *dst = NULL; \ - if (dst < vxnextheap+3) return; \ - src = vxlastheap; vxlastheap = vxnextheap; vxnextheap = src; \ - } - - - DOCLIP(Far, -, z); - DOCLIP(Near, +, z); - DOCLIP(Bottom, -, y); - DOCLIP(Top, +, y); - DOCLIP(Right, -, x); - DOCLIP(Left, +, x); - -#undef DOCLIP - - VDTriBltTransformedVertex **src = vxlastheap+1; - - while(src[1]) { - RenderTri(dst, pSources, nMipmaps, vxlastheap[0], src[0], src[1], filterMode, mipMapLODBias); - ++src; - } - } - -} - -bool VDPixmapTriFill(VDPixmap& dst, const uint32 c, const VDTriBltVertex *pVertices, int nVertices, const int *pIndices, int nIndices, const float pTransform[16]) { - if (dst.format != nsVDPixmap::kPixFormat_XRGB8888) - return false; - - static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; - vdfastvector xverts(nVertices); - - if (!pTransform) - pTransform = xf_ident; - - TransformVerts(xverts.data(), pVertices, nVertices, pTransform); - - const VDTriBltTransformedVertex *xsrc = xverts.data(); - - VDTriClipWorkspace clipws; - - while(nIndices >= 3) { - const int idx0 = pIndices[0]; - const int idx1 = pIndices[1]; - const int idx2 = pIndices[2]; - const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; - const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; - const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; - const int kode0 = xv0->outcode; - const int kode1 = xv1->outcode; - const int kode2 = xv2->outcode; - - if (!(kode0 & kode1 & kode2)) { - if (int orflags = kode0 | kode1 | kode2) { - VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); - - if (src) { - VDTriBltTransformedVertex *src0 = *src++; - - // fan out triangles - while(src[1]) { - FillTri(dst, c, src0, src[0], src[1]); - ++src; - } - } - } else - FillTri(dst, c, xv0, xv1, xv2); - } - - pIndices += 3; - nIndices -= 3; - } - - return true; -} - -bool VDPixmapTriFill(VDPixmap& dst, const VDTriColorVertex *pVertices, int nVertices, const int *pIndices, int nIndices, const float pTransform[16], const float *chroma_yoffset) { - VDPixmap pxY; - VDPixmap pxCb; - VDPixmap pxCr; - bool ycbcr = false; - float ycbcr_xoffset = 0; - - switch(dst.format) { - case nsVDPixmap::kPixFormat_XRGB8888: - case nsVDPixmap::kPixFormat_Y8: - break; - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - pxY.format = nsVDPixmap::kPixFormat_Y8; - pxY.data = dst.data; - pxY.pitch = dst.pitch; - pxY.w = dst.w; - pxY.h = dst.h; - - pxCb.format = nsVDPixmap::kPixFormat_Y8; - pxCb.data = dst.data2; - pxCb.pitch = dst.pitch2; - pxCb.w = dst.w; - pxCb.h = dst.h; - - pxCr.format = nsVDPixmap::kPixFormat_Y8; - pxCr.data = dst.data3; - pxCr.pitch = dst.pitch3; - pxCr.w = dst.w; - pxCr.h = dst.h; - - switch(dst.format) { - case nsVDPixmap::kPixFormat_YUV410_Planar: - case nsVDPixmap::kPixFormat_YUV410_Planar_FR: - case nsVDPixmap::kPixFormat_YUV410_Planar_709: - case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 2; - pxCr.h = pxCb.h = dst.h >> 2; - ycbcr_xoffset = 0.75f / (float)pxCr.w; - break; - - case nsVDPixmap::kPixFormat_YUV420_Planar: - case nsVDPixmap::kPixFormat_YUV420_Planar_FR: - case nsVDPixmap::kPixFormat_YUV420_Planar_709: - case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 1; - pxCr.h = pxCb.h = dst.h >> 1; - ycbcr_xoffset = 0.5f / (float)pxCr.w; - break; - - case nsVDPixmap::kPixFormat_YUV422_Planar: - case nsVDPixmap::kPixFormat_YUV422_Planar_FR: - case nsVDPixmap::kPixFormat_YUV422_Planar_709: - case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: - pxCr.w = pxCb.w = dst.w >> 1; - ycbcr_xoffset = 0.5f / (float)pxCr.w; - break; - - case nsVDPixmap::kPixFormat_YUV444_Planar: - case nsVDPixmap::kPixFormat_YUV444_Planar_FR: - case nsVDPixmap::kPixFormat_YUV444_Planar_709: - case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: - pxCr.w = pxCb.w = dst.w; - ycbcr_xoffset = 0.0f; - break; - } - - ycbcr = true; - break; - default: - return false; - } - - VDTriBltTransformedVertex fastxverts[64]; - vdfastvector xverts; - - VDTriBltTransformedVertex *xsrc; - if (nVertices <= 64) { - xsrc = fastxverts; - } else { - xverts.resize(nVertices); - xsrc = xverts.data(); - } - - static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; - if (!pTransform) - pTransform = xf_ident; - - VDTriClipWorkspace clipws; - for(int plane=0; plane<(ycbcr?3:1); ++plane) { - VDPixmap& pxPlane = ycbcr ? plane == 0 ? pxY : plane == 1 ? pxCb : pxCr : dst; - - if (ycbcr && plane) { - float xf_ycbcr[16]; - memcpy(xf_ycbcr, pTransform, sizeof(float) * 16); - - // translate in x by ycbcr_xoffset - xf_ycbcr[0] += xf_ycbcr[12]*ycbcr_xoffset; - xf_ycbcr[1] += xf_ycbcr[13]*ycbcr_xoffset; - xf_ycbcr[2] += xf_ycbcr[14]*ycbcr_xoffset; - xf_ycbcr[3] += xf_ycbcr[15]*ycbcr_xoffset; - - // translate in y by chroma_yoffset - if (chroma_yoffset) { - xf_ycbcr[4] += xf_ycbcr[12]*(*chroma_yoffset); - xf_ycbcr[5] += xf_ycbcr[13]*(*chroma_yoffset); - xf_ycbcr[6] += xf_ycbcr[14]*(*chroma_yoffset); - xf_ycbcr[7] += xf_ycbcr[15]*(*chroma_yoffset); - } - - TransformVerts(xsrc, pVertices, nVertices, xf_ycbcr); - - switch(plane) { - case 1: - for(int i=0; i= 3) { - const int idx0 = nextIndex[0]; - const int idx1 = nextIndex[1]; - const int idx2 = nextIndex[2]; - const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; - const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; - const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; - const int kode0 = xv0->outcode; - const int kode1 = xv1->outcode; - const int kode2 = xv2->outcode; - - if (!(kode0 & kode1 & kode2)) { - if (int orflags = kode0 | kode1 | kode2) { - VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); - - if (src) { - VDTriBltTransformedVertex *src0 = *src++; - - // fan out triangles - while(src[1]) { - FillTriGrad(pxPlane, src0, src[0], src[1]); - ++src; - } - } - } else { - FillTriGrad(pxPlane, xv0, xv1, xv2); - } - } - - nextIndex += 3; - indicesLeft -= 3; - } - } - - return true; -} - -bool VDPixmapTriBlt(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, - const VDTriBltVertex *pVertices, int nVertices, - const int *pIndices, int nIndices, - VDTriBltFilterMode filterMode, - float mipMapLODBias, - const float pTransform[16]) -{ - if (dst.format != nsVDPixmap::kPixFormat_XRGB8888) - return false; - - static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; - vdfastvector xverts(nVertices); - - if (!pTransform) - pTransform = xf_ident; - - TransformVerts(xverts.data(), pVertices, nVertices, pTransform); - - const VDTriBltTransformedVertex *xsrc = xverts.data(); - - VDTriClipWorkspace clipws; - - while(nIndices >= 3) { - const int idx0 = pIndices[0]; - const int idx1 = pIndices[1]; - const int idx2 = pIndices[2]; - const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; - const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; - const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; - const int kode0 = xv0->outcode; - const int kode1 = xv1->outcode; - const int kode2 = xv2->outcode; - - if (!(kode0 & kode1 & kode2)) { - if (int orflags = kode0 | kode1 | kode2) { - VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); - - if (src) { - VDTriBltTransformedVertex *src0 = *src++; - - // fan out triangles - while(src[1]) { - RenderTri(dst, pSources, nMipmaps, src0, src[0], src[1], filterMode, mipMapLODBias); - ++src; - } - } - } else - RenderTri(dst, pSources, nMipmaps, xv0, xv1, xv2, filterMode, mipMapLODBias); - } - - pIndices += 3; - nIndices -= 3; - } - - return true; -} - -/////////////////////////////////////////////////////////////////////////// - -void VDPixmapSetTextureBorders(VDPixmap& px, bool wrap) { - const int w = px.w; - const int h = px.h; - - VDPixmapBlt(px, 0, 1, px, wrap ? w-2 : 1, 1, 1, h-2); - VDPixmapBlt(px, w-1, 1, px, wrap ? 1 : w-2, 1, 1, h-2); - - VDPixmapBlt(px, 0, 0, px, 0, wrap ? h-2 : 1, w, 1); - VDPixmapBlt(px, 0, h-1, px, 0, wrap ? 1 : h-2, w, 1); -} - -void VDPixmapSetTextureBordersCubic(VDPixmap& px) { - const int w = px.w; - const int h = px.h; - - VDPixmapBlt(px, 0, 1, px, 2, 1, 1, h-2); - VDPixmapBlt(px, 1, 1, px, 2, 1, 1, h-2); - VDPixmapBlt(px, w-2, 1, px, w-3, 1, 1, h-2); - VDPixmapBlt(px, w-1, 1, px, w-3, 1, 1, h-2); - - VDPixmapBlt(px, 0, 0, px, 0, 2, w, 1); - VDPixmapBlt(px, 0, 1, px, 0, 2, w, 1); - VDPixmapBlt(px, 0, h-2, px, 0, h-3, w, 1); - VDPixmapBlt(px, 0, h-1, px, 0, h-3, w, 1); -} - -/////////////////////////////////////////////////////////////////////////// - -VDPixmapTextureMipmapChain::VDPixmapTextureMipmapChain(const VDPixmap& src, bool wrap, bool cubic, int maxlevels) { - int w = src.w; - int h = src.h; - int mipcount = 0; - - while((w>1 || h>1) && maxlevels--) { - ++mipcount; - w >>= 1; - h >>= 1; - } - - mBuffers.resize(mipcount); - mMipMaps.resize(mipcount); - - vdautoptr r(VDCreatePixmapResampler()); - r->SetFilters(IVDPixmapResampler::kFilterLinear, IVDPixmapResampler::kFilterLinear, false); - - float fw = (float)src.w; - float fh = (float)src.h; - for(int mip=0; mipInit(rdst, curmip.w, curmip.h, curmip.format, rsrc, prevmip.w, prevmip.h, prevmip.format); - r->Process(curmip, prevmip); - } - } else { - mBuffers[mip].init(mipw+2, miph+2, nsVDPixmap::kPixFormat_XRGB8888); - - if (!mip) { - VDPixmapBlt(mBuffers[0], 1, 1, src, 0, 0, src.w, src.h); - VDPixmapSetTextureBorders(mBuffers[0], wrap); - } else { - const VDPixmap& curmip = mBuffers[mip]; - const VDPixmap& prevmip = mBuffers[mip-1]; - - vdrect32f rdst( 0.0f, 0.0f, (float)curmip.w , (float)curmip.h ); - vdrect32f rsrc(-1.0f, -1.0f, 2.0f*(float)curmip.w - 1.0f, 2.0f*(float)curmip.h - 1.0f); - r->Init(rdst, curmip.w, curmip.h, curmip.format, rsrc, prevmip.w, prevmip.h, prevmip.format); - r->Process(curmip, prevmip); - } - } - - fw *= 0.5f; - fh *= 0.5f; - } -} - +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + uint32 lerp_RGB888(sint32 a, sint32 b, sint32 x) { + sint32 a_rb = a & 0xff00ff; + sint32 a_g = a & 0x00ff00; + sint32 b_rb = b & 0xff00ff; + sint32 b_g = b & 0x00ff00; + + const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; + + return top_rb + top_g; + } + + uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) { + sint32 a_rb = a & 0xff00ff; + sint32 a_g = a & 0x00ff00; + sint32 b_rb = b & 0xff00ff; + sint32 b_g = b & 0x00ff00; + sint32 c_rb = c & 0xff00ff; + sint32 c_g = c & 0x00ff00; + sint32 d_rb = d & 0xff00ff; + sint32 d_g = d & 0x00ff00; + + const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 top_g = (a_g + (((b_g - a_g )*x + 0x00008000) >> 8)) & 0x00ff00; + const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff; + const uint32 bot_g = (c_g + (((d_g - c_g )*x + 0x00008000) >> 8)) & 0x00ff00; + + const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff; + const uint32 final_g = (top_g + (((bot_g - top_g )*y) >> 8)) & 0x00ff00; + + return final_rb + final_g; + } + + uint32 bicubic_RGB888(const uint32 *src0, const uint32 *src1, const uint32 *src2, const uint32 *src3, sint32 x, sint32 y) { + const uint32 p00 = src0[0]; + const uint32 p01 = src0[1]; + const uint32 p02 = src0[2]; + const uint32 p03 = src0[3]; + const uint32 p10 = src1[0]; + const uint32 p11 = src1[1]; + const uint32 p12 = src1[2]; + const uint32 p13 = src1[3]; + const uint32 p20 = src2[0]; + const uint32 p21 = src2[1]; + const uint32 p22 = src2[2]; + const uint32 p23 = src2[3]; + const uint32 p30 = src3[0]; + const uint32 p31 = src3[1]; + const uint32 p32 = src3[2]; + const uint32 p33 = src3[3]; + + const sint32 *htab = kVDCubicInterpTableFX14_075[x]; + const sint32 *vtab = kVDCubicInterpTableFX14_075[y]; + + const int ch0 = htab[0]; + const int ch1 = htab[1]; + const int ch2 = htab[2]; + const int ch3 = htab[3]; + const int cv0 = vtab[0]; + const int cv1 = vtab[1]; + const int cv2 = vtab[2]; + const int cv3 = vtab[3]; + + int r0 = ((int)((p00>>16)&0xff) * ch0 + (int)((p01>>16)&0xff) * ch1 + (int)((p02>>16)&0xff) * ch2 + (int)((p03>>16)&0xff) * ch3 + 128) >> 8; + int g0 = ((int)((p00>> 8)&0xff) * ch0 + (int)((p01>> 8)&0xff) * ch1 + (int)((p02>> 8)&0xff) * ch2 + (int)((p03>> 8)&0xff) * ch3 + 128) >> 8; + int b0 = ((int)((p00 )&0xff) * ch0 + (int)((p01 )&0xff) * ch1 + (int)((p02 )&0xff) * ch2 + (int)((p03 )&0xff) * ch3 + 128) >> 8; + int r1 = ((int)((p10>>16)&0xff) * ch0 + (int)((p11>>16)&0xff) * ch1 + (int)((p12>>16)&0xff) * ch2 + (int)((p13>>16)&0xff) * ch3 + 128) >> 8; + int g1 = ((int)((p10>> 8)&0xff) * ch0 + (int)((p11>> 8)&0xff) * ch1 + (int)((p12>> 8)&0xff) * ch2 + (int)((p13>> 8)&0xff) * ch3 + 128) >> 8; + int b1 = ((int)((p10 )&0xff) * ch0 + (int)((p11 )&0xff) * ch1 + (int)((p12 )&0xff) * ch2 + (int)((p13 )&0xff) * ch3 + 128) >> 8; + int r2 = ((int)((p20>>16)&0xff) * ch0 + (int)((p21>>16)&0xff) * ch1 + (int)((p22>>16)&0xff) * ch2 + (int)((p23>>16)&0xff) * ch3 + 128) >> 8; + int g2 = ((int)((p20>> 8)&0xff) * ch0 + (int)((p21>> 8)&0xff) * ch1 + (int)((p22>> 8)&0xff) * ch2 + (int)((p23>> 8)&0xff) * ch3 + 128) >> 8; + int b2 = ((int)((p20 )&0xff) * ch0 + (int)((p21 )&0xff) * ch1 + (int)((p22 )&0xff) * ch2 + (int)((p23 )&0xff) * ch3 + 128) >> 8; + int r3 = ((int)((p30>>16)&0xff) * ch0 + (int)((p31>>16)&0xff) * ch1 + (int)((p32>>16)&0xff) * ch2 + (int)((p33>>16)&0xff) * ch3 + 128) >> 8; + int g3 = ((int)((p30>> 8)&0xff) * ch0 + (int)((p31>> 8)&0xff) * ch1 + (int)((p32>> 8)&0xff) * ch2 + (int)((p33>> 8)&0xff) * ch3 + 128) >> 8; + int b3 = ((int)((p30 )&0xff) * ch0 + (int)((p31 )&0xff) * ch1 + (int)((p32 )&0xff) * ch2 + (int)((p33 )&0xff) * ch3 + 128) >> 8; + + int r = (r0 * cv0 + r1 * cv1 + r2 * cv2 + r3 * cv3 + (1<<19)) >> 20; + int g = (g0 * cv0 + g1 * cv1 + g2 * cv2 + g3 * cv3 + (1<<19)) >> 20; + int b = (b0 * cv0 + b1 * cv1 + b2 * cv2 + b3 * cv3 + (1<<19)) >> 20; + + if (r<0) r=0; else if (r>255) r=255; + if (g<0) g=0; else if (g>255) g=255; + if (b<0) b=0; else if (b>255) b=255; + + return (r<<16) + (g<<8) + b; + } +} + +namespace { + enum { + kTop = 1, + kBottom = 2, + kLeft = 4, + kRight = 8, + kNear = 16, + kFar = 32 + }; + + struct VDTriBltMipInfo { + const uint32 *mip; + ptrdiff_t pitch; + uint32 uvmul, _pad; + }; + + struct VDTriBltInfo { + VDTriBltMipInfo mips[16]; + uint32 *dst; + const uint32 *src; + sint32 width; + const int *cubictab; + }; + + struct VDTriBltGenInfo { + float u; + float v; + float rhw; + float dudx; + float dvdx; + float drhwdx; + }; + + typedef void (*VDTriBltSpanFunction)(const VDTriBltInfo *); + typedef void (*VDTriBltGenFunction)(const VDTriBltGenInfo *); + + void vd_triblt_span_point(const VDTriBltInfo *pInfo) { + sint32 w = -pInfo->width; + uint32 *dst = pInfo->dst + pInfo->width; + const uint32 *src = pInfo->src; + const uint32 *texture = pInfo->mips[0].mip; + const ptrdiff_t texpitch = pInfo->mips[0].pitch; + + do { + dst[w] = vdptroffset(texture, texpitch * src[1])[src[0]]; + src += 2; + } while(++w); + } + + void vd_triblt_span_bilinear(const VDTriBltInfo *pInfo) { + sint32 w = -pInfo->width; + uint32 *dst = pInfo->dst + pInfo->width; + const uint32 *src = pInfo->src; + const uint32 *texture = pInfo->mips[0].mip; + const ptrdiff_t texpitch = pInfo->mips[0].pitch; + + do { + const sint32 u = src[0]; + const sint32 v = src[1]; + src += 2; + const uint32 *src1 = vdptroffset(texture, texpitch * (v>>8)) + (u>>8); + const uint32 *src2 = vdptroffset(src1, texpitch); + + dst[w] = bilerp_RGB888(src1[0], src1[1], src2[0], src2[1], u&255, v&255); + } while(++w); + } + + void vd_triblt_span_trilinear(const VDTriBltInfo *pInfo) { + sint32 w = -pInfo->width; + uint32 *dst = pInfo->dst + pInfo->width; + const uint32 *src = pInfo->src; + + do { + sint32 u = src[0]; + sint32 v = src[1]; + const sint32 lambda = src[2]; + src += 3; + + const sint32 lod = lambda >> 8; + + const uint32 *texture1 = pInfo->mips[lod].mip; + const ptrdiff_t texpitch1 = pInfo->mips[lod].pitch; + const uint32 *texture2 = pInfo->mips[lod+1].mip; + const ptrdiff_t texpitch2 = pInfo->mips[lod+1].pitch; + + u >>= lod; + v >>= lod; + + u += 128; + v += 128; + + const uint32 *src1 = vdptroffset(texture1, texpitch1 * (v>>8)) + (u>>8); + const uint32 *src2 = vdptroffset(src1, texpitch1); + const uint32 p1 = bilerp_RGB888(src1[0], src1[1], src2[0], src2[1], u&255, v&255); + + u += 128; + v += 128; + + const uint32 *src3 = vdptroffset(texture2, texpitch2 * (v>>9)) + (u>>9); + const uint32 *src4 = vdptroffset(src3, texpitch2); + const uint32 p2 = bilerp_RGB888(src3[0], src3[1], src4[0], src4[1], (u>>1)&255, (v>>1)&255); + + dst[w] = lerp_RGB888(p1, p2, lambda & 255); + } while(++w); + } + + void vd_triblt_span_bicubic_mip_linear(const VDTriBltInfo *pInfo) { + sint32 w = -pInfo->width; + uint32 *dst = pInfo->dst + pInfo->width; + const uint32 *src = pInfo->src; + + do { + sint32 u = src[0]; + sint32 v = src[1]; + const sint32 lambda = src[2]; + src += 3; + + const sint32 lod = lambda >> 8; + + const uint32 *texture1 = pInfo->mips[lod].mip; + const ptrdiff_t texpitch1 = pInfo->mips[lod].pitch; + const uint32 *texture2 = pInfo->mips[lod+1].mip; + const ptrdiff_t texpitch2 = pInfo->mips[lod+1].pitch; + + u >>= lod; + v >>= lod; + + u += 128; + v += 128; + + const uint32 *src1 = vdptroffset(texture1, texpitch1 * (v>>8)) + (u>>8); + const uint32 *src2 = vdptroffset(src1, texpitch1); + const uint32 *src3 = vdptroffset(src2, texpitch1); + const uint32 *src4 = vdptroffset(src3, texpitch1); + const uint32 p1 = bicubic_RGB888(src1, src2, src3, src4, u&255, v&255); + + u += 128; + v += 128; + + const uint32 *src5 = vdptroffset(texture2, texpitch2 * (v>>9)) + (u>>9); + const uint32 *src6 = vdptroffset(src5, texpitch2); + const uint32 *src7 = vdptroffset(src6, texpitch2); + const uint32 *src8 = vdptroffset(src7, texpitch2); + const uint32 p2 = bicubic_RGB888(src5, src6, src7, src8, (u>>1)&255, (v>>1)&255); + + dst[w] = lerp_RGB888(p1, p2, lambda & 255); + } while(++w); + } + +#ifdef _M_IX86 + extern "C" void vdasm_triblt_span_bilinear_mmx(const VDTriBltInfo *pInfo); + extern "C" void vdasm_triblt_span_trilinear_mmx(const VDTriBltInfo *pInfo); + extern "C" void vdasm_triblt_span_bicubic_mip_linear_mmx(const VDTriBltInfo *pInfo); + extern "C" void vdasm_triblt_span_bicubic_mip_linear_sse2(const VDTriBltInfo *pInfo); + extern "C" void vdasm_triblt_span_point(const VDTriBltInfo *pInfo); +#endif + + struct VDTriBltTransformedVertex { + float x, y, z; + union { + float w; + float rhw; + }; + float r, g, b, a; + float u, v; + int outcode; + + void interp(const VDTriBltTransformedVertex *v1, const VDTriBltTransformedVertex *v2, float alpha) { + x = v1->x + alpha * (v2->x - v1->x); + y = v1->y + alpha * (v2->y - v1->y); + z = v1->z + alpha * (v2->z - v1->z); + w = v1->w + alpha * (v2->w - v1->w); + + r = v1->r + alpha * (v2->r - v1->r); + g = v1->g + alpha * (v2->g - v1->g); + b = v1->b + alpha * (v2->b - v1->b); + a = v1->a + alpha * (v2->a - v1->a); + + u = v1->u + alpha * (v2->u - v1->u); + v = v1->v + alpha * (v2->v - v1->v); + + outcode = (x < -w ? kLeft : 0) + + (x > +w ? kRight : 0) + + (y < -w ? kTop : 0) + + (y > +w ? kBottom : 0) + + (z < -w ? kNear : 0) + + (z > +w ? kFar : 0); + } + }; + + void TransformVerts(VDTriBltTransformedVertex *dst, const VDTriBltVertex *src, int nVerts, const float xform[16]) { + const float xflocal[16]={ + xform[ 0], xform[ 1], xform[ 2], xform[ 3], + xform[ 4], xform[ 5], xform[ 6], xform[ 7], + xform[ 8], xform[ 9], xform[10], xform[11], + xform[12], xform[13], xform[14], xform[15], + }; + + if (nVerts <= 0) + return; + + do { + const float x0 = src->x; + const float y0 = src->y; + const float z0 = src->z; + + const float w = x0*xflocal[12] + y0*xflocal[13] + z0*xflocal[14] + xflocal[15]; + const float x = x0*xflocal[ 0] + y0*xflocal[ 1] + z0*xflocal[ 2] + xflocal[ 3]; + const float y = x0*xflocal[ 4] + y0*xflocal[ 5] + z0*xflocal[ 6] + xflocal[ 7]; + const float z = x0*xflocal[ 8] + y0*xflocal[ 9] + z0*xflocal[10] + xflocal[11]; + + int outcode = 0; + + if (x < -w) outcode += kLeft; + if (x > w) outcode += kRight; + if (y < -w) outcode += kTop; + if (y > w) outcode += kBottom; + if (z < -w) outcode += kNear; + if (z > w) outcode += kFar; + + dst->x = x; + dst->y = y; + dst->z = z; + dst->w = w; + dst->u = src->u; + dst->v = src->v; + dst->r = 1.0f; + dst->g = 1.0f; + dst->b = 1.0f; + dst->a = 1.0f; + dst->outcode = outcode; + + ++src; + ++dst; + } while(--nVerts); + } + + void TransformVerts(VDTriBltTransformedVertex *dst, const VDTriColorVertex *src, int nVerts, const float xform[16]) { + const float xflocal[16]={ + xform[ 0], xform[ 1], xform[ 2], xform[ 3], + xform[ 4], xform[ 5], xform[ 6], xform[ 7], + xform[ 8], xform[ 9], xform[10], xform[11], + xform[12], xform[13], xform[14], xform[15], + }; + + if (nVerts <= 0) + return; + + do { + const float x0 = src->x; + const float y0 = src->y; + const float z0 = src->z; + + const float w = x0*xflocal[12] + y0*xflocal[13] + z0*xflocal[14] + xflocal[15]; + const float x = x0*xflocal[ 0] + y0*xflocal[ 1] + z0*xflocal[ 2] + xflocal[ 3]; + const float y = x0*xflocal[ 4] + y0*xflocal[ 5] + z0*xflocal[ 6] + xflocal[ 7]; + const float z = x0*xflocal[ 8] + y0*xflocal[ 9] + z0*xflocal[10] + xflocal[11]; + + int outcode = 0; + + if (x < -w) outcode += kLeft; + if (x > w) outcode += kRight; + if (y < -w) outcode += kTop; + if (y > w) outcode += kBottom; + if (z < -w) outcode += kNear; + if (z > w) outcode += kFar; + + dst->x = x; + dst->y = y; + dst->z = z; + dst->w = w; + dst->u = 0.0f; + dst->v = 0.0f; + dst->r = src->r; + dst->g = src->g; + dst->b = src->b; + dst->a = src->a; + dst->outcode = outcode; + + ++src; + ++dst; + } while(--nVerts); + } + + struct VDTriangleSetupInfo { + const VDTriBltTransformedVertex *pt, *pr, *pl; + VDTriBltTransformedVertex tmp0, tmp1, tmp2; + }; + + void SetupTri( + VDTriangleSetupInfo& setup, + VDPixmap& dst, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2, + const VDTriBltFilterMode *filterMode + ) + { + setup.tmp0 = *vx0; + setup.tmp1 = *vx1; + setup.tmp2 = *vx2; + + // adjust UVs for filter mode + if (filterMode) { + switch(*filterMode) { + case kTriBltFilterBilinear: + setup.tmp0.u += 0.5f; + setup.tmp0.v += 0.5f; + setup.tmp1.u += 0.5f; + setup.tmp1.v += 0.5f; + setup.tmp2.u += 0.5f; + setup.tmp2.v += 0.5f; + case kTriBltFilterTrilinear: + case kTriBltFilterBicubicMipLinear: + setup.tmp0.u *= 256.0f; + setup.tmp0.v *= 256.0f; + setup.tmp1.u *= 256.0f; + setup.tmp1.v *= 256.0f; + setup.tmp2.u *= 256.0f; + setup.tmp2.v *= 256.0f; + break; + case kTriBltFilterPoint: + setup.tmp0.u += 1.0f; + setup.tmp0.v += 1.0f; + setup.tmp1.u += 1.0f; + setup.tmp1.v += 1.0f; + setup.tmp2.u += 1.0f; + setup.tmp2.v += 1.0f; + break; + } + } + + // do perspective divide and NDC space conversion + const float xscale = dst.w * 0.5f; + const float yscale = dst.h * 0.5f; + + setup.tmp0.rhw = 1.0f / setup.tmp0.w; + setup.tmp0.x = (1.0f+setup.tmp0.x*setup.tmp0.rhw)*xscale; + setup.tmp0.y = (1.0f+setup.tmp0.y*setup.tmp0.rhw)*yscale; + setup.tmp0.u *= setup.tmp0.rhw; + setup.tmp0.v *= setup.tmp0.rhw; + setup.tmp0.r *= setup.tmp0.rhw; + setup.tmp0.g *= setup.tmp0.rhw; + setup.tmp0.b *= setup.tmp0.rhw; + setup.tmp0.a *= setup.tmp0.rhw; + setup.tmp1.rhw = 1.0f / setup.tmp1.w; + setup.tmp1.x = (1.0f+setup.tmp1.x*setup.tmp1.rhw)*xscale; + setup.tmp1.y = (1.0f+setup.tmp1.y*setup.tmp1.rhw)*yscale; + setup.tmp1.u *= setup.tmp1.rhw; + setup.tmp1.v *= setup.tmp1.rhw; + setup.tmp1.r *= setup.tmp1.rhw; + setup.tmp1.g *= setup.tmp1.rhw; + setup.tmp1.b *= setup.tmp1.rhw; + setup.tmp1.a *= setup.tmp1.rhw; + setup.tmp2.rhw = 1.0f / setup.tmp2.w; + setup.tmp2.x = (1.0f+setup.tmp2.x*setup.tmp2.rhw)*xscale; + setup.tmp2.y = (1.0f+setup.tmp2.y*setup.tmp2.rhw)*yscale; + setup.tmp2.u *= setup.tmp2.rhw; + setup.tmp2.v *= setup.tmp2.rhw; + setup.tmp2.r *= setup.tmp2.rhw; + setup.tmp2.g *= setup.tmp2.rhw; + setup.tmp2.b *= setup.tmp2.rhw; + setup.tmp2.a *= setup.tmp2.rhw; + + // verify clipping + VDASSERT(setup.tmp0.x >= 0 && setup.tmp0.x <= dst.w); + VDASSERT(setup.tmp1.x >= 0 && setup.tmp1.x <= dst.w); + VDASSERT(setup.tmp2.x >= 0 && setup.tmp2.x <= dst.w); + VDASSERT(setup.tmp0.y >= 0 && setup.tmp0.y <= dst.h); + VDASSERT(setup.tmp1.y >= 0 && setup.tmp1.y <= dst.h); + VDASSERT(setup.tmp2.y >= 0 && setup.tmp2.y <= dst.h); + + vx0 = &setup.tmp0; + vx1 = &setup.tmp1; + vx2 = &setup.tmp2; + + const VDTriBltTransformedVertex *pt, *pl, *pr; + + // sort points + if (vx0->y < vx1->y) // 1 < 2 + if (vx0->y < vx2->y) { // 1 < 2,3 + pt = vx0; + pr = vx1; + pl = vx2; + } else { // 3 < 1 < 2 + pt = vx2; + pr = vx0; + pl = vx1; + } + else // 2 < 1 + if (vx1->y < vx2->y) { // 2 < 1,3 + pt = vx1; + pr = vx2; + pl = vx0; + } else { // 3 < 2 < 1 + pt = vx2; + pr = vx0; + pl = vx1; + } + + setup.pl = pl; + setup.pt = pt; + setup.pr = pr; + } + + void RenderTri(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2, + VDTriBltFilterMode filterMode, + float mipMapLODBias) + { + VDTriangleSetupInfo setup; + + SetupTri(setup, dst, vx0, vx1, vx2, &filterMode); + + const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; + + const float x10 = pl->x - pt->x; + const float x20 = pr->x - pt->x; + const float y10 = pl->y - pt->y; + const float y20 = pr->y - pt->y; + const float A = x20*y10 - x10*y20; + + if (A <= 0.f) + return; + + float invA = 0.f; + if (A >= 1e-5f) + invA = 1.0f / A; + + float x10_A = x10 * invA; + float x20_A = x20 * invA; + float y10_A = y10 * invA; + float y20_A = y20 * invA; + + float u10 = pl->u - pt->u; + float u20 = pr->u - pt->u; + float v10 = pl->v - pt->v; + float v20 = pr->v - pt->v; + float rhw10 = pl->rhw - pt->rhw; + float rhw20 = pr->rhw - pt->rhw; + + float dudx = u20*y10_A - u10*y20_A; + float dudy = u10*x20_A - u20*x10_A; + float dvdx = v20*y10_A - v10*y20_A; + float dvdy = v10*x20_A - v20*x10_A; + float drhwdx = rhw20*y10_A - rhw10*y20_A; + float drhwdy = rhw10*x20_A - rhw20*x10_A; + + // Compute edge walking parameters + + float dxl1=0, dxr1=0, dul1=0, dvl1=0, drhwl1=0; + float dxl2=0, dxr2=0, dul2=0, dvl2=0, drhwl2=0; + + // Compute left-edge interpolation parameters for first half. + + if (pl->y != pt->y) { + dxl1 = (pl->x - pt->x) / (pl->y - pt->y); + + dul1 = dudy + dxl1 * dudx; + dvl1 = dvdy + dxl1 * dvdx; + drhwl1 = drhwdy + dxl1 * drhwdx; + } + + // Compute right-edge interpolation parameters for first half. + + if (pr->y != pt->y) { + dxr1 = (pr->x - pt->x) / (pr->y - pt->y); + } + + // Compute third-edge interpolation parameters. + + if (pr->y != pl->y) { + dxl2 = (pr->x - pl->x) / (pr->y - pl->y); + + dul2 = dudy + dxl2 * dudx; + dvl2 = dvdy + dxl2 * dvdx; + drhwl2 = drhwdy + dxl2 * drhwdx; + + dxr2 = dxl2; + } + + // Initialize parameters for first half. + // + // We place pixel centers at (x+0.5, y+0.5). + + double xl, xr, ul, vl, rhwl, yf; + int y, y1, y2; + + // y_start < y+0.5 to include pixel y. + + y = (int)floor(pt->y + 0.5); + yf = (y+0.5) - pt->y; + + xl = pt->x + dxl1 * yf; + xr = pt->x + dxr1 * yf; + ul = pt->u + dul1 * yf; + vl = pt->v + dvl1 * yf; + rhwl = pt->rhw + drhwl1 * yf; + + // Initialize parameters for second half. + + double xl2, xr2, ul2, vl2, rhwl2; + + if (pl->y > pr->y) { // Left edge is long side + dxl2 = dxl1; + dul2 = dul1; + dvl2 = dvl1; + drhwl2 = drhwl1; + + y1 = (int)floor(pr->y + 0.5); + y2 = (int)floor(pl->y + 0.5); + + yf = (y1+0.5) - pr->y; + + // Step left edge. + + xl2 = xl + dxl1 * (y1 - y); + ul2 = ul + dul1 * (y1 - y); + vl2 = vl + dvl1 * (y1 - y); + rhwl2 = rhwl + drhwl1 * (y1 - y); + + // Prestep right edge. + + xr2 = pr->x + dxr2 * yf; + } else { // Right edge is long side + dxr2 = dxr1; + + y1 = (int)floor(pl->y + 0.5); + y2 = (int)floor(pr->y + 0.5); + + yf = (y1+0.5) - pl->y; + + // Prestep left edge. + + xl2 = pl->x + dxl2 * yf; + ul2 = pl->u + dul2 * yf; + vl2 = pl->v + dvl2 * yf; + rhwl2 = pl->rhw + drhwl2 * yf; + + // Step right edge. + + xr2 = xr + dxr1 * (y1 - y); + } + + // rasterize + const ptrdiff_t dstpitch = dst.pitch; + uint32 *dstp = (uint32 *)((char *)dst.data + dstpitch * y); + + VDTriBltInfo texinfo; + VDTriBltSpanFunction drawSpan; + uint32 cpuflags = CPUGetEnabledExtensions(); + + bool triBlt16 = false; + + switch(filterMode) { + case kTriBltFilterBicubicMipLinear: +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_SSE2) { + drawSpan = vdasm_triblt_span_bicubic_mip_linear_sse2; + triBlt16 = true; + } else if (cpuflags & CPUF_SUPPORTS_MMX) { + drawSpan = vdasm_triblt_span_bicubic_mip_linear_mmx; + triBlt16 = true; + } else +#endif + drawSpan = vd_triblt_span_bicubic_mip_linear; + break; + case kTriBltFilterTrilinear: +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_MMX) { + drawSpan = vdasm_triblt_span_trilinear_mmx; + triBlt16 = true; + } else +#endif + drawSpan = vd_triblt_span_trilinear; + break; + case kTriBltFilterBilinear: +#ifdef _M_IX86 + if (cpuflags & CPUF_SUPPORTS_MMX) { + drawSpan = vdasm_triblt_span_bilinear_mmx; + triBlt16 = true; + } else +#endif + drawSpan = vd_triblt_span_bilinear; + break; + case kTriBltFilterPoint: + drawSpan = vd_triblt_span_point; + break; + } + + float rhobase = sqrtf(std::max(dudx*dudx + dvdx*dvdx, dudy*dudy + dvdy*dvdy) * (1.0f / 65536.0f)) * powf(2.0f, mipMapLODBias); + + if (triBlt16) { + ul *= 256.0f; + vl *= 256.0f; + ul2 *= 256.0f; + vl2 *= 256.0f; + dul1 *= 256.0f; + dvl1 *= 256.0f; + dul2 *= 256.0f; + dvl2 *= 256.0f; + dudx *= 256.0f; + dvdx *= 256.0f; + dudy *= 256.0f; + dvdy *= 256.0f; + } + + int minx1 = (int)floor(std::min(std::min(pl->x, pr->x), pt->x) + 0.5); + int maxx2 = (int)floor(std::max(std::max(pl->x, pr->x), pt->x) + 0.5); + + uint32 *const spanptr = new uint32[3 * (maxx2 - minx1)]; + + while(y < y2) { + if (y == y1) { + xl = xl2; + xr = xr2; + ul = ul2; + vl = vl2; + rhwl = rhwl2; + dxl1 = dxl2; + dxr1 = dxr2; + dul1 = dul2; + dvl1 = dvl2; + drhwl1 = drhwl2; + } + + int x1, x2; + double xf; + double u, v, rhw; + + // x_left must be less than (x+0.5) to include pixel x. + + x1 = (int)floor(xl + 0.5); + x2 = (int)floor(xr + 0.5); + xf = (x1+0.5) - xl; + + u = ul + xf * dudx; + v = vl + xf * dvdx; + rhw = rhwl + xf * drhwdx; + + int x = x1; + uint32 *spanp = spanptr; + + float w = 1.0f / (float)rhw; + + if (x < x2) { + if (filterMode >= kTriBltFilterTrilinear) { + do { + int utexel = VDRoundToIntFastFullRange(u * w); + int vtexel = VDRoundToIntFastFullRange(v * w); + union{ float f; sint32 i; } rho = {rhobase * w}; + + int lambda = ((rho.i - 0x3F800000) >> (23-8)); + if (lambda < 0) + lambda = 0; + if (lambda >= (nMipmaps<<8)-256) + lambda = (nMipmaps<<8)-257; + + spanp[0] = utexel; + spanp[1] = vtexel; + spanp[2] = lambda; + spanp += 3; + + u += dudx; + v += dvdx; + rhw += drhwdx; + + w *= (2.0f - w*(float)rhw); + } while(++x < x2); + } else { + do { + int utexel = VDFloorToInt(u * w); + int vtexel = VDFloorToInt(v * w); + + spanp[0] = utexel; + spanp[1] = vtexel; + spanp += 2; + + u += dudx; + v += dvdx; + rhw += drhwdx; + + w *= (2.0f - w*(float)rhw); + } while(++x < x2); + } + } + + for(int i=0; idata; + texinfo.mips[i].pitch = pSources[i]->pitch; + texinfo.mips[i].uvmul = (pSources[i]->pitch << 16) + 4; + } + texinfo.dst = dstp+x1; + texinfo.src = spanptr; + texinfo.width = x2-x1; + + if (texinfo.width>0) + drawSpan(&texinfo); + + dstp = vdptroffset(dstp, dstpitch); + xl += dxl1; + xr += dxr1; + ul += dul1; + vl += dvl1; + rhwl += drhwl1; + + ++y; + } + + delete[] spanptr; + } + + void FillTri(VDPixmap& dst, uint32 c, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2 + ) + { + + VDTriangleSetupInfo setup; + + SetupTri(setup, dst, vx0, vx1, vx2, NULL); + + const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; + + // Compute edge walking parameters + float dxl1=0, dxr1=0; + float dxl2=0, dxr2=0; + + float x_lt = pl->x - pt->x; + float x_rt = pr->x - pt->x; + float x_rl = pr->x - pl->x; + float y_lt = pl->y - pt->y; + float y_rt = pr->y - pt->y; + float y_rl = pr->y - pl->y; + + // reject backfaces + if (x_lt*y_rt >= x_rt*y_lt) + return; + + // Compute left-edge interpolation parameters for first half. + if (pl->y != pt->y) + dxl1 = x_lt / y_lt; + + // Compute right-edge interpolation parameters for first half. + if (pr->y != pt->y) + dxr1 = x_rt / y_rt; + + // Compute third-edge interpolation parameters. + if (pr->y != pl->y) { + dxl2 = x_rl / y_rl; + + dxr2 = dxl2; + } + + // Initialize parameters for first half. + // + // We place pixel centers at (x+0.5, y+0.5). + + double xl, xr, yf; + int y, y1, y2; + + // y_start < y+0.5 to include pixel y. + + y = (int)floor(pt->y + 0.5); + yf = (y+0.5) - pt->y; + + xl = pt->x + dxl1 * yf; + xr = pt->x + dxr1 * yf; + + // Initialize parameters for second half. + double xl2, xr2; + + if (pl->y > pr->y) { // Left edge is long side + dxl2 = dxl1; + + y1 = (int)floor(pr->y + 0.5); + y2 = (int)floor(pl->y + 0.5); + + yf = (y1+0.5) - pr->y; + + // Prestep right edge. + xr2 = pr->x + dxr2 * yf; + + // Step left edge. + xl2 = xl + dxl1 * (y1 - y); + } else { // Right edge is long side + dxr2 = dxr1; + + y1 = (int)floor(pl->y + 0.5); + y2 = (int)floor(pr->y + 0.5); + + yf = (y1+0.5) - pl->y; + + // Prestep left edge. + xl2 = pl->x + dxl2 * yf; + + // Step right edge. + xr2 = xr + dxr1 * (y1 - y); + } + + // rasterize + const ptrdiff_t dstpitch = dst.pitch; + uint32 *dstp = (uint32 *)((char *)dst.data + dstpitch * y); + + while(y < y2) { + if (y == y1) { + xl = xl2; + xr = xr2; + dxl1 = dxl2; + dxr1 = dxr2; + } + + int x1, x2; + double xf; + + // x_left must be less than (x+0.5) to include pixel x. + + x1 = (int)floor(xl + 0.5); + x2 = (int)floor(xr + 0.5); + xf = (x1+0.5) - xl; + + while(x1 < x2) + dstp[x1++] = c; + + dstp = vdptroffset(dstp, dstpitch); + xl += dxl1; + xr += dxr1; + ++y; + } + } + + void FillTriGrad(VDPixmap& dst, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2 + ) + { + + VDTriangleSetupInfo setup; + + SetupTri(setup, dst, vx0, vx1, vx2, NULL); + + const VDTriBltTransformedVertex *pt = setup.pt, *pl = setup.pl, *pr = setup.pr; + const float x10 = pl->x - pt->x; + const float x20 = pr->x - pt->x; + const float y10 = pl->y - pt->y; + const float y20 = pr->y - pt->y; + const float A = x20*y10 - x10*y20; + + if (A <= 0.f) + return; + + float invA = 0.f; + if (A >= 1e-5f) + invA = 1.0f / A; + + float x10_A = x10 * invA; + float x20_A = x20 * invA; + float y10_A = y10 * invA; + float y20_A = y20 * invA; + + float r10 = pl->r - pt->r; + float r20 = pr->r - pt->r; + float g10 = pl->g - pt->g; + float g20 = pr->g - pt->g; + float b10 = pl->b - pt->b; + float b20 = pr->b - pt->b; + float a10 = pl->a - pt->a; + float a20 = pr->a - pt->a; + float rhw10 = pl->rhw - pt->rhw; + float rhw20 = pr->rhw - pt->rhw; + + float drdx = r20*y10_A - r10*y20_A; + float drdy = r10*x20_A - r20*x10_A; + float dgdx = g20*y10_A - g10*y20_A; + float dgdy = g10*x20_A - g20*x10_A; + float dbdx = b20*y10_A - b10*y20_A; + float dbdy = b10*x20_A - b20*x10_A; + float dadx = a20*y10_A - a10*y20_A; + float dady = a10*x20_A - a20*x10_A; + float drhwdx = rhw20*y10_A - rhw10*y20_A; + float drhwdy = rhw10*x20_A - rhw20*x10_A; + + // Compute edge walking parameters + float dxl1=0; + float drl1=0; + float dgl1=0; + float dbl1=0; + float dal1=0; + float drhwl1=0; + float dxr1=0; + float dxl2=0; + float drl2=0; + float dgl2=0; + float dbl2=0; + float dal2=0; + float drhwl2=0; + float dxr2=0; + + float x_lt = pl->x - pt->x; + float x_rt = pr->x - pt->x; + float x_rl = pr->x - pl->x; + float y_lt = pl->y - pt->y; + float y_rt = pr->y - pt->y; + float y_rl = pr->y - pl->y; + + // Compute left-edge interpolation parameters for first half. + if (pl->y != pt->y) { + dxl1 = x_lt / y_lt; + drl1 = drdy + dxl1 * drdx; + dgl1 = dgdy + dxl1 * dgdx; + dbl1 = dbdy + dxl1 * dbdx; + dal1 = dady + dxl1 * dadx; + drhwl1 = drhwdy + dxl1 * drhwdx; + } + + // Compute right-edge interpolation parameters for first half. + if (pr->y != pt->y) + dxr1 = x_rt / y_rt; + + // Compute third-edge interpolation parameters. + if (pr->y != pl->y) { + dxl2 = x_rl / y_rl; + + drl2 = drdy + dxl2 * drdx; + dgl2 = dgdy + dxl2 * dgdx; + dbl2 = dbdy + dxl2 * dbdx; + dal2 = dady + dxl2 * dadx; + drhwl2 = drhwdy + dxl2 * drhwdx; + + dxr2 = dxl2; + } + + // Initialize parameters for first half. + // + // We place pixel centers at (x+0.5, y+0.5). + + double xl, xr, yf; + double rl, gl, bl, al, rhwl; + double rl2, gl2, bl2, al2, rhwl2; + int y, y1, y2; + + // y_start < y+0.5 to include pixel y. + + y = (int)floor(pt->y + 0.5); + yf = (y+0.5) - pt->y; + + xl = pt->x + dxl1 * yf; + xr = pt->x + dxr1 * yf; + rl = pt->r + drl1 * yf; + gl = pt->g + dgl1 * yf; + bl = pt->b + dbl1 * yf; + al = pt->a + dal1 * yf; + rhwl = pt->rhw + drhwl1 * yf; + + // Initialize parameters for second half. + double xl2, xr2; + + if (pl->y > pr->y) { // Left edge is long side + dxl2 = dxl1; + drl2 = drl1; + dgl2 = dgl1; + dbl2 = dbl1; + dal2 = dal1; + drhwl2 = drhwl1; + + y1 = (int)floor(pr->y + 0.5); + y2 = (int)floor(pl->y + 0.5); + + yf = (y1+0.5) - pr->y; + + // Step left edge. + xl2 = xl + dxl1 * (y1 - y); + rl2 = rl + drl1 * (y1 - y); + gl2 = gl + dgl1 * (y1 - y); + bl2 = bl + dbl1 * (y1 - y); + al2 = al + dal1 * (y1 - y); + rhwl2 = rhwl + drhwl1 * (y1 - y); + + // Prestep right edge. + xr2 = pr->x + dxr2 * yf; + } else { // Right edge is long side + dxr2 = dxr1; + + y1 = (int)floor(pl->y + 0.5); + y2 = (int)floor(pr->y + 0.5); + + yf = (y1+0.5) - pl->y; + + // Prestep left edge. + xl2 = pl->x + dxl2 * yf; + rl2 = pl->r + drl2 * yf; + gl2 = pl->g + dgl2 * yf; + bl2 = pl->b + dbl2 * yf; + al2 = pl->a + dal2 * yf; + rhwl2 = pl->rhw + drhwl2 * yf; + + // Step right edge. + xr2 = xr + dxr2 * (y1 - y); + } + + // rasterize + const ptrdiff_t dstpitch = dst.pitch; + char *dstp0 = (char *)dst.data + dstpitch * y; + + while(y < y2) { + if (y == y1) { + xl = xl2; + xr = xr2; + rl = rl2; + gl = gl2; + bl = bl2; + al = al2; + rhwl = rhwl2; + dxl1 = dxl2; + drl1 = drl2; + dgl1 = dgl2; + dbl1 = dbl2; + dal1 = dal2; + drhwl1 = drhwl2; + dxr1 = dxr2; + } + + int x1, x2; + double xf; + double r, g, b, a, rhw; + + // x_left must be less than (x+0.5) to include pixel x. + + x1 = (int)floor(xl + 0.5); + x2 = (int)floor(xr + 0.5); + xf = (x1+0.5) - xl; + + r = rl + xf * drdx; + g = gl + xf * dgdx; + b = bl + xf * dbdx; + a = al + xf * dadx; + rhw = rhwl + xf * drhwdx; + + float w = 1.0f / (float)rhw; + + if (x1 < x2) { + if (dst.format == nsVDPixmap::kPixFormat_XRGB8888) { + uint32 *dstp = (uint32 *)dstp0; + + do { + float sr = (float)(r * w); + float sg = (float)(g * w); + float sb = (float)(b * w); + float sa = (float)(a * w); + + uint8 ir = VDClampedRoundFixedToUint8Fast(sr); + uint8 ig = VDClampedRoundFixedToUint8Fast(sg); + uint8 ib = VDClampedRoundFixedToUint8Fast(sb); + uint8 ia = VDClampedRoundFixedToUint8Fast(sa); + + dstp[x1] = ((uint32)ia << 24) + ((uint32)ir << 16) + ((uint32)ig << 8) + ib; + + r += drdx; + g += dgdx; + b += dbdx; + a += dadx; + rhw += drhwdx; + + w *= (2.0f - w*(float)rhw); + } while(++x1 < x2); + } else { + uint8 *dstp = (uint8 *)dstp0; + + do { + float sg = (float)(g * w); + + uint8 ig = VDClampedRoundFixedToUint8Fast(sg); + + dstp[x1] = ig; + + g += dgdx; + rhw += drhwdx; + + w *= (2.0f - w*(float)rhw); + } while(++x1 < x2); + } + } + + dstp0 = vdptroffset(dstp0, dstpitch); + xl += dxl1; + rl += drl1; + gl += dgl1; + bl += dbl1; + al += dal1; + rhwl += drhwl1; + xr += dxr1; + ++y; + } + } + + struct VDTriClipWorkspace { + VDTriBltTransformedVertex *vxheapptr[2][19]; + VDTriBltTransformedVertex vxheap[21]; + }; + + VDTriBltTransformedVertex **VDClipTriangle(VDTriClipWorkspace& ws, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2, + int orflags) { + // Each line segment can intersect all six planes, meaning the maximum bound is + // 18 vertices. Add 3 for the original. + + VDTriBltTransformedVertex *vxheapnext; + VDTriBltTransformedVertex **vxlastheap = ws.vxheapptr[0], **vxnextheap = ws.vxheapptr[1]; + + ws.vxheap[0] = *vx0; + ws.vxheap[1] = *vx1; + ws.vxheap[2] = *vx2; + + vxlastheap[0] = &ws.vxheap[0]; + vxlastheap[1] = &ws.vxheap[1]; + vxlastheap[2] = &ws.vxheap[2]; + vxlastheap[3] = NULL; + + vxheapnext = ws.vxheap + 3; + + // Current Next Action + // ------- ---- ------ + // Unclipped Unclipped Copy vertex + // Unclipped Clipped Copy vertex and add intersection + // Clipped Unclipped Add intersection + // Clipped Clipped No action + +#define DOCLIP(cliptype, _sign_, cliparg) \ + if (orflags & k##cliptype) { \ + VDTriBltTransformedVertex **src = vxlastheap; \ + VDTriBltTransformedVertex **dst = vxnextheap; \ + \ + while(*src) { \ + VDTriBltTransformedVertex *cur = *src; \ + VDTriBltTransformedVertex *next = src[1]; \ + \ + if (!next) \ + next = vxlastheap[0]; \ + \ + if (!(cur->outcode & k##cliptype)) \ + *dst++ = cur; \ + \ + if ((cur->outcode ^ next->outcode) & k##cliptype) { \ + double alpha = (cur->w _sign_ cur->cliparg) / ((cur->w _sign_ cur->cliparg) - (next->w _sign_ next->cliparg)); \ + \ + if (alpha >= 0.0 && alpha <= 1.0) { \ + vxheapnext->interp(cur, next, (float)alpha); \ + vxheapnext->cliparg = -(_sign_ vxheapnext->w); \ + *dst++ = vxheapnext++; \ + } \ + } \ + ++src; \ + } \ + *dst = NULL; \ + if (dst < vxnextheap+3) return NULL; \ + src = vxlastheap; vxlastheap = vxnextheap; vxnextheap = src; \ + } + + + DOCLIP(Far, -, z); + DOCLIP(Near, +, z); + DOCLIP(Bottom, -, y); + DOCLIP(Top, +, y); + DOCLIP(Right, -, x); + DOCLIP(Left, +, x); + +#undef DOCLIP + + return vxlastheap; + } + + void RenderClippedTri(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, + const VDTriBltTransformedVertex *vx0, + const VDTriBltTransformedVertex *vx1, + const VDTriBltTransformedVertex *vx2, + VDTriBltFilterMode filterMode, + float mipMapLODBias, + int orflags) + { + + VDTriBltTransformedVertex *vxheapnext; + VDTriBltTransformedVertex vxheap[21]; + + VDTriBltTransformedVertex *vxheapptr[2][19]; + VDTriBltTransformedVertex **vxlastheap = vxheapptr[0], **vxnextheap = vxheapptr[1]; + + vxheap[0] = *vx0; + vxheap[1] = *vx1; + vxheap[2] = *vx2; + + vxlastheap[0] = &vxheap[0]; + vxlastheap[1] = &vxheap[1]; + vxlastheap[2] = &vxheap[2]; + vxlastheap[3] = NULL; + + vxheapnext = vxheap + 3; + + // Current Next Action + // ------- ---- ------ + // Unclipped Unclipped Copy vertex + // Unclipped Clipped Copy vertex and add intersection + // Clipped Unclipped Add intersection + // Clipped Clipped No action + +#define DOCLIP(cliptype, _sign_, cliparg) \ + if (orflags & k##cliptype) { \ + VDTriBltTransformedVertex **src = vxlastheap; \ + VDTriBltTransformedVertex **dst = vxnextheap; \ + \ + while(*src) { \ + VDTriBltTransformedVertex *cur = *src; \ + VDTriBltTransformedVertex *next = src[1]; \ + \ + if (!next) \ + next = vxlastheap[0]; \ + \ + if (!(cur->outcode & k##cliptype)) \ + *dst++ = cur; \ + \ + if ((cur->outcode ^ next->outcode) & k##cliptype) { \ + double alpha = (cur->w _sign_ cur->cliparg) / ((cur->w _sign_ cur->cliparg) - (next->w _sign_ next->cliparg)); \ + \ + if (alpha >= 0.0 && alpha <= 1.0) { \ + vxheapnext->interp(cur, next, (float)alpha); \ + vxheapnext->cliparg = -(_sign_ vxheapnext->w); \ + *dst++ = vxheapnext++; \ + } \ + } \ + ++src; \ + } \ + *dst = NULL; \ + if (dst < vxnextheap+3) return; \ + src = vxlastheap; vxlastheap = vxnextheap; vxnextheap = src; \ + } + + + DOCLIP(Far, -, z); + DOCLIP(Near, +, z); + DOCLIP(Bottom, -, y); + DOCLIP(Top, +, y); + DOCLIP(Right, -, x); + DOCLIP(Left, +, x); + +#undef DOCLIP + + VDTriBltTransformedVertex **src = vxlastheap+1; + + while(src[1]) { + RenderTri(dst, pSources, nMipmaps, vxlastheap[0], src[0], src[1], filterMode, mipMapLODBias); + ++src; + } + } + +} + +bool VDPixmapTriFill(VDPixmap& dst, const uint32 c, const VDTriBltVertex *pVertices, int nVertices, const int *pIndices, int nIndices, const float pTransform[16]) { + if (dst.format != nsVDPixmap::kPixFormat_XRGB8888) + return false; + + static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; + vdfastvector xverts(nVertices); + + if (!pTransform) + pTransform = xf_ident; + + TransformVerts(xverts.data(), pVertices, nVertices, pTransform); + + const VDTriBltTransformedVertex *xsrc = xverts.data(); + + VDTriClipWorkspace clipws; + + while(nIndices >= 3) { + const int idx0 = pIndices[0]; + const int idx1 = pIndices[1]; + const int idx2 = pIndices[2]; + const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; + const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; + const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; + const int kode0 = xv0->outcode; + const int kode1 = xv1->outcode; + const int kode2 = xv2->outcode; + + if (!(kode0 & kode1 & kode2)) { + if (int orflags = kode0 | kode1 | kode2) { + VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); + + if (src) { + VDTriBltTransformedVertex *src0 = *src++; + + // fan out triangles + while(src[1]) { + FillTri(dst, c, src0, src[0], src[1]); + ++src; + } + } + } else + FillTri(dst, c, xv0, xv1, xv2); + } + + pIndices += 3; + nIndices -= 3; + } + + return true; +} + +bool VDPixmapTriFill(VDPixmap& dst, const VDTriColorVertex *pVertices, int nVertices, const int *pIndices, int nIndices, const float pTransform[16], const float *chroma_yoffset) { + VDPixmap pxY; + VDPixmap pxCb; + VDPixmap pxCr; + bool ycbcr = false; + float ycbcr_xoffset = 0; + + switch(dst.format) { + case nsVDPixmap::kPixFormat_XRGB8888: + case nsVDPixmap::kPixFormat_Y8: + break; + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + pxY.format = nsVDPixmap::kPixFormat_Y8; + pxY.data = dst.data; + pxY.pitch = dst.pitch; + pxY.w = dst.w; + pxY.h = dst.h; + + pxCb.format = nsVDPixmap::kPixFormat_Y8; + pxCb.data = dst.data2; + pxCb.pitch = dst.pitch2; + pxCb.w = dst.w; + pxCb.h = dst.h; + + pxCr.format = nsVDPixmap::kPixFormat_Y8; + pxCr.data = dst.data3; + pxCr.pitch = dst.pitch3; + pxCr.w = dst.w; + pxCr.h = dst.h; + + switch(dst.format) { + case nsVDPixmap::kPixFormat_YUV410_Planar: + case nsVDPixmap::kPixFormat_YUV410_Planar_FR: + case nsVDPixmap::kPixFormat_YUV410_Planar_709: + case nsVDPixmap::kPixFormat_YUV410_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 2; + pxCr.h = pxCb.h = dst.h >> 2; + ycbcr_xoffset = 0.75f / (float)pxCr.w; + break; + + case nsVDPixmap::kPixFormat_YUV420_Planar: + case nsVDPixmap::kPixFormat_YUV420_Planar_FR: + case nsVDPixmap::kPixFormat_YUV420_Planar_709: + case nsVDPixmap::kPixFormat_YUV420_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 1; + pxCr.h = pxCb.h = dst.h >> 1; + ycbcr_xoffset = 0.5f / (float)pxCr.w; + break; + + case nsVDPixmap::kPixFormat_YUV422_Planar: + case nsVDPixmap::kPixFormat_YUV422_Planar_FR: + case nsVDPixmap::kPixFormat_YUV422_Planar_709: + case nsVDPixmap::kPixFormat_YUV422_Planar_709_FR: + pxCr.w = pxCb.w = dst.w >> 1; + ycbcr_xoffset = 0.5f / (float)pxCr.w; + break; + + case nsVDPixmap::kPixFormat_YUV444_Planar: + case nsVDPixmap::kPixFormat_YUV444_Planar_FR: + case nsVDPixmap::kPixFormat_YUV444_Planar_709: + case nsVDPixmap::kPixFormat_YUV444_Planar_709_FR: + pxCr.w = pxCb.w = dst.w; + ycbcr_xoffset = 0.0f; + break; + } + + ycbcr = true; + break; + default: + return false; + } + + VDTriBltTransformedVertex fastxverts[64]; + vdfastvector xverts; + + VDTriBltTransformedVertex *xsrc; + if (nVertices <= 64) { + xsrc = fastxverts; + } else { + xverts.resize(nVertices); + xsrc = xverts.data(); + } + + static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; + if (!pTransform) + pTransform = xf_ident; + + VDTriClipWorkspace clipws; + for(int plane=0; plane<(ycbcr?3:1); ++plane) { + VDPixmap& pxPlane = ycbcr ? plane == 0 ? pxY : plane == 1 ? pxCb : pxCr : dst; + + if (ycbcr && plane) { + float xf_ycbcr[16]; + memcpy(xf_ycbcr, pTransform, sizeof(float) * 16); + + // translate in x by ycbcr_xoffset + xf_ycbcr[0] += xf_ycbcr[12]*ycbcr_xoffset; + xf_ycbcr[1] += xf_ycbcr[13]*ycbcr_xoffset; + xf_ycbcr[2] += xf_ycbcr[14]*ycbcr_xoffset; + xf_ycbcr[3] += xf_ycbcr[15]*ycbcr_xoffset; + + // translate in y by chroma_yoffset + if (chroma_yoffset) { + xf_ycbcr[4] += xf_ycbcr[12]*(*chroma_yoffset); + xf_ycbcr[5] += xf_ycbcr[13]*(*chroma_yoffset); + xf_ycbcr[6] += xf_ycbcr[14]*(*chroma_yoffset); + xf_ycbcr[7] += xf_ycbcr[15]*(*chroma_yoffset); + } + + TransformVerts(xsrc, pVertices, nVertices, xf_ycbcr); + + switch(plane) { + case 1: + for(int i=0; i= 3) { + const int idx0 = nextIndex[0]; + const int idx1 = nextIndex[1]; + const int idx2 = nextIndex[2]; + const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; + const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; + const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; + const int kode0 = xv0->outcode; + const int kode1 = xv1->outcode; + const int kode2 = xv2->outcode; + + if (!(kode0 & kode1 & kode2)) { + if (int orflags = kode0 | kode1 | kode2) { + VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); + + if (src) { + VDTriBltTransformedVertex *src0 = *src++; + + // fan out triangles + while(src[1]) { + FillTriGrad(pxPlane, src0, src[0], src[1]); + ++src; + } + } + } else { + FillTriGrad(pxPlane, xv0, xv1, xv2); + } + } + + nextIndex += 3; + indicesLeft -= 3; + } + } + + return true; +} + +bool VDPixmapTriBlt(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, + const VDTriBltVertex *pVertices, int nVertices, + const int *pIndices, int nIndices, + VDTriBltFilterMode filterMode, + float mipMapLODBias, + const float pTransform[16]) +{ + if (dst.format != nsVDPixmap::kPixFormat_XRGB8888) + return false; + + static const float xf_ident[16]={1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f,0.f,0.f,0.f,0.f,1.f}; + vdfastvector xverts(nVertices); + + if (!pTransform) + pTransform = xf_ident; + + TransformVerts(xverts.data(), pVertices, nVertices, pTransform); + + const VDTriBltTransformedVertex *xsrc = xverts.data(); + + VDTriClipWorkspace clipws; + + while(nIndices >= 3) { + const int idx0 = pIndices[0]; + const int idx1 = pIndices[1]; + const int idx2 = pIndices[2]; + const VDTriBltTransformedVertex *xv0 = &xsrc[idx0]; + const VDTriBltTransformedVertex *xv1 = &xsrc[idx1]; + const VDTriBltTransformedVertex *xv2 = &xsrc[idx2]; + const int kode0 = xv0->outcode; + const int kode1 = xv1->outcode; + const int kode2 = xv2->outcode; + + if (!(kode0 & kode1 & kode2)) { + if (int orflags = kode0 | kode1 | kode2) { + VDTriBltTransformedVertex **src = VDClipTriangle(clipws, xv0, xv1, xv2, orflags); + + if (src) { + VDTriBltTransformedVertex *src0 = *src++; + + // fan out triangles + while(src[1]) { + RenderTri(dst, pSources, nMipmaps, src0, src[0], src[1], filterMode, mipMapLODBias); + ++src; + } + } + } else + RenderTri(dst, pSources, nMipmaps, xv0, xv1, xv2, filterMode, mipMapLODBias); + } + + pIndices += 3; + nIndices -= 3; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////// + +void VDPixmapSetTextureBorders(VDPixmap& px, bool wrap) { + const int w = px.w; + const int h = px.h; + + VDPixmapBlt(px, 0, 1, px, wrap ? w-2 : 1, 1, 1, h-2); + VDPixmapBlt(px, w-1, 1, px, wrap ? 1 : w-2, 1, 1, h-2); + + VDPixmapBlt(px, 0, 0, px, 0, wrap ? h-2 : 1, w, 1); + VDPixmapBlt(px, 0, h-1, px, 0, wrap ? 1 : h-2, w, 1); +} + +void VDPixmapSetTextureBordersCubic(VDPixmap& px) { + const int w = px.w; + const int h = px.h; + + VDPixmapBlt(px, 0, 1, px, 2, 1, 1, h-2); + VDPixmapBlt(px, 1, 1, px, 2, 1, 1, h-2); + VDPixmapBlt(px, w-2, 1, px, w-3, 1, 1, h-2); + VDPixmapBlt(px, w-1, 1, px, w-3, 1, 1, h-2); + + VDPixmapBlt(px, 0, 0, px, 0, 2, w, 1); + VDPixmapBlt(px, 0, 1, px, 0, 2, w, 1); + VDPixmapBlt(px, 0, h-2, px, 0, h-3, w, 1); + VDPixmapBlt(px, 0, h-1, px, 0, h-3, w, 1); +} + +/////////////////////////////////////////////////////////////////////////// + +VDPixmapTextureMipmapChain::VDPixmapTextureMipmapChain(const VDPixmap& src, bool wrap, bool cubic, int maxlevels) { + int w = src.w; + int h = src.h; + int mipcount = 0; + + while((w>1 || h>1) && maxlevels--) { + ++mipcount; + w >>= 1; + h >>= 1; + } + + mBuffers.resize(mipcount); + mMipMaps.resize(mipcount); + + vdautoptr r(VDCreatePixmapResampler()); + r->SetFilters(IVDPixmapResampler::kFilterLinear, IVDPixmapResampler::kFilterLinear, false); + + float fw = (float)src.w; + float fh = (float)src.h; + for(int mip=0; mipInit(rdst, curmip.w, curmip.h, curmip.format, rsrc, prevmip.w, prevmip.h, prevmip.format); + r->Process(curmip, prevmip); + } + } else { + mBuffers[mip].init(mipw+2, miph+2, nsVDPixmap::kPixFormat_XRGB8888); + + if (!mip) { + VDPixmapBlt(mBuffers[0], 1, 1, src, 0, 0, src.w, src.h); + VDPixmapSetTextureBorders(mBuffers[0], wrap); + } else { + const VDPixmap& curmip = mBuffers[mip]; + const VDPixmap& prevmip = mBuffers[mip-1]; + + vdrect32f rdst( 0.0f, 0.0f, (float)curmip.w , (float)curmip.h ); + vdrect32f rsrc(-1.0f, -1.0f, 2.0f*(float)curmip.w - 1.0f, 2.0f*(float)curmip.h - 1.0f); + r->Init(rdst, curmip.w, curmip.h, curmip.format, rsrc, prevmip.w, prevmip.h, prevmip.format); + r->Process(curmip, prevmip); + } + } + + fw *= 0.5f; + fh *= 0.5f; + } +} + diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit.cpp index 7381a7d4746..d6caf3707fc 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit.cpp @@ -1,1416 +1,1416 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include "uberblit.h" -#include "uberblit_gen.h" -#include "uberblit_ycbcr_generic.h" - -uint32 VDPixmapGetFormatTokenFromFormat(int format) { - using namespace nsVDPixmap; - switch(format) { - case kPixFormat_Pal1: return kVDPixType_1 | kVDPixSamp_444 | kVDPixSpace_Pal; - case kPixFormat_Pal2: return kVDPixType_2 | kVDPixSamp_444 | kVDPixSpace_Pal; - case kPixFormat_Pal4: return kVDPixType_4 | kVDPixSamp_444 | kVDPixSpace_Pal; - case kPixFormat_Pal8: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Pal; - case kPixFormat_XRGB1555: return kVDPixType_1555_LE | kVDPixSamp_444 | kVDPixSpace_BGR; - case kPixFormat_RGB565: return kVDPixType_565_LE | kVDPixSamp_444 | kVDPixSpace_BGR; - case kPixFormat_RGB888: return kVDPixType_888 | kVDPixSamp_444 | kVDPixSpace_BGR; - case kPixFormat_XRGB8888: return kVDPixType_8888 | kVDPixSamp_444 | kVDPixSpace_BGR; - case kPixFormat_Y8: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Y_601; - case kPixFormat_YUV422_UYVY: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_YUYV: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV444_XVYU: return kVDPixType_8888 | kVDPixSamp_444 | kVDPixSpace_YCC_601; - case kPixFormat_YUV444_Planar: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_Planar: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_Planar_16F: return kVDPixType_16F_16F_16F_LE | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV420_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601; - case kPixFormat_YUV411_Planar: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_601; - case kPixFormat_YUV410_Planar: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_Planar_Centered: return kVDPixType_8_8_8 | kVDPixSamp_422_JPEG | kVDPixSpace_YCC_601; - case kPixFormat_YUV420_Planar_Centered: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG1 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_V210: return kVDPixType_V210 | kVDPixSamp_422 | kVDPixSpace_YCC_601; - case kPixFormat_YUV422_UYVY_709: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; - case kPixFormat_YUV420_NV12: return kVDPixType_8_B8R8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601; - case kPixFormat_Y8_FR: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Y_601_FR; - case kPixFormat_YUV422_YUYV_709: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; - case kPixFormat_YUV444_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_709; - case kPixFormat_YUV422_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; - case kPixFormat_YUV420_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_709; - case kPixFormat_YUV411_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_709; - case kPixFormat_YUV410_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_709; - case kPixFormat_YUV422_UYVY_FR: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV422_YUYV_FR: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV444_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV422_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV420_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV411_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV410_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV422_UYVY_709_FR: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV422_YUYV_709_FR: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV444_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV422_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV420_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV411_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV410_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV420i_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_601; - case kPixFormat_YUV420i_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV420i_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_709; - case kPixFormat_YUV420i_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV420it_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_601; - case kPixFormat_YUV420it_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV420it_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_709; - case kPixFormat_YUV420it_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_709_FR; - case kPixFormat_YUV420ib_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_601; - case kPixFormat_YUV420ib_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_601_FR; - case kPixFormat_YUV420ib_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_709; - case kPixFormat_YUV420ib_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_709_FR; - default: - VDASSERT(false); - return 0; - } -} - -const VDPixmapSamplingInfo& VDPixmapGetSamplingInfo(uint32 samplingToken) { - static const VDPixmapSamplingInfo kPixmapSamplingInfo[]={ - /* Null */ { false, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, - /* 444 */ { false, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, - /* 422 */ { false, { -4, 0, 1, 0 }, { -4, 0, 1, 0 } }, - /* 422_JPEG */ { false, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } }, - /* 420_MPEG2 */ { false, { -4, 0, 1, 1 }, { -4, 0, 1, 1 } }, - /* 420_MPEG2INT */ { true , { -4, -2, 1, 1 }, { -4, -2, 1, 1 }, { -4, +2, 1, 1 }, { -4, +2, 1, 1 } }, - /* 420_MPEG2INT1*/ { false, { -4, -2, 1, 1 }, { -4, -2, 1, 1 } }, - /* 420_MPEG2INT2*/ { false, { -4, +2, 1, 1 }, { -4, +2, 1, 1 } }, - /* 420_MPEG1 */ { false, { 0, 0, 1, 1 }, { 0, 0, 1, 1 } }, - /* 420_DVPAL */ { true , { -4, 0, 1, 1 }, { -4, 0, 1, 1 } }, - /* 411 */ { false, { -6, 0, 2, 0 }, { -6, 0, 2, 0 } }, - /* 410 */ { false, { -6, 0, 2, 2 }, { -6, 0, 2, 2 } }, - }; - - uint32 index = (samplingToken & kVDPixSamp_Mask) >> kVDPixSamp_Bits; - - return index >= sizeof(kPixmapSamplingInfo)/sizeof(kPixmapSamplingInfo[0]) ? kPixmapSamplingInfo[0] : kPixmapSamplingInfo[index]; -} - -namespace { - uint32 GetChromaPlaneBpr(uint32 w, uint32 srcToken) { - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_1: - case kVDPixType_2: - case kVDPixType_4: - case kVDPixType_8: - case kVDPixType_555_LE: - case kVDPixType_565_LE: - case kVDPixType_1555_LE: - case kVDPixType_16F_LE: - case kVDPixType_888: - case kVDPixType_8888: - case kVDPixType_16Fx4_LE: - case kVDPixType_32F_LE: - case kVDPixType_32Fx4_LE: - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - case kVDPixType_V210: - case kVDPixType_8_B8R8: - case kVDPixType_B8R8: - default: - return 0; - - case kVDPixType_8_8_8: - return w; - - case kVDPixType_16F_16F_16F_LE: - return w*2; - - case kVDPixType_32F_32F_32F_LE: - return w*4; - } - } - - void BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapSamplingInfo& dstInfo, const VDPixmapSamplingInfo& srcInfo, sint32 cw, sint32 ch); - void BlitterConvertPlaneSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapPlaneSamplingInfo& dstInfo, const VDPixmapPlaneSamplingInfo& srcInfo, sint32 cw, sint32 ch); - - uint32 BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, uint32 srcToken, uint32 dstSamplingToken, sint32 w, sint32 h) { - // if the source type is 16F, we have to convert to 32F - if ((srcToken & kVDPixType_Mask) == kVDPixType_16F_16F_16F_LE) { - // 0 1 2 - gen.conv_16F_to_32F(); - gen.swap(1); - // 1 0 2 - gen.conv_16F_to_32F(); - gen.swap(2); - // 2 0 1 - gen.conv_16F_to_32F(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - } - - // look up sampling info - const VDPixmapSamplingInfo& srcInfo = VDPixmapGetSamplingInfo(srcToken); - const VDPixmapSamplingInfo& dstInfo = VDPixmapGetSamplingInfo(dstSamplingToken); - - // Check if we have an interlacing mismatch. If so, then we have to convert up to - // full resolution vertically in order to split or merge fields. - const sint32 cw = -(-w >> dstInfo.mPlane1Cr.mXBits); - const sint32 ch = -(-h >> dstInfo.mPlane1Cr.mYBits); - const uint32 cbpr = GetChromaPlaneBpr(cw, srcToken); - - if (dstInfo.mbInterlaced || srcInfo.mbInterlaced) { - const sint32 src_cw = -(-w >> srcInfo.mPlane1Cr.mXBits); - - const sint32 ch1 = (ch + 1) >> 1; - const sint32 ch2 = ch >> 1; - - if (dstInfo.mbInterlaced) { - if (srcInfo.mbInterlaced) { - // interlaced -> interlaced: split fields, resample, merge fields - // - // cr y cb - gen.split_fields(cbpr); - - // cr-odd cr-even y cb - BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cr, srcInfo.mPlane2Cr, cw, ch2); - - // cr-odd' cr-even y cb - gen.swap(1); - - // cr-even cr-odd' y cb - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, srcInfo.mPlane1Cr, cw, ch1); - - // cr-even' cr-odd' y cb - gen.swap(1); - - // cr-odd' cr-even' y cb - gen.merge_fields(cw, ch, cbpr); - - // cr' y cb - gen.swap(2); - - // cb' y cr' - gen.split_fields(cbpr); - - // cb-odd cb-even y cr' - BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cb, srcInfo.mPlane2Cb, cw, ch2); - - // cb-odd' cb-even y cr' - gen.swap(1); - - // cb-even cb-odd' y cr' - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, srcInfo.mPlane1Cb, cw, ch1); - - // cb-even' cb-odd' y cr' - gen.swap(1); - - // cb-odd' cb-even' y cr' - gen.merge_fields(cw, ch, cbpr); - - // cb' y cr' - gen.swap(2); - - // cr' y cb' - } else { - // non-interlaced -> interlaced - VDPixmapPlaneSamplingInfo crPlaneInt(srcInfo.mPlane1Cr); - VDPixmapPlaneSamplingInfo crPlaneFieldInt(srcInfo.mPlane1Cr); - VDPixmapPlaneSamplingInfo cbPlaneInt(srcInfo.mPlane1Cb); - VDPixmapPlaneSamplingInfo cbPlaneFieldInt(srcInfo.mPlane1Cb); - - crPlaneInt.mX = dstInfo.mPlane1Cr.mX; - crPlaneInt.mXBits = dstInfo.mPlane1Cr.mXBits; - crPlaneInt.mY = 0; - crPlaneInt.mYBits = 0; - crPlaneFieldInt.mX = dstInfo.mPlane1Cr.mX; - crPlaneFieldInt.mXBits = dstInfo.mPlane1Cr.mXBits; - crPlaneFieldInt.mY = 0; - crPlaneFieldInt.mYBits = 0; - - cbPlaneInt.mX = dstInfo.mPlane1Cb.mX; - cbPlaneInt.mXBits = dstInfo.mPlane1Cb.mXBits; - cbPlaneFieldInt.mX = dstInfo.mPlane1Cb.mX; - cbPlaneFieldInt.mXBits = dstInfo.mPlane1Cb.mXBits; - cbPlaneFieldInt.mY = 0; - cbPlaneFieldInt.mYBits = 0; - - // cr y cb - BlitterConvertPlaneSampling(gen, crPlaneInt, srcInfo.mPlane1Cr, cw, h); - - // cr' y cb - gen.split_fields(cbpr); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, crPlaneFieldInt, cw, ch1); - gen.swap(1); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cr, crPlaneFieldInt, cw, ch2); - gen.swap(1); - gen.merge_fields(cw, ch, cbpr); - - gen.swap(2); - BlitterConvertPlaneSampling(gen, cbPlaneInt, srcInfo.mPlane1Cb, cw, h); - gen.split_fields(cbpr); - gen.swap(1); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneFieldInt, cw, ch1); - gen.swap(1); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneFieldInt, cw, ch2); - gen.merge_fields(cw, ch, cbpr); - gen.swap(2); - } - } else { - sint32 src_cbpr = src_cw; - - // interlaced -> non-interlaced - VDPixmapPlaneSamplingInfo crPlaneFieldInt(srcInfo.mPlane1Cr); - VDPixmapPlaneSamplingInfo crPlaneInt(srcInfo.mPlane1Cr); - VDPixmapPlaneSamplingInfo cbPlaneFieldInt(srcInfo.mPlane1Cb); - VDPixmapPlaneSamplingInfo cbPlaneInt(srcInfo.mPlane1Cb); - - crPlaneFieldInt.mY = 0; - crPlaneFieldInt.mYBits = 0; - crPlaneInt.mY = 0; - crPlaneInt.mYBits = 0; - cbPlaneFieldInt.mY = 0; - cbPlaneFieldInt.mYBits = 0; - cbPlaneInt.mY = 0; - cbPlaneInt.mYBits = 0; - - // cr y cb - gen.split_fields(src_cbpr); - BlitterConvertPlaneSampling(gen, crPlaneFieldInt, srcInfo.mPlane1Cr, src_cw, (h + 1) >> 1); - gen.swap(1); - BlitterConvertPlaneSampling(gen, crPlaneFieldInt, srcInfo.mPlane2Cr, src_cw, h >> 1); - gen.swap(1); - gen.merge_fields(src_cw, h, src_cbpr); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, crPlaneInt, cw, ch); - gen.swap(2); - - // cr' y cb - gen.split_fields(src_cbpr); - BlitterConvertPlaneSampling(gen, cbPlaneFieldInt, srcInfo.mPlane1Cb, src_cw, (h + 1) >> 1); - gen.swap(1); - BlitterConvertPlaneSampling(gen, cbPlaneFieldInt, srcInfo.mPlane2Cb, src_cw, h >> 1); - gen.swap(1); - gen.merge_fields(src_cw, h, src_cbpr); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneInt, cw, ch); - gen.swap(2); - } - } else { - // non-interlaced -> non-interlaced - BlitterConvertSampling(gen, dstInfo, srcInfo, cw, ch); - } - - return (srcToken & ~kVDPixSamp_Mask) | (dstSamplingToken & kVDPixSamp_Mask); - } - - void BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapSamplingInfo& dstInfo, const VDPixmapSamplingInfo& srcInfo, sint32 cw, sint32 ch) { - gen.swap(2); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, srcInfo.mPlane1Cb, cw, ch); - gen.swap(2); - BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, srcInfo.mPlane1Cr, cw, ch); - } - - void BlitterConvertPlaneSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapPlaneSamplingInfo& dstInfo, const VDPixmapPlaneSamplingInfo& srcInfo, sint32 cw, sint32 ch) { - // convert destination chroma origin to luma space - int c_x = ((8 + dstInfo.mX) << dstInfo.mXBits) - 8; - int c_y = ((8 + dstInfo.mY) << dstInfo.mYBits) - 8; - - // convert luma chroma location to source chroma space - c_x = ((8 + c_x) >> srcInfo.mXBits) - 8 - srcInfo.mX; - c_y = ((8 + c_y) >> srcInfo.mYBits) - 8 - srcInfo.mY; - - float cxo = c_x / 16.0f + 0.5f; - float cxf = ((16 << dstInfo.mXBits) >> srcInfo.mXBits) / 16.0f; - float cyf = ((16 << dstInfo.mYBits) >> srcInfo.mYBits) / 16.0f; - - gen.linear(cxo, cxf, cw, c_y / 16.0f + 0.5f, cyf, ch); - } - - uint32 BlitterConvertType(VDPixmapUberBlitterGenerator& gen, uint32 srcToken, uint32 dstToken, sint32 w, sint32 h) { - uint32 dstType = dstToken & kVDPixType_Mask; - - while((srcToken ^ dstToken) & kVDPixType_Mask) { - uint32 srcType = srcToken & kVDPixType_Mask; - uint32 targetType = dstType; - - type_reconvert: - switch(targetType) { - case kVDPixType_1555_LE: - switch(srcType) { - case kVDPixType_565_LE: - gen.conv_565_to_555(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_1555_LE; - break; - - case kVDPixType_8888: - gen.conv_8888_to_555(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_1555_LE; - break; - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - default: - targetType = kVDPixType_8888; - goto type_reconvert; - } - break; - - case kVDPixType_565_LE: - switch(srcType) { - case kVDPixType_1555_LE: - gen.conv_555_to_565(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_565_LE; - break; - case kVDPixType_8888: - gen.conv_8888_to_565(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_565_LE; - break; - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - default: - targetType = kVDPixType_8888; - goto type_reconvert; - } - break; - - case kVDPixType_888: - switch(srcType) { - case kVDPixType_8888: - gen.conv_8888_to_888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_888; - break; - default: - targetType = kVDPixType_8888; - goto type_reconvert; - } - break; - - case kVDPixType_8888: - switch(srcType) { - case kVDPixType_1555_LE: - gen.conv_555_to_8888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - case kVDPixType_565_LE: - gen.conv_565_to_8888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - case kVDPixType_888: - gen.conv_888_to_8888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - case kVDPixType_32Fx4_LE: - gen.conv_X32F_to_8888(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - case kVDPixType_8_8_8: - if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_444) - srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_444, w, h); - gen.interleave_X8R8G8B8(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; - break; - default: - VDASSERT(false); - break; - } - break; - - case kVDPixType_8: - switch(srcType) { - case kVDPixType_8_8_8: - gen.pop(); - gen.swap(1); - gen.pop(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - break; - - case kVDPixType_16F_LE: - targetType = kVDPixType_32F_LE; - goto type_reconvert; - - case kVDPixType_32F_LE: - gen.conv_32F_to_8(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - break; - - default: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - } - break; - - case kVDPixType_8_8_8: - switch(srcType) { - case kVDPixType_B8G8_R8G8: - gen.dup(); - gen.dup(); - gen.extract_8in32(2, (w + 1) >> 1, h); - gen.swap(2); - gen.extract_8in16(1, w, h); - gen.swap(1); - gen.extract_8in32(0, (w + 1) >> 1, h); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_8_8_8 | kVDPixSamp_422; - break; - case kVDPixType_G8B8_G8R8: - gen.dup(); - gen.dup(); - gen.extract_8in32(3, (w + 1) >> 1, h); - gen.swap(2); - gen.extract_8in16(0, w, h); - gen.swap(1); - gen.extract_8in32(1, (w + 1) >> 1, h); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_8_8_8 | kVDPixSamp_422; - break; - case kVDPixType_16F_16F_16F_LE: - case kVDPixType_V210: - targetType = kVDPixType_32F_32F_32F_LE; - goto type_reconvert; - case kVDPixType_32F_32F_32F_LE: - // 0 1 2 - gen.conv_32F_to_8(); - gen.swap(1); - // 1 0 2 - gen.conv_32F_to_8(); - gen.swap(2); - // 2 0 1 - gen.conv_32F_to_8(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - case kVDPixType_8_B8R8: - { - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - int cw = -(-w >> sampInfo.mPlane1Cr.mXBits); - int ch = -(-h >> sampInfo.mPlane1Cr.mYBits); - - gen.dup(); - gen.extract_8in16(1, cw, ch); - gen.swap(2); - gen.swap(1); - gen.extract_8in16(0, cw, ch); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - } - break; - default: - VDASSERT(false); - break; - } - break; - - case kVDPixType_B8G8_R8G8: - switch(srcType) { - case kVDPixType_8_8_8: - if ((srcToken ^ dstToken) & kVDPixSamp_Mask) - srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); - - gen.interleave_B8G8_R8G8(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_B8G8_R8G8; - break; - case kVDPixType_G8B8_G8R8: - gen.swap_8in16(w, h, ((w + 1) & ~1)*2); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_B8G8_R8G8; - break; - default: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - } - break; - - case kVDPixType_G8B8_G8R8: - switch(srcType) { - case kVDPixType_8_8_8: - if ((srcToken ^ dstToken) & kVDPixSamp_Mask) - srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); - - gen.interleave_G8B8_G8R8(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_G8B8_G8R8; - break; - case kVDPixType_B8G8_R8G8: - gen.swap_8in16(w, h, ((w + 1) & ~1)*2); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_G8B8_G8R8; - break; - default: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - } - break; - - case kVDPixType_16F_16F_16F_LE: - switch(srcType) { - case kVDPixType_32F_32F_32F_LE: - // 0 1 2 - gen.conv_32F_to_16F(); - gen.swap(1); - // 1 0 2 - gen.conv_32F_to_16F(); - gen.swap(2); - // 2 0 1 - gen.conv_32F_to_16F(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_16F_16F_LE; - break; - - default: - targetType = kVDPixType_32F_32F_32F_LE; - goto type_reconvert; - } - break; - - case kVDPixType_32F_32F_32F_LE: - switch(srcType) { - case kVDPixType_8_8_8: - // 0 1 2 - gen.conv_8_to_32F(); - gen.swap(1); - // 1 0 2 - gen.conv_8_to_32F(); - gen.swap(2); - // 2 0 1 - gen.conv_8_to_32F(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - break; - - case kVDPixType_16F_16F_16F_LE: - // 0 1 2 - gen.conv_16F_to_32F(); - gen.swap(1); - // 1 0 2 - gen.conv_16F_to_32F(); - gen.swap(2); - // 2 0 1 - gen.conv_16F_to_32F(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - break; - - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - case kVDPixType_8_B8R8: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - - case kVDPixType_V210: - gen.conv_V210_to_32F(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - break; - - default: - VDASSERT(false); - } - break; - - case kVDPixType_V210: - switch(srcType) { - case kVDPixType_32F_32F_32F_LE: - if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_422) - srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_422, w, h); - - gen.conv_32F_to_V210(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_V210; - break; - - case kVDPixType_16F_16F_16F_LE: - targetType = kVDPixType_32F_32F_32F_LE; - goto type_reconvert; - - case kVDPixType_8_8_8: - if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_422) - srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_422, w, h); - - targetType = kVDPixType_32F_32F_32F_LE; - goto type_reconvert; - - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - case kVDPixType_8_B8R8: - targetType = kVDPixType_8_8_8; - goto type_reconvert; - - default: - VDASSERT(false); - } - break; - - case kVDPixType_32F_LE: - switch(srcType) { - case kVDPixType_8: - gen.conv_8_to_32F(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - break; - case kVDPixType_16F_LE: - gen.conv_16F_to_32F(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - break; - default: - VDASSERT(false); - } - break; - - case kVDPixType_8_B8R8: - switch(srcType) { - case kVDPixType_8_8_8: - gen.swap(1); - gen.swap(2); - gen.interleave_B8R8(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_B8R8; - break; - default: - VDASSERT(false); - break; - } - break; - - default: - VDASSERT(false); - break; - } - } - - return srcToken; - } -} - -IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmap& dst, const VDPixmap& src) { - const VDPixmapLayout& dstlayout = VDPixmapToLayoutFromBase(dst, dst.data); - const VDPixmapLayout& srclayout = VDPixmapToLayoutFromBase(src, src.data); - - return VDPixmapCreateBlitter(dstlayout, srclayout); -} - -IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmapLayout& dst, const VDPixmapLayout& src) { - if (src.format == dst.format) { - return VDCreatePixmapUberBlitterDirectCopy(dst, src); - } - - uint32 srcToken = VDPixmapGetFormatTokenFromFormat(src.format); - uint32 dstToken = VDPixmapGetFormatTokenFromFormat(dst.format); - - VDPixmapUberBlitterGenerator gen; - - // load source channels - int w = src.w; - int h = src.h; - - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_1: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 7) >> 3); - break; - - case kVDPixType_2: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 3) >> 2); - break; - - case kVDPixType_4: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 1) >> 1); - break; - - case kVDPixType_8: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w); - break; - - case kVDPixType_555_LE: - case kVDPixType_565_LE: - case kVDPixType_1555_LE: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*2); - break; - - case kVDPixType_888: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*3); - break; - - case kVDPixType_8888: - case kVDPixType_32F_LE: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*4); - break; - - case kVDPixType_32Fx4_LE: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*16); - break; - - case kVDPixType_B8G8_R8G8: - case kVDPixType_G8B8_G8R8: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, ((w + 1) & ~1)*2); - break; - - case kVDPixType_8_8_8: - { - uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - - int cxbits = sampInfo.mPlane1Cb.mXBits; - int cybits = sampInfo.mPlane1Cb.mYBits; - int w2 = -(-w >> cxbits); - int h2 = -(-h >> cybits); - gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2); - gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w); - gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2); - } - break; - - case kVDPixType_16F_16F_16F_LE: - { - uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; - uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; - uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; - - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - - int cxbits = sampInfo.mPlane1Cb.mXBits; - int cybits = sampInfo.mPlane1Cb.mYBits; - int w2 = -(-w >> cxbits); - int h2 = -(-h >> cybits); - gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2 * 2); - gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w*2); - gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2 * 2); - } - break; - - case kVDPixType_32F_32F_32F_LE: - { - uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; - - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - - int cxbits = sampInfo.mPlane1Cb.mXBits; - int cybits = sampInfo.mPlane1Cb.mYBits; - int w2 = -(-w >> cxbits); - int h2 = -(-h >> cybits); - gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2 * 4); - gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w*4); - gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2 * 4); - } - break; - - case kVDPixType_V210: - gen.ldsrc(0, 0, 0, 0, w, h, srcToken, ((w + 5) / 6) * 4); - break; - - case kVDPixType_8_B8R8: - { - uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; - uint32 ctoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_B8R8; - - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - - int cxbits = sampInfo.mPlane1Cb.mXBits; - int cybits = sampInfo.mPlane1Cb.mYBits; - int w2 = -(-w >> cxbits); - int h2 = -(-h >> cybits); - gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w); - gen.ldsrc(0, 1, 0, 0, w2, h2, ctoken, w2*2); - } - break; - - default: - VDASSERT(false); - } - - // check if we need a color space change - if ((srcToken ^ dstToken) & kVDPixSpace_Mask) { - // first, if we're dealing with an interleaved format, deinterleave it - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_B8G8_R8G8: - gen.dup(); - gen.dup(); - gen.extract_8in32(2, (w + 1) >> 1, h); - gen.swap(2); - gen.extract_8in16(1, w, h); - gen.swap(1); - gen.extract_8in32(0, (w + 1) >> 1, h); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - - case kVDPixType_G8B8_G8R8: - gen.dup(); - gen.dup(); - gen.extract_8in32(3, (w + 1) >> 1, h); - gen.swap(2); - gen.extract_8in16(0, w, h); - gen.swap(1); - gen.extract_8in32(1, (w + 1) >> 1, h); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - - case kVDPixType_8_B8R8: - gen.dup(); - gen.extract_8in16(1, (w + 1) >> 1, (h + 1) >> 1); - gen.swap(2); - gen.swap(1); - gen.extract_8in16(0, (w + 1) >> 1, (h + 1) >> 1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - - case kVDPixType_V210: - gen.conv_V210_to_32F(); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; - break; - } - - // if the source is subsampled, converge on 4:4:4 subsampling, but only if we actually need - // the auxiliary channels - const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); - -#if 0 - // This check is currently disabled because we currently do need the chroma planes - // if we're doing a color space conversion, even if we are going to Y-only. - switch(dstToken & kVDPixSpace_Mask) { -// case kVDPixSpace_Y_601: -// case kVDPixSpace_Y_709: -// case kVDPixSpace_Y_601_FR: -// case kVDPixSpace_Y_709_FR: -// break; - - default: -#endif - if (sampInfo.mPlane1Cb.mXBits | - sampInfo.mPlane1Cb.mYBits | - sampInfo.mPlane1Cb.mX | - sampInfo.mPlane1Cb.mY | - sampInfo.mPlane1Cr.mX | - sampInfo.mPlane1Cr.mY) - srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_444, w, h); -#if 0 - break; - } -#endif - - // change color spaces - uint32 dstSpace = dstToken & kVDPixSpace_Mask; - while((srcToken ^ dstToken) & kVDPixSpace_Mask) { - uint32 srcSpace = srcToken & kVDPixSpace_Mask; - uint32 targetSpace = dstSpace; - -space_reconvert: - switch(targetSpace) { - case kVDPixSpace_BGR: - switch(srcSpace) { - case kVDPixSpace_YCC_709: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - gen.ycbcr709_to_rgb32(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_16F_16F_16F_LE: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_32F_32F_32F_LE, w, h); - gen.ycbcr709_to_rgb32_32f(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; - break; - - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr709_to_rgb32_32f(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_601: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - gen.ycbcr601_to_rgb32(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_16F_16F_16F_LE: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_32F_32F_32F_LE, w, h); - gen.ycbcr601_to_rgb32_32f(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; - break; - - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr601_to_rgb32_32f(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_709_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - gen.ycbcr_to_rgb32_generic(g_VDPixmapGenYCbCrBasis_709, false); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_601_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - gen.ycbcr_to_rgb32_generic(g_VDPixmapGenYCbCrBasis_601, false); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_Y_601: - targetSpace = kVDPixSpace_YCC_601; - goto space_reconvert; - - case kVDPixSpace_Y_709: - targetSpace = kVDPixSpace_YCC_709; - goto space_reconvert; - - case kVDPixSpace_Y_601_FR: - targetSpace = kVDPixSpace_YCC_601_FR; - goto space_reconvert; - - case kVDPixSpace_Y_709_FR: - targetSpace = kVDPixSpace_YCC_709_FR; - goto space_reconvert; - - case kVDPixSpace_Pal: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_1: - gen.conv_Pal1_to_8888(0); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_2: - gen.conv_Pal2_to_8888(0); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_4: - gen.conv_Pal4_to_8888(0); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - case kVDPixType_8: - gen.conv_Pal8_to_8888(0); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; - break; - - default: - VDASSERT(false); - break; - } - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_Y_601: - switch(srcSpace) { - case kVDPixSpace_YCC_601: - gen.pop(); - gen.swap(1); - gen.pop(); - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_32F_32F_32F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; - break; - case kVDPixType_16F_16F_16F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; - break; - case kVDPixType_8_8_8: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - break; - - default: - VDASSERT(false); - } - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); - break; - - default: - targetSpace = kVDPixSpace_YCC_601; - goto space_reconvert; - } - break; - - case kVDPixSpace_Y_601_FR: - switch(srcSpace) { - case kVDPixSpace_YCC_601_FR: - gen.pop(); - gen.swap(1); - gen.pop(); - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_32F_32F_32F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; - break; - case kVDPixType_16F_16F_16F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; - break; - case kVDPixType_8_8_8: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - break; - - default: - VDASSERT(false); - } - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); - break; - - default: - targetSpace = kVDPixSpace_YCC_601_FR; - goto space_reconvert; - } - break; - - case kVDPixSpace_Y_709: - switch(srcSpace) { - case kVDPixSpace_YCC_709: - gen.pop(); - gen.swap(1); - gen.pop(); - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_32F_32F_32F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; - break; - case kVDPixType_16F_16F_16F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; - break; - case kVDPixType_8_8_8: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - break; - - default: - VDASSERT(false); - } - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); - break; - - default: - targetSpace = kVDPixSpace_YCC_709; - goto space_reconvert; - } - break; - - case kVDPixSpace_Y_709_FR: - switch(srcSpace) { - case kVDPixSpace_YCC_709_FR: - gen.pop(); - gen.swap(1); - gen.pop(); - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_32F_32F_32F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; - break; - case kVDPixType_16F_16F_16F_LE: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; - break; - case kVDPixType_8_8_8: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - break; - - default: - VDASSERT(false); - } - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); - break; - - default: - targetSpace = kVDPixSpace_YCC_709_FR; - goto space_reconvert; - } - break; - - case kVDPixSpace_YCC_601: - switch(srcSpace) { - case kVDPixSpace_BGR: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); - gen.rgb32_to_ycbcr601(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_601 | kVDPixType_8_8_8; - break; - case kVDPixSpace_Y_601: - case kVDPixSpace_Y_709: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_601 | kVDPixType_8; - - { - const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); - int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; - int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; - - gen.ldconst(0x80, cw, cw, ch, srcToken); - } - - gen.dup(); - gen.swap(2); - gen.swap(1); - srcToken = kVDPixSpace_YCC_601 | kVDPixType_8_8_8 | (srcToken & kVDPixSamp_Mask); - break; - - case kVDPixSpace_Y_601_FR: - targetSpace = kVDPixSpace_YCC_601_FR; - goto space_reconvert; - - case kVDPixSpace_Y_709_FR: - targetSpace = kVDPixSpace_YCC_709_FR; - goto space_reconvert; - - case kVDPixSpace_YCC_709: - VDASSERT((srcToken & kVDPixType_Mask) == kVDPixType_8_8_8); - gen.ycbcr709_to_ycbcr601(); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; - break; - - case kVDPixSpace_YCC_601_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_601, true, g_VDPixmapGenYCbCrBasis_601, false, kVDPixSpace_YCC_601); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_709_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_601, true, g_VDPixmapGenYCbCrBasis_709, false, kVDPixSpace_YCC_601); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_Pal: - targetSpace = kVDPixSpace_BGR; - goto space_reconvert; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_709: - switch(srcSpace) { - case kVDPixSpace_BGR: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); - gen.rgb32_to_ycbcr709(); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_709 | kVDPixType_8_8_8; - break; - case kVDPixSpace_Y_601: - case kVDPixSpace_Y_709: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_709 | kVDPixType_8; - - { - const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); - int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; - int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; - - gen.ldconst(0x80, cw, cw, ch, srcToken); - } - - gen.dup(); - gen.swap(2); - gen.swap(1); - srcToken = kVDPixSpace_YCC_709 | kVDPixType_8_8_8 | (srcToken & kVDPixSamp_Mask); - break; - case kVDPixSpace_YCC_601: - if ((srcToken & kVDPixType_Mask) == kVDPixType_8_8_8) - gen.ycbcr601_to_ycbcr709(); - else - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_601, true, kVDPixSpace_YCC_709); - - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; - break; - - case kVDPixSpace_YCC_601_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_601, false, kVDPixSpace_YCC_709); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_709_FR: - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_32F_32F_32F_LE: - gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_709, false, kVDPixSpace_YCC_709); - srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; - break; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_Y_601_FR: - targetSpace = kVDPixSpace_YCC_601_FR; - goto space_reconvert; - - case kVDPixSpace_Y_709_FR: - targetSpace = kVDPixSpace_YCC_709_FR; - goto space_reconvert; - - case kVDPixSpace_Pal: - targetSpace = kVDPixSpace_BGR; - goto space_reconvert; - - default: - VDASSERT(false); - break; - } - break; - - case kVDPixSpace_YCC_601_FR: - case kVDPixSpace_YCC_709_FR: - { - const VDPixmapGenYCbCrBasis& dstBasis = *(targetSpace == kVDPixSpace_YCC_601_FR ? &g_VDPixmapGenYCbCrBasis_601 : &g_VDPixmapGenYCbCrBasis_709); - - switch(srcSpace) { - case kVDPixSpace_BGR: - srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); - gen.rgb32_to_ycbcr_generic(dstBasis, false, targetSpace); - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8_8_8; - break; - case kVDPixSpace_Y_601_FR: - case kVDPixSpace_Y_709_FR: - srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; - - { - const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); - int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; - int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; - - gen.ldconst(0x80, cw, cw, ch, srcToken); - } - - gen.dup(); - gen.swap(2); - gen.swap(1); - srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; - break; - case kVDPixSpace_YCC_601: - gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_601, true, targetSpace); - srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; - break; - case kVDPixSpace_YCC_709: - gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_709, true, targetSpace); - srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; - break; - case kVDPixSpace_YCC_601_FR: - gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_601, false, targetSpace); - srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; - break; - case kVDPixSpace_YCC_709_FR: - gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_709, false, targetSpace); - srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; - break; - case kVDPixSpace_Pal: - targetSpace = kVDPixSpace_BGR; - goto space_reconvert; - - case kVDPixSpace_Y_601: - targetSpace = kVDPixSpace_YCC_601; - goto space_reconvert; - - case kVDPixSpace_Y_709: - targetSpace = kVDPixSpace_YCC_709; - goto space_reconvert; - - default: - VDASSERT(false); - break; - } - } - break; - - default: - VDASSERT(false); - break; - } - } - } - - // check if we need a type change - // - // Note: If the sampling is also different, we have to be careful about what types we - // target. The type conversion may itself involve a sampling conversion, so things get - // VERY tricky here. - if ((srcToken ^ dstToken) & kVDPixType_Mask) { - bool samplingDifferent = 0 != ((srcToken ^ dstToken) & kVDPixSamp_Mask); - uint32 intermediateTypeToken = dstToken & kVDPixType_Mask; - - if (samplingDifferent) { - switch(dstToken & kVDPixType_Mask) { - case kVDPixType_16F_16F_16F_LE: - intermediateTypeToken = kVDPixType_32F_32F_32F_LE; - break; - case kVDPixType_8_B8R8: - intermediateTypeToken = kVDPixType_8_8_8; - break; - } - } - - srcToken = BlitterConvertType(gen, srcToken, (dstToken & ~kVDPixType_Mask) | intermediateTypeToken, w, h); - } - - // convert subsampling if necessary - switch(srcToken & kVDPixType_Mask) { - case kVDPixType_8_8_8: - case kVDPixType_16F_16F_16F_LE: - case kVDPixType_32F_32F_32F_LE: - if ((srcToken ^ dstToken) & kVDPixSamp_Mask) - srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); - break; - } - - // check if we need a type change (possible with 16F) - srcToken = BlitterConvertType(gen, srcToken, dstToken, w, h); - - return gen.create(); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include "uberblit.h" +#include "uberblit_gen.h" +#include "uberblit_ycbcr_generic.h" + +uint32 VDPixmapGetFormatTokenFromFormat(int format) { + using namespace nsVDPixmap; + switch(format) { + case kPixFormat_Pal1: return kVDPixType_1 | kVDPixSamp_444 | kVDPixSpace_Pal; + case kPixFormat_Pal2: return kVDPixType_2 | kVDPixSamp_444 | kVDPixSpace_Pal; + case kPixFormat_Pal4: return kVDPixType_4 | kVDPixSamp_444 | kVDPixSpace_Pal; + case kPixFormat_Pal8: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Pal; + case kPixFormat_XRGB1555: return kVDPixType_1555_LE | kVDPixSamp_444 | kVDPixSpace_BGR; + case kPixFormat_RGB565: return kVDPixType_565_LE | kVDPixSamp_444 | kVDPixSpace_BGR; + case kPixFormat_RGB888: return kVDPixType_888 | kVDPixSamp_444 | kVDPixSpace_BGR; + case kPixFormat_XRGB8888: return kVDPixType_8888 | kVDPixSamp_444 | kVDPixSpace_BGR; + case kPixFormat_Y8: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Y_601; + case kPixFormat_YUV422_UYVY: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_YUYV: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV444_XVYU: return kVDPixType_8888 | kVDPixSamp_444 | kVDPixSpace_YCC_601; + case kPixFormat_YUV444_Planar: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_Planar: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_Planar_16F: return kVDPixType_16F_16F_16F_LE | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV420_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601; + case kPixFormat_YUV411_Planar: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_601; + case kPixFormat_YUV410_Planar: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_Planar_Centered: return kVDPixType_8_8_8 | kVDPixSamp_422_JPEG | kVDPixSpace_YCC_601; + case kPixFormat_YUV420_Planar_Centered: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG1 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_V210: return kVDPixType_V210 | kVDPixSamp_422 | kVDPixSpace_YCC_601; + case kPixFormat_YUV422_UYVY_709: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; + case kPixFormat_YUV420_NV12: return kVDPixType_8_B8R8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601; + case kPixFormat_Y8_FR: return kVDPixType_8 | kVDPixSamp_444 | kVDPixSpace_Y_601_FR; + case kPixFormat_YUV422_YUYV_709: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; + case kPixFormat_YUV444_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_709; + case kPixFormat_YUV422_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_709; + case kPixFormat_YUV420_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_709; + case kPixFormat_YUV411_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_709; + case kPixFormat_YUV410_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_709; + case kPixFormat_YUV422_UYVY_FR: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV422_YUYV_FR: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV444_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV422_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV420_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV411_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV410_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV422_UYVY_709_FR: return kVDPixType_B8G8_R8G8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV422_YUYV_709_FR: return kVDPixType_G8B8_G8R8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV444_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_444 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV422_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_422 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV420_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV411_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_411 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV410_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_410 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV420i_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_601; + case kPixFormat_YUV420i_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV420i_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_709; + case kPixFormat_YUV420i_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV420it_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_601; + case kPixFormat_YUV420it_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV420it_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_709; + case kPixFormat_YUV420it_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT1 | kVDPixSpace_YCC_709_FR; + case kPixFormat_YUV420ib_Planar: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_601; + case kPixFormat_YUV420ib_Planar_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_601_FR; + case kPixFormat_YUV420ib_Planar_709: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_709; + case kPixFormat_YUV420ib_Planar_709_FR: return kVDPixType_8_8_8 | kVDPixSamp_420_MPEG2INT2 | kVDPixSpace_YCC_709_FR; + default: + VDASSERT(false); + return 0; + } +} + +const VDPixmapSamplingInfo& VDPixmapGetSamplingInfo(uint32 samplingToken) { + static const VDPixmapSamplingInfo kPixmapSamplingInfo[]={ + /* Null */ { false, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, + /* 444 */ { false, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, + /* 422 */ { false, { -4, 0, 1, 0 }, { -4, 0, 1, 0 } }, + /* 422_JPEG */ { false, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } }, + /* 420_MPEG2 */ { false, { -4, 0, 1, 1 }, { -4, 0, 1, 1 } }, + /* 420_MPEG2INT */ { true , { -4, -2, 1, 1 }, { -4, -2, 1, 1 }, { -4, +2, 1, 1 }, { -4, +2, 1, 1 } }, + /* 420_MPEG2INT1*/ { false, { -4, -2, 1, 1 }, { -4, -2, 1, 1 } }, + /* 420_MPEG2INT2*/ { false, { -4, +2, 1, 1 }, { -4, +2, 1, 1 } }, + /* 420_MPEG1 */ { false, { 0, 0, 1, 1 }, { 0, 0, 1, 1 } }, + /* 420_DVPAL */ { true , { -4, 0, 1, 1 }, { -4, 0, 1, 1 } }, + /* 411 */ { false, { -6, 0, 2, 0 }, { -6, 0, 2, 0 } }, + /* 410 */ { false, { -6, 0, 2, 2 }, { -6, 0, 2, 2 } }, + }; + + uint32 index = (samplingToken & kVDPixSamp_Mask) >> kVDPixSamp_Bits; + + return index >= sizeof(kPixmapSamplingInfo)/sizeof(kPixmapSamplingInfo[0]) ? kPixmapSamplingInfo[0] : kPixmapSamplingInfo[index]; +} + +namespace { + uint32 GetChromaPlaneBpr(uint32 w, uint32 srcToken) { + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_1: + case kVDPixType_2: + case kVDPixType_4: + case kVDPixType_8: + case kVDPixType_555_LE: + case kVDPixType_565_LE: + case kVDPixType_1555_LE: + case kVDPixType_16F_LE: + case kVDPixType_888: + case kVDPixType_8888: + case kVDPixType_16Fx4_LE: + case kVDPixType_32F_LE: + case kVDPixType_32Fx4_LE: + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + case kVDPixType_V210: + case kVDPixType_8_B8R8: + case kVDPixType_B8R8: + default: + return 0; + + case kVDPixType_8_8_8: + return w; + + case kVDPixType_16F_16F_16F_LE: + return w*2; + + case kVDPixType_32F_32F_32F_LE: + return w*4; + } + } + + void BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapSamplingInfo& dstInfo, const VDPixmapSamplingInfo& srcInfo, sint32 cw, sint32 ch); + void BlitterConvertPlaneSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapPlaneSamplingInfo& dstInfo, const VDPixmapPlaneSamplingInfo& srcInfo, sint32 cw, sint32 ch); + + uint32 BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, uint32 srcToken, uint32 dstSamplingToken, sint32 w, sint32 h) { + // if the source type is 16F, we have to convert to 32F + if ((srcToken & kVDPixType_Mask) == kVDPixType_16F_16F_16F_LE) { + // 0 1 2 + gen.conv_16F_to_32F(); + gen.swap(1); + // 1 0 2 + gen.conv_16F_to_32F(); + gen.swap(2); + // 2 0 1 + gen.conv_16F_to_32F(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + } + + // look up sampling info + const VDPixmapSamplingInfo& srcInfo = VDPixmapGetSamplingInfo(srcToken); + const VDPixmapSamplingInfo& dstInfo = VDPixmapGetSamplingInfo(dstSamplingToken); + + // Check if we have an interlacing mismatch. If so, then we have to convert up to + // full resolution vertically in order to split or merge fields. + const sint32 cw = -(-w >> dstInfo.mPlane1Cr.mXBits); + const sint32 ch = -(-h >> dstInfo.mPlane1Cr.mYBits); + const uint32 cbpr = GetChromaPlaneBpr(cw, srcToken); + + if (dstInfo.mbInterlaced || srcInfo.mbInterlaced) { + const sint32 src_cw = -(-w >> srcInfo.mPlane1Cr.mXBits); + + const sint32 ch1 = (ch + 1) >> 1; + const sint32 ch2 = ch >> 1; + + if (dstInfo.mbInterlaced) { + if (srcInfo.mbInterlaced) { + // interlaced -> interlaced: split fields, resample, merge fields + // + // cr y cb + gen.split_fields(cbpr); + + // cr-odd cr-even y cb + BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cr, srcInfo.mPlane2Cr, cw, ch2); + + // cr-odd' cr-even y cb + gen.swap(1); + + // cr-even cr-odd' y cb + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, srcInfo.mPlane1Cr, cw, ch1); + + // cr-even' cr-odd' y cb + gen.swap(1); + + // cr-odd' cr-even' y cb + gen.merge_fields(cw, ch, cbpr); + + // cr' y cb + gen.swap(2); + + // cb' y cr' + gen.split_fields(cbpr); + + // cb-odd cb-even y cr' + BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cb, srcInfo.mPlane2Cb, cw, ch2); + + // cb-odd' cb-even y cr' + gen.swap(1); + + // cb-even cb-odd' y cr' + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, srcInfo.mPlane1Cb, cw, ch1); + + // cb-even' cb-odd' y cr' + gen.swap(1); + + // cb-odd' cb-even' y cr' + gen.merge_fields(cw, ch, cbpr); + + // cb' y cr' + gen.swap(2); + + // cr' y cb' + } else { + // non-interlaced -> interlaced + VDPixmapPlaneSamplingInfo crPlaneInt(srcInfo.mPlane1Cr); + VDPixmapPlaneSamplingInfo crPlaneFieldInt(srcInfo.mPlane1Cr); + VDPixmapPlaneSamplingInfo cbPlaneInt(srcInfo.mPlane1Cb); + VDPixmapPlaneSamplingInfo cbPlaneFieldInt(srcInfo.mPlane1Cb); + + crPlaneInt.mX = dstInfo.mPlane1Cr.mX; + crPlaneInt.mXBits = dstInfo.mPlane1Cr.mXBits; + crPlaneInt.mY = 0; + crPlaneInt.mYBits = 0; + crPlaneFieldInt.mX = dstInfo.mPlane1Cr.mX; + crPlaneFieldInt.mXBits = dstInfo.mPlane1Cr.mXBits; + crPlaneFieldInt.mY = 0; + crPlaneFieldInt.mYBits = 0; + + cbPlaneInt.mX = dstInfo.mPlane1Cb.mX; + cbPlaneInt.mXBits = dstInfo.mPlane1Cb.mXBits; + cbPlaneFieldInt.mX = dstInfo.mPlane1Cb.mX; + cbPlaneFieldInt.mXBits = dstInfo.mPlane1Cb.mXBits; + cbPlaneFieldInt.mY = 0; + cbPlaneFieldInt.mYBits = 0; + + // cr y cb + BlitterConvertPlaneSampling(gen, crPlaneInt, srcInfo.mPlane1Cr, cw, h); + + // cr' y cb + gen.split_fields(cbpr); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, crPlaneFieldInt, cw, ch1); + gen.swap(1); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane2Cr, crPlaneFieldInt, cw, ch2); + gen.swap(1); + gen.merge_fields(cw, ch, cbpr); + + gen.swap(2); + BlitterConvertPlaneSampling(gen, cbPlaneInt, srcInfo.mPlane1Cb, cw, h); + gen.split_fields(cbpr); + gen.swap(1); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneFieldInt, cw, ch1); + gen.swap(1); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneFieldInt, cw, ch2); + gen.merge_fields(cw, ch, cbpr); + gen.swap(2); + } + } else { + sint32 src_cbpr = src_cw; + + // interlaced -> non-interlaced + VDPixmapPlaneSamplingInfo crPlaneFieldInt(srcInfo.mPlane1Cr); + VDPixmapPlaneSamplingInfo crPlaneInt(srcInfo.mPlane1Cr); + VDPixmapPlaneSamplingInfo cbPlaneFieldInt(srcInfo.mPlane1Cb); + VDPixmapPlaneSamplingInfo cbPlaneInt(srcInfo.mPlane1Cb); + + crPlaneFieldInt.mY = 0; + crPlaneFieldInt.mYBits = 0; + crPlaneInt.mY = 0; + crPlaneInt.mYBits = 0; + cbPlaneFieldInt.mY = 0; + cbPlaneFieldInt.mYBits = 0; + cbPlaneInt.mY = 0; + cbPlaneInt.mYBits = 0; + + // cr y cb + gen.split_fields(src_cbpr); + BlitterConvertPlaneSampling(gen, crPlaneFieldInt, srcInfo.mPlane1Cr, src_cw, (h + 1) >> 1); + gen.swap(1); + BlitterConvertPlaneSampling(gen, crPlaneFieldInt, srcInfo.mPlane2Cr, src_cw, h >> 1); + gen.swap(1); + gen.merge_fields(src_cw, h, src_cbpr); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, crPlaneInt, cw, ch); + gen.swap(2); + + // cr' y cb + gen.split_fields(src_cbpr); + BlitterConvertPlaneSampling(gen, cbPlaneFieldInt, srcInfo.mPlane1Cb, src_cw, (h + 1) >> 1); + gen.swap(1); + BlitterConvertPlaneSampling(gen, cbPlaneFieldInt, srcInfo.mPlane2Cb, src_cw, h >> 1); + gen.swap(1); + gen.merge_fields(src_cw, h, src_cbpr); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, cbPlaneInt, cw, ch); + gen.swap(2); + } + } else { + // non-interlaced -> non-interlaced + BlitterConvertSampling(gen, dstInfo, srcInfo, cw, ch); + } + + return (srcToken & ~kVDPixSamp_Mask) | (dstSamplingToken & kVDPixSamp_Mask); + } + + void BlitterConvertSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapSamplingInfo& dstInfo, const VDPixmapSamplingInfo& srcInfo, sint32 cw, sint32 ch) { + gen.swap(2); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cb, srcInfo.mPlane1Cb, cw, ch); + gen.swap(2); + BlitterConvertPlaneSampling(gen, dstInfo.mPlane1Cr, srcInfo.mPlane1Cr, cw, ch); + } + + void BlitterConvertPlaneSampling(VDPixmapUberBlitterGenerator& gen, const VDPixmapPlaneSamplingInfo& dstInfo, const VDPixmapPlaneSamplingInfo& srcInfo, sint32 cw, sint32 ch) { + // convert destination chroma origin to luma space + int c_x = ((8 + dstInfo.mX) << dstInfo.mXBits) - 8; + int c_y = ((8 + dstInfo.mY) << dstInfo.mYBits) - 8; + + // convert luma chroma location to source chroma space + c_x = ((8 + c_x) >> srcInfo.mXBits) - 8 - srcInfo.mX; + c_y = ((8 + c_y) >> srcInfo.mYBits) - 8 - srcInfo.mY; + + float cxo = c_x / 16.0f + 0.5f; + float cxf = ((16 << dstInfo.mXBits) >> srcInfo.mXBits) / 16.0f; + float cyf = ((16 << dstInfo.mYBits) >> srcInfo.mYBits) / 16.0f; + + gen.linear(cxo, cxf, cw, c_y / 16.0f + 0.5f, cyf, ch); + } + + uint32 BlitterConvertType(VDPixmapUberBlitterGenerator& gen, uint32 srcToken, uint32 dstToken, sint32 w, sint32 h) { + uint32 dstType = dstToken & kVDPixType_Mask; + + while((srcToken ^ dstToken) & kVDPixType_Mask) { + uint32 srcType = srcToken & kVDPixType_Mask; + uint32 targetType = dstType; + + type_reconvert: + switch(targetType) { + case kVDPixType_1555_LE: + switch(srcType) { + case kVDPixType_565_LE: + gen.conv_565_to_555(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_1555_LE; + break; + + case kVDPixType_8888: + gen.conv_8888_to_555(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_1555_LE; + break; + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + default: + targetType = kVDPixType_8888; + goto type_reconvert; + } + break; + + case kVDPixType_565_LE: + switch(srcType) { + case kVDPixType_1555_LE: + gen.conv_555_to_565(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_565_LE; + break; + case kVDPixType_8888: + gen.conv_8888_to_565(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_565_LE; + break; + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + default: + targetType = kVDPixType_8888; + goto type_reconvert; + } + break; + + case kVDPixType_888: + switch(srcType) { + case kVDPixType_8888: + gen.conv_8888_to_888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_888; + break; + default: + targetType = kVDPixType_8888; + goto type_reconvert; + } + break; + + case kVDPixType_8888: + switch(srcType) { + case kVDPixType_1555_LE: + gen.conv_555_to_8888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + case kVDPixType_565_LE: + gen.conv_565_to_8888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + case kVDPixType_888: + gen.conv_888_to_8888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + case kVDPixType_32Fx4_LE: + gen.conv_X32F_to_8888(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + case kVDPixType_8_8_8: + if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_444) + srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_444, w, h); + gen.interleave_X8R8G8B8(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8888; + break; + default: + VDASSERT(false); + break; + } + break; + + case kVDPixType_8: + switch(srcType) { + case kVDPixType_8_8_8: + gen.pop(); + gen.swap(1); + gen.pop(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + break; + + case kVDPixType_16F_LE: + targetType = kVDPixType_32F_LE; + goto type_reconvert; + + case kVDPixType_32F_LE: + gen.conv_32F_to_8(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + break; + + default: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + } + break; + + case kVDPixType_8_8_8: + switch(srcType) { + case kVDPixType_B8G8_R8G8: + gen.dup(); + gen.dup(); + gen.extract_8in32(2, (w + 1) >> 1, h); + gen.swap(2); + gen.extract_8in16(1, w, h); + gen.swap(1); + gen.extract_8in32(0, (w + 1) >> 1, h); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_8_8_8 | kVDPixSamp_422; + break; + case kVDPixType_G8B8_G8R8: + gen.dup(); + gen.dup(); + gen.extract_8in32(3, (w + 1) >> 1, h); + gen.swap(2); + gen.extract_8in16(0, w, h); + gen.swap(1); + gen.extract_8in32(1, (w + 1) >> 1, h); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_8_8_8 | kVDPixSamp_422; + break; + case kVDPixType_16F_16F_16F_LE: + case kVDPixType_V210: + targetType = kVDPixType_32F_32F_32F_LE; + goto type_reconvert; + case kVDPixType_32F_32F_32F_LE: + // 0 1 2 + gen.conv_32F_to_8(); + gen.swap(1); + // 1 0 2 + gen.conv_32F_to_8(); + gen.swap(2); + // 2 0 1 + gen.conv_32F_to_8(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + case kVDPixType_8_B8R8: + { + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + int cw = -(-w >> sampInfo.mPlane1Cr.mXBits); + int ch = -(-h >> sampInfo.mPlane1Cr.mYBits); + + gen.dup(); + gen.extract_8in16(1, cw, ch); + gen.swap(2); + gen.swap(1); + gen.extract_8in16(0, cw, ch); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + } + break; + default: + VDASSERT(false); + break; + } + break; + + case kVDPixType_B8G8_R8G8: + switch(srcType) { + case kVDPixType_8_8_8: + if ((srcToken ^ dstToken) & kVDPixSamp_Mask) + srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); + + gen.interleave_B8G8_R8G8(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_B8G8_R8G8; + break; + case kVDPixType_G8B8_G8R8: + gen.swap_8in16(w, h, ((w + 1) & ~1)*2); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_B8G8_R8G8; + break; + default: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + } + break; + + case kVDPixType_G8B8_G8R8: + switch(srcType) { + case kVDPixType_8_8_8: + if ((srcToken ^ dstToken) & kVDPixSamp_Mask) + srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); + + gen.interleave_G8B8_G8R8(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_G8B8_G8R8; + break; + case kVDPixType_B8G8_R8G8: + gen.swap_8in16(w, h, ((w + 1) & ~1)*2); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSamp_Mask)) | kVDPixType_G8B8_G8R8; + break; + default: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + } + break; + + case kVDPixType_16F_16F_16F_LE: + switch(srcType) { + case kVDPixType_32F_32F_32F_LE: + // 0 1 2 + gen.conv_32F_to_16F(); + gen.swap(1); + // 1 0 2 + gen.conv_32F_to_16F(); + gen.swap(2); + // 2 0 1 + gen.conv_32F_to_16F(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_16F_16F_LE; + break; + + default: + targetType = kVDPixType_32F_32F_32F_LE; + goto type_reconvert; + } + break; + + case kVDPixType_32F_32F_32F_LE: + switch(srcType) { + case kVDPixType_8_8_8: + // 0 1 2 + gen.conv_8_to_32F(); + gen.swap(1); + // 1 0 2 + gen.conv_8_to_32F(); + gen.swap(2); + // 2 0 1 + gen.conv_8_to_32F(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + break; + + case kVDPixType_16F_16F_16F_LE: + // 0 1 2 + gen.conv_16F_to_32F(); + gen.swap(1); + // 1 0 2 + gen.conv_16F_to_32F(); + gen.swap(2); + // 2 0 1 + gen.conv_16F_to_32F(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + break; + + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + case kVDPixType_8_B8R8: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + + case kVDPixType_V210: + gen.conv_V210_to_32F(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + break; + + default: + VDASSERT(false); + } + break; + + case kVDPixType_V210: + switch(srcType) { + case kVDPixType_32F_32F_32F_LE: + if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_422) + srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_422, w, h); + + gen.conv_32F_to_V210(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_V210; + break; + + case kVDPixType_16F_16F_16F_LE: + targetType = kVDPixType_32F_32F_32F_LE; + goto type_reconvert; + + case kVDPixType_8_8_8: + if ((srcToken & kVDPixSamp_Mask) != kVDPixSamp_422) + srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_422, w, h); + + targetType = kVDPixType_32F_32F_32F_LE; + goto type_reconvert; + + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + case kVDPixType_8_B8R8: + targetType = kVDPixType_8_8_8; + goto type_reconvert; + + default: + VDASSERT(false); + } + break; + + case kVDPixType_32F_LE: + switch(srcType) { + case kVDPixType_8: + gen.conv_8_to_32F(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + break; + case kVDPixType_16F_LE: + gen.conv_16F_to_32F(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + break; + default: + VDASSERT(false); + } + break; + + case kVDPixType_8_B8R8: + switch(srcType) { + case kVDPixType_8_8_8: + gen.swap(1); + gen.swap(2); + gen.interleave_B8R8(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_B8R8; + break; + default: + VDASSERT(false); + break; + } + break; + + default: + VDASSERT(false); + break; + } + } + + return srcToken; + } +} + +IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmap& dst, const VDPixmap& src) { + const VDPixmapLayout& dstlayout = VDPixmapToLayoutFromBase(dst, dst.data); + const VDPixmapLayout& srclayout = VDPixmapToLayoutFromBase(src, src.data); + + return VDPixmapCreateBlitter(dstlayout, srclayout); +} + +IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmapLayout& dst, const VDPixmapLayout& src) { + if (src.format == dst.format) { + return VDCreatePixmapUberBlitterDirectCopy(dst, src); + } + + uint32 srcToken = VDPixmapGetFormatTokenFromFormat(src.format); + uint32 dstToken = VDPixmapGetFormatTokenFromFormat(dst.format); + + VDPixmapUberBlitterGenerator gen; + + // load source channels + int w = src.w; + int h = src.h; + + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_1: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 7) >> 3); + break; + + case kVDPixType_2: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 3) >> 2); + break; + + case kVDPixType_4: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, (w + 1) >> 1); + break; + + case kVDPixType_8: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w); + break; + + case kVDPixType_555_LE: + case kVDPixType_565_LE: + case kVDPixType_1555_LE: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*2); + break; + + case kVDPixType_888: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*3); + break; + + case kVDPixType_8888: + case kVDPixType_32F_LE: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*4); + break; + + case kVDPixType_32Fx4_LE: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, w*16); + break; + + case kVDPixType_B8G8_R8G8: + case kVDPixType_G8B8_G8R8: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, ((w + 1) & ~1)*2); + break; + + case kVDPixType_8_8_8: + { + uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + + int cxbits = sampInfo.mPlane1Cb.mXBits; + int cybits = sampInfo.mPlane1Cb.mYBits; + int w2 = -(-w >> cxbits); + int h2 = -(-h >> cybits); + gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2); + gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w); + gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2); + } + break; + + case kVDPixType_16F_16F_16F_LE: + { + uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; + uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; + uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_16F_LE; + + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + + int cxbits = sampInfo.mPlane1Cb.mXBits; + int cybits = sampInfo.mPlane1Cb.mYBits; + int w2 = -(-w >> cxbits); + int h2 = -(-h >> cybits); + gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2 * 2); + gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w*2); + gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2 * 2); + } + break; + + case kVDPixType_32F_32F_32F_LE: + { + uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + uint32 cbtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + uint32 crtoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_LE; + + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + + int cxbits = sampInfo.mPlane1Cb.mXBits; + int cybits = sampInfo.mPlane1Cb.mYBits; + int w2 = -(-w >> cxbits); + int h2 = -(-h >> cybits); + gen.ldsrc(0, 2, 0, 0, w2, h2, cbtoken, w2 * 4); + gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w*4); + gen.ldsrc(0, 1, 0, 0, w2, h2, crtoken, w2 * 4); + } + break; + + case kVDPixType_V210: + gen.ldsrc(0, 0, 0, 0, w, h, srcToken, ((w + 5) / 6) * 4); + break; + + case kVDPixType_8_B8R8: + { + uint32 ytoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8; + uint32 ctoken = (srcToken & ~kVDPixType_Mask) | kVDPixType_B8R8; + + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + + int cxbits = sampInfo.mPlane1Cb.mXBits; + int cybits = sampInfo.mPlane1Cb.mYBits; + int w2 = -(-w >> cxbits); + int h2 = -(-h >> cybits); + gen.ldsrc(0, 0, 0, 0, w, h, ytoken, w); + gen.ldsrc(0, 1, 0, 0, w2, h2, ctoken, w2*2); + } + break; + + default: + VDASSERT(false); + } + + // check if we need a color space change + if ((srcToken ^ dstToken) & kVDPixSpace_Mask) { + // first, if we're dealing with an interleaved format, deinterleave it + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_B8G8_R8G8: + gen.dup(); + gen.dup(); + gen.extract_8in32(2, (w + 1) >> 1, h); + gen.swap(2); + gen.extract_8in16(1, w, h); + gen.swap(1); + gen.extract_8in32(0, (w + 1) >> 1, h); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + + case kVDPixType_G8B8_G8R8: + gen.dup(); + gen.dup(); + gen.extract_8in32(3, (w + 1) >> 1, h); + gen.swap(2); + gen.extract_8in16(0, w, h); + gen.swap(1); + gen.extract_8in32(1, (w + 1) >> 1, h); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + + case kVDPixType_8_B8R8: + gen.dup(); + gen.extract_8in16(1, (w + 1) >> 1, (h + 1) >> 1); + gen.swap(2); + gen.swap(1); + gen.extract_8in16(0, (w + 1) >> 1, (h + 1) >> 1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + + case kVDPixType_V210: + gen.conv_V210_to_32F(); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_32F_32F_32F_LE; + break; + } + + // if the source is subsampled, converge on 4:4:4 subsampling, but only if we actually need + // the auxiliary channels + const VDPixmapSamplingInfo& sampInfo = VDPixmapGetSamplingInfo(srcToken); + +#if 0 + // This check is currently disabled because we currently do need the chroma planes + // if we're doing a color space conversion, even if we are going to Y-only. + switch(dstToken & kVDPixSpace_Mask) { +// case kVDPixSpace_Y_601: +// case kVDPixSpace_Y_709: +// case kVDPixSpace_Y_601_FR: +// case kVDPixSpace_Y_709_FR: +// break; + + default: +#endif + if (sampInfo.mPlane1Cb.mXBits | + sampInfo.mPlane1Cb.mYBits | + sampInfo.mPlane1Cb.mX | + sampInfo.mPlane1Cb.mY | + sampInfo.mPlane1Cr.mX | + sampInfo.mPlane1Cr.mY) + srcToken = BlitterConvertSampling(gen, srcToken, kVDPixSamp_444, w, h); +#if 0 + break; + } +#endif + + // change color spaces + uint32 dstSpace = dstToken & kVDPixSpace_Mask; + while((srcToken ^ dstToken) & kVDPixSpace_Mask) { + uint32 srcSpace = srcToken & kVDPixSpace_Mask; + uint32 targetSpace = dstSpace; + +space_reconvert: + switch(targetSpace) { + case kVDPixSpace_BGR: + switch(srcSpace) { + case kVDPixSpace_YCC_709: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + gen.ycbcr709_to_rgb32(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_16F_16F_16F_LE: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_32F_32F_32F_LE, w, h); + gen.ycbcr709_to_rgb32_32f(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; + break; + + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr709_to_rgb32_32f(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_601: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + gen.ycbcr601_to_rgb32(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_16F_16F_16F_LE: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_32F_32F_32F_LE, w, h); + gen.ycbcr601_to_rgb32_32f(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; + break; + + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr601_to_rgb32_32f(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_32Fx4_LE; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_709_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + gen.ycbcr_to_rgb32_generic(g_VDPixmapGenYCbCrBasis_709, false); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_601_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + gen.ycbcr_to_rgb32_generic(g_VDPixmapGenYCbCrBasis_601, false); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_Y_601: + targetSpace = kVDPixSpace_YCC_601; + goto space_reconvert; + + case kVDPixSpace_Y_709: + targetSpace = kVDPixSpace_YCC_709; + goto space_reconvert; + + case kVDPixSpace_Y_601_FR: + targetSpace = kVDPixSpace_YCC_601_FR; + goto space_reconvert; + + case kVDPixSpace_Y_709_FR: + targetSpace = kVDPixSpace_YCC_709_FR; + goto space_reconvert; + + case kVDPixSpace_Pal: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_1: + gen.conv_Pal1_to_8888(0); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_2: + gen.conv_Pal2_to_8888(0); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_4: + gen.conv_Pal4_to_8888(0); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + case kVDPixType_8: + gen.conv_Pal8_to_8888(0); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_BGR | kVDPixType_8888; + break; + + default: + VDASSERT(false); + break; + } + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_Y_601: + switch(srcSpace) { + case kVDPixSpace_YCC_601: + gen.pop(); + gen.swap(1); + gen.pop(); + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_32F_32F_32F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; + break; + case kVDPixType_16F_16F_16F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; + break; + case kVDPixType_8_8_8: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + break; + + default: + VDASSERT(false); + } + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); + break; + + default: + targetSpace = kVDPixSpace_YCC_601; + goto space_reconvert; + } + break; + + case kVDPixSpace_Y_601_FR: + switch(srcSpace) { + case kVDPixSpace_YCC_601_FR: + gen.pop(); + gen.swap(1); + gen.pop(); + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_32F_32F_32F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; + break; + case kVDPixType_16F_16F_16F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; + break; + case kVDPixType_8_8_8: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + break; + + default: + VDASSERT(false); + } + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); + break; + + default: + targetSpace = kVDPixSpace_YCC_601_FR; + goto space_reconvert; + } + break; + + case kVDPixSpace_Y_709: + switch(srcSpace) { + case kVDPixSpace_YCC_709: + gen.pop(); + gen.swap(1); + gen.pop(); + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_32F_32F_32F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; + break; + case kVDPixType_16F_16F_16F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; + break; + case kVDPixType_8_8_8: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + break; + + default: + VDASSERT(false); + } + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); + break; + + default: + targetSpace = kVDPixSpace_YCC_709; + goto space_reconvert; + } + break; + + case kVDPixSpace_Y_709_FR: + switch(srcSpace) { + case kVDPixSpace_YCC_709_FR: + gen.pop(); + gen.swap(1); + gen.pop(); + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_32F_32F_32F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_32F_LE; + break; + case kVDPixType_16F_16F_16F_LE: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_16F_LE; + break; + case kVDPixType_8_8_8: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + break; + + default: + VDASSERT(false); + } + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8, w, h); + break; + + default: + targetSpace = kVDPixSpace_YCC_709_FR; + goto space_reconvert; + } + break; + + case kVDPixSpace_YCC_601: + switch(srcSpace) { + case kVDPixSpace_BGR: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); + gen.rgb32_to_ycbcr601(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_601 | kVDPixType_8_8_8; + break; + case kVDPixSpace_Y_601: + case kVDPixSpace_Y_709: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_601 | kVDPixType_8; + + { + const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); + int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; + int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; + + gen.ldconst(0x80, cw, cw, ch, srcToken); + } + + gen.dup(); + gen.swap(2); + gen.swap(1); + srcToken = kVDPixSpace_YCC_601 | kVDPixType_8_8_8 | (srcToken & kVDPixSamp_Mask); + break; + + case kVDPixSpace_Y_601_FR: + targetSpace = kVDPixSpace_YCC_601_FR; + goto space_reconvert; + + case kVDPixSpace_Y_709_FR: + targetSpace = kVDPixSpace_YCC_709_FR; + goto space_reconvert; + + case kVDPixSpace_YCC_709: + VDASSERT((srcToken & kVDPixType_Mask) == kVDPixType_8_8_8); + gen.ycbcr709_to_ycbcr601(); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; + break; + + case kVDPixSpace_YCC_601_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_601, true, g_VDPixmapGenYCbCrBasis_601, false, kVDPixSpace_YCC_601); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_709_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_601, true, g_VDPixmapGenYCbCrBasis_709, false, kVDPixSpace_YCC_601); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_601; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_Pal: + targetSpace = kVDPixSpace_BGR; + goto space_reconvert; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_709: + switch(srcSpace) { + case kVDPixSpace_BGR: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); + gen.rgb32_to_ycbcr709(); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_709 | kVDPixType_8_8_8; + break; + case kVDPixSpace_Y_601: + case kVDPixSpace_Y_709: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixSpace_YCC_709 | kVDPixType_8; + + { + const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); + int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; + int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; + + gen.ldconst(0x80, cw, cw, ch, srcToken); + } + + gen.dup(); + gen.swap(2); + gen.swap(1); + srcToken = kVDPixSpace_YCC_709 | kVDPixType_8_8_8 | (srcToken & kVDPixSamp_Mask); + break; + case kVDPixSpace_YCC_601: + if ((srcToken & kVDPixType_Mask) == kVDPixType_8_8_8) + gen.ycbcr601_to_ycbcr709(); + else + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_601, true, kVDPixSpace_YCC_709); + + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; + break; + + case kVDPixSpace_YCC_601_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_601, false, kVDPixSpace_YCC_709); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_709_FR: + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_32F_32F_32F_LE: + gen.ycbcr_to_ycbcr_generic(g_VDPixmapGenYCbCrBasis_709, true, g_VDPixmapGenYCbCrBasis_709, false, kVDPixSpace_YCC_709); + srcToken = (srcToken & ~kVDPixSpace_Mask) | kVDPixSpace_YCC_709; + break; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_Y_601_FR: + targetSpace = kVDPixSpace_YCC_601_FR; + goto space_reconvert; + + case kVDPixSpace_Y_709_FR: + targetSpace = kVDPixSpace_YCC_709_FR; + goto space_reconvert; + + case kVDPixSpace_Pal: + targetSpace = kVDPixSpace_BGR; + goto space_reconvert; + + default: + VDASSERT(false); + break; + } + break; + + case kVDPixSpace_YCC_601_FR: + case kVDPixSpace_YCC_709_FR: + { + const VDPixmapGenYCbCrBasis& dstBasis = *(targetSpace == kVDPixSpace_YCC_601_FR ? &g_VDPixmapGenYCbCrBasis_601 : &g_VDPixmapGenYCbCrBasis_709); + + switch(srcSpace) { + case kVDPixSpace_BGR: + srcToken = BlitterConvertType(gen, srcToken, kVDPixType_8888, w, h); + gen.rgb32_to_ycbcr_generic(dstBasis, false, targetSpace); + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8_8_8; + break; + case kVDPixSpace_Y_601_FR: + case kVDPixSpace_Y_709_FR: + srcToken = (srcToken & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | targetSpace | kVDPixType_8; + + { + const VDPixmapSamplingInfo& sinfo = VDPixmapGetSamplingInfo(srcToken); + int cw = ((w - 1) >> sinfo.mPlane1Cb.mXBits) + 1; + int ch = ((h - 1) >> sinfo.mPlane1Cb.mYBits) + 1; + + gen.ldconst(0x80, cw, cw, ch, srcToken); + } + + gen.dup(); + gen.swap(2); + gen.swap(1); + srcToken = (srcToken & ~kVDPixType_Mask) | kVDPixType_8_8_8; + break; + case kVDPixSpace_YCC_601: + gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_601, true, targetSpace); + srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; + break; + case kVDPixSpace_YCC_709: + gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_709, true, targetSpace); + srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; + break; + case kVDPixSpace_YCC_601_FR: + gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_601, false, targetSpace); + srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; + break; + case kVDPixSpace_YCC_709_FR: + gen.ycbcr_to_ycbcr_generic(dstBasis, false, g_VDPixmapGenYCbCrBasis_709, false, targetSpace); + srcToken = (srcToken & ~kVDPixSpace_Mask) | targetSpace; + break; + case kVDPixSpace_Pal: + targetSpace = kVDPixSpace_BGR; + goto space_reconvert; + + case kVDPixSpace_Y_601: + targetSpace = kVDPixSpace_YCC_601; + goto space_reconvert; + + case kVDPixSpace_Y_709: + targetSpace = kVDPixSpace_YCC_709; + goto space_reconvert; + + default: + VDASSERT(false); + break; + } + } + break; + + default: + VDASSERT(false); + break; + } + } + } + + // check if we need a type change + // + // Note: If the sampling is also different, we have to be careful about what types we + // target. The type conversion may itself involve a sampling conversion, so things get + // VERY tricky here. + if ((srcToken ^ dstToken) & kVDPixType_Mask) { + bool samplingDifferent = 0 != ((srcToken ^ dstToken) & kVDPixSamp_Mask); + uint32 intermediateTypeToken = dstToken & kVDPixType_Mask; + + if (samplingDifferent) { + switch(dstToken & kVDPixType_Mask) { + case kVDPixType_16F_16F_16F_LE: + intermediateTypeToken = kVDPixType_32F_32F_32F_LE; + break; + case kVDPixType_8_B8R8: + intermediateTypeToken = kVDPixType_8_8_8; + break; + } + } + + srcToken = BlitterConvertType(gen, srcToken, (dstToken & ~kVDPixType_Mask) | intermediateTypeToken, w, h); + } + + // convert subsampling if necessary + switch(srcToken & kVDPixType_Mask) { + case kVDPixType_8_8_8: + case kVDPixType_16F_16F_16F_LE: + case kVDPixType_32F_32F_32F_LE: + if ((srcToken ^ dstToken) & kVDPixSamp_Mask) + srcToken = BlitterConvertSampling(gen, srcToken, dstToken, w, h); + break; + } + + // check if we need a type change (possible with 16F) + srcToken = BlitterConvertType(gen, srcToken, dstToken, w, h); + + return gen.create(); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_16f.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_16f.cpp index be71be8232b..34422884b0d 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_16f.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_16f.cpp @@ -1,59 +1,59 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include "uberblit_16f.h" - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_32F_To_16F::Start() { - StartWindow(mWidth * sizeof(uint16)); -} - -uint32 VDPixmapGen_32F_To_16F::GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_16F_LE; -} - -void VDPixmapGen_32F_To_16F::Compute(void *dst0, sint32 y) { - uint16 *dst = (uint16 *)dst0; - const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); - uint32 w = mWidth; - - for(uint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; -} - -void VDPixmapGen_16F_To_32F::Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); - uint32 w = mWidth; - - for(uint32 i=0; i +#include +#include "uberblit_16f.h" + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_32F_To_16F::Start() { + StartWindow(mWidth * sizeof(uint16)); +} + +uint32 VDPixmapGen_32F_To_16F::GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_16F_LE; +} + +void VDPixmapGen_32F_To_16F::Compute(void *dst0, sint32 y) { + uint16 *dst = (uint16 *)dst0; + const float *src = (const float *)mpSrc->GetRow(y, mSrcIndex); + uint32 w = mWidth; + + for(uint32 i=0; iGetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; +} + +void VDPixmapGen_16F_To_32F::Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const uint16 *src = (const uint16 *)mpSrc->GetRow(y, mSrcIndex); + uint32 w = mWidth; + + for(uint32 i=0; i -#include -#include -#include "uberblit.h" -#include "uberblit_gen.h" -#include "uberblit_fill.h" -#include "uberblit_input.h" -#include "uberblit_resample.h" -#include "uberblit_resample_special.h" -#include "uberblit_ycbcr.h" -#include "uberblit_ycbcr_generic.h" -#include "uberblit_rgb.h" -#include "uberblit_swizzle.h" -#include "uberblit_pal.h" -#include "uberblit_16f.h" -#include "uberblit_v210.h" -#include "uberblit_interlace.h" - -#ifdef VD_CPU_X86 - #include "uberblit_swizzle_x86.h" - #include "uberblit_ycbcr_x86.h" - #include "uberblit_rgb_x86.h" - #include "uberblit_resample_special_x86.h" -#endif - -void VDPixmapGenerate(void *dst, ptrdiff_t pitch, sint32 bpr, sint32 height, IVDPixmapGen *gen, int genIndex) { - for(sint32 y=0; yGetRow(y, genIndex), bpr); - vdptrstep(dst, pitch); - } - VDCPUCleanupExtensions(); -} - -void VDPixmapGenerateFast(void *dst, ptrdiff_t pitch, sint32 height, IVDPixmapGen *gen) { - for(sint32 y=0; yProcessRow(dst, y); - vdptrstep(dst, pitch); - } - VDCPUCleanupExtensions(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmap& dst, const VDPixmap& src) { - return new VDPixmapUberBlitterDirectCopy; -} - -IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmapLayout& dst, const VDPixmapLayout& src) { - return new VDPixmapUberBlitterDirectCopy; -} - -VDPixmapUberBlitterDirectCopy::VDPixmapUberBlitterDirectCopy() { -} - -VDPixmapUberBlitterDirectCopy::~VDPixmapUberBlitterDirectCopy() { -} - -void VDPixmapUberBlitterDirectCopy::Blit(const VDPixmap& dst, const VDPixmap& src) { - Blit(dst, NULL, src); -} - -void VDPixmapUberBlitterDirectCopy::Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) { - VDASSERT(dst.format == src.format); - - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); - - void *p = dst.data; - void *p2 = dst.data2; - void *p3 = dst.data3; - int w = std::min(dst.w, src.w); - int h = std::min(dst.h, src.h); - - if (formatInfo.qchunky) { - w = (w + formatInfo.qw - 1) / formatInfo.qw; - h = -(-h >> formatInfo.qhbits); - } - - int w2 = -(-dst.w >> formatInfo.auxwbits); - int h2 = -(-dst.h >> formatInfo.auxhbits); - - if (rDst) { - int x1 = rDst->left; - int y1 = rDst->top; - int x2 = rDst->right; - int y2 = rDst->bottom; - - VDASSERT(x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h && x2 >= x1 && y2 >= y1); - - if (x2 < x1 || y2 < y1) - return; - - p = vdptroffset(dst.data, dst.pitch * y1 + x1 * formatInfo.qsize); - w = x2 - x1; - h = y2 - y1; - - if (formatInfo.auxbufs >= 1) { - VDASSERT(!((x1|x2) & ((1 << formatInfo.auxwbits) - 1))); - VDASSERT(!((y1|y2) & ((1 << formatInfo.auxhbits) - 1))); - - int ax1 = x1 >> formatInfo.auxwbits; - int ay1 = y1 >> formatInfo.auxhbits; - int ax2 = x2 >> formatInfo.auxwbits; - int ay2 = y2 >> formatInfo.auxhbits; - - p2 = vdptroffset(dst.data2, dst.pitch2 * ay1 + ax1); - w2 = ax2 - ax1; - h2 = ay2 - ay1; - - if (formatInfo.auxbufs >= 2) - p3 = vdptroffset(dst.data3, dst.pitch3 * ay1 + ax1); - } - } - - uint32 bpr = formatInfo.qsize * w; - - VDMemcpyRect(p, dst.pitch, src.data, src.pitch, bpr, h); - - if (formatInfo.auxbufs >= 1) { - VDMemcpyRect(p2, dst.pitch2, src.data2, src.pitch2, w2 * formatInfo.auxsize, h2); - - if (formatInfo.auxbufs >= 2) - VDMemcpyRect(p3, dst.pitch3, src.data3, src.pitch3, w2 * formatInfo.auxsize, h2); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -VDPixmapUberBlitter::VDPixmapUberBlitter() { -} - -VDPixmapUberBlitter::~VDPixmapUberBlitter() { - while(!mGenerators.empty()) { - delete mGenerators.back(); - mGenerators.pop_back(); - } -} - -void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const VDPixmap& src) { - Blit(dst, NULL, src); -} - -void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) { - for(Sources::const_iterator it(mSources.begin()), itEnd(mSources.end()); it!=itEnd; ++it) { - const SourceEntry& se = *it; - const void *p; - ptrdiff_t pitch; - - switch(se.mSrcPlane) { - case 0: - p = src.data; - pitch = src.pitch; - break; - case 1: - p = src.data2; - pitch = src.pitch2; - break; - case 2: - p = src.data3; - pitch = src.pitch3; - break; - default: - VDASSERT(false); - break; - } - - se.mpSrc->SetSource((const char *)p + pitch*se.mSrcY + se.mSrcX, pitch, src.palette); - } - - if (mOutputs[2].mpSrc) { - if (mbIndependentPlanes) - Blit3Separated(dst, rDst); - else if (mbIndependentChromaPlanes) - Blit3Split(dst, rDst); - else - Blit3(dst, rDst); - } else if (mOutputs[1].mpSrc) { - if (mbIndependentPlanes) - Blit2Separated(dst, rDst); - else - Blit2(dst, rDst); - } else - Blit(dst, rDst); -} - -void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); - - mOutputs[0].mpSrc->AddWindowRequest(0, 0); - mOutputs[0].mpSrc->Start(); - - void *p = dst.data; - int w = dst.w; - int h = dst.h; - - if (formatInfo.qchunky) { - w = (w + formatInfo.qw - 1) / formatInfo.qw; - h = -(-h >> formatInfo.qhbits); - } - - if (rDst) { - int x1 = rDst->left; - int y1 = rDst->top; - int x2 = rDst->right; - int y2 = rDst->bottom; - - if (formatInfo.qchunky) { - x1 = x1 / formatInfo.qw; - y1 = y1 / formatInfo.qh; - x2 = (x2 + formatInfo.qw - 1) / formatInfo.qw; - y2 = (y2 + formatInfo.qh - 1) / formatInfo.qh; - } - - VDASSERT(x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h && x2 >= x1 && y2 >= y1); - - if (x2 < x1 || y2 < y1) - return; - - p = vdptroffset(dst.data, dst.pitch * y1 + x1 * formatInfo.qsize); - w = x2 - x1; - h = y2 - y1; - } - - uint32 bpr = formatInfo.qsize * w; - - if (mOutputs[0].mSrcIndex == 0) - VDPixmapGenerateFast(p, dst.pitch, h, mOutputs[0].mpSrc); - else - VDPixmapGenerate(p, dst.pitch, bpr, h, mOutputs[0].mpSrc, mOutputs[0].mSrcIndex); -} - -void VDPixmapUberBlitter::Blit3(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[1].mpSrc; - int idx = mOutputs[1].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[2].mpSrc; - int idx1 = mOutputs[2].mSrcIndex; - IVDPixmapGen *gen2 = mOutputs[0].mpSrc; - int idx2 = mOutputs[0].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - gen2->AddWindowRequest(0, 0); - gen2->Start(); - - uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; - uint32 auxaccum = 0; - - auxstep += auxstep; - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint32 bpr2 = formatInfo.auxsize * -(-px.w >> formatInfo.auxwbits); - uint8 *dst = (uint8 *)px.data; - uint8 *dst2 = (uint8 *)px.data2; - uint8 *dst3 = (uint8 *)px.data3; - ptrdiff_t pitch = px.pitch; - ptrdiff_t pitch2 = px.pitch2; - ptrdiff_t pitch3 = px.pitch3; - uint32 y2 = 0; - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - - if (!auxaccum) { - memcpy(dst2, gen1->GetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - memcpy(dst3, gen2->GetRow(y2, idx2), bpr2); - vdptrstep(dst3, pitch3); - ++y2; - } - - auxaccum += auxstep; - } - - VDCPUCleanupExtensions(); -} - -void VDPixmapUberBlitter::Blit3Split(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[1].mpSrc; - int idx = mOutputs[1].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[2].mpSrc; - int idx1 = mOutputs[2].mSrcIndex; - IVDPixmapGen *gen2 = mOutputs[0].mpSrc; - int idx2 = mOutputs[0].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - gen2->AddWindowRequest(0, 0); - gen2->Start(); - - uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; - uint32 auxaccum = 0; - - auxstep += auxstep; - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint8 *dst = (uint8 *)px.data; - ptrdiff_t pitch = px.pitch; - - if (idx == 0) { - for(uint32 y=0; yProcessRow(dst, y); - vdptrstep(dst, pitch); - } - } else { - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - } - } - - uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; - uint8 *dst2 = (uint8 *)px.data2; - uint8 *dst3 = (uint8 *)px.data3; - ptrdiff_t pitch2 = px.pitch2; - ptrdiff_t pitch3 = px.pitch3; - uint32 y2 = 0; - for(uint32 y=0; yGetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - memcpy(dst3, gen2->GetRow(y2, idx2), bpr2); - vdptrstep(dst3, pitch3); - ++y2; - } - - auxaccum += auxstep; - } - - VDCPUCleanupExtensions(); -} - -void VDPixmapUberBlitter::Blit3Separated(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[1].mpSrc; - int idx = mOutputs[1].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[2].mpSrc; - int idx1 = mOutputs[2].mSrcIndex; - IVDPixmapGen *gen2 = mOutputs[0].mpSrc; - int idx2 = mOutputs[0].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - gen2->AddWindowRequest(0, 0); - gen2->Start(); - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint8 *dst = (uint8 *)px.data; - ptrdiff_t pitch = px.pitch; - - if (idx == 0) { - for(uint32 y=0; yProcessRow(dst, y); - vdptrstep(dst, pitch); - } - } else { - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - } - } - - uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; - uint32 h2 = -(-px.h >> formatInfo.auxhbits); - uint8 *dst2 = (uint8 *)px.data2; - ptrdiff_t pitch2 = px.pitch2; - if (idx1 == 0) { - for(uint32 y2=0; y2ProcessRow(dst2, y2); - vdptrstep(dst2, pitch2); - } - } else { - for(uint32 y2=0; y2GetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - } - } - - uint8 *dst3 = (uint8 *)px.data3; - ptrdiff_t pitch3 = px.pitch3; - if (idx2 == 0) { - for(uint32 y2=0; y2ProcessRow(dst3, y2); - vdptrstep(dst3, pitch3); - } - } else { - for(uint32 y2=0; y2GetRow(y2, idx2), bpr2); - vdptrstep(dst3, pitch3); - } - } - - VDCPUCleanupExtensions(); -} - -void VDPixmapUberBlitter::Blit2(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[0].mpSrc; - int idx = mOutputs[0].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[1].mpSrc; - int idx1 = mOutputs[1].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - - uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; - uint32 auxaccum = 0; - - auxstep += auxstep; - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint32 bpr2 = formatInfo.auxsize * -(-px.w >> formatInfo.auxwbits); - uint8 *dst = (uint8 *)px.data; - uint8 *dst2 = (uint8 *)px.data2; - ptrdiff_t pitch = px.pitch; - ptrdiff_t pitch2 = px.pitch2; - uint32 y2 = 0; - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - - if (!auxaccum) { - memcpy(dst2, gen1->GetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - ++y2; - } - - auxaccum += auxstep; - } - - VDCPUCleanupExtensions(); -} - -void VDPixmapUberBlitter::Blit2Separated(const VDPixmap& px, const vdrect32 *rDst) { - const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); - IVDPixmapGen *gen = mOutputs[0].mpSrc; - int idx = mOutputs[0].mSrcIndex; - IVDPixmapGen *gen1 = mOutputs[1].mpSrc; - int idx1 = mOutputs[1].mSrcIndex; - - gen->AddWindowRequest(0, 0); - gen->Start(); - gen1->AddWindowRequest(0, 0); - gen1->Start(); - - int qw = px.w; - int qh = px.h; - - if (formatInfo.qchunky) { - qw = (qw + formatInfo.qw - 1) / formatInfo.qw; - qh = -(-qh >> formatInfo.qhbits); - } - - uint32 height = qh; - uint32 bpr = formatInfo.qsize * qw; - uint8 *dst = (uint8 *)px.data; - ptrdiff_t pitch = px.pitch; - - if (idx == 0) { - for(uint32 y=0; yProcessRow(dst, y); - vdptrstep(dst, pitch); - } - } else { - for(uint32 y=0; yGetRow(y, idx), bpr); - vdptrstep(dst, pitch); - } - } - - uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; - uint32 h2 = -(-px.h >> formatInfo.auxhbits); - uint8 *dst2 = (uint8 *)px.data2; - ptrdiff_t pitch2 = px.pitch2; - if (idx1 == 0) { - for(uint32 y2=0; y2ProcessRow(dst2, y2); - vdptrstep(dst2, pitch2); - } - } else { - for(uint32 y2=0; y2GetRow(y2, idx1), bpr2); - vdptrstep(dst2, pitch2); - } - } - - VDCPUCleanupExtensions(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -VDPixmapUberBlitterGenerator::VDPixmapUberBlitterGenerator() { -} - -VDPixmapUberBlitterGenerator::~VDPixmapUberBlitterGenerator() { - while(!mGenerators.empty()) { - delete mGenerators.back(); - mGenerators.pop_back(); - } -} - -void VDPixmapUberBlitterGenerator::swap(int index) { - std::swap(mStack.back(), (&mStack.back())[-index]); -} - -void VDPixmapUberBlitterGenerator::dup() { - mStack.push_back(mStack.back()); -} - -void VDPixmapUberBlitterGenerator::pop() { - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::ldsrc(int srcIndex, int srcPlane, int x, int y, uint32 w, uint32 h, uint32 type, uint32 bpr) { - VDPixmapGenSrc *src = new VDPixmapGenSrc; - - src->Init(w, h, type, bpr); - - mGenerators.push_back(src); - mStack.push_back(StackEntry(src, 0)); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = srcPlane; - se.mSrcX = x; - se.mSrcY = y; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::ldconst(uint8 fill, uint32 bpr, uint32 w, uint32 h, uint32 type) { - VDPixmapGenFill8 *src = new VDPixmapGenFill8; - - src->Init(fill, bpr, w, h, type); - - mGenerators.push_back(src); - mStack.push_back(StackEntry(src, 0)); -} - -void VDPixmapUberBlitterGenerator::extract_8in16(int offset, uint32 w, uint32 h) { - StackEntry *args = &mStack.back(); - VDPixmapGen_8In16 *src = NULL; - -#if VD_CPU_X86 - if (MMX_enabled) { - if (offset == 0) - src = new VDPixmapGen_8In16_Even_MMX; - else if (offset == 1) - src = new VDPixmapGen_8In16_Odd_MMX; - } -#endif - if (!src) - src = new VDPixmapGen_8In16; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, offset, w, h); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::extract_8in32(int offset, uint32 w, uint32 h) { - StackEntry *args = &mStack.back(); - VDPixmapGen_8In32 *src = NULL; - -#if VD_CPU_X86 - if (MMX_enabled) { - if ((unsigned)offset < 4) - src = new VDPixmapGen_8In32_MMX; - } -#endif - - if (!src) - src = new VDPixmapGen_8In32; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, offset, w, h); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::swap_8in16(uint32 w, uint32 h, uint32 bpr) { - StackEntry *args = &mStack.back(); - -#if VD_CPU_X86 - VDPixmapGen_Swap8In16 *src = MMX_enabled ? new VDPixmapGen_Swap8In16_MMX : new VDPixmapGen_Swap8In16; -#else - VDPixmapGen_Swap8In16 *src = new VDPixmapGen_Swap8In16; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex, w, h, bpr); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_Pal1_to_8888(int srcIndex) { - StackEntry *args = &mStack.back(); - VDPixmapGen_Pal1_To_X8R8G8B8 *src = new VDPixmapGen_Pal1_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = 0; - se.mSrcX = 0; - se.mSrcY = 0; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::conv_Pal2_to_8888(int srcIndex) { - StackEntry *args = &mStack.back(); - VDPixmapGen_Pal2_To_X8R8G8B8 *src = new VDPixmapGen_Pal2_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = 0; - se.mSrcX = 0; - se.mSrcY = 0; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::conv_Pal4_to_8888(int srcIndex) { - StackEntry *args = &mStack.back(); - VDPixmapGen_Pal4_To_X8R8G8B8 *src = new VDPixmapGen_Pal4_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = 0; - se.mSrcX = 0; - se.mSrcY = 0; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::conv_Pal8_to_8888(int srcIndex) { - StackEntry *args = &mStack.back(); - VDPixmapGen_Pal8_To_X8R8G8B8 *src = new VDPixmapGen_Pal8_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - - SourceEntry se; - se.mpSrc = src; - se.mSrcIndex = srcIndex; - se.mSrcPlane = 0; - se.mSrcX = 0; - se.mSrcY = 0; - mSources.push_back(se); -} - -void VDPixmapUberBlitterGenerator::pointh(float xoffset, float xfactor, uint32 w) { - StackEntry *args = &mStack.back(); - - if (xoffset != 0.5f || xfactor != 1.0f) { - VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterPoint, 0, false); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::pointv(float yoffset, float yfactor, uint32 h) { - StackEntry *args = &mStack.back(); - - if (yoffset != 0.5f || yfactor != 1.0f) { - VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterPoint, 0, false); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::linearh(float xoffset, float xfactor, uint32 w, bool interpOnly) { - StackEntry *args = &mStack.back(); - IVDPixmapGen *src = args[0].mpSrc; - int srcIndex = args[0].mSrcIndex; - - sint32 srcw = src->GetWidth(srcIndex); - if (xoffset == 0.5f && xfactor == 1.0f && srcw == w) - return; - - if (xoffset == 0.5f && (src->GetType(srcIndex) & kVDPixType_Mask) == kVDPixType_8) { - if (xfactor == 2.0f && w == ((srcw + 1) >> 1)) { - VDPixmapGenResampleRow_d2_p0_lin_u8 *out = new VDPixmapGenResampleRow_d2_p0_lin_u8; - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (xfactor == 4.0f && w == ((srcw + 3) >> 2)) { - VDPixmapGenResampleRow_d4_p0_lin_u8 *out = new VDPixmapGenResampleRow_d4_p0_lin_u8; - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (xfactor == 0.5f && w == srcw*2) { -#if VD_CPU_X86 - VDPixmapGenResampleRow_x2_p0_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE : new VDPixmapGenResampleRow_x2_p0_lin_u8; -#else - VDPixmapGenResampleRow_x2_p0_lin_u8 *out = new VDPixmapGenResampleRow_x2_p0_lin_u8; -#endif - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (xfactor == 0.25f && w == srcw*4) { -#if VD_CPU_X86 - VDPixmapGenResampleRow_x4_p0_lin_u8 *out = MMX_enabled ? new VDPixmapGenResampleRow_x4_p0_lin_u8_MMX : new VDPixmapGenResampleRow_x4_p0_lin_u8; -#else - VDPixmapGenResampleRow_x4_p0_lin_u8 *out = new VDPixmapGenResampleRow_x4_p0_lin_u8; -#endif - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - } - - VDPixmapGenResampleRow *out = new VDPixmapGenResampleRow; - - out->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterLinear, 0, interpOnly); - - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); -} - -void VDPixmapUberBlitterGenerator::linearv(float yoffset, float yfactor, uint32 h, bool interpOnly) { - StackEntry *args = &mStack.back(); - IVDPixmapGen *src = args[0].mpSrc; - int srcIndex = args[0].mSrcIndex; - - sint32 srch = src->GetHeight(srcIndex); - if (yoffset == 0.5f && yfactor == 1.0f && srch == h) - return; - - if ((src->GetType(srcIndex) & kVDPixType_Mask) == kVDPixType_8) { - if (yoffset == 1.0f && yfactor == 2.0f && h == ((srch + 1) >> 1)) { - VDPixmapGenResampleCol_x2_phalf_lin_u8 *out = new VDPixmapGenResampleCol_x2_phalf_lin_u8; - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (yoffset == 2.0f && yfactor == 4.0f && h == ((srch + 2) >> 2)) { - VDPixmapGenResampleCol_x4_p1half_lin_u8 *out = new VDPixmapGenResampleCol_x4_p1half_lin_u8; - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (yoffset == 0.25f && yfactor == 0.5f && h == srch*2) { -#if VD_CPU_X86 - VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE : new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8; -#else - VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 *out = new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8; -#endif - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - - if (yoffset == 0.125f && yfactor == 0.25f && h == srch*4) { -#if VD_CPU_X86 - VDPixmapGenResampleCol_d4_pn38_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE : new VDPixmapGenResampleCol_d4_pn38_lin_u8; -#else - VDPixmapGenResampleCol_d4_pn38_lin_u8 *out = new VDPixmapGenResampleCol_d4_pn38_lin_u8; -#endif - - out->Init(src, srcIndex); - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); - return; - } - } - - VDPixmapGenResampleCol *out = new VDPixmapGenResampleCol; - - out->Init(src, srcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterLinear, 0, interpOnly); - - mGenerators.push_back(out); - MarkDependency(out, src); - args[0] = StackEntry(out, 0); -} - -void VDPixmapUberBlitterGenerator::linear(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h) { - linearh(xoffset, xfactor, w, false); - linearv(yoffset, yfactor, h, false); -} - -void VDPixmapUberBlitterGenerator::cubich(float xoffset, float xfactor, uint32 w, float splineFactor, bool interpOnly) { - StackEntry *args = &mStack.back(); - - if (xoffset != 0.5f || xfactor != 1.0f) { - VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterCubic, splineFactor, interpOnly); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::cubicv(float yoffset, float yfactor, uint32 h, float splineFactor, bool interpOnly) { - StackEntry *args = &mStack.back(); - - if (yoffset != 0.5f || yfactor != 1.0f) { - VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterCubic, splineFactor, interpOnly); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::cubic(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h, float splineFactor) { - cubich(xoffset, xfactor, w, splineFactor, false); - cubicv(yoffset, yfactor, h, splineFactor, false); -} - -void VDPixmapUberBlitterGenerator::lanczos3h(float xoffset, float xfactor, uint32 w) { - StackEntry *args = &mStack.back(); - - if (xoffset != 0.5f || xfactor != 1.0f) { - VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterLanczos3, 0, false); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::lanczos3v(float yoffset, float yfactor, uint32 h) { - StackEntry *args = &mStack.back(); - - if (yoffset != 0.5f || yfactor != 1.0f) { - VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterLanczos3, 0, false); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - } -} - -void VDPixmapUberBlitterGenerator::lanczos3(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h) { - lanczos3h(xoffset, xfactor, w); - lanczos3v(yoffset, yfactor, h); -} - -void VDPixmapUberBlitterGenerator::conv_555_to_8888() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X1R5G5B5_To_X8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_X1R5G5B5_To_X8R8G8B8_MMX : new VDPixmapGen_X1R5G5B5_To_X8R8G8B8; -#else - VDPixmapGen_X1R5G5B5_To_X8R8G8B8 *src = new VDPixmapGen_X1R5G5B5_To_X8R8G8B8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_565_to_8888() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_R5G6B5_To_X8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_R5G6B5_To_X8R8G8B8_MMX : new VDPixmapGen_R5G6B5_To_X8R8G8B8; -#else - VDPixmapGen_R5G6B5_To_X8R8G8B8 *src = new VDPixmapGen_R5G6B5_To_X8R8G8B8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_888_to_8888() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_R8G8B8_To_A8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_R8G8B8_To_X8R8G8B8_MMX : new VDPixmapGen_R8G8B8_To_A8R8G8B8; -#else - VDPixmapGen_R8G8B8_To_A8R8G8B8 *src = new VDPixmapGen_R8G8B8_To_A8R8G8B8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_8_to_32F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_8_To_32F *src = new VDPixmapGen_8_To_32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_16F_to_32F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_16F_To_32F *src = new VDPixmapGen_16F_To_32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_V210_to_32F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_V210_To_32F *src = new VDPixmapGen_V210_To_32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::conv_8888_to_X32F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X8R8G8B8_To_X32B32G32R32F *src = new VDPixmapGen_X8R8G8B8_To_X32B32G32R32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_8888_to_555() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X8R8G8B8_To_X1R5G5B5 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_X1R5G5B5_MMX : new VDPixmapGen_X8R8G8B8_To_X1R5G5B5; -#else - VDPixmapGen_X8R8G8B8_To_X1R5G5B5 *src = new VDPixmapGen_X8R8G8B8_To_X1R5G5B5; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_555_to_565() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X1R5G5B5_To_R5G6B5 *src = MMX_enabled ? new VDPixmapGen_X1R5G5B5_To_R5G6B5_MMX : new VDPixmapGen_X1R5G5B5_To_R5G6B5; -#else - VDPixmapGen_X1R5G5B5_To_R5G6B5 *src = new VDPixmapGen_X1R5G5B5_To_R5G6B5; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_565_to_555() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_R5G6B5_To_X1R5G5B5 *src = MMX_enabled ? new VDPixmapGen_R5G6B5_To_X1R5G5B5_MMX : new VDPixmapGen_R5G6B5_To_X1R5G5B5; -#else - VDPixmapGen_R5G6B5_To_X1R5G5B5 *src = new VDPixmapGen_R5G6B5_To_X1R5G5B5; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_8888_to_565() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X8R8G8B8_To_R5G6B5 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_R5G6B5_MMX : new VDPixmapGen_X8R8G8B8_To_R5G6B5; -#else - VDPixmapGen_X8R8G8B8_To_R5G6B5 *src = new VDPixmapGen_X8R8G8B8_To_R5G6B5; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_8888_to_888() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGen_X8R8G8B8_To_R8G8B8 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_R8G8B8_MMX : new VDPixmapGen_X8R8G8B8_To_R8G8B8; -#else - VDPixmapGen_X8R8G8B8_To_R8G8B8 *src = new VDPixmapGen_X8R8G8B8_To_R8G8B8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_32F_to_8() { - StackEntry *args = &mStack.back(); - VDPixmapGen_32F_To_8 *src = new VDPixmapGen_32F_To_8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_X32F_to_8888() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X32B32G32R32F_To_X8R8G8B8 *src = new VDPixmapGen_X32B32G32R32F_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_32F_to_16F() { - StackEntry *args = &mStack.back(); - VDPixmapGen_32F_To_16F *src = new VDPixmapGen_32F_To_16F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::conv_32F_to_V210() { - StackEntry *args = &*(mStack.end() - 3); - VDPixmapGen_32F_To_V210 *src = new VDPixmapGen_32F_To_V210; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::convd_8888_to_555() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X8R8G8B8_To_X1R5G5B5_Dithered *src = new VDPixmapGen_X8R8G8B8_To_X1R5G5B5_Dithered; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::convd_8888_to_565() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered *src = new VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::convd_32F_to_8() { - StackEntry *args = &mStack.back(); - VDPixmapGen_32F_To_8_Dithered *src = new VDPixmapGen_32F_To_8_Dithered; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::convd_X32F_to_8888() { - StackEntry *args = &mStack.back(); - VDPixmapGen_X32B32G32R32F_To_X8R8G8B8_Dithered *src = new VDPixmapGen_X32B32G32R32F_To_X8R8G8B8_Dithered; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); -} - -void VDPixmapUberBlitterGenerator::interleave_B8G8_R8G8() { - StackEntry *args = &mStack.back() - 2; - VDPixmapGen_B8x3_To_B8G8_R8G8 *src = NULL; - -#if VD_CPU_X86 - if (MMX_enabled) - src = new VDPixmapGen_B8x3_To_B8G8_R8G8_MMX; -#endif - - if (!src) - src = new VDPixmapGen_B8x3_To_B8G8_R8G8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::interleave_G8B8_G8R8() { - StackEntry *args = &mStack.back() - 2; - VDPixmapGen_B8x3_To_G8B8_G8R8 *src = NULL; - -#if VD_CPU_X86 - if (MMX_enabled) - src = new VDPixmapGen_B8x3_To_G8B8_G8R8_MMX; -#endif - - if (!src) - src = new VDPixmapGen_B8x3_To_G8B8_G8R8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::interleave_X8R8G8B8() { - StackEntry *args = &mStack.back() - 2; - VDPixmapGen_B8x3_To_X8R8G8B8 *src = new VDPixmapGen_B8x3_To_X8R8G8B8; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::interleave_B8R8() { - StackEntry *args = &mStack.back() - 1; - -#if VD_CPU_X86 - VDPixmapGen_B8x2_To_B8R8 *src = MMX_enabled ? new VDPixmapGen_B8x2_To_B8R8_MMX : new VDPixmapGen_B8x2_To_B8R8; -#else - VDPixmapGen_B8x2_To_B8R8 *src = new VDPixmapGen_B8x2_To_B8R8; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::merge_fields(uint32 w, uint32 h, uint32 bpr) { - StackEntry *args = &mStack.back() - 1; - - VDPixmapGen_MergeFields *src = new VDPixmapGen_MergeFields; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, w, h, bpr); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::split_fields(uint32 bpr) { - StackEntry *args = &mStack.back(); - - VDPixmapGen_SplitFields *src = new VDPixmapGen_SplitFields; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, bpr); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); -} - -void VDPixmapUberBlitterGenerator::ycbcr601_to_rgb32() { - StackEntry *args = &mStack.back() - 2; - -#ifdef VD_CPU_X86 - VDPixmapGenYCbCr601ToRGB32 *src = MMX_enabled ? new VDPixmapGenYCbCr601ToRGB32_MMX : new VDPixmapGenYCbCr601ToRGB32; -#else - VDPixmapGenYCbCr601ToRGB32 *src = new VDPixmapGenYCbCr601ToRGB32; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::ycbcr709_to_rgb32() { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCr709ToRGB32 *src = new VDPixmapGenYCbCr709ToRGB32; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr601() { - StackEntry *args = &mStack.back(); -#ifdef VD_CPU_X86 - VDPixmapGenRGB32ToYCbCr601 *src = SSE2_enabled ? new VDPixmapGenRGB32ToYCbCr601_SSE2 : new VDPixmapGenRGB32ToYCbCr601; -#else - VDPixmapGenRGB32ToYCbCr601 *src = new VDPixmapGenRGB32ToYCbCr601; -#endif - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr709() { - StackEntry *args = &mStack.back(); - VDPixmapGenRGB32ToYCbCr709 *src = new VDPixmapGenRGB32ToYCbCr709; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::ycbcr601_to_rgb32_32f() { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCr601ToRGB32F *src = new VDPixmapGenYCbCr601ToRGB32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::ycbcr709_to_rgb32_32f() { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCr709ToRGB32F *src = new VDPixmapGenYCbCr709ToRGB32F; - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr601_32f() { - StackEntry *args = &mStack.back(); - VDPixmapGenRGB32FToYCbCr601 *src = new VDPixmapGenRGB32FToYCbCr601; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr709_32f() { - StackEntry *args = &mStack.back(); - VDPixmapGenRGB32FToYCbCr709 *src = new VDPixmapGenRGB32FToYCbCr709; - - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::ycbcr601_to_ycbcr709() { - StackEntry *args = &mStack.back() - 2; - - IVDPixmapGen *src; - if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { - VDPixmapGenYCbCr601ToYCbCr709_32F *src2 = new VDPixmapGenYCbCr601ToYCbCr709_32F; - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } else { - VDPixmapGenYCbCr601ToYCbCr709 *src2 = new VDPixmapGenYCbCr601ToYCbCr709; - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - args[1] = StackEntry(src, 1); - args[2] = StackEntry(src, 2); -} - -void VDPixmapUberBlitterGenerator::ycbcr709_to_ycbcr601() { - StackEntry *args = &mStack.back() - 2; - - IVDPixmapGen *src; - if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { - VDPixmapGenYCbCr709ToYCbCr601_32F *src2 = new VDPixmapGenYCbCr709ToYCbCr601_32F; - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } else { - VDPixmapGenYCbCr709ToYCbCr601 *src2 = new VDPixmapGenYCbCr709ToYCbCr601; - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - args[1] = StackEntry(src, 1); - args[2] = StackEntry(src, 2); -} - -void VDPixmapUberBlitterGenerator::ycbcr_to_rgb32_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB) { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCrToRGB32Generic *src = new VDPixmapGenYCbCrToRGB32Generic(basis, studioRGB); - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::ycbcr_to_rgb32f_generic(const VDPixmapGenYCbCrBasis& basis) { - StackEntry *args = &mStack.back() - 2; - - VDPixmapGenYCbCrToRGB32FGeneric *src = new VDPixmapGenYCbCrToRGB32FGeneric(basis); - - src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - mStack.pop_back(); - mStack.pop_back(); -} - -void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB, uint32 colorSpace) { - StackEntry *args = &mStack.back(); - - VDPixmapGenRGB32ToYCbCrGeneric *src = new VDPixmapGenRGB32ToYCbCrGeneric(basis, studioRGB, colorSpace); - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::rgb32f_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace) { - StackEntry *args = &mStack.back(); - - VDPixmapGenRGB32FToYCbCrGeneric *src = new VDPixmapGenRGB32FToYCbCrGeneric(basis, colorSpace); - src->Init(args[0].mpSrc, args[0].mSrcIndex); - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - args[0] = StackEntry(src, 0); - mStack.push_back(StackEntry(src, 1)); - mStack.push_back(StackEntry(src, 2)); -} - -void VDPixmapUberBlitterGenerator::ycbcr_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basisDst, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& basisSrc, bool srcLimitedRange, uint32 colorSpace) { - StackEntry *args = &mStack.back() - 2; - - IVDPixmapGen *src; - if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { - VDPixmapGenYCbCrToYCbCrGeneric_32F *src2 = new VDPixmapGenYCbCrToYCbCrGeneric_32F(basisDst, dstLimitedRange, basisSrc, srcLimitedRange, colorSpace); - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } else { - VDPixmapGenYCbCrToYCbCrGeneric *src2 = new VDPixmapGenYCbCrToYCbCrGeneric(basisDst, dstLimitedRange, basisSrc, srcLimitedRange, colorSpace); - - src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); - src = src2; - } - - mGenerators.push_back(src); - MarkDependency(src, args[0].mpSrc); - MarkDependency(src, args[1].mpSrc); - MarkDependency(src, args[2].mpSrc); - args[0] = StackEntry(src, 0); - args[1] = StackEntry(src, 1); - args[2] = StackEntry(src, 2); -} - -IVDPixmapBlitter *VDPixmapUberBlitterGenerator::create() { - vdautoptr blitter(new VDPixmapUberBlitter); - - int numStackEntries = (int)mStack.size(); - - for(int i=0; i<3; ++i) { - if (i < numStackEntries) { - blitter->mOutputs[i].mpSrc = mStack[i].mpSrc; - blitter->mOutputs[i].mSrcIndex = mStack[i].mSrcIndex; - } else { - blitter->mOutputs[i].mpSrc = NULL; - blitter->mOutputs[i].mSrcIndex = 0; - } - } - - mStack.clear(); - - // If this blitter has three outputs, determine if outputs 1 and 2 are independent - // from output 0. - blitter->mbIndependentChromaPlanes = true; - blitter->mbIndependentPlanes = true; - if (numStackEntries >= 3) { - int numGens = mGenerators.size(); - vdfastvector genflags(numGens, 0); - - enum { - kFlagStateful = 0x80, - kFlagY = 0x01, - kFlagCb = 0x02, - kFlagCr = 0x04, - kFlagYCbCr = 0x07 - }; - - for(int i=0; i<3; ++i) - genflags[std::find(mGenerators.begin(), mGenerators.end(), blitter->mOutputs[i].mpSrc) - mGenerators.begin()] |= (1 << i); - - for(int i=0; iIsStateful()) - genflags[i] |= kFlagStateful; - } - - while(!mDependencies.empty()) { - const Dependency& dep = mDependencies.back(); - - genflags[dep.mSrcIdx] |= (genflags[dep.mDstIdx] & ~kFlagStateful); - - mDependencies.pop_back(); - } - - for(int i=0; imbIndependentPlanes = false; - break; - case kFlagCb | kFlagY: - case kFlagCr | kFlagY: - case kFlagCr | kFlagCb | kFlagY: - blitter->mbIndependentPlanes = false; - blitter->mbIndependentChromaPlanes = false; - break; - } - } - } else if (numStackEntries >= 2) { - int numGens = mGenerators.size(); - vdfastvector genflags(numGens, 0); - - enum { - kFlagStateful = 0x80, - kFlagY = 0x01, - kFlagC = 0x02, - kFlagYC = 0x03 - }; - - for(int i=0; i<2; ++i) - genflags[std::find(mGenerators.begin(), mGenerators.end(), blitter->mOutputs[i].mpSrc) - mGenerators.begin()] |= (1 << i); - - for(int i=0; iIsStateful()) - genflags[i] |= kFlagStateful; - } - - while(!mDependencies.empty()) { - const Dependency& dep = mDependencies.back(); - - genflags[dep.mSrcIdx] |= (genflags[dep.mDstIdx] & ~kFlagStateful); - - mDependencies.pop_back(); - } - - for(int i=0; imbIndependentPlanes = false; - blitter->mbIndependentChromaPlanes = false; - break; - } - } - } - - blitter->mGenerators.swap(mGenerators); - blitter->mSources.swap(mSources); - return blitter.release(); -} - -void VDPixmapUberBlitterGenerator::MarkDependency(IVDPixmapGen *dst, IVDPixmapGen *src) { - Generators::const_iterator it1(std::find(mGenerators.begin(), mGenerators.end(), dst)); - Generators::const_iterator it2(std::find(mGenerators.begin(), mGenerators.end(), src)); - - VDASSERT(it1 != mGenerators.end()); - VDASSERT(it2 != mGenerators.end()); - - int idx1 = it1 - mGenerators.begin(); - int idx2 = it2 - mGenerators.begin(); - - Dependency dep = { idx1, idx2 }; - - mDependencies.push_back(dep); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include "uberblit.h" +#include "uberblit_gen.h" +#include "uberblit_fill.h" +#include "uberblit_input.h" +#include "uberblit_resample.h" +#include "uberblit_resample_special.h" +#include "uberblit_ycbcr.h" +#include "uberblit_ycbcr_generic.h" +#include "uberblit_rgb.h" +#include "uberblit_swizzle.h" +#include "uberblit_pal.h" +#include "uberblit_16f.h" +#include "uberblit_v210.h" +#include "uberblit_interlace.h" + +#ifdef VD_CPU_X86 + #include "uberblit_swizzle_x86.h" + #include "uberblit_ycbcr_x86.h" + #include "uberblit_rgb_x86.h" + #include "uberblit_resample_special_x86.h" +#endif + +void VDPixmapGenerate(void *dst, ptrdiff_t pitch, sint32 bpr, sint32 height, IVDPixmapGen *gen, int genIndex) { + for(sint32 y=0; yGetRow(y, genIndex), bpr); + vdptrstep(dst, pitch); + } + VDCPUCleanupExtensions(); +} + +void VDPixmapGenerateFast(void *dst, ptrdiff_t pitch, sint32 height, IVDPixmapGen *gen) { + for(sint32 y=0; yProcessRow(dst, y); + vdptrstep(dst, pitch); + } + VDCPUCleanupExtensions(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmap& dst, const VDPixmap& src) { + return new VDPixmapUberBlitterDirectCopy; +} + +IVDPixmapBlitter *VDCreatePixmapUberBlitterDirectCopy(const VDPixmapLayout& dst, const VDPixmapLayout& src) { + return new VDPixmapUberBlitterDirectCopy; +} + +VDPixmapUberBlitterDirectCopy::VDPixmapUberBlitterDirectCopy() { +} + +VDPixmapUberBlitterDirectCopy::~VDPixmapUberBlitterDirectCopy() { +} + +void VDPixmapUberBlitterDirectCopy::Blit(const VDPixmap& dst, const VDPixmap& src) { + Blit(dst, NULL, src); +} + +void VDPixmapUberBlitterDirectCopy::Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) { + VDASSERT(dst.format == src.format); + + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); + + void *p = dst.data; + void *p2 = dst.data2; + void *p3 = dst.data3; + int w = std::min(dst.w, src.w); + int h = std::min(dst.h, src.h); + + if (formatInfo.qchunky) { + w = (w + formatInfo.qw - 1) / formatInfo.qw; + h = -(-h >> formatInfo.qhbits); + } + + int w2 = -(-dst.w >> formatInfo.auxwbits); + int h2 = -(-dst.h >> formatInfo.auxhbits); + + if (rDst) { + int x1 = rDst->left; + int y1 = rDst->top; + int x2 = rDst->right; + int y2 = rDst->bottom; + + VDASSERT(x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h && x2 >= x1 && y2 >= y1); + + if (x2 < x1 || y2 < y1) + return; + + p = vdptroffset(dst.data, dst.pitch * y1 + x1 * formatInfo.qsize); + w = x2 - x1; + h = y2 - y1; + + if (formatInfo.auxbufs >= 1) { + VDASSERT(!((x1|x2) & ((1 << formatInfo.auxwbits) - 1))); + VDASSERT(!((y1|y2) & ((1 << formatInfo.auxhbits) - 1))); + + int ax1 = x1 >> formatInfo.auxwbits; + int ay1 = y1 >> formatInfo.auxhbits; + int ax2 = x2 >> formatInfo.auxwbits; + int ay2 = y2 >> formatInfo.auxhbits; + + p2 = vdptroffset(dst.data2, dst.pitch2 * ay1 + ax1); + w2 = ax2 - ax1; + h2 = ay2 - ay1; + + if (formatInfo.auxbufs >= 2) + p3 = vdptroffset(dst.data3, dst.pitch3 * ay1 + ax1); + } + } + + uint32 bpr = formatInfo.qsize * w; + + VDMemcpyRect(p, dst.pitch, src.data, src.pitch, bpr, h); + + if (formatInfo.auxbufs >= 1) { + VDMemcpyRect(p2, dst.pitch2, src.data2, src.pitch2, w2 * formatInfo.auxsize, h2); + + if (formatInfo.auxbufs >= 2) + VDMemcpyRect(p3, dst.pitch3, src.data3, src.pitch3, w2 * formatInfo.auxsize, h2); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +VDPixmapUberBlitter::VDPixmapUberBlitter() { +} + +VDPixmapUberBlitter::~VDPixmapUberBlitter() { + while(!mGenerators.empty()) { + delete mGenerators.back(); + mGenerators.pop_back(); + } +} + +void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const VDPixmap& src) { + Blit(dst, NULL, src); +} + +void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) { + for(Sources::const_iterator it(mSources.begin()), itEnd(mSources.end()); it!=itEnd; ++it) { + const SourceEntry& se = *it; + const void *p; + ptrdiff_t pitch; + + switch(se.mSrcPlane) { + case 0: + p = src.data; + pitch = src.pitch; + break; + case 1: + p = src.data2; + pitch = src.pitch2; + break; + case 2: + p = src.data3; + pitch = src.pitch3; + break; + default: + VDASSERT(false); + break; + } + + se.mpSrc->SetSource((const char *)p + pitch*se.mSrcY + se.mSrcX, pitch, src.palette); + } + + if (mOutputs[2].mpSrc) { + if (mbIndependentPlanes) + Blit3Separated(dst, rDst); + else if (mbIndependentChromaPlanes) + Blit3Split(dst, rDst); + else + Blit3(dst, rDst); + } else if (mOutputs[1].mpSrc) { + if (mbIndependentPlanes) + Blit2Separated(dst, rDst); + else + Blit2(dst, rDst); + } else + Blit(dst, rDst); +} + +void VDPixmapUberBlitter::Blit(const VDPixmap& dst, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(dst.format); + + mOutputs[0].mpSrc->AddWindowRequest(0, 0); + mOutputs[0].mpSrc->Start(); + + void *p = dst.data; + int w = dst.w; + int h = dst.h; + + if (formatInfo.qchunky) { + w = (w + formatInfo.qw - 1) / formatInfo.qw; + h = -(-h >> formatInfo.qhbits); + } + + if (rDst) { + int x1 = rDst->left; + int y1 = rDst->top; + int x2 = rDst->right; + int y2 = rDst->bottom; + + if (formatInfo.qchunky) { + x1 = x1 / formatInfo.qw; + y1 = y1 / formatInfo.qh; + x2 = (x2 + formatInfo.qw - 1) / formatInfo.qw; + y2 = (y2 + formatInfo.qh - 1) / formatInfo.qh; + } + + VDASSERT(x1 >= 0 && y1 >= 0 && x2 <= w && y2 <= h && x2 >= x1 && y2 >= y1); + + if (x2 < x1 || y2 < y1) + return; + + p = vdptroffset(dst.data, dst.pitch * y1 + x1 * formatInfo.qsize); + w = x2 - x1; + h = y2 - y1; + } + + uint32 bpr = formatInfo.qsize * w; + + if (mOutputs[0].mSrcIndex == 0) + VDPixmapGenerateFast(p, dst.pitch, h, mOutputs[0].mpSrc); + else + VDPixmapGenerate(p, dst.pitch, bpr, h, mOutputs[0].mpSrc, mOutputs[0].mSrcIndex); +} + +void VDPixmapUberBlitter::Blit3(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[1].mpSrc; + int idx = mOutputs[1].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[2].mpSrc; + int idx1 = mOutputs[2].mSrcIndex; + IVDPixmapGen *gen2 = mOutputs[0].mpSrc; + int idx2 = mOutputs[0].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + gen2->AddWindowRequest(0, 0); + gen2->Start(); + + uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; + uint32 auxaccum = 0; + + auxstep += auxstep; + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint32 bpr2 = formatInfo.auxsize * -(-px.w >> formatInfo.auxwbits); + uint8 *dst = (uint8 *)px.data; + uint8 *dst2 = (uint8 *)px.data2; + uint8 *dst3 = (uint8 *)px.data3; + ptrdiff_t pitch = px.pitch; + ptrdiff_t pitch2 = px.pitch2; + ptrdiff_t pitch3 = px.pitch3; + uint32 y2 = 0; + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + + if (!auxaccum) { + memcpy(dst2, gen1->GetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + memcpy(dst3, gen2->GetRow(y2, idx2), bpr2); + vdptrstep(dst3, pitch3); + ++y2; + } + + auxaccum += auxstep; + } + + VDCPUCleanupExtensions(); +} + +void VDPixmapUberBlitter::Blit3Split(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[1].mpSrc; + int idx = mOutputs[1].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[2].mpSrc; + int idx1 = mOutputs[2].mSrcIndex; + IVDPixmapGen *gen2 = mOutputs[0].mpSrc; + int idx2 = mOutputs[0].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + gen2->AddWindowRequest(0, 0); + gen2->Start(); + + uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; + uint32 auxaccum = 0; + + auxstep += auxstep; + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint8 *dst = (uint8 *)px.data; + ptrdiff_t pitch = px.pitch; + + if (idx == 0) { + for(uint32 y=0; yProcessRow(dst, y); + vdptrstep(dst, pitch); + } + } else { + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + } + } + + uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; + uint8 *dst2 = (uint8 *)px.data2; + uint8 *dst3 = (uint8 *)px.data3; + ptrdiff_t pitch2 = px.pitch2; + ptrdiff_t pitch3 = px.pitch3; + uint32 y2 = 0; + for(uint32 y=0; yGetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + memcpy(dst3, gen2->GetRow(y2, idx2), bpr2); + vdptrstep(dst3, pitch3); + ++y2; + } + + auxaccum += auxstep; + } + + VDCPUCleanupExtensions(); +} + +void VDPixmapUberBlitter::Blit3Separated(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[1].mpSrc; + int idx = mOutputs[1].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[2].mpSrc; + int idx1 = mOutputs[2].mSrcIndex; + IVDPixmapGen *gen2 = mOutputs[0].mpSrc; + int idx2 = mOutputs[0].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + gen2->AddWindowRequest(0, 0); + gen2->Start(); + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint8 *dst = (uint8 *)px.data; + ptrdiff_t pitch = px.pitch; + + if (idx == 0) { + for(uint32 y=0; yProcessRow(dst, y); + vdptrstep(dst, pitch); + } + } else { + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + } + } + + uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; + uint32 h2 = -(-px.h >> formatInfo.auxhbits); + uint8 *dst2 = (uint8 *)px.data2; + ptrdiff_t pitch2 = px.pitch2; + if (idx1 == 0) { + for(uint32 y2=0; y2ProcessRow(dst2, y2); + vdptrstep(dst2, pitch2); + } + } else { + for(uint32 y2=0; y2GetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + } + } + + uint8 *dst3 = (uint8 *)px.data3; + ptrdiff_t pitch3 = px.pitch3; + if (idx2 == 0) { + for(uint32 y2=0; y2ProcessRow(dst3, y2); + vdptrstep(dst3, pitch3); + } + } else { + for(uint32 y2=0; y2GetRow(y2, idx2), bpr2); + vdptrstep(dst3, pitch3); + } + } + + VDCPUCleanupExtensions(); +} + +void VDPixmapUberBlitter::Blit2(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[0].mpSrc; + int idx = mOutputs[0].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[1].mpSrc; + int idx1 = mOutputs[1].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + + uint32 auxstep = 0x80000000UL >> formatInfo.auxhbits; + uint32 auxaccum = 0; + + auxstep += auxstep; + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint32 bpr2 = formatInfo.auxsize * -(-px.w >> formatInfo.auxwbits); + uint8 *dst = (uint8 *)px.data; + uint8 *dst2 = (uint8 *)px.data2; + ptrdiff_t pitch = px.pitch; + ptrdiff_t pitch2 = px.pitch2; + uint32 y2 = 0; + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + + if (!auxaccum) { + memcpy(dst2, gen1->GetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + ++y2; + } + + auxaccum += auxstep; + } + + VDCPUCleanupExtensions(); +} + +void VDPixmapUberBlitter::Blit2Separated(const VDPixmap& px, const vdrect32 *rDst) { + const VDPixmapFormatInfo& formatInfo = VDPixmapGetInfo(px.format); + IVDPixmapGen *gen = mOutputs[0].mpSrc; + int idx = mOutputs[0].mSrcIndex; + IVDPixmapGen *gen1 = mOutputs[1].mpSrc; + int idx1 = mOutputs[1].mSrcIndex; + + gen->AddWindowRequest(0, 0); + gen->Start(); + gen1->AddWindowRequest(0, 0); + gen1->Start(); + + int qw = px.w; + int qh = px.h; + + if (formatInfo.qchunky) { + qw = (qw + formatInfo.qw - 1) / formatInfo.qw; + qh = -(-qh >> formatInfo.qhbits); + } + + uint32 height = qh; + uint32 bpr = formatInfo.qsize * qw; + uint8 *dst = (uint8 *)px.data; + ptrdiff_t pitch = px.pitch; + + if (idx == 0) { + for(uint32 y=0; yProcessRow(dst, y); + vdptrstep(dst, pitch); + } + } else { + for(uint32 y=0; yGetRow(y, idx), bpr); + vdptrstep(dst, pitch); + } + } + + uint32 bpr2 = -(-px.w >> formatInfo.auxwbits) * formatInfo.auxsize; + uint32 h2 = -(-px.h >> formatInfo.auxhbits); + uint8 *dst2 = (uint8 *)px.data2; + ptrdiff_t pitch2 = px.pitch2; + if (idx1 == 0) { + for(uint32 y2=0; y2ProcessRow(dst2, y2); + vdptrstep(dst2, pitch2); + } + } else { + for(uint32 y2=0; y2GetRow(y2, idx1), bpr2); + vdptrstep(dst2, pitch2); + } + } + + VDCPUCleanupExtensions(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +VDPixmapUberBlitterGenerator::VDPixmapUberBlitterGenerator() { +} + +VDPixmapUberBlitterGenerator::~VDPixmapUberBlitterGenerator() { + while(!mGenerators.empty()) { + delete mGenerators.back(); + mGenerators.pop_back(); + } +} + +void VDPixmapUberBlitterGenerator::swap(int index) { + std::swap(mStack.back(), (&mStack.back())[-index]); +} + +void VDPixmapUberBlitterGenerator::dup() { + mStack.push_back(mStack.back()); +} + +void VDPixmapUberBlitterGenerator::pop() { + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::ldsrc(int srcIndex, int srcPlane, int x, int y, uint32 w, uint32 h, uint32 type, uint32 bpr) { + VDPixmapGenSrc *src = new VDPixmapGenSrc; + + src->Init(w, h, type, bpr); + + mGenerators.push_back(src); + mStack.push_back(StackEntry(src, 0)); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = srcPlane; + se.mSrcX = x; + se.mSrcY = y; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::ldconst(uint8 fill, uint32 bpr, uint32 w, uint32 h, uint32 type) { + VDPixmapGenFill8 *src = new VDPixmapGenFill8; + + src->Init(fill, bpr, w, h, type); + + mGenerators.push_back(src); + mStack.push_back(StackEntry(src, 0)); +} + +void VDPixmapUberBlitterGenerator::extract_8in16(int offset, uint32 w, uint32 h) { + StackEntry *args = &mStack.back(); + VDPixmapGen_8In16 *src = NULL; + +#if VD_CPU_X86 + if (MMX_enabled) { + if (offset == 0) + src = new VDPixmapGen_8In16_Even_MMX; + else if (offset == 1) + src = new VDPixmapGen_8In16_Odd_MMX; + } +#endif + if (!src) + src = new VDPixmapGen_8In16; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, offset, w, h); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::extract_8in32(int offset, uint32 w, uint32 h) { + StackEntry *args = &mStack.back(); + VDPixmapGen_8In32 *src = NULL; + +#if VD_CPU_X86 + if (MMX_enabled) { + if ((unsigned)offset < 4) + src = new VDPixmapGen_8In32_MMX; + } +#endif + + if (!src) + src = new VDPixmapGen_8In32; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, offset, w, h); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::swap_8in16(uint32 w, uint32 h, uint32 bpr) { + StackEntry *args = &mStack.back(); + +#if VD_CPU_X86 + VDPixmapGen_Swap8In16 *src = MMX_enabled ? new VDPixmapGen_Swap8In16_MMX : new VDPixmapGen_Swap8In16; +#else + VDPixmapGen_Swap8In16 *src = new VDPixmapGen_Swap8In16; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex, w, h, bpr); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_Pal1_to_8888(int srcIndex) { + StackEntry *args = &mStack.back(); + VDPixmapGen_Pal1_To_X8R8G8B8 *src = new VDPixmapGen_Pal1_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = 0; + se.mSrcX = 0; + se.mSrcY = 0; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::conv_Pal2_to_8888(int srcIndex) { + StackEntry *args = &mStack.back(); + VDPixmapGen_Pal2_To_X8R8G8B8 *src = new VDPixmapGen_Pal2_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = 0; + se.mSrcX = 0; + se.mSrcY = 0; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::conv_Pal4_to_8888(int srcIndex) { + StackEntry *args = &mStack.back(); + VDPixmapGen_Pal4_To_X8R8G8B8 *src = new VDPixmapGen_Pal4_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = 0; + se.mSrcX = 0; + se.mSrcY = 0; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::conv_Pal8_to_8888(int srcIndex) { + StackEntry *args = &mStack.back(); + VDPixmapGen_Pal8_To_X8R8G8B8 *src = new VDPixmapGen_Pal8_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + + SourceEntry se; + se.mpSrc = src; + se.mSrcIndex = srcIndex; + se.mSrcPlane = 0; + se.mSrcX = 0; + se.mSrcY = 0; + mSources.push_back(se); +} + +void VDPixmapUberBlitterGenerator::pointh(float xoffset, float xfactor, uint32 w) { + StackEntry *args = &mStack.back(); + + if (xoffset != 0.5f || xfactor != 1.0f) { + VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterPoint, 0, false); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::pointv(float yoffset, float yfactor, uint32 h) { + StackEntry *args = &mStack.back(); + + if (yoffset != 0.5f || yfactor != 1.0f) { + VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterPoint, 0, false); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::linearh(float xoffset, float xfactor, uint32 w, bool interpOnly) { + StackEntry *args = &mStack.back(); + IVDPixmapGen *src = args[0].mpSrc; + int srcIndex = args[0].mSrcIndex; + + sint32 srcw = src->GetWidth(srcIndex); + if (xoffset == 0.5f && xfactor == 1.0f && srcw == w) + return; + + if (xoffset == 0.5f && (src->GetType(srcIndex) & kVDPixType_Mask) == kVDPixType_8) { + if (xfactor == 2.0f && w == ((srcw + 1) >> 1)) { + VDPixmapGenResampleRow_d2_p0_lin_u8 *out = new VDPixmapGenResampleRow_d2_p0_lin_u8; + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (xfactor == 4.0f && w == ((srcw + 3) >> 2)) { + VDPixmapGenResampleRow_d4_p0_lin_u8 *out = new VDPixmapGenResampleRow_d4_p0_lin_u8; + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (xfactor == 0.5f && w == srcw*2) { +#if VD_CPU_X86 + VDPixmapGenResampleRow_x2_p0_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE : new VDPixmapGenResampleRow_x2_p0_lin_u8; +#else + VDPixmapGenResampleRow_x2_p0_lin_u8 *out = new VDPixmapGenResampleRow_x2_p0_lin_u8; +#endif + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (xfactor == 0.25f && w == srcw*4) { +#if VD_CPU_X86 + VDPixmapGenResampleRow_x4_p0_lin_u8 *out = MMX_enabled ? new VDPixmapGenResampleRow_x4_p0_lin_u8_MMX : new VDPixmapGenResampleRow_x4_p0_lin_u8; +#else + VDPixmapGenResampleRow_x4_p0_lin_u8 *out = new VDPixmapGenResampleRow_x4_p0_lin_u8; +#endif + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + } + + VDPixmapGenResampleRow *out = new VDPixmapGenResampleRow; + + out->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterLinear, 0, interpOnly); + + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); +} + +void VDPixmapUberBlitterGenerator::linearv(float yoffset, float yfactor, uint32 h, bool interpOnly) { + StackEntry *args = &mStack.back(); + IVDPixmapGen *src = args[0].mpSrc; + int srcIndex = args[0].mSrcIndex; + + sint32 srch = src->GetHeight(srcIndex); + if (yoffset == 0.5f && yfactor == 1.0f && srch == h) + return; + + if ((src->GetType(srcIndex) & kVDPixType_Mask) == kVDPixType_8) { + if (yoffset == 1.0f && yfactor == 2.0f && h == ((srch + 1) >> 1)) { + VDPixmapGenResampleCol_x2_phalf_lin_u8 *out = new VDPixmapGenResampleCol_x2_phalf_lin_u8; + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (yoffset == 2.0f && yfactor == 4.0f && h == ((srch + 2) >> 2)) { + VDPixmapGenResampleCol_x4_p1half_lin_u8 *out = new VDPixmapGenResampleCol_x4_p1half_lin_u8; + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (yoffset == 0.25f && yfactor == 0.5f && h == srch*2) { +#if VD_CPU_X86 + VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE : new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8; +#else + VDPixmapGenResampleCol_d2_pnqrtr_lin_u8 *out = new VDPixmapGenResampleCol_d2_pnqrtr_lin_u8; +#endif + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + + if (yoffset == 0.125f && yfactor == 0.25f && h == srch*4) { +#if VD_CPU_X86 + VDPixmapGenResampleCol_d4_pn38_lin_u8 *out = ISSE_enabled ? new VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE : new VDPixmapGenResampleCol_d4_pn38_lin_u8; +#else + VDPixmapGenResampleCol_d4_pn38_lin_u8 *out = new VDPixmapGenResampleCol_d4_pn38_lin_u8; +#endif + + out->Init(src, srcIndex); + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); + return; + } + } + + VDPixmapGenResampleCol *out = new VDPixmapGenResampleCol; + + out->Init(src, srcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterLinear, 0, interpOnly); + + mGenerators.push_back(out); + MarkDependency(out, src); + args[0] = StackEntry(out, 0); +} + +void VDPixmapUberBlitterGenerator::linear(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h) { + linearh(xoffset, xfactor, w, false); + linearv(yoffset, yfactor, h, false); +} + +void VDPixmapUberBlitterGenerator::cubich(float xoffset, float xfactor, uint32 w, float splineFactor, bool interpOnly) { + StackEntry *args = &mStack.back(); + + if (xoffset != 0.5f || xfactor != 1.0f) { + VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterCubic, splineFactor, interpOnly); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::cubicv(float yoffset, float yfactor, uint32 h, float splineFactor, bool interpOnly) { + StackEntry *args = &mStack.back(); + + if (yoffset != 0.5f || yfactor != 1.0f) { + VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterCubic, splineFactor, interpOnly); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::cubic(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h, float splineFactor) { + cubich(xoffset, xfactor, w, splineFactor, false); + cubicv(yoffset, yfactor, h, splineFactor, false); +} + +void VDPixmapUberBlitterGenerator::lanczos3h(float xoffset, float xfactor, uint32 w) { + StackEntry *args = &mStack.back(); + + if (xoffset != 0.5f || xfactor != 1.0f) { + VDPixmapGenResampleRow *src = new VDPixmapGenResampleRow; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, w, xoffset, xfactor, nsVDPixmap::kFilterLanczos3, 0, false); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::lanczos3v(float yoffset, float yfactor, uint32 h) { + StackEntry *args = &mStack.back(); + + if (yoffset != 0.5f || yfactor != 1.0f) { + VDPixmapGenResampleCol *src = new VDPixmapGenResampleCol; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, h, yoffset, yfactor, nsVDPixmap::kFilterLanczos3, 0, false); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + } +} + +void VDPixmapUberBlitterGenerator::lanczos3(float xoffset, float xfactor, uint32 w, float yoffset, float yfactor, uint32 h) { + lanczos3h(xoffset, xfactor, w); + lanczos3v(yoffset, yfactor, h); +} + +void VDPixmapUberBlitterGenerator::conv_555_to_8888() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X1R5G5B5_To_X8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_X1R5G5B5_To_X8R8G8B8_MMX : new VDPixmapGen_X1R5G5B5_To_X8R8G8B8; +#else + VDPixmapGen_X1R5G5B5_To_X8R8G8B8 *src = new VDPixmapGen_X1R5G5B5_To_X8R8G8B8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_565_to_8888() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_R5G6B5_To_X8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_R5G6B5_To_X8R8G8B8_MMX : new VDPixmapGen_R5G6B5_To_X8R8G8B8; +#else + VDPixmapGen_R5G6B5_To_X8R8G8B8 *src = new VDPixmapGen_R5G6B5_To_X8R8G8B8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_888_to_8888() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_R8G8B8_To_A8R8G8B8 *src = MMX_enabled ? new VDPixmapGen_R8G8B8_To_X8R8G8B8_MMX : new VDPixmapGen_R8G8B8_To_A8R8G8B8; +#else + VDPixmapGen_R8G8B8_To_A8R8G8B8 *src = new VDPixmapGen_R8G8B8_To_A8R8G8B8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_8_to_32F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_8_To_32F *src = new VDPixmapGen_8_To_32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_16F_to_32F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_16F_To_32F *src = new VDPixmapGen_16F_To_32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_V210_to_32F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_V210_To_32F *src = new VDPixmapGen_V210_To_32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::conv_8888_to_X32F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X8R8G8B8_To_X32B32G32R32F *src = new VDPixmapGen_X8R8G8B8_To_X32B32G32R32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_8888_to_555() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X8R8G8B8_To_X1R5G5B5 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_X1R5G5B5_MMX : new VDPixmapGen_X8R8G8B8_To_X1R5G5B5; +#else + VDPixmapGen_X8R8G8B8_To_X1R5G5B5 *src = new VDPixmapGen_X8R8G8B8_To_X1R5G5B5; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_555_to_565() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X1R5G5B5_To_R5G6B5 *src = MMX_enabled ? new VDPixmapGen_X1R5G5B5_To_R5G6B5_MMX : new VDPixmapGen_X1R5G5B5_To_R5G6B5; +#else + VDPixmapGen_X1R5G5B5_To_R5G6B5 *src = new VDPixmapGen_X1R5G5B5_To_R5G6B5; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_565_to_555() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_R5G6B5_To_X1R5G5B5 *src = MMX_enabled ? new VDPixmapGen_R5G6B5_To_X1R5G5B5_MMX : new VDPixmapGen_R5G6B5_To_X1R5G5B5; +#else + VDPixmapGen_R5G6B5_To_X1R5G5B5 *src = new VDPixmapGen_R5G6B5_To_X1R5G5B5; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_8888_to_565() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X8R8G8B8_To_R5G6B5 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_R5G6B5_MMX : new VDPixmapGen_X8R8G8B8_To_R5G6B5; +#else + VDPixmapGen_X8R8G8B8_To_R5G6B5 *src = new VDPixmapGen_X8R8G8B8_To_R5G6B5; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_8888_to_888() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGen_X8R8G8B8_To_R8G8B8 *src = MMX_enabled ? new VDPixmapGen_X8R8G8B8_To_R8G8B8_MMX : new VDPixmapGen_X8R8G8B8_To_R8G8B8; +#else + VDPixmapGen_X8R8G8B8_To_R8G8B8 *src = new VDPixmapGen_X8R8G8B8_To_R8G8B8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_32F_to_8() { + StackEntry *args = &mStack.back(); + VDPixmapGen_32F_To_8 *src = new VDPixmapGen_32F_To_8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_X32F_to_8888() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X32B32G32R32F_To_X8R8G8B8 *src = new VDPixmapGen_X32B32G32R32F_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_32F_to_16F() { + StackEntry *args = &mStack.back(); + VDPixmapGen_32F_To_16F *src = new VDPixmapGen_32F_To_16F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::conv_32F_to_V210() { + StackEntry *args = &*(mStack.end() - 3); + VDPixmapGen_32F_To_V210 *src = new VDPixmapGen_32F_To_V210; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::convd_8888_to_555() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X8R8G8B8_To_X1R5G5B5_Dithered *src = new VDPixmapGen_X8R8G8B8_To_X1R5G5B5_Dithered; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::convd_8888_to_565() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered *src = new VDPixmapGen_X8R8G8B8_To_R5G6B5_Dithered; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::convd_32F_to_8() { + StackEntry *args = &mStack.back(); + VDPixmapGen_32F_To_8_Dithered *src = new VDPixmapGen_32F_To_8_Dithered; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::convd_X32F_to_8888() { + StackEntry *args = &mStack.back(); + VDPixmapGen_X32B32G32R32F_To_X8R8G8B8_Dithered *src = new VDPixmapGen_X32B32G32R32F_To_X8R8G8B8_Dithered; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); +} + +void VDPixmapUberBlitterGenerator::interleave_B8G8_R8G8() { + StackEntry *args = &mStack.back() - 2; + VDPixmapGen_B8x3_To_B8G8_R8G8 *src = NULL; + +#if VD_CPU_X86 + if (MMX_enabled) + src = new VDPixmapGen_B8x3_To_B8G8_R8G8_MMX; +#endif + + if (!src) + src = new VDPixmapGen_B8x3_To_B8G8_R8G8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::interleave_G8B8_G8R8() { + StackEntry *args = &mStack.back() - 2; + VDPixmapGen_B8x3_To_G8B8_G8R8 *src = NULL; + +#if VD_CPU_X86 + if (MMX_enabled) + src = new VDPixmapGen_B8x3_To_G8B8_G8R8_MMX; +#endif + + if (!src) + src = new VDPixmapGen_B8x3_To_G8B8_G8R8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::interleave_X8R8G8B8() { + StackEntry *args = &mStack.back() - 2; + VDPixmapGen_B8x3_To_X8R8G8B8 *src = new VDPixmapGen_B8x3_To_X8R8G8B8; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::interleave_B8R8() { + StackEntry *args = &mStack.back() - 1; + +#if VD_CPU_X86 + VDPixmapGen_B8x2_To_B8R8 *src = MMX_enabled ? new VDPixmapGen_B8x2_To_B8R8_MMX : new VDPixmapGen_B8x2_To_B8R8; +#else + VDPixmapGen_B8x2_To_B8R8 *src = new VDPixmapGen_B8x2_To_B8R8; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::merge_fields(uint32 w, uint32 h, uint32 bpr) { + StackEntry *args = &mStack.back() - 1; + + VDPixmapGen_MergeFields *src = new VDPixmapGen_MergeFields; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, w, h, bpr); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::split_fields(uint32 bpr) { + StackEntry *args = &mStack.back(); + + VDPixmapGen_SplitFields *src = new VDPixmapGen_SplitFields; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, bpr); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); +} + +void VDPixmapUberBlitterGenerator::ycbcr601_to_rgb32() { + StackEntry *args = &mStack.back() - 2; + +#ifdef VD_CPU_X86 + VDPixmapGenYCbCr601ToRGB32 *src = MMX_enabled ? new VDPixmapGenYCbCr601ToRGB32_MMX : new VDPixmapGenYCbCr601ToRGB32; +#else + VDPixmapGenYCbCr601ToRGB32 *src = new VDPixmapGenYCbCr601ToRGB32; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::ycbcr709_to_rgb32() { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCr709ToRGB32 *src = new VDPixmapGenYCbCr709ToRGB32; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr601() { + StackEntry *args = &mStack.back(); +#ifdef VD_CPU_X86 + VDPixmapGenRGB32ToYCbCr601 *src = SSE2_enabled ? new VDPixmapGenRGB32ToYCbCr601_SSE2 : new VDPixmapGenRGB32ToYCbCr601; +#else + VDPixmapGenRGB32ToYCbCr601 *src = new VDPixmapGenRGB32ToYCbCr601; +#endif + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr709() { + StackEntry *args = &mStack.back(); + VDPixmapGenRGB32ToYCbCr709 *src = new VDPixmapGenRGB32ToYCbCr709; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::ycbcr601_to_rgb32_32f() { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCr601ToRGB32F *src = new VDPixmapGenYCbCr601ToRGB32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::ycbcr709_to_rgb32_32f() { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCr709ToRGB32F *src = new VDPixmapGenYCbCr709ToRGB32F; + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr601_32f() { + StackEntry *args = &mStack.back(); + VDPixmapGenRGB32FToYCbCr601 *src = new VDPixmapGenRGB32FToYCbCr601; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr709_32f() { + StackEntry *args = &mStack.back(); + VDPixmapGenRGB32FToYCbCr709 *src = new VDPixmapGenRGB32FToYCbCr709; + + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::ycbcr601_to_ycbcr709() { + StackEntry *args = &mStack.back() - 2; + + IVDPixmapGen *src; + if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { + VDPixmapGenYCbCr601ToYCbCr709_32F *src2 = new VDPixmapGenYCbCr601ToYCbCr709_32F; + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } else { + VDPixmapGenYCbCr601ToYCbCr709 *src2 = new VDPixmapGenYCbCr601ToYCbCr709; + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + args[1] = StackEntry(src, 1); + args[2] = StackEntry(src, 2); +} + +void VDPixmapUberBlitterGenerator::ycbcr709_to_ycbcr601() { + StackEntry *args = &mStack.back() - 2; + + IVDPixmapGen *src; + if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { + VDPixmapGenYCbCr709ToYCbCr601_32F *src2 = new VDPixmapGenYCbCr709ToYCbCr601_32F; + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } else { + VDPixmapGenYCbCr709ToYCbCr601 *src2 = new VDPixmapGenYCbCr709ToYCbCr601; + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + args[1] = StackEntry(src, 1); + args[2] = StackEntry(src, 2); +} + +void VDPixmapUberBlitterGenerator::ycbcr_to_rgb32_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB) { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCrToRGB32Generic *src = new VDPixmapGenYCbCrToRGB32Generic(basis, studioRGB); + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::ycbcr_to_rgb32f_generic(const VDPixmapGenYCbCrBasis& basis) { + StackEntry *args = &mStack.back() - 2; + + VDPixmapGenYCbCrToRGB32FGeneric *src = new VDPixmapGenYCbCrToRGB32FGeneric(basis); + + src->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + mStack.pop_back(); + mStack.pop_back(); +} + +void VDPixmapUberBlitterGenerator::rgb32_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB, uint32 colorSpace) { + StackEntry *args = &mStack.back(); + + VDPixmapGenRGB32ToYCbCrGeneric *src = new VDPixmapGenRGB32ToYCbCrGeneric(basis, studioRGB, colorSpace); + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::rgb32f_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace) { + StackEntry *args = &mStack.back(); + + VDPixmapGenRGB32FToYCbCrGeneric *src = new VDPixmapGenRGB32FToYCbCrGeneric(basis, colorSpace); + src->Init(args[0].mpSrc, args[0].mSrcIndex); + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + args[0] = StackEntry(src, 0); + mStack.push_back(StackEntry(src, 1)); + mStack.push_back(StackEntry(src, 2)); +} + +void VDPixmapUberBlitterGenerator::ycbcr_to_ycbcr_generic(const VDPixmapGenYCbCrBasis& basisDst, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& basisSrc, bool srcLimitedRange, uint32 colorSpace) { + StackEntry *args = &mStack.back() - 2; + + IVDPixmapGen *src; + if ((args[0].mpSrc->GetType(args[0].mSrcIndex) & kVDPixType_Mask) == kVDPixType_32F_LE) { + VDPixmapGenYCbCrToYCbCrGeneric_32F *src2 = new VDPixmapGenYCbCrToYCbCrGeneric_32F(basisDst, dstLimitedRange, basisSrc, srcLimitedRange, colorSpace); + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } else { + VDPixmapGenYCbCrToYCbCrGeneric *src2 = new VDPixmapGenYCbCrToYCbCrGeneric(basisDst, dstLimitedRange, basisSrc, srcLimitedRange, colorSpace); + + src2->Init(args[0].mpSrc, args[0].mSrcIndex, args[1].mpSrc, args[1].mSrcIndex, args[2].mpSrc, args[2].mSrcIndex); + src = src2; + } + + mGenerators.push_back(src); + MarkDependency(src, args[0].mpSrc); + MarkDependency(src, args[1].mpSrc); + MarkDependency(src, args[2].mpSrc); + args[0] = StackEntry(src, 0); + args[1] = StackEntry(src, 1); + args[2] = StackEntry(src, 2); +} + +IVDPixmapBlitter *VDPixmapUberBlitterGenerator::create() { + vdautoptr blitter(new VDPixmapUberBlitter); + + int numStackEntries = (int)mStack.size(); + + for(int i=0; i<3; ++i) { + if (i < numStackEntries) { + blitter->mOutputs[i].mpSrc = mStack[i].mpSrc; + blitter->mOutputs[i].mSrcIndex = mStack[i].mSrcIndex; + } else { + blitter->mOutputs[i].mpSrc = NULL; + blitter->mOutputs[i].mSrcIndex = 0; + } + } + + mStack.clear(); + + // If this blitter has three outputs, determine if outputs 1 and 2 are independent + // from output 0. + blitter->mbIndependentChromaPlanes = true; + blitter->mbIndependentPlanes = true; + if (numStackEntries >= 3) { + int numGens = mGenerators.size(); + vdfastvector genflags(numGens, 0); + + enum { + kFlagStateful = 0x80, + kFlagY = 0x01, + kFlagCb = 0x02, + kFlagCr = 0x04, + kFlagYCbCr = 0x07 + }; + + for(int i=0; i<3; ++i) + genflags[std::find(mGenerators.begin(), mGenerators.end(), blitter->mOutputs[i].mpSrc) - mGenerators.begin()] |= (1 << i); + + for(int i=0; iIsStateful()) + genflags[i] |= kFlagStateful; + } + + while(!mDependencies.empty()) { + const Dependency& dep = mDependencies.back(); + + genflags[dep.mSrcIdx] |= (genflags[dep.mDstIdx] & ~kFlagStateful); + + mDependencies.pop_back(); + } + + for(int i=0; imbIndependentPlanes = false; + break; + case kFlagCb | kFlagY: + case kFlagCr | kFlagY: + case kFlagCr | kFlagCb | kFlagY: + blitter->mbIndependentPlanes = false; + blitter->mbIndependentChromaPlanes = false; + break; + } + } + } else if (numStackEntries >= 2) { + int numGens = mGenerators.size(); + vdfastvector genflags(numGens, 0); + + enum { + kFlagStateful = 0x80, + kFlagY = 0x01, + kFlagC = 0x02, + kFlagYC = 0x03 + }; + + for(int i=0; i<2; ++i) + genflags[std::find(mGenerators.begin(), mGenerators.end(), blitter->mOutputs[i].mpSrc) - mGenerators.begin()] |= (1 << i); + + for(int i=0; iIsStateful()) + genflags[i] |= kFlagStateful; + } + + while(!mDependencies.empty()) { + const Dependency& dep = mDependencies.back(); + + genflags[dep.mSrcIdx] |= (genflags[dep.mDstIdx] & ~kFlagStateful); + + mDependencies.pop_back(); + } + + for(int i=0; imbIndependentPlanes = false; + blitter->mbIndependentChromaPlanes = false; + break; + } + } + } + + blitter->mGenerators.swap(mGenerators); + blitter->mSources.swap(mSources); + return blitter.release(); +} + +void VDPixmapUberBlitterGenerator::MarkDependency(IVDPixmapGen *dst, IVDPixmapGen *src) { + Generators::const_iterator it1(std::find(mGenerators.begin(), mGenerators.end(), dst)); + Generators::const_iterator it2(std::find(mGenerators.begin(), mGenerators.end(), src)); + + VDASSERT(it1 != mGenerators.end()); + VDASSERT(it2 != mGenerators.end()); + + int idx1 = it1 - mGenerators.begin(); + int idx2 = it2 - mGenerators.begin(); + + Dependency dep = { idx1, idx2 }; + + mDependencies.push_back(dep); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample.cpp index 6918efed975..8174d67219e 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample.cpp @@ -1,642 +1,642 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "resample_stages_x86.h" -#include "uberblit_resample.h" - -namespace { - sint32 scale32x32_fp16(sint32 x, sint32 y) { - return (sint32)(((sint64)x * y + 0x8000) >> 16); - } - - template - IVDResamplerSeparableRowStage *RowFactory(double cutoff, float filterFactor) { - return new T; - } - - template - IVDResamplerSeparableRowStage *RowFactoryLinear(double cutoff, float filterFactor) { - return new T(VDResamplerLinearFilter(cutoff)); - } - - template - IVDResamplerSeparableRowStage *RowFactoryCubic(double cutoff, float filterFactor) { - return new T(VDResamplerCubicFilter(cutoff, filterFactor)); - } - - template - IVDResamplerSeparableRowStage *RowFactoryCubic2(double cutoff, float filterFactor) { - return new T(filterFactor); - } - - template - IVDResamplerSeparableRowStage *RowFactoryLanczos3(double cutoff, float filterFactor) { - return new T(VDResamplerLanczos3Filter(cutoff)); - } - - template - IVDResamplerSeparableColStage *ColFactory(double cutoff, float filterFactor) { - return new T; - } - - template - IVDResamplerSeparableColStage *ColFactoryLinear(double cutoff, float filterFactor) { - return new T(VDResamplerLinearFilter(cutoff)); - } - - template - IVDResamplerSeparableColStage *ColFactoryCubic(double cutoff, float filterFactor) { - return new T(VDResamplerCubicFilter(cutoff, filterFactor)); - } - - template - IVDResamplerSeparableColStage *ColFactoryCubic2(double cutoff, float filterFactor) { - return new T(filterFactor); - } - - template - IVDResamplerSeparableColStage *ColFactoryLanczos3(double cutoff, float filterFactor) { - return new T(VDResamplerLanczos3Filter(cutoff)); - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDPixmapGenResampleRow -// -/////////////////////////////////////////////////////////////////////////// - -VDPixmapGenResampleRow::VDPixmapGenResampleRow() - : mpRowStage(NULL) - , mpRowStage2(NULL) -{ -} - -VDPixmapGenResampleRow::~VDPixmapGenResampleRow() { - if (mpRowStage) - delete mpRowStage; -} - -void VDPixmapGenResampleRow::Init(IVDPixmapGen *src, uint32 srcIndex, uint32 width, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly) { - InitSource(src, srcIndex); - - sint32 u0 = (sint32)(offset * 65536.0); - sint32 dudx = (sint32)(step * 65536.0); - - mAxis.Init(dudx); - - double x_2fc = 1.0; - if (!interpolationOnly && step > 1.0f) - x_2fc = 1.0 / step; - - struct SpecialCaseSpanRoutine { - sint32 mPhase; - sint32 mStep; - uint32 mType; - nsVDPixmap::FilterMode mFilterMode; - uint32 mCPUFlags; - IVDResamplerSeparableRowStage *(*mpClassFactory)(double filterCutoff, float filterFactor); - }; - - static const SpecialCaseSpanRoutine kSpecialCaseSpanRoutines[]={ - // Generic -#if defined _M_IX86 - { +0x0000, 0x008000, kVDPixType_8, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_INTEGER_SSE, RowFactory }, -#endif - - { +0x0000, 0x008000, kVDPixType_8, nsVDPixmap::kFilterLinear, 0, RowFactory }, - }; - - long flags = CPUGetEnabledExtensions(); - uint32 type = mpSrc->GetType(mSrcIndex) & kVDPixType_Mask; - - for(int i=0; iAsRowStage2(); - break; - } - - if (!mpRowStage) { - struct SpanRoutine { - uint32 mType; - bool mbInterpOnly; - nsVDPixmap::FilterMode mFilterMode; - uint32 mCPUFlags; - IVDResamplerSeparableRowStage *(*mpClassFactory)(double filterCutoff, float filterFactor); - }; - - static const SpanRoutine kSpanRoutines[]={ -#if defined _M_IX86 - // X86 - { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, CPUF_SUPPORTS_MMX, RowFactory }, - { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE41, RowFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactoryLinear }, - { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactory }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, RowFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE41, RowFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic }, - { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic2 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, RowFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE41, RowFactoryLanczos3 }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, RowFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, RowFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, RowFactoryLanczos3 }, -#elif defined _M_AMD64 - // AMD64 - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, RowFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, RowFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, RowFactoryLanczos3 }, -#endif - // Generic - { kVDPixType_8, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, - { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, - { kVDPixType_8, true, nsVDPixmap::kFilterLinear, 0, RowFactory }, - { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, 0, RowFactory }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, - }; - - for(int i=0; iAsRowStage2(); - break; - } - } - - VDASSERT(mpRowStage); - - mRowFiltW = mpRowStage->GetWindowSize(); - - mpSrc->AddWindowRequest(0, 0); - - sint32 fsx1 = (sint32)(offset * 65536.0) - ((mRowFiltW-1) << 15); - mAxis.Compute(width, fsx1, mSrcWidth, mRowFiltW); - mWidth = width; - - switch(type) { - case kVDPixType_8: - mBytesPerSample = 1; - break; - case kVDPixType_8888: - case kVDPixType_32F_LE: - mBytesPerSample = 4; - break; - case kVDPixType_32Fx4_LE: - mBytesPerSample = 16; - break; - - default: - VDASSERT(false); - } -} - -void VDPixmapGenResampleRow::Start() { - StartWindow(mWidth * mBytesPerSample); - - uint32 clipSpace = ((mRowFiltW*3*mBytesPerSample + 15) >> 4) << 2; - mTempSpace.resize(clipSpace); - - if (mpRowStage2) - mpRowStage2->Init(mAxis, mSrcWidth); -} - -void VDPixmapGenResampleRow::Compute(void *dst0, sint32 y) { - switch(mBytesPerSample) { - case 1: - Compute8(dst0, y); - break; - case 4: - Compute32(dst0, y); - break; - case 16: - Compute128(dst0, y); - break; - } -} - -void VDPixmapGenResampleRow::Compute8(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - uint8 *dst = (uint8 *)dst0; - - // process pre-copy region - if (uint32 count = mAxis.dx_precopy) { - VDMemset8(dst, src[0], count); - dst += count; - } - - uint8 *p = (uint8*)mTempSpace.data(); - sint32 u = mAxis.u; - const sint32 dudx = mAxis.dudx; - - // process dual-clip region - if (mpRowStage2) { - uint32 count = mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip + mAxis.dx_dualclip; - mpRowStage2->Process(dst, src, count); - dst += count; - } else if (uint32 count = mAxis.dx_dualclip) { - VDMemset8(p, src[0], mRowFiltW); - memcpy(p + mRowFiltW, src+1, (mSrcWidth-2)); - VDMemset8(p + mRowFiltW + (mSrcWidth-2), src[mSrcWidth-1], mRowFiltW); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count; - } else { - // process pre-clip region - if (uint32 count = mAxis.dx_preclip) { - VDMemset8(p, src[0], mRowFiltW); - memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count; - } - - // process active region - if (uint32 count = mAxis.dx_active) { - mpRowStage->Process(dst, src, count, u, dudx); - u += dudx*count; - dst += count; - } - - // process post-clip region - if (uint32 count = mAxis.dx_postclip) { - uint32 offset = mSrcWidth + 1 - mRowFiltW; - - memcpy(p, src+offset, (mRowFiltW-1)); - VDMemset8(p + (mRowFiltW-1), src[mSrcWidth-1], mRowFiltW); - - mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); - dst += count; - } - } - - // process post-copy region - if (uint32 count = mAxis.dx_postcopy) { - VDMemset8(dst, src[mSrcWidth-1], count); - } -} - -void VDPixmapGenResampleRow::Compute32(void *dst0, sint32 y) { - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - uint32 *dst = (uint32 *)dst0; - - // process pre-copy region - if (uint32 count = mAxis.dx_precopy) { - VDMemset32(dst, src[0], count); - dst += count; - } - - uint32 *p = mTempSpace.data(); - sint32 u = mAxis.u; - const sint32 dudx = mAxis.dudx; - - // process dual-clip region - if (uint32 count = mAxis.dx_dualclip) { - VDMemset32(p, src[0], mRowFiltW); - memcpy(p + mRowFiltW, src+1, (mSrcWidth-2)*sizeof(uint32)); - VDMemset32(p + mRowFiltW + (mSrcWidth-2), src[mSrcWidth-1], mRowFiltW); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count; - } else if (mpRowStage2) { - mpRowStage2->Process(dst, p, mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip); - } else { - // process pre-clip region - if (uint32 count = mAxis.dx_preclip) { - VDMemset32(p, src[0], mRowFiltW); - memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32)); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count; - } - - // process active region - if (uint32 count = mAxis.dx_active) { - mpRowStage->Process(dst, src, count, u, dudx); - u += dudx*count; - dst += count; - } - - // process post-clip region - if (uint32 count = mAxis.dx_postclip) { - uint32 offset = mSrcWidth + 1 - mRowFiltW; - - memcpy(p, src+offset, (mRowFiltW-1)*sizeof(uint32)); - VDMemset32(p + (mRowFiltW-1), src[mSrcWidth-1], mRowFiltW); - - mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); - dst += count; - } - } - - // process post-copy region - if (uint32 count = mAxis.dx_postcopy) { - VDMemset32(dst, src[mSrcWidth-1], count); - } -} - -void VDPixmapGenResampleRow::Compute128(void *dst0, sint32 y) { - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - uint32 *dst = (uint32 *)dst0; - - // process pre-copy region - if (uint32 count = mAxis.dx_precopy) { - VDMemset128(dst, src, count); - dst += 4*count; - } - - uint32 *p = mTempSpace.data(); - sint32 u = mAxis.u; - const sint32 dudx = mAxis.dudx; - - // process dual-clip region - if (uint32 count = mAxis.dx_dualclip) { - VDMemset128(p, src, mRowFiltW); - memcpy(p + 4*mRowFiltW, src+1, (mSrcWidth-2)*sizeof(uint32)*4); - VDMemset128(p + 4*(mRowFiltW + (mSrcWidth-2)), src + 4*(mSrcWidth-1), mRowFiltW); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count * 4; - } else if (mpRowStage2) { - mpRowStage2->Process(dst, p, mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip); - } else { - // process pre-clip region - if (uint32 count = mAxis.dx_preclip) { - VDMemset128(p, src, mRowFiltW); - memcpy(p + 4*mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32)*4); - - mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); - u += dudx*count; - dst += count*4; - } - - // process active region - if (uint32 count = mAxis.dx_active) { - mpRowStage->Process(dst, src, count, u, dudx); - u += dudx*count; - dst += count*4; - } - - // process post-clip region - if (uint32 count = mAxis.dx_postclip) { - uint32 offset = mSrcWidth + 1 - mRowFiltW; - - memcpy(p, src+offset*4, (mRowFiltW-1)*sizeof(uint32)*4); - VDMemset128(p + 4*(mRowFiltW-1), src + 4*(mSrcWidth-1), mRowFiltW); - - mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); - dst += count*4; - } - } - - // process post-copy region - if (uint32 count = mAxis.dx_postcopy) { - VDMemset128(dst, src + 4*(mSrcWidth-1), count); - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDPixmapGenResampleCol -// -/////////////////////////////////////////////////////////////////////////// - -VDPixmapGenResampleCol::VDPixmapGenResampleCol() - : mpColStage(NULL) -{ -} - -VDPixmapGenResampleCol::~VDPixmapGenResampleCol() { - if (mpColStage) - delete mpColStage; -} - -void VDPixmapGenResampleCol::Init(IVDPixmapGen *src, uint32 srcIndex, uint32 height, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly) { - InitSource(src, srcIndex); - - sint32 dvdy = (sint32)(step * 65536.0); - - mAxis.Init(dvdy); - - // construct stages - double y_2fc = 1.0; - if (!interpolationOnly && step > 1.0f) - y_2fc = 1.0 / step; - - struct SpanRoutine { - uint32 mType; - bool mbInterpOnly; - nsVDPixmap::FilterMode mFilterMode; - uint32 mCPUFlags; - IVDResamplerSeparableColStage *(*mpClassFactory)(double filterCutoff, float filterFactor); - }; - - static const SpanRoutine kSpanRoutines[]={ -#if defined _M_IX86 - // X86 - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE41, ColFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactoryLinear }, - { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactory }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, ColFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE41, ColFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic }, - { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic2 }, - { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic2 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE41, ColFactoryLanczos3 }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, ColFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, ColFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, ColFactoryLanczos3 }, -#elif defined _M_AMD64 - // AMD64 - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, ColFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, ColFactoryLanczos3 }, -#endif - // Generic - { kVDPixType_8, true, nsVDPixmap::kFilterLinear, 0, ColFactory }, - { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, 0, ColFactory }, - { kVDPixType_8, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, - { kVDPixType_8, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, - { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, - { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, - { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, - { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, - { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, - }; - - long flags = CPUGetEnabledExtensions(); - uint32 type = src->GetType(srcIndex) & kVDPixType_Mask; - for(int i=0; iGetWindowSize() : 1; - mWindow.resize(mWinSize); - - int delta = (mWinSize + 1) >> 1; - mpSrc->AddWindowRequest(-delta, delta); - - sint32 fsy1 = (sint32)(offset * 65536.0) - ((mWinSize-1)<<15); - mAxis.Compute(height, fsy1, mSrcHeight, mWinSize); - mHeight = height; - - switch(type) { - case kVDPixType_8: - mBytesPerSample = 1; - break; - case kVDPixType_8888: - case kVDPixType_32F_LE: - mBytesPerSample = 4; - break; - case kVDPixType_32Fx4_LE: - mBytesPerSample = 16; - break; - - default: - VDASSERT(false); - } -} - -void VDPixmapGenResampleCol::Start() { - mBytesPerRow = mWidth * mBytesPerSample; - StartWindow(mBytesPerRow); -} - -void VDPixmapGenResampleCol::Compute(void *dst0, sint32 y) { - const uint32 winsize = mWinSize; - const uint32 dx = mSrcWidth; - - y -= (sint32)mAxis.dx_precopy; - - if (y < 0) { - const void *srcrow0 = mpSrc->GetRow(0, mSrcIndex); - memcpy(dst0, srcrow0, mBytesPerRow); - return; - } - - uint32 midrange = mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip + mAxis.dx_dualclip; - - if (y < (sint32)midrange) { - sint32 v = mAxis.u + mAxis.dudx * y; - - if (mpColStage) { - for(uint32 i=0; i> 16) + i; - - if ((unsigned)sy >= (unsigned)mSrcHeight) - sy = (~sy >> 31) & (mSrcHeight - 1); - - mWindow[i] = mpSrc->GetRow(sy, mSrcIndex); - } - - mpColStage->Process(dst0, mWindow.data(), dx, v); - } else - memcpy(dst0, mpSrc->GetRow(v >> 16, mSrcIndex), mBytesPerRow); - return; - } - - const void *p = mpSrc->GetRow(mSrcHeight - 1, mSrcIndex); - - memcpy(dst0, p, mBytesPerRow); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "resample_stages_x86.h" +#include "uberblit_resample.h" + +namespace { + sint32 scale32x32_fp16(sint32 x, sint32 y) { + return (sint32)(((sint64)x * y + 0x8000) >> 16); + } + + template + IVDResamplerSeparableRowStage *RowFactory(double cutoff, float filterFactor) { + return new T; + } + + template + IVDResamplerSeparableRowStage *RowFactoryLinear(double cutoff, float filterFactor) { + return new T(VDResamplerLinearFilter(cutoff)); + } + + template + IVDResamplerSeparableRowStage *RowFactoryCubic(double cutoff, float filterFactor) { + return new T(VDResamplerCubicFilter(cutoff, filterFactor)); + } + + template + IVDResamplerSeparableRowStage *RowFactoryCubic2(double cutoff, float filterFactor) { + return new T(filterFactor); + } + + template + IVDResamplerSeparableRowStage *RowFactoryLanczos3(double cutoff, float filterFactor) { + return new T(VDResamplerLanczos3Filter(cutoff)); + } + + template + IVDResamplerSeparableColStage *ColFactory(double cutoff, float filterFactor) { + return new T; + } + + template + IVDResamplerSeparableColStage *ColFactoryLinear(double cutoff, float filterFactor) { + return new T(VDResamplerLinearFilter(cutoff)); + } + + template + IVDResamplerSeparableColStage *ColFactoryCubic(double cutoff, float filterFactor) { + return new T(VDResamplerCubicFilter(cutoff, filterFactor)); + } + + template + IVDResamplerSeparableColStage *ColFactoryCubic2(double cutoff, float filterFactor) { + return new T(filterFactor); + } + + template + IVDResamplerSeparableColStage *ColFactoryLanczos3(double cutoff, float filterFactor) { + return new T(VDResamplerLanczos3Filter(cutoff)); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDPixmapGenResampleRow +// +/////////////////////////////////////////////////////////////////////////// + +VDPixmapGenResampleRow::VDPixmapGenResampleRow() + : mpRowStage(NULL) + , mpRowStage2(NULL) +{ +} + +VDPixmapGenResampleRow::~VDPixmapGenResampleRow() { + if (mpRowStage) + delete mpRowStage; +} + +void VDPixmapGenResampleRow::Init(IVDPixmapGen *src, uint32 srcIndex, uint32 width, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly) { + InitSource(src, srcIndex); + + sint32 u0 = (sint32)(offset * 65536.0); + sint32 dudx = (sint32)(step * 65536.0); + + mAxis.Init(dudx); + + double x_2fc = 1.0; + if (!interpolationOnly && step > 1.0f) + x_2fc = 1.0 / step; + + struct SpecialCaseSpanRoutine { + sint32 mPhase; + sint32 mStep; + uint32 mType; + nsVDPixmap::FilterMode mFilterMode; + uint32 mCPUFlags; + IVDResamplerSeparableRowStage *(*mpClassFactory)(double filterCutoff, float filterFactor); + }; + + static const SpecialCaseSpanRoutine kSpecialCaseSpanRoutines[]={ + // Generic +#if defined _M_IX86 + { +0x0000, 0x008000, kVDPixType_8, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_INTEGER_SSE, RowFactory }, +#endif + + { +0x0000, 0x008000, kVDPixType_8, nsVDPixmap::kFilterLinear, 0, RowFactory }, + }; + + long flags = CPUGetEnabledExtensions(); + uint32 type = mpSrc->GetType(mSrcIndex) & kVDPixType_Mask; + + for(int i=0; iAsRowStage2(); + break; + } + + if (!mpRowStage) { + struct SpanRoutine { + uint32 mType; + bool mbInterpOnly; + nsVDPixmap::FilterMode mFilterMode; + uint32 mCPUFlags; + IVDResamplerSeparableRowStage *(*mpClassFactory)(double filterCutoff, float filterFactor); + }; + + static const SpanRoutine kSpanRoutines[]={ +#if defined _M_IX86 + // X86 + { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, CPUF_SUPPORTS_MMX, RowFactory }, + { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE41, RowFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactoryLinear }, + { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactory }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, RowFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, RowFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE41, RowFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic }, + { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic2 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, RowFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, RowFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE41, RowFactoryLanczos3 }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, RowFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, RowFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, RowFactoryLanczos3 }, +#elif defined _M_AMD64 + // AMD64 + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, RowFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, RowFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, RowFactoryLanczos3 }, +#endif + // Generic + { kVDPixType_8, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, + { kVDPixType_8888, false, nsVDPixmap::kFilterPoint, 0, RowFactory }, + { kVDPixType_8, true, nsVDPixmap::kFilterLinear, 0, RowFactory }, + { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, 0, RowFactory }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLinear, 0, RowFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterCubic, 0, RowFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLanczos3, 0, RowFactoryLanczos3 }, + }; + + for(int i=0; iAsRowStage2(); + break; + } + } + + VDASSERT(mpRowStage); + + mRowFiltW = mpRowStage->GetWindowSize(); + + mpSrc->AddWindowRequest(0, 0); + + sint32 fsx1 = (sint32)(offset * 65536.0) - ((mRowFiltW-1) << 15); + mAxis.Compute(width, fsx1, mSrcWidth, mRowFiltW); + mWidth = width; + + switch(type) { + case kVDPixType_8: + mBytesPerSample = 1; + break; + case kVDPixType_8888: + case kVDPixType_32F_LE: + mBytesPerSample = 4; + break; + case kVDPixType_32Fx4_LE: + mBytesPerSample = 16; + break; + + default: + VDASSERT(false); + } +} + +void VDPixmapGenResampleRow::Start() { + StartWindow(mWidth * mBytesPerSample); + + uint32 clipSpace = ((mRowFiltW*3*mBytesPerSample + 15) >> 4) << 2; + mTempSpace.resize(clipSpace); + + if (mpRowStage2) + mpRowStage2->Init(mAxis, mSrcWidth); +} + +void VDPixmapGenResampleRow::Compute(void *dst0, sint32 y) { + switch(mBytesPerSample) { + case 1: + Compute8(dst0, y); + break; + case 4: + Compute32(dst0, y); + break; + case 16: + Compute128(dst0, y); + break; + } +} + +void VDPixmapGenResampleRow::Compute8(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + uint8 *dst = (uint8 *)dst0; + + // process pre-copy region + if (uint32 count = mAxis.dx_precopy) { + VDMemset8(dst, src[0], count); + dst += count; + } + + uint8 *p = (uint8*)mTempSpace.data(); + sint32 u = mAxis.u; + const sint32 dudx = mAxis.dudx; + + // process dual-clip region + if (mpRowStage2) { + uint32 count = mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip + mAxis.dx_dualclip; + mpRowStage2->Process(dst, src, count); + dst += count; + } else if (uint32 count = mAxis.dx_dualclip) { + VDMemset8(p, src[0], mRowFiltW); + memcpy(p + mRowFiltW, src+1, (mSrcWidth-2)); + VDMemset8(p + mRowFiltW + (mSrcWidth-2), src[mSrcWidth-1], mRowFiltW); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count; + } else { + // process pre-clip region + if (uint32 count = mAxis.dx_preclip) { + VDMemset8(p, src[0], mRowFiltW); + memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count; + } + + // process active region + if (uint32 count = mAxis.dx_active) { + mpRowStage->Process(dst, src, count, u, dudx); + u += dudx*count; + dst += count; + } + + // process post-clip region + if (uint32 count = mAxis.dx_postclip) { + uint32 offset = mSrcWidth + 1 - mRowFiltW; + + memcpy(p, src+offset, (mRowFiltW-1)); + VDMemset8(p + (mRowFiltW-1), src[mSrcWidth-1], mRowFiltW); + + mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); + dst += count; + } + } + + // process post-copy region + if (uint32 count = mAxis.dx_postcopy) { + VDMemset8(dst, src[mSrcWidth-1], count); + } +} + +void VDPixmapGenResampleRow::Compute32(void *dst0, sint32 y) { + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + uint32 *dst = (uint32 *)dst0; + + // process pre-copy region + if (uint32 count = mAxis.dx_precopy) { + VDMemset32(dst, src[0], count); + dst += count; + } + + uint32 *p = mTempSpace.data(); + sint32 u = mAxis.u; + const sint32 dudx = mAxis.dudx; + + // process dual-clip region + if (uint32 count = mAxis.dx_dualclip) { + VDMemset32(p, src[0], mRowFiltW); + memcpy(p + mRowFiltW, src+1, (mSrcWidth-2)*sizeof(uint32)); + VDMemset32(p + mRowFiltW + (mSrcWidth-2), src[mSrcWidth-1], mRowFiltW); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count; + } else if (mpRowStage2) { + mpRowStage2->Process(dst, p, mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip); + } else { + // process pre-clip region + if (uint32 count = mAxis.dx_preclip) { + VDMemset32(p, src[0], mRowFiltW); + memcpy(p + mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32)); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count; + } + + // process active region + if (uint32 count = mAxis.dx_active) { + mpRowStage->Process(dst, src, count, u, dudx); + u += dudx*count; + dst += count; + } + + // process post-clip region + if (uint32 count = mAxis.dx_postclip) { + uint32 offset = mSrcWidth + 1 - mRowFiltW; + + memcpy(p, src+offset, (mRowFiltW-1)*sizeof(uint32)); + VDMemset32(p + (mRowFiltW-1), src[mSrcWidth-1], mRowFiltW); + + mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); + dst += count; + } + } + + // process post-copy region + if (uint32 count = mAxis.dx_postcopy) { + VDMemset32(dst, src[mSrcWidth-1], count); + } +} + +void VDPixmapGenResampleRow::Compute128(void *dst0, sint32 y) { + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + uint32 *dst = (uint32 *)dst0; + + // process pre-copy region + if (uint32 count = mAxis.dx_precopy) { + VDMemset128(dst, src, count); + dst += 4*count; + } + + uint32 *p = mTempSpace.data(); + sint32 u = mAxis.u; + const sint32 dudx = mAxis.dudx; + + // process dual-clip region + if (uint32 count = mAxis.dx_dualclip) { + VDMemset128(p, src, mRowFiltW); + memcpy(p + 4*mRowFiltW, src+1, (mSrcWidth-2)*sizeof(uint32)*4); + VDMemset128(p + 4*(mRowFiltW + (mSrcWidth-2)), src + 4*(mSrcWidth-1), mRowFiltW); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count * 4; + } else if (mpRowStage2) { + mpRowStage2->Process(dst, p, mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip); + } else { + // process pre-clip region + if (uint32 count = mAxis.dx_preclip) { + VDMemset128(p, src, mRowFiltW); + memcpy(p + 4*mRowFiltW, src+1, (mRowFiltW-1)*sizeof(uint32)*4); + + mpRowStage->Process(dst, p, count, u + ((mRowFiltW-1)<<16), dudx); + u += dudx*count; + dst += count*4; + } + + // process active region + if (uint32 count = mAxis.dx_active) { + mpRowStage->Process(dst, src, count, u, dudx); + u += dudx*count; + dst += count*4; + } + + // process post-clip region + if (uint32 count = mAxis.dx_postclip) { + uint32 offset = mSrcWidth + 1 - mRowFiltW; + + memcpy(p, src+offset*4, (mRowFiltW-1)*sizeof(uint32)*4); + VDMemset128(p + 4*(mRowFiltW-1), src + 4*(mSrcWidth-1), mRowFiltW); + + mpRowStage->Process(dst, p, count, u - (offset<<16), dudx); + dst += count*4; + } + } + + // process post-copy region + if (uint32 count = mAxis.dx_postcopy) { + VDMemset128(dst, src + 4*(mSrcWidth-1), count); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDPixmapGenResampleCol +// +/////////////////////////////////////////////////////////////////////////// + +VDPixmapGenResampleCol::VDPixmapGenResampleCol() + : mpColStage(NULL) +{ +} + +VDPixmapGenResampleCol::~VDPixmapGenResampleCol() { + if (mpColStage) + delete mpColStage; +} + +void VDPixmapGenResampleCol::Init(IVDPixmapGen *src, uint32 srcIndex, uint32 height, float offset, float step, nsVDPixmap::FilterMode filterMode, float filterFactor, bool interpolationOnly) { + InitSource(src, srcIndex); + + sint32 dvdy = (sint32)(step * 65536.0); + + mAxis.Init(dvdy); + + // construct stages + double y_2fc = 1.0; + if (!interpolationOnly && step > 1.0f) + y_2fc = 1.0 / step; + + struct SpanRoutine { + uint32 mType; + bool mbInterpOnly; + nsVDPixmap::FilterMode mFilterMode; + uint32 mCPUFlags; + IVDResamplerSeparableColStage *(*mpClassFactory)(double filterCutoff, float filterFactor); + }; + + static const SpanRoutine kSpanRoutines[]={ +#if defined _M_IX86 + // X86 + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE41, ColFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactoryLinear }, + { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactory }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, ColFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_MMX, ColFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE41, ColFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic }, + { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic2 }, + { kVDPixType_8888, true, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic2 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_MMX, ColFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE41, ColFactoryLanczos3 }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, ColFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, ColFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_MMX, ColFactoryLanczos3 }, +#elif defined _M_AMD64 + // AMD64 + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, CPUF_SUPPORTS_SSE2, ColFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, CPUF_SUPPORTS_SSE2, ColFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, CPUF_SUPPORTS_SSE2, ColFactoryLanczos3 }, +#endif + // Generic + { kVDPixType_8, true, nsVDPixmap::kFilterLinear, 0, ColFactory }, + { kVDPixType_8888, true, nsVDPixmap::kFilterLinear, 0, ColFactory }, + { kVDPixType_8, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLinear, 0, ColFactoryLinear }, + { kVDPixType_8, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, + { kVDPixType_8888, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterCubic, 0, ColFactoryCubic }, + { kVDPixType_8, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, + { kVDPixType_8888, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, + { kVDPixType_32F_LE, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, + { kVDPixType_32Fx4_LE, false, nsVDPixmap::kFilterLanczos3, 0, ColFactoryLanczos3 }, + }; + + long flags = CPUGetEnabledExtensions(); + uint32 type = src->GetType(srcIndex) & kVDPixType_Mask; + for(int i=0; iGetWindowSize() : 1; + mWindow.resize(mWinSize); + + int delta = (mWinSize + 1) >> 1; + mpSrc->AddWindowRequest(-delta, delta); + + sint32 fsy1 = (sint32)(offset * 65536.0) - ((mWinSize-1)<<15); + mAxis.Compute(height, fsy1, mSrcHeight, mWinSize); + mHeight = height; + + switch(type) { + case kVDPixType_8: + mBytesPerSample = 1; + break; + case kVDPixType_8888: + case kVDPixType_32F_LE: + mBytesPerSample = 4; + break; + case kVDPixType_32Fx4_LE: + mBytesPerSample = 16; + break; + + default: + VDASSERT(false); + } +} + +void VDPixmapGenResampleCol::Start() { + mBytesPerRow = mWidth * mBytesPerSample; + StartWindow(mBytesPerRow); +} + +void VDPixmapGenResampleCol::Compute(void *dst0, sint32 y) { + const uint32 winsize = mWinSize; + const uint32 dx = mSrcWidth; + + y -= (sint32)mAxis.dx_precopy; + + if (y < 0) { + const void *srcrow0 = mpSrc->GetRow(0, mSrcIndex); + memcpy(dst0, srcrow0, mBytesPerRow); + return; + } + + uint32 midrange = mAxis.dx_preclip + mAxis.dx_active + mAxis.dx_postclip + mAxis.dx_dualclip; + + if (y < (sint32)midrange) { + sint32 v = mAxis.u + mAxis.dudx * y; + + if (mpColStage) { + for(uint32 i=0; i> 16) + i; + + if ((unsigned)sy >= (unsigned)mSrcHeight) + sy = (~sy >> 31) & (mSrcHeight - 1); + + mWindow[i] = mpSrc->GetRow(sy, mSrcIndex); + } + + mpColStage->Process(dst0, mWindow.data(), dx, v); + } else + memcpy(dst0, mpSrc->GetRow(v >> 16, mSrcIndex), mBytesPerRow); + return; + } + + const void *p = mpSrc->GetRow(mSrcHeight - 1, mSrcIndex); + + memcpy(dst0, p, mBytesPerRow); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special.cpp index a962dd4a02b..b162dbcc035 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special.cpp @@ -1,205 +1,205 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include "uberblit_resample_special.h" -#include "blt_spanutils.h" - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleRow_d2_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(0, 0); - - mWidth = (mSrcWidth + 1) >> 1; -} - -void VDPixmapGenResampleRow_d2_p0_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleRow_d2_p0_lin_u8::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_compress2x_coaligned((uint8 *)dst0, src, mSrcWidth); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleRow_d4_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(0, 0); - - mWidth = (mSrcWidth + 3) >> 2; -} - -void VDPixmapGenResampleRow_d4_p0_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleRow_d4_p0_lin_u8::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_compress4x_coaligned((uint8 *)dst0, src, mSrcWidth); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleRow_x2_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(0, 0); - - mWidth = mSrcWidth * 2; -} - -void VDPixmapGenResampleRow_x2_p0_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleRow_x2_p0_lin_u8::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_expand2x_coaligned((uint8 *)dst0, src, mWidth); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleRow_x4_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(0, 0); - - mWidth = mSrcWidth * 4; -} - -void VDPixmapGenResampleRow_x4_p0_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleRow_x4_p0_lin_u8::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_expand4x_coaligned((uint8 *)dst0, src, mWidth); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleCol_x2_phalf_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(-2, 2); - - mHeight = (mSrcHeight + 1) >> 1; -} - -void VDPixmapGenResampleCol_x2_phalf_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleCol_x2_phalf_lin_u8::Compute(void *dst0, sint32 y) { - sint32 y2 = y+y; - const uint8 *src[4] = { - (const uint8 *)mpSrc->GetRow(y2 > 0 ? y2-1 : 0, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2 , mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+2, mSrcIndex) - }; - - nsVDPixmapSpanUtils::vert_compress2x_centered((uint8 *)dst0, src, mWidth, 0); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleCol_x4_p1half_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(-4, 4); - - mHeight = (mSrcHeight + 2) >> 2; -} - -void VDPixmapGenResampleCol_x4_p1half_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleCol_x4_p1half_lin_u8::Compute(void *dst0, sint32 y) { - sint32 y4 = y*4; - const uint8 *src[8] = { - (const uint8 *)mpSrc->GetRow(y4 > 2 ? y4-2 : 0, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4 > 1 ? y4-1 : 0, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4 , mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+1, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+3, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+4, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y4+5, mSrcIndex) - }; - - nsVDPixmapSpanUtils::vert_compress4x_centered((uint8 *)dst0, src, mWidth, 0); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(-1, 1); - - mHeight = mSrcHeight * 2; -} - -void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Compute(void *dst0, sint32 y) { - sint32 y2 = (y - 1) >> 1; - const uint8 *src[2] = { - (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - }; - - nsVDPixmapSpanUtils::vert_expand2x_centered((uint8 *)dst0, src, mWidth, ~y << 7); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGenResampleCol_d4_pn38_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { - InitSource(src, srcIndex); - src->AddWindowRequest(-1, 1); - - mHeight = mSrcHeight * 4; -} - -void VDPixmapGenResampleCol_d4_pn38_lin_u8::Start() { - mpSrc->Start(); - StartWindow(mWidth); -} - -void VDPixmapGenResampleCol_d4_pn38_lin_u8::Compute(void *dst0, sint32 y) { - sint32 y2 = (y - 2) >> 2; - const uint8 *src[2] = { - (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - }; - - nsVDPixmapSpanUtils::vert_expand4x_centered((uint8 *)dst0, src, mWidth, (y - 2) << 6); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "uberblit_resample_special.h" +#include "blt_spanutils.h" + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleRow_d2_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(0, 0); + + mWidth = (mSrcWidth + 1) >> 1; +} + +void VDPixmapGenResampleRow_d2_p0_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleRow_d2_p0_lin_u8::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_compress2x_coaligned((uint8 *)dst0, src, mSrcWidth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleRow_d4_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(0, 0); + + mWidth = (mSrcWidth + 3) >> 2; +} + +void VDPixmapGenResampleRow_d4_p0_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleRow_d4_p0_lin_u8::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_compress4x_coaligned((uint8 *)dst0, src, mSrcWidth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleRow_x2_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(0, 0); + + mWidth = mSrcWidth * 2; +} + +void VDPixmapGenResampleRow_x2_p0_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleRow_x2_p0_lin_u8::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_expand2x_coaligned((uint8 *)dst0, src, mWidth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleRow_x4_p0_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(0, 0); + + mWidth = mSrcWidth * 4; +} + +void VDPixmapGenResampleRow_x4_p0_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleRow_x4_p0_lin_u8::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_expand4x_coaligned((uint8 *)dst0, src, mWidth); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleCol_x2_phalf_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(-2, 2); + + mHeight = (mSrcHeight + 1) >> 1; +} + +void VDPixmapGenResampleCol_x2_phalf_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleCol_x2_phalf_lin_u8::Compute(void *dst0, sint32 y) { + sint32 y2 = y+y; + const uint8 *src[4] = { + (const uint8 *)mpSrc->GetRow(y2 > 0 ? y2-1 : 0, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2 , mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+2, mSrcIndex) + }; + + nsVDPixmapSpanUtils::vert_compress2x_centered((uint8 *)dst0, src, mWidth, 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleCol_x4_p1half_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(-4, 4); + + mHeight = (mSrcHeight + 2) >> 2; +} + +void VDPixmapGenResampleCol_x4_p1half_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleCol_x4_p1half_lin_u8::Compute(void *dst0, sint32 y) { + sint32 y4 = y*4; + const uint8 *src[8] = { + (const uint8 *)mpSrc->GetRow(y4 > 2 ? y4-2 : 0, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4 > 1 ? y4-1 : 0, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4 , mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+1, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+3, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+4, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y4+5, mSrcIndex) + }; + + nsVDPixmapSpanUtils::vert_compress4x_centered((uint8 *)dst0, src, mWidth, 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(-1, 1); + + mHeight = mSrcHeight * 2; +} + +void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8::Compute(void *dst0, sint32 y) { + sint32 y2 = (y - 1) >> 1; + const uint8 *src[2] = { + (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + }; + + nsVDPixmapSpanUtils::vert_expand2x_centered((uint8 *)dst0, src, mWidth, ~y << 7); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGenResampleCol_d4_pn38_lin_u8::Init(IVDPixmapGen *src, uint32 srcIndex) { + InitSource(src, srcIndex); + src->AddWindowRequest(-1, 1); + + mHeight = mSrcHeight * 4; +} + +void VDPixmapGenResampleCol_d4_pn38_lin_u8::Start() { + mpSrc->Start(); + StartWindow(mWidth); +} + +void VDPixmapGenResampleCol_d4_pn38_lin_u8::Compute(void *dst0, sint32 y) { + sint32 y2 = (y - 2) >> 2; + const uint8 *src[2] = { + (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + }; + + nsVDPixmapSpanUtils::vert_expand4x_centered((uint8 *)dst0, src, mWidth, (y - 2) << 6); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special_x86.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special_x86.cpp index dcb650513a9..990e0520ed3 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special_x86.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_resample_special_x86.cpp @@ -1,54 +1,54 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include "uberblit_resample_special_x86.h" -#include "blt_spanutils.h" -#include "blt_spanutils_x86.h" - -void VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE((uint8 *)dst0, src, mWidth); -} - -void VDPixmapGenResampleRow_x4_p0_lin_u8_MMX::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - nsVDPixmapSpanUtils::horiz_expand4x_coaligned_MMX((uint8 *)dst0, src, mWidth); -} - -void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE::Compute(void *dst0, sint32 y) { - sint32 y2 = (y - 1) >> 1; - const uint8 *src[2] = { - (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - }; - - nsVDPixmapSpanUtils::vert_expand2x_centered_ISSE((uint8 *)dst0, src, mWidth, ~y << 7); -} - -void VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE::Compute(void *dst0, sint32 y) { - sint32 y2 = (y - 2) >> 2; - const uint8 *src[2] = { - (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), - (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), - }; - - nsVDPixmapSpanUtils::vert_expand4x_centered_ISSE((uint8 *)dst0, src, mWidth, (y - 2) << 6); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "uberblit_resample_special_x86.h" +#include "blt_spanutils.h" +#include "blt_spanutils_x86.h" + +void VDPixmapGenResampleRow_x2_p0_lin_u8_ISSE::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE((uint8 *)dst0, src, mWidth); +} + +void VDPixmapGenResampleRow_x4_p0_lin_u8_MMX::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + nsVDPixmapSpanUtils::horiz_expand4x_coaligned_MMX((uint8 *)dst0, src, mWidth); +} + +void VDPixmapGenResampleCol_d2_pnqrtr_lin_u8_ISSE::Compute(void *dst0, sint32 y) { + sint32 y2 = (y - 1) >> 1; + const uint8 *src[2] = { + (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + }; + + nsVDPixmapSpanUtils::vert_expand2x_centered_ISSE((uint8 *)dst0, src, mWidth, ~y << 7); +} + +void VDPixmapGenResampleCol_d4_pn38_lin_u8_ISSE::Compute(void *dst0, sint32 y) { + sint32 y2 = (y - 2) >> 2; + const uint8 *src[2] = { + (const uint8 *)mpSrc->GetRow(y2, mSrcIndex), + (const uint8 *)mpSrc->GetRow(y2+1, mSrcIndex), + }; + + nsVDPixmapSpanUtils::vert_expand4x_centered_ISSE((uint8 *)dst0, src, mWidth, (y - 2) << 6); +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_swizzle.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_swizzle.cpp index 7376692eafa..d65c317a242 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_swizzle.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_swizzle.cpp @@ -1,108 +1,108 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include "uberblit_swizzle.h" - -void VDPixmapGen_Swap8In16::Init(IVDPixmapGen *gen, int srcIndex, uint32 w, uint32 h, uint32 bpr) { - InitSource(gen, srcIndex); - mRowLength = bpr; - SetOutputSize(w, h); - gen->AddWindowRequest(0, 0); -} - -void VDPixmapGen_Swap8In16::Start() { - StartWindow(mRowLength); -} - -uint32 VDPixmapGen_Swap8In16::GetType(uint32 index) const { - return mpSrc->GetType(mSrcIndex); -} - -void VDPixmapGen_Swap8In16::Compute(void *dst0, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - uint8 *dst = (uint8 *)dst0; - sint32 w = mRowLength; - - uint32 n4 = w >> 2; - - for(uint32 i=0; i> 8) + ((p & 0x00ff00ff) << 8); - - *(uint32 *)dst = r; - dst += 4; - } - - if (w & 2) { - dst[0] = src[1]; - dst[1] = src[0]; - dst += 2; - src += 2; - } - - if (w & 1) { - *dst = *src; - } -} - -///////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_B8x2_To_B8R8::Init(IVDPixmapGen *srcCb, uint32 srcindexCb, IVDPixmapGen *srcCr, uint32 srcindexCr) { - mpSrcCb = srcCb; - mSrcIndexCb = srcindexCb; - mpSrcCr = srcCr; - mSrcIndexCr = srcindexCr; - mWidth = srcCb->GetWidth(srcindexCb); - mHeight = srcCb->GetHeight(srcindexCb); - - srcCb->AddWindowRequest(0, 0); - srcCr->AddWindowRequest(0, 0); -} - -void VDPixmapGen_B8x2_To_B8R8::Start() { - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * 2); -} - -uint32 VDPixmapGen_B8x2_To_B8R8::GetType(uint32 output) const { - return (mpSrcCb->GetType(mSrcIndexCb) & ~kVDPixType_Mask) | kVDPixType_B8R8; -} - -void VDPixmapGen_B8x2_To_B8R8::Compute(void *dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *)dst0; - const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - sint32 w = mWidth; - for(sint32 x=0; x +#include "uberblit_swizzle.h" + +void VDPixmapGen_Swap8In16::Init(IVDPixmapGen *gen, int srcIndex, uint32 w, uint32 h, uint32 bpr) { + InitSource(gen, srcIndex); + mRowLength = bpr; + SetOutputSize(w, h); + gen->AddWindowRequest(0, 0); +} + +void VDPixmapGen_Swap8In16::Start() { + StartWindow(mRowLength); +} + +uint32 VDPixmapGen_Swap8In16::GetType(uint32 index) const { + return mpSrc->GetType(mSrcIndex); +} + +void VDPixmapGen_Swap8In16::Compute(void *dst0, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + uint8 *dst = (uint8 *)dst0; + sint32 w = mRowLength; + + uint32 n4 = w >> 2; + + for(uint32 i=0; i> 8) + ((p & 0x00ff00ff) << 8); + + *(uint32 *)dst = r; + dst += 4; + } + + if (w & 2) { + dst[0] = src[1]; + dst[1] = src[0]; + dst += 2; + src += 2; + } + + if (w & 1) { + *dst = *src; + } +} + +///////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_B8x2_To_B8R8::Init(IVDPixmapGen *srcCb, uint32 srcindexCb, IVDPixmapGen *srcCr, uint32 srcindexCr) { + mpSrcCb = srcCb; + mSrcIndexCb = srcindexCb; + mpSrcCr = srcCr; + mSrcIndexCr = srcindexCr; + mWidth = srcCb->GetWidth(srcindexCb); + mHeight = srcCb->GetHeight(srcindexCb); + + srcCb->AddWindowRequest(0, 0); + srcCr->AddWindowRequest(0, 0); +} + +void VDPixmapGen_B8x2_To_B8R8::Start() { + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * 2); +} + +uint32 VDPixmapGen_B8x2_To_B8R8::GetType(uint32 output) const { + return (mpSrcCb->GetType(mSrcIndexCb) & ~kVDPixType_Mask) | kVDPixType_B8R8; +} + +void VDPixmapGen_B8x2_To_B8R8::Compute(void *dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *)dst0; + const uint8 *VDRESTRICT srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + sint32 w = mWidth; + for(sint32 x=0; x -#include "uberblit_swizzle_x86.h" - -#ifdef VD_COMPILER_MSVC - #pragma warning(disable: 4799) // warning C4799: function 'vdasm_extract_8in16_even_MMX' has no EMMS instruction -#endif - -void __declspec(naked) __fastcall vdasm_extract_8in16_even_MMX(void *dst, const void *src, uint32 count) { - __asm { - mov eax, [esp+4] - pcmpeqb mm2, mm2 - psrlw mm2, 8 - sub eax, 8 - jc xtra -xloop: - movq mm0, [edx] - movq mm1, [edx+8] - pand mm0, mm2 - pand mm1, mm2 - packuswb mm0, mm1 - add edx, 16 - movq [ecx], mm0 - add ecx, 8 - sub eax, 8 - jns xloop -xtra: - add eax, 8 - jz fin - push ebx -xtraloop: - mov bl, [edx] - add edx, 2 - mov [ecx], bl - add ecx, 1 - sub eax, 1 - jnz xtraloop - - pop ebx -fin: - ret 4 - } -} - -void __declspec(naked) __fastcall vdasm_extract_8in16_odd_MMX(void *dst, const void *src, uint32 count) { - __asm { - mov eax, [esp+4] - sub eax, 8 - jc xtra -xloop: - movq mm0, [edx] - movq mm1, [edx+8] - psrlw mm0, 8 - psrlw mm1, 8 - add edx, 16 - packuswb mm0, mm1 - movq [ecx], mm0 - add ecx, 8 - sub eax, 8 - jns xloop -xtra: - add eax, 8 - jz fin - push ebx -xtraloop: - mov bl, [edx+1] - add edx, 2 - mov [ecx], bl - add ecx, 1 - sub eax, 1 - jnz xtraloop - - pop ebx -fin: - ret 4 - } -} - -void __declspec(naked) __fastcall vdasm_extract_8in32_MMX(void *dst, const void *src, uint32 count, int byteshift) { - __asm { - movd mm4, [esp+8] - pcmpeqb mm5, mm5 - pslld mm4, 3 - mov eax, [esp+4] - psrld mm5, 24 - sub eax, 8 - jc xtra -xloop: - movq mm0, [edx] - movq mm1, [edx+8] - psrld mm0, mm4 - movq mm2, [edx+16] - psrld mm1, mm4 - pand mm0, mm5 - movq mm3, [edx+24] - psrld mm2, mm4 - pand mm1, mm5 - packssdw mm0, mm1 - psrld mm3, mm4 - pand mm2, mm5 - pand mm3, mm5 - add edx, 32 - packssdw mm2, mm3 - packuswb mm0, mm2 - movq [ecx], mm0 - add ecx, 8 - sub eax, 8 - jns xloop -xtra: - add eax, 8 - jz fin - add edx, dword ptr [esp+8] - push ebx -xtraloop: - mov bl, [edx] - add edx, 4 - mov [ecx], bl - add ecx, 1 - sub eax, 1 - jnz xtraloop - - pop ebx -fin: - ret 8 - } -} - -void __declspec(naked) __fastcall vdasm_swap_8in16_MMX(void *dst, const void *src, uint32 count) { - __asm { - mov eax, [esp+4] - sub eax, 8 - js xtra -xloop: - movq mm0, [edx] - add edx, 8 - movq mm1, mm0 - psllw mm0, 8 - psrlw mm1, 8 - paddb mm0, mm1 - movq [ecx], mm0 - add ecx, 8 - sub eax, 8 - jns xloop -xtra: - add eax, 6 - js nopairs - push ebx -pairloop: - mov bl, [edx] - mov bh, [edx+1] - add edx, 2 - mov [ecx], bh - mov [ecx+1], bl - add ecx, 2 - sub eax, 2 - jns pairloop - pop ebx -nopairs: - add eax, 2 - jz noodd - mov al, [edx] - mov [ecx], al -noodd: - ret 4 - } -} - -void __declspec(naked) __fastcall vdasm_interleave_BGRG_MMX(void *dst, const void *srcR, const void *srcG, const void *srcB, uint32 count) { - __asm { - push edi - push esi - push ebx - mov esi, [esp+12+12] - mov edi, [esp+8+12] - mov ebx, [esp+4+12] - sub esi, 4 - jc xtra - ; ecx = dst - ; edx = srcR - ; ebx = srcG - ; edi = srcB -xloop: - movd mm0, [edi] - movd mm1, [edx] - punpcklbw mm0, mm1 - movq mm1, [ebx] - movq mm2, mm0 - punpcklbw mm0, mm1 - add edx, 4 - punpckhbw mm2, mm1 - add edi, 4 - movq [ecx], mm0 - add ebx, 8 - movq [ecx+8], mm2 - add ecx, 16 - sub esi, 4 - jns xloop -xtra: - add esi, 4 - jz fin -xtraloop: - mov al, [edi] - mov [ecx], al - mov al, [ebx] - mov [ecx+1], al - mov al, [edx] - mov [ecx+2], al - mov al, [ebx+1] - mov [ecx+3], al - add ebx, 2 - add edx, 1 - add edi, 1 - add ecx, 4 - sub esi, 1 - jnz xtraloop -fin: - pop ebx - pop esi - pop edi - ret 12 - } -} - -void __declspec(naked) __fastcall vdasm_interleave_GBGR_MMX(void *dst, const void *srcR, const void *srcG, const void *srcB, uint32 count) { - __asm { - push edi - push esi - push ebx - mov esi, [esp+12+12] - mov edi, [esp+8+12] - mov ebx, [esp+4+12] - sub esi, 4 - jc xtra - ; ecx = dst - ; edx = srcR - ; ebx = srcG - ; edi = srcB -xloop: - movd mm0, [edi] - movd mm1, [edx] - punpcklbw mm0, mm1 - movq mm2, [ebx] - movq mm1, mm2 - punpcklbw mm2, mm0 - add edx, 4 - punpckhbw mm1, mm0 - add edi, 4 - movq [ecx], mm2 - add ebx, 8 - movq [ecx+8], mm1 - add ecx, 16 - sub esi, 4 - jns xloop -xtra: - add esi, 4 - jz fin -xtraloop: - mov al, [ebx] - mov [ecx], al - mov al, [edi] - mov [ecx+1], al - mov al, [ebx+1] - mov [ecx+2], al - mov al, [edx] - mov [ecx+3], al - add ebx, 2 - add edx, 1 - add edi, 1 - add ecx, 4 - sub esi, 1 - jnz xtraloop -fin: - pop ebx - pop esi - pop edi - ret 12 - } -} - -void __declspec(naked) __fastcall vdasm_interleave_BR_MMX(void *dst, const void *srcB, const void *srcR, uint32 count) { - __asm { - push edi - push esi - push ebx - mov esi, [esp+8+12] - mov ebx, [esp+4+12] - sub esi, 8 - jc xtra - ; ecx = dst - ; edx = srcB - ; ebx = srcG -xloop: - movq mm0, [edx] - movq mm1, [ebx] - movq mm2, mm0 - punpcklbw mm0, mm1 - punpckhbw mm2, mm1 - add edx, 8 - movq [ecx], mm0 - add ebx, 8 - movq [ecx+8], mm2 - add ecx, 16 - sub esi, 8 - jns xloop -xtra: - add esi, 8 - jz fin -xtraloop: - mov al, [edx] - mov [ecx], al - mov al, [ebx] - mov [ecx+1], al - add ebx, 1 - add edx, 1 - add ecx, 2 - sub esi, 1 - jnz xtraloop -fin: - pop ebx - pop esi - pop edi - ret 8 - } -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_8In16_Even_MMX::Compute(void *dst, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_extract_8in16_even_MMX(dst, srcp, mWidth); -} - -void VDPixmapGen_8In16_Odd_MMX::Compute(void *dst, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_extract_8in16_odd_MMX(dst, srcp, mWidth); -} - -void VDPixmapGen_8In32_MMX::Compute(void *dst, sint32 y) { - const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_extract_8in32_MMX(dst, srcp, mWidth, mOffset); -} - -void VDPixmapGen_Swap8In16_MMX::Compute(void *dst, sint32 y) { - const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - vdasm_swap_8in16_MMX(dst, src, mRowLength); -} - -void VDPixmapGen_B8x2_To_B8R8_MMX::Compute(void *dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; - const uint8 *VDRESTRICT srcCb = (const uint8 *VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); - - vdasm_interleave_BR_MMX(dst, srcCb, srcCr, mWidth); -} - -void VDPixmapGen_B8x3_To_G8B8_G8R8_MMX::Compute(void *VDRESTRICT dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; - const uint8 *VDRESTRICT srcY = (const uint8 *VDRESTRICT)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *VDRESTRICT srcCb = (const uint8 *VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 *VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); - - vdasm_interleave_GBGR_MMX(dst, srcCr, srcY, srcCb, mWidth >> 1); - - if (mWidth & 1) { - int w2 = mWidth >> 1; - srcY += mWidth; - srcCb += w2; - srcCr += w2; - dst += mWidth * 2; - - dst[-2] = srcY[-1]; - dst[-1] = srcCb[0]; - dst[ 0] = 0; // must be zero for QuickTime compatibility - dst[ 1] = srcCr[0]; - } -} - -void VDPixmapGen_B8x3_To_B8G8_R8G8_MMX::Compute(void *VDRESTRICT dst0, sint32 y) { - uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; - const uint8 *VDRESTRICT srcY = (const uint8 * VDRESTRICT)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *VDRESTRICT srcCb = (const uint8 * VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *VDRESTRICT srcCr = (const uint8 * VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); - - vdasm_interleave_BGRG_MMX(dst, srcCr, srcY, srcCb, mWidth >> 1); - - if (mWidth & 1) { - int w2 = mWidth >> 1; - srcY += mWidth; - srcCb += w2; - srcCr += w2; - dst += mWidth * 2; - - dst[-2] = srcCb[0]; - dst[-1] = srcY[-1]; - dst[ 0] = srcCr[0]; - dst[ 1] = 0; // must be zero for QuickTime compatibility - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "uberblit_swizzle_x86.h" + +#ifdef VD_COMPILER_MSVC + #pragma warning(disable: 4799) // warning C4799: function 'vdasm_extract_8in16_even_MMX' has no EMMS instruction +#endif + +void __declspec(naked) __fastcall vdasm_extract_8in16_even_MMX(void *dst, const void *src, uint32 count) { + __asm { + mov eax, [esp+4] + pcmpeqb mm2, mm2 + psrlw mm2, 8 + sub eax, 8 + jc xtra +xloop: + movq mm0, [edx] + movq mm1, [edx+8] + pand mm0, mm2 + pand mm1, mm2 + packuswb mm0, mm1 + add edx, 16 + movq [ecx], mm0 + add ecx, 8 + sub eax, 8 + jns xloop +xtra: + add eax, 8 + jz fin + push ebx +xtraloop: + mov bl, [edx] + add edx, 2 + mov [ecx], bl + add ecx, 1 + sub eax, 1 + jnz xtraloop + + pop ebx +fin: + ret 4 + } +} + +void __declspec(naked) __fastcall vdasm_extract_8in16_odd_MMX(void *dst, const void *src, uint32 count) { + __asm { + mov eax, [esp+4] + sub eax, 8 + jc xtra +xloop: + movq mm0, [edx] + movq mm1, [edx+8] + psrlw mm0, 8 + psrlw mm1, 8 + add edx, 16 + packuswb mm0, mm1 + movq [ecx], mm0 + add ecx, 8 + sub eax, 8 + jns xloop +xtra: + add eax, 8 + jz fin + push ebx +xtraloop: + mov bl, [edx+1] + add edx, 2 + mov [ecx], bl + add ecx, 1 + sub eax, 1 + jnz xtraloop + + pop ebx +fin: + ret 4 + } +} + +void __declspec(naked) __fastcall vdasm_extract_8in32_MMX(void *dst, const void *src, uint32 count, int byteshift) { + __asm { + movd mm4, [esp+8] + pcmpeqb mm5, mm5 + pslld mm4, 3 + mov eax, [esp+4] + psrld mm5, 24 + sub eax, 8 + jc xtra +xloop: + movq mm0, [edx] + movq mm1, [edx+8] + psrld mm0, mm4 + movq mm2, [edx+16] + psrld mm1, mm4 + pand mm0, mm5 + movq mm3, [edx+24] + psrld mm2, mm4 + pand mm1, mm5 + packssdw mm0, mm1 + psrld mm3, mm4 + pand mm2, mm5 + pand mm3, mm5 + add edx, 32 + packssdw mm2, mm3 + packuswb mm0, mm2 + movq [ecx], mm0 + add ecx, 8 + sub eax, 8 + jns xloop +xtra: + add eax, 8 + jz fin + add edx, dword ptr [esp+8] + push ebx +xtraloop: + mov bl, [edx] + add edx, 4 + mov [ecx], bl + add ecx, 1 + sub eax, 1 + jnz xtraloop + + pop ebx +fin: + ret 8 + } +} + +void __declspec(naked) __fastcall vdasm_swap_8in16_MMX(void *dst, const void *src, uint32 count) { + __asm { + mov eax, [esp+4] + sub eax, 8 + js xtra +xloop: + movq mm0, [edx] + add edx, 8 + movq mm1, mm0 + psllw mm0, 8 + psrlw mm1, 8 + paddb mm0, mm1 + movq [ecx], mm0 + add ecx, 8 + sub eax, 8 + jns xloop +xtra: + add eax, 6 + js nopairs + push ebx +pairloop: + mov bl, [edx] + mov bh, [edx+1] + add edx, 2 + mov [ecx], bh + mov [ecx+1], bl + add ecx, 2 + sub eax, 2 + jns pairloop + pop ebx +nopairs: + add eax, 2 + jz noodd + mov al, [edx] + mov [ecx], al +noodd: + ret 4 + } +} + +void __declspec(naked) __fastcall vdasm_interleave_BGRG_MMX(void *dst, const void *srcR, const void *srcG, const void *srcB, uint32 count) { + __asm { + push edi + push esi + push ebx + mov esi, [esp+12+12] + mov edi, [esp+8+12] + mov ebx, [esp+4+12] + sub esi, 4 + jc xtra + ; ecx = dst + ; edx = srcR + ; ebx = srcG + ; edi = srcB +xloop: + movd mm0, [edi] + movd mm1, [edx] + punpcklbw mm0, mm1 + movq mm1, [ebx] + movq mm2, mm0 + punpcklbw mm0, mm1 + add edx, 4 + punpckhbw mm2, mm1 + add edi, 4 + movq [ecx], mm0 + add ebx, 8 + movq [ecx+8], mm2 + add ecx, 16 + sub esi, 4 + jns xloop +xtra: + add esi, 4 + jz fin +xtraloop: + mov al, [edi] + mov [ecx], al + mov al, [ebx] + mov [ecx+1], al + mov al, [edx] + mov [ecx+2], al + mov al, [ebx+1] + mov [ecx+3], al + add ebx, 2 + add edx, 1 + add edi, 1 + add ecx, 4 + sub esi, 1 + jnz xtraloop +fin: + pop ebx + pop esi + pop edi + ret 12 + } +} + +void __declspec(naked) __fastcall vdasm_interleave_GBGR_MMX(void *dst, const void *srcR, const void *srcG, const void *srcB, uint32 count) { + __asm { + push edi + push esi + push ebx + mov esi, [esp+12+12] + mov edi, [esp+8+12] + mov ebx, [esp+4+12] + sub esi, 4 + jc xtra + ; ecx = dst + ; edx = srcR + ; ebx = srcG + ; edi = srcB +xloop: + movd mm0, [edi] + movd mm1, [edx] + punpcklbw mm0, mm1 + movq mm2, [ebx] + movq mm1, mm2 + punpcklbw mm2, mm0 + add edx, 4 + punpckhbw mm1, mm0 + add edi, 4 + movq [ecx], mm2 + add ebx, 8 + movq [ecx+8], mm1 + add ecx, 16 + sub esi, 4 + jns xloop +xtra: + add esi, 4 + jz fin +xtraloop: + mov al, [ebx] + mov [ecx], al + mov al, [edi] + mov [ecx+1], al + mov al, [ebx+1] + mov [ecx+2], al + mov al, [edx] + mov [ecx+3], al + add ebx, 2 + add edx, 1 + add edi, 1 + add ecx, 4 + sub esi, 1 + jnz xtraloop +fin: + pop ebx + pop esi + pop edi + ret 12 + } +} + +void __declspec(naked) __fastcall vdasm_interleave_BR_MMX(void *dst, const void *srcB, const void *srcR, uint32 count) { + __asm { + push edi + push esi + push ebx + mov esi, [esp+8+12] + mov ebx, [esp+4+12] + sub esi, 8 + jc xtra + ; ecx = dst + ; edx = srcB + ; ebx = srcG +xloop: + movq mm0, [edx] + movq mm1, [ebx] + movq mm2, mm0 + punpcklbw mm0, mm1 + punpckhbw mm2, mm1 + add edx, 8 + movq [ecx], mm0 + add ebx, 8 + movq [ecx+8], mm2 + add ecx, 16 + sub esi, 8 + jns xloop +xtra: + add esi, 8 + jz fin +xtraloop: + mov al, [edx] + mov [ecx], al + mov al, [ebx] + mov [ecx+1], al + add ebx, 1 + add edx, 1 + add ecx, 2 + sub esi, 1 + jnz xtraloop +fin: + pop ebx + pop esi + pop edi + ret 8 + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_8In16_Even_MMX::Compute(void *dst, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_extract_8in16_even_MMX(dst, srcp, mWidth); +} + +void VDPixmapGen_8In16_Odd_MMX::Compute(void *dst, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_extract_8in16_odd_MMX(dst, srcp, mWidth); +} + +void VDPixmapGen_8In32_MMX::Compute(void *dst, sint32 y) { + const uint8 *srcp = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_extract_8in32_MMX(dst, srcp, mWidth, mOffset); +} + +void VDPixmapGen_Swap8In16_MMX::Compute(void *dst, sint32 y) { + const uint8 *src = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + vdasm_swap_8in16_MMX(dst, src, mRowLength); +} + +void VDPixmapGen_B8x2_To_B8R8_MMX::Compute(void *dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; + const uint8 *VDRESTRICT srcCb = (const uint8 *VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); + + vdasm_interleave_BR_MMX(dst, srcCb, srcCr, mWidth); +} + +void VDPixmapGen_B8x3_To_G8B8_G8R8_MMX::Compute(void *VDRESTRICT dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; + const uint8 *VDRESTRICT srcY = (const uint8 *VDRESTRICT)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *VDRESTRICT srcCb = (const uint8 *VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 *VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); + + vdasm_interleave_GBGR_MMX(dst, srcCr, srcY, srcCb, mWidth >> 1); + + if (mWidth & 1) { + int w2 = mWidth >> 1; + srcY += mWidth; + srcCb += w2; + srcCr += w2; + dst += mWidth * 2; + + dst[-2] = srcY[-1]; + dst[-1] = srcCb[0]; + dst[ 0] = 0; // must be zero for QuickTime compatibility + dst[ 1] = srcCr[0]; + } +} + +void VDPixmapGen_B8x3_To_B8G8_R8G8_MMX::Compute(void *VDRESTRICT dst0, sint32 y) { + uint8 *VDRESTRICT dst = (uint8 *VDRESTRICT)dst0; + const uint8 *VDRESTRICT srcY = (const uint8 * VDRESTRICT)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *VDRESTRICT srcCb = (const uint8 * VDRESTRICT)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *VDRESTRICT srcCr = (const uint8 * VDRESTRICT)mpSrcCr->GetRow(y, mSrcIndexCr); + + vdasm_interleave_BGRG_MMX(dst, srcCr, srcY, srcCb, mWidth >> 1); + + if (mWidth & 1) { + int w2 = mWidth >> 1; + srcY += mWidth; + srcCb += w2; + srcCr += w2; + dst += mWidth * 2; + + dst[-2] = srcCb[0]; + dst[-1] = srcY[-1]; + dst[ 0] = srcCr[0]; + dst[ 1] = 0; // must be zero for QuickTime compatibility + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_v210.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_v210.cpp index 073bd1af0d9..1e558aabd77 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_v210.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_v210.cpp @@ -1,218 +1,218 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include -#include "uberblit_v210.h" - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_32F_To_V210::Compute(void *dst0, sint32 y) { - uint32 *dst = (uint32 *)dst0; - const float *srcR = (const float *)mpSrcR->GetRow(y, mSrcIndexR); - const float *srcG = (const float *)mpSrcG->GetRow(y, mSrcIndexG); - const float *srcB = (const float *)mpSrcB->GetRow(y, mSrcIndexB); - - VDCPUCleanupExtensions(); - - int w6 = mWidth / 6; - for(sint32 i=0; i 1.0f) r0 = 1.0f; - if (r1 < 0.0f) r1 = 0.0f; else if (r1 > 1.0f) r1 = 1.0f; - if (r2 < 0.0f) r2 = 0.0f; else if (r2 > 1.0f) r2 = 1.0f; - if (g0 < 0.0f) g0 = 0.0f; else if (g0 > 1.0f) g0 = 1.0f; - if (g1 < 0.0f) g1 = 0.0f; else if (g1 > 1.0f) g1 = 1.0f; - if (g2 < 0.0f) g2 = 0.0f; else if (g2 > 1.0f) g2 = 1.0f; - if (g3 < 0.0f) g3 = 0.0f; else if (g3 > 1.0f) g3 = 1.0f; - if (g4 < 0.0f) g4 = 0.0f; else if (g4 > 1.0f) g4 = 1.0f; - if (g5 < 0.0f) g5 = 0.0f; else if (g5 > 1.0f) g5 = 1.0f; - if (b0 < 0.0f) b0 = 0.0f; else if (b0 > 1.0f) b0 = 1.0f; - if (b1 < 0.0f) b1 = 0.0f; else if (b1 > 1.0f) b1 = 1.0f; - if (b2 < 0.0f) b2 = 0.0f; else if (b2 > 1.0f) b2 = 1.0f; - - uint32 ir0 = (uint32)VDRoundToIntFast(r0 * 1024.0f); - uint32 ir1 = (uint32)VDRoundToIntFast(r1 * 1024.0f); - uint32 ir2 = (uint32)VDRoundToIntFast(r2 * 1024.0f); - uint32 ib0 = (uint32)VDRoundToIntFast(b0 * 1024.0f); - uint32 ib1 = (uint32)VDRoundToIntFast(b1 * 1024.0f); - uint32 ib2 = (uint32)VDRoundToIntFast(b2 * 1024.0f); - uint32 ig0 = (uint32)VDRoundToIntFast(g0 * 1024.0f); - uint32 ig1 = (uint32)VDRoundToIntFast(g1 * 1024.0f); - uint32 ig2 = (uint32)VDRoundToIntFast(g2 * 1024.0f); - uint32 ig3 = (uint32)VDRoundToIntFast(g3 * 1024.0f); - uint32 ig4 = (uint32)VDRoundToIntFast(g4 * 1024.0f); - uint32 ig5 = (uint32)VDRoundToIntFast(g5 * 1024.0f); - - // dword 0: XX Cr0 Y0 Cb0 - // dword 1: XX Y2 Cb1 Y1 - // dword 2: XX Cb2 Y3 Cr1 - // dword 3: XX Y5 Cr2 Y4 - dst[0] = (ir0 << 20) + (ig0 << 10) + ib0; - dst[1] = (ig2 << 20) + (ib1 << 10) + ig1; - dst[2] = (ib2 << 20) + (ig3 << 10) + ir1; - dst[3] = (ig5 << 20) + (ir2 << 10) + ig4; - - dst += 4; - } - - int leftovers = mWidth - w6*6; - if (leftovers) { - float g0 = 0; - float g1 = 0; - float g2 = 0; - float g3 = 0; - float g4 = 0; - float r0 = 0; - float r1 = 0; - float r2 = 0; - float b0 = 0; - float b1 = 0; - float b2 = 0; - - switch(leftovers) { - case 5: r2 = srcR[2]; - b2 = srcB[2]; - g4 = srcG[4]; - case 4: g3 = srcG[3]; - case 3: r1 = srcR[1]; - b1 = srcB[1]; - g2 = srcG[2]; - case 2: g1 = srcG[1]; - case 1: r0 = srcR[0]; - b0 = srcB[0]; - g0 = srcG[0]; - } - - if (r0 < 0.0f) r0 = 0.0f; else if (r0 > 1.0f) r0 = 1.0f; - if (r1 < 0.0f) r1 = 0.0f; else if (r1 > 1.0f) r1 = 1.0f; - if (r2 < 0.0f) r2 = 0.0f; else if (r2 > 1.0f) r2 = 1.0f; - if (g0 < 0.0f) g0 = 0.0f; else if (g0 > 1.0f) g0 = 1.0f; - if (g1 < 0.0f) g1 = 0.0f; else if (g1 > 1.0f) g1 = 1.0f; - if (g2 < 0.0f) g2 = 0.0f; else if (g2 > 1.0f) g2 = 1.0f; - if (g3 < 0.0f) g3 = 0.0f; else if (g3 > 1.0f) g3 = 1.0f; - if (g4 < 0.0f) g4 = 0.0f; else if (g4 > 1.0f) g4 = 1.0f; - if (b0 < 0.0f) b0 = 0.0f; else if (b0 > 1.0f) b0 = 1.0f; - if (b1 < 0.0f) b1 = 0.0f; else if (b1 > 1.0f) b1 = 1.0f; - if (b2 < 0.0f) b2 = 0.0f; else if (b2 > 1.0f) b2 = 1.0f; - - uint32 ir0 = (uint32)VDRoundToIntFast(r0 * 1024.0f); - uint32 ir1 = (uint32)VDRoundToIntFast(r1 * 1024.0f); - uint32 ir2 = (uint32)VDRoundToIntFast(r2 * 1024.0f); - uint32 ib0 = (uint32)VDRoundToIntFast(b0 * 1024.0f); - uint32 ib1 = (uint32)VDRoundToIntFast(b1 * 1024.0f); - uint32 ib2 = (uint32)VDRoundToIntFast(b2 * 1024.0f); - uint32 ig0 = (uint32)VDRoundToIntFast(g0 * 1024.0f); - uint32 ig1 = (uint32)VDRoundToIntFast(g1 * 1024.0f); - uint32 ig2 = (uint32)VDRoundToIntFast(g2 * 1024.0f); - uint32 ig3 = (uint32)VDRoundToIntFast(g3 * 1024.0f); - uint32 ig4 = (uint32)VDRoundToIntFast(g4 * 1024.0f); - - // dword 0: XX Cr0 Y0 Cb0 - // dword 1: XX Y2 Cb1 Y1 - // dword 2: XX Cb2 Y3 Cr1 - // dword 3: XX Y5 Cr2 Y4 - dst[0] = (ir0 << 20) + (ig0 << 10) + ib0; - dst[1] = (ig2 << 20) + (ib1 << 10) + ig1; - dst[2] = (ib2 << 20) + (ig3 << 10) + ir1; - dst[3] = (ir2 << 10) + ig4; - dst += 4; - } - - // QuickTime defines the v210 format and requires zero padding in all unused samples. - int w48up = (mWidth + 23) / 24; - int w6up = (mWidth + 5) / 6; - int zeropad = w48up * 16 - w6up * 4; - memset(dst, 0, zeropad * 4); -} - -/////////////////////////////////////////////////////////////////////////////// - -void VDPixmapGen_V210_To_32F::Start() { - StartWindow(((mWidth + 5) / 6) * 6 * sizeof(float), 3); -} - -const void *VDPixmapGen_V210_To_32F::GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; -} - -sint32 VDPixmapGen_V210_To_32F::GetWidth(int index) const { - return index == 1 ? mWidth : (mWidth + 1) >> 1; -} - -uint32 VDPixmapGen_V210_To_32F::GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; -} - -void VDPixmapGen_V210_To_32F::Compute(void *dst0, sint32 y) { - float *dstR = (float *)dst0; - float *dstG = (float *)((char *)dstR + mWindowPitch); - float *dstB = (float *)((char *)dstG + mWindowPitch); - const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); - uint32 w = (mWidth + 5) / 6; - - VDCPUCleanupExtensions(); - - // dword 0: XX Cr0 Y0 Cb0 - // dword 1: XX Y2 Cb1 Y1 - // dword 2: XX Cb2 Y3 Cr1 - // dword 3: XX Y5 Cr2 Y4 - - for(uint32 i=0; i> 10) & 0x3ff) / 1023.0f; - dstR[0] = (float)((w0 >> 20) & 0x3ff) / 1023.0f; - dstG[1] = (float)( w1 & 0x3ff) / 1023.0f; - dstB[1] = (float)((w1 >> 10) & 0x3ff) / 1023.0f; - dstG[2] = (float)((w1 >> 20) & 0x3ff) / 1023.0f; - dstR[1] = (float)( w2 & 0x3ff) / 1023.0f; - dstG[3] = (float)((w2 >> 10) & 0x3ff) / 1023.0f; - dstB[2] = (float)((w2 >> 20) & 0x3ff) / 1023.0f; - dstG[4] = (float)( w3 & 0x3ff) / 1023.0f; - dstR[2] = (float)((w3 >> 10) & 0x3ff) / 1023.0f; - dstG[5] = (float)((w3 >> 20) & 0x3ff) / 1023.0f; - - dstR += 3; - dstG += 6; - dstB += 3; - } -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include +#include +#include "uberblit_v210.h" + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_32F_To_V210::Compute(void *dst0, sint32 y) { + uint32 *dst = (uint32 *)dst0; + const float *srcR = (const float *)mpSrcR->GetRow(y, mSrcIndexR); + const float *srcG = (const float *)mpSrcG->GetRow(y, mSrcIndexG); + const float *srcB = (const float *)mpSrcB->GetRow(y, mSrcIndexB); + + VDCPUCleanupExtensions(); + + int w6 = mWidth / 6; + for(sint32 i=0; i 1.0f) r0 = 1.0f; + if (r1 < 0.0f) r1 = 0.0f; else if (r1 > 1.0f) r1 = 1.0f; + if (r2 < 0.0f) r2 = 0.0f; else if (r2 > 1.0f) r2 = 1.0f; + if (g0 < 0.0f) g0 = 0.0f; else if (g0 > 1.0f) g0 = 1.0f; + if (g1 < 0.0f) g1 = 0.0f; else if (g1 > 1.0f) g1 = 1.0f; + if (g2 < 0.0f) g2 = 0.0f; else if (g2 > 1.0f) g2 = 1.0f; + if (g3 < 0.0f) g3 = 0.0f; else if (g3 > 1.0f) g3 = 1.0f; + if (g4 < 0.0f) g4 = 0.0f; else if (g4 > 1.0f) g4 = 1.0f; + if (g5 < 0.0f) g5 = 0.0f; else if (g5 > 1.0f) g5 = 1.0f; + if (b0 < 0.0f) b0 = 0.0f; else if (b0 > 1.0f) b0 = 1.0f; + if (b1 < 0.0f) b1 = 0.0f; else if (b1 > 1.0f) b1 = 1.0f; + if (b2 < 0.0f) b2 = 0.0f; else if (b2 > 1.0f) b2 = 1.0f; + + uint32 ir0 = (uint32)VDRoundToIntFast(r0 * 1024.0f); + uint32 ir1 = (uint32)VDRoundToIntFast(r1 * 1024.0f); + uint32 ir2 = (uint32)VDRoundToIntFast(r2 * 1024.0f); + uint32 ib0 = (uint32)VDRoundToIntFast(b0 * 1024.0f); + uint32 ib1 = (uint32)VDRoundToIntFast(b1 * 1024.0f); + uint32 ib2 = (uint32)VDRoundToIntFast(b2 * 1024.0f); + uint32 ig0 = (uint32)VDRoundToIntFast(g0 * 1024.0f); + uint32 ig1 = (uint32)VDRoundToIntFast(g1 * 1024.0f); + uint32 ig2 = (uint32)VDRoundToIntFast(g2 * 1024.0f); + uint32 ig3 = (uint32)VDRoundToIntFast(g3 * 1024.0f); + uint32 ig4 = (uint32)VDRoundToIntFast(g4 * 1024.0f); + uint32 ig5 = (uint32)VDRoundToIntFast(g5 * 1024.0f); + + // dword 0: XX Cr0 Y0 Cb0 + // dword 1: XX Y2 Cb1 Y1 + // dword 2: XX Cb2 Y3 Cr1 + // dword 3: XX Y5 Cr2 Y4 + dst[0] = (ir0 << 20) + (ig0 << 10) + ib0; + dst[1] = (ig2 << 20) + (ib1 << 10) + ig1; + dst[2] = (ib2 << 20) + (ig3 << 10) + ir1; + dst[3] = (ig5 << 20) + (ir2 << 10) + ig4; + + dst += 4; + } + + int leftovers = mWidth - w6*6; + if (leftovers) { + float g0 = 0; + float g1 = 0; + float g2 = 0; + float g3 = 0; + float g4 = 0; + float r0 = 0; + float r1 = 0; + float r2 = 0; + float b0 = 0; + float b1 = 0; + float b2 = 0; + + switch(leftovers) { + case 5: r2 = srcR[2]; + b2 = srcB[2]; + g4 = srcG[4]; + case 4: g3 = srcG[3]; + case 3: r1 = srcR[1]; + b1 = srcB[1]; + g2 = srcG[2]; + case 2: g1 = srcG[1]; + case 1: r0 = srcR[0]; + b0 = srcB[0]; + g0 = srcG[0]; + } + + if (r0 < 0.0f) r0 = 0.0f; else if (r0 > 1.0f) r0 = 1.0f; + if (r1 < 0.0f) r1 = 0.0f; else if (r1 > 1.0f) r1 = 1.0f; + if (r2 < 0.0f) r2 = 0.0f; else if (r2 > 1.0f) r2 = 1.0f; + if (g0 < 0.0f) g0 = 0.0f; else if (g0 > 1.0f) g0 = 1.0f; + if (g1 < 0.0f) g1 = 0.0f; else if (g1 > 1.0f) g1 = 1.0f; + if (g2 < 0.0f) g2 = 0.0f; else if (g2 > 1.0f) g2 = 1.0f; + if (g3 < 0.0f) g3 = 0.0f; else if (g3 > 1.0f) g3 = 1.0f; + if (g4 < 0.0f) g4 = 0.0f; else if (g4 > 1.0f) g4 = 1.0f; + if (b0 < 0.0f) b0 = 0.0f; else if (b0 > 1.0f) b0 = 1.0f; + if (b1 < 0.0f) b1 = 0.0f; else if (b1 > 1.0f) b1 = 1.0f; + if (b2 < 0.0f) b2 = 0.0f; else if (b2 > 1.0f) b2 = 1.0f; + + uint32 ir0 = (uint32)VDRoundToIntFast(r0 * 1024.0f); + uint32 ir1 = (uint32)VDRoundToIntFast(r1 * 1024.0f); + uint32 ir2 = (uint32)VDRoundToIntFast(r2 * 1024.0f); + uint32 ib0 = (uint32)VDRoundToIntFast(b0 * 1024.0f); + uint32 ib1 = (uint32)VDRoundToIntFast(b1 * 1024.0f); + uint32 ib2 = (uint32)VDRoundToIntFast(b2 * 1024.0f); + uint32 ig0 = (uint32)VDRoundToIntFast(g0 * 1024.0f); + uint32 ig1 = (uint32)VDRoundToIntFast(g1 * 1024.0f); + uint32 ig2 = (uint32)VDRoundToIntFast(g2 * 1024.0f); + uint32 ig3 = (uint32)VDRoundToIntFast(g3 * 1024.0f); + uint32 ig4 = (uint32)VDRoundToIntFast(g4 * 1024.0f); + + // dword 0: XX Cr0 Y0 Cb0 + // dword 1: XX Y2 Cb1 Y1 + // dword 2: XX Cb2 Y3 Cr1 + // dword 3: XX Y5 Cr2 Y4 + dst[0] = (ir0 << 20) + (ig0 << 10) + ib0; + dst[1] = (ig2 << 20) + (ib1 << 10) + ig1; + dst[2] = (ib2 << 20) + (ig3 << 10) + ir1; + dst[3] = (ir2 << 10) + ig4; + dst += 4; + } + + // QuickTime defines the v210 format and requires zero padding in all unused samples. + int w48up = (mWidth + 23) / 24; + int w6up = (mWidth + 5) / 6; + int zeropad = w48up * 16 - w6up * 4; + memset(dst, 0, zeropad * 4); +} + +/////////////////////////////////////////////////////////////////////////////// + +void VDPixmapGen_V210_To_32F::Start() { + StartWindow(((mWidth + 5) / 6) * 6 * sizeof(float), 3); +} + +const void *VDPixmapGen_V210_To_32F::GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenWindowBasedOneSource::GetRow(y, index) + mWindowPitch * index; +} + +sint32 VDPixmapGen_V210_To_32F::GetWidth(int index) const { + return index == 1 ? mWidth : (mWidth + 1) >> 1; +} + +uint32 VDPixmapGen_V210_To_32F::GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~kVDPixType_Mask) | kVDPixType_32F_LE; +} + +void VDPixmapGen_V210_To_32F::Compute(void *dst0, sint32 y) { + float *dstR = (float *)dst0; + float *dstG = (float *)((char *)dstR + mWindowPitch); + float *dstB = (float *)((char *)dstG + mWindowPitch); + const uint32 *src = (const uint32 *)mpSrc->GetRow(y, mSrcIndex); + uint32 w = (mWidth + 5) / 6; + + VDCPUCleanupExtensions(); + + // dword 0: XX Cr0 Y0 Cb0 + // dword 1: XX Y2 Cb1 Y1 + // dword 2: XX Cb2 Y3 Cr1 + // dword 3: XX Y5 Cr2 Y4 + + for(uint32 i=0; i> 10) & 0x3ff) / 1023.0f; + dstR[0] = (float)((w0 >> 20) & 0x3ff) / 1023.0f; + dstG[1] = (float)( w1 & 0x3ff) / 1023.0f; + dstB[1] = (float)((w1 >> 10) & 0x3ff) / 1023.0f; + dstG[2] = (float)((w1 >> 20) & 0x3ff) / 1023.0f; + dstR[1] = (float)( w2 & 0x3ff) / 1023.0f; + dstG[3] = (float)((w2 >> 10) & 0x3ff) / 1023.0f; + dstB[2] = (float)((w2 >> 20) & 0x3ff) / 1023.0f; + dstG[4] = (float)( w3 & 0x3ff) / 1023.0f; + dstR[2] = (float)((w3 >> 10) & 0x3ff) / 1023.0f; + dstG[5] = (float)((w3 >> 20) & 0x3ff) / 1023.0f; + + dstR += 3; + dstG += 6; + dstB += 3; + } +} diff --git a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_ycbcr_generic.cpp b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_ycbcr_generic.cpp index b60a6452e36..3820c7254c0 100644 --- a/src/thirdparty/VirtualDub/Kasumi/source/uberblit_ycbcr_generic.cpp +++ b/src/thirdparty/VirtualDub/Kasumi/source/uberblit_ycbcr_generic.cpp @@ -1,545 +1,545 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include -#include -#include "uberblit_ycbcr_generic.h" - -extern const VDPixmapGenYCbCrBasis g_VDPixmapGenYCbCrBasis_601 = { - 0.299f, - 0.114f, - { - 0.0f, -0.3441363f, 1.772f, - 1.402f, -0.7141363f, 0.0f, - } -}; - -extern const VDPixmapGenYCbCrBasis g_VDPixmapGenYCbCrBasis_709 = { - 0.2126f, - 0.0722f, - { - 0.0f, -0.1873243f, 1.8556f, - 1.5748f, -0.4681243f, 0.0f, - } -}; - -//////////////////////////////////////////////////////////////////////////// - -VDPixmapGenYCbCrToRGB32Generic::VDPixmapGenYCbCrToRGB32Generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB) { - float scale; - float bias; - - if (studioRGB) { - scale = 65536.0f * (219.0f / 255.0f); - bias = 65536.0f * (16.0f / 255.0f + 0.5f); - } else { - scale = 65536.0f; - bias = 32768.0f; - } - - float scale255 = scale * 255.0f; - - mCoY = VDRoundToInt32(scale); - mCoRCr = VDRoundToInt32(basis.mToRGB[1][0] * scale); - mCoGCr = VDRoundToInt32(basis.mToRGB[1][1] * scale); - mCoGCb = VDRoundToInt32(basis.mToRGB[0][1] * scale); - mCoBCb = VDRoundToInt32(basis.mToRGB[0][2] * scale); - mBiasR = VDRoundToInt32(bias) - 128*mCoRCr; - mBiasG = VDRoundToInt32(bias) - 128*(mCoGCr + mCoGCb); - mBiasB = VDRoundToInt32(bias) - 128*mCoBCb; -} - -uint32 VDPixmapGenYCbCrToRGB32Generic::GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; -} - -void VDPixmapGenYCbCrToRGB32Generic::Compute(void *dst0, sint32 y) { - uint8 *dst = (uint8 *)dst0; - const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); - - const sint32 coY = mCoY; - const sint32 coRCr = mCoRCr; - const sint32 coGCr = mCoGCr; - const sint32 coGCb = mCoGCb; - const sint32 coBCb = mCoBCb; - const sint32 biasR = mBiasR; - const sint32 biasG = mBiasG; - const sint32 biasB = mBiasB; - - const sint32 w = mWidth; - for(sint32 i=0; i> 31; - g &= ~g >> 31; - b &= ~b >> 31; - - // clip high - sint32 clipR = 0xffffff - r; - sint32 clipG = 0xffffff - g; - sint32 clipB = 0xffffff - b; - r |= clipR >> 31; - g |= clipG >> 31; - b |= clipB >> 31; - - dst[0] = (uint8)(b >> 16); - dst[1] = (uint8)(g >> 16); - dst[2] = (uint8)(r >> 16); - dst[3] = 0xff; - - dst += 4; - } -} - -//////////////////////////////////////////////////////////////////////////// - -VDPixmapGenYCbCrToRGB32FGeneric::VDPixmapGenYCbCrToRGB32FGeneric(const VDPixmapGenYCbCrBasis& basis) { - mCoRCr = basis.mToRGB[1][0]; - mCoGCr = basis.mToRGB[1][1]; - mCoGCb = basis.mToRGB[0][1]; - mCoBCb = basis.mToRGB[0][2]; -} - -uint32 VDPixmapGenYCbCrToRGB32FGeneric::GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; -} - -void VDPixmapGenYCbCrToRGB32FGeneric::Compute(void *dst0, sint32 y) { - float *dst = (float *)dst0; - const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); - const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - const float coRCr = mCoRCr; - const float coGCr = mCoGCr; - const float coGCb = mCoGCb; - const float coBCb = mCoBCb; - - for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | mColorSpace; -} - -void VDPixmapGenRGB32ToYCbCrGeneric::Compute(void *dst0, sint32 y) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - const sint32 coYR = mCoYR; - const sint32 coYG = mCoYG; - const sint32 coYB = mCoYB; - const sint32 coCbR = mCoCbR; - const sint32 coCbG = mCoCbG; - const sint32 coCbB = mCoCbB; - const sint32 coCrR = mCoCrR; - const sint32 coCrG = mCoCrG; - const sint32 coCrB = mCoCrB; - const sint32 coYA = mCoYA; - const sint32 coCbA = mCoCbA; - const sint32 coCrA = mCoCrA; - - const sint32 w = mWidth; - for(sint32 i=0; i> 31; - cr16 |= (0xffffff - cr16) >> 31; - - *dstCb++ = (uint8)(cb16 >> 16); - *dstY ++ = (uint8)( y16 >> 16); - *dstCr++ = (uint8)(cr16 >> 16); - } -} - -//////////////////////////////////////////////////////////////////////////// - -VDPixmapGenRGB32FToYCbCrGeneric::VDPixmapGenRGB32FToYCbCrGeneric(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace) - : mColorSpace(colorSpace) -{ - mCoYR = basis.mKr; - mCoYG = 1.0f - basis.mKr - basis.mKb; - mCoYB = basis.mKb; - - // Cb = 0.5 * (B-Y) / (1-Kb) - mCoCb = 0.5f / (1.0f - basis.mKb); - - // Cr = 0.5 * (R-Y) / (1-Kr) - mCoCr = 0.5f / (1.0f - basis.mKr); -} - -uint32 VDPixmapGenRGB32FToYCbCrGeneric::GetType(uint32 output) const { - return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | mColorSpace; -} - -void VDPixmapGenRGB32FToYCbCrGeneric::Compute(void *dst0, sint32 y) { - float *dstCr = (float *)dst0; - float *dstY = dstCr + mWindowPitch; - float *dstCb = dstY + mWindowPitch; - - const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); - - VDCPUCleanupExtensions(); - - const float coYR = mCoYR; - const float coYG = mCoYG; - const float coYB = mCoYB; - const float coCb = mCoCb; - const float coCr = mCoCr; - - const sint32 w = mWidth; - for(sint32 i=0; iStart(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth, 3); -} - -const void *VDPixmapGenYCbCrToYCbCrGeneric::GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; -} - -uint32 VDPixmapGenYCbCrToYCbCrGeneric::GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixSpace_Mask) | mColorSpace; -} - -void VDPixmapGenYCbCrToYCbCrGeneric::Compute(void *dst0, sint32 ypos) { - uint8 *dstCr = (uint8 *)dst0; - uint8 *dstY = dstCr + mWindowPitch; - uint8 *dstCb = dstY + mWindowPitch; - - const uint8 *srcY = (const uint8 *)mpSrcY ->GetRow(ypos, mSrcIndexY ); - const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - const sint32 coYY = mCoYY; - const sint32 coYCb = mCoYCb; - const sint32 coYCr = mCoYCr; - const sint32 coYA = mCoYA; - const sint32 coCbCb = mCoCbCb; - const sint32 coCbCr = mCoCbCr; - const sint32 coCbA = mCoCbA; - const sint32 coCrCb = mCoCrCb; - const sint32 coCrCr = mCoCrCr; - const sint32 coCrA = mCoCrA; - - for(sint32 i=0; i> 31; - cb2 &= ~cb2 >> 31; - cr2 &= ~cr2 >> 31; - - y2 |= (0xffffff - y2) >> 31; - cb2 |= (0xffffff - cb2) >> 31; - cr2 |= (0xffffff - cr2) >> 31; - - *dstY++ = (uint8)(y2 >> 16); - *dstCb++ = (uint8)(cb2 >> 16); - *dstCr++ = (uint8)(cr2 >> 16); - } -} - -//////////////////////////////////////////////////////////////////////////// - -VDPixmapGenYCbCrToYCbCrGeneric_32F::VDPixmapGenYCbCrToYCbCrGeneric_32F(const VDPixmapGenYCbCrBasis& dstBasis, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& srcBasis, bool srcLimitedRange, uint32 colorSpace) - : mColorSpace(colorSpace) -{ - vdfloat3x3 dstToRGB; - dstToRGB.m[0] = vdfloat3c(1, 1, 1); - dstToRGB.m[1] = vdfloat3c(dstBasis.mToRGB[0]); - dstToRGB.m[2] = vdfloat3c(dstBasis.mToRGB[1]); - - if (dstLimitedRange) { - dstToRGB.m[0] *= (255.0f / 219.0f); - dstToRGB.m[1] *= (255.0f / 224.0f); - dstToRGB.m[2] *= (255.0f / 224.0f); - } - - vdfloat3x3 srcToRGB; - srcToRGB.m[0] = vdfloat3c(1, 1, 1); - srcToRGB.m[1] = vdfloat3c(srcBasis.mToRGB[0]); - srcToRGB.m[2] = vdfloat3c(srcBasis.mToRGB[1]); - - if (srcLimitedRange) { - srcToRGB.m[0] *= (255.0f / 219.0f); - srcToRGB.m[1] *= (255.0f / 224.0f); - srcToRGB.m[2] *= (255.0f / 224.0f); - } - - vdfloat3x3 xf(srcToRGB * ~dstToRGB); - - // We should get a transform that looks like this: - // - // |k 0 0| - // [y cb cr 1] |a c e| = [y' cb' cr] - // |b d f| - // |x y z| - - VDASSERT(fabsf(xf.m[0].v[1]) < 1e-5f); - VDASSERT(fabsf(xf.m[0].v[2]) < 1e-5f); - - mCoYY = xf.m[0].v[0]; - mCoYCb = xf.m[1].v[0]; - mCoYCr = xf.m[2].v[0]; - mCoCbCb = xf.m[1].v[1]; - mCoCbCr = xf.m[2].v[1]; - mCoCrCb = xf.m[1].v[2]; - mCoCrCr = xf.m[2].v[2]; - - vdfloat3c srcBias(0, 128.0f/255.0f, 128.0f/255.0f); - if (srcLimitedRange) - srcBias.set(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f); - - vdfloat3c dstBias(0, 128.0f/255.0f, 128.0f/255.0f); - if (dstLimitedRange) - dstBias.set(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f); - - vdfloat3 bias = -srcBias * xf + dstBias; - - mCoYA = bias.x; - mCoCbA = bias.y; - mCoCrA = bias.z; -} - -void VDPixmapGenYCbCrToYCbCrGeneric_32F::Start() { - mpSrcY->Start(); - mpSrcCb->Start(); - mpSrcCr->Start(); - - StartWindow(mWidth * sizeof(float), 3); -} - -const void *VDPixmapGenYCbCrToYCbCrGeneric_32F::GetRow(sint32 y, uint32 index) { - return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; -} - -uint32 VDPixmapGenYCbCrToYCbCrGeneric_32F::GetType(uint32 output) const { - return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixSpace_Mask) | mColorSpace; -} - -void VDPixmapGenYCbCrToYCbCrGeneric_32F::Compute(void *dst0, sint32 ypos) { - float *dstCr = (float *)dst0; - float *dstY = vdptroffset(dstCr, mWindowPitch); - float *dstCb = vdptroffset(dstY, mWindowPitch); - - const float *srcY = (const float *)mpSrcY ->GetRow(ypos, mSrcIndexY ); - const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); - const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); - - VDCPUCleanupExtensions(); - - const float coYY = mCoYY; - const float coYCb = mCoYCb; - const float coYCr = mCoYCr; - const float coYA = mCoYA; - const float coCbCb = mCoCbCb; - const float coCbCr = mCoCbCr; - const float coCbA = mCoCbA; - const float coCrCb = mCoCrCb; - const float coCrCr = mCoCrCr; - const float coCrA = mCoCrA; - - for(sint32 i=0; i +#include +#include "uberblit_ycbcr_generic.h" + +extern const VDPixmapGenYCbCrBasis g_VDPixmapGenYCbCrBasis_601 = { + 0.299f, + 0.114f, + { + 0.0f, -0.3441363f, 1.772f, + 1.402f, -0.7141363f, 0.0f, + } +}; + +extern const VDPixmapGenYCbCrBasis g_VDPixmapGenYCbCrBasis_709 = { + 0.2126f, + 0.0722f, + { + 0.0f, -0.1873243f, 1.8556f, + 1.5748f, -0.4681243f, 0.0f, + } +}; + +//////////////////////////////////////////////////////////////////////////// + +VDPixmapGenYCbCrToRGB32Generic::VDPixmapGenYCbCrToRGB32Generic(const VDPixmapGenYCbCrBasis& basis, bool studioRGB) { + float scale; + float bias; + + if (studioRGB) { + scale = 65536.0f * (219.0f / 255.0f); + bias = 65536.0f * (16.0f / 255.0f + 0.5f); + } else { + scale = 65536.0f; + bias = 32768.0f; + } + + float scale255 = scale * 255.0f; + + mCoY = VDRoundToInt32(scale); + mCoRCr = VDRoundToInt32(basis.mToRGB[1][0] * scale); + mCoGCr = VDRoundToInt32(basis.mToRGB[1][1] * scale); + mCoGCb = VDRoundToInt32(basis.mToRGB[0][1] * scale); + mCoBCb = VDRoundToInt32(basis.mToRGB[0][2] * scale); + mBiasR = VDRoundToInt32(bias) - 128*mCoRCr; + mBiasG = VDRoundToInt32(bias) - 128*(mCoGCr + mCoGCb); + mBiasB = VDRoundToInt32(bias) - 128*mCoBCb; +} + +uint32 VDPixmapGenYCbCrToRGB32Generic::GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8888 | kVDPixSpace_BGR; +} + +void VDPixmapGenYCbCrToRGB32Generic::Compute(void *dst0, sint32 y) { + uint8 *dst = (uint8 *)dst0; + const uint8 *srcY = (const uint8 *)mpSrcY->GetRow(y, mSrcIndexY); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(y, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(y, mSrcIndexCr); + + const sint32 coY = mCoY; + const sint32 coRCr = mCoRCr; + const sint32 coGCr = mCoGCr; + const sint32 coGCb = mCoGCb; + const sint32 coBCb = mCoBCb; + const sint32 biasR = mBiasR; + const sint32 biasG = mBiasG; + const sint32 biasB = mBiasB; + + const sint32 w = mWidth; + for(sint32 i=0; i> 31; + g &= ~g >> 31; + b &= ~b >> 31; + + // clip high + sint32 clipR = 0xffffff - r; + sint32 clipG = 0xffffff - g; + sint32 clipB = 0xffffff - b; + r |= clipR >> 31; + g |= clipG >> 31; + b |= clipB >> 31; + + dst[0] = (uint8)(b >> 16); + dst[1] = (uint8)(g >> 16); + dst[2] = (uint8)(r >> 16); + dst[3] = 0xff; + + dst += 4; + } +} + +//////////////////////////////////////////////////////////////////////////// + +VDPixmapGenYCbCrToRGB32FGeneric::VDPixmapGenYCbCrToRGB32FGeneric(const VDPixmapGenYCbCrBasis& basis) { + mCoRCr = basis.mToRGB[1][0]; + mCoGCr = basis.mToRGB[1][1]; + mCoGCb = basis.mToRGB[0][1]; + mCoBCb = basis.mToRGB[0][2]; +} + +uint32 VDPixmapGenYCbCrToRGB32FGeneric::GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32Fx4_LE | kVDPixSpace_BGR; +} + +void VDPixmapGenYCbCrToRGB32FGeneric::Compute(void *dst0, sint32 y) { + float *dst = (float *)dst0; + const float *srcY = (const float *)mpSrcY->GetRow(y, mSrcIndexY); + const float *srcCb = (const float *)mpSrcCb->GetRow(y, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(y, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + const float coRCr = mCoRCr; + const float coGCr = mCoGCr; + const float coGCb = mCoGCb; + const float coBCb = mCoBCb; + + for(sint32 i=0; iGetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_8 | mColorSpace; +} + +void VDPixmapGenRGB32ToYCbCrGeneric::Compute(void *dst0, sint32 y) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + const sint32 coYR = mCoYR; + const sint32 coYG = mCoYG; + const sint32 coYB = mCoYB; + const sint32 coCbR = mCoCbR; + const sint32 coCbG = mCoCbG; + const sint32 coCbB = mCoCbB; + const sint32 coCrR = mCoCrR; + const sint32 coCrG = mCoCrG; + const sint32 coCrB = mCoCrB; + const sint32 coYA = mCoYA; + const sint32 coCbA = mCoCbA; + const sint32 coCrA = mCoCrA; + + const sint32 w = mWidth; + for(sint32 i=0; i> 31; + cr16 |= (0xffffff - cr16) >> 31; + + *dstCb++ = (uint8)(cb16 >> 16); + *dstY ++ = (uint8)( y16 >> 16); + *dstCr++ = (uint8)(cr16 >> 16); + } +} + +//////////////////////////////////////////////////////////////////////////// + +VDPixmapGenRGB32FToYCbCrGeneric::VDPixmapGenRGB32FToYCbCrGeneric(const VDPixmapGenYCbCrBasis& basis, uint32 colorSpace) + : mColorSpace(colorSpace) +{ + mCoYR = basis.mKr; + mCoYG = 1.0f - basis.mKr - basis.mKb; + mCoYB = basis.mKb; + + // Cb = 0.5 * (B-Y) / (1-Kb) + mCoCb = 0.5f / (1.0f - basis.mKb); + + // Cr = 0.5 * (R-Y) / (1-Kr) + mCoCr = 0.5f / (1.0f - basis.mKr); +} + +uint32 VDPixmapGenRGB32FToYCbCrGeneric::GetType(uint32 output) const { + return (mpSrc->GetType(mSrcIndex) & ~(kVDPixType_Mask | kVDPixSpace_Mask)) | kVDPixType_32F_LE | mColorSpace; +} + +void VDPixmapGenRGB32FToYCbCrGeneric::Compute(void *dst0, sint32 y) { + float *dstCr = (float *)dst0; + float *dstY = dstCr + mWindowPitch; + float *dstCb = dstY + mWindowPitch; + + const float *srcRGB = (const float *)mpSrc->GetRow(y, mSrcIndex); + + VDCPUCleanupExtensions(); + + const float coYR = mCoYR; + const float coYG = mCoYG; + const float coYB = mCoYB; + const float coCb = mCoCb; + const float coCr = mCoCr; + + const sint32 w = mWidth; + for(sint32 i=0; iStart(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth, 3); +} + +const void *VDPixmapGenYCbCrToYCbCrGeneric::GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; +} + +uint32 VDPixmapGenYCbCrToYCbCrGeneric::GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixSpace_Mask) | mColorSpace; +} + +void VDPixmapGenYCbCrToYCbCrGeneric::Compute(void *dst0, sint32 ypos) { + uint8 *dstCr = (uint8 *)dst0; + uint8 *dstY = dstCr + mWindowPitch; + uint8 *dstCb = dstY + mWindowPitch; + + const uint8 *srcY = (const uint8 *)mpSrcY ->GetRow(ypos, mSrcIndexY ); + const uint8 *srcCb = (const uint8 *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const uint8 *srcCr = (const uint8 *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + const sint32 coYY = mCoYY; + const sint32 coYCb = mCoYCb; + const sint32 coYCr = mCoYCr; + const sint32 coYA = mCoYA; + const sint32 coCbCb = mCoCbCb; + const sint32 coCbCr = mCoCbCr; + const sint32 coCbA = mCoCbA; + const sint32 coCrCb = mCoCrCb; + const sint32 coCrCr = mCoCrCr; + const sint32 coCrA = mCoCrA; + + for(sint32 i=0; i> 31; + cb2 &= ~cb2 >> 31; + cr2 &= ~cr2 >> 31; + + y2 |= (0xffffff - y2) >> 31; + cb2 |= (0xffffff - cb2) >> 31; + cr2 |= (0xffffff - cr2) >> 31; + + *dstY++ = (uint8)(y2 >> 16); + *dstCb++ = (uint8)(cb2 >> 16); + *dstCr++ = (uint8)(cr2 >> 16); + } +} + +//////////////////////////////////////////////////////////////////////////// + +VDPixmapGenYCbCrToYCbCrGeneric_32F::VDPixmapGenYCbCrToYCbCrGeneric_32F(const VDPixmapGenYCbCrBasis& dstBasis, bool dstLimitedRange, const VDPixmapGenYCbCrBasis& srcBasis, bool srcLimitedRange, uint32 colorSpace) + : mColorSpace(colorSpace) +{ + vdfloat3x3 dstToRGB; + dstToRGB.m[0] = vdfloat3c(1, 1, 1); + dstToRGB.m[1] = vdfloat3c(dstBasis.mToRGB[0]); + dstToRGB.m[2] = vdfloat3c(dstBasis.mToRGB[1]); + + if (dstLimitedRange) { + dstToRGB.m[0] *= (255.0f / 219.0f); + dstToRGB.m[1] *= (255.0f / 224.0f); + dstToRGB.m[2] *= (255.0f / 224.0f); + } + + vdfloat3x3 srcToRGB; + srcToRGB.m[0] = vdfloat3c(1, 1, 1); + srcToRGB.m[1] = vdfloat3c(srcBasis.mToRGB[0]); + srcToRGB.m[2] = vdfloat3c(srcBasis.mToRGB[1]); + + if (srcLimitedRange) { + srcToRGB.m[0] *= (255.0f / 219.0f); + srcToRGB.m[1] *= (255.0f / 224.0f); + srcToRGB.m[2] *= (255.0f / 224.0f); + } + + vdfloat3x3 xf(srcToRGB * ~dstToRGB); + + // We should get a transform that looks like this: + // + // |k 0 0| + // [y cb cr 1] |a c e| = [y' cb' cr] + // |b d f| + // |x y z| + + VDASSERT(fabsf(xf.m[0].v[1]) < 1e-5f); + VDASSERT(fabsf(xf.m[0].v[2]) < 1e-5f); + + mCoYY = xf.m[0].v[0]; + mCoYCb = xf.m[1].v[0]; + mCoYCr = xf.m[2].v[0]; + mCoCbCb = xf.m[1].v[1]; + mCoCbCr = xf.m[2].v[1]; + mCoCrCb = xf.m[1].v[2]; + mCoCrCr = xf.m[2].v[2]; + + vdfloat3c srcBias(0, 128.0f/255.0f, 128.0f/255.0f); + if (srcLimitedRange) + srcBias.set(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f); + + vdfloat3c dstBias(0, 128.0f/255.0f, 128.0f/255.0f); + if (dstLimitedRange) + dstBias.set(16.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f); + + vdfloat3 bias = -srcBias * xf + dstBias; + + mCoYA = bias.x; + mCoCbA = bias.y; + mCoCrA = bias.z; +} + +void VDPixmapGenYCbCrToYCbCrGeneric_32F::Start() { + mpSrcY->Start(); + mpSrcCb->Start(); + mpSrcCr->Start(); + + StartWindow(mWidth * sizeof(float), 3); +} + +const void *VDPixmapGenYCbCrToYCbCrGeneric_32F::GetRow(sint32 y, uint32 index) { + return (const uint8 *)VDPixmapGenYCbCrToRGBBase::GetRow(y, index) + mWindowPitch * index; +} + +uint32 VDPixmapGenYCbCrToYCbCrGeneric_32F::GetType(uint32 output) const { + return (mpSrcY->GetType(mSrcIndexY) & ~kVDPixSpace_Mask) | mColorSpace; +} + +void VDPixmapGenYCbCrToYCbCrGeneric_32F::Compute(void *dst0, sint32 ypos) { + float *dstCr = (float *)dst0; + float *dstY = vdptroffset(dstCr, mWindowPitch); + float *dstCb = vdptroffset(dstY, mWindowPitch); + + const float *srcY = (const float *)mpSrcY ->GetRow(ypos, mSrcIndexY ); + const float *srcCb = (const float *)mpSrcCb->GetRow(ypos, mSrcIndexCb); + const float *srcCr = (const float *)mpSrcCr->GetRow(ypos, mSrcIndexCr); + + VDCPUCleanupExtensions(); + + const float coYY = mCoYY; + const float coYCb = mCoYCb; + const float coYCr = mCoYCr; + const float coYA = mCoYA; + const float coCbCb = mCoCbCb; + const float coCbCr = mCoCbCr; + const float coCbA = mCoCbA; + const float coCrCb = mCoCrCb; + const float coCrCr = mCoCrCr; + const float coCrA = mCoCrA; + + for(sint32 i=0; i -#include "uberblit_ycbcr_x86.h" - -extern "C" void vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2(void *dstY, void *dstCb, void *dstCr, const void *srcRGB, uint32 count, const void *coeffs); - -void VDPixmapGenRGB32ToYCbCr601_SSE2::Compute(void *dst0, sint32 y) { - uint8 *dstCb = (uint8 *)dst0; - uint8 *dstY = dstCb + mWindowPitch; - uint8 *dstCr = dstY + mWindowPitch; - const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); - - static const __declspec(align(16)) struct { - sint16 rb_to_y[8]; - sint16 rb_to_cb[8]; - sint16 rb_to_cr[8]; - sint16 g_to_y[8]; - sint16 g_to_cb[8]; - sint16 g_to_cr[8]; - sint32 y_bias[4]; - sint32 c_bias[4]; - } kCoeffs={ - // Cb = (28784*r - 24103*g - 4681*b + 8388608 + 32768) >> 16; - // Y = (16829*r + 33039*g + 6416*b + 1048576 + 32768) >> 16; - // Cr = (-9714*r - 19071*g + 28784*b + 8388608 + 32768) >> 16; - { 3208, 8414, 3208, 8414, 3208, 8414, 3208, 8414, }, // rb to y - { -2340, 14392, -2340, 14392, -2340, 14392, -2340, 14392, }, // rb to cb - { 16519, 0, 16519, 0, 16519, 0, 16519, 0, }, // g to y - { -12050, 0, -12050, 0, -12050, 0, -12050, 0, }, // g to cb - { 14392, -4857, 14392, -4857, 14392, -4857, 14392, -4857, }, // rb to cr - { -9535, 0, -9535, 0, -9535, 0, -9535, 0, }, // g to cr - { 0x084000, 0x084000, 0x084000, 0x084000, }, // y bias - { 0x404000, 0x404000, 0x404000, 0x404000, }, // c bias - }; - - vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2(dstY, dstCb, dstCr, srcRGB, mWidth, &kCoeffs); -} +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#include +#include "uberblit_ycbcr_x86.h" + +extern "C" void vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2(void *dstY, void *dstCb, void *dstCr, const void *srcRGB, uint32 count, const void *coeffs); + +void VDPixmapGenRGB32ToYCbCr601_SSE2::Compute(void *dst0, sint32 y) { + uint8 *dstCb = (uint8 *)dst0; + uint8 *dstY = dstCb + mWindowPitch; + uint8 *dstCr = dstY + mWindowPitch; + const uint8 *srcRGB = (const uint8 *)mpSrc->GetRow(y, mSrcIndex); + + static const __declspec(align(16)) struct { + sint16 rb_to_y[8]; + sint16 rb_to_cb[8]; + sint16 rb_to_cr[8]; + sint16 g_to_y[8]; + sint16 g_to_cb[8]; + sint16 g_to_cr[8]; + sint32 y_bias[4]; + sint32 c_bias[4]; + } kCoeffs={ + // Cb = (28784*r - 24103*g - 4681*b + 8388608 + 32768) >> 16; + // Y = (16829*r + 33039*g + 6416*b + 1048576 + 32768) >> 16; + // Cr = (-9714*r - 19071*g + 28784*b + 8388608 + 32768) >> 16; + { 3208, 8414, 3208, 8414, 3208, 8414, 3208, 8414, }, // rb to y + { -2340, 14392, -2340, 14392, -2340, 14392, -2340, 14392, }, // rb to cb + { 16519, 0, 16519, 0, 16519, 0, 16519, 0, }, // g to y + { -12050, 0, -12050, 0, -12050, 0, -12050, 0, }, // g to cb + { 14392, -4857, 14392, -4857, 14392, -4857, 14392, -4857, }, // rb to cr + { -9535, 0, -9535, 0, -9535, 0, -9535, 0, }, // g to cr + { 0x084000, 0x084000, 0x084000, 0x084000, }, // y bias + { 0x404000, 0x404000, 0x404000, 0x404000, }, // c bias + }; + + vdasm_pixblt_XRGB8888_to_YUV444Planar_scan_SSE2(dstY, dstCb, dstCr, srcRGB, mWidth, &kCoeffs); +} diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/blitter.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/blitter.h index 4ced35dc449..d930f0d6432 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/blitter.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/blitter.h @@ -1,39 +1,39 @@ -#ifndef f_VD2_KASUMI_BLITTER_H -#define f_VD2_KASUMI_BLITTER_H - -#include - -struct VDPixmap; -struct VDPixmapLayout; - -class IVDPixmapBlitter { -public: - virtual ~IVDPixmapBlitter() {} - virtual void Blit(const VDPixmap& dst, const VDPixmap& src) = 0; - virtual void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) = 0; -}; - -IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmap& dst, const VDPixmap& src); -IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmapLayout& dst, const VDPixmapLayout& src); - -class VDPixmapCachedBlitter { - VDPixmapCachedBlitter(const VDPixmapCachedBlitter&); - VDPixmapCachedBlitter& operator=(const VDPixmapCachedBlitter&); -public: - VDPixmapCachedBlitter(); - ~VDPixmapCachedBlitter(); - - void Blit(const VDPixmap& dst, const VDPixmap& src); - void Invalidate(); - -protected: - sint32 mSrcWidth; - sint32 mSrcHeight; - int mSrcFormat; - sint32 mDstWidth; - sint32 mDstHeight; - int mDstFormat; - IVDPixmapBlitter *mpCachedBlitter; -}; - -#endif +#ifndef f_VD2_KASUMI_BLITTER_H +#define f_VD2_KASUMI_BLITTER_H + +#include + +struct VDPixmap; +struct VDPixmapLayout; + +class IVDPixmapBlitter { +public: + virtual ~IVDPixmapBlitter() {} + virtual void Blit(const VDPixmap& dst, const VDPixmap& src) = 0; + virtual void Blit(const VDPixmap& dst, const vdrect32 *rDst, const VDPixmap& src) = 0; +}; + +IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmap& dst, const VDPixmap& src); +IVDPixmapBlitter *VDPixmapCreateBlitter(const VDPixmapLayout& dst, const VDPixmapLayout& src); + +class VDPixmapCachedBlitter { + VDPixmapCachedBlitter(const VDPixmapCachedBlitter&); + VDPixmapCachedBlitter& operator=(const VDPixmapCachedBlitter&); +public: + VDPixmapCachedBlitter(); + ~VDPixmapCachedBlitter(); + + void Blit(const VDPixmap& dst, const VDPixmap& src); + void Invalidate(); + +protected: + sint32 mSrcWidth; + sint32 mSrcHeight; + int mSrcFormat; + sint32 mDstWidth; + sint32 mDstHeight; + int mDstFormat; + IVDPixmapBlitter *mpCachedBlitter; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixel.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixel.h index 149a7da91d5..3c65ac1cced 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixel.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixel.h @@ -1,40 +1,40 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_PIXEL_H -#define f_VD2_KASUMI_PIXEL_H - -#ifndef f_VD2_SYSTEM_VDTYPES_H - #include -#endif - -struct VDPixmap; - -uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y); -uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x, sint32 y); - -inline uint8 VDPixmapSample8(const void *data, ptrdiff_t pitch, sint32 x, sint32 y) { - return ((const uint8 *)data)[pitch*y + x]; -} - -uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256); -uint32 VDConvertYCbCrToRGB(uint8 y, uint8 cb, uint8 cr, bool use709, bool useFullRange); -uint32 VDConvertRGBToYCbCr(uint32 c); -uint32 VDConvertRGBToYCbCr(uint8 r, uint8 g, uint8 b, bool use709, bool useFullRange); - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_PIXEL_H +#define f_VD2_KASUMI_PIXEL_H + +#ifndef f_VD2_SYSTEM_VDTYPES_H + #include +#endif + +struct VDPixmap; + +uint32 VDPixmapSample(const VDPixmap& px, sint32 x, sint32 y); +uint32 VDPixmapInterpolateSampleRGB24(const VDPixmap& px, sint32 x, sint32 y); + +inline uint8 VDPixmapSample8(const void *data, ptrdiff_t pitch, sint32 x, sint32 y) { + return ((const uint8 *)data)[pitch*y + x]; +} + +uint8 VDPixmapInterpolateSample8(const void *data, ptrdiff_t pitch, uint32 w, uint32 h, sint32 x_256, sint32 y_256); +uint32 VDConvertYCbCrToRGB(uint8 y, uint8 cb, uint8 cr, bool use709, bool useFullRange); +uint32 VDConvertRGBToYCbCr(uint32 c); +uint32 VDConvertRGBToYCbCr(uint8 r, uint8 g, uint8 b, bool use709, bool useFullRange); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmap.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmap.h index 58c64d73d65..33e36f67bf8 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmap.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmap.h @@ -1,109 +1,109 @@ -#ifndef f_VD2_KASUMI_PIXMAP_H -#define f_VD2_KASUMI_PIXMAP_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -namespace nsVDPixmap { - enum VDPixmapFormat { - kPixFormat_Null, - kPixFormat_Pal1, - kPixFormat_Pal2, - kPixFormat_Pal4, - kPixFormat_Pal8, - kPixFormat_XRGB1555, - kPixFormat_RGB565, - kPixFormat_RGB888, - kPixFormat_XRGB8888, - kPixFormat_Y8, - kPixFormat_YUV422_UYVY, - kPixFormat_YUV422_YUYV, - kPixFormat_YUV444_XVYU, // The reason for the strange VYU ordering is to make it easier to convert to UYVY/YUY2. - kPixFormat_YUV444_Planar, - kPixFormat_YUV422_Planar, - kPixFormat_YUV420_Planar, - kPixFormat_YUV411_Planar, - kPixFormat_YUV410_Planar, - kPixFormat_YUV422_Planar_Centered, // MPEG-1/MJPEG chroma alignment - kPixFormat_YUV420_Planar_Centered, // MPEG-1/MJPEG chroma alignment - kPixFormat_YUV422_Planar_16F, - kPixFormat_YUV422_V210, - kPixFormat_YUV422_UYVY_709, // Also known as HDYC. - kPixFormat_YUV420_NV12, - kPixFormat_Y8_FR, - kPixFormat_YUV422_YUYV_709, - kPixFormat_YUV444_Planar_709, - kPixFormat_YUV422_Planar_709, - kPixFormat_YUV420_Planar_709, - kPixFormat_YUV411_Planar_709, - kPixFormat_YUV410_Planar_709, - kPixFormat_YUV422_UYVY_FR, - kPixFormat_YUV422_YUYV_FR, - kPixFormat_YUV444_Planar_FR, - kPixFormat_YUV422_Planar_FR, - kPixFormat_YUV420_Planar_FR, - kPixFormat_YUV411_Planar_FR, - kPixFormat_YUV410_Planar_FR, - kPixFormat_YUV422_UYVY_709_FR, - kPixFormat_YUV422_YUYV_709_FR, - kPixFormat_YUV444_Planar_709_FR, - kPixFormat_YUV422_Planar_709_FR, - kPixFormat_YUV420_Planar_709_FR, - kPixFormat_YUV411_Planar_709_FR, - kPixFormat_YUV410_Planar_709_FR, - kPixFormat_YUV420i_Planar, - kPixFormat_YUV420i_Planar_FR, - kPixFormat_YUV420i_Planar_709, - kPixFormat_YUV420i_Planar_709_FR, - kPixFormat_YUV420it_Planar, - kPixFormat_YUV420it_Planar_FR, - kPixFormat_YUV420it_Planar_709, - kPixFormat_YUV420it_Planar_709_FR, - kPixFormat_YUV420ib_Planar, - kPixFormat_YUV420ib_Planar_FR, - kPixFormat_YUV420ib_Planar_709, - kPixFormat_YUV420ib_Planar_709_FR, - kPixFormat_Max_Standard - }; -} - -typedef sint32 vdpixpos; -typedef sint32 vdpixsize; -typedef ptrdiff_t vdpixoffset; - -struct VDPixmap { - void *data; - const uint32 *palette; - vdpixsize w; - vdpixsize h; - vdpixoffset pitch; - sint32 format; - - // Auxiliary planes are always byte-per-pixel. - - void *data2; // Cb (U) for YCbCr - vdpixoffset pitch2; - void *data3; // Cr (V) for YCbCr - vdpixoffset pitch3; -}; - -struct VDPixmapLayout { - ptrdiff_t data; - const uint32 *palette; - vdpixsize w; - vdpixsize h; - vdpixoffset pitch; - sint32 format; - - // Auxiliary planes are always byte-per-pixel. - - ptrdiff_t data2; // Cb (U) for YCbCr - vdpixoffset pitch2; - ptrdiff_t data3; // Cr (V) for YCbCr - vdpixoffset pitch3; -}; - -#endif +#ifndef f_VD2_KASUMI_PIXMAP_H +#define f_VD2_KASUMI_PIXMAP_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +namespace nsVDPixmap { + enum VDPixmapFormat { + kPixFormat_Null, + kPixFormat_Pal1, + kPixFormat_Pal2, + kPixFormat_Pal4, + kPixFormat_Pal8, + kPixFormat_XRGB1555, + kPixFormat_RGB565, + kPixFormat_RGB888, + kPixFormat_XRGB8888, + kPixFormat_Y8, + kPixFormat_YUV422_UYVY, + kPixFormat_YUV422_YUYV, + kPixFormat_YUV444_XVYU, // The reason for the strange VYU ordering is to make it easier to convert to UYVY/YUY2. + kPixFormat_YUV444_Planar, + kPixFormat_YUV422_Planar, + kPixFormat_YUV420_Planar, + kPixFormat_YUV411_Planar, + kPixFormat_YUV410_Planar, + kPixFormat_YUV422_Planar_Centered, // MPEG-1/MJPEG chroma alignment + kPixFormat_YUV420_Planar_Centered, // MPEG-1/MJPEG chroma alignment + kPixFormat_YUV422_Planar_16F, + kPixFormat_YUV422_V210, + kPixFormat_YUV422_UYVY_709, // Also known as HDYC. + kPixFormat_YUV420_NV12, + kPixFormat_Y8_FR, + kPixFormat_YUV422_YUYV_709, + kPixFormat_YUV444_Planar_709, + kPixFormat_YUV422_Planar_709, + kPixFormat_YUV420_Planar_709, + kPixFormat_YUV411_Planar_709, + kPixFormat_YUV410_Planar_709, + kPixFormat_YUV422_UYVY_FR, + kPixFormat_YUV422_YUYV_FR, + kPixFormat_YUV444_Planar_FR, + kPixFormat_YUV422_Planar_FR, + kPixFormat_YUV420_Planar_FR, + kPixFormat_YUV411_Planar_FR, + kPixFormat_YUV410_Planar_FR, + kPixFormat_YUV422_UYVY_709_FR, + kPixFormat_YUV422_YUYV_709_FR, + kPixFormat_YUV444_Planar_709_FR, + kPixFormat_YUV422_Planar_709_FR, + kPixFormat_YUV420_Planar_709_FR, + kPixFormat_YUV411_Planar_709_FR, + kPixFormat_YUV410_Planar_709_FR, + kPixFormat_YUV420i_Planar, + kPixFormat_YUV420i_Planar_FR, + kPixFormat_YUV420i_Planar_709, + kPixFormat_YUV420i_Planar_709_FR, + kPixFormat_YUV420it_Planar, + kPixFormat_YUV420it_Planar_FR, + kPixFormat_YUV420it_Planar_709, + kPixFormat_YUV420it_Planar_709_FR, + kPixFormat_YUV420ib_Planar, + kPixFormat_YUV420ib_Planar_FR, + kPixFormat_YUV420ib_Planar_709, + kPixFormat_YUV420ib_Planar_709_FR, + kPixFormat_Max_Standard + }; +} + +typedef sint32 vdpixpos; +typedef sint32 vdpixsize; +typedef ptrdiff_t vdpixoffset; + +struct VDPixmap { + void *data; + const uint32 *palette; + vdpixsize w; + vdpixsize h; + vdpixoffset pitch; + sint32 format; + + // Auxiliary planes are always byte-per-pixel. + + void *data2; // Cb (U) for YCbCr + vdpixoffset pitch2; + void *data3; // Cr (V) for YCbCr + vdpixoffset pitch3; +}; + +struct VDPixmapLayout { + ptrdiff_t data; + const uint32 *palette; + vdpixsize w; + vdpixsize h; + vdpixoffset pitch; + sint32 format; + + // Auxiliary planes are always byte-per-pixel. + + ptrdiff_t data2; // Cb (U) for YCbCr + vdpixoffset pitch2; + ptrdiff_t data3; // Cr (V) for YCbCr + vdpixoffset pitch3; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmapops.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmapops.h index 150437052b2..6dce3a858cc 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmapops.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmapops.h @@ -1,20 +1,20 @@ -#ifndef f_VD2_KASUMI_PIXMAPOPS_H -#define f_VD2_KASUMI_PIXMAPOPS_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -bool VDPixmapIsBltPossible(int dst_format, int src_format); -bool VDPixmapBlt(const VDPixmap& dst, const VDPixmap& src); -bool VDPixmapBlt(const VDPixmap& dst, vdpixpos x1, vdpixpos y1, const VDPixmap& src, vdpixpos x2, vdpixpos y2, vdpixsize w, vdpixsize h); -bool VDPixmapStretchBltNearest(const VDPixmap& dst, const VDPixmap& src); -bool VDPixmapStretchBltNearest(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); -bool VDPixmapStretchBltBilinear(const VDPixmap& dst, const VDPixmap& src); -bool VDPixmapStretchBltBilinear(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); - -bool VDPixmapBltAlphaConst(const VDPixmap& dst, const VDPixmap& src, float alpha); - -#endif +#ifndef f_VD2_KASUMI_PIXMAPOPS_H +#define f_VD2_KASUMI_PIXMAPOPS_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +bool VDPixmapIsBltPossible(int dst_format, int src_format); +bool VDPixmapBlt(const VDPixmap& dst, const VDPixmap& src); +bool VDPixmapBlt(const VDPixmap& dst, vdpixpos x1, vdpixpos y1, const VDPixmap& src, vdpixpos x2, vdpixpos y2, vdpixsize w, vdpixsize h); +bool VDPixmapStretchBltNearest(const VDPixmap& dst, const VDPixmap& src); +bool VDPixmapStretchBltNearest(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); +bool VDPixmapStretchBltBilinear(const VDPixmap& dst, const VDPixmap& src); +bool VDPixmapStretchBltBilinear(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2); + +bool VDPixmapBltAlphaConst(const VDPixmap& dst, const VDPixmap& src, float alpha); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmaputils.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmaputils.h index 9eb04706241..c572b52ae53 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmaputils.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/pixmaputils.h @@ -1,171 +1,171 @@ -#ifndef f_VD2_KASUMI_PIXMAPUTILS_H -#define f_VD2_KASUMI_PIXMAPUTILS_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -struct VDPixmapFormatInfo { - const char *name; // debugging name - bool qchunky; // quantums are chunky (not 1x1 pixels) - int qw, qh; // width, height of a quantum - int qwbits, qhbits; // width and height of a quantum as shifts - int qsize; // size of a pixel in bytes - int auxbufs; // number of auxiliary buffers (0 for chunky formats, usually 2 for planar) - int auxwbits, auxhbits; // subsampling factors for auxiliary buffers in shifts - int auxsize; // size of an aux sample in bytes - int palsize; // entries in palette - int subformats; // number of subformats for this format -}; - -extern const VDPixmapFormatInfo g_vdPixmapFormats[]; - -inline const VDPixmapFormatInfo& VDPixmapGetInfo(sint32 format) { - VDASSERT((uint32)format < nsVDPixmap::kPixFormat_Max_Standard); - return g_vdPixmapFormats[(uint32)format < nsVDPixmap::kPixFormat_Max_Standard ? format : 0]; -} - -#ifdef _DEBUG - bool VDAssertValidPixmap(const VDPixmap& px); -#else - inline bool VDAssertValidPixmap(const VDPixmap& px) { return true; } -#endif - -inline VDPixmap VDPixmapFromLayout(const VDPixmapLayout& layout, void *p) { - VDPixmap px; - - px.data = (char *)p + layout.data; - px.data2 = (char *)p + layout.data2; - px.data3 = (char *)p + layout.data3; - px.format = layout.format; - px.w = layout.w; - px.h = layout.h; - px.palette = layout.palette; - px.pitch = layout.pitch; - px.pitch2 = layout.pitch2; - px.pitch3 = layout.pitch3; - - return px; -} - -inline VDPixmapLayout VDPixmapToLayoutFromBase(const VDPixmap& px, void *p) { - VDPixmapLayout layout; - layout.data = (char *)px.data - (char *)p; - layout.data2 = (char *)px.data2 - (char *)p; - layout.data3 = (char *)px.data3 - (char *)p; - layout.format = px.format; - layout.w = px.w; - layout.h = px.h; - layout.palette = px.palette; - layout.pitch = px.pitch; - layout.pitch2 = px.pitch2; - layout.pitch3 = px.pitch3; - return layout; -} - -inline VDPixmapLayout VDPixmapToLayout(const VDPixmap& px, void *&p) { - VDPixmapLayout layout; - p = px.data; - layout.data = 0; - layout.data2 = (char *)px.data2 - (char *)px.data; - layout.data3 = (char *)px.data3 - (char *)px.data; - layout.format = px.format; - layout.w = px.w; - layout.h = px.h; - layout.palette = px.palette; - layout.pitch = px.pitch; - layout.pitch2 = px.pitch2; - layout.pitch3 = px.pitch3; - return layout; -} - -uint32 VDPixmapCreateLinearLayout(VDPixmapLayout& layout, int format, vdpixsize w, vdpixsize h, int alignment); - -VDPixmap VDPixmapOffset(const VDPixmap& src, vdpixpos x, vdpixpos y); -VDPixmapLayout VDPixmapLayoutOffset(const VDPixmapLayout& src, vdpixpos x, vdpixpos y); - -void VDPixmapFlipV(VDPixmap& layout); -void VDPixmapLayoutFlipV(VDPixmapLayout& layout); - -uint32 VDPixmapLayoutGetMinSize(const VDPixmapLayout& layout); - -VDPixmap VDPixmapExtractField(const VDPixmap& src, bool field2); - -#ifndef VDPTRSTEP_DECLARED - template - inline void vdptrstep(T *&p, ptrdiff_t offset) { - p = (T *)((char *)p + offset); - } -#endif -#ifndef VDPTROFFSET_DECLARED - template - inline T *vdptroffset(T *p, ptrdiff_t offset) { - return (T *)((char *)p + offset); - } -#endif -#ifndef VDPTRDIFFABS_DECLARED - inline ptrdiff_t vdptrdiffabs(ptrdiff_t x) { - return x<0 ? -x : x; - } -#endif - - -typedef void (*VDPixmapBlitterFn)(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); -typedef VDPixmapBlitterFn (*tpVDPixBltTable)[nsVDPixmap::kPixFormat_Max_Standard]; - -tpVDPixBltTable VDGetPixBltTableReference(); -tpVDPixBltTable VDGetPixBltTableX86Scalar(); -tpVDPixBltTable VDGetPixBltTableX86MMX(); - - - -class VDPixmapBuffer : public VDPixmap { -public: - VDPixmapBuffer() : mpBuffer(NULL), mLinearSize(0) { data = NULL; format = 0; } - explicit VDPixmapBuffer(const VDPixmap& src); - VDPixmapBuffer(const VDPixmapBuffer& src); - VDPixmapBuffer(sint32 w, sint32 h, int format) : mpBuffer(NULL), mLinearSize(0) { - init(w, h, format); - } - explicit VDPixmapBuffer(const VDPixmapLayout& layout); - - ~VDPixmapBuffer(); - - void clear() { - if (mpBuffer) // to reduce debug checks - delete[] mpBuffer; - mpBuffer = NULL; - mLinearSize = 0; - format = nsVDPixmap::kPixFormat_Null; - } - -#ifdef _DEBUG - void *base() { return mpBuffer + (-(int)(uintptr)mpBuffer & 15) + 16; } - const void *base() const { return mpBuffer + (-(int)(uintptr)mpBuffer & 15) + 16; } - size_t size() const { return mLinearSize - 28; } - - void validate(); -#else - void *base() { return mpBuffer + (-(int)(uintptr)mpBuffer & 15); } - const void *base() const { return mpBuffer + (-(int)(uintptr)mpBuffer & 15); } - size_t size() const { return mLinearSize; } - - void validate() {} -#endif - - void init(sint32 w, sint32 h, int format); - void init(const VDPixmapLayout&, uint32 additionalPadding = 0); - - void assign(const VDPixmap& src); - - void swap(VDPixmapBuffer&); - -protected: - char *mpBuffer; - size_t mLinearSize; -}; - - -#endif +#ifndef f_VD2_KASUMI_PIXMAPUTILS_H +#define f_VD2_KASUMI_PIXMAPUTILS_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +struct VDPixmapFormatInfo { + const char *name; // debugging name + bool qchunky; // quantums are chunky (not 1x1 pixels) + int qw, qh; // width, height of a quantum + int qwbits, qhbits; // width and height of a quantum as shifts + int qsize; // size of a pixel in bytes + int auxbufs; // number of auxiliary buffers (0 for chunky formats, usually 2 for planar) + int auxwbits, auxhbits; // subsampling factors for auxiliary buffers in shifts + int auxsize; // size of an aux sample in bytes + int palsize; // entries in palette + int subformats; // number of subformats for this format +}; + +extern const VDPixmapFormatInfo g_vdPixmapFormats[]; + +inline const VDPixmapFormatInfo& VDPixmapGetInfo(sint32 format) { + VDASSERT((uint32)format < nsVDPixmap::kPixFormat_Max_Standard); + return g_vdPixmapFormats[(uint32)format < nsVDPixmap::kPixFormat_Max_Standard ? format : 0]; +} + +#ifdef _DEBUG + bool VDAssertValidPixmap(const VDPixmap& px); +#else + inline bool VDAssertValidPixmap(const VDPixmap& px) { return true; } +#endif + +inline VDPixmap VDPixmapFromLayout(const VDPixmapLayout& layout, void *p) { + VDPixmap px; + + px.data = (char *)p + layout.data; + px.data2 = (char *)p + layout.data2; + px.data3 = (char *)p + layout.data3; + px.format = layout.format; + px.w = layout.w; + px.h = layout.h; + px.palette = layout.palette; + px.pitch = layout.pitch; + px.pitch2 = layout.pitch2; + px.pitch3 = layout.pitch3; + + return px; +} + +inline VDPixmapLayout VDPixmapToLayoutFromBase(const VDPixmap& px, void *p) { + VDPixmapLayout layout; + layout.data = (char *)px.data - (char *)p; + layout.data2 = (char *)px.data2 - (char *)p; + layout.data3 = (char *)px.data3 - (char *)p; + layout.format = px.format; + layout.w = px.w; + layout.h = px.h; + layout.palette = px.palette; + layout.pitch = px.pitch; + layout.pitch2 = px.pitch2; + layout.pitch3 = px.pitch3; + return layout; +} + +inline VDPixmapLayout VDPixmapToLayout(const VDPixmap& px, void *&p) { + VDPixmapLayout layout; + p = px.data; + layout.data = 0; + layout.data2 = (char *)px.data2 - (char *)px.data; + layout.data3 = (char *)px.data3 - (char *)px.data; + layout.format = px.format; + layout.w = px.w; + layout.h = px.h; + layout.palette = px.palette; + layout.pitch = px.pitch; + layout.pitch2 = px.pitch2; + layout.pitch3 = px.pitch3; + return layout; +} + +uint32 VDPixmapCreateLinearLayout(VDPixmapLayout& layout, int format, vdpixsize w, vdpixsize h, int alignment); + +VDPixmap VDPixmapOffset(const VDPixmap& src, vdpixpos x, vdpixpos y); +VDPixmapLayout VDPixmapLayoutOffset(const VDPixmapLayout& src, vdpixpos x, vdpixpos y); + +void VDPixmapFlipV(VDPixmap& layout); +void VDPixmapLayoutFlipV(VDPixmapLayout& layout); + +uint32 VDPixmapLayoutGetMinSize(const VDPixmapLayout& layout); + +VDPixmap VDPixmapExtractField(const VDPixmap& src, bool field2); + +#ifndef VDPTRSTEP_DECLARED + template + inline void vdptrstep(T *&p, ptrdiff_t offset) { + p = (T *)((char *)p + offset); + } +#endif +#ifndef VDPTROFFSET_DECLARED + template + inline T *vdptroffset(T *p, ptrdiff_t offset) { + return (T *)((char *)p + offset); + } +#endif +#ifndef VDPTRDIFFABS_DECLARED + inline ptrdiff_t vdptrdiffabs(ptrdiff_t x) { + return x<0 ? -x : x; + } +#endif + + +typedef void (*VDPixmapBlitterFn)(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h); +typedef VDPixmapBlitterFn (*tpVDPixBltTable)[nsVDPixmap::kPixFormat_Max_Standard]; + +tpVDPixBltTable VDGetPixBltTableReference(); +tpVDPixBltTable VDGetPixBltTableX86Scalar(); +tpVDPixBltTable VDGetPixBltTableX86MMX(); + + + +class VDPixmapBuffer : public VDPixmap { +public: + VDPixmapBuffer() : mpBuffer(NULL), mLinearSize(0) { data = NULL; format = 0; } + explicit VDPixmapBuffer(const VDPixmap& src); + VDPixmapBuffer(const VDPixmapBuffer& src); + VDPixmapBuffer(sint32 w, sint32 h, int format) : mpBuffer(NULL), mLinearSize(0) { + init(w, h, format); + } + explicit VDPixmapBuffer(const VDPixmapLayout& layout); + + ~VDPixmapBuffer(); + + void clear() { + if (mpBuffer) // to reduce debug checks + delete[] mpBuffer; + mpBuffer = NULL; + mLinearSize = 0; + format = nsVDPixmap::kPixFormat_Null; + } + +#ifdef _DEBUG + void *base() { return mpBuffer + (-(int)(uintptr)mpBuffer & 15) + 16; } + const void *base() const { return mpBuffer + (-(int)(uintptr)mpBuffer & 15) + 16; } + size_t size() const { return mLinearSize - 28; } + + void validate(); +#else + void *base() { return mpBuffer + (-(int)(uintptr)mpBuffer & 15); } + const void *base() const { return mpBuffer + (-(int)(uintptr)mpBuffer & 15); } + size_t size() const { return mLinearSize; } + + void validate() {} +#endif + + void init(sint32 w, sint32 h, int format); + void init(const VDPixmapLayout&, uint32 additionalPadding = 0); + + void assign(const VDPixmap& src); + + void swap(VDPixmapBuffer&); + +protected: + char *mpBuffer; + size_t mLinearSize; +}; + + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/region.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/region.h index 8e5093b2bcc..b063221cb0e 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/region.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/region.h @@ -1,93 +1,93 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_REGION_H -#define f_VD2_KASUMI_REGION_H - -struct VDPixmap; - -#include -#include - -class VDPixmapRegion { -public: - void swap(VDPixmapRegion& x); - void clear(); - -public: - vdfastvector mSpans; - vdrect32 mBounds; -}; - -class VDPixmapPathRasterizer { -public: - VDPixmapPathRasterizer(); - VDPixmapPathRasterizer(const VDPixmapPathRasterizer&); // no-op - ~VDPixmapPathRasterizer(); - - VDPixmapPathRasterizer& operator=(const VDPixmapPathRasterizer&); // no-op - - void Clear(); - void QuadraticBezier(const vdint2 pts[4]); - void CubicBezier(const vdint2 pts[4]); - void Line(const vdint2& pt1, const vdint2& pt2); - void FastLine(int x0, int y0, int x1, int y1); - - void ScanConvert(VDPixmapRegion& region); - -protected: - void ClearEdgeList(); - void FreeEdgeLists(); - void ClearScanBuffer(); - void ReallocateScanBuffer(int ymin, int ymax); - - struct Edge { - Edge *next; - int posandflag; - }; - - enum { kEdgeBlockMax = 1024 }; - - struct EdgeBlock { - EdgeBlock *next; - Edge edges[1024]; - - EdgeBlock(EdgeBlock *p) : next(p) {} - }; - - struct Scan { - Edge *chain; - uint32 count; - }; - - EdgeBlock *mpEdgeBlocks; - EdgeBlock *mpFreeEdgeBlocks; - int mEdgeBlockIdx; - Scan *mpScanBuffer; - Scan *mpScanBufferBiased; - int mScanYMin; - int mScanYMax; -}; - -bool VDPixmapFillRegion(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color); -bool VDPixmapFillRegionAntialiased8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color); - -void VDPixmapCreateRoundRegion(VDPixmapRegion& dst, float r); -void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, VDPixmapRegion *tempCache = NULL); - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_REGION_H +#define f_VD2_KASUMI_REGION_H + +struct VDPixmap; + +#include +#include + +class VDPixmapRegion { +public: + void swap(VDPixmapRegion& x); + void clear(); + +public: + vdfastvector mSpans; + vdrect32 mBounds; +}; + +class VDPixmapPathRasterizer { +public: + VDPixmapPathRasterizer(); + VDPixmapPathRasterizer(const VDPixmapPathRasterizer&); // no-op + ~VDPixmapPathRasterizer(); + + VDPixmapPathRasterizer& operator=(const VDPixmapPathRasterizer&); // no-op + + void Clear(); + void QuadraticBezier(const vdint2 pts[4]); + void CubicBezier(const vdint2 pts[4]); + void Line(const vdint2& pt1, const vdint2& pt2); + void FastLine(int x0, int y0, int x1, int y1); + + void ScanConvert(VDPixmapRegion& region); + +protected: + void ClearEdgeList(); + void FreeEdgeLists(); + void ClearScanBuffer(); + void ReallocateScanBuffer(int ymin, int ymax); + + struct Edge { + Edge *next; + int posandflag; + }; + + enum { kEdgeBlockMax = 1024 }; + + struct EdgeBlock { + EdgeBlock *next; + Edge edges[1024]; + + EdgeBlock(EdgeBlock *p) : next(p) {} + }; + + struct Scan { + Edge *chain; + uint32 count; + }; + + EdgeBlock *mpEdgeBlocks; + EdgeBlock *mpFreeEdgeBlocks; + int mEdgeBlockIdx; + Scan *mpScanBuffer; + Scan *mpScanBufferBiased; + int mScanYMin; + int mScanYMax; +}; + +bool VDPixmapFillRegion(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color); +bool VDPixmapFillRegionAntialiased8x(const VDPixmap& dst, const VDPixmapRegion& region, int x, int y, uint32 color); + +void VDPixmapCreateRoundRegion(VDPixmapRegion& dst, float r); +void VDPixmapConvolveRegion(VDPixmapRegion& dst, const VDPixmapRegion& r1, const VDPixmapRegion& r2, VDPixmapRegion *tempCache = NULL); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample.h index ba79bf1add4..12c6f01a288 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample.h @@ -1,31 +1,31 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_H -#define f_VD2_KASUMI_RESAMPLE_H - -#include - -struct VDPixmap; - -class IVDPixmapResampler { -public: - enum FilterMode { - kFilterPoint, - kFilterLinear, - kFilterCubic, - kFilterLanczos3, - kFilterCount - }; - - virtual ~IVDPixmapResampler() {} - virtual void SetSplineFactor(double A) = 0; - virtual void SetFilters(FilterMode h, FilterMode v, bool interpolationOnly) = 0; - virtual bool Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat) = 0; - virtual bool Init(const vdrect32f& dstrect, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect, uint32 sw, uint32 sh, int srcformat) = 0; - virtual void Shutdown() = 0; - - virtual void Process(const VDPixmap& dst, const VDPixmap& src) = 0; -}; - -IVDPixmapResampler *VDCreatePixmapResampler(); -bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter); - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_H +#define f_VD2_KASUMI_RESAMPLE_H + +#include + +struct VDPixmap; + +class IVDPixmapResampler { +public: + enum FilterMode { + kFilterPoint, + kFilterLinear, + kFilterCubic, + kFilterLanczos3, + kFilterCount + }; + + virtual ~IVDPixmapResampler() {} + virtual void SetSplineFactor(double A) = 0; + virtual void SetFilters(FilterMode h, FilterMode v, bool interpolationOnly) = 0; + virtual bool Init(uint32 dw, uint32 dh, int dstformat, uint32 sw, uint32 sh, int srcformat) = 0; + virtual bool Init(const vdrect32f& dstrect, uint32 dw, uint32 dh, int dstformat, const vdrect32f& srcrect, uint32 sw, uint32 sh, int srcformat) = 0; + virtual void Shutdown() = 0; + + virtual void Process(const VDPixmap& dst, const VDPixmap& src) = 0; +}; + +IVDPixmapResampler *VDCreatePixmapResampler(); +bool VDPixmapResample(const VDPixmap& dst, const VDPixmap& src, IVDPixmapResampler::FilterMode filter); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample_kernels.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample_kernels.h index 54be5827e3e..a95e9b02892 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample_kernels.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/resample_kernels.h @@ -1,91 +1,91 @@ -#ifndef f_VD2_KASUMI_RESAMPLE_KERNELS_H -#define f_VD2_KASUMI_RESAMPLE_KERNELS_H - -#include -#include - -struct VDResamplerAxis { - sint32 dx; - sint32 u; - sint32 dudx; - uint32 dx_precopy; - uint32 dx_preclip; - uint32 dx_active; - uint32 dx_postclip; - uint32 dx_postcopy; - uint32 dx_dualclip; - - void Init(sint32 dudx); - void Compute(sint32 count, sint32 u0, sint32 w, sint32 kernel_width); -}; - - -/////////////////////////////////////////////////////////////////////////// -// -// filter kernels -// -/////////////////////////////////////////////////////////////////////////// - -class IVDResamplerFilter { -public: - virtual ~IVDResamplerFilter() {} - - virtual int GetFilterWidth() const = 0; - virtual double EvaluateFilter(double offset) const = 0; - virtual void GenerateFilter(float *dst, double offset) const = 0; - virtual void GenerateFilterBank(float *dst) const = 0; -}; - -class VDResamplerLinearFilter : public IVDResamplerFilter { -public: - VDResamplerLinearFilter(double twofc); - - int GetFilterWidth() const; - - double EvaluateFilter(double offset) const; - void GenerateFilter(float *dst, double offset) const; - void GenerateFilterBank(float *dst) const; - -protected: - double mScale; - unsigned mTaps; -}; - -class VDResamplerCubicFilter : public IVDResamplerFilter { -public: - VDResamplerCubicFilter(double twofc, double A); - - int GetFilterWidth() const; - - double EvaluateFilter(double offset) const; - void GenerateFilter(float *dst, double offset) const; - void GenerateFilterBank(float *dst) const; - -protected: - double mScale; - double mA0; - double mA2; - double mA3; - double mB0; - double mB1; - double mB2; - double mB3; - unsigned mTaps; -}; - -class VDResamplerLanczos3Filter : public IVDResamplerFilter { -public: - VDResamplerLanczos3Filter(double twofc); - - int GetFilterWidth() const; - - double EvaluateFilter(double offset) const; - void GenerateFilter(float *dst, double offset) const; - void GenerateFilterBank(float *dst) const; - -protected: - double mScale; - unsigned mTaps; -}; - -#endif +#ifndef f_VD2_KASUMI_RESAMPLE_KERNELS_H +#define f_VD2_KASUMI_RESAMPLE_KERNELS_H + +#include +#include + +struct VDResamplerAxis { + sint32 dx; + sint32 u; + sint32 dudx; + uint32 dx_precopy; + uint32 dx_preclip; + uint32 dx_active; + uint32 dx_postclip; + uint32 dx_postcopy; + uint32 dx_dualclip; + + void Init(sint32 dudx); + void Compute(sint32 count, sint32 u0, sint32 w, sint32 kernel_width); +}; + + +/////////////////////////////////////////////////////////////////////////// +// +// filter kernels +// +/////////////////////////////////////////////////////////////////////////// + +class IVDResamplerFilter { +public: + virtual ~IVDResamplerFilter() {} + + virtual int GetFilterWidth() const = 0; + virtual double EvaluateFilter(double offset) const = 0; + virtual void GenerateFilter(float *dst, double offset) const = 0; + virtual void GenerateFilterBank(float *dst) const = 0; +}; + +class VDResamplerLinearFilter : public IVDResamplerFilter { +public: + VDResamplerLinearFilter(double twofc); + + int GetFilterWidth() const; + + double EvaluateFilter(double offset) const; + void GenerateFilter(float *dst, double offset) const; + void GenerateFilterBank(float *dst) const; + +protected: + double mScale; + unsigned mTaps; +}; + +class VDResamplerCubicFilter : public IVDResamplerFilter { +public: + VDResamplerCubicFilter(double twofc, double A); + + int GetFilterWidth() const; + + double EvaluateFilter(double offset) const; + void GenerateFilter(float *dst, double offset) const; + void GenerateFilterBank(float *dst) const; + +protected: + double mScale; + double mA0; + double mA2; + double mA3; + double mB0; + double mB1; + double mB2; + double mB3; + unsigned mTaps; +}; + +class VDResamplerLanczos3Filter : public IVDResamplerFilter { +public: + VDResamplerLanczos3Filter(double twofc); + + int GetFilterWidth() const; + + double EvaluateFilter(double offset) const; + void GenerateFilter(float *dst, double offset) const; + void GenerateFilterBank(float *dst) const; + +protected: + double mScale; + unsigned mTaps; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/tables.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/tables.h index 1ff663df9d2..972f3703672 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/tables.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/tables.h @@ -1,41 +1,41 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2008 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_TABLES_H -#define f_VD2_KASUMI_TABLES_H - -/////////////////////////////////////////////////////////////////////////////// -// Cubic interpolation tables -// -// These tables give coefficients for 1-D cubic interpolation with 8-bit -// subunit precision. The [0] entry is positioned exactly on top of the -// second sample, and the [255] entry is 255/256th of the way to the third -// sample. The cardinal spline constant is -0.75 and the output range is -// [-0.1875, 1.1875], where the maximum overshoot and undershoot occur at -// the midpoint. -// -// The first and fourth coefficients are always negative; the second and -// third coefficients are always positive. -// -extern "C" const sint32 kVDCubicInterpTableFX14_075[256][4]; - -#ifdef _M_IX86 - extern "C" const sint16 kVDCubicInterpTableFX14_075_MMX[256][8]; -#endif - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2008 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_TABLES_H +#define f_VD2_KASUMI_TABLES_H + +/////////////////////////////////////////////////////////////////////////////// +// Cubic interpolation tables +// +// These tables give coefficients for 1-D cubic interpolation with 8-bit +// subunit precision. The [0] entry is positioned exactly on top of the +// second sample, and the [255] entry is 255/256th of the way to the third +// sample. The cardinal spline constant is -0.75 and the output range is +// [-0.1875, 1.1875], where the maximum overshoot and undershoot occur at +// the midpoint. +// +// The first and fourth coefficients are always negative; the second and +// third coefficients are always positive. +// +extern "C" const sint32 kVDCubicInterpTableFX14_075[256][4]; + +#ifdef _M_IX86 + extern "C" const sint16 kVDCubicInterpTableFX14_075_MMX[256][8]; +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h index 70452b66f15..f4dba2796ca 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/text.h @@ -1,76 +1,76 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2009 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_TEXT_H -#define f_VD2_KASUMI_TEXT_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -class VDPixmapPathRasterizer; - -struct VDOutlineFontGlyphInfo { - uint16 mPointArrayStart; // start of points (encoded as 8:8) - uint16 mCommandArrayStart; // start of commands (encoded as 6:2 RLE). - sint16 mAWidth; // advance from start to character cell - sint16 mBWidth; // width of character cell - sint16 mCWidth; // advance from character cell to end -}; - -struct VDOutlineFontInfo { - const uint16 *mpPointArray; - const uint8 *mpCommandArray; - const VDOutlineFontGlyphInfo *mpGlyphArray; - int mStartGlyph; - int mEndGlyph; - int mMinX; - int mMinY; - int mMaxX; - int mMaxY; - int mEmSquare; - int mAscent; - int mDescent; - int mLineGap; -}; - -struct VDTextLayoutMetrics { - vdrect32f mExtents; - float mAdvance; -}; - -void VDPixmapGetTextExtents(const VDOutlineFontInfo *font, float size, const char *pText, VDTextLayoutMetrics& out_Metrics); -void VDPixmapConvertTextToPath(VDPixmapPathRasterizer& rast, const VDOutlineFontInfo *font, float size, float x, float y, const char *pText, const float transform[2][2] = NULL); - -struct VDBitmapFontInfo { - const uint8 *mpBitsArray; - const uint16 *mpPosArray; - uint8 mStartChar; - uint8 mEndChar; - int mCellWidth; - int mCellHeight; - int mCellAscent; - int mCellAdvance; - int mLineGap; -}; - -void VDPixmapDrawText(const VDPixmap& pxdst, const VDBitmapFontInfo *font, int x, int y, uint32 fore, uint32 back, const char *pText); - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2009 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_TEXT_H +#define f_VD2_KASUMI_TEXT_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +class VDPixmapPathRasterizer; + +struct VDOutlineFontGlyphInfo { + uint16 mPointArrayStart; // start of points (encoded as 8:8) + uint16 mCommandArrayStart; // start of commands (encoded as 6:2 RLE). + sint16 mAWidth; // advance from start to character cell + sint16 mBWidth; // width of character cell + sint16 mCWidth; // advance from character cell to end +}; + +struct VDOutlineFontInfo { + const uint16 *mpPointArray; + const uint8 *mpCommandArray; + const VDOutlineFontGlyphInfo *mpGlyphArray; + int mStartGlyph; + int mEndGlyph; + int mMinX; + int mMinY; + int mMaxX; + int mMaxY; + int mEmSquare; + int mAscent; + int mDescent; + int mLineGap; +}; + +struct VDTextLayoutMetrics { + vdrect32f mExtents; + float mAdvance; +}; + +void VDPixmapGetTextExtents(const VDOutlineFontInfo *font, float size, const char *pText, VDTextLayoutMetrics& out_Metrics); +void VDPixmapConvertTextToPath(VDPixmapPathRasterizer& rast, const VDOutlineFontInfo *font, float size, float x, float y, const char *pText, const float transform[2][2] = NULL); + +struct VDBitmapFontInfo { + const uint8 *mpBitsArray; + const uint16 *mpPosArray; + uint8 mStartChar; + uint8 mEndChar; + int mCellWidth; + int mCellHeight; + int mCellAscent; + int mCellAdvance; + int mLineGap; +}; + +void VDPixmapDrawText(const VDPixmap& pxdst, const VDBitmapFontInfo *font, int x, int y, uint32 fore, uint32 back, const char *pText); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/Kasumi/triblt.h b/src/thirdparty/VirtualDub/h/vd2/Kasumi/triblt.h index c564ebbb0af..9765f8e4165 100644 --- a/src/thirdparty/VirtualDub/h/vd2/Kasumi/triblt.h +++ b/src/thirdparty/VirtualDub/h/vd2/Kasumi/triblt.h @@ -1,72 +1,72 @@ -// VirtualDub - Video processing and capture application -// Graphics support library -// Copyright (C) 1998-2008 Avery Lee -// -// This program 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 2 of the License, or -// (at your option) any later version. -// -// This program 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, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#ifndef f_VD2_KASUMI_TRIBLT_H -#define f_VD2_KASUMI_TRIBLT_H - -#include -#include -#include - -struct VDTriBltVertex { - float x, y, z, u, v; -}; - -struct VDTriColorVertex { - float x, y, z, r, g, b, a; -}; - -enum VDTriBltFilterMode { - kTriBltFilterPoint, - kTriBltFilterBilinear, - kTriBltFilterTrilinear, - kTriBltFilterBicubicMipLinear, - kTriBltFilterCount -}; - -bool VDPixmapTriFill(VDPixmap& dst, uint32 c, - const VDTriBltVertex *pVertices, int nVertices, - const int *pIndices, const int nIndices, - const float pTransform[16] = NULL); - -bool VDPixmapTriFill(VDPixmap& dst, - const VDTriColorVertex *pVertices, int nVertices, - const int *pIndices, const int nIndices, - const float pTransform[16] = NULL, - const float *chroma_yoffset = NULL); - -bool VDPixmapTriBlt(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, - const VDTriBltVertex *pVertices, int nVertices, - const int *pIndices, const int nIndices, - VDTriBltFilterMode filterMode, - float mipMapLODBias, - const float pTransform[16] = NULL); - -class VDPixmapTextureMipmapChain { -public: - VDPixmapTextureMipmapChain(const VDPixmap& src, bool wrap=false, bool cubic = false, int maxlevels = 16); - - const VDPixmap *const *Mips() const { return mMipMaps.data(); } - int Levels() const { return mMipMaps.size(); } - -protected: - std::vector mBuffers; - vdfastvector mMipMaps; -}; - -#endif +// VirtualDub - Video processing and capture application +// Graphics support library +// Copyright (C) 1998-2008 Avery Lee +// +// This program 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 2 of the License, or +// (at your option) any later version. +// +// This program 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +#ifndef f_VD2_KASUMI_TRIBLT_H +#define f_VD2_KASUMI_TRIBLT_H + +#include +#include +#include + +struct VDTriBltVertex { + float x, y, z, u, v; +}; + +struct VDTriColorVertex { + float x, y, z, r, g, b, a; +}; + +enum VDTriBltFilterMode { + kTriBltFilterPoint, + kTriBltFilterBilinear, + kTriBltFilterTrilinear, + kTriBltFilterBicubicMipLinear, + kTriBltFilterCount +}; + +bool VDPixmapTriFill(VDPixmap& dst, uint32 c, + const VDTriBltVertex *pVertices, int nVertices, + const int *pIndices, const int nIndices, + const float pTransform[16] = NULL); + +bool VDPixmapTriFill(VDPixmap& dst, + const VDTriColorVertex *pVertices, int nVertices, + const int *pIndices, const int nIndices, + const float pTransform[16] = NULL, + const float *chroma_yoffset = NULL); + +bool VDPixmapTriBlt(VDPixmap& dst, const VDPixmap *const *pSources, int nMipmaps, + const VDTriBltVertex *pVertices, int nVertices, + const int *pIndices, const int nIndices, + VDTriBltFilterMode filterMode, + float mipMapLODBias, + const float pTransform[16] = NULL); + +class VDPixmapTextureMipmapChain { +public: + VDPixmapTextureMipmapChain(const VDPixmap& src, bool wrap=false, bool cubic = false, int maxlevels = 16); + + const VDPixmap *const *Mips() const { return mMipMaps.data(); } + int Levels() const { return mMipMaps.size(); } + +protected: + std::vector mBuffers; + vdfastvector mMipMaps; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/Error.h b/src/thirdparty/VirtualDub/h/vd2/system/Error.h index 9b4d79c50ab..519d7faf64e 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/Error.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/Error.h @@ -1,125 +1,125 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_ERROR_H -#define f_VD2_ERROR_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -class MyError; - -/////////////////////////////////////////////////////////////////////////// -// IVDAsyncErrorCallback -// -class IVDAsyncErrorCallback { -public: - virtual bool OnAsyncError(MyError& e) = 0; -}; - -/////////////////////////////////////////////////////////////////////////// -// MyError -// -class MyError { -private: - const MyError& operator=(const MyError&); // protect against accidents - -protected: - char *buf; - -public: - MyError(); - MyError(const MyError& err); - MyError(const char *f, ...); - ~MyError(); - void clear(); - void assign(const MyError& e); - void assign(const char *s); - void setf(const char *f, ...); - void vsetf(const char *f, va_list val); - void post(struct HWND__ *hWndParent, const char *title) const; - char *gets() const { - return buf; - } - char *c_str() const { - return buf; - } - bool empty() const { return !buf; } - void discard(); - void swap(MyError& err); - void TransferFrom(MyError& err); -}; - -class MyICError : public MyError { -public: - MyICError(const char *s, uint32 icErr); - MyICError(uint32 icErr, const char *format, ...); -}; - -class MyMMIOError : public MyError { -public: - MyMMIOError(const char *s, uint32 icErr); -}; - -class MyAVIError : public MyError { -public: - MyAVIError(const char *s, uint32 aviErr); -}; - -class MyMemoryError : public MyError { -public: - MyMemoryError(); - MyMemoryError(size_t attemptedSize); -}; - -class MyWin32Error : public MyError { -public: - MyWin32Error(const char *format, uint32 err, ...); - - uint32 GetWin32Error() const { return mWin32Error; } - -protected: - const uint32 mWin32Error; -}; - -class MyCrashError : public MyError { -public: - MyCrashError(const char *format, uint32 dwExceptionCode); -}; - -class MyUserAbortError : public MyError { -public: - MyUserAbortError(); -}; - -class MyInternalError : public MyError { -public: - MyInternalError(const char *format, ...); -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_ERROR_H +#define f_VD2_ERROR_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +class MyError; + +/////////////////////////////////////////////////////////////////////////// +// IVDAsyncErrorCallback +// +class IVDAsyncErrorCallback { +public: + virtual bool OnAsyncError(MyError& e) = 0; +}; + +/////////////////////////////////////////////////////////////////////////// +// MyError +// +class MyError { +private: + const MyError& operator=(const MyError&); // protect against accidents + +protected: + char *buf; + +public: + MyError(); + MyError(const MyError& err); + MyError(const char *f, ...); + ~MyError(); + void clear(); + void assign(const MyError& e); + void assign(const char *s); + void setf(const char *f, ...); + void vsetf(const char *f, va_list val); + void post(struct HWND__ *hWndParent, const char *title) const; + char *gets() const { + return buf; + } + char *c_str() const { + return buf; + } + bool empty() const { return !buf; } + void discard(); + void swap(MyError& err); + void TransferFrom(MyError& err); +}; + +class MyICError : public MyError { +public: + MyICError(const char *s, uint32 icErr); + MyICError(uint32 icErr, const char *format, ...); +}; + +class MyMMIOError : public MyError { +public: + MyMMIOError(const char *s, uint32 icErr); +}; + +class MyAVIError : public MyError { +public: + MyAVIError(const char *s, uint32 aviErr); +}; + +class MyMemoryError : public MyError { +public: + MyMemoryError(); + MyMemoryError(size_t attemptedSize); +}; + +class MyWin32Error : public MyError { +public: + MyWin32Error(const char *format, uint32 err, ...); + + uint32 GetWin32Error() const { return mWin32Error; } + +protected: + const uint32 mWin32Error; +}; + +class MyCrashError : public MyError { +public: + MyCrashError(const char *format, uint32 dwExceptionCode); +}; + +class MyUserAbortError : public MyError { +public: + MyUserAbortError(); +}; + +class MyInternalError : public MyError { +public: + MyInternalError(const char *format, ...); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/Fraction.h b/src/thirdparty/VirtualDub/h/vd2/system/Fraction.h index f7aa17ea60c..74253363522 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/Fraction.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/Fraction.h @@ -1,95 +1,95 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_FRACTION_H -#define f_VD2_SYSTEM_FRACTION_H - -#include - -class VDFraction { -friend VDFraction operator*(unsigned long b, const VDFraction f); -friend VDFraction operator*(int b, const VDFraction f); -private: - unsigned long hi, lo; - - static VDFraction reduce(uint64 hi, uint64 lo); - -public: - VDFraction() {} - explicit VDFraction(int i) : hi(i), lo(1) {} - explicit VDFraction(unsigned long i) : hi(i), lo(1) { } - explicit VDFraction(unsigned long i, unsigned long j) : hi(i), lo(j) {} - explicit VDFraction(double d); - - bool operator<(VDFraction b) const; - bool operator<=(VDFraction b) const; - bool operator>(VDFraction b) const; - bool operator>=(VDFraction b) const; - bool operator==(VDFraction b) const; - bool operator!=(VDFraction b) const; - - VDFraction operator*(VDFraction b) const; - VDFraction operator/(VDFraction b) const; - - VDFraction operator*(unsigned long b) const; - VDFraction operator/(unsigned long b) const; - - VDFraction& operator*=(VDFraction b); - VDFraction& operator/=(VDFraction b); - VDFraction& operator*=(unsigned long b); - VDFraction& operator/=(unsigned long b); - - void Assign(unsigned long n, unsigned long d) { - hi = n; - lo = d; - } - - sint64 scale64t(sint64) const; - sint64 scale64r(sint64) const; - sint64 scale64u(sint64) const; - sint64 scale64it(sint64) const; - sint64 scale64ir(sint64) const; - sint64 scale64iu(sint64) const; - - double asDouble() const; - double AsInverseDouble() const; - - unsigned long roundup32ul() const; - - unsigned long getHi() const { return hi; } - unsigned long getLo() const { return lo; } - - VDFraction reduce() const { return reduce(hi, lo); } - - bool Parse(const char *s); - - static inline VDFraction reduce64(sint64 hi, sint64 lo) { return reduce(hi, lo); } -}; - -inline VDFraction operator*(unsigned long b, const VDFraction f) { return f*b; } - -typedef VDFraction Fraction; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_FRACTION_H +#define f_VD2_SYSTEM_FRACTION_H + +#include + +class VDFraction { +friend VDFraction operator*(unsigned long b, const VDFraction f); +friend VDFraction operator*(int b, const VDFraction f); +private: + unsigned long hi, lo; + + static VDFraction reduce(uint64 hi, uint64 lo); + +public: + VDFraction() {} + explicit VDFraction(int i) : hi(i), lo(1) {} + explicit VDFraction(unsigned long i) : hi(i), lo(1) { } + explicit VDFraction(unsigned long i, unsigned long j) : hi(i), lo(j) {} + explicit VDFraction(double d); + + bool operator<(VDFraction b) const; + bool operator<=(VDFraction b) const; + bool operator>(VDFraction b) const; + bool operator>=(VDFraction b) const; + bool operator==(VDFraction b) const; + bool operator!=(VDFraction b) const; + + VDFraction operator*(VDFraction b) const; + VDFraction operator/(VDFraction b) const; + + VDFraction operator*(unsigned long b) const; + VDFraction operator/(unsigned long b) const; + + VDFraction& operator*=(VDFraction b); + VDFraction& operator/=(VDFraction b); + VDFraction& operator*=(unsigned long b); + VDFraction& operator/=(unsigned long b); + + void Assign(unsigned long n, unsigned long d) { + hi = n; + lo = d; + } + + sint64 scale64t(sint64) const; + sint64 scale64r(sint64) const; + sint64 scale64u(sint64) const; + sint64 scale64it(sint64) const; + sint64 scale64ir(sint64) const; + sint64 scale64iu(sint64) const; + + double asDouble() const; + double AsInverseDouble() const; + + unsigned long roundup32ul() const; + + unsigned long getHi() const { return hi; } + unsigned long getLo() const { return lo; } + + VDFraction reduce() const { return reduce(hi, lo); } + + bool Parse(const char *s); + + static inline VDFraction reduce64(sint64 hi, sint64 lo) { return reduce(hi, lo); } +}; + +inline VDFraction operator*(unsigned long b, const VDFraction f) { return f*b; } + +typedef VDFraction Fraction; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDNamespace.h b/src/thirdparty/VirtualDub/h/vd2/system/VDNamespace.h index 31baa28b69d..c0f0d41413b 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDNamespace.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDNamespace.h @@ -1,157 +1,157 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. -#ifndef f_SYSTEM_VDNAMESPACE_H -#define f_SYSTEM_VDNAMESPACE_H - -#include - -class VDNamespaceNode; -class VDNamespaceGroup; -class VDNamespaceItem; -class VDNamespace; -template class VDNamespace2; - -/////////////////////////////////////////////////////////////////////////// -// -// Node: Any item in the namespace. -// -/////////////////////////////////////////////////////////////////////////// - -class VDNamespaceNode { -public: - const char *pszName; - VDNamespaceGroup *const pParent; - - VDNamespaceNode(const char *name, VDNamespaceGroup *parent) : pszName(name), pParent(parent) { } -}; - -/////////////////////////////////////////////////////////////////////////// -// -// Group: Holds items. -// -/////////////////////////////////////////////////////////////////////////// - -class VDNamespaceGroup : public VDNamespaceNode, public ListNode2 { -public: - ListAlloc listItems; - ListAlloc listGroups; - - const char *namedup(const char *s); - - VDNamespaceGroup(const char *_pszName, VDNamespaceGroup *parent); - ~VDNamespaceGroup(); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// Item class -// -/////////////////////////////////////////////////////////////////////////// - -class VDNamespaceItem : public VDNamespaceNode, public ListNode2 { -public: - const void *object; - - VDNamespaceItem(const char *_pszName, VDNamespaceGroup *parent, const void *src); - ~VDNamespaceItem(); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// Namespace class -// -/////////////////////////////////////////////////////////////////////////// - -class VDNamespace { -protected: - VDNamespaceGroup root; - - VDNamespaceGroup *_lookupGroup(const char *pszName, bool fCreate, bool fIsFilter); - VDNamespaceItem *_findItemByObject(const VDNamespaceGroup *pGroup, const void *pObj); - bool _getPathByItem(const VDNamespaceNode *pEntry, char *buf, int maxlen); - -public: - - VDNamespace(); - ~VDNamespace(); - - typedef bool (*tGroupEnumerator)(VDNamespace *pThis, const char *pszName, const VDNamespaceGroup *pGroup, void *pvData); - typedef bool (*tItemEnumerator)(VDNamespace *pThis, const char *pszName, const void *pItem, void *pvData); - - void clear(); - void add(const char *pszGroup, const char *pszName, const void *pDef); - const void *lookup(const char *pszName); - - bool enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData); - bool enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData); - - bool getPathByItem(const void *pObj, char *buf, int maxlen); -}; - -/////////////////////////////////////////////////////////////////////////// -// -// Templated Namespace class -// -/////////////////////////////////////////////////////////////////////////// - -template -class VDNamespace2 : public VDNamespace { -public: - VDNamespace2() {} - ~VDNamespace2() {} - - typedef bool (*tGroupEnumerator)(VDNamespace2 *pThis, const char *pszName, const VDNamespaceGroup *pGroup, void *pvData); - typedef bool (*tItemEnumerator)(VDNamespace2 *pThis, const char *pszName, const T *pItem, void *pvData); - - void add(const char *pszGroup, const char *pszName, const T *pDef) { - VDNamespace::add(pszGroup, pszName, pDef); - } - - const T *lookup(const char *pszName) { - return static_cast(VDNamespace::lookup(pszName)); - } - - bool enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData) { - for(ListAlloc::fwit it = (pGroupRoot ? pGroupRoot : &root)->listGroups.begin(); it; ++it) - if (!pEnum(this, it->pszName, it, pvData)) - return false; - - return true; - } - - bool enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData) { - for(ListAlloc::fwit it = (pGroupRoot ? pGroupRoot : &root)->listItems.begin(); it; ++it) - if (!pEnum(this, it->pszName, static_cast(it->object), pvData)) - return false; - - return true; - } - - bool getPathByItem(const T *pObj, char *buf, int maxlen) { - return VDNamespace::getPathByItem(pObj, buf, maxlen); - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. +#ifndef f_SYSTEM_VDNAMESPACE_H +#define f_SYSTEM_VDNAMESPACE_H + +#include + +class VDNamespaceNode; +class VDNamespaceGroup; +class VDNamespaceItem; +class VDNamespace; +template class VDNamespace2; + +/////////////////////////////////////////////////////////////////////////// +// +// Node: Any item in the namespace. +// +/////////////////////////////////////////////////////////////////////////// + +class VDNamespaceNode { +public: + const char *pszName; + VDNamespaceGroup *const pParent; + + VDNamespaceNode(const char *name, VDNamespaceGroup *parent) : pszName(name), pParent(parent) { } +}; + +/////////////////////////////////////////////////////////////////////////// +// +// Group: Holds items. +// +/////////////////////////////////////////////////////////////////////////// + +class VDNamespaceGroup : public VDNamespaceNode, public ListNode2 { +public: + ListAlloc listItems; + ListAlloc listGroups; + + const char *namedup(const char *s); + + VDNamespaceGroup(const char *_pszName, VDNamespaceGroup *parent); + ~VDNamespaceGroup(); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// Item class +// +/////////////////////////////////////////////////////////////////////////// + +class VDNamespaceItem : public VDNamespaceNode, public ListNode2 { +public: + const void *object; + + VDNamespaceItem(const char *_pszName, VDNamespaceGroup *parent, const void *src); + ~VDNamespaceItem(); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// Namespace class +// +/////////////////////////////////////////////////////////////////////////// + +class VDNamespace { +protected: + VDNamespaceGroup root; + + VDNamespaceGroup *_lookupGroup(const char *pszName, bool fCreate, bool fIsFilter); + VDNamespaceItem *_findItemByObject(const VDNamespaceGroup *pGroup, const void *pObj); + bool _getPathByItem(const VDNamespaceNode *pEntry, char *buf, int maxlen); + +public: + + VDNamespace(); + ~VDNamespace(); + + typedef bool (*tGroupEnumerator)(VDNamespace *pThis, const char *pszName, const VDNamespaceGroup *pGroup, void *pvData); + typedef bool (*tItemEnumerator)(VDNamespace *pThis, const char *pszName, const void *pItem, void *pvData); + + void clear(); + void add(const char *pszGroup, const char *pszName, const void *pDef); + const void *lookup(const char *pszName); + + bool enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData); + bool enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData); + + bool getPathByItem(const void *pObj, char *buf, int maxlen); +}; + +/////////////////////////////////////////////////////////////////////////// +// +// Templated Namespace class +// +/////////////////////////////////////////////////////////////////////////// + +template +class VDNamespace2 : public VDNamespace { +public: + VDNamespace2() {} + ~VDNamespace2() {} + + typedef bool (*tGroupEnumerator)(VDNamespace2 *pThis, const char *pszName, const VDNamespaceGroup *pGroup, void *pvData); + typedef bool (*tItemEnumerator)(VDNamespace2 *pThis, const char *pszName, const T *pItem, void *pvData); + + void add(const char *pszGroup, const char *pszName, const T *pDef) { + VDNamespace::add(pszGroup, pszName, pDef); + } + + const T *lookup(const char *pszName) { + return static_cast(VDNamespace::lookup(pszName)); + } + + bool enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData) { + for(ListAlloc::fwit it = (pGroupRoot ? pGroupRoot : &root)->listGroups.begin(); it; ++it) + if (!pEnum(this, it->pszName, it, pvData)) + return false; + + return true; + } + + bool enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData) { + for(ListAlloc::fwit it = (pGroupRoot ? pGroupRoot : &root)->listItems.begin(); it; ++it) + if (!pEnum(this, it->pszName, static_cast(it->object), pvData)) + return false; + + return true; + } + + bool getPathByItem(const T *pObj, char *buf, int maxlen) { + return VDNamespace::getPathByItem(pObj, buf, maxlen); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDQueue.h b/src/thirdparty/VirtualDub/h/vd2/system/VDQueue.h index ace02ae4e86..43367d287ae 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDQueue.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDQueue.h @@ -1,90 +1,90 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDQUEUE_H -#define f_VD2_SYSTEM_VDQUEUE_H - -#include - -template -class VDQueueNode : public ListNode2< VDQueueNode > { -public: - T t; - VDQueueNode(const T& t2) : t(t2) {} -}; - -template -class VDQueue { -public: - ListAlloc< VDQueueNode > list; - - VDQueue(); - ~VDQueue(); - T Pop(); - T Peek(); - void Push(const T&); - bool isEmpty() { return list.IsEmpty(); } -}; - -template -VDQueue::VDQueue() { -} - -template -VDQueue::~VDQueue() { - while(!list.IsEmpty()) - delete list.RemoveTail(); -} - -template -T VDQueue::Peek() { - return list.AtHead()->t; -} - -template -T VDQueue::Pop() { - return list.RemoveHead()->t; -} - -template -void VDQueue::Push(const T& t) { - list.AddTail(new VDQueueNode(t)); -} - -///////////// - -template -class VDQueueAlloc : public VDQueue { -public: - ~VDQueueAlloc(); -}; - -template -VDQueueAlloc::~VDQueueAlloc() { - for(ListAlloc< VDQueueNode >::fwit it = list.begin(); it; ++it) - delete &*it; -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDQUEUE_H +#define f_VD2_SYSTEM_VDQUEUE_H + +#include + +template +class VDQueueNode : public ListNode2< VDQueueNode > { +public: + T t; + VDQueueNode(const T& t2) : t(t2) {} +}; + +template +class VDQueue { +public: + ListAlloc< VDQueueNode > list; + + VDQueue(); + ~VDQueue(); + T Pop(); + T Peek(); + void Push(const T&); + bool isEmpty() { return list.IsEmpty(); } +}; + +template +VDQueue::VDQueue() { +} + +template +VDQueue::~VDQueue() { + while(!list.IsEmpty()) + delete list.RemoveTail(); +} + +template +T VDQueue::Peek() { + return list.AtHead()->t; +} + +template +T VDQueue::Pop() { + return list.RemoveHead()->t; +} + +template +void VDQueue::Push(const T& t) { + list.AddTail(new VDQueueNode(t)); +} + +///////////// + +template +class VDQueueAlloc : public VDQueue { +public: + ~VDQueueAlloc(); +}; + +template +VDQueueAlloc::~VDQueueAlloc() { + for(ListAlloc< VDQueueNode >::fwit it = list.begin(); it; ++it) + delete &*it; +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDRingBuffer.h b/src/thirdparty/VirtualDub/h/vd2/system/VDRingBuffer.h index cd05ff1690f..c564cd7f9c8 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDRingBuffer.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDRingBuffer.h @@ -1,301 +1,301 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_SYSTEM_VDRINGBUFFER_H -#define f_SYSTEM_VDRINGBUFFER_H - -#include -#include - -#include - -class VDRingBufferBase { -public: - VDRingBufferBase() - : nSize(0) - , nReadPoint(0) - , nWritePoint(0) - { - } - - int getSize() const { return nSize; } - int getReadOffset() const { return nReadPoint; } - int getWriteOffset() const { return nWritePoint; } - -protected: - int nSize; - int nReadPoint; - int nWritePoint; -}; - -template > -class VDRingBuffer : public VDRingBufferBase, private Allocator { -protected: - T *pBuffer; - VDAtomicInt nLevel; - -public: - VDRingBuffer(); - VDRingBuffer(int size); - ~VDRingBuffer(); - - void Init(int size); - void Shutdown(); - - int getLevel() const { return nLevel; } - int getSpace() const { return nSize - nLevel; } - int getWriteSpace() const; - T * getWritePtr() const { return pBuffer+nWritePoint; } - - int size() const { return nSize; } - bool empty() const { return !nLevel; } - bool full() const { return nLevel == nSize; } - - void Flush() { nReadPoint = nWritePoint = nLevel = 0; } - - int Read(T *pBuffer, int bytes); - const T *LockRead(int requested, int& actual); - const T *LockReadAll(int& actual); - const T *LockReadWrapped(int requested, int& actual, int& nReadPoint); - const T *LockReadAllWrapped(int& actual, int& nReadPoint); - int UnlockRead(int actual); - - int Write(const T *pData, int bytes); - T *LockWrite(int requested, int& actual); - T *LockWriteAll(int& actual); - int UnlockWrite(int actual); -}; - -template -VDRingBuffer::VDRingBuffer(int size) - : pBuffer(NULL) -{ - Init(size); -} - -template -VDRingBuffer::VDRingBuffer() - : pBuffer(NULL) - , nLevel(0) -{ -} - -template -VDRingBuffer::~VDRingBuffer() { - Shutdown(); -} - -template -void VDRingBuffer::Init(int size) { - Shutdown(); - pBuffer = Allocator::allocate(nSize = size, 0); - nLevel = 0; - nReadPoint = 0; - nWritePoint = 0; -} - -template -void VDRingBuffer::Shutdown() { - if (pBuffer) { - Allocator::deallocate(pBuffer, nSize); - pBuffer = NULL; - } -} - -template -int VDRingBuffer::getWriteSpace() const { - volatile int tc = nSize - nWritePoint; - volatile int space = nSize - nLevel; - - if (tc > space) - tc = space; - - return tc; -} - -template -int VDRingBuffer::Read(T *pBuffer, int units) { - VDASSERT(units >= 0); - - int actual = 0; - const T *pSrc; - - while(units) { - int tc; - - pSrc = LockRead(units, tc); - - if (!tc) - break; - - memcpy(pBuffer, pSrc, tc * sizeof(T)); - - UnlockRead(tc); - - actual += tc; - units -= tc; - pBuffer += tc; - } - - return actual; -} - -template -const T *VDRingBuffer::LockRead(int requested, int& actual) { - VDASSERT(requested >= 0); - - int nLevelNow = nLevel; - - if (requested > nLevelNow) - requested = nLevelNow; - - if (requested + nReadPoint > nSize) - requested = nSize - nReadPoint; - - actual = requested; - - return pBuffer + nReadPoint; -} - -template -const T *VDRingBuffer::LockReadAll(int& actual) { - int requested = nLevel; - - if (requested + nReadPoint > nSize) - requested = nSize - nReadPoint; - - actual = requested; - - return pBuffer + nReadPoint; -} - -template -const T *VDRingBuffer::LockReadWrapped(int requested, int& actual, int& readpt) { - int nLevelNow = nLevel; - - if (requested > nLevelNow) - requested = nLevelNow; - - actual = requested; - readpt = nReadPoint; - - return pBuffer; -} - -template -const T *VDRingBuffer::LockReadAllWrapped(int& actual, int& readpt) { - int requested = nLevel; - - actual = requested; - readpt = nReadPoint; - - return pBuffer; -} - -template -int VDRingBuffer::UnlockRead(int actual) { - VDASSERT(actual >= 0); - VDASSERT(nLevel >= actual); - - int newpt = nReadPoint + actual; - - if (newpt >= nSize) - newpt -= nSize; - - nReadPoint = newpt; - - return nLevel.add(-actual); -} - -template -int VDRingBuffer::Write(const T *src, int elements) { - VDASSERT(elements >= 0); - - int actual = 0; - while(elements) { - int tc; - void *dst = LockWrite(elements, tc); - - if (!tc) - break; - - memcpy(dst, src, tc*sizeof(T)); - - UnlockWrite(tc); - - actual += tc; - elements -= tc; - src += tc; - } - - return actual; -} - -template -T *VDRingBuffer::LockWrite(int requested, int& actual) { - VDASSERT(requested >= 0); - int nLevelNow = nSize - nLevel; - - if (requested > nLevelNow) - requested = nLevelNow; - - if (requested + nWritePoint > nSize) - requested = nSize - nWritePoint; - - actual = requested; - - return pBuffer + nWritePoint; -} - -template -T *VDRingBuffer::LockWriteAll(int& actual) { - int requested = nSize - nLevel; - - if (requested + nWritePoint > nSize) - requested = nSize - nWritePoint; - - actual = requested; - - return pBuffer + nWritePoint; -} - -template -int VDRingBuffer::UnlockWrite(int actual) { - VDASSERT(actual >= 0); - VDASSERT(nLevel + actual <= nSize); - - int newpt = nWritePoint + actual; - - if (newpt >= nSize) - newpt = 0; - - nWritePoint = newpt; - - return nLevel.add(actual); -} - - - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_SYSTEM_VDRINGBUFFER_H +#define f_SYSTEM_VDRINGBUFFER_H + +#include +#include + +#include + +class VDRingBufferBase { +public: + VDRingBufferBase() + : nSize(0) + , nReadPoint(0) + , nWritePoint(0) + { + } + + int getSize() const { return nSize; } + int getReadOffset() const { return nReadPoint; } + int getWriteOffset() const { return nWritePoint; } + +protected: + int nSize; + int nReadPoint; + int nWritePoint; +}; + +template > +class VDRingBuffer : public VDRingBufferBase, private Allocator { +protected: + T *pBuffer; + VDAtomicInt nLevel; + +public: + VDRingBuffer(); + VDRingBuffer(int size); + ~VDRingBuffer(); + + void Init(int size); + void Shutdown(); + + int getLevel() const { return nLevel; } + int getSpace() const { return nSize - nLevel; } + int getWriteSpace() const; + T * getWritePtr() const { return pBuffer+nWritePoint; } + + int size() const { return nSize; } + bool empty() const { return !nLevel; } + bool full() const { return nLevel == nSize; } + + void Flush() { nReadPoint = nWritePoint = nLevel = 0; } + + int Read(T *pBuffer, int bytes); + const T *LockRead(int requested, int& actual); + const T *LockReadAll(int& actual); + const T *LockReadWrapped(int requested, int& actual, int& nReadPoint); + const T *LockReadAllWrapped(int& actual, int& nReadPoint); + int UnlockRead(int actual); + + int Write(const T *pData, int bytes); + T *LockWrite(int requested, int& actual); + T *LockWriteAll(int& actual); + int UnlockWrite(int actual); +}; + +template +VDRingBuffer::VDRingBuffer(int size) + : pBuffer(NULL) +{ + Init(size); +} + +template +VDRingBuffer::VDRingBuffer() + : pBuffer(NULL) + , nLevel(0) +{ +} + +template +VDRingBuffer::~VDRingBuffer() { + Shutdown(); +} + +template +void VDRingBuffer::Init(int size) { + Shutdown(); + pBuffer = Allocator::allocate(nSize = size, 0); + nLevel = 0; + nReadPoint = 0; + nWritePoint = 0; +} + +template +void VDRingBuffer::Shutdown() { + if (pBuffer) { + Allocator::deallocate(pBuffer, nSize); + pBuffer = NULL; + } +} + +template +int VDRingBuffer::getWriteSpace() const { + volatile int tc = nSize - nWritePoint; + volatile int space = nSize - nLevel; + + if (tc > space) + tc = space; + + return tc; +} + +template +int VDRingBuffer::Read(T *pBuffer, int units) { + VDASSERT(units >= 0); + + int actual = 0; + const T *pSrc; + + while(units) { + int tc; + + pSrc = LockRead(units, tc); + + if (!tc) + break; + + memcpy(pBuffer, pSrc, tc * sizeof(T)); + + UnlockRead(tc); + + actual += tc; + units -= tc; + pBuffer += tc; + } + + return actual; +} + +template +const T *VDRingBuffer::LockRead(int requested, int& actual) { + VDASSERT(requested >= 0); + + int nLevelNow = nLevel; + + if (requested > nLevelNow) + requested = nLevelNow; + + if (requested + nReadPoint > nSize) + requested = nSize - nReadPoint; + + actual = requested; + + return pBuffer + nReadPoint; +} + +template +const T *VDRingBuffer::LockReadAll(int& actual) { + int requested = nLevel; + + if (requested + nReadPoint > nSize) + requested = nSize - nReadPoint; + + actual = requested; + + return pBuffer + nReadPoint; +} + +template +const T *VDRingBuffer::LockReadWrapped(int requested, int& actual, int& readpt) { + int nLevelNow = nLevel; + + if (requested > nLevelNow) + requested = nLevelNow; + + actual = requested; + readpt = nReadPoint; + + return pBuffer; +} + +template +const T *VDRingBuffer::LockReadAllWrapped(int& actual, int& readpt) { + int requested = nLevel; + + actual = requested; + readpt = nReadPoint; + + return pBuffer; +} + +template +int VDRingBuffer::UnlockRead(int actual) { + VDASSERT(actual >= 0); + VDASSERT(nLevel >= actual); + + int newpt = nReadPoint + actual; + + if (newpt >= nSize) + newpt -= nSize; + + nReadPoint = newpt; + + return nLevel.add(-actual); +} + +template +int VDRingBuffer::Write(const T *src, int elements) { + VDASSERT(elements >= 0); + + int actual = 0; + while(elements) { + int tc; + void *dst = LockWrite(elements, tc); + + if (!tc) + break; + + memcpy(dst, src, tc*sizeof(T)); + + UnlockWrite(tc); + + actual += tc; + elements -= tc; + src += tc; + } + + return actual; +} + +template +T *VDRingBuffer::LockWrite(int requested, int& actual) { + VDASSERT(requested >= 0); + int nLevelNow = nSize - nLevel; + + if (requested > nLevelNow) + requested = nLevelNow; + + if (requested + nWritePoint > nSize) + requested = nSize - nWritePoint; + + actual = requested; + + return pBuffer + nWritePoint; +} + +template +T *VDRingBuffer::LockWriteAll(int& actual) { + int requested = nSize - nLevel; + + if (requested + nWritePoint > nSize) + requested = nSize - nWritePoint; + + actual = requested; + + return pBuffer + nWritePoint; +} + +template +int VDRingBuffer::UnlockWrite(int actual) { + VDASSERT(actual >= 0); + VDASSERT(nLevel + actual <= nSize); + + int newpt = nWritePoint + actual; + + if (newpt >= nSize) + newpt = 0; + + nWritePoint = newpt; + + return nLevel.add(actual); +} + + + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDScheduler.h b/src/thirdparty/VirtualDub/h/vd2/system/VDScheduler.h index cd2674aaab0..4a685e25a68 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDScheduler.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDScheduler.h @@ -1,147 +1,147 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSCHEDULER_H -#define f_VD2_SYSTEM_VDSCHEDULER_H - -#include -#include -#include - -class VDSchedulerNode; -class VDSchedulerSuspendNode; -class VDSignal; -class IVDAsyncErrorCallback; - -class VDScheduler { -public: - VDScheduler(); - ~VDScheduler(); - - void setSignal(VDSignal *); - VDSignal *getSignal() { return pWakeupSignal; } - void setSchedulerNode(VDSchedulerNode *pSchedulerNode); - - IVDAsyncErrorCallback *getErrorCallback() const { return mpErrorCB; } - void setErrorCallback(IVDAsyncErrorCallback *pCB) { mpErrorCB = pCB; } - - bool isShuttingDown() const { return mbExitThreads; } - - void BeginShutdown(); ///< Start signaling scheduling threads to exit. - - bool Run(); - bool IdleWait(); ///< Wait because no nodes are ready. Returns false if a thread should exit immediately. - void Ping(); ///< Restart a scheduler thread. This is required when a scheduler thread leaves. - void Lock(); - void Unlock(); - void Reschedule(VDSchedulerNode *); ///< Move node to Ready if Waiting. - void RescheduleFast(VDSchedulerNode *); ///< Same as Reschedule(), but assumes the scheduler is already locked. - void Add(VDSchedulerNode *pNode); ///< Add node to scheduler. - void Remove(VDSchedulerNode *pNode); ///< Remove node from scheduler. - void DumpStatus(); - -protected: - void Repost(VDSchedulerNode *, bool); - - VDCriticalSection csScheduler; - IVDAsyncErrorCallback *mpErrorCB; - VDSignal *pWakeupSignal; - volatile bool mbExitThreads; - VDSchedulerNode *pParentSchedulerNode; - - typedef vdlist tNodeList; - tNodeList listWaiting, listReady; - - typedef vdlist tSuspendList; - tSuspendList listSuspends; -}; - -class VDSchedulerNode : public vdlist::node { -friend class VDScheduler; -public: - int nPriority; - - VDSchedulerNode() : nPriority(0), mpScheduler(NULL) {} - - virtual bool Service()=0; - - virtual void DumpStatus(); - - void Reschedule() { mpScheduler->Reschedule(this); } - void RemoveFromScheduler() { mpScheduler->Remove(this); } - -protected: - VDScheduler *mpScheduler; - volatile bool bRunning; - volatile bool bReschedule; - volatile bool bReady; - volatile bool bCondemned; -}; - -class VDSchedulerSuspendNode : public vdlist::node { -public: - VDSchedulerSuspendNode(VDSchedulerNode *pNode) : mpNode(pNode) {} - - VDSchedulerNode *mpNode; - VDSignal mSignal; -}; - -class VDSchedulerThread : public VDThread { - VDSchedulerThread(const VDSchedulerThread&); - VDSchedulerThread& operator=(const VDSchedulerThread&); -public: - VDSchedulerThread(); - ~VDSchedulerThread(); - - bool Start(VDScheduler *pScheduler); - -protected: - void ThreadRun(); - - VDScheduler *mpScheduler; - uint32 mAffinity; -}; - -class VDSchedulerThreadPool { - VDSchedulerThreadPool(const VDSchedulerThreadPool&); - VDSchedulerThreadPool& operator=(const VDSchedulerThreadPool&); -public: - VDSchedulerThreadPool(); - ~VDSchedulerThreadPool(); - - uint32 GetThreadCount() const { return mThreadCount; } - - void SetPriority(int priority); - - bool Start(VDScheduler *pScheduler); - bool Start(VDScheduler *pScheduler, uint32 threadCount); - -protected: - VDSchedulerThread *mpThreads; - uint32 mThreadCount; - int mThreadPriority; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSCHEDULER_H +#define f_VD2_SYSTEM_VDSCHEDULER_H + +#include +#include +#include + +class VDSchedulerNode; +class VDSchedulerSuspendNode; +class VDSignal; +class IVDAsyncErrorCallback; + +class VDScheduler { +public: + VDScheduler(); + ~VDScheduler(); + + void setSignal(VDSignal *); + VDSignal *getSignal() { return pWakeupSignal; } + void setSchedulerNode(VDSchedulerNode *pSchedulerNode); + + IVDAsyncErrorCallback *getErrorCallback() const { return mpErrorCB; } + void setErrorCallback(IVDAsyncErrorCallback *pCB) { mpErrorCB = pCB; } + + bool isShuttingDown() const { return mbExitThreads; } + + void BeginShutdown(); ///< Start signaling scheduling threads to exit. + + bool Run(); + bool IdleWait(); ///< Wait because no nodes are ready. Returns false if a thread should exit immediately. + void Ping(); ///< Restart a scheduler thread. This is required when a scheduler thread leaves. + void Lock(); + void Unlock(); + void Reschedule(VDSchedulerNode *); ///< Move node to Ready if Waiting. + void RescheduleFast(VDSchedulerNode *); ///< Same as Reschedule(), but assumes the scheduler is already locked. + void Add(VDSchedulerNode *pNode); ///< Add node to scheduler. + void Remove(VDSchedulerNode *pNode); ///< Remove node from scheduler. + void DumpStatus(); + +protected: + void Repost(VDSchedulerNode *, bool); + + VDCriticalSection csScheduler; + IVDAsyncErrorCallback *mpErrorCB; + VDSignal *pWakeupSignal; + volatile bool mbExitThreads; + VDSchedulerNode *pParentSchedulerNode; + + typedef vdlist tNodeList; + tNodeList listWaiting, listReady; + + typedef vdlist tSuspendList; + tSuspendList listSuspends; +}; + +class VDSchedulerNode : public vdlist::node { +friend class VDScheduler; +public: + int nPriority; + + VDSchedulerNode() : nPriority(0), mpScheduler(NULL) {} + + virtual bool Service()=0; + + virtual void DumpStatus(); + + void Reschedule() { mpScheduler->Reschedule(this); } + void RemoveFromScheduler() { mpScheduler->Remove(this); } + +protected: + VDScheduler *mpScheduler; + volatile bool bRunning; + volatile bool bReschedule; + volatile bool bReady; + volatile bool bCondemned; +}; + +class VDSchedulerSuspendNode : public vdlist::node { +public: + VDSchedulerSuspendNode(VDSchedulerNode *pNode) : mpNode(pNode) {} + + VDSchedulerNode *mpNode; + VDSignal mSignal; +}; + +class VDSchedulerThread : public VDThread { + VDSchedulerThread(const VDSchedulerThread&); + VDSchedulerThread& operator=(const VDSchedulerThread&); +public: + VDSchedulerThread(); + ~VDSchedulerThread(); + + bool Start(VDScheduler *pScheduler); + +protected: + void ThreadRun(); + + VDScheduler *mpScheduler; + uint32 mAffinity; +}; + +class VDSchedulerThreadPool { + VDSchedulerThreadPool(const VDSchedulerThreadPool&); + VDSchedulerThreadPool& operator=(const VDSchedulerThreadPool&); +public: + VDSchedulerThreadPool(); + ~VDSchedulerThreadPool(); + + uint32 GetThreadCount() const { return mThreadCount; } + + void SetPriority(int priority); + + bool Start(VDScheduler *pScheduler); + bool Start(VDScheduler *pScheduler, uint32 threadCount); + +protected: + VDSchedulerThread *mpThreads; + uint32 mThreadCount; + int mThreadPriority; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/VDString.h b/src/thirdparty/VirtualDub/h/vd2/system/VDString.h index 01ec217df69..997b3964221 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/VDString.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/VDString.h @@ -1,1264 +1,1264 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTRING_H -#define f_VD2_SYSTEM_VDSTRING_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -class VDStringSpanA { -public: - typedef char value_type; - typedef uint32 size_type; - typedef ptrdiff_t difference_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type * pointer; - typedef const value_type * const_pointer; - typedef pointer iterator; - typedef const_pointer const_iterator; - - static const size_type npos = (size_type)-1; - - VDStringSpanA() - : mpBegin(const_cast(sNull)) - , mpEnd(const_cast(sNull)) - { - } - - explicit VDStringSpanA(const value_type *s) - : mpBegin(const_cast(s)) - , mpEnd(const_cast(s) + strlen(s)) - { - } - - VDStringSpanA(const value_type *s, const value_type *t) - : mpBegin(const_cast(s)) - , mpEnd(const_cast(t)) - { - } - - // 21.3.2 iterators - const_iterator begin() const { return mpBegin; } - const_iterator end() const { return mpEnd; } - - // 21.3.3 capacity - size_type size() const { return (size_type)(mpEnd - mpBegin); } - size_type length() const { return (size_type)(mpEnd - mpBegin); } - bool empty() const { return mpBegin == mpEnd; } - - // 21.3.4 element access - const_reference operator[](size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - const_reference at(size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - - const_reference front() const { VDASSERT(mpBegin != mpEnd); return *mpBegin; } - const_reference back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } - - // 21.3.6 string operations - const_pointer data() const { return mpBegin; } - - size_type copy(value_type *dst, size_type n, size_type pos = 0) const { - size_type len = (size_type)(mpEnd - mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - memcpy(dst, mpBegin + pos, n*sizeof(value_type)); - return n; - } - - size_type find(value_type c, size_type pos = 0) const { - VDASSERT(pos <= (size_type)(mpEnd - mpBegin)); - const void *p = memchr(mpBegin + pos, c, mpEnd - (mpBegin + pos)); - - return p ? (size_type)((const value_type *)p - mpBegin) : npos; - } - - size_type find_last_of(value_type c) const { - const value_type *s = mpEnd; - - while(s != mpBegin) { - --s; - - if (*s == c) - return (size_type)(s - mpBegin); - } - - return npos; - } - - int compare(const VDStringSpanA& s) const { - size_type l1 = (size_type)(mpEnd - mpBegin); - size_type l2 = (size_type)(s.mpEnd - s.mpBegin); - size_type lm = l1 < l2 ? l1 : l2; - - int r = memcmp(mpBegin, s.mpBegin, lm); - - if (!r && l1 != l2) - r = (int)mpBegin[lm] - (int)s.mpBegin[lm]; - - return r; - } - - int comparei(const char *s) const { - return comparei(VDStringSpanA(s)); - } - - int comparei(const VDStringSpanA& s) const { - size_type l1 = (size_type)(mpEnd - mpBegin); - size_type l2 = (size_type)(s.mpEnd - s.mpBegin); - size_type lm = l1 < l2 ? l1 : l2; - - const char *p = mpBegin; - const char *q = s.mpBegin; - - while(lm--) { - const unsigned char c = tolower((unsigned char)*p++); - const unsigned char d = tolower((unsigned char)*q++); - - if (c != d) - return (int)c - (int)d; - } - - return (int)l1 - (int)l2; - } - - const VDStringSpanA trim(const value_type *s) const { - bool flags[256]={false}; - - while(value_type c = *s++) - flags[(unsigned char)c] = true; - - const value_type *p = mpBegin; - const value_type *q = mpEnd; - - while(p != q && flags[*p]) - ++p; - - while(p != q && flags[q[-1]]) - --q; - - return VDStringSpanA(p, q); - } - - const VDStringSpanA subspan(size_type pos = 0, size_type n = npos) const { - - size_type len = (size_type)(mpEnd - mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - value_type *p = mpBegin + pos; - return VDStringSpanA(p, p+n); - } - -protected: - friend bool operator==(const VDStringSpanA& x, const VDStringSpanA& y); - friend bool operator==(const VDStringSpanA& x, const char *y); - - value_type *mpBegin; - value_type *mpEnd; - - static const value_type sNull[1]; -}; - -inline bool operator==(const VDStringSpanA& x, const VDStringSpanA& y) { VDStringSpanA::size_type len = (VDStringSpanA::size_type)(x.mpEnd - x.mpBegin); return len == (VDStringSpanA::size_type)(y.mpEnd - y.mpBegin) && !memcmp(x.mpBegin, y.mpBegin, len*sizeof(char)); } -inline bool operator==(const VDStringSpanA& x, const char *y) { size_t len = strlen(y); return len == (size_t)(x.mpEnd - x.mpBegin) && !memcmp(x.mpBegin, y, len*sizeof(char)); } -inline bool operator==(const char *x, const VDStringSpanA& y) { return y == x; } - -inline bool operator!=(const VDStringSpanA& x, const VDStringSpanA& y) { return !(x == y); } -inline bool operator!=(const VDStringSpanA& x, const char *y) { return !(x == y); } -inline bool operator!=(const char *x, const VDStringSpanA& y) { return !(y == x); } - -inline bool operator<(const VDStringSpanA& x, const VDStringSpanA& y) { - return x.compare(y) < 0; -} - -inline bool operator>(const VDStringSpanA& x, const VDStringSpanA& y) { - return x.compare(y) > 0; -} - -inline bool operator<=(const VDStringSpanA& x, const VDStringSpanA& y) { - return x.compare(y) <= 0; -} - -inline bool operator>=(const VDStringSpanA& x, const VDStringSpanA& y) { - return x.compare(y) >= 0; -} - -class VDStringRefA : public VDStringSpanA { -public: - typedef VDStringRefA this_type; - - VDStringRefA() { - } - - explicit VDStringRefA(const value_type *s) - : VDStringSpanA(s) - { - } - - explicit VDStringRefA(const VDStringSpanA& s) - : VDStringSpanA(s) - { - } - - VDStringRefA(const value_type *s, const value_type *t) - : VDStringSpanA(s, t) - { - } - - this_type& operator=(const value_type *s) { - assign(s); - return *this; - } - - this_type& operator=(const VDStringSpanA& str) { - assign(str); - return *this; - } - - void assign(const value_type *s) { - static_cast(*this) = VDStringSpanA(s); - } - - void assign(const value_type *s, const value_type *t) { - static_cast(*this) = VDStringSpanA(s, t); - } - - void assign(const VDStringSpanA& s) { - static_cast(*this) = s; - } - - void clear() { - mpBegin = mpEnd = NULL; - } - - bool split(value_type c, VDStringRefA& token) { - size_type pos = find(c); - - if (pos == npos) - return false; - - token = subspan(0, pos); - mpBegin += pos+1; - return true; - } -}; - -class VDStringA : public VDStringSpanA { -public: - typedef VDStringA this_type; - - // 21.3.1 construct/copy/destroy - - VDStringA() - : mpEOS(const_cast(sNull)) - { - } - - VDStringA(const VDStringSpanA& x) - : mpEOS(const_cast(sNull)) - { - assign(x.begin(), x.end()); - } - - VDStringA(const this_type& x) - : mpEOS(const_cast(sNull)) - { - assign(x); - } - - explicit VDStringA(const value_type *s) - : mpEOS(const_cast(sNull)) - { - assign(s); - } - - explicit VDStringA(size_type n) - : mpEOS(const_cast(sNull)) - { - resize(n); - } - - VDStringA(const value_type *s, size_type n) - : mpEOS(const_cast(sNull)) - { - assign(s, n); - } - - VDStringA(const value_type *s, const value_type *t) - : mpEOS(const_cast(sNull)) - { - assign(s, t); - } - - ~VDStringA() { - if (mpBegin != sNull) - delete[] mpBegin; - } - - this_type& operator=(const value_type *s) { - assign(s); - return *this; - } - - this_type& operator=(const this_type& str) { - assign(str); - return *this; - } - - this_type& operator=(const VDStringSpanA& str) { - assign(str); - return *this; - } - - // 21.3.2 iterators - using VDStringSpanA::begin; - using VDStringSpanA::end; - - iterator begin() { return mpBegin; } - iterator end() { return mpEnd; } - - // 21.3.3 capacity (COMPLETE) - void resize(size_type n) { - size_type current = (size_type)(mpEnd - mpBegin); - - if (n < current) { - mpEnd = mpBegin + n; - mpEnd[0] = 0; - } else if (n > current) - resize_slow(n, current); - } - - void resize(size_type n, value_type v) { - size_type current = (size_type)(mpEnd - mpBegin); - - if (n < current) { - mpEnd = mpBegin + n; - mpEnd[0] = 0; - } else if (n > current) - resize_slow(n, current, v); - } - - size_type capacity() const { return (size_type)(mpEOS - mpBegin); } - - void reserve(size_type n) { - size_type current = (size_type)(mpEOS - mpBegin); - - if (n > current) - reserve_slow(n, current); - } - - void clear() { - if (mpEnd != mpBegin) { - mpEnd = mpBegin; - mpEnd[0] = 0; - } - } - - // 21.3.4 element access - using VDStringSpanA::operator[]; - using VDStringSpanA::at; - using VDStringSpanA::front; - using VDStringSpanA::back; - - reference operator[](size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - reference at(size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - reference front() { VDASSERT(mpBegin != mpEnd); return *mpBegin; } - reference back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } - - // 21.3.5 modifiers - this_type& operator+=(const this_type& str) { - return append(str.mpBegin, str.mpEnd); - } - - this_type& operator+=(const value_type *s) { - return append(s, s+strlen(s)); - } - - this_type& operator+=(value_type c) { - if (mpEnd == mpEOS) - push_back_extend(); - - *mpEnd++ = c; - *mpEnd = 0; - return *this; - } - - this_type& append(const this_type& str) { - return append(str.mpBegin, str.mpEnd); - } - - this_type& append(const this_type& str, size_type pos, size_type n) { - size_type len = (size_type)(str.mpEnd - str.mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - return append(str.mpBegin + pos, str.mpBegin + pos + n); - } - - this_type& append(const value_type *s, size_type n) { - return append(s, s+n); - } - - this_type& append(const value_type *s) { - return append(s, s+strlen(s)); - } - - this_type& append(const value_type *s, const value_type *t) { - if (s != t) { - size_type current_size = (size_type)(mpEnd - mpBegin); - size_type current_capacity = (size_type)(mpEOS - mpBegin); - size_type n = (size_type)(t - s); - - if (current_capacity - current_size < n) - reserve_amortized_slow(n, current_size, current_capacity); - - memcpy(mpBegin + current_size, s, n*sizeof(value_type)); - mpEnd += n; - *mpEnd = 0; - } - return *this; - } - - void push_back(const value_type c) { - if (mpEnd == mpEOS) - push_back_extend(); - - *mpEnd++ = c; - *mpEnd = 0; - } - - void pop_back() { - --mpEnd; - *mpEnd = 0; - } - - this_type& assign(const VDStringSpanA& str) { - return assign(str.begin(), str.end()); - } - - this_type& assign(const this_type& str) { - return assign(str.mpBegin, str.mpEnd); - } - - this_type& assign(const this_type& str, size_type pos, size_type n) { - size_type len = (size_type)(str.mpEnd - str.mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - return assign(str.mpBegin + pos, str.mpBegin + pos + n); - } - - this_type& assign(const value_type *s, size_type n) { - return assign(s, s+n); - } - - this_type& assign(const value_type *s) { - return assign(s, s+strlen(s)); - } - - this_type& assign(size_type n, value_type c) { - size_type current_capacity = (size_type)(mpEOS - mpBegin); - - if (current_capacity < n) - reserve_slow(n, current_capacity); - - if (mpBegin != sNull) { - mpEnd = mpBegin; - while(n--) - *mpEnd++ = c; - } - - return *this; - } - - this_type& assign(const value_type *s, const value_type *t) { - size_type current_capacity = (size_type)(mpEOS - mpBegin); - size_type n = (size_type)(t - s); - - if (current_capacity < n) - reserve_slow(n, current_capacity); - - if (mpBegin != sNull) { - memcpy(mpBegin, s, sizeof(value_type)*n); - mpEnd = mpBegin + n; - *mpEnd = 0; - } - - return *this; - } - - this_type& insert(iterator it, value_type c) { - if (mpEnd == mpEOS) { - size_type pos = (size_type)(it - mpBegin); - push_back_extend(); - it = mpBegin + pos; - } - - memmove(it + 1, it, (mpEnd - it + 1)*sizeof(value_type)); - *it = c; - ++mpEnd; - return *this; - } - - this_type& erase(size_type pos = 0, size_type n = npos) { - size_type len = (size_type)(mpEnd - mpBegin); - - VDASSERT(pos <= len); - len -= pos; - if (n > len) - n = len; - - if (n) { - size_type pos2 = pos + n; - memmove(mpBegin + pos, mpBegin + pos2, (len + 1 - n)*sizeof(value_type)); - mpEnd -= n; - } - - return *this; - } - - iterator erase(iterator x) { - VDASSERT(x != mpEnd); - - memmove(x, x+1, (mpEnd - x)*sizeof(value_type)); - --mpEnd; - return x; - } - - iterator erase(iterator first, iterator last) { - VDASSERT(last >= first); - - memmove(first, last, ((mpEnd - last) + 1)*sizeof(value_type)); - mpEnd -= (last - first); - return first; - } - - this_type& replace(size_type pos, size_type n1, const value_type *s, size_type n2) { - size_type len = (size_type)(mpEnd - mpBegin); - - VDASSERT(pos <= len); - size_type limit = len - pos; - if (n1 > limit) - n1 = limit; - - size_type len2 = len - n1 + n2; - size_type current_capacity = (size_type)(mpEOS - mpBegin); - - if (current_capacity < len2) - reserve_slow(len2, current_capacity); - - memmove(mpBegin + pos + n2, mpBegin + pos + n1, (limit - n1 + 1) * sizeof(value_type)); - memcpy(mpBegin + pos, s, n2*sizeof(value_type)); - mpEnd = mpBegin + len2; - return *this; - } - - void swap(this_type& x) { - value_type *p; - - p = mpBegin; mpBegin = x.mpBegin; x.mpBegin = p; - p = mpEnd; mpEnd = x.mpEnd; x.mpEnd = p; - p = mpEOS; mpEOS = x.mpEOS; x.mpEOS = p; - } - - // 21.3.6 string operations - const_pointer c_str() const { return mpBegin; } - - this_type& sprintf(const value_type *format, ...); - this_type& append_sprintf(const value_type *format, ...); - this_type& append_vsprintf(const value_type *format, va_list val); - - void move_from(VDStringA& src); - -protected: - void push_back_extend(); - void resize_slow(size_type n, size_type current_size); - void resize_slow(size_type n, size_type current_size, value_type c); - void reserve_slow(size_type n, size_type current_capacity); - void reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity); - - char *mpEOS; -}; - -/////////////////////////////////////////////////////////////////////////// - -inline VDStringA operator+(const VDStringA& str, const VDStringA& s) { - VDStringA result; - result.reserve((VDStringA::size_type)(str.size() + s.size())); - result.assign(str); - result.append(s); - return result; -} - -inline VDStringA operator+(const VDStringA& str, const char *s) { - VDStringA result; - result.reserve((VDStringA::size_type)(str.size() + strlen(s))); - result.assign(str); - result.append(s); - return result; -} - -inline VDStringA operator+(const VDStringA& str, char c) { - VDStringA result; - result.reserve(str.size() + 1); - result.assign(str); - result += c; - return result; -} - -// Start patch MPC-HC -/* -namespace std { - template<> - struct less : binary_function { - bool operator()(const VDStringA& x, const VDStringA& y) const { - return x.compare(y) < 0; - } - }; -} -*/ -// End patch MPC-HC - -/////////////////////////////////////////////////////////////////////////// - -class VDStringSpanW { -public: - typedef wchar_t value_type; - typedef uint32 size_type; - typedef ptrdiff_t difference_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type * pointer; - typedef const value_type * const_pointer; - typedef pointer iterator; - typedef const_pointer const_iterator; - - static const size_type npos = (size_type)-1; - - VDStringSpanW() - : mpBegin(const_cast(sNull)) - , mpEnd(const_cast(sNull)) - { - } - - explicit VDStringSpanW(const value_type *s) - : mpBegin(const_cast(s)) - , mpEnd(const_cast(s) + wcslen(s)) - { - } - - VDStringSpanW(const value_type *s, const value_type *t) - : mpBegin(const_cast(s)) - , mpEnd(const_cast(t)) - { - } - - // 21.3.2 iterators - const_iterator begin() const { return mpBegin; } - const_iterator end() const { return mpEnd; } - - // 21.3.3 capacity - size_type size() const { return (size_type)(mpEnd - mpBegin); } - size_type length() const { return (size_type)(mpEnd - mpBegin); } - bool empty() const { return mpBegin == mpEnd; } - - // 21.3.4 element access - const_reference operator[](size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - const_reference at(size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - - const_reference front() const { VDASSERT(mpBegin != mpEnd); return *mpBegin; } - const_reference back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } - - // 21.3.6 string operations - const_pointer data() const { return mpBegin; } - - size_type copy(value_type *dst, size_type n, size_type pos = 0) const { - size_type len = (size_type)(mpEnd - mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - memcpy(dst, mpBegin + pos, n*sizeof(value_type)); - return n; - } - - size_type find(value_type c, size_type pos = 0) const { - VDASSERT(pos <= (size_type)(mpEnd - mpBegin)); - const void *p = wmemchr(mpBegin + pos, c, mpEnd - (mpBegin + pos)); - - return p ? (size_type)((const value_type *)p - mpBegin) : npos; - } - - int compare(const VDStringSpanW& s) const { - size_type l1 = (size_type)(mpEnd - mpBegin); - size_type l2 = (size_type)(s.mpEnd - s.mpBegin); - size_type lm = l1 < l2 ? l1 : l2; - - for(size_type i = 0; i < lm; ++i) { - if (mpBegin[i] != s.mpBegin[i]) - return mpBegin[i] < s.mpBegin[i] ? -1 : +1; - } - - if (l1 == l2) - return 0; - - return l1 < l2 ? -1 : +1; - } - - int comparei(const wchar_t *s) const { - return comparei(VDStringSpanW(s)); - } - - int comparei(const VDStringSpanW& s) const { - size_type l1 = (size_type)(mpEnd - mpBegin); - size_type l2 = (size_type)(s.mpEnd - s.mpBegin); - size_type lm = l1 < l2 ? l1 : l2; - - for(size_type i = 0; i < lm; ++i) { - wint_t c = towlower(mpBegin[i]); - wint_t d = towlower(s.mpBegin[i]); - - if (c != d) - return c < d ? -1 : +1; - } - - if (l1 == l2) - return 0; - - return l1 < l2 ? -1 : +1; - } - - // extensions - const VDStringSpanW subspan(size_type pos, size_type n) const { - size_type len = (size_type)(mpEnd - mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - value_type *p = mpBegin + pos; - return VDStringSpanW(p, p+n); - } - -protected: - friend class VDStringW; - friend bool operator==(const VDStringSpanW& x, const VDStringSpanW& y); - friend bool operator==(const VDStringSpanW& x, const wchar_t *y); - - value_type *mpBegin; - value_type *mpEnd; - - static const value_type sNull[1]; -}; - -inline bool operator==(const VDStringSpanW& x, const VDStringSpanW& y) { VDStringA::size_type len = (VDStringSpanW::size_type)(x.mpEnd - x.mpBegin); return len == (VDStringSpanW::size_type)(y.mpEnd - y.mpBegin) && !memcmp(x.mpBegin, y.mpBegin, len*sizeof(wchar_t)); } -inline bool operator==(const VDStringSpanW& x, const wchar_t *y) { size_t len = wcslen(y); return len == (size_t)(x.mpEnd - x.mpBegin) && !memcmp(x.mpBegin, y, len*sizeof(wchar_t)); } -inline bool operator==(const wchar_t *x, const VDStringSpanW& y) { return y == x; } - -inline bool operator!=(const VDStringSpanW& x, const VDStringSpanW& y) { return !(x == y); } -inline bool operator!=(const VDStringSpanW& x, const wchar_t *y) { return !(x == y); } -inline bool operator!=(const wchar_t *x, const VDStringSpanW& y) { return !(y == x); } - -inline bool operator<(const VDStringSpanW& x, const VDStringSpanW& y) { - return x.compare(y) < 0; -} - -inline bool operator>(const VDStringSpanW& x, const VDStringSpanW& y) { - return x.compare(y) > 0; -} - -inline bool operator<=(const VDStringSpanW& x, const VDStringSpanW& y) { - return x.compare(y) <= 0; -} - -inline bool operator>=(const VDStringSpanW& x, const VDStringSpanW& y) { - return x.compare(y) >= 0; -} - -class VDStringRefW : public VDStringSpanW { -public: - typedef VDStringRefW this_type; - - VDStringRefW() { - } - - explicit VDStringRefW(const value_type *s) - : VDStringSpanW(s) - { - } - - explicit VDStringRefW(const VDStringSpanW& s) - : VDStringSpanW(s) - { - } - - VDStringRefW(const value_type *s, const value_type *t) - : VDStringSpanW(s, t) - { - } - - this_type& operator=(const value_type *s) { - assign(s); - return *this; - } - - this_type& operator=(const VDStringSpanW& str) { - assign(str); - return *this; - } - - void assign(const value_type *s) { - static_cast(*this) = VDStringSpanW(s); - } - - void assign(const value_type *s, const value_type *t) { - static_cast(*this) = VDStringSpanW(s, t); - } - - void assign(const VDStringSpanW& s) { - static_cast(*this) = s; - } - - void clear() { - mpBegin = mpEnd = NULL; - } - - bool split(value_type c, VDStringRefW& token) { - size_type pos = find(c); - - if (pos == npos) - return false; - - token = subspan(0, pos); - mpBegin += pos+1; - return true; - } -}; - -class VDStringW : public VDStringSpanW { -public: - typedef VDStringW this_type; - - // 21.3.1 construct/copy/destroy - - VDStringW() - : mpEOS(const_cast(sNull)) - { - } - - VDStringW(const VDStringSpanW& x) - : mpEOS(const_cast(sNull)) - { - assign(x.begin(), x.end()); - } - - VDStringW(const this_type& x) - : mpEOS(const_cast(sNull)) - { - assign(x); - } - - explicit VDStringW(const value_type *s) - : mpEOS(const_cast(sNull)) - { - assign(s); - } - - explicit VDStringW(size_type n) - : mpEOS(const_cast(sNull)) - { - resize(n); - } - - VDStringW(const value_type *s, size_type n) - : mpEOS(const_cast(sNull)) - { - assign(s, n); - } - - VDStringW(const value_type *s, const value_type *t) - : mpEOS(const_cast(sNull)) - { - assign(s, t); - } - - ~VDStringW() { - if (mpBegin != sNull) - delete[] mpBegin; - } - - this_type& operator=(const wchar_t *s) { - assign(s); - return *this; - } - - this_type& operator=(const this_type& str) { - assign(str); - return *this; - } - - // 21.3.2 iterators - using VDStringSpanW::begin; - using VDStringSpanW::end; - iterator begin() { return mpBegin; } - iterator end() { return mpEnd; } - - // 21.3.3 capacity (COMPLETE) - void resize(size_type n) { - size_type current = (size_type)(mpEnd - mpBegin); - - if (n < current) { - mpEnd = mpBegin + n; - mpEnd[0] = 0; - } else if (n > current) - resize_slow(n, current); - } - - void resize(size_type n, value_type v) { - size_type current = (size_type)(mpEnd - mpBegin); - - if (n < current) { - mpEnd = mpBegin + n; - mpEnd[0] = 0; - } else if (n > current) - resize_slow(n, current); - wmemset(mpBegin, v, n); - } - - size_type capacity() const { return (size_type)(mpEOS - mpBegin); } - - void reserve(size_type n) { - size_type current = (size_type)(mpEOS - mpBegin); - - if (n > current) - reserve_slow(n, current); - } - - void clear() { - if (mpEnd != mpBegin) { - mpEnd = mpBegin; - mpEnd[0] = 0; - } - } - - // 21.3.4 element access - using VDStringSpanW::operator[]; - using VDStringSpanW::at; - using VDStringSpanW::front; - using VDStringSpanW::back; - reference operator[](size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - reference at(size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } - reference front() { VDASSERT(mpBegin != mpEnd); return *mpBegin; } - reference back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } - - // 21.3.5 modifiers - this_type& operator+=(const this_type& str) { - return append(str.mpBegin, str.mpEnd); - } - - this_type& operator+=(const value_type *s) { - return append(s, s+wcslen(s)); - } - - this_type& operator+=(value_type c) { - if (mpEnd == mpEOS) - push_back_extend(); - - *mpEnd++ = c; - *mpEnd = 0; - return *this; - } - - this_type& append(const this_type& str) { - return append(str.mpBegin, str.mpEnd); - } - - this_type& append(const this_type& str, size_type pos, size_type n) { - size_type len = (size_type)(str.mpEnd - str.mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - return append(str.mpBegin + pos, str.mpBegin + pos + n); - } - - this_type& append(const value_type *s, size_type n) { - return append(s, s+n); - } - - this_type& append(const value_type *s) { - return append(s, s+wcslen(s)); - } - - this_type& append(const value_type *s, const value_type *t) { - if (s != t) { - size_type current_size = (size_type)(mpEnd - mpBegin); - size_type current_capacity = (size_type)(mpEOS - mpBegin); - size_type n = (size_type)(t - s); - - if (current_capacity - current_size < n) - reserve_amortized_slow(n, current_size, current_capacity); - - memcpy(mpBegin + current_size, s, n*sizeof(value_type)); - mpEnd += n; - *mpEnd = 0; - } - return *this; - } - - void push_back(const value_type c) { - if (mpEnd == mpEOS) - push_back_extend(); - - *mpEnd++ = c; - *mpEnd = 0; - } - - void pop_back() { - --mpEnd; - *mpEnd = 0; - } - - this_type& assign(const VDStringSpanW& str) { - return assign(str.mpBegin, str.mpEnd); - } - - this_type& assign(const VDStringSpanW& str, size_type pos, size_type n) { - size_type len = (size_type)(str.mpEnd - str.mpBegin); - VDASSERT(pos <= len); - - len -= pos; - if (n > len) - n = len; - - return assign(str.mpBegin + pos, str.mpBegin + pos + n); - } - - this_type& assign(const value_type *s, size_type n) { - return assign(s, s+n); - } - - this_type& assign(const value_type *s) { - return assign(s, s+wcslen(s)); - } - - this_type& assign(size_type n, value_type c) { - size_type current_capacity = (size_type)(mpEOS - mpBegin); - - if (current_capacity < n) - reserve_slow(n, current_capacity); - - if (mpBegin != sNull) { - mpEnd = mpBegin; - while(n--) - *mpEnd++ = c; - } - - return *this; - } - - this_type& assign(const value_type *s, const value_type *t) { - size_type current_capacity = (size_type)(mpEOS - mpBegin); - size_type n = (size_type)(t - s); - - if (current_capacity < n) - reserve_slow(n, current_capacity); - - if (mpBegin != sNull) { - memcpy(mpBegin, s, sizeof(value_type)*n); - mpEnd = mpBegin + n; - *mpEnd = 0; - } - - return *this; - } - - this_type& insert(iterator it, value_type c) { - if (mpEnd == mpEOS) { - size_type pos = (size_type)(it - mpBegin); - push_back_extend(); - it = mpBegin + pos; - } - - memmove(it + 1, it, (mpEnd - it + 1)*sizeof(value_type)); - *it = c; - ++mpEnd; - return *this; - } - - this_type& erase(size_type pos = 0, size_type n = npos) { - size_type len = (size_type)(mpEnd - mpBegin); - - VDASSERT(pos <= len); - len -= pos; - if (n > len) - n = len; - - if (n) { - size_type pos2 = pos + n; - memmove(mpBegin + pos, mpBegin + pos2, (len + 1 - n)*sizeof(value_type)); - mpEnd -= n; - } - - return *this; - } - - iterator erase(iterator x) { - VDASSERT(x != mpEnd); - - memmove(x, x+1, (mpEnd - x)*sizeof(value_type)); - --mpEnd; - return x; - } - - iterator erase(iterator first, iterator last) { - VDASSERT(last >= first); - - memmove(first, last, ((mpEnd - last) + 1)*sizeof(value_type)); - mpEnd -= (last - first); - return first; - } - - this_type& replace(size_type pos, size_type n1, const value_type *s, size_type n2) { - size_type len = (size_type)(mpEnd - mpBegin); - - VDASSERT(pos <= len); - size_type limit = len - pos; - if (n1 > limit) - n1 = limit; - - size_type len2 = len - n1 + n2; - size_type current_capacity = (size_type)(mpEOS - mpBegin); - - if (current_capacity < len2) - reserve_slow(len2, current_capacity); - - memmove(mpBegin + pos + n2, mpBegin + pos + n1, (limit - n1 + 1) * sizeof(value_type)); - memcpy(mpBegin + pos, s, n2*sizeof(value_type)); - mpEnd = mpBegin + len2; - return *this; - } - - void swap(this_type& x) { - std::swap(mpBegin, x.mpBegin); - std::swap(mpEnd, x.mpEnd); - std::swap(mpEOS, x.mpEOS); - } - - void swap(this_type&& x) { - std::swap(mpBegin, x.mpBegin); - std::swap(mpEnd, x.mpEnd); - std::swap(mpEOS, x.mpEOS); - } - - // 21.3.6 string operations - const_pointer c_str() const { return mpBegin; } - - this_type& sprintf(const value_type *format, ...); - this_type& append_sprintf(const value_type *format, ...); - this_type& append_vsprintf(const value_type *format, va_list val); - - void move_from(VDStringW& src); - -protected: - void push_back_extend(); - void resize_slow(size_type n, size_type current_size); - void reserve_slow(size_type n, size_type current_capacity); - void reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity); - - value_type *mpEOS; -}; - -/////////////////////////////////////////////////////////////////////////// - -inline VDStringW operator+(const VDStringW& str, const VDStringW& s) { - VDStringW result; - result.reserve((VDStringA::size_type)(str.size() + s.size())); - result.assign(str); - result.append(s); - return result; -} - -inline VDStringW operator+(const VDStringW& str, const wchar_t *s) { - VDStringW result; - result.reserve((VDStringA::size_type)(str.size() + wcslen(s))); - result.assign(str); - result.append(s); - return result; -} - -inline VDStringW operator+(const VDStringW& str, wchar_t c) { - VDStringW result; - result.reserve(str.size() + 1); - result.assign(str); - result += c; - return result; -} - -/////////////////////////////////////////////////////////////////////////// - -typedef VDStringA VDString; - -template<> VDStringA *vdmove_forward(VDStringA *src1, VDStringA *src2, VDStringA *dst); -template<> VDStringW *vdmove_forward(VDStringW *src1, VDStringW *src2, VDStringW *dst); -template<> VDStringA *vdmove_backward(VDStringA *src1, VDStringA *src2, VDStringA *dst); -template<> VDStringW *vdmove_backward(VDStringW *src1, VDStringW *src2, VDStringW *dst); - -VDMOVE_CAPABLE(VDStringA); -VDMOVE_CAPABLE(VDStringW); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTRING_H +#define f_VD2_SYSTEM_VDSTRING_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +class VDStringSpanA { +public: + typedef char value_type; + typedef uint32 size_type; + typedef ptrdiff_t difference_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type * pointer; + typedef const value_type * const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + + static const size_type npos = (size_type)-1; + + VDStringSpanA() + : mpBegin(const_cast(sNull)) + , mpEnd(const_cast(sNull)) + { + } + + explicit VDStringSpanA(const value_type *s) + : mpBegin(const_cast(s)) + , mpEnd(const_cast(s) + strlen(s)) + { + } + + VDStringSpanA(const value_type *s, const value_type *t) + : mpBegin(const_cast(s)) + , mpEnd(const_cast(t)) + { + } + + // 21.3.2 iterators + const_iterator begin() const { return mpBegin; } + const_iterator end() const { return mpEnd; } + + // 21.3.3 capacity + size_type size() const { return (size_type)(mpEnd - mpBegin); } + size_type length() const { return (size_type)(mpEnd - mpBegin); } + bool empty() const { return mpBegin == mpEnd; } + + // 21.3.4 element access + const_reference operator[](size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + const_reference at(size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + + const_reference front() const { VDASSERT(mpBegin != mpEnd); return *mpBegin; } + const_reference back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } + + // 21.3.6 string operations + const_pointer data() const { return mpBegin; } + + size_type copy(value_type *dst, size_type n, size_type pos = 0) const { + size_type len = (size_type)(mpEnd - mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + memcpy(dst, mpBegin + pos, n*sizeof(value_type)); + return n; + } + + size_type find(value_type c, size_type pos = 0) const { + VDASSERT(pos <= (size_type)(mpEnd - mpBegin)); + const void *p = memchr(mpBegin + pos, c, mpEnd - (mpBegin + pos)); + + return p ? (size_type)((const value_type *)p - mpBegin) : npos; + } + + size_type find_last_of(value_type c) const { + const value_type *s = mpEnd; + + while(s != mpBegin) { + --s; + + if (*s == c) + return (size_type)(s - mpBegin); + } + + return npos; + } + + int compare(const VDStringSpanA& s) const { + size_type l1 = (size_type)(mpEnd - mpBegin); + size_type l2 = (size_type)(s.mpEnd - s.mpBegin); + size_type lm = l1 < l2 ? l1 : l2; + + int r = memcmp(mpBegin, s.mpBegin, lm); + + if (!r && l1 != l2) + r = (int)mpBegin[lm] - (int)s.mpBegin[lm]; + + return r; + } + + int comparei(const char *s) const { + return comparei(VDStringSpanA(s)); + } + + int comparei(const VDStringSpanA& s) const { + size_type l1 = (size_type)(mpEnd - mpBegin); + size_type l2 = (size_type)(s.mpEnd - s.mpBegin); + size_type lm = l1 < l2 ? l1 : l2; + + const char *p = mpBegin; + const char *q = s.mpBegin; + + while(lm--) { + const unsigned char c = tolower((unsigned char)*p++); + const unsigned char d = tolower((unsigned char)*q++); + + if (c != d) + return (int)c - (int)d; + } + + return (int)l1 - (int)l2; + } + + const VDStringSpanA trim(const value_type *s) const { + bool flags[256]={false}; + + while(value_type c = *s++) + flags[(unsigned char)c] = true; + + const value_type *p = mpBegin; + const value_type *q = mpEnd; + + while(p != q && flags[*p]) + ++p; + + while(p != q && flags[q[-1]]) + --q; + + return VDStringSpanA(p, q); + } + + const VDStringSpanA subspan(size_type pos = 0, size_type n = npos) const { + + size_type len = (size_type)(mpEnd - mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + value_type *p = mpBegin + pos; + return VDStringSpanA(p, p+n); + } + +protected: + friend bool operator==(const VDStringSpanA& x, const VDStringSpanA& y); + friend bool operator==(const VDStringSpanA& x, const char *y); + + value_type *mpBegin; + value_type *mpEnd; + + static const value_type sNull[1]; +}; + +inline bool operator==(const VDStringSpanA& x, const VDStringSpanA& y) { VDStringSpanA::size_type len = (VDStringSpanA::size_type)(x.mpEnd - x.mpBegin); return len == (VDStringSpanA::size_type)(y.mpEnd - y.mpBegin) && !memcmp(x.mpBegin, y.mpBegin, len*sizeof(char)); } +inline bool operator==(const VDStringSpanA& x, const char *y) { size_t len = strlen(y); return len == (size_t)(x.mpEnd - x.mpBegin) && !memcmp(x.mpBegin, y, len*sizeof(char)); } +inline bool operator==(const char *x, const VDStringSpanA& y) { return y == x; } + +inline bool operator!=(const VDStringSpanA& x, const VDStringSpanA& y) { return !(x == y); } +inline bool operator!=(const VDStringSpanA& x, const char *y) { return !(x == y); } +inline bool operator!=(const char *x, const VDStringSpanA& y) { return !(y == x); } + +inline bool operator<(const VDStringSpanA& x, const VDStringSpanA& y) { + return x.compare(y) < 0; +} + +inline bool operator>(const VDStringSpanA& x, const VDStringSpanA& y) { + return x.compare(y) > 0; +} + +inline bool operator<=(const VDStringSpanA& x, const VDStringSpanA& y) { + return x.compare(y) <= 0; +} + +inline bool operator>=(const VDStringSpanA& x, const VDStringSpanA& y) { + return x.compare(y) >= 0; +} + +class VDStringRefA : public VDStringSpanA { +public: + typedef VDStringRefA this_type; + + VDStringRefA() { + } + + explicit VDStringRefA(const value_type *s) + : VDStringSpanA(s) + { + } + + explicit VDStringRefA(const VDStringSpanA& s) + : VDStringSpanA(s) + { + } + + VDStringRefA(const value_type *s, const value_type *t) + : VDStringSpanA(s, t) + { + } + + this_type& operator=(const value_type *s) { + assign(s); + return *this; + } + + this_type& operator=(const VDStringSpanA& str) { + assign(str); + return *this; + } + + void assign(const value_type *s) { + static_cast(*this) = VDStringSpanA(s); + } + + void assign(const value_type *s, const value_type *t) { + static_cast(*this) = VDStringSpanA(s, t); + } + + void assign(const VDStringSpanA& s) { + static_cast(*this) = s; + } + + void clear() { + mpBegin = mpEnd = NULL; + } + + bool split(value_type c, VDStringRefA& token) { + size_type pos = find(c); + + if (pos == npos) + return false; + + token = subspan(0, pos); + mpBegin += pos+1; + return true; + } +}; + +class VDStringA : public VDStringSpanA { +public: + typedef VDStringA this_type; + + // 21.3.1 construct/copy/destroy + + VDStringA() + : mpEOS(const_cast(sNull)) + { + } + + VDStringA(const VDStringSpanA& x) + : mpEOS(const_cast(sNull)) + { + assign(x.begin(), x.end()); + } + + VDStringA(const this_type& x) + : mpEOS(const_cast(sNull)) + { + assign(x); + } + + explicit VDStringA(const value_type *s) + : mpEOS(const_cast(sNull)) + { + assign(s); + } + + explicit VDStringA(size_type n) + : mpEOS(const_cast(sNull)) + { + resize(n); + } + + VDStringA(const value_type *s, size_type n) + : mpEOS(const_cast(sNull)) + { + assign(s, n); + } + + VDStringA(const value_type *s, const value_type *t) + : mpEOS(const_cast(sNull)) + { + assign(s, t); + } + + ~VDStringA() { + if (mpBegin != sNull) + delete[] mpBegin; + } + + this_type& operator=(const value_type *s) { + assign(s); + return *this; + } + + this_type& operator=(const this_type& str) { + assign(str); + return *this; + } + + this_type& operator=(const VDStringSpanA& str) { + assign(str); + return *this; + } + + // 21.3.2 iterators + using VDStringSpanA::begin; + using VDStringSpanA::end; + + iterator begin() { return mpBegin; } + iterator end() { return mpEnd; } + + // 21.3.3 capacity (COMPLETE) + void resize(size_type n) { + size_type current = (size_type)(mpEnd - mpBegin); + + if (n < current) { + mpEnd = mpBegin + n; + mpEnd[0] = 0; + } else if (n > current) + resize_slow(n, current); + } + + void resize(size_type n, value_type v) { + size_type current = (size_type)(mpEnd - mpBegin); + + if (n < current) { + mpEnd = mpBegin + n; + mpEnd[0] = 0; + } else if (n > current) + resize_slow(n, current, v); + } + + size_type capacity() const { return (size_type)(mpEOS - mpBegin); } + + void reserve(size_type n) { + size_type current = (size_type)(mpEOS - mpBegin); + + if (n > current) + reserve_slow(n, current); + } + + void clear() { + if (mpEnd != mpBegin) { + mpEnd = mpBegin; + mpEnd[0] = 0; + } + } + + // 21.3.4 element access + using VDStringSpanA::operator[]; + using VDStringSpanA::at; + using VDStringSpanA::front; + using VDStringSpanA::back; + + reference operator[](size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + reference at(size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + reference front() { VDASSERT(mpBegin != mpEnd); return *mpBegin; } + reference back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } + + // 21.3.5 modifiers + this_type& operator+=(const this_type& str) { + return append(str.mpBegin, str.mpEnd); + } + + this_type& operator+=(const value_type *s) { + return append(s, s+strlen(s)); + } + + this_type& operator+=(value_type c) { + if (mpEnd == mpEOS) + push_back_extend(); + + *mpEnd++ = c; + *mpEnd = 0; + return *this; + } + + this_type& append(const this_type& str) { + return append(str.mpBegin, str.mpEnd); + } + + this_type& append(const this_type& str, size_type pos, size_type n) { + size_type len = (size_type)(str.mpEnd - str.mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + return append(str.mpBegin + pos, str.mpBegin + pos + n); + } + + this_type& append(const value_type *s, size_type n) { + return append(s, s+n); + } + + this_type& append(const value_type *s) { + return append(s, s+strlen(s)); + } + + this_type& append(const value_type *s, const value_type *t) { + if (s != t) { + size_type current_size = (size_type)(mpEnd - mpBegin); + size_type current_capacity = (size_type)(mpEOS - mpBegin); + size_type n = (size_type)(t - s); + + if (current_capacity - current_size < n) + reserve_amortized_slow(n, current_size, current_capacity); + + memcpy(mpBegin + current_size, s, n*sizeof(value_type)); + mpEnd += n; + *mpEnd = 0; + } + return *this; + } + + void push_back(const value_type c) { + if (mpEnd == mpEOS) + push_back_extend(); + + *mpEnd++ = c; + *mpEnd = 0; + } + + void pop_back() { + --mpEnd; + *mpEnd = 0; + } + + this_type& assign(const VDStringSpanA& str) { + return assign(str.begin(), str.end()); + } + + this_type& assign(const this_type& str) { + return assign(str.mpBegin, str.mpEnd); + } + + this_type& assign(const this_type& str, size_type pos, size_type n) { + size_type len = (size_type)(str.mpEnd - str.mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + return assign(str.mpBegin + pos, str.mpBegin + pos + n); + } + + this_type& assign(const value_type *s, size_type n) { + return assign(s, s+n); + } + + this_type& assign(const value_type *s) { + return assign(s, s+strlen(s)); + } + + this_type& assign(size_type n, value_type c) { + size_type current_capacity = (size_type)(mpEOS - mpBegin); + + if (current_capacity < n) + reserve_slow(n, current_capacity); + + if (mpBegin != sNull) { + mpEnd = mpBegin; + while(n--) + *mpEnd++ = c; + } + + return *this; + } + + this_type& assign(const value_type *s, const value_type *t) { + size_type current_capacity = (size_type)(mpEOS - mpBegin); + size_type n = (size_type)(t - s); + + if (current_capacity < n) + reserve_slow(n, current_capacity); + + if (mpBegin != sNull) { + memcpy(mpBegin, s, sizeof(value_type)*n); + mpEnd = mpBegin + n; + *mpEnd = 0; + } + + return *this; + } + + this_type& insert(iterator it, value_type c) { + if (mpEnd == mpEOS) { + size_type pos = (size_type)(it - mpBegin); + push_back_extend(); + it = mpBegin + pos; + } + + memmove(it + 1, it, (mpEnd - it + 1)*sizeof(value_type)); + *it = c; + ++mpEnd; + return *this; + } + + this_type& erase(size_type pos = 0, size_type n = npos) { + size_type len = (size_type)(mpEnd - mpBegin); + + VDASSERT(pos <= len); + len -= pos; + if (n > len) + n = len; + + if (n) { + size_type pos2 = pos + n; + memmove(mpBegin + pos, mpBegin + pos2, (len + 1 - n)*sizeof(value_type)); + mpEnd -= n; + } + + return *this; + } + + iterator erase(iterator x) { + VDASSERT(x != mpEnd); + + memmove(x, x+1, (mpEnd - x)*sizeof(value_type)); + --mpEnd; + return x; + } + + iterator erase(iterator first, iterator last) { + VDASSERT(last >= first); + + memmove(first, last, ((mpEnd - last) + 1)*sizeof(value_type)); + mpEnd -= (last - first); + return first; + } + + this_type& replace(size_type pos, size_type n1, const value_type *s, size_type n2) { + size_type len = (size_type)(mpEnd - mpBegin); + + VDASSERT(pos <= len); + size_type limit = len - pos; + if (n1 > limit) + n1 = limit; + + size_type len2 = len - n1 + n2; + size_type current_capacity = (size_type)(mpEOS - mpBegin); + + if (current_capacity < len2) + reserve_slow(len2, current_capacity); + + memmove(mpBegin + pos + n2, mpBegin + pos + n1, (limit - n1 + 1) * sizeof(value_type)); + memcpy(mpBegin + pos, s, n2*sizeof(value_type)); + mpEnd = mpBegin + len2; + return *this; + } + + void swap(this_type& x) { + value_type *p; + + p = mpBegin; mpBegin = x.mpBegin; x.mpBegin = p; + p = mpEnd; mpEnd = x.mpEnd; x.mpEnd = p; + p = mpEOS; mpEOS = x.mpEOS; x.mpEOS = p; + } + + // 21.3.6 string operations + const_pointer c_str() const { return mpBegin; } + + this_type& sprintf(const value_type *format, ...); + this_type& append_sprintf(const value_type *format, ...); + this_type& append_vsprintf(const value_type *format, va_list val); + + void move_from(VDStringA& src); + +protected: + void push_back_extend(); + void resize_slow(size_type n, size_type current_size); + void resize_slow(size_type n, size_type current_size, value_type c); + void reserve_slow(size_type n, size_type current_capacity); + void reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity); + + char *mpEOS; +}; + +/////////////////////////////////////////////////////////////////////////// + +inline VDStringA operator+(const VDStringA& str, const VDStringA& s) { + VDStringA result; + result.reserve((VDStringA::size_type)(str.size() + s.size())); + result.assign(str); + result.append(s); + return result; +} + +inline VDStringA operator+(const VDStringA& str, const char *s) { + VDStringA result; + result.reserve((VDStringA::size_type)(str.size() + strlen(s))); + result.assign(str); + result.append(s); + return result; +} + +inline VDStringA operator+(const VDStringA& str, char c) { + VDStringA result; + result.reserve(str.size() + 1); + result.assign(str); + result += c; + return result; +} + +// Start patch MPC-HC +/* +namespace std { + template<> + struct less : binary_function { + bool operator()(const VDStringA& x, const VDStringA& y) const { + return x.compare(y) < 0; + } + }; +} +*/ +// End patch MPC-HC + +/////////////////////////////////////////////////////////////////////////// + +class VDStringSpanW { +public: + typedef wchar_t value_type; + typedef uint32 size_type; + typedef ptrdiff_t difference_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type * pointer; + typedef const value_type * const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + + static const size_type npos = (size_type)-1; + + VDStringSpanW() + : mpBegin(const_cast(sNull)) + , mpEnd(const_cast(sNull)) + { + } + + explicit VDStringSpanW(const value_type *s) + : mpBegin(const_cast(s)) + , mpEnd(const_cast(s) + wcslen(s)) + { + } + + VDStringSpanW(const value_type *s, const value_type *t) + : mpBegin(const_cast(s)) + , mpEnd(const_cast(t)) + { + } + + // 21.3.2 iterators + const_iterator begin() const { return mpBegin; } + const_iterator end() const { return mpEnd; } + + // 21.3.3 capacity + size_type size() const { return (size_type)(mpEnd - mpBegin); } + size_type length() const { return (size_type)(mpEnd - mpBegin); } + bool empty() const { return mpBegin == mpEnd; } + + // 21.3.4 element access + const_reference operator[](size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + const_reference at(size_type pos) const { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + + const_reference front() const { VDASSERT(mpBegin != mpEnd); return *mpBegin; } + const_reference back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } + + // 21.3.6 string operations + const_pointer data() const { return mpBegin; } + + size_type copy(value_type *dst, size_type n, size_type pos = 0) const { + size_type len = (size_type)(mpEnd - mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + memcpy(dst, mpBegin + pos, n*sizeof(value_type)); + return n; + } + + size_type find(value_type c, size_type pos = 0) const { + VDASSERT(pos <= (size_type)(mpEnd - mpBegin)); + const void *p = wmemchr(mpBegin + pos, c, mpEnd - (mpBegin + pos)); + + return p ? (size_type)((const value_type *)p - mpBegin) : npos; + } + + int compare(const VDStringSpanW& s) const { + size_type l1 = (size_type)(mpEnd - mpBegin); + size_type l2 = (size_type)(s.mpEnd - s.mpBegin); + size_type lm = l1 < l2 ? l1 : l2; + + for(size_type i = 0; i < lm; ++i) { + if (mpBegin[i] != s.mpBegin[i]) + return mpBegin[i] < s.mpBegin[i] ? -1 : +1; + } + + if (l1 == l2) + return 0; + + return l1 < l2 ? -1 : +1; + } + + int comparei(const wchar_t *s) const { + return comparei(VDStringSpanW(s)); + } + + int comparei(const VDStringSpanW& s) const { + size_type l1 = (size_type)(mpEnd - mpBegin); + size_type l2 = (size_type)(s.mpEnd - s.mpBegin); + size_type lm = l1 < l2 ? l1 : l2; + + for(size_type i = 0; i < lm; ++i) { + wint_t c = towlower(mpBegin[i]); + wint_t d = towlower(s.mpBegin[i]); + + if (c != d) + return c < d ? -1 : +1; + } + + if (l1 == l2) + return 0; + + return l1 < l2 ? -1 : +1; + } + + // extensions + const VDStringSpanW subspan(size_type pos, size_type n) const { + size_type len = (size_type)(mpEnd - mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + value_type *p = mpBegin + pos; + return VDStringSpanW(p, p+n); + } + +protected: + friend class VDStringW; + friend bool operator==(const VDStringSpanW& x, const VDStringSpanW& y); + friend bool operator==(const VDStringSpanW& x, const wchar_t *y); + + value_type *mpBegin; + value_type *mpEnd; + + static const value_type sNull[1]; +}; + +inline bool operator==(const VDStringSpanW& x, const VDStringSpanW& y) { VDStringA::size_type len = (VDStringSpanW::size_type)(x.mpEnd - x.mpBegin); return len == (VDStringSpanW::size_type)(y.mpEnd - y.mpBegin) && !memcmp(x.mpBegin, y.mpBegin, len*sizeof(wchar_t)); } +inline bool operator==(const VDStringSpanW& x, const wchar_t *y) { size_t len = wcslen(y); return len == (size_t)(x.mpEnd - x.mpBegin) && !memcmp(x.mpBegin, y, len*sizeof(wchar_t)); } +inline bool operator==(const wchar_t *x, const VDStringSpanW& y) { return y == x; } + +inline bool operator!=(const VDStringSpanW& x, const VDStringSpanW& y) { return !(x == y); } +inline bool operator!=(const VDStringSpanW& x, const wchar_t *y) { return !(x == y); } +inline bool operator!=(const wchar_t *x, const VDStringSpanW& y) { return !(y == x); } + +inline bool operator<(const VDStringSpanW& x, const VDStringSpanW& y) { + return x.compare(y) < 0; +} + +inline bool operator>(const VDStringSpanW& x, const VDStringSpanW& y) { + return x.compare(y) > 0; +} + +inline bool operator<=(const VDStringSpanW& x, const VDStringSpanW& y) { + return x.compare(y) <= 0; +} + +inline bool operator>=(const VDStringSpanW& x, const VDStringSpanW& y) { + return x.compare(y) >= 0; +} + +class VDStringRefW : public VDStringSpanW { +public: + typedef VDStringRefW this_type; + + VDStringRefW() { + } + + explicit VDStringRefW(const value_type *s) + : VDStringSpanW(s) + { + } + + explicit VDStringRefW(const VDStringSpanW& s) + : VDStringSpanW(s) + { + } + + VDStringRefW(const value_type *s, const value_type *t) + : VDStringSpanW(s, t) + { + } + + this_type& operator=(const value_type *s) { + assign(s); + return *this; + } + + this_type& operator=(const VDStringSpanW& str) { + assign(str); + return *this; + } + + void assign(const value_type *s) { + static_cast(*this) = VDStringSpanW(s); + } + + void assign(const value_type *s, const value_type *t) { + static_cast(*this) = VDStringSpanW(s, t); + } + + void assign(const VDStringSpanW& s) { + static_cast(*this) = s; + } + + void clear() { + mpBegin = mpEnd = NULL; + } + + bool split(value_type c, VDStringRefW& token) { + size_type pos = find(c); + + if (pos == npos) + return false; + + token = subspan(0, pos); + mpBegin += pos+1; + return true; + } +}; + +class VDStringW : public VDStringSpanW { +public: + typedef VDStringW this_type; + + // 21.3.1 construct/copy/destroy + + VDStringW() + : mpEOS(const_cast(sNull)) + { + } + + VDStringW(const VDStringSpanW& x) + : mpEOS(const_cast(sNull)) + { + assign(x.begin(), x.end()); + } + + VDStringW(const this_type& x) + : mpEOS(const_cast(sNull)) + { + assign(x); + } + + explicit VDStringW(const value_type *s) + : mpEOS(const_cast(sNull)) + { + assign(s); + } + + explicit VDStringW(size_type n) + : mpEOS(const_cast(sNull)) + { + resize(n); + } + + VDStringW(const value_type *s, size_type n) + : mpEOS(const_cast(sNull)) + { + assign(s, n); + } + + VDStringW(const value_type *s, const value_type *t) + : mpEOS(const_cast(sNull)) + { + assign(s, t); + } + + ~VDStringW() { + if (mpBegin != sNull) + delete[] mpBegin; + } + + this_type& operator=(const wchar_t *s) { + assign(s); + return *this; + } + + this_type& operator=(const this_type& str) { + assign(str); + return *this; + } + + // 21.3.2 iterators + using VDStringSpanW::begin; + using VDStringSpanW::end; + iterator begin() { return mpBegin; } + iterator end() { return mpEnd; } + + // 21.3.3 capacity (COMPLETE) + void resize(size_type n) { + size_type current = (size_type)(mpEnd - mpBegin); + + if (n < current) { + mpEnd = mpBegin + n; + mpEnd[0] = 0; + } else if (n > current) + resize_slow(n, current); + } + + void resize(size_type n, value_type v) { + size_type current = (size_type)(mpEnd - mpBegin); + + if (n < current) { + mpEnd = mpBegin + n; + mpEnd[0] = 0; + } else if (n > current) + resize_slow(n, current); + wmemset(mpBegin, v, n); + } + + size_type capacity() const { return (size_type)(mpEOS - mpBegin); } + + void reserve(size_type n) { + size_type current = (size_type)(mpEOS - mpBegin); + + if (n > current) + reserve_slow(n, current); + } + + void clear() { + if (mpEnd != mpBegin) { + mpEnd = mpBegin; + mpEnd[0] = 0; + } + } + + // 21.3.4 element access + using VDStringSpanW::operator[]; + using VDStringSpanW::at; + using VDStringSpanW::front; + using VDStringSpanW::back; + reference operator[](size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + reference at(size_type pos) { VDASSERT(pos < (size_type)(mpEnd - mpBegin)); return mpBegin[pos]; } + reference front() { VDASSERT(mpBegin != mpEnd); return *mpBegin; } + reference back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } + + // 21.3.5 modifiers + this_type& operator+=(const this_type& str) { + return append(str.mpBegin, str.mpEnd); + } + + this_type& operator+=(const value_type *s) { + return append(s, s+wcslen(s)); + } + + this_type& operator+=(value_type c) { + if (mpEnd == mpEOS) + push_back_extend(); + + *mpEnd++ = c; + *mpEnd = 0; + return *this; + } + + this_type& append(const this_type& str) { + return append(str.mpBegin, str.mpEnd); + } + + this_type& append(const this_type& str, size_type pos, size_type n) { + size_type len = (size_type)(str.mpEnd - str.mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + return append(str.mpBegin + pos, str.mpBegin + pos + n); + } + + this_type& append(const value_type *s, size_type n) { + return append(s, s+n); + } + + this_type& append(const value_type *s) { + return append(s, s+wcslen(s)); + } + + this_type& append(const value_type *s, const value_type *t) { + if (s != t) { + size_type current_size = (size_type)(mpEnd - mpBegin); + size_type current_capacity = (size_type)(mpEOS - mpBegin); + size_type n = (size_type)(t - s); + + if (current_capacity - current_size < n) + reserve_amortized_slow(n, current_size, current_capacity); + + memcpy(mpBegin + current_size, s, n*sizeof(value_type)); + mpEnd += n; + *mpEnd = 0; + } + return *this; + } + + void push_back(const value_type c) { + if (mpEnd == mpEOS) + push_back_extend(); + + *mpEnd++ = c; + *mpEnd = 0; + } + + void pop_back() { + --mpEnd; + *mpEnd = 0; + } + + this_type& assign(const VDStringSpanW& str) { + return assign(str.mpBegin, str.mpEnd); + } + + this_type& assign(const VDStringSpanW& str, size_type pos, size_type n) { + size_type len = (size_type)(str.mpEnd - str.mpBegin); + VDASSERT(pos <= len); + + len -= pos; + if (n > len) + n = len; + + return assign(str.mpBegin + pos, str.mpBegin + pos + n); + } + + this_type& assign(const value_type *s, size_type n) { + return assign(s, s+n); + } + + this_type& assign(const value_type *s) { + return assign(s, s+wcslen(s)); + } + + this_type& assign(size_type n, value_type c) { + size_type current_capacity = (size_type)(mpEOS - mpBegin); + + if (current_capacity < n) + reserve_slow(n, current_capacity); + + if (mpBegin != sNull) { + mpEnd = mpBegin; + while(n--) + *mpEnd++ = c; + } + + return *this; + } + + this_type& assign(const value_type *s, const value_type *t) { + size_type current_capacity = (size_type)(mpEOS - mpBegin); + size_type n = (size_type)(t - s); + + if (current_capacity < n) + reserve_slow(n, current_capacity); + + if (mpBegin != sNull) { + memcpy(mpBegin, s, sizeof(value_type)*n); + mpEnd = mpBegin + n; + *mpEnd = 0; + } + + return *this; + } + + this_type& insert(iterator it, value_type c) { + if (mpEnd == mpEOS) { + size_type pos = (size_type)(it - mpBegin); + push_back_extend(); + it = mpBegin + pos; + } + + memmove(it + 1, it, (mpEnd - it + 1)*sizeof(value_type)); + *it = c; + ++mpEnd; + return *this; + } + + this_type& erase(size_type pos = 0, size_type n = npos) { + size_type len = (size_type)(mpEnd - mpBegin); + + VDASSERT(pos <= len); + len -= pos; + if (n > len) + n = len; + + if (n) { + size_type pos2 = pos + n; + memmove(mpBegin + pos, mpBegin + pos2, (len + 1 - n)*sizeof(value_type)); + mpEnd -= n; + } + + return *this; + } + + iterator erase(iterator x) { + VDASSERT(x != mpEnd); + + memmove(x, x+1, (mpEnd - x)*sizeof(value_type)); + --mpEnd; + return x; + } + + iterator erase(iterator first, iterator last) { + VDASSERT(last >= first); + + memmove(first, last, ((mpEnd - last) + 1)*sizeof(value_type)); + mpEnd -= (last - first); + return first; + } + + this_type& replace(size_type pos, size_type n1, const value_type *s, size_type n2) { + size_type len = (size_type)(mpEnd - mpBegin); + + VDASSERT(pos <= len); + size_type limit = len - pos; + if (n1 > limit) + n1 = limit; + + size_type len2 = len - n1 + n2; + size_type current_capacity = (size_type)(mpEOS - mpBegin); + + if (current_capacity < len2) + reserve_slow(len2, current_capacity); + + memmove(mpBegin + pos + n2, mpBegin + pos + n1, (limit - n1 + 1) * sizeof(value_type)); + memcpy(mpBegin + pos, s, n2*sizeof(value_type)); + mpEnd = mpBegin + len2; + return *this; + } + + void swap(this_type& x) { + std::swap(mpBegin, x.mpBegin); + std::swap(mpEnd, x.mpEnd); + std::swap(mpEOS, x.mpEOS); + } + + void swap(this_type&& x) { + std::swap(mpBegin, x.mpBegin); + std::swap(mpEnd, x.mpEnd); + std::swap(mpEOS, x.mpEOS); + } + + // 21.3.6 string operations + const_pointer c_str() const { return mpBegin; } + + this_type& sprintf(const value_type *format, ...); + this_type& append_sprintf(const value_type *format, ...); + this_type& append_vsprintf(const value_type *format, va_list val); + + void move_from(VDStringW& src); + +protected: + void push_back_extend(); + void resize_slow(size_type n, size_type current_size); + void reserve_slow(size_type n, size_type current_capacity); + void reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity); + + value_type *mpEOS; +}; + +/////////////////////////////////////////////////////////////////////////// + +inline VDStringW operator+(const VDStringW& str, const VDStringW& s) { + VDStringW result; + result.reserve((VDStringA::size_type)(str.size() + s.size())); + result.assign(str); + result.append(s); + return result; +} + +inline VDStringW operator+(const VDStringW& str, const wchar_t *s) { + VDStringW result; + result.reserve((VDStringA::size_type)(str.size() + wcslen(s))); + result.assign(str); + result.append(s); + return result; +} + +inline VDStringW operator+(const VDStringW& str, wchar_t c) { + VDStringW result; + result.reserve(str.size() + 1); + result.assign(str); + result += c; + return result; +} + +/////////////////////////////////////////////////////////////////////////// + +typedef VDStringA VDString; + +template<> VDStringA *vdmove_forward(VDStringA *src1, VDStringA *src2, VDStringA *dst); +template<> VDStringW *vdmove_forward(VDStringW *src1, VDStringW *src2, VDStringW *dst); +template<> VDStringA *vdmove_backward(VDStringA *src1, VDStringA *src2, VDStringA *dst); +template<> VDStringW *vdmove_backward(VDStringW *src1, VDStringW *src2, VDStringW *dst); + +VDMOVE_CAPABLE(VDStringA); +VDMOVE_CAPABLE(VDStringW); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/atomic.h b/src/thirdparty/VirtualDub/h/vd2/system/atomic.h index f00330a44fd..1e82c87aa6c 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/atomic.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/atomic.h @@ -1,376 +1,376 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_ATOMIC_H -#define f_VD2_SYSTEM_ATOMIC_H - -#include - -#ifdef VD_COMPILER_MSVC - // Intrinsics available in VC6.0 - extern "C" long __cdecl _InterlockedDecrement(volatile long *p); - extern "C" long __cdecl _InterlockedIncrement(volatile long *p); - extern "C" long __cdecl _InterlockedCompareExchange(volatile long *p, long n, long p_compare); - extern "C" long __cdecl _InterlockedExchange(volatile long *p, long n); - extern "C" long __cdecl _InterlockedExchangeAdd(volatile long *p, long n); - - #pragma intrinsic(_InterlockedDecrement) - #pragma intrinsic(_InterlockedIncrement) - #pragma intrinsic(_InterlockedCompareExchange) - #pragma intrinsic(_InterlockedExchange) - #pragma intrinsic(_InterlockedExchangeAdd) - - // Intrinsics available in VC7.1. Note that the compiler is smart enough to - // use straight LOCK AND/OR/XOR if the return value is not needed; otherwise - // it uses a LOCK CMPXCHG loop. - #if _MSC_VER >= 1310 - extern "C" long __cdecl _InterlockedAnd(volatile long *p, long n); - extern "C" long __cdecl _InterlockedOr(volatile long *p, long n); - extern "C" long __cdecl _InterlockedXor(volatile long *p, long n); - - #pragma intrinsic(_InterlockedAnd) - #pragma intrinsic(_InterlockedOr) - #pragma intrinsic(_InterlockedXor) - #endif - - // Intrinsics available with AMD64 - #ifdef VD_CPU_AMD64 - extern "C" void *__cdecl _InterlockedExchangePointer(void *volatile *pp, void *p); - #pragma intrinsic(_InterlockedExchangePointer) - extern "C" void *__cdecl _InterlockedCompareExchangePointer(void *volatile *pp, void *p, void *compare); - #pragma intrinsic(_InterlockedCompareExchangePointer) - #endif -#endif - -inline void *VDAtomicCompareExchangePointer(void *volatile *pp, void *p, void *compare) { -#if defined(VD_COMPILER_MSVC) - #ifdef _M_AMD64 - return _InterlockedCompareExchangePointer(pp, p, compare); - #else - return (void *)(sintptr)_InterlockedCompareExchange((volatile long *)(volatile sintptr *)pp, (long)(sintptr)p, (long)(sintptr)compare); - #endif -#elif defined(VD_COMPILER_GCC) - return __sync_val_compare_and_swap(pp, compare, p); -#endif -} - -/////////////////////////////////////////////////////////////////////////// -/// \class VDAtomicInt -/// \brief Wrapped integer supporting thread-safe atomic operations. -/// -/// VDAtomicInt allows integer values shared between threads to be -/// modified with several common operations in a lock-less manner and -/// without the need for explicit barriers. This is particularly useful -/// for thread-safe reference counting. -/// -class VDAtomicInt { -protected: - volatile int n; - -public: - VDAtomicInt() {} - VDAtomicInt(int v) : n(v) {} - - bool operator!() const { return !n; } - bool operator!=(volatile int v) const { return n!=v; } - bool operator==(volatile int v) const { return n==v; } - bool operator<=(volatile int v) const { return n<=v; } - bool operator>=(volatile int v) const { return n>=v; } - bool operator<(volatile int v) const { return n(volatile int v) const { return n>v; } - - /////////////////////////////// - - /// Atomically exchanges a value with an integer in memory. - static inline int staticExchange(volatile int *dst, int v) { - #if defined(VD_COMPILER_MSVC) - return (int)_InterlockedExchange((volatile long *)dst, v); - #elif defined(VD_COMPILER_GCC) - return __sync_lock_test_and_set((int *)&dst, v); - #endif - } - - /// Atomically adds one to an integer in memory. - static inline void staticIncrement(volatile int *dst) { - #if defined(VD_COMPILER_MSVC) - _InterlockedExchangeAdd((volatile long *)dst, 1); - #elif defined(VD_COMPILER_GCC) - __sync_fetch_and_add(&dst, 1); - #endif - } - - /// Atomically subtracts one from an integer in memory. - static inline void staticDecrement(volatile int *dst) { - #if defined(VD_COMPILER_MSVC) - _InterlockedExchangeAdd((volatile long *)dst, -1); - #elif defined(VD_COMPILER_GCC) - __sync_fetch_and_sub(&dst, 1); - #endif - } - - /// Atomically subtracts one from an integer in memory and returns - /// true if the result is zero. - static inline bool staticDecrementTestZero(volatile int *dst) { - #if defined(VD_COMPILER_MSVC) - return 1 == _InterlockedExchangeAdd((volatile long *)dst, -1); - #elif defined(VD_COMPILER_GCC) - return 1 == __sync_fetch_and_sub((int *)&dst, 1); - #endif - } - - /// Atomically adds a value to an integer in memory and returns the - /// result. - static inline int staticAdd(volatile int *dst, int v) { - #if defined(VD_COMPILER_MSVC) - return (int)_InterlockedExchangeAdd((volatile long *)dst, v) + v; - #elif defined(VD_COMPILER_GCC) - return __sync_fetch_and_add((int *)&dst, v) + v; - #endif - } - - /// Atomically adds a value to an integer in memory and returns the - /// old result (post-add). - static inline int staticExchangeAdd(volatile int *dst, int v) { - #if defined(VD_COMPILER_MSVC) - return _InterlockedExchangeAdd((volatile long *)dst, v); - #elif defined(VD_COMPILER_GCC) - return __sync_fetch_and_add((int *)&dst, v); - #endif - } - - /// Atomically compares an integer in memory to a compare value and - /// swaps the memory location with a second value if the compare - /// succeeds. The return value is the memory value prior to the swap. - static inline int staticCompareExchange(volatile int *dst, int v, int compare) { - #if defined(VD_COMPILER_MSVC) - return _InterlockedCompareExchange((volatile long *)dst, v, compare); - #elif defined(VD_COMPILER_GCC) - return __sync_val_compare_and_swap((int *)&dst, compare, v); - #endif - } - - /////////////////////////////// - - int operator=(int v) { return n = v; } - - int operator++() { return staticAdd(&n, 1); } - int operator--() { return staticAdd(&n, -1); } - int operator++(int) { return staticExchangeAdd(&n, 1); } - int operator--(int) { return staticExchangeAdd(&n, -1); } - int operator+=(int v) { return staticAdd(&n, v); } - int operator-=(int v) { return staticAdd(&n, -v); } - -#if _MSC_VER >= 1310 - - void operator&=(int v) { _InterlockedAnd((volatile long *)&n, v); } ///< Atomic bitwise AND. - void operator|=(int v) { _InterlockedOr((volatile long *)&n, v); } ///< Atomic bitwise OR. - void operator^=(int v) { _InterlockedXor((volatile long *)&n, v); } ///< Atomic bitwise XOR. - -#elif defined(VD_COMPILER_GCC) - - void operator&=(int v) { - __sync_fetch_and_and(&n, v); - } - - void operator|=(int v) { - __sync_fetch_and_or(&n, v); - } - - void operator^=(int v) { - __sync_fetch_and_xor(&n, v); - } - -#else - /// Atomic bitwise AND. - void operator&=(int v) { - __asm mov eax,v - __asm mov ecx,this - __asm lock and dword ptr [ecx],eax - } - - /// Atomic bitwise OR. - void operator|=(int v) { - __asm mov eax,v - __asm mov ecx,this - __asm lock or dword ptr [ecx],eax - } - - /// Atomic bitwise XOR. - void operator^=(int v) { - __asm mov eax,v - __asm mov ecx,this - __asm lock xor dword ptr [ecx],eax - } -#endif - - operator int() const { - return n; - } - - /// Atomic exchange. - int xchg(int v) { - return staticExchange(&n, v); - } - - /// Compare/exchange (486+). - int compareExchange(int newValue, int oldValue) { - return staticCompareExchange(&n, newValue, oldValue); - } - - // 486 only, but much nicer. They return the actual result. - - int inc() { return operator++(); } ///< Atomic increment. - int dec() { return operator--(); } ///< Atomic decrement. - int add(int v) { return operator+=(v); } ///< Atomic add. - - // These return the result before the operation, which is more inline with - // what XADD allows us to do. - - int postinc() { return operator++(0); } ///< Atomic post-increment. - int postdec() { return operator--(0); } ///< Atomic post-decrement. - int postadd(int v) { return staticExchangeAdd(&n, v); } ///< Atomic post-add. - -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDAtomicFloat { -protected: - volatile float n; - -public: - VDAtomicFloat() {} - VDAtomicFloat(float v) : n(v) {} - - bool operator!=(float v) const { return n!=v; } - bool operator==(float v) const { return n==v; } - bool operator<=(float v) const { return n<=v; } - bool operator>=(float v) const { return n>=v; } - bool operator<(float v) const { return n(float v) const { return n>v; } - - float operator=(float v) { return n = v; } - - operator float() const { - return n; - } - - /// Atomic exchange. - float xchg(float v) { - union { int i; float f; } converter = {VDAtomicInt::staticExchange((volatile int *)&n, *(const int *)&v)}; - - return converter.f; - } -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDAtomicBool { -protected: - volatile char n; - -public: - VDAtomicBool() {} - VDAtomicBool(bool v) : n(v) {} - - bool operator!=(bool v) const { return (n != 0) != v; } - bool operator==(bool v) const { return (n != 0) == v; } - - bool operator=(bool v) { return n = v; } - - operator bool() const { - return n != 0; - } - - /// Atomic exchange. - bool xchg(bool v) { - const uint32 mask = ((uint32)0xFF << (int)((size_t)&n & 3)); - const int andval = (int)~mask; - const int orval = (int)(mask & 0x01010101); - volatile int *p = (volatile int *)((uintptr)&n & ~(uintptr)3); - - for(;;) { - const uint32 prevval = *p; - const uint32 newval = (prevval & andval) + orval; - - if (prevval == VDAtomicInt::staticCompareExchange(p, newval, prevval)) - return (prevval & mask) != 0; - } - } -}; - -/////////////////////////////////////////////////////////////////////////// -/// \class VDAtomicPtr -/// \brief Wrapped pointer supporting thread-safe atomic operations. -/// -/// VDAtomicPtr allows a shared pointer to be safely manipulated by -/// multiple threads without locks. Note that atomicity is only guaranteed -/// for the pointer itself, so any operations on the object must be dealt -/// with in other manners, such as an inner lock or other atomic -/// operations. An atomic pointer can serve as a single entry queue. -/// -template -class VDAtomicPtr { -protected: - T *volatile ptr; - -public: - VDAtomicPtr() {} - VDAtomicPtr(T *p) : ptr(p) { } - - operator T*() const { return ptr; } - T* operator->() const { return ptr; } - - T* operator=(T* p) { - return ptr = p; - } - - /// Atomic pointer exchange. - T *xchg(T* p) { - #if defined(VD_COMPILER_MSVC) - #ifdef _M_AMD64 - return ptr == p ? p : (T *)_InterlockedExchangePointer((void *volatile *)&ptr, p); - #else - return ptr == p ? p : (T *)_InterlockedExchange((volatile long *)&ptr, (long)p); - #endif - #elif defined(VD_COMPILER_GCC) - return __sync_lock_test_and_set(&ptr, p); - #endif - } - - T *compareExchange(T *newValue, T *oldValue) { - #if defined(VD_COMPILER_MSVC) - #ifdef _M_AMD64 - return (T *)_InterlockedCompareExchangePointer((void *volatile *)&ptr, (void *)newValue, (void *)oldValue); - #else - return (T *)_InterlockedCompareExchange((volatile long *)&ptr, (long)(size_t)newValue, (long)(size_t)oldValue); - #endif - #elif defined(VD_COMPILER_GCC) - return __sync_val_compare_and_swap(&ptr, oldValue, newValue); - #endif - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_ATOMIC_H +#define f_VD2_SYSTEM_ATOMIC_H + +#include + +#ifdef VD_COMPILER_MSVC + // Intrinsics available in VC6.0 + extern "C" long __cdecl _InterlockedDecrement(volatile long *p); + extern "C" long __cdecl _InterlockedIncrement(volatile long *p); + extern "C" long __cdecl _InterlockedCompareExchange(volatile long *p, long n, long p_compare); + extern "C" long __cdecl _InterlockedExchange(volatile long *p, long n); + extern "C" long __cdecl _InterlockedExchangeAdd(volatile long *p, long n); + + #pragma intrinsic(_InterlockedDecrement) + #pragma intrinsic(_InterlockedIncrement) + #pragma intrinsic(_InterlockedCompareExchange) + #pragma intrinsic(_InterlockedExchange) + #pragma intrinsic(_InterlockedExchangeAdd) + + // Intrinsics available in VC7.1. Note that the compiler is smart enough to + // use straight LOCK AND/OR/XOR if the return value is not needed; otherwise + // it uses a LOCK CMPXCHG loop. + #if _MSC_VER >= 1310 + extern "C" long __cdecl _InterlockedAnd(volatile long *p, long n); + extern "C" long __cdecl _InterlockedOr(volatile long *p, long n); + extern "C" long __cdecl _InterlockedXor(volatile long *p, long n); + + #pragma intrinsic(_InterlockedAnd) + #pragma intrinsic(_InterlockedOr) + #pragma intrinsic(_InterlockedXor) + #endif + + // Intrinsics available with AMD64 + #ifdef VD_CPU_AMD64 + extern "C" void *__cdecl _InterlockedExchangePointer(void *volatile *pp, void *p); + #pragma intrinsic(_InterlockedExchangePointer) + extern "C" void *__cdecl _InterlockedCompareExchangePointer(void *volatile *pp, void *p, void *compare); + #pragma intrinsic(_InterlockedCompareExchangePointer) + #endif +#endif + +inline void *VDAtomicCompareExchangePointer(void *volatile *pp, void *p, void *compare) { +#if defined(VD_COMPILER_MSVC) + #ifdef _M_AMD64 + return _InterlockedCompareExchangePointer(pp, p, compare); + #else + return (void *)(sintptr)_InterlockedCompareExchange((volatile long *)(volatile sintptr *)pp, (long)(sintptr)p, (long)(sintptr)compare); + #endif +#elif defined(VD_COMPILER_GCC) + return __sync_val_compare_and_swap(pp, compare, p); +#endif +} + +/////////////////////////////////////////////////////////////////////////// +/// \class VDAtomicInt +/// \brief Wrapped integer supporting thread-safe atomic operations. +/// +/// VDAtomicInt allows integer values shared between threads to be +/// modified with several common operations in a lock-less manner and +/// without the need for explicit barriers. This is particularly useful +/// for thread-safe reference counting. +/// +class VDAtomicInt { +protected: + volatile int n; + +public: + VDAtomicInt() {} + VDAtomicInt(int v) : n(v) {} + + bool operator!() const { return !n; } + bool operator!=(volatile int v) const { return n!=v; } + bool operator==(volatile int v) const { return n==v; } + bool operator<=(volatile int v) const { return n<=v; } + bool operator>=(volatile int v) const { return n>=v; } + bool operator<(volatile int v) const { return n(volatile int v) const { return n>v; } + + /////////////////////////////// + + /// Atomically exchanges a value with an integer in memory. + static inline int staticExchange(volatile int *dst, int v) { + #if defined(VD_COMPILER_MSVC) + return (int)_InterlockedExchange((volatile long *)dst, v); + #elif defined(VD_COMPILER_GCC) + return __sync_lock_test_and_set((int *)&dst, v); + #endif + } + + /// Atomically adds one to an integer in memory. + static inline void staticIncrement(volatile int *dst) { + #if defined(VD_COMPILER_MSVC) + _InterlockedExchangeAdd((volatile long *)dst, 1); + #elif defined(VD_COMPILER_GCC) + __sync_fetch_and_add(&dst, 1); + #endif + } + + /// Atomically subtracts one from an integer in memory. + static inline void staticDecrement(volatile int *dst) { + #if defined(VD_COMPILER_MSVC) + _InterlockedExchangeAdd((volatile long *)dst, -1); + #elif defined(VD_COMPILER_GCC) + __sync_fetch_and_sub(&dst, 1); + #endif + } + + /// Atomically subtracts one from an integer in memory and returns + /// true if the result is zero. + static inline bool staticDecrementTestZero(volatile int *dst) { + #if defined(VD_COMPILER_MSVC) + return 1 == _InterlockedExchangeAdd((volatile long *)dst, -1); + #elif defined(VD_COMPILER_GCC) + return 1 == __sync_fetch_and_sub((int *)&dst, 1); + #endif + } + + /// Atomically adds a value to an integer in memory and returns the + /// result. + static inline int staticAdd(volatile int *dst, int v) { + #if defined(VD_COMPILER_MSVC) + return (int)_InterlockedExchangeAdd((volatile long *)dst, v) + v; + #elif defined(VD_COMPILER_GCC) + return __sync_fetch_and_add((int *)&dst, v) + v; + #endif + } + + /// Atomically adds a value to an integer in memory and returns the + /// old result (post-add). + static inline int staticExchangeAdd(volatile int *dst, int v) { + #if defined(VD_COMPILER_MSVC) + return _InterlockedExchangeAdd((volatile long *)dst, v); + #elif defined(VD_COMPILER_GCC) + return __sync_fetch_and_add((int *)&dst, v); + #endif + } + + /// Atomically compares an integer in memory to a compare value and + /// swaps the memory location with a second value if the compare + /// succeeds. The return value is the memory value prior to the swap. + static inline int staticCompareExchange(volatile int *dst, int v, int compare) { + #if defined(VD_COMPILER_MSVC) + return _InterlockedCompareExchange((volatile long *)dst, v, compare); + #elif defined(VD_COMPILER_GCC) + return __sync_val_compare_and_swap((int *)&dst, compare, v); + #endif + } + + /////////////////////////////// + + int operator=(int v) { return n = v; } + + int operator++() { return staticAdd(&n, 1); } + int operator--() { return staticAdd(&n, -1); } + int operator++(int) { return staticExchangeAdd(&n, 1); } + int operator--(int) { return staticExchangeAdd(&n, -1); } + int operator+=(int v) { return staticAdd(&n, v); } + int operator-=(int v) { return staticAdd(&n, -v); } + +#if _MSC_VER >= 1310 + + void operator&=(int v) { _InterlockedAnd((volatile long *)&n, v); } ///< Atomic bitwise AND. + void operator|=(int v) { _InterlockedOr((volatile long *)&n, v); } ///< Atomic bitwise OR. + void operator^=(int v) { _InterlockedXor((volatile long *)&n, v); } ///< Atomic bitwise XOR. + +#elif defined(VD_COMPILER_GCC) + + void operator&=(int v) { + __sync_fetch_and_and(&n, v); + } + + void operator|=(int v) { + __sync_fetch_and_or(&n, v); + } + + void operator^=(int v) { + __sync_fetch_and_xor(&n, v); + } + +#else + /// Atomic bitwise AND. + void operator&=(int v) { + __asm mov eax,v + __asm mov ecx,this + __asm lock and dword ptr [ecx],eax + } + + /// Atomic bitwise OR. + void operator|=(int v) { + __asm mov eax,v + __asm mov ecx,this + __asm lock or dword ptr [ecx],eax + } + + /// Atomic bitwise XOR. + void operator^=(int v) { + __asm mov eax,v + __asm mov ecx,this + __asm lock xor dword ptr [ecx],eax + } +#endif + + operator int() const { + return n; + } + + /// Atomic exchange. + int xchg(int v) { + return staticExchange(&n, v); + } + + /// Compare/exchange (486+). + int compareExchange(int newValue, int oldValue) { + return staticCompareExchange(&n, newValue, oldValue); + } + + // 486 only, but much nicer. They return the actual result. + + int inc() { return operator++(); } ///< Atomic increment. + int dec() { return operator--(); } ///< Atomic decrement. + int add(int v) { return operator+=(v); } ///< Atomic add. + + // These return the result before the operation, which is more inline with + // what XADD allows us to do. + + int postinc() { return operator++(0); } ///< Atomic post-increment. + int postdec() { return operator--(0); } ///< Atomic post-decrement. + int postadd(int v) { return staticExchangeAdd(&n, v); } ///< Atomic post-add. + +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDAtomicFloat { +protected: + volatile float n; + +public: + VDAtomicFloat() {} + VDAtomicFloat(float v) : n(v) {} + + bool operator!=(float v) const { return n!=v; } + bool operator==(float v) const { return n==v; } + bool operator<=(float v) const { return n<=v; } + bool operator>=(float v) const { return n>=v; } + bool operator<(float v) const { return n(float v) const { return n>v; } + + float operator=(float v) { return n = v; } + + operator float() const { + return n; + } + + /// Atomic exchange. + float xchg(float v) { + union { int i; float f; } converter = {VDAtomicInt::staticExchange((volatile int *)&n, *(const int *)&v)}; + + return converter.f; + } +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDAtomicBool { +protected: + volatile char n; + +public: + VDAtomicBool() {} + VDAtomicBool(bool v) : n(v) {} + + bool operator!=(bool v) const { return (n != 0) != v; } + bool operator==(bool v) const { return (n != 0) == v; } + + bool operator=(bool v) { return n = v; } + + operator bool() const { + return n != 0; + } + + /// Atomic exchange. + bool xchg(bool v) { + const uint32 mask = ((uint32)0xFF << (int)((size_t)&n & 3)); + const int andval = (int)~mask; + const int orval = (int)(mask & 0x01010101); + volatile int *p = (volatile int *)((uintptr)&n & ~(uintptr)3); + + for(;;) { + const uint32 prevval = *p; + const uint32 newval = (prevval & andval) + orval; + + if (prevval == VDAtomicInt::staticCompareExchange(p, newval, prevval)) + return (prevval & mask) != 0; + } + } +}; + +/////////////////////////////////////////////////////////////////////////// +/// \class VDAtomicPtr +/// \brief Wrapped pointer supporting thread-safe atomic operations. +/// +/// VDAtomicPtr allows a shared pointer to be safely manipulated by +/// multiple threads without locks. Note that atomicity is only guaranteed +/// for the pointer itself, so any operations on the object must be dealt +/// with in other manners, such as an inner lock or other atomic +/// operations. An atomic pointer can serve as a single entry queue. +/// +template +class VDAtomicPtr { +protected: + T *volatile ptr; + +public: + VDAtomicPtr() {} + VDAtomicPtr(T *p) : ptr(p) { } + + operator T*() const { return ptr; } + T* operator->() const { return ptr; } + + T* operator=(T* p) { + return ptr = p; + } + + /// Atomic pointer exchange. + T *xchg(T* p) { + #if defined(VD_COMPILER_MSVC) + #ifdef _M_AMD64 + return ptr == p ? p : (T *)_InterlockedExchangePointer((void *volatile *)&ptr, p); + #else + return ptr == p ? p : (T *)_InterlockedExchange((volatile long *)&ptr, (long)p); + #endif + #elif defined(VD_COMPILER_GCC) + return __sync_lock_test_and_set(&ptr, p); + #endif + } + + T *compareExchange(T *newValue, T *oldValue) { + #if defined(VD_COMPILER_MSVC) + #ifdef _M_AMD64 + return (T *)_InterlockedCompareExchangePointer((void *volatile *)&ptr, (void *)newValue, (void *)oldValue); + #else + return (T *)_InterlockedCompareExchange((volatile long *)&ptr, (long)(size_t)newValue, (long)(size_t)oldValue); + #endif + #elif defined(VD_COMPILER_GCC) + return __sync_val_compare_and_swap(&ptr, oldValue, newValue); + #endif + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/binary.h b/src/thirdparty/VirtualDub/h/vd2/system/binary.h index 207333010e8..8ab90be3eaf 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/binary.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/binary.h @@ -1,181 +1,181 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_BINARY_H -#define f_VD2_SYSTEM_BINARY_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -#define VDMAKEFOURCC(byte1, byte2, byte3, byte4) (((uint8)byte1) + (((uint8)byte2) << 8) + (((uint8)byte3) << 16) + (((uint8)byte4) << 24)) - -#ifdef _MSC_VER - #include - - inline uint16 VDSwizzleU16(uint16 value) { return (uint16)_byteswap_ushort((unsigned short)value); } - inline sint16 VDSwizzleS16(sint16 value) { return (sint16)_byteswap_ushort((unsigned short)value); } - inline uint32 VDSwizzleU32(uint32 value) { return (uint32)_byteswap_ulong((unsigned long)value); } - inline sint32 VDSwizzleS32(sint32 value) { return (sint32)_byteswap_ulong((unsigned long)value); } - inline uint64 VDSwizzleU64(uint64 value) { return (uint64)_byteswap_uint64((unsigned __int64)value); } - inline sint64 VDSwizzleS64(sint64 value) { return (sint64)_byteswap_uint64((unsigned __int64)value); } - - inline uint32 VDRotateLeftU32(uint32 value, int bits) { return (uint32)_rotl((unsigned int)value, bits); } - inline uint32 VDRotateRightU32(uint32 value, int bits) { return (uint32)_rotr((unsigned int)value, bits); } -#else - inline uint16 VDSwizzleU16(uint16 value) { - return (value >> 8) + (value << 8); - } - - inline sint16 VDSwizzleS16(sint16 value) { - return (sint16)(((uint16)value >> 8) + ((uint16)value << 8)); - } - - inline uint32 VDSwizzleU32(uint32 value) { - return (value >> 24) + (value << 24) + ((value&0xff00)<<8) + ((value&0xff0000)>>8); - } - - inline sint32 VDSwizzleS32(sint32 value) { - return (sint32)(((uint32)value >> 24) + ((uint32)value << 24) + (((uint32)value&0xff00)<<8) + (((uint32)value&0xff0000)>>8)); - } - - inline uint64 VDSwizzleU64(uint64 value) { - return ((value & 0xFF00000000000000) >> 56) + - ((value & 0x00FF000000000000) >> 40) + - ((value & 0x0000FF0000000000) >> 24) + - ((value & 0x000000FF00000000) >> 8) + - ((value & 0x00000000FF000000) << 8) + - ((value & 0x0000000000FF0000) << 24) + - ((value & 0x000000000000FF00) << 40) + - ((value & 0x00000000000000FF) << 56); - } - - inline sint64 VDSwizzleS64(sint64 value) { - return (sint64)((((uint64)value & 0xFF00000000000000) >> 56) + - (((uint64)value & 0x00FF000000000000) >> 40) + - (((uint64)value & 0x0000FF0000000000) >> 24) + - (((uint64)value & 0x000000FF00000000) >> 8) + - (((uint64)value & 0x00000000FF000000) << 8) + - (((uint64)value & 0x0000000000FF0000) << 24) + - (((uint64)value & 0x000000000000FF00) << 40) + - (((uint64)value & 0x00000000000000FF) << 56)); - } -#endif - -inline uint16 VDReadUnalignedU16(const void *p) { return *(uint16 *)p; } -inline sint16 VDReadUnalignedS16(const void *p) { return *(sint16 *)p; } -inline uint32 VDReadUnalignedU32(const void *p) { return *(uint32 *)p; } -inline sint32 VDReadUnalignedS32(const void *p) { return *(sint32 *)p; } -inline uint64 VDReadUnalignedU64(const void *p) { return *(uint64 *)p; } -inline sint64 VDReadUnalignedS64(const void *p) { return *(sint64 *)p; } -inline float VDReadUnalignedF(const void *p) { return *(float *)p; } -inline double VDReadUnalignedD(const void *p) { return *(double *)p; } - -inline uint16 VDReadUnalignedLEU16(const void *p) { return *(uint16 *)p; } -inline sint16 VDReadUnalignedLES16(const void *p) { return *(sint16 *)p; } -inline uint32 VDReadUnalignedLEU32(const void *p) { return *(uint32 *)p; } -inline sint32 VDReadUnalignedLES32(const void *p) { return *(sint32 *)p; } -inline uint64 VDReadUnalignedLEU64(const void *p) { return *(uint64 *)p; } -inline sint64 VDReadUnalignedLES64(const void *p) { return *(sint64 *)p; } -inline float VDReadUnalignedLEF(const void *p) { return *(float *)p; } -inline double VDReadUnalignedLED(const void *p) { return *(double *)p; } - -inline uint16 VDReadUnalignedBEU16(const void *p) { return VDSwizzleU16(*(uint16 *)p); } -inline sint16 VDReadUnalignedBES16(const void *p) { return VDSwizzleS16(*(sint16 *)p); } -inline uint32 VDReadUnalignedBEU32(const void *p) { return VDSwizzleU32(*(uint32 *)p); } -inline sint32 VDReadUnalignedBES32(const void *p) { return VDSwizzleS32(*(sint32 *)p); } -inline uint64 VDReadUnalignedBEU64(const void *p) { return VDSwizzleU64(*(uint64 *)p); } -inline sint64 VDReadUnalignedBES64(const void *p) { return VDSwizzleS64(*(sint64 *)p); } -inline float VDReadUnalignedBEF(const void *p) { - union { - uint32 i; - float f; - } conv = {VDSwizzleU32(*(const uint32 *)p)}; - return conv.f; -} -inline double VDReadUnalignedBED(const void *p) { - union { - uint64 i; - double d; - } conv = {VDSwizzleU64(*(const uint32 *)p)}; - return conv.d; -} - -inline void VDWriteUnalignedU16 (void *p, uint16 v) { *(uint16 *)p = v; } -inline void VDWriteUnalignedS16 (void *p, sint16 v) { *(sint16 *)p = v; } -inline void VDWriteUnalignedU32 (void *p, uint32 v) { *(uint32 *)p = v; } -inline void VDWriteUnalignedS32 (void *p, sint32 v) { *(sint32 *)p = v; } -inline void VDWriteUnalignedU64 (void *p, uint64 v) { *(uint64 *)p = v; } -inline void VDWriteUnalignedS64 (void *p, sint64 v) { *(sint64 *)p = v; } -inline void VDWriteUnalignedF (void *p, float v) { *(float *)p = v; } -inline void VDWriteUnalignedD (void *p, double v) { *(double *)p = v; } - -inline void VDWriteUnalignedLEU16(void *p, uint16 v) { *(uint16 *)p = v; } -inline void VDWriteUnalignedLES16(void *p, sint16 v) { *(sint16 *)p = v; } -inline void VDWriteUnalignedLEU32(void *p, uint32 v) { *(uint32 *)p = v; } -inline void VDWriteUnalignedLES32(void *p, sint32 v) { *(sint32 *)p = v; } -inline void VDWriteUnalignedLEU64(void *p, uint64 v) { *(uint64 *)p = v; } -inline void VDWriteUnalignedLES64(void *p, sint64 v) { *(sint64 *)p = v; } -inline void VDWriteUnalignedLEF (void *p, float v) { *(float *)p = v; } -inline void VDWriteUnalignedLED (void *p, double v) { *(double *)p = v; } - -inline void VDWriteUnalignedBEU16(void *p, uint16 v) { *(uint16 *)p = VDSwizzleU16(v); } -inline void VDWriteUnalignedBES16(void *p, sint16 v) { *(sint16 *)p = VDSwizzleS16(v); } -inline void VDWriteUnalignedBEU32(void *p, uint32 v) { *(uint32 *)p = VDSwizzleU32(v); } -inline void VDWriteUnalignedBES32(void *p, sint32 v) { *(sint32 *)p = VDSwizzleS32(v); } -inline void VDWriteUnalignedBEU64(void *p, uint64 v) { *(uint64 *)p = VDSwizzleU64(v); } -inline void VDWriteUnalignedBES64(void *p, sint64 v) { *(sint64 *)p = VDSwizzleS64(v); } -inline void VDReadUnalignedBEF(void *p, float v) { - union { - float f; - uint32 i; - } conv = {v}; - *(uint32 *)p = VDSwizzleU32(conv.i); -} -inline double VDReadUnalignedBED(void *p, double v) { - union { - double f; - uint64 i; - } conv = {v}; - *(uint64 *)p = VDSwizzleU64(conv.i); -} - -#define VDFromLE8(x) (x) -#define VDFromLE16(x) (x) -#define VDFromLE32(x) (x) -#define VDFromBE8(x) VDSwizzleU8(x) -#define VDFromBE16(x) VDSwizzleU16(x) -#define VDFromBE32(x) VDSwizzleU32(x) - -#define VDToLE8(x) (x) -#define VDToLE16(x) (x) -#define VDToLE32(x) (x) -#define VDToBE8(x) VDSwizzleU8(x) -#define VDToBE16(x) VDSwizzleU16(x) -#define VDToBE32(x) VDSwizzleU32(x) - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_BINARY_H +#define f_VD2_SYSTEM_BINARY_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +#define VDMAKEFOURCC(byte1, byte2, byte3, byte4) (((uint8)byte1) + (((uint8)byte2) << 8) + (((uint8)byte3) << 16) + (((uint8)byte4) << 24)) + +#ifdef _MSC_VER + #include + + inline uint16 VDSwizzleU16(uint16 value) { return (uint16)_byteswap_ushort((unsigned short)value); } + inline sint16 VDSwizzleS16(sint16 value) { return (sint16)_byteswap_ushort((unsigned short)value); } + inline uint32 VDSwizzleU32(uint32 value) { return (uint32)_byteswap_ulong((unsigned long)value); } + inline sint32 VDSwizzleS32(sint32 value) { return (sint32)_byteswap_ulong((unsigned long)value); } + inline uint64 VDSwizzleU64(uint64 value) { return (uint64)_byteswap_uint64((unsigned __int64)value); } + inline sint64 VDSwizzleS64(sint64 value) { return (sint64)_byteswap_uint64((unsigned __int64)value); } + + inline uint32 VDRotateLeftU32(uint32 value, int bits) { return (uint32)_rotl((unsigned int)value, bits); } + inline uint32 VDRotateRightU32(uint32 value, int bits) { return (uint32)_rotr((unsigned int)value, bits); } +#else + inline uint16 VDSwizzleU16(uint16 value) { + return (value >> 8) + (value << 8); + } + + inline sint16 VDSwizzleS16(sint16 value) { + return (sint16)(((uint16)value >> 8) + ((uint16)value << 8)); + } + + inline uint32 VDSwizzleU32(uint32 value) { + return (value >> 24) + (value << 24) + ((value&0xff00)<<8) + ((value&0xff0000)>>8); + } + + inline sint32 VDSwizzleS32(sint32 value) { + return (sint32)(((uint32)value >> 24) + ((uint32)value << 24) + (((uint32)value&0xff00)<<8) + (((uint32)value&0xff0000)>>8)); + } + + inline uint64 VDSwizzleU64(uint64 value) { + return ((value & 0xFF00000000000000) >> 56) + + ((value & 0x00FF000000000000) >> 40) + + ((value & 0x0000FF0000000000) >> 24) + + ((value & 0x000000FF00000000) >> 8) + + ((value & 0x00000000FF000000) << 8) + + ((value & 0x0000000000FF0000) << 24) + + ((value & 0x000000000000FF00) << 40) + + ((value & 0x00000000000000FF) << 56); + } + + inline sint64 VDSwizzleS64(sint64 value) { + return (sint64)((((uint64)value & 0xFF00000000000000) >> 56) + + (((uint64)value & 0x00FF000000000000) >> 40) + + (((uint64)value & 0x0000FF0000000000) >> 24) + + (((uint64)value & 0x000000FF00000000) >> 8) + + (((uint64)value & 0x00000000FF000000) << 8) + + (((uint64)value & 0x0000000000FF0000) << 24) + + (((uint64)value & 0x000000000000FF00) << 40) + + (((uint64)value & 0x00000000000000FF) << 56)); + } +#endif + +inline uint16 VDReadUnalignedU16(const void *p) { return *(uint16 *)p; } +inline sint16 VDReadUnalignedS16(const void *p) { return *(sint16 *)p; } +inline uint32 VDReadUnalignedU32(const void *p) { return *(uint32 *)p; } +inline sint32 VDReadUnalignedS32(const void *p) { return *(sint32 *)p; } +inline uint64 VDReadUnalignedU64(const void *p) { return *(uint64 *)p; } +inline sint64 VDReadUnalignedS64(const void *p) { return *(sint64 *)p; } +inline float VDReadUnalignedF(const void *p) { return *(float *)p; } +inline double VDReadUnalignedD(const void *p) { return *(double *)p; } + +inline uint16 VDReadUnalignedLEU16(const void *p) { return *(uint16 *)p; } +inline sint16 VDReadUnalignedLES16(const void *p) { return *(sint16 *)p; } +inline uint32 VDReadUnalignedLEU32(const void *p) { return *(uint32 *)p; } +inline sint32 VDReadUnalignedLES32(const void *p) { return *(sint32 *)p; } +inline uint64 VDReadUnalignedLEU64(const void *p) { return *(uint64 *)p; } +inline sint64 VDReadUnalignedLES64(const void *p) { return *(sint64 *)p; } +inline float VDReadUnalignedLEF(const void *p) { return *(float *)p; } +inline double VDReadUnalignedLED(const void *p) { return *(double *)p; } + +inline uint16 VDReadUnalignedBEU16(const void *p) { return VDSwizzleU16(*(uint16 *)p); } +inline sint16 VDReadUnalignedBES16(const void *p) { return VDSwizzleS16(*(sint16 *)p); } +inline uint32 VDReadUnalignedBEU32(const void *p) { return VDSwizzleU32(*(uint32 *)p); } +inline sint32 VDReadUnalignedBES32(const void *p) { return VDSwizzleS32(*(sint32 *)p); } +inline uint64 VDReadUnalignedBEU64(const void *p) { return VDSwizzleU64(*(uint64 *)p); } +inline sint64 VDReadUnalignedBES64(const void *p) { return VDSwizzleS64(*(sint64 *)p); } +inline float VDReadUnalignedBEF(const void *p) { + union { + uint32 i; + float f; + } conv = {VDSwizzleU32(*(const uint32 *)p)}; + return conv.f; +} +inline double VDReadUnalignedBED(const void *p) { + union { + uint64 i; + double d; + } conv = {VDSwizzleU64(*(const uint32 *)p)}; + return conv.d; +} + +inline void VDWriteUnalignedU16 (void *p, uint16 v) { *(uint16 *)p = v; } +inline void VDWriteUnalignedS16 (void *p, sint16 v) { *(sint16 *)p = v; } +inline void VDWriteUnalignedU32 (void *p, uint32 v) { *(uint32 *)p = v; } +inline void VDWriteUnalignedS32 (void *p, sint32 v) { *(sint32 *)p = v; } +inline void VDWriteUnalignedU64 (void *p, uint64 v) { *(uint64 *)p = v; } +inline void VDWriteUnalignedS64 (void *p, sint64 v) { *(sint64 *)p = v; } +inline void VDWriteUnalignedF (void *p, float v) { *(float *)p = v; } +inline void VDWriteUnalignedD (void *p, double v) { *(double *)p = v; } + +inline void VDWriteUnalignedLEU16(void *p, uint16 v) { *(uint16 *)p = v; } +inline void VDWriteUnalignedLES16(void *p, sint16 v) { *(sint16 *)p = v; } +inline void VDWriteUnalignedLEU32(void *p, uint32 v) { *(uint32 *)p = v; } +inline void VDWriteUnalignedLES32(void *p, sint32 v) { *(sint32 *)p = v; } +inline void VDWriteUnalignedLEU64(void *p, uint64 v) { *(uint64 *)p = v; } +inline void VDWriteUnalignedLES64(void *p, sint64 v) { *(sint64 *)p = v; } +inline void VDWriteUnalignedLEF (void *p, float v) { *(float *)p = v; } +inline void VDWriteUnalignedLED (void *p, double v) { *(double *)p = v; } + +inline void VDWriteUnalignedBEU16(void *p, uint16 v) { *(uint16 *)p = VDSwizzleU16(v); } +inline void VDWriteUnalignedBES16(void *p, sint16 v) { *(sint16 *)p = VDSwizzleS16(v); } +inline void VDWriteUnalignedBEU32(void *p, uint32 v) { *(uint32 *)p = VDSwizzleU32(v); } +inline void VDWriteUnalignedBES32(void *p, sint32 v) { *(sint32 *)p = VDSwizzleS32(v); } +inline void VDWriteUnalignedBEU64(void *p, uint64 v) { *(uint64 *)p = VDSwizzleU64(v); } +inline void VDWriteUnalignedBES64(void *p, sint64 v) { *(sint64 *)p = VDSwizzleS64(v); } +inline void VDReadUnalignedBEF(void *p, float v) { + union { + float f; + uint32 i; + } conv = {v}; + *(uint32 *)p = VDSwizzleU32(conv.i); +} +inline double VDReadUnalignedBED(void *p, double v) { + union { + double f; + uint64 i; + } conv = {v}; + *(uint64 *)p = VDSwizzleU64(conv.i); +} + +#define VDFromLE8(x) (x) +#define VDFromLE16(x) (x) +#define VDFromLE32(x) (x) +#define VDFromBE8(x) VDSwizzleU8(x) +#define VDFromBE16(x) VDSwizzleU16(x) +#define VDFromBE32(x) VDSwizzleU32(x) + +#define VDToLE8(x) (x) +#define VDToLE16(x) (x) +#define VDToLE32(x) (x) +#define VDToBE8(x) VDSwizzleU8(x) +#define VDToBE16(x) VDSwizzleU16(x) +#define VDToBE32(x) VDSwizzleU32(x) + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/bitmath.h b/src/thirdparty/VirtualDub/h/vd2/system/bitmath.h index 308ac6202aa..c6bd7607801 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/bitmath.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/bitmath.h @@ -1,95 +1,95 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_BITMATH_H -#define f_VD2_SYSTEM_BITMATH_H - -#ifdef _MSC_VER - #pragma once -#endif - -#ifndef f_VD2_SYSTEM_VDTYPES_H - #include -#endif - -int VDCountBits(uint32 v); -int VDFindLowestSetBit(uint32 v); -int VDFindHighestSetBit(uint32 v); -uint32 VDCeilToPow2(uint32 v); - -union VDFloatAsInt { - float f; - sint32 i; -}; - -union VDIntAsFloat { - sint32 i; - float f; -}; - -inline sint32 VDGetFloatAsInt(float f) { - const VDFloatAsInt conv = { f }; - return conv.i; -} - -inline float VDGetIntAsFloat(sint32 i) { - const VDIntAsFloat conv = { i }; - return conv.f; -} - -/////////////////////////////////////////////////////////////////////////////// - -#ifdef VD_COMPILER_MSVC_VC8_OR_LATER - #include - #pragma intrinsic(_BitScanForward) - #pragma intrinsic(_BitScanReverse) - - inline int VDFindLowestSetBit(uint32 v) { - unsigned long index; - return _BitScanForward(&index, v) ? index : 32; - } - - inline int VDFindHighestSetBit(uint32 v) { - unsigned long index; - return _BitScanReverse(&index, v) ? index : -1; - } - - inline int VDFindLowestSetBitFast(uint32 v) { - unsigned long index; - _BitScanForward(&index, v); - return index; - } - - inline int VDFindHighestSetBitFast(uint32 v) { - unsigned long index; - _BitScanReverse(&index, v); - return index; - } -#else - #define VDFindLowestSetBitFast VDFindLowestSetBit - #define VDFindHighestSetBitFast VDFindHighestSetBit -#endif - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_BITMATH_H +#define f_VD2_SYSTEM_BITMATH_H + +#ifdef _MSC_VER + #pragma once +#endif + +#ifndef f_VD2_SYSTEM_VDTYPES_H + #include +#endif + +int VDCountBits(uint32 v); +int VDFindLowestSetBit(uint32 v); +int VDFindHighestSetBit(uint32 v); +uint32 VDCeilToPow2(uint32 v); + +union VDFloatAsInt { + float f; + sint32 i; +}; + +union VDIntAsFloat { + sint32 i; + float f; +}; + +inline sint32 VDGetFloatAsInt(float f) { + const VDFloatAsInt conv = { f }; + return conv.i; +} + +inline float VDGetIntAsFloat(sint32 i) { + const VDIntAsFloat conv = { i }; + return conv.f; +} + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef VD_COMPILER_MSVC_VC8_OR_LATER + #include + #pragma intrinsic(_BitScanForward) + #pragma intrinsic(_BitScanReverse) + + inline int VDFindLowestSetBit(uint32 v) { + unsigned long index; + return _BitScanForward(&index, v) ? index : 32; + } + + inline int VDFindHighestSetBit(uint32 v) { + unsigned long index; + return _BitScanReverse(&index, v) ? index : -1; + } + + inline int VDFindLowestSetBitFast(uint32 v) { + unsigned long index; + _BitScanForward(&index, v); + return index; + } + + inline int VDFindHighestSetBitFast(uint32 v) { + unsigned long index; + _BitScanReverse(&index, v); + return index; + } +#else + #define VDFindLowestSetBitFast VDFindLowestSetBit + #define VDFindHighestSetBitFast VDFindHighestSetBit +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/cache.h b/src/thirdparty/VirtualDub/h/vd2/system/cache.h index 599d979fafd..e4d45eb152f 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/cache.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/cache.h @@ -1,325 +1,325 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_CACHE_H -#define f_VD2_SYSTEM_CACHE_H - -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -struct vdfixedhashmap_node { - vdfixedhashmap_node *mpHashPrev; - vdfixedhashmap_node *mpHashNext; -}; - -template -struct vdhash { - size_t operator()(const K key) const { - return (size_t)key; - } -}; - -template, int N = 256> -class vdfixedhashmap_iterator { -public: - typedef vdfixedhashmap_node node; - - bool operator==(vdfixedhashmap_iterator& x) const { return mpNode == x.mpNode; } - bool operator!=(vdfixedhashmap_iterator& x) const { return mpNode != x.mpNode; } - - V& operator*() const { return *static_cast((node *)mpNode); } - V *operator->() const { return static_cast((node *)mpNode); } - - vdfixedhashmap_iterator& operator++() { - do { - mpNode = ((node *)mpNode)->mpHashNext; - if (mpNode != mpTableNode) - break; - - ++mpTableNode; - mpNode = mpTableNode->mpHashNext; - } while(mpNode); - - return *this; - } - - vdfixedhashmap_iterator operator++(int) { - vdfixedhashmap_iterator it(*this); - ++*this; - return it; - } - -public: - vdfixedhashmap_node *mpNode; - vdfixedhashmap_node *mpTableNode; -}; - -template, int N = 256> -class vdfixedhashmap { -public: - typedef K key_type; - typedef V value_type; - typedef Hash hash_type; - typedef vdfixedhashmap_node node; - typedef vdfixedhashmap_iterator iterator; - - vdfixedhashmap() { - for(int i=0; impHashNext; p != r; p = p->mpHashNext) { - if (static_cast(p)->mHashKey == key) - return static_cast(p); - } - - return NULL; - } - - iterator find(const K& key) { - const size_t htidx = m(key) % N; - - node *r = &m.mpTable[htidx]; - for(node *p = r->mpHashNext; p != r; p = p->mpHashNext) { - if (static_cast(p)->mHashKey == key) { - iterator it = { p, &m.mpTable[htidx] }; - return it; - } - } - - return end(); - } - - iterator insert(V *p) { - const size_t htidx = m(p->mHashKey) % N; - - node *r = &m.mpTable[htidx]; - node *n = r->mpHashNext; - r->mpHashNext = p; - p->mpHashPrev = &m.mpTable[htidx]; - p->mpHashNext = n; - n->mpHashPrev = p; - - iterator it = { p, &m.mpTable[htidx] }; - return it; - } - - void erase(V *x) { - node *p = x->mpHashPrev; - node *n = x->mpHashNext; - - p->mpHashNext = n; - n->mpHashPrev = p; - } - - void erase(iterator it) { - erase(it.mpNode); - } - -protected: - struct Data : public Hash { - vdfixedhashmap_node mpTable[N]; - } m; -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDCachedObject; - -class IVDCacheAllocator { -public: - virtual VDCachedObject *OnCacheAllocate() = 0; -}; - -/////////////////////////////////////////////////////////////////////////// - -enum VDCacheState { - kVDCacheStateFree, - kVDCacheStatePending, - kVDCacheStateReady, - kVDCacheStateActive, - kVDCacheStateComplete, - kVDCacheStateIdle, - kVDCacheStateAborting, - kVDCacheStateCount -}; - -struct VDCachedObjectNodes : public vdlist_node, public vdfixedhashmap_node { - sint64 mHashKey; -}; - -class VDCache { -public: - VDCache(IVDCacheAllocator *pAllocator); - ~VDCache(); - - void Shutdown(); - - int GetStateCount(int state); - - void DumpListStatus(int state); - - VDCachedObject *Create(sint64 key, bool& is_new); - - VDCachedObject *Allocate(sint64 key); - void Schedule(VDCachedObject *); // Moves a Pending or Active object to Ready. - VDCachedObject *GetNextReady(); // Selects a Ready object and moves it to Active. - void MarkCompleted(VDCachedObject *); // Marks an object as completed. - -public: - void NotifyFree(VDCachedObject *pObject); - -protected: - void Evict(uint32 level); - -protected: - VDCriticalSection mLock; - - IVDCacheAllocator *mpAllocator; - uint32 mObjectCount; - uint32 mObjectLimit; - - typedef vdlist ObjectList; - ObjectList mLists[kVDCacheStateCount]; - - vdfixedhashmap mHash; -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDCachedObject : private VDCachedObjectNodes { - friend class VDCache; -public: - VDCachedObject(); - virtual ~VDCachedObject() {} - - int AddRef(); - int Release(); - - void WeakAddRef(); - void WeakRelease(); - -protected: - virtual void OnCacheEvict() {} - virtual void OnCacheAbortPending() {} - virtual void DumpStatus() {} - -protected: - int GetRefCount() const { return mRefCount; } - void SetCache(VDCache *pCache); - - VDCacheState GetState() const { return mState; } - void SetState(VDCacheState state) { mState = state; } - - sint64 GetCacheKey() const { return mHashKey; } - - virtual bool IsValid() const { return true; } - -protected: - VDCache *mpCache; - VDAtomicInt mRefCount; - VDCacheState mState; -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDPooledObject; - -class IVDPoolAllocator { -public: - virtual VDPooledObject *OnPoolAllocate() = 0; -}; - -/////////////////////////////////////////////////////////////////////////// - -enum VDPoolState { - kVDPoolStateFree, - kVDPoolStateActive, - kVDPoolStateCount -}; - -struct VDPooledObjectNodes : public vdlist_node {}; - -class VDPool { -public: - VDPool(IVDPoolAllocator *pAllocator); - ~VDPool(); - - void Shutdown(); - - VDPooledObject *Allocate(); - -public: - void NotifyFree(VDPooledObject *pObject); - -protected: - VDCriticalSection mLock; - - IVDPoolAllocator *mpAllocator; - uint32 mObjectCount; - uint32 mObjectLimit; - - typedef vdlist ObjectList; - ObjectList mLists[kVDPoolStateCount]; -}; - -class VDPooledObject : private VDPooledObjectNodes { - friend class VDPool; -public: - VDPooledObject(); - virtual ~VDPooledObject() {} - - int AddRef(); - int Release(); - -protected: - int GetRefCount() const { return mRefCount; } - void SetPool(VDPool *pPool); - -protected: - VDPool *mpPool; - VDAtomicInt mRefCount; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_CACHE_H +#define f_VD2_SYSTEM_CACHE_H + +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +struct vdfixedhashmap_node { + vdfixedhashmap_node *mpHashPrev; + vdfixedhashmap_node *mpHashNext; +}; + +template +struct vdhash { + size_t operator()(const K key) const { + return (size_t)key; + } +}; + +template, int N = 256> +class vdfixedhashmap_iterator { +public: + typedef vdfixedhashmap_node node; + + bool operator==(vdfixedhashmap_iterator& x) const { return mpNode == x.mpNode; } + bool operator!=(vdfixedhashmap_iterator& x) const { return mpNode != x.mpNode; } + + V& operator*() const { return *static_cast((node *)mpNode); } + V *operator->() const { return static_cast((node *)mpNode); } + + vdfixedhashmap_iterator& operator++() { + do { + mpNode = ((node *)mpNode)->mpHashNext; + if (mpNode != mpTableNode) + break; + + ++mpTableNode; + mpNode = mpTableNode->mpHashNext; + } while(mpNode); + + return *this; + } + + vdfixedhashmap_iterator operator++(int) { + vdfixedhashmap_iterator it(*this); + ++*this; + return it; + } + +public: + vdfixedhashmap_node *mpNode; + vdfixedhashmap_node *mpTableNode; +}; + +template, int N = 256> +class vdfixedhashmap { +public: + typedef K key_type; + typedef V value_type; + typedef Hash hash_type; + typedef vdfixedhashmap_node node; + typedef vdfixedhashmap_iterator iterator; + + vdfixedhashmap() { + for(int i=0; impHashNext; p != r; p = p->mpHashNext) { + if (static_cast(p)->mHashKey == key) + return static_cast(p); + } + + return NULL; + } + + iterator find(const K& key) { + const size_t htidx = m(key) % N; + + node *r = &m.mpTable[htidx]; + for(node *p = r->mpHashNext; p != r; p = p->mpHashNext) { + if (static_cast(p)->mHashKey == key) { + iterator it = { p, &m.mpTable[htidx] }; + return it; + } + } + + return end(); + } + + iterator insert(V *p) { + const size_t htidx = m(p->mHashKey) % N; + + node *r = &m.mpTable[htidx]; + node *n = r->mpHashNext; + r->mpHashNext = p; + p->mpHashPrev = &m.mpTable[htidx]; + p->mpHashNext = n; + n->mpHashPrev = p; + + iterator it = { p, &m.mpTable[htidx] }; + return it; + } + + void erase(V *x) { + node *p = x->mpHashPrev; + node *n = x->mpHashNext; + + p->mpHashNext = n; + n->mpHashPrev = p; + } + + void erase(iterator it) { + erase(it.mpNode); + } + +protected: + struct Data : public Hash { + vdfixedhashmap_node mpTable[N]; + } m; +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDCachedObject; + +class IVDCacheAllocator { +public: + virtual VDCachedObject *OnCacheAllocate() = 0; +}; + +/////////////////////////////////////////////////////////////////////////// + +enum VDCacheState { + kVDCacheStateFree, + kVDCacheStatePending, + kVDCacheStateReady, + kVDCacheStateActive, + kVDCacheStateComplete, + kVDCacheStateIdle, + kVDCacheStateAborting, + kVDCacheStateCount +}; + +struct VDCachedObjectNodes : public vdlist_node, public vdfixedhashmap_node { + sint64 mHashKey; +}; + +class VDCache { +public: + VDCache(IVDCacheAllocator *pAllocator); + ~VDCache(); + + void Shutdown(); + + int GetStateCount(int state); + + void DumpListStatus(int state); + + VDCachedObject *Create(sint64 key, bool& is_new); + + VDCachedObject *Allocate(sint64 key); + void Schedule(VDCachedObject *); // Moves a Pending or Active object to Ready. + VDCachedObject *GetNextReady(); // Selects a Ready object and moves it to Active. + void MarkCompleted(VDCachedObject *); // Marks an object as completed. + +public: + void NotifyFree(VDCachedObject *pObject); + +protected: + void Evict(uint32 level); + +protected: + VDCriticalSection mLock; + + IVDCacheAllocator *mpAllocator; + uint32 mObjectCount; + uint32 mObjectLimit; + + typedef vdlist ObjectList; + ObjectList mLists[kVDCacheStateCount]; + + vdfixedhashmap mHash; +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDCachedObject : private VDCachedObjectNodes { + friend class VDCache; +public: + VDCachedObject(); + virtual ~VDCachedObject() {} + + int AddRef(); + int Release(); + + void WeakAddRef(); + void WeakRelease(); + +protected: + virtual void OnCacheEvict() {} + virtual void OnCacheAbortPending() {} + virtual void DumpStatus() {} + +protected: + int GetRefCount() const { return mRefCount; } + void SetCache(VDCache *pCache); + + VDCacheState GetState() const { return mState; } + void SetState(VDCacheState state) { mState = state; } + + sint64 GetCacheKey() const { return mHashKey; } + + virtual bool IsValid() const { return true; } + +protected: + VDCache *mpCache; + VDAtomicInt mRefCount; + VDCacheState mState; +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDPooledObject; + +class IVDPoolAllocator { +public: + virtual VDPooledObject *OnPoolAllocate() = 0; +}; + +/////////////////////////////////////////////////////////////////////////// + +enum VDPoolState { + kVDPoolStateFree, + kVDPoolStateActive, + kVDPoolStateCount +}; + +struct VDPooledObjectNodes : public vdlist_node {}; + +class VDPool { +public: + VDPool(IVDPoolAllocator *pAllocator); + ~VDPool(); + + void Shutdown(); + + VDPooledObject *Allocate(); + +public: + void NotifyFree(VDPooledObject *pObject); + +protected: + VDCriticalSection mLock; + + IVDPoolAllocator *mpAllocator; + uint32 mObjectCount; + uint32 mObjectLimit; + + typedef vdlist ObjectList; + ObjectList mLists[kVDPoolStateCount]; +}; + +class VDPooledObject : private VDPooledObjectNodes { + friend class VDPool; +public: + VDPooledObject(); + virtual ~VDPooledObject() {} + + int AddRef(); + int Release(); + +protected: + int GetRefCount() const { return mRefCount; } + void SetPool(VDPool *pPool); + +protected: + VDPool *mpPool; + VDAtomicInt mRefCount; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/cmdline.h b/src/thirdparty/VirtualDub/h/vd2/system/cmdline.h index 5194cae99ff..f4f217dd54b 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/cmdline.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/cmdline.h @@ -1,84 +1,84 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_CMDLINE_H -#define f_VD2_SYSTEM_CMDLINE_H - -#include - -class VDStringSpanW; - -class VDCommandLineIterator { - friend class VDCommandLine; -public: - VDCommandLineIterator() : mIndex(1) {} - -private: - int mIndex; -}; - -class VDCommandLine { -public: - VDCommandLine(); - VDCommandLine(const wchar_t *s); - ~VDCommandLine(); - - void Init(const wchar_t *s); - - // This splits the cmdline using rules that are closer to Visual C++'s: - // - 2N+1 backslashes followed by a quote inserts a literal quote. - // - 2N backslashes followed by a quote toggles the quote state. - // - Outside of a quote, spaces, tabs, and forward slashes delimit parameters. - // - // We still have special switch processing: - // - A parameter starting with a forward slash followed by a ? or an alphanumeric - // char is a switch. A switch is terminated by a non-alphanumeric character or - // a colon. - void InitAlt(const wchar_t *s); - - uint32 GetCount() const; - const wchar_t *operator[](int index) const; - const VDStringSpanW operator()(int index) const; - - bool GetNextArgument(VDCommandLineIterator& index, const wchar_t *& token, bool& isSwitch) const; - bool GetNextNonSwitchArgument(VDCommandLineIterator& index, const wchar_t *& token) const; - bool GetNextSwitchArgument(VDCommandLineIterator& index, const wchar_t *& token) const; - bool FindAndRemoveSwitch(const wchar_t *name); - bool FindAndRemoveSwitch(const wchar_t *name, const wchar_t *& token); - -protected: - void RemoveArgument(int index); - - vdfastvector mLine; - - struct Token { - int mTokenIndex; - bool mbIsSwitch; - }; - - vdfastvector mTokens; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_CMDLINE_H +#define f_VD2_SYSTEM_CMDLINE_H + +#include + +class VDStringSpanW; + +class VDCommandLineIterator { + friend class VDCommandLine; +public: + VDCommandLineIterator() : mIndex(1) {} + +private: + int mIndex; +}; + +class VDCommandLine { +public: + VDCommandLine(); + VDCommandLine(const wchar_t *s); + ~VDCommandLine(); + + void Init(const wchar_t *s); + + // This splits the cmdline using rules that are closer to Visual C++'s: + // - 2N+1 backslashes followed by a quote inserts a literal quote. + // - 2N backslashes followed by a quote toggles the quote state. + // - Outside of a quote, spaces, tabs, and forward slashes delimit parameters. + // + // We still have special switch processing: + // - A parameter starting with a forward slash followed by a ? or an alphanumeric + // char is a switch. A switch is terminated by a non-alphanumeric character or + // a colon. + void InitAlt(const wchar_t *s); + + uint32 GetCount() const; + const wchar_t *operator[](int index) const; + const VDStringSpanW operator()(int index) const; + + bool GetNextArgument(VDCommandLineIterator& index, const wchar_t *& token, bool& isSwitch) const; + bool GetNextNonSwitchArgument(VDCommandLineIterator& index, const wchar_t *& token) const; + bool GetNextSwitchArgument(VDCommandLineIterator& index, const wchar_t *& token) const; + bool FindAndRemoveSwitch(const wchar_t *name); + bool FindAndRemoveSwitch(const wchar_t *name, const wchar_t *& token); + +protected: + void RemoveArgument(int index); + + vdfastvector mLine; + + struct Token { + int mTokenIndex; + bool mbIsSwitch; + }; + + vdfastvector mTokens; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/cpuaccel.h b/src/thirdparty/VirtualDub/h/vd2/system/cpuaccel.h index ff34c2eda74..829de1c81c8 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/cpuaccel.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/cpuaccel.h @@ -1,51 +1,51 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VIRTUALDUB_CPUACCEL_H -#define f_VIRTUALDUB_CPUACCEL_H - -#define CPUF_SUPPORTS_CPUID (0x00000001L) -#define CPUF_SUPPORTS_FPU (0x00000002L) -#define CPUF_SUPPORTS_MMX (0x00000004L) -#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) -#define CPUF_SUPPORTS_SSE (0x00000010L) -#define CPUF_SUPPORTS_SSE2 (0x00000020L) -#define CPUF_SUPPORTS_3DNOW (0x00000040L) -#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) -#define CPUF_SUPPORTS_SSE3 (0x00000100L) -#define CPUF_SUPPORTS_SSSE3 (0x00000200L) -#define CPUF_SUPPORTS_SSE41 (0x00000400L) -#define CPUF_SUPPORTS_AVX (0x00000800L) -#define CPUF_SUPPORTS_SSE42 (0x00001000L) -#define CPUF_SUPPORTS_MASK (0x00001FFFL) - -long CPUCheckForExtensions(); -long CPUEnableExtensions(long lEnableFlags); -long CPUGetEnabledExtensions(); -void VDCPUCleanupExtensions(); - -extern "C" bool FPU_enabled, MMX_enabled, SSE_enabled, ISSE_enabled, SSE2_enabled; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VIRTUALDUB_CPUACCEL_H +#define f_VIRTUALDUB_CPUACCEL_H + +#define CPUF_SUPPORTS_CPUID (0x00000001L) +#define CPUF_SUPPORTS_FPU (0x00000002L) +#define CPUF_SUPPORTS_MMX (0x00000004L) +#define CPUF_SUPPORTS_INTEGER_SSE (0x00000008L) +#define CPUF_SUPPORTS_SSE (0x00000010L) +#define CPUF_SUPPORTS_SSE2 (0x00000020L) +#define CPUF_SUPPORTS_3DNOW (0x00000040L) +#define CPUF_SUPPORTS_3DNOW_EXT (0x00000080L) +#define CPUF_SUPPORTS_SSE3 (0x00000100L) +#define CPUF_SUPPORTS_SSSE3 (0x00000200L) +#define CPUF_SUPPORTS_SSE41 (0x00000400L) +#define CPUF_SUPPORTS_AVX (0x00000800L) +#define CPUF_SUPPORTS_SSE42 (0x00001000L) +#define CPUF_SUPPORTS_MASK (0x00001FFFL) + +long CPUCheckForExtensions(); +long CPUEnableExtensions(long lEnableFlags); +long CPUGetEnabledExtensions(); +void VDCPUCleanupExtensions(); + +extern "C" bool FPU_enabled, MMX_enabled, SSE_enabled, ISSE_enabled, SSE2_enabled; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/debug.h b/src/thirdparty/VirtualDub/h/vd2/system/debug.h index 6ce397361a1..a4eb59e60f2 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/debug.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/debug.h @@ -1,96 +1,96 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_DEBUG_H -#define f_VD2_SYSTEM_DEBUG_H - -#include - -class IVDExternalCallTrap { -public: - virtual void OnMMXTrap(const wchar_t *context, const char *file, int line) = 0; - virtual void OnFPUTrap(const wchar_t *context, const char *file, int line, uint16 fpucw) = 0; - virtual void OnSSETrap(const wchar_t *context, const char *file, int line, uint32 mxcsr) = 0; -}; - -void VDSetExternalCallTrap(IVDExternalCallTrap *); - -bool IsMMXState(); -void ClearMMXState(); -void VDClearEvilCPUStates(); -void VDPreCheckExternalCodeCall(const char *file, int line); -void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine); - -struct VDSilentExternalCodeBracket { - VDSilentExternalCodeBracket() { - VDClearEvilCPUStates(); - } - - ~VDSilentExternalCodeBracket() { - VDClearEvilCPUStates(); - } -}; - -struct VDExternalCodeBracketLocation { - VDExternalCodeBracketLocation(const wchar_t *pContext, const char *file, const int line) - : mpContext(pContext) - , mpFile(file) - , mLine(line) - { - } - - const wchar_t *mpContext; - const char *mpFile; - const int mLine; -}; - -struct VDExternalCodeBracket { - VDExternalCodeBracket(const wchar_t *pContext, const char *file, const int line) - : mpContext(pContext) - , mpFile(file) - , mLine(line) - { - VDPreCheckExternalCodeCall(file, line); - } - - VDExternalCodeBracket(const VDExternalCodeBracketLocation& loc) - : mpContext(loc.mpContext) - , mpFile(loc.mpFile) - , mLine(loc.mLine) - { - } - - ~VDExternalCodeBracket() { - VDPostCheckExternalCodeCall(mpContext, mpFile, mLine); - } - - operator bool() const { return false; } - - const wchar_t *mpContext; - const char *mpFile; - const int mLine; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_DEBUG_H +#define f_VD2_SYSTEM_DEBUG_H + +#include + +class IVDExternalCallTrap { +public: + virtual void OnMMXTrap(const wchar_t *context, const char *file, int line) = 0; + virtual void OnFPUTrap(const wchar_t *context, const char *file, int line, uint16 fpucw) = 0; + virtual void OnSSETrap(const wchar_t *context, const char *file, int line, uint32 mxcsr) = 0; +}; + +void VDSetExternalCallTrap(IVDExternalCallTrap *); + +bool IsMMXState(); +void ClearMMXState(); +void VDClearEvilCPUStates(); +void VDPreCheckExternalCodeCall(const char *file, int line); +void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine); + +struct VDSilentExternalCodeBracket { + VDSilentExternalCodeBracket() { + VDClearEvilCPUStates(); + } + + ~VDSilentExternalCodeBracket() { + VDClearEvilCPUStates(); + } +}; + +struct VDExternalCodeBracketLocation { + VDExternalCodeBracketLocation(const wchar_t *pContext, const char *file, const int line) + : mpContext(pContext) + , mpFile(file) + , mLine(line) + { + } + + const wchar_t *mpContext; + const char *mpFile; + const int mLine; +}; + +struct VDExternalCodeBracket { + VDExternalCodeBracket(const wchar_t *pContext, const char *file, const int line) + : mpContext(pContext) + , mpFile(file) + , mLine(line) + { + VDPreCheckExternalCodeCall(file, line); + } + + VDExternalCodeBracket(const VDExternalCodeBracketLocation& loc) + : mpContext(loc.mpContext) + , mpFile(loc.mpFile) + , mLine(loc.mLine) + { + } + + ~VDExternalCodeBracket() { + VDPostCheckExternalCodeCall(mpContext, mpFile, mLine); + } + + operator bool() const { return false; } + + const wchar_t *mpContext; + const char *mpFile; + const int mLine; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/debugx86.h b/src/thirdparty/VirtualDub/h/vd2/system/debugx86.h index 06e1d711cb6..03a4f29a33c 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/debugx86.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/debugx86.h @@ -1,37 +1,37 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -enum VDInstructionTypeX86 { - kX86InstUnknown, - kX86InstP6, - kX86InstMMX, - kX86InstMMX2, - kX86InstSSE, - kX86InstSSE2, - kX86Inst3DNow -}; - -bool VDIsValidCallX86(const char *buf, int len); -VDInstructionTypeX86 VDGetInstructionTypeX86(const void *p); +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +enum VDInstructionTypeX86 { + kX86InstUnknown, + kX86InstP6, + kX86InstMMX, + kX86InstMMX2, + kX86InstSSE, + kX86InstSSE2, + kX86Inst3DNow +}; + +bool VDIsValidCallX86(const char *buf, int len); +VDInstructionTypeX86 VDGetInstructionTypeX86(const void *p); diff --git a/src/thirdparty/VirtualDub/h/vd2/system/event.h b/src/thirdparty/VirtualDub/h/vd2/system/event.h index 0af4c436d50..66e5394feb4 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/event.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/event.h @@ -1,199 +1,199 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_EVENT_H -#define f_VD2_SYSTEM_EVENT_H - -// Because Visual C++ uses different pointer-to-member representations for -// different inheritance regimes, we have to include a whole lot of stupid -// logic to detect and switch code paths based on the inheritance used. -// We detect the inheritance by the size of the member function pointer. -// -// Some have managed to make faster and more compact delegates by hacking -// into the PMT representation and pre-folding the this pointer adjustment. -// I'm avoiding this for now because (a) it's even less portable than what -// we have here, and (b) that fails if the object undergoes a change in -// virtual table status while the delegate is alive (which is possible -// during construction/destruction). -// -// Note: We can't handle virtual inheritance here because on X64, MSVC uses -// 16 bytes for both multiple and virtual inheritance cases. - -#ifdef _MSC_VER - class __single_inheritance VDDelegateHolderS; - class __multiple_inheritance VDDelegateHolderM; -#else - class VDDelegateHolderS; -#endif - -class VDDelegate; - -struct VDDelegateNode { - VDDelegateNode *mpNext, *mpPrev; - - void (*mpCallback)(void *src, const void *info, VDDelegateNode&); - void *mpObj; - -#ifdef _MSC_VER - union { - void (VDDelegateHolderS::*mpFnS)(); - void (VDDelegateHolderM::*mpFnM)(); - }; -#else - void (VDDelegateHolderS::*mpFnS)(); -#endif -}; - -class VDEventBase { -protected: - VDEventBase(); - ~VDEventBase(); - - void Add(VDDelegate&); - void Remove(VDDelegate&); - void Raise(void *src, const void *info); - - VDDelegateNode mAnchor; -}; - -template -class VDDelegateBinding { -public: - VDDelegate *mpBoundDelegate; -}; - -template -struct VDDelegateAdapterS { - typedef void (T::*T_Fn)(Source *, const ArgType&); - typedef void (T::*T_Fn2)(Source *, ArgType); - - static void Init(VDDelegateNode& dst, T_Fn fn) { - dst.mpCallback = Fn; - dst.mpFnS = reinterpret_cast(fn); - } - - static void Init(VDDelegateNode& dst, T_Fn2 fn) { - dst.mpCallback = Fn2; - dst.mpFnS = reinterpret_cast(fn); - } - - static void Fn(void *src, const void *info, VDDelegateNode& del) { - return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnS))(static_cast(src), *static_cast(info)); - } - - static void Fn2(void *src, const void *info, VDDelegateNode& del) { - return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnS))(static_cast(src), *static_cast(info)); - } -}; - -template -class VDDelegateAdapter { -public: - template - struct AdapterLookup { - typedef VDDelegateAdapterS result; - }; -}; - -#ifdef _MSC_VER -template -struct VDDelegateAdapterM { - typedef void (T::*T_Fn)(Source *, const ArgType&); - typedef void (T::*T_Fn2)(Source *, ArgType); - - static void Init(VDDelegateNode& dst, T_Fn fn) { - dst.mpCallback = Fn; - dst.mpFnM = reinterpret_cast(fn); - } - - static void Init(VDDelegateNode& dst, T_Fn2 fn) { - dst.mpCallback = Fn2; - dst.mpFnM = reinterpret_cast(fn); - } - - static void Fn(void *src, const void *info, VDDelegateNode& del) { - return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnM))(static_cast(src), *static_cast(info)); - } - - static void Fn2(void *src, const void *info, VDDelegateNode& del) { - return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnM))(static_cast(src), *static_cast(info)); - } -}; - - -template<> -class VDDelegateAdapter { -public: - template - struct AdapterLookup { - typedef VDDelegateAdapterM result; - }; -}; -#endif - -class VDDelegate : public VDDelegateNode { - friend class VDEventBase; -public: - VDDelegate(); - ~VDDelegate(); - - template - VDDelegateBinding operator()(T *obj, void (T::*fn)(Source *, const ArgType&)) { - mpObj = obj; - - VDDelegateAdapter::template AdapterLookup::result::Init(*this, fn); - - VDDelegateBinding binding = {this}; - return binding; - } - - template - VDDelegateBinding Bind(T *obj, void (T::*fn)(Source *, ArgType)) { - mpObj = obj; - - VDDelegateAdapter::template AdapterLookup::result::Init(*this, fn); - - VDDelegateBinding binding = {this}; - return binding; - } -}; - -template -class VDEvent : public VDEventBase { -public: - void operator+=(const VDDelegateBinding& binding) { - Add(*binding.mpBoundDelegate); - } - - void operator-=(VDDelegate& del) { - Remove(del); - } - - void Raise(Source *src, const ArgType& args) { - VDEventBase::Raise(src, &args); - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_EVENT_H +#define f_VD2_SYSTEM_EVENT_H + +// Because Visual C++ uses different pointer-to-member representations for +// different inheritance regimes, we have to include a whole lot of stupid +// logic to detect and switch code paths based on the inheritance used. +// We detect the inheritance by the size of the member function pointer. +// +// Some have managed to make faster and more compact delegates by hacking +// into the PMT representation and pre-folding the this pointer adjustment. +// I'm avoiding this for now because (a) it's even less portable than what +// we have here, and (b) that fails if the object undergoes a change in +// virtual table status while the delegate is alive (which is possible +// during construction/destruction). +// +// Note: We can't handle virtual inheritance here because on X64, MSVC uses +// 16 bytes for both multiple and virtual inheritance cases. + +#ifdef _MSC_VER + class __single_inheritance VDDelegateHolderS; + class __multiple_inheritance VDDelegateHolderM; +#else + class VDDelegateHolderS; +#endif + +class VDDelegate; + +struct VDDelegateNode { + VDDelegateNode *mpNext, *mpPrev; + + void (*mpCallback)(void *src, const void *info, VDDelegateNode&); + void *mpObj; + +#ifdef _MSC_VER + union { + void (VDDelegateHolderS::*mpFnS)(); + void (VDDelegateHolderM::*mpFnM)(); + }; +#else + void (VDDelegateHolderS::*mpFnS)(); +#endif +}; + +class VDEventBase { +protected: + VDEventBase(); + ~VDEventBase(); + + void Add(VDDelegate&); + void Remove(VDDelegate&); + void Raise(void *src, const void *info); + + VDDelegateNode mAnchor; +}; + +template +class VDDelegateBinding { +public: + VDDelegate *mpBoundDelegate; +}; + +template +struct VDDelegateAdapterS { + typedef void (T::*T_Fn)(Source *, const ArgType&); + typedef void (T::*T_Fn2)(Source *, ArgType); + + static void Init(VDDelegateNode& dst, T_Fn fn) { + dst.mpCallback = Fn; + dst.mpFnS = reinterpret_cast(fn); + } + + static void Init(VDDelegateNode& dst, T_Fn2 fn) { + dst.mpCallback = Fn2; + dst.mpFnS = reinterpret_cast(fn); + } + + static void Fn(void *src, const void *info, VDDelegateNode& del) { + return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnS))(static_cast(src), *static_cast(info)); + } + + static void Fn2(void *src, const void *info, VDDelegateNode& del) { + return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnS))(static_cast(src), *static_cast(info)); + } +}; + +template +class VDDelegateAdapter { +public: + template + struct AdapterLookup { + typedef VDDelegateAdapterS result; + }; +}; + +#ifdef _MSC_VER +template +struct VDDelegateAdapterM { + typedef void (T::*T_Fn)(Source *, const ArgType&); + typedef void (T::*T_Fn2)(Source *, ArgType); + + static void Init(VDDelegateNode& dst, T_Fn fn) { + dst.mpCallback = Fn; + dst.mpFnM = reinterpret_cast(fn); + } + + static void Init(VDDelegateNode& dst, T_Fn2 fn) { + dst.mpCallback = Fn2; + dst.mpFnM = reinterpret_cast(fn); + } + + static void Fn(void *src, const void *info, VDDelegateNode& del) { + return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnM))(static_cast(src), *static_cast(info)); + } + + static void Fn2(void *src, const void *info, VDDelegateNode& del) { + return (((T *)del.mpObj)->*reinterpret_cast(del.mpFnM))(static_cast(src), *static_cast(info)); + } +}; + + +template<> +class VDDelegateAdapter { +public: + template + struct AdapterLookup { + typedef VDDelegateAdapterM result; + }; +}; +#endif + +class VDDelegate : public VDDelegateNode { + friend class VDEventBase; +public: + VDDelegate(); + ~VDDelegate(); + + template + VDDelegateBinding operator()(T *obj, void (T::*fn)(Source *, const ArgType&)) { + mpObj = obj; + + VDDelegateAdapter::template AdapterLookup::result::Init(*this, fn); + + VDDelegateBinding binding = {this}; + return binding; + } + + template + VDDelegateBinding Bind(T *obj, void (T::*fn)(Source *, ArgType)) { + mpObj = obj; + + VDDelegateAdapter::template AdapterLookup::result::Init(*this, fn); + + VDDelegateBinding binding = {this}; + return binding; + } +}; + +template +class VDEvent : public VDEventBase { +public: + void operator+=(const VDDelegateBinding& binding) { + Add(*binding.mpBoundDelegate); + } + + void operator-=(VDDelegate& del) { + Remove(del); + } + + void Raise(Source *src, const ArgType& args) { + VDEventBase::Raise(src, &args); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/file.h b/src/thirdparty/VirtualDub/h/vd2/system/file.h index 53aeae75800..4ee3d77a062 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/file.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/file.h @@ -1,327 +1,327 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_FILE_H -#define f_VD2_SYSTEM_FILE_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include -#include -#include -#include - -#ifdef WIN32 - typedef void *VDFileHandle; // this needs to match wtypes.h definition for HANDLE -#else - #error No operating system target declared?? -#endif - -namespace nsVDFile { - enum eSeekMode { - kSeekStart=0, kSeekCur, kSeekEnd - }; - - enum eFlags { - kRead = 0x00000001, - kWrite = 0x00000002, - kReadWrite = kRead | kWrite, - - kDenyNone = 0x00000000, - kDenyRead = 0x00000010, - kDenyWrite = 0x00000020, - kDenyAll = kDenyRead | kDenyWrite, - - kOpenExisting = 0x00000100, - kOpenAlways = 0x00000200, - kCreateAlways = 0x00000300, - kCreateNew = 0x00000400, - kTruncateExisting = 0x00000500, // not particularly useful, really - kCreationMask = 0x0000FF00, - - kSequential = 0x00010000, - kRandomAccess = 0x00020000, - kUnbuffered = 0x00040000, // much faster on Win32 thanks to the crappy cache, but possibly bad in Unix? - kWriteThrough = 0x00080000, - - kAllFileFlags = 0xFFFFFFFF - }; -}; - -class VDFile { -protected: - VDFileHandle mhFile; - vdautoptr2 mpFilename; - sint64 mFilePosition; - -private: - VDFile(const VDFile&); - const VDFile& operator=(const VDFile& f); - -public: - VDFile() : mhFile(NULL) {} - VDFile(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - VDFile(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - VDFile(VDFileHandle h); - ~VDFile(); - - // The "NT" functions are non-throwing and return success/failure; the regular functions throw exceptions - // when something bad happens. - - void open(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - void open(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - - bool openNT(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); - - bool closeNT(); - void close(); - bool truncateNT(); - void truncate(); - - // extendValid() pushes the valid threshold of a file out, so that the system allocates - // space for a file without ensuring that it is cleared. It is mainly useful for - // preallocating a file without waiting for the system to clear all of it. The caveats: - // - // - only required on NTFS - // - requires Windows XP or Windows Server 2003 - // - does not work on compressed or sparse files - // - // As such, it shouldn't normally be relied upon, and extendValidNT() should be the call - // of choice. - // - // enableExtendValid() must be called beforehand, as SeVolumeNamePrivilege must be - // enabled on the process before the file is opened! - - bool extendValidNT(sint64 pos); - void extendValid(sint64 pos); - static bool enableExtendValid(); - - sint64 size(); - void read(void *buffer, long length); - long readData(void *buffer, long length); - void write(const void *buffer, long length); - long writeData(const void *buffer, long length); - bool seekNT(sint64 newPos, nsVDFile::eSeekMode mode = nsVDFile::kSeekStart); - void seek(sint64 newPos, nsVDFile::eSeekMode mode = nsVDFile::kSeekStart); - bool skipNT(sint64 delta); - void skip(sint64 delta); - sint64 tell(); - - bool flushNT(); - void flush(); - - bool isOpen(); - VDFileHandle getRawHandle(); - - const wchar_t *getFilenameForError() const { return mpFilename; } - - // unbuffered I/O requires aligned buffers ("unbuffers") - static void *AllocUnbuffer(size_t nBytes); - static void FreeUnbuffer(void *p); - -protected: - bool open_internal(const char *pszFilename, const wchar_t *pwszFilename, uint32 flags, bool throwOnError); -}; - -/////////////////////////////////////////////////////////////////////////// - -template -class VDFileUnbufferAllocator { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template struct rebind { typedef VDFileUnbufferAllocator other; }; - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, void *p = 0) { return (pointer)VDFile::AllocUnbuffer(n * sizeof(T)); } - void deallocate(pointer p, size_type n) { VDFile::FreeUnbuffer(p); } - size_type max_size() const throw() { return INT_MAX; } - - void construct(pointer p, const T& val) { new((void *)p) T(val); } - void destroy(pointer p) { ((T*)p)->~T(); } - -#if defined(_MSC_VER) && _MSC_VER < 1300 - char * _Charalloc(size_type n) { return (char *)allocate((n + sizeof(T) - 1) / sizeof(T)); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////// - -class IVDStream { -public: - virtual const wchar_t *GetNameForError() = 0; - virtual sint64 Pos() = 0; - virtual void Read(void *buffer, sint32 bytes) = 0; - virtual sint32 ReadData(void *buffer, sint32 bytes) = 0; - virtual void Write(const void *buffer, sint32 bytes) = 0; -}; - -class IVDRandomAccessStream : public IVDStream { -public: - virtual sint64 Length() = 0; - virtual void Seek(sint64 offset) = 0; -}; - -class VDFileStream : public VDFile, public IVDRandomAccessStream { -private: - VDFileStream(const VDFile&); - const VDFileStream& operator=(const VDFileStream& f); - -public: - VDFileStream() {} - VDFileStream(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting) - : VDFile(pszFileName, flags) {} - VDFileStream(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting) - : VDFile(pwszFileName, flags) {} - VDFileStream(VDFileHandle h) : VDFile(h) {} - ~VDFileStream(); - - const wchar_t *GetNameForError(); - sint64 Pos(); - void Read(void *buffer, sint32 bytes); - sint32 ReadData(void *buffer, sint32 bytes); - void Write(const void *buffer, sint32 bytes); - sint64 Length(); - void Seek(sint64 offset); -}; - -class VDMemoryStream : public IVDRandomAccessStream { -public: - VDMemoryStream(const void *pSrc, uint32 len); - - const wchar_t *GetNameForError(); - sint64 Pos(); - void Read(void *buffer, sint32 bytes); - sint32 ReadData(void *buffer, sint32 bytes); - void Write(const void *buffer, sint32 bytes); - sint64 Length(); - void Seek(sint64 offset); - -protected: - const char *mpSrc; - const uint32 mLength; - uint32 mPos; -}; - -class VDBufferedStream : public IVDRandomAccessStream { -public: - VDBufferedStream(IVDRandomAccessStream *pSrc, uint32 bufferSize); - ~VDBufferedStream(); - - const wchar_t *GetNameForError(); - sint64 Pos(); - void Read(void *buffer, sint32 bytes); - sint32 ReadData(void *buffer, sint32 bytes); - void Write(const void *buffer, sint32 bytes); - - sint64 Length(); - void Seek(sint64 offset); - - void Skip(sint64 size); - -protected: - IVDRandomAccessStream *mpSrc; - vdblock mBuffer; - sint64 mBasePosition; - uint32 mBufferOffset; - uint32 mBufferValidSize; -}; - -class VDTextStream { -public: - VDTextStream(IVDStream *pSrc); - ~VDTextStream(); - - const char *GetNextLine(); - -protected: - IVDStream *mpSrc; - uint32 mBufferPos; - uint32 mBufferLimit; - enum { - kFetchLine, - kEatNextIfCR, - kEatNextIfLF - } mState; - - enum { - kFileBufferSize = 4096 - }; - - vdfastvector mLineBuffer; - vdblock mFileBuffer; -}; - -class VDTextInputFile { -public: - VDTextInputFile(const wchar_t *filename, uint32 flags = nsVDFile::kOpenExisting); - ~VDTextInputFile(); - - inline const char *GetNextLine() { - return mTextStream.GetNextLine(); - } - -protected: - VDFileStream mFileStream; - VDTextStream mTextStream; -}; - -class VDTextOutputStream { -public: - VDTextOutputStream(IVDStream *stream); - ~VDTextOutputStream(); - - void Flush(); - - void Write(const char *s); - void Write(const char *s, int len); - void PutLine(); - void PutLine(const char *s); - void Format(const char *format, ...); - void FormatLine(const char *format, ...); - -protected: - void Format2(const char *format, va_list val); - void PutData(const char *s, int len); - - enum { kBufSize = 4096 }; - - int mLevel; - IVDStream *mpDst; - char mBuf[kBufSize]; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_FILE_H +#define f_VD2_SYSTEM_FILE_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include +#include +#include + +#ifdef WIN32 + typedef void *VDFileHandle; // this needs to match wtypes.h definition for HANDLE +#else + #error No operating system target declared?? +#endif + +namespace nsVDFile { + enum eSeekMode { + kSeekStart=0, kSeekCur, kSeekEnd + }; + + enum eFlags { + kRead = 0x00000001, + kWrite = 0x00000002, + kReadWrite = kRead | kWrite, + + kDenyNone = 0x00000000, + kDenyRead = 0x00000010, + kDenyWrite = 0x00000020, + kDenyAll = kDenyRead | kDenyWrite, + + kOpenExisting = 0x00000100, + kOpenAlways = 0x00000200, + kCreateAlways = 0x00000300, + kCreateNew = 0x00000400, + kTruncateExisting = 0x00000500, // not particularly useful, really + kCreationMask = 0x0000FF00, + + kSequential = 0x00010000, + kRandomAccess = 0x00020000, + kUnbuffered = 0x00040000, // much faster on Win32 thanks to the crappy cache, but possibly bad in Unix? + kWriteThrough = 0x00080000, + + kAllFileFlags = 0xFFFFFFFF + }; +}; + +class VDFile { +protected: + VDFileHandle mhFile; + vdautoptr2 mpFilename; + sint64 mFilePosition; + +private: + VDFile(const VDFile&); + const VDFile& operator=(const VDFile& f); + +public: + VDFile() : mhFile(NULL) {} + VDFile(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + VDFile(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + VDFile(VDFileHandle h); + ~VDFile(); + + // The "NT" functions are non-throwing and return success/failure; the regular functions throw exceptions + // when something bad happens. + + void open(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + void open(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + + bool openNT(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); + + bool closeNT(); + void close(); + bool truncateNT(); + void truncate(); + + // extendValid() pushes the valid threshold of a file out, so that the system allocates + // space for a file without ensuring that it is cleared. It is mainly useful for + // preallocating a file without waiting for the system to clear all of it. The caveats: + // + // - only required on NTFS + // - requires Windows XP or Windows Server 2003 + // - does not work on compressed or sparse files + // + // As such, it shouldn't normally be relied upon, and extendValidNT() should be the call + // of choice. + // + // enableExtendValid() must be called beforehand, as SeVolumeNamePrivilege must be + // enabled on the process before the file is opened! + + bool extendValidNT(sint64 pos); + void extendValid(sint64 pos); + static bool enableExtendValid(); + + sint64 size(); + void read(void *buffer, long length); + long readData(void *buffer, long length); + void write(const void *buffer, long length); + long writeData(const void *buffer, long length); + bool seekNT(sint64 newPos, nsVDFile::eSeekMode mode = nsVDFile::kSeekStart); + void seek(sint64 newPos, nsVDFile::eSeekMode mode = nsVDFile::kSeekStart); + bool skipNT(sint64 delta); + void skip(sint64 delta); + sint64 tell(); + + bool flushNT(); + void flush(); + + bool isOpen(); + VDFileHandle getRawHandle(); + + const wchar_t *getFilenameForError() const { return mpFilename; } + + // unbuffered I/O requires aligned buffers ("unbuffers") + static void *AllocUnbuffer(size_t nBytes); + static void FreeUnbuffer(void *p); + +protected: + bool open_internal(const char *pszFilename, const wchar_t *pwszFilename, uint32 flags, bool throwOnError); +}; + +/////////////////////////////////////////////////////////////////////////// + +template +class VDFileUnbufferAllocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template struct rebind { typedef VDFileUnbufferAllocator other; }; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, void *p = 0) { return (pointer)VDFile::AllocUnbuffer(n * sizeof(T)); } + void deallocate(pointer p, size_type n) { VDFile::FreeUnbuffer(p); } + size_type max_size() const throw() { return INT_MAX; } + + void construct(pointer p, const T& val) { new((void *)p) T(val); } + void destroy(pointer p) { ((T*)p)->~T(); } + +#if defined(_MSC_VER) && _MSC_VER < 1300 + char * _Charalloc(size_type n) { return (char *)allocate((n + sizeof(T) - 1) / sizeof(T)); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////// + +class IVDStream { +public: + virtual const wchar_t *GetNameForError() = 0; + virtual sint64 Pos() = 0; + virtual void Read(void *buffer, sint32 bytes) = 0; + virtual sint32 ReadData(void *buffer, sint32 bytes) = 0; + virtual void Write(const void *buffer, sint32 bytes) = 0; +}; + +class IVDRandomAccessStream : public IVDStream { +public: + virtual sint64 Length() = 0; + virtual void Seek(sint64 offset) = 0; +}; + +class VDFileStream : public VDFile, public IVDRandomAccessStream { +private: + VDFileStream(const VDFile&); + const VDFileStream& operator=(const VDFileStream& f); + +public: + VDFileStream() {} + VDFileStream(const char *pszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting) + : VDFile(pszFileName, flags) {} + VDFileStream(const wchar_t *pwszFileName, uint32 flags = nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting) + : VDFile(pwszFileName, flags) {} + VDFileStream(VDFileHandle h) : VDFile(h) {} + ~VDFileStream(); + + const wchar_t *GetNameForError(); + sint64 Pos(); + void Read(void *buffer, sint32 bytes); + sint32 ReadData(void *buffer, sint32 bytes); + void Write(const void *buffer, sint32 bytes); + sint64 Length(); + void Seek(sint64 offset); +}; + +class VDMemoryStream : public IVDRandomAccessStream { +public: + VDMemoryStream(const void *pSrc, uint32 len); + + const wchar_t *GetNameForError(); + sint64 Pos(); + void Read(void *buffer, sint32 bytes); + sint32 ReadData(void *buffer, sint32 bytes); + void Write(const void *buffer, sint32 bytes); + sint64 Length(); + void Seek(sint64 offset); + +protected: + const char *mpSrc; + const uint32 mLength; + uint32 mPos; +}; + +class VDBufferedStream : public IVDRandomAccessStream { +public: + VDBufferedStream(IVDRandomAccessStream *pSrc, uint32 bufferSize); + ~VDBufferedStream(); + + const wchar_t *GetNameForError(); + sint64 Pos(); + void Read(void *buffer, sint32 bytes); + sint32 ReadData(void *buffer, sint32 bytes); + void Write(const void *buffer, sint32 bytes); + + sint64 Length(); + void Seek(sint64 offset); + + void Skip(sint64 size); + +protected: + IVDRandomAccessStream *mpSrc; + vdblock mBuffer; + sint64 mBasePosition; + uint32 mBufferOffset; + uint32 mBufferValidSize; +}; + +class VDTextStream { +public: + VDTextStream(IVDStream *pSrc); + ~VDTextStream(); + + const char *GetNextLine(); + +protected: + IVDStream *mpSrc; + uint32 mBufferPos; + uint32 mBufferLimit; + enum { + kFetchLine, + kEatNextIfCR, + kEatNextIfLF + } mState; + + enum { + kFileBufferSize = 4096 + }; + + vdfastvector mLineBuffer; + vdblock mFileBuffer; +}; + +class VDTextInputFile { +public: + VDTextInputFile(const wchar_t *filename, uint32 flags = nsVDFile::kOpenExisting); + ~VDTextInputFile(); + + inline const char *GetNextLine() { + return mTextStream.GetNextLine(); + } + +protected: + VDFileStream mFileStream; + VDTextStream mTextStream; +}; + +class VDTextOutputStream { +public: + VDTextOutputStream(IVDStream *stream); + ~VDTextOutputStream(); + + void Flush(); + + void Write(const char *s); + void Write(const char *s, int len); + void PutLine(); + void PutLine(const char *s); + void Format(const char *format, ...); + void FormatLine(const char *format, ...); + +protected: + void Format2(const char *format, va_list val); + void PutData(const char *s, int len); + + enum { kBufSize = 4096 }; + + int mLevel; + IVDStream *mpDst; + char mBuf[kBufSize]; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/fileasync.h b/src/thirdparty/VirtualDub/h/vd2/system/fileasync.h index de0ed37a501..753d3488f39 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/fileasync.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/fileasync.h @@ -1,67 +1,67 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_FILEASYNC_H -#define f_VD2_SYSTEM_FILEASYNC_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include - -class VDRTProfileChannel; - -class IVDFileAsync { -public: - enum Mode { - kModeSynchronous, ///< Use synchronous I/O. - kModeThreaded, ///< Use multithreaded I/O. - kModeAsynchronous, ///< Use true asynchronous I/O (Windows NT only). - kModeBuffered, ///< Use regular buffered synchronous I/O - kModeCount - }; - - virtual ~IVDFileAsync() {} - virtual void SetPreemptiveExtend(bool b) = 0; - virtual bool IsPreemptiveExtendActive() = 0; - virtual bool IsOpen() = 0; - virtual void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) = 0; - virtual void Open(VDFileHandle h, uint32 count, uint32 bufferSize) = 0; - virtual void Close() = 0; - virtual void FastWrite(const void *pData, uint32 bytes) = 0; - virtual void FastWriteEnd() = 0; - virtual void Write(sint64 pos, const void *pData, uint32 bytes) = 0; - virtual bool Extend(sint64 pos) = 0; - virtual void Truncate(sint64 pos) = 0; - virtual void SafeTruncateAndClose(sint64 pos) = 0; - virtual sint64 GetFastWritePos() = 0; - virtual sint64 GetSize() = 0; -}; - -IVDFileAsync *VDCreateFileAsync(IVDFileAsync::Mode); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_FILEASYNC_H +#define f_VD2_SYSTEM_FILEASYNC_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include + +class VDRTProfileChannel; + +class IVDFileAsync { +public: + enum Mode { + kModeSynchronous, ///< Use synchronous I/O. + kModeThreaded, ///< Use multithreaded I/O. + kModeAsynchronous, ///< Use true asynchronous I/O (Windows NT only). + kModeBuffered, ///< Use regular buffered synchronous I/O + kModeCount + }; + + virtual ~IVDFileAsync() {} + virtual void SetPreemptiveExtend(bool b) = 0; + virtual bool IsPreemptiveExtendActive() = 0; + virtual bool IsOpen() = 0; + virtual void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) = 0; + virtual void Open(VDFileHandle h, uint32 count, uint32 bufferSize) = 0; + virtual void Close() = 0; + virtual void FastWrite(const void *pData, uint32 bytes) = 0; + virtual void FastWriteEnd() = 0; + virtual void Write(sint64 pos, const void *pData, uint32 bytes) = 0; + virtual bool Extend(sint64 pos) = 0; + virtual void Truncate(sint64 pos) = 0; + virtual void SafeTruncateAndClose(sint64 pos) = 0; + virtual sint64 GetFastWritePos() = 0; + virtual sint64 GetSize() = 0; +}; + +IVDFileAsync *VDCreateFileAsync(IVDFileAsync::Mode); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/halffloat.h b/src/thirdparty/VirtualDub/h/vd2/system/halffloat.h index df7ab9483ab..e65a4109c53 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/halffloat.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/halffloat.h @@ -1,9 +1,9 @@ -#ifndef f_VD2_SYSTEM_HALFFLOAT_H -#define f_VD2_SYSTEM_HALFFLOAT_H - -#include - -uint16 VDConvertFloatToHalf(const void *f); -void VDConvertHalfToFloat(uint16 h, void *dst); - -#endif // f_VD2_SYSTEM_HALFFLOAT_H +#ifndef f_VD2_SYSTEM_HALFFLOAT_H +#define f_VD2_SYSTEM_HALFFLOAT_H + +#include + +uint16 VDConvertFloatToHalf(const void *f); +void VDConvertHalfToFloat(uint16 h, void *dst); + +#endif // f_VD2_SYSTEM_HALFFLOAT_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/hash.h b/src/thirdparty/VirtualDub/h/vd2/system/hash.h index a26c1ead760..9b93f3e2c75 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/hash.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/hash.h @@ -1,51 +1,51 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_HASH_H -#define f_VD2_SYSTEM_HASH_H - -#ifdef _MSC_VER - #pragma once -#endif - -#ifndef f_VD2_SYSTEM_VDTYPES_H - #include -#endif - -// Case-sensitive string hashes - -uint32 VDHashString32(const char *s); -uint32 VDHashString32(const char *s, uint32 len); -uint32 VDHashString32(const wchar_t *s); -uint32 VDHashString32(const wchar_t *s, uint32 len); - -// Case-insensitive, culture-invariant string hashes - -uint32 VDHashString32I(const char *s); -uint32 VDHashString32I(const char *s, uint32 len); -uint32 VDHashString32I(const wchar_t *s); -uint32 VDHashString32I(const wchar_t *s, uint32 len); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_HASH_H +#define f_VD2_SYSTEM_HASH_H + +#ifdef _MSC_VER + #pragma once +#endif + +#ifndef f_VD2_SYSTEM_VDTYPES_H + #include +#endif + +// Case-sensitive string hashes + +uint32 VDHashString32(const char *s); +uint32 VDHashString32(const char *s, uint32 len); +uint32 VDHashString32(const wchar_t *s); +uint32 VDHashString32(const wchar_t *s, uint32 len); + +// Case-insensitive, culture-invariant string hashes + +uint32 VDHashString32I(const char *s); +uint32 VDHashString32I(const char *s, uint32 len); +uint32 VDHashString32I(const wchar_t *s); +uint32 VDHashString32I(const wchar_t *s, uint32 len); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/int128.h b/src/thirdparty/VirtualDub/h/vd2/system/int128.h index b89cb179c6d..ebef416cc89 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/int128.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/int128.h @@ -1,375 +1,375 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_INT128_H -#define f_VD2_SYSTEM_INT128_H - -#include - -struct vdint128; -struct vduint128; - -#ifdef _M_AMD64 - extern "C" __int64 _mul128(__int64 x, __int64 y, __int64 *hiresult); - extern "C" unsigned __int64 _umul128(unsigned __int64 x, unsigned __int64 y, unsigned __int64 *hiresult); - extern "C" unsigned __int64 __shiftleft128(unsigned __int64 low, unsigned __int64 high, unsigned char shift); - extern "C" unsigned __int64 __shiftright128(unsigned __int64 low, unsigned __int64 high, unsigned char shift); - - #pragma intrinsic(_mul128) - #pragma intrinsic(_umul128) - #pragma intrinsic(__shiftleft128) - #pragma intrinsic(__shiftright128) - - extern "C" { - void vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - void vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - void vdasm_uint128_mul(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - } -#else - extern "C" { - void __cdecl vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - void __cdecl vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]); - } -#endif - -struct vdint128 { -public: - union { - sint32 d[4]; - sint64 q[2]; - }; - - vdint128() {} - - vdint128(sint64 x) { - q[0] = x; - q[1] = x>>63; - } - - vdint128(uint64 x) { - q[0] = (sint64)x; - q[1] = 0; - } - - vdint128(int x) { - q[0] = x; - q[1] = (sint64)x >> 63; - } - - vdint128(unsigned int x) { - q[0] = x; - q[1] = 0; - } - - vdint128(unsigned long x) { - q[0] = x; - q[1] = 0; - } - - vdint128(sint64 hi, uint64 lo) { - q[0] = lo; - q[1] = hi; - } - - explicit inline vdint128(const vduint128& x); - - sint64 getHi() const { return q[1]; } - uint64 getLo() const { return q[0]; } - - operator double() const; - operator sint64() const { - return (sint64)q[0]; - } - operator uint64() const { - return (uint64)q[0]; - } - - bool operator==(const vdint128& x) const { - return q[1] == x.q[1] && q[0] == x.q[0]; - } - - bool operator!=(const vdint128& x) const { - return q[1] != x.q[1] || q[0] != x.q[0]; - } - - bool operator<(const vdint128& x) const { - return q[1] < x.q[1] || (q[1] == x.q[1] && (uint64)q[0] < (uint64)x.q[0]); - } - - bool operator<=(const vdint128& x) const { - return q[1] < x.q[1] || (q[1] == x.q[1] && (uint64)q[0] <= (uint64)x.q[0]); - } - - bool operator>(const vdint128& x) const { - return q[1] > x.q[1] || (q[1] == x.q[1] && (uint64)q[0] > (uint64)x.q[0]); - } - - bool operator>=(const vdint128& x) const { - return q[1] > x.q[1] || (q[1] == x.q[1] && (uint64)q[0] >= (uint64)x.q[0]); - } - - const vdint128 operator+(const vdint128& x) const { - vdint128 t; - vdasm_uint128_add((uint64 *)t.q, (const uint64 *)q, (const uint64 *)x.q); - return t; - } - - const vdint128 operator-(const vdint128& x) const { - vdint128 t; - vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)q, (const uint64 *)x.q); - return t; - } - - const vdint128& operator+=(const vdint128& x) { - vdasm_uint128_add((uint64 *)q, (const uint64 *)q, (const uint64 *)x.q); - return *this; - } - - const vdint128& operator-=(const vdint128& x) { - vdasm_uint128_sub((uint64 *)q, (const uint64 *)q, (const uint64 *)x.q); - return *this; - } - - const vdint128 operator*(const vdint128& x) const; - - const vdint128 operator/(int x) const; - - const vdint128 operator-() const { - vdint128 t(0); - vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)t.q, (const uint64 *)q); - return t; - } - - const vdint128 abs() const { - return q[1] < 0 ? -*this : *this; - } - -#ifdef _M_AMD64 - void setSquare(sint64 v) { - const vdint128 v128(v); - operator=(v128*v128); - } - - const vdint128 operator<<(int count) const { - vdint128 t; - - if (count >= 64) { - t.q[0] = 0; - t.q[1] = q[0] << (count-64); - } else { - t.q[0] = q[0] << count; - t.q[1] = __shiftleft128(q[0], q[1], count); - } - - return t; - } - - const vdint128 operator>>(int count) const { - vdint128 t; - - if (count >= 64) { - t.q[0] = q[1] >> (count-64); - t.q[1] = q[1] >> 63; - } else { - t.q[0] = __shiftright128(q[0], q[1], count); - t.q[1] = q[1] >> count; - } - - return t; - } -#else - void setSquare(sint64 v); - - const vdint128 operator<<(int v) const; - const vdint128 operator>>(int v) const; -#endif -}; - -struct vduint128 { -public: - union { - uint32 d[4]; - uint64 q[2]; - }; - - vduint128() {} - - vduint128(sint64 x) { - q[0] = (sint64)x; - q[1] = 0; - } - - vduint128(uint64 x) { - q[0] = x; - q[1] = 0; - } - - vduint128(int x) { - q[0] = (uint64)x; - q[1] = 0; - } - - vduint128(unsigned x) { - q[0] = x; - q[1] = 0; - } - - vduint128(uint64 hi, uint64 lo) { - q[0] = lo; - q[1] = hi; - } - - explicit inline vduint128(const vdint128& x); - - uint64 getHi() const { return q[1]; } - uint64 getLo() const { return q[0]; } - - operator sint64() const { - return (sint64)q[0]; - } - - operator uint64() const { - return (uint64)q[0]; - } - - bool operator==(const vduint128& x) const { - return q[1] == x.q[1] && q[0] == x.q[0]; - } - - bool operator!=(const vduint128& x) const { - return q[1] != x.q[1] || q[0] != x.q[0]; - } - - bool operator<(const vduint128& x) const { - return q[1] < x.q[1] || (q[1] == x.q[1] && q[0] < x.q[0]); - } - - bool operator<=(const vduint128& x) const { - return q[1] < x.q[1] || (q[1] == x.q[1] && q[0] <= x.q[0]); - } - - bool operator>(const vduint128& x) const { - return q[1] > x.q[1] || (q[1] == x.q[1] && q[0] > x.q[0]); - } - - bool operator>=(const vduint128& x) const { - return q[1] > x.q[1] || (q[1] == x.q[1] && q[0] >= x.q[0]); - } - - const vduint128 operator+(const vduint128& x) const { - vduint128 t; - vdasm_uint128_add(t.q, q, x.q); - return t; - } - - const vduint128 operator-(const vduint128& x) const { - vduint128 t; - vdasm_uint128_sub(t.q, q, x.q); - return t; - } - - const vduint128& operator+=(const vduint128& x) { - vdasm_uint128_add(q, q, x.q); - return *this; - } - - const vduint128& operator-=(const vduint128& x) { - vdasm_uint128_sub(q, q, x.q); - return *this; - } - - const vduint128 operator*(const vduint128& x) const; - - const vduint128 operator-() const { - vduint128 t(0U); - vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)t.q, (const uint64 *)q); - return t; - } - - vduint128& operator<<=(int count) { - return operator=(operator<<(count)); - } - - vduint128& operator>>=(int count) { - return operator=(operator>>(count)); - } - -#ifdef _M_AMD64 - const vduint128 operator<<(int count) const { - vduint128 t; - - if (count >= 64) { - t.q[0] = 0; - t.q[1] = q[0] << (count-64); - } else { - t.q[0] = q[0] << count; - t.q[1] = __shiftleft128(q[0], q[1], count); - } - - return t; - } - - const vduint128 operator>>(int count) const { - vduint128 t; - - if (count >= 64) { - t.q[0] = q[1] >> (count-64); - t.q[1] = 0; - } else { - t.q[0] = __shiftright128(q[0], q[1], count); - t.q[1] = q[1] >> count; - } - - return t; - } -#else - const vduint128 operator<<(int v) const; - const vduint128 operator>>(int v) const; -#endif -}; - -inline vdint128::vdint128(const vduint128& x) { - q[0] = x.q[0]; - q[1] = x.q[1]; -} - -inline vduint128::vduint128(const vdint128& x) { - q[0] = x.q[0]; - q[1] = x.q[1]; -} - -#ifdef _M_AMD64 - inline vduint128 VDUMul64x64To128(uint64 x, uint64 y) { - vduint128 result; - result.q[0] = _umul128(x, y, &result.q[1]); - return result; - } - uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder); -#else - vduint128 VDUMul64x64To128(uint64 x, uint64 y); - uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder); -#endif - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_INT128_H +#define f_VD2_SYSTEM_INT128_H + +#include + +struct vdint128; +struct vduint128; + +#ifdef _M_AMD64 + extern "C" __int64 _mul128(__int64 x, __int64 y, __int64 *hiresult); + extern "C" unsigned __int64 _umul128(unsigned __int64 x, unsigned __int64 y, unsigned __int64 *hiresult); + extern "C" unsigned __int64 __shiftleft128(unsigned __int64 low, unsigned __int64 high, unsigned char shift); + extern "C" unsigned __int64 __shiftright128(unsigned __int64 low, unsigned __int64 high, unsigned char shift); + + #pragma intrinsic(_mul128) + #pragma intrinsic(_umul128) + #pragma intrinsic(__shiftleft128) + #pragma intrinsic(__shiftright128) + + extern "C" { + void vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + void vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + void vdasm_uint128_mul(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + } +#else + extern "C" { + void __cdecl vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + void __cdecl vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]); + } +#endif + +struct vdint128 { +public: + union { + sint32 d[4]; + sint64 q[2]; + }; + + vdint128() {} + + vdint128(sint64 x) { + q[0] = x; + q[1] = x>>63; + } + + vdint128(uint64 x) { + q[0] = (sint64)x; + q[1] = 0; + } + + vdint128(int x) { + q[0] = x; + q[1] = (sint64)x >> 63; + } + + vdint128(unsigned int x) { + q[0] = x; + q[1] = 0; + } + + vdint128(unsigned long x) { + q[0] = x; + q[1] = 0; + } + + vdint128(sint64 hi, uint64 lo) { + q[0] = lo; + q[1] = hi; + } + + explicit inline vdint128(const vduint128& x); + + sint64 getHi() const { return q[1]; } + uint64 getLo() const { return q[0]; } + + operator double() const; + operator sint64() const { + return (sint64)q[0]; + } + operator uint64() const { + return (uint64)q[0]; + } + + bool operator==(const vdint128& x) const { + return q[1] == x.q[1] && q[0] == x.q[0]; + } + + bool operator!=(const vdint128& x) const { + return q[1] != x.q[1] || q[0] != x.q[0]; + } + + bool operator<(const vdint128& x) const { + return q[1] < x.q[1] || (q[1] == x.q[1] && (uint64)q[0] < (uint64)x.q[0]); + } + + bool operator<=(const vdint128& x) const { + return q[1] < x.q[1] || (q[1] == x.q[1] && (uint64)q[0] <= (uint64)x.q[0]); + } + + bool operator>(const vdint128& x) const { + return q[1] > x.q[1] || (q[1] == x.q[1] && (uint64)q[0] > (uint64)x.q[0]); + } + + bool operator>=(const vdint128& x) const { + return q[1] > x.q[1] || (q[1] == x.q[1] && (uint64)q[0] >= (uint64)x.q[0]); + } + + const vdint128 operator+(const vdint128& x) const { + vdint128 t; + vdasm_uint128_add((uint64 *)t.q, (const uint64 *)q, (const uint64 *)x.q); + return t; + } + + const vdint128 operator-(const vdint128& x) const { + vdint128 t; + vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)q, (const uint64 *)x.q); + return t; + } + + const vdint128& operator+=(const vdint128& x) { + vdasm_uint128_add((uint64 *)q, (const uint64 *)q, (const uint64 *)x.q); + return *this; + } + + const vdint128& operator-=(const vdint128& x) { + vdasm_uint128_sub((uint64 *)q, (const uint64 *)q, (const uint64 *)x.q); + return *this; + } + + const vdint128 operator*(const vdint128& x) const; + + const vdint128 operator/(int x) const; + + const vdint128 operator-() const { + vdint128 t(0); + vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)t.q, (const uint64 *)q); + return t; + } + + const vdint128 abs() const { + return q[1] < 0 ? -*this : *this; + } + +#ifdef _M_AMD64 + void setSquare(sint64 v) { + const vdint128 v128(v); + operator=(v128*v128); + } + + const vdint128 operator<<(int count) const { + vdint128 t; + + if (count >= 64) { + t.q[0] = 0; + t.q[1] = q[0] << (count-64); + } else { + t.q[0] = q[0] << count; + t.q[1] = __shiftleft128(q[0], q[1], count); + } + + return t; + } + + const vdint128 operator>>(int count) const { + vdint128 t; + + if (count >= 64) { + t.q[0] = q[1] >> (count-64); + t.q[1] = q[1] >> 63; + } else { + t.q[0] = __shiftright128(q[0], q[1], count); + t.q[1] = q[1] >> count; + } + + return t; + } +#else + void setSquare(sint64 v); + + const vdint128 operator<<(int v) const; + const vdint128 operator>>(int v) const; +#endif +}; + +struct vduint128 { +public: + union { + uint32 d[4]; + uint64 q[2]; + }; + + vduint128() {} + + vduint128(sint64 x) { + q[0] = (sint64)x; + q[1] = 0; + } + + vduint128(uint64 x) { + q[0] = x; + q[1] = 0; + } + + vduint128(int x) { + q[0] = (uint64)x; + q[1] = 0; + } + + vduint128(unsigned x) { + q[0] = x; + q[1] = 0; + } + + vduint128(uint64 hi, uint64 lo) { + q[0] = lo; + q[1] = hi; + } + + explicit inline vduint128(const vdint128& x); + + uint64 getHi() const { return q[1]; } + uint64 getLo() const { return q[0]; } + + operator sint64() const { + return (sint64)q[0]; + } + + operator uint64() const { + return (uint64)q[0]; + } + + bool operator==(const vduint128& x) const { + return q[1] == x.q[1] && q[0] == x.q[0]; + } + + bool operator!=(const vduint128& x) const { + return q[1] != x.q[1] || q[0] != x.q[0]; + } + + bool operator<(const vduint128& x) const { + return q[1] < x.q[1] || (q[1] == x.q[1] && q[0] < x.q[0]); + } + + bool operator<=(const vduint128& x) const { + return q[1] < x.q[1] || (q[1] == x.q[1] && q[0] <= x.q[0]); + } + + bool operator>(const vduint128& x) const { + return q[1] > x.q[1] || (q[1] == x.q[1] && q[0] > x.q[0]); + } + + bool operator>=(const vduint128& x) const { + return q[1] > x.q[1] || (q[1] == x.q[1] && q[0] >= x.q[0]); + } + + const vduint128 operator+(const vduint128& x) const { + vduint128 t; + vdasm_uint128_add(t.q, q, x.q); + return t; + } + + const vduint128 operator-(const vduint128& x) const { + vduint128 t; + vdasm_uint128_sub(t.q, q, x.q); + return t; + } + + const vduint128& operator+=(const vduint128& x) { + vdasm_uint128_add(q, q, x.q); + return *this; + } + + const vduint128& operator-=(const vduint128& x) { + vdasm_uint128_sub(q, q, x.q); + return *this; + } + + const vduint128 operator*(const vduint128& x) const; + + const vduint128 operator-() const { + vduint128 t(0U); + vdasm_uint128_sub((uint64 *)t.q, (const uint64 *)t.q, (const uint64 *)q); + return t; + } + + vduint128& operator<<=(int count) { + return operator=(operator<<(count)); + } + + vduint128& operator>>=(int count) { + return operator=(operator>>(count)); + } + +#ifdef _M_AMD64 + const vduint128 operator<<(int count) const { + vduint128 t; + + if (count >= 64) { + t.q[0] = 0; + t.q[1] = q[0] << (count-64); + } else { + t.q[0] = q[0] << count; + t.q[1] = __shiftleft128(q[0], q[1], count); + } + + return t; + } + + const vduint128 operator>>(int count) const { + vduint128 t; + + if (count >= 64) { + t.q[0] = q[1] >> (count-64); + t.q[1] = 0; + } else { + t.q[0] = __shiftright128(q[0], q[1], count); + t.q[1] = q[1] >> count; + } + + return t; + } +#else + const vduint128 operator<<(int v) const; + const vduint128 operator>>(int v) const; +#endif +}; + +inline vdint128::vdint128(const vduint128& x) { + q[0] = x.q[0]; + q[1] = x.q[1]; +} + +inline vduint128::vduint128(const vdint128& x) { + q[0] = x.q[0]; + q[1] = x.q[1]; +} + +#ifdef _M_AMD64 + inline vduint128 VDUMul64x64To128(uint64 x, uint64 y) { + vduint128 result; + result.q[0] = _umul128(x, y, &result.q[1]); + return result; + } + uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder); +#else + vduint128 VDUMul64x64To128(uint64 x, uint64 y); + uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder); +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/linearalloc.h b/src/thirdparty/VirtualDub/h/vd2/system/linearalloc.h index 9a9ef4cba6d..08a35dc3abf 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/linearalloc.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/linearalloc.h @@ -1,88 +1,88 @@ -#ifndef f_VD2_SYSTEM_LINEARALLOC_H -#define f_VD2_SYSTEM_LINEARALLOC_H - -#include - -class VDLinearAllocator { -public: - explicit VDLinearAllocator(uint32 blockSize = 4096); - ~VDLinearAllocator(); - - void Clear(); - - void *Allocate(size_t bytes) { - void *p = mpAllocPtr; - - bytes = (bytes + sizeof(void *) - 1) & ((size_t)0 - (size_t)sizeof(void *)); - - if (mAllocLeft < bytes) - p = AllocateSlow(bytes); - else { - mAllocLeft -= bytes; - mpAllocPtr += bytes; - } - - return p; - } - - template - T *Allocate() { - return new(Allocate(sizeof(T))) T; - } - - template - T *Allocate(const A1& a1) { - return new(Allocate(sizeof(T))) T(a1); - } - - template - T *Allocate(const A1& a1, const A2& a2) { - return new(Allocate(sizeof(T))) T(a1, a2); - } - - template - T *Allocate(const A1& a1, const A2& a2, const A3& a3) { - return new(Allocate(sizeof(T))) T(a1, a2, a3); - } - -protected: - void *AllocateSlow(size_t bytes); - - union Block { - Block *mpNext; - double mAlign; - }; - - Block *mpBlocks; - char *mpAllocPtr; - size_t mAllocLeft; - size_t mBlockSize; -}; - -class VDFixedLinearAllocator { -public: - VDFixedLinearAllocator(void *mem, size_t size) - : mpAllocPtr((char *)mem) - , mAllocLeft(size) - { - } - - void *Allocate(size_t bytes) { - void *p = mpAllocPtr; - - if (mAllocLeft < bytes) - ThrowException(); - - mAllocLeft -= bytes; - mpAllocPtr += bytes; - return p; - } - -protected: - void ThrowException(); - - char *mpAllocPtr; - size_t mAllocLeft; -}; - -#endif +#ifndef f_VD2_SYSTEM_LINEARALLOC_H +#define f_VD2_SYSTEM_LINEARALLOC_H + +#include + +class VDLinearAllocator { +public: + explicit VDLinearAllocator(uint32 blockSize = 4096); + ~VDLinearAllocator(); + + void Clear(); + + void *Allocate(size_t bytes) { + void *p = mpAllocPtr; + + bytes = (bytes + sizeof(void *) - 1) & ((size_t)0 - (size_t)sizeof(void *)); + + if (mAllocLeft < bytes) + p = AllocateSlow(bytes); + else { + mAllocLeft -= bytes; + mpAllocPtr += bytes; + } + + return p; + } + + template + T *Allocate() { + return new(Allocate(sizeof(T))) T; + } + + template + T *Allocate(const A1& a1) { + return new(Allocate(sizeof(T))) T(a1); + } + + template + T *Allocate(const A1& a1, const A2& a2) { + return new(Allocate(sizeof(T))) T(a1, a2); + } + + template + T *Allocate(const A1& a1, const A2& a2, const A3& a3) { + return new(Allocate(sizeof(T))) T(a1, a2, a3); + } + +protected: + void *AllocateSlow(size_t bytes); + + union Block { + Block *mpNext; + double mAlign; + }; + + Block *mpBlocks; + char *mpAllocPtr; + size_t mAllocLeft; + size_t mBlockSize; +}; + +class VDFixedLinearAllocator { +public: + VDFixedLinearAllocator(void *mem, size_t size) + : mpAllocPtr((char *)mem) + , mAllocLeft(size) + { + } + + void *Allocate(size_t bytes) { + void *p = mpAllocPtr; + + if (mAllocLeft < bytes) + ThrowException(); + + mAllocLeft -= bytes; + mpAllocPtr += bytes; + return p; + } + +protected: + void ThrowException(); + + char *mpAllocPtr; + size_t mAllocLeft; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/list.h b/src/thirdparty/VirtualDub/h/vd2/system/list.h index 42a81ae8e12..103c9a49eef 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/list.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/list.h @@ -1,275 +1,275 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_LIST_H -#define f_LIST_H - -class ListNode { -public: - ListNode *next, *prev; - - void Remove() { - next->prev = prev; - prev->next = next; -#ifdef _DEBUG - prev = next = 0; -#endif - } - - void InsertAfter(ListNode *node) { - next = node; - prev = node->prev; - if (node->prev) node->prev->next = this; - node->prev = this; - } - - void InsertBefore(ListNode *node) { - next = node->next; - prev = node; - if (node->next) node->next->prev = this; - node->next = this; - } - - ListNode *NextFromHead() const { - return prev; - } - - ListNode *NextFromTail() const { - return next; - } -}; - -class List { -private: -public: - ListNode head, tail; - - // <--- next prev ---> - // - // head <-> node <-> node <-> tail - - List(); - List(int) {} - - void Init(); - - void AddHead(ListNode *node) { - node->InsertAfter(&head); - } - - void AddTail(ListNode *node) { - node->InsertBefore(&tail); - } - - ListNode *RemoveHead(); - ListNode *RemoveTail(); - - bool IsEmpty() const { - return !head.prev->prev; - } - - ListNode *AtHead() const { - return head.prev; - } - - ListNode *AtTail() const { - return tail.next; - } - - void Take(List& from); - void Swap(List& with); -}; - -// Templated classes... templated classes good. - -template class List2; - -template -class ListNode2 : public ListNode { -friend class List2; -public: - void InsertBefore(ListNode2 *node) { ListNode::InsertBefore(node); } - void InsertAfter(ListNode2 *node) { ListNode::InsertAfter(node); } - - void Remove() { ListNode::Remove(); } - T *NextFromHead() const { return static_cast(static_cast*>(ListNode::NextFromHead())); } - T *NextFromTail() const { return static_cast(static_cast*>(ListNode::NextFromTail())); } -}; - -template -class List2 : public List { -public: - List2() {} - - // This is a really lame, stupid way to postpone initialization of the - // list. - - List2(int v) : List(v) {} - - void AddHead(ListNode2 *node) { List::AddHead(node); } - void AddTail(ListNode2 *node) { List::AddTail(node); } - T *RemoveHead() { return static_cast(static_cast*>(List::RemoveHead())); } - T *RemoveTail() { return static_cast(static_cast*>(List::RemoveTail())); } - T *AtHead() const { return static_cast(static_cast*>(List::AtHead())); } - T *AtTail() const { return static_cast(static_cast*>(List::AtTail())); } - - // I must admit to being pampered by STL (end is different though!!) - - T *begin() const { return AtHead(); } - T *end() const { return AtTail(); } - - void take(List2& from) { List::Take(from); } - - class iterator { - protected: - ListNode2 *node; - ListNode2 *next; - - public: - iterator() {} - iterator(const iterator& src) throw() : node(src.node), next(src.next) {} - - bool operator!() const throw() { return 0 == next; } - T *operator->() const throw() { return (T *)node; } - operator bool() const throw() { return 0 != next; } - operator T *() const throw() { return (T *)node; } - T& operator *() const throw() { return *(T *)node; } - }; - - // fwit: forward iterator (SAFE if node disappears) - // rvit: reverse iterator (SAFE if node disappears) - - class fwit : public iterator { - public: - fwit() throw() {} - fwit(const fwit& src) throw() : iterator(src) {} - fwit(ListNode2 *start) throw() { - this->node = start; - this->next = start->NextFromHead(); - } - - const fwit& operator=(ListNode2 *start) throw() { - this->node = start; - this->next = start->NextFromHead(); - - return *this; - } - - fwit& operator++() throw() { - this->node = this->next; - this->next = this->node->NextFromHead(); - - return *this; - } - - const fwit& operator+=(int v) throw() { - while(this->next && v--) { - this->node = this->next; - this->next = this->node->NextFromHead(); - } - - return *this; - } - - fwit operator+(int v) const throw() { - fwit t(*this); - - t += v; - - return t; - } - - // This one's for my sanity. - - void operator++(int) throw() { - ++*this; - } - }; - - class rvit : public iterator { - public: - rvit() throw() {} - - rvit(ListNode2 *start) throw() { - this->node = start; - this->next = start->NextFromTail(); - } - - const rvit& operator=(ListNode2 *start) throw() { - this->node = start; - this->next = start->NextFromTail(); - - return *this; - } - - rvit& operator--() throw() { - this->node = this->next; - this->next = this->node->NextFromTail(); - - return *this; - } - - const rvit& operator-=(int v) throw() { - while(this->next && v--) { - this->node = this->next; - this->next = this->node->NextFromTail(); - } - - return *this; - } - - rvit operator-(int v) const throw() { - rvit t(*this); - - t -= v; - - return t; - } - - // This one's for my sanity. - - void operator--(int) throw() { - --*this; - } - }; -}; - -template -class ListAlloc : public List2 { -public: - ListAlloc() {} - ~ListAlloc() { - dispose(); - } - - void dispose() { - T *node; - - while(node = this->RemoveHead()) - delete node; - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_LIST_H +#define f_LIST_H + +class ListNode { +public: + ListNode *next, *prev; + + void Remove() { + next->prev = prev; + prev->next = next; +#ifdef _DEBUG + prev = next = 0; +#endif + } + + void InsertAfter(ListNode *node) { + next = node; + prev = node->prev; + if (node->prev) node->prev->next = this; + node->prev = this; + } + + void InsertBefore(ListNode *node) { + next = node->next; + prev = node; + if (node->next) node->next->prev = this; + node->next = this; + } + + ListNode *NextFromHead() const { + return prev; + } + + ListNode *NextFromTail() const { + return next; + } +}; + +class List { +private: +public: + ListNode head, tail; + + // <--- next prev ---> + // + // head <-> node <-> node <-> tail + + List(); + List(int) {} + + void Init(); + + void AddHead(ListNode *node) { + node->InsertAfter(&head); + } + + void AddTail(ListNode *node) { + node->InsertBefore(&tail); + } + + ListNode *RemoveHead(); + ListNode *RemoveTail(); + + bool IsEmpty() const { + return !head.prev->prev; + } + + ListNode *AtHead() const { + return head.prev; + } + + ListNode *AtTail() const { + return tail.next; + } + + void Take(List& from); + void Swap(List& with); +}; + +// Templated classes... templated classes good. + +template class List2; + +template +class ListNode2 : public ListNode { +friend class List2; +public: + void InsertBefore(ListNode2 *node) { ListNode::InsertBefore(node); } + void InsertAfter(ListNode2 *node) { ListNode::InsertAfter(node); } + + void Remove() { ListNode::Remove(); } + T *NextFromHead() const { return static_cast(static_cast*>(ListNode::NextFromHead())); } + T *NextFromTail() const { return static_cast(static_cast*>(ListNode::NextFromTail())); } +}; + +template +class List2 : public List { +public: + List2() {} + + // This is a really lame, stupid way to postpone initialization of the + // list. + + List2(int v) : List(v) {} + + void AddHead(ListNode2 *node) { List::AddHead(node); } + void AddTail(ListNode2 *node) { List::AddTail(node); } + T *RemoveHead() { return static_cast(static_cast*>(List::RemoveHead())); } + T *RemoveTail() { return static_cast(static_cast*>(List::RemoveTail())); } + T *AtHead() const { return static_cast(static_cast*>(List::AtHead())); } + T *AtTail() const { return static_cast(static_cast*>(List::AtTail())); } + + // I must admit to being pampered by STL (end is different though!!) + + T *begin() const { return AtHead(); } + T *end() const { return AtTail(); } + + void take(List2& from) { List::Take(from); } + + class iterator { + protected: + ListNode2 *node; + ListNode2 *next; + + public: + iterator() {} + iterator(const iterator& src) throw() : node(src.node), next(src.next) {} + + bool operator!() const throw() { return 0 == next; } + T *operator->() const throw() { return (T *)node; } + operator bool() const throw() { return 0 != next; } + operator T *() const throw() { return (T *)node; } + T& operator *() const throw() { return *(T *)node; } + }; + + // fwit: forward iterator (SAFE if node disappears) + // rvit: reverse iterator (SAFE if node disappears) + + class fwit : public iterator { + public: + fwit() throw() {} + fwit(const fwit& src) throw() : iterator(src) {} + fwit(ListNode2 *start) throw() { + this->node = start; + this->next = start->NextFromHead(); + } + + const fwit& operator=(ListNode2 *start) throw() { + this->node = start; + this->next = start->NextFromHead(); + + return *this; + } + + fwit& operator++() throw() { + this->node = this->next; + this->next = this->node->NextFromHead(); + + return *this; + } + + const fwit& operator+=(int v) throw() { + while(this->next && v--) { + this->node = this->next; + this->next = this->node->NextFromHead(); + } + + return *this; + } + + fwit operator+(int v) const throw() { + fwit t(*this); + + t += v; + + return t; + } + + // This one's for my sanity. + + void operator++(int) throw() { + ++*this; + } + }; + + class rvit : public iterator { + public: + rvit() throw() {} + + rvit(ListNode2 *start) throw() { + this->node = start; + this->next = start->NextFromTail(); + } + + const rvit& operator=(ListNode2 *start) throw() { + this->node = start; + this->next = start->NextFromTail(); + + return *this; + } + + rvit& operator--() throw() { + this->node = this->next; + this->next = this->node->NextFromTail(); + + return *this; + } + + const rvit& operator-=(int v) throw() { + while(this->next && v--) { + this->node = this->next; + this->next = this->node->NextFromTail(); + } + + return *this; + } + + rvit operator-(int v) const throw() { + rvit t(*this); + + t -= v; + + return t; + } + + // This one's for my sanity. + + void operator--(int) throw() { + --*this; + } + }; +}; + +template +class ListAlloc : public List2 { +public: + ListAlloc() {} + ~ListAlloc() { + dispose(); + } + + void dispose() { + T *node; + + while(node = this->RemoveHead()) + delete node; + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/math.h b/src/thirdparty/VirtualDub/h/vd2/system/math.h index d251de61ddd..221035bb8e0 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/math.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/math.h @@ -1,269 +1,269 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_MATH_H -#define f_VD2_SYSTEM_MATH_H - -#include -#include - -// Constants -namespace nsVDMath { - static const float kfPi = 3.1415926535897932384626433832795f; - static const double krPi = 3.1415926535897932384626433832795; - static const float kfTwoPi = 6.283185307179586476925286766559f; - static const double krTwoPi = 6.283185307179586476925286766559; - static const float kfLn2 = 0.69314718055994530941723212145818f; - static const double krLn2 = 0.69314718055994530941723212145818; - static const float kfLn10 = 2.3025850929940456840179914546844f; - static const double krLn10 = 2.3025850929940456840179914546844; - static const float kfOneOverLn10 = 0.43429448190325182765112891891661f; - static const double krOneOverLn10 = 0.43429448190325182765112891891661; -}; - -/////////////////////////////////////////////////////////////////////////// -// Integer clamping functions -// -#ifdef _M_IX86 - inline uint32 VDClampToUint32(uint64 v) { - return v >= 0x100000000UL ? 0xFFFFFFFFUL : (uint32)v; - } - - inline uint32 VDClampToUint32(sint64 v) { - union U { - __int64 v64; - struct { - unsigned lo; - int hi; - } v32; - }; - - return ((U *)&v)->v32.hi ? ~(((U *)&v)->v32.hi >> 31) : ((U *)&v)->v32.lo; - } - - inline uint32 VDClampToUint32(sint32 v) { - return v < 0 ? 0 : (uint32)v; - } -#else - inline uint32 VDClampToUint32(sint64 v) { - uint32 r = (uint32)v; - return r == v ? r : (uint32)~(sint32)(v>>63); - } -#endif - -inline sint32 VDClampToSint32(uint32 v) { - return (v | ((sint32)v >> 31)) & 0x7FFFFFFF; -} - -inline sint32 VDClampToSint32(sint64 v) { - sint32 r = (sint32)v; - return r == v ? r : (sint32)(v >> 63) ^ 0x7FFFFFFF; -} - -inline uint16 VDClampToUint16(uint32 v) { - if (v > 0xffff) - v = 0xffff; - return (uint16)v; -} - -/////////////////////////////////////////////////////////////////////////// -// Absolute value functions -inline sint64 VDAbs64(sint64 v) { - return v<0 ? -v : v; -} - -inline ptrdiff_t VDAbsPtrdiff(ptrdiff_t v) { - return v<0 ? -v : v; -} - -// Rounding functions -// -// Round a double to an int or a long. Behavior is not specified at -// int(y)+0.5, if x is NaN or Inf, or if x is out of range. - -int VDRoundToInt(double x); -long VDRoundToLong(double x); -sint32 VDRoundToInt32(double x); -sint64 VDRoundToInt64(double x); - -inline sint32 VDRoundToIntFast(float x) { - union { - float f; - sint32 i; - } u = {x + 12582912.0f}; // 2^22+2^23 - - return (sint32)u.i - 0x4B400000; -} - -inline sint32 VDRoundToIntFastFullRange(double x) { - union { - double f; - sint32 i[2]; - } u = {x + 6755399441055744.0f}; // 2^51+2^52 - - return (sint32)u.i[0]; -} - -#if !defined(VD_CPU_X86) || !defined(VD_COMPILER_MSVC) - inline sint32 VDFloorToInt(double x) { - return (sint32)floor(x); - } - - inline sint64 VDFloorToInt64(double x) { - return (sint64)floor(x); - } -#else - #pragma warning(push) - #pragma warning(disable: 4035) // warning C4035: 'VDFloorToInt' : no return value - inline sint32 VDFloorToInt(double x) { - sint32 temp; - - __asm { - fld x - fist temp - fild temp - mov eax, temp - fsub - fstp temp - cmp temp, 80000001h - adc eax, -1 - } - } - inline sint64 VDFloorToInt64(double x) { - sint64 temp; - sint32 temp2; - - __asm { - fld x - fld st(0) - fistp qword ptr temp - fild qword ptr temp - mov eax, dword ptr temp - mov edx, dword ptr temp+4 - fsub - fstp dword ptr temp2 - cmp dword ptr temp2, 80000001h - adc eax, -1 - adc edx, -1 - } - } - #pragma warning(pop) -#endif - -#if !defined(VD_CPU_X86) || !defined(VD_COMPILER_MSVC) - inline sint32 VDCeilToInt(double x) { - return (sint32)ceil(x); - } - - inline sint64 VDCeilToInt64(double x) { - return (sint64)ceil(x); - } -#else - #pragma warning(push) - #pragma warning(disable: 4035) // warning C4035: 'VDCeilToInt' : no return value - inline sint32 VDCeilToInt(double x) { - sint32 temp; - - __asm { - fld x - fist temp - fild temp - mov eax, temp - fsubr - fstp temp - cmp temp, 80000001h - sbb eax, -1 - } - } - - inline sint32 VDCeilToInt64(double x) { - sint64 temp; - sint32 temp2; - - __asm { - fld x - fld st(0) - fistp temp - fild temp - mov eax, dword ptr temp - mov edx, dword ptr temp+4 - fsubr - fstp temp2 - cmp temp2, 80000001h - sbb eax, -1 - sbb edx, -1 - } - } - #pragma warning(pop) -#endif - -/////////////////////////////////////////////////////////////////////////// -/// Convert a value from [-~1..1] to [-32768, 32767] with clamping. -inline sint16 VDClampedRoundFixedToInt16Fast(float x) { - union { - float f; - sint32 i; - } u = {x * 65535.0f + 12582912.0f}; // 2^22+2^23 - - sint32 v = (sint32)u.i - 0x4B3F8000; - - if ((uint32)v >= 0x10000) - v = ~v >> 31; - - return (sint16)(v - 0x8000); -} - -/// Convert a value from [0..1] to [0..255] with clamping. -inline uint8 VDClampedRoundFixedToUint8Fast(float x) { - union { - float f; - sint32 i; - } u = {x * 255.0f + 12582912.0f}; // 2^22+2^23 - - sint32 v = (sint32)u.i - 0x4B400000; - - if ((uint32)v >= 0x100) - v = ~v >> 31; - - return (uint8)v; -} - -/////////////////////////////////////////////////////////////////////////// - -#ifdef _M_IX86 - sint64 __stdcall VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder); - uint64 __stdcall VDUMulDiv64x32(uint64 a, uint32 b, uint32 c); -#else - extern "C" sint64 VDFractionScale64(uint64 a, uint64 b, uint64 c, uint32& remainder); - extern "C" uint64 VDUMulDiv64x32(uint64 a, uint32 b, uint32 c); -#endif - -sint64 VDMulDiv64(sint64 a, sint64 b, sint64 c); - -/////////////////////////////////////////////////////////////////////////// - -bool VDVerifyFiniteFloats(const float *p, uint32 n); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_MATH_H +#define f_VD2_SYSTEM_MATH_H + +#include +#include + +// Constants +namespace nsVDMath { + static const float kfPi = 3.1415926535897932384626433832795f; + static const double krPi = 3.1415926535897932384626433832795; + static const float kfTwoPi = 6.283185307179586476925286766559f; + static const double krTwoPi = 6.283185307179586476925286766559; + static const float kfLn2 = 0.69314718055994530941723212145818f; + static const double krLn2 = 0.69314718055994530941723212145818; + static const float kfLn10 = 2.3025850929940456840179914546844f; + static const double krLn10 = 2.3025850929940456840179914546844; + static const float kfOneOverLn10 = 0.43429448190325182765112891891661f; + static const double krOneOverLn10 = 0.43429448190325182765112891891661; +}; + +/////////////////////////////////////////////////////////////////////////// +// Integer clamping functions +// +#ifdef _M_IX86 + inline uint32 VDClampToUint32(uint64 v) { + return v >= 0x100000000UL ? 0xFFFFFFFFUL : (uint32)v; + } + + inline uint32 VDClampToUint32(sint64 v) { + union U { + __int64 v64; + struct { + unsigned lo; + int hi; + } v32; + }; + + return ((U *)&v)->v32.hi ? ~(((U *)&v)->v32.hi >> 31) : ((U *)&v)->v32.lo; + } + + inline uint32 VDClampToUint32(sint32 v) { + return v < 0 ? 0 : (uint32)v; + } +#else + inline uint32 VDClampToUint32(sint64 v) { + uint32 r = (uint32)v; + return r == v ? r : (uint32)~(sint32)(v>>63); + } +#endif + +inline sint32 VDClampToSint32(uint32 v) { + return (v | ((sint32)v >> 31)) & 0x7FFFFFFF; +} + +inline sint32 VDClampToSint32(sint64 v) { + sint32 r = (sint32)v; + return r == v ? r : (sint32)(v >> 63) ^ 0x7FFFFFFF; +} + +inline uint16 VDClampToUint16(uint32 v) { + if (v > 0xffff) + v = 0xffff; + return (uint16)v; +} + +/////////////////////////////////////////////////////////////////////////// +// Absolute value functions +inline sint64 VDAbs64(sint64 v) { + return v<0 ? -v : v; +} + +inline ptrdiff_t VDAbsPtrdiff(ptrdiff_t v) { + return v<0 ? -v : v; +} + +// Rounding functions +// +// Round a double to an int or a long. Behavior is not specified at +// int(y)+0.5, if x is NaN or Inf, or if x is out of range. + +int VDRoundToInt(double x); +long VDRoundToLong(double x); +sint32 VDRoundToInt32(double x); +sint64 VDRoundToInt64(double x); + +inline sint32 VDRoundToIntFast(float x) { + union { + float f; + sint32 i; + } u = {x + 12582912.0f}; // 2^22+2^23 + + return (sint32)u.i - 0x4B400000; +} + +inline sint32 VDRoundToIntFastFullRange(double x) { + union { + double f; + sint32 i[2]; + } u = {x + 6755399441055744.0f}; // 2^51+2^52 + + return (sint32)u.i[0]; +} + +#if !defined(VD_CPU_X86) || !defined(VD_COMPILER_MSVC) + inline sint32 VDFloorToInt(double x) { + return (sint32)floor(x); + } + + inline sint64 VDFloorToInt64(double x) { + return (sint64)floor(x); + } +#else + #pragma warning(push) + #pragma warning(disable: 4035) // warning C4035: 'VDFloorToInt' : no return value + inline sint32 VDFloorToInt(double x) { + sint32 temp; + + __asm { + fld x + fist temp + fild temp + mov eax, temp + fsub + fstp temp + cmp temp, 80000001h + adc eax, -1 + } + } + inline sint64 VDFloorToInt64(double x) { + sint64 temp; + sint32 temp2; + + __asm { + fld x + fld st(0) + fistp qword ptr temp + fild qword ptr temp + mov eax, dword ptr temp + mov edx, dword ptr temp+4 + fsub + fstp dword ptr temp2 + cmp dword ptr temp2, 80000001h + adc eax, -1 + adc edx, -1 + } + } + #pragma warning(pop) +#endif + +#if !defined(VD_CPU_X86) || !defined(VD_COMPILER_MSVC) + inline sint32 VDCeilToInt(double x) { + return (sint32)ceil(x); + } + + inline sint64 VDCeilToInt64(double x) { + return (sint64)ceil(x); + } +#else + #pragma warning(push) + #pragma warning(disable: 4035) // warning C4035: 'VDCeilToInt' : no return value + inline sint32 VDCeilToInt(double x) { + sint32 temp; + + __asm { + fld x + fist temp + fild temp + mov eax, temp + fsubr + fstp temp + cmp temp, 80000001h + sbb eax, -1 + } + } + + inline sint32 VDCeilToInt64(double x) { + sint64 temp; + sint32 temp2; + + __asm { + fld x + fld st(0) + fistp temp + fild temp + mov eax, dword ptr temp + mov edx, dword ptr temp+4 + fsubr + fstp temp2 + cmp temp2, 80000001h + sbb eax, -1 + sbb edx, -1 + } + } + #pragma warning(pop) +#endif + +/////////////////////////////////////////////////////////////////////////// +/// Convert a value from [-~1..1] to [-32768, 32767] with clamping. +inline sint16 VDClampedRoundFixedToInt16Fast(float x) { + union { + float f; + sint32 i; + } u = {x * 65535.0f + 12582912.0f}; // 2^22+2^23 + + sint32 v = (sint32)u.i - 0x4B3F8000; + + if ((uint32)v >= 0x10000) + v = ~v >> 31; + + return (sint16)(v - 0x8000); +} + +/// Convert a value from [0..1] to [0..255] with clamping. +inline uint8 VDClampedRoundFixedToUint8Fast(float x) { + union { + float f; + sint32 i; + } u = {x * 255.0f + 12582912.0f}; // 2^22+2^23 + + sint32 v = (sint32)u.i - 0x4B400000; + + if ((uint32)v >= 0x100) + v = ~v >> 31; + + return (uint8)v; +} + +/////////////////////////////////////////////////////////////////////////// + +#ifdef _M_IX86 + sint64 __stdcall VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder); + uint64 __stdcall VDUMulDiv64x32(uint64 a, uint32 b, uint32 c); +#else + extern "C" sint64 VDFractionScale64(uint64 a, uint64 b, uint64 c, uint32& remainder); + extern "C" uint64 VDUMulDiv64x32(uint64 a, uint32 b, uint32 c); +#endif + +sint64 VDMulDiv64(sint64 a, sint64 b, sint64 c); + +/////////////////////////////////////////////////////////////////////////// + +bool VDVerifyFiniteFloats(const float *p, uint32 n); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/memory.h b/src/thirdparty/VirtualDub/h/vd2/system/memory.h index 3a7a63f4771..52dbb432703 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/memory.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/memory.h @@ -1,84 +1,84 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_MEMORY_H -#define f_VD2_SYSTEM_MEMORY_H - -#include - -void *VDAlignedMalloc(size_t n, unsigned alignment); -void VDAlignedFree(void *p); - -template -struct VDAlignedObject { - inline void *operator new(size_t n) { return VDAlignedMalloc(n, alignment); } - inline void operator delete(void *p) { VDAlignedFree(p); } -}; - -void *VDAlignedVirtualAlloc(size_t n); -void VDAlignedVirtualFree(void *p); - -extern void (__cdecl *VDSwapMemory)(void *p0, void *p1, size_t bytes); - -void VDInvertMemory(void *p, unsigned bytes); - -bool VDIsValidReadRegion(const void *p, size_t bytes); -bool VDIsValidWriteRegion(void *p, size_t bytes); - -bool VDCompareRect(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, size_t w, size_t h); - -const void *VDMemCheck8(const void *src, uint8 value, size_t count); - -void VDMemset8(void *dst, uint8 value, size_t count); -void VDMemset16(void *dst, uint16 value, size_t count); -void VDMemset24(void *dst, uint32 value, size_t count); -void VDMemset32(void *dst, uint32 value, size_t count); -void VDMemset64(void *dst, uint64 value, size_t count); -void VDMemset128(void *dst, const void *value, size_t count); -void VDMemsetPointer(void *dst, const void *value, size_t count); - -void VDMemset8Rect(void *dst, ptrdiff_t pitch, uint8 value, size_t w, size_t h); -void VDMemset16Rect(void *dst, ptrdiff_t pitch, uint16 value, size_t w, size_t h); -void VDMemset24Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h); -void VDMemset32Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h); - -#if defined(_WIN32) && defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - extern void (__cdecl *VDFastMemcpyPartial)(void *dst, const void *src, size_t bytes); - extern void (__cdecl *VDFastMemcpyFinish)(); - void VDFastMemcpyAutodetect(); -#else - void VDFastMemcpyPartial(void *dst, const void *src, size_t bytes); - void VDFastMemcpyFinish(); - void VDFastMemcpyAutodetect(); -#endif - - -void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h); - -/// Copy a region of memory with an access violation guard; used in cases where a sporadic -/// AV is unavoidable (dynamic Direct3D VB under XP). The regions must not overlap. -bool VDMemcpyGuarded(void *dst, const void *src, size_t bytes); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_MEMORY_H +#define f_VD2_SYSTEM_MEMORY_H + +#include + +void *VDAlignedMalloc(size_t n, unsigned alignment); +void VDAlignedFree(void *p); + +template +struct VDAlignedObject { + inline void *operator new(size_t n) { return VDAlignedMalloc(n, alignment); } + inline void operator delete(void *p) { VDAlignedFree(p); } +}; + +void *VDAlignedVirtualAlloc(size_t n); +void VDAlignedVirtualFree(void *p); + +extern void (__cdecl *VDSwapMemory)(void *p0, void *p1, size_t bytes); + +void VDInvertMemory(void *p, unsigned bytes); + +bool VDIsValidReadRegion(const void *p, size_t bytes); +bool VDIsValidWriteRegion(void *p, size_t bytes); + +bool VDCompareRect(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, size_t w, size_t h); + +const void *VDMemCheck8(const void *src, uint8 value, size_t count); + +void VDMemset8(void *dst, uint8 value, size_t count); +void VDMemset16(void *dst, uint16 value, size_t count); +void VDMemset24(void *dst, uint32 value, size_t count); +void VDMemset32(void *dst, uint32 value, size_t count); +void VDMemset64(void *dst, uint64 value, size_t count); +void VDMemset128(void *dst, const void *value, size_t count); +void VDMemsetPointer(void *dst, const void *value, size_t count); + +void VDMemset8Rect(void *dst, ptrdiff_t pitch, uint8 value, size_t w, size_t h); +void VDMemset16Rect(void *dst, ptrdiff_t pitch, uint16 value, size_t w, size_t h); +void VDMemset24Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h); +void VDMemset32Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h); + +#if defined(_WIN32) && defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + extern void (__cdecl *VDFastMemcpyPartial)(void *dst, const void *src, size_t bytes); + extern void (__cdecl *VDFastMemcpyFinish)(); + void VDFastMemcpyAutodetect(); +#else + void VDFastMemcpyPartial(void *dst, const void *src, size_t bytes); + void VDFastMemcpyFinish(); + void VDFastMemcpyAutodetect(); +#endif + + +void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h); + +/// Copy a region of memory with an access violation guard; used in cases where a sporadic +/// AV is unavoidable (dynamic Direct3D VB under XP). The regions must not overlap. +bool VDMemcpyGuarded(void *dst, const void *src, size_t bytes); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/progress.h b/src/thirdparty/VirtualDub/h/vd2/system/progress.h index 82368e5e129..976e3c6e382 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/progress.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/progress.h @@ -1,96 +1,96 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_SYSTEM_PROGRESS_H -#define f_SYSTEM_PROGRESS_H - -#include - -class VDAtomicInt; -class VDSignalPersistent; - -class IProgress { -public: - virtual void Error(const char *)=0; - virtual void Warning(const char *)=0; - virtual bool Query(const char *query, bool fDefault)=0; - virtual void ProgressStart(const char *text, const char *caption, const char *progtext, long lMax)=0; - virtual void ProgressAdvance(long)=0; - virtual void ProgressEnd()=0; - virtual void Output(const char *text)=0; - virtual VDAtomicInt *ProgressGetAbortFlag()=0; - virtual VDSignalPersistent *ProgressGetAbortSignal()=0; -}; - - -void ProgressSetHandler(IProgress *pp); -IProgress *ProgressGetHandler(); - -bool ProgressCheckAbort(); -void ProgressSetAbort(bool bNewValue); -VDSignalPersistent *ProgressGetAbortSignal(); -void ProgressError(const class MyError&); -void ProgressWarning(const char *format, ...); -void ProgressOutput(const char *format, ...); -bool ProgressQuery(bool fDefault, const char *format, ...); -void ProgressStart(long lMax, const char *caption, const char *progresstext, const char *format, ...); -void ProgressAdvance(long lNewValue); -void ProgressEnd(); - - -class VDProgress { -public: - VDProgress(long lMax, const char *caption, const char *progresstext, const char *format, ...) { - ProgressStart(lMax, caption, progresstext, format); - } - - ~VDProgress() { - ProgressEnd(); - } - - void advance(long v) { - ProgressAdvance(v); - } -}; - -class VDProgressAbortable { -public: - VDProgressAbortable(long lMax, const char *caption, const char *progresstext, const char *format, ...) { - ProgressStart(lMax, caption, progresstext, format); - ProgressSetAbort(false); - } - - ~VDProgressAbortable() { - ProgressEnd(); - } - - void advance(long v) { - if (ProgressCheckAbort()) - throw MyUserAbortError(); - ProgressAdvance(v); - } -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_SYSTEM_PROGRESS_H +#define f_SYSTEM_PROGRESS_H + +#include + +class VDAtomicInt; +class VDSignalPersistent; + +class IProgress { +public: + virtual void Error(const char *)=0; + virtual void Warning(const char *)=0; + virtual bool Query(const char *query, bool fDefault)=0; + virtual void ProgressStart(const char *text, const char *caption, const char *progtext, long lMax)=0; + virtual void ProgressAdvance(long)=0; + virtual void ProgressEnd()=0; + virtual void Output(const char *text)=0; + virtual VDAtomicInt *ProgressGetAbortFlag()=0; + virtual VDSignalPersistent *ProgressGetAbortSignal()=0; +}; + + +void ProgressSetHandler(IProgress *pp); +IProgress *ProgressGetHandler(); + +bool ProgressCheckAbort(); +void ProgressSetAbort(bool bNewValue); +VDSignalPersistent *ProgressGetAbortSignal(); +void ProgressError(const class MyError&); +void ProgressWarning(const char *format, ...); +void ProgressOutput(const char *format, ...); +bool ProgressQuery(bool fDefault, const char *format, ...); +void ProgressStart(long lMax, const char *caption, const char *progresstext, const char *format, ...); +void ProgressAdvance(long lNewValue); +void ProgressEnd(); + + +class VDProgress { +public: + VDProgress(long lMax, const char *caption, const char *progresstext, const char *format, ...) { + ProgressStart(lMax, caption, progresstext, format); + } + + ~VDProgress() { + ProgressEnd(); + } + + void advance(long v) { + ProgressAdvance(v); + } +}; + +class VDProgressAbortable { +public: + VDProgressAbortable(long lMax, const char *caption, const char *progresstext, const char *format, ...) { + ProgressStart(lMax, caption, progresstext, format); + ProgressSetAbort(false); + } + + ~VDProgressAbortable() { + ProgressEnd(); + } + + void advance(long v) { + if (ProgressCheckAbort()) + throw MyUserAbortError(); + ProgressAdvance(v); + } +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/protscope.h b/src/thirdparty/VirtualDub/h/vd2/system/protscope.h index 2832271c4e2..6c22a54ad1f 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/protscope.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/protscope.h @@ -1,245 +1,245 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_PROTSCOPE_H -#define f_VD2_SYSTEM_PROTSCOPE_H - -#ifdef _MSC_VER - #pragma once -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// Protected scope macros -// -// These macros allow you to define a scope which is known to the crash -// handler -- that is, if the application crashes within a protected scope -// the handler will report the scope information in the crash output. -// - -class VDProtectedAutoScope; - -typedef VDProtectedAutoScope *(*tpVDGetProtectedScopeLink)(); -typedef void (*tpVDSetProtectedScopeLink)(VDProtectedAutoScope *); - -extern tpVDGetProtectedScopeLink g_pVDGetProtectedScopeLink; -extern tpVDSetProtectedScopeLink g_pVDSetProtectedScopeLink; - -// The reason for this function is a bug in the Intel compiler regarding -// construction optimization -- it stores VDProtectedAutoScope::'vtable' -// in the vtable slot instead of VDProtectedAutoScope1::'vtable', thus -// killing the printf()s. "volatile" doesn't work to fix the problem, but -// calling an opaque global function does. Oh well. - -#ifdef __INTEL_COMPILER -void VDProtectedAutoScopeICLWorkaround(); -#endif - -class IVDProtectedScopeOutput { -public: - virtual void write(const char *s) = 0; - virtual void writef(const char *s, ...) = 0; -}; - -class VDProtectedAutoScope { -public: - VDProtectedAutoScope(const char *file, int line, const char *action) : mpFile(file), mLine(line), mpAction(action), mpLink(g_pVDGetProtectedScopeLink()) { - // Note that the assignment to g_protectedScopeLink cannot occur here, as the - // derived class has not been constructed yet. Uninitialized objects in - // the debugging chain are *bad*. - } - - ~VDProtectedAutoScope() { - g_pVDSetProtectedScopeLink(mpLink); - } - - operator bool() const { return false; } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.write(mpAction); - } - - VDProtectedAutoScope *mpLink; - const char *const mpFile; - const int mLine; - const char *const mpAction; -}; - -class VDProtectedAutoScopeData0 { -public: - VDProtectedAutoScopeData0(const char *file, int line, const char *action) : mpFile(file), mLine(line), mpAction(action) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; -}; - -template -class VDProtectedAutoScopeData1 { -public: - VDProtectedAutoScopeData1(const char *file, int line, const char *action, const T1 a1) : mpFile(file), mLine(line), mpAction(action), mArg1(a1) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; - const T1 mArg1; -}; - -template -class VDProtectedAutoScopeData2 { -public: - VDProtectedAutoScopeData2(const char *file, int line, const char *action, const T1 a1, const T2 a2) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; - const T1 mArg1; - const T2 mArg2; -}; - -template -class VDProtectedAutoScopeData3 { -public: - VDProtectedAutoScopeData3(const char *file, int line, const char *action, const T1 a1, const T2 a2, const T3 a3) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2), mArg3(a3) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; - const T1 mArg1; - const T2 mArg2; - const T3 mArg3; -}; - -template -class VDProtectedAutoScopeData4 { -public: - VDProtectedAutoScopeData4(const char *file, int line, const char *action, const T1 a1, const T2 a2, const T3 a3, const T4 a4) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2), mArg3(a3), mArg4(a4) {} - const char *const mpFile; - const int mLine; - const char *const mpAction; - const T1 mArg1; - const T2 mArg2; - const T3 mArg3; - const T4 mArg4; -}; - -class VDProtectedAutoScope0 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope0(const VDProtectedAutoScopeData0& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } -}; - -template -class VDProtectedAutoScope1 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope1(const VDProtectedAutoScopeData1& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.writef(mpAction, mArg1); - } - - const T1 mArg1; -}; - -template -class VDProtectedAutoScope2 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope2(const VDProtectedAutoScopeData2& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.writef(mpAction, mArg1, mArg2); - } - - const T1 mArg1; - const T2 mArg2; -}; - -template -class VDProtectedAutoScope3 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope3(const VDProtectedAutoScopeData3& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2), mArg3(data.mArg3) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.writef(mpAction, mArg1, mArg2, mArg3); - } - - const T1 mArg1; - const T2 mArg2; - const T3 mArg3; -}; - -template -class VDProtectedAutoScope4 : public VDProtectedAutoScope { -public: - VDProtectedAutoScope4(const VDProtectedAutoScopeData4& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2), mArg3(data.mArg3), mArg4(data.mArg4) { - g_pVDSetProtectedScopeLink(this); -#ifdef __INTEL_COMPILER - VDProtectedAutoScopeICLWorkaround(); -#endif - } - - virtual void Write(IVDProtectedScopeOutput& out) { - out.writef(mpAction, mArg1, mArg2, mArg3, mArg4); - } - - const T1 mArg1; - const T2 mArg2; - const T3 mArg3; - const T4 mArg4; -}; - - -#define vdprotected(action) vdobjectscope(VDProtectedAutoScope0 autoscope = VDProtectedAutoScopeData0(__FILE__, __LINE__, action)) -#define vdprotected1(actionf, type1, arg1) vdobjectscope(VDProtectedAutoScope1 autoscope = VDProtectedAutoScopeData1(__FILE__, __LINE__, actionf, arg1)) - -// @&#(* preprocessor doesn't view template brackets as escaping commas, so we have a slight -// problem.... - -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || defined(VD_COMPILER_MSVC_VC8_DDK)) -#define vdprotected2(actionf, type1, arg1, type2, arg2) if(VDProtectedAutoScope2 autoscope = VDProtectedAutoScopeData2(__FILE__, __LINE__, actionf, arg1, arg2)) VDNEVERHERE; else -#define vdprotected3(actionf, type1, arg1, type2, arg2, type3, arg3) if(VDProtectedAutoScope3 autoscope = VDProtectedAutoScopeData3(__FILE__, __LINE__, actionf, arg1, arg2, arg3)) VDNEVERHERE; else -#define vdprotected4(actionf, type1, arg1, type2, arg2, type3, arg3, type4, arg4) if(VDProtectedAutoScope4 autoscope = VDProtectedAutoScopeData4(__FILE__, __LINE__, actionf, arg1, arg2, arg3, arg4)) VDNEVERHERE; else -#else -#define vdprotected2(actionf, type1, arg1, type2, arg2) switch(VDProtectedAutoScope2 autoscope = VDProtectedAutoScopeData2(__FILE__, __LINE__, actionf, arg1, arg2)) case 0: default: -#define vdprotected3(actionf, type1, arg1, type2, arg2, type3, arg3) switch(VDProtectedAutoScope3 autoscope = VDProtectedAutoScopeData3(__FILE__, __LINE__, actionf, arg1, arg2, arg3)) case 0: default: -#define vdprotected4(actionf, type1, arg1, type2, arg2, type3, arg3, type4, arg4) switch(VDProtectedAutoScope4 autoscope = VDProtectedAutoScopeData4(__FILE__, __LINE__, actionf, arg1, arg2, arg3, arg4)) case 0: default: -#endif - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_PROTSCOPE_H +#define f_VD2_SYSTEM_PROTSCOPE_H + +#ifdef _MSC_VER + #pragma once +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// Protected scope macros +// +// These macros allow you to define a scope which is known to the crash +// handler -- that is, if the application crashes within a protected scope +// the handler will report the scope information in the crash output. +// + +class VDProtectedAutoScope; + +typedef VDProtectedAutoScope *(*tpVDGetProtectedScopeLink)(); +typedef void (*tpVDSetProtectedScopeLink)(VDProtectedAutoScope *); + +extern tpVDGetProtectedScopeLink g_pVDGetProtectedScopeLink; +extern tpVDSetProtectedScopeLink g_pVDSetProtectedScopeLink; + +// The reason for this function is a bug in the Intel compiler regarding +// construction optimization -- it stores VDProtectedAutoScope::'vtable' +// in the vtable slot instead of VDProtectedAutoScope1::'vtable', thus +// killing the printf()s. "volatile" doesn't work to fix the problem, but +// calling an opaque global function does. Oh well. + +#ifdef __INTEL_COMPILER +void VDProtectedAutoScopeICLWorkaround(); +#endif + +class IVDProtectedScopeOutput { +public: + virtual void write(const char *s) = 0; + virtual void writef(const char *s, ...) = 0; +}; + +class VDProtectedAutoScope { +public: + VDProtectedAutoScope(const char *file, int line, const char *action) : mpFile(file), mLine(line), mpAction(action), mpLink(g_pVDGetProtectedScopeLink()) { + // Note that the assignment to g_protectedScopeLink cannot occur here, as the + // derived class has not been constructed yet. Uninitialized objects in + // the debugging chain are *bad*. + } + + ~VDProtectedAutoScope() { + g_pVDSetProtectedScopeLink(mpLink); + } + + operator bool() const { return false; } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.write(mpAction); + } + + VDProtectedAutoScope *mpLink; + const char *const mpFile; + const int mLine; + const char *const mpAction; +}; + +class VDProtectedAutoScopeData0 { +public: + VDProtectedAutoScopeData0(const char *file, int line, const char *action) : mpFile(file), mLine(line), mpAction(action) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; +}; + +template +class VDProtectedAutoScopeData1 { +public: + VDProtectedAutoScopeData1(const char *file, int line, const char *action, const T1 a1) : mpFile(file), mLine(line), mpAction(action), mArg1(a1) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; + const T1 mArg1; +}; + +template +class VDProtectedAutoScopeData2 { +public: + VDProtectedAutoScopeData2(const char *file, int line, const char *action, const T1 a1, const T2 a2) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; + const T1 mArg1; + const T2 mArg2; +}; + +template +class VDProtectedAutoScopeData3 { +public: + VDProtectedAutoScopeData3(const char *file, int line, const char *action, const T1 a1, const T2 a2, const T3 a3) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2), mArg3(a3) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; + const T1 mArg1; + const T2 mArg2; + const T3 mArg3; +}; + +template +class VDProtectedAutoScopeData4 { +public: + VDProtectedAutoScopeData4(const char *file, int line, const char *action, const T1 a1, const T2 a2, const T3 a3, const T4 a4) : mpFile(file), mLine(line), mpAction(action), mArg1(a1), mArg2(a2), mArg3(a3), mArg4(a4) {} + const char *const mpFile; + const int mLine; + const char *const mpAction; + const T1 mArg1; + const T2 mArg2; + const T3 mArg3; + const T4 mArg4; +}; + +class VDProtectedAutoScope0 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope0(const VDProtectedAutoScopeData0& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } +}; + +template +class VDProtectedAutoScope1 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope1(const VDProtectedAutoScopeData1& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.writef(mpAction, mArg1); + } + + const T1 mArg1; +}; + +template +class VDProtectedAutoScope2 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope2(const VDProtectedAutoScopeData2& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.writef(mpAction, mArg1, mArg2); + } + + const T1 mArg1; + const T2 mArg2; +}; + +template +class VDProtectedAutoScope3 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope3(const VDProtectedAutoScopeData3& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2), mArg3(data.mArg3) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.writef(mpAction, mArg1, mArg2, mArg3); + } + + const T1 mArg1; + const T2 mArg2; + const T3 mArg3; +}; + +template +class VDProtectedAutoScope4 : public VDProtectedAutoScope { +public: + VDProtectedAutoScope4(const VDProtectedAutoScopeData4& data) : VDProtectedAutoScope(data.mpFile, data.mLine, data.mpAction), mArg1(data.mArg1), mArg2(data.mArg2), mArg3(data.mArg3), mArg4(data.mArg4) { + g_pVDSetProtectedScopeLink(this); +#ifdef __INTEL_COMPILER + VDProtectedAutoScopeICLWorkaround(); +#endif + } + + virtual void Write(IVDProtectedScopeOutput& out) { + out.writef(mpAction, mArg1, mArg2, mArg3, mArg4); + } + + const T1 mArg1; + const T2 mArg2; + const T3 mArg3; + const T4 mArg4; +}; + + +#define vdprotected(action) vdobjectscope(VDProtectedAutoScope0 autoscope = VDProtectedAutoScopeData0(__FILE__, __LINE__, action)) +#define vdprotected1(actionf, type1, arg1) vdobjectscope(VDProtectedAutoScope1 autoscope = VDProtectedAutoScopeData1(__FILE__, __LINE__, actionf, arg1)) + +// @&#(* preprocessor doesn't view template brackets as escaping commas, so we have a slight +// problem.... + +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || defined(VD_COMPILER_MSVC_VC8_DDK)) +#define vdprotected2(actionf, type1, arg1, type2, arg2) if(VDProtectedAutoScope2 autoscope = VDProtectedAutoScopeData2(__FILE__, __LINE__, actionf, arg1, arg2)) VDNEVERHERE; else +#define vdprotected3(actionf, type1, arg1, type2, arg2, type3, arg3) if(VDProtectedAutoScope3 autoscope = VDProtectedAutoScopeData3(__FILE__, __LINE__, actionf, arg1, arg2, arg3)) VDNEVERHERE; else +#define vdprotected4(actionf, type1, arg1, type2, arg2, type3, arg3, type4, arg4) if(VDProtectedAutoScope4 autoscope = VDProtectedAutoScopeData4(__FILE__, __LINE__, actionf, arg1, arg2, arg3, arg4)) VDNEVERHERE; else +#else +#define vdprotected2(actionf, type1, arg1, type2, arg2) switch(VDProtectedAutoScope2 autoscope = VDProtectedAutoScopeData2(__FILE__, __LINE__, actionf, arg1, arg2)) case 0: default: +#define vdprotected3(actionf, type1, arg1, type2, arg2, type3, arg3) switch(VDProtectedAutoScope3 autoscope = VDProtectedAutoScopeData3(__FILE__, __LINE__, actionf, arg1, arg2, arg3)) case 0: default: +#define vdprotected4(actionf, type1, arg1, type2, arg2, type3, arg3, type4, arg4) switch(VDProtectedAutoScope4 autoscope = VDProtectedAutoScopeData4(__FILE__, __LINE__, actionf, arg1, arg2, arg3, arg4)) case 0: default: +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/refcount.h b/src/thirdparty/VirtualDub/h/vd2/system/refcount.h index 2e56682ac0d..346595eff67 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/refcount.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/refcount.h @@ -1,347 +1,347 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_REFCOUNT_H -#define f_VD2_SYSTEM_REFCOUNT_H - -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// IVDRefCount -/// Base interface for reference-counted objects. -/// -/// Reference counting is a relatively straightforward and simple method -/// of garbage collection. The rules are: -/// -/// 1) Objects increment their reference count on an AddRef() and -/// decrement it on a Release(). -/// 2) Objects destroy themselves when their reference count is dropped -/// to zero. -/// 3) Clients create references with AddRef() and destroy them with -/// Release(). -/// -/// One way to interact with refcounted objects is to call AddRef() -/// whenever a pointer is created, and Release() when the pointer is -/// nulled or changed. The vdrefptr template does this automatically. -/// Reference counting may be "combined" between pointers for optimization -/// reasons, such that fewer reference counts are outstanding than actual -/// pointers; this requires weak (non-refcounted) pointers and explicit -/// refcount management. -/// -/// Reference counting has two issues: -/// -/// A) It is expensive. VirtualDub uses it somewhat sparingly. -/// -/// B) Reference counting cannot cope with cycles. This issue is -/// avoided by arranging objects in a clearly ordered tree, such that -/// no class ever holds a pointer to another object of the same class -/// or to a parent in the reference hierarchy. vdrefptr can -/// implicitly create cycles if you are not careful. -/// -/// In VirtualDub, reference counting must be multithread safe, so atomic -/// increment/decrement should be used. vdrefcounted handles this -/// automatically for the template type class. -/// -/// Two final implementation details: -/// -/// - Little or no code should be executed after the reference count -/// drops to zero, preferably nothing more than the destructor implicitly -/// generated by the compiler. The reason is that otherwise there is the -/// potential for an object to be resurrected past its final release by -/// temporarily creating a new reference on the object. -/// -/// - AddRef() and Release() traditionally return the reference count on -/// the object after increment or decrement, but this is not required. -/// For Release builds, it is only required that the value for Release() -/// be zero iff the object is destroyed. (The same applies for AddRef(), -/// but since the result of AddRef() is always non-zero, the return of -/// AddRef() is of no use unless it is the actual count.) -/// -class VDINTERFACE IVDRefCount { -public: - virtual int AddRef()=0; - virtual int Release()=0; -}; - -/////////////////////////////////////////////////////////////////////////// -class vdrefcount { -public: - vdrefcount() : mRefCount(0) {} - vdrefcount(const vdrefcount& src) : mRefCount(0) {} // do not copy the refcount - virtual ~vdrefcount() {} - - vdrefcount& operator=(const vdrefcount&) {} // do not copy the refcount - - int AddRef() { - return mRefCount.inc(); - } - - int Release() { - int rc = --mRefCount; - - if (!rc) { - delete this; - return 0; - } - - VDASSERT(rc > 0); - return rc; - } - -protected: - VDAtomicInt mRefCount; -}; - -/////////////////////////////////////////////////////////////////////////// -// vdrefcounted -/// Implements thread-safe reference counting on top of a base class. -/// -/// vdrefcounted is used to either add reference counting to a base -/// class or to implement it on an interface. Use it by deriving your -/// class from it. -/// -template class vdrefcounted : public T { -public: - vdrefcounted() : mRefCount(0) {} - vdrefcounted(const vdrefcounted& src) : mRefCount(0) {} // do not copy the refcount - virtual ~vdrefcounted() {} - - vdrefcounted& operator=(const vdrefcounted&) {} // do not copy the refcount - - inline virtual int AddRef() { - return mRefCount.inc(); - } - - inline virtual int Release() { - int rc = --mRefCount; - - if (!rc) { - delete this; - return 0; - } - - VDASSERT(rc > 0); - - return rc; - } - -protected: - VDAtomicInt mRefCount; -}; - -/////////////////////////////////////////////////////////////////////////// -// vdrefptr -/// Reference-counting smart pointer. -/// -/// Maintains a strong reference on any object that supports AddRef/Release -/// semantics. This includes any interface including IVDRefCount, -/// IVDRefUnknown, or the IUnknown interface in Microsoft COM. Because -/// references are automatically traded as necessary, smart pointers are -/// very useful for maintaining exception safety. -/// -template class vdrefptr { -protected: - T *ptr; - -public: - typedef vdrefptr self_type; - typedef T element_type; - - /// Creates a new smart pointer and obtains a new reference on the - /// specified object. - explicit vdrefptr(T *p = 0) : ptr(p) { - if (p) - p->AddRef(); - } - - /// Clones a smart pointer, duplicating any held reference. - vdrefptr(const self_type& src) { - ptr = src.ptr; - if (ptr) - ptr->AddRef(); - } - - /// Destroys the smart pointer, releasing any held reference. - ~vdrefptr() { - if (ptr) - ptr->Release(); - } - - /// Assigns a new object to a smart pointer. Any old object is released - /// and the new object is addrefed. - inline self_type& operator=(T *src) { - if (src) - src->AddRef(); - if (ptr) - ptr->Release(); - ptr = src; - return *this; - } - - /// Assigns a new object to a smart pointer. Any old object is released - /// and the new object is addrefed. - inline self_type& operator=(const vdrefptr& src) { - if (src.ptr) - src.ptr->AddRef(); - if (ptr) - ptr->Release(); - ptr = src.ptr; - return *this; - } - - operator T*() const { return ptr; } - T& operator*() const { return *ptr; } - T *operator->() const { return ptr; } - - /// Removes any old reference and returns a double-pointer to the nulled - /// internal pointer. This is useful for passing to IUnknown-derived - /// interfaces that accept (T **) parameters, like QueryInterface(). - T** operator~() { - if (ptr) { - ptr->Release(); - ptr = NULL; - } - return &ptr; - } - - /// Removes any held reference. - inline void clear() { - if (ptr) - ptr->Release(); - ptr = NULL; - } - - /// Removes any existing reference and moves a reference from another - /// smart pointer. The source pointer is cleared afterward. - inline void from(vdrefptr& src) { - if (ptr) - ptr->Release(); - ptr = src.ptr; - src.ptr = NULL; - } - - /// Removes any existing reference and accepts a reference to a new - /// object without actually obtaining one. This is useful if someone - /// has already addrefed an object for you. - inline void set(T* src) { - if (ptr) - ptr->Release(); - - ptr = src; - } - - /// Returns the held reference and clears the smart pointer without - /// releasing the reference. This is useful for holding onto a reference - /// in an exception-safe manner up until the last moment. - inline T *release() { - T *p = ptr; - ptr = NULL; - return p; - } - - /// Swaps the references between two smart pointers. - void swap(vdrefptr& r) { - T *p = ptr; - ptr = r.ptr; - r.ptr = p; - } -}; - -/////////////////////////////////////////////////////////////////////////// - -template -bool VDRefCountObjectFactory(U **pp) { - T *p = new_nothrow T; - if (!p) - return false; - - *pp = static_cast(p); - p->AddRef(); - return true; -} - -/////////////////////////////////////////////////////////////////////////// - -struct vdsaferelease_t {}; -extern vdsaferelease_t vdsaferelease; - -template -inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *& p) { - if (p) { - p->Release(); - p = 0; - } - - return x; -} - -template -inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *& p) { - if (p) { - p->Release(); - p = 0; - } - - return x; -} - -template -inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *(&p)[N]) { - for(size_t i=0; iRelease(); - p[i] = 0; - } - } - - return x; -} - -template -inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *(&p)[N]) { - for(size_t i=0; iRelease(); - p[i] = 0; - } - } - - return x; -} - -/////////////////////////////////////////////////////////////////////////// - -template -void VDReleaseObjects(const T& container) { - for(typename T::const_iterator it(container.begin()), itEnd(container.end()); - it != itEnd; - ++it) - { - (*it)->Release(); - } -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_REFCOUNT_H +#define f_VD2_SYSTEM_REFCOUNT_H + +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// IVDRefCount +/// Base interface for reference-counted objects. +/// +/// Reference counting is a relatively straightforward and simple method +/// of garbage collection. The rules are: +/// +/// 1) Objects increment their reference count on an AddRef() and +/// decrement it on a Release(). +/// 2) Objects destroy themselves when their reference count is dropped +/// to zero. +/// 3) Clients create references with AddRef() and destroy them with +/// Release(). +/// +/// One way to interact with refcounted objects is to call AddRef() +/// whenever a pointer is created, and Release() when the pointer is +/// nulled or changed. The vdrefptr template does this automatically. +/// Reference counting may be "combined" between pointers for optimization +/// reasons, such that fewer reference counts are outstanding than actual +/// pointers; this requires weak (non-refcounted) pointers and explicit +/// refcount management. +/// +/// Reference counting has two issues: +/// +/// A) It is expensive. VirtualDub uses it somewhat sparingly. +/// +/// B) Reference counting cannot cope with cycles. This issue is +/// avoided by arranging objects in a clearly ordered tree, such that +/// no class ever holds a pointer to another object of the same class +/// or to a parent in the reference hierarchy. vdrefptr can +/// implicitly create cycles if you are not careful. +/// +/// In VirtualDub, reference counting must be multithread safe, so atomic +/// increment/decrement should be used. vdrefcounted handles this +/// automatically for the template type class. +/// +/// Two final implementation details: +/// +/// - Little or no code should be executed after the reference count +/// drops to zero, preferably nothing more than the destructor implicitly +/// generated by the compiler. The reason is that otherwise there is the +/// potential for an object to be resurrected past its final release by +/// temporarily creating a new reference on the object. +/// +/// - AddRef() and Release() traditionally return the reference count on +/// the object after increment or decrement, but this is not required. +/// For Release builds, it is only required that the value for Release() +/// be zero iff the object is destroyed. (The same applies for AddRef(), +/// but since the result of AddRef() is always non-zero, the return of +/// AddRef() is of no use unless it is the actual count.) +/// +class VDINTERFACE IVDRefCount { +public: + virtual int AddRef()=0; + virtual int Release()=0; +}; + +/////////////////////////////////////////////////////////////////////////// +class vdrefcount { +public: + vdrefcount() : mRefCount(0) {} + vdrefcount(const vdrefcount& src) : mRefCount(0) {} // do not copy the refcount + virtual ~vdrefcount() {} + + vdrefcount& operator=(const vdrefcount&) {} // do not copy the refcount + + int AddRef() { + return mRefCount.inc(); + } + + int Release() { + int rc = --mRefCount; + + if (!rc) { + delete this; + return 0; + } + + VDASSERT(rc > 0); + return rc; + } + +protected: + VDAtomicInt mRefCount; +}; + +/////////////////////////////////////////////////////////////////////////// +// vdrefcounted +/// Implements thread-safe reference counting on top of a base class. +/// +/// vdrefcounted is used to either add reference counting to a base +/// class or to implement it on an interface. Use it by deriving your +/// class from it. +/// +template class vdrefcounted : public T { +public: + vdrefcounted() : mRefCount(0) {} + vdrefcounted(const vdrefcounted& src) : mRefCount(0) {} // do not copy the refcount + virtual ~vdrefcounted() {} + + vdrefcounted& operator=(const vdrefcounted&) {} // do not copy the refcount + + inline virtual int AddRef() { + return mRefCount.inc(); + } + + inline virtual int Release() { + int rc = --mRefCount; + + if (!rc) { + delete this; + return 0; + } + + VDASSERT(rc > 0); + + return rc; + } + +protected: + VDAtomicInt mRefCount; +}; + +/////////////////////////////////////////////////////////////////////////// +// vdrefptr +/// Reference-counting smart pointer. +/// +/// Maintains a strong reference on any object that supports AddRef/Release +/// semantics. This includes any interface including IVDRefCount, +/// IVDRefUnknown, or the IUnknown interface in Microsoft COM. Because +/// references are automatically traded as necessary, smart pointers are +/// very useful for maintaining exception safety. +/// +template class vdrefptr { +protected: + T *ptr; + +public: + typedef vdrefptr self_type; + typedef T element_type; + + /// Creates a new smart pointer and obtains a new reference on the + /// specified object. + explicit vdrefptr(T *p = 0) : ptr(p) { + if (p) + p->AddRef(); + } + + /// Clones a smart pointer, duplicating any held reference. + vdrefptr(const self_type& src) { + ptr = src.ptr; + if (ptr) + ptr->AddRef(); + } + + /// Destroys the smart pointer, releasing any held reference. + ~vdrefptr() { + if (ptr) + ptr->Release(); + } + + /// Assigns a new object to a smart pointer. Any old object is released + /// and the new object is addrefed. + inline self_type& operator=(T *src) { + if (src) + src->AddRef(); + if (ptr) + ptr->Release(); + ptr = src; + return *this; + } + + /// Assigns a new object to a smart pointer. Any old object is released + /// and the new object is addrefed. + inline self_type& operator=(const vdrefptr& src) { + if (src.ptr) + src.ptr->AddRef(); + if (ptr) + ptr->Release(); + ptr = src.ptr; + return *this; + } + + operator T*() const { return ptr; } + T& operator*() const { return *ptr; } + T *operator->() const { return ptr; } + + /// Removes any old reference and returns a double-pointer to the nulled + /// internal pointer. This is useful for passing to IUnknown-derived + /// interfaces that accept (T **) parameters, like QueryInterface(). + T** operator~() { + if (ptr) { + ptr->Release(); + ptr = NULL; + } + return &ptr; + } + + /// Removes any held reference. + inline void clear() { + if (ptr) + ptr->Release(); + ptr = NULL; + } + + /// Removes any existing reference and moves a reference from another + /// smart pointer. The source pointer is cleared afterward. + inline void from(vdrefptr& src) { + if (ptr) + ptr->Release(); + ptr = src.ptr; + src.ptr = NULL; + } + + /// Removes any existing reference and accepts a reference to a new + /// object without actually obtaining one. This is useful if someone + /// has already addrefed an object for you. + inline void set(T* src) { + if (ptr) + ptr->Release(); + + ptr = src; + } + + /// Returns the held reference and clears the smart pointer without + /// releasing the reference. This is useful for holding onto a reference + /// in an exception-safe manner up until the last moment. + inline T *release() { + T *p = ptr; + ptr = NULL; + return p; + } + + /// Swaps the references between two smart pointers. + void swap(vdrefptr& r) { + T *p = ptr; + ptr = r.ptr; + r.ptr = p; + } +}; + +/////////////////////////////////////////////////////////////////////////// + +template +bool VDRefCountObjectFactory(U **pp) { + T *p = new_nothrow T; + if (!p) + return false; + + *pp = static_cast(p); + p->AddRef(); + return true; +} + +/////////////////////////////////////////////////////////////////////////// + +struct vdsaferelease_t {}; +extern vdsaferelease_t vdsaferelease; + +template +inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *& p) { + if (p) { + p->Release(); + p = 0; + } + + return x; +} + +template +inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *& p) { + if (p) { + p->Release(); + p = 0; + } + + return x; +} + +template +inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *(&p)[N]) { + for(size_t i=0; iRelease(); + p[i] = 0; + } + } + + return x; +} + +template +inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *(&p)[N]) { + for(size_t i=0; iRelease(); + p[i] = 0; + } + } + + return x; +} + +/////////////////////////////////////////////////////////////////////////// + +template +void VDReleaseObjects(const T& container) { + for(typename T::const_iterator it(container.begin()), itEnd(container.end()); + it != itEnd; + ++it) + { + (*it)->Release(); + } +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/registry.h b/src/thirdparty/VirtualDub/h/vd2/system/registry.h index b741ff4f2b0..426f2c48582 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/registry.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/registry.h @@ -1,155 +1,155 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_REGISTRY_H -#define f_VD2_SYSTEM_REGISTRY_H - -#include - -class IVDRegistryProvider { -public: - enum Type { - kTypeUnknown, - kTypeInt, - kTypeString, - kTypeBinary - }; - - virtual void *GetMachineKey() = 0; - virtual void *GetUserKey() = 0; - virtual void *CreateKey(void *key, const char *path, bool write) = 0; - virtual void CloseKey(void *key) = 0; - - virtual bool SetBool(void *key, const char *name, bool) = 0; - virtual bool SetInt(void *key, const char *name, int) = 0; - virtual bool SetString(void *key, const char *name, const char *pszString) = 0; - virtual bool SetString(void *key, const char *name, const wchar_t *pszString) = 0; - virtual bool SetBinary(void *key, const char *name, const char *data, int len) = 0; - - virtual Type GetType(void *key, const char *name) = 0; - virtual bool GetBool(void *key, const char *name, bool& val) = 0; - virtual bool GetInt(void *key, const char *name, int& val) = 0; - virtual bool GetString(void *key, const char *name, VDStringA& s) = 0; - virtual bool GetString(void *key, const char *name, VDStringW& s) = 0; - - virtual int GetBinaryLength(void *key, const char *name) = 0; - virtual bool GetBinary(void *key, const char *name, char *buf, int maxlen) = 0; - - virtual bool RemoveValue(void *key, const char *name) = 0; - virtual bool RemoveKey(void *key, const char *name) = 0; - - virtual void *EnumKeysBegin(void *key) = 0; - virtual const char *EnumKeysNext(void *enumerator) = 0; - virtual void EnumKeysClose(void *enumerator) = 0; - - virtual void *EnumValuesBegin(void *key) = 0; - virtual const char *EnumValuesNext(void *enumerator) = 0; - virtual void EnumValuesClose(void *enumerator) = 0; -}; - -IVDRegistryProvider *VDGetRegistryProvider(); -void VDSetRegistryProvider(IVDRegistryProvider *provider); - -/////////////////////////////////////////////////////////////////////////// - -class VDRegistryKey { -public: - enum Type { - kTypeUnknown, - kTypeInt, - kTypeString, - kTypeBinary - }; - - VDRegistryKey(const char *pszKey, bool global = false, bool write = true); - VDRegistryKey(VDRegistryKey& baseKey, const char *name, bool write = true); - ~VDRegistryKey(); - - void *getRawHandle() const { return mKey; } - - bool isReady() const { return mKey != 0; } - - bool setBool(const char *name, bool) const; - bool setInt(const char *name, int) const; - bool setString(const char *name, const char *pszString) const; - bool setString(const char *name, const wchar_t *pszString) const; - bool setBinary(const char *name, const char *data, int len) const; - - Type getValueType(const char *name) const; - - bool getBool(const char *name, bool def=false) const; - int getInt(const char *name, int def=0) const; - int getEnumInt(const char *name, int maxVal, int def=0) const; - bool getString(const char *name, VDStringA& s) const; - bool getString(const char *name, VDStringW& s) const; - - int getBinaryLength(const char *name) const; - bool getBinary(const char *name, char *buf, int maxlen) const; - - bool removeValue(const char *); - bool removeKey(const char *); - -private: - void *mKey; -}; - -class VDRegistryValueIterator { - VDRegistryValueIterator(const VDRegistryValueIterator&); - VDRegistryValueIterator& operator=(const VDRegistryValueIterator&); -public: - VDRegistryValueIterator(const VDRegistryKey& key); - ~VDRegistryValueIterator(); - - const char *Next(); - -protected: - void *mEnumerator; -}; - -class VDRegistryKeyIterator { - VDRegistryKeyIterator(const VDRegistryKeyIterator& key); - VDRegistryKeyIterator& operator=(const VDRegistryKeyIterator& key); -public: - VDRegistryKeyIterator(const VDRegistryKey& key); - ~VDRegistryKeyIterator(); - - const char *Next(); - -protected: - void *mEnumerator; -}; - -class VDRegistryAppKey : public VDRegistryKey { -private: - static VDString s_appbase; - -public: - VDRegistryAppKey(); - VDRegistryAppKey(const char *pszKey, bool write = true, bool global = false); - - static void setDefaultKey(const char *pszAppName); -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_REGISTRY_H +#define f_VD2_SYSTEM_REGISTRY_H + +#include + +class IVDRegistryProvider { +public: + enum Type { + kTypeUnknown, + kTypeInt, + kTypeString, + kTypeBinary + }; + + virtual void *GetMachineKey() = 0; + virtual void *GetUserKey() = 0; + virtual void *CreateKey(void *key, const char *path, bool write) = 0; + virtual void CloseKey(void *key) = 0; + + virtual bool SetBool(void *key, const char *name, bool) = 0; + virtual bool SetInt(void *key, const char *name, int) = 0; + virtual bool SetString(void *key, const char *name, const char *pszString) = 0; + virtual bool SetString(void *key, const char *name, const wchar_t *pszString) = 0; + virtual bool SetBinary(void *key, const char *name, const char *data, int len) = 0; + + virtual Type GetType(void *key, const char *name) = 0; + virtual bool GetBool(void *key, const char *name, bool& val) = 0; + virtual bool GetInt(void *key, const char *name, int& val) = 0; + virtual bool GetString(void *key, const char *name, VDStringA& s) = 0; + virtual bool GetString(void *key, const char *name, VDStringW& s) = 0; + + virtual int GetBinaryLength(void *key, const char *name) = 0; + virtual bool GetBinary(void *key, const char *name, char *buf, int maxlen) = 0; + + virtual bool RemoveValue(void *key, const char *name) = 0; + virtual bool RemoveKey(void *key, const char *name) = 0; + + virtual void *EnumKeysBegin(void *key) = 0; + virtual const char *EnumKeysNext(void *enumerator) = 0; + virtual void EnumKeysClose(void *enumerator) = 0; + + virtual void *EnumValuesBegin(void *key) = 0; + virtual const char *EnumValuesNext(void *enumerator) = 0; + virtual void EnumValuesClose(void *enumerator) = 0; +}; + +IVDRegistryProvider *VDGetRegistryProvider(); +void VDSetRegistryProvider(IVDRegistryProvider *provider); + +/////////////////////////////////////////////////////////////////////////// + +class VDRegistryKey { +public: + enum Type { + kTypeUnknown, + kTypeInt, + kTypeString, + kTypeBinary + }; + + VDRegistryKey(const char *pszKey, bool global = false, bool write = true); + VDRegistryKey(VDRegistryKey& baseKey, const char *name, bool write = true); + ~VDRegistryKey(); + + void *getRawHandle() const { return mKey; } + + bool isReady() const { return mKey != 0; } + + bool setBool(const char *name, bool) const; + bool setInt(const char *name, int) const; + bool setString(const char *name, const char *pszString) const; + bool setString(const char *name, const wchar_t *pszString) const; + bool setBinary(const char *name, const char *data, int len) const; + + Type getValueType(const char *name) const; + + bool getBool(const char *name, bool def=false) const; + int getInt(const char *name, int def=0) const; + int getEnumInt(const char *name, int maxVal, int def=0) const; + bool getString(const char *name, VDStringA& s) const; + bool getString(const char *name, VDStringW& s) const; + + int getBinaryLength(const char *name) const; + bool getBinary(const char *name, char *buf, int maxlen) const; + + bool removeValue(const char *); + bool removeKey(const char *); + +private: + void *mKey; +}; + +class VDRegistryValueIterator { + VDRegistryValueIterator(const VDRegistryValueIterator&); + VDRegistryValueIterator& operator=(const VDRegistryValueIterator&); +public: + VDRegistryValueIterator(const VDRegistryKey& key); + ~VDRegistryValueIterator(); + + const char *Next(); + +protected: + void *mEnumerator; +}; + +class VDRegistryKeyIterator { + VDRegistryKeyIterator(const VDRegistryKeyIterator& key); + VDRegistryKeyIterator& operator=(const VDRegistryKeyIterator& key); +public: + VDRegistryKeyIterator(const VDRegistryKey& key); + ~VDRegistryKeyIterator(); + + const char *Next(); + +protected: + void *mEnumerator; +}; + +class VDRegistryAppKey : public VDRegistryKey { +private: + static VDString s_appbase; + +public: + VDRegistryAppKey(); + VDRegistryAppKey(const char *pszKey, bool write = true, bool global = false); + + static void setDefaultKey(const char *pszAppName); +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/registrymemory.h b/src/thirdparty/VirtualDub/h/vd2/system/registrymemory.h index 9a2d98daa6c..38e2a9c452e 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/registrymemory.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/registrymemory.h @@ -1,81 +1,81 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_REGISTRYMEMORY_H -#define f_VD2_SYSTEM_REGISTRYMEMORY_H - -#include -#include -#include -#include - -class VDRegistryProviderMemory : public IVDRegistryProvider { -public: - VDRegistryProviderMemory(); - ~VDRegistryProviderMemory(); - - void *GetMachineKey(); - void *GetUserKey(); - void *CreateKey(void *key, const char *path, bool write); - void CloseKey(void *key); - - bool SetBool(void *key, const char *name, bool); - bool SetInt(void *key, const char *name, int); - bool SetString(void *key, const char *name, const char *str); - bool SetString(void *key, const char *name, const wchar_t *str); - bool SetBinary(void *key, const char *name, const char *data, int len); - - Type GetType(void *key, const char *name); - bool GetBool(void *key, const char *name, bool& val); - bool GetInt(void *key, const char *name, int& val); - bool GetString(void *key, const char *name, VDStringA& s); - bool GetString(void *key, const char *name, VDStringW& s); - - int GetBinaryLength(void *key, const char *name); - bool GetBinary(void *key, const char *name, char *buf, int maxlen); - - bool RemoveValue(void *key, const char *name); - bool RemoveKey(void *key, const char *name); - - void *EnumKeysBegin(void *key); - const char *EnumKeysNext(void *enumerator); - void EnumKeysClose(void *enumerator); - - void *EnumValuesBegin(void *key); - const char *EnumValuesNext(void *enumerator); - void EnumValuesClose(void *enumerator); - -protected: - class Key; - class Value; - struct Enumerator; - - Key *mpUserKey; - Key *mpMachineKey; - - VDCriticalSection mMutex; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_REGISTRYMEMORY_H +#define f_VD2_SYSTEM_REGISTRYMEMORY_H + +#include +#include +#include +#include + +class VDRegistryProviderMemory : public IVDRegistryProvider { +public: + VDRegistryProviderMemory(); + ~VDRegistryProviderMemory(); + + void *GetMachineKey(); + void *GetUserKey(); + void *CreateKey(void *key, const char *path, bool write); + void CloseKey(void *key); + + bool SetBool(void *key, const char *name, bool); + bool SetInt(void *key, const char *name, int); + bool SetString(void *key, const char *name, const char *str); + bool SetString(void *key, const char *name, const wchar_t *str); + bool SetBinary(void *key, const char *name, const char *data, int len); + + Type GetType(void *key, const char *name); + bool GetBool(void *key, const char *name, bool& val); + bool GetInt(void *key, const char *name, int& val); + bool GetString(void *key, const char *name, VDStringA& s); + bool GetString(void *key, const char *name, VDStringW& s); + + int GetBinaryLength(void *key, const char *name); + bool GetBinary(void *key, const char *name, char *buf, int maxlen); + + bool RemoveValue(void *key, const char *name); + bool RemoveKey(void *key, const char *name); + + void *EnumKeysBegin(void *key); + const char *EnumKeysNext(void *enumerator); + void EnumKeysClose(void *enumerator); + + void *EnumValuesBegin(void *key); + const char *EnumValuesNext(void *enumerator); + void EnumValuesClose(void *enumerator); + +protected: + class Key; + class Value; + struct Enumerator; + + Key *mpUserKey; + Key *mpMachineKey; + + VDCriticalSection mMutex; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/source/registrymemory.cpp b/src/thirdparty/VirtualDub/h/vd2/system/source/registrymemory.cpp index 8e50463d18d..020e7d66833 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/source/registrymemory.cpp +++ b/src/thirdparty/VirtualDub/h/vd2/system/source/registrymemory.cpp @@ -1,669 +1,669 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include - -class VDRegistryProviderMemory::Value : public vdhashtable_base_node { -public: - enum Type { - kTypeInt, - kTypeString, - kTypeBinary - }; - - Value(); - - void SetInt(sint32 v); - void SetString(const wchar_t *str); - void SetBinary(const void *p, size_t len); - - Type GetType() const { return mType; } - - bool GetInt(sint32& v) const; - bool GetString(const wchar_t *&s) const; - bool GetBinary(const void *&p, size_t& len) const; - -protected: - Type mType; - - // we're being lazy for now - sint32 mInt; - VDStringW mString; - vdfastvector mRawData; -}; - -VDRegistryProviderMemory::Value::Value() - : mType(kTypeInt) - , mInt(0) -{ -} - -void VDRegistryProviderMemory::Value::SetInt(sint32 v) { - if (mType != kTypeInt) { - mString.swap(VDStringW()); - mRawData.swap(vdfastvector()); - mType = kTypeInt; - } - - mInt = v; -} - -void VDRegistryProviderMemory::Value::SetString(const wchar_t *str) { - if (mType != kTypeString) { - mRawData.swap(vdfastvector()); - mType = kTypeString; - } - - mString = str; -} - -void VDRegistryProviderMemory::Value::SetBinary(const void *p, size_t len) { - if (mType != kTypeBinary) { - mString.swap(VDStringW()); - mType = kTypeBinary; - } - - mRawData.assign((char *)p, (char *)p + len); -} - -bool VDRegistryProviderMemory::Value::GetInt(sint32& v) const { - if (mType != kTypeInt) - return false; - - v = mInt; - return true; -} - -bool VDRegistryProviderMemory::Value::GetString(const wchar_t *&s) const { - if (mType != kTypeString) - return false; - - s = mString.c_str(); - return true; -} - -bool VDRegistryProviderMemory::Value::GetBinary(const void *&p, size_t& len) const { - if (mType != kTypeBinary) - return false; - - p = mRawData.data(); - len = mRawData.size(); - return true; -} - -class VDRegistryProviderMemory::Key { -public: - Key(); - ~Key(); - - void AddRef(); - void Release(); - - bool Add(const VDStringA& name, VDRegistryProviderMemory::Value *value); - void Remove(VDRegistryProviderMemory::Key *key); - bool RemoveKey(const char *name); - bool RemoveValue(const char *name); - - const char *GetKeyName(size_t index) const { - if (index >= mKeyList.size()) - return NULL; - - return mKeyList[index]->first.c_str(); - } - - const char *GetValueName(size_t index) const { - if (index >= mValueList.size()) - return NULL; - - return mValueList[index]->first.c_str(); - } - - Value *OpenValue(const char *name, bool create); - Key *OpenKey(const VDStringSpanA& name, bool create); - - int mRefCount; - bool mbCondemned; - - Key *mpParent; - - struct KeyHash { - size_t operator()(const VDStringA& s) const; - size_t operator()(const char *s) const; - }; - - struct KeyPred { - bool operator()(const VDStringA& s, const VDStringA& t) const; - bool operator()(const VDStringA& s, const VDStringSpanA& t) const; - bool operator()(const VDStringA& s, const char *t) const; - }; - - typedef vdhashmap KeyMap; - KeyMap mKeyMap; - - typedef vdfastvector KeyList; - KeyList mKeyList; - - typedef vdhashmap ValueMap; - ValueMap mValueMap; - - typedef vdfastvector ValueList; - ValueList mValueList; -}; - -size_t VDRegistryProviderMemory::Key::KeyHash::operator()(const VDStringA& s) const { - return VDHashString32I(s.data(), s.size()); -} - -size_t VDRegistryProviderMemory::Key::KeyHash::operator()(const char *s) const { - return VDHashString32I(s); -} - -bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const VDStringA& t) const { - return s.comparei(t) == 0; -} - -bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const VDStringSpanA& t) const { - return s.comparei(t) == 0; -} - -bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const char *t) const { - return s.comparei(t) == 0; -} - -VDRegistryProviderMemory::Key::Key() - : mRefCount(0) - , mbCondemned(false) - , mpParent(NULL) -{ -} - -VDRegistryProviderMemory::Key::~Key() { - VDASSERT(!mRefCount); -} - -void VDRegistryProviderMemory::Key::AddRef() { - ++mRefCount; -} - -void VDRegistryProviderMemory::Key::Release() { - if (!--mRefCount && mbCondemned) - mpParent->Remove(this); -} - -bool VDRegistryProviderMemory::Key::Add(const VDStringA& name, VDRegistryProviderMemory::Value *value) { - ValueMap::insert_return_type r(mValueMap.insert(name)); - if (!r.second) - return false; - - mValueList.push_back(&*r.first); - return true; -} - -void VDRegistryProviderMemory::Key::Remove(VDRegistryProviderMemory::Key *key) { - VDASSERT(key->mRefCount == 0); - - for(KeyList::iterator it(mKeyList.begin()), itEnd(mKeyList.end()); it != itEnd; ++it) { - const KeyMap::value_type *e = *it; - - if (&e->second == key) { - mKeyMap.erase(e->first); - mKeyList.erase(it); - break; - } - } -} - -bool VDRegistryProviderMemory::Key::RemoveKey(const char *name) { - if (!name) - name = ""; - - // look up the subkey - KeyMap::iterator it(mKeyMap.find_as(name)); - - // fail if not found - if (it != mKeyMap.end()) - return false; - - // can't delete key if it has subkeys - Key& key = it->second; - if (!key.mKeyList.empty()) - return false; - - // if the key is open, we have to condemn it and delete it later - if (key.mRefCount) { - key.mbCondemned = true; - return true; - } - - // delete the key - mKeyMap.erase(it); - - KeyList::iterator it2(std::find(mKeyList.begin(), mKeyList.end(), &*it)); - VDASSERT(it2 != mKeyList.end()); - - mKeyList.erase(it2); - return true; -} - -bool VDRegistryProviderMemory::Key::RemoveValue(const char *name) { - if (!name) - name = ""; - - ValueMap::iterator it(mValueMap.find_as(name)); - - if (it == mValueMap.end()) - return false; - - ValueList::iterator it2(std::find(mValueList.begin(), mValueList.end(), &*it)); - VDASSERT(it2 != mValueList.end()); - - mValueList.erase(it2); - mValueMap.erase(it); - return true; -} - -VDRegistryProviderMemory::Value *VDRegistryProviderMemory::Key::OpenValue(const char *name, bool create) { - if (!name) - name = ""; - - ValueMap::iterator it(mValueMap.find_as(name)); - - if (it != mValueMap.end()) - return &it->second; - - if (!create) - return NULL; - - ValueMap::insert_return_type r(mValueMap.insert(VDStringA(name))); - mValueList.push_back(&*r.first); - - return &r.first->second; -} - -VDRegistryProviderMemory::Key *VDRegistryProviderMemory::Key::OpenKey(const VDStringSpanA& name, bool create) { - KeyMap::iterator it(mKeyMap.find_as(name)); - - if (it != mKeyMap.end()) - return &it->second; - - if (!create) - return NULL; - - KeyMap::insert_return_type r(mKeyMap.insert(VDStringA(name))); - mKeyList.push_back(&*r.first); - - Key *key = &r.first->second; - - key->mpParent = this; - - return key; -} - -/////////////////////////////////////////////////////////////////////// - -VDRegistryProviderMemory::VDRegistryProviderMemory() { - vdautoptr machineKey(new Key); - vdautoptr userKey(new Key); - - mpMachineKey = machineKey.release(); - mpUserKey = userKey.release(); -} - -VDRegistryProviderMemory::~VDRegistryProviderMemory() { - delete mpMachineKey; - delete mpUserKey; -} - -void *VDRegistryProviderMemory::GetMachineKey() { - return mpMachineKey; -} - -void *VDRegistryProviderMemory::GetUserKey() { - return mpUserKey; -} - -void *VDRegistryProviderMemory::CreateKey(void *key0, const char *path, bool write) { - Key *key = (Key *)key0; - - vdsynchronized(mMutex) { - // check for root specifier - if (*path == '\\') { - do { - ++path; - } while(*path == '\\'); - - while(key->mpParent) - key = key->mpParent; - } - - // parse out a component at a time - for(;;) { - const char *split = strchr(path, '\\'); - if (!split) - split = path + strlen(path); - - if (path == split) - break; - - VDStringSpanA component(path, split); - - // lookup component - key = key->OpenKey(component, write); - if (!key) - return NULL; - - // skip path specifier - if (!*split) - break; - - path = split; - do { - ++path; - } while(*path == L'\\'); - } - - key->AddRef(); - } - - return key; -} - -void VDRegistryProviderMemory::CloseKey(void *key0) { - Key *key = (Key *)key0; - - vdsynchronized(mMutex) { - key->Release(); - } -} - -bool VDRegistryProviderMemory::SetBool(void *key0, const char *name, bool v) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetInt(v); - } - return true; -} - -bool VDRegistryProviderMemory::SetInt(void *key0, const char *name, int v) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetInt(v); - } - return true; -} - -bool VDRegistryProviderMemory::SetString(void *key0, const char *name, const char *str) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetString(VDTextAToW(str).c_str()); - } - return true; -} - -bool VDRegistryProviderMemory::SetString(void *key0, const char *name, const wchar_t *str) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetString(str); - } - return true; -} - -bool VDRegistryProviderMemory::SetBinary(void *key0, const char *name, const char *data, int len) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (!value) - return false; - - value->SetBinary(data, len); - } - return true; -} - -IVDRegistryProvider::Type VDRegistryProviderMemory::GetType(void *key0, const char *name) { - Type type = kTypeUnknown; - - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, true); - - if (value) { - switch(value->GetType()) { - case Value::kTypeInt: - type = kTypeInt; - break; - - case Value::kTypeString: - type = kTypeString; - break; - - case Value::kTypeBinary: - type = kTypeBinary; - break; - } - } - } - - return type; -} - -bool VDRegistryProviderMemory::GetBool(void *key0, const char *name, bool& val) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - sint32 v32; - if (!value || !value->GetInt(v32)) - return false; - - val = v32 != 0; - } - return true; -} - -bool VDRegistryProviderMemory::GetInt(void *key0, const char *name, int& val) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - sint32 v32; - if (!value || !value->GetInt(v32)) - return false; - - val = v32; - } - return true; -} - -bool VDRegistryProviderMemory::GetString(void *key0, const char *name, VDStringA& s) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - const wchar_t *raws; - if (!value || !value->GetString(raws)) - return false; - - s = VDTextWToA(raws); - } - return true; -} - -bool VDRegistryProviderMemory::GetString(void *key0, const char *name, VDStringW& s) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - const wchar_t *raws; - if (!value || !value->GetString(raws)) - return false; - - s = raws; - } - return true; -} - -int VDRegistryProviderMemory::GetBinaryLength(void *key0, const char *name) { - size_t len; - - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - const void *p; - if (!value || !value->GetBinary(p, len)) - return -1; - } - return len; -} - -bool VDRegistryProviderMemory::GetBinary(void *key0, const char *name, char *buf, int maxlen) { - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - Value *value = key->OpenValue(name, false); - - const void *p; - size_t len; - if (!value || !value->GetBinary(p, len) || (int)len > maxlen) - return false; - - memcpy(buf, p, len); - } - - return true; -} - -bool VDRegistryProviderMemory::RemoveValue(void *key0, const char *name) { - bool success; - - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - - success = key->RemoveValue(name); - } - - return true; -} - -bool VDRegistryProviderMemory::RemoveKey(void *key0, const char *name) { - bool success; - - vdsynchronized(mMutex) { - Key *key = (Key *)key0; - - // if the key is a root key, silently ignore the request - if (!key->mpParent) - return true; - - success = key->RemoveKey(name); - } - - return true; -} - -struct VDRegistryProviderMemory::Enumerator { - Enumerator(Key *key) : mKey(key), mIndex(0) {} - - Key *mKey; - size_t mIndex; - VDStringA mName; -}; - -void *VDRegistryProviderMemory::EnumKeysBegin(void *key) { - return new Enumerator((Key *)key); -} - -const char *VDRegistryProviderMemory::EnumKeysNext(void *enumerator) { - Enumerator *en = (Enumerator *)enumerator; - - vdsynchronized(mMutex) { - const char *s = en->mKey->GetKeyName(en->mIndex); - if (!s) - return NULL; - - ++en->mIndex; - en->mName = s; - } - - return en->mName.c_str(); -} - -void VDRegistryProviderMemory::EnumKeysClose(void *enumerator) { - Enumerator *en = (Enumerator *)enumerator; - - delete en; -} - -void *VDRegistryProviderMemory::EnumValuesBegin(void *key) { - return new Enumerator((Key *)key); -} - -const char *VDRegistryProviderMemory::EnumValuesNext(void *enumerator) { - Enumerator *en = (Enumerator *)enumerator; - - if (!en->mKey) - return NULL; - - vdsynchronized(mMutex) { - const char *s = en->mKey->GetValueName(en->mIndex); - if (!s) - return NULL; - - ++en->mIndex; - en->mName = s; - } - - return en->mName.c_str(); -} - -void VDRegistryProviderMemory::EnumValuesClose(void *enumerator) { - Enumerator *en = (Enumerator *)enumerator; - - delete en; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include + +class VDRegistryProviderMemory::Value : public vdhashtable_base_node { +public: + enum Type { + kTypeInt, + kTypeString, + kTypeBinary + }; + + Value(); + + void SetInt(sint32 v); + void SetString(const wchar_t *str); + void SetBinary(const void *p, size_t len); + + Type GetType() const { return mType; } + + bool GetInt(sint32& v) const; + bool GetString(const wchar_t *&s) const; + bool GetBinary(const void *&p, size_t& len) const; + +protected: + Type mType; + + // we're being lazy for now + sint32 mInt; + VDStringW mString; + vdfastvector mRawData; +}; + +VDRegistryProviderMemory::Value::Value() + : mType(kTypeInt) + , mInt(0) +{ +} + +void VDRegistryProviderMemory::Value::SetInt(sint32 v) { + if (mType != kTypeInt) { + mString.swap(VDStringW()); + mRawData.swap(vdfastvector()); + mType = kTypeInt; + } + + mInt = v; +} + +void VDRegistryProviderMemory::Value::SetString(const wchar_t *str) { + if (mType != kTypeString) { + mRawData.swap(vdfastvector()); + mType = kTypeString; + } + + mString = str; +} + +void VDRegistryProviderMemory::Value::SetBinary(const void *p, size_t len) { + if (mType != kTypeBinary) { + mString.swap(VDStringW()); + mType = kTypeBinary; + } + + mRawData.assign((char *)p, (char *)p + len); +} + +bool VDRegistryProviderMemory::Value::GetInt(sint32& v) const { + if (mType != kTypeInt) + return false; + + v = mInt; + return true; +} + +bool VDRegistryProviderMemory::Value::GetString(const wchar_t *&s) const { + if (mType != kTypeString) + return false; + + s = mString.c_str(); + return true; +} + +bool VDRegistryProviderMemory::Value::GetBinary(const void *&p, size_t& len) const { + if (mType != kTypeBinary) + return false; + + p = mRawData.data(); + len = mRawData.size(); + return true; +} + +class VDRegistryProviderMemory::Key { +public: + Key(); + ~Key(); + + void AddRef(); + void Release(); + + bool Add(const VDStringA& name, VDRegistryProviderMemory::Value *value); + void Remove(VDRegistryProviderMemory::Key *key); + bool RemoveKey(const char *name); + bool RemoveValue(const char *name); + + const char *GetKeyName(size_t index) const { + if (index >= mKeyList.size()) + return NULL; + + return mKeyList[index]->first.c_str(); + } + + const char *GetValueName(size_t index) const { + if (index >= mValueList.size()) + return NULL; + + return mValueList[index]->first.c_str(); + } + + Value *OpenValue(const char *name, bool create); + Key *OpenKey(const VDStringSpanA& name, bool create); + + int mRefCount; + bool mbCondemned; + + Key *mpParent; + + struct KeyHash { + size_t operator()(const VDStringA& s) const; + size_t operator()(const char *s) const; + }; + + struct KeyPred { + bool operator()(const VDStringA& s, const VDStringA& t) const; + bool operator()(const VDStringA& s, const VDStringSpanA& t) const; + bool operator()(const VDStringA& s, const char *t) const; + }; + + typedef vdhashmap KeyMap; + KeyMap mKeyMap; + + typedef vdfastvector KeyList; + KeyList mKeyList; + + typedef vdhashmap ValueMap; + ValueMap mValueMap; + + typedef vdfastvector ValueList; + ValueList mValueList; +}; + +size_t VDRegistryProviderMemory::Key::KeyHash::operator()(const VDStringA& s) const { + return VDHashString32I(s.data(), s.size()); +} + +size_t VDRegistryProviderMemory::Key::KeyHash::operator()(const char *s) const { + return VDHashString32I(s); +} + +bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const VDStringA& t) const { + return s.comparei(t) == 0; +} + +bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const VDStringSpanA& t) const { + return s.comparei(t) == 0; +} + +bool VDRegistryProviderMemory::Key::KeyPred::operator()(const VDStringA& s, const char *t) const { + return s.comparei(t) == 0; +} + +VDRegistryProviderMemory::Key::Key() + : mRefCount(0) + , mbCondemned(false) + , mpParent(NULL) +{ +} + +VDRegistryProviderMemory::Key::~Key() { + VDASSERT(!mRefCount); +} + +void VDRegistryProviderMemory::Key::AddRef() { + ++mRefCount; +} + +void VDRegistryProviderMemory::Key::Release() { + if (!--mRefCount && mbCondemned) + mpParent->Remove(this); +} + +bool VDRegistryProviderMemory::Key::Add(const VDStringA& name, VDRegistryProviderMemory::Value *value) { + ValueMap::insert_return_type r(mValueMap.insert(name)); + if (!r.second) + return false; + + mValueList.push_back(&*r.first); + return true; +} + +void VDRegistryProviderMemory::Key::Remove(VDRegistryProviderMemory::Key *key) { + VDASSERT(key->mRefCount == 0); + + for(KeyList::iterator it(mKeyList.begin()), itEnd(mKeyList.end()); it != itEnd; ++it) { + const KeyMap::value_type *e = *it; + + if (&e->second == key) { + mKeyMap.erase(e->first); + mKeyList.erase(it); + break; + } + } +} + +bool VDRegistryProviderMemory::Key::RemoveKey(const char *name) { + if (!name) + name = ""; + + // look up the subkey + KeyMap::iterator it(mKeyMap.find_as(name)); + + // fail if not found + if (it != mKeyMap.end()) + return false; + + // can't delete key if it has subkeys + Key& key = it->second; + if (!key.mKeyList.empty()) + return false; + + // if the key is open, we have to condemn it and delete it later + if (key.mRefCount) { + key.mbCondemned = true; + return true; + } + + // delete the key + mKeyMap.erase(it); + + KeyList::iterator it2(std::find(mKeyList.begin(), mKeyList.end(), &*it)); + VDASSERT(it2 != mKeyList.end()); + + mKeyList.erase(it2); + return true; +} + +bool VDRegistryProviderMemory::Key::RemoveValue(const char *name) { + if (!name) + name = ""; + + ValueMap::iterator it(mValueMap.find_as(name)); + + if (it == mValueMap.end()) + return false; + + ValueList::iterator it2(std::find(mValueList.begin(), mValueList.end(), &*it)); + VDASSERT(it2 != mValueList.end()); + + mValueList.erase(it2); + mValueMap.erase(it); + return true; +} + +VDRegistryProviderMemory::Value *VDRegistryProviderMemory::Key::OpenValue(const char *name, bool create) { + if (!name) + name = ""; + + ValueMap::iterator it(mValueMap.find_as(name)); + + if (it != mValueMap.end()) + return &it->second; + + if (!create) + return NULL; + + ValueMap::insert_return_type r(mValueMap.insert(VDStringA(name))); + mValueList.push_back(&*r.first); + + return &r.first->second; +} + +VDRegistryProviderMemory::Key *VDRegistryProviderMemory::Key::OpenKey(const VDStringSpanA& name, bool create) { + KeyMap::iterator it(mKeyMap.find_as(name)); + + if (it != mKeyMap.end()) + return &it->second; + + if (!create) + return NULL; + + KeyMap::insert_return_type r(mKeyMap.insert(VDStringA(name))); + mKeyList.push_back(&*r.first); + + Key *key = &r.first->second; + + key->mpParent = this; + + return key; +} + +/////////////////////////////////////////////////////////////////////// + +VDRegistryProviderMemory::VDRegistryProviderMemory() { + vdautoptr machineKey(new Key); + vdautoptr userKey(new Key); + + mpMachineKey = machineKey.release(); + mpUserKey = userKey.release(); +} + +VDRegistryProviderMemory::~VDRegistryProviderMemory() { + delete mpMachineKey; + delete mpUserKey; +} + +void *VDRegistryProviderMemory::GetMachineKey() { + return mpMachineKey; +} + +void *VDRegistryProviderMemory::GetUserKey() { + return mpUserKey; +} + +void *VDRegistryProviderMemory::CreateKey(void *key0, const char *path, bool write) { + Key *key = (Key *)key0; + + vdsynchronized(mMutex) { + // check for root specifier + if (*path == '\\') { + do { + ++path; + } while(*path == '\\'); + + while(key->mpParent) + key = key->mpParent; + } + + // parse out a component at a time + for(;;) { + const char *split = strchr(path, '\\'); + if (!split) + split = path + strlen(path); + + if (path == split) + break; + + VDStringSpanA component(path, split); + + // lookup component + key = key->OpenKey(component, write); + if (!key) + return NULL; + + // skip path specifier + if (!*split) + break; + + path = split; + do { + ++path; + } while(*path == L'\\'); + } + + key->AddRef(); + } + + return key; +} + +void VDRegistryProviderMemory::CloseKey(void *key0) { + Key *key = (Key *)key0; + + vdsynchronized(mMutex) { + key->Release(); + } +} + +bool VDRegistryProviderMemory::SetBool(void *key0, const char *name, bool v) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetInt(v); + } + return true; +} + +bool VDRegistryProviderMemory::SetInt(void *key0, const char *name, int v) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetInt(v); + } + return true; +} + +bool VDRegistryProviderMemory::SetString(void *key0, const char *name, const char *str) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetString(VDTextAToW(str).c_str()); + } + return true; +} + +bool VDRegistryProviderMemory::SetString(void *key0, const char *name, const wchar_t *str) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetString(str); + } + return true; +} + +bool VDRegistryProviderMemory::SetBinary(void *key0, const char *name, const char *data, int len) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (!value) + return false; + + value->SetBinary(data, len); + } + return true; +} + +IVDRegistryProvider::Type VDRegistryProviderMemory::GetType(void *key0, const char *name) { + Type type = kTypeUnknown; + + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, true); + + if (value) { + switch(value->GetType()) { + case Value::kTypeInt: + type = kTypeInt; + break; + + case Value::kTypeString: + type = kTypeString; + break; + + case Value::kTypeBinary: + type = kTypeBinary; + break; + } + } + } + + return type; +} + +bool VDRegistryProviderMemory::GetBool(void *key0, const char *name, bool& val) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + sint32 v32; + if (!value || !value->GetInt(v32)) + return false; + + val = v32 != 0; + } + return true; +} + +bool VDRegistryProviderMemory::GetInt(void *key0, const char *name, int& val) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + sint32 v32; + if (!value || !value->GetInt(v32)) + return false; + + val = v32; + } + return true; +} + +bool VDRegistryProviderMemory::GetString(void *key0, const char *name, VDStringA& s) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + const wchar_t *raws; + if (!value || !value->GetString(raws)) + return false; + + s = VDTextWToA(raws); + } + return true; +} + +bool VDRegistryProviderMemory::GetString(void *key0, const char *name, VDStringW& s) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + const wchar_t *raws; + if (!value || !value->GetString(raws)) + return false; + + s = raws; + } + return true; +} + +int VDRegistryProviderMemory::GetBinaryLength(void *key0, const char *name) { + size_t len; + + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + const void *p; + if (!value || !value->GetBinary(p, len)) + return -1; + } + return len; +} + +bool VDRegistryProviderMemory::GetBinary(void *key0, const char *name, char *buf, int maxlen) { + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + Value *value = key->OpenValue(name, false); + + const void *p; + size_t len; + if (!value || !value->GetBinary(p, len) || (int)len > maxlen) + return false; + + memcpy(buf, p, len); + } + + return true; +} + +bool VDRegistryProviderMemory::RemoveValue(void *key0, const char *name) { + bool success; + + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + + success = key->RemoveValue(name); + } + + return true; +} + +bool VDRegistryProviderMemory::RemoveKey(void *key0, const char *name) { + bool success; + + vdsynchronized(mMutex) { + Key *key = (Key *)key0; + + // if the key is a root key, silently ignore the request + if (!key->mpParent) + return true; + + success = key->RemoveKey(name); + } + + return true; +} + +struct VDRegistryProviderMemory::Enumerator { + Enumerator(Key *key) : mKey(key), mIndex(0) {} + + Key *mKey; + size_t mIndex; + VDStringA mName; +}; + +void *VDRegistryProviderMemory::EnumKeysBegin(void *key) { + return new Enumerator((Key *)key); +} + +const char *VDRegistryProviderMemory::EnumKeysNext(void *enumerator) { + Enumerator *en = (Enumerator *)enumerator; + + vdsynchronized(mMutex) { + const char *s = en->mKey->GetKeyName(en->mIndex); + if (!s) + return NULL; + + ++en->mIndex; + en->mName = s; + } + + return en->mName.c_str(); +} + +void VDRegistryProviderMemory::EnumKeysClose(void *enumerator) { + Enumerator *en = (Enumerator *)enumerator; + + delete en; +} + +void *VDRegistryProviderMemory::EnumValuesBegin(void *key) { + return new Enumerator((Key *)key); +} + +const char *VDRegistryProviderMemory::EnumValuesNext(void *enumerator) { + Enumerator *en = (Enumerator *)enumerator; + + if (!en->mKey) + return NULL; + + vdsynchronized(mMutex) { + const char *s = en->mKey->GetValueName(en->mIndex); + if (!s) + return NULL; + + ++en->mIndex; + en->mName = s; + } + + return en->mName.c_str(); +} + +void VDRegistryProviderMemory::EnumValuesClose(void *enumerator) { + Enumerator *en = (Enumerator *)enumerator; + + delete en; +} diff --git a/src/thirdparty/VirtualDub/h/vd2/system/strutil.h b/src/thirdparty/VirtualDub/h/vd2/system/strutil.h index 1beb3bb239b..89d1f9f3f57 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/strutil.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/strutil.h @@ -1,60 +1,60 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. -#ifndef f_VD2_SYSTEM_STRUTIL_H -#define f_VD2_SYSTEM_STRUTIL_H - -#include -#include - -char *strncpyz(char *strDest, const char *strSource, size_t count); -wchar_t *wcsncpyz(wchar_t *strDest, const wchar_t *strSource, size_t count); -const char *strskipspace(const char *s); - -inline char *strskipspace(char *s) { - return const_cast(strskipspace(s)); -} - -size_t vdstrlcpy(char *dst, const char *src, size_t sizeChars); -size_t vdwcslcpy(wchar_t *dst, const wchar_t *src, size_t sizeChars); - -size_t vdstrlcat(char *dst, const char *src, size_t sizeChars); - -inline int vdstricmp(const char *s, const char *t) { - return _stricmp(s, t); -} - -inline int vdstricmp(const char *s, const char *t, size_t maxlen) { - return _strnicmp(s, t, maxlen); -} - -inline int vdwcsicmp(const wchar_t *s, const wchar_t *t) { - return _wcsicmp(s, t); -} - -inline int vdwcsnicmp(const wchar_t *s, const wchar_t *t, size_t maxlen) { - return _wcsnicmp(s, t, maxlen); -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. +#ifndef f_VD2_SYSTEM_STRUTIL_H +#define f_VD2_SYSTEM_STRUTIL_H + +#include +#include + +char *strncpyz(char *strDest, const char *strSource, size_t count); +wchar_t *wcsncpyz(wchar_t *strDest, const wchar_t *strSource, size_t count); +const char *strskipspace(const char *s); + +inline char *strskipspace(char *s) { + return const_cast(strskipspace(s)); +} + +size_t vdstrlcpy(char *dst, const char *src, size_t sizeChars); +size_t vdwcslcpy(wchar_t *dst, const wchar_t *src, size_t sizeChars); + +size_t vdstrlcat(char *dst, const char *src, size_t sizeChars); + +inline int vdstricmp(const char *s, const char *t) { + return _stricmp(s, t); +} + +inline int vdstricmp(const char *s, const char *t, size_t maxlen) { + return _strnicmp(s, t, maxlen); +} + +inline int vdwcsicmp(const wchar_t *s, const wchar_t *t) { + return _wcsicmp(s, t); +} + +inline int vdwcsnicmp(const wchar_t *s, const wchar_t *t, size_t maxlen) { + return _wcsnicmp(s, t, maxlen); +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/text.h b/src/thirdparty/VirtualDub/h/vd2/system/text.h index b0e4b88e752..bc8ea93f386 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/text.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/text.h @@ -1,60 +1,60 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_TEXT_H -#define f_VD2_SYSTEM_TEXT_H - -#include -#include - -class VDStringA; -class VDStringW; - -// The max_dst value needs to include space for the NULL as well. The number -// of characters produced is returned, minus the null terminator. - -int VDTextWToA(char *dst, int max_dst, const wchar_t *src, int max_src = -1); -int VDTextAToW(wchar_t *dst, int max_dst, const char *src, int max_src = -1); - -VDStringA VDTextWToA(const wchar_t *src, int length = -1); -VDStringA VDTextWToA(const VDStringW& sw); -VDStringW VDTextAToW(const char *src, int length = -1); -VDStringW VDTextAToW(const VDStringA& sw); - -VDStringA VDTextWToU8(const VDStringW& s); -VDStringA VDTextWToU8(const wchar_t *s, int length); -VDStringW VDTextU8ToW(const VDStringA& s); -VDStringW VDTextU8ToW(const char *s, int length); - -// The terminating NULL character is not included in these. - -int VDTextWToALength(const wchar_t *s, int length=-1); -int VDTextAToWLength(const char *s, int length=-1); - -VDStringW VDaswprintf(const wchar_t *format, int args, const void *const *argv); -VDStringW VDvswprintf(const wchar_t *format, int args, va_list val); -VDStringW VDswprintf(const wchar_t *format, int args, ...); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_TEXT_H +#define f_VD2_SYSTEM_TEXT_H + +#include +#include + +class VDStringA; +class VDStringW; + +// The max_dst value needs to include space for the NULL as well. The number +// of characters produced is returned, minus the null terminator. + +int VDTextWToA(char *dst, int max_dst, const wchar_t *src, int max_src = -1); +int VDTextAToW(wchar_t *dst, int max_dst, const char *src, int max_src = -1); + +VDStringA VDTextWToA(const wchar_t *src, int length = -1); +VDStringA VDTextWToA(const VDStringW& sw); +VDStringW VDTextAToW(const char *src, int length = -1); +VDStringW VDTextAToW(const VDStringA& sw); + +VDStringA VDTextWToU8(const VDStringW& s); +VDStringA VDTextWToU8(const wchar_t *s, int length); +VDStringW VDTextU8ToW(const VDStringA& s); +VDStringW VDTextU8ToW(const char *s, int length); + +// The terminating NULL character is not included in these. + +int VDTextWToALength(const wchar_t *s, int length=-1); +int VDTextAToWLength(const char *s, int length=-1); + +VDStringW VDaswprintf(const wchar_t *format, int args, const void *const *argv); +VDStringW VDvswprintf(const wchar_t *format, int args, va_list val); +VDStringW VDswprintf(const wchar_t *format, int args, ...); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/thread.h b/src/thirdparty/VirtualDub/h/vd2/system/thread.h index 61a016f7230..2d7d7074bc3 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/thread.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/thread.h @@ -1,285 +1,285 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_THREAD_H -#define f_VD2_SYSTEM_THREAD_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include - -typedef void *VDThreadHandle; -typedef uint32 VDThreadID; -typedef uint32 VDThreadId; -typedef uint32 VDProcessId; - -#if defined(__MINGW32__) || defined(__MINGW64__) - struct _CRITICAL_SECTION; - typedef _CRITICAL_SECTION VDCriticalSectionW32; -#else - struct _RTL_CRITICAL_SECTION; - typedef _RTL_CRITICAL_SECTION VDCriticalSectionW32; -#endif - -extern "C" void __declspec(dllimport) __stdcall InitializeCriticalSection(VDCriticalSectionW32 *lpCriticalSection); -extern "C" void __declspec(dllimport) __stdcall LeaveCriticalSection(VDCriticalSectionW32 *lpCriticalSection); -extern "C" void __declspec(dllimport) __stdcall EnterCriticalSection(VDCriticalSectionW32 *lpCriticalSection); -extern "C" void __declspec(dllimport) __stdcall DeleteCriticalSection(VDCriticalSectionW32 *lpCriticalSection); -extern "C" unsigned long __declspec(dllimport) __stdcall WaitForSingleObject(void *hHandle, unsigned long dwMilliseconds); -extern "C" int __declspec(dllimport) __stdcall ReleaseSemaphore(void *hSemaphore, long lReleaseCount, long *lpPreviousCount); - -VDThreadID VDGetCurrentThreadID(); -VDProcessId VDGetCurrentProcessId(); -uint32 VDGetLogicalProcessorCount(); - -void VDSetThreadDebugName(VDThreadID tid, const char *name); -void VDThreadSleep(int milliseconds); - -/////////////////////////////////////////////////////////////////////////// -// -// VDThread -// -// VDThread is a quick way to portably create threads -- to use it, -// derive a subclass from it that implements the ThreadRun() function. -// -// Win32 notes: -// -// The thread startup code will attempt to notify the VC++ debugger of -// the debug name of the thread. Only the first 9 characters are used -// by Visual C 6.0; Visual Studio .NET will accept a few dozen. -// -// VDThread objects must not be WaitThread()ed or destructed from a -// DllMain() function, TLS callback for an executable, or static -// destructor unless the thread has been detached from the object. -// The reason is that Win32 serializes calls to DllMain() functions. -// If you attempt to do so, you will cause a deadlock when Win32 -// attempts to fire thread detach notifications. -// -/////////////////////////////////////////////////////////////////////////// - -class VDThread { -public: - enum { - kPriorityDefault = INT_MIN - }; - - VDThread(const char *pszDebugName = NULL); // NOTE: pszDebugName must have static duration - ~VDThread() throw(); - - // external functions - - bool ThreadStart(); // start thread - void ThreadDetach(); // detach thread (wait() won't be called) - void ThreadWait(); // wait for thread to finish - void ThreadSetPriority(int priority); - - bool isThreadActive(); - - bool isThreadAttached() const { // NOTE: Will return true if thread started, even if thread has since exited - return mhThread != 0; - } - - VDThreadHandle getThreadHandle() const { // get handle to thread (Win32: HANDLE) - return mhThread; - } - - VDThreadID getThreadID() const { // get ID of thread (Win32: DWORD) - return mThreadID; - } - - void *ThreadLocation() const; // retrieve current EIP of thread (use only for debug purposes -- may not return reliable information on syscall, etc.) - - // thread-local functions - - virtual void ThreadRun() = 0; // thread, come to life - void ThreadFinish(); // exit thread - -private: - static unsigned __stdcall StaticThreadStart(void *pThis); - - const char *mpszDebugName; - VDThreadHandle mhThread; - VDThreadID mThreadID; - int mThreadPriority; -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDCriticalSection { -private: - struct CritSec { // This is a clone of CRITICAL_SECTION. - void *DebugInfo; - sint32 LockCount; - sint32 RecursionCount; - void *OwningThread; - void *LockSemaphore; - uint32 SpinCount; - } csect; - - VDCriticalSection(const VDCriticalSection&); - const VDCriticalSection& operator=(const VDCriticalSection&); - static void StructCheck(); -public: - class AutoLock { - private: - VDCriticalSection& cs; - public: - AutoLock(VDCriticalSection& csect) : cs(csect) { cs.Lock(); } - ~AutoLock() { cs.Unlock(); } - - inline operator bool() const { return false; } - }; - - VDCriticalSection() { - InitializeCriticalSection((VDCriticalSectionW32 *)&csect); - } - - ~VDCriticalSection() { - DeleteCriticalSection((VDCriticalSectionW32 *)&csect); - } - - void operator++() { - EnterCriticalSection((VDCriticalSectionW32 *)&csect); - } - - void operator--() { - LeaveCriticalSection((VDCriticalSectionW32 *)&csect); - } - - void Lock() { - EnterCriticalSection((VDCriticalSectionW32 *)&csect); - } - - void Unlock() { - LeaveCriticalSection((VDCriticalSectionW32 *)&csect); - } -}; - -// 'vdsynchronized' keyword -// -// The vdsynchronized(lock) keyword emulates Java's 'synchronized' keyword, which -// protects the following statement or block from race conditions by obtaining a -// lock during its execution: -// -// vdsynchronized(list_lock) { -// mList.pop_back(); -// if (mList.empty()) -// return false; -// } -// -// The construct is exception safe and will release the lock even if a return, -// continue, break, or thrown exception exits the block. However, hardware -// exceptions (access violations) may not work due to synchronous model -// exception handling. -// -// There are two Visual C++ bugs we need to work around here (both are in VC6 and VC7). -// -// 1) Declaring an object with a non-trivial destructor in a switch() condition -// causes a C1001 INTERNAL COMPILER ERROR. -// -// 2) Using __LINE__ in a macro expanded in a function with Edit and Continue (/ZI) -// breaks the preprocessor (KB article Q199057). Shame, too, because without it -// all the autolocks look the same. - -#define vdsynchronized2(lock) if(VDCriticalSection::AutoLock vd__lock=(lock))VDNEVERHERE;else -#define vdsynchronized1(lock) vdsynchronized2(lock) -#define vdsynchronized(lock) vdsynchronized1(lock) - -/////////////////////////////////////////////////////////////////////////// - -class VDSignalBase { -protected: - void *hEvent; - -public: - ~VDSignalBase(); - - void signal(); - bool check(); - void wait(); - int wait(VDSignalBase *second); - int wait(VDSignalBase *second, VDSignalBase *third); - static int waitMultiple(const VDSignalBase **signals, int count); - - bool tryWait(uint32 timeoutMillisec); - - void *getHandle() { return hEvent; } - - void operator()() { signal(); } -}; - -class VDSignal : public VDSignalBase { - VDSignal(const VDSignal&); - VDSignal& operator=(const VDSignal&); -public: - VDSignal(); -}; - -class VDSignalPersistent : public VDSignalBase { - VDSignalPersistent(const VDSignalPersistent&); - VDSignalPersistent& operator=(const VDSignalPersistent&); -public: - VDSignalPersistent(); - - void unsignal(); -}; - -/////////////////////////////////////////////////////////////////////////// - -class VDSemaphore { -public: - VDSemaphore(int initial); - ~VDSemaphore(); - - void *GetHandle() const { - return mKernelSema; - } - - void Reset(int count); - - void Wait() { - WaitForSingleObject(mKernelSema, 0xFFFFFFFFU); - } - - bool Wait(int timeout) { - return 0 == WaitForSingleObject(mKernelSema, timeout); - } - - bool TryWait() { - return 0 == WaitForSingleObject(mKernelSema, 0); - } - - void Post() { - ReleaseSemaphore(mKernelSema, 1, NULL); - } - -private: - void *mKernelSema; -}; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_THREAD_H +#define f_VD2_SYSTEM_THREAD_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include + +typedef void *VDThreadHandle; +typedef uint32 VDThreadID; +typedef uint32 VDThreadId; +typedef uint32 VDProcessId; + +#if defined(__MINGW32__) || defined(__MINGW64__) + struct _CRITICAL_SECTION; + typedef _CRITICAL_SECTION VDCriticalSectionW32; +#else + struct _RTL_CRITICAL_SECTION; + typedef _RTL_CRITICAL_SECTION VDCriticalSectionW32; +#endif + +extern "C" void __declspec(dllimport) __stdcall InitializeCriticalSection(VDCriticalSectionW32 *lpCriticalSection); +extern "C" void __declspec(dllimport) __stdcall LeaveCriticalSection(VDCriticalSectionW32 *lpCriticalSection); +extern "C" void __declspec(dllimport) __stdcall EnterCriticalSection(VDCriticalSectionW32 *lpCriticalSection); +extern "C" void __declspec(dllimport) __stdcall DeleteCriticalSection(VDCriticalSectionW32 *lpCriticalSection); +extern "C" unsigned long __declspec(dllimport) __stdcall WaitForSingleObject(void *hHandle, unsigned long dwMilliseconds); +extern "C" int __declspec(dllimport) __stdcall ReleaseSemaphore(void *hSemaphore, long lReleaseCount, long *lpPreviousCount); + +VDThreadID VDGetCurrentThreadID(); +VDProcessId VDGetCurrentProcessId(); +uint32 VDGetLogicalProcessorCount(); + +void VDSetThreadDebugName(VDThreadID tid, const char *name); +void VDThreadSleep(int milliseconds); + +/////////////////////////////////////////////////////////////////////////// +// +// VDThread +// +// VDThread is a quick way to portably create threads -- to use it, +// derive a subclass from it that implements the ThreadRun() function. +// +// Win32 notes: +// +// The thread startup code will attempt to notify the VC++ debugger of +// the debug name of the thread. Only the first 9 characters are used +// by Visual C 6.0; Visual Studio .NET will accept a few dozen. +// +// VDThread objects must not be WaitThread()ed or destructed from a +// DllMain() function, TLS callback for an executable, or static +// destructor unless the thread has been detached from the object. +// The reason is that Win32 serializes calls to DllMain() functions. +// If you attempt to do so, you will cause a deadlock when Win32 +// attempts to fire thread detach notifications. +// +/////////////////////////////////////////////////////////////////////////// + +class VDThread { +public: + enum { + kPriorityDefault = INT_MIN + }; + + VDThread(const char *pszDebugName = NULL); // NOTE: pszDebugName must have static duration + ~VDThread() throw(); + + // external functions + + bool ThreadStart(); // start thread + void ThreadDetach(); // detach thread (wait() won't be called) + void ThreadWait(); // wait for thread to finish + void ThreadSetPriority(int priority); + + bool isThreadActive(); + + bool isThreadAttached() const { // NOTE: Will return true if thread started, even if thread has since exited + return mhThread != 0; + } + + VDThreadHandle getThreadHandle() const { // get handle to thread (Win32: HANDLE) + return mhThread; + } + + VDThreadID getThreadID() const { // get ID of thread (Win32: DWORD) + return mThreadID; + } + + void *ThreadLocation() const; // retrieve current EIP of thread (use only for debug purposes -- may not return reliable information on syscall, etc.) + + // thread-local functions + + virtual void ThreadRun() = 0; // thread, come to life + void ThreadFinish(); // exit thread + +private: + static unsigned __stdcall StaticThreadStart(void *pThis); + + const char *mpszDebugName; + VDThreadHandle mhThread; + VDThreadID mThreadID; + int mThreadPriority; +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDCriticalSection { +private: + struct CritSec { // This is a clone of CRITICAL_SECTION. + void *DebugInfo; + sint32 LockCount; + sint32 RecursionCount; + void *OwningThread; + void *LockSemaphore; + uint32 SpinCount; + } csect; + + VDCriticalSection(const VDCriticalSection&); + const VDCriticalSection& operator=(const VDCriticalSection&); + static void StructCheck(); +public: + class AutoLock { + private: + VDCriticalSection& cs; + public: + AutoLock(VDCriticalSection& csect) : cs(csect) { cs.Lock(); } + ~AutoLock() { cs.Unlock(); } + + inline operator bool() const { return false; } + }; + + VDCriticalSection() { + InitializeCriticalSection((VDCriticalSectionW32 *)&csect); + } + + ~VDCriticalSection() { + DeleteCriticalSection((VDCriticalSectionW32 *)&csect); + } + + void operator++() { + EnterCriticalSection((VDCriticalSectionW32 *)&csect); + } + + void operator--() { + LeaveCriticalSection((VDCriticalSectionW32 *)&csect); + } + + void Lock() { + EnterCriticalSection((VDCriticalSectionW32 *)&csect); + } + + void Unlock() { + LeaveCriticalSection((VDCriticalSectionW32 *)&csect); + } +}; + +// 'vdsynchronized' keyword +// +// The vdsynchronized(lock) keyword emulates Java's 'synchronized' keyword, which +// protects the following statement or block from race conditions by obtaining a +// lock during its execution: +// +// vdsynchronized(list_lock) { +// mList.pop_back(); +// if (mList.empty()) +// return false; +// } +// +// The construct is exception safe and will release the lock even if a return, +// continue, break, or thrown exception exits the block. However, hardware +// exceptions (access violations) may not work due to synchronous model +// exception handling. +// +// There are two Visual C++ bugs we need to work around here (both are in VC6 and VC7). +// +// 1) Declaring an object with a non-trivial destructor in a switch() condition +// causes a C1001 INTERNAL COMPILER ERROR. +// +// 2) Using __LINE__ in a macro expanded in a function with Edit and Continue (/ZI) +// breaks the preprocessor (KB article Q199057). Shame, too, because without it +// all the autolocks look the same. + +#define vdsynchronized2(lock) if(VDCriticalSection::AutoLock vd__lock=(lock))VDNEVERHERE;else +#define vdsynchronized1(lock) vdsynchronized2(lock) +#define vdsynchronized(lock) vdsynchronized1(lock) + +/////////////////////////////////////////////////////////////////////////// + +class VDSignalBase { +protected: + void *hEvent; + +public: + ~VDSignalBase(); + + void signal(); + bool check(); + void wait(); + int wait(VDSignalBase *second); + int wait(VDSignalBase *second, VDSignalBase *third); + static int waitMultiple(const VDSignalBase **signals, int count); + + bool tryWait(uint32 timeoutMillisec); + + void *getHandle() { return hEvent; } + + void operator()() { signal(); } +}; + +class VDSignal : public VDSignalBase { + VDSignal(const VDSignal&); + VDSignal& operator=(const VDSignal&); +public: + VDSignal(); +}; + +class VDSignalPersistent : public VDSignalBase { + VDSignalPersistent(const VDSignalPersistent&); + VDSignalPersistent& operator=(const VDSignalPersistent&); +public: + VDSignalPersistent(); + + void unsignal(); +}; + +/////////////////////////////////////////////////////////////////////////// + +class VDSemaphore { +public: + VDSemaphore(int initial); + ~VDSemaphore(); + + void *GetHandle() const { + return mKernelSema; + } + + void Reset(int count); + + void Wait() { + WaitForSingleObject(mKernelSema, 0xFFFFFFFFU); + } + + bool Wait(int timeout) { + return 0 == WaitForSingleObject(mKernelSema, timeout); + } + + bool TryWait() { + return 0 == WaitForSingleObject(mKernelSema, 0); + } + + void Post() { + ReleaseSemaphore(mKernelSema, 1, NULL); + } + +private: + void *mKernelSema; +}; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/thunk.h b/src/thirdparty/VirtualDub/h/vd2/system/thunk.h index 3e1b2e1b856..cf92407acd2 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/thunk.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/thunk.h @@ -1,76 +1,76 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_THUNK_H -#define f_VD2_SYSTEM_THUNK_H - -#ifdef _MSC_VER - #pragma once -#endif - -bool VDInitThunkAllocator(); -void VDShutdownThunkAllocator(); - -void *VDAllocateThunkMemory(size_t len); -void VDFreeThunkMemory(void *p, size_t len); -void VDSetThunkMemory(void *p, const void *src, size_t len); -void VDFlushThunkMemory(void *p, size_t len); - -class VDFunctionThunk; - -VDFunctionThunk *VDCreateFunctionThunkFromMethod(void *method, void *pThis, size_t argbytes, bool stdcall_thunk); -void VDDestroyFunctionThunk(VDFunctionThunk *pFnThunk); - -/////////////////////////////////////////////////////////////////////////////// - -template struct VDMetaSizeofArg { enum { value = (sizeof(T) + sizeof(void *) - 1) & ~(sizeof(void *) - 1) }; }; - -// This doesn't work for references. Sadly, these seem to get stripped during template matching. -template -char (&VDMetaGetMethodArgBytes(R (T::*method)()))[1]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1)))[1 + VDMetaSizeofArg::value]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3, A4)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; - -template -char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3, A4)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; - -/////////////////////////////////////////////////////////////////////////////// - -template -VDFunctionThunk *VDCreateFunctionThunkFromMethod(T *pThis, T_Method method, bool stdcall_thunk) { - return VDCreateFunctionThunkFromMethod(*(void **)&method, pThis, sizeof VDMetaGetMethodArgBytes(method) - 1, stdcall_thunk); -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_THUNK_H +#define f_VD2_SYSTEM_THUNK_H + +#ifdef _MSC_VER + #pragma once +#endif + +bool VDInitThunkAllocator(); +void VDShutdownThunkAllocator(); + +void *VDAllocateThunkMemory(size_t len); +void VDFreeThunkMemory(void *p, size_t len); +void VDSetThunkMemory(void *p, const void *src, size_t len); +void VDFlushThunkMemory(void *p, size_t len); + +class VDFunctionThunk; + +VDFunctionThunk *VDCreateFunctionThunkFromMethod(void *method, void *pThis, size_t argbytes, bool stdcall_thunk); +void VDDestroyFunctionThunk(VDFunctionThunk *pFnThunk); + +/////////////////////////////////////////////////////////////////////////////// + +template struct VDMetaSizeofArg { enum { value = (sizeof(T) + sizeof(void *) - 1) & ~(sizeof(void *) - 1) }; }; + +// This doesn't work for references. Sadly, these seem to get stripped during template matching. +template +char (&VDMetaGetMethodArgBytes(R (T::*method)()))[1]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1)))[1 + VDMetaSizeofArg::value]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3, A4)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; + +template +char (&VDMetaGetMethodArgBytes(R (T::*method)(A1, A2, A3, A4)))[1 + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value + VDMetaSizeofArg::value]; + +/////////////////////////////////////////////////////////////////////////////// + +template +VDFunctionThunk *VDCreateFunctionThunkFromMethod(T *pThis, T_Method method, bool stdcall_thunk) { + return VDCreateFunctionThunkFromMethod(*(void **)&method, pThis, sizeof VDMetaGetMethodArgBytes(method) - 1, stdcall_thunk); +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/tls.h b/src/thirdparty/VirtualDub/h/vd2/system/tls.h index 87b44643692..2cd2ecc70e1 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/tls.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/tls.h @@ -1,38 +1,38 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_SYSTEM_TLS_H -#define f_SYSTEM_TLS_H - -#include - -void VDInitThreadData(const char *pszThreadName); -void VDDeinitThreadData(); - -typedef void (*VDThreadInitHook)(bool init, const char *threadName); - -void VDSetThreadInitHook(VDThreadInitHook pHook); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_SYSTEM_TLS_H +#define f_SYSTEM_TLS_H + +#include + +void VDInitThreadData(const char *pszThreadName); +void VDDeinitThreadData(); + +typedef void (*VDThreadInitHook)(bool init, const char *threadName); + +void VDSetThreadInitHook(VDThreadInitHook pHook); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/unknown.h b/src/thirdparty/VirtualDub/h/vd2/system/unknown.h index 69b008864e6..1a3efb71b79 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/unknown.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/unknown.h @@ -1,77 +1,77 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_UNKNOWN_H -#define f_VD2_SYSTEM_UNKNOWN_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -/////////////////////////////////////////////////////////////////////////// -// IVDUnknown -/// Base interface for runtime type discovery. -class IVDUnknown { -public: - /// Attempt to cast to another type. Returns NULL if interface is unsupported. - virtual void *AsInterface(uint32 id) = 0; - - inline const void *AsInterface(uint32 id) const { - return const_cast(this)->AsInterface(id); - } -}; - -/////////////////////////////////////////////////////////////////////////// -// IVDUnknown -/// Base interface for runtime type discovery with reference counting. -class IVDRefUnknown : public IVDUnknown { -public: - virtual int AddRef() = 0; ///< Add strong reference to object. Returns new reference count (debug builds only). - virtual int Release() = 0; ///< Remove strong refence from object, and destroy it if the refcount drops to zero. Returns zero if object was destroyed. -}; - -template -inline uint32 vdpoly_id_from_ptr(T *p) { - return T::kTypeID; -} - -/////////////////////////////////////////////////////////////////////////// -// vdpoly_cast -/// Performs a runtime polymorphic cast on an IUnknown-based object. -/// -/// \param pUnk Pointer to cast. May be NULL. -/// -/// Attempts to cast a pointer to a different type using the -/// \c AsInterface() method. The destination type must support the -/// \c kTypeID convention for returning the type ID. -/// -template -T vdpoly_cast(IVDUnknown *pUnk) { - return pUnk ? (T)pUnk->AsInterface(vdpoly_id_from_ptr(T(NULL))) : NULL; -} - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_UNKNOWN_H +#define f_VD2_SYSTEM_UNKNOWN_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include + +/////////////////////////////////////////////////////////////////////////// +// IVDUnknown +/// Base interface for runtime type discovery. +class IVDUnknown { +public: + /// Attempt to cast to another type. Returns NULL if interface is unsupported. + virtual void *AsInterface(uint32 id) = 0; + + inline const void *AsInterface(uint32 id) const { + return const_cast(this)->AsInterface(id); + } +}; + +/////////////////////////////////////////////////////////////////////////// +// IVDUnknown +/// Base interface for runtime type discovery with reference counting. +class IVDRefUnknown : public IVDUnknown { +public: + virtual int AddRef() = 0; ///< Add strong reference to object. Returns new reference count (debug builds only). + virtual int Release() = 0; ///< Remove strong refence from object, and destroy it if the refcount drops to zero. Returns zero if object was destroyed. +}; + +template +inline uint32 vdpoly_id_from_ptr(T *p) { + return T::kTypeID; +} + +/////////////////////////////////////////////////////////////////////////// +// vdpoly_cast +/// Performs a runtime polymorphic cast on an IUnknown-based object. +/// +/// \param pUnk Pointer to cast. May be NULL. +/// +/// Attempts to cast a pointer to a different type using the +/// \c AsInterface() method. The destination type must support the +/// \c kTypeID convention for returning the type ID. +/// +template +T vdpoly_cast(IVDUnknown *pUnk) { + return pUnk ? (T)pUnk->AsInterface(vdpoly_id_from_ptr(T(NULL))) : NULL; +} + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdalloc.h b/src/thirdparty/VirtualDub/h/vd2/system/vdalloc.h index 3dab889a498..ad866ebfa6b 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdalloc.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdalloc.h @@ -1,190 +1,190 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDALLOC_H -#define f_VD2_SYSTEM_VDALLOC_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include - -// Why don't I use STL auto_ptr? Two reasons. First, auto_ptr has -// the overhead of an ownership flag, and second, auto_ptr can't -// be used with malloc() blocks. So think of these as auto_ptr -// objects, but not quite.... - -#pragma warning(push) -#pragma warning(disable: 4284) // operator-> must return pointer to UDT - -class vdautoblockptr { -protected: - void *ptr; - -public: - explicit vdautoblockptr(void *p = 0) : ptr(p) {} - ~vdautoblockptr() { free(ptr); } - - vdautoblockptr& operator=(void *src) { free(ptr); ptr = src; return *this; } - - operator void*() const { return ptr; } - - void from(vdautoblockptr& src) { free(ptr); ptr=src.ptr; src.ptr=0; } - void *get() const { return ptr; } - void *release() { void *v = ptr; ptr = NULL; return v; } -}; - -template class vdautoptr2 { -protected: - T *ptr; - -public: - explicit vdautoptr2(T *p = 0) : ptr(p) {} - ~vdautoptr2() { free((void *)ptr); } - - vdautoptr2& operator=(T *src) { free((void *)ptr); ptr = src; return *this; } - - operator T*() const { return ptr; } - T& operator*() const { return *ptr; } - T *operator->() const { return ptr; } - - vdautoptr2& from(vdautoptr2& src) { free((void *)ptr); ptr=src.ptr; src.ptr=0; } - T *get() const { return ptr; } - T *release() { T *v = ptr; ptr = NULL; return v; } -}; - -template class vdautoptr { -protected: - T *ptr; - -public: - explicit vdautoptr(T *p = 0) : ptr(p) {} - ~vdautoptr() { delete ptr; } - - vdautoptr& operator=(T *src) { delete ptr; ptr = src; return *this; } - - operator T*() const { return ptr; } - T& operator*() const { return *ptr; } - T *operator->() const { return ptr; } - - T** operator~() { - if (ptr) { - delete ptr; - ptr = NULL; - } - - return &ptr; - } - - void from(vdautoptr& src) { delete ptr; ptr=src.ptr; src.ptr=0; } - T *get() const { return ptr; } - T *release() { T *v = ptr; ptr = NULL; return v; } - - void reset() { - if (ptr) { - delete ptr; - ptr = NULL; - } - } - - void swap(vdautoptr& other) { - T *p = other.ptr; - other.ptr = ptr; - ptr = p; - } -}; - -template class vdautoarrayptr { -protected: - T *ptr; - -public: - explicit vdautoarrayptr(T *p = 0) : ptr(p) {} - ~vdautoarrayptr() { delete[] ptr; } - - vdautoarrayptr& operator=(T *src) { delete[] ptr; ptr = src; return *this; } - - T& operator[](int offset) const { return ptr[offset]; } - - void from(vdautoarrayptr& src) { delete[] ptr; ptr=src.ptr; src.ptr=0; } - T *get() const { return ptr; } - T *release() { T *v = ptr; ptr = NULL; return v; } -}; - -/////////////////////////////////////////////////////////////////////////// - -struct vdsafedelete_t {}; -extern vdsafedelete_t vdsafedelete; - -template -inline vdsafedelete_t& operator<<=(vdsafedelete_t& x, T *& p) { - if (p) { - delete p; - p = 0; - } - - return x; -} - -template -inline vdsafedelete_t& operator,(vdsafedelete_t& x, T *& p) { - if (p) { - delete p; - p = 0; - } - - return x; -} - -template -inline vdsafedelete_t& operator<<=(vdsafedelete_t& x, T *(&p)[N]) { - for(size_t i=0; i -inline vdsafedelete_t& operator,(vdsafedelete_t& x, T *(&p)[N]) { - for(size_t i=0; i + +// Why don't I use STL auto_ptr? Two reasons. First, auto_ptr has +// the overhead of an ownership flag, and second, auto_ptr can't +// be used with malloc() blocks. So think of these as auto_ptr +// objects, but not quite.... + +#pragma warning(push) +#pragma warning(disable: 4284) // operator-> must return pointer to UDT + +class vdautoblockptr { +protected: + void *ptr; + +public: + explicit vdautoblockptr(void *p = 0) : ptr(p) {} + ~vdautoblockptr() { free(ptr); } + + vdautoblockptr& operator=(void *src) { free(ptr); ptr = src; return *this; } + + operator void*() const { return ptr; } + + void from(vdautoblockptr& src) { free(ptr); ptr=src.ptr; src.ptr=0; } + void *get() const { return ptr; } + void *release() { void *v = ptr; ptr = NULL; return v; } +}; + +template class vdautoptr2 { +protected: + T *ptr; + +public: + explicit vdautoptr2(T *p = 0) : ptr(p) {} + ~vdautoptr2() { free((void *)ptr); } + + vdautoptr2& operator=(T *src) { free((void *)ptr); ptr = src; return *this; } + + operator T*() const { return ptr; } + T& operator*() const { return *ptr; } + T *operator->() const { return ptr; } + + vdautoptr2& from(vdautoptr2& src) { free((void *)ptr); ptr=src.ptr; src.ptr=0; } + T *get() const { return ptr; } + T *release() { T *v = ptr; ptr = NULL; return v; } +}; + +template class vdautoptr { +protected: + T *ptr; + +public: + explicit vdautoptr(T *p = 0) : ptr(p) {} + ~vdautoptr() { delete ptr; } + + vdautoptr& operator=(T *src) { delete ptr; ptr = src; return *this; } + + operator T*() const { return ptr; } + T& operator*() const { return *ptr; } + T *operator->() const { return ptr; } + + T** operator~() { + if (ptr) { + delete ptr; + ptr = NULL; + } + + return &ptr; + } + + void from(vdautoptr& src) { delete ptr; ptr=src.ptr; src.ptr=0; } + T *get() const { return ptr; } + T *release() { T *v = ptr; ptr = NULL; return v; } + + void reset() { + if (ptr) { + delete ptr; + ptr = NULL; + } + } + + void swap(vdautoptr& other) { + T *p = other.ptr; + other.ptr = ptr; + ptr = p; + } +}; + +template class vdautoarrayptr { +protected: + T *ptr; + +public: + explicit vdautoarrayptr(T *p = 0) : ptr(p) {} + ~vdautoarrayptr() { delete[] ptr; } + + vdautoarrayptr& operator=(T *src) { delete[] ptr; ptr = src; return *this; } + + T& operator[](int offset) const { return ptr[offset]; } + + void from(vdautoarrayptr& src) { delete[] ptr; ptr=src.ptr; src.ptr=0; } + T *get() const { return ptr; } + T *release() { T *v = ptr; ptr = NULL; return v; } +}; + +/////////////////////////////////////////////////////////////////////////// + +struct vdsafedelete_t {}; +extern vdsafedelete_t vdsafedelete; + +template +inline vdsafedelete_t& operator<<=(vdsafedelete_t& x, T *& p) { + if (p) { + delete p; + p = 0; + } + + return x; +} + +template +inline vdsafedelete_t& operator,(vdsafedelete_t& x, T *& p) { + if (p) { + delete p; + p = 0; + } + + return x; +} + +template +inline vdsafedelete_t& operator<<=(vdsafedelete_t& x, T *(&p)[N]) { + for(size_t i=0; i +inline vdsafedelete_t& operator,(vdsafedelete_t& x, T *(&p)[N]) { + for(size_t i=0; i -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// -// glue -// -/////////////////////////////////////////////////////////////////////////// - -template -struct vdreverse_iterator { -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1310 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) - typedef std::reverse_iterator type; -#else - typedef std::reverse_iterator type; -#endif -}; - -/////////////////////////////////////////////////////////////////////////// - -struct vdfalse_type { }; -struct vdtrue_type { }; - -struct vdfalse_result { typedef vdfalse_type result; }; -struct vdtrue_result { typedef vdtrue_type result; }; - -template void vdmove(T& dst, T& src); -template struct vdmove_capable : public vdfalse_result {}; - -template -T *vdmove_forward_impl(T *src1, T *src2, T *dst, vdfalse_type) { - T *p = src1; - while(p != src2) { - *dst = *p; - ++dst; - ++p; - } - - return dst; -} - -template -T *vdmove_backward_impl(T *src1, T *src2, T *dst, vdfalse_type) { - T *p = src2; - while(p != src1) { - --dst; - --p; - *dst = *p; - } - - return dst; -} - -template -T *vdmove_forward_impl(T *src1, T *src2, T *dst, vdtrue_type) { - T *p = src1; - while(p != src2) { - vdmove(*dst, *p); - ++dst; - ++p; - } - - return dst; -} - -template -T *vdmove_backward_impl(T *src1, T *src2, T *dst, vdtrue_type) { - T *p = src2; - while(p != src1) { - --dst; - --p; - vdmove(*dst, *p); - } - - return dst; -} - -template -T *vdmove_forward(T *src1, T *src2, T *dst) { - return vdmove_forward_impl(src1, src2, dst, vdmove_capable::result()); -} - -template -T *vdmove_backward(T *src1, T *src2, T *dst) { - return vdmove_backward_impl(src1, src2, dst, vdmove_capable::result()); -} - -#define VDMOVE_CAPABLE(type) \ - template<> struct vdmove_capable : public vdtrue_result {}; \ - template<> void vdmove(type& dst, type& src) - -/////////////////////////////////////////////////////////////////////////// - -template char (&VDCountOfHelper(const T(&)[N]))[N]; - -#define vdcountof(array) (sizeof(VDCountOfHelper(array))) - -/////////////////////////////////////////////////////////////////////////// - -class vdallocator_base { -protected: - void VDNORETURN throw_oom(size_t n, size_t elsize); -}; - -template -class vdallocator : public vdallocator_base { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template struct rebind { typedef vdallocator other; }; - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, void *p_close = 0) { - if (n > ((~(size_type)0) >> 1) / sizeof(T)) - throw_oom(n, sizeof(T)); - - pointer p = (pointer)malloc(n*sizeof(T)); - - if (!p) - throw_oom(n, sizeof(T)); - - return p; - } - - void deallocate(pointer p, size_type n) { - free(p); - } - - size_type max_size() const throw() { return ((~(size_type)0) >> 1) / sizeof(T); } - - void construct(pointer p, const T& val) { new((void *)p) T(val); } - void destroy(pointer p) { ((T*)p)->~T(); } - -#if defined(_MSC_VER) && _MSC_VER < 1300 - char * _Charalloc(size_type n) { return rebind::other::allocate(n); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////// - -template -class vddebug_alloc { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template struct rebind { typedef vddebug_alloc other; }; - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, void *p_close = 0) { - pointer p = (pointer)VDAlignedMalloc(n*sizeof(T) + 2*kDeadZone, 16); - - if (!p) - return p; - - memset((char *)p, 0xa9, kDeadZone); - memset((char *)p + kDeadZone + n*sizeof(T), 0xa9, kDeadZone); - - return (pointer)((char *)p + kDeadZone); - } - - void deallocate(pointer p, size_type n) { - char *p1 = (char *)p - kDeadZone; - char *p2 = (char *)p + n*sizeof(T); - - for(uint32 i=0; i~T(); } - -#if defined(_MSC_VER) && _MSC_VER < 1300 - char * _Charalloc(size_type n) { return rebind::other::allocate(n); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////// - -template -class vdaligned_alloc { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - vdaligned_alloc() {} - - template - vdaligned_alloc(const vdaligned_alloc&) {} - - template struct rebind { typedef vdaligned_alloc other; }; - - pointer address(reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } - - pointer allocate(size_type n, void *p = 0) { return (pointer)VDAlignedMalloc(n*sizeof(T), kAlignment); } - void deallocate(pointer p, size_type n) { VDAlignedFree(p); } - size_type max_size() const throw() { return INT_MAX; } - - void construct(pointer p, const T& val) { new((void *)p) T(val); } - void destroy(pointer p) { ((T*)p)->~T(); } - -#if defined(_MSC_VER) && _MSC_VER < 1300 - char * _Charalloc(size_type n) { return rebind::other::allocate(n); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////// -// -// vdblock -// -// vdblock is similar to vector, except: -// -// 1) May only be used with POD types. -// 2) No construction or destruction of elements is performed. -// 3) Capacity is always equal to size, and reallocation is performed -// whenever the size changes. -// 4) Contents are undefined after a reallocation. -// 5) No insertion or deletion operations are provided. -// -/////////////////////////////////////////////////////////////////////////// - -template > -class vdblock : protected A { -public: - typedef T value_type; - typedef typename A::pointer pointer; - typedef typename A::const_pointer const_pointer; - typedef typename A::reference reference; - typedef typename A::const_reference const_reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef pointer iterator; - typedef const_pointer const_iterator; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - vdblock(const A& alloc = A()) : A(alloc), mpBlock(NULL), mSize(0) {} - vdblock(size_type s, const A& alloc = A()) : A(alloc), mpBlock(A::allocate(s, 0)), mSize(s) {} - ~vdblock() { - if (mpBlock) - A::deallocate(mpBlock, mSize); - } - - reference operator[](size_type n) { return mpBlock[n]; } - const_reference operator[](size_type n) const { return mpBlock[n]; } - reference at(size_type n) { return n < mSize ? mpBlock[n] : throw std::length_error("n"); } - const_reference at(size_type n) const { return n < mSize ? mpBlock[n] : throw std::length_error("n"); } - reference front() { return *mpBlock; } - const_reference front() const { return *mpBlock; } - reference back() { return mpBlock[mSize-1]; } - const_reference back() const { return mpBlock[mSize-1]; } - - const_pointer data() const { return mpBlock; } - pointer data() { return mpBlock; } - - const_iterator begin() const { return mpBlock; } - iterator begin() { return mpBlock; } - const_iterator end() const { return mpBlock + mSize; } - iterator end() { return mpBlock + mSize; } - - const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } - reverse_iterator rbegin() { return reverse_iterator(end()); } - const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - - bool empty() const { return !mSize; } - size_type size() const { return mSize; } - size_type capacity() const { return mSize; } - - void clear() { - if (mpBlock) - A::deallocate(mpBlock, mSize); - mpBlock = NULL; - mSize = 0; - } - - void resize(size_type s) { - if (s != mSize) { - if (mpBlock) { - A::deallocate(mpBlock, mSize); - mpBlock = NULL; - mSize = 0; - } - if (s) - mpBlock = A::allocate(s, 0); - mSize = s; - } - } - - void resize(size_type s, const T& value) { - if (s != mSize) { - if (mpBlock) { - A::deallocate(mpBlock, mSize); - mpBlock = NULL; - mSize = 0; - } - if (s) { - mpBlock = A::allocate(s, 0); - std::fill(mpBlock, mpBlock+s, value); - } - mSize = s; - } - } - - void swap(vdblock& x) { - std::swap(mpBlock, x.mpBlock); - std::swap(mSize, x.mSize); - } - -protected: - typename A::pointer mpBlock; - typename A::size_type mSize; - - union PODType { - T x; - }; -}; - -/////////////////////////////////////////////////////////////////////////// -// -// vdstructex -// -// vdstructex describes an extensible format structure, such as -// BITMAPINFOHEADER or WAVEFORMATEX, without the pain-in-the-butt -// casting normally associated with one. -// -/////////////////////////////////////////////////////////////////////////// - -template -class vdstructex { -public: - typedef size_t size_type; - typedef T value_type; - - vdstructex() : mpMemory(NULL), mSize(0) {} - - explicit vdstructex(size_t len) : mpMemory(NULL), mSize(0) { - resize(len); - } - - vdstructex(const T *pStruct, size_t len) : mSize(len), mpMemory((T*)malloc(len)) { - memcpy(mpMemory, pStruct, len); - } - - vdstructex(const vdstructex& src) : mSize(src.mSize), mpMemory((T*)malloc(src.mSize)) { - memcpy(mpMemory, src.mpMemory, mSize); - } - - ~vdstructex() { - free(mpMemory); - } - - bool empty() const { return !mpMemory; } - size_type size() const { return mSize; } - T* data() const { return mpMemory; } - - T& operator *() const { return *(T *)mpMemory; } - T* operator->() const { return (T *)mpMemory; } - - bool operator==(const vdstructex& x) const { - return mSize == x.mSize && (!mSize || !memcmp(mpMemory, x.mpMemory, mSize)); - } - - bool operator!=(const vdstructex& x) const { - return mSize != x.mSize || (mSize && memcmp(mpMemory, x.mpMemory, mSize)); - } - - vdstructex& operator=(const vdstructex& src) { - assign(src.mpMemory, src.mSize); - return *this; - } - - void assign(const T *pStruct, size_type len) { - if (mSize != len) - resize(len); - - memcpy(mpMemory, pStruct, len); - } - - void clear() { - free(mpMemory); - mpMemory = NULL; - mSize = 0; - } - - void resize(size_type len) { - if (mSize != len) - mpMemory = (T *)realloc(mpMemory, mSize = len); - } - -protected: - size_type mSize; - T *mpMemory; -}; - -/////////////////////////////////////////////////////////////////////////// -// -// vdlist -// -// vdlist is similar to list, except: -// -// 1) The node structure must be embedded as a superclass of T. -// Thus, the client is in full control of allocation. -// 2) Node pointers may be converted back into iterators in O(1). -// -/////////////////////////////////////////////////////////////////////////// - -struct vdlist_node { - vdlist_node *mListNodeNext, *mListNodePrev; -}; - -template -class vdlist_iterator { -public: - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef T *pointer_type; - typedef T& reference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - vdlist_iterator() {} - vdlist_iterator(T *p) : mp(p) {} - vdlist_iterator(const vdlist_iterator& src) : mp(src.mp) {} - - T* operator *() const { - return static_cast(mp); - } - - bool operator==(const vdlist_iterator& x) const { - return mp == x.mp; - } - - bool operator!=(const vdlist_iterator& x) const { - return mp != x.mp; - } - - vdlist_iterator& operator++() { - mp = mp->mListNodeNext; - return *this; - } - - vdlist_iterator& operator--() { - mp = mp->mListNodePrev; - return *this; - } - - vdlist_iterator operator++(int) { - vdlist_iterator tmp(*this); - mp = mp->mListNodeNext; - return tmp; - } - - vdlist_iterator& operator--(int) { - vdlist_iterator tmp(*this); - mp = mp->mListNodePrev; - return tmp; - } - - vdlist_node *mp; -}; - -class vdlist_base { -public: - typedef vdlist_node node; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - bool empty() const { - return mAnchor.mListNodeNext == &mAnchor; - } - - size_type size() const { - node *p = { mAnchor.mListNodeNext }; - size_type s = 0; - - if (p != &mAnchor) - do { - ++s; - p = p->mListNodeNext; - } while(p != &mAnchor); - - return s; - } - - void clear() { - mAnchor.mListNodePrev = &mAnchor; - mAnchor.mListNodeNext = &mAnchor; - } - - void pop_front() { - mAnchor.mListNodeNext = mAnchor.mListNodeNext->mListNodeNext; - mAnchor.mListNodeNext->mListNodePrev = &mAnchor; - } - - void pop_back() { - mAnchor.mListNodePrev = mAnchor.mListNodePrev->mListNodePrev; - mAnchor.mListNodePrev->mListNodeNext = &mAnchor; - } - - static void unlink(vdlist_node& node) { - vdlist_node& n1 = *node.mListNodePrev; - vdlist_node& n2 = *node.mListNodeNext; - - n1.mListNodeNext = &n2; - n2.mListNodePrev = &n1; - } - -protected: - node mAnchor; -}; - -template -class vdlist : public vdlist_base { -public: - typedef T* value_type; - typedef T** pointer; - typedef const T** const_pointer; - typedef T*& reference; - typedef const T*& const_reference; - typedef vdlist_iterator iterator; - typedef vdlist_iterator const_iterator; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - vdlist() { - mAnchor.mListNodePrev = &mAnchor; - mAnchor.mListNodeNext = &mAnchor; - } - - iterator begin() { - iterator it; - it.mp = mAnchor.mListNodeNext; - return it; - } - - const_iterator begin() const { - const_iterator it; - it.mp = mAnchor.mListNodeNext; - return it; - } - - iterator end() { - iterator it; - it.mp = &mAnchor; - return it; - } - - const_iterator end() const { - const_iterator it; - it.mp = &mAnchor; - return it; - } - - reverse_iterator rbegin() { - return reverse_iterator(begin()); - } - - const_reverse_iterator rbegin() const { - return const_reverse_iterator(begin()); - } - - reverse_iterator rend() { - return reverse_iterator(end); - } - - const_reverse_iterator rend() const { - return const_reverse_iterator(end()); - } - - const value_type front() const { - return static_cast(mAnchor.mListNodeNext); - } - - const value_type back() const { - return static_cast(mAnchor.mListNodePrev); - } - - iterator find(T *p) { - iterator it; - it.mp = mAnchor.mListNodeNext; - - if (it.mp != &mAnchor) - do { - if (it.mp == static_cast(p)) - break; - - it.mp = it.mp->mListNodeNext; - } while(it.mp != &mAnchor); - - return it; - } - - const_iterator find(T *p) const { - const_iterator it; - it.mp = mAnchor.mListNodeNext; - - if (it.mp != &mAnchor) - do { - if (it.mp == static_cast(p)) - break; - - it.mp = it.mp->mListNodeNext; - } while(it.mp != &mAnchor); - - return it; - } - - iterator fast_find(T *p) { - iterator it(p); - return it; - } - - const_iterator fast_find(T *p) const { - iterator it(p); - } - - void push_front(T *p) { - node& n = *p; - n.mListNodePrev = &mAnchor; - n.mListNodeNext = mAnchor.mListNodeNext; - n.mListNodeNext->mListNodePrev = &n; - mAnchor.mListNodeNext = &n; - } - - void push_back(T *p) { - node& n = *p; - n.mListNodeNext = &mAnchor; - n.mListNodePrev = mAnchor.mListNodePrev; - n.mListNodePrev->mListNodeNext = &n; - mAnchor.mListNodePrev = &n; - } - - iterator erase(T *p) { - return erase(fast_find(p)); - } - - iterator erase(iterator it) { - node& n = *it.mp; - - n.mListNodePrev->mListNodeNext = n.mListNodeNext; - n.mListNodeNext->mListNodePrev = n.mListNodePrev; - - it.mp = n.mListNodeNext; - return it; - } - - iterator erase(iterator i1, iterator i2) { - node& np = *i1.mp->mListNodePrev; - node& nn = *i2.mp; - - np.mListNodeNext = &nn; - nn.mListNodePrev = &np; - - return i2; - } - - void insert(iterator dst, T *src) { - node& ns = *src; - node& nd = *dst.mp; - - ns.mListNodeNext = &nd; - ns.mListNodePrev = nd.mListNodePrev; - nd.mListNodePrev->mListNodeNext = &ns; - nd.mListNodePrev = &ns; - } - - void insert(iterator dst, iterator i1, iterator i2) { - if (i1 != i2) { - node& np = *dst.mp->mListNodePrev; - node& nn = *dst.mp; - node& n1 = *i1.mp; - node& n2 = *i2.mp->mListNodePrev; - - np.mListNodeNext = &n1; - n1.mListNodePrev = &np; - n2.mListNodeNext = &nn; - nn.mListNodePrev = &n2; - } - } - - void splice(iterator dst, vdlist& srclist) { - insert(dst, srclist.begin(), srclist.end()); - srclist.clear(); - } - - void splice(iterator dst, vdlist& srclist, iterator src) { - T *v = *src; - srclist.erase(src); - insert(dst, v); - } - - void splice(iterator dst, vdlist& srclist, iterator i1, iterator i2) { - if (dst.mp != i1.mp && dst.mp != i2.mp) { - srclist.erase(i1, i2); - insert(dst, i1, i2); - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -#if defined(_DEBUG) && defined(_MSC_VER) - #define VD_ACCELERATE_TEMPLATES -#endif - -#ifndef VDTINLINE - #ifdef VD_ACCELERATE_TEMPLATES - #ifndef VDTEXTERN - #define VDTEXTERN extern - #endif - - #define VDTINLINE - #else - #define VDTINLINE inline - #endif -#endif - -/////////////////////////////////////////////////////////////////////////////// - -template -class vdspan { -public: - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef pointer iterator; - typedef const_pointer const_iterator; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - VDTINLINE vdspan(); - - template - VDTINLINE vdspan(T (&arr)[N]); - - VDTINLINE vdspan(T *p1, T *p2); - VDTINLINE vdspan(T *p1, size_type len); - -public: - VDTINLINE bool empty() const; - VDTINLINE size_type size() const; - - VDTINLINE pointer data(); - VDTINLINE const_pointer data() const; - - VDTINLINE iterator begin(); - VDTINLINE const_iterator begin() const; - VDTINLINE iterator end(); - VDTINLINE const_iterator end() const; - - VDTINLINE reverse_iterator rbegin(); - VDTINLINE const_reverse_iterator rbegin() const; - VDTINLINE reverse_iterator rend(); - VDTINLINE const_reverse_iterator rend() const; - - VDTINLINE reference front(); - VDTINLINE const_reference front() const; - VDTINLINE reference back(); - VDTINLINE const_reference back() const; - - VDTINLINE reference operator[](size_type n); - VDTINLINE const_reference operator[](size_type n) const; - -protected: - T *mpBegin; - T *mpEnd; -}; - -#ifdef VD_ACCELERATE_TEMPLATES - #pragma warning(push) - #pragma warning(disable: 4231) // warning C4231: nonstandard extension used : 'extern' before template explicit instantiation - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - VDTEXTERN template vdspan; - #pragma warning(pop) -#endif - -template VDTINLINE vdspan::vdspan() : mpBegin(NULL), mpEnd(NULL) {} -template template VDTINLINE vdspan::vdspan(T (&arr)[N]) : mpBegin(&arr[0]), mpEnd(&arr[N]) {} -template VDTINLINE vdspan::vdspan(T *p1, T *p2) : mpBegin(p1), mpEnd(p2) {} -template VDTINLINE vdspan::vdspan(T *p, size_type len) : mpBegin(p), mpEnd(p+len) {} -template VDTINLINE bool vdspan::empty() const { return mpBegin == mpEnd; } -template VDTINLINE typename vdspan::size_type vdspan::size() const { return size_type(mpEnd - mpBegin); } -template VDTINLINE typename vdspan::pointer vdspan::data() { return mpBegin; } -template VDTINLINE typename vdspan::const_pointer vdspan::data() const { return mpBegin; } -template VDTINLINE typename vdspan::iterator vdspan::begin() { return mpBegin; } -template VDTINLINE typename vdspan::const_iterator vdspan::begin() const { return mpBegin; } -template VDTINLINE typename vdspan::iterator vdspan::end() { return mpEnd; } -template VDTINLINE typename vdspan::const_iterator vdspan::end() const { return mpEnd; } -template VDTINLINE typename vdspan::reverse_iterator vdspan::rbegin() { return reverse_iterator(mpEnd); } -template VDTINLINE typename vdspan::const_reverse_iterator vdspan::rbegin() const { return const_reverse_iterator(mpEnd); } -template VDTINLINE typename vdspan::reverse_iterator vdspan::rend() { return reverse_iterator(mpBegin); } -template VDTINLINE typename vdspan::const_reverse_iterator vdspan::rend() const { return const_reverse_iterator(mpBegin); } -template VDTINLINE typename vdspan::reference vdspan::front() { return *mpBegin; } -template VDTINLINE typename vdspan::const_reference vdspan::front() const { return *mpBegin; } -template VDTINLINE typename vdspan::reference vdspan::back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } -template VDTINLINE typename vdspan::const_reference vdspan::back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } -template VDTINLINE typename vdspan::reference vdspan::operator[](size_type n) { VDASSERT(n < size_type(mpEnd - mpBegin)); return mpBegin[n]; } -template VDTINLINE typename vdspan::const_reference vdspan::operator[](size_type n) const { VDASSERT(n < size_type(mpEnd - mpBegin)); return mpBegin[n]; } - -/////////////////////////////////////////////////////////////////////////////// - -template -bool operator==(const vdspan& x, const vdspan& y) { - uint32 len = x.size(); - if (len != y.size()) - return false; - - const T *px = x.data(); - const T *py = y.data(); - - for(uint32 i=0; i -inline bool operator!=(const vdspan& x, const vdspan& y) { return !(x == y); } - -/////////////////////////////////////////////////////////////////////////////// - -template > -class vdfastvector_base : public vdspan { -protected: - using vdspan::mpBegin; - using vdspan::mpEnd; - -public: - typedef typename vdspan::value_type value_type; - typedef typename vdspan::pointer pointer; - typedef typename vdspan::const_pointer const_pointer; - typedef typename vdspan::reference reference; - typedef typename vdspan::const_reference const_reference; - typedef typename vdspan::size_type size_type; - typedef typename vdspan::difference_type difference_type; - typedef typename vdspan::iterator iterator; - typedef typename vdspan::const_iterator const_iterator; - typedef typename vdspan::reverse_iterator reverse_iterator; - typedef typename vdspan::const_reverse_iterator const_reverse_iterator; - - ~vdfastvector_base() { - if (static_cast(m).is_deallocatable_storage(mpBegin)) - m.deallocate(mpBegin, m.eos - mpBegin); - } - - size_type capacity() const { return size_type(m.eos - mpBegin); } - -public: - T *alloc(size_type n) { - size_type offset = (size_type)(mpEnd - mpBegin); - resize(offset + n); - return mpBegin + offset; - } - - void assign(const T *p1, const T *p2) { - resize(p2 - p1); - memcpy(mpBegin, p1, (char *)p2 - (char *)p1); - } - - void clear() { - mpEnd = mpBegin; - } - - iterator erase(iterator it) { - VDASSERT(it - mpBegin < mpEnd - mpBegin); - - memmove(it, it+1, (char *)mpEnd - (char *)(it+1)); - - --mpEnd; - - return it; - } - - iterator erase(iterator it1, iterator it2) { - VDASSERT(it1 - mpBegin <= mpEnd - mpBegin); - VDASSERT(it2 - mpBegin <= mpEnd - mpBegin); - VDASSERT(it1 <= it2); - - memmove(it1, it2, (char *)mpEnd - (char *)it2); - - mpEnd -= (it2 - it1); - - return it1; - } - - iterator insert(iterator it, const T& value) { - const T temp(value); // copy in case value is inside container. - - if (mpEnd == m.eos) { - difference_type delta = it - mpBegin; - _reserve_always_add_one(); - it = mpBegin + delta; - } - - memmove(it+1, it, sizeof(T) * (mpEnd - it)); - *it = temp; - ++mpEnd; - VDASSERT(mpEnd <= m.eos); - - return it; - } - - iterator insert(iterator it, size_type n, const T& value) { - const T temp(value); // copy in case value is inside container. - - ptrdiff_t bytesToInsert = n * sizeof(T); - - if ((char *)m.eos - (char *)mpEnd < bytesToInsert) { - difference_type delta = it - mpBegin; - _reserve_always_add(bytesToInsert); - it = mpBegin + delta; - } - - memmove((char *)it + bytesToInsert, it, (char *)mpEnd - (char *)it); - for(size_t i=0; i size_type((char *)m.eos - (char *)mpBegin)) - _reserve_always_amortized(n); - - mpEnd = mpBegin + n; - } - - void resize(size_type n, const T& value) { - const T temp(value); - - if (n*sizeof(T) > size_type((char *)m.eos - (char *)mpBegin)) { - _reserve_always_amortized(n); - } - - const iterator newEnd(mpBegin + n); - if (newEnd > mpEnd) - std::fill(mpEnd, newEnd, temp); - mpEnd = newEnd; - } - - void reserve(size_type n) { - if (n*sizeof(T) > size_type((char *)m.eos - (char *)mpBegin)) - _reserve_always(n); - } - -protected: -#ifdef _MSC_VER - __declspec(noinline) -#endif - void _reserve_always_add_one() { - _reserve_always((m.eos - mpBegin) * 2 + 1); - } - -#ifdef _MSC_VER - __declspec(noinline) -#endif - void _reserve_always_add(size_type n) { - _reserve_always((m.eos - mpBegin) * 2 + n); - } - -#ifdef _MSC_VER - __declspec(noinline) -#endif - void _reserve_always(size_type n) { - size_type oldSize = mpEnd - mpBegin; - T *oldStorage = mpBegin; - T *newStorage = m.allocate(n, NULL); - - memcpy(newStorage, mpBegin, (char *)mpEnd - (char *)mpBegin); - if (static_cast(m).is_deallocatable_storage(oldStorage)) - m.deallocate(oldStorage, m.eos - mpBegin); - mpBegin = newStorage; - mpEnd = newStorage + oldSize; - m.eos = newStorage + n; - } - -#ifdef _MSC_VER - __declspec(noinline) -#endif - void _reserve_always_amortized(size_type n) { - size_type nextCapacity = (size_type)((m.eos - mpBegin)*2); - - if (nextCapacity < n) - nextCapacity = n; - - _reserve_always(nextCapacity); - } - - struct : A, S { - T *eos; - } m; - - union TrivialObjectConstraint { - T m; - }; -}; - -/////////////////////////////////////////////////////////////////////////////// - -struct vdfastvector_storage { - bool is_deallocatable_storage(void *p) const { - return p != 0; - } -}; - -template > -class vdfastvector : public vdfastvector_base { -protected: - using vdfastvector_base::m; - using vdfastvector_base::mpBegin; - using vdfastvector_base::mpEnd; - -public: - typedef typename vdfastvector_base::value_type value_type; - typedef typename vdfastvector_base::pointer pointer; - typedef typename vdfastvector_base::const_pointer const_pointer; - typedef typename vdfastvector_base::reference reference; - typedef typename vdfastvector_base::const_reference const_reference; - typedef typename vdfastvector_base::size_type size_type; - typedef typename vdfastvector_base::difference_type difference_type; - typedef typename vdfastvector_base::iterator iterator; - typedef typename vdfastvector_base::const_iterator const_iterator; - typedef typename vdfastvector_base::reverse_iterator reverse_iterator; - typedef typename vdfastvector_base::const_reverse_iterator const_reverse_iterator; - - vdfastvector() { - m.eos = NULL; - } - - vdfastvector(size_type len) { - mpBegin = m.allocate(len, NULL); - mpEnd = mpBegin + len; - m.eos = mpEnd; - } - - vdfastvector(size_type len, const T& fill) { - mpBegin = m.allocate(len, NULL); - mpEnd = mpBegin + len; - m.eos = mpEnd; - - std::fill(mpBegin, mpEnd, fill); - } - - vdfastvector(const vdfastvector& x) { - size_type n = x.mpEnd - x.mpBegin; - mpBegin = m.allocate(n, NULL); - mpEnd = mpBegin + n; - m.eos = mpEnd; - memcpy(mpBegin, x.mpBegin, sizeof(T) * n); - } - - vdfastvector(const value_type *p, const value_type *q) { - m.eos = NULL; - - assign(p, q); - } - - vdfastvector& operator=(const vdfastvector& x) { - if (this != &x) - vdfastvector::assign(x.mpBegin, x.mpEnd); - - return *this; - } - - void swap(vdfastvector& x) { - std::swap(mpBegin, x.mpBegin); - std::swap(mpEnd, x.mpEnd); - std::swap(m.eos, x.m.eos); - } - - void swap(vdfastvector&& x) { - std::swap(mpBegin, x.mpBegin); - std::swap(mpEnd, x.mpEnd); - std::swap(m.eos, x.m.eos); - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -template -struct vdfastfixedvector_storage { - T mArray[N]; - - bool is_deallocatable_storage(void *p) const { - return p != mArray; - } -}; - -template > -class vdfastfixedvector : public vdfastvector_base, A> { -protected: - using vdfastvector_base, A>::mpBegin; - using vdfastvector_base, A>::mpEnd; - using vdfastvector_base, A>::m; - -public: - typedef typename vdfastvector_base, A>::value_type value_type; - typedef typename vdfastvector_base, A>::pointer pointer; - typedef typename vdfastvector_base, A>::const_pointer const_pointer; - typedef typename vdfastvector_base, A>::reference reference; - typedef typename vdfastvector_base, A>::const_reference const_reference; - typedef typename vdfastvector_base, A>::size_type size_type; - typedef typename vdfastvector_base, A>::difference_type difference_type; - typedef typename vdfastvector_base, A>::iterator iterator; - typedef typename vdfastvector_base, A>::const_iterator const_iterator; - typedef typename vdfastvector_base, A>::reverse_iterator reverse_iterator; - typedef typename vdfastvector_base, A>::const_reverse_iterator const_reverse_iterator; - - vdfastfixedvector() { - mpBegin = m.mArray; - mpEnd = m.mArray; - m.eos = m.mArray + N; - } - - vdfastfixedvector(size_type len) { - if (len <= N) { - mpBegin = m.mArray; - mpEnd = m.mArray + len; - m.eos = m.mArray + N; - } else { - mpBegin = m.allocate(len, NULL); - mpEnd = mpBegin + len; - m.eos = mpEnd; - } - } - - vdfastfixedvector(size_type len, const T& fill) { - mpBegin = m.allocate(len, NULL); - mpEnd = mpBegin + len; - m.eos = mpEnd; - - std::fill(mpBegin, mpEnd, fill); - } - - vdfastfixedvector(const vdfastfixedvector& x) { - size_type n = x.mpEnd - x.mpBegin; - - if (n <= N) { - mpBegin = m.mArray; - mpEnd = m.mArray + n; - m.eos = m.mArray + N; - } else { - mpBegin = m.allocate(n, NULL); - mpEnd = mpBegin + n; - m.eos = mpEnd; - } - - memcpy(mpBegin, x.mpBegin, sizeof(T) * n); - } - - vdfastfixedvector(const value_type *p, const value_type *q) { - mpBegin = m.mArray; - mpEnd = m.mArray; - m.eos = m.mArray + N; - - assign(p, q); - } - - vdfastfixedvector& operator=(const vdfastfixedvector& x) { - if (this != &x) - assign(x.mpBegin, x.mpEnd); - - return *this; - } - - void swap(vdfastfixedvector& x) { - size_t this_bytes = (char *)mpEnd - (char *)mpBegin; - size_t other_bytes = (char *)x.mpEnd - (char *)x.mpBegin; - - T *p; - - if (mpBegin == m.mArray) { - if (x.mpBegin == x.m.mArray) { - if (this_bytes < other_bytes) { - VDSwapMemory(m.mArray, x.m.mArray, this_bytes); - memcpy((char *)m.mArray + this_bytes, (char *)x.m.mArray + this_bytes, other_bytes - this_bytes); - } else { - VDSwapMemory(m.mArray, x.m.mArray, other_bytes); - memcpy((char *)m.mArray + other_bytes, (char *)x.m.mArray + other_bytes, this_bytes - other_bytes); - } - - mpEnd = (T *)((char *)mpBegin + other_bytes); - x.mpEnd = (T *)((char *)x.mpBegin + this_bytes); - } else { - memcpy(x.m.mArray, mpBegin, this_bytes); - - mpBegin = x.mpBegin; - mpEnd = x.mpEnd; - m.eos = x.m.eos; - - x.mpBegin = x.m.mArray; - x.mpEnd = (T *)((char *)x.m.mArray + this_bytes); - x.m.eos = x.m.mArray + N; - } - } else { - if (x.mpBegin == x.m.mArray) { - memcpy(x.m.mArray, mpBegin, other_bytes); - - x.mpBegin = mpBegin; - x.mpEnd = mpEnd; - x.m.eos = m.eos; - - mpBegin = m.mArray; - mpEnd = (T *)((char *)m.mArray + other_bytes); - m.eos = m.mArray + N; - } else { - p = mpBegin; mpBegin = x.mpBegin; x.mpBegin = p; - p = mpEnd; mpEnd = x.mpEnd; x.mpEnd = p; - p = m.eos; m.eos = x.m.eos; x.m.eos = p; - } - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -template -struct vdfastdeque_block { - enum { - kBlockSize = 32, - kBlockSizeBits = 5 - }; - - T data[kBlockSize]; -}; - -template -class vdfastdeque_iterator { -public: - typedef T value_type; - typedef T* pointer; - typedef T& reference; - typedef ptrdiff_t difference_type; - typedef std::bidirectional_iterator_tag iterator_category; - - vdfastdeque_iterator(const vdfastdeque_iterator&); - vdfastdeque_iterator(vdfastdeque_block **pMapEntry, uint32 index); - - T& operator *() const; - T& operator ->() const; - vdfastdeque_iterator& operator++(); - vdfastdeque_iterator operator++(int); - vdfastdeque_iterator& operator--(); - vdfastdeque_iterator operator--(int); - -public: - vdfastdeque_block **mpMap; - vdfastdeque_block *mpBlock; - uint32 mIndex; -}; - -template -vdfastdeque_iterator::vdfastdeque_iterator(const vdfastdeque_iterator& x) - : mpMap(x.mpMap) - , mpBlock(x.mpBlock) - , mIndex(x.mIndex) -{ -} - -template -vdfastdeque_iterator::vdfastdeque_iterator(vdfastdeque_block **pMapEntry, uint32 index) - : mpMap(pMapEntry) - , mpBlock(mpMap ? *mpMap : NULL) - , mIndex(index) -{ -} - -template -T& vdfastdeque_iterator::operator *() const { - return mpBlock->data[mIndex]; -} - -template -T& vdfastdeque_iterator::operator ->() const { - return mpBlock->data[mIndex]; -} - -template -vdfastdeque_iterator& vdfastdeque_iterator::operator++() { - if (++mIndex >= vdfastdeque_block::kBlockSize) { - mIndex = 0; - mpBlock = *++mpMap; - } - return *this; -} - -template -vdfastdeque_iterator vdfastdeque_iterator::operator++(int) { - vdfastdeque_iterator r(*this); - operator++(); - return r; -} - -template -vdfastdeque_iterator& vdfastdeque_iterator::operator--() { - if (mIndex-- == 0) { - mIndex = vdfastdeque_block::kBlockSize - 1; - mpBlock = *--mpMap; - } - return *this; -} - -template -vdfastdeque_iterator vdfastdeque_iterator::operator--(int) { - vdfastdeque_iterator r(*this); - operator--(); - return r; -} - -template -bool operator==(const vdfastdeque_iterator& x,const vdfastdeque_iterator& y) { - return x.mpBlock == y.mpBlock && x.mIndex == y.mIndex; -} - -template -bool operator!=(const vdfastdeque_iterator& x,const vdfastdeque_iterator& y) { - return x.mpBlock != y.mpBlock || x.mIndex != y.mIndex; -} - -/////////////////////////////////////////////////////////////////////////////// - -template > -class vdfastdeque { -public: - typedef typename A::reference reference; - typedef typename A::const_reference const_reference; - typedef typename A::pointer pointer; - typedef typename A::const_pointer const_pointer; - typedef T value_type; - typedef A allocator_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef vdfastdeque_iterator iterator; - typedef vdfastdeque_iterator const_iterator; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - vdfastdeque(); - ~vdfastdeque(); - - bool empty() const; - size_type size() const; - - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; - - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - - reference operator[](size_type n); - const_reference operator[](size_type n) const; - - void clear(); - - reference push_back(); - void push_back(const_reference x); - - void pop_front(); - void pop_back(); - - void swap(vdfastdeque& x); - -protected: - void push_back_extend(); - void validate(); - - typedef vdfastdeque_block Block; - - enum { - kBlockSize = Block::kBlockSize, - kBlockSizeBits = Block::kBlockSizeBits - }; - - struct M1 : public A::template rebind::other { - Block **mapStartAlloc; // start of map - Block **mapStartCommit; // start of range of allocated blocks - Block **mapStart; // start of range of active blocks - Block **mapEnd; // end of range of active blocks - Block **mapEndCommit; // end of range of allocated blocks - Block **mapEndAlloc; // end of map - } m; - - struct M2 : public A::template rebind::other { - int startIndex; - int endIndex; - } mTails; - - union TrivialObjectConstraint { - T obj; - }; -}; - -template -vdfastdeque::vdfastdeque() { - m.mapStartAlloc = NULL; - m.mapStartCommit = NULL; - m.mapStart = NULL; - m.mapEnd = NULL; - m.mapEndCommit = NULL; - m.mapEndAlloc = NULL; - mTails.startIndex = 0; - mTails.endIndex = kBlockSize - 1; -} - -template -vdfastdeque::~vdfastdeque() { - while(m.mapStartCommit != m.mapEndCommit) { - mTails.deallocate(*m.mapStartCommit++, 1); - } - - if (m.mapStartAlloc) - m.deallocate(m.mapStartAlloc, m.mapEndAlloc - m.mapStartAlloc); -} - -template -bool vdfastdeque::empty() const { - return size() == 0; -} - -template -typename vdfastdeque::size_type vdfastdeque::size() const { - if (m.mapEnd == m.mapStart) - return 0; - - return kBlockSize * ((m.mapEnd - m.mapStart) - 1) + (mTails.endIndex + 1) - mTails.startIndex; -} - -template -typename vdfastdeque::reference vdfastdeque::front() { - VDASSERT(m.mapStart != m.mapEnd); - return (*m.mapStart)->data[mTails.startIndex]; -} - -template -typename vdfastdeque::const_reference vdfastdeque::front() const { - VDASSERT(m.mapStart != m.mapEnd); - return (*m.mapStart)->data[mTails.startIndex]; -} - -template -typename vdfastdeque::reference vdfastdeque::back() { - VDASSERT(m.mapStart != m.mapEnd); - return m.mapEnd[-1]->data[mTails.endIndex]; -} - -template -typename vdfastdeque::const_reference vdfastdeque::back() const { - VDASSERT(m.mapStart != m.mapEnd); - return m.mapEnd[-1]->data[mTails.endIndex]; -} - -template -typename vdfastdeque::iterator vdfastdeque::begin() { - return iterator(m.mapStart, mTails.startIndex); -} - -template -typename vdfastdeque::const_iterator vdfastdeque::begin() const { - return const_iterator(m.mapStart, mTails.startIndex); -} - -template -typename vdfastdeque::iterator vdfastdeque::end() { - if (mTails.endIndex == kBlockSize - 1) - return iterator(m.mapEnd, 0); - else - return iterator(m.mapEnd - 1, mTails.endIndex + 1); -} - -template -typename vdfastdeque::const_iterator vdfastdeque::end() const { - if (mTails.endIndex == kBlockSize - 1) - return const_iterator(m.mapEnd, 0); - else - return const_iterator(m.mapEnd - 1, mTails.endIndex + 1); -} - -template -typename vdfastdeque::reference vdfastdeque::operator[](size_type n) { - n += mTails.startIndex; - return m.mapStart[n >> kBlockSizeBits]->data[n & (kBlockSize - 1)]; -} - -template -typename vdfastdeque::const_reference vdfastdeque::operator[](size_type n) const { - n += mTails.startIndex; - return m.mapStart[n >> kBlockSizeBits]->data[n & (kBlockSize - 1)]; -} - -template -void vdfastdeque::clear() { - m.mapEnd = m.mapStart; - mTails.startIndex = 0; - mTails.endIndex = kBlockSize - 1; -} - -template -typename vdfastdeque::reference vdfastdeque::push_back() { - if (mTails.endIndex >= kBlockSize - 1) { - push_back_extend(); - - mTails.endIndex = -1; - } - - ++mTails.endIndex; - - VDASSERT(m.mapEnd[-1]); - reference r = m.mapEnd[-1]->data[mTails.endIndex]; - return r; -} - -template -void vdfastdeque::push_back(const_reference x) { - const T x2(x); - push_back() = x2; -} - -template -void vdfastdeque::pop_front() { - if (++mTails.startIndex >= kBlockSize) { - VDASSERT(m.mapEnd != m.mapStart); - mTails.startIndex = 0; - ++m.mapStart; - } -} - -template -void vdfastdeque::pop_back() { - if (--mTails.endIndex < 0) { - VDASSERT(m.mapEnd != m.mapStart); - mTails.endIndex = kBlockSize - 1; - --m.mapEnd; - } -} - -template -void vdfastdeque::swap(vdfastdeque& x) { - std::swap(m.mapStartAlloc, x.m.mapStartAlloc); - std::swap(m.mapStartCommit, x.m.mapStartCommit); - std::swap(m.mapStart, x.m.mapStart); - std::swap(m.mapEnd, x.m.mapEnd); - std::swap(m.mapEndCommit, x.m.mapEndCommit); - std::swap(m.mapEndAlloc, x.m.mapEndAlloc); - std::swap(mTails.startIndex, x.mTails.startIndex); - std::swap(mTails.endIndex, x.mTails.endIndex); -} - -///////////////////////////////// - -template -void vdfastdeque::push_back_extend() { - validate(); - - // check if we need to extend the map itself - if (m.mapEnd == m.mapEndAlloc) { - // can we just shift the map? - size_type currentMapSize = m.mapEndAlloc - m.mapStartAlloc; - size_type freeAtStart = m.mapStartCommit - m.mapStartAlloc; - - if (freeAtStart >= 2 && (freeAtStart + freeAtStart) >= currentMapSize) { - size_type shiftDistance = freeAtStart >> 1; - - VDASSERT(!m.mapStartAlloc[0]); - memmove(m.mapStartAlloc, m.mapStartAlloc + shiftDistance, sizeof(Block *) * (currentMapSize - shiftDistance)); - memset(m.mapStartAlloc + (currentMapSize - shiftDistance), 0, shiftDistance * sizeof(Block *)); - - // relocate pointers - m.mapEndCommit -= shiftDistance; - m.mapEnd -= shiftDistance; - m.mapStart -= shiftDistance; - m.mapStartCommit -= shiftDistance; - validate(); - } else { - size_type newMapSize = currentMapSize*2+1; - - Block **newMap = m.allocate(newMapSize); - - memcpy(newMap, m.mapStartAlloc, currentMapSize * sizeof(Block *)); - memset(newMap + currentMapSize, 0, (newMapSize - currentMapSize) * sizeof(Block *)); - - // relocate pointers - m.mapEndAlloc = newMap + newMapSize; - m.mapEndCommit = newMap + (m.mapEndCommit - m.mapStartAlloc); - m.mapEnd = newMap + (m.mapEnd - m.mapStartAlloc); - m.mapStart = newMap + (m.mapStart - m.mapStartAlloc); - m.mapStartCommit = newMap + (m.mapStartCommit - m.mapStartAlloc); - - m.deallocate(m.mapStartAlloc, currentMapSize); - m.mapStartAlloc = newMap; - validate(); - } - } - - VDASSERT(m.mapEnd != m.mapEndAlloc); - - // check if we already have a block we can use - if (*m.mapEnd) { - ++m.mapEnd; - validate(); - return; - } - - // check if we can steal a block from the beginning - if (m.mapStartCommit != m.mapStart) { - VDASSERT(*m.mapStartCommit); - if (m.mapStartCommit != m.mapEnd) { - *m.mapEnd = *m.mapStartCommit; - *m.mapStartCommit = NULL; - ++m.mapStartCommit; - } - ++m.mapEnd; - m.mapEndCommit = m.mapEnd; - validate(); - return; - } - - // allocate a new block - *m.mapEnd = mTails.allocate(1); - ++m.mapEnd; - m.mapEndCommit = m.mapEnd; - validate(); -} - -template -void vdfastdeque::validate() { - VDASSERT(m.mapStartAlloc <= m.mapStartCommit); - VDASSERT(m.mapStartCommit <= m.mapStart); - VDASSERT(m.mapStart <= m.mapEnd); - VDASSERT(m.mapEnd <= m.mapEndCommit); - VDASSERT(m.mapEndCommit <= m.mapEndAlloc); - - VDASSERT(m.mapStartAlloc == m.mapStartCommit || !*m.mapStartAlloc); - VDASSERT(m.mapStartCommit == m.mapEndCommit || m.mapStartCommit[0]); - VDASSERT(m.mapStart == m.mapEnd || (m.mapStart[0] && m.mapEnd[-1])); - VDASSERT(m.mapEndCommit == m.mapEndAlloc || !m.mapEndCommit[0]); -} - -#include -#include -#include - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef VD2_SYSTEM_VDSTL_H +#define VD2_SYSTEM_VDSTL_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// +// glue +// +/////////////////////////////////////////////////////////////////////////// + +template +struct vdreverse_iterator { +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1310 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) + typedef std::reverse_iterator type; +#else + typedef std::reverse_iterator type; +#endif +}; + +/////////////////////////////////////////////////////////////////////////// + +struct vdfalse_type { }; +struct vdtrue_type { }; + +struct vdfalse_result { typedef vdfalse_type result; }; +struct vdtrue_result { typedef vdtrue_type result; }; + +template void vdmove(T& dst, T& src); +template struct vdmove_capable : public vdfalse_result {}; + +template +T *vdmove_forward_impl(T *src1, T *src2, T *dst, vdfalse_type) { + T *p = src1; + while(p != src2) { + *dst = *p; + ++dst; + ++p; + } + + return dst; +} + +template +T *vdmove_backward_impl(T *src1, T *src2, T *dst, vdfalse_type) { + T *p = src2; + while(p != src1) { + --dst; + --p; + *dst = *p; + } + + return dst; +} + +template +T *vdmove_forward_impl(T *src1, T *src2, T *dst, vdtrue_type) { + T *p = src1; + while(p != src2) { + vdmove(*dst, *p); + ++dst; + ++p; + } + + return dst; +} + +template +T *vdmove_backward_impl(T *src1, T *src2, T *dst, vdtrue_type) { + T *p = src2; + while(p != src1) { + --dst; + --p; + vdmove(*dst, *p); + } + + return dst; +} + +template +T *vdmove_forward(T *src1, T *src2, T *dst) { + return vdmove_forward_impl(src1, src2, dst, vdmove_capable::result()); +} + +template +T *vdmove_backward(T *src1, T *src2, T *dst) { + return vdmove_backward_impl(src1, src2, dst, vdmove_capable::result()); +} + +#define VDMOVE_CAPABLE(type) \ + template<> struct vdmove_capable : public vdtrue_result {}; \ + template<> void vdmove(type& dst, type& src) + +/////////////////////////////////////////////////////////////////////////// + +template char (&VDCountOfHelper(const T(&)[N]))[N]; + +#define vdcountof(array) (sizeof(VDCountOfHelper(array))) + +/////////////////////////////////////////////////////////////////////////// + +class vdallocator_base { +protected: + void VDNORETURN throw_oom(size_t n, size_t elsize); +}; + +template +class vdallocator : public vdallocator_base { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template struct rebind { typedef vdallocator other; }; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, void *p_close = 0) { + if (n > ((~(size_type)0) >> 1) / sizeof(T)) + throw_oom(n, sizeof(T)); + + pointer p = (pointer)malloc(n*sizeof(T)); + + if (!p) + throw_oom(n, sizeof(T)); + + return p; + } + + void deallocate(pointer p, size_type n) { + free(p); + } + + size_type max_size() const throw() { return ((~(size_type)0) >> 1) / sizeof(T); } + + void construct(pointer p, const T& val) { new((void *)p) T(val); } + void destroy(pointer p) { ((T*)p)->~T(); } + +#if defined(_MSC_VER) && _MSC_VER < 1300 + char * _Charalloc(size_type n) { return rebind::other::allocate(n); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////// + +template +class vddebug_alloc { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template struct rebind { typedef vddebug_alloc other; }; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, void *p_close = 0) { + pointer p = (pointer)VDAlignedMalloc(n*sizeof(T) + 2*kDeadZone, 16); + + if (!p) + return p; + + memset((char *)p, 0xa9, kDeadZone); + memset((char *)p + kDeadZone + n*sizeof(T), 0xa9, kDeadZone); + + return (pointer)((char *)p + kDeadZone); + } + + void deallocate(pointer p, size_type n) { + char *p1 = (char *)p - kDeadZone; + char *p2 = (char *)p + n*sizeof(T); + + for(uint32 i=0; i~T(); } + +#if defined(_MSC_VER) && _MSC_VER < 1300 + char * _Charalloc(size_type n) { return rebind::other::allocate(n); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////// + +template +class vdaligned_alloc { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + vdaligned_alloc() {} + + template + vdaligned_alloc(const vdaligned_alloc&) {} + + template struct rebind { typedef vdaligned_alloc other; }; + + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + + pointer allocate(size_type n, void *p = 0) { return (pointer)VDAlignedMalloc(n*sizeof(T), kAlignment); } + void deallocate(pointer p, size_type n) { VDAlignedFree(p); } + size_type max_size() const throw() { return INT_MAX; } + + void construct(pointer p, const T& val) { new((void *)p) T(val); } + void destroy(pointer p) { ((T*)p)->~T(); } + +#if defined(_MSC_VER) && _MSC_VER < 1300 + char * _Charalloc(size_type n) { return rebind::other::allocate(n); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////// +// +// vdblock +// +// vdblock is similar to vector, except: +// +// 1) May only be used with POD types. +// 2) No construction or destruction of elements is performed. +// 3) Capacity is always equal to size, and reallocation is performed +// whenever the size changes. +// 4) Contents are undefined after a reallocation. +// 5) No insertion or deletion operations are provided. +// +/////////////////////////////////////////////////////////////////////////// + +template > +class vdblock : protected A { +public: + typedef T value_type; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + vdblock(const A& alloc = A()) : A(alloc), mpBlock(NULL), mSize(0) {} + vdblock(size_type s, const A& alloc = A()) : A(alloc), mpBlock(A::allocate(s, 0)), mSize(s) {} + ~vdblock() { + if (mpBlock) + A::deallocate(mpBlock, mSize); + } + + reference operator[](size_type n) { return mpBlock[n]; } + const_reference operator[](size_type n) const { return mpBlock[n]; } + reference at(size_type n) { return n < mSize ? mpBlock[n] : throw std::length_error("n"); } + const_reference at(size_type n) const { return n < mSize ? mpBlock[n] : throw std::length_error("n"); } + reference front() { return *mpBlock; } + const_reference front() const { return *mpBlock; } + reference back() { return mpBlock[mSize-1]; } + const_reference back() const { return mpBlock[mSize-1]; } + + const_pointer data() const { return mpBlock; } + pointer data() { return mpBlock; } + + const_iterator begin() const { return mpBlock; } + iterator begin() { return mpBlock; } + const_iterator end() const { return mpBlock + mSize; } + iterator end() { return mpBlock + mSize; } + + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + + bool empty() const { return !mSize; } + size_type size() const { return mSize; } + size_type capacity() const { return mSize; } + + void clear() { + if (mpBlock) + A::deallocate(mpBlock, mSize); + mpBlock = NULL; + mSize = 0; + } + + void resize(size_type s) { + if (s != mSize) { + if (mpBlock) { + A::deallocate(mpBlock, mSize); + mpBlock = NULL; + mSize = 0; + } + if (s) + mpBlock = A::allocate(s, 0); + mSize = s; + } + } + + void resize(size_type s, const T& value) { + if (s != mSize) { + if (mpBlock) { + A::deallocate(mpBlock, mSize); + mpBlock = NULL; + mSize = 0; + } + if (s) { + mpBlock = A::allocate(s, 0); + std::fill(mpBlock, mpBlock+s, value); + } + mSize = s; + } + } + + void swap(vdblock& x) { + std::swap(mpBlock, x.mpBlock); + std::swap(mSize, x.mSize); + } + +protected: + typename A::pointer mpBlock; + typename A::size_type mSize; + + union PODType { + T x; + }; +}; + +/////////////////////////////////////////////////////////////////////////// +// +// vdstructex +// +// vdstructex describes an extensible format structure, such as +// BITMAPINFOHEADER or WAVEFORMATEX, without the pain-in-the-butt +// casting normally associated with one. +// +/////////////////////////////////////////////////////////////////////////// + +template +class vdstructex { +public: + typedef size_t size_type; + typedef T value_type; + + vdstructex() : mpMemory(NULL), mSize(0) {} + + explicit vdstructex(size_t len) : mpMemory(NULL), mSize(0) { + resize(len); + } + + vdstructex(const T *pStruct, size_t len) : mSize(len), mpMemory((T*)malloc(len)) { + memcpy(mpMemory, pStruct, len); + } + + vdstructex(const vdstructex& src) : mSize(src.mSize), mpMemory((T*)malloc(src.mSize)) { + memcpy(mpMemory, src.mpMemory, mSize); + } + + ~vdstructex() { + free(mpMemory); + } + + bool empty() const { return !mpMemory; } + size_type size() const { return mSize; } + T* data() const { return mpMemory; } + + T& operator *() const { return *(T *)mpMemory; } + T* operator->() const { return (T *)mpMemory; } + + bool operator==(const vdstructex& x) const { + return mSize == x.mSize && (!mSize || !memcmp(mpMemory, x.mpMemory, mSize)); + } + + bool operator!=(const vdstructex& x) const { + return mSize != x.mSize || (mSize && memcmp(mpMemory, x.mpMemory, mSize)); + } + + vdstructex& operator=(const vdstructex& src) { + assign(src.mpMemory, src.mSize); + return *this; + } + + void assign(const T *pStruct, size_type len) { + if (mSize != len) + resize(len); + + memcpy(mpMemory, pStruct, len); + } + + void clear() { + free(mpMemory); + mpMemory = NULL; + mSize = 0; + } + + void resize(size_type len) { + if (mSize != len) + mpMemory = (T *)realloc(mpMemory, mSize = len); + } + +protected: + size_type mSize; + T *mpMemory; +}; + +/////////////////////////////////////////////////////////////////////////// +// +// vdlist +// +// vdlist is similar to list, except: +// +// 1) The node structure must be embedded as a superclass of T. +// Thus, the client is in full control of allocation. +// 2) Node pointers may be converted back into iterators in O(1). +// +/////////////////////////////////////////////////////////////////////////// + +struct vdlist_node { + vdlist_node *mListNodeNext, *mListNodePrev; +}; + +template +class vdlist_iterator { +public: + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T *pointer_type; + typedef T& reference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + vdlist_iterator() {} + vdlist_iterator(T *p) : mp(p) {} + vdlist_iterator(const vdlist_iterator& src) : mp(src.mp) {} + + T* operator *() const { + return static_cast(mp); + } + + bool operator==(const vdlist_iterator& x) const { + return mp == x.mp; + } + + bool operator!=(const vdlist_iterator& x) const { + return mp != x.mp; + } + + vdlist_iterator& operator++() { + mp = mp->mListNodeNext; + return *this; + } + + vdlist_iterator& operator--() { + mp = mp->mListNodePrev; + return *this; + } + + vdlist_iterator operator++(int) { + vdlist_iterator tmp(*this); + mp = mp->mListNodeNext; + return tmp; + } + + vdlist_iterator& operator--(int) { + vdlist_iterator tmp(*this); + mp = mp->mListNodePrev; + return tmp; + } + + vdlist_node *mp; +}; + +class vdlist_base { +public: + typedef vdlist_node node; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + bool empty() const { + return mAnchor.mListNodeNext == &mAnchor; + } + + size_type size() const { + node *p = { mAnchor.mListNodeNext }; + size_type s = 0; + + if (p != &mAnchor) + do { + ++s; + p = p->mListNodeNext; + } while(p != &mAnchor); + + return s; + } + + void clear() { + mAnchor.mListNodePrev = &mAnchor; + mAnchor.mListNodeNext = &mAnchor; + } + + void pop_front() { + mAnchor.mListNodeNext = mAnchor.mListNodeNext->mListNodeNext; + mAnchor.mListNodeNext->mListNodePrev = &mAnchor; + } + + void pop_back() { + mAnchor.mListNodePrev = mAnchor.mListNodePrev->mListNodePrev; + mAnchor.mListNodePrev->mListNodeNext = &mAnchor; + } + + static void unlink(vdlist_node& node) { + vdlist_node& n1 = *node.mListNodePrev; + vdlist_node& n2 = *node.mListNodeNext; + + n1.mListNodeNext = &n2; + n2.mListNodePrev = &n1; + } + +protected: + node mAnchor; +}; + +template +class vdlist : public vdlist_base { +public: + typedef T* value_type; + typedef T** pointer; + typedef const T** const_pointer; + typedef T*& reference; + typedef const T*& const_reference; + typedef vdlist_iterator iterator; + typedef vdlist_iterator const_iterator; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + vdlist() { + mAnchor.mListNodePrev = &mAnchor; + mAnchor.mListNodeNext = &mAnchor; + } + + iterator begin() { + iterator it; + it.mp = mAnchor.mListNodeNext; + return it; + } + + const_iterator begin() const { + const_iterator it; + it.mp = mAnchor.mListNodeNext; + return it; + } + + iterator end() { + iterator it; + it.mp = &mAnchor; + return it; + } + + const_iterator end() const { + const_iterator it; + it.mp = &mAnchor; + return it; + } + + reverse_iterator rbegin() { + return reverse_iterator(begin()); + } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(begin()); + } + + reverse_iterator rend() { + return reverse_iterator(end); + } + + const_reverse_iterator rend() const { + return const_reverse_iterator(end()); + } + + const value_type front() const { + return static_cast(mAnchor.mListNodeNext); + } + + const value_type back() const { + return static_cast(mAnchor.mListNodePrev); + } + + iterator find(T *p) { + iterator it; + it.mp = mAnchor.mListNodeNext; + + if (it.mp != &mAnchor) + do { + if (it.mp == static_cast(p)) + break; + + it.mp = it.mp->mListNodeNext; + } while(it.mp != &mAnchor); + + return it; + } + + const_iterator find(T *p) const { + const_iterator it; + it.mp = mAnchor.mListNodeNext; + + if (it.mp != &mAnchor) + do { + if (it.mp == static_cast(p)) + break; + + it.mp = it.mp->mListNodeNext; + } while(it.mp != &mAnchor); + + return it; + } + + iterator fast_find(T *p) { + iterator it(p); + return it; + } + + const_iterator fast_find(T *p) const { + iterator it(p); + } + + void push_front(T *p) { + node& n = *p; + n.mListNodePrev = &mAnchor; + n.mListNodeNext = mAnchor.mListNodeNext; + n.mListNodeNext->mListNodePrev = &n; + mAnchor.mListNodeNext = &n; + } + + void push_back(T *p) { + node& n = *p; + n.mListNodeNext = &mAnchor; + n.mListNodePrev = mAnchor.mListNodePrev; + n.mListNodePrev->mListNodeNext = &n; + mAnchor.mListNodePrev = &n; + } + + iterator erase(T *p) { + return erase(fast_find(p)); + } + + iterator erase(iterator it) { + node& n = *it.mp; + + n.mListNodePrev->mListNodeNext = n.mListNodeNext; + n.mListNodeNext->mListNodePrev = n.mListNodePrev; + + it.mp = n.mListNodeNext; + return it; + } + + iterator erase(iterator i1, iterator i2) { + node& np = *i1.mp->mListNodePrev; + node& nn = *i2.mp; + + np.mListNodeNext = &nn; + nn.mListNodePrev = &np; + + return i2; + } + + void insert(iterator dst, T *src) { + node& ns = *src; + node& nd = *dst.mp; + + ns.mListNodeNext = &nd; + ns.mListNodePrev = nd.mListNodePrev; + nd.mListNodePrev->mListNodeNext = &ns; + nd.mListNodePrev = &ns; + } + + void insert(iterator dst, iterator i1, iterator i2) { + if (i1 != i2) { + node& np = *dst.mp->mListNodePrev; + node& nn = *dst.mp; + node& n1 = *i1.mp; + node& n2 = *i2.mp->mListNodePrev; + + np.mListNodeNext = &n1; + n1.mListNodePrev = &np; + n2.mListNodeNext = &nn; + nn.mListNodePrev = &n2; + } + } + + void splice(iterator dst, vdlist& srclist) { + insert(dst, srclist.begin(), srclist.end()); + srclist.clear(); + } + + void splice(iterator dst, vdlist& srclist, iterator src) { + T *v = *src; + srclist.erase(src); + insert(dst, v); + } + + void splice(iterator dst, vdlist& srclist, iterator i1, iterator i2) { + if (dst.mp != i1.mp && dst.mp != i2.mp) { + srclist.erase(i1, i2); + insert(dst, i1, i2); + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +#if defined(_DEBUG) && defined(_MSC_VER) + #define VD_ACCELERATE_TEMPLATES +#endif + +#ifndef VDTINLINE + #ifdef VD_ACCELERATE_TEMPLATES + #ifndef VDTEXTERN + #define VDTEXTERN extern + #endif + + #define VDTINLINE + #else + #define VDTINLINE inline + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// + +template +class vdspan { +public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + VDTINLINE vdspan(); + + template + VDTINLINE vdspan(T (&arr)[N]); + + VDTINLINE vdspan(T *p1, T *p2); + VDTINLINE vdspan(T *p1, size_type len); + +public: + VDTINLINE bool empty() const; + VDTINLINE size_type size() const; + + VDTINLINE pointer data(); + VDTINLINE const_pointer data() const; + + VDTINLINE iterator begin(); + VDTINLINE const_iterator begin() const; + VDTINLINE iterator end(); + VDTINLINE const_iterator end() const; + + VDTINLINE reverse_iterator rbegin(); + VDTINLINE const_reverse_iterator rbegin() const; + VDTINLINE reverse_iterator rend(); + VDTINLINE const_reverse_iterator rend() const; + + VDTINLINE reference front(); + VDTINLINE const_reference front() const; + VDTINLINE reference back(); + VDTINLINE const_reference back() const; + + VDTINLINE reference operator[](size_type n); + VDTINLINE const_reference operator[](size_type n) const; + +protected: + T *mpBegin; + T *mpEnd; +}; + +#ifdef VD_ACCELERATE_TEMPLATES + #pragma warning(push) + #pragma warning(disable: 4231) // warning C4231: nonstandard extension used : 'extern' before template explicit instantiation + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + VDTEXTERN template vdspan; + #pragma warning(pop) +#endif + +template VDTINLINE vdspan::vdspan() : mpBegin(NULL), mpEnd(NULL) {} +template template VDTINLINE vdspan::vdspan(T (&arr)[N]) : mpBegin(&arr[0]), mpEnd(&arr[N]) {} +template VDTINLINE vdspan::vdspan(T *p1, T *p2) : mpBegin(p1), mpEnd(p2) {} +template VDTINLINE vdspan::vdspan(T *p, size_type len) : mpBegin(p), mpEnd(p+len) {} +template VDTINLINE bool vdspan::empty() const { return mpBegin == mpEnd; } +template VDTINLINE typename vdspan::size_type vdspan::size() const { return size_type(mpEnd - mpBegin); } +template VDTINLINE typename vdspan::pointer vdspan::data() { return mpBegin; } +template VDTINLINE typename vdspan::const_pointer vdspan::data() const { return mpBegin; } +template VDTINLINE typename vdspan::iterator vdspan::begin() { return mpBegin; } +template VDTINLINE typename vdspan::const_iterator vdspan::begin() const { return mpBegin; } +template VDTINLINE typename vdspan::iterator vdspan::end() { return mpEnd; } +template VDTINLINE typename vdspan::const_iterator vdspan::end() const { return mpEnd; } +template VDTINLINE typename vdspan::reverse_iterator vdspan::rbegin() { return reverse_iterator(mpEnd); } +template VDTINLINE typename vdspan::const_reverse_iterator vdspan::rbegin() const { return const_reverse_iterator(mpEnd); } +template VDTINLINE typename vdspan::reverse_iterator vdspan::rend() { return reverse_iterator(mpBegin); } +template VDTINLINE typename vdspan::const_reverse_iterator vdspan::rend() const { return const_reverse_iterator(mpBegin); } +template VDTINLINE typename vdspan::reference vdspan::front() { return *mpBegin; } +template VDTINLINE typename vdspan::const_reference vdspan::front() const { return *mpBegin; } +template VDTINLINE typename vdspan::reference vdspan::back() { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } +template VDTINLINE typename vdspan::const_reference vdspan::back() const { VDASSERT(mpBegin != mpEnd); return mpEnd[-1]; } +template VDTINLINE typename vdspan::reference vdspan::operator[](size_type n) { VDASSERT(n < size_type(mpEnd - mpBegin)); return mpBegin[n]; } +template VDTINLINE typename vdspan::const_reference vdspan::operator[](size_type n) const { VDASSERT(n < size_type(mpEnd - mpBegin)); return mpBegin[n]; } + +/////////////////////////////////////////////////////////////////////////////// + +template +bool operator==(const vdspan& x, const vdspan& y) { + uint32 len = x.size(); + if (len != y.size()) + return false; + + const T *px = x.data(); + const T *py = y.data(); + + for(uint32 i=0; i +inline bool operator!=(const vdspan& x, const vdspan& y) { return !(x == y); } + +/////////////////////////////////////////////////////////////////////////////// + +template > +class vdfastvector_base : public vdspan { +protected: + using vdspan::mpBegin; + using vdspan::mpEnd; + +public: + typedef typename vdspan::value_type value_type; + typedef typename vdspan::pointer pointer; + typedef typename vdspan::const_pointer const_pointer; + typedef typename vdspan::reference reference; + typedef typename vdspan::const_reference const_reference; + typedef typename vdspan::size_type size_type; + typedef typename vdspan::difference_type difference_type; + typedef typename vdspan::iterator iterator; + typedef typename vdspan::const_iterator const_iterator; + typedef typename vdspan::reverse_iterator reverse_iterator; + typedef typename vdspan::const_reverse_iterator const_reverse_iterator; + + ~vdfastvector_base() { + if (static_cast(m).is_deallocatable_storage(mpBegin)) + m.deallocate(mpBegin, m.eos - mpBegin); + } + + size_type capacity() const { return size_type(m.eos - mpBegin); } + +public: + T *alloc(size_type n) { + size_type offset = (size_type)(mpEnd - mpBegin); + resize(offset + n); + return mpBegin + offset; + } + + void assign(const T *p1, const T *p2) { + resize(p2 - p1); + memcpy(mpBegin, p1, (char *)p2 - (char *)p1); + } + + void clear() { + mpEnd = mpBegin; + } + + iterator erase(iterator it) { + VDASSERT(it - mpBegin < mpEnd - mpBegin); + + memmove(it, it+1, (char *)mpEnd - (char *)(it+1)); + + --mpEnd; + + return it; + } + + iterator erase(iterator it1, iterator it2) { + VDASSERT(it1 - mpBegin <= mpEnd - mpBegin); + VDASSERT(it2 - mpBegin <= mpEnd - mpBegin); + VDASSERT(it1 <= it2); + + memmove(it1, it2, (char *)mpEnd - (char *)it2); + + mpEnd -= (it2 - it1); + + return it1; + } + + iterator insert(iterator it, const T& value) { + const T temp(value); // copy in case value is inside container. + + if (mpEnd == m.eos) { + difference_type delta = it - mpBegin; + _reserve_always_add_one(); + it = mpBegin + delta; + } + + memmove(it+1, it, sizeof(T) * (mpEnd - it)); + *it = temp; + ++mpEnd; + VDASSERT(mpEnd <= m.eos); + + return it; + } + + iterator insert(iterator it, size_type n, const T& value) { + const T temp(value); // copy in case value is inside container. + + ptrdiff_t bytesToInsert = n * sizeof(T); + + if ((char *)m.eos - (char *)mpEnd < bytesToInsert) { + difference_type delta = it - mpBegin; + _reserve_always_add(bytesToInsert); + it = mpBegin + delta; + } + + memmove((char *)it + bytesToInsert, it, (char *)mpEnd - (char *)it); + for(size_t i=0; i size_type((char *)m.eos - (char *)mpBegin)) + _reserve_always_amortized(n); + + mpEnd = mpBegin + n; + } + + void resize(size_type n, const T& value) { + const T temp(value); + + if (n*sizeof(T) > size_type((char *)m.eos - (char *)mpBegin)) { + _reserve_always_amortized(n); + } + + const iterator newEnd(mpBegin + n); + if (newEnd > mpEnd) + std::fill(mpEnd, newEnd, temp); + mpEnd = newEnd; + } + + void reserve(size_type n) { + if (n*sizeof(T) > size_type((char *)m.eos - (char *)mpBegin)) + _reserve_always(n); + } + +protected: +#ifdef _MSC_VER + __declspec(noinline) +#endif + void _reserve_always_add_one() { + _reserve_always((m.eos - mpBegin) * 2 + 1); + } + +#ifdef _MSC_VER + __declspec(noinline) +#endif + void _reserve_always_add(size_type n) { + _reserve_always((m.eos - mpBegin) * 2 + n); + } + +#ifdef _MSC_VER + __declspec(noinline) +#endif + void _reserve_always(size_type n) { + size_type oldSize = mpEnd - mpBegin; + T *oldStorage = mpBegin; + T *newStorage = m.allocate(n, NULL); + + memcpy(newStorage, mpBegin, (char *)mpEnd - (char *)mpBegin); + if (static_cast(m).is_deallocatable_storage(oldStorage)) + m.deallocate(oldStorage, m.eos - mpBegin); + mpBegin = newStorage; + mpEnd = newStorage + oldSize; + m.eos = newStorage + n; + } + +#ifdef _MSC_VER + __declspec(noinline) +#endif + void _reserve_always_amortized(size_type n) { + size_type nextCapacity = (size_type)((m.eos - mpBegin)*2); + + if (nextCapacity < n) + nextCapacity = n; + + _reserve_always(nextCapacity); + } + + struct : A, S { + T *eos; + } m; + + union TrivialObjectConstraint { + T m; + }; +}; + +/////////////////////////////////////////////////////////////////////////////// + +struct vdfastvector_storage { + bool is_deallocatable_storage(void *p) const { + return p != 0; + } +}; + +template > +class vdfastvector : public vdfastvector_base { +protected: + using vdfastvector_base::m; + using vdfastvector_base::mpBegin; + using vdfastvector_base::mpEnd; + +public: + typedef typename vdfastvector_base::value_type value_type; + typedef typename vdfastvector_base::pointer pointer; + typedef typename vdfastvector_base::const_pointer const_pointer; + typedef typename vdfastvector_base::reference reference; + typedef typename vdfastvector_base::const_reference const_reference; + typedef typename vdfastvector_base::size_type size_type; + typedef typename vdfastvector_base::difference_type difference_type; + typedef typename vdfastvector_base::iterator iterator; + typedef typename vdfastvector_base::const_iterator const_iterator; + typedef typename vdfastvector_base::reverse_iterator reverse_iterator; + typedef typename vdfastvector_base::const_reverse_iterator const_reverse_iterator; + + vdfastvector() { + m.eos = NULL; + } + + vdfastvector(size_type len) { + mpBegin = m.allocate(len, NULL); + mpEnd = mpBegin + len; + m.eos = mpEnd; + } + + vdfastvector(size_type len, const T& fill) { + mpBegin = m.allocate(len, NULL); + mpEnd = mpBegin + len; + m.eos = mpEnd; + + std::fill(mpBegin, mpEnd, fill); + } + + vdfastvector(const vdfastvector& x) { + size_type n = x.mpEnd - x.mpBegin; + mpBegin = m.allocate(n, NULL); + mpEnd = mpBegin + n; + m.eos = mpEnd; + memcpy(mpBegin, x.mpBegin, sizeof(T) * n); + } + + vdfastvector(const value_type *p, const value_type *q) { + m.eos = NULL; + + assign(p, q); + } + + vdfastvector& operator=(const vdfastvector& x) { + if (this != &x) + vdfastvector::assign(x.mpBegin, x.mpEnd); + + return *this; + } + + void swap(vdfastvector& x) { + std::swap(mpBegin, x.mpBegin); + std::swap(mpEnd, x.mpEnd); + std::swap(m.eos, x.m.eos); + } + + void swap(vdfastvector&& x) { + std::swap(mpBegin, x.mpBegin); + std::swap(mpEnd, x.mpEnd); + std::swap(m.eos, x.m.eos); + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +struct vdfastfixedvector_storage { + T mArray[N]; + + bool is_deallocatable_storage(void *p) const { + return p != mArray; + } +}; + +template > +class vdfastfixedvector : public vdfastvector_base, A> { +protected: + using vdfastvector_base, A>::mpBegin; + using vdfastvector_base, A>::mpEnd; + using vdfastvector_base, A>::m; + +public: + typedef typename vdfastvector_base, A>::value_type value_type; + typedef typename vdfastvector_base, A>::pointer pointer; + typedef typename vdfastvector_base, A>::const_pointer const_pointer; + typedef typename vdfastvector_base, A>::reference reference; + typedef typename vdfastvector_base, A>::const_reference const_reference; + typedef typename vdfastvector_base, A>::size_type size_type; + typedef typename vdfastvector_base, A>::difference_type difference_type; + typedef typename vdfastvector_base, A>::iterator iterator; + typedef typename vdfastvector_base, A>::const_iterator const_iterator; + typedef typename vdfastvector_base, A>::reverse_iterator reverse_iterator; + typedef typename vdfastvector_base, A>::const_reverse_iterator const_reverse_iterator; + + vdfastfixedvector() { + mpBegin = m.mArray; + mpEnd = m.mArray; + m.eos = m.mArray + N; + } + + vdfastfixedvector(size_type len) { + if (len <= N) { + mpBegin = m.mArray; + mpEnd = m.mArray + len; + m.eos = m.mArray + N; + } else { + mpBegin = m.allocate(len, NULL); + mpEnd = mpBegin + len; + m.eos = mpEnd; + } + } + + vdfastfixedvector(size_type len, const T& fill) { + mpBegin = m.allocate(len, NULL); + mpEnd = mpBegin + len; + m.eos = mpEnd; + + std::fill(mpBegin, mpEnd, fill); + } + + vdfastfixedvector(const vdfastfixedvector& x) { + size_type n = x.mpEnd - x.mpBegin; + + if (n <= N) { + mpBegin = m.mArray; + mpEnd = m.mArray + n; + m.eos = m.mArray + N; + } else { + mpBegin = m.allocate(n, NULL); + mpEnd = mpBegin + n; + m.eos = mpEnd; + } + + memcpy(mpBegin, x.mpBegin, sizeof(T) * n); + } + + vdfastfixedvector(const value_type *p, const value_type *q) { + mpBegin = m.mArray; + mpEnd = m.mArray; + m.eos = m.mArray + N; + + assign(p, q); + } + + vdfastfixedvector& operator=(const vdfastfixedvector& x) { + if (this != &x) + assign(x.mpBegin, x.mpEnd); + + return *this; + } + + void swap(vdfastfixedvector& x) { + size_t this_bytes = (char *)mpEnd - (char *)mpBegin; + size_t other_bytes = (char *)x.mpEnd - (char *)x.mpBegin; + + T *p; + + if (mpBegin == m.mArray) { + if (x.mpBegin == x.m.mArray) { + if (this_bytes < other_bytes) { + VDSwapMemory(m.mArray, x.m.mArray, this_bytes); + memcpy((char *)m.mArray + this_bytes, (char *)x.m.mArray + this_bytes, other_bytes - this_bytes); + } else { + VDSwapMemory(m.mArray, x.m.mArray, other_bytes); + memcpy((char *)m.mArray + other_bytes, (char *)x.m.mArray + other_bytes, this_bytes - other_bytes); + } + + mpEnd = (T *)((char *)mpBegin + other_bytes); + x.mpEnd = (T *)((char *)x.mpBegin + this_bytes); + } else { + memcpy(x.m.mArray, mpBegin, this_bytes); + + mpBegin = x.mpBegin; + mpEnd = x.mpEnd; + m.eos = x.m.eos; + + x.mpBegin = x.m.mArray; + x.mpEnd = (T *)((char *)x.m.mArray + this_bytes); + x.m.eos = x.m.mArray + N; + } + } else { + if (x.mpBegin == x.m.mArray) { + memcpy(x.m.mArray, mpBegin, other_bytes); + + x.mpBegin = mpBegin; + x.mpEnd = mpEnd; + x.m.eos = m.eos; + + mpBegin = m.mArray; + mpEnd = (T *)((char *)m.mArray + other_bytes); + m.eos = m.mArray + N; + } else { + p = mpBegin; mpBegin = x.mpBegin; x.mpBegin = p; + p = mpEnd; mpEnd = x.mpEnd; x.mpEnd = p; + p = m.eos; m.eos = x.m.eos; x.m.eos = p; + } + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +struct vdfastdeque_block { + enum { + kBlockSize = 32, + kBlockSizeBits = 5 + }; + + T data[kBlockSize]; +}; + +template +class vdfastdeque_iterator { +public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + vdfastdeque_iterator(const vdfastdeque_iterator&); + vdfastdeque_iterator(vdfastdeque_block **pMapEntry, uint32 index); + + T& operator *() const; + T& operator ->() const; + vdfastdeque_iterator& operator++(); + vdfastdeque_iterator operator++(int); + vdfastdeque_iterator& operator--(); + vdfastdeque_iterator operator--(int); + +public: + vdfastdeque_block **mpMap; + vdfastdeque_block *mpBlock; + uint32 mIndex; +}; + +template +vdfastdeque_iterator::vdfastdeque_iterator(const vdfastdeque_iterator& x) + : mpMap(x.mpMap) + , mpBlock(x.mpBlock) + , mIndex(x.mIndex) +{ +} + +template +vdfastdeque_iterator::vdfastdeque_iterator(vdfastdeque_block **pMapEntry, uint32 index) + : mpMap(pMapEntry) + , mpBlock(mpMap ? *mpMap : NULL) + , mIndex(index) +{ +} + +template +T& vdfastdeque_iterator::operator *() const { + return mpBlock->data[mIndex]; +} + +template +T& vdfastdeque_iterator::operator ->() const { + return mpBlock->data[mIndex]; +} + +template +vdfastdeque_iterator& vdfastdeque_iterator::operator++() { + if (++mIndex >= vdfastdeque_block::kBlockSize) { + mIndex = 0; + mpBlock = *++mpMap; + } + return *this; +} + +template +vdfastdeque_iterator vdfastdeque_iterator::operator++(int) { + vdfastdeque_iterator r(*this); + operator++(); + return r; +} + +template +vdfastdeque_iterator& vdfastdeque_iterator::operator--() { + if (mIndex-- == 0) { + mIndex = vdfastdeque_block::kBlockSize - 1; + mpBlock = *--mpMap; + } + return *this; +} + +template +vdfastdeque_iterator vdfastdeque_iterator::operator--(int) { + vdfastdeque_iterator r(*this); + operator--(); + return r; +} + +template +bool operator==(const vdfastdeque_iterator& x,const vdfastdeque_iterator& y) { + return x.mpBlock == y.mpBlock && x.mIndex == y.mIndex; +} + +template +bool operator!=(const vdfastdeque_iterator& x,const vdfastdeque_iterator& y) { + return x.mpBlock != y.mpBlock || x.mIndex != y.mIndex; +} + +/////////////////////////////////////////////////////////////////////////////// + +template > +class vdfastdeque { +public: + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef T value_type; + typedef A allocator_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef vdfastdeque_iterator iterator; + typedef vdfastdeque_iterator const_iterator; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + vdfastdeque(); + ~vdfastdeque(); + + bool empty() const; + size_type size() const; + + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + reference operator[](size_type n); + const_reference operator[](size_type n) const; + + void clear(); + + reference push_back(); + void push_back(const_reference x); + + void pop_front(); + void pop_back(); + + void swap(vdfastdeque& x); + +protected: + void push_back_extend(); + void validate(); + + typedef vdfastdeque_block Block; + + enum { + kBlockSize = Block::kBlockSize, + kBlockSizeBits = Block::kBlockSizeBits + }; + + struct M1 : public A::template rebind::other { + Block **mapStartAlloc; // start of map + Block **mapStartCommit; // start of range of allocated blocks + Block **mapStart; // start of range of active blocks + Block **mapEnd; // end of range of active blocks + Block **mapEndCommit; // end of range of allocated blocks + Block **mapEndAlloc; // end of map + } m; + + struct M2 : public A::template rebind::other { + int startIndex; + int endIndex; + } mTails; + + union TrivialObjectConstraint { + T obj; + }; +}; + +template +vdfastdeque::vdfastdeque() { + m.mapStartAlloc = NULL; + m.mapStartCommit = NULL; + m.mapStart = NULL; + m.mapEnd = NULL; + m.mapEndCommit = NULL; + m.mapEndAlloc = NULL; + mTails.startIndex = 0; + mTails.endIndex = kBlockSize - 1; +} + +template +vdfastdeque::~vdfastdeque() { + while(m.mapStartCommit != m.mapEndCommit) { + mTails.deallocate(*m.mapStartCommit++, 1); + } + + if (m.mapStartAlloc) + m.deallocate(m.mapStartAlloc, m.mapEndAlloc - m.mapStartAlloc); +} + +template +bool vdfastdeque::empty() const { + return size() == 0; +} + +template +typename vdfastdeque::size_type vdfastdeque::size() const { + if (m.mapEnd == m.mapStart) + return 0; + + return kBlockSize * ((m.mapEnd - m.mapStart) - 1) + (mTails.endIndex + 1) - mTails.startIndex; +} + +template +typename vdfastdeque::reference vdfastdeque::front() { + VDASSERT(m.mapStart != m.mapEnd); + return (*m.mapStart)->data[mTails.startIndex]; +} + +template +typename vdfastdeque::const_reference vdfastdeque::front() const { + VDASSERT(m.mapStart != m.mapEnd); + return (*m.mapStart)->data[mTails.startIndex]; +} + +template +typename vdfastdeque::reference vdfastdeque::back() { + VDASSERT(m.mapStart != m.mapEnd); + return m.mapEnd[-1]->data[mTails.endIndex]; +} + +template +typename vdfastdeque::const_reference vdfastdeque::back() const { + VDASSERT(m.mapStart != m.mapEnd); + return m.mapEnd[-1]->data[mTails.endIndex]; +} + +template +typename vdfastdeque::iterator vdfastdeque::begin() { + return iterator(m.mapStart, mTails.startIndex); +} + +template +typename vdfastdeque::const_iterator vdfastdeque::begin() const { + return const_iterator(m.mapStart, mTails.startIndex); +} + +template +typename vdfastdeque::iterator vdfastdeque::end() { + if (mTails.endIndex == kBlockSize - 1) + return iterator(m.mapEnd, 0); + else + return iterator(m.mapEnd - 1, mTails.endIndex + 1); +} + +template +typename vdfastdeque::const_iterator vdfastdeque::end() const { + if (mTails.endIndex == kBlockSize - 1) + return const_iterator(m.mapEnd, 0); + else + return const_iterator(m.mapEnd - 1, mTails.endIndex + 1); +} + +template +typename vdfastdeque::reference vdfastdeque::operator[](size_type n) { + n += mTails.startIndex; + return m.mapStart[n >> kBlockSizeBits]->data[n & (kBlockSize - 1)]; +} + +template +typename vdfastdeque::const_reference vdfastdeque::operator[](size_type n) const { + n += mTails.startIndex; + return m.mapStart[n >> kBlockSizeBits]->data[n & (kBlockSize - 1)]; +} + +template +void vdfastdeque::clear() { + m.mapEnd = m.mapStart; + mTails.startIndex = 0; + mTails.endIndex = kBlockSize - 1; +} + +template +typename vdfastdeque::reference vdfastdeque::push_back() { + if (mTails.endIndex >= kBlockSize - 1) { + push_back_extend(); + + mTails.endIndex = -1; + } + + ++mTails.endIndex; + + VDASSERT(m.mapEnd[-1]); + reference r = m.mapEnd[-1]->data[mTails.endIndex]; + return r; +} + +template +void vdfastdeque::push_back(const_reference x) { + const T x2(x); + push_back() = x2; +} + +template +void vdfastdeque::pop_front() { + if (++mTails.startIndex >= kBlockSize) { + VDASSERT(m.mapEnd != m.mapStart); + mTails.startIndex = 0; + ++m.mapStart; + } +} + +template +void vdfastdeque::pop_back() { + if (--mTails.endIndex < 0) { + VDASSERT(m.mapEnd != m.mapStart); + mTails.endIndex = kBlockSize - 1; + --m.mapEnd; + } +} + +template +void vdfastdeque::swap(vdfastdeque& x) { + std::swap(m.mapStartAlloc, x.m.mapStartAlloc); + std::swap(m.mapStartCommit, x.m.mapStartCommit); + std::swap(m.mapStart, x.m.mapStart); + std::swap(m.mapEnd, x.m.mapEnd); + std::swap(m.mapEndCommit, x.m.mapEndCommit); + std::swap(m.mapEndAlloc, x.m.mapEndAlloc); + std::swap(mTails.startIndex, x.mTails.startIndex); + std::swap(mTails.endIndex, x.mTails.endIndex); +} + +///////////////////////////////// + +template +void vdfastdeque::push_back_extend() { + validate(); + + // check if we need to extend the map itself + if (m.mapEnd == m.mapEndAlloc) { + // can we just shift the map? + size_type currentMapSize = m.mapEndAlloc - m.mapStartAlloc; + size_type freeAtStart = m.mapStartCommit - m.mapStartAlloc; + + if (freeAtStart >= 2 && (freeAtStart + freeAtStart) >= currentMapSize) { + size_type shiftDistance = freeAtStart >> 1; + + VDASSERT(!m.mapStartAlloc[0]); + memmove(m.mapStartAlloc, m.mapStartAlloc + shiftDistance, sizeof(Block *) * (currentMapSize - shiftDistance)); + memset(m.mapStartAlloc + (currentMapSize - shiftDistance), 0, shiftDistance * sizeof(Block *)); + + // relocate pointers + m.mapEndCommit -= shiftDistance; + m.mapEnd -= shiftDistance; + m.mapStart -= shiftDistance; + m.mapStartCommit -= shiftDistance; + validate(); + } else { + size_type newMapSize = currentMapSize*2+1; + + Block **newMap = m.allocate(newMapSize); + + memcpy(newMap, m.mapStartAlloc, currentMapSize * sizeof(Block *)); + memset(newMap + currentMapSize, 0, (newMapSize - currentMapSize) * sizeof(Block *)); + + // relocate pointers + m.mapEndAlloc = newMap + newMapSize; + m.mapEndCommit = newMap + (m.mapEndCommit - m.mapStartAlloc); + m.mapEnd = newMap + (m.mapEnd - m.mapStartAlloc); + m.mapStart = newMap + (m.mapStart - m.mapStartAlloc); + m.mapStartCommit = newMap + (m.mapStartCommit - m.mapStartAlloc); + + m.deallocate(m.mapStartAlloc, currentMapSize); + m.mapStartAlloc = newMap; + validate(); + } + } + + VDASSERT(m.mapEnd != m.mapEndAlloc); + + // check if we already have a block we can use + if (*m.mapEnd) { + ++m.mapEnd; + validate(); + return; + } + + // check if we can steal a block from the beginning + if (m.mapStartCommit != m.mapStart) { + VDASSERT(*m.mapStartCommit); + if (m.mapStartCommit != m.mapEnd) { + *m.mapEnd = *m.mapStartCommit; + *m.mapStartCommit = NULL; + ++m.mapStartCommit; + } + ++m.mapEnd; + m.mapEndCommit = m.mapEnd; + validate(); + return; + } + + // allocate a new block + *m.mapEnd = mTails.allocate(1); + ++m.mapEnd; + m.mapEndCommit = m.mapEnd; + validate(); +} + +template +void vdfastdeque::validate() { + VDASSERT(m.mapStartAlloc <= m.mapStartCommit); + VDASSERT(m.mapStartCommit <= m.mapStart); + VDASSERT(m.mapStart <= m.mapEnd); + VDASSERT(m.mapEnd <= m.mapEndCommit); + VDASSERT(m.mapEndCommit <= m.mapEndAlloc); + + VDASSERT(m.mapStartAlloc == m.mapStartCommit || !*m.mapStartAlloc); + VDASSERT(m.mapStartCommit == m.mapEndCommit || m.mapStartCommit[0]); + VDASSERT(m.mapStart == m.mapEnd || (m.mapStart[0] && m.mapEnd[-1])); + VDASSERT(m.mapEndCommit == m.mapEndAlloc || !m.mapEndCommit[0]); +} + +#include +#include +#include + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hash.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hash.h index 1f18c7470ca..e7ad59dd54e 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hash.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hash.h @@ -1,140 +1,140 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_HASH_H -#define f_VD2_SYSTEM_VDSTL_HASH_H - -#include - -/////////////////////////////////////////////////////////////////////////////// -// vdhash -// -// Differences from TR1: -// -// - We omit the hash for long double, as that's not really useful, esp. on -// Windows. - -template struct vdhash; - -#define VDSTL_DECLARE_STANDARD_HASH(T) \ - template<> struct vdhash { \ - size_t operator()(T val) const { return (size_t)val; } \ - }; - -VDSTL_DECLARE_STANDARD_HASH(char); -VDSTL_DECLARE_STANDARD_HASH(signed char); -VDSTL_DECLARE_STANDARD_HASH(unsigned char); -VDSTL_DECLARE_STANDARD_HASH(wchar_t); -VDSTL_DECLARE_STANDARD_HASH(short); -VDSTL_DECLARE_STANDARD_HASH(unsigned short); -VDSTL_DECLARE_STANDARD_HASH(int); -VDSTL_DECLARE_STANDARD_HASH(unsigned int); -VDSTL_DECLARE_STANDARD_HASH(long); -VDSTL_DECLARE_STANDARD_HASH(unsigned long); -VDSTL_DECLARE_STANDARD_HASH(long long); -VDSTL_DECLARE_STANDARD_HASH(unsigned long long); - -template<> struct vdhash { - size_t operator()(float v) const { - const union { float f; sint32 i; } conv = {v}; - - uint32 i = conv.i; - - // Denormals and infinities are unique encodings and work as-is. NaNs work - // because they never compare equal to anything else, so their hash value - // can be arbitrary. Zero and negative zero, however, compare equal. - if (i == 0x80000000) - i = 0; - - return i; - } -}; - -template<> struct vdhash { - size_t operator()(double v) const { - const union conv { double f; sint64 i; } conv = {v}; - - uint64 i = conv.i; - - // Denormals and infinities are unique encodings and work as-is. NaNs work - // because they never compare equal to anything else, so their hash value - // can be arbitrary. Zero and negative zero, however, compare equal. - if (i == 0x8000000000000000ULL) - i = 0; - - if constexpr (sizeof(size_t) < 8) - return (size_t)((i >> 32) ^ i); - else - return (size_t)i; - } -}; - -#undef VDSTL_DECLARE_STANDARD_HASH - -class VDStringA; -class VDStringSpanA; -class VDStringW; -class VDStringSpanW; - -template<> struct vdhash { - size_t operator()(const VDStringA& s) const; - size_t operator()(const char *s) const; -}; - -template<> struct vdhash { - size_t operator()(const VDStringW& s) const; - size_t operator()(const wchar_t *s) const; -}; - -template struct vdhash { - size_t operator()(T *val) const { return (size_t)val; } -}; - -struct vdstringhashi { - size_t operator()(const VDStringA& s) const; - size_t operator()(const char *s) const; - size_t operator()(const VDStringW& s) const; - size_t operator()(const wchar_t *s) const; -}; - -struct vdstringpred { - bool operator()(const VDStringA& s, const VDStringA& t) const; - bool operator()(const VDStringA& s, const VDStringSpanA& t) const; - bool operator()(const VDStringA& s, const char *t) const; - bool operator()(const VDStringW& s, const VDStringW& t) const; - bool operator()(const VDStringW& s, const VDStringSpanW& t) const; - bool operator()(const VDStringW& s, const wchar_t *t) const; -}; - -struct vdstringpredi { - bool operator()(const VDStringA& s, const VDStringA& t) const; - bool operator()(const VDStringA& s, const VDStringSpanA& t) const; - bool operator()(const VDStringA& s, const char *t) const; - bool operator()(const VDStringW& s, const VDStringW& t) const; - bool operator()(const VDStringW& s, const VDStringSpanW& t) const; - bool operator()(const VDStringW& s, const wchar_t *t) const; -}; - -#endif // f_VD2_SYSTEM_VDSTL_HASH_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_HASH_H +#define f_VD2_SYSTEM_VDSTL_HASH_H + +#include + +/////////////////////////////////////////////////////////////////////////////// +// vdhash +// +// Differences from TR1: +// +// - We omit the hash for long double, as that's not really useful, esp. on +// Windows. + +template struct vdhash; + +#define VDSTL_DECLARE_STANDARD_HASH(T) \ + template<> struct vdhash { \ + size_t operator()(T val) const { return (size_t)val; } \ + }; + +VDSTL_DECLARE_STANDARD_HASH(char); +VDSTL_DECLARE_STANDARD_HASH(signed char); +VDSTL_DECLARE_STANDARD_HASH(unsigned char); +VDSTL_DECLARE_STANDARD_HASH(wchar_t); +VDSTL_DECLARE_STANDARD_HASH(short); +VDSTL_DECLARE_STANDARD_HASH(unsigned short); +VDSTL_DECLARE_STANDARD_HASH(int); +VDSTL_DECLARE_STANDARD_HASH(unsigned int); +VDSTL_DECLARE_STANDARD_HASH(long); +VDSTL_DECLARE_STANDARD_HASH(unsigned long); +VDSTL_DECLARE_STANDARD_HASH(long long); +VDSTL_DECLARE_STANDARD_HASH(unsigned long long); + +template<> struct vdhash { + size_t operator()(float v) const { + const union { float f; sint32 i; } conv = {v}; + + uint32 i = conv.i; + + // Denormals and infinities are unique encodings and work as-is. NaNs work + // because they never compare equal to anything else, so their hash value + // can be arbitrary. Zero and negative zero, however, compare equal. + if (i == 0x80000000) + i = 0; + + return i; + } +}; + +template<> struct vdhash { + size_t operator()(double v) const { + const union conv { double f; sint64 i; } conv = {v}; + + uint64 i = conv.i; + + // Denormals and infinities are unique encodings and work as-is. NaNs work + // because they never compare equal to anything else, so their hash value + // can be arbitrary. Zero and negative zero, however, compare equal. + if (i == 0x8000000000000000ULL) + i = 0; + + if constexpr (sizeof(size_t) < 8) + return (size_t)((i >> 32) ^ i); + else + return (size_t)i; + } +}; + +#undef VDSTL_DECLARE_STANDARD_HASH + +class VDStringA; +class VDStringSpanA; +class VDStringW; +class VDStringSpanW; + +template<> struct vdhash { + size_t operator()(const VDStringA& s) const; + size_t operator()(const char *s) const; +}; + +template<> struct vdhash { + size_t operator()(const VDStringW& s) const; + size_t operator()(const wchar_t *s) const; +}; + +template struct vdhash { + size_t operator()(T *val) const { return (size_t)val; } +}; + +struct vdstringhashi { + size_t operator()(const VDStringA& s) const; + size_t operator()(const char *s) const; + size_t operator()(const VDStringW& s) const; + size_t operator()(const wchar_t *s) const; +}; + +struct vdstringpred { + bool operator()(const VDStringA& s, const VDStringA& t) const; + bool operator()(const VDStringA& s, const VDStringSpanA& t) const; + bool operator()(const VDStringA& s, const char *t) const; + bool operator()(const VDStringW& s, const VDStringW& t) const; + bool operator()(const VDStringW& s, const VDStringSpanW& t) const; + bool operator()(const VDStringW& s, const wchar_t *t) const; +}; + +struct vdstringpredi { + bool operator()(const VDStringA& s, const VDStringA& t) const; + bool operator()(const VDStringA& s, const VDStringSpanA& t) const; + bool operator()(const VDStringA& s, const char *t) const; + bool operator()(const VDStringW& s, const VDStringW& t) const; + bool operator()(const VDStringW& s, const VDStringSpanW& t) const; + bool operator()(const VDStringW& s, const wchar_t *t) const; +}; + +#endif // f_VD2_SYSTEM_VDSTL_HASH_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashmap.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashmap.h index 6a7ae900c20..9bcf1c60fd2 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashmap.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashmap.h @@ -1,604 +1,604 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_HASHMAP_H -#define f_VD2_SYSTEM_VDSTL_HASHMAP_H - -#include -#include -#include - -template, class Pred = std::equal_to, class A = std::allocator > > > -class vdhashmap : public vdhashtable > { -protected: - using vdhashtable >::mpBucketStart; - using vdhashtable >::mpBucketEnd; - using vdhashtable >::mBucketCount; - using vdhashtable >::mElementCount; - using vdhashtable >::sEmptyBucket; - -public: - typedef typename vdhashtable >::node_type node_type; - typedef typename vdhashtable >::value_type value_type; - typedef typename vdhashtable >::size_type size_type; - typedef typename vdhashtable >::difference_type difference_type; - typedef typename vdhashtable >::pointer pointer; - typedef typename vdhashtable >::const_pointer const_pointer; - typedef typename vdhashtable >::reference reference; - typedef typename vdhashtable >::const_reference const_reference; - typedef typename vdhashtable >::iterator iterator; - typedef typename vdhashtable >::const_iterator const_iterator; - typedef typename vdhashtable >::local_iterator local_iterator; - typedef typename vdhashtable >::const_local_iterator const_local_iterator; - typedef K key_type; - typedef V mapped_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef A allocator_type; - typedef std::pair insert_return_type; - - vdhashmap(); - vdhashmap(const vdhashmap&); - ~vdhashmap(); - - vdhashmap& operator=(const vdhashmap&); - - mapped_type& operator[](const K& key); - - allocator_type get_allocator() const; - - // iterators - using vdhashtable::begin; - using vdhashtable::end; -// iterator begin(); Inherited. -// const_iterator begin() const; Inherited. -// iterator end(); Inherited. -// const_iterator end() const; Inherited. - - // modifiers - insert_return_type insert(const key_type& key); - insert_return_type insert(const std::pair& obj); -// iterator insert(iterator hint, const value_type& obj); // TODO -// const_iterator insert(const_iterator hint, const value_type& obj); // TODO - - template - insert_return_type insert_as(const U& k); // extension - - iterator erase(iterator position); - const_iterator erase(const_iterator position); - size_type erase(const key_type& k); -// iterator erase(iterator first, iterator last); // TODO -// const_iterator erase(const_iterator first, const_iterator last); // TODO - void clear(); - - // observers - hasher hash_function() const; - key_equal key_eq() const; - - // lookup - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; - size_type count(const key_type& k) const; - std::pair equal_range(const key_type& k); - std::pair equal_range(const key_type& k) const; - - // lookup (extensions) - template - iterator find_as(const U& k); - - template - const_iterator find_as(const U& k) const; - - // bucket interface -// size_type bucket_count() const; Inherited. -// size_type max_bucket_count() const; Inherited. -// size_type bucket_size(size_type n) const; Inherited. - size_type bucket(const key_type& k) const; - local_iterator begin(size_type n); - const_local_iterator begin(size_type n) const; - local_iterator end(size_type n); - const_local_iterator end(size_type n) const; - - // hash policy -// float load_factor() const; // TODO -// float max_load_factor() const; // TODO -// void max_load_factor(float z); // TODO - void rehash(size_type n); - -protected: - void rehash_to_size(size_type n); - void reset(); - - A mAllocator; - typename A::template rebind::other mBucketAllocator; - Hash mHasher; - Pred mPred; -}; - -template -vdhashmap::vdhashmap() { -} - -template -vdhashmap::vdhashmap(const vdhashmap& src) - : mHasher(src.mHasher) - , mPred(src.mPred) -{ - rehash_to_size(src.mElementCount); - - try { - for(vdhashtable_base_node **bucket = mpBucketStart; bucket != mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - insert(node->mData); - - p = next; - } - - *bucket = NULL; - } - } catch(...) { - reset(); - throw; - } -} - -template -vdhashmap::~vdhashmap() { - reset(); -} - -template -vdhashmap& vdhashmap::operator=(const vdhashmap& src) { - if (&src != this) { - clear(); - - mHasher = src.mHasher; - mPred = src.mPred; - - for(vdhashtable_base_node **bucket = src.mpBucketStart; bucket != src.mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - insert(node->mData); - - p = next; - } - - *bucket = NULL; - } - } - - return *this; -} - -template -typename vdhashmap::mapped_type& vdhashmap::operator[](const K& key) { - return insert(key).first->second; -} - -template -typename vdhashmap::allocator_type vdhashmap::get_allocator() const { - return A(); -} - -// modifiers -template -typename vdhashmap::insert_return_type vdhashmap::insert(const key_type& key) { - if (mElementCount >= mBucketCount) - rehash_to_size(mElementCount + 1); - - size_type bucket = mHasher(key) % mBucketCount; - - for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { - if (mPred(p->mData.first, key)) - return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); - } - - node_type *node = mAllocator.allocate(1); - try { - new(node) node_type(static_cast(mpBucketStart[bucket]), value_type(key, V())); - } catch(...) { - mAllocator.deallocate(node, 1); - throw; - } - - mpBucketStart[bucket] = node; - ++mElementCount; - - return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); -} - -template -typename vdhashmap::insert_return_type vdhashmap::insert(const std::pair& obj) { - if (mElementCount >= mBucketCount) - rehash_to_size(mElementCount + 1); - - size_type bucket = mHasher(obj.first) % mBucketCount; - - for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { - if (mPred(p->mData.first, obj.first)) - return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); - } - - node_type *node = mAllocator.allocate(1); - try { - new(node) node_type(static_cast(mpBucketStart[bucket]), obj); - } catch(...) { - mAllocator.deallocate(node, 1); - throw; - } - - mpBucketStart[bucket] = node; - ++mElementCount; - - return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); -} - -template -template -typename vdhashmap::insert_return_type vdhashmap::insert_as(const U& key) { - if (mElementCount >= mBucketCount) - rehash_to_size(mElementCount + 1); - - size_type bucket = mHasher(key) % mBucketCount; - - for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { - if (mPred(p->mData.first, key)) - return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); - } - - node_type *node = mAllocator.allocate(1); - try { - new(node) node_type(static_cast(mpBucketStart[bucket])); - - try { - node->mData.first = key; - } catch(...) { - node->~node_type(); - } - - } catch(...) { - mAllocator.deallocate(node, 1); - throw; - } - - mpBucketStart[bucket] = node; - ++mElementCount; - - return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); -} - -template -typename vdhashmap::iterator vdhashmap::erase(iterator position) { - size_type bucket = mHasher(position->first) % mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = mpBucketStart[bucket]; - - while(&static_cast(p)->mData != &*position) { - prev = p; - p = p->mpHashNext; - } - - vdhashtable_base_node *next = p->mpHashNext; - if (prev) - prev->mpHashNext = next; - else - mpBucketStart[bucket] = next; - - node_type *node = static_cast(p); - node->~node_type(); - mAllocator.deallocate(node, 1); - --mElementCount; - - return iterator(next, &mpBucketStart[bucket], mpBucketEnd); -} - -template -typename vdhashmap::const_iterator vdhashmap::erase(const_iterator position) { - size_type bucket = mHasher(position->first) % mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = mpBucketStart[bucket]; - - while(&static_cast(p)->mData != &*position) { - prev = p; - p = p->mpHashNext; - } - - vdhashtable_base_node *next = p->mpHashNext; - if (prev) - prev->mpHashNext = next; - else - mpBucketStart[bucket] = next; - - node_type *node = static_cast(p); - node->~node_type(); - mAllocator.deallocate(node, 1); - --mElementCount; - - return const_iterator(next, &mpBucketStart[bucket], mpBucketEnd); -} - -template -typename vdhashmap::size_type vdhashmap::erase(const key_type& k) { - if (!mBucketCount) - return 0; - - size_type bucket = mHasher(k) % mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = mpBucketStart[bucket]; - - while(p) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) { - vdhashtable_base_node *next = p->mpHashNext; - - if (prev) - prev->mpHashNext = next; - else - mpBucketStart[bucket] = next; - - node->~node_type(); - mAllocator.deallocate(node, 1); - --mElementCount; - return 1; - } - - prev = p; - p = p->mpHashNext; - } - - return 0; -} - -template -void vdhashmap::clear() { - for(vdhashtable_base_node **bucket = mpBucketStart; bucket != mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - node->~node_type(); - - mAllocator.deallocate(node, 1); - - p = next; - } - - *bucket = NULL; - } - - mElementCount = 0; -} - -// observers -template -typename vdhashmap::hasher vdhashmap::hash_function() const { - return mHasher; -} - -template -typename vdhashmap::key_equal vdhashmap::key_eq() const { - return mPred; -} - -// lookup -template -typename vdhashmap::iterator vdhashmap::find(const key_type& k) { - if (!mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % mBucketCount; - - for(vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return iterator(node, &mpBucketStart[bucket], mpBucketEnd); - } - - return iterator(); -} - -template -typename vdhashmap::const_iterator vdhashmap::find(const key_type& k) const { - if (!mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % mBucketCount; - - for(const vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { - const node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return const_iterator(const_cast(static_cast(node)), &mpBucketStart[bucket], mpBucketEnd); - } - - return iterator(); -} - -template -typename vdhashmap::size_type vdhashmap::count(const key_type& k) const { - return find(k) != end() ? 1 : 0; -} - -template -std::pair::iterator, typename vdhashmap::iterator> vdhashmap::equal_range(const key_type& k) { - iterator it = find(k); - iterator itEnd; - - if (it == itEnd) - return std::make_pair(itEnd, itEnd); - - itEnd = it; - ++itEnd; - - return std::make_pair(); -} - -template -std::pair::const_iterator, typename vdhashmap::const_iterator> vdhashmap::equal_range(const key_type& k) const { - const_iterator it = find(k); - const_iterator itEnd; - - if (it == itEnd) - return std::make_pair(itEnd, itEnd); - - itEnd = it; - ++itEnd; - - return std::make_pair(it, itEnd); -} - -template -template -typename vdhashmap::iterator vdhashmap::find_as(const U& k) { - if (!mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % mBucketCount; - - for(vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return iterator(node, &mpBucketStart[bucket], mpBucketEnd); - } - - return iterator(); -} - -template -template -typename vdhashmap::const_iterator vdhashmap::find_as(const U& k) const { - if (!mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % mBucketCount; - - for(const vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { - const node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return const_iterator(const_cast(static_cast(node)), &mpBucketStart[bucket], mpBucketEnd); - } - - return iterator(); -} - -// bucket interface -template -typename vdhashmap::size_type vdhashmap::bucket(const key_type& k) const { - size_type bucket = 0; - - if (mBucketCount) - bucket = mHasher(k) % mBucketCount; - - return bucket; -} - -template -typename vdhashmap::local_iterator vdhashmap::begin(size_type n) { - return local_iterator(mpBucketStart[n]); -} - -template -typename vdhashmap::const_local_iterator vdhashmap::begin(size_type n) const { - return const_local_iterator(mpBucketStart[n]); -} - -template -typename vdhashmap::local_iterator vdhashmap::end(size_type n) { - return local_iterator(NULL); -} - -template -typename vdhashmap::const_local_iterator vdhashmap::end(size_type n) const { - return const_local_iterator(NULL); -} - -// hash policy -template -void vdhashmap::rehash(size_type n) { - if (!n) - n = 1; - - if (mBucketCount == n) - return; - - vdhashtable_base_node **newBuckets = mBucketAllocator.allocate(n + 1); - - for(size_type i=0; i<=n; ++i) - newBuckets[i] = NULL; - - const size_type m = mBucketCount; - for(size_type i=0; impHashNext; - const value_type& vt = static_cast *>(p)->mData; - size_t bucket = mHasher(vt.first) % n; - - vdhashtable_base_node *head = newBuckets[bucket]; - - p->mpHashNext = head; - newBuckets[bucket] = p; - - p = next; - } - } - - if (mpBucketStart != &sEmptyBucket) - mBucketAllocator.deallocate(mpBucketStart, (mpBucketEnd - mpBucketStart) + 1); - - mpBucketStart = newBuckets; - mpBucketEnd = newBuckets + n; - mBucketCount = n; -} - -template -void vdhashmap::rehash_to_size(size_type n) { - size_type buckets = vdhashtable_base::compute_bucket_count(n); - rehash(buckets); -} - -template -void vdhashmap::reset() { - clear(); - - if (mpBucketStart != &sEmptyBucket) - mBucketAllocator.deallocate(mpBucketStart, (mpBucketEnd - mpBucketStart) + 1); -} - -#endif // f_VD2_SYSTEM_VDSTL_HASHMAP_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_HASHMAP_H +#define f_VD2_SYSTEM_VDSTL_HASHMAP_H + +#include +#include +#include + +template, class Pred = std::equal_to, class A = std::allocator > > > +class vdhashmap : public vdhashtable > { +protected: + using vdhashtable >::mpBucketStart; + using vdhashtable >::mpBucketEnd; + using vdhashtable >::mBucketCount; + using vdhashtable >::mElementCount; + using vdhashtable >::sEmptyBucket; + +public: + typedef typename vdhashtable >::node_type node_type; + typedef typename vdhashtable >::value_type value_type; + typedef typename vdhashtable >::size_type size_type; + typedef typename vdhashtable >::difference_type difference_type; + typedef typename vdhashtable >::pointer pointer; + typedef typename vdhashtable >::const_pointer const_pointer; + typedef typename vdhashtable >::reference reference; + typedef typename vdhashtable >::const_reference const_reference; + typedef typename vdhashtable >::iterator iterator; + typedef typename vdhashtable >::const_iterator const_iterator; + typedef typename vdhashtable >::local_iterator local_iterator; + typedef typename vdhashtable >::const_local_iterator const_local_iterator; + typedef K key_type; + typedef V mapped_type; + typedef Hash hasher; + typedef Pred key_equal; + typedef A allocator_type; + typedef std::pair insert_return_type; + + vdhashmap(); + vdhashmap(const vdhashmap&); + ~vdhashmap(); + + vdhashmap& operator=(const vdhashmap&); + + mapped_type& operator[](const K& key); + + allocator_type get_allocator() const; + + // iterators + using vdhashtable::begin; + using vdhashtable::end; +// iterator begin(); Inherited. +// const_iterator begin() const; Inherited. +// iterator end(); Inherited. +// const_iterator end() const; Inherited. + + // modifiers + insert_return_type insert(const key_type& key); + insert_return_type insert(const std::pair& obj); +// iterator insert(iterator hint, const value_type& obj); // TODO +// const_iterator insert(const_iterator hint, const value_type& obj); // TODO + + template + insert_return_type insert_as(const U& k); // extension + + iterator erase(iterator position); + const_iterator erase(const_iterator position); + size_type erase(const key_type& k); +// iterator erase(iterator first, iterator last); // TODO +// const_iterator erase(const_iterator first, const_iterator last); // TODO + void clear(); + + // observers + hasher hash_function() const; + key_equal key_eq() const; + + // lookup + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + size_type count(const key_type& k) const; + std::pair equal_range(const key_type& k); + std::pair equal_range(const key_type& k) const; + + // lookup (extensions) + template + iterator find_as(const U& k); + + template + const_iterator find_as(const U& k) const; + + // bucket interface +// size_type bucket_count() const; Inherited. +// size_type max_bucket_count() const; Inherited. +// size_type bucket_size(size_type n) const; Inherited. + size_type bucket(const key_type& k) const; + local_iterator begin(size_type n); + const_local_iterator begin(size_type n) const; + local_iterator end(size_type n); + const_local_iterator end(size_type n) const; + + // hash policy +// float load_factor() const; // TODO +// float max_load_factor() const; // TODO +// void max_load_factor(float z); // TODO + void rehash(size_type n); + +protected: + void rehash_to_size(size_type n); + void reset(); + + A mAllocator; + typename A::template rebind::other mBucketAllocator; + Hash mHasher; + Pred mPred; +}; + +template +vdhashmap::vdhashmap() { +} + +template +vdhashmap::vdhashmap(const vdhashmap& src) + : mHasher(src.mHasher) + , mPred(src.mPred) +{ + rehash_to_size(src.mElementCount); + + try { + for(vdhashtable_base_node **bucket = mpBucketStart; bucket != mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + insert(node->mData); + + p = next; + } + + *bucket = NULL; + } + } catch(...) { + reset(); + throw; + } +} + +template +vdhashmap::~vdhashmap() { + reset(); +} + +template +vdhashmap& vdhashmap::operator=(const vdhashmap& src) { + if (&src != this) { + clear(); + + mHasher = src.mHasher; + mPred = src.mPred; + + for(vdhashtable_base_node **bucket = src.mpBucketStart; bucket != src.mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + insert(node->mData); + + p = next; + } + + *bucket = NULL; + } + } + + return *this; +} + +template +typename vdhashmap::mapped_type& vdhashmap::operator[](const K& key) { + return insert(key).first->second; +} + +template +typename vdhashmap::allocator_type vdhashmap::get_allocator() const { + return A(); +} + +// modifiers +template +typename vdhashmap::insert_return_type vdhashmap::insert(const key_type& key) { + if (mElementCount >= mBucketCount) + rehash_to_size(mElementCount + 1); + + size_type bucket = mHasher(key) % mBucketCount; + + for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { + if (mPred(p->mData.first, key)) + return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); + } + + node_type *node = mAllocator.allocate(1); + try { + new(node) node_type(static_cast(mpBucketStart[bucket]), value_type(key, V())); + } catch(...) { + mAllocator.deallocate(node, 1); + throw; + } + + mpBucketStart[bucket] = node; + ++mElementCount; + + return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); +} + +template +typename vdhashmap::insert_return_type vdhashmap::insert(const std::pair& obj) { + if (mElementCount >= mBucketCount) + rehash_to_size(mElementCount + 1); + + size_type bucket = mHasher(obj.first) % mBucketCount; + + for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { + if (mPred(p->mData.first, obj.first)) + return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); + } + + node_type *node = mAllocator.allocate(1); + try { + new(node) node_type(static_cast(mpBucketStart[bucket]), obj); + } catch(...) { + mAllocator.deallocate(node, 1); + throw; + } + + mpBucketStart[bucket] = node; + ++mElementCount; + + return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); +} + +template +template +typename vdhashmap::insert_return_type vdhashmap::insert_as(const U& key) { + if (mElementCount >= mBucketCount) + rehash_to_size(mElementCount + 1); + + size_type bucket = mHasher(key) % mBucketCount; + + for(node_type *p = static_cast(mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { + if (mPred(p->mData.first, key)) + return std::pair(iterator(p, &mpBucketStart[bucket], mpBucketEnd), false); + } + + node_type *node = mAllocator.allocate(1); + try { + new(node) node_type(static_cast(mpBucketStart[bucket])); + + try { + node->mData.first = key; + } catch(...) { + node->~node_type(); + } + + } catch(...) { + mAllocator.deallocate(node, 1); + throw; + } + + mpBucketStart[bucket] = node; + ++mElementCount; + + return std::pair(iterator(node, &mpBucketStart[bucket], mpBucketEnd), true); +} + +template +typename vdhashmap::iterator vdhashmap::erase(iterator position) { + size_type bucket = mHasher(position->first) % mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = mpBucketStart[bucket]; + + while(&static_cast(p)->mData != &*position) { + prev = p; + p = p->mpHashNext; + } + + vdhashtable_base_node *next = p->mpHashNext; + if (prev) + prev->mpHashNext = next; + else + mpBucketStart[bucket] = next; + + node_type *node = static_cast(p); + node->~node_type(); + mAllocator.deallocate(node, 1); + --mElementCount; + + return iterator(next, &mpBucketStart[bucket], mpBucketEnd); +} + +template +typename vdhashmap::const_iterator vdhashmap::erase(const_iterator position) { + size_type bucket = mHasher(position->first) % mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = mpBucketStart[bucket]; + + while(&static_cast(p)->mData != &*position) { + prev = p; + p = p->mpHashNext; + } + + vdhashtable_base_node *next = p->mpHashNext; + if (prev) + prev->mpHashNext = next; + else + mpBucketStart[bucket] = next; + + node_type *node = static_cast(p); + node->~node_type(); + mAllocator.deallocate(node, 1); + --mElementCount; + + return const_iterator(next, &mpBucketStart[bucket], mpBucketEnd); +} + +template +typename vdhashmap::size_type vdhashmap::erase(const key_type& k) { + if (!mBucketCount) + return 0; + + size_type bucket = mHasher(k) % mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = mpBucketStart[bucket]; + + while(p) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) { + vdhashtable_base_node *next = p->mpHashNext; + + if (prev) + prev->mpHashNext = next; + else + mpBucketStart[bucket] = next; + + node->~node_type(); + mAllocator.deallocate(node, 1); + --mElementCount; + return 1; + } + + prev = p; + p = p->mpHashNext; + } + + return 0; +} + +template +void vdhashmap::clear() { + for(vdhashtable_base_node **bucket = mpBucketStart; bucket != mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + node->~node_type(); + + mAllocator.deallocate(node, 1); + + p = next; + } + + *bucket = NULL; + } + + mElementCount = 0; +} + +// observers +template +typename vdhashmap::hasher vdhashmap::hash_function() const { + return mHasher; +} + +template +typename vdhashmap::key_equal vdhashmap::key_eq() const { + return mPred; +} + +// lookup +template +typename vdhashmap::iterator vdhashmap::find(const key_type& k) { + if (!mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % mBucketCount; + + for(vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return iterator(node, &mpBucketStart[bucket], mpBucketEnd); + } + + return iterator(); +} + +template +typename vdhashmap::const_iterator vdhashmap::find(const key_type& k) const { + if (!mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % mBucketCount; + + for(const vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { + const node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return const_iterator(const_cast(static_cast(node)), &mpBucketStart[bucket], mpBucketEnd); + } + + return iterator(); +} + +template +typename vdhashmap::size_type vdhashmap::count(const key_type& k) const { + return find(k) != end() ? 1 : 0; +} + +template +std::pair::iterator, typename vdhashmap::iterator> vdhashmap::equal_range(const key_type& k) { + iterator it = find(k); + iterator itEnd; + + if (it == itEnd) + return std::make_pair(itEnd, itEnd); + + itEnd = it; + ++itEnd; + + return std::make_pair(); +} + +template +std::pair::const_iterator, typename vdhashmap::const_iterator> vdhashmap::equal_range(const key_type& k) const { + const_iterator it = find(k); + const_iterator itEnd; + + if (it == itEnd) + return std::make_pair(itEnd, itEnd); + + itEnd = it; + ++itEnd; + + return std::make_pair(it, itEnd); +} + +template +template +typename vdhashmap::iterator vdhashmap::find_as(const U& k) { + if (!mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % mBucketCount; + + for(vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return iterator(node, &mpBucketStart[bucket], mpBucketEnd); + } + + return iterator(); +} + +template +template +typename vdhashmap::const_iterator vdhashmap::find_as(const U& k) const { + if (!mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % mBucketCount; + + for(const vdhashtable_base_node *p = mpBucketStart[bucket]; p; p = p->mpHashNext) { + const node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return const_iterator(const_cast(static_cast(node)), &mpBucketStart[bucket], mpBucketEnd); + } + + return iterator(); +} + +// bucket interface +template +typename vdhashmap::size_type vdhashmap::bucket(const key_type& k) const { + size_type bucket = 0; + + if (mBucketCount) + bucket = mHasher(k) % mBucketCount; + + return bucket; +} + +template +typename vdhashmap::local_iterator vdhashmap::begin(size_type n) { + return local_iterator(mpBucketStart[n]); +} + +template +typename vdhashmap::const_local_iterator vdhashmap::begin(size_type n) const { + return const_local_iterator(mpBucketStart[n]); +} + +template +typename vdhashmap::local_iterator vdhashmap::end(size_type n) { + return local_iterator(NULL); +} + +template +typename vdhashmap::const_local_iterator vdhashmap::end(size_type n) const { + return const_local_iterator(NULL); +} + +// hash policy +template +void vdhashmap::rehash(size_type n) { + if (!n) + n = 1; + + if (mBucketCount == n) + return; + + vdhashtable_base_node **newBuckets = mBucketAllocator.allocate(n + 1); + + for(size_type i=0; i<=n; ++i) + newBuckets[i] = NULL; + + const size_type m = mBucketCount; + for(size_type i=0; impHashNext; + const value_type& vt = static_cast *>(p)->mData; + size_t bucket = mHasher(vt.first) % n; + + vdhashtable_base_node *head = newBuckets[bucket]; + + p->mpHashNext = head; + newBuckets[bucket] = p; + + p = next; + } + } + + if (mpBucketStart != &sEmptyBucket) + mBucketAllocator.deallocate(mpBucketStart, (mpBucketEnd - mpBucketStart) + 1); + + mpBucketStart = newBuckets; + mpBucketEnd = newBuckets + n; + mBucketCount = n; +} + +template +void vdhashmap::rehash_to_size(size_type n) { + size_type buckets = vdhashtable_base::compute_bucket_count(n); + rehash(buckets); +} + +template +void vdhashmap::reset() { + clear(); + + if (mpBucketStart != &sEmptyBucket) + mBucketAllocator.deallocate(mpBucketStart, (mpBucketEnd - mpBucketStart) + 1); +} + +#endif // f_VD2_SYSTEM_VDSTL_HASHMAP_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashset.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashset.h index 31d5fe8485e..81f4ef7e31f 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashset.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashset.h @@ -1,526 +1,526 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_HASHSET_H -#define f_VD2_SYSTEM_VDSTL_HASHSET_H - -#include -#include -#include - -template, class Pred = std::equal_to, class A = std::allocator > > -class vdhashset : public vdhashtable { -public: - typedef typename vdhashtable::node_type node_type; - typedef typename vdhashtable::value_type value_type; - typedef typename vdhashtable::size_type size_type; - typedef typename vdhashtable::difference_type difference_type; - typedef typename vdhashtable::pointer pointer; - typedef typename vdhashtable::const_pointer const_pointer; - typedef typename vdhashtable::reference reference; - typedef typename vdhashtable::const_reference const_reference; - typedef typename vdhashtable::iterator iterator; - typedef typename vdhashtable::const_iterator const_iterator; - typedef typename vdhashtable::local_iterator local_iterator; - typedef typename vdhashtable::const_local_iterator const_local_iterator; - - typedef K key_type; - typedef Hash hasher; - typedef Pred key_equal; - typedef A allocator_type; - typedef std::pair insert_return_type; - - vdhashset(); - vdhashset(const vdhashset&); - ~vdhashset(); - - vdhashset& operator=(const vdhashset&); - - allocator_type get_allocator() const; - - // iterators - using vdhashtable::begin; - using vdhashtable::end; -// iterator begin(); Inherited. -// const_iterator begin() const; Inherited. -// iterator end(); Inherited. -// const_iterator end() const; Inherited. - - // modifiers - insert_return_type insert(const key_type& key); -// iterator insert(iterator hint, const value_type& obj); // TODO -// const_iterator insert(const_iterator hint, const value_type& obj); // TODO - - iterator erase(iterator position); - const_iterator erase(const_iterator position); - size_type erase(const key_type& k); -// iterator erase(iterator first, iterator last); // TODO -// const_iterator erase(const_iterator first, const_iterator last); // TODO - void clear(); - - // observers - hasher hash_function() const; - key_equal key_eq() const; - - // lookup - iterator find(const key_type& k); - const_iterator find(const key_type& k) const; - size_type count(const key_type& k) const; - std::pair equal_range(const key_type& k); - std::pair equal_range(const key_type& k) const; - - // lookup (extensions) - template - iterator find_as(const U& k); - - template - const_iterator find_as(const U& k) const; - - // bucket interface -// size_type bucket_count() const; Inherited. -// size_type max_bucket_count() const; Inherited. -// size_type bucket_size(size_type n) const; Inherited. - size_type bucket(const key_type& k) const; - local_iterator begin(size_type n); - const_local_iterator begin(size_type n) const; - local_iterator end(size_type n); - const_local_iterator end(size_type n) const; - - // hash policy -// float load_factor() const; // TODO -// float max_load_factor() const; // TODO -// void max_load_factor(float z); // TODO - void rehash(size_type n); - -protected: - void rehash_to_size(size_type n); - void reset(); - - A mAllocator; - typename A::template rebind::other mBucketAllocator; - Hash mHasher; - Pred mPred; -}; - -template -vdhashset::vdhashset() { -} - -template -vdhashset::vdhashset(const vdhashset& src) - : mHasher(src.mHasher) - , mPred(src.mPred) -{ - rehash_to_size(src.mElementCount); - - try { - for(vdhashtable_base_node **bucket = this->mpBucketStart; bucket != this->mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - insert(node->mData); - - p = next; - } - - *bucket = NULL; - } - } catch(...) { - reset(); - throw; - } -} - -template -vdhashset::~vdhashset() { - reset(); -} - -template -vdhashset& vdhashset::operator=(const vdhashset& src) { - if (&src != this) { - clear(); - - mHasher = src.mHasher; - mPred = src.mPred; - - for(vdhashtable_base_node **bucket = src.mpBucketStart; bucket != src.mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - insert(node->mData); - - p = next; - } - - *bucket = NULL; - } - } - - return *this; -} - -template -typename vdhashset::allocator_type vdhashset::get_allocator() const { - return A(); -} - -// modifiers -template -typename vdhashset::insert_return_type vdhashset::insert(const key_type& key) { - if (this->mElementCount >= this->mBucketCount) - rehash_to_size(this->mElementCount + 1); - - size_type bucket = mHasher(key) % this->mBucketCount; - - for(node_type *p = static_cast(this->mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { - if (mPred(p->mData, key)) - return std::pair(iterator(p, &this->mpBucketStart[bucket], this->mpBucketEnd), false); - } - - node_type *node = mAllocator.allocate(1); - try { - new(node) node_type(static_cast(this->mpBucketStart[bucket]), key); - } catch(...) { - mAllocator.deallocate(node, 1); - throw; - } - - this->mpBucketStart[bucket] = node; - ++this->mElementCount; - - return std::pair(iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd), true); -} - -template -typename vdhashset::iterator vdhashset::erase(iterator position) { - size_type bucket = mHasher(position->first) % this->mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = this->mpBucketStart[bucket]; - - while(&static_cast(p)->mData != &*position) { - prev = p; - p = p->mpHashNext; - } - - vdhashtable_base_node *next = p->mpHashNext; - if (prev) - prev->mpHashNext = next; - else - this->mpBucketStart[bucket] = next; - - node_type *node = static_cast(p); - node->~node_type(); - mAllocator.deallocate(node, 1); - --this->mElementCount; - - return iterator(next, &this->mpBucketStart[bucket], this->mpBucketEnd); -} - -template -typename vdhashset::const_iterator vdhashset::erase(const_iterator position) { - size_type bucket = mHasher(position->first) % this->mBucketCount; - const vdhashtable_base_node *prev = NULL; - const vdhashtable_base_node *p = this->mpBucketStart[bucket]; - - while(&static_cast(p)->mData != &*position) { - prev = p; - p = p->mpHashNext; - } - - const vdhashtable_base_node *next = p->mpHashNext; - if (prev) - prev->mpHashNext = next; - else - this->mpBucketStart[bucket] = next; - - node_type *node = static_cast(p); - node->~node_type(); - mAllocator.deallocate(node, 1); - --this->mElementCount; - - return const_iterator(next, &this->mpBucketStart[bucket], this->mpBucketEnd); -} - -template -typename vdhashset::size_type vdhashset::erase(const key_type& k) { - if (!this->mBucketCount) - return 0; - - size_type bucket = mHasher(k) % this->mBucketCount; - vdhashtable_base_node *prev = NULL; - vdhashtable_base_node *p = this->mpBucketStart[bucket]; - - while(p) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) { - vdhashtable_base_node *next = p->mpHashNext; - - if (prev) - prev->mpHashNext = next; - else - this->mpBucketStart[bucket] = next; - - node->~node_type(); - mAllocator.deallocate(node, 1); - --this->mElementCount; - return 1; - } - - prev = p; - p = p->mpHashNext; - } - - return 0; -} - -template -void vdhashset::clear() { - for(vdhashtable_base_node **bucket = this->mpBucketStart; bucket != this->mpBucketEnd; ++bucket) { - vdhashtable_base_node *p = *bucket; - - while(p) { - vdhashtable_base_node *next = p->mpHashNext; - node_type *node = static_cast(p); - - node->~node_type(); - - mAllocator.deallocate(node, 1); - - p = next; - } - - *bucket = NULL; - } - - this->mElementCount = 0; -} - -// observers -template -typename vdhashset::hasher vdhashset::hash_function() const { - return mHasher; -} - -template -typename vdhashset::key_equal vdhashset::key_eq() const { - return mPred; -} - -// lookup -template -typename vdhashset::iterator vdhashset::find(const key_type& k) { - if (!this->mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % this->mBucketCount; - - for(vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd); - } - - return iterator(); -} - -template -typename vdhashset::const_iterator vdhashset::find(const key_type& k) const { - if (!this->mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % this->mBucketCount; - - for(const vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { - const node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return const_iterator(const_cast(static_cast(node)), &this->mpBucketStart[bucket], this->mpBucketEnd); - } - - return iterator(); -} - -template -typename vdhashset::size_type vdhashset::count(const key_type& k) const { - return find(k) != end() ? 1 : 0; -} - -template -std::pair::iterator, typename vdhashset::iterator> vdhashset::equal_range(const key_type& k) { - iterator it = find(k); - iterator itEnd; - - if (it == itEnd) - return std::make_pair(itEnd, itEnd); - - itEnd = it; - ++itEnd; - - return std::make_pair(it, itEnd); -} - -template -std::pair::const_iterator, typename vdhashset::const_iterator> vdhashset::equal_range(const key_type& k) const { - const_iterator it = find(k); - const_iterator itEnd; - - if (it == itEnd) - return std::make_pair(itEnd, itEnd); - - itEnd = it; - ++itEnd; - - return std::make_pair(it, itEnd); -} - -template -template -typename vdhashset::iterator vdhashset::find_as(const U& k) { - if (!this->mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % this->mBucketCount; - - for(vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { - node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd); - } - - return iterator(); -} - -template -template -typename vdhashset::const_iterator vdhashset::find_as(const U& k) const { - if (!this->mBucketCount) - return iterator(); - - size_type bucket = mHasher(k) % this->mBucketCount; - - for(const vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { - const node_type *node = static_cast(p); - - if (mPred(node->mData.first, k)) - return const_iterator(const_cast(static_cast(node)), &this->mpBucketStart[bucket], this->mpBucketEnd); - } - - return iterator(); -} - -// bucket interface -template -typename vdhashset::size_type vdhashset::bucket(const key_type& k) const { - size_type bucket = 0; - - if (this->mBucketCount) - bucket = mHasher(k) % this->mBucketCount; - - return bucket; -} - -template -typename vdhashset::local_iterator vdhashset::begin(size_type n) { - return local_iterator(this->mpBucketStart[n]); -} - -template -typename vdhashset::const_local_iterator vdhashset::begin(size_type n) const { - return const_local_iterator(this->mpBucketStart[n]); -} - -template -typename vdhashset::local_iterator vdhashset::end(size_type n) { - return local_iterator(NULL); -} - -template -typename vdhashset::const_local_iterator vdhashset::end(size_type n) const { - return const_local_iterator(NULL); -} - -// hash policy -template -void vdhashset::rehash(size_type n) { - if (!n) - n = 1; - - if (this->mBucketCount == n) - return; - - vdhashtable_base_node **newBuckets = mBucketAllocator.allocate(n + 1); - - for(size_type i=0; i<=n; ++i) - newBuckets[i] = NULL; - - const size_type m = this->mBucketCount; - for(size_type i=0; impBucketStart[i]; p;) { - vdhashtable_base_node *next = p->mpHashNext; - const value_type& vt = static_cast *>(p)->mData; - size_t bucket = mHasher(vt) % n; - - vdhashtable_base_node *head = newBuckets[bucket]; - - p->mpHashNext = head; - newBuckets[bucket] = p; - - p = next; - } - } - - if (this->mpBucketStart != &vdhashtable::sEmptyBucket) - mBucketAllocator.deallocate(this->mpBucketStart, (this->mpBucketEnd - this->mpBucketStart) + 1); - - this->mpBucketStart = newBuckets; - this->mpBucketEnd = newBuckets + n; - this->mBucketCount = n; -} - -template -void vdhashset::rehash_to_size(size_type n) { - size_type buckets = compute_bucket_count(n); - rehash(buckets); -} - -template -void vdhashset::reset() { - clear(); - - if (this->mpBucketStart != &vdhashtable::sEmptyBucket) - mBucketAllocator.deallocate(this->mpBucketStart, (this->mpBucketEnd - this->mpBucketStart) + 1); -} - -#endif // f_VD2_SYSTEM_VDSTL_HASHSET_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_HASHSET_H +#define f_VD2_SYSTEM_VDSTL_HASHSET_H + +#include +#include +#include + +template, class Pred = std::equal_to, class A = std::allocator > > +class vdhashset : public vdhashtable { +public: + typedef typename vdhashtable::node_type node_type; + typedef typename vdhashtable::value_type value_type; + typedef typename vdhashtable::size_type size_type; + typedef typename vdhashtable::difference_type difference_type; + typedef typename vdhashtable::pointer pointer; + typedef typename vdhashtable::const_pointer const_pointer; + typedef typename vdhashtable::reference reference; + typedef typename vdhashtable::const_reference const_reference; + typedef typename vdhashtable::iterator iterator; + typedef typename vdhashtable::const_iterator const_iterator; + typedef typename vdhashtable::local_iterator local_iterator; + typedef typename vdhashtable::const_local_iterator const_local_iterator; + + typedef K key_type; + typedef Hash hasher; + typedef Pred key_equal; + typedef A allocator_type; + typedef std::pair insert_return_type; + + vdhashset(); + vdhashset(const vdhashset&); + ~vdhashset(); + + vdhashset& operator=(const vdhashset&); + + allocator_type get_allocator() const; + + // iterators + using vdhashtable::begin; + using vdhashtable::end; +// iterator begin(); Inherited. +// const_iterator begin() const; Inherited. +// iterator end(); Inherited. +// const_iterator end() const; Inherited. + + // modifiers + insert_return_type insert(const key_type& key); +// iterator insert(iterator hint, const value_type& obj); // TODO +// const_iterator insert(const_iterator hint, const value_type& obj); // TODO + + iterator erase(iterator position); + const_iterator erase(const_iterator position); + size_type erase(const key_type& k); +// iterator erase(iterator first, iterator last); // TODO +// const_iterator erase(const_iterator first, const_iterator last); // TODO + void clear(); + + // observers + hasher hash_function() const; + key_equal key_eq() const; + + // lookup + iterator find(const key_type& k); + const_iterator find(const key_type& k) const; + size_type count(const key_type& k) const; + std::pair equal_range(const key_type& k); + std::pair equal_range(const key_type& k) const; + + // lookup (extensions) + template + iterator find_as(const U& k); + + template + const_iterator find_as(const U& k) const; + + // bucket interface +// size_type bucket_count() const; Inherited. +// size_type max_bucket_count() const; Inherited. +// size_type bucket_size(size_type n) const; Inherited. + size_type bucket(const key_type& k) const; + local_iterator begin(size_type n); + const_local_iterator begin(size_type n) const; + local_iterator end(size_type n); + const_local_iterator end(size_type n) const; + + // hash policy +// float load_factor() const; // TODO +// float max_load_factor() const; // TODO +// void max_load_factor(float z); // TODO + void rehash(size_type n); + +protected: + void rehash_to_size(size_type n); + void reset(); + + A mAllocator; + typename A::template rebind::other mBucketAllocator; + Hash mHasher; + Pred mPred; +}; + +template +vdhashset::vdhashset() { +} + +template +vdhashset::vdhashset(const vdhashset& src) + : mHasher(src.mHasher) + , mPred(src.mPred) +{ + rehash_to_size(src.mElementCount); + + try { + for(vdhashtable_base_node **bucket = this->mpBucketStart; bucket != this->mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + insert(node->mData); + + p = next; + } + + *bucket = NULL; + } + } catch(...) { + reset(); + throw; + } +} + +template +vdhashset::~vdhashset() { + reset(); +} + +template +vdhashset& vdhashset::operator=(const vdhashset& src) { + if (&src != this) { + clear(); + + mHasher = src.mHasher; + mPred = src.mPred; + + for(vdhashtable_base_node **bucket = src.mpBucketStart; bucket != src.mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + insert(node->mData); + + p = next; + } + + *bucket = NULL; + } + } + + return *this; +} + +template +typename vdhashset::allocator_type vdhashset::get_allocator() const { + return A(); +} + +// modifiers +template +typename vdhashset::insert_return_type vdhashset::insert(const key_type& key) { + if (this->mElementCount >= this->mBucketCount) + rehash_to_size(this->mElementCount + 1); + + size_type bucket = mHasher(key) % this->mBucketCount; + + for(node_type *p = static_cast(this->mpBucketStart[bucket]); p; p = static_cast(p->mpHashNext)) { + if (mPred(p->mData, key)) + return std::pair(iterator(p, &this->mpBucketStart[bucket], this->mpBucketEnd), false); + } + + node_type *node = mAllocator.allocate(1); + try { + new(node) node_type(static_cast(this->mpBucketStart[bucket]), key); + } catch(...) { + mAllocator.deallocate(node, 1); + throw; + } + + this->mpBucketStart[bucket] = node; + ++this->mElementCount; + + return std::pair(iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd), true); +} + +template +typename vdhashset::iterator vdhashset::erase(iterator position) { + size_type bucket = mHasher(position->first) % this->mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = this->mpBucketStart[bucket]; + + while(&static_cast(p)->mData != &*position) { + prev = p; + p = p->mpHashNext; + } + + vdhashtable_base_node *next = p->mpHashNext; + if (prev) + prev->mpHashNext = next; + else + this->mpBucketStart[bucket] = next; + + node_type *node = static_cast(p); + node->~node_type(); + mAllocator.deallocate(node, 1); + --this->mElementCount; + + return iterator(next, &this->mpBucketStart[bucket], this->mpBucketEnd); +} + +template +typename vdhashset::const_iterator vdhashset::erase(const_iterator position) { + size_type bucket = mHasher(position->first) % this->mBucketCount; + const vdhashtable_base_node *prev = NULL; + const vdhashtable_base_node *p = this->mpBucketStart[bucket]; + + while(&static_cast(p)->mData != &*position) { + prev = p; + p = p->mpHashNext; + } + + const vdhashtable_base_node *next = p->mpHashNext; + if (prev) + prev->mpHashNext = next; + else + this->mpBucketStart[bucket] = next; + + node_type *node = static_cast(p); + node->~node_type(); + mAllocator.deallocate(node, 1); + --this->mElementCount; + + return const_iterator(next, &this->mpBucketStart[bucket], this->mpBucketEnd); +} + +template +typename vdhashset::size_type vdhashset::erase(const key_type& k) { + if (!this->mBucketCount) + return 0; + + size_type bucket = mHasher(k) % this->mBucketCount; + vdhashtable_base_node *prev = NULL; + vdhashtable_base_node *p = this->mpBucketStart[bucket]; + + while(p) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) { + vdhashtable_base_node *next = p->mpHashNext; + + if (prev) + prev->mpHashNext = next; + else + this->mpBucketStart[bucket] = next; + + node->~node_type(); + mAllocator.deallocate(node, 1); + --this->mElementCount; + return 1; + } + + prev = p; + p = p->mpHashNext; + } + + return 0; +} + +template +void vdhashset::clear() { + for(vdhashtable_base_node **bucket = this->mpBucketStart; bucket != this->mpBucketEnd; ++bucket) { + vdhashtable_base_node *p = *bucket; + + while(p) { + vdhashtable_base_node *next = p->mpHashNext; + node_type *node = static_cast(p); + + node->~node_type(); + + mAllocator.deallocate(node, 1); + + p = next; + } + + *bucket = NULL; + } + + this->mElementCount = 0; +} + +// observers +template +typename vdhashset::hasher vdhashset::hash_function() const { + return mHasher; +} + +template +typename vdhashset::key_equal vdhashset::key_eq() const { + return mPred; +} + +// lookup +template +typename vdhashset::iterator vdhashset::find(const key_type& k) { + if (!this->mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % this->mBucketCount; + + for(vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd); + } + + return iterator(); +} + +template +typename vdhashset::const_iterator vdhashset::find(const key_type& k) const { + if (!this->mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % this->mBucketCount; + + for(const vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { + const node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return const_iterator(const_cast(static_cast(node)), &this->mpBucketStart[bucket], this->mpBucketEnd); + } + + return iterator(); +} + +template +typename vdhashset::size_type vdhashset::count(const key_type& k) const { + return find(k) != end() ? 1 : 0; +} + +template +std::pair::iterator, typename vdhashset::iterator> vdhashset::equal_range(const key_type& k) { + iterator it = find(k); + iterator itEnd; + + if (it == itEnd) + return std::make_pair(itEnd, itEnd); + + itEnd = it; + ++itEnd; + + return std::make_pair(it, itEnd); +} + +template +std::pair::const_iterator, typename vdhashset::const_iterator> vdhashset::equal_range(const key_type& k) const { + const_iterator it = find(k); + const_iterator itEnd; + + if (it == itEnd) + return std::make_pair(itEnd, itEnd); + + itEnd = it; + ++itEnd; + + return std::make_pair(it, itEnd); +} + +template +template +typename vdhashset::iterator vdhashset::find_as(const U& k) { + if (!this->mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % this->mBucketCount; + + for(vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { + node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return iterator(node, &this->mpBucketStart[bucket], this->mpBucketEnd); + } + + return iterator(); +} + +template +template +typename vdhashset::const_iterator vdhashset::find_as(const U& k) const { + if (!this->mBucketCount) + return iterator(); + + size_type bucket = mHasher(k) % this->mBucketCount; + + for(const vdhashtable_base_node *p = this->mpBucketStart[bucket]; p; p = p->mpHashNext) { + const node_type *node = static_cast(p); + + if (mPred(node->mData.first, k)) + return const_iterator(const_cast(static_cast(node)), &this->mpBucketStart[bucket], this->mpBucketEnd); + } + + return iterator(); +} + +// bucket interface +template +typename vdhashset::size_type vdhashset::bucket(const key_type& k) const { + size_type bucket = 0; + + if (this->mBucketCount) + bucket = mHasher(k) % this->mBucketCount; + + return bucket; +} + +template +typename vdhashset::local_iterator vdhashset::begin(size_type n) { + return local_iterator(this->mpBucketStart[n]); +} + +template +typename vdhashset::const_local_iterator vdhashset::begin(size_type n) const { + return const_local_iterator(this->mpBucketStart[n]); +} + +template +typename vdhashset::local_iterator vdhashset::end(size_type n) { + return local_iterator(NULL); +} + +template +typename vdhashset::const_local_iterator vdhashset::end(size_type n) const { + return const_local_iterator(NULL); +} + +// hash policy +template +void vdhashset::rehash(size_type n) { + if (!n) + n = 1; + + if (this->mBucketCount == n) + return; + + vdhashtable_base_node **newBuckets = mBucketAllocator.allocate(n + 1); + + for(size_type i=0; i<=n; ++i) + newBuckets[i] = NULL; + + const size_type m = this->mBucketCount; + for(size_type i=0; impBucketStart[i]; p;) { + vdhashtable_base_node *next = p->mpHashNext; + const value_type& vt = static_cast *>(p)->mData; + size_t bucket = mHasher(vt) % n; + + vdhashtable_base_node *head = newBuckets[bucket]; + + p->mpHashNext = head; + newBuckets[bucket] = p; + + p = next; + } + } + + if (this->mpBucketStart != &vdhashtable::sEmptyBucket) + mBucketAllocator.deallocate(this->mpBucketStart, (this->mpBucketEnd - this->mpBucketStart) + 1); + + this->mpBucketStart = newBuckets; + this->mpBucketEnd = newBuckets + n; + this->mBucketCount = n; +} + +template +void vdhashset::rehash_to_size(size_type n) { + size_type buckets = compute_bucket_count(n); + rehash(buckets); +} + +template +void vdhashset::reset() { + clear(); + + if (this->mpBucketStart != &vdhashtable::sEmptyBucket) + mBucketAllocator.deallocate(this->mpBucketStart, (this->mpBucketEnd - this->mpBucketStart) + 1); +} + +#endif // f_VD2_SYSTEM_VDSTL_HASHSET_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashtable.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashtable.h index 353aa986d74..9cecbde653c 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashtable.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_hashtable.h @@ -1,365 +1,365 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_HASHTABLE_H -#define f_VD2_SYSTEM_VDSTL_HASHTABLE_H - -/////////////////////////////////////////////////////////////////////////////// -// vdhashtable_base_node -// -struct vdhashtable_base_node { - vdhashtable_base_node *mpHashNext; -}; - -/////////////////////////////////////////////////////////////////////////////// -// vdhashtable_base -// -class vdhashtable_base { -public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - vdhashtable_base(); - - // size and capacity - bool empty() const { return mElementCount == 0; } - size_type size() const { return mElementCount; } - size_type max_size() const { return (size_type)-1 >> 1; } - - // bucket interface - size_type bucket_count() const; - size_type max_bucket_count() const; - size_type bucket_size(size_type n) const; - -protected: - static size_type compute_bucket_count(size_type n); - - size_type mBucketCount; - size_type mElementCount; - vdhashtable_base_node **mpBucketStart; - vdhashtable_base_node **mpBucketEnd; - - static vdhashtable_base_node *const sEmptyBucket; -}; - -/////////////////////////////////////////////////////////////////////////// - -template -struct vdhashtable_node : public vdhashtable_base_node { - T mData; - - vdhashtable_node() {} - vdhashtable_node(vdhashtable_node *next) : mData() { - mpHashNext = next; - } - - vdhashtable_node(vdhashtable_node *next, const T& val) : mData(val) { - mpHashNext = next; - } -}; - -/////////////////////////////////////////////////////////////////////////// - -template -class vdhashtable_local_iterator { -public: - typedef std::forward_iterator_tag iterator_category; - typedef T value_type; - typedef T* pointer; - typedef T& reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - vdhashtable_local_iterator(vdhashtable_base_node *node); - - vdhashtable_local_iterator& operator++(); - vdhashtable_local_iterator operator++(int); - - T& operator*() const; - T* operator->() const; - -private: - template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); - - vdhashtable_base_node *mpNode; -}; - -template -vdhashtable_local_iterator::vdhashtable_local_iterator(vdhashtable_base_node *node) - : mpNode(node) -{ -} - -template -vdhashtable_local_iterator& vdhashtable_local_iterator::operator++() { - mpNode = mpNode->mpHashNext; - return *this; -} - -template -vdhashtable_local_iterator vdhashtable_local_iterator::operator++(int) { - vdhashtable_local_iterator prev(*this); - mpNode = mpNode->mpHashNext; - return prev; -} - -template -T& vdhashtable_local_iterator::operator*() const { - return static_cast *>(mpNode)->mData; -} - -template -T* vdhashtable_local_iterator::operator->() const { - return &static_cast *>(mpNode)->mData; -} - -template -bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode != y.mpNode; -} - -template -bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode != y.mpNode; -} - -template -bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { - return x.mpNode != y.mpNode; -} - -/////////////////////////////////////////////////////////////////////////// - -template struct vdhashtable_iterator_nonconst { - typedef T result; -}; - -template struct vdhashtable_iterator_nonconst { - typedef T result; -}; - -template -class vdhashtable_iterator { - typedef typename vdhashtable_iterator_nonconst::result T_NonConst; -public: - typedef std::forward_iterator_tag iterator_category; - typedef T value_type; - typedef T* pointer; - typedef T& reference; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - - vdhashtable_iterator(); - vdhashtable_iterator(vdhashtable_base_node *node, vdhashtable_base_node **bucket, vdhashtable_base_node **bucketEnd); - vdhashtable_iterator(const vdhashtable_iterator& src); - - vdhashtable_iterator& operator++(); - vdhashtable_iterator operator++(int); - - T& operator*() const; - T* operator->() const; - -private: - friend class vdhashtable_iterator; - template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); - - vdhashtable_base_node *mpNode; - vdhashtable_base_node **mpBucket; - vdhashtable_base_node **mpBucketEnd; -}; - -template -vdhashtable_iterator::vdhashtable_iterator() - : mpNode(NULL) - , mpBucket(NULL) - , mpBucketEnd(NULL) -{ -} - -template -vdhashtable_iterator::vdhashtable_iterator(vdhashtable_base_node *node, vdhashtable_base_node **bucket, vdhashtable_base_node **bucketEnd) - : mpNode(node) - , mpBucket(bucket) - , mpBucketEnd(bucketEnd) -{ -} - -template -vdhashtable_iterator::vdhashtable_iterator(const vdhashtable_iterator& src) - : mpNode(src.mpNode) - , mpBucket(src.mpBucket) - , mpBucketEnd(src.mpBucketEnd) -{ -} - -template -vdhashtable_iterator& vdhashtable_iterator::operator++() { - mpNode = mpNode->mpHashNext; - - while(!mpNode && ++mpBucket != mpBucketEnd) - mpNode = static_cast *>(*mpBucket); - - return *this; -} - -template -vdhashtable_iterator vdhashtable_iterator::operator++(int) { - vdhashtable_iterator prev(*this); - mpNode = mpNode->mpHashNext; - return prev; -} - -template -T& vdhashtable_iterator::operator*() const { - return static_cast *>(mpNode)->mData; -} - -template -T* vdhashtable_iterator::operator->() const { - return &static_cast *>(mpNode)->mData; -} - -template -bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode == y.mpNode; -} - -template -bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode != y.mpNode; -} - -template -bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode != y.mpNode; -} - -template -bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { - return x.mpNode != y.mpNode; -} - -/////////////////////////////////////////////////////////////////////////// - -template -class vdhashtable : public vdhashtable_base { -public: - typedef T value_type; - typedef vdhashtable_node node_type; - typedef value_type *pointer; - typedef const value_type *const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef vdhashtable_iterator iterator; - typedef vdhashtable_iterator const_iterator; - typedef vdhashtable_local_iterator local_iterator; - typedef vdhashtable_local_iterator const_local_iterator; - - // iterators - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; -}; - -// iterators -template -typename vdhashtable::iterator vdhashtable::begin() { - vdhashtable_base_node **bucket = mpBucketStart; - vdhashtable_base_node *p = NULL; - - while(bucket != mpBucketEnd) { - p = *bucket; - if (p) - break; - - ++bucket; - } - - return iterator(static_cast(p), bucket, mpBucketEnd); -} - -template -typename vdhashtable::const_iterator vdhashtable::begin() const { - vdhashtable_base_node **bucket = mpBucketStart; - vdhashtable_base_node *p = NULL; - - while(bucket != mpBucketEnd) { - p = *bucket; - if (p) - break; - - ++bucket; - } - - return const_iterator(static_cast(p), bucket, mpBucketEnd); -} - -template -typename vdhashtable::iterator vdhashtable::end() { - return iterator(NULL, NULL, NULL); -} - -template -typename vdhashtable::const_iterator vdhashtable::end() const { - return const_iterator(NULL, NULL, NULL); -} - -#endif // f_VD2_SYSTEM_VDSTL_HASHTABLE_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_HASHTABLE_H +#define f_VD2_SYSTEM_VDSTL_HASHTABLE_H + +/////////////////////////////////////////////////////////////////////////////// +// vdhashtable_base_node +// +struct vdhashtable_base_node { + vdhashtable_base_node *mpHashNext; +}; + +/////////////////////////////////////////////////////////////////////////////// +// vdhashtable_base +// +class vdhashtable_base { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + vdhashtable_base(); + + // size and capacity + bool empty() const { return mElementCount == 0; } + size_type size() const { return mElementCount; } + size_type max_size() const { return (size_type)-1 >> 1; } + + // bucket interface + size_type bucket_count() const; + size_type max_bucket_count() const; + size_type bucket_size(size_type n) const; + +protected: + static size_type compute_bucket_count(size_type n); + + size_type mBucketCount; + size_type mElementCount; + vdhashtable_base_node **mpBucketStart; + vdhashtable_base_node **mpBucketEnd; + + static vdhashtable_base_node *const sEmptyBucket; +}; + +/////////////////////////////////////////////////////////////////////////// + +template +struct vdhashtable_node : public vdhashtable_base_node { + T mData; + + vdhashtable_node() {} + vdhashtable_node(vdhashtable_node *next) : mData() { + mpHashNext = next; + } + + vdhashtable_node(vdhashtable_node *next, const T& val) : mData(val) { + mpHashNext = next; + } +}; + +/////////////////////////////////////////////////////////////////////////// + +template +class vdhashtable_local_iterator { +public: + typedef std::forward_iterator_tag iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + vdhashtable_local_iterator(vdhashtable_base_node *node); + + vdhashtable_local_iterator& operator++(); + vdhashtable_local_iterator operator++(int); + + T& operator*() const; + T* operator->() const; + +private: + template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + template friend bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y); + + vdhashtable_base_node *mpNode; +}; + +template +vdhashtable_local_iterator::vdhashtable_local_iterator(vdhashtable_base_node *node) + : mpNode(node) +{ +} + +template +vdhashtable_local_iterator& vdhashtable_local_iterator::operator++() { + mpNode = mpNode->mpHashNext; + return *this; +} + +template +vdhashtable_local_iterator vdhashtable_local_iterator::operator++(int) { + vdhashtable_local_iterator prev(*this); + mpNode = mpNode->mpHashNext; + return prev; +} + +template +T& vdhashtable_local_iterator::operator*() const { + return static_cast *>(mpNode)->mData; +} + +template +T* vdhashtable_local_iterator::operator->() const { + return &static_cast *>(mpNode)->mData; +} + +template +bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator==(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode != y.mpNode; +} + +template +bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode != y.mpNode; +} + +template +bool operator!=(const vdhashtable_local_iterator& x, const vdhashtable_local_iterator& y) { + return x.mpNode != y.mpNode; +} + +/////////////////////////////////////////////////////////////////////////// + +template struct vdhashtable_iterator_nonconst { + typedef T result; +}; + +template struct vdhashtable_iterator_nonconst { + typedef T result; +}; + +template +class vdhashtable_iterator { + typedef typename vdhashtable_iterator_nonconst::result T_NonConst; +public: + typedef std::forward_iterator_tag iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + vdhashtable_iterator(); + vdhashtable_iterator(vdhashtable_base_node *node, vdhashtable_base_node **bucket, vdhashtable_base_node **bucketEnd); + vdhashtable_iterator(const vdhashtable_iterator& src); + + vdhashtable_iterator& operator++(); + vdhashtable_iterator operator++(int); + + T& operator*() const; + T* operator->() const; + +private: + friend class vdhashtable_iterator; + template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + template friend bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y); + + vdhashtable_base_node *mpNode; + vdhashtable_base_node **mpBucket; + vdhashtable_base_node **mpBucketEnd; +}; + +template +vdhashtable_iterator::vdhashtable_iterator() + : mpNode(NULL) + , mpBucket(NULL) + , mpBucketEnd(NULL) +{ +} + +template +vdhashtable_iterator::vdhashtable_iterator(vdhashtable_base_node *node, vdhashtable_base_node **bucket, vdhashtable_base_node **bucketEnd) + : mpNode(node) + , mpBucket(bucket) + , mpBucketEnd(bucketEnd) +{ +} + +template +vdhashtable_iterator::vdhashtable_iterator(const vdhashtable_iterator& src) + : mpNode(src.mpNode) + , mpBucket(src.mpBucket) + , mpBucketEnd(src.mpBucketEnd) +{ +} + +template +vdhashtable_iterator& vdhashtable_iterator::operator++() { + mpNode = mpNode->mpHashNext; + + while(!mpNode && ++mpBucket != mpBucketEnd) + mpNode = static_cast *>(*mpBucket); + + return *this; +} + +template +vdhashtable_iterator vdhashtable_iterator::operator++(int) { + vdhashtable_iterator prev(*this); + mpNode = mpNode->mpHashNext; + return prev; +} + +template +T& vdhashtable_iterator::operator*() const { + return static_cast *>(mpNode)->mData; +} + +template +T* vdhashtable_iterator::operator->() const { + return &static_cast *>(mpNode)->mData; +} + +template +bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator==(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode == y.mpNode; +} + +template +bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode != y.mpNode; +} + +template +bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode != y.mpNode; +} + +template +bool operator!=(const vdhashtable_iterator& x, const vdhashtable_iterator& y) { + return x.mpNode != y.mpNode; +} + +/////////////////////////////////////////////////////////////////////////// + +template +class vdhashtable : public vdhashtable_base { +public: + typedef T value_type; + typedef vdhashtable_node node_type; + typedef value_type *pointer; + typedef const value_type *const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef vdhashtable_iterator iterator; + typedef vdhashtable_iterator const_iterator; + typedef vdhashtable_local_iterator local_iterator; + typedef vdhashtable_local_iterator const_local_iterator; + + // iterators + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; +}; + +// iterators +template +typename vdhashtable::iterator vdhashtable::begin() { + vdhashtable_base_node **bucket = mpBucketStart; + vdhashtable_base_node *p = NULL; + + while(bucket != mpBucketEnd) { + p = *bucket; + if (p) + break; + + ++bucket; + } + + return iterator(static_cast(p), bucket, mpBucketEnd); +} + +template +typename vdhashtable::const_iterator vdhashtable::begin() const { + vdhashtable_base_node **bucket = mpBucketStart; + vdhashtable_base_node *p = NULL; + + while(bucket != mpBucketEnd) { + p = *bucket; + if (p) + break; + + ++bucket; + } + + return const_iterator(static_cast(p), bucket, mpBucketEnd); +} + +template +typename vdhashtable::iterator vdhashtable::end() { + return iterator(NULL, NULL, NULL); +} + +template +typename vdhashtable::const_iterator vdhashtable::end() const { + return const_iterator(NULL, NULL, NULL); +} + +#endif // f_VD2_SYSTEM_VDSTL_HASHTABLE_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_vector.h b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_vector.h index e39989bb4f6..10183a88b69 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdstl_vector.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdstl_vector.h @@ -1,606 +1,606 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2009 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDSTL_VECTOR_H -#define f_VD2_SYSTEM_VDSTL_VECTOR_H - -#ifdef _MSC_VER -#pragma once -#endif - -template > -class vdvector { -public: - typedef typename A::reference reference; - typedef typename A::const_reference const_reference; - typedef T *iterator; - typedef const T *const_iterator; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef A allocator_type; - typedef typename A::pointer pointer; - typedef typename A::const_pointer const_pointer; - typedef typename vdreverse_iterator::type reverse_iterator; - typedef typename vdreverse_iterator::type const_reverse_iterator; - - // 23.2.4.1 construct/copy/destroy: - explicit vdvector(); - explicit vdvector(const A&); - explicit vdvector(size_type n); - explicit vdvector(size_type n, const T& value, const A& = A()); - template - vdvector(InputIterator first, InputIterator last, const A& = A()); - vdvector(const vdvector& x); - ~vdvector(); - vdvector& operator=(const vdvector& x); - template - void assign(InputIterator first, InputIterator last); - void assign(size_type n, const T& u); - allocator_type get_allocator() const; - - // iterators: - iterator begin(); - const_iterator begin() const; - iterator end(); - const_iterator end() const; - reverse_iterator rbegin(); - const_reverse_iterator rbegin() const; - reverse_iterator rend(); - const_reverse_iterator rend() const; - pointer data(); - const_pointer data() const; - - // 23.2.4.2 capacity: - size_type size() const; - size_type max_size() const; - size_type capacity() const; - bool empty() const; - - // element access: - reference operator[](size_type n); - const_reference operator[](size_type n) const; - const_reference at(size_type n) const; - reference at(size_type n); - reference front(); - const_reference front() const; - reference back(); - const_reference back() const; - - void resize(size_type sz, T c = T()); - void reserve(size_type n); - - template - void push_back_as(const U& x); - - reference push_back(); - void push_back(const T& x); - void pop_back(); - iterator insert(iterator position, const T& x); - - template - iterator insert_as(iterator position, const U& x); - - void insert(iterator position, size_type n, const T& x); - template - void insert(iterator position, InputIterator first, InputIterator last); - iterator erase(iterator position); - iterator erase(iterator first, iterator last); - void swap(vdvector&); - void clear(); - -private: - void free_storage(); - - struct Data : public A { - pointer mpBegin; - pointer mpEnd; - pointer mpEOS; - - Data() : A(), mpBegin(NULL), mpEnd(NULL), mpEOS(NULL) {} - Data(const A& alloc) : A(alloc), mpBegin(NULL), mpEnd(NULL), mpEOS(NULL) {} - } m; -}; - -template -vdvector::vdvector() { -} - -template -vdvector::vdvector(const A& a) - : m(a) -{ -} - -template -vdvector::vdvector(size_type n) { - resize(n); -} - -template -vdvector::vdvector(size_type n, const T& value, const A& a) - : m(a) -{ - resize(n, value); -} - -template -template -vdvector::vdvector(InputIterator first, InputIterator last, const A& a) - : m(a) -{ - assign(first, last); -} - -template -vdvector::vdvector(const vdvector& x) - : m(static_cast(x.m)) -{ - assign(x.m.mpBegin, x.m.mpEnd); -} - -template -vdvector::~vdvector() { - clear(); - - if (m.mpBegin) - m.deallocate(m.mpBegin, m.mpEOS - m.mpBegin); -} - -template -vdvector& vdvector::operator=(const vdvector& x) { - if (&x != this) { - vdvector tmp(x); - - swap(tmp); - } - - return *this; -} - -template -template -void vdvector::assign(InputIterator first, InputIterator last) { - clear(); - insert(m.mpBegin, first, last); -} - -template -void vdvector::assign(size_type n, const T& u) { - clear(); - insert(m.mpBegin, n, u); -} - -template typename vdvector::allocator_type vdvector::get_allocator() const { return m; } -template typename vdvector::iterator vdvector::begin() { return m.mpBegin; } -template typename vdvector::const_iterator vdvector::begin() const { return m.mpBegin; } -template typename vdvector::iterator vdvector::end() { return m.mpEnd; } -template typename vdvector::const_iterator vdvector::end() const { return m.mpEnd; } -template typename vdvector::reverse_iterator vdvector::rbegin() { return reverse_iterator(m.mpEnd); } -template typename vdvector::const_reverse_iterator vdvector::rbegin() const { return const_reverse_iterator(m.mpEnd); } -template typename vdvector::reverse_iterator vdvector::rend() { return reverse_iterator(m.mpBegin); } -template typename vdvector::const_reverse_iterator vdvector::rend() const { return const_reverse_iterator(m.mpBegin); } -template typename vdvector::pointer vdvector::data() { return m.mpBegin; } -template typename vdvector::const_pointer vdvector::data() const { return m.mpBegin; } - -template typename vdvector::size_type vdvector::size() const { return m.mpEnd - m.mpBegin; } -template typename vdvector::size_type vdvector::max_size() const { return m.max_size(); } -template typename vdvector::size_type vdvector::capacity() const { return m.mpEOS - m.mpBegin; } -template bool vdvector::empty() const { return m.mpBegin == m.mpEnd; } - -template typename vdvector::reference vdvector::operator[](size_type n) { return m.mpBegin[n]; } -template typename vdvector::const_reference vdvector::operator[](size_type n) const { return m.mpBegin[n]; } -template typename vdvector::const_reference vdvector::at(size_type n) const { if (n >= (size_type)(m.mpEnd - m.mpBegin)) throw std::out_of_range("The index is out of range."); return m.mpBegin[n]; } -template typename vdvector::reference vdvector::at(size_type n) { if (n >= (size_type)(m.mpEnd - m.mpBegin)) throw std::out_of_range("The index is out of range."); return m.mpBegin[n]; } -template typename vdvector::reference vdvector::front() { return *m.mpBegin; } -template typename vdvector::const_reference vdvector::front() const { return *m.mpBegin; } -template typename vdvector::reference vdvector::back() { return m.mpEnd[-1]; } -template typename vdvector::const_reference vdvector::back() const { return m.mpEnd[-1]; } - -template -void vdvector::resize(size_type sz, T c) { - const size_type currSize = m.mpEnd - m.mpBegin; - - if (sz < currSize) { - T *p = m.mpBegin + sz; - while(m.mpEnd != p) { - --m.mpEnd; - m.mpEnd->~T(); - } - } else if (sz > currSize) { - const size_type currCapacity = m.mpEOS - m.mpBegin; - - if (sz > currCapacity) { - pointer p0 = m.allocate(sz); - - try { - pointer p1 = std::uninitialized_copy(m.mpBegin, m.mpEnd, p0); - pointer p2 = p0 + sz; - - T *prev0 = m.mpBegin; - T *prev1 = m.mpEnd; - T *prev2 = m.mpEOS; - try { - std::uninitialized_fill(p1, p2, c); - - // destroy old range - while(prev1 != prev0) { - --prev1; - prev0->~T(); - } - - m.mpBegin = p0; - m.mpEnd = p2; - m.mpEOS = p2; - } catch(...) { - while(p2 != p1) { - --p2; - p2->~T(); - } - m.deallocate(p0, sz); - throw; - } - - m.deallocate(prev0, prev2 - prev0); - } catch(...) { - m.deallocate(p0, sz); - throw; - } - } else { - pointer newEnd = m.mpBegin + sz; - std::uninitialized_fill(m.mpEnd, newEnd, c); - m.mpEnd = newEnd; - } - } -} - -template -void vdvector::reserve(size_type n) { - const size_type currCapacity = m.mpEOS - m.mpBegin; - - if (n <= currCapacity) - return; - - pointer p0 = m.allocate(n); - - try { - pointer p1 = std::uninitialized_copy(m.mpBegin, m.mpEnd, p0); - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = p1; - m.mpEOS = p0 + n; - } catch(...) { - m.deallocate(p0, n); - throw; - } -} - -template -template -void vdvector::push_back_as(const U& x) { - if (m.mpEnd != m.mpEOS) { - new(m.mpEnd) T(x); - ++m.mpEnd; - } else { - insert_as(m.mpEnd, x); - } -} - -template -typename vdvector::reference vdvector::push_back() { - if (m.mpEnd != m.mpEOS) { - new(m.mpEnd) T(); - return *m.mpEnd++; - } else { - return *insert(m.mpEnd, T()); - } -} - -template -void vdvector::push_back(const T& x) { - VDASSERT(m.mpEnd >= m.mpBegin && m.mpEnd <= m.mpEOS); - if (m.mpEnd != m.mpEOS) { - new(m.mpEnd) T(x); - ++m.mpEnd; - } else { - insert(m.mpEnd, x); - } -} - -template -void vdvector::pop_back() { - --m.mpEnd; - m.mpEnd->~T(); -} - -template -template -typename vdvector::iterator vdvector::insert_as(iterator position, const U& x) { - if (m.mpEnd == m.mpEOS) { - const size_type currSize = m.mpEnd - m.mpBegin; - const size_type newCapacity = currSize + 1; - - const pointer p0 = m.allocate(newCapacity); - pointer pe = p0; - try { - const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); - pe = p1; - - new(pe) T(x); - ++pe; - - const pointer p3 = std::uninitialized_copy(position, m.mpEnd, pe); - pe = p3; - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = pe; - m.mpEOS = p0 + newCapacity; - - return p1; - } catch(...) { - while(pe != p0) { - --pe; - pe->~T(); - } - - m.deallocate(p0, newCapacity); - throw; - } - } else if (position != m.mpEnd) { - T tmp(*position); - - *position = x; - - new(m.mpEnd) T(); - - try { - vdmove_backward(position + 1, m.mpEnd, m.mpEnd + 1); - position[1] = tmp; - ++m.mpEnd; - } catch(...) { - m.mpEnd->~T(); - throw; - } - - return position; - } else { - new(m.mpEnd) T(x); - ++m.mpEnd; - - return position; - } -} - -template -typename vdvector::iterator vdvector::insert(iterator position, const T& x) { - if (m.mpEnd == m.mpEOS) { - const size_type currSize = m.mpEnd - m.mpBegin; - const size_type newCapacity = currSize + 1; - - const pointer p0 = m.allocate(newCapacity); - pointer pe = p0; - try { - const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); - pe = p1; - - new(pe) T(x); - ++pe; - - const pointer p3 = std::uninitialized_copy(position, m.mpEnd, pe); - pe = p3; - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = pe; - m.mpEOS = p0 + newCapacity; - - return p1; - } catch(...) { - while(pe != p0) { - --pe; - pe->~T(); - } - - m.deallocate(p0, newCapacity); - throw; - } - } else if (position != m.mpEnd) { - T tmp(*position); - - *position = x; - - new(m.mpEnd) T(); - - try { - vdmove_backward(position + 1, m.mpEnd, m.mpEnd + 1); - position[1] = tmp; - ++m.mpEnd; - } catch(...) { - m.mpEnd->~T(); - throw; - } - - return position; - } else { - new(m.mpEnd) T(x); - ++m.mpEnd; - - return position; - } -} - -template -void vdvector::insert(iterator position, size_type n, const T& x) { - if ((size_type)(m.mpEOS - m.mpEnd) < n) { - const size_type currSize = m.mpEnd - m.mpBegin; - const size_type newCapacity = currSize + n; - - const pointer p0 = m.allocate(newCapacity); - pointer pe = p0; - try { - const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); - pe = p1; - - const pointer p2 = p1 + n; - std::uninitialized_fill(p1, p2, x); - pe = p2; - - const pointer p3 = std::uninitialized_copy(position, m.mpEnd, p2); - pe = p3; - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = pe; - m.mpEOS = p0 + newCapacity; - } catch(...) { - while(pe != p0) { - --pe; - pe->~T(); - } - - m.deallocate(p0, newCapacity); - throw; - } - } else if (n) { - pointer newEnd = m.mpEnd + n; - pointer insEnd = std::copy_backward(position, m.mpEnd, newEnd); - - try { - std::uninitialized_fill(position, m.mpEnd, x); - m.mpEnd = newEnd; - } catch(...) { - std::copy(insEnd, newEnd, position); - throw; - } - } -} - -template -template -void vdvector::insert(iterator position, InputIterator first, InputIterator last) { - const size_type n = last - first; - - if ((size_type)(m.mpEOS - m.mpEnd) < n) { - const size_type currSize = m.mpEnd - m.mpBegin; - const size_type newCapacity = currSize + n; - - const pointer p0 = m.allocate(newCapacity); - pointer pe = p0; - try { - const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); - pe = p1; - - const pointer p2 = p1 + n; - std::uninitialized_copy(first, last, p1); - pe = p2; - - const pointer p3 = std::uninitialized_copy(position, m.mpEnd, p2); - pe = p3; - - free_storage(); - - m.mpBegin = p0; - m.mpEnd = pe; - m.mpEOS = p0 + newCapacity; - } catch(...) { - while(pe != p0) { - --pe; - pe->~T(); - } - - m.deallocate(p0, newCapacity); - throw; - } - } else if (n) { - pointer newEnd = m.mpEnd + n; - pointer insEnd = std::copy_backward(position, m.mpEnd, newEnd); - - try { - std::uninitialized_copy(first, last, position); - m.mpEnd = newEnd; - } catch(...) { - std::copy(insEnd, newEnd, position); - throw; - } - } -} - -template -typename vdvector::iterator vdvector::erase(iterator position) { - m.mpEnd = vdmove_forward(position + 1, m.mpEnd, position); - m.mpEnd->~T(); - - return position; -} - -template -typename vdvector::iterator vdvector::erase(iterator first, iterator last) { - if (first != last) { - pointer p = vdmove_forward(last, m.mpEnd, first); - - for(pointer q = p; q != m.mpEnd; ++q) - q->~T(); - - m.mpEnd = p; - } - - return first; -} - -template -void vdvector::swap(vdvector& x) { - std::swap(m.mpBegin, x.m.mpBegin); - std::swap(m.mpEnd, x.m.mpEnd); - std::swap(m.mpEOS, x.m.mpEOS); -} - -template -void vdvector::clear() { - while(m.mpEnd != m.mpBegin) { - --m.mpEnd; - m.mpEnd->~T(); - } -} - -template -void vdvector::free_storage() { - pointer b = m.mpBegin; - pointer p = m.mpEnd; - - while(p != b) { - --p; - p->~T(); - } - - m.deallocate(b, m.mpEOS - b); -} - -#endif // f_VD2_SYSTEM_VDSTL_VECTOR_H +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2009 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDSTL_VECTOR_H +#define f_VD2_SYSTEM_VDSTL_VECTOR_H + +#ifdef _MSC_VER +#pragma once +#endif + +template > +class vdvector { +public: + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef T *iterator; + typedef const T *const_iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef A allocator_type; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef typename vdreverse_iterator::type reverse_iterator; + typedef typename vdreverse_iterator::type const_reverse_iterator; + + // 23.2.4.1 construct/copy/destroy: + explicit vdvector(); + explicit vdvector(const A&); + explicit vdvector(size_type n); + explicit vdvector(size_type n, const T& value, const A& = A()); + template + vdvector(InputIterator first, InputIterator last, const A& = A()); + vdvector(const vdvector& x); + ~vdvector(); + vdvector& operator=(const vdvector& x); + template + void assign(InputIterator first, InputIterator last); + void assign(size_type n, const T& u); + allocator_type get_allocator() const; + + // iterators: + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + reverse_iterator rend(); + const_reverse_iterator rend() const; + pointer data(); + const_pointer data() const; + + // 23.2.4.2 capacity: + size_type size() const; + size_type max_size() const; + size_type capacity() const; + bool empty() const; + + // element access: + reference operator[](size_type n); + const_reference operator[](size_type n) const; + const_reference at(size_type n) const; + reference at(size_type n); + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + void resize(size_type sz, T c = T()); + void reserve(size_type n); + + template + void push_back_as(const U& x); + + reference push_back(); + void push_back(const T& x); + void pop_back(); + iterator insert(iterator position, const T& x); + + template + iterator insert_as(iterator position, const U& x); + + void insert(iterator position, size_type n, const T& x); + template + void insert(iterator position, InputIterator first, InputIterator last); + iterator erase(iterator position); + iterator erase(iterator first, iterator last); + void swap(vdvector&); + void clear(); + +private: + void free_storage(); + + struct Data : public A { + pointer mpBegin; + pointer mpEnd; + pointer mpEOS; + + Data() : A(), mpBegin(NULL), mpEnd(NULL), mpEOS(NULL) {} + Data(const A& alloc) : A(alloc), mpBegin(NULL), mpEnd(NULL), mpEOS(NULL) {} + } m; +}; + +template +vdvector::vdvector() { +} + +template +vdvector::vdvector(const A& a) + : m(a) +{ +} + +template +vdvector::vdvector(size_type n) { + resize(n); +} + +template +vdvector::vdvector(size_type n, const T& value, const A& a) + : m(a) +{ + resize(n, value); +} + +template +template +vdvector::vdvector(InputIterator first, InputIterator last, const A& a) + : m(a) +{ + assign(first, last); +} + +template +vdvector::vdvector(const vdvector& x) + : m(static_cast(x.m)) +{ + assign(x.m.mpBegin, x.m.mpEnd); +} + +template +vdvector::~vdvector() { + clear(); + + if (m.mpBegin) + m.deallocate(m.mpBegin, m.mpEOS - m.mpBegin); +} + +template +vdvector& vdvector::operator=(const vdvector& x) { + if (&x != this) { + vdvector tmp(x); + + swap(tmp); + } + + return *this; +} + +template +template +void vdvector::assign(InputIterator first, InputIterator last) { + clear(); + insert(m.mpBegin, first, last); +} + +template +void vdvector::assign(size_type n, const T& u) { + clear(); + insert(m.mpBegin, n, u); +} + +template typename vdvector::allocator_type vdvector::get_allocator() const { return m; } +template typename vdvector::iterator vdvector::begin() { return m.mpBegin; } +template typename vdvector::const_iterator vdvector::begin() const { return m.mpBegin; } +template typename vdvector::iterator vdvector::end() { return m.mpEnd; } +template typename vdvector::const_iterator vdvector::end() const { return m.mpEnd; } +template typename vdvector::reverse_iterator vdvector::rbegin() { return reverse_iterator(m.mpEnd); } +template typename vdvector::const_reverse_iterator vdvector::rbegin() const { return const_reverse_iterator(m.mpEnd); } +template typename vdvector::reverse_iterator vdvector::rend() { return reverse_iterator(m.mpBegin); } +template typename vdvector::const_reverse_iterator vdvector::rend() const { return const_reverse_iterator(m.mpBegin); } +template typename vdvector::pointer vdvector::data() { return m.mpBegin; } +template typename vdvector::const_pointer vdvector::data() const { return m.mpBegin; } + +template typename vdvector::size_type vdvector::size() const { return m.mpEnd - m.mpBegin; } +template typename vdvector::size_type vdvector::max_size() const { return m.max_size(); } +template typename vdvector::size_type vdvector::capacity() const { return m.mpEOS - m.mpBegin; } +template bool vdvector::empty() const { return m.mpBegin == m.mpEnd; } + +template typename vdvector::reference vdvector::operator[](size_type n) { return m.mpBegin[n]; } +template typename vdvector::const_reference vdvector::operator[](size_type n) const { return m.mpBegin[n]; } +template typename vdvector::const_reference vdvector::at(size_type n) const { if (n >= (size_type)(m.mpEnd - m.mpBegin)) throw std::out_of_range("The index is out of range."); return m.mpBegin[n]; } +template typename vdvector::reference vdvector::at(size_type n) { if (n >= (size_type)(m.mpEnd - m.mpBegin)) throw std::out_of_range("The index is out of range."); return m.mpBegin[n]; } +template typename vdvector::reference vdvector::front() { return *m.mpBegin; } +template typename vdvector::const_reference vdvector::front() const { return *m.mpBegin; } +template typename vdvector::reference vdvector::back() { return m.mpEnd[-1]; } +template typename vdvector::const_reference vdvector::back() const { return m.mpEnd[-1]; } + +template +void vdvector::resize(size_type sz, T c) { + const size_type currSize = m.mpEnd - m.mpBegin; + + if (sz < currSize) { + T *p = m.mpBegin + sz; + while(m.mpEnd != p) { + --m.mpEnd; + m.mpEnd->~T(); + } + } else if (sz > currSize) { + const size_type currCapacity = m.mpEOS - m.mpBegin; + + if (sz > currCapacity) { + pointer p0 = m.allocate(sz); + + try { + pointer p1 = std::uninitialized_copy(m.mpBegin, m.mpEnd, p0); + pointer p2 = p0 + sz; + + T *prev0 = m.mpBegin; + T *prev1 = m.mpEnd; + T *prev2 = m.mpEOS; + try { + std::uninitialized_fill(p1, p2, c); + + // destroy old range + while(prev1 != prev0) { + --prev1; + prev0->~T(); + } + + m.mpBegin = p0; + m.mpEnd = p2; + m.mpEOS = p2; + } catch(...) { + while(p2 != p1) { + --p2; + p2->~T(); + } + m.deallocate(p0, sz); + throw; + } + + m.deallocate(prev0, prev2 - prev0); + } catch(...) { + m.deallocate(p0, sz); + throw; + } + } else { + pointer newEnd = m.mpBegin + sz; + std::uninitialized_fill(m.mpEnd, newEnd, c); + m.mpEnd = newEnd; + } + } +} + +template +void vdvector::reserve(size_type n) { + const size_type currCapacity = m.mpEOS - m.mpBegin; + + if (n <= currCapacity) + return; + + pointer p0 = m.allocate(n); + + try { + pointer p1 = std::uninitialized_copy(m.mpBegin, m.mpEnd, p0); + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = p1; + m.mpEOS = p0 + n; + } catch(...) { + m.deallocate(p0, n); + throw; + } +} + +template +template +void vdvector::push_back_as(const U& x) { + if (m.mpEnd != m.mpEOS) { + new(m.mpEnd) T(x); + ++m.mpEnd; + } else { + insert_as(m.mpEnd, x); + } +} + +template +typename vdvector::reference vdvector::push_back() { + if (m.mpEnd != m.mpEOS) { + new(m.mpEnd) T(); + return *m.mpEnd++; + } else { + return *insert(m.mpEnd, T()); + } +} + +template +void vdvector::push_back(const T& x) { + VDASSERT(m.mpEnd >= m.mpBegin && m.mpEnd <= m.mpEOS); + if (m.mpEnd != m.mpEOS) { + new(m.mpEnd) T(x); + ++m.mpEnd; + } else { + insert(m.mpEnd, x); + } +} + +template +void vdvector::pop_back() { + --m.mpEnd; + m.mpEnd->~T(); +} + +template +template +typename vdvector::iterator vdvector::insert_as(iterator position, const U& x) { + if (m.mpEnd == m.mpEOS) { + const size_type currSize = m.mpEnd - m.mpBegin; + const size_type newCapacity = currSize + 1; + + const pointer p0 = m.allocate(newCapacity); + pointer pe = p0; + try { + const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); + pe = p1; + + new(pe) T(x); + ++pe; + + const pointer p3 = std::uninitialized_copy(position, m.mpEnd, pe); + pe = p3; + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = pe; + m.mpEOS = p0 + newCapacity; + + return p1; + } catch(...) { + while(pe != p0) { + --pe; + pe->~T(); + } + + m.deallocate(p0, newCapacity); + throw; + } + } else if (position != m.mpEnd) { + T tmp(*position); + + *position = x; + + new(m.mpEnd) T(); + + try { + vdmove_backward(position + 1, m.mpEnd, m.mpEnd + 1); + position[1] = tmp; + ++m.mpEnd; + } catch(...) { + m.mpEnd->~T(); + throw; + } + + return position; + } else { + new(m.mpEnd) T(x); + ++m.mpEnd; + + return position; + } +} + +template +typename vdvector::iterator vdvector::insert(iterator position, const T& x) { + if (m.mpEnd == m.mpEOS) { + const size_type currSize = m.mpEnd - m.mpBegin; + const size_type newCapacity = currSize + 1; + + const pointer p0 = m.allocate(newCapacity); + pointer pe = p0; + try { + const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); + pe = p1; + + new(pe) T(x); + ++pe; + + const pointer p3 = std::uninitialized_copy(position, m.mpEnd, pe); + pe = p3; + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = pe; + m.mpEOS = p0 + newCapacity; + + return p1; + } catch(...) { + while(pe != p0) { + --pe; + pe->~T(); + } + + m.deallocate(p0, newCapacity); + throw; + } + } else if (position != m.mpEnd) { + T tmp(*position); + + *position = x; + + new(m.mpEnd) T(); + + try { + vdmove_backward(position + 1, m.mpEnd, m.mpEnd + 1); + position[1] = tmp; + ++m.mpEnd; + } catch(...) { + m.mpEnd->~T(); + throw; + } + + return position; + } else { + new(m.mpEnd) T(x); + ++m.mpEnd; + + return position; + } +} + +template +void vdvector::insert(iterator position, size_type n, const T& x) { + if ((size_type)(m.mpEOS - m.mpEnd) < n) { + const size_type currSize = m.mpEnd - m.mpBegin; + const size_type newCapacity = currSize + n; + + const pointer p0 = m.allocate(newCapacity); + pointer pe = p0; + try { + const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); + pe = p1; + + const pointer p2 = p1 + n; + std::uninitialized_fill(p1, p2, x); + pe = p2; + + const pointer p3 = std::uninitialized_copy(position, m.mpEnd, p2); + pe = p3; + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = pe; + m.mpEOS = p0 + newCapacity; + } catch(...) { + while(pe != p0) { + --pe; + pe->~T(); + } + + m.deallocate(p0, newCapacity); + throw; + } + } else if (n) { + pointer newEnd = m.mpEnd + n; + pointer insEnd = std::copy_backward(position, m.mpEnd, newEnd); + + try { + std::uninitialized_fill(position, m.mpEnd, x); + m.mpEnd = newEnd; + } catch(...) { + std::copy(insEnd, newEnd, position); + throw; + } + } +} + +template +template +void vdvector::insert(iterator position, InputIterator first, InputIterator last) { + const size_type n = last - first; + + if ((size_type)(m.mpEOS - m.mpEnd) < n) { + const size_type currSize = m.mpEnd - m.mpBegin; + const size_type newCapacity = currSize + n; + + const pointer p0 = m.allocate(newCapacity); + pointer pe = p0; + try { + const pointer p1 = std::uninitialized_copy(m.mpBegin, position, p0); + pe = p1; + + const pointer p2 = p1 + n; + std::uninitialized_copy(first, last, p1); + pe = p2; + + const pointer p3 = std::uninitialized_copy(position, m.mpEnd, p2); + pe = p3; + + free_storage(); + + m.mpBegin = p0; + m.mpEnd = pe; + m.mpEOS = p0 + newCapacity; + } catch(...) { + while(pe != p0) { + --pe; + pe->~T(); + } + + m.deallocate(p0, newCapacity); + throw; + } + } else if (n) { + pointer newEnd = m.mpEnd + n; + pointer insEnd = std::copy_backward(position, m.mpEnd, newEnd); + + try { + std::uninitialized_copy(first, last, position); + m.mpEnd = newEnd; + } catch(...) { + std::copy(insEnd, newEnd, position); + throw; + } + } +} + +template +typename vdvector::iterator vdvector::erase(iterator position) { + m.mpEnd = vdmove_forward(position + 1, m.mpEnd, position); + m.mpEnd->~T(); + + return position; +} + +template +typename vdvector::iterator vdvector::erase(iterator first, iterator last) { + if (first != last) { + pointer p = vdmove_forward(last, m.mpEnd, first); + + for(pointer q = p; q != m.mpEnd; ++q) + q->~T(); + + m.mpEnd = p; + } + + return first; +} + +template +void vdvector::swap(vdvector& x) { + std::swap(m.mpBegin, x.m.mpBegin); + std::swap(m.mpEnd, x.m.mpEnd); + std::swap(m.mpEOS, x.m.mpEOS); +} + +template +void vdvector::clear() { + while(m.mpEnd != m.mpBegin) { + --m.mpEnd; + m.mpEnd->~T(); + } +} + +template +void vdvector::free_storage() { + pointer b = m.mpBegin; + pointer p = m.mpEnd; + + while(p != b) { + --p; + p->~T(); + } + + m.deallocate(b, m.mpEOS - b); +} + +#endif // f_VD2_SYSTEM_VDSTL_VECTOR_H diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vdtypes.h b/src/thirdparty/VirtualDub/h/vd2/system/vdtypes.h index 98bfde66558..3bcf227f323 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vdtypes.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vdtypes.h @@ -1,449 +1,449 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VDTYPES_H -#define f_VD2_SYSTEM_VDTYPES_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include -#include -#include - -#ifndef NULL -#define NULL 0 -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// compiler detection -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef VD_COMPILER_DETECTED - #define VD_COMPILER_DETECTED - - #if defined(_MSC_VER) - #define VD_COMPILER_MSVC _MSC_VER - - #if _MSC_VER >= 1400 - #define VD_COMPILER_MSVC_VC8 1 - #define VD_COMPILER_MSVC_VC8_OR_LATER 1 - - #if _MSC_FULL_VER == 140040310 - #define VD_COMPILER_MSVC_VC8_PSDK 1 - #elif _MSC_FULL_VER == 14002207 - #define VD_COMPILER_MSVC_VC8_DDK 1 - #endif - - #elif _MSC_VER >= 1310 - #define VD_COMPILER_MSVC_VC71 1 - #elif _MSC_VER >= 1300 - #define VD_COMPILER_MSVC_VC7 1 - #elif _MSC_VER >= 1200 - #define VD_COMPILER_MSVC_VC6 1 - #endif - #elif defined(__GNUC__) - #define VD_COMPILER_GCC - #if defined(__MINGW32__) || defined(__MINGW64__) - #define VD_COMPILER_GCC_MINGW - #endif - #endif -#endif - -#ifndef VD_CPU_DETECTED - #define VD_CPU_DETECTED - - #if defined(_M_AMD64) - #define VD_CPU_AMD64 1 - #elif defined(_M_IX86) || defined(__i386__) - #define VD_CPU_X86 1 - #elif defined(_M_ARM) - #define VD_CPU_ARM - #endif -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// types -// -/////////////////////////////////////////////////////////////////////////// - -#ifndef VD_STANDARD_TYPES_DECLARED - #if defined(_MSC_VER) - typedef signed __int64 sint64; - typedef unsigned __int64 uint64; - #elif defined(__GNUC__) - typedef signed long long sint64; - typedef unsigned long long uint64; - #endif - typedef signed int sint32; - typedef unsigned int uint32; - typedef signed short sint16; - typedef unsigned short uint16; - typedef signed char sint8; - typedef unsigned char uint8; - - typedef sint64 int64; - typedef sint32 int32; - typedef sint16 int16; - typedef sint8 int8; - - #ifdef _M_AMD64 - typedef sint64 sintptr; - typedef uint64 uintptr; - #else - #if _MSC_VER >= 1310 - typedef __w64 sint32 sintptr; - typedef __w64 uint32 uintptr; - #else - typedef sint32 sintptr; - typedef uint32 uintptr; - #endif - #endif -#endif - -#if defined(_MSC_VER) - #define VD64(x) x##i64 -#elif defined(__GNUC__) - #define VD64(x) x##ll -#else - #error Please add an entry for your compiler for 64-bit constant literals. -#endif - - -#define VDAPIENTRY __cdecl - -typedef int64 VDTime; -typedef int64 VDPosition; -typedef struct __VDGUIHandle *VDGUIHandle; - -// enforce wchar_t under Visual C++ - -#if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) - #include -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// allocation -// -/////////////////////////////////////////////////////////////////////////// - -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1300 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) -#define new_nothrow new -#else -#define new_nothrow new(std::nothrow) -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// STL fixes -// -/////////////////////////////////////////////////////////////////////////// - -#if defined(VD_COMPILER_MSVC_VC6) || defined(VD_COMPILER_MSVC_VC8_DDK) || defined(VD_COMPILER_MSVC_VC8_PSDK) - // The VC6 STL was deliberately borked to avoid conflicting with - // Windows min/max macros. We work around this bogosity here. Note - // that NOMINMAX must be defined for these to compile properly. Also, - // there is a bug in the VC6 compiler that sometimes causes long - // lvalues to "promote" to int, causing ambiguous override errors. - // To avoid this, always explicitly declare which type you are using, - // i.e. min(x,0). None of this is a problem with VC7 or later. - namespace std { - template - inline const T& min(const T& x, const T& y) { - return _cpp_min(x, y); - } - - template - inline const T& max(const T& x, const T& y) { - return _cpp_max(x, y); - } - }; -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// compiler fixes -// -/////////////////////////////////////////////////////////////////////////// - -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) - inline int vswprintf(wchar_t *dst, size_t bufsize, const wchar_t *format, va_list val) { - return _vsnwprintf(dst, bufsize, format, val); - } - - inline int swprintf(wchar_t *dst, size_t bufsize, const wchar_t *format, ...) { - va_list val; - - va_start(val, format); - int r = vswprintf(dst, bufsize, format, val); - va_end(val); - - return r; - } - - #define _strdup strdup - #define _stricmp stricmp - #define _strnicmp strnicmp - #define _wcsdup wcsdup - #define _wcsicmp wcsicmp - #define _wcsnicmp wcsnicmp -#endif - -#if defined(VD_COMPILER_MSVC) && VD_COMPILER_MSVC < 1400 - #define vdfor if(0);else for -#else - #define vdfor for -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// attribute support -// -/////////////////////////////////////////////////////////////////////////// - -#if defined(VD_COMPILER_MSVC) - #define VDINTERFACE __declspec(novtable) - #define VDNORETURN __declspec(noreturn) - #define VDPUREFUNC - - #if VD_COMPILER_MSVC >= 1400 - #define VDRESTRICT __restrict - #else - #define VDRESTRICT - #endif - - #define VDNOINLINE __declspec(noinline) - #define VDFORCEINLINE __forceinline - #define VDALIGN(alignment) __declspec(align(alignment)) -#elif defined(VD_COMPILER_GCC) - #define VDINTERFACE - #define VDNORETURN __attribute__((noreturn)) - #define VDPUREFUNC __attribute__((pure)) - #define VDRESTRICT __restrict - #define VDNOINLINE __attribute__((noinline)) - #define VDFORCEINLINE inline __attribute__((always_inline)) - #define VDALIGN(alignment) __attribute__((aligned(alignment))) -#else - #define VDINTERFACE - #define VDNORETURN - #define VDPUREFUNC - #define VDRESTRICT - #define VDFORCEINLINE - #define VDALIGN(alignment) -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// debug support -// -/////////////////////////////////////////////////////////////////////////// - -enum VDAssertResult { - kVDAssertBreak, - kVDAssertContinue, - kVDAssertIgnore -}; - -extern VDAssertResult VDAssert(const char *exp, const char *file, int line); -extern VDAssertResult VDAssertPtr(const char *exp, const char *file, int line); -extern void VDDebugPrint(const char *format, ...); - -#if defined(_MSC_VER) - #if _MSC_VER >= 1300 - #define VDBREAK __debugbreak() - #else - #define VDBREAK __asm { int 3 } - #endif -#elif defined(__GNUC__) - #define VDBREAK __asm__ volatile ("int3" : : ) -#else - #define VDBREAK *(volatile char *)0 = *(volatile char *)0 -#endif - - -#ifdef _DEBUG - - namespace { - template - struct VDAssertHelper { - VDAssertHelper(const char *exp, const char *file) { - if (!sbAssertDisabled) - switch(VDAssert(exp, file, line)) { - case kVDAssertBreak: - VDBREAK; - break; - case kVDAssertIgnore: - sbAssertDisabled = true; - break; - } - } - - static bool sbAssertDisabled; - }; - - template - bool VDAssertHelper::sbAssertDisabled; - - template - struct VDAssertHelper2 { static bool sDisabled; }; - - template - bool VDAssertHelper2::sDisabled; - } - -// MPC-HC custom code start -// We use the old code since the new templated code isn't compatible with MSVC "Edit and continue" feature -// because __LINE__ can't be known at compile time. -#if !defined(VD_COMPILER_MSVC) || defined(__INTEL_COMPILER) - #define VDASSERT(exp) if (!VDAssertHelper2<__LINE__>::sDisabled) if (exp); else switch(VDAssert (#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) - #define VDASSERTPTR(exp) if (!VDAssertHelper2<__LINE__>::sDisabled) if (exp); else switch(VDAssertPtr(#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) - #define VDVERIFY(exp) if (exp); else if (!VDAssertHelper2<__LINE__>::sDisabled) switch(VDAssert (#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) - #define VDVERIFYPTR(exp) if (exp); else if (!VDAssertHelper2<__LINE__>::sDisabled) switch(VDAssertPtr(#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) -#else - #define VDASSERT(exp) do { } while (0) - #define VDASSERTPTR(exp) do { } while (0) - #define VDVERIFY(exp) do { } while (0) - #define VDVERIFYPTR(exp) do { } while (0) -#endif -// MPC-HC custom code end - #define VDASSERTCT(exp) (void)sizeof(int[(exp)?1:-1]) - - #define VDINLINEASSERT(exp) ((exp)||(VDAssertHelper<__LINE__>(#exp, __FILE__),false)) - #define VDINLINEASSERTFALSE(exp) ((exp)&&(VDAssertHelper<__LINE__>("!("#exp")", __FILE__),true)) - - #define NEVER_HERE do { if (VDAssert( "[never here]", __FILE__, __LINE__ )) VDBREAK; __assume(false); } while(false) - #define VDNEVERHERE do { if (VDAssert( "[never here]", __FILE__, __LINE__ )) VDBREAK; __assume(false); } while(false) - - #define VDDEBUG VDDebugPrint - -#else - - #if defined(_MSC_VER) - #ifndef _M_AMD64 - #define VDASSERT(exp) __assume(!!(exp)) - #define VDASSERTPTR(exp) __assume(!!(exp)) - #else - #define VDASSERT(exp) __noop(exp) - #define VDASSERTPTR(exp) __noop(exp) - #endif - #elif defined(__GNUC__) - #define VDASSERT(exp) __builtin_expect(0 != (exp), 1) - #define VDASSERTPTR(exp) __builtin_expect(0 != (exp), 1) - #endif - - #define VDVERIFY(exp) (exp) - #define VDVERIFYPTR(exp) (exp) - #define VDASSERTCT(exp) - - #define VDINLINEASSERT(exp) (exp) - #define VDINLINEASSERTFALSE(exp) (exp) - - #if defined(VD_COMPILER_MSVC) - #define NEVER_HERE __assume(false) - #define VDNEVERHERE __assume(false) - #else - #define NEVER_HERE VDASSERT(false) - #define VDNEVERHERE VDASSERT(false) - #endif - - extern int VDDEBUG_Helper(const char *, ...); - #define VDDEBUG (void)sizeof VDDEBUG_Helper - -#endif - -#define VDDEBUG2 VDDebugPrint - -// TODO macros -// -// These produce a diagnostic during compilation that indicate a TODO for -// later: -// -// #pragma message(__TODO__ "Fix this.) -// #vdpragma_TODO("Fix this.") - -#define vdpragma_TODO2(x) #x -#define vdpragma_TODO1(x) vdpragma_TODO2(x) -#define vdpragma_TODO0 __FILE__ "(" vdpragma_TODO1(__LINE__) ") : TODO: " - -#ifdef _MSC_VER -#define vdpragma_TODO(x) message(vdpragma_TODO0 x) -#else -#define vdpragma_TODO(x) -#endif - -// BS macros -// -// These tag code that is not meant to go into a final build. - -#define vdpragma_BS2(x) #x -#define vdpragma_BS1(x) vdpragma_BS2(x) -#define vdpragma_BS0 __FILE__ "(" vdpragma_BS1(__LINE__) ") : BS: " - -#ifdef _MSC_VER -#define vdpragma_BS(x) message(vdpragma_BS0 x) -#else -#define vdpragma_BS(x) -#endif - -/////////////////////////////////////////////////////////////////////////// -// -// Object scope macros -// -// vdobjectscope() allows you to define a construct where an object is -// constructed and live only within the controlled statement. This is -// used for vdsynchronized (thread.h) and protected scopes below. -// It relies on a strange quirk of C++ regarding initialized objects -// in the condition of a selection statement and also horribly abuses -// the switch statement, generating rather good code in release builds. -// The catch is that the controlled object must implement a conversion to -// bool returning false and must only be initialized with one argument (C -// syntax). -// -// Unfortunately, handy as this macro is, it is also damned good at -// breaking compilers. For a start, declaring an object with a non- -// trivial destructor in a switch() kills both VC6 and VC7 with a C1001. -// The bug is fixed in VC8 (MSC 14.00). -// -// A somewhat safer alternative is the for() statement, along the lines -// of: -// -// switch(bool v=false) case 0: default: for(object_def; !v; v=true) -// -// This avoids the conversion operator but unfortunately usually generates -// an actual loop in the output. - -#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || defined(VD_COMPILER_MSVC_VC8_DDK)) -#define vdobjectscope(object_def) if(object_def) VDNEVERHERE; else -#else -#define vdobjectscope(object_def) switch(object_def) case 0: default: -#endif - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VDTYPES_H +#define f_VD2_SYSTEM_VDTYPES_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include +#include + +#ifndef NULL +#define NULL 0 +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// compiler detection +// +/////////////////////////////////////////////////////////////////////////// + +#ifndef VD_COMPILER_DETECTED + #define VD_COMPILER_DETECTED + + #if defined(_MSC_VER) + #define VD_COMPILER_MSVC _MSC_VER + + #if _MSC_VER >= 1400 + #define VD_COMPILER_MSVC_VC8 1 + #define VD_COMPILER_MSVC_VC8_OR_LATER 1 + + #if _MSC_FULL_VER == 140040310 + #define VD_COMPILER_MSVC_VC8_PSDK 1 + #elif _MSC_FULL_VER == 14002207 + #define VD_COMPILER_MSVC_VC8_DDK 1 + #endif + + #elif _MSC_VER >= 1310 + #define VD_COMPILER_MSVC_VC71 1 + #elif _MSC_VER >= 1300 + #define VD_COMPILER_MSVC_VC7 1 + #elif _MSC_VER >= 1200 + #define VD_COMPILER_MSVC_VC6 1 + #endif + #elif defined(__GNUC__) + #define VD_COMPILER_GCC + #if defined(__MINGW32__) || defined(__MINGW64__) + #define VD_COMPILER_GCC_MINGW + #endif + #endif +#endif + +#ifndef VD_CPU_DETECTED + #define VD_CPU_DETECTED + + #if defined(_M_AMD64) + #define VD_CPU_AMD64 1 + #elif defined(_M_IX86) || defined(__i386__) + #define VD_CPU_X86 1 + #elif defined(_M_ARM) + #define VD_CPU_ARM + #endif +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// types +// +/////////////////////////////////////////////////////////////////////////// + +#ifndef VD_STANDARD_TYPES_DECLARED + #if defined(_MSC_VER) + typedef signed __int64 sint64; + typedef unsigned __int64 uint64; + #elif defined(__GNUC__) + typedef signed long long sint64; + typedef unsigned long long uint64; + #endif + typedef signed int sint32; + typedef unsigned int uint32; + typedef signed short sint16; + typedef unsigned short uint16; + typedef signed char sint8; + typedef unsigned char uint8; + + typedef sint64 int64; + typedef sint32 int32; + typedef sint16 int16; + typedef sint8 int8; + + #ifdef _M_AMD64 + typedef sint64 sintptr; + typedef uint64 uintptr; + #else + #if _MSC_VER >= 1310 + typedef __w64 sint32 sintptr; + typedef __w64 uint32 uintptr; + #else + typedef sint32 sintptr; + typedef uint32 uintptr; + #endif + #endif +#endif + +#if defined(_MSC_VER) + #define VD64(x) x##i64 +#elif defined(__GNUC__) + #define VD64(x) x##ll +#else + #error Please add an entry for your compiler for 64-bit constant literals. +#endif + + +#define VDAPIENTRY __cdecl + +typedef int64 VDTime; +typedef int64 VDPosition; +typedef struct __VDGUIHandle *VDGUIHandle; + +// enforce wchar_t under Visual C++ + +#if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) + #include +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// allocation +// +/////////////////////////////////////////////////////////////////////////// + +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1300 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) +#define new_nothrow new +#else +#define new_nothrow new(std::nothrow) +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// STL fixes +// +/////////////////////////////////////////////////////////////////////////// + +#if defined(VD_COMPILER_MSVC_VC6) || defined(VD_COMPILER_MSVC_VC8_DDK) || defined(VD_COMPILER_MSVC_VC8_PSDK) + // The VC6 STL was deliberately borked to avoid conflicting with + // Windows min/max macros. We work around this bogosity here. Note + // that NOMINMAX must be defined for these to compile properly. Also, + // there is a bug in the VC6 compiler that sometimes causes long + // lvalues to "promote" to int, causing ambiguous override errors. + // To avoid this, always explicitly declare which type you are using, + // i.e. min(x,0). None of this is a problem with VC7 or later. + namespace std { + template + inline const T& min(const T& x, const T& y) { + return _cpp_min(x, y); + } + + template + inline const T& max(const T& x, const T& y) { + return _cpp_max(x, y); + } + }; +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// compiler fixes +// +/////////////////////////////////////////////////////////////////////////// + +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || (defined(VD_COMPILER_MSVC_VC8_PSDK) || defined(VD_COMPILER_MSVC_VC8_DDK))) + inline int vswprintf(wchar_t *dst, size_t bufsize, const wchar_t *format, va_list val) { + return _vsnwprintf(dst, bufsize, format, val); + } + + inline int swprintf(wchar_t *dst, size_t bufsize, const wchar_t *format, ...) { + va_list val; + + va_start(val, format); + int r = vswprintf(dst, bufsize, format, val); + va_end(val); + + return r; + } + + #define _strdup strdup + #define _stricmp stricmp + #define _strnicmp strnicmp + #define _wcsdup wcsdup + #define _wcsicmp wcsicmp + #define _wcsnicmp wcsnicmp +#endif + +#if defined(VD_COMPILER_MSVC) && VD_COMPILER_MSVC < 1400 + #define vdfor if(0);else for +#else + #define vdfor for +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// attribute support +// +/////////////////////////////////////////////////////////////////////////// + +#if defined(VD_COMPILER_MSVC) + #define VDINTERFACE __declspec(novtable) + #define VDNORETURN __declspec(noreturn) + #define VDPUREFUNC + + #if VD_COMPILER_MSVC >= 1400 + #define VDRESTRICT __restrict + #else + #define VDRESTRICT + #endif + + #define VDNOINLINE __declspec(noinline) + #define VDFORCEINLINE __forceinline + #define VDALIGN(alignment) __declspec(align(alignment)) +#elif defined(VD_COMPILER_GCC) + #define VDINTERFACE + #define VDNORETURN __attribute__((noreturn)) + #define VDPUREFUNC __attribute__((pure)) + #define VDRESTRICT __restrict + #define VDNOINLINE __attribute__((noinline)) + #define VDFORCEINLINE inline __attribute__((always_inline)) + #define VDALIGN(alignment) __attribute__((aligned(alignment))) +#else + #define VDINTERFACE + #define VDNORETURN + #define VDPUREFUNC + #define VDRESTRICT + #define VDFORCEINLINE + #define VDALIGN(alignment) +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// debug support +// +/////////////////////////////////////////////////////////////////////////// + +enum VDAssertResult { + kVDAssertBreak, + kVDAssertContinue, + kVDAssertIgnore +}; + +extern VDAssertResult VDAssert(const char *exp, const char *file, int line); +extern VDAssertResult VDAssertPtr(const char *exp, const char *file, int line); +extern void VDDebugPrint(const char *format, ...); + +#if defined(_MSC_VER) + #if _MSC_VER >= 1300 + #define VDBREAK __debugbreak() + #else + #define VDBREAK __asm { int 3 } + #endif +#elif defined(__GNUC__) + #define VDBREAK __asm__ volatile ("int3" : : ) +#else + #define VDBREAK *(volatile char *)0 = *(volatile char *)0 +#endif + + +#ifdef _DEBUG + + namespace { + template + struct VDAssertHelper { + VDAssertHelper(const char *exp, const char *file) { + if (!sbAssertDisabled) + switch(VDAssert(exp, file, line)) { + case kVDAssertBreak: + VDBREAK; + break; + case kVDAssertIgnore: + sbAssertDisabled = true; + break; + } + } + + static bool sbAssertDisabled; + }; + + template + bool VDAssertHelper::sbAssertDisabled; + + template + struct VDAssertHelper2 { static bool sDisabled; }; + + template + bool VDAssertHelper2::sDisabled; + } + +// MPC-HC custom code start +// We use the old code since the new templated code isn't compatible with MSVC "Edit and continue" feature +// because __LINE__ can't be known at compile time. +#if !defined(VD_COMPILER_MSVC) || defined(__INTEL_COMPILER) + #define VDASSERT(exp) if (!VDAssertHelper2<__LINE__>::sDisabled) if (exp); else switch(VDAssert (#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) + #define VDASSERTPTR(exp) if (!VDAssertHelper2<__LINE__>::sDisabled) if (exp); else switch(VDAssertPtr(#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) + #define VDVERIFY(exp) if (exp); else if (!VDAssertHelper2<__LINE__>::sDisabled) switch(VDAssert (#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) + #define VDVERIFYPTR(exp) if (exp); else if (!VDAssertHelper2<__LINE__>::sDisabled) switch(VDAssertPtr(#exp, __FILE__, __LINE__)) { case kVDAssertBreak: VDBREAK; break; case kVDAssertIgnore: VDAssertHelper2<__LINE__>::sDisabled = true; } else ((void)0) +#else + #define VDASSERT(exp) do { } while (0) + #define VDASSERTPTR(exp) do { } while (0) + #define VDVERIFY(exp) do { } while (0) + #define VDVERIFYPTR(exp) do { } while (0) +#endif +// MPC-HC custom code end + #define VDASSERTCT(exp) (void)sizeof(int[(exp)?1:-1]) + + #define VDINLINEASSERT(exp) ((exp)||(VDAssertHelper<__LINE__>(#exp, __FILE__),false)) + #define VDINLINEASSERTFALSE(exp) ((exp)&&(VDAssertHelper<__LINE__>("!("#exp")", __FILE__),true)) + + #define NEVER_HERE do { if (VDAssert( "[never here]", __FILE__, __LINE__ )) VDBREAK; __assume(false); } while(false) + #define VDNEVERHERE do { if (VDAssert( "[never here]", __FILE__, __LINE__ )) VDBREAK; __assume(false); } while(false) + + #define VDDEBUG VDDebugPrint + +#else + + #if defined(_MSC_VER) + #ifndef _M_AMD64 + #define VDASSERT(exp) __assume(!!(exp)) + #define VDASSERTPTR(exp) __assume(!!(exp)) + #else + #define VDASSERT(exp) __noop(exp) + #define VDASSERTPTR(exp) __noop(exp) + #endif + #elif defined(__GNUC__) + #define VDASSERT(exp) __builtin_expect(0 != (exp), 1) + #define VDASSERTPTR(exp) __builtin_expect(0 != (exp), 1) + #endif + + #define VDVERIFY(exp) (exp) + #define VDVERIFYPTR(exp) (exp) + #define VDASSERTCT(exp) + + #define VDINLINEASSERT(exp) (exp) + #define VDINLINEASSERTFALSE(exp) (exp) + + #if defined(VD_COMPILER_MSVC) + #define NEVER_HERE __assume(false) + #define VDNEVERHERE __assume(false) + #else + #define NEVER_HERE VDASSERT(false) + #define VDNEVERHERE VDASSERT(false) + #endif + + extern int VDDEBUG_Helper(const char *, ...); + #define VDDEBUG (void)sizeof VDDEBUG_Helper + +#endif + +#define VDDEBUG2 VDDebugPrint + +// TODO macros +// +// These produce a diagnostic during compilation that indicate a TODO for +// later: +// +// #pragma message(__TODO__ "Fix this.) +// #vdpragma_TODO("Fix this.") + +#define vdpragma_TODO2(x) #x +#define vdpragma_TODO1(x) vdpragma_TODO2(x) +#define vdpragma_TODO0 __FILE__ "(" vdpragma_TODO1(__LINE__) ") : TODO: " + +#ifdef _MSC_VER +#define vdpragma_TODO(x) message(vdpragma_TODO0 x) +#else +#define vdpragma_TODO(x) +#endif + +// BS macros +// +// These tag code that is not meant to go into a final build. + +#define vdpragma_BS2(x) #x +#define vdpragma_BS1(x) vdpragma_BS2(x) +#define vdpragma_BS0 __FILE__ "(" vdpragma_BS1(__LINE__) ") : BS: " + +#ifdef _MSC_VER +#define vdpragma_BS(x) message(vdpragma_BS0 x) +#else +#define vdpragma_BS(x) +#endif + +/////////////////////////////////////////////////////////////////////////// +// +// Object scope macros +// +// vdobjectscope() allows you to define a construct where an object is +// constructed and live only within the controlled statement. This is +// used for vdsynchronized (thread.h) and protected scopes below. +// It relies on a strange quirk of C++ regarding initialized objects +// in the condition of a selection statement and also horribly abuses +// the switch statement, generating rather good code in release builds. +// The catch is that the controlled object must implement a conversion to +// bool returning false and must only be initialized with one argument (C +// syntax). +// +// Unfortunately, handy as this macro is, it is also damned good at +// breaking compilers. For a start, declaring an object with a non- +// trivial destructor in a switch() kills both VC6 and VC7 with a C1001. +// The bug is fixed in VC8 (MSC 14.00). +// +// A somewhat safer alternative is the for() statement, along the lines +// of: +// +// switch(bool v=false) case 0: default: for(object_def; !v; v=true) +// +// This avoids the conversion operator but unfortunately usually generates +// an actual loop in the output. + +#if defined(VD_COMPILER_MSVC) && (VD_COMPILER_MSVC < 1400 || defined(VD_COMPILER_MSVC_VC8_DDK)) +#define vdobjectscope(object_def) if(object_def) VDNEVERHERE; else +#else +#define vdobjectscope(object_def) switch(object_def) case 0: default: +#endif + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vectors.h b/src/thirdparty/VirtualDub/h/vd2/system/vectors.h index df411757b12..a7957a4d185 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vectors.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vectors.h @@ -1,616 +1,616 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_VECTORS_H -#define f_VD2_SYSTEM_VECTORS_H - -#ifdef _MSC_VER - #pragma once -#endif - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -bool VDSolveLinearEquation(double *src, int n, ptrdiff_t stride_elements, double *b, double tolerance = 1e-5); - -/////////////////////////////////////////////////////////////////////////// - -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -class vdfloat2x2 { -public: - enum zero_type { zero }; - enum identity_type { identity }; - - typedef float value_type; - typedef vdfloat2 vector_type; - typedef vdfloat2c vector_ctor_type; - typedef vdfloat2x2 self_type; - - vdfloat2x2() {} - vdfloat2x2(zero_type) { m[0] = m[1] = vector_ctor_type(0, 0); } - vdfloat2x2(identity_type) { - m[0] = vector_ctor_type(1, 0); - m[1] = vector_ctor_type(0, 1); - } - - vector_type& operator[](int k) { return m[k]; } - const vector_type& operator[](int k) const { return m[k]; } - - self_type operator*(const self_type& v) const { - self_type result; - -#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] - DO(0,0); - DO(0,1); - DO(1,0); - DO(1,1); -#undef DO - - return result; - } - - vector_type operator*(const vector_type& r) const { - return vector_ctor_type( - m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1], - m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1]); - } - - self_type transpose() const { - self_type res; - - res.m[0].v[0] = m[0].v[0]; - res.m[0].v[1] = m[1].v[0]; - res.m[1].v[0] = m[0].v[1]; - res.m[1].v[1] = m[1].v[1]; - - return res; - } - - self_type adjunct() const { - self_type res; - - res.m[0].set(m[1].v[1], -m[0].v[1]); - res.m[1].set(-m[1].v[0], -m[0].v[0]); - - return res; - } - - value_type det() const { - return m[0].v[0]*m[1].v[1] - m[1].v[0]*m[0].v[1]; - } - - self_type operator~() const { - return adjunct() / det(); - } - - self_type& operator*=(const value_type factor) { - m[0] *= factor; - m[1] *= factor; - - return *this; - } - - self_type& operator/=(const value_type factor) { - return operator*=(value_type(1)/factor); - } - - self_type operator*(const value_type factor) const { - return self_type(*this) *= factor; - } - - self_type operator/(const value_type factor) const { - return self_type(*this) /= factor; - } - - vector_type m[2]; -}; - -class vdfloat3x3 { -public: - enum zero_type { zero }; - enum identity_type { identity }; - enum rotation_x_type { rotation_x }; - enum rotation_y_type { rotation_y }; - enum rotation_z_type { rotation_z }; - - typedef float value_type; - typedef vdfloat3 vector_type; - typedef vdfloat3c vector_ctor_type; - typedef vdfloat3x3 self_type; - - vdfloat3x3() {} - vdfloat3x3(zero_type) { m[0] = m[1] = m[2] = vector_ctor_type(0, 0, 0); } - vdfloat3x3(identity_type) { - m[0].set(1, 0, 0); - m[1].set(0, 1, 0); - m[2].set(0, 0, 1); - } - vdfloat3x3(rotation_x_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( 1, 0, 0); - m[1].set( 0, c,-s); - m[2].set( 0, s, c); - } - - vdfloat3x3(rotation_y_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( c, 0, s); - m[1].set( 0, 1, 0); - m[2].set(-s, 0, c); - } - vdfloat3x3(rotation_z_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( c,-s, 0); - m[1].set( s, c, 0); - m[2].set( 0, 0, 1); - } - - vector_type& operator[](int k) { return m[k]; } - const vector_type& operator[](int k) const { return m[k]; } - - self_type operator*(const self_type& v) const { - self_type result; - -#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + m[i].v[2]*v.m[2].v[j] - DO(0,0); - DO(0,1); - DO(0,2); - DO(1,0); - DO(1,1); - DO(1,2); - DO(2,0); - DO(2,1); - DO(2,2); -#undef DO - - return result; - } - - vector_type operator*(const vector_type& r) const { - return vector_ctor_type( - m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2], - m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2], - m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2]); - } - - self_type transpose() const { - self_type res; - - res.m[0].v[0] = m[0].v[0]; - res.m[0].v[1] = m[1].v[0]; - res.m[0].v[2] = m[2].v[0]; - res.m[1].v[0] = m[0].v[1]; - res.m[1].v[1] = m[1].v[1]; - res.m[1].v[2] = m[2].v[1]; - res.m[2].v[0] = m[0].v[2]; - res.m[2].v[1] = m[1].v[2]; - res.m[2].v[2] = m[2].v[2]; - - return res; - } - - self_type adjunct() const { - using namespace nsVDMath; - - self_type res; - - res.m[0] = cross(m[1], m[2]); - res.m[1] = cross(m[2], m[0]); - res.m[2] = cross(m[0], m[1]); - - return res.transpose(); - } - - value_type det() const { - return + m[0].v[0] * m[1].v[1] * m[2].v[2] - + m[1].v[0] * m[2].v[1] * m[0].v[2] - + m[2].v[0] * m[0].v[1] * m[1].v[2] - - m[0].v[0] * m[2].v[1] * m[1].v[2] - - m[1].v[0] * m[0].v[1] * m[2].v[2] - - m[2].v[0] * m[1].v[1] * m[0].v[2]; - } - - self_type operator~() const { - return adjunct() / det(); - } - - self_type& operator*=(const value_type factor) { - m[0] *= factor; - m[1] *= factor; - m[2] *= factor; - - return *this; - } - - self_type& operator/=(const value_type factor) { - return operator*=(value_type(1)/factor); - } - - self_type operator*(const value_type factor) const { - return self_type(*this) *= factor; - } - - self_type operator/(const value_type factor) const { - return self_type(*this) /= factor; - } - - vector_type m[3]; -}; - -inline vdfloat3 operator*(const vdfloat3& v, const vdfloat3x3& m) { - return v.x * m.m[0] + v.y * m.m[1] + v.z * m.m[2]; -} - -class vdfloat4x4 { -public: - enum zero_type { zero }; - enum identity_type { identity }; - enum rotation_x_type { rotation_x }; - enum rotation_y_type { rotation_y }; - enum rotation_z_type { rotation_z }; - - typedef float value_type; - typedef vdfloat4 vector_type; - typedef vdfloat4c vector_ctor_type; - - vdfloat4x4() {} - vdfloat4x4(const vdfloat3x3& v) { - m[0].set(v.m[0].x, v.m[0].y, v.m[0].z, 0.0f); - m[1].set(v.m[1].x, v.m[1].y, v.m[1].z, 0.0f); - m[2].set(v.m[2].x, v.m[2].y, v.m[2].z, 0.0f); - m[3].set(0, 0, 0, 1); - } - - vdfloat4x4(zero_type) { - m[0].setzero(); - m[1].setzero(); - m[2].setzero(); - m[3].setzero(); - } - - vdfloat4x4(identity_type) { - m[0].set(1, 0, 0, 0); - m[1].set(0, 1, 0, 0); - m[2].set(0, 0, 1, 0); - m[3].set(0, 0, 0, 1); - } - vdfloat4x4(rotation_x_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( 1, 0, 0, 0); - m[1].set( 0, c,-s, 0); - m[2].set( 0, s, c, 0); - m[3].set( 0, 0, 0, 1); - } - vdfloat4x4(rotation_y_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( c, 0, s, 0); - m[1].set( 0, 1, 0, 0); - m[2].set(-s, 0, c, 0); - m[3].set( 0, 0, 0, 1); - } - vdfloat4x4(rotation_z_type, value_type angle) { - const value_type s(sin(angle)); - const value_type c(cos(angle)); - - m[0].set( c,-s, 0, 0); - m[1].set( s, c, 0, 0); - m[2].set( 0, 0, 1, 0); - m[3].set( 0, 0, 0, 1); - } - - const value_type *data() const { return &m[0][0]; } - - vector_type& operator[](int n) { return m[n]; } - const vector_type& operator[](int n) const { return m[n]; } - - vdfloat4x4 operator*(const vdfloat4x4& v) const { - vdfloat4x4 result; - -#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + m[i].v[2]*v.m[2].v[j] + m[i].v[3]*v.m[3].v[j] - DO(0,0); - DO(0,1); - DO(0,2); - DO(0,3); - DO(1,0); - DO(1,1); - DO(1,2); - DO(1,3); - DO(2,0); - DO(2,1); - DO(2,2); - DO(2,3); - DO(3,0); - DO(3,1); - DO(3,2); - DO(3,3); -#undef DO - - return result; - } - - vdfloat4x4& operator*=(const vdfloat4x4& v) { - return operator=(operator*(v)); - } - - vector_type operator*(const vdfloat3& r) const { - return vector_ctor_type( - m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2] + m[0].v[3], - m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2] + m[1].v[3], - m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2] + m[2].v[3], - m[3].v[0]*r.v[0] + m[3].v[1]*r.v[1] + m[3].v[2]*r.v[2] + m[3].v[3]); - } - - vector_type operator*(const vector_type& r) const { - return vector_ctor_type( - m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2] + m[0].v[3]*r.v[3], - m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2] + m[1].v[3]*r.v[3], - m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2] + m[2].v[3]*r.v[3], - m[3].v[0]*r.v[0] + m[3].v[1]*r.v[1] + m[3].v[2]*r.v[2] + m[3].v[3]*r.v[3]); - } - - vector_type m[4]; -}; - -template -struct VDSize { - typedef T value_type; - - int w, h; - - VDSize() {} - VDSize(int _w, int _h) : w(_w), h(_h) {} - - bool operator==(const VDSize& s) const { return w==s.w && h==s.h; } - bool operator!=(const VDSize& s) const { return w!=s.w || h!=s.h; } - - VDSize& operator+=(const VDSize& s) { - w += s.w; - h += s.h; - return *this; - } - - T area() const { return w*h; } - - void include(const VDSize& s) { - if (w < s.w) - w = s.w; - if (h < s.h) - h = s.h; - } -}; - -template -class VDPoint { -public: - VDPoint(); - VDPoint(T x_, T y_); - - T x; - T y; -}; - -template -VDPoint::VDPoint() { -} - -template -VDPoint::VDPoint(T x_, T y_) - : x(x_), y(y_) -{ -} - -template -class VDRect { -public: - typedef T value_type; - - VDRect(); - VDRect(T left_, T top_, T right_, T bottom_); - - bool empty() const; - bool valid() const; - - void clear(); - void invalidate(); - void set(T l, T t, T r, T b); - - void add(T x, T y); - void add(const VDRect& r); - void translate(T x, T y); - void scale(T x, T y); - void transform(T scaleX, T scaleY, T offsetX, T offsety); - void resize(T w, T h); - - bool operator==(const VDRect& r) const; - bool operator!=(const VDRect& r) const; - - T width() const; - T height() const; - T area() const; - VDSize size() const; - VDPoint top_left() const; - VDPoint bottom_right() const; - - bool contains(const VDPoint& pt) const; - -public: - T left, top, right, bottom; -}; - -template -VDRect::VDRect() { -} - -template -VDRect::VDRect(T left_, T top_, T right_, T bottom_) - : left(left_) - , top(top_) - , right(right_) - , bottom(bottom_) -{ -} - -template -bool VDRect::empty() const { - return left >= right || top >= bottom; -} - -template -bool VDRect::valid() const { - return left <= right; -} - -template -void VDRect::clear() { - left = top = right = bottom = 0; -} - -template -void VDRect::invalidate() { - left = top = (std::numeric_limits::max)(); - right = bottom = std::numeric_limits::is_signed ? -(std::numeric_limits::max)() : T(0); -} - -template -void VDRect::set(T l, T t, T r, T b) { - left = l; - top = t; - right = r; - bottom = b; -} - -template -void VDRect::add(T x, T y) { - if (left > x) - left = x; - if (top > y) - top = y; - if (right < x) - right = x; - if (bottom < y) - bottom = y; -} - -template -void VDRect::add(const VDRect& src) { - if (left > src.left) - left = src.left; - if (top > src.top) - top = src.top; - if (right < src.right) - right = src.right; - if (bottom < src.bottom) - bottom = src.bottom; -} - -template -void VDRect::translate(T x, T y) { - left += x; - top += y; - right += x; - bottom += y; -} - -template -void VDRect::scale(T x, T y) { - left *= x; - top *= y; - right *= x; - bottom *= y; -} - -template -void VDRect::transform(T scaleX, T scaleY, T offsetX, T offsetY) { - left = left * scaleX + offsetX; - top = top * scaleY + offsetY; - right = right * scaleX + offsetX; - bottom = bottom * scaleY + offsetY; -} - -template -void VDRect::resize(T w, T h) { - right = left + w; - bottom = top + h; -} - -template -bool VDRect::operator==(const VDRect& r) const { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } - -template -bool VDRect::operator!=(const VDRect& r) const { return left!=r.left || top!=r.top || right!=r.right || bottom!=r.bottom; } - -template -T VDRect::width() const { return right-left; } - -template -T VDRect::height() const { return bottom-top; } - -template -T VDRect::area() const { return (right-left)*(bottom-top); } - -template -VDPoint VDRect::top_left() const { return VDPoint(left, top); } - -template -VDPoint VDRect::bottom_right() const { return VDPoint(right, bottom); } - -template -VDSize VDRect::size() const { return VDSize(right-left, bottom-top); } - -template -bool VDRect::contains(const VDPoint& pt) const { - return pt.x >= left - && pt.x < right - && pt.y >= top - && pt.y < bottom; -} - -/////////////////////////////////////////////////////////////////////////////// -typedef VDPoint vdpoint32; -typedef VDSize vdsize32; -typedef VDSize vdsize32f; -typedef VDRect vdrect32; -typedef VDRect vdrect32f; - -template<> bool vdrect32::contains(const vdpoint32& pt) const; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_VECTORS_H +#define f_VD2_SYSTEM_VECTORS_H + +#ifdef _MSC_VER + #pragma once +#endif + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +bool VDSolveLinearEquation(double *src, int n, ptrdiff_t stride_elements, double *b, double tolerance = 1e-5); + +/////////////////////////////////////////////////////////////////////////// + +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +class vdfloat2x2 { +public: + enum zero_type { zero }; + enum identity_type { identity }; + + typedef float value_type; + typedef vdfloat2 vector_type; + typedef vdfloat2c vector_ctor_type; + typedef vdfloat2x2 self_type; + + vdfloat2x2() {} + vdfloat2x2(zero_type) { m[0] = m[1] = vector_ctor_type(0, 0); } + vdfloat2x2(identity_type) { + m[0] = vector_ctor_type(1, 0); + m[1] = vector_ctor_type(0, 1); + } + + vector_type& operator[](int k) { return m[k]; } + const vector_type& operator[](int k) const { return m[k]; } + + self_type operator*(const self_type& v) const { + self_type result; + +#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + DO(0,0); + DO(0,1); + DO(1,0); + DO(1,1); +#undef DO + + return result; + } + + vector_type operator*(const vector_type& r) const { + return vector_ctor_type( + m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1], + m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1]); + } + + self_type transpose() const { + self_type res; + + res.m[0].v[0] = m[0].v[0]; + res.m[0].v[1] = m[1].v[0]; + res.m[1].v[0] = m[0].v[1]; + res.m[1].v[1] = m[1].v[1]; + + return res; + } + + self_type adjunct() const { + self_type res; + + res.m[0].set(m[1].v[1], -m[0].v[1]); + res.m[1].set(-m[1].v[0], -m[0].v[0]); + + return res; + } + + value_type det() const { + return m[0].v[0]*m[1].v[1] - m[1].v[0]*m[0].v[1]; + } + + self_type operator~() const { + return adjunct() / det(); + } + + self_type& operator*=(const value_type factor) { + m[0] *= factor; + m[1] *= factor; + + return *this; + } + + self_type& operator/=(const value_type factor) { + return operator*=(value_type(1)/factor); + } + + self_type operator*(const value_type factor) const { + return self_type(*this) *= factor; + } + + self_type operator/(const value_type factor) const { + return self_type(*this) /= factor; + } + + vector_type m[2]; +}; + +class vdfloat3x3 { +public: + enum zero_type { zero }; + enum identity_type { identity }; + enum rotation_x_type { rotation_x }; + enum rotation_y_type { rotation_y }; + enum rotation_z_type { rotation_z }; + + typedef float value_type; + typedef vdfloat3 vector_type; + typedef vdfloat3c vector_ctor_type; + typedef vdfloat3x3 self_type; + + vdfloat3x3() {} + vdfloat3x3(zero_type) { m[0] = m[1] = m[2] = vector_ctor_type(0, 0, 0); } + vdfloat3x3(identity_type) { + m[0].set(1, 0, 0); + m[1].set(0, 1, 0); + m[2].set(0, 0, 1); + } + vdfloat3x3(rotation_x_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( 1, 0, 0); + m[1].set( 0, c,-s); + m[2].set( 0, s, c); + } + + vdfloat3x3(rotation_y_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( c, 0, s); + m[1].set( 0, 1, 0); + m[2].set(-s, 0, c); + } + vdfloat3x3(rotation_z_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( c,-s, 0); + m[1].set( s, c, 0); + m[2].set( 0, 0, 1); + } + + vector_type& operator[](int k) { return m[k]; } + const vector_type& operator[](int k) const { return m[k]; } + + self_type operator*(const self_type& v) const { + self_type result; + +#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + m[i].v[2]*v.m[2].v[j] + DO(0,0); + DO(0,1); + DO(0,2); + DO(1,0); + DO(1,1); + DO(1,2); + DO(2,0); + DO(2,1); + DO(2,2); +#undef DO + + return result; + } + + vector_type operator*(const vector_type& r) const { + return vector_ctor_type( + m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2], + m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2], + m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2]); + } + + self_type transpose() const { + self_type res; + + res.m[0].v[0] = m[0].v[0]; + res.m[0].v[1] = m[1].v[0]; + res.m[0].v[2] = m[2].v[0]; + res.m[1].v[0] = m[0].v[1]; + res.m[1].v[1] = m[1].v[1]; + res.m[1].v[2] = m[2].v[1]; + res.m[2].v[0] = m[0].v[2]; + res.m[2].v[1] = m[1].v[2]; + res.m[2].v[2] = m[2].v[2]; + + return res; + } + + self_type adjunct() const { + using namespace nsVDMath; + + self_type res; + + res.m[0] = cross(m[1], m[2]); + res.m[1] = cross(m[2], m[0]); + res.m[2] = cross(m[0], m[1]); + + return res.transpose(); + } + + value_type det() const { + return + m[0].v[0] * m[1].v[1] * m[2].v[2] + + m[1].v[0] * m[2].v[1] * m[0].v[2] + + m[2].v[0] * m[0].v[1] * m[1].v[2] + - m[0].v[0] * m[2].v[1] * m[1].v[2] + - m[1].v[0] * m[0].v[1] * m[2].v[2] + - m[2].v[0] * m[1].v[1] * m[0].v[2]; + } + + self_type operator~() const { + return adjunct() / det(); + } + + self_type& operator*=(const value_type factor) { + m[0] *= factor; + m[1] *= factor; + m[2] *= factor; + + return *this; + } + + self_type& operator/=(const value_type factor) { + return operator*=(value_type(1)/factor); + } + + self_type operator*(const value_type factor) const { + return self_type(*this) *= factor; + } + + self_type operator/(const value_type factor) const { + return self_type(*this) /= factor; + } + + vector_type m[3]; +}; + +inline vdfloat3 operator*(const vdfloat3& v, const vdfloat3x3& m) { + return v.x * m.m[0] + v.y * m.m[1] + v.z * m.m[2]; +} + +class vdfloat4x4 { +public: + enum zero_type { zero }; + enum identity_type { identity }; + enum rotation_x_type { rotation_x }; + enum rotation_y_type { rotation_y }; + enum rotation_z_type { rotation_z }; + + typedef float value_type; + typedef vdfloat4 vector_type; + typedef vdfloat4c vector_ctor_type; + + vdfloat4x4() {} + vdfloat4x4(const vdfloat3x3& v) { + m[0].set(v.m[0].x, v.m[0].y, v.m[0].z, 0.0f); + m[1].set(v.m[1].x, v.m[1].y, v.m[1].z, 0.0f); + m[2].set(v.m[2].x, v.m[2].y, v.m[2].z, 0.0f); + m[3].set(0, 0, 0, 1); + } + + vdfloat4x4(zero_type) { + m[0].setzero(); + m[1].setzero(); + m[2].setzero(); + m[3].setzero(); + } + + vdfloat4x4(identity_type) { + m[0].set(1, 0, 0, 0); + m[1].set(0, 1, 0, 0); + m[2].set(0, 0, 1, 0); + m[3].set(0, 0, 0, 1); + } + vdfloat4x4(rotation_x_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( 1, 0, 0, 0); + m[1].set( 0, c,-s, 0); + m[2].set( 0, s, c, 0); + m[3].set( 0, 0, 0, 1); + } + vdfloat4x4(rotation_y_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( c, 0, s, 0); + m[1].set( 0, 1, 0, 0); + m[2].set(-s, 0, c, 0); + m[3].set( 0, 0, 0, 1); + } + vdfloat4x4(rotation_z_type, value_type angle) { + const value_type s(sin(angle)); + const value_type c(cos(angle)); + + m[0].set( c,-s, 0, 0); + m[1].set( s, c, 0, 0); + m[2].set( 0, 0, 1, 0); + m[3].set( 0, 0, 0, 1); + } + + const value_type *data() const { return &m[0][0]; } + + vector_type& operator[](int n) { return m[n]; } + const vector_type& operator[](int n) const { return m[n]; } + + vdfloat4x4 operator*(const vdfloat4x4& v) const { + vdfloat4x4 result; + +#define DO(i,j) result.m[i].v[j] = m[i].v[0]*v.m[0].v[j] + m[i].v[1]*v.m[1].v[j] + m[i].v[2]*v.m[2].v[j] + m[i].v[3]*v.m[3].v[j] + DO(0,0); + DO(0,1); + DO(0,2); + DO(0,3); + DO(1,0); + DO(1,1); + DO(1,2); + DO(1,3); + DO(2,0); + DO(2,1); + DO(2,2); + DO(2,3); + DO(3,0); + DO(3,1); + DO(3,2); + DO(3,3); +#undef DO + + return result; + } + + vdfloat4x4& operator*=(const vdfloat4x4& v) { + return operator=(operator*(v)); + } + + vector_type operator*(const vdfloat3& r) const { + return vector_ctor_type( + m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2] + m[0].v[3], + m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2] + m[1].v[3], + m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2] + m[2].v[3], + m[3].v[0]*r.v[0] + m[3].v[1]*r.v[1] + m[3].v[2]*r.v[2] + m[3].v[3]); + } + + vector_type operator*(const vector_type& r) const { + return vector_ctor_type( + m[0].v[0]*r.v[0] + m[0].v[1]*r.v[1] + m[0].v[2]*r.v[2] + m[0].v[3]*r.v[3], + m[1].v[0]*r.v[0] + m[1].v[1]*r.v[1] + m[1].v[2]*r.v[2] + m[1].v[3]*r.v[3], + m[2].v[0]*r.v[0] + m[2].v[1]*r.v[1] + m[2].v[2]*r.v[2] + m[2].v[3]*r.v[3], + m[3].v[0]*r.v[0] + m[3].v[1]*r.v[1] + m[3].v[2]*r.v[2] + m[3].v[3]*r.v[3]); + } + + vector_type m[4]; +}; + +template +struct VDSize { + typedef T value_type; + + int w, h; + + VDSize() {} + VDSize(int _w, int _h) : w(_w), h(_h) {} + + bool operator==(const VDSize& s) const { return w==s.w && h==s.h; } + bool operator!=(const VDSize& s) const { return w!=s.w || h!=s.h; } + + VDSize& operator+=(const VDSize& s) { + w += s.w; + h += s.h; + return *this; + } + + T area() const { return w*h; } + + void include(const VDSize& s) { + if (w < s.w) + w = s.w; + if (h < s.h) + h = s.h; + } +}; + +template +class VDPoint { +public: + VDPoint(); + VDPoint(T x_, T y_); + + T x; + T y; +}; + +template +VDPoint::VDPoint() { +} + +template +VDPoint::VDPoint(T x_, T y_) + : x(x_), y(y_) +{ +} + +template +class VDRect { +public: + typedef T value_type; + + VDRect(); + VDRect(T left_, T top_, T right_, T bottom_); + + bool empty() const; + bool valid() const; + + void clear(); + void invalidate(); + void set(T l, T t, T r, T b); + + void add(T x, T y); + void add(const VDRect& r); + void translate(T x, T y); + void scale(T x, T y); + void transform(T scaleX, T scaleY, T offsetX, T offsety); + void resize(T w, T h); + + bool operator==(const VDRect& r) const; + bool operator!=(const VDRect& r) const; + + T width() const; + T height() const; + T area() const; + VDSize size() const; + VDPoint top_left() const; + VDPoint bottom_right() const; + + bool contains(const VDPoint& pt) const; + +public: + T left, top, right, bottom; +}; + +template +VDRect::VDRect() { +} + +template +VDRect::VDRect(T left_, T top_, T right_, T bottom_) + : left(left_) + , top(top_) + , right(right_) + , bottom(bottom_) +{ +} + +template +bool VDRect::empty() const { + return left >= right || top >= bottom; +} + +template +bool VDRect::valid() const { + return left <= right; +} + +template +void VDRect::clear() { + left = top = right = bottom = 0; +} + +template +void VDRect::invalidate() { + left = top = (std::numeric_limits::max)(); + right = bottom = std::numeric_limits::is_signed ? -(std::numeric_limits::max)() : T(0); +} + +template +void VDRect::set(T l, T t, T r, T b) { + left = l; + top = t; + right = r; + bottom = b; +} + +template +void VDRect::add(T x, T y) { + if (left > x) + left = x; + if (top > y) + top = y; + if (right < x) + right = x; + if (bottom < y) + bottom = y; +} + +template +void VDRect::add(const VDRect& src) { + if (left > src.left) + left = src.left; + if (top > src.top) + top = src.top; + if (right < src.right) + right = src.right; + if (bottom < src.bottom) + bottom = src.bottom; +} + +template +void VDRect::translate(T x, T y) { + left += x; + top += y; + right += x; + bottom += y; +} + +template +void VDRect::scale(T x, T y) { + left *= x; + top *= y; + right *= x; + bottom *= y; +} + +template +void VDRect::transform(T scaleX, T scaleY, T offsetX, T offsetY) { + left = left * scaleX + offsetX; + top = top * scaleY + offsetY; + right = right * scaleX + offsetX; + bottom = bottom * scaleY + offsetY; +} + +template +void VDRect::resize(T w, T h) { + right = left + w; + bottom = top + h; +} + +template +bool VDRect::operator==(const VDRect& r) const { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } + +template +bool VDRect::operator!=(const VDRect& r) const { return left!=r.left || top!=r.top || right!=r.right || bottom!=r.bottom; } + +template +T VDRect::width() const { return right-left; } + +template +T VDRect::height() const { return bottom-top; } + +template +T VDRect::area() const { return (right-left)*(bottom-top); } + +template +VDPoint VDRect::top_left() const { return VDPoint(left, top); } + +template +VDPoint VDRect::bottom_right() const { return VDPoint(right, bottom); } + +template +VDSize VDRect::size() const { return VDSize(right-left, bottom-top); } + +template +bool VDRect::contains(const VDPoint& pt) const { + return pt.x >= left + && pt.x < right + && pt.y >= top + && pt.y < bottom; +} + +/////////////////////////////////////////////////////////////////////////////// +typedef VDPoint vdpoint32; +typedef VDSize vdsize32; +typedef VDSize vdsize32f; +typedef VDRect vdrect32; +typedef VDRect vdrect32f; + +template<> bool vdrect32::contains(const vdpoint32& pt) const; + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vectors_float.h b/src/thirdparty/VirtualDub/h/vd2/system/vectors_float.h index 5af26dbc199..3be7fb4ac97 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vectors_float.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vectors_float.h @@ -1,207 +1,207 @@ -class vdfloat2 { -public: - typedef vdfloat2 self_type; - typedef float value_type; - - void set(float x2, float y2) { x=x2; y=y2; } - - float& operator[](int k) { return v[k]; } - const float& operator[](int k) const { return v[k]; } - - float lensq() const { return x*x + y*y; } - - self_type operator-() const { self_type a = {-x, -y}; return a; } - - self_type operator+(const self_type& r) const { self_type a = {x+r.x, y+r.y}; return a; } - self_type operator-(const self_type& r) const { self_type a = {x-r.x, y-r.y}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; return *this; } - - self_type operator*(const float s) const { self_type a = {x*s, x*s}; return a; } - self_type& operator*=(const float s) { x*=s; y*=s; return *this; } - - self_type operator/(const float s) const { const float inv(float(1)/s); self_type a = {x*inv, y*inv}; return a; } - self_type& operator/=(const float s) { const float inv(float(1)/s); x*=inv; y*=inv; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; return *this; } - - union { - struct { - float x; - float y; - }; - float v[2]; - }; -}; - -VDFORCEINLINE vdfloat2 operator*(const float s, const vdfloat2& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdfloat3 { -public: - typedef vdfloat3 self_type; - typedef float value_type; - - void set(float x2, float y2, float z2) { x=x2; y=y2; z=z2; } - - float& operator[](int k) { return v[k]; } - const float& operator[](int k) const { return v[k]; } - - float lensq() const { return x*x + y*y + z*z; } - - vdfloat2 project() const { const float inv(float(1)/z); const vdfloat2 a = {x*inv, y*inv}; return a; } - vdfloat2 as2d() const { const vdfloat2 a = {x, y}; return a; } - - self_type operator-() const { const self_type a = {-x, -y, -z}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; return *this; } - - self_type operator*(const float s) const { const self_type a = {x*s, y*s, z*s}; return a; } - self_type& operator*=(const float s) { x*=s; y*=s; z*=s; return *this; } - - self_type operator/(const float s) const { const float inv(float(1)/s); const self_type a = {x*inv, y*inv, z*inv}; return a; } - self_type& operator/=(const float s) { const float inv(float(1)/s); x*=inv; y*=inv; z*=inv; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; return *this; } - - union { - struct { - float x; - float y; - float z; - }; - float v[3]; - }; -}; - -VDFORCEINLINE vdfloat3 operator*(const float s, const vdfloat3& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdfloat4 { -public: - typedef vdfloat4 self_type; - typedef float value_type; - - void setzero() { x=y=z=w = 0; } - void set(float x2, float y2, float z2, float w2) { x=x2; y=y2; z=z2; w=w2; } - - float& operator[](int i) { return v[i]; } - const float& operator[](int i) const { return v[i]; } - - float lensq() const { return x*x + y*y + z*z + w*w; } - - vdfloat3 project() const { const float inv(float(1)/w); const vdfloat3 a = {x*inv, y*inv, z*inv}; return a; } - - self_type operator-() const { const self_type a = {-x, -y, -z, -w}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z, w+r.w}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z, w-r.w}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; w+=r.w; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; w-=r.w; return *this; } - - self_type operator*(const float factor) const { const self_type a = {x*factor, y*factor, z*factor, w*factor}; return a; } - self_type operator/(const float factor) const { const float inv(float(1) / factor); const self_type a = {x*inv, y*inv, z*inv, w*inv}; return a; } - - self_type& operator*=(const float factor) { x *= factor; y *= factor; z *= factor; w *= factor; return *this; } - self_type& operator/=(const float factor) { const float inv(float(1) / factor); x *= inv; y *= inv; z *= inv; w *= inv; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z, w*r.w}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; w*=r.w; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z, w*r.w}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; w/=r.w; return *this; } - - union { - struct { - float x; - float y; - float z; - float w; - }; - float v[4]; - }; -}; - -VDFORCEINLINE vdfloat4 operator*(const float s, const vdfloat4& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdfloat2c : public vdfloat2 { -public: - VDFORCEINLINE vdfloat2c(float x2, float y2) {x=x2; y=y2;} - VDFORCEINLINE vdfloat2c(const float src[2]) {x=src[0]; y=src[1];} -}; - -class vdfloat3c : public vdfloat3 { -public: - VDFORCEINLINE vdfloat3c(float x2, float y2, float z2) { x=x2; y=y2; z=z2; } - VDFORCEINLINE vdfloat3c(const float src[3]) { x=src[0]; y=src[1]; z=src[2]; } -}; - -class vdfloat4c : public vdfloat4 { -public: - VDFORCEINLINE vdfloat4c(float x2, float y2, float z2, float w2) { x=x2; y=y2; z=z2; w=w2; } - VDFORCEINLINE vdfloat4c(const float src[4]) { x=src[0]; y=src[1]; z=src[2]; w=src[3]; } -}; - - -/////////////////////////////////////////////////////////////////////////// - -namespace nsVDMath { - VDFORCEINLINE float length(const vdfloat2& a) { - return sqrtf(a.x*a.x + a.y*a.y); - } - - VDFORCEINLINE float length(const vdfloat3& a) { - return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z); - } - - VDFORCEINLINE float length(const vdfloat4& a) { - return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w); - } - - VDFORCEINLINE vdfloat2 normalize(const vdfloat2& a) { - return a / length(a); - } - - VDFORCEINLINE vdfloat3 normalize(const vdfloat3& a) { - return a / length(a); - } - - VDFORCEINLINE vdfloat4 normalize(const vdfloat4& a) { - return a / length(a); - } - - VDFORCEINLINE float dot(const vdfloat2& a, const vdfloat2& b) { - return a.x*b.x + a.y*b.y; - } - - VDFORCEINLINE float dot(const vdfloat3& a, const vdfloat3& b) { - return a.x*b.x + a.y*b.y + a.z*b.z; - } - - VDFORCEINLINE float dot(const vdfloat4& a, const vdfloat4& b) { - return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; - } - - VDFORCEINLINE vdfloat3 cross(const vdfloat3& a, const vdfloat3& b) { - const vdfloat3 r = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; - return r; - } -}; +class vdfloat2 { +public: + typedef vdfloat2 self_type; + typedef float value_type; + + void set(float x2, float y2) { x=x2; y=y2; } + + float& operator[](int k) { return v[k]; } + const float& operator[](int k) const { return v[k]; } + + float lensq() const { return x*x + y*y; } + + self_type operator-() const { self_type a = {-x, -y}; return a; } + + self_type operator+(const self_type& r) const { self_type a = {x+r.x, y+r.y}; return a; } + self_type operator-(const self_type& r) const { self_type a = {x-r.x, y-r.y}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; return *this; } + + self_type operator*(const float s) const { self_type a = {x*s, x*s}; return a; } + self_type& operator*=(const float s) { x*=s; y*=s; return *this; } + + self_type operator/(const float s) const { const float inv(float(1)/s); self_type a = {x*inv, y*inv}; return a; } + self_type& operator/=(const float s) { const float inv(float(1)/s); x*=inv; y*=inv; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; return *this; } + + union { + struct { + float x; + float y; + }; + float v[2]; + }; +}; + +VDFORCEINLINE vdfloat2 operator*(const float s, const vdfloat2& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdfloat3 { +public: + typedef vdfloat3 self_type; + typedef float value_type; + + void set(float x2, float y2, float z2) { x=x2; y=y2; z=z2; } + + float& operator[](int k) { return v[k]; } + const float& operator[](int k) const { return v[k]; } + + float lensq() const { return x*x + y*y + z*z; } + + vdfloat2 project() const { const float inv(float(1)/z); const vdfloat2 a = {x*inv, y*inv}; return a; } + vdfloat2 as2d() const { const vdfloat2 a = {x, y}; return a; } + + self_type operator-() const { const self_type a = {-x, -y, -z}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; return *this; } + + self_type operator*(const float s) const { const self_type a = {x*s, y*s, z*s}; return a; } + self_type& operator*=(const float s) { x*=s; y*=s; z*=s; return *this; } + + self_type operator/(const float s) const { const float inv(float(1)/s); const self_type a = {x*inv, y*inv, z*inv}; return a; } + self_type& operator/=(const float s) { const float inv(float(1)/s); x*=inv; y*=inv; z*=inv; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; return *this; } + + union { + struct { + float x; + float y; + float z; + }; + float v[3]; + }; +}; + +VDFORCEINLINE vdfloat3 operator*(const float s, const vdfloat3& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdfloat4 { +public: + typedef vdfloat4 self_type; + typedef float value_type; + + void setzero() { x=y=z=w = 0; } + void set(float x2, float y2, float z2, float w2) { x=x2; y=y2; z=z2; w=w2; } + + float& operator[](int i) { return v[i]; } + const float& operator[](int i) const { return v[i]; } + + float lensq() const { return x*x + y*y + z*z + w*w; } + + vdfloat3 project() const { const float inv(float(1)/w); const vdfloat3 a = {x*inv, y*inv, z*inv}; return a; } + + self_type operator-() const { const self_type a = {-x, -y, -z, -w}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z, w+r.w}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z, w-r.w}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; w+=r.w; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; w-=r.w; return *this; } + + self_type operator*(const float factor) const { const self_type a = {x*factor, y*factor, z*factor, w*factor}; return a; } + self_type operator/(const float factor) const { const float inv(float(1) / factor); const self_type a = {x*inv, y*inv, z*inv, w*inv}; return a; } + + self_type& operator*=(const float factor) { x *= factor; y *= factor; z *= factor; w *= factor; return *this; } + self_type& operator/=(const float factor) { const float inv(float(1) / factor); x *= inv; y *= inv; z *= inv; w *= inv; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z, w*r.w}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; w*=r.w; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z, w*r.w}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; w/=r.w; return *this; } + + union { + struct { + float x; + float y; + float z; + float w; + }; + float v[4]; + }; +}; + +VDFORCEINLINE vdfloat4 operator*(const float s, const vdfloat4& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdfloat2c : public vdfloat2 { +public: + VDFORCEINLINE vdfloat2c(float x2, float y2) {x=x2; y=y2;} + VDFORCEINLINE vdfloat2c(const float src[2]) {x=src[0]; y=src[1];} +}; + +class vdfloat3c : public vdfloat3 { +public: + VDFORCEINLINE vdfloat3c(float x2, float y2, float z2) { x=x2; y=y2; z=z2; } + VDFORCEINLINE vdfloat3c(const float src[3]) { x=src[0]; y=src[1]; z=src[2]; } +}; + +class vdfloat4c : public vdfloat4 { +public: + VDFORCEINLINE vdfloat4c(float x2, float y2, float z2, float w2) { x=x2; y=y2; z=z2; w=w2; } + VDFORCEINLINE vdfloat4c(const float src[4]) { x=src[0]; y=src[1]; z=src[2]; w=src[3]; } +}; + + +/////////////////////////////////////////////////////////////////////////// + +namespace nsVDMath { + VDFORCEINLINE float length(const vdfloat2& a) { + return sqrtf(a.x*a.x + a.y*a.y); + } + + VDFORCEINLINE float length(const vdfloat3& a) { + return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z); + } + + VDFORCEINLINE float length(const vdfloat4& a) { + return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w); + } + + VDFORCEINLINE vdfloat2 normalize(const vdfloat2& a) { + return a / length(a); + } + + VDFORCEINLINE vdfloat3 normalize(const vdfloat3& a) { + return a / length(a); + } + + VDFORCEINLINE vdfloat4 normalize(const vdfloat4& a) { + return a / length(a); + } + + VDFORCEINLINE float dot(const vdfloat2& a, const vdfloat2& b) { + return a.x*b.x + a.y*b.y; + } + + VDFORCEINLINE float dot(const vdfloat3& a, const vdfloat3& b) { + return a.x*b.x + a.y*b.y + a.z*b.z; + } + + VDFORCEINLINE float dot(const vdfloat4& a, const vdfloat4& b) { + return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; + } + + VDFORCEINLINE vdfloat3 cross(const vdfloat3& a, const vdfloat3& b) { + const vdfloat3 r = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; + return r; + } +}; diff --git a/src/thirdparty/VirtualDub/h/vd2/system/vectors_int.h b/src/thirdparty/VirtualDub/h/vd2/system/vectors_int.h index 72a3478c644..78c79676171 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/vectors_int.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/vectors_int.h @@ -1,183 +1,183 @@ -class vdint2 { -public: - typedef vdint2 self_type; - typedef int value_type; - - void set(int x2, int y2) { x=x2; y=y2; } - - int& operator[](int k) { return v[k]; } - const int& operator[](int k) const { return v[k]; } - - int lensq() const { return x*x + y*y; } - int len() const { return (int)sqrtf((float)(x*x + y*y)); } - self_type normalized() const { return *this / len(); } - - self_type operator-() const { const self_type a = {-x, -y}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; return *this; } - - self_type operator*(const int s) const { const self_type a = {x*s, x*s}; return a; } - self_type& operator*=(const int s) { x*=s; y*=s; return *this; } - - self_type operator/(const int s) const { const self_type a = {x/s, y/s}; return a; } - self_type& operator/=(const int s) { x/=s; y/=s; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; return *this; } - - union { - struct { - int x; - int y; - }; - int v[2]; - }; -}; - -VDFORCEINLINE vdint2 operator*(const int s, const vdint2& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdint3 { -public: - typedef vdint3 self_type; - typedef int value_type; - - int& operator[](int k) { return v[k]; } - const int& operator[](int k) const { return v[k]; } - - int lensq() const { return x*x + y*y + z*z; } - int len() const { return (int)sqrtf((float)(x*x + y*y + z*z)); } - self_type normalized() const { return *this / len(); } - - vdint2 project() const { const int inv(int(1)/z); const vdint2 a = {x*inv, y*inv}; return a; } - vdint2 as2d() const { const vdint2 a = {x, y}; return a; } - - self_type operator-() const { const self_type a = {-x, -y, -z}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; return *this; } - - self_type operator*(const int s) const { const self_type a = {x*s, y*s, z*s}; return a; } - self_type& operator*=(const int s) { x*=s; y*=s; z*=s; return *this; } - - self_type operator/(const int s) const { const self_type a = {x/s, y/s, z/s}; return a; } - self_type& operator/=(const int s) { x /= s; y /= s; z /= s; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; return *this; } - - union { - struct { - int x; - int y; - int z; - }; - int v[3]; - }; -}; - -VDFORCEINLINE vdint3 operator*(const int s, const vdint3& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdint4 { -public: - typedef vdint4 self_type; - typedef int value_type; - - int& operator[](int i) { return v[i]; } - const int& operator[](int i) const { return v[i]; } - - int lensq() const { return x*x + y*y + z*z + w*w; } - int len() const { return (int)sqrtf((float)(x*x + y*y + z*z + w*w)); } - self_type normalized() const { return *this / len(); } - - vdint3 project() const { const int inv(int(1)/w); const vdint3 a = {x*inv, y*inv, z*inv}; return a; } - - self_type operator-() const { const self_type a = {-x, -y, -z, -w}; return a; } - - self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z, w+r.w}; return a; } - self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z, w-r.w}; return a; } - - self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; w+=r.w; return *this; } - self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; w-=r.w; return *this; } - - self_type operator*(const int factor) const { const self_type a = {x*factor, y*factor, z*factor, w*factor}; return a; } - self_type operator/(const int factor) const { const self_type a = {x/factor, y/factor, z/factor, w/factor}; return a; } - - self_type& operator*=(const int factor) { x *= factor; y *= factor; z *= factor; w *= factor; return *this; } - self_type& operator/=(const int factor) { x /= factor; y /= factor; z /= factor; w /= factor; return *this; } - - self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z, w*r.w}; return a; } - self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; w*=r.w; return *this; } - - self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z, w*r.w}; return a; } - self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; w/=r.w; return *this; } - - union { - struct { - int x; - int y; - int z; - int w; - }; - int v[4]; - }; -}; - -VDFORCEINLINE vdint4 operator*(const int s, const vdint4& v) { return v*s; } - -/////////////////////////////////////////////////////////////////////////// - -class vdint2c : vdint2 { -public: - VDFORCEINLINE vdint2c(int x2, int y2) {x=x2; y=y2;} - VDFORCEINLINE vdint2c(const int src[2]) {x=src[0]; y=src[1];} -}; - -class vdint3c : vdint3 { -public: - VDFORCEINLINE vdint3c(int x2, int y2, int z2) { x=x2; y=y2; z=z2; } - VDFORCEINLINE vdint3c(const int src[3]) { x=src[0]; y=src[1]; z=src[2]; } -}; - -class vdint4c : vdint4 { -public: - VDFORCEINLINE vdint4c(int x2, int y2, int z2, int w2) { x=x2; y=y2; z=z2; w=w2; } - VDFORCEINLINE vdint4c(const int src[4]) { x=src[0]; y=src[1]; z=src[2]; w=src[3]; } -}; - -/////////////////////////////////////////////////////////////////////////// - -namespace nsVDMath { - VDFORCEINLINE int dot(const vdint2& a, const vdint2& b) { - return a.x*b.x + a.y*b.y; - } - - VDFORCEINLINE int dot(const vdint3& a, const vdint3& b) { - return a.x*b.x + a.y*b.y + a.z*b.z; - } - - VDFORCEINLINE int dot(const vdint4& a, const vdint4& b) { - return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; - } - - VDFORCEINLINE vdint3 cross(const vdint3& a, const vdint3& b) { - const vdint3 r = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; - return r; - } -}; +class vdint2 { +public: + typedef vdint2 self_type; + typedef int value_type; + + void set(int x2, int y2) { x=x2; y=y2; } + + int& operator[](int k) { return v[k]; } + const int& operator[](int k) const { return v[k]; } + + int lensq() const { return x*x + y*y; } + int len() const { return (int)sqrtf((float)(x*x + y*y)); } + self_type normalized() const { return *this / len(); } + + self_type operator-() const { const self_type a = {-x, -y}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; return *this; } + + self_type operator*(const int s) const { const self_type a = {x*s, x*s}; return a; } + self_type& operator*=(const int s) { x*=s; y*=s; return *this; } + + self_type operator/(const int s) const { const self_type a = {x/s, y/s}; return a; } + self_type& operator/=(const int s) { x/=s; y/=s; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; return *this; } + + union { + struct { + int x; + int y; + }; + int v[2]; + }; +}; + +VDFORCEINLINE vdint2 operator*(const int s, const vdint2& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdint3 { +public: + typedef vdint3 self_type; + typedef int value_type; + + int& operator[](int k) { return v[k]; } + const int& operator[](int k) const { return v[k]; } + + int lensq() const { return x*x + y*y + z*z; } + int len() const { return (int)sqrtf((float)(x*x + y*y + z*z)); } + self_type normalized() const { return *this / len(); } + + vdint2 project() const { const int inv(int(1)/z); const vdint2 a = {x*inv, y*inv}; return a; } + vdint2 as2d() const { const vdint2 a = {x, y}; return a; } + + self_type operator-() const { const self_type a = {-x, -y, -z}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; return *this; } + + self_type operator*(const int s) const { const self_type a = {x*s, y*s, z*s}; return a; } + self_type& operator*=(const int s) { x*=s; y*=s; z*=s; return *this; } + + self_type operator/(const int s) const { const self_type a = {x/s, y/s, z/s}; return a; } + self_type& operator/=(const int s) { x /= s; y /= s; z /= s; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; return *this; } + + union { + struct { + int x; + int y; + int z; + }; + int v[3]; + }; +}; + +VDFORCEINLINE vdint3 operator*(const int s, const vdint3& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdint4 { +public: + typedef vdint4 self_type; + typedef int value_type; + + int& operator[](int i) { return v[i]; } + const int& operator[](int i) const { return v[i]; } + + int lensq() const { return x*x + y*y + z*z + w*w; } + int len() const { return (int)sqrtf((float)(x*x + y*y + z*z + w*w)); } + self_type normalized() const { return *this / len(); } + + vdint3 project() const { const int inv(int(1)/w); const vdint3 a = {x*inv, y*inv, z*inv}; return a; } + + self_type operator-() const { const self_type a = {-x, -y, -z, -w}; return a; } + + self_type operator+(const self_type& r) const { const self_type a = {x+r.x, y+r.y, z+r.z, w+r.w}; return a; } + self_type operator-(const self_type& r) const { const self_type a = {x-r.x, y-r.y, z-r.z, w-r.w}; return a; } + + self_type& operator+=(const self_type& r) { x+=r.x; y+=r.y; z+=r.z; w+=r.w; return *this; } + self_type& operator-=(const self_type& r) { x-=r.x; y-=r.y; z-=r.z; w-=r.w; return *this; } + + self_type operator*(const int factor) const { const self_type a = {x*factor, y*factor, z*factor, w*factor}; return a; } + self_type operator/(const int factor) const { const self_type a = {x/factor, y/factor, z/factor, w/factor}; return a; } + + self_type& operator*=(const int factor) { x *= factor; y *= factor; z *= factor; w *= factor; return *this; } + self_type& operator/=(const int factor) { x /= factor; y /= factor; z /= factor; w /= factor; return *this; } + + self_type operator*(const self_type& r) const { self_type a = {x*r.x, y*r.y, z*r.z, w*r.w}; return a; } + self_type& operator*=(const self_type& r) { x*=r.x; y*=r.y; z*=r.z; w*=r.w; return *this; } + + self_type operator/(const self_type& r) const { self_type a = {x/r.x, y/r.y, z/r.z, w*r.w}; return a; } + self_type& operator/=(const self_type& r) { x/=r.x; y/=r.y; z/=r.z; w/=r.w; return *this; } + + union { + struct { + int x; + int y; + int z; + int w; + }; + int v[4]; + }; +}; + +VDFORCEINLINE vdint4 operator*(const int s, const vdint4& v) { return v*s; } + +/////////////////////////////////////////////////////////////////////////// + +class vdint2c : vdint2 { +public: + VDFORCEINLINE vdint2c(int x2, int y2) {x=x2; y=y2;} + VDFORCEINLINE vdint2c(const int src[2]) {x=src[0]; y=src[1];} +}; + +class vdint3c : vdint3 { +public: + VDFORCEINLINE vdint3c(int x2, int y2, int z2) { x=x2; y=y2; z=z2; } + VDFORCEINLINE vdint3c(const int src[3]) { x=src[0]; y=src[1]; z=src[2]; } +}; + +class vdint4c : vdint4 { +public: + VDFORCEINLINE vdint4c(int x2, int y2, int z2, int w2) { x=x2; y=y2; z=z2; w=w2; } + VDFORCEINLINE vdint4c(const int src[4]) { x=src[0]; y=src[1]; z=src[2]; w=src[3]; } +}; + +/////////////////////////////////////////////////////////////////////////// + +namespace nsVDMath { + VDFORCEINLINE int dot(const vdint2& a, const vdint2& b) { + return a.x*b.x + a.y*b.y; + } + + VDFORCEINLINE int dot(const vdint3& a, const vdint3& b) { + return a.x*b.x + a.y*b.y + a.z*b.z; + } + + VDFORCEINLINE int dot(const vdint4& a, const vdint4& b) { + return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; + } + + VDFORCEINLINE vdint3 cross(const vdint3& a, const vdint3& b) { + const vdint3 r = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; + return r; + } +}; diff --git a/src/thirdparty/VirtualDub/h/vd2/system/w32assist.h b/src/thirdparty/VirtualDub/h/vd2/system/w32assist.h index a7b1cb2a2db..a92da8723b9 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/w32assist.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/w32assist.h @@ -1,107 +1,107 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_W32ASSIST_H -#define f_VD2_SYSTEM_W32ASSIST_H - -#include - -#include - -inline bool VDIsWindowsNT() { -#ifdef _M_AMD64 - return true; -#else - static bool is_nt = !(GetVersion() & 0x80000000); - - return is_nt; -#endif -} - -inline bool VDIsAtLeastVistaW32() { - return (sint32)(::GetVersion() & 0x800000FF) >= 6; -} - -// useful constants missing from the Platform SDK - -enum { -#ifdef _M_AMD64 - MENUITEMINFO_SIZE_VERSION_400A = sizeof(MENUITEMINFOA), - MENUITEMINFO_SIZE_VERSION_400W = sizeof(MENUITEMINFOW) -#else - MENUITEMINFO_SIZE_VERSION_400A = (offsetof(MENUITEMINFOA, cch) + sizeof(UINT)), - MENUITEMINFO_SIZE_VERSION_400W = (offsetof(MENUITEMINFOW, cch) + sizeof(UINT)) -#endif -}; - -// helper functions - -bool VDIsForegroundTaskW32(); - -LPVOID VDConvertThreadToFiberW32(LPVOID parm); -void VDSwitchToFiberW32(LPVOID fiber); - -int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr); -void VDSetWindowTextW32(HWND hwnd, const wchar_t *s); -void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...); -VDStringA VDGetWindowTextAW32(HWND hwnd); -VDStringW VDGetWindowTextW32(HWND hwnd); -void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text); -bool VDAppendPopupMenuW32(HMENU hmenu, UINT flags, HMENU hmenuPopup, const wchar_t *text); -void VDAppendMenuSeparatorW32(HMENU hmenu); -void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked); -void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); -void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked); -void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); -void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); -VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd); -void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text); - -LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - -EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags); - -bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod); -bool VDGetFileSizeW32(HANDLE h, sint64& size); - -#if !defined(_MSC_VER) || _MSC_VER < 1300 - HMODULE VDGetLocalModuleHandleW32(); -#else - extern "C" IMAGE_DOS_HEADER __ImageBase; - inline HMODULE VDGetLocalModuleHandleW32() { - return (HINSTANCE)&__ImageBase; - } -#endif - -bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat); - -bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue); -bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue); - -/// Load a library from the Windows system directory. -HMODULE VDLoadSystemLibraryW32(const char *name); - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_W32ASSIST_H +#define f_VD2_SYSTEM_W32ASSIST_H + +#include + +#include + +inline bool VDIsWindowsNT() { +#ifdef _M_AMD64 + return true; +#else + static bool is_nt = !(GetVersion() & 0x80000000); + + return is_nt; +#endif +} + +inline bool VDIsAtLeastVistaW32() { + return (sint32)(::GetVersion() & 0x800000FF) >= 6; +} + +// useful constants missing from the Platform SDK + +enum { +#ifdef _M_AMD64 + MENUITEMINFO_SIZE_VERSION_400A = sizeof(MENUITEMINFOA), + MENUITEMINFO_SIZE_VERSION_400W = sizeof(MENUITEMINFOW) +#else + MENUITEMINFO_SIZE_VERSION_400A = (offsetof(MENUITEMINFOA, cch) + sizeof(UINT)), + MENUITEMINFO_SIZE_VERSION_400W = (offsetof(MENUITEMINFOW, cch) + sizeof(UINT)) +#endif +}; + +// helper functions + +bool VDIsForegroundTaskW32(); + +LPVOID VDConvertThreadToFiberW32(LPVOID parm); +void VDSwitchToFiberW32(LPVOID fiber); + +int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr); +void VDSetWindowTextW32(HWND hwnd, const wchar_t *s); +void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...); +VDStringA VDGetWindowTextAW32(HWND hwnd); +VDStringW VDGetWindowTextW32(HWND hwnd); +void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text); +bool VDAppendPopupMenuW32(HMENU hmenu, UINT flags, HMENU hmenuPopup, const wchar_t *text); +void VDAppendMenuSeparatorW32(HMENU hmenu); +void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked); +void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); +void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked); +void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); +void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked); +VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd); +void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text); + +LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags); + +bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod); +bool VDGetFileSizeW32(HANDLE h, sint64& size); + +#if !defined(_MSC_VER) || _MSC_VER < 1300 + HMODULE VDGetLocalModuleHandleW32(); +#else + extern "C" IMAGE_DOS_HEADER __ImageBase; + inline HMODULE VDGetLocalModuleHandleW32() { + return (HINSTANCE)&__ImageBase; + } +#endif + +bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat); + +bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue); +bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue); + +/// Load a library from the Windows system directory. +HMODULE VDLoadSystemLibraryW32(const char *name); + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/win32/intrin.h b/src/thirdparty/VirtualDub/h/vd2/system/win32/intrin.h index 0566fa5ce52..d0597a24544 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/win32/intrin.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/win32/intrin.h @@ -1,56 +1,56 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2011 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_WIN32_INTRIN_H -#define f_VD2_SYSTEM_WIN32_INTRIN_H - -#pragma once - -// The Windows SDK conflicts with the VS2005 declaration of a couple -// of intrinsics starting with the Vista SDK. The conflict is between -// intrin.h and winnt.h. To work around this, we wrap intrin.h and -// rename its declaration. -#pragma push_macro("_interlockedbittestandset") -#pragma push_macro("_interlockedbittestandreset") -#pragma push_macro("_interlockedbittestandset64") -#pragma push_macro("_interlockedbittestandreset64") - -#define _interlockedbittestandset _interlockedbittestandset_vc -#define _interlockedbittestandreset _interlockedbittestandreset_vc -#define _interlockedbittestandset64 _interlockedbittestandset64_vc -#define _interlockedbittestandreset64 _interlockedbittestandreset64_vc - -#ifdef _MSC_VER - #include -#else - #include -#endif - -#pragma pop_macro("_interlockedbittestandreset64") -#pragma pop_macro("_interlockedbittestandset64") -#pragma pop_macro("_interlockedbittestandreset") -#pragma pop_macro("_interlockedbittestandset") - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2011 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_WIN32_INTRIN_H +#define f_VD2_SYSTEM_WIN32_INTRIN_H + +#pragma once + +// The Windows SDK conflicts with the VS2005 declaration of a couple +// of intrinsics starting with the Vista SDK. The conflict is between +// intrin.h and winnt.h. To work around this, we wrap intrin.h and +// rename its declaration. +#pragma push_macro("_interlockedbittestandset") +#pragma push_macro("_interlockedbittestandreset") +#pragma push_macro("_interlockedbittestandset64") +#pragma push_macro("_interlockedbittestandreset64") + +#define _interlockedbittestandset _interlockedbittestandset_vc +#define _interlockedbittestandreset _interlockedbittestandreset_vc +#define _interlockedbittestandset64 _interlockedbittestandset64_vc +#define _interlockedbittestandreset64 _interlockedbittestandreset64_vc + +#ifdef _MSC_VER + #include +#else + #include +#endif + +#pragma pop_macro("_interlockedbittestandreset64") +#pragma pop_macro("_interlockedbittestandset64") +#pragma pop_macro("_interlockedbittestandreset") +#pragma pop_macro("_interlockedbittestandset") + +#endif diff --git a/src/thirdparty/VirtualDub/h/vd2/system/win32/miniwindows.h b/src/thirdparty/VirtualDub/h/vd2/system/win32/miniwindows.h index c5426049965..fb8f8a667d3 100644 --- a/src/thirdparty/VirtualDub/h/vd2/system/win32/miniwindows.h +++ b/src/thirdparty/VirtualDub/h/vd2/system/win32/miniwindows.h @@ -1,61 +1,61 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#ifndef f_VD2_SYSTEM_WIN32_MINIWINDOWS_H -#define f_VD2_SYSTEM_WIN32_MINIWINDOWS_H - -#define VDZCALLBACK __stdcall - -#ifndef _WIN64 - #ifdef VD_COMPILER_MSVC - typedef __w64 int VDZINT_PTR; - typedef __w64 unsigned VDZUINT_PTR; - typedef __w64 long VDZLONG_PTR; - #else - typedef int VDZINT_PTR; - typedef unsigned VDZUINT_PTR; - typedef long VDZLONG_PTR; - #endif -#else - typedef __int64 VDZINT_PTR; - typedef unsigned __int64 VDZUINT_PTR; - typedef __int64 VDZLONG_PTR; -#endif - -typedef struct HWND__ *VDZHWND; -typedef struct HDC__ *VDZHDC; -typedef struct HKEY__ *VDZHKEY; -typedef unsigned VDZUINT; -typedef unsigned short VDZWORD; -typedef unsigned long VDZDWORD; -typedef VDZUINT_PTR VDZWPARAM; -typedef VDZLONG_PTR VDZLPARAM; -typedef VDZLONG_PTR VDZLRESULT; -typedef struct HDROP__ *VDZHDROP; -typedef struct HACCEL__ *VDZHACCEL; - -typedef VDZWORD VDZATOM; - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#ifndef f_VD2_SYSTEM_WIN32_MINIWINDOWS_H +#define f_VD2_SYSTEM_WIN32_MINIWINDOWS_H + +#define VDZCALLBACK __stdcall + +#ifndef _WIN64 + #ifdef VD_COMPILER_MSVC + typedef __w64 int VDZINT_PTR; + typedef __w64 unsigned VDZUINT_PTR; + typedef __w64 long VDZLONG_PTR; + #else + typedef int VDZINT_PTR; + typedef unsigned VDZUINT_PTR; + typedef long VDZLONG_PTR; + #endif +#else + typedef __int64 VDZINT_PTR; + typedef unsigned __int64 VDZUINT_PTR; + typedef __int64 VDZLONG_PTR; +#endif + +typedef struct HWND__ *VDZHWND; +typedef struct HDC__ *VDZHDC; +typedef struct HKEY__ *VDZHKEY; +typedef unsigned VDZUINT; +typedef unsigned short VDZWORD; +typedef unsigned long VDZDWORD; +typedef VDZUINT_PTR VDZWPARAM; +typedef VDZLONG_PTR VDZLPARAM; +typedef VDZLONG_PTR VDZLRESULT; +typedef struct HDROP__ *VDZHDROP; +typedef struct HACCEL__ *VDZHACCEL; + +typedef VDZWORD VDZATOM; + +#endif diff --git a/src/thirdparty/VirtualDub/system/h/stdafx.h b/src/thirdparty/VirtualDub/system/h/stdafx.h index 1af05fa819f..24638d54925 100644 --- a/src/thirdparty/VirtualDub/system/h/stdafx.h +++ b/src/thirdparty/VirtualDub/system/h/stdafx.h @@ -1,36 +1,36 @@ -// Force C locale to avoid this warning: -// -// mmreg.h : warning C4819: The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss -#pragma setlocale("C") - -/* MPC-HC comment out -// Detect the Windows SDK in use and select Windows 2000 baseline -// if the Vista SDK, else Windows 98 baseline. -#ifdef _MSC_VER -#include -#else -#define VER_PRODUCTBUILD 6001 -#endif -#if VER_PRODUCTBUILD > 6000 -#define _WIN32_WINNT 0x0500 -#else -#define _WIN32_WINNT 0x0410 -#endif -*/ - -// Start patch MPC-HC -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif -// End patch MPC-HC - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +// Force C locale to avoid this warning: +// +// mmreg.h : warning C4819: The file contains a character that cannot be represented in the current code page (932). Save the file in Unicode format to prevent data loss +#pragma setlocale("C") + +/* MPC-HC comment out +// Detect the Windows SDK in use and select Windows 2000 baseline +// if the Vista SDK, else Windows 98 baseline. +#ifdef _MSC_VER +#include +#else +#define VER_PRODUCTBUILD 6001 +#endif +#if VER_PRODUCTBUILD > 6000 +#define _WIN32_WINNT 0x0500 +#else +#define _WIN32_WINNT 0x0410 +#endif +*/ + +// Start patch MPC-HC +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +// End patch MPC-HC + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/thirdparty/VirtualDub/system/source/Error.cpp b/src/thirdparty/VirtualDub/system/source/Error.cpp index 2b379d59fc9..17f856a46f3 100644 --- a/src/thirdparty/VirtualDub/system/source/Error.cpp +++ b/src/thirdparty/VirtualDub/system/source/Error.cpp @@ -1,149 +1,149 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include -#include - -MyError::MyError() { - buf = NULL; -} - -MyError::MyError(const MyError& err) { - buf = _strdup(err.buf); -} - -MyError::MyError(const char *f, ...) - : buf(NULL) -{ - va_list val; - - va_start(val, f); - vsetf(f, val); - va_end(val); -} - -MyError::~MyError() { - free(buf); -} - -void MyError::clear() { - if (buf) // we do this check because debug free() always does a heapchk even if buf==NULL - free(buf); - buf = NULL; -} - -void MyError::assign(const MyError& e) { - if (buf) - free(buf); - buf = _strdup(e.buf); -} - -void MyError::assign(const char *s) { - if (buf) - free(buf); - buf = _strdup(s); -} - -void MyError::setf(const char *f, ...) { - va_list val; - - va_start(val, f); - vsetf(f,val); - va_end(val); -} - -void MyError::vsetf(const char *f, va_list val) { - for(int size = 1024; size <= 32768; size += size) { - free(buf); - buf = NULL; - - buf = (char *)malloc(size); - if (!buf) - return; - - if ((unsigned)_vsnprintf(buf, size, f, val) < (unsigned)size) - return; - } - - free(buf); - buf = NULL; -} - -void MyError::post(HWND hWndParent, const char *title) const { - if (!buf || !*buf) - return; - - VDDEBUG("*** %s: %s\n", title, buf); - //VDLog(kVDLogError, VDswprintf(L"Error: %hs", 1, &buf)); - - MessageBox(hWndParent, buf, title, MB_OK | MB_ICONERROR | MB_SETFOREGROUND); -} - -void MyError::discard() { - free(buf); - buf = NULL; -} - -void MyError::swap(MyError& err) { - char *s = err.buf; - err.buf = buf; - buf = s; -} - -void MyError::TransferFrom(MyError& err) { - if (buf) - free(buf); - - buf = err.buf; - err.buf = NULL; -} - -MyMemoryError::MyMemoryError() { - setf("Out of memory"); -} - -MyMemoryError::MyMemoryError(size_t requestedSize) { - setf("Out of memory (unable to allocate %llu bytes)", (unsigned long long)requestedSize); -} - -MyUserAbortError::MyUserAbortError() { - buf = _strdup(""); -} - -MyInternalError::MyInternalError(const char *format, ...) { - char buf[1024]; - va_list val; - - va_start(val, format); - _vsnprintf(buf, (sizeof buf) - 1, format, val); - buf[1023] = 0; - va_end(val); - - setf("Internal error: %s", buf); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +#include +#include + +MyError::MyError() { + buf = NULL; +} + +MyError::MyError(const MyError& err) { + buf = _strdup(err.buf); +} + +MyError::MyError(const char *f, ...) + : buf(NULL) +{ + va_list val; + + va_start(val, f); + vsetf(f, val); + va_end(val); +} + +MyError::~MyError() { + free(buf); +} + +void MyError::clear() { + if (buf) // we do this check because debug free() always does a heapchk even if buf==NULL + free(buf); + buf = NULL; +} + +void MyError::assign(const MyError& e) { + if (buf) + free(buf); + buf = _strdup(e.buf); +} + +void MyError::assign(const char *s) { + if (buf) + free(buf); + buf = _strdup(s); +} + +void MyError::setf(const char *f, ...) { + va_list val; + + va_start(val, f); + vsetf(f,val); + va_end(val); +} + +void MyError::vsetf(const char *f, va_list val) { + for(int size = 1024; size <= 32768; size += size) { + free(buf); + buf = NULL; + + buf = (char *)malloc(size); + if (!buf) + return; + + if ((unsigned)_vsnprintf(buf, size, f, val) < (unsigned)size) + return; + } + + free(buf); + buf = NULL; +} + +void MyError::post(HWND hWndParent, const char *title) const { + if (!buf || !*buf) + return; + + VDDEBUG("*** %s: %s\n", title, buf); + //VDLog(kVDLogError, VDswprintf(L"Error: %hs", 1, &buf)); + + MessageBox(hWndParent, buf, title, MB_OK | MB_ICONERROR | MB_SETFOREGROUND); +} + +void MyError::discard() { + free(buf); + buf = NULL; +} + +void MyError::swap(MyError& err) { + char *s = err.buf; + err.buf = buf; + buf = s; +} + +void MyError::TransferFrom(MyError& err) { + if (buf) + free(buf); + + buf = err.buf; + err.buf = NULL; +} + +MyMemoryError::MyMemoryError() { + setf("Out of memory"); +} + +MyMemoryError::MyMemoryError(size_t requestedSize) { + setf("Out of memory (unable to allocate %llu bytes)", (unsigned long long)requestedSize); +} + +MyUserAbortError::MyUserAbortError() { + buf = _strdup(""); +} + +MyInternalError::MyInternalError(const char *format, ...) { + char buf[1024]; + va_list val; + + va_start(val, format); + _vsnprintf(buf, (sizeof buf) - 1, format, val); + buf[1023] = 0; + va_end(val); + + setf("Internal error: %s", buf); +} diff --git a/src/thirdparty/VirtualDub/system/source/Fraction.cpp b/src/thirdparty/VirtualDub/system/source/Fraction.cpp index be7c1e7e065..cac7da91d10 100644 --- a/src/thirdparty/VirtualDub/system/source/Fraction.cpp +++ b/src/thirdparty/VirtualDub/system/source/Fraction.cpp @@ -1,327 +1,327 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -#include -#include -#include - -VDFraction::VDFraction(double d) { - int xp; - double mant = frexp(d, &xp); - - if (xp >= 33) { - hi = 0xFFFFFFFF; - lo = 1; - } else if (xp < -31) { - hi = 0; - lo = 1; - } else if (xp >= 0) { - *this = reduce((uint64)(0.5 + ldexp(mant, 62)), 1ll<<(62-xp)); - } else { - // This is not quite accurate for very tiny numbers. - VDFraction t(1.0 / d); - lo = t.hi; - hi = t.lo; - } -} - -VDFraction VDFraction::reduce(uint64 hi, uint64 lo) { - - // Check for undefined. - - if (!lo) - return VDFraction(0,0); - - // Check for zero. - - if (!hi) { - return VDFraction(0,1); - } - - // Check for infinity. - - if (!((uint64)lo>>32) && (uint64)hi > ((uint64)lo<<32)-lo) - return VDFraction(0xFFFFFFFFUL, 1); - - // Algorithm from Wikipedia, Continued Fractions: - uint64 n0 = 0; - uint64 d0 = 1; - uint32 n1 = 1; - uint32 d1 = 0; - uint64 fp = 0; - - uint32 n_best; - uint32 d_best; - - for(;;) { - uint64 a = hi/lo; // next continued fraction term - uint64 f = hi%lo; // remainder - - uint64 n2 = n0 + n1*a; // next convergent numerator - uint64 d2 = d0 + d1*a; // next convergent denominator - - uint32 n_overflow = (uint32)(n2 >> 32); - uint32 d_overflow = (uint32)(d2 >> 32); - - if (n_overflow | d_overflow) { - uint64 a2 = a; - - // reduce last component until numerator and denominator are within range - if (n_overflow) - a2 = (0xFFFFFFFF - n0) / n1; - - if (d_overflow) { - uint64 a3 = (0xFFFFFFFF - d0) / d1; - if (a2 > a3) - a2 = a3; - } - - // check if new term is better - // 1/2a_k admissibility test - if (a2*2 < a || (a2*2 == a && d0*fp <= f*d1)) - return VDFraction((uint32)n_best, (uint32)d_best); - - return VDFraction((uint32)(n0 + n1*a2), (uint32)(d0 + d1*a2)); - } - - n_best = (uint32)n2; - d_best = (uint32)d2; - - // if fraction is exact, we're done. - if (!f) - return VDFraction((uint32)n_best, (uint32)d_best); - - n0 = n1; - n1 = (uint32)n2; - d0 = d1; - d1 = (uint32)d2; - fp = f; - - hi = lo; - lo = f; - } -} - -// a (cond) b -// a-b (cond) 0 -// aH*bL - aL*bh (cond) 0 -// aH*bL (cond) aL*bH - -bool VDFraction::operator==(VDFraction b) const { - return (uint64)hi * b.lo == (uint64)lo * b.hi; -} - -bool VDFraction::operator!=(VDFraction b) const { - return (uint64)hi * b.lo != (uint64)lo * b.hi; -} - -bool VDFraction::operator< (VDFraction b) const { - return (uint64)hi * b.lo < (uint64)lo * b.hi; -} - -bool VDFraction::operator<=(VDFraction b) const { - return (uint64)hi * b.lo <= (uint64)lo * b.hi; -} - -bool VDFraction::operator> (VDFraction b) const { - return (uint64)hi * b.lo > (uint64)lo * b.hi; -} - -bool VDFraction::operator>=(VDFraction b) const { - return (uint64)hi * b.lo >= (uint64)lo * b.hi; -} - -VDFraction VDFraction::operator*(VDFraction b) const { - return reduce((uint64)hi * b.hi, (uint64)lo * b.lo); -} - -VDFraction VDFraction::operator/(VDFraction b) const { - return reduce((uint64)hi * b.lo, (uint64)lo * b.hi); -} - -VDFraction VDFraction::operator*(unsigned long b) const { - return reduce((uint64)hi * b, lo); -} - -VDFraction VDFraction::operator/(unsigned long b) const { - return reduce(hi, (uint64)lo * b); -} - -VDFraction& VDFraction::operator*=(VDFraction b) { - return *this = reduce((uint64)hi * b.hi, (uint64)lo * b.lo); -} - -VDFraction& VDFraction::operator/=(VDFraction b) { - return *this = reduce((uint64)hi * b.lo, (uint64)lo * b.hi); -} - -VDFraction& VDFraction::operator*=(unsigned long b) { - return *this = reduce((uint64)hi * b, lo); -} - -VDFraction& VDFraction::operator/=(unsigned long b) { - return *this = reduce(hi, (uint64)lo * b); -} - -/////////////////////////////////////////////////////////////////////////// - -sint64 VDFraction::scale64t(sint64 v) const { - uint32 r; - return v<0 ? -VDFractionScale64(-v, hi, lo, r) : VDFractionScale64(v, hi, lo, r); -} - -sint64 VDFraction::scale64u(sint64 v) const { - uint32 r; - if (v<0) { - v = -VDFractionScale64(-v, hi, lo, r); - return v; - } else { - v = +VDFractionScale64(+v, hi, lo, r); - return v + (r > 0); - } -} - -sint64 VDFraction::scale64r(sint64 v) const { - uint32 r; - if (v<0) { - v = -VDFractionScale64(-v, hi, lo, r); - return v - (r >= (lo>>1) + (lo&1)); - } else { - v = +VDFractionScale64(+v, hi, lo, r); - return v + (r >= (lo>>1) + (lo&1)); - } -} - -sint64 VDFraction::scale64it(sint64 v) const { - uint32 r; - return v<0 ? -VDFractionScale64(-v, lo, hi, r) : +VDFractionScale64(+v, lo, hi, r); -} - -sint64 VDFraction::scale64ir(sint64 v) const { - uint32 r; - if (v<0) { - v = -VDFractionScale64(-v, lo, hi, r); - return v - (r >= (hi>>1) + (hi&1)); - } else { - v = +VDFractionScale64(+v, lo, hi, r); - return v + (r >= (hi>>1) + (hi&1)); - } -} - -sint64 VDFraction::scale64iu(sint64 v) const { - uint32 r; - if (v<0) { - v = -VDFractionScale64(-v, lo, hi, r); - return v; - } else { - v = +VDFractionScale64(+v, lo, hi, r); - return v + (r > 0); - } -} - -/////////////////////////////////////////////////////////////////////////// - -double VDFraction::asDouble() const { - return (double)hi / (double)lo; -} - -double VDFraction::AsInverseDouble() const { - return (double)lo / (double)hi; -} - -unsigned long VDFraction::roundup32ul() const { - return (hi + (lo-1)) / lo; -} - -/////////////////////////////////////////////////////////////////////////// - -bool VDFraction::Parse(const char *s) { - char c; - - // skip whitespace - while((c = *s) && (c == ' ' || c == '\t')) - ++s; - - // accumulate integer digits - uint64 x = 0; - uint64 y = 1; - - while(c = *s) { - uint32 offset = (uint32)c - '0'; - - if (offset >= 10) - break; - - x = (x * 10) + offset; - - // check for overflow - if (x >> 32) - return false; - - ++s; - } - - if (c == '.') { - ++s; - - while(c = *s) { - uint32 offset = (uint32)c - '0'; - - if (offset >= 10) - break; - - if (x >= 100000000000000000 || - y >= 100000000000000000) { - if (offset >= 5) - ++x; - while((c = *s) && (unsigned)(c - '0') < 10) - ++s; - break; - } - - x = (x * 10) + offset; - y *= 10; - ++s; - } - } - - while(c == ' ' || c == '\t') - c = *++s; - - // check for trailing garbage - if (c) - return false; - - // check for overflow - if (!(y >> 32) && ((uint64)(uint32)y << 32) <= x) - return false; - - // reduce fraction and return success - *this = reduce(x, y); - return true; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include +#include +#include + +VDFraction::VDFraction(double d) { + int xp; + double mant = frexp(d, &xp); + + if (xp >= 33) { + hi = 0xFFFFFFFF; + lo = 1; + } else if (xp < -31) { + hi = 0; + lo = 1; + } else if (xp >= 0) { + *this = reduce((uint64)(0.5 + ldexp(mant, 62)), 1ll<<(62-xp)); + } else { + // This is not quite accurate for very tiny numbers. + VDFraction t(1.0 / d); + lo = t.hi; + hi = t.lo; + } +} + +VDFraction VDFraction::reduce(uint64 hi, uint64 lo) { + + // Check for undefined. + + if (!lo) + return VDFraction(0,0); + + // Check for zero. + + if (!hi) { + return VDFraction(0,1); + } + + // Check for infinity. + + if (!((uint64)lo>>32) && (uint64)hi > ((uint64)lo<<32)-lo) + return VDFraction(0xFFFFFFFFUL, 1); + + // Algorithm from Wikipedia, Continued Fractions: + uint64 n0 = 0; + uint64 d0 = 1; + uint32 n1 = 1; + uint32 d1 = 0; + uint64 fp = 0; + + uint32 n_best; + uint32 d_best; + + for(;;) { + uint64 a = hi/lo; // next continued fraction term + uint64 f = hi%lo; // remainder + + uint64 n2 = n0 + n1*a; // next convergent numerator + uint64 d2 = d0 + d1*a; // next convergent denominator + + uint32 n_overflow = (uint32)(n2 >> 32); + uint32 d_overflow = (uint32)(d2 >> 32); + + if (n_overflow | d_overflow) { + uint64 a2 = a; + + // reduce last component until numerator and denominator are within range + if (n_overflow) + a2 = (0xFFFFFFFF - n0) / n1; + + if (d_overflow) { + uint64 a3 = (0xFFFFFFFF - d0) / d1; + if (a2 > a3) + a2 = a3; + } + + // check if new term is better + // 1/2a_k admissibility test + if (a2*2 < a || (a2*2 == a && d0*fp <= f*d1)) + return VDFraction((uint32)n_best, (uint32)d_best); + + return VDFraction((uint32)(n0 + n1*a2), (uint32)(d0 + d1*a2)); + } + + n_best = (uint32)n2; + d_best = (uint32)d2; + + // if fraction is exact, we're done. + if (!f) + return VDFraction((uint32)n_best, (uint32)d_best); + + n0 = n1; + n1 = (uint32)n2; + d0 = d1; + d1 = (uint32)d2; + fp = f; + + hi = lo; + lo = f; + } +} + +// a (cond) b +// a-b (cond) 0 +// aH*bL - aL*bh (cond) 0 +// aH*bL (cond) aL*bH + +bool VDFraction::operator==(VDFraction b) const { + return (uint64)hi * b.lo == (uint64)lo * b.hi; +} + +bool VDFraction::operator!=(VDFraction b) const { + return (uint64)hi * b.lo != (uint64)lo * b.hi; +} + +bool VDFraction::operator< (VDFraction b) const { + return (uint64)hi * b.lo < (uint64)lo * b.hi; +} + +bool VDFraction::operator<=(VDFraction b) const { + return (uint64)hi * b.lo <= (uint64)lo * b.hi; +} + +bool VDFraction::operator> (VDFraction b) const { + return (uint64)hi * b.lo > (uint64)lo * b.hi; +} + +bool VDFraction::operator>=(VDFraction b) const { + return (uint64)hi * b.lo >= (uint64)lo * b.hi; +} + +VDFraction VDFraction::operator*(VDFraction b) const { + return reduce((uint64)hi * b.hi, (uint64)lo * b.lo); +} + +VDFraction VDFraction::operator/(VDFraction b) const { + return reduce((uint64)hi * b.lo, (uint64)lo * b.hi); +} + +VDFraction VDFraction::operator*(unsigned long b) const { + return reduce((uint64)hi * b, lo); +} + +VDFraction VDFraction::operator/(unsigned long b) const { + return reduce(hi, (uint64)lo * b); +} + +VDFraction& VDFraction::operator*=(VDFraction b) { + return *this = reduce((uint64)hi * b.hi, (uint64)lo * b.lo); +} + +VDFraction& VDFraction::operator/=(VDFraction b) { + return *this = reduce((uint64)hi * b.lo, (uint64)lo * b.hi); +} + +VDFraction& VDFraction::operator*=(unsigned long b) { + return *this = reduce((uint64)hi * b, lo); +} + +VDFraction& VDFraction::operator/=(unsigned long b) { + return *this = reduce(hi, (uint64)lo * b); +} + +/////////////////////////////////////////////////////////////////////////// + +sint64 VDFraction::scale64t(sint64 v) const { + uint32 r; + return v<0 ? -VDFractionScale64(-v, hi, lo, r) : VDFractionScale64(v, hi, lo, r); +} + +sint64 VDFraction::scale64u(sint64 v) const { + uint32 r; + if (v<0) { + v = -VDFractionScale64(-v, hi, lo, r); + return v; + } else { + v = +VDFractionScale64(+v, hi, lo, r); + return v + (r > 0); + } +} + +sint64 VDFraction::scale64r(sint64 v) const { + uint32 r; + if (v<0) { + v = -VDFractionScale64(-v, hi, lo, r); + return v - (r >= (lo>>1) + (lo&1)); + } else { + v = +VDFractionScale64(+v, hi, lo, r); + return v + (r >= (lo>>1) + (lo&1)); + } +} + +sint64 VDFraction::scale64it(sint64 v) const { + uint32 r; + return v<0 ? -VDFractionScale64(-v, lo, hi, r) : +VDFractionScale64(+v, lo, hi, r); +} + +sint64 VDFraction::scale64ir(sint64 v) const { + uint32 r; + if (v<0) { + v = -VDFractionScale64(-v, lo, hi, r); + return v - (r >= (hi>>1) + (hi&1)); + } else { + v = +VDFractionScale64(+v, lo, hi, r); + return v + (r >= (hi>>1) + (hi&1)); + } +} + +sint64 VDFraction::scale64iu(sint64 v) const { + uint32 r; + if (v<0) { + v = -VDFractionScale64(-v, lo, hi, r); + return v; + } else { + v = +VDFractionScale64(+v, lo, hi, r); + return v + (r > 0); + } +} + +/////////////////////////////////////////////////////////////////////////// + +double VDFraction::asDouble() const { + return (double)hi / (double)lo; +} + +double VDFraction::AsInverseDouble() const { + return (double)lo / (double)hi; +} + +unsigned long VDFraction::roundup32ul() const { + return (hi + (lo-1)) / lo; +} + +/////////////////////////////////////////////////////////////////////////// + +bool VDFraction::Parse(const char *s) { + char c; + + // skip whitespace + while((c = *s) && (c == ' ' || c == '\t')) + ++s; + + // accumulate integer digits + uint64 x = 0; + uint64 y = 1; + + while(c = *s) { + uint32 offset = (uint32)c - '0'; + + if (offset >= 10) + break; + + x = (x * 10) + offset; + + // check for overflow + if (x >> 32) + return false; + + ++s; + } + + if (c == '.') { + ++s; + + while(c = *s) { + uint32 offset = (uint32)c - '0'; + + if (offset >= 10) + break; + + if (x >= 100000000000000000 || + y >= 100000000000000000) { + if (offset >= 5) + ++x; + while((c = *s) && (unsigned)(c - '0') < 10) + ++s; + break; + } + + x = (x * 10) + offset; + y *= 10; + ++s; + } + } + + while(c == ' ' || c == '\t') + c = *++s; + + // check for trailing garbage + if (c) + return false; + + // check for overflow + if (!(y >> 32) && ((uint64)(uint32)y << 32) <= x) + return false; + + // reduce fraction and return success + *this = reduce(x, y); + return true; +} diff --git a/src/thirdparty/VirtualDub/system/source/VDNamespace.cpp b/src/thirdparty/VirtualDub/system/source/VDNamespace.cpp index 91b7c8dd250..6098dc77d90 100644 --- a/src/thirdparty/VirtualDub/system/source/VDNamespace.cpp +++ b/src/thirdparty/VirtualDub/system/source/VDNamespace.cpp @@ -1,253 +1,253 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// -// Group -// -/////////////////////////////////////////////////////////////////////////// - -VDNamespaceGroup::VDNamespaceGroup(const char *_pszName, VDNamespaceGroup *parent) -: VDNamespaceNode(namedup(_pszName),parent) -{ - const char *t = strchr(_pszName,'/'); - - if (t) { - - } else - strcpy((char *)pszName, _pszName); -} - -VDNamespaceGroup::~VDNamespaceGroup() { - delete[] (char *)pszName; -} - -const char *VDNamespaceGroup::namedup(const char *s) { - const char *t = strchr(s,'/'); - char *mem; - - if (t) { - mem = new char[(t-s)+1]; - - memcpy(mem, s, (t-s)); - mem[t-s] = 0; - - return mem; - } else { - mem = new char[strlen(s)+1]; - - return strcpy(mem, s); - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// Item -// -/////////////////////////////////////////////////////////////////////////// - -VDNamespaceItem::VDNamespaceItem(const char *_pszName, VDNamespaceGroup *parent, const void *src) -: VDNamespaceNode(_pszName,parent), object(src) -{} - -VDNamespaceItem::~VDNamespaceItem() {} - -/////////////////////////////////////////////////////////////////////////// -// -// VDNamespace -// -/////////////////////////////////////////////////////////////////////////// - -bool VDNamespaceCompare(const char *psz1, const char *psz2) { - char c, d; - - while((!!(c=toupper(*psz1++)) & !!(d=toupper(*psz2++))) && c!='/' && d!='/' && c==d) - ; - - if (c=='/') c=0; - if (d=='/') d=0; - - return c==d; -} - -VDNamespace::VDNamespace() : root("", NULL) { -} - -VDNamespace::~VDNamespace() { -} - -VDNamespaceGroup *VDNamespace::_lookupGroup(const char *pszName, bool fCreate, bool fIsFilter) { - const char *pszNameLimit = pszName; - const char *slash = NULL; - VDNamespaceGroup *pGroup = &root, *pGroupNext; - - while(*pszNameLimit) { - if (*pszNameLimit++ == '/') - slash = pszNameLimit - 1; - } - - if (fIsFilter) - pszNameLimit = slash; - - while(pszName < pszNameLimit) { - VDNamespaceGroup *pGroupParent = pGroup; - - pGroup = pGroup->listGroups.AtHead(); - - while(pGroupNext = pGroup->NextFromHead()) { - if (VDNamespaceCompare(pszName, pGroup->pszName)) - break; - - pGroup = pGroupNext; - } - - if (!pGroupNext && fCreate) { - pGroupNext = pGroup = new VDNamespaceGroup(pszName, pGroupParent); - - pGroupParent->listGroups.AddTail(pGroup); - } - - // group not found? - - if (!pGroupNext) { - return NULL; - } - - // advance to next slash - - while(*pszName && *pszName++!='/') - ; - } - - return pGroup; -} - -void VDNamespace::clear() { - root.listGroups.dispose(); - root.listItems.dispose(); -} - -void VDNamespace::add(const char *pszGroup, const char *pszName, const void *pDef) { - VDNamespaceGroup *pGroup = _lookupGroup(pszGroup, true, false); - - pGroup->listItems.AddTail(new VDNamespaceItem(pszName, pGroup, pDef)); -} - -const void *VDNamespace::lookup(const char *pszName) { - VDNamespaceGroup *pGroup = _lookupGroup(pszName, false, true); - - if (!pGroup) - return NULL; - - const char *pszNameBase = pszName; - - while(*pszName++) - if (pszName[-1]=='/') - pszNameBase = pszName; - - for(ListAlloc::fwit it = pGroup->listItems.begin(); it; ++it) - if (!_stricmp(it->pszName, pszNameBase)) - return it->object; - - return NULL; -} - -bool VDNamespace::enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData) { - VDNamespaceGroup *pGroup, *pGroupNext; - - pGroup = (pGroupRoot ? pGroupRoot : &root)->listGroups.AtHead(); - while(pGroupNext = pGroup->NextFromHead()) { - if (!pEnum(this, pGroup->pszName, pGroup, pvData)) - return false; - - pGroup = pGroupNext; - } - - return true; -} - -bool VDNamespace::enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData) { - VDNamespaceItem *pEntry, *pEntryNext; - - pEntry = pGroupRoot->listItems.AtHead(); - while(pEntryNext = pEntry->NextFromHead()) { - if (!pEnum(this, pEntry->pszName, pEntry->object, pvData)) - return false; - - pEntry = pEntryNext; - } - - return true; -} - -VDNamespaceItem *VDNamespace::_findItemByObject(const VDNamespaceGroup *pGroup, const void *pObj) { - for(ListAlloc::fwit it=pGroup->listItems.begin(); it; ++it) { - if (it->object == pObj) { - return it; - } - } - - for(ListAlloc::fwit it2=pGroup->listGroups.begin(); it2; ++it2) { - VDNamespaceItem *v; - - if (v = _findItemByObject(it2, pObj)) - return v; - } - - return NULL; -} - -bool VDNamespace::_getPathByItem(const VDNamespaceNode *pEntry, char *buf, int maxlen) { - if (!pEntry) - return false; - - if (maxlen < (int)strlen(pEntry->pszName)+2) - return false; - - if (pEntry->pParent && pEntry->pParent->pParent) { - if (!_getPathByItem(pEntry->pParent, buf, maxlen)) - return false; - - while(*buf) - ++buf, --maxlen; - - *buf++ = '/'; - } - - strcpy(buf, pEntry->pszName); - - return true; -} - -bool VDNamespace::getPathByItem(const void *pObj, char *buf, int maxlen) { - return _getPathByItem(_findItemByObject(&root, pObj), buf, maxlen); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// +// Group +// +/////////////////////////////////////////////////////////////////////////// + +VDNamespaceGroup::VDNamespaceGroup(const char *_pszName, VDNamespaceGroup *parent) +: VDNamespaceNode(namedup(_pszName),parent) +{ + const char *t = strchr(_pszName,'/'); + + if (t) { + + } else + strcpy((char *)pszName, _pszName); +} + +VDNamespaceGroup::~VDNamespaceGroup() { + delete[] (char *)pszName; +} + +const char *VDNamespaceGroup::namedup(const char *s) { + const char *t = strchr(s,'/'); + char *mem; + + if (t) { + mem = new char[(t-s)+1]; + + memcpy(mem, s, (t-s)); + mem[t-s] = 0; + + return mem; + } else { + mem = new char[strlen(s)+1]; + + return strcpy(mem, s); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// Item +// +/////////////////////////////////////////////////////////////////////////// + +VDNamespaceItem::VDNamespaceItem(const char *_pszName, VDNamespaceGroup *parent, const void *src) +: VDNamespaceNode(_pszName,parent), object(src) +{} + +VDNamespaceItem::~VDNamespaceItem() {} + +/////////////////////////////////////////////////////////////////////////// +// +// VDNamespace +// +/////////////////////////////////////////////////////////////////////////// + +bool VDNamespaceCompare(const char *psz1, const char *psz2) { + char c, d; + + while((!!(c=toupper(*psz1++)) & !!(d=toupper(*psz2++))) && c!='/' && d!='/' && c==d) + ; + + if (c=='/') c=0; + if (d=='/') d=0; + + return c==d; +} + +VDNamespace::VDNamespace() : root("", NULL) { +} + +VDNamespace::~VDNamespace() { +} + +VDNamespaceGroup *VDNamespace::_lookupGroup(const char *pszName, bool fCreate, bool fIsFilter) { + const char *pszNameLimit = pszName; + const char *slash = NULL; + VDNamespaceGroup *pGroup = &root, *pGroupNext; + + while(*pszNameLimit) { + if (*pszNameLimit++ == '/') + slash = pszNameLimit - 1; + } + + if (fIsFilter) + pszNameLimit = slash; + + while(pszName < pszNameLimit) { + VDNamespaceGroup *pGroupParent = pGroup; + + pGroup = pGroup->listGroups.AtHead(); + + while(pGroupNext = pGroup->NextFromHead()) { + if (VDNamespaceCompare(pszName, pGroup->pszName)) + break; + + pGroup = pGroupNext; + } + + if (!pGroupNext && fCreate) { + pGroupNext = pGroup = new VDNamespaceGroup(pszName, pGroupParent); + + pGroupParent->listGroups.AddTail(pGroup); + } + + // group not found? + + if (!pGroupNext) { + return NULL; + } + + // advance to next slash + + while(*pszName && *pszName++!='/') + ; + } + + return pGroup; +} + +void VDNamespace::clear() { + root.listGroups.dispose(); + root.listItems.dispose(); +} + +void VDNamespace::add(const char *pszGroup, const char *pszName, const void *pDef) { + VDNamespaceGroup *pGroup = _lookupGroup(pszGroup, true, false); + + pGroup->listItems.AddTail(new VDNamespaceItem(pszName, pGroup, pDef)); +} + +const void *VDNamespace::lookup(const char *pszName) { + VDNamespaceGroup *pGroup = _lookupGroup(pszName, false, true); + + if (!pGroup) + return NULL; + + const char *pszNameBase = pszName; + + while(*pszName++) + if (pszName[-1]=='/') + pszNameBase = pszName; + + for(ListAlloc::fwit it = pGroup->listItems.begin(); it; ++it) + if (!_stricmp(it->pszName, pszNameBase)) + return it->object; + + return NULL; +} + +bool VDNamespace::enumerateGroups(const VDNamespaceGroup *pGroupRoot, tGroupEnumerator pEnum, void *pvData) { + VDNamespaceGroup *pGroup, *pGroupNext; + + pGroup = (pGroupRoot ? pGroupRoot : &root)->listGroups.AtHead(); + while(pGroupNext = pGroup->NextFromHead()) { + if (!pEnum(this, pGroup->pszName, pGroup, pvData)) + return false; + + pGroup = pGroupNext; + } + + return true; +} + +bool VDNamespace::enumerateItems(const VDNamespaceGroup *pGroupRoot, tItemEnumerator pEnum, void *pvData) { + VDNamespaceItem *pEntry, *pEntryNext; + + pEntry = pGroupRoot->listItems.AtHead(); + while(pEntryNext = pEntry->NextFromHead()) { + if (!pEnum(this, pEntry->pszName, pEntry->object, pvData)) + return false; + + pEntry = pEntryNext; + } + + return true; +} + +VDNamespaceItem *VDNamespace::_findItemByObject(const VDNamespaceGroup *pGroup, const void *pObj) { + for(ListAlloc::fwit it=pGroup->listItems.begin(); it; ++it) { + if (it->object == pObj) { + return it; + } + } + + for(ListAlloc::fwit it2=pGroup->listGroups.begin(); it2; ++it2) { + VDNamespaceItem *v; + + if (v = _findItemByObject(it2, pObj)) + return v; + } + + return NULL; +} + +bool VDNamespace::_getPathByItem(const VDNamespaceNode *pEntry, char *buf, int maxlen) { + if (!pEntry) + return false; + + if (maxlen < (int)strlen(pEntry->pszName)+2) + return false; + + if (pEntry->pParent && pEntry->pParent->pParent) { + if (!_getPathByItem(pEntry->pParent, buf, maxlen)) + return false; + + while(*buf) + ++buf, --maxlen; + + *buf++ = '/'; + } + + strcpy(buf, pEntry->pszName); + + return true; +} + +bool VDNamespace::getPathByItem(const void *pObj, char *buf, int maxlen) { + return _getPathByItem(_findItemByObject(&root, pObj), buf, maxlen); +} diff --git a/src/thirdparty/VirtualDub/system/source/VDScheduler.cpp b/src/thirdparty/VirtualDub/system/source/VDScheduler.cpp index e4bdcafa517..caa0c6134d1 100644 --- a/src/thirdparty/VirtualDub/system/source/VDScheduler.cpp +++ b/src/thirdparty/VirtualDub/system/source/VDScheduler.cpp @@ -1,322 +1,322 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include -#include -#include - -VDScheduler::VDScheduler() - : mpErrorCB(NULL) - , pWakeupSignal(NULL) - , pParentSchedulerNode(NULL) - , mbExitThreads(false) -{ -} - -VDScheduler::~VDScheduler() { -} - -void VDScheduler::setSignal(VDSignal *pSignal) { - pWakeupSignal = pSignal; -} - -void VDScheduler::setSchedulerNode(VDSchedulerNode *pSchedulerNode) { - pParentSchedulerNode = pSchedulerNode; -} - -void VDScheduler::BeginShutdown() { - mbExitThreads = true; - Ping(); -} - -void VDScheduler::Repost(VDSchedulerNode *pNode, bool bReschedule) { - vdsynchronized(csScheduler) { - if (pNode->bCondemned) { - tSuspendList::iterator it(listSuspends.begin()), itEnd(listSuspends.end()); - - while(it!=itEnd) { - VDSchedulerSuspendNode *pSuspendNode = *it; - - if (pSuspendNode->mpNode == pNode) { - it = listSuspends.erase(it); - pSuspendNode->mSignal.signal(); - } else - ++it; - } - } else { - pNode->bRunning = false; - if (bReschedule || pNode->bReschedule) { - pNode->bReschedule = false; - pNode->bReady = true; - listReady.push_back(pNode); - } else - listWaiting.push_back(pNode); - } - } -} - -bool VDScheduler::Run() { - VDSchedulerNode *pNode = NULL; - vdsynchronized(csScheduler) { - if (!listReady.empty()) { - pNode = listReady.front(); - listReady.pop_front(); - pNode->bRunning = true; - pNode->bReady = false; - } - } - - if (!pNode) - return false; - - bool bReschedule; - try { - bReschedule = pNode->Service(); - } catch(MyError& e) { - Repost(pNode, false); - - vdsynchronized(csScheduler) { - if (mpErrorCB) { - if (!mpErrorCB->OnAsyncError(e)) - throw; - } - } - - return true; - } catch(...) { - Repost(pNode, false); - throw; - } - - Repost(pNode, bReschedule); - - return true; -} - -bool VDScheduler::IdleWait() { - if (mbExitThreads) - return false; - - if (pWakeupSignal) { -#if 0 - while(WAIT_TIMEOUT == WaitForSingleObject(pWakeupSignal->getHandle(), 1000)) - DumpStatus(); -#else - pWakeupSignal->wait(); -#endif - } - - return true; -} - -void VDScheduler::Ping() { - if (pWakeupSignal) - pWakeupSignal->signal(); -} - -void VDScheduler::Lock() { - ++csScheduler; -} - -void VDScheduler::Unlock() { - --csScheduler; -} - -void VDScheduler::Reschedule(VDSchedulerNode *pNode) { - VDCriticalSection::AutoLock lock(csScheduler); - - RescheduleFast(pNode); -} - -void VDScheduler::RescheduleFast(VDSchedulerNode *pNode) { - if (pNode->bReady) - return; - - pNode->bReady = true; - - if (pNode->bRunning) - pNode->bReschedule = true; - else { - if (pWakeupSignal) - pWakeupSignal->signal(); - - if (pParentSchedulerNode) - pParentSchedulerNode->Reschedule(); - - listWaiting.erase(pNode); - listReady.push_back(pNode); - } -} - -void VDScheduler::Add(VDSchedulerNode *pNode) { - VDASSERT(pNode); - - pNode->mpScheduler = this; - pNode->bRunning = false; - pNode->bReschedule = false; - pNode->bReady = true; - pNode->bCondemned = false; - - vdsynchronized(csScheduler) { - tNodeList::iterator it(listReady.begin()), itEnd(listReady.end()); - - while(it != itEnd && (*it)->nPriority <= pNode->nPriority) - ++it; - - listReady.insert(it, pNode); - } - - if (pWakeupSignal) - pWakeupSignal->signal(); - - if (pParentSchedulerNode) - pParentSchedulerNode->Reschedule(); -} - -void VDScheduler::Remove(VDSchedulerNode *pNode) { - VDASSERT(pNode); - - VDSchedulerSuspendNode suspendNode(pNode); - bool running = false; - - vdsynchronized(csScheduler) { - pNode->bCondemned = true; - if (pNode->bRunning) { - running = true; - listSuspends.push_back(&suspendNode); - } else if (pNode->bReady) - listReady.erase(pNode); - else - listWaiting.erase(pNode); - } - - if (running) - suspendNode.mSignal.wait(); -} - -void VDScheduler::DumpStatus() { - vdsynchronized(csScheduler) { - VDDEBUG2("\n Waiting nodes:\n"); - for(tNodeList::iterator it(listWaiting.begin()), itEnd(listWaiting.end()); it!=itEnd; ++it) - (*it)->DumpStatus(); - VDDEBUG2("\n Ready nodes:\n"); - for(tNodeList::iterator it2(listReady.begin()), it2End(listReady.end()); it2!=it2End; ++it2) - (*it2)->DumpStatus(); - } -} - -void VDSchedulerNode::DumpStatus() { - VDDEBUG2(" anonymous %p\n", this); -} - -/////////////////////////////////////////////////////////////////////////// - -VDSchedulerThread::VDSchedulerThread() - : VDThread("Scheduler thread") - , mpScheduler(NULL) -{ -} - -VDSchedulerThread::~VDSchedulerThread() { -} - -bool VDSchedulerThread::Start(VDScheduler *pScheduler) { - mpScheduler = pScheduler; - return VDThread::ThreadStart(); -} - -void VDSchedulerThread::ThreadRun() { - VDScheduler& scheduler = *mpScheduler; - - do { - while(scheduler.Run()) - ; - } while(scheduler.IdleWait()); - - scheduler.Ping(); -} - -/////////////////////////////////////////////////////////////////////////// - -VDSchedulerThreadPool::VDSchedulerThreadPool() - : mpThreads(NULL) - , mThreadCount(0) - , mThreadPriority(VDThread::kPriorityDefault) -{ -} - -VDSchedulerThreadPool::~VDSchedulerThreadPool() { - if (mpThreads) { - for(uint32 i=0; i +#include +#include +#include +#include + +VDScheduler::VDScheduler() + : mpErrorCB(NULL) + , pWakeupSignal(NULL) + , pParentSchedulerNode(NULL) + , mbExitThreads(false) +{ +} + +VDScheduler::~VDScheduler() { +} + +void VDScheduler::setSignal(VDSignal *pSignal) { + pWakeupSignal = pSignal; +} + +void VDScheduler::setSchedulerNode(VDSchedulerNode *pSchedulerNode) { + pParentSchedulerNode = pSchedulerNode; +} + +void VDScheduler::BeginShutdown() { + mbExitThreads = true; + Ping(); +} + +void VDScheduler::Repost(VDSchedulerNode *pNode, bool bReschedule) { + vdsynchronized(csScheduler) { + if (pNode->bCondemned) { + tSuspendList::iterator it(listSuspends.begin()), itEnd(listSuspends.end()); + + while(it!=itEnd) { + VDSchedulerSuspendNode *pSuspendNode = *it; + + if (pSuspendNode->mpNode == pNode) { + it = listSuspends.erase(it); + pSuspendNode->mSignal.signal(); + } else + ++it; + } + } else { + pNode->bRunning = false; + if (bReschedule || pNode->bReschedule) { + pNode->bReschedule = false; + pNode->bReady = true; + listReady.push_back(pNode); + } else + listWaiting.push_back(pNode); + } + } +} + +bool VDScheduler::Run() { + VDSchedulerNode *pNode = NULL; + vdsynchronized(csScheduler) { + if (!listReady.empty()) { + pNode = listReady.front(); + listReady.pop_front(); + pNode->bRunning = true; + pNode->bReady = false; + } + } + + if (!pNode) + return false; + + bool bReschedule; + try { + bReschedule = pNode->Service(); + } catch(MyError& e) { + Repost(pNode, false); + + vdsynchronized(csScheduler) { + if (mpErrorCB) { + if (!mpErrorCB->OnAsyncError(e)) + throw; + } + } + + return true; + } catch(...) { + Repost(pNode, false); + throw; + } + + Repost(pNode, bReschedule); + + return true; +} + +bool VDScheduler::IdleWait() { + if (mbExitThreads) + return false; + + if (pWakeupSignal) { +#if 0 + while(WAIT_TIMEOUT == WaitForSingleObject(pWakeupSignal->getHandle(), 1000)) + DumpStatus(); +#else + pWakeupSignal->wait(); +#endif + } + + return true; +} + +void VDScheduler::Ping() { + if (pWakeupSignal) + pWakeupSignal->signal(); +} + +void VDScheduler::Lock() { + ++csScheduler; +} + +void VDScheduler::Unlock() { + --csScheduler; +} + +void VDScheduler::Reschedule(VDSchedulerNode *pNode) { + VDCriticalSection::AutoLock lock(csScheduler); + + RescheduleFast(pNode); +} + +void VDScheduler::RescheduleFast(VDSchedulerNode *pNode) { + if (pNode->bReady) + return; + + pNode->bReady = true; + + if (pNode->bRunning) + pNode->bReschedule = true; + else { + if (pWakeupSignal) + pWakeupSignal->signal(); + + if (pParentSchedulerNode) + pParentSchedulerNode->Reschedule(); + + listWaiting.erase(pNode); + listReady.push_back(pNode); + } +} + +void VDScheduler::Add(VDSchedulerNode *pNode) { + VDASSERT(pNode); + + pNode->mpScheduler = this; + pNode->bRunning = false; + pNode->bReschedule = false; + pNode->bReady = true; + pNode->bCondemned = false; + + vdsynchronized(csScheduler) { + tNodeList::iterator it(listReady.begin()), itEnd(listReady.end()); + + while(it != itEnd && (*it)->nPriority <= pNode->nPriority) + ++it; + + listReady.insert(it, pNode); + } + + if (pWakeupSignal) + pWakeupSignal->signal(); + + if (pParentSchedulerNode) + pParentSchedulerNode->Reschedule(); +} + +void VDScheduler::Remove(VDSchedulerNode *pNode) { + VDASSERT(pNode); + + VDSchedulerSuspendNode suspendNode(pNode); + bool running = false; + + vdsynchronized(csScheduler) { + pNode->bCondemned = true; + if (pNode->bRunning) { + running = true; + listSuspends.push_back(&suspendNode); + } else if (pNode->bReady) + listReady.erase(pNode); + else + listWaiting.erase(pNode); + } + + if (running) + suspendNode.mSignal.wait(); +} + +void VDScheduler::DumpStatus() { + vdsynchronized(csScheduler) { + VDDEBUG2("\n Waiting nodes:\n"); + for(tNodeList::iterator it(listWaiting.begin()), itEnd(listWaiting.end()); it!=itEnd; ++it) + (*it)->DumpStatus(); + VDDEBUG2("\n Ready nodes:\n"); + for(tNodeList::iterator it2(listReady.begin()), it2End(listReady.end()); it2!=it2End; ++it2) + (*it2)->DumpStatus(); + } +} + +void VDSchedulerNode::DumpStatus() { + VDDEBUG2(" anonymous %p\n", this); +} + +/////////////////////////////////////////////////////////////////////////// + +VDSchedulerThread::VDSchedulerThread() + : VDThread("Scheduler thread") + , mpScheduler(NULL) +{ +} + +VDSchedulerThread::~VDSchedulerThread() { +} + +bool VDSchedulerThread::Start(VDScheduler *pScheduler) { + mpScheduler = pScheduler; + return VDThread::ThreadStart(); +} + +void VDSchedulerThread::ThreadRun() { + VDScheduler& scheduler = *mpScheduler; + + do { + while(scheduler.Run()) + ; + } while(scheduler.IdleWait()); + + scheduler.Ping(); +} + +/////////////////////////////////////////////////////////////////////////// + +VDSchedulerThreadPool::VDSchedulerThreadPool() + : mpThreads(NULL) + , mThreadCount(0) + , mThreadPriority(VDThread::kPriorityDefault) +{ +} + +VDSchedulerThreadPool::~VDSchedulerThreadPool() { + if (mpThreads) { + for(uint32 i=0; i -#include -#include - -const VDStringSpanA::value_type VDStringSpanA::sNull[1] = {0}; - -void VDStringA::push_back_extend() { - VDASSERT(mpEOS == mpEnd); - size_type current_size = (size_type)(mpEnd - mpBegin); - - reserve_slow(current_size * 2 + 1, current_size); -} - -void VDStringA::resize_slow(size_type n, size_type current_size) { - resize_slow(n, current_size, 0); -} - -void VDStringA::resize_slow(size_type n, size_type current_size, value_type c) { - VDASSERT(n > current_size); - - size_type current_capacity = (size_type)(mpEOS - mpBegin); - if (n > current_capacity) - reserve_slow(n, current_capacity); - - memset(mpBegin + current_size, c, n - current_size); - mpEnd = mpBegin + n; - *mpEnd = 0; -} - -void VDStringA::reserve_slow(size_type n, size_type current_capacity) { - VDASSERT(n > current_capacity); - - size_type current_size = (size_type)(mpEnd - mpBegin); - value_type *s = new value_type[n + 1]; - memcpy(s, mpBegin, (current_size + 1) * sizeof(value_type)); - if (mpBegin != sNull) - delete[] mpBegin; - - mpBegin = s; - mpEnd = s + current_size; - mpEOS = s + n; -} - -void VDStringA::reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity) { - n += current_size; - - size_type doublesize = current_size * 2; - if (n < doublesize) - n = doublesize; - - reserve_slow(n, current_capacity); -} - -VDStringA& VDStringA::sprintf(const value_type *format, ...) { - clear(); - va_list val; - va_start(val, format); - append_vsprintf(format, val); - va_end(val); - return *this; -} - -VDStringA& VDStringA::append_sprintf(const value_type *format, ...) { - va_list val; - va_start(val, format); - append_vsprintf(format, val); - va_end(val); - return *this; -} - -VDStringA& VDStringA::append_vsprintf(const value_type *format, va_list val) { - char buf[2048]; - - int len = vdvsnprintf(buf, 2048, format, val); - if (len >= 0) - append(buf, buf+len); - else { - int len; - - vdfastvector tmp; - for(int siz = 8192; siz <= 65536; siz += siz) { - tmp.resize(siz); - - char *tmpp = tmp.data(); - len = vdvsnprintf(tmp.data(), siz, format, val); - if (len >= 0) { - append(tmpp, tmpp+len); - break; - } - } - } - - return *this; -} - -void VDStringA::move_from(VDStringA& src) { - if (mpBegin != sNull) - delete[] mpBegin; - - mpBegin = src.mpBegin; - mpEnd = src.mpEnd; - mpEOS = src.mpEOS; - - src.mpBegin = NULL; - src.mpEnd = NULL; - src.mpEOS = NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -const VDStringSpanW::value_type VDStringSpanW::sNull[1] = {0}; - -void VDStringW::push_back_extend() { - VDASSERT(mpEOS == mpEnd); - size_type current_size = (size_type)(mpEnd - mpBegin); - - reserve_slow(current_size * 2 + 1, current_size); -} - -void VDStringW::resize_slow(size_type n, size_type current_size) { - VDASSERT(n > current_size); - - size_type current_capacity = (size_type)(mpEOS - mpBegin); - if (n > current_capacity) - reserve_slow(n, current_capacity); - - mpEnd = mpBegin + n; - *mpEnd = 0; -} - -void VDStringW::reserve_slow(size_type n, size_type current_capacity) { - VDASSERT(current_capacity == (size_type)(mpEOS - mpBegin)); - VDASSERT(n > current_capacity); - - size_type current_size = (size_type)(mpEnd - mpBegin); - value_type *s = new value_type[n + 1]; - memcpy(s, mpBegin, (current_size + 1) * sizeof(value_type)); - if (mpBegin != sNull) - delete[] mpBegin; - - mpBegin = s; - mpEnd = s + current_size; - mpEOS = s + n; -} - -void VDStringW::reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity) { - n += current_size; - - size_type doublesize = current_size * 2; - if (n < doublesize) - n = doublesize; - - reserve_slow(n, current_capacity); -} - -VDStringW& VDStringW::sprintf(const value_type *format, ...) { - clear(); - va_list val; - va_start(val, format); - append_vsprintf(format, val); - va_end(val); - return *this; -} - -VDStringW& VDStringW::append_sprintf(const value_type *format, ...) { - va_list val; - va_start(val, format); - append_vsprintf(format, val); - va_end(val); - return *this; -} - -VDStringW& VDStringW::append_vsprintf(const value_type *format, va_list val) { - wchar_t buf[1024]; - - int len = vdvswprintf(buf, 1024, format, val); - if (len >= 0) - append(buf, buf+len); - else { - int len; - - vdfastvector tmp; - for(int siz = 4096; siz <= 65536; siz += siz) { - tmp.resize(siz); - - wchar_t *tmpp = tmp.data(); - len = vdvswprintf(tmpp, siz, format, val); - if (len >= 0) { - append(tmpp, tmpp+len); - break; - } - } - } - - va_end(val); - return *this; -} - -void VDStringW::move_from(VDStringW& src) { - if (mpBegin != sNull) - delete[] mpBegin; - - mpBegin = src.mpBegin; - mpEnd = src.mpEnd; - mpEOS = src.mpEOS; - - src.mpBegin = NULL; - src.mpEnd = NULL; - src.mpEOS = NULL; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -template<> -VDStringA *vdmove_forward(VDStringA *src1, VDStringA *src2, VDStringA *dst) { - VDStringA *p = src1; - while(p != src2) { - dst->move_from(*p); - ++dst; - ++p; - } - - return dst; -} - -template<> -VDStringW *vdmove_forward(VDStringW *src1, VDStringW *src2, VDStringW *dst) { - VDStringW *p = src1; - while(p != src2) { - dst->move_from(*p); - ++dst; - ++p; - } - - return dst; -} - -template<> -VDStringA *vdmove_backward(VDStringA *src1, VDStringA *src2, VDStringA *dst) { - VDStringA *p = src2; - while(p != src1) { - --dst; - --p; - dst->move_from(*p); - } - - return dst; -} - -template<> -VDStringW *vdmove_backward(VDStringW *src1, VDStringW *src2, VDStringW *dst) { - VDStringW *p = src2; - while(p != src1) { - --dst; - --p; - dst->move_from(*p); - } - - return dst; -} - -template<> -void vdmove(VDStringA& dst, VDStringA& src) { - dst.move_from(src); -} - -template<> -void vdmove(VDStringW& dst, VDStringW& src) { - dst.move_from(src); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include + +const VDStringSpanA::value_type VDStringSpanA::sNull[1] = {0}; + +void VDStringA::push_back_extend() { + VDASSERT(mpEOS == mpEnd); + size_type current_size = (size_type)(mpEnd - mpBegin); + + reserve_slow(current_size * 2 + 1, current_size); +} + +void VDStringA::resize_slow(size_type n, size_type current_size) { + resize_slow(n, current_size, 0); +} + +void VDStringA::resize_slow(size_type n, size_type current_size, value_type c) { + VDASSERT(n > current_size); + + size_type current_capacity = (size_type)(mpEOS - mpBegin); + if (n > current_capacity) + reserve_slow(n, current_capacity); + + memset(mpBegin + current_size, c, n - current_size); + mpEnd = mpBegin + n; + *mpEnd = 0; +} + +void VDStringA::reserve_slow(size_type n, size_type current_capacity) { + VDASSERT(n > current_capacity); + + size_type current_size = (size_type)(mpEnd - mpBegin); + value_type *s = new value_type[n + 1]; + memcpy(s, mpBegin, (current_size + 1) * sizeof(value_type)); + if (mpBegin != sNull) + delete[] mpBegin; + + mpBegin = s; + mpEnd = s + current_size; + mpEOS = s + n; +} + +void VDStringA::reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity) { + n += current_size; + + size_type doublesize = current_size * 2; + if (n < doublesize) + n = doublesize; + + reserve_slow(n, current_capacity); +} + +VDStringA& VDStringA::sprintf(const value_type *format, ...) { + clear(); + va_list val; + va_start(val, format); + append_vsprintf(format, val); + va_end(val); + return *this; +} + +VDStringA& VDStringA::append_sprintf(const value_type *format, ...) { + va_list val; + va_start(val, format); + append_vsprintf(format, val); + va_end(val); + return *this; +} + +VDStringA& VDStringA::append_vsprintf(const value_type *format, va_list val) { + char buf[2048]; + + int len = vdvsnprintf(buf, 2048, format, val); + if (len >= 0) + append(buf, buf+len); + else { + int len; + + vdfastvector tmp; + for(int siz = 8192; siz <= 65536; siz += siz) { + tmp.resize(siz); + + char *tmpp = tmp.data(); + len = vdvsnprintf(tmp.data(), siz, format, val); + if (len >= 0) { + append(tmpp, tmpp+len); + break; + } + } + } + + return *this; +} + +void VDStringA::move_from(VDStringA& src) { + if (mpBegin != sNull) + delete[] mpBegin; + + mpBegin = src.mpBegin; + mpEnd = src.mpEnd; + mpEOS = src.mpEOS; + + src.mpBegin = NULL; + src.mpEnd = NULL; + src.mpEOS = NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +const VDStringSpanW::value_type VDStringSpanW::sNull[1] = {0}; + +void VDStringW::push_back_extend() { + VDASSERT(mpEOS == mpEnd); + size_type current_size = (size_type)(mpEnd - mpBegin); + + reserve_slow(current_size * 2 + 1, current_size); +} + +void VDStringW::resize_slow(size_type n, size_type current_size) { + VDASSERT(n > current_size); + + size_type current_capacity = (size_type)(mpEOS - mpBegin); + if (n > current_capacity) + reserve_slow(n, current_capacity); + + mpEnd = mpBegin + n; + *mpEnd = 0; +} + +void VDStringW::reserve_slow(size_type n, size_type current_capacity) { + VDASSERT(current_capacity == (size_type)(mpEOS - mpBegin)); + VDASSERT(n > current_capacity); + + size_type current_size = (size_type)(mpEnd - mpBegin); + value_type *s = new value_type[n + 1]; + memcpy(s, mpBegin, (current_size + 1) * sizeof(value_type)); + if (mpBegin != sNull) + delete[] mpBegin; + + mpBegin = s; + mpEnd = s + current_size; + mpEOS = s + n; +} + +void VDStringW::reserve_amortized_slow(size_type n, size_type current_size, size_type current_capacity) { + n += current_size; + + size_type doublesize = current_size * 2; + if (n < doublesize) + n = doublesize; + + reserve_slow(n, current_capacity); +} + +VDStringW& VDStringW::sprintf(const value_type *format, ...) { + clear(); + va_list val; + va_start(val, format); + append_vsprintf(format, val); + va_end(val); + return *this; +} + +VDStringW& VDStringW::append_sprintf(const value_type *format, ...) { + va_list val; + va_start(val, format); + append_vsprintf(format, val); + va_end(val); + return *this; +} + +VDStringW& VDStringW::append_vsprintf(const value_type *format, va_list val) { + wchar_t buf[1024]; + + int len = vdvswprintf(buf, 1024, format, val); + if (len >= 0) + append(buf, buf+len); + else { + int len; + + vdfastvector tmp; + for(int siz = 4096; siz <= 65536; siz += siz) { + tmp.resize(siz); + + wchar_t *tmpp = tmp.data(); + len = vdvswprintf(tmpp, siz, format, val); + if (len >= 0) { + append(tmpp, tmpp+len); + break; + } + } + } + + va_end(val); + return *this; +} + +void VDStringW::move_from(VDStringW& src) { + if (mpBegin != sNull) + delete[] mpBegin; + + mpBegin = src.mpBegin; + mpEnd = src.mpEnd; + mpEOS = src.mpEOS; + + src.mpBegin = NULL; + src.mpEnd = NULL; + src.mpEOS = NULL; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template<> +VDStringA *vdmove_forward(VDStringA *src1, VDStringA *src2, VDStringA *dst) { + VDStringA *p = src1; + while(p != src2) { + dst->move_from(*p); + ++dst; + ++p; + } + + return dst; +} + +template<> +VDStringW *vdmove_forward(VDStringW *src1, VDStringW *src2, VDStringW *dst) { + VDStringW *p = src1; + while(p != src2) { + dst->move_from(*p); + ++dst; + ++p; + } + + return dst; +} + +template<> +VDStringA *vdmove_backward(VDStringA *src1, VDStringA *src2, VDStringA *dst) { + VDStringA *p = src2; + while(p != src1) { + --dst; + --p; + dst->move_from(*p); + } + + return dst; +} + +template<> +VDStringW *vdmove_backward(VDStringW *src1, VDStringW *src2, VDStringW *dst) { + VDStringW *p = src2; + while(p != src1) { + --dst; + --p; + dst->move_from(*p); + } + + return dst; +} + +template<> +void vdmove(VDStringA& dst, VDStringA& src) { + dst.move_from(src); +} + +template<> +void vdmove(VDStringW& dst, VDStringW& src) { + dst.move_from(src); +} diff --git a/src/thirdparty/VirtualDub/system/source/a64_cpuaccel.asm b/src/thirdparty/VirtualDub/system/source/a64_cpuaccel.asm index 248a6918911..278754c4edc 100644 --- a/src/thirdparty/VirtualDub/system/source/a64_cpuaccel.asm +++ b/src/thirdparty/VirtualDub/system/source/a64_cpuaccel.asm @@ -1,42 +1,42 @@ -; VirtualDub - Video processing and capture application -; System library component -; Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -; -; Beginning with 1.6.0, the VirtualDub system library is licensed -; differently than the remainder of VirtualDub. This particular file is -; thus licensed as follows (the "zlib" license): -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any purpose, -; including commercial applications, and to alter it and redistribute it -; freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you must -; not claim that you wrote the original software. If you use this -; software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; 2. Altered source versions must be plainly marked as such, and must -; not be misrepresented as being the original software. -; 3. This notice may not be removed or altered from any source -; distribution. - - segment .text - -;-------------------------------------------------------------------------- - global VDIsAVXSupportedByOS -VDIsAVXSupportedByOS: - xor ecx, ecx - xgetbv - and al, 6 - cmp al, 6 - jnz .notsupported - mov eax, 1 - ret -.notsupported: - xor eax, eax - ret - - end +; VirtualDub - Video processing and capture application +; System library component +; Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +; +; Beginning with 1.6.0, the VirtualDub system library is licensed +; differently than the remainder of VirtualDub. This particular file is +; thus licensed as follows (the "zlib" license): +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must +; not claim that you wrote the original software. If you use this +; software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must +; not be misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source +; distribution. + + segment .text + +;-------------------------------------------------------------------------- + global VDIsAVXSupportedByOS +VDIsAVXSupportedByOS: + xor ecx, ecx + xgetbv + and al, 6 + cmp al, 6 + jnz .notsupported + mov eax, 1 + ret +.notsupported: + xor eax, eax + ret + + end diff --git a/src/thirdparty/VirtualDub/system/source/a64_fraction.asm b/src/thirdparty/VirtualDub/system/source/a64_fraction.asm index 39f6666f261..43b0baddfd4 100644 --- a/src/thirdparty/VirtualDub/system/source/a64_fraction.asm +++ b/src/thirdparty/VirtualDub/system/source/a64_fraction.asm @@ -1,58 +1,58 @@ -; VirtualDub - Video processing and capture application -; System library component -; Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -; -; Beginning with 1.6.0, the VirtualDub system library is licensed -; differently than the remainder of VirtualDub. This particular file is -; thus licensed as follows (the "zlib" license): -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any purpose, -; including commercial applications, and to alter it and redistribute it -; freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you must -; not claim that you wrote the original software. If you use this -; software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; 2. Altered source versions must be plainly marked as such, and must -; not be misrepresented as being the original software. -; 3. This notice may not be removed or altered from any source -; distribution. - - segment .text - -;-------------------------------------------------------------------------- -; VDFractionScale64( -; [rcx] uint64 a, -; [rdx] uint64 b, -; [r8] uint64 c, -; [r9] uint32& remainder); -; -; - global VDFractionScale64 -VDFractionScale64: - mov rax, rcx - mul rdx - div r8 - mov [r9], edx - ret - -;-------------------------------------------------------------------------- -; VDUMulDiv64x32( -; [rcx] uint64 a, -; [rdx] uint64 b, -; [r8] uint64 c); -; -; - global VDUMulDiv64x32 -VDUMulDiv64x32: - mov rax, rcx - mul rdx - div r8 - ret - - end +; VirtualDub - Video processing and capture application +; System library component +; Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +; +; Beginning with 1.6.0, the VirtualDub system library is licensed +; differently than the remainder of VirtualDub. This particular file is +; thus licensed as follows (the "zlib" license): +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must +; not claim that you wrote the original software. If you use this +; software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must +; not be misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source +; distribution. + + segment .text + +;-------------------------------------------------------------------------- +; VDFractionScale64( +; [rcx] uint64 a, +; [rdx] uint64 b, +; [r8] uint64 c, +; [r9] uint32& remainder); +; +; + global VDFractionScale64 +VDFractionScale64: + mov rax, rcx + mul rdx + div r8 + mov [r9], edx + ret + +;-------------------------------------------------------------------------- +; VDUMulDiv64x32( +; [rcx] uint64 a, +; [rdx] uint64 b, +; [r8] uint64 c); +; +; + global VDUMulDiv64x32 +VDUMulDiv64x32: + mov rax, rcx + mul rdx + div r8 + ret + + end diff --git a/src/thirdparty/VirtualDub/system/source/a64_int128.asm b/src/thirdparty/VirtualDub/system/source/a64_int128.asm index 99cfb8d8749..706e298f629 100644 --- a/src/thirdparty/VirtualDub/system/source/a64_int128.asm +++ b/src/thirdparty/VirtualDub/system/source/a64_int128.asm @@ -1,73 +1,73 @@ -; VirtualDub - Video processing and capture application -; System library component -; Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -; -; Beginning with 1.6.0, the VirtualDub system library is licensed -; differently than the remainder of VirtualDub. This particular file is -; thus licensed as follows (the "zlib" license): -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any purpose, -; including commercial applications, and to alter it and redistribute it -; freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you must -; not claim that you wrote the original software. If you use this -; software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; 2. Altered source versions must be plainly marked as such, and must -; not be misrepresented as being the original software. -; 3. This notice may not be removed or altered from any source -; distribution. - - segment .text - - global vdasm_uint128_add -vdasm_uint128_add: - mov rax, [rdx] - add rax, [r8] - mov [rcx], rax - mov rax, [rdx+8] - adc rax, [r8+8] - mov [rcx+8], rax - ret - - global vdasm_uint128_sub -vdasm_uint128_sub: - mov rax, [rdx] - sub rax, [r8] - mov [rcx], rax - mov rax, [rdx+8] - sbb rax, [r8+8] - mov [rcx+8], rax - ret - -proc_frame vdasm_uint128_mul - mov [esp+8], rbx - [savereg rbx, 8] - mov [esp+16], rsi - [savereg rsi, 16] -end_prolog - - mov rbx, rdx ;rbx = src1 - mov rax, [rdx] ;rax = src1a - mov rsi, [r8] ;rsi = src2a - mul rsi ;rdx:rax = src1a*src2a - mov [rcx], rax ;write low result - mov r9, rdx ;r9 = (src1a*src2a).hi - mov rax, [rbx+8] ;rax = src1b - mul rsi ;rdx:rax = src1b*src2a - add r9, rax ;r9 = (src1a*src2a).hi + (src1b*src2a).lo - mov rax, [rbx] ;rax = src1a - mul qword [r8+8] ;rdx:rax = src1a*src2b - add rax, r9 ;rax = (src1a*src2b).lo + (src1b*src2a).lo + (src1a*src2a).hi - mov [rcx+8], rax ;write high result - mov rsi, [esp+16] - mov rbx, [esp+8] - ret -endproc_frame - - end +; VirtualDub - Video processing and capture application +; System library component +; Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +; +; Beginning with 1.6.0, the VirtualDub system library is licensed +; differently than the remainder of VirtualDub. This particular file is +; thus licensed as follows (the "zlib" license): +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must +; not claim that you wrote the original software. If you use this +; software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must +; not be misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source +; distribution. + + segment .text + + global vdasm_uint128_add +vdasm_uint128_add: + mov rax, [rdx] + add rax, [r8] + mov [rcx], rax + mov rax, [rdx+8] + adc rax, [r8+8] + mov [rcx+8], rax + ret + + global vdasm_uint128_sub +vdasm_uint128_sub: + mov rax, [rdx] + sub rax, [r8] + mov [rcx], rax + mov rax, [rdx+8] + sbb rax, [r8+8] + mov [rcx+8], rax + ret + +proc_frame vdasm_uint128_mul + mov [esp+8], rbx + [savereg rbx, 8] + mov [esp+16], rsi + [savereg rsi, 16] +end_prolog + + mov rbx, rdx ;rbx = src1 + mov rax, [rdx] ;rax = src1a + mov rsi, [r8] ;rsi = src2a + mul rsi ;rdx:rax = src1a*src2a + mov [rcx], rax ;write low result + mov r9, rdx ;r9 = (src1a*src2a).hi + mov rax, [rbx+8] ;rax = src1b + mul rsi ;rdx:rax = src1b*src2a + add r9, rax ;r9 = (src1a*src2a).hi + (src1b*src2a).lo + mov rax, [rbx] ;rax = src1a + mul qword [r8+8] ;rdx:rax = src1a*src2b + add rax, r9 ;rax = (src1a*src2b).lo + (src1b*src2a).lo + (src1a*src2a).hi + mov [rcx+8], rax ;write high result + mov rsi, [esp+16] + mov rbx, [esp+8] + ret +endproc_frame + + end diff --git a/src/thirdparty/VirtualDub/system/source/a64_thunk.asm b/src/thirdparty/VirtualDub/system/source/a64_thunk.asm index fdf1986bfcd..72745606dda 100644 --- a/src/thirdparty/VirtualDub/system/source/a64_thunk.asm +++ b/src/thirdparty/VirtualDub/system/source/a64_thunk.asm @@ -1,58 +1,58 @@ - segment .text - - global VDMethodToFunctionThunk64 -proc_frame VDMethodToFunctionThunk64 - ;prolog - db 48h ;emit REX prefix -- first instruction must be two bytes for hot patching - push rbp - [pushreg rbp] - - mov rbp, rsp ;create stack pointer - [setframe rbp, 0] - - mov [rbp+16], rcx ;save arg1 - [savereg rcx, 0] - - mov [rbp+24], rdx ;save arg2 - [savereg rcx, 8] - - mov [rbp+32], r8 ;save arg3 - [savereg rcx, 16] - - mov [rbp+40], r9 ;save arg4 - [savereg rcx, 24] - - [endprolog] - - ;re-copy arguments 4 and up - mov ecx, [rax+24] - or ecx, ecx - jz .argsdone - lea rdx, [rcx+32] -.argsloop: - push qword [rsp+rdx] - sub ecx, 8 - jnz .argsloop -.argsdone: - - ;load 'this' pointer - mov rcx, [rax+16] - - ;reload arguments 1-3 - mov rdx, [rbp+16] - mov r8, [rbp+24] - mov r9, [rbp+32] - - ;reserve argument 1-4 space on stack - sub rsp, 32 - - ;call function - call qword [rax+8] - - ;epilog - lea rsp, [rbp] ;pop off stack frame and any additional arg space - pop rbp ;restore base pointer - ret ;all done -endproc_frame - - end + segment .text + + global VDMethodToFunctionThunk64 +proc_frame VDMethodToFunctionThunk64 + ;prolog + db 48h ;emit REX prefix -- first instruction must be two bytes for hot patching + push rbp + [pushreg rbp] + + mov rbp, rsp ;create stack pointer + [setframe rbp, 0] + + mov [rbp+16], rcx ;save arg1 + [savereg rcx, 0] + + mov [rbp+24], rdx ;save arg2 + [savereg rcx, 8] + + mov [rbp+32], r8 ;save arg3 + [savereg rcx, 16] + + mov [rbp+40], r9 ;save arg4 + [savereg rcx, 24] + + [endprolog] + + ;re-copy arguments 4 and up + mov ecx, [rax+24] + or ecx, ecx + jz .argsdone + lea rdx, [rcx+32] +.argsloop: + push qword [rsp+rdx] + sub ecx, 8 + jnz .argsloop +.argsdone: + + ;load 'this' pointer + mov rcx, [rax+16] + + ;reload arguments 1-3 + mov rdx, [rbp+16] + mov r8, [rbp+24] + mov r9, [rbp+32] + + ;reserve argument 1-4 space on stack + sub rsp, 32 + + ;call function + call qword [rax+8] + + ;epilog + lea rsp, [rbp] ;pop off stack frame and any additional arg space + pop rbp ;restore base pointer + ret ;all done +endproc_frame + + end diff --git a/src/thirdparty/VirtualDub/system/source/a_memory.asm b/src/thirdparty/VirtualDub/system/source/a_memory.asm index 54844bce18d..226be080143 100644 --- a/src/thirdparty/VirtualDub/system/source/a_memory.asm +++ b/src/thirdparty/VirtualDub/system/source/a_memory.asm @@ -1,197 +1,197 @@ -; VirtualDub - Video processing and capture application -; System library component -; Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -; -; Beginning with 1.6.0, the VirtualDub system library is licensed -; differently than the remainder of VirtualDub. This particular file is -; thus licensed as follows (the "zlib" license): -; -; This software is provided 'as-is', without any express or implied -; warranty. In no event will the authors be held liable for any -; damages arising from the use of this software. -; -; Permission is granted to anyone to use this software for any purpose, -; including commercial applications, and to alter it and redistribute it -; freely, subject to the following restrictions: -; -; 1. The origin of this software must not be misrepresented; you must -; not claim that you wrote the original software. If you use this -; software in a product, an acknowledgment in the product -; documentation would be appreciated but is not required. -; 2. Altered source versions must be plainly marked as such, and must -; not be misrepresented as being the original software. -; 3. This notice may not be removed or altered from any source -; distribution. - - segment .text - - global _VDFastMemcpyPartialScalarAligned8 -_VDFastMemcpyPartialScalarAligned8: - mov eax, [esp+12] - mov edx, [esp+4] - mov ecx, [esp+8] - add ecx, eax - add edx, eax - neg eax - jz .nobytes - add eax, 8 - jz .doodd - jmp short .xloop - align 16 -.xloop: - fild qword [ecx+eax-8] - fild qword [ecx+eax] - fxch - fistp qword [edx+eax-8] - fistp qword [edx+eax] - add eax,16 - jnc .xloop - jnz .nobytes -.doodd: - fild qword [ecx-8] - fistp qword [edx-8] -.nobytes: - ret - - global _VDFastMemcpyPartialMMX -_VDFastMemcpyPartialMMX: - push edi - push esi - - mov edi, [esp+4+8] - mov esi, [esp+8+8] - mov ecx, [esp+12+8] - mov edx, ecx - shr ecx, 2 - and edx, 3 - rep movsd - mov ecx, edx - rep movsb - pop esi - pop edi - ret - -; MPC custom code start - global _VDFastMemcpyPartialSSE2 -_VDFastMemcpyPartialSSE2: - push ebp - push edi - push esi - push ebx - - mov ecx, [esp+12+16] - cmp ecx, 128 - jb _VDFastMemcpyPartialMMX2.MMX2 - mov edi, [esp+4+16] - mov esi, [esp+8+16] - mov eax, edi - or eax, esi - test al, 15 - jne SHORT _VDFastMemcpyPartialMMX2.MMX2 - - shr ecx, 7 -.loop128: - prefetchnta [esi+16*8] - movaps xmm0, [esi] - movaps xmm1, [esi+16*1] - movaps xmm2, [esi+16*2] - movaps xmm3, [esi+16*3] - movaps xmm4, [esi+16*4] - movaps xmm5, [esi+16*5] - movaps xmm6, [esi+16*6] - movaps xmm7, [esi+16*7] - movntps [edi], xmm0 - movntps [edi+16*1], xmm1 - movntps [edi+16*2], xmm2 - movntps [edi+16*3], xmm3 - movntps [edi+16*4], xmm4 - movntps [edi+16*5], xmm5 - movntps [edi+16*6], xmm6 - movntps [edi+16*7], xmm7 - add esi, 128 - add edi, 128 - dec ecx - jne .loop128 -.skiploop128: - mov ecx, [esp+12+16] - and ecx, 127 - cmp ecx, 0 - je .nooddballs -.loop: - mov dl, [esi] - mov [edi], dl - inc esi - inc edi - dec ecx - jne .loop -.nooddballs: - pop ebx - pop esi - pop edi - pop ebp - ret -; MPC custom code end - - global _VDFastMemcpyPartialMMX2 -_VDFastMemcpyPartialMMX2: - push ebp - push edi - push esi - push ebx - -.MMX2 ; MPC custom code - mov ebx, [esp+4+16] - mov edx, [esp+8+16] - mov eax, [esp+12+16] - neg eax - add eax, 63 - jbe .skipblastloop -.blastloop: - movq mm0, [edx] - movq mm1, [edx+8] - movq mm2, [edx+16] - movq mm3, [edx+24] - movq mm4, [edx+32] - movq mm5, [edx+40] - movq mm6, [edx+48] - movq mm7, [edx+56] - movntq [ebx], mm0 - movntq [ebx+8], mm1 - movntq [ebx+16], mm2 - movntq [ebx+24], mm3 - movntq [ebx+32], mm4 - movntq [ebx+40], mm5 - movntq [ebx+48], mm6 - movntq [ebx+56], mm7 - add ebx, 64 - add edx, 64 - add eax, 64 - jnc .blastloop -.skipblastloop: - sub eax, 63-7 - jns .noextras -.quadloop: - movq mm0, [edx] - movntq [ebx], mm0 - add edx, 8 - add ebx, 8 - add eax, 8 - jnc .quadloop -.noextras: - sub eax, 7 - jz .nooddballs - mov ecx, eax - neg ecx - mov esi, edx - mov edi, ebx - rep movsb -.nooddballs: - pop ebx - pop esi - pop edi - pop ebp - ret - - - end - +; VirtualDub - Video processing and capture application +; System library component +; Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +; +; Beginning with 1.6.0, the VirtualDub system library is licensed +; differently than the remainder of VirtualDub. This particular file is +; thus licensed as follows (the "zlib" license): +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must +; not claim that you wrote the original software. If you use this +; software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must +; not be misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source +; distribution. + + segment .text + + global _VDFastMemcpyPartialScalarAligned8 +_VDFastMemcpyPartialScalarAligned8: + mov eax, [esp+12] + mov edx, [esp+4] + mov ecx, [esp+8] + add ecx, eax + add edx, eax + neg eax + jz .nobytes + add eax, 8 + jz .doodd + jmp short .xloop + align 16 +.xloop: + fild qword [ecx+eax-8] + fild qword [ecx+eax] + fxch + fistp qword [edx+eax-8] + fistp qword [edx+eax] + add eax,16 + jnc .xloop + jnz .nobytes +.doodd: + fild qword [ecx-8] + fistp qword [edx-8] +.nobytes: + ret + + global _VDFastMemcpyPartialMMX +_VDFastMemcpyPartialMMX: + push edi + push esi + + mov edi, [esp+4+8] + mov esi, [esp+8+8] + mov ecx, [esp+12+8] + mov edx, ecx + shr ecx, 2 + and edx, 3 + rep movsd + mov ecx, edx + rep movsb + pop esi + pop edi + ret + +; MPC custom code start + global _VDFastMemcpyPartialSSE2 +_VDFastMemcpyPartialSSE2: + push ebp + push edi + push esi + push ebx + + mov ecx, [esp+12+16] + cmp ecx, 128 + jb _VDFastMemcpyPartialMMX2.MMX2 + mov edi, [esp+4+16] + mov esi, [esp+8+16] + mov eax, edi + or eax, esi + test al, 15 + jne SHORT _VDFastMemcpyPartialMMX2.MMX2 + + shr ecx, 7 +.loop128: + prefetchnta [esi+16*8] + movaps xmm0, [esi] + movaps xmm1, [esi+16*1] + movaps xmm2, [esi+16*2] + movaps xmm3, [esi+16*3] + movaps xmm4, [esi+16*4] + movaps xmm5, [esi+16*5] + movaps xmm6, [esi+16*6] + movaps xmm7, [esi+16*7] + movntps [edi], xmm0 + movntps [edi+16*1], xmm1 + movntps [edi+16*2], xmm2 + movntps [edi+16*3], xmm3 + movntps [edi+16*4], xmm4 + movntps [edi+16*5], xmm5 + movntps [edi+16*6], xmm6 + movntps [edi+16*7], xmm7 + add esi, 128 + add edi, 128 + dec ecx + jne .loop128 +.skiploop128: + mov ecx, [esp+12+16] + and ecx, 127 + cmp ecx, 0 + je .nooddballs +.loop: + mov dl, [esi] + mov [edi], dl + inc esi + inc edi + dec ecx + jne .loop +.nooddballs: + pop ebx + pop esi + pop edi + pop ebp + ret +; MPC custom code end + + global _VDFastMemcpyPartialMMX2 +_VDFastMemcpyPartialMMX2: + push ebp + push edi + push esi + push ebx + +.MMX2 ; MPC custom code + mov ebx, [esp+4+16] + mov edx, [esp+8+16] + mov eax, [esp+12+16] + neg eax + add eax, 63 + jbe .skipblastloop +.blastloop: + movq mm0, [edx] + movq mm1, [edx+8] + movq mm2, [edx+16] + movq mm3, [edx+24] + movq mm4, [edx+32] + movq mm5, [edx+40] + movq mm6, [edx+48] + movq mm7, [edx+56] + movntq [ebx], mm0 + movntq [ebx+8], mm1 + movntq [ebx+16], mm2 + movntq [ebx+24], mm3 + movntq [ebx+32], mm4 + movntq [ebx+40], mm5 + movntq [ebx+48], mm6 + movntq [ebx+56], mm7 + add ebx, 64 + add edx, 64 + add eax, 64 + jnc .blastloop +.skipblastloop: + sub eax, 63-7 + jns .noextras +.quadloop: + movq mm0, [edx] + movntq [ebx], mm0 + add edx, 8 + add ebx, 8 + add eax, 8 + jnc .quadloop +.noextras: + sub eax, 7 + jz .nooddballs + mov ecx, eax + neg ecx + mov esi, edx + mov edi, ebx + rep movsb +.nooddballs: + pop ebx + pop esi + pop edi + pop ebp + ret + + + end + diff --git a/src/thirdparty/VirtualDub/system/source/a_thunk.asm b/src/thirdparty/VirtualDub/system/source/a_thunk.asm index ad2efb7b4c9..5dcdecbbe01 100644 --- a/src/thirdparty/VirtualDub/system/source/a_thunk.asm +++ b/src/thirdparty/VirtualDub/system/source/a_thunk.asm @@ -1,63 +1,63 @@ - segment .text - - align 16 - global _VDMethodToFunctionThunk32 -_VDMethodToFunctionThunk32: - pop eax ;get return address in thunk - - ;re-copy arguments - movzx ecx, byte [eax+1] - mov edx, ecx -argsloop: - push dword [esp+edx] - sub ecx, 4 - jnz argsloop - - push eax ;replace thunk return address - - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - align 16 - global _VDMethodToFunctionThunk32_4 -_VDMethodToFunctionThunk32_4: - pop eax ;get return address in thunk - push dword [esp+4] ;replicate 1st argument - push eax ;replace thunk return address - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - align 16 - global _VDMethodToFunctionThunk32_8 -_VDMethodToFunctionThunk32_8: - pop eax ;get return address in thunk - push dword [esp+8] ;replicate 2nd argument - push dword [esp+8] ;replicate 1st argument - push eax ;replace thunk return address - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - align 16 - global _VDMethodToFunctionThunk32_12 -_VDMethodToFunctionThunk32_12: - pop eax ;get return address in thunk - push dword [esp+12] ;replicate 3rd argument - push dword [esp+12] ;replicate 2nd argument - push dword [esp+12] ;replicate 1st argument - push eax ;replace thunk return address - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - align 16 - global _VDMethodToFunctionThunk32_16 -_VDMethodToFunctionThunk32_16: - pop eax ;get return address in thunk - push dword [esp+16] ;replicate 4th argument - push dword [esp+16] ;replicate 3rd argument - push dword [esp+16] ;replicate 2nd argument - push dword [esp+16] ;replicate 1st argument - push eax ;replace thunk return address - mov ecx, [eax+7] ;load 'this' pointer - jmp dword [eax+3] ;tail-call function - - end + segment .text + + align 16 + global _VDMethodToFunctionThunk32 +_VDMethodToFunctionThunk32: + pop eax ;get return address in thunk + + ;re-copy arguments + movzx ecx, byte [eax+1] + mov edx, ecx +argsloop: + push dword [esp+edx] + sub ecx, 4 + jnz argsloop + + push eax ;replace thunk return address + + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + align 16 + global _VDMethodToFunctionThunk32_4 +_VDMethodToFunctionThunk32_4: + pop eax ;get return address in thunk + push dword [esp+4] ;replicate 1st argument + push eax ;replace thunk return address + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + align 16 + global _VDMethodToFunctionThunk32_8 +_VDMethodToFunctionThunk32_8: + pop eax ;get return address in thunk + push dword [esp+8] ;replicate 2nd argument + push dword [esp+8] ;replicate 1st argument + push eax ;replace thunk return address + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + align 16 + global _VDMethodToFunctionThunk32_12 +_VDMethodToFunctionThunk32_12: + pop eax ;get return address in thunk + push dword [esp+12] ;replicate 3rd argument + push dword [esp+12] ;replicate 2nd argument + push dword [esp+12] ;replicate 1st argument + push eax ;replace thunk return address + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + align 16 + global _VDMethodToFunctionThunk32_16 +_VDMethodToFunctionThunk32_16: + pop eax ;get return address in thunk + push dword [esp+16] ;replicate 4th argument + push dword [esp+16] ;replicate 3rd argument + push dword [esp+16] ;replicate 2nd argument + push dword [esp+16] ;replicate 1st argument + push eax ;replace thunk return address + mov ecx, [eax+7] ;load 'this' pointer + jmp dword [eax+3] ;tail-call function + + end diff --git a/src/thirdparty/VirtualDub/system/source/cache.cpp b/src/thirdparty/VirtualDub/system/source/cache.cpp index dc2788b104e..5da77d089b6 100644 --- a/src/thirdparty/VirtualDub/system/source/cache.cpp +++ b/src/thirdparty/VirtualDub/system/source/cache.cpp @@ -1,422 +1,422 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -/////////////////////////////////////////////////////////////////////////// - -VDCache::VDCache(IVDCacheAllocator *pAllocator) - : mpAllocator(pAllocator) - , mObjectCount(0) - , mObjectLimit(16) -{ -} - -VDCache::~VDCache() { - Shutdown(); -} - -void VDCache::Shutdown() { - for(int i=0; i(ol.back()); - ol.pop_back(); - - pObject->OnCacheEvict(); - pObject->SetCache(NULL); // will release object - - if (i != kVDCacheStateFree) { - VDASSERT((int)--mObjectCount >= 0); - } - } - } -} - -int VDCache::GetStateCount(int state) { - vdsynchronized(mLock) { - return mLists[state].size(); - } -} - -void VDCache::DumpListStatus(int state) { - vdsynchronized(mLock) { - ObjectList& ol = mLists[state]; - - for(ObjectList::iterator it(ol.begin()), itEnd(ol.end()); it!=itEnd; ++it) { - VDCachedObject *pObj = static_cast(*it); - - pObj->DumpStatus(); - } - } -} - -VDCachedObject *VDCache::Allocate(sint64 key) { - VDCachedObject *pObj = NULL; - - vdsynchronized(mLock) { - if (mObjectCount >= mObjectLimit - 1) - Evict(mObjectLimit - 1); - - ObjectList& fl = mLists[kVDCacheStateFree]; - ObjectList& pl = mLists[kVDCacheStatePending]; - - if (fl.empty()) { - VDCachedObject *pNewObject = mpAllocator->OnCacheAllocate(); - - pNewObject->SetCache(this); - pNewObject->SetState(kVDCacheStateFree); - - fl.push_front(pNewObject); - } - - ++mObjectCount; - - pObj = static_cast(fl.front()); - VDASSERT(pObj->GetState() == kVDCacheStateFree); - pObj->AddRef(); - pObj->SetState(kVDCacheStatePending); - pObj->mHashKey = key; - pl.splice(pl.begin(), fl, fl.fast_find(pObj)); - mHash.insert(pObj); - } - - return pObj; -} - -VDCachedObject *VDCache::Create(sint64 key, bool& is_new) { - // The pending, ready, active, and complete lists are eligible for lookup. - // The free and aborted lists are not. - - VDCachedObject *pObj = NULL; - - is_new = false; - - vdsynchronized(mLock) { - pObj = static_cast(mHash[key]); - - if (pObj) { - pObj->AddRef(); - - VDASSERT(pObj->GetState() != kVDCacheStateFree); - - if (pObj->GetState() == kVDCacheStateIdle) { - pObj->SetState(kVDCacheStateComplete); - - ObjectList& il = mLists[kVDCacheStateIdle]; - ObjectList& cl = mLists[kVDCacheStateComplete]; - - cl.splice(cl.begin(), il, il.fast_find(pObj)); - } - } - - if (!pObj) { - is_new = true; - pObj = Allocate(key); - } - } - - return pObj; -} - -void VDCache::Evict(uint32 level) { - if (mObjectCount <= level) - return; - - int maxfree = mObjectCount - level; - - ObjectList& il = mLists[kVDCacheStateIdle]; - ObjectList& al = mLists[kVDCacheStateAborting]; - - while(maxfree-- > 0 && mObjectCount >= level && !il.empty()) { - VDCachedObject *pObject = static_cast(il.back()); - VDASSERT(pObject->GetState() == kVDCacheStateIdle); - - pObject->SetState(kVDCacheStateAborting); - al.splice(al.begin(), il, pObject); - - pObject->WeakAddRef(); - - mLock.Unlock(); - - pObject->OnCacheEvict(); - pObject->WeakRelease(); // Will move to free list. - - mLock.Lock(); - } -} - -void VDCache::NotifyFree(VDCachedObject *pObject) { - vdsynchronized(mLock) { - int rc = pObject->GetRefCount(); - - // This check is required because it is possible for a call to - // Allocate() to sneak in before we acquire the lock. - if (rc < 0x10000) { - VDCacheState oldState = pObject->GetState(); - VDCacheState newState = oldState; - - if (rc & 0xfffe) - newState = kVDCacheStateAborting; - else if (pObject->IsValid()) - newState = kVDCacheStateIdle; - else { - VDVERIFY((int)--mObjectCount >= 0); - newState = kVDCacheStateFree; - mHash.erase(pObject); - } - - if (newState != oldState) { - pObject->SetState(newState); - - ObjectList& nl = mLists[newState]; - ObjectList& ol = mLists[oldState]; - nl.splice(nl.begin(), ol, ol.fast_find(pObject)); - } - - if (oldState == kVDCacheStatePending || oldState == kVDCacheStateReady) - pObject->OnCacheAbortPending(); - } - } -} - -void VDCache::Schedule(VDCachedObject *pObject) { - vdsynchronized(mLock) { - VDCacheState oldState = pObject->GetState(); - - VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive); - - ObjectList& ol = mLists[oldState]; - ObjectList& nl = mLists[kVDCacheStateReady]; - - nl.splice(nl.back(), ol, ol.fast_find(pObject)); - pObject->SetState(kVDCacheStateReady); - } -} - -VDCachedObject *VDCache::GetNextReady() { - VDCachedObject *pObject = NULL; - - vdsynchronized(mLock) { - ObjectList& rl = mLists[kVDCacheStateReady]; - ObjectList& al = mLists[kVDCacheStateActive]; - - if (!rl.empty()) { - pObject = static_cast(rl.front()); - VDASSERT(pObject->GetState() == kVDCacheStateReady); - - al.splice(al.end(), rl, rl.begin()); - - pObject->SetState(kVDCacheStateActive); - pObject->AddRef(); - } - } - - return pObject; -} - -void VDCache::MarkCompleted(VDCachedObject *pObject) { - vdsynchronized(mLock) { - VDCacheState oldState = pObject->GetState(); - VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive); - - ObjectList& al = mLists[oldState]; - ObjectList& cl = mLists[kVDCacheStateComplete]; - - if (!al.empty()) { - cl.splice(cl.end(), al, al.fast_find(pObject)); - - pObject = static_cast(cl.back()); - pObject->SetState(kVDCacheStateComplete); - } - } -} - -/////////////////////////////////////////////////////////////////////////// - -VDCachedObject::VDCachedObject() - : mRefCount(0) - , mpCache(NULL) -{ -} - -int VDCachedObject::AddRef() { - int rv = (mRefCount += 0x10000); - - return rv >> 16; -} - -int VDCachedObject::Release() { - int rv = (mRefCount -= 0x10000); - - VDASSERT(rv >= 0); - - if (rv < 0x10000) { - if (!rv) - delete this; - else if (mpCache) - mpCache->NotifyFree(this); - } - - return rv >> 16; -} - -void VDCachedObject::WeakAddRef() { - mRefCount += 2; -} - -void VDCachedObject::WeakRelease() { - int rv = (mRefCount -= 2); - - VDASSERT((rv & 0xffff) < 0x8000); - - if (rv < 2) { - if (!rv) - delete this; - else - mpCache->NotifyFree(this); - } -} - -void VDCachedObject::SetCache(VDCache *pCache) { - mpCache = pCache; - if (pCache) - ++mRefCount; - else { - if (!--mRefCount) - delete this; - } -} - -/////////////////////////////////////////////////////////////////////////// - -VDPool::VDPool(IVDPoolAllocator *pAllocator) - : mpAllocator(pAllocator) - , mObjectCount(0) - , mObjectLimit(16) -{ -} - -VDPool::~VDPool() { - Shutdown(); -} - -void VDPool::Shutdown() { - for(int i=0; i(ol.back()); - ol.pop_back(); - - pObject->SetPool(NULL); // will release object - - VDASSERT((int)--mObjectCount >= 0); - } - } -} - -VDPooledObject *VDPool::Allocate() { - VDPooledObject *pObj = NULL; - - vdsynchronized(mLock) { - ObjectList& fl = mLists[kVDPoolStateFree]; - ObjectList& pl = mLists[kVDPoolStateActive]; - - if (fl.empty()) { - VDPooledObject *pNewObject = mpAllocator->OnPoolAllocate(); - - pNewObject->SetPool(this); - - fl.push_front(pNewObject); - ++mObjectCount; - } - - pObj = static_cast(fl.front()); - pObj->AddRef(); - pl.splice(pl.begin(), fl, fl.fast_find(pObj)); - } - - return pObj; -} - -void VDPool::NotifyFree(VDPooledObject *pObject) { - vdsynchronized(mLock) { - // This check is required because it is possible for a call to - // Allocate() to sneak in before we acquire the lock. - - if (pObject->GetRefCount() < 2) { - VDPoolState oldState = kVDPoolStateActive; - VDPoolState newState = kVDPoolStateFree; - - mLists[kVDPoolStateActive].erase(pObject); - - if (mObjectCount > mObjectLimit) { - delete pObject; - --mObjectCount; - } else - mLists[kVDPoolStateFree].push_back(pObject); - } - } -} - -/////////////////////////////////////////////////////////////////////////// - -VDPooledObject::VDPooledObject() - : mRefCount(0) - , mpPool(NULL) -{ -} - -int VDPooledObject::AddRef() { - return (mRefCount += 2) >> 1; -} - -int VDPooledObject::Release() { - int rv = (mRefCount -= 2); - - VDASSERT(rv >= 0); - - if (rv < 2) { - if (!rv) - delete this; - else if (mpPool) - mpPool->NotifyFree(this); - } - - return rv >> 1; -} - -void VDPooledObject::SetPool(VDPool *pPool) { - mpPool = pPool; - if (pPool) - ++mRefCount; - else { - if (!--mRefCount) - delete this; - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +/////////////////////////////////////////////////////////////////////////// + +VDCache::VDCache(IVDCacheAllocator *pAllocator) + : mpAllocator(pAllocator) + , mObjectCount(0) + , mObjectLimit(16) +{ +} + +VDCache::~VDCache() { + Shutdown(); +} + +void VDCache::Shutdown() { + for(int i=0; i(ol.back()); + ol.pop_back(); + + pObject->OnCacheEvict(); + pObject->SetCache(NULL); // will release object + + if (i != kVDCacheStateFree) { + VDASSERT((int)--mObjectCount >= 0); + } + } + } +} + +int VDCache::GetStateCount(int state) { + vdsynchronized(mLock) { + return mLists[state].size(); + } +} + +void VDCache::DumpListStatus(int state) { + vdsynchronized(mLock) { + ObjectList& ol = mLists[state]; + + for(ObjectList::iterator it(ol.begin()), itEnd(ol.end()); it!=itEnd; ++it) { + VDCachedObject *pObj = static_cast(*it); + + pObj->DumpStatus(); + } + } +} + +VDCachedObject *VDCache::Allocate(sint64 key) { + VDCachedObject *pObj = NULL; + + vdsynchronized(mLock) { + if (mObjectCount >= mObjectLimit - 1) + Evict(mObjectLimit - 1); + + ObjectList& fl = mLists[kVDCacheStateFree]; + ObjectList& pl = mLists[kVDCacheStatePending]; + + if (fl.empty()) { + VDCachedObject *pNewObject = mpAllocator->OnCacheAllocate(); + + pNewObject->SetCache(this); + pNewObject->SetState(kVDCacheStateFree); + + fl.push_front(pNewObject); + } + + ++mObjectCount; + + pObj = static_cast(fl.front()); + VDASSERT(pObj->GetState() == kVDCacheStateFree); + pObj->AddRef(); + pObj->SetState(kVDCacheStatePending); + pObj->mHashKey = key; + pl.splice(pl.begin(), fl, fl.fast_find(pObj)); + mHash.insert(pObj); + } + + return pObj; +} + +VDCachedObject *VDCache::Create(sint64 key, bool& is_new) { + // The pending, ready, active, and complete lists are eligible for lookup. + // The free and aborted lists are not. + + VDCachedObject *pObj = NULL; + + is_new = false; + + vdsynchronized(mLock) { + pObj = static_cast(mHash[key]); + + if (pObj) { + pObj->AddRef(); + + VDASSERT(pObj->GetState() != kVDCacheStateFree); + + if (pObj->GetState() == kVDCacheStateIdle) { + pObj->SetState(kVDCacheStateComplete); + + ObjectList& il = mLists[kVDCacheStateIdle]; + ObjectList& cl = mLists[kVDCacheStateComplete]; + + cl.splice(cl.begin(), il, il.fast_find(pObj)); + } + } + + if (!pObj) { + is_new = true; + pObj = Allocate(key); + } + } + + return pObj; +} + +void VDCache::Evict(uint32 level) { + if (mObjectCount <= level) + return; + + int maxfree = mObjectCount - level; + + ObjectList& il = mLists[kVDCacheStateIdle]; + ObjectList& al = mLists[kVDCacheStateAborting]; + + while(maxfree-- > 0 && mObjectCount >= level && !il.empty()) { + VDCachedObject *pObject = static_cast(il.back()); + VDASSERT(pObject->GetState() == kVDCacheStateIdle); + + pObject->SetState(kVDCacheStateAborting); + al.splice(al.begin(), il, pObject); + + pObject->WeakAddRef(); + + mLock.Unlock(); + + pObject->OnCacheEvict(); + pObject->WeakRelease(); // Will move to free list. + + mLock.Lock(); + } +} + +void VDCache::NotifyFree(VDCachedObject *pObject) { + vdsynchronized(mLock) { + int rc = pObject->GetRefCount(); + + // This check is required because it is possible for a call to + // Allocate() to sneak in before we acquire the lock. + if (rc < 0x10000) { + VDCacheState oldState = pObject->GetState(); + VDCacheState newState = oldState; + + if (rc & 0xfffe) + newState = kVDCacheStateAborting; + else if (pObject->IsValid()) + newState = kVDCacheStateIdle; + else { + VDVERIFY((int)--mObjectCount >= 0); + newState = kVDCacheStateFree; + mHash.erase(pObject); + } + + if (newState != oldState) { + pObject->SetState(newState); + + ObjectList& nl = mLists[newState]; + ObjectList& ol = mLists[oldState]; + nl.splice(nl.begin(), ol, ol.fast_find(pObject)); + } + + if (oldState == kVDCacheStatePending || oldState == kVDCacheStateReady) + pObject->OnCacheAbortPending(); + } + } +} + +void VDCache::Schedule(VDCachedObject *pObject) { + vdsynchronized(mLock) { + VDCacheState oldState = pObject->GetState(); + + VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive); + + ObjectList& ol = mLists[oldState]; + ObjectList& nl = mLists[kVDCacheStateReady]; + + nl.splice(nl.back(), ol, ol.fast_find(pObject)); + pObject->SetState(kVDCacheStateReady); + } +} + +VDCachedObject *VDCache::GetNextReady() { + VDCachedObject *pObject = NULL; + + vdsynchronized(mLock) { + ObjectList& rl = mLists[kVDCacheStateReady]; + ObjectList& al = mLists[kVDCacheStateActive]; + + if (!rl.empty()) { + pObject = static_cast(rl.front()); + VDASSERT(pObject->GetState() == kVDCacheStateReady); + + al.splice(al.end(), rl, rl.begin()); + + pObject->SetState(kVDCacheStateActive); + pObject->AddRef(); + } + } + + return pObject; +} + +void VDCache::MarkCompleted(VDCachedObject *pObject) { + vdsynchronized(mLock) { + VDCacheState oldState = pObject->GetState(); + VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive); + + ObjectList& al = mLists[oldState]; + ObjectList& cl = mLists[kVDCacheStateComplete]; + + if (!al.empty()) { + cl.splice(cl.end(), al, al.fast_find(pObject)); + + pObject = static_cast(cl.back()); + pObject->SetState(kVDCacheStateComplete); + } + } +} + +/////////////////////////////////////////////////////////////////////////// + +VDCachedObject::VDCachedObject() + : mRefCount(0) + , mpCache(NULL) +{ +} + +int VDCachedObject::AddRef() { + int rv = (mRefCount += 0x10000); + + return rv >> 16; +} + +int VDCachedObject::Release() { + int rv = (mRefCount -= 0x10000); + + VDASSERT(rv >= 0); + + if (rv < 0x10000) { + if (!rv) + delete this; + else if (mpCache) + mpCache->NotifyFree(this); + } + + return rv >> 16; +} + +void VDCachedObject::WeakAddRef() { + mRefCount += 2; +} + +void VDCachedObject::WeakRelease() { + int rv = (mRefCount -= 2); + + VDASSERT((rv & 0xffff) < 0x8000); + + if (rv < 2) { + if (!rv) + delete this; + else + mpCache->NotifyFree(this); + } +} + +void VDCachedObject::SetCache(VDCache *pCache) { + mpCache = pCache; + if (pCache) + ++mRefCount; + else { + if (!--mRefCount) + delete this; + } +} + +/////////////////////////////////////////////////////////////////////////// + +VDPool::VDPool(IVDPoolAllocator *pAllocator) + : mpAllocator(pAllocator) + , mObjectCount(0) + , mObjectLimit(16) +{ +} + +VDPool::~VDPool() { + Shutdown(); +} + +void VDPool::Shutdown() { + for(int i=0; i(ol.back()); + ol.pop_back(); + + pObject->SetPool(NULL); // will release object + + VDASSERT((int)--mObjectCount >= 0); + } + } +} + +VDPooledObject *VDPool::Allocate() { + VDPooledObject *pObj = NULL; + + vdsynchronized(mLock) { + ObjectList& fl = mLists[kVDPoolStateFree]; + ObjectList& pl = mLists[kVDPoolStateActive]; + + if (fl.empty()) { + VDPooledObject *pNewObject = mpAllocator->OnPoolAllocate(); + + pNewObject->SetPool(this); + + fl.push_front(pNewObject); + ++mObjectCount; + } + + pObj = static_cast(fl.front()); + pObj->AddRef(); + pl.splice(pl.begin(), fl, fl.fast_find(pObj)); + } + + return pObj; +} + +void VDPool::NotifyFree(VDPooledObject *pObject) { + vdsynchronized(mLock) { + // This check is required because it is possible for a call to + // Allocate() to sneak in before we acquire the lock. + + if (pObject->GetRefCount() < 2) { + VDPoolState oldState = kVDPoolStateActive; + VDPoolState newState = kVDPoolStateFree; + + mLists[kVDPoolStateActive].erase(pObject); + + if (mObjectCount > mObjectLimit) { + delete pObject; + --mObjectCount; + } else + mLists[kVDPoolStateFree].push_back(pObject); + } + } +} + +/////////////////////////////////////////////////////////////////////////// + +VDPooledObject::VDPooledObject() + : mRefCount(0) + , mpPool(NULL) +{ +} + +int VDPooledObject::AddRef() { + return (mRefCount += 2) >> 1; +} + +int VDPooledObject::Release() { + int rv = (mRefCount -= 2); + + VDASSERT(rv >= 0); + + if (rv < 2) { + if (!rv) + delete this; + else if (mpPool) + mpPool->NotifyFree(this); + } + + return rv >> 1; +} + +void VDPooledObject::SetPool(VDPool *pPool) { + mpPool = pPool; + if (pPool) + ++mRefCount; + else { + if (!--mRefCount) + delete this; + } +} diff --git a/src/thirdparty/VirtualDub/system/source/cmdline.cpp b/src/thirdparty/VirtualDub/system/source/cmdline.cpp index 51b7658c344..2c7fdd66e3d 100644 --- a/src/thirdparty/VirtualDub/system/source/cmdline.cpp +++ b/src/thirdparty/VirtualDub/system/source/cmdline.cpp @@ -1,274 +1,274 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2005 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -VDCommandLine::VDCommandLine() { -} - -VDCommandLine::VDCommandLine(const wchar_t *s) { - Init(s); -} - -VDCommandLine::~VDCommandLine() { -} - -void VDCommandLine::Init(const wchar_t *s) { - mTokens.clear(); - mLine.clear(); - - for(;;) { - while(iswspace(*s)) - ++s; - - if (!*s) - break; - - Token te = { (int)mLine.size(), *s == L'/' }; - - if (te.mbIsSwitch) { - mLine.push_back(L'/'); - ++s; - } - - mTokens.push_back(te); - - // special case for /? - if (te.mbIsSwitch && *s == L'?') { - mLine.push_back(L'?'); - ++s; - } - - while(*s && *s != L' ' && *s != L'/') { - if (te.mbIsSwitch) { - if (!isalnum((unsigned char)*s)) { - if (*s == L':') - ++s; - break; - } - - mLine.push_back(*s++); - } else if (*s == L'"') { - ++s; - while(*s && *s != L'"') - mLine.push_back(*s++); - - if (*s) { - ++s; - - if (*s == ',') { - ++s; - break; - } - } - } else - mLine.push_back(*s++); - } - - mLine.push_back(0); - } -} - -void VDCommandLine::InitAlt(const wchar_t *s) { - mTokens.clear(); - mLine.clear(); - - for(;;) { - while(*s == L' ' || *s == L'\t') - ++s; - - if (!*s) - break; - - Token te = { (int)mLine.size(), *s == L'/' }; - - if (te.mbIsSwitch) { - mLine.push_back(L'/'); - ++s; - } - - mTokens.push_back(te); - - // special case for /? - if (te.mbIsSwitch && *s == L'?') { - mLine.push_back(L'?'); - ++s; - } - - bool inquote = false; - for(;;) { - wchar_t c = *s; - - if (!c) - break; - - if (!inquote && (c == L' ' || c == L'\t' || c == L'/')) - break; - - if (te.mbIsSwitch) { - if (!isalnum((unsigned char)*s)) { - if (*s == L':') - ++s; - break; - } - - mLine.push_back(c); - ++s; - } else { - if (c == L'\\') { - uint32 backslashes = 0; - - do { - ++backslashes; - c = *++s; - } while(c == L'\\'); - - bool postquote = false; - if (c == L'"') { - if (backslashes & 1) - postquote = true; - else - inquote = !inquote; - - backslashes >>= 1; - ++s; - } - - while(backslashes--) - mLine.push_back(L'\\'); - - if (postquote) - mLine.push_back(L'"'); - } else { - if (c == L'"') - inquote = !inquote; - else - mLine.push_back(c); - - ++s; - } - } - } - - mLine.push_back(0); - } -} - -uint32 VDCommandLine::GetCount() const { - return mTokens.size(); -} - -const wchar_t *VDCommandLine::operator[](int index) const { - return (uint32)index < mTokens.size() ? mLine.data() + mTokens[index].mTokenIndex : NULL; -} - -const VDStringSpanW VDCommandLine::operator()(int index) const { - if ((uint32)index >= mTokens.size()) - return VDStringSpanW(); - - const wchar_t *s = mLine.data() + mTokens[index].mTokenIndex; - - return VDStringSpanW(s); -} - -bool VDCommandLine::GetNextArgument(VDCommandLineIterator& it, const wchar_t *& token, bool& isSwitch) const { - int count = (int)mTokens.size(); - - if (it.mIndex >= count) - return false; - - token = mLine.data() + mTokens[it.mIndex].mTokenIndex; - isSwitch = mTokens[it.mIndex].mbIsSwitch; - - ++it.mIndex; - return true; -} - -bool VDCommandLine::GetNextNonSwitchArgument(VDCommandLineIterator& it, const wchar_t *& token) const { - int count = (int)mTokens.size(); - - if (it.mIndex >= count) - return false; - - if (mTokens[it.mIndex].mbIsSwitch) - return false; - - token = mLine.data() + mTokens[it.mIndex++].mTokenIndex; - return true; -} - -bool VDCommandLine::GetNextSwitchArgument(VDCommandLineIterator& it, const wchar_t *& token) const { - int count = (int)mTokens.size(); - - if (it.mIndex >= count) - return false; - - if (!mTokens[it.mIndex].mbIsSwitch) - return false; - - token = mLine.data() + mTokens[it.mIndex++].mTokenIndex; - return true; -} - -bool VDCommandLine::FindAndRemoveSwitch(const wchar_t *name) { - int count = (int)mTokens.size(); - - for(int i=1; i +#include + +VDCommandLine::VDCommandLine() { +} + +VDCommandLine::VDCommandLine(const wchar_t *s) { + Init(s); +} + +VDCommandLine::~VDCommandLine() { +} + +void VDCommandLine::Init(const wchar_t *s) { + mTokens.clear(); + mLine.clear(); + + for(;;) { + while(iswspace(*s)) + ++s; + + if (!*s) + break; + + Token te = { (int)mLine.size(), *s == L'/' }; + + if (te.mbIsSwitch) { + mLine.push_back(L'/'); + ++s; + } + + mTokens.push_back(te); + + // special case for /? + if (te.mbIsSwitch && *s == L'?') { + mLine.push_back(L'?'); + ++s; + } + + while(*s && *s != L' ' && *s != L'/') { + if (te.mbIsSwitch) { + if (!isalnum((unsigned char)*s)) { + if (*s == L':') + ++s; + break; + } + + mLine.push_back(*s++); + } else if (*s == L'"') { + ++s; + while(*s && *s != L'"') + mLine.push_back(*s++); + + if (*s) { + ++s; + + if (*s == ',') { + ++s; + break; + } + } + } else + mLine.push_back(*s++); + } + + mLine.push_back(0); + } +} + +void VDCommandLine::InitAlt(const wchar_t *s) { + mTokens.clear(); + mLine.clear(); + + for(;;) { + while(*s == L' ' || *s == L'\t') + ++s; + + if (!*s) + break; + + Token te = { (int)mLine.size(), *s == L'/' }; + + if (te.mbIsSwitch) { + mLine.push_back(L'/'); + ++s; + } + + mTokens.push_back(te); + + // special case for /? + if (te.mbIsSwitch && *s == L'?') { + mLine.push_back(L'?'); + ++s; + } + + bool inquote = false; + for(;;) { + wchar_t c = *s; + + if (!c) + break; + + if (!inquote && (c == L' ' || c == L'\t' || c == L'/')) + break; + + if (te.mbIsSwitch) { + if (!isalnum((unsigned char)*s)) { + if (*s == L':') + ++s; + break; + } + + mLine.push_back(c); + ++s; + } else { + if (c == L'\\') { + uint32 backslashes = 0; + + do { + ++backslashes; + c = *++s; + } while(c == L'\\'); + + bool postquote = false; + if (c == L'"') { + if (backslashes & 1) + postquote = true; + else + inquote = !inquote; + + backslashes >>= 1; + ++s; + } + + while(backslashes--) + mLine.push_back(L'\\'); + + if (postquote) + mLine.push_back(L'"'); + } else { + if (c == L'"') + inquote = !inquote; + else + mLine.push_back(c); + + ++s; + } + } + } + + mLine.push_back(0); + } +} + +uint32 VDCommandLine::GetCount() const { + return mTokens.size(); +} + +const wchar_t *VDCommandLine::operator[](int index) const { + return (uint32)index < mTokens.size() ? mLine.data() + mTokens[index].mTokenIndex : NULL; +} + +const VDStringSpanW VDCommandLine::operator()(int index) const { + if ((uint32)index >= mTokens.size()) + return VDStringSpanW(); + + const wchar_t *s = mLine.data() + mTokens[index].mTokenIndex; + + return VDStringSpanW(s); +} + +bool VDCommandLine::GetNextArgument(VDCommandLineIterator& it, const wchar_t *& token, bool& isSwitch) const { + int count = (int)mTokens.size(); + + if (it.mIndex >= count) + return false; + + token = mLine.data() + mTokens[it.mIndex].mTokenIndex; + isSwitch = mTokens[it.mIndex].mbIsSwitch; + + ++it.mIndex; + return true; +} + +bool VDCommandLine::GetNextNonSwitchArgument(VDCommandLineIterator& it, const wchar_t *& token) const { + int count = (int)mTokens.size(); + + if (it.mIndex >= count) + return false; + + if (mTokens[it.mIndex].mbIsSwitch) + return false; + + token = mLine.data() + mTokens[it.mIndex++].mTokenIndex; + return true; +} + +bool VDCommandLine::GetNextSwitchArgument(VDCommandLineIterator& it, const wchar_t *& token) const { + int count = (int)mTokens.size(); + + if (it.mIndex >= count) + return false; + + if (!mTokens[it.mIndex].mbIsSwitch) + return false; + + token = mLine.data() + mTokens[it.mIndex++].mTokenIndex; + return true; +} + +bool VDCommandLine::FindAndRemoveSwitch(const wchar_t *name) { + int count = (int)mTokens.size(); + + for(int i=1; i -#include -#include -#include - -static long g_lCPUExtensionsEnabled; -static long g_lCPUExtensionsAvailable; - -extern "C" { - bool FPU_enabled, MMX_enabled, SSE_enabled, ISSE_enabled, SSE2_enabled; -}; - -#if (!defined(VD_CPU_X86) && !defined(VD_CPU_AMD64)) || defined(__MINGW32__) -long CPUCheckForExtensions() { - return 0; -} -#else - -namespace { -#ifdef _M_IX86 - bool VDIsAVXSupportedByOS() { - uint32 xfeature_enabled_mask; - - __asm { - xor ecx, ecx - __emit 0x0f ;xgetbv - __emit 0x01 - __emit 0xd0 - mov dword ptr xfeature_enabled_mask, eax - } - - return (xfeature_enabled_mask & 0x06) == 0x06; - } -#else - extern "C" bool VDIsAVXSupportedByOS(); -#endif -} - -// This code used to use IsProcessorFeaturePresent(), but this function is somewhat -// suboptimal in Win64 -- for one thing, it doesn't return true for MMX, at least -// on Vista 64. -long CPUCheckForExtensions() { - // check for CPUID (x86 only) -#ifdef _M_IX86 - uint32 id; - __asm { - pushfd - or dword ptr [esp], 00200000h ;set the ID bit - popfd - pushfd ;flags -> EAX - pop dword ptr id - } - - if (!(id & 0x00200000)) { - // if we don't have CPUID, we probably won't want to try FPU optimizations - // (80486). - return 0; - } -#endif - - // check for features register - long flags = CPUF_SUPPORTS_FPU | CPUF_SUPPORTS_CPUID; - - int cpuInfo[4]; - __cpuid(cpuInfo, 0); - if (cpuInfo[0] == 0) - return flags; - - __cpuid(cpuInfo, 1); - - if (cpuInfo[3] & (1 << 23)) - flags |= CPUF_SUPPORTS_MMX; - - if (cpuInfo[3] & (1 << 25)) { - // Check if SSE is actually supported. - bool sseSupported = true; - -#ifdef _M_IX86 - __try { - __asm andps xmm0,xmm0 - } __except(EXCEPTION_EXECUTE_HANDLER) { - if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) - sseSupported = false; - } -#endif - - if (sseSupported) { - flags |= CPUF_SUPPORTS_SSE | CPUF_SUPPORTS_INTEGER_SSE; - - if (cpuInfo[3] & (1 << 26)) - flags |= CPUF_SUPPORTS_SSE2; - - if (cpuInfo[2] & 0x00000001) - flags |= CPUF_SUPPORTS_SSE3; - - if (cpuInfo[2] & 0x00000200) - flags |= CPUF_SUPPORTS_SSSE3; - - if (cpuInfo[2] & 0x00080000) - flags |= CPUF_SUPPORTS_SSE41; - - if (cpuInfo[2] & 0x00100000) - flags |= CPUF_SUPPORTS_SSE42; - - // check OSXSAVE and AVX bits - if ((cpuInfo[2] & ((1 << 27) | (1 << 28))) == ((1 << 27) | (1 << 28))) { - if (VDIsAVXSupportedByOS()) - flags |= CPUF_SUPPORTS_AVX; - } - } - } - - // check for 3DNow!, 3DNow! extensions - __cpuid(cpuInfo, 0x80000000); - if ((unsigned)cpuInfo[0] >= 0x80000001U) { - __cpuid(cpuInfo, 0x80000001); - - if (cpuInfo[3] & (1 << 31)) - flags |= CPUF_SUPPORTS_3DNOW; - - if (cpuInfo[3] & (1 << 30)) - flags |= CPUF_SUPPORTS_3DNOW_EXT; - - if (cpuInfo[3] & (1 << 22)) - flags |= CPUF_SUPPORTS_INTEGER_SSE; - } - - return flags; -} -#endif - -long CPUEnableExtensions(long lEnableFlags) { - g_lCPUExtensionsEnabled = lEnableFlags; - - MMX_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_MMX); - FPU_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_FPU); - SSE_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_SSE); - ISSE_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_INTEGER_SSE); - SSE2_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_SSE2); - - return g_lCPUExtensionsEnabled; -} - -long CPUGetAvailableExtensions() { - return g_lCPUExtensionsAvailable; -} - -long CPUGetEnabledExtensions() { - return g_lCPUExtensionsEnabled; -} - -void VDCPUCleanupExtensions() { -#if defined(VD_CPU_X86) - if (ISSE_enabled) - _mm_sfence(); - - if (MMX_enabled) - _mm_empty(); -#elif defined(VD_CPU_AMD64) - _mm_sfence(); -#endif -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include +#include + +static long g_lCPUExtensionsEnabled; +static long g_lCPUExtensionsAvailable; + +extern "C" { + bool FPU_enabled, MMX_enabled, SSE_enabled, ISSE_enabled, SSE2_enabled; +}; + +#if (!defined(VD_CPU_X86) && !defined(VD_CPU_AMD64)) || defined(__MINGW32__) +long CPUCheckForExtensions() { + return 0; +} +#else + +namespace { +#ifdef _M_IX86 + bool VDIsAVXSupportedByOS() { + uint32 xfeature_enabled_mask; + + __asm { + xor ecx, ecx + __emit 0x0f ;xgetbv + __emit 0x01 + __emit 0xd0 + mov dword ptr xfeature_enabled_mask, eax + } + + return (xfeature_enabled_mask & 0x06) == 0x06; + } +#else + extern "C" bool VDIsAVXSupportedByOS(); +#endif +} + +// This code used to use IsProcessorFeaturePresent(), but this function is somewhat +// suboptimal in Win64 -- for one thing, it doesn't return true for MMX, at least +// on Vista 64. +long CPUCheckForExtensions() { + // check for CPUID (x86 only) +#ifdef _M_IX86 + uint32 id; + __asm { + pushfd + or dword ptr [esp], 00200000h ;set the ID bit + popfd + pushfd ;flags -> EAX + pop dword ptr id + } + + if (!(id & 0x00200000)) { + // if we don't have CPUID, we probably won't want to try FPU optimizations + // (80486). + return 0; + } +#endif + + // check for features register + long flags = CPUF_SUPPORTS_FPU | CPUF_SUPPORTS_CPUID; + + int cpuInfo[4]; + __cpuid(cpuInfo, 0); + if (cpuInfo[0] == 0) + return flags; + + __cpuid(cpuInfo, 1); + + if (cpuInfo[3] & (1 << 23)) + flags |= CPUF_SUPPORTS_MMX; + + if (cpuInfo[3] & (1 << 25)) { + // Check if SSE is actually supported. + bool sseSupported = true; + +#ifdef _M_IX86 + __try { + __asm andps xmm0,xmm0 + } __except(EXCEPTION_EXECUTE_HANDLER) { + if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) + sseSupported = false; + } +#endif + + if (sseSupported) { + flags |= CPUF_SUPPORTS_SSE | CPUF_SUPPORTS_INTEGER_SSE; + + if (cpuInfo[3] & (1 << 26)) + flags |= CPUF_SUPPORTS_SSE2; + + if (cpuInfo[2] & 0x00000001) + flags |= CPUF_SUPPORTS_SSE3; + + if (cpuInfo[2] & 0x00000200) + flags |= CPUF_SUPPORTS_SSSE3; + + if (cpuInfo[2] & 0x00080000) + flags |= CPUF_SUPPORTS_SSE41; + + if (cpuInfo[2] & 0x00100000) + flags |= CPUF_SUPPORTS_SSE42; + + // check OSXSAVE and AVX bits + if ((cpuInfo[2] & ((1 << 27) | (1 << 28))) == ((1 << 27) | (1 << 28))) { + if (VDIsAVXSupportedByOS()) + flags |= CPUF_SUPPORTS_AVX; + } + } + } + + // check for 3DNow!, 3DNow! extensions + __cpuid(cpuInfo, 0x80000000); + if ((unsigned)cpuInfo[0] >= 0x80000001U) { + __cpuid(cpuInfo, 0x80000001); + + if (cpuInfo[3] & (1 << 31)) + flags |= CPUF_SUPPORTS_3DNOW; + + if (cpuInfo[3] & (1 << 30)) + flags |= CPUF_SUPPORTS_3DNOW_EXT; + + if (cpuInfo[3] & (1 << 22)) + flags |= CPUF_SUPPORTS_INTEGER_SSE; + } + + return flags; +} +#endif + +long CPUEnableExtensions(long lEnableFlags) { + g_lCPUExtensionsEnabled = lEnableFlags; + + MMX_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_MMX); + FPU_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_FPU); + SSE_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_SSE); + ISSE_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_INTEGER_SSE); + SSE2_enabled = !!(g_lCPUExtensionsEnabled & CPUF_SUPPORTS_SSE2); + + return g_lCPUExtensionsEnabled; +} + +long CPUGetAvailableExtensions() { + return g_lCPUExtensionsAvailable; +} + +long CPUGetEnabledExtensions() { + return g_lCPUExtensionsEnabled; +} + +void VDCPUCleanupExtensions() { +#if defined(VD_CPU_X86) + if (ISSE_enabled) + _mm_sfence(); + + if (MMX_enabled) + _mm_empty(); +#elif defined(VD_CPU_AMD64) + _mm_sfence(); +#endif +} diff --git a/src/thirdparty/VirtualDub/system/source/debug.cpp b/src/thirdparty/VirtualDub/system/source/debug.cpp index d0173e497b3..66ff40a8eef 100644 --- a/src/thirdparty/VirtualDub/system/source/debug.cpp +++ b/src/thirdparty/VirtualDub/system/source/debug.cpp @@ -1,290 +1,290 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -#include -#include - -#include -#include -#include -#include - -#ifdef _DEBUG - -class VDSafeMessageBoxThreadW32 : public VDThread { -public: - VDSafeMessageBoxThreadW32(HWND hwndParent, const char *pszText, const char *pszCaption, DWORD dwFlags) - : mhwndParent(hwndParent) - , mpszText(pszText) - , mpszCaption(pszCaption) - , mdwFlags(dwFlags) - { - } - - DWORD GetResult() const { return mdwResult; } - -protected: - void ThreadRun() { - mdwResult = MessageBox(mhwndParent, mpszText, mpszCaption, mdwFlags); - } - - HWND mhwndParent; - const char *const mpszText; - const char *const mpszCaption; - const DWORD mdwFlags; - DWORD mdwResult; -}; - -UINT VDSafeMessageBoxW32(HWND hwndParent, const char *pszText, const char *pszCaption, DWORD dwFlags) { - VDSafeMessageBoxThreadW32 mbox(hwndParent, pszText, pszCaption, dwFlags); - - mbox.ThreadStart(); - mbox.ThreadWait(); - return mbox.GetResult(); -} - -VDAssertResult VDAssert(const char *exp, const char *file, int line) { - DWORD dwOldError = GetLastError(); - char szText[1024]; - - VDDEBUG("%s(%d): Assert failed: %s\n", file, line, exp); - - wsprintf(szText, - "Assert failed in module %s, line %d:\n" - "\n" - "\t%s\n" - "\n" - "Break into debugger?", file, line, exp); - - UINT result = VDSafeMessageBoxW32(NULL, szText, "Assert failure", MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_TASKMODAL); - - SetLastError(dwOldError); - - switch(result) { - case IDABORT: - ::Sleep(250); // Pause for a moment so the VC6 debugger doesn't freeze. - return kVDAssertBreak; - case IDRETRY: - return kVDAssertContinue; - default: - VDNEVERHERE; - case IDIGNORE: - return kVDAssertIgnore; - } -} - -VDAssertResult VDAssertPtr(const char *exp, const char *file, int line) { - DWORD dwOldError = GetLastError(); - char szText[1024]; - - VDDEBUG("%s(%d): Assert failed: %s is not a valid pointer\n", file, line, exp); - - wsprintf(szText, - "Assert failed in module %s, line %d:\n" - "\n" - "\t(%s) not a valid pointer\n" - "\n" - "Break into debugger?", file, line, exp); - - UINT result = VDSafeMessageBoxW32(NULL, szText, "Assert failure", MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_TASKMODAL); - - SetLastError(dwOldError); - - switch(result) { - case IDABORT: - return kVDAssertBreak; - case IDRETRY: - return kVDAssertContinue; - default: - VDNEVERHERE; - case IDIGNORE: - return kVDAssertIgnore; - } -} - -#endif - -void VDProtectedAutoScopeICLWorkaround() {} - -void VDDebugPrint(const char *format, ...) { - char buf[4096]; - - va_list val; - va_start(val, format); - _vsnprintf(buf, sizeof buf, format, val); - va_end(val); - Sleep(0); - OutputDebugString(buf); -} - -/////////////////////////////////////////////////////////////////////////// - -namespace { - IVDExternalCallTrap *g_pExCallTrap; -} - -void VDSetExternalCallTrap(IVDExternalCallTrap *trap) { - g_pExCallTrap = trap; -} - -#if defined(WIN32) && defined(_M_IX86) && defined(__MSC_VER) - namespace { - bool IsFPUStateOK(unsigned& ctlword) { - ctlword = 0; - - __asm mov eax, ctlword - __asm fnstcw [eax] - - ctlword &= 0x0f3f; - - return ctlword == 0x023f; - } - - void ResetFPUState() { - static const unsigned ctlword = 0x027f; - - __asm fnclex - __asm fldcw ctlword - } - - bool IsSSEStateOK(uint32& ctlword) { - ctlword = _mm_getcsr(); - - // Intel C/C++ flips FTZ and DAZ. :( - return (ctlword & 0x7f80) == 0x1f80; - } - - void ResetSSEState() { - _mm_setcsr(0x1f80); - } - } - - bool IsMMXState() { - char buf[28]; - unsigned short tagword; - - __asm fnstenv buf // this resets the FPU control word somehow!? - - tagword = *(unsigned short *)(buf + 8); - - return (tagword != 0xffff); - } - void ClearMMXState() { - if (MMX_enabled) - __asm emms - else { - __asm { - ffree st(0) - ffree st(1) - ffree st(2) - ffree st(3) - ffree st(4) - ffree st(5) - ffree st(6) - ffree st(7) - } - } - } - - void VDClearEvilCPUStates() { - ResetFPUState(); - ClearMMXState(); - } - - void VDPreCheckExternalCodeCall(const char *file, int line) { - unsigned fpucw; - uint32 mxcsr; - bool bFPUStateBad = !IsFPUStateOK(fpucw); - bool bSSEStateBad = SSE_enabled && !IsSSEStateOK(mxcsr); - bool bMMXStateBad = IsMMXState(); - - if (bMMXStateBad || bFPUStateBad || bSSEStateBad) { - ClearMMXState(); - ResetFPUState(); - if (SSE_enabled) - ResetSSEState(); - } - - if (g_pExCallTrap) { - if (bMMXStateBad) - g_pExCallTrap->OnMMXTrap(NULL, file, line); - - if (bFPUStateBad) - g_pExCallTrap->OnFPUTrap(NULL, file, line, fpucw); - - if (bSSEStateBad) - g_pExCallTrap->OnSSETrap(NULL, file, line, mxcsr); - } - } - - void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine) { - unsigned fpucw; - uint32 mxcsr; - bool bFPUStateBad = !IsFPUStateOK(fpucw); - bool bSSEStateBad = SSE_enabled && !IsSSEStateOK(mxcsr); - bool bMMXStateBad = IsMMXState(); - bool bBadState = bMMXStateBad || bFPUStateBad || bSSEStateBad; - - if (bBadState) { - ClearMMXState(); - ResetFPUState(); - if (SSE_enabled) - ResetSSEState(); - } - - if (g_pExCallTrap) { - if (bMMXStateBad) - g_pExCallTrap->OnMMXTrap(mpContext, mpFile, mLine); - - if (bFPUStateBad) - g_pExCallTrap->OnFPUTrap(mpContext, mpFile, mLine, fpucw); - - if (bSSEStateBad) - g_pExCallTrap->OnSSETrap(mpContext, mpFile, mLine, mxcsr); - } - } - -#else - - bool IsMMXState() { - return false; - } - - void ClearMMXState() { - } - - void VDClearEvilCPUStates() { - } - - void VDPreCheckExternalCodeCall(const char *file, int line) { - } - - void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine) { - } - -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include +#include + +#include +#include +#include +#include + +#ifdef _DEBUG + +class VDSafeMessageBoxThreadW32 : public VDThread { +public: + VDSafeMessageBoxThreadW32(HWND hwndParent, const char *pszText, const char *pszCaption, DWORD dwFlags) + : mhwndParent(hwndParent) + , mpszText(pszText) + , mpszCaption(pszCaption) + , mdwFlags(dwFlags) + { + } + + DWORD GetResult() const { return mdwResult; } + +protected: + void ThreadRun() { + mdwResult = MessageBox(mhwndParent, mpszText, mpszCaption, mdwFlags); + } + + HWND mhwndParent; + const char *const mpszText; + const char *const mpszCaption; + const DWORD mdwFlags; + DWORD mdwResult; +}; + +UINT VDSafeMessageBoxW32(HWND hwndParent, const char *pszText, const char *pszCaption, DWORD dwFlags) { + VDSafeMessageBoxThreadW32 mbox(hwndParent, pszText, pszCaption, dwFlags); + + mbox.ThreadStart(); + mbox.ThreadWait(); + return mbox.GetResult(); +} + +VDAssertResult VDAssert(const char *exp, const char *file, int line) { + DWORD dwOldError = GetLastError(); + char szText[1024]; + + VDDEBUG("%s(%d): Assert failed: %s\n", file, line, exp); + + wsprintf(szText, + "Assert failed in module %s, line %d:\n" + "\n" + "\t%s\n" + "\n" + "Break into debugger?", file, line, exp); + + UINT result = VDSafeMessageBoxW32(NULL, szText, "Assert failure", MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_TASKMODAL); + + SetLastError(dwOldError); + + switch(result) { + case IDABORT: + ::Sleep(250); // Pause for a moment so the VC6 debugger doesn't freeze. + return kVDAssertBreak; + case IDRETRY: + return kVDAssertContinue; + default: + VDNEVERHERE; + case IDIGNORE: + return kVDAssertIgnore; + } +} + +VDAssertResult VDAssertPtr(const char *exp, const char *file, int line) { + DWORD dwOldError = GetLastError(); + char szText[1024]; + + VDDEBUG("%s(%d): Assert failed: %s is not a valid pointer\n", file, line, exp); + + wsprintf(szText, + "Assert failed in module %s, line %d:\n" + "\n" + "\t(%s) not a valid pointer\n" + "\n" + "Break into debugger?", file, line, exp); + + UINT result = VDSafeMessageBoxW32(NULL, szText, "Assert failure", MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_TASKMODAL); + + SetLastError(dwOldError); + + switch(result) { + case IDABORT: + return kVDAssertBreak; + case IDRETRY: + return kVDAssertContinue; + default: + VDNEVERHERE; + case IDIGNORE: + return kVDAssertIgnore; + } +} + +#endif + +void VDProtectedAutoScopeICLWorkaround() {} + +void VDDebugPrint(const char *format, ...) { + char buf[4096]; + + va_list val; + va_start(val, format); + _vsnprintf(buf, sizeof buf, format, val); + va_end(val); + Sleep(0); + OutputDebugString(buf); +} + +/////////////////////////////////////////////////////////////////////////// + +namespace { + IVDExternalCallTrap *g_pExCallTrap; +} + +void VDSetExternalCallTrap(IVDExternalCallTrap *trap) { + g_pExCallTrap = trap; +} + +#if defined(WIN32) && defined(_M_IX86) && defined(__MSC_VER) + namespace { + bool IsFPUStateOK(unsigned& ctlword) { + ctlword = 0; + + __asm mov eax, ctlword + __asm fnstcw [eax] + + ctlword &= 0x0f3f; + + return ctlword == 0x023f; + } + + void ResetFPUState() { + static const unsigned ctlword = 0x027f; + + __asm fnclex + __asm fldcw ctlword + } + + bool IsSSEStateOK(uint32& ctlword) { + ctlword = _mm_getcsr(); + + // Intel C/C++ flips FTZ and DAZ. :( + return (ctlword & 0x7f80) == 0x1f80; + } + + void ResetSSEState() { + _mm_setcsr(0x1f80); + } + } + + bool IsMMXState() { + char buf[28]; + unsigned short tagword; + + __asm fnstenv buf // this resets the FPU control word somehow!? + + tagword = *(unsigned short *)(buf + 8); + + return (tagword != 0xffff); + } + void ClearMMXState() { + if (MMX_enabled) + __asm emms + else { + __asm { + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + ffree st(7) + } + } + } + + void VDClearEvilCPUStates() { + ResetFPUState(); + ClearMMXState(); + } + + void VDPreCheckExternalCodeCall(const char *file, int line) { + unsigned fpucw; + uint32 mxcsr; + bool bFPUStateBad = !IsFPUStateOK(fpucw); + bool bSSEStateBad = SSE_enabled && !IsSSEStateOK(mxcsr); + bool bMMXStateBad = IsMMXState(); + + if (bMMXStateBad || bFPUStateBad || bSSEStateBad) { + ClearMMXState(); + ResetFPUState(); + if (SSE_enabled) + ResetSSEState(); + } + + if (g_pExCallTrap) { + if (bMMXStateBad) + g_pExCallTrap->OnMMXTrap(NULL, file, line); + + if (bFPUStateBad) + g_pExCallTrap->OnFPUTrap(NULL, file, line, fpucw); + + if (bSSEStateBad) + g_pExCallTrap->OnSSETrap(NULL, file, line, mxcsr); + } + } + + void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine) { + unsigned fpucw; + uint32 mxcsr; + bool bFPUStateBad = !IsFPUStateOK(fpucw); + bool bSSEStateBad = SSE_enabled && !IsSSEStateOK(mxcsr); + bool bMMXStateBad = IsMMXState(); + bool bBadState = bMMXStateBad || bFPUStateBad || bSSEStateBad; + + if (bBadState) { + ClearMMXState(); + ResetFPUState(); + if (SSE_enabled) + ResetSSEState(); + } + + if (g_pExCallTrap) { + if (bMMXStateBad) + g_pExCallTrap->OnMMXTrap(mpContext, mpFile, mLine); + + if (bFPUStateBad) + g_pExCallTrap->OnFPUTrap(mpContext, mpFile, mLine, fpucw); + + if (bSSEStateBad) + g_pExCallTrap->OnSSETrap(mpContext, mpFile, mLine, mxcsr); + } + } + +#else + + bool IsMMXState() { + return false; + } + + void ClearMMXState() { + } + + void VDClearEvilCPUStates() { + } + + void VDPreCheckExternalCodeCall(const char *file, int line) { + } + + void VDPostCheckExternalCodeCall(const wchar_t *mpContext, const char *mpFile, int mLine) { + } + +#endif diff --git a/src/thirdparty/VirtualDub/system/source/debugx86.cpp b/src/thirdparty/VirtualDub/system/source/debugx86.cpp index f89fe560b04..6784d8d4434 100644 --- a/src/thirdparty/VirtualDub/system/source/debugx86.cpp +++ b/src/thirdparty/VirtualDub/system/source/debugx86.cpp @@ -1,156 +1,156 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include - -bool VDIsValidCallX86(const char *buf, int len) { - // Permissible CALL sequences that we care about: - // - // E8 xx xx xx xx CALL near relative - // FF (group 2) CALL near absolute indirect - // - // Minimum sequence is 2 bytes (call eax). - // Maximum sequence is 7 bytes (call dword ptr [eax+disp32]). - - if (len >= 5 && buf[-5] == (char)0xE8) - return true; - - // FF 14 xx CALL [reg32+reg32*scale] - - if (len >= 3 && buf[-3] == (char)0xFF && buf[-2]==0x14) - return true; - - // FF 15 xx xx xx xx CALL disp32 - - if (len >= 6 && buf[-6] == (char)0xFF && buf[-5]==0x15) - return true; - - // FF 00-3F(!14/15) CALL [reg32] - - if (len >= 2 && buf[-2] == (char)0xFF && (unsigned char)buf[-1] < 0x40) - return true; - - // FF D0-D7 CALL reg32 - - if (len >= 2 && buf[-2] == (char)0xFF && (buf[-1]&0xF8) == 0xD0) - return true; - - // FF 50-57 xx CALL [reg32+reg32*scale+disp8] - - if (len >= 3 && buf[-3] == (char)0xFF && (buf[-2]&0xF8) == 0x50) - return true; - - // FF 90-97 xx xx xx xx xx CALL [reg32+reg32*scale+disp32] - - if (len >= 7 && buf[-7] == (char)0xFF && (buf[-6]&0xF8) == 0x90) - return true; - - return false; -} - -VDInstructionTypeX86 VDGetInstructionTypeX86(const void *p) { - struct local { - static bool RangeHitTest(const uint8 *range, uint8 c) { - while(*range) { - if (c>=range[0] && c<=range[1]) - return true; - range += 2; - } - - return false; - } - }; - - VDInstructionTypeX86 type = kX86InstUnknown; - - vd_seh_guard_try { - unsigned char buf[8]; - - memcpy(buf, p, 8); - - if (buf[0] == 0x0f && buf[1] == 0x0f) - type = kX86Inst3DNow; // Conveniently, all 3DNow! instructions begin 0F 0F - else if ((buf[0] == 0xdb || buf[0] == 0xdf) && (buf[1]>=0xe8 && buf[1]<=0xf7)) - type = kX86InstP6; // DB/DF E8-F7: FCOMI/FCOMIP/FUCOMI/FUCOMIP (P6) - else if ((buf[0]&0xfe)==0xda && (buf[1]&0xe0)==0xc0) - type = kX86InstP6; // DA/DB C0-DF: FCMOVcc (P6) - else if (buf[0] == 0x0f && (buf[1]&0xf0)==0x40) - type = kX86InstP6; // 0F 40-4F: CMOVcc (P6) - else { - const unsigned char *s = buf; - bool bWide = false; - bool bRepF2 = false; - bool bRepF3 = false; - - // At this point we're down to MMX, SSE, SSE2 -- which makes things simpler - // as we must see F2 0F, F3 0F, or 0F next. MMX ops use 0F exclusively, - // some SSE ops use F2, and a few SSE2 ones use F3. If we see 66 on an - // MMX or SSE op it's automatically SSE2 as it's either a 128-bit MMX op - // or a double-precision version of an SSE one. - - if (*s == 0x66) { // 66h override used by SSE2 and is supposed to be ahead of F2/F3 in encodings - ++s; - bWide = true; - } - - if (*s == 0xf2) { - ++s; - bRepF2 = true; - } - - if (*s == 0xf3) { - ++s; - bRepF3 = true; - } - - if (*s++ == 0x0f) { - // SSE - 1x, 28-2F, 5x, C2, AE - // MMX2 - 70, C4-C6, D7, DA, DE, E0, E3, E4, E7, EA, EE, F6, F7 - // MMX - 6x, 7x, Dx, Ex, and Fx except for MMX2 - // SSE2 - C3, SSE ops with 66 or F2, MMX/MMX2 ops with 66/F2/F3 - - static const uint8 sse_ranges[]={0x10,0x1f,0x28,0x2f,0x50,0x5f,0xc2,0xc2,0xae,0xae,0}; - static const uint8 sse2_ranges[]={0xc3,0xc3,0}; - static const uint8 mmx2_ranges[]={0x70,0x70,0xc4,0xc6,0xd7,0xd7,0xda,0xda,0xde,0xde,0xe0,0xe0,0xe3,0xe4,0xe7,0xe7,0xea,0xea,0xee,0xee,0xf6,0xf7,0}; - static const uint8 mmx_ranges[]={0x60,0x7f,0xd0,0xff,0}; - - if (local::RangeHitTest(sse_ranges, *s)) - type = (bWide||bRepF2) ? kX86InstSSE2 : kX86InstSSE; - else if (local::RangeHitTest(sse2_ranges, *s)) - type = kX86InstSSE2; - else if (local::RangeHitTest(mmx2_ranges, *s)) - type = (bWide||bRepF2||bRepF3) ? kX86InstSSE2 : kX86InstMMX2; - else if (local::RangeHitTest(mmx_ranges, *s)) - type = (bWide||bRepF2||bRepF3) ? kX86InstSSE2 : kX86InstMMX; - } - } - } vd_seh_guard_except { - } - - return type; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include + +bool VDIsValidCallX86(const char *buf, int len) { + // Permissible CALL sequences that we care about: + // + // E8 xx xx xx xx CALL near relative + // FF (group 2) CALL near absolute indirect + // + // Minimum sequence is 2 bytes (call eax). + // Maximum sequence is 7 bytes (call dword ptr [eax+disp32]). + + if (len >= 5 && buf[-5] == (char)0xE8) + return true; + + // FF 14 xx CALL [reg32+reg32*scale] + + if (len >= 3 && buf[-3] == (char)0xFF && buf[-2]==0x14) + return true; + + // FF 15 xx xx xx xx CALL disp32 + + if (len >= 6 && buf[-6] == (char)0xFF && buf[-5]==0x15) + return true; + + // FF 00-3F(!14/15) CALL [reg32] + + if (len >= 2 && buf[-2] == (char)0xFF && (unsigned char)buf[-1] < 0x40) + return true; + + // FF D0-D7 CALL reg32 + + if (len >= 2 && buf[-2] == (char)0xFF && (buf[-1]&0xF8) == 0xD0) + return true; + + // FF 50-57 xx CALL [reg32+reg32*scale+disp8] + + if (len >= 3 && buf[-3] == (char)0xFF && (buf[-2]&0xF8) == 0x50) + return true; + + // FF 90-97 xx xx xx xx xx CALL [reg32+reg32*scale+disp32] + + if (len >= 7 && buf[-7] == (char)0xFF && (buf[-6]&0xF8) == 0x90) + return true; + + return false; +} + +VDInstructionTypeX86 VDGetInstructionTypeX86(const void *p) { + struct local { + static bool RangeHitTest(const uint8 *range, uint8 c) { + while(*range) { + if (c>=range[0] && c<=range[1]) + return true; + range += 2; + } + + return false; + } + }; + + VDInstructionTypeX86 type = kX86InstUnknown; + + vd_seh_guard_try { + unsigned char buf[8]; + + memcpy(buf, p, 8); + + if (buf[0] == 0x0f && buf[1] == 0x0f) + type = kX86Inst3DNow; // Conveniently, all 3DNow! instructions begin 0F 0F + else if ((buf[0] == 0xdb || buf[0] == 0xdf) && (buf[1]>=0xe8 && buf[1]<=0xf7)) + type = kX86InstP6; // DB/DF E8-F7: FCOMI/FCOMIP/FUCOMI/FUCOMIP (P6) + else if ((buf[0]&0xfe)==0xda && (buf[1]&0xe0)==0xc0) + type = kX86InstP6; // DA/DB C0-DF: FCMOVcc (P6) + else if (buf[0] == 0x0f && (buf[1]&0xf0)==0x40) + type = kX86InstP6; // 0F 40-4F: CMOVcc (P6) + else { + const unsigned char *s = buf; + bool bWide = false; + bool bRepF2 = false; + bool bRepF3 = false; + + // At this point we're down to MMX, SSE, SSE2 -- which makes things simpler + // as we must see F2 0F, F3 0F, or 0F next. MMX ops use 0F exclusively, + // some SSE ops use F2, and a few SSE2 ones use F3. If we see 66 on an + // MMX or SSE op it's automatically SSE2 as it's either a 128-bit MMX op + // or a double-precision version of an SSE one. + + if (*s == 0x66) { // 66h override used by SSE2 and is supposed to be ahead of F2/F3 in encodings + ++s; + bWide = true; + } + + if (*s == 0xf2) { + ++s; + bRepF2 = true; + } + + if (*s == 0xf3) { + ++s; + bRepF3 = true; + } + + if (*s++ == 0x0f) { + // SSE - 1x, 28-2F, 5x, C2, AE + // MMX2 - 70, C4-C6, D7, DA, DE, E0, E3, E4, E7, EA, EE, F6, F7 + // MMX - 6x, 7x, Dx, Ex, and Fx except for MMX2 + // SSE2 - C3, SSE ops with 66 or F2, MMX/MMX2 ops with 66/F2/F3 + + static const uint8 sse_ranges[]={0x10,0x1f,0x28,0x2f,0x50,0x5f,0xc2,0xc2,0xae,0xae,0}; + static const uint8 sse2_ranges[]={0xc3,0xc3,0}; + static const uint8 mmx2_ranges[]={0x70,0x70,0xc4,0xc6,0xd7,0xd7,0xda,0xda,0xde,0xde,0xe0,0xe0,0xe3,0xe4,0xe7,0xe7,0xea,0xea,0xee,0xee,0xf6,0xf7,0}; + static const uint8 mmx_ranges[]={0x60,0x7f,0xd0,0xff,0}; + + if (local::RangeHitTest(sse_ranges, *s)) + type = (bWide||bRepF2) ? kX86InstSSE2 : kX86InstSSE; + else if (local::RangeHitTest(sse2_ranges, *s)) + type = kX86InstSSE2; + else if (local::RangeHitTest(mmx2_ranges, *s)) + type = (bWide||bRepF2||bRepF3) ? kX86InstSSE2 : kX86InstMMX2; + else if (local::RangeHitTest(mmx_ranges, *s)) + type = (bWide||bRepF2||bRepF3) ? kX86InstSSE2 : kX86InstMMX; + } + } + } vd_seh_guard_except { + } + + return type; +} diff --git a/src/thirdparty/VirtualDub/system/source/event.cpp b/src/thirdparty/VirtualDub/system/source/event.cpp index db1a5f8dc82..70e8e853426 100644 --- a/src/thirdparty/VirtualDub/system/source/event.cpp +++ b/src/thirdparty/VirtualDub/system/source/event.cpp @@ -1,88 +1,88 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -VDDelegate::VDDelegate() { - mpPrev = mpNext = this; -} - -VDDelegate::~VDDelegate() { - VDDelegateNode *next = mpNext; - VDDelegateNode *prev = mpPrev; - prev->mpNext = next; - next->mpPrev = prev; -} - -/////////////////////////////////////////////////////////////////////////////// - -VDEventBase::VDEventBase() { - mAnchor.mpPrev = mAnchor.mpNext = &mAnchor; -} - -VDEventBase::~VDEventBase() { - while(mAnchor.mpPrev != &mAnchor) - Remove(static_cast(*mAnchor.mpPrev)); -} - -void VDEventBase::Add(VDDelegate& dbase) { - VDDelegateNode *next = mAnchor.mpNext; - - VDASSERT(dbase.mpPrev == &dbase); - - mAnchor.mpNext = &dbase; - dbase.mpPrev = &mAnchor; - dbase.mpNext = next; - next->mpPrev = &dbase; -} - -void VDEventBase::Remove(VDDelegate& dbase) { - VDASSERT(dbase.mpPrev != &dbase); - - VDDelegateNode *next = dbase.mpNext; - VDDelegateNode *prev = dbase.mpPrev; - prev->mpNext = next; - next->mpPrev = prev; - dbase.mpPrev = dbase.mpNext = &dbase; -} - -void VDEventBase::Raise(void *src, const void *info) { - // We allow the specific case of removing the delegate that's being removed. - VDDelegateNode *node = mAnchor.mpNext; - - while(node != &mAnchor) { - VDDelegateNode *next = node->mpNext; - - VDDelegate& dbase = static_cast(*node); - - dbase.mpCallback(src, info, dbase); - - node = next; - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2006 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +/////////////////////////////////////////////////////////////////////////////// + +VDDelegate::VDDelegate() { + mpPrev = mpNext = this; +} + +VDDelegate::~VDDelegate() { + VDDelegateNode *next = mpNext; + VDDelegateNode *prev = mpPrev; + prev->mpNext = next; + next->mpPrev = prev; +} + +/////////////////////////////////////////////////////////////////////////////// + +VDEventBase::VDEventBase() { + mAnchor.mpPrev = mAnchor.mpNext = &mAnchor; +} + +VDEventBase::~VDEventBase() { + while(mAnchor.mpPrev != &mAnchor) + Remove(static_cast(*mAnchor.mpPrev)); +} + +void VDEventBase::Add(VDDelegate& dbase) { + VDDelegateNode *next = mAnchor.mpNext; + + VDASSERT(dbase.mpPrev == &dbase); + + mAnchor.mpNext = &dbase; + dbase.mpPrev = &mAnchor; + dbase.mpNext = next; + next->mpPrev = &dbase; +} + +void VDEventBase::Remove(VDDelegate& dbase) { + VDASSERT(dbase.mpPrev != &dbase); + + VDDelegateNode *next = dbase.mpNext; + VDDelegateNode *prev = dbase.mpPrev; + prev->mpNext = next; + next->mpPrev = prev; + dbase.mpPrev = dbase.mpNext = &dbase; +} + +void VDEventBase::Raise(void *src, const void *info) { + // We allow the specific case of removing the delegate that's being removed. + VDDelegateNode *node = mAnchor.mpNext; + + while(node != &mAnchor) { + VDDelegateNode *next = node->mpNext; + + VDDelegate& dbase = static_cast(*node); + + dbase.mpCallback(src, info, dbase); + + node = next; + } +} diff --git a/src/thirdparty/VirtualDub/system/source/file.cpp b/src/thirdparty/VirtualDub/system/source/file.cpp index 49415289e12..c7530445cbb 100644 --- a/src/thirdparty/VirtualDub/system/source/file.cpp +++ b/src/thirdparty/VirtualDub/system/source/file.cpp @@ -1,430 +1,430 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -#include -#include -#include -#include - -namespace { - bool IsWindowsNT() { - static bool sbIsNT = (LONG)GetVersion()>=0; - return sbIsNT; - } - - bool IsHardDrivePath(const wchar_t *path) { - const VDStringW rootPath(VDFileGetRootPath(path)); - - UINT type = GetDriveTypeW(rootPath.c_str()); - - return type == DRIVE_FIXED || type == DRIVE_UNKNOWN || type == DRIVE_REMOVABLE; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// -// VDFile -// -/////////////////////////////////////////////////////////////////////////////// - -using namespace nsVDFile; - -VDFile::VDFile(const char *pszFileName, uint32 flags) - : mhFile(NULL) -{ - open_internal(pszFileName, NULL, flags, true); -} - -VDFile::VDFile(const wchar_t *pwszFileName, uint32 flags) - : mhFile(NULL) -{ - open_internal(NULL, pwszFileName, flags, true); -} - -VDFile::VDFile(HANDLE h) - : mhFile(h) -{ - LONG lo, hi = 0; - - lo = SetFilePointer(h, 0, &hi, FILE_CURRENT); - - mFilePosition = (uint32)lo + ((uint64)(uint32)hi << 32); -} - -VDFile::~VDFile() { - closeNT(); -} - -void VDFile::open(const char *pszFilename, uint32 flags) { - open_internal(pszFilename, NULL, flags, true); -} - -void VDFile::open(const wchar_t *pwszFilename, uint32 flags) { - open_internal(NULL, pwszFilename, flags, true); -} - -bool VDFile::openNT(const wchar_t *pwszFilename, uint32 flags) { - return open_internal(NULL, pwszFilename, flags, false); -} - -bool VDFile::open_internal(const char *pszFilename, const wchar_t *pwszFilename, uint32 flags, bool throwOnError) { - close(); - - mpFilename = _wcsdup(VDFileSplitPath(pszFilename ? VDTextAToW(pszFilename).c_str() : pwszFilename)); - if (!mpFilename) { - if (!throwOnError) - return false; - throw MyMemoryError(); - } - - // At least one of the read/write flags must be set. - VDASSERT(flags & (kRead | kWrite)); - - DWORD dwDesiredAccess = 0; - - if (flags & kRead) dwDesiredAccess = GENERIC_READ; - if (flags & kWrite) dwDesiredAccess |= GENERIC_WRITE; - - // Win32 docs are screwed here -- FILE_SHARE_xxx is the inverse of a deny flag. - - DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; - if (flags & kDenyRead) dwShareMode = FILE_SHARE_WRITE; - if (flags & kDenyWrite) dwShareMode &= ~FILE_SHARE_WRITE; - - // One of the creation flags must be set. - VDASSERT(flags & kCreationMask); - - DWORD dwCreationDisposition; - - uint32 creationType = flags & kCreationMask; - - switch(creationType) { - case kOpenExisting: dwCreationDisposition = OPEN_EXISTING; break; - case kOpenAlways: dwCreationDisposition = OPEN_ALWAYS; break; - case kCreateAlways: dwCreationDisposition = CREATE_ALWAYS; break; - case kCreateNew: dwCreationDisposition = CREATE_NEW; break; - case kTruncateExisting: dwCreationDisposition = TRUNCATE_EXISTING; break; - default: - VDNEVERHERE; - return false; - } - - VDASSERT((flags & (kSequential | kRandomAccess)) != (kSequential | kRandomAccess)); - - DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL; - - if (flags & kSequential) dwAttributes |= FILE_FLAG_SEQUENTIAL_SCAN; - if (flags & kRandomAccess) dwAttributes |= FILE_FLAG_RANDOM_ACCESS; - if (flags & kWriteThrough) dwAttributes |= FILE_FLAG_WRITE_THROUGH; - if (flags & kUnbuffered) dwAttributes |= FILE_FLAG_NO_BUFFERING; - - VDStringA tempFilenameA; - VDStringW tempFilenameW; - - if (IsWindowsNT()) { - if (pszFilename) { - tempFilenameW = VDTextAToW(pszFilename); - pwszFilename = tempFilenameW.c_str(); - pszFilename = NULL; - } - } else { - if (pwszFilename) { - tempFilenameA = VDTextWToA(pwszFilename); - pszFilename = tempFilenameA.c_str(); - pwszFilename = NULL; - } - } - - if (pszFilename) - mhFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); - else { - if (!IsHardDrivePath(pwszFilename)) - flags &= ~FILE_FLAG_NO_BUFFERING; - - mhFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); - } - - DWORD err = GetLastError(); - - // If we failed and FILE_FLAG_NO_BUFFERING was set, strip it and try again. - // VPC and Novell shares sometimes do this.... - if (mhFile == INVALID_HANDLE_VALUE && err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) { - if (dwAttributes & FILE_FLAG_NO_BUFFERING) { - dwAttributes &= ~FILE_FLAG_NO_BUFFERING; - dwAttributes |= FILE_FLAG_WRITE_THROUGH; - - if (pszFilename) - mhFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); - else - mhFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); - - err = GetLastError(); - } - } - - // INVALID_HANDLE_VALUE isn't NULL. *sigh* - - if (mhFile == INVALID_HANDLE_VALUE) { - mhFile = NULL; - - if (!throwOnError) - return false; - - throw MyWin32Error("Cannot open file \"%ls\":\n%%s", err, mpFilename.get()); - } - - mFilePosition = 0; - return true; -} - -bool VDFile::closeNT() { - if (mhFile) { - HANDLE h = mhFile; - mhFile = NULL; - if (!CloseHandle(h)) - return false; - } - - return true; -} - -void VDFile::close() { - if (!closeNT()) - throw MyWin32Error("Cannot complete file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::truncateNT() { - return 0 != SetEndOfFile(mhFile); -} - -void VDFile::truncate() { - if (!truncateNT()) - throw MyWin32Error("Cannot truncate file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::extendValidNT(sint64 pos) { - if (GetVersion() & 0x80000000) - return true; // No need, Windows 95/98/ME do this automatically anyway. - - // The SetFileValidData() API is only available on XP and Server 2003. - - typedef BOOL (APIENTRY *tpSetFileValidData)(HANDLE hFile, LONGLONG ValidDataLength); // Windows XP, Server 2003 - static tpSetFileValidData pSetFileValidData = (tpSetFileValidData)GetProcAddress(GetModuleHandle("kernel32"), "SetFileValidData"); - - if (!pSetFileValidData) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; - } - - return 0 != pSetFileValidData(mhFile, pos); -} - -void VDFile::extendValid(sint64 pos) { - if (!extendValidNT(pos)) - throw MyWin32Error("Cannot extend file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::enableExtendValid() { - if (GetVersion() & 0x80000000) - return true; // Not Windows NT, no privileges involved - - // SetFileValidData() requires the SE_MANAGE_VOLUME_NAME privilege, so we must enable it - // on the process token. We don't attempt to strip the privilege afterward as that would - // introduce race conditions. - bool bSuccessful = false; - DWORD err = 0; - - SetLastError(0); - - HANDLE h; - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &h)) { - LUID luid; - - if (LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &luid)) { - TOKEN_PRIVILEGES tp; - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - if (AdjustTokenPrivileges(h, FALSE, &tp, 0, NULL, NULL)) - bSuccessful = true; - else - err = GetLastError(); - } - - CloseHandle(h); - } - - if (!bSuccessful && err) - SetLastError(err); - - return bSuccessful; -} - -long VDFile::readData(void *buffer, long length) { - DWORD dwActual; - - if (!ReadFile(mhFile, buffer, (DWORD)length, &dwActual, NULL)) - throw MyWin32Error("Cannot read from file \"%ls\": %%s", GetLastError(), mpFilename.get()); - - mFilePosition += dwActual; - - return dwActual; -} - -void VDFile::read(void *buffer, long length) { - if (length != readData(buffer, length)) - throw MyWin32Error("Cannot read from file \"%ls\": Premature end of file.", GetLastError(), mpFilename.get()); -} - -long VDFile::writeData(const void *buffer, long length) { - DWORD dwActual; - bool success = false; - - if (!WriteFile(mhFile, buffer, (DWORD)length, &dwActual, NULL) || dwActual != (DWORD)length) - goto found_error; - - mFilePosition += dwActual; - - return dwActual; - -found_error: - throw MyWin32Error("Cannot write to file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -void VDFile::write(const void *buffer, long length) { - if (length != writeData(buffer, length)) - throw MyWin32Error("Cannot write to file \"%ls\": Unable to write all data.", GetLastError(), mpFilename.get()); -} - -bool VDFile::seekNT(sint64 newPos, eSeekMode mode) { - DWORD dwMode; - - switch(mode) { - case kSeekStart: - dwMode = FILE_BEGIN; - break; - case kSeekCur: - dwMode = FILE_CURRENT; - break; - case kSeekEnd: - dwMode = FILE_END; - break; - default: - VDNEVERHERE; - return false; - } - - union { - sint64 pos; - LONG l[2]; - } u = { newPos }; - - u.l[0] = SetFilePointer(mhFile, u.l[0], &u.l[1], dwMode); - - if (u.l[0] == -1 && GetLastError() != NO_ERROR) - return false; - - mFilePosition = u.pos; - return true; -} - -void VDFile::seek(sint64 newPos, eSeekMode mode) { - if (!seekNT(newPos, mode)) - throw MyWin32Error("Cannot seek within file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::skipNT(sint64 delta) { - if (!delta) - return true; - - char buf[1024]; - - if (delta <= sizeof buf) { - return (long)delta == readData(buf, (long)delta); - } else - return seekNT(delta, kSeekCur); -} - -void VDFile::skip(sint64 delta) { - if (!delta) - return; - - char buf[1024]; - - if (delta > 0 && delta <= sizeof buf) { - if ((long)delta != readData(buf, (long)delta)) - throw MyWin32Error("Cannot seek within file \"%ls\": %%s", GetLastError(), mpFilename.get()); - } else - seek(delta, kSeekCur); -} - -sint64 VDFile::size() { - union { - uint64 siz; - DWORD l[2]; - } u; - - u.l[0] = GetFileSize(mhFile, &u.l[1]); - - DWORD err; - - if (u.l[0] == (DWORD)-1L && (err = GetLastError()) != NO_ERROR) - throw MyWin32Error("Cannot retrieve size of file \"%ls\": %%s", GetLastError(), mpFilename.get()); - - return (sint64)u.siz; -} - -sint64 VDFile::tell() { - return mFilePosition; -} - -bool VDFile::flushNT() { - return 0 != FlushFileBuffers(mhFile); -} - -void VDFile::flush() { - if (!flushNT()) - throw MyWin32Error("Cannot flush file \"%ls\": %%s", GetLastError(), mpFilename.get()); -} - -bool VDFile::isOpen() { - return mhFile != 0; -} - -VDFileHandle VDFile::getRawHandle() { - return mhFile; -} - -void *VDFile::AllocUnbuffer(size_t nBytes) { - return VirtualAlloc(NULL, nBytes, MEM_COMMIT, PAGE_READWRITE); -} - -void VDFile::FreeUnbuffer(void *p) { - VirtualFree(p, 0, MEM_RELEASE); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include +#include +#include +#include + +namespace { + bool IsWindowsNT() { + static bool sbIsNT = (LONG)GetVersion()>=0; + return sbIsNT; + } + + bool IsHardDrivePath(const wchar_t *path) { + const VDStringW rootPath(VDFileGetRootPath(path)); + + UINT type = GetDriveTypeW(rootPath.c_str()); + + return type == DRIVE_FIXED || type == DRIVE_UNKNOWN || type == DRIVE_REMOVABLE; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// VDFile +// +/////////////////////////////////////////////////////////////////////////////// + +using namespace nsVDFile; + +VDFile::VDFile(const char *pszFileName, uint32 flags) + : mhFile(NULL) +{ + open_internal(pszFileName, NULL, flags, true); +} + +VDFile::VDFile(const wchar_t *pwszFileName, uint32 flags) + : mhFile(NULL) +{ + open_internal(NULL, pwszFileName, flags, true); +} + +VDFile::VDFile(HANDLE h) + : mhFile(h) +{ + LONG lo, hi = 0; + + lo = SetFilePointer(h, 0, &hi, FILE_CURRENT); + + mFilePosition = (uint32)lo + ((uint64)(uint32)hi << 32); +} + +VDFile::~VDFile() { + closeNT(); +} + +void VDFile::open(const char *pszFilename, uint32 flags) { + open_internal(pszFilename, NULL, flags, true); +} + +void VDFile::open(const wchar_t *pwszFilename, uint32 flags) { + open_internal(NULL, pwszFilename, flags, true); +} + +bool VDFile::openNT(const wchar_t *pwszFilename, uint32 flags) { + return open_internal(NULL, pwszFilename, flags, false); +} + +bool VDFile::open_internal(const char *pszFilename, const wchar_t *pwszFilename, uint32 flags, bool throwOnError) { + close(); + + mpFilename = _wcsdup(VDFileSplitPath(pszFilename ? VDTextAToW(pszFilename).c_str() : pwszFilename)); + if (!mpFilename) { + if (!throwOnError) + return false; + throw MyMemoryError(); + } + + // At least one of the read/write flags must be set. + VDASSERT(flags & (kRead | kWrite)); + + DWORD dwDesiredAccess = 0; + + if (flags & kRead) dwDesiredAccess = GENERIC_READ; + if (flags & kWrite) dwDesiredAccess |= GENERIC_WRITE; + + // Win32 docs are screwed here -- FILE_SHARE_xxx is the inverse of a deny flag. + + DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + if (flags & kDenyRead) dwShareMode = FILE_SHARE_WRITE; + if (flags & kDenyWrite) dwShareMode &= ~FILE_SHARE_WRITE; + + // One of the creation flags must be set. + VDASSERT(flags & kCreationMask); + + DWORD dwCreationDisposition; + + uint32 creationType = flags & kCreationMask; + + switch(creationType) { + case kOpenExisting: dwCreationDisposition = OPEN_EXISTING; break; + case kOpenAlways: dwCreationDisposition = OPEN_ALWAYS; break; + case kCreateAlways: dwCreationDisposition = CREATE_ALWAYS; break; + case kCreateNew: dwCreationDisposition = CREATE_NEW; break; + case kTruncateExisting: dwCreationDisposition = TRUNCATE_EXISTING; break; + default: + VDNEVERHERE; + return false; + } + + VDASSERT((flags & (kSequential | kRandomAccess)) != (kSequential | kRandomAccess)); + + DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL; + + if (flags & kSequential) dwAttributes |= FILE_FLAG_SEQUENTIAL_SCAN; + if (flags & kRandomAccess) dwAttributes |= FILE_FLAG_RANDOM_ACCESS; + if (flags & kWriteThrough) dwAttributes |= FILE_FLAG_WRITE_THROUGH; + if (flags & kUnbuffered) dwAttributes |= FILE_FLAG_NO_BUFFERING; + + VDStringA tempFilenameA; + VDStringW tempFilenameW; + + if (IsWindowsNT()) { + if (pszFilename) { + tempFilenameW = VDTextAToW(pszFilename); + pwszFilename = tempFilenameW.c_str(); + pszFilename = NULL; + } + } else { + if (pwszFilename) { + tempFilenameA = VDTextWToA(pwszFilename); + pszFilename = tempFilenameA.c_str(); + pwszFilename = NULL; + } + } + + if (pszFilename) + mhFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); + else { + if (!IsHardDrivePath(pwszFilename)) + flags &= ~FILE_FLAG_NO_BUFFERING; + + mhFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); + } + + DWORD err = GetLastError(); + + // If we failed and FILE_FLAG_NO_BUFFERING was set, strip it and try again. + // VPC and Novell shares sometimes do this.... + if (mhFile == INVALID_HANDLE_VALUE && err != ERROR_FILE_NOT_FOUND && err != ERROR_PATH_NOT_FOUND) { + if (dwAttributes & FILE_FLAG_NO_BUFFERING) { + dwAttributes &= ~FILE_FLAG_NO_BUFFERING; + dwAttributes |= FILE_FLAG_WRITE_THROUGH; + + if (pszFilename) + mhFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); + else + mhFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwAttributes, NULL); + + err = GetLastError(); + } + } + + // INVALID_HANDLE_VALUE isn't NULL. *sigh* + + if (mhFile == INVALID_HANDLE_VALUE) { + mhFile = NULL; + + if (!throwOnError) + return false; + + throw MyWin32Error("Cannot open file \"%ls\":\n%%s", err, mpFilename.get()); + } + + mFilePosition = 0; + return true; +} + +bool VDFile::closeNT() { + if (mhFile) { + HANDLE h = mhFile; + mhFile = NULL; + if (!CloseHandle(h)) + return false; + } + + return true; +} + +void VDFile::close() { + if (!closeNT()) + throw MyWin32Error("Cannot complete file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::truncateNT() { + return 0 != SetEndOfFile(mhFile); +} + +void VDFile::truncate() { + if (!truncateNT()) + throw MyWin32Error("Cannot truncate file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::extendValidNT(sint64 pos) { + if (GetVersion() & 0x80000000) + return true; // No need, Windows 95/98/ME do this automatically anyway. + + // The SetFileValidData() API is only available on XP and Server 2003. + + typedef BOOL (APIENTRY *tpSetFileValidData)(HANDLE hFile, LONGLONG ValidDataLength); // Windows XP, Server 2003 + static tpSetFileValidData pSetFileValidData = (tpSetFileValidData)GetProcAddress(GetModuleHandle("kernel32"), "SetFileValidData"); + + if (!pSetFileValidData) { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return false; + } + + return 0 != pSetFileValidData(mhFile, pos); +} + +void VDFile::extendValid(sint64 pos) { + if (!extendValidNT(pos)) + throw MyWin32Error("Cannot extend file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::enableExtendValid() { + if (GetVersion() & 0x80000000) + return true; // Not Windows NT, no privileges involved + + // SetFileValidData() requires the SE_MANAGE_VOLUME_NAME privilege, so we must enable it + // on the process token. We don't attempt to strip the privilege afterward as that would + // introduce race conditions. + bool bSuccessful = false; + DWORD err = 0; + + SetLastError(0); + + HANDLE h; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &h)) { + LUID luid; + + if (LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &luid)) { + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (AdjustTokenPrivileges(h, FALSE, &tp, 0, NULL, NULL)) + bSuccessful = true; + else + err = GetLastError(); + } + + CloseHandle(h); + } + + if (!bSuccessful && err) + SetLastError(err); + + return bSuccessful; +} + +long VDFile::readData(void *buffer, long length) { + DWORD dwActual; + + if (!ReadFile(mhFile, buffer, (DWORD)length, &dwActual, NULL)) + throw MyWin32Error("Cannot read from file \"%ls\": %%s", GetLastError(), mpFilename.get()); + + mFilePosition += dwActual; + + return dwActual; +} + +void VDFile::read(void *buffer, long length) { + if (length != readData(buffer, length)) + throw MyWin32Error("Cannot read from file \"%ls\": Premature end of file.", GetLastError(), mpFilename.get()); +} + +long VDFile::writeData(const void *buffer, long length) { + DWORD dwActual; + bool success = false; + + if (!WriteFile(mhFile, buffer, (DWORD)length, &dwActual, NULL) || dwActual != (DWORD)length) + goto found_error; + + mFilePosition += dwActual; + + return dwActual; + +found_error: + throw MyWin32Error("Cannot write to file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +void VDFile::write(const void *buffer, long length) { + if (length != writeData(buffer, length)) + throw MyWin32Error("Cannot write to file \"%ls\": Unable to write all data.", GetLastError(), mpFilename.get()); +} + +bool VDFile::seekNT(sint64 newPos, eSeekMode mode) { + DWORD dwMode; + + switch(mode) { + case kSeekStart: + dwMode = FILE_BEGIN; + break; + case kSeekCur: + dwMode = FILE_CURRENT; + break; + case kSeekEnd: + dwMode = FILE_END; + break; + default: + VDNEVERHERE; + return false; + } + + union { + sint64 pos; + LONG l[2]; + } u = { newPos }; + + u.l[0] = SetFilePointer(mhFile, u.l[0], &u.l[1], dwMode); + + if (u.l[0] == -1 && GetLastError() != NO_ERROR) + return false; + + mFilePosition = u.pos; + return true; +} + +void VDFile::seek(sint64 newPos, eSeekMode mode) { + if (!seekNT(newPos, mode)) + throw MyWin32Error("Cannot seek within file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::skipNT(sint64 delta) { + if (!delta) + return true; + + char buf[1024]; + + if (delta <= sizeof buf) { + return (long)delta == readData(buf, (long)delta); + } else + return seekNT(delta, kSeekCur); +} + +void VDFile::skip(sint64 delta) { + if (!delta) + return; + + char buf[1024]; + + if (delta > 0 && delta <= sizeof buf) { + if ((long)delta != readData(buf, (long)delta)) + throw MyWin32Error("Cannot seek within file \"%ls\": %%s", GetLastError(), mpFilename.get()); + } else + seek(delta, kSeekCur); +} + +sint64 VDFile::size() { + union { + uint64 siz; + DWORD l[2]; + } u; + + u.l[0] = GetFileSize(mhFile, &u.l[1]); + + DWORD err; + + if (u.l[0] == (DWORD)-1L && (err = GetLastError()) != NO_ERROR) + throw MyWin32Error("Cannot retrieve size of file \"%ls\": %%s", GetLastError(), mpFilename.get()); + + return (sint64)u.siz; +} + +sint64 VDFile::tell() { + return mFilePosition; +} + +bool VDFile::flushNT() { + return 0 != FlushFileBuffers(mhFile); +} + +void VDFile::flush() { + if (!flushNT()) + throw MyWin32Error("Cannot flush file \"%ls\": %%s", GetLastError(), mpFilename.get()); +} + +bool VDFile::isOpen() { + return mhFile != 0; +} + +VDFileHandle VDFile::getRawHandle() { + return mhFile; +} + +void *VDFile::AllocUnbuffer(size_t nBytes) { + return VirtualAlloc(NULL, nBytes, MEM_COMMIT, PAGE_READWRITE); +} + +void VDFile::FreeUnbuffer(void *p) { + VirtualFree(p, 0, MEM_RELEASE); +} diff --git a/src/thirdparty/VirtualDub/system/source/fileasync.cpp b/src/thirdparty/VirtualDub/system/source/fileasync.cpp index b9d65b88ab9..a5e1734509d 100644 --- a/src/thirdparty/VirtualDub/system/source/fileasync.cpp +++ b/src/thirdparty/VirtualDub/system/source/fileasync.cpp @@ -1,925 +1,925 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// -// -// VDFileAsync - Windows 9x implementation -// -/////////////////////////////////////////////////////////////////////////// - -class VDFileAsync9x : public IVDFileAsync, protected VDThread { -public: - VDFileAsync9x(bool useFastMode, bool writeThrough); - ~VDFileAsync9x(); - - void SetPreemptiveExtend(bool b) { mbPreemptiveExtend = b; } - bool IsPreemptiveExtendActive() { return mbPreemptiveExtend; } - - bool IsOpen() { return mhFileSlow != INVALID_HANDLE_VALUE; } - - void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize); - void Open(VDFileHandle h, uint32 count, uint32 bufferSize); - void Close(); - void FastWrite(const void *pData, uint32 bytes); - void FastWriteEnd(); - void Write(sint64 pos, const void *pData, uint32 bytes); - bool Extend(sint64 pos); - void Truncate(sint64 pos); - void SafeTruncateAndClose(sint64 pos); - sint64 GetSize(); - sint64 GetFastWritePos() { return mClientFastPointer; } - -protected: - void WriteZero(sint64 pos, uint32 bytes); - void Seek(sint64 pos); - bool SeekNT(sint64 pos); - void ThrowError(); - void ThreadRun(); - - HANDLE mhFileSlow; - HANDLE mhFileFast; - uint32 mBlockSize; - uint32 mBlockCount; - uint32 mSectorSize; - sint64 mClientSlowPointer; - sint64 mClientFastPointer; - - const bool mbUseFastMode; - const bool mbWriteThrough; - - volatile bool mbPreemptiveExtend; - - enum { - kStateNormal, - kStateFlush, - kStateAbort - }; - VDAtomicInt mState; - - VDSignal mReadOccurred; - VDSignal mWriteOccurred; - - VDRingBuffer > mBuffer; - - VDStringA mFilename; - VDAtomicPtr mpError; -}; - -/////////////////////////////////////////////////////////////////////////// - -VDFileAsync9x::VDFileAsync9x(bool useFastMode, bool writeThrough) - : mhFileSlow(INVALID_HANDLE_VALUE) - , mhFileFast(INVALID_HANDLE_VALUE) - , mClientSlowPointer(0) - , mClientFastPointer(0) - , mbUseFastMode(useFastMode) - , mbWriteThrough(writeThrough) - , mbPreemptiveExtend(false) - , mpError(NULL) -{ -} - -VDFileAsync9x::~VDFileAsync9x() { - Close(); -} - -void VDFileAsync9x::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { - try { - mFilename = VDTextWToA(pszFilename); - - const DWORD slowFlags = mbWriteThrough ? FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH : FILE_ATTRIBUTE_NORMAL; - - mhFileSlow = CreateFile(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, slowFlags, NULL); - if (mhFileSlow == INVALID_HANDLE_VALUE) - throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); - - if (mbUseFastMode) - mhFileFast = CreateFile(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); - - mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). - - mBlockSize = bufferSize; - mBlockCount = count; - mBuffer.Init(count * bufferSize); - - mState = kStateNormal; - } catch(const MyError&) { - Close(); - throw; - } - - ThreadStart(); -} - -void VDFileAsync9x::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { - try { - mFilename = ""; - - HANDLE hProcess = GetCurrentProcess(); - if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) - throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); - - mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). - - mBlockSize = bufferSize; - mBlockCount = count; - mBuffer.Init(count * bufferSize); - - mState = kStateNormal; - } catch(const MyError&) { - Close(); - throw; - } - - ThreadStart(); -} - -void VDFileAsync9x::Close() { - mState = kStateAbort; - mWriteOccurred.signal(); - ThreadWait(); - - if (mhFileSlow != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileSlow); - mhFileSlow = INVALID_HANDLE_VALUE; - } - if (mhFileFast != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileFast); - mhFileFast = INVALID_HANDLE_VALUE; - } -} - -void VDFileAsync9x::FastWrite(const void *pData, uint32 bytes) { - if (mhFileFast == INVALID_HANDLE_VALUE) { - if (pData) - Write(mClientFastPointer, pData, bytes); - else - WriteZero(mClientFastPointer, bytes); - } else { - if (mpError) - ThrowError(); - - uint32 bytesLeft = bytes; - while(bytesLeft) { - int actual; - void *p = mBuffer.LockWrite(bytesLeft, actual); - - if (!actual) { - mReadOccurred.wait(); - if (mpError) - ThrowError(); - continue; - } - - if (pData) { - memcpy(p, pData, actual); - pData = (const char *)pData + actual; - } else { - memset(p, 0, actual); - } - mBuffer.UnlockWrite(actual); - mWriteOccurred.signal(); - bytesLeft -= actual; - } - } - - mClientFastPointer += bytes; -} - -void VDFileAsync9x::FastWriteEnd() { - FastWrite(NULL, mSectorSize - 1); - - mState = kStateFlush; - mWriteOccurred.signal(); - ThreadWait(); - - if (mpError) - ThrowError(); -} - -void VDFileAsync9x::Write(sint64 pos, const void *p, uint32 bytes) { - Seek(pos); - - DWORD dwActual; - if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || dwActual != bytes) { - mClientSlowPointer = -1; - throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); - } - - mClientSlowPointer += bytes; -} - -void VDFileAsync9x::WriteZero(sint64 pos, uint32 bytes) { - uint32 bufsize = bytes > 2048 ? 2048 : bytes; - void *p = _alloca(bufsize); - memset(p, 0, bufsize); - - while(bytes > 0) { - uint32 tc = bytes > 2048 ? 2048 : bytes; - - Write(pos, p, tc); - pos += tc; - bytes -= tc; - } -} - -bool VDFileAsync9x::Extend(sint64 pos) { - return SeekNT(pos) && SetEndOfFile(mhFileSlow); -} - -void VDFileAsync9x::Truncate(sint64 pos) { - Seek(pos); - if (!SetEndOfFile(mhFileSlow)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -void VDFileAsync9x::SafeTruncateAndClose(sint64 pos) { - if (mhFileSlow != INVALID_HANDLE_VALUE) { - FastWrite(NULL, mSectorSize - 1); - - mState = kStateFlush; - mWriteOccurred.signal(); - ThreadWait(); - - Extend(pos); - Close(); - } -} - -sint64 VDFileAsync9x::GetSize() { - DWORD dwSizeHigh; - DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); - - if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - return dwSizeLow + ((sint64)dwSizeHigh << 32); -} - -void VDFileAsync9x::Seek(sint64 pos) { - if (!SeekNT(pos)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -bool VDFileAsync9x::SeekNT(sint64 pos) { - if (mClientSlowPointer == pos) - return true; - - LONG posHi = (LONG)(pos >> 32); - DWORD result = SetFilePointer(mhFileSlow, (LONG)pos, &posHi, FILE_BEGIN); - - if (result == INVALID_SET_FILE_POINTER) { - DWORD dwError = GetLastError(); - - if (dwError != NO_ERROR) { - mClientSlowPointer = -1; - return false; - } - } - - mClientSlowPointer = pos; - - return true; -} - -void VDFileAsync9x::ThrowError() { - MyError *e = mpError.xchg(NULL); - - if (e) { - if (mhFileFast != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileFast); - mhFileFast = INVALID_HANDLE_VALUE; - } - - MyError tmp; - tmp.TransferFrom(*e); - delete e; - throw tmp; - } -} - -void VDFileAsync9x::ThreadRun() { - bool bPreemptiveExtend = mbPreemptiveExtend; - sint64 currentSize; - sint64 pos = 0; - uint32 bufferSize = mBlockCount * mBlockSize; - HANDLE hFile = mhFileFast != INVALID_HANDLE_VALUE ? mhFileFast : mhFileSlow; - - try { - if (bPreemptiveExtend && !VDGetFileSizeW32(hFile, currentSize)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - for(;;) { - int state = mState; - - if (state == kStateAbort) - break; - - int actual; - const void *p = mBuffer.LockRead(mBlockSize, actual); - - if ((uint32)actual < mBlockSize) { - if (state == kStateNormal) { - mWriteOccurred.wait(); - continue; - } - - VDASSERT(state == kStateFlush); - - actual &= ~(mSectorSize-1); - if (!actual) - break; - } else { - if (bPreemptiveExtend) { - sint64 checkpt = pos + mBlockSize + bufferSize; - - if (checkpt > currentSize) { - currentSize += bufferSize; - if (currentSize < checkpt) - currentSize = checkpt; - - if (!VDSetFilePointerW32(hFile, currentSize, FILE_BEGIN) - || !SetEndOfFile(hFile)) - mbPreemptiveExtend = bPreemptiveExtend = false; - - if (!VDSetFilePointerW32(hFile, pos, FILE_BEGIN)) - throw MyWin32Error("Seek error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); - } - } - } - - DWORD dwActual; - if (!WriteFile(hFile, p, actual, &dwActual, NULL) || dwActual != actual) { - DWORD dwError = GetLastError(); - throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", dwError, mFilename.c_str()); - } - - pos += actual; - - mBuffer.UnlockRead(actual); - - mReadOccurred.signal(); - } - } catch(MyError& e) { - MyError *p = new MyError; - - p->TransferFrom(e); - delete mpError.xchg(p); - mReadOccurred.signal(); - } -} - -/////////////////////////////////////////////////////////////////////////// -// -// VDFileAsync - Windows NT implementation -// -/////////////////////////////////////////////////////////////////////////// - -struct VDFileAsyncNTBuffer : public OVERLAPPED { - bool mbActive; - bool mbPending; - uint32 mLength; - - VDFileAsyncNTBuffer() : mbActive(false), mbPending(false) { hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } - ~VDFileAsyncNTBuffer() { if (hEvent) CloseHandle(hEvent); } -}; - -class VDFileAsyncNT : public IVDFileAsync, private VDThread { -public: - VDFileAsyncNT(); - ~VDFileAsyncNT(); - - void SetPreemptiveExtend(bool b) { mbPreemptiveExtend = b; } - bool IsPreemptiveExtendActive() { return mbPreemptiveExtend; } - - bool IsOpen() { return mhFileSlow != INVALID_HANDLE_VALUE; } - - void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize); - void Open(VDFileHandle h, uint32 count, uint32 bufferSize); - void Close(); - void FastWrite(const void *pData, uint32 bytes); - void FastWriteEnd(); - void Write(sint64 pos, const void *pData, uint32 bytes); - bool Extend(sint64 pos); - void Truncate(sint64 pos); - void SafeTruncateAndClose(sint64 pos); - sint64 GetSize(); - sint64 GetFastWritePos() { return mClientFastPointer; } - -protected: - void WriteZero(sint64 pos, uint32 bytes); - void Seek(sint64 pos); - bool SeekNT(sint64 pos); - void ThrowError(); - void ThreadRun(); - - HANDLE mhFileSlow; - HANDLE mhFileFast; - uint32 mBlockSize; - uint32 mBlockCount; - uint32 mBufferSize; - uint32 mSectorSize; - - enum { - kStateNormal, - kStateFlush, - kStateAbort - }; - VDAtomicInt mState; - - VDSignal mReadOccurred; - VDSignal mWriteOccurred; - - uint32 mWriteOffset; - VDAtomicInt mBufferLevel; - sint64 mClientSlowPointer; - sint64 mClientFastPointer; - sint64 mFastPointer; - - volatile bool mbPreemptiveExtend; - - vdautoarrayptr mpBlocks; - - vdblock > mBuffer; - - VDAtomicPtr mpError; - VDStringA mFilename; -}; - -VDFileAsyncNT::VDFileAsyncNT() - : mhFileSlow(INVALID_HANDLE_VALUE) - , mhFileFast(INVALID_HANDLE_VALUE) - , mFastPointer(0) - , mClientSlowPointer(0) - , mClientFastPointer(0) - , mbPreemptiveExtend(false) - , mpError(NULL) -{ -} - -VDFileAsyncNT::~VDFileAsyncNT() { - Close(); -} - -void VDFileAsyncNT::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { - try { - mFilename = VDTextWToA(pszFilename); - - mhFileSlow = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (mhFileSlow == INVALID_HANDLE_VALUE) - throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); - - mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); - if (mhFileFast == INVALID_HANDLE_VALUE) - mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL); - - mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). - - mBlockSize = bufferSize; - mBlockCount = count; - mBufferSize = mBlockSize * mBlockCount; - - mWriteOffset = 0; - mBufferLevel = 0; - - mState = kStateNormal; - - if (mhFileFast != INVALID_HANDLE_VALUE) { - mpBlocks = new VDFileAsyncNTBuffer[count]; - mBuffer.resize(count * bufferSize); - ThreadStart(); - } - } catch(const MyError&) { - Close(); - throw; - } -} - -void VDFileAsyncNT::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { - try { - mFilename = ""; - - HANDLE hProcess = GetCurrentProcess(); - if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) - throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); - - mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). - - mBlockSize = bufferSize; - mBlockCount = count; - mBufferSize = mBlockSize * mBlockCount; - - mWriteOffset = 0; - mBufferLevel = 0; - - mState = kStateNormal; - - if (mhFileFast != INVALID_HANDLE_VALUE) { - mpBlocks = new VDFileAsyncNTBuffer[count]; - mBuffer.resize(count * bufferSize); - ThreadStart(); - } - } catch(const MyError&) { - Close(); - throw; - } -} - -void VDFileAsyncNT::Close() { - mState = kStateAbort; - mWriteOccurred.signal(); - ThreadWait(); - - if (mpError) { - delete mpError; - mpError = NULL; - } - - if (mhFileSlow != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileSlow); - mhFileSlow = INVALID_HANDLE_VALUE; - } - if (mhFileFast != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileFast); - mhFileFast = INVALID_HANDLE_VALUE; - } - - mpBlocks = NULL; -} - -void VDFileAsyncNT::FastWrite(const void *pData, uint32 bytes) { - if (mhFileFast == INVALID_HANDLE_VALUE) { - if (pData) - Write(mClientFastPointer, pData, bytes); - else - WriteZero(mClientFastPointer, bytes); - } else { - if (mpError) - ThrowError(); - - uint32 bytesLeft = bytes; - while(bytesLeft) { - uint32 actual = mBufferSize - mBufferLevel; - - if (actual > bytesLeft) - actual = bytesLeft; - - if (mWriteOffset + actual > mBufferSize) - actual = mBufferSize - mWriteOffset; - - if (!actual) { - mReadOccurred.wait(); - if (mpError) - ThrowError(); - continue; - } - - if (pData) { - memcpy(&mBuffer[mWriteOffset], pData, actual); - pData = (const char *)pData + actual; - } else { - memset(&mBuffer[mWriteOffset], 0, actual); - } - - uint32 oldWriteOffset = mWriteOffset; - mWriteOffset += actual; - if (mWriteOffset >= mBufferSize) - mWriteOffset = 0; - mBufferLevel += actual; - - // only bother signaling if the write offset crossed a block boundary - if (oldWriteOffset % mBlockSize + actual >= mBlockSize) { - mWriteOccurred.signal(); - if (mpError) - ThrowError(); - } - - bytesLeft -= actual; - } - } - - mClientFastPointer += bytes; -} - -void VDFileAsyncNT::FastWriteEnd() { - if (mhFileFast != INVALID_HANDLE_VALUE) { - FastWrite(NULL, mSectorSize - 1); - mState = kStateFlush; - mWriteOccurred.signal(); - ThreadWait(); - } - - if (mpError) - ThrowError(); -} - -void VDFileAsyncNT::Write(sint64 pos, const void *p, uint32 bytes) { - Seek(pos); - - DWORD dwActual; - if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || (mClientSlowPointer += dwActual),(dwActual != bytes)) - throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -void VDFileAsyncNT::WriteZero(sint64 pos, uint32 bytes) { - uint32 bufsize = bytes > 2048 ? 2048 : bytes; - void *p = _alloca(bufsize); - memset(p, 0, bufsize); - - while(bytes > 0) { - uint32 tc = bytes > 2048 ? 2048 : bytes; - - Write(pos, p, tc); - pos += tc; - bytes -= tc; - } -} - -bool VDFileAsyncNT::Extend(sint64 pos) { - return SeekNT(pos) && SetEndOfFile(mhFileSlow); -} - -void VDFileAsyncNT::Truncate(sint64 pos) { - Seek(pos); - if (!SetEndOfFile(mhFileSlow)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -void VDFileAsyncNT::SafeTruncateAndClose(sint64 pos) { - if (isThreadAttached()) { - mState = kStateAbort; - mWriteOccurred.signal(); - ThreadWait(); - - if (mpError) { - delete mpError; - mpError = NULL; - } - } - - if (mhFileSlow != INVALID_HANDLE_VALUE) { - Extend(pos); - Close(); - } -} - -sint64 VDFileAsyncNT::GetSize() { - DWORD dwSizeHigh; - DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); - - if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - return dwSizeLow + ((sint64)dwSizeHigh << 32); -} - -void VDFileAsyncNT::Seek(sint64 pos) { - if (!SeekNT(pos)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); -} - -bool VDFileAsyncNT::SeekNT(sint64 pos) { - if (mClientSlowPointer == pos) - return true; - - LONG posHi = (LONG)(pos >> 32); - DWORD result = SetFilePointer(mhFileSlow, (LONG)pos, &posHi, FILE_BEGIN); - - if (result == INVALID_SET_FILE_POINTER) { - DWORD dwError = GetLastError(); - - if (dwError != NO_ERROR) - return false; - } - - mClientSlowPointer = pos; - return true; -} - -void VDFileAsyncNT::ThrowError() { - MyError *e = mpError.xchg(NULL); - - if (e) { - if (mhFileFast != INVALID_HANDLE_VALUE) { - CloseHandle(mhFileFast); - mhFileFast = INVALID_HANDLE_VALUE; - } - - MyError tmp; - tmp.TransferFrom(*e); - delete e; - throw tmp; - } -} - -void VDFileAsyncNT::ThreadRun() { - int requestHead = 0; - int requestTail = 0; - int requestCount = mBlockCount; - uint32 pendingLevel = 0; - uint32 readOffset = 0; - bool bPreemptiveExtend = mbPreemptiveExtend; - sint64 currentSize; - - try { - if (!VDGetFileSizeW32(mhFileFast, currentSize)) - throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - for(;;) { - int state = mState; - - if (state == kStateAbort) { - typedef BOOL (WINAPI *tpCancelIo)(HANDLE); - static const tpCancelIo pCancelIo = (tpCancelIo)GetProcAddress(GetModuleHandle("kernel32"), "CancelIo"); - pCancelIo(mhFileFast); - - // Wait for any pending blocks to complete. - for(int i=0; i= 0); - if (readOffset + actual > mBufferSize) - actual = mBufferSize - readOffset; - - if (actual < mBlockSize) { - if (state == kStateNormal || actual < mSectorSize) { - // check for blocks that have completed - bool blocksCompleted = false; - for(;;) { - VDFileAsyncNTBuffer& buf = mpBlocks[requestTail]; - - if (!buf.mbActive) { - if (state == kStateFlush) - goto all_done; - - if (!blocksCompleted) { - // wait for further writes - mWriteOccurred.wait(); - } - break; - } - - if (buf.mbPending) { - HANDLE h[2] = {buf.hEvent, mWriteOccurred.getHandle()}; - DWORD waitResult = WaitForMultipleObjects(2, h, FALSE, INFINITE); - - if (waitResult == WAIT_OBJECT_0+1) // write pending - break; - - DWORD dwActual; - if (!GetOverlappedResult(mhFileFast, &buf, &dwActual, TRUE)) - throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - } - - buf.mbActive = false; - - blocksCompleted = true; - - if (++requestTail >= requestCount) - requestTail = 0; - - mBufferLevel -= buf.mLength; - pendingLevel -= buf.mLength; - VDASSERT((int)mBufferLevel >= 0); - VDASSERT((int)pendingLevel >= 0); - - mReadOccurred.signal(); - - } - - continue; - } - - VDASSERT(state == kStateFlush); - - actual &= ~(mSectorSize-1); - - VDASSERT(actual > 0); - } else { - actual = mBlockSize; - - if (bPreemptiveExtend) { - sint64 checkpt = mFastPointer + mBlockSize + mBufferSize; - - if (checkpt > currentSize) { - currentSize += mBufferSize; - if (currentSize < checkpt) - currentSize = checkpt; - - if (!VDSetFilePointerW32(mhFileFast, currentSize, FILE_BEGIN) - || !SetEndOfFile(mhFileFast)) - mbPreemptiveExtend = bPreemptiveExtend = false; - } - } - } - - // Issue a write to OS - VDFileAsyncNTBuffer& buf = mpBlocks[requestHead]; - - VDASSERT(!buf.mbActive); - - DWORD dwActual; - - buf.Offset = (DWORD)mFastPointer; - buf.OffsetHigh = (DWORD)((uint64)mFastPointer >> 32); - buf.Internal = 0; - buf.InternalHigh = 0; - buf.mLength = actual; - buf.mbPending = false; - - if (!WriteFile(mhFileFast, &mBuffer[readOffset], actual, &dwActual, &buf)) { - if (GetLastError() != ERROR_IO_PENDING) - throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); - - buf.mbPending = true; - } - - buf.mbActive = true; - - pendingLevel += actual; - VDASSERT(pendingLevel <= (uint32)mBufferLevel); - - readOffset += actual; - VDASSERT(readOffset <= mBufferSize); - if (readOffset >= mBufferSize) - readOffset = 0; - - mFastPointer += actual; - - if (++requestHead >= requestCount) - requestHead = 0; - } -all_done: - ; - - } catch(MyError& e) { - MyError *p = new MyError; - - p->TransferFrom(e); - delete mpError.xchg(p); - mReadOccurred.signal(); - } -} - -/////////////////////////////////////////////////////////////////////////// - -IVDFileAsync *VDCreateFileAsync(IVDFileAsync::Mode mode) { - switch(mode) { - - case IVDFileAsync::kModeAsynchronous: - if (VDIsWindowsNT()) - return new VDFileAsyncNT; - // Can't do async I/O. Fall-through to 9x method. - case IVDFileAsync::kModeThreaded: - return new VDFileAsync9x(true, true); - - default: - return new VDFileAsync9x(false, true); - - case IVDFileAsync::kModeBuffered: - return new VDFileAsync9x(false, false); - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// +// +// VDFileAsync - Windows 9x implementation +// +/////////////////////////////////////////////////////////////////////////// + +class VDFileAsync9x : public IVDFileAsync, protected VDThread { +public: + VDFileAsync9x(bool useFastMode, bool writeThrough); + ~VDFileAsync9x(); + + void SetPreemptiveExtend(bool b) { mbPreemptiveExtend = b; } + bool IsPreemptiveExtendActive() { return mbPreemptiveExtend; } + + bool IsOpen() { return mhFileSlow != INVALID_HANDLE_VALUE; } + + void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize); + void Open(VDFileHandle h, uint32 count, uint32 bufferSize); + void Close(); + void FastWrite(const void *pData, uint32 bytes); + void FastWriteEnd(); + void Write(sint64 pos, const void *pData, uint32 bytes); + bool Extend(sint64 pos); + void Truncate(sint64 pos); + void SafeTruncateAndClose(sint64 pos); + sint64 GetSize(); + sint64 GetFastWritePos() { return mClientFastPointer; } + +protected: + void WriteZero(sint64 pos, uint32 bytes); + void Seek(sint64 pos); + bool SeekNT(sint64 pos); + void ThrowError(); + void ThreadRun(); + + HANDLE mhFileSlow; + HANDLE mhFileFast; + uint32 mBlockSize; + uint32 mBlockCount; + uint32 mSectorSize; + sint64 mClientSlowPointer; + sint64 mClientFastPointer; + + const bool mbUseFastMode; + const bool mbWriteThrough; + + volatile bool mbPreemptiveExtend; + + enum { + kStateNormal, + kStateFlush, + kStateAbort + }; + VDAtomicInt mState; + + VDSignal mReadOccurred; + VDSignal mWriteOccurred; + + VDRingBuffer > mBuffer; + + VDStringA mFilename; + VDAtomicPtr mpError; +}; + +/////////////////////////////////////////////////////////////////////////// + +VDFileAsync9x::VDFileAsync9x(bool useFastMode, bool writeThrough) + : mhFileSlow(INVALID_HANDLE_VALUE) + , mhFileFast(INVALID_HANDLE_VALUE) + , mClientSlowPointer(0) + , mClientFastPointer(0) + , mbUseFastMode(useFastMode) + , mbWriteThrough(writeThrough) + , mbPreemptiveExtend(false) + , mpError(NULL) +{ +} + +VDFileAsync9x::~VDFileAsync9x() { + Close(); +} + +void VDFileAsync9x::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { + try { + mFilename = VDTextWToA(pszFilename); + + const DWORD slowFlags = mbWriteThrough ? FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH : FILE_ATTRIBUTE_NORMAL; + + mhFileSlow = CreateFile(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, slowFlags, NULL); + if (mhFileSlow == INVALID_HANDLE_VALUE) + throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); + + if (mbUseFastMode) + mhFileFast = CreateFile(mFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL); + + mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). + + mBlockSize = bufferSize; + mBlockCount = count; + mBuffer.Init(count * bufferSize); + + mState = kStateNormal; + } catch(const MyError&) { + Close(); + throw; + } + + ThreadStart(); +} + +void VDFileAsync9x::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { + try { + mFilename = ""; + + HANDLE hProcess = GetCurrentProcess(); + if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) + throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); + + mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). + + mBlockSize = bufferSize; + mBlockCount = count; + mBuffer.Init(count * bufferSize); + + mState = kStateNormal; + } catch(const MyError&) { + Close(); + throw; + } + + ThreadStart(); +} + +void VDFileAsync9x::Close() { + mState = kStateAbort; + mWriteOccurred.signal(); + ThreadWait(); + + if (mhFileSlow != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileSlow); + mhFileSlow = INVALID_HANDLE_VALUE; + } + if (mhFileFast != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileFast); + mhFileFast = INVALID_HANDLE_VALUE; + } +} + +void VDFileAsync9x::FastWrite(const void *pData, uint32 bytes) { + if (mhFileFast == INVALID_HANDLE_VALUE) { + if (pData) + Write(mClientFastPointer, pData, bytes); + else + WriteZero(mClientFastPointer, bytes); + } else { + if (mpError) + ThrowError(); + + uint32 bytesLeft = bytes; + while(bytesLeft) { + int actual; + void *p = mBuffer.LockWrite(bytesLeft, actual); + + if (!actual) { + mReadOccurred.wait(); + if (mpError) + ThrowError(); + continue; + } + + if (pData) { + memcpy(p, pData, actual); + pData = (const char *)pData + actual; + } else { + memset(p, 0, actual); + } + mBuffer.UnlockWrite(actual); + mWriteOccurred.signal(); + bytesLeft -= actual; + } + } + + mClientFastPointer += bytes; +} + +void VDFileAsync9x::FastWriteEnd() { + FastWrite(NULL, mSectorSize - 1); + + mState = kStateFlush; + mWriteOccurred.signal(); + ThreadWait(); + + if (mpError) + ThrowError(); +} + +void VDFileAsync9x::Write(sint64 pos, const void *p, uint32 bytes) { + Seek(pos); + + DWORD dwActual; + if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || dwActual != bytes) { + mClientSlowPointer = -1; + throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); + } + + mClientSlowPointer += bytes; +} + +void VDFileAsync9x::WriteZero(sint64 pos, uint32 bytes) { + uint32 bufsize = bytes > 2048 ? 2048 : bytes; + void *p = _alloca(bufsize); + memset(p, 0, bufsize); + + while(bytes > 0) { + uint32 tc = bytes > 2048 ? 2048 : bytes; + + Write(pos, p, tc); + pos += tc; + bytes -= tc; + } +} + +bool VDFileAsync9x::Extend(sint64 pos) { + return SeekNT(pos) && SetEndOfFile(mhFileSlow); +} + +void VDFileAsync9x::Truncate(sint64 pos) { + Seek(pos); + if (!SetEndOfFile(mhFileSlow)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +void VDFileAsync9x::SafeTruncateAndClose(sint64 pos) { + if (mhFileSlow != INVALID_HANDLE_VALUE) { + FastWrite(NULL, mSectorSize - 1); + + mState = kStateFlush; + mWriteOccurred.signal(); + ThreadWait(); + + Extend(pos); + Close(); + } +} + +sint64 VDFileAsync9x::GetSize() { + DWORD dwSizeHigh; + DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); + + if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + return dwSizeLow + ((sint64)dwSizeHigh << 32); +} + +void VDFileAsync9x::Seek(sint64 pos) { + if (!SeekNT(pos)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +bool VDFileAsync9x::SeekNT(sint64 pos) { + if (mClientSlowPointer == pos) + return true; + + LONG posHi = (LONG)(pos >> 32); + DWORD result = SetFilePointer(mhFileSlow, (LONG)pos, &posHi, FILE_BEGIN); + + if (result == INVALID_SET_FILE_POINTER) { + DWORD dwError = GetLastError(); + + if (dwError != NO_ERROR) { + mClientSlowPointer = -1; + return false; + } + } + + mClientSlowPointer = pos; + + return true; +} + +void VDFileAsync9x::ThrowError() { + MyError *e = mpError.xchg(NULL); + + if (e) { + if (mhFileFast != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileFast); + mhFileFast = INVALID_HANDLE_VALUE; + } + + MyError tmp; + tmp.TransferFrom(*e); + delete e; + throw tmp; + } +} + +void VDFileAsync9x::ThreadRun() { + bool bPreemptiveExtend = mbPreemptiveExtend; + sint64 currentSize; + sint64 pos = 0; + uint32 bufferSize = mBlockCount * mBlockSize; + HANDLE hFile = mhFileFast != INVALID_HANDLE_VALUE ? mhFileFast : mhFileSlow; + + try { + if (bPreemptiveExtend && !VDGetFileSizeW32(hFile, currentSize)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + for(;;) { + int state = mState; + + if (state == kStateAbort) + break; + + int actual; + const void *p = mBuffer.LockRead(mBlockSize, actual); + + if ((uint32)actual < mBlockSize) { + if (state == kStateNormal) { + mWriteOccurred.wait(); + continue; + } + + VDASSERT(state == kStateFlush); + + actual &= ~(mSectorSize-1); + if (!actual) + break; + } else { + if (bPreemptiveExtend) { + sint64 checkpt = pos + mBlockSize + bufferSize; + + if (checkpt > currentSize) { + currentSize += bufferSize; + if (currentSize < checkpt) + currentSize = checkpt; + + if (!VDSetFilePointerW32(hFile, currentSize, FILE_BEGIN) + || !SetEndOfFile(hFile)) + mbPreemptiveExtend = bPreemptiveExtend = false; + + if (!VDSetFilePointerW32(hFile, pos, FILE_BEGIN)) + throw MyWin32Error("Seek error occurred on file \"%s\": %%s\n", GetLastError(), mFilename.c_str()); + } + } + } + + DWORD dwActual; + if (!WriteFile(hFile, p, actual, &dwActual, NULL) || dwActual != actual) { + DWORD dwError = GetLastError(); + throw MyWin32Error("Write error occurred on file \"%s\": %%s\n", dwError, mFilename.c_str()); + } + + pos += actual; + + mBuffer.UnlockRead(actual); + + mReadOccurred.signal(); + } + } catch(MyError& e) { + MyError *p = new MyError; + + p->TransferFrom(e); + delete mpError.xchg(p); + mReadOccurred.signal(); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// VDFileAsync - Windows NT implementation +// +/////////////////////////////////////////////////////////////////////////// + +struct VDFileAsyncNTBuffer : public OVERLAPPED { + bool mbActive; + bool mbPending; + uint32 mLength; + + VDFileAsyncNTBuffer() : mbActive(false), mbPending(false) { hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } + ~VDFileAsyncNTBuffer() { if (hEvent) CloseHandle(hEvent); } +}; + +class VDFileAsyncNT : public IVDFileAsync, private VDThread { +public: + VDFileAsyncNT(); + ~VDFileAsyncNT(); + + void SetPreemptiveExtend(bool b) { mbPreemptiveExtend = b; } + bool IsPreemptiveExtendActive() { return mbPreemptiveExtend; } + + bool IsOpen() { return mhFileSlow != INVALID_HANDLE_VALUE; } + + void Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize); + void Open(VDFileHandle h, uint32 count, uint32 bufferSize); + void Close(); + void FastWrite(const void *pData, uint32 bytes); + void FastWriteEnd(); + void Write(sint64 pos, const void *pData, uint32 bytes); + bool Extend(sint64 pos); + void Truncate(sint64 pos); + void SafeTruncateAndClose(sint64 pos); + sint64 GetSize(); + sint64 GetFastWritePos() { return mClientFastPointer; } + +protected: + void WriteZero(sint64 pos, uint32 bytes); + void Seek(sint64 pos); + bool SeekNT(sint64 pos); + void ThrowError(); + void ThreadRun(); + + HANDLE mhFileSlow; + HANDLE mhFileFast; + uint32 mBlockSize; + uint32 mBlockCount; + uint32 mBufferSize; + uint32 mSectorSize; + + enum { + kStateNormal, + kStateFlush, + kStateAbort + }; + VDAtomicInt mState; + + VDSignal mReadOccurred; + VDSignal mWriteOccurred; + + uint32 mWriteOffset; + VDAtomicInt mBufferLevel; + sint64 mClientSlowPointer; + sint64 mClientFastPointer; + sint64 mFastPointer; + + volatile bool mbPreemptiveExtend; + + vdautoarrayptr mpBlocks; + + vdblock > mBuffer; + + VDAtomicPtr mpError; + VDStringA mFilename; +}; + +VDFileAsyncNT::VDFileAsyncNT() + : mhFileSlow(INVALID_HANDLE_VALUE) + , mhFileFast(INVALID_HANDLE_VALUE) + , mFastPointer(0) + , mClientSlowPointer(0) + , mClientFastPointer(0) + , mbPreemptiveExtend(false) + , mpError(NULL) +{ +} + +VDFileAsyncNT::~VDFileAsyncNT() { + Close(); +} + +void VDFileAsyncNT::Open(const wchar_t *pszFilename, uint32 count, uint32 bufferSize) { + try { + mFilename = VDTextWToA(pszFilename); + + mhFileSlow = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (mhFileSlow == INVALID_HANDLE_VALUE) + throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); + + mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); + if (mhFileFast == INVALID_HANDLE_VALUE) + mhFileFast = CreateFileW(pszFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL); + + mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). + + mBlockSize = bufferSize; + mBlockCount = count; + mBufferSize = mBlockSize * mBlockCount; + + mWriteOffset = 0; + mBufferLevel = 0; + + mState = kStateNormal; + + if (mhFileFast != INVALID_HANDLE_VALUE) { + mpBlocks = new VDFileAsyncNTBuffer[count]; + mBuffer.resize(count * bufferSize); + ThreadStart(); + } + } catch(const MyError&) { + Close(); + throw; + } +} + +void VDFileAsyncNT::Open(VDFileHandle h, uint32 count, uint32 bufferSize) { + try { + mFilename = ""; + + HANDLE hProcess = GetCurrentProcess(); + if (!DuplicateHandle(hProcess, h, hProcess, &mhFileSlow, 0, FALSE, DUPLICATE_SAME_ACCESS)) + throw MyWin32Error("Unable to open file \"%s\" for write: %%s", GetLastError(), mFilename.c_str()); + + mSectorSize = 4096; // guess for now... proper way would be GetVolumeMountPoint() followed by GetDiskFreeSpace(). + + mBlockSize = bufferSize; + mBlockCount = count; + mBufferSize = mBlockSize * mBlockCount; + + mWriteOffset = 0; + mBufferLevel = 0; + + mState = kStateNormal; + + if (mhFileFast != INVALID_HANDLE_VALUE) { + mpBlocks = new VDFileAsyncNTBuffer[count]; + mBuffer.resize(count * bufferSize); + ThreadStart(); + } + } catch(const MyError&) { + Close(); + throw; + } +} + +void VDFileAsyncNT::Close() { + mState = kStateAbort; + mWriteOccurred.signal(); + ThreadWait(); + + if (mpError) { + delete mpError; + mpError = NULL; + } + + if (mhFileSlow != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileSlow); + mhFileSlow = INVALID_HANDLE_VALUE; + } + if (mhFileFast != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileFast); + mhFileFast = INVALID_HANDLE_VALUE; + } + + mpBlocks = NULL; +} + +void VDFileAsyncNT::FastWrite(const void *pData, uint32 bytes) { + if (mhFileFast == INVALID_HANDLE_VALUE) { + if (pData) + Write(mClientFastPointer, pData, bytes); + else + WriteZero(mClientFastPointer, bytes); + } else { + if (mpError) + ThrowError(); + + uint32 bytesLeft = bytes; + while(bytesLeft) { + uint32 actual = mBufferSize - mBufferLevel; + + if (actual > bytesLeft) + actual = bytesLeft; + + if (mWriteOffset + actual > mBufferSize) + actual = mBufferSize - mWriteOffset; + + if (!actual) { + mReadOccurred.wait(); + if (mpError) + ThrowError(); + continue; + } + + if (pData) { + memcpy(&mBuffer[mWriteOffset], pData, actual); + pData = (const char *)pData + actual; + } else { + memset(&mBuffer[mWriteOffset], 0, actual); + } + + uint32 oldWriteOffset = mWriteOffset; + mWriteOffset += actual; + if (mWriteOffset >= mBufferSize) + mWriteOffset = 0; + mBufferLevel += actual; + + // only bother signaling if the write offset crossed a block boundary + if (oldWriteOffset % mBlockSize + actual >= mBlockSize) { + mWriteOccurred.signal(); + if (mpError) + ThrowError(); + } + + bytesLeft -= actual; + } + } + + mClientFastPointer += bytes; +} + +void VDFileAsyncNT::FastWriteEnd() { + if (mhFileFast != INVALID_HANDLE_VALUE) { + FastWrite(NULL, mSectorSize - 1); + mState = kStateFlush; + mWriteOccurred.signal(); + ThreadWait(); + } + + if (mpError) + ThrowError(); +} + +void VDFileAsyncNT::Write(sint64 pos, const void *p, uint32 bytes) { + Seek(pos); + + DWORD dwActual; + if (!WriteFile(mhFileSlow, p, bytes, &dwActual, NULL) || (mClientSlowPointer += dwActual),(dwActual != bytes)) + throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +void VDFileAsyncNT::WriteZero(sint64 pos, uint32 bytes) { + uint32 bufsize = bytes > 2048 ? 2048 : bytes; + void *p = _alloca(bufsize); + memset(p, 0, bufsize); + + while(bytes > 0) { + uint32 tc = bytes > 2048 ? 2048 : bytes; + + Write(pos, p, tc); + pos += tc; + bytes -= tc; + } +} + +bool VDFileAsyncNT::Extend(sint64 pos) { + return SeekNT(pos) && SetEndOfFile(mhFileSlow); +} + +void VDFileAsyncNT::Truncate(sint64 pos) { + Seek(pos); + if (!SetEndOfFile(mhFileSlow)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +void VDFileAsyncNT::SafeTruncateAndClose(sint64 pos) { + if (isThreadAttached()) { + mState = kStateAbort; + mWriteOccurred.signal(); + ThreadWait(); + + if (mpError) { + delete mpError; + mpError = NULL; + } + } + + if (mhFileSlow != INVALID_HANDLE_VALUE) { + Extend(pos); + Close(); + } +} + +sint64 VDFileAsyncNT::GetSize() { + DWORD dwSizeHigh; + DWORD dwSizeLow = GetFileSize(mhFileSlow, &dwSizeHigh); + + if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + return dwSizeLow + ((sint64)dwSizeHigh << 32); +} + +void VDFileAsyncNT::Seek(sint64 pos) { + if (!SeekNT(pos)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); +} + +bool VDFileAsyncNT::SeekNT(sint64 pos) { + if (mClientSlowPointer == pos) + return true; + + LONG posHi = (LONG)(pos >> 32); + DWORD result = SetFilePointer(mhFileSlow, (LONG)pos, &posHi, FILE_BEGIN); + + if (result == INVALID_SET_FILE_POINTER) { + DWORD dwError = GetLastError(); + + if (dwError != NO_ERROR) + return false; + } + + mClientSlowPointer = pos; + return true; +} + +void VDFileAsyncNT::ThrowError() { + MyError *e = mpError.xchg(NULL); + + if (e) { + if (mhFileFast != INVALID_HANDLE_VALUE) { + CloseHandle(mhFileFast); + mhFileFast = INVALID_HANDLE_VALUE; + } + + MyError tmp; + tmp.TransferFrom(*e); + delete e; + throw tmp; + } +} + +void VDFileAsyncNT::ThreadRun() { + int requestHead = 0; + int requestTail = 0; + int requestCount = mBlockCount; + uint32 pendingLevel = 0; + uint32 readOffset = 0; + bool bPreemptiveExtend = mbPreemptiveExtend; + sint64 currentSize; + + try { + if (!VDGetFileSizeW32(mhFileFast, currentSize)) + throw MyWin32Error("I/O error on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + for(;;) { + int state = mState; + + if (state == kStateAbort) { + typedef BOOL (WINAPI *tpCancelIo)(HANDLE); + static const tpCancelIo pCancelIo = (tpCancelIo)GetProcAddress(GetModuleHandle("kernel32"), "CancelIo"); + pCancelIo(mhFileFast); + + // Wait for any pending blocks to complete. + for(int i=0; i= 0); + if (readOffset + actual > mBufferSize) + actual = mBufferSize - readOffset; + + if (actual < mBlockSize) { + if (state == kStateNormal || actual < mSectorSize) { + // check for blocks that have completed + bool blocksCompleted = false; + for(;;) { + VDFileAsyncNTBuffer& buf = mpBlocks[requestTail]; + + if (!buf.mbActive) { + if (state == kStateFlush) + goto all_done; + + if (!blocksCompleted) { + // wait for further writes + mWriteOccurred.wait(); + } + break; + } + + if (buf.mbPending) { + HANDLE h[2] = {buf.hEvent, mWriteOccurred.getHandle()}; + DWORD waitResult = WaitForMultipleObjects(2, h, FALSE, INFINITE); + + if (waitResult == WAIT_OBJECT_0+1) // write pending + break; + + DWORD dwActual; + if (!GetOverlappedResult(mhFileFast, &buf, &dwActual, TRUE)) + throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + } + + buf.mbActive = false; + + blocksCompleted = true; + + if (++requestTail >= requestCount) + requestTail = 0; + + mBufferLevel -= buf.mLength; + pendingLevel -= buf.mLength; + VDASSERT((int)mBufferLevel >= 0); + VDASSERT((int)pendingLevel >= 0); + + mReadOccurred.signal(); + + } + + continue; + } + + VDASSERT(state == kStateFlush); + + actual &= ~(mSectorSize-1); + + VDASSERT(actual > 0); + } else { + actual = mBlockSize; + + if (bPreemptiveExtend) { + sint64 checkpt = mFastPointer + mBlockSize + mBufferSize; + + if (checkpt > currentSize) { + currentSize += mBufferSize; + if (currentSize < checkpt) + currentSize = checkpt; + + if (!VDSetFilePointerW32(mhFileFast, currentSize, FILE_BEGIN) + || !SetEndOfFile(mhFileFast)) + mbPreemptiveExtend = bPreemptiveExtend = false; + } + } + } + + // Issue a write to OS + VDFileAsyncNTBuffer& buf = mpBlocks[requestHead]; + + VDASSERT(!buf.mbActive); + + DWORD dwActual; + + buf.Offset = (DWORD)mFastPointer; + buf.OffsetHigh = (DWORD)((uint64)mFastPointer >> 32); + buf.Internal = 0; + buf.InternalHigh = 0; + buf.mLength = actual; + buf.mbPending = false; + + if (!WriteFile(mhFileFast, &mBuffer[readOffset], actual, &dwActual, &buf)) { + if (GetLastError() != ERROR_IO_PENDING) + throw MyWin32Error("Write error occurred on file \"%s\": %%s", GetLastError(), mFilename.c_str()); + + buf.mbPending = true; + } + + buf.mbActive = true; + + pendingLevel += actual; + VDASSERT(pendingLevel <= (uint32)mBufferLevel); + + readOffset += actual; + VDASSERT(readOffset <= mBufferSize); + if (readOffset >= mBufferSize) + readOffset = 0; + + mFastPointer += actual; + + if (++requestHead >= requestCount) + requestHead = 0; + } +all_done: + ; + + } catch(MyError& e) { + MyError *p = new MyError; + + p->TransferFrom(e); + delete mpError.xchg(p); + mReadOccurred.signal(); + } +} + +/////////////////////////////////////////////////////////////////////////// + +IVDFileAsync *VDCreateFileAsync(IVDFileAsync::Mode mode) { + switch(mode) { + + case IVDFileAsync::kModeAsynchronous: + if (VDIsWindowsNT()) + return new VDFileAsyncNT; + // Can't do async I/O. Fall-through to 9x method. + case IVDFileAsync::kModeThreaded: + return new VDFileAsync9x(true, true); + + default: + return new VDFileAsync9x(false, true); + + case IVDFileAsync::kModeBuffered: + return new VDFileAsync9x(false, false); + } +} diff --git a/src/thirdparty/VirtualDub/system/source/filewatcher.cpp b/src/thirdparty/VirtualDub/system/source/filewatcher.cpp index 72053740b1c..f09c8dcf38e 100644 --- a/src/thirdparty/VirtualDub/system/source/filewatcher.cpp +++ b/src/thirdparty/VirtualDub/system/source/filewatcher.cpp @@ -1,157 +1,157 @@ -#include "stdafx.h" -#include -#include -#include -#include -#include - -VDFileWatcher::VDFileWatcher() - : mChangeHandle(INVALID_HANDLE_VALUE) - , mLastWriteTime(0) - , mbWatchDir(false) - , mbRepeatRequested(false) - , mbThunksInited(false) - , mpThunk(NULL) - , mTimerId(0) -{ -} - -VDFileWatcher::~VDFileWatcher() { - Shutdown(); -} - -bool VDFileWatcher::IsActive() const { - return mChangeHandle != INVALID_HANDLE_VALUE; -} - -void VDFileWatcher::Init(const wchar_t *file, IVDFileWatcherCallback *callback) { - Shutdown(); - - const wchar_t *pathEnd = VDFileSplitPath(file); - - VDStringW basePath(file, pathEnd); - - if (basePath.empty()) - basePath = L"."; - - if (VDIsWindowsNT()) - mChangeHandle = FindFirstChangeNotificationW(basePath.c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); - else - mChangeHandle = FindFirstChangeNotificationA(VDTextWToA(basePath).c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); - - if (mChangeHandle == INVALID_HANDLE_VALUE) - throw MyError("Unable to monitor file: %ls", file); - - mPath = file; - mLastWriteTime = VDFileGetLastWriteTime(mPath.c_str()); - mpCB = callback; - mbRepeatRequested = false; - mbWatchDir = false; - - if (callback) { - if (!mbThunksInited) - mbThunksInited = VDInitThunkAllocator(); - - if (mbThunksInited) { - mpThunk = VDCreateFunctionThunkFromMethod(this, &VDFileWatcher::StaticTimerCallback, true); - - if (mpThunk) { - mTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)mpThunk); - } - } - } -} - -void VDFileWatcher::InitDir(const wchar_t *path, bool subdirs, IVDFileWatcherCallback *callback) { - Shutdown(); - - const DWORD flags - = FILE_NOTIFY_CHANGE_SIZE - | FILE_NOTIFY_CHANGE_ATTRIBUTES - | FILE_NOTIFY_CHANGE_LAST_WRITE - | FILE_NOTIFY_CHANGE_FILE_NAME - | FILE_NOTIFY_CHANGE_CREATION; - if (VDIsWindowsNT()) - mChangeHandle = FindFirstChangeNotificationW(path, subdirs, flags); - else - mChangeHandle = FindFirstChangeNotificationA(VDTextWToA(path).c_str(), subdirs, flags); - - if (mChangeHandle == INVALID_HANDLE_VALUE) - throw MyError("Unable to monitor path: %ls", path); - - mPath = path; - mpCB = callback; - mbRepeatRequested = false; - mbWatchDir = true; - - if (callback) { - if (!mbThunksInited) - mbThunksInited = VDInitThunkAllocator(); - - if (mbThunksInited) { - mpThunk = VDCreateFunctionThunkFromMethod(this, &VDFileWatcher::StaticTimerCallback, true); - - if (mpThunk) { - mTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)mpThunk); - } - } - } -} - -void VDFileWatcher::Shutdown() { - if (mChangeHandle != INVALID_HANDLE_VALUE) { - FindCloseChangeNotification(mChangeHandle); - mChangeHandle = INVALID_HANDLE_VALUE; - } - - if (mTimerId) { - KillTimer(NULL, mTimerId); - mTimerId = 0; - } - - if (mpThunk) { - VDDestroyFunctionThunk(mpThunk); - mpThunk = NULL; - } - - if (mbThunksInited) { - mbThunksInited = false; - - VDShutdownThunkAllocator(); - } -} - -bool VDFileWatcher::Wait(uint32 delay) { - if (mChangeHandle == INVALID_HANDLE_VALUE) - return false; - - if (WAIT_OBJECT_0 != WaitForSingleObject(mChangeHandle, delay)) - return false; - - FindNextChangeNotification(mChangeHandle); - - if (!mbWatchDir) { - uint64 t = VDFileGetLastWriteTime(mPath.c_str()); - - if (mLastWriteTime == t) - return false; - - mLastWriteTime = t; - } - return true; -} - -void VDFileWatcher::StaticTimerCallback(void *, unsigned, unsigned, unsigned long) { - if (mbRepeatRequested) { - if (mpCB) - mbRepeatRequested = !mpCB->OnFileUpdated(mPath.c_str()); - else - mbRepeatRequested = false; - return; - } - - if (Wait(0)) { - if (mpCB) - mbRepeatRequested = !mpCB->OnFileUpdated(mPath.c_str()); - } -} +#include "stdafx.h" +#include +#include +#include +#include +#include + +VDFileWatcher::VDFileWatcher() + : mChangeHandle(INVALID_HANDLE_VALUE) + , mLastWriteTime(0) + , mbWatchDir(false) + , mbRepeatRequested(false) + , mbThunksInited(false) + , mpThunk(NULL) + , mTimerId(0) +{ +} + +VDFileWatcher::~VDFileWatcher() { + Shutdown(); +} + +bool VDFileWatcher::IsActive() const { + return mChangeHandle != INVALID_HANDLE_VALUE; +} + +void VDFileWatcher::Init(const wchar_t *file, IVDFileWatcherCallback *callback) { + Shutdown(); + + const wchar_t *pathEnd = VDFileSplitPath(file); + + VDStringW basePath(file, pathEnd); + + if (basePath.empty()) + basePath = L"."; + + if (VDIsWindowsNT()) + mChangeHandle = FindFirstChangeNotificationW(basePath.c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); + else + mChangeHandle = FindFirstChangeNotificationA(VDTextWToA(basePath).c_str(), FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); + + if (mChangeHandle == INVALID_HANDLE_VALUE) + throw MyError("Unable to monitor file: %ls", file); + + mPath = file; + mLastWriteTime = VDFileGetLastWriteTime(mPath.c_str()); + mpCB = callback; + mbRepeatRequested = false; + mbWatchDir = false; + + if (callback) { + if (!mbThunksInited) + mbThunksInited = VDInitThunkAllocator(); + + if (mbThunksInited) { + mpThunk = VDCreateFunctionThunkFromMethod(this, &VDFileWatcher::StaticTimerCallback, true); + + if (mpThunk) { + mTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)mpThunk); + } + } + } +} + +void VDFileWatcher::InitDir(const wchar_t *path, bool subdirs, IVDFileWatcherCallback *callback) { + Shutdown(); + + const DWORD flags + = FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_ATTRIBUTES + | FILE_NOTIFY_CHANGE_LAST_WRITE + | FILE_NOTIFY_CHANGE_FILE_NAME + | FILE_NOTIFY_CHANGE_CREATION; + if (VDIsWindowsNT()) + mChangeHandle = FindFirstChangeNotificationW(path, subdirs, flags); + else + mChangeHandle = FindFirstChangeNotificationA(VDTextWToA(path).c_str(), subdirs, flags); + + if (mChangeHandle == INVALID_HANDLE_VALUE) + throw MyError("Unable to monitor path: %ls", path); + + mPath = path; + mpCB = callback; + mbRepeatRequested = false; + mbWatchDir = true; + + if (callback) { + if (!mbThunksInited) + mbThunksInited = VDInitThunkAllocator(); + + if (mbThunksInited) { + mpThunk = VDCreateFunctionThunkFromMethod(this, &VDFileWatcher::StaticTimerCallback, true); + + if (mpThunk) { + mTimerId = SetTimer(NULL, 0, 1000, (TIMERPROC)mpThunk); + } + } + } +} + +void VDFileWatcher::Shutdown() { + if (mChangeHandle != INVALID_HANDLE_VALUE) { + FindCloseChangeNotification(mChangeHandle); + mChangeHandle = INVALID_HANDLE_VALUE; + } + + if (mTimerId) { + KillTimer(NULL, mTimerId); + mTimerId = 0; + } + + if (mpThunk) { + VDDestroyFunctionThunk(mpThunk); + mpThunk = NULL; + } + + if (mbThunksInited) { + mbThunksInited = false; + + VDShutdownThunkAllocator(); + } +} + +bool VDFileWatcher::Wait(uint32 delay) { + if (mChangeHandle == INVALID_HANDLE_VALUE) + return false; + + if (WAIT_OBJECT_0 != WaitForSingleObject(mChangeHandle, delay)) + return false; + + FindNextChangeNotification(mChangeHandle); + + if (!mbWatchDir) { + uint64 t = VDFileGetLastWriteTime(mPath.c_str()); + + if (mLastWriteTime == t) + return false; + + mLastWriteTime = t; + } + return true; +} + +void VDFileWatcher::StaticTimerCallback(void *, unsigned, unsigned, unsigned long) { + if (mbRepeatRequested) { + if (mpCB) + mbRepeatRequested = !mpCB->OnFileUpdated(mPath.c_str()); + else + mbRepeatRequested = false; + return; + } + + if (Wait(0)) { + if (mpCB) + mbRepeatRequested = !mpCB->OnFileUpdated(mPath.c_str()); + } +} diff --git a/src/thirdparty/VirtualDub/system/source/halffloat.cpp b/src/thirdparty/VirtualDub/system/source/halffloat.cpp index f9620e5ae15..9875a3003b8 100644 --- a/src/thirdparty/VirtualDub/system/source/halffloat.cpp +++ b/src/thirdparty/VirtualDub/system/source/halffloat.cpp @@ -1,79 +1,79 @@ -#include "stdafx.h" -#include - -uint16 VDConvertFloatToHalf(const void *f) { - uint32 v = *(const uint32 *)f; - - uint32 sign = (v >> 16) & 0x8000; - sint32 exmant = v & 0x7fffffff; - - if (exmant > 0x7f800000) { - // convert NaNs directly - exmant = (exmant & 0x00400000) + 0x47a00000; - } else if (exmant > 0x47800000) { - // clamp large numbers to infinity - exmant = 0x47800000; - } else if (exmant < 0x33800000) { - // clamp very tiny numbers to zero - exmant = 0x38000000; - } else if (exmant < 0x38800000) { - // normalized finite converting to denormal - uint32 ex = exmant & 0x7f800000; - uint32 mant = (exmant & 0x007fffff) | 0x800000; - uint32 sticky = 0; - - while(ex < 0x38800000) { - ex += 0x00800000; - sticky |= mant; - mant >>= 1; - } - - // round to nearest even - sticky |= mant >> 13; - - // round up with sticky bits - mant += (sticky & 1); - - // round up with round bit - mant += 0x0fff; - - exmant = ex + mant - 0x800000; - } else { - // round normal numbers using round to nearest even - exmant |= (exmant & 0x00002000) >> 13; - exmant += 0x00000fff; - } - - // shift and rebias exponent - exmant -= 0x38000000; - exmant >>= 13; - - return (uint16)(sign + exmant); -} - -void VDConvertHalfToFloat(uint16 h, void *dst) { - uint32 sign = ((uint32)h << 16) & 0x80000000; - uint32 exmant = (uint32)h & 0x7fff; - uint32 v = 0; - - if (exmant >= 0x7c00) { - // infinity or NaN - v = (exmant << 13) + 0x70000000; - } else if (exmant >= 0x0400) { - // normalized finite - v = (exmant << 13) + 0x38000000; - } else if (exmant) { - // denormal - uint32 ex32 = 0x38000000; - uint32 mant32 = (exmant & 0x3ff) << 13; - - while(!(mant32 & 0x800000)) { - mant32 <<= 1; - ex32 -= 0x800000; - } - - v = ex32 + mant32; - } - - *(uint32 *)dst = v + sign; -} +#include "stdafx.h" +#include + +uint16 VDConvertFloatToHalf(const void *f) { + uint32 v = *(const uint32 *)f; + + uint32 sign = (v >> 16) & 0x8000; + sint32 exmant = v & 0x7fffffff; + + if (exmant > 0x7f800000) { + // convert NaNs directly + exmant = (exmant & 0x00400000) + 0x47a00000; + } else if (exmant > 0x47800000) { + // clamp large numbers to infinity + exmant = 0x47800000; + } else if (exmant < 0x33800000) { + // clamp very tiny numbers to zero + exmant = 0x38000000; + } else if (exmant < 0x38800000) { + // normalized finite converting to denormal + uint32 ex = exmant & 0x7f800000; + uint32 mant = (exmant & 0x007fffff) | 0x800000; + uint32 sticky = 0; + + while(ex < 0x38800000) { + ex += 0x00800000; + sticky |= mant; + mant >>= 1; + } + + // round to nearest even + sticky |= mant >> 13; + + // round up with sticky bits + mant += (sticky & 1); + + // round up with round bit + mant += 0x0fff; + + exmant = ex + mant - 0x800000; + } else { + // round normal numbers using round to nearest even + exmant |= (exmant & 0x00002000) >> 13; + exmant += 0x00000fff; + } + + // shift and rebias exponent + exmant -= 0x38000000; + exmant >>= 13; + + return (uint16)(sign + exmant); +} + +void VDConvertHalfToFloat(uint16 h, void *dst) { + uint32 sign = ((uint32)h << 16) & 0x80000000; + uint32 exmant = (uint32)h & 0x7fff; + uint32 v = 0; + + if (exmant >= 0x7c00) { + // infinity or NaN + v = (exmant << 13) + 0x70000000; + } else if (exmant >= 0x0400) { + // normalized finite + v = (exmant << 13) + 0x38000000; + } else if (exmant) { + // denormal + uint32 ex32 = 0x38000000; + uint32 mant32 = (exmant & 0x3ff) << 13; + + while(!(mant32 & 0x800000)) { + mant32 <<= 1; + ex32 -= 0x800000; + } + + v = ex32 + mant32; + } + + *(uint32 *)dst = v + sign; +} diff --git a/src/thirdparty/VirtualDub/system/source/hash.cpp b/src/thirdparty/VirtualDub/system/source/hash.cpp index 8d80ba59779..c9665f9cbdc 100644 --- a/src/thirdparty/VirtualDub/system/source/hash.cpp +++ b/src/thirdparty/VirtualDub/system/source/hash.cpp @@ -1,123 +1,123 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -// Based on: SuperFastHash by Paul Hsieh -// http://www.azillionmonkeys.com/qed/hash.html - -uint32 VDHashString32(const char *s) { - uint32 len = (uint32)strlen(s); - - return VDHashString32(s, len); -} - -uint32 VDHashString32(const char *s, uint32 len) { - uint32 hash = len; - - uint32 rem = len & 3; - len >>= 2; - - uint32 tmp; - for(uint32 i=0; i> 11; - } - - switch(rem) { - case 3: - hash += VDReadUnalignedU16(s); - hash ^= hash << 16; - hash ^= (uint32)(uint8)s[2] << 18; - hash += hash >> 11; - break; - case 2: - hash += VDReadUnalignedU16(s); - hash ^= hash << 11; - hash += hash >> 17; - break; - case 1: - hash += (uint8)s[0]; - hash ^= hash << 10; - hash += hash >> 1; - break; - } - - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} - -uint32 VDHashString32(const wchar_t *s) { - return VDHashString32((const char *)s, wcslen(s) * sizeof(wchar_t)); -} - -uint32 VDHashString32(const wchar_t *s, uint32 len) { - return VDHashString32((const char *)s, len * sizeof(wchar_t)); -} - -uint32 VDHashString32I(const char *s) { - uint32 len = (uint32)strlen(s); - - return VDHashString32I(s, len); -} - -uint32 VDHashString32I(const char *s, uint32 len) { - uint32 hash = 2166136261U; - - for(uint32 i=0; i +#include + +// Based on: SuperFastHash by Paul Hsieh +// http://www.azillionmonkeys.com/qed/hash.html + +uint32 VDHashString32(const char *s) { + uint32 len = (uint32)strlen(s); + + return VDHashString32(s, len); +} + +uint32 VDHashString32(const char *s, uint32 len) { + uint32 hash = len; + + uint32 rem = len & 3; + len >>= 2; + + uint32 tmp; + for(uint32 i=0; i> 11; + } + + switch(rem) { + case 3: + hash += VDReadUnalignedU16(s); + hash ^= hash << 16; + hash ^= (uint32)(uint8)s[2] << 18; + hash += hash >> 11; + break; + case 2: + hash += VDReadUnalignedU16(s); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: + hash += (uint8)s[0]; + hash ^= hash << 10; + hash += hash >> 1; + break; + } + + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +uint32 VDHashString32(const wchar_t *s) { + return VDHashString32((const char *)s, wcslen(s) * sizeof(wchar_t)); +} + +uint32 VDHashString32(const wchar_t *s, uint32 len) { + return VDHashString32((const char *)s, len * sizeof(wchar_t)); +} + +uint32 VDHashString32I(const char *s) { + uint32 len = (uint32)strlen(s); + + return VDHashString32I(s, len); +} + +uint32 VDHashString32I(const char *s, uint32 len) { + uint32 hash = 2166136261U; + + for(uint32 i=0; i - -#include - -#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - void __declspec(naked) __cdecl vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { - __asm { - push ebx - - mov ebx, [esp+16] - mov ecx, [esp+12] - mov edx, [esp+8] - - mov eax, [ecx+0] - add eax, [ebx+0] - mov [edx+0],eax - mov eax, [ecx+4] - adc eax, [ebx+4] - mov [edx+4],eax - mov eax, [ecx+8] - adc eax, [ebx+8] - mov [edx+8],eax - mov eax, [ecx+12] - adc eax, [ebx+12] - mov [edx+12],eax - - pop ebx - ret - } - } - - void __declspec(naked) __cdecl vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { - __asm { - push ebx - - mov ebx, [esp+16] - mov ecx, [esp+12] - mov edx, [esp+8] - - mov eax, [ecx+0] - sub eax, [ebx+0] - mov [edx+0],eax - mov eax, [ecx+4] - sbb eax, [ebx+4] - mov [edx+4],eax - mov eax, [ecx+8] - sbb eax, [ebx+8] - mov [edx+8],eax - mov eax, [ecx+12] - sbb eax, [ebx+12] - mov [edx+12],eax - - pop ebx - ret - } - } - - void __declspec(naked) vdint128::setSquare(sint64 v) { - __asm { - push edi - push esi - push ebx - mov eax, [esp+20] - cdq - mov esi, eax - mov eax, [esp+16] - xor eax, edx - xor esi, edx - sub eax, edx - sbb esi, edx - mov ebx, eax - mul eax - mov [ecx], eax - mov edi, edx - mov eax, ebx - mul esi - mov ebx, 0 - add eax, eax - adc edx, edx - add eax, edi - adc edx, 0 - mov edi, edx - adc ebx, 0 - mov [ecx+4], eax - mov eax, esi - mul esi - add eax, edi - adc edx, ebx - mov [ecx+8], eax - mov [ecx+12], edx - pop ebx - pop esi - pop edi - ret 8 - } - } - - const vdint128 __declspec(naked) vdint128::operator<<(int v) const { - __asm { - push ebp - push ebx - push esi - push edi - - mov esi,ecx - mov edx,[esp+20] - - mov ecx,[esp+24] - cmp ecx,128 - jae zeroit - - mov eax,[esi+12] - mov ebx,[esi+8] - mov edi,[esi+4] - mov ebp,[esi] - - dwordloop: - cmp ecx,32 - jb bits - - mov eax,ebx - mov ebx,edi - mov edi,ebp - xor ebp,ebp - sub ecx,32 - jmp short dwordloop - - bits: - shld eax,ebx,cl - shld ebx,edi,cl - mov [edx+12],eax - mov [edx+8],ebx - shld edi,ebp,cl - - shl ebp,cl - mov [edx+4],edi - mov [edx],ebp - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - - zeroit: - xor eax,eax - mov [edx+0],eax - mov [edx+4],eax - mov [edx+8],eax - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - } - } - - const vdint128 __declspec(naked) vdint128::operator>>(int v) const { - __asm { - push ebp - push ebx - push esi - push edi - - mov esi,ecx - mov edx,[esp+20] - - mov eax,[esi+12] - mov ecx,[esp+24] - cmp ecx,127 - jae clearit - - mov ebx,[esi+8] - mov edi,[esi+4] - mov ebp,[esi] - - dwordloop: - cmp ecx,32 - jb bits - - mov ebp,edi - mov edi,ebx - mov ebx,eax - sar eax,31 - sub ecx,32 - jmp short dwordloop - - bits: - shrd ebp,edi,cl - shrd edi,ebx,cl - mov [edx],ebp - mov [edx+4],edi - shrd ebx,eax,cl - - sar eax,cl - mov [edx+8],ebx - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - - clearit: - sar eax, 31 - mov [edx+0],eax - mov [edx+4],eax - mov [edx+8],eax - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - } - } - - const vduint128 __declspec(naked) vduint128::operator<<(int v) const { - __asm { - push ebp - push ebx - push esi - push edi - - mov esi,ecx - mov edx,[esp+20] - - mov ecx,[esp+24] - cmp ecx,128 - jae zeroit - - mov eax,[esi+12] - mov ebx,[esi+8] - mov edi,[esi+4] - mov ebp,[esi] - - dwordloop: - cmp ecx,32 - jb bits - - mov eax,ebx - mov ebx,edi - mov edi,ebp - xor ebp,ebp - sub ecx,32 - jmp short dwordloop - - bits: - shld eax,ebx,cl - shld ebx,edi,cl - mov [edx+12],eax - mov [edx+8],ebx - shld edi,ebp,cl - - shl ebp,cl - mov [edx+4],edi - mov [edx],ebp - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - - zeroit: - xor eax,eax - mov [edx+0],eax - mov [edx+4],eax - mov [edx+8],eax - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - } - } - - const vduint128 __declspec(naked) vduint128::operator>>(int v) const { - __asm { - push ebp - push ebx - push esi - push edi - - mov esi,ecx - mov edx,[esp+20] - - mov eax,[esi+12] - mov ecx,[esp+24] - cmp ecx,127 - jae clearit - - mov ebx,[esi+8] - mov edi,[esi+4] - mov ebp,[esi] - - dwordloop: - cmp ecx,32 - jb bits - - mov ebp,edi - mov edi,ebx - mov ebx,eax - xor eax,eax - sub ecx,32 - jmp short dwordloop - - bits: - shrd ebp,edi,cl - shrd edi,ebx,cl - mov [edx],ebp - mov [edx+4],edi - shrd ebx,eax,cl - - shr eax,cl - mov [edx+8],ebx - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - - clearit: - sar eax, 31 - mov [edx+0],eax - mov [edx+4],eax - mov [edx+8],eax - mov [edx+12],eax - - pop edi - pop esi - pop ebx - pop ebp - mov eax,[esp+4] - ret 8 - } - } - -#elif !defined(VD_CPU_AMD64) - - // These aren't really assembly routines, but we define them so we aren't asm dependent. - - void vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { - dst[0] = x[0] + y[0]; - dst[1] = x[1] + y[1] + (dst[0] < x[0]); - } - - void vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { - dst[0] = x[0] - y[0]; - dst[1] = x[1] - y[1] - (dst[0] > x[0]); - } - - void vdint128::setSquare(sint64 v) { - vdint128 r; - - uint32 u0 = (uint32)v; - uint32 u1 = (uint32)(v >> 32); - uint64 m0 = u0*u0; - uint64 m1 = u0*u1; // added twice - uint64 m2 = u1*u1; - uint32 s0 = (uint32)m0; - uint32 s1a = (uint32)(m0 >> 32); - uint32 s1b = (uint32)m1; - uint32 s2a = (uint32)(m1 >> 32); - - q[1] = m2 + s2a; - - d[0] = s0; - - d[1] = s1a + s1b; - if (d[1] < s1b) - ++q[1]; - - d[1] += s1b; - if (d[1] < s1b) - ++q[1]; - } - - const vdint128 vdint128::operator<<(int v) const { - vdint128 r; - - r.q[0] = q[0]; - r.q[1] = q[1]; - - if (v >= 64) { - if (v >= 128) { - r.q[0] = 0; - r.q[1] = 0; - return r; - } - - r.q[1] = r.q[0]; - r.q[0] = 0; - - v -= 64; - } - - if (v) { - r.q[1] = (r.q[1] << v) + ((uint64)r.q[0] >> (64 - v)); - r.q[0] <<= v; - } - - return r; - } - - const vdint128 vdint128::operator>>(int v) const { - vdint128 r; - - r.q[0] = q[0]; - r.q[1] = q[1]; - - if (v >= 64) { - sint64 sign = q[1] >> 63; - - if (v >= 128) { - r.q[0] = sign; - r.q[1] = sign; - return r; - } - - r.q[0] = r.q[1]; - r.q[1] = sign; - - v -= 64; - } - - if (v) { - r.q[0] = ((uint64)r.q[0] >> v) + (r.q[1] << (64 - v)); - r.q[1] >>= v; - } - - return r; - } - - const vduint128 vduint128::operator<<(int v) const { - vduint128 r; - - r.q[0] = q[0]; - r.q[1] = q[1]; - - if (v >= 64) { - if (v >= 128) { - r.q[0] = 0; - r.q[1] = 0; - return r; - } - - r.q[1] = r.q[0]; - r.q[0] = 0; - - v -= 64; - } - - if (v) { - r.q[1] = (r.q[1] << v) + (r.q[0] >> (64 - v)); - r.q[0] <<= v; - } - - return r; - } - - const vduint128 vduint128::operator>>(int v) const { - vduint128 r; - - r.q[0] = q[0]; - r.q[1] = q[1]; - - if (v >= 64) { - if (v >= 128) { - r.q[0] = 0; - r.q[1] = 0; - return r; - } - - r.q[0] = r.q[1]; - r.q[1] = 0; - - v -= 64; - } - - if (v) { - r.q[0] = (r.q[0] >> v) + (r.q[1] << (64 - v)); - r.q[1] >>= v; - } - - return r; - } -#endif - -const vdint128 vdint128::operator*(const vdint128& x) const { - vdint128 X = x.abs(); - vdint128 Y = abs(); - - vduint128 bd(VDUMul64x64To128(X.q[0], Y.q[0])); - - bd.q[1] += X.q[0]*Y.q[1] + X.q[1]*Y.q[0]; - - return (q[1]^x.q[1])<0 ? -vdint128(bd) : vdint128(bd); -} - -const vdint128 vdint128::operator/(int x) const { - vdint128 r; - sint64 accum; - - r.d[3] = d[3] / x; - - accum = ((sint64)(d[3] % x) << 32) + d[2]; - r.d[2] = (sint32)(accum / x); - - accum = ((accum % x) << 32) + d[1]; - r.d[1] = (sint32)(accum / x); - - accum = ((accum % x) << 32) + d[0]; - r.d[0] = (sint32)(accum / x); - - return r; -} - -vdint128::operator double() const { - return (double)(unsigned long)q[0] - + ldexp((double)(unsigned long)((unsigned __int64)q[0]>>32), 32) - + ldexp((double)q[1], 64); -} - -///////////////////////////////////////////////////////////////////////////// - -const vduint128 vduint128::operator*(const vduint128& x) const { - vduint128 result(VDUMul64x64To128(q[0], x.q[0])); - - result.q[1] += q[0]*x.q[1] + q[1]*x.q[0]; - - return result; -} - -#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - vduint128 __declspec(naked) __cdecl VDUMul64x64To128(uint64 x, uint64 y) { - __asm { - mov ecx,[esp+4] - - mov eax,[esp+8] - mul dword ptr [esp+16] ;EDX:EAX = BD - mov [ecx+0],eax - mov [ecx+4],edx - - mov eax,[esp+12] - mul dword ptr [esp+20] ;EDX:EAX = AC - mov [ecx+8],eax - mov [ecx+12],edx - - mov eax,[esp+8] - mul dword ptr [esp+20] ;EDX:EAX = BC - add [ecx+4],eax - adc [ecx+8],edx - adc dword ptr [ecx+12], 0 - - mov eax,[esp+12] - mul dword ptr [esp+16] ;EDX:EAX = AD - add [ecx+4],eax - adc [ecx+8],edx - adc dword ptr [ecx+12], 0 - - mov eax, ecx - ret - } - } -#elif !defined(VD_CPU_AMD64) - vduint128 VDUMul64x64To128(uint64 x, uint64 y) { - uint32 x0 = (uint32)x; - uint32 x1 = (uint32)(x >> 32); - uint32 y0 = (uint32)y; - uint32 y1 = (uint32)(y >> 32); - - uint64 m0 = (uint64)x0*y0; - uint64 m1a = (uint64)x1*y0; - uint64 m1b = (uint64)x0*y1; - uint64 m2 = (uint64)x1*y1; - - uint32 s0 = (uint32)m0; - uint32 s1a = (uint32)(m0 >> 32); - uint32 s1b = (uint32)m1a; - uint32 s1c = (uint32)m1b; - uint32 s2a = (uint32)(m1a >> 32); - uint32 s2b = (uint32)(m1b >> 32); - uint32 s2c = (uint32)m2; - uint32 s3 = (uint32)(m2 >> 32); - - vduint128 r; - r.d[0] = s0; - r.d[1] = s1a + s1b; - r.d[2] = r.d[1] < s1b; - r.d[1] += s1c; - r.d[2] += r.d[1] < s1c; - r.d[2] += s2a; - r.d[3] = r.d[2] < s2a; - r.d[2] += s2b; - r.d[3] += r.d[2] < s2b; - r.d[2] += s2c; - r.d[3] += r.d[2] < s2c; - r.d[3] += s3; - - return r; - } -#endif - -uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder) { - vduint128 temp(dividend); - vduint128 divisor2(divisor); - - divisor2 <<= 63; - - uint64 result = 0; - for(int i=0; i<64; ++i) { - result += result; - if (temp >= divisor2) { - temp -= divisor2; - ++result; - } - temp += temp; - } - - remainder = temp.q[1]; - - return result; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include + +#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + void __declspec(naked) __cdecl vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { + __asm { + push ebx + + mov ebx, [esp+16] + mov ecx, [esp+12] + mov edx, [esp+8] + + mov eax, [ecx+0] + add eax, [ebx+0] + mov [edx+0],eax + mov eax, [ecx+4] + adc eax, [ebx+4] + mov [edx+4],eax + mov eax, [ecx+8] + adc eax, [ebx+8] + mov [edx+8],eax + mov eax, [ecx+12] + adc eax, [ebx+12] + mov [edx+12],eax + + pop ebx + ret + } + } + + void __declspec(naked) __cdecl vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { + __asm { + push ebx + + mov ebx, [esp+16] + mov ecx, [esp+12] + mov edx, [esp+8] + + mov eax, [ecx+0] + sub eax, [ebx+0] + mov [edx+0],eax + mov eax, [ecx+4] + sbb eax, [ebx+4] + mov [edx+4],eax + mov eax, [ecx+8] + sbb eax, [ebx+8] + mov [edx+8],eax + mov eax, [ecx+12] + sbb eax, [ebx+12] + mov [edx+12],eax + + pop ebx + ret + } + } + + void __declspec(naked) vdint128::setSquare(sint64 v) { + __asm { + push edi + push esi + push ebx + mov eax, [esp+20] + cdq + mov esi, eax + mov eax, [esp+16] + xor eax, edx + xor esi, edx + sub eax, edx + sbb esi, edx + mov ebx, eax + mul eax + mov [ecx], eax + mov edi, edx + mov eax, ebx + mul esi + mov ebx, 0 + add eax, eax + adc edx, edx + add eax, edi + adc edx, 0 + mov edi, edx + adc ebx, 0 + mov [ecx+4], eax + mov eax, esi + mul esi + add eax, edi + adc edx, ebx + mov [ecx+8], eax + mov [ecx+12], edx + pop ebx + pop esi + pop edi + ret 8 + } + } + + const vdint128 __declspec(naked) vdint128::operator<<(int v) const { + __asm { + push ebp + push ebx + push esi + push edi + + mov esi,ecx + mov edx,[esp+20] + + mov ecx,[esp+24] + cmp ecx,128 + jae zeroit + + mov eax,[esi+12] + mov ebx,[esi+8] + mov edi,[esi+4] + mov ebp,[esi] + + dwordloop: + cmp ecx,32 + jb bits + + mov eax,ebx + mov ebx,edi + mov edi,ebp + xor ebp,ebp + sub ecx,32 + jmp short dwordloop + + bits: + shld eax,ebx,cl + shld ebx,edi,cl + mov [edx+12],eax + mov [edx+8],ebx + shld edi,ebp,cl + + shl ebp,cl + mov [edx+4],edi + mov [edx],ebp + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + + zeroit: + xor eax,eax + mov [edx+0],eax + mov [edx+4],eax + mov [edx+8],eax + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + } + } + + const vdint128 __declspec(naked) vdint128::operator>>(int v) const { + __asm { + push ebp + push ebx + push esi + push edi + + mov esi,ecx + mov edx,[esp+20] + + mov eax,[esi+12] + mov ecx,[esp+24] + cmp ecx,127 + jae clearit + + mov ebx,[esi+8] + mov edi,[esi+4] + mov ebp,[esi] + + dwordloop: + cmp ecx,32 + jb bits + + mov ebp,edi + mov edi,ebx + mov ebx,eax + sar eax,31 + sub ecx,32 + jmp short dwordloop + + bits: + shrd ebp,edi,cl + shrd edi,ebx,cl + mov [edx],ebp + mov [edx+4],edi + shrd ebx,eax,cl + + sar eax,cl + mov [edx+8],ebx + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + + clearit: + sar eax, 31 + mov [edx+0],eax + mov [edx+4],eax + mov [edx+8],eax + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + } + } + + const vduint128 __declspec(naked) vduint128::operator<<(int v) const { + __asm { + push ebp + push ebx + push esi + push edi + + mov esi,ecx + mov edx,[esp+20] + + mov ecx,[esp+24] + cmp ecx,128 + jae zeroit + + mov eax,[esi+12] + mov ebx,[esi+8] + mov edi,[esi+4] + mov ebp,[esi] + + dwordloop: + cmp ecx,32 + jb bits + + mov eax,ebx + mov ebx,edi + mov edi,ebp + xor ebp,ebp + sub ecx,32 + jmp short dwordloop + + bits: + shld eax,ebx,cl + shld ebx,edi,cl + mov [edx+12],eax + mov [edx+8],ebx + shld edi,ebp,cl + + shl ebp,cl + mov [edx+4],edi + mov [edx],ebp + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + + zeroit: + xor eax,eax + mov [edx+0],eax + mov [edx+4],eax + mov [edx+8],eax + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + } + } + + const vduint128 __declspec(naked) vduint128::operator>>(int v) const { + __asm { + push ebp + push ebx + push esi + push edi + + mov esi,ecx + mov edx,[esp+20] + + mov eax,[esi+12] + mov ecx,[esp+24] + cmp ecx,127 + jae clearit + + mov ebx,[esi+8] + mov edi,[esi+4] + mov ebp,[esi] + + dwordloop: + cmp ecx,32 + jb bits + + mov ebp,edi + mov edi,ebx + mov ebx,eax + xor eax,eax + sub ecx,32 + jmp short dwordloop + + bits: + shrd ebp,edi,cl + shrd edi,ebx,cl + mov [edx],ebp + mov [edx+4],edi + shrd ebx,eax,cl + + shr eax,cl + mov [edx+8],ebx + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + + clearit: + sar eax, 31 + mov [edx+0],eax + mov [edx+4],eax + mov [edx+8],eax + mov [edx+12],eax + + pop edi + pop esi + pop ebx + pop ebp + mov eax,[esp+4] + ret 8 + } + } + +#elif !defined(VD_CPU_AMD64) + + // These aren't really assembly routines, but we define them so we aren't asm dependent. + + void vdasm_uint128_add(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { + dst[0] = x[0] + y[0]; + dst[1] = x[1] + y[1] + (dst[0] < x[0]); + } + + void vdasm_uint128_sub(uint64 dst[2], const uint64 x[2], const uint64 y[2]) { + dst[0] = x[0] - y[0]; + dst[1] = x[1] - y[1] - (dst[0] > x[0]); + } + + void vdint128::setSquare(sint64 v) { + vdint128 r; + + uint32 u0 = (uint32)v; + uint32 u1 = (uint32)(v >> 32); + uint64 m0 = u0*u0; + uint64 m1 = u0*u1; // added twice + uint64 m2 = u1*u1; + uint32 s0 = (uint32)m0; + uint32 s1a = (uint32)(m0 >> 32); + uint32 s1b = (uint32)m1; + uint32 s2a = (uint32)(m1 >> 32); + + q[1] = m2 + s2a; + + d[0] = s0; + + d[1] = s1a + s1b; + if (d[1] < s1b) + ++q[1]; + + d[1] += s1b; + if (d[1] < s1b) + ++q[1]; + } + + const vdint128 vdint128::operator<<(int v) const { + vdint128 r; + + r.q[0] = q[0]; + r.q[1] = q[1]; + + if (v >= 64) { + if (v >= 128) { + r.q[0] = 0; + r.q[1] = 0; + return r; + } + + r.q[1] = r.q[0]; + r.q[0] = 0; + + v -= 64; + } + + if (v) { + r.q[1] = (r.q[1] << v) + ((uint64)r.q[0] >> (64 - v)); + r.q[0] <<= v; + } + + return r; + } + + const vdint128 vdint128::operator>>(int v) const { + vdint128 r; + + r.q[0] = q[0]; + r.q[1] = q[1]; + + if (v >= 64) { + sint64 sign = q[1] >> 63; + + if (v >= 128) { + r.q[0] = sign; + r.q[1] = sign; + return r; + } + + r.q[0] = r.q[1]; + r.q[1] = sign; + + v -= 64; + } + + if (v) { + r.q[0] = ((uint64)r.q[0] >> v) + (r.q[1] << (64 - v)); + r.q[1] >>= v; + } + + return r; + } + + const vduint128 vduint128::operator<<(int v) const { + vduint128 r; + + r.q[0] = q[0]; + r.q[1] = q[1]; + + if (v >= 64) { + if (v >= 128) { + r.q[0] = 0; + r.q[1] = 0; + return r; + } + + r.q[1] = r.q[0]; + r.q[0] = 0; + + v -= 64; + } + + if (v) { + r.q[1] = (r.q[1] << v) + (r.q[0] >> (64 - v)); + r.q[0] <<= v; + } + + return r; + } + + const vduint128 vduint128::operator>>(int v) const { + vduint128 r; + + r.q[0] = q[0]; + r.q[1] = q[1]; + + if (v >= 64) { + if (v >= 128) { + r.q[0] = 0; + r.q[1] = 0; + return r; + } + + r.q[0] = r.q[1]; + r.q[1] = 0; + + v -= 64; + } + + if (v) { + r.q[0] = (r.q[0] >> v) + (r.q[1] << (64 - v)); + r.q[1] >>= v; + } + + return r; + } +#endif + +const vdint128 vdint128::operator*(const vdint128& x) const { + vdint128 X = x.abs(); + vdint128 Y = abs(); + + vduint128 bd(VDUMul64x64To128(X.q[0], Y.q[0])); + + bd.q[1] += X.q[0]*Y.q[1] + X.q[1]*Y.q[0]; + + return (q[1]^x.q[1])<0 ? -vdint128(bd) : vdint128(bd); +} + +const vdint128 vdint128::operator/(int x) const { + vdint128 r; + sint64 accum; + + r.d[3] = d[3] / x; + + accum = ((sint64)(d[3] % x) << 32) + d[2]; + r.d[2] = (sint32)(accum / x); + + accum = ((accum % x) << 32) + d[1]; + r.d[1] = (sint32)(accum / x); + + accum = ((accum % x) << 32) + d[0]; + r.d[0] = (sint32)(accum / x); + + return r; +} + +vdint128::operator double() const { + return (double)(unsigned long)q[0] + + ldexp((double)(unsigned long)((unsigned __int64)q[0]>>32), 32) + + ldexp((double)q[1], 64); +} + +///////////////////////////////////////////////////////////////////////////// + +const vduint128 vduint128::operator*(const vduint128& x) const { + vduint128 result(VDUMul64x64To128(q[0], x.q[0])); + + result.q[1] += q[0]*x.q[1] + q[1]*x.q[0]; + + return result; +} + +#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + vduint128 __declspec(naked) __cdecl VDUMul64x64To128(uint64 x, uint64 y) { + __asm { + mov ecx,[esp+4] + + mov eax,[esp+8] + mul dword ptr [esp+16] ;EDX:EAX = BD + mov [ecx+0],eax + mov [ecx+4],edx + + mov eax,[esp+12] + mul dword ptr [esp+20] ;EDX:EAX = AC + mov [ecx+8],eax + mov [ecx+12],edx + + mov eax,[esp+8] + mul dword ptr [esp+20] ;EDX:EAX = BC + add [ecx+4],eax + adc [ecx+8],edx + adc dword ptr [ecx+12], 0 + + mov eax,[esp+12] + mul dword ptr [esp+16] ;EDX:EAX = AD + add [ecx+4],eax + adc [ecx+8],edx + adc dword ptr [ecx+12], 0 + + mov eax, ecx + ret + } + } +#elif !defined(VD_CPU_AMD64) + vduint128 VDUMul64x64To128(uint64 x, uint64 y) { + uint32 x0 = (uint32)x; + uint32 x1 = (uint32)(x >> 32); + uint32 y0 = (uint32)y; + uint32 y1 = (uint32)(y >> 32); + + uint64 m0 = (uint64)x0*y0; + uint64 m1a = (uint64)x1*y0; + uint64 m1b = (uint64)x0*y1; + uint64 m2 = (uint64)x1*y1; + + uint32 s0 = (uint32)m0; + uint32 s1a = (uint32)(m0 >> 32); + uint32 s1b = (uint32)m1a; + uint32 s1c = (uint32)m1b; + uint32 s2a = (uint32)(m1a >> 32); + uint32 s2b = (uint32)(m1b >> 32); + uint32 s2c = (uint32)m2; + uint32 s3 = (uint32)(m2 >> 32); + + vduint128 r; + r.d[0] = s0; + r.d[1] = s1a + s1b; + r.d[2] = r.d[1] < s1b; + r.d[1] += s1c; + r.d[2] += r.d[1] < s1c; + r.d[2] += s2a; + r.d[3] = r.d[2] < s2a; + r.d[2] += s2b; + r.d[3] += r.d[2] < s2b; + r.d[2] += s2c; + r.d[3] += r.d[2] < s2c; + r.d[3] += s3; + + return r; + } +#endif + +uint64 VDUDiv128x64To64(const vduint128& dividend, uint64 divisor, uint64& remainder) { + vduint128 temp(dividend); + vduint128 divisor2(divisor); + + divisor2 <<= 63; + + uint64 result = 0; + for(int i=0; i<64; ++i) { + result += result; + if (temp >= divisor2) { + temp -= divisor2; + ++result; + } + temp += temp; + } + + remainder = temp.q[1]; + + return result; +} diff --git a/src/thirdparty/VirtualDub/system/source/list.cpp b/src/thirdparty/VirtualDub/system/source/list.cpp index 91912c551de..bf443b6a6e7 100644 --- a/src/thirdparty/VirtualDub/system/source/list.cpp +++ b/src/thirdparty/VirtualDub/system/source/list.cpp @@ -1,97 +1,97 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -/////////////////////////////////////////////////////////////////////////// -// -// For those of you who say this looks familiar... it should. This is -// the same linked-list style that the Amiga Exec uses, with dummy head -// and tail nodes. It's really a very convienent way to implement -// doubly-linked lists. -// - -#include "stdafx.h" -#include -#include - -List::List() { - Init(); -} - -void List::Init() { - head.next = tail.prev = 0; - head.prev = &tail; - tail.next = &head; -} - -ListNode *List::RemoveHead() { - if (head.prev->prev) { - ListNode *t = head.prev; - - head.prev->Remove(); - return t; - } - - return 0; -} - -ListNode *List::RemoveTail() { - if (tail.next->next) { - ListNode *t = tail.next; - - tail.next->Remove(); - return t; - } - - return 0; -} - -void List::Take(List &from) { - if (from.IsEmpty()) - return; - - head.prev = from.head.prev; - tail.next = from.tail.next; - head.prev->next = &head; - tail.next->prev = &tail; - - from.Init(); -} - -void List::Swap(List &dst) { - if (IsEmpty()) - Take(dst); - else if (dst.IsEmpty()) - dst.Take(*this); - else { - std::swap(head.prev, dst.head.prev); - std::swap(tail.next, dst.tail.next); - - head.prev->next = &head; - tail.next->prev = &tail; - - dst.head.prev->next = &dst.head; - dst.tail.next->prev = &dst.tail; - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +/////////////////////////////////////////////////////////////////////////// +// +// For those of you who say this looks familiar... it should. This is +// the same linked-list style that the Amiga Exec uses, with dummy head +// and tail nodes. It's really a very convienent way to implement +// doubly-linked lists. +// + +#include "stdafx.h" +#include +#include + +List::List() { + Init(); +} + +void List::Init() { + head.next = tail.prev = 0; + head.prev = &tail; + tail.next = &head; +} + +ListNode *List::RemoveHead() { + if (head.prev->prev) { + ListNode *t = head.prev; + + head.prev->Remove(); + return t; + } + + return 0; +} + +ListNode *List::RemoveTail() { + if (tail.next->next) { + ListNode *t = tail.next; + + tail.next->Remove(); + return t; + } + + return 0; +} + +void List::Take(List &from) { + if (from.IsEmpty()) + return; + + head.prev = from.head.prev; + tail.next = from.tail.next; + head.prev->next = &head; + tail.next->prev = &tail; + + from.Init(); +} + +void List::Swap(List &dst) { + if (IsEmpty()) + Take(dst); + else if (dst.IsEmpty()) + dst.Take(*this); + else { + std::swap(head.prev, dst.head.prev); + std::swap(tail.next, dst.tail.next); + + head.prev->next = &head; + tail.next->prev = &tail; + + dst.head.prev->next = &dst.head; + dst.tail.next->prev = &dst.tail; + } +} diff --git a/src/thirdparty/VirtualDub/system/source/math.cpp b/src/thirdparty/VirtualDub/system/source/math.cpp index 53bde234a14..b3852cb1145 100644 --- a/src/thirdparty/VirtualDub/system/source/math.cpp +++ b/src/thirdparty/VirtualDub/system/source/math.cpp @@ -1,185 +1,185 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include - -int VDRoundToInt(double x) { - return (int)floor(x + 0.5); -} - -long VDRoundToLong(double x) { - return (long)floor(x + 0.5); -} - -sint32 VDRoundToInt32(double x) { - return (sint32)floor(x + 0.5); -} - -sint64 VDRoundToInt64(double x) { - return (sint64)floor(x + 0.5); -} - -#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - sint64 __declspec(naked) __stdcall VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder) { - __asm { - push edi - push ebx - mov edi, [esp+12+8] ;edi = b - mov eax, [esp+4+8] ;eax = a[lo] - mul edi ;edx:eax = a[lo]*b - mov ecx, eax ;ecx = (a*b)[lo] - mov eax, [esp+8+8] ;eax = a[hi] - mov ebx, edx ;ebx = (a*b)[mid] - mul edi ;edx:eax = a[hi]*b - add eax, ebx - mov ebx, [esp+16+8] ;ebx = c - adc edx, 0 - div ebx ;eax = (a*b)/c [hi], edx = (a[hi]*b)%c - mov edi, eax ;edi = (a[hi]*b)/c - mov eax, ecx ;eax = (a*b)[lo] - mov ecx, [esp+20+8] - div ebx ;eax = (a*b)/c [lo], edx = (a*b)%c - mov [ecx], edx - mov edx, edi - pop ebx - pop edi - ret 20 - } - } - - uint64 __declspec(naked) __stdcall VDUMulDiv64x32(uint64 a, uint32 b, uint32 c) { - __asm { - mov eax, [esp+4] ;eax = a0 - mul dword ptr [esp+12] ;edx:eax = a0*b - mov dword ptr [esp+4], eax ;tmp = a0*b[0:31] - mov ecx, edx ;ecx = a0*b[32:63] - mov eax, [esp+8] ;eax = a1 - mul dword ptr [esp+12] ;edx:eax = a1*b - add eax, ecx ;edx:eax += a0*b[32:95] - adc edx, 0 ;(cont.) - cmp edx, [esp+16] ;test if a*b[64:95] >= c; equiv to a*b >= (c<<64) - jae invalid ;abort if so (overflow) - div dword ptr [esp+16] ;edx,eax = ((a*b)[32:95]/c, (a*b)[32:95]%c) - mov ecx, eax - mov eax, [esp+4] - div dword ptr [esp+16] - mov edx, ecx - ret 16 -invalid: - mov eax, -1 ;return FFFFFFFFFFFFFFFF - mov edx, -1 - ret 16 - } - } -#elif !defined(VD_CPU_AMD64) - sint64 VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder) { - uint32 a0 = (uint32)a; - uint32 a1 = (uint32)(a >> 32); - - uint64 m0 = (uint64)a0*b; - uint64 m1 = (uint64)a1*b; - - // collect all multiplier terms - uint32 s0 = (uint32)m0; - uint32 s1a = (uint32)(m0 >> 32); - uint32 s1b = (uint32)m1; - uint32 s2 = (uint32)(m1 >> 32); - - // form 96-bit intermediate product - uint32 acc0 = s0; - uint32 acc1 = s1a + s1b; - uint32 acc2 = s2 + (acc1 < s1b); - - // check for overflow (or divide by zero) - if (acc2 >= c) - return 0xFFFFFFFFFFFFFFFFULL; - - // do divide - uint64 div1 = ((uint64)acc2 << 32) + acc1; - uint64 q1 = div1 / c; - uint64 div0 = ((div1 % c) << 32) + acc0; - uint32 q0 = (uint32)(div0 / c); - - remainder = (uint32)(div0 % c); - - return (q1 << 32) + q0; - } - - uint64 VDUMulDiv64x32(uint64 a, uint32 b, uint32 c) { - uint32 r; - - return VDFractionScale64(a, b, c, r); - } -#endif - -sint64 VDMulDiv64(sint64 a, sint64 b, sint64 c) { - bool flip = false; - - if (a < 0) { - a = -a; - flip = true; - } - - if (b < 0) { - b = -b; - flip = !flip; - } - - if (c < 0) { - c = -c; - flip = !flip; - } - - uint64 rem; - uint64 v = VDUDiv128x64To64(VDUMul64x64To128((uint64)a, (uint64)b), (uint64)c, rem); - - if ((rem+rem) >= (uint64)c) - ++v; - - return flip ? -(sint64)v : (sint64)v; -} - -bool VDVerifyFiniteFloats(const float *p0, uint32 n) { - const uint32 *p = (const uint32 *)p0; - - while(n--) { - uint32 v = *p++; - - // 00000000 zero - // 00000001-007FFFFF denormal - // 00800000-7F7FFFFF finite - // 7F800000 infinity - // 7F800001-7FBFFFFF SNaN - // 7FC00000-7FFFFFFF QNaN - - if ((v & 0x7FFFFFFF) >= 0x7F800000) - return false; - } - - return true; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include + +int VDRoundToInt(double x) { + return (int)floor(x + 0.5); +} + +long VDRoundToLong(double x) { + return (long)floor(x + 0.5); +} + +sint32 VDRoundToInt32(double x) { + return (sint32)floor(x + 0.5); +} + +sint64 VDRoundToInt64(double x) { + return (sint64)floor(x + 0.5); +} + +#if defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + sint64 __declspec(naked) __stdcall VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder) { + __asm { + push edi + push ebx + mov edi, [esp+12+8] ;edi = b + mov eax, [esp+4+8] ;eax = a[lo] + mul edi ;edx:eax = a[lo]*b + mov ecx, eax ;ecx = (a*b)[lo] + mov eax, [esp+8+8] ;eax = a[hi] + mov ebx, edx ;ebx = (a*b)[mid] + mul edi ;edx:eax = a[hi]*b + add eax, ebx + mov ebx, [esp+16+8] ;ebx = c + adc edx, 0 + div ebx ;eax = (a*b)/c [hi], edx = (a[hi]*b)%c + mov edi, eax ;edi = (a[hi]*b)/c + mov eax, ecx ;eax = (a*b)[lo] + mov ecx, [esp+20+8] + div ebx ;eax = (a*b)/c [lo], edx = (a*b)%c + mov [ecx], edx + mov edx, edi + pop ebx + pop edi + ret 20 + } + } + + uint64 __declspec(naked) __stdcall VDUMulDiv64x32(uint64 a, uint32 b, uint32 c) { + __asm { + mov eax, [esp+4] ;eax = a0 + mul dword ptr [esp+12] ;edx:eax = a0*b + mov dword ptr [esp+4], eax ;tmp = a0*b[0:31] + mov ecx, edx ;ecx = a0*b[32:63] + mov eax, [esp+8] ;eax = a1 + mul dword ptr [esp+12] ;edx:eax = a1*b + add eax, ecx ;edx:eax += a0*b[32:95] + adc edx, 0 ;(cont.) + cmp edx, [esp+16] ;test if a*b[64:95] >= c; equiv to a*b >= (c<<64) + jae invalid ;abort if so (overflow) + div dword ptr [esp+16] ;edx,eax = ((a*b)[32:95]/c, (a*b)[32:95]%c) + mov ecx, eax + mov eax, [esp+4] + div dword ptr [esp+16] + mov edx, ecx + ret 16 +invalid: + mov eax, -1 ;return FFFFFFFFFFFFFFFF + mov edx, -1 + ret 16 + } + } +#elif !defined(VD_CPU_AMD64) + sint64 VDFractionScale64(uint64 a, uint32 b, uint32 c, uint32& remainder) { + uint32 a0 = (uint32)a; + uint32 a1 = (uint32)(a >> 32); + + uint64 m0 = (uint64)a0*b; + uint64 m1 = (uint64)a1*b; + + // collect all multiplier terms + uint32 s0 = (uint32)m0; + uint32 s1a = (uint32)(m0 >> 32); + uint32 s1b = (uint32)m1; + uint32 s2 = (uint32)(m1 >> 32); + + // form 96-bit intermediate product + uint32 acc0 = s0; + uint32 acc1 = s1a + s1b; + uint32 acc2 = s2 + (acc1 < s1b); + + // check for overflow (or divide by zero) + if (acc2 >= c) + return 0xFFFFFFFFFFFFFFFFULL; + + // do divide + uint64 div1 = ((uint64)acc2 << 32) + acc1; + uint64 q1 = div1 / c; + uint64 div0 = ((div1 % c) << 32) + acc0; + uint32 q0 = (uint32)(div0 / c); + + remainder = (uint32)(div0 % c); + + return (q1 << 32) + q0; + } + + uint64 VDUMulDiv64x32(uint64 a, uint32 b, uint32 c) { + uint32 r; + + return VDFractionScale64(a, b, c, r); + } +#endif + +sint64 VDMulDiv64(sint64 a, sint64 b, sint64 c) { + bool flip = false; + + if (a < 0) { + a = -a; + flip = true; + } + + if (b < 0) { + b = -b; + flip = !flip; + } + + if (c < 0) { + c = -c; + flip = !flip; + } + + uint64 rem; + uint64 v = VDUDiv128x64To64(VDUMul64x64To128((uint64)a, (uint64)b), (uint64)c, rem); + + if ((rem+rem) >= (uint64)c) + ++v; + + return flip ? -(sint64)v : (sint64)v; +} + +bool VDVerifyFiniteFloats(const float *p0, uint32 n) { + const uint32 *p = (const uint32 *)p0; + + while(n--) { + uint32 v = *p++; + + // 00000000 zero + // 00000001-007FFFFF denormal + // 00800000-7F7FFFFF finite + // 7F800000 infinity + // 7F800001-7FBFFFFF SNaN + // 7FC00000-7FFFFFFF QNaN + + if ((v & 0x7FFFFFFF) >= 0x7F800000) + return false; + } + + return true; +} diff --git a/src/thirdparty/VirtualDub/system/source/memory.cpp b/src/thirdparty/VirtualDub/system/source/memory.cpp index 5143bddefa0..911d3f4b128 100644 --- a/src/thirdparty/VirtualDub/system/source/memory.cpp +++ b/src/thirdparty/VirtualDub/system/source/memory.cpp @@ -1,472 +1,472 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include -#include -#include -#include - -void *VDAlignedMalloc(size_t n, unsigned alignment) { -#ifdef VD_COMPILER_MSVC - return _aligned_malloc(n, alignment); -#else - void *p = malloc(n + sizeof(void *) + alignment - 1); - - if (p) { - void *alignedp = (void *)(((uintptr)p + sizeof(void *) + alignment - 1) & ~((uintptr)alignment - 1)); - - ((void **)alignedp)[-1] = p; - p = alignedp; - } - - return p; -#endif -} - -void VDAlignedFree(void *p) { -#ifdef VD_COMPILER_MSVC - _aligned_free(p); -#else - free(((void **)p)[-1]); -#endif -} - -void *VDAlignedVirtualAlloc(size_t n) { - return VirtualAlloc(NULL, n, MEM_COMMIT, PAGE_READWRITE); -} - -void VDAlignedVirtualFree(void *p) { - VirtualFree(p, 0, MEM_RELEASE); -} - -void VDSwapMemoryScalar(void *p0, void *p1, size_t bytes) { - uint32 *dst0 = (uint32 *)p0; - uint32 *dst1 = (uint32 *)p1; - - while(bytes >= 4) { - uint32 a = *dst0; - uint32 b = *dst1; - - *dst0++ = b; - *dst1++ = a; - - bytes -= 4; - } - - char *dstb0 = (char *)dst0; - char *dstb1 = (char *)dst1; - - while(bytes--) { - char a = *dstb0; - char b = *dstb1; - - *dstb0++ = b; - *dstb1++ = a; - } -} - -#if defined(VD_CPU_AMD64) || defined(VD_CPU_X86) - void VDSwapMemorySSE(void *p0, void *p1, size_t bytes) { - if (((uint32)(size_t)p0 | (uint32)(size_t)p1) & 15) - return VDSwapMemoryScalar(p0, p1, bytes); - - __m128 *pv0 = (__m128 *)p0; - __m128 *pv1 = (__m128 *)p1; - - size_t veccount = bytes >> 4; - if (veccount) { - do { - __m128 v0 = *pv0; - __m128 v1 = *pv1; - - *pv0++ = v1; - *pv1++ = v0; - } while(--veccount); - } - - uint32 left = bytes & 15; - if (left) { - uint8 *pb0 = (uint8 *)pv0; - uint8 *pb1 = (uint8 *)pv1; - do { - uint8 b0 = *pb0; - uint8 b1 = *pb1; - - *pb0++ = b1; - *pb1++ = b0; - } while(--left); - } - } -#endif - -void (__cdecl *VDSwapMemory)(void *p0, void *p1, size_t bytes) = VDSwapMemoryScalar; - -void VDInvertMemory(void *p, unsigned bytes) { - char *dst = (char *)p; - - if (!bytes) - return; - - while((int)dst & 3) { - *dst = ~*dst; - ++dst; - - if (!--bytes) - return; - } - - unsigned lcount = bytes >> 2; - - if (lcount) - do { - *(long *)dst = ~*(long *)dst; - dst += 4; - } while(--lcount); - - bytes &= 3; - - while(bytes--) { - *dst = ~*dst; - ++dst; - } -} - -namespace { - uintptr VDGetSystemPageSizeW32() { - SYSTEM_INFO sysInfo; - GetSystemInfo(&sysInfo); - - return sysInfo.dwPageSize; - } - - uintptr VDGetSystemPageSize() { - static uintptr pageSize = VDGetSystemPageSizeW32(); - - return pageSize; - } -} - -bool VDIsValidReadRegion(const void *p0, size_t bytes) { - if (!bytes) - return true; - - if (!p0) - return false; - - uintptr pageSize = VDGetSystemPageSize(); - uintptr p = (uintptr)p0; - uintptr pLimit = p + (bytes-1); - - vd_seh_guard_try { - for(;;) { - *(volatile char *)p; - - if (pLimit - p < pageSize) - break; - - p += pageSize; - } - } vd_seh_guard_except { - return false; - } - - return true; -} - -bool VDIsValidWriteRegion(void *p0, size_t bytes) { - if (!bytes) - return true; - - if (!p0) - return false; - - // Note: Unlike IsValidWritePtr(), this is threadsafe. - - uintptr pageSize = VDGetSystemPageSize(); - uintptr p = (uintptr)p0; - uintptr pLimit = p + (bytes-1); - p &= ~(uintptr)3; - - vd_seh_guard_try { - - for(;;) { - VDAtomicInt::staticCompareExchange((volatile int *)p, 0xa5, 0xa5); - - if (pLimit - p < pageSize) - break; - - p += pageSize; - } - } vd_seh_guard_except { - return false; - } - - return true; -} - -bool VDCompareRect(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, size_t w, size_t h) { - if (!w || !h) - return false; - - do { - if (memcmp(dst, src, w)) - return true; - - dst = (char *)dst + dstpitch; - src = (const char *)src + srcpitch; - } while(--h); - - return false; -} - -const void *VDMemCheck8(const void *src, uint8 value, size_t count) { - if (count) { - const uint8 *src8 = (const uint8 *)src; - - do { - if (*src8 != value) - return src8; - - ++src8; - } while(--count); - } - - return NULL; -} - -void VDMemset8(void *dst, uint8 value, size_t count) { - if (count) { - uint8 *dst2 = (uint8 *)dst; - - do { - *dst2++ = value; - } while(--count); - } -} - -void VDMemset16(void *dst, uint16 value, size_t count) { - if (count) { - uint16 *dst2 = (uint16 *)dst; - - do { - *dst2++ = value; - } while(--count); - } -} - -void VDMemset24(void *dst, uint32 value, size_t count) { - if (count) { - uint8 *dst2 = (uint8 *)dst; - uint8 c0 = (uint8)value; - uint8 c1 = (uint8)(value >> 8); - uint8 c2 = (uint8)(value >> 16); - - do { - *dst2++ = c0; - *dst2++ = c1; - *dst2++ = c2; - } while(--count); - } -} - -void VDMemset32(void *dst, uint32 value, size_t count) { - if (count) { - uint32 *dst2 = (uint32 *)dst; - - do { - *dst2++ = value; - } while(--count); - } -} - -void VDMemset64(void *dst, uint64 value, size_t count) { - if (count) { - uint64 *dst2 = (uint64 *)dst; - - do { - *dst2++ = value; - } while(--count); - } -} - -void VDMemset128(void *dst, const void *src0, size_t count) { - if (count) { - const uint32 *src = (const uint32 *)src0; - uint32 a0 = src[0]; - uint32 a1 = src[1]; - uint32 a2 = src[2]; - uint32 a3 = src[3]; - - uint32 *dst2 = (uint32 *)dst; - - do { - dst2[0] = a0; - dst2[1] = a1; - dst2[2] = a2; - dst2[3] = a3; - dst2 += 4; - } while(--count); - } -} - -void VDMemsetPointer(void *dst, const void *value, size_t count) { -#if defined(VD_CPU_X86) || defined(VD_CPU_ARM) - VDMemset32(dst, (uint32)(size_t)value, count); -#elif defined(VD_CPU_AMD64) - VDMemset64(dst, (uint64)(size_t)value, count); -#else - #error Unknown pointer size -#endif -} - -void VDMemset8Rect(void *dst, ptrdiff_t pitch, uint8 value, size_t w, size_t h) { - if (w>0 && h>0) { - do { - memset(dst, value, w); - dst = (char *)dst + pitch; - } while(--h); - } -} - -void VDMemset16Rect(void *dst, ptrdiff_t pitch, uint16 value, size_t w, size_t h) { - if (w>0 && h>0) { - do { - VDMemset16(dst, value, w); - dst = (char *)dst + pitch; - } while(--h); - } -} - -void VDMemset24Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h) { - if (w>0 && h>0) { - do { - VDMemset24(dst, value, w); - dst = (char *)dst + pitch; - } while(--h); - } -} - -void VDMemset32Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h) { - if (w>0 && h>0) { - do { - VDMemset32(dst, value, w); - dst = (char *)dst + pitch; - } while(--h); - } -} - -#if defined(_WIN32) && defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) - extern "C" void __cdecl VDFastMemcpyPartialScalarAligned8(void *dst, const void *src, size_t bytes); - extern "C" void __cdecl VDFastMemcpyPartialMMX(void *dst, const void *src, size_t bytes); - extern "C" void __cdecl VDFastMemcpyPartialMMX2(void *dst, const void *src, size_t bytes); - extern "C" void __cdecl VDFastMemcpyPartialSSE2(void *dst, const void *src, size_t bytes); //MPC custom code - - void VDFastMemcpyPartialScalar(void *dst, const void *src, size_t bytes) { - if (!(((int)dst | (int)src | bytes) & 7)) - VDFastMemcpyPartialScalarAligned8(dst, src, bytes); - else - memcpy(dst, src, bytes); - } - - void VDFastMemcpyFinishScalar() { - } - - void __cdecl VDFastMemcpyFinishMMX() { - _mm_empty(); - } - - void __cdecl VDFastMemcpyFinishMMX2() { - _mm_empty(); - _mm_sfence(); - } - - void (__cdecl *VDFastMemcpyPartial)(void *dst, const void *src, size_t bytes) = VDFastMemcpyPartialScalar; - void (__cdecl *VDFastMemcpyFinish)() = VDFastMemcpyFinishScalar; - - void VDFastMemcpyAutodetect() { - long exts = CPUGetEnabledExtensions(); - - if (exts & CPUF_SUPPORTS_SSE) { - VDFastMemcpyPartial = VDFastMemcpyPartialMMX2; - VDFastMemcpyFinish = VDFastMemcpyFinishMMX2; - VDSwapMemory = VDSwapMemorySSE; - } else if (exts & CPUF_SUPPORTS_INTEGER_SSE) { - VDFastMemcpyPartial = VDFastMemcpyPartialMMX2; - VDFastMemcpyFinish = VDFastMemcpyFinishMMX2; - VDSwapMemory = VDSwapMemoryScalar; - } else if (exts & CPUF_SUPPORTS_MMX) { - VDFastMemcpyPartial = VDFastMemcpyPartialMMX; - VDFastMemcpyFinish = VDFastMemcpyFinishMMX; - VDSwapMemory = VDSwapMemoryScalar; - } else { - VDFastMemcpyPartial = VDFastMemcpyPartialScalar; - VDFastMemcpyFinish = VDFastMemcpyFinishScalar; - VDSwapMemory = VDSwapMemoryScalar; - } - } - -#else - void VDFastMemcpyPartial(void *dst, const void *src, size_t bytes) { - memcpy(dst, src, bytes); - } - - void VDFastMemcpyFinish() { - } - - void VDFastMemcpyAutodetect() { - } -#endif - -void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h) { - if (w <= 0 || h <= 0) - return; - - if (w == srcstride && w == dststride) - VDFastMemcpyPartial(dst, src, w*h); - else { - char *dst2 = (char *)dst; - const char *src2 = (const char *)src; - - do { - VDFastMemcpyPartial(dst2, src2, w); - dst2 += dststride; - src2 += srcstride; - } while(--h); - } - VDFastMemcpyFinish(); -} - -bool VDMemcpyGuarded(void *dst, const void *src, size_t bytes) { - vd_seh_guard_try { - memcpy(dst, src, bytes); - } vd_seh_guard_except { - return false; - } - - return true; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include + +void *VDAlignedMalloc(size_t n, unsigned alignment) { +#ifdef VD_COMPILER_MSVC + return _aligned_malloc(n, alignment); +#else + void *p = malloc(n + sizeof(void *) + alignment - 1); + + if (p) { + void *alignedp = (void *)(((uintptr)p + sizeof(void *) + alignment - 1) & ~((uintptr)alignment - 1)); + + ((void **)alignedp)[-1] = p; + p = alignedp; + } + + return p; +#endif +} + +void VDAlignedFree(void *p) { +#ifdef VD_COMPILER_MSVC + _aligned_free(p); +#else + free(((void **)p)[-1]); +#endif +} + +void *VDAlignedVirtualAlloc(size_t n) { + return VirtualAlloc(NULL, n, MEM_COMMIT, PAGE_READWRITE); +} + +void VDAlignedVirtualFree(void *p) { + VirtualFree(p, 0, MEM_RELEASE); +} + +void VDSwapMemoryScalar(void *p0, void *p1, size_t bytes) { + uint32 *dst0 = (uint32 *)p0; + uint32 *dst1 = (uint32 *)p1; + + while(bytes >= 4) { + uint32 a = *dst0; + uint32 b = *dst1; + + *dst0++ = b; + *dst1++ = a; + + bytes -= 4; + } + + char *dstb0 = (char *)dst0; + char *dstb1 = (char *)dst1; + + while(bytes--) { + char a = *dstb0; + char b = *dstb1; + + *dstb0++ = b; + *dstb1++ = a; + } +} + +#if defined(VD_CPU_AMD64) || defined(VD_CPU_X86) + void VDSwapMemorySSE(void *p0, void *p1, size_t bytes) { + if (((uint32)(size_t)p0 | (uint32)(size_t)p1) & 15) + return VDSwapMemoryScalar(p0, p1, bytes); + + __m128 *pv0 = (__m128 *)p0; + __m128 *pv1 = (__m128 *)p1; + + size_t veccount = bytes >> 4; + if (veccount) { + do { + __m128 v0 = *pv0; + __m128 v1 = *pv1; + + *pv0++ = v1; + *pv1++ = v0; + } while(--veccount); + } + + uint32 left = bytes & 15; + if (left) { + uint8 *pb0 = (uint8 *)pv0; + uint8 *pb1 = (uint8 *)pv1; + do { + uint8 b0 = *pb0; + uint8 b1 = *pb1; + + *pb0++ = b1; + *pb1++ = b0; + } while(--left); + } + } +#endif + +void (__cdecl *VDSwapMemory)(void *p0, void *p1, size_t bytes) = VDSwapMemoryScalar; + +void VDInvertMemory(void *p, unsigned bytes) { + char *dst = (char *)p; + + if (!bytes) + return; + + while((int)dst & 3) { + *dst = ~*dst; + ++dst; + + if (!--bytes) + return; + } + + unsigned lcount = bytes >> 2; + + if (lcount) + do { + *(long *)dst = ~*(long *)dst; + dst += 4; + } while(--lcount); + + bytes &= 3; + + while(bytes--) { + *dst = ~*dst; + ++dst; + } +} + +namespace { + uintptr VDGetSystemPageSizeW32() { + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + + return sysInfo.dwPageSize; + } + + uintptr VDGetSystemPageSize() { + static uintptr pageSize = VDGetSystemPageSizeW32(); + + return pageSize; + } +} + +bool VDIsValidReadRegion(const void *p0, size_t bytes) { + if (!bytes) + return true; + + if (!p0) + return false; + + uintptr pageSize = VDGetSystemPageSize(); + uintptr p = (uintptr)p0; + uintptr pLimit = p + (bytes-1); + + vd_seh_guard_try { + for(;;) { + *(volatile char *)p; + + if (pLimit - p < pageSize) + break; + + p += pageSize; + } + } vd_seh_guard_except { + return false; + } + + return true; +} + +bool VDIsValidWriteRegion(void *p0, size_t bytes) { + if (!bytes) + return true; + + if (!p0) + return false; + + // Note: Unlike IsValidWritePtr(), this is threadsafe. + + uintptr pageSize = VDGetSystemPageSize(); + uintptr p = (uintptr)p0; + uintptr pLimit = p + (bytes-1); + p &= ~(uintptr)3; + + vd_seh_guard_try { + + for(;;) { + VDAtomicInt::staticCompareExchange((volatile int *)p, 0xa5, 0xa5); + + if (pLimit - p < pageSize) + break; + + p += pageSize; + } + } vd_seh_guard_except { + return false; + } + + return true; +} + +bool VDCompareRect(void *dst, ptrdiff_t dstpitch, const void *src, ptrdiff_t srcpitch, size_t w, size_t h) { + if (!w || !h) + return false; + + do { + if (memcmp(dst, src, w)) + return true; + + dst = (char *)dst + dstpitch; + src = (const char *)src + srcpitch; + } while(--h); + + return false; +} + +const void *VDMemCheck8(const void *src, uint8 value, size_t count) { + if (count) { + const uint8 *src8 = (const uint8 *)src; + + do { + if (*src8 != value) + return src8; + + ++src8; + } while(--count); + } + + return NULL; +} + +void VDMemset8(void *dst, uint8 value, size_t count) { + if (count) { + uint8 *dst2 = (uint8 *)dst; + + do { + *dst2++ = value; + } while(--count); + } +} + +void VDMemset16(void *dst, uint16 value, size_t count) { + if (count) { + uint16 *dst2 = (uint16 *)dst; + + do { + *dst2++ = value; + } while(--count); + } +} + +void VDMemset24(void *dst, uint32 value, size_t count) { + if (count) { + uint8 *dst2 = (uint8 *)dst; + uint8 c0 = (uint8)value; + uint8 c1 = (uint8)(value >> 8); + uint8 c2 = (uint8)(value >> 16); + + do { + *dst2++ = c0; + *dst2++ = c1; + *dst2++ = c2; + } while(--count); + } +} + +void VDMemset32(void *dst, uint32 value, size_t count) { + if (count) { + uint32 *dst2 = (uint32 *)dst; + + do { + *dst2++ = value; + } while(--count); + } +} + +void VDMemset64(void *dst, uint64 value, size_t count) { + if (count) { + uint64 *dst2 = (uint64 *)dst; + + do { + *dst2++ = value; + } while(--count); + } +} + +void VDMemset128(void *dst, const void *src0, size_t count) { + if (count) { + const uint32 *src = (const uint32 *)src0; + uint32 a0 = src[0]; + uint32 a1 = src[1]; + uint32 a2 = src[2]; + uint32 a3 = src[3]; + + uint32 *dst2 = (uint32 *)dst; + + do { + dst2[0] = a0; + dst2[1] = a1; + dst2[2] = a2; + dst2[3] = a3; + dst2 += 4; + } while(--count); + } +} + +void VDMemsetPointer(void *dst, const void *value, size_t count) { +#if defined(VD_CPU_X86) || defined(VD_CPU_ARM) + VDMemset32(dst, (uint32)(size_t)value, count); +#elif defined(VD_CPU_AMD64) + VDMemset64(dst, (uint64)(size_t)value, count); +#else + #error Unknown pointer size +#endif +} + +void VDMemset8Rect(void *dst, ptrdiff_t pitch, uint8 value, size_t w, size_t h) { + if (w>0 && h>0) { + do { + memset(dst, value, w); + dst = (char *)dst + pitch; + } while(--h); + } +} + +void VDMemset16Rect(void *dst, ptrdiff_t pitch, uint16 value, size_t w, size_t h) { + if (w>0 && h>0) { + do { + VDMemset16(dst, value, w); + dst = (char *)dst + pitch; + } while(--h); + } +} + +void VDMemset24Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h) { + if (w>0 && h>0) { + do { + VDMemset24(dst, value, w); + dst = (char *)dst + pitch; + } while(--h); + } +} + +void VDMemset32Rect(void *dst, ptrdiff_t pitch, uint32 value, size_t w, size_t h) { + if (w>0 && h>0) { + do { + VDMemset32(dst, value, w); + dst = (char *)dst + pitch; + } while(--h); + } +} + +#if defined(_WIN32) && defined(VD_CPU_X86) && defined(VD_COMPILER_MSVC) + extern "C" void __cdecl VDFastMemcpyPartialScalarAligned8(void *dst, const void *src, size_t bytes); + extern "C" void __cdecl VDFastMemcpyPartialMMX(void *dst, const void *src, size_t bytes); + extern "C" void __cdecl VDFastMemcpyPartialMMX2(void *dst, const void *src, size_t bytes); + extern "C" void __cdecl VDFastMemcpyPartialSSE2(void *dst, const void *src, size_t bytes); //MPC custom code + + void VDFastMemcpyPartialScalar(void *dst, const void *src, size_t bytes) { + if (!(((int)dst | (int)src | bytes) & 7)) + VDFastMemcpyPartialScalarAligned8(dst, src, bytes); + else + memcpy(dst, src, bytes); + } + + void VDFastMemcpyFinishScalar() { + } + + void __cdecl VDFastMemcpyFinishMMX() { + _mm_empty(); + } + + void __cdecl VDFastMemcpyFinishMMX2() { + _mm_empty(); + _mm_sfence(); + } + + void (__cdecl *VDFastMemcpyPartial)(void *dst, const void *src, size_t bytes) = VDFastMemcpyPartialScalar; + void (__cdecl *VDFastMemcpyFinish)() = VDFastMemcpyFinishScalar; + + void VDFastMemcpyAutodetect() { + long exts = CPUGetEnabledExtensions(); + + if (exts & CPUF_SUPPORTS_SSE) { + VDFastMemcpyPartial = VDFastMemcpyPartialMMX2; + VDFastMemcpyFinish = VDFastMemcpyFinishMMX2; + VDSwapMemory = VDSwapMemorySSE; + } else if (exts & CPUF_SUPPORTS_INTEGER_SSE) { + VDFastMemcpyPartial = VDFastMemcpyPartialMMX2; + VDFastMemcpyFinish = VDFastMemcpyFinishMMX2; + VDSwapMemory = VDSwapMemoryScalar; + } else if (exts & CPUF_SUPPORTS_MMX) { + VDFastMemcpyPartial = VDFastMemcpyPartialMMX; + VDFastMemcpyFinish = VDFastMemcpyFinishMMX; + VDSwapMemory = VDSwapMemoryScalar; + } else { + VDFastMemcpyPartial = VDFastMemcpyPartialScalar; + VDFastMemcpyFinish = VDFastMemcpyFinishScalar; + VDSwapMemory = VDSwapMemoryScalar; + } + } + +#else + void VDFastMemcpyPartial(void *dst, const void *src, size_t bytes) { + memcpy(dst, src, bytes); + } + + void VDFastMemcpyFinish() { + } + + void VDFastMemcpyAutodetect() { + } +#endif + +void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h) { + if (w <= 0 || h <= 0) + return; + + if (w == srcstride && w == dststride) + VDFastMemcpyPartial(dst, src, w*h); + else { + char *dst2 = (char *)dst; + const char *src2 = (const char *)src; + + do { + VDFastMemcpyPartial(dst2, src2, w); + dst2 += dststride; + src2 += srcstride; + } while(--h); + } + VDFastMemcpyFinish(); +} + +bool VDMemcpyGuarded(void *dst, const void *src, size_t bytes) { + vd_seh_guard_try { + memcpy(dst, src, bytes); + } vd_seh_guard_except { + return false; + } + + return true; +} diff --git a/src/thirdparty/VirtualDub/system/source/progress.cpp b/src/thirdparty/VirtualDub/system/source/progress.cpp index 64075f40314..1ac26a0f65f 100644 --- a/src/thirdparty/VirtualDub/system/source/progress.cpp +++ b/src/thirdparty/VirtualDub/system/source/progress.cpp @@ -1,35 +1,35 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include -#include -#include -#include -#include - +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +#include +#include +#include +#include +#include + diff --git a/src/thirdparty/VirtualDub/system/source/protscope.cpp b/src/thirdparty/VirtualDub/system/source/protscope.cpp index cc7092c3a4a..61208282418 100644 --- a/src/thirdparty/VirtualDub/system/source/protscope.cpp +++ b/src/thirdparty/VirtualDub/system/source/protscope.cpp @@ -1,37 +1,37 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -VDProtectedAutoScope *VDGetProtectedScopeLinkNull() { - return NULL; -} - -void VDSetProtectedScopeLinkNull(VDProtectedAutoScope *) { -} - -tpVDGetProtectedScopeLink g_pVDGetProtectedScopeLink = VDGetProtectedScopeLinkNull; -tpVDSetProtectedScopeLink g_pVDSetProtectedScopeLink = VDSetProtectedScopeLinkNull; +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +VDProtectedAutoScope *VDGetProtectedScopeLinkNull() { + return NULL; +} + +void VDSetProtectedScopeLinkNull(VDProtectedAutoScope *) { +} + +tpVDGetProtectedScopeLink g_pVDGetProtectedScopeLink = VDGetProtectedScopeLinkNull; +tpVDSetProtectedScopeLink g_pVDSetProtectedScopeLink = VDSetProtectedScopeLinkNull; diff --git a/src/thirdparty/VirtualDub/system/source/refcount.cpp b/src/thirdparty/VirtualDub/system/source/refcount.cpp index 4dcf5d08cd7..f0d82760a81 100644 --- a/src/thirdparty/VirtualDub/system/source/refcount.cpp +++ b/src/thirdparty/VirtualDub/system/source/refcount.cpp @@ -1,29 +1,29 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2009 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -vdsaferelease_t vdsaferelease; +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2009 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +vdsaferelease_t vdsaferelease; diff --git a/src/thirdparty/VirtualDub/system/source/registry.cpp b/src/thirdparty/VirtualDub/system/source/registry.cpp index d36202e970f..ef8059a61e2 100644 --- a/src/thirdparty/VirtualDub/system/source/registry.cpp +++ b/src/thirdparty/VirtualDub/system/source/registry.cpp @@ -1,480 +1,480 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////// - -class VDRegistryProviderW32 : public IVDRegistryProvider { -public: - void *GetUserKey(); - void *GetMachineKey(); - void *CreateKey(void *key, const char *path, bool write); - void CloseKey(void *key); - - bool SetBool(void *key, const char *pszName, bool); - bool SetInt(void *key, const char *pszName, int); - bool SetString(void *key, const char *pszName, const char *pszString); - bool SetString(void *key, const char *pszName, const wchar_t *pszString); - bool SetBinary(void *key, const char *pszName, const char *data, int len); - - Type GetType(void *key, const char *name); - bool GetBool(void *key, const char *pszName, bool& val); - bool GetInt(void *key, const char *pszName, int& val); - bool GetString(void *key, const char *pszName, VDStringA& s); - bool GetString(void *key, const char *pszName, VDStringW& s); - - int GetBinaryLength(void *key, const char *pszName); - bool GetBinary(void *key, const char *pszName, char *buf, int maxlen); - - bool RemoveValue(void *key, const char *name); - bool RemoveKey(void *key, const char *name); - - void *EnumKeysBegin(void *key); - const char *EnumKeysNext(void *enumerator); - void EnumKeysClose(void *enumerator); - - void *EnumValuesBegin(void *key); - const char *EnumValuesNext(void *enumerator); - void EnumValuesClose(void *enumerator); - -protected: - struct KeyEnumerator { - void *mKey; - uint32 mIndex; - char mName[256]; - }; - - struct ValueEnumerator { - void *mKey; - uint32 mIndex; - char mName[256]; - }; -}; - -void *VDRegistryProviderW32::GetUserKey() { - return HKEY_CURRENT_USER; -} - -void *VDRegistryProviderW32::GetMachineKey() { - return HKEY_LOCAL_MACHINE; -} - -void *VDRegistryProviderW32::CreateKey(void *key, const char *path, bool write) { - HKEY newKey; - - if (write) { - if (RegCreateKeyEx((HKEY)key, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newKey, NULL)) - return NULL; - } else { - if (RegOpenKeyEx((HKEY)key, path, 0, KEY_READ, &newKey)) - return NULL; - } - - return newKey; -} - -void VDRegistryProviderW32::CloseKey(void *key) { - RegCloseKey((HKEY)key); -} - -bool VDRegistryProviderW32::SetBool(void *key, const char *pszName, bool val) { - DWORD dw = val; - - return !RegSetValueEx((HKEY)key, pszName, 0, REG_DWORD, (const BYTE *)&dw, sizeof dw); -} - -bool VDRegistryProviderW32::SetInt(void *key, const char *pszName, int val) { - DWORD dw = val; - - return !RegSetValueEx((HKEY)key, pszName, 0, REG_DWORD, (const BYTE *)&dw, sizeof dw); -} - -bool VDRegistryProviderW32::SetString(void *key, const char *pszName, const char *pszString) { - return !RegSetValueEx((HKEY)key, pszName, 0, REG_SZ, (const BYTE *)pszString, strlen(pszString)); -} - -bool VDRegistryProviderW32::SetString(void *key, const char *pszName, const wchar_t *pszString) { - if (!VDIsWindowsNT()) { - VDStringA s(VDTextWToA(pszString)); - - if (RegSetValueEx((HKEY)key, pszName, 0, REG_SZ, (const BYTE *)s.data(), s.size())) - return false; - } else { - if (RegSetValueExW((HKEY)key, VDTextAToW(pszName).c_str(), 0, REG_SZ, (const BYTE *)pszString, sizeof(wchar_t) * wcslen(pszString))) - return false; - } - - return true; -} - -bool VDRegistryProviderW32::SetBinary(void *key, const char *pszName, const char *data, int len) { - return !RegSetValueEx((HKEY)key, pszName, 0, REG_BINARY, (const BYTE *)data, len); -} - -IVDRegistryProvider::Type VDRegistryProviderW32::GetType(void *key, const char *name) { - DWORD type; - - if (RegQueryValueEx((HKEY)key, name, 0, &type, NULL, NULL)) - return kTypeUnknown; - - switch(type) { - case REG_SZ: - return kTypeString; - - case REG_BINARY: - return kTypeBinary; - - case REG_DWORD: - return kTypeInt; - - default: - return kTypeUnknown; - } -} - -bool VDRegistryProviderW32::GetBool(void *key, const char *pszName, bool& val) { - DWORD type; - DWORD v; - DWORD len = sizeof(DWORD); - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)&v, &len) || type != REG_DWORD) - return false; - - val = (v != 0); - return true; -} - -bool VDRegistryProviderW32::GetInt(void *key, const char *pszName, int& val) { - DWORD type; - DWORD v; - DWORD len = sizeof(DWORD); - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)&v, &len) || type != REG_DWORD) - return false; - - val = v; - return true; -} - -bool VDRegistryProviderW32::GetString(void *key, const char *pszName, VDStringA& str) { - DWORD type; - DWORD s = sizeof(DWORD); - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, NULL, &s) || type != REG_SZ) - return false; - - str.resize(s); - if (RegQueryValueEx((HKEY)key, pszName, 0, NULL, (BYTE *)str.data(), &s)) - return false; - - if (!s) - str.clear(); - else - str.resize(strlen(str.c_str())); // Trim off pesky terminating NULLs. - - return true; -} - -bool VDRegistryProviderW32::GetString(void *key, const char *pszName, VDStringW& str) { - if (!VDIsWindowsNT()) { - VDStringA v; - if (!GetString(key, pszName, v)) - return false; - str = VDTextAToW(v); - return true; - } - - const VDStringW wsName(VDTextAToW(pszName)); - DWORD type; - DWORD s = sizeof(DWORD); - - if (RegQueryValueExW((HKEY)key, wsName.c_str(), 0, &type, NULL, &s) || type != REG_SZ) - return false; - - if (s <= 0) - str.clear(); - else { - str.resize((s + sizeof(wchar_t) - 1) / sizeof(wchar_t)); - - if (RegQueryValueExW((HKEY)key, wsName.c_str(), 0, NULL, (BYTE *)&str[0], &s)) - return false; - - str.resize(wcslen(str.c_str())); // Trim off pesky terminating NULLs. - } - - return true; -} - -int VDRegistryProviderW32::GetBinaryLength(void *key, const char *pszName) { - DWORD type; - DWORD s = sizeof(DWORD); - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, NULL, &s) || type != REG_BINARY) - return -1; - - return s; -} - -bool VDRegistryProviderW32::GetBinary(void *key, const char *pszName, char *buf, int maxlen) { - DWORD type; - DWORD s = maxlen; - - if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)buf, &s) || maxlen < (int)s || type != REG_BINARY) - return false; - - return true; -} - -bool VDRegistryProviderW32::RemoveValue(void *key, const char *name) { - return 0 != RegDeleteValue((HKEY)key, name); -} - -bool VDRegistryProviderW32::RemoveKey(void *key, const char *name) { - return 0 != RegDeleteKey((HKEY)key, name); -} - -void *VDRegistryProviderW32::EnumKeysBegin(void *key) { - KeyEnumerator *ke = new KeyEnumerator; - - ke->mKey = key; - ke->mIndex = 0; - - return ke; -} - -const char *VDRegistryProviderW32::EnumKeysNext(void *enumerator) { - KeyEnumerator *ke = (KeyEnumerator *)enumerator; - - DWORD len = sizeof(ke->mName)/sizeof(ke->mName[0]); - FILETIME ft; - LONG error = RegEnumKeyExA((HKEY)ke->mKey, ke->mIndex, ke->mName, &len, NULL, NULL, NULL, &ft); - - if (error) - return NULL; - - ++ke->mIndex; - return ke->mName; -} - -void VDRegistryProviderW32::EnumKeysClose(void *enumerator) { - delete (KeyEnumerator *)enumerator; -} - -void *VDRegistryProviderW32::EnumValuesBegin(void *key) { - ValueEnumerator *ve = new ValueEnumerator; - - ve->mKey = key; - ve->mIndex = 0; - - return ve; -} - -const char *VDRegistryProviderW32::EnumValuesNext(void *enumerator) { - ValueEnumerator *ve = (ValueEnumerator *)enumerator; - - DWORD len = sizeof(ve->mName)/sizeof(ve->mName[0]); - LONG error = RegEnumValueA((HKEY)ve->mKey, ve->mIndex, ve->mName, &len, NULL, NULL, NULL, NULL); - - if (error) - return NULL; - - ++ve->mIndex; - return ve->mName; -} - -void VDRegistryProviderW32::EnumValuesClose(void *enumerator) { - delete (ValueEnumerator *)enumerator; -} - -/////////////////////////////////////////////////////////////////////////// - -VDRegistryProviderW32 g_VDRegistryProviderW32; -IVDRegistryProvider *g_pVDRegistryProvider = &g_VDRegistryProviderW32; - -IVDRegistryProvider *VDGetRegistryProvider() { - return g_pVDRegistryProvider; -} - -void VDSetRegistryProvider(IVDRegistryProvider *provider) { - g_pVDRegistryProvider = provider; -} - -/////////////////////////////////////////////////////////////////////////// - -VDRegistryKey::VDRegistryKey(const char *keyName, bool global, bool write) { - IVDRegistryProvider *provider = VDGetRegistryProvider(); - void *rootKey = global ? provider->GetMachineKey() : provider->GetUserKey(); - - mKey = provider->CreateKey(rootKey, keyName, write); -} - -VDRegistryKey::VDRegistryKey(VDRegistryKey& baseKey, const char *name, bool write) { - IVDRegistryProvider *provider = VDGetRegistryProvider(); - void *rootKey = baseKey.getRawHandle(); - - mKey = rootKey ? provider->CreateKey(rootKey, name, write) : NULL; -} - -VDRegistryKey::~VDRegistryKey() { - if (mKey) - VDGetRegistryProvider()->CloseKey(mKey); -} - -bool VDRegistryKey::setBool(const char *name, bool v) const { - return mKey && VDGetRegistryProvider()->SetBool(mKey, name, v); -} - -bool VDRegistryKey::setInt(const char *name, int i) const { - return mKey && VDGetRegistryProvider()->SetInt(mKey, name, i); -} - -bool VDRegistryKey::setString(const char *name, const char *s) const { - return mKey && VDGetRegistryProvider()->SetString(mKey, name, s); -} - -bool VDRegistryKey::setString(const char *name, const wchar_t *s) const { - return mKey && VDGetRegistryProvider()->SetString(mKey, name, s); -} - -bool VDRegistryKey::setBinary(const char *name, const char *data, int len) const { - return mKey && VDGetRegistryProvider()->SetBinary(mKey, name, data, len); -} - -VDRegistryKey::Type VDRegistryKey::getValueType(const char *name) const { - Type type = kTypeUnknown; - - if (mKey) { - switch(VDGetRegistryProvider()->GetType(mKey, name)) { - case IVDRegistryProvider::kTypeInt: - type = kTypeInt; - break; - - case IVDRegistryProvider::kTypeString: - type = kTypeString; - break; - - case IVDRegistryProvider::kTypeBinary: - type = kTypeBinary; - break; - } - } - - return type; -} - -bool VDRegistryKey::getBool(const char *name, bool def) const { - bool v; - return mKey && VDGetRegistryProvider()->GetBool(mKey, name, v) ? v : def; -} - -int VDRegistryKey::getInt(const char *name, int def) const { - int v; - return mKey && VDGetRegistryProvider()->GetInt(mKey, name, v) ? v : def; -} - -int VDRegistryKey::getEnumInt(const char *pszName, int maxVal, int def) const { - int v = getInt(pszName, def); - - if (v<0 || v>=maxVal) - v = def; - - return v; -} - -bool VDRegistryKey::getString(const char *name, VDStringA& str) const { - return mKey && VDGetRegistryProvider()->GetString(mKey, name, str); -} - -bool VDRegistryKey::getString(const char *name, VDStringW& str) const { - return mKey && VDGetRegistryProvider()->GetString(mKey, name, str); -} - -int VDRegistryKey::getBinaryLength(const char *name) const { - return mKey ? VDGetRegistryProvider()->GetBinaryLength(mKey, name) : -1; -} - -bool VDRegistryKey::getBinary(const char *name, char *buf, int maxlen) const { - return mKey && VDGetRegistryProvider()->GetBinary(mKey, name, buf, maxlen); -} - -bool VDRegistryKey::removeValue(const char *name) { - return mKey && VDGetRegistryProvider()->RemoveValue(mKey, name); -} - -bool VDRegistryKey::removeKey(const char *name) { - return mKey && VDGetRegistryProvider()->RemoveKey(mKey, name); -} - -/////////////////////////////////////////////////////////////////////////////// - -VDRegistryValueIterator::VDRegistryValueIterator(const VDRegistryKey& key) - : mEnumerator(VDGetRegistryProvider()->EnumValuesBegin(key.getRawHandle())) -{ -} - -VDRegistryValueIterator::~VDRegistryValueIterator() { - VDGetRegistryProvider()->EnumValuesClose(mEnumerator); -} - -const char *VDRegistryValueIterator::Next() { - return mEnumerator ? VDGetRegistryProvider()->EnumValuesNext(mEnumerator) : NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -VDRegistryKeyIterator::VDRegistryKeyIterator(const VDRegistryKey& key) - : mEnumerator(VDGetRegistryProvider()->EnumKeysBegin(key.getRawHandle())) -{ -} - -VDRegistryKeyIterator::~VDRegistryKeyIterator() { - VDGetRegistryProvider()->EnumKeysClose(mEnumerator); -} - -const char *VDRegistryKeyIterator::Next() { - return mEnumerator ? VDGetRegistryProvider()->EnumKeysNext(mEnumerator) : NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -VDString VDRegistryAppKey::s_appbase; - -VDRegistryAppKey::VDRegistryAppKey() : VDRegistryKey(s_appbase.c_str()) { -} - -VDRegistryAppKey::VDRegistryAppKey(const char *pszKey, bool write, bool global) - : VDRegistryKey((s_appbase + pszKey).c_str(), global, write) -{ -} - -void VDRegistryAppKey::setDefaultKey(const char *pszAppName) { - s_appbase = pszAppName; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + +class VDRegistryProviderW32 : public IVDRegistryProvider { +public: + void *GetUserKey(); + void *GetMachineKey(); + void *CreateKey(void *key, const char *path, bool write); + void CloseKey(void *key); + + bool SetBool(void *key, const char *pszName, bool); + bool SetInt(void *key, const char *pszName, int); + bool SetString(void *key, const char *pszName, const char *pszString); + bool SetString(void *key, const char *pszName, const wchar_t *pszString); + bool SetBinary(void *key, const char *pszName, const char *data, int len); + + Type GetType(void *key, const char *name); + bool GetBool(void *key, const char *pszName, bool& val); + bool GetInt(void *key, const char *pszName, int& val); + bool GetString(void *key, const char *pszName, VDStringA& s); + bool GetString(void *key, const char *pszName, VDStringW& s); + + int GetBinaryLength(void *key, const char *pszName); + bool GetBinary(void *key, const char *pszName, char *buf, int maxlen); + + bool RemoveValue(void *key, const char *name); + bool RemoveKey(void *key, const char *name); + + void *EnumKeysBegin(void *key); + const char *EnumKeysNext(void *enumerator); + void EnumKeysClose(void *enumerator); + + void *EnumValuesBegin(void *key); + const char *EnumValuesNext(void *enumerator); + void EnumValuesClose(void *enumerator); + +protected: + struct KeyEnumerator { + void *mKey; + uint32 mIndex; + char mName[256]; + }; + + struct ValueEnumerator { + void *mKey; + uint32 mIndex; + char mName[256]; + }; +}; + +void *VDRegistryProviderW32::GetUserKey() { + return HKEY_CURRENT_USER; +} + +void *VDRegistryProviderW32::GetMachineKey() { + return HKEY_LOCAL_MACHINE; +} + +void *VDRegistryProviderW32::CreateKey(void *key, const char *path, bool write) { + HKEY newKey; + + if (write) { + if (RegCreateKeyEx((HKEY)key, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &newKey, NULL)) + return NULL; + } else { + if (RegOpenKeyEx((HKEY)key, path, 0, KEY_READ, &newKey)) + return NULL; + } + + return newKey; +} + +void VDRegistryProviderW32::CloseKey(void *key) { + RegCloseKey((HKEY)key); +} + +bool VDRegistryProviderW32::SetBool(void *key, const char *pszName, bool val) { + DWORD dw = val; + + return !RegSetValueEx((HKEY)key, pszName, 0, REG_DWORD, (const BYTE *)&dw, sizeof dw); +} + +bool VDRegistryProviderW32::SetInt(void *key, const char *pszName, int val) { + DWORD dw = val; + + return !RegSetValueEx((HKEY)key, pszName, 0, REG_DWORD, (const BYTE *)&dw, sizeof dw); +} + +bool VDRegistryProviderW32::SetString(void *key, const char *pszName, const char *pszString) { + return !RegSetValueEx((HKEY)key, pszName, 0, REG_SZ, (const BYTE *)pszString, strlen(pszString)); +} + +bool VDRegistryProviderW32::SetString(void *key, const char *pszName, const wchar_t *pszString) { + if (!VDIsWindowsNT()) { + VDStringA s(VDTextWToA(pszString)); + + if (RegSetValueEx((HKEY)key, pszName, 0, REG_SZ, (const BYTE *)s.data(), s.size())) + return false; + } else { + if (RegSetValueExW((HKEY)key, VDTextAToW(pszName).c_str(), 0, REG_SZ, (const BYTE *)pszString, sizeof(wchar_t) * wcslen(pszString))) + return false; + } + + return true; +} + +bool VDRegistryProviderW32::SetBinary(void *key, const char *pszName, const char *data, int len) { + return !RegSetValueEx((HKEY)key, pszName, 0, REG_BINARY, (const BYTE *)data, len); +} + +IVDRegistryProvider::Type VDRegistryProviderW32::GetType(void *key, const char *name) { + DWORD type; + + if (RegQueryValueEx((HKEY)key, name, 0, &type, NULL, NULL)) + return kTypeUnknown; + + switch(type) { + case REG_SZ: + return kTypeString; + + case REG_BINARY: + return kTypeBinary; + + case REG_DWORD: + return kTypeInt; + + default: + return kTypeUnknown; + } +} + +bool VDRegistryProviderW32::GetBool(void *key, const char *pszName, bool& val) { + DWORD type; + DWORD v; + DWORD len = sizeof(DWORD); + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)&v, &len) || type != REG_DWORD) + return false; + + val = (v != 0); + return true; +} + +bool VDRegistryProviderW32::GetInt(void *key, const char *pszName, int& val) { + DWORD type; + DWORD v; + DWORD len = sizeof(DWORD); + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)&v, &len) || type != REG_DWORD) + return false; + + val = v; + return true; +} + +bool VDRegistryProviderW32::GetString(void *key, const char *pszName, VDStringA& str) { + DWORD type; + DWORD s = sizeof(DWORD); + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, NULL, &s) || type != REG_SZ) + return false; + + str.resize(s); + if (RegQueryValueEx((HKEY)key, pszName, 0, NULL, (BYTE *)str.data(), &s)) + return false; + + if (!s) + str.clear(); + else + str.resize(strlen(str.c_str())); // Trim off pesky terminating NULLs. + + return true; +} + +bool VDRegistryProviderW32::GetString(void *key, const char *pszName, VDStringW& str) { + if (!VDIsWindowsNT()) { + VDStringA v; + if (!GetString(key, pszName, v)) + return false; + str = VDTextAToW(v); + return true; + } + + const VDStringW wsName(VDTextAToW(pszName)); + DWORD type; + DWORD s = sizeof(DWORD); + + if (RegQueryValueExW((HKEY)key, wsName.c_str(), 0, &type, NULL, &s) || type != REG_SZ) + return false; + + if (s <= 0) + str.clear(); + else { + str.resize((s + sizeof(wchar_t) - 1) / sizeof(wchar_t)); + + if (RegQueryValueExW((HKEY)key, wsName.c_str(), 0, NULL, (BYTE *)&str[0], &s)) + return false; + + str.resize(wcslen(str.c_str())); // Trim off pesky terminating NULLs. + } + + return true; +} + +int VDRegistryProviderW32::GetBinaryLength(void *key, const char *pszName) { + DWORD type; + DWORD s = sizeof(DWORD); + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, NULL, &s) || type != REG_BINARY) + return -1; + + return s; +} + +bool VDRegistryProviderW32::GetBinary(void *key, const char *pszName, char *buf, int maxlen) { + DWORD type; + DWORD s = maxlen; + + if (RegQueryValueEx((HKEY)key, pszName, 0, &type, (BYTE *)buf, &s) || maxlen < (int)s || type != REG_BINARY) + return false; + + return true; +} + +bool VDRegistryProviderW32::RemoveValue(void *key, const char *name) { + return 0 != RegDeleteValue((HKEY)key, name); +} + +bool VDRegistryProviderW32::RemoveKey(void *key, const char *name) { + return 0 != RegDeleteKey((HKEY)key, name); +} + +void *VDRegistryProviderW32::EnumKeysBegin(void *key) { + KeyEnumerator *ke = new KeyEnumerator; + + ke->mKey = key; + ke->mIndex = 0; + + return ke; +} + +const char *VDRegistryProviderW32::EnumKeysNext(void *enumerator) { + KeyEnumerator *ke = (KeyEnumerator *)enumerator; + + DWORD len = sizeof(ke->mName)/sizeof(ke->mName[0]); + FILETIME ft; + LONG error = RegEnumKeyExA((HKEY)ke->mKey, ke->mIndex, ke->mName, &len, NULL, NULL, NULL, &ft); + + if (error) + return NULL; + + ++ke->mIndex; + return ke->mName; +} + +void VDRegistryProviderW32::EnumKeysClose(void *enumerator) { + delete (KeyEnumerator *)enumerator; +} + +void *VDRegistryProviderW32::EnumValuesBegin(void *key) { + ValueEnumerator *ve = new ValueEnumerator; + + ve->mKey = key; + ve->mIndex = 0; + + return ve; +} + +const char *VDRegistryProviderW32::EnumValuesNext(void *enumerator) { + ValueEnumerator *ve = (ValueEnumerator *)enumerator; + + DWORD len = sizeof(ve->mName)/sizeof(ve->mName[0]); + LONG error = RegEnumValueA((HKEY)ve->mKey, ve->mIndex, ve->mName, &len, NULL, NULL, NULL, NULL); + + if (error) + return NULL; + + ++ve->mIndex; + return ve->mName; +} + +void VDRegistryProviderW32::EnumValuesClose(void *enumerator) { + delete (ValueEnumerator *)enumerator; +} + +/////////////////////////////////////////////////////////////////////////// + +VDRegistryProviderW32 g_VDRegistryProviderW32; +IVDRegistryProvider *g_pVDRegistryProvider = &g_VDRegistryProviderW32; + +IVDRegistryProvider *VDGetRegistryProvider() { + return g_pVDRegistryProvider; +} + +void VDSetRegistryProvider(IVDRegistryProvider *provider) { + g_pVDRegistryProvider = provider; +} + +/////////////////////////////////////////////////////////////////////////// + +VDRegistryKey::VDRegistryKey(const char *keyName, bool global, bool write) { + IVDRegistryProvider *provider = VDGetRegistryProvider(); + void *rootKey = global ? provider->GetMachineKey() : provider->GetUserKey(); + + mKey = provider->CreateKey(rootKey, keyName, write); +} + +VDRegistryKey::VDRegistryKey(VDRegistryKey& baseKey, const char *name, bool write) { + IVDRegistryProvider *provider = VDGetRegistryProvider(); + void *rootKey = baseKey.getRawHandle(); + + mKey = rootKey ? provider->CreateKey(rootKey, name, write) : NULL; +} + +VDRegistryKey::~VDRegistryKey() { + if (mKey) + VDGetRegistryProvider()->CloseKey(mKey); +} + +bool VDRegistryKey::setBool(const char *name, bool v) const { + return mKey && VDGetRegistryProvider()->SetBool(mKey, name, v); +} + +bool VDRegistryKey::setInt(const char *name, int i) const { + return mKey && VDGetRegistryProvider()->SetInt(mKey, name, i); +} + +bool VDRegistryKey::setString(const char *name, const char *s) const { + return mKey && VDGetRegistryProvider()->SetString(mKey, name, s); +} + +bool VDRegistryKey::setString(const char *name, const wchar_t *s) const { + return mKey && VDGetRegistryProvider()->SetString(mKey, name, s); +} + +bool VDRegistryKey::setBinary(const char *name, const char *data, int len) const { + return mKey && VDGetRegistryProvider()->SetBinary(mKey, name, data, len); +} + +VDRegistryKey::Type VDRegistryKey::getValueType(const char *name) const { + Type type = kTypeUnknown; + + if (mKey) { + switch(VDGetRegistryProvider()->GetType(mKey, name)) { + case IVDRegistryProvider::kTypeInt: + type = kTypeInt; + break; + + case IVDRegistryProvider::kTypeString: + type = kTypeString; + break; + + case IVDRegistryProvider::kTypeBinary: + type = kTypeBinary; + break; + } + } + + return type; +} + +bool VDRegistryKey::getBool(const char *name, bool def) const { + bool v; + return mKey && VDGetRegistryProvider()->GetBool(mKey, name, v) ? v : def; +} + +int VDRegistryKey::getInt(const char *name, int def) const { + int v; + return mKey && VDGetRegistryProvider()->GetInt(mKey, name, v) ? v : def; +} + +int VDRegistryKey::getEnumInt(const char *pszName, int maxVal, int def) const { + int v = getInt(pszName, def); + + if (v<0 || v>=maxVal) + v = def; + + return v; +} + +bool VDRegistryKey::getString(const char *name, VDStringA& str) const { + return mKey && VDGetRegistryProvider()->GetString(mKey, name, str); +} + +bool VDRegistryKey::getString(const char *name, VDStringW& str) const { + return mKey && VDGetRegistryProvider()->GetString(mKey, name, str); +} + +int VDRegistryKey::getBinaryLength(const char *name) const { + return mKey ? VDGetRegistryProvider()->GetBinaryLength(mKey, name) : -1; +} + +bool VDRegistryKey::getBinary(const char *name, char *buf, int maxlen) const { + return mKey && VDGetRegistryProvider()->GetBinary(mKey, name, buf, maxlen); +} + +bool VDRegistryKey::removeValue(const char *name) { + return mKey && VDGetRegistryProvider()->RemoveValue(mKey, name); +} + +bool VDRegistryKey::removeKey(const char *name) { + return mKey && VDGetRegistryProvider()->RemoveKey(mKey, name); +} + +/////////////////////////////////////////////////////////////////////////////// + +VDRegistryValueIterator::VDRegistryValueIterator(const VDRegistryKey& key) + : mEnumerator(VDGetRegistryProvider()->EnumValuesBegin(key.getRawHandle())) +{ +} + +VDRegistryValueIterator::~VDRegistryValueIterator() { + VDGetRegistryProvider()->EnumValuesClose(mEnumerator); +} + +const char *VDRegistryValueIterator::Next() { + return mEnumerator ? VDGetRegistryProvider()->EnumValuesNext(mEnumerator) : NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +VDRegistryKeyIterator::VDRegistryKeyIterator(const VDRegistryKey& key) + : mEnumerator(VDGetRegistryProvider()->EnumKeysBegin(key.getRawHandle())) +{ +} + +VDRegistryKeyIterator::~VDRegistryKeyIterator() { + VDGetRegistryProvider()->EnumKeysClose(mEnumerator); +} + +const char *VDRegistryKeyIterator::Next() { + return mEnumerator ? VDGetRegistryProvider()->EnumKeysNext(mEnumerator) : NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +VDString VDRegistryAppKey::s_appbase; + +VDRegistryAppKey::VDRegistryAppKey() : VDRegistryKey(s_appbase.c_str()) { +} + +VDRegistryAppKey::VDRegistryAppKey(const char *pszKey, bool write, bool global) + : VDRegistryKey((s_appbase + pszKey).c_str(), global, write) +{ +} + +void VDRegistryAppKey::setDefaultKey(const char *pszAppName) { + s_appbase = pszAppName; +} diff --git a/src/thirdparty/VirtualDub/system/source/stdaccel.cpp b/src/thirdparty/VirtualDub/system/source/stdaccel.cpp index 7214797b13d..4acad27fdc9 100644 --- a/src/thirdparty/VirtualDub/system/source/stdaccel.cpp +++ b/src/thirdparty/VirtualDub/system/source/stdaccel.cpp @@ -1,42 +1,42 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#define VDTEXTERN - -#include -#include - -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; -template class vdspan; +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2007 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#define VDTEXTERN + +#include +#include + +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; +template class vdspan; diff --git a/src/thirdparty/VirtualDub/system/source/stdafx.cpp b/src/thirdparty/VirtualDub/system/source/stdafx.cpp index 92339e1d947..acf0b47e42b 100644 --- a/src/thirdparty/VirtualDub/system/source/stdafx.cpp +++ b/src/thirdparty/VirtualDub/system/source/stdafx.cpp @@ -1,46 +1,46 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include - -#ifdef _MSC_VER - #pragma hdrstop -#endif - -// compiler/setup checks - -#if defined(_MSC_VER) - #if _MSC_VER < 1300 - #include - - #line 1 " \n \n \n***** You do not have the correct version of the Microsoft Platform SDK installed *****\nPlease see Docs\\index.html for details.\n \n \n" - namespace { const DWORD PlatformSDKTest = INVALID_SET_FILE_POINTER; } - #line 1 "" - - #line 1 " \n \n \n***** You do not have the Visual C++ Processor Pack installed *****\nPlease see Docs\\index.html for details.\n \n \n" - namespace { void VCPPCheck() { __asm { sfence } } } - #line 1 "" - #endif -#endif +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include + +#ifdef _MSC_VER + #pragma hdrstop +#endif + +// compiler/setup checks + +#if defined(_MSC_VER) + #if _MSC_VER < 1300 + #include + + #line 1 " \n \n \n***** You do not have the correct version of the Microsoft Platform SDK installed *****\nPlease see Docs\\index.html for details.\n \n \n" + namespace { const DWORD PlatformSDKTest = INVALID_SET_FILE_POINTER; } + #line 1 "" + + #line 1 " \n \n \n***** You do not have the Visual C++ Processor Pack installed *****\nPlease see Docs\\index.html for details.\n \n \n" + namespace { void VCPPCheck() { __asm { sfence } } } + #line 1 "" + #endif +#endif diff --git a/src/thirdparty/VirtualDub/system/source/strutil.cpp b/src/thirdparty/VirtualDub/system/source/strutil.cpp index 31f4e985994..2d9becc857d 100644 --- a/src/thirdparty/VirtualDub/system/source/strutil.cpp +++ b/src/thirdparty/VirtualDub/system/source/strutil.cpp @@ -1,99 +1,99 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include - -char *strncpyz(char *strDest, const char *strSource, size_t count) { - char *s; - - s = strncpy(strDest, strSource, count); - strDest[count-1] = 0; - - return s; -} - -wchar_t *wcsncpyz(wchar_t *strDest, const wchar_t *strSource, size_t count) { - wchar_t *s; - - s = wcsncpy(strDest, strSource, count); - strDest[count-1] = 0; - - return s; -} - -const char *strskipspace(const char *s) { - while(isspace((unsigned char)*s++)) - ; - - return s-1; -} - -size_t vdstrlcpy(char *dst, const char *src, size_t size) { - size_t len = strlen(src); - - if (size) { - if (size > len) - size = len; - - memcpy(dst, src, size); - dst[size] = 0; - } - return len; -} - -size_t vdwcslcpy(wchar_t *dst, const wchar_t *src, size_t size) { - size_t len = wcslen(src); - - if (size) { - if (size > len) - size = len; - - memcpy(dst, src, size * sizeof(wchar_t)); - dst[size] = 0; - } - return len; -} - -size_t vdstrlcat(char *dst, const char *src, size_t size) { - size_t dlen = strlen(dst); - size_t slen = strlen(src); - - if (dlen < size) { - size_t maxappend = size - dlen - 1; - if (maxappend > slen) - maxappend = slen; - - if (maxappend) { - memcpy(dst + dlen, src, maxappend); - dst[dlen+maxappend] = 0; - } - } - - return dlen+slen; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +#include + +char *strncpyz(char *strDest, const char *strSource, size_t count) { + char *s; + + s = strncpy(strDest, strSource, count); + strDest[count-1] = 0; + + return s; +} + +wchar_t *wcsncpyz(wchar_t *strDest, const wchar_t *strSource, size_t count) { + wchar_t *s; + + s = wcsncpy(strDest, strSource, count); + strDest[count-1] = 0; + + return s; +} + +const char *strskipspace(const char *s) { + while(isspace((unsigned char)*s++)) + ; + + return s-1; +} + +size_t vdstrlcpy(char *dst, const char *src, size_t size) { + size_t len = strlen(src); + + if (size) { + if (size > len) + size = len; + + memcpy(dst, src, size); + dst[size] = 0; + } + return len; +} + +size_t vdwcslcpy(wchar_t *dst, const wchar_t *src, size_t size) { + size_t len = wcslen(src); + + if (size) { + if (size > len) + size = len; + + memcpy(dst, src, size * sizeof(wchar_t)); + dst[size] = 0; + } + return len; +} + +size_t vdstrlcat(char *dst, const char *src, size_t size) { + size_t dlen = strlen(dst); + size_t slen = strlen(src); + + if (dlen < size) { + size_t maxappend = size - dlen - 1; + if (maxappend > slen) + maxappend = slen; + + if (maxappend) { + memcpy(dst + dlen, src, maxappend); + dst[dlen+maxappend] = 0; + } + } + + return dlen+slen; +} diff --git a/src/thirdparty/VirtualDub/system/source/text.cpp b/src/thirdparty/VirtualDub/system/source/text.cpp index 508a871287b..c87e3155845 100644 --- a/src/thirdparty/VirtualDub/system/source/text.cpp +++ b/src/thirdparty/VirtualDub/system/source/text.cpp @@ -1,653 +1,653 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -int VDTextWToA(char *dst, int max_dst, const wchar_t *src, int max_src) { - VDASSERTPTR(dst); - VDASSERTPTR(src); - VDASSERT(max_dst>0); - - *dst = 0; - - int len = WideCharToMultiByte(CP_ACP, 0, src, max_src, dst, max_dst, NULL, NULL); - - // remove null terminator if source was null-terminated (source - // length was provided) - return max_src<0 && len>0 ? len-1 : len; -} - -int VDTextAToW(wchar_t *dst, int max_dst, const char *src, int max_src) { - VDASSERTPTR(dst); - VDASSERTPTR(src); - VDASSERT(max_dst>0); - - *dst = 0; - - int len = MultiByteToWideChar(CP_ACP, 0, src, max_src, dst, max_dst); - - // remove null terminator if source was null-terminated (source - // length was provided) - return max_src<0 && len>0 ? len-1 : len; -} - -VDStringA VDTextWToA(const VDStringW& sw) { - return VDTextWToA(sw.data(), sw.length()); -} - -VDStringA VDTextWToA(const wchar_t *src, int srclen) { - VDStringA s; - - if (src) { - int l = VDTextWToALength(src, srclen); - - if (l) { - s.resize(l); - VDTextWToA((char *)s.data(), l+1, src, srclen); - } - } - - return s; -} - -VDStringW VDTextAToW(const VDStringA& s) { - return VDTextAToW(s.data(), s.length()); -} - -VDStringW VDTextAToW(const char *src, int srclen) { - VDStringW sw; - - if (src) { - int l = VDTextAToWLength(src, srclen); - - if (l) { - sw.resize(l); - VDTextAToW(&sw[0], sw.length()+1, src, srclen); - } - } - - return sw; -} - -int VDTextWToALength(const wchar_t *s, int length) { - SetLastError(0); - int rv = WideCharToMultiByte(CP_ACP, 0, s, length, NULL, 0, NULL, 0); - - if (length < 0 && rv>0) - --rv; - - return rv; -} - -int VDTextAToWLength(const char *s, int length) { - SetLastError(0); - int rv = MultiByteToWideChar(CP_ACP, 0, s, length, NULL, 0); - - if (length < 0 && rv > 0) - --rv; - - return rv; -} - -namespace { - // UTF8: - // 000000000xxxxxxx -> 0xxxxxxx - // 00000yyyyyxxxxxx -> 110yyyyy 10xxxxxx - // zzzzyyyyyyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx - // uuuuuzzzzyyyyyyxxxxxx -> 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx - // (UTF16) -> 110110wwwwzzzzyy (uuuuu = wwww+1) - // 110111yyyyxxxxxx - int VDGetCharLengthInUTF8(wchar_t c) { - if (c < 0x0080) // 7 bits - return 1; - else if (c < 0x0800) // 11 bits - return 2; - else if (c < 0x10000) // 16 bits - return 3; - else if (c < 0x200000) // 21 bits - return 4; - else { - VDASSERT(false); - return 1; // Uh oh. Well, we're screwed. - } - } - - bool VDIsUnicodeSurrogateFirst(wchar_t c) { - return (c >= 0xD800 && c < 0xDC00); - } - - bool VDIsUnicodeSurrogateSecond(wchar_t c) { - return (c >= 0xDC00 && c < 0xE000); - } -}; - -VDStringA VDTextWToU8(const VDStringW& s) { - return VDTextWToU8(s.data(), s.length()); -} - -VDStringA VDTextWToU8(const wchar_t *s, int length) { - vdfastvector temp; - - if (length<0) { - const wchar_t *t = s; - do { - ++length; - } while(*t++); - } - - while(length--) { - uint32 c = *s++; - - if (VDIsUnicodeSurrogateFirst(c)) { - if (!length || !VDIsUnicodeSurrogateSecond(*s)) { - VDASSERT(false); - c = '?'; - } else { - c = 0x10000 + ((c & 0x3ff)<<10) + (*s++ & 0x3ff); - --length; - } - } - - if (c < 0x0080) { - temp.push_back((char)c); - } else { - if (c < 0x0800) - temp.push_back((char)(0xc0 + (c>>6))); - else { - if (c < 0x10000) - temp.push_back((char)(0xe0 + (c>>12))); - else { - temp.push_back((char)(0xf0 + ((c>>18) & 0x07))); - temp.push_back((char)(0x80 + ((c>>12) & 0x3f))); - } - temp.push_back((char)(0x80 + ((c>>6) & 0x3f))); - } - temp.push_back((char)(0x80 + (c & 0x3f))); - } - } - - VDStringA a(temp.data(), temp.size()); - - return a; -} - -VDStringW VDTextU8ToW(const VDStringA& s) { - return VDTextU8ToW(s.data(), s.length()); -} - -VDStringW VDTextU8ToW(const char *s, int length) { - vdfastvector temp; - - if (length<0) { - const char *t = s; - VDASSERT(length == -1); - do { - ++length; - } while(*t++); - } - - while(length--) { - unsigned char c = (char)*s++; - uint32 wc = c; // we reconstruct UTF-32 first and then split to UTF-16 if necessary - - if (c >= 0x80) { - int required_extra = 0; - - if (c < 0xc0 || c >= 0xf7) { - VDASSERT(false); - break; - } - - while(c >= 0xc0) { - c <<= 1; - ++required_extra; - } - - wc = (c&0x3f) >> required_extra; - - do { - char d; - - if (!length-- || (((d=*s++)&0xc0)!=0x80)) - goto bad_sequence_exit; - - wc = (wc<<6) + (d&0x3f); - } while(--required_extra); - } - - // Two cases here. If we are using UTF-16, surrogates need to be split in half. If we are using - // UTF-32, surrogates need to be combined. - - if (sizeof(wchar_t) > 2) { - if (VDIsUnicodeSurrogateSecond(wc)) { - if (temp.empty() || !VDIsUnicodeSurrogateFirst(temp.back())) { - VDASSERT(false); - break; - } - - temp.back() = 0x10000 + ((temp.back()&0x3ff) << 10) + (wc & 0x3ff); - continue; - } - } else { - if (wc >= 0x10000) { - wc -= 0x10000; - temp.push_back(0xD800 + ((wc & 0x3ff) >> 10)); - wc = 0xDC00 + (wc&0x3ff); - } - } - temp.push_back(wc); - } -bad_sequence_exit: - - VDStringW w(temp.data(), temp.size()); - - return w; -} - -/////////////////////////////////////////////////////////////////////////// -// -// VirtualDub's very own printf() functions. -// -// VD[v|a]swprintf() differs from wsprintf() in the following ways: -// -// * The output is a string. -// * All parameters must be passed by pointer instead of by value. -// * The 'll' modifier permits long long / __int64 integers. -// * [n] allows picking parameters out of order. -// * %lc/%ls forces Unicode; %hc/%hs forces ANSI. - -VDStringW VDaswprintf(const wchar_t *format, int args, const void *const *argv) { - const void *const *argv0 = argv; - vdfastfixedvector out; - wchar_t c; - - VDStringW tempConv; - - while(c = *format) { - if (c != L'%') { - const wchar_t *s = format; - - while(*s && *s != L'%') - ++s; - - int len = s - format; - int clen = out.size(); - - out.resize(clen + len); - - std::copy(format, s, &out[clen]); - - format = s; - } else { - ++format; - - // check for %% - - if (*format == L'%') { - ++format; - out.push_back(L'%'); - continue; - } - - // Check for a renumbering identifier. - - if (*format == L'[') { - ++format; - - int newid = wcstol(format, const_cast(&format), 0); - - VDASSERT(newid >= 0 && newid < args); - - argv = argv0 + newid; - - VDVERIFY(*format++ == L']'); - } - - // process flags - - struct { - bool bLeftAlign:1, // pad right with spaces (priority over zero pad) - bZeroPad:1, // pad left with zeroes - bPositiveSign:1, // prefix with + or -; priority over bPositiveBlank - bPositiveBlank:1, // prefix with space for nonnegative - bPrefix:1; // prefix with 0, 0x, 0X, or force decimal point - } flags={false}; - int width = 0; - int precision = -1; - - for(;;) { - c = *format; - - if (c == L'0') - flags.bZeroPad = true; - else if (c == L' ') - flags.bPositiveBlank = true; - else if (c == L'#') - flags.bPrefix = true; - else if (c == L'-') - flags.bLeftAlign = true; - else if (c == L'+') - flags.bPositiveSign = true; - else - break; - - ++format; - } - - // process width - - c = *format; - if (c == L'*') { - ++format; - width = *(int *)*argv++; - } else if (iswdigit(c)) - width = (int)wcstol(format, const_cast(&format), 0); - - // process precision - - if (*format == L'.') { - c = *++format; - - if (c == L'*') { - ++format; - precision = *(int *)*argv++; - } else if (iswdigit(c)) - precision = (int)wcstol(format, const_cast(&format), 0); - } - - // process flags - - enum { kDefault, kLong, kLongLong, kShort } size = kDefault; - - c = *format; - - if (c == L'l') { - ++format; - size = kLong; - - if (*format == L'l') { - ++format; - size = kLongLong; - } - - } else if (c == L'h') { - ++format; - size = kShort; - } - - // process format character - - wchar_t xf[32], buf[32], *pxf = xf, *pbuf0 = buf, *pbuf = buf; - int zero_pad = 0; - - switch(*format++) { - case L'd': - case L'i': - case L'o': - case L'u': - case L'x': - case L'X': - *pxf++ = '%'; - if (flags.bPrefix) - *pxf++ = '#'; - if (flags.bPositiveBlank) - *pxf++ = ' '; - if (flags.bPositiveSign) - *pxf++ = '+'; - - switch(size) { - case kShort: - *pxf++ = 'h'; - *pxf++ = format[-1]; - *pxf = 0; - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const short *)*argv++); - break; - case kDefault: - *pxf++ = format[-1]; - *pxf = 0; - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const int *)*argv++); - break; - case kLong: - *pxf++ = 'l'; - *pxf++ = format[-1]; - *pxf = 0; - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const long *)*argv++); - break; - case kLongLong: -#if defined(_MSC_VER) - *pxf++ = 'I'; - *pxf++ = '6'; - *pxf++ = '4'; -#elif defined(__GNUC__) - *pxf++ = 'l'; - *pxf++ = 'l'; -#else -#error Please insert the appropriate 64-bit printf format for your platform. -#endif - *pxf++ = format[-1]; - *pxf = 0; - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const int64 *)*argv++); - break; - default: - VDNEVERHERE; - } - - if (pbuf - pbuf0 < precision) - zero_pad = precision - (pbuf - pbuf0); - - break; - - case L'c': - if (size == kShort) { - char buf[2] = {*(const char *)*argv++, 0}; - pbuf += VDTextAToW(pbuf, 4, buf); - } else - *pbuf++ = *(const wchar_t *)*argv++; - break; - - case L's': - if (size == kShort) { - const char *s = *(const char *const *)*argv++; - int maxsrc = strlen(s); - - if (precision >= 0 && precision < maxsrc) - maxsrc = precision; - - tempConv = VDTextAToW(s, maxsrc); - pbuf0 = const_cast(tempConv.c_str()); - - pbuf = pbuf0 + tempConv.size(); - } else { - pbuf = pbuf0 = *(wchar_t *const *)*argv++; - - while(*pbuf && precision) { - ++pbuf; - --precision; - } - } - break; - - case L'e': - case L'E': - case L'f': - case L'F': - case L'g': - case L'G': - // We place an artificial limit of 256 characters on the precision value. - { - if (precision > 256) - precision = 256; - - tempConv.resize(256); - pbuf0 = pbuf = const_cast(tempConv.data()); - - *pxf++ = '%'; - if (flags.bPrefix) - *pxf++ = '#'; - if (flags.bPositiveBlank) - *pxf++ = ' '; - if (flags.bPositiveSign) - *pxf++ = '+'; - if (precision>=0) { - *pxf++ = '.'; - *pxf++ = '*'; - } - *pxf++ = format[-1]; - *pxf = 0; - - if (precision >= 0) - pbuf += vdswprintf(pbuf, 256, xf, precision, *(const double *)*argv++); - else - pbuf += vdswprintf(pbuf, 256, xf, *(const double *)*argv++); - } - break; - - case L'n': // no flags honored; precision ignored - *(int *)(*argv++) = out.size(); - continue; - case L'p': // no flags honored; precision ignored - pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], L"%p", *(void *const *)*argv++); - break; - - case L'z': - switch(*format++) { - case L's': - { - int64 value; - - switch(size) { - case kShort: value = *(const short *)*argv++; break; - case kDefault: value = *(const int *)*argv++; break; - case kLong: value = *(const long *)*argv++; break; - case kLongLong: value = *(const int64 *)*argv++; break; - break; - default: - VDNEVERHERE; - } - - if (value < 0) - *pbuf++ = L'-'; - else if (flags.bPositiveSign) - *pbuf++ = L'+'; - else if (flags.bPositiveBlank) - *pbuf++ = L' '; - - if (value < (VD64(10) << 10)) - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d bytes", (int)value); - else if (value < (VD64(10) << 20)) - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d KB", (int)((sint32)value >> 10)); - else if (value < (VD64(10) << 30)) - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d MB", (int)((sint32)value >> 20)); - else if (value < (VD64(10) << 40)) - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d GB", (int)(value >> 30)); - else - pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d TB", (int)(value >> 40)); - } - - break; - } - break; - - } - - int string_width = (pbuf - pbuf0) + zero_pad; - int string_delta = width - string_width; - - if (!flags.bLeftAlign && string_delta > 0) { - int siz = out.size(); - out.resize(siz + string_delta, flags.bZeroPad ? L'0' : L' '); - } - - if (zero_pad) { - int siz = out.size(); - out.resize(siz + zero_pad); - std::fill(&out[siz], &out[siz+zero_pad], L'0'); - } - - if (pbuf != pbuf0) { - int siz = out.size(); - out.resize(siz + (pbuf - pbuf0)); - - std::copy(pbuf0, pbuf, &out[siz]); - } - - if (flags.bLeftAlign && string_delta > 0) { - int siz = out.size(); - out.resize(siz + string_delta); - std::fill(&out[siz], &out[siz+string_delta], L' '); - } - } - } - - out.push_back(0); - - return VDStringW(out.data()); -} - -VDStringW VDvswprintf(const wchar_t *format, int args, va_list val) { - if (args < 16) { - const void *argv[16]; - - for(int i=0; i argv(args); - - for(int i=0; i +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +int VDTextWToA(char *dst, int max_dst, const wchar_t *src, int max_src) { + VDASSERTPTR(dst); + VDASSERTPTR(src); + VDASSERT(max_dst>0); + + *dst = 0; + + int len = WideCharToMultiByte(CP_ACP, 0, src, max_src, dst, max_dst, NULL, NULL); + + // remove null terminator if source was null-terminated (source + // length was provided) + return max_src<0 && len>0 ? len-1 : len; +} + +int VDTextAToW(wchar_t *dst, int max_dst, const char *src, int max_src) { + VDASSERTPTR(dst); + VDASSERTPTR(src); + VDASSERT(max_dst>0); + + *dst = 0; + + int len = MultiByteToWideChar(CP_ACP, 0, src, max_src, dst, max_dst); + + // remove null terminator if source was null-terminated (source + // length was provided) + return max_src<0 && len>0 ? len-1 : len; +} + +VDStringA VDTextWToA(const VDStringW& sw) { + return VDTextWToA(sw.data(), sw.length()); +} + +VDStringA VDTextWToA(const wchar_t *src, int srclen) { + VDStringA s; + + if (src) { + int l = VDTextWToALength(src, srclen); + + if (l) { + s.resize(l); + VDTextWToA((char *)s.data(), l+1, src, srclen); + } + } + + return s; +} + +VDStringW VDTextAToW(const VDStringA& s) { + return VDTextAToW(s.data(), s.length()); +} + +VDStringW VDTextAToW(const char *src, int srclen) { + VDStringW sw; + + if (src) { + int l = VDTextAToWLength(src, srclen); + + if (l) { + sw.resize(l); + VDTextAToW(&sw[0], sw.length()+1, src, srclen); + } + } + + return sw; +} + +int VDTextWToALength(const wchar_t *s, int length) { + SetLastError(0); + int rv = WideCharToMultiByte(CP_ACP, 0, s, length, NULL, 0, NULL, 0); + + if (length < 0 && rv>0) + --rv; + + return rv; +} + +int VDTextAToWLength(const char *s, int length) { + SetLastError(0); + int rv = MultiByteToWideChar(CP_ACP, 0, s, length, NULL, 0); + + if (length < 0 && rv > 0) + --rv; + + return rv; +} + +namespace { + // UTF8: + // 000000000xxxxxxx -> 0xxxxxxx + // 00000yyyyyxxxxxx -> 110yyyyy 10xxxxxx + // zzzzyyyyyyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx + // uuuuuzzzzyyyyyyxxxxxx -> 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (UTF16) -> 110110wwwwzzzzyy (uuuuu = wwww+1) + // 110111yyyyxxxxxx + int VDGetCharLengthInUTF8(wchar_t c) { + if (c < 0x0080) // 7 bits + return 1; + else if (c < 0x0800) // 11 bits + return 2; + else if (c < 0x10000) // 16 bits + return 3; + else if (c < 0x200000) // 21 bits + return 4; + else { + VDASSERT(false); + return 1; // Uh oh. Well, we're screwed. + } + } + + bool VDIsUnicodeSurrogateFirst(wchar_t c) { + return (c >= 0xD800 && c < 0xDC00); + } + + bool VDIsUnicodeSurrogateSecond(wchar_t c) { + return (c >= 0xDC00 && c < 0xE000); + } +}; + +VDStringA VDTextWToU8(const VDStringW& s) { + return VDTextWToU8(s.data(), s.length()); +} + +VDStringA VDTextWToU8(const wchar_t *s, int length) { + vdfastvector temp; + + if (length<0) { + const wchar_t *t = s; + do { + ++length; + } while(*t++); + } + + while(length--) { + uint32 c = *s++; + + if (VDIsUnicodeSurrogateFirst(c)) { + if (!length || !VDIsUnicodeSurrogateSecond(*s)) { + VDASSERT(false); + c = '?'; + } else { + c = 0x10000 + ((c & 0x3ff)<<10) + (*s++ & 0x3ff); + --length; + } + } + + if (c < 0x0080) { + temp.push_back((char)c); + } else { + if (c < 0x0800) + temp.push_back((char)(0xc0 + (c>>6))); + else { + if (c < 0x10000) + temp.push_back((char)(0xe0 + (c>>12))); + else { + temp.push_back((char)(0xf0 + ((c>>18) & 0x07))); + temp.push_back((char)(0x80 + ((c>>12) & 0x3f))); + } + temp.push_back((char)(0x80 + ((c>>6) & 0x3f))); + } + temp.push_back((char)(0x80 + (c & 0x3f))); + } + } + + VDStringA a(temp.data(), temp.size()); + + return a; +} + +VDStringW VDTextU8ToW(const VDStringA& s) { + return VDTextU8ToW(s.data(), s.length()); +} + +VDStringW VDTextU8ToW(const char *s, int length) { + vdfastvector temp; + + if (length<0) { + const char *t = s; + VDASSERT(length == -1); + do { + ++length; + } while(*t++); + } + + while(length--) { + unsigned char c = (char)*s++; + uint32 wc = c; // we reconstruct UTF-32 first and then split to UTF-16 if necessary + + if (c >= 0x80) { + int required_extra = 0; + + if (c < 0xc0 || c >= 0xf7) { + VDASSERT(false); + break; + } + + while(c >= 0xc0) { + c <<= 1; + ++required_extra; + } + + wc = (c&0x3f) >> required_extra; + + do { + char d; + + if (!length-- || (((d=*s++)&0xc0)!=0x80)) + goto bad_sequence_exit; + + wc = (wc<<6) + (d&0x3f); + } while(--required_extra); + } + + // Two cases here. If we are using UTF-16, surrogates need to be split in half. If we are using + // UTF-32, surrogates need to be combined. + + if (sizeof(wchar_t) > 2) { + if (VDIsUnicodeSurrogateSecond(wc)) { + if (temp.empty() || !VDIsUnicodeSurrogateFirst(temp.back())) { + VDASSERT(false); + break; + } + + temp.back() = 0x10000 + ((temp.back()&0x3ff) << 10) + (wc & 0x3ff); + continue; + } + } else { + if (wc >= 0x10000) { + wc -= 0x10000; + temp.push_back(0xD800 + ((wc & 0x3ff) >> 10)); + wc = 0xDC00 + (wc&0x3ff); + } + } + temp.push_back(wc); + } +bad_sequence_exit: + + VDStringW w(temp.data(), temp.size()); + + return w; +} + +/////////////////////////////////////////////////////////////////////////// +// +// VirtualDub's very own printf() functions. +// +// VD[v|a]swprintf() differs from wsprintf() in the following ways: +// +// * The output is a string. +// * All parameters must be passed by pointer instead of by value. +// * The 'll' modifier permits long long / __int64 integers. +// * [n] allows picking parameters out of order. +// * %lc/%ls forces Unicode; %hc/%hs forces ANSI. + +VDStringW VDaswprintf(const wchar_t *format, int args, const void *const *argv) { + const void *const *argv0 = argv; + vdfastfixedvector out; + wchar_t c; + + VDStringW tempConv; + + while(c = *format) { + if (c != L'%') { + const wchar_t *s = format; + + while(*s && *s != L'%') + ++s; + + int len = s - format; + int clen = out.size(); + + out.resize(clen + len); + + std::copy(format, s, &out[clen]); + + format = s; + } else { + ++format; + + // check for %% + + if (*format == L'%') { + ++format; + out.push_back(L'%'); + continue; + } + + // Check for a renumbering identifier. + + if (*format == L'[') { + ++format; + + int newid = wcstol(format, const_cast(&format), 0); + + VDASSERT(newid >= 0 && newid < args); + + argv = argv0 + newid; + + VDVERIFY(*format++ == L']'); + } + + // process flags + + struct { + bool bLeftAlign:1, // pad right with spaces (priority over zero pad) + bZeroPad:1, // pad left with zeroes + bPositiveSign:1, // prefix with + or -; priority over bPositiveBlank + bPositiveBlank:1, // prefix with space for nonnegative + bPrefix:1; // prefix with 0, 0x, 0X, or force decimal point + } flags={false}; + int width = 0; + int precision = -1; + + for(;;) { + c = *format; + + if (c == L'0') + flags.bZeroPad = true; + else if (c == L' ') + flags.bPositiveBlank = true; + else if (c == L'#') + flags.bPrefix = true; + else if (c == L'-') + flags.bLeftAlign = true; + else if (c == L'+') + flags.bPositiveSign = true; + else + break; + + ++format; + } + + // process width + + c = *format; + if (c == L'*') { + ++format; + width = *(int *)*argv++; + } else if (iswdigit(c)) + width = (int)wcstol(format, const_cast(&format), 0); + + // process precision + + if (*format == L'.') { + c = *++format; + + if (c == L'*') { + ++format; + precision = *(int *)*argv++; + } else if (iswdigit(c)) + precision = (int)wcstol(format, const_cast(&format), 0); + } + + // process flags + + enum { kDefault, kLong, kLongLong, kShort } size = kDefault; + + c = *format; + + if (c == L'l') { + ++format; + size = kLong; + + if (*format == L'l') { + ++format; + size = kLongLong; + } + + } else if (c == L'h') { + ++format; + size = kShort; + } + + // process format character + + wchar_t xf[32], buf[32], *pxf = xf, *pbuf0 = buf, *pbuf = buf; + int zero_pad = 0; + + switch(*format++) { + case L'd': + case L'i': + case L'o': + case L'u': + case L'x': + case L'X': + *pxf++ = '%'; + if (flags.bPrefix) + *pxf++ = '#'; + if (flags.bPositiveBlank) + *pxf++ = ' '; + if (flags.bPositiveSign) + *pxf++ = '+'; + + switch(size) { + case kShort: + *pxf++ = 'h'; + *pxf++ = format[-1]; + *pxf = 0; + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const short *)*argv++); + break; + case kDefault: + *pxf++ = format[-1]; + *pxf = 0; + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const int *)*argv++); + break; + case kLong: + *pxf++ = 'l'; + *pxf++ = format[-1]; + *pxf = 0; + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const long *)*argv++); + break; + case kLongLong: +#if defined(_MSC_VER) + *pxf++ = 'I'; + *pxf++ = '6'; + *pxf++ = '4'; +#elif defined(__GNUC__) + *pxf++ = 'l'; + *pxf++ = 'l'; +#else +#error Please insert the appropriate 64-bit printf format for your platform. +#endif + *pxf++ = format[-1]; + *pxf = 0; + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], xf, *(const int64 *)*argv++); + break; + default: + VDNEVERHERE; + } + + if (pbuf - pbuf0 < precision) + zero_pad = precision - (pbuf - pbuf0); + + break; + + case L'c': + if (size == kShort) { + char buf[2] = {*(const char *)*argv++, 0}; + pbuf += VDTextAToW(pbuf, 4, buf); + } else + *pbuf++ = *(const wchar_t *)*argv++; + break; + + case L's': + if (size == kShort) { + const char *s = *(const char *const *)*argv++; + int maxsrc = strlen(s); + + if (precision >= 0 && precision < maxsrc) + maxsrc = precision; + + tempConv = VDTextAToW(s, maxsrc); + pbuf0 = const_cast(tempConv.c_str()); + + pbuf = pbuf0 + tempConv.size(); + } else { + pbuf = pbuf0 = *(wchar_t *const *)*argv++; + + while(*pbuf && precision) { + ++pbuf; + --precision; + } + } + break; + + case L'e': + case L'E': + case L'f': + case L'F': + case L'g': + case L'G': + // We place an artificial limit of 256 characters on the precision value. + { + if (precision > 256) + precision = 256; + + tempConv.resize(256); + pbuf0 = pbuf = const_cast(tempConv.data()); + + *pxf++ = '%'; + if (flags.bPrefix) + *pxf++ = '#'; + if (flags.bPositiveBlank) + *pxf++ = ' '; + if (flags.bPositiveSign) + *pxf++ = '+'; + if (precision>=0) { + *pxf++ = '.'; + *pxf++ = '*'; + } + *pxf++ = format[-1]; + *pxf = 0; + + if (precision >= 0) + pbuf += vdswprintf(pbuf, 256, xf, precision, *(const double *)*argv++); + else + pbuf += vdswprintf(pbuf, 256, xf, *(const double *)*argv++); + } + break; + + case L'n': // no flags honored; precision ignored + *(int *)(*argv++) = out.size(); + continue; + case L'p': // no flags honored; precision ignored + pbuf += vdswprintf(pbuf, sizeof buf / sizeof buf[0], L"%p", *(void *const *)*argv++); + break; + + case L'z': + switch(*format++) { + case L's': + { + int64 value; + + switch(size) { + case kShort: value = *(const short *)*argv++; break; + case kDefault: value = *(const int *)*argv++; break; + case kLong: value = *(const long *)*argv++; break; + case kLongLong: value = *(const int64 *)*argv++; break; + break; + default: + VDNEVERHERE; + } + + if (value < 0) + *pbuf++ = L'-'; + else if (flags.bPositiveSign) + *pbuf++ = L'+'; + else if (flags.bPositiveBlank) + *pbuf++ = L' '; + + if (value < (VD64(10) << 10)) + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d bytes", (int)value); + else if (value < (VD64(10) << 20)) + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d KB", (int)((sint32)value >> 10)); + else if (value < (VD64(10) << 30)) + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d MB", (int)((sint32)value >> 20)); + else if (value < (VD64(10) << 40)) + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d GB", (int)(value >> 30)); + else + pbuf += vdswprintf(pbuf, (buf + sizeof(buf) / sizeof(buf[0])) - pbuf, L"%d TB", (int)(value >> 40)); + } + + break; + } + break; + + } + + int string_width = (pbuf - pbuf0) + zero_pad; + int string_delta = width - string_width; + + if (!flags.bLeftAlign && string_delta > 0) { + int siz = out.size(); + out.resize(siz + string_delta, flags.bZeroPad ? L'0' : L' '); + } + + if (zero_pad) { + int siz = out.size(); + out.resize(siz + zero_pad); + std::fill(&out[siz], &out[siz+zero_pad], L'0'); + } + + if (pbuf != pbuf0) { + int siz = out.size(); + out.resize(siz + (pbuf - pbuf0)); + + std::copy(pbuf0, pbuf, &out[siz]); + } + + if (flags.bLeftAlign && string_delta > 0) { + int siz = out.size(); + out.resize(siz + string_delta); + std::fill(&out[siz], &out[siz+string_delta], L' '); + } + } + } + + out.push_back(0); + + return VDStringW(out.data()); +} + +VDStringW VDvswprintf(const wchar_t *format, int args, va_list val) { + if (args < 16) { + const void *argv[16]; + + for(int i=0; i argv(args); + + for(int i=0; i - -#include - -#include -#include -#include -#include -#include - -namespace { - // - // This apparently came from one a talk by one of the Visual Studio - // developers, i.e. I didn't write it. - // - #define MS_VC_EXCEPTION 0x406d1388 - - typedef struct tagTHREADNAME_INFO - { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in same addr space) - DWORD dwThreadID; // thread ID (-1 caller thread) - DWORD dwFlags; // reserved for future use, most be zero - } THREADNAME_INFO; -} - -VDThreadID VDGetCurrentThreadID() { - return (VDThreadID)GetCurrentThreadId(); -} - -VDProcessId VDGetCurrentProcessId() { - return (VDProcessId)GetCurrentProcessId(); -} - -uint32 VDGetLogicalProcessorCount() { - DWORD_PTR processAffinityMask; - DWORD_PTR systemAffinityMask; - if (!::GetProcessAffinityMask(::GetCurrentProcess(), &processAffinityMask, &systemAffinityMask)) - return 1; - - // avoid unnecessary WTFs - if (!processAffinityMask) - return 1; - - // We use the process affinity mask as that's the number of logical processors we'll - // actually be working with. - return VDCountBits(processAffinityMask); -} - -void VDSetThreadDebugName(VDThreadID tid, const char *name) { - #ifdef VD_COMPILER_MSVC - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = name; - info.dwThreadID = tid; - info.dwFlags = 0; - - __try { - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info); - } __except (EXCEPTION_CONTINUE_EXECUTION) { - } - #endif -} - -void VDThreadSleep(int milliseconds) { - if (milliseconds > 0) - ::Sleep(milliseconds); -} - -/////////////////////////////////////////////////////////////////////////// - -VDThread::VDThread(const char *pszDebugName) - : mpszDebugName(pszDebugName) - , mhThread(0) - , mThreadID(0) - , mThreadPriority(INT_MIN) -{ -} - -VDThread::~VDThread() throw() { - if (isThreadAttached()) - ThreadWait(); -} - -bool VDThread::ThreadStart() { - VDASSERT(!isThreadAttached()); - - if (!isThreadAttached()) { - mhThread = (void *)_beginthreadex(NULL, 0, StaticThreadStart, this, 0, &mThreadID); - - if (mhThread && mThreadPriority != INT_MIN) - ::SetThreadPriority(mhThread, mThreadPriority); - } - - return mhThread != 0; -} - -void VDThread::ThreadDetach() { - if (isThreadAttached()) { - CloseHandle((HANDLE)mhThread); - mhThread = NULL; - mThreadID = 0; - } -} - -void VDThread::ThreadWait() { - if (isThreadAttached()) { - WaitForSingleObject((HANDLE)mhThread, INFINITE); - ThreadDetach(); - mThreadID = 0; - } -} - -void VDThread::ThreadSetPriority(int priority) { - if (mThreadPriority != priority) { - mThreadPriority = priority; - - if (mhThread && priority != INT_MIN) - ::SetThreadPriority(mhThread, priority); - } -} - -bool VDThread::isThreadActive() { - if (isThreadAttached()) { - if (WAIT_TIMEOUT == WaitForSingleObject((HANDLE)mhThread, 0)) - return true; - - ThreadDetach(); - mThreadID = 0; - } - return false; -} - -void VDThread::ThreadFinish() { - _endthreadex(0); -} - -void *VDThread::ThreadLocation() const { - if (!isThreadAttached()) - return NULL; - - CONTEXT ctx; - - ctx.ContextFlags = CONTEXT_CONTROL; - - SuspendThread(mhThread); - GetThreadContext(mhThread, &ctx); - ResumeThread(mhThread); - -#if defined(VD_CPU_AMD64) - return (void *)ctx.Rip; -#elif defined(VD_CPU_X86) - return (void *)ctx.Eip; -#elif defined(VD_CPU_ARM) - return (void *)ctx.Pc; -#endif -} - -/////////////////////////////////////////////////////////////////////////// - -unsigned __stdcall VDThread::StaticThreadStart(void *pThisAsVoid) { - VDThread *pThis = static_cast(pThisAsVoid); - - // We cannot use mThreadID here because it might already have been - // invalidated by a detach in the main thread. - if (pThis->mpszDebugName) - VDSetThreadDebugName(GetCurrentThreadId(), pThis->mpszDebugName); - - VDInitThreadData(pThis->mpszDebugName); - - vdprotected1("running thread \"%.64s\"", const char *, pThis->mpszDebugName) { - pThis->ThreadRun(); - } - - // NOTE: Do not put anything referencing this here, since our object - // may have been destroyed by the threaded code. - - VDDeinitThreadData(); - - return 0; -} - -/////////////////////////////////////////////////////////////////////////// - -void VDCriticalSection::StructCheck() { - VDASSERTCT(sizeof(CritSec) == sizeof(CRITICAL_SECTION)); -} - -/////////////////////////////////////////////////////////////////////////// - -VDSignal::VDSignal() { - hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); -} - -VDSignalPersistent::VDSignalPersistent() { - hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); -} - -VDSignalBase::~VDSignalBase() { - CloseHandle(hEvent); -} - -void VDSignalBase::signal() { - SetEvent(hEvent); -} - -void VDSignalBase::wait() { - WaitForSingleObject(hEvent, INFINITE); -} - -bool VDSignalBase::check() { - return WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0); -} - -int VDSignalBase::wait(VDSignalBase *second) { - HANDLE hArray[16]; - DWORD dwRet; - - hArray[0] = hEvent; - hArray[1] = second->hEvent; - - dwRet = WaitForMultipleObjects(2, hArray, FALSE, INFINITE); - - return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; -} - -int VDSignalBase::wait(VDSignalBase *second, VDSignalBase *third) { - HANDLE hArray[3]; - DWORD dwRet; - - hArray[0] = hEvent; - hArray[1] = second->hEvent; - hArray[2] = third->hEvent; - - dwRet = WaitForMultipleObjects(3, hArray, FALSE, INFINITE); - - return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; -} - -int VDSignalBase::waitMultiple(const VDSignalBase **signals, int count) { - VDASSERT(count <= 16); - - HANDLE handles[16]; - int active = 0; - - for(int i=0; ihEvent; - - if (h) - handles[active++] = h; - } - - if (!active) - return -1; - - DWORD dwRet = WaitForMultipleObjects(active, handles, FALSE, INFINITE); - - return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; -} - -bool VDSignalBase::tryWait(uint32 timeoutMillisec) { - return WAIT_OBJECT_0 == WaitForSingleObject(hEvent, timeoutMillisec); -} - -void VDSignalPersistent::unsignal() { - ResetEvent(hEvent); -} - -VDSemaphore::VDSemaphore(int initial) - : mKernelSema(CreateSemaphore(NULL, initial, 0x0fffffff, NULL)) -{ -} - -VDSemaphore::~VDSemaphore() { - if (mKernelSema) - CloseHandle(mKernelSema); -} - -void VDSemaphore::Reset(int count) { - // reset semaphore to zero - while(WAIT_OBJECT_0 == WaitForSingleObject(mKernelSema, 0)) - ; - - if (count) - ReleaseSemaphore(mKernelSema, count, NULL); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +#include + +#include +#include +#include +#include +#include + +namespace { + // + // This apparently came from one a talk by one of the Visual Studio + // developers, i.e. I didn't write it. + // + #define MS_VC_EXCEPTION 0x406d1388 + + typedef struct tagTHREADNAME_INFO + { + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in same addr space) + DWORD dwThreadID; // thread ID (-1 caller thread) + DWORD dwFlags; // reserved for future use, most be zero + } THREADNAME_INFO; +} + +VDThreadID VDGetCurrentThreadID() { + return (VDThreadID)GetCurrentThreadId(); +} + +VDProcessId VDGetCurrentProcessId() { + return (VDProcessId)GetCurrentProcessId(); +} + +uint32 VDGetLogicalProcessorCount() { + DWORD_PTR processAffinityMask; + DWORD_PTR systemAffinityMask; + if (!::GetProcessAffinityMask(::GetCurrentProcess(), &processAffinityMask, &systemAffinityMask)) + return 1; + + // avoid unnecessary WTFs + if (!processAffinityMask) + return 1; + + // We use the process affinity mask as that's the number of logical processors we'll + // actually be working with. + return VDCountBits(processAffinityMask); +} + +void VDSetThreadDebugName(VDThreadID tid, const char *name) { + #ifdef VD_COMPILER_MSVC + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = tid; + info.dwFlags = 0; + + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info); + } __except (EXCEPTION_CONTINUE_EXECUTION) { + } + #endif +} + +void VDThreadSleep(int milliseconds) { + if (milliseconds > 0) + ::Sleep(milliseconds); +} + +/////////////////////////////////////////////////////////////////////////// + +VDThread::VDThread(const char *pszDebugName) + : mpszDebugName(pszDebugName) + , mhThread(0) + , mThreadID(0) + , mThreadPriority(INT_MIN) +{ +} + +VDThread::~VDThread() throw() { + if (isThreadAttached()) + ThreadWait(); +} + +bool VDThread::ThreadStart() { + VDASSERT(!isThreadAttached()); + + if (!isThreadAttached()) { + mhThread = (void *)_beginthreadex(NULL, 0, StaticThreadStart, this, 0, &mThreadID); + + if (mhThread && mThreadPriority != INT_MIN) + ::SetThreadPriority(mhThread, mThreadPriority); + } + + return mhThread != 0; +} + +void VDThread::ThreadDetach() { + if (isThreadAttached()) { + CloseHandle((HANDLE)mhThread); + mhThread = NULL; + mThreadID = 0; + } +} + +void VDThread::ThreadWait() { + if (isThreadAttached()) { + WaitForSingleObject((HANDLE)mhThread, INFINITE); + ThreadDetach(); + mThreadID = 0; + } +} + +void VDThread::ThreadSetPriority(int priority) { + if (mThreadPriority != priority) { + mThreadPriority = priority; + + if (mhThread && priority != INT_MIN) + ::SetThreadPriority(mhThread, priority); + } +} + +bool VDThread::isThreadActive() { + if (isThreadAttached()) { + if (WAIT_TIMEOUT == WaitForSingleObject((HANDLE)mhThread, 0)) + return true; + + ThreadDetach(); + mThreadID = 0; + } + return false; +} + +void VDThread::ThreadFinish() { + _endthreadex(0); +} + +void *VDThread::ThreadLocation() const { + if (!isThreadAttached()) + return NULL; + + CONTEXT ctx; + + ctx.ContextFlags = CONTEXT_CONTROL; + + SuspendThread(mhThread); + GetThreadContext(mhThread, &ctx); + ResumeThread(mhThread); + +#if defined(VD_CPU_AMD64) + return (void *)ctx.Rip; +#elif defined(VD_CPU_X86) + return (void *)ctx.Eip; +#elif defined(VD_CPU_ARM) + return (void *)ctx.Pc; +#endif +} + +/////////////////////////////////////////////////////////////////////////// + +unsigned __stdcall VDThread::StaticThreadStart(void *pThisAsVoid) { + VDThread *pThis = static_cast(pThisAsVoid); + + // We cannot use mThreadID here because it might already have been + // invalidated by a detach in the main thread. + if (pThis->mpszDebugName) + VDSetThreadDebugName(GetCurrentThreadId(), pThis->mpszDebugName); + + VDInitThreadData(pThis->mpszDebugName); + + vdprotected1("running thread \"%.64s\"", const char *, pThis->mpszDebugName) { + pThis->ThreadRun(); + } + + // NOTE: Do not put anything referencing this here, since our object + // may have been destroyed by the threaded code. + + VDDeinitThreadData(); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// + +void VDCriticalSection::StructCheck() { + VDASSERTCT(sizeof(CritSec) == sizeof(CRITICAL_SECTION)); +} + +/////////////////////////////////////////////////////////////////////////// + +VDSignal::VDSignal() { + hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); +} + +VDSignalPersistent::VDSignalPersistent() { + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); +} + +VDSignalBase::~VDSignalBase() { + CloseHandle(hEvent); +} + +void VDSignalBase::signal() { + SetEvent(hEvent); +} + +void VDSignalBase::wait() { + WaitForSingleObject(hEvent, INFINITE); +} + +bool VDSignalBase::check() { + return WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0); +} + +int VDSignalBase::wait(VDSignalBase *second) { + HANDLE hArray[16]; + DWORD dwRet; + + hArray[0] = hEvent; + hArray[1] = second->hEvent; + + dwRet = WaitForMultipleObjects(2, hArray, FALSE, INFINITE); + + return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; +} + +int VDSignalBase::wait(VDSignalBase *second, VDSignalBase *third) { + HANDLE hArray[3]; + DWORD dwRet; + + hArray[0] = hEvent; + hArray[1] = second->hEvent; + hArray[2] = third->hEvent; + + dwRet = WaitForMultipleObjects(3, hArray, FALSE, INFINITE); + + return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; +} + +int VDSignalBase::waitMultiple(const VDSignalBase **signals, int count) { + VDASSERT(count <= 16); + + HANDLE handles[16]; + int active = 0; + + for(int i=0; ihEvent; + + if (h) + handles[active++] = h; + } + + if (!active) + return -1; + + DWORD dwRet = WaitForMultipleObjects(active, handles, FALSE, INFINITE); + + return dwRet == WAIT_FAILED ? -1 : dwRet - WAIT_OBJECT_0; +} + +bool VDSignalBase::tryWait(uint32 timeoutMillisec) { + return WAIT_OBJECT_0 == WaitForSingleObject(hEvent, timeoutMillisec); +} + +void VDSignalPersistent::unsignal() { + ResetEvent(hEvent); +} + +VDSemaphore::VDSemaphore(int initial) + : mKernelSema(CreateSemaphore(NULL, initial, 0x0fffffff, NULL)) +{ +} + +VDSemaphore::~VDSemaphore() { + if (mKernelSema) + CloseHandle(mKernelSema); +} + +void VDSemaphore::Reset(int count) { + // reset semaphore to zero + while(WAIT_OBJECT_0 == WaitForSingleObject(mKernelSema, 0)) + ; + + if (count) + ReleaseSemaphore(mKernelSema, count, NULL); +} diff --git a/src/thirdparty/VirtualDub/system/source/thunk.cpp b/src/thirdparty/VirtualDub/system/source/thunk.cpp index 6bfddddfaed..698510bc5e6 100644 --- a/src/thirdparty/VirtualDub/system/source/thunk.cpp +++ b/src/thirdparty/VirtualDub/system/source/thunk.cpp @@ -1,308 +1,308 @@ -#include "stdafx.h" -#include -#include -#include -#include -#include -#include - -class IVDJITAllocator {}; - -class VDJITAllocator : public vdrefcounted { -public: - VDJITAllocator(); - ~VDJITAllocator(); - - void *Allocate(size_t len); - void Free(void *p, size_t len); - - void EndUpdate(void *p, size_t len); - -protected: - typedef std::map FreeChunks; - FreeChunks mFreeChunks; - FreeChunks::iterator mNextChunk; - - typedef std::map Allocations; - Allocations mAllocations; - - uintptr mAllocationGranularity; -}; - -VDJITAllocator::VDJITAllocator() - : mNextChunk(mFreeChunks.end()) -{ - SYSTEM_INFO si; - GetSystemInfo(&si); - - mAllocationGranularity = si.dwAllocationGranularity; -} - -VDJITAllocator::~VDJITAllocator() { - for(Allocations::iterator it(mAllocations.begin()), itEnd(mAllocations.end()); it!=itEnd; ++it) { - VirtualFree(it->first, 0, MEM_RELEASE); - } -} - -void *VDJITAllocator::Allocate(size_t len) { - len = (len + 15) & ~(size_t)15; - - FreeChunks::iterator itMark(mNextChunk), itEnd(mFreeChunks.end()), it(itMark); - - if (it == itEnd) - it = mFreeChunks.begin(); - - for(;;) { - for(; it!=itEnd; ++it) { - if (it->second >= len) { - it->second -= len; - - void *p = (char *)it->first + it->second; - - if (!it->second) { - if (mNextChunk == it) - ++mNextChunk; - - mFreeChunks.erase(it); - } - - return p; - } - } - - if (itEnd == itMark) - break; - - it = mFreeChunks.begin(); - itEnd = itMark; - } - - size_t alloclen = (len + mAllocationGranularity - 1) & ~(mAllocationGranularity - 1); - - void *p = VirtualAlloc(NULL, alloclen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (p) { - try { - Allocations::iterator itA(mAllocations.insert(Allocations::value_type(p, alloclen)).first); - - try { - if (len < alloclen) - mFreeChunks.insert(FreeChunks::value_type((char *)p + len, alloclen - len)); - - } catch(...) { - mAllocations.erase(itA); - throw; - } - } catch(...) { - VirtualFree(p, 0, MEM_RELEASE); - p = NULL; - } - } - - return p; -} - -void VDJITAllocator::Free(void *p, size_t len) { - VDASSERT(p); - VDASSERT(len < 0x10000); - - FreeChunks::iterator cur(mFreeChunks.lower_bound(p)); - if (cur != mFreeChunks.end() && (char *)p + len == cur->first) { - len += cur->second; - if (mNextChunk == cur) - ++mNextChunk; - - mFreeChunks.erase(cur++); - } - - if (cur != mFreeChunks.begin()) { - FreeChunks::iterator prev(cur); - - --prev; - if ((char *)prev->first + prev->second == p) { - p = prev->first; - len += prev->second; - if (mNextChunk == prev) - ++mNextChunk; - mFreeChunks.erase(prev); - } - } - - uintptr start = (size_t)p; - uintptr end = start + len; - - if (!((start | end) & (mAllocationGranularity - 1))) { - Allocations::iterator it(mAllocations.find(p)); - - if (it != mAllocations.end()) { - VirtualFree((void *)start, 0, MEM_RELEASE); - mAllocations.erase(it); - return; - } - } - - mFreeChunks.insert(FreeChunks::value_type((void *)start, end-start)); -} - -void VDJITAllocator::EndUpdate(void *p, size_t len) { - FlushInstructionCache(GetCurrentProcess(), p, len); -} - -/////////////////////////////////////////////////////////////////////////// - -VDJITAllocator *g_pVDJITAllocator; -VDAtomicInt g_VDJITAllocatorLock; - -bool VDInitThunkAllocator() { - bool success = true; - - while(g_VDJITAllocatorLock.xchg(1)) - ::Sleep(1); - - if (!g_pVDJITAllocator) { - g_pVDJITAllocator = new_nothrow VDJITAllocator; - if (!g_pVDJITAllocator) - success = false; - } - - if (success) - g_pVDJITAllocator->AddRef(); - - VDVERIFY(1 == g_VDJITAllocatorLock.xchg(0)); - - return success; -} - -void VDShutdownThunkAllocator() { - while(g_VDJITAllocatorLock.xchg(1)) - ::Sleep(1); - - VDASSERT(g_pVDJITAllocator); - - if (!g_pVDJITAllocator->Release()) - g_pVDJITAllocator = NULL; - - VDVERIFY(1 == g_VDJITAllocatorLock.xchg(0)); -} - -void *VDAllocateThunkMemory(size_t len) { - return g_pVDJITAllocator->Allocate(len); -} - -void VDFreeThunkMemory(void *p, size_t len) { - g_pVDJITAllocator->Free(p, len); -} - -void VDSetThunkMemory(void *p, const void *src, size_t len) { - memcpy(p, src, len); - g_pVDJITAllocator->EndUpdate(p, len); -} - -void VDFlushThunkMemory(void *p, size_t len) { - g_pVDJITAllocator->EndUpdate(p, len); -} - -/////////////////////////////////////////////////////////////////////////// - -#ifdef _M_AMD64 - extern "C" void VDMethodToFunctionThunk64(); -#else - extern "C" void VDMethodToFunctionThunk32(); - extern "C" void VDMethodToFunctionThunk32_4(); - extern "C" void VDMethodToFunctionThunk32_8(); - extern "C" void VDMethodToFunctionThunk32_12(); - extern "C" void VDMethodToFunctionThunk32_16(); -#endif - -VDFunctionThunk *VDCreateFunctionThunkFromMethod(void *method, void *pThis, size_t argbytes, bool stdcall_thunk) { -#if defined(_M_IX86) - void *pThunk = VDAllocateThunkMemory(16); - - if (!pThunk) - return NULL; - - if (stdcall_thunk || !argbytes) { // thiscall -> stdcall (easy case) - uint8 thunkbytes[16]={ - 0xB9, 0x00, 0x00, 0x00, 0x00, // mov ecx, this - 0xE9, 0x00, 0x00, 0x00, 0x00 // jmp fn - }; - - - VDWriteUnalignedLEU32(thunkbytes+1, (uint32)(uintptr)pThis); - VDWriteUnalignedLEU32(thunkbytes+6, (uint32)method - ((uint32)pThunk + 10)); - - VDSetThunkMemory(pThunk, thunkbytes, 15); - } else { // thiscall -> cdecl (hard case) - uint8 thunkbytes[16]={ - 0xE8, 0x00, 0x00, 0x00, 0x00, // call VDFunctionThunk32 - 0xC3, // ret - argbytes, // db argbytes - 0, // db 0 - 0x00, 0x00, 0x00, 0x00, // dd method - 0x00, 0x00, 0x00, 0x00, // dd this - }; - - void (*adapter)(); - - switch(argbytes) { - case 4: adapter = VDMethodToFunctionThunk32_4; break; - case 8: adapter = VDMethodToFunctionThunk32_8; break; - case 12: adapter = VDMethodToFunctionThunk32_12; break; - case 16: adapter = VDMethodToFunctionThunk32_16; break; - default: adapter = VDMethodToFunctionThunk32; break; - } - - VDWriteUnalignedLEU32(thunkbytes+1, (uint32)(uintptr)adapter - ((uint32)pThunk + 5)); - VDWriteUnalignedLEU32(thunkbytes+8, (uint32)(uintptr)method); - VDWriteUnalignedLEU32(thunkbytes+12, (uint32)(uintptr)pThis); - - VDSetThunkMemory(pThunk, thunkbytes, 16); - } - - return (VDFunctionThunk *)pThunk; -#elif defined(_M_AMD64) - void *pThunk = VDAllocateThunkMemory(44); - if (!pThunk) - return NULL; - - uint8 thunkbytes[44]={ - 0x48, 0x8D, 0x05, 0x09, 0x00, 0x00, 0x00, // lea rax, [rip+9] - 0xFF, 0x25, 0x03, 0x00, 0x00, 0x00, // jmp qword ptr [rip+3] - 0x90, // nop - 0x90, // nop - 0x90, // nop - 0, 0, 0, 0, 0, 0, 0, 0, // dq VDFunctionThunk64 - 0, 0, 0, 0, 0, 0, 0, 0, // dq method - 0, 0, 0, 0, 0, 0, 0, 0, // dq this - 0, 0, 0, 0 // dd argspillbytes - }; - - VDWriteUnalignedLEU64(thunkbytes+16, (uint64)(uintptr)VDMethodToFunctionThunk64); - VDWriteUnalignedLEU64(thunkbytes+24, (uint64)(uintptr)method); - VDWriteUnalignedLEU64(thunkbytes+32, (uint64)(uintptr)pThis); - - // The stack must be aligned to a 16 byte boundary when the CALL - // instruction occurs. On entry to VDFunctionThunk64(), the stack is misaligned - // to 16n+8. Therefore, the number of argbytes must be 16m+8 and the number of - // argspillbytes must be 16m+8-24. - VDWriteUnalignedLEU32(thunkbytes+40, argbytes < 32 ? 0 : ((argbytes - 16 + 15) & ~15)); - - VDSetThunkMemory(pThunk, thunkbytes, 44); - - return (VDFunctionThunk *)pThunk; -#else - return NULL; -#endif -} - -void VDDestroyFunctionThunk(VDFunctionThunk *pFnThunk) { - // validate thunk -#if defined(_M_IX86) - VDASSERT(((const uint8 *)pFnThunk)[0] == 0xB9 || ((const uint8 *)pFnThunk)[0] == 0xE8); - VDFreeThunkMemory(pFnThunk, 16); -#elif defined(_M_AMD64) - VDFreeThunkMemory(pFnThunk, 44); -#else - VDASSERT(false); -#endif - -} +#include "stdafx.h" +#include +#include +#include +#include +#include +#include + +class IVDJITAllocator {}; + +class VDJITAllocator : public vdrefcounted { +public: + VDJITAllocator(); + ~VDJITAllocator(); + + void *Allocate(size_t len); + void Free(void *p, size_t len); + + void EndUpdate(void *p, size_t len); + +protected: + typedef std::map FreeChunks; + FreeChunks mFreeChunks; + FreeChunks::iterator mNextChunk; + + typedef std::map Allocations; + Allocations mAllocations; + + uintptr mAllocationGranularity; +}; + +VDJITAllocator::VDJITAllocator() + : mNextChunk(mFreeChunks.end()) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + + mAllocationGranularity = si.dwAllocationGranularity; +} + +VDJITAllocator::~VDJITAllocator() { + for(Allocations::iterator it(mAllocations.begin()), itEnd(mAllocations.end()); it!=itEnd; ++it) { + VirtualFree(it->first, 0, MEM_RELEASE); + } +} + +void *VDJITAllocator::Allocate(size_t len) { + len = (len + 15) & ~(size_t)15; + + FreeChunks::iterator itMark(mNextChunk), itEnd(mFreeChunks.end()), it(itMark); + + if (it == itEnd) + it = mFreeChunks.begin(); + + for(;;) { + for(; it!=itEnd; ++it) { + if (it->second >= len) { + it->second -= len; + + void *p = (char *)it->first + it->second; + + if (!it->second) { + if (mNextChunk == it) + ++mNextChunk; + + mFreeChunks.erase(it); + } + + return p; + } + } + + if (itEnd == itMark) + break; + + it = mFreeChunks.begin(); + itEnd = itMark; + } + + size_t alloclen = (len + mAllocationGranularity - 1) & ~(mAllocationGranularity - 1); + + void *p = VirtualAlloc(NULL, alloclen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (p) { + try { + Allocations::iterator itA(mAllocations.insert(Allocations::value_type(p, alloclen)).first); + + try { + if (len < alloclen) + mFreeChunks.insert(FreeChunks::value_type((char *)p + len, alloclen - len)); + + } catch(...) { + mAllocations.erase(itA); + throw; + } + } catch(...) { + VirtualFree(p, 0, MEM_RELEASE); + p = NULL; + } + } + + return p; +} + +void VDJITAllocator::Free(void *p, size_t len) { + VDASSERT(p); + VDASSERT(len < 0x10000); + + FreeChunks::iterator cur(mFreeChunks.lower_bound(p)); + if (cur != mFreeChunks.end() && (char *)p + len == cur->first) { + len += cur->second; + if (mNextChunk == cur) + ++mNextChunk; + + mFreeChunks.erase(cur++); + } + + if (cur != mFreeChunks.begin()) { + FreeChunks::iterator prev(cur); + + --prev; + if ((char *)prev->first + prev->second == p) { + p = prev->first; + len += prev->second; + if (mNextChunk == prev) + ++mNextChunk; + mFreeChunks.erase(prev); + } + } + + uintptr start = (size_t)p; + uintptr end = start + len; + + if (!((start | end) & (mAllocationGranularity - 1))) { + Allocations::iterator it(mAllocations.find(p)); + + if (it != mAllocations.end()) { + VirtualFree((void *)start, 0, MEM_RELEASE); + mAllocations.erase(it); + return; + } + } + + mFreeChunks.insert(FreeChunks::value_type((void *)start, end-start)); +} + +void VDJITAllocator::EndUpdate(void *p, size_t len) { + FlushInstructionCache(GetCurrentProcess(), p, len); +} + +/////////////////////////////////////////////////////////////////////////// + +VDJITAllocator *g_pVDJITAllocator; +VDAtomicInt g_VDJITAllocatorLock; + +bool VDInitThunkAllocator() { + bool success = true; + + while(g_VDJITAllocatorLock.xchg(1)) + ::Sleep(1); + + if (!g_pVDJITAllocator) { + g_pVDJITAllocator = new_nothrow VDJITAllocator; + if (!g_pVDJITAllocator) + success = false; + } + + if (success) + g_pVDJITAllocator->AddRef(); + + VDVERIFY(1 == g_VDJITAllocatorLock.xchg(0)); + + return success; +} + +void VDShutdownThunkAllocator() { + while(g_VDJITAllocatorLock.xchg(1)) + ::Sleep(1); + + VDASSERT(g_pVDJITAllocator); + + if (!g_pVDJITAllocator->Release()) + g_pVDJITAllocator = NULL; + + VDVERIFY(1 == g_VDJITAllocatorLock.xchg(0)); +} + +void *VDAllocateThunkMemory(size_t len) { + return g_pVDJITAllocator->Allocate(len); +} + +void VDFreeThunkMemory(void *p, size_t len) { + g_pVDJITAllocator->Free(p, len); +} + +void VDSetThunkMemory(void *p, const void *src, size_t len) { + memcpy(p, src, len); + g_pVDJITAllocator->EndUpdate(p, len); +} + +void VDFlushThunkMemory(void *p, size_t len) { + g_pVDJITAllocator->EndUpdate(p, len); +} + +/////////////////////////////////////////////////////////////////////////// + +#ifdef _M_AMD64 + extern "C" void VDMethodToFunctionThunk64(); +#else + extern "C" void VDMethodToFunctionThunk32(); + extern "C" void VDMethodToFunctionThunk32_4(); + extern "C" void VDMethodToFunctionThunk32_8(); + extern "C" void VDMethodToFunctionThunk32_12(); + extern "C" void VDMethodToFunctionThunk32_16(); +#endif + +VDFunctionThunk *VDCreateFunctionThunkFromMethod(void *method, void *pThis, size_t argbytes, bool stdcall_thunk) { +#if defined(_M_IX86) + void *pThunk = VDAllocateThunkMemory(16); + + if (!pThunk) + return NULL; + + if (stdcall_thunk || !argbytes) { // thiscall -> stdcall (easy case) + uint8 thunkbytes[16]={ + 0xB9, 0x00, 0x00, 0x00, 0x00, // mov ecx, this + 0xE9, 0x00, 0x00, 0x00, 0x00 // jmp fn + }; + + + VDWriteUnalignedLEU32(thunkbytes+1, (uint32)(uintptr)pThis); + VDWriteUnalignedLEU32(thunkbytes+6, (uint32)method - ((uint32)pThunk + 10)); + + VDSetThunkMemory(pThunk, thunkbytes, 15); + } else { // thiscall -> cdecl (hard case) + uint8 thunkbytes[16]={ + 0xE8, 0x00, 0x00, 0x00, 0x00, // call VDFunctionThunk32 + 0xC3, // ret + argbytes, // db argbytes + 0, // db 0 + 0x00, 0x00, 0x00, 0x00, // dd method + 0x00, 0x00, 0x00, 0x00, // dd this + }; + + void (*adapter)(); + + switch(argbytes) { + case 4: adapter = VDMethodToFunctionThunk32_4; break; + case 8: adapter = VDMethodToFunctionThunk32_8; break; + case 12: adapter = VDMethodToFunctionThunk32_12; break; + case 16: adapter = VDMethodToFunctionThunk32_16; break; + default: adapter = VDMethodToFunctionThunk32; break; + } + + VDWriteUnalignedLEU32(thunkbytes+1, (uint32)(uintptr)adapter - ((uint32)pThunk + 5)); + VDWriteUnalignedLEU32(thunkbytes+8, (uint32)(uintptr)method); + VDWriteUnalignedLEU32(thunkbytes+12, (uint32)(uintptr)pThis); + + VDSetThunkMemory(pThunk, thunkbytes, 16); + } + + return (VDFunctionThunk *)pThunk; +#elif defined(_M_AMD64) + void *pThunk = VDAllocateThunkMemory(44); + if (!pThunk) + return NULL; + + uint8 thunkbytes[44]={ + 0x48, 0x8D, 0x05, 0x09, 0x00, 0x00, 0x00, // lea rax, [rip+9] + 0xFF, 0x25, 0x03, 0x00, 0x00, 0x00, // jmp qword ptr [rip+3] + 0x90, // nop + 0x90, // nop + 0x90, // nop + 0, 0, 0, 0, 0, 0, 0, 0, // dq VDFunctionThunk64 + 0, 0, 0, 0, 0, 0, 0, 0, // dq method + 0, 0, 0, 0, 0, 0, 0, 0, // dq this + 0, 0, 0, 0 // dd argspillbytes + }; + + VDWriteUnalignedLEU64(thunkbytes+16, (uint64)(uintptr)VDMethodToFunctionThunk64); + VDWriteUnalignedLEU64(thunkbytes+24, (uint64)(uintptr)method); + VDWriteUnalignedLEU64(thunkbytes+32, (uint64)(uintptr)pThis); + + // The stack must be aligned to a 16 byte boundary when the CALL + // instruction occurs. On entry to VDFunctionThunk64(), the stack is misaligned + // to 16n+8. Therefore, the number of argbytes must be 16m+8 and the number of + // argspillbytes must be 16m+8-24. + VDWriteUnalignedLEU32(thunkbytes+40, argbytes < 32 ? 0 : ((argbytes - 16 + 15) & ~15)); + + VDSetThunkMemory(pThunk, thunkbytes, 44); + + return (VDFunctionThunk *)pThunk; +#else + return NULL; +#endif +} + +void VDDestroyFunctionThunk(VDFunctionThunk *pFnThunk) { + // validate thunk +#if defined(_M_IX86) + VDASSERT(((const uint8 *)pFnThunk)[0] == 0xB9 || ((const uint8 *)pFnThunk)[0] == 0xE8); + VDFreeThunkMemory(pFnThunk, 16); +#elif defined(_M_AMD64) + VDFreeThunkMemory(pFnThunk, 44); +#else + VDASSERT(false); +#endif + +} diff --git a/src/thirdparty/VirtualDub/system/source/tls.cpp b/src/thirdparty/VirtualDub/system/source/tls.cpp index e5411b9b584..71044d1e50f 100644 --- a/src/thirdparty/VirtualDub/system/source/tls.cpp +++ b/src/thirdparty/VirtualDub/system/source/tls.cpp @@ -1,43 +1,43 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include - -VDThreadInitHook g_pInitHook; - -void VDInitThreadData(const char *pszThreadName) { - if (g_pInitHook) - g_pInitHook(true, pszThreadName); -} - -void VDDeinitThreadData() { - if (g_pInitHook) - g_pInitHook(false, NULL); -} - -void VDSetThreadInitHook(VDThreadInitHook pHook) { - g_pInitHook = pHook; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include + +VDThreadInitHook g_pInitHook; + +void VDInitThreadData(const char *pszThreadName) { + if (g_pInitHook) + g_pInitHook(true, pszThreadName); +} + +void VDDeinitThreadData() { + if (g_pInitHook) + g_pInitHook(false, NULL); +} + +void VDSetThreadInitHook(VDThreadInitHook pHook) { + g_pInitHook = pHook; +} diff --git a/src/thirdparty/VirtualDub/system/source/vdstl.cpp b/src/thirdparty/VirtualDub/system/source/vdstl.cpp index 48edd6883da..819ecd15b41 100644 --- a/src/thirdparty/VirtualDub/system/source/vdstl.cpp +++ b/src/thirdparty/VirtualDub/system/source/vdstl.cpp @@ -1,37 +1,37 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2008 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -void VDNORETURN vdallocator_base::throw_oom(size_t n, size_t elsize) { - size_t nbytes = ~(size_t)0; - - if (n <= nbytes / elsize) - nbytes = n * elsize; - - throw MyMemoryError(nbytes); -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2008 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +void VDNORETURN vdallocator_base::throw_oom(size_t n, size_t elsize) { + size_t nbytes = ~(size_t)0; + + if (n <= nbytes / elsize) + nbytes = n * elsize; + + throw MyMemoryError(nbytes); +} diff --git a/src/thirdparty/VirtualDub/system/source/vdstl_hash.cpp b/src/thirdparty/VirtualDub/system/source/vdstl_hash.cpp index 660d9359af4..8e842eadaa0 100644 --- a/src/thirdparty/VirtualDub/system/source/vdstl_hash.cpp +++ b/src/thirdparty/VirtualDub/system/source/vdstl_hash.cpp @@ -1,109 +1,109 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include -#include -#include -#include - -size_t vdhash::operator()(const VDStringA& s) const { - return VDHashString32(s.data(), s.length()); -} - -size_t vdhash::operator()(const char *s) const { - return VDHashString32(s, strlen(s)); -} - -size_t vdhash::operator()(const VDStringW& s) const { - return VDHashString32(s.data(), s.length()); -} - -size_t vdhash::operator()(const wchar_t *s) const { - return VDHashString32(s, wcslen(s)); -} - -size_t vdstringhashi::operator()(const VDStringA& s) const { - return VDHashString32I(s.data(), s.length()); -} - -size_t vdstringhashi::operator()(const char *s) const { - return VDHashString32I(s); -} - -size_t vdstringhashi::operator()(const VDStringW& s) const { - return VDHashString32I(s.data(), s.length()); -} - -size_t vdstringhashi::operator()(const wchar_t *s) const { - return VDHashString32I(s); -} - -bool vdstringpred::operator()(const VDStringA& s, const VDStringA& t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringA& s, const VDStringSpanA& t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringA& s, const char *t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringW& s, const VDStringW& t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringW& s, const VDStringSpanW& t) const { - return s == t; -} - -bool vdstringpred::operator()(const VDStringW& s, const wchar_t *t) const { - return s == t; -} - -bool vdstringpredi::operator()(const VDStringA& s, const VDStringA& t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringA& s, const VDStringSpanA& t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringA& s, const char *t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringW& s, const VDStringW& t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringW& s, const VDStringSpanW& t) const { - return s.comparei(t) == 0; -} - -bool vdstringpredi::operator()(const VDStringW& s, const wchar_t *t) const { - return s.comparei(t) == 0; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include +#include +#include +#include + +size_t vdhash::operator()(const VDStringA& s) const { + return VDHashString32(s.data(), s.length()); +} + +size_t vdhash::operator()(const char *s) const { + return VDHashString32(s, strlen(s)); +} + +size_t vdhash::operator()(const VDStringW& s) const { + return VDHashString32(s.data(), s.length()); +} + +size_t vdhash::operator()(const wchar_t *s) const { + return VDHashString32(s, wcslen(s)); +} + +size_t vdstringhashi::operator()(const VDStringA& s) const { + return VDHashString32I(s.data(), s.length()); +} + +size_t vdstringhashi::operator()(const char *s) const { + return VDHashString32I(s); +} + +size_t vdstringhashi::operator()(const VDStringW& s) const { + return VDHashString32I(s.data(), s.length()); +} + +size_t vdstringhashi::operator()(const wchar_t *s) const { + return VDHashString32I(s); +} + +bool vdstringpred::operator()(const VDStringA& s, const VDStringA& t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringA& s, const VDStringSpanA& t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringA& s, const char *t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringW& s, const VDStringW& t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringW& s, const VDStringSpanW& t) const { + return s == t; +} + +bool vdstringpred::operator()(const VDStringW& s, const wchar_t *t) const { + return s == t; +} + +bool vdstringpredi::operator()(const VDStringA& s, const VDStringA& t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringA& s, const VDStringSpanA& t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringA& s, const char *t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringW& s, const VDStringW& t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringW& s, const VDStringSpanW& t) const { + return s.comparei(t) == 0; +} + +bool vdstringpredi::operator()(const VDStringW& s, const wchar_t *t) const { + return s.comparei(t) == 0; +} diff --git a/src/thirdparty/VirtualDub/system/source/vdstl_hashtable.cpp b/src/thirdparty/VirtualDub/system/source/vdstl_hashtable.cpp index 13234f3307d..9b1c277fe97 100644 --- a/src/thirdparty/VirtualDub/system/source/vdstl_hashtable.cpp +++ b/src/thirdparty/VirtualDub/system/source/vdstl_hashtable.cpp @@ -1,82 +1,82 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include -#include - -vdhashtable_base_node *const vdhashtable_base::sEmptyBucket = {NULL}; - -vdhashtable_base::vdhashtable_base() - : mBucketCount(0) - , mElementCount(0) - , mpBucketStart(const_cast(&sEmptyBucket)) - , mpBucketEnd(const_cast(&sEmptyBucket)) -{ -} - -vdhashtable_base::size_type vdhashtable_base::bucket_count() const { - return mpBucketEnd - mpBucketStart; -} - -vdhashtable_base::size_type vdhashtable_base::max_bucket_count() const { - return (size_type)-1 >> 1; -} - -vdhashtable_base::size_type vdhashtable_base::bucket_size(size_type n) const { - VDASSERT(n < (size_type)(mpBucketEnd - mpBucketStart)); - - size_type len = 0; - for(vdhashtable_base_node *p = mpBucketStart[n]; p; p = p->mpHashNext) - ++len; - - return len; -} - -vdhashtable_base::size_type vdhashtable_base::compute_bucket_count(size_type n) { - static const size_t kBucketSizes[]={ - 11, - 17, 37, 67, 131, - 257, 521, 1031, 2049, - 4099, 8209, 16411, 32771, - 65537, 131101, 262147, 524309, - 1048583, 2097169, 4194319, 8388617, - 16777259, 33554467, 67108879, 134217757, - 268435459, 536870923, 1073741827 - }; - - int i = 0; - size_type buckets; - - while(i < sizeof(kBucketSizes)/sizeof(kBucketSizes[0])) { - buckets = kBucketSizes[i]; - - if (n <= buckets) - break; - - ++i; - } - - return buckets; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2010 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include +#include + +vdhashtable_base_node *const vdhashtable_base::sEmptyBucket = {NULL}; + +vdhashtable_base::vdhashtable_base() + : mBucketCount(0) + , mElementCount(0) + , mpBucketStart(const_cast(&sEmptyBucket)) + , mpBucketEnd(const_cast(&sEmptyBucket)) +{ +} + +vdhashtable_base::size_type vdhashtable_base::bucket_count() const { + return mpBucketEnd - mpBucketStart; +} + +vdhashtable_base::size_type vdhashtable_base::max_bucket_count() const { + return (size_type)-1 >> 1; +} + +vdhashtable_base::size_type vdhashtable_base::bucket_size(size_type n) const { + VDASSERT(n < (size_type)(mpBucketEnd - mpBucketStart)); + + size_type len = 0; + for(vdhashtable_base_node *p = mpBucketStart[n]; p; p = p->mpHashNext) + ++len; + + return len; +} + +vdhashtable_base::size_type vdhashtable_base::compute_bucket_count(size_type n) { + static const size_t kBucketSizes[]={ + 11, + 17, 37, 67, 131, + 257, 521, 1031, 2049, + 4099, 8209, 16411, 32771, + 65537, 131101, 262147, 524309, + 1048583, 2097169, 4194319, 8388617, + 16777259, 33554467, 67108879, 134217757, + 268435459, 536870923, 1073741827 + }; + + int i = 0; + size_type buckets; + + while(i < sizeof(kBucketSizes)/sizeof(kBucketSizes[0])) { + buckets = kBucketSizes[i]; + + if (n <= buckets) + break; + + ++i; + } + + return buckets; +} diff --git a/src/thirdparty/VirtualDub/system/source/vectors.cpp b/src/thirdparty/VirtualDub/system/source/vectors.cpp index 4dfed053111..3a6b91c434c 100644 --- a/src/thirdparty/VirtualDub/system/source/vectors.cpp +++ b/src/thirdparty/VirtualDub/system/source/vectors.cpp @@ -1,83 +1,83 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include - -bool VDSolveLinearEquation(double *src, int n, ptrdiff_t stride_elements, double *b, double tolerance) { - vdfastvector array(n); - double **m = &array[0]; - int i, j, k; - - for(i=0; i=i; --k) - m[j][k] -= m[i][k] * m[j][i]; - } - } - - // factor L - for(i=n-1; i>=0; --i) - for(j=i-1; j>=0; --j) - b[j] -= b[i] * m[j][i]; - - return true; -} - -template<> -bool vdrect32::contains(const vdpoint32& pt) const { - return ((uint32)pt.x - (uint32)left) < (uint32)right - (uint32)left - && ((uint32)pt.y - (uint32)top) < (uint32)bottom - (uint32)top; -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include + +bool VDSolveLinearEquation(double *src, int n, ptrdiff_t stride_elements, double *b, double tolerance) { + vdfastvector array(n); + double **m = &array[0]; + int i, j, k; + + for(i=0; i=i; --k) + m[j][k] -= m[i][k] * m[j][i]; + } + } + + // factor L + for(i=n-1; i>=0; --i) + for(j=i-1; j>=0; --j) + b[j] -= b[i] * m[j][i]; + + return true; +} + +template<> +bool vdrect32::contains(const vdpoint32& pt) const { + return ((uint32)pt.x - (uint32)left) < (uint32)right - (uint32)left + && ((uint32)pt.y - (uint32)top) < (uint32)bottom - (uint32)top; +} diff --git a/src/thirdparty/VirtualDub/system/source/w32assist.cpp b/src/thirdparty/VirtualDub/system/source/w32assist.cpp index 659aee6e9bb..311810dc5c6 100644 --- a/src/thirdparty/VirtualDub/system/source/w32assist.cpp +++ b/src/thirdparty/VirtualDub/system/source/w32assist.cpp @@ -1,710 +1,710 @@ -// VirtualDub - Video processing and capture application -// System library component -// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. -// -// Beginning with 1.6.0, the VirtualDub system library is licensed -// differently than the remainder of VirtualDub. This particular file is -// thus licensed as follows (the "zlib" license): -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any -// damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must -// not claim that you wrote the original software. If you use this -// software in a product, an acknowledgment in the product -// documentation would be appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must -// not be misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source -// distribution. - -#include "stdafx.h" -#include -#include -#include -#include -#include - -bool VDIsForegroundTaskW32() { - HWND hwndFore = GetForegroundWindow(); - - if (!hwndFore) - return false; - - DWORD dwProcessId = 0; - GetWindowThreadProcessId(hwndFore, &dwProcessId); - - return dwProcessId == GetCurrentProcessId(); -} - -LPVOID VDConvertThreadToFiberW32(LPVOID parm) { - typedef LPVOID (WINAPI *tpConvertThreadToFiber)(LPVOID p); - static tpConvertThreadToFiber ctof = (tpConvertThreadToFiber)GetProcAddress(GetModuleHandle("kernel32"), "ConvertThreadToFiber"); - - if (!ctof) - return NULL; - - return ctof(parm); -} - -void VDSwitchToFiberW32(LPVOID fiber) { - typedef void (WINAPI *tpSwitchToFiber)(LPVOID p); - static tpSwitchToFiber stof = (tpSwitchToFiber)GetProcAddress(GetModuleHandle("kernel32"), "SwitchToFiber"); - - if (stof) - stof(fiber); -} - -int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr) { - int palents = 0; - - if ((pHdr->biCompression == BI_RGB || pHdr->biCompression == BI_RLE4 || pHdr->biCompression == BI_RLE8) && pHdr->biBitCount <= 8) { - palents = pHdr->biClrUsed; - if (!palents) - palents = 1 << pHdr->biBitCount; - } - int size = pHdr->biSize + palents * sizeof(RGBQUAD); - - if (pHdr->biSize < sizeof(BITMAPV4HEADER) && pHdr->biCompression == BI_BITFIELDS) - size += sizeof(DWORD) * 3; - - return size; -} - -void VDSetWindowTextW32(HWND hwnd, const wchar_t *s) { - if (VDIsWindowsNT()) { - SetWindowTextW(hwnd, s); - } else { - SetWindowTextA(hwnd, VDTextWToA(s).c_str()); - } -} - -void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...) { - va_list val; - - va_start(val, format); - { - wchar_t buf[512]; - int r = vdvswprintf(buf, 512, format, val); - - if ((unsigned)r < 512) { - VDSetWindowTextW32(hwnd, buf); - va_end(val); - return; - } - } - - VDStringW s; - s.append_vsprintf(format, val); - VDSetWindowTextW32(hwnd, s.c_str()); - - va_end(val); -} - -VDStringA VDGetWindowTextAW32(HWND hwnd) { - char buf[512]; - - int len = GetWindowTextLengthA(hwnd); - - if (len > 511) { - vdblock tmp(len + 1); - len = GetWindowTextA(hwnd, tmp.data(), tmp.size()); - - const char *s = tmp.data(); - VDStringA text(s, s+len); - return text; - } else if (len > 0) { - len = GetWindowTextA(hwnd, buf, 512); - - return VDStringA(buf, buf + len); - } - - return VDStringA(); -} - -VDStringW VDGetWindowTextW32(HWND hwnd) { - union { - wchar_t w[256]; - char a[512]; - } buf; - - if (VDIsWindowsNT()) { - int len = GetWindowTextLengthW(hwnd); - - if (len > 255) { - vdblock tmp(len + 1); - len = GetWindowTextW(hwnd, tmp.data(), tmp.size()); - - VDStringW text(tmp.data(), len); - return text; - } else if (len > 0) { - len = GetWindowTextW(hwnd, buf.w, 256); - - VDStringW text(buf.w, len); - return text; - } - } else { - int len = GetWindowTextLengthA(hwnd); - - if (len > 511) { - vdblock tmp(len + 1); - len = GetWindowTextA(hwnd, tmp.data(), tmp.size()); - - VDStringW text(VDTextAToW(tmp.data(), len)); - return text; - } else if (len > 0) { - len = GetWindowTextA(hwnd, buf.a, 512); - - VDStringW text(VDTextAToW(buf.a, len)); - return text; - } - } - - return VDStringW(); -} - -void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text){ - if (VDIsWindowsNT()) { - AppendMenuW(hmenu, flags, id, text); - } else { - AppendMenuA(hmenu, flags, id, VDTextWToA(text).c_str()); - } -} - -bool VDAppendPopupMenuW32(HMENU hmenu, UINT flags, HMENU hmenuPopup, const wchar_t *text){ - flags |= MF_POPUP; - - if (VDIsWindowsNT()) - return 0 != AppendMenuW(hmenu, flags, (UINT_PTR)hmenuPopup, text); - else - return 0 != AppendMenuA(hmenu, flags, (UINT_PTR)hmenuPopup, VDTextWToA(text).c_str()); -} - -void VDAppendMenuSeparatorW32(HMENU hmenu) { - int pos = GetMenuItemCount(hmenu); - if (pos < 0) - return; - - if (VDIsWindowsNT()) { - MENUITEMINFOW mmiW; - vdfastfixedvector bufW; - - mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; - mmiW.fMask = MIIM_TYPE; - mmiW.fType = MFT_SEPARATOR; - - InsertMenuItemW(hmenu, pos, TRUE, &mmiW); - } else { - MENUITEMINFOA mmiA; - - mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; - mmiA.fMask = MIIM_TYPE; - mmiA.fType = MFT_SEPARATOR; - - InsertMenuItemA(hmenu, pos, TRUE, &mmiA); - } -} - -void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) { - CheckMenuItem(hmenu, pos, checked ? MF_BYPOSITION|MF_CHECKED : MF_BYPOSITION|MF_UNCHECKED); -} - -void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { - CheckMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED); -} - -void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) { - MENUITEMINFOA mii; - - mii.cbSize = sizeof(MENUITEMINFOA); - mii.fMask = MIIM_FTYPE | MIIM_STATE; - if (GetMenuItemInfo(hmenu, pos, TRUE, &mii)) { - mii.fType |= MFT_RADIOCHECK; - mii.fState &= ~MFS_CHECKED; - if (checked) - mii.fState |= MFS_CHECKED; - SetMenuItemInfo(hmenu, pos, TRUE, &mii); - } -} - -void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { - MENUITEMINFOA mii; - - mii.cbSize = sizeof(MENUITEMINFOA); - mii.fMask = MIIM_FTYPE | MIIM_STATE; - if (GetMenuItemInfo(hmenu, cmd, FALSE, &mii)) { - mii.fType |= MFT_RADIOCHECK; - mii.fState &= ~MFS_CHECKED; - if (checked) - mii.fState |= MFS_CHECKED; - SetMenuItemInfo(hmenu, cmd, FALSE, &mii); - } -} - -void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { - EnableMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_ENABLED : MF_BYCOMMAND|MF_GRAYED); -} - -VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd) { - VDStringW s; - - if (VDIsWindowsNT()) { - MENUITEMINFOW mmiW; - vdfastfixedvector bufW; - - mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; - mmiW.fMask = MIIM_TYPE; - mmiW.fType = MFT_STRING; - mmiW.dwTypeData = NULL; - mmiW.cch = 0; // required to avoid crash on NT4 - - if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) { - bufW.resize(mmiW.cch + 1, 0); - ++mmiW.cch; - mmiW.dwTypeData = bufW.data(); - - if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) - s = bufW.data(); - } - } else { - MENUITEMINFOA mmiA; - vdfastfixedvector bufA; - - mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; - mmiA.fMask = MIIM_TYPE; - mmiA.fType = MFT_STRING; - mmiA.dwTypeData = NULL; - - if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) { - bufA.resize(mmiA.cch + 1, 0); - ++mmiA.cch; - mmiA.dwTypeData = bufA.data(); - - if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) - s = VDTextAToW(bufA.data()); - } - } - - return s; -} - -void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text) { - if (VDIsWindowsNT()) { - MENUITEMINFOW mmiW; - - mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; - mmiW.fMask = MIIM_TYPE; - mmiW.fType = MFT_STRING; - mmiW.dwTypeData = (LPWSTR)text; - - SetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW); - } else { - MENUITEMINFOA mmiA; - VDStringA textA(VDTextWToA(text)); - - mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; - mmiA.fMask = MIIM_TYPE; - mmiA.fType = MFT_STRING; - mmiA.dwTypeData = (LPSTR)textA.c_str(); - - SetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA); - } -} - -LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - return (IsWindowUnicode(hwnd) ? CallWindowProcW : CallWindowProcA)(wp, hwnd, msg, wParam, lParam); -} - -LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, msg, wParam, lParam) : DefWindowProcA(hwnd, msg, wParam, lParam); -} - -EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags) { - EXECUTION_STATE es = 0; - - // SetThreadExecutionState(): requires Windows 98+/2000+. - typedef EXECUTION_STATE (WINAPI *tSetThreadExecutionState)(EXECUTION_STATE); - static tSetThreadExecutionState pFunc = (tSetThreadExecutionState)GetProcAddress(GetModuleHandle("kernel32"), "SetThreadExecutionState"); - - if (pFunc) - es = pFunc(esFlags); - - return es; -} - -bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod) { - LONG posHi = (LONG)(pos >> 32); - DWORD result = SetFilePointer(h, (LONG)pos, &posHi, dwMoveMethod); - - if (result != INVALID_SET_FILE_POINTER) - return true; - - DWORD dwError = GetLastError(); - - return (dwError == NO_ERROR); -} - -bool VDGetFileSizeW32(HANDLE h, sint64& size) { - DWORD dwSizeHigh; - DWORD dwSizeLow = GetFileSize(h, &dwSizeHigh); - - if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) - return false; - - size = dwSizeLow + ((sint64)dwSizeHigh << 32); - return true; -} - -#if !defined(_MSC_VER) || _MSC_VER < 1300 -HMODULE VDGetLocalModuleHandleW32() { - MEMORY_BASIC_INFORMATION meminfo; - static HMODULE shmod = (VirtualQuery((HINSTANCE)&VDGetLocalModuleHandleW32, &meminfo, sizeof meminfo), (HMODULE)meminfo.AllocationBase); - - return shmod; -} -#endif - -bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat) { - RECT r; - if (VDIsWindowsNT()) { - // If multiline and vcentered (not normally supported...) - if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) { - uFormat &= ~DT_VCENTER; - - r = *lpRect; - if (!DrawTextW(hdc, s, nCount, &r, uFormat | DT_CALCRECT)) - return false; - - int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1; - int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1; - - r.left += dx; - r.right += dx; - r.top += dy; - r.bottom += dy; - lpRect = &r; - } - - return !!DrawTextW(hdc, s, nCount, lpRect, uFormat); - } else { - VDStringA strA(VDTextWToA(s, nCount)); - - // If multiline and vcentered (not normally supported...) - if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) { - uFormat &= ~DT_VCENTER; - - r = *lpRect; - if (!DrawTextA(hdc, strA.data(), strA.size(), &r, uFormat | DT_CALCRECT)) - return false; - - int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1; - int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1; - - r.left += dx; - r.right += dx; - r.top += dy; - r.bottom += dy; - lpRect = &r; - } - - return !!DrawTextA(hdc, strA.data(), strA.size(), lpRect, uFormat); - } -} - -bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) { - char *pBase = (char *)hmod; - - vd_seh_guard_try { - // The PEheader offset is at hmod+0x3c. Add the size of the optional header - // to step to the section headers. - - const uint32 peoffset = ((const long *)pBase)[15]; - const uint32 signature = *(uint32 *)(pBase + peoffset); - - if (signature != IMAGE_NT_SIGNATURE) - return false; - - const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4); - - // Verify the PE optional structure. - - if (pHeader->SizeOfOptionalHeader < 104) - return false; - - // Find import header. - - const IMAGE_IMPORT_DESCRIPTOR *pImportDir; - int nImports; - - switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) { - -#ifdef _M_AMD64 - case IMAGE_NT_OPTIONAL_HDR64_MAGIC: - { - const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); - - if (pOpt->NumberOfRvaAndSizes < 2) - return false; - - pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); - nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); - } - break; -#else - case IMAGE_NT_OPTIONAL_HDR32_MAGIC: - { - const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); - - if (pOpt->NumberOfRvaAndSizes < 2) - return false; - - pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); - nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); - } - break; -#endif - - default: // reject PE32+ - return false; - } - - // Hmmm... no imports? - - if ((const char *)pImportDir == pBase) - return false; - - // Scan down the import entries. We are looking for MSVFW32. - - int i; - - for(i=0; i= nImports) - return false; - - // Found it. Start scanning MSVFW32 imports until we find DrawDibDraw. - - const long *pImports = (const long *)(pBase + pImportDir[i].OriginalFirstThunk); - void * volatile *pVector = (void * volatile *)(pBase + pImportDir[i].FirstThunk); - - while(*pImports) { - if (*pImports >= 0) { - const char *pName = pBase + *pImports + 2; - - if (!strcmp(pName, name)) { - - // Found it! Reset the protection. - - DWORD dwOldProtect; - - if (VirtualProtect((void *)pVector, sizeof(void *), PAGE_EXECUTE_READWRITE, &dwOldProtect)) { - if (ppOldValue) { - for(;;) { - void *old = *pVector; - if (pCompareValue && pCompareValue != old) - return false; - - *ppOldValue = old; - if (old == VDAtomicCompareExchangePointer(pVector, pNewValue, old)) - break; - } - } else { - *pVector = pNewValue; - } - - VirtualProtect((void *)pVector, sizeof(void *), dwOldProtect, &dwOldProtect); - - return true; - } - - break; - } - } - - ++pImports; - ++pVector; - } - } vd_seh_guard_except { - } - - return false; -} - -bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) { - char *pBase = (char *)hmod; - - vd_seh_guard_try { - // The PEheader offset is at hmod+0x3c. Add the size of the optional header - // to step to the section headers. - - const uint32 peoffset = ((const long *)pBase)[15]; - const uint32 signature = *(uint32 *)(pBase + peoffset); - - if (signature != IMAGE_NT_SIGNATURE) - return false; - - const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4); - - // Verify the PE optional structure. - - if (pHeader->SizeOfOptionalHeader < 104) - return false; - - // Find export directory. - - const IMAGE_EXPORT_DIRECTORY *pExportDir; - - switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) { - -#ifdef _M_AMD64 - case IMAGE_NT_OPTIONAL_HDR64_MAGIC: - { - const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); - - if (pOpt->NumberOfRvaAndSizes < 1) - return false; - - DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - - if (!exportDirRVA) - return false; - - pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA); - } - break; -#else - case IMAGE_NT_OPTIONAL_HDR32_MAGIC: - { - const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); - - if (pOpt->NumberOfRvaAndSizes < 1) - return false; - - DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - - if (!exportDirRVA) - return false; - - pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA); - } - break; -#endif - - default: // reject PE32+ - return false; - } - - // Scan for the export name. - DWORD nameCount = pExportDir->AddressOfNames; - const DWORD *nameRVAs = (const DWORD *)(pBase + pExportDir->AddressOfNames); - const WORD *nameOrdinals = (const WORD *)(pBase + pExportDir->AddressOfNameOrdinals); - DWORD *functionTable = (DWORD *)(pBase + pExportDir->AddressOfFunctions); - - for(DWORD i=0; i pathW(MAX_PATH, 0); - - size_t len = GetSystemDirectoryW(pathW.data(), MAX_PATH); - - if (!len) - return NULL; - - if (len > MAX_PATH) { - pathW.resize(len + 1, 0); - - len = GetSystemDirectoryW(pathW.data(), len); - if (!len || len >= pathW.size()) - return NULL; - } - - pathW.resize(len); - - if (pathW.back() != '\\') - pathW.push_back('\\'); - - while(const char c = *name++) - pathW.push_back(c); - - pathW.push_back(0); - - return LoadLibraryW(pathW.data()); - } else { - vdfastvector pathA(MAX_PATH, 0); - size_t len = GetSystemDirectoryA(pathA.data(), MAX_PATH); - - if (!len) - return NULL; - - if (len > MAX_PATH) { - pathA.resize(len + 1, 0); - - len = GetSystemDirectoryA(pathA.data(), len); - if (!len || len >= pathA.size()) - return NULL; - } - - pathA.resize(len); - - if (pathA.back() != '\\') - pathA.push_back('\\'); - - pathA.insert(pathA.end(), name, name + strlen(name)); - pathA.push_back(0); - - return LoadLibraryA(pathA.data()); - } -} +// VirtualDub - Video processing and capture application +// System library component +// Copyright (C) 1998-2004 Avery Lee, All Rights Reserved. +// +// Beginning with 1.6.0, the VirtualDub system library is licensed +// differently than the remainder of VirtualDub. This particular file is +// thus licensed as follows (the "zlib" license): +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must +// not claim that you wrote the original software. If you use this +// software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must +// not be misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. + +#include "stdafx.h" +#include +#include +#include +#include +#include + +bool VDIsForegroundTaskW32() { + HWND hwndFore = GetForegroundWindow(); + + if (!hwndFore) + return false; + + DWORD dwProcessId = 0; + GetWindowThreadProcessId(hwndFore, &dwProcessId); + + return dwProcessId == GetCurrentProcessId(); +} + +LPVOID VDConvertThreadToFiberW32(LPVOID parm) { + typedef LPVOID (WINAPI *tpConvertThreadToFiber)(LPVOID p); + static tpConvertThreadToFiber ctof = (tpConvertThreadToFiber)GetProcAddress(GetModuleHandle("kernel32"), "ConvertThreadToFiber"); + + if (!ctof) + return NULL; + + return ctof(parm); +} + +void VDSwitchToFiberW32(LPVOID fiber) { + typedef void (WINAPI *tpSwitchToFiber)(LPVOID p); + static tpSwitchToFiber stof = (tpSwitchToFiber)GetProcAddress(GetModuleHandle("kernel32"), "SwitchToFiber"); + + if (stof) + stof(fiber); +} + +int VDGetSizeOfBitmapHeaderW32(const BITMAPINFOHEADER *pHdr) { + int palents = 0; + + if ((pHdr->biCompression == BI_RGB || pHdr->biCompression == BI_RLE4 || pHdr->biCompression == BI_RLE8) && pHdr->biBitCount <= 8) { + palents = pHdr->biClrUsed; + if (!palents) + palents = 1 << pHdr->biBitCount; + } + int size = pHdr->biSize + palents * sizeof(RGBQUAD); + + if (pHdr->biSize < sizeof(BITMAPV4HEADER) && pHdr->biCompression == BI_BITFIELDS) + size += sizeof(DWORD) * 3; + + return size; +} + +void VDSetWindowTextW32(HWND hwnd, const wchar_t *s) { + if (VDIsWindowsNT()) { + SetWindowTextW(hwnd, s); + } else { + SetWindowTextA(hwnd, VDTextWToA(s).c_str()); + } +} + +void VDSetWindowTextFW32(HWND hwnd, const wchar_t *format, ...) { + va_list val; + + va_start(val, format); + { + wchar_t buf[512]; + int r = vdvswprintf(buf, 512, format, val); + + if ((unsigned)r < 512) { + VDSetWindowTextW32(hwnd, buf); + va_end(val); + return; + } + } + + VDStringW s; + s.append_vsprintf(format, val); + VDSetWindowTextW32(hwnd, s.c_str()); + + va_end(val); +} + +VDStringA VDGetWindowTextAW32(HWND hwnd) { + char buf[512]; + + int len = GetWindowTextLengthA(hwnd); + + if (len > 511) { + vdblock tmp(len + 1); + len = GetWindowTextA(hwnd, tmp.data(), tmp.size()); + + const char *s = tmp.data(); + VDStringA text(s, s+len); + return text; + } else if (len > 0) { + len = GetWindowTextA(hwnd, buf, 512); + + return VDStringA(buf, buf + len); + } + + return VDStringA(); +} + +VDStringW VDGetWindowTextW32(HWND hwnd) { + union { + wchar_t w[256]; + char a[512]; + } buf; + + if (VDIsWindowsNT()) { + int len = GetWindowTextLengthW(hwnd); + + if (len > 255) { + vdblock tmp(len + 1); + len = GetWindowTextW(hwnd, tmp.data(), tmp.size()); + + VDStringW text(tmp.data(), len); + return text; + } else if (len > 0) { + len = GetWindowTextW(hwnd, buf.w, 256); + + VDStringW text(buf.w, len); + return text; + } + } else { + int len = GetWindowTextLengthA(hwnd); + + if (len > 511) { + vdblock tmp(len + 1); + len = GetWindowTextA(hwnd, tmp.data(), tmp.size()); + + VDStringW text(VDTextAToW(tmp.data(), len)); + return text; + } else if (len > 0) { + len = GetWindowTextA(hwnd, buf.a, 512); + + VDStringW text(VDTextAToW(buf.a, len)); + return text; + } + } + + return VDStringW(); +} + +void VDAppendMenuW32(HMENU hmenu, UINT flags, UINT id, const wchar_t *text){ + if (VDIsWindowsNT()) { + AppendMenuW(hmenu, flags, id, text); + } else { + AppendMenuA(hmenu, flags, id, VDTextWToA(text).c_str()); + } +} + +bool VDAppendPopupMenuW32(HMENU hmenu, UINT flags, HMENU hmenuPopup, const wchar_t *text){ + flags |= MF_POPUP; + + if (VDIsWindowsNT()) + return 0 != AppendMenuW(hmenu, flags, (UINT_PTR)hmenuPopup, text); + else + return 0 != AppendMenuA(hmenu, flags, (UINT_PTR)hmenuPopup, VDTextWToA(text).c_str()); +} + +void VDAppendMenuSeparatorW32(HMENU hmenu) { + int pos = GetMenuItemCount(hmenu); + if (pos < 0) + return; + + if (VDIsWindowsNT()) { + MENUITEMINFOW mmiW; + vdfastfixedvector bufW; + + mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; + mmiW.fMask = MIIM_TYPE; + mmiW.fType = MFT_SEPARATOR; + + InsertMenuItemW(hmenu, pos, TRUE, &mmiW); + } else { + MENUITEMINFOA mmiA; + + mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; + mmiA.fMask = MIIM_TYPE; + mmiA.fType = MFT_SEPARATOR; + + InsertMenuItemA(hmenu, pos, TRUE, &mmiA); + } +} + +void VDCheckMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) { + CheckMenuItem(hmenu, pos, checked ? MF_BYPOSITION|MF_CHECKED : MF_BYPOSITION|MF_UNCHECKED); +} + +void VDCheckMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { + CheckMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_CHECKED : MF_BYCOMMAND|MF_UNCHECKED); +} + +void VDCheckRadioMenuItemByPositionW32(HMENU hmenu, uint32 pos, bool checked) { + MENUITEMINFOA mii; + + mii.cbSize = sizeof(MENUITEMINFOA); + mii.fMask = MIIM_FTYPE | MIIM_STATE; + if (GetMenuItemInfo(hmenu, pos, TRUE, &mii)) { + mii.fType |= MFT_RADIOCHECK; + mii.fState &= ~MFS_CHECKED; + if (checked) + mii.fState |= MFS_CHECKED; + SetMenuItemInfo(hmenu, pos, TRUE, &mii); + } +} + +void VDCheckRadioMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { + MENUITEMINFOA mii; + + mii.cbSize = sizeof(MENUITEMINFOA); + mii.fMask = MIIM_FTYPE | MIIM_STATE; + if (GetMenuItemInfo(hmenu, cmd, FALSE, &mii)) { + mii.fType |= MFT_RADIOCHECK; + mii.fState &= ~MFS_CHECKED; + if (checked) + mii.fState |= MFS_CHECKED; + SetMenuItemInfo(hmenu, cmd, FALSE, &mii); + } +} + +void VDEnableMenuItemByCommandW32(HMENU hmenu, UINT cmd, bool checked) { + EnableMenuItem(hmenu, cmd, checked ? MF_BYCOMMAND|MF_ENABLED : MF_BYCOMMAND|MF_GRAYED); +} + +VDStringW VDGetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd) { + VDStringW s; + + if (VDIsWindowsNT()) { + MENUITEMINFOW mmiW; + vdfastfixedvector bufW; + + mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; + mmiW.fMask = MIIM_TYPE; + mmiW.fType = MFT_STRING; + mmiW.dwTypeData = NULL; + mmiW.cch = 0; // required to avoid crash on NT4 + + if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) { + bufW.resize(mmiW.cch + 1, 0); + ++mmiW.cch; + mmiW.dwTypeData = bufW.data(); + + if (GetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW)) + s = bufW.data(); + } + } else { + MENUITEMINFOA mmiA; + vdfastfixedvector bufA; + + mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; + mmiA.fMask = MIIM_TYPE; + mmiA.fType = MFT_STRING; + mmiA.dwTypeData = NULL; + + if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) { + bufA.resize(mmiA.cch + 1, 0); + ++mmiA.cch; + mmiA.dwTypeData = bufA.data(); + + if (GetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA)) + s = VDTextAToW(bufA.data()); + } + } + + return s; +} + +void VDSetMenuItemTextByCommandW32(HMENU hmenu, UINT cmd, const wchar_t *text) { + if (VDIsWindowsNT()) { + MENUITEMINFOW mmiW; + + mmiW.cbSize = MENUITEMINFO_SIZE_VERSION_400W; + mmiW.fMask = MIIM_TYPE; + mmiW.fType = MFT_STRING; + mmiW.dwTypeData = (LPWSTR)text; + + SetMenuItemInfoW(hmenu, cmd, FALSE, &mmiW); + } else { + MENUITEMINFOA mmiA; + VDStringA textA(VDTextWToA(text)); + + mmiA.cbSize = MENUITEMINFO_SIZE_VERSION_400A; + mmiA.fMask = MIIM_TYPE; + mmiA.fType = MFT_STRING; + mmiA.dwTypeData = (LPSTR)textA.c_str(); + + SetMenuItemInfoA(hmenu, cmd, FALSE, &mmiA); + } +} + +LRESULT VDDualCallWindowProcW32(WNDPROC wp, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + return (IsWindowUnicode(hwnd) ? CallWindowProcW : CallWindowProcA)(wp, hwnd, msg, wParam, lParam); +} + +LRESULT VDDualDefWindowProcW32(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, msg, wParam, lParam) : DefWindowProcA(hwnd, msg, wParam, lParam); +} + +EXECUTION_STATE VDSetThreadExecutionStateW32(EXECUTION_STATE esFlags) { + EXECUTION_STATE es = 0; + + // SetThreadExecutionState(): requires Windows 98+/2000+. + typedef EXECUTION_STATE (WINAPI *tSetThreadExecutionState)(EXECUTION_STATE); + static tSetThreadExecutionState pFunc = (tSetThreadExecutionState)GetProcAddress(GetModuleHandle("kernel32"), "SetThreadExecutionState"); + + if (pFunc) + es = pFunc(esFlags); + + return es; +} + +bool VDSetFilePointerW32(HANDLE h, sint64 pos, DWORD dwMoveMethod) { + LONG posHi = (LONG)(pos >> 32); + DWORD result = SetFilePointer(h, (LONG)pos, &posHi, dwMoveMethod); + + if (result != INVALID_SET_FILE_POINTER) + return true; + + DWORD dwError = GetLastError(); + + return (dwError == NO_ERROR); +} + +bool VDGetFileSizeW32(HANDLE h, sint64& size) { + DWORD dwSizeHigh; + DWORD dwSizeLow = GetFileSize(h, &dwSizeHigh); + + if (dwSizeLow == (DWORD)-1 && GetLastError() != NO_ERROR) + return false; + + size = dwSizeLow + ((sint64)dwSizeHigh << 32); + return true; +} + +#if !defined(_MSC_VER) || _MSC_VER < 1300 +HMODULE VDGetLocalModuleHandleW32() { + MEMORY_BASIC_INFORMATION meminfo; + static HMODULE shmod = (VirtualQuery((HINSTANCE)&VDGetLocalModuleHandleW32, &meminfo, sizeof meminfo), (HMODULE)meminfo.AllocationBase); + + return shmod; +} +#endif + +bool VDDrawTextW32(HDC hdc, const wchar_t *s, int nCount, LPRECT lpRect, UINT uFormat) { + RECT r; + if (VDIsWindowsNT()) { + // If multiline and vcentered (not normally supported...) + if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) { + uFormat &= ~DT_VCENTER; + + r = *lpRect; + if (!DrawTextW(hdc, s, nCount, &r, uFormat | DT_CALCRECT)) + return false; + + int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1; + int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1; + + r.left += dx; + r.right += dx; + r.top += dy; + r.bottom += dy; + lpRect = &r; + } + + return !!DrawTextW(hdc, s, nCount, lpRect, uFormat); + } else { + VDStringA strA(VDTextWToA(s, nCount)); + + // If multiline and vcentered (not normally supported...) + if (!((uFormat ^ DT_VCENTER) & (DT_VCENTER|DT_SINGLELINE))) { + uFormat &= ~DT_VCENTER; + + r = *lpRect; + if (!DrawTextA(hdc, strA.data(), strA.size(), &r, uFormat | DT_CALCRECT)) + return false; + + int dx = ((lpRect->right - lpRect->left) - (r.right - r.left)) >> 1; + int dy = ((lpRect->bottom - lpRect->top) - (r.bottom - r.top)) >> 1; + + r.left += dx; + r.right += dx; + r.top += dy; + r.bottom += dy; + lpRect = &r; + } + + return !!DrawTextA(hdc, strA.data(), strA.size(), lpRect, uFormat); + } +} + +bool VDPatchModuleImportTableW32(HMODULE hmod, const char *srcModule, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) { + char *pBase = (char *)hmod; + + vd_seh_guard_try { + // The PEheader offset is at hmod+0x3c. Add the size of the optional header + // to step to the section headers. + + const uint32 peoffset = ((const long *)pBase)[15]; + const uint32 signature = *(uint32 *)(pBase + peoffset); + + if (signature != IMAGE_NT_SIGNATURE) + return false; + + const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4); + + // Verify the PE optional structure. + + if (pHeader->SizeOfOptionalHeader < 104) + return false; + + // Find import header. + + const IMAGE_IMPORT_DESCRIPTOR *pImportDir; + int nImports; + + switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) { + +#ifdef _M_AMD64 + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + { + const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); + + if (pOpt->NumberOfRvaAndSizes < 2) + return false; + + pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); + } + break; +#else + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + { + const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); + + if (pOpt->NumberOfRvaAndSizes < 2) + return false; + + pImportDir = (const IMAGE_IMPORT_DESCRIPTOR *)(pBase + pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + nImports = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); + } + break; +#endif + + default: // reject PE32+ + return false; + } + + // Hmmm... no imports? + + if ((const char *)pImportDir == pBase) + return false; + + // Scan down the import entries. We are looking for MSVFW32. + + int i; + + for(i=0; i= nImports) + return false; + + // Found it. Start scanning MSVFW32 imports until we find DrawDibDraw. + + const long *pImports = (const long *)(pBase + pImportDir[i].OriginalFirstThunk); + void * volatile *pVector = (void * volatile *)(pBase + pImportDir[i].FirstThunk); + + while(*pImports) { + if (*pImports >= 0) { + const char *pName = pBase + *pImports + 2; + + if (!strcmp(pName, name)) { + + // Found it! Reset the protection. + + DWORD dwOldProtect; + + if (VirtualProtect((void *)pVector, sizeof(void *), PAGE_EXECUTE_READWRITE, &dwOldProtect)) { + if (ppOldValue) { + for(;;) { + void *old = *pVector; + if (pCompareValue && pCompareValue != old) + return false; + + *ppOldValue = old; + if (old == VDAtomicCompareExchangePointer(pVector, pNewValue, old)) + break; + } + } else { + *pVector = pNewValue; + } + + VirtualProtect((void *)pVector, sizeof(void *), dwOldProtect, &dwOldProtect); + + return true; + } + + break; + } + } + + ++pImports; + ++pVector; + } + } vd_seh_guard_except { + } + + return false; +} + +bool VDPatchModuleExportTableW32(HMODULE hmod, const char *name, void *pCompareValue, void *pNewValue, void *volatile *ppOldValue) { + char *pBase = (char *)hmod; + + vd_seh_guard_try { + // The PEheader offset is at hmod+0x3c. Add the size of the optional header + // to step to the section headers. + + const uint32 peoffset = ((const long *)pBase)[15]; + const uint32 signature = *(uint32 *)(pBase + peoffset); + + if (signature != IMAGE_NT_SIGNATURE) + return false; + + const IMAGE_FILE_HEADER *pHeader = (const IMAGE_FILE_HEADER *)(pBase + peoffset + 4); + + // Verify the PE optional structure. + + if (pHeader->SizeOfOptionalHeader < 104) + return false; + + // Find export directory. + + const IMAGE_EXPORT_DIRECTORY *pExportDir; + + switch(*(short *)((char *)pHeader + IMAGE_SIZEOF_FILE_HEADER)) { + +#ifdef _M_AMD64 + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + { + const IMAGE_OPTIONAL_HEADER64 *pOpt = (IMAGE_OPTIONAL_HEADER64 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); + + if (pOpt->NumberOfRvaAndSizes < 1) + return false; + + DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + + if (!exportDirRVA) + return false; + + pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA); + } + break; +#else + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + { + const IMAGE_OPTIONAL_HEADER32 *pOpt = (IMAGE_OPTIONAL_HEADER32 *)((const char *)pHeader + sizeof(IMAGE_FILE_HEADER)); + + if (pOpt->NumberOfRvaAndSizes < 1) + return false; + + DWORD exportDirRVA = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + + if (!exportDirRVA) + return false; + + pExportDir = (const IMAGE_EXPORT_DIRECTORY *)(pBase + exportDirRVA); + } + break; +#endif + + default: // reject PE32+ + return false; + } + + // Scan for the export name. + DWORD nameCount = pExportDir->AddressOfNames; + const DWORD *nameRVAs = (const DWORD *)(pBase + pExportDir->AddressOfNames); + const WORD *nameOrdinals = (const WORD *)(pBase + pExportDir->AddressOfNameOrdinals); + DWORD *functionTable = (DWORD *)(pBase + pExportDir->AddressOfFunctions); + + for(DWORD i=0; i pathW(MAX_PATH, 0); + + size_t len = GetSystemDirectoryW(pathW.data(), MAX_PATH); + + if (!len) + return NULL; + + if (len > MAX_PATH) { + pathW.resize(len + 1, 0); + + len = GetSystemDirectoryW(pathW.data(), len); + if (!len || len >= pathW.size()) + return NULL; + } + + pathW.resize(len); + + if (pathW.back() != '\\') + pathW.push_back('\\'); + + while(const char c = *name++) + pathW.push_back(c); + + pathW.push_back(0); + + return LoadLibraryW(pathW.data()); + } else { + vdfastvector pathA(MAX_PATH, 0); + size_t len = GetSystemDirectoryA(pathA.data(), MAX_PATH); + + if (!len) + return NULL; + + if (len > MAX_PATH) { + pathA.resize(len + 1, 0); + + len = GetSystemDirectoryA(pathA.data(), len); + if (!len || len >= pathA.size()) + return NULL; + } + + pathA.resize(len); + + if (pathA.back() != '\\') + pathA.push_back('\\'); + + pathA.insert(pathA.end(), name, name + strlen(name)); + pathA.push_back(0); + + return LoadLibraryA(pathA.data()); + } +} diff --git a/src/thirdparty/VirtualDub/system/system.vcxproj b/src/thirdparty/VirtualDub/system/system.vcxproj index d6851c64287..367d112cb60 100644 --- a/src/thirdparty/VirtualDub/system/system.vcxproj +++ b/src/thirdparty/VirtualDub/system/system.vcxproj @@ -1,178 +1,178 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {C2082189-3ECB-4079-91FA-89D3C8A305C0} - system - system - - - - - StaticLibrary - MultiByte - - - - - - - - - - - - - - ..\h;h;%(AdditionalIncludeDirectories) - _LIB;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - - - Winmm.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - NotUsing - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {C2082189-3ECB-4079-91FA-89D3C8A305C0} + system + system + + + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + ..\h;h;%(AdditionalIncludeDirectories) + _LIB;NOMINMAX;WIN32_LEAN_AND_MEAN;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Winmm.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + NotUsing + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + true + + + true + + + + + + \ No newline at end of file diff --git a/src/thirdparty/VirtualDub/system/system.vcxproj.filters b/src/thirdparty/VirtualDub/system/system.vcxproj.filters index 57366dfa8d8..255c87dcbe4 100644 --- a/src/thirdparty/VirtualDub/system/system.vcxproj.filters +++ b/src/thirdparty/VirtualDub/system/system.vcxproj.filters @@ -1,332 +1,332 @@ - - - - - {5c673951-5083-408a-a3de-a63babf1344b} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {75631612-a2f0-4a60-80e8-cd36f92f4a73} - h;hpp;hxx;hm;inl - - - {0d0e6712-502c-46f9-b0e5-e14256cf6143} - - - {f8e51076-77af-4e45-90bf-adf37a8929fc} - asm - - - {710e4e94-dd20-48a6-8e4d-8c9b28bb7584} - - - {811fdd7e-ea30-44c3-8790-87fb8cd7109f} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Precompiled Header Support - - - Precompiled Header Support - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\win32 - - - Header Files\win32 - - - Precompiled Header Support - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Assembly Files %28x86%29 - - - Assembly Files %28x86%29 - - - Assembly Files %28AMD64%29 - - - Assembly Files %28AMD64%29 - - - Assembly Files %28AMD64%29 - - - Assembly Files %28AMD64%29 - - + + + + + {5c673951-5083-408a-a3de-a63babf1344b} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {75631612-a2f0-4a60-80e8-cd36f92f4a73} + h;hpp;hxx;hm;inl + + + {0d0e6712-502c-46f9-b0e5-e14256cf6143} + + + {f8e51076-77af-4e45-90bf-adf37a8929fc} + asm + + + {710e4e94-dd20-48a6-8e4d-8c9b28bb7584} + + + {811fdd7e-ea30-44c3-8790-87fb8cd7109f} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Precompiled Header Support + + + Precompiled Header Support + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\win32 + + + Header Files\win32 + + + Precompiled Header Support + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Assembly Files %28x86%29 + + + Assembly Files %28x86%29 + + + Assembly Files %28AMD64%29 + + + Assembly Files %28AMD64%29 + + + Assembly Files %28AMD64%29 + + + Assembly Files %28AMD64%29 + + \ No newline at end of file diff --git a/src/thirdparty/XeScrollBar/XeScrollBarBase.cpp b/src/thirdparty/XeScrollBar/XeScrollBarBase.cpp index 19dd70daa4a..52d17e3fb1c 100755 --- a/src/thirdparty/XeScrollBar/XeScrollBarBase.cpp +++ b/src/thirdparty/XeScrollBar/XeScrollBarBase.cpp @@ -1,1430 +1,1430 @@ -///////////////////////////////////////////////////////////////////////////////////////// -// XeScrollBarBase.cpp Version 1.1 -// This class is designed as a base class for another class that will -// do all painting. This class handles all business logic. No painting -// is done in this class - except in debug mode. -// -// Author: Snorri Kristjansson -// snorrikris@gmail.com -// -// History -// Version 1.1 - 2010 October 21 -// - Changed base class to CScrollBar (was CWnd). -// - Fixed many issues to make this scroll bar behave (almost) the same as windows -// scroll bar. -// -// Version 1.0 - 2009 -// - Never released. -// -// Acknowledgements: -// Thanks to Hans Dietrich for his CXScrollBar class, -// which I used as the starting point for CXeScrollBarBase: -// http://www.codeproject.com/KB/miscctrl/XScrollBar.aspx -// (I don't think any of his code survived into this version - but thanks all the same). -// -// License: -// This software is released into the public domain. You are free to use -// it in any way you like, except that you may not sell this source code. -// -// This software is provided "as is" with no expressed or implied warranty. -// I accept no liability for any damage or loss of business that this -// software may cause. -// -///////////////////////////////////////////////////////////////////////////////////////// - -/**************************************************************************************** -TODO: - H Mouse wheel support (L/R wheel push) - WM_MOUSEHWHEEL (new message Vista and later). - - Change code to pure WIN32 - no MFC - use as base base class for CXeScrollBarBase. -****************************************************************************************/ - -#include "stdafx.h" -#include "XeScrollBarBase.h" - -/**************************************************************************************** -Research resources: - -Scroll bar MSDN WIN32 reference. -http://msdn.microsoft.com/en-us/library/bb787529(VS.85).aspx - -Scroll Bar Controls in Win32 -http://msdn.microsoft.com/en-us/library/ms997557.aspx - -How/why to handle WM_CANCELMODE message. -http://support.microsoft.com/kb/74548/en-us - -How/why to handle WM_GETDLGCODE message. -http://support.microsoft.com/kb/83302 - -Discussion about thumb size calculations and more (good one). -http://blogs.msdn.com/oldnewthing/archive/2009/09/21/9897553.aspx - -Discussion about thumb size calculations. -http://social.msdn.microsoft.com/forums/en-US/wpf/thread/415eacf6-481e-4ebd-a6b0-2953e851183d/ - -From the November 2001 issue of MSDN Magazine. -Understanding CControlView, Changing Scroll Bar Color in MFC Apps -by Paul DiLascia -http://msdn.microsoft.com/en-us/magazine/cc301457.aspx - -Handling Keyboard and Mouse Application Buttons in WTL -By Michael Dunn -http://www.codeproject.com/KB/wtl/WTLAppButtons.aspx - -XScrollBar - Scroll bar like Windows Media Player's -By Hans Dietrich -http://www.codeproject.com/KB/miscctrl/XScrollBar.aspx - -Developing a Custom Windows Scrollbar in MFC -By Don Metzler, DDJ June 01, 2003 -http://www.drdobbs.com/windows/184416659 - -SkinControls 1.1 - A journey in automating the skinning of Windows controls -by .dan.g. -http://www.codeproject.com/KB/library/SkinCtrl.aspx - -Custom Scrollbar Library version 1.1 -by James Brown -http://www.codeproject.com/KB/dialog/coolscroll.aspx - -Replace a Window's Internal Scrollbar with a customdraw scrollbar Control -By flyhigh -http://www.codeproject.com/KB/dialog/skinscrollbar.aspx -****************************************************************************************/ - -double fabs_dbl( double dbl ) -{ - if( dbl >= 0 ) - return dbl; - return (-dbl); -} - -// Round a double number up or down. -int round_ud_dbl( double dbl ) -{ - BOOL bNeg = FALSE; - if( dbl < 0 ) - { - bNeg = TRUE; - dbl = -dbl; - } - int n = (int)dbl; - double fract = dbl - (double)n; - if( fract > 0.5 ) - n++; - if( bNeg ) - n = -n; - return n; -} - -/////////////////////////////////////////////////////////////////////////// -// CXeScrollBarBase - -#define XESCROLLBARWND_CLASSNAME _T("XeScrollBarWndClass") // Window class name - -#define XSB_LBTN_DOWN_TIMERID 1001 -#define XSB_LBTN_DOWN_TIME 200 // mS - time to first auto repeat. -#define XSB_LBTN_REPT_TIMERID 1002 -#define XSB_LBTN_REPT_TIME 50 // mS - repeat interval. -#define XSB_FOCUS_TIMERID 1003 -#define XSB_FOCUS_TIME 500 // mS - blink 'gripper' interval. - -// Menu ID's - Note: same ID's as menu from user32.dll. -#define XSB_IDM_SCRHERE 4100 // Scroll Here Scroll Here -#define XSB_IDM_SCR_TL 4102 // Top Left Edge -#define XSB_IDM_SCR_BR 4103 // Bottom Right Edge -#define XSB_IDM_SCR_PG_UL 4098 // Page Up Page Left -#define XSB_IDM_SCR_PG_DR 4099 // Page Down Page Right -#define XSB_IDM_SCR_UL 4096 // Scroll Up Scroll Left -#define XSB_IDM_SCR_DR 4097 // Scroll Down Scroll Right - - -IMPLEMENT_DYNAMIC(CXeScrollBarBase, CScrollBar) - -BEGIN_MESSAGE_MAP(CXeScrollBarBase, CScrollBar) - ON_MESSAGE(SBM_ENABLE_ARROWS, OnSbmEnableArrows) - ON_MESSAGE(SBM_GETPOS, OnSbmGetPos) - ON_MESSAGE(SBM_GETRANGE, OnSbmGetRange) - ON_MESSAGE(SBM_GETSCROLLBARINFO, OnSbmGetScrollBarInfo) - ON_MESSAGE(SBM_GETSCROLLINFO, OnSbmGetScrollInfo) - ON_MESSAGE(SBM_SETPOS, OnSbmSetPos) - ON_MESSAGE(SBM_SETRANGE, OnSbmSetRange) - ON_MESSAGE(SBM_SETRANGEREDRAW, OnSbmSetRangeRedraw) - ON_MESSAGE(SBM_SETSCROLLINFO, OnSbmSetScrollInfo) - ON_WM_PAINT() - ON_WM_ERASEBKGND() - ON_MESSAGE(WM_KEYDOWN, OnKeyDown) - ON_MESSAGE(WM_KEYUP, OnKeyUp) - ON_WM_LBUTTONDOWN() - ON_WM_LBUTTONUP() - ON_WM_MOUSEMOVE() - ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) - ON_MESSAGE(WM_GETDLGCODE, OnGetDlgCode) - ON_WM_CANCELMODE() - ON_WM_CONTEXTMENU() - ON_COMMAND_RANGE(XSB_IDM_SCR_UL,XSB_IDM_SCR_BR,OnMenuCommands) - ON_WM_TIMER() - ON_WM_SIZE() - ON_WM_SETFOCUS() - ON_WM_KILLFOCUS() - ON_WM_ENABLE() - ON_WM_MOUSEWHEEL() -END_MESSAGE_MAP() - -CXeScrollBarBase::CXeScrollBarBase() -{ - m_pParent = 0; - m_bEnabled = m_bHorizontal = m_bDrawGripper = TRUE; - m_bHasFocus = FALSE; - m_bNoScroll = m_bDragging = m_bTrackMouseLeave = m_bNeedEndScroll = FALSE; - m_nPos = m_nTrackPos = m_nMinPos = m_nMaxPos = m_nMaxReportedPos = 0; - m_uPage = 1; - m_rectClient.SetRectEmpty(); - m_rectThumb.SetRectEmpty(); - m_rectTLArrow.SetRectEmpty(); - m_rectBRArrow.SetRectEmpty(); - m_rectTLChannel.SetRectEmpty(); - m_rectBRChannel.SetRectEmpty(); - m_uArrowWH = 0; - m_uThumbMinHW = 8; // Minimum thumb width or height - m_dblPx_SU = 0; - m_ptMenu.SetPoint(0,0); - m_xyThumbDragOffset = 0; - if (!SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0)) { //added to support multiple rows per mouse notch - scrollLines = 3; - } -} - -CXeScrollBarBase::~CXeScrollBarBase() -{ - // Note - base class dtor (CScrollBar) calls DestroyWindow(). -} - -BOOL CXeScrollBarBase::Create( DWORD dwStyle, const RECT& rect, CWnd *pParentWnd, UINT nID ) -{ - if( !RegisterWindowClass() ) - return FALSE; - - ASSERT(pParentWnd); - ASSERT(IsWindow(pParentWnd->m_hWnd)); - m_pParent = pParentWnd; - - m_bHorizontal = ( dwStyle & SBS_VERT ) ? FALSE : TRUE; - // Note - SBS_HORZ is defined as 0 in winuser.h. - - m_bEnabled = ( dwStyle & WS_DISABLED ) ? FALSE : TRUE; - - BOOL bResult = CWnd::Create( XESCROLLBARWND_CLASSNAME, 0, dwStyle, rect, - pParentWnd, nID ); - - if( bResult ) - { - RecalcRects(); - } - else - { - TRACE(_T("ERROR - failed to create %s\n"),XESCROLLBARWND_CLASSNAME); - ASSERT(FALSE); - } - - return bResult; - - // Note - We DO NOT call base class (CScrollBar) because CScrollBar creates 'normal' - // windows scrollbar. -} - -BOOL CXeScrollBarBase::CreateFromExisting( CWnd *pParentWnd, UINT nID, - BOOL bUseDefaultWH /*= TRUE*/ ) -{ - ASSERT(pParentWnd); - HWND hWndParent = pParentWnd->GetSafeHwnd(); - if( !::IsWindow( hWndParent ) ) - { - ASSERT(FALSE); - return FALSE; - } - HWND hWndExistingSB = ::GetDlgItem( hWndParent, nID ); - if( !hWndExistingSB ) - { - ASSERT(FALSE); - return FALSE; - } - - DWORD dwStyle = ::GetWindowLong( hWndExistingSB, GWL_STYLE ); - - RECT rect; - ::GetWindowRect( hWndExistingSB, &rect ); - ::ScreenToClient( hWndParent, (LPPOINT)&rect ); - ::ScreenToClient( hWndParent, ((LPPOINT)&rect) + 1 ); - if( bUseDefaultWH ) - { // Set width or height to system standard scroll bar width/height. - if( dwStyle & SBS_VERT ) - { - // Get width of 'sys' vert. SB. - int cxSysSbV = ::GetSystemMetrics( SM_CXVSCROLL ); - rect.right = rect.left + cxSysSbV; // Set width of vert. SB to 'normal'. - } - else - { - // Get height of 'sys' horz. SB. - int cySysSbH = ::GetSystemMetrics( SM_CYHSCROLL ); - rect.bottom = rect.top + cySysSbH; // Set height of horz. SB to 'normal'. - } - } - - // Get current range, page and position from existing scrollbar. - SCROLLINFO info; - info.cbSize = sizeof(SCROLLINFO); - info.fMask = SIF_ALL; - ::SendMessage( hWndExistingSB, SBM_GETSCROLLINFO, 0, (LPARAM)&info ); - - // Create new scroll bar of 'this' type. Note - Control ID = 0 until old SB destroyed. - if( !Create( dwStyle, rect, pParentWnd, 0 ) ) - return FALSE; - - // Note - new scroll bar is now the last window in our parent window child Z-order. - - HWND hWndNewSB = GetSafeHwnd(); - ASSERT(hWndNewSB); - - // Set Z-order of new scroll bar - insert after the existing scroll bar. - ::SetWindowPos( hWndNewSB, hWndExistingSB, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); - - // Destroy existing (old) scroll bar. - ::DestroyWindow( hWndExistingSB ); - - // Set Control ID of new scroll bar. - ::SetWindowLong( hWndNewSB, GWL_ID, nID ); - - // Set range, page and position parameters in scroll bar. - SetScrollInfo( &info ); - - return TRUE; -} - -BOOL CXeScrollBarBase::RegisterWindowClass() -{ - WNDCLASS wndcls; - HINSTANCE hInst = AfxGetInstanceHandle(); - - // 'Our' class already registered? - if( !(::GetClassInfo( hInst, XESCROLLBARWND_CLASSNAME, &wndcls )) ) - { // Otherwise we need to register a new class - wndcls.style = CS_HREDRAW | CS_VREDRAW; - // Note - CS_DBLCLKS style not used so don't need to - // process WM_LBUTTONDBLCLK message. - wndcls.lpfnWndProc = ::DefWindowProc; - wndcls.cbClsExtra = wndcls.cbWndExtra = 0; - wndcls.hInstance = hInst; - wndcls.hIcon = NULL; - wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); - wndcls.hbrBackground = NULL; - wndcls.lpszMenuName = NULL; - wndcls.lpszClassName = XESCROLLBARWND_CLASSNAME; - - if( !AfxRegisterClass( &wndcls ) ) - { - TRACE(_T("Register window class %s failed\n"),XESCROLLBARWND_CLASSNAME); - ASSERT(FALSE); - AfxThrowResourceException(); - return FALSE; - } - } - return TRUE; -} - -void CXeScrollBarBase::DrawScrollBar( CDC* pDC ) -{ - // Draw scrollbar as solid color rects - in debug mode ONLY! -#ifdef _DEBUG -#define X_GRBTN RGB(140,140,140) -#define X_GRCH RGB(180,180,180) -#define X_GRTHM RGB(96,96,96) -#define X_NRMBT RGB(128,0,128) -#define X_NRMCH RGB(128,128,0) -#define X_NRMTH RGB(0,192,0) -#define X_HOTBT RGB(192,0,192) -#define X_HOTCH RGB(192,192,0) -#define X_HOTTH RGB(0,255,0) -#define X_DWNBT (~X_NRMBT & 0xFFFFFF) -#define X_DWNCH (~X_NRMCH & 0xFFFFFF) -#define X_DWNTH (~X_NRMTH & 0xFFFFFF) - COLORREF rgbarr[5][6] = { -// eNone eTLbutton eBRbutton eTLchannel eBRchannel eThumb -// 0 1 2 3 4 5 - { 0, 0, 0, 0, 0, 0 }, // 0 eNotDrawn - { 0, X_GRBTN, X_GRBTN, X_GRCH, X_GRCH, X_GRTHM }, // 1 eDisabled - { 0, X_NRMBT, X_NRMBT, X_NRMCH, X_NRMCH, X_NRMTH }, // 2 eNormal - { 0, X_DWNBT, X_DWNBT, X_DWNCH, X_DWNCH, X_DWNTH }, // 3 eDown - { 0, X_HOTBT, X_HOTBT, X_HOTCH, X_HOTCH, X_HOTTH } // 4 eHot - }; - XSB_EDRAWELEM eState; - const CRect *prcElem = 0; - for( int nElem = eTLbutton; nElem <= eThumb; nElem++ ) - { - prcElem = GetUIelementDrawState( (eXSB_AREA)nElem, eState ); - if( !prcElem || eState == eNotDrawn ) - continue; - COLORREF rgb = rgbarr[eState][nElem]; - pDC->FillSolidRect( prcElem, rgb ); - } -#endif -} - -// SBM_GETPOS message handler. -LRESULT CXeScrollBarBase::OnSbmGetPos( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - return m_nPos; -} - -// SBM_SETPOS message handler. -LRESULT CXeScrollBarBase::OnSbmSetPos( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - int nPos = (int)wparam; - BOOL bRedraw = (BOOL)lparam; - int nOldPos = m_nPos; - - m_nPos = nPos; - - if( m_nPos < m_nMinPos ) - m_nPos = m_nMinPos; - else if( m_nPos > m_nMaxReportedPos ) - m_nPos = m_nMaxReportedPos; - - if( m_bNoScroll && !m_bEnabled ) // SB disabled because of SIF_DISABLENOSCROLL? - { // SBM_SETPOS cancels SIF_DISABLENOSCROLL. - m_bNoScroll = FALSE; - EnableWindow( TRUE ); - } - - RecalcRects(); - - if( bRedraw ) - Invalidate(); - - return nOldPos; -} - -// SBM_GETRANGE message handler. -LRESULT CXeScrollBarBase::OnSbmGetRange( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - LPINT lpMinPos = (LPINT)wparam; - LPINT lpMaxPos = (LPINT)lparam; - *lpMinPos = m_nMinPos; - *lpMaxPos = m_nMaxPos; - return 0; -} - -// SBM_SETRANGE message handler. -LRESULT CXeScrollBarBase::OnSbmSetRange( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - int nMinPos = (int)wparam; - int nMaxPos = (int)lparam; - m_nMinPos = nMinPos; - m_nMaxPos = nMaxPos; - if( m_nMaxPos < m_nMinPos ) - m_nMaxPos = m_nMinPos; - int nSUrange = abs(m_nMaxPos - m_nMinPos) + 1; - if( m_uPage > (UINT)nSUrange ) - m_uPage = (UINT)nSUrange; - - if( m_uPage == 0 ) - m_nMaxReportedPos = m_nMaxPos; - else - m_nMaxReportedPos = m_nMaxPos - ((int)m_uPage - 1); - - int nOldPos = m_nPos; - if( m_nPos < m_nMinPos ) - m_nPos = m_nMinPos; - else if( m_nPos > m_nMaxReportedPos ) - m_nPos = m_nMaxReportedPos; - - if( m_bNoScroll && !m_bEnabled ) // SB disabled because of SIF_DISABLENOSCROLL? - { // SBM_SETRANGE cancels SIF_DISABLENOSCROLL. - m_bNoScroll = FALSE; - EnableWindow( TRUE ); - } - - RecalcRects(); - - if( nOldPos != m_nPos ) - return nOldPos; - return 0; -} - -// SBM_SETRANGEREDRAW message handler. -LRESULT CXeScrollBarBase::OnSbmSetRangeRedraw( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - LRESULT lResult = OnSbmSetRange( wparam, lparam ); - Invalidate(); - return lResult; -} - -// SBM_GETSCROLLINFO message handler. -LRESULT CXeScrollBarBase::OnSbmGetScrollInfo( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - LPSCROLLINFO lpScrollInfo = (LPSCROLLINFO)lparam; - if( lpScrollInfo->cbSize != sizeof(SCROLLINFO) ) - return FALSE; - lpScrollInfo->nMin = m_nMinPos; - lpScrollInfo->nMax = m_nMaxPos; - lpScrollInfo->nPage = m_uPage; - lpScrollInfo->nPos = m_nPos; - lpScrollInfo->nTrackPos = m_nTrackPos; - return TRUE; -} - -// SBM_SETSCROLLINFO message handler. -LRESULT CXeScrollBarBase::OnSbmSetScrollInfo( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - BOOL bRedraw = (BOOL)wparam; - LPSCROLLINFO lpScrollInfo = (LPSCROLLINFO)lparam; - if( lpScrollInfo->cbSize != sizeof(SCROLLINFO) ) - return 0; - if( lpScrollInfo->fMask & SIF_PAGE ) - { - m_uPage = lpScrollInfo->nPage; - // Note - windows scrollbars can have a page size = 0. - } - if( lpScrollInfo->fMask & SIF_RANGE ) - { - m_nMinPos = lpScrollInfo->nMin; - m_nMaxPos = lpScrollInfo->nMax; - } - if( lpScrollInfo->fMask & SIF_POS ) - { - m_nPos = lpScrollInfo->nPos; - } - if( lpScrollInfo->fMask & SIF_DISABLENOSCROLL ) - { - BOOL bEnable = ( (int)m_uPage < (m_nMaxPos - m_nMinPos) ) ? TRUE : FALSE; - m_bNoScroll = !bEnable; - EnableWindow( bEnable ); - } - - if( m_nMaxPos < m_nMinPos ) - m_nMaxPos = m_nMinPos; - int nSUrange = abs(m_nMaxPos - m_nMinPos) + 1; - if( m_uPage > (UINT)nSUrange ) - m_uPage = (UINT)nSUrange; - - if( m_uPage == 0 ) - m_nMaxReportedPos = m_nMaxPos; - else - m_nMaxReportedPos = m_nMaxPos - ((int)m_uPage - 1); - - if( m_nPos < m_nMinPos ) - m_nPos = m_nMinPos; - else if( m_nPos > m_nMaxReportedPos ) - m_nPos = m_nMaxReportedPos; - - RecalcRects(); - - if( bRedraw ) - Invalidate(); - - return m_nPos; -} - -// SBM_ENABLE_ARROWS message handler. -LRESULT CXeScrollBarBase::OnSbmEnableArrows( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - /* ImplNote - during testing the windows scrollbar behaved strangely when only one - button was disabled. For that reason only enable/disable both is supported here. */ - EnableWindow( ( wparam & ESB_DISABLE_BOTH ) ? FALSE : TRUE ); - // wParam Specifies whether the scroll bar arrows are enabled or disabled and - // indicates which arrows are enabled or disabled. - return TRUE; -} - -// SBM_GETSCROLLBARINFO message handler. -LRESULT CXeScrollBarBase::OnSbmGetScrollBarInfo( WPARAM wparam, LPARAM lparam ) -{ - ASSERT(::IsWindow(m_hWnd)); - SCROLLBARINFO *psbi = (SCROLLBARINFO *)lparam; - if( !psbi || psbi->cbSize != sizeof(SCROLLBARINFO) ) - return FALSE; - - /* Note - information on how to implement this is a little sparse from MS. - Need make a few educated guesses. - Note - testing (comparing 'this' to WIN SBs) has shown that: - rcScrollBar is in screen coords. - dxyLineButton is arrow button width when horz. SB. - dxyLineButton is arrow button height when vert. SB. - */ - - psbi->rcScrollBar = m_rectClient; // Coordinates of the scroll bar. - ClientToScreen( &psbi->rcScrollBar ); // In screen coords. - - if( m_bHorizontal ) - { - psbi->dxyLineButton = m_rectTLArrow.Width();// arrow button width. - psbi->xyThumbTop = m_rectThumb.left; // Position of the left of the thumb. - psbi->xyThumbBottom = m_rectThumb.right; // Position of the right of the thumb. - } - else - { - psbi->dxyLineButton = m_rectTLArrow.Height();// arrow button height. - psbi->xyThumbTop = m_rectThumb.top; // Position of the top of the thumb. - psbi->xyThumbBottom = m_rectThumb.bottom; // Position of the bottom of the thumb. - } - - // psbi->rgstate - An array of DWORD elements. Each element indicates the state of a - // scroll bar component. The following values show the scroll bar component that - // corresponds to each array index. Index Scroll bar component - // 0 The scroll bar itself. - // 1 The top or right arrow button. - // 2 The page up or page right region. - // 3 The scroll box (thumb). - // 4 The page down or page left region. - // 5 The bottom or left arrow button. - DWORD dwState = ( m_bEnabled ) ? 0 : STATE_SYSTEM_UNAVAILABLE; - DWORD dwTLchSt = dwState, dwBRchSt = dwState, dwThumbSt = dwState; - DWORD dwTLbtnSt = dwState, dwBRbtnSt = dwState; - if( m_rectTLChannel.IsRectEmpty() ) - dwTLchSt |= STATE_SYSTEM_INVISIBLE; - if( m_rectBRChannel.IsRectEmpty() ) - dwBRchSt |= STATE_SYSTEM_INVISIBLE; - if( m_rectThumb.IsRectEmpty() ) - dwThumbSt |= STATE_SYSTEM_INVISIBLE; - if( m_eMouseDownArea.IsTLButton() ) - dwTLbtnSt |= STATE_SYSTEM_PRESSED; - if( m_eMouseDownArea.IsTLChannel() ) - dwTLchSt |= STATE_SYSTEM_PRESSED; - if( m_eMouseDownArea.IsThumb() ) - dwThumbSt |= STATE_SYSTEM_PRESSED; - if( m_eMouseDownArea.IsBRChannel() ) - dwBRchSt |= STATE_SYSTEM_PRESSED; - if( m_eMouseDownArea.IsBRButton() ) - dwBRbtnSt |= STATE_SYSTEM_PRESSED; - psbi->rgstate[0] = dwState; - psbi->rgstate[1] = dwTLbtnSt; - psbi->rgstate[2] = dwTLchSt; - psbi->rgstate[3] = dwThumbSt; - psbi->rgstate[4] = dwBRchSt; - psbi->rgstate[5] = dwBRbtnSt; - - // The DWORD element for each scroll bar component can include a combination of the - // following bit flags. - // STATE_SYSTEM_INVISIBLE - For the scroll bar itself, indicates the specified - // vertical or horizontal scroll bar does not exist. For the page up or page - // down regions, indicates the thumb is positioned such that the region does - // not exist. - // STATE_SYSTEM_OFFSCREEN - For the scroll bar itself, indicates the window is sized - // such that the specified vertical or horizontal scroll bar is not currently - // displayed. (SK note - applies to NC scroll bars only). - // STATE_SYSTEM_PRESSED - The arrow button or page region is pressed. - // STATE_SYSTEM_UNAVAILABLE - The component is disabled. - - return TRUE; -} - -void CXeScrollBarBase::OnPaint() -{ // WM_PAINT message handler. - ASSERT(::IsWindow(m_hWnd)); - CPaintDC dc(this); // device context for painting - - DrawScrollBar( &dc ); - // Do not call CScrollBar::OnPaint() for painting messages -} - -BOOL CXeScrollBarBase::OnEraseBkgnd( CDC* pDC ) -{ // WM_ERASEBKGND message handler. - return TRUE; // All painting done in OnPaint. -} - -LRESULT CXeScrollBarBase::OnKeyDown( WPARAM wParam, LPARAM lParam ) -{ // WM_KEYDOWN message handler. - ASSERT(::IsWindow(m_hWnd)); - WORD wSBcode = 0xFFFF; - // Note - SB_PAGELEFT == SB_PAGEUP etc. see winuser.h - switch( wParam ) - { - case VK_PRIOR: - wSBcode = SB_PAGELEFT; - break; - - case VK_NEXT: - wSBcode = SB_PAGERIGHT; - break; - - case VK_HOME: - wSBcode = SB_LEFT; - break; - - case VK_END: - wSBcode = SB_RIGHT; - break; - - case VK_LEFT: - wSBcode = SB_LINELEFT; - break; - - case VK_RIGHT: - wSBcode = SB_LINERIGHT; - break; - - case VK_UP: - wSBcode = SB_LINEUP; - break; - - case VK_DOWN: - wSBcode = SB_LINEDOWN; - break; - } - - if( wSBcode != 0xFFFF ) - { - SendScrollMsg( wSBcode ); - m_bNeedEndScroll = TRUE; // Send SB_ENDSCROLL on WM_KEYUP. - } - - return 0; // Indicate we processed this message (eat all key msgs). - // Note - testing shows that windows looks for another child control to process - // keyboard input if we don't return 0 here (and we lose focus). -} - -LRESULT CXeScrollBarBase::OnKeyUp( WPARAM wParam, LPARAM lParam ) -{ // WM_KEYUP message handler. - if( m_bNeedEndScroll ) - { - SendScrollMsg( SB_ENDSCROLL ); - m_bNeedEndScroll = FALSE; - } - return 0; // Indicate we processed this message (eat all key msgs). -} - -void CXeScrollBarBase::OnLButtonDown( UINT nFlags, CPoint point ) -{ // WM_LBUTTONDOWN message handler. - ASSERT(::IsWindow(m_hWnd)); - SetCapture(); - BOOL bHasTabStop = ( ::GetWindowLong( m_hWnd, GWL_STYLE ) & WS_TABSTOP ) ? TRUE : FALSE; - if( bHasTabStop ) - SetFocus(); // Only 'steal' focus if 'this' has Tab stop. - - m_eMouseDownArea = GetAreaFromPoint( point ); - - WORD wSBcode = 0xFFFF; - // Note - SB_PAGELEFT == SB_PAGEUP etc. see winuser.h - if( m_eMouseDownArea.eArea == eTLbutton ) - wSBcode = SB_LINELEFT; - else if( m_eMouseDownArea.eArea == eTLchannel ) - wSBcode = SB_PAGELEFT; - else if( m_eMouseDownArea.eArea == eBRchannel ) - wSBcode = SB_PAGERIGHT; - else if( m_eMouseDownArea.eArea == eBRbutton ) - wSBcode = SB_LINERIGHT; - - if( wSBcode != 0xFFFF ) - { - SendScrollMsg( wSBcode ); - m_bNeedEndScroll = TRUE; // Send SB_ENDSCROLL on WM_LBUTTONUP message. - } - - if( m_eMouseDownArea.IsThumb() ) // Store X or Y offset from thumb edge. - m_xyThumbDragOffset = ( m_bHorizontal ) ? point.x - m_rectThumb.left - : point.y - m_rectThumb.top; - - // Set timer for first auto repeat - when button or channel clicked. - if( m_eMouseDownArea.IsButton() || m_eMouseDownArea.IsChannel() ) - SetTimer( XSB_LBTN_DOWN_TIMERID, XSB_LBTN_DOWN_TIME, 0 ); - - CScrollBar::OnLButtonDown(nFlags, point); -} - -void CXeScrollBarBase::OnLButtonUp( UINT nFlags, CPoint point ) -{ // WM_LBUTTONUP message handler. - ASSERT(::IsWindow(m_hWnd)); - ReleaseCapture(); - KillTimer( XSB_LBTN_DOWN_TIMERID ); - KillTimer( XSB_LBTN_REPT_TIMERID ); - - m_eMouseDownArea = eNone; - - if( m_bDragging ) // Did we send any SB_THUMBTRACK messages? - { - SendScrollMsg( SB_THUMBPOSITION, (WORD)m_nTrackPos ); - m_bDragging = FALSE; - RecalcRects(); // Reset thumb pos. to current scroll pos. - } - - if( m_bNeedEndScroll ) - { - SendScrollMsg( SB_ENDSCROLL ); // Let parent know scrolling has ended. - m_bNeedEndScroll = FALSE; - } - - Invalidate(); - - CScrollBar::OnLButtonUp(nFlags, point); -} - -/* updated to newer api and reversing return value to avoid mousewheel propagating */ -/* remove restriction on vert scrollbar, as both are valid in win32 */ -BOOL CXeScrollBarBase::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { - ASSERT(::IsWindow(m_hWnd)); - //short xPos = pt.x; - //short yPos = pt.y; - - //if (!m_bHorizontal) // Mouse wheel messages only apply to vertical scrollbar. - //{ - WORD wSBcode = 0xFFFF; - if (zDelta >= WHEEL_DELTA) { - wSBcode = SB_LINEUP; - } else if (zDelta <= -WHEEL_DELTA) { - wSBcode = SB_LINEDOWN; - zDelta = -zDelta; - } - if (wSBcode != 0xFFFF) { - do { - for (UINT i=0; i= WHEEL_DELTA); - SendScrollMsg(SB_ENDSCROLL); - } - return 1; // Message was processed. (was 0, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 1 if scrolling enabled - //} - //return 0; // Message not processed. (was 1, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 0 if scrolling not enabled -} - - -void CXeScrollBarBase::OnMouseMove( UINT nFlags, CPoint point ) -{ // WM_MOUSEMOVE message handler. - ASSERT(::IsWindow(m_hWnd)); - if( !m_bTrackMouseLeave ) - { // We want a WM_MOUSELEAVE message when mouse leaves our client area. - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(tme); - tme.hwndTrack = m_hWnd; - tme.dwFlags = TME_LEAVE; - tme.dwHoverTime = 0; - - // Note - _TrackMouseEvent is from comctl32.dll - emulates TrackMouseEvent - // if it does not exist. - m_bTrackMouseLeave = _TrackMouseEvent( &tme ); - } - - stXSB_AREA eOldMouseArea = m_eMouseOverArea; - - m_eMouseOverArea = GetAreaFromPoint( point ); // Update mouse over area. - - if( m_eMouseDownArea.IsThumb() && m_dblPx_SU > 0 ) - { // User is dragging the thumb. - BOOL bStartDrag = FALSE; - if( !m_bDragging ) - { - bStartDrag = TRUE; // Start of thumb dragging. - m_bDragging = TRUE; - } - int nTrackPos; - double dblScrollPos; - if( m_bHorizontal ) - { // X pos of left edge of thumb (0...?) - int xPos = point.x - m_xyThumbDragOffset - m_rectTLArrow.right; - dblScrollPos = (double)xPos / m_dblPx_SU; - nTrackPos = round_ud_dbl( dblScrollPos ) + m_nMinPos; - } - else - { // Y pos of top edge of thumb (0...?) - int yPos = point.y - m_xyThumbDragOffset - m_rectTLArrow.bottom; - dblScrollPos = (double)yPos / m_dblPx_SU; - nTrackPos = round_ud_dbl( dblScrollPos ) + m_nMinPos; - } - if( nTrackPos < m_nMinPos ) - nTrackPos = m_nMinPos; - else if( nTrackPos > m_nMaxReportedPos ) - nTrackPos = m_nMaxReportedPos; - - //adipose: moved this block to before sending scroll message. otherwise scrollbar updates poorly on slower windows (listctrl) - //also call updatewindow to redraw immediately - // Recalculate thumb XY pos. and redraw if pos. changed. - if (RecalcRectsThumbTrack(point)) { - Invalidate(); - UpdateWindow(); - } - - if( bStartDrag || m_nTrackPos != nTrackPos ) - { // Send scroll message when user starts dragging - // OR when track pos has changed. - m_nTrackPos = nTrackPos; - SendScrollMsg( SB_THUMBTRACK, (WORD)m_nTrackPos ); - m_bNeedEndScroll = TRUE; - } - } - - if( m_eMouseOverArea != eOldMouseArea ) - Invalidate(); - - CScrollBar::OnMouseMove(nFlags, point); -} - -LRESULT CXeScrollBarBase::OnMouseLeave( WPARAM wparam, LPARAM lparam ) -{ // WM_MOUSELEAVE message handler. - ASSERT(::IsWindow(m_hWnd)); - m_bTrackMouseLeave = FALSE; - m_eMouseOverArea = eNone; - Invalidate(); - return 0; -} - -LRESULT CXeScrollBarBase::OnGetDlgCode( WPARAM wParam, LPARAM lParam ) -{ // WM_GETDLGCODE message handler. - ASSERT(::IsWindow(m_hWnd)); - BOOL bHasTabStop = ( ::GetWindowLong( m_hWnd, GWL_STYLE ) & WS_TABSTOP ) ? TRUE : FALSE; - - LRESULT lResult = Default(); - if( lParam ) // lParam points to an MSG structure? - { - LPMSG lpmsg = (LPMSG)lParam; - if( (lpmsg->message == WM_KEYDOWN // Keyboard input? - || lpmsg->message == WM_KEYUP) - && lpmsg->wParam != VK_TAB ) // AND NOT TAB key? - { - if( bHasTabStop ) // 'this' window has Tab stop? - { - lResult |= DLGC_WANTMESSAGE; // We want keyboard input (except TAB). - // Note - windows will set focus to 'this' (and send WM_SETFOCUS) - // if we return DLGC_WANTMESSAGE here. - } - else - { // 'this' windows does NOT have TAB stop. - // Note - windows standard scroll bar implements a special behaviour - // for scroll bars when no tab stop for the UP, DOWN, LEFT, RIGHT keys. - if( m_bHorizontal ) - { - if( lpmsg->wParam == VK_LEFT || lpmsg->wParam == VK_RIGHT ) - lResult |= DLGC_WANTMESSAGE; - } - else - { - if( lpmsg->wParam == VK_UP || lpmsg->wParam == VK_DOWN ) - lResult |= DLGC_WANTMESSAGE; - } - } - } - } - else - { - if( bHasTabStop ) - lResult |= DLGC_WANTTAB; // 'this' has WS_TABSTOP style - we want focus. - else - lResult |= DLGC_STATIC; // no tab stop - we don't want focus. - } - return lResult; -} - -void CXeScrollBarBase::OnCancelMode() -{ // WM_CANCELMODE message handler. - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnCancelMode(); - - // Need to handle WM_CANCELMODE message. - // See -> http://support.microsoft.com/kb/74548/en-us - - if( !m_eMouseDownArea.IsNone() ) // Mouse L button down? - OnLButtonUp( 0, CPoint(0,0) ); // Do L btn up processing now. -} - -void CXeScrollBarBase::OnContextMenu( CWnd* pWnd, CPoint point ) -{ // WM_CONTEXTMENU message handler. - ASSERT(::IsWindow(m_hWnd)); - - m_ptMenu = point; - ScreenToClient( &m_ptMenu ); - - // Try to load scroll bar menu from user32.dll - to get menu in 'local' language. - CString strDllPathName; - GetWindowsDirectory( strDllPathName.GetBuffer(MAX_PATH), MAX_PATH ); - strDllPathName.ReleaseBuffer(); - strDllPathName += _T("\\system32\\user32.dll"); - - HMODULE hUser32dllModule = ::LoadLibrary( strDllPathName ); - if( hUser32dllModule ) - { // Get menu #64 (horz.) or menu #80 (vert.) from user32.dll. - HMENU hMenu = 0, hSubMenu = 0; - if( m_bHorizontal ) - hMenu = ::LoadMenu( hUser32dllModule, MAKEINTRESOURCE(64) ); - else - hMenu = ::LoadMenu( hUser32dllModule, MAKEINTRESOURCE(80) ); - if( hMenu ) - { - hSubMenu = ::GetSubMenu( hMenu, 0 ); - if( hSubMenu ) - { - ::TrackPopupMenu( hSubMenu, TPM_LEFTALIGN, point.x, point.y, 0, - GetSafeHwnd(), 0 ); - // Note - TrackPopupMenu does not return until menu has been dismissed. - ::DestroyMenu( hMenu ); - } - } - ::FreeLibrary( hUser32dllModule ); - if( hSubMenu ) - return; // Using menu from user32.dll was successful. - } - - // If using menu from user32.dll was unsuccessful - create menu (in english). - CMenu menu; - menu.CreatePopupMenu(); - menu.AppendMenu( MF_STRING, XSB_IDM_SCRHERE, _T("Scroll Here") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - if( m_bHorizontal ) - { - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_TL, _T("Left Edge") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_BR, _T("Right Edge") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_UL, _T("Page Left") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_DR, _T("Page Right") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_UL, _T("Scroll Left") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_DR, _T("Scroll Right") ); - } - else - { - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_TL, _T("Top") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_BR, _T("Bottom") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_UL, _T("Page Up") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_DR, _T("Page Down") ); - menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_UL, _T("Scroll Up") ); - menu.AppendMenu( MF_STRING, XSB_IDM_SCR_DR, _T("Scroll Down") ); - } - menu.TrackPopupMenu( TPM_LEFTALIGN, point.x, point.y, pWnd ); - // Note - TrackPopupMenu does not return until menu has been dismissed. - menu.DestroyMenu(); -} - -void CXeScrollBarBase::OnMenuCommands( UINT uID ) -{ - ASSERT(::IsWindow(m_hWnd)); - int xyOfs, nScrollHerePos; - double dblScrollPos; - WORD wSBcode = 0xFFFF; - switch( uID ) - { - case XSB_IDM_SCRHERE: - // Calculate pos (in scroll units) - if( m_bHorizontal ) - xyOfs = m_ptMenu.x - m_rectTLArrow.right; - else - xyOfs = m_ptMenu.y - m_rectTLArrow.bottom; - if( xyOfs < 0 ) - xyOfs = 0; - if( m_rectThumb.IsRectEmpty() || !(m_dblPx_SU > 0) ) - break; // Can't 'Scroll Here'. - dblScrollPos = (double)xyOfs / m_dblPx_SU; - nScrollHerePos = m_nMinPos + round_ud_dbl( dblScrollPos ); - if( nScrollHerePos < m_nMinPos ) - nScrollHerePos = m_nMinPos; - else if( nScrollHerePos > m_nMaxReportedPos ) - nScrollHerePos = m_nMaxReportedPos; - m_nTrackPos = nScrollHerePos; - SendScrollMsg( SB_THUMBPOSITION, (WORD)m_nTrackPos ); - SendScrollMsg( SB_ENDSCROLL ); - break; - case XSB_IDM_SCR_TL: - wSBcode = SB_TOP; - break; - case XSB_IDM_SCR_BR: - wSBcode = SB_BOTTOM; - break; - case XSB_IDM_SCR_PG_UL: - wSBcode = SB_PAGEUP; - break; - case XSB_IDM_SCR_PG_DR: - wSBcode = SB_PAGEDOWN; - break; - case XSB_IDM_SCR_UL: - wSBcode = SB_LINEUP; - break; - case XSB_IDM_SCR_DR: - wSBcode = SB_LINEDOWN; - break; - } - if( wSBcode != 0xFFFF ) - { - SendScrollMsg( wSBcode ); - SendScrollMsg( SB_ENDSCROLL ); - } -} - -void CXeScrollBarBase::OnTimer( UINT_PTR nIDEvent ) -{ // WM_TIMER message handler. - ASSERT(::IsWindow(m_hWnd)); - if( nIDEvent == XSB_LBTN_DOWN_TIMERID ) - { // First auto repeat timer event. - KillTimer( XSB_LBTN_DOWN_TIMERID ); - SetTimer( XSB_LBTN_REPT_TIMERID, XSB_LBTN_REPT_TIME, 0 ); - } - if( nIDEvent == XSB_LBTN_DOWN_TIMERID || nIDEvent == XSB_LBTN_REPT_TIMERID ) - { // Auto repeat - CPoint ptCurMouse; - if( ::GetCursorPos( &ptCurMouse ) ) - { - ::ScreenToClient( GetSafeHwnd(), &ptCurMouse ); - m_eMouseOverArea = GetAreaFromPoint( ptCurMouse ); // Update mouse over area. - } - if( m_eMouseDownArea.IsTLButton() ) - { - if( m_eMouseOverArea.IsTLButton() ) // Mouse still over button? - SendScrollMsg( SB_LINELEFT ); - } - else if( m_eMouseDownArea.IsBRButton() ) - { - if( m_eMouseOverArea.IsBRButton() ) // Mouse still over button? - SendScrollMsg( SB_LINERIGHT ); - } - else if( m_eMouseDownArea.IsTLChannel() ) - { - if( m_eMouseOverArea.IsTLChannel() ) // Mouse still over channel? - SendScrollMsg( SB_PAGELEFT ); - } - else if( m_eMouseDownArea.IsBRChannel() ) - { - if( m_eMouseOverArea.IsBRChannel() ) // Mouse still over channel? - SendScrollMsg( SB_PAGERIGHT ); - } - // Note - SB_LINELEFT == SB_LINEUP etc. see winuser.h - } - if( nIDEvent == XSB_FOCUS_TIMERID ) - { // Blinking focus timer. - if( m_bNeedEndScroll ) - { // Draw normal thumb box while user is scrolling. - if( !m_bDrawGripper ) - { // Redraw scroll bar if currently drawn without 'gripper'. - m_bDrawGripper = TRUE; - Invalidate(); // Draw 'blinking' focus. - } - } - else - { // Draw blinking 'gripper' to indicate 'focus'. - m_bDrawGripper = !m_bDrawGripper; - Invalidate(); // Draw 'blinking' focus. - } - } - - CScrollBar::OnTimer( nIDEvent ); -} - -void CXeScrollBarBase::OnSize( UINT nType, int cx, int cy ) -{ // WM_SIZE message handler. - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnSize( nType, cx, cy ); - - if( m_hWnd ) - RecalcRects(); -} - -void CXeScrollBarBase::OnSetFocus( CWnd* pOldWnd ) -{ // WM_SETFOCUS message handler. - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnSetFocus( pOldWnd ); - m_bHasFocus = TRUE; - m_bDrawGripper = FALSE; - SetTimer( XSB_FOCUS_TIMERID, XSB_FOCUS_TIME, 0 ); - Invalidate(); -} - -void CXeScrollBarBase::OnKillFocus( CWnd* pNewWnd ) -{ // WM_KILLFOCUS message handler. - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnKillFocus( pNewWnd ); - m_bHasFocus = FALSE; - m_bDrawGripper = TRUE; - KillTimer( XSB_FOCUS_TIMERID ); - Invalidate(); -} - -void CXeScrollBarBase::OnEnable( BOOL bEnable ) -{ // WM_ENABLE message handler - ASSERT(::IsWindow(m_hWnd)); - CScrollBar::OnEnable(bEnable); - - m_bEnabled = bEnable; - - RecalcRects(); // Need to recalc. because no thumb is shown when disabled. - - Invalidate(); -} - -void CXeScrollBarBase::SendScrollMsg( WORD wSBcode, WORD wHiWPARAM /*= 0*/ ) -{ - ASSERT(::IsWindow(m_hWnd)); - if( m_pParent && ::IsWindow( m_pParent->m_hWnd ) ) - { - m_pParent->SendMessage( ( m_bHorizontal ) ? WM_HSCROLL : WM_VSCROLL, - MAKELONG(wSBcode,wHiWPARAM), (LPARAM)m_hWnd ); - } -} - -eXSB_AREA CXeScrollBarBase::GetAreaFromPoint( CPoint point ) -{ - ASSERT(::IsWindow(m_hWnd)); - if( !m_rectClient.PtInRect( point ) ) - return eNone; - if( m_rectThumb.PtInRect( point ) ) - return eThumb; - if( m_rectTLArrow.PtInRect( point ) ) - return eTLbutton; - if( m_rectBRArrow.PtInRect( point ) ) - return eBRbutton; - if( m_rectTLChannel.PtInRect( point ) ) - return eTLchannel; - if( m_rectBRChannel.PtInRect( point ) ) - return eBRchannel; - return eNone; -} - -const CRect *CXeScrollBarBase::GetUIelementDrawState( eXSB_AREA eElem, - XSB_EDRAWELEM &eState ) -{ - ASSERT(::IsWindow(m_hWnd)); - CRect *prcElem = 0; - eState = eNotDrawn; - switch( eElem ) - { - case eTLbutton: - prcElem = &m_rectTLArrow; - break; - case eBRbutton: - prcElem = &m_rectBRArrow; - break; - case eTLchannel: - prcElem = &m_rectTLChannel; - break; - case eBRchannel: - prcElem = &m_rectBRChannel; - break; - case eThumb: - prcElem = &m_rectThumb; - break; - } - if( !prcElem || prcElem->IsRectEmpty() ) - eState = eNotDrawn; - if( !m_bEnabled ) - eState = eDisabled; - else if( m_eMouseDownArea.eArea == eElem ) - eState = eDown; - else if( m_eMouseOverArea.eArea == eElem && !m_bDragging) - eState = eHot; - else - eState = eNormal; - return prcElem; -} - -BOOL CXeScrollBarBase::CalcThumb( int cxyChannel, int &xyThumb, int &cxyThumb ) -{ - // Range in 'scroll units' (SU) - Note +1 because min/max are 'inclusive' values. - int nSU_Range = abs(m_nMaxPos - m_nMinPos) + 1; - if( nSU_Range == 0 // No thumb when scroll range is 0 - || cxyChannel <= (int)m_uThumbMinHW // No space for thumb. - || !m_bEnabled ) // No thumb when disabled. - return FALSE; - - // We have space for thumb. - - // thumb size = scroll bar size * page size / scroll bar range - // (pixels) (pixels) (scroll units) (scroll units) - - // When page size is 0 thumb size is set to minimum size. - - m_dblPx_SU = (double)cxyChannel / (double)nSU_Range; // Pixels per scroll unit. - - double dblXY = (double)(m_nPos - m_nMinPos) * m_dblPx_SU; - xyThumb = (int)dblXY; - if( fabs_dbl( dblXY - (double)xyThumb ) > 0.5 ) - xyThumb++; - - double dblCXY = (double)m_uPage * m_dblPx_SU; - cxyThumb = (int)dblCXY; - if( fabs_dbl( dblCXY - (double)cxyThumb ) > 0.5 ) - cxyThumb++; - - //if( m_uPage == 0 ) - // cxyThumb = GetCXYarrow(); // Thumb is same as arrow button when page = 0. - // Note - WIN SBs show thumb box same size as arrow button when PAGE = 0. - - if( cxyThumb < (int)m_uThumbMinHW ) - { - int nErrCXY = (int)m_uThumbMinHW - cxyThumb; - cxyThumb = (int)m_uThumbMinHW; - - // Calculate new thumb X or Y position when 'error' in position. - double dblErr_Px = (double)nErrCXY / (double)cxyChannel; - double dblXYoffs = dblErr_Px * xyThumb; - int xyOffs = (int)dblXYoffs; - if( fabs_dbl( dblXYoffs - (double)xyOffs ) > 0.5 ) - xyOffs++; - xyThumb -= xyOffs; - } - - // Sometimes it's needed to adjust the size and or position because scroll bar - // parameters are in error. - - // Calculate last possible X or Y for thumb. - int xyLastPossible = cxyChannel - cxyThumb; - if( xyThumb > xyLastPossible ) - xyThumb = xyLastPossible; - - if( xyThumb < 0 ) - xyThumb = 0; - - if( (xyThumb + cxyThumb) > cxyChannel ) - cxyThumb = cxyChannel - xyThumb; - - return TRUE; -} - -void CXeScrollBarBase::RecalcRects() -{ - if( !GetSafeHwnd() ) - return; - - GetClientRect( &m_rectClient ); // Update client rect. - - BOOL bHasThumb = FALSE; - m_rectThumb.SetRectEmpty(); - - if( m_bHorizontal ) - { // Calc. arrows - int cxClient = m_rectClient.Width(); - int cxArrow = GetCXYarrow(); // Arrow button width. - - if( cxClient < (2 * cxArrow) ) - cxArrow = cxClient / 2; // Limit arrow width to available area. - - m_rectTLArrow.SetRect( m_rectClient.left, m_rectClient.top, - m_rectClient.left + cxArrow, m_rectClient.bottom); - - m_rectBRArrow.SetRect( m_rectClient.right - cxArrow, m_rectClient.top, - m_rectClient.right, m_rectClient.bottom ); - - // Calc. thumb size and position - int xThumb, cxThumb, cxChannel = cxClient - (2 * cxArrow); - bHasThumb = CalcThumb( cxChannel, xThumb, cxThumb ); - if( bHasThumb ) - { // We have space for thumb. - xThumb += m_rectTLArrow.right; - m_rectThumb = m_rectTLArrow; - m_rectThumb.left = xThumb; - m_rectThumb.right = xThumb + cxThumb; - } - - // Calc. channels - m_rectTLChannel = m_rectTLArrow; - m_rectBRChannel = m_rectBRArrow; - m_rectTLChannel.left = m_rectTLArrow.right; - if( bHasThumb ) - { - m_rectTLChannel.right = m_rectThumb.left; - m_rectBRChannel.left = m_rectThumb.right; - m_rectBRChannel.right = m_rectBRArrow.left; - } - else - { - m_rectTLChannel.right = m_rectBRArrow.left; // L channel reaches to R arrow. - m_rectBRChannel.SetRectEmpty(); // No thumb - so R channel not needed. - } - } - else // Vertical scroll bar. - { // Calc. arrows - int cyClient = m_rectClient.Height(); - int cyArrow = GetCXYarrow(); // Arrow button height. - - if( cyClient < (2 * cyArrow) ) - cyArrow = cyClient / 2; // Limit arrow height to available area. - - m_rectTLArrow.SetRect( m_rectClient.left, m_rectClient.top, - m_rectClient.right, m_rectClient.top + cyArrow ); - - m_rectBRArrow.SetRect( m_rectClient.left, m_rectClient.bottom - cyArrow, - m_rectClient.right, m_rectClient.bottom ); - - // Calc. thumb size and position - int yThumb, cyThumb, cyChannel = cyClient - (2 * cyArrow); - bHasThumb = CalcThumb( cyChannel, yThumb, cyThumb ); - if( bHasThumb ) - { // We have space for thumb. - yThumb +=m_rectTLArrow.bottom ; - m_rectThumb = m_rectTLArrow; - m_rectThumb.top = yThumb; - m_rectThumb.bottom = yThumb + cyThumb; - } - - // Calc. channels - m_rectTLChannel = m_rectTLArrow; - m_rectBRChannel = m_rectBRArrow; - m_rectTLChannel.top = m_rectTLArrow.bottom; - if( bHasThumb ) - { - m_rectTLChannel.bottom = m_rectThumb.top; - m_rectBRChannel.top = m_rectThumb.bottom; - m_rectBRChannel.bottom = m_rectBRArrow.top; - } - else - { - m_rectTLChannel.bottom = m_rectBRArrow.top; // T channel reaches to B arrow. - m_rectBRChannel.SetRectEmpty(); // No thumb - so T channel not needed. - } - } -} - -BOOL CXeScrollBarBase::RecalcRectsThumbTrack( CPoint point ) -{ - ASSERT(m_bDragging && !m_rectThumb.IsRectEmpty()); // Sanity check. - if( m_bHorizontal ) - { // Horizontal scroll bar. - // X pos of left edge of thumb (0...?) - int xPos = point.x - m_xyThumbDragOffset; - if( xPos < m_rectTLArrow.right ) - xPos = m_rectTLArrow.right; - int nThumbWidth = m_rectThumb.Width(); - if( xPos > (m_rectBRArrow.left - nThumbWidth) ) - xPos = (m_rectBRArrow.left - nThumbWidth); - if( xPos == m_rectThumb.left ) - return FALSE; // No change. - m_rectThumb.left = xPos; - m_rectThumb.right = m_rectThumb.left + nThumbWidth; - m_rectTLChannel.right = m_rectThumb.left; - m_rectBRChannel.left = m_rectThumb.right; - } - else - { // Vertical scroll bar. - // Y pos of top edge of thumb (0...?) - int yPos = point.y - m_xyThumbDragOffset; - if( yPos < m_rectTLArrow.bottom ) - yPos = m_rectTLArrow.bottom; - int nThumbHeight = m_rectThumb.Height(); - if( yPos > (m_rectBRArrow.top - nThumbHeight) ) - yPos = (m_rectBRArrow.top - nThumbHeight); - if( yPos == m_rectThumb.top ) - return FALSE; // No change. - m_rectThumb.top = yPos; - m_rectThumb.bottom = m_rectThumb.top + nThumbHeight; - m_rectTLChannel.bottom = m_rectThumb.top; - m_rectBRChannel.top = m_rectThumb.bottom; - } - return TRUE; -} - -UINT CXeScrollBarBase::GetCXYarrow() -{ - if( m_uArrowWH ) // Has derived class set this value? - return m_uArrowWH; // Use arrow button width/height set by derived class. - - // If m_uArrowWH == 0 we must assume the arrow button is same width or height as - // the scrollbar window. - if( m_bHorizontal ) - return m_rectClient.Height(); // Horz. arrow button is same height as window. - return m_rectClient.Width(); // Vert. arrow button is same width as window. +///////////////////////////////////////////////////////////////////////////////////////// +// XeScrollBarBase.cpp Version 1.1 +// This class is designed as a base class for another class that will +// do all painting. This class handles all business logic. No painting +// is done in this class - except in debug mode. +// +// Author: Snorri Kristjansson +// snorrikris@gmail.com +// +// History +// Version 1.1 - 2010 October 21 +// - Changed base class to CScrollBar (was CWnd). +// - Fixed many issues to make this scroll bar behave (almost) the same as windows +// scroll bar. +// +// Version 1.0 - 2009 +// - Never released. +// +// Acknowledgements: +// Thanks to Hans Dietrich for his CXScrollBar class, +// which I used as the starting point for CXeScrollBarBase: +// http://www.codeproject.com/KB/miscctrl/XScrollBar.aspx +// (I don't think any of his code survived into this version - but thanks all the same). +// +// License: +// This software is released into the public domain. You are free to use +// it in any way you like, except that you may not sell this source code. +// +// This software is provided "as is" with no expressed or implied warranty. +// I accept no liability for any damage or loss of business that this +// software may cause. +// +///////////////////////////////////////////////////////////////////////////////////////// + +/**************************************************************************************** +TODO: + H Mouse wheel support (L/R wheel push) - WM_MOUSEHWHEEL (new message Vista and later). + + Change code to pure WIN32 - no MFC - use as base base class for CXeScrollBarBase. +****************************************************************************************/ + +#include "stdafx.h" +#include "XeScrollBarBase.h" + +/**************************************************************************************** +Research resources: + +Scroll bar MSDN WIN32 reference. +http://msdn.microsoft.com/en-us/library/bb787529(VS.85).aspx + +Scroll Bar Controls in Win32 +http://msdn.microsoft.com/en-us/library/ms997557.aspx + +How/why to handle WM_CANCELMODE message. +http://support.microsoft.com/kb/74548/en-us + +How/why to handle WM_GETDLGCODE message. +http://support.microsoft.com/kb/83302 + +Discussion about thumb size calculations and more (good one). +http://blogs.msdn.com/oldnewthing/archive/2009/09/21/9897553.aspx + +Discussion about thumb size calculations. +http://social.msdn.microsoft.com/forums/en-US/wpf/thread/415eacf6-481e-4ebd-a6b0-2953e851183d/ + +From the November 2001 issue of MSDN Magazine. +Understanding CControlView, Changing Scroll Bar Color in MFC Apps +by Paul DiLascia +http://msdn.microsoft.com/en-us/magazine/cc301457.aspx + +Handling Keyboard and Mouse Application Buttons in WTL +By Michael Dunn +http://www.codeproject.com/KB/wtl/WTLAppButtons.aspx + +XScrollBar - Scroll bar like Windows Media Player's +By Hans Dietrich +http://www.codeproject.com/KB/miscctrl/XScrollBar.aspx + +Developing a Custom Windows Scrollbar in MFC +By Don Metzler, DDJ June 01, 2003 +http://www.drdobbs.com/windows/184416659 + +SkinControls 1.1 - A journey in automating the skinning of Windows controls +by .dan.g. +http://www.codeproject.com/KB/library/SkinCtrl.aspx + +Custom Scrollbar Library version 1.1 +by James Brown +http://www.codeproject.com/KB/dialog/coolscroll.aspx + +Replace a Window's Internal Scrollbar with a customdraw scrollbar Control +By flyhigh +http://www.codeproject.com/KB/dialog/skinscrollbar.aspx +****************************************************************************************/ + +double fabs_dbl( double dbl ) +{ + if( dbl >= 0 ) + return dbl; + return (-dbl); +} + +// Round a double number up or down. +int round_ud_dbl( double dbl ) +{ + BOOL bNeg = FALSE; + if( dbl < 0 ) + { + bNeg = TRUE; + dbl = -dbl; + } + int n = (int)dbl; + double fract = dbl - (double)n; + if( fract > 0.5 ) + n++; + if( bNeg ) + n = -n; + return n; +} + +/////////////////////////////////////////////////////////////////////////// +// CXeScrollBarBase + +#define XESCROLLBARWND_CLASSNAME _T("XeScrollBarWndClass") // Window class name + +#define XSB_LBTN_DOWN_TIMERID 1001 +#define XSB_LBTN_DOWN_TIME 200 // mS - time to first auto repeat. +#define XSB_LBTN_REPT_TIMERID 1002 +#define XSB_LBTN_REPT_TIME 50 // mS - repeat interval. +#define XSB_FOCUS_TIMERID 1003 +#define XSB_FOCUS_TIME 500 // mS - blink 'gripper' interval. + +// Menu ID's - Note: same ID's as menu from user32.dll. +#define XSB_IDM_SCRHERE 4100 // Scroll Here Scroll Here +#define XSB_IDM_SCR_TL 4102 // Top Left Edge +#define XSB_IDM_SCR_BR 4103 // Bottom Right Edge +#define XSB_IDM_SCR_PG_UL 4098 // Page Up Page Left +#define XSB_IDM_SCR_PG_DR 4099 // Page Down Page Right +#define XSB_IDM_SCR_UL 4096 // Scroll Up Scroll Left +#define XSB_IDM_SCR_DR 4097 // Scroll Down Scroll Right + + +IMPLEMENT_DYNAMIC(CXeScrollBarBase, CScrollBar) + +BEGIN_MESSAGE_MAP(CXeScrollBarBase, CScrollBar) + ON_MESSAGE(SBM_ENABLE_ARROWS, OnSbmEnableArrows) + ON_MESSAGE(SBM_GETPOS, OnSbmGetPos) + ON_MESSAGE(SBM_GETRANGE, OnSbmGetRange) + ON_MESSAGE(SBM_GETSCROLLBARINFO, OnSbmGetScrollBarInfo) + ON_MESSAGE(SBM_GETSCROLLINFO, OnSbmGetScrollInfo) + ON_MESSAGE(SBM_SETPOS, OnSbmSetPos) + ON_MESSAGE(SBM_SETRANGE, OnSbmSetRange) + ON_MESSAGE(SBM_SETRANGEREDRAW, OnSbmSetRangeRedraw) + ON_MESSAGE(SBM_SETSCROLLINFO, OnSbmSetScrollInfo) + ON_WM_PAINT() + ON_WM_ERASEBKGND() + ON_MESSAGE(WM_KEYDOWN, OnKeyDown) + ON_MESSAGE(WM_KEYUP, OnKeyUp) + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_MOUSEMOVE() + ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) + ON_MESSAGE(WM_GETDLGCODE, OnGetDlgCode) + ON_WM_CANCELMODE() + ON_WM_CONTEXTMENU() + ON_COMMAND_RANGE(XSB_IDM_SCR_UL,XSB_IDM_SCR_BR,OnMenuCommands) + ON_WM_TIMER() + ON_WM_SIZE() + ON_WM_SETFOCUS() + ON_WM_KILLFOCUS() + ON_WM_ENABLE() + ON_WM_MOUSEWHEEL() +END_MESSAGE_MAP() + +CXeScrollBarBase::CXeScrollBarBase() +{ + m_pParent = 0; + m_bEnabled = m_bHorizontal = m_bDrawGripper = TRUE; + m_bHasFocus = FALSE; + m_bNoScroll = m_bDragging = m_bTrackMouseLeave = m_bNeedEndScroll = FALSE; + m_nPos = m_nTrackPos = m_nMinPos = m_nMaxPos = m_nMaxReportedPos = 0; + m_uPage = 1; + m_rectClient.SetRectEmpty(); + m_rectThumb.SetRectEmpty(); + m_rectTLArrow.SetRectEmpty(); + m_rectBRArrow.SetRectEmpty(); + m_rectTLChannel.SetRectEmpty(); + m_rectBRChannel.SetRectEmpty(); + m_uArrowWH = 0; + m_uThumbMinHW = 8; // Minimum thumb width or height + m_dblPx_SU = 0; + m_ptMenu.SetPoint(0,0); + m_xyThumbDragOffset = 0; + if (!SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0)) { //added to support multiple rows per mouse notch + scrollLines = 3; + } +} + +CXeScrollBarBase::~CXeScrollBarBase() +{ + // Note - base class dtor (CScrollBar) calls DestroyWindow(). +} + +BOOL CXeScrollBarBase::Create( DWORD dwStyle, const RECT& rect, CWnd *pParentWnd, UINT nID ) +{ + if( !RegisterWindowClass() ) + return FALSE; + + ASSERT(pParentWnd); + ASSERT(IsWindow(pParentWnd->m_hWnd)); + m_pParent = pParentWnd; + + m_bHorizontal = ( dwStyle & SBS_VERT ) ? FALSE : TRUE; + // Note - SBS_HORZ is defined as 0 in winuser.h. + + m_bEnabled = ( dwStyle & WS_DISABLED ) ? FALSE : TRUE; + + BOOL bResult = CWnd::Create( XESCROLLBARWND_CLASSNAME, 0, dwStyle, rect, + pParentWnd, nID ); + + if( bResult ) + { + RecalcRects(); + } + else + { + TRACE(_T("ERROR - failed to create %s\n"),XESCROLLBARWND_CLASSNAME); + ASSERT(FALSE); + } + + return bResult; + + // Note - We DO NOT call base class (CScrollBar) because CScrollBar creates 'normal' + // windows scrollbar. +} + +BOOL CXeScrollBarBase::CreateFromExisting( CWnd *pParentWnd, UINT nID, + BOOL bUseDefaultWH /*= TRUE*/ ) +{ + ASSERT(pParentWnd); + HWND hWndParent = pParentWnd->GetSafeHwnd(); + if( !::IsWindow( hWndParent ) ) + { + ASSERT(FALSE); + return FALSE; + } + HWND hWndExistingSB = ::GetDlgItem( hWndParent, nID ); + if( !hWndExistingSB ) + { + ASSERT(FALSE); + return FALSE; + } + + DWORD dwStyle = ::GetWindowLong( hWndExistingSB, GWL_STYLE ); + + RECT rect; + ::GetWindowRect( hWndExistingSB, &rect ); + ::ScreenToClient( hWndParent, (LPPOINT)&rect ); + ::ScreenToClient( hWndParent, ((LPPOINT)&rect) + 1 ); + if( bUseDefaultWH ) + { // Set width or height to system standard scroll bar width/height. + if( dwStyle & SBS_VERT ) + { + // Get width of 'sys' vert. SB. + int cxSysSbV = ::GetSystemMetrics( SM_CXVSCROLL ); + rect.right = rect.left + cxSysSbV; // Set width of vert. SB to 'normal'. + } + else + { + // Get height of 'sys' horz. SB. + int cySysSbH = ::GetSystemMetrics( SM_CYHSCROLL ); + rect.bottom = rect.top + cySysSbH; // Set height of horz. SB to 'normal'. + } + } + + // Get current range, page and position from existing scrollbar. + SCROLLINFO info; + info.cbSize = sizeof(SCROLLINFO); + info.fMask = SIF_ALL; + ::SendMessage( hWndExistingSB, SBM_GETSCROLLINFO, 0, (LPARAM)&info ); + + // Create new scroll bar of 'this' type. Note - Control ID = 0 until old SB destroyed. + if( !Create( dwStyle, rect, pParentWnd, 0 ) ) + return FALSE; + + // Note - new scroll bar is now the last window in our parent window child Z-order. + + HWND hWndNewSB = GetSafeHwnd(); + ASSERT(hWndNewSB); + + // Set Z-order of new scroll bar - insert after the existing scroll bar. + ::SetWindowPos( hWndNewSB, hWndExistingSB, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); + + // Destroy existing (old) scroll bar. + ::DestroyWindow( hWndExistingSB ); + + // Set Control ID of new scroll bar. + ::SetWindowLong( hWndNewSB, GWL_ID, nID ); + + // Set range, page and position parameters in scroll bar. + SetScrollInfo( &info ); + + return TRUE; +} + +BOOL CXeScrollBarBase::RegisterWindowClass() +{ + WNDCLASS wndcls; + HINSTANCE hInst = AfxGetInstanceHandle(); + + // 'Our' class already registered? + if( !(::GetClassInfo( hInst, XESCROLLBARWND_CLASSNAME, &wndcls )) ) + { // Otherwise we need to register a new class + wndcls.style = CS_HREDRAW | CS_VREDRAW; + // Note - CS_DBLCLKS style not used so don't need to + // process WM_LBUTTONDBLCLK message. + wndcls.lpfnWndProc = ::DefWindowProc; + wndcls.cbClsExtra = wndcls.cbWndExtra = 0; + wndcls.hInstance = hInst; + wndcls.hIcon = NULL; + wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); + wndcls.hbrBackground = NULL; + wndcls.lpszMenuName = NULL; + wndcls.lpszClassName = XESCROLLBARWND_CLASSNAME; + + if( !AfxRegisterClass( &wndcls ) ) + { + TRACE(_T("Register window class %s failed\n"),XESCROLLBARWND_CLASSNAME); + ASSERT(FALSE); + AfxThrowResourceException(); + return FALSE; + } + } + return TRUE; +} + +void CXeScrollBarBase::DrawScrollBar( CDC* pDC ) +{ + // Draw scrollbar as solid color rects - in debug mode ONLY! +#ifdef _DEBUG +#define X_GRBTN RGB(140,140,140) +#define X_GRCH RGB(180,180,180) +#define X_GRTHM RGB(96,96,96) +#define X_NRMBT RGB(128,0,128) +#define X_NRMCH RGB(128,128,0) +#define X_NRMTH RGB(0,192,0) +#define X_HOTBT RGB(192,0,192) +#define X_HOTCH RGB(192,192,0) +#define X_HOTTH RGB(0,255,0) +#define X_DWNBT (~X_NRMBT & 0xFFFFFF) +#define X_DWNCH (~X_NRMCH & 0xFFFFFF) +#define X_DWNTH (~X_NRMTH & 0xFFFFFF) + COLORREF rgbarr[5][6] = { +// eNone eTLbutton eBRbutton eTLchannel eBRchannel eThumb +// 0 1 2 3 4 5 + { 0, 0, 0, 0, 0, 0 }, // 0 eNotDrawn + { 0, X_GRBTN, X_GRBTN, X_GRCH, X_GRCH, X_GRTHM }, // 1 eDisabled + { 0, X_NRMBT, X_NRMBT, X_NRMCH, X_NRMCH, X_NRMTH }, // 2 eNormal + { 0, X_DWNBT, X_DWNBT, X_DWNCH, X_DWNCH, X_DWNTH }, // 3 eDown + { 0, X_HOTBT, X_HOTBT, X_HOTCH, X_HOTCH, X_HOTTH } // 4 eHot + }; + XSB_EDRAWELEM eState; + const CRect *prcElem = 0; + for( int nElem = eTLbutton; nElem <= eThumb; nElem++ ) + { + prcElem = GetUIelementDrawState( (eXSB_AREA)nElem, eState ); + if( !prcElem || eState == eNotDrawn ) + continue; + COLORREF rgb = rgbarr[eState][nElem]; + pDC->FillSolidRect( prcElem, rgb ); + } +#endif +} + +// SBM_GETPOS message handler. +LRESULT CXeScrollBarBase::OnSbmGetPos( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + return m_nPos; +} + +// SBM_SETPOS message handler. +LRESULT CXeScrollBarBase::OnSbmSetPos( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + int nPos = (int)wparam; + BOOL bRedraw = (BOOL)lparam; + int nOldPos = m_nPos; + + m_nPos = nPos; + + if( m_nPos < m_nMinPos ) + m_nPos = m_nMinPos; + else if( m_nPos > m_nMaxReportedPos ) + m_nPos = m_nMaxReportedPos; + + if( m_bNoScroll && !m_bEnabled ) // SB disabled because of SIF_DISABLENOSCROLL? + { // SBM_SETPOS cancels SIF_DISABLENOSCROLL. + m_bNoScroll = FALSE; + EnableWindow( TRUE ); + } + + RecalcRects(); + + if( bRedraw ) + Invalidate(); + + return nOldPos; +} + +// SBM_GETRANGE message handler. +LRESULT CXeScrollBarBase::OnSbmGetRange( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + LPINT lpMinPos = (LPINT)wparam; + LPINT lpMaxPos = (LPINT)lparam; + *lpMinPos = m_nMinPos; + *lpMaxPos = m_nMaxPos; + return 0; +} + +// SBM_SETRANGE message handler. +LRESULT CXeScrollBarBase::OnSbmSetRange( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + int nMinPos = (int)wparam; + int nMaxPos = (int)lparam; + m_nMinPos = nMinPos; + m_nMaxPos = nMaxPos; + if( m_nMaxPos < m_nMinPos ) + m_nMaxPos = m_nMinPos; + int nSUrange = abs(m_nMaxPos - m_nMinPos) + 1; + if( m_uPage > (UINT)nSUrange ) + m_uPage = (UINT)nSUrange; + + if( m_uPage == 0 ) + m_nMaxReportedPos = m_nMaxPos; + else + m_nMaxReportedPos = m_nMaxPos - ((int)m_uPage - 1); + + int nOldPos = m_nPos; + if( m_nPos < m_nMinPos ) + m_nPos = m_nMinPos; + else if( m_nPos > m_nMaxReportedPos ) + m_nPos = m_nMaxReportedPos; + + if( m_bNoScroll && !m_bEnabled ) // SB disabled because of SIF_DISABLENOSCROLL? + { // SBM_SETRANGE cancels SIF_DISABLENOSCROLL. + m_bNoScroll = FALSE; + EnableWindow( TRUE ); + } + + RecalcRects(); + + if( nOldPos != m_nPos ) + return nOldPos; + return 0; +} + +// SBM_SETRANGEREDRAW message handler. +LRESULT CXeScrollBarBase::OnSbmSetRangeRedraw( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + LRESULT lResult = OnSbmSetRange( wparam, lparam ); + Invalidate(); + return lResult; +} + +// SBM_GETSCROLLINFO message handler. +LRESULT CXeScrollBarBase::OnSbmGetScrollInfo( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + LPSCROLLINFO lpScrollInfo = (LPSCROLLINFO)lparam; + if( lpScrollInfo->cbSize != sizeof(SCROLLINFO) ) + return FALSE; + lpScrollInfo->nMin = m_nMinPos; + lpScrollInfo->nMax = m_nMaxPos; + lpScrollInfo->nPage = m_uPage; + lpScrollInfo->nPos = m_nPos; + lpScrollInfo->nTrackPos = m_nTrackPos; + return TRUE; +} + +// SBM_SETSCROLLINFO message handler. +LRESULT CXeScrollBarBase::OnSbmSetScrollInfo( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + BOOL bRedraw = (BOOL)wparam; + LPSCROLLINFO lpScrollInfo = (LPSCROLLINFO)lparam; + if( lpScrollInfo->cbSize != sizeof(SCROLLINFO) ) + return 0; + if( lpScrollInfo->fMask & SIF_PAGE ) + { + m_uPage = lpScrollInfo->nPage; + // Note - windows scrollbars can have a page size = 0. + } + if( lpScrollInfo->fMask & SIF_RANGE ) + { + m_nMinPos = lpScrollInfo->nMin; + m_nMaxPos = lpScrollInfo->nMax; + } + if( lpScrollInfo->fMask & SIF_POS ) + { + m_nPos = lpScrollInfo->nPos; + } + if( lpScrollInfo->fMask & SIF_DISABLENOSCROLL ) + { + BOOL bEnable = ( (int)m_uPage < (m_nMaxPos - m_nMinPos) ) ? TRUE : FALSE; + m_bNoScroll = !bEnable; + EnableWindow( bEnable ); + } + + if( m_nMaxPos < m_nMinPos ) + m_nMaxPos = m_nMinPos; + int nSUrange = abs(m_nMaxPos - m_nMinPos) + 1; + if( m_uPage > (UINT)nSUrange ) + m_uPage = (UINT)nSUrange; + + if( m_uPage == 0 ) + m_nMaxReportedPos = m_nMaxPos; + else + m_nMaxReportedPos = m_nMaxPos - ((int)m_uPage - 1); + + if( m_nPos < m_nMinPos ) + m_nPos = m_nMinPos; + else if( m_nPos > m_nMaxReportedPos ) + m_nPos = m_nMaxReportedPos; + + RecalcRects(); + + if( bRedraw ) + Invalidate(); + + return m_nPos; +} + +// SBM_ENABLE_ARROWS message handler. +LRESULT CXeScrollBarBase::OnSbmEnableArrows( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + /* ImplNote - during testing the windows scrollbar behaved strangely when only one + button was disabled. For that reason only enable/disable both is supported here. */ + EnableWindow( ( wparam & ESB_DISABLE_BOTH ) ? FALSE : TRUE ); + // wParam Specifies whether the scroll bar arrows are enabled or disabled and + // indicates which arrows are enabled or disabled. + return TRUE; +} + +// SBM_GETSCROLLBARINFO message handler. +LRESULT CXeScrollBarBase::OnSbmGetScrollBarInfo( WPARAM wparam, LPARAM lparam ) +{ + ASSERT(::IsWindow(m_hWnd)); + SCROLLBARINFO *psbi = (SCROLLBARINFO *)lparam; + if( !psbi || psbi->cbSize != sizeof(SCROLLBARINFO) ) + return FALSE; + + /* Note - information on how to implement this is a little sparse from MS. + Need make a few educated guesses. + Note - testing (comparing 'this' to WIN SBs) has shown that: + rcScrollBar is in screen coords. + dxyLineButton is arrow button width when horz. SB. + dxyLineButton is arrow button height when vert. SB. + */ + + psbi->rcScrollBar = m_rectClient; // Coordinates of the scroll bar. + ClientToScreen( &psbi->rcScrollBar ); // In screen coords. + + if( m_bHorizontal ) + { + psbi->dxyLineButton = m_rectTLArrow.Width();// arrow button width. + psbi->xyThumbTop = m_rectThumb.left; // Position of the left of the thumb. + psbi->xyThumbBottom = m_rectThumb.right; // Position of the right of the thumb. + } + else + { + psbi->dxyLineButton = m_rectTLArrow.Height();// arrow button height. + psbi->xyThumbTop = m_rectThumb.top; // Position of the top of the thumb. + psbi->xyThumbBottom = m_rectThumb.bottom; // Position of the bottom of the thumb. + } + + // psbi->rgstate - An array of DWORD elements. Each element indicates the state of a + // scroll bar component. The following values show the scroll bar component that + // corresponds to each array index. Index Scroll bar component + // 0 The scroll bar itself. + // 1 The top or right arrow button. + // 2 The page up or page right region. + // 3 The scroll box (thumb). + // 4 The page down or page left region. + // 5 The bottom or left arrow button. + DWORD dwState = ( m_bEnabled ) ? 0 : STATE_SYSTEM_UNAVAILABLE; + DWORD dwTLchSt = dwState, dwBRchSt = dwState, dwThumbSt = dwState; + DWORD dwTLbtnSt = dwState, dwBRbtnSt = dwState; + if( m_rectTLChannel.IsRectEmpty() ) + dwTLchSt |= STATE_SYSTEM_INVISIBLE; + if( m_rectBRChannel.IsRectEmpty() ) + dwBRchSt |= STATE_SYSTEM_INVISIBLE; + if( m_rectThumb.IsRectEmpty() ) + dwThumbSt |= STATE_SYSTEM_INVISIBLE; + if( m_eMouseDownArea.IsTLButton() ) + dwTLbtnSt |= STATE_SYSTEM_PRESSED; + if( m_eMouseDownArea.IsTLChannel() ) + dwTLchSt |= STATE_SYSTEM_PRESSED; + if( m_eMouseDownArea.IsThumb() ) + dwThumbSt |= STATE_SYSTEM_PRESSED; + if( m_eMouseDownArea.IsBRChannel() ) + dwBRchSt |= STATE_SYSTEM_PRESSED; + if( m_eMouseDownArea.IsBRButton() ) + dwBRbtnSt |= STATE_SYSTEM_PRESSED; + psbi->rgstate[0] = dwState; + psbi->rgstate[1] = dwTLbtnSt; + psbi->rgstate[2] = dwTLchSt; + psbi->rgstate[3] = dwThumbSt; + psbi->rgstate[4] = dwBRchSt; + psbi->rgstate[5] = dwBRbtnSt; + + // The DWORD element for each scroll bar component can include a combination of the + // following bit flags. + // STATE_SYSTEM_INVISIBLE - For the scroll bar itself, indicates the specified + // vertical or horizontal scroll bar does not exist. For the page up or page + // down regions, indicates the thumb is positioned such that the region does + // not exist. + // STATE_SYSTEM_OFFSCREEN - For the scroll bar itself, indicates the window is sized + // such that the specified vertical or horizontal scroll bar is not currently + // displayed. (SK note - applies to NC scroll bars only). + // STATE_SYSTEM_PRESSED - The arrow button or page region is pressed. + // STATE_SYSTEM_UNAVAILABLE - The component is disabled. + + return TRUE; +} + +void CXeScrollBarBase::OnPaint() +{ // WM_PAINT message handler. + ASSERT(::IsWindow(m_hWnd)); + CPaintDC dc(this); // device context for painting + + DrawScrollBar( &dc ); + // Do not call CScrollBar::OnPaint() for painting messages +} + +BOOL CXeScrollBarBase::OnEraseBkgnd( CDC* pDC ) +{ // WM_ERASEBKGND message handler. + return TRUE; // All painting done in OnPaint. +} + +LRESULT CXeScrollBarBase::OnKeyDown( WPARAM wParam, LPARAM lParam ) +{ // WM_KEYDOWN message handler. + ASSERT(::IsWindow(m_hWnd)); + WORD wSBcode = 0xFFFF; + // Note - SB_PAGELEFT == SB_PAGEUP etc. see winuser.h + switch( wParam ) + { + case VK_PRIOR: + wSBcode = SB_PAGELEFT; + break; + + case VK_NEXT: + wSBcode = SB_PAGERIGHT; + break; + + case VK_HOME: + wSBcode = SB_LEFT; + break; + + case VK_END: + wSBcode = SB_RIGHT; + break; + + case VK_LEFT: + wSBcode = SB_LINELEFT; + break; + + case VK_RIGHT: + wSBcode = SB_LINERIGHT; + break; + + case VK_UP: + wSBcode = SB_LINEUP; + break; + + case VK_DOWN: + wSBcode = SB_LINEDOWN; + break; + } + + if( wSBcode != 0xFFFF ) + { + SendScrollMsg( wSBcode ); + m_bNeedEndScroll = TRUE; // Send SB_ENDSCROLL on WM_KEYUP. + } + + return 0; // Indicate we processed this message (eat all key msgs). + // Note - testing shows that windows looks for another child control to process + // keyboard input if we don't return 0 here (and we lose focus). +} + +LRESULT CXeScrollBarBase::OnKeyUp( WPARAM wParam, LPARAM lParam ) +{ // WM_KEYUP message handler. + if( m_bNeedEndScroll ) + { + SendScrollMsg( SB_ENDSCROLL ); + m_bNeedEndScroll = FALSE; + } + return 0; // Indicate we processed this message (eat all key msgs). +} + +void CXeScrollBarBase::OnLButtonDown( UINT nFlags, CPoint point ) +{ // WM_LBUTTONDOWN message handler. + ASSERT(::IsWindow(m_hWnd)); + SetCapture(); + BOOL bHasTabStop = ( ::GetWindowLong( m_hWnd, GWL_STYLE ) & WS_TABSTOP ) ? TRUE : FALSE; + if( bHasTabStop ) + SetFocus(); // Only 'steal' focus if 'this' has Tab stop. + + m_eMouseDownArea = GetAreaFromPoint( point ); + + WORD wSBcode = 0xFFFF; + // Note - SB_PAGELEFT == SB_PAGEUP etc. see winuser.h + if( m_eMouseDownArea.eArea == eTLbutton ) + wSBcode = SB_LINELEFT; + else if( m_eMouseDownArea.eArea == eTLchannel ) + wSBcode = SB_PAGELEFT; + else if( m_eMouseDownArea.eArea == eBRchannel ) + wSBcode = SB_PAGERIGHT; + else if( m_eMouseDownArea.eArea == eBRbutton ) + wSBcode = SB_LINERIGHT; + + if( wSBcode != 0xFFFF ) + { + SendScrollMsg( wSBcode ); + m_bNeedEndScroll = TRUE; // Send SB_ENDSCROLL on WM_LBUTTONUP message. + } + + if( m_eMouseDownArea.IsThumb() ) // Store X or Y offset from thumb edge. + m_xyThumbDragOffset = ( m_bHorizontal ) ? point.x - m_rectThumb.left + : point.y - m_rectThumb.top; + + // Set timer for first auto repeat - when button or channel clicked. + if( m_eMouseDownArea.IsButton() || m_eMouseDownArea.IsChannel() ) + SetTimer( XSB_LBTN_DOWN_TIMERID, XSB_LBTN_DOWN_TIME, 0 ); + + CScrollBar::OnLButtonDown(nFlags, point); +} + +void CXeScrollBarBase::OnLButtonUp( UINT nFlags, CPoint point ) +{ // WM_LBUTTONUP message handler. + ASSERT(::IsWindow(m_hWnd)); + ReleaseCapture(); + KillTimer( XSB_LBTN_DOWN_TIMERID ); + KillTimer( XSB_LBTN_REPT_TIMERID ); + + m_eMouseDownArea = eNone; + + if( m_bDragging ) // Did we send any SB_THUMBTRACK messages? + { + SendScrollMsg( SB_THUMBPOSITION, (WORD)m_nTrackPos ); + m_bDragging = FALSE; + RecalcRects(); // Reset thumb pos. to current scroll pos. + } + + if( m_bNeedEndScroll ) + { + SendScrollMsg( SB_ENDSCROLL ); // Let parent know scrolling has ended. + m_bNeedEndScroll = FALSE; + } + + Invalidate(); + + CScrollBar::OnLButtonUp(nFlags, point); +} + +/* updated to newer api and reversing return value to avoid mousewheel propagating */ +/* remove restriction on vert scrollbar, as both are valid in win32 */ +BOOL CXeScrollBarBase::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { + ASSERT(::IsWindow(m_hWnd)); + //short xPos = pt.x; + //short yPos = pt.y; + + //if (!m_bHorizontal) // Mouse wheel messages only apply to vertical scrollbar. + //{ + WORD wSBcode = 0xFFFF; + if (zDelta >= WHEEL_DELTA) { + wSBcode = SB_LINEUP; + } else if (zDelta <= -WHEEL_DELTA) { + wSBcode = SB_LINEDOWN; + zDelta = -zDelta; + } + if (wSBcode != 0xFFFF) { + do { + for (UINT i=0; i= WHEEL_DELTA); + SendScrollMsg(SB_ENDSCROLL); + } + return 1; // Message was processed. (was 0, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 1 if scrolling enabled + //} + //return 0; // Message not processed. (was 1, but per https://msdn.microsoft.com/en-us/data/eff58fe7(v=vs.85) should be 0 if scrolling not enabled +} + + +void CXeScrollBarBase::OnMouseMove( UINT nFlags, CPoint point ) +{ // WM_MOUSEMOVE message handler. + ASSERT(::IsWindow(m_hWnd)); + if( !m_bTrackMouseLeave ) + { // We want a WM_MOUSELEAVE message when mouse leaves our client area. + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(tme); + tme.hwndTrack = m_hWnd; + tme.dwFlags = TME_LEAVE; + tme.dwHoverTime = 0; + + // Note - _TrackMouseEvent is from comctl32.dll - emulates TrackMouseEvent + // if it does not exist. + m_bTrackMouseLeave = _TrackMouseEvent( &tme ); + } + + stXSB_AREA eOldMouseArea = m_eMouseOverArea; + + m_eMouseOverArea = GetAreaFromPoint( point ); // Update mouse over area. + + if( m_eMouseDownArea.IsThumb() && m_dblPx_SU > 0 ) + { // User is dragging the thumb. + BOOL bStartDrag = FALSE; + if( !m_bDragging ) + { + bStartDrag = TRUE; // Start of thumb dragging. + m_bDragging = TRUE; + } + int nTrackPos; + double dblScrollPos; + if( m_bHorizontal ) + { // X pos of left edge of thumb (0...?) + int xPos = point.x - m_xyThumbDragOffset - m_rectTLArrow.right; + dblScrollPos = (double)xPos / m_dblPx_SU; + nTrackPos = round_ud_dbl( dblScrollPos ) + m_nMinPos; + } + else + { // Y pos of top edge of thumb (0...?) + int yPos = point.y - m_xyThumbDragOffset - m_rectTLArrow.bottom; + dblScrollPos = (double)yPos / m_dblPx_SU; + nTrackPos = round_ud_dbl( dblScrollPos ) + m_nMinPos; + } + if( nTrackPos < m_nMinPos ) + nTrackPos = m_nMinPos; + else if( nTrackPos > m_nMaxReportedPos ) + nTrackPos = m_nMaxReportedPos; + + //adipose: moved this block to before sending scroll message. otherwise scrollbar updates poorly on slower windows (listctrl) + //also call updatewindow to redraw immediately + // Recalculate thumb XY pos. and redraw if pos. changed. + if (RecalcRectsThumbTrack(point)) { + Invalidate(); + UpdateWindow(); + } + + if( bStartDrag || m_nTrackPos != nTrackPos ) + { // Send scroll message when user starts dragging + // OR when track pos has changed. + m_nTrackPos = nTrackPos; + SendScrollMsg( SB_THUMBTRACK, (WORD)m_nTrackPos ); + m_bNeedEndScroll = TRUE; + } + } + + if( m_eMouseOverArea != eOldMouseArea ) + Invalidate(); + + CScrollBar::OnMouseMove(nFlags, point); +} + +LRESULT CXeScrollBarBase::OnMouseLeave( WPARAM wparam, LPARAM lparam ) +{ // WM_MOUSELEAVE message handler. + ASSERT(::IsWindow(m_hWnd)); + m_bTrackMouseLeave = FALSE; + m_eMouseOverArea = eNone; + Invalidate(); + return 0; +} + +LRESULT CXeScrollBarBase::OnGetDlgCode( WPARAM wParam, LPARAM lParam ) +{ // WM_GETDLGCODE message handler. + ASSERT(::IsWindow(m_hWnd)); + BOOL bHasTabStop = ( ::GetWindowLong( m_hWnd, GWL_STYLE ) & WS_TABSTOP ) ? TRUE : FALSE; + + LRESULT lResult = Default(); + if( lParam ) // lParam points to an MSG structure? + { + LPMSG lpmsg = (LPMSG)lParam; + if( (lpmsg->message == WM_KEYDOWN // Keyboard input? + || lpmsg->message == WM_KEYUP) + && lpmsg->wParam != VK_TAB ) // AND NOT TAB key? + { + if( bHasTabStop ) // 'this' window has Tab stop? + { + lResult |= DLGC_WANTMESSAGE; // We want keyboard input (except TAB). + // Note - windows will set focus to 'this' (and send WM_SETFOCUS) + // if we return DLGC_WANTMESSAGE here. + } + else + { // 'this' windows does NOT have TAB stop. + // Note - windows standard scroll bar implements a special behaviour + // for scroll bars when no tab stop for the UP, DOWN, LEFT, RIGHT keys. + if( m_bHorizontal ) + { + if( lpmsg->wParam == VK_LEFT || lpmsg->wParam == VK_RIGHT ) + lResult |= DLGC_WANTMESSAGE; + } + else + { + if( lpmsg->wParam == VK_UP || lpmsg->wParam == VK_DOWN ) + lResult |= DLGC_WANTMESSAGE; + } + } + } + } + else + { + if( bHasTabStop ) + lResult |= DLGC_WANTTAB; // 'this' has WS_TABSTOP style - we want focus. + else + lResult |= DLGC_STATIC; // no tab stop - we don't want focus. + } + return lResult; +} + +void CXeScrollBarBase::OnCancelMode() +{ // WM_CANCELMODE message handler. + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnCancelMode(); + + // Need to handle WM_CANCELMODE message. + // See -> http://support.microsoft.com/kb/74548/en-us + + if( !m_eMouseDownArea.IsNone() ) // Mouse L button down? + OnLButtonUp( 0, CPoint(0,0) ); // Do L btn up processing now. +} + +void CXeScrollBarBase::OnContextMenu( CWnd* pWnd, CPoint point ) +{ // WM_CONTEXTMENU message handler. + ASSERT(::IsWindow(m_hWnd)); + + m_ptMenu = point; + ScreenToClient( &m_ptMenu ); + + // Try to load scroll bar menu from user32.dll - to get menu in 'local' language. + CString strDllPathName; + GetWindowsDirectory( strDllPathName.GetBuffer(MAX_PATH), MAX_PATH ); + strDllPathName.ReleaseBuffer(); + strDllPathName += _T("\\system32\\user32.dll"); + + HMODULE hUser32dllModule = ::LoadLibrary( strDllPathName ); + if( hUser32dllModule ) + { // Get menu #64 (horz.) or menu #80 (vert.) from user32.dll. + HMENU hMenu = 0, hSubMenu = 0; + if( m_bHorizontal ) + hMenu = ::LoadMenu( hUser32dllModule, MAKEINTRESOURCE(64) ); + else + hMenu = ::LoadMenu( hUser32dllModule, MAKEINTRESOURCE(80) ); + if( hMenu ) + { + hSubMenu = ::GetSubMenu( hMenu, 0 ); + if( hSubMenu ) + { + ::TrackPopupMenu( hSubMenu, TPM_LEFTALIGN, point.x, point.y, 0, + GetSafeHwnd(), 0 ); + // Note - TrackPopupMenu does not return until menu has been dismissed. + ::DestroyMenu( hMenu ); + } + } + ::FreeLibrary( hUser32dllModule ); + if( hSubMenu ) + return; // Using menu from user32.dll was successful. + } + + // If using menu from user32.dll was unsuccessful - create menu (in english). + CMenu menu; + menu.CreatePopupMenu(); + menu.AppendMenu( MF_STRING, XSB_IDM_SCRHERE, _T("Scroll Here") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + if( m_bHorizontal ) + { + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_TL, _T("Left Edge") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_BR, _T("Right Edge") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_UL, _T("Page Left") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_DR, _T("Page Right") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_UL, _T("Scroll Left") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_DR, _T("Scroll Right") ); + } + else + { + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_TL, _T("Top") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_BR, _T("Bottom") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_UL, _T("Page Up") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_PG_DR, _T("Page Down") ); + menu.AppendMenu( MF_SEPARATOR, 0, _T("") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_UL, _T("Scroll Up") ); + menu.AppendMenu( MF_STRING, XSB_IDM_SCR_DR, _T("Scroll Down") ); + } + menu.TrackPopupMenu( TPM_LEFTALIGN, point.x, point.y, pWnd ); + // Note - TrackPopupMenu does not return until menu has been dismissed. + menu.DestroyMenu(); +} + +void CXeScrollBarBase::OnMenuCommands( UINT uID ) +{ + ASSERT(::IsWindow(m_hWnd)); + int xyOfs, nScrollHerePos; + double dblScrollPos; + WORD wSBcode = 0xFFFF; + switch( uID ) + { + case XSB_IDM_SCRHERE: + // Calculate pos (in scroll units) + if( m_bHorizontal ) + xyOfs = m_ptMenu.x - m_rectTLArrow.right; + else + xyOfs = m_ptMenu.y - m_rectTLArrow.bottom; + if( xyOfs < 0 ) + xyOfs = 0; + if( m_rectThumb.IsRectEmpty() || !(m_dblPx_SU > 0) ) + break; // Can't 'Scroll Here'. + dblScrollPos = (double)xyOfs / m_dblPx_SU; + nScrollHerePos = m_nMinPos + round_ud_dbl( dblScrollPos ); + if( nScrollHerePos < m_nMinPos ) + nScrollHerePos = m_nMinPos; + else if( nScrollHerePos > m_nMaxReportedPos ) + nScrollHerePos = m_nMaxReportedPos; + m_nTrackPos = nScrollHerePos; + SendScrollMsg( SB_THUMBPOSITION, (WORD)m_nTrackPos ); + SendScrollMsg( SB_ENDSCROLL ); + break; + case XSB_IDM_SCR_TL: + wSBcode = SB_TOP; + break; + case XSB_IDM_SCR_BR: + wSBcode = SB_BOTTOM; + break; + case XSB_IDM_SCR_PG_UL: + wSBcode = SB_PAGEUP; + break; + case XSB_IDM_SCR_PG_DR: + wSBcode = SB_PAGEDOWN; + break; + case XSB_IDM_SCR_UL: + wSBcode = SB_LINEUP; + break; + case XSB_IDM_SCR_DR: + wSBcode = SB_LINEDOWN; + break; + } + if( wSBcode != 0xFFFF ) + { + SendScrollMsg( wSBcode ); + SendScrollMsg( SB_ENDSCROLL ); + } +} + +void CXeScrollBarBase::OnTimer( UINT_PTR nIDEvent ) +{ // WM_TIMER message handler. + ASSERT(::IsWindow(m_hWnd)); + if( nIDEvent == XSB_LBTN_DOWN_TIMERID ) + { // First auto repeat timer event. + KillTimer( XSB_LBTN_DOWN_TIMERID ); + SetTimer( XSB_LBTN_REPT_TIMERID, XSB_LBTN_REPT_TIME, 0 ); + } + if( nIDEvent == XSB_LBTN_DOWN_TIMERID || nIDEvent == XSB_LBTN_REPT_TIMERID ) + { // Auto repeat + CPoint ptCurMouse; + if( ::GetCursorPos( &ptCurMouse ) ) + { + ::ScreenToClient( GetSafeHwnd(), &ptCurMouse ); + m_eMouseOverArea = GetAreaFromPoint( ptCurMouse ); // Update mouse over area. + } + if( m_eMouseDownArea.IsTLButton() ) + { + if( m_eMouseOverArea.IsTLButton() ) // Mouse still over button? + SendScrollMsg( SB_LINELEFT ); + } + else if( m_eMouseDownArea.IsBRButton() ) + { + if( m_eMouseOverArea.IsBRButton() ) // Mouse still over button? + SendScrollMsg( SB_LINERIGHT ); + } + else if( m_eMouseDownArea.IsTLChannel() ) + { + if( m_eMouseOverArea.IsTLChannel() ) // Mouse still over channel? + SendScrollMsg( SB_PAGELEFT ); + } + else if( m_eMouseDownArea.IsBRChannel() ) + { + if( m_eMouseOverArea.IsBRChannel() ) // Mouse still over channel? + SendScrollMsg( SB_PAGERIGHT ); + } + // Note - SB_LINELEFT == SB_LINEUP etc. see winuser.h + } + if( nIDEvent == XSB_FOCUS_TIMERID ) + { // Blinking focus timer. + if( m_bNeedEndScroll ) + { // Draw normal thumb box while user is scrolling. + if( !m_bDrawGripper ) + { // Redraw scroll bar if currently drawn without 'gripper'. + m_bDrawGripper = TRUE; + Invalidate(); // Draw 'blinking' focus. + } + } + else + { // Draw blinking 'gripper' to indicate 'focus'. + m_bDrawGripper = !m_bDrawGripper; + Invalidate(); // Draw 'blinking' focus. + } + } + + CScrollBar::OnTimer( nIDEvent ); +} + +void CXeScrollBarBase::OnSize( UINT nType, int cx, int cy ) +{ // WM_SIZE message handler. + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnSize( nType, cx, cy ); + + if( m_hWnd ) + RecalcRects(); +} + +void CXeScrollBarBase::OnSetFocus( CWnd* pOldWnd ) +{ // WM_SETFOCUS message handler. + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnSetFocus( pOldWnd ); + m_bHasFocus = TRUE; + m_bDrawGripper = FALSE; + SetTimer( XSB_FOCUS_TIMERID, XSB_FOCUS_TIME, 0 ); + Invalidate(); +} + +void CXeScrollBarBase::OnKillFocus( CWnd* pNewWnd ) +{ // WM_KILLFOCUS message handler. + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnKillFocus( pNewWnd ); + m_bHasFocus = FALSE; + m_bDrawGripper = TRUE; + KillTimer( XSB_FOCUS_TIMERID ); + Invalidate(); +} + +void CXeScrollBarBase::OnEnable( BOOL bEnable ) +{ // WM_ENABLE message handler + ASSERT(::IsWindow(m_hWnd)); + CScrollBar::OnEnable(bEnable); + + m_bEnabled = bEnable; + + RecalcRects(); // Need to recalc. because no thumb is shown when disabled. + + Invalidate(); +} + +void CXeScrollBarBase::SendScrollMsg( WORD wSBcode, WORD wHiWPARAM /*= 0*/ ) +{ + ASSERT(::IsWindow(m_hWnd)); + if( m_pParent && ::IsWindow( m_pParent->m_hWnd ) ) + { + m_pParent->SendMessage( ( m_bHorizontal ) ? WM_HSCROLL : WM_VSCROLL, + MAKELONG(wSBcode,wHiWPARAM), (LPARAM)m_hWnd ); + } +} + +eXSB_AREA CXeScrollBarBase::GetAreaFromPoint( CPoint point ) +{ + ASSERT(::IsWindow(m_hWnd)); + if( !m_rectClient.PtInRect( point ) ) + return eNone; + if( m_rectThumb.PtInRect( point ) ) + return eThumb; + if( m_rectTLArrow.PtInRect( point ) ) + return eTLbutton; + if( m_rectBRArrow.PtInRect( point ) ) + return eBRbutton; + if( m_rectTLChannel.PtInRect( point ) ) + return eTLchannel; + if( m_rectBRChannel.PtInRect( point ) ) + return eBRchannel; + return eNone; +} + +const CRect *CXeScrollBarBase::GetUIelementDrawState( eXSB_AREA eElem, + XSB_EDRAWELEM &eState ) +{ + ASSERT(::IsWindow(m_hWnd)); + CRect *prcElem = 0; + eState = eNotDrawn; + switch( eElem ) + { + case eTLbutton: + prcElem = &m_rectTLArrow; + break; + case eBRbutton: + prcElem = &m_rectBRArrow; + break; + case eTLchannel: + prcElem = &m_rectTLChannel; + break; + case eBRchannel: + prcElem = &m_rectBRChannel; + break; + case eThumb: + prcElem = &m_rectThumb; + break; + } + if( !prcElem || prcElem->IsRectEmpty() ) + eState = eNotDrawn; + if( !m_bEnabled ) + eState = eDisabled; + else if( m_eMouseDownArea.eArea == eElem ) + eState = eDown; + else if( m_eMouseOverArea.eArea == eElem && !m_bDragging) + eState = eHot; + else + eState = eNormal; + return prcElem; +} + +BOOL CXeScrollBarBase::CalcThumb( int cxyChannel, int &xyThumb, int &cxyThumb ) +{ + // Range in 'scroll units' (SU) - Note +1 because min/max are 'inclusive' values. + int nSU_Range = abs(m_nMaxPos - m_nMinPos) + 1; + if( nSU_Range == 0 // No thumb when scroll range is 0 + || cxyChannel <= (int)m_uThumbMinHW // No space for thumb. + || !m_bEnabled ) // No thumb when disabled. + return FALSE; + + // We have space for thumb. + + // thumb size = scroll bar size * page size / scroll bar range + // (pixels) (pixels) (scroll units) (scroll units) + + // When page size is 0 thumb size is set to minimum size. + + m_dblPx_SU = (double)cxyChannel / (double)nSU_Range; // Pixels per scroll unit. + + double dblXY = (double)(m_nPos - m_nMinPos) * m_dblPx_SU; + xyThumb = (int)dblXY; + if( fabs_dbl( dblXY - (double)xyThumb ) > 0.5 ) + xyThumb++; + + double dblCXY = (double)m_uPage * m_dblPx_SU; + cxyThumb = (int)dblCXY; + if( fabs_dbl( dblCXY - (double)cxyThumb ) > 0.5 ) + cxyThumb++; + + //if( m_uPage == 0 ) + // cxyThumb = GetCXYarrow(); // Thumb is same as arrow button when page = 0. + // Note - WIN SBs show thumb box same size as arrow button when PAGE = 0. + + if( cxyThumb < (int)m_uThumbMinHW ) + { + int nErrCXY = (int)m_uThumbMinHW - cxyThumb; + cxyThumb = (int)m_uThumbMinHW; + + // Calculate new thumb X or Y position when 'error' in position. + double dblErr_Px = (double)nErrCXY / (double)cxyChannel; + double dblXYoffs = dblErr_Px * xyThumb; + int xyOffs = (int)dblXYoffs; + if( fabs_dbl( dblXYoffs - (double)xyOffs ) > 0.5 ) + xyOffs++; + xyThumb -= xyOffs; + } + + // Sometimes it's needed to adjust the size and or position because scroll bar + // parameters are in error. + + // Calculate last possible X or Y for thumb. + int xyLastPossible = cxyChannel - cxyThumb; + if( xyThumb > xyLastPossible ) + xyThumb = xyLastPossible; + + if( xyThumb < 0 ) + xyThumb = 0; + + if( (xyThumb + cxyThumb) > cxyChannel ) + cxyThumb = cxyChannel - xyThumb; + + return TRUE; +} + +void CXeScrollBarBase::RecalcRects() +{ + if( !GetSafeHwnd() ) + return; + + GetClientRect( &m_rectClient ); // Update client rect. + + BOOL bHasThumb = FALSE; + m_rectThumb.SetRectEmpty(); + + if( m_bHorizontal ) + { // Calc. arrows + int cxClient = m_rectClient.Width(); + int cxArrow = GetCXYarrow(); // Arrow button width. + + if( cxClient < (2 * cxArrow) ) + cxArrow = cxClient / 2; // Limit arrow width to available area. + + m_rectTLArrow.SetRect( m_rectClient.left, m_rectClient.top, + m_rectClient.left + cxArrow, m_rectClient.bottom); + + m_rectBRArrow.SetRect( m_rectClient.right - cxArrow, m_rectClient.top, + m_rectClient.right, m_rectClient.bottom ); + + // Calc. thumb size and position + int xThumb, cxThumb, cxChannel = cxClient - (2 * cxArrow); + bHasThumb = CalcThumb( cxChannel, xThumb, cxThumb ); + if( bHasThumb ) + { // We have space for thumb. + xThumb += m_rectTLArrow.right; + m_rectThumb = m_rectTLArrow; + m_rectThumb.left = xThumb; + m_rectThumb.right = xThumb + cxThumb; + } + + // Calc. channels + m_rectTLChannel = m_rectTLArrow; + m_rectBRChannel = m_rectBRArrow; + m_rectTLChannel.left = m_rectTLArrow.right; + if( bHasThumb ) + { + m_rectTLChannel.right = m_rectThumb.left; + m_rectBRChannel.left = m_rectThumb.right; + m_rectBRChannel.right = m_rectBRArrow.left; + } + else + { + m_rectTLChannel.right = m_rectBRArrow.left; // L channel reaches to R arrow. + m_rectBRChannel.SetRectEmpty(); // No thumb - so R channel not needed. + } + } + else // Vertical scroll bar. + { // Calc. arrows + int cyClient = m_rectClient.Height(); + int cyArrow = GetCXYarrow(); // Arrow button height. + + if( cyClient < (2 * cyArrow) ) + cyArrow = cyClient / 2; // Limit arrow height to available area. + + m_rectTLArrow.SetRect( m_rectClient.left, m_rectClient.top, + m_rectClient.right, m_rectClient.top + cyArrow ); + + m_rectBRArrow.SetRect( m_rectClient.left, m_rectClient.bottom - cyArrow, + m_rectClient.right, m_rectClient.bottom ); + + // Calc. thumb size and position + int yThumb, cyThumb, cyChannel = cyClient - (2 * cyArrow); + bHasThumb = CalcThumb( cyChannel, yThumb, cyThumb ); + if( bHasThumb ) + { // We have space for thumb. + yThumb +=m_rectTLArrow.bottom ; + m_rectThumb = m_rectTLArrow; + m_rectThumb.top = yThumb; + m_rectThumb.bottom = yThumb + cyThumb; + } + + // Calc. channels + m_rectTLChannel = m_rectTLArrow; + m_rectBRChannel = m_rectBRArrow; + m_rectTLChannel.top = m_rectTLArrow.bottom; + if( bHasThumb ) + { + m_rectTLChannel.bottom = m_rectThumb.top; + m_rectBRChannel.top = m_rectThumb.bottom; + m_rectBRChannel.bottom = m_rectBRArrow.top; + } + else + { + m_rectTLChannel.bottom = m_rectBRArrow.top; // T channel reaches to B arrow. + m_rectBRChannel.SetRectEmpty(); // No thumb - so T channel not needed. + } + } +} + +BOOL CXeScrollBarBase::RecalcRectsThumbTrack( CPoint point ) +{ + ASSERT(m_bDragging && !m_rectThumb.IsRectEmpty()); // Sanity check. + if( m_bHorizontal ) + { // Horizontal scroll bar. + // X pos of left edge of thumb (0...?) + int xPos = point.x - m_xyThumbDragOffset; + if( xPos < m_rectTLArrow.right ) + xPos = m_rectTLArrow.right; + int nThumbWidth = m_rectThumb.Width(); + if( xPos > (m_rectBRArrow.left - nThumbWidth) ) + xPos = (m_rectBRArrow.left - nThumbWidth); + if( xPos == m_rectThumb.left ) + return FALSE; // No change. + m_rectThumb.left = xPos; + m_rectThumb.right = m_rectThumb.left + nThumbWidth; + m_rectTLChannel.right = m_rectThumb.left; + m_rectBRChannel.left = m_rectThumb.right; + } + else + { // Vertical scroll bar. + // Y pos of top edge of thumb (0...?) + int yPos = point.y - m_xyThumbDragOffset; + if( yPos < m_rectTLArrow.bottom ) + yPos = m_rectTLArrow.bottom; + int nThumbHeight = m_rectThumb.Height(); + if( yPos > (m_rectBRArrow.top - nThumbHeight) ) + yPos = (m_rectBRArrow.top - nThumbHeight); + if( yPos == m_rectThumb.top ) + return FALSE; // No change. + m_rectThumb.top = yPos; + m_rectThumb.bottom = m_rectThumb.top + nThumbHeight; + m_rectTLChannel.bottom = m_rectThumb.top; + m_rectBRChannel.top = m_rectThumb.bottom; + } + return TRUE; +} + +UINT CXeScrollBarBase::GetCXYarrow() +{ + if( m_uArrowWH ) // Has derived class set this value? + return m_uArrowWH; // Use arrow button width/height set by derived class. + + // If m_uArrowWH == 0 we must assume the arrow button is same width or height as + // the scrollbar window. + if( m_bHorizontal ) + return m_rectClient.Height(); // Horz. arrow button is same height as window. + return m_rectClient.Width(); // Vert. arrow button is same width as window. } \ No newline at end of file diff --git a/src/thirdparty/XeScrollBar/xescrollbarbase.h b/src/thirdparty/XeScrollBar/xescrollbarbase.h index e75de1259ad..0d0dfa4e7ac 100755 --- a/src/thirdparty/XeScrollBar/xescrollbarbase.h +++ b/src/thirdparty/XeScrollBar/xescrollbarbase.h @@ -1,399 +1,399 @@ -#pragma once - -/**************************************************************************************** -CXeScrollBarBase class. -This class implements a very close copy of the standard windows scroll bar. -This class is designed as a base class for another class that will do all painting. -This class handles all the business logic. -No painting is done in this class - except in debug mode. - -The derived class needs to do the following: -* MUST override DrawScrollBar member function to do all the painting. - Example: - Create memory DC - same size as client area. - XSB_EDRAWELEM eState; - const CRect *prcElem = 0; - stXSB_AREA stArea; - for( int nElem = eTLbutton; nElem <= eThumb; nElem++ ) // loop through all UI elements. - { - stArea.eArea = (eXSB_AREA)nElem; - - // Get bounding rect of UI element to draw (client coords.) - prcElem = GetUIelementDrawState( stArea.eArea, eState ); - if( !prcElem || eState == eNotDrawn ) // Rect empty or area not drawn? - continue; - - // stArea.eArea identifies UI element to draw: - // eTLbutton or eTLchannel or eThumb or eBRchannel or eBRbutton. - - // eState identifes in what state the UI element is drawn: - // eDisabled or eNormal or eDown or eHot. - - // m_bHorizontal is TRUE if 'this' is a horizontal scroll bar. - - // Draw UI element to memory DC. (using prcElem rect). - // Note - use m_bDrawGripper to determine if 'gripper' is drawn on thumb box. - // This is used to implement 'blinking' to show scroll bar has input - // focus. (every 500mS). - } - Copy memory DC to pDC. - -* (optional) Set m_uArrowWH to the width of the arrow button in horizontal scrollbar, - note - height of arrow button in vertical scrollbar is the same. - If this member is left unchanged (= 0) the arrow button width in horizontal scrollbar - is assumed to be equal to the height of the window. Same for vertical scroll bar - except the width of the window is arrow button height. - This number is needed to calculate sizes of other UI elements of the scroll bar. - -* (optional) Set m_uThumbMinHW to the minimum allowed width of the thumb box in a - horizontal scroll bar, this value is also the minimum height of the thumb box in a - vertical scroll bar. The default is 8 pixels. -****************************************************************************************/ - -// Enum - UI element state - helps with drawing scrollbar. -typedef enum tagXSB_EDRAWELEM -{ - eNotDrawn = 0, // UI element is not visible. (UI Rect empty). - eDisabled, // Element should be drawn in disabled state. - eNormal, // Element should be drawn in normal state. - eDown, // Element should be drawn in down state. - eHot // Element should be drawn in hot state. - // Note - Scroll bar channel is usually not drawn 'hot'. -} XSB_EDRAWELEM; - -// Enum - For Scrollbar five UI elements: -// Top (Left) arrow button. -// Top (Left) channel (or shaft). -// Thumb track button. -// Bottom (Right) channel (or shaft). -// Bottom (Right) arrow button. -typedef enum tagXSB_EAREA -{ - eNone = 0, - eTLbutton, // Top (Left) arrow button. - eBRbutton, // Bottom (Right) arrow button. - eTLchannel, // Top (Left) channel (or shaft). - eBRchannel, // Bottom (Right) channel (or shaft). - eThumb // Thumb track button. -} eXSB_AREA; - -// 'Helper' data structure - helps make the code readable. -typedef struct tagXSB_STAREA -{ - tagXSB_STAREA() { eArea = eNone; } - void operator=( eXSB_AREA e ) { eArea = e; } - void operator=( tagXSB_STAREA &st ) { eArea = st.eArea; } - - bool operator==( tagXSB_STAREA &stB ) { return ( eArea == stB.eArea ); } - bool operator!=( tagXSB_STAREA &stB ) { return ( eArea != stB.eArea ); } - - bool IsNone() { return ( eArea == eNone ); } - - bool IsButton() { return ( eArea == eTLbutton || eArea == eBRbutton ); } - - bool IsThumb() { return ( eArea == eThumb ); } - - bool IsChannel() { return ( eArea == eTLchannel || eArea == eBRchannel ); } - - bool IsLeftButton() { return ( eArea == eTLbutton ); } - - bool IsRightButton() { return ( eArea == eBRbutton ); } - - bool IsUpButton() { return ( eArea == eTLbutton ); } - - bool IsDownButton() { return ( eArea == eBRbutton ); } - - bool IsLeftChannel() { return ( eArea == eTLchannel ); } - - bool IsRightChannel() { return ( eArea == eBRchannel ); } - - bool IsUpChannel() { return ( eArea == eTLchannel ); } - - bool IsDownChannel() { return ( eArea == eBRchannel ); } - - bool IsTLButton() { return ( eArea == eTLbutton ); } - - bool IsBRButton() { return ( eArea == eBRbutton ); } - - bool IsTLChannel() { return ( eArea == eTLchannel ); } - - bool IsBRChannel() { return ( eArea == eBRchannel ); } - - eXSB_AREA eArea; // <- the only data member of this structure. -} stXSB_AREA; - -/////////////////////////////////////////////////////////////////////////// -// CXeScrollBarBase class. - -class CXeScrollBarBase : public CScrollBar -{ - DECLARE_DYNAMIC(CXeScrollBarBase) - -public: - /////////////////////////////////////////////////////////////////////////// - // Construction / destruction - - CXeScrollBarBase(); - virtual ~CXeScrollBarBase(); - - /////////////////////////////////////////////////////////////////////////// - // Create - - // Create 'this' type of scroll bar. - // [IN] dwStyle = Window style. (if SBS_VERT present a vertical scroll bar is created). - // [IN] rect = position and size of window in parent client coords. - // [IN] pParentWnd = Parent window. ASSERTs if not valid. - // [IN] uID = Control identifier. - // Returns TRUE if create was successful. - // returns FALSE if create failed. - virtual BOOL Create( DWORD dwStyle, const RECT& rect, CWnd *pParentWnd, UINT nID ); - - // Create 'this' type of scroll bar from existing (windows standard) scroll bar. - // New scroll bar is created by using the following from the existing scroll bar: - // * Window style. (if SBS_VERT present a vertical scroll bar is created). - // * Window size and position. - // * Control ID. - // * Z-order. - // * Scroll bar parameters (range, page and position). - // [IN] pParentWnd = Parent window. ASSERTs if not valid. - // [IN] nID = Control identifier of exisiting scroll bar. ASSERTs if not found. - // [IN] bUseDefaultWH = TRUE to use system default scroll bar width/height. - // = FALSE to use width/height from existing scroll bar. - // Returns TRUE if create was successful, note - existing scroll has been destroyed. - // returns FALSE if create failed. - BOOL CreateFromExisting( CWnd *pParentWnd, UINT nID, BOOL bUseDefaultWH = TRUE ); - - BOOL RegisterWindowClass(); - - /////////////////////////////////////////////////////////////////////////// - // Overrides - - // This is the only member a derived class needs to override. - // Note - derived class should NOT call DrawScrollBar in this class. - virtual void DrawScrollBar( CDC* pDC ); - -protected: - /////////////////////////////////////////////////////////////////////////// - // Message map functions - - /////////////////////////////////////////////////////////////////////////// - // Scroll bar message (SBM_XXX) handlers - - // SBM_ENABLE_ARROWS message handler. - afx_msg LRESULT OnSbmEnableArrows( WPARAM wparam, LPARAM lparam ); - - // SBM_GETPOS message handler. - afx_msg LRESULT OnSbmGetPos( WPARAM wparam, LPARAM lparam ); - - // SBM_GETRANGE message handler. - afx_msg LRESULT OnSbmGetRange( WPARAM wparam, LPARAM lparam ); - - // SBM_GETSCROLLBARINFO message handler. - afx_msg LRESULT OnSbmGetScrollBarInfo( WPARAM wparam, LPARAM lparam ); - - // SBM_GETSCROLLINFO message handler. - afx_msg LRESULT OnSbmGetScrollInfo( WPARAM wparam, LPARAM lparam ); - - // SBM_SETPOS message handler. - afx_msg LRESULT OnSbmSetPos( WPARAM wparam, LPARAM lparam ); - - // SBM_SETRANGE message handler. - afx_msg LRESULT OnSbmSetRange( WPARAM wparam, LPARAM lparam ); - - // SBM_SETRANGEREDRAW message handler. - afx_msg LRESULT OnSbmSetRangeRedraw( WPARAM wparam, LPARAM lparam ); - - // SBM_SETSCROLLINFO message handler. - afx_msg LRESULT OnSbmSetScrollInfo( WPARAM wparam, LPARAM lparam ); - - /////////////////////////////////////////////////////////////////////////// - // Paint messages - - // WM_PAINT message handler. - afx_msg void OnPaint(); - - // WM_ERASEBKGND message handler. - afx_msg BOOL OnEraseBkgnd( CDC* pDC ); - - /////////////////////////////////////////////////////////////////////////// - // Keyboard messages - - // WM_KEYDOWN message handler. - afx_msg LRESULT OnKeyDown( WPARAM wParam, LPARAM lParam ); - - // WM_KEYUP message handler. - afx_msg LRESULT OnKeyUp( WPARAM wParam, LPARAM lParam ); - - /////////////////////////////////////////////////////////////////////////// - // Mouse messages - - // WM_LBUTTONDOWN message handler. - afx_msg void OnLButtonDown( UINT nFlags, CPoint point ); - - // WM_LBUTTONUP message handler. - afx_msg void OnLButtonUp( UINT nFlags, CPoint point ); - - // WM_MOUSEWHEEL message handler. - afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - - // WM_MOUSEMOVE message handler. - afx_msg void OnMouseMove( UINT nFlags, CPoint point ); - - // WM_MOUSELEAVE message handler. - afx_msg LRESULT OnMouseLeave( WPARAM wparam, LPARAM lparam ); - - /////////////////////////////////////////////////////////////////////////// - // Other messages - - // WM_GETDLGCODE message handler. - afx_msg LRESULT OnGetDlgCode( WPARAM wParam, LPARAM lParam ); - - // WM_CANCELMODE message handler. - afx_msg void OnCancelMode(); - - // WM_CONTEXTMENU message handler. - afx_msg void OnContextMenu( CWnd* pWnd, CPoint point ); - - // ON_COMMAND_RANGE message map handler - for menu commands. - afx_msg void OnMenuCommands( UINT uID ); - - // WM_TIMER message handler. - afx_msg void OnTimer(UINT_PTR nIDEvent ); - - // WM_SIZE message handler. - afx_msg void OnSize( UINT nType, int cx, int cy ); - - // WM_SETFOCUS message handler. - afx_msg void OnSetFocus( CWnd* pOldWnd ); - - // WM_KILLFOCUS message handler. - afx_msg void OnKillFocus( CWnd* pNewWnd ); - - // WM_ENABLE message handler. - afx_msg void OnEnable( BOOL bEnable ); - - /////////////////////////////////////////////////////////////////////////// - // Helpers - - // Send WM_HSCROLL or WM_VSCROLL message to parent window. - // [IN] wSBcode = SB_XXX message (LOWORD of WPARAM). - // [IN] wHiWPARAM = Scroll pos when SB_THUMBTRACK or SB_THUMBPOSITION. - virtual void SendScrollMsg( WORD wSBcode, WORD wHiWPARAM = 0 ); - - // Get UI area (element) from point. - // Returns UI area enum if point is within a UI element else eNone. - eXSB_AREA GetAreaFromPoint( CPoint point ); - - // Get 'state' of UI element. - // [IN] eElem = UI area (element). - // [OUT] eState = enumerated 'state' of requested area. - // Returns pointer to CRect of UI element or NULL if eElem invalid enum. - const CRect *GetUIelementDrawState( eXSB_AREA eElem, XSB_EDRAWELEM &eState ); - - // Calculate thumb size and position - used by RecalcRects(). - // [IN] cxyChannel = channel width or height (excluding arrow buttons). - // [OUT] xyThumb = Thumb x or y pos. (0 = first pixel in channel). - // [OUT] cxyThumb = Thumb width or height. - // Returns TRUE if channel W/H big enough for a thumb. - // Returns FALSE if no space for thumb (xyThumb and cxyThumb unchanged). - BOOL CalcThumb( int cxyChannel, int &xyThumb, int &cxyThumb ); - - // Recalculate UI elements size and positions. - // Note - thumb XY position is calculated from current scroll pos (m_nPos). - // Called from Create(...), SetScrollPos(...), SetScrollRange(...), - // SetScrollInfo(...), OnSize(...). - void RecalcRects(); - - // Recalculate thumb and channel rects - used while user is dragging the thumb. - // [IN] point = current mouse coords. in client coords. - // Returns TRUE if thumb XY position has changed, else FALSE. - // Note - Only thumb position changes, not the width/height. - // Note - called from within OnMouseMove(...). - BOOL RecalcRectsThumbTrack( CPoint point ); - - /////////////////////////////////////////////////////////////////////////// - // Data members - CWnd *m_pParent; // Parent window. - - BOOL m_bEnabled; // Window enabled state - TRUE = enabled. - // Note - Updated on WM_ENABLE message. - - BOOL m_bHasFocus; // TRUE when 'this' has input focus. - // Set TRUE in OnSetFocus. - // Set FALSE in OnKillFocus. - - BOOL m_bDrawGripper; // TRUE when 'gripper' shown on thumb box. - // FALSE when 'gripper' not drawn. - // Note - helps implement 'blinking' focus. - - BOOL m_bHorizontal; // TRUE = 'this' is horizontal scroll bar - - int m_nPos; // Current thumb position in scroll units - int m_nTrackPos; // Current thumb position (while dragging). - UINT m_uPage; // Scroll 'page' size in scroll units (min = 0). - int m_nMinPos; // Minimum scrolling position - int m_nMaxPos; // Maximum scrolling position - - BOOL m_bNoScroll; // Set TRUE if 'this' scroll bar was disabled because - // of SIF_DISABLENOSCROLL flag in SBM_SETSCROLLINFO msg. - - int m_nMaxReportedPos; // Max. pos scrollbar can report. - // = m_nMaxPos - (m_uPage - 1). - // = m_nMaxPos when m_uPage == 0. - - BOOL m_bDragging; // TRUE = thumb is being dragged - - BOOL m_bTrackMouseLeave; // TRUE when TrackMouseEvent called. - // Set FALSE when OnMouseLeave called. - - BOOL m_bNeedEndScroll; // TRUE if sending SB_ENDSCROLL is needed. - // Set TRUE in OnKeyDown if a SB_XXX message was sent. - // Set TRUE in OnLButtonDown if a SB_XXX message was sent. - // Set TRUE in OnMouseMove if a SB_XXX message was sent. - // Note - SB_ENDSCROLL is sent in OnKeyDown and in - // OnLButtonUp if m_bNeedEndScroll is TRUE. - - stXSB_AREA m_eMouseOverArea; // Where mouse is 'now'. - stXSB_AREA m_eMouseDownArea; // Where mouse is when L btn down. - - CPoint m_ptMenu; // Client coords. of context menu. - // Needed for 'Scroll Here' command. - - //=================================================================================== - // These vars. are calculated when RecalcRects() called. - CRect m_rectClient; // client rect - updated when RecalcRects() called. - CRect m_rectThumb; // current rect for thumb - CRect m_rectTLArrow; // top or left arrow rect - CRect m_rectBRArrow; // bottom or right arrow rect - CRect m_rectTLChannel; // top or left channel rect - CRect m_rectBRChannel; // bottom or right channel rect - - double m_dblPx_SU; // Number of pixels in one scroll unit. - // Note - not valid unless m_rectThumb is not empty. - //=================================================================================== - - UINT m_uArrowWH; // width or height of arrow button - // - set by derived class. - // If = 0 and Horz - // button width = client area height. - // If = 0 and Vert - // button height = client area width. - // Set to 0 by ctor. - UINT GetCXYarrow(); - - UINT m_uThumbMinHW; // Minimum width or height of thumb (pixels). - // Set to 8 pixels by ctor. - - int m_xyThumbDragOffset;// Offset (x or y) into m_rectThumb. - // When user presses L button down in the thumb - we need to capture the - // relative X or Y position of the mouse cursor in m_rectThumb. - // This is used while dragging so mouse x or y rel. pos. in thumb is unchanged. - - /////////////////////////////////////////////////////////////////////////// - - UINT scrollLines; //added to support multiple rows per mouse notch - - DECLARE_MESSAGE_MAP() -}; - - +#pragma once + +/**************************************************************************************** +CXeScrollBarBase class. +This class implements a very close copy of the standard windows scroll bar. +This class is designed as a base class for another class that will do all painting. +This class handles all the business logic. +No painting is done in this class - except in debug mode. + +The derived class needs to do the following: +* MUST override DrawScrollBar member function to do all the painting. + Example: + Create memory DC - same size as client area. + XSB_EDRAWELEM eState; + const CRect *prcElem = 0; + stXSB_AREA stArea; + for( int nElem = eTLbutton; nElem <= eThumb; nElem++ ) // loop through all UI elements. + { + stArea.eArea = (eXSB_AREA)nElem; + + // Get bounding rect of UI element to draw (client coords.) + prcElem = GetUIelementDrawState( stArea.eArea, eState ); + if( !prcElem || eState == eNotDrawn ) // Rect empty or area not drawn? + continue; + + // stArea.eArea identifies UI element to draw: + // eTLbutton or eTLchannel or eThumb or eBRchannel or eBRbutton. + + // eState identifes in what state the UI element is drawn: + // eDisabled or eNormal or eDown or eHot. + + // m_bHorizontal is TRUE if 'this' is a horizontal scroll bar. + + // Draw UI element to memory DC. (using prcElem rect). + // Note - use m_bDrawGripper to determine if 'gripper' is drawn on thumb box. + // This is used to implement 'blinking' to show scroll bar has input + // focus. (every 500mS). + } + Copy memory DC to pDC. + +* (optional) Set m_uArrowWH to the width of the arrow button in horizontal scrollbar, + note - height of arrow button in vertical scrollbar is the same. + If this member is left unchanged (= 0) the arrow button width in horizontal scrollbar + is assumed to be equal to the height of the window. Same for vertical scroll bar + except the width of the window is arrow button height. + This number is needed to calculate sizes of other UI elements of the scroll bar. + +* (optional) Set m_uThumbMinHW to the minimum allowed width of the thumb box in a + horizontal scroll bar, this value is also the minimum height of the thumb box in a + vertical scroll bar. The default is 8 pixels. +****************************************************************************************/ + +// Enum - UI element state - helps with drawing scrollbar. +typedef enum tagXSB_EDRAWELEM +{ + eNotDrawn = 0, // UI element is not visible. (UI Rect empty). + eDisabled, // Element should be drawn in disabled state. + eNormal, // Element should be drawn in normal state. + eDown, // Element should be drawn in down state. + eHot // Element should be drawn in hot state. + // Note - Scroll bar channel is usually not drawn 'hot'. +} XSB_EDRAWELEM; + +// Enum - For Scrollbar five UI elements: +// Top (Left) arrow button. +// Top (Left) channel (or shaft). +// Thumb track button. +// Bottom (Right) channel (or shaft). +// Bottom (Right) arrow button. +typedef enum tagXSB_EAREA +{ + eNone = 0, + eTLbutton, // Top (Left) arrow button. + eBRbutton, // Bottom (Right) arrow button. + eTLchannel, // Top (Left) channel (or shaft). + eBRchannel, // Bottom (Right) channel (or shaft). + eThumb // Thumb track button. +} eXSB_AREA; + +// 'Helper' data structure - helps make the code readable. +typedef struct tagXSB_STAREA +{ + tagXSB_STAREA() { eArea = eNone; } + void operator=( eXSB_AREA e ) { eArea = e; } + void operator=( tagXSB_STAREA &st ) { eArea = st.eArea; } + + bool operator==( tagXSB_STAREA &stB ) { return ( eArea == stB.eArea ); } + bool operator!=( tagXSB_STAREA &stB ) { return ( eArea != stB.eArea ); } + + bool IsNone() { return ( eArea == eNone ); } + + bool IsButton() { return ( eArea == eTLbutton || eArea == eBRbutton ); } + + bool IsThumb() { return ( eArea == eThumb ); } + + bool IsChannel() { return ( eArea == eTLchannel || eArea == eBRchannel ); } + + bool IsLeftButton() { return ( eArea == eTLbutton ); } + + bool IsRightButton() { return ( eArea == eBRbutton ); } + + bool IsUpButton() { return ( eArea == eTLbutton ); } + + bool IsDownButton() { return ( eArea == eBRbutton ); } + + bool IsLeftChannel() { return ( eArea == eTLchannel ); } + + bool IsRightChannel() { return ( eArea == eBRchannel ); } + + bool IsUpChannel() { return ( eArea == eTLchannel ); } + + bool IsDownChannel() { return ( eArea == eBRchannel ); } + + bool IsTLButton() { return ( eArea == eTLbutton ); } + + bool IsBRButton() { return ( eArea == eBRbutton ); } + + bool IsTLChannel() { return ( eArea == eTLchannel ); } + + bool IsBRChannel() { return ( eArea == eBRchannel ); } + + eXSB_AREA eArea; // <- the only data member of this structure. +} stXSB_AREA; + +/////////////////////////////////////////////////////////////////////////// +// CXeScrollBarBase class. + +class CXeScrollBarBase : public CScrollBar +{ + DECLARE_DYNAMIC(CXeScrollBarBase) + +public: + /////////////////////////////////////////////////////////////////////////// + // Construction / destruction + + CXeScrollBarBase(); + virtual ~CXeScrollBarBase(); + + /////////////////////////////////////////////////////////////////////////// + // Create + + // Create 'this' type of scroll bar. + // [IN] dwStyle = Window style. (if SBS_VERT present a vertical scroll bar is created). + // [IN] rect = position and size of window in parent client coords. + // [IN] pParentWnd = Parent window. ASSERTs if not valid. + // [IN] uID = Control identifier. + // Returns TRUE if create was successful. + // returns FALSE if create failed. + virtual BOOL Create( DWORD dwStyle, const RECT& rect, CWnd *pParentWnd, UINT nID ); + + // Create 'this' type of scroll bar from existing (windows standard) scroll bar. + // New scroll bar is created by using the following from the existing scroll bar: + // * Window style. (if SBS_VERT present a vertical scroll bar is created). + // * Window size and position. + // * Control ID. + // * Z-order. + // * Scroll bar parameters (range, page and position). + // [IN] pParentWnd = Parent window. ASSERTs if not valid. + // [IN] nID = Control identifier of exisiting scroll bar. ASSERTs if not found. + // [IN] bUseDefaultWH = TRUE to use system default scroll bar width/height. + // = FALSE to use width/height from existing scroll bar. + // Returns TRUE if create was successful, note - existing scroll has been destroyed. + // returns FALSE if create failed. + BOOL CreateFromExisting( CWnd *pParentWnd, UINT nID, BOOL bUseDefaultWH = TRUE ); + + BOOL RegisterWindowClass(); + + /////////////////////////////////////////////////////////////////////////// + // Overrides + + // This is the only member a derived class needs to override. + // Note - derived class should NOT call DrawScrollBar in this class. + virtual void DrawScrollBar( CDC* pDC ); + +protected: + /////////////////////////////////////////////////////////////////////////// + // Message map functions + + /////////////////////////////////////////////////////////////////////////// + // Scroll bar message (SBM_XXX) handlers + + // SBM_ENABLE_ARROWS message handler. + afx_msg LRESULT OnSbmEnableArrows( WPARAM wparam, LPARAM lparam ); + + // SBM_GETPOS message handler. + afx_msg LRESULT OnSbmGetPos( WPARAM wparam, LPARAM lparam ); + + // SBM_GETRANGE message handler. + afx_msg LRESULT OnSbmGetRange( WPARAM wparam, LPARAM lparam ); + + // SBM_GETSCROLLBARINFO message handler. + afx_msg LRESULT OnSbmGetScrollBarInfo( WPARAM wparam, LPARAM lparam ); + + // SBM_GETSCROLLINFO message handler. + afx_msg LRESULT OnSbmGetScrollInfo( WPARAM wparam, LPARAM lparam ); + + // SBM_SETPOS message handler. + afx_msg LRESULT OnSbmSetPos( WPARAM wparam, LPARAM lparam ); + + // SBM_SETRANGE message handler. + afx_msg LRESULT OnSbmSetRange( WPARAM wparam, LPARAM lparam ); + + // SBM_SETRANGEREDRAW message handler. + afx_msg LRESULT OnSbmSetRangeRedraw( WPARAM wparam, LPARAM lparam ); + + // SBM_SETSCROLLINFO message handler. + afx_msg LRESULT OnSbmSetScrollInfo( WPARAM wparam, LPARAM lparam ); + + /////////////////////////////////////////////////////////////////////////// + // Paint messages + + // WM_PAINT message handler. + afx_msg void OnPaint(); + + // WM_ERASEBKGND message handler. + afx_msg BOOL OnEraseBkgnd( CDC* pDC ); + + /////////////////////////////////////////////////////////////////////////// + // Keyboard messages + + // WM_KEYDOWN message handler. + afx_msg LRESULT OnKeyDown( WPARAM wParam, LPARAM lParam ); + + // WM_KEYUP message handler. + afx_msg LRESULT OnKeyUp( WPARAM wParam, LPARAM lParam ); + + /////////////////////////////////////////////////////////////////////////// + // Mouse messages + + // WM_LBUTTONDOWN message handler. + afx_msg void OnLButtonDown( UINT nFlags, CPoint point ); + + // WM_LBUTTONUP message handler. + afx_msg void OnLButtonUp( UINT nFlags, CPoint point ); + + // WM_MOUSEWHEEL message handler. + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + + // WM_MOUSEMOVE message handler. + afx_msg void OnMouseMove( UINT nFlags, CPoint point ); + + // WM_MOUSELEAVE message handler. + afx_msg LRESULT OnMouseLeave( WPARAM wparam, LPARAM lparam ); + + /////////////////////////////////////////////////////////////////////////// + // Other messages + + // WM_GETDLGCODE message handler. + afx_msg LRESULT OnGetDlgCode( WPARAM wParam, LPARAM lParam ); + + // WM_CANCELMODE message handler. + afx_msg void OnCancelMode(); + + // WM_CONTEXTMENU message handler. + afx_msg void OnContextMenu( CWnd* pWnd, CPoint point ); + + // ON_COMMAND_RANGE message map handler - for menu commands. + afx_msg void OnMenuCommands( UINT uID ); + + // WM_TIMER message handler. + afx_msg void OnTimer(UINT_PTR nIDEvent ); + + // WM_SIZE message handler. + afx_msg void OnSize( UINT nType, int cx, int cy ); + + // WM_SETFOCUS message handler. + afx_msg void OnSetFocus( CWnd* pOldWnd ); + + // WM_KILLFOCUS message handler. + afx_msg void OnKillFocus( CWnd* pNewWnd ); + + // WM_ENABLE message handler. + afx_msg void OnEnable( BOOL bEnable ); + + /////////////////////////////////////////////////////////////////////////// + // Helpers + + // Send WM_HSCROLL or WM_VSCROLL message to parent window. + // [IN] wSBcode = SB_XXX message (LOWORD of WPARAM). + // [IN] wHiWPARAM = Scroll pos when SB_THUMBTRACK or SB_THUMBPOSITION. + virtual void SendScrollMsg( WORD wSBcode, WORD wHiWPARAM = 0 ); + + // Get UI area (element) from point. + // Returns UI area enum if point is within a UI element else eNone. + eXSB_AREA GetAreaFromPoint( CPoint point ); + + // Get 'state' of UI element. + // [IN] eElem = UI area (element). + // [OUT] eState = enumerated 'state' of requested area. + // Returns pointer to CRect of UI element or NULL if eElem invalid enum. + const CRect *GetUIelementDrawState( eXSB_AREA eElem, XSB_EDRAWELEM &eState ); + + // Calculate thumb size and position - used by RecalcRects(). + // [IN] cxyChannel = channel width or height (excluding arrow buttons). + // [OUT] xyThumb = Thumb x or y pos. (0 = first pixel in channel). + // [OUT] cxyThumb = Thumb width or height. + // Returns TRUE if channel W/H big enough for a thumb. + // Returns FALSE if no space for thumb (xyThumb and cxyThumb unchanged). + BOOL CalcThumb( int cxyChannel, int &xyThumb, int &cxyThumb ); + + // Recalculate UI elements size and positions. + // Note - thumb XY position is calculated from current scroll pos (m_nPos). + // Called from Create(...), SetScrollPos(...), SetScrollRange(...), + // SetScrollInfo(...), OnSize(...). + void RecalcRects(); + + // Recalculate thumb and channel rects - used while user is dragging the thumb. + // [IN] point = current mouse coords. in client coords. + // Returns TRUE if thumb XY position has changed, else FALSE. + // Note - Only thumb position changes, not the width/height. + // Note - called from within OnMouseMove(...). + BOOL RecalcRectsThumbTrack( CPoint point ); + + /////////////////////////////////////////////////////////////////////////// + // Data members + CWnd *m_pParent; // Parent window. + + BOOL m_bEnabled; // Window enabled state - TRUE = enabled. + // Note - Updated on WM_ENABLE message. + + BOOL m_bHasFocus; // TRUE when 'this' has input focus. + // Set TRUE in OnSetFocus. + // Set FALSE in OnKillFocus. + + BOOL m_bDrawGripper; // TRUE when 'gripper' shown on thumb box. + // FALSE when 'gripper' not drawn. + // Note - helps implement 'blinking' focus. + + BOOL m_bHorizontal; // TRUE = 'this' is horizontal scroll bar + + int m_nPos; // Current thumb position in scroll units + int m_nTrackPos; // Current thumb position (while dragging). + UINT m_uPage; // Scroll 'page' size in scroll units (min = 0). + int m_nMinPos; // Minimum scrolling position + int m_nMaxPos; // Maximum scrolling position + + BOOL m_bNoScroll; // Set TRUE if 'this' scroll bar was disabled because + // of SIF_DISABLENOSCROLL flag in SBM_SETSCROLLINFO msg. + + int m_nMaxReportedPos; // Max. pos scrollbar can report. + // = m_nMaxPos - (m_uPage - 1). + // = m_nMaxPos when m_uPage == 0. + + BOOL m_bDragging; // TRUE = thumb is being dragged + + BOOL m_bTrackMouseLeave; // TRUE when TrackMouseEvent called. + // Set FALSE when OnMouseLeave called. + + BOOL m_bNeedEndScroll; // TRUE if sending SB_ENDSCROLL is needed. + // Set TRUE in OnKeyDown if a SB_XXX message was sent. + // Set TRUE in OnLButtonDown if a SB_XXX message was sent. + // Set TRUE in OnMouseMove if a SB_XXX message was sent. + // Note - SB_ENDSCROLL is sent in OnKeyDown and in + // OnLButtonUp if m_bNeedEndScroll is TRUE. + + stXSB_AREA m_eMouseOverArea; // Where mouse is 'now'. + stXSB_AREA m_eMouseDownArea; // Where mouse is when L btn down. + + CPoint m_ptMenu; // Client coords. of context menu. + // Needed for 'Scroll Here' command. + + //=================================================================================== + // These vars. are calculated when RecalcRects() called. + CRect m_rectClient; // client rect - updated when RecalcRects() called. + CRect m_rectThumb; // current rect for thumb + CRect m_rectTLArrow; // top or left arrow rect + CRect m_rectBRArrow; // bottom or right arrow rect + CRect m_rectTLChannel; // top or left channel rect + CRect m_rectBRChannel; // bottom or right channel rect + + double m_dblPx_SU; // Number of pixels in one scroll unit. + // Note - not valid unless m_rectThumb is not empty. + //=================================================================================== + + UINT m_uArrowWH; // width or height of arrow button + // - set by derived class. + // If = 0 and Horz + // button width = client area height. + // If = 0 and Vert + // button height = client area width. + // Set to 0 by ctor. + UINT GetCXYarrow(); + + UINT m_uThumbMinHW; // Minimum width or height of thumb (pixels). + // Set to 8 pixels by ctor. + + int m_xyThumbDragOffset;// Offset (x or y) into m_rectThumb. + // When user presses L button down in the thumb - we need to capture the + // relative X or Y position of the mouse cursor in m_rectThumb. + // This is used while dragging so mouse x or y rel. pos. in thumb is unchanged. + + /////////////////////////////////////////////////////////////////////////// + + UINT scrollLines; //added to support multiple rows per mouse notch + + DECLARE_MESSAGE_MAP() +}; + + diff --git a/src/thirdparty/lcms2/lcms2.vcxproj b/src/thirdparty/lcms2/lcms2.vcxproj index d4eba961026..a9324e7992d 100644 --- a/src/thirdparty/lcms2/lcms2.vcxproj +++ b/src/thirdparty/lcms2/lcms2.vcxproj @@ -1,88 +1,88 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {ACF5C64B-78AA-4730-91A2-24F4910FBAD9} - Win32Proj - lcms2 - lcms2 - - - - - StaticLibrary - Unicode - - - - - - - - - - - - - _LIB;%(PreprocessorDefinitions) - library\include;library\src - lcms2_internal.h - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {ACF5C64B-78AA-4730-91A2-24F4910FBAD9} + Win32Proj + lcms2 + lcms2 + + + + + StaticLibrary + Unicode + + + + + + + + + + + + + _LIB;%(PreprocessorDefinitions) + library\include;library\src + lcms2_internal.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + + + + + \ No newline at end of file diff --git a/src/thirdparty/lcms2/lcms2.vcxproj.filters b/src/thirdparty/lcms2/lcms2.vcxproj.filters index 6587959dda5..781d672b6bf 100644 --- a/src/thirdparty/lcms2/lcms2.vcxproj.filters +++ b/src/thirdparty/lcms2/lcms2.vcxproj.filters @@ -1,107 +1,107 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Header Files - - - Header Files - - - Source Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/src/thirdparty/sizecbar/scbarcf.cpp b/src/thirdparty/sizecbar/scbarcf.cpp index 23c7be1d20d..d5a965e643b 100644 --- a/src/thirdparty/sizecbar/scbarcf.cpp +++ b/src/thirdparty/sizecbar/scbarcf.cpp @@ -1,234 +1,234 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBarCF Version 2.44 -// -// Created: Dec 21, 1998 Last Modified: March 31, 2002 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2002 by Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// You must obtain the author's consent before you can include this code -// in a software library. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com or post them at the message board at the site. -///////////////////////////////////////////////////////////////////////// - -#include "stdafx.h" -#include "scbarcf.h" - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarCF - -IMPLEMENT_DYNAMIC(CSizingControlBarCF, baseCSizingControlBarCF); - -int CALLBACK EnumFontFamProc(ENUMLOGFONT FAR *lpelf, - NEWTEXTMETRIC FAR *lpntm, - int FontType, - LPARAM lParam) -{ - UNUSED_ALWAYS(lpelf); - UNUSED_ALWAYS(lpntm); - UNUSED_ALWAYS(FontType); - UNUSED_ALWAYS(lParam); - - return 0; -} - -CSizingControlBarCF::CSizingControlBarCF() -{ - m_bActive = FALSE; - - CDC dc; - dc.CreateCompatibleDC(NULL); - - m_sFontFace = (::EnumFontFamilies(dc.m_hDC, - _T("Tahoma"), (FONTENUMPROC) EnumFontFamProc, 0) == 0) ? - _T("Tahoma") : _T("Arial"); - - dc.DeleteDC(); - -} - -BEGIN_MESSAGE_MAP(CSizingControlBarCF, baseCSizingControlBarCF) - //{{AFX_MSG_MAP(CSizingControlBarCF) - //}}AFX_MSG_MAP - ON_MESSAGE(WM_SETTEXT, OnSetText) -END_MESSAGE_MAP() - -void CSizingControlBarCF::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) -{ - baseCSizingControlBarCF::OnUpdateCmdUI(pTarget, bDisableIfNoHndler); - - if (!HasGripper()) - return; - - BOOL bNeedPaint = FALSE; - - CWnd* pFocus = GetFocus(); - BOOL bActiveOld = m_bActive; - - m_bActive = (pFocus->GetSafeHwnd() && IsChild(pFocus)); - - if (m_bActive != bActiveOld) - bNeedPaint = TRUE; - - if (bNeedPaint) - SendMessage(WM_NCPAINT); -} - -// gradient defines (if not already defined) -#ifndef COLOR_GRADIENTACTIVECAPTION -#define COLOR_GRADIENTACTIVECAPTION 27 -#define COLOR_GRADIENTINACTIVECAPTION 28 -#define SPI_GETGRADIENTCAPTIONS 0x1008 -#endif - -void CSizingControlBarCF::NcPaintGripper(CDC* pDC, CRect rcClient) -{ - if (!HasGripper()) - return; - - // compute the caption rectangle - BOOL bHorz = IsHorzDocked(); - CRect rcGrip = rcClient; - CRect rcBtn = m_biHide.GetRect(); - if (bHorz) - { // right side gripper - rcGrip.left -= m_cyGripper + 1; - rcGrip.right = rcGrip.left + 11; - rcGrip.top = rcBtn.bottom + 3; - } - else - { // gripper at top - rcGrip.top -= m_cyGripper + 1; - rcGrip.bottom = rcGrip.top + 11; - rcGrip.right = rcBtn.left - 3; - } - rcGrip.InflateRect(bHorz ? 1 : 0, bHorz ? 0 : 1); - - // draw the caption background - //CBrush br; - COLORREF clrCptn = m_bActive ? - ::GetSysColor(COLOR_ACTIVECAPTION) : - ::GetSysColor(COLOR_INACTIVECAPTION); - - // query gradient info (usually TRUE for Win98/Win2k) - BOOL bGradient = FALSE; - ::SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &bGradient, 0); - - if (!bGradient) - pDC->FillSolidRect(&rcGrip, clrCptn); // solid color - else - { - // gradient from left to right or from bottom to top - // get second gradient color (the right end) - COLORREF clrCptnRight = m_bActive ? - ::GetSysColor(COLOR_GRADIENTACTIVECAPTION) : - ::GetSysColor(COLOR_GRADIENTINACTIVECAPTION); - - // this will make 2^6 = 64 fountain steps - int nShift = 6; - int nSteps = 1 << nShift; - - for (int i = 0; i < nSteps; i++) - { - // do a little alpha blending - int nR = (GetRValue(clrCptn) * (nSteps - i) + - GetRValue(clrCptnRight) * i) >> nShift; - int nG = (GetGValue(clrCptn) * (nSteps - i) + - GetGValue(clrCptnRight) * i) >> nShift; - int nB = (GetBValue(clrCptn) * (nSteps - i) + - GetBValue(clrCptnRight) * i) >> nShift; - - COLORREF cr = RGB(nR, nG, nB); - - // then paint with the resulting color - CRect r2 = rcGrip; - if (bHorz) - { - r2.bottom = rcGrip.bottom - - ((i * rcGrip.Height()) >> nShift); - r2.top = rcGrip.bottom - - (((i + 1) * rcGrip.Height()) >> nShift); - if (r2.Height() > 0) - pDC->FillSolidRect(r2, cr); - } - else - { - r2.left = rcGrip.left + - ((i * rcGrip.Width()) >> nShift); - r2.right = rcGrip.left + - (((i + 1) * rcGrip.Width()) >> nShift); - if (r2.Width() > 0) - pDC->FillSolidRect(r2, cr); - } - } - } - - // draw the caption text - first select a font - CFont font; - int ppi = pDC->GetDeviceCaps(LOGPIXELSX); - int pointsize = MulDiv(85, 96, ppi); // 8.5 points at 96 ppi - - LOGFONT lf; - BOOL bFont = font.CreatePointFont(pointsize, m_sFontFace); - if (bFont) - { - // get the text color - COLORREF clrCptnText = m_bActive ? - ::GetSysColor(COLOR_CAPTIONTEXT) : - ::GetSysColor(COLOR_INACTIVECAPTIONTEXT); - - int nOldBkMode = pDC->SetBkMode(TRANSPARENT); - COLORREF clrOldText = pDC->SetTextColor(clrCptnText); - - if (bHorz) - { - // rotate text 90 degrees CCW if horizontally docked - font.GetLogFont(&lf); - font.DeleteObject(); - lf.lfEscapement = 900; - font.CreateFontIndirect(&lf); - } - - CFont* pOldFont = pDC->SelectObject(&font); - CString sTitle; - GetWindowText(sTitle); - - CPoint ptOrg = bHorz ? - CPoint(rcGrip.left - 1, rcGrip.bottom - 3) : - CPoint(rcGrip.left + 3, rcGrip.top - 1); - - pDC->ExtTextOut(ptOrg.x, ptOrg.y, - ETO_CLIPPED, rcGrip, sTitle, NULL); - - pDC->SelectObject(pOldFont); - pDC->SetBkMode(nOldBkMode); - pDC->SetTextColor(clrOldText); - } - - // draw the button - m_biHide.Paint(pDC); -} - -LRESULT CSizingControlBarCF::OnSetText(WPARAM wParam, LPARAM lParam) -{ - LRESULT lResult = baseCSizingControlBarCF::OnSetText(wParam, lParam); - - SendMessage(WM_NCPAINT); - - return lResult; -} +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBarCF Version 2.44 +// +// Created: Dec 21, 1998 Last Modified: March 31, 2002 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2002 by Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// You must obtain the author's consent before you can include this code +// in a software library. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com or post them at the message board at the site. +///////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "scbarcf.h" + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarCF + +IMPLEMENT_DYNAMIC(CSizingControlBarCF, baseCSizingControlBarCF); + +int CALLBACK EnumFontFamProc(ENUMLOGFONT FAR *lpelf, + NEWTEXTMETRIC FAR *lpntm, + int FontType, + LPARAM lParam) +{ + UNUSED_ALWAYS(lpelf); + UNUSED_ALWAYS(lpntm); + UNUSED_ALWAYS(FontType); + UNUSED_ALWAYS(lParam); + + return 0; +} + +CSizingControlBarCF::CSizingControlBarCF() +{ + m_bActive = FALSE; + + CDC dc; + dc.CreateCompatibleDC(NULL); + + m_sFontFace = (::EnumFontFamilies(dc.m_hDC, + _T("Tahoma"), (FONTENUMPROC) EnumFontFamProc, 0) == 0) ? + _T("Tahoma") : _T("Arial"); + + dc.DeleteDC(); + +} + +BEGIN_MESSAGE_MAP(CSizingControlBarCF, baseCSizingControlBarCF) + //{{AFX_MSG_MAP(CSizingControlBarCF) + //}}AFX_MSG_MAP + ON_MESSAGE(WM_SETTEXT, OnSetText) +END_MESSAGE_MAP() + +void CSizingControlBarCF::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) +{ + baseCSizingControlBarCF::OnUpdateCmdUI(pTarget, bDisableIfNoHndler); + + if (!HasGripper()) + return; + + BOOL bNeedPaint = FALSE; + + CWnd* pFocus = GetFocus(); + BOOL bActiveOld = m_bActive; + + m_bActive = (pFocus->GetSafeHwnd() && IsChild(pFocus)); + + if (m_bActive != bActiveOld) + bNeedPaint = TRUE; + + if (bNeedPaint) + SendMessage(WM_NCPAINT); +} + +// gradient defines (if not already defined) +#ifndef COLOR_GRADIENTACTIVECAPTION +#define COLOR_GRADIENTACTIVECAPTION 27 +#define COLOR_GRADIENTINACTIVECAPTION 28 +#define SPI_GETGRADIENTCAPTIONS 0x1008 +#endif + +void CSizingControlBarCF::NcPaintGripper(CDC* pDC, CRect rcClient) +{ + if (!HasGripper()) + return; + + // compute the caption rectangle + BOOL bHorz = IsHorzDocked(); + CRect rcGrip = rcClient; + CRect rcBtn = m_biHide.GetRect(); + if (bHorz) + { // right side gripper + rcGrip.left -= m_cyGripper + 1; + rcGrip.right = rcGrip.left + 11; + rcGrip.top = rcBtn.bottom + 3; + } + else + { // gripper at top + rcGrip.top -= m_cyGripper + 1; + rcGrip.bottom = rcGrip.top + 11; + rcGrip.right = rcBtn.left - 3; + } + rcGrip.InflateRect(bHorz ? 1 : 0, bHorz ? 0 : 1); + + // draw the caption background + //CBrush br; + COLORREF clrCptn = m_bActive ? + ::GetSysColor(COLOR_ACTIVECAPTION) : + ::GetSysColor(COLOR_INACTIVECAPTION); + + // query gradient info (usually TRUE for Win98/Win2k) + BOOL bGradient = FALSE; + ::SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &bGradient, 0); + + if (!bGradient) + pDC->FillSolidRect(&rcGrip, clrCptn); // solid color + else + { + // gradient from left to right or from bottom to top + // get second gradient color (the right end) + COLORREF clrCptnRight = m_bActive ? + ::GetSysColor(COLOR_GRADIENTACTIVECAPTION) : + ::GetSysColor(COLOR_GRADIENTINACTIVECAPTION); + + // this will make 2^6 = 64 fountain steps + int nShift = 6; + int nSteps = 1 << nShift; + + for (int i = 0; i < nSteps; i++) + { + // do a little alpha blending + int nR = (GetRValue(clrCptn) * (nSteps - i) + + GetRValue(clrCptnRight) * i) >> nShift; + int nG = (GetGValue(clrCptn) * (nSteps - i) + + GetGValue(clrCptnRight) * i) >> nShift; + int nB = (GetBValue(clrCptn) * (nSteps - i) + + GetBValue(clrCptnRight) * i) >> nShift; + + COLORREF cr = RGB(nR, nG, nB); + + // then paint with the resulting color + CRect r2 = rcGrip; + if (bHorz) + { + r2.bottom = rcGrip.bottom - + ((i * rcGrip.Height()) >> nShift); + r2.top = rcGrip.bottom - + (((i + 1) * rcGrip.Height()) >> nShift); + if (r2.Height() > 0) + pDC->FillSolidRect(r2, cr); + } + else + { + r2.left = rcGrip.left + + ((i * rcGrip.Width()) >> nShift); + r2.right = rcGrip.left + + (((i + 1) * rcGrip.Width()) >> nShift); + if (r2.Width() > 0) + pDC->FillSolidRect(r2, cr); + } + } + } + + // draw the caption text - first select a font + CFont font; + int ppi = pDC->GetDeviceCaps(LOGPIXELSX); + int pointsize = MulDiv(85, 96, ppi); // 8.5 points at 96 ppi + + LOGFONT lf; + BOOL bFont = font.CreatePointFont(pointsize, m_sFontFace); + if (bFont) + { + // get the text color + COLORREF clrCptnText = m_bActive ? + ::GetSysColor(COLOR_CAPTIONTEXT) : + ::GetSysColor(COLOR_INACTIVECAPTIONTEXT); + + int nOldBkMode = pDC->SetBkMode(TRANSPARENT); + COLORREF clrOldText = pDC->SetTextColor(clrCptnText); + + if (bHorz) + { + // rotate text 90 degrees CCW if horizontally docked + font.GetLogFont(&lf); + font.DeleteObject(); + lf.lfEscapement = 900; + font.CreateFontIndirect(&lf); + } + + CFont* pOldFont = pDC->SelectObject(&font); + CString sTitle; + GetWindowText(sTitle); + + CPoint ptOrg = bHorz ? + CPoint(rcGrip.left - 1, rcGrip.bottom - 3) : + CPoint(rcGrip.left + 3, rcGrip.top - 1); + + pDC->ExtTextOut(ptOrg.x, ptOrg.y, + ETO_CLIPPED, rcGrip, sTitle, NULL); + + pDC->SelectObject(pOldFont); + pDC->SetBkMode(nOldBkMode); + pDC->SetTextColor(clrOldText); + } + + // draw the button + m_biHide.Paint(pDC); +} + +LRESULT CSizingControlBarCF::OnSetText(WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = baseCSizingControlBarCF::OnSetText(wParam, lParam); + + SendMessage(WM_NCPAINT); + + return lResult; +} diff --git a/src/thirdparty/sizecbar/scbarcf.h b/src/thirdparty/sizecbar/scbarcf.h index 9788fd5cbfc..e5c20d2463e 100644 --- a/src/thirdparty/sizecbar/scbarcf.h +++ b/src/thirdparty/sizecbar/scbarcf.h @@ -1,78 +1,78 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBarCF Version 2.44 -// -// Created: Dec 21, 1998 Last Modified: March 31, 2002 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2002 by Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// You must obtain the author's consent before you can include this code -// in a software library. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com or post them at the message board at the site. -///////////////////////////////////////////////////////////////////////// - -#if !defined(__SCBARCF_H__) -#define __SCBARCF_H__ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 -// scbarcf.h : header file -// - -#include "scbarg.h" - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarCF - -#ifndef baseCSizingControlBarCF -#define baseCSizingControlBarCF CSizingControlBarG -#endif - -class CSizingControlBarCF : public baseCSizingControlBarCF -{ - DECLARE_DYNAMIC(CSizingControlBarCF) - -// Construction -public: - CSizingControlBarCF(); - -// Overridables - virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); - -// Implementation -protected: - // implementation helpers - virtual void NcPaintGripper(CDC* pDC, CRect rcClient); - -protected: - BOOL m_bActive; // a child has focus - CString m_sFontFace; - -// Generated message map functions -protected: - //{{AFX_MSG(CSizingControlBarCF) - //}}AFX_MSG - afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam); - - DECLARE_MESSAGE_MAP() -}; - -///////////////////////////////////////////////////////////////////////// - -#endif // !defined(__SCBARCF_H__) +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBarCF Version 2.44 +// +// Created: Dec 21, 1998 Last Modified: March 31, 2002 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2002 by Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// You must obtain the author's consent before you can include this code +// in a software library. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com or post them at the message board at the site. +///////////////////////////////////////////////////////////////////////// + +#if !defined(__SCBARCF_H__) +#define __SCBARCF_H__ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// scbarcf.h : header file +// + +#include "scbarg.h" + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarCF + +#ifndef baseCSizingControlBarCF +#define baseCSizingControlBarCF CSizingControlBarG +#endif + +class CSizingControlBarCF : public baseCSizingControlBarCF +{ + DECLARE_DYNAMIC(CSizingControlBarCF) + +// Construction +public: + CSizingControlBarCF(); + +// Overridables + virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); + +// Implementation +protected: + // implementation helpers + virtual void NcPaintGripper(CDC* pDC, CRect rcClient); + +protected: + BOOL m_bActive; // a child has focus + CString m_sFontFace; + +// Generated message map functions +protected: + //{{AFX_MSG(CSizingControlBarCF) + //}}AFX_MSG + afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////// + +#endif // !defined(__SCBARCF_H__) diff --git a/src/thirdparty/sizecbar/scbarg.cpp b/src/thirdparty/sizecbar/scbarg.cpp index 5e9c249c64a..5922940460e 100644 --- a/src/thirdparty/sizecbar/scbarg.cpp +++ b/src/thirdparty/sizecbar/scbarg.cpp @@ -1,256 +1,256 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBarG Version 2.45 -// -// Created: Jan 24, 1998 Last Modified: April 16, 2010 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com . -///////////////////////////////////////////////////////////////////////// - -// sizecbar.cpp : implementation file -// - -#include "stdafx.h" -#include "scbarg.h" - - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarG - -IMPLEMENT_DYNAMIC(CSizingControlBarG, baseCSizingControlBarG); - -CSizingControlBarG::CSizingControlBarG() -{ - m_cyGripper = 12; -} - -CSizingControlBarG::~CSizingControlBarG() -{ -} - -BEGIN_MESSAGE_MAP(CSizingControlBarG, baseCSizingControlBarG) - //{{AFX_MSG_MAP(CSizingControlBarG) - ON_WM_NCLBUTTONUP() - ON_WM_NCHITTEST() - //}}AFX_MSG_MAP - ON_MESSAGE(WM_SETTEXT, OnSetText) -END_MESSAGE_MAP() - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarG message handlers - -///////////////////////////////////////////////////////////////////////// -// Mouse Handling -// - -void CSizingControlBarG::OnNcLButtonUp(UINT nHitTest, CPoint point) -{ - if (nHitTest == HTCLOSE) - m_pDockSite->ShowControlBar(this, FALSE, FALSE); // hide - - baseCSizingControlBarG::OnNcLButtonUp(nHitTest, point); -} - -void CSizingControlBarG::NcCalcClient(LPRECT pRc, UINT nDockBarID) -{ - CRect rcBar(pRc); // save the bar rect - - // subtract edges - baseCSizingControlBarG::NcCalcClient(pRc, nDockBarID); - - if (!HasGripper()) - return; - - CRect rc(pRc); // the client rect as calculated by the base class - //mpc-hc custom code start - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ClientToScreen(rcBar); - GetParent()->ClientToScreen(rc); - //mpc-hc custom code end - - BOOL bHorz = (nDockBarID == AFX_IDW_DOCKBAR_TOP) || - (nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); - - if (bHorz) - rc.DeflateRect(m_cyGripper, 0, 0, 0); - else - rc.DeflateRect(0, m_cyGripper, 0, 0); - - // set position for the "x" (hide bar) button - CPoint ptOrgBtn; - if (bHorz) - ptOrgBtn = CPoint(rc.left - 13, rc.top); - else - ptOrgBtn = CPoint(rc.right - 12, rc.top - 13); - - m_biHide.Move(ptOrgBtn - rcBar.TopLeft()); - - //mpc-hc custom code start - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ScreenToClient(&rc); - //mpc-hc custom code end - - *pRc = rc; -} - -void CSizingControlBarG::NcPaintGripper(CDC* pDC, CRect rcClient) -{ - if (!HasGripper()) - return; - - // paints a simple "two raised lines" gripper - // override this if you want a more sophisticated gripper - CRect gripper = rcClient; - CRect rcbtn = m_biHide.GetRect(); - BOOL bHorz = IsHorzDocked(); - - gripper.DeflateRect(1, 1); - if (bHorz) - { // gripper at left - gripper.left -= m_cyGripper; - gripper.right = gripper.left + 3; - gripper.top = rcbtn.bottom + 3; - } - else - { // gripper at top - gripper.top -= m_cyGripper; - gripper.bottom = gripper.top + 3; - gripper.right = rcbtn.left - 3; - } - - pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), - ::GetSysColor(COLOR_BTNSHADOW)); - - gripper.OffsetRect(bHorz ? 3 : 0, bHorz ? 0 : 3); - - pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), - ::GetSysColor(COLOR_BTNSHADOW)); - - m_biHide.Paint(pDC); -} - -LRESULT CSizingControlBarG::OnNcHitTest(CPoint point) -{ - CRect rcBar; - GetWindowRect(rcBar); - - LRESULT nRet = baseCSizingControlBarG::OnNcHitTest(point); - if (nRet != HTCLIENT) - return nRet; - - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - ScreenToClient(&rcBar); - ScreenToClient(&point); - //mpc-hc custom code end - - CRect rc = m_biHide.GetRect(); - rc.OffsetRect(rcBar.TopLeft()); - if (rc.PtInRect(point)) - return HTCLOSE; - - return HTCLIENT; -} - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBarG implementation helpers - -void CSizingControlBarG::OnUpdateCmdUI(CFrameWnd* pTarget, - BOOL bDisableIfNoHndler) -{ - UNUSED_ALWAYS(bDisableIfNoHndler); - UNUSED_ALWAYS(pTarget); - - if (!HasGripper()) - return; - - BOOL bNeedPaint = FALSE; - - CPoint pt; - ::GetCursorPos(&pt); - BOOL bHit = (OnNcHitTest(pt) == HTCLOSE); - BOOL bLButtonDown = (::GetKeyState(VK_LBUTTON) < 0); - - BOOL bWasPushed = m_biHide.bPushed; - m_biHide.bPushed = bHit && bLButtonDown; - - BOOL bWasRaised = m_biHide.bRaised; - m_biHide.bRaised = bHit && !bLButtonDown; - - bNeedPaint |= (m_biHide.bPushed ^ bWasPushed) || - (m_biHide.bRaised ^ bWasRaised); - - if (bNeedPaint) - SendMessage(WM_NCPAINT); -} - -///////////////////////////////////////////////////////////////////////// -// CSCBButton - -CSCBButton::CSCBButton() -{ - bRaised = FALSE; - bPushed = FALSE; - dpiSize = CSize(11, 11); //mpc-hc addition to support dpi sizing -} - -void CSCBButton::Paint(CDC* pDC) -{ - CRect rc = GetRect(); - - if (bPushed) - pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNSHADOW), - ::GetSysColor(COLOR_BTNHIGHLIGHT)); - else - if (bRaised) - pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNHIGHLIGHT), - ::GetSysColor(COLOR_BTNSHADOW)); - - COLORREF clrOldTextColor = pDC->GetTextColor(); - pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT)); - int nPrevBkMode = pDC->SetBkMode(TRANSPARENT); - CFont font; - int ppi = pDC->GetDeviceCaps(LOGPIXELSX); - int pointsize = MulDiv(60, 96, ppi); // 6 points at 96 ppi - font.CreatePointFont(pointsize, _T("Marlett")); - CFont* oldfont = pDC->SelectObject(&font); - - //mpc-hc custom code start - // TextOut is affected by the layout so we need to account for that - DWORD dwLayout = pDC->GetLayout(); - pDC->TextOut(ptOrg.x + (dwLayout == LAYOUT_LTR ? 2 : -1), ptOrg.y + 2, CString(_T("r"))); // x-like - //mpc-hc custom code end - - pDC->SelectObject(oldfont); - pDC->SetBkMode(nPrevBkMode); - pDC->SetTextColor(clrOldTextColor); -} - -BOOL CSizingControlBarG::HasGripper() const -{ -#if defined(_SCB_MINIFRAME_CAPTION) || !defined(_SCB_REPLACE_MINIFRAME) - // if the miniframe has a caption, don't display the gripper - if (IsFloating()) - return FALSE; -#endif //_SCB_MINIFRAME_CAPTION - - return TRUE; +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBarG Version 2.45 +// +// Created: Jan 24, 1998 Last Modified: April 16, 2010 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com . +///////////////////////////////////////////////////////////////////////// + +// sizecbar.cpp : implementation file +// + +#include "stdafx.h" +#include "scbarg.h" + + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarG + +IMPLEMENT_DYNAMIC(CSizingControlBarG, baseCSizingControlBarG); + +CSizingControlBarG::CSizingControlBarG() +{ + m_cyGripper = 12; +} + +CSizingControlBarG::~CSizingControlBarG() +{ +} + +BEGIN_MESSAGE_MAP(CSizingControlBarG, baseCSizingControlBarG) + //{{AFX_MSG_MAP(CSizingControlBarG) + ON_WM_NCLBUTTONUP() + ON_WM_NCHITTEST() + //}}AFX_MSG_MAP + ON_MESSAGE(WM_SETTEXT, OnSetText) +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarG message handlers + +///////////////////////////////////////////////////////////////////////// +// Mouse Handling +// + +void CSizingControlBarG::OnNcLButtonUp(UINT nHitTest, CPoint point) +{ + if (nHitTest == HTCLOSE) + m_pDockSite->ShowControlBar(this, FALSE, FALSE); // hide + + baseCSizingControlBarG::OnNcLButtonUp(nHitTest, point); +} + +void CSizingControlBarG::NcCalcClient(LPRECT pRc, UINT nDockBarID) +{ + CRect rcBar(pRc); // save the bar rect + + // subtract edges + baseCSizingControlBarG::NcCalcClient(pRc, nDockBarID); + + if (!HasGripper()) + return; + + CRect rc(pRc); // the client rect as calculated by the base class + //mpc-hc custom code start + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ClientToScreen(rcBar); + GetParent()->ClientToScreen(rc); + //mpc-hc custom code end + + BOOL bHorz = (nDockBarID == AFX_IDW_DOCKBAR_TOP) || + (nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); + + if (bHorz) + rc.DeflateRect(m_cyGripper, 0, 0, 0); + else + rc.DeflateRect(0, m_cyGripper, 0, 0); + + // set position for the "x" (hide bar) button + CPoint ptOrgBtn; + if (bHorz) + ptOrgBtn = CPoint(rc.left - 13, rc.top); + else + ptOrgBtn = CPoint(rc.right - 12, rc.top - 13); + + m_biHide.Move(ptOrgBtn - rcBar.TopLeft()); + + //mpc-hc custom code start + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ScreenToClient(&rc); + //mpc-hc custom code end + + *pRc = rc; +} + +void CSizingControlBarG::NcPaintGripper(CDC* pDC, CRect rcClient) +{ + if (!HasGripper()) + return; + + // paints a simple "two raised lines" gripper + // override this if you want a more sophisticated gripper + CRect gripper = rcClient; + CRect rcbtn = m_biHide.GetRect(); + BOOL bHorz = IsHorzDocked(); + + gripper.DeflateRect(1, 1); + if (bHorz) + { // gripper at left + gripper.left -= m_cyGripper; + gripper.right = gripper.left + 3; + gripper.top = rcbtn.bottom + 3; + } + else + { // gripper at top + gripper.top -= m_cyGripper; + gripper.bottom = gripper.top + 3; + gripper.right = rcbtn.left - 3; + } + + pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), + ::GetSysColor(COLOR_BTNSHADOW)); + + gripper.OffsetRect(bHorz ? 3 : 0, bHorz ? 0 : 3); + + pDC->Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), + ::GetSysColor(COLOR_BTNSHADOW)); + + m_biHide.Paint(pDC); +} + +LRESULT CSizingControlBarG::OnNcHitTest(CPoint point) +{ + CRect rcBar; + GetWindowRect(rcBar); + + LRESULT nRet = baseCSizingControlBarG::OnNcHitTest(point); + if (nRet != HTCLIENT) + return nRet; + + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + ScreenToClient(&rcBar); + ScreenToClient(&point); + //mpc-hc custom code end + + CRect rc = m_biHide.GetRect(); + rc.OffsetRect(rcBar.TopLeft()); + if (rc.PtInRect(point)) + return HTCLOSE; + + return HTCLIENT; +} + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBarG implementation helpers + +void CSizingControlBarG::OnUpdateCmdUI(CFrameWnd* pTarget, + BOOL bDisableIfNoHndler) +{ + UNUSED_ALWAYS(bDisableIfNoHndler); + UNUSED_ALWAYS(pTarget); + + if (!HasGripper()) + return; + + BOOL bNeedPaint = FALSE; + + CPoint pt; + ::GetCursorPos(&pt); + BOOL bHit = (OnNcHitTest(pt) == HTCLOSE); + BOOL bLButtonDown = (::GetKeyState(VK_LBUTTON) < 0); + + BOOL bWasPushed = m_biHide.bPushed; + m_biHide.bPushed = bHit && bLButtonDown; + + BOOL bWasRaised = m_biHide.bRaised; + m_biHide.bRaised = bHit && !bLButtonDown; + + bNeedPaint |= (m_biHide.bPushed ^ bWasPushed) || + (m_biHide.bRaised ^ bWasRaised); + + if (bNeedPaint) + SendMessage(WM_NCPAINT); +} + +///////////////////////////////////////////////////////////////////////// +// CSCBButton + +CSCBButton::CSCBButton() +{ + bRaised = FALSE; + bPushed = FALSE; + dpiSize = CSize(11, 11); //mpc-hc addition to support dpi sizing +} + +void CSCBButton::Paint(CDC* pDC) +{ + CRect rc = GetRect(); + + if (bPushed) + pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNSHADOW), + ::GetSysColor(COLOR_BTNHIGHLIGHT)); + else + if (bRaised) + pDC->Draw3dRect(rc, ::GetSysColor(COLOR_BTNHIGHLIGHT), + ::GetSysColor(COLOR_BTNSHADOW)); + + COLORREF clrOldTextColor = pDC->GetTextColor(); + pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT)); + int nPrevBkMode = pDC->SetBkMode(TRANSPARENT); + CFont font; + int ppi = pDC->GetDeviceCaps(LOGPIXELSX); + int pointsize = MulDiv(60, 96, ppi); // 6 points at 96 ppi + font.CreatePointFont(pointsize, _T("Marlett")); + CFont* oldfont = pDC->SelectObject(&font); + + //mpc-hc custom code start + // TextOut is affected by the layout so we need to account for that + DWORD dwLayout = pDC->GetLayout(); + pDC->TextOut(ptOrg.x + (dwLayout == LAYOUT_LTR ? 2 : -1), ptOrg.y + 2, CString(_T("r"))); // x-like + //mpc-hc custom code end + + pDC->SelectObject(oldfont); + pDC->SetBkMode(nPrevBkMode); + pDC->SetTextColor(clrOldTextColor); +} + +BOOL CSizingControlBarG::HasGripper() const +{ +#if defined(_SCB_MINIFRAME_CAPTION) || !defined(_SCB_REPLACE_MINIFRAME) + // if the miniframe has a caption, don't display the gripper + if (IsFloating()) + return FALSE; +#endif //_SCB_MINIFRAME_CAPTION + + return TRUE; } \ No newline at end of file diff --git a/src/thirdparty/sizecbar/scbarg.h b/src/thirdparty/sizecbar/scbarg.h index 43900b8b3d8..2e880fe43ec 100644 --- a/src/thirdparty/sizecbar/scbarg.h +++ b/src/thirdparty/sizecbar/scbarg.h @@ -1,118 +1,118 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBarG Version 2.45 -// -// Created: Jan 24, 1998 Last Modified: April 16, 2010 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com . -///////////////////////////////////////////////////////////////////////// - -#if !defined(__SCBARG_H__) -#define __SCBARG_H__ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 - -#include "sizecbar.h" - -///////////////////////////////////////////////////////////////////////// -// CSCBButton (button info) helper class - -class CSCBButton -{ -public: - CSCBButton(); - - void Move(CPoint ptTo) {ptOrg = ptTo; }; - //mpc-hc changes to allow DPI changes - //CRect GetRect() { return CRect(ptOrg, CSize(11, 11)); }; - CRect GetRect() { return CRect(ptOrg, dpiSize); }; - void SetDpiSize(CSize s) { dpiSize = s; }; - - CSize dpiSize; - //end mpc-hc - - void Paint(CDC* pDC); - - - BOOL bPushed; - BOOL bRaised; - -protected: - CPoint ptOrg; -}; - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar control bar - -#ifndef baseCSizingControlBarG -#define baseCSizingControlBarG CSizingControlBar -#endif - -class CSizingControlBarG : public baseCSizingControlBarG -{ - DECLARE_DYNAMIC(CSizingControlBarG); - -// Construction -public: - CSizingControlBarG(); - -// Attributes -public: - virtual BOOL HasGripper() const; - -// Operations -public: - -// Overridables - virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); - -// Overrides -public: - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CSizingControlBarG) - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CSizingControlBarG(); - -protected: - // implementation helpers - virtual void NcPaintGripper(CDC* pDC, CRect rcClient); - virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); - -protected: - int m_cyGripper; - - CSCBButton m_biHide; - -// Generated message map functions -protected: - //{{AFX_MSG(CSizingControlBarG) - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg void OnNcLButtonUp(UINT nHitTest, CPoint point); - //}}AFX_MSG - - DECLARE_MESSAGE_MAP() -}; - -#endif // !defined(__SCBARG_H__) - +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBarG Version 2.45 +// +// Created: Jan 24, 1998 Last Modified: April 16, 2010 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com . +///////////////////////////////////////////////////////////////////////// + +#if !defined(__SCBARG_H__) +#define __SCBARG_H__ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#include "sizecbar.h" + +///////////////////////////////////////////////////////////////////////// +// CSCBButton (button info) helper class + +class CSCBButton +{ +public: + CSCBButton(); + + void Move(CPoint ptTo) {ptOrg = ptTo; }; + //mpc-hc changes to allow DPI changes + //CRect GetRect() { return CRect(ptOrg, CSize(11, 11)); }; + CRect GetRect() { return CRect(ptOrg, dpiSize); }; + void SetDpiSize(CSize s) { dpiSize = s; }; + + CSize dpiSize; + //end mpc-hc + + void Paint(CDC* pDC); + + + BOOL bPushed; + BOOL bRaised; + +protected: + CPoint ptOrg; +}; + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar control bar + +#ifndef baseCSizingControlBarG +#define baseCSizingControlBarG CSizingControlBar +#endif + +class CSizingControlBarG : public baseCSizingControlBarG +{ + DECLARE_DYNAMIC(CSizingControlBarG); + +// Construction +public: + CSizingControlBarG(); + +// Attributes +public: + virtual BOOL HasGripper() const; + +// Operations +public: + +// Overridables + virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); + +// Overrides +public: + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSizingControlBarG) + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CSizingControlBarG(); + +protected: + // implementation helpers + virtual void NcPaintGripper(CDC* pDC, CRect rcClient); + virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); + +protected: + int m_cyGripper; + + CSCBButton m_biHide; + +// Generated message map functions +protected: + //{{AFX_MSG(CSizingControlBarG) + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg void OnNcLButtonUp(UINT nHitTest, CPoint point); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +#endif // !defined(__SCBARG_H__) + diff --git a/src/thirdparty/sizecbar/sizecbar.cpp b/src/thirdparty/sizecbar/sizecbar.cpp index fc95004a8e4..8ad2d64733a 100644 --- a/src/thirdparty/sizecbar/sizecbar.cpp +++ b/src/thirdparty/sizecbar/sizecbar.cpp @@ -1,1463 +1,1463 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBar Version 2.45 -// -// Created: Jan 24, 1998 Last Modified: April 16, 2010 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com . -// -// The sources and a short version of the docs are also available at -// www.codeproject.com . Look for a "Docking Windows" section and check -// the version to be sure you get the latest one ;) -// -// Hint: These classes are intended to be used as base classes. Do not -// simply add your code to these files - instead create a new class -// derived from one of CSizingControlBarXX classes and put there what -// you need. See CMyBar classes in the demo projects for examples. -// Modify this file only to fix bugs, and don't forget to send me a copy. -///////////////////////////////////////////////////////////////////////// -// Acknowledgements: -// o Thanks to Harlan R. Seymour for his continuous support during -// development of this code. -// o Thanks to Dundas Software and Formatta Corporation for the -// opportunities to test this code on real-life applications. -// o Some ideas for the gripper came from the CToolBarEx flat toolbar -// by Joerg Koenig. Thanks, Joerg! -// o Thanks to Robert Wolpow for the code on which CDockContext based -// dialgonal resizing is based. -// o Thanks to the following people for various bug fixes and/or -// enhancements: Chris Maunder, Jakawan Ratiwanich, Udo Schaefer, -// Anatoly Ivasyuk, Peter Hauptmann, DJ(?), Pat Kusbel, Aleksey -// Malyshev, and many others who used this code and sent feedback. -///////////////////////////////////////////////////////////////////////// - -// sizecbar.cpp : implementation file -// - -#include "stdafx.h" -#include "sizecbar.h" - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar - -IMPLEMENT_DYNAMIC(CSizingControlBar, baseCSizingControlBar); - -CSizingControlBar::CSizingControlBar() -{ - m_szMinHorz = CSize(33, 32); - m_szMinVert = CSize(33, 32); - m_szMinFloat = CSize(37, 32); - m_szHorz = CSize(200, 200); - m_szVert = CSize(200, 200); - m_szFloat = CSize(200, 200); - m_bTracking = FALSE; - m_bKeepSize = FALSE; - m_bParentSizing = FALSE; - m_cxEdge = 5; - m_bDragShowContent = FALSE; - m_nDockBarID = 0; - m_dwSCBStyle = 0; - m_htEdge = 0; - m_nTrackPosMin = 0; - m_nTrackPosMax = 0; - m_nTrackPosOld = 0; - m_nTrackEdgeOfs = 0; - m_bFixedFloat = FALSE; -} - -CSizingControlBar::~CSizingControlBar() -{ -} - -BEGIN_MESSAGE_MAP(CSizingControlBar, baseCSizingControlBar) - //{{AFX_MSG_MAP(CSizingControlBar) - ON_WM_CREATE() - ON_WM_PAINT() - ON_WM_NCPAINT() - ON_WM_NCCALCSIZE() - ON_WM_WINDOWPOSCHANGING() - ON_WM_CAPTURECHANGED() - ON_WM_SETTINGCHANGE() - ON_WM_LBUTTONUP() - ON_WM_MOUSEMOVE() - ON_WM_NCLBUTTONDOWN() - ON_WM_LBUTTONDOWN() - ON_WM_LBUTTONDBLCLK() - ON_WM_RBUTTONDOWN() - ON_WM_NCMOUSEMOVE() - ON_WM_NCHITTEST() - ON_WM_CLOSE() - ON_WM_SIZE() - //}}AFX_MSG_MAP - ON_MESSAGE(WM_SETTEXT, OnSetText) -END_MESSAGE_MAP() - -// old creation method, still here for compatibility reasons -BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, - CSize sizeDefault, BOOL bHasGripper, - UINT nID, DWORD dwStyle) -{ - UNUSED_ALWAYS(bHasGripper); - - m_szHorz = m_szVert = m_szFloat = sizeDefault; - return Create(lpszWindowName, pParentWnd, nID, dwStyle); -} - -// preffered creation method -BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, - CWnd* pParentWnd, UINT nID, - DWORD dwStyle) -{ - // must have a parent - ASSERT_VALID(pParentWnd); - // cannot be both fixed and dynamic - // (CBRS_SIZE_DYNAMIC is used for resizng when floating) - ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && - (dwStyle & CBRS_SIZE_DYNAMIC))); - - m_dwStyle = dwStyle & CBRS_ALL; // save the control bar styles - - // register and create the window - skip CControlBar::Create() - CString wndclass = ::AfxRegisterWndClass(CS_DBLCLKS, - ::LoadCursor(NULL, IDC_ARROW), - ::GetSysColorBrush(COLOR_BTNFACE), 0); - - dwStyle &= ~CBRS_ALL; // keep only the generic window styles - dwStyle |= WS_CLIPCHILDREN; // prevents flashing - if (!CWnd::Create(wndclass, lpszWindowName, dwStyle, - CRect(0, 0, 0, 0), pParentWnd, nID)) - return FALSE; - - return TRUE; -} - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar operations -#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) -void CSizingControlBar::EnableDocking(DWORD dwDockStyle) -{ - // must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only - ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI)) == 0); - // cannot have the CBRS_FLOAT_MULTI style - ASSERT((dwDockStyle & CBRS_FLOAT_MULTI) == 0); - // the bar must have CBRS_SIZE_DYNAMIC style - ASSERT((m_dwStyle & CBRS_SIZE_DYNAMIC) != 0); - - m_dwDockStyle = dwDockStyle; - if (m_pDockContext == NULL) - m_pDockContext = new CSCBDockContext(this); - - // permanently wire the bar's owner to its current parent - if (m_hWndOwner == NULL) - m_hWndOwner = ::GetParent(m_hWnd); -} -#endif - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar message handlers - -int CSizingControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct) -{ - if (baseCSizingControlBar::OnCreate(lpCreateStruct) == -1) - return -1; - - // query SPI_GETDRAGFULLWINDOWS system parameter - // OnSettingChange() will update m_bDragShowContent - m_bDragShowContent = FALSE; - ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, - &m_bDragShowContent, 0); - - // uncomment this line if you want raised borders -// m_dwSCBStyle |= SCBS_SHOWEDGES; - - return 0; -} - - -LRESULT CSizingControlBar::OnSetText(WPARAM wParam, LPARAM lParam) -{ - UNUSED_ALWAYS(wParam); - - LRESULT lResult = CWnd::Default(); - - if (IsFloating() && - GetParentFrame()->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd))) - { - m_pDockBar->SetWindowText((LPCTSTR) lParam); // update dockbar - GetParentFrame()->DelayRecalcLayout(); // refresh miniframe - } - - return lResult; -} - -const BOOL CSizingControlBar::IsFloating() const -{ - return !IsHorzDocked() && !IsVertDocked(); -} - -const BOOL CSizingControlBar::IsHorzDocked() const -{ - return (m_nDockBarID == AFX_IDW_DOCKBAR_TOP || - m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); -} - -const BOOL CSizingControlBar::IsVertDocked() const -{ - return (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT || - m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT); -} - -const BOOL CSizingControlBar::IsSideTracking() const -{ - // don't call this when not tracking - ASSERT(m_bTracking && !IsFloating()); - - return (m_htEdge == HTLEFT || m_htEdge == HTRIGHT) ? - IsHorzDocked() : IsVertDocked(); -} - -CSize CSizingControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) -{ - if (bStretch) // the bar is stretched (is not the child of a dockbar) - if (bHorz) - return CSize(32767, m_szHorz.cy); - else - return CSize(m_szVert.cx, 32767); - - // dirty cast - we need access to protected CDockBar members - CSCBDockBar* pDockBar = static_cast (m_pDockBar); - - // force imediate RecalcDelayShow() for all sizing bars on the row - // with delayShow/delayHide flags set to avoid IsVisible() problems - CSCBArray arrSCBars; - GetRowSizingBars(arrSCBars); - AFX_SIZEPARENTPARAMS layout; - layout.hDWP = pDockBar->m_bLayoutQuery ? - NULL : ::BeginDeferWindowPos(arrSCBars.GetSize()); - for (int i = 0; i < arrSCBars.GetSize(); i++) - if (arrSCBars[i]->m_nStateFlags & (delayHide|delayShow)) - arrSCBars[i]->RecalcDelayShow(&layout); - if (layout.hDWP != NULL) - ::EndDeferWindowPos(layout.hDWP); - - // get available length - CRect rc = pDockBar->m_rectLayout; - if (rc.IsRectEmpty()) - m_pDockSite->GetClientRect(&rc); - int nLengthTotal = bHorz ? rc.Width() + 2 : rc.Height() - 2; - - if (IsVisible() && !IsFloating() && - m_bParentSizing && arrSCBars[0] == this) - if (NegotiateSpace(nLengthTotal, (bHorz != FALSE))) - AlignControlBars(); - - m_bParentSizing = FALSE; - - if (bHorz) - return CSize(max(m_szMinHorz.cx, m_szHorz.cx), - max(m_szMinHorz.cy, m_szHorz.cy)); - - return CSize(max(m_szMinVert.cx, m_szVert.cx), - max(m_szMinVert.cy, m_szVert.cy)); -} - -CSize CSizingControlBar::CalcDynamicLayout(int nLength, DWORD dwMode) -{ - if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) // docked ? - { - if (nLength == -1) - m_bParentSizing = TRUE; - - return baseCSizingControlBar::CalcDynamicLayout(nLength, dwMode); - } - - if (dwMode & LM_MRUWIDTH) return m_szFloat; - if (dwMode & LM_COMMIT) return m_szFloat; // already committed - -#ifndef _SCB_REPLACE_MINIFRAME - // check for dialgonal resizing hit test - int nHitTest = m_pDockContext->m_nHitTest; - if (IsFloating() && - (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT || - nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT)) - { - CPoint ptCursor; - ::GetCursorPos(&ptCursor); - - CRect rFrame, rBar; - GetParentFrame()->GetWindowRect(&rFrame); - GetWindowRect(&rBar); - - if (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT) - { - m_szFloat.cx = rFrame.left + rBar.Width() - ptCursor.x; - m_pDockContext->m_rectFrameDragHorz.left = - min(ptCursor.x, rFrame.left + rBar.Width() - m_szMinFloat.cx); - } - - if (nHitTest == HTTOPLEFT || nHitTest == HTTOPRIGHT) - { - m_szFloat.cy = rFrame.top + rBar.Height() - ptCursor.y; - m_pDockContext->m_rectFrameDragHorz.top = - min(ptCursor.y, rFrame.top + rBar.Height() - m_szMinFloat.cy); - } - - if (nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT) - m_szFloat.cx = rBar.Width() + ptCursor.x - rFrame.right; - - if (nHitTest == HTBOTTOMLEFT || nHitTest == HTBOTTOMRIGHT) - m_szFloat.cy = rBar.Height() + ptCursor.y - rFrame.bottom; - } - else -#endif //_SCB_REPLACE_MINIFRAME - ((dwMode & LM_LENGTHY) ? m_szFloat.cy : m_szFloat.cx) = nLength; - - m_szFloat.cx = max(m_szFloat.cx, m_szMinFloat.cx); - m_szFloat.cy = max(m_szFloat.cy, m_szMinFloat.cy); - - return m_szFloat; -} - -void CSizingControlBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) -{ - // force non-client recalc if moved or resized - lpwndpos->flags |= SWP_FRAMECHANGED; - - baseCSizingControlBar::OnWindowPosChanging(lpwndpos); - - // find on which side are we docked - m_nDockBarID = GetParent()->GetDlgCtrlID(); - - if (!IsFloating()) - if (lpwndpos->flags & SWP_SHOWWINDOW) - m_bKeepSize = TRUE; -} - -///////////////////////////////////////////////////////////////////////// -// Mouse Handling -// -void CSizingControlBar::OnLButtonDown(UINT nFlags, CPoint point) -{ - if (m_pDockBar != NULL) - { - // start the drag - ASSERT(m_pDockContext != NULL); - ClientToScreen(&point); - m_pDockContext->StartDrag(point); - } - else - CWnd::OnLButtonDown(nFlags, point); -} - -void CSizingControlBar::OnLButtonDblClk(UINT nFlags, CPoint point) -{ - if (m_pDockBar != NULL) - { - // toggle docking - ASSERT(m_pDockContext != NULL); - m_pDockContext->ToggleDocking(); - } - else - CWnd::OnLButtonDblClk(nFlags, point); -} - -void CSizingControlBar::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - UNUSED_ALWAYS(point); - - if (m_bTracking || IsFloating()) - return; - - if ((nHitTest >= HTSIZEFIRST) && (nHitTest <= HTSIZELAST)) - StartTracking(nHitTest, point); // sizing edge hit -} - -void CSizingControlBar::OnLButtonUp(UINT nFlags, CPoint point) -{ - if (m_bTracking) - StopTracking(); - - baseCSizingControlBar::OnLButtonUp(nFlags, point); -} - -void CSizingControlBar::OnRButtonDown(UINT nFlags, CPoint point) -{ - if (m_bTracking) - StopTracking(); - - baseCSizingControlBar::OnRButtonDown(nFlags, point); -} - -void CSizingControlBar::OnMouseMove(UINT nFlags, CPoint point) -{ - if (m_bTracking) - { - CPoint ptScreen = point; - ClientToScreen(&ptScreen); - - //mpc-hc custom code start - // Switch to parent window client coordinates to account for possible RTL layout - CPoint ptParentClient = ptScreen; - GetParentFrame()->ScreenToClient(&ptParentClient); - OnTrackUpdateSize(ptParentClient); - //mpc-hc custom code end - } - - baseCSizingControlBar::OnMouseMove(nFlags, point); -} - -void CSizingControlBar::OnCaptureChanged(CWnd *pWnd) -{ - if (m_bTracking && (pWnd != this)) - StopTracking(); - - baseCSizingControlBar::OnCaptureChanged(pWnd); -} - -void CSizingControlBar::OnNcCalcSize(BOOL bCalcValidRects, - NCCALCSIZE_PARAMS FAR* lpncsp) -{ - UNUSED_ALWAYS(bCalcValidRects); - -#ifndef _SCB_REPLACE_MINIFRAME - // Enable diagonal resizing for floating miniframe - if (IsFloating()) - { - CFrameWnd* pFrame = GetParentFrame(); - if (pFrame != NULL && - pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd))) - { -//mpc-hc custom code start - LONG_PTR dwStyle = ::GetWindowLongPtr(pFrame->m_hWnd, GWL_STYLE); -//mpc-hc custom code end - if ((dwStyle & MFS_4THICKFRAME) != 0) - { - pFrame->ModifyStyle(MFS_4THICKFRAME, 0); // clear - GetParent()->ModifyStyle(0, WS_CLIPCHILDREN); - } - } - } -#endif _SCB_REPLACE_MINIFRAME - - // compute the the client area - m_dwSCBStyle &= ~SCBS_EDGEALL; - - // add resizing edges between bars on the same row - if (!IsFloating() && m_pDockBar != NULL) - { - CSCBArray arrSCBars; - int nThis; - GetRowSizingBars(arrSCBars, nThis); - - BOOL bHorz = IsHorzDocked(); - if (nThis > 0) - m_dwSCBStyle |= bHorz ? SCBS_EDGELEFT : SCBS_EDGETOP; - - if (nThis < arrSCBars.GetUpperBound()) - m_dwSCBStyle |= bHorz ? SCBS_EDGERIGHT : SCBS_EDGEBOTTOM; - } - - NcCalcClient(&lpncsp->rgrc[0], m_nDockBarID); -} - -void CSizingControlBar::NcCalcClient(LPRECT pRc, UINT nDockBarID) -{ - CRect rc(pRc); - //mpc-hc custom code start - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ClientToScreen(&rc); - //mpc-hc custom code end - - rc.DeflateRect(3, 5, 3, 3); - if (nDockBarID != AFX_IDW_DOCKBAR_FLOAT) - rc.DeflateRect(2, 0, 2, 2); - - switch(nDockBarID) - { - case AFX_IDW_DOCKBAR_TOP: - m_dwSCBStyle |= SCBS_EDGEBOTTOM; - break; - case AFX_IDW_DOCKBAR_BOTTOM: - m_dwSCBStyle |= SCBS_EDGETOP; - break; - case AFX_IDW_DOCKBAR_LEFT: - m_dwSCBStyle |= SCBS_EDGERIGHT; - break; - case AFX_IDW_DOCKBAR_RIGHT: - m_dwSCBStyle |= SCBS_EDGELEFT; - break; - } - - // make room for edges only if they will be painted - if (m_dwSCBStyle & SCBS_SHOWEDGES) - rc.DeflateRect( - (m_dwSCBStyle & SCBS_EDGELEFT) ? m_cxEdge : 0, - (m_dwSCBStyle & SCBS_EDGETOP) ? m_cxEdge : 0, - (m_dwSCBStyle & SCBS_EDGERIGHT) ? m_cxEdge : 0, - (m_dwSCBStyle & SCBS_EDGEBOTTOM) ? m_cxEdge : 0); - - //mpc-hc custom code start - // Work in screen coordinates before converting back to - // client coordinates to account for possible RTL layout - GetParent()->ScreenToClient(&rc); - //mpc-hc custom code end - - *pRc = rc; -} - -void CSizingControlBar::OnNcPaint() -{ - // get window DC that is clipped to the non-client area - CWindowDC dc(this); // the HDC will be released by the destructor - - CRect rcClient, rcBar; - GetClientRect(rcClient); - //mpc-hc custom code start - //ClientToScreen(rcClient); - //mpc-hc custom code end - GetWindowRect(rcBar); - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - ScreenToClient(rcBar); - //mpc-hc custom code end - rcClient.OffsetRect(-rcBar.TopLeft()); - rcBar.OffsetRect(-rcBar.TopLeft()); - - CDC mdc; - mdc.CreateCompatibleDC(&dc); - - CBitmap bm; - bm.CreateCompatibleBitmap(&dc, rcBar.Width(), rcBar.Height()); - CBitmap* pOldBm = mdc.SelectObject(&bm); - - // draw borders in non-client area - CRect rcDraw = rcBar; - DrawBorders(&mdc, rcDraw); - - // erase the NC background -//mpc-hc custom code start - mpc_fillNcBG(&mdc, rcDraw); -//mpc-hc custom code end - - if (m_dwSCBStyle & SCBS_SHOWEDGES) - { - CRect rcEdge; // paint the sizing edges - for (int i = 0; i < 4; i++) - if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge)) - mdc.Draw3dRect(rcEdge, ::GetSysColor(COLOR_BTNHIGHLIGHT), - ::GetSysColor(COLOR_BTNSHADOW)); - } - - NcPaintGripper(&mdc, rcClient); - - // client area is not our bussiness :) - dc.IntersectClipRect(rcBar); - dc.ExcludeClipRect(rcClient); - - dc.BitBlt(0, 0, rcBar.Width(), rcBar.Height(), &mdc, 0, 0, SRCCOPY); - - mdc.SelectObject(pOldBm); - bm.DeleteObject(); - mdc.DeleteDC(); -} - -void CSizingControlBar::NcPaintGripper(CDC* pDC, CRect rcClient) -{ - UNUSED_ALWAYS(pDC); - UNUSED_ALWAYS(rcClient); -} - -void CSizingControlBar::OnPaint() -{ - // overridden to skip border painting based on clientrect - CPaintDC dc(this); -} - -LRESULT CSizingControlBar::OnNcHitTest(CPoint point) -{ - CRect rcBar, rcEdge; - GetWindowRect(rcBar); - - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - ScreenToClient(&rcBar); - ScreenToClient(&point); - //mpc-hc custom code end - - if (!IsFloating()) - for (int i = 0; i < 4; i++) - if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge)) - if (rcEdge.PtInRect(point)) - return GetEdgeHTCode(i); - - return HTCLIENT; -} - -void CSizingControlBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) -{ - baseCSizingControlBar::OnSettingChange(uFlags, lpszSection); - - m_bDragShowContent = FALSE; - ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, - &m_bDragShowContent, 0); // update -} - -void CSizingControlBar::OnSize(UINT nType, int cx, int cy) -{ - UNUSED_ALWAYS(nType); - - if ((m_dwSCBStyle & SCBS_SIZECHILD) != 0) - { - // automatic child resizing - only one child is allowed - CWnd* pWnd = GetWindow(GW_CHILD); - if (pWnd != NULL) - { - pWnd->MoveWindow(0, 0, cx, cy); - ASSERT(pWnd->GetWindow(GW_HWNDNEXT) == NULL); - } - } -} - -void CSizingControlBar::OnClose() -{ - // do nothing: protection against accidentally destruction by the - // child control (i.e. if user hits Esc in a child editctrl) -} - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar implementation helpers - -void CSizingControlBar::StartTracking(UINT nHitTest, CPoint point) -{ - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - GetParentFrame()->ScreenToClient(&point); - //mpc-hc custom code end - - SetCapture(); - - // make sure no updates are pending - if (!m_bDragShowContent) - RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); - - m_htEdge = nHitTest; - m_bTracking = TRUE; - - BOOL bHorz = IsHorzDocked(); - BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; - - m_nTrackPosOld = bHorzTracking ? point.x : point.y; - - CRect rcBar, rcEdge; - GetWindowRect(rcBar); - //mpc-hc custom code start - // Convert to client coordinates to account for possible RTL layout - GetParent()->ScreenToClient(&rcBar); - //mpc-hc custom code end - GetEdgeRect(rcBar, m_htEdge, rcEdge); - m_nTrackEdgeOfs = m_nTrackPosOld - - (bHorzTracking ? rcEdge.CenterPoint().x : rcEdge.CenterPoint().y); - - CSCBArray arrSCBars; - int nThis; - GetRowSizingBars(arrSCBars, nThis); - - m_nTrackPosMin = m_nTrackPosMax = m_nTrackPosOld; - if (!IsSideTracking()) - { - // calc minwidth as the max minwidth of the sizing bars on row - int nMinWidth = bHorz ? m_szMinHorz.cy : m_szMinVert.cx; - for (int i = 0; i < arrSCBars.GetSize(); i++) - nMinWidth = max(nMinWidth, bHorz ? - arrSCBars[i]->m_szMinHorz.cy : - arrSCBars[i]->m_szMinVert.cx); - int nExcessWidth = (bHorz ? m_szHorz.cy : m_szVert.cx) - nMinWidth; - - // the control bar cannot grow with more than the width of - // remaining client area of the mainframe - CRect rcT; - m_pDockSite->RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST, - reposQuery, &rcT, NULL, TRUE); - int nMaxWidth = bHorz ? rcT.Height() - 2 : rcT.Width() - 2; - - BOOL bTopOrLeft = m_htEdge == HTTOP || m_htEdge == HTLEFT; - - m_nTrackPosMin -= bTopOrLeft ? nMaxWidth : nExcessWidth; - m_nTrackPosMax += bTopOrLeft ? nExcessWidth : nMaxWidth; - } - else - { - // side tracking: - // max size is the actual size plus the amount the other - // sizing bars can be decreased until they reach their minsize - if (m_htEdge == HTBOTTOM || m_htEdge == HTRIGHT) - nThis++; - - for (int i = 0; i < arrSCBars.GetSize(); i++) - { - CSizingControlBar* pBar = arrSCBars[i]; - - int nExcessWidth = bHorz ? - pBar->m_szHorz.cx - pBar->m_szMinHorz.cx : - pBar->m_szVert.cy - pBar->m_szMinVert.cy; - - if (i < nThis) - m_nTrackPosMin -= nExcessWidth; - else - m_nTrackPosMax += nExcessWidth; - } - } - - OnTrackInvertTracker(); // draw tracker -} - -void CSizingControlBar::StopTracking() -{ - OnTrackInvertTracker(); // erase tracker - - m_bTracking = FALSE; - ReleaseCapture(); - - m_pDockSite->DelayRecalcLayout(); -} - -void CSizingControlBar::OnTrackUpdateSize(CPoint& point) -{ - ASSERT(!IsFloating()); - - BOOL bHorzTrack = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; - - int nTrackPos = bHorzTrack ? point.x : point.y; - nTrackPos = max(m_nTrackPosMin, min(m_nTrackPosMax, nTrackPos)); - - int nDelta = nTrackPos - m_nTrackPosOld; - - if (nDelta == 0) - return; // no pos change - - OnTrackInvertTracker(); // erase tracker - - m_nTrackPosOld = nTrackPos; - - BOOL bHorz = IsHorzDocked(); - - CSize sizeNew = bHorz ? m_szHorz : m_szVert; - switch (m_htEdge) - { - case HTLEFT: sizeNew -= CSize(nDelta, 0); break; - case HTTOP: sizeNew -= CSize(0, nDelta); break; - case HTRIGHT: sizeNew += CSize(nDelta, 0); break; - case HTBOTTOM: sizeNew += CSize(0, nDelta); break; - } - - CSCBArray arrSCBars; - int nThis; - GetRowSizingBars(arrSCBars, nThis); - - if (!IsSideTracking()) - for (int i = 0; i < arrSCBars.GetSize(); i++) - { - CSizingControlBar* pBar = arrSCBars[i]; - // make same width (or height) - (bHorz ? pBar->m_szHorz.cy : pBar->m_szVert.cx) = - bHorz ? sizeNew.cy : sizeNew.cx; - } - else - { - int nGrowingBar = nThis; - BOOL bBefore = m_htEdge == HTTOP || m_htEdge == HTLEFT; - if (bBefore && nDelta > 0) - nGrowingBar--; - if (!bBefore && nDelta < 0) - nGrowingBar++; - if (nGrowingBar != nThis) - bBefore = !bBefore; - - // nGrowing is growing - nDelta = abs(nDelta); - CSizingControlBar* pBar = arrSCBars[nGrowingBar]; - (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta; - - // the others are shrinking - int nFirst = bBefore ? nGrowingBar - 1 : nGrowingBar + 1; - int nLimit = bBefore ? -1 : arrSCBars.GetSize(); - - for (int i = nFirst; nDelta != 0 && i != nLimit; i += (bBefore ? -1 : 1)) - { - CSizingControlBar* pBar = arrSCBars[i]; - - int nDeltaT = min(nDelta, - (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) - - (bHorz ? pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy)); - - (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) -= nDeltaT; - nDelta -= nDeltaT; - } - } - - OnTrackInvertTracker(); // redraw tracker at new pos - - if (m_bDragShowContent) - m_pDockSite->DelayRecalcLayout(); -} - -void CSizingControlBar::OnTrackInvertTracker() -{ - ASSERT(m_bTracking); - - if (m_bDragShowContent) - return; // don't show tracker if DragFullWindows is on - - BOOL bHorz = IsHorzDocked(); - CRect rc, rcBar, rcDock, rcFrame; - GetWindowRect(rcBar); - m_pDockBar->GetWindowRect(rcDock); - m_pDockSite->GetWindowRect(rcFrame); - VERIFY(GetEdgeRect(rcBar, m_htEdge, rc)); - if (!IsSideTracking()) - rc = bHorz ? - CRect(rcDock.left + 1, rc.top, rcDock.right - 1, rc.bottom) : - CRect(rc.left, rcDock.top + 1, rc.right, rcDock.bottom - 1); - - BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; - int nOfs = m_nTrackPosOld - m_nTrackEdgeOfs; - nOfs -= bHorzTracking ? rc.CenterPoint().x : rc.CenterPoint().y; - rc.OffsetRect(bHorzTracking ? nOfs : 0, bHorzTracking ? 0 : nOfs); - rc.OffsetRect(-rcFrame.TopLeft()); - - CDC *pDC = m_pDockSite->GetDCEx(NULL, - DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); - CBrush* pBrush = CDC::GetHalftoneBrush(); - CBrush* pBrushOld = pDC->SelectObject(pBrush); - - pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATINVERT); - - pDC->SelectObject(pBrushOld); - m_pDockSite->ReleaseDC(pDC); -} - -BOOL CSizingControlBar::GetEdgeRect(CRect rcWnd, UINT nHitTest, - CRect& rcEdge) -{ - rcEdge = rcWnd; - if (m_dwSCBStyle & SCBS_SHOWEDGES) - rcEdge.DeflateRect(1, 1); - BOOL bHorz = IsHorzDocked(); - - switch (nHitTest) - { - case HTLEFT: - if (!(m_dwSCBStyle & SCBS_EDGELEFT)) return FALSE; - rcEdge.right = rcEdge.left + m_cxEdge; - rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0); - break; - case HTTOP: - if (!(m_dwSCBStyle & SCBS_EDGETOP)) return FALSE; - rcEdge.bottom = rcEdge.top + m_cxEdge; - rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0); - break; - case HTRIGHT: - if (!(m_dwSCBStyle & SCBS_EDGERIGHT)) return FALSE; - rcEdge.left = rcEdge.right - m_cxEdge; - rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0); - break; - case HTBOTTOM: - if (!(m_dwSCBStyle & SCBS_EDGEBOTTOM)) return FALSE; - rcEdge.top = rcEdge.bottom - m_cxEdge; - rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0); - break; - default: - ASSERT(FALSE); // invalid hit test code - } - return TRUE; -} - -UINT CSizingControlBar::GetEdgeHTCode(int nEdge) -{ - if (nEdge == 0) return HTLEFT; - if (nEdge == 1) return HTTOP; - if (nEdge == 2) return HTRIGHT; - if (nEdge == 3) return HTBOTTOM; - ASSERT(FALSE); // invalid edge code - return HTNOWHERE; -} - -void CSizingControlBar::GetRowInfo(int& nFirst, int& nLast, int& nThis) -{ - ASSERT_VALID(m_pDockBar); // verify bounds - - nThis = m_pDockBar->FindBar(this); - ASSERT(nThis != -1); - - int i, nBars = m_pDockBar->m_arrBars.GetSize(); - - // find the first and the last bar in row - for (nFirst = -1, i = nThis - 1; i >= 0 && nFirst == -1; i--) - if (m_pDockBar->m_arrBars[i] == NULL) - nFirst = i + 1; - for (nLast = -1, i = nThis + 1; i < nBars && nLast == -1; i++) - if (m_pDockBar->m_arrBars[i] == NULL) - nLast = i - 1; - - ASSERT((nLast != -1) && (nFirst != -1)); -} - -void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars) -{ - int nThis; // dummy - GetRowSizingBars(arrSCBars, nThis); -} - -void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars, int& nThis) -{ - arrSCBars.RemoveAll(); - - int nFirstT, nLastT, nThisT; - GetRowInfo(nFirstT, nLastT, nThisT); - - nThis = -1; - for (int i = nFirstT; i <= nLastT; i++) - { - CSizingControlBar* pBar = static_cast (m_pDockBar->m_arrBars[i]); - if (HIWORD(pBar) == 0) continue; // placeholder - if (!pBar->IsVisible()) continue; - if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - { - if (pBar == this) - nThis = arrSCBars.GetSize(); - - arrSCBars.Add(pBar); - } - } -} - -BOOL CSizingControlBar::NegotiateSpace(int nLengthTotal, BOOL bHorz) -{ - ASSERT(bHorz == IsHorzDocked()); - - int nFirst, nLast, nThis; - GetRowInfo(nFirst, nLast, nThis); - - int nLengthAvail = nLengthTotal; - int nLengthActual = 0; - int nLengthMin = 2; - int nWidthMax = 0; - CSizingControlBar* pBar; - - int i; - for (i = nFirst; i <= nLast; i++) - { - pBar = static_cast (m_pDockBar->m_arrBars[i]); - if (HIWORD(pBar) == 0) continue; // placeholder - if (!pBar->IsVisible()) continue; - BOOL bIsSizingBar = - pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar)); - - int nLengthBar; // minimum length of the bar - if (bIsSizingBar) - nLengthBar = bHorz ? pBar->m_szMinHorz.cx - 2 : - pBar->m_szMinVert.cy - 2; - else - { - CRect rcBar; - pBar->GetWindowRect(&rcBar); - nLengthBar = bHorz ? rcBar.Width() - 2 : rcBar.Height() - 2; - } - - nLengthMin += nLengthBar; - if (nLengthMin > nLengthTotal) - { - // split the row after fixed bar - if (i < nThis) - { - m_pDockBar->m_arrBars.InsertAt(i + 1, - (CControlBar*) NULL); - return FALSE; - } - - // only this sizebar remains on the row, adjust it to minsize - if (i == nThis) - { - if (bHorz) - m_szHorz.cx = m_szMinHorz.cx; - else - m_szVert.cy = m_szMinVert.cy; - - return TRUE; // the dockbar will split the row for us - } - - // we have enough bars - go negotiate with them - m_pDockBar->m_arrBars.InsertAt(i, (CControlBar*) NULL); - nLast = i - 1; - break; - } - - if (bIsSizingBar) - { - nLengthActual += bHorz ? pBar->m_szHorz.cx - 2 : - pBar->m_szVert.cy - 2; - nWidthMax = max(nWidthMax, bHorz ? pBar->m_szHorz.cy : - pBar->m_szVert.cx); - } - else - nLengthAvail -= nLengthBar; - } - - CSCBArray arrSCBars; - GetRowSizingBars(arrSCBars); - int nNumBars = arrSCBars.GetSize(); - int nDelta = nLengthAvail - nLengthActual; - - // return faster when there is only one sizing bar per row (this one) - if (nNumBars == 1) - { - ASSERT(arrSCBars[0] == this); - - if (nDelta == 0) - return TRUE; - - m_bKeepSize = FALSE; - (bHorz ? m_szHorz.cx : m_szVert.cy) += nDelta; - - return TRUE; - } - - // make all the bars the same width - for (i = 0; i < nNumBars; i++) - if (bHorz) - arrSCBars[i]->m_szHorz.cy = nWidthMax; - else - arrSCBars[i]->m_szVert.cx = nWidthMax; - - // distribute the difference between the bars, - // but don't shrink them below their minsizes - while (nDelta != 0) - { - int nDeltaOld = nDelta; - for (i = 0; i < nNumBars; i++) - { - pBar = arrSCBars[i]; - int nLMin = bHorz ? - pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy; - int nL = bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy; - - if ((nL == nLMin) && (nDelta < 0) || // already at min length - pBar->m_bKeepSize) // or wants to keep its size - continue; - - // sign of nDelta - int nDelta2 = (nDelta < 0) ? -1 : 1; - - (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta2; - nDelta -= nDelta2; - if (nDelta == 0) break; - } - // clear m_bKeepSize flags - if ((nDeltaOld == nDelta) || (nDelta == 0)) - for (i = 0; i < nNumBars; i++) - arrSCBars[i]->m_bKeepSize = FALSE; - } - - return TRUE; -} - -void CSizingControlBar::AlignControlBars() -{ - int nFirst, nLast, nThis; - GetRowInfo(nFirst, nLast, nThis); - - BOOL bHorz = IsHorzDocked(); - BOOL bNeedRecalc = FALSE; - int nAlign = bHorz ? -2 : 0; - - CRect rc, rcDock; - m_pDockBar->GetWindowRect(&rcDock); - - for (int i = nFirst; i <= nLast; i++) - { - CSizingControlBar* pBar = static_cast(m_pDockBar->m_arrBars[i]); - if (HIWORD(pBar) == 0) continue; // placeholder - if (!pBar->IsVisible()) continue; - - pBar->GetWindowRect(&rc); - rc.OffsetRect(-rcDock.TopLeft()); - - if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - rc = CRect(rc.TopLeft(), - bHorz ? pBar->m_szHorz : pBar->m_szVert); - - if ((bHorz ? rc.left : rc.top) != nAlign) - { - if (!bHorz) - rc.OffsetRect(0, nAlign - rc.top - 2); - else if (m_nDockBarID == AFX_IDW_DOCKBAR_TOP) - rc.OffsetRect(nAlign - rc.left, -2); - else - rc.OffsetRect(nAlign - rc.left, 0); - pBar->MoveWindow(rc); - bNeedRecalc = TRUE; - } - nAlign += (bHorz ? rc.Width() : rc.Height()) - 2; - } - - if (bNeedRecalc) - m_pDockSite->DelayRecalcLayout(); -} - -void CSizingControlBar::OnUpdateCmdUI(CFrameWnd* pTarget, - BOOL bDisableIfNoHndler) -{ - UNUSED_ALWAYS(bDisableIfNoHndler); - UNUSED_ALWAYS(pTarget); -} - -void CSizingControlBar::LoadState(LPCTSTR lpszProfileName) -{ - ASSERT_VALID(this); - ASSERT(GetSafeHwnd()); // must be called after Create() - -#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) - // compensate the caption miscalculation in CFrameWnd::SetDockState() - CDockState state; - state.LoadState(lpszProfileName); - - UINT nID = GetDlgCtrlID(); - for (int i = 0; i < state.m_arrBarInfo.GetSize(); i++) - { - CControlBarInfo* pInfo = (CControlBarInfo*)state.m_arrBarInfo[i]; - ASSERT(pInfo != NULL); - if (!pInfo->m_bFloating) - continue; - - // this is a floating dockbar - check the ID array - for (int j = 0; j < pInfo->m_arrBarID.GetSize(); j++) - if ((DWORD) pInfo->m_arrBarID[j] == nID) - { - // found this bar - offset origin and save settings - pInfo->m_pointPos.x++; - pInfo->m_pointPos.y += - ::GetSystemMetrics(SM_CYSMCAPTION) + 1; - pInfo->SaveState(lpszProfileName, i); - } - } -#endif //_SCB_REPLACE_MINIFRAME && !_SCB_MINIFRAME_CAPTION - - CWinApp* pApp = AfxGetApp(); - - TCHAR szSection[256]; - wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName, - GetDlgCtrlID()); - - m_szHorz.cx = max(m_szMinHorz.cx, (int) pApp->GetProfileInt( - szSection, _T("sizeHorzCX"), m_szHorz.cx)); - m_szHorz.cy = max(m_szMinHorz.cy, (int) pApp->GetProfileInt( - szSection, _T("sizeHorzCY"), m_szHorz.cy)); - - m_szVert.cx = max(m_szMinVert.cx, (int) pApp->GetProfileInt( - szSection, _T("sizeVertCX"), m_szVert.cx)); - m_szVert.cy = max(m_szMinVert.cy, (int) pApp->GetProfileInt( - szSection, _T("sizeVertCY"), m_szVert.cy)); - - m_szFloat.cx = max(m_szMinFloat.cx, (int) pApp->GetProfileInt( - szSection, _T("sizeFloatCX"), m_szFloat.cx)); - m_szFloat.cy = max(m_szMinFloat.cy, (int) pApp->GetProfileInt( - szSection, _T("sizeFloatCY"), m_szFloat.cy)); -} - -void CSizingControlBar::SaveState(LPCTSTR lpszProfileName) -{ - // place your SaveState or GlobalSaveState call in - // CMainFrame's OnClose() or DestroyWindow(), not in OnDestroy() - ASSERT_VALID(this); - ASSERT(GetSafeHwnd()); - - CWinApp* pApp = AfxGetApp(); - - TCHAR szSection[256]; - wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName, - GetDlgCtrlID()); - - pApp->WriteProfileInt(szSection, _T("sizeHorzCX"), m_szHorz.cx); - pApp->WriteProfileInt(szSection, _T("sizeHorzCY"), m_szHorz.cy); - - pApp->WriteProfileInt(szSection, _T("sizeVertCX"), m_szVert.cx); - pApp->WriteProfileInt(szSection, _T("sizeVertCY"), m_szVert.cy); - - pApp->WriteProfileInt(szSection, _T("sizeFloatCX"), m_szFloat.cx); - pApp->WriteProfileInt(szSection, _T("sizeFloatCY"), m_szFloat.cy); -} - -void CSizingControlBar::GlobalLoadState(CFrameWnd* pFrame, - LPCTSTR lpszProfileName) -{ - POSITION pos = pFrame->m_listControlBars.GetHeadPosition(); - while (pos != NULL) - { - CSizingControlBar* pBar = static_cast (pFrame->m_listControlBars.GetNext(pos)); - ASSERT(pBar != NULL); - if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - pBar->LoadState(lpszProfileName); - } -} - -void CSizingControlBar::GlobalSaveState(CFrameWnd* pFrame, - LPCTSTR lpszProfileName) -{ - POSITION pos = pFrame->m_listControlBars.GetHeadPosition(); - while (pos != NULL) - { - CSizingControlBar* pBar = static_cast (pFrame->m_listControlBars.GetNext(pos)); - ASSERT(pBar != NULL); - if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - pBar->SaveState(lpszProfileName); - } -} - -//mpc-hc custom code start -void CSizingControlBar::mpc_fillNcBG(CDC* mdc, CRect rcDraw) { - mdc->FillRect(rcDraw, CBrush::FromHandle( - (HBRUSH)GetClassLongPtr(m_hWnd, GCLP_HBRBACKGROUND))); -} -//mpc-hc custom code end - -#ifdef _SCB_REPLACE_MINIFRAME -#ifndef _SCB_MINIFRAME_CAPTION -///////////////////////////////////////////////////////////////////////////// -// CSCBDockContext Drag Operations - -static void AdjustRectangle(CRect& rect, CPoint pt) -{ - int nXOffset = (pt.x < rect.left) ? (pt.x - rect.left) : - (pt.x > rect.right) ? (pt.x - rect.right) : 0; - int nYOffset = (pt.y < rect.top) ? (pt.y - rect.top) : - (pt.y > rect.bottom) ? (pt.y - rect.bottom) : 0; - rect.OffsetRect(nXOffset, nYOffset); -} - -void CSCBDockContext::StartDrag(CPoint pt) -{ - ASSERT_VALID(m_pBar); - m_bDragging = TRUE; - - InitLoop(); - - ASSERT((m_pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) != 0); - - // get true bar size (including borders) - CRect rect; - m_pBar->GetWindowRect(rect); - m_ptLast = pt; - CSize sizeHorz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK); - CSize sizeVert = m_pBar->CalcDynamicLayout(0, LM_VERTDOCK); - CSize sizeFloat = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH); - - m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz); - m_rectDragVert = CRect(rect.TopLeft(), sizeVert); - - // calculate frame dragging rectangle - m_rectFrameDragHorz = CRect(rect.TopLeft(), sizeFloat); - -#ifdef _MAC - CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, - WS_THICKFRAME, WS_EX_FORCESIZEBOX); -#else - CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, WS_THICKFRAME); -#endif - m_rectFrameDragHorz.DeflateRect(2, 2); - m_rectFrameDragVert = m_rectFrameDragHorz; - - // adjust rectangles so that point is inside - AdjustRectangle(m_rectDragHorz, pt); - AdjustRectangle(m_rectDragVert, pt); - AdjustRectangle(m_rectFrameDragHorz, pt); - AdjustRectangle(m_rectFrameDragVert, pt); - - // initialize tracking state and enter tracking loop - m_dwOverDockStyle = CanDock(); - Move(pt); // call it here to handle special keys - Track(); -} -#endif //_SCB_MINIFRAME_CAPTION - -///////////////////////////////////////////////////////////////////////////// -// CSCBMiniDockFrameWnd - -IMPLEMENT_DYNCREATE(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd); - -BEGIN_MESSAGE_MAP(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd) - //{{AFX_MSG_MAP(CSCBMiniDockFrameWnd) - ON_WM_NCLBUTTONDOWN() - ON_WM_GETMINMAXINFO() - ON_WM_WINDOWPOSCHANGING() - ON_WM_SIZE() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() - -BOOL CSCBMiniDockFrameWnd::Create(CWnd* pParent, DWORD dwBarStyle) -{ - // set m_bInRecalcLayout to avoid flashing during creation - // RecalcLayout will be called once something is docked - m_bInRecalcLayout = TRUE; - - DWORD dwStyle = WS_POPUP|WS_CAPTION|WS_SYSMENU|MFS_MOVEFRAME| - MFS_4THICKFRAME|MFS_SYNCACTIVE|MFS_BLOCKSYSMENU| - FWS_SNAPTOBARS; - - if (dwBarStyle & CBRS_SIZE_DYNAMIC) - dwStyle &= ~MFS_MOVEFRAME; - - DWORD dwExStyle = 0; -#ifdef _MAC - if (dwBarStyle & CBRS_SIZE_DYNAMIC) - dwExStyle |= WS_EX_FORCESIZEBOX; - else - dwStyle &= ~(MFS_MOVEFRAME|MFS_4THICKFRAME); -#endif - - if (!CMiniFrameWnd::CreateEx(dwExStyle, - NULL, "", dwStyle, rectDefault, pParent)) - { - m_bInRecalcLayout = FALSE; - return FALSE; - } - dwStyle = dwBarStyle & (CBRS_ALIGN_LEFT|CBRS_ALIGN_RIGHT) ? - CBRS_ALIGN_LEFT : CBRS_ALIGN_TOP; - dwStyle |= dwBarStyle & CBRS_FLOAT_MULTI; - CMenu* pSysMenu = GetSystemMenu(FALSE); - //pSysMenu->DeleteMenu(SC_SIZE, MF_BYCOMMAND); - CString strHide; - if (strHide.LoadString(AFX_IDS_HIDE)) - { - pSysMenu->DeleteMenu(SC_CLOSE, MF_BYCOMMAND); - pSysMenu->AppendMenu(MF_STRING|MF_ENABLED, SC_CLOSE, strHide); - } - - // must initially create with parent frame as parent - if (!m_wndDockBar.Create(pParent, WS_CHILD | WS_VISIBLE | dwStyle, - AFX_IDW_DOCKBAR_FLOAT)) - { - m_bInRecalcLayout = FALSE; - return FALSE; - } - - // set parent to CMiniDockFrameWnd - m_wndDockBar.SetParent(this); - m_bInRecalcLayout = FALSE; - - return TRUE; -} - -void CSCBMiniDockFrameWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) -{ - if (nHitTest == HTCAPTION || nHitTest == HTCLOSE) - { - baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); - return; - } - - if (GetSizingControlBar() != NULL) - CMiniFrameWnd::OnNcLButtonDown(nHitTest, point); - else - baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); -} - -CSizingControlBar* CSCBMiniDockFrameWnd::GetSizingControlBar() -{ - CWnd* pWnd = GetWindow(GW_CHILD); // get the dockbar - if (pWnd == NULL) - return NULL; - - pWnd = pWnd->GetWindow(GW_CHILD); // get the controlbar - if (pWnd == NULL) - return NULL; - - if (!pWnd->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) - return NULL; - - return static_cast (pWnd); -} - -void CSCBMiniDockFrameWnd::OnSize(UINT nType, int cx, int cy) -{ - CSizingControlBar* pBar = GetSizingControlBar(); - if ((pBar != NULL) && (GetStyle() & MFS_4THICKFRAME) == 0 - && pBar->IsVisible() && - cx + 4 >= pBar->m_szMinFloat.cx && - cy + 4 >= pBar->m_szMinFloat.cy) - pBar->m_szFloat = CSize(cx + 4, cy + 4); - - baseCSCBMiniDockFrameWnd::OnSize(nType, cx, cy); -} - -void CSCBMiniDockFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) -{ - baseCSCBMiniDockFrameWnd::OnGetMinMaxInfo(lpMMI); - - CSizingControlBar* pBar = GetSizingControlBar(); - if (pBar != NULL) - { - CRect r(CPoint(0, 0), pBar->m_szMinFloat - CSize(4, 4)); -#ifndef _SCB_MINIFRAME_CAPTION - CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME); -#else - CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME|WS_CAPTION); -#endif //_SCB_MINIFRAME_CAPTION - lpMMI->ptMinTrackSize.x = r.Width(); - lpMMI->ptMinTrackSize.y = r.Height(); -// mpc-hc custom code start - if(pBar->m_bFixedFloat) - { - lpMMI->ptMinTrackSize.x = pBar->m_szFixedFloat.cx; - lpMMI->ptMinTrackSize.y = pBar->m_szFixedFloat.cy; - lpMMI->ptMaxTrackSize.x = pBar->m_szFixedFloat.cx; - lpMMI->ptMaxTrackSize.y = pBar->m_szFixedFloat.cy; - } -// mpc-hc custom code end - } -} - -void CSCBMiniDockFrameWnd::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) -{ - if ((GetStyle() & MFS_4THICKFRAME) != 0) - { - CSizingControlBar* pBar = GetSizingControlBar(); - if (pBar != NULL) - { - lpwndpos->flags |= SWP_NOSIZE; // don't size this time - // prevents flicker - pBar->m_pDockBar->ModifyStyle(0, WS_CLIPCHILDREN); - - // enable diagonal resizing - DWORD dwStyleRemove = MFS_4THICKFRAME; -#ifndef _SCB_MINIFRAME_CAPTION - // remove caption - dwStyleRemove |= WS_SYSMENU|WS_CAPTION; -#endif - ModifyStyle(dwStyleRemove, 0); - - DelayRecalcLayout(); - pBar->PostMessage(WM_NCPAINT); - } - } - - CMiniFrameWnd::OnWindowPosChanging(lpwndpos); -} - -#endif //_SCB_REPLACE_MINIFRAME +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBar Version 2.45 +// +// Created: Jan 24, 1998 Last Modified: April 16, 2010 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com . +// +// The sources and a short version of the docs are also available at +// www.codeproject.com . Look for a "Docking Windows" section and check +// the version to be sure you get the latest one ;) +// +// Hint: These classes are intended to be used as base classes. Do not +// simply add your code to these files - instead create a new class +// derived from one of CSizingControlBarXX classes and put there what +// you need. See CMyBar classes in the demo projects for examples. +// Modify this file only to fix bugs, and don't forget to send me a copy. +///////////////////////////////////////////////////////////////////////// +// Acknowledgements: +// o Thanks to Harlan R. Seymour for his continuous support during +// development of this code. +// o Thanks to Dundas Software and Formatta Corporation for the +// opportunities to test this code on real-life applications. +// o Some ideas for the gripper came from the CToolBarEx flat toolbar +// by Joerg Koenig. Thanks, Joerg! +// o Thanks to Robert Wolpow for the code on which CDockContext based +// dialgonal resizing is based. +// o Thanks to the following people for various bug fixes and/or +// enhancements: Chris Maunder, Jakawan Ratiwanich, Udo Schaefer, +// Anatoly Ivasyuk, Peter Hauptmann, DJ(?), Pat Kusbel, Aleksey +// Malyshev, and many others who used this code and sent feedback. +///////////////////////////////////////////////////////////////////////// + +// sizecbar.cpp : implementation file +// + +#include "stdafx.h" +#include "sizecbar.h" + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar + +IMPLEMENT_DYNAMIC(CSizingControlBar, baseCSizingControlBar); + +CSizingControlBar::CSizingControlBar() +{ + m_szMinHorz = CSize(33, 32); + m_szMinVert = CSize(33, 32); + m_szMinFloat = CSize(37, 32); + m_szHorz = CSize(200, 200); + m_szVert = CSize(200, 200); + m_szFloat = CSize(200, 200); + m_bTracking = FALSE; + m_bKeepSize = FALSE; + m_bParentSizing = FALSE; + m_cxEdge = 5; + m_bDragShowContent = FALSE; + m_nDockBarID = 0; + m_dwSCBStyle = 0; + m_htEdge = 0; + m_nTrackPosMin = 0; + m_nTrackPosMax = 0; + m_nTrackPosOld = 0; + m_nTrackEdgeOfs = 0; + m_bFixedFloat = FALSE; +} + +CSizingControlBar::~CSizingControlBar() +{ +} + +BEGIN_MESSAGE_MAP(CSizingControlBar, baseCSizingControlBar) + //{{AFX_MSG_MAP(CSizingControlBar) + ON_WM_CREATE() + ON_WM_PAINT() + ON_WM_NCPAINT() + ON_WM_NCCALCSIZE() + ON_WM_WINDOWPOSCHANGING() + ON_WM_CAPTURECHANGED() + ON_WM_SETTINGCHANGE() + ON_WM_LBUTTONUP() + ON_WM_MOUSEMOVE() + ON_WM_NCLBUTTONDOWN() + ON_WM_LBUTTONDOWN() + ON_WM_LBUTTONDBLCLK() + ON_WM_RBUTTONDOWN() + ON_WM_NCMOUSEMOVE() + ON_WM_NCHITTEST() + ON_WM_CLOSE() + ON_WM_SIZE() + //}}AFX_MSG_MAP + ON_MESSAGE(WM_SETTEXT, OnSetText) +END_MESSAGE_MAP() + +// old creation method, still here for compatibility reasons +BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, + CSize sizeDefault, BOOL bHasGripper, + UINT nID, DWORD dwStyle) +{ + UNUSED_ALWAYS(bHasGripper); + + m_szHorz = m_szVert = m_szFloat = sizeDefault; + return Create(lpszWindowName, pParentWnd, nID, dwStyle); +} + +// preffered creation method +BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, + CWnd* pParentWnd, UINT nID, + DWORD dwStyle) +{ + // must have a parent + ASSERT_VALID(pParentWnd); + // cannot be both fixed and dynamic + // (CBRS_SIZE_DYNAMIC is used for resizng when floating) + ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && + (dwStyle & CBRS_SIZE_DYNAMIC))); + + m_dwStyle = dwStyle & CBRS_ALL; // save the control bar styles + + // register and create the window - skip CControlBar::Create() + CString wndclass = ::AfxRegisterWndClass(CS_DBLCLKS, + ::LoadCursor(NULL, IDC_ARROW), + ::GetSysColorBrush(COLOR_BTNFACE), 0); + + dwStyle &= ~CBRS_ALL; // keep only the generic window styles + dwStyle |= WS_CLIPCHILDREN; // prevents flashing + if (!CWnd::Create(wndclass, lpszWindowName, dwStyle, + CRect(0, 0, 0, 0), pParentWnd, nID)) + return FALSE; + + return TRUE; +} + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar operations +#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) +void CSizingControlBar::EnableDocking(DWORD dwDockStyle) +{ + // must be CBRS_ALIGN_XXX or CBRS_FLOAT_MULTI only + ASSERT((dwDockStyle & ~(CBRS_ALIGN_ANY|CBRS_FLOAT_MULTI)) == 0); + // cannot have the CBRS_FLOAT_MULTI style + ASSERT((dwDockStyle & CBRS_FLOAT_MULTI) == 0); + // the bar must have CBRS_SIZE_DYNAMIC style + ASSERT((m_dwStyle & CBRS_SIZE_DYNAMIC) != 0); + + m_dwDockStyle = dwDockStyle; + if (m_pDockContext == NULL) + m_pDockContext = new CSCBDockContext(this); + + // permanently wire the bar's owner to its current parent + if (m_hWndOwner == NULL) + m_hWndOwner = ::GetParent(m_hWnd); +} +#endif + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar message handlers + +int CSizingControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (baseCSizingControlBar::OnCreate(lpCreateStruct) == -1) + return -1; + + // query SPI_GETDRAGFULLWINDOWS system parameter + // OnSettingChange() will update m_bDragShowContent + m_bDragShowContent = FALSE; + ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, + &m_bDragShowContent, 0); + + // uncomment this line if you want raised borders +// m_dwSCBStyle |= SCBS_SHOWEDGES; + + return 0; +} + + +LRESULT CSizingControlBar::OnSetText(WPARAM wParam, LPARAM lParam) +{ + UNUSED_ALWAYS(wParam); + + LRESULT lResult = CWnd::Default(); + + if (IsFloating() && + GetParentFrame()->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd))) + { + m_pDockBar->SetWindowText((LPCTSTR) lParam); // update dockbar + GetParentFrame()->DelayRecalcLayout(); // refresh miniframe + } + + return lResult; +} + +const BOOL CSizingControlBar::IsFloating() const +{ + return !IsHorzDocked() && !IsVertDocked(); +} + +const BOOL CSizingControlBar::IsHorzDocked() const +{ + return (m_nDockBarID == AFX_IDW_DOCKBAR_TOP || + m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); +} + +const BOOL CSizingControlBar::IsVertDocked() const +{ + return (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT || + m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT); +} + +const BOOL CSizingControlBar::IsSideTracking() const +{ + // don't call this when not tracking + ASSERT(m_bTracking && !IsFloating()); + + return (m_htEdge == HTLEFT || m_htEdge == HTRIGHT) ? + IsHorzDocked() : IsVertDocked(); +} + +CSize CSizingControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) +{ + if (bStretch) // the bar is stretched (is not the child of a dockbar) + if (bHorz) + return CSize(32767, m_szHorz.cy); + else + return CSize(m_szVert.cx, 32767); + + // dirty cast - we need access to protected CDockBar members + CSCBDockBar* pDockBar = static_cast (m_pDockBar); + + // force imediate RecalcDelayShow() for all sizing bars on the row + // with delayShow/delayHide flags set to avoid IsVisible() problems + CSCBArray arrSCBars; + GetRowSizingBars(arrSCBars); + AFX_SIZEPARENTPARAMS layout; + layout.hDWP = pDockBar->m_bLayoutQuery ? + NULL : ::BeginDeferWindowPos(arrSCBars.GetSize()); + for (int i = 0; i < arrSCBars.GetSize(); i++) + if (arrSCBars[i]->m_nStateFlags & (delayHide|delayShow)) + arrSCBars[i]->RecalcDelayShow(&layout); + if (layout.hDWP != NULL) + ::EndDeferWindowPos(layout.hDWP); + + // get available length + CRect rc = pDockBar->m_rectLayout; + if (rc.IsRectEmpty()) + m_pDockSite->GetClientRect(&rc); + int nLengthTotal = bHorz ? rc.Width() + 2 : rc.Height() - 2; + + if (IsVisible() && !IsFloating() && + m_bParentSizing && arrSCBars[0] == this) + if (NegotiateSpace(nLengthTotal, (bHorz != FALSE))) + AlignControlBars(); + + m_bParentSizing = FALSE; + + if (bHorz) + return CSize(max(m_szMinHorz.cx, m_szHorz.cx), + max(m_szMinHorz.cy, m_szHorz.cy)); + + return CSize(max(m_szMinVert.cx, m_szVert.cx), + max(m_szMinVert.cy, m_szVert.cy)); +} + +CSize CSizingControlBar::CalcDynamicLayout(int nLength, DWORD dwMode) +{ + if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) // docked ? + { + if (nLength == -1) + m_bParentSizing = TRUE; + + return baseCSizingControlBar::CalcDynamicLayout(nLength, dwMode); + } + + if (dwMode & LM_MRUWIDTH) return m_szFloat; + if (dwMode & LM_COMMIT) return m_szFloat; // already committed + +#ifndef _SCB_REPLACE_MINIFRAME + // check for dialgonal resizing hit test + int nHitTest = m_pDockContext->m_nHitTest; + if (IsFloating() && + (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT || + nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT)) + { + CPoint ptCursor; + ::GetCursorPos(&ptCursor); + + CRect rFrame, rBar; + GetParentFrame()->GetWindowRect(&rFrame); + GetWindowRect(&rBar); + + if (nHitTest == HTTOPLEFT || nHitTest == HTBOTTOMLEFT) + { + m_szFloat.cx = rFrame.left + rBar.Width() - ptCursor.x; + m_pDockContext->m_rectFrameDragHorz.left = + min(ptCursor.x, rFrame.left + rBar.Width() - m_szMinFloat.cx); + } + + if (nHitTest == HTTOPLEFT || nHitTest == HTTOPRIGHT) + { + m_szFloat.cy = rFrame.top + rBar.Height() - ptCursor.y; + m_pDockContext->m_rectFrameDragHorz.top = + min(ptCursor.y, rFrame.top + rBar.Height() - m_szMinFloat.cy); + } + + if (nHitTest == HTTOPRIGHT || nHitTest == HTBOTTOMRIGHT) + m_szFloat.cx = rBar.Width() + ptCursor.x - rFrame.right; + + if (nHitTest == HTBOTTOMLEFT || nHitTest == HTBOTTOMRIGHT) + m_szFloat.cy = rBar.Height() + ptCursor.y - rFrame.bottom; + } + else +#endif //_SCB_REPLACE_MINIFRAME + ((dwMode & LM_LENGTHY) ? m_szFloat.cy : m_szFloat.cx) = nLength; + + m_szFloat.cx = max(m_szFloat.cx, m_szMinFloat.cx); + m_szFloat.cy = max(m_szFloat.cy, m_szMinFloat.cy); + + return m_szFloat; +} + +void CSizingControlBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) +{ + // force non-client recalc if moved or resized + lpwndpos->flags |= SWP_FRAMECHANGED; + + baseCSizingControlBar::OnWindowPosChanging(lpwndpos); + + // find on which side are we docked + m_nDockBarID = GetParent()->GetDlgCtrlID(); + + if (!IsFloating()) + if (lpwndpos->flags & SWP_SHOWWINDOW) + m_bKeepSize = TRUE; +} + +///////////////////////////////////////////////////////////////////////// +// Mouse Handling +// +void CSizingControlBar::OnLButtonDown(UINT nFlags, CPoint point) +{ + if (m_pDockBar != NULL) + { + // start the drag + ASSERT(m_pDockContext != NULL); + ClientToScreen(&point); + m_pDockContext->StartDrag(point); + } + else + CWnd::OnLButtonDown(nFlags, point); +} + +void CSizingControlBar::OnLButtonDblClk(UINT nFlags, CPoint point) +{ + if (m_pDockBar != NULL) + { + // toggle docking + ASSERT(m_pDockContext != NULL); + m_pDockContext->ToggleDocking(); + } + else + CWnd::OnLButtonDblClk(nFlags, point); +} + +void CSizingControlBar::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + UNUSED_ALWAYS(point); + + if (m_bTracking || IsFloating()) + return; + + if ((nHitTest >= HTSIZEFIRST) && (nHitTest <= HTSIZELAST)) + StartTracking(nHitTest, point); // sizing edge hit +} + +void CSizingControlBar::OnLButtonUp(UINT nFlags, CPoint point) +{ + if (m_bTracking) + StopTracking(); + + baseCSizingControlBar::OnLButtonUp(nFlags, point); +} + +void CSizingControlBar::OnRButtonDown(UINT nFlags, CPoint point) +{ + if (m_bTracking) + StopTracking(); + + baseCSizingControlBar::OnRButtonDown(nFlags, point); +} + +void CSizingControlBar::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_bTracking) + { + CPoint ptScreen = point; + ClientToScreen(&ptScreen); + + //mpc-hc custom code start + // Switch to parent window client coordinates to account for possible RTL layout + CPoint ptParentClient = ptScreen; + GetParentFrame()->ScreenToClient(&ptParentClient); + OnTrackUpdateSize(ptParentClient); + //mpc-hc custom code end + } + + baseCSizingControlBar::OnMouseMove(nFlags, point); +} + +void CSizingControlBar::OnCaptureChanged(CWnd *pWnd) +{ + if (m_bTracking && (pWnd != this)) + StopTracking(); + + baseCSizingControlBar::OnCaptureChanged(pWnd); +} + +void CSizingControlBar::OnNcCalcSize(BOOL bCalcValidRects, + NCCALCSIZE_PARAMS FAR* lpncsp) +{ + UNUSED_ALWAYS(bCalcValidRects); + +#ifndef _SCB_REPLACE_MINIFRAME + // Enable diagonal resizing for floating miniframe + if (IsFloating()) + { + CFrameWnd* pFrame = GetParentFrame(); + if (pFrame != NULL && + pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd))) + { +//mpc-hc custom code start + LONG_PTR dwStyle = ::GetWindowLongPtr(pFrame->m_hWnd, GWL_STYLE); +//mpc-hc custom code end + if ((dwStyle & MFS_4THICKFRAME) != 0) + { + pFrame->ModifyStyle(MFS_4THICKFRAME, 0); // clear + GetParent()->ModifyStyle(0, WS_CLIPCHILDREN); + } + } + } +#endif _SCB_REPLACE_MINIFRAME + + // compute the the client area + m_dwSCBStyle &= ~SCBS_EDGEALL; + + // add resizing edges between bars on the same row + if (!IsFloating() && m_pDockBar != NULL) + { + CSCBArray arrSCBars; + int nThis; + GetRowSizingBars(arrSCBars, nThis); + + BOOL bHorz = IsHorzDocked(); + if (nThis > 0) + m_dwSCBStyle |= bHorz ? SCBS_EDGELEFT : SCBS_EDGETOP; + + if (nThis < arrSCBars.GetUpperBound()) + m_dwSCBStyle |= bHorz ? SCBS_EDGERIGHT : SCBS_EDGEBOTTOM; + } + + NcCalcClient(&lpncsp->rgrc[0], m_nDockBarID); +} + +void CSizingControlBar::NcCalcClient(LPRECT pRc, UINT nDockBarID) +{ + CRect rc(pRc); + //mpc-hc custom code start + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ClientToScreen(&rc); + //mpc-hc custom code end + + rc.DeflateRect(3, 5, 3, 3); + if (nDockBarID != AFX_IDW_DOCKBAR_FLOAT) + rc.DeflateRect(2, 0, 2, 2); + + switch(nDockBarID) + { + case AFX_IDW_DOCKBAR_TOP: + m_dwSCBStyle |= SCBS_EDGEBOTTOM; + break; + case AFX_IDW_DOCKBAR_BOTTOM: + m_dwSCBStyle |= SCBS_EDGETOP; + break; + case AFX_IDW_DOCKBAR_LEFT: + m_dwSCBStyle |= SCBS_EDGERIGHT; + break; + case AFX_IDW_DOCKBAR_RIGHT: + m_dwSCBStyle |= SCBS_EDGELEFT; + break; + } + + // make room for edges only if they will be painted + if (m_dwSCBStyle & SCBS_SHOWEDGES) + rc.DeflateRect( + (m_dwSCBStyle & SCBS_EDGELEFT) ? m_cxEdge : 0, + (m_dwSCBStyle & SCBS_EDGETOP) ? m_cxEdge : 0, + (m_dwSCBStyle & SCBS_EDGERIGHT) ? m_cxEdge : 0, + (m_dwSCBStyle & SCBS_EDGEBOTTOM) ? m_cxEdge : 0); + + //mpc-hc custom code start + // Work in screen coordinates before converting back to + // client coordinates to account for possible RTL layout + GetParent()->ScreenToClient(&rc); + //mpc-hc custom code end + + *pRc = rc; +} + +void CSizingControlBar::OnNcPaint() +{ + // get window DC that is clipped to the non-client area + CWindowDC dc(this); // the HDC will be released by the destructor + + CRect rcClient, rcBar; + GetClientRect(rcClient); + //mpc-hc custom code start + //ClientToScreen(rcClient); + //mpc-hc custom code end + GetWindowRect(rcBar); + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + ScreenToClient(rcBar); + //mpc-hc custom code end + rcClient.OffsetRect(-rcBar.TopLeft()); + rcBar.OffsetRect(-rcBar.TopLeft()); + + CDC mdc; + mdc.CreateCompatibleDC(&dc); + + CBitmap bm; + bm.CreateCompatibleBitmap(&dc, rcBar.Width(), rcBar.Height()); + CBitmap* pOldBm = mdc.SelectObject(&bm); + + // draw borders in non-client area + CRect rcDraw = rcBar; + DrawBorders(&mdc, rcDraw); + + // erase the NC background +//mpc-hc custom code start + mpc_fillNcBG(&mdc, rcDraw); +//mpc-hc custom code end + + if (m_dwSCBStyle & SCBS_SHOWEDGES) + { + CRect rcEdge; // paint the sizing edges + for (int i = 0; i < 4; i++) + if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge)) + mdc.Draw3dRect(rcEdge, ::GetSysColor(COLOR_BTNHIGHLIGHT), + ::GetSysColor(COLOR_BTNSHADOW)); + } + + NcPaintGripper(&mdc, rcClient); + + // client area is not our bussiness :) + dc.IntersectClipRect(rcBar); + dc.ExcludeClipRect(rcClient); + + dc.BitBlt(0, 0, rcBar.Width(), rcBar.Height(), &mdc, 0, 0, SRCCOPY); + + mdc.SelectObject(pOldBm); + bm.DeleteObject(); + mdc.DeleteDC(); +} + +void CSizingControlBar::NcPaintGripper(CDC* pDC, CRect rcClient) +{ + UNUSED_ALWAYS(pDC); + UNUSED_ALWAYS(rcClient); +} + +void CSizingControlBar::OnPaint() +{ + // overridden to skip border painting based on clientrect + CPaintDC dc(this); +} + +LRESULT CSizingControlBar::OnNcHitTest(CPoint point) +{ + CRect rcBar, rcEdge; + GetWindowRect(rcBar); + + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + ScreenToClient(&rcBar); + ScreenToClient(&point); + //mpc-hc custom code end + + if (!IsFloating()) + for (int i = 0; i < 4; i++) + if (GetEdgeRect(rcBar, GetEdgeHTCode(i), rcEdge)) + if (rcEdge.PtInRect(point)) + return GetEdgeHTCode(i); + + return HTCLIENT; +} + +void CSizingControlBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) +{ + baseCSizingControlBar::OnSettingChange(uFlags, lpszSection); + + m_bDragShowContent = FALSE; + ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, + &m_bDragShowContent, 0); // update +} + +void CSizingControlBar::OnSize(UINT nType, int cx, int cy) +{ + UNUSED_ALWAYS(nType); + + if ((m_dwSCBStyle & SCBS_SIZECHILD) != 0) + { + // automatic child resizing - only one child is allowed + CWnd* pWnd = GetWindow(GW_CHILD); + if (pWnd != NULL) + { + pWnd->MoveWindow(0, 0, cx, cy); + ASSERT(pWnd->GetWindow(GW_HWNDNEXT) == NULL); + } + } +} + +void CSizingControlBar::OnClose() +{ + // do nothing: protection against accidentally destruction by the + // child control (i.e. if user hits Esc in a child editctrl) +} + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar implementation helpers + +void CSizingControlBar::StartTracking(UINT nHitTest, CPoint point) +{ + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + GetParentFrame()->ScreenToClient(&point); + //mpc-hc custom code end + + SetCapture(); + + // make sure no updates are pending + if (!m_bDragShowContent) + RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); + + m_htEdge = nHitTest; + m_bTracking = TRUE; + + BOOL bHorz = IsHorzDocked(); + BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; + + m_nTrackPosOld = bHorzTracking ? point.x : point.y; + + CRect rcBar, rcEdge; + GetWindowRect(rcBar); + //mpc-hc custom code start + // Convert to client coordinates to account for possible RTL layout + GetParent()->ScreenToClient(&rcBar); + //mpc-hc custom code end + GetEdgeRect(rcBar, m_htEdge, rcEdge); + m_nTrackEdgeOfs = m_nTrackPosOld - + (bHorzTracking ? rcEdge.CenterPoint().x : rcEdge.CenterPoint().y); + + CSCBArray arrSCBars; + int nThis; + GetRowSizingBars(arrSCBars, nThis); + + m_nTrackPosMin = m_nTrackPosMax = m_nTrackPosOld; + if (!IsSideTracking()) + { + // calc minwidth as the max minwidth of the sizing bars on row + int nMinWidth = bHorz ? m_szMinHorz.cy : m_szMinVert.cx; + for (int i = 0; i < arrSCBars.GetSize(); i++) + nMinWidth = max(nMinWidth, bHorz ? + arrSCBars[i]->m_szMinHorz.cy : + arrSCBars[i]->m_szMinVert.cx); + int nExcessWidth = (bHorz ? m_szHorz.cy : m_szVert.cx) - nMinWidth; + + // the control bar cannot grow with more than the width of + // remaining client area of the mainframe + CRect rcT; + m_pDockSite->RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST, + reposQuery, &rcT, NULL, TRUE); + int nMaxWidth = bHorz ? rcT.Height() - 2 : rcT.Width() - 2; + + BOOL bTopOrLeft = m_htEdge == HTTOP || m_htEdge == HTLEFT; + + m_nTrackPosMin -= bTopOrLeft ? nMaxWidth : nExcessWidth; + m_nTrackPosMax += bTopOrLeft ? nExcessWidth : nMaxWidth; + } + else + { + // side tracking: + // max size is the actual size plus the amount the other + // sizing bars can be decreased until they reach their minsize + if (m_htEdge == HTBOTTOM || m_htEdge == HTRIGHT) + nThis++; + + for (int i = 0; i < arrSCBars.GetSize(); i++) + { + CSizingControlBar* pBar = arrSCBars[i]; + + int nExcessWidth = bHorz ? + pBar->m_szHorz.cx - pBar->m_szMinHorz.cx : + pBar->m_szVert.cy - pBar->m_szMinVert.cy; + + if (i < nThis) + m_nTrackPosMin -= nExcessWidth; + else + m_nTrackPosMax += nExcessWidth; + } + } + + OnTrackInvertTracker(); // draw tracker +} + +void CSizingControlBar::StopTracking() +{ + OnTrackInvertTracker(); // erase tracker + + m_bTracking = FALSE; + ReleaseCapture(); + + m_pDockSite->DelayRecalcLayout(); +} + +void CSizingControlBar::OnTrackUpdateSize(CPoint& point) +{ + ASSERT(!IsFloating()); + + BOOL bHorzTrack = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; + + int nTrackPos = bHorzTrack ? point.x : point.y; + nTrackPos = max(m_nTrackPosMin, min(m_nTrackPosMax, nTrackPos)); + + int nDelta = nTrackPos - m_nTrackPosOld; + + if (nDelta == 0) + return; // no pos change + + OnTrackInvertTracker(); // erase tracker + + m_nTrackPosOld = nTrackPos; + + BOOL bHorz = IsHorzDocked(); + + CSize sizeNew = bHorz ? m_szHorz : m_szVert; + switch (m_htEdge) + { + case HTLEFT: sizeNew -= CSize(nDelta, 0); break; + case HTTOP: sizeNew -= CSize(0, nDelta); break; + case HTRIGHT: sizeNew += CSize(nDelta, 0); break; + case HTBOTTOM: sizeNew += CSize(0, nDelta); break; + } + + CSCBArray arrSCBars; + int nThis; + GetRowSizingBars(arrSCBars, nThis); + + if (!IsSideTracking()) + for (int i = 0; i < arrSCBars.GetSize(); i++) + { + CSizingControlBar* pBar = arrSCBars[i]; + // make same width (or height) + (bHorz ? pBar->m_szHorz.cy : pBar->m_szVert.cx) = + bHorz ? sizeNew.cy : sizeNew.cx; + } + else + { + int nGrowingBar = nThis; + BOOL bBefore = m_htEdge == HTTOP || m_htEdge == HTLEFT; + if (bBefore && nDelta > 0) + nGrowingBar--; + if (!bBefore && nDelta < 0) + nGrowingBar++; + if (nGrowingBar != nThis) + bBefore = !bBefore; + + // nGrowing is growing + nDelta = abs(nDelta); + CSizingControlBar* pBar = arrSCBars[nGrowingBar]; + (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta; + + // the others are shrinking + int nFirst = bBefore ? nGrowingBar - 1 : nGrowingBar + 1; + int nLimit = bBefore ? -1 : arrSCBars.GetSize(); + + for (int i = nFirst; nDelta != 0 && i != nLimit; i += (bBefore ? -1 : 1)) + { + CSizingControlBar* pBar = arrSCBars[i]; + + int nDeltaT = min(nDelta, + (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) - + (bHorz ? pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy)); + + (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) -= nDeltaT; + nDelta -= nDeltaT; + } + } + + OnTrackInvertTracker(); // redraw tracker at new pos + + if (m_bDragShowContent) + m_pDockSite->DelayRecalcLayout(); +} + +void CSizingControlBar::OnTrackInvertTracker() +{ + ASSERT(m_bTracking); + + if (m_bDragShowContent) + return; // don't show tracker if DragFullWindows is on + + BOOL bHorz = IsHorzDocked(); + CRect rc, rcBar, rcDock, rcFrame; + GetWindowRect(rcBar); + m_pDockBar->GetWindowRect(rcDock); + m_pDockSite->GetWindowRect(rcFrame); + VERIFY(GetEdgeRect(rcBar, m_htEdge, rc)); + if (!IsSideTracking()) + rc = bHorz ? + CRect(rcDock.left + 1, rc.top, rcDock.right - 1, rc.bottom) : + CRect(rc.left, rcDock.top + 1, rc.right, rcDock.bottom - 1); + + BOOL bHorzTracking = m_htEdge == HTLEFT || m_htEdge == HTRIGHT; + int nOfs = m_nTrackPosOld - m_nTrackEdgeOfs; + nOfs -= bHorzTracking ? rc.CenterPoint().x : rc.CenterPoint().y; + rc.OffsetRect(bHorzTracking ? nOfs : 0, bHorzTracking ? 0 : nOfs); + rc.OffsetRect(-rcFrame.TopLeft()); + + CDC *pDC = m_pDockSite->GetDCEx(NULL, + DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); + CBrush* pBrush = CDC::GetHalftoneBrush(); + CBrush* pBrushOld = pDC->SelectObject(pBrush); + + pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATINVERT); + + pDC->SelectObject(pBrushOld); + m_pDockSite->ReleaseDC(pDC); +} + +BOOL CSizingControlBar::GetEdgeRect(CRect rcWnd, UINT nHitTest, + CRect& rcEdge) +{ + rcEdge = rcWnd; + if (m_dwSCBStyle & SCBS_SHOWEDGES) + rcEdge.DeflateRect(1, 1); + BOOL bHorz = IsHorzDocked(); + + switch (nHitTest) + { + case HTLEFT: + if (!(m_dwSCBStyle & SCBS_EDGELEFT)) return FALSE; + rcEdge.right = rcEdge.left + m_cxEdge; + rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0); + break; + case HTTOP: + if (!(m_dwSCBStyle & SCBS_EDGETOP)) return FALSE; + rcEdge.bottom = rcEdge.top + m_cxEdge; + rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0); + break; + case HTRIGHT: + if (!(m_dwSCBStyle & SCBS_EDGERIGHT)) return FALSE; + rcEdge.left = rcEdge.right - m_cxEdge; + rcEdge.DeflateRect(0, bHorz ? m_cxEdge: 0); + break; + case HTBOTTOM: + if (!(m_dwSCBStyle & SCBS_EDGEBOTTOM)) return FALSE; + rcEdge.top = rcEdge.bottom - m_cxEdge; + rcEdge.DeflateRect(bHorz ? 0 : m_cxEdge, 0); + break; + default: + ASSERT(FALSE); // invalid hit test code + } + return TRUE; +} + +UINT CSizingControlBar::GetEdgeHTCode(int nEdge) +{ + if (nEdge == 0) return HTLEFT; + if (nEdge == 1) return HTTOP; + if (nEdge == 2) return HTRIGHT; + if (nEdge == 3) return HTBOTTOM; + ASSERT(FALSE); // invalid edge code + return HTNOWHERE; +} + +void CSizingControlBar::GetRowInfo(int& nFirst, int& nLast, int& nThis) +{ + ASSERT_VALID(m_pDockBar); // verify bounds + + nThis = m_pDockBar->FindBar(this); + ASSERT(nThis != -1); + + int i, nBars = m_pDockBar->m_arrBars.GetSize(); + + // find the first and the last bar in row + for (nFirst = -1, i = nThis - 1; i >= 0 && nFirst == -1; i--) + if (m_pDockBar->m_arrBars[i] == NULL) + nFirst = i + 1; + for (nLast = -1, i = nThis + 1; i < nBars && nLast == -1; i++) + if (m_pDockBar->m_arrBars[i] == NULL) + nLast = i - 1; + + ASSERT((nLast != -1) && (nFirst != -1)); +} + +void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars) +{ + int nThis; // dummy + GetRowSizingBars(arrSCBars, nThis); +} + +void CSizingControlBar::GetRowSizingBars(CSCBArray& arrSCBars, int& nThis) +{ + arrSCBars.RemoveAll(); + + int nFirstT, nLastT, nThisT; + GetRowInfo(nFirstT, nLastT, nThisT); + + nThis = -1; + for (int i = nFirstT; i <= nLastT; i++) + { + CSizingControlBar* pBar = static_cast (m_pDockBar->m_arrBars[i]); + if (HIWORD(pBar) == 0) continue; // placeholder + if (!pBar->IsVisible()) continue; + if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + { + if (pBar == this) + nThis = arrSCBars.GetSize(); + + arrSCBars.Add(pBar); + } + } +} + +BOOL CSizingControlBar::NegotiateSpace(int nLengthTotal, BOOL bHorz) +{ + ASSERT(bHorz == IsHorzDocked()); + + int nFirst, nLast, nThis; + GetRowInfo(nFirst, nLast, nThis); + + int nLengthAvail = nLengthTotal; + int nLengthActual = 0; + int nLengthMin = 2; + int nWidthMax = 0; + CSizingControlBar* pBar; + + int i; + for (i = nFirst; i <= nLast; i++) + { + pBar = static_cast (m_pDockBar->m_arrBars[i]); + if (HIWORD(pBar) == 0) continue; // placeholder + if (!pBar->IsVisible()) continue; + BOOL bIsSizingBar = + pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar)); + + int nLengthBar; // minimum length of the bar + if (bIsSizingBar) + nLengthBar = bHorz ? pBar->m_szMinHorz.cx - 2 : + pBar->m_szMinVert.cy - 2; + else + { + CRect rcBar; + pBar->GetWindowRect(&rcBar); + nLengthBar = bHorz ? rcBar.Width() - 2 : rcBar.Height() - 2; + } + + nLengthMin += nLengthBar; + if (nLengthMin > nLengthTotal) + { + // split the row after fixed bar + if (i < nThis) + { + m_pDockBar->m_arrBars.InsertAt(i + 1, + (CControlBar*) NULL); + return FALSE; + } + + // only this sizebar remains on the row, adjust it to minsize + if (i == nThis) + { + if (bHorz) + m_szHorz.cx = m_szMinHorz.cx; + else + m_szVert.cy = m_szMinVert.cy; + + return TRUE; // the dockbar will split the row for us + } + + // we have enough bars - go negotiate with them + m_pDockBar->m_arrBars.InsertAt(i, (CControlBar*) NULL); + nLast = i - 1; + break; + } + + if (bIsSizingBar) + { + nLengthActual += bHorz ? pBar->m_szHorz.cx - 2 : + pBar->m_szVert.cy - 2; + nWidthMax = max(nWidthMax, bHorz ? pBar->m_szHorz.cy : + pBar->m_szVert.cx); + } + else + nLengthAvail -= nLengthBar; + } + + CSCBArray arrSCBars; + GetRowSizingBars(arrSCBars); + int nNumBars = arrSCBars.GetSize(); + int nDelta = nLengthAvail - nLengthActual; + + // return faster when there is only one sizing bar per row (this one) + if (nNumBars == 1) + { + ASSERT(arrSCBars[0] == this); + + if (nDelta == 0) + return TRUE; + + m_bKeepSize = FALSE; + (bHorz ? m_szHorz.cx : m_szVert.cy) += nDelta; + + return TRUE; + } + + // make all the bars the same width + for (i = 0; i < nNumBars; i++) + if (bHorz) + arrSCBars[i]->m_szHorz.cy = nWidthMax; + else + arrSCBars[i]->m_szVert.cx = nWidthMax; + + // distribute the difference between the bars, + // but don't shrink them below their minsizes + while (nDelta != 0) + { + int nDeltaOld = nDelta; + for (i = 0; i < nNumBars; i++) + { + pBar = arrSCBars[i]; + int nLMin = bHorz ? + pBar->m_szMinHorz.cx : pBar->m_szMinVert.cy; + int nL = bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy; + + if ((nL == nLMin) && (nDelta < 0) || // already at min length + pBar->m_bKeepSize) // or wants to keep its size + continue; + + // sign of nDelta + int nDelta2 = (nDelta < 0) ? -1 : 1; + + (bHorz ? pBar->m_szHorz.cx : pBar->m_szVert.cy) += nDelta2; + nDelta -= nDelta2; + if (nDelta == 0) break; + } + // clear m_bKeepSize flags + if ((nDeltaOld == nDelta) || (nDelta == 0)) + for (i = 0; i < nNumBars; i++) + arrSCBars[i]->m_bKeepSize = FALSE; + } + + return TRUE; +} + +void CSizingControlBar::AlignControlBars() +{ + int nFirst, nLast, nThis; + GetRowInfo(nFirst, nLast, nThis); + + BOOL bHorz = IsHorzDocked(); + BOOL bNeedRecalc = FALSE; + int nAlign = bHorz ? -2 : 0; + + CRect rc, rcDock; + m_pDockBar->GetWindowRect(&rcDock); + + for (int i = nFirst; i <= nLast; i++) + { + CSizingControlBar* pBar = static_cast(m_pDockBar->m_arrBars[i]); + if (HIWORD(pBar) == 0) continue; // placeholder + if (!pBar->IsVisible()) continue; + + pBar->GetWindowRect(&rc); + rc.OffsetRect(-rcDock.TopLeft()); + + if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + rc = CRect(rc.TopLeft(), + bHorz ? pBar->m_szHorz : pBar->m_szVert); + + if ((bHorz ? rc.left : rc.top) != nAlign) + { + if (!bHorz) + rc.OffsetRect(0, nAlign - rc.top - 2); + else if (m_nDockBarID == AFX_IDW_DOCKBAR_TOP) + rc.OffsetRect(nAlign - rc.left, -2); + else + rc.OffsetRect(nAlign - rc.left, 0); + pBar->MoveWindow(rc); + bNeedRecalc = TRUE; + } + nAlign += (bHorz ? rc.Width() : rc.Height()) - 2; + } + + if (bNeedRecalc) + m_pDockSite->DelayRecalcLayout(); +} + +void CSizingControlBar::OnUpdateCmdUI(CFrameWnd* pTarget, + BOOL bDisableIfNoHndler) +{ + UNUSED_ALWAYS(bDisableIfNoHndler); + UNUSED_ALWAYS(pTarget); +} + +void CSizingControlBar::LoadState(LPCTSTR lpszProfileName) +{ + ASSERT_VALID(this); + ASSERT(GetSafeHwnd()); // must be called after Create() + +#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) + // compensate the caption miscalculation in CFrameWnd::SetDockState() + CDockState state; + state.LoadState(lpszProfileName); + + UINT nID = GetDlgCtrlID(); + for (int i = 0; i < state.m_arrBarInfo.GetSize(); i++) + { + CControlBarInfo* pInfo = (CControlBarInfo*)state.m_arrBarInfo[i]; + ASSERT(pInfo != NULL); + if (!pInfo->m_bFloating) + continue; + + // this is a floating dockbar - check the ID array + for (int j = 0; j < pInfo->m_arrBarID.GetSize(); j++) + if ((DWORD) pInfo->m_arrBarID[j] == nID) + { + // found this bar - offset origin and save settings + pInfo->m_pointPos.x++; + pInfo->m_pointPos.y += + ::GetSystemMetrics(SM_CYSMCAPTION) + 1; + pInfo->SaveState(lpszProfileName, i); + } + } +#endif //_SCB_REPLACE_MINIFRAME && !_SCB_MINIFRAME_CAPTION + + CWinApp* pApp = AfxGetApp(); + + TCHAR szSection[256]; + wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName, + GetDlgCtrlID()); + + m_szHorz.cx = max(m_szMinHorz.cx, (int) pApp->GetProfileInt( + szSection, _T("sizeHorzCX"), m_szHorz.cx)); + m_szHorz.cy = max(m_szMinHorz.cy, (int) pApp->GetProfileInt( + szSection, _T("sizeHorzCY"), m_szHorz.cy)); + + m_szVert.cx = max(m_szMinVert.cx, (int) pApp->GetProfileInt( + szSection, _T("sizeVertCX"), m_szVert.cx)); + m_szVert.cy = max(m_szMinVert.cy, (int) pApp->GetProfileInt( + szSection, _T("sizeVertCY"), m_szVert.cy)); + + m_szFloat.cx = max(m_szMinFloat.cx, (int) pApp->GetProfileInt( + szSection, _T("sizeFloatCX"), m_szFloat.cx)); + m_szFloat.cy = max(m_szMinFloat.cy, (int) pApp->GetProfileInt( + szSection, _T("sizeFloatCY"), m_szFloat.cy)); +} + +void CSizingControlBar::SaveState(LPCTSTR lpszProfileName) +{ + // place your SaveState or GlobalSaveState call in + // CMainFrame's OnClose() or DestroyWindow(), not in OnDestroy() + ASSERT_VALID(this); + ASSERT(GetSafeHwnd()); + + CWinApp* pApp = AfxGetApp(); + + TCHAR szSection[256]; + wsprintf(szSection, _T("%s-SCBar-%d"), lpszProfileName, + GetDlgCtrlID()); + + pApp->WriteProfileInt(szSection, _T("sizeHorzCX"), m_szHorz.cx); + pApp->WriteProfileInt(szSection, _T("sizeHorzCY"), m_szHorz.cy); + + pApp->WriteProfileInt(szSection, _T("sizeVertCX"), m_szVert.cx); + pApp->WriteProfileInt(szSection, _T("sizeVertCY"), m_szVert.cy); + + pApp->WriteProfileInt(szSection, _T("sizeFloatCX"), m_szFloat.cx); + pApp->WriteProfileInt(szSection, _T("sizeFloatCY"), m_szFloat.cy); +} + +void CSizingControlBar::GlobalLoadState(CFrameWnd* pFrame, + LPCTSTR lpszProfileName) +{ + POSITION pos = pFrame->m_listControlBars.GetHeadPosition(); + while (pos != NULL) + { + CSizingControlBar* pBar = static_cast (pFrame->m_listControlBars.GetNext(pos)); + ASSERT(pBar != NULL); + if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + pBar->LoadState(lpszProfileName); + } +} + +void CSizingControlBar::GlobalSaveState(CFrameWnd* pFrame, + LPCTSTR lpszProfileName) +{ + POSITION pos = pFrame->m_listControlBars.GetHeadPosition(); + while (pos != NULL) + { + CSizingControlBar* pBar = static_cast (pFrame->m_listControlBars.GetNext(pos)); + ASSERT(pBar != NULL); + if (pBar->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + pBar->SaveState(lpszProfileName); + } +} + +//mpc-hc custom code start +void CSizingControlBar::mpc_fillNcBG(CDC* mdc, CRect rcDraw) { + mdc->FillRect(rcDraw, CBrush::FromHandle( + (HBRUSH)GetClassLongPtr(m_hWnd, GCLP_HBRBACKGROUND))); +} +//mpc-hc custom code end + +#ifdef _SCB_REPLACE_MINIFRAME +#ifndef _SCB_MINIFRAME_CAPTION +///////////////////////////////////////////////////////////////////////////// +// CSCBDockContext Drag Operations + +static void AdjustRectangle(CRect& rect, CPoint pt) +{ + int nXOffset = (pt.x < rect.left) ? (pt.x - rect.left) : + (pt.x > rect.right) ? (pt.x - rect.right) : 0; + int nYOffset = (pt.y < rect.top) ? (pt.y - rect.top) : + (pt.y > rect.bottom) ? (pt.y - rect.bottom) : 0; + rect.OffsetRect(nXOffset, nYOffset); +} + +void CSCBDockContext::StartDrag(CPoint pt) +{ + ASSERT_VALID(m_pBar); + m_bDragging = TRUE; + + InitLoop(); + + ASSERT((m_pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) != 0); + + // get true bar size (including borders) + CRect rect; + m_pBar->GetWindowRect(rect); + m_ptLast = pt; + CSize sizeHorz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK); + CSize sizeVert = m_pBar->CalcDynamicLayout(0, LM_VERTDOCK); + CSize sizeFloat = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH); + + m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz); + m_rectDragVert = CRect(rect.TopLeft(), sizeVert); + + // calculate frame dragging rectangle + m_rectFrameDragHorz = CRect(rect.TopLeft(), sizeFloat); + +#ifdef _MAC + CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, + WS_THICKFRAME, WS_EX_FORCESIZEBOX); +#else + CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz, WS_THICKFRAME); +#endif + m_rectFrameDragHorz.DeflateRect(2, 2); + m_rectFrameDragVert = m_rectFrameDragHorz; + + // adjust rectangles so that point is inside + AdjustRectangle(m_rectDragHorz, pt); + AdjustRectangle(m_rectDragVert, pt); + AdjustRectangle(m_rectFrameDragHorz, pt); + AdjustRectangle(m_rectFrameDragVert, pt); + + // initialize tracking state and enter tracking loop + m_dwOverDockStyle = CanDock(); + Move(pt); // call it here to handle special keys + Track(); +} +#endif //_SCB_MINIFRAME_CAPTION + +///////////////////////////////////////////////////////////////////////////// +// CSCBMiniDockFrameWnd + +IMPLEMENT_DYNCREATE(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd); + +BEGIN_MESSAGE_MAP(CSCBMiniDockFrameWnd, baseCSCBMiniDockFrameWnd) + //{{AFX_MSG_MAP(CSCBMiniDockFrameWnd) + ON_WM_NCLBUTTONDOWN() + ON_WM_GETMINMAXINFO() + ON_WM_WINDOWPOSCHANGING() + ON_WM_SIZE() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +BOOL CSCBMiniDockFrameWnd::Create(CWnd* pParent, DWORD dwBarStyle) +{ + // set m_bInRecalcLayout to avoid flashing during creation + // RecalcLayout will be called once something is docked + m_bInRecalcLayout = TRUE; + + DWORD dwStyle = WS_POPUP|WS_CAPTION|WS_SYSMENU|MFS_MOVEFRAME| + MFS_4THICKFRAME|MFS_SYNCACTIVE|MFS_BLOCKSYSMENU| + FWS_SNAPTOBARS; + + if (dwBarStyle & CBRS_SIZE_DYNAMIC) + dwStyle &= ~MFS_MOVEFRAME; + + DWORD dwExStyle = 0; +#ifdef _MAC + if (dwBarStyle & CBRS_SIZE_DYNAMIC) + dwExStyle |= WS_EX_FORCESIZEBOX; + else + dwStyle &= ~(MFS_MOVEFRAME|MFS_4THICKFRAME); +#endif + + if (!CMiniFrameWnd::CreateEx(dwExStyle, + NULL, "", dwStyle, rectDefault, pParent)) + { + m_bInRecalcLayout = FALSE; + return FALSE; + } + dwStyle = dwBarStyle & (CBRS_ALIGN_LEFT|CBRS_ALIGN_RIGHT) ? + CBRS_ALIGN_LEFT : CBRS_ALIGN_TOP; + dwStyle |= dwBarStyle & CBRS_FLOAT_MULTI; + CMenu* pSysMenu = GetSystemMenu(FALSE); + //pSysMenu->DeleteMenu(SC_SIZE, MF_BYCOMMAND); + CString strHide; + if (strHide.LoadString(AFX_IDS_HIDE)) + { + pSysMenu->DeleteMenu(SC_CLOSE, MF_BYCOMMAND); + pSysMenu->AppendMenu(MF_STRING|MF_ENABLED, SC_CLOSE, strHide); + } + + // must initially create with parent frame as parent + if (!m_wndDockBar.Create(pParent, WS_CHILD | WS_VISIBLE | dwStyle, + AFX_IDW_DOCKBAR_FLOAT)) + { + m_bInRecalcLayout = FALSE; + return FALSE; + } + + // set parent to CMiniDockFrameWnd + m_wndDockBar.SetParent(this); + m_bInRecalcLayout = FALSE; + + return TRUE; +} + +void CSCBMiniDockFrameWnd::OnNcLButtonDown(UINT nHitTest, CPoint point) +{ + if (nHitTest == HTCAPTION || nHitTest == HTCLOSE) + { + baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); + return; + } + + if (GetSizingControlBar() != NULL) + CMiniFrameWnd::OnNcLButtonDown(nHitTest, point); + else + baseCSCBMiniDockFrameWnd::OnNcLButtonDown(nHitTest, point); +} + +CSizingControlBar* CSCBMiniDockFrameWnd::GetSizingControlBar() +{ + CWnd* pWnd = GetWindow(GW_CHILD); // get the dockbar + if (pWnd == NULL) + return NULL; + + pWnd = pWnd->GetWindow(GW_CHILD); // get the controlbar + if (pWnd == NULL) + return NULL; + + if (!pWnd->IsKindOf(RUNTIME_CLASS(CSizingControlBar))) + return NULL; + + return static_cast (pWnd); +} + +void CSCBMiniDockFrameWnd::OnSize(UINT nType, int cx, int cy) +{ + CSizingControlBar* pBar = GetSizingControlBar(); + if ((pBar != NULL) && (GetStyle() & MFS_4THICKFRAME) == 0 + && pBar->IsVisible() && + cx + 4 >= pBar->m_szMinFloat.cx && + cy + 4 >= pBar->m_szMinFloat.cy) + pBar->m_szFloat = CSize(cx + 4, cy + 4); + + baseCSCBMiniDockFrameWnd::OnSize(nType, cx, cy); +} + +void CSCBMiniDockFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) +{ + baseCSCBMiniDockFrameWnd::OnGetMinMaxInfo(lpMMI); + + CSizingControlBar* pBar = GetSizingControlBar(); + if (pBar != NULL) + { + CRect r(CPoint(0, 0), pBar->m_szMinFloat - CSize(4, 4)); +#ifndef _SCB_MINIFRAME_CAPTION + CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME); +#else + CMiniFrameWnd::CalcBorders(&r, WS_THICKFRAME|WS_CAPTION); +#endif //_SCB_MINIFRAME_CAPTION + lpMMI->ptMinTrackSize.x = r.Width(); + lpMMI->ptMinTrackSize.y = r.Height(); +// mpc-hc custom code start + if(pBar->m_bFixedFloat) + { + lpMMI->ptMinTrackSize.x = pBar->m_szFixedFloat.cx; + lpMMI->ptMinTrackSize.y = pBar->m_szFixedFloat.cy; + lpMMI->ptMaxTrackSize.x = pBar->m_szFixedFloat.cx; + lpMMI->ptMaxTrackSize.y = pBar->m_szFixedFloat.cy; + } +// mpc-hc custom code end + } +} + +void CSCBMiniDockFrameWnd::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) +{ + if ((GetStyle() & MFS_4THICKFRAME) != 0) + { + CSizingControlBar* pBar = GetSizingControlBar(); + if (pBar != NULL) + { + lpwndpos->flags |= SWP_NOSIZE; // don't size this time + // prevents flicker + pBar->m_pDockBar->ModifyStyle(0, WS_CLIPCHILDREN); + + // enable diagonal resizing + DWORD dwStyleRemove = MFS_4THICKFRAME; +#ifndef _SCB_MINIFRAME_CAPTION + // remove caption + dwStyleRemove |= WS_SYSMENU|WS_CAPTION; +#endif + ModifyStyle(dwStyleRemove, 0); + + DelayRecalcLayout(); + pBar->PostMessage(WM_NCPAINT); + } + } + + CMiniFrameWnd::OnWindowPosChanging(lpwndpos); +} + +#endif //_SCB_REPLACE_MINIFRAME diff --git a/src/thirdparty/sizecbar/sizecbar.h b/src/thirdparty/sizecbar/sizecbar.h index d3338d629e5..10de2dc68cb 100644 --- a/src/thirdparty/sizecbar/sizecbar.h +++ b/src/thirdparty/sizecbar/sizecbar.h @@ -1,257 +1,257 @@ -///////////////////////////////////////////////////////////////////////// -// -// CSizingControlBar Version 2.45 -// -// Created: Jan 24, 1998 Last Modified: April 16, 2010 -// -// See the official site at www.datamekanix.com for documentation and -// the latest news. -// -///////////////////////////////////////////////////////////////////////// -// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. -// -// This code is free for personal and commercial use, providing this -// notice remains intact in the source files and all eventual changes are -// clearly marked with comments. -// -// No warrantee of any kind, express or implied, is included with this -// software; use at your own risk, responsibility for damages (if any) to -// anyone resulting from the use of this software rests entirely with the -// user. -// -// Send bug reports, bug fixes, enhancements, requests, flames, etc. to -// cristi@datamekanix.com . -///////////////////////////////////////////////////////////////////////// - -#if !defined(__SIZECBAR_H__) -#define __SIZECBAR_H__ - -#include // for CDockContext -#include // for CTypedPtrArray - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 - - -#if defined(_SCB_MINIFRAME_CAPTION) && !defined(_SCB_REPLACE_MINIFRAME) - #error "_SCB_MINIFRAME_CAPTION requires _SCB_REPLACE_MINIFRAME" -#endif - -///////////////////////////////////////////////////////////////////////// -// CSCBDockBar dummy class for access to protected members - -class CSCBDockBar : public CDockBar -{ - friend class CSizingControlBar; -}; - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar control bar styles - -#define SCBS_EDGELEFT 0x00000001 -#define SCBS_EDGERIGHT 0x00000002 -#define SCBS_EDGETOP 0x00000004 -#define SCBS_EDGEBOTTOM 0x00000008 -#define SCBS_EDGEALL 0x0000000F -#define SCBS_SHOWEDGES 0x00000010 -#define SCBS_SIZECHILD 0x00000020 - -///////////////////////////////////////////////////////////////////////// -// CSizingControlBar control bar - -#ifndef baseCSizingControlBar -#define baseCSizingControlBar CControlBar -#endif - -class CSizingControlBar; -typedef CTypedPtrArray CSCBArray; - -class CSizingControlBar : public baseCSizingControlBar -{ - DECLARE_DYNAMIC(CSizingControlBar); - -// Construction -public: - CSizingControlBar(); - - virtual BOOL Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, - CSize sizeDefault, BOOL bHasGripper, - UINT nID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP); - virtual BOOL Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, - UINT nID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP); - -// Attributes -public: - const BOOL IsFloating() const; - const BOOL IsHorzDocked() const; - const BOOL IsVertDocked() const; - const BOOL IsSideTracking() const; - const BOOL GetSCBStyle() const {return m_dwSCBStyle;} - -// Operations -public: -#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) - void EnableDocking(DWORD dwDockStyle); -#endif - virtual void LoadState(LPCTSTR lpszProfileName); - virtual void SaveState(LPCTSTR lpszProfileName); - static void GlobalLoadState(CFrameWnd* pFrame, LPCTSTR lpszProfileName); - static void GlobalSaveState(CFrameWnd* pFrame, LPCTSTR lpszProfileName); - void SetSCBStyle(DWORD dwSCBStyle) - {m_dwSCBStyle = (dwSCBStyle & ~SCBS_EDGEALL);} - -//mpc-hc custom code start - virtual void mpc_fillNcBG(CDC *mdc, CRect rcDraw); - - void SetWidth(const int nWidth) - { - m_szFloat.cx = m_szHorz.cx = m_szVert.cx = nWidth; - m_pDockSite->DelayRecalcLayout(); - } - - void SetHeight(const int nHeight) - { - m_szFloat.cy = m_szHorz.cy = m_szVert.cy = nHeight; - m_pDockSite->DelayRecalcLayout(); - } -//mpc-hc custom code end - -// Overridables - virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); - -// Overrides -public: - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CSizingControlBar) - public: - virtual CSize CalcFixedLayout(BOOL bStretch, BOOL bHorz); - virtual CSize CalcDynamicLayout(int nLength, DWORD dwMode); - //}}AFX_VIRTUAL - -// Implementation -public: - virtual ~CSizingControlBar(); - -protected: - // implementation helpers - UINT GetEdgeHTCode(int nEdge); - BOOL GetEdgeRect(CRect rcWnd, UINT nHitTest, CRect& rcEdge); - virtual void StartTracking(UINT nHitTest, CPoint point); - virtual void StopTracking(); - virtual void OnTrackUpdateSize(CPoint& point); - virtual void OnTrackInvertTracker(); - virtual void NcPaintGripper(CDC* pDC, CRect rcClient); - virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); - - virtual void AlignControlBars(); - void GetRowInfo(int& nFirst, int& nLast, int& nThis); - void GetRowSizingBars(CSCBArray& arrSCBars); - void GetRowSizingBars(CSCBArray& arrSCBars, int& nThis); - BOOL NegotiateSpace(int nLengthTotal, BOOL bHorz); - -protected: - DWORD m_dwSCBStyle; - UINT m_htEdge; - - CSize m_szHorz; - CSize m_szVert; - CSize m_szFloat; - CSize m_szMinHorz; - CSize m_szMinVert; - CSize m_szMinFloat; - int m_nTrackPosMin; - int m_nTrackPosMax; - int m_nTrackPosOld; - int m_nTrackEdgeOfs; - BOOL m_bTracking; - BOOL m_bKeepSize; - BOOL m_bParentSizing; - BOOL m_bDragShowContent; - UINT m_nDockBarID; - int m_cxEdge; - -//mpc-hc custom code start - BOOL m_bFixedFloat; - CSize m_szFixedFloat; -//mpc-hc custom code end - -// Generated message map functions -protected: - //{{AFX_MSG(CSizingControlBar) - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnNcPaint(); - afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp); - afx_msg LRESULT OnNcHitTest(CPoint point); - afx_msg void OnCaptureChanged(CWnd *pWnd); - afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); - afx_msg void OnRButtonDown(UINT nFlags, CPoint point); - afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); - afx_msg void OnPaint(); - afx_msg void OnClose(); - afx_msg void OnSize(UINT nType, int cx, int cy); - //}}AFX_MSG - afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam); - - DECLARE_MESSAGE_MAP() - -#ifdef _SCB_REPLACE_MINIFRAME - friend class CSCBMiniDockFrameWnd; -#endif //_SCB_REPLACE_MINIFRAME -}; - -#ifdef _SCB_REPLACE_MINIFRAME -#ifndef _SCB_MINIFRAME_CAPTION -///////////////////////////////////////////////////////////////////////// -// CSCBDockContext dockcontext - -class CSCBDockContext : public CDockContext -{ -public: -// Construction - CSCBDockContext(CControlBar* pBar) : CDockContext(pBar) {} - -// Drag Operations - virtual void StartDrag(CPoint pt); -}; -#endif //_SCB_MINIFRAME_CAPTION - -///////////////////////////////////////////////////////////////////////// -// CSCBMiniDockFrameWnd miniframe - -#ifndef baseCSCBMiniDockFrameWnd -#define baseCSCBMiniDockFrameWnd CMiniDockFrameWnd -#endif - -class CSCBMiniDockFrameWnd : public baseCSCBMiniDockFrameWnd -{ - DECLARE_DYNCREATE(CSCBMiniDockFrameWnd) - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CSCBMiniDockFrameWnd) - public: - virtual BOOL Create(CWnd* pParent, DWORD dwBarStyle); - //}}AFX_VIRTUAL - -// Implementation -public: - CSizingControlBar* GetSizingControlBar(); - - //{{AFX_MSG(CSCBMiniDockFrameWnd) - afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); - afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); - afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); - afx_msg void OnSize(UINT nType, int cx, int cy); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; -#endif //_SCB_REPLACE_MINIFRAME - -#endif // !defined(__SIZECBAR_H__) - +///////////////////////////////////////////////////////////////////////// +// +// CSizingControlBar Version 2.45 +// +// Created: Jan 24, 1998 Last Modified: April 16, 2010 +// +// See the official site at www.datamekanix.com for documentation and +// the latest news. +// +///////////////////////////////////////////////////////////////////////// +// Copyright (C) 1998-2010 Cristi Posea. All rights reserved. +// +// This code is free for personal and commercial use, providing this +// notice remains intact in the source files and all eventual changes are +// clearly marked with comments. +// +// No warrantee of any kind, express or implied, is included with this +// software; use at your own risk, responsibility for damages (if any) to +// anyone resulting from the use of this software rests entirely with the +// user. +// +// Send bug reports, bug fixes, enhancements, requests, flames, etc. to +// cristi@datamekanix.com . +///////////////////////////////////////////////////////////////////////// + +#if !defined(__SIZECBAR_H__) +#define __SIZECBAR_H__ + +#include // for CDockContext +#include // for CTypedPtrArray + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + + +#if defined(_SCB_MINIFRAME_CAPTION) && !defined(_SCB_REPLACE_MINIFRAME) + #error "_SCB_MINIFRAME_CAPTION requires _SCB_REPLACE_MINIFRAME" +#endif + +///////////////////////////////////////////////////////////////////////// +// CSCBDockBar dummy class for access to protected members + +class CSCBDockBar : public CDockBar +{ + friend class CSizingControlBar; +}; + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar control bar styles + +#define SCBS_EDGELEFT 0x00000001 +#define SCBS_EDGERIGHT 0x00000002 +#define SCBS_EDGETOP 0x00000004 +#define SCBS_EDGEBOTTOM 0x00000008 +#define SCBS_EDGEALL 0x0000000F +#define SCBS_SHOWEDGES 0x00000010 +#define SCBS_SIZECHILD 0x00000020 + +///////////////////////////////////////////////////////////////////////// +// CSizingControlBar control bar + +#ifndef baseCSizingControlBar +#define baseCSizingControlBar CControlBar +#endif + +class CSizingControlBar; +typedef CTypedPtrArray CSCBArray; + +class CSizingControlBar : public baseCSizingControlBar +{ + DECLARE_DYNAMIC(CSizingControlBar); + +// Construction +public: + CSizingControlBar(); + + virtual BOOL Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, + CSize sizeDefault, BOOL bHasGripper, + UINT nID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP); + virtual BOOL Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, + UINT nID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP); + +// Attributes +public: + const BOOL IsFloating() const; + const BOOL IsHorzDocked() const; + const BOOL IsVertDocked() const; + const BOOL IsSideTracking() const; + const BOOL GetSCBStyle() const {return m_dwSCBStyle;} + +// Operations +public: +#if defined(_SCB_REPLACE_MINIFRAME) && !defined(_SCB_MINIFRAME_CAPTION) + void EnableDocking(DWORD dwDockStyle); +#endif + virtual void LoadState(LPCTSTR lpszProfileName); + virtual void SaveState(LPCTSTR lpszProfileName); + static void GlobalLoadState(CFrameWnd* pFrame, LPCTSTR lpszProfileName); + static void GlobalSaveState(CFrameWnd* pFrame, LPCTSTR lpszProfileName); + void SetSCBStyle(DWORD dwSCBStyle) + {m_dwSCBStyle = (dwSCBStyle & ~SCBS_EDGEALL);} + +//mpc-hc custom code start + virtual void mpc_fillNcBG(CDC *mdc, CRect rcDraw); + + void SetWidth(const int nWidth) + { + m_szFloat.cx = m_szHorz.cx = m_szVert.cx = nWidth; + m_pDockSite->DelayRecalcLayout(); + } + + void SetHeight(const int nHeight) + { + m_szFloat.cy = m_szHorz.cy = m_szVert.cy = nHeight; + m_pDockSite->DelayRecalcLayout(); + } +//mpc-hc custom code end + +// Overridables + virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); + +// Overrides +public: + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSizingControlBar) + public: + virtual CSize CalcFixedLayout(BOOL bStretch, BOOL bHorz); + virtual CSize CalcDynamicLayout(int nLength, DWORD dwMode); + //}}AFX_VIRTUAL + +// Implementation +public: + virtual ~CSizingControlBar(); + +protected: + // implementation helpers + UINT GetEdgeHTCode(int nEdge); + BOOL GetEdgeRect(CRect rcWnd, UINT nHitTest, CRect& rcEdge); + virtual void StartTracking(UINT nHitTest, CPoint point); + virtual void StopTracking(); + virtual void OnTrackUpdateSize(CPoint& point); + virtual void OnTrackInvertTracker(); + virtual void NcPaintGripper(CDC* pDC, CRect rcClient); + virtual void NcCalcClient(LPRECT pRc, UINT nDockBarID); + + virtual void AlignControlBars(); + void GetRowInfo(int& nFirst, int& nLast, int& nThis); + void GetRowSizingBars(CSCBArray& arrSCBars); + void GetRowSizingBars(CSCBArray& arrSCBars, int& nThis); + BOOL NegotiateSpace(int nLengthTotal, BOOL bHorz); + +protected: + DWORD m_dwSCBStyle; + UINT m_htEdge; + + CSize m_szHorz; + CSize m_szVert; + CSize m_szFloat; + CSize m_szMinHorz; + CSize m_szMinVert; + CSize m_szMinFloat; + int m_nTrackPosMin; + int m_nTrackPosMax; + int m_nTrackPosOld; + int m_nTrackEdgeOfs; + BOOL m_bTracking; + BOOL m_bKeepSize; + BOOL m_bParentSizing; + BOOL m_bDragShowContent; + UINT m_nDockBarID; + int m_cxEdge; + +//mpc-hc custom code start + BOOL m_bFixedFloat; + CSize m_szFixedFloat; +//mpc-hc custom code end + +// Generated message map functions +protected: + //{{AFX_MSG(CSizingControlBar) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnNcPaint(); + afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp); + afx_msg LRESULT OnNcHitTest(CPoint point); + afx_msg void OnCaptureChanged(CWnd *pWnd); + afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); + afx_msg void OnPaint(); + afx_msg void OnClose(); + afx_msg void OnSize(UINT nType, int cx, int cy); + //}}AFX_MSG + afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam); + + DECLARE_MESSAGE_MAP() + +#ifdef _SCB_REPLACE_MINIFRAME + friend class CSCBMiniDockFrameWnd; +#endif //_SCB_REPLACE_MINIFRAME +}; + +#ifdef _SCB_REPLACE_MINIFRAME +#ifndef _SCB_MINIFRAME_CAPTION +///////////////////////////////////////////////////////////////////////// +// CSCBDockContext dockcontext + +class CSCBDockContext : public CDockContext +{ +public: +// Construction + CSCBDockContext(CControlBar* pBar) : CDockContext(pBar) {} + +// Drag Operations + virtual void StartDrag(CPoint pt); +}; +#endif //_SCB_MINIFRAME_CAPTION + +///////////////////////////////////////////////////////////////////////// +// CSCBMiniDockFrameWnd miniframe + +#ifndef baseCSCBMiniDockFrameWnd +#define baseCSCBMiniDockFrameWnd CMiniDockFrameWnd +#endif + +class CSCBMiniDockFrameWnd : public baseCSCBMiniDockFrameWnd +{ + DECLARE_DYNCREATE(CSCBMiniDockFrameWnd) + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CSCBMiniDockFrameWnd) + public: + virtual BOOL Create(CWnd* pParent, DWORD dwBarStyle); + //}}AFX_VIRTUAL + +// Implementation +public: + CSizingControlBar* GetSizingControlBar(); + + //{{AFX_MSG(CSCBMiniDockFrameWnd) + afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point); + afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI); + afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); + afx_msg void OnSize(UINT nType, int cx, int cy); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; +#endif //_SCB_REPLACE_MINIFRAME + +#endif // !defined(__SIZECBAR_H__) + diff --git a/src/thirdparty/sizecbar/sizecbar.vcxproj b/src/thirdparty/sizecbar/sizecbar.vcxproj index f9273bf15ec..ead70eb5d60 100644 --- a/src/thirdparty/sizecbar/sizecbar.vcxproj +++ b/src/thirdparty/sizecbar/sizecbar.vcxproj @@ -1,67 +1,67 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {61E6EB4D-2F1A-443B-94B0-E8200B26E99F} - sizecbar - MFCProj - sizecbar - - - - - StaticLibrary - Static - Unicode - - - - - - - - - - - False - - - - _LIB;%(PreprocessorDefinitions) - - - - - - - - Create - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {61E6EB4D-2F1A-443B-94B0-E8200B26E99F} + sizecbar + MFCProj + sizecbar + + + + + StaticLibrary + Static + Unicode + + + + + + + + + + + False + + + + _LIB;%(PreprocessorDefinitions) + + + + + + + + Create + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/sizecbar/sizecbar.vcxproj.filters b/src/thirdparty/sizecbar/sizecbar.vcxproj.filters index c73b56b00a4..23fc896d1cb 100644 --- a/src/thirdparty/sizecbar/sizecbar.vcxproj.filters +++ b/src/thirdparty/sizecbar/sizecbar.vcxproj.filters @@ -1,41 +1,41 @@ - - - - - {8d9a4844-0f68-4c0d-a6f5-a20f411affaa} - cpp;c;cxx;def;odl;idl;hpj;bat;asm - - - {c249b3fd-b54b-4fe2-b48b-b2ecf391f42a} - h;hpp;hxx;hm;inl;inc - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {8d9a4844-0f68-4c0d-a6f5-a20f411affaa} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c249b3fd-b54b-4fe2-b48b-b2ecf391f42a} + h;hpp;hxx;hm;inl;inc + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/sizecbar/stdafx.cpp b/src/thirdparty/sizecbar/stdafx.cpp index 36116eb6a86..784f2cebc5c 100644 --- a/src/thirdparty/sizecbar/stdafx.cpp +++ b/src/thirdparty/sizecbar/stdafx.cpp @@ -1,22 +1,22 @@ -/* - * (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 . - * - */ - -#include "stdafx.h" +/* + * (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 . + * + */ + +#include "stdafx.h" diff --git a/src/thirdparty/sizecbar/stdafx.h b/src/thirdparty/sizecbar/stdafx.h index 228e406bec3..9efc54936db 100644 --- a/src/thirdparty/sizecbar/stdafx.h +++ b/src/thirdparty/sizecbar/stdafx.h @@ -1,33 +1,33 @@ -/* - * (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 . - * - */ - -#pragma once - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#endif -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#endif - -#include "scbarcf.h" +/* + * (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 . + * + */ + +#pragma once + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +#include "scbarcf.h" diff --git a/src/thirdparty/unrar/acknow.txt b/src/thirdparty/unrar/acknow.txt index b8d35a6aac2..ec2c2c7cdcf 100644 --- a/src/thirdparty/unrar/acknow.txt +++ b/src/thirdparty/unrar/acknow.txt @@ -1,59 +1,59 @@ - ACKNOWLEDGMENTS - -* We used "Screaming Fast Galois Field Arithmetic Using Intel - SIMD Instructions" paper by James S. Plank, Kevin M. Greenan - and Ethan L. Miller to improve Reed-Solomon coding performance. - Also we are grateful to Artem Drobanov and Bulat Ziganshin - for samples and ideas allowed to make Reed-Solomon coding - more efficient. - -* RAR4 text compression algorithm is based on Dmitry Shkarin PPMII - and Dmitry Subbotin carryless rangecoder public domain source code. - You can find it in ftp.elf.stuba.sk/pub/pc/pack. - -* RAR encryption includes parts of public domain code - from Szymon Stefanek AES and Steve Reid SHA-1 implementations. - -* With exception of SFX modules, RAR uses CRC32 function based - on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code - is available here: - - https://sourceforge.net/projects/slicing-by-8/ - - Original Intel Slicing-by-8 code is licensed under BSD License - available at http://www.opensource.org/licenses/bsd-license.html - - Copyright (c) 2004-2006 Intel Corporation. - All Rights Reserved - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with - the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ), - designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn - and Christian Winnerlein. - -* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed - to significantly improve RAR compression and speed. + ACKNOWLEDGMENTS + +* We used "Screaming Fast Galois Field Arithmetic Using Intel + SIMD Instructions" paper by James S. Plank, Kevin M. Greenan + and Ethan L. Miller to improve Reed-Solomon coding performance. + Also we are grateful to Artem Drobanov and Bulat Ziganshin + for samples and ideas allowed to make Reed-Solomon coding + more efficient. + +* RAR4 text compression algorithm is based on Dmitry Shkarin PPMII + and Dmitry Subbotin carryless rangecoder public domain source code. + You can find it in ftp.elf.stuba.sk/pub/pc/pack. + +* RAR encryption includes parts of public domain code + from Szymon Stefanek AES and Steve Reid SHA-1 implementations. + +* With exception of SFX modules, RAR uses CRC32 function based + on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code + is available here: + + https://sourceforge.net/projects/slicing-by-8/ + + Original Intel Slicing-by-8 code is licensed under BSD License + available at http://www.opensource.org/licenses/bsd-license.html + + Copyright (c) 2004-2006 Intel Corporation. + All Rights Reserved + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with + the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ), + designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn + and Christian Winnerlein. + +* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed + to significantly improve RAR compression and speed. diff --git a/src/thirdparty/unrar/dll.def b/src/thirdparty/unrar/dll.def index a7241141a07..3c9a2c83ab5 100644 --- a/src/thirdparty/unrar/dll.def +++ b/src/thirdparty/unrar/dll.def @@ -1,13 +1,13 @@ -EXPORTS - RAROpenArchive - RAROpenArchiveEx - RARCloseArchive - RARReadHeader - RARReadHeaderEx - RARProcessFile - RARProcessFileW - RARSetCallback - RARSetChangeVolProc - RARSetProcessDataProc - RARSetPassword - RARGetDllVersion +EXPORTS + RAROpenArchive + RAROpenArchiveEx + RARCloseArchive + RARReadHeader + RARReadHeaderEx + RARProcessFile + RARProcessFileW + RARSetCallback + RARSetChangeVolProc + RARSetProcessDataProc + RARSetPassword + RARGetDllVersion diff --git a/src/thirdparty/unrar/dll.rc b/src/thirdparty/unrar/dll.rc index 645f8b4b99f..b7f07785b11 100644 --- a/src/thirdparty/unrar/dll.rc +++ b/src/thirdparty/unrar/dll.rc @@ -1,28 +1,28 @@ -#include -#include - -VS_VERSION_INFO VERSIONINFO +#include +#include + +VS_VERSION_INFO VERSIONINFO FILEVERSION 6, 24, 100, 1007 PRODUCTVERSION 6, 24, 100, 1007 -FILEOS VOS__WINDOWS32 -FILETYPE VFT_APP -{ - BLOCK "StringFileInfo" - { - BLOCK "040904E4" - { - VALUE "CompanyName", "Alexander Roshal\0" - VALUE "ProductName", "RAR decompression library\0" - VALUE "FileDescription", "RAR decompression library\0" +FILEOS VOS__WINDOWS32 +FILETYPE VFT_APP +{ + BLOCK "StringFileInfo" + { + BLOCK "040904E4" + { + VALUE "CompanyName", "Alexander Roshal\0" + VALUE "ProductName", "RAR decompression library\0" + VALUE "FileDescription", "RAR decompression library\0" VALUE "FileVersion", "6.24.0\0" VALUE "ProductVersion", "6.24.0\0" VALUE "LegalCopyright", "Copyright Alexander Roshal 1993-2023\0" - VALUE "OriginalFilename", "Unrar.dll\0" - } - } - BLOCK "VarFileInfo" - { - VALUE "Translation", 0x0409, 0x04E4 - } -} - + VALUE "OriginalFilename", "Unrar.dll\0" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04E4 + } +} + diff --git a/src/thirdparty/unrar/unrar.vcxproj b/src/thirdparty/unrar/unrar.vcxproj index 7445a240edf..952243010a2 100644 --- a/src/thirdparty/unrar/unrar.vcxproj +++ b/src/thirdparty/unrar/unrar.vcxproj @@ -1,173 +1,173 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - unrar - {DA8461C4-7683-4360-9372-2A9E0F1795C2} - Win32Proj - - - - - StaticLibrary - MultiByte - - - - - - - - - - - - - rar.hpp - _LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - - - - - - - - - - - - - - - - - - - - - - - NotUsing - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + unrar + {DA8461C4-7683-4360-9372-2A9E0F1795C2} + Win32Proj + + + + + StaticLibrary + MultiByte + + + + + + + + + + + + + rar.hpp + _LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + NotUsing + + + + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/unrar/unrar.vcxproj.filters b/src/thirdparty/unrar/unrar.vcxproj.filters index ef1d860ccee..5a8f8aa24b4 100644 --- a/src/thirdparty/unrar/unrar.vcxproj.filters +++ b/src/thirdparty/unrar/unrar.vcxproj.filters @@ -1,365 +1,365 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/thirdparty/zlib/zlib.vcxproj b/src/thirdparty/zlib/zlib.vcxproj index c2ee8fed805..41fe3e42579 100644 --- a/src/thirdparty/zlib/zlib.vcxproj +++ b/src/thirdparty/zlib/zlib.vcxproj @@ -1,84 +1,84 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {2FCD4B66-9CF9-4C8F-BC70-37CD20002D49} - zlib - Win32Proj - zlib - - - - - StaticLibrary - Unicode - - - - - - - - - - - - - _LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - NotUsing - TurnOffAllWarnings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {2FCD4B66-9CF9-4C8F-BC70-37CD20002D49} + zlib + Win32Proj + zlib + + + + + StaticLibrary + Unicode + + + + + + + + + + + + + _LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + NotUsing + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/thirdparty/zlib/zlib.vcxproj.filters b/src/thirdparty/zlib/zlib.vcxproj.filters index e6e5259d9e6..6030351d8b4 100644 --- a/src/thirdparty/zlib/zlib.vcxproj.filters +++ b/src/thirdparty/zlib/zlib.vcxproj.filters @@ -1,101 +1,101 @@ - - - - - {65ae02f7-7823-4d41-b101-45ef452df4b8} - cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90 - - - {53954850-f4af-433e-97cf-8e28a81233fa} - h;hpp;hxx;hm;inl;fi;fd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {65ae02f7-7823-4d41-b101-45ef452df4b8} + cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90 + + + {53954850-f4af-433e-97cf-8e28a81233fa} + h;hpp;hxx;hm;inl;fi;fd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/update_version.bat b/update_version.bat index 13a2c8b1a9a..e2555950014 100755 --- a/update_version.bat +++ b/update_version.bat @@ -1,51 +1,51 @@ -@ECHO OFF -REM (C) 2010-2020 see Authors.txt -REM -REM This file is part of MPC-HC. -REM -REM MPC-HC is free software; you can redistribute it and/or modify -REM it under the terms of the GNU General Public License as published by -REM the Free Software Foundation; either version 3 of the License, or -REM (at your option) any later version. -REM -REM MPC-HC is distributed in the hope that it will be useful, -REM but WITHOUT ANY WARRANTY; without even the implied warranty of -REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -REM GNU General Public License for more details. -REM -REM You should have received a copy of the GNU General Public License -REM along with this program. If not, see . - - -SETLOCAL -SET "FILE_DIR=%~dp0" -PUSHD "%FILE_DIR%" - -SET "COMMON=%FILE_DIR%\common.bat" - -IF EXIST "build.user.bat" CALL "build.user.bat" - -IF NOT DEFINED MPCHC_GIT IF DEFINED GIT (SET MPCHC_GIT=%GIT%) ELSE (SET MPCHC_GIT="C:\Program Files\Git") - -SET "PATH=%MPCHC_GIT%\bin;%PATH%" - -CALL "%COMMON%" :SubDoesExist bash.exe -IF %ERRORLEVEL% NEQ 0 GOTO MissingVar - -bash.exe ./version.sh %* - - -:END -POPD -ENDLOCAL -EXIT /B - - -:MissingVar -copy /Y "build\version_rev_fallback.h" "build\version_rev.h" -copy /Y "src\mpc-hc\res\mpc-hc.exe.manifest.fallback" "src\mpc-hc\res\mpc-hc.exe.manifest" -ECHO Not all build dependencies were found: Missing bash.exe in Git installation -ECHO. -ECHO See "docs\Compilation.md" for more information. -ENDLOCAL -EXIT /B +@ECHO OFF +REM (C) 2010-2020 see Authors.txt +REM +REM This file is part of MPC-HC. +REM +REM MPC-HC is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as published by +REM the Free Software Foundation; either version 3 of the License, or +REM (at your option) any later version. +REM +REM MPC-HC is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public License +REM along with this program. If not, see . + + +SETLOCAL +SET "FILE_DIR=%~dp0" +PUSHD "%FILE_DIR%" + +SET "COMMON=%FILE_DIR%\common.bat" + +IF EXIST "build.user.bat" CALL "build.user.bat" + +IF NOT DEFINED MPCHC_GIT IF DEFINED GIT (SET MPCHC_GIT=%GIT%) ELSE (SET MPCHC_GIT="C:\Program Files\Git") + +SET "PATH=%MPCHC_GIT%\bin;%PATH%" + +CALL "%COMMON%" :SubDoesExist bash.exe +IF %ERRORLEVEL% NEQ 0 GOTO MissingVar + +bash.exe ./version.sh %* + + +:END +POPD +ENDLOCAL +EXIT /B + + +:MissingVar +copy /Y "build\version_rev_fallback.h" "build\version_rev.h" +copy /Y "src\mpc-hc\res\mpc-hc.exe.manifest.fallback" "src\mpc-hc\res\mpc-hc.exe.manifest" +ECHO Not all build dependencies were found: Missing bash.exe in Git installation +ECHO. +ECHO See "docs\Compilation.md" for more information. +ENDLOCAL +EXIT /B From 9c224dcc3bd9cdae4ebe20a1f2fd54d6928d5f4f Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 9 Mar 2025 13:35:10 -0700 Subject: [PATCH 12/20] revert formatting changes to mpc-hc.rc --- src/mpc-hc/mpc-hc.rc | 80 +++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/src/mpc-hc/mpc-hc.rc b/src/mpc-hc/mpc-hc.rc index 880e98198a8..b99a605c466 100644 --- a/src/mpc-hc/mpc-hc.rc +++ b/src/mpc-hc/mpc-hc.rc @@ -125,7 +125,7 @@ BEGIN LTEXT "%",IDC_STATIC5,194,37,14,8 CONTROL "Regain volume",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,212,37,130,8 LTEXT "Boost:",IDC_STATIC6,6,59,66,8 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,72,55,132,15 + CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | TBS_DOWNISLEFT,72,55,132,15 CONTROL "Down-sample to 44100 Hz",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,78,343,8 CONTROL "Audio time shift (ms):",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,95,138,8 EDITTEXT IDC_EDIT2,149,92,55,13,ES_AUTOHSCROLL,WS_EX_RIGHT @@ -179,7 +179,7 @@ FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN ICON "",IDR_MAINFRAME,14,10,48,48 LTEXT "",IDC_STATIC1,60,8,199,8 - CONTROL "Copyright 2002-2024 clsid2 and others",IDC_AUTHORS_LINK, + CONTROL "Copyright 2002-2025 clsid2 and others",IDC_AUTHORS_LINK, "SysLink",WS_TABSTOP,60,20,200,8 CONTROL "",IDC_HOMEPAGE_LINK,"SysLink",WS_TABSTOP,60,32,200,8 LTEXT "This program is freeware and released under the GNU General Public License.",IDC_STATIC,7,46,246,18 @@ -233,7 +233,7 @@ BEGIN CONTROL "Display full path",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON | WS_GROUP,12,169,126,8 CONTROL "File name only",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,12,184,126,8 CONTROL "Don't prefix anything",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,12,198,126,8 - CONTROL "Replace file name with title",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_GROUP | WS_TABSTOP,12,212,126,18 + CONTROL "Replace file name with title",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP | WS_GROUP,12,212,126,18 GROUPBOX "Other",IDC_STATIC,149,6,200,90,WS_GROUP CONTROL "Tray icon",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,155,20,192,8 CONTROL "Store settings in .ini file",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,155,35,192,8 @@ -277,11 +277,11 @@ BEGIN GROUPBOX "Audio",IDC_STATIC,6,6,343,56 CTEXT "Volume",IDC_STATIC,54,18,66,8 RTEXT "Min",IDC_STATIC,12,37,24,8 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_TOOLTIPS | WS_TABSTOP | 0x400,36,28,102,24 + CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_TOOLTIPS | WS_TABSTOP | TBS_DOWNISLEFT,36,28,102,24 LTEXT "Max",IDC_STATIC,139,37,28,8 CTEXT "Balance",IDC_STATIC_BALANCE,228,18,66,8,SS_NOTIFY RTEXT "L",IDC_STATIC,174,37,36,8 - CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_TOOLTIPS | WS_TABSTOP | 0x400,210,28,102,24 + CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | TBS_TOOLTIPS | WS_TABSTOP | TBS_DOWNISLEFT,210,28,102,24 LTEXT "R",IDC_STATIC,313,37,32,8 GROUPBOX "Control",IDC_STATIC,6,66,151,55 LTEXT "Volume step:",IDC_STATIC5,13,80,82,8 @@ -579,8 +579,8 @@ CAPTION "Saving..." FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN CONTROL "",IDC_ANIMATE1,"SysAnimate32",ACS_CENTER | ACS_TRANSPARENT | WS_TABSTOP,5,5,187,30 - CONTROL "",IDC_STATIC1,"Static",SS_LEFTNOWORDWRAP | SS_PATHELLIPSIS | WS_GROUP,5,37,240,8 - CONTROL "",IDC_STATIC2,"Static",SS_LEFTNOWORDWRAP | SS_PATHELLIPSIS | WS_GROUP,5,45,240,8 + CONTROL "",IDC_STATIC1,"Static",SS_LEFTNOWORDWRAP | WS_GROUP | SS_PATHELLIPSIS,5,37,240,8 + CONTROL "",IDC_STATIC2,"Static",SS_LEFTNOWORDWRAP | WS_GROUP | SS_PATHELLIPSIS,5,45,240,8 CONTROL "",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,5,58,189,8 LTEXT "",IDC_REPORT,5,70,189,8 PUSHBUTTON "Cancel",IDCANCEL,198,65,47,14 @@ -658,16 +658,16 @@ BEGIN LTEXT "100%",IDC_STATIC,322,97,24,8 LTEXT "Primary",IDC_STATIC,143,114,56,8 CONTROL "",IDC_COLORPRI,"Button",BS_OWNERDRAW | WS_TABSTOP,204,110,24,14 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,233,112,113,14 + CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | TBS_DOWNISLEFT | TBS_TOOLTIPS,233,112,113,14 LTEXT "Secondary",IDC_STATIC,143,133,56,8 CONTROL "",IDC_COLORSEC,"Button",BS_OWNERDRAW | WS_TABSTOP,204,130,24,14 - CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,233,131,113,14 + CONTROL "",IDC_SLIDER2,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | TBS_DOWNISLEFT | TBS_TOOLTIPS,233,131,113,14 LTEXT "Outline",IDC_STATIC,143,152,56,8 CONTROL "",IDC_COLOROUTL,"Button",BS_OWNERDRAW | WS_TABSTOP,204,149,24,14 - CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,233,150,113,14 + CONTROL "",IDC_SLIDER3,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | TBS_DOWNISLEFT | TBS_TOOLTIPS,233,150,113,14 LTEXT "Shadow",IDC_STATIC,143,172,56,8 CONTROL "",IDC_COLORSHAD,"Button",BS_OWNERDRAW | WS_TABSTOP,204,168,24,14 - CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP | 0x400,233,169,113,14 + CONTROL "",IDC_SLIDER4,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP | TBS_DOWNISLEFT | TBS_TOOLTIPS,233,169,113,14 CONTROL "Link alpha channels",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,216,196,132,10 LTEXT "8-bit Character Set",IDC_STATIC21,12,46,112,8 LTEXT "OpenType Language",IDC_STATIC22,12,86,112,8 @@ -716,7 +716,7 @@ BEGIN CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS | UDS_HORZ,76,246,43,13 EDITTEXT IDC_AUTHOR,124,246,224,13,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY EDITTEXT IDC_LOGOFILENAME,77,266,208,13,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Browse...",IDC_BUTTON2,289,266,60,14 + PUSHBUTTON "Browse...",IDC_BUTTON2,289,266,60,14,WS_TABSTOP END IDD_PPAGEOUTPUT DIALOGEX 0, 0, 355, 289 @@ -822,10 +822,10 @@ BEGIN RTEXT "",IDC_STATIC2,84,42,24,10,SS_SUNKEN RTEXT "",IDC_STATIC3,84,61,24,10,SS_SUNKEN RTEXT "",IDC_STATIC4,84,80,24,10,SS_SUNKEN - CONTROL "",IDC_SLI_BRIGHTNESS,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | 0x400,119,20,224,14 - CONTROL "",IDC_SLI_CONTRAST,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | 0x400,119,40,224,14 - CONTROL "",IDC_SLI_HUE,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | 0x400,119,59,224,14 - CONTROL "",IDC_SLI_SATURATION,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | 0x400,119,78,224,14 + CONTROL "",IDC_SLI_BRIGHTNESS,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | TBS_DOWNISLEFT,119,20,224,14 + CONTROL "",IDC_SLI_CONTRAST,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | TBS_DOWNISLEFT,119,40,224,14 + CONTROL "",IDC_SLI_HUE,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | TBS_DOWNISLEFT,119,59,224,14 + CONTROL "",IDC_SLI_SATURATION,"msctls_trackbar32",WS_DISABLED | WS_TABSTOP | TBS_DOWNISLEFT,119,78,224,14 PUSHBUTTON "Reset",IDC_RESET,277,96,60,14 GROUPBOX "Update check",IDC_STATIC,6,127,343,48 CONTROL "Enable automatic update check",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,142,300,8 @@ -1479,14 +1479,6 @@ BEGIN VERTGUIDE, 8 VERTGUIDE, 78 END - - IDD_PPAGETOOLBAR, DIALOG - BEGIN - VERTGUIDE, 10 - HORZGUIDE, 4 - HORZGUIDE, 20 - HORZGUIDE, 22 - END END #endif // APSTUDIO_INVOKED @@ -2523,11 +2515,6 @@ BEGIN 0 END -IDD_PPAGETOOLBAR AFX_DIALOG_LAYOUT -BEGIN - 0 -END - ///////////////////////////////////////////////////////////////////////////// // @@ -2549,6 +2536,7 @@ BEGIN IDS_PROPSHEET_PROPERTIES "Properties" IDS_PLAY_LOOPMODE_FILE "File" IDS_SUB_OVERRIDE_DEFAULT_STYLE "Override Default Style" + IDS_SUB_OVERRIDE_ALL_STYLES "Override All Styles" IDS_PLAY_LOOPMODE_PLAYLIST "Playlist" IDS_FAVFILES "Files" IDS_FAVDVDS "DVDs" @@ -2564,7 +2552,6 @@ BEGIN IDS_THEMEMODE_DARK "Dark" IDS_THEMEMODE_LIGHT "Light" IDS_THEMEMODE_WINDOWS "Windows Default" - IDS_SUB_OVERRIDE_ALL_STYLES "Override All Styles" END STRINGTABLE @@ -2747,7 +2734,6 @@ BEGIN IDD_PPAGESYNC "Playback::Sync Renderer Settings" IDD_PPAGEFULLSCREEN "Playback::Fullscreen" IDD_PPAGEAUDIORENDERER "Internal Filters::Audio Renderer" - IDD_PPAGEMOUSE "Player::Mouse" END STRINGTABLE @@ -2786,6 +2772,7 @@ END STRINGTABLE BEGIN IDD_PPAGEACCELTBL "Player::Keys" + IDD_PPAGEMOUSE "Player::Mouse" IDD_PPAGESUBSTYLE "Subtitles::Default Style" IDD_PPAGEINTERNALFILTERS "Internal Filters" IDD_PPAGELOGO "Player::Logo" @@ -2968,8 +2955,6 @@ BEGIN "Insert deinterlace filter (blend) in capture mode" IDS_PLAYLIST_TOGGLE_SHUFFLE "Toggle Playlist Shuffle" IDS_AUDIOSHIFT_ONOFF "Toggle Audio Delay" - IDS_PPAGEADVANCED_PAUSE_WHILE_DRAGGING_SEEKBAR - "Pause playback while dragging the seekbar." END STRINGTABLE @@ -3651,7 +3636,6 @@ BEGIN IDS_MFMT_FLV "Flash Video" IDS_MFMT_OGM "Ogg Media" IDS_MFMT_RM "Real Media" - IDS_MFMT_RT "Real Script" IDS_MFMT_WMV "Windows Media Video" IDS_MFMT_BINK "Smacker/Bink Video" IDS_MFMT_FLIC "FLIC Animation" @@ -4044,23 +4028,14 @@ BEGIN IDS_CMD_UNREGALL "/unregall\t\tRemove all file associations" IDS_CMD_START "/start ms\t\tStart playing at ""ms"" (= milliseconds)" IDS_CMD_STARTPOS "/startpos hh:mm:ss\tStart playing at position hh:mm:ss" + IDS_CMD_AB_START "/ab_start hh:mm:ss\tA-B repeat start position" + IDS_CMD_AB_END "/ab_end hh:mm:ss\tA-B repeat end position" IDS_CMD_FIXEDSIZE "/fixedsize w,h[,x,y]\tSet a fixed window size; optionally specificy upper-left window position" IDS_CMD_MONITOR "/monitor N\tStart player on monitor N, where N starts from 1" IDS_CMD_AUDIORENDERER "/audiorenderer N\tStart using audiorenderer N, where N starts from 1 (see ""Output"" settings)" IDS_CMD_SHADERPRESET "/shaderpreset ""Pr""\tStart using ""Pr"" shader preset" END -STRINGTABLE -BEGIN - IDS_CMD_THUMBNAILS "/thumbnails\tCreate thumbnails" - IDS_PPAGEADVANCED_CONFIRM_FILE_DELETE - "Show confirmation prompt before deleting file" - IDS_PPAGEADVANCED_LIBASS_FOR_SRT - "Use libass (instead of standard renderer) for SRT subtitles. NOT recommended." - IDS_CMD_AB_START "/ab_start hh:mm:ss\tA-B repeat start position" - IDS_CMD_AB_END "/ab_end hh:mm:ss\tA-B repeat end position" -END - STRINGTABLE BEGIN IDS_MESSAGEBOX_CANCEL "Cancel" @@ -4081,10 +4056,6 @@ BEGIN IDS_MOUSE_WHEEL_RIGHT "Wheel Right" IDS_MOUSE_ACTION "Action" IDS_MOUSE_COMMAND "Command" -END - -STRINGTABLE -BEGIN IDS_MOUSE_RIGHT_BUTTON "Right button" END @@ -4131,6 +4102,12 @@ BEGIN "Display current A-B repeat marks in status bar." IDS_PPAGEADVANCED_SHOW_VIDEOINFO_STATUSBAR "Display video info (codec name, resolution) in status bar." + IDS_PPAGEADVANCED_PAUSE_WHILE_DRAGGING_SEEKBAR + "Pause playback while dragging the seekbar." + IDS_PPAGEADVANCED_CONFIRM_FILE_DELETE + "Show confirmation prompt before deleting file" + IDS_PPAGEADVANCED_LIBASS_FOR_SRT + "Use libass (instead of standard renderer) for SRT subtitles. NOT recommended." END STRINGTABLE @@ -4192,6 +4169,11 @@ BEGIN IDS_AG_DEFAULT "Default" END +STRINGTABLE +BEGIN + IDS_CMD_THUMBNAILS "/thumbnails\tCreate thumbnails" +END + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// From 6a4ad067747b10a2b7bce3b5b700ca0e41b5298a Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 9 Mar 2025 14:20:12 -0700 Subject: [PATCH 13/20] revert refactor on CPnSPresetsDlg --- src/mpc-hc/PnSPresetsDlg.cpp | 4 ++-- src/mpc-hc/PnSPresetsDlg.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mpc-hc/PnSPresetsDlg.cpp b/src/mpc-hc/PnSPresetsDlg.cpp index 6ef8e43db69..1ee4c4bd5b5 100644 --- a/src/mpc-hc/PnSPresetsDlg.cpp +++ b/src/mpc-hc/PnSPresetsDlg.cpp @@ -133,7 +133,7 @@ BEGIN_MESSAGE_MAP(CPnSPresetsDlg, CMPCThemeResizableDialog) ON_LBN_SELCHANGE(IDC_LIST1, OnLbnSelchangeList1) ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2) ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateButton2) - ON_BN_CLICKED(IDC_BUTTON3, MoveDown) + ON_BN_CLICKED(IDC_BUTTON3, OnBnClickedButton6) ON_UPDATE_COMMAND_UI(IDC_BUTTON3, OnUpdateButton6) ON_BN_CLICKED(IDC_BUTTON4, OnBnClickedButton9) ON_UPDATE_COMMAND_UI(IDC_BUTTON4, OnUpdateButton9) @@ -183,7 +183,7 @@ void CPnSPresetsDlg::OnUpdateButton2(CCmdUI* pCmdUI) pCmdUI->Enable(str != _T("New")); } -void CPnSPresetsDlg::MoveDown() // del +void CPnSPresetsDlg::OnBnClickedButton6() // del { int i = m_list.GetCurSel(); m_list.DeleteString(i); diff --git a/src/mpc-hc/PnSPresetsDlg.h b/src/mpc-hc/PnSPresetsDlg.h index 2ad976575a2..fb571b0d8d5 100644 --- a/src/mpc-hc/PnSPresetsDlg.h +++ b/src/mpc-hc/PnSPresetsDlg.h @@ -62,7 +62,7 @@ class CPnSPresetsDlg : public CMPCThemeResizableDialog afx_msg void OnLbnSelchangeList1(); afx_msg void OnBnClickedButton2(); afx_msg void OnUpdateButton2(CCmdUI* pCmdUI); - afx_msg void MoveDown(); + afx_msg void OnBnClickedButton6(); afx_msg void OnUpdateButton6(CCmdUI* pCmdUI); afx_msg void OnBnClickedButton9(); afx_msg void OnUpdateButton9(CCmdUI* pCmdUI); From 3f07227a2a90cbeac77288701f315b199613a4ca Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 9 Mar 2025 15:06:21 -0700 Subject: [PATCH 14/20] support directional lock to handle edge case of no unlocked buttons --- src/mpc-hc/PPageToolBar.cpp | 20 +++++--------------- src/mpc-hc/PlayerToolBar.cpp | 12 +++++++----- src/mpc-hc/PlayerToolBar.h | 8 +++++++- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/mpc-hc/PPageToolBar.cpp b/src/mpc-hc/PPageToolBar.cpp index cd6713b6964..28f746ee073 100644 --- a/src/mpc-hc/PPageToolBar.cpp +++ b/src/mpc-hc/PPageToolBar.cpp @@ -236,22 +236,13 @@ bool CPPageToolBar::IsValidInsertPos(int destRow) { if (supportedButtons.count(tidCommand) == 0) { //this should never happen return false; } - if (destRow == 0) { //first - if (supportedButtons[tidCommand].positionLocked) {//can't insert before locked first button - return false; - } - } else if (destRow == m_list_active.GetItemCount() - 1) { //last--don't insert before if prior button locked + if (supportedButtons[tidCommand].positionLocked == CPlayerToolBar::LOCK_LEFT) { + return false; + } else { int priorIdCommand = (int)m_list_active.GetItemData(destRow - 1); - if (supportedButtons.count(priorIdCommand) == 0 || supportedButtons[priorIdCommand].positionLocked) { + if (supportedButtons.count(priorIdCommand) == 0 || CPlayerToolBar::LOCK_RIGHT == supportedButtons[priorIdCommand].positionLocked) { return false; } - } else {//we have at least two rows. if the insert point is between two locked rows we will not allow it - if (supportedButtons[tidCommand].positionLocked) { - int priorIdCommand = (int)m_list_active.GetItemData(destRow - 1); - if (supportedButtons.count(priorIdCommand) == 0 || supportedButtons[priorIdCommand].positionLocked) { - return false; - } - } } } @@ -281,8 +272,7 @@ bool CPPageToolBar::MoveButton(CMPCThemePlayerListCtrl& srcList, CMPCThemePlayer } else { //active if (destRow == -1) { for (destRow = 0; destRow < dstList.GetItemCount(); destRow++) { - beforeID = (int)dstList.GetItemData(destRow); - if (supportedButtons.count(beforeID) != 0 && !supportedButtons[beforeID].positionLocked) { + if (IsValidInsertPos(destRow)) { break; } } diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index 00b1d6f284b..5afd392b03c 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -44,16 +44,16 @@ #define VOLUME_SVG_INDEX 28 std::map CPlayerToolBar::supportedSvgButtons = { - {ID_PLAY_PLAY, {TBBS_CHECKGROUP,0,true}}, - {ID_PLAY_PAUSE, {TBBS_CHECKGROUP,1,true}}, - {ID_PLAY_STOP, {TBBS_CHECKGROUP,2,true}}, + {ID_PLAY_PLAY, {TBBS_CHECKGROUP,0,LOCK_LEFT}}, + {ID_PLAY_PAUSE, {TBBS_CHECKGROUP,1,LOCK_LEFT}}, + {ID_PLAY_STOP, {TBBS_CHECKGROUP,2,LOCK_LEFT}}, {ID_NAVIGATE_SKIPBACK, {TBBS_BUTTON,3}}, {ID_PLAY_DECRATE, {TBBS_BUTTON,4}}, {ID_PLAY_INCRATE, {TBBS_BUTTON,5}}, {ID_NAVIGATE_SKIPFORWARD, {TBBS_BUTTON,6}}, {ID_PLAY_FRAMESTEP, {TBBS_BUTTON,7}}, - {ID_DUMMYSEPARATOR, {TBBS_SEPARATOR,-1,true}}, - {ID_VOLUME_MUTE, {TBBS_CHECKBOX,VOLUMEBUTTON_SVG_INDEX,true}}, + {ID_DUMMYSEPARATOR, {TBBS_SEPARATOR,-1,LOCK_RIGHT}}, + {ID_VOLUME_MUTE, {TBBS_CHECKBOX,VOLUMEBUTTON_SVG_INDEX,LOCK_RIGHT}}, }; static std::vector supportedSvgButtonsSeq; @@ -70,6 +70,8 @@ CPlayerToolBar::CPlayerToolBar(CMainFrame* pMainFrame) , flexibleSpaceIndex(10) , currentlyDraggingButton(-1) , toolbarAdjustActive(false) + , buttonCount(0) + , sepCount(0) { GetEventd().Connect(m_eventc, { MpcEvent::DPI_CHANGED, diff --git a/src/mpc-hc/PlayerToolBar.h b/src/mpc-hc/PlayerToolBar.h index ff179d59c20..8afc65bae45 100644 --- a/src/mpc-hc/PlayerToolBar.h +++ b/src/mpc-hc/PlayerToolBar.h @@ -32,6 +32,12 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil { DECLARE_DYNAMIC(CPlayerToolBar) +public: + enum PositionLock { + LOCK_NONE = 0, + LOCK_LEFT, + LOCK_RIGHT, + }; private: CMainFrame* m_pMainFrame; @@ -62,7 +68,7 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil struct svgButtonInfo { UINT style; int svgIndex; - bool positionLocked = false; + PositionLock positionLocked = LOCK_NONE; CString text; }; From 5a1013c18b5ca3e7562be6d7a9e451ba9d418a87 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 9 Mar 2025 15:13:14 -0700 Subject: [PATCH 15/20] try to keep a button selected when moving between lists --- src/mpc-hc/PPageToolBar.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mpc-hc/PPageToolBar.cpp b/src/mpc-hc/PPageToolBar.cpp index 28f746ee073..1265868d3b0 100644 --- a/src/mpc-hc/PPageToolBar.cpp +++ b/src/mpc-hc/PPageToolBar.cpp @@ -286,6 +286,12 @@ bool CPPageToolBar::MoveButton(CMPCThemePlayerListCtrl& srcList, CMPCThemePlayer dstList.InsertItem(LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM, destRow, tb.GetStringFromID(buttonID), 0, 0, supportedButtons[buttonID].svgIndex, buttonID); srcList.DeleteItem(selectedRow); + //we'll select the next element, which after having deleted selectedRow, will be at selectedRow + if (selectedRow < srcList.GetItemCount()) { + srcList.SetItemState(selectedRow, LVIS_SELECTED, LVIS_SELECTED); + srcList.SetSelectionMark(selectedRow); + } + if (addingButton) { InsertButton(beforeID, buttonID); } else { From cea0cabbb4b698ff8f27557fd4ded8d489e984e6 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 9 Mar 2025 15:51:19 -0700 Subject: [PATCH 16/20] add column headings --- src/mpc-hc/PPageToolBar.cpp | 11 +++++++---- src/mpc-hc/PPageToolBar.h | 3 +-- src/mpc-hc/mpc-hc.rc | 2 ++ src/mpc-hc/resource.h | 2 ++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/mpc-hc/PPageToolBar.cpp b/src/mpc-hc/PPageToolBar.cpp index 1265868d3b0..5069138ac67 100644 --- a/src/mpc-hc/PPageToolBar.cpp +++ b/src/mpc-hc/PPageToolBar.cpp @@ -103,15 +103,18 @@ BOOL CPPageToolBar::OnInitDialog() m_list_active.SetExtendedStyle(m_list_active.GetExtendedStyle() /* | LVS_EX_FULLROWSELECT */ /*| LVS_EX_DOUBLEBUFFER */ | LVS_EX_INFOTIP | LVS_ICON | LVS_SHAREIMAGELISTS); m_list_active.setAdditionalStyles(LVS_EX_FULLROWSELECT); - m_list_active.InsertColumn(COL_IMAGE, L"", LVCFMT_LEFT); - m_list_active.SetColumnWidth(COL_IMAGE, LVSCW_AUTOSIZE_USEHEADER); + CString col(StrRes(IDS_PPAGE_TOOLBAR_CUR_BUTTONS)); + m_list_active.InsertColumn(COL_BUTTON, col, LVCFMT_LEFT); + m_list_active.SetColumnWidth(COL_BUTTON, LVSCW_AUTOSIZE_USEHEADER); m_list_active.SetImageList(tbctrl.GetImageList(), LVSIL_SMALL); m_list_active.setColorInterface(this); + m_list_inactive.SetExtendedStyle(m_list_inactive.GetExtendedStyle() /* | LVS_EX_FULLROWSELECT */ /*| LVS_EX_DOUBLEBUFFER */ | LVS_EX_INFOTIP | LVS_ICON | LVS_SHAREIMAGELISTS); m_list_inactive.setAdditionalStyles(LVS_EX_FULLROWSELECT); - m_list_inactive.InsertColumn(COL_IMAGE, L"", LVCFMT_LEFT); - m_list_inactive.SetColumnWidth(COL_IMAGE, LVSCW_AUTOSIZE_USEHEADER); + CString col2(StrRes(IDS_PPAGE_TOOLBAR_AVAIL_BUTTONS)); + m_list_inactive.InsertColumn(COL_BUTTON, col2, LVCFMT_LEFT); + m_list_inactive.SetColumnWidth(COL_BUTTON, LVSCW_AUTOSIZE_USEHEADER); m_list_inactive.SetImageList(tbctrl.GetImageList(), LVSIL_SMALL); LoadToolBarButtons(); diff --git a/src/mpc-hc/PPageToolBar.h b/src/mpc-hc/PPageToolBar.h index b2b42efe2c0..d5a1d538845 100644 --- a/src/mpc-hc/PPageToolBar.h +++ b/src/mpc-hc/PPageToolBar.h @@ -40,8 +40,7 @@ class CPPageToolBar : public CMPCThemePPageBase private: enum { IDD = IDD_PPAGETOOLBAR }; enum { - COL_IMAGE, - COL_TEXT, + COL_BUTTON, }; enum ButtonPosition { diff --git a/src/mpc-hc/mpc-hc.rc b/src/mpc-hc/mpc-hc.rc index b99a605c466..6ec0d08db5b 100644 --- a/src/mpc-hc/mpc-hc.rc +++ b/src/mpc-hc/mpc-hc.rc @@ -2723,6 +2723,8 @@ END STRINGTABLE BEGIN IDD_PPAGETOOLBAR "Player::ToolBar" + IDS_PPAGE_TOOLBAR_AVAIL_BUTTONS "Available Buttons" + IDS_PPAGE_TOOLBAR_CUR_BUTTONS "Current Buttons" END STRINGTABLE diff --git a/src/mpc-hc/resource.h b/src/mpc-hc/resource.h index b93c1bf36d7..cdf10882a8b 100644 --- a/src/mpc-hc/resource.h +++ b/src/mpc-hc/resource.h @@ -1472,6 +1472,8 @@ #define IDS_MOUSE_ACTION 41710 #define IDS_MOUSE_COMMAND 41711 #define IDS_MOUSE_RIGHT_BUTTON 41712 +#define IDS_PPAGE_TOOLBAR_CUR_BUTTONS 41713 +#define IDS_PPAGE_TOOLBAR_AVAIL_BUTTONS 41714 #define IDS_PPAGE_CAPTURE_FG0 57345 #define IDS_PPAGE_CAPTURE_FG1 57346 #define IDS_PPAGE_CAPTURE_FG2 57347 From 62b340e7d39680b4ed546eecc03916ea97c8533b Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Sun, 9 Mar 2025 16:52:59 -0700 Subject: [PATCH 17/20] create separate imagelist for customize dialog; prevents issues with arbitrary tb sizes --- src/mpc-hc/PPageToolBar.cpp | 9 ++-- src/mpc-hc/PlayerToolBar.cpp | 102 ++++++++++++++++++++--------------- src/mpc-hc/PlayerToolBar.h | 5 ++ 3 files changed, 70 insertions(+), 46 deletions(-) diff --git a/src/mpc-hc/PPageToolBar.cpp b/src/mpc-hc/PPageToolBar.cpp index 5069138ac67..b296d6c10c9 100644 --- a/src/mpc-hc/PPageToolBar.cpp +++ b/src/mpc-hc/PPageToolBar.cpp @@ -53,6 +53,7 @@ void CPPageToolBar::LoadToolBarButtons() { auto supportedButtons = tb.GetSupportedSvgButtons(); std::set idsAdded; bool foundFirst = false; + int disabledOffset = tb.GetCustomizeButtonImages()->GetImageCount() / 2; for (int i = 0; i < tbctrl.GetButtonCount(); i++) { TBBUTTON button; tbctrl.GetButton(i, &button); @@ -60,7 +61,9 @@ void CPPageToolBar::LoadToolBarButtons() { int index = m_list_active.InsertItem(LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM, i, tb.GetStringFromID(button.idCommand), 0, 0, button.iBitmap, button.idCommand); auto& buttonInfo = supportedButtons[button.idCommand]; - if (!buttonInfo.positionLocked && !foundFirst) { + if (buttonInfo.positionLocked) { + m_list_active.SetItem(index, 0, LVIF_IMAGE, 0, button.iBitmap+disabledOffset, 0, 0, 0); + } else if (!foundFirst) { m_list_active.SetItemState(index, LVIS_SELECTED, LVIS_SELECTED); m_list_active.SetSelectionMark(index); foundFirst = true; @@ -106,7 +109,7 @@ BOOL CPPageToolBar::OnInitDialog() CString col(StrRes(IDS_PPAGE_TOOLBAR_CUR_BUTTONS)); m_list_active.InsertColumn(COL_BUTTON, col, LVCFMT_LEFT); m_list_active.SetColumnWidth(COL_BUTTON, LVSCW_AUTOSIZE_USEHEADER); - m_list_active.SetImageList(tbctrl.GetImageList(), LVSIL_SMALL); + m_list_active.SetImageList(tb.GetCustomizeButtonImages().get(), LVSIL_SMALL); m_list_active.setColorInterface(this); @@ -115,7 +118,7 @@ BOOL CPPageToolBar::OnInitDialog() CString col2(StrRes(IDS_PPAGE_TOOLBAR_AVAIL_BUTTONS)); m_list_inactive.InsertColumn(COL_BUTTON, col2, LVCFMT_LEFT); m_list_inactive.SetColumnWidth(COL_BUTTON, LVSCW_AUTOSIZE_USEHEADER); - m_list_inactive.SetImageList(tbctrl.GetImageList(), LVSIL_SMALL); + m_list_inactive.SetImageList(tb.GetCustomizeButtonImages().get(), LVSIL_SMALL); LoadToolBarButtons(); diff --git a/src/mpc-hc/PlayerToolBar.cpp b/src/mpc-hc/PlayerToolBar.cpp index 5afd392b03c..25a15b85a7c 100644 --- a/src/mpc-hc/PlayerToolBar.cpp +++ b/src/mpc-hc/PlayerToolBar.cpp @@ -104,25 +104,27 @@ bool CPlayerToolBar::LoadExternalToolBar(CImage& image, float svgscale) return false; } -void CPlayerToolBar::LoadToolbarImage() -{ +void CPlayerToolBar::MakeImageList(bool createCustomizeButtons, int buttonSize, std::unique_ptr &imageList) { auto& s = AfxGetAppSettings(); // We are currently not aware of any cases where the scale factors are different float dpiScaling = (float)std::min(m_pMainFrame->m_dpi.ScaleFactorX(), m_pMainFrame->m_dpi.ScaleFactorY()); - int targetsize = int(dpiScaling * AfxGetAppSettings().nDefaultToolbarSize); + int targetsize = int(dpiScaling * buttonSize); float svgscale = targetsize / 16.0f; CImage image; - m_pButtonsImages.reset(); - m_pDisabledButtonsImages.reset(); + imageList.reset(); + if (!createCustomizeButtons) { + m_pDisabledButtonsImages.reset(); + } bool buttonsImageLoaded = false; - if (LoadExternalToolBar(image, svgscale) && image.GetHeight() % 4 == 0 && image.GetWidth() % (image.GetHeight()/4) == 0) { + if (LoadExternalToolBar(image, svgscale) && image.GetHeight() % 4 == 0 && image.GetWidth() % (image.GetHeight() / 4) == 0) { buttonsImageLoaded = true; } + if (buttonsImageLoaded || SUCCEEDED(SVGImage::Load(IDF_SVG_BUTTONS, image, svgscale))) { CImage imageDisabled; CBitmap* bmp = CBitmap::FromHandle(image); @@ -132,28 +134,31 @@ void CPlayerToolBar::LoadToolbarImage() int height = image.GetHeight() / 4; int bpp = image.GetBPP(); if (width % height == 0) { //todo: dynamically determine which buttons are supported by this toolbar, otherwise show generic buttons? - // the manual specifies that sizeButton should be sizeImage inflated by (7, 6) - SetSizes(CSize(height + 7, height + 6), CSize(height, height)); - int volumeIndex = VOLUME_SVG_INDEX; - volumeOn.Destroy(); - volumeOff.Destroy(); - volumeOn.Create(height * 2, height, bpp, CImage::createAlphaChannel); - volumeOff.Create(height * 2, height, bpp, CImage::createAlphaChannel); - - m_pButtonsImages.reset(DEBUG_NEW CImageList()); - m_pButtonsImages->Create(height, height, ILC_COLOR32 | ILC_MASK, 1, 64); - m_pDisabledButtonsImages.reset(DEBUG_NEW CImageList()); - m_pDisabledButtonsImages->Create(height, height, ILC_COLOR32 | ILC_MASK, 1, 64); - + + imageList.reset(DEBUG_NEW CImageList()); + imageList->Create(height, height, ILC_COLOR32 | ILC_MASK, 1, 64); CImage dynamicToolbar, dynamicToolbarDisabled; - dynamicToolbar.Create(width, height, bpp, CImage::createAlphaChannel); - dynamicToolbarDisabled.Create(width, height, bpp, CImage::createAlphaChannel); + if (!createCustomizeButtons) { + // the manual specifies that sizeButton should be sizeImage inflated by (7, 6) + SetSizes(CSize(height + 7, height + 6), CSize(height, height)); + + volumeOn.Destroy(); + volumeOff.Destroy(); + volumeOn.Create(height * 2, height, bpp, CImage::createAlphaChannel); + volumeOff.Create(height * 2, height, bpp, CImage::createAlphaChannel); + + m_pDisabledButtonsImages.reset(DEBUG_NEW CImageList()); + m_pDisabledButtonsImages->Create(height, height, ILC_COLOR32 | ILC_MASK, 1, 64); + dynamicToolbar.Create(width, height, bpp, CImage::createAlphaChannel); + dynamicToolbarDisabled.Create(width, height, bpp, CImage::createAlphaChannel); + } else { + dynamicToolbar.Create(width * 2, height, bpp, CImage::createAlphaChannel); + } CBitmap* pOldTargetBmp = nullptr; CBitmap* pOldSourceBmp = nullptr; - CDC targetDC; CDC sourceDC; @@ -164,7 +169,7 @@ void CPlayerToolBar::LoadToolbarImage() pOldTargetBmp = targetDC.SelectObject(CBitmap::FromHandle(dynamicToolbar)); pOldSourceBmp = sourceDC.GetCurrentBitmap(); - int imageOffset = 0, imageDisabledOffset=height; + int imageOffset = 0, imageDisabledOffset = height; if (AppIsThemeLoaded() && s.eModernThemeMode == CMPCTheme::ModernThemeMode::DARK) { imageOffset = height * 2; imageDisabledOffset = height * 3; @@ -173,19 +178,23 @@ void CPlayerToolBar::LoadToolbarImage() sourceDC.SelectObject(bmp); targetDC.BitBlt(0, 0, image.GetWidth(), height, &sourceDC, 0, imageOffset, SRCCOPY); - targetDC.SelectObject(CBitmap::FromHandle(dynamicToolbarDisabled)); - targetDC.BitBlt(0, 0, image.GetWidth(), height, &sourceDC, 0, imageDisabledOffset, SRCCOPY); - - targetDC.SelectObject(CBitmap::FromHandle(volumeOn)); - targetDC.BitBlt(0, 0, height * 2, height, &sourceDC, volumeIndex * height, imageOffset, SRCCOPY); - targetDC.SelectObject(CBitmap::FromHandle(volumeOff)); - targetDC.BitBlt(0, 0, height * 2, height, &sourceDC, volumeIndex * height, imageDisabledOffset, SRCCOPY); - - //volumeOn.Save(L"c:\\temp\\vON.png", Gdiplus::ImageFormatPNG); - //volumeOff.Save(L"c:\\temp\\vOFF.png", Gdiplus::ImageFormatPNG); - - ImageGrayer::PreMultiplyAlpha(volumeOn); - ImageGrayer::PreMultiplyAlpha(volumeOff); + if (!createCustomizeButtons) { + targetDC.SelectObject(CBitmap::FromHandle(dynamicToolbarDisabled)); + targetDC.BitBlt(0, 0, image.GetWidth(), height, &sourceDC, 0, imageDisabledOffset, SRCCOPY); + + targetDC.SelectObject(CBitmap::FromHandle(volumeOn)); + targetDC.BitBlt(0, 0, height * 2, height, &sourceDC, volumeIndex * height, imageOffset, SRCCOPY); + targetDC.SelectObject(CBitmap::FromHandle(volumeOff)); + targetDC.BitBlt(0, 0, height * 2, height, &sourceDC, volumeIndex * height, imageDisabledOffset, SRCCOPY); + //volumeOn.Save(L"c:\\temp\\vON.png", Gdiplus::ImageFormatPNG); + //volumeOff.Save(L"c:\\temp\\vOFF.png", Gdiplus::ImageFormatPNG); + + ImageGrayer::PreMultiplyAlpha(volumeOn); + ImageGrayer::PreMultiplyAlpha(volumeOff); + } else {//we will add the disabled buttons to the end of the imagelist, so the customize page can access them + targetDC.SelectObject(CBitmap::FromHandle(dynamicToolbar)); + targetDC.BitBlt(image.GetWidth(), 0, image.GetWidth(), height, &sourceDC, 0, imageDisabledOffset, SRCCOPY); + } sourceDC.SelectObject(pOldSourceBmp); targetDC.SelectObject(pOldTargetBmp); @@ -195,20 +204,27 @@ void CPlayerToolBar::LoadToolbarImage() ReleaseDC(pDC); - m_pButtonsImages->Add(CBitmap::FromHandle(dynamicToolbar), nullptr); + imageList->Add(CBitmap::FromHandle(dynamicToolbar), nullptr); dynamicToolbar.Destroy(); - m_pDisabledButtonsImages->Add(CBitmap::FromHandle(dynamicToolbarDisabled), nullptr); - dynamicToolbarDisabled.Destroy(); + if (!createCustomizeButtons) { + m_pDisabledButtonsImages->Add(CBitmap::FromHandle(dynamicToolbarDisabled), nullptr); + dynamicToolbarDisabled.Destroy(); + m_nButtonHeight = height; - m_nButtonHeight = height; + GetToolBarCtrl().SetImageList(imageList.get()); + GetToolBarCtrl().SetDisabledImageList(m_pDisabledButtonsImages.get()); + } - GetToolBarCtrl().SetImageList(m_pButtonsImages.get()); - GetToolBarCtrl().SetDisabledImageList(m_pDisabledButtonsImages.get()); } } image.Destroy(); - +} + +void CPlayerToolBar::LoadToolbarImage() +{ + MakeImageList(false, AfxGetAppSettings().nDefaultToolbarSize, m_pButtonsImages); + MakeImageList(true, 32, m_pCustomizeButtonImages); } TBBUTTON CPlayerToolBar::GetStandardButton(int cmdid) { diff --git a/src/mpc-hc/PlayerToolBar.h b/src/mpc-hc/PlayerToolBar.h index 8afc65bae45..e622a5eac47 100644 --- a/src/mpc-hc/PlayerToolBar.h +++ b/src/mpc-hc/PlayerToolBar.h @@ -55,6 +55,7 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil int m_nButtonHeight; std::unique_ptr m_pButtonsImages; std::unique_ptr m_pDisabledButtonsImages; + std::unique_ptr m_pCustomizeButtonImages; int buttonCount, sepCount; int m_volumeCtrlSize; @@ -78,10 +79,14 @@ class CPlayerToolBar : public CToolBar, public CMPCThemeUtil virtual ~CPlayerToolBar(); bool LoadExternalToolBar(CImage& image, float svgscale); + void MakeImageList(bool createCustomizeButtons, int buttonSize, std::unique_ptr &imageList); LPCWSTR GetStringFromID(int idCommand); const std::map GetSupportedSvgButtons() { return supportedSvgButtons; } + std::unique_ptr& GetCustomizeButtonImages() { + return m_pCustomizeButtonImages; + } int GetVolume() const; int GetMinWidth() const; From de4864cbd4e8eab835066ccd011c059525e281d4 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Fri, 14 Mar 2025 18:02:40 -0700 Subject: [PATCH 18/20] center buttons --- src/mpc-hc/mpc-hc.rc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mpc-hc/mpc-hc.rc b/src/mpc-hc/mpc-hc.rc index 6ec0d08db5b..21b8df34aea 100644 --- a/src/mpc-hc/mpc-hc.rc +++ b/src/mpc-hc/mpc-hc.rc @@ -1201,13 +1201,13 @@ IDD_PPAGETOOLBAR DIALOGEX 0, 0, 355, 289 STYLE DS_SETFONT | WS_CHILD FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN - CONTROL "",IDC_LIST2,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,190,22,153,230 - PUSHBUTTON "Default",IDC_BUTTON1,278,262,65,14 - CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,24,22,138,230 - PUSHBUTTON "<<",IDC_BUTTON3,168,94,16,16 - PUSHBUTTON ">>",IDC_BUTTON4,168,113,16,16 - PUSHBUTTON "^",IDC_BUTTON5,71,254,16,16 - PUSHBUTTON "v",IDC_BUTTON6,91,254,16,16 + CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,6,36,155,230 + CONTROL "",IDC_LIST2,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,193,36,156,230 + PUSHBUTTON "Default",IDC_BUTTON1,284,271,65,14 + PUSHBUTTON "<<",IDC_BUTTON3,169,137,16,16 + PUSHBUTTON ">>",IDC_BUTTON4,169,157,16,16 + PUSHBUTTON "^",IDC_BUTTON5,62,269,16,16 + PUSHBUTTON "v",IDC_BUTTON6,82,269,16,16 END From 9ccf103b62d6d9d8ef0963c5a85085ad86a62299 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Fri, 14 Mar 2025 21:58:52 -0700 Subject: [PATCH 19/20] move toolbar button size to toolbar settings --- src/mpc-hc/PPageTheme.cpp | 18 ------------------ src/mpc-hc/PPageTheme.h | 3 --- src/mpc-hc/PPageToolBar.cpp | 28 +++++++++++++++++++++++++++- src/mpc-hc/PPageToolBar.h | 4 ++++ src/mpc-hc/mpc-hc.rc | 6 +++--- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/mpc-hc/PPageTheme.cpp b/src/mpc-hc/PPageTheme.cpp index 30b2ab1ac76..619772c603d 100644 --- a/src/mpc-hc/PPageTheme.cpp +++ b/src/mpc-hc/PPageTheme.cpp @@ -39,7 +39,6 @@ CPPageTheme::CPPageTheme() , m_iModernSeekbarHeight(DEF_MODERN_SEEKBAR_HEIGHT) , m_iThemeMode(0) , m_nPosLangEnglish(0) - , m_iDefaultToolbarSize(DEF_TOOLBAR_HEIGHT) , m_nOSDSize(0) , m_fShowChapters(TRUE) , m_bShowPreview(FALSE) @@ -60,7 +59,6 @@ CPPageTheme::CPPageTheme() { EventRouter::EventSelection fires; fires.insert(MpcEvent::CHANGING_UI_LANGUAGE); - fires.insert(MpcEvent::DEFAULT_TOOLBAR_SIZE_CHANGED); GetEventd().Connect(m_eventc, fires); } @@ -91,10 +89,6 @@ void CPPageTheme::DoDataExchange(CDataExchange* pDX) DDX_Check(pDX, IDC_CHECK2, m_fShowChapters); - DDX_Text(pDX, IDC_EDIT1, m_iDefaultToolbarSize); - DDV_MinMaxInt(pDX, m_iDefaultToolbarSize, MIN_TOOLBAR_HEIGHT, MAX_TOOLBAR_HEIGHT); - DDX_Control(pDX, IDC_SPIN1, m_DefaultToolbarSizeCtrl); - DDX_Control(pDX, IDC_COMBO3, m_HoverPosition); DDX_Check(pDX, IDC_SHOW_OSD, m_fShowOSD); DDX_Check(pDX, IDC_CHECK13, m_fShowCurrentTimeInOSD); @@ -146,9 +140,6 @@ BOOL CPPageTheme::OnInitDialog() m_ModernSeekbarHeightCtrl.SetRange32(MIN_MODERN_SEEKBAR_HEIGHT, MAX_MODERN_SEEKBAR_HEIGHT); m_iModernSeekbarHeight = s.iModernSeekbarHeight; - m_DefaultToolbarSizeCtrl.SetRange32(MIN_TOOLBAR_HEIGHT, MAX_TOOLBAR_HEIGHT); - m_iDefaultToolbarSize = s.nDefaultToolbarSize; - m_iThemeMode = static_cast(s.eModernThemeMode); m_ThemeMode.AddString(ResStr(IDS_THEMEMODE_DARK)); @@ -251,11 +242,9 @@ BOOL CPPageTheme::OnApply() UpdateData(); CAppSettings& s = AfxGetAppSettings(); - int nOldDefaultToolbarSize = s.nDefaultToolbarSize; s.bMPCTheme = !!m_bUseModernTheme; s.iModernSeekbarHeight = m_iModernSeekbarHeight; - s.nDefaultToolbarSize = m_iDefaultToolbarSize; s.eModernThemeMode = static_cast(m_iThemeMode); int iLangSel = m_langsComboBox.GetCurSel(); @@ -282,12 +271,6 @@ BOOL CPPageTheme::OnApply() ASSERT(FALSE); } - if (nOldDefaultToolbarSize != s.nDefaultToolbarSize) { - m_eventc.FireEvent(MpcEvent::DEFAULT_TOOLBAR_SIZE_CHANGED); - if (CMainFrame* pMainFrame = AfxGetMainFrame()) { - pMainFrame->RecalcLayout(); - } - } s.nHoverPosition = m_HoverPosition.GetCurSel(); s.nOSDSize = m_nOSDSize; @@ -411,7 +394,6 @@ void CPPageTheme::OnChngOSDCombo() { void CPPageTheme::AdjustDynamicWidgets() { AdjustDynamicWidgetPair(this, IDC_STATIC22, IDC_MODERNSEEKBARHEIGHT); - AdjustDynamicWidgetPair(this, IDC_STATIC3, IDC_EDIT1); AdjustDynamicWidgetPair(this, IDC_STATIC2, IDC_COMBO1); AdjustDynamicWidgetPair(this, IDC_STATIC5, IDC_COMBO2); AdjustDynamicWidgetPair(this, IDC_STATIC11, IDC_COMBO3); diff --git a/src/mpc-hc/PPageTheme.h b/src/mpc-hc/PPageTheme.h index 594ac3b05c1..eefb7081dd1 100644 --- a/src/mpc-hc/PPageTheme.h +++ b/src/mpc-hc/PPageTheme.h @@ -37,18 +37,15 @@ class CPPageTheme : public CMPCThemePPageBase int m_iModernSeekbarHeight; CMPCThemeSpinButtonCtrl m_ModernSeekbarHeightCtrl; CMPCThemeEdit m_ModernSeekbarHeightEdit; - CMPCThemeSpinButtonCtrl m_DefaultToolbarSizeCtrl; CMPCThemeComboBox m_ThemeMode; int m_iThemeMode; CMPCThemeComboBox m_langsComboBox; CMPCThemeComboBox m_HoverPosition; int m_nPosLangEnglish; - int m_iDefaultToolbarSize; CMPCThemeComboBox m_FontSize; CMPCThemeComboBox m_FontType; int m_nOSDSize; - BOOL m_fUseSeekbarHover; CString m_strOSDFont; BOOL m_fShowChapters; diff --git a/src/mpc-hc/PPageToolBar.cpp b/src/mpc-hc/PPageToolBar.cpp index b296d6c10c9..1f1ae1c806b 100644 --- a/src/mpc-hc/PPageToolBar.cpp +++ b/src/mpc-hc/PPageToolBar.cpp @@ -28,13 +28,20 @@ IMPLEMENT_DYNAMIC(CPPageToolBar, CMPCThemePPageBase) CPPageToolBar::CPPageToolBar() : CMPCThemePPageBase(IDD, IDD) - +, m_iDefaultToolbarSize(DEF_TOOLBAR_HEIGHT) { + EventRouter::EventSelection fires; + fires.insert(MpcEvent::DEFAULT_TOOLBAR_SIZE_CHANGED); + GetEventd().Connect(m_eventc, fires); } void CPPageToolBar::DoDataExchange(CDataExchange* pDX) { __super::DoDataExchange(pDX); + DDX_Text(pDX, IDC_EDIT1, m_iDefaultToolbarSize); + DDV_MinMaxInt(pDX, m_iDefaultToolbarSize, MIN_TOOLBAR_HEIGHT, MAX_TOOLBAR_HEIGHT); + DDX_Control(pDX, IDC_SPIN1, m_DefaultToolbarSizeCtrl); + DDX_Control(pDX, IDC_LIST1, m_list_active); DDX_Control(pDX, IDC_LIST2, m_list_inactive); DDX_Control(pDX, IDC_BUTTON3, leftButton); @@ -87,6 +94,10 @@ void CPPageToolBar::LoadToolBarButtons() { BOOL CPPageToolBar::OnInitDialog() { __super::OnInitDialog(); + auto& s = AfxGetAppSettings(); + + m_DefaultToolbarSizeCtrl.SetRange32(MIN_TOOLBAR_HEIGHT, MAX_TOOLBAR_HEIGHT); + m_iDefaultToolbarSize = s.nDefaultToolbarSize; CRect brc; leftButton.GetWindowRect(brc); @@ -122,13 +133,28 @@ BOOL CPPageToolBar::OnInitDialog() LoadToolBarButtons(); + AdjustDynamicWidgetPair(this, IDC_STATIC3, IDC_EDIT1); SetRedraw(TRUE); + + UpdateData(FALSE); + return TRUE; } BOOL CPPageToolBar::OnApply() { + UpdateData(); auto& s = AfxGetAppSettings(); + + int nOldDefaultToolbarSize = s.nDefaultToolbarSize; + s.nDefaultToolbarSize = m_iDefaultToolbarSize; + if (nOldDefaultToolbarSize != s.nDefaultToolbarSize) { + m_eventc.FireEvent(MpcEvent::DEFAULT_TOOLBAR_SIZE_CHANGED); + if (CMainFrame* pMainFrame = AfxGetMainFrame()) { + pMainFrame->RecalcLayout(); + } + } + return __super::OnApply(); } diff --git a/src/mpc-hc/PPageToolBar.h b/src/mpc-hc/PPageToolBar.h index d5a1d538845..289da21be1b 100644 --- a/src/mpc-hc/PPageToolBar.h +++ b/src/mpc-hc/PPageToolBar.h @@ -24,6 +24,7 @@ #include "resource.h" #include "CMPCThemeSpinButtonCtrl.h" #include "CMPCThemePlayerListCtrl.h" +#include "EventDispatcher.h" class CPPageToolBar : public CMPCThemePPageBase , public CMPCThemeListCtrlCustomInterface @@ -36,6 +37,7 @@ class CPPageToolBar : public CMPCThemePPageBase virtual void DoCustomPrePaint() {}; virtual void GetCustomGridColors(int nItem, COLORREF& horzGridColor, COLORREF& vertGridColor) {}; virtual bool UseCustomGrid() { return false; }; + EventClient m_eventc; private: enum { IDD = IDD_PPAGETOOLBAR }; @@ -52,6 +54,8 @@ class CPPageToolBar : public CMPCThemePPageBase CMPCThemePlayerListCtrl m_list_active, m_list_inactive; CMPCThemeButton leftButton, rightButton, upButton, downButton; CImage arrow; + CMPCThemeSpinButtonCtrl m_DefaultToolbarSizeCtrl; + int m_iDefaultToolbarSize; virtual void DoDataExchange(CDataExchange* pDX) override; void OnUpdateLeft(CCmdUI* pCmdUI); diff --git a/src/mpc-hc/mpc-hc.rc b/src/mpc-hc/mpc-hc.rc index 21b8df34aea..67fbff40657 100644 --- a/src/mpc-hc/mpc-hc.rc +++ b/src/mpc-hc/mpc-hc.rc @@ -1145,9 +1145,6 @@ BEGIN CONTROL "Use Modern Theme",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,20,114,8 LTEXT "Modern Theme Color:",IDC_STATIC2,12,34,70,8 COMBOBOX IDC_COMBO1,88,34,84,47,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Control buttons size:",IDC_STATIC3,12,48,115,8 - EDITTEXT IDC_EDIT1,129,48,43,14,ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER - CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,160,48,13,14 GROUPBOX "Seekbar",IDC_STATIC4,6,70,170,46 LTEXT "Modern Seekbar height:",IDC_STATIC22,12,84,82,8 EDITTEXT IDC_MODERNSEEKBARHEIGHT,129,84,43,14,ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER @@ -1201,6 +1198,9 @@ IDD_PPAGETOOLBAR DIALOGEX 0, 0, 355, 289 STYLE DS_SETFONT | WS_CHILD FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN + LTEXT "ToolBar Scale:",IDC_STATIC3,6,18,115,8 + EDITTEXT IDC_EDIT1,118,18,43,14,ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,149,18,13,14 CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,6,36,155,230 CONTROL "",IDC_LIST2,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,193,36,156,230 PUSHBUTTON "Default",IDC_BUTTON1,284,271,65,14 From 1ad5d6586114b93392d4b34b67b1987f555be121 Mon Sep 17 00:00:00 2001 From: adipose <3324395+adipose@users.noreply.github.com> Date: Fri, 14 Mar 2025 23:24:51 -0700 Subject: [PATCH 20/20] simplify arrow svg --- src/mpc-hc/res/arrow.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mpc-hc/res/arrow.svg b/src/mpc-hc/res/arrow.svg index 38bf5886646..72eb1318e90 100644 --- a/src/mpc-hc/res/arrow.svg +++ b/src/mpc-hc/res/arrow.svg @@ -1,8 +1,8 @@ + viewBox="0 0 1008 672" style="enable-background:new 0 0 1008 672;" xml:space="preserve"> - +